From e98e3350c03af4187e1d5fe007c7b460e378990c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:38 +0000 Subject: netxen: code cleanup o remove unused structure defs. o remove unnecessary includes. o replace enums with specific #defines. o reduce footprint of stats structure. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index c408151..184eb6f 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -34,10 +34,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -49,18 +45,12 @@ #include #include -#include #include -#include -#include #include -#include #include #include -#include -#include #include "netxen_nic_hw.h" @@ -118,6 +108,7 @@ #define NX_P3_A2 0x30 #define NX_P3_B0 0x40 #define NX_P3_B1 0x41 +#define NX_P3_B2 0x42 #define NX_IS_REVISION_P2(REVISION) (REVISION <= NX_P2_C1) #define NX_IS_REVISION_P3(REVISION) (REVISION >= NX_P3_A0) @@ -203,18 +194,8 @@ #define MAX_RCV_DESCRIPTORS_10G 4096 #define MAX_JUMBO_RCV_DESCRIPTORS 1024 #define MAX_LRO_RCV_DESCRIPTORS 8 -#define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS -#define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS -#define MAX_RCV_DESC MAX_RCV_DESCRIPTORS -#define MAX_RCVSTATUS_DESC MAX_RCV_DESCRIPTORS -#define MAX_EPG_DESCRIPTORS (MAX_CMD_DESCRIPTORS * 8) -#define NUM_RCV_DESC (MAX_RCV_DESC + MAX_JUMBO_RCV_DESCRIPTORS + \ - MAX_LRO_RCV_DESCRIPTORS) -#define MIN_TX_COUNT 4096 -#define MIN_RX_COUNT 4096 #define NETXEN_CTX_SIGNATURE 0xdee0 #define NETXEN_RCV_PRODUCER(ringid) (ringid) -#define MAX_FRAME_SIZE 0x10000 /* 64K MAX size for LSO */ #define PHAN_PEG_RCV_INITIALIZED 0xff01 #define PHAN_PEG_RCV_START_INITIALIZE 0xff00 @@ -384,11 +365,6 @@ struct rcv_desc { /* Note: sizeof(status_desc) should always be a mutliple of 2 */ -#define netxen_get_sts_desc_lro_cnt(status_desc) \ - ((status_desc)->lro & 0x7F) -#define netxen_get_sts_desc_lro_last_frag(status_desc) \ - (((status_desc)->lro & 0x80) >> 7) - #define netxen_get_sts_port(sts_data) \ ((sts_data) & 0x0F) #define netxen_get_sts_status(sts_data) \ @@ -434,10 +410,6 @@ struct status_desc { }; } __attribute__ ((aligned(16))); -enum { - NETXEN_RCV_PEG_0 = 0, - NETXEN_RCV_PEG_1 -}; /* The version of the main data structure */ #define NETXEN_BDINFO_VERSION 1 @@ -447,85 +419,35 @@ enum { /* Max number of Gig ports on a Phantom board */ #define NETXEN_MAX_PORTS 4 -typedef enum { - NETXEN_BRDTYPE_P1_BD = 0x0000, - NETXEN_BRDTYPE_P1_SB = 0x0001, - NETXEN_BRDTYPE_P1_SMAX = 0x0002, - NETXEN_BRDTYPE_P1_SOCK = 0x0003, - - NETXEN_BRDTYPE_P2_SOCK_31 = 0x0008, - NETXEN_BRDTYPE_P2_SOCK_35 = 0x0009, - NETXEN_BRDTYPE_P2_SB35_4G = 0x000a, - NETXEN_BRDTYPE_P2_SB31_10G = 0x000b, - NETXEN_BRDTYPE_P2_SB31_2G = 0x000c, - - NETXEN_BRDTYPE_P2_SB31_10G_IMEZ = 0x000d, - NETXEN_BRDTYPE_P2_SB31_10G_HMEZ = 0x000e, - NETXEN_BRDTYPE_P2_SB31_10G_CX4 = 0x000f, - - NETXEN_BRDTYPE_P3_REF_QG = 0x0021, - NETXEN_BRDTYPE_P3_HMEZ = 0x0022, - NETXEN_BRDTYPE_P3_10G_CX4_LP = 0x0023, - NETXEN_BRDTYPE_P3_4_GB = 0x0024, - NETXEN_BRDTYPE_P3_IMEZ = 0x0025, - NETXEN_BRDTYPE_P3_10G_SFP_PLUS = 0x0026, - NETXEN_BRDTYPE_P3_10000_BASE_T = 0x0027, - NETXEN_BRDTYPE_P3_XG_LOM = 0x0028, - NETXEN_BRDTYPE_P3_4_GB_MM = 0x0029, - NETXEN_BRDTYPE_P3_10G_SFP_CT = 0x002a, - NETXEN_BRDTYPE_P3_10G_SFP_QT = 0x002b, - NETXEN_BRDTYPE_P3_10G_CX4 = 0x0031, - NETXEN_BRDTYPE_P3_10G_XFP = 0x0032, - NETXEN_BRDTYPE_P3_10G_TP = 0x0080 - -} netxen_brdtype_t; - -typedef enum { - NETXEN_BRDMFG_INVENTEC = 1 -} netxen_brdmfg; - -typedef enum { - MEM_ORG_128Mbx4 = 0x0, /* DDR1 only */ - MEM_ORG_128Mbx8 = 0x1, /* DDR1 only */ - MEM_ORG_128Mbx16 = 0x2, /* DDR1 only */ - MEM_ORG_256Mbx4 = 0x3, - MEM_ORG_256Mbx8 = 0x4, - MEM_ORG_256Mbx16 = 0x5, - MEM_ORG_512Mbx4 = 0x6, - MEM_ORG_512Mbx8 = 0x7, - MEM_ORG_512Mbx16 = 0x8, - MEM_ORG_1Gbx4 = 0x9, - MEM_ORG_1Gbx8 = 0xa, - MEM_ORG_1Gbx16 = 0xb, - MEM_ORG_2Gbx4 = 0xc, - MEM_ORG_2Gbx8 = 0xd, - MEM_ORG_2Gbx16 = 0xe, - MEM_ORG_128Mbx32 = 0x10002, /* GDDR only */ - MEM_ORG_256Mbx32 = 0x10005 /* GDDR only */ -} netxen_mn_mem_org_t; - -typedef enum { - MEM_ORG_512Kx36 = 0x0, - MEM_ORG_1Mx36 = 0x1, - MEM_ORG_2Mx36 = 0x2 -} netxen_sn_mem_org_t; - -typedef enum { - MEM_DEPTH_4MB = 0x1, - MEM_DEPTH_8MB = 0x2, - MEM_DEPTH_16MB = 0x3, - MEM_DEPTH_32MB = 0x4, - MEM_DEPTH_64MB = 0x5, - MEM_DEPTH_128MB = 0x6, - MEM_DEPTH_256MB = 0x7, - MEM_DEPTH_512MB = 0x8, - MEM_DEPTH_1GB = 0x9, - MEM_DEPTH_2GB = 0xa, - MEM_DEPTH_4GB = 0xb, - MEM_DEPTH_8GB = 0xc, - MEM_DEPTH_16GB = 0xd, - MEM_DEPTH_32GB = 0xe -} netxen_mem_depth_t; +#define NETXEN_BRDTYPE_P1_BD 0x0000 +#define NETXEN_BRDTYPE_P1_SB 0x0001 +#define NETXEN_BRDTYPE_P1_SMAX 0x0002 +#define NETXEN_BRDTYPE_P1_SOCK 0x0003 + +#define NETXEN_BRDTYPE_P2_SOCK_31 0x0008 +#define NETXEN_BRDTYPE_P2_SOCK_35 0x0009 +#define NETXEN_BRDTYPE_P2_SB35_4G 0x000a +#define NETXEN_BRDTYPE_P2_SB31_10G 0x000b +#define NETXEN_BRDTYPE_P2_SB31_2G 0x000c + +#define NETXEN_BRDTYPE_P2_SB31_10G_IMEZ 0x000d +#define NETXEN_BRDTYPE_P2_SB31_10G_HMEZ 0x000e +#define NETXEN_BRDTYPE_P2_SB31_10G_CX4 0x000f + +#define NETXEN_BRDTYPE_P3_REF_QG 0x0021 +#define NETXEN_BRDTYPE_P3_HMEZ 0x0022 +#define NETXEN_BRDTYPE_P3_10G_CX4_LP 0x0023 +#define NETXEN_BRDTYPE_P3_4_GB 0x0024 +#define NETXEN_BRDTYPE_P3_IMEZ 0x0025 +#define NETXEN_BRDTYPE_P3_10G_SFP_PLUS 0x0026 +#define NETXEN_BRDTYPE_P3_10000_BASE_T 0x0027 +#define NETXEN_BRDTYPE_P3_XG_LOM 0x0028 +#define NETXEN_BRDTYPE_P3_4_GB_MM 0x0029 +#define NETXEN_BRDTYPE_P3_10G_SFP_CT 0x002a +#define NETXEN_BRDTYPE_P3_10G_SFP_QT 0x002b +#define NETXEN_BRDTYPE_P3_10G_CX4 0x0031 +#define NETXEN_BRDTYPE_P3_10G_XFP 0x0032 +#define NETXEN_BRDTYPE_P3_10G_TP 0x0080 struct netxen_board_info { u32 header_version; @@ -676,17 +598,15 @@ struct netxen_new_user_info { #define PRIMARY_IMAGE_BAD 0xffffffff /* Flash memory map */ -typedef enum { - NETXEN_CRBINIT_START = 0, /* Crbinit section */ - NETXEN_BRDCFG_START = 0x4000, /* board config */ - NETXEN_INITCODE_START = 0x6000, /* pegtune code */ - NETXEN_BOOTLD_START = 0x10000, /* bootld */ - NETXEN_IMAGE_START = 0x43000, /* compressed image */ - NETXEN_SECONDARY_START = 0x200000, /* backup images */ - NETXEN_PXE_START = 0x3E0000, /* user defined region */ - NETXEN_USER_START = 0x3E8000, /* User defined region for new boards */ - NETXEN_FIXED_START = 0x3F0000 /* backup of crbinit */ -} netxen_flash_map_t; +#define NETXEN_CRBINIT_START 0 /* crbinit section */ +#define NETXEN_BRDCFG_START 0x4000 /* board config */ +#define NETXEN_INITCODE_START 0x6000 /* pegtune code */ +#define NETXEN_BOOTLD_START 0x10000 /* bootld */ +#define NETXEN_IMAGE_START 0x43000 /* compressed image */ +#define NETXEN_SECONDARY_START 0x200000 /* backup images */ +#define NETXEN_PXE_START 0x3E0000 /* PXE boot rom */ +#define NETXEN_USER_START 0x3E8000 /* Firmare info */ +#define NETXEN_FIXED_START 0x3F0000 /* backup of crbinit */ #define NX_FW_VERSION_OFFSET (NETXEN_USER_START+0x408) #define NX_FW_SIZE_OFFSET (NETXEN_USER_START+0x40c) @@ -708,21 +628,8 @@ typedef enum { #define NETXEN_FLASH_SECONDARY_SIZE (NETXEN_USER_START-NETXEN_SECONDARY_START) #define NETXEN_NUM_PRIMARY_SECTORS (0x20) #define NETXEN_NUM_CONFIG_SECTORS (1) -#define PFX "NetXen: " extern char netxen_nic_driver_name[]; -/* Note: Make sure to not call this before adapter->port is valid */ -#if !defined(NETXEN_DEBUG) -#define DPRINTK(klevel, fmt, args...) do { \ - } while (0) -#else -#define DPRINTK(klevel, fmt, args...) do { \ - printk(KERN_##klevel PFX "%s: %s: " fmt, __func__,\ - (adapter != NULL && adapter->netdev != NULL) ? \ - adapter->netdev->name : NULL, \ - ## args); } while(0) -#endif - /* Number of status descriptors to handle per interrupt */ #define MAX_STATUS_HANDLE (64) @@ -807,20 +714,14 @@ struct netxen_hardware_context { #define ETHERNET_FCS_SIZE 4 struct netxen_adapter_stats { - u64 rcvdbadskb; u64 xmitcalled; - u64 xmitedframes; u64 xmitfinished; - u64 badskblen; - u64 nocmddescriptor; - u64 polled; u64 rxdropped; u64 txdropped; u64 csummed; u64 no_rcv; u64 rxbytes; u64 txbytes; - u64 ints; }; /* @@ -1154,26 +1055,53 @@ typedef struct { #define NX_MAC_EVENT 0x1 -enum { - NX_NIC_H2C_OPCODE_START = 0, - NX_NIC_H2C_OPCODE_CONFIG_RSS, - NX_NIC_H2C_OPCODE_CONFIG_RSS_TBL, - NX_NIC_H2C_OPCODE_CONFIG_INTR_COALESCE, - NX_NIC_H2C_OPCODE_CONFIG_LED, - NX_NIC_H2C_OPCODE_CONFIG_PROMISCUOUS, - NX_NIC_H2C_OPCODE_CONFIG_L2_MAC, - NX_NIC_H2C_OPCODE_LRO_REQUEST, - NX_NIC_H2C_OPCODE_GET_SNMP_STATS, - NX_NIC_H2C_OPCODE_PROXY_START_REQUEST, - NX_NIC_H2C_OPCODE_PROXY_STOP_REQUEST, - NX_NIC_H2C_OPCODE_PROXY_SET_MTU, - NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE, - NX_H2P_OPCODE_GET_FINGER_PRINT_REQUEST, - NX_H2P_OPCODE_INSTALL_LICENSE_REQUEST, - NX_H2P_OPCODE_GET_LICENSE_CAPABILITY_REQUEST, - NX_NIC_H2C_OPCODE_GET_NET_STATS, - NX_NIC_H2C_OPCODE_LAST -}; +/* + * Driver --> Firmware + */ +#define NX_NIC_H2C_OPCODE_START 0 +#define NX_NIC_H2C_OPCODE_CONFIG_RSS 1 +#define NX_NIC_H2C_OPCODE_CONFIG_RSS_TBL 2 +#define NX_NIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3 +#define NX_NIC_H2C_OPCODE_CONFIG_LED 4 +#define NX_NIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5 +#define NX_NIC_H2C_OPCODE_CONFIG_L2_MAC 6 +#define NX_NIC_H2C_OPCODE_LRO_REQUEST 7 +#define NX_NIC_H2C_OPCODE_GET_SNMP_STATS 8 +#define NX_NIC_H2C_OPCODE_PROXY_START_REQUEST 9 +#define NX_NIC_H2C_OPCODE_PROXY_STOP_REQUEST 10 +#define NX_NIC_H2C_OPCODE_PROXY_SET_MTU 11 +#define NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12 +#define NX_NIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13 +#define NX_NIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14 +#define NX_NIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15 +#define NX_NIC_H2C_OPCODE_GET_NET_STATS 16 +#define NX_NIC_H2C_OPCODE_PROXY_UPDATE_P2V 17 +#define NX_NIC_H2C_OPCODE_CONFIG_IPADDR 18 +#define NX_NIC_H2C_OPCODE_CONFIG_LOOPBACK 19 +#define NX_NIC_H2C_OPCODE_PROXY_STOP_DONE 20 +#define NX_NIC_H2C_OPCODE_GET_LINKEVENT 21 +#define NX_NIC_C2C_OPCODE 22 +#define NX_NIC_H2C_OPCODE_LAST 23 + +/* + * Firmware --> Driver + */ + +#define NX_NIC_C2H_OPCODE_START 128 +#define NX_NIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129 +#define NX_NIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130 +#define NX_NIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131 +#define NX_NIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132 +#define NX_NIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133 +#define NX_NIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134 +#define NX_NIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135 +#define NX_NIC_C2H_OPCODE_GET_SNMP_STATS 136 +#define NX_NIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137 +#define NX_NIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138 +#define NX_NIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139 +#define NX_NIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140 +#define NX_NIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141 +#define NX_NIC_C2H_OPCODE_LAST 142 #define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */ #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ @@ -1491,7 +1419,7 @@ void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, #define NETXEN_MAX_SHORT_NAME 32 struct netxen_brdinfo { - netxen_brdtype_t brdtype; /* type of board */ + int brdtype; /* type of board */ long ports; /* max no of physical ports */ char short_name[NETXEN_MAX_SHORT_NAME]; }; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index a677ff8..fe910c1 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -53,13 +52,9 @@ struct netxen_nic_stats { #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { - {"rcvd_bad_skb", NETXEN_NIC_STAT(stats.rcvdbadskb)}, {"xmit_called", NETXEN_NIC_STAT(stats.xmitcalled)}, - {"xmited_frames", NETXEN_NIC_STAT(stats.xmitedframes)}, {"xmit_finished", NETXEN_NIC_STAT(stats.xmitfinished)}, - {"bad_skb_len", NETXEN_NIC_STAT(stats.badskblen)}, - {"no_cmd_desc", NETXEN_NIC_STAT(stats.nocmddescriptor)}, - {"polled", NETXEN_NIC_STAT(stats.polled)}, + {"rx_dropped", NETXEN_NIC_STAT(stats.rxdropped)}, {"tx_dropped", NETXEN_NIC_STAT(stats.txdropped)}, {"csummed", NETXEN_NIC_STAT(stats.csummed)}, {"no_rcv", NETXEN_NIC_STAT(stats.no_rcv)}, @@ -168,7 +163,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->phy_address = adapter->physical_port; ecmd->transceiver = XCVR_EXTERNAL; - switch ((netxen_brdtype_t)adapter->ahw.board_type) { + switch (adapter->ahw.board_type) { case NETXEN_BRDTYPE_P2_SB35_4G: case NETXEN_BRDTYPE_P2_SB31_2G: case NETXEN_BRDTYPE_P3_REF_QG: @@ -227,7 +222,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) break; default: printk(KERN_ERR "netxen-nic: Unsupported board model %d\n", - (netxen_brdtype_t)adapter->ahw.board_type); + adapter->ahw.board_type); return -EIO; } diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 016c621..7f0ddbf 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -31,16 +31,8 @@ #ifndef __NETXEN_NIC_HDR_H_ #define __NETXEN_NIC_HDR_H_ -#include #include -#include -#include -#include -#include -#include #include -#include -#include /* for memset */ /* * The basic unit of access when reading/writing control registers. diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 5026811..67d63ee 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -48,6 +48,21 @@ #define CRB_HI(off) ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000)) #define CRB_INDIRECT_2M (0x1e0000UL) +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ + return readl(addr) | (((u64) readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(((u32) (val)), (addr)); + writel(((u32) (val >> 32)), (addr + 4)); +} +#endif + #define CRB_WIN_LOCK_TIMEOUT 100000000 static crb_128M_2M_block_map_t crb_128M_2M_map[64] = { {{{0, 0, 0, 0} } }, /* 0: PCI */ @@ -2148,7 +2163,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) board_type = NETXEN_BRDTYPE_P3_10G_TP; } - switch ((netxen_brdtype_t)board_type) { + switch (board_type) { case NETXEN_BRDTYPE_P2_SB35_4G: adapter->ahw.port_type = NETXEN_NIC_GBE; break; diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 04b47a7..f20c965 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -36,35 +36,15 @@ /* Hardware memory size of 128 meg */ #define NETXEN_MEMADDR_MAX (128 * 1024 * 1024) -#ifndef readq -static inline u64 readq(void __iomem * addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem * addr) -{ - writel(((u32) (val)), (addr)); - writel(((u32) (val >> 32)), (addr + 4)); -} -#endif - struct netxen_adapter; #define NETXEN_PCI_MAPSIZE_BYTES (NETXEN_PCI_MAPSIZE << 20) -struct netxen_port; void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); typedef u8 netxen_ethernet_macaddr_t[6]; /* Nibble or Byte mode for phy interface (GbE mode only) */ -typedef enum { - NETXEN_NIU_10_100_MB = 0, - NETXEN_NIU_1000_MB -} netxen_niu_gbe_ifmode_t; #define _netxen_crb_get_bit(var, bit) ((var >> bit) & 0x1) @@ -222,30 +202,28 @@ typedef enum { /* * PHY-Specific MII control/status registers. */ -typedef enum { - NETXEN_NIU_GB_MII_MGMT_ADDR_CONTROL = 0, - NETXEN_NIU_GB_MII_MGMT_ADDR_STATUS = 1, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_0 = 2, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_1 = 3, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG = 4, - NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART = 5, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG_MORE = 6, - NETXEN_NIU_GB_MII_MGMT_ADDR_NEXTPAGE_XMIT = 7, - NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART_NEXTPAGE = 8, - NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_CONTROL = 9, - NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_STATUS = 10, - NETXEN_NIU_GB_MII_MGMT_ADDR_EXTENDED_STATUS = 15, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL = 16, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS = 17, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE = 18, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS = 19, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE = 20, - NETXEN_NIU_GB_MII_MGMT_ADDR_RECV_ERROR_COUNT = 21, - NETXEN_NIU_GB_MII_MGMT_ADDR_LED_CONTROL = 24, - NETXEN_NIU_GB_MII_MGMT_ADDR_LED_OVERRIDE = 25, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE_YET = 26, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS_MORE = 27 -} netxen_niu_phy_register_t; +#define NETXEN_NIU_GB_MII_MGMT_ADDR_CONTROL 0 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_STATUS 1 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_0 2 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_1 3 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG 4 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART 5 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG_MORE 6 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_NEXTPAGE_XMIT 7 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART_NEXTPAGE 8 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_CONTROL 9 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_STATUS 10 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_EXTENDED_STATUS 15 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL 16 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS 17 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE 18 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS 19 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE 20 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_RECV_ERROR_COUNT 21 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LED_CONTROL 24 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LED_OVERRIDE 25 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE_YET 26 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS_MORE 27 /* * PHY-Specific Status Register (reg 17). diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index aef7728..85693c0 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -29,7 +29,7 @@ */ #include -#include +#include #include "netxen_nic_hw.h" #include "netxen_nic.h" @@ -1598,10 +1598,6 @@ static void netxen_tx_timeout_task(struct work_struct *work) netif_wake_queue(adapter->netdev); } -/* - * netxen_nic_get_stats - Get System Network Statistics - * @netdev: network interface device structure - */ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); @@ -1609,22 +1605,11 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) memset(stats, 0, sizeof(*stats)); - /* total packets received */ stats->rx_packets = adapter->stats.no_rcv; - /* total packets transmitted */ - stats->tx_packets = adapter->stats.xmitedframes + - adapter->stats.xmitfinished; - /* total bytes received */ + stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes; - /* total bytes transmitted */ stats->tx_bytes = adapter->stats.txbytes; - /* bad packets received */ - stats->rx_errors = adapter->stats.rcvdbadskb; - /* packet transmit problems */ - stats->tx_errors = adapter->stats.nocmddescriptor; - /* no space in linux buffers */ stats->rx_dropped = adapter->stats.rxdropped; - /* no space available in linux */ stats->tx_dropped = adapter->stats.txdropped; return stats; diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index d852032..3310471 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -342,9 +342,9 @@ static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, } if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); + printk(KERN_ERR "ERROR enabling PHY interrupts\n"); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); } /* @@ -380,9 +380,9 @@ static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, } if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); + printk(KERN_ERR "ERROR enabling PHY interrupts\n"); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); } int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) @@ -428,13 +428,13 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) | NETXEN_GB_MAC_PAUSED_FRMS); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR PFX + printk(KERN_ERR "ERROR enabling PHY interrupts\n"); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); result = -1; } diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 5018333..18ea35d 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -41,18 +41,18 @@ #define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04) #define CRB_CMD_PRODUCER_OFFSET NETXEN_NIC_REG(0x08) #define CRB_CMD_CONSUMER_OFFSET NETXEN_NIC_REG(0x0c) -#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) /* C0 EPG BUG */ +#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) #define CRB_PAUSE_ADDR_HI NETXEN_NIC_REG(0x14) #define NX_CDRP_CRB_OFFSET NETXEN_NIC_REG(0x18) #define NX_ARG1_CRB_OFFSET NETXEN_NIC_REG(0x1c) #define NX_ARG2_CRB_OFFSET NETXEN_NIC_REG(0x20) #define NX_ARG3_CRB_OFFSET NETXEN_NIC_REG(0x24) #define NX_SIGN_CRB_OFFSET NETXEN_NIC_REG(0x28) -#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x20) /* 4 regs for perf */ +#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x20) #define CRB_CMD_DMA_LOOP NETXEN_NIC_REG(0x24) #define CRB_RCV_INTR_LOOP NETXEN_NIC_REG(0x28) #define CRB_RCV_DMA_LOOP NETXEN_NIC_REG(0x2c) -#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x30) /* phantom init status */ +#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x30) #define CRB_MMAP_ADDR_3 NETXEN_NIC_REG(0x34) #define CRB_CMDPEG_CMDRING NETXEN_NIC_REG(0x38) #define CRB_HOST_DUMMY_BUF_ADDR_HI NETXEN_NIC_REG(0x3c) @@ -65,7 +65,7 @@ #define CRB_MMAP_SIZE_1 NETXEN_NIC_REG(0x58) #define CRB_MMAP_SIZE_2 NETXEN_NIC_REG(0x5c) #define CRB_MMAP_SIZE_3 NETXEN_NIC_REG(0x60) -#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x64) /* interrupt coalescing */ +#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x64) #define CRB_INT_COAL_MODE NETXEN_NIC_REG(0x68) #define CRB_MAX_RCV_BUFS NETXEN_NIC_REG(0x6c) #define CRB_TX_INT_THRESHOLD NETXEN_NIC_REG(0x70) @@ -83,13 +83,13 @@ #define CRB_AGENT_TX_TYPE NETXEN_NIC_REG(0xa0) #define CRB_AGENT_TX_ADDR NETXEN_NIC_REG(0xa4) #define CRB_AGENT_TX_MSS NETXEN_NIC_REG(0xa8) -#define CRB_TX_STATE NETXEN_NIC_REG(0xac) /* Debug -performance */ +#define CRB_TX_STATE NETXEN_NIC_REG(0xac) #define CRB_TX_COUNT NETXEN_NIC_REG(0xb0) #define CRB_RX_STATE NETXEN_NIC_REG(0xb4) #define CRB_RX_PERF_DEBUG_1 NETXEN_NIC_REG(0xb8) -#define CRB_RX_LRO_CONTROL NETXEN_NIC_REG(0xbc) /* LRO On/OFF */ +#define CRB_RX_LRO_CONTROL NETXEN_NIC_REG(0xbc) #define CRB_RX_LRO_START_NUM NETXEN_NIC_REG(0xc0) -#define CRB_MPORT_MODE NETXEN_NIC_REG(0xc4) /* Multiport Mode */ +#define CRB_MPORT_MODE NETXEN_NIC_REG(0xc4) #define CRB_CMD_RING_SIZE NETXEN_NIC_REG(0xc8) #define CRB_DMA_SHIFT NETXEN_NIC_REG(0xcc) #define CRB_INT_VECTOR NETXEN_NIC_REG(0xd4) @@ -109,8 +109,6 @@ #define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) #define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8) #define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc) - -// 1c0 to 1cc used for signature reg #define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0) #define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4) #define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) @@ -120,8 +118,7 @@ #define CRB_V2P_2 NETXEN_NIC_REG(0x298) #define CRB_V2P_3 NETXEN_NIC_REG(0x29c) #define CRB_V2P(port) (CRB_V2P_0+((port)*4)) -#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) -/* sw int status/mask registers */ +#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) #define CRB_SW_INT_MASK_0 NETXEN_NIC_REG(0x1d8) #define CRB_SW_INT_MASK_1 NETXEN_NIC_REG(0x1e0) #define CRB_SW_INT_MASK_2 NETXEN_NIC_REG(0x1e4) @@ -136,7 +133,7 @@ #define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) #define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) #define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) -#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) +#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) #define INTR_SCHEME_PERPORT 0x1 #define MSI_MODE_MULTIFUNC 0x1 -- cgit v0.10.2 From 1b1f789818c6be9437cfe199932ee13faafca60f Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:39 +0000 Subject: netxen: refactor netxen_adapter Rearrange members to align them at right offset. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 184eb6f..1165f53 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -700,14 +700,13 @@ struct netxen_hardware_context { u8 cut_through; u8 revision_id; + u8 pci_func; + u8 linkup; u16 port_type; - int board_type; - u32 linkup; + u16 board_type; /* Address of cmd ring in Phantom */ struct cmd_desc_type0 *cmd_desc_head; dma_addr_t cmd_desc_phys_addr; - struct netxen_adapter *adapter; - int pci_func; }; #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ @@ -1146,61 +1145,52 @@ struct netxen_adapter { struct net_device *netdev; struct pci_dev *pdev; - int pci_using_dac; - struct net_device_stats net_stats; - int mtu; - int portnum; - u8 physical_port; - u16 tx_context_id; - - uint8_t mc_enabled; - uint8_t max_mc_count; nx_mac_list_t *mac_list; - struct netxen_legacy_intr_set legacy_intr; - - struct work_struct watchdog_task; - struct timer_list watchdog_timer; - struct work_struct tx_timeout_task; - u32 curr_window; u32 crb_win; rwlock_t adapter_lock; + spinlock_t tx_clean_lock; u32 cmd_producer; - __le32 *cmd_consumer; u32 last_cmd_consumer; u32 crb_addr_cmd_producer; u32 crb_addr_cmd_consumer; - spinlock_t tx_clean_lock; + __le32 *cmd_consumer; u32 num_txd; u32 num_rxd; u32 num_jumbo_rxd; u32 num_lro_rxd; - int max_rds_rings; - int max_sds_rings; + u8 max_rds_rings; + u8 max_sds_rings; + u8 driver_mismatch; + u8 msix_supported; + u8 rx_csum; + u8 pci_using_dac; + u8 portnum; + u8 physical_port; + + u8 mc_enabled; + u8 max_mc_count; + u16 tx_context_id; + u16 mtu; + u16 is_up; + u16 link_speed; + u16 link_duplex; + u16 link_autoneg; + u16 resv1; + u32 resv2; u32 flags; u32 irq; - int driver_mismatch; u32 temp; - u32 fw_major; u32 fw_version; - int msix_supported; - struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; - struct netxen_adapter_stats stats; - u16 link_speed; - u16 link_duplex; - u16 state; - u16 link_autoneg; - int rx_csum; - struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */ /* @@ -1209,15 +1199,9 @@ struct netxen_adapter { */ struct netxen_recv_context recv_ctx; - int is_up; - struct netxen_dummy_dma dummy_dma; - nx_nic_intr_coalesce_t coal; - /* Context interface shared between card and host */ struct netxen_ring_ctx *ctx_desc; dma_addr_t ctx_desc_phys_addr; - int intr_scheme; - int msi_mode; int (*enable_phy_interrupts) (struct netxen_adapter *); int (*disable_phy_interrupts) (struct netxen_adapter *); int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t); @@ -1238,7 +1222,21 @@ struct netxen_adapter { u32 (*pci_read_normalize)(struct netxen_adapter *, u64); unsigned long (*pci_set_window)(struct netxen_adapter *, unsigned long long); -}; /* netxen_adapter structure */ + + struct netxen_legacy_intr_set legacy_intr; + + struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; + + struct netxen_dummy_dma dummy_dma; + + struct work_struct watchdog_task; + struct timer_list watchdog_timer; + struct work_struct tx_timeout_task; + + struct net_device_stats net_stats; + + nx_nic_intr_coalesce_t coal; +}; /* * NetXen dma watchdog control structure diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9234473..73f6deb 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -624,9 +624,6 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (adapter->fw_major >= 4) { - adapter->intr_scheme = INTR_SCHEME_PERPORT; - adapter->msi_mode = MSI_MODE_MULTIFUNC; - err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; @@ -638,10 +635,6 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) sds_ring->crb_sts_consumer = recv_crb_registers[adapter->portnum].crb_sts_consumer; - adapter->intr_scheme = adapter->pci_read_normalize(adapter, - CRB_NIC_CAPABILITIES_FW); - adapter->msi_mode = adapter->pci_read_normalize(adapter, - CRB_NIC_MSI_MODE_FW); recv_ctx->sds_rings[0].crb_intr_mask = sw_int_mask[adapter->portnum]; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 85693c0..853dee8 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -462,8 +462,6 @@ netxen_setup_intr(struct netxen_adapter *adapter) struct pci_dev *pdev = adapter->pdev; adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED); - adapter->intr_scheme = -1; - adapter->msi_mode = -1; if (adapter->ahw.revision_id >= NX_P3_B0) legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; @@ -726,15 +724,6 @@ netxen_nic_request_irq(struct netxen_adapter *adapter) struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; - if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) || - (adapter->intr_scheme != INTR_SCHEME_PERPORT)) { - printk(KERN_ERR "%s: Firmware interrupt scheme is " - "incompatible with driver\n", - netdev->name); - adapter->driver_mismatch = 1; - return -EINVAL; - } - if (adapter->flags & NETXEN_NIC_MSIX_ENABLED) handler = netxen_msix_intr; else if (adapter->flags & NETXEN_NIC_MSI_ENABLED) -- cgit v0.10.2 From d877f1e344f5515988d9dcd6db5d4285911778a3 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:40 +0000 Subject: netxen: refactor transmit code o move tx stuff into nx_host_tx_ring structure, this will help managing multiple tx rings in future. o sanitize some variable names Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 1165f53..2aa658d 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -74,10 +74,10 @@ (sizeof(struct netxen_rx_buffer) * rds_ring->num_desc) #define STATUS_DESC_RINGSIZE(sds_ring) \ (sizeof(struct status_desc) * (sds_ring)->num_desc) -#define TX_BUFF_RINGSIZE(adapter) \ - (sizeof(struct netxen_cmd_buffer) * adapter->num_txd) -#define TX_DESC_RINGSIZE(adapter) \ - (sizeof(struct cmd_desc_type0) * adapter->num_txd) +#define TX_BUFF_RINGSIZE(tx_ring) \ + (sizeof(struct netxen_cmd_buffer) * tx_ring->num_desc) +#define TX_DESC_RINGSIZE(tx_ring) \ + (sizeof(struct cmd_desc_type0) * tx_ring->num_desc) #define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a))) @@ -639,7 +639,7 @@ extern char netxen_nic_driver_name[]; */ struct netxen_skb_frag { u64 dma; - ulong length; + u64 length; }; #define _netxen_set_bits(config_word, start, bits, val) {\ @@ -704,9 +704,6 @@ struct netxen_hardware_context { u8 linkup; u16 port_type; u16 board_type; - /* Address of cmd ring in Phantom */ - struct cmd_desc_type0 *cmd_desc_head; - dma_addr_t cmd_desc_phys_addr; }; #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ @@ -752,14 +749,25 @@ struct nx_host_sds_ring { struct napi_struct napi; struct list_head free_list[NUM_RCV_DESC_RINGS]; - u16 clean_tx; - u16 post_rxd; int irq; dma_addr_t phys_addr; char name[IFNAMSIZ+4]; }; +struct nx_host_tx_ring { + u32 producer; + __le32 *hw_consumer; + u32 sw_consumer; + u32 crb_cmd_producer; + u32 crb_cmd_consumer; + u32 num_desc; + + struct netxen_cmd_buffer *cmd_buf_arr; + struct cmd_desc_type0 *desc_head; + dma_addr_t phys_addr; +}; + /* * Receive context. There is one such structure per instance of the * receive processing. Any state information that is relevant to @@ -1152,11 +1160,6 @@ struct netxen_adapter { rwlock_t adapter_lock; spinlock_t tx_clean_lock; - u32 cmd_producer; - u32 last_cmd_consumer; - u32 crb_addr_cmd_producer; - u32 crb_addr_cmd_consumer; - __le32 *cmd_consumer; u32 num_txd; u32 num_rxd; @@ -1191,13 +1194,8 @@ struct netxen_adapter { struct netxen_adapter_stats stats; - struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */ - - /* - * Receive instances. These can be either one per port, - * or one per peg, etc. - */ struct netxen_recv_context recv_ctx; + struct nx_host_tx_ring tx_ring; /* Context interface shared between card and host */ struct netxen_ring_ctx *ctx_desc; @@ -1409,7 +1407,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p); struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev); void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, - uint32_t crb_producer); + struct nx_host_tx_ring *tx_ring, uint32_t crb_producer); /* * NetXen Board information diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 73f6deb..7943351 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -328,6 +328,7 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) int err = 0; u64 offset, phys_addr; dma_addr_t rq_phys_addr, rsp_phys_addr; + struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; rq_size = SIZEOF_HOSTRQ_TX(nx_hostrq_tx_ctx_t); rq_addr = pci_alloc_consistent(adapter->pdev, @@ -367,10 +368,8 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) prq_cds = &prq->cds_ring; - prq_cds->host_phys_addr = - cpu_to_le64(adapter->ahw.cmd_desc_phys_addr); - - prq_cds->ring_size = cpu_to_le32(adapter->num_txd); + prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr); + prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc); phys_addr = rq_phys_addr; err = netxen_issue_cmd(adapter, @@ -383,8 +382,7 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) if (err == NX_RCODE_SUCCESS) { temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); - adapter->crb_addr_cmd_producer = - NETXEN_NIC_REG(temp - 0x200); + tx_ring->crb_cmd_producer = NETXEN_NIC_REG(temp - 0x200); #if 0 adapter->tx_state = le32_to_cpu(prsp->host_ctx_state); @@ -497,13 +495,13 @@ netxen_init_old_ctx(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring; int ring; int func_id = adapter->portnum; - adapter->ctx_desc->cmd_ring_addr = - cpu_to_le64(adapter->ahw.cmd_desc_phys_addr); - adapter->ctx_desc->cmd_ring_size = - cpu_to_le32(adapter->num_txd); + tx_ring = &adapter->tx_ring; + adapter->ctx_desc->cmd_ring_addr = cpu_to_le64(tx_ring->phys_addr); + adapter->ctx_desc->cmd_ring_size = cpu_to_le32(tx_ring->num_desc); recv_ctx = &adapter->recv_ctx; @@ -535,25 +533,17 @@ static uint32_t sw_int_mask[4] = { int netxen_alloc_hw_resources(struct netxen_adapter *adapter) { - struct netxen_hardware_context *hw = &adapter->ahw; - u32 state = 0; void *addr; int err = 0; int ring; struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; - err = netxen_receive_peg_ready(adapter); - if (err) { - printk(KERN_ERR "Rcv Peg initialization not complete:%x.\n", - state); - return err; - } - addr = pci_alloc_consistent(pdev, sizeof(struct netxen_ring_ctx) + sizeof(uint32_t), &adapter->ctx_desc_phys_addr); @@ -568,13 +558,12 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) adapter->ctx_desc->cmd_consumer_offset = cpu_to_le64(adapter->ctx_desc_phys_addr + sizeof(struct netxen_ring_ctx)); - adapter->cmd_consumer = + tx_ring->hw_consumer = (__le32 *)(((char *)addr) + sizeof(struct netxen_ring_ctx)); /* cmd desc ring */ - addr = pci_alloc_consistent(pdev, - TX_DESC_RINGSIZE(adapter), - &hw->cmd_desc_phys_addr); + addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), + &tx_ring->phys_addr); if (addr == NULL) { dev_err(&pdev->dev, "%s: failed to allocate tx desc ring\n", @@ -582,7 +571,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) return -ENOMEM; } - hw->cmd_desc_head = (struct cmd_desc_type0 *)addr; + tx_ring->desc_head = (struct cmd_desc_type0 *)addr; recv_ctx = &adapter->recv_ctx; @@ -658,6 +647,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring; int ring; if (adapter->fw_major >= 4) { @@ -674,13 +664,12 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) adapter->ctx_desc = NULL; } - if (adapter->ahw.cmd_desc_head != NULL) { + tx_ring = &adapter->tx_ring; + if (tx_ring->desc_head != NULL) { pci_free_consistent(adapter->pdev, - sizeof(struct cmd_desc_type0) * - adapter->num_txd, - adapter->ahw.cmd_desc_head, - adapter->ahw.cmd_desc_phys_addr); - adapter->ahw.cmd_desc_head = NULL; + TX_DESC_RINGSIZE(tx_ring), + tx_ring->desc_head, tx_ring->phys_addr); + tx_ring->desc_head = NULL; } recv_ctx = &adapter->recv_ctx; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 67d63ee..8416962 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -501,45 +501,44 @@ static int nx_p3_nic_add_mac(struct netxen_adapter *adapter, static int netxen_send_cmd_descs(struct netxen_adapter *adapter, - struct cmd_desc_type0 *cmd_desc_arr, int nr_elements) + struct cmd_desc_type0 *cmd_desc_arr, int nr_desc) { - uint32_t i, producer; + u32 i, producer, consumer; struct netxen_cmd_buffer *pbuf; struct cmd_desc_type0 *cmd_desc; - - if (nr_elements > MAX_PENDING_DESC_BLOCK_SIZE || nr_elements == 0) { - printk(KERN_WARNING "%s: Too many command descriptors in a " - "request\n", __func__); - return -EINVAL; - } + struct nx_host_tx_ring *tx_ring; i = 0; + tx_ring = &adapter->tx_ring; netif_tx_lock_bh(adapter->netdev); - producer = adapter->cmd_producer; + producer = tx_ring->producer; + consumer = tx_ring->sw_consumer; + + if (nr_desc > find_diff_among(producer, consumer, tx_ring->num_desc)) { + netif_tx_unlock_bh(adapter->netdev); + return -EBUSY; + } + do { cmd_desc = &cmd_desc_arr[i]; - pbuf = &adapter->cmd_buf_arr[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; pbuf->frag_count = 0; - /* adapter->ahw.cmd_desc_head[producer] = *cmd_desc; */ - memcpy(&adapter->ahw.cmd_desc_head[producer], + memcpy(&tx_ring->desc_head[producer], &cmd_desc_arr[i], sizeof(struct cmd_desc_type0)); - producer = get_next_index(producer, - adapter->num_txd); + producer = get_next_index(producer, tx_ring->num_desc); i++; - } while (i != nr_elements); - - adapter->cmd_producer = producer; + } while (i != nr_desc); - /* write producer index to start the xmit */ + tx_ring->producer = producer; - netxen_nic_update_cmd_producer(adapter, adapter->cmd_producer); + netxen_nic_update_cmd_producer(adapter, tx_ring, producer); netif_tx_unlock_bh(adapter->netdev); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 0759c35..8e45dcc 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -173,9 +173,10 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) struct netxen_cmd_buffer *cmd_buf; struct netxen_skb_frag *buffrag; int i, j; + struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; - cmd_buf = adapter->cmd_buf_arr; - for (i = 0; i < adapter->num_txd; i++) { + cmd_buf = tx_ring->cmd_buf_arr; + for (i = 0; i < tx_ring->num_desc; i++) { buffrag = cmd_buf->frag_array; if (buffrag->dma) { pci_unmap_single(adapter->pdev, buffrag->dma, @@ -203,6 +204,7 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) { struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; + struct nx_host_tx_ring *tx_ring; int ring; recv_ctx = &adapter->recv_ctx; @@ -214,8 +216,9 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) } } - if (adapter->cmd_buf_arr) - vfree(adapter->cmd_buf_arr); + tx_ring = &adapter->tx_ring; + if (tx_ring->cmd_buf_arr) + vfree(tx_ring->cmd_buf_arr); return; } @@ -224,21 +227,24 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; struct netxen_rx_buffer *rx_buf; int ring, i, num_rx_bufs; struct netxen_cmd_buffer *cmd_buf_arr; struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + tx_ring->num_desc = adapter->num_txd; cmd_buf_arr = - (struct netxen_cmd_buffer *)vmalloc(TX_BUFF_RINGSIZE(adapter)); + (struct netxen_cmd_buffer *)vmalloc(TX_BUFF_RINGSIZE(tx_ring)); if (cmd_buf_arr == NULL) { - printk(KERN_ERR "%s: Failed to allocate cmd buffer ring\n", + dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n", netdev->name); return -ENOMEM; } - memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(adapter)); - adapter->cmd_buf_arr = cmd_buf_arr; + memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring)); + tx_ring->cmd_buf_arr = cmd_buf_arr; recv_ctx = &adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { @@ -307,8 +313,6 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; sds_ring->irq = adapter->msix_entries[ring].vector; - sds_ring->clean_tx = (ring == 0); - sds_ring->post_rxd = (ring == 0); sds_ring->adapter = adapter; sds_ring->num_desc = adapter->num_rxd; @@ -990,23 +994,24 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) /* Process Command status ring */ int netxen_process_cmd_ring(struct netxen_adapter *adapter) { - u32 last_consumer, consumer; + u32 sw_consumer, hw_consumer; int count = 0, i; struct netxen_cmd_buffer *buffer; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; struct netxen_skb_frag *frag; int done = 0; + struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; if (!spin_trylock(&adapter->tx_clean_lock)) return 1; - last_consumer = adapter->last_cmd_consumer; - barrier(); /* cmd_consumer can change underneath */ - consumer = le32_to_cpu(*(adapter->cmd_consumer)); + sw_consumer = tx_ring->sw_consumer; + barrier(); /* hw_consumer can change underneath */ + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); - while (last_consumer != consumer) { - buffer = &adapter->cmd_buf_arr[last_consumer]; + while (sw_consumer != hw_consumer) { + buffer = &tx_ring->cmd_buf_arr[sw_consumer]; if (buffer->skb) { frag = &buffer->frag_array[0]; pci_unmap_single(pdev, frag->dma, frag->length, @@ -1024,14 +1029,13 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) buffer->skb = NULL; } - last_consumer = get_next_index(last_consumer, - adapter->num_txd); + sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc); if (++count >= MAX_STATUS_HANDLE) break; } if (count) { - adapter->last_cmd_consumer = last_consumer; + tx_ring->sw_consumer = sw_consumer; smp_mb(); if (netif_queue_stopped(netdev) && netif_running(netdev)) { netif_tx_lock(netdev); @@ -1053,9 +1057,9 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) * There is still a possible race condition and the host could miss an * interrupt. The card has to take care of this. */ - barrier(); /* cmd_consumer can change underneath */ - consumer = le32_to_cpu(*(adapter->cmd_consumer)); - done = (last_consumer == consumer); + barrier(); /* hw_consumer can change underneath */ + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); + done = (sw_consumer == hw_consumer); spin_unlock(&adapter->tx_clean_lock); return (done); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 853dee8..22b2d49 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -107,10 +107,10 @@ static uint32_t crb_cmd_producer[4] = { void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, - uint32_t crb_producer) + struct nx_host_tx_ring *tx_ring, u32 producer) { adapter->pci_write_normalize(adapter, - adapter->crb_addr_cmd_producer, crb_producer); + tx_ring->crb_cmd_producer, producer); } static uint32_t crb_cmd_consumer[4] = { @@ -120,10 +120,10 @@ static uint32_t crb_cmd_consumer[4] = { static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, - u32 crb_consumer) + struct nx_host_tx_ring *tx_ring, u32 consumer) { adapter->pci_write_normalize(adapter, - adapter->crb_addr_cmd_consumer, crb_consumer); + tx_ring->crb_cmd_consumer, consumer); } static uint32_t msi_tgt_status[8] = { @@ -814,6 +814,7 @@ netxen_nic_attach(struct netxen_adapter *adapter) struct pci_dev *pdev = adapter->pdev; int err, ring; struct nx_host_rds_ring *rds_ring; + struct nx_host_tx_ring *tx_ring; err = netxen_init_firmware(adapter); if (err != 0) { @@ -843,13 +844,12 @@ netxen_nic_attach(struct netxen_adapter *adapter) } if (adapter->fw_major < 4) { - adapter->crb_addr_cmd_producer = - crb_cmd_producer[adapter->portnum]; - adapter->crb_addr_cmd_consumer = - crb_cmd_consumer[adapter->portnum]; + tx_ring = &adapter->tx_ring; + tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum]; + tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum]; - netxen_nic_update_cmd_producer(adapter, 0); - netxen_nic_update_cmd_consumer(adapter, 0); + netxen_nic_update_cmd_producer(adapter, tx_ring, 0); + netxen_nic_update_cmd_consumer(adapter, tx_ring, 0); } for (ring = 0; ring < adapter->max_rds_rings; ring++) { @@ -1304,7 +1304,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); - struct netxen_hardware_context *hw = &adapter->ahw; + struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; unsigned int first_seg_len = skb->len - skb->data_len; struct netxen_cmd_buffer *pbuf; struct netxen_skb_frag *buffrag; @@ -1315,28 +1315,26 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) u32 producer, consumer; int frag_count, no_of_desc; - u32 num_txd = adapter->num_txd; + u32 num_txd = tx_ring->num_desc; bool is_tso = false; frag_count = skb_shinfo(skb)->nr_frags + 1; - /* There 4 fragments per descriptor */ + /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; - producer = adapter->cmd_producer; + producer = tx_ring->producer; smp_mb(); - consumer = adapter->last_cmd_consumer; + consumer = tx_ring->sw_consumer; if ((no_of_desc+2) > find_diff_among(producer, consumer, num_txd)) { netif_stop_queue(netdev); smp_mb(); return NETDEV_TX_BUSY; } - /* Copy the descriptors into the hardware */ - hwdesc = &hw->cmd_desc_head[producer]; + hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - /* Take skb->data itself */ - pbuf = &adapter->cmd_buf_arr[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; is_tso = netxen_tso_check(netdev, hwdesc, skb); @@ -1365,9 +1363,9 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if ((i & 0x3) == 0) { k = 0; producer = get_next_index(producer, num_txd); - hwdesc = &hw->cmd_desc_head[producer]; + hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - pbuf = &adapter->cmd_buf_arr[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; } frag = &skb_shinfo(skb)->frags[i - 1]; @@ -1419,8 +1417,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) more_hdr = 0; } /* copy the MAC/IP/TCP headers to the cmd descriptor list */ - hwdesc = &hw->cmd_desc_head[producer]; - pbuf = &adapter->cmd_buf_arr[producer]; + hwdesc = &tx_ring->desc_head[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; /* copy the first 64 bytes */ @@ -1429,8 +1427,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) producer = get_next_index(producer, num_txd); if (more_hdr) { - hwdesc = &hw->cmd_desc_head[producer]; - pbuf = &adapter->cmd_buf_arr[producer]; + hwdesc = &tx_ring->desc_head[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; /* copy the next 64 bytes - should be enough except * for pathological case @@ -1443,10 +1441,10 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } } - adapter->cmd_producer = producer; + tx_ring->producer = producer; adapter->stats.txbytes += skb->len; - netxen_nic_update_cmd_producer(adapter, adapter->cmd_producer); + netxen_nic_update_cmd_producer(adapter, tx_ring, producer); adapter->stats.xmitcalled++; netdev->trans_start = jiffies; -- cgit v0.10.2 From 56a007871a6689db80e19f63fe6dc3692daa2a6f Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:41 +0000 Subject: netxen: defer firmware handshake Removed duplicate firmware handshake, defer it until first port (interface) is brought up. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 2aa658d..7e208b3 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1359,7 +1359,6 @@ unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, void netxen_free_adapter_offload(struct netxen_adapter *adapter); int netxen_initialize_adapter_offload(struct netxen_adapter *adapter); int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); -int netxen_receive_peg_ready(struct netxen_adapter *adapter); int netxen_load_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 8e45dcc..9991951 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -108,42 +108,6 @@ static void crb_addr_transform_setup(void) crb_addr_transform(I2C0); } -int netxen_init_firmware(struct netxen_adapter *adapter) -{ - u32 state = 0, loops = 0, err = 0; - - /* Window 1 call */ - state = adapter->pci_read_normalize(adapter, CRB_CMDPEG_STATE); - - if (state == PHAN_INITIALIZE_ACK) - return 0; - - while (state != PHAN_INITIALIZE_COMPLETE && loops < 2000) { - msleep(1); - /* Window 1 call */ - state = adapter->pci_read_normalize(adapter, CRB_CMDPEG_STATE); - - loops++; - } - if (loops >= 2000) { - printk(KERN_ERR "Cmd Peg initialization not complete:%x.\n", - state); - err = -EIO; - return err; - } - /* Window 1 call */ - adapter->pci_write_normalize(adapter, - CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); - adapter->pci_write_normalize(adapter, - CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); - adapter->pci_write_normalize(adapter, - CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); - adapter->pci_write_normalize(adapter, - CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); - - return err; -} - void netxen_release_rx_buffers(struct netxen_adapter *adapter) { struct netxen_recv_context *recv_ctx; @@ -789,7 +753,8 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) return 0; } -int netxen_receive_peg_ready(struct netxen_adapter *adapter) +static int +netxen_receive_peg_ready(struct netxen_adapter *adapter) { u32 val = 0; int retries = 2000; @@ -813,6 +778,26 @@ int netxen_receive_peg_ready(struct netxen_adapter *adapter) return 0; } +int netxen_init_firmware(struct netxen_adapter *adapter) +{ + int err; + + err = netxen_receive_peg_ready(adapter); + if (err) + return err; + + adapter->pci_write_normalize(adapter, + CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); + adapter->pci_write_normalize(adapter, + CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); + adapter->pci_write_normalize(adapter, + CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); + adapter->pci_write_normalize(adapter, + CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); + + return err; +} + static int netxen_alloc_rx_skb(struct netxen_adapter *adapter, struct nx_host_rds_ring *rds_ring, diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 22b2d49..665fce5 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1027,10 +1027,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netxen_napi_add(adapter, netdev); - err = netxen_receive_peg_ready(adapter); - if (err) - goto err_out_disable_msi; - init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &netxen_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; -- cgit v0.10.2 From 3bf26ce3f4cc3c9e0d0478b4016c6113a16faaf1 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:42 +0000 Subject: netxen: async link event handling Add support for asynchronous events from firmware, received over one of the rx rings. Add support for event based phy interrupts, enhanced links status reporting from firmware. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 7e208b3..f4d7e2d 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -354,6 +354,7 @@ struct rcv_desc { /* opcode field in status_desc */ #define NETXEN_NIC_RXPKT_DESC 0x04 #define NETXEN_OLD_RXPKT_DESC 0x3f +#define NETXEN_NIC_RESPONSE_DESC 0x05 /* for status field in status_desc */ #define STATUS_NEED_CKSUM (1) @@ -363,8 +364,11 @@ struct rcv_desc { #define STATUS_OWNER_HOST (0x1ULL << 56) #define STATUS_OWNER_PHANTOM (0x2ULL << 56) -/* Note: sizeof(status_desc) should always be a mutliple of 2 */ - +/* Status descriptor: + 0-3 port, 4-7 status, 8-11 type, 12-27 total_length + 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset + 53-55 desc_cnt, 56-57 owner, 58-63 opcode + */ #define netxen_get_sts_port(sts_data) \ ((sts_data) & 0x0F) #define netxen_get_sts_status(sts_data) \ @@ -379,35 +383,13 @@ struct rcv_desc { (((sts_data) >> 44) & 0x0F) #define netxen_get_sts_pkt_offset(sts_data) \ (((sts_data) >> 48) & 0x1F) +#define netxen_get_sts_desc_cnt(sts_data) \ + (((sts_data) >> 53) & 0x7) #define netxen_get_sts_opcode(sts_data) \ (((sts_data) >> 58) & 0x03F) struct status_desc { - /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length - 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset - 53-55 desc_cnt, 56-57 owner, 58-63 opcode - */ - __le64 status_desc_data; - union { - struct { - __le32 hash_value; - u8 hash_type; - u8 msg_type; - u8 unused; - union { - /* Bit pattern: 0-6 lro_count indicates frag - * sequence, 7 last_frag indicates last frag - */ - u8 lro; - - /* chained buffers */ - u8 nr_frags; - }; - }; - struct { - __le16 frag_handles[4]; - }; - }; + __le64 status_desc_data[2]; } __attribute__ ((aligned(16))); /* The version of the main data structure */ @@ -1114,6 +1096,66 @@ typedef struct { #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ #define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ +#define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5) +#define NX_FW_CAPABILITY_SWITCHING (1 << 6) + +/* module types */ +#define LINKEVENT_MODULE_NOT_PRESENT 1 +#define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2 +#define LINKEVENT_MODULE_OPTICAL_SRLR 3 +#define LINKEVENT_MODULE_OPTICAL_LRM 4 +#define LINKEVENT_MODULE_OPTICAL_SFP_1G 5 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE 6 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN 7 +#define LINKEVENT_MODULE_TWINAX 8 + +#define LINKSPEED_10GBPS 10000 +#define LINKSPEED_1GBPS 1000 +#define LINKSPEED_100MBPS 100 +#define LINKSPEED_10MBPS 10 + +#define LINKSPEED_ENCODED_10MBPS 0 +#define LINKSPEED_ENCODED_100MBPS 1 +#define LINKSPEED_ENCODED_1GBPS 2 + +#define LINKEVENT_AUTONEG_DISABLED 0 +#define LINKEVENT_AUTONEG_ENABLED 1 + +#define LINKEVENT_HALF_DUPLEX 0 +#define LINKEVENT_FULL_DUPLEX 1 + +#define LINKEVENT_LINKSPEED_MBPS 0 +#define LINKEVENT_LINKSPEED_ENCODED 1 + +/* firmware response header: + * 63:58 - message type + * 57:56 - owner + * 55:53 - desc count + * 52:48 - reserved + * 47:40 - completion id + * 39:32 - opcode + * 31:16 - error code + * 15:00 - reserved + */ +#define netxen_get_nic_msgtype(msg_hdr) \ + ((msg_hdr >> 58) & 0x3F) +#define netxen_get_nic_msg_compid(msg_hdr) \ + ((msg_hdr >> 40) & 0xFF) +#define netxen_get_nic_msg_opcode(msg_hdr) \ + ((msg_hdr >> 32) & 0xFF) +#define netxen_get_nic_msg_errcode(msg_hdr) \ + ((msg_hdr >> 16) & 0xFFFF) + +typedef struct { + union { + struct { + u64 hdr; + u64 body[7]; + }; + u64 words[8]; + }; +} nx_fw_msg_t; + typedef struct { __le64 qhdr; __le64 req_hdr; @@ -1177,15 +1219,21 @@ struct netxen_adapter { u8 mc_enabled; u8 max_mc_count; + u16 resv2; + u32 resv3; + + u8 has_link_events; + u8 resv1; u16 tx_context_id; u16 mtu; u16 is_up; + u16 link_speed; u16 link_duplex; u16 link_autoneg; - u16 resv1; + u16 module_type; - u32 resv2; + u32 capabilities; u32 flags; u32 irq; u32 temp; @@ -1398,6 +1446,8 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter); int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); int netxen_config_intr_coalesce(struct netxen_adapter *adapter); int netxen_config_rss(struct netxen_adapter *adapter, int enable); +int netxen_linkevent_request(struct netxen_adapter *adapter, int enable); +void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index fe910c1..5fde9e0 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -110,6 +110,7 @@ static int netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct netxen_adapter *adapter = netdev_priv(dev); + int check_sfp_module = 0; /* read which mode */ if (adapter->ahw.port_type == NETXEN_NIC_GBE) { @@ -143,6 +144,13 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->advertising = ADVERTISED_10000baseT_Full; } + if (netif_running(dev) && adapter->has_link_events) { + ecmd->speed = adapter->link_speed; + ecmd->autoneg = adapter->link_autoneg; + ecmd->duplex = adapter->link_duplex; + goto skip; + } + ecmd->port = PORT_TP; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { @@ -160,6 +168,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else return -EIO; +skip: ecmd->phy_address = adapter->physical_port; ecmd->transceiver = XCVR_EXTERNAL; @@ -190,7 +199,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) case NETXEN_BRDTYPE_P3_HMEZ: ecmd->supported |= SUPPORTED_MII; ecmd->advertising |= ADVERTISED_MII; - ecmd->port = PORT_FIBRE; + ecmd->port = PORT_MII; ecmd->autoneg = AUTONEG_DISABLE; break; case NETXEN_BRDTYPE_P3_10G_SFP_PLUS: @@ -198,6 +207,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) case NETXEN_BRDTYPE_P3_10G_SFP_QT: ecmd->advertising |= ADVERTISED_TP; ecmd->supported |= SUPPORTED_TP; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; case NETXEN_BRDTYPE_P2_SB31_10G: case NETXEN_BRDTYPE_P3_10G_XFP: ecmd->supported |= SUPPORTED_FIBRE; @@ -212,6 +223,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP); ecmd->port = PORT_FIBRE; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; } else { ecmd->autoneg = AUTONEG_ENABLE; ecmd->supported |= (SUPPORTED_TP |SUPPORTED_Autoneg); @@ -226,6 +239,23 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) return -EIO; } + if (check_sfp_module) { + switch (adapter->module_type) { + case LINKEVENT_MODULE_OPTICAL_UNKNOWN: + case LINKEVENT_MODULE_OPTICAL_SRLR: + case LINKEVENT_MODULE_OPTICAL_LRM: + case LINKEVENT_MODULE_OPTICAL_SFP_1G: + ecmd->port = PORT_FIBRE; + break; + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE: + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN: + case LINKEVENT_MODULE_TWINAX: + ecmd->port = PORT_TP; + default: + ecmd->port = -1; + } + } + return 0; } diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 8416962..33444a2 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -731,6 +731,28 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_linkevent_request(struct netxen_adapter *adapter, int enable) +{ + nx_nic_req_t req; + u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + req.words[0] = cpu_to_le64(enable); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "%s: could not configure link notification\n", + adapter->netdev->name); + } + + return rv; +} + /* * netxen_nic_change_mtu - Change the Maximum Transfer Unit * @returns 0 on success, negative on failure diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 9991951..974783c 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -795,9 +795,81 @@ int netxen_init_firmware(struct netxen_adapter *adapter) adapter->pci_write_normalize(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); + if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) { + adapter->capabilities = netxen_nic_reg_read(adapter, + CRB_FW_CAPABILITIES_1); + } + return err; } +static void +netxen_handle_linkevent(struct netxen_adapter *adapter, nx_fw_msg_t *msg) +{ + u32 cable_OUI; + u16 cable_len; + u16 link_speed; + u8 link_status, module, duplex, autoneg; + struct net_device *netdev = adapter->netdev; + + adapter->has_link_events = 1; + + cable_OUI = msg->body[1] & 0xffffffff; + cable_len = (msg->body[1] >> 32) & 0xffff; + link_speed = (msg->body[1] >> 48) & 0xffff; + + link_status = msg->body[2] & 0xff; + duplex = (msg->body[2] >> 16) & 0xff; + autoneg = (msg->body[2] >> 24) & 0xff; + + module = (msg->body[2] >> 8) & 0xff; + if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) { + printk(KERN_INFO "%s: unsupported cable: OUI 0x%x, length %d\n", + netdev->name, cable_OUI, cable_len); + } else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN) { + printk(KERN_INFO "%s: unsupported cable length %d\n", + netdev->name, cable_len); + } + + netxen_advert_link_change(adapter, link_status); + + /* update link parameters */ + if (duplex == LINKEVENT_FULL_DUPLEX) + adapter->link_duplex = DUPLEX_FULL; + else + adapter->link_duplex = DUPLEX_HALF; + adapter->module_type = module; + adapter->link_autoneg = autoneg; + adapter->link_speed = link_speed; +} + +static void +netxen_handle_fw_message(int desc_cnt, int index, + struct nx_host_sds_ring *sds_ring) +{ + nx_fw_msg_t msg; + struct status_desc *desc; + int i = 0, opcode; + + while (desc_cnt > 0 && i < 8) { + desc = &sds_ring->desc_head[index]; + msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]); + msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]); + + index = get_next_index(index, sds_ring->num_desc); + desc_cnt--; + } + + opcode = netxen_get_nic_msg_opcode(msg.body[0]); + switch (opcode) { + case NX_NIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: + netxen_handle_linkevent(sds_ring->adapter, &msg); + break; + default: + break; + } +} + static int netxen_alloc_rx_skb(struct netxen_adapter *adapter, struct nx_host_rds_ring *rds_ring, @@ -916,21 +988,35 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) int count = 0; u64 sts_data; - int opcode, ring, index, length, cksum, pkt_offset; + int opcode, ring, index, length, cksum, pkt_offset, desc_cnt; while (count < max) { desc = &sds_ring->desc_head[consumer]; - sts_data = le64_to_cpu(desc->status_desc_data); + sts_data = le64_to_cpu(desc->status_desc_data[0]); if (!(sts_data & STATUS_OWNER_HOST)) break; + desc_cnt = netxen_get_sts_desc_cnt(sts_data); ring = netxen_get_sts_type(sts_data); + if (ring > RCV_RING_JUMBO) - continue; + goto skip; opcode = netxen_get_sts_opcode(sts_data); + switch (opcode) { + case NETXEN_NIC_RXPKT_DESC: + case NETXEN_OLD_RXPKT_DESC: + break; + case NETXEN_NIC_RESPONSE_DESC: + netxen_handle_fw_message(desc_cnt, consumer, sds_ring); + default: + goto skip; + } + + WARN_ON(desc_cnt > 1); + index = netxen_get_sts_refhandle(sts_data); length = netxen_get_sts_totallength(sts_data); cksum = netxen_get_sts_status(sts_data); @@ -942,9 +1028,13 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) if (rxbuf) list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); - desc->status_desc_data = cpu_to_le64(STATUS_OWNER_PHANTOM); - - consumer = get_next_index(consumer, sds_ring->num_desc); +skip: + for (; desc_cnt > 0; desc_cnt--) { + desc = &sds_ring->desc_head[consumer]; + desc->status_desc_data[0] = + cpu_to_le64(STATUS_OWNER_PHANTOM); + consumer = get_next_index(consumer, sds_ring->num_desc); + } count++; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 665fce5..bd93296 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -787,6 +787,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->max_sds_rings > 1) netxen_config_rss(adapter, 1); + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_linkevent_request(adapter, 1); + return 0; } @@ -1493,26 +1496,9 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter) return rv; } -static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) +void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup) { struct net_device *netdev = adapter->netdev; - u32 val, port, linkup; - - port = adapter->physical_port; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE_P3); - val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); - linkup = (val == XG_LINK_UP_P3); - } else { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE); - if (adapter->ahw.port_type == NETXEN_NIC_GBE) - linkup = (val >> port) & 1; - else { - val = (val >> port*8) & 0xff; - linkup = (val == XG_LINK_UP); - } - } if (adapter->ahw.linkup && !linkup) { printk(KERN_INFO "%s: %s NIC Link is down\n", @@ -1523,7 +1509,9 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) netif_stop_queue(netdev); } - netxen_nic_set_link_parameters(adapter); + if (!adapter->has_link_events) + netxen_nic_set_link_parameters(adapter); + } else if (!adapter->ahw.linkup && linkup) { printk(KERN_INFO "%s: %s NIC Link is up\n", netxen_nic_driver_name, netdev->name); @@ -1533,10 +1521,34 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) netif_wake_queue(netdev); } - netxen_nic_set_link_parameters(adapter); + if (!adapter->has_link_events) + netxen_nic_set_link_parameters(adapter); } } +static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) +{ + u32 val, port, linkup; + + port = adapter->physical_port; + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + val = adapter->pci_read_normalize(adapter, CRB_XG_STATE_P3); + val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); + linkup = (val == XG_LINK_UP_P3); + } else { + val = adapter->pci_read_normalize(adapter, CRB_XG_STATE); + if (adapter->ahw.port_type == NETXEN_NIC_GBE) + linkup = (val >> port) & 1; + else { + val = (val >> port*8) & 0xff; + linkup = (val == XG_LINK_UP); + } + } + + netxen_advert_link_change(adapter, linkup); +} + static void netxen_watchdog(unsigned long v) { struct netxen_adapter *adapter = (struct netxen_adapter *)v; @@ -1552,7 +1564,8 @@ void netxen_watchdog_task(struct work_struct *work) if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter)) return; - netxen_nic_handle_phy_intr(adapter); + if (!adapter->has_link_events) + netxen_nic_handle_phy_intr(adapter); if (netif_running(adapter->netdev)) mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 18ea35d..ecd622e 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -134,6 +134,7 @@ #define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) #define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) #define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) +#define CRB_FW_CAPABILITIES_1 NETXEN_NIC_REG(0x128) #define INTR_SCHEME_PERPORT 0x1 #define MSI_MODE_MULTIFUNC 0x1 -- cgit v0.10.2 From 71dcddbdd35487eb931aa8aab28a2df474008754 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:43 +0000 Subject: netxen: allocate status rings dynamically This reduces netxen_adapter footprint when rss (msi-x) is disabled. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index f4d7e2d..e0f329f 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -762,7 +762,7 @@ struct netxen_recv_context { u16 virt_port; struct nx_host_rds_ring rds_rings[NUM_RCV_DESC_RINGS]; - struct nx_host_sds_ring sds_rings[NUM_STS_DESC_RINGS]; + struct nx_host_sds_ring *sds_rings; }; /* New HW context creation */ @@ -1203,10 +1203,10 @@ struct netxen_adapter { spinlock_t tx_clean_lock; - u32 num_txd; - u32 num_rxd; - u32 num_jumbo_rxd; - u32 num_lro_rxd; + u16 num_txd; + u16 num_rxd; + u16 num_jumbo_rxd; + u16 num_lro_rxd; u8 max_rds_rings; u8 max_sds_rings; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index bd93296..cbd47ae 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -153,7 +153,24 @@ static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring) adapter->legacy_intr.tgt_mask_reg, 0xfbff); } +static int +netxen_alloc_sds_rings(struct netxen_recv_context *recv_ctx, int count) +{ + int size = sizeof(struct nx_host_sds_ring) * count; + + recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL); + + return (recv_ctx->sds_rings == NULL); +} + static void +netxen_free_sds_rings(struct netxen_recv_context *recv_ctx) +{ + if (recv_ctx->sds_rings != NULL) + kfree(recv_ctx->sds_rings); +} + +static int netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev) { int ring; @@ -165,11 +182,16 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev) else adapter->max_sds_rings = 1; + if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) + return 1; + for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; netif_napi_add(netdev, &sds_ring->napi, netxen_nic_poll, NETXEN_NETDEV_WEIGHT); } + + return 0; } static void @@ -1028,7 +1050,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->irq = adapter->msix_entries[0].vector; - netxen_napi_add(adapter, netdev); + if (netxen_napi_add(adapter, netdev)) + goto err_out_disable_msi; init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &netxen_watchdog; @@ -1110,6 +1133,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netxen_free_adapter_offload(adapter); netxen_teardown_intr(adapter); + netxen_free_sds_rings(&adapter->recv_ctx); netxen_cleanup_pci_map(adapter); -- cgit v0.10.2 From 1fbe63235893e5dce28fe91d8465dd231b0cb3d9 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:44 +0000 Subject: netxen: annotate register access functions o remove unnecessary length parameter since register access width is fixed 4 byte. o remove superfluous pci_read_normalize and pci_write_normalize functions. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e0f329f..1e4190d 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1258,14 +1258,12 @@ struct netxen_adapter { int (*init_port) (struct netxen_adapter *, int); int (*stop_port) (struct netxen_adapter *); - int (*hw_read_wx)(struct netxen_adapter *, ulong, void *, int); - int (*hw_write_wx)(struct netxen_adapter *, ulong, void *, int); + u32 (*hw_read_wx)(struct netxen_adapter *, ulong); + int (*hw_write_wx)(struct netxen_adapter *, ulong, u32); int (*pci_mem_read)(struct netxen_adapter *, u64, void *, int); int (*pci_mem_write)(struct netxen_adapter *, u64, void *, int); int (*pci_write_immediate)(struct netxen_adapter *, u64, u32); u32 (*pci_read_immediate)(struct netxen_adapter *, u64); - void (*pci_write_normalize)(struct netxen_adapter *, u64, u32); - u32 (*pci_read_normalize)(struct netxen_adapter *, u64); unsigned long (*pci_set_window)(struct netxen_adapter *, unsigned long long); @@ -1302,46 +1300,6 @@ struct netxen_adapter { #define netxen_get_dma_watchdog_disabled(config_word) \ (((config_word) >> 1) & 0x1) -/* Max number of xmit producer threads that can run simultaneously */ -#define MAX_XMIT_PRODUCERS 16 - -#define PCI_OFFSET_FIRST_RANGE(adapter, off) \ - ((adapter)->ahw.pci_base0 + (off)) -#define PCI_OFFSET_SECOND_RANGE(adapter, off) \ - ((adapter)->ahw.pci_base1 + (off) - SECOND_PAGE_GROUP_START) -#define PCI_OFFSET_THIRD_RANGE(adapter, off) \ - ((adapter)->ahw.pci_base2 + (off) - THIRD_PAGE_GROUP_START) - -static inline void __iomem *pci_base_offset(struct netxen_adapter *adapter, - unsigned long off) -{ - if ((off < FIRST_PAGE_GROUP_END) && (off >= FIRST_PAGE_GROUP_START)) { - return (adapter->ahw.pci_base0 + off); - } else if ((off < SECOND_PAGE_GROUP_END) && - (off >= SECOND_PAGE_GROUP_START)) { - return (adapter->ahw.pci_base1 + off - SECOND_PAGE_GROUP_START); - } else if ((off < THIRD_PAGE_GROUP_END) && - (off >= THIRD_PAGE_GROUP_START)) { - return (adapter->ahw.pci_base2 + off - THIRD_PAGE_GROUP_START); - } - return NULL; -} - -static inline void __iomem *pci_base(struct netxen_adapter *adapter, - unsigned long off) -{ - if ((off < FIRST_PAGE_GROUP_END) && (off >= FIRST_PAGE_GROUP_START)) { - return adapter->ahw.pci_base0; - } else if ((off < SECOND_PAGE_GROUP_END) && - (off >= SECOND_PAGE_GROUP_START)) { - return adapter->ahw.pci_base1; - } else if ((off < THIRD_PAGE_GROUP_END) && - (off >= THIRD_PAGE_GROUP_START)) { - return adapter->ahw.pci_base2; - } - return NULL; -} - int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); @@ -1357,18 +1315,17 @@ int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu); void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val); int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off); void netxen_nic_write_w0(struct netxen_adapter *adapter, u32 index, u32 value); -void netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index, u32 *value); +u32 netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index); void netxen_nic_write_w1(struct netxen_adapter *adapter, u32 index, u32 value); -void netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index, u32 *value); +u32 netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index); int netxen_nic_get_board_info(struct netxen_adapter *adapter); void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); -int netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len); +u32 netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off); int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len); + ulong off, u32 data); int netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, u64 off, void *data, int size); int netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, @@ -1384,10 +1341,9 @@ unsigned long netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, void netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, u32 wndw); -int netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len); +u32 netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off); int netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len); + ulong off, u32 data); int netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, u64 off, void *data, int size); int netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, @@ -1514,9 +1470,8 @@ dma_watchdog_shutdown_request(struct netxen_adapter *adapter) u32 ctrl; /* check if already inactive */ - if (adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4)) - printk(KERN_ERR "failed to read dma watchdog status\n"); + ctrl = adapter->hw_read_wx(adapter, + NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); if (netxen_get_dma_watchdog_enabled(ctrl) == 0) return 1; @@ -1534,9 +1489,8 @@ dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter) { u32 ctrl; - if (adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4)) - printk(KERN_ERR "failed to read dma watchdog status\n"); + ctrl = adapter->hw_read_wx(adapter, + NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); return (netxen_get_dma_watchdog_enabled(ctrl) == 0); } @@ -1546,9 +1500,8 @@ dma_watchdog_wakeup(struct netxen_adapter *adapter) { u32 ctrl; - if (adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4)) - printk(KERN_ERR "failed to read dma watchdog status\n"); + ctrl = adapter->hw_read_wx(adapter, + NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); if (netxen_get_dma_watchdog_enabled(ctrl)) return 1; diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 7943351..7a13ee8 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -41,8 +41,8 @@ netxen_api_lock(struct netxen_adapter *adapter) for (;;) { /* Acquire PCIE HW semaphore5 */ - netxen_nic_read_w0(adapter, - NETXEN_PCIE_REG(PCIE_SEM5_LOCK), &done); + done = netxen_nic_read_w0(adapter, + NETXEN_PCIE_REG(PCIE_SEM5_LOCK)); if (done == 1) break; @@ -65,11 +65,9 @@ netxen_api_lock(struct netxen_adapter *adapter) static int netxen_api_unlock(struct netxen_adapter *adapter) { - u32 val; - /* Release PCIE HW semaphore5 */ netxen_nic_read_w0(adapter, - NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK), &val); + NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK)); return 0; } @@ -86,7 +84,7 @@ netxen_poll_rsp(struct netxen_adapter *adapter) if (++timeout > NX_OS_CRB_RETRY_COUNT) return NX_CDRP_RSP_TIMEOUT; - netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET, &rsp); + rsp = netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET); } while (!NX_CDRP_IS_RSP(rsp)); return rsp; @@ -125,7 +123,7 @@ netxen_issue_cmd(struct netxen_adapter *adapter, rcode = NX_RCODE_TIMEOUT; } else if (rsp == NX_CDRP_RSP_FAIL) { - netxen_nic_read_w1(adapter, NX_ARG1_CRB_OFFSET, &rcode); + rcode = netxen_nic_read_w1(adapter, NX_ARG1_CRB_OFFSET); printk(KERN_ERR "%s: failed card response code:0x%x\n", netxen_nic_driver_name, rcode); @@ -517,11 +515,11 @@ netxen_init_old_ctx(struct netxen_adapter *adapter) adapter->ctx_desc->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr); adapter->ctx_desc->sts_ring_size = cpu_to_le32(sds_ring->num_desc); - adapter->pci_write_normalize(adapter, CRB_CTX_ADDR_REG_LO(func_id), + adapter->hw_write_wx(adapter, CRB_CTX_ADDR_REG_LO(func_id), lower32(adapter->ctx_desc_phys_addr)); - adapter->pci_write_normalize(adapter, CRB_CTX_ADDR_REG_HI(func_id), + adapter->hw_write_wx(adapter, CRB_CTX_ADDR_REG_HI(func_id), upper32(adapter->ctx_desc_phys_addr)); - adapter->pci_write_normalize(adapter, CRB_CTX_SIGNATURE_REG(func_id), + adapter->hw_write_wx(adapter, CRB_CTX_SIGNATURE_REG(func_id), NETXEN_CTX_SIGNATURE | func_id); return 0; } diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 5fde9e0..6c5a111 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -92,11 +92,11 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) strncpy(drvinfo->driver, netxen_nic_driver_name, 32); strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32); write_lock_irqsave(&adapter->adapter_lock, flags); - fw_major = adapter->pci_read_normalize(adapter, + fw_major = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MAJOR); - fw_minor = adapter->pci_read_normalize(adapter, + fw_minor = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MINOR); - fw_build = adapter->pci_read_normalize(adapter, + fw_build = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_SUB); write_unlock_irqrestore(&adapter->adapter_lock, flags); sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); @@ -135,7 +135,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { u32 val; - adapter->hw_read_wx(adapter, NETXEN_PORT_MODE_ADDR, &val, 4); + val = adapter->hw_read_wx(adapter, NETXEN_PORT_MODE_ADDR); if (val == NETXEN_PORT_MODE_802_3_AP) { ecmd->supported = SUPPORTED_1000baseT_Full; ecmd->advertising = ADVERTISED_1000baseT_Full; @@ -156,8 +156,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { u16 pcifn = adapter->ahw.pci_func; - adapter->hw_read_wx(adapter, - P3_LINK_SPEED_REG(pcifn), &val, 4); + val = adapter->hw_read_wx(adapter, + P3_LINK_SPEED_REG(pcifn)); ecmd->speed = P3_LINK_SPEED_MHZ * P3_LINK_SPEED_VAL(pcifn, val); } else @@ -423,12 +423,12 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; /* which mode */ - adapter->hw_read_wx(adapter, NETXEN_NIU_MODE, ®s_buff[0], 4); + regs_buff[0] = adapter->hw_read_wx(adapter, NETXEN_NIU_MODE); mode = regs_buff[0]; /* Common registers to all the modes */ - adapter->hw_read_wx(adapter, - NETXEN_NIU_STRAP_VALUE_SAVE_HIGHER, ®s_buff[2], 4); + regs_buff[2] = adapter->hw_read_wx(adapter, + NETXEN_NIU_STRAP_VALUE_SAVE_HIGHER); /* GB/XGB Mode */ mode = (mode / 2) - 1; window = 0; @@ -439,9 +439,8 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) window = adapter->physical_port * NETXEN_NIC_PORT_WINDOW; - adapter->hw_read_wx(adapter, - niu_registers[mode].reg[i - 3] + window, - ®s_buff[i], 4); + regs_buff[i] = adapter->hw_read_wx(adapter, + niu_registers[mode].reg[i - 3] + window); } } @@ -465,7 +464,7 @@ static u32 netxen_nic_test_link(struct net_device *dev) return !val; } } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE); + val = adapter->hw_read_wx(adapter, CRB_XG_STATE); return (val == XG_LINK_UP) ? 0 : 1; } return -EIO; @@ -529,10 +528,10 @@ netxen_nic_get_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ - netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port), - &val); + val = netxen_nic_read_w0(adapter, + NETXEN_NIU_GB_MAC_CONFIG_0(port)); pause->rx_pause = netxen_gb_get_rx_flowctl(val); - netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); + val = netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL); switch (port) { case 0: pause->tx_pause = !(netxen_gb_get_gb0_mask(val)); @@ -552,7 +551,7 @@ netxen_nic_get_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); + val = netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL); if (port == 0) pause->tx_pause = !(netxen_xg_get_xg0_mask(val)); else @@ -575,8 +574,8 @@ netxen_nic_set_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), &val); + val = netxen_nic_read_w0(adapter, + NETXEN_NIU_GB_MAC_CONFIG_0(port)); if (pause->rx_pause) netxen_gb_rx_flowctl(val); @@ -586,7 +585,7 @@ netxen_nic_set_pauseparam(struct net_device *dev, netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), val); /* set autoneg */ - netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); + val = netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL); switch (port) { case 0: if (pause->tx_pause) @@ -618,7 +617,7 @@ netxen_nic_set_pauseparam(struct net_device *dev, } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) return -EIO; - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); + val = netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL); if (port == 0) { if (pause->tx_pause) netxen_xg_unset_xg0_mask(val); @@ -644,14 +643,14 @@ static int netxen_nic_reg_test(struct net_device *dev) struct netxen_adapter *adapter = netdev_priv(dev); u32 data_read, data_written; - netxen_nic_read_w0(adapter, NETXEN_PCIX_PH_REG(0), &data_read); + data_read = netxen_nic_read_w0(adapter, NETXEN_PCIX_PH_REG(0)); if ((data_read & 0xffff) != PHAN_VENDOR_ID) return 1; data_written = (u32)0xa5a5a5a5; netxen_nic_reg_write(adapter, CRB_SCRATCHPAD_TEST, data_written); - data_read = adapter->pci_read_normalize(adapter, CRB_SCRATCHPAD_TEST); + data_read = adapter->hw_read_wx(adapter, CRB_SCRATCHPAD_TEST); if (data_written != data_read) return 1; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 33444a2..87cda65 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -63,6 +63,31 @@ static inline void writeq(u64 val, void __iomem *addr) } #endif +#define ADDR_IN_RANGE(addr, low, high) \ + (((addr) < (high)) && ((addr) >= (low))) + +#define PCI_OFFSET_FIRST_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base0 + (off)) +#define PCI_OFFSET_SECOND_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base1 + (off) - SECOND_PAGE_GROUP_START) +#define PCI_OFFSET_THIRD_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base2 + (off) - THIRD_PAGE_GROUP_START) + +static void __iomem *pci_base_offset(struct netxen_adapter *adapter, + unsigned long off) +{ + if (ADDR_IN_RANGE(off, FIRST_PAGE_GROUP_START, FIRST_PAGE_GROUP_END)) + return PCI_OFFSET_FIRST_RANGE(adapter, off); + + if (ADDR_IN_RANGE(off, SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_END)) + return PCI_OFFSET_SECOND_RANGE(adapter, off); + + if (ADDR_IN_RANGE(off, THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_END)) + return PCI_OFFSET_THIRD_RANGE(adapter, off); + + return NULL; +} + #define CRB_WIN_LOCK_TIMEOUT 100000000 static crb_128M_2M_block_map_t crb_128M_2M_map[64] = { {{{0, 0, 0, 0} } }, /* 0: PCI */ @@ -294,18 +319,8 @@ static unsigned crb_hub_agt[64] = /* PCI Windowing for DDR regions. */ -#define ADDR_IN_RANGE(addr, low, high) \ - (((addr) <= (high)) && ((addr) >= (low))) - #define NETXEN_WINDOW_ONE 0x2000000 /*CRB Window: bit 25 of CRB address */ -#define NETXEN_NIC_ZERO_PAUSE_ADDR 0ULL -#define NETXEN_NIC_UNIT_PAUSE_ADDR 0x200ULL -#define NETXEN_NIC_EPG_PAUSE_ADDR1 0x2200010000c28001ULL -#define NETXEN_NIC_EPG_PAUSE_ADDR2 0x0100088866554433ULL - -#define NETXEN_NIC_WINDOW_MARGIN 0x100000 - int netxen_nic_set_mac(struct net_device *netdev, void *p) { struct netxen_adapter *adapter = netdev_priv(netdev); @@ -346,9 +361,9 @@ netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter) if (adapter->mc_enabled) return 0; - adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + val = adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG); val |= (1UL << (28+port)); - adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); /* add broadcast addr to filter */ val = 0xffffff; @@ -377,9 +392,9 @@ netxen_nic_disable_mcast_filter(struct netxen_adapter *adapter) if (!adapter->mc_enabled) return 0; - adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + val = adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG); val &= ~(1UL << (28+port)); - adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); val = MAC_HI(addr); netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val); @@ -848,8 +863,8 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) crbaddr = CRB_MAC_BLOCK_START + (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1)); - adapter->hw_read_wx(adapter, crbaddr, &mac_lo, 4); - adapter->hw_read_wx(adapter, crbaddr+4, &mac_hi, 4); + mac_lo = adapter->hw_read_wx(adapter, crbaddr); + mac_hi = adapter->hw_read_wx(adapter, crbaddr+4); if (pci_func & 1) *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16)); @@ -867,8 +882,8 @@ static int crb_win_lock(struct netxen_adapter *adapter) while (!done) { /* acquire semaphore3 from PCI HW block */ - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(PCIE_SEM7_LOCK), &done, 4); + done = adapter->hw_read_wx(adapter, + NETXEN_PCIE_REG(PCIE_SEM7_LOCK)); if (done == 1) break; if (timeout >= CRB_WIN_LOCK_TIMEOUT) @@ -885,8 +900,8 @@ static void crb_win_unlock(struct netxen_adapter *adapter) { int val; - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK), &val, 4); + val = adapter->hw_read_wx(adapter, + NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK)); } /* @@ -1022,7 +1037,7 @@ netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname, dev_info(&pdev->dev, "loading firmware from flash\n"); if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1); if (fw) { @@ -1075,12 +1090,12 @@ netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname, msleep(1); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d); else { - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff); - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0); } @@ -1168,8 +1183,8 @@ request_mn: netxen_rom_fast_read(adapter, NX_FW_VERSION_OFFSET, (int *)&flashed_ver); if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { - adapter->hw_read_wx(adapter, - NX_PEG_TUNE_CAPABILITY, &capability, 4); + capability = adapter->hw_read_wx(adapter, + NX_PEG_TUNE_CAPABILITY); if (capability & NX_PEG_TUNE_MN_PRESENT) { fw_type = NX_P3_MN_ROMIMAGE; goto request_fw; @@ -1209,13 +1224,10 @@ load_fw: } int -netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data) { void __iomem *addr; - BUG_ON(len != 4); - if (ADDR_IN_WINDOW1(off)) { addr = NETXEN_CRB_NORMALIZE(adapter, off); } else { /* Window 0 */ @@ -1228,7 +1240,7 @@ netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, return 1; } - writel(*(u32 *) data, addr); + writel(data, addr); if (!ADDR_IN_WINDOW1(off)) netxen_nic_pci_change_crbwindow_128M(adapter, 1); @@ -1236,13 +1248,11 @@ netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, return 0; } -int -netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +u32 +netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off) { void __iomem *addr; - - BUG_ON(len != 4); + u32 data; if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ addr = NETXEN_CRB_NORMALIZE(adapter, off); @@ -1256,24 +1266,21 @@ netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, return 1; } - *(u32 *)data = readl(addr); + data = readl(addr); if (!ADDR_IN_WINDOW1(off)) netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 0; + return data; } int -netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data) { unsigned long flags = 0; int rv; - BUG_ON(len != 4); - - rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len); + rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, 4); if (rv == -1) { printk(KERN_ERR "%s: invalid offset: 0x%016lx\n", @@ -1286,26 +1293,24 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, write_lock_irqsave(&adapter->adapter_lock, flags); crb_win_lock(adapter); netxen_nic_pci_set_crbwindow_2M(adapter, &off); - writel(*(uint32_t *)data, (void __iomem *)off); + writel(data, (void __iomem *)off); crb_win_unlock(adapter); write_unlock_irqrestore(&adapter->adapter_lock, flags); } else - writel(*(uint32_t *)data, (void __iomem *)off); + writel(data, (void __iomem *)off); return 0; } -int -netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +u32 +netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) { unsigned long flags = 0; int rv; + u32 data; - BUG_ON(len != 4); - - rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len); + rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, 4); if (rv == -1) { printk(KERN_ERR "%s: invalid offset: 0x%016lx\n", @@ -1318,47 +1323,45 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, write_lock_irqsave(&adapter->adapter_lock, flags); crb_win_lock(adapter); netxen_nic_pci_set_crbwindow_2M(adapter, &off); - *(uint32_t *)data = readl((void __iomem *)off); + data = readl((void __iomem *)off); crb_win_unlock(adapter); write_unlock_irqrestore(&adapter->adapter_lock, flags); } else - *(uint32_t *)data = readl((void __iomem *)off); + data = readl((void __iomem *)off); - return 0; + return data; } void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val) { - adapter->hw_write_wx(adapter, off, &val, 4); + adapter->hw_write_wx(adapter, off, val); } int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off) { - int val; - adapter->hw_read_wx(adapter, off, &val, 4); - return val; + return adapter->hw_read_wx(adapter, off); } /* Change the window to 0, write and change back to window 1. */ void netxen_nic_write_w0(struct netxen_adapter *adapter, u32 index, u32 value) { - adapter->hw_write_wx(adapter, index, &value, 4); + adapter->hw_write_wx(adapter, index, value); } /* Change the window to 0, read and change back to window 1. */ -void netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index, u32 *value) +u32 netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index) { - adapter->hw_read_wx(adapter, index, value, 4); + return adapter->hw_read_wx(adapter, index); } void netxen_nic_write_w1(struct netxen_adapter *adapter, u32 index, u32 value) { - adapter->hw_write_wx(adapter, index, &value, 4); + adapter->hw_write_wx(adapter, index, value); } -void netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index, u32 *value) +u32 netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index) { - adapter->hw_read_wx(adapter, index, value, 4); + return adapter->hw_read_wx(adapter, index); } /* @@ -1461,17 +1464,6 @@ u32 netxen_nic_pci_read_immediate_128M(struct netxen_adapter *adapter, u64 off) return readl((void __iomem *)(pci_base_offset(adapter, off))); } -void netxen_nic_pci_write_normalize_128M(struct netxen_adapter *adapter, - u64 off, u32 data) -{ - writel(data, NETXEN_CRB_NORMALIZE(adapter, off)); -} - -u32 netxen_nic_pci_read_normalize_128M(struct netxen_adapter *adapter, u64 off) -{ - return readl(NETXEN_CRB_NORMALIZE(adapter, off)); -} - unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, unsigned long long addr) @@ -1485,10 +1477,9 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, adapter->ahw.ddr_mn_window = window; adapter->hw_write_wx(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &window, 4); - adapter->hw_read_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &win_read, 4); + window); + win_read = adapter->hw_read_wx(adapter, + adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); if ((win_read << 17) != window) { printk(KERN_INFO "Written MNwin (0x%x) != " "Read MNwin (0x%x)\n", window, win_read); @@ -1505,10 +1496,9 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, adapter->ahw.ddr_mn_window = window; adapter->hw_write_wx(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &window, 4); - adapter->hw_read_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &win_read, 4); + window); + win_read = adapter->hw_read_wx(adapter, + adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); if ((win_read >> 7) != window) { printk(KERN_INFO "%s: Written OCMwin (0x%x) != " "Read OCMwin (0x%x)\n", @@ -1523,10 +1513,9 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, adapter->ahw.qdr_sn_window = window; adapter->hw_write_wx(adapter, adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, - &window, 4); - adapter->hw_read_wx(adapter, - adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, - &win_read, 4); + window); + win_read = adapter->hw_read_wx(adapter, + adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE); if (win_read != window) { printk(KERN_INFO "%s: Written MSwin (0x%x) != " "Read MSwin (0x%x)\n", @@ -1973,26 +1962,26 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, for (i = 0; i < loop; i++) { temp = off8 + (i << 3); adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_ADDR_LO, &temp, 4); + mem_crb+MIU_TEST_AGT_ADDR_LO, temp); temp = 0; adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_ADDR_HI, &temp, 4); + mem_crb+MIU_TEST_AGT_ADDR_HI, temp); temp = word[i] & 0xffffffff; adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_WRDATA_LO, &temp, 4); + mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); temp = (word[i] >> 32) & 0xffffffff; adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_WRDATA_HI, &temp, 4); + mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_CTRL, &temp, 4); + mem_crb+MIU_TEST_AGT_CTRL, temp); temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_CTRL, &temp, 4); + mem_crb+MIU_TEST_AGT_CTRL, temp); for (j = 0; j < MAX_CTL_CHECK; j++) { - adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + temp = adapter->hw_read_wx(adapter, + mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2050,20 +2039,20 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, for (i = 0; i < loop; i++) { temp = off8 + (i << 3); adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_ADDR_LO, &temp, 4); + mem_crb + MIU_TEST_AGT_ADDR_LO, temp); temp = 0; adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_ADDR_HI, &temp, 4); + mem_crb + MIU_TEST_AGT_ADDR_HI, temp); temp = MIU_TA_CTL_ENABLE; adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + mem_crb + MIU_TEST_AGT_CTRL, temp); temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + mem_crb + MIU_TEST_AGT_CTRL, temp); for (j = 0; j < MAX_CTL_CHECK; j++) { - adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + temp = adapter->hw_read_wx(adapter, + mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2078,8 +2067,8 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, start = off0[i] >> 2; end = (off0[i] + sz[i] - 1) >> 2; for (k = start; k <= end; k++) { - adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_RDDATA(k), &temp, 4); + temp = adapter->hw_read_wx(adapter, + mem_crb + MIU_TEST_AGT_RDDATA(k)); word[i] |= ((uint64_t)temp << (32 * k)); } } @@ -2122,29 +2111,14 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, u64 off, u32 data) { - adapter->hw_write_wx(adapter, off, &data, 4); + adapter->hw_write_wx(adapter, off, data); return 0; } u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off) { - u32 temp; - adapter->hw_read_wx(adapter, off, &temp, 4); - return temp; -} - -void netxen_nic_pci_write_normalize_2M(struct netxen_adapter *adapter, - u64 off, u32 data) -{ - adapter->hw_write_wx(adapter, off, &data, 4); -} - -u32 netxen_nic_pci_read_normalize_2M(struct netxen_adapter *adapter, u64 off) -{ - u32 temp; - adapter->hw_read_wx(adapter, off, &temp, 4); - return temp; + return adapter->hw_read_wx(adapter, off); } int netxen_nic_get_board_info(struct netxen_adapter *adapter) @@ -2253,7 +2227,7 @@ void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, int data) { - adapter->hw_write_wx(adapter, off, &data, 4); + adapter->hw_write_wx(adapter, off, data); } void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) @@ -2270,8 +2244,8 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) } if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->hw_read_wx(adapter, - NETXEN_PORT_MODE_ADDR, &port_mode, 4); + port_mode = adapter->hw_read_wx(adapter, + NETXEN_PORT_MODE_ADDR); if (port_mode == NETXEN_PORT_MODE_802_3_AP) { adapter->link_speed = SPEED_1000; adapter->link_duplex = DUPLEX_FULL; @@ -2348,9 +2322,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) addr += sizeof(u32); } - adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MAJOR, &fw_major, 4); - adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MINOR, &fw_minor, 4); - adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_SUB, &fw_build, 4); + fw_major = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MAJOR); + fw_minor = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MINOR); + fw_build = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_SUB); adapter->fw_major = fw_major; adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); @@ -2373,8 +2347,7 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) fw_major, fw_minor, fw_build); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - adapter->hw_read_wx(adapter, - NETXEN_MIU_MN_CONTROL, &i, 4); + i = adapter->hw_read_wx(adapter, NETXEN_MIU_MN_CONTROL); adapter->ahw.cut_through = (i & 0x4) ? 1 : 0; dev_info(&pdev->dev, "firmware running in %s mode\n", adapter->ahw.cut_through ? "cut-through" : "legacy"); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 974783c..83116c2 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -368,8 +368,8 @@ static int rom_lock(struct netxen_adapter *adapter) while (!done) { /* acquire semaphore2 from PCI HW block */ - netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK), - &done); + done = netxen_nic_read_w0(adapter, + NETXEN_PCIE_REG(PCIE_SEM2_LOCK)); if (done == 1) break; if (timeout >= rom_lock_timeout) @@ -411,10 +411,8 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter) static void netxen_rom_unlock(struct netxen_adapter *adapter) { - u32 val; - /* release semaphore2 */ - netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK), &val); + netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK)); } @@ -623,7 +621,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) } } - adapter->hw_write_wx(adapter, off, &buf[i].data, 4); + adapter->hw_write_wx(adapter, off, buf[i].data); msleep(init_delay); } @@ -633,8 +631,8 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) /* unreset_net_cache */ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - adapter->hw_read_wx(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, &val, 4); + val = adapter->hw_read_wx(adapter, + NETXEN_ROMUSB_GLB_SW_RESET); netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET, (val & 0xffffff0f)); } @@ -683,12 +681,12 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) hi = (addr >> 32) & 0xffffffff; lo = addr & 0xffffffff; - adapter->pci_write_normalize(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); - adapter->pci_write_normalize(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); + adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); + adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { uint32_t temp = 0; - adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF, &temp, 4); + adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF, temp); } return 0; @@ -730,7 +728,7 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) if (!pegtune_val) { do { - val = adapter->pci_read_normalize(adapter, + val = adapter->hw_read_wx(adapter, CRB_CMDPEG_STATE); if (val == PHAN_INITIALIZE_COMPLETE || @@ -742,7 +740,7 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) } while (--retries); if (!retries) { - pegtune_val = adapter->pci_read_normalize(adapter, + pegtune_val = adapter->hw_read_wx(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE); printk(KERN_WARNING "netxen_phantom_init: init failed, " "pegtune_val=%x\n", pegtune_val); @@ -760,7 +758,7 @@ netxen_receive_peg_ready(struct netxen_adapter *adapter) int retries = 2000; do { - val = adapter->pci_read_normalize(adapter, CRB_RCVPEG_STATE); + val = adapter->hw_read_wx(adapter, CRB_RCVPEG_STATE); if (val == PHAN_PEG_RCV_INITIALIZED) return 0; @@ -786,13 +784,13 @@ int netxen_init_firmware(struct netxen_adapter *adapter) if (err) return err; - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) { @@ -1059,7 +1057,7 @@ skip: if (count) { sds_ring->consumer = consumer; - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, sds_ring->crb_sts_consumer, consumer); } @@ -1178,7 +1176,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, if (count) { rds_ring->producer = producer; - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, rds_ring->crb_rcv_producer, (producer-1) & (rds_ring->num_desc-1)); @@ -1239,7 +1237,7 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, if (count) { rds_ring->producer = producer; - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, rds_ring->crb_rcv_producer, (producer - 1) & (rds_ring->num_desc - 1)); wmb(); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index cbd47ae..31966a0 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -109,7 +109,7 @@ void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring, u32 producer) { - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, tx_ring->crb_cmd_producer, producer); } @@ -122,7 +122,7 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring, u32 consumer) { - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, tx_ring->crb_cmd_consumer, consumer); } @@ -139,14 +139,14 @@ static inline void netxen_nic_disable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0); + adapter->hw_write_wx(adapter, sds_ring->crb_intr_mask, 0); } static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0x1); + adapter->hw_write_wx(adapter, sds_ring->crb_intr_mask, 0x1); if (!NETXEN_IS_MSI_FAMILY(adapter)) adapter->pci_write_immediate(adapter, @@ -309,42 +309,41 @@ netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot) if (first_boot == 0x55555555) { /* This is the first boot after power up */ - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 0; /* PCI bus master workaround */ - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(0x4), &first_boot, 4); + first_boot = adapter->hw_read_wx(adapter, NETXEN_PCIE_REG(0x4)); if (!(first_boot & 0x4)) { first_boot |= 0x4; adapter->hw_write_wx(adapter, - NETXEN_PCIE_REG(0x4), &first_boot, 4); - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(0x4), &first_boot, 4); + NETXEN_PCIE_REG(0x4), first_boot); + first_boot = adapter->hw_read_wx(adapter, + NETXEN_PCIE_REG(0x4)); } /* This is the first boot after power up */ - adapter->hw_read_wx(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, &first_boot, 4); + first_boot = adapter->hw_read_wx(adapter, + NETXEN_ROMUSB_GLB_SW_RESET); if (first_boot != 0x80000f) { /* clear the register for future unloads/loads */ - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, NETXEN_CAM_RAM(0x1fc), 0); return -EIO; } /* Start P2 boot loader */ - val = adapter->pci_read_normalize(adapter, + val = adapter->hw_read_wx(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE); - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE, val | 0x1); timeout = 0; do { msleep(1); - val = adapter->pci_read_normalize(adapter, + val = adapter->hw_read_wx(adapter, NETXEN_CAM_RAM(0x1fc)); if (++timeout > 5000) @@ -365,23 +364,23 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter) if (port_mode == NETXEN_PORT_MODE_802_3_AP) { data = NETXEN_PORT_MODE_802_3_AP; adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_XG) { data = NETXEN_PORT_MODE_XG; adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_AUTO_NEG_1G) { data = NETXEN_PORT_MODE_AUTO_NEG_1G; adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_AUTO_NEG_XG) { data = NETXEN_PORT_MODE_AUTO_NEG_XG; adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NETXEN_PORT_MODE_ADDR, data); } else { data = NETXEN_PORT_MODE_AUTO_NEG; adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NETXEN_PORT_MODE_ADDR, data); } if ((wol_port_mode != NETXEN_PORT_MODE_802_3_AP) && @@ -391,7 +390,7 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter) wol_port_mode = NETXEN_PORT_MODE_AUTO_NEG; } adapter->hw_write_wx(adapter, NETXEN_WOL_PORT_MODE, - &wol_port_mode, 4); + wol_port_mode); } } @@ -572,8 +571,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) adapter->hw_read_wx = netxen_nic_hw_read_wx_128M; adapter->pci_read_immediate = netxen_nic_pci_read_immediate_128M; adapter->pci_write_immediate = netxen_nic_pci_write_immediate_128M; - adapter->pci_read_normalize = netxen_nic_pci_read_normalize_128M; - adapter->pci_write_normalize = netxen_nic_pci_write_normalize_128M; adapter->pci_set_window = netxen_nic_pci_set_window_128M; adapter->pci_mem_read = netxen_nic_pci_mem_read_128M; adapter->pci_mem_write = netxen_nic_pci_mem_write_128M; @@ -595,9 +592,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) adapter->pci_read_immediate = netxen_nic_pci_read_immediate_2M; adapter->pci_write_immediate = netxen_nic_pci_write_immediate_2M; - adapter->pci_read_normalize = netxen_nic_pci_read_normalize_2M; - adapter->pci_write_normalize = - netxen_nic_pci_write_normalize_2M; adapter->pci_set_window = netxen_nic_pci_set_window_2M; adapter->pci_mem_read = netxen_nic_pci_mem_read_2M; adapter->pci_mem_write = netxen_nic_pci_mem_write_2M; @@ -680,7 +674,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) if (!first_driver) return 0; - first_boot = adapter->pci_read_normalize(adapter, + first_boot = adapter->hw_read_wx(adapter, NETXEN_CAM_RAM(0x1fc)); err = netxen_check_hw_init(adapter, first_boot); @@ -690,7 +684,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) } if (first_boot != 0x55555555) { - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, CRB_CMDPEG_STATE, 0); netxen_pinit_from_rom(adapter, 0); msleep(1); @@ -723,7 +717,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) val = (_NETXEN_NIC_LINUX_MAJOR << 16) | ((_NETXEN_NIC_LINUX_MINOR << 8)) | (_NETXEN_NIC_LINUX_SUBVERSION); - adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, val); + adapter->hw_write_wx(adapter, CRB_DRIVER_VERSION, val); /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); @@ -1038,7 +1032,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ adapter->physical_port = adapter->portnum; if (adapter->fw_major < 4) { - i = adapter->pci_read_normalize(adapter, + i = adapter->hw_read_wx(adapter, CRB_V2P(adapter->portnum)); if (i != 0x55555555) adapter->physical_port = i; @@ -1486,7 +1480,7 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter) uint32_t temp, temp_state, temp_val; int rv = 0; - temp = adapter->pci_read_normalize(adapter, CRB_TEMP_STATE); + temp = adapter->hw_read_wx(adapter, CRB_TEMP_STATE); temp_state = nx_get_temp_state(temp); temp_val = nx_get_temp_val(temp); @@ -1557,11 +1551,11 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) port = adapter->physical_port; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE_P3); + val = adapter->hw_read_wx(adapter, CRB_XG_STATE_P3); val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); linkup = (val == XG_LINK_UP_P3); } else { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE); + val = adapter->hw_read_wx(adapter, CRB_XG_STATE); if (adapter->ahw.port_type == NETXEN_NIC_GBE) linkup = (val >> port) & 1; else { @@ -1656,14 +1650,14 @@ static irqreturn_t netxen_intr(int irq, void *data) } else { unsigned long our_int = 0; - our_int = adapter->pci_read_normalize(adapter, CRB_INT_VECTOR); + our_int = adapter->hw_read_wx(adapter, CRB_INT_VECTOR); /* not our interrupt */ if (!test_and_clear_bit((7 + adapter->portnum), &our_int)) return IRQ_NONE; /* claim interrupt */ - adapter->pci_write_normalize(adapter, + adapter->hw_write_wx(adapter, CRB_INT_VECTOR, (our_int & 0xffffffff)); } diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 3310471..b54a63a 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -105,9 +105,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, * so it cannot be in reset */ - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) - return -EIO; + mac_cfg0 = adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); if (netxen_gb_get_soft_reset(mac_cfg0)) { __u32 temp; temp = 0; @@ -116,8 +114,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, netxen_gb_tx_reset_mac(temp); netxen_gb_rx_reset_mac(temp); if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &temp, 4)) + NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) return -EIO; restore = 1; } @@ -125,43 +122,38 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, address = 0; netxen_gb_mii_mgmt_reg_addr(address, reg); netxen_gb_mii_mgmt_phy_addr(address, phy); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), - &address, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) return -EIO; command = 0; /* turn off any prior activity */ - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), - &command, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; /* send read command */ netxen_gb_mii_mgmt_set_read_cycle(command); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), - &command, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; status = 0; do { - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(0), - &status, 4)) - return -EIO; + status = adapter->hw_read_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); timeout++; } while ((netxen_get_gb_mii_mgmt_busy(status) || netxen_get_gb_mii_mgmt_notvalid(status)) && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); if (timeout < NETXEN_NIU_PHY_WAITMAX) { - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_STATUS(0), - readval, 4)) - return -EIO; + *readval = adapter->hw_read_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_STATUS(0)); result = 0; } else result = -1; if (restore) if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) + NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; phy_unlock(adapter); return result; @@ -197,9 +189,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, * cannot be in reset */ - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) - return -EIO; + mac_cfg0 = adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); if (netxen_gb_get_soft_reset(mac_cfg0)) { __u32 temp; temp = 0; @@ -209,34 +199,31 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, netxen_gb_rx_reset_mac(temp); if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &temp, 4)) + NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) return -EIO; restore = 1; } command = 0; /* turn off any prior activity */ - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), - &command, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; address = 0; netxen_gb_mii_mgmt_reg_addr(address, reg); netxen_gb_mii_mgmt_phy_addr(address, phy); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), - &address, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) return -EIO; - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0), - &val, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_CTRL(0), val)) return -EIO; status = 0; do { - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(0), - &status, 4)) - return -EIO; + status = adapter->hw_read_wx(adapter, + NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); timeout++; } while ((netxen_get_gb_mii_mgmt_busy(status)) && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); @@ -249,8 +236,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, /* restore the state of port 0 MAC in case we tampered with it */ if (restore) if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) + NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; return result; @@ -473,12 +459,10 @@ static int netxen_niu_macaddr_get(struct netxen_adapter *adapter, if ((phy < 0) || (phy > 3)) return -EINVAL; - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), - &stationhigh, 4)) - return -EIO; - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), - &stationlow, 4)) - return -EIO; + stationhigh = adapter->hw_read_wx(adapter, + NETXEN_NIU_GB_STATION_ADDR_0(phy)); + stationlow = adapter->hw_read_wx(adapter, + NETXEN_NIU_GB_STATION_ADDR_1(phy)); ((__le32 *)val)[1] = cpu_to_le32(stationhigh); ((__le32 *)val)[0] = cpu_to_le32(stationlow); @@ -508,13 +492,13 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, memcpy(temp + 2, addr, 2); val = le32_to_cpu(*(__le32 *)temp); if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_1(phy), &val, 4)) + NETXEN_NIU_GB_STATION_ADDR_1(phy), val)) return -EIO; memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32)); val = le32_to_cpu(*(__le32 *)temp); if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) + NETXEN_NIU_GB_STATION_ADDR_0(phy), val)) return -2; netxen_niu_macaddr_get(adapter, @@ -545,8 +529,8 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) return -EINVAL; mac_cfg0 = 0; netxen_gb_soft_reset(mac_cfg0); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - &mac_cfg0, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_GB_MAC_CONFIG_0(port), mac_cfg0)) return -EIO; return 0; } @@ -565,7 +549,7 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) mac_cfg = 0; if (adapter->hw_write_wx(adapter, - NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), &mac_cfg, 4)) + NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) return -EIO; return 0; } @@ -581,9 +565,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, return -EINVAL; /* save previous contents */ - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, - ®, 4)) - return -EIO; + reg = adapter->hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR); if (mode == NETXEN_NIU_PROMISC_MODE) { switch (port) { case 0: @@ -619,8 +601,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, return -EIO; } } - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, - ®, 4)) + if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, reg)) return -EIO; return 0; } @@ -647,28 +628,28 @@ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, case 0: memcpy(temp + 2, addr, 2); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, - &val, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_XGE_STATION_ADDR_0_1, val)) return -EIO; memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, - &val, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_XGE_STATION_ADDR_0_HI, val)) return -EIO; break; case 1: memcpy(temp + 2, addr, 2); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, - &val, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_XG1_STATION_ADDR_0_1, val)) return -EIO; memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, - &val, 4)) + if (adapter->hw_write_wx(adapter, + NETXEN_NIU_XG1_STATION_ADDR_0_HI, val)) return -EIO; break; @@ -689,9 +670,8 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, if (port > NETXEN_NIU_MAX_XG_PORTS) return -EINVAL; - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), ®, 4)) - return -EIO; + reg = adapter->hw_read_wx(adapter, + NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); if (mode == NETXEN_NIU_PROMISC_MODE) reg = (reg | 0x2000UL); else -- cgit v0.10.2 From f98a9f693b5f4919d9c4085a2fd8d67c7e152f3e Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:45 +0000 Subject: netxen: sanitize function names Replace superfluous wrapper functions with two macros: NXWR32 replaces netxen_nic_reg_write, netxen_nic_write_w0, netxen_nic_read_w1, netxen_crb_writelit_adapter. NXRD32 replaces netxen_nic_reg_read, netxen_nic_read_w0, netxen_nic_read_w1. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 1e4190d..f13fd02 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1312,12 +1312,11 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, /* Functions available from netxen_nic_hw.c */ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu); int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu); -void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val); -int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off); -void netxen_nic_write_w0(struct netxen_adapter *adapter, u32 index, u32 value); -u32 netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index); -void netxen_nic_write_w1(struct netxen_adapter *adapter, u32 index, u32 value); -u32 netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index); + +#define NXRD32(adapter, off) \ + (adapter->hw_read_wx(adapter, off)) +#define NXWR32(adapter, off, val) \ + (adapter->hw_write_wx(adapter, off, val)) int netxen_nic_get_board_info(struct netxen_adapter *adapter); void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); @@ -1348,8 +1347,6 @@ int netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, u64 off, void *data, int size); int netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, u64 off, void *data, int size); -void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, - unsigned long off, int data); int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, u64 off, u32 data); u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off); @@ -1478,8 +1475,7 @@ dma_watchdog_shutdown_request(struct netxen_adapter *adapter) /* Send the disable request */ netxen_set_dma_watchdog_disable_req(ctrl); - netxen_crb_writelit_adapter(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); + NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); return 0; } @@ -1509,8 +1505,7 @@ dma_watchdog_wakeup(struct netxen_adapter *adapter) /* send the wakeup request */ netxen_set_dma_watchdog_enable_req(ctrl); - netxen_crb_writelit_adapter(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); + NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); return 0; } diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 7a13ee8..32f4839 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -41,8 +41,7 @@ netxen_api_lock(struct netxen_adapter *adapter) for (;;) { /* Acquire PCIE HW semaphore5 */ - done = netxen_nic_read_w0(adapter, - NETXEN_PCIE_REG(PCIE_SEM5_LOCK)); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_LOCK)); if (done == 1) break; @@ -56,7 +55,7 @@ netxen_api_lock(struct netxen_adapter *adapter) } #if 0 - netxen_nic_write_w1(adapter, + NXWR32(adapter, NETXEN_API_LOCK_ID, NX_OS_API_LOCK_DRIVER); #endif return 0; @@ -66,8 +65,7 @@ static int netxen_api_unlock(struct netxen_adapter *adapter) { /* Release PCIE HW semaphore5 */ - netxen_nic_read_w0(adapter, - NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK)); + NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK)); return 0; } @@ -84,7 +82,7 @@ netxen_poll_rsp(struct netxen_adapter *adapter) if (++timeout > NX_OS_CRB_RETRY_COUNT) return NX_CDRP_RSP_TIMEOUT; - rsp = netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET); + rsp = NXRD32(adapter, NX_CDRP_CRB_OFFSET); } while (!NX_CDRP_IS_RSP(rsp)); return rsp; @@ -104,16 +102,15 @@ netxen_issue_cmd(struct netxen_adapter *adapter, if (netxen_api_lock(adapter)) return NX_RCODE_TIMEOUT; - netxen_nic_write_w1(adapter, NX_SIGN_CRB_OFFSET, signature); + NXWR32(adapter, NX_SIGN_CRB_OFFSET, signature); - netxen_nic_write_w1(adapter, NX_ARG1_CRB_OFFSET, arg1); + NXWR32(adapter, NX_ARG1_CRB_OFFSET, arg1); - netxen_nic_write_w1(adapter, NX_ARG2_CRB_OFFSET, arg2); + NXWR32(adapter, NX_ARG2_CRB_OFFSET, arg2); - netxen_nic_write_w1(adapter, NX_ARG3_CRB_OFFSET, arg3); + NXWR32(adapter, NX_ARG3_CRB_OFFSET, arg3); - netxen_nic_write_w1(adapter, NX_CDRP_CRB_OFFSET, - NX_CDRP_FORM_CMD(cmd)); + NXWR32(adapter, NX_CDRP_CRB_OFFSET, NX_CDRP_FORM_CMD(cmd)); rsp = netxen_poll_rsp(adapter); @@ -123,7 +120,7 @@ netxen_issue_cmd(struct netxen_adapter *adapter, rcode = NX_RCODE_TIMEOUT; } else if (rsp == NX_CDRP_RSP_FAIL) { - rcode = netxen_nic_read_w1(adapter, NX_ARG1_CRB_OFFSET); + rcode = NXRD32(adapter, NX_ARG1_CRB_OFFSET); printk(KERN_ERR "%s: failed card response code:0x%x\n", netxen_nic_driver_name, rcode); @@ -515,11 +512,11 @@ netxen_init_old_ctx(struct netxen_adapter *adapter) adapter->ctx_desc->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr); adapter->ctx_desc->sts_ring_size = cpu_to_le32(sds_ring->num_desc); - adapter->hw_write_wx(adapter, CRB_CTX_ADDR_REG_LO(func_id), + NXWR32(adapter, CRB_CTX_ADDR_REG_LO(func_id), lower32(adapter->ctx_desc_phys_addr)); - adapter->hw_write_wx(adapter, CRB_CTX_ADDR_REG_HI(func_id), + NXWR32(adapter, CRB_CTX_ADDR_REG_HI(func_id), upper32(adapter->ctx_desc_phys_addr)); - adapter->hw_write_wx(adapter, CRB_CTX_SIGNATURE_REG(func_id), + NXWR32(adapter, CRB_CTX_SIGNATURE_REG(func_id), NETXEN_CTX_SIGNATURE | func_id); return 0; } diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 6c5a111..a452b2f 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -92,12 +92,9 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) strncpy(drvinfo->driver, netxen_nic_driver_name, 32); strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32); write_lock_irqsave(&adapter->adapter_lock, flags); - fw_major = adapter->hw_read_wx(adapter, - NETXEN_FW_VERSION_MAJOR); - fw_minor = adapter->hw_read_wx(adapter, - NETXEN_FW_VERSION_MINOR); - fw_build = adapter->hw_read_wx(adapter, - NETXEN_FW_VERSION_SUB); + fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); + fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); + fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); write_unlock_irqrestore(&adapter->adapter_lock, flags); sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); @@ -135,7 +132,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { u32 val; - val = adapter->hw_read_wx(adapter, NETXEN_PORT_MODE_ADDR); + val = NXRD32(adapter, NETXEN_PORT_MODE_ADDR); if (val == NETXEN_PORT_MODE_802_3_AP) { ecmd->supported = SUPPORTED_1000baseT_Full; ecmd->advertising = ADVERTISED_1000baseT_Full; @@ -156,8 +153,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { u16 pcifn = adapter->ahw.pci_func; - val = adapter->hw_read_wx(adapter, - P3_LINK_SPEED_REG(pcifn)); + val = NXRD32(adapter, P3_LINK_SPEED_REG(pcifn)); ecmd->speed = P3_LINK_SPEED_MHZ * P3_LINK_SPEED_VAL(pcifn, val); } else @@ -423,12 +419,11 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; /* which mode */ - regs_buff[0] = adapter->hw_read_wx(adapter, NETXEN_NIU_MODE); + regs_buff[0] = NXRD32(adapter, NETXEN_NIU_MODE); mode = regs_buff[0]; /* Common registers to all the modes */ - regs_buff[2] = adapter->hw_read_wx(adapter, - NETXEN_NIU_STRAP_VALUE_SAVE_HIGHER); + regs_buff[2] = NXRD32(adapter, NETXEN_NIU_STRAP_VALUE_SAVE_HIGHER); /* GB/XGB Mode */ mode = (mode / 2) - 1; window = 0; @@ -439,7 +434,7 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) window = adapter->physical_port * NETXEN_NIC_PORT_WINDOW; - regs_buff[i] = adapter->hw_read_wx(adapter, + regs_buff[i] = NXRD32(adapter, niu_registers[mode].reg[i - 3] + window); } @@ -464,7 +459,7 @@ static u32 netxen_nic_test_link(struct net_device *dev) return !val; } } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { - val = adapter->hw_read_wx(adapter, CRB_XG_STATE); + val = NXRD32(adapter, CRB_XG_STATE); return (val == XG_LINK_UP) ? 0 : 1; } return -EIO; @@ -528,10 +523,9 @@ netxen_nic_get_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ - val = netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port)); + val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port)); pause->rx_pause = netxen_gb_get_rx_flowctl(val); - val = netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL); + val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL); switch (port) { case 0: pause->tx_pause = !(netxen_gb_get_gb0_mask(val)); @@ -551,7 +545,7 @@ netxen_nic_get_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; - val = netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL); + val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL); if (port == 0) pause->tx_pause = !(netxen_xg_get_xg0_mask(val)); else @@ -574,18 +568,17 @@ netxen_nic_set_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ - val = netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port)); + val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port)); if (pause->rx_pause) netxen_gb_rx_flowctl(val); else netxen_gb_unset_rx_flowctl(val); - netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), val); /* set autoneg */ - val = netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL); + val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL); switch (port) { case 0: if (pause->tx_pause) @@ -613,11 +606,11 @@ netxen_nic_set_pauseparam(struct net_device *dev, netxen_gb_set_gb3_mask(val); break; } - netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val); + NXWR32(adapter, NETXEN_NIU_GB_PAUSE_CTL, val); } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) return -EIO; - val = netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL); + val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL); if (port == 0) { if (pause->tx_pause) netxen_xg_unset_xg0_mask(val); @@ -629,7 +622,7 @@ netxen_nic_set_pauseparam(struct net_device *dev, else netxen_xg_set_xg1_mask(val); } - netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); + NXWR32(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); } else { printk(KERN_ERR "%s: Unknown board type: %x\n", netxen_nic_driver_name, @@ -643,14 +636,14 @@ static int netxen_nic_reg_test(struct net_device *dev) struct netxen_adapter *adapter = netdev_priv(dev); u32 data_read, data_written; - data_read = netxen_nic_read_w0(adapter, NETXEN_PCIX_PH_REG(0)); + data_read = NXRD32(adapter, NETXEN_PCIX_PH_REG(0)); if ((data_read & 0xffff) != PHAN_VENDOR_ID) return 1; data_written = (u32)0xa5a5a5a5; - netxen_nic_reg_write(adapter, CRB_SCRATCHPAD_TEST, data_written); - data_read = adapter->hw_read_wx(adapter, CRB_SCRATCHPAD_TEST); + NXWR32(adapter, CRB_SCRATCHPAD_TEST, data_written); + data_read = NXRD32(adapter, CRB_SCRATCHPAD_TEST); if (data_written != data_read) return 1; @@ -767,11 +760,11 @@ netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); if (wol_cfg & (1UL << adapter->portnum)) wol->supported |= WAKE_MAGIC; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); if (wol_cfg & (1UL << adapter->portnum)) wol->wolopts |= WAKE_MAGIC; } @@ -788,16 +781,16 @@ netxen_nic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EOPNOTSUPP; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); if (!(wol_cfg & (1 << adapter->portnum))) return -EOPNOTSUPP; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); if (wol->wolopts & WAKE_MAGIC) wol_cfg |= 1UL << adapter->portnum; else wol_cfg &= ~(1UL << adapter->portnum); - netxen_nic_reg_write(adapter, NETXEN_WOL_CONFIG, wol_cfg); + NXWR32(adapter, NETXEN_WOL_CONFIG, wol_cfg); return 0; } diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 87cda65..9439f89 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -361,22 +361,20 @@ netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter) if (adapter->mc_enabled) return 0; - val = adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG); + val = NXRD32(adapter, NETXEN_MAC_ADDR_CNTL_REG); val |= (1UL << (28+port)); - adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); + NXWR32(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); /* add broadcast addr to filter */ val = 0xffffff; - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val); - netxen_crb_writelit_adapter(adapter, - NETXEN_UNICAST_ADDR(port, 0)+4, val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0), val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0)+4, val); /* add station addr to filter */ val = MAC_HI(addr); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1), val); val = MAC_LO(addr); - netxen_crb_writelit_adapter(adapter, - NETXEN_UNICAST_ADDR(port, 1)+4, val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, val); adapter->mc_enabled = 1; return 0; @@ -392,18 +390,17 @@ netxen_nic_disable_mcast_filter(struct netxen_adapter *adapter) if (!adapter->mc_enabled) return 0; - val = adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG); + val = NXRD32(adapter, NETXEN_MAC_ADDR_CNTL_REG); val &= ~(1UL << (28+port)); - adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); + NXWR32(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); val = MAC_HI(addr); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0), val); val = MAC_LO(addr); - netxen_crb_writelit_adapter(adapter, - NETXEN_UNICAST_ADDR(port, 0)+4, val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0)+4, val); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), 0); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, 0); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1), 0); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, 0); adapter->mc_enabled = 0; return 0; @@ -419,10 +416,8 @@ netxen_nic_set_mcast_addr(struct netxen_adapter *adapter, lo = MAC_LO(addr); hi = MAC_HI(addr); - netxen_crb_writelit_adapter(adapter, - NETXEN_MCAST_ADDR(port, index), hi); - netxen_crb_writelit_adapter(adapter, - NETXEN_MCAST_ADDR(port, index)+4, lo); + NXWR32(adapter, NETXEN_MCAST_ADDR(port, index), hi); + NXWR32(adapter, NETXEN_MCAST_ADDR(port, index)+4, lo); return 0; } @@ -863,8 +858,8 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) crbaddr = CRB_MAC_BLOCK_START + (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1)); - mac_lo = adapter->hw_read_wx(adapter, crbaddr); - mac_hi = adapter->hw_read_wx(adapter, crbaddr+4); + mac_lo = NXRD32(adapter, crbaddr); + mac_hi = NXRD32(adapter, crbaddr+4); if (pci_func & 1) *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16)); @@ -882,8 +877,7 @@ static int crb_win_lock(struct netxen_adapter *adapter) while (!done) { /* acquire semaphore3 from PCI HW block */ - done = adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(PCIE_SEM7_LOCK)); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_LOCK)); if (done == 1) break; if (timeout >= CRB_WIN_LOCK_TIMEOUT) @@ -891,8 +885,7 @@ static int crb_win_lock(struct netxen_adapter *adapter) timeout++; udelay(1); } - netxen_crb_writelit_adapter(adapter, - NETXEN_CRB_WIN_LOCK_ID, adapter->portnum); + NXWR32(adapter, NETXEN_CRB_WIN_LOCK_ID, adapter->portnum); return 0; } @@ -900,8 +893,7 @@ static void crb_win_unlock(struct netxen_adapter *adapter) { int val; - val = adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK)); + val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK)); } /* @@ -1037,8 +1029,7 @@ netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname, dev_info(&pdev->dev, "loading firmware from flash\n"); if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - adapter->hw_write_wx(adapter, - NETXEN_ROMUSB_GLB_CAS_RST, 1); + NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1); if (fw) { __le64 data; @@ -1090,13 +1081,10 @@ netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname, msleep(1); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - adapter->hw_write_wx(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d); + NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d); else { - adapter->hw_write_wx(adapter, - NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff); - adapter->hw_write_wx(adapter, - NETXEN_ROMUSB_GLB_CAS_RST, 0); + NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff); + NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0); } return 0; @@ -1154,8 +1142,7 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname, if (NETXEN_VERSION_CODE(major, minor, build) > ver) return -EINVAL; - netxen_nic_reg_write(adapter, NETXEN_CAM_RAM(0x1fc), - NETXEN_BDINFO_MAGIC); + NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); return 0; } @@ -1183,8 +1170,7 @@ request_mn: netxen_rom_fast_read(adapter, NX_FW_VERSION_OFFSET, (int *)&flashed_ver); if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { - capability = adapter->hw_read_wx(adapter, - NX_PEG_TUNE_CAPABILITY); + capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); if (capability & NX_PEG_TUNE_MN_PRESENT) { fw_type = NX_P3_MN_ROMIMAGE; goto request_fw; @@ -1332,38 +1318,6 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) return data; } -void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val) -{ - adapter->hw_write_wx(adapter, off, val); -} - -int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off) -{ - return adapter->hw_read_wx(adapter, off); -} - -/* Change the window to 0, write and change back to window 1. */ -void netxen_nic_write_w0(struct netxen_adapter *adapter, u32 index, u32 value) -{ - adapter->hw_write_wx(adapter, index, value); -} - -/* Change the window to 0, read and change back to window 1. */ -u32 netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index) -{ - return adapter->hw_read_wx(adapter, index); -} - -void netxen_nic_write_w1(struct netxen_adapter *adapter, u32 index, u32 value) -{ - adapter->hw_write_wx(adapter, index, value); -} - -u32 netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index) -{ - return adapter->hw_read_wx(adapter, index); -} - /* * check memory access boundary. * used by test agent. support ddr access only for now @@ -1475,10 +1429,9 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* DDR network side */ window = MN_WIN(addr); adapter->ahw.ddr_mn_window = window; - adapter->hw_write_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, + NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, window); - win_read = adapter->hw_read_wx(adapter, + win_read = NXRD32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); if ((win_read << 17) != window) { printk(KERN_INFO "Written MNwin (0x%x) != " @@ -1494,10 +1447,9 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, window = OCM_WIN(addr); adapter->ahw.ddr_mn_window = window; - adapter->hw_write_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, + NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, window); - win_read = adapter->hw_read_wx(adapter, + win_read = NXRD32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); if ((win_read >> 7) != window) { printk(KERN_INFO "%s: Written OCMwin (0x%x) != " @@ -1511,10 +1463,9 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* QDR network side */ window = MS_WIN(addr); adapter->ahw.qdr_sn_window = window; - adapter->hw_write_wx(adapter, - adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, + NXWR32(adapter, adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, window); - win_read = adapter->hw_read_wx(adapter, + win_read = NXRD32(adapter, adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE); if (win_read != window) { printk(KERN_INFO "%s: Written MSwin (0x%x) != " @@ -1961,27 +1912,20 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, for (i = 0; i < loop; i++) { temp = off8 + (i << 3); - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_ADDR_LO, temp); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); temp = 0; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_ADDR_HI, temp); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); temp = word[i] & 0xffffffff; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); temp = (word[i] >> 32) & 0xffffffff; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_CTRL, temp); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_CTRL, temp); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL); + temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2038,21 +1982,16 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, for (i = 0; i < loop; i++) { temp = off8 + (i << 3); - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_ADDR_LO, temp); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); temp = 0; - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_ADDR_HI, temp); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); temp = MIU_TA_CTL_ENABLE; - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, temp); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, temp); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL); + temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2067,7 +2006,7 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, start = off0[i] >> 2; end = (off0[i] + sz[i] - 1) >> 2; for (k = start; k <= end; k++) { - temp = adapter->hw_read_wx(adapter, + temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_RDDATA(k)); word[i] |= ((uint64_t)temp << (32 * k)); } @@ -2111,14 +2050,14 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, u64 off, u32 data) { - adapter->hw_write_wx(adapter, off, data); + NXWR32(adapter, off, data); return 0; } u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off) { - return adapter->hw_read_wx(adapter, off); + return NXRD32(adapter, off); } int netxen_nic_get_board_info(struct netxen_adapter *adapter) @@ -2152,8 +2091,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) adapter->ahw.board_type = board_type; if (board_type == NETXEN_BRDTYPE_P3_4_GB_MM) { - u32 gpio = netxen_nic_reg_read(adapter, - NETXEN_ROMUSB_GLB_PAD_GPIO_I); + u32 gpio = NXRD32(adapter, NETXEN_ROMUSB_GLB_PAD_GPIO_I); if ((gpio & 0x8000) == 0) board_type = NETXEN_BRDTYPE_P3_10G_TP; } @@ -2205,8 +2143,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu) { new_mtu += MTU_FUDGE_FACTOR; - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_MAX_FRAME_SIZE(adapter->physical_port), + NXWR32(adapter, NETXEN_NIU_GB_MAX_FRAME_SIZE(adapter->physical_port), new_mtu); return 0; } @@ -2215,21 +2152,12 @@ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu) { new_mtu += MTU_FUDGE_FACTOR; if (adapter->physical_port == 0) - netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, - new_mtu); + NXWR32(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu); else - netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, - new_mtu); + NXWR32(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu); return 0; } -void -netxen_crb_writelit_adapter(struct netxen_adapter *adapter, - unsigned long off, int data) -{ - adapter->hw_write_wx(adapter, off, data); -} - void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) { __u32 status; @@ -2244,8 +2172,7 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) } if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - port_mode = adapter->hw_read_wx(adapter, - NETXEN_PORT_MODE_ADDR); + port_mode = NXRD32(adapter, NETXEN_PORT_MODE_ADDR); if (port_mode == NETXEN_PORT_MODE_802_3_AP) { adapter->link_speed = SPEED_1000; adapter->link_duplex = DUPLEX_FULL; @@ -2322,9 +2249,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) addr += sizeof(u32); } - fw_major = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MAJOR); - fw_minor = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MINOR); - fw_build = adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_SUB); + fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); + fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); + fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); adapter->fw_major = fw_major; adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); @@ -2347,7 +2274,7 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) fw_major, fw_minor, fw_build); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - i = adapter->hw_read_wx(adapter, NETXEN_MIU_MN_CONTROL); + i = NXRD32(adapter, NETXEN_MIU_MN_CONTROL); adapter->ahw.cut_through = (i & 0x4) ? 1 : 0; dev_info(&pdev->dev, "firmware running in %s mode\n", adapter->ahw.cut_through ? "cut-through" : "legacy"); @@ -2362,9 +2289,9 @@ netxen_nic_wol_supported(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 0; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); if (wol_cfg & (1UL << adapter->portnum)) { - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); if (wol_cfg & (1 << adapter->portnum)) return 1; } diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 83116c2..0c91238 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -368,8 +368,7 @@ static int rom_lock(struct netxen_adapter *adapter) while (!done) { /* acquire semaphore2 from PCI HW block */ - done = netxen_nic_read_w0(adapter, - NETXEN_PCIE_REG(PCIE_SEM2_LOCK)); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK)); if (done == 1) break; if (timeout >= rom_lock_timeout) @@ -386,7 +385,7 @@ static int rom_lock(struct netxen_adapter *adapter) cpu_relax(); /*This a nop instr on i386 */ } } - netxen_nic_reg_write(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER); + NXWR32(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER); return 0; } @@ -398,7 +397,7 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter) cond_resched(); while (done == 0) { - done = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_GLB_STATUS); + done = NXRD32(adapter, NETXEN_ROMUSB_GLB_STATUS); done &= 2; timeout++; if (timeout >= rom_max_timeout) { @@ -412,27 +411,27 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter) static void netxen_rom_unlock(struct netxen_adapter *adapter) { /* release semaphore2 */ - netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK)); + NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK)); } static int do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); + NXWR32(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); + NXWR32(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + NXWR32(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); + NXWR32(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); if (netxen_wait_rom_done(adapter)) { printk("Error waiting for rom done\n"); return -EIO; } /* reset abyte_cnt and dummy_byte_cnt */ - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); + NXWR32(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); udelay(10); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + NXWR32(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA); + *valp = NXRD32(adapter, NETXEN_ROMUSB_ROM_RDATA); return 0; } @@ -496,8 +495,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) /* resetall */ rom_lock(adapter); - netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET, - 0xffffffff); + NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff); netxen_rom_unlock(adapter); if (verbose) { @@ -621,7 +619,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) } } - adapter->hw_write_wx(adapter, off, buf[i].data); + NXWR32(adapter, off, buf[i].data); msleep(init_delay); } @@ -631,33 +629,31 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) /* unreset_net_cache */ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - val = adapter->hw_read_wx(adapter, - NETXEN_ROMUSB_GLB_SW_RESET); - netxen_crb_writelit_adapter(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, (val & 0xffffff0f)); + val = NXRD32(adapter, NETXEN_ROMUSB_GLB_SW_RESET); + NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, (val & 0xffffff0f)); } /* p2dn replyCount */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_D + 0xec, 0x1e); + NXWR32(adapter, NETXEN_CRB_PEG_NET_D + 0xec, 0x1e); /* disable_peg_cache 0 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_D + 0x4c, 8); + NXWR32(adapter, NETXEN_CRB_PEG_NET_D + 0x4c, 8); /* disable_peg_cache 1 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_I + 0x4c, 8); + NXWR32(adapter, NETXEN_CRB_PEG_NET_I + 0x4c, 8); /* peg_clr_all */ /* peg_clr 0 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_0 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_0 + 0xc, 0); /* peg_clr 1 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_1 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_1 + 0xc, 0); /* peg_clr 2 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_2 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_2 + 0xc, 0); /* peg_clr 3 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_3 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_3 + 0xc, 0); return 0; } @@ -681,12 +677,12 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) hi = (addr >> 32) & 0xffffffff; lo = addr & 0xffffffff; - adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); - adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); + NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); + NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { uint32_t temp = 0; - adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF, temp); + NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp); } return 0; @@ -728,8 +724,7 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) if (!pegtune_val) { do { - val = adapter->hw_read_wx(adapter, - CRB_CMDPEG_STATE); + val = NXRD32(adapter, CRB_CMDPEG_STATE); if (val == PHAN_INITIALIZE_COMPLETE || val == PHAN_INITIALIZE_ACK) @@ -740,7 +735,7 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) } while (--retries); if (!retries) { - pegtune_val = adapter->hw_read_wx(adapter, + pegtune_val = NXRD32(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE); printk(KERN_WARNING "netxen_phantom_init: init failed, " "pegtune_val=%x\n", pegtune_val); @@ -758,7 +753,7 @@ netxen_receive_peg_ready(struct netxen_adapter *adapter) int retries = 2000; do { - val = adapter->hw_read_wx(adapter, CRB_RCVPEG_STATE); + val = NXRD32(adapter, CRB_RCVPEG_STATE); if (val == PHAN_PEG_RCV_INITIALIZED) return 0; @@ -784,18 +779,13 @@ int netxen_init_firmware(struct netxen_adapter *adapter) if (err) return err; - adapter->hw_write_wx(adapter, - CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); - adapter->hw_write_wx(adapter, - CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); - adapter->hw_write_wx(adapter, - CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); - adapter->hw_write_wx(adapter, - CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); + NXWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); + NXWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); + NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); + NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) { - adapter->capabilities = netxen_nic_reg_read(adapter, - CRB_FW_CAPABILITIES_1); + adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); } return err; @@ -1057,8 +1047,7 @@ skip: if (count) { sds_ring->consumer = consumer; - adapter->hw_write_wx(adapter, - sds_ring->crb_sts_consumer, consumer); + NXWR32(adapter, sds_ring->crb_sts_consumer, consumer); } return count; @@ -1176,8 +1165,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, if (count) { rds_ring->producer = producer; - adapter->hw_write_wx(adapter, - rds_ring->crb_rcv_producer, + NXWR32(adapter, rds_ring->crb_rcv_producer, (producer-1) & (rds_ring->num_desc-1)); if (adapter->fw_major < 4) { @@ -1237,8 +1225,7 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, if (count) { rds_ring->producer = producer; - adapter->hw_write_wx(adapter, - rds_ring->crb_rcv_producer, + NXWR32(adapter, rds_ring->crb_rcv_producer, (producer - 1) & (rds_ring->num_desc - 1)); wmb(); } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 31966a0..8426092 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -109,8 +109,7 @@ void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring, u32 producer) { - adapter->hw_write_wx(adapter, - tx_ring->crb_cmd_producer, producer); + NXWR32(adapter, tx_ring->crb_cmd_producer, producer); } static uint32_t crb_cmd_consumer[4] = { @@ -122,8 +121,7 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring, u32 consumer) { - adapter->hw_write_wx(adapter, - tx_ring->crb_cmd_consumer, consumer); + NXWR32(adapter, tx_ring->crb_cmd_consumer, consumer); } static uint32_t msi_tgt_status[8] = { @@ -139,14 +137,14 @@ static inline void netxen_nic_disable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - adapter->hw_write_wx(adapter, sds_ring->crb_intr_mask, 0); + NXWR32(adapter, sds_ring->crb_intr_mask, 0); } static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - adapter->hw_write_wx(adapter, sds_ring->crb_intr_mask, 0x1); + NXWR32(adapter, sds_ring->crb_intr_mask, 0x1); if (!NETXEN_IS_MSI_FAMILY(adapter)) adapter->pci_write_immediate(adapter, @@ -262,7 +260,7 @@ nx_update_dma_mask(struct netxen_adapter *adapter) change = 0; - shift = netxen_nic_reg_read(adapter, CRB_DMA_SHIFT); + shift = NXRD32(adapter, CRB_DMA_SHIFT); if (shift >= 32) return 0; @@ -309,42 +307,34 @@ netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot) if (first_boot == 0x55555555) { /* This is the first boot after power up */ - adapter->hw_write_wx(adapter, - NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); + NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 0; /* PCI bus master workaround */ - first_boot = adapter->hw_read_wx(adapter, NETXEN_PCIE_REG(0x4)); + first_boot = NXRD32(adapter, NETXEN_PCIE_REG(0x4)); if (!(first_boot & 0x4)) { first_boot |= 0x4; - adapter->hw_write_wx(adapter, - NETXEN_PCIE_REG(0x4), first_boot); - first_boot = adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(0x4)); + NXWR32(adapter, NETXEN_PCIE_REG(0x4), first_boot); + first_boot = NXRD32(adapter, NETXEN_PCIE_REG(0x4)); } /* This is the first boot after power up */ - first_boot = adapter->hw_read_wx(adapter, - NETXEN_ROMUSB_GLB_SW_RESET); + first_boot = NXRD32(adapter, NETXEN_ROMUSB_GLB_SW_RESET); if (first_boot != 0x80000f) { /* clear the register for future unloads/loads */ - adapter->hw_write_wx(adapter, - NETXEN_CAM_RAM(0x1fc), 0); + NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), 0); return -EIO; } /* Start P2 boot loader */ - val = adapter->hw_read_wx(adapter, - NETXEN_ROMUSB_GLB_PEGTUNE_DONE); - adapter->hw_write_wx(adapter, - NETXEN_ROMUSB_GLB_PEGTUNE_DONE, val | 0x1); + val = NXRD32(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE); + NXWR32(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE, val | 0x1); timeout = 0; do { msleep(1); - val = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(0x1fc)); + val = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc)); if (++timeout > 5000) return -EIO; @@ -363,24 +353,19 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter) (val == NETXEN_BRDTYPE_P3_XG_LOM)) { if (port_mode == NETXEN_PORT_MODE_802_3_AP) { data = NETXEN_PORT_MODE_802_3_AP; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, data); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_XG) { data = NETXEN_PORT_MODE_XG; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, data); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_AUTO_NEG_1G) { data = NETXEN_PORT_MODE_AUTO_NEG_1G; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, data); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_AUTO_NEG_XG) { data = NETXEN_PORT_MODE_AUTO_NEG_XG; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, data); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else { data = NETXEN_PORT_MODE_AUTO_NEG; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, data); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } if ((wol_port_mode != NETXEN_PORT_MODE_802_3_AP) && @@ -389,8 +374,7 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter) (wol_port_mode != NETXEN_PORT_MODE_AUTO_NEG_XG)) { wol_port_mode = NETXEN_PORT_MODE_AUTO_NEG; } - adapter->hw_write_wx(adapter, NETXEN_WOL_PORT_MODE, - wol_port_mode); + NXWR32(adapter, NETXEN_WOL_PORT_MODE, wol_port_mode); } } @@ -674,8 +658,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) if (!first_driver) return 0; - first_boot = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(0x1fc)); + first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc)); err = netxen_check_hw_init(adapter, first_boot); if (err) { @@ -684,13 +667,12 @@ netxen_start_firmware(struct netxen_adapter *adapter) } if (first_boot != 0x55555555) { - adapter->hw_write_wx(adapter, - CRB_CMDPEG_STATE, 0); + NXWR32(adapter, CRB_CMDPEG_STATE, 0); netxen_pinit_from_rom(adapter, 0); msleep(1); } - netxen_nic_reg_write(adapter, CRB_DMA_SHIFT, 0x55555555); + NXWR32(adapter, CRB_DMA_SHIFT, 0x55555555); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_set_port_mode(adapter); @@ -702,8 +684,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) val = 0x7654; if (adapter->ahw.port_type == NETXEN_NIC_XGBE) val |= 0x0f000000; - netxen_crb_writelit_adapter(adapter, - NETXEN_MAC_ADDR_CNTL_REG, val); + NXWR32(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); } @@ -717,7 +698,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) val = (_NETXEN_NIC_LINUX_MAJOR << 16) | ((_NETXEN_NIC_LINUX_MINOR << 8)) | (_NETXEN_NIC_LINUX_SUBVERSION); - adapter->hw_write_wx(adapter, CRB_DRIVER_VERSION, val); + NXWR32(adapter, CRB_DRIVER_VERSION, val); /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); @@ -1032,8 +1013,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ adapter->physical_port = adapter->portnum; if (adapter->fw_major < 4) { - i = adapter->hw_read_wx(adapter, - CRB_V2P(adapter->portnum)); + i = NXRD32(adapter, CRB_V2P(adapter->portnum)); if (i != 0x55555555) adapter->physical_port = i; } @@ -1480,7 +1460,7 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter) uint32_t temp, temp_state, temp_val; int rv = 0; - temp = adapter->hw_read_wx(adapter, CRB_TEMP_STATE); + temp = NXRD32(adapter, CRB_TEMP_STATE); temp_state = nx_get_temp_state(temp); temp_val = nx_get_temp_val(temp); @@ -1551,11 +1531,11 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) port = adapter->physical_port; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - val = adapter->hw_read_wx(adapter, CRB_XG_STATE_P3); + val = NXRD32(adapter, CRB_XG_STATE_P3); val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); linkup = (val == XG_LINK_UP_P3); } else { - val = adapter->hw_read_wx(adapter, CRB_XG_STATE); + val = NXRD32(adapter, CRB_XG_STATE); if (adapter->ahw.port_type == NETXEN_NIC_GBE) linkup = (val >> port) & 1; else { @@ -1650,15 +1630,14 @@ static irqreturn_t netxen_intr(int irq, void *data) } else { unsigned long our_int = 0; - our_int = adapter->hw_read_wx(adapter, CRB_INT_VECTOR); + our_int = NXRD32(adapter, CRB_INT_VECTOR); /* not our interrupt */ if (!test_and_clear_bit((7 + adapter->portnum), &our_int)) return IRQ_NONE; /* claim interrupt */ - adapter->hw_write_wx(adapter, - CRB_INT_VECTOR, (our_int & 0xffffffff)); + NXWR32(adapter, CRB_INT_VECTOR, (our_int & 0xffffffff)); } /* clear interrupt */ diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index b54a63a..5e2698b 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -43,8 +43,7 @@ static int phy_lock(struct netxen_adapter *adapter) int done = 0, timeout = 0; while (!done) { - done = netxen_nic_reg_read(adapter, - NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); if (done == 1) break; if (timeout >= phy_lock_timeout) { @@ -59,8 +58,7 @@ static int phy_lock(struct netxen_adapter *adapter) } } - netxen_crb_writelit_adapter(adapter, - NETXEN_PHY_LOCK_ID, PHY_LOCK_DRIVER); + NXWR32(adapter, NETXEN_PHY_LOCK_ID, PHY_LOCK_DRIVER); return 0; } @@ -105,7 +103,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, * so it cannot be in reset */ - mac_cfg0 = adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); + mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); if (netxen_gb_get_soft_reset(mac_cfg0)) { __u32 temp; temp = 0; @@ -113,8 +111,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, netxen_gb_rx_reset_pb(temp); netxen_gb_tx_reset_mac(temp); netxen_gb_rx_reset_mac(temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) return -EIO; restore = 1; } @@ -122,38 +119,32 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, address = 0; netxen_gb_mii_mgmt_reg_addr(address, reg); netxen_gb_mii_mgmt_phy_addr(address, phy); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) return -EIO; command = 0; /* turn off any prior activity */ - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; /* send read command */ netxen_gb_mii_mgmt_set_read_cycle(command); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; status = 0; do { - status = adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); + status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); timeout++; } while ((netxen_get_gb_mii_mgmt_busy(status) || netxen_get_gb_mii_mgmt_notvalid(status)) && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); if (timeout < NETXEN_NIU_PHY_WAITMAX) { - *readval = adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_STATUS(0)); + *readval = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_STATUS(0)); result = 0; } else result = -1; if (restore) - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; phy_unlock(adapter); return result; @@ -189,7 +180,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, * cannot be in reset */ - mac_cfg0 = adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); + mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); if (netxen_gb_get_soft_reset(mac_cfg0)) { __u32 temp; temp = 0; @@ -198,32 +189,27 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, netxen_gb_tx_reset_mac(temp); netxen_gb_rx_reset_mac(temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) return -EIO; restore = 1; } command = 0; /* turn off any prior activity */ - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; address = 0; netxen_gb_mii_mgmt_reg_addr(address, reg); netxen_gb_mii_mgmt_phy_addr(address, phy); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) return -EIO; - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_CTRL(0), val)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0), val)) return -EIO; status = 0; do { - status = adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); + status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); timeout++; } while ((netxen_get_gb_mii_mgmt_busy(status)) && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); @@ -235,8 +221,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, /* restore the state of port 0 MAC in case we tampered with it */ if (restore) - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; return result; @@ -244,7 +229,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f); + NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x3f); return 0; } @@ -267,7 +252,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f); + NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x7f); return 0; } @@ -301,30 +286,21 @@ static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port, long enable) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x80000000); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x0000f0025); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), - 0xf1ff); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); - netxen_crb_writelit_adapter(adapter, - (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); + NXWR32(adapter, NETXEN_NIU_MODE, 0x2); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf1ff); + NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); + NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); + NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); + NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); if (enable) { /* * Do NOT enable flow control until a suitable solution for * shutting down pause frames is found. */ - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x5); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); } if (netxen_niu_gbe_enable_phy_interrupts(adapter)) @@ -339,30 +315,21 @@ static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port, long enable) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x80000000); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x0000f0025); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), - 0xf2ff); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); - netxen_crb_writelit_adapter(adapter, - (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); + NXWR32(adapter, NETXEN_NIU_MODE, 0x2); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf2ff); + NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); + NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); + NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); + NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); if (enable) { /* * Do NOT enable flow control until a suitable solution for * shutting down pause frames is found. */ - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x5); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); } if (netxen_niu_gbe_enable_phy_interrupts(adapter)) @@ -402,17 +369,12 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) * plugged in. */ - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0 - (port), + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), NETXEN_GB_MAC_SOFT_RESET); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0 - (port), - NETXEN_GB_MAC_RESET_PROT_BLK - | NETXEN_GB_MAC_ENABLE_TX_RX - | - NETXEN_GB_MAC_PAUSED_FRMS); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + NETXEN_GB_MAC_RESET_PROT_BLK | + NETXEN_GB_MAC_ENABLE_TX_RX | + NETXEN_GB_MAC_PAUSED_FRMS); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) printk(KERN_ERR "ERROR clearing PHY interrupts\n"); @@ -433,10 +395,8 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) { if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); } return 0; @@ -459,10 +419,8 @@ static int netxen_niu_macaddr_get(struct netxen_adapter *adapter, if ((phy < 0) || (phy > 3)) return -EINVAL; - stationhigh = adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_0(phy)); - stationlow = adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_1(phy)); + stationhigh = NXRD32(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy)); + stationlow = NXRD32(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy)); ((__le32 *)val)[1] = cpu_to_le32(stationhigh); ((__le32 *)val)[0] = cpu_to_le32(stationlow); @@ -491,14 +449,12 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, temp[0] = temp[1] = 0; memcpy(temp + 2, addr, 2); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_1(phy), val)) + if (NXWR32(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), val)) return -EIO; memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32)); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_0(phy), val)) + if (NXWR32(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), val)) return -2; netxen_niu_macaddr_get(adapter, @@ -529,8 +485,7 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) return -EINVAL; mac_cfg0 = 0; netxen_gb_soft_reset(mac_cfg0); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), mac_cfg0)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), mac_cfg0)) return -EIO; return 0; } @@ -548,8 +503,8 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) return -EINVAL; mac_cfg = 0; - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) + if (NXWR32(adapter, + NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) return -EIO; return 0; } @@ -565,7 +520,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, return -EINVAL; /* save previous contents */ - reg = adapter->hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR); + reg = NXRD32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR); if (mode == NETXEN_NIU_PROMISC_MODE) { switch (port) { case 0: @@ -601,7 +556,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, return -EIO; } } - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, reg)) + if (NXWR32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, reg)) return -EIO; return 0; } @@ -628,28 +583,24 @@ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, case 0: memcpy(temp + 2, addr, 2); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_XGE_STATION_ADDR_0_1, val)) + if (NXWR32(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, val)) return -EIO; memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_XGE_STATION_ADDR_0_HI, val)) + if (NXWR32(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, val)) return -EIO; break; case 1: memcpy(temp + 2, addr, 2); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_XG1_STATION_ADDR_0_1, val)) + if (NXWR32(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, val)) return -EIO; memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_XG1_STATION_ADDR_0_HI, val)) + if (NXWR32(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, val)) return -EIO; break; @@ -670,8 +621,7 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, if (port > NETXEN_NIU_MAX_XG_PORTS) return -EINVAL; - reg = adapter->hw_read_wx(adapter, - NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); + reg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); if (mode == NETXEN_NIU_PROMISC_MODE) reg = (reg | 0x2000UL); else @@ -682,8 +632,7 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, else reg = (reg & ~0x1000UL); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); return 0; } -- cgit v0.10.2 From f6d21f44122630cc9549b8ffbab23ea8c68254e0 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:46 +0000 Subject: netxen: enable rss for NX2031 Enable multiple rx rings for older NX2031 chip, firmware 3.4.336 or newer supports this feature. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index f13fd02..ebd6c2e 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -195,6 +195,8 @@ #define MAX_JUMBO_RCV_DESCRIPTORS 1024 #define MAX_LRO_RCV_DESCRIPTORS 8 #define NETXEN_CTX_SIGNATURE 0xdee0 +#define NETXEN_CTX_SIGNATURE_V2 0x0002dee0 +#define NETXEN_CTX_RESET 0xbad0 #define NETXEN_RCV_PRODUCER(ringid) (ringid) #define PHAN_PEG_RCV_INITIALIZED 0xff01 @@ -234,12 +236,19 @@ typedef u32 netxen_ctx_msg; #define netxen_set_msg_opcode(config_word, val) \ ((config_word) &= ~(0xf<<28), (config_word) |= (val & 0xf) << 28) -struct netxen_rcv_context { - __le64 rcv_ring_addr; - __le32 rcv_ring_size; +struct netxen_rcv_ring { + __le64 addr; + __le32 size; __le32 rsrvd; }; +struct netxen_sts_ring { + __le64 addr; + __le32 size; + __le16 msi_index; + __le16 rsvd; +} ; + struct netxen_ring_ctx { /* one command ring */ @@ -249,13 +258,18 @@ struct netxen_ring_ctx { __le32 rsrvd; /* three receive rings */ - struct netxen_rcv_context rcv_ctx[3]; + struct netxen_rcv_ring rcv_rings[NUM_RCV_DESC_RINGS]; - /* one status ring */ __le64 sts_ring_addr; __le32 sts_ring_size; __le32 ctx_id; + + __le64 rsrvd_2[3]; + __le32 sts_ring_count; + __le32 rsrvd_3; + struct netxen_sts_ring sts_rings[NUM_STS_DESC_RINGS]; + } __attribute__ ((aligned(64))); /* @@ -1219,7 +1233,8 @@ struct netxen_adapter { u8 mc_enabled; u8 max_mc_count; - u16 resv2; + u8 rss_supported; + u8 resv2; u32 resv3; u8 has_link_events; diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 32f4839..fd82adf 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -441,7 +441,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x120) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x138), + { + NETXEN_NIC_REG(0x138), + NETXEN_NIC_REG_2(0x000), + NETXEN_NIC_REG_2(0x004), + NETXEN_NIC_REG_2(0x008), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_0, + NETXEN_NIC_REG_2(0x044), + NETXEN_NIC_REG_2(0x048), + NETXEN_NIC_REG_2(0x04c), + }, }, /* Instance 1 */ { @@ -454,7 +466,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x164) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x17c), + { + NETXEN_NIC_REG(0x17c), + NETXEN_NIC_REG_2(0x020), + NETXEN_NIC_REG_2(0x024), + NETXEN_NIC_REG_2(0x028), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_1, + NETXEN_NIC_REG_2(0x064), + NETXEN_NIC_REG_2(0x068), + NETXEN_NIC_REG_2(0x06c), + }, }, /* Instance 2 */ { @@ -467,7 +491,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x208) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x220), + { + NETXEN_NIC_REG(0x220), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_2, + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, }, /* Instance 3 */ { @@ -480,7 +516,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x24c) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x264), + { + NETXEN_NIC_REG(0x264), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_3, + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, }, }; @@ -492,40 +540,50 @@ netxen_init_old_ctx(struct netxen_adapter *adapter) struct nx_host_sds_ring *sds_ring; struct nx_host_tx_ring *tx_ring; int ring; - int func_id = adapter->portnum; + int port = adapter->portnum; + struct netxen_ring_ctx *hwctx = adapter->ctx_desc; + u32 signature; tx_ring = &adapter->tx_ring; - adapter->ctx_desc->cmd_ring_addr = cpu_to_le64(tx_ring->phys_addr); - adapter->ctx_desc->cmd_ring_size = cpu_to_le32(tx_ring->num_desc); + hwctx->cmd_ring_addr = cpu_to_le64(tx_ring->phys_addr); + hwctx->cmd_ring_size = cpu_to_le32(tx_ring->num_desc); recv_ctx = &adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr = + hwctx->rcv_rings[ring].addr = cpu_to_le64(rds_ring->phys_addr); - adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size = + hwctx->rcv_rings[ring].size = cpu_to_le32(rds_ring->num_desc); } - sds_ring = &recv_ctx->sds_rings[0]; - adapter->ctx_desc->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr); - adapter->ctx_desc->sts_ring_size = cpu_to_le32(sds_ring->num_desc); - NXWR32(adapter, CRB_CTX_ADDR_REG_LO(func_id), + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + + if (ring == 0) { + hwctx->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr); + hwctx->sts_ring_size = cpu_to_le32(sds_ring->num_desc); + } + hwctx->sts_rings[ring].addr = cpu_to_le64(sds_ring->phys_addr); + hwctx->sts_rings[ring].size = cpu_to_le32(sds_ring->num_desc); + hwctx->sts_rings[ring].msi_index = cpu_to_le16(ring); + } + hwctx->sts_ring_count = cpu_to_le32(adapter->max_sds_rings); + + signature = (adapter->max_sds_rings > 1) ? + NETXEN_CTX_SIGNATURE_V2 : NETXEN_CTX_SIGNATURE; + + NXWR32(adapter, CRB_CTX_ADDR_REG_LO(port), lower32(adapter->ctx_desc_phys_addr)); - NXWR32(adapter, CRB_CTX_ADDR_REG_HI(func_id), + NXWR32(adapter, CRB_CTX_ADDR_REG_HI(port), upper32(adapter->ctx_desc_phys_addr)); - NXWR32(adapter, CRB_CTX_SIGNATURE_REG(func_id), - NETXEN_CTX_SIGNATURE | func_id); + NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port), + signature | port); return 0; } -static uint32_t sw_int_mask[4] = { - CRB_SW_INT_MASK_0, CRB_SW_INT_MASK_1, - CRB_SW_INT_MASK_2, CRB_SW_INT_MASK_3 -}; - int netxen_alloc_hw_resources(struct netxen_adapter *adapter) { void *addr; @@ -538,6 +596,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; + int port = adapter->portnum; addr = pci_alloc_consistent(pdev, sizeof(struct netxen_ring_ctx) + sizeof(uint32_t), @@ -549,7 +608,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } memset(addr, 0, sizeof(struct netxen_ring_ctx)); adapter->ctx_desc = (struct netxen_ring_ctx *)addr; - adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum); + adapter->ctx_desc->ctx_id = cpu_to_le32(port); adapter->ctx_desc->cmd_consumer_offset = cpu_to_le64(adapter->ctx_desc_phys_addr + sizeof(struct netxen_ring_ctx)); @@ -586,8 +645,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (adapter->fw_major < 4) rds_ring->crb_rcv_producer = - recv_crb_registers[adapter->portnum]. - crb_rcv_producer[ring]; + recv_crb_registers[port].crb_rcv_producer[ring]; } for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -604,6 +662,12 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) goto err_out_free; } sds_ring->desc_head = (struct status_desc *)addr; + + sds_ring->crb_sts_consumer = + recv_crb_registers[port].crb_sts_consumer[ring]; + + sds_ring->crb_intr_mask = + recv_crb_registers[port].sw_int_mask[ring]; } @@ -615,19 +679,11 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (err) goto err_out_free; } else { - sds_ring = &recv_ctx->sds_rings[0]; - sds_ring->crb_sts_consumer = - recv_crb_registers[adapter->portnum].crb_sts_consumer; - - recv_ctx->sds_rings[0].crb_intr_mask = - sw_int_mask[adapter->portnum]; - err = netxen_init_old_ctx(adapter); if (err) { netxen_free_hw_resources(adapter); return err; } - } return 0; @@ -645,9 +701,16 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) struct nx_host_tx_ring *tx_ring; int ring; + int port = adapter->portnum; + if (adapter->fw_major >= 4) { nx_fw_cmd_destroy_tx_ctx(adapter); nx_fw_cmd_destroy_rx_ctx(adapter); + } else { + netxen_api_lock(adapter); + NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port), + NETXEN_CTX_RESET | port); + netxen_api_unlock(adapter); } if (adapter->ctx_desc != NULL) { diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 8426092..da9b90d 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -175,7 +175,8 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev) struct nx_host_sds_ring *sds_ring; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; - if (adapter->flags & NETXEN_NIC_MSIX_ENABLED) + if ((adapter->flags & NETXEN_NIC_MSIX_ENABLED) && + adapter->rss_supported) adapter->max_sds_rings = (num_online_cpus() >= 4) ? 4 : 2; else adapter->max_sds_rings = 1; @@ -288,10 +289,22 @@ static void netxen_check_options(struct netxen_adapter *adapter) else if (adapter->ahw.port_type == NETXEN_NIC_GBE) adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + adapter->msix_supported = 0; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { adapter->msix_supported = !!use_msi_x; - else - adapter->msix_supported = 0; + adapter->rss_supported = !!use_msi_x; + } else if (adapter->fw_version >= NETXEN_VERSION_CODE(3, 4, 336)) { + switch (adapter->ahw.board_type) { + case NETXEN_BRDTYPE_P2_SB31_10G: + case NETXEN_BRDTYPE_P2_SB31_10G_CX4: + case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ: + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + break; + default: + break; + } + } adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST; adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS; diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index ecd622e..845dcf4 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -36,6 +36,8 @@ */ #define NIC_CRB_BASE NETXEN_CAM_RAM(0x200) #define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X)) +#define NIC_CRB_BASE_2 NETXEN_CAM_RAM(0x700) +#define NETXEN_NIC_REG_2(X) (NIC_CRB_BASE_2+(X)) #define CRB_PHAN_CNTRL_LO_OFFSET NETXEN_NIC_REG(0x00) #define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04) @@ -160,7 +162,8 @@ struct netxen_recv_crb { u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; - u32 crb_sts_consumer; + u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; + u32 sw_int_mask[NUM_STS_DESC_RINGS]; }; /* -- cgit v0.10.2 From a92e9e65f0068a291a677c627a747fae1f230284 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 7 Apr 2009 22:50:47 +0000 Subject: netxen: enable GRO support Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 0c91238..8893a97 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -923,7 +923,8 @@ no_skb: static struct netxen_rx_buffer * netxen_process_rcv(struct netxen_adapter *adapter, - int ring, int index, int length, int cksum, int pkt_offset) + int ring, int index, int length, int cksum, int pkt_offset, + struct nx_host_sds_ring *sds_ring) { struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; @@ -951,7 +952,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - netif_receive_skb(skb); + napi_gro_receive(&sds_ring->napi, skb); adapter->stats.no_rcv++; adapter->stats.rxbytes += length; @@ -1011,7 +1012,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) pkt_offset = netxen_get_sts_pkt_offset(sts_data); rxbuf = netxen_process_rcv(adapter, ring, index, - length, cksum, pkt_offset); + length, cksum, pkt_offset, sds_ring); if (rxbuf) list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index da9b90d..e877eef 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -981,6 +981,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->features |= (NETIF_F_GRO); netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); if (NX_IS_REVISION_P3(revision_id)) { -- cgit v0.10.2 From ea7eaa39ffadffaa8f1dd1a1f85fa38bf8ae9d39 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 7 Apr 2009 22:50:48 +0000 Subject: netxen: cache align register map table Aligning register offset translation table imporves performance on rx side. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 9439f89..3bb2b8c 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -89,7 +89,8 @@ static void __iomem *pci_base_offset(struct netxen_adapter *adapter, } #define CRB_WIN_LOCK_TIMEOUT 100000000 -static crb_128M_2M_block_map_t crb_128M_2M_map[64] = { +static crb_128M_2M_block_map_t +crb_128M_2M_map[64] __cacheline_aligned_in_smp = { {{{0, 0, 0, 0} } }, /* 0: PCI */ {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ {1, 0x0110000, 0x0120000, 0x130000}, -- cgit v0.10.2 From 8509500ac4c82c1e31515ffda6028f88693f49fd Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 8 Apr 2009 15:59:53 -0700 Subject: sfc: Don't specify unexistent IRQ Neither the lm90 driver nor the lm87 driver do support interrupts, so there is no point in specifying one when declaring the devices. Signed-off-by: Jean Delvare Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index 5182ac5..4a4c74c 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c @@ -172,7 +172,6 @@ static const u8 sfe4002_lm87_regs[] = { static struct i2c_board_info sfe4002_hwmon_info = { I2C_BOARD_INFO("lm87", 0x2e), .platform_data = &sfe4002_lm87_channel, - .irq = -1, }; /****************************************************************************/ @@ -247,7 +246,6 @@ static const u8 sfn4112f_lm87_regs[] = { static struct i2c_board_info sfn4112f_hwmon_info = { I2C_BOARD_INFO("lm87", 0x2e), .platform_data = &sfn4112f_lm87_channel, - .irq = -1, }; #define SFN4112F_ACT_LED 0 diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index 4eac5da..cee00ad 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -296,7 +296,6 @@ static int sfe4001_check_hw(struct efx_nic *efx) static struct i2c_board_info sfe4001_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), - .irq = -1, }; /* This board uses an I2C expander to provider power to the PHY, which needs to @@ -389,12 +388,10 @@ static void sfn4111t_fini(struct efx_nic *efx) static struct i2c_board_info sfn4111t_a0_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), - .irq = -1, }; static struct i2c_board_info sfn4111t_r5_hwmon_info = { I2C_BOARD_INFO("max6646", 0x4d), - .irq = -1, }; int sfn4111t_init(struct efx_nic *efx) -- cgit v0.10.2 From a0c31fdfb7f158780faa43ab83cc08b414bebd7e Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 8 Apr 2009 16:01:16 -0700 Subject: ISDN: update Documentation/isdn/00-INDEX After the merging of mISDN, state which files refer only to the old isdn4linux subsystem. Also add a few missing files and sort alphabetically. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX index 9fee5f2..33543ac 100644 --- a/Documentation/isdn/00-INDEX +++ b/Documentation/isdn/00-INDEX @@ -2,28 +2,20 @@ - this file (info on ISDN implementation for Linux) CREDITS - list of the kind folks that brought you this stuff. +HiSax.cert + - information about the ITU approval certification of the HiSax driver. INTERFACE - - description of Linklevel and Hardwarelevel ISDN interface. + - description of isdn4linux Link Level and Hardware Level interfaces. +INTERFACE.fax + - description of the fax subinterface of isdn4linux. README - general info on what you need and what to do for Linux ISDN. README.FAQ - general info for FAQ. -README.audio - - info for running audio over ISDN. -README.fax - - info for using Fax over ISDN. -README.icn - - info on the ICN-ISDN-card and its driver. README.HiSax - info on the HiSax driver which replaces the old teles. -README.hfc-pci - - info on hfc-pci based cards. -README.pcbit - - info on the PCBIT-D ISDN adapter and driver. -README.syncppp - - info on running Sync PPP over ISDN. -syncPPP.FAQ - - frequently asked questions about running PPP over ISDN. +README.audio + - info for running audio over ISDN. README.avmb1 - info on driver for AVM-B1 ISDN card. README.act2000 @@ -34,10 +26,25 @@ README.concap - info on "CONCAP" encapsulation protocol interface used for X.25. README.diversion - info on module for isdn diversion services. +README.fax + - info for using Fax over ISDN. +README.gigaset + - info on the drivers for Siemens Gigaset ISDN adapters +README.hfc-pci + - info on hfc-pci based cards. +README.hysdn + - info on driver for Hypercope active HYSDN cards +README.icn + - info on the ICN-ISDN-card and its driver. +README.mISDN + - info on the Modular ISDN subsystem (mISDN) +README.pcbit + - info on the PCBIT-D ISDN adapter and driver. README.sc - info on driver for Spellcaster cards. +README.syncppp + - info on running Sync PPP over ISDN. README.x25 - _ info for running X.25 over ISDN. -README.hysdn - - info on driver for Hypercope active HYSDN cards - + - info on running X.25 over ISDN. +syncPPP.FAQ + - frequently asked questions about running PPP over ISDN. -- cgit v0.10.2 From 5cd2fe6d54c91aa76893b3034f5f3473063c0202 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Thu, 9 Apr 2009 14:09:36 +0000 Subject: RDS/IW+IB: Set recv ring low water mark to 1/2 full. Currently the recv ring low water mark is 1/4 the depth. Performance measurements show that this limits iWARP throughput by flow controlling the rds-stress senders. Setting it to 1/2 seems to max the T3 performance. I tried even higher levels but that didn't help and it started to increase the rds thread cpu utilization. Signed-off-by: Steve Wise Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_ring.c b/net/rds/ib_ring.c index 99a6cca..ff97e8e 100644 --- a/net/rds/ib_ring.c +++ b/net/rds/ib_ring.c @@ -137,7 +137,7 @@ int rds_ib_ring_empty(struct rds_ib_work_ring *ring) int rds_ib_ring_low(struct rds_ib_work_ring *ring) { - return __rds_ib_ring_used(ring) <= (ring->w_nr >> 2); + return __rds_ib_ring_used(ring) <= (ring->w_nr >> 1); } /* diff --git a/net/rds/iw_ring.c b/net/rds/iw_ring.c index d422d4b..da8e3b6 100644 --- a/net/rds/iw_ring.c +++ b/net/rds/iw_ring.c @@ -137,7 +137,7 @@ int rds_iw_ring_empty(struct rds_iw_work_ring *ring) int rds_iw_ring_low(struct rds_iw_work_ring *ring) { - return __rds_iw_ring_used(ring) <= (ring->w_nr >> 2); + return __rds_iw_ring_used(ring) <= (ring->w_nr >> 1); } -- cgit v0.10.2 From 11bc9421da3040c71fc96da1a31e95217e8cf2af Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 9 Apr 2009 14:09:37 +0000 Subject: RDS: Correct some iw references in rdma_transport.c Had some lingering instances of _iw_ variable names from when the listen code was centralized into rdma_transport.c Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c index 7b19024..7d0f901 100644 --- a/net/rds/rdma_transport.c +++ b/net/rds/rdma_transport.c @@ -34,7 +34,7 @@ #include "rdma_transport.h" -static struct rdma_cm_id *rds_iw_listen_id; +static struct rdma_cm_id *rds_rdma_listen_id; int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id, struct rdma_cm_event *event) @@ -161,7 +161,7 @@ static int __init rds_rdma_listen_init(void) rdsdebug("cm %p listening on port %u\n", cm_id, RDS_PORT); - rds_iw_listen_id = cm_id; + rds_rdma_listen_id = cm_id; cm_id = NULL; out: if (cm_id) @@ -171,10 +171,10 @@ out: static void rds_rdma_listen_stop(void) { - if (rds_iw_listen_id) { - rdsdebug("cm %p\n", rds_iw_listen_id); - rdma_destroy_id(rds_iw_listen_id); - rds_iw_listen_id = NULL; + if (rds_rdma_listen_id) { + rdsdebug("cm %p\n", rds_rdma_listen_id); + rdma_destroy_id(rds_rdma_listen_id); + rds_rdma_listen_id = NULL; } } -- cgit v0.10.2 From d39e0602bb987133321d358d9b837d67c27b223d Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Thu, 9 Apr 2009 14:09:38 +0000 Subject: RDS/IW+IB: Set the RDS_LL_SEND_FULL bit when we're throttled. The RDS_LL_SEND_FULL bit should be set when we stop transmitted due to flow control. Otherwise the send worker will keep trying as opposed to sleeping until we unthrottle. Saves CPU. Signed-off-by: Steve Wise Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index cb6c52c..fa684b7 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -506,7 +506,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, flow_controlled++; } if (work_alloc == 0) { - rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc); + set_bit(RDS_LL_SEND_FULL, &conn->c_flags); rds_ib_stats_inc(s_ib_tx_throttle); ret = -ENOMEM; goto out; diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c index 22dd38f..626290b 100644 --- a/net/rds/iw_send.c +++ b/net/rds/iw_send.c @@ -549,7 +549,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm, flow_controlled++; } if (work_alloc == 0) { - rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc); + set_bit(RDS_LL_SEND_FULL, &conn->c_flags); rds_iw_stats_inc(s_iw_tx_throttle); ret = -ENOMEM; goto out; -- cgit v0.10.2 From 7b70d0336da777c00395cc7a503497c2cdabd1a8 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Thu, 9 Apr 2009 14:09:39 +0000 Subject: RDS/IW+IB: Allow max credit advertise window. Fix hack that restricts the credit advertisement to 127. Signed-off-by: Steve Wise Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib.h b/net/rds/ib.h index 069206c..455ae73 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -333,7 +333,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op); void rds_ib_send_add_credits(struct rds_connection *conn, unsigned int credits); void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted); int rds_ib_send_grab_credits(struct rds_ib_connection *ic, u32 wanted, - u32 *adv_credits, int need_posted); + u32 *adv_credits, int need_posted, int max_posted); /* ib_stats.c */ DECLARE_PER_CPU(struct rds_ib_statistics, rds_ib_stats); diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 36d9315..5709bad 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -524,7 +524,7 @@ void rds_ib_attempt_ack(struct rds_ib_connection *ic) } /* Can we get a send credit? */ - if (!rds_ib_send_grab_credits(ic, 1, &adv_credits, 0)) { + if (!rds_ib_send_grab_credits(ic, 1, &adv_credits, 0, RDS_MAX_ADV_CREDIT)) { rds_ib_stats_inc(s_ib_tx_throttle); clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags); return; diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index fa684b7..23bf830 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -311,7 +311,7 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context) * and using atomic_cmpxchg when updating the two counters. */ int rds_ib_send_grab_credits(struct rds_ib_connection *ic, - u32 wanted, u32 *adv_credits, int need_posted) + u32 wanted, u32 *adv_credits, int need_posted, int max_posted) { unsigned int avail, posted, got = 0, advertise; long oldval, newval; @@ -351,7 +351,7 @@ try_again: * available. */ if (posted && (got || need_posted)) { - advertise = min_t(unsigned int, posted, RDS_MAX_ADV_CREDIT); + advertise = min_t(unsigned int, posted, max_posted); newval -= IB_SET_POST_CREDITS(advertise); } @@ -498,7 +498,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, credit_alloc = work_alloc; if (ic->i_flowctl) { - credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0); + credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT); adv_credits += posted; if (credit_alloc < work_alloc) { rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc); @@ -571,7 +571,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, /* * Update adv_credits since we reset the ACK_REQUIRED bit. */ - rds_ib_send_grab_credits(ic, 0, &posted, 1); + rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits); adv_credits += posted; BUG_ON(adv_credits > 255); } else if (ic->i_rm != rm) diff --git a/net/rds/iw.h b/net/rds/iw.h index b4fb272..0715dde 100644 --- a/net/rds/iw.h +++ b/net/rds/iw.h @@ -361,7 +361,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op); void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits); void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted); int rds_iw_send_grab_credits(struct rds_iw_connection *ic, u32 wanted, - u32 *adv_credits, int need_posted); + u32 *adv_credits, int need_posted, int max_posted); /* ib_stats.c */ DECLARE_PER_CPU(struct rds_iw_statistics, rds_iw_stats); diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index fde470f..8683f5f 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -524,7 +524,7 @@ void rds_iw_attempt_ack(struct rds_iw_connection *ic) } /* Can we get a send credit? */ - if (!rds_iw_send_grab_credits(ic, 1, &adv_credits, 0)) { + if (!rds_iw_send_grab_credits(ic, 1, &adv_credits, 0, RDS_MAX_ADV_CREDIT)) { rds_iw_stats_inc(s_iw_tx_throttle); clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags); return; diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c index 626290b..44a6a05 100644 --- a/net/rds/iw_send.c +++ b/net/rds/iw_send.c @@ -347,7 +347,7 @@ void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context) * and using atomic_cmpxchg when updating the two counters. */ int rds_iw_send_grab_credits(struct rds_iw_connection *ic, - u32 wanted, u32 *adv_credits, int need_posted) + u32 wanted, u32 *adv_credits, int need_posted, int max_posted) { unsigned int avail, posted, got = 0, advertise; long oldval, newval; @@ -387,7 +387,7 @@ try_again: * available. */ if (posted && (got || need_posted)) { - advertise = min_t(unsigned int, posted, RDS_MAX_ADV_CREDIT); + advertise = min_t(unsigned int, posted, max_posted); newval -= IB_SET_POST_CREDITS(advertise); } @@ -541,7 +541,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm, credit_alloc = work_alloc; if (ic->i_flowctl) { - credit_alloc = rds_iw_send_grab_credits(ic, work_alloc, &posted, 0); + credit_alloc = rds_iw_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT); adv_credits += posted; if (credit_alloc < work_alloc) { rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc); @@ -614,7 +614,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm, /* * Update adv_credits since we reset the ACK_REQUIRED bit. */ - rds_iw_send_grab_credits(ic, 0, &posted, 1); + rds_iw_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits); adv_credits += posted; BUG_ON(adv_credits > 255); } else if (ic->i_rm != rm) diff --git a/net/rds/rds.h b/net/rds/rds.h index 619f0a3..1f82ec0 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -132,7 +132,7 @@ struct rds_connection { #define RDS_FLAG_CONG_BITMAP 0x01 #define RDS_FLAG_ACK_REQUIRED 0x02 #define RDS_FLAG_RETRANSMITTED 0x04 -#define RDS_MAX_ADV_CREDIT 127 +#define RDS_MAX_ADV_CREDIT 255 /* * Maximum space available for extension headers. -- cgit v0.10.2 From 7acd4a794c1530af063e51f3f7171e75556458f3 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 9 Apr 2009 14:09:40 +0000 Subject: RDS: Fix ordering in a conditional Putting the constant first is a supposed "best practice" that actually makes the code harder to read. Thanks to Roland Dreier for finding a bug in this "simple, obviously correct" patch. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/rdma.c b/net/rds/rdma.c index eaeeb91..e390dc7 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -155,7 +155,7 @@ static int rds_pin_pages(unsigned long user_addr, unsigned int nr_pages, nr_pages, write, 0, pages, NULL); up_read(¤t->mm->mmap_sem); - if (0 <= ret && (unsigned) ret < nr_pages) { + if (ret >= 0 && ret < nr_pages) { while (ret--) put_page(pages[ret]); ret = -EFAULT; -- cgit v0.10.2 From 49f696914100780f6bf8e652d3468de0015d6172 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 9 Apr 2009 14:09:41 +0000 Subject: RDS: Establish connection before parsing CMSGs The first message to a remote node should prompt a new connection. Even an RDMA op via CMSG. Therefore move CMSG parsing to after connection establishment. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/send.c b/net/rds/send.c index 104fe03..a4a7f42 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -854,11 +854,6 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, rm->m_daddr = daddr; - /* Parse any control messages the user may have included. */ - ret = rds_cmsg_send(rs, rm, msg, &allocated_mr); - if (ret) - goto out; - /* rds_conn_create has a spinlock that runs with IRQ off. * Caching the conn in the socket helps a lot. */ if (rs->rs_conn && rs->rs_conn->c_faddr == daddr) @@ -874,6 +869,11 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, rs->rs_conn = conn; } + /* Parse any control messages the user may have included. */ + ret = rds_cmsg_send(rs, rm, msg, &allocated_mr); + if (ret) + goto out; + if ((rm->m_rdma_cookie || rm->m_rdma_op) && conn->c_trans->xmit_rdma == NULL) { if (printk_ratelimit()) -- cgit v0.10.2 From 830eb7d56c18ff4c29acd8b0bb48db404660321f Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 9 Apr 2009 14:09:42 +0000 Subject: RDS: use get_user_pages_fast() Use the new function that is simpler and faster. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/info.c b/net/rds/info.c index 1d88553..62aeef3 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -188,10 +188,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, ret = -ENOMEM; goto out; } - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, start, nr_pages, 1, 0, - pages, NULL); - up_read(¤t->mm->mmap_sem); + ret = get_user_pages_fast(start, nr_pages, 1, pages); if (ret != nr_pages) { if (ret > 0) nr_pages = ret; diff --git a/net/rds/rdma.c b/net/rds/rdma.c index e390dc7..8dc83d2 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -150,10 +150,7 @@ static int rds_pin_pages(unsigned long user_addr, unsigned int nr_pages, { int ret; - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, user_addr, - nr_pages, write, 0, pages, NULL); - up_read(¤t->mm->mmap_sem); + ret = get_user_pages_fast(user_addr, nr_pages, write, pages); if (ret >= 0 && ret < nr_pages) { while (ret--) -- cgit v0.10.2 From 9c56a84478b708e5d8d34d28cc3a8e71842d5b05 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Thu, 9 Apr 2009 14:09:43 +0000 Subject: RDS: remove unused #include Remove unused #include in net/rds/af_rds.c. Signed-off-by: Huang Weiyi Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 20cf16f..b11e7e5 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "rds.h" -- cgit v0.10.2 From 05a178ecdc7396b78dfbb5d8bda65108b37b8672 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 9 Apr 2009 14:09:44 +0000 Subject: rds: use kmem_cache_zalloc instead of kmem_cache_alloc/memset Use kmem_cache_zalloc instead of kmem_cache_alloc/memset. Signed-off-by: Wei Yongjun Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/connection.c b/net/rds/connection.c index 273f064..d14445c 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -148,14 +148,12 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, if (conn) goto out; - conn = kmem_cache_alloc(rds_conn_slab, gfp); + conn = kmem_cache_zalloc(rds_conn_slab, gfp); if (conn == NULL) { conn = ERR_PTR(-ENOMEM); goto out; } - memset(conn, 0, sizeof(*conn)); - INIT_HLIST_NODE(&conn->c_hash_node); conn->c_version = RDS_PROTOCOL_3_0; conn->c_laddr = laddr; -- cgit v0.10.2 From 5d57eeb52ae71a03c8e083a9b0a818a9b63ca440 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Apr 2009 14:09:45 +0000 Subject: ERR_PTR() dereference in net/rds/iw.c rdma_create_id() returns ERR_PTR() not null. Found by smatch (http://repo.or.cz/w/smatch.git). Compile tested. regards, dan carpenter Signed-off-by: Dan Carpenter Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/iw.c b/net/rds/iw.c index b732efb..d16e1cb 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c @@ -233,8 +233,8 @@ static int rds_iw_laddr_check(__be32 addr) * IB and iWARP capable NICs. */ cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP); - if (!cm_id) - return -EADDRNOTAVAIL; + if (IS_ERR(cm_id)) + return PTR_ERR(cm_id); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; -- cgit v0.10.2 From 94713bab649736177a1c33a39b7bb33cbd5af3a5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Apr 2009 14:09:46 +0000 Subject: ERR_PTR() dereference in net/rds/ib.c rdma_create_id() doesn't return NULL, only ERR_PTR(). Found by smatch (http://repo.or.cz/w/smatch.git). Compile tested. regards, dan carpenter Signed-off-by: Dan Carpenter Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib.c b/net/rds/ib.c index 4933b38..b9bcd32 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -224,8 +224,8 @@ static int rds_ib_laddr_check(__be32 addr) * IB and iWARP capable NICs. */ cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP); - if (!cm_id) - return -EADDRNOTAVAIL; + if (IS_ERR(cm_id)) + return PTR_ERR(cm_id); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; -- cgit v0.10.2 From fbb5a5583034e98f87fcff94183637486d7ada18 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 9 Apr 2009 14:09:47 +0000 Subject: MAINTAINERS: rds list is moderated Signed-off-by: Kyle McMartin Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index c3b2159..28421c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3729,7 +3729,7 @@ S: Maintained RDS - RELIABLE DATAGRAM SOCKETS P: Andy Grover M: andy.grover@oracle.com -L: rds-devel@oss.oracle.com +L: rds-devel@oss.oracle.com (moderated for non-subscribers) S: Supported READ-COPY UPDATE (RCU) -- cgit v0.10.2 From 2132d38133f48ef51d28252bb9c0b792f5b57019 Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Thu, 9 Apr 2009 22:26:21 +0000 Subject: ixgbe: Enable another bit for flow control operation The discard pause frames bit was not enabled, so flow control frames could be passed up to the host. Enabled DPF to keep the frames off the stack. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index de4db0d..63aacd5 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -322,6 +322,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) } /* Enable 802.3x based flow control settings. */ + fctrl_reg |= IXGBE_FCTRL_DPF; IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg); IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 63ab667..846c9de 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1700,6 +1700,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) } /* Enable 802.3x based flow control settings. */ + mflcn_reg |= IXGBE_MFLCN_DPF; IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); -- cgit v0.10.2 From d988eadbe2d93b5a2d4aa4ec46264e0f6213a71c Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 9 Apr 2009 22:26:40 +0000 Subject: ixgbe: fix IXGBE_MTQC values IXGBE_MTQC_64VF was wrong and 32VF not defined at all. This patch corrects that. Signed-off-by: Don Skidmore Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 030ff0a..0d25036 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1553,7 +1553,8 @@ #define IXGBE_MTQC_RT_ENA 0x1 /* DCB Enable */ #define IXGBE_MTQC_VT_ENA 0x2 /* VMDQ2 Enable */ #define IXGBE_MTQC_64Q_1PB 0x0 /* 64 queues 1 pack buffer */ -#define IXGBE_MTQC_64VF 0x8 /* 2 TX Queues per pool w/64VF's */ +#define IXGBE_MTQC_32VF 0x8 /* 4 TX Queues per pool w/32VF's */ +#define IXGBE_MTQC_64VF 0x4 /* 2 TX Queues per pool w/64VF's */ #define IXGBE_MTQC_8TC_8TQ 0xC /* 8 TC if RT_ENA or 8 TQ if VT_ENA */ /* Receive Descriptor bit definitions */ -- cgit v0.10.2 From 6e4e87d68a89028204fe744a8eda8f74bff5b6a9 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 9 Apr 2009 22:27:00 +0000 Subject: ixgbe: add support for addition VT_CTL defines These defines allow for definition of target pool for packets that pass L2 filtering but didn't pass any of the pool filters. They are needed to reset the default pool. Signed-off-by: Don Skidmore Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 0d25036..50285c2 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -958,6 +958,8 @@ #define IXGBE_VT_CTL_DIS_DEFPL 0x20000000 /* disable default pool */ #define IXGBE_VT_CTL_REPLEN 0x40000000 /* replication enabled */ #define IXGBE_VT_CTL_VT_ENABLE 0x00000001 /* Enable VT Mode */ +#define IXGBE_VT_CTL_POOL_SHIFT 7 +#define IXGBE_VT_CTL_POOL_MASK (0x3F << IXGBE_VT_CTL_POOL_SHIFT) /* VMOLR bitmasks */ #define IXGBE_VMOLR_AUPE 0x01000000 /* accept untagged packets */ -- cgit v0.10.2 From e80e887a959ca41066412582c5f79aae5ffd5821 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 9 Apr 2009 22:27:19 +0000 Subject: ixgbe: add define to support 82599 64 IVAR registers 82599 supports 64 IVAR registers this patch adds a define to allow us to access them. Signed-off-by: Don Skidmore Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 50285c2..96e15d0 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1150,6 +1150,7 @@ /* Interrupt Vector Allocation Registers */ #define IXGBE_IVAR_REG_NUM 25 +#define IXGBE_IVAR_REG_NUM_82599 64 #define IXGBE_IVAR_TXRX_ENTRY 96 #define IXGBE_IVAR_RX_ENTRY 64 #define IXGBE_IVAR_RX_QUEUE(_i) (0 + (_i)) -- cgit v0.10.2 From d3e9c56cafb98040c8601dcc784a773ac86da18b Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Thu, 9 Apr 2009 22:27:39 +0000 Subject: ixgbe: Don't return error in flow control configuration if FC is off When flow control is disabled, an invalid low/high watermark configuration should not matter. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 63aacd5..1e1d8b7 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -381,9 +381,11 @@ static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) * because it causes the controller to just blast out fc packets. */ if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; + if (hw->fc.requested_mode != ixgbe_fc_none) { + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } } /* diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 846c9de..2d4af5d 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1907,9 +1907,11 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) * because it causes the controller to just blast out fc packets. */ if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; + if (hw->fc.requested_mode != ixgbe_fc_none) { + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } } /* -- cgit v0.10.2 From 04f165ef4f18444854865d44a3359618480060af Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Thu, 9 Apr 2009 22:27:57 +0000 Subject: ixgbe: Move PHY ops initialization to centralize bus accesses When PHY operations are determined, the PHY must be identified. This identification causes bus access, and should be contained within its own routines. This also helps the 82599 PHY init paths for both SFP+ and KX/KX4 devices to be easier to maintain. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 1e1d8b7..a8151f2 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -75,18 +75,49 @@ static u16 ixgbe_get_pcie_msix_count_82598(struct ixgbe_hw *hw) static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; + + /* Call PHY identify routine to get the phy type */ + ixgbe_identify_phy_generic(hw); + + 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; + mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82598(hw); + + return 0; +} + +/** + * ixgbe_init_phy_ops_82598 - PHY/SFP specific init + * @hw: pointer to hardware structure + * + * Initialize any function pointers that were not able to be + * set during get_invariants because the PHY/SFP type was + * not known. Perform the SFP init if necessary. + * + **/ +s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; s32 ret_val = 0; u16 list_offset, data_offset; - /* Set the bus information prior to PHY identification */ - mac->ops.get_bus_info(hw); + /* Identify the PHY */ + phy->ops.identify(hw); - /* Call PHY identify routine to get the phy type */ - ixgbe_identify_phy_generic(hw); + /* Overwrite the link function pointers if copper PHY */ + 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; + } - /* PHY Init */ - switch (phy->type) { + switch (hw->phy.type) { case ixgbe_phy_tn: phy->ops.check_link = &ixgbe_check_phy_link_tnx; phy->ops.get_firmware_version = @@ -106,8 +137,8 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) /* Check to see if SFP+ module is supported */ ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, - &list_offset, - &data_offset); + &list_offset, + &data_offset); if (ret_val != 0) { ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; goto out; @@ -117,21 +148,6 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) 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; - mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82598(hw); - out: return ret_val; } @@ -719,14 +735,23 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) } /* Reset PHY */ - if (hw->phy.reset_disable == false) + if (hw->phy.reset_disable == false) { + /* PHY ops must be identified and initialized prior to reset */ + + /* Init PHY and function pointers, perform SFP setup */ + status = hw->phy.ops.init(hw); + if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto reset_hw_out; + hw->phy.ops.reset(hw); + } /* * Prevent the PCI-E bus from from hanging by disabling PCI-E master * access and verify no pending requests before reset */ - if (ixgbe_disable_pcie_master(hw) != 0) { + status = ixgbe_disable_pcie_master(hw); + if (status != 0) { status = IXGBE_ERR_MASTER_REQUESTS_PENDING; hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); } @@ -773,6 +798,7 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) /* Store the permanent mac address */ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); +reset_hw_out: return status; } @@ -1157,6 +1183,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82598 = { static struct ixgbe_phy_operations phy_ops_82598 = { .identify = &ixgbe_identify_phy_generic, .identify_sfp = &ixgbe_identify_sfp_module_generic, + .init = &ixgbe_init_phy_ops_82598, .reset = &ixgbe_reset_phy_generic, .read_reg = &ixgbe_read_phy_reg_generic, .write_reg = &ixgbe_write_phy_reg_generic, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index beae7e0..9a99989 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -148,51 +148,60 @@ u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw) static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; - struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val; - /* Set the bus information prior to PHY identification */ - mac->ops.get_bus_info(hw); + ixgbe_init_mac_link_ops_82599(hw); - /* Call PHY identify routine to get the Cu or SFI phy type */ - ret_val = phy->ops.identify(hw); + mac->mcft_size = IXGBE_82599_MC_TBL_SIZE; + mac->vft_size = IXGBE_82599_VFT_TBL_SIZE; + mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES; + mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES; + mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES; + mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82599(hw); - if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED) - goto get_invariants_out; + return 0; +} - ixgbe_init_mac_link_ops_82599(hw); +/** + * ixgbe_init_phy_ops_82599 - PHY/SFP specific init + * @hw: pointer to hardware structure + * + * Initialize any function pointers that were not able to be + * set during get_invariants because the PHY/SFP type was + * not known. Perform the SFP init if necessary. + * + **/ +s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; + s32 ret_val = 0; - /* Setup SFP module if there is one present. */ - ret_val = mac->ops.setup_sfp(hw); + /* Identify the PHY or SFP module */ + ret_val = phy->ops.identify(hw); + + /* Setup function pointers based on detected SFP module and speeds */ + ixgbe_init_mac_link_ops_82599(hw); /* If copper media, overwrite with copper function pointers */ if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { mac->ops.setup_link = &ixgbe_setup_copper_link_82599; mac->ops.setup_link_speed = - &ixgbe_setup_copper_link_speed_82599; + &ixgbe_setup_copper_link_speed_82599; mac->ops.get_link_capabilities = &ixgbe_get_copper_link_capabilities_82599; } - /* PHY Init */ + /* Set necessary function pointers based on phy type */ switch (hw->phy.type) { case ixgbe_phy_tn: phy->ops.check_link = &ixgbe_check_phy_link_tnx; phy->ops.get_firmware_version = - &ixgbe_get_phy_firmware_version_tnx; + &ixgbe_get_phy_firmware_version_tnx; break; default: break; } - mac->mcft_size = IXGBE_82599_MC_TBL_SIZE; - mac->vft_size = IXGBE_82599_VFT_TBL_SIZE; - mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES; - mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES; - mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES; - mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82599(hw); - -get_invariants_out: return ret_val; } @@ -708,13 +717,24 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) hw->mac.ops.stop_adapter(hw); /* Reset PHY */ - hw->phy.ops.reset(hw); + if (hw->phy.reset_disable == false) { + /* PHY ops must be identified and initialized prior to reset */ + + /* Init PHY and function pointers, perform SFP setup */ + status = hw->phy.ops.init(hw); + + if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto reset_hw_out; + + hw->phy.ops.reset(hw); + } /* * Prevent the PCI-E bus from from hanging by disabling PCI-E master * access and verify no pending requests before reset */ - if (ixgbe_disable_pcie_master(hw) != 0) { + status = ixgbe_disable_pcie_master(hw); + if (status != 0) { status = IXGBE_ERR_MASTER_REQUESTS_PENDING; hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); } @@ -775,6 +795,7 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) /* Store the permanent mac address */ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); +reset_hw_out: return status; } @@ -1272,6 +1293,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82599 = { static struct ixgbe_phy_operations phy_ops_82599 = { .identify = &ixgbe_identify_phy_82599, .identify_sfp = &ixgbe_identify_sfp_module_generic, + .init = &ixgbe_init_phy_ops_82599, .reset = &ixgbe_reset_phy_generic, .read_reg = &ixgbe_read_phy_reg_generic, .write_reg = &ixgbe_write_phy_reg_generic, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 9ef128a..936a3ef 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4630,7 +4630,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* reset_hw fills in the perm_addr as well */ err = hw->mac.ops.reset_hw(hw); - if (err) { + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + dev_err(&adapter->pdev->dev, "failed to load because an " + "unsupported SFP+ module type was detected.\n"); + goto err_sw_init; + } else if (err) { dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err); goto err_sw_init; } @@ -4703,6 +4707,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, device_init_wakeup(&adapter->pdev->dev, true); device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + /* pick up the PCI bus settings for reporting later */ + hw->mac.ops.get_bus_info(hw); + /* print bus type/speed/width info */ dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n", ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s": diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 96e15d0..06d7e8a 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2150,6 +2150,7 @@ struct ixgbe_mac_operations { struct ixgbe_phy_operations { s32 (*identify)(struct ixgbe_hw *); s32 (*identify_sfp)(struct ixgbe_hw *); + s32 (*init)(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); -- cgit v0.10.2 From 553b449784e27bb7244c41aa27397d29f213e5a3 Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Thu, 9 Apr 2009 22:28:15 +0000 Subject: ixgbe: Remove unnecessary PHY reset, properly identify multispeed fiber modules This patch does two things: 1) On 82599, the PHY is emedded in the MAC. On 82598, the SFP+ NIC has an external PHY. The reset in the SFP+ setup patch for 82598 is unnecessary on 82599, and adds extra dead time to device initialization. This removes that PHY reset for 82599 only. 2) On 82599, the SFP+ modules are multispeed fiber modules (10G/1G). We need to make sure to identify them properly for the remaining init sections to properly set them up. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 9a99989..72a0d27 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -102,6 +102,9 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { ixgbe_init_mac_link_ops_82599(hw); + + hw->phy.ops.reset = NULL; + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, &data_offset); @@ -716,19 +719,24 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) /* Call adapter stop to disable tx/rx and clear interrupts */ hw->mac.ops.stop_adapter(hw); - /* Reset PHY */ - if (hw->phy.reset_disable == false) { - /* PHY ops must be identified and initialized prior to reset */ + /* PHY ops must be identified and initialized prior to reset */ - /* Init PHY and function pointers, perform SFP setup */ - status = hw->phy.ops.init(hw); + /* Init PHY and function pointers, perform SFP setup */ + status = hw->phy.ops.init(hw); - if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) - goto reset_hw_out; + if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto reset_hw_out; - hw->phy.ops.reset(hw); + /* Setup SFP module if there is one present. */ + if (hw->phy.sfp_setup_needed) { + status = hw->mac.ops.setup_sfp(hw); + hw->phy.sfp_setup_needed = false; } + /* Reset PHY */ + if (hw->phy.reset_disable == false && hw->phy.ops.reset != NULL) + hw->phy.ops.reset(hw); + /* * Prevent the PCI-E bus from from hanging by disabling PCI-E master * access and verify no pending requests before reset diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 14e9606..6f11df7 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -552,6 +552,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; u32 vendor_oui = 0; + enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; u8 identifier = 0; u8 comp_codes_1g = 0; u8 comp_codes_10g = 0; @@ -620,6 +621,16 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_type = ixgbe_sfp_type_unknown; } + if (hw->phy.sfp_type != stored_sfp_type) + hw->phy.sfp_setup_needed = true; + + /* Determine if the SFP+ PHY is dual speed or not. */ + if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && + (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || + ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && + (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) + hw->phy.multispeed_fiber = true; + /* Determine PHY vendor */ if (hw->phy.type == ixgbe_phy_unknown) { hw->phy.id = identifier; diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index cc5f1b3..c9964b7 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -44,6 +44,7 @@ /* Bitmasks */ #define IXGBE_SFF_TWIN_AX_CAPABLE 0x80 #define IXGBE_SFF_1GBASESX_CAPABLE 0x1 +#define IXGBE_SFF_1GBASELX_CAPABLE 0x2 #define IXGBE_SFF_10GBASESR_CAPABLE 0x10 #define IXGBE_SFF_10GBASELR_CAPABLE 0x20 #define IXGBE_I2C_EEPROM_READ_MASK 0x100 diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 06d7e8a..db65c05 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2198,6 +2198,7 @@ struct ixgbe_phy_info { u32 addr; u32 id; enum ixgbe_sfp_type sfp_type; + bool sfp_setup_needed; u32 revision; enum ixgbe_media_type media_type; bool reset_disable; -- cgit v0.10.2 From 1eb99d5ac44e2a9ac0b2856c579ba4d7cc349ada Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Thu, 9 Apr 2009 22:28:33 +0000 Subject: ixgbe: Update the usage of orig_autoc to be more consistent The orig_autoc variable tracks the original setting of the autonegotiate state prior to trying a new speed. The usage is inconsistent and not very maintainable. This patch updates the usage to make it more consistent. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index a8151f2..361c9d1d 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -165,12 +165,19 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, bool *autoneg) { s32 status = 0; + u32 autoc = 0; /* * Determine link capabilities based on the stored value of AUTOC, - * which represents EEPROM defaults. + * which represents EEPROM defaults. If AUTOC value has not been + * stored, use the current register value. */ - switch (hw->mac.orig_autoc & IXGBE_AUTOC_LMS_MASK) { + if (hw->mac.orig_link_settings_stored) + autoc = hw->mac.orig_autoc; + else + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + switch (autoc & IXGBE_AUTOC_LMS_MASK) { case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: *speed = IXGBE_LINK_SPEED_1GB_FULL; *autoneg = false; @@ -189,9 +196,9 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, case IXGBE_AUTOC_LMS_KX4_AN: case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: *speed = IXGBE_LINK_SPEED_UNKNOWN; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (autoc & IXGBE_AUTOC_KX4_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP) + if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; *autoneg = true; break; diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 72a0d27..50b399c 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -221,8 +221,19 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, bool *negotiation) { s32 status = 0; + u32 autoc = 0; - switch (hw->mac.orig_autoc & IXGBE_AUTOC_LMS_MASK) { + /* + * Determine link capabilities based on the stored value of AUTOC, + * which represents EEPROM defaults. If AUTOC value has not been + * stored, use the current register value. + */ + if (hw->mac.orig_link_settings_stored) + autoc = hw->mac.orig_autoc; + else + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + switch (autoc & IXGBE_AUTOC_LMS_MASK) { case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: *speed = IXGBE_LINK_SPEED_1GB_FULL; *negotiation = false; @@ -246,22 +257,22 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, case IXGBE_AUTOC_LMS_KX4_KX_KR: case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN: *speed = IXGBE_LINK_SPEED_UNKNOWN; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP) + if (autoc & IXGBE_AUTOC_KR_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (autoc & IXGBE_AUTOC_KX4_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP) + if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; *negotiation = true; break; case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII: *speed = IXGBE_LINK_SPEED_100_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP) + if (autoc & IXGBE_AUTOC_KR_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (autoc & IXGBE_AUTOC_KX4_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP) + if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; *negotiation = true; break; @@ -572,6 +583,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + u32 orig_autoc = 0; u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK; u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; @@ -583,6 +595,13 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, hw->mac.ops.get_link_capabilities(hw, &link_capabilities, &autoneg); speed &= link_capabilities; + /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ + if (hw->mac.orig_link_settings_stored) + orig_autoc = hw->mac.orig_autoc; + else + orig_autoc = autoc; + + if (speed == IXGBE_LINK_SPEED_UNKNOWN) { status = IXGBE_ERR_LINK_SETUP; } else if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || @@ -591,9 +610,9 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, /* Set KX4/KX/KR support according to speed requested */ autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP); if (speed & IXGBE_LINK_SPEED_10GB_FULL) - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (orig_autoc & IXGBE_AUTOC_KX4_SUPP) autoc |= IXGBE_AUTOC_KX4_SUPP; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP) + if (orig_autoc & IXGBE_AUTOC_KR_SUPP) autoc |= IXGBE_AUTOC_KR_SUPP; if (speed & IXGBE_LINK_SPEED_1GB_FULL) autoc |= IXGBE_AUTOC_KX_SUPP; -- cgit v0.10.2 From 04193058c1005551af93f04a4b975fbd7f95cad5 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 9 Apr 2009 22:28:50 +0000 Subject: ixgbe: Update get_physical_layer() calls, plus a version bump Not all physical connection types are being correctly identified. This fixes that issue, and cleans up the logic to make it more maintainable. Also clean up the code for device capabilities from the EEPROM to support multiple SKUs of the same hardware. Bump the version to reflect all the updates since the 82599 merge. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 361c9d1d..a7ae4d4 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -1089,35 +1089,56 @@ out: static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) { u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 pma_pmd_10g = autoc & IXGBE_AUTOC_10G_PMA_PMD_MASK; + u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; + u16 ext_ability = 0; + + hw->phy.ops.identify(hw); + + /* Copper PHY must be checked before AUTOC LMS to determine correct + * physical layer because 10GBase-T PHYs use LMS = KX4/KX */ + if (hw->phy.type == ixgbe_phy_tn || + hw->phy.type == ixgbe_phy_cu_unknown) { + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability); + if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; + if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; + if (ext_ability & IXGBE_MDIO_PHY_100BASETX_ABILITY) + physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; + goto out; + } - switch (hw->device_id) { - case IXGBE_DEV_ID_82598: - /* Default device ID is mezzanine card KX/KX4 */ - physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | - IXGBE_PHYSICAL_LAYER_1000BASE_KX); - break; - case IXGBE_DEV_ID_82598_BX: - physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_BX; - 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_82598_DA_DUAL_PORT: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + switch (autoc & IXGBE_AUTOC_LMS_MASK) { + case IXGBE_AUTOC_LMS_1G_AN: + case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: + if (pma_pmd_1g == IXGBE_AUTOC_1G_KX) + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX; + else + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_BX; break; - case IXGBE_DEV_ID_82598AF_DUAL_PORT: - case IXGBE_DEV_ID_82598AF_SINGLE_PORT: - case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: + if (pma_pmd_10g == IXGBE_AUTOC_10G_CX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; + else if (pma_pmd_10g == IXGBE_AUTOC_10G_KX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4; + else /* XAUI */ + physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; break; - case IXGBE_DEV_ID_82598EB_XF_LR: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + case IXGBE_AUTOC_LMS_KX4_AN: + case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: + if (autoc & IXGBE_AUTOC_KX_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_KX; + if (autoc & IXGBE_AUTOC_KX4_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KX4; break; - case IXGBE_DEV_ID_82598AT: - physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T | - IXGBE_PHYSICAL_LAYER_1000BASE_T); + default: break; - case IXGBE_DEV_ID_82598EB_SFP_LOM: + } + + if (hw->phy.type == ixgbe_phy_nl) { hw->phy.ops.identify_sfp(hw); switch (hw->phy.sfp_type) { @@ -1134,13 +1155,25 @@ static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; break; } - break; + } + switch (hw->device_id) { + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: + 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; } +out: return physical_layer; } diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 50b399c..b3f4e96 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1177,53 +1177,98 @@ s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) { u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; + u32 pma_pmd_10g_parallel = autoc & IXGBE_AUTOC_10G_PMA_PMD_MASK; + u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; + u16 ext_ability = 0; u8 comp_codes_10g = 0; - switch (hw->device_id) { - case IXGBE_DEV_ID_82599: - case IXGBE_DEV_ID_82599_KX4: - /* Default device ID is mezzanine card KX/KX4 */ - physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | - IXGBE_PHYSICAL_LAYER_1000BASE_KX); + hw->phy.ops.identify(hw); + + if (hw->phy.type == ixgbe_phy_tn || + hw->phy.type == ixgbe_phy_cu_unknown) { + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability); + if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; + if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; + if (ext_ability & IXGBE_MDIO_PHY_100BASETX_ABILITY) + physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; + goto out; + } + + switch (autoc & IXGBE_AUTOC_LMS_MASK) { + case IXGBE_AUTOC_LMS_1G_AN: + case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: + if (pma_pmd_1g == IXGBE_AUTOC_1G_KX_BX) { + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX | + IXGBE_PHYSICAL_LAYER_1000BASE_BX; + goto out; + } else + /* SFI mode so read SFP module */ + goto sfp_check; break; - case IXGBE_DEV_ID_82599_SFP: - hw->phy.ops.identify_sfp(hw); + case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: + if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_CX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; + else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_KX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4; + goto out; + break; + case IXGBE_AUTOC_LMS_10G_SERIAL: + if (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_KR) { + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR; + goto out; + } else if (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_SFI) + goto sfp_check; + break; + case IXGBE_AUTOC_LMS_KX4_KX_KR: + case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN: + if (autoc & IXGBE_AUTOC_KX_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_KX; + if (autoc & IXGBE_AUTOC_KX4_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KX4; + if (autoc & IXGBE_AUTOC_KR_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KR; + goto out; + break; + default: + goto out; + break; + } - switch (hw->phy.sfp_type) { - case ixgbe_sfp_type_da_cu: - case ixgbe_sfp_type_da_cu_core0: - case ixgbe_sfp_type_da_cu_core1: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; - break; - case ixgbe_sfp_type_sr: +sfp_check: + /* SFP check must be done last since DA modules are sometimes used to + * test KR mode - we need to id KR mode correctly before SFP module. + * Call identify_sfp because the pluggable module may have changed */ + hw->phy.ops.identify_sfp(hw); + if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) + goto out; + + switch (hw->phy.type) { + case ixgbe_phy_tw_tyco: + case ixgbe_phy_tw_unknown: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; + case ixgbe_phy_sfp_avago: + case ixgbe_phy_sfp_ftl: + case ixgbe_phy_sfp_intel: + case ixgbe_phy_sfp_unknown: + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); + if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; - break; - case ixgbe_sfp_type_lr: + else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; - break; - case ixgbe_sfp_type_srlr_core0: - case ixgbe_sfp_type_srlr_core1: - hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_10GBE_COMP_CODES, - &comp_codes_10g); - if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) - physical_layer = - IXGBE_PHYSICAL_LAYER_10GBASE_SR; - else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) - physical_layer = - IXGBE_PHYSICAL_LAYER_10GBASE_LR; - else - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - default: - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - break; - } break; default: - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; break; } +out: return physical_layer; } @@ -1271,6 +1316,22 @@ s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) return 0; } +/** + * ixgbe_get_device_caps_82599 - Get additional device capabilities + * @hw: pointer to hardware structure + * @device_caps: the EEPROM word with the extra device capabilities + * + * This function will read the EEPROM location for the device capabilities, + * and return the word through device_caps. + **/ +s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) +{ + hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); + + return 0; +} + + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, @@ -1280,6 +1341,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82599, .enable_rx_dma = &ixgbe_enable_rx_dma_82599, .get_mac_addr = &ixgbe_get_mac_addr_generic, + .get_device_caps = &ixgbe_get_device_caps_82599, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 936a3ef..2856486 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -47,7 +47,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.8-k2" +#define DRV_VERSION "2.0.16-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 6f11df7..f3258ec 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -632,7 +632,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.multispeed_fiber = true; /* Determine PHY vendor */ - if (hw->phy.type == ixgbe_phy_unknown) { + if (hw->phy.type != ixgbe_phy_nl) { hw->phy.id = identifier; hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_VENDOR_OUI_BYTE0, @@ -682,9 +682,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) goto out; } - hw->eeprom.ops.read(hw, IXGBE_PHY_ENFORCE_INTEL_SFP_OFFSET, - &enforce_sfp); - if (!(enforce_sfp & IXGBE_PHY_ALLOW_ANY_SFP)) { + /* This is guaranteed to be 82599, no need to check for NULL */ + hw->mac.ops.get_device_caps(hw, &enforce_sfp); + if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { /* Make sure we're a supported PHY type */ if (hw->phy.type == ixgbe_phy_sfp_intel) { status = 0; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index db65c05..a3317d8 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -862,6 +862,7 @@ #define IXGBE_MDIO_PHY_EXT_ABILITY 0xB /* Ext Ability Reg */ #define IXGBE_MDIO_PHY_10GBASET_ABILITY 0x0004 /* 10GBaseT capable */ #define IXGBE_MDIO_PHY_1000BASET_ABILITY 0x0020 /* 1000BaseT capable */ +#define IXGBE_MDIO_PHY_100BASETX_ABILITY 0x0080 /* 100BaseTX capable */ #define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Addr Reg */ #define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA 0xC30B /* PHY_XS SDA/SCL Data Reg */ @@ -898,8 +899,6 @@ #define IXGBE_CONTROL_NL 0x000F #define IXGBE_CONTROL_EOL_NL 0x0FFF #define IXGBE_CONTROL_SOL_NL 0x0000 -#define IXGBE_PHY_ENFORCE_INTEL_SFP_OFFSET 0x002C -#define IXGBE_PHY_ALLOW_ANY_SFP 0x1 /* General purpose Interrupt Enable */ #define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ @@ -1385,6 +1384,7 @@ #define IXGBE_FW_PTR 0x0F #define IXGBE_PBANUM0_PTR 0x15 #define IXGBE_PBANUM1_PTR 0x16 +#define IXGBE_DEVICE_CAPS 0x2C #define IXGBE_PCIE_MSIX_82599_CAPS 0x72 #define IXGBE_PCIE_MSIX_82598_CAPS 0x62 @@ -1428,6 +1428,8 @@ #define IXGBE_EERD_ATTEMPTS 100000 #endif +#define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 + /* PCI Bus Info */ #define IXGBE_PCI_LINK_STATUS 0xB2 #define IXGBE_PCI_LINK_WIDTH 0x3F0 @@ -1865,7 +1867,7 @@ 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_100BASE_TX 0x0004 #define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU 0x0008 #define IXGBE_PHYSICAL_LAYER_10GBASE_LR 0x0010 #define IXGBE_PHYSICAL_LAYER_10GBASE_LRM 0x0020 @@ -1874,6 +1876,7 @@ typedef u32 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_10GBASE_CX4 0x0100 #define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x0200 #define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x0400 +#define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x0800 enum ixgbe_eeprom_type { ixgbe_eeprom_uninitialized = 0, @@ -2105,6 +2108,7 @@ struct ixgbe_mac_operations { enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); u32 (*get_supported_physical_layer)(struct ixgbe_hw *); s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); + s32 (*get_device_caps)(struct ixgbe_hw *, u16 *); s32 (*stop_adapter)(struct ixgbe_hw *); s32 (*get_bus_info)(struct ixgbe_hw *); void (*set_lan_id)(struct ixgbe_hw *); -- cgit v0.10.2 From 8d1c3c0746098bee8ad116073120166347f21719 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Thu, 9 Apr 2009 22:29:10 +0000 Subject: ixgbe: Be explict with what we are !'ing in ixgbe_sfp_config_module_task() GCC warns: drivers/net/ixgbe/ixgbe_main.c: In function 'ixgbe_sfp_config_module_task': drivers/net/ixgbe/ixgbe_main.c:3920: warning: suggest parantheses around operand of '!' or change '&' to '&&' or '!' to '~' Which I think is right. Bracket to remove ambiguity. Signed-off-by: Tony Breeds Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 2856486..813c5bc 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3917,7 +3917,7 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work) } hw->mac.ops.setup_sfp(hw); - if (!adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK) + if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) /* This will also work for DA Twinax connections */ schedule_work(&adapter->multispeed_fiber_task); adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK; -- cgit v0.10.2 From 728a9972d1f290608e730b9ccec2061aa81f6609 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Mon, 13 Apr 2009 15:41:22 -0700 Subject: be2net: changes for checksum and segmentation offload - Enables Rx checksum feature by default. - Disables support for ipv6 tso. - Changes in Rx path to handle Rx completions with various checksum options. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 9b75aa6..8994b03 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -637,6 +637,22 @@ static void be_rx_stats_update(struct be_adapter *adapter, stats->be_rx_bytes += pktsize; } +static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso) +{ + u8 l4_cksm, ip_version, ipcksm, tcpf = 0, udpf = 0, ipv6_chk; + + l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp); + ipcksm = AMAP_GET_BITS(struct amap_eth_rx_compl, ipcksm, rxcp); + ip_version = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp); + if (ip_version) { + tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp); + udpf = AMAP_GET_BITS(struct amap_eth_rx_compl, udpf, rxcp); + } + ipv6_chk = (ip_version && (tcpf || udpf)); + + return ((l4_cksm && ipv6_chk && ipcksm) && cso) ? false : true; +} + static struct be_rx_page_info * get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) { @@ -752,9 +768,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, { struct sk_buff *skb; u32 vtp, vid; - int l4_cksm; - l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp); vtp = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN); @@ -769,10 +783,10 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb_fill_rx_data(adapter, skb, rxcp); - if (l4_cksm && adapter->rx_csum) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else + if (do_pkt_csum(rxcp, adapter->rx_csum)) skb->ip_summed = CHECKSUM_NONE; + else + skb->ip_summed = CHECKSUM_UNNECESSARY; skb->truesize = skb->len + sizeof(struct sk_buff); skb->protocol = eth_type_trans(skb, adapter->netdev); @@ -1626,10 +1640,12 @@ static void be_netdev_init(struct net_device *netdev) netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + NETIF_F_IPV6_CSUM; netdev->flags |= IFF_MULTICAST; + adapter->rx_csum = true; + BE_SET_NETDEV_OPS(netdev, &be_netdev_ops); SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); -- cgit v0.10.2 From 54cb2284dce50672c40248b8e95940318ec2ca41 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 8 Apr 2009 22:16:38 +0000 Subject: at76c50x-usb: remove pointless conditional before kfree_skb() Remove pointless conditional before kfree_skb(). Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 0c02f1c..c220c97 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -2309,8 +2309,7 @@ static void at76_delete_device(struct at76_priv *priv) del_timer_sync(&ledtrig_tx_timer); - if (priv->rx_skb) - kfree_skb(priv->rx_skb); + kfree_skb(priv->rx_skb); usb_put_dev(priv->udev); -- cgit v0.10.2 From 710b523ac59426e8bfdea3533f42118e46b9cbfb Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 9 Apr 2009 07:11:55 +0000 Subject: kaweth: Clean up code The driver kaweth yields a -EBUSY error when starting, and a -ETIME error when shutting down. These errors are avoided, and the RX status is further checked for other potential errors. Signed-off-by: Larry Finger Signed-off-by: David S. Miller diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 3d0d0b0..e013147 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -31,7 +31,6 @@ ****************************************************************/ /* TODO: - * Fix in_interrupt() problem * Develop test procedures for USB net interfaces * Run test procedures * Fix bugs from previous two steps @@ -606,14 +605,30 @@ static void kaweth_usb_receive(struct urb *urb) struct sk_buff *skb; - if(unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) - /* we are killed - set a flag and wake the disconnect handler */ - { + if (unlikely(status == -EPIPE)) { + kaweth->stats.rx_errors++; kaweth->end = 1; wake_up(&kaweth->term_wait); + dbg("Status was -EPIPE."); return; } - + if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) { + /* we are killed - set a flag and wake the disconnect handler */ + kaweth->end = 1; + wake_up(&kaweth->term_wait); + dbg("Status was -ECONNRESET or -ESHUTDOWN."); + return; + } + if (unlikely(status == -EPROTO || status == -ETIME || + status == -EILSEQ)) { + kaweth->stats.rx_errors++; + dbg("Status was -EPROTO, -ETIME, or -EILSEQ."); + return; + } + if (unlikely(status == -EOVERFLOW)) { + kaweth->stats.rx_errors++; + dbg("Status was -EOVERFLOW."); + } spin_lock(&kaweth->device_lock); if (IS_BLOCKED(kaweth->status)) { spin_unlock(&kaweth->device_lock); @@ -883,13 +898,16 @@ static void kaweth_set_rx_mode(struct net_device *net) ****************************************************************/ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) { + int result; __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; + kaweth->packet_filter_bitmap = 0; if (packet_filter_bitmap == 0) return; - { - int result; + if (in_interrupt()) + return; + result = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), KAWETH_COMMAND_SET_PACKET_FILTER, @@ -906,7 +924,6 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) else { dbg("Set Rx mode to %d", packet_filter_bitmap); } - } } /**************************************************************** -- cgit v0.10.2 From 0ee904c35cc3fdd26a9c76077d9692d458309186 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Sat, 11 Apr 2009 14:50:23 +0000 Subject: drivers/net: replace BUG() with BUG_ON() if possible Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index fb57b75..adac061 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1794,8 +1794,7 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter, memcpy(use_tpd, tpd, sizeof(struct atl1e_tpd_desc)); tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd); - if (tx_buffer->skb) - BUG(); + BUG_ON(tx_buffer->skb); tx_buffer->skb = NULL; tx_buffer->length = diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 0ab2254..13f0bdc 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2207,8 +2207,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, nr_frags = skb_shinfo(skb)->nr_frags; next_to_use = atomic_read(&tpd_ring->next_to_use); buffer_info = &tpd_ring->buffer_info[next_to_use]; - if (unlikely(buffer_info->skb)) - BUG(); + BUG_ON(buffer_info->skb); /* put skb in last TPD */ buffer_info->skb = NULL; @@ -2274,8 +2273,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, ATL1_MAX_TX_BUF_LEN; for (i = 0; i < nseg; i++) { buffer_info = &tpd_ring->buffer_info[next_to_use]; - if (unlikely(buffer_info->skb)) - BUG(); + BUG_ON(buffer_info->skb); + buffer_info->skb = NULL; buffer_info->length = (buf_len > ATL1_MAX_TX_BUF_LEN) ? ATL1_MAX_TX_BUF_LEN : buf_len; diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 58f6fc0..5e97a1a 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1149,8 +1149,8 @@ static inline void write_tx_desc(struct cmdQ_e *e, dma_addr_t mapping, unsigned int len, unsigned int gen, unsigned int eop) { - if (unlikely(len > SGE_TX_DESC_MAX_PLEN)) - BUG(); + BUG_ON(len > SGE_TX_DESC_MAX_PLEN); + e->addr_lo = (u32)mapping; e->addr_hi = (u64)mapping >> 32; e->len_gen = V_CMD_LEN(len) | V_CMD_GEN1(gen); diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 28077cc..61aaae4 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -54,8 +54,7 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) fec_t __iomem *fecp = fec->fecp; int i, ret = -1; - if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); + BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); /* Add PHY address to register command. */ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); @@ -79,8 +78,7 @@ static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, int i; /* this must never happen */ - if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); + BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); /* Add PHY address to register command. */ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h index d92e72b..371a6be 100644 --- a/drivers/net/ixgb/ixgb_osdep.h +++ b/drivers/net/ixgb/ixgb_osdep.h @@ -40,7 +40,7 @@ #include #undef ASSERT -#define ASSERT(x) if (!(x)) BUG() +#define ASSERT(x) BUG_ON(!(x)) #define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B) #ifdef DBG diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 5b07dd8..5981deb 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -1238,8 +1238,7 @@ static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel) struct pppol2tp_session *session; struct sock *sk; - if (tunnel == NULL) - BUG(); + BUG_ON(tunnel == NULL); PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, "%s: closing all sessions...\n", tunnel->name); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 264e614..842b1a2c 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1601,8 +1601,7 @@ static int w840_suspend (struct pci_dev *pdev, pm_message_t state) /* no more hardware accesses behind this line. */ - BUG_ON(np->csr6); - if (ioread32(ioaddr + IntrEnable)) BUG(); + BUG_ON(np->csr6 || ioread32(ioaddr + IntrEnable)); /* pci_power_off(pdev, -1); */ diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9c82a39..0718558 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -621,12 +621,9 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, virtio_net_ctrl_ack status = ~0; unsigned int tmp; - if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { - BUG(); /* Caller should know better */ - return false; - } - - BUG_ON(out + in > VIRTNET_SEND_COMMAND_SG_MAX); + /* Caller should know better */ + BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) || + (out + in > VIRTNET_SEND_COMMAND_SG_MAX)); out++; /* Add header */ in++; /* Add return status */ @@ -640,8 +637,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, memcpy(&sg[1], data, sizeof(struct scatterlist) * (out + in - 2)); sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); - if (vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi) != 0) - BUG(); + BUG_ON(vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi)); vi->cvq->vq_ops->kick(vi->cvq); diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 7a17d31..cb5e15f 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -54,9 +54,8 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, 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(); + BUG_ON(!(ah->ah_version == AR5K_AR5212) || + !(channel->hw_value & CHANNEL_OFDM)); /* Get coefficient * ALGO: coef = (5 * clock * carrier_freq) / 2) diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 2689a08a..7b1b40a 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -53,11 +53,7 @@ struct ath_node; #define A_MAX(a, b) ((a) > (b) ? (a) : (b)) -#define ASSERT(exp) do { \ - if (unlikely(!(exp))) { \ - BUG(); \ - } \ - } while (0) +#define ASSERT(exp) BUG_ON(!(exp)) #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index bd4dbcf..9a123fb 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -3176,11 +3176,8 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) /* Start the Dma */ rc = ipw_fw_dma_enable(priv); - if (priv->sram_desc.last_cb_index > 0) { - /* the DMA is already ready this would be a bug. */ - BUG(); - goto out; - } + /* the DMA is already ready this would be a bug. */ + BUG_ON(priv->sram_desc.last_cb_index > 0); do { chunk = (struct fw_chunk *)(data + offset); diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index ea3dc038..d649cae 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -686,8 +686,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, return; } - if (!in_interrupt()) - BUG(); + BUG_ON(!in_interrupt()); spin_lock(&priv->driver_lock); diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index 59634c3..392337b 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -461,8 +461,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, return; } - if (!in_interrupt()) - BUG(); + BUG_ON(!in_interrupt()); spin_lock(&priv->driver_lock); memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN, -- cgit v0.10.2 From 861ab44059350e5cab350238606cf8814abab93b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 5 Apr 2009 08:40:04 +0000 Subject: NET/r8169: Rework suspend and resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recent changes of the PCI PM core allow us to simplify the suspend and resume handling in a number of device drivers, since they don't need to carry out the general PCI PM operations, such as changing the power state of the device, during suspend and resume any more. Simplify the suspend and resume callbacks of r8169 using the observation that the PCI PM core can take care of some operations carried out by the driver. Additionally, make the shutdown callback of r8169 only put the device into a low power state if the system is going to be powered off (kexec is known to have problems with network adapters that are put into low power states on shutdown). This patch has been tested on MSI Wind U100. Signed-off-by: Rafael J. Wysocki Tested-by: Bruno Prémont Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0b6e8c8..c812e16 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3791,16 +3791,13 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) return &dev->stats; } -#ifdef CONFIG_PM - -static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) +static void rtl8169_net_suspend(struct net_device *dev) { - struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; if (!netif_running(dev)) - goto out_pci_suspend; + return; netif_device_detach(dev); netif_stop_queue(dev); @@ -3812,24 +3809,25 @@ static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) rtl8169_rx_missed(dev, ioaddr); spin_unlock_irq(&tp->lock); +} + +#ifdef CONFIG_PM + +static int rtl8169_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct net_device *dev = pci_get_drvdata(pdev); -out_pci_suspend: - pci_save_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, state), - (tp->features & RTL_FEATURE_WOL) ? 1 : 0); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + rtl8169_net_suspend(dev); return 0; } -static int rtl8169_resume(struct pci_dev *pdev) +static int rtl8169_resume(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct net_device *dev = pci_get_drvdata(pdev); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D0, 0); - if (!netif_running(dev)) goto out; @@ -3840,23 +3838,42 @@ out: return 0; } +static struct dev_pm_ops rtl8169_pm_ops = { + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, + .freeze = rtl8169_suspend, + .thaw = rtl8169_resume, + .poweroff = rtl8169_suspend, + .restore = rtl8169_resume, +}; + +#define RTL8169_PM_OPS (&rtl8169_pm_ops) + +#else /* !CONFIG_PM */ + +#define RTL8169_PM_OPS NULL + +#endif /* !CONFIG_PM */ + static void rtl_shutdown(struct pci_dev *pdev) { - rtl8169_suspend(pdev, PMSG_SUSPEND); -} + struct net_device *dev = pci_get_drvdata(pdev); + + rtl8169_net_suspend(dev); -#endif /* CONFIG_PM */ + if (system_state == SYSTEM_POWER_OFF) { + pci_wake_from_d3(pdev, true); + pci_set_power_state(pdev, PCI_D3hot); + } +} static struct pci_driver rtl8169_pci_driver = { .name = MODULENAME, .id_table = rtl8169_pci_tbl, .probe = rtl8169_init_one, .remove = __devexit_p(rtl8169_remove_one), -#ifdef CONFIG_PM - .suspend = rtl8169_suspend, - .resume = rtl8169_resume, .shutdown = rtl_shutdown, -#endif + .driver.pm = RTL8169_PM_OPS, }; static int __init rtl8169_init_module(void) -- cgit v0.10.2 From 76620aafd66f0004829764940c5466144969cffc Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 16 Apr 2009 02:02:07 -0700 Subject: gro: New frags interface to avoid copying shinfo It turns out that copying a 16-byte area at ~800k times a second can be really expensive :) This patch redesigns the frags GRO interface to avoid copying that area twice. The two disciples of the frags interface have been converted. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 714df2b..322434a 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -195,7 +195,7 @@ struct sge_qset { /* an SGE queue set */ struct sge_rspq rspq; struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; - struct napi_gro_fraginfo lro_frag_tbl; + int nomem; int lro_enabled; void *lro_va; struct net_device *netdev; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 26d3587..73d569e 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -654,7 +654,8 @@ static void t3_reset_qset(struct sge_qset *q) q->txq_stopped = 0; q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ q->rx_reclaim_timer.function = NULL; - q->lro_frag_tbl.nr_frags = q->lro_frag_tbl.len = 0; + q->nomem = 0; + napi_free_frags(&q->napi); } @@ -2074,20 +2075,19 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, struct sge_fl *fl, int len, int complete) { struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + struct sk_buff *skb = NULL; struct cpl_rx_pkt *cpl; - struct skb_frag_struct *rx_frag = qs->lro_frag_tbl.frags; - int nr_frags = qs->lro_frag_tbl.nr_frags; - int frag_len = qs->lro_frag_tbl.len; + struct skb_frag_struct *rx_frag; + int nr_frags; int offset = 0; - if (!nr_frags) { - offset = 2 + sizeof(struct cpl_rx_pkt); - qs->lro_va = cpl = sd->pg_chunk.va + 2; + if (!qs->nomem) { + skb = napi_get_frags(&qs->napi); + qs->nomem = !skb; } fl->credits--; - len -= offset; pci_dma_sync_single_for_cpu(adap->pdev, pci_unmap_addr(sd, dma_addr), fl->buf_size - SGE_PG_RSVD, @@ -2100,21 +2100,38 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, fl->alloc_size, PCI_DMA_FROMDEVICE); + if (!skb) { + put_page(sd->pg_chunk.page); + if (complete) + qs->nomem = 0; + return; + } + + rx_frag = skb_shinfo(skb)->frags; + nr_frags = skb_shinfo(skb)->nr_frags; + + if (!nr_frags) { + offset = 2 + sizeof(struct cpl_rx_pkt); + qs->lro_va = sd->pg_chunk.va + 2; + } + len -= offset; + prefetch(qs->lro_va); rx_frag += nr_frags; rx_frag->page = sd->pg_chunk.page; rx_frag->page_offset = sd->pg_chunk.offset + offset; rx_frag->size = len; - frag_len += len; - qs->lro_frag_tbl.nr_frags++; - qs->lro_frag_tbl.len = frag_len; + skb->len += len; + skb->data_len += len; + skb->truesize += len; + skb_shinfo(skb)->nr_frags++; if (!complete) return; - qs->lro_frag_tbl.ip_summed = CHECKSUM_UNNECESSARY; + skb->ip_summed = CHECKSUM_UNNECESSARY; cpl = qs->lro_va; if (unlikely(cpl->vlan_valid)) { @@ -2123,15 +2140,11 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, struct vlan_group *grp = pi->vlan_grp; if (likely(grp != NULL)) { - vlan_gro_frags(&qs->napi, grp, ntohs(cpl->vlan), - &qs->lro_frag_tbl); - goto out; + vlan_gro_frags(&qs->napi, grp, ntohs(cpl->vlan)); + return; } } - napi_gro_frags(&qs->napi, &qs->lro_frag_tbl); - -out: - qs->lro_frag_tbl.nr_frags = qs->lro_frag_tbl.len = 0; + napi_gro_frags(&qs->napi); } /** @@ -2300,8 +2313,6 @@ no_mem: if (fl->use_pages) { void *addr = fl->sdesc[fl->cidx].pg_chunk.va; - prefetch(&qs->lro_frag_tbl); - prefetch(addr); #if L1_CACHE_BYTES < 128 prefetch(addr + L1_CACHE_BYTES); diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 66d7fe3..01f9432 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -450,17 +450,27 @@ static void efx_rx_packet_lro(struct efx_channel *channel, /* Pass the skb/page into the LRO engine */ if (rx_buf->page) { - struct napi_gro_fraginfo info; + struct sk_buff *skb = napi_get_frags(napi); - info.frags[0].page = rx_buf->page; - info.frags[0].page_offset = efx_rx_buf_offset(rx_buf); - info.frags[0].size = rx_buf->len; - info.nr_frags = 1; - info.ip_summed = CHECKSUM_UNNECESSARY; - info.len = rx_buf->len; + if (!skb) { + put_page(rx_buf->page); + goto out; + } + + skb_shinfo(skb)->frags[0].page = rx_buf->page; + skb_shinfo(skb)->frags[0].page_offset = + efx_rx_buf_offset(rx_buf); + skb_shinfo(skb)->frags[0].size = rx_buf->len; + skb_shinfo(skb)->nr_frags = 1; + + skb->len = rx_buf->len; + skb->data_len = rx_buf->len; + skb->truesize += rx_buf->len; + skb->ip_summed = CHECKSUM_UNNECESSARY; - napi_gro_frags(napi, &info); + napi_gro_frags(napi); +out: EFX_BUG_ON_PARANOID(rx_buf->skb); rx_buf->page = NULL; } else { diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index e1ff5b1..7ff9af1 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -118,8 +118,7 @@ extern int vlan_hwaccel_do_receive(struct sk_buff *skb); extern int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, unsigned int vlan_tci, struct sk_buff *skb); extern int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci, - struct napi_gro_fraginfo *info); + unsigned int vlan_tci); #else static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) @@ -154,8 +153,7 @@ static inline int vlan_gro_receive(struct napi_struct *napi, } static inline int vlan_gro_frags(struct napi_struct *napi, - struct vlan_group *grp, unsigned int vlan_tci, - struct napi_gro_fraginfo *info) + struct vlan_group *grp, unsigned int vlan_tci) { return NET_RX_DROP; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2e7783f..54db3eb 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1047,14 +1047,6 @@ struct packet_type { struct list_head list; }; -struct napi_gro_fraginfo { - skb_frag_t frags[MAX_SKB_FRAGS]; - unsigned int nr_frags; - unsigned int ip_summed; - unsigned int len; - __wsum csum; -}; - #include #include @@ -1442,12 +1434,18 @@ extern int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb); extern void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb); -extern struct sk_buff * napi_fraginfo_skb(struct napi_struct *napi, - struct napi_gro_fraginfo *info); +extern struct sk_buff * napi_get_frags(struct napi_struct *napi); extern int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret); -extern int napi_gro_frags(struct napi_struct *napi, - struct napi_gro_fraginfo *info); +extern struct sk_buff * napi_frags_skb(struct napi_struct *napi); +extern int napi_gro_frags(struct napi_struct *napi); + +static inline void napi_free_frags(struct napi_struct *napi) +{ + kfree_skb(napi->skb); + napi->skb = NULL; +} + extern void netif_nit_deliver(struct sk_buff *skb); extern int dev_valid_name(const char *name); extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 654e45f..c1f51e4 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -114,9 +114,9 @@ int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, EXPORT_SYMBOL(vlan_gro_receive); int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci, struct napi_gro_fraginfo *info) + unsigned int vlan_tci) { - struct sk_buff *skb = napi_fraginfo_skb(napi, info); + struct sk_buff *skb = napi_frags_skb(napi); if (!skb) return NET_RX_DROP; diff --git a/net/core/dev.c b/net/core/dev.c index 91d792d..619fa14 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2519,16 +2519,10 @@ void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) } EXPORT_SYMBOL(napi_reuse_skb); -struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi, - struct napi_gro_fraginfo *info) +struct sk_buff *napi_get_frags(struct napi_struct *napi) { struct net_device *dev = napi->dev; struct sk_buff *skb = napi->skb; - struct ethhdr *eth; - skb_frag_t *frag; - int i; - - napi->skb = NULL; if (!skb) { skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN); @@ -2536,47 +2530,14 @@ struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi, goto out; skb_reserve(skb, NET_IP_ALIGN); - } - - BUG_ON(info->nr_frags > MAX_SKB_FRAGS); - frag = &info->frags[info->nr_frags - 1]; - for (i = skb_shinfo(skb)->nr_frags; i < info->nr_frags; i++) { - skb_fill_page_desc(skb, i, frag->page, frag->page_offset, - frag->size); - frag++; + napi->skb = skb; } - skb_shinfo(skb)->nr_frags = info->nr_frags; - - skb->data_len = info->len; - skb->len += info->len; - skb->truesize += info->len; - - skb_reset_mac_header(skb); - skb_gro_reset_offset(skb); - - eth = skb_gro_header(skb, sizeof(*eth)); - if (!eth) { - napi_reuse_skb(napi, skb); - skb = NULL; - goto out; - } - - skb_gro_pull(skb, sizeof(*eth)); - - /* - * This works because the only protocols we care about don't require - * special handling. We'll fix it up properly at the end. - */ - skb->protocol = eth->h_proto; - - skb->ip_summed = info->ip_summed; - skb->csum = info->csum; out: return skb; } -EXPORT_SYMBOL(napi_fraginfo_skb); +EXPORT_SYMBOL(napi_get_frags); int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) { @@ -2606,9 +2567,39 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) } EXPORT_SYMBOL(napi_frags_finish); -int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info) +struct sk_buff *napi_frags_skb(struct napi_struct *napi) +{ + struct sk_buff *skb = napi->skb; + struct ethhdr *eth; + + napi->skb = NULL; + + skb_reset_mac_header(skb); + skb_gro_reset_offset(skb); + + eth = skb_gro_header(skb, sizeof(*eth)); + if (!eth) { + napi_reuse_skb(napi, skb); + skb = NULL; + goto out; + } + + skb_gro_pull(skb, sizeof(*eth)); + + /* + * This works because the only protocols we care about don't require + * special handling. We'll fix it up properly at the end. + */ + skb->protocol = eth->h_proto; + +out: + return skb; +} +EXPORT_SYMBOL(napi_frags_skb); + +int napi_gro_frags(struct napi_struct *napi) { - struct sk_buff *skb = napi_fraginfo_skb(napi, info); + struct sk_buff *skb = napi_frags_skb(napi); if (!skb) return NET_RX_DROP; @@ -2712,7 +2703,7 @@ void netif_napi_del(struct napi_struct *napi) struct sk_buff *skb, *next; list_del_init(&napi->dev_list); - kfree_skb(napi->skb); + napi_free_frags(napi); for (skb = napi->gro_list; skb; skb = next) { next = skb->next; -- cgit v0.10.2 From d130fe5c95739472b61b30f3f2b401ee43d5e3ea Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 07:58:27 +0000 Subject: ipw2x00: remove old compat_net_dev_ops code Since both ipw2100 and ipw2200 are already converted to new net_device_ops this code is useless. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 92a2692..8ce6e96 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -154,10 +154,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) goto failed; } ieee = netdev_priv(dev); -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->hard_start_xmit = ieee80211_xmit; - dev->change_mtu = ieee80211_change_mtu; -#endif ieee->dev = dev; -- cgit v0.10.2 From 84381eed93c974024402eda250c9e7890b72ca4a Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 07:58:28 +0000 Subject: usbnet: remove old compat_net_dev_ops code Since all usb network drivers are already converted to net_device_ops this code is useless. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index f3a2fce..2b8b903 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1185,12 +1185,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) #endif net->netdev_ops = &usbnet_netdev_ops; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - net->hard_start_xmit = usbnet_start_xmit; - net->open = usbnet_open; - net->stop = usbnet_stop; - net->tx_timeout = usbnet_tx_timeout; -#endif net->watchdog_timeo = TX_TIMEOUT_JIFFIES; net->ethtool_ops = &usbnet_ethtool_ops; -- cgit v0.10.2 From eb9bdaee550e4a56592ae12171b0be6de8fc9d17 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 07:58:29 +0000 Subject: 8390(p): remove old compat_net_dev_ops code Remove compat_net_dev_ops code and use struct net_device_ops instead of it. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/8390.c b/drivers/net/8390.c index ec3e22e..21153de 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -74,14 +74,8 @@ EXPORT_SYMBOL(ei_netdev_ops); struct net_device *__alloc_ei_netdev(int size) { struct net_device *dev = ____alloc_ei_netdev(size); -#ifdef CONFIG_COMPAT_NET_DEV_OPS - if (dev) { - dev->hard_start_xmit = ei_start_xmit; - dev->get_stats = ei_get_stats; - dev->set_multicast_list = ei_set_multicast_list; - dev->tx_timeout = ei_tx_timeout; - } -#endif + if (dev) + dev->netdev_ops = &ei_netdev_ops; return dev; } EXPORT_SYMBOL(__alloc_ei_netdev); diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index da863c9..6ec11da 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -79,14 +79,8 @@ EXPORT_SYMBOL(eip_netdev_ops); struct net_device *__alloc_eip_netdev(int size) { struct net_device *dev = ____alloc_ei_netdev(size); -#ifdef CONFIG_COMPAT_NET_DEV_OPS - if (dev) { - dev->hard_start_xmit = eip_start_xmit; - dev->get_stats = eip_get_stats; - dev->set_multicast_list = eip_set_multicast_list; - dev->tx_timeout = eip_tx_timeout; - } -#endif + if (dev) + dev->netdev_ops = &eip_netdev_ops; return dev; } EXPORT_SYMBOL(__alloc_eip_netdev); -- cgit v0.10.2 From 7a4762abf20531fc8d0bdbe132bc63181b8bebe8 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:35 +0000 Subject: bmac: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 44d015f..9578a3d 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1247,6 +1247,16 @@ static const struct ethtool_ops bmac_ethtool_ops = { .get_link = ethtool_op_get_link, }; +static const struct net_device_ops bmac_netdev_ops = { + .ndo_open = bmac_open, + .ndo_stop = bmac_close, + .ndo_start_xmit = bmac_output, + .ndo_set_multicast_list = bmac_set_multicast, + .ndo_set_mac_address = bmac_set_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match) { int j, rev, ret; @@ -1308,12 +1318,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i bmac_enable_and_reset_chip(dev); bmwrite(dev, INTDISABLE, DisableAll); - dev->open = bmac_open; - dev->stop = bmac_close; + dev->netdev_ops = &bmac_netdev_ops; dev->ethtool_ops = &bmac_ethtool_ops; - dev->hard_start_xmit = bmac_output; - dev->set_multicast_list = bmac_set_multicast; - dev->set_mac_address = bmac_set_address; bmac_get_station_address(dev, addr); if (bmac_verify_checksum(dev) != 0) -- cgit v0.10.2 From 63ef7d89cbecc249339a59c7a1ec58d2e8e88ea5 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:36 +0000 Subject: cpmac: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 3f476c7..af305c0 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1093,6 +1093,19 @@ static int cpmac_stop(struct net_device *dev) return 0; } +static const struct net_device_ops cpmac_netdev_ops = { + .ndo_open = cpmac_open, + .ndo_stop = cpmac_stop, + .ndo_start_xmit = cpmac_start_xmit, + .ndo_tx_timeout = cpmac_tx_timeout, + .ndo_set_multicast_list = cpmac_set_multicast_list, + .ndo_so_ioctl = cpmac_ioctl, + .ndo_set_config = cpmac_config, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int external_switch; static int __devinit cpmac_probe(struct platform_device *pdev) @@ -1143,14 +1156,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev) dev->irq = platform_get_irq_byname(pdev, "irq"); - dev->open = cpmac_open; - dev->stop = cpmac_stop; - dev->set_config = cpmac_config; - dev->hard_start_xmit = cpmac_start_xmit; - dev->do_ioctl = cpmac_ioctl; - dev->set_multicast_list = cpmac_set_multicast_list; - dev->tx_timeout = cpmac_tx_timeout; - dev->ethtool_ops = &cpmac_ethtool_ops; + dev->netdev_ops = &cpmac_netdev_ops; + dev->ethtool_ops = &cpmac_ethtool_ops; netif_napi_add(dev, &priv->napi, cpmac_poll, 64); -- cgit v0.10.2 From d88106b70178a87203a23108c47eaa1f20c424b5 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:37 +0000 Subject: dm9000: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index d835086..e402e91 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1170,6 +1170,21 @@ dm9000_stop(struct net_device *ndev) return 0; } +static const struct net_device_ops dm9000_netdev_ops = { + .ndo_open = dm9000_open, + .ndo_stop = dm9000_stop, + .ndo_start_xmit = dm9000_start_xmit, + .ndo_tx_timeout = dm9000_timeout, + .ndo_set_multicast_list = dm9000_hash_table, + .ndo_do_ioctl = dm9000_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = dm9000_poll_controller, +#endif +}; + #define res_size(_r) (((_r)->end - (_r)->start) + 1) /* @@ -1339,18 +1354,9 @@ dm9000_probe(struct platform_device *pdev) /* driver system function */ ether_setup(ndev); - ndev->open = &dm9000_open; - ndev->hard_start_xmit = &dm9000_start_xmit; - ndev->tx_timeout = &dm9000_timeout; - ndev->watchdog_timeo = msecs_to_jiffies(watchdog); - ndev->stop = &dm9000_stop; - ndev->set_multicast_list = &dm9000_hash_table; - ndev->ethtool_ops = &dm9000_ethtool_ops; - ndev->do_ioctl = &dm9000_ioctl; - -#ifdef CONFIG_NET_POLL_CONTROLLER - ndev->poll_controller = &dm9000_poll_controller; -#endif + ndev->netdev_ops = &dm9000_netdev_ops; + ndev->watchdog_timeo = msecs_to_jiffies(watchdog); + ndev->ethtool_ops = &dm9000_ethtool_ops; db->msg_enable = NETIF_MSG_LINK; db->mii.phy_id_mask = 0x1f; -- cgit v0.10.2 From 2e303a929f2178420820cbfab581ca1c7efa18e8 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:38 +0000 Subject: hplance: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index 2e80263..3e3528a 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -71,6 +71,19 @@ static struct dio_driver hplance_driver = { .remove = __devexit_p(hplance_remove_one), }; +static const struct net_device_ops hplance_netdev_ops = { + .ndo_open = hplance_open, + .ndo_stop = hplance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_set_multicast_list = lance_set_multicast, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = lance_poll, +#endif +}; + /* Find all the HP Lance boards and initialise them... */ static int __devinit hplance_init_one(struct dio_dev *d, const struct dio_device_id *ent) @@ -135,13 +148,7 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d) /* Fill the dev fields */ dev->base_addr = va; - dev->open = &hplance_open; - dev->stop = &hplance_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = lance_poll; -#endif - dev->hard_start_xmit = &lance_start_xmit; - dev->set_multicast_list = &lance_set_multicast; + dev->netdev_ops = &hplance_netdev_ops; dev->dma = 0; for (i=0; i<6; i++) { -- cgit v0.10.2 From e186d174e04a7c79606e1ee57abb7470861b3b00 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:39 +0000 Subject: ibmveth: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5c6315d..0a51b0b 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1203,6 +1203,20 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev) return ret; } +static const struct net_device_ops ibmveth_netdev_ops = { + .ndo_open = ibmveth_open, + .ndo_stop = ibmveth_close, + .ndo_start_xmit = ibmveth_start_xmit, + .ndo_set_multicast_list = ibmveth_set_multicast_list, + .ndo_do_ioctl = ibmveth_ioctl, + .ndo_change_mtu = ibmveth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ibmveth_poll_controller, +#endif +}; + static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { int rc, i; @@ -1265,17 +1279,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ memcpy(&adapter->mac_addr, mac_addr_p, 6); netdev->irq = dev->irq; - netdev->open = ibmveth_open; - netdev->stop = ibmveth_close; - netdev->hard_start_xmit = ibmveth_start_xmit; - netdev->set_multicast_list = ibmveth_set_multicast_list; - netdev->do_ioctl = ibmveth_ioctl; - netdev->ethtool_ops = &netdev_ethtool_ops; - netdev->change_mtu = ibmveth_change_mtu; + netdev->netdev_ops = &ibmveth_netdev_ops; + netdev->ethtool_ops = &netdev_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = ibmveth_poll_controller; -#endif netdev->features |= NETIF_F_LLTX; spin_lock_init(&adapter->stats_lock); -- cgit v0.10.2 From 602355a03508bf54dbf113234ef72d75080a492d Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:40 +0000 Subject: irda/au1k_ir: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index 9411640..204def0 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -198,6 +198,17 @@ static int au1k_irda_init_iobuf(iobuff_t *io, int size) return io->head ? 0 : -ENOMEM; } +static const struct net_device_ops au1k_irda_netdev_ops = { + .ndo_open = au1k_irda_start, + .ndo_stop = au1k_irda_stop, + .ndo_start_xmit = au1k_irda_hard_xmit, + .ndo_tx_timeout = au1k_tx_timeout, + .ndo_do_ioctl = au1k_irda_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int au1k_irda_net_init(struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); @@ -209,11 +220,7 @@ static int au1k_irda_net_init(struct net_device *dev) if (err) goto out1; - dev->open = au1k_irda_start; - dev->hard_start_xmit = au1k_irda_hard_xmit; - dev->stop = au1k_irda_stop; - dev->do_ioctl = au1k_irda_ioctl; - dev->tx_timeout = au1k_tx_timeout; + dev->netdev_ops = &au1k_irda_netdev_ops; irda_init_max_qos_capabilies(&aup->qos); -- cgit v0.10.2 From c76ccd6a256004cca1127c9afb5474638fc78b74 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:41 +0000 Subject: irda/pxaficp_ir: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index e775338..e8ced56 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -797,6 +797,16 @@ static int pxa_irda_init_iobuf(iobuff_t *io, int size) return io->head ? 0 : -ENOMEM; } +static const struct net_device_ops pxa_irda_netdev_ops = { + .ndo_open = pxa_irda_start, + .ndo_stop = pxa_irda_stop, + .ndo_start_xmit = pxa_irda_hard_xmit, + .ndo_do_ioctl = pxa_irda_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int pxa_irda_probe(struct platform_device *pdev) { struct net_device *dev; @@ -845,10 +855,7 @@ static int pxa_irda_probe(struct platform_device *pdev) if (err) goto err_startup; - dev->hard_start_xmit = pxa_irda_hard_xmit; - dev->open = pxa_irda_start; - dev->stop = pxa_irda_stop; - dev->do_ioctl = pxa_irda_ioctl; + dev->netdev_ops = &pxa_irda_netdev_ops; irda_init_max_qos_capabilies(&si->qos); -- cgit v0.10.2 From a1de966682551debbe690672e760487cc555c05f Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:42 +0000 Subject: irda/sa1100_ir: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 7a2b003..44a748e 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -875,6 +875,16 @@ static int sa1100_irda_init_iobuf(iobuff_t *io, int size) return io->head ? 0 : -ENOMEM; } +static const struct net_device_ops sa1100_irda_netdev_ops = { + .ndo_open = sa1100_irda_start, + .ndo_stop = sa1100_irda_stop, + .ndo_start_xmit = sa1100_irda_hard_xmit, + .ndo_do_ioctl = sa1100_irda_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int sa1100_irda_probe(struct platform_device *pdev) { struct net_device *dev; @@ -913,11 +923,8 @@ static int sa1100_irda_probe(struct platform_device *pdev) if (err) goto err_mem_5; - dev->hard_start_xmit = sa1100_irda_hard_xmit; - dev->open = sa1100_irda_start; - dev->stop = sa1100_irda_stop; - dev->do_ioctl = sa1100_irda_ioctl; - dev->irq = IRQ_Ser2ICP; + dev->netdev_ops = &sa1100_irda_netdev_ops; + dev->ir = IRQ_Ser2ICP; irda_init_max_qos_capabilies(&si->qos); -- cgit v0.10.2 From c2775360e82760be3ad7339a7a1442c45c35b395 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:43 +0000 Subject: iseries_veth: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index cb793c2..264654d 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1021,6 +1021,16 @@ static const struct ethtool_ops ops = { .get_link = veth_get_link, }; +static const struct net_device_ops veth_netdev_ops = { + .ndo_open = veth_open, + .ndo_stop = veth_close, + .ndo_start_xmit = veth_start_xmit, + .ndo_change_mtu = veth_change_mtu, + .ndo_set_multicast_list = veth_set_multicast_list, + .ndo_set_mac_address = NULL, + .ndo_validate_addr = eth_validate_addr, +}; + static struct net_device *veth_probe_one(int vlan, struct vio_dev *vio_dev) { @@ -1067,12 +1077,7 @@ static struct net_device *veth_probe_one(int vlan, memcpy(&port->mac_addr, mac_addr, ETH_ALEN); - dev->open = veth_open; - dev->hard_start_xmit = veth_start_xmit; - dev->stop = veth_close; - dev->change_mtu = veth_change_mtu; - dev->set_mac_address = NULL; - dev->set_multicast_list = veth_set_multicast_list; + dev->netdev = &veth_netdev_ops; SET_ETHTOOL_OPS(dev, &ops); SET_NETDEV_DEV(dev, vdev); -- cgit v0.10.2 From e7090e347ad8bce0de35f9fe2b95e22e4ae8fbab Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:44 +0000 Subject: ixp2000/ixpdev: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index d3bf2f0..2a0174b 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -270,6 +270,18 @@ static int ixpdev_close(struct net_device *dev) return 0; } +static const struct net_device_ops ixpdev_netdev_ops = { + .ndo_open = ixpdev_open, + .ndo_stop = ixpdev_close, + .ndo_start_xmit = ixpdev_xmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ixpdev_poll_controller, +#endif +}; + struct net_device *ixpdev_alloc(int channel, int sizeof_priv) { struct net_device *dev; @@ -279,12 +291,7 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) if (dev == NULL) return NULL; - dev->hard_start_xmit = ixpdev_xmit; - dev->open = ixpdev_open; - dev->stop = ixpdev_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ixpdev_poll_controller; -#endif + dev->netdev_ops = &ixpdev_netdev_ops; dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; -- cgit v0.10.2 From 502a326f833927a84a8de29f5fb638aa9da15f4b Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:45 +0000 Subject: jazzsonic: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 14248cf..d12106b 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -96,6 +96,18 @@ static int jazzsonic_close(struct net_device* dev) return err; } +static const struct net_device_ops sonic_netdev_ops = { + .ndo_open = jazzsonic_open, + .ndo_stop = jazzsonic_close, + .ndo_start_xmit = sonic_send_packet, + .ndo_get_stats = sonic_get_stats, + .ndo_set_multicast_list = sonic_multicast_list, + .ndo_tx_timeout = sonic_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed; @@ -179,12 +191,7 @@ static int __init sonic_probe1(struct net_device *dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = jazzsonic_open; - dev->stop = jazzsonic_close; - dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; - dev->set_multicast_list = &sonic_multicast_list; - dev->tx_timeout = sonic_tx_timeout; + dev->netdev_ops = &sonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; /* -- cgit v0.10.2 From 52b031ff3987a079ea759d81447312f1665dbfbd Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:46 +0000 Subject: korina: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 38d6649..dc23856 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -1081,6 +1081,21 @@ static int korina_close(struct net_device *dev) return 0; } +static const struct net_device_ops korina_netdev_ops = { + .ndo_open = korina_open, + .ndo_stop = korina_close, + .ndo_start_xmit = korina_send_packet, + .ndo_set_multicast_list = korina_multicast_list, + .ndo_tx_timeout = korina_tx_timeout, + .ndo_do_ioctl = korina_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = korina_poll_controller, +#endif +}; + static int korina_probe(struct platform_device *pdev) { struct korina_device *bif = platform_get_drvdata(pdev); @@ -1149,17 +1164,9 @@ static int korina_probe(struct platform_device *pdev) dev->irq = lp->rx_irq; lp->dev = dev; - dev->open = korina_open; - dev->stop = korina_close; - dev->hard_start_xmit = korina_send_packet; - dev->set_multicast_list = &korina_multicast_list; + dev->netdev_ops = &korina_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = korina_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->do_ioctl = &korina_ioctl; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = korina_poll_controller; -#endif netif_napi_add(dev, &lp->napi, korina_poll, 64); lp->phy_addr = (((lp->rx_irq == 0x2c? 1:0) << 8) | 0x05); -- cgit v0.10.2 From 71f4367ca24830d967fca7a9c1cfb944b08742e5 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:47 +0000 Subject: lib82596: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 7415f51..070fa45 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1036,6 +1036,19 @@ static void print_eth(unsigned char *add, char *str) printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", add, add + 6, add, add[12], add[13], str); } +static const struct net_device_ops i596_netdev_ops = { + .ndo_open = i596_open, + .ndo_stop = i596_close, + .ndo_start_xmit = i596_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_tx_timeout = i596_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = i596_poll_controller, +#endif +}; static int __devinit i82596_probe(struct net_device *dev) { @@ -1062,16 +1075,8 @@ static int __devinit i82596_probe(struct net_device *dev) return -ENOMEM; } - /* The 82596-specific entries in the device structure. */ - dev->open = i596_open; - dev->stop = i596_close; - dev->hard_start_xmit = i596_start_xmit; - dev->set_multicast_list = set_multicast_list; - dev->tx_timeout = i596_tx_timeout; + dev->netdev_ops = &i596_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = i596_poll_controller; -#endif memset(dma, 0, sizeof(struct i596_dma)); lp->dma = dma; -- cgit v0.10.2 From 488b4abcd750c0a600eefa4d9ab42aad980ace11 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:48 +0000 Subject: mace: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/mace.c b/drivers/net/mace.c index feebbd9..1ad740b 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -94,6 +94,16 @@ static void __mace_set_address(struct net_device *dev, void *addr); */ static unsigned char *dummy_buf; +static const struct net_device_ops mace_netdev_ops = { + .ndo_open = mace_open, + .ndo_stop = mace_close, + .ndo_start_xmit = mace_xmit_start, + .ndo_set_multicast_list = mace_set_multicast, + .ndo_set_mac_address = mace_set_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *mace = macio_get_of_node(mdev); @@ -207,11 +217,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i } } - dev->open = mace_open; - dev->stop = mace_close; - dev->hard_start_xmit = mace_xmit_start; - dev->set_multicast_list = mace_set_multicast; - dev->set_mac_address = mace_set_address; + dev->netdev_ops = &mace_netdev_ops; /* * Most of what is below could be moved to mace_open() -- cgit v0.10.2 From 0d3936a8b11b72e1387923342e33fdad553271d4 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:49 +0000 Subject: macmace: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 274e99b..44f3c28 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -180,6 +180,17 @@ static void mace_dma_off(struct net_device *dev) psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100); } +static const struct net_device_ops mace_netdev_ops = { + .ndo_open = mace_open, + .ndo_stop = mace_close, + .ndo_start_xmit = mace_xmit_start, + .ndo_tx_timeout = mace_tx_timeout, + .ndo_set_multicast_list = mace_set_multicast, + .ndo_set_mac_address = mace_set_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + /* * Not really much of a probe. The hardware table tells us if this * model of Macintrash has a MACE (AV macintoshes) @@ -240,13 +251,8 @@ static int __devinit mace_probe(struct platform_device *pdev) return -ENODEV; } - dev->open = mace_open; - dev->stop = mace_close; - dev->hard_start_xmit = mace_xmit_start; - dev->tx_timeout = mace_tx_timeout; + dev->netdev_ops = &mace_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->set_multicast_list = mace_set_multicast; - dev->set_mac_address = mace_set_address; printk(KERN_INFO "%s: 68K MACE, hardware address %pM\n", dev->name, dev->dev_addr); -- cgit v0.10.2 From d53bc2df189f1e11a947eed077f0360bfadf9986 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:50 +0000 Subject: meth: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/meth.c b/drivers/net/meth.c index aa08987..46ffdb4 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -769,9 +769,17 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } -/* - * Return statistics to the caller - */ +static const struct net_device_ops meth_netdev_ops = { + .ndo_open = meth_open, + .ndo_stop = meth_release, + .ndo_start_xmit = meth_tx, + .ndo_do_ioctl = meth_ioctl, + .ndo_tx_timeout = meth_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + /* * The init function. */ @@ -785,16 +793,10 @@ static int __init meth_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - dev->open = meth_open; - dev->stop = meth_release; - dev->hard_start_xmit = meth_tx; - dev->do_ioctl = meth_ioctl; -#ifdef HAVE_TX_TIMEOUT - dev->tx_timeout = meth_tx_timeout; - dev->watchdog_timeo = timeout; -#endif - dev->irq = MACE_ETHERNET_IRQ; - dev->base_addr = (unsigned long)&mace->eth; + dev->netdev_ops = &meth_netdev_ops; + dev->watchdog_timeo = timeout; + dev->irq = MACE_ETHERNET_IRQ; + dev->base_addr = (unsigned long)&mace->eth; memcpy(dev->dev_addr, o2meth_eaddr, 6); priv = netdev_priv(dev); -- cgit v0.10.2 From d6771e0b895f04e8bbd12f12fb3a97e130a4a5f4 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:51 +0000 Subject: mipsnet: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 664835b..b3b9a14 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -237,6 +237,16 @@ static void mipsnet_set_mclist(struct net_device *dev) { } +static const struct net_device_ops mipsnet_netdev_ops = { + .ndo_open = mipsnet_open, + .ndo_stop = mipsnet_close, + .ndo_start_xmit = mipsnet_xmit, + .ndo_set_multicast_list = mipsnet_set_mclist, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init mipsnet_probe(struct platform_device *dev) { struct net_device *netdev; @@ -250,10 +260,7 @@ static int __init mipsnet_probe(struct platform_device *dev) platform_set_drvdata(dev, netdev); - netdev->open = mipsnet_open; - netdev->stop = mipsnet_close; - netdev->hard_start_xmit = mipsnet_xmit; - netdev->set_multicast_list = mipsnet_set_mclist; + netdev->netdev_ops = &mipsnet_netdev_ops; /* * TODO: probe for these or load them from PARAM -- cgit v0.10.2 From 96cd55ea0edac7f6d51d2391d5cc1b5c2e360e67 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:52 +0000 Subject: mvme147: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 435e5a8..93c709d 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -57,6 +57,17 @@ typedef void (*writerap_t)(void *, unsigned short); typedef void (*writerdp_t)(void *, unsigned short); typedef unsigned short (*readrdp_t)(void *); +static const struct net_device_ops lance_netdev_ops = { + .ndo_open = m147lance_open, + .ndo_stop = m147lance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_set_multicast_list = lance_set_multicast, + .ndo_tx_timeout = lance_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + /* Initialise the one and only on-board 7990 */ struct net_device * __init mvme147lance_probe(int unit) { @@ -81,11 +92,7 @@ struct net_device * __init mvme147lance_probe(int unit) /* Fill the dev fields */ dev->base_addr = (unsigned long)MVME147_LANCE_BASE; - dev->open = &m147lance_open; - dev->stop = &m147lance_close; - dev->hard_start_xmit = &lance_start_xmit; - dev->set_multicast_list = &lance_set_multicast; - dev->tx_timeout = &lance_tx_timeout; + dev->netdev_ops = &lance_netdev_ops; dev->dma = 0; addr=(u_long *)ETHERNET_ADDRESS; -- cgit v0.10.2 From cd732de21e3d4f0b905fdbee8abfbb8192144b3d Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:53 +0000 Subject: netx-eth: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 1861d5b..946366d 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -301,6 +301,17 @@ netx_eth_phy_write(struct net_device *ndev, int phy_id, int reg, int value) while (readl(NETX_MIIMU) & MIIMU_SNRDY); } +static const struct net_device_ops netx_eth_netdev_ops = { + .ndo_open = netx_eth_open, + .ndo_stop = netx_eth_close, + .ndo_start_xmit = netx_eth_hard_start_xmit, + .ndo_tx_timeout = netx_eth_timeout, + .ndo_set_multicast_list = netx_eth_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int netx_eth_enable(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); @@ -309,12 +320,8 @@ static int netx_eth_enable(struct net_device *ndev) ether_setup(ndev); - ndev->open = netx_eth_open; - ndev->stop = netx_eth_close; - ndev->hard_start_xmit = netx_eth_hard_start_xmit; - ndev->tx_timeout = netx_eth_timeout; + ndev->netdev_ops = &netx_eth_netdev_ops; ndev->watchdog_timeo = msecs_to_jiffies(5000); - ndev->set_multicast_list = netx_eth_set_multicast_list; priv->msg_enable = NETIF_MSG_LINK; priv->mii.phy_id_mask = 0x1f; -- cgit v0.10.2 From 9e0ac841f42df4e7acdab7dc1620de0933ed56d7 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:54 +0000 Subject: pasemi_mac: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 5eeb5a8..067caba 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1735,6 +1735,19 @@ out: return ret; } +static const struct net_device_ops pasemi_netdev_ops = { + .ndo_open = pasemi_mac_open, + .ndo_stop = pasemi_mac_close, + .ndo_start_xmit = pasemi_mac_start_tx, + .ndo_set_multicast_list = pasemi_mac_set_rx_mode, + .ndo_set_mac_address = pasemi_mac_set_mac_addr, + .ndo_change_mtu = pasemi_mac_change_mtu, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = pasemi_mac_netpoll, +#endif +}; + static int __devinit pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1817,19 +1830,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out; } - dev->open = pasemi_mac_open; - dev->stop = pasemi_mac_close; - dev->hard_start_xmit = pasemi_mac_start_tx; - dev->set_multicast_list = pasemi_mac_set_rx_mode; - dev->set_mac_address = pasemi_mac_set_mac_addr; + dev->netdev_ops = &pasemi_netdev_ops; dev->mtu = PE_DEF_MTU; /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = pasemi_mac_netpoll; -#endif - dev->change_mtu = pasemi_mac_change_mtu; dev->ethtool_ops = &pasemi_mac_ethtool_ops; if (err) -- cgit v0.10.2 From 1ec847f6d46f041bb2ae65efc7b00d122b03d212 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:55 +0000 Subject: pci-skeleton: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index c95fd72..8c1f698 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -728,6 +728,17 @@ err_out: return rc; } +static const struct net_device_ops netdrv_netdev_ops = { + .ndo_open = netdrv_open, + .ndo_stop = netdrv_close, + .ndo_start_xmit = netdrv_start_xmit, + .ndo_set_multicast_list = netdrv_set_rx_mode, + .ndo_do_ioctl = netdrv_ioctl, + .ndo_tx_timeout = netdrv_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; static int __devinit netdrv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -769,13 +780,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); - /* The Rtl8139-specific entries in the device structure. */ - dev->open = netdrv_open; - dev->hard_start_xmit = netdrv_start_xmit; - dev->stop = netdrv_close; - dev->set_multicast_list = netdrv_set_rx_mode; - dev->do_ioctl = netdrv_ioctl; - dev->tx_timeout = netdrv_tx_timeout; + dev->netdev_ops = &netdrv_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->irq = pdev->irq; -- cgit v0.10.2 From a33a2bb3c9f38c79e97f6ed720412d946e894e81 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:56 +0000 Subject: rionet: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index ec59e29..8702e7a 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -428,6 +428,15 @@ static const struct ethtool_ops rionet_ethtool_ops = { .get_link = ethtool_op_get_link, }; +static const struct net_device_ops rionet_netdev_ops = { + .ndo_open = rionet_open, + .ndo_stop = rionet_close, + .ndo_start_xmit = rionet_start_xmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int rionet_setup_netdev(struct rio_mport *mport) { int rc = 0; @@ -466,10 +475,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) ndev->dev_addr[4] = device_id >> 8; ndev->dev_addr[5] = device_id & 0xff; - /* Fill in the driver function table */ - ndev->open = &rionet_open; - ndev->hard_start_xmit = &rionet_start_xmit; - ndev->stop = &rionet_close; + ndev->netdev_ops = &rionet_netdev_ops; ndev->mtu = RIO_MAX_MSG_SIZE - 14; ndev->features = NETIF_F_LLTX; SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); -- cgit v0.10.2 From b4cf3421afce25655233cf66f6ec545baa8cb6ae Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:57 +0000 Subject: sb1250-mac: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index ce7551e..aaeebf5 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2271,6 +2271,21 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) return 0; } +static const struct net_device_ops sbmac_netdev_ops = { + .ndo_open = sbmac_open, + .ndo_stop = sbmac_close, + .ndo_start_xmit = sbmac_start_tx, + .ndo_set_multicast_list = sbmac_set_rx_mode, + .ndo_tx_timeout = sbmac_tx_timeout, + .ndo_do_ioctl = sbmac_mii_ioctl, + .ndo_change_mtu = sb1250_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sbmac_netpoll, +#endif +}; + /********************************************************************** * SBMAC_INIT(dev) * @@ -2327,21 +2342,11 @@ static int sbmac_init(struct platform_device *pldev, long long base) spin_lock_init(&(sc->sbm_lock)); - dev->open = sbmac_open; - dev->hard_start_xmit = sbmac_start_tx; - dev->stop = sbmac_close; - dev->set_multicast_list = sbmac_set_rx_mode; - dev->do_ioctl = sbmac_mii_ioctl; - dev->tx_timeout = sbmac_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; + dev->netdev_ops = &sbmac_netdev_ops; + dev->watchdog_timeo = TX_TIMEOUT; netif_napi_add(dev, &sc->napi, sbmac_poll, 16); - dev->change_mtu = sb1250_change_mtu; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sbmac_netpoll; -#endif - dev->irq = UNIT_INT(idx); /* This is needed for PASS2 for Rx H/W checksum feature */ -- cgit v0.10.2 From 8c2c6be186097aafd8f8a17927203b457545cc69 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:58 +0000 Subject: sgiseeq: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 97d6856..5fb88ca 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -709,6 +709,17 @@ static inline void setup_rx_ring(struct net_device *dev, dma_sync_desc_dev(dev, &buf[i]); } +static const struct net_device_ops sgiseeq_netdev_ops = { + .ndo_open = sgiseeq_open, + .ndo_stop = sgiseeq_close, + .ndo_start_xmit = sgiseeq_start_xmit, + .ndo_tx_timeout = timeout, + .ndo_set_multicast_list = sgiseeq_set_multicast, + .ndo_set_mac_address = sgiseeq_set_mac_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __init sgiseeq_probe(struct platform_device *pdev) { struct sgiseeq_platform_data *pd = pdev->dev.platform_data; @@ -775,13 +786,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev) SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT | SEEQ_CTRL_ENCARR; - dev->open = sgiseeq_open; - dev->stop = sgiseeq_close; - dev->hard_start_xmit = sgiseeq_start_xmit; - dev->tx_timeout = timeout; + dev->netdev_ops = &sgiseeq_netdev_ops; dev->watchdog_timeo = (200 * HZ) / 1000; - dev->set_multicast_list = sgiseeq_set_multicast; - dev->set_mac_address = sgiseeq_set_mac_address; dev->irq = irq; if (register_netdev(dev)) { -- cgit v0.10.2 From ec4e0cff9b8c97f5d63c8f1bdf7f44fb65fa8e3b Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:52:59 +0000 Subject: smc911x: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2936103..bc4976a 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1774,6 +1774,20 @@ static int __devinit smc911x_findirq(struct net_device *dev) return probe_irq_off(cookie); } +static const struct net_device_ops smc911x_netdev_ops = { + .ndo_open = smc911x_open, + .ndo_stop = smc911x_close, + .ndo_start_xmit = smc911x_hard_start_xmit, + .ndo_tx_timeout = smc911x_timeout, + .ndo_set_multicast_list = smc911x_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = smc911x_poll_controller, +#endif +}; + /* * Function: smc911x_probe(unsigned long ioaddr) * @@ -1940,16 +1954,9 @@ static int __devinit smc911x_probe(struct net_device *dev) /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); - dev->open = smc911x_open; - dev->stop = smc911x_close; - dev->hard_start_xmit = smc911x_hard_start_xmit; - dev->tx_timeout = smc911x_timeout; + dev->netdev_ops = &smc911x_netdev_ops; dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->set_multicast_list = smc911x_set_multicast_list; dev->ethtool_ops = &smc911x_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = smc911x_poll_controller; -#endif INIT_WORK(&lp->phy_configure, smc911x_phy_configure); lp->mii.phy_id_mask = 0x1f; -- cgit v0.10.2 From 2160187a0a1cdeeeff1d41f53333bea91c82f259 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Wed, 15 Apr 2009 12:53:00 +0000 Subject: sun3lance: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index e5beb29..9bd9dad 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -294,6 +294,16 @@ out: return ERR_PTR(err); } +static const struct net_device_ops lance_netdev_ops = { + .ndo_open = lance_open, + .ndo_stop = lance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_set_mac_address = NULL, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __init lance_probe( struct net_device *dev) { unsigned long ioaddr; @@ -397,12 +407,7 @@ static int __init lance_probe( struct net_device *dev) if (did_version++ == 0) printk( version ); - /* The LANCE-specific entries in the device structure. */ - dev->open = &lance_open; - dev->hard_start_xmit = &lance_start_xmit; - dev->stop = &lance_close; - dev->set_multicast_list = &set_multicast_list; - dev->set_mac_address = NULL; + dev->netdev_ops = &lance_netdev_ops; // KLUDGE -- REMOVE ME set_bit(__LINK_STATE_PRESENT, &dev->state); -- cgit v0.10.2 From f44d6305280378cb34319e0118e18d84cc7ac773 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 03:11:30 +0000 Subject: fec: switch to writel/readl Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index a515acc..37b3332 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -165,7 +165,7 @@ typedef struct { */ struct fec_enet_private { /* Hardware registers of the FEC device */ - volatile fec_t *hwp; + void __iomem *hwp; struct net_device *netdev; @@ -288,15 +288,11 @@ static int mii_queue(struct net_device *dev, int request, static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); volatile cbd_t *bdp; unsigned short status; unsigned long flags; - fep = netdev_priv(dev); - fecp = (volatile fec_t*)dev->base_addr; - if (!fep->link) { /* Link is down or autonegotiation is in progress. */ return 1; @@ -363,7 +359,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; /* Trigger transmission start */ - fecp->fec_x_des_active = 0; + writel(0, fep->hwp + FEC_X_DES_ACTIVE); /* If this was the last BD in the ring, start at the beginning again. */ @@ -436,29 +432,25 @@ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); uint int_events; irqreturn_t ret = IRQ_NONE; - fecp = (volatile fec_t*)dev->base_addr; - - /* Get the interrupt events that caused us to be here. - */ + /* Get the interrupt events that caused us to be here. */ do { - int_events = fecp->fec_ievent; - fecp->fec_ievent = int_events; + int_events = readl(fep->hwp + FEC_IEVENT); + writel(int_events, fep->hwp + FEC_IEVENT); - /* Handle receive event in its own function. - */ + /* Handle receive event in its own function. */ if (int_events & FEC_ENET_RXF) { ret = IRQ_HANDLED; fec_enet_rx(dev); } /* Transmit OK, or non-fatal error. Update the buffer - descriptors. FEC handles all errors, we just discover - them as part of the transmit process. - */ + * descriptors. FEC handles all errors, we just discover + * them as part of the transmit process. + */ if (int_events & FEC_ENET_TXF) { ret = IRQ_HANDLED; fec_enet_tx(dev); @@ -555,8 +547,7 @@ fec_enet_tx(struct net_device *dev) static void fec_enet_rx(struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); volatile cbd_t *bdp; unsigned short status; struct sk_buff *skb; @@ -567,9 +558,6 @@ fec_enet_rx(struct net_device *dev) flush_cache_all(); #endif - fep = netdev_priv(dev); - fecp = (volatile fec_t*)dev->base_addr; - spin_lock_irq(&fep->hw_lock); /* First, grab all of the stats for the incoming packet. @@ -665,7 +653,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { * incoming frames. On a heavily loaded network, we should be * able to keep up at the expense of system resources. */ - fecp->fec_r_des_active = 0; + writel(0, fep->hwp + FEC_R_DES_ACTIVE); #endif } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ fep->cur_rx = (cbd_t *)bdp; @@ -690,30 +678,25 @@ static void fec_enet_mii(struct net_device *dev) { struct fec_enet_private *fep; - volatile fec_t *ep; mii_list_t *mip; - uint mii_reg; fep = netdev_priv(dev); spin_lock_irq(&fep->mii_lock); - ep = fep->hwp; - mii_reg = ep->fec_mii_data; - if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); goto unlock; } if (mip->mii_func != NULL) - (*(mip->mii_func))(mii_reg, dev); + (*(mip->mii_func))(readl(fep->hwp + FEC_MII_DATA), dev); mii_head = mip->mii_next; mip->mii_next = mii_free; mii_free = mip; if ((mip = mii_head) != NULL) - ep->fec_mii_data = mip->mii_regval; + writel(mip->mii_regval, fep->hwp + FEC_MII_DATA); unlock: spin_unlock_irq(&fep->mii_lock); @@ -745,7 +728,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi mii_tail = mip; } else { mii_head = mii_tail = mip; - fep->hwp->fec_mii_data = regval; + writel(regval, fep->hwp + FEC_MII_DATA); } } else { retval = 1; @@ -1245,11 +1228,8 @@ static void __inline__ fec_phy_ack_intr(void) static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile fec_t *fecp; unsigned char *iap, tmpaddr[ETH_ALEN]; - fecp = fep->hwp; - if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. @@ -1263,8 +1243,8 @@ static void __inline__ fec_get_mac(struct net_device *dev) (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) iap = fec_mac_default; } else { - *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; - *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW); + *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16); iap = &tmpaddr[0]; } @@ -1456,11 +1436,9 @@ static void mii_discover_phy(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep; - volatile fec_t *fecp; uint phytype; fep = netdev_priv(dev); - fecp = fep->hwp; if (fep->phy_addr < 32) { if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { @@ -1478,7 +1456,8 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) } else { printk("FEC: No PHY device found.\n"); /* Disable external MII interface */ - fecp->fec_mii_speed = fep->phy_speed = 0; + writel(0, fep->hwp + FEC_MII_SPEED); + fep->phy_speed = 0; #ifdef HAVE_mii_link_interrupt fec_disable_phy_intr(); #endif @@ -1582,32 +1561,31 @@ fec_enet_close(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *ep; + struct fec_enet_private *fep = netdev_priv(dev); struct dev_mc_list *dmi; - unsigned int i, j, bit, data, crc; + unsigned int i, j, bit, data, crc, tmp; unsigned char hash; - fep = netdev_priv(dev); - ep = fep->hwp; - if (dev->flags&IFF_PROMISC) { - ep->fec_r_cntrl |= 0x0008; + tmp = readl(fep->hwp + FEC_R_CNTRL); + tmp |= 0x8; + writel(tmp, fep->hwp + FEC_R_CNTRL); } else { - - ep->fec_r_cntrl &= ~0x0008; + tmp = readl(fep->hwp + FEC_R_CNTRL); + tmp &= ~0x8; + writel(tmp, fep->hwp + FEC_R_CNTRL); if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the * filter to all 1's. */ - ep->fec_grp_hash_table_high = 0xffffffff; - ep->fec_grp_hash_table_low = 0xffffffff; + writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); } else { /* Clear filter and add the addresses in hash register. */ - ep->fec_grp_hash_table_high = 0; - ep->fec_grp_hash_table_low = 0; + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); dmi = dev->mc_list; @@ -1637,10 +1615,15 @@ static void set_multicast_list(struct net_device *dev) */ hash = (crc >> (32 - HASH_BITS)) & 0x3f; - if (hash > 31) - ep->fec_grp_hash_table_high |= 1 << (hash - 32); - else - ep->fec_grp_hash_table_low |= 1 << hash; + if (hash > 31) { + tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + tmp |= 1 << (hash - 32); + writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + } else { + tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); + tmp |= 1 << hash; + writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); + } } } } @@ -1651,16 +1634,14 @@ static void set_multicast_list(struct net_device *dev) static void fec_set_mac_address(struct net_device *dev) { - volatile fec_t *fecp; - - fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; + struct fec_enet_private *fep = netdev_priv(dev); /* Set station address. */ - fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | - (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); - fecp->fec_addr_high = (dev->dev_addr[5] << 16) | - (dev->dev_addr[4] << 24); - + writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) | + (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24), + fep->hwp + FEC_ADDR_LOW); + writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24), + fep + FEC_ADDR_HIGH); } /* @@ -1674,7 +1655,6 @@ int __init fec_enet_init(struct net_device *dev, int index) unsigned long mem_addr; volatile cbd_t *bdp; cbd_t *cbd_base; - volatile fec_t *fecp; int i, j; /* Allocate memory for buffer descriptors. @@ -1689,17 +1669,13 @@ int __init fec_enet_init(struct net_device *dev, int index) spin_lock_init(&fep->hw_lock); spin_lock_init(&fep->mii_lock); - /* Create an Ethernet device instance. - */ - fecp = (volatile fec_t *)dev->base_addr; - fep->index = index; - fep->hwp = fecp; + fep->hwp = (void __iomem *)dev->base_addr; fep->netdev = dev; /* Whack a reset. We should wait for this. */ - fecp->fec_ecntrl = 1; + writel(1, fep->hwp + FEC_ECNTRL); udelay(10); /* Set the Ethernet address */ @@ -1708,12 +1684,12 @@ int __init fec_enet_init(struct net_device *dev, int index) #else { unsigned long l; - l = fecp->fec_addr_low; + l = readl(fep->hwp + FEC_ADDR_LOW); dev->dev_addr[0] = (unsigned char)((l & 0xFF000000) >> 24); dev->dev_addr[1] = (unsigned char)((l & 0x00FF0000) >> 16); dev->dev_addr[2] = (unsigned char)((l & 0x0000FF00) >> 8); dev->dev_addr[3] = (unsigned char)((l & 0x000000FF) >> 0); - l = fecp->fec_addr_high; + l = readl(fep->hwp + FEC_ADDR_HIGH); dev->dev_addr[4] = (unsigned char)((l & 0xFF000000) >> 24); dev->dev_addr[5] = (unsigned char)((l & 0x00FF0000) >> 16); } @@ -1783,22 +1759,22 @@ int __init fec_enet_init(struct net_device *dev, int index) /* Set receive and transmit descriptor base. */ - fecp->fec_r_des_start = fep->bd_dma; - fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) - * RX_RING_SIZE; + writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); + writel((unsigned long)fep->bd_dma + sizeof(cbd_t) * RX_RING_SIZE, + fep->hwp + FEC_X_DES_START); #ifdef HAVE_mii_link_interrupt fec_request_mii_intr(dev); #endif - fecp->fec_grp_hash_table_high = 0; - fecp->fec_grp_hash_table_low = 0; - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0; + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); + writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); + writel(2, fep->hwp + FEC_ECNTRL); + writel(0, fep->hwp + FEC_R_DES_ACTIVE); #ifndef CONFIG_M5272 - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; + writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_HASH_TABLE_LOW); #endif /* The FEC Ethernet specific entries in the device structure. */ @@ -1814,20 +1790,21 @@ int __init fec_enet_init(struct net_device *dev, int index) mii_free = mii_cmds; /* setup MII interface */ - fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; - fecp->fec_x_cntrl = 0x00; + writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL); + writel(0, fep->hwp + FEC_X_CNTRL); /* * Set MII speed to 2.5 MHz */ fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) / 2500000) / 2) & 0x3F) << 1; - fecp->fec_mii_speed = fep->phy_speed; + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); fec_restart(dev, 0); /* Clear and enable interrupts */ - fecp->fec_ievent = 0xffc00000; - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); + writel(0xffc00000, fep->hwp + FEC_IEVENT); + writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII, + fep->hwp + FEC_IMASK); /* Queue up command to detect the PHY and initialize the * remainder of the interface. @@ -1846,47 +1823,36 @@ int __init fec_enet_init(struct net_device *dev, int index) static void fec_restart(struct net_device *dev, int duplex) { - struct fec_enet_private *fep; + struct fec_enet_private *fep = netdev_priv(dev); volatile cbd_t *bdp; - volatile fec_t *fecp; int i; - fep = netdev_priv(dev); - fecp = fep->hwp; - - /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; + /* Whack a reset. We should wait for this. */ + writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - /* Clear any outstanding interrupt. - */ - fecp->fec_ievent = 0xffc00000; + /* Clear any outstanding interrupt. */ + writel(0xffc00000, fep->hwp + FEC_IEVENT); - /* Set station address. - */ + /* Set station address. */ fec_set_mac_address(dev); - /* Reset all multicast. - */ - fecp->fec_grp_hash_table_high = 0; - fecp->fec_grp_hash_table_low = 0; + /* Reset all multicast. */ + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - /* Set maximum receive buffer size. - */ - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + /* Set maximum receive buffer size. */ + writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); - /* Set receive and transmit descriptor base. - */ - fecp->fec_r_des_start = fep->bd_dma; - fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) - * RX_RING_SIZE; + /* Set receive and transmit descriptor base. */ + writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); + writel((unsigned long)fep->bd_dma + sizeof(cbd_t) * RX_RING_SIZE, + fep->hwp + FEC_X_DES_START); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->cur_rx = fep->rx_bd_base; - /* Reset SKB transmit buffers. - */ + /* Reset SKB transmit buffers. */ fep->skb_cur = fep->skb_dirty = 0; for (i=0; i<=TX_RING_MOD_MASK; i++) { if (fep->tx_skbuff[i] != NULL) { @@ -1895,96 +1861,81 @@ fec_restart(struct net_device *dev, int duplex) } } - /* Initialize the receive buffer descriptors. - */ + /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; for (i=0; icbd_sc = BD_ENET_RX_EMPTY; bdp++; } - /* Set the last buffer to wrap. - */ + /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* ...and the same for transmmit. - */ + /* ...and the same for transmmit. */ bdp = fep->tx_bd_base; for (i=0; icbd_sc = 0; bdp->cbd_bufaddr = 0; bdp++; } - /* Set the last buffer to wrap. - */ + /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* Enable MII mode. - */ + /* Enable MII mode. */ if (duplex) { - fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */ - fecp->fec_x_cntrl = 0x04; /* FD enable */ + /* MII enable / FD enable */ + writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL); + writel(0x04, fep->hwp + FEC_X_CNTRL); } else { - /* MII enable|No Rcv on Xmit */ - fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06; - fecp->fec_x_cntrl = 0x00; + /* MII enable / No Rcv on Xmit */ + writel(OPT_FRAME_SIZE | 0x06, fep->hwp + FEC_R_CNTRL); + writel(0x0, fep->hwp + FEC_X_CNTRL); } fep->full_duplex = duplex; - /* Set MII speed. - */ - fecp->fec_mii_speed = fep->phy_speed; + /* Set MII speed. */ + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - /* And last, enable the transmit and receive processing. - */ - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0; + /* And last, enable the transmit and receive processing. */ + writel(2, fep->hwp + FEC_ECNTRL); + writel(0, fep->hwp + FEC_R_DES_ACTIVE); - /* Enable interrupts we wish to service. - */ - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); + /* Enable interrupts we wish to service. */ + writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII, + fep->hwp + FEC_IMASK); } static void fec_stop(struct net_device *dev) { - volatile fec_t *fecp; - struct fec_enet_private *fep; - - fep = netdev_priv(dev); - fecp = fep->hwp; + struct fec_enet_private *fep = netdev_priv(dev); /* ** We cannot expect a graceful transmit stop without link !!! */ - if (fep->link) - { - fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ + if (fep->link) { + writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ udelay(10); - if (!(fecp->fec_ievent & FEC_ENET_GRA)) + if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) printk("fec_stop : Graceful transmit stop did not complete !\n"); - } + } - /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; + /* Whack a reset. We should wait for this. */ + writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - /* Clear outstanding MII command interrupts. - */ - fecp->fec_ievent = FEC_ENET_MII; + /* Clear outstanding MII command interrupts. */ + writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); - fecp->fec_imask = FEC_ENET_MII; - fecp->fec_mii_speed = fep->phy_speed; + writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); } static int __devinit diff --git a/drivers/net/fec.h b/drivers/net/fec.h index 76c64c9..5474ba3 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -20,82 +20,55 @@ * registers in the same peripheral device on different models * of the ColdFire! */ -typedef struct fec { - unsigned long fec_reserved0; - unsigned long fec_ievent; /* Interrupt event reg */ - unsigned long fec_imask; /* Interrupt mask reg */ - unsigned long fec_reserved1; - unsigned long fec_r_des_active; /* Receive descriptor reg */ - unsigned long fec_x_des_active; /* Transmit descriptor reg */ - unsigned long fec_reserved2[3]; - unsigned long fec_ecntrl; /* Ethernet control reg */ - unsigned long fec_reserved3[6]; - unsigned long fec_mii_data; /* MII manage frame reg */ - unsigned long fec_mii_speed; /* MII speed control reg */ - unsigned long fec_reserved4[7]; - unsigned long fec_mib_ctrlstat; /* MIB control/status reg */ - unsigned long fec_reserved5[7]; - unsigned long fec_r_cntrl; /* Receive control reg */ - unsigned long fec_reserved6[15]; - unsigned long fec_x_cntrl; /* Transmit Control reg */ - unsigned long fec_reserved7[7]; - unsigned long fec_addr_low; /* Low 32bits MAC address */ - unsigned long fec_addr_high; /* High 16bits MAC address */ - unsigned long fec_opd; /* Opcode + Pause duration */ - unsigned long fec_reserved8[10]; - unsigned long fec_hash_table_high; /* High 32bits hash table */ - unsigned long fec_hash_table_low; /* Low 32bits hash table */ - unsigned long fec_grp_hash_table_high;/* High 32bits hash table */ - unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */ - unsigned long fec_reserved9[7]; - unsigned long fec_x_wmrk; /* FIFO transmit water mark */ - unsigned long fec_reserved10; - unsigned long fec_r_bound; /* FIFO receive bound reg */ - unsigned long fec_r_fstart; /* FIFO receive start reg */ - unsigned long fec_reserved11[11]; - unsigned long fec_r_des_start; /* Receive descriptor ring */ - unsigned long fec_x_des_start; /* Transmit descriptor ring */ - unsigned long fec_r_buff_size; /* Maximum receive buff size */ -} fec_t; +#define FEC_IEVENT 0x004 /* Interrupt event reg */ +#define FEC_IMASK 0x008 /* Interrupt mask reg */ +#define FEC_R_DES_ACTIVE 0x010 /* Receive descriptor reg */ +#define FEC_X_DES_ACTIVE 0x014 /* Transmit descriptor reg */ +#define FEC_ECNTRL 0x024 /* Ethernet control reg */ +#define FEC_MII_DATA 0x040 /* MII manage frame reg */ +#define FEC_MII_SPEED 0x044 /* MII speed control reg */ +#define FEC_MIB_CTRLSTAT 0x064 /* MIB control/status reg */ +#define FEC_R_CNTRL 0x084 /* Receive control reg */ +#define FEC_X_CNTRL 0x0c4 /* Transmit Control reg */ +#define FEC_ADDR_LOW 0x0e4 /* Low 32bits MAC address */ +#define FEC_ADDR_HIGH 0x0e8 /* High 16bits MAC address */ +#define FEC_OPD 0x0ec /* Opcode + Pause duration */ +#define FEC_HASH_TABLE_HIGH 0x118 /* High 32bits hash table */ +#define FEC_HASH_TABLE_LOW 0x11c /* Low 32bits hash table */ +#define FEC_GRP_HASH_TABLE_HIGH 0x120 /* High 32bits hash table */ +#define FEC_GRP_HASH_TABLE_LOW 0x124 /* Low 32bits hash table */ +#define FEC_X_WMRK 0x144 /* FIFO transmit water mark */ +#define FEC_R_BOUND 0x14c /* FIFO receive bound reg */ +#define FEC_R_FSTART 0x150 /* FIFO receive start reg */ +#define FEC_R_DES_START 0x180 /* Receive descriptor ring */ +#define FEC_X_DES_START 0x184 /* Transmit descriptor ring */ +#define FEC_R_BUFF_SIZE 0x188 /* Maximum receive buff size */ #else -/* - * Define device register set address map. - */ -typedef struct fec { - unsigned long fec_ecntrl; /* Ethernet control reg */ - unsigned long fec_ievent; /* Interrupt even reg */ - unsigned long fec_imask; /* Interrupt mask reg */ - unsigned long fec_ivec; /* Interrupt vec status reg */ - unsigned long fec_r_des_active; /* Receive descriptor reg */ - unsigned long fec_x_des_active; /* Transmit descriptor reg */ - unsigned long fec_reserved1[10]; - unsigned long fec_mii_data; /* MII manage frame reg */ - unsigned long fec_mii_speed; /* MII speed control reg */ - unsigned long fec_reserved2[17]; - unsigned long fec_r_bound; /* FIFO receive bound reg */ - unsigned long fec_r_fstart; /* FIFO receive start reg */ - unsigned long fec_reserved3[4]; - unsigned long fec_x_wmrk; /* FIFO transmit water mark */ - unsigned long fec_reserved4; - unsigned long fec_x_fstart; /* FIFO transmit start reg */ - unsigned long fec_reserved5[21]; - unsigned long fec_r_cntrl; /* Receive control reg */ - unsigned long fec_max_frm_len; /* Maximum frame length reg */ - unsigned long fec_reserved6[14]; - unsigned long fec_x_cntrl; /* Transmit Control reg */ - unsigned long fec_reserved7[158]; - unsigned long fec_addr_low; /* Low 32bits MAC address */ - unsigned long fec_addr_high; /* High 16bits MAC address */ - unsigned long fec_grp_hash_table_high;/* High 32bits hash table */ - unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */ - unsigned long fec_r_des_start; /* Receive descriptor ring */ - unsigned long fec_x_des_start; /* Transmit descriptor ring */ - unsigned long fec_r_buff_size; /* Maximum receive buff size */ - unsigned long reserved8[9]; - unsigned long fec_fifo_ram[112]; /* FIFO RAM buffer */ -} fec_t; +#define FEC_ECNTRL; 0x000 /* Ethernet control reg */ +#define FEC_IEVENT; 0x004 /* Interrupt even reg */ +#define FEC_IMASK; 0x008 /* Interrupt mask reg */ +#define FEC_IVEC; 0x00c /* Interrupt vec status reg */ +#define FEC_R_DES_ACTIVE; 0x010 /* Receive descriptor reg */ +#define FEC_X_DES_ACTIVE; 0x01c /* Transmit descriptor reg */ +#define FEC_MII_DATA 0x040 /* MII manage frame reg */ +#define FEC_MII_SPEED 0x044 /* MII speed control reg */ +#define FEC_R_BOUND 0x08c /* FIFO receive bound reg */ +#define FEC_R_FSTART 0x090 /* FIFO receive start reg */ +#define FEC_X_WMRK 0x0a4 /* FIFO transmit water mark */ +#define FEC_X_FSTART 0x0ac /* FIFO transmit start reg */ +#define FEC_R_CNTRL 0x104 /* Receive control reg */ +#define FEC_MAX_FRM_LEN 0x108 /* Maximum frame length reg */ +#define FEC_X_CNTRL 0x144 /* Transmit Control reg */ +#define FEC_ADDR_LOW 0x3c0 /* Low 32bits MAC address */ +#define FEC_ADDR_HIGH 0x3c4 /* High 16bits MAC address */ +#define FEC_GRP_HASH_TABLE_HIGH 0x3c8 /* High 32bits hash table */ +#define FEC_GRP_HASH_TABLE_LOW 0x3cc /* Low 32bits hash table */ +#define FEC_R_DES_START 0x3d0 /* Receive descriptor ring */ +#define FEC_X_DES_START 0x3d4 /* Transmit descriptor ring */ +#define FEC_R_BUFF_SIZE 0x3d8 /* Maximum receive buff size */ +#define FEC_FIFO_RAM 0x400 /* FIFO RAM buffer */ #endif /* CONFIG_M5272 */ -- cgit v0.10.2 From 2e28532f7e63c3011f7b3c1516cfebd5321bdd15 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:16 +0000 Subject: fec: do not typedef struct types Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 37b3332..f8396fb 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -180,10 +180,14 @@ struct fec_enet_private { /* CPM dual port RAM relative addresses. */ dma_addr_t bd_dma; - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ - cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + /* Address of Rx and Tx buffers. */ + struct bufdesc *rx_bd_base; + struct bufdesc *tx_bd_base; + /* The next free ring entry */ + struct bufdesc *cur_rx, *cur_tx; + /* The ring entries to be free()ed. */ + struct bufdesc *dirty_tx; + uint tx_full; /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ spinlock_t hw_lock; @@ -289,7 +293,7 @@ static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile cbd_t *bdp; + struct bufdesc *bdp; unsigned short status; unsigned long flags; @@ -374,7 +378,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - fep->cur_tx = (cbd_t *)bdp; + fep->cur_tx = bdp; spin_unlock_irqrestore(&fep->hw_lock, flags); @@ -391,7 +395,7 @@ fec_timeout(struct net_device *dev) #ifndef final_version { int i; - cbd_t *bdp; + struct bufdesc *bdp; printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", @@ -471,7 +475,7 @@ static void fec_enet_tx(struct net_device *dev) { struct fec_enet_private *fep; - volatile cbd_t *bdp; + struct bufdesc *bdp; unsigned short status; struct sk_buff *skb; @@ -534,7 +538,7 @@ fec_enet_tx(struct net_device *dev) netif_wake_queue(dev); } } - fep->dirty_tx = (cbd_t *)bdp; + fep->dirty_tx = bdp; spin_unlock_irq(&fep->hw_lock); } @@ -548,7 +552,7 @@ static void fec_enet_rx(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile cbd_t *bdp; + struct bufdesc *bdp; unsigned short status; struct sk_buff *skb; ushort pkt_len; @@ -656,7 +660,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { writel(0, fep->hwp + FEC_R_DES_ACTIVE); #endif } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ - fep->cur_rx = (cbd_t *)bdp; + fep->cur_rx = bdp; #if 0 /* Doing this here will allow us to process all frames in the @@ -1653,8 +1657,7 @@ int __init fec_enet_init(struct net_device *dev, int index) { struct fec_enet_private *fep = netdev_priv(dev); unsigned long mem_addr; - volatile cbd_t *bdp; - cbd_t *cbd_base; + struct bufdesc *bdp, *cbd_base; int i, j; /* Allocate memory for buffer descriptors. @@ -1695,7 +1698,7 @@ int __init fec_enet_init(struct net_device *dev, int index) } #endif - cbd_base = (cbd_t *)mem_addr; + cbd_base = (struct bufdesc *)mem_addr; /* Set receive and transmit descriptor base. */ @@ -1760,7 +1763,7 @@ int __init fec_enet_init(struct net_device *dev, int index) /* Set receive and transmit descriptor base. */ writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); - writel((unsigned long)fep->bd_dma + sizeof(cbd_t) * RX_RING_SIZE, + writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); #ifdef HAVE_mii_link_interrupt @@ -1824,7 +1827,7 @@ static void fec_restart(struct net_device *dev, int duplex) { struct fec_enet_private *fep = netdev_priv(dev); - volatile cbd_t *bdp; + struct bufdesc *bdp; int i; /* Whack a reset. We should wait for this. */ @@ -1846,7 +1849,7 @@ fec_restart(struct net_device *dev, int duplex) /* Set receive and transmit descriptor base. */ writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); - writel((unsigned long)fep->bd_dma + sizeof(cbd_t) * RX_RING_SIZE, + writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; diff --git a/drivers/net/fec.h b/drivers/net/fec.h index 5474ba3..30b7dd6 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -77,17 +77,17 @@ * Define the buffer descriptor structure. */ #ifdef CONFIG_ARCH_MXC -typedef struct bufdesc { +struct bufdesc { unsigned short cbd_datlen; /* Data length */ unsigned short cbd_sc; /* Control and status info */ unsigned long cbd_bufaddr; /* Buffer address */ -} cbd_t; +}; #else -typedef struct bufdesc { +struct bufdesc { unsigned short cbd_sc; /* Control and status info */ unsigned short cbd_datlen; /* Data length */ unsigned long cbd_bufaddr; /* Buffer address */ -} cbd_t; +}; #endif /* -- cgit v0.10.2 From 8d4dd5cff892e18a34422852c05a88b79ff978ed Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:17 +0000 Subject: fec: remove unnecessary cast Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index f8396fb..e03b177 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1660,11 +1660,10 @@ int __init fec_enet_init(struct net_device *dev, int index) struct bufdesc *bdp, *cbd_base; int i, j; - /* Allocate memory for buffer descriptors. - */ - mem_addr = (unsigned long)dma_alloc_coherent(NULL, PAGE_SIZE, - &fep->bd_dma, GFP_KERNEL); - if (mem_addr == 0) { + /* Allocate memory for buffer descriptors. */ + cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, + GFP_KERNEL); + if (!cbd_base) { printk("FEC: allocate descriptor memory failed?\n"); return -ENOMEM; } @@ -1698,10 +1697,7 @@ int __init fec_enet_init(struct net_device *dev, int index) } #endif - cbd_base = (struct bufdesc *)mem_addr; - - /* Set receive and transmit descriptor base. - */ + /* Set receive and transmit descriptor base. */ fep->rx_bd_base = cbd_base; fep->tx_bd_base = cbd_base + RX_RING_SIZE; -- cgit v0.10.2 From 22f6b860da25abe2c3e33347ccb806e6bcc57390 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:18 +0000 Subject: fec: Codingstyle cleanups Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index e03b177..672566b 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -86,8 +86,7 @@ static unsigned char fec_mac_default[] = { #endif #endif /* CONFIG_M5272 */ -/* Forward declarations of some structures to support different PHYs -*/ +/* Forward declarations of some structures to support different PHYs */ typedef struct { uint mii_data; @@ -123,8 +122,7 @@ typedef struct { #error "FEC: descriptor ring size constants too large" #endif -/* Interrupt events/masks. -*/ +/* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ #define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ #define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ @@ -177,15 +175,14 @@ struct fec_enet_private { ushort skb_cur; ushort skb_dirty; - /* CPM dual port RAM relative addresses. - */ + /* CPM dual port RAM relative addresses */ dma_addr_t bd_dma; - /* Address of Rx and Tx buffers. */ + /* Address of Rx and Tx buffers */ struct bufdesc *rx_bd_base; struct bufdesc *tx_bd_base; /* The next free ring entry */ struct bufdesc *cur_rx, *cur_tx; - /* The ring entries to be free()ed. */ + /* The ring entries to be free()ed */ struct bufdesc *dirty_tx; uint tx_full; @@ -245,19 +242,16 @@ static mii_list_t *mii_tail; static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *)); -/* Make MII read/write commands for the FEC. -*/ +/* Make MII read/write commands for the FEC */ #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ (VAL & 0xffff)) #define mk_mii_end 0 -/* Transmitter timeout. -*/ -#define TX_TIMEOUT (2*HZ) +/* Transmitter timeout */ +#define TX_TIMEOUT (2 * HZ) -/* Register definitions for the PHY. -*/ +/* Register definitions for the PHY */ #define MII_REG_CR 0 /* Control Register */ #define MII_REG_SR 1 /* Status Register */ @@ -307,7 +301,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) bdp = fep->cur_tx; status = bdp->cbd_sc; -#ifndef final_version + if (status & BD_ENET_TX_READY) { /* Ooops. All transmit buffers are full. Bail out. * This should not happen, since dev->tbusy should be set. @@ -316,21 +310,18 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&fep->hw_lock, flags); return 1; } -#endif - /* Clear all of the status flags. - */ + /* Clear all of the status flags */ status &= ~BD_ENET_TX_STATS; - /* Set buffer length and buffer pointer. - */ + /* Set buffer length and buffer pointer */ bdp->cbd_bufaddr = __pa(skb->data); bdp->cbd_datlen = skb->len; /* - * On some FEC implementations data must be aligned on - * 4-byte boundaries. Use bounce buffers to copy data - * and get it aligned. Ugh. + * On some FEC implementations data must be aligned on + * 4-byte boundaries. Use bounce buffers to copy data + * and get it aligned. Ugh. */ if (bdp->cbd_bufaddr & FEC_ALIGNMENT) { unsigned int index; @@ -339,8 +330,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]); } - /* Save skb pointer. - */ + /* Save skb pointer */ fep->tx_skbuff[fep->skb_cur] = skb; dev->stats.tx_bytes += skb->len; @@ -355,7 +345,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. */ - status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); bdp->cbd_sc = status; @@ -365,13 +354,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Trigger transmission start */ writel(0, fep->hwp + FEC_X_DES_ACTIVE); - /* If this was the last BD in the ring, start at the beginning again. - */ - if (status & BD_ENET_TX_WRAP) { + /* If this was the last BD in the ring, start at the beginning again. */ + if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; - } else { + else bdp++; - } if (bdp == fep->dirty_tx) { fep->tx_full = 1; @@ -429,9 +416,6 @@ fec_timeout(struct net_device *dev) netif_wake_queue(dev); } -/* The interrupt handler. - * This is called from the MPC core interrupt. - */ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id) { @@ -440,12 +424,10 @@ fec_enet_interrupt(int irq, void * dev_id) uint int_events; irqreturn_t ret = IRQ_NONE; - /* Get the interrupt events that caused us to be here. */ do { int_events = readl(fep->hwp + FEC_IEVENT); writel(int_events, fep->hwp + FEC_IEVENT); - /* Handle receive event in its own function. */ if (int_events & FEC_ENET_RXF) { ret = IRQ_HANDLED; fec_enet_rx(dev); @@ -506,31 +488,27 @@ fec_enet_tx(struct net_device *dev) dev->stats.tx_packets++; } -#ifndef final_version if (status & BD_ENET_TX_READY) printk("HEY! Enet xmit interrupt and TX_READY.\n"); -#endif + /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ if (status & BD_ENET_TX_DEF) dev->stats.collisions++; - /* Free the sk buffer associated with this last transmit. - */ + /* Free the sk buffer associated with this last transmit */ dev_kfree_skb_any(skb); fep->tx_skbuff[fep->skb_dirty] = NULL; fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; - /* Update pointer to next buffer descriptor to be transmitted. - */ + /* Update pointer to next buffer descriptor to be transmitted */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; else bdp++; - /* Since we have freed up a buffer, the ring is no longer - * full. + /* Since we have freed up a buffer, the ring is no longer full */ if (fep->tx_full) { fep->tx_full = 0; @@ -569,114 +547,93 @@ fec_enet_rx(struct net_device *dev) */ bdp = fep->cur_rx; -while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { + while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { -#ifndef final_version - /* Since we have allocated space to hold a complete frame, - * the last indicator should be set. - */ - if ((status & BD_ENET_RX_LAST) == 0) - printk("FEC ENET: rcv is not +last\n"); -#endif + /* Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((status & BD_ENET_RX_LAST) == 0) + printk("FEC ENET: rcv is not +last\n"); - if (!fep->opened) - goto rx_processing_done; + if (!fep->opened) + goto rx_processing_done; - /* Check for errors. */ - if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | + /* Check for errors. */ + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - dev->stats.rx_errors++; - if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { - /* Frame too long or too short. */ - dev->stats.rx_length_errors++; + dev->stats.rx_errors++; + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { + /* Frame too long or too short. */ + dev->stats.rx_length_errors++; + } + if (status & BD_ENET_RX_NO) /* Frame alignment */ + dev->stats.rx_frame_errors++; + if (status & BD_ENET_RX_CR) /* CRC Error */ + dev->stats.rx_crc_errors++; + if (status & BD_ENET_RX_OV) /* FIFO overrun */ + dev->stats.rx_fifo_errors++; } - if (status & BD_ENET_RX_NO) /* Frame alignment */ - dev->stats.rx_frame_errors++; - if (status & BD_ENET_RX_CR) /* CRC Error */ - dev->stats.rx_crc_errors++; - if (status & BD_ENET_RX_OV) /* FIFO overrun */ - dev->stats.rx_fifo_errors++; - } - /* Report late collisions as a frame error. - * On this error, the BD is closed, but we don't know what we - * have in the buffer. So, just drop this frame on the floor. - */ - if (status & BD_ENET_RX_CL) { - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; - goto rx_processing_done; - } + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (status & BD_ENET_RX_CL) { + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; + goto rx_processing_done; + } - /* Process the incoming frame. - */ - dev->stats.rx_packets++; - pkt_len = bdp->cbd_datlen; - dev->stats.rx_bytes += pkt_len; - data = (__u8*)__va(bdp->cbd_bufaddr); + /* Process the incoming frame. */ + dev->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + dev->stats.rx_bytes += pkt_len; + data = (__u8*)__va(bdp->cbd_bufaddr); - dma_sync_single(NULL, (unsigned long)__pa(data), + dma_sync_single(NULL, (unsigned long)__pa(data), pkt_len - 4, DMA_FROM_DEVICE); - /* This does 16 byte alignment, exactly what we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ - skb = dev_alloc_skb(pkt_len-4); - - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - dev->stats.rx_dropped++; - } else { - skb_put(skb,pkt_len-4); /* Make room */ - skb_copy_to_linear_data(skb, data, pkt_len-4); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } - rx_processing_done: - - /* Clear the status flags for this buffer. - */ - status &= ~BD_ENET_RX_STATS; + /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len - 4); - /* Mark the buffer empty. - */ - status |= BD_ENET_RX_EMPTY; - bdp->cbd_sc = status; + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", + dev->name); + dev->stats.rx_dropped++; + } else { + skb_put(skb, pkt_len - 4); /* Make room */ + skb_copy_to_linear_data(skb, data, pkt_len - 4); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + } +rx_processing_done: + /* Clear the status flags for this buffer */ + status &= ~BD_ENET_RX_STATS; - /* Update BD pointer to next entry. - */ - if (status & BD_ENET_RX_WRAP) - bdp = fep->rx_bd_base; - else - bdp++; + /* Mark the buffer empty */ + status |= BD_ENET_RX_EMPTY; + bdp->cbd_sc = status; -#if 1 - /* Doing this here will keep the FEC running while we process - * incoming frames. On a heavily loaded network, we should be - * able to keep up at the expense of system resources. - */ - writel(0, fep->hwp + FEC_R_DES_ACTIVE); -#endif - } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ + /* Update BD pointer to next entry */ + if (status & BD_ENET_RX_WRAP) + bdp = fep->rx_bd_base; + else + bdp++; + /* Doing this here will keep the FEC running while we process + * incoming frames. On a heavily loaded network, we should be + * able to keep up at the expense of system resources. + */ + writel(0, fep->hwp + FEC_R_DES_ACTIVE); + } fep->cur_rx = bdp; -#if 0 - /* Doing this here will allow us to process all frames in the - * ring before the FEC is allowed to put more there. On a heavily - * loaded network, some frames may be lost. Unfortunately, this - * increases the interrupt overhead since we can potentially work - * our way back to the interrupt return only to come right back - * here. - */ - fecp->fec_r_des_active = 0; -#endif - spin_unlock_irq(&fep->hw_lock); } - /* called from interrupt context */ static void fec_enet_mii(struct net_device *dev) @@ -714,8 +671,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi mii_list_t *mip; int retval; - /* Add PHY address to register command. - */ + /* Add PHY address to register command */ fep = netdev_priv(dev); spin_lock_irqsave(&fep->mii_lock, flags); @@ -1358,11 +1314,6 @@ static void mii_relink(struct work_struct *work) fec_restart(dev, duplex); } else fec_stop(dev); - -#if 0 - enable_irq(fep->mii_irq); -#endif - } /* mii_queue_relink is called in interrupt context from mii_link_interrupt */ @@ -1371,12 +1322,12 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) struct fec_enet_private *fep = netdev_priv(dev); /* - ** We cannot queue phy_task twice in the workqueue. It - ** would cause an endless loop in the workqueue. - ** Fortunately, if the last mii_relink entry has not yet been - ** executed now, it will do the job for the current interrupt, - ** which is just what we want. - */ + * We cannot queue phy_task twice in the workqueue. It + * would cause an endless loop in the workqueue. + * Fortunately, if the last mii_relink entry has not yet been + * executed now, it will do the job for the current interrupt, + * which is just what we want. + */ if (fep->mii_phy_task_queued) return; @@ -1407,8 +1358,7 @@ phy_cmd_t const phy_cmd_config[] = { { mk_mii_end, } }; -/* Read remainder of PHY ID. -*/ +/* Read remainder of PHY ID. */ static void mii_discover_phy3(uint mii_reg, struct net_device *dev) { @@ -1447,8 +1397,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) if (fep->phy_addr < 32) { if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { - /* Got first part of ID, now get remainder. - */ + /* Got first part of ID, now get remainder */ fep->phy_id = phytype << 16; mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3); @@ -1468,8 +1417,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) } } -/* This interrupt occurs when the PHY detects a link change. -*/ +/* This interrupt occurs when the PHY detects a link change */ #ifdef HAVE_mii_link_interrupt static irqreturn_t mii_link_interrupt(int irq, void * dev_id) @@ -1479,10 +1427,6 @@ mii_link_interrupt(int irq, void * dev_id) fec_phy_ack_intr(); -#if 0 - disable_irq(fep->mii_irq); /* disable now, enable later */ -#endif - mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ @@ -1533,7 +1477,7 @@ fec_enet_open(struct net_device *dev) netif_start_queue(dev); fep->opened = 1; - return 0; /* Success */ + return 0; } static int @@ -1541,8 +1485,7 @@ fec_enet_close(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - /* Don't know what to do yet. - */ + /* Don't know what to do yet. */ fep->opened = 0; netif_stop_queue(dev); fec_stop(dev); @@ -1570,7 +1513,7 @@ static void set_multicast_list(struct net_device *dev) unsigned int i, j, bit, data, crc, tmp; unsigned char hash; - if (dev->flags&IFF_PROMISC) { + if (dev->flags & IFF_PROMISC) { tmp = readl(fep->hwp + FEC_R_CNTRL); tmp |= 0x8; writel(tmp, fep->hwp + FEC_R_CNTRL); @@ -1581,42 +1524,37 @@ static void set_multicast_list(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the - * filter to all 1's. + * filter to all 1's */ writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); } else { - /* Clear filter and add the addresses in hash register. - */ + /* Clear filter and add the addresses in hash register + */ writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); dmi = dev->mc_list; - for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) - { - /* Only support group multicast for now. - */ + for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { + /* Only support group multicast for now */ if (!(dmi->dmi_addr[0] & 1)) continue; - /* calculate crc32 value of mac address - */ + /* calculate crc32 value of mac address */ crc = 0xffffffff; - for (i = 0; i < dmi->dmi_addrlen; i++) - { + for (i = 0; i < dmi->dmi_addrlen; i++) { data = dmi->dmi_addr[i]; - for (bit = 0; bit < 8; bit++, data >>= 1) - { + for (bit = 0; bit < 8; bit++, data >>= 1) { crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CRC32_POLY : 0); } } /* only upper 6 bits (HASH_BITS) are used - which point to specific bit in he hash registers - */ + * which point to specific bit in he hash registers + */ hash = (crc >> (32 - HASH_BITS)) & 0x3f; if (hash > 31) { @@ -1633,8 +1571,7 @@ static void set_multicast_list(struct net_device *dev) } } -/* Set a MAC change in hardware. - */ +/* Set a MAC change in hardware. */ static void fec_set_mac_address(struct net_device *dev) { @@ -1675,8 +1612,7 @@ int __init fec_enet_init(struct net_device *dev, int index) fep->hwp = (void __iomem *)dev->base_addr; fep->netdev = dev; - /* Whack a reset. We should wait for this. - */ + /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); udelay(10); @@ -1706,18 +1642,15 @@ int __init fec_enet_init(struct net_device *dev, int index) fep->skb_cur = fep->skb_dirty = 0; - /* Initialize the receive buffer descriptors. - */ + /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; for (i=0; icbd_sc = BD_ENET_RX_EMPTY; bdp->cbd_bufaddr = __pa(mem_addr); @@ -1726,13 +1659,11 @@ int __init fec_enet_init(struct net_device *dev, int index) } } - /* Set the last buffer to wrap. - */ + /* Set the last buffer to wrap */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* ...and the same for transmmit. - */ + /* ...and the same for transmit */ bdp = fep->tx_bd_base; for (i=0, j=FEC_ENET_TX_FRPPG; i= FEC_ENET_TX_FRPPG) { @@ -1744,20 +1675,17 @@ int __init fec_enet_init(struct net_device *dev, int index) } fep->tx_bounce[i] = (unsigned char *) mem_addr; - /* Initialize the BD for every fragment in the page. - */ + /* Initialize the BD for every fragment in the page */ bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; bdp++; } - /* Set the last buffer to wrap. - */ + /* Set the last buffer to wrap */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* Set receive and transmit descriptor base. - */ + /* Set receive and transmit descriptor base */ writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); @@ -1776,7 +1704,7 @@ int __init fec_enet_init(struct net_device *dev, int index) writel(0, fep->hwp + FEC_HASH_TABLE_LOW); #endif - /* The FEC Ethernet specific entries in the device structure. */ + /* The FEC Ethernet specific entries in the device structure */ dev->open = fec_enet_open; dev->hard_start_xmit = fec_enet_start_xmit; dev->tx_timeout = fec_timeout; @@ -1792,9 +1720,7 @@ int __init fec_enet_init(struct net_device *dev, int index) writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL); writel(0, fep->hwp + FEC_X_CNTRL); - /* - * Set MII speed to 2.5 MHz - */ + /* Set MII speed to 2.5 MHz */ fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) / 2500000) / 2) & 0x3F) << 1; writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); @@ -1853,8 +1779,8 @@ fec_restart(struct net_device *dev, int duplex) /* Reset SKB transmit buffers. */ fep->skb_cur = fep->skb_dirty = 0; - for (i=0; i<=TX_RING_MOD_MASK; i++) { - if (fep->tx_skbuff[i] != NULL) { + for (i = 0; i <= TX_RING_MOD_MASK; i++) { + if (fep->tx_skbuff[i]) { dev_kfree_skb_any(fep->tx_skbuff[i]); fep->tx_skbuff[i] = NULL; } @@ -1862,20 +1788,20 @@ fec_restart(struct net_device *dev, int duplex) /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; - for (i=0; icbd_sc = BD_ENET_RX_EMPTY; bdp++; } - /* Set the last buffer to wrap. */ + /* Set the last buffer to wrap */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* ...and the same for transmmit. */ + /* ...and the same for transmit */ bdp = fep->tx_bd_base; - for (i=0; icbd_sc = 0; @@ -1883,11 +1809,11 @@ fec_restart(struct net_device *dev, int duplex) bdp++; } - /* Set the last buffer to wrap. */ + /* Set the last buffer to wrap */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* Enable MII mode. */ + /* Enable MII mode */ if (duplex) { /* MII enable / FD enable */ writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL); @@ -1899,14 +1825,14 @@ fec_restart(struct net_device *dev, int duplex) } fep->full_duplex = duplex; - /* Set MII speed. */ + /* Set MII speed */ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - /* And last, enable the transmit and receive processing. */ + /* And last, enable the transmit and receive processing */ writel(2, fep->hwp + FEC_ECNTRL); writel(0, fep->hwp + FEC_R_DES_ACTIVE); - /* Enable interrupts we wish to service. */ + /* Enable interrupts we wish to service */ writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII, fep->hwp + FEC_IMASK); } @@ -1916,9 +1842,7 @@ fec_stop(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - /* - ** We cannot expect a graceful transmit stop without link !!! - */ + /* We cannot expect a graceful transmit stop without link !!! */ if (fep->link) { writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ udelay(10); -- cgit v0.10.2 From 4e8318368af44488f6438a31537ddb57de0d4e00 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:19 +0000 Subject: fec: refactor set_multicast_list() to make it more readable Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 672566b..6ac1b90 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1517,57 +1517,60 @@ static void set_multicast_list(struct net_device *dev) tmp = readl(fep->hwp + FEC_R_CNTRL); tmp |= 0x8; writel(tmp, fep->hwp + FEC_R_CNTRL); - } else { - tmp = readl(fep->hwp + FEC_R_CNTRL); - tmp &= ~0x8; - writel(tmp, fep->hwp + FEC_R_CNTRL); + return; + } - if (dev->flags & IFF_ALLMULTI) { - /* Catch all multicast addresses, so set the - * filter to all 1's - */ - writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - } else { - /* Clear filter and add the addresses in hash register - */ - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - - dmi = dev->mc_list; - - for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { - /* Only support group multicast for now */ - if (!(dmi->dmi_addr[0] & 1)) - continue; - - /* calculate crc32 value of mac address */ - crc = 0xffffffff; - - for (i = 0; i < dmi->dmi_addrlen; i++) { - data = dmi->dmi_addr[i]; - for (bit = 0; bit < 8; bit++, data >>= 1) { - crc = (crc >> 1) ^ - (((crc ^ data) & 1) ? CRC32_POLY : 0); - } - } - - /* only upper 6 bits (HASH_BITS) are used - * which point to specific bit in he hash registers - */ - hash = (crc >> (32 - HASH_BITS)) & 0x3f; - - if (hash > 31) { - tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - tmp |= 1 << (hash - 32); - writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - } else { - tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); - tmp |= 1 << hash; - writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - } + tmp = readl(fep->hwp + FEC_R_CNTRL); + tmp &= ~0x8; + writel(tmp, fep->hwp + FEC_R_CNTRL); + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's + */ + writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); + + return; + } + + /* Clear filter and add the addresses in hash register + */ + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); + + dmi = dev->mc_list; + + for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { + /* Only support group multicast for now */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* calculate crc32 value of mac address */ + crc = 0xffffffff; + + for (i = 0; i < dmi->dmi_addrlen; i++) { + data = dmi->dmi_addr[i]; + for (bit = 0; bit < 8; bit++, data >>= 1) { + crc = (crc >> 1) ^ + (((crc ^ data) & 1) ? CRC32_POLY : 0); } } + + /* only upper 6 bits (HASH_BITS) are used + * which point to specific bit in he hash registers + */ + hash = (crc >> (32 - HASH_BITS)) & 0x3f; + + if (hash > 31) { + tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + tmp |= 1 << (hash - 32); + writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + } else { + tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); + tmp |= 1 << hash; + writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); + } } } -- cgit v0.10.2 From 4f1ceb4b46d523382f5a46622af9d3315a9b3e7f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:20 +0000 Subject: fec: refactor init function fec_enet_init() does the hardware initialisation and then calls fec_restart() which does the same initialisation again, so we can safely remove the initialisation from fec_enet_init(). Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 6ac1b90..5ca2d6b 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1615,10 +1615,6 @@ int __init fec_enet_init(struct net_device *dev, int index) fep->hwp = (void __iomem *)dev->base_addr; fep->netdev = dev; - /* Whack a reset. We should wait for this. */ - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); - /* Set the Ethernet address */ #ifdef CONFIG_M5272 fec_get_mac(dev); @@ -1640,11 +1636,6 @@ int __init fec_enet_init(struct net_device *dev, int index) fep->rx_bd_base = cbd_base; fep->tx_bd_base = cbd_base + RX_RING_SIZE; - fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; - fep->cur_rx = fep->rx_bd_base; - - fep->skb_cur = fep->skb_dirty = 0; - /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; for (i=0; icbd_sc |= BD_SC_WRAP; - /* Set receive and transmit descriptor base */ - writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); - writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, - fep->hwp + FEC_X_DES_START); - #ifdef HAVE_mii_link_interrupt fec_request_mii_intr(dev); #endif - - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); - writel(2, fep->hwp + FEC_ECNTRL); - writel(0, fep->hwp + FEC_R_DES_ACTIVE); -#ifndef CONFIG_M5272 - writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_HASH_TABLE_LOW); -#endif - /* The FEC Ethernet specific entries in the device structure */ dev->open = fec_enet_open; dev->hard_start_xmit = fec_enet_start_xmit; @@ -1719,21 +1694,11 @@ int __init fec_enet_init(struct net_device *dev, int index) mii_cmds[i].mii_next = &mii_cmds[i+1]; mii_free = mii_cmds; - /* setup MII interface */ - writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL); - writel(0, fep->hwp + FEC_X_CNTRL); - /* Set MII speed to 2.5 MHz */ fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) / 2500000) / 2) & 0x3F) << 1; - writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); fec_restart(dev, 0); - /* Clear and enable interrupts */ - writel(0xffc00000, fep->hwp + FEC_IEVENT); - writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII, - fep->hwp + FEC_IMASK); - /* Queue up command to detect the PHY and initialize the * remainder of the interface. */ @@ -1768,6 +1733,10 @@ fec_restart(struct net_device *dev, int duplex) /* Reset all multicast. */ writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); +#ifndef CONFIG_M5272 + writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_HASH_TABLE_LOW); +#endif /* Set maximum receive buffer size. */ writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); -- cgit v0.10.2 From 8549889c3369f7653bd98861c3d2cf97d810dc37 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:21 +0000 Subject: fec: align receive packets Otherwise we get a lot of alignment errors Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 5ca2d6b..ba3eb54 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -598,13 +598,14 @@ fec_enet_rx(struct net_device *dev) * include that when passing upstream as it messes up * bridging applications. */ - skb = dev_alloc_skb(pkt_len - 4); + skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN); - if (skb == NULL) { + if (unlikely(!skb)) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; } else { + skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pkt_len - 4); /* Make room */ skb_copy_to_linear_data(skb, data, pkt_len - 4); skb->protocol = eth_type_trans(skb, dev); -- cgit v0.10.2 From 3644ee00c43cca08c9baac7eaea22250aaf84182 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:22 +0000 Subject: fec: remove debugging printks These printks in fec_timeout do not give useful information in a production kernel. Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index ba3eb54..7b3e331d 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -377,41 +377,8 @@ fec_timeout(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - printk("%s: transmit timed out.\n", dev->name); dev->stats.tx_errors++; -#ifndef final_version - { - int i; - struct bufdesc *bdp; - - printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", - (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", - (unsigned long)fep->dirty_tx, - (unsigned long)fep->cur_rx); - - bdp = fep->tx_bd_base; - printk(" tx: %u buffers\n", TX_RING_SIZE); - for (i = 0 ; i < TX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", - (uint) bdp, - bdp->cbd_sc, - bdp->cbd_datlen, - (int) bdp->cbd_bufaddr); - bdp++; - } - bdp = fep->rx_bd_base; - printk(" rx: %lu buffers\n", (unsigned long) RX_RING_SIZE); - for (i = 0 ; i < RX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", - (uint) bdp, - bdp->cbd_sc, - bdp->cbd_datlen, - (int) bdp->cbd_bufaddr); - bdp++; - } - } -#endif fec_restart(dev, fep->full_duplex); netif_wake_queue(dev); } -- cgit v0.10.2 From 009fda83ee2f38e5deb9d62fc54a904a92645fe4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:23 +0000 Subject: fec: switch to net_device_ops Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 7b3e331d..54ee493 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -210,17 +210,13 @@ struct fec_enet_private { int full_duplex; }; -static int fec_enet_open(struct net_device *dev); -static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static void fec_enet_mii(struct net_device *dev); static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); static void fec_restart(struct net_device *dev, int duplex); static void fec_stop(struct net_device *dev); -static void fec_set_mac_address(struct net_device *dev); /* MII processing. We keep this as simple as possible. Requests are @@ -1410,7 +1406,6 @@ fec_enet_open(struct net_device *dev) /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ - fec_set_mac_address(dev); fep->sequence_done = 0; fep->link = 0; @@ -1543,19 +1538,35 @@ static void set_multicast_list(struct net_device *dev) } /* Set a MAC change in hardware. */ -static void -fec_set_mac_address(struct net_device *dev) +static int +fec_set_mac_address(struct net_device *dev, void *p) { struct fec_enet_private *fep = netdev_priv(dev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - /* Set station address. */ writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) | (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24), fep->hwp + FEC_ADDR_LOW); writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24), fep + FEC_ADDR_HIGH); + return 0; } +static const struct net_device_ops fec_netdev_ops = { + .ndo_open = fec_enet_open, + .ndo_stop = fec_enet_close, + .ndo_start_xmit = fec_enet_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = fec_timeout, + .ndo_set_mac_address = fec_set_mac_address, +}; + /* * XXX: We need to clean up on failure exits here. * @@ -1651,12 +1662,8 @@ int __init fec_enet_init(struct net_device *dev, int index) fec_request_mii_intr(dev); #endif /* The FEC Ethernet specific entries in the device structure */ - dev->open = fec_enet_open; - dev->hard_start_xmit = fec_enet_start_xmit; - dev->tx_timeout = fec_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = fec_enet_close; - dev->set_multicast_list = set_multicast_list; + dev->netdev_ops = &fec_netdev_ops; for (i=0; ihwp + FEC_IEVENT); - /* Set station address. */ - fec_set_mac_address(dev); - /* Reset all multicast. */ writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); -- cgit v0.10.2 From f0b3fbeae11a526c3d308b691684589ee37c359b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:24 +0000 Subject: FEC Buffer rework Allocate buffers in fec_open and free them again in fec_close. This makes it possible to use this driver as a module. Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 54ee493..54d6f86 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -172,6 +172,7 @@ struct fec_enet_private { /* The saved address of a sent-in-place packet/buffer, for skfree(). */ unsigned char *tx_bounce[TX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct sk_buff* rx_skbuff[RX_RING_SIZE]; ushort skb_cur; ushort skb_dirty; @@ -335,8 +336,8 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Push the data cache so the CPM does not get stale memory * data. */ - dma_sync_single(NULL, bdp->cbd_bufaddr, - bdp->cbd_datlen, DMA_TO_DEVICE); + bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data, + FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. @@ -429,7 +430,11 @@ fec_enet_tx(struct net_device *dev) bdp = fep->dirty_tx; while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { - if (bdp == fep->cur_tx && fep->tx_full == 0) break; + if (bdp == fep->cur_tx && fep->tx_full == 0) + break; + + dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); + bdp->cbd_bufaddr = 0; skb = fep->tx_skbuff[fep->skb_dirty]; /* Check for errors. */ @@ -553,8 +558,8 @@ fec_enet_rx(struct net_device *dev) dev->stats.rx_bytes += pkt_len; data = (__u8*)__va(bdp->cbd_bufaddr); - dma_sync_single(NULL, (unsigned long)__pa(data), - pkt_len - 4, DMA_FROM_DEVICE); + dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen, + DMA_FROM_DEVICE); /* This does 16 byte alignment, exactly what we need. * The packet length includes FCS, but we don't want to @@ -574,6 +579,9 @@ fec_enet_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); } + + bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen, + DMA_FROM_DEVICE); rx_processing_done: /* Clear the status flags for this buffer */ status &= ~BD_ENET_RX_STATS; @@ -1398,15 +1406,86 @@ mii_link_interrupt(int irq, void * dev_id) } #endif +static void fec_enet_free_buffers(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + int i; + struct sk_buff *skb; + struct bufdesc *bdp; + + bdp = fep->rx_bd_base; + for (i = 0; i < RX_RING_SIZE; i++) { + skb = fep->rx_skbuff[i]; + + if (bdp->cbd_bufaddr) + dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); + if (skb) + dev_kfree_skb(skb); + bdp++; + } + + bdp = fep->tx_bd_base; + for (i = 0; i < TX_RING_SIZE; i++) + kfree(fep->tx_bounce[i]); +} + +static int fec_enet_alloc_buffers(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + int i; + struct sk_buff *skb; + struct bufdesc *bdp; + + bdp = fep->rx_bd_base; + for (i = 0; i < RX_RING_SIZE; i++) { + skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE); + if (!skb) { + fec_enet_free_buffers(dev); + return -ENOMEM; + } + fep->rx_skbuff[i] = skb; + + bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); + bdp->cbd_sc = BD_ENET_RX_EMPTY; + bdp++; + } + + /* Set the last buffer to wrap. */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + bdp = fep->tx_bd_base; + for (i = 0; i < TX_RING_SIZE; i++) { + fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); + + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + return 0; +} + static int fec_enet_open(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); + int ret; /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ + ret = fec_enet_alloc_buffers(dev); + if (ret) + return ret; + fep->sequence_done = 0; fep->link = 0; @@ -1453,6 +1532,8 @@ fec_enet_close(struct net_device *dev) netif_stop_queue(dev); fec_stop(dev); + fec_enet_free_buffers(dev); + return 0; } @@ -1575,9 +1656,8 @@ static const struct net_device_ops fec_netdev_ops = { int __init fec_enet_init(struct net_device *dev, int index) { struct fec_enet_private *fep = netdev_priv(dev); - unsigned long mem_addr; - struct bufdesc *bdp, *cbd_base; - int i, j; + struct bufdesc *cbd_base; + int i; /* Allocate memory for buffer descriptors. */ cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, @@ -1615,49 +1695,6 @@ int __init fec_enet_init(struct net_device *dev, int index) fep->rx_bd_base = cbd_base; fep->tx_bd_base = cbd_base + RX_RING_SIZE; - /* Initialize the receive buffer descriptors. */ - bdp = fep->rx_bd_base; - for (i=0; icbd_sc = BD_ENET_RX_EMPTY; - bdp->cbd_bufaddr = __pa(mem_addr); - mem_addr += FEC_ENET_RX_FRSIZE; - bdp++; - } - } - - /* Set the last buffer to wrap */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - /* ...and the same for transmit */ - bdp = fep->tx_bd_base; - for (i=0, j=FEC_ENET_TX_FRPPG; i= FEC_ENET_TX_FRPPG) { - mem_addr = __get_free_page(GFP_KERNEL); - j = 1; - } else { - mem_addr += FEC_ENET_TX_FRSIZE; - j++; - } - fep->tx_bounce[i] = (unsigned char *) mem_addr; - - /* Initialize the BD for every fragment in the page */ - bdp->cbd_sc = 0; - bdp->cbd_bufaddr = 0; - bdp++; - } - - /* Set the last buffer to wrap */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - #ifdef HAVE_mii_link_interrupt fec_request_mii_intr(dev); #endif -- cgit v0.10.2 From fe957c40ec5e2763b9977c565beab3bde3aaf85b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Apr 2009 01:32:25 +0000 Subject: fec: call fec_restart() in fec_open() We called fec_stop() in fec_enet_close(), thus we have to call fec_restart() in fec_enet_open(). Signed-off-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 54d6f86..63eaf5d 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1489,6 +1489,8 @@ fec_enet_open(struct net_device *dev) fep->sequence_done = 0; fep->link = 0; + fec_restart(dev, 1); + if (fep->phy) { mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, fep->phy->config); @@ -1505,18 +1507,14 @@ fec_enet_open(struct net_device *dev) schedule(); mii_do_cmd(dev, fep->phy->startup); - - /* Set the initial link state to true. A lot of hardware - * based on this device does not implement a PHY interrupt, - * so we are never notified of link change. - */ - fep->link = 1; - } else { - fep->link = 1; /* lets just try it and see */ - /* no phy, go full duplex, it's most likely a hub chip */ - fec_restart(dev, 1); } + /* Set the initial link state to true. A lot of hardware + * based on this device does not implement a PHY interrupt, + * so we are never notified of link change. + */ + fep->link = 1; + netif_start_queue(dev); fep->opened = 1; return 0; -- cgit v0.10.2 From 590818250684d18bb0e30c45d79971dcdff96ad0 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 16 Apr 2009 02:23:56 +0000 Subject: myri10ge: force stats update in ethtool gstats Force a statistics update when our ethtool gstats routine is called. Otherwise, ethtool will continue to read stale stats until something forces an update by reading /proc/net/dev This requires putting a lock around the stats update to guard against 2 threads (one via ethtool, and one via procfs) updating the stats at once. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index f2c4a66..a833cdd 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -361,6 +361,8 @@ static inline void put_be32(__be32 val, __be32 __iomem * p) __raw_writel((__force __u32) val, (__force void __iomem *)p); } +static struct net_device_stats *myri10ge_get_stats(struct net_device *dev); + static int myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, struct myri10ge_cmd *data, int atomic) @@ -1803,6 +1805,8 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, int slice; int i; + /* force stats update */ + (void)myri10ge_get_stats(netdev); for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++) data[i] = ((unsigned long *)&mgp->stats)[i]; @@ -2969,6 +2973,7 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) struct net_device_stats *stats = &mgp->stats; int i; + spin_lock(&mgp->stats_lock); memset(stats, 0, sizeof(*stats)); for (i = 0; i < mgp->num_slices; i++) { slice_stats = &mgp->ss[i].stats; @@ -2979,6 +2984,7 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) stats->rx_dropped += slice_stats->rx_dropped; stats->tx_dropped += slice_stats->tx_dropped; } + spin_unlock(&mgp->stats_lock); return stats; } @@ -3902,6 +3908,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer, (unsigned long)mgp); + spin_lock_init(&mgp->stats_lock); SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops); INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog); status = register_netdev(netdev); -- cgit v0.10.2 From 2d90b0aa3bc484189940444bcddcbe0ebbb53af5 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 16 Apr 2009 02:24:59 +0000 Subject: myri10ge: allow per-board firmware overriding Add myri10ge_fw_names to override the default firmware on a per-board basis. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index a833cdd..77de964 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -255,6 +255,7 @@ struct myri10ge_priv { u32 read_write_dma; u32 link_changes; u32 msg_enable; + unsigned int board_number; }; static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; @@ -266,6 +267,13 @@ static char *myri10ge_fw_name = NULL; module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name"); +#define MYRI10GE_MAX_BOARDS 8 +static char *myri10ge_fw_names[MYRI10GE_MAX_BOARDS] = + {[0...(MYRI10GE_MAX_BOARDS - 1)] = NULL }; +module_param_array_named(myri10ge_fw_names, myri10ge_fw_names, charp, NULL, + 0444); +MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image names per board"); + static int myri10ge_ecrc_enable = 1; module_param(myri10ge_ecrc_enable, int, S_IRUGO); MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E"); @@ -3259,6 +3267,8 @@ abort: static void myri10ge_select_firmware(struct myri10ge_priv *mgp) { + int overridden = 0; + if (myri10ge_force_firmware == 0) { int link_width, exp_cap; u16 lnk; @@ -3292,10 +3302,18 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) } } if (myri10ge_fw_name != NULL) { - dev_info(&mgp->pdev->dev, "overriding firmware to %s\n", - myri10ge_fw_name); + overridden = 1; mgp->fw_name = myri10ge_fw_name; } + if (mgp->board_number < MYRI10GE_MAX_BOARDS && + myri10ge_fw_names[mgp->board_number] != NULL && + strlen(myri10ge_fw_names[mgp->board_number])) { + mgp->fw_name = myri10ge_fw_names[mgp->board_number]; + overridden = 1; + } + if (overridden) + dev_info(&mgp->pdev->dev, "overriding firmware to %s\n", + mgp->fw_name); } #ifdef CONFIG_PM @@ -3760,6 +3778,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int status = -ENXIO; int dac_enabled; unsigned hdr_offset, ss_offset; + static int board_number; netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES); if (netdev == NULL) { @@ -3776,6 +3795,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp->pause = myri10ge_flow_control; mgp->intr_coal_delay = myri10ge_intr_coal_delay; mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT); + mgp->board_number = board_number; init_waitqueue_head(&mgp->down_wq); if (pci_enable_device(pdev)) { @@ -3926,6 +3946,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->irq, mgp->tx_boundary, mgp->fw_name, (mgp->wc_enabled ? "Enabled" : "Disabled")); + board_number++; return 0; abort_with_state: -- cgit v0.10.2 From 97131079183cd671e18e661f1a387cdb5dffd313 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 16 Apr 2009 02:29:22 +0000 Subject: myri10ge: add MODULE_DEVICE_TABLE Add MODULE_DEVICE_TABLE so that modinfo reports pci device id aliases. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 77de964..4a2ab4e 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.4-1.401" +#define MYRI10GE_VERSION_STR "1.4.4-1.412" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -4036,6 +4036,8 @@ static struct pci_device_id myri10ge_pci_tbl[] = { {0}, }; +MODULE_DEVICE_TABLE(pci, myri10ge_pci_tbl); + static struct pci_driver myri10ge_driver = { .name = "myri10ge", .probe = myri10ge_probe, -- cgit v0.10.2 From 6498be3fba7b102132241be5763263e8e8bf6f9e Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 16 Apr 2009 17:56:57 -0700 Subject: myri10ge: fix tx ring size in ethtool -g Fix tx ring size reported via ethtool -g. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 4a2ab4e..291944d 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1696,7 +1696,7 @@ myri10ge_get_ringparam(struct net_device *netdev, ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1; ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1; ring->rx_jumbo_max_pending = 0; - ring->tx_max_pending = mgp->ss[0].rx_small.mask + 1; + ring->tx_max_pending = mgp->ss[0].tx.mask + 1; ring->rx_mini_pending = ring->rx_mini_max_pending; ring->rx_pending = ring->rx_max_pending; ring->rx_jumbo_pending = ring->rx_jumbo_max_pending; -- cgit v0.10.2 From f6a2629353718e588820b731af43a445b6f35648 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Thu, 16 Apr 2009 15:23:03 +0000 Subject: irda: include etherdevice.h for eth_*() functions Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index 204def0..269153e 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index e8ced56..3376a4f 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 44a748e..4ed7636 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From d32da050a340214c5dae0d014e39f75548cac2f2 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Thu, 16 Apr 2009 15:48:17 +0000 Subject: wan/pc300_drv: convert to net_device_ops On Fri, Apr 17, 2009 at 05:23:02AM +0400, Alexander Beregalov wrote: > > Signed-off-by: Alexander Beregalov > --- > drivers/net/wan/pc300_drv.c | 22 ++++++++++++++-------- > 1 files changed, 14 insertions(+), 8 deletions(-) > > diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c > index c23fde0..df10a4c 100644 > --- a/drivers/net/wan/pc300_drv.c > +++ b/drivers/net/wan/pc300_drv.c > @@ -225,6 +225,7 @@ static char rcsid[] = > #include > #include > #include > +#include > #include > #include > #include > @@ -3246,6 +3247,18 @@ static inline void show_version(void) > rcsvers, rcsdate, __DATE__, __TIME__); > } /* show_version */ > > +static const struct net_device_ops cpc_netdev_ops = { > + .ndo_init = NULL, > + .ndo_open = cpc_open, > + .ndo_stop = cpc_close, > + .ndo_tx_timeout = cpc_tx_timeout, > + .ndo_set_multicast_list = NULL, In this case ndo_init and ndo_set_multicast_list are not needed. >From 1507a5a797a5f0005696a9bf10e390caca9c3800 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 17 Apr 2009 05:45:48 +0400 Subject: [PATCH] wan/pc300_drv: convert to net_device_ops Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index c23fde0..79dabc5 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -225,6 +225,7 @@ static char rcsid[] = #include #include #include +#include #include #include #include @@ -3246,6 +3247,16 @@ static inline void show_version(void) rcsvers, rcsdate, __DATE__, __TIME__); } /* show_version */ +static const struct net_device_ops cpc_netdev_ops = { + .ndo_open = cpc_open, + .ndo_stop = cpc_close, + .ndo_tx_timeout = cpc_tx_timeout, + .ndo_set_mac_address = NULL, + .ndo_change_mtu = cpc_change_mtu, + .ndo_do_ioctl = cpc_ioctl, + .ndo_validate_addr = eth_validate_addr, +}; + static void cpc_init_card(pc300_t * card) { int i, devcount = 0; @@ -3357,18 +3368,11 @@ static void cpc_init_card(pc300_t * card) dev->mem_start = card->hw.ramphys; dev->mem_end = card->hw.ramphys + card->hw.ramsize - 1; dev->irq = card->hw.irq; - dev->init = NULL; dev->tx_queue_len = PC300_TX_QUEUE_LEN; dev->mtu = PC300_DEF_MTU; - dev->open = cpc_open; - dev->stop = cpc_close; - dev->tx_timeout = cpc_tx_timeout; + dev->netdev_ops = &cpc_netdev_ops; dev->watchdog_timeo = PC300_TX_TIMEOUT; - dev->set_multicast_list = NULL; - dev->set_mac_address = NULL; - dev->change_mtu = cpc_change_mtu; - dev->do_ioctl = cpc_ioctl; if (register_hdlc_device(dev) == 0) { printk("%s: Cyclades-PC300/", dev->name); -- cgit v0.10.2 From 573636cbafeba88f7c88832ae053dafe265bf94b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Apr 2009 04:52:48 -0700 Subject: [PATCH] net: remove superfluous call to synchronize_net() inet_register_protosw() function is responsible for adding a new inet protocol into a global table (inetsw[]) that is used with RCU rules. As soon as the store of the pointer is done, other cpus might see this new protocol in inetsw[], so we have to make sure new protocol is ready for use. All pending memory updates should thus be committed to memory before setting the pointer. This is correctly done using rcu_assign_pointer() synchronize_net() is typically used at unregister time, after unsetting the pointer, to make sure no other cpu is still using the object we want to dismantle. Using it at register time is only adding an artificial delay that could hide a real bug, and this bug could popup if/when synchronize_rcu() can proceed faster than now. This saves about 13 ms on boot time on a HZ=1000 8 cpus machine ;) (4 calls to inet_register_protosw(), and about 3200 us per call) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 7f03373..1706896 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1003,8 +1003,6 @@ void inet_register_protosw(struct inet_protosw *p) out: spin_unlock_bh(&inetsw_lock); - synchronize_net(); - return; out_permanent: -- cgit v0.10.2 From 7fe624f5607ed98de0034adf130e857474dffc2b Mon Sep 17 00:00:00 2001 From: Andrew Gallatin Date: Fri, 17 Apr 2009 15:45:15 -0700 Subject: myri10ge: fix compile error A compilation error snuck into 2d90b0aa3bc484189940444bcddcbe0ebbb53af5 due to an over-zealous indent script removing spaces around array initialization ellipsis. The attached patch fixes the myri10ge compilation in net-next. Signed-off-by: Andrew Gallatin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 291944d..140794a 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -269,7 +269,7 @@ MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name"); #define MYRI10GE_MAX_BOARDS 8 static char *myri10ge_fw_names[MYRI10GE_MAX_BOARDS] = - {[0...(MYRI10GE_MAX_BOARDS - 1)] = NULL }; + {[0 ... (MYRI10GE_MAX_BOARDS - 1)] = NULL }; module_param_array_named(myri10ge_fw_names, myri10ge_fw_names, charp, NULL, 0444); MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image names per board"); -- cgit v0.10.2 From 3ef8e4e9e4d18910cd03dcd481a5dced437b83cf Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Sun, 19 Apr 2009 18:42:58 -0700 Subject: iseries_veth: fix build breakage Reported-by: Stephen Rothwell Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 264654d..e44215c 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1077,7 +1077,7 @@ static struct net_device *veth_probe_one(int vlan, memcpy(&port->mac_addr, mac_addr, ETH_ALEN); - dev->netdev = &veth_netdev_ops; + dev->netdev_ops = &veth_netdev_ops; SET_ETHTOOL_OPS(dev, &ops); SET_NETDEV_DEV(dev, vdev); -- cgit v0.10.2 From 5438646724c34c2180664a57f862a1da8dd21db1 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 17 Apr 2009 20:44:27 +0000 Subject: ixgbe: fix link down initial state As reported by Andrew Lutomirski All the intel wired ethernet drivers were calling netif_carrier_off and netif_stop_queue (or variants) before calling register_netdevice This is incorrect behavior as was pointed out by davem, and causes ifconfig and friends to report a strange state before first link after the driver was loaded, since without a netif_carrier_off, the stack assumes carrier_on, but before register_netdev, netlink messages are not sent out telling link state. This apparently confused *some* versions of networkmanager. Signed-off-by: Jesse Brandeburg Reported-by: Andrew Lutomirski Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 0d9a3ac..d5d9589 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3459,6 +3459,8 @@ static int ixgbe_open(struct net_device *netdev) if (test_bit(__IXGBE_TESTING, &adapter->state)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = ixgbe_setup_all_tx_resources(adapter); if (err) @@ -4772,13 +4774,14 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* reset the hardware with the new settings */ hw->mac.ops.start_hw(hw); - netif_carrier_off(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; -- cgit v0.10.2 From 3a6d1bc4163fee27c312184d5f1a9cc1e110d300 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 17 Apr 2009 20:44:29 +0000 Subject: ixgb: fix link down initial state As reported by Andrew Lutomirski All the intel wired ethernet drivers were calling netif_carrier_off and netif_stop_queue (or variants) before calling register_netdevice This is incorrect behavior as was pointed out by davem, and causes ifconfig and friends to report a strange state before first link after the driver was loaded, since without a netif_carrier_off, the stack assumes carrier_on, but before register_netdev, netlink messages are not sent out telling link state. This apparently confused *some* versions of networkmanager. in addition this driver appeared to need a netif_start_queue at the end of open. Signed-off-by: Jesse Brandeburg Reported-by: Andrew Lutomirski Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 4a0826b..ff741ca 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -471,10 +471,8 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_register; - /* we're going to reset, so assume we have no link for now */ - + /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); - netif_stop_queue(netdev); DPRINTK(PROBE, INFO, "Intel(R) PRO/10GbE Network Connection\n"); ixgb_check_options(adapter); @@ -592,6 +590,8 @@ ixgb_open(struct net_device *netdev) if (err) goto err_setup_tx; + netif_carrier_off(netdev); + /* allocate receive descriptors */ err = ixgb_setup_rx_resources(adapter); @@ -602,6 +602,8 @@ ixgb_open(struct net_device *netdev) if (err) goto err_up; + netif_start_queue(netdev); + return 0; err_up: -- cgit v0.10.2 From b168dfc51604ec293db16dc4d558043585578a2d Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 17 Apr 2009 20:44:32 +0000 Subject: igb: fix link down inital state As reported by Andrew Lutomirski All the intel wired ethernet drivers were calling netif_carrier_off and netif_stop_queue (or variants) before calling register_netdevice This is incorrect behavior as was pointed out by davem, and causes ifconfig and friends to report a strange state before first link after the driver was loaded, since without a netif_carrier_off, the stack assumes carrier_on, but before register_netdev, netlink messages are not sent out telling link state. This apparently confused *some* versions of networkmanager. Signed-off-by: Jesse Brandeburg Reported-by: Andrew Lutomirski Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 08c8014..ceaa585 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1442,15 +1442,14 @@ static int __devinit igb_probe(struct pci_dev *pdev, * driver. */ igb_get_hw_control(adapter); - /* tell the stack to leave us alone until igb_open() is called */ - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + #ifdef CONFIG_IGB_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IGB_FLAG_DCA_ENABLED; @@ -1699,6 +1698,8 @@ static int igb_open(struct net_device *netdev) if (test_bit(__IGB_TESTING, &adapter->state)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = igb_setup_all_tx_resources(adapter); if (err) -- cgit v0.10.2 From 9c563d20671e5fbe3045fd79c18b306ccb77b0b6 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 17 Apr 2009 20:44:34 +0000 Subject: e1000e: indicate link down at load As reported by Andrew Lutomirski All the intel wired ethernet drivers were calling netif_carrier_off and netif_stop_queue (or variants) before calling register_netdevice This is incorrect behavior as was pointed out by davem, and causes ifconfig and friends to report a strange state before first link after the driver was loaded, since without a netif_carrier_off, the stack assumes carrier_on, but before register_netdev, netlink messages are not sent out telling link state. This apparently confused *some* versions of networkmanager. Andy tested this for e1000e and confirmed it was working for him. see thread: http://marc.info/?l=linux-netdev&m=123946479705636&w=2 Signed-off-by: Jesse Brandeburg Tested-by: Andy Lutomirski Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 1693ed1..c0ff550 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3072,6 +3072,8 @@ static int e1000_open(struct net_device *netdev) if (test_bit(__E1000_TESTING, &adapter->state)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = e1000e_setup_tx_resources(adapter); if (err) @@ -5037,15 +5039,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (!(adapter->flags & FLAG_HAS_AMT)) e1000_get_hw_control(adapter); - /* tell the stack to leave us alone until e1000_open() is called */ - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + e1000_print_device_info(adapter); return 0; -- cgit v0.10.2 From eb62efd287fe6e12d18083287e38e4a811c28256 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 17 Apr 2009 20:44:36 +0000 Subject: e1000: init link state correctly As reported by Andrew Lutomirski All the intel wired ethernet drivers were calling netif_carrier_off and netif_stop_queue (or variants) before calling register_netdevice This is incorrect behavior as was pointed out by davem, and causes ifconfig and friends to report a strange state before first link after the driver was loaded. This apparently confused *some* versions of networkmanager. Andy tested this for e1000e and confirmed it was working for him. Signed-off-by: Jesse Brandeburg Reported-by: Andrew Lutomirski Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ef12931..9bdcf4d 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1234,15 +1234,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev, !e1000_check_mng_mode(hw)) e1000_get_hw_control(adapter); - /* tell the stack to leave us alone until e1000_open() is called */ - netif_carrier_off(netdev); - netif_stop_queue(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n"); cards_found++; @@ -1441,6 +1440,8 @@ static int e1000_open(struct net_device *netdev) if (test_bit(__E1000_TESTING, &adapter->flags)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = e1000_setup_all_tx_resources(adapter); if (err) -- cgit v0.10.2 From 7eebb0b28f755e297d355a205bb04945b256db6b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Apr 2009 22:03:10 +0000 Subject: loopback: packet drops accounting We can in some situations drop packets in netif_rx() loopback driver does not report these (unlikely) drops to its stats, and incorrectly change packets/bytes counts. After this patch applied, "ifconfig lo" can reports these drops as in : # ifconfig lo lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:692562900 errors:3228 dropped:3228 overruns:0 frame:0 TX packets:692562900 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:2865674174 (2.6 GiB) TX bytes:2865674174 (2.6 GiB) I initialy chose to reflect those errors only in tx_dropped/tx_errors, but David convinced me that it was really RX errors, as loopback_xmit() really starts a RX process. (calling eth_type_trans() for example, that itself pulls the ethernet header) These errors are accounted in rx_dropped/rx_errors. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b7d438a..6f71157 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -62,6 +62,7 @@ struct pcpu_lstats { unsigned long packets; unsigned long bytes; + unsigned long drops; }; /* @@ -71,18 +72,22 @@ struct pcpu_lstats { static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { struct pcpu_lstats *pcpu_lstats, *lb_stats; + int len; skb_orphan(skb); - skb->protocol = eth_type_trans(skb,dev); + skb->protocol = eth_type_trans(skb, dev); /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = dev->ml_priv; lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); - lb_stats->bytes += skb->len; - lb_stats->packets++; - netif_rx(skb); + len = skb->len; + if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { + lb_stats->bytes += len; + lb_stats->packets++; + } else + lb_stats->drops++; return 0; } @@ -93,6 +98,7 @@ static struct net_device_stats *loopback_get_stats(struct net_device *dev) struct net_device_stats *stats = &dev->stats; unsigned long bytes = 0; unsigned long packets = 0; + unsigned long drops = 0; int i; pcpu_lstats = dev->ml_priv; @@ -102,11 +108,14 @@ static struct net_device_stats *loopback_get_stats(struct net_device *dev) lb_stats = per_cpu_ptr(pcpu_lstats, i); bytes += lb_stats->bytes; packets += lb_stats->packets; + drops += lb_stats->drops; } stats->rx_packets = packets; stats->tx_packets = packets; - stats->rx_bytes = bytes; - stats->tx_bytes = bytes; + stats->rx_dropped = drops; + stats->rx_errors = drops; + stats->rx_bytes = bytes; + stats->tx_bytes = bytes; return stats; } -- cgit v0.10.2 From a0f82f64e26929776c58a5c93c2ecb38e3d82815 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 19 Apr 2009 09:43:48 +0000 Subject: syncookies: remove last_synq_overflow from struct tcp_sock last_synq_overflow eats 4 or 8 bytes in struct tcp_sock, even though it is only used when a listening sockets syn queue is full. We can (ab)use rx_opt.ts_recent_stamp to store the same information; it is not used otherwise as long as a socket is in listen state. Move linger2 around to avoid splitting struct mtu_probe across cacheline boundary on 32 bit arches. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 9d5078b..8afac76 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -377,7 +377,7 @@ struct tcp_sock { unsigned int keepalive_time; /* time before keep alive takes place */ unsigned int keepalive_intvl; /* time interval between keep alive probes */ - unsigned long last_synq_overflow; + int linger2; /* Receiver side RTT estimation */ struct { @@ -406,8 +406,6 @@ struct tcp_sock { /* TCP MD5 Signagure Option information */ struct tcp_md5sig_info *md5sig_info; #endif - - int linger2; }; static inline struct tcp_sock *tcp_sk(const struct sock *sk) diff --git a/include/net/tcp.h b/include/net/tcp.h index 1b94b9b..b55b489 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -265,6 +265,19 @@ static inline int tcp_too_many_orphans(struct sock *sk, int num) atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]); } +/* syncookies: remember time of last synqueue overflow */ +static inline void tcp_synq_overflow(struct sock *sk) +{ + tcp_sk(sk)->rx_opt.ts_recent_stamp = jiffies; +} + +/* syncookies: no recent synqueue overflow on this listening socket? */ +static inline int tcp_synq_no_recent_overflow(const struct sock *sk) +{ + unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp; + return time_after(jiffies, last_overflow + TCP_TIMEOUT_INIT); +} + extern struct proto tcp_prot; #define TCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.tcp_statistics, field) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index b35a950..cd2b97f 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -161,13 +161,12 @@ static __u16 const msstab[] = { */ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) { - struct tcp_sock *tp = tcp_sk(sk); const struct iphdr *iph = ip_hdr(skb); const struct tcphdr *th = tcp_hdr(skb); int mssind; const __u16 mss = *mssp; - tp->last_synq_overflow = jiffies; + tcp_synq_overflow(sk); /* XXX sort msstab[] by probability? Binary search? */ for (mssind = 0; mss > msstab[mssind + 1]; mssind++) @@ -268,7 +267,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, if (!sysctl_tcp_syncookies || !th->ack) goto out; - if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) || + if (tcp_synq_no_recent_overflow(sk) || (mss = cookie_check(skb, cookie)) == 0) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); goto out; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 711175e..8c25139 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -131,7 +131,7 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) int mssind; const __u16 mss = *mssp; - tcp_sk(sk)->last_synq_overflow = jiffies; + tcp_synq_overflow(sk); for (mssind = 0; mss > msstab[mssind + 1]; mssind++) ; @@ -175,7 +175,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (!sysctl_tcp_syncookies || !th->ack) goto out; - if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) || + if (tcp_synq_no_recent_overflow(sk) || (mss = cookie_check(skb, cookie)) == 0) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); goto out; -- cgit v0.10.2 From 624f8e5082efd0348ccf7e3d3f4bfc41efead26c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 20 Apr 2009 06:55:01 +0000 Subject: tg3: Allow screaming interrupt detection The tg3 driver's ISR is coded to accept interrupts as its own if the status block tag does not equal the last tag the driver has seen. The last_tag field is updated from tg3_poll. In a screaming interrupt situation from another device sharing tg3's IRQ, tg3_poll does not get a chance to be called, so the last_tag will always be out of sync with the status block tag. Consequently, the driver will continually declare the screaming interrupts as its own, thus thwarting the screaming interrupt detection logic. This patch solves the problem by creating a new last_irq_tag member and recording the status block tag in the ISR. The ISR then checks the last_irq_tag for interrupt ownership. Many thanks to John Marvin for the detailed bug report and analysis and Michael Chan for the bugfix. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Tested-by: John Marvin Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 201be42..e4fa02c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4656,6 +4656,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) * so we must read it before checking for more work. */ tp->last_tag = sblk->status_tag; + tp->last_irq_tag = tp->last_tag; rmb(); } else sblk->status &= ~SD_STATUS_UPDATED; @@ -4811,7 +4812,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * Reading the PCI State register will confirm whether the * interrupt is ours and will flush the status block. */ - if (unlikely(sblk->status_tag == tp->last_tag)) { + if (unlikely(sblk->status_tag == tp->last_irq_tag)) { if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; @@ -4831,18 +4832,22 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * excessive spurious interrupts can be worse in some cases. */ tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + + /* + * In a shared interrupt configuration, sometimes other devices' + * interrupts will scream. We record the current status tag here + * so that the above check can report that the screaming interrupts + * are unhandled. Eventually they will be silenced. + */ + tp->last_irq_tag = sblk->status_tag; + if (tg3_irq_sync(tp)) goto out; - if (napi_schedule_prep(&tp->napi)) { - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - /* Update last_tag to mark that this status has been - * seen. Because interrupt may be shared, we may be - * racing with tg3_poll(), so only update last_tag - * if tg3_poll() is not scheduled. - */ - tp->last_tag = sblk->status_tag; - __napi_schedule(&tp->napi); - } + + prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + + napi_schedule(&tp->napi); + out: return IRQ_RETVAL(handled); } @@ -6156,6 +6161,7 @@ static int tg3_chip_reset(struct tg3 *tp) tp->hw_status->status_tag = 0; } tp->last_tag = 0; + tp->last_irq_tag = 0; smp_mb(); synchronize_irq(tp->pdev->irq); @@ -7138,7 +7144,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(100); tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); - tp->last_tag = 0; if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index cb4c62a..ca71a49 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2501,6 +2501,7 @@ struct tg3 { struct tg3_hw_status *hw_status; dma_addr_t status_mapping; u32 last_tag; + u32 last_irq_tag; u32 msg_enable; -- cgit v0.10.2 From df259d8cba7d7880dc04d34c7a6e0ce15fbc9644 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 20 Apr 2009 06:57:14 +0000 Subject: tg3: Handle NVRAM absent cases Some 57780 ASIC revision parts do not have NVRAM. Code the driver so that it is tolerant of this configuration. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e4fa02c..9b04954 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8544,6 +8544,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u32 i, offset, len, b_offset, b_count; __be32 val; + if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + return -EINVAL; + if (tp->link_config.phy_is_low_power) return -EAGAIN; @@ -8609,7 +8612,8 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (tp->link_config.phy_is_low_power) return -EAGAIN; - if (eeprom->magic != TG3_EEPROM_MAGIC) + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + eeprom->magic != TG3_EEPROM_MAGIC) return -EINVAL; offset = eeprom->offset; @@ -9206,6 +9210,9 @@ static int tg3_test_nvram(struct tg3 *tp) __be32 *buf; int i, j, k, err = 0, size; + if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + return 0; + if (tg3_nvram_read(tp, 0, &magic) != 0) return -EIO; @@ -10188,7 +10195,8 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp) { u32 val; - if (tg3_nvram_read(tp, 0, &val) != 0) + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + tg3_nvram_read(tp, 0, &val) != 0) return; /* Selfboot format */ @@ -10570,6 +10578,7 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) } break; default: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; return; } @@ -11370,7 +11379,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp) unsigned int i; u32 magic; - if (tg3_nvram_read(tp, 0x0, &magic)) + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + tg3_nvram_read(tp, 0x0, &magic)) goto out_not_found; if (magic == TG3_EEPROM_MAGIC) { @@ -11462,6 +11472,15 @@ static void __devinit tg3_read_partno(struct tg3 *tp) out_not_found: if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) strcpy(tp->board_part_number, "BCM95906"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57780) + strcpy(tp->board_part_number, "BCM57780"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57760) + strcpy(tp->board_part_number, "BCM57760"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790) + strcpy(tp->board_part_number, "BCM57790"); else strcpy(tp->board_part_number, "none"); } @@ -11672,6 +11691,14 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) { u32 val; + if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) { + tp->fw_ver[0] = 's'; + tp->fw_ver[1] = 'b'; + tp->fw_ver[2] = '\0'; + + return; + } + if (tg3_nvram_read(tp, 0, &val)) return; @@ -12459,7 +12486,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) } if (!addr_ok) { /* Next, try NVRAM. */ - if (!tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && + if (!(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) && + !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) { memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2); memcpy(&dev->dev_addr[2], (char *)&lo, sizeof(lo)); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index ca71a49..afbabf2 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2636,6 +2636,7 @@ struct tg3 { #define TG3_FLG3_CLKREQ_BUG 0x00000800 #define TG3_FLG3_PHY_ENABLE_APD 0x00001000 #define TG3_FLG3_5755_PLUS 0x00002000 +#define TG3_FLG3_NO_NVRAM 0x00004000 struct timer_list timer; u16 timer_counter; -- cgit v0.10.2 From 33466d938f43ab65312466ba5472b9c6ee200cce Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 20 Apr 2009 06:57:41 +0000 Subject: tg3: Prevent send BD corruption On rare occasions, send BD corruptions can occur. This patch fixes the problem by increasing the L1 entry threshold to 4 milliseconds. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9b04954..ed7a86d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6717,6 +6717,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3_CPMU_HST_ACC, val); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { + val = tr32(PCIE_PWR_MGMT_THRESH) & ~PCIE_PWR_MGMT_L1_THRESH_MSK; + val |= PCIE_PWR_MGMT_EXT_ASPM_TMR_EN | + PCIE_PWR_MGMT_L1_THRESH_4MS; + tw32(PCIE_PWR_MGMT_THRESH, val); + } + /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. But do not set this on PCI Express diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index afbabf2..f1016cb 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1697,6 +1697,8 @@ #define PCIE_PWR_MGMT_THRESH 0x00007d28 #define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00 +#define PCIE_PWR_MGMT_L1_THRESH_4MS 0x0000ff00 +#define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN 0x01000000 /* OTP bit definitions */ -- cgit v0.10.2 From 8d519ab2866c92f5d722085492a124f016f601aa Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 20 Apr 2009 06:58:01 +0000 Subject: tg3: Allow 5761 WOL and LED fixes to 5761S too The 5761 WOL and LED fixes used the PCI device ID to as the activation key. The 5761S requires the same process. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ed7a86d..c5c3d28 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1950,7 +1950,8 @@ static void tg3_frob_aux_power(struct tg3 *tp) GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1), 100); - } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) { /* The 5761 non-e device swaps GPIO 0 and GPIO 2. */ u32 grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | @@ -12183,7 +12184,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; - if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) { /* Turn off the debug UART. */ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) -- cgit v0.10.2 From 9cf74ebb634fe79587cf9a1d5ff971391dd12e1b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 20 Apr 2009 06:58:27 +0000 Subject: tg3: Limit CLKREQ fix to A[01] of 57780 asic rev This patch restricts the CLKREQ bugfix to the A0 and A1 revisions of 57780 ASIC rev chips. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c5c3d28..0501fb4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11992,7 +11992,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_57780_A1) tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; } } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index f1016cb..b3347c4 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -95,6 +95,8 @@ #define CHIPREV_ID_5752_A1 0x6001 #define CHIPREV_ID_5714_A2 0x9002 #define CHIPREV_ID_5906_A1 0xc001 +#define CHIPREV_ID_57780_A0 0x57780000 +#define CHIPREV_ID_57780_A1 0x57780001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 -- cgit v0.10.2 From daba2a631d2b7831b6a021b36d61314a9153526e Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 20 Apr 2009 06:58:52 +0000 Subject: tg3: Restore LAA sooner in shutdown sequence After a shutdown reset, the LAA needs to be restored before posting the post-reset signature in shared memory. If the LAA is not restored before then, the bootcode will assume the factory default MAC address and WOL will not work with the LAA. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0501fb4..f2b7ff8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2456,8 +2456,6 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } - __tg3_set_mac_addr(tp, 0); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 val; @@ -6357,6 +6355,8 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent) tg3_abort_hw(tp, silent); err = tg3_chip_reset(tp); + __tg3_set_mac_addr(tp, 0); + tg3_write_sig_legacy(tp, kind); tg3_write_sig_post_reset(tp, kind); -- cgit v0.10.2 From bb9e63e27117b469a151c61fb0045a8ec4cced5d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 20 Apr 2009 07:13:31 +0000 Subject: tg3: Update version to 3.99 This patch updates the tg3 version to 3.99. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f2b7ff8..eb65e25 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.98" -#define DRV_MODULE_RELDATE "February 25, 2009" +#define DRV_MODULE_VERSION "3.99" +#define DRV_MODULE_RELDATE "April 20, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v0.10.2 From 03ad032bb78b2732b607ed198e951240e1d21e59 Mon Sep 17 00:00:00 2001 From: Peter Holik Date: Sat, 18 Apr 2009 07:24:17 +0000 Subject: export usbnet_get_ethernet_addr from usbnet and fixed cdc_ether.c because of using the same function get_ethernet_addr as cdc_ether.c i export usbnet_get_ethernet_addr from usbnet and fixed cdc_ether (suggested by Oliver Neukum). Signed-off-by: Peter Holik Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 55e8ecc..01fd528 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -389,36 +388,6 @@ static void cdc_status(struct usbnet *dev, struct urb *urb) } } -static u8 nibble(unsigned char c) -{ - if (likely(isdigit(c))) - return c - '0'; - c = toupper(c); - if (likely(isxdigit(c))) - return 10 + c - 'A'; - return 0; -} - -static inline int -get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) -{ - int tmp, i; - unsigned char buf [13]; - - tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); - if (tmp != 12) { - dev_dbg(&dev->udev->dev, - "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); - if (tmp >= 0) - tmp = -EINVAL; - return tmp; - } - for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net->dev_addr [i] = - (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); - return 0; -} - static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) { int status; @@ -428,7 +397,7 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) if (status < 0) return status; - status = get_ethernet_addr(dev, info->ether); + status = usbnet_get_ethernet_addr(dev, info->ether->iMACAddress); if (status < 0) { usb_set_intfdata(info->data, NULL); usb_driver_release_interface(driver_of(intf), info->data); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 2b8b903..c94de62 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,36 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usbnet_get_endpoints); +static u8 nibble(unsigned char c) +{ + if (likely(isdigit(c))) + return c - '0'; + c = toupper(c); + if (likely(isxdigit(c))) + return 10 + c - 'A'; + return 0; +} + +int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) +{ + int tmp, i; + unsigned char buf [13]; + + tmp = usb_string(dev->udev, iMACAddress, buf, sizeof buf); + if (tmp != 12) { + dev_dbg(&dev->udev->dev, + "bad MAC string %d fetch, %d\n", iMACAddress, tmp); + if (tmp >= 0) + tmp = -EINVAL; + return tmp; + } + for (i = tmp = 0; i < 6; i++, tmp += 2) + dev->net->dev_addr [i] = + (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); + return 0; +} +EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); + static void intr_complete (struct urb *urb); static int init_status (struct usbnet *dev, struct usb_interface *intf) diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 36fabb9..5d44059 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -183,6 +183,7 @@ extern void usbnet_tx_timeout (struct net_device *net); extern int usbnet_change_mtu (struct net_device *net, int new_mtu); extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *); +extern int usbnet_get_ethernet_addr(struct usbnet *, int); extern void usbnet_defer_kevent (struct usbnet *, int); extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); extern void usbnet_unlink_rx_urbs(struct usbnet *); -- cgit v0.10.2 From 4510d7cb8b4e7d389652b8a4f89fad469a5ecc92 Mon Sep 17 00:00:00 2001 From: Peter Holik Date: Sat, 18 Apr 2009 07:24:21 +0000 Subject: usb driver for intellon int51x1 based PLC like devolo dlan duo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit usb driver for intellon int51x1 based PLC like devolo dlan duo with improvements suggested by the guys of the mailinglist: - name and prefix with int51x1 (Florian Fainelli) - use conversion functions cpu_to_le16 / le16_to_cpu (Oliver Neukum) - use pskb_may_pull instead of skb->len (Ilpo Järvinen) - better code in tx_fixup (Ilpo Järvinen) - use gotos for error handling (Ilpo Järvinen) - better description (Jon Smirl) Signed-off-by: Peter Holik Signed-off-by: David S. Miller diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 8ee2103..e00b5b1 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -345,4 +345,12 @@ config USB_HSO To compile this driver as a module, choose M here: the module will be called hso. +config USB_NET_INT51X1 + tristate "Intellon PLC based usb adapter" + depends on USB_USBNET + help + Choose this option if you're using a 14Mb USB-based PLC + (Powerline Communications) solution with an Intellon + INT51x1/INT5200 chip, like the "devolo dLan duo". + endmenu diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index 88a87eeb3..f4402a0 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -19,4 +19,5 @@ obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o obj-$(CONFIG_USB_USBNET) += usbnet.o +obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c new file mode 100644 index 0000000..55cf708 --- /dev/null +++ b/drivers/net/usb/int51x1.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2009 Peter Holik + * + * Intellon usb PLC (Powerline Communications) usb net driver + * + * http://www.tandel.be/downloads/INT51X1_Datasheet.pdf + * + * Based on the work of Jan 'RedBully' Seiffert + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define INT51X1_VENDOR_ID 0x09e1 +#define INT51X1_PRODUCT_ID 0x5121 + +#define INT51X1_HEADER_SIZE 2 /* 2 byte header */ + +#define PACKET_TYPE_PROMISCUOUS (1 << 0) +#define PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ +#define PACKET_TYPE_DIRECTED (1 << 2) +#define PACKET_TYPE_BROADCAST (1 << 3) +#define PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ + +#define SET_ETHERNET_PACKET_FILTER 0x43 + +static int int51x1_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + int len; + + if (!(pskb_may_pull(skb, INT51X1_HEADER_SIZE))) { + deverr(dev, "unexpected tiny rx frame"); + return 0; + } + + len = le16_to_cpu(*(__le16 *)&skb->data[skb->len - 2]); + + skb_trim(skb, len); + + return 1; +} + +static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags) +{ + int pack_len = skb->len; + int pack_with_header_len = pack_len + INT51X1_HEADER_SIZE; + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + int need_tail = 0; + __le16 *len; + + /* if packet and our header is smaler than 64 pad to 64 (+ ZLP) */ + if ((pack_with_header_len) < dev->maxpacket) + need_tail = dev->maxpacket - pack_with_header_len + 1; + /* + * usbnet would send a ZLP if packetlength mod urbsize == 0 for us, + * but we need to know ourself, because this would add to the length + * we send down to the device... + */ + else if (!(pack_with_header_len % dev->maxpacket)) + need_tail = 1; + + if (!skb_cloned(skb) && + (headroom + tailroom >= need_tail + INT51X1_HEADER_SIZE)) { + if (headroom < INT51X1_HEADER_SIZE || tailroom < need_tail) { + skb->data = memmove(skb->head + INT51X1_HEADER_SIZE, + skb->data, skb->len); + skb_set_tail_pointer(skb, skb->len); + } + } else { + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, + INT51X1_HEADER_SIZE, + need_tail, + flags); + dev_kfree_skb_any(skb); + if (!skb2) + return NULL; + skb = skb2; + } + + pack_len += need_tail; + pack_len &= 0x07ff; + + len = (__le16 *) __skb_push(skb, INT51X1_HEADER_SIZE); + *len = cpu_to_le16(pack_len); + + if(need_tail) + memset(__skb_put(skb, need_tail), 0, need_tail); + + return skb; +} + +static void int51x1_async_cmd_callback(struct urb *urb) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; + + if (status < 0) + dev_warn(&urb->dev->dev, "async callback failed with %d\n", status); + + kfree(req); + usb_free_urb(urb); +} + +static void int51x1_set_multicast(struct net_device *netdev) +{ + struct usb_ctrlrequest *req; + int status; + struct urb *urb; + struct usbnet *dev = netdev_priv(netdev); + u16 filter = PACKET_TYPE_DIRECTED | PACKET_TYPE_BROADCAST; + + if (netdev->flags & IFF_PROMISC) { + /* do not expect to see traffic of other PLCs */ + filter |= PACKET_TYPE_PROMISCUOUS; + devinfo(dev, "promiscuous mode enabled"); + } else if (netdev->mc_count || + (netdev->flags & IFF_ALLMULTI)) { + filter |= PACKET_TYPE_ALL_MULTICAST; + devdbg(dev, "receive all multicast enabled"); + } else { + /* ~PROMISCUOUS, ~MULTICAST */ + devdbg(dev, "receive own packets only"); + } + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + devwarn(dev, "Error allocating URB"); + return; + } + + req = kmalloc(sizeof(*req), GFP_ATOMIC); + if (!req) { + devwarn(dev, "Error allocating control msg"); + goto out; + } + + req->bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + req->bRequest = SET_ETHERNET_PACKET_FILTER; + req->wValue = cpu_to_le16(filter); + req->wIndex = 0; + req->wLength = 0; + + usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), + (void *)req, NULL, 0, + int51x1_async_cmd_callback, + (void *)req); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + devwarn(dev, "Error submitting control msg, sts=%d", status); + goto out1; + } + return; +out1: + kfree(req); +out: + usb_free_urb(urb); +} + +static const struct net_device_ops int51x1_netdev_ops = { + .ndo_open = usbnet_open, + .ndo_stop = usbnet_stop, + .ndo_start_xmit = usbnet_start_xmit, + .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_change_mtu = usbnet_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = int51x1_set_multicast, +}; + +static int int51x1_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int status = usbnet_get_ethernet_addr(dev, 3); + + if (status) + return status; + + dev->net->hard_header_len += INT51X1_HEADER_SIZE; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; + dev->net->netdev_ops = &int51x1_netdev_ops; + + return usbnet_get_endpoints(dev, intf); +} + +static const struct driver_info int51x1_info = { + .description = "Intellon usb powerline adapter", + .bind = int51x1_bind, + .rx_fixup = int51x1_rx_fixup, + .tx_fixup = int51x1_tx_fixup, + .in = 1, + .out = 2, + .flags = FLAG_ETHER, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(INT51X1_VENDOR_ID, INT51X1_PRODUCT_ID), + .driver_info = (unsigned long) &int51x1_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver int51x1_driver = { + .name = "int51x1", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init int51x1_init(void) +{ + return usb_register(&int51x1_driver); +} +module_init(int51x1_init); + +static void __exit int51x1_exit(void) +{ + usb_deregister(&int51x1_driver); +} +module_exit(int51x1_exit); + +MODULE_AUTHOR("Peter Holik"); +MODULE_DESCRIPTION("Intellon usb powerline adapter"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From b1b67dd45a6b629eb41553856805aaa1614fbb83 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 20 Apr 2009 04:49:28 +0000 Subject: net: factor out ethtool invocation of vlan/macvlan drivers Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 214a8cf..329cd50 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -374,36 +374,20 @@ static void macvlan_ethtool_get_drvinfo(struct net_device *dev, static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); - struct net_device *lowerdev = vlan->lowerdev; - - if (lowerdev->ethtool_ops == NULL || - lowerdev->ethtool_ops->get_rx_csum == NULL) - return 0; - return lowerdev->ethtool_ops->get_rx_csum(lowerdev); + return dev_ethtool_get_rx_csum(vlan->lowerdev); } static int macvlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { const struct macvlan_dev *vlan = netdev_priv(dev); - struct net_device *lowerdev = vlan->lowerdev; - - if (!lowerdev->ethtool_ops || - !lowerdev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - - return lowerdev->ethtool_ops->get_settings(lowerdev, cmd); + return dev_ethtool_get_settings(vlan->lowerdev, cmd); } static u32 macvlan_ethtool_get_flags(struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); - struct net_device *lowerdev = vlan->lowerdev; - - if (!lowerdev->ethtool_ops || - !lowerdev->ethtool_ops->get_flags) - return 0; - return lowerdev->ethtool_ops->get_flags(lowerdev); + return dev_ethtool_get_flags(vlan->lowerdev); } static const struct ethtool_ops macvlan_ethtool_ops = { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 54db3eb..3116745 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -42,6 +42,7 @@ #include #include +#include #include #include #ifdef CONFIG_DCB @@ -49,7 +50,6 @@ #endif struct vlan_group; -struct ethtool_ops; struct netpoll_info; /* 802.11 specific */ struct wireless_dev; @@ -1906,6 +1906,28 @@ static inline int skb_bond_should_drop(struct sk_buff *skb) } extern struct pernet_operations __net_initdata loopback_net_ops; + +static inline int dev_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) + return -EOPNOTSUPP; + return dev->ethtool_ops->get_settings(dev, cmd); +} + +static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev) +{ + if (!dev->ethtool_ops || !dev->ethtool_ops->get_rx_csum) + return 0; + return dev->ethtool_ops->get_rx_csum(dev); +} + +static inline u32 dev_ethtool_get_flags(struct net_device *dev) +{ + if (!dev->ethtool_ops || !dev->ethtool_ops->get_flags) + return 0; + return dev->ethtool_ops->get_flags(dev); +} #endif /* __KERNEL__ */ #endif /* _LINUX_DEV_H */ diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6b09213..04dc8c8 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -666,13 +666,7 @@ static int vlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); - struct net_device *real_dev = vlan->real_dev; - - if (!real_dev->ethtool_ops || - !real_dev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - - return real_dev->ethtool_ops->get_settings(real_dev, cmd); + return dev_ethtool_get_settings(vlan->real_dev, cmd); } static void vlan_ethtool_get_drvinfo(struct net_device *dev, @@ -686,24 +680,13 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev, static u32 vlan_ethtool_get_rx_csum(struct net_device *dev) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); - struct net_device *real_dev = vlan->real_dev; - - if (real_dev->ethtool_ops == NULL || - real_dev->ethtool_ops->get_rx_csum == NULL) - return 0; - return real_dev->ethtool_ops->get_rx_csum(real_dev); + return dev_ethtool_get_rx_csum(vlan->real_dev); } static u32 vlan_ethtool_get_flags(struct net_device *dev) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); - struct net_device *real_dev = vlan->real_dev; - - if (!(real_dev->features & NETIF_F_HW_VLAN_RX) || - real_dev->ethtool_ops == NULL || - real_dev->ethtool_ops->get_flags == NULL) - return 0; - return real_dev->ethtool_ops->get_flags(real_dev); + return dev_ethtool_get_flags(vlan->real_dev); } static const struct ethtool_ops vlan_ethtool_ops = { -- cgit v0.10.2 From d035fbccc4edd2bd69d9314faf03ba832b85a1d7 Mon Sep 17 00:00:00 2001 From: Jianjun Kong Date: Mon, 20 Apr 2009 04:05:34 +0000 Subject: rtl8139: unify the struct's name unify the struct's name of "struct rtl8139_private *np" to "struct rtl8139_private *tp" most of them like this: struct rtl8139_private *tp = netdev_priv(dev); Signed-off-by: Amos Kong Signed-off-by: David S. Miller diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 29df398..00fe130 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2292,11 +2292,11 @@ static int rtl8139_close (struct net_device *dev) other threads or interrupts aren't messing with the 8139. */ static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct rtl8139_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mmio_addr; + struct rtl8139_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; - spin_lock_irq(&np->lock); - if (rtl_chip_info[np->chipset].flags & HasLWake) { + spin_lock_irq(&tp->lock); + if (rtl_chip_info[tp->chipset].flags & HasLWake) { u8 cfg3 = RTL_R8 (Config3); u8 cfg5 = RTL_R8 (Config5); @@ -2317,7 +2317,7 @@ static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (cfg5 & Cfg5_BWF) wol->wolopts |= WAKE_BCAST; } - spin_unlock_irq(&np->lock); + spin_unlock_irq(&tp->lock); } @@ -2326,19 +2326,19 @@ static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) aren't messing with the 8139. */ static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct rtl8139_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mmio_addr; + struct rtl8139_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; u32 support; u8 cfg3, cfg5; - support = ((rtl_chip_info[np->chipset].flags & HasLWake) + support = ((rtl_chip_info[tp->chipset].flags & HasLWake) ? (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST) : 0); if (wol->wolopts & ~support) return -EINVAL; - spin_lock_irq(&np->lock); + spin_lock_irq(&tp->lock); cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic); if (wol->wolopts & WAKE_PHY) cfg3 |= Cfg3_LinkUp; @@ -2359,87 +2359,87 @@ static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & WAKE_BCAST) cfg5 |= Cfg5_BWF; RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */ - spin_unlock_irq(&np->lock); + spin_unlock_irq(&tp->lock); return 0; } static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); - strcpy(info->bus_info, pci_name(np->pci_dev)); - info->regdump_len = np->regs_len; + strcpy(info->bus_info, pci_name(tp->pci_dev)); + info->regdump_len = tp->regs_len; } static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct rtl8139_private *np = netdev_priv(dev); - spin_lock_irq(&np->lock); - mii_ethtool_gset(&np->mii, cmd); - spin_unlock_irq(&np->lock); + struct rtl8139_private *tp = netdev_priv(dev); + spin_lock_irq(&tp->lock); + mii_ethtool_gset(&tp->mii, cmd); + spin_unlock_irq(&tp->lock); return 0; } static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); int rc; - spin_lock_irq(&np->lock); - rc = mii_ethtool_sset(&np->mii, cmd); - spin_unlock_irq(&np->lock); + spin_lock_irq(&tp->lock); + rc = mii_ethtool_sset(&tp->mii, cmd); + spin_unlock_irq(&tp->lock); return rc; } static int rtl8139_nway_reset(struct net_device *dev) { - struct rtl8139_private *np = netdev_priv(dev); - return mii_nway_restart(&np->mii); + struct rtl8139_private *tp = netdev_priv(dev); + return mii_nway_restart(&tp->mii); } static u32 rtl8139_get_link(struct net_device *dev) { - struct rtl8139_private *np = netdev_priv(dev); - return mii_link_ok(&np->mii); + struct rtl8139_private *tp = netdev_priv(dev); + return mii_link_ok(&tp->mii); } static u32 rtl8139_get_msglevel(struct net_device *dev) { - struct rtl8139_private *np = netdev_priv(dev); - return np->msg_enable; + struct rtl8139_private *tp = netdev_priv(dev); + return tp->msg_enable; } static void rtl8139_set_msglevel(struct net_device *dev, u32 datum) { - struct rtl8139_private *np = netdev_priv(dev); - np->msg_enable = datum; + struct rtl8139_private *tp = netdev_priv(dev); + tp->msg_enable = datum; } static int rtl8139_get_regs_len(struct net_device *dev) { - struct rtl8139_private *np; + struct rtl8139_private *tp; /* TODO: we are too slack to do reg dumping for pio, for now */ if (use_io) return 0; - np = netdev_priv(dev); - return np->regs_len; + tp = netdev_priv(dev); + return tp->regs_len; } static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf) { - struct rtl8139_private *np; + struct rtl8139_private *tp; /* TODO: we are too slack to do reg dumping for pio, for now */ if (use_io) return; - np = netdev_priv(dev); + tp = netdev_priv(dev); regs->version = RTL_REGS_VER; - spin_lock_irq(&np->lock); - memcpy_fromio(regbuf, np->mmio_addr, regs->len); - spin_unlock_irq(&np->lock); + spin_lock_irq(&tp->lock); + memcpy_fromio(regbuf, tp->mmio_addr, regs->len); + spin_unlock_irq(&tp->lock); } static int rtl8139_get_sset_count(struct net_device *dev, int sset) @@ -2454,12 +2454,12 @@ static int rtl8139_get_sset_count(struct net_device *dev, int sset) static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); - data[0] = np->xstats.early_rx; - data[1] = np->xstats.tx_buf_mapped; - data[2] = np->xstats.tx_timeouts; - data[3] = np->xstats.rx_lost_in_ring; + data[0] = tp->xstats.early_rx; + data[1] = tp->xstats.tx_buf_mapped; + data[2] = tp->xstats.tx_timeouts; + data[3] = tp->xstats.rx_lost_in_ring; } static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -2486,15 +2486,15 @@ static const struct ethtool_ops rtl8139_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); int rc; if (!netif_running(dev)) return -EINVAL; - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL); - spin_unlock_irq(&np->lock); + spin_lock_irq(&tp->lock); + rc = generic_mii_ioctl(&tp->mii, if_mii(rq), cmd, NULL); + spin_unlock_irq(&tp->lock); return rc; } -- cgit v0.10.2 From 0cededf3ffbb775c3716aa1d246338fdc24b1259 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 17 Apr 2009 12:03:48 +0000 Subject: ucc_geth: Move freeing of TX packets to NAPI context This will make the system alot more responsive while ping flooding the ucc_geth ethernet interface. Also set NAPI weight to 64 as this is a common value. Signed-off-by: Joakim Tjernlund Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index d3f39e8..98f961e 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3216,7 +3216,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) dev->stats.tx_packets++; /* Free the sk buffer associated with this TxBD */ - dev_kfree_skb_irq(ugeth-> + dev_kfree_skb(ugeth-> tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; ugeth->skb_dirtytx[txQ] = @@ -3250,9 +3250,15 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) for (i = 0; i < ug_info->numQueuesRx; i++) howmany += ucc_geth_rx(ugeth, i, budget - howmany); + /* Tx event processing */ + spin_lock(&ugeth->lock); + for (i = 0; i < ug_info->numQueuesTx; i++) + ucc_geth_tx(ugeth->ndev, i); + spin_unlock(&ugeth->lock); + if (howmany < budget) { napi_complete(napi); - setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS); + setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS); } return howmany; @@ -3266,8 +3272,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) struct ucc_geth_info *ug_info; register u32 ucce; register u32 uccm; - register u32 tx_mask; - u8 i; ugeth_vdbg("%s: IN", __func__); @@ -3281,27 +3285,14 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) out_be32(uccf->p_ucce, ucce); /* check for receive events that require processing */ - if (ucce & UCCE_RX_EVENTS) { + if (ucce & (UCCE_RX_EVENTS | UCCE_TX_EVENTS)) { if (napi_schedule_prep(&ugeth->napi)) { - uccm &= ~UCCE_RX_EVENTS; + uccm &= ~(UCCE_RX_EVENTS | UCCE_TX_EVENTS); out_be32(uccf->p_uccm, uccm); __napi_schedule(&ugeth->napi); } } - /* Tx event processing */ - if (ucce & UCCE_TX_EVENTS) { - spin_lock(&ugeth->lock); - tx_mask = UCC_GETH_UCCE_TXB0; - for (i = 0; i < ug_info->numQueuesTx; i++) { - if (ucce & tx_mask) - ucc_geth_tx(dev, i); - ucce &= ~tx_mask; - tx_mask <<= 1; - } - spin_unlock(&ugeth->lock); - } - /* Errors and other events */ if (ucce & UCCE_OTHER) { if (ucce & UCC_GETH_UCCE_BSY) @@ -3734,7 +3725,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->netdev_ops = &ucc_geth_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work); - netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); + netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, 64); dev->mtu = 1500; ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT); diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 2f8ee7c..6027647 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -852,7 +852,6 @@ struct ucc_geth_hardware_statistics { /* Driver definitions */ #define TX_BD_RING_LEN 0x10 #define RX_BD_RING_LEN 0x10 -#define UCC_GETH_DEV_WEIGHT TX_BD_RING_LEN #define TX_RING_MOD_MASK(size) (size-1) #define RX_RING_MOD_MASK(size) (size-1) -- cgit v0.10.2 From 0a1ec07a67bd8b0033dace237249654d015efa21 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 20 Apr 2009 01:25:46 +0000 Subject: net: skb_copy_datagram_const_iovec() There's an skb_copy_datagram_iovec() to copy out of a paged skb, but it modifies the iovec, and does not support starting at an offset in the destination. We want both in tun.c, so let's add the function. It's a carbon copy of skb_copy_datagram_iovec() with enough changes to be annoying. Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5fd3891..af2b21b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1717,6 +1717,11 @@ extern int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, struct iovec *from, int len); +extern int skb_copy_datagram_const_iovec(const struct sk_buff *from, + int offset, + const struct iovec *to, + int to_offset, + int size); extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); extern int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); diff --git a/include/linux/socket.h b/include/linux/socket.h index 421afb4..171b08d 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -318,6 +318,8 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata, extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode); extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); +extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata, + int offset, int len); extern int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr, int __user *ulen); extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); diff --git a/net/core/datagram.c b/net/core/datagram.c index d0de644..4dbb05c 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -339,6 +339,98 @@ fault: } /** + * skb_copy_datagram_const_iovec - Copy a datagram to an iovec. + * @skb: buffer to copy + * @offset: offset in the buffer to start copying from + * @to: io vector to copy to + * @to_offset: offset in the io vector to start copying to + * @len: amount of data to copy from buffer to iovec + * + * Returns 0 or -EFAULT. + * Note: the iovec is not modified during the copy. + */ +int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset, + const struct iovec *to, int to_offset, + int len) +{ + int start = skb_headlen(skb); + int i, copy = start - offset; + + /* Copy header. */ + if (copy > 0) { + if (copy > len) + copy = len; + if (memcpy_toiovecend(to, skb->data + offset, to_offset, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to_offset += copy; + } + + /* Copy paged appendix. Hmm... why does this look so complicated? */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + WARN_ON(start > offset + len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end - offset) > 0) { + int err; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; + + if (copy > len) + copy = len; + vaddr = kmap(page); + err = memcpy_toiovecend(to, vaddr + frag->page_offset + + offset - start, to_offset, copy); + kunmap(page); + if (err) + goto fault; + if (!(len -= copy)) + return 0; + offset += copy; + to_offset += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list = skb_shinfo(skb)->frag_list; + + for (; list; list = list->next) { + int end; + + WARN_ON(start > offset + len); + + end = start + list->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_const_iovec(list, + offset - start, + to, to_offset, + copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to_offset += copy; + } + start = end; + } + } + if (!len) + return 0; + +fault: + return -EFAULT; +} +EXPORT_SYMBOL(skb_copy_datagram_const_iovec); + +/** * skb_copy_datagram_from_iovec - Copy a datagram from an iovec. * @skb: buffer to copy * @offset: offset in the buffer to start copying to diff --git a/net/core/iovec.c b/net/core/iovec.c index 4c9c012..a215545 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -98,6 +98,31 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) } /* + * Copy kernel to iovec. Returns -EFAULT on error. + */ + +int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, + int offset, int len) +{ + int copy; + for (; len > 0; ++iov) { + /* Skip over the finished iovecs */ + if (unlikely(offset >= iov->iov_len)) { + offset -= iov->iov_len; + continue; + } + copy = min_t(unsigned int, iov->iov_len - offset, len); + offset = 0; + if (copy_to_user(iov->iov_base, kdata, copy)) + return -EFAULT; + kdata += copy; + len -= copy; + } + + return 0; +} + +/* * Copy iovec to kernel. Returns -EFAULT on error. * * Note: this modifies the original iovec. @@ -236,3 +261,4 @@ EXPORT_SYMBOL(csum_partial_copy_fromiovecend); EXPORT_SYMBOL(memcpy_fromiovec); EXPORT_SYMBOL(memcpy_fromiovecend); EXPORT_SYMBOL(memcpy_toiovec); +EXPORT_SYMBOL(memcpy_toiovecend); -- cgit v0.10.2 From 43b39dcdbdf823a1c0ac1f2aa2d76bd2f210adc8 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 20 Apr 2009 01:25:59 +0000 Subject: tun: fix tun_chr_aio_read so that aio works aio_read gets const struct iovec * but tun_chr_aio_read casts this to struct iovec * and modifies the iovec. As a result, attempts to use io_submit to get packets from a tun device fail with weird errors such as EINVAL. Fix by using the new skb_copy_datagram_const_iovec. Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 735bf41..3b513e2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -683,7 +683,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, /* Put packet to the user space buffer */ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, struct sk_buff *skb, - struct iovec *iv, int len) + const struct iovec *iv, int len) { struct tun_pi pi = { 0, skb->protocol }; ssize_t total = 0; @@ -697,7 +697,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, pi.flags |= TUN_PKT_STRIP; } - if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi))) + if (memcpy_toiovecend(iv, (void *) &pi, 0, sizeof(pi))) return -EFAULT; total += sizeof(pi); } @@ -730,14 +730,15 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, gso.csum_offset = skb->csum_offset; } /* else everything is zero */ - if (unlikely(memcpy_toiovec(iv, (void *)&gso, sizeof(gso)))) + if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, + sizeof(gso)))) return -EFAULT; total += sizeof(gso); } len = min_t(int, skb->len, len); - skb_copy_datagram_iovec(skb, 0, iv, len); + skb_copy_datagram_const_iovec(skb, 0, iv, total, len); total += len; tun->dev->stats.tx_packets++; @@ -792,7 +793,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, } netif_wake_queue(tun->dev); - ret = tun_put_user(tun, skb, (struct iovec *) iv, len); + ret = tun_put_user(tun, skb, iv, len); kfree_skb(skb); break; } -- cgit v0.10.2 From 6f26c9a7555e5bcca3560919db9b852015077dae Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 20 Apr 2009 01:26:11 +0000 Subject: tun: fix tun_chr_aio_write so that aio works aio_write gets const struct iovec * but tun_chr_aio_write casts this to struct iovec * and modifies the iovec. As a result, attempts to use io_submit to send packets to a tun device fail with weird errors such as EINVAL. Since tun is the only user of skb_copy_datagram_from_iovec, we can fix this simply by changing the later so that it does not touch the iovec passed to it. Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3b513e2..589f0ca 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -540,31 +540,34 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, /* Get packet from user space buffer */ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, - struct iovec *iv, size_t count, + const struct iovec *iv, size_t count, int noblock) { struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) }; struct sk_buff *skb; size_t len = count, align = 0; struct virtio_net_hdr gso = { 0 }; + int offset = 0; if (!(tun->flags & TUN_NO_PI)) { if ((len -= sizeof(pi)) > count) return -EINVAL; - if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi))) + if (memcpy_fromiovecend((void *)&pi, iv, 0, sizeof(pi))) return -EFAULT; + offset += sizeof(pi); } if (tun->flags & TUN_VNET_HDR) { if ((len -= sizeof(gso)) > count) return -EINVAL; - if (memcpy_fromiovec((void *)&gso, iv, sizeof(gso))) + if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) return -EFAULT; if (gso.hdr_len > len) return -EINVAL; + offset += sizeof(pi); } if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { @@ -581,7 +584,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, return PTR_ERR(skb); } - if (skb_copy_datagram_from_iovec(skb, 0, iv, len)) { + if (skb_copy_datagram_from_iovec(skb, 0, iv, offset, len)) { tun->dev->stats.rx_dropped++; kfree_skb(skb); return -EFAULT; @@ -673,7 +676,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); - result = tun_get_user(tun, (struct iovec *)iv, iov_length(iv, count), + result = tun_get_user(tun, iv, iov_length(iv, count), file->f_flags & O_NONBLOCK); tun_put(tun); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index af2b21b..1b5c3d2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1715,7 +1715,8 @@ extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, struct iovec *iov); extern int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, - struct iovec *from, + const struct iovec *from, + int from_offset, int len); extern int skb_copy_datagram_const_iovec(const struct sk_buff *from, int offset, diff --git a/include/linux/socket.h b/include/linux/socket.h index 171b08d..42a0396 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -309,8 +309,8 @@ struct ucred { #ifdef __KERNEL__ extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); -extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, - int offset, int len); +extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, + int offset, int len); extern int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, diff --git a/net/core/datagram.c b/net/core/datagram.c index 4dbb05c..914d5fa 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -435,13 +435,15 @@ EXPORT_SYMBOL(skb_copy_datagram_const_iovec); * @skb: buffer to copy * @offset: offset in the buffer to start copying to * @from: io vector to copy to + * @from_offset: offset in the io vector to start copying from * @len: amount of data to copy to buffer from iovec * * Returns 0 or -EFAULT. - * Note: the iovec is modified during the copy. + * Note: the iovec is not modified during the copy. */ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, - struct iovec *from, int len) + const struct iovec *from, int from_offset, + int len) { int start = skb_headlen(skb); int i, copy = start - offset; @@ -450,11 +452,12 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, if (copy > 0) { if (copy > len) copy = len; - if (memcpy_fromiovec(skb->data + offset, from, copy)) + if (memcpy_fromiovecend(skb->data + offset, from, 0, copy)) goto fault; if ((len -= copy) == 0) return 0; offset += copy; + from_offset += copy; } /* Copy paged appendix. Hmm... why does this look so complicated? */ @@ -473,8 +476,9 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, if (copy > len) copy = len; vaddr = kmap(page); - err = memcpy_fromiovec(vaddr + frag->page_offset + - offset - start, from, copy); + err = memcpy_fromiovecend(vaddr + frag->page_offset + + offset - start, + from, from_offset, copy); kunmap(page); if (err) goto fault; @@ -482,6 +486,7 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, if (!(len -= copy)) return 0; offset += copy; + from_offset += copy; } start = end; } @@ -500,11 +505,14 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, copy = len; if (skb_copy_datagram_from_iovec(list, offset - start, - from, copy)) + from, + from_offset, + copy)) goto fault; if ((len -= copy) == 0) return 0; offset += copy; + from_offset += copy; } start = end; } diff --git a/net/core/iovec.c b/net/core/iovec.c index a215545..40a76ce 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -147,10 +147,11 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) } /* - * For use with ip_build_xmit + * Copy iovec from kernel. Returns -EFAULT on error. */ -int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, - int len) + +int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, + int offset, int len) { /* Skip over the finished iovecs */ while (offset >= iov->iov_len) { -- cgit v0.10.2 From bf98a82633b97fb638fcee0fae3c0de54d1f7b05 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Tue, 21 Apr 2009 18:12:11 -0700 Subject: sa1100_ir: fix build breakage Fix simple typo. Caused by commit a1de966682551debbe690672e760487cc555c05f ("irda/sa1100_ir: convert to net_device_ops"). Reported-by: Stephen Rothwell Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 4ed7636..2aeb2e6 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -925,7 +925,7 @@ static int sa1100_irda_probe(struct platform_device *pdev) goto err_mem_5; dev->netdev_ops = &sa1100_irda_netdev_ops; - dev->ir = IRQ_Ser2ICP; + dev->irq = IRQ_Ser2ICP; irda_init_max_qos_capabilies(&si->qos); -- cgit v0.10.2 From 4cb9be7ab47820a1fa747569f5f035a5f628c91b Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 21 Apr 2009 18:42:05 +0000 Subject: e1000/e1000e/igb/ixgb: do not use netif_wake_queue un-necessarily It was pointed out that the Intel wired ethernet drivers do not need to wake the tx queue since netif_carrier_on/off will take care of the qdisc management in order to guarantee the correct handling of the transmit routine enable state. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 112e6b0..71d4fe1 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -498,6 +498,8 @@ int e1000_up(struct e1000_adapter *adapter) e1000_irq_enable(adapter); + netif_wake_queue(adapter->netdev); + /* fire a link change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); return 0; @@ -2591,7 +2593,6 @@ static void e1000_watchdog(unsigned long data) ew32(TCTL, tctl); netif_carrier_on(netdev); - netif_wake_queue(netdev); mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); adapter->smartspeed = 0; } else { @@ -2608,7 +2609,6 @@ static void e1000_watchdog(unsigned long data) printk(KERN_INFO "e1000: %s NIC Link is Down\n", netdev->name); netif_carrier_off(netdev); - netif_stop_queue(netdev); mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); /* 80003ES2LAN workaround-- diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 9048f8e..da6b37e 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2826,6 +2826,8 @@ int e1000e_up(struct e1000_adapter *adapter) e1000_configure_msix(adapter); e1000_irq_enable(adapter); + netif_wake_queue(adapter->netdev); + /* fire a link change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); return 0; @@ -2848,7 +2850,7 @@ void e1000e_down(struct e1000_adapter *adapter) ew32(RCTL, rctl & ~E1000_RCTL_EN); /* flush and sleep below */ - netif_tx_stop_all_queues(netdev); + netif_stop_queue(netdev); /* disable transmits in the hardware */ tctl = er32(TCTL); @@ -3130,7 +3132,7 @@ static int e1000_open(struct net_device *netdev) e1000_irq_enable(adapter); - netif_tx_start_all_queues(netdev); + netif_start_queue(netdev); /* fire a link status change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); @@ -3600,7 +3602,6 @@ static void e1000_watchdog_task(struct work_struct *work) phy->ops.cfg_on_link_up(hw); netif_carrier_on(netdev); - netif_tx_wake_all_queues(netdev); if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, @@ -3614,7 +3615,6 @@ static void e1000_watchdog_task(struct work_struct *work) printk(KERN_INFO "e1000e: %s NIC Link is Down\n", adapter->netdev->name); netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index ceaa585..183235d 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -942,6 +942,8 @@ int igb_up(struct igb_adapter *adapter) rd32(E1000_ICR); igb_irq_enable(adapter); + netif_tx_start_all_queues(adapter->netdev); + /* Fire a link change interrupt to start the watchdog. */ wr32(E1000_ICS, E1000_ICS_LSC); return 0; @@ -2664,7 +2666,6 @@ static void igb_watchdog_task(struct work_struct *work) } netif_carrier_on(netdev); - netif_tx_wake_all_queues(netdev); igb_ping_all_vfs(adapter); @@ -2681,7 +2682,6 @@ static void igb_watchdog_task(struct work_struct *work) printk(KERN_INFO "igb: %s NIC Link is Down\n", netdev->name); netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); igb_ping_all_vfs(adapter); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index ff741ca..cb9ecc4 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -266,6 +266,8 @@ ixgb_up(struct ixgb_adapter *adapter) napi_enable(&adapter->napi); ixgb_irq_enable(adapter); + netif_wake_queue(netdev); + mod_timer(&adapter->watchdog_timer, jiffies); return 0; @@ -1118,7 +1120,6 @@ ixgb_watchdog(unsigned long data) adapter->link_speed = 10000; adapter->link_duplex = FULL_DUPLEX; netif_carrier_on(netdev); - netif_wake_queue(netdev); } } else { if (netif_carrier_ok(netdev)) { @@ -1127,8 +1128,6 @@ ixgb_watchdog(unsigned long data) printk(KERN_INFO "ixgb: %s NIC Link is Down\n", netdev->name); netif_carrier_off(netdev); - netif_stop_queue(netdev); - } } -- cgit v0.10.2 From 362b76edb78923face033e18e4ffc85df8db0f28 Mon Sep 17 00:00:00 2001 From: Mateusz Mandera Date: Wed, 22 Apr 2009 02:24:28 -0700 Subject: 8390p: Get rid of init_module/cleanup_module This trivial patch just "gets rid of" init_module and cleanup_module from drivers/net/8390p.c Signed-off-by: Mateusz Mandera Signed-off-by: David S. Miller diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index 6ec11da..cacdd86 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -91,16 +91,15 @@ void NS8390p_init(struct net_device *dev, int startp) } EXPORT_SYMBOL(NS8390p_init); -#if defined(MODULE) - -int init_module(void) +static int __init 8390p_init_module(void) { return 0; } -void cleanup_module(void) +static void __exit 8390p_cleanup_module(void) { } -#endif /* MODULE */ +module_init(8390p_init_module); +module_exit(8390p_cleanup_module); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From f74d0f5cacb7023422098dd5c98e3ce06787ba56 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 25 Mar 2009 08:30:15 +0300 Subject: p54spi: mask value read from SPI_ADRS_DMA_WRITE_CTRL in p54spi_wait_bit Mask value read from SPI_ADRS_DMA_WRITE_CTRL in p54spi_wait_bit. Without this, 'fw_upload not allowed to DMA write' is observed at both N800 and N810. Signed-off-by: Max Filippov Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index d1fe577..5540272 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -171,7 +171,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) for (i = 0; i < 2000; i++) { p54spi_spi_read(priv, reg, &buffer, sizeof(buffer)); - if (buffer == bits) + if ((buffer & bits) == bits) return 1; msleep(1); -- cgit v0.10.2 From 5e3af1d2d3e6c0011b4c22514d39c73dcbc6674f Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 25 Mar 2009 13:45:01 +0100 Subject: p54spi: fix p54spi_upload_firmware Instead of firmware itself p54_upload_firmware was sending to the device content of struct firmware and the following random garbage. Notice '&' before priv->firmware->data at p54spi_spi_write. But simple removing of '&' sign triggered BUG_ON at dma_cache_maint. Thus kmemdup - kfree workaround. Signed-off-by: Max Filippov Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 5540272..bed894a 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -228,8 +228,15 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev) static int p54spi_upload_firmware(struct ieee80211_hw *dev) { struct p54s_priv *priv = dev->priv; - unsigned long fw_len, fw_addr; - long _fw_len; + unsigned long fw_len, _fw_len; + unsigned int offset = 0; + int err = 0; + u8 *fw; + + fw_len = priv->firmware->size; + fw = kmemdup(priv->firmware->data, fw_len, GFP_KERNEL); + if (!fw) + return -ENOMEM; /* stop the device */ p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( @@ -244,9 +251,6 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) msleep(TARGET_BOOT_SLEEP); - fw_addr = ISL38XX_DEV_FIRMWARE_ADDR; - fw_len = priv->firmware->size; - while (fw_len > 0) { _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE); @@ -257,23 +261,20 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) cpu_to_le32(HOST_ALLOWED)) == 0) { dev_err(&priv->spi->dev, "fw_upload not allowed " "to DMA write."); - return -EAGAIN; + err = -EAGAIN; + goto out; } p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(_fw_len)); - p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, - cpu_to_le32(fw_addr)); + p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, cpu_to_le32( + ISL38XX_DEV_FIRMWARE_ADDR + offset)); p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, - &priv->firmware->data, _fw_len); + (fw + offset), _fw_len); fw_len -= _fw_len; - fw_addr += _fw_len; - - /* FIXME: I think this doesn't work if firmware is large, - * this loop goes to second round. fw->data is not - * increased at all! */ + offset += _fw_len; } BUG_ON(fw_len != 0); @@ -292,7 +293,10 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT)); msleep(TARGET_BOOT_SLEEP); - return 0; + +out: + kfree(fw); + return err; } static void p54spi_power_off(struct p54s_priv *priv) -- cgit v0.10.2 From 684d6b360222f31b6b9be9a63aa5c6ed5674c890 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 25 Mar 2009 09:51:16 -0700 Subject: libertas: support mesh for various firmware versions CMD_MESH_CONFIG command ID and a couple of structure members in TxPD, RxPD have been changed in firmware version 10.x.y.z and newer. Signed-off-by: Kiran Divekar Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8c3605c..c455b9a 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -119,6 +119,19 @@ int lbs_update_hw_spec(struct lbs_private *priv) lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", cmd.hwifversion, cmd.version); + /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ + /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ + /* 5.110.22 have mesh command with 0xa3 command id */ + /* 10.0.0.p0 FW brings in mesh config command with different id */ + /* Check FW version MSB and initialize mesh_fw_ver */ + if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) + priv->mesh_fw_ver = MESH_FW_OLD; + else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && + (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) + priv->mesh_fw_ver = MESH_FW_NEW; + else + priv->mesh_fw_ver = MESH_NONE; + /* 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. @@ -1036,17 +1049,26 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, uint16_t action, uint16_t type) { int ret; + u16 command = CMD_MESH_CONFIG_OLD; lbs_deb_enter(LBS_DEB_CMD); - cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG); + /* + * Command id is 0xac for v10 FW along with mesh interface + * id in bits 14-13-12. + */ + if (priv->mesh_fw_ver == MESH_FW_NEW) + command = CMD_MESH_CONFIG | + (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); + + cmd->hdr.command = cpu_to_le16(command); cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); cmd->hdr.result = 0; cmd->type = cpu_to_le16(type); cmd->action = cpu_to_le16(action); - ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd); + ret = lbs_cmd_with_response(priv, command, cmd); lbs_deb_leave(LBS_DEB_CMD); return ret; diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index e8dfde3..48da157 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -227,6 +227,20 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define TxPD_CONTROL_WDS_FRAME (1<<17) #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME +/** Mesh interface ID */ +#define MESH_IFACE_ID 0x0001 +/** Mesh id should be in bits 14-13-12 */ +#define MESH_IFACE_BIT_OFFSET 0x000c +/** Mesh enable bit in FW capability */ +#define MESH_CAPINFO_ENABLE_MASK (1<<16) + +/** FW definition from Marvell v5 */ +#define MRVL_FW_V5 (0x05) +/** FW definition from Marvell v10 */ +#define MRVL_FW_V10 (0x0a) +/** FW major revision definition */ +#define MRVL_FW_MAJOR_REV(x) ((x)>>24) + /** RxPD status */ #define MRVDRV_RXPD_STATUS_OK 0x0001 @@ -380,6 +394,13 @@ enum KEY_INFO_WPA { KEY_INFO_WPA_ENABLED = 0x04 }; +/** mesh_fw_ver */ +enum _mesh_fw_ver { + MESH_NONE = 0, /* MESH is not supported */ + MESH_FW_OLD, /* MESH is supported in FW V5 */ + MESH_FW_NEW, /* MESH is supported in FW V10 and newer */ +}; + /* 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 27e81fd..cbaafa6 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -101,6 +101,7 @@ struct lbs_mesh_stats { /** Private structure for the MV device */ struct lbs_private { int mesh_open; + int mesh_fw_ver; int infra_open; int mesh_autostart_enabled; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index d4457ef..8ff8ac9 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -83,7 +83,8 @@ #define CMD_FWT_ACCESS 0x0095 #define CMD_802_11_MONITOR_MODE 0x0098 #define CMD_MESH_ACCESS 0x009b -#define CMD_MESH_CONFIG 0x00a3 +#define CMD_MESH_CONFIG_OLD 0x00a3 +#define CMD_MESH_CONFIG 0x00ac #define CMD_SET_BOOT2_VER 0x00a5 #define CMD_802_11_BEACON_CTRL 0x00b0 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index a899aeb..391c54a 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -13,8 +13,19 @@ /* TxPD descriptor */ struct txpd { - /* Current Tx packet status */ - __le32 tx_status; + /* union to cope up with later FW revisions */ + union { + /* Current Tx packet status */ + __le32 tx_status; + struct { + /* BSS type: client, AP, etc. */ + u8 bss_type; + /* BSS number */ + u8 bss_num; + /* Reserved */ + __le16 reserved; + } bss; + } u; /* Tx control */ __le32 tx_control; __le32 tx_packet_location; @@ -36,8 +47,17 @@ struct txpd { /* RxPD Descriptor */ struct rxpd { - /* Current Rx packet status */ - __le16 status; + /* union to cope up with later FW revisions */ + union { + /* Current Rx packet status */ + __le16 status; + struct { + /* BSS type: client, AP, etc. */ + u8 bss_type; + /* BSS number */ + u8 bss_num; + } bss; + } u; /* SNR */ u8 snr; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 8ae935a..89575e4 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1307,8 +1307,10 @@ int lbs_start_card(struct lbs_private *priv) lbs_update_channel(priv); - /* 5.0.16p0 is known to NOT support any mesh */ - if (priv->fwrelease > 0x05001000) { + /* Check mesh FW version and appropriately send the mesh start + * command + */ + if (priv->mesh_fw_ver == MESH_FW_OLD) { /* Enable mesh, if supported, and work out which TLV it uses. 0x100 + 291 is an unofficial value used in 5.110.20.pXX 0x100 + 37 is the official value used in 5.110.21.pXX @@ -1322,27 +1324,35 @@ int lbs_start_card(struct lbs_private *priv) It's just that 5.110.20.pXX will not have done anything useful */ - priv->mesh_tlv = 0x100 + 291; + priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->curbssparams.channel)) { - priv->mesh_tlv = 0x100 + 37; + priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->curbssparams.channel)) priv->mesh_tlv = 0; } - if (priv->mesh_tlv) { - lbs_add_mesh(priv); - - if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) - lbs_pr_err("cannot register lbs_mesh attribute\n"); - - /* While rtap isn't related to mesh, only mesh-enabled - * firmware implements the rtap functionality via - * CMD_802_11_MONITOR_MODE. - */ - if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) - lbs_pr_err("cannot register lbs_rtap attribute\n"); - } + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + /* 10.0.0.pXX new firmwares should succeed with TLV + * 0x100+37; Do not invoke command with old TLV. + */ + priv->mesh_tlv = TLV_TYPE_MESH_ID; + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) + priv->mesh_tlv = 0; + } + if (priv->mesh_tlv) { + lbs_add_mesh(priv); + + if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) + lbs_pr_err("cannot register lbs_mesh attribute\n"); + + /* While rtap isn't related to mesh, only mesh-enabled + * firmware implements the rtap functionality via + * CMD_802_11_MONITOR_MODE. + */ + if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) + lbs_pr_err("cannot register lbs_rtap attribute\n"); } lbs_debugfs_init_one(priv, dev); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 8e66977..820c22d 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -160,8 +160,15 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) p_rx_pkt = (struct rxpackethdr *) skb->data; p_rx_pd = &p_rx_pkt->rx_pd; - if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME)) - dev = priv->mesh_dev; + if (priv->mesh_dev) { + if (priv->mesh_fw_ver == MESH_FW_OLD) { + if (p_rx_pd->rx_control & RxPD_MESH_FRAME) + dev = priv->mesh_dev; + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + if (p_rx_pd->u.bss.bss_num == MESH_IFACE_ID) + dev = priv->mesh_dev; + } + } lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); @@ -174,18 +181,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) goto done; } - /* - * Check rxpd status and update 802.3 stat, - */ - if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { - lbs_deb_rx("rx err: frame received with bad status\n"); - lbs_pr_alert("rxpd not ok\n"); - dev->stats.rx_errors++; - ret = 0; - dev_kfree_skb(skb); - goto done; - } - lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); @@ -334,14 +329,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, goto done; } - /* - * Check rxpd status and update 802.3 stat, - */ - if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { - //lbs_deb_rx("rx err: frame received with bad status\n"); - dev->stats.rx_errors++; - } - lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); @@ -353,8 +340,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, radiotap_hdr.hdr.it_pad = 0; radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); - if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) - radiotap_hdr.flags |= IEEE80211_RADIOTAP_F_BADFCS; radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); /* XXX must check no carryout */ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index f10aa39..160cfd8 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -132,8 +132,12 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) txpd->tx_packet_length = cpu_to_le16(pkt_len); txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); - if (dev == priv->mesh_dev) - txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); + if (dev == priv->mesh_dev) { + if (priv->mesh_fw_ver == MESH_FW_OLD) + txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); + else if (priv->mesh_fw_ver == MESH_FW_NEW) + txpd->u.bss.bss_num = MESH_IFACE_ID; + } lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index fb7a2d1..de03b9c 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -94,6 +94,8 @@ struct ieeetypes_assocrsp { #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) #define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) +#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) +#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) /** TLV related data structures*/ struct mrvlietypesheader { -- cgit v0.10.2 From 4f5cab969bdbec1ab0c5b690282372b4978123ac Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 26 Mar 2009 06:38:25 +0300 Subject: p54spi: fix p54spi_tx_frame DMA transfer initiation and skb cleanup p54spi_tx_frame wasn't waiting for HOST_ALLOWED in SPI_ADRS_DMA_WRITE_CTRL. This resulted in frequent 'WR_READY timeout' on beacon resubmission. Also don't free skb on error path, as it gets freed on p54spi_wq_tx. Signed-off-by: Max Filippov Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index bed894a..f8af096 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -179,6 +179,25 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) return 0; } +static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, + const void *buf, size_t len) +{ + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); + + if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le32(HOST_ALLOWED)) == 0) { + dev_err(&priv->spi->dev, "spi_write_dma not allowed " + "to DMA write."); + return -EAGAIN; + } + + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len)); + p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base); + p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len); + return 0; +} + static int p54spi_request_firmware(struct ieee80211_hw *dev) { struct p54s_priv *priv = dev->priv; @@ -254,24 +273,11 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) while (fw_len > 0) { _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE); - p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); - - if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le32(HOST_ALLOWED)) == 0) { - dev_err(&priv->spi->dev, "fw_upload not allowed " - "to DMA write."); - err = -EAGAIN; + err = p54spi_spi_write_dma(priv, cpu_to_le32( + ISL38XX_DEV_FIRMWARE_ADDR + offset), + (fw + offset), _fw_len); + if (err < 0) goto out; - } - - p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, - cpu_to_le16(_fw_len)); - p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, cpu_to_le32( - ISL38XX_DEV_FIRMWARE_ADDR + offset)); - - p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, - (fw + offset), _fw_len); fw_len -= _fw_len; offset += _fw_len; @@ -418,27 +424,21 @@ static irqreturn_t p54spi_interrupt(int irq, void *config) static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) { struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54s_dma_regs dma_regs; unsigned long timeout; int ret = 0; u32 ints; p54spi_wakeup(priv); - dma_regs.cmd = cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE); - dma_regs.len = cpu_to_le16(skb->len); - dma_regs.addr = hdr->req_id; - - p54spi_spi_write(priv, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs, - sizeof(dma_regs)); - - p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, skb->data, skb->len); + ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len); + if (ret < 0) + goto out; timeout = jiffies + 2 * HZ; ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); while (!(ints & SPI_HOST_INT_WR_READY)) { if (time_after(jiffies, timeout)) { - dev_err(&priv->spi->dev, "WR_READY timeout"); + dev_err(&priv->spi->dev, "WR_READY timeout\n"); ret = -1; goto out; } @@ -448,9 +448,9 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); p54spi_sleep(priv); -out: if (FREE_AFTER_TX(skb)) p54_free_skb(priv->hw, skb); +out: return ret; } -- cgit v0.10.2 From 6da3a13e4fcab0ff58592087d28bd283caf23d88 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 26 Mar 2009 10:14:08 -0700 Subject: iwlwifi: merge and better support of suspend/resume for iwlagn and iwl3945 With mac80211's help to call stop() and start() in mac80211 suspend/resume function, both iwlagn and iwl3945 no longer calling stop() and start(); remove un-necessary STATUS_IN_SUSPEND bit from both header files and functions, Move apm_ops.stop() function into pci_suspend() to ensure DMA is stopped before go into suspend mode. iwl3945 has the similar suspend/resume function as iwlagn, so move both functions to iwlcore to be shared by both drivers. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ab7aaf6..29bc0d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -162,7 +162,6 @@ struct iwl3945_frame { #define STATUS_TEMPERATURE 8 #define STATUS_GEO_CONFIGURED 9 #define STATUS_EXIT_PENDING 10 -#define STATUS_IN_SUSPEND 11 #define STATUS_STATISTICS 12 #define STATUS_SCANNING 13 #define STATUS_SCAN_ABORTING 14 diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3889158..2cb073e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1654,7 +1654,7 @@ static void __iwl_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill and SUSPEND bits and return */ + * clear all bits but the RF Kill bits and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | @@ -1662,23 +1662,19 @@ static void __iwl_down(struct iwl_priv *priv) STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; goto exit; } - /* ...otherwise clear out all the status bits but the RF Kill and - * SUSPEND bits and continue taking the NIC down. */ + /* ...otherwise clear out all the status bits but the RF Kill + * bits and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << STATUS_FW_ERROR | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -1703,7 +1699,7 @@ static void __iwl_down(struct iwl_priv *priv) udelay(5); /* FIXME: apm_ops.suspend(priv) */ - if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status)) + if (exit_pending) priv->cfg->ops->lib->apm_ops.stop(priv); else priv->cfg->ops->lib->apm_ops.reset(priv); @@ -2064,9 +2060,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw) IWL_DEBUG_INFO(priv, "Start UP work done.\n"); - if (test_bit(STATUS_IN_SUSPEND, &priv->status)) - return 0; - /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -3566,45 +3559,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) ieee80211_free_hw(priv->hw); } -#ifdef CONFIG_PM - -static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - - if (priv->is_open) { - set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl_mac_stop(priv->hw); - priv->is_open = 1; - } - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int iwl_pci_resume(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - int ret; - - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_device(pdev); - if (ret) - return ret; - pci_restore_state(pdev); - iwl_enable_interrupts(priv); - - if (priv->is_open) - iwl_mac_start(priv->hw); - - clear_bit(STATUS_IN_SUSPEND, &priv->status); - return 0; -} - -#endif /* CONFIG_PM */ /***************************************************************************** * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c54fb93..2e44d6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2112,3 +2112,43 @@ void iwl_rx_reply_error(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_reply_error); +#ifdef CONFIG_PM + +int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + /* + * This function is called when system goes into suspend state + * mac80211 will call iwl_mac_stop() from the mac80211 suspend function + * first but since iwl_mac_stop() has no knowledge of who the caller is, + * it will not call apm_ops.stop() to stop the DMA operation. + * Calling apm_ops.stop here to make sure we stop the DMA. + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} +EXPORT_SYMBOL(iwl_pci_suspend); + +int iwl_pci_resume(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + int ret; + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); + if (ret) + return ret; + pci_restore_state(pdev); + iwl_enable_interrupts(priv); + + return 0; +} +EXPORT_SYMBOL(iwl_pci_resume); + +#endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a8eac8c..5d49045 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -432,6 +432,10 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); return pci_lnk_ctl; } +#ifdef CONFIG_PM +int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); +int iwl_pci_resume(struct pci_dev *pdev); +#endif /* CONFIG_PM */ /***************************************************** * Error Handling Debugging @@ -458,7 +462,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_TEMPERATURE 8 #define STATUS_GEO_CONFIGURED 9 #define STATUS_EXIT_PENDING 10 -#define STATUS_IN_SUSPEND 11 #define STATUS_STATISTICS 12 #define STATUS_SCANNING 13 #define STATUS_SCAN_ABORTING 14 diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 64eb585..af1d121 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -456,8 +456,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_GEO_CONFIGURED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n", test_bit(STATUS_EXIT_PENDING, &priv->status)); - pos += scnprintf(buf + pos, bufsz - pos, "STATUS_IN_SUSPEND:\t %d\n", - test_bit(STATUS_IN_SUSPEND, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n", test_bit(STATUS_STATISTICS, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index da61ecd..afb838b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2996,7 +2996,7 @@ static void __iwl3945_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl3945_init() then - * clear all bits but the RF Kill and SUSPEND bits and return */ + * clear all bits but the RF Kill bits and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | @@ -3004,23 +3004,19 @@ static void __iwl3945_down(struct iwl_priv *priv) STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; goto exit; } - /* ...otherwise clear out all the status bits but the RF Kill and - * SUSPEND bits and continue taking the NIC down. */ + /* ...otherwise clear out all the status bits but the RF Kill + * bits and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << STATUS_FW_ERROR | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -3044,7 +3040,7 @@ static void __iwl3945_down(struct iwl_priv *priv) udelay(5); - if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status)) + if (exit_pending) priv->cfg->ops->lib->apm_ops.stop(priv); else priv->cfg->ops->lib->apm_ops.reset(priv); @@ -3097,10 +3093,8 @@ static int __iwl3945_up(struct iwl_priv *priv) clear_bit(STATUS_RF_KILL_HW, &priv->status); else { set_bit(STATUS_RF_KILL_HW, &priv->status); - if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { - IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); - return -ENODEV; - } + IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); + return -ENODEV; } iwl_write32(priv, CSR_INT, 0xFFFFFFFF); @@ -3592,9 +3586,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) IWL_DEBUG_INFO(priv, "Start UP work.\n"); - if (test_bit(STATUS_IN_SUSPEND, &priv->status)) - return 0; - /* Wait for START_ALIVE from ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -5233,43 +5224,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) ieee80211_free_hw(priv->hw); } -#ifdef CONFIG_PM - -static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - - if (priv->is_open) { - set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl3945_mac_stop(priv->hw); - priv->is_open = 1; - } - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int iwl3945_pci_resume(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - int ret; - - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_device(pdev); - if (ret) - return ret; - pci_restore_state(pdev); - - if (priv->is_open) - iwl3945_mac_start(priv->hw); - - clear_bit(STATUS_IN_SUSPEND, &priv->status); - return 0; -} - -#endif /* CONFIG_PM */ /***************************************************************************** * @@ -5283,8 +5237,8 @@ static struct pci_driver iwl3945_driver = { .probe = iwl3945_pci_probe, .remove = __devexit_p(iwl3945_pci_remove), #ifdef CONFIG_PM - .suspend = iwl3945_pci_suspend, - .resume = iwl3945_pci_resume, + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, #endif }; -- cgit v0.10.2 From 488829f1b141858944a24fd793220fa1d52cd9a6 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Thu, 26 Mar 2009 10:14:10 -0700 Subject: iwl3945: use iwl_mac_conf_tx 3945 now uses iwl_mac_conf_tx. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2cb073e..1f5ee55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2628,49 +2628,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - int q; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (queue >= AC_NUM) { - IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); - return 0; - } - - q = AC_NUM - 1 - queue; - - spin_lock_irqsave(&priv->lock, flags); - - priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); - priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); - priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; - priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->txop * 32)); - - priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; - priv->qos_data.qos_active = 1; - - 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); - - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2e44d6e..7609bfc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2112,6 +2112,49 @@ void iwl_rx_reply_error(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_reply_error); +int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + int q; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); + return 0; + } + + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->lock, flags); + + priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); + priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); + priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + priv->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->txop * 32)); + + priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; + priv->qos_data.qos_active = 1; + + 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); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + return 0; +} +EXPORT_SYMBOL(iwl_mac_conf_tx); #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 5d49045..d56edcd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -225,6 +225,8 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, void iwl_hw_detect(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_activate_qos(struct iwl_priv *priv, u8 force); +int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params); void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv); int iwl_full_rxon_required(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index afb838b..ed31030 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4100,52 +4100,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - int q; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (queue >= AC_NUM) { - IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); - return 0; - } - - q = AC_NUM - 1 - queue; - - spin_lock_irqsave(&priv->lock, flags); - - priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); - priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); - priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; - priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->txop * 32)); - - priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; - priv->qos_data.qos_active = 1; - - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - 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); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { @@ -4809,7 +4763,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .configure_filter = iwl_configure_filter, .set_key = iwl3945_mac_set_key, .get_tx_stats = iwl3945_mac_get_tx_stats, - .conf_tx = iwl3945_mac_conf_tx, + .conf_tx = iwl_mac_conf_tx, .reset_tsf = iwl3945_mac_reset_tsf, .bss_info_changed = iwl3945_bss_info_changed, .hw_scan = iwl_mac_hw_scan -- cgit v0.10.2 From 9f201a87831af9458df1eda65941c955f2da87ed Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 27 Mar 2009 07:50:53 +0300 Subject: p54spi: compensate firmware alignment bug in p54spi_rx Firmware may insert up to 4 padding bytes after the lmac header, but it does not amend the size of SPI data transfer. Such packets has correct data size in header, thus referencing past the end of allocated skb. Put extra 4 bytes to the end of the received skb to compensate for this case. Signed-off-by: Max Filippov Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index f8af096..52023127 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -395,7 +395,12 @@ static int p54spi_rx(struct p54s_priv *priv) return 0; } - skb = dev_alloc_skb(len); + + /* Firmware may insert up to 4 padding bytes after the lmac header, + * but it does not amend the size of SPI data transfer. + * Such packets has correct data size in header, thus referencing + * past the end of allocated skb. Reserve extra 4 bytes for this case */ + skb = dev_alloc_skb(len + 4); if (!skb) { dev_err(&priv->spi->dev, "could not alloc skb"); return 0; @@ -403,6 +408,9 @@ static int p54spi_rx(struct p54s_priv *priv) p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len); p54spi_sleep(priv); + /* Put additional bytes to compensate for the possible + * alignment-caused truncation */ + skb_put(skb, 4); if (p54_rx(priv->hw, skb) == 0) dev_kfree_skb(skb); -- cgit v0.10.2 From b0741a1a2b00d9b4d88ba60016c88e42f176e4d6 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 27 Mar 2009 13:08:45 +0530 Subject: mac80211: Don't access managed mode bits in non-managed mode This fixes a stupid bug introduced in 25f85c31d4f.. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 959aa83..a52fb3a 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -675,7 +675,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, !sdata->default_key, keybuf, erq->length); - if (!ret) { + if (!ret && sdata->vif.type == NL80211_IFTYPE_STATION) { if (remove) sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; else -- cgit v0.10.2 From f4a11bb0c2d5968ea35f95bdbabdd453862f202a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Mar 2009 12:40:28 +0100 Subject: nl80211: validate some input better This patch changes nl80211 to: * validate that any IE input is a valid IE (stream) * move some validation code before locking * require that a reason code is given for both deauth/disassoc Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2456e4e..2f449dd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -118,6 +118,36 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, }; +/* IE validation */ +static bool is_valid_ie_attr(const struct nlattr *attr) +{ + const u8 *pos; + int len; + + if (!attr) + return true; + + pos = nla_data(attr); + len = nla_len(attr); + + while (len) { + u8 elemlen; + + if (len < 2) + return false; + len -= 2; + + elemlen = pos[1]; + if (elemlen > len) + return false; + + len -= elemlen; + pos += 2 + elemlen; + } + + return true; +} + /* message building helper */ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, int flags, u8 cmd) @@ -1069,6 +1099,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) struct beacon_parameters params; int haveinfo = 0; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2442,6 +2475,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) enum ieee80211_band band; size_t ie_len; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2710,6 +2746,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2731,11 +2773,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); @@ -2788,6 +2825,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_SSID]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2809,12 +2853,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC] || - !info->attrs[NL80211_ATTR_SSID]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); @@ -2856,6 +2894,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2877,24 +2924,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (info->attrs[NL80211_ATTR_REASON_CODE]) { - req.reason_code = - nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); - if (req.reason_code == 0) { - /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; - } + req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (req.reason_code == 0) { + /* Reason Code 0 is reserved */ + err = -EINVAL; + goto out; } if (info->attrs[NL80211_ATTR_IE]) { @@ -2920,6 +2959,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2941,24 +2989,16 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (info->attrs[NL80211_ATTR_REASON_CODE]) { - req.reason_code = - nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); - if (req.reason_code == 0) { - /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; - } + req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (req.reason_code == 0) { + /* Reason Code 0 is reserved */ + err = -EINVAL; + goto out; } if (info->attrs[NL80211_ATTR_IE]) { -- cgit v0.10.2 From c1c6b14b22af0f85d05a70405dc3fba5de840c7b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Mar 2009 11:32:46 +0200 Subject: rfkill: remove deprecated state constants I only did superficial review, but these constants are stupid to have and without proper warnings nobody will review the code anyway, no amount of shouting will help. Also fix wimax to use correct states. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/arch/arm/mach-pxa/tosa-bt.c b/arch/arm/mach-pxa/tosa-bt.c index fb0294b..bde42aa 100644 --- a/arch/arm/mach-pxa/tosa-bt.c +++ b/arch/arm/mach-pxa/tosa-bt.c @@ -38,9 +38,9 @@ static void tosa_bt_off(struct tosa_bt_data *data) static int tosa_bt_toggle_radio(void *data, enum rfkill_state state) { pr_info("BT_RADIO going: %s\n", - state == RFKILL_STATE_ON ? "on" : "off"); + state == RFKILL_STATE_UNBLOCKED ? "on" : "off"); - if (state == RFKILL_STATE_ON) { + if (state == RFKILL_STATE_UNBLOCKED) { pr_info("TOSA_BT: going ON\n"); tosa_bt_on(data); } else { diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index f84b78d..d696e5f 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2484,7 +2484,7 @@ static int add_net_device(struct hso_device *hso_dev) static int hso_radio_toggle(void *data, enum rfkill_state state) { struct hso_device *hso_dev = data; - int enabled = (state == RFKILL_STATE_ON); + int enabled = (state == RFKILL_STATE_UNBLOCKED); int rv; mutex_lock(&hso_dev->mutex); @@ -2522,7 +2522,7 @@ static void hso_create_rfkill(struct hso_device *hso_dev, snprintf(rfkn, 20, "hso-%d", interface->altsetting->desc.bInterfaceNumber); hso_net->rfkill->name = rfkn; - hso_net->rfkill->state = RFKILL_STATE_ON; + hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED; hso_net->rfkill->data = hso_dev; hso_net->rfkill->toggle_radio = hso_radio_toggle; if (rfkill_register(hso_net->rfkill) < 0) { diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 164332c..e1ec7d9 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -52,14 +52,6 @@ enum rfkill_state { RFKILL_STATE_MAX, /* marker for last valid state */ }; -/* - * These are DEPRECATED, drivers using them should be verified to - * comply with the rfkill usage guidelines in Documentation/rfkill.txt - * and then converted to use the new names for rfkill_state - */ -#define RFKILL_STATE_OFF RFKILL_STATE_SOFT_BLOCKED -#define RFKILL_STATE_ON RFKILL_STATE_UNBLOCKED - /** * struct rfkill - rfkill control structure. * @name: Name of the switch. diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 2b75aee..870032f 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -113,7 +113,7 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, if (state != wimax_dev->rf_hw) { wimax_dev->rf_hw = state; rfkill_state = state == WIMAX_RF_ON ? - RFKILL_STATE_OFF : RFKILL_STATE_ON; + RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; if (wimax_dev->rf_hw == WIMAX_RF_ON && wimax_dev->rf_sw == WIMAX_RF_ON) wimax_state = WIMAX_ST_READY; @@ -259,10 +259,10 @@ int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state) d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); switch (state) { - case RFKILL_STATE_ON: + case RFKILL_STATE_SOFT_BLOCKED: rf_state = WIMAX_RF_OFF; break; - case RFKILL_STATE_OFF: + case RFKILL_STATE_UNBLOCKED: rf_state = WIMAX_RF_ON; break; default: @@ -361,7 +361,7 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) wimax_dev->rfkill = rfkill; rfkill->name = wimax_dev->name; - rfkill->state = RFKILL_STATE_OFF; + rfkill->state = RFKILL_STATE_UNBLOCKED; rfkill->data = wimax_dev; rfkill->toggle_radio = wimax_rfkill_toggle_radio; rfkill->user_claim_unsupported = 1; -- cgit v0.10.2 From 621cac85297de5ba655e3430b007dd2e0da91da6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Mar 2009 14:14:31 +0100 Subject: rfkill: remove user_claim stuff Almost all drivers do not support user_claim, so remove it completely and always report -EOPNOTSUPP to userspace. Since userspace cannot really drive rfkill _anyway_ (due to the odd restrictions imposed by the documentation) having this code is just pointless. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 4d3ee31..40c3a3f 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -521,16 +521,12 @@ status of the system. Input devices may issue events that are related to rfkill. These are the various KEY_* events and SW_* events supported by rfkill-input.c. -******IMPORTANT****** -When rfkill-input is ACTIVE, userspace is NOT TO CHANGE THE STATE OF AN RFKILL -SWITCH IN RESPONSE TO AN INPUT EVENT also handled by rfkill-input, unless it -has set to true the user_claim attribute for that particular switch. This rule -is *absolute*; do NOT violate it. -******IMPORTANT****** - -Userspace must not assume it is the only source of control for rfkill switches. -Their state CAN and WILL change due to firmware actions, direct user actions, -and the rfkill-input EPO override for *_RFKILL_ALL. +Userspace may not change the state of an rfkill switch in response to an +input event, it should refrain from changing states entirely. + +Userspace cannot assume it is the only source of control for rfkill switches. +Their state can change due to firmware actions, direct user actions, and the +rfkill-input EPO override for *_RFKILL_ALL. When rfkill-input is not active, userspace must initiate a rfkill status change by writing to the "state" attribute in order for anything to happen. diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 13d4e67..0607df2 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1267,7 +1267,6 @@ static int ath_init_sw_rfkill(struct ath_softc *sc) 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; } diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index afad423..9e1d00b 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -139,7 +139,6 @@ void b43_rfkill_init(struct b43_wldev *dev) rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; - rfk->rfkill->user_claim_unsupported = 1; rfk->poll_dev = input_allocate_polled_device(); if (!rfk->poll_dev) { diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index b32bf6a..4b0c7d2 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -142,7 +142,6 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; - rfk->rfkill->user_claim_unsupported = 1; rfk->poll_dev = input_allocate_polled_device(); if (!rfk->poll_dev) { diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 2ad9faf..65605ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -91,7 +91,6 @@ int iwl_rfkill_init(struct iwl_priv *priv) priv->rfkill->data = priv; priv->rfkill->state = RFKILL_STATE_UNBLOCKED; priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; - priv->rfkill->user_claim_unsupported = 1; priv->rfkill->dev.class->suspend = NULL; priv->rfkill->dev.class->resume = NULL; diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 0f6e43b..62d02b3 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1005,7 +1005,6 @@ enum rfkill_type type, char *name, u32 cap) *data = cap; rfkill_dev->data = data; rfkill_dev->toggle_radio = acer_rfkill_set; - rfkill_dev->user_claim_unsupported = 1; err = rfkill_register(rfkill_dev); if (err) { diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 50d9019..fe171fa 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -434,7 +434,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) wifi_rfkill->name = "hp-wifi"; wifi_rfkill->state = hp_wmi_wifi_state(); wifi_rfkill->toggle_radio = hp_wmi_wifi_set; - wifi_rfkill->user_claim_unsupported = 1; err = rfkill_register(wifi_rfkill); if (err) goto add_sysfs_error; @@ -446,7 +445,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) bluetooth_rfkill->name = "hp-bluetooth"; bluetooth_rfkill->state = hp_wmi_bluetooth_state(); bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; - bluetooth_rfkill->user_claim_unsupported = 1; err = rfkill_register(bluetooth_rfkill); if (err) goto register_bluetooth_error; @@ -457,7 +455,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) wwan_rfkill->name = "hp-wwan"; wwan_rfkill->state = hp_wmi_wwan_state(); wwan_rfkill->toggle_radio = hp_wmi_wwan_set; - wwan_rfkill->user_claim_unsupported = 1; err = rfkill_register(wwan_rfkill); if (err) goto register_wwan_err; diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index d3c92d7..184e99e 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1097,7 +1097,6 @@ static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) sony_wifi_rfkill->name = "sony-wifi"; sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set; sony_wifi_rfkill->get_state = sony_nc_rfkill_get; - sony_wifi_rfkill->user_claim_unsupported = 1; sony_wifi_rfkill->data = (void *)SONY_WIFI; err = rfkill_register(sony_wifi_rfkill); if (err) @@ -1119,7 +1118,6 @@ static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) sony_bluetooth_rfkill->name = "sony-bluetooth"; sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; - sony_bluetooth_rfkill->user_claim_unsupported = 1; sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; err = rfkill_register(sony_bluetooth_rfkill); if (err) @@ -1140,7 +1138,6 @@ static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) sony_wwan_rfkill->name = "sony-wwan"; sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set; sony_wwan_rfkill->get_state = sony_nc_rfkill_get; - sony_wwan_rfkill->user_claim_unsupported = 1; sony_wwan_rfkill->data = (void *)SONY_WWAN; err = rfkill_register(sony_wwan_rfkill); if (err) @@ -1161,7 +1158,6 @@ static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) sony_wimax_rfkill->name = "sony-wimax"; sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set; sony_wimax_rfkill->get_state = sony_nc_rfkill_get; - sony_wimax_rfkill->user_claim_unsupported = 1; sony_wimax_rfkill->data = (void *)SONY_WIMAX; err = rfkill_register(sony_wimax_rfkill); if (err) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 9f18726..4345089 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -803,7 +803,6 @@ static int __init toshiba_acpi_init(void) toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio; - toshiba_acpi.rfk_dev->user_claim_unsupported = 1; toshiba_acpi.rfk_dev->data = &toshiba_acpi; if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) { diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index e1ec7d9..de18ef2 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -58,9 +58,6 @@ enum rfkill_state { * @type: Radio type which the button controls, the value stored * here should be a value from enum rfkill_type. * @state: State of the switch, "UNBLOCKED" means radio can operate. - * @user_claim_unsupported: Whether the hardware supports exclusive - * RF-kill control by userspace. Set this before registering. - * @user_claim: Set when the switch is controlled exlusively by userspace. * @mutex: Guards switch state transitions. It serializes callbacks * and also protects the state. * @data: Pointer to the RF button drivers private data which will be @@ -83,9 +80,6 @@ struct rfkill { const char *name; enum rfkill_type type; - bool user_claim_unsupported; - bool user_claim; - /* the mutex serializes callbacks and also protects * the state */ struct mutex mutex; diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 3eaa394..df1269c 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -200,7 +200,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, rfkill_global_states[type].current_state = state; list_for_each_entry(rfkill, &rfkill_list, node) { - if ((!rfkill->user_claim) && (rfkill->type == type)) { + if (rfkill->type == type) { mutex_lock(&rfkill->mutex); rfkill_toggle_radio(rfkill, state, 0); mutex_unlock(&rfkill->mutex); @@ -447,53 +447,14 @@ static ssize_t rfkill_claim_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct rfkill *rfkill = to_rfkill(dev); - - return sprintf(buf, "%d\n", rfkill->user_claim); + return sprintf(buf, "%d\n", 0); } static ssize_t rfkill_claim_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct rfkill *rfkill = to_rfkill(dev); - unsigned long claim_tmp; - bool claim; - int error; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (rfkill->user_claim_unsupported) - return -EOPNOTSUPP; - - error = strict_strtoul(buf, 0, &claim_tmp); - if (error) - return error; - claim = !!claim_tmp; - - /* - * Take the global lock to make sure the kernel is not in - * the middle of rfkill_switch_all - */ - error = mutex_lock_killable(&rfkill_global_mutex); - if (error) - return error; - - if (rfkill->user_claim != claim) { - if (!claim && !rfkill_epo_lock_active) { - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, - rfkill_global_states[rfkill->type].current_state, - 0); - mutex_unlock(&rfkill->mutex); - } - rfkill->user_claim = claim; - } - - mutex_unlock(&rfkill_global_mutex); - - return error ? error : count; + return -EOPNOTSUPP; } static struct device_attribute rfkill_dev_attrs[] = { diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 870032f..a3616e2 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -364,7 +364,6 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) rfkill->state = RFKILL_STATE_UNBLOCKED; rfkill->data = wimax_dev; rfkill->toggle_radio = wimax_rfkill_toggle_radio; - rfkill->user_claim_unsupported = 1; /* Initialize the input device for the hw key */ input_dev = input_allocate_device(); -- cgit v0.10.2 From fd7fbb17bec7b055fafec4d0ae3bfb4ed60cad8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Mar 2009 14:16:44 +0100 Subject: rfkill-input: remove unused code There's a lot of rfkill-input code that cannot ever be compiled and is useless until somebody needs and tests it -- therefore remove it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c index 84efde9..60a34f3 100644 --- a/net/rfkill/rfkill-input.c +++ b/net/rfkill/rfkill-input.c @@ -47,12 +47,6 @@ enum rfkill_global_sched_op { RFKILL_GLOBAL_OP_UNBLOCK, }; -/* - * Currently, the code marked with RFKILL_NEED_SWSET is inactive. - * If handling of EV_SW SW_WLAN/WWAN/BLUETOOTH/etc is needed in the - * future, when such events are added, that code will be necessary. - */ - struct rfkill_task { struct delayed_work dwork; @@ -65,14 +59,6 @@ struct rfkill_task { /* pending regular switch operations (1=pending) */ unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; -#ifdef RFKILL_NEED_SWSET - /* set operation pending (1=pending) */ - unsigned long sw_setpending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - - /* desired state for pending set operation (1=unblock) */ - unsigned long sw_newstate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; -#endif - /* should the state be complemented (1=yes) */ unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; @@ -111,24 +97,6 @@ static void __rfkill_handle_global_op(enum rfkill_global_sched_op op) } } -#ifdef RFKILL_NEED_SWSET -static void __rfkill_handle_normal_op(const enum rfkill_type type, - const bool sp, const bool s, const bool c) -{ - enum rfkill_state state; - - if (sp) - state = (s) ? RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED; - else - state = rfkill_get_global_state(type); - - if (c) - state = rfkill_state_complement(state); - - rfkill_switch_all(type, state); -} -#else static void __rfkill_handle_normal_op(const enum rfkill_type type, const bool c) { @@ -140,7 +108,6 @@ static void __rfkill_handle_normal_op(const enum rfkill_type type, rfkill_switch_all(type, state); } -#endif static void rfkill_task_handler(struct work_struct *work) { @@ -171,21 +138,11 @@ static void rfkill_task_handler(struct work_struct *work) i < RFKILL_TYPE_MAX) { if (test_and_clear_bit(i, task->sw_pending)) { bool c; -#ifdef RFKILL_NEED_SWSET - bool sp, s; - sp = test_and_clear_bit(i, - task->sw_setpending); - s = test_bit(i, task->sw_newstate); -#endif c = test_and_clear_bit(i, task->sw_togglestate); spin_unlock_irq(&task->lock); -#ifdef RFKILL_NEED_SWSET - __rfkill_handle_normal_op(i, sp, s, c); -#else __rfkill_handle_normal_op(i, c); -#endif spin_lock_irq(&task->lock); } @@ -238,32 +195,6 @@ static void rfkill_schedule_global_op(enum rfkill_global_sched_op op) spin_unlock_irqrestore(&rfkill_task.lock, flags); } -#ifdef RFKILL_NEED_SWSET -/* Use this if you need to add EV_SW SW_WLAN/WWAN/BLUETOOTH/etc handling */ - -static void rfkill_schedule_set(enum rfkill_type type, - enum rfkill_state desired_state) -{ - unsigned long flags; - - if (rfkill_is_epo_lock_active()) - return; - - spin_lock_irqsave(&rfkill_task.lock, flags); - if (!rfkill_task.global_op_pending) { - set_bit(type, rfkill_task.sw_pending); - set_bit(type, rfkill_task.sw_setpending); - clear_bit(type, rfkill_task.sw_togglestate); - if (desired_state) - set_bit(type, rfkill_task.sw_newstate); - else - clear_bit(type, rfkill_task.sw_newstate); - rfkill_schedule_ratelimited(); - } - spin_unlock_irqrestore(&rfkill_task.lock, flags); -} -#endif - static void rfkill_schedule_toggle(enum rfkill_type type) { unsigned long flags; -- cgit v0.10.2 From 07f62d01c1f476a3b328a44faafdfd103a4dedc3 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Fri, 27 Mar 2009 22:20:27 +0800 Subject: cfg80211: remove duplicated #include Remove duplicated #include in include/net/cfg80211.h. Signed-off-by: Huang Weiyi Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5389afd..d1b8f0d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -10,7 +10,6 @@ #include #include /* remove once we remove the wext stuff */ -#include /* * 802.11 configuration in-kernel interface -- cgit v0.10.2 From c0ed418977edf60f1df9933e1ccd48920a28eb66 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Fri, 27 Mar 2009 22:21:36 +0800 Subject: nl80211: remove duplicated #include Remove duplicated #include in net/wireless/core.h. Signed-off-by: Huang Weiyi Signed-off-by: John W. Linville diff --git a/net/wireless/core.h b/net/wireless/core.h index 0a592e4..fcee83a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 1778092e1739155acec35a3bccee2fb8a1ae4e91 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 27 Mar 2009 20:52:47 +0200 Subject: nl80211: Require auth type for NL80211_CMD_AUTHENTICATE NL80211_ATTR_AUTH_TYPE is a required parameter for NL80211_CMD_AUTHENTICATE. We are currently (by chance) defaulting to open system authentication if the attribute is not specified. It is better to just reject the invalid command. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2f449dd..c04df6a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2752,6 +2752,9 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; + if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2798,13 +2801,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { - req.auth_type = - nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(req.auth_type)) { - err = -EINVAL; - goto out; - } + req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(req.auth_type)) { + err = -EINVAL; + goto out; } err = drv->ops->auth(&drv->wiphy, dev, &req); -- cgit v0.10.2 From 53b46b8444f600cc1744521ea096ea0c5d494dd0 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 27 Mar 2009 20:53:56 +0200 Subject: nl80211: Generate deauth/disassoc event for locally generated frames Previously, nl80211 mlme events were generated only for received deauthentication and disassociation frames. We need to do the same for locally generated ones in order to let applications know that we disconnected (e.g., when AP does not reply to a probe). Rename the nl80211 and cfg80211 functions (s/rx_//) to make it clearer that they are used for both received and locally generated frames. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d1b8f0d..ec33096 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -917,28 +917,28 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); /** - * cfg80211_send_rx_deauth - notification of processed deauthentication + * cfg80211_send_deauth - notification of processed deauthentication * @dev: network device * @buf: deauthentication frame (header + body) * @len: length of the frame data * * This function is called whenever deauthentication has been processed in - * station mode. + * station mode. This includes both received deauthentication frames and + * locally generated ones. */ -void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, - size_t len); +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); /** - * cfg80211_send_rx_disassoc - notification of processed disassociation + * cfg80211_send_disassoc - notification of processed disassociation * @dev: network device * @buf: disassociation response frame (header + body) * @len: length of the frame data * * This function is called whenever disassociation has been processed in - * station mode. + * station mode. This includes both received disassociation frames and locally + * generated ones. */ -void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf, - size_t len); +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); /** * cfg80211_hold_bss - exclude bss from expiration diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 132938b..08db02c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -325,6 +325,10 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, /* u.deauth.reason_code == u.disassoc.reason_code */ mgmt->u.deauth.reason_code = cpu_to_le16(reason); + if (stype == IEEE80211_STYPE_DEAUTH) + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); + else + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1187,7 +1191,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_set_disassoc(sdata, true, false, 0); ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; - cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len); } @@ -1218,7 +1222,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, } ieee80211_set_disassoc(sdata, false, false, reason_code); - cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len); } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index bec5721..33ff7cc 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -28,19 +28,18 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) } EXPORT_SYMBOL(cfg80211_send_rx_assoc); -void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_rx_deauth(rdev, dev, buf, len); + nl80211_send_deauth(rdev, dev, buf, len); } -EXPORT_SYMBOL(cfg80211_send_rx_deauth); +EXPORT_SYMBOL(cfg80211_send_deauth); -void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf, - size_t len) +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_rx_disassoc(rdev, dev, buf, len); + nl80211_send_disassoc(rdev, dev, buf, len); } -EXPORT_SYMBOL(cfg80211_send_rx_disassoc); +EXPORT_SYMBOL(cfg80211_send_disassoc); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c04df6a..195424e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3415,17 +3415,16 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); } -void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, - size_t len) +void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, size_t len) { nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_DEAUTHENTICATE); } -void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, - size_t len) +void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len) { nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_DISASSOCIATE); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b77af4a..55686fc 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -17,11 +17,11 @@ extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len); -extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *buf, size_t len); -extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *buf, size_t len); +extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); +extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); #endif /* __NET_WIRELESS_NL80211_H */ -- cgit v0.10.2 From a3b8b0569fbef725597f05278ec58083321f6e9d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 27 Mar 2009 21:59:49 +0200 Subject: nl80211: Add Michael MIC failure event Define a new nl80211 event, NL80211_CMD_MICHAEL_MIC_FAILURE, to be used to notify user space about locally detected Michael MIC failures. This matches with the MLME-MICHAELMICFAILURE.indication() primitive. Since we do not actually have TSC in the skb anymore when mac80211_ev_michael_mic_failure() is called, that function is changed to take in the TSC as an optional parameter instead of as a requirement to include the TSC after the hdr field (which we did not really follow). For now, TSC is not included in the events from mac80211, but it could be added at some point. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index cbe8ce3..27f230f 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -199,6 +199,14 @@ * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives). * + * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael + * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the + * event includes %NL80211_ATTR_MAC to describe the source MAC address of + * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key + * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and + * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this + * event matches with MLME-MICHAELMICFAILURE.indication() primitive + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -260,6 +268,8 @@ enum nl80211_commands { NL80211_CMD_DEAUTHENTICATE, NL80211_CMD_DISASSOCIATE, + NL80211_CMD_MICHAEL_MIC_FAILURE, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -408,6 +418,9 @@ enum nl80211_commands { * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and * %NL80211_CMD_DISASSOCIATE, u16 * + * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as + * a u32 + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -492,6 +505,8 @@ enum nl80211_attrs { NL80211_ATTR_AUTH_TYPE, NL80211_ATTR_REASON_CODE, + NL80211_ATTR_KEY_TYPE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1062,4 +1077,17 @@ enum nl80211_auth_type { NL80211_AUTHTYPE_FT, NL80211_AUTHTYPE_NETWORK_EAP, }; + +/** + * enum nl80211_key_type - Key Type + * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key + * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key + * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS) + */ +enum nl80211_key_type { + NL80211_KEYTYPE_GROUP, + NL80211_KEYTYPE_PAIRWISE, + NL80211_KEYTYPE_PEERKEY, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ec33096..f8bf0c8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -957,4 +957,20 @@ void cfg80211_hold_bss(struct cfg80211_bss *bss); */ void cfg80211_unhold_bss(struct cfg80211_bss *bss); +/** + * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) + * @dev: network device + * @addr: The source MAC address of the frame + * @key_type: The key type that the received frame used + * @key_id: Key identifier (0..3) + * @tsc: The TSC value of the frame that generated the MIC failure (6 octets) + * + * This function is called whenever the local MAC detects a MIC failure in a + * received frame. This matches with MLME-MICHAELMICFAILURE.indication() + * primitive. + */ +void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc); + #endif /* __NET_CFG80211_H */ diff --git a/net/mac80211/event.c b/net/mac80211/event.c index 0d95561..f288d01 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -12,12 +12,12 @@ #include "ieee80211_i.h" /* - * indicate a failed Michael MIC to userspace; the passed packet - * (in the variable hdr) must be long enough to extract the TKIP - * fields like TSC + * Indicate a failed Michael MIC to userspace. If the caller knows the TSC of + * the frame that generated the MIC failure (i.e., if it was provided by the + * driver or is still in the frame), it should provide that information. */ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr *hdr, const u8 *tsc) { union iwreq_data wrqu; char *buf = kmalloc(128, GFP_ATOMIC); @@ -34,8 +34,9 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke kfree(buf); } - /* - * TODO: re-add support for sending MIC failure indication - * with all info via nl80211 - */ + cfg80211_michael_mic_failure(sdata->dev, hdr->addr2, + (hdr->addr1[0] & 0x01) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE, + keyidx, tsc); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e6ed78c..312347d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1060,7 +1060,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int rate, int erp, int short_preamble); void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr); + struct ieee80211_hdr *hdr, const u8 *tsc); void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int encrypt); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5fa7aed..19c4b45 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1932,7 +1932,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, !ieee80211_is_auth(hdr->frame_control)) goto ignore; - mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr); + mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL); ignore: dev_kfree_skb(rx->skb); rx->skb = NULL; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 4f8bfea..dcfae88 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -122,7 +122,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, - (void *) skb->data); + (void *) skb->data, NULL); return RX_DROP_UNUSABLE; } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 33ff7cc..1407244 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -43,3 +43,13 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) nl80211_send_disassoc(rdev, dev, buf, len); } EXPORT_SYMBOL(cfg80211_send_disassoc); + +void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc); +} +EXPORT_SYMBOL(cfg80211_michael_mic_failure); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 195424e..1394115 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3430,6 +3430,46 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, NL80211_CMD_DISASSOCIATE); } +void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + if (addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); + if (tsc) + NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + /* initialisation/exit functions */ int nl80211_init(void) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 55686fc..e4b92cc 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -23,5 +23,10 @@ extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev, extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len); +extern void +nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, + int key_id, const u8 *tsc); #endif /* __NET_WIRELESS_NL80211_H */ -- cgit v0.10.2 From 295936c56672e82369c6d989e27d3a87495808e4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 27 Mar 2009 17:21:05 -0400 Subject: ath9k: Update maintainers for ath9k This has been the case really, we just forgot to update it. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 2dc197c..6dfcb6d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -888,6 +888,12 @@ P: Luis R. Rodriguez M: lrodriguez@atheros.com P: Jouni Malinen M: jmalinen@atheros.com +P: Sujith Manoharan +M: Sujith.Manoharan@atheros.com +P: Vasanthakumar Thiagarajan +M: vasanth@atheros.com +P: Senthil Balasubramanian +M: senthilkumar@atheros.com L: linux-wireless@vger.kernel.org L: ath9k-devel@lists.ath9k.org S: Supported -- cgit v0.10.2 From 807e37394b5a1dc23a2908b59f34edbbae67e9ea Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 27 Mar 2009 17:47:27 -0400 Subject: ath5k: fix scanning in AR2424 AR5K_PHY_PLL_40MHZ_5413 should not be ORed with AR5K_PHY_MODE_RAD_RF5112 for 5 GHz channels. The incorrect PLL value breaks scanning in the countries where 5 GHz channels are allowed. Signed-off-by: Pavel Roskin Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index cb5e15f..775fdf7 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -358,7 +358,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) mode |= AR5K_PHY_MODE_FREQ_5GHZ; if (ah->ah_radio == AR5K_RF5413) - clock |= AR5K_PHY_PLL_40MHZ_5413; + clock = AR5K_PHY_PLL_40MHZ_5413; else clock |= AR5K_PHY_PLL_40MHZ; -- cgit v0.10.2 From 32c1628f153a5468cf48be5e5c04cd599ae9e01d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 28 Mar 2009 01:46:14 +0100 Subject: ar9170: fix hang on stop This patch fixes a locking problem which freezes the network core. The deadlock goes as follows: - ar9170_op_stop - is called 1. change the state to IDLE 2. > take the MUTEX < 3. cancel_SYNC all pending work, which means "block until a work_struct's callback has terminated" => if filter_config_work was queued it tries to get the MUTEX, before checking the device state... Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ar9170/main.c index 5996ff9..5f55754 100644 --- a/drivers/net/wireless/ar9170/main.c +++ b/drivers/net/wireless/ar9170/main.c @@ -742,8 +742,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) if (IS_STARTED(ar)) ar->state = AR9170_IDLE; - mutex_lock(&ar->mutex); + flush_workqueue(ar->hw->workqueue); + mutex_lock(&ar->mutex); cancel_delayed_work_sync(&ar->tx_status_janitor); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); @@ -1123,10 +1124,10 @@ static void ar9170_set_filters(struct work_struct *work) filter_config_work); int err; - mutex_lock(&ar->mutex); if (unlikely(!IS_STARTED(ar))) - goto unlock; + return ; + mutex_lock(&ar->mutex); if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { err = ar9170_set_operating_mode(ar); if (err) -- cgit v0.10.2 From 440ddadaee6d0d5e8a7ee53ac913f78a8e5570a1 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 28 Mar 2009 20:51:24 +0100 Subject: rt2x00: Move Move pci_dev specific access to rt2x00pci pci_dev->irq and pci_name(pci_dev) access should be limited to rt2x00pci only. This is more generic and allows a rt2x00 pci driver to be controlled as PCI device but also as platform driver (needed for rt2800pci SoC support). Signed-off-by: Felix Fietkau Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0f08773..411eb9c 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1361,7 +1361,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2460, value, reg); + rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && !rt2x00_rf(&rt2x00dev->chip, RF2421)) { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 276a823..e1be67c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1525,7 +1525,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2560, value, reg); + rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && !rt2x00_rf(&rt2x00dev->chip, RF2523) && diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 84bd6f1..e03d699 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -672,6 +672,12 @@ struct rt2x00_dev { unsigned long flags; /* + * Device information, Bus IRQ and name (PCI, SoC) + */ + int irq; + const char *name; + + /* * Chipset identification. */ struct rt2x00_chip chip; @@ -860,6 +866,18 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, rt2x00dev->chip.rev = rev; } +static inline void rt2x00_set_chip_rt(struct rt2x00_dev *rt2x00dev, + const u16 rt) +{ + rt2x00dev->chip.rt = rt; +} + +static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev, + const u16 rf, const u32 rev) +{ + rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev); +} + static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) { return (chipset->rt == chip); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 9730b4f..cdd5154 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -170,7 +170,6 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) { - struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); struct data_queue *queue; int status; @@ -186,11 +185,11 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) /* * Register interrupt handler. */ - status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler, - IRQF_SHARED, pci_name(pci_dev), rt2x00dev); + status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler, + IRQF_SHARED, rt2x00dev->name, rt2x00dev); if (status) { ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", - pci_dev->irq, status); + rt2x00dev->irq, status); goto exit; } @@ -270,6 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; + u16 chip; retval = pci_request_regions(pci_dev, pci_name(pci_dev)); if (retval) { @@ -307,6 +307,14 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) rt2x00dev->dev = &pci_dev->dev; rt2x00dev->ops = ops; rt2x00dev->hw = hw; + rt2x00dev->irq = pci_dev->irq; + rt2x00dev->name = pci_name(pci_dev); + + /* + * Determine RT chipset by reading PCI header. + */ + pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip); + rt2x00_set_chip_rt(rt2x00dev, chip); retval = rt2x00pci_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2ca8b7a..4346cd1 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2308,7 +2308,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) u32 reg; u16 value; u16 eeprom; - u16 device; /* * Read EEPROM word for configuration. @@ -2317,14 +2316,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Identify RF chipset. - * To determine the RT chip we have to read the - * PCI header of the device. */ - pci_read_config_word(to_pci_dev(rt2x00dev->dev), - PCI_CONFIG_HEADER_DEVICE, &device); value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, device, value, reg); + rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && !rt2x00_rf(&rt2x00dev->chip, RF5325) && diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 41e8959..6c71f77 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -63,12 +63,6 @@ */ /* - * PCI Configuration Header - */ -#define PCI_CONFIG_HEADER_VENDOR 0x0000 -#define PCI_CONFIG_HEADER_DEVICE 0x0002 - -/* * HOST_CMD_CSR: For HOST to interrupt embedded processor */ #define HOST_CMD_CSR 0x0008 -- cgit v0.10.2 From a57e2e84b65d1b89c4b1effeceb27b181226b950 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 28 Mar 2009 20:51:41 +0100 Subject: rt2x00: Fix Sparse warning rt2x00link_reset_qual() is not declared in a header, and is only internally used within rt2x00link.c. It should be declared as static. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 7eb5cd7..eb9b981 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -387,7 +387,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna) rt2x00link_antenna_reset(rt2x00dev); } -void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev) +static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev) { struct link_qual *qual = &rt2x00dev->link.qual; -- cgit v0.10.2 From 616de35da94df8748771a014ef898360d5f4d0c8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 29 Mar 2009 13:19:31 +0200 Subject: b43: Do not "select" HW_RANDOM Auto-depend on HW_RANDOM, rather than "select"ing it. This way the user has the choice to enable or disable HWRNG support. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index aab71a7..21572e4 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -3,7 +3,6 @@ config B43 depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA select SSB select FW_LOADER - select HW_RANDOM ---help--- b43 is a driver for the Broadcom 43xx series wireless devices. @@ -106,6 +105,13 @@ config B43_RFKILL depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) default y +# This config option automatically enables b43 HW-RNG support, +# if the HW-RNG core is enabled. +config B43_HWRNG + bool + depends on B43 && (HW_RANDOM = y || HW_RANDOM = B43) + default y + config B43_DEBUG bool "Broadcom 43xx debugging" depends on B43 diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index beaf18d..cc1db7e 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -625,9 +625,11 @@ struct b43_wl { /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; +#ifdef CONFIG_B43_HWRNG struct hwrng rng; - u8 rng_initialized; + bool rng_initialized; char rng_name[30 + 1]; +#endif /* CONFIG_B43_HWRNG */ /* The RF-kill button */ struct b43_rfkill rfkill; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 79b685e..09e0c60 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2980,6 +2980,7 @@ static void b43_security_init(struct b43_wldev *dev) b43_clear_keys(dev); } +#ifdef CONFIG_B43_HWRNG static int b43_rng_read(struct hwrng *rng, u32 *data) { struct b43_wl *wl = (struct b43_wl *)rng->priv; @@ -2995,17 +2996,21 @@ static int b43_rng_read(struct hwrng *rng, u32 *data) return (sizeof(u16)); } +#endif /* CONFIG_B43_HWRNG */ static void b43_rng_exit(struct b43_wl *wl) { +#ifdef CONFIG_B43_HWRNG if (wl->rng_initialized) hwrng_unregister(&wl->rng); +#endif /* CONFIG_B43_HWRNG */ } static int b43_rng_init(struct b43_wl *wl) { - int err; + int err = 0; +#ifdef CONFIG_B43_HWRNG snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); wl->rng.name = wl->rng_name; @@ -3018,6 +3023,7 @@ static int b43_rng_init(struct b43_wl *wl) b43err(wl, "Failed to register the random " "number generator (%d)\n", err); } +#endif /* CONFIG_B43_HWRNG */ return err; } -- cgit v0.10.2 From 8782b41d13c8e5f9a201477d3c15edf9fe7c372c Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Mon, 30 Mar 2009 14:17:00 +0530 Subject: ath9k: No need to abort Rx path when autosleep is enabled. For chipsets supporting autosleep feature, there is no need to abort Rx engine since they are capable of automatically going back to sleep after receiving a packet. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0607df2..97cf83f 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -2325,26 +2325,33 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ieee80211_conf *conf = &hw->conf; + struct ath_hw *ah = sc->sc_ah; mutex_lock(&sc->mutex); if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { - sc->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + if (!(ah->caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { + sc->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } + ath9k_hw_setrxabort(sc->sc_ah, 1); } - ath9k_hw_setrxabort(sc->sc_ah, 1); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); } else { ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; - if (sc->imask & ATH9K_INT_TIM_TIMER) { - sc->imask &= ~ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + if (!(ah->caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + ath9k_hw_setrxabort(sc->sc_ah, 0); + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + if (sc->imask & ATH9K_INT_TIM_TIMER) { + sc->imask &= ~ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } } } } -- cgit v0.10.2 From bdbdf46daa6dccb472f56559854477faddc44de9 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:22 +0530 Subject: ath9k: Remove a few unused flags This patch removes unused HW capability flags and HW operation variables, and a chainmask flag that we don't use anywhere. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 7b1b40a..1dfc381 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -525,19 +525,18 @@ struct ath_rfkill { #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_PREAMBLE_SHORT BIT(6) -#define SC_OP_PROTECT_ENABLE BIT(7) -#define SC_OP_RXFLUSH BIT(8) -#define SC_OP_LED_ASSOCIATED BIT(9) -#define SC_OP_RFKILL_REGISTERED BIT(10) -#define SC_OP_RFKILL_SW_BLOCKED BIT(11) -#define SC_OP_RFKILL_HW_BLOCKED BIT(12) -#define SC_OP_WAIT_FOR_BEACON BIT(13) -#define SC_OP_LED_ON BIT(14) -#define SC_OP_SCANNING BIT(15) -#define SC_OP_TSF_RESET BIT(16) +#define SC_OP_FULL_RESET BIT(4) +#define SC_OP_PREAMBLE_SHORT BIT(5) +#define SC_OP_PROTECT_ENABLE BIT(6) +#define SC_OP_RXFLUSH BIT(7) +#define SC_OP_LED_ASSOCIATED BIT(8) +#define SC_OP_RFKILL_REGISTERED BIT(9) +#define SC_OP_RFKILL_SW_BLOCKED BIT(10) +#define SC_OP_RFKILL_HW_BLOCKED BIT(11) +#define SC_OP_WAIT_FOR_BEACON BIT(12) +#define SC_OP_LED_ON BIT(13) +#define SC_OP_SCANNING BIT(14) +#define SC_OP_TSF_RESET BIT(15) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index b15eaf8..13d8c2a 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -363,10 +363,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; ah->config.pcie_powersave_enable = 0; - ah->config.pcie_l1skp_enable = 0; ah->config.pcie_clock_req = 0; - ah->config.pcie_power_reset = 0x100; - ah->config.pcie_restore = 0; ah->config.pcie_waen = 0; ah->config.analog_shiftreg = 1; ah->config.ht_enable = 1; @@ -375,13 +372,6 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.cck_trig_high = 200; ah->config.cck_trig_low = 100; ah->config.enable_ani = 1; - ah->config.noise_immunity_level = 4; - ah->config.ofdm_weaksignal_det = 1; - ah->config.cck_weaksignal_thr = 0; - ah->config.spur_immunity_level = 2; - ah->config.firstep_level = 0; - ah->config.rssi_thr_high = 40; - ah->config.rssi_thr_low = 7; ah->config.diversity_control = 0; ah->config.antenna_switch_swap = 0; @@ -3343,8 +3333,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - if (ah->config.ht_enable) pCap->hw_caps |= ATH9K_HW_CAP_HT; else @@ -3368,7 +3356,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->keycache_size = AR_KEYTABLE_SIZE; pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->num_mr_retries = 4; pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; if (AR_SREV_9285_10_OR_LATER(ah)) @@ -3378,14 +3365,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->num_gpio_pins = AR_NUM_GPIO; - if (AR_SREV_9280_10_OR_LATER(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_WOW; - pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } else { - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { pCap->hw_caps |= ATH9K_HW_CAP_CST; pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 0b594e0..5ba6a4b 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -124,29 +124,24 @@ enum wireless_mode { }; enum ath9k_hw_caps { - ATH9K_HW_CAP_CHAN_SPREAD = BIT(0), - ATH9K_HW_CAP_MIC_AESCCM = BIT(1), - ATH9K_HW_CAP_MIC_CKIP = BIT(2), - ATH9K_HW_CAP_MIC_TKIP = BIT(3), - ATH9K_HW_CAP_CIPHER_AESCCM = BIT(4), - ATH9K_HW_CAP_CIPHER_CKIP = BIT(5), - ATH9K_HW_CAP_CIPHER_TKIP = BIT(6), - ATH9K_HW_CAP_VEOL = BIT(7), - ATH9K_HW_CAP_BSSIDMASK = BIT(8), - ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(9), - ATH9K_HW_CAP_CHAN_HALFRATE = BIT(10), - ATH9K_HW_CAP_CHAN_QUARTERRATE = BIT(11), - ATH9K_HW_CAP_HT = BIT(12), - ATH9K_HW_CAP_GTT = BIT(13), - ATH9K_HW_CAP_FASTCC = BIT(14), - ATH9K_HW_CAP_RFSILENT = BIT(15), - ATH9K_HW_CAP_WOW = BIT(16), - ATH9K_HW_CAP_CST = BIT(17), - ATH9K_HW_CAP_ENHANCEDPM = BIT(18), - ATH9K_HW_CAP_AUTOSLEEP = BIT(19), - ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(20), - ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT = BIT(21), - ATH9K_HW_CAP_BT_COEX = BIT(22) + ATH9K_HW_CAP_MIC_AESCCM = BIT(0), + ATH9K_HW_CAP_MIC_CKIP = BIT(1), + ATH9K_HW_CAP_MIC_TKIP = BIT(2), + ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3), + ATH9K_HW_CAP_CIPHER_CKIP = BIT(4), + ATH9K_HW_CAP_CIPHER_TKIP = BIT(5), + ATH9K_HW_CAP_VEOL = BIT(6), + ATH9K_HW_CAP_BSSIDMASK = BIT(7), + ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8), + ATH9K_HW_CAP_HT = BIT(9), + ATH9K_HW_CAP_GTT = BIT(10), + ATH9K_HW_CAP_FASTCC = BIT(11), + ATH9K_HW_CAP_RFSILENT = BIT(12), + ATH9K_HW_CAP_CST = BIT(13), + ATH9K_HW_CAP_ENHANCEDPM = BIT(14), + ATH9K_HW_CAP_AUTOSLEEP = BIT(15), + ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16), + ATH9K_HW_CAP_BT_COEX = BIT(17) }; enum ath9k_capability_type { @@ -166,7 +161,6 @@ struct ath9k_hw_capabilities { u16 keycache_size; u16 low_5ghz_chan, high_5ghz_chan; u16 low_2ghz_chan, high_2ghz_chan; - u16 num_mr_retries; u16 rts_aggr_limit; u8 tx_chainmask; u8 rx_chainmask; @@ -184,11 +178,8 @@ struct ath9k_ops_config { int ack_6mb; int cwm_ignore_extcca; u8 pcie_powersave_enable; - u8 pcie_l1skp_enable; u8 pcie_clock_req; u32 pcie_waen; - int pcie_power_reset; - u8 pcie_restore; u8 analog_shiftreg; u8 ht_enable; u32 ofdm_trig_low; @@ -196,13 +187,6 @@ struct ath9k_ops_config { u32 cck_trig_high; u32 cck_trig_low; u32 enable_ani; - u8 noise_immunity_level; - u32 ofdm_weaksignal_det; - u32 cck_weaksignal_thr; - u8 spur_immunity_level; - u8 firstep_level; - int8_t rssi_thr_high; - int8_t rssi_thr_low; u16 diversity_control; u16 antenna_switch_swap; int serialize_regmode; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 97cf83f..74fe777 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -287,7 +287,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, } spin_unlock_bh(&sc->sc_resetlock); - sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; sc->sc_flags &= ~SC_OP_FULL_RESET; if (ath_startrecv(sc) != 0) { @@ -416,7 +415,6 @@ set_timer: */ void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; if (is_ht || (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 199a3ce57..ec72dd2 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -24,7 +24,6 @@ struct ath_softc; #define ATH_RATE_MAX 30 #define RATE_TABLE_SIZE 64 #define MAX_TX_RATE_PHY 48 -#define WLAN_CTRL_FRAME_SIZE (2+2+6+4) /* VALID_ALL - valid for 20/40/Legacy, * VALID - Legacy only, -- cgit v0.10.2 From 6ed6a05e5c8061cdcd69a418c90c5f11979ce650 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:24 +0530 Subject: ath9k: Remove redundant chainmask check We get the valid chainmasks on HW attach, checking it again during reset is redundant. This patch removes the check. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 13d8c2a..22ef93f 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -2189,14 +2189,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->txchainmask = sc->tx_chainmask; ah->rxchainmask = sc->rx_chainmask; - if (AR_SREV_9285(ah)) { - ah->txchainmask &= 0x1; - ah->rxchainmask &= 0x1; - } else if (AR_SREV_9280(ah)) { - ah->txchainmask &= 0x3; - ah->rxchainmask &= 0x3; - } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; -- cgit v0.10.2 From d8baa9392666d1c50ef42e9f6fbbb0cf536327b9 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:25 +0530 Subject: ath9k: Cleanup debug messages Clean debug messages to use appropriate levels, remove useless messages, and trim the number of debug levels. Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c index 6c5e887..1aeafb5 100644 --- a/drivers/net/wireless/ath9k/ani.c +++ b/drivers/net/wireless/ath9k/ani.c @@ -569,8 +569,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, DPRINTF(ah->ah_sc, ATH_DBG_ANI, "phyCnt1 0x%x, resetting " "counter value to 0x%x\n", - phyCnt1, - aniState->ofdmPhyErrBase); + phyCnt1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_1, @@ -580,8 +579,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, DPRINTF(ah->ah_sc, ATH_DBG_ANI, "phyCnt2 0x%x, resetting " "counter value to 0x%x\n", - phyCnt2, - aniState->cckPhyErrBase); + phyCnt2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_2, @@ -667,7 +665,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 cc = REG_READ(ah, AR_CCCNT); if (cycles == 0 || cycles > cc) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "cycle counter wrap. ExtBusy = 0\n"); good = 0; } else { diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index ec99573..5b2752b 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -43,7 +43,7 @@ static int ath_beaconq_config(struct ath_softc *sc) if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "unable to update h/w beacon queue parameters\n"); + "Unable to update h/w beacon queue parameters\n"); return 0; } else { ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); @@ -132,11 +132,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, avp = (void *)vif->drv_priv; cabq = sc->beacon.cabq; - if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", - avp, avp->av_bcbuf); + if (avp->av_bcbuf == NULL) return NULL; - } /* Release the old beacon first */ diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath9k/debug.h index 7b0e541..23298b9 100644 --- a/drivers/net/wireless/ath9k/debug.h +++ b/drivers/net/wireless/ath9k/debug.h @@ -19,20 +19,16 @@ enum ATH_DEBUG { ATH_DBG_RESET = 0x00000001, - ATH_DBG_REG_IO = 0x00000002, - ATH_DBG_QUEUE = 0x00000004, - ATH_DBG_EEPROM = 0x00000008, - ATH_DBG_CALIBRATE = 0x00000010, - ATH_DBG_CHANNEL = 0x00000020, - ATH_DBG_INTERRUPT = 0x00000040, - ATH_DBG_REGULATORY = 0x00000080, - ATH_DBG_ANI = 0x00000100, - ATH_DBG_POWER_MGMT = 0x00000200, - ATH_DBG_XMIT = 0x00000400, - ATH_DBG_BEACON = 0x00001000, - ATH_DBG_CONFIG = 0x00002000, - ATH_DBG_KEYCACHE = 0x00004000, - ATH_DBG_FATAL = 0x00008000, + ATH_DBG_QUEUE = 0x00000002, + ATH_DBG_EEPROM = 0x00000004, + ATH_DBG_CALIBRATE = 0x00000008, + ATH_DBG_INTERRUPT = 0x00000010, + ATH_DBG_REGULATORY = 0x00000020, + ATH_DBG_ANI = 0x00000040, + ATH_DBG_XMIT = 0x00000080, + ATH_DBG_BEACON = 0x00000100, + ATH_DBG_CONFIG = 0x00000200, + ATH_DBG_FATAL = 0x00000400, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index ffc36b0..44fee5a 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -783,11 +783,11 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC: Chain %d | " "PDADC %3d Value %3d | " "PDADC %3d Value %3d | " @@ -910,7 +910,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, @@ -918,7 +918,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " "chan %d\n", @@ -941,7 +941,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, IS_CHAN_2GHZ(chan), AR5416_EEP4K_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " MATCH-EE_IDX %d: ch %d is2 %d " "2xMinEdge %d chainmask %d chains %d\n", i, freq, IS_CHAN_2GHZ(chan), @@ -961,7 +961,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " SEL-Min ctlMode %d pCtlMode %d " "2xMaxEdge %d sP %d minCtlPwr %d\n", ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, @@ -2234,11 +2234,11 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC: Chain %d | PDADC %3d " "Value %3d | PDADC %3d Value %3d | " "PDADC %3d Value %3d | PDADC %3d " @@ -2415,14 +2415,14 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " "chan %d\n", @@ -2441,7 +2441,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " MATCH-EE_IDX %d: ch %d is2 %d " "2xMinEdge %d chainmask %d chains %d\n", i, freq, IS_CHAN_2GHZ(chan), @@ -2460,7 +2460,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, minCtlPower = min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " SEL-Min ctlMode %d pCtlMode %d " "2xMaxEdge %d sP %d minCtlPwr %d\n", ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 22ef93f..169d8ef 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -97,7 +97,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) udelay(AH_TIME_QUANTUM); } - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", timeout, reg, REG_READ(ah, reg), mask, val); @@ -181,7 +181,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Unknown phy %u (rate ix %u)\n", rates->info[rateix].phy, rateix); txTime = 0; @@ -306,7 +306,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (rdData != wrData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", addr, wrData, rdData); @@ -318,7 +318,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (wrData != rdData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", addr, wrData, rdData); @@ -453,8 +453,8 @@ static int ath9k_hw_rfattach(struct ath_hw *ah) rfStatus = ath9k_hw_init_rf(ah, &ecode); if (!rfStatus) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "RF setup failed, status %u\n", ecode); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "RF setup failed, status: %u\n", ecode); return ecode; } @@ -478,10 +478,9 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah) case AR_RAD2122_SREV_MAJOR: break; default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "5G Radio Chip Rev 0x%02X is not " - "supported by this driver\n", - ah->hw_version.analog5GhzRev); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Radio Chip Rev 0x%02X not supported\n", + val & AR_RADIO_SREV_MAJOR); return -EOPNOTSUPP; } @@ -503,12 +502,8 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah) ah->macaddr[2 * i] = eeval >> 8; ah->macaddr[2 * i + 1] = eeval & 0xff; } - if (sum == 0 || sum == 0xffff * 3) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "mac address read failed: %pM\n", - ah->macaddr); + if (sum == 0 || sum == 0xffff * 3) return -EADDRNOTAVAIL; - } return 0; } @@ -565,11 +560,8 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) { int ecode; - if (!ath9k_hw_chip_test(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "hardware self-test failed\n"); + if (!ath9k_hw_chip_test(ah)) return -ENODEV; - } ecode = ath9k_hw_rf_claim(ah); if (ecode != 0) @@ -611,13 +603,13 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ah->intr_mitigation = true; if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(sc, ATH_DBG_RESET, "Couldn't reset chip\n"); + DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); ecode = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(sc, ATH_DBG_RESET, "Couldn't wakeup chip\n"); + DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); ecode = -EIO; goto bad; } @@ -640,7 +632,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { - DPRINTF(sc, ATH_DBG_RESET, + DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); @@ -680,10 +672,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (AR_SREV_9280_10_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - DPRINTF(sc, ATH_DBG_RESET, - "This Mac Chip Rev 0x%02x.%x is \n", - ah->hw_version.macVersion, ah->hw_version.macRev); - if (AR_SREV_9285_12_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, @@ -875,8 +863,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ecode = ath9k_hw_init_macaddr(ah); if (ecode != 0) { - DPRINTF(sc, ATH_DBG_RESET, - "failed initializing mac address\n"); + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to initialize MAC address\n"); goto bad; } @@ -1193,23 +1181,23 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, switch (ah->hw_version.devid) { case AR9280_DEVID_PCI: if (reg == 0x7894) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ini VAL: %x EEPROM: %x\n", value, (pBase->version & 0xff)); if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PWDCLKIND: %d\n", pBase->pwdclkind); value &= ~AR_AN_TOP2_PWDCLKIND; value |= AR_AN_TOP2_PWDCLKIND & (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); } else { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PWDCLKIND Earlier Rev\n"); } - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "final ini VAL: %x\n", value); } break; @@ -1356,13 +1344,13 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, min((u32) MAX_RATE_POWER, (u32) ah->regulatory.power_limit)); if (status != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "error init'ing transmit power\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Error initializing transmit power\n"); return -EIO; } if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "ar5416SetRfRegs failed\n"); return -EIO; } @@ -1668,7 +1656,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Could not kill baseband RX\n"); return false; } @@ -1677,14 +1665,14 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, if (AR_SREV_9280_10_OR_LATER(ah)) { if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "failed to set channel\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Failed to set channel\n"); return false; } } else { if (!(ath9k_hw_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "failed to set channel\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Failed to set channel\n"); return false; } } @@ -1696,7 +1684,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, min((u32) MAX_RATE_POWER, (u32) ah->regulatory.power_limit)) != 0) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "error init'ing transmit power\n"); + "Error initializing transmit power\n"); return false; } @@ -2224,7 +2212,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_mark_phy_inactive(ah); if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n"); return -EINVAL; } @@ -2367,8 +2355,8 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) u32 keyType; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "entry %u out of range\n", entry); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); return false; } @@ -2404,8 +2392,8 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) u32 macHi, macLo; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "entry %u out of range\n", entry); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); return false; } @@ -2436,8 +2424,8 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, u32 keyType; if (entry >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "entry %u out of range\n", entry); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keycache entry %u out of range\n", entry); return false; } @@ -2447,7 +2435,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, break; case ATH9K_CIPHER_AES_CCM: if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "AES-CCM not supported by mac rev 0x%x\n", ah->hw_version.macRev); return false; @@ -2458,14 +2446,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_TKIP; if (ATH9K_IS_MIC_ENABLED(ah) && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "entry %u inappropriate for TKIP\n", entry); return false; } break; case ATH9K_CIPHER_WEP: if (k->kv_len < LEN_WEP40) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "WEP key length %u too small\n", k->kv_len); return false; } @@ -2480,7 +2468,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_CLR; break; default: - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "cipher %u not supported\n", k->kv_type); return false; } @@ -2698,7 +2686,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) AR_RTC_FORCE_WAKE_EN); } if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); return false; } @@ -2719,9 +2707,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) "UNDEFINED" }; - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", - modes[ah->power_mode], modes[mode], - setChip ? "set chip " : ""); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", + modes[ah->power_mode], modes[mode]); switch (mode) { case ATH9K_PM_AWAKE: @@ -2735,7 +2722,7 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) ath9k_set_power_network_sleep(ah, setChip); break; default: - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Unknown power mode %u\n", mode); return false; } diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index e0a6dee..8ae4ec2 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c @@ -49,7 +49,7 @@ bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); @@ -110,13 +110,15 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + "inactive queue: %u\n", q); return false; } @@ -146,7 +148,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) break; DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "TSF have moved while trying to set " + "TSF has moved while trying to set " "quiet time TSF: 0x%08x\n", tsfLow); } @@ -158,8 +160,8 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) wait = wait_time; while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "Failed to stop Tx DMA in 100 " + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "Failed to stop TX DMA in 100 " "msec after killing last frame\n"); break; } @@ -454,17 +456,19 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + "inactive queue: %u\n", q); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); qi->tqi_ver = qinfo->tqi_ver; qi->tqi_subtype = qinfo->tqi_subtype; @@ -521,13 +525,15 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + "inactive queue: %u\n", q); return false; } @@ -575,22 +581,23 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, ATH9K_TX_QUEUE_INACTIVE) break; if (q == pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "no available tx queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "No available TX queue\n"); return -1; } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n", + type); return -1; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); qi = &ah->txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "tx queue %u already active\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "TX queue: %u already active\n", q); return -1; } memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -620,16 +627,18 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + "inactive queue: %u\n", q); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; ah->txok_interrupt_mask &= ~(1 << q); @@ -650,17 +659,19 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) u32 cwMin, chanCwMin, value; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + "inactive queue: %u\n", q); return true; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { if (chan && IS_CHAN_B(chan)) @@ -894,7 +905,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) reg = REG_READ(ah, AR_OBS_BUS_1); DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "rx failed to go idle in 10 ms RXSM=0x%x\n", reg); + "RX failed to go idle in 10 ms RXSM=0x%x\n", reg); return false; } @@ -949,8 +960,8 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) } if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "dma failed to stop in %d ms " + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "DMA failed to stop in %d ms " "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, REG_READ(ah, AR_CR), diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 74fe777..1b43cb4 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -674,7 +674,7 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */ - DPRINTF(sc, ATH_DBG_KEYCACHE, + DPRINTF(sc, ATH_DBG_FATAL, "Setting TX MIC Key Failed\n"); return 0; } @@ -1400,7 +1400,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* Get the hardware key cache size. */ sc->keymax = ah->caps.keycache_size; if (sc->keymax > ATH_KEYMAX) { - DPRINTF(sc, ATH_DBG_KEYCACHE, + DPRINTF(sc, ATH_DBG_ANY, "Warning, using only %u entries in %u key cache\n", ATH_KEYMAX, sc->keymax); sc->keymax = ATH_KEYMAX; @@ -2602,7 +2602,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n"); switch (cmd) { case SET_KEY: diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index 8bcba90..5ec9ce9 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c @@ -46,7 +46,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ((freq - 704) * 2 - 3040) / 10; bModeSynth = 1; } else { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); return false; } @@ -79,7 +79,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); aModeRefSel = ath9k_hw_reverse_bits(1, 2); } else { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); return false; } diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 0f7f8e0..296d0e9 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -556,9 +556,6 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int r; \ for (r = 0; r < ((iniarray)->ia_rows); r++) { \ REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, \ - "RF 0x%x V 0x%x\n", \ - INI_RA((iniarray), r, 0), (regData)[r]); \ DO_DELAY(regWr); \ } \ } while (0) diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index dd1f301..efa57ae 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -320,7 +320,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on RX init\n"); error = -ENOMEM; break; @@ -675,7 +675,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on RX\n"); break; } -- cgit v0.10.2 From eef7a57430c83b0419ba943bb1650ed5c349d454 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:28 +0530 Subject: ath9k: Change return value of ath9k_hw_fill_cap_info This routine always return true, checking for false in the return value is invalid. Fix this. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 169d8ef..4ad1508 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -837,11 +837,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (AR_SREV_9280_20(ah)) ath9k_hw_init_txgain_ini(ah); - if (!ath9k_hw_fill_cap_info(ah)) { - DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n"); - ecode = -EINVAL; - goto bad; - } + ath9k_hw_fill_cap_info(ah); if ((ah->hw_version.devid == AR9280_DEVID_PCI) && test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { @@ -3228,7 +3224,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, /* HW Capabilities */ /*******************/ -bool ath9k_hw_fill_cap_info(struct ath_hw *ah) +void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; u16 capField = 0, eeval; @@ -3403,8 +3399,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->btactive_gpio = 6; ah->wlanactive_gpio = 5; } - - return true; } bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 5ba6a4b..c50faae 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -557,7 +557,7 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); -bool ath9k_hw_fill_cap_info(struct ath_hw *ah); +void ath9k_hw_fill_cap_info(struct ath_hw *ah); bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result); bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, -- cgit v0.10.2 From 0ef1f168b6bc82b0b157c568e764b75961867970 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:35 +0530 Subject: ath9k: Remove redundant variable for Interrupt Mitigation The state is already stored in ath9k_ops_config, so remove the duplicate variable in ath_hw. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 4ad1508..bb208f5 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -380,7 +380,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } - ah->config.intr_mitigation = 1; + ah->config.intr_mitigation = true; /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -599,9 +599,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ath9k_hw_set_defaults(ah); - if (ah->config.intr_mitigation != 0) - ah->intr_mitigation = true; - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); ecode = -EIO; @@ -1028,7 +1025,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (ah->intr_mitigation) + if (ah->config.intr_mitigation) ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else ah->mask_reg |= AR_IMR_RXOK; @@ -2301,8 +2298,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_OBS, 8); - if (ah->intr_mitigation) { - + if (ah->config.intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); } @@ -2908,7 +2904,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; - if (ah->intr_mitigation) { + if (ah->config.intr_mitigation) { if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -3026,7 +3022,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_RX) { mask |= AR_IMR_RXERR; - if (ah->intr_mitigation) + if (ah->config.intr_mitigation) mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; else mask |= AR_IMR_RXOK | AR_IMR_RXDESC; diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index c50faae..5a1128d 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -190,7 +190,7 @@ struct ath9k_ops_config { u16 diversity_control; u16 antenna_switch_swap; int serialize_regmode; - int intr_mitigation; + bool intr_mitigation; #define SPUR_DISABLE 0 #define SPUR_ENABLE_IOCTL 1 #define SPUR_ENABLE_EEPROM 2 @@ -524,7 +524,6 @@ struct ath_hw { enum ath9k_ani_cmd ani_function; u32 intr_txqs; - bool intr_mitigation; enum ath9k_ht_extprotspacing extprotspacing; u8 txchainmask; u8 rxchainmask; -- cgit v0.10.2 From a22be22ab8fe571cce88d0d30b49f297a563c4a7 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:36 +0530 Subject: ath9k: Avoid unneeded casts Change the void pointer to struct sk_buff and access bf_mpdu directly, removing all casts in the process. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 1dfc381..9adc991 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -130,7 +130,7 @@ struct ath_buf { struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or an aggregate) */ struct ath_buf *bf_next; /* next subframe in the aggregate */ - void *bf_mpdu; /* enclosing frame structure */ + struct sk_buff *bf_mpdu; /* enclosing frame structure */ struct ath_desc *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 5b2752b..eb4759f 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -59,7 +59,7 @@ static int ath_beaconq_config(struct ath_softc *sc) static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_buf *bf) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; struct ath_hw *ah = sc->sc_ah; struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; @@ -138,7 +138,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, /* Release the old beacon first */ bf = avp->av_bcbuf; - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; if (skb) { dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); @@ -226,7 +226,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, return; bf = avp->av_bcbuf; - skb = (struct sk_buff *) bf->bf_mpdu; + skb = bf->bf_mpdu; ath_beacon_setup(sc, avp, bf); @@ -299,7 +299,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) /* release the previous beacon frame, if it already exists. */ bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); @@ -371,7 +371,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 689bdbf..87bbeaa 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -283,7 +283,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; bool rc_update = true; - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; rcu_read_lock(); @@ -444,7 +444,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, u16 aggr_limit, legacy = 0, maxampdu; int i; - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; @@ -1452,7 +1452,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; hdr = (struct ieee80211_hdr *)skb->data; @@ -1586,7 +1586,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_control *txctl) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_node *an = NULL; @@ -1860,7 +1860,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad, int txok, bool update_rc) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); -- cgit v0.10.2 From a119cc492fc720de7fcaf7c1b9394d6c025d276d Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:38 +0530 Subject: ath9k: Cleanup buffer status handling Using a u32 to store a single flag is overkill. Use a bool to store whether the buffer is stale or not. Also, use u8 instead of u32 to store the buffer type. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 9adc991..e6c39c1 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -74,13 +74,17 @@ struct ath_config { /*************************/ #define ATH_TXBUF_RESET(_bf) do { \ - (_bf)->bf_status = 0; \ + (_bf)->bf_stale = false; \ (_bf)->bf_lastbf = NULL; \ (_bf)->bf_next = NULL; \ memset(&((_bf)->bf_state), 0, \ sizeof(struct ath_buf_state)); \ } while (0) +#define ATH_RXBUF_RESET(_bf) do { \ + (_bf)->bf_stale = false; \ + } while (0) + /** * enum buffer_type - Buffer type flags * @@ -106,7 +110,7 @@ struct ath_buf_state { int bfs_seqno; int bfs_tidno; int bfs_retries; - u32 bf_type; + u8 bf_type; u32 bfs_keyix; enum ath9k_key_type bfs_keytype; }; @@ -134,15 +138,12 @@ struct ath_buf { struct ath_desc *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ - u32 bf_status; + bool bf_stale; u16 bf_flags; struct ath_buf_state bf_state; dma_addr_t bf_dmacontext; }; -#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0) -#define ATH_BUFSTATUS_STALE 0x00000002 - struct ath_descdma { const char *dd_name; struct ath_desc *dd_desc; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 87bbeaa..735256f 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -380,8 +380,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); } else { /* retry the un-acked ones */ - if (bf->bf_next == NULL && - bf_last->bf_status & ATH_BUFSTATUS_STALE) { + if (bf->bf_next == NULL && bf_last->bf_stale) { struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); @@ -1004,7 +1003,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) bf = list_first_entry(&txq->axq_q, struct ath_buf, list); - if (bf->bf_status & ATH_BUFSTATUS_STALE) { + if (bf->bf_stale) { list_del(&bf->list); spin_unlock_bh(&txq->axq_lock); @@ -1941,7 +1940,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * it with the STALE flag. */ bf_held = NULL; - if (bf->bf_status & ATH_BUFSTATUS_STALE) { + if (bf->bf_stale) { bf_held = bf; if (list_is_last(&bf_held->list, &txq->axq_q)) { txq->axq_link = NULL; @@ -1982,7 +1981,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * however leave the last descriptor back as the holding * descriptor for hw. */ - lastbf->bf_status |= ATH_BUFSTATUS_STALE; + lastbf->bf_stale = true; INIT_LIST_HEAD(&bf_head); if (!list_is_singular(&lastbf->list)) list_cut_position(&bf_head, -- cgit v0.10.2 From ae459af12816b507aed3fcb2b9fc933c212ea12e Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:40 +0530 Subject: ath9k: Remove a couple of unused variables in descriptor handling Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index e6c39c1..dc42ad1 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -145,12 +145,10 @@ struct ath_buf { }; struct ath_descdma { - const char *dd_name; struct ath_desc *dd_desc; dma_addr_t dd_desc_paddr; u32 dd_desc_len; struct ath_buf *dd_bufptr; - dma_addr_t dd_dmacontext; }; int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 1b43cb4..f5a541b 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1789,7 +1789,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, goto fail; } - dd->dd_name = name; dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; /* @@ -1819,7 +1818,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } ds = dd->dd_desc; DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", - dd->dd_name, ds, (u32) dd->dd_desc_len, + name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); /* allocate buffers */ -- cgit v0.10.2 From 5cc93992cc4cf12ddfe63c8a5be2d509e6678e99 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:41 +0530 Subject: ath9k: Remove unused structures struct aggr_rifs_param and ath_tx_stat are not used anywhere. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index dc42ad1..9a12f76 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -294,26 +294,6 @@ struct ath_tx_control { #define ATH_TX_XRETRY 0x02 #define ATH_TX_BAR 0x04 -/* All RSSI values are noise floor adjusted */ -struct ath_tx_stat { - int rssi; - int rssictl[ATH_MAX_ANTENNA]; - int rssiextn[ATH_MAX_ANTENNA]; - int rateieee; - int rateKbps; - int ratecode; - int flags; - u32 airtime; /* time on air per final tx rate */ -}; - -struct aggr_rifs_param { - int param_max_frames; - int param_max_len; - int param_rl; - int param_al; - struct ath_rc_series *param_rcs; -}; - struct ath_node { struct ath_softc *an_sc; struct ath_atx_tid tid[WME_NUM_TID]; -- cgit v0.10.2 From 7dd58748592db1e5a77cfbddb8beffcfdb0242fe Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:42 +0530 Subject: ath9k: Check for root debugfs file Creation of the root debugfs file could have failed for some reason, check properly before proceeding in this case. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index fdf9528..97df20c 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c @@ -498,6 +498,9 @@ int ath9k_init_debug(struct ath_softc *sc) { sc->debug.debug_mask = ath9k_debug; + if (!ath9k_debugfs_root) + return -ENOENT; + sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), ath9k_debugfs_root); if (!sc->debug.debugfs_phy) -- cgit v0.10.2 From 4658b985170d9d0c88304d2d4459938b600f8c0b Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:43 +0530 Subject: ath9k: Remove TIM from the interrupt mask We never handle TIM, TIM_TIMER is used instead. Remove this and the unnecessary swBeaconProcess variable. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 9a12f76..0ef89bb 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -66,7 +66,6 @@ struct ath_config { u32 ath_aggr_prot; u16 txpowlimit; u8 cabqReadytime; - u8 swBeaconProcess; }; /*************************/ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f5a541b..0c1cc2d 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1542,9 +1542,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) sc->beacon.bslot_aphy[i] = NULL; } - /* save MISC configurations */ - sc->config.swBeaconProcess = 1; - /* setup channels and rates */ sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; @@ -2253,17 +2250,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, sc->imask |= ATH9K_INT_TSFOOR; } - /* - * Some hardware processes the TIM IE and fires an - * interrupt when the TIM bit is set. For hardware - * that does, if not overridden by configuration, - * enable the TIM interrupt when operating as station. - */ - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (conf->type == NL80211_IFTYPE_STATION) && - !sc->config.swBeaconProcess) - sc->imask |= ATH9K_INT_TIM; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); if (conf->type == NL80211_IFTYPE_AP) { -- cgit v0.10.2 From 797fe5cbefdb91f796502677e3a6623262eb9fcd Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:45 +0530 Subject: ath9k: Remove the useless do..while loops These are unnecessary constructs in a function. This patch removes these from both RX and TX init routines. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 0ef89bb..c92d46f 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -340,7 +340,7 @@ 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); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); -int ath_tx_cleanup(struct ath_softc *sc); +void ath_tx_cleanup(struct ath_softc *sc); struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index efa57ae..b46badd 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -283,54 +283,51 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) struct ath_buf *bf; int error = 0; - do { - spin_lock_init(&sc->rx.rxflushlock); - sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_lock_init(&sc->rx.rxbuflock); - - sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(sc->cachelsz, - (u16)64)); + spin_lock_init(&sc->rx.rxflushlock); + sc->sc_flags &= ~SC_OP_RXFLUSH; + spin_lock_init(&sc->rx.rxbuflock); - DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rx.bufsize); + sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, + min(sc->cachelsz, (u16)64)); - /* Initialize rx descriptors */ + DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + sc->cachelsz, sc->rx.bufsize); - error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, - "rx", nbufs, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "failed to allocate rx descriptors: %d\n", error); - break; - } + /* Initialize rx descriptors */ - list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); - if (skb == NULL) { - error = -ENOMEM; - break; - } + error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, + "rx", nbufs, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "failed to allocate rx descriptors: %d\n", error); + goto err; + } - bf->bf_mpdu = skb; - bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, - sc->rx.bufsize, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, - bf->bf_buf_addr))) { - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, - "dma_mapping_error() on RX init\n"); - error = -ENOMEM; - break; - } - bf->bf_dmacontext = bf->bf_buf_addr; + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); + if (skb == NULL) { + error = -ENOMEM; + goto err; } - sc->rx.rxlink = NULL; - } while (0); + bf->bf_mpdu = skb; + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, + sc->rx.bufsize, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_FATAL, + "dma_mapping_error() on RX init\n"); + error = -ENOMEM; + goto err; + } + bf->bf_dmacontext = bf->bf_buf_addr; + } + sc->rx.rxlink = NULL; +err: if (error) ath_rx_cleanup(sc); @@ -345,10 +342,8 @@ void ath_rx_cleanup(struct ath_softc *sc) list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = bf->bf_mpdu; if (skb) { - dma_unmap_single(sc->dev, - bf->bf_buf_addr, - sc->rx.bufsize, - DMA_FROM_DEVICE); + dma_unmap_single(sc->dev, bf->bf_buf_addr, + sc->rx.bufsize, DMA_FROM_DEVICE); dev_kfree_skb(skb); } } diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 735256f..628b780 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2047,44 +2047,38 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) { int error = 0; - do { - spin_lock_init(&sc->tx.txbuflock); + spin_lock_init(&sc->tx.txbuflock); - error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, - "tx", nbufs, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate tx descriptors: %d\n", - error); - break; - } - - error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, - "beacon", ATH_BCBUF, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate beacon descriptors: %d\n", - error); - break; - } + error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, + "tx", nbufs, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate tx descriptors: %d\n", error); + goto err; + } - } while (0); + error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, + "beacon", ATH_BCBUF, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate beacon descriptors: %d\n", error); + goto err; + } +err: if (error != 0) ath_tx_cleanup(sc); return error; } -int ath_tx_cleanup(struct ath_softc *sc) +void ath_tx_cleanup(struct ath_softc *sc) { if (sc->beacon.bdma.dd_desc_len != 0) ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); if (sc->tx.txdma.dd_desc_len != 0) ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); - - return 0; } void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) -- cgit v0.10.2 From 1ffb0610be915650cff44c69dc6728215eae08c0 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:46 +0530 Subject: ath9k: Initialize values when setting up the queue parameters Also fix a small typo. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0c1cc2d..0917def 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -922,7 +922,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); } else { - DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); sc->curaid = 0; } } @@ -2036,8 +2036,7 @@ static int ath9k_start(struct ieee80211_hw *hw) * here except setup the interrupt mask. */ if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to start recv logic\n"); + DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; goto mutex_unlock; } @@ -2551,6 +2550,8 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, mutex_lock(&sc->mutex); + memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); + qi.tqi_aifs = params->aifs; qi.tqi_cwmin = params->cw_min; qi.tqi_cwmax = params->cw_max; -- cgit v0.10.2 From 87792efc7d20a21844eb7f4247e7b9027e783ec0 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:48 +0530 Subject: ath9k: Trivial fix to handle AMPDU params properly Handle aggregation params only when aggregation is supported. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0917def..99a6852 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -434,12 +434,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) an = (struct ath_node *)sta->drv_priv; - if (sc->sc_flags & SC_OP_TXAGGR) + if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); - - an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + } } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) -- cgit v0.10.2 From 063d8be37d6f5818976a1185db4af55c5a5ae809 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:49 +0530 Subject: ath9k: Clean Interrupt handling routine This patch cleans up the ISR, removing a unnecessary do..while loop, and waking up the chip before getting the pending interrupts. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 99a6852..76c58cc 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -456,133 +456,124 @@ static void ath9k_tasklet(unsigned long data) u32 status = sc->intrstatus; if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ ath_reset(sc, false); return; - } else { + } - if (status & - (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { - spin_lock_bh(&sc->rx.rxflushlock); - ath_rx_tasklet(sc, 0); - spin_unlock_bh(&sc->rx.rxflushlock); - } - /* XXX: optimize this */ - if (status & ATH9K_INT_TX) - ath_tx_tasklet(sc); + if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { + spin_lock_bh(&sc->rx.rxflushlock); + ath_rx_tasklet(sc, 0); + spin_unlock_bh(&sc->rx.rxflushlock); } + if (status & ATH9K_INT_TX) + ath_tx_tasklet(sc); + /* re-enable hardware interrupt */ ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); } irqreturn_t ath_isr(int irq, void *dev) { +#define SCHED_INTR ( \ + ATH9K_INT_FATAL | \ + ATH9K_INT_RXORN | \ + ATH9K_INT_RXEOL | \ + ATH9K_INT_RX | \ + ATH9K_INT_TX | \ + ATH9K_INT_BMISS | \ + ATH9K_INT_CST | \ + ATH9K_INT_TSFOOR) + struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; enum ath9k_int status; bool sched = false; - do { - if (sc->sc_flags & SC_OP_INVALID) { - /* - * The hardware is not ready/present, don't - * touch anything. Note this can happen early - * on if the IRQ is shared. - */ - return IRQ_NONE; - } - if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ - return IRQ_NONE; - } + /* + * The hardware is not ready/present, don't + * touch anything. Note this can happen early + * on if the IRQ is shared. + */ + if (sc->sc_flags & SC_OP_INVALID) + return IRQ_NONE; - /* - * Figure out the reason(s) for the interrupt. Note - * that the hal returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. - */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + ath9k_ps_wakeup(sc); - status &= sc->imask; /* discard unasked-for bits */ + /* shared irq, not for us */ + + if (!ath9k_hw_intrpend(ah)) { + ath9k_ps_restore(sc); + return IRQ_NONE; + } + + /* + * Figure out the reason(s) for the interrupt. Note + * that the hal returns a pseudo-ISR that may include + * bits we haven't explicitly enabled so we mask the + * value to insure we only process bits we requested. + */ + ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + status &= sc->imask; /* discard unasked-for bits */ + + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). + */ + if (!status) { + ath9k_ps_restore(sc); + return IRQ_NONE; + } + /* Cache the status */ + sc->intrstatus = status; + + if (status & SCHED_INTR) + sched = true; + + /* + * If a FATAL or RXORN interrupt is received, we have to reset the + * chip immediately. + */ + if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN)) + goto chip_reset; + + if (status & ATH9K_INT_SWBA) + tasklet_schedule(&sc->bcon_tasklet); + + if (status & ATH9K_INT_TXURN) + ath9k_hw_updatetxtriglevel(ah, true); + + if (status & ATH9K_INT_MIB) { /* - * If there are no status bits set, then this interrupt was not - * for me (should have been caught above). + * Disable interrupts until we service the MIB + * interrupt; otherwise it will continue to + * fire. */ - if (!status) - return IRQ_NONE; - - sc->intrstatus = status; - ath9k_ps_wakeup(sc); + ath9k_hw_set_interrupts(ah, 0); + /* + * Let the hal handle the event. We assume + * it will clear whatever condition caused + * the interrupt. + */ + ath9k_hw_procmibevent(ah, &sc->nodestats); + ath9k_hw_set_interrupts(ah, sc->imask); + } - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - sched = true; - } else if (status & ATH9K_INT_RXORN) { - /* need a chip reset */ + if (status & ATH9K_INT_TIM_TIMER) { + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + /* Clear RxAbort bit so that we can + * receive frames */ + ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); + ath9k_hw_setrxabort(ah, 0); sched = true; - } else { - if (status & ATH9K_INT_SWBA) { - /* schedule a tasklet for beacon handling */ - tasklet_schedule(&sc->bcon_tasklet); - } - if (status & ATH9K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work - * at least on older hardware revs. - */ - sched = true; - } - - if (status & ATH9K_INT_TXURN) - /* bump tx trigger level */ - ath9k_hw_updatetxtriglevel(ah, true); - /* XXX: optimize this */ - if (status & ATH9K_INT_RX) - sched = true; - if (status & ATH9K_INT_TX) - sched = true; - if (status & ATH9K_INT_BMISS) - sched = true; - /* carrier sense timeout */ - if (status & ATH9K_INT_CST) - sched = true; - if (status & ATH9K_INT_MIB) { - /* - * Disable interrupts until we service the MIB - * interrupt; otherwise it will continue to - * fire. - */ - ath9k_hw_set_interrupts(ah, 0); - /* - * Let the hal handle the event. We assume - * it will clear whatever condition caused - * the interrupt. - */ - ath9k_hw_procmibevent(ah, &sc->nodestats); - ath9k_hw_set_interrupts(ah, sc->imask); - } - if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - /* Clear RxAbort bit so that we can - * receive frames */ - ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); - ath9k_hw_setrxabort(ah, 0); - sched = true; - sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; - } - } - if (status & ATH9K_INT_TSFOOR) { - /* FIXME: Handle this interrupt for power save */ - sched = true; - } + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } - ath9k_ps_restore(sc); - } while (0); + } +chip_reset: + + ath9k_ps_restore(sc); ath_debug_stat_interrupt(sc, status); if (sched) { @@ -592,6 +583,8 @@ irqreturn_t ath_isr(int irq, void *dev) } return IRQ_HANDLED; + +#undef SCHED_INTR } static u32 ath_get_extchanmode(struct ath_softc *sc, -- cgit v0.10.2 From c6483cfe7147534719197c03a99848f49e004308 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:56 +0530 Subject: ath9k: Determine number of streams from HT capabilities The number of streams supported by a STA can be determined directly from the HT capabilities. Remove the redundant variable storing the stream cap. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 824ccbb..a6933cc 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -524,7 +524,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, u32 valid; for (i = 0; i < rate_table->rate_cnt; i++) { - valid = (ath_rc_priv->single_stream ? + valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? rate_table->info[i].valid_single_stream : rate_table->info[i].valid); if (valid == 1) { @@ -557,9 +557,9 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, for (i = 0; i < rateset->rs_nrates; i++) { 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); + u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? + rate_table->info[j].valid_single_stream : + rate_table->info[j].valid); u8 rate = rateset->rs_rates[i]; u8 dot11rate = rate_table->info[j].dot11rate; @@ -603,7 +603,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; - u32 valid = (ath_rc_priv->single_stream ? + u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? rate_table->info[j].valid_single_stream : rate_table->info[j].valid); u8 rate = rateset->rs_rates[i]; @@ -740,9 +740,10 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, if (rate > (ath_rc_priv->rate_table_size - 1)) rate = ath_rc_priv->rate_table_size - 1; - ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || + ASSERT((rate_table->info[rate].valid && + (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) || (rate_table->info[rate].valid_single_stream && - ath_rc_priv->single_stream)); + !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))); return rate; } @@ -1422,9 +1423,6 @@ static void ath_rc_init(struct ath_softc *sc, } ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG; - /* Set stream capability */ - ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; - if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ hi = ath_rc_init_validrates(ath_rc_priv, rate_table, diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index ec72dd2..bdfd205 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -157,7 +157,6 @@ struct ath_rateset { * @probe_interval: interval for ratectrl to probe for other rates * @prev_data_rix: rate idx of last data frame * @ht_cap: HT capabilities - * @single_stream: When TRUE, only single TX stream possible * @neg_rates: Negotatied rates * @neg_ht_rates: Negotiated HT rates */ @@ -175,7 +174,6 @@ struct ath_rate_priv { u8 max_valid_rate; u8 valid_rate_index[RATE_TABLE_SIZE]; u8 ht_cap; - u8 single_stream; u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rc_phy_mode; -- cgit v0.10.2 From f5c38ef06e005705ef87b7a77752c183bacb94cc Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 30 Mar 2009 15:28:57 +0530 Subject: ath9k: Fix bug in determining HT40 mode This patch fixes a bug in checking for HT40 mode. The STA's mode can be determined from the cached HT capabilities, use that and remove the redundant variable 'rc_phy_mode'. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index a6933cc..a13668b 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1321,7 +1321,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, * 40 to 20 => don't update */ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) + !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) return; rix = ath_rc_get_rateindex(rate_table, &rates[i]); @@ -1346,9 +1346,8 @@ static void ath_rc_tx_status(struct ath_softc *sc, /* If HT40 and we have switched mode from 40 to 20 => don't update */ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) { + !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) return; - } rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, @@ -1421,7 +1420,6 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->valid_phy_rateidx[i][j] = 0; ath_rc_priv->valid_phy_ratecnt[i] = 0; } - ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG; if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index bdfd205..e3abd76 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -176,7 +176,6 @@ struct ath_rate_priv { u8 ht_cap; u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; - u8 rc_phy_mode; u8 rate_max_phy; u32 rssi_time; u32 rssi_down_time; -- cgit v0.10.2 From d5522e039586fdf72493225a88b944f726b69671 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Mar 2009 13:23:35 +0200 Subject: mac80211: move ieee80211_enable_ht function to mlme.c It really belongs into that file since it is only relevant for managed mode. Move 1:1, not even whitespace changes, but make it static and remove from header file. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4e3c72f..73bd4277 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -83,89 +83,6 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, ht_cap->mcs.rx_mask[32/8] |= 1; } -/* - * ieee80211_enable_ht should be called only after the operating band - * has been determined as ht configuration depends on the hw's - * HT abilities for a specific band. - */ -u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, - struct ieee80211_ht_info *hti, - u16 ap_ht_cap_flags) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss_ht_conf ht; - struct sta_info *sta; - u32 changed = 0; - bool enable_ht = true, ht_changed; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - memset(&ht, 0, sizeof(ht)); - - /* HT is not supported */ - if (!sband->ht_cap.ht_supported) - enable_ht = false; - - /* check that channel matches the right operating channel */ - if (local->hw.conf.channel->center_freq != - ieee80211_channel_to_frequency(hti->control_chan)) - enable_ht = false; - - if (enable_ht) { - channel_type = NL80211_CHAN_HT20; - - if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && - (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { - switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - channel_type = NL80211_CHAN_HT40PLUS; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - channel_type = NL80211_CHAN_HT40MINUS; - break; - } - } - } - - ht_changed = conf_is_ht(&local->hw.conf) != enable_ht || - channel_type != local->hw.conf.channel_type; - - local->oper_channel_type = channel_type; - - if (ht_changed) { - /* channel_type change automatically detected */ - ieee80211_hw_config(local, 0); - - rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); - if (sta) - rate_control_rate_update(local, sband, sta, - IEEE80211_RC_HT_CHANGED); - - rcu_read_unlock(); - - } - - /* disable HT */ - if (!enable_ht) - return 0; - - ht.operation_mode = le16_to_cpu(hti->operation_mode); - - /* if bss configuration changed store the new one */ - if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) { - changed |= BSS_CHANGED_HT; - sdata->vif.bss_conf.ht = ht; - } - - return changed; -} - void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) { int i; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 312347d..73d9f89 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -995,9 +995,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, struct ieee80211_ht_cap *ht_cap_ie, struct ieee80211_sta_ht_cap *ht_cap); -u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, - struct ieee80211_ht_info *hti, - u16 ap_ht_cap_flags); void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 08db02c..4ce5b9c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -80,6 +80,89 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, return count; } +/* + * ieee80211_enable_ht should be called only after the operating band + * has been determined as ht configuration depends on the hw's + * HT abilities for a specific band. + */ +static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, + struct ieee80211_ht_info *hti, + u16 ap_ht_cap_flags) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_supported_band *sband; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_bss_ht_conf ht; + struct sta_info *sta; + u32 changed = 0; + bool enable_ht = true, ht_changed; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + memset(&ht, 0, sizeof(ht)); + + /* HT is not supported */ + if (!sband->ht_cap.ht_supported) + enable_ht = false; + + /* check that channel matches the right operating channel */ + if (local->hw.conf.channel->center_freq != + ieee80211_channel_to_frequency(hti->control_chan)) + enable_ht = false; + + if (enable_ht) { + channel_type = NL80211_CHAN_HT20; + + if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && + (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { + switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + channel_type = NL80211_CHAN_HT40PLUS; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + channel_type = NL80211_CHAN_HT40MINUS; + break; + } + } + } + + ht_changed = conf_is_ht(&local->hw.conf) != enable_ht || + channel_type != local->hw.conf.channel_type; + + local->oper_channel_type = channel_type; + + if (ht_changed) { + /* channel_type change automatically detected */ + ieee80211_hw_config(local, 0); + + rcu_read_lock(); + + sta = sta_info_get(local, ifmgd->bssid); + if (sta) + rate_control_rate_update(local, sband, sta, + IEEE80211_RC_HT_CHANGED); + + rcu_read_unlock(); + + } + + /* disable HT */ + if (!enable_ht) + return 0; + + ht.operation_mode = le16_to_cpu(hti->operation_mode); + + /* if bss configuration changed store the new one */ + if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) { + changed |= BSS_CHANGED_HT; + sdata->vif.bss_conf.ht = ht; + } + + return changed; +} + /* frame sending functions */ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) -- cgit v0.10.2 From 42639fcd443d97a9a471f4b8269620286dd7036b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 30 Mar 2009 08:05:29 -0400 Subject: ath5k: reduce exported channel list Claiming every available 5 ghz channel has a couple of negative side-effects: scanning takes a long time, and the channel list overflows the available buffer space for netlink commands, resulting in: $ iw phy phy0 info command failed: No buffer space available (-105) This patch adds a modparam so people who want to see all the channels can do so by passing all_channels=1. By default users will see a smaller list of channels. This also halves scan time, from 10 seconds down to less than 5 when using world regulatory. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Reported-by: Simon Farnsworth Tested-By: Simon Farnsworth Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index a08bc8a..d8c60c5 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -64,6 +64,10 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +static int modparam_all_channels; +module_param_named(all_channels, modparam_all_channels, int, 0444); +MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); + /******************\ * Internal defines * @@ -862,6 +866,20 @@ ath5k_ieee2mhz(short chan) return 2212 + chan * 20; } +/* + * Returns true for the channel numbers used without all_channels modparam. + */ +static bool ath5k_is_standard_channel(short chan) +{ + return ((chan <= 14) || + /* UNII 1,2 */ + ((chan & 3) == 0 && chan >= 36 && chan <= 64) || + /* midband */ + ((chan & 3) == 0 && chan >= 100 && chan <= 140) || + /* UNII-3 */ + ((chan & 3) == 1 && chan >= 149 && chan <= 165)); +} + static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, @@ -899,6 +917,9 @@ ath5k_copy_channels(struct ath5k_hw *ah, if (!ath5k_channel_ok(ah, freq, chfreq)) continue; + if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) + continue; + /* Write channel info and increment counter */ channels[count].center_freq = freq; channels[count].band = (chfreq == CHANNEL_2GHZ) ? -- cgit v0.10.2 From ae3d2462f89db4592ea71e8f6e326d4b38dc952c Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Mon, 30 Mar 2009 11:04:04 -0700 Subject: net/ps3: Update maintainer Update the MAINTAINERS entry for PS3 NETWORK SUPPORT. CC: Masakazu Mokuno Signed-off-by: Geoff Levand Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 6dfcb6d..3dfe1a7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4427,8 +4427,8 @@ S: Maintained F: drivers/ata/sata_promise.* PS3 NETWORK SUPPORT -P: Masakazu Mokuno -M: mokuno@sm.sony.co.jp +P: Geoff Levand +M: geoffrey.levand@am.sony.com L: netdev@vger.kernel.org L: cbe-oss-dev@ozlabs.org S: Supported -- cgit v0.10.2 From cf3a9579f61c643c15c172da0baf5429578b0ba3 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 25 Mar 2009 03:11:58 +0100 Subject: p54: clean up p54.h's struct p54_common This patch rearrange and regroups most elements in p54_common. Signed-off-by: Christian Lamparter Acked-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index ecf8b6e..04d95a1 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -133,55 +133,72 @@ struct p54_led_dev { struct p54_common { struct ieee80211_hw *hw; - u32 rx_start; - u32 rx_end; - struct sk_buff_head tx_queue; void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); - int mode; + struct sk_buff_head tx_queue; + struct mutex conf_mutex; + + /* memory management (as seen by the firmware) */ + u32 rx_start; + u32 rx_end; u16 rx_mtu; u8 headroom; u8 tailroom; - struct mutex conf_mutex; - u8 mac_addr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; + + /* firmware/hardware info */ + unsigned int tx_hdr_len; + unsigned int fw_var; + unsigned int fw_interface; + u8 version; + + /* (e)DCF / QOS state */ + bool use_short_slot; + struct ieee80211_tx_queue_stats tx_stats[8]; + struct p54_edcf_queue_param qos_params[8]; + + /* Radio data */ + u16 rxhw; u8 rx_diversity_mask; u8 tx_diversity_mask; + unsigned int output_power; + int noise; + /* calibration, output power limit and rssi<->dBm conversation data */ struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; - struct p54_cal_database *output_limit; struct p54_cal_database *curve_data; + struct p54_cal_database *output_limit; struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; + + /* BBP/MAC state */ + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u16 wakeup_timer; unsigned int filter_flags; - bool use_short_slot; - u16 rxhw; - u8 version; - unsigned int tx_hdr_len; - unsigned int fw_var; - unsigned int fw_interface; - unsigned int output_power; - u32 tsf_low32; - u32 tsf_high32; + int mode; + u32 tsf_low32, tsf_high32; u32 basic_rate_mask; - u16 wakeup_timer; u16 aid; - struct ieee80211_tx_queue_stats tx_stats[8]; - struct p54_edcf_queue_param qos_params[8]; - struct ieee80211_low_level_stats stats; - struct delayed_work work; struct sk_buff *cached_beacon; - int noise; - void *eeprom; - struct completion eeprom_comp; + + /* cryptographic engine information */ u8 privacy_caps; u8 rx_keycache_size; + /* LED management */ #ifdef CONFIG_P54_LEDS struct p54_led_dev assoc_led; struct p54_led_dev tx_led; #endif /* CONFIG_P54_LEDS */ u16 softled_state; /* bit field of glowing LEDs */ + + /* statistics */ + struct ieee80211_low_level_stats stats; + struct delayed_work work; + + /* eeprom handling */ + void *eeprom; + struct completion eeprom_comp; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); -- cgit v0.10.2 From dce072580e095d1fb7be59a1be30dc0e8307821b Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 25 Mar 2009 03:12:18 +0100 Subject: p54: more SoftLED updates This patch hopefully finishes the SoftLED code: - It adds two more LEDs (rx and radio). (the FW claims it can support up to 16 LEDs, but I doubt that any vendor put more than 4 on a board) - update the LEDs in a _delayed_ workqueue. No one reported any more crashes. (see: "PATCH] p54: fix race condition in memory management") So we can stop burning the mm code. Signed-off-by: Christian Lamparter Acked-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 04d95a1..4499035 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -125,6 +125,7 @@ struct p54_led_dev { struct led_classdev led_dev; char name[P54_LED_MAX_NAME_LEN + 1]; + unsigned int toggled; unsigned int index; unsigned int registered; }; @@ -186,10 +187,10 @@ struct p54_common { u8 rx_keycache_size; /* LED management */ -#ifdef CONFIG_P54_LEDS - struct p54_led_dev assoc_led; - struct p54_led_dev tx_led; -#endif /* CONFIG_P54_LEDS */ +#ifdef CONFIG_MAC80211_LEDS + struct p54_led_dev leds[4]; + struct delayed_work led_work; +#endif /* CONFIG_MAC80211_LEDS */ u16 softled_state; /* bit field of glowing LEDs */ /* statistics */ diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index c8f0232..696067e 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -2088,6 +2088,9 @@ static void p54_stop(struct ieee80211_hw *dev) priv->softled_state = 0; p54_set_leds(dev); +#ifdef CONFIG_P54_LEDS + cancel_delayed_work_sync(&priv->led_work); +#endif /* CONFIG_P54_LEDS */ cancel_delayed_work_sync(&priv->work); if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); @@ -2421,6 +2424,43 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, } #ifdef CONFIG_P54_LEDS +static void p54_update_leds(struct work_struct *work) +{ + struct p54_common *priv = container_of(work, struct p54_common, + led_work.work); + int err, i, tmp, blink_delay = 400; + bool rerun = false; + + /* Don't toggle the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].toggled) { + priv->softled_state |= BIT(i); + + tmp = 70 + 200 / (priv->leds[i].toggled); + if (tmp < blink_delay) + blink_delay = tmp; + + if (priv->leds[i].led_dev.brightness == LED_OFF) + rerun = true; + + priv->leds[i].toggled = + !!priv->leds[i].led_dev.brightness; + } else + priv->softled_state &= ~BIT(i); + + err = p54_set_leds(priv->hw); + if (err && net_ratelimit()) + printk(KERN_ERR "%s: failed to update LEDs.\n", + wiphy_name(priv->hw->wiphy)); + + if (rerun) + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + msecs_to_jiffies(blink_delay)); +} + static void p54_led_brightness_set(struct led_classdev *led_dev, enum led_brightness brightness) { @@ -2428,28 +2468,23 @@ static void p54_led_brightness_set(struct led_classdev *led_dev, led_dev); struct ieee80211_hw *dev = led->hw_dev; struct p54_common *priv = dev->priv; - int err; - /* Don't toggle the LED, when the device is down. */ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) return ; - if (brightness != LED_OFF) - priv->softled_state |= BIT(led->index); - else - priv->softled_state &= ~BIT(led->index); - - err = p54_set_leds(dev); - if (err && net_ratelimit()) - printk(KERN_ERR "%s: failed to update %s LED.\n", - wiphy_name(dev->wiphy), led_dev->name); + if (brightness) { + led->toggled++; + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + HZ/10); + } } static int p54_register_led(struct ieee80211_hw *dev, - struct p54_led_dev *led, unsigned int led_index, char *name, char *trigger) { + struct p54_common *priv = dev->priv; + struct p54_led_dev *led = &priv->leds[led_index]; int err; if (led->registered) @@ -2482,19 +2517,30 @@ static int p54_init_leds(struct ieee80211_hw *dev) * TODO: * Figure out if the EEPROM contains some hints about the number * of available/programmable LEDs of the device. - * But for now, we can assume that we have two programmable LEDs. */ - err = p54_register_led(dev, &priv->assoc_led, 0, "assoc", + INIT_DELAYED_WORK(&priv->led_work, p54_update_leds); + + err = p54_register_led(dev, 0, "assoc", ieee80211_get_assoc_led_name(dev)); if (err) return err; - err = p54_register_led(dev, &priv->tx_led, 1, "tx", + err = p54_register_led(dev, 1, "tx", ieee80211_get_tx_led_name(dev)); if (err) return err; + err = p54_register_led(dev, 2, "rx", + ieee80211_get_rx_led_name(dev)); + if (err) + return err; + + err = p54_register_led(dev, 3, "radio", + ieee80211_get_radio_led_name(dev)); + if (err) + return err; + err = p54_set_leds(dev); return err; } @@ -2502,11 +2548,11 @@ static int p54_init_leds(struct ieee80211_hw *dev) static void p54_unregister_leds(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; + int i; - if (priv->tx_led.registered) - led_classdev_unregister(&priv->tx_led.led_dev); - if (priv->assoc_led.registered) - led_classdev_unregister(&priv->assoc_led.led_dev); + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].registered) + led_classdev_unregister(&priv->leds[i].led_dev); } #endif /* CONFIG_P54_LEDS */ -- cgit v0.10.2 From f13027af5cd567757c18b85776232e31a2ba55d4 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 25 Mar 2009 03:12:49 +0100 Subject: p54: add beacon filtering support This patch adds beacon filtering support to p54. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 4499035..d6354fa 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -134,6 +134,7 @@ struct p54_led_dev { struct p54_common { struct ieee80211_hw *hw; + struct ieee80211_vif *vif; void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 696067e..cb49058 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1044,6 +1044,7 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct p54_common *priv = dev->priv; struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_trap *trap = (struct p54_trap *) hdr->data; u16 event = le16_to_cpu(trap->event); @@ -1057,6 +1058,8 @@ static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) wiphy_name(dev->wiphy), freq); break; case P54_TRAP_NO_BEACON: + if (priv->vif) + ieee80211_beacon_loss(priv->vif); break; case P54_TRAP_SCAN: break; @@ -1939,7 +1942,8 @@ static int p54_set_ps(struct ieee80211_hw *dev) int i; if (dev->conf.flags & IEEE80211_CONF_PS) - mode = P54_PSM | P54_PSM_DTIM | P54_PSM_MCBC; + mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | + P54_PSM_CHECKSUM | P54_PSM_MCBC; else mode = P54_PSM_CAM; @@ -1957,9 +1961,10 @@ static int p54_set_ps(struct ieee80211_hw *dev) psm->intervals[i].periods = cpu_to_le16(1); } - psm->beacon_rssi_skip_max = 60; + psm->beacon_rssi_skip_max = 200; psm->rssi_delta_threshold = 0; - psm->nr = 0; + psm->nr = 10; + psm->exclude[0] = 0; priv->tx(dev, skb); @@ -2114,6 +2119,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } + priv->vif = conf->vif; + switch (conf->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: @@ -2138,6 +2145,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); + priv->vif = NULL; if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); priv->mode = NL80211_IFTYPE_MONITOR; @@ -2590,7 +2598,8 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_queue); dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_BEACON_FILTER; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | -- cgit v0.10.2 From 5c8fa4f7e7fcceabb3b37d7ec66d3e7115a4bba3 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 26 Mar 2009 23:39:53 +0200 Subject: rndis_wlan: initiate cfg80211 conversion Signed-off-by: John W. Linville Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index db91db7..c995d7c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include @@ -316,12 +318,44 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) +static const struct ieee80211_channel rndis_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + +static const struct ieee80211_rate rndis_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60 }, + { .bitrate = 90 }, + { .bitrate = 120 }, + { .bitrate = 180 }, + { .bitrate = 240 }, + { .bitrate = 360 }, + { .bitrate = 480 }, + { .bitrate = 540 } +}; + /* RNDIS device private data */ struct rndis_wext_private { - char name[32]; - struct usbnet *usbdev; + struct wireless_dev wdev; + struct workqueue_struct *workqueue; struct delayed_work stats_work; struct work_struct work; @@ -329,6 +363,10 @@ struct rndis_wext_private { spinlock_t stats_lock; unsigned long work_pending; + struct ieee80211_supported_band band; + struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; + struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; + struct iw_statistics iwstats; struct iw_statistics privstats; @@ -369,7 +407,8 @@ struct rndis_wext_private { }; -static const int rates_80211g[8] = { 6, 9, 12, 18, 24, 36, 48, 54 }; +struct cfg80211_ops rndis_config_ops = { }; +void *rndis_wiphy_privid = &rndis_wiphy_privid; static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; @@ -1151,15 +1190,15 @@ static int rndis_iw_get_range(struct net_device *dev, /* fill in 802.11g rates */ if (has_80211g_rates) { num = range->num_bitrates; - for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) { + for (i = 4; i < ARRAY_SIZE(rndis_rates); i++) { for (j = 0; j < num; j++) { if (range->bitrate[j] == - rates_80211g[i] * 1000000) + rndis_rates[i].bitrate * 100000) break; } if (j == num) range->bitrate[range->num_bitrates++] = - rates_80211g[i] * 1000000; + rndis_rates[i].bitrate * 100000; if (range->num_bitrates == IW_MAX_BITRATES) break; } @@ -1204,17 +1243,6 @@ static int rndis_iw_get_range(struct net_device *dev, } -static int rndis_iw_get_name(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - strcpy(wrqu->name, priv->name); - return 0; -} - - static int rndis_iw_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { @@ -2165,7 +2193,7 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) static const iw_handler rndis_iw_handler[] = { IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, - IW_IOCTL(SIOCGIWNAME) = rndis_iw_get_name, + IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq, IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, IW_IOCTL(SIOCSIWMODE) = rndis_iw_set_mode, @@ -2338,12 +2366,6 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) break; } } - if (priv->caps & CAP_MODE_80211A) - strcat(priv->name, "a"); - if (priv->caps & CAP_MODE_80211B) - strcat(priv->name, "b"); - if (priv->caps & CAP_MODE_80211G) - strcat(priv->name, "g"); } return retval; @@ -2538,20 +2560,28 @@ static const struct net_device_ops rndis_wext_netdev_ops = { static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) { + struct wiphy *wiphy; struct rndis_wext_private *priv; int retval, len; __le32 tmp; - /* allocate rndis private data */ - priv = kzalloc(sizeof(struct rndis_wext_private), GFP_KERNEL); - if (!priv) + /* allocate wiphy and rndis private data + * NOTE: We only support a single virtual interface, so wiphy + * and wireless_dev are somewhat synonymous for this device. + */ + wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wext_private)); + if (!wiphy) return -ENOMEM; + priv = wiphy_priv(wiphy); + usbdev->net->ieee80211_ptr = &priv->wdev; + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_STATION; + /* These have to be initialized before calling generic_rndis_bind(). * Otherwise we'll be in big trouble in rndis_wext_early_init(). */ usbdev->driver_priv = priv; - strcpy(priv->name, "IEEE802.11"); usbdev->net->wireless_handlers = &rndis_iw_handlers; priv->usbdev = usbdev; @@ -2595,7 +2625,31 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + /* fill-out wiphy structure and register w/ cfg80211 */ + memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); + wiphy->privid = rndis_wiphy_privid; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC); + wiphy->max_scan_ssids = 1; + + /* TODO: fill-out band information based on priv->caps */ rndis_wext_get_caps(usbdev); + + memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); + memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rndis_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = ARRAY_SIZE(rndis_rates); + wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + + set_wiphy_dev(wiphy, &usbdev->udev->dev); + + if (wiphy_register(wiphy)) { + wiphy_free(wiphy); + return -ENODEV; + } + set_default_iw_params(usbdev); /* turn radio on */ @@ -2632,9 +2686,11 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) if (priv && priv->wpa_ie_len) kfree(priv->wpa_ie); - kfree(priv); rndis_unbind(usbdev, intf); + + wiphy_unregister(priv->wdev.wiphy); + wiphy_free(priv->wdev.wiphy); } -- cgit v0.10.2 From 964c1d417e4738d359ba263921a7b9c18fa711c4 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 26 Mar 2009 23:40:01 +0200 Subject: rndis_wlan: convert get/set mode to cfg80211 Signed-off-by: John W. Linville [edit: made rndis_change_virtual_intf static] Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c995d7c..a875860 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -406,8 +406,17 @@ struct rndis_wext_private { u8 command_buffer[COMMAND_BUFFER_SIZE]; }; +/* + * cfg80211 ops + */ +static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params); + +struct cfg80211_ops rndis_config_ops = { + .change_virtual_intf = rndis_change_virtual_intf, +}; -struct cfg80211_ops rndis_config_ops = { }; void *rndis_wiphy_privid = &rndis_wiphy_privid; static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; @@ -1125,6 +1134,37 @@ static void set_multicast_list(struct usbnet *usbdev) /* + * cfg80211 ops + */ +static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct net_device *dev; + struct usbnet *usbdev; + int mode; + + /* we're under RTNL */ + dev = __dev_get_by_index(&init_net, ifindex); + if (!dev) + return -ENODEV; + usbdev = netdev_priv(dev); + + switch (type) { + case NL80211_IFTYPE_ADHOC: + mode = ndis_80211_infra_adhoc; + break; + case NL80211_IFTYPE_STATION: + mode = ndis_80211_infra_infra; + break; + default: + return -EINVAL; + } + + return set_infra_mode(usbdev, mode); +} + +/* * wireless extension handlers */ @@ -1450,55 +1490,6 @@ static int rndis_iw_get_auth(struct net_device *dev, } -static int rndis_iw_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - switch (priv->infra_mode) { - case ndis_80211_infra_adhoc: - wrqu->mode = IW_MODE_ADHOC; - break; - case ndis_80211_infra_infra: - wrqu->mode = IW_MODE_INFRA; - break; - /*case ndis_80211_infra_auto_unknown:*/ - default: - wrqu->mode = IW_MODE_AUTO; - break; - } - devdbg(usbdev, "SIOCGIWMODE: %08x", wrqu->mode); - return 0; -} - - -static int rndis_iw_set_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - int mode; - - devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode); - - switch (wrqu->mode) { - case IW_MODE_ADHOC: - mode = ndis_80211_infra_adhoc; - break; - case IW_MODE_INFRA: - mode = ndis_80211_infra_infra; - break; - /*case IW_MODE_AUTO:*/ - default: - mode = ndis_80211_infra_auto_unknown; - break; - } - - return set_infra_mode(usbdev, mode); -} - - static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2196,8 +2187,8 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq, IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, - IW_IOCTL(SIOCSIWMODE) = rndis_iw_set_mode, - IW_IOCTL(SIOCGIWMODE) = rndis_iw_get_mode, + IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, + IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, IW_IOCTL(SIOCGIWRANGE) = rndis_iw_get_range, IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid, IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid, -- cgit v0.10.2 From 06aa7afaaa21a4e7f1bcb196bd3f29193924a603 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 26 Mar 2009 23:40:09 +0200 Subject: cfg80211: add cfg80211_inform_bss Added cfg80211_inform_bss() for full-mac devices to use. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f8bf0c8..2b1f6c6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -863,6 +863,14 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, s32 signal, gfp_t gfp); +struct cfg80211_bss* +cfg80211_inform_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + u64 timestamp, u16 capability, u16 beacon_interval, + const u8 *ie, size_t ielen, + s32 signal, gfp_t gfp); + struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *bssid, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2ae65b3..1396248 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -414,6 +414,55 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, return found; } +struct cfg80211_bss* +cfg80211_inform_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + u64 timestamp, u16 capability, u16 beacon_interval, + const u8 *ie, size_t ielen, + s32 signal, gfp_t gfp) +{ + struct cfg80211_internal_bss *res; + size_t privsz; + + if (WARN_ON(!wiphy)) + return NULL; + + privsz = wiphy->bss_priv_size; + + if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && + (signal < 0 || signal > 100))) + return NULL; + + res = kzalloc(sizeof(*res) + privsz + ielen, gfp); + if (!res) + return NULL; + + memcpy(res->pub.bssid, bssid, ETH_ALEN); + res->pub.channel = channel; + res->pub.signal = signal; + res->pub.tsf = timestamp; + res->pub.beacon_interval = beacon_interval; + res->pub.capability = capability; + /* point to after the private area */ + res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; + memcpy(res->pub.information_elements, ie, ielen); + res->pub.len_information_elements = ielen; + + kref_init(&res->ref); + + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); + if (!res) + return NULL; + + if (res->pub.capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + + /* cfg80211_bss_update gives us a referenced result */ + return &res->pub; +} +EXPORT_SYMBOL(cfg80211_inform_bss); + struct cfg80211_bss * cfg80211_inform_bss_frame(struct wiphy *wiphy, struct ieee80211_channel *channel, -- cgit v0.10.2 From 4bd7f03e915b6946307ce57f20718c6547734b5d Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 26 Mar 2009 23:40:16 +0200 Subject: rndis_wlan: change quality level scale Change quality level scale to match cfg80211 CFG80211_SIGNAL_TYPE_UNSPEC. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index a875860..9e7956d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1269,7 +1269,7 @@ static int rndis_iw_get_range(struct net_device *dev, range->max_frag = 2346; range->max_qual.qual = 100; - range->max_qual.level = 154; + range->max_qual.level = 100; range->max_qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; @@ -1712,7 +1712,7 @@ static char *rndis_translate_scan(struct net_device *dev, devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi)); iwe.cmd = IWEVQUAL; iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->rssi)); - iwe.u.qual.level = le32_to_cpu(bssid->rssi); + iwe.u.qual.level = level_to_qual(le32_to_cpu(bssid->rssi)); iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; @@ -2400,7 +2400,7 @@ static void rndis_update_wireless_stats(struct work_struct *work) if (ret == 0) { memset(&iwstats.qual, 0, sizeof(iwstats.qual)); iwstats.qual.qual = level_to_qual(le32_to_cpu(rssi)); - iwstats.qual.level = le32_to_cpu(rssi); + iwstats.qual.level = level_to_qual(le32_to_cpu(rssi)); iwstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; -- cgit v0.10.2 From 4d2a369ec09167f423c0783b1cf85cee8102544f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 26 Mar 2009 23:40:23 +0200 Subject: rndis_wlan: convert get range to cfg80211 Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9e7956d..4252903 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1176,113 +1176,6 @@ static int rndis_iw_commit(struct net_device *dev, } -static int rndis_iw_get_range(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - int len, ret, i, j, num, has_80211g_rates; - u8 rates[8]; - __le32 tx_power; - - devdbg(usbdev, "SIOCGIWRANGE"); - - /* clear iw_range struct */ - memset(range, 0, sizeof(*range)); - wrqu->data.length = sizeof(*range); - - range->txpower_capa = IW_TXPOW_MWATT; - range->num_txpower = 1; - if (priv->caps & CAP_SUPPORT_TXPOWER) { - len = sizeof(tx_power); - ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, - &tx_power, &len); - if (ret == 0 && le32_to_cpu(tx_power) != 0xFF) - range->txpower[0] = le32_to_cpu(tx_power); - else - range->txpower[0] = get_bcm4320_power(priv); - } else - range->txpower[0] = get_bcm4320_power(priv); - - len = sizeof(rates); - ret = rndis_query_oid(usbdev, OID_802_11_SUPPORTED_RATES, &rates, - &len); - has_80211g_rates = 0; - if (ret == 0) { - j = 0; - for (i = 0; i < len; i++) { - if (rates[i] == 0) - break; - range->bitrate[j] = (rates[i] & 0x7f) * 500000; - /* check for non 802.11b rates */ - if (range->bitrate[j] == 6000000 || - range->bitrate[j] == 9000000 || - (range->bitrate[j] >= 12000000 && - range->bitrate[j] != 22000000)) - has_80211g_rates = 1; - j++; - } - range->num_bitrates = j; - } else - range->num_bitrates = 0; - - /* fill in 802.11g rates */ - if (has_80211g_rates) { - num = range->num_bitrates; - for (i = 4; i < ARRAY_SIZE(rndis_rates); i++) { - for (j = 0; j < num; j++) { - if (range->bitrate[j] == - rndis_rates[i].bitrate * 100000) - break; - } - if (j == num) - range->bitrate[range->num_bitrates++] = - rndis_rates[i].bitrate * 100000; - if (range->num_bitrates == IW_MAX_BITRATES) - break; - } - - /* estimated max real througput in bps */ - range->throughput = 54 * 1000 * 1000 / 2; - - /* ~35% more with afterburner */ - if (priv->param_afterburner) - range->throughput = range->throughput / 100 * 135; - } else { - /* estimated max real througput in bps */ - range->throughput = 11 * 1000 * 1000 / 2; - } - - range->num_channels = 14; - - for (i = 0; (i < 14) && (i < IW_MAX_FREQUENCIES); i++) { - range->freq[i].i = i + 1; - range->freq[i].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000; - range->freq[i].e = 1; - } - range->num_frequency = i; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->max_qual.qual = 100; - range->max_qual.level = 100; - range->max_qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID; - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = WIRELESS_EXT; - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - return 0; -} - - static int rndis_iw_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { @@ -2189,7 +2082,7 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, - IW_IOCTL(SIOCGIWRANGE) = rndis_iw_get_range, + IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid, IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid, IW_IOCTL(SIOCSIWSCAN) = rndis_iw_set_scan, @@ -2633,6 +2526,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) priv->band.bitrates = priv->rates; priv->band.n_bitrates = ARRAY_SIZE(rndis_rates); wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; set_wiphy_dev(wiphy, &usbdev->udev->dev); -- cgit v0.10.2 From 71a7b26d3e6404e43574f80236c00eaa39b2525e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 26 Mar 2009 23:40:31 +0200 Subject: rndis_wlan: convert scan to cfg80211 Convert scan function to cfg80211. Unlike old scan code new code waits 1 sec before getting scan data from device and passing forward to cfg80211. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 4252903..239e6a1 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -356,8 +356,11 @@ struct rndis_wext_private { struct wireless_dev wdev; + struct cfg80211_scan_request *scan_request; + struct workqueue_struct *workqueue; struct delayed_work stats_work; + struct delayed_work scan_work; struct work_struct work; struct mutex command_lock; spinlock_t stats_lock; @@ -413,8 +416,12 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, enum nl80211_iftype type, u32 *flags, struct vif_params *params); +static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request); + struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, + .scan = rndis_scan, }; void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -1164,6 +1171,142 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, return set_infra_mode(usbdev, mode); } + +#define SCAN_DELAY_JIFFIES (HZ) +static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + struct usbnet *usbdev = netdev_priv(dev); + struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + int ret; + __le32 tmp; + + devdbg(usbdev, "cfg80211.scan"); + + if (!request) + return -EINVAL; + + if (priv->scan_request && priv->scan_request != request) + return -EBUSY; + + priv->scan_request = request; + + tmp = cpu_to_le32(1); + ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, + sizeof(tmp)); + if (ret == 0) { + /* Wait before retrieving scan results from device */ + queue_delayed_work(priv->workqueue, &priv->scan_work, + SCAN_DELAY_JIFFIES); + } + + return ret; +} + + +static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, + struct ndis_80211_bssid_ex *bssid) +{ + struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct ieee80211_channel *channel; + s32 signal; + u64 timestamp; + u16 capability; + u16 beacon_interval; + struct ndis_80211_fixed_ies *fixed; + int ie_len, bssid_len; + u8 *ie; + + /* parse bssid structure */ + bssid_len = le32_to_cpu(bssid->length); + + if (bssid_len < sizeof(struct ndis_80211_bssid_ex) + + sizeof(struct ndis_80211_fixed_ies)) + return NULL; + + fixed = (struct ndis_80211_fixed_ies *)bssid->ies; + + ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); + ie_len = min(bssid_len - (int)sizeof(*bssid), + (int)le32_to_cpu(bssid->ie_length)); + ie_len -= sizeof(struct ndis_80211_fixed_ies); + if (ie_len < 0) + return NULL; + + /* extract data for cfg80211_inform_bss */ + channel = ieee80211_get_channel(priv->wdev.wiphy, + KHZ_TO_MHZ(le32_to_cpu(bssid->config.ds_config))); + if (!channel) + return NULL; + + signal = level_to_qual(le32_to_cpu(bssid->rssi)); + timestamp = le64_to_cpu(*(__le64 *)fixed->timestamp); + capability = le16_to_cpu(fixed->capabilities); + beacon_interval = le16_to_cpu(fixed->beacon_interval); + + return cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac, + timestamp, capability, beacon_interval, ie, ie_len, signal, + GFP_KERNEL); +} + + +static int rndis_check_bssid_list(struct usbnet *usbdev) +{ + void *buf = NULL; + struct ndis_80211_bssid_list_ex *bssid_list; + struct ndis_80211_bssid_ex *bssid; + int ret = -EINVAL, len, count, bssid_len; + + devdbg(usbdev, "check_bssid_list"); + + len = CONTROL_BUFFER_SIZE; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out; + } + + ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); + if (ret != 0) + goto out; + + bssid_list = buf; + bssid = bssid_list->bssid; + bssid_len = le32_to_cpu(bssid->length); + count = le32_to_cpu(bssid_list->num_items); + devdbg(usbdev, "check_bssid_list: %d BSSIDs found", count); + + while (count && ((void *)bssid + bssid_len) <= (buf + len)) { + rndis_bss_info_update(usbdev, bssid); + + bssid = (void *)bssid + bssid_len; + bssid_len = le32_to_cpu(bssid->length); + count--; + } + +out: + kfree(buf); + return ret; +} + + +static void rndis_get_scan_results(struct work_struct *work) +{ + struct rndis_wext_private *priv = + container_of(work, struct rndis_wext_private, scan_work.work); + struct usbnet *usbdev = priv->usbdev; + int ret; + + devdbg(usbdev, "get_scan_results"); + + ret = rndis_check_bssid_list(usbdev); + + cfg80211_scan_done(priv->scan_request, ret < 0); + + priv->scan_request = NULL; +} + + /* * wireless extension handlers */ @@ -1531,198 +1674,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 usbnet *usbdev = netdev_priv(dev); - union iwreq_data evt; - int ret = -EINVAL; - __le32 tmp; - - devdbg(usbdev, "SIOCSIWSCAN"); - - if (wrqu->data.flags == 0) { - tmp = cpu_to_le32(1); - ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, - sizeof(tmp)); - evt.data.flags = 0; - evt.data.length = 0; - wireless_send_event(dev, SIOCGIWSCAN, &evt, NULL); - } - return ret; -} - - -static char *rndis_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *cev, - char *end_buf, - struct ndis_80211_bssid_ex *bssid) -{ - struct usbnet *usbdev = netdev_priv(dev); - u8 *ie; - char *current_val; - int bssid_len, ie_len, i; - u32 beacon, atim; - struct iw_event iwe; - unsigned char sbuf[32]; - - bssid_len = le32_to_cpu(bssid->length); - - devdbg(usbdev, "BSSID %pM", bssid->mac); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_ADDR_LEN); - - devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length), - bssid->ssid.essid); - iwe.cmd = SIOCGIWESSID; - iwe.u.essid.length = le32_to_cpu(bssid->ssid.length); - iwe.u.essid.flags = 1; - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, bssid->ssid.essid); - - devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra)); - iwe.cmd = SIOCGIWMODE; - switch (le32_to_cpu(bssid->net_infra)) { - case ndis_80211_infra_adhoc: - iwe.u.mode = IW_MODE_ADHOC; - break; - case ndis_80211_infra_infra: - iwe.u.mode = IW_MODE_INFRA; - break; - /*case ndis_80211_infra_auto_unknown:*/ - default: - iwe.u.mode = IW_MODE_AUTO; - break; - } - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_UINT_LEN); - - devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config)); - iwe.cmd = SIOCGIWFREQ; - dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq); - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_FREQ_LEN); - - devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi)); - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->rssi)); - iwe.u.qual.level = level_to_qual(le32_to_cpu(bssid->rssi)); - iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID; - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_QUAL_LEN); - - devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy)); - iwe.cmd = SIOCGIWENCODE; - iwe.u.data.length = 0; - if (le32_to_cpu(bssid->privacy) == ndis_80211_priv_accept_all) - iwe.u.data.flags = IW_ENCODE_DISABLED; - else - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); - - devdbg(usbdev, "RATES:"); - current_val = cev + iwe_stream_lcp_len(info); - iwe.cmd = SIOCGIWRATE; - for (i = 0; i < sizeof(bssid->rates); i++) { - if (bssid->rates[i] & 0x7f) { - iwe.u.bitrate.value = - ((bssid->rates[i] & 0x7f) * - 500000); - devdbg(usbdev, " %d", iwe.u.bitrate.value); - current_val = iwe_stream_add_value(info, cev, - current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - } - } - - if ((current_val - cev) > iwe_stream_lcp_len(info)) - cev = current_val; - - beacon = le32_to_cpu(bssid->config.beacon_period); - devdbg(usbdev, "BCN_INT %d", beacon); - iwe.cmd = IWEVCUSTOM; - snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon); - iwe.u.data.length = strlen(sbuf); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf); - - atim = le32_to_cpu(bssid->config.atim_window); - devdbg(usbdev, "ATIM %d", atim); - iwe.cmd = IWEVCUSTOM; - snprintf(sbuf, sizeof(sbuf), "atim=%u", atim); - iwe.u.data.length = strlen(sbuf); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf); - - ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); - ie_len = min(bssid_len - (int)sizeof(*bssid), - (int)le32_to_cpu(bssid->ie_length)); - ie_len -= sizeof(struct ndis_80211_fixed_ies); - while (ie_len >= 2 && 2 + ie[1] <= ie_len) { - if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 && - memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) || - ie[0] == WLAN_EID_RSN) { - devdbg(usbdev, "IE: WPA%d", - (ie[0] == WLAN_EID_RSN) ? 2 : 1); - iwe.cmd = IWEVGENIE; - /* arbitrary cut-off at 64 */ - iwe.u.data.length = min(ie[1] + 2, 64); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie); - } - - ie_len -= 2 + ie[1]; - ie += 2 + ie[1]; - } - - return cev; -} - - -static int rndis_iw_get_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - void *buf = NULL; - char *cev = extra; - struct ndis_80211_bssid_list_ex *bssid_list; - struct ndis_80211_bssid_ex *bssid; - int ret = -EINVAL, len, count, bssid_len; - - devdbg(usbdev, "SIOCGIWSCAN"); - - len = CONTROL_BUFFER_SIZE; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto out; - } - - ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); - - if (ret != 0) - goto out; - - bssid_list = buf; - bssid = bssid_list->bssid; - bssid_len = le32_to_cpu(bssid->length); - count = le32_to_cpu(bssid_list->num_items); - devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count); - - while (count && ((void *)bssid + bssid_len) <= (buf + len)) { - cev = rndis_translate_scan(dev, info, cev, - extra + IW_SCAN_MAX_DATA, bssid); - bssid = (void *)bssid + bssid_len; - bssid_len = le32_to_cpu(bssid->length); - count--; - } - -out: - wrqu->data.length = cev - extra; - wrqu->data.flags = 0; - kfree(buf); - return ret; -} - - static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2085,8 +2036,8 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid, IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid, - IW_IOCTL(SIOCSIWSCAN) = rndis_iw_set_scan, - IW_IOCTL(SIOCGIWSCAN) = rndis_iw_get_scan, + IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, + IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, IW_IOCTL(SIOCSIWNICKN) = rndis_iw_set_nick, @@ -2547,6 +2498,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); queue_delayed_work(priv->workqueue, &priv->stats_work, round_jiffies_relative(STATS_UPDATE_JIFFIES)); + INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); INIT_WORK(&priv->work, rndis_wext_worker); return 0; @@ -2565,6 +2517,7 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) disassociate(usbdev, 0); cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); -- cgit v0.10.2 From 55a3757a5703ebc58612ffbfbcb7f193dae17df7 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 27 Mar 2009 12:45:30 -0700 Subject: iwlwifi: change check triggering device restart after rfkill change The STATUS_ALIVE value cannot be used because it is cleared when interface is brought down and will not be set if rfkill is enabled when interface is started again. The interface can thus not be brought up if rfkill was enabled before stopping the interface and disabled after starting the interface. Change the test to use priv->is_open instead, this will be set when interface is started whether rfkill is enabled or not. Thanks to Helmut Schaa for the suggested fix. Signed-off-by: Reinette Chatre Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7609bfc..82abb1f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2054,7 +2054,7 @@ void iwl_bg_rf_kill(struct work_struct *work) "HW and/or SW RF Kill no longer active, restarting " "device\n"); if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && - test_bit(STATUS_ALIVE, &priv->status)) + priv->is_open) queue_work(priv->workqueue, &priv->restart); } else { /* make sure mac80211 stop sending Tx frame */ -- cgit v0.10.2 From fc2ada30cacc28c96eabc598d3ef294338d8dcf5 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 30 Mar 2009 22:30:27 -0400 Subject: ath9k: separate ath9k specific code from ath9k_regd_get_ctl() Until ath5k and ath9k share common channel structures, they will have to implement their own get_ctl() function. Split out the portion that only relies on the current band and reg domain so that it can be common code. Signed-off-by: Bob Copeland Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 4ca6251..43ed35b 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -16,6 +16,7 @@ #include #include +#include #include "ath9k.h" #include "regd_common.h" @@ -492,28 +493,37 @@ int ath9k_regd_init(struct ath_hw *ah) return 0; } -u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan) +static +u32 ath9k_regd_get_band_ctl(struct ath_hw *ah, enum ieee80211_band band) { - u32 ctl = NO_CTL; - if (!ah->regulatory.regpair || (ah->regulatory.country_code == CTRY_DEFAULT && is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) { - if (IS_CHAN_B(chan)) - ctl = SD_NO_CTL | CTL_11B; - else if (IS_CHAN_G(chan)) - ctl = SD_NO_CTL | CTL_11G; - else - ctl = SD_NO_CTL | CTL_11A; - return ctl; + return SD_NO_CTL; + } + + switch (band) { + case IEEE80211_BAND_2GHZ: + return ah->regulatory.regpair->reg_2ghz_ctl; + case IEEE80211_BAND_5GHZ: + return ah->regulatory.regpair->reg_5ghz_ctl; + default: + return NO_CTL; } + return NO_CTL; +} + +u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan) +{ + u32 ctl = ath9k_regd_get_band_ctl(ah, chan->chan->band); + if (IS_CHAN_B(chan)) - ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B; + ctl |= CTL_11B; else if (IS_CHAN_G(chan)) - ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G; + ctl |= CTL_11G; else - ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A; + ctl |= CTL_11A; return ctl; } -- cgit v0.10.2 From c02cf3738c9dbc446c160b9d49a001eb2be316c8 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 30 Mar 2009 22:30:28 -0400 Subject: ath9k: pass regd structure directly to regulatory functions All regulatory information is encapsulated by the ath9k_regulatory struct, so we can now change all the callers to take that directly instead of struct ath_hw. This in turn will enable us to move the regulatory functions to common code also used by ath5k, since both can use this regulatory struct. Signed-off-by: Bob Copeland Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index bb208f5..a8465bb 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -1331,7 +1331,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, ath9k_olc_init(ah); status = ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), + ath9k_regd_get_ctl(&ah->regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, @@ -1671,7 +1671,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } if (ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), + ath9k_regd_get_ctl(&ah->regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, @@ -3710,7 +3710,7 @@ bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); if (ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), + ath9k_regd_get_ctl(&ah->regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 76c58cc..3647a47 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1406,7 +1406,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (ath9k_regd_init(sc->sc_ah)) + if (ath9k_regd_init(&sc->sc_ah->regulatory)) goto bad; /* default to MONITOR mode */ @@ -1614,6 +1614,7 @@ int ath_attach(u16 devid, struct ath_softc *sc) struct ieee80211_hw *hw = sc->hw; const struct ieee80211_regdomain *regd; int error = 0, i; + struct ath9k_regulatory *reg; DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); @@ -1621,6 +1622,8 @@ int ath_attach(u16 devid, struct ath_softc *sc) if (error != 0) return error; + reg = &sc->sc_ah->regulatory; + /* get mac address from hardware and set in mac80211 */ SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); @@ -1653,10 +1656,10 @@ int ath_attach(u16 devid, struct ath_softc *sc) goto error_attach; #endif - if (ath9k_is_world_regd(sc->sc_ah)) { + if (ath9k_is_world_regd(reg)) { /* Anything applied here (prior to wiphy registration) gets * saved on the wiphy orig_* parameters */ - regd = ath9k_world_regdomain(sc->sc_ah); + regd = ath9k_world_regdomain(reg); hw->wiphy->custom_regulatory = true; hw->wiphy->strict_regulatory = false; } else { @@ -1667,7 +1670,9 @@ int ath_attach(u16 devid, struct ath_softc *sc) } wiphy_apply_custom_regulatory(hw->wiphy, regd); ath9k_reg_apply_radar_flags(hw->wiphy); - ath9k_reg_apply_world_flags(hw->wiphy, NL80211_REGDOM_SET_BY_DRIVER); + ath9k_reg_apply_world_flags(hw->wiphy, + NL80211_REGDOM_SET_BY_DRIVER, + reg); INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); @@ -1675,9 +1680,8 @@ int ath_attach(u16 devid, struct ath_softc *sc) error = ieee80211_register_hw(hw); - if (!ath9k_is_world_regd(sc->sc_ah)) { - error = regulatory_hint(hw->wiphy, - sc->sc_ah->regulatory.alpha2); + if (!ath9k_is_world_regd(reg)) { + error = regulatory_hint(hw->wiphy, reg->alpha2); if (error) goto error_attach; } diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 43ed35b..7eaa59e 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -113,14 +113,14 @@ static inline bool is_wwr_sku(u16 regd) (regd == WORLD); } -static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah) +static u16 ath9k_regd_get_eepromRD(struct ath9k_regulatory *reg) { - return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG; + return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; } -bool ath9k_is_world_regd(struct ath_hw *ah) +bool ath9k_is_world_regd(struct ath9k_regulatory *reg) { - return is_wwr_sku(ath9k_regd_get_eepromRD(ah)); + return is_wwr_sku(ath9k_regd_get_eepromRD(reg)); } const struct ieee80211_regdomain *ath9k_default_world_regdomain(void) @@ -129,9 +129,10 @@ const struct ieee80211_regdomain *ath9k_default_world_regdomain(void) return &ath9k_world_regdom_64; } -const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah) +const struct +ieee80211_regdomain *ath9k_world_regdomain(struct ath9k_regulatory *reg) { - switch (ah->regulatory.regpair->regDmnEnum) { + switch (reg->regpair->regDmnEnum) { case 0x60: case 0x61: case 0x62: @@ -312,14 +313,10 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy) } void ath9k_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) + enum nl80211_reg_initiator initiator, + struct ath9k_regulatory *reg) { - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; - - switch (ah->regulatory.regpair->regDmnEnum) { + switch (reg->regpair->regDmnEnum) { case 0x60: case 0x63: case 0x66: @@ -334,12 +331,9 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, return; } -int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +static int ath9k_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, struct ath9k_regulatory *reg) { - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - /* We always apply this */ ath9k_reg_apply_radar_flags(wiphy); @@ -349,17 +343,28 @@ int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) case NL80211_REGDOM_SET_BY_USER: break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - if (ath9k_is_world_regd(sc->sc_ah)) - ath9k_reg_apply_world_flags(wiphy, request->initiator); + if (ath9k_is_world_regd(reg)) + ath9k_reg_apply_world_flags(wiphy, request->initiator, + reg); break; } return 0; } -bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah) +int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath9k_regulatory *reg = &sc->sc_ah->regulatory; + + return ath9k_reg_notifier_apply(wiphy, request, reg); +} + +bool ath9k_regd_is_eeprom_valid(struct ath9k_regulatory *reg) { - u16 rd = ath9k_regd_get_eepromRD(ah); + u16 rd = ath9k_regd_get_eepromRD(reg); int i; if (rd & COUNTRY_ERD_FLAG) { @@ -374,8 +379,8 @@ bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah) if (regDomainPairs[i].regDmnEnum == rd) return true; } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "invalid regulatory domain/country code 0x%x\n", rd); + printk(KERN_DEBUG + "ath9k: invalid regulatory domain/country code 0x%x\n", rd); return false; } @@ -434,41 +439,40 @@ ath9k_get_regpair(int regdmn) return NULL; } -int ath9k_regd_init(struct ath_hw *ah) +int ath9k_regd_init(struct ath9k_regulatory *reg) { struct country_code_to_enum_rd *country = NULL; u16 regdmn; - if (!ath9k_regd_is_eeprom_valid(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Invalid EEPROM contents\n"); + if (!ath9k_regd_is_eeprom_valid(reg)) { + printk(KERN_DEBUG "ath9k: Invalid EEPROM contents\n"); return -EINVAL; } - regdmn = ath9k_regd_get_eepromRD(ah); - ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn); + regdmn = ath9k_regd_get_eepromRD(reg); + reg->country_code = ath9k_regd_get_default_country(regdmn); - if (ah->regulatory.country_code == CTRY_DEFAULT && + if (reg->country_code == CTRY_DEFAULT && regdmn == CTRY_DEFAULT) - ah->regulatory.country_code = CTRY_UNITED_STATES; + reg->country_code = CTRY_UNITED_STATES; - if (ah->regulatory.country_code == CTRY_DEFAULT) { + if (reg->country_code == CTRY_DEFAULT) { country = NULL; } else { - country = ath9k_regd_find_country(ah->regulatory.country_code); + country = ath9k_regd_find_country(reg->country_code); if (country == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Country is NULL!!!!, cc= %d\n", - ah->regulatory.country_code); + printk(KERN_DEBUG + "ath9k: Country is NULL!!!!, cc= %d\n", + reg->country_code); return -EINVAL; } else regdmn = country->regDmnEnum; } - ah->regulatory.regpair = ath9k_get_regpair(regdmn); + reg->regpair = ath9k_get_regpair(regdmn); - if (!ah->regulatory.regpair) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + if (!reg->regpair) { + printk(KERN_DEBUG "ath9k: " "No regulatory domain pair found, cannot continue\n"); return -EINVAL; } @@ -477,36 +481,36 @@ int ath9k_regd_init(struct ath_hw *ah) country = ath9k_regd_find_country_by_rd(regdmn); if (country) { - ah->regulatory.alpha2[0] = country->isoName[0]; - ah->regulatory.alpha2[1] = country->isoName[1]; + reg->alpha2[0] = country->isoName[0]; + reg->alpha2[1] = country->isoName[1]; } else { - ah->regulatory.alpha2[0] = '0'; - ah->regulatory.alpha2[1] = '0'; + reg->alpha2[0] = '0'; + reg->alpha2[1] = '0'; } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Country alpha2 being used: %c%c\n" - "Regulatory.Regpair detected: 0x%0x\n", - ah->regulatory.alpha2[0], ah->regulatory.alpha2[1], - ah->regulatory.regpair->regDmnEnum); + printk(KERN_DEBUG "ath9k: Country alpha2 being used: %c%c\n", + reg->alpha2[0], reg->alpha2[1]); + printk(KERN_DEBUG "ath9k: Regpair detected: 0x%0x\n", + reg->regpair->regDmnEnum); return 0; } static -u32 ath9k_regd_get_band_ctl(struct ath_hw *ah, enum ieee80211_band band) +u32 ath9k_regd_get_band_ctl(struct ath9k_regulatory *reg, + enum ieee80211_band band) { - if (!ah->regulatory.regpair || - (ah->regulatory.country_code == CTRY_DEFAULT && - is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) { + if (!reg->regpair || + (reg->country_code == CTRY_DEFAULT && + is_wwr_sku(ath9k_regd_get_eepromRD(reg)))) { return SD_NO_CTL; } switch (band) { case IEEE80211_BAND_2GHZ: - return ah->regulatory.regpair->reg_2ghz_ctl; + return reg->regpair->reg_2ghz_ctl; case IEEE80211_BAND_5GHZ: - return ah->regulatory.regpair->reg_5ghz_ctl; + return reg->regpair->reg_5ghz_ctl; default: return NO_CTL; } @@ -514,9 +518,9 @@ u32 ath9k_regd_get_band_ctl(struct ath_hw *ah, enum ieee80211_band band) return NO_CTL; } -u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan) +u32 ath9k_regd_get_ctl(struct ath9k_regulatory *reg, struct ath9k_channel *chan) { - u32 ctl = ath9k_regd_get_band_ctl(ah, chan->chan->band); + u32 ctl = ath9k_regd_get_band_ctl(reg, chan->chan->band); if (IS_CHAN_B(chan)) ctl |= CTL_11B; diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h index 9f5fbd4..61fa42e 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath9k/regd.h @@ -17,6 +17,8 @@ #ifndef REGD_H #define REGD_H +#include + #define COUNTRY_ERD_FLAG 0x8000 #define WORLDWIDE_ROAMING_FLAG 0x4000 @@ -233,15 +235,18 @@ enum CountryCode { CTRY_BELGIUM2 = 5002 }; -bool ath9k_is_world_regd(struct ath_hw *ah); -const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah); +bool ath9k_is_world_regd(struct ath9k_regulatory *reg); +const struct ieee80211_regdomain *ath9k_world_regdomain( + struct ath9k_regulatory *reg); const struct ieee80211_regdomain *ath9k_default_world_regdomain(void); void ath9k_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator); + enum nl80211_reg_initiator, + struct ath9k_regulatory *reg); void ath9k_reg_apply_radar_flags(struct wiphy *wiphy); -int ath9k_regd_init(struct ath_hw *ah); -bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah); -u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan); +int ath9k_regd_init(struct ath9k_regulatory *reg); +bool ath9k_regd_is_eeprom_valid(struct ath9k_regulatory *reg); +u32 ath9k_regd_get_ctl(struct ath9k_regulatory *reg, + struct ath9k_channel *chan); int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); #endif -- cgit v0.10.2 From 3a702e49c03ba959e3f5bb2b74ec9921a81c8c98 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 30 Mar 2009 22:30:29 -0400 Subject: atheros: introduce ath module containing common ath5k/ath9k/ar9170 code This change creates a new module, ath.ko, which includes code that can be shared between ath5k, ath9k and ar9170. For now, extract most of the ath9k regulatory code so it can also be used in ath5k. Signed-off-by: Bob Copeland Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8a08235..9e2c7e2 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -483,6 +483,7 @@ config MWL8K will be called mwl8k. If unsure, say N. source "drivers/net/wireless/p54/Kconfig" +source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/ath5k/Kconfig" source "drivers/net/wireless/ath9k/Kconfig" source "drivers/net/wireless/ar9170/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 50e7fba..104639e 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_P54_COMMON) += p54/ +obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_ATH5K) += ath5k/ obj-$(CONFIG_ATH9K) += ath9k/ obj-$(CONFIG_AR9170_USB) += ar9170/ diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig new file mode 100644 index 0000000..c2873a2 --- /dev/null +++ b/drivers/net/wireless/ath/Kconfig @@ -0,0 +1,4 @@ +config ATH_COMMON + tristate "Atheros Wireless Cards Shared Support" + depends on ATH5K || ATH9K + diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile new file mode 100644 index 0000000..bc77646 --- /dev/null +++ b/drivers/net/wireless/ath/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_ATH_COMMON) += ath.o +ath-objs := regd.o + diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c new file mode 100644 index 0000000..4d3935b --- /dev/null +++ b/drivers/net/wireless/ath/regd.c @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "regd.h" +#include "regd_common.h" + +/* + * This is a set of common rules used by our world regulatory domains. + * We have 12 world regulatory domains. To save space we consolidate + * the regulatory domains in 5 structures by frequency and change + * the flags on our reg_notifier() on a case by case basis. + */ + +/* Only these channels all allow active scan on all world regulatory domains */ +#define ATH9K_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) + +/* We enable active scan on these a case by case basis by regulatory domain */ +#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ + NL80211_RRF_PASSIVE_SCAN) +#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) + +/* We allow IBSS on these on a case by case basis by regulatory domain */ +#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 40, 0, 30,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) +#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 40, 0, 30,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) +#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 40, 0, 30,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \ + ATH9K_2GHZ_CH12_13, \ + ATH9K_2GHZ_CH14 + +#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \ + ATH9K_5GHZ_5470_5850 +/* This one skips what we call "mid band" */ +#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ + ATH9K_5GHZ_5725_5850 + +/* Can be used for: + * 0x60, 0x61, 0x62 */ +static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { + .n_reg_rules = 5, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_ALL, + ATH9K_5GHZ_ALL, + } +}; + +/* Can be used by 0x63 and 0x65 */ +static const struct ieee80211_regdomain ath_world_regdom_63_65 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_2GHZ_CH12_13, + ATH9K_5GHZ_NO_MIDBAND, + } +}; + +/* Can be used by 0x64 only */ +static const struct ieee80211_regdomain ath_world_regdom_64 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_5GHZ_NO_MIDBAND, + } +}; + +/* Can be used by 0x66 and 0x69 */ +static const struct ieee80211_regdomain ath_world_regdom_66_69 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_5GHZ_ALL, + } +}; + +/* Can be used by 0x67, 0x6A and 0x68 */ +static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_2GHZ_CH12_13, + ATH9K_5GHZ_ALL, + } +}; + +static inline bool is_wwr_sku(u16 regd) +{ + return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || + (regd == WORLD); +} + +static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) +{ + return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; +} + +bool ath_is_world_regd(struct ath_regulatory *reg) +{ + return is_wwr_sku(ath_regd_get_eepromRD(reg)); +} +EXPORT_SYMBOL(ath_is_world_regd); + +const struct ieee80211_regdomain *ath_default_world_regdomain(void) +{ + /* this is the most restrictive */ + return &ath_world_regdom_64; +} +EXPORT_SYMBOL(ath_default_world_regdomain); + +const struct +ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) +{ + switch (reg->regpair->regDmnEnum) { + case 0x60: + case 0x61: + case 0x62: + return &ath_world_regdom_60_61_62; + case 0x63: + case 0x65: + return &ath_world_regdom_63_65; + case 0x64: + return &ath_world_regdom_64; + case 0x66: + case 0x69: + return &ath_world_regdom_66_69; + case 0x67: + case 0x68: + case 0x6A: + return &ath_world_regdom_67_68_6A; + default: + WARN_ON(1); + return ath_default_world_regdomain(); + } +} +EXPORT_SYMBOL(ath_world_regdomain); + +/* Frequency is one where radar detection is required */ +static bool ath_is_radar_freq(u16 center_freq) +{ + return (center_freq >= 5260 && center_freq <= 5700); +} + +/* + * N.B: These exception rules do not apply radar freqs. + * + * - We enable adhoc (or beaconing) if allowed by 11d + * - We enable active scan if the channel is allowed by 11d + * - If no country IE has been processed and a we determine we have + * received a beacon on a channel we can enable active scan and + * adhoc (or beaconing). + */ +static void ath_reg_apply_beaconing_flags( + struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + const struct ieee80211_reg_rule *reg_rule; + struct ieee80211_channel *ch; + unsigned int i; + u32 bandwidth = 0; + int r; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + + if (!wiphy->bands[band]) + continue; + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) { + + ch = &sband->channels[i]; + + if (ath_is_radar_freq(ch->center_freq) || + (ch->flags & IEEE80211_CHAN_RADAR)) + continue; + + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { + r = freq_reg_info(wiphy, ch->center_freq, + &bandwidth, ®_rule); + if (r) + continue; + /* + * If 11d had a rule for this channel ensure + * we enable adhoc/beaconing if it allows us to + * use it. Note that we would have disabled it + * by applying our static world regdomain by + * default during init, prior to calling our + * regulatory_hint(). + */ + if (!(reg_rule->flags & + NL80211_RRF_NO_IBSS)) + ch->flags &= + ~IEEE80211_CHAN_NO_IBSS; + if (!(reg_rule->flags & + NL80211_RRF_PASSIVE_SCAN)) + ch->flags &= + ~IEEE80211_CHAN_PASSIVE_SCAN; + } else { + if (ch->beacon_found) + ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN); + } + } + } + +} + +/* Allows active scan scan on Ch 12 and 13 */ +static void ath_reg_apply_active_scan_flags( + struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + const struct ieee80211_reg_rule *reg_rule; + u32 bandwidth = 0; + int r; + + sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + + /* + * If no country IE has been received always enable active scan + * on these channels. This is only done for specific regulatory SKUs + */ + if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + ch = &sband->channels[11]; /* CH 12 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + ch = &sband->channels[12]; /* CH 13 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + return; + } + + /* + * If a country IE has been recieved check its rule for this + * channel first before enabling active scan. The passive scan + * would have been enforced by the initial processing of our + * custom regulatory domain. + */ + + ch = &sband->channels[11]; /* CH 12 */ + r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + if (!r) { + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } + + ch = &sband->channels[12]; /* CH 13 */ + r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + if (!r) { + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } +} + +/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ +void ath_reg_apply_radar_flags(struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + unsigned int i; + + if (!wiphy->bands[IEEE80211_BAND_5GHZ]) + return; + + sband = wiphy->bands[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (!ath_is_radar_freq(ch->center_freq)) + continue; + /* We always enable radar detection/DFS on this + * frequency range. Additionally we also apply on + * this frequency range: + * - If STA mode does not yet have DFS supports disable + * active scanning + * - If adhoc mode does not support DFS yet then + * disable adhoc in the frequency. + * - If AP mode does not yet support radar detection/DFS + * do not allow AP mode + */ + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) + ch->flags |= IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN; + } +} +EXPORT_SYMBOL(ath_reg_apply_radar_flags); + +void ath_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + struct ath_regulatory *reg) +{ + switch (reg->regpair->regDmnEnum) { + case 0x60: + case 0x63: + case 0x66: + case 0x67: + ath_reg_apply_beaconing_flags(wiphy, initiator); + break; + case 0x68: + ath_reg_apply_beaconing_flags(wiphy, initiator); + ath_reg_apply_active_scan_flags(wiphy, initiator); + break; + } + return; +} +EXPORT_SYMBOL(ath_reg_apply_world_flags); + +int ath_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, struct ath_regulatory *reg) +{ + /* We always apply this */ + ath_reg_apply_radar_flags(wiphy); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + break; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + if (ath_is_world_regd(reg)) + ath_reg_apply_world_flags(wiphy, request->initiator, + reg); + break; + } + + return 0; +} +EXPORT_SYMBOL(ath_reg_notifier_apply); + +bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) +{ + u16 rd = ath_regd_get_eepromRD(reg); + int i; + + if (rd & COUNTRY_ERD_FLAG) { + /* EEPROM value is a country code */ + u16 cc = rd & ~COUNTRY_ERD_FLAG; + for (i = 0; i < ARRAY_SIZE(allCountries); i++) + if (allCountries[i].countryCode == cc) + return true; + } else { + /* EEPROM value is a regpair value */ + for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) + if (regDomainPairs[i].regDmnEnum == rd) + return true; + } + printk(KERN_DEBUG + "ath: invalid regulatory domain/country code 0x%x\n", rd); + return false; +} +EXPORT_SYMBOL(ath_regd_is_eeprom_valid); + +/* EEPROM country code to regpair mapping */ +static struct country_code_to_enum_rd* +ath_regd_find_country(u16 countryCode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].countryCode == countryCode) + return &allCountries[i]; + } + return NULL; +} + +/* EEPROM rd code to regpair mapping */ +static struct country_code_to_enum_rd* +ath_regd_find_country_by_rd(int regdmn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].regDmnEnum == regdmn) + return &allCountries[i]; + } + return NULL; +} + +/* Returns the map of the EEPROM set RD to a country code */ +static u16 ath_regd_get_default_country(u16 rd) +{ + if (rd & COUNTRY_ERD_FLAG) { + struct country_code_to_enum_rd *country = NULL; + u16 cc = rd & ~COUNTRY_ERD_FLAG; + + country = ath_regd_find_country(cc); + if (country != NULL) + return cc; + } + + return CTRY_DEFAULT; +} + +static struct reg_dmn_pair_mapping* +ath_get_regpair(int regdmn) +{ + int i; + + if (regdmn == NO_ENUMRD) + return NULL; + for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { + if (regDomainPairs[i].regDmnEnum == regdmn) + return ®DomainPairs[i]; + } + return NULL; +} + +int ath_regd_init(struct ath_regulatory *reg) +{ + struct country_code_to_enum_rd *country = NULL; + u16 regdmn; + + if (!ath_regd_is_eeprom_valid(reg)) { + printk(KERN_DEBUG "ath: Invalid EEPROM contents\n"); + return -EINVAL; + } + + regdmn = ath_regd_get_eepromRD(reg); + reg->country_code = ath_regd_get_default_country(regdmn); + + if (reg->country_code == CTRY_DEFAULT && + regdmn == CTRY_DEFAULT) + reg->country_code = CTRY_UNITED_STATES; + + if (reg->country_code == CTRY_DEFAULT) { + country = NULL; + } else { + country = ath_regd_find_country(reg->country_code); + if (country == NULL) { + printk(KERN_DEBUG + "ath: Country is NULL!!!!, cc= %d\n", + reg->country_code); + return -EINVAL; + } else + regdmn = country->regDmnEnum; + } + + reg->regpair = ath_get_regpair(regdmn); + + if (!reg->regpair) { + printk(KERN_DEBUG "ath: " + "No regulatory domain pair found, cannot continue\n"); + return -EINVAL; + } + + if (!country) + country = ath_regd_find_country_by_rd(regdmn); + + if (country) { + reg->alpha2[0] = country->isoName[0]; + reg->alpha2[1] = country->isoName[1]; + } else { + reg->alpha2[0] = '0'; + reg->alpha2[1] = '0'; + } + + printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", + reg->alpha2[0], reg->alpha2[1]); + printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n", + reg->regpair->regDmnEnum); + + return 0; +} +EXPORT_SYMBOL(ath_regd_init); + +u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, + enum ieee80211_band band) +{ + if (!reg->regpair || + (reg->country_code == CTRY_DEFAULT && + is_wwr_sku(ath_regd_get_eepromRD(reg)))) { + return SD_NO_CTL; + } + + switch (band) { + case IEEE80211_BAND_2GHZ: + return reg->regpair->reg_2ghz_ctl; + case IEEE80211_BAND_5GHZ: + return reg->regpair->reg_5ghz_ctl; + default: + return NO_CTL; + } + + return NO_CTL; +} +EXPORT_SYMBOL(ath_regd_get_band_ctl); diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h new file mode 100644 index 0000000..981f5cf --- /dev/null +++ b/drivers/net/wireless/ath/regd.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REGD_H +#define REGD_H + +#include + +#include +#include + +#define NO_CTL 0xff +#define SD_NO_CTL 0xE0 +#define NO_CTL 0xff +#define CTL_MODE_M 7 +#define CTL_11A 0 +#define CTL_11B 1 +#define CTL_11G 2 +#define CTL_2GHT20 5 +#define CTL_5GHT20 6 +#define CTL_2GHT40 7 +#define CTL_5GHT40 8 + +#define CTRY_DEBUG 0x1ff +#define CTRY_DEFAULT 0 + +#define COUNTRY_ERD_FLAG 0x8000 +#define WORLDWIDE_ROAMING_FLAG 0x4000 + +#define MULTI_DOMAIN_MASK 0xFF00 + +#define WORLD_SKU_MASK 0x00F0 +#define WORLD_SKU_PREFIX 0x0060 + +#define CHANNEL_HALF_BW 10 +#define CHANNEL_QUARTER_BW 5 + +struct reg_dmn_pair_mapping { + u16 regDmnEnum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +struct country_code_to_enum_rd { + u16 countryCode; + u16 regDmnEnum; + const char *isoName; +}; + +struct ath_regulatory { + char alpha2[2]; + u16 country_code; + u16 max_power_level; + u32 tp_scale; + u16 current_rd; + u16 current_rd_ext; + int16_t power_limit; + struct reg_dmn_pair_mapping *regpair; +}; + +enum CountryCode { + CTRY_ALBANIA = 8, + CTRY_ALGERIA = 12, + CTRY_ARGENTINA = 32, + CTRY_ARMENIA = 51, + CTRY_AUSTRALIA = 36, + CTRY_AUSTRIA = 40, + CTRY_AZERBAIJAN = 31, + CTRY_BAHRAIN = 48, + CTRY_BELARUS = 112, + CTRY_BELGIUM = 56, + CTRY_BELIZE = 84, + CTRY_BOLIVIA = 68, + CTRY_BOSNIA_HERZ = 70, + CTRY_BRAZIL = 76, + CTRY_BRUNEI_DARUSSALAM = 96, + CTRY_BULGARIA = 100, + CTRY_CANADA = 124, + CTRY_CHILE = 152, + CTRY_CHINA = 156, + CTRY_COLOMBIA = 170, + CTRY_COSTA_RICA = 188, + CTRY_CROATIA = 191, + CTRY_CYPRUS = 196, + CTRY_CZECH = 203, + CTRY_DENMARK = 208, + CTRY_DOMINICAN_REPUBLIC = 214, + CTRY_ECUADOR = 218, + CTRY_EGYPT = 818, + CTRY_EL_SALVADOR = 222, + CTRY_ESTONIA = 233, + CTRY_FAEROE_ISLANDS = 234, + CTRY_FINLAND = 246, + CTRY_FRANCE = 250, + CTRY_GEORGIA = 268, + CTRY_GERMANY = 276, + CTRY_GREECE = 300, + CTRY_GUATEMALA = 320, + CTRY_HONDURAS = 340, + CTRY_HONG_KONG = 344, + CTRY_HUNGARY = 348, + CTRY_ICELAND = 352, + CTRY_INDIA = 356, + CTRY_INDONESIA = 360, + CTRY_IRAN = 364, + CTRY_IRAQ = 368, + CTRY_IRELAND = 372, + CTRY_ISRAEL = 376, + CTRY_ITALY = 380, + CTRY_JAMAICA = 388, + CTRY_JAPAN = 392, + CTRY_JORDAN = 400, + CTRY_KAZAKHSTAN = 398, + CTRY_KENYA = 404, + CTRY_KOREA_NORTH = 408, + CTRY_KOREA_ROC = 410, + CTRY_KOREA_ROC2 = 411, + CTRY_KOREA_ROC3 = 412, + CTRY_KUWAIT = 414, + CTRY_LATVIA = 428, + CTRY_LEBANON = 422, + CTRY_LIBYA = 434, + CTRY_LIECHTENSTEIN = 438, + CTRY_LITHUANIA = 440, + CTRY_LUXEMBOURG = 442, + CTRY_MACAU = 446, + CTRY_MACEDONIA = 807, + CTRY_MALAYSIA = 458, + CTRY_MALTA = 470, + CTRY_MEXICO = 484, + CTRY_MONACO = 492, + CTRY_MOROCCO = 504, + CTRY_NEPAL = 524, + CTRY_NETHERLANDS = 528, + CTRY_NETHERLANDS_ANTILLES = 530, + CTRY_NEW_ZEALAND = 554, + CTRY_NICARAGUA = 558, + CTRY_NORWAY = 578, + CTRY_OMAN = 512, + CTRY_PAKISTAN = 586, + CTRY_PANAMA = 591, + CTRY_PAPUA_NEW_GUINEA = 598, + CTRY_PARAGUAY = 600, + CTRY_PERU = 604, + CTRY_PHILIPPINES = 608, + CTRY_POLAND = 616, + CTRY_PORTUGAL = 620, + CTRY_PUERTO_RICO = 630, + CTRY_QATAR = 634, + CTRY_ROMANIA = 642, + CTRY_RUSSIA = 643, + CTRY_SAUDI_ARABIA = 682, + CTRY_SERBIA_MONTENEGRO = 891, + CTRY_SINGAPORE = 702, + CTRY_SLOVAKIA = 703, + CTRY_SLOVENIA = 705, + CTRY_SOUTH_AFRICA = 710, + CTRY_SPAIN = 724, + CTRY_SRI_LANKA = 144, + CTRY_SWEDEN = 752, + CTRY_SWITZERLAND = 756, + CTRY_SYRIA = 760, + CTRY_TAIWAN = 158, + CTRY_THAILAND = 764, + CTRY_TRINIDAD_Y_TOBAGO = 780, + CTRY_TUNISIA = 788, + CTRY_TURKEY = 792, + CTRY_UAE = 784, + CTRY_UKRAINE = 804, + CTRY_UNITED_KINGDOM = 826, + CTRY_UNITED_STATES = 840, + CTRY_UNITED_STATES_FCC49 = 842, + CTRY_URUGUAY = 858, + CTRY_UZBEKISTAN = 860, + CTRY_VENEZUELA = 862, + CTRY_VIET_NAM = 704, + CTRY_YEMEN = 887, + CTRY_ZIMBABWE = 716, + CTRY_JAPAN1 = 393, + CTRY_JAPAN2 = 394, + CTRY_JAPAN3 = 395, + CTRY_JAPAN4 = 396, + CTRY_JAPAN5 = 397, + CTRY_JAPAN6 = 4006, + CTRY_JAPAN7 = 4007, + CTRY_JAPAN8 = 4008, + CTRY_JAPAN9 = 4009, + CTRY_JAPAN10 = 4010, + CTRY_JAPAN11 = 4011, + CTRY_JAPAN12 = 4012, + CTRY_JAPAN13 = 4013, + CTRY_JAPAN14 = 4014, + CTRY_JAPAN15 = 4015, + CTRY_JAPAN16 = 4016, + CTRY_JAPAN17 = 4017, + CTRY_JAPAN18 = 4018, + CTRY_JAPAN19 = 4019, + CTRY_JAPAN20 = 4020, + CTRY_JAPAN21 = 4021, + CTRY_JAPAN22 = 4022, + CTRY_JAPAN23 = 4023, + CTRY_JAPAN24 = 4024, + CTRY_JAPAN25 = 4025, + CTRY_JAPAN26 = 4026, + CTRY_JAPAN27 = 4027, + CTRY_JAPAN28 = 4028, + CTRY_JAPAN29 = 4029, + CTRY_JAPAN30 = 4030, + CTRY_JAPAN31 = 4031, + CTRY_JAPAN32 = 4032, + CTRY_JAPAN33 = 4033, + CTRY_JAPAN34 = 4034, + CTRY_JAPAN35 = 4035, + CTRY_JAPAN36 = 4036, + CTRY_JAPAN37 = 4037, + CTRY_JAPAN38 = 4038, + CTRY_JAPAN39 = 4039, + CTRY_JAPAN40 = 4040, + CTRY_JAPAN41 = 4041, + CTRY_JAPAN42 = 4042, + CTRY_JAPAN43 = 4043, + CTRY_JAPAN44 = 4044, + CTRY_JAPAN45 = 4045, + CTRY_JAPAN46 = 4046, + CTRY_JAPAN47 = 4047, + CTRY_JAPAN48 = 4048, + CTRY_JAPAN49 = 4049, + CTRY_JAPAN50 = 4050, + CTRY_JAPAN51 = 4051, + CTRY_JAPAN52 = 4052, + CTRY_JAPAN53 = 4053, + CTRY_JAPAN54 = 4054, + CTRY_JAPAN55 = 4055, + CTRY_JAPAN56 = 4056, + CTRY_JAPAN57 = 4057, + CTRY_JAPAN58 = 4058, + CTRY_JAPAN59 = 4059, + CTRY_AUSTRALIA2 = 5000, + CTRY_CANADA2 = 5001, + CTRY_BELGIUM2 = 5002 +}; + +bool ath_is_world_regd(struct ath_regulatory *reg); +const +struct ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg); +const struct ieee80211_regdomain *ath_default_world_regdomain(void); +void ath_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator, + struct ath_regulatory *reg); +void ath_reg_apply_radar_flags(struct wiphy *wiphy); +int ath_regd_init(struct ath_regulatory *reg); +bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg); +u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, + enum ieee80211_band band); +int ath_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct ath_regulatory *reg); + +#endif diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h new file mode 100644 index 0000000..4d0e298 --- /dev/null +++ b/drivers/net/wireless/ath/regd_common.h @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REGD_COMMON_H +#define REGD_COMMON_H + +enum EnumRd { + NO_ENUMRD = 0x00, + NULL1_WORLD = 0x03, + NULL1_ETSIB = 0x07, + NULL1_ETSIC = 0x08, + FCC1_FCCA = 0x10, + FCC1_WORLD = 0x11, + FCC4_FCCA = 0x12, + FCC5_FCCA = 0x13, + FCC6_FCCA = 0x14, + + FCC2_FCCA = 0x20, + FCC2_WORLD = 0x21, + FCC2_ETSIC = 0x22, + FCC6_WORLD = 0x23, + FRANCE_RES = 0x31, + FCC3_FCCA = 0x3A, + FCC3_WORLD = 0x3B, + + ETSI1_WORLD = 0x37, + ETSI3_ETSIA = 0x32, + ETSI2_WORLD = 0x35, + ETSI3_WORLD = 0x36, + ETSI4_WORLD = 0x30, + ETSI4_ETSIC = 0x38, + ETSI5_WORLD = 0x39, + ETSI6_WORLD = 0x34, + ETSI_RESERVED = 0x33, + + MKK1_MKKA = 0x40, + MKK1_MKKB = 0x41, + APL4_WORLD = 0x42, + MKK2_MKKA = 0x43, + APL_RESERVED = 0x44, + APL2_WORLD = 0x45, + APL2_APLC = 0x46, + APL3_WORLD = 0x47, + MKK1_FCCA = 0x48, + APL2_APLD = 0x49, + MKK1_MKKA1 = 0x4A, + MKK1_MKKA2 = 0x4B, + MKK1_MKKC = 0x4C, + + APL3_FCCA = 0x50, + APL1_WORLD = 0x52, + APL1_FCCA = 0x53, + APL1_APLA = 0x54, + APL1_ETSIC = 0x55, + APL2_ETSIC = 0x56, + APL5_WORLD = 0x58, + APL6_WORLD = 0x5B, + APL7_FCCA = 0x5C, + APL8_WORLD = 0x5D, + APL9_WORLD = 0x5E, + + WOR0_WORLD = 0x60, + WOR1_WORLD = 0x61, + WOR2_WORLD = 0x62, + WOR3_WORLD = 0x63, + WOR4_WORLD = 0x64, + WOR5_ETSIC = 0x65, + + WOR01_WORLD = 0x66, + WOR02_WORLD = 0x67, + EU1_WORLD = 0x68, + + WOR9_WORLD = 0x69, + WORA_WORLD = 0x6A, + WORB_WORLD = 0x6B, + + MKK3_MKKB = 0x80, + MKK3_MKKA2 = 0x81, + MKK3_MKKC = 0x82, + + MKK4_MKKB = 0x83, + MKK4_MKKA2 = 0x84, + MKK4_MKKC = 0x85, + + MKK5_MKKB = 0x86, + MKK5_MKKA2 = 0x87, + MKK5_MKKC = 0x88, + + MKK6_MKKB = 0x89, + MKK6_MKKA2 = 0x8A, + MKK6_MKKC = 0x8B, + + MKK7_MKKB = 0x8C, + MKK7_MKKA2 = 0x8D, + MKK7_MKKC = 0x8E, + + MKK8_MKKB = 0x8F, + MKK8_MKKA2 = 0x90, + MKK8_MKKC = 0x91, + + MKK14_MKKA1 = 0x92, + MKK15_MKKA1 = 0x93, + + MKK10_FCCA = 0xD0, + MKK10_MKKA1 = 0xD1, + MKK10_MKKC = 0xD2, + MKK10_MKKA2 = 0xD3, + + MKK11_MKKA = 0xD4, + MKK11_FCCA = 0xD5, + MKK11_MKKA1 = 0xD6, + MKK11_MKKC = 0xD7, + MKK11_MKKA2 = 0xD8, + + MKK12_MKKA = 0xD9, + MKK12_FCCA = 0xDA, + MKK12_MKKA1 = 0xDB, + MKK12_MKKC = 0xDC, + MKK12_MKKA2 = 0xDD, + + MKK13_MKKB = 0xDE, + + MKK3_MKKA = 0xF0, + MKK3_MKKA1 = 0xF1, + MKK3_FCCA = 0xF2, + MKK4_MKKA = 0xF3, + MKK4_MKKA1 = 0xF4, + MKK4_FCCA = 0xF5, + MKK9_MKKA = 0xF6, + MKK10_MKKA = 0xF7, + MKK6_MKKA1 = 0xF8, + MKK6_FCCA = 0xF9, + MKK7_MKKA1 = 0xFA, + MKK7_FCCA = 0xFB, + MKK9_FCCA = 0xFC, + MKK9_MKKA1 = 0xFD, + MKK9_MKKC = 0xFE, + MKK9_MKKA2 = 0xFF, + + WORLD = 0x0199, + DEBUG_REG_DMN = 0x01ff, +}; + +enum ctl_group { + CTL_FCC = 0x10, + CTL_MKK = 0x40, + CTL_ETSI = 0x30, +}; + +/* Regpair to CTL band mapping */ +static struct reg_dmn_pair_mapping regDomainPairs[] = { + /* regpair, 5 GHz CTL, 2 GHz CTL */ + {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN}, + {NULL1_WORLD, NO_CTL, CTL_ETSI}, + {NULL1_ETSIB, NO_CTL, CTL_ETSI}, + {NULL1_ETSIC, NO_CTL, CTL_ETSI}, + + {FCC2_FCCA, CTL_FCC, CTL_FCC}, + {FCC2_WORLD, CTL_FCC, CTL_ETSI}, + {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC3_FCCA, CTL_FCC, CTL_FCC}, + {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC4_FCCA, CTL_FCC, CTL_FCC}, + {FCC5_FCCA, CTL_FCC, CTL_FCC}, + {FCC6_FCCA, CTL_FCC, CTL_FCC}, + {FCC6_WORLD, CTL_FCC, CTL_ETSI}, + + {ETSI1_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI2_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI3_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + + /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ + {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, + {FRANCE_RES, CTL_ETSI, CTL_ETSI}, + + {FCC1_WORLD, CTL_FCC, CTL_ETSI}, + {FCC1_FCCA, CTL_FCC, CTL_FCC}, + {APL1_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL3_WORLD, CTL_FCC, CTL_ETSI}, + {APL4_WORLD, CTL_FCC, CTL_ETSI}, + {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL6_WORLD, CTL_ETSI, CTL_ETSI}, + {APL8_WORLD, CTL_ETSI, CTL_ETSI}, + {APL9_WORLD, CTL_ETSI, CTL_ETSI}, + + {APL3_FCCA, CTL_FCC, CTL_FCC}, + {APL1_ETSIC, CTL_FCC, CTL_ETSI}, + {APL2_ETSIC, CTL_FCC, CTL_ETSI}, + {APL2_APLD, CTL_FCC, NO_CTL}, + + {MKK1_MKKA, CTL_MKK, CTL_MKK}, + {MKK1_MKKB, CTL_MKK, CTL_MKK}, + {MKK1_FCCA, CTL_MKK, CTL_FCC}, + {MKK1_MKKA1, CTL_MKK, CTL_MKK}, + {MKK1_MKKA2, CTL_MKK, CTL_MKK}, + {MKK1_MKKC, CTL_MKK, CTL_MKK}, + + {MKK2_MKKA, CTL_MKK, CTL_MKK}, + {MKK3_MKKA, CTL_MKK, CTL_MKK}, + {MKK3_MKKB, CTL_MKK, CTL_MKK}, + {MKK3_MKKA1, CTL_MKK, CTL_MKK}, + {MKK3_MKKA2, CTL_MKK, CTL_MKK}, + {MKK3_MKKC, CTL_MKK, CTL_MKK}, + {MKK3_FCCA, CTL_MKK, CTL_FCC}, + + {MKK4_MKKA, CTL_MKK, CTL_MKK}, + {MKK4_MKKB, CTL_MKK, CTL_MKK}, + {MKK4_MKKA1, CTL_MKK, CTL_MKK}, + {MKK4_MKKA2, CTL_MKK, CTL_MKK}, + {MKK4_MKKC, CTL_MKK, CTL_MKK}, + {MKK4_FCCA, CTL_MKK, CTL_FCC}, + + {MKK5_MKKB, CTL_MKK, CTL_MKK}, + {MKK5_MKKA2, CTL_MKK, CTL_MKK}, + {MKK5_MKKC, CTL_MKK, CTL_MKK}, + + {MKK6_MKKB, CTL_MKK, CTL_MKK}, + {MKK6_MKKA1, CTL_MKK, CTL_MKK}, + {MKK6_MKKA2, CTL_MKK, CTL_MKK}, + {MKK6_MKKC, CTL_MKK, CTL_MKK}, + {MKK6_FCCA, CTL_MKK, CTL_FCC}, + + {MKK7_MKKB, CTL_MKK, CTL_MKK}, + {MKK7_MKKA1, CTL_MKK, CTL_MKK}, + {MKK7_MKKA2, CTL_MKK, CTL_MKK}, + {MKK7_MKKC, CTL_MKK, CTL_MKK}, + {MKK7_FCCA, CTL_MKK, CTL_FCC}, + + {MKK8_MKKB, CTL_MKK, CTL_MKK}, + {MKK8_MKKA2, CTL_MKK, CTL_MKK}, + {MKK8_MKKC, CTL_MKK, CTL_MKK}, + + {MKK9_MKKA, CTL_MKK, CTL_MKK}, + {MKK9_FCCA, CTL_MKK, CTL_FCC}, + {MKK9_MKKA1, CTL_MKK, CTL_MKK}, + {MKK9_MKKA2, CTL_MKK, CTL_MKK}, + {MKK9_MKKC, CTL_MKK, CTL_MKK}, + + {MKK10_MKKA, CTL_MKK, CTL_MKK}, + {MKK10_FCCA, CTL_MKK, CTL_FCC}, + {MKK10_MKKA1, CTL_MKK, CTL_MKK}, + {MKK10_MKKA2, CTL_MKK, CTL_MKK}, + {MKK10_MKKC, CTL_MKK, CTL_MKK}, + + {MKK11_MKKA, CTL_MKK, CTL_MKK}, + {MKK11_FCCA, CTL_MKK, CTL_FCC}, + {MKK11_MKKA1, CTL_MKK, CTL_MKK}, + {MKK11_MKKA2, CTL_MKK, CTL_MKK}, + {MKK11_MKKC, CTL_MKK, CTL_MKK}, + + {MKK12_MKKA, CTL_MKK, CTL_MKK}, + {MKK12_FCCA, CTL_MKK, CTL_FCC}, + {MKK12_MKKA1, CTL_MKK, CTL_MKK}, + {MKK12_MKKA2, CTL_MKK, CTL_MKK}, + {MKK12_MKKC, CTL_MKK, CTL_MKK}, + + {MKK13_MKKB, CTL_MKK, CTL_MKK}, + {MKK14_MKKA1, CTL_MKK, CTL_MKK}, + {MKK15_MKKA1, CTL_MKK, CTL_MKK}, + + {WOR0_WORLD, NO_CTL, NO_CTL}, + {WOR1_WORLD, NO_CTL, NO_CTL}, + {WOR2_WORLD, NO_CTL, NO_CTL}, + {WOR3_WORLD, NO_CTL, NO_CTL}, + {WOR4_WORLD, NO_CTL, NO_CTL}, + {WOR5_ETSIC, NO_CTL, NO_CTL}, + {WOR01_WORLD, NO_CTL, NO_CTL}, + {WOR02_WORLD, NO_CTL, NO_CTL}, + {EU1_WORLD, NO_CTL, NO_CTL}, + {WOR9_WORLD, NO_CTL, NO_CTL}, + {WORA_WORLD, NO_CTL, NO_CTL}, + {WORB_WORLD, NO_CTL, NO_CTL}, +}; + +static struct country_code_to_enum_rd allCountries[] = { + {CTRY_DEBUG, NO_ENUMRD, "DB"}, + {CTRY_DEFAULT, FCC1_FCCA, "CO"}, + {CTRY_ALBANIA, NULL1_WORLD, "AL"}, + {CTRY_ALGERIA, NULL1_WORLD, "DZ"}, + {CTRY_ARGENTINA, APL3_WORLD, "AR"}, + {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, + {CTRY_AUSTRALIA, FCC2_WORLD, "AU"}, + {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, + {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, + {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHRAIN, APL6_WORLD, "BH"}, + {CTRY_BELARUS, ETSI1_WORLD, "BY"}, + {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, + {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, + {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, + {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, + {CTRY_BRAZIL, FCC3_WORLD, "BR"}, + {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"}, + {CTRY_BULGARIA, ETSI6_WORLD, "BG"}, + {CTRY_CANADA, FCC2_FCCA, "CA"}, + {CTRY_CANADA2, FCC6_FCCA, "CA"}, + {CTRY_CHILE, APL6_WORLD, "CL"}, + {CTRY_CHINA, APL1_WORLD, "CN"}, + {CTRY_COLOMBIA, FCC1_FCCA, "CO"}, + {CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, + {CTRY_CROATIA, ETSI3_WORLD, "HR"}, + {CTRY_CYPRUS, ETSI1_WORLD, "CY"}, + {CTRY_CZECH, ETSI3_WORLD, "CZ"}, + {CTRY_DENMARK, ETSI1_WORLD, "DK"}, + {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO"}, + {CTRY_ECUADOR, FCC1_WORLD, "EC"}, + {CTRY_EGYPT, ETSI3_WORLD, "EG"}, + {CTRY_EL_SALVADOR, FCC1_WORLD, "SV"}, + {CTRY_ESTONIA, ETSI1_WORLD, "EE"}, + {CTRY_FINLAND, ETSI1_WORLD, "FI"}, + {CTRY_FRANCE, ETSI1_WORLD, "FR"}, + {CTRY_GEORGIA, ETSI4_WORLD, "GE"}, + {CTRY_GERMANY, ETSI1_WORLD, "DE"}, + {CTRY_GREECE, ETSI1_WORLD, "GR"}, + {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, + {CTRY_HONDURAS, NULL1_WORLD, "HN"}, + {CTRY_HONG_KONG, FCC2_WORLD, "HK"}, + {CTRY_HUNGARY, ETSI1_WORLD, "HU"}, + {CTRY_ICELAND, ETSI1_WORLD, "IS"}, + {CTRY_INDIA, APL6_WORLD, "IN"}, + {CTRY_INDONESIA, APL1_WORLD, "ID"}, + {CTRY_IRAN, APL1_WORLD, "IR"}, + {CTRY_IRELAND, ETSI1_WORLD, "IE"}, + {CTRY_ISRAEL, NULL1_WORLD, "IL"}, + {CTRY_ITALY, ETSI1_WORLD, "IT"}, + {CTRY_JAMAICA, ETSI1_WORLD, "JM"}, + + {CTRY_JAPAN, MKK1_MKKA, "JP"}, + {CTRY_JAPAN1, MKK1_MKKB, "JP"}, + {CTRY_JAPAN2, MKK1_FCCA, "JP"}, + {CTRY_JAPAN3, MKK2_MKKA, "JP"}, + {CTRY_JAPAN4, MKK1_MKKA1, "JP"}, + {CTRY_JAPAN5, MKK1_MKKA2, "JP"}, + {CTRY_JAPAN6, MKK1_MKKC, "JP"}, + {CTRY_JAPAN7, MKK3_MKKB, "JP"}, + {CTRY_JAPAN8, MKK3_MKKA2, "JP"}, + {CTRY_JAPAN9, MKK3_MKKC, "JP"}, + {CTRY_JAPAN10, MKK4_MKKB, "JP"}, + {CTRY_JAPAN11, MKK4_MKKA2, "JP"}, + {CTRY_JAPAN12, MKK4_MKKC, "JP"}, + {CTRY_JAPAN13, MKK5_MKKB, "JP"}, + {CTRY_JAPAN14, MKK5_MKKA2, "JP"}, + {CTRY_JAPAN15, MKK5_MKKC, "JP"}, + {CTRY_JAPAN16, MKK6_MKKB, "JP"}, + {CTRY_JAPAN17, MKK6_MKKA2, "JP"}, + {CTRY_JAPAN18, MKK6_MKKC, "JP"}, + {CTRY_JAPAN19, MKK7_MKKB, "JP"}, + {CTRY_JAPAN20, MKK7_MKKA2, "JP"}, + {CTRY_JAPAN21, MKK7_MKKC, "JP"}, + {CTRY_JAPAN22, MKK8_MKKB, "JP"}, + {CTRY_JAPAN23, MKK8_MKKA2, "JP"}, + {CTRY_JAPAN24, MKK8_MKKC, "JP"}, + {CTRY_JAPAN25, MKK3_MKKA, "JP"}, + {CTRY_JAPAN26, MKK3_MKKA1, "JP"}, + {CTRY_JAPAN27, MKK3_FCCA, "JP"}, + {CTRY_JAPAN28, MKK4_MKKA1, "JP"}, + {CTRY_JAPAN29, MKK4_FCCA, "JP"}, + {CTRY_JAPAN30, MKK6_MKKA1, "JP"}, + {CTRY_JAPAN31, MKK6_FCCA, "JP"}, + {CTRY_JAPAN32, MKK7_MKKA1, "JP"}, + {CTRY_JAPAN33, MKK7_FCCA, "JP"}, + {CTRY_JAPAN34, MKK9_MKKA, "JP"}, + {CTRY_JAPAN35, MKK10_MKKA, "JP"}, + {CTRY_JAPAN36, MKK4_MKKA, "JP"}, + {CTRY_JAPAN37, MKK9_FCCA, "JP"}, + {CTRY_JAPAN38, MKK9_MKKA1, "JP"}, + {CTRY_JAPAN39, MKK9_MKKC, "JP"}, + {CTRY_JAPAN40, MKK9_MKKA2, "JP"}, + {CTRY_JAPAN41, MKK10_FCCA, "JP"}, + {CTRY_JAPAN42, MKK10_MKKA1, "JP"}, + {CTRY_JAPAN43, MKK10_MKKC, "JP"}, + {CTRY_JAPAN44, MKK10_MKKA2, "JP"}, + {CTRY_JAPAN45, MKK11_MKKA, "JP"}, + {CTRY_JAPAN46, MKK11_FCCA, "JP"}, + {CTRY_JAPAN47, MKK11_MKKA1, "JP"}, + {CTRY_JAPAN48, MKK11_MKKC, "JP"}, + {CTRY_JAPAN49, MKK11_MKKA2, "JP"}, + {CTRY_JAPAN50, MKK12_MKKA, "JP"}, + {CTRY_JAPAN51, MKK12_FCCA, "JP"}, + {CTRY_JAPAN52, MKK12_MKKA1, "JP"}, + {CTRY_JAPAN53, MKK12_MKKC, "JP"}, + {CTRY_JAPAN54, MKK12_MKKA2, "JP"}, + {CTRY_JAPAN57, MKK13_MKKB, "JP"}, + {CTRY_JAPAN58, MKK14_MKKA1, "JP"}, + {CTRY_JAPAN59, MKK15_MKKA1, "JP"}, + + {CTRY_JORDAN, ETSI2_WORLD, "JO"}, + {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ"}, + {CTRY_KOREA_NORTH, APL9_WORLD, "KP"}, + {CTRY_KOREA_ROC, APL9_WORLD, "KR"}, + {CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, + {CTRY_KOREA_ROC3, APL9_WORLD, "K3"}, + {CTRY_KUWAIT, NULL1_WORLD, "KW"}, + {CTRY_LATVIA, ETSI1_WORLD, "LV"}, + {CTRY_LEBANON, NULL1_WORLD, "LB"}, + {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"}, + {CTRY_LITHUANIA, ETSI1_WORLD, "LT"}, + {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU"}, + {CTRY_MACAU, FCC2_WORLD, "MO"}, + {CTRY_MACEDONIA, NULL1_WORLD, "MK"}, + {CTRY_MALAYSIA, APL8_WORLD, "MY"}, + {CTRY_MALTA, ETSI1_WORLD, "MT"}, + {CTRY_MEXICO, FCC1_FCCA, "MX"}, + {CTRY_MONACO, ETSI4_WORLD, "MC"}, + {CTRY_MOROCCO, NULL1_WORLD, "MA"}, + {CTRY_NEPAL, APL1_WORLD, "NP"}, + {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, + {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, + {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, + {CTRY_NORWAY, ETSI1_WORLD, "NO"}, + {CTRY_OMAN, APL6_WORLD, "OM"}, + {CTRY_PAKISTAN, NULL1_WORLD, "PK"}, + {CTRY_PANAMA, FCC1_FCCA, "PA"}, + {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, + {CTRY_PERU, APL1_WORLD, "PE"}, + {CTRY_PHILIPPINES, APL1_WORLD, "PH"}, + {CTRY_POLAND, ETSI1_WORLD, "PL"}, + {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, + {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, + {CTRY_QATAR, NULL1_WORLD, "QA"}, + {CTRY_ROMANIA, NULL1_WORLD, "RO"}, + {CTRY_RUSSIA, NULL1_WORLD, "RU"}, + {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, + {CTRY_SINGAPORE, APL6_WORLD, "SG"}, + {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, + {CTRY_SLOVENIA, ETSI1_WORLD, "SI"}, + {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA"}, + {CTRY_SPAIN, ETSI1_WORLD, "ES"}, + {CTRY_SRI_LANKA, FCC3_WORLD, "LK"}, + {CTRY_SWEDEN, ETSI1_WORLD, "SE"}, + {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, + {CTRY_SYRIA, NULL1_WORLD, "SY"}, + {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_THAILAND, NULL1_WORLD, "TH"}, + {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, + {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, + {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UKRAINE, NULL1_WORLD, "UA"}, + {CTRY_UAE, NULL1_WORLD, "AE"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, + {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, + /* This "PS" is for US public safety actually... to support this we + * would need to assign new special alpha2 to CRDA db as with the world + * regdomain and use another alpha2 */ + {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"}, + {CTRY_URUGUAY, APL2_WORLD, "UY"}, + {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"}, + {CTRY_VENEZUELA, APL2_ETSIC, "VE"}, + {CTRY_VIET_NAM, NULL1_WORLD, "VN"}, + {CTRY_YEMEN, NULL1_WORLD, "YE"}, + {CTRY_ZIMBABWE, NULL1_WORLD, "ZW"}, +}; + +#endif diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig index 90a8dd8..0ed1ac3 100644 --- a/drivers/net/wireless/ath9k/Kconfig +++ b/drivers/net/wireless/ath9k/Kconfig @@ -2,6 +2,7 @@ config ATH9K tristate "Atheros 802.11n wireless cards support" depends on PCI && MAC80211 && WLAN_80211 depends on RFKILL || RFKILL=n + select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index 1a4d4ea..783bc39 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -4,7 +4,6 @@ ath9k-y += hw.o \ calib.o \ ani.o \ phy.o \ - regd.o \ beacon.o \ main.o \ recv.o \ diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath9k/eeprom.h index 25b68c8..9a7715d 100644 --- a/drivers/net/wireless/ath9k/eeprom.h +++ b/drivers/net/wireless/ath9k/eeprom.h @@ -17,6 +17,8 @@ #ifndef EEPROM_H #define EEPROM_H +#include + #define AH_USE_EEPROM 0x1 #ifdef __BIG_ENDIAN diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index a8465bb..24299e6 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -1220,6 +1220,21 @@ static void ath9k_olc_init(struct ath_hw *ah) ah->PDADCdelta = 0; } +static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, + struct ath9k_channel *chan) +{ + u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band); + + if (IS_CHAN_B(chan)) + ctl |= CTL_11B; + else if (IS_CHAN_G(chan)) + ctl |= CTL_11G; + else + ctl |= CTL_11A; + + return ctl; +} + static int ath9k_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 5a1128d..984ac7d 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -25,10 +25,11 @@ #include "ani.h" #include "eeprom.h" #include "calib.h" -#include "regd.h" #include "reg.h" #include "phy.h" +#include "../ath/regd.h" + #define ATHEROS_VENDOR_ID 0x168c #define AR5416_DEVID_PCI 0x0023 #define AR5416_DEVID_PCIE 0x0024 @@ -404,7 +405,7 @@ struct ath_hw { struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; - struct ath9k_regulatory regulatory; + struct ath_regulatory regulatory; struct ath9k_channel channels[38]; struct ath9k_channel *curchan; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 3647a47..d779f00 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1406,7 +1406,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (ath9k_regd_init(&sc->sc_ah->regulatory)) + if (ath_regd_init(&sc->sc_ah->regulatory)) goto bad; /* default to MONITOR mode */ @@ -1570,6 +1570,17 @@ bad: return error; } +static int ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_regulatory *reg = &sc->sc_ah->regulatory; + + return ath_reg_notifier_apply(wiphy, request, reg); +} + void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | @@ -1614,7 +1625,7 @@ int ath_attach(u16 devid, struct ath_softc *sc) struct ieee80211_hw *hw = sc->hw; const struct ieee80211_regdomain *regd; int error = 0, i; - struct ath9k_regulatory *reg; + struct ath_regulatory *reg; DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); @@ -1656,23 +1667,23 @@ int ath_attach(u16 devid, struct ath_softc *sc) goto error_attach; #endif - if (ath9k_is_world_regd(reg)) { + if (ath_is_world_regd(reg)) { /* Anything applied here (prior to wiphy registration) gets * saved on the wiphy orig_* parameters */ - regd = ath9k_world_regdomain(reg); + regd = ath_world_regdomain(reg); hw->wiphy->custom_regulatory = true; hw->wiphy->strict_regulatory = false; } else { /* This gets applied in the case of the absense of CRDA, * it's our own custom world regulatory domain, similar to * cfg80211's but we enable passive scanning */ - regd = ath9k_default_world_regdomain(); + regd = ath_default_world_regdomain(); } wiphy_apply_custom_regulatory(hw->wiphy, regd); - ath9k_reg_apply_radar_flags(hw->wiphy); - ath9k_reg_apply_world_flags(hw->wiphy, - NL80211_REGDOM_SET_BY_DRIVER, - reg); + ath_reg_apply_radar_flags(hw->wiphy); + ath_reg_apply_world_flags(hw->wiphy, + NL80211_REGDOM_SET_BY_DRIVER, + reg); INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); @@ -1680,7 +1691,7 @@ int ath_attach(u16 devid, struct ath_softc *sc) error = ieee80211_register_hw(hw); - if (!ath9k_is_world_regd(reg)) { + if (!ath_is_world_regd(reg)) { error = regulatory_hint(hw->wiphy, reg->alpha2); if (error) goto error_attach; diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c deleted file mode 100644 index 7eaa59e..0000000 --- a/drivers/net/wireless/ath9k/regd.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include "ath9k.h" -#include "regd_common.h" - -/* - * This is a set of common rules used by our world regulatory domains. - * We have 12 world regulatory domains. To save space we consolidate - * the regulatory domains in 5 structures by frequency and change - * the flags on our reg_notifier() on a case by case basis. - */ - -/* Only these channels all allow active scan on all world regulatory domains */ -#define ATH9K_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) - -/* We enable active scan on these a case by case basis by regulatory domain */ -#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN) -#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) - -/* We allow IBSS on these on a case by case basis by regulatory domain */ -#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 40, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) -#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 40, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) -#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 40, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) - -#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \ - ATH9K_2GHZ_CH12_13, \ - ATH9K_2GHZ_CH14 - -#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \ - ATH9K_5GHZ_5470_5850 -/* This one skips what we call "mid band" */ -#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ - ATH9K_5GHZ_5725_5850 - -/* Can be used for: - * 0x60, 0x61, 0x62 */ -static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = { - .n_reg_rules = 5, - .alpha2 = "99", - .reg_rules = { - ATH9K_2GHZ_ALL, - ATH9K_5GHZ_ALL, - } -}; - -/* Can be used by 0x63 and 0x65 */ -static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = { - .n_reg_rules = 4, - .alpha2 = "99", - .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_2GHZ_CH12_13, - ATH9K_5GHZ_NO_MIDBAND, - } -}; - -/* Can be used by 0x64 only */ -static const struct ieee80211_regdomain ath9k_world_regdom_64 = { - .n_reg_rules = 3, - .alpha2 = "99", - .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_5GHZ_NO_MIDBAND, - } -}; - -/* Can be used by 0x66 and 0x69 */ -static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = { - .n_reg_rules = 3, - .alpha2 = "99", - .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_5GHZ_ALL, - } -}; - -/* Can be used by 0x67, 0x6A and 0x68 */ -static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = { - .n_reg_rules = 4, - .alpha2 = "99", - .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_2GHZ_CH12_13, - ATH9K_5GHZ_ALL, - } -}; - -static inline bool is_wwr_sku(u16 regd) -{ - return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || - (regd == WORLD); -} - -static u16 ath9k_regd_get_eepromRD(struct ath9k_regulatory *reg) -{ - return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; -} - -bool ath9k_is_world_regd(struct ath9k_regulatory *reg) -{ - return is_wwr_sku(ath9k_regd_get_eepromRD(reg)); -} - -const struct ieee80211_regdomain *ath9k_default_world_regdomain(void) -{ - /* this is the most restrictive */ - return &ath9k_world_regdom_64; -} - -const struct -ieee80211_regdomain *ath9k_world_regdomain(struct ath9k_regulatory *reg) -{ - switch (reg->regpair->regDmnEnum) { - case 0x60: - case 0x61: - case 0x62: - return &ath9k_world_regdom_60_61_62; - case 0x63: - case 0x65: - return &ath9k_world_regdom_63_65; - case 0x64: - return &ath9k_world_regdom_64; - case 0x66: - case 0x69: - return &ath9k_world_regdom_66_69; - case 0x67: - case 0x68: - case 0x6A: - return &ath9k_world_regdom_67_68_6A; - default: - WARN_ON(1); - return ath9k_default_world_regdomain(); - } -} - -/* Frequency is one where radar detection is required */ -static bool ath9k_is_radar_freq(u16 center_freq) -{ - return (center_freq >= 5260 && center_freq <= 5700); -} - -/* - * N.B: These exception rules do not apply radar freqs. - * - * - We enable adhoc (or beaconing) if allowed by 11d - * - We enable active scan if the channel is allowed by 11d - * - If no country IE has been processed and a we determine we have - * received a beacon on a channel we can enable active scan and - * adhoc (or beaconing). - */ -static void ath9k_reg_apply_beaconing_flags( - struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) -{ - enum ieee80211_band band; - struct ieee80211_supported_band *sband; - const struct ieee80211_reg_rule *reg_rule; - struct ieee80211_channel *ch; - unsigned int i; - u32 bandwidth = 0; - int r; - - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - - if (!wiphy->bands[band]) - continue; - - sband = wiphy->bands[band]; - - for (i = 0; i < sband->n_channels; i++) { - - ch = &sband->channels[i]; - - if (ath9k_is_radar_freq(ch->center_freq) || - (ch->flags & IEEE80211_CHAN_RADAR)) - continue; - - if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - r = freq_reg_info(wiphy, ch->center_freq, - &bandwidth, ®_rule); - if (r) - continue; - /* - * If 11d had a rule for this channel ensure - * we enable adhoc/beaconing if it allows us to - * use it. Note that we would have disabled it - * by applying our static world regdomain by - * default during init, prior to calling our - * regulatory_hint(). - */ - if (!(reg_rule->flags & - NL80211_RRF_NO_IBSS)) - ch->flags &= - ~IEEE80211_CHAN_NO_IBSS; - if (!(reg_rule->flags & - NL80211_RRF_PASSIVE_SCAN)) - ch->flags &= - ~IEEE80211_CHAN_PASSIVE_SCAN; - } else { - if (ch->beacon_found) - ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN); - } - } - } - -} - -/* Allows active scan scan on Ch 12 and 13 */ -static void ath9k_reg_apply_active_scan_flags( - struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) -{ - struct ieee80211_supported_band *sband; - struct ieee80211_channel *ch; - const struct ieee80211_reg_rule *reg_rule; - u32 bandwidth = 0; - int r; - - sband = wiphy->bands[IEEE80211_BAND_2GHZ]; - - /* - * If no country IE has been received always enable active scan - * on these channels. This is only done for specific regulatory SKUs - */ - if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { - ch = &sband->channels[11]; /* CH 12 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - ch = &sband->channels[12]; /* CH 13 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - return; - } - - /* - * If a country IE has been recieved check its rule for this - * channel first before enabling active scan. The passive scan - * would have been enforced by the initial processing of our - * custom regulatory domain. - */ - - ch = &sband->channels[11]; /* CH 12 */ - r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); - if (!r) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - } - - ch = &sband->channels[12]; /* CH 13 */ - r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); - if (!r) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - } -} - -/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ -void ath9k_reg_apply_radar_flags(struct wiphy *wiphy) -{ - struct ieee80211_supported_band *sband; - struct ieee80211_channel *ch; - unsigned int i; - - if (!wiphy->bands[IEEE80211_BAND_5GHZ]) - return; - - sband = wiphy->bands[IEEE80211_BAND_5GHZ]; - - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; - if (!ath9k_is_radar_freq(ch->center_freq)) - continue; - /* We always enable radar detection/DFS on this - * frequency range. Additionally we also apply on - * this frequency range: - * - If STA mode does not yet have DFS supports disable - * active scanning - * - If adhoc mode does not support DFS yet then - * disable adhoc in the frequency. - * - If AP mode does not yet support radar detection/DFS - * do not allow AP mode - */ - if (!(ch->flags & IEEE80211_CHAN_DISABLED)) - ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; - } -} - -void ath9k_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator, - struct ath9k_regulatory *reg) -{ - switch (reg->regpair->regDmnEnum) { - case 0x60: - case 0x63: - case 0x66: - case 0x67: - ath9k_reg_apply_beaconing_flags(wiphy, initiator); - break; - case 0x68: - ath9k_reg_apply_beaconing_flags(wiphy, initiator); - ath9k_reg_apply_active_scan_flags(wiphy, initiator); - break; - } - return; -} - -static int ath9k_reg_notifier_apply(struct wiphy *wiphy, - struct regulatory_request *request, struct ath9k_regulatory *reg) -{ - /* We always apply this */ - ath9k_reg_apply_radar_flags(wiphy); - - switch (request->initiator) { - case NL80211_REGDOM_SET_BY_DRIVER: - case NL80211_REGDOM_SET_BY_CORE: - case NL80211_REGDOM_SET_BY_USER: - break; - case NL80211_REGDOM_SET_BY_COUNTRY_IE: - if (ath9k_is_world_regd(reg)) - ath9k_reg_apply_world_flags(wiphy, request->initiator, - reg); - break; - } - - return 0; -} - -int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath9k_regulatory *reg = &sc->sc_ah->regulatory; - - return ath9k_reg_notifier_apply(wiphy, request, reg); -} - -bool ath9k_regd_is_eeprom_valid(struct ath9k_regulatory *reg) -{ - u16 rd = ath9k_regd_get_eepromRD(reg); - int i; - - if (rd & COUNTRY_ERD_FLAG) { - /* EEPROM value is a country code */ - u16 cc = rd & ~COUNTRY_ERD_FLAG; - for (i = 0; i < ARRAY_SIZE(allCountries); i++) - if (allCountries[i].countryCode == cc) - return true; - } else { - /* EEPROM value is a regpair value */ - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) - return true; - } - printk(KERN_DEBUG - "ath9k: invalid regulatory domain/country code 0x%x\n", rd); - return false; -} - -/* EEPROM country code to regpair mapping */ -static struct country_code_to_enum_rd* -ath9k_regd_find_country(u16 countryCode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(allCountries); i++) { - if (allCountries[i].countryCode == countryCode) - return &allCountries[i]; - } - return NULL; -} - -/* EEPROM rd code to regpair mapping */ -static struct country_code_to_enum_rd* -ath9k_regd_find_country_by_rd(int regdmn) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(allCountries); i++) { - if (allCountries[i].regDmnEnum == regdmn) - return &allCountries[i]; - } - return NULL; -} - -/* Returns the map of the EEPROM set RD to a country code */ -static u16 ath9k_regd_get_default_country(u16 rd) -{ - if (rd & COUNTRY_ERD_FLAG) { - struct country_code_to_enum_rd *country = NULL; - u16 cc = rd & ~COUNTRY_ERD_FLAG; - - country = ath9k_regd_find_country(cc); - if (country != NULL) - return cc; - } - - return CTRY_DEFAULT; -} - -static struct reg_dmn_pair_mapping* -ath9k_get_regpair(int regdmn) -{ - int i; - - if (regdmn == NO_ENUMRD) - return NULL; - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regdmn) - return ®DomainPairs[i]; - } - return NULL; -} - -int ath9k_regd_init(struct ath9k_regulatory *reg) -{ - struct country_code_to_enum_rd *country = NULL; - u16 regdmn; - - if (!ath9k_regd_is_eeprom_valid(reg)) { - printk(KERN_DEBUG "ath9k: Invalid EEPROM contents\n"); - return -EINVAL; - } - - regdmn = ath9k_regd_get_eepromRD(reg); - reg->country_code = ath9k_regd_get_default_country(regdmn); - - if (reg->country_code == CTRY_DEFAULT && - regdmn == CTRY_DEFAULT) - reg->country_code = CTRY_UNITED_STATES; - - if (reg->country_code == CTRY_DEFAULT) { - country = NULL; - } else { - country = ath9k_regd_find_country(reg->country_code); - if (country == NULL) { - printk(KERN_DEBUG - "ath9k: Country is NULL!!!!, cc= %d\n", - reg->country_code); - return -EINVAL; - } else - regdmn = country->regDmnEnum; - } - - reg->regpair = ath9k_get_regpair(regdmn); - - if (!reg->regpair) { - printk(KERN_DEBUG "ath9k: " - "No regulatory domain pair found, cannot continue\n"); - return -EINVAL; - } - - if (!country) - country = ath9k_regd_find_country_by_rd(regdmn); - - if (country) { - reg->alpha2[0] = country->isoName[0]; - reg->alpha2[1] = country->isoName[1]; - } else { - reg->alpha2[0] = '0'; - reg->alpha2[1] = '0'; - } - - printk(KERN_DEBUG "ath9k: Country alpha2 being used: %c%c\n", - reg->alpha2[0], reg->alpha2[1]); - printk(KERN_DEBUG "ath9k: Regpair detected: 0x%0x\n", - reg->regpair->regDmnEnum); - - return 0; -} - -static -u32 ath9k_regd_get_band_ctl(struct ath9k_regulatory *reg, - enum ieee80211_band band) -{ - if (!reg->regpair || - (reg->country_code == CTRY_DEFAULT && - is_wwr_sku(ath9k_regd_get_eepromRD(reg)))) { - return SD_NO_CTL; - } - - switch (band) { - case IEEE80211_BAND_2GHZ: - return reg->regpair->reg_2ghz_ctl; - case IEEE80211_BAND_5GHZ: - return reg->regpair->reg_5ghz_ctl; - default: - return NO_CTL; - } - - return NO_CTL; -} - -u32 ath9k_regd_get_ctl(struct ath9k_regulatory *reg, struct ath9k_channel *chan) -{ - u32 ctl = ath9k_regd_get_band_ctl(reg, chan->chan->band); - - if (IS_CHAN_B(chan)) - ctl |= CTL_11B; - else if (IS_CHAN_G(chan)) - ctl |= CTL_11G; - else - ctl |= CTL_11A; - - return ctl; -} diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h deleted file mode 100644 index 61fa42e..0000000 --- a/drivers/net/wireless/ath9k/regd.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef REGD_H -#define REGD_H - -#include - -#define COUNTRY_ERD_FLAG 0x8000 -#define WORLDWIDE_ROAMING_FLAG 0x4000 - -#define MULTI_DOMAIN_MASK 0xFF00 - -#define WORLD_SKU_MASK 0x00F0 -#define WORLD_SKU_PREFIX 0x0060 - -#define CHANNEL_HALF_BW 10 -#define CHANNEL_QUARTER_BW 5 - -struct reg_dmn_pair_mapping { - u16 regDmnEnum; - u16 reg_5ghz_ctl; - u16 reg_2ghz_ctl; -}; - -struct country_code_to_enum_rd { - u16 countryCode; - u16 regDmnEnum; - const char *isoName; -}; - -struct ath9k_regulatory { - char alpha2[2]; - u16 country_code; - u16 max_power_level; - u32 tp_scale; - u16 current_rd; - u16 current_rd_ext; - int16_t power_limit; - struct reg_dmn_pair_mapping *regpair; -}; - -enum CountryCode { - CTRY_ALBANIA = 8, - CTRY_ALGERIA = 12, - CTRY_ARGENTINA = 32, - CTRY_ARMENIA = 51, - CTRY_AUSTRALIA = 36, - CTRY_AUSTRIA = 40, - CTRY_AZERBAIJAN = 31, - CTRY_BAHRAIN = 48, - CTRY_BELARUS = 112, - CTRY_BELGIUM = 56, - CTRY_BELIZE = 84, - CTRY_BOLIVIA = 68, - CTRY_BOSNIA_HERZ = 70, - CTRY_BRAZIL = 76, - CTRY_BRUNEI_DARUSSALAM = 96, - CTRY_BULGARIA = 100, - CTRY_CANADA = 124, - CTRY_CHILE = 152, - CTRY_CHINA = 156, - CTRY_COLOMBIA = 170, - CTRY_COSTA_RICA = 188, - CTRY_CROATIA = 191, - CTRY_CYPRUS = 196, - CTRY_CZECH = 203, - CTRY_DENMARK = 208, - CTRY_DOMINICAN_REPUBLIC = 214, - CTRY_ECUADOR = 218, - CTRY_EGYPT = 818, - CTRY_EL_SALVADOR = 222, - CTRY_ESTONIA = 233, - CTRY_FAEROE_ISLANDS = 234, - CTRY_FINLAND = 246, - CTRY_FRANCE = 250, - CTRY_GEORGIA = 268, - CTRY_GERMANY = 276, - CTRY_GREECE = 300, - CTRY_GUATEMALA = 320, - CTRY_HONDURAS = 340, - CTRY_HONG_KONG = 344, - CTRY_HUNGARY = 348, - CTRY_ICELAND = 352, - CTRY_INDIA = 356, - CTRY_INDONESIA = 360, - CTRY_IRAN = 364, - CTRY_IRAQ = 368, - CTRY_IRELAND = 372, - CTRY_ISRAEL = 376, - CTRY_ITALY = 380, - CTRY_JAMAICA = 388, - CTRY_JAPAN = 392, - CTRY_JORDAN = 400, - CTRY_KAZAKHSTAN = 398, - CTRY_KENYA = 404, - CTRY_KOREA_NORTH = 408, - CTRY_KOREA_ROC = 410, - CTRY_KOREA_ROC2 = 411, - CTRY_KOREA_ROC3 = 412, - CTRY_KUWAIT = 414, - CTRY_LATVIA = 428, - CTRY_LEBANON = 422, - CTRY_LIBYA = 434, - CTRY_LIECHTENSTEIN = 438, - CTRY_LITHUANIA = 440, - CTRY_LUXEMBOURG = 442, - CTRY_MACAU = 446, - CTRY_MACEDONIA = 807, - CTRY_MALAYSIA = 458, - CTRY_MALTA = 470, - CTRY_MEXICO = 484, - CTRY_MONACO = 492, - CTRY_MOROCCO = 504, - CTRY_NEPAL = 524, - CTRY_NETHERLANDS = 528, - CTRY_NETHERLANDS_ANTILLES = 530, - CTRY_NEW_ZEALAND = 554, - CTRY_NICARAGUA = 558, - CTRY_NORWAY = 578, - CTRY_OMAN = 512, - CTRY_PAKISTAN = 586, - CTRY_PANAMA = 591, - CTRY_PAPUA_NEW_GUINEA = 598, - CTRY_PARAGUAY = 600, - CTRY_PERU = 604, - CTRY_PHILIPPINES = 608, - CTRY_POLAND = 616, - CTRY_PORTUGAL = 620, - CTRY_PUERTO_RICO = 630, - CTRY_QATAR = 634, - CTRY_ROMANIA = 642, - CTRY_RUSSIA = 643, - CTRY_SAUDI_ARABIA = 682, - CTRY_SERBIA_MONTENEGRO = 891, - CTRY_SINGAPORE = 702, - CTRY_SLOVAKIA = 703, - CTRY_SLOVENIA = 705, - CTRY_SOUTH_AFRICA = 710, - CTRY_SPAIN = 724, - CTRY_SRI_LANKA = 144, - CTRY_SWEDEN = 752, - CTRY_SWITZERLAND = 756, - CTRY_SYRIA = 760, - CTRY_TAIWAN = 158, - CTRY_THAILAND = 764, - CTRY_TRINIDAD_Y_TOBAGO = 780, - CTRY_TUNISIA = 788, - CTRY_TURKEY = 792, - CTRY_UAE = 784, - CTRY_UKRAINE = 804, - CTRY_UNITED_KINGDOM = 826, - CTRY_UNITED_STATES = 840, - CTRY_UNITED_STATES_FCC49 = 842, - CTRY_URUGUAY = 858, - CTRY_UZBEKISTAN = 860, - CTRY_VENEZUELA = 862, - CTRY_VIET_NAM = 704, - CTRY_YEMEN = 887, - CTRY_ZIMBABWE = 716, - CTRY_JAPAN1 = 393, - CTRY_JAPAN2 = 394, - CTRY_JAPAN3 = 395, - CTRY_JAPAN4 = 396, - CTRY_JAPAN5 = 397, - CTRY_JAPAN6 = 4006, - CTRY_JAPAN7 = 4007, - CTRY_JAPAN8 = 4008, - CTRY_JAPAN9 = 4009, - CTRY_JAPAN10 = 4010, - CTRY_JAPAN11 = 4011, - CTRY_JAPAN12 = 4012, - CTRY_JAPAN13 = 4013, - CTRY_JAPAN14 = 4014, - CTRY_JAPAN15 = 4015, - CTRY_JAPAN16 = 4016, - CTRY_JAPAN17 = 4017, - CTRY_JAPAN18 = 4018, - CTRY_JAPAN19 = 4019, - CTRY_JAPAN20 = 4020, - CTRY_JAPAN21 = 4021, - CTRY_JAPAN22 = 4022, - CTRY_JAPAN23 = 4023, - CTRY_JAPAN24 = 4024, - CTRY_JAPAN25 = 4025, - CTRY_JAPAN26 = 4026, - CTRY_JAPAN27 = 4027, - CTRY_JAPAN28 = 4028, - CTRY_JAPAN29 = 4029, - CTRY_JAPAN30 = 4030, - CTRY_JAPAN31 = 4031, - CTRY_JAPAN32 = 4032, - CTRY_JAPAN33 = 4033, - CTRY_JAPAN34 = 4034, - CTRY_JAPAN35 = 4035, - CTRY_JAPAN36 = 4036, - CTRY_JAPAN37 = 4037, - CTRY_JAPAN38 = 4038, - CTRY_JAPAN39 = 4039, - CTRY_JAPAN40 = 4040, - CTRY_JAPAN41 = 4041, - CTRY_JAPAN42 = 4042, - CTRY_JAPAN43 = 4043, - CTRY_JAPAN44 = 4044, - CTRY_JAPAN45 = 4045, - CTRY_JAPAN46 = 4046, - CTRY_JAPAN47 = 4047, - CTRY_JAPAN48 = 4048, - CTRY_JAPAN49 = 4049, - CTRY_JAPAN50 = 4050, - CTRY_JAPAN51 = 4051, - CTRY_JAPAN52 = 4052, - CTRY_JAPAN53 = 4053, - CTRY_JAPAN54 = 4054, - CTRY_JAPAN55 = 4055, - CTRY_JAPAN56 = 4056, - CTRY_JAPAN57 = 4057, - CTRY_JAPAN58 = 4058, - CTRY_JAPAN59 = 4059, - CTRY_AUSTRALIA2 = 5000, - CTRY_CANADA2 = 5001, - CTRY_BELGIUM2 = 5002 -}; - -bool ath9k_is_world_regd(struct ath9k_regulatory *reg); -const struct ieee80211_regdomain *ath9k_world_regdomain( - struct ath9k_regulatory *reg); -const struct ieee80211_regdomain *ath9k_default_world_regdomain(void); -void ath9k_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator, - struct ath9k_regulatory *reg); -void ath9k_reg_apply_radar_flags(struct wiphy *wiphy); -int ath9k_regd_init(struct ath9k_regulatory *reg); -bool ath9k_regd_is_eeprom_valid(struct ath9k_regulatory *reg); -u32 ath9k_regd_get_ctl(struct ath9k_regulatory *reg, - struct ath9k_channel *chan); -int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); - -#endif diff --git a/drivers/net/wireless/ath9k/regd_common.h b/drivers/net/wireless/ath9k/regd_common.h deleted file mode 100644 index 4d0e298..0000000 --- a/drivers/net/wireless/ath9k/regd_common.h +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef REGD_COMMON_H -#define REGD_COMMON_H - -enum EnumRd { - NO_ENUMRD = 0x00, - NULL1_WORLD = 0x03, - NULL1_ETSIB = 0x07, - NULL1_ETSIC = 0x08, - FCC1_FCCA = 0x10, - FCC1_WORLD = 0x11, - FCC4_FCCA = 0x12, - FCC5_FCCA = 0x13, - FCC6_FCCA = 0x14, - - FCC2_FCCA = 0x20, - FCC2_WORLD = 0x21, - FCC2_ETSIC = 0x22, - FCC6_WORLD = 0x23, - FRANCE_RES = 0x31, - FCC3_FCCA = 0x3A, - FCC3_WORLD = 0x3B, - - ETSI1_WORLD = 0x37, - ETSI3_ETSIA = 0x32, - ETSI2_WORLD = 0x35, - ETSI3_WORLD = 0x36, - ETSI4_WORLD = 0x30, - ETSI4_ETSIC = 0x38, - ETSI5_WORLD = 0x39, - ETSI6_WORLD = 0x34, - ETSI_RESERVED = 0x33, - - MKK1_MKKA = 0x40, - MKK1_MKKB = 0x41, - APL4_WORLD = 0x42, - MKK2_MKKA = 0x43, - APL_RESERVED = 0x44, - APL2_WORLD = 0x45, - APL2_APLC = 0x46, - APL3_WORLD = 0x47, - MKK1_FCCA = 0x48, - APL2_APLD = 0x49, - MKK1_MKKA1 = 0x4A, - MKK1_MKKA2 = 0x4B, - MKK1_MKKC = 0x4C, - - APL3_FCCA = 0x50, - APL1_WORLD = 0x52, - APL1_FCCA = 0x53, - APL1_APLA = 0x54, - APL1_ETSIC = 0x55, - APL2_ETSIC = 0x56, - APL5_WORLD = 0x58, - APL6_WORLD = 0x5B, - APL7_FCCA = 0x5C, - APL8_WORLD = 0x5D, - APL9_WORLD = 0x5E, - - WOR0_WORLD = 0x60, - WOR1_WORLD = 0x61, - WOR2_WORLD = 0x62, - WOR3_WORLD = 0x63, - WOR4_WORLD = 0x64, - WOR5_ETSIC = 0x65, - - WOR01_WORLD = 0x66, - WOR02_WORLD = 0x67, - EU1_WORLD = 0x68, - - WOR9_WORLD = 0x69, - WORA_WORLD = 0x6A, - WORB_WORLD = 0x6B, - - MKK3_MKKB = 0x80, - MKK3_MKKA2 = 0x81, - MKK3_MKKC = 0x82, - - MKK4_MKKB = 0x83, - MKK4_MKKA2 = 0x84, - MKK4_MKKC = 0x85, - - MKK5_MKKB = 0x86, - MKK5_MKKA2 = 0x87, - MKK5_MKKC = 0x88, - - MKK6_MKKB = 0x89, - MKK6_MKKA2 = 0x8A, - MKK6_MKKC = 0x8B, - - MKK7_MKKB = 0x8C, - MKK7_MKKA2 = 0x8D, - MKK7_MKKC = 0x8E, - - MKK8_MKKB = 0x8F, - MKK8_MKKA2 = 0x90, - MKK8_MKKC = 0x91, - - MKK14_MKKA1 = 0x92, - MKK15_MKKA1 = 0x93, - - MKK10_FCCA = 0xD0, - MKK10_MKKA1 = 0xD1, - MKK10_MKKC = 0xD2, - MKK10_MKKA2 = 0xD3, - - MKK11_MKKA = 0xD4, - MKK11_FCCA = 0xD5, - MKK11_MKKA1 = 0xD6, - MKK11_MKKC = 0xD7, - MKK11_MKKA2 = 0xD8, - - MKK12_MKKA = 0xD9, - MKK12_FCCA = 0xDA, - MKK12_MKKA1 = 0xDB, - MKK12_MKKC = 0xDC, - MKK12_MKKA2 = 0xDD, - - MKK13_MKKB = 0xDE, - - MKK3_MKKA = 0xF0, - MKK3_MKKA1 = 0xF1, - MKK3_FCCA = 0xF2, - MKK4_MKKA = 0xF3, - MKK4_MKKA1 = 0xF4, - MKK4_FCCA = 0xF5, - MKK9_MKKA = 0xF6, - MKK10_MKKA = 0xF7, - MKK6_MKKA1 = 0xF8, - MKK6_FCCA = 0xF9, - MKK7_MKKA1 = 0xFA, - MKK7_FCCA = 0xFB, - MKK9_FCCA = 0xFC, - MKK9_MKKA1 = 0xFD, - MKK9_MKKC = 0xFE, - MKK9_MKKA2 = 0xFF, - - WORLD = 0x0199, - DEBUG_REG_DMN = 0x01ff, -}; - -enum ctl_group { - CTL_FCC = 0x10, - CTL_MKK = 0x40, - CTL_ETSI = 0x30, -}; - -/* Regpair to CTL band mapping */ -static struct reg_dmn_pair_mapping regDomainPairs[] = { - /* regpair, 5 GHz CTL, 2 GHz CTL */ - {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN}, - {NULL1_WORLD, NO_CTL, CTL_ETSI}, - {NULL1_ETSIB, NO_CTL, CTL_ETSI}, - {NULL1_ETSIC, NO_CTL, CTL_ETSI}, - - {FCC2_FCCA, CTL_FCC, CTL_FCC}, - {FCC2_WORLD, CTL_FCC, CTL_ETSI}, - {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, - {FCC3_FCCA, CTL_FCC, CTL_FCC}, - {FCC3_WORLD, CTL_FCC, CTL_ETSI}, - {FCC4_FCCA, CTL_FCC, CTL_FCC}, - {FCC5_FCCA, CTL_FCC, CTL_FCC}, - {FCC6_FCCA, CTL_FCC, CTL_FCC}, - {FCC6_WORLD, CTL_FCC, CTL_ETSI}, - - {ETSI1_WORLD, CTL_ETSI, CTL_ETSI}, - {ETSI2_WORLD, CTL_ETSI, CTL_ETSI}, - {ETSI3_WORLD, CTL_ETSI, CTL_ETSI}, - {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, - {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, - {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, - - /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ - {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, - {FRANCE_RES, CTL_ETSI, CTL_ETSI}, - - {FCC1_WORLD, CTL_FCC, CTL_ETSI}, - {FCC1_FCCA, CTL_FCC, CTL_FCC}, - {APL1_WORLD, CTL_FCC, CTL_ETSI}, - {APL2_WORLD, CTL_FCC, CTL_ETSI}, - {APL3_WORLD, CTL_FCC, CTL_ETSI}, - {APL4_WORLD, CTL_FCC, CTL_ETSI}, - {APL5_WORLD, CTL_FCC, CTL_ETSI}, - {APL6_WORLD, CTL_ETSI, CTL_ETSI}, - {APL8_WORLD, CTL_ETSI, CTL_ETSI}, - {APL9_WORLD, CTL_ETSI, CTL_ETSI}, - - {APL3_FCCA, CTL_FCC, CTL_FCC}, - {APL1_ETSIC, CTL_FCC, CTL_ETSI}, - {APL2_ETSIC, CTL_FCC, CTL_ETSI}, - {APL2_APLD, CTL_FCC, NO_CTL}, - - {MKK1_MKKA, CTL_MKK, CTL_MKK}, - {MKK1_MKKB, CTL_MKK, CTL_MKK}, - {MKK1_FCCA, CTL_MKK, CTL_FCC}, - {MKK1_MKKA1, CTL_MKK, CTL_MKK}, - {MKK1_MKKA2, CTL_MKK, CTL_MKK}, - {MKK1_MKKC, CTL_MKK, CTL_MKK}, - - {MKK2_MKKA, CTL_MKK, CTL_MKK}, - {MKK3_MKKA, CTL_MKK, CTL_MKK}, - {MKK3_MKKB, CTL_MKK, CTL_MKK}, - {MKK3_MKKA1, CTL_MKK, CTL_MKK}, - {MKK3_MKKA2, CTL_MKK, CTL_MKK}, - {MKK3_MKKC, CTL_MKK, CTL_MKK}, - {MKK3_FCCA, CTL_MKK, CTL_FCC}, - - {MKK4_MKKA, CTL_MKK, CTL_MKK}, - {MKK4_MKKB, CTL_MKK, CTL_MKK}, - {MKK4_MKKA1, CTL_MKK, CTL_MKK}, - {MKK4_MKKA2, CTL_MKK, CTL_MKK}, - {MKK4_MKKC, CTL_MKK, CTL_MKK}, - {MKK4_FCCA, CTL_MKK, CTL_FCC}, - - {MKK5_MKKB, CTL_MKK, CTL_MKK}, - {MKK5_MKKA2, CTL_MKK, CTL_MKK}, - {MKK5_MKKC, CTL_MKK, CTL_MKK}, - - {MKK6_MKKB, CTL_MKK, CTL_MKK}, - {MKK6_MKKA1, CTL_MKK, CTL_MKK}, - {MKK6_MKKA2, CTL_MKK, CTL_MKK}, - {MKK6_MKKC, CTL_MKK, CTL_MKK}, - {MKK6_FCCA, CTL_MKK, CTL_FCC}, - - {MKK7_MKKB, CTL_MKK, CTL_MKK}, - {MKK7_MKKA1, CTL_MKK, CTL_MKK}, - {MKK7_MKKA2, CTL_MKK, CTL_MKK}, - {MKK7_MKKC, CTL_MKK, CTL_MKK}, - {MKK7_FCCA, CTL_MKK, CTL_FCC}, - - {MKK8_MKKB, CTL_MKK, CTL_MKK}, - {MKK8_MKKA2, CTL_MKK, CTL_MKK}, - {MKK8_MKKC, CTL_MKK, CTL_MKK}, - - {MKK9_MKKA, CTL_MKK, CTL_MKK}, - {MKK9_FCCA, CTL_MKK, CTL_FCC}, - {MKK9_MKKA1, CTL_MKK, CTL_MKK}, - {MKK9_MKKA2, CTL_MKK, CTL_MKK}, - {MKK9_MKKC, CTL_MKK, CTL_MKK}, - - {MKK10_MKKA, CTL_MKK, CTL_MKK}, - {MKK10_FCCA, CTL_MKK, CTL_FCC}, - {MKK10_MKKA1, CTL_MKK, CTL_MKK}, - {MKK10_MKKA2, CTL_MKK, CTL_MKK}, - {MKK10_MKKC, CTL_MKK, CTL_MKK}, - - {MKK11_MKKA, CTL_MKK, CTL_MKK}, - {MKK11_FCCA, CTL_MKK, CTL_FCC}, - {MKK11_MKKA1, CTL_MKK, CTL_MKK}, - {MKK11_MKKA2, CTL_MKK, CTL_MKK}, - {MKK11_MKKC, CTL_MKK, CTL_MKK}, - - {MKK12_MKKA, CTL_MKK, CTL_MKK}, - {MKK12_FCCA, CTL_MKK, CTL_FCC}, - {MKK12_MKKA1, CTL_MKK, CTL_MKK}, - {MKK12_MKKA2, CTL_MKK, CTL_MKK}, - {MKK12_MKKC, CTL_MKK, CTL_MKK}, - - {MKK13_MKKB, CTL_MKK, CTL_MKK}, - {MKK14_MKKA1, CTL_MKK, CTL_MKK}, - {MKK15_MKKA1, CTL_MKK, CTL_MKK}, - - {WOR0_WORLD, NO_CTL, NO_CTL}, - {WOR1_WORLD, NO_CTL, NO_CTL}, - {WOR2_WORLD, NO_CTL, NO_CTL}, - {WOR3_WORLD, NO_CTL, NO_CTL}, - {WOR4_WORLD, NO_CTL, NO_CTL}, - {WOR5_ETSIC, NO_CTL, NO_CTL}, - {WOR01_WORLD, NO_CTL, NO_CTL}, - {WOR02_WORLD, NO_CTL, NO_CTL}, - {EU1_WORLD, NO_CTL, NO_CTL}, - {WOR9_WORLD, NO_CTL, NO_CTL}, - {WORA_WORLD, NO_CTL, NO_CTL}, - {WORB_WORLD, NO_CTL, NO_CTL}, -}; - -static struct country_code_to_enum_rd allCountries[] = { - {CTRY_DEBUG, NO_ENUMRD, "DB"}, - {CTRY_DEFAULT, FCC1_FCCA, "CO"}, - {CTRY_ALBANIA, NULL1_WORLD, "AL"}, - {CTRY_ALGERIA, NULL1_WORLD, "DZ"}, - {CTRY_ARGENTINA, APL3_WORLD, "AR"}, - {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, - {CTRY_AUSTRALIA, FCC2_WORLD, "AU"}, - {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, - {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, - {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, - {CTRY_BAHRAIN, APL6_WORLD, "BH"}, - {CTRY_BELARUS, ETSI1_WORLD, "BY"}, - {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, - {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, - {CTRY_BELIZE, APL1_ETSIC, "BZ"}, - {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, - {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, - {CTRY_BRAZIL, FCC3_WORLD, "BR"}, - {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"}, - {CTRY_BULGARIA, ETSI6_WORLD, "BG"}, - {CTRY_CANADA, FCC2_FCCA, "CA"}, - {CTRY_CANADA2, FCC6_FCCA, "CA"}, - {CTRY_CHILE, APL6_WORLD, "CL"}, - {CTRY_CHINA, APL1_WORLD, "CN"}, - {CTRY_COLOMBIA, FCC1_FCCA, "CO"}, - {CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, - {CTRY_CROATIA, ETSI3_WORLD, "HR"}, - {CTRY_CYPRUS, ETSI1_WORLD, "CY"}, - {CTRY_CZECH, ETSI3_WORLD, "CZ"}, - {CTRY_DENMARK, ETSI1_WORLD, "DK"}, - {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO"}, - {CTRY_ECUADOR, FCC1_WORLD, "EC"}, - {CTRY_EGYPT, ETSI3_WORLD, "EG"}, - {CTRY_EL_SALVADOR, FCC1_WORLD, "SV"}, - {CTRY_ESTONIA, ETSI1_WORLD, "EE"}, - {CTRY_FINLAND, ETSI1_WORLD, "FI"}, - {CTRY_FRANCE, ETSI1_WORLD, "FR"}, - {CTRY_GEORGIA, ETSI4_WORLD, "GE"}, - {CTRY_GERMANY, ETSI1_WORLD, "DE"}, - {CTRY_GREECE, ETSI1_WORLD, "GR"}, - {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, - {CTRY_HONDURAS, NULL1_WORLD, "HN"}, - {CTRY_HONG_KONG, FCC2_WORLD, "HK"}, - {CTRY_HUNGARY, ETSI1_WORLD, "HU"}, - {CTRY_ICELAND, ETSI1_WORLD, "IS"}, - {CTRY_INDIA, APL6_WORLD, "IN"}, - {CTRY_INDONESIA, APL1_WORLD, "ID"}, - {CTRY_IRAN, APL1_WORLD, "IR"}, - {CTRY_IRELAND, ETSI1_WORLD, "IE"}, - {CTRY_ISRAEL, NULL1_WORLD, "IL"}, - {CTRY_ITALY, ETSI1_WORLD, "IT"}, - {CTRY_JAMAICA, ETSI1_WORLD, "JM"}, - - {CTRY_JAPAN, MKK1_MKKA, "JP"}, - {CTRY_JAPAN1, MKK1_MKKB, "JP"}, - {CTRY_JAPAN2, MKK1_FCCA, "JP"}, - {CTRY_JAPAN3, MKK2_MKKA, "JP"}, - {CTRY_JAPAN4, MKK1_MKKA1, "JP"}, - {CTRY_JAPAN5, MKK1_MKKA2, "JP"}, - {CTRY_JAPAN6, MKK1_MKKC, "JP"}, - {CTRY_JAPAN7, MKK3_MKKB, "JP"}, - {CTRY_JAPAN8, MKK3_MKKA2, "JP"}, - {CTRY_JAPAN9, MKK3_MKKC, "JP"}, - {CTRY_JAPAN10, MKK4_MKKB, "JP"}, - {CTRY_JAPAN11, MKK4_MKKA2, "JP"}, - {CTRY_JAPAN12, MKK4_MKKC, "JP"}, - {CTRY_JAPAN13, MKK5_MKKB, "JP"}, - {CTRY_JAPAN14, MKK5_MKKA2, "JP"}, - {CTRY_JAPAN15, MKK5_MKKC, "JP"}, - {CTRY_JAPAN16, MKK6_MKKB, "JP"}, - {CTRY_JAPAN17, MKK6_MKKA2, "JP"}, - {CTRY_JAPAN18, MKK6_MKKC, "JP"}, - {CTRY_JAPAN19, MKK7_MKKB, "JP"}, - {CTRY_JAPAN20, MKK7_MKKA2, "JP"}, - {CTRY_JAPAN21, MKK7_MKKC, "JP"}, - {CTRY_JAPAN22, MKK8_MKKB, "JP"}, - {CTRY_JAPAN23, MKK8_MKKA2, "JP"}, - {CTRY_JAPAN24, MKK8_MKKC, "JP"}, - {CTRY_JAPAN25, MKK3_MKKA, "JP"}, - {CTRY_JAPAN26, MKK3_MKKA1, "JP"}, - {CTRY_JAPAN27, MKK3_FCCA, "JP"}, - {CTRY_JAPAN28, MKK4_MKKA1, "JP"}, - {CTRY_JAPAN29, MKK4_FCCA, "JP"}, - {CTRY_JAPAN30, MKK6_MKKA1, "JP"}, - {CTRY_JAPAN31, MKK6_FCCA, "JP"}, - {CTRY_JAPAN32, MKK7_MKKA1, "JP"}, - {CTRY_JAPAN33, MKK7_FCCA, "JP"}, - {CTRY_JAPAN34, MKK9_MKKA, "JP"}, - {CTRY_JAPAN35, MKK10_MKKA, "JP"}, - {CTRY_JAPAN36, MKK4_MKKA, "JP"}, - {CTRY_JAPAN37, MKK9_FCCA, "JP"}, - {CTRY_JAPAN38, MKK9_MKKA1, "JP"}, - {CTRY_JAPAN39, MKK9_MKKC, "JP"}, - {CTRY_JAPAN40, MKK9_MKKA2, "JP"}, - {CTRY_JAPAN41, MKK10_FCCA, "JP"}, - {CTRY_JAPAN42, MKK10_MKKA1, "JP"}, - {CTRY_JAPAN43, MKK10_MKKC, "JP"}, - {CTRY_JAPAN44, MKK10_MKKA2, "JP"}, - {CTRY_JAPAN45, MKK11_MKKA, "JP"}, - {CTRY_JAPAN46, MKK11_FCCA, "JP"}, - {CTRY_JAPAN47, MKK11_MKKA1, "JP"}, - {CTRY_JAPAN48, MKK11_MKKC, "JP"}, - {CTRY_JAPAN49, MKK11_MKKA2, "JP"}, - {CTRY_JAPAN50, MKK12_MKKA, "JP"}, - {CTRY_JAPAN51, MKK12_FCCA, "JP"}, - {CTRY_JAPAN52, MKK12_MKKA1, "JP"}, - {CTRY_JAPAN53, MKK12_MKKC, "JP"}, - {CTRY_JAPAN54, MKK12_MKKA2, "JP"}, - {CTRY_JAPAN57, MKK13_MKKB, "JP"}, - {CTRY_JAPAN58, MKK14_MKKA1, "JP"}, - {CTRY_JAPAN59, MKK15_MKKA1, "JP"}, - - {CTRY_JORDAN, ETSI2_WORLD, "JO"}, - {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ"}, - {CTRY_KOREA_NORTH, APL9_WORLD, "KP"}, - {CTRY_KOREA_ROC, APL9_WORLD, "KR"}, - {CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, - {CTRY_KOREA_ROC3, APL9_WORLD, "K3"}, - {CTRY_KUWAIT, NULL1_WORLD, "KW"}, - {CTRY_LATVIA, ETSI1_WORLD, "LV"}, - {CTRY_LEBANON, NULL1_WORLD, "LB"}, - {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"}, - {CTRY_LITHUANIA, ETSI1_WORLD, "LT"}, - {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU"}, - {CTRY_MACAU, FCC2_WORLD, "MO"}, - {CTRY_MACEDONIA, NULL1_WORLD, "MK"}, - {CTRY_MALAYSIA, APL8_WORLD, "MY"}, - {CTRY_MALTA, ETSI1_WORLD, "MT"}, - {CTRY_MEXICO, FCC1_FCCA, "MX"}, - {CTRY_MONACO, ETSI4_WORLD, "MC"}, - {CTRY_MOROCCO, NULL1_WORLD, "MA"}, - {CTRY_NEPAL, APL1_WORLD, "NP"}, - {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, - {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, - {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, - {CTRY_NORWAY, ETSI1_WORLD, "NO"}, - {CTRY_OMAN, APL6_WORLD, "OM"}, - {CTRY_PAKISTAN, NULL1_WORLD, "PK"}, - {CTRY_PANAMA, FCC1_FCCA, "PA"}, - {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, - {CTRY_PERU, APL1_WORLD, "PE"}, - {CTRY_PHILIPPINES, APL1_WORLD, "PH"}, - {CTRY_POLAND, ETSI1_WORLD, "PL"}, - {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, - {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, - {CTRY_QATAR, NULL1_WORLD, "QA"}, - {CTRY_ROMANIA, NULL1_WORLD, "RO"}, - {CTRY_RUSSIA, NULL1_WORLD, "RU"}, - {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, - {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, - {CTRY_SINGAPORE, APL6_WORLD, "SG"}, - {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, - {CTRY_SLOVENIA, ETSI1_WORLD, "SI"}, - {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA"}, - {CTRY_SPAIN, ETSI1_WORLD, "ES"}, - {CTRY_SRI_LANKA, FCC3_WORLD, "LK"}, - {CTRY_SWEDEN, ETSI1_WORLD, "SE"}, - {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, - {CTRY_SYRIA, NULL1_WORLD, "SY"}, - {CTRY_TAIWAN, APL3_FCCA, "TW"}, - {CTRY_THAILAND, NULL1_WORLD, "TH"}, - {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, - {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, - {CTRY_TURKEY, ETSI3_WORLD, "TR"}, - {CTRY_UKRAINE, NULL1_WORLD, "UA"}, - {CTRY_UAE, NULL1_WORLD, "AE"}, - {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, - {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, - /* This "PS" is for US public safety actually... to support this we - * would need to assign new special alpha2 to CRDA db as with the world - * regdomain and use another alpha2 */ - {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"}, - {CTRY_URUGUAY, APL2_WORLD, "UY"}, - {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"}, - {CTRY_VENEZUELA, APL2_ETSIC, "VE"}, - {CTRY_VIET_NAM, NULL1_WORLD, "VN"}, - {CTRY_YEMEN, NULL1_WORLD, "YE"}, - {CTRY_ZIMBABWE, NULL1_WORLD, "ZW"}, -}; - -#endif -- cgit v0.10.2 From e3bb249be89dd387e78ca382d08fad31745edac9 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 30 Mar 2009 22:30:30 -0400 Subject: ath: move more setup code into ath_regd_init Setup the wiphy regulatory parameters when first initializing the Atheros regulatory module. We can remove five exported symbols this way and simplify the driver code for both ath5k and ath9k. Signed-off-by: Bob Copeland Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 4d3935b..3ccf21c 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -126,14 +126,13 @@ bool ath_is_world_regd(struct ath_regulatory *reg) } EXPORT_SYMBOL(ath_is_world_regd); -const struct ieee80211_regdomain *ath_default_world_regdomain(void) +static const struct ieee80211_regdomain *ath_default_world_regdomain(void) { /* this is the most restrictive */ return &ath_world_regdom_64; } -EXPORT_SYMBOL(ath_default_world_regdomain); -const struct +static const struct ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) { switch (reg->regpair->regDmnEnum) { @@ -158,7 +157,6 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) return ath_default_world_regdomain(); } } -EXPORT_SYMBOL(ath_world_regdomain); /* Frequency is one where radar detection is required */ static bool ath_is_radar_freq(u16 center_freq) @@ -285,7 +283,7 @@ static void ath_reg_apply_active_scan_flags( } /* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ -void ath_reg_apply_radar_flags(struct wiphy *wiphy) +static void ath_reg_apply_radar_flags(struct wiphy *wiphy) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; @@ -316,11 +314,10 @@ void ath_reg_apply_radar_flags(struct wiphy *wiphy) IEEE80211_CHAN_PASSIVE_SCAN; } } -EXPORT_SYMBOL(ath_reg_apply_radar_flags); -void ath_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator, - struct ath_regulatory *reg) +static void ath_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + struct ath_regulatory *reg) { switch (reg->regpair->regDmnEnum) { case 0x60: @@ -336,7 +333,6 @@ void ath_reg_apply_world_flags(struct wiphy *wiphy, } return; } -EXPORT_SYMBOL(ath_reg_apply_world_flags); int ath_reg_notifier_apply(struct wiphy *wiphy, struct regulatory_request *request, struct ath_regulatory *reg) @@ -360,7 +356,7 @@ int ath_reg_notifier_apply(struct wiphy *wiphy, } EXPORT_SYMBOL(ath_reg_notifier_apply); -bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) +static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) { u16 rd = ath_regd_get_eepromRD(reg); int i; @@ -381,7 +377,6 @@ bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) "ath: invalid regulatory domain/country code 0x%x\n", rd); return false; } -EXPORT_SYMBOL(ath_regd_is_eeprom_valid); /* EEPROM country code to regpair mapping */ static struct country_code_to_enum_rd* @@ -438,7 +433,40 @@ ath_get_regpair(int regdmn) return NULL; } -int ath_regd_init(struct ath_regulatory *reg) +static int ath_regd_init_wiphy(struct ath_regulatory *reg, struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) +{ + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; + wiphy->strict_regulatory = true; + + if (ath_is_world_regd(reg)) { + /* + * Anything applied here (prior to wiphy registration) gets + * saved on the wiphy orig_* parameters + */ + regd = ath_world_regdomain(reg); + wiphy->custom_regulatory = true; + wiphy->strict_regulatory = false; + } else { + /* + * This gets applied in the case of the absense of CRDA, + * it's our own custom world regulatory domain, similar to + * cfg80211's but we enable passive scanning. + */ + regd = ath_default_world_regdomain(); + } + wiphy_apply_custom_regulatory(wiphy, regd); + ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); + return 0; +} + +int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) { struct country_code_to_enum_rd *country = NULL; u16 regdmn; @@ -492,6 +520,7 @@ int ath_regd_init(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n", reg->regpair->regDmnEnum); + ath_regd_init_wiphy(reg, wiphy, reg_notifier); return 0; } EXPORT_SYMBOL(ath_regd_init); diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 981f5cf..eba7c71 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -254,15 +254,9 @@ enum CountryCode { }; bool ath_is_world_regd(struct ath_regulatory *reg); -const -struct ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg); -const struct ieee80211_regdomain *ath_default_world_regdomain(void); -void ath_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator, - struct ath_regulatory *reg); -void ath_reg_apply_radar_flags(struct wiphy *wiphy); -int ath_regd_init(struct ath_regulatory *reg); -bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg); +int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)); u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, enum ieee80211_band band); int ath_reg_notifier_apply(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index d779f00..8b6a7ea 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1352,6 +1352,17 @@ void ath_detach(struct ath_softc *sc) ath9k_ps_restore(sc); } +static int ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_regulatory *reg = &sc->sc_ah->regulatory; + + return ath_reg_notifier_apply(wiphy, request, reg); +} + static int ath_init(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; @@ -1406,7 +1417,8 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (ath_regd_init(&sc->sc_ah->regulatory)) + if (ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + ath9k_reg_notifier)) goto bad; /* default to MONITOR mode */ @@ -1570,17 +1582,6 @@ bad: return error; } -static int ath9k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = &sc->sc_ah->regulatory; - - return ath_reg_notifier_apply(wiphy, request, reg); -} - void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | @@ -1600,9 +1601,6 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->wiphy->reg_notifier = ath9k_reg_notifier; - hw->wiphy->strict_regulatory = true; - hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; @@ -1623,7 +1621,6 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) int ath_attach(u16 devid, struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; - const struct ieee80211_regdomain *regd; int error = 0, i; struct ath_regulatory *reg; @@ -1667,24 +1664,6 @@ int ath_attach(u16 devid, struct ath_softc *sc) goto error_attach; #endif - if (ath_is_world_regd(reg)) { - /* Anything applied here (prior to wiphy registration) gets - * saved on the wiphy orig_* parameters */ - regd = ath_world_regdomain(reg); - hw->wiphy->custom_regulatory = true; - hw->wiphy->strict_regulatory = false; - } else { - /* This gets applied in the case of the absense of CRDA, - * it's our own custom world regulatory domain, similar to - * cfg80211's but we enable passive scanning */ - regd = ath_default_world_regdomain(); - } - wiphy_apply_custom_regulatory(hw->wiphy, regd); - ath_reg_apply_radar_flags(hw->wiphy); - ath_reg_apply_world_flags(hw->wiphy, - NL80211_REGDOM_SET_BY_DRIVER, - reg); - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); sc->wiphy_scheduler_int = msecs_to_jiffies(500); -- cgit v0.10.2 From f769c36bd71ebe8d7a5f83764f0428d36ebced35 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 30 Mar 2009 22:30:31 -0400 Subject: ath5k: use regulatory infrastructure Make ath5k select the ath module and add in the hooks to make the eeprom regulatory hint and reg notifier take effect. Changes to attach.c Changes-licensed-under: ISC Changes to base.c Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath5k/Kconfig b/drivers/net/wireless/ath5k/Kconfig index 75383a5..509b6f9 100644 --- a/drivers/net/wireless/ath5k/Kconfig +++ b/drivers/net/wireless/ath5k/Kconfig @@ -1,6 +1,7 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 0b616e7..48c18d1 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -27,6 +27,8 @@ #include #include +#include "../ath/regd.h" + /* RX/TX descriptor hw structs * TODO: Driver part should only see sw structs */ #include "desc.h" @@ -1039,8 +1041,6 @@ struct ath5k_hw { bool ah_5ghz; bool ah_2ghz; -#define ah_regdomain ah_capabilities.cap_regdomain.reg_current -#define ah_regdomain_hw ah_capabilities.cap_regdomain.reg_hw #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version @@ -1065,6 +1065,7 @@ struct ath5k_hw { u32 ah_gpio[AR5K_MAX_GPIO]; int ah_gpio_npins; + struct ath_regulatory ah_regulatory; struct ath5k_capabilities ah_capabilities; struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index d8c60c5..ff6d4f8 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -709,6 +709,15 @@ err_no_irq: * Driver Initialization * \***********************/ +static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath5k_softc *sc = hw->priv; + struct ath_regulatory *reg = &sc->ah->ah_regulatory; + + return ath_reg_notifier_apply(wiphy, request, reg); +} + static int ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { @@ -797,12 +806,23 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) memset(sc->bssidmask, 0xff, ETH_ALEN); ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + ah->ah_regulatory.current_rd = + ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier); + if (ret) { + ATH5K_ERR(sc, "can't initialize regulatory system\n"); + goto err_queues; + } + ret = ieee80211_register_hw(hw); if (ret) { ATH5K_ERR(sc, "can't register ieee80211 hw\n"); goto err_queues; } + if (!ath_is_world_regd(&sc->ah->ah_regulatory)) + regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2); + ath5k_init_leds(sc); return 0; -- cgit v0.10.2 From 1878f77e13b9d720b78c4f818b94bfd4a7f596e5 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 30 Mar 2009 22:30:32 -0400 Subject: Make ar9170 use common ath reg code Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ar9170/Kconfig b/drivers/net/wireless/ar9170/Kconfig index de4281f..b99e326 100644 --- a/drivers/net/wireless/ar9170/Kconfig +++ b/drivers/net/wireless/ar9170/Kconfig @@ -2,6 +2,7 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER + select ATH_COMMON help This is a driver for the Atheros "otus" 802.11n USB devices. diff --git a/drivers/net/wireless/ar9170/ar9170.h b/drivers/net/wireless/ar9170/ar9170.h index f4fb2e9..87c1985 100644 --- a/drivers/net/wireless/ar9170/ar9170.h +++ b/drivers/net/wireless/ar9170/ar9170.h @@ -48,6 +48,8 @@ #include "eeprom.h" #include "hw.h" +#include "../ath/regd.h" + #define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) enum ar9170_bw { @@ -151,6 +153,7 @@ struct ar9170 { /* EEPROM */ struct ar9170_eeprom eeprom; + struct ath_regulatory regulatory; /* global tx status for unregistered Stations. */ struct sk_buff_head global_tx_status; diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ar9170/main.c index 5f55754..8de0ff9 100644 --- a/drivers/net/wireless/ar9170/main.c +++ b/drivers/net/wireless/ar9170/main.c @@ -1620,12 +1620,24 @@ static int ar9170_read_eeprom(struct ar9170 *ar) else ar->hw->channel_change_time = 80 * 1000; + ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); + ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); + /* second part of wiphy init */ SET_IEEE80211_PERM_ADDR(ar->hw, addr); return bands ? 0 : -EINVAL; } +static int ar9170_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ar9170 *ar = hw->priv; + + return ath_reg_notifier_apply(wiphy, request, &ar->regulatory); +} + int ar9170_register(struct ar9170 *ar, struct device *pdev) { int err; @@ -1635,10 +1647,16 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; + err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, + ar9170_reg_notifier); + err = ieee80211_register_hw(ar->hw); if (err) goto err_out; + if (!ath_is_world_regd(&ar->regulatory)) + regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2); + err = ar9170_init_leds(ar); if (err) goto err_unreg; diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index c2873a2..76517a4 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,4 +1,4 @@ config ATH_COMMON tristate "Atheros Wireless Cards Shared Support" - depends on ATH5K || ATH9K + depends on ATH5K || ATH9K || AR9170_USB -- cgit v0.10.2 From 203c4805e91786f9a010bc7945a0fde70c9da28e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 30 Mar 2009 22:30:33 -0400 Subject: atheros: put atheros wireless drivers into ath/ Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9e2c7e2..8f279e7 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -484,9 +484,6 @@ config MWL8K source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/ath/Kconfig" -source "drivers/net/wireless/ath5k/Kconfig" -source "drivers/net/wireless/ath9k/Kconfig" -source "drivers/net/wireless/ar9170/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 104639e..0625e91 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -56,8 +56,5 @@ obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_P54_COMMON) += p54/ obj-$(CONFIG_ATH_COMMON) += ath/ -obj-$(CONFIG_ATH5K) += ath5k/ -obj-$(CONFIG_ATH9K) += ath9k/ -obj-$(CONFIG_AR9170_USB) += ar9170/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o diff --git a/drivers/net/wireless/ar9170/Kconfig b/drivers/net/wireless/ar9170/Kconfig deleted file mode 100644 index b99e326..0000000 --- a/drivers/net/wireless/ar9170/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config AR9170_USB - tristate "Atheros AR9170 802.11n USB support" - depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL - select FW_LOADER - select ATH_COMMON - help - This is a driver for the Atheros "otus" 802.11n USB devices. - - These devices require additional firmware (2 files). - For now, these files can be downloaded from here: - http://wireless.kernel.org/en/users/Drivers/ar9170 - - If you choose to build a module, it'll be called ar9170usb. - -config AR9170_LEDS - bool - depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) - default y diff --git a/drivers/net/wireless/ar9170/Makefile b/drivers/net/wireless/ar9170/Makefile deleted file mode 100644 index 8d91c7e..0000000 --- a/drivers/net/wireless/ar9170/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o - -obj-$(CONFIG_AR9170_USB) += ar9170usb.o diff --git a/drivers/net/wireless/ar9170/ar9170.h b/drivers/net/wireless/ar9170/ar9170.h deleted file mode 100644 index 87c1985..0000000 --- a/drivers/net/wireless/ar9170/ar9170.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __AR9170_H -#define __AR9170_H - -#include -#include -#include -#include -#ifdef CONFIG_AR9170_LEDS -#include -#endif /* CONFIG_AR9170_LEDS */ -#include "eeprom.h" -#include "hw.h" - -#include "../ath/regd.h" - -#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) - -enum ar9170_bw { - AR9170_BW_20, - AR9170_BW_40_BELOW, - AR9170_BW_40_ABOVE, - - __AR9170_NUM_BW, -}; - -enum ar9170_rf_init_mode { - AR9170_RFI_NONE, - AR9170_RFI_WARM, - AR9170_RFI_COLD, -}; - -#define AR9170_MAX_RX_BUFFER_SIZE 8192 - -#ifdef CONFIG_AR9170_LEDS -struct ar9170; - -struct ar9170_led { - struct ar9170 *ar; - struct led_classdev l; - char name[32]; - unsigned int toggled; - bool registered; -}; - -#endif /* CONFIG_AR9170_LEDS */ - -enum ar9170_device_state { - AR9170_UNKNOWN_STATE, - AR9170_STOPPED, - AR9170_IDLE, - AR9170_STARTED, - AR9170_ASSOCIATED, -}; - -struct ar9170 { - struct ieee80211_hw *hw; - struct mutex mutex; - enum ar9170_device_state state; - - int (*open)(struct ar9170 *); - void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int); - int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , - void *, u32 , void *); - void (*callback_cmd)(struct ar9170 *, u32 , void *); - - /* interface mode settings */ - struct ieee80211_vif *vif; - u8 mac_addr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - - /* beaconing */ - struct sk_buff *beacon; - struct work_struct beacon_work; - - /* cryptographic engine */ - u64 usedkeys; - bool rx_software_decryption; - bool disable_offload; - - /* filter settings */ - struct work_struct filter_config_work; - u64 cur_mc_hash, want_mc_hash; - u32 cur_filter, want_filter; - unsigned int filter_changed; - bool sniffer_enabled; - - /* PHY */ - struct ieee80211_channel *channel; - int noise[4]; - - /* power calibration data */ - u8 power_5G_leg[4]; - u8 power_2G_cck[4]; - u8 power_2G_ofdm[4]; - u8 power_5G_ht20[8]; - u8 power_5G_ht40[8]; - u8 power_2G_ht20[8]; - u8 power_2G_ht40[8]; - -#ifdef CONFIG_AR9170_LEDS - struct delayed_work led_work; - struct ar9170_led leds[AR9170_NUM_LEDS]; -#endif /* CONFIG_AR9170_LEDS */ - - /* qos queue settings */ - spinlock_t tx_stats_lock; - struct ieee80211_tx_queue_stats tx_stats[5]; - struct ieee80211_tx_queue_params edcf[5]; - - spinlock_t cmdlock; - __le32 cmdbuf[PAYLOAD_MAX + 1]; - - /* MAC statistics */ - struct ieee80211_low_level_stats stats; - - /* EEPROM */ - struct ar9170_eeprom eeprom; - struct ath_regulatory regulatory; - - /* global tx status for unregistered Stations. */ - struct sk_buff_head global_tx_status; - struct sk_buff_head global_tx_status_waste; - struct delayed_work tx_status_janitor; -}; - -struct ar9170_sta_info { - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; -}; - -#define IS_STARTED(a) (a->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) - -#define AR9170_FILTER_CHANGED_PROMISC BIT(0) -#define AR9170_FILTER_CHANGED_MULTICAST BIT(1) -#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) - -/* exported interface */ -void *ar9170_alloc(size_t priv_size); -int ar9170_register(struct ar9170 *ar, struct device *pdev); -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); -void ar9170_unregister(struct ar9170 *ar); -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool update_statistics, u16 tx_status); - -/* MAC */ -int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int ar9170_init_mac(struct ar9170 *ar); -int ar9170_set_qos(struct ar9170 *ar); -int ar9170_update_multicast(struct ar9170 *ar); -int ar9170_update_frame_filter(struct ar9170 *ar); -int ar9170_set_operating_mode(struct ar9170 *ar); -int ar9170_set_beacon_timers(struct ar9170 *ar); -int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); -int ar9170_update_beacon(struct ar9170 *ar); -void ar9170_new_beacon(struct work_struct *work); -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen); -int ar9170_disable_key(struct ar9170 *ar, u8 id); - -/* LEDs */ -#ifdef CONFIG_AR9170_LEDS -int ar9170_register_leds(struct ar9170 *ar); -void ar9170_unregister_leds(struct ar9170 *ar); -#endif /* CONFIG_AR9170_LEDS */ -int ar9170_init_leds(struct ar9170 *ar); -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); - -/* PHY / RF */ -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); -int ar9170_init_rf(struct ar9170 *ar); -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); - -#endif /* __AR9170_H */ diff --git a/drivers/net/wireless/ar9170/cmd.c b/drivers/net/wireless/ar9170/cmd.c deleted file mode 100644 index f57a620..0000000 --- a/drivers/net/wireless/ar9170/cmd.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ar9170.h" -#include "cmd.h" - -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) -{ - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); - if (err) - printk(KERN_DEBUG "%s: writing memory failed\n", - wiphy_name(ar->hw->wiphy)); - return err; -} - -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) -{ - __le32 buf[2] = { - cpu_to_le32(reg), - cpu_to_le32(val), - }; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), - (u8 *) buf, 0, NULL); - if (err) - printk(KERN_DEBUG "%s: writing reg %#x (val %#x) failed\n", - wiphy_name(ar->hw->wiphy), reg, val); - return err; -} - -static int ar9170_read_mreg(struct ar9170 *ar, int nregs, - const u32 *regs, u32 *out) -{ - int i, err; - __le32 *offs, *res; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - /* abuse "out" for the register offsets, must be same length */ - offs = (__le32 *)out; - for (i = 0; i < nregs; i++) - offs[i] = cpu_to_le32(regs[i]); - - /* also use the same buffer for the input */ - res = (__le32 *)out; - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - 4 * nregs, (u8 *)offs, - 4 * nregs, (u8 *)res); - if (err) - return err; - - /* convert result to cpu endian */ - for (i = 0; i < nregs; i++) - out[i] = le32_to_cpu(res[i]); - - return 0; -} - -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) -{ - return ar9170_read_mreg(ar, 1, ®, val); -} - -int ar9170_echo_test(struct ar9170 *ar, u32 v) -{ - __le32 echobuf = cpu_to_le32(v); - __le32 echores; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -ENODEV; - - err = ar->exec_cmd(ar, AR9170_CMD_ECHO, - 4, (u8 *)&echobuf, - 4, (u8 *)&echores); - if (err) - return err; - - if (echobuf != echores) - return -EINVAL; - - return 0; -} diff --git a/drivers/net/wireless/ar9170/cmd.h b/drivers/net/wireless/ar9170/cmd.h deleted file mode 100644 index a4f0e50..0000000 --- a/drivers/net/wireless/ar9170/cmd.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __CMD_H -#define __CMD_H - -#include "ar9170.h" - -/* basic HW access */ -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); -int ar9170_echo_test(struct ar9170 *ar, u32 v); - -/* - * Macros to facilitate writing multiple registers in a single - * write-combining USB command. Note that when the first group - * fails the whole thing will fail without any others attempted, - * but you won't know which write in the group failed. - */ -#define ar9170_regwrite_begin(ar) \ -do { \ - int __nreg = 0, __err = 0; \ - struct ar9170 *__ar = ar; - -#define ar9170_regwrite(r, v) do { \ - __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ - __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ - __nreg++; \ - if ((__nreg >= PAYLOAD_MAX/2)) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - if (__err) \ - goto __regwrite_out; \ - } \ -} while (0) - -#define ar9170_regwrite_finish() \ -__regwrite_out : \ - if (__nreg) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - } - -#define ar9170_regwrite_result() \ - __err; \ -} while (0); - -#endif /* __CMD_H */ diff --git a/drivers/net/wireless/ar9170/eeprom.h b/drivers/net/wireless/ar9170/eeprom.h deleted file mode 100644 index d2c8cc8..0000000 --- a/drivers/net/wireless/ar9170/eeprom.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Atheros AR9170 driver - * - * EEPROM layout - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __AR9170_EEPROM_H -#define __AR9170_EEPROM_H - -#define AR5416_MAX_CHAINS 2 -#define AR5416_MODAL_SPURS 5 - -struct ar9170_eeprom_modal { - __le32 antCtrlChain[AR5416_MAX_CHAINS]; - __le32 antCtrlCommon; - s8 antennaGainCh[AR5416_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_MAX_CHAINS]; - s8 adcDesiredSize; - s8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - s8 iqCalICh[AR5416_MAX_CHAINS]; - s8 iqCalQCh[AR5416_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob; - u8 db; - u8 xpaBiasLvl; - u8 pwrDecreaseFor2Chain; - u8 pwrDecreaseFor3Chain; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_MAX_CHAINS]; - u8 bswMargin[AR5416_MAX_CHAINS]; - u8 swSettleHt40; - u8 reserved[22]; - struct spur_channel { - __le16 spurChan; - u8 spurRangeLow; - u8 spurRangeHigh; - } __packed spur_channels[AR5416_MODAL_SPURS]; -} __packed; - -#define AR5416_NUM_PD_GAINS 4 -#define AR5416_PD_GAIN_ICEPTS 5 - -struct ar9170_calibration_data_per_freq { - u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; - u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; -} __packed; - -#define AR5416_NUM_5G_CAL_PIERS 8 -#define AR5416_NUM_2G_CAL_PIERS 4 - -#define AR5416_NUM_5G_TARGET_PWRS 8 -#define AR5416_NUM_2G_CCK_TARGET_PWRS 3 -#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 -#define AR5416_MAX_NUM_TGT_PWRS 8 - -struct ar9170_calibration_target_power_legacy { - u8 freq; - u8 power[4]; -} __packed; - -struct ar9170_calibration_target_power_ht { - u8 freq; - u8 power[8]; -} __packed; - -#define AR5416_NUM_CTLS 24 - -struct ar9170_calctl_edges { - u8 channel; -#define AR9170_CALCTL_EDGE_FLAGS 0xC0 - u8 power_flags; -} __packed; - -#define AR5416_NUM_BAND_EDGES 8 - -struct ar9170_calctl_data { - struct ar9170_calctl_edges - control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; -} __packed; - - -struct ar9170_eeprom { - __le16 length; - __le16 checksum; - __le16 version; - u8 operating_flags; -#define AR9170_OPFLAG_5GHZ 1 -#define AR9170_OPFLAG_2GHZ 2 - u8 misc; - __le16 reg_domain[2]; - u8 mac_address[6]; - u8 rx_mask; - u8 tx_mask; - __le16 rf_silent; - __le16 bluetooth_options; - __le16 device_capabilities; - __le32 build_number; - u8 deviceType; - u8 reserved[33]; - - u8 customer_data[64]; - - struct ar9170_eeprom_modal - modal_header[2]; - - u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; - u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; - - struct ar9170_calibration_data_per_freq - cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], - cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; - - /* power calibration data */ - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], - cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; - - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], - cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], - cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - - /* conformance testing limits */ - u8 ctl_index[AR5416_NUM_CTLS]; - struct ar9170_calctl_data - ctl_data[AR5416_NUM_CTLS]; - - u8 pad; - __le16 subsystem_id; -} __packed; - -#endif /* __AR9170_EEPROM_H */ diff --git a/drivers/net/wireless/ar9170/hw.h b/drivers/net/wireless/ar9170/hw.h deleted file mode 100644 index 53e250a..0000000 --- a/drivers/net/wireless/ar9170/hw.h +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Hardware-specific definitions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __AR9170_HW_H -#define __AR9170_HW_H - -#define AR9170_MAX_CMD_LEN 64 - -enum ar9170_cmd { - AR9170_CMD_RREG = 0x00, - AR9170_CMD_WREG = 0x01, - AR9170_CMD_RMEM = 0x02, - AR9170_CMD_WMEM = 0x03, - AR9170_CMD_BITAND = 0x04, - AR9170_CMD_BITOR = 0x05, - AR9170_CMD_EKEY = 0x28, - AR9170_CMD_DKEY = 0x29, - AR9170_CMD_FREQUENCY = 0x30, - AR9170_CMD_RF_INIT = 0x31, - AR9170_CMD_SYNTH = 0x32, - AR9170_CMD_FREQ_START = 0x33, - AR9170_CMD_ECHO = 0x80, - AR9170_CMD_TALLY = 0x81, - AR9170_CMD_TALLY_APD = 0x82, - AR9170_CMD_CONFIG = 0x83, - AR9170_CMD_RESET = 0x90, - AR9170_CMD_DKRESET = 0x91, - AR9170_CMD_DKTX_STATUS = 0x92, - AR9170_CMD_FDC = 0xA0, - AR9170_CMD_WREEPROM = 0xB0, - AR9170_CMD_WFLASH = 0xB0, - AR9170_CMD_FLASH_ERASE = 0xB1, - AR9170_CMD_FLASH_PROG = 0xB2, - AR9170_CMD_FLASH_CHKSUM = 0xB3, - AR9170_CMD_FLASH_READ = 0xB4, - AR9170_CMD_FW_DL_INIT = 0xB5, - AR9170_CMD_MEM_WREEPROM = 0xBB, -}; - -/* endpoints */ -#define AR9170_EP_TX 1 -#define AR9170_EP_RX 2 -#define AR9170_EP_IRQ 3 -#define AR9170_EP_CMD 4 - -#define AR9170_EEPROM_START 0x1600 - -#define AR9170_GPIO_REG_BASE 0x1d0100 -#define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE -#define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) -#define AR9170_NUM_LEDS 2 - - -#define AR9170_USB_REG_BASE 0x1e1000 -#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) -#define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 -#define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 -#define AR9170_DMA_CTL_HIGH_SPEED 0x4 -#define AR9170_DMA_CTL_PACKET_MODE 0x8 - -#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) -#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) - - - -#define AR9170_MAC_REG_BASE 0x1c3000 - -#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) -#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) - -#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) -#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) -#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) - -#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) -#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) -#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) -#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) - -#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) -#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) - -#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) - -#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) -#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) -#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) -#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) -#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) -#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) - -#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) -#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) -#define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) -#define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 -#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) -#define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) -#define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 - -#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) -#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) - -#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) -#define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) -#define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) -#define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) -#define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) -#define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) -#define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) -#define AR9170_MAC_REG_FTF_BIT6 BIT(6) -#define AR9170_MAC_REG_FTF_BIT7 BIT(7) -#define AR9170_MAC_REG_FTF_BEACON BIT(8) -#define AR9170_MAC_REG_FTF_ATIM BIT(9) -#define AR9170_MAC_REG_FTF_DEASSOC BIT(10) -#define AR9170_MAC_REG_FTF_AUTH BIT(11) -#define AR9170_MAC_REG_FTF_DEAUTH BIT(12) -#define AR9170_MAC_REG_FTF_BIT13 BIT(13) -#define AR9170_MAC_REG_FTF_BIT14 BIT(14) -#define AR9170_MAC_REG_FTF_BIT15 BIT(15) -#define AR9170_MAC_REG_FTF_BAR BIT(24) -#define AR9170_MAC_REG_FTF_BIT25 BIT(25) -#define AR9170_MAC_REG_FTF_PSPOLL BIT(26) -#define AR9170_MAC_REG_FTF_RTS BIT(27) -#define AR9170_MAC_REG_FTF_CTS BIT(28) -#define AR9170_MAC_REG_FTF_ACK BIT(29) -#define AR9170_MAC_REG_FTF_CFE BIT(30) -#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) -#define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff -#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff - -#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) -#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) -#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) -#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) -#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) -#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) - - -#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) -#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) - -#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) - -#define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) -#define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 -#define AR9170_MAC_REG_POWERMGT_AP 0xa1 -#define AR9170_MAC_REG_POWERMGT_STA 0x2 -#define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 -#define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) - -#define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) -#define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) - -#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) -#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) -#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) -#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) -#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) -#define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) -#define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) - -#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) - -#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) -#define AR9170_MAC_FCS_SWFCS 0x1 -#define AR9170_MAC_FCS_FIFO_PROT 0x4 - - -#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) - -#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) -#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) - -#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) -#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) - -#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) -#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f -#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 -#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 -#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 - -#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) -#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) -#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) -#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) -#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) -#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) - - -#define AR9170_PWR_REG_BASE 0x1D4000 - -#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) -#define AR9170_PWR_CLK_AHB_40MHZ 0 -#define AR9170_PWR_CLK_AHB_20_22MHZ 1 -#define AR9170_PWR_CLK_AHB_40_44MHZ 2 -#define AR9170_PWR_CLK_AHB_80_88MHZ 3 -#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 - - -/* put beacon here in memory */ -#define AR9170_BEACON_BUFFER_ADDRESS 0x117900 - - -struct ar9170_tx_control { - __le16 length; - __le16 mac_control; - __le32 phy_control; - u8 frame_data[0]; -} __packed; - -/* these are either-or */ -#define AR9170_TX_MAC_PROT_RTS 0x0001 -#define AR9170_TX_MAC_PROT_CTS 0x0002 - -#define AR9170_TX_MAC_NO_ACK 0x0004 -/* if unset, MAC will only do SIFS space before frame */ -#define AR9170_TX_MAC_BACKOFF 0x0008 -#define AR9170_TX_MAC_BURST 0x0010 -#define AR9170_TX_MAC_AGGR 0x0020 - -/* encryption is a two-bit field */ -#define AR9170_TX_MAC_ENCR_NONE 0x0000 -#define AR9170_TX_MAC_ENCR_RC4 0x0040 -#define AR9170_TX_MAC_ENCR_CENC 0x0080 -#define AR9170_TX_MAC_ENCR_AES 0x00c0 - -#define AR9170_TX_MAC_MMIC 0x0100 -#define AR9170_TX_MAC_HW_DURATION 0x0200 -#define AR9170_TX_MAC_QOS_SHIFT 10 -#define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) -#define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 -#define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 -#define AR9170_TX_MAC_DISABLE_TXOP 0x1000 -#define AR9170_TX_MAC_TXOP_RIFS 0x2000 -#define AR9170_TX_MAC_IMM_AMPDU 0x4000 -#define AR9170_TX_MAC_RATE_PROBE 0x8000 - -/* either-or */ -#define AR9170_TX_PHY_MOD_CCK 0x00000000 -#define AR9170_TX_PHY_MOD_OFDM 0x00000001 -#define AR9170_TX_PHY_MOD_HT 0x00000002 - -/* depends on modulation */ -#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 -#define AR9170_TX_PHY_GREENFIELD 0x00000004 - -#define AR9170_TX_PHY_BW_SHIFT 3 -#define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) -#define AR9170_TX_PHY_BW_20MHZ 0 -#define AR9170_TX_PHY_BW_40MHZ 2 -#define AR9170_TX_PHY_BW_40MHZ_DUP 3 - -#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 -#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) - -#define AR9170_TX_PHY_TX_PWR_SHIFT 9 -#define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) - -/* not part of the hw-spec */ -#define AR9170_TX_PHY_QOS_SHIFT 25 -#define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) - -#define AR9170_TX_PHY_TXCHAIN_SHIFT 15 -#define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) -#define AR9170_TX_PHY_TXCHAIN_1 1 -/* use for cck, ofdm 6/9/12/18/24 and HT if capable */ -#define AR9170_TX_PHY_TXCHAIN_2 5 - -#define AR9170_TX_PHY_MCS_SHIFT 18 -#define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) - -#define AR9170_TX_PHY_SHORT_GI 0x80000000 - -struct ar9170_rx_head { - u8 plcp[12]; -} __packed; - -struct ar9170_rx_tail { - union { - struct { - u8 rssi_ant0, rssi_ant1, rssi_ant2, - rssi_ant0x, rssi_ant1x, rssi_ant2x, - rssi_combined; - } __packed; - u8 rssi[7]; - } __packed; - - u8 evm_stream0[6], evm_stream1[6]; - u8 phy_err; - u8 SAidx, DAidx; - u8 error; - u8 status; -} __packed; - -#define AR9170_ENC_ALG_NONE 0x0 -#define AR9170_ENC_ALG_WEP64 0x1 -#define AR9170_ENC_ALG_TKIP 0x2 -#define AR9170_ENC_ALG_AESCCMP 0x4 -#define AR9170_ENC_ALG_WEP128 0x5 -#define AR9170_ENC_ALG_WEP256 0x6 -#define AR9170_ENC_ALG_CENC 0x7 - -#define AR9170_RX_ENC_SOFTWARE 0x8 - -static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) -{ - return (t->SAidx & 0xc0) >> 4 | - (t->DAidx & 0xc0) >> 6; -} - -#define AR9170_RX_STATUS_MODULATION_MASK 0x03 -#define AR9170_RX_STATUS_MODULATION_CCK 0x00 -#define AR9170_RX_STATUS_MODULATION_OFDM 0x01 -#define AR9170_RX_STATUS_MODULATION_HT 0x02 -#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 - -/* depends on modulation */ -#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 -#define AR9170_RX_STATUS_GREENFIELD 0x08 - -#define AR9170_RX_STATUS_MPDU_MASK 0x30 -#define AR9170_RX_STATUS_MPDU_SINGLE 0x00 -#define AR9170_RX_STATUS_MPDU_FIRST 0x10 -#define AR9170_RX_STATUS_MPDU_MIDDLE 0x20 -#define AR9170_RX_STATUS_MPDU_LAST 0x30 - - -#define AR9170_RX_ERROR_RXTO 0x01 -#define AR9170_RX_ERROR_OVERRUN 0x02 -#define AR9170_RX_ERROR_DECRYPT 0x04 -#define AR9170_RX_ERROR_FCS 0x08 -#define AR9170_RX_ERROR_WRONG_RA 0x10 -#define AR9170_RX_ERROR_PLCP 0x20 -#define AR9170_RX_ERROR_MMIC 0x40 - -struct ar9170_cmd_tx_status { - __le16 unkn; - u8 dst[ETH_ALEN]; - __le32 rate; - __le16 status; -} __packed; - -#define AR9170_TX_STATUS_COMPLETE 0x00 -#define AR9170_TX_STATUS_RETRY 0x01 -#define AR9170_TX_STATUS_FAILED 0x02 - -struct ar9170_cmd_ba_failed_count { - __le16 failed; - __le16 rate; -} __packed; - -struct ar9170_cmd_response { - u8 flag; - u8 type; - - union { - struct ar9170_cmd_tx_status tx_status; - struct ar9170_cmd_ba_failed_count ba_fail_cnt; - u8 data[0]; - }; -} __packed; - -/* QoS */ - -/* mac80211 queue to HW/FW map */ -static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; - -/* HW/FW queue to mac80211 map */ -static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; - -enum ar9170_txq { - AR9170_TXQ_BE, - AR9170_TXQ_BK, - AR9170_TXQ_VI, - AR9170_TXQ_VO, - - __AR9170_NUM_TXQ, -}; - -#endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ar9170/led.c b/drivers/net/wireless/ar9170/led.c deleted file mode 100644 index 341cead..0000000 --- a/drivers/net/wireless/ar9170/led.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Atheros AR9170 driver - * - * LED handling - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ar9170.h" -#include "cmd.h" - -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) -{ - return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); -} - -int ar9170_init_leds(struct ar9170 *ar) -{ - int err; - - /* disable LEDs */ - /* GPIO [0/1 mode: output, 2/3: input] */ - err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); - if (err) - goto out; - - /* GPIO 0/1 value: off */ - err = ar9170_set_leds_state(ar, 0); - -out: - return err; -} - -#ifdef CONFIG_AR9170_LEDS -static void ar9170_update_leds(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); - int i, tmp, blink_delay = 1000; - u32 led_val = 0; - bool rerun = false; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return ; - - mutex_lock(&ar->mutex); - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].toggled) { - led_val |= 1 << i; - - tmp = 70 + 200 / (ar->leds[i].toggled); - if (tmp < blink_delay) - blink_delay = tmp; - - if (ar->leds[i].toggled > 1) - ar->leds[i].toggled = 0; - - rerun = true; - } - - ar9170_set_leds_state(ar, led_val); - mutex_unlock(&ar->mutex); - - if (rerun) - queue_delayed_work(ar->hw->workqueue, &ar->led_work, - msecs_to_jiffies(blink_delay)); -} - -static void ar9170_led_brightness_set(struct led_classdev *led, - enum led_brightness brightness) -{ - struct ar9170_led *arl = container_of(led, struct ar9170_led, l); - struct ar9170 *ar = arl->ar; - - arl->toggled++; - - if (likely(IS_ACCEPTING_CMD(ar) && brightness)) - queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); -} - -static int ar9170_register_led(struct ar9170 *ar, int i, char *name, - char *trigger) -{ - int err; - - snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), - "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); - - ar->leds[i].ar = ar; - ar->leds[i].l.name = ar->leds[i].name; - ar->leds[i].l.brightness_set = ar9170_led_brightness_set; - ar->leds[i].l.brightness = 0; - ar->leds[i].l.default_trigger = trigger; - - err = led_classdev_register(wiphy_dev(ar->hw->wiphy), - &ar->leds[i].l); - if (err) - printk(KERN_ERR "%s: failed to register %s LED (%d).\n", - wiphy_name(ar->hw->wiphy), ar->leds[i].name, err); - else - ar->leds[i].registered = true; - - return err; -} - -void ar9170_unregister_leds(struct ar9170 *ar) -{ - int i; - - cancel_delayed_work_sync(&ar->led_work); - - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].registered) { - led_classdev_unregister(&ar->leds[i].l); - ar->leds[i].registered = false; - } -} - -int ar9170_register_leds(struct ar9170 *ar) -{ - int err; - - INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); - - err = ar9170_register_led(ar, 0, "tx", - ieee80211_get_tx_led_name(ar->hw)); - if (err) - goto fail; - - err = ar9170_register_led(ar, 1, "assoc", - ieee80211_get_assoc_led_name(ar->hw)); - if (err) - goto fail; - - return 0; - -fail: - ar9170_unregister_leds(ar); - return err; -} - -#endif /* CONFIG_AR9170_LEDS */ diff --git a/drivers/net/wireless/ar9170/mac.c b/drivers/net/wireless/ar9170/mac.c deleted file mode 100644 index c8fa307..0000000 --- a/drivers/net/wireless/ar9170/mac.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Atheros AR9170 driver - * - * MAC programming - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include "ar9170.h" -#include "cmd.h" - -int ar9170_set_qos(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | - (ar->edcf[0].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | - (ar->edcf[1].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | - (ar->edcf[2].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | - (ar->edcf[3].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | - (ar->edcf[4].cw_max << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, - ((ar->edcf[0].aifs * 9 + 10)) | - ((ar->edcf[1].aifs * 9 + 10) << 12) | - ((ar->edcf[2].aifs * 9 + 10) << 24)); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, - ((ar->edcf[2].aifs * 9 + 10) >> 8) | - ((ar->edcf[3].aifs * 9 + 10) << 4) | - ((ar->edcf[4].aifs * 9 + 10) << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, - ar->edcf[0].txop | ar->edcf[1].txop << 16); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, - ar->edcf[1].txop | ar->edcf[3].txop << 16); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_init_mac(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); - - ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); - - /* enable MMIC */ - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, - AR9170_MAC_REG_SNIFFER_DEFAULTS); - - ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); - - ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); - ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); - - /* CF-END mode */ - ar9170_regwrite(0x1c3b2c, 0x19000000); - - /* NAV protects ACK only (in TXOP) */ - ar9170_regwrite(0x1c3b38, 0x201); - - /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ - /* OTUS set AM to 0x1 */ - ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); - - ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); - - /* AGG test code*/ - /* Aggregation MAX number and timeout */ - ar9170_regwrite(0x1c3b9c, 0x10000a); - - ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, - AR9170_MAC_REG_FTF_DEFAULTS); - - /* Enable deaggregator, response in sniffer mode */ - ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); - - /* rate sets */ - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); - - /* MIMO response control */ - ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ - - /* switch MAC to OTUS interface */ - ar9170_regwrite(0x1c3600, 0x3); - - ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); - - /* set PHY register read timeout (??) */ - ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); - - /* Disable Rx TimeOut, workaround for BB. */ - ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); - - /* Set CPU clock frequency to 88/80MHz */ - ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, - AR9170_PWR_CLK_AHB_80_88MHZ | - AR9170_PWR_CLK_DAC_160_INV_DLY); - - /* Set WLAN DMA interrupt mode: generate int per packet */ - ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); - - ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, - AR9170_MAC_FCS_FIFO_PROT); - - /* Disables the CF_END frame, undocumented register */ - ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, - 0x141E0F48); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) -{ - static const u8 zero[ETH_ALEN] = { 0 }; - - if (!mac) - mac = zero; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(reg, - (mac[3] << 24) | (mac[2] << 16) | - (mac[1] << 8) | mac[0]); - - ar9170_regwrite(reg + 4, (mac[5] << 8) | mac[4]); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_update_multicast(struct ar9170 *ar) -{ - int err; - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, - ar->want_mc_hash >> 32); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, - ar->want_mc_hash); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - - if (err) - return err; - - ar->cur_mc_hash = ar->want_mc_hash; - - return 0; -} - -int ar9170_update_frame_filter(struct ar9170 *ar) -{ - int err; - - err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, - ar->want_filter); - - if (err) - return err; - - ar->cur_filter = ar->want_filter; - - return 0; -} - -static int ar9170_set_promiscouous(struct ar9170 *ar) -{ - u32 encr_mode, sniffer; - int err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); - if (err) - return err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); - if (err) - return err; - - if (ar->sniffer_enabled) { - sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - /* - * Rx decryption works in place. - * - * If we don't disable it, the hardware will render all - * encrypted frames which are encrypted with an unknown - * key useless. - */ - - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - ar->sniffer_enabled = true; - } else { - sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - if (ar->rx_software_decryption) - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - else - encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_operating_mode(struct ar9170 *ar) -{ - u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; - u8 *mac_addr, *bssid; - int err; - - if (ar->vif) { - mac_addr = ar->mac_addr; - bssid = ar->bssid; - - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; - break; -/* case NL80211_IFTYPE_AP: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP; - break;*/ - case NL80211_IFTYPE_WDS: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; - break; - case NL80211_IFTYPE_MONITOR: - ar->sniffer_enabled = true; - ar->rx_software_decryption = true; - break; - default: - pm_mode |= AR9170_MAC_REG_POWERMGT_STA; - break; - } - } else { - mac_addr = NULL; - bssid = NULL; - } - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); - if (err) - return err; - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); - if (err) - return err; - - err = ar9170_set_promiscouous(ar); - if (err) - return err; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) -{ - u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); - - return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); -} - -int ar9170_set_beacon_timers(struct ar9170 *ar) -{ - u32 v = 0; - u32 pretbtt = 0; - - v |= ar->hw->conf.beacon_int; - - if (ar->vif) { - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - v |= BIT(25); - break; - case NL80211_IFTYPE_AP: - v |= BIT(24); - pretbtt = (ar->hw->conf.beacon_int - 6) << 16; - break; - default: - break; - } - - v |= ar->vif->bss_conf.dtim_period << 16; - } - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); - ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -int ar9170_update_beacon(struct ar9170 *ar) -{ - struct sk_buff *skb; - __le32 *data, *old = NULL; - u32 word; - int i; - - skb = ieee80211_beacon_get(ar->hw, ar->vif); - if (!skb) - return -ENOMEM; - - data = (__le32 *)skb->data; - if (ar->beacon) - old = (__le32 *)ar->beacon->data; - - ar9170_regwrite_begin(ar); - for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { - /* - * XXX: This accesses beyond skb data for up - * to the last 3 bytes!! - */ - - if (old && (data[i] == old[i])) - continue; - - word = le32_to_cpu(data[i]); - ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); - } - - /* XXX: use skb->cb info */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); - else - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); - - ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); - ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); - ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); - - ar9170_regwrite_finish(); - - dev_kfree_skb(ar->beacon); - ar->beacon = skb; - - return ar9170_regwrite_result(); -} - -void ar9170_new_beacon(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - beacon_work); - struct sk_buff *skb; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - - if (!ar->vif) - goto out; - - ar9170_update_beacon(ar); - - rcu_read_lock(); - while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) - ar9170_op_tx(ar->hw, skb); - - rcu_read_unlock(); - - out: - mutex_unlock(&ar->mutex); -} - -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen) -{ - __le32 vals[7]; - static const u8 bcast[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - u8 dummy; - - mac = mac ? : bcast; - - vals[0] = cpu_to_le32((keyidx << 16) + id); - vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); - vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | - mac[3] << 8 | mac[2]); - memset(&vals[3], 0, 16); - if (keydata) - memcpy(&vals[3], keydata, keylen); - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(vals), (u8 *)vals, - 1, &dummy); -} - -int ar9170_disable_key(struct ar9170 *ar, u8 id) -{ - __le32 val = cpu_to_le32(id); - u8 dummy; - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(val), (u8 *)&val, - 1, &dummy); -} diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ar9170/main.c deleted file mode 100644 index 8de0ff9..0000000 --- a/drivers/net/wireless/ar9170/main.c +++ /dev/null @@ -1,1690 +0,0 @@ -/* - * Atheros AR9170 driver - * - * mac80211 interaction code - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include "ar9170.h" -#include "hw.h" -#include "cmd.h" - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); - -#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate) | (_txpidx) << 4, \ -} - -static struct ieee80211_rate __ar9170_ratetable[] = { - RATE(10, 0, 0, 0), - RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0xb, 0, 0), - RATE(90, 0xf, 0, 0), - RATE(120, 0xa, 0, 0), - RATE(180, 0xe, 0, 0), - RATE(240, 0x9, 0, 0), - RATE(360, 0xd, 1, 0), - RATE(480, 0x8, 2, 0), - RATE(540, 0xc, 3, 0), -}; -#undef RATE - -#define ar9170_g_ratetable (__ar9170_ratetable + 0) -#define ar9170_g_ratetable_size 12 -#define ar9170_a_ratetable (__ar9170_ratetable + 4) -#define ar9170_a_ratetable_size 8 - -/* - * NB: The hw_value is used as an index into the ar9170_phy_freq_params - * array in phy.c so that we don't have to do frequency lookups! - */ -#define CHAN(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 18, /* XXX */ \ -} - -static struct ieee80211_channel ar9170_2ghz_chantable[] = { - CHAN(2412, 0), - CHAN(2417, 1), - CHAN(2422, 2), - CHAN(2427, 3), - CHAN(2432, 4), - CHAN(2437, 5), - CHAN(2442, 6), - CHAN(2447, 7), - CHAN(2452, 8), - CHAN(2457, 9), - CHAN(2462, 10), - CHAN(2467, 11), - CHAN(2472, 12), - CHAN(2484, 13), -}; - -static struct ieee80211_channel ar9170_5ghz_chantable[] = { - CHAN(4920, 14), - CHAN(4940, 15), - CHAN(4960, 16), - CHAN(4980, 17), - CHAN(5040, 18), - CHAN(5060, 19), - CHAN(5080, 20), - CHAN(5180, 21), - CHAN(5200, 22), - CHAN(5220, 23), - CHAN(5240, 24), - CHAN(5260, 25), - CHAN(5280, 26), - CHAN(5300, 27), - CHAN(5320, 28), - CHAN(5500, 29), - CHAN(5520, 30), - CHAN(5540, 31), - CHAN(5560, 32), - CHAN(5580, 33), - CHAN(5600, 34), - CHAN(5620, 35), - CHAN(5640, 36), - CHAN(5660, 37), - CHAN(5680, 38), - CHAN(5700, 39), - CHAN(5745, 40), - CHAN(5765, 41), - CHAN(5785, 42), - CHAN(5805, 43), - CHAN(5825, 44), - CHAN(5170, 45), - CHAN(5190, 46), - CHAN(5210, 47), - CHAN(5230, 48), -}; -#undef CHAN - -static struct ieee80211_supported_band ar9170_band_2GHz = { - .channels = ar9170_2ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), - .bitrates = ar9170_g_ratetable, - .n_bitrates = ar9170_g_ratetable_size, -}; - -#ifdef AR9170_QUEUE_DEBUG -/* - * In case some wants works with AR9170's crazy tx_status queueing techniques. - * He might need this rather useful probing function. - * - * NOTE: caller must hold the queue's spinlock! - */ - -static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; - - printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " - "mac_control:%04x, phy_control:%08x]\n", - wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), - le32_to_cpu(txc->phy_control)); -} - -static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - struct sk_buff *skb; - int i = 0; - - printk(KERN_DEBUG "---[ cut here ]---\n"); - printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", - wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); - - skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; - - printk(KERN_DEBUG "index:%d => \n", i); - ar9170_print_txheader(ar, skb); - } - printk(KERN_DEBUG "---[ end ]---\n"); -} -#endif /* AR9170_QUEUE_DEBUG */ - -static struct ieee80211_supported_band ar9170_band_5GHz = { - .channels = ar9170_5ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), - .bitrates = ar9170_a_ratetable, - .n_bitrates = ar9170_a_ratetable_size, -}; - -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool valid_status, u16 tx_status) -{ - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0, queue = skb_get_queue_mapping(skb); - unsigned long flags; - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - if (ieee80211_queue_stopped(ar->hw, queue)) - ieee80211_wake_queue(ar->hw, queue); - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - txinfo = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(txinfo); - - switch (tx_status) { - case AR9170_TX_STATUS_RETRY: - retries = 2; - case AR9170_TX_STATUS_COMPLETE: - txinfo->flags |= IEEE80211_TX_STAT_ACK; - break; - - case AR9170_TX_STATUS_FAILED: - retries = ar->hw->conf.long_frame_max_tx_count; - break; - - default: - printk(KERN_ERR "%s: invalid tx_status response (%x).\n", - wiphy_name(ar->hw->wiphy), tx_status); - break; - } - - if (valid_status) - txinfo->status.rates[0].count = retries + 1; - - skb_pull(skb, sizeof(struct ar9170_tx_control)); - ieee80211_tx_status_irqsafe(ar->hw, skb); -} - -static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, - const u8 *mac, - const u32 queue, - struct sk_buff_head *q) -{ - unsigned long flags; - struct sk_buff *skb; - - spin_lock_irqsave(&q->lock, flags); - skb_queue_walk(q, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 txc_queue = (le32_to_cpu(txc->phy_control) & - AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; - - if ((queue != txc_queue) || - (compare_ether_addr(ieee80211_get_DA(hdr), mac))) - continue; - - __skb_unlink(skb, q); - spin_unlock_irqrestore(&q->lock, flags); - return skb; - } - spin_unlock_irqrestore(&q->lock, flags); - return NULL; -} - -static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, - const u32 queue) -{ - struct ieee80211_sta *sta; - struct sk_buff *skb; - - /* - * Unfortunately, the firmware does not tell to which (queued) frame - * this transmission status report belongs to. - * - * So we have to make risky guesses - with the scarce information - * the firmware provided (-> destination MAC, and phy_control) - - * and hope that we picked the right one... - */ - rcu_read_lock(); - sta = ieee80211_find_sta(ar->hw, mac); - - if (likely(sta)) { - struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; - skb = skb_dequeue(&sta_priv->tx_status[queue]); - rcu_read_unlock(); - if (likely(skb)) - return skb; - } else - rcu_read_unlock(); - - /* scan the waste queue for candidates */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status_waste); - if (!skb) { - /* so it still _must_ be in the global list. */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status); - } - -#ifdef AR9170_QUEUE_DEBUG - if (unlikely((!skb) && net_ratelimit())) { - printk(KERN_ERR "%s: ESS:[%pM] does not have any " - "outstanding frames in this queue (%d).\n", - wiphy_name(ar->hw->wiphy), mac, queue); - } -#endif /* AR9170_QUEUE_DEBUG */ - return skb; -} - -/* - * This worker tries to keep the global tx_status queue empty. - * So we can guarantee that incoming tx_status reports for - * unregistered stations are always synced with the actual - * frame - which we think - belongs to. - */ - -static void ar9170_tx_status_janitor(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - tx_status_janitor.work); - struct sk_buff *skb; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - /* recycle the garbage back to mac80211... one by one. */ - while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: dispose queued frame =>\n", - wiphy_name(ar->hw->wiphy)); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - ar9170_handle_tx_status(ar, skb, false, - AR9170_TX_STATUS_FAILED); - } - - while ((skb = skb_dequeue(&ar->global_tx_status))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", - wiphy_name(ar->hw->wiphy)); - - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status_waste, skb); - } - - /* recall the janitor in 100ms - if there's garbage in the can. */ - if (skb_queue_len(&ar->global_tx_status_waste) > 0) - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - - mutex_unlock(&ar->mutex); -} - -static void ar9170_handle_command_response(struct ar9170 *ar, - void *buf, u32 len) -{ - struct ar9170_cmd_response *cmd = (void *) buf; - - if ((cmd->type & 0xc0) != 0xc0) { - ar->callback_cmd(ar, len, buf); - return; - } - - /* hardware event handlers */ - switch (cmd->type) { - case 0xc1: { - /* - * TX status notification: - * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 - * - * XX always 81 - * YY always 00 - * M1-M6 is the MAC address - * R1-R4 is the transmit rate - * S1-S2 is the transmit status - */ - - struct sk_buff *skb; - u32 queue = (le32_to_cpu(cmd->tx_status.rate) & - AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; - - skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); - if (unlikely(!skb)) - return ; - - ar9170_handle_tx_status(ar, skb, true, - le16_to_cpu(cmd->tx_status.status)); - break; - } - - case 0xc0: - /* - * pre-TBTT event - */ - if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) - queue_work(ar->hw->workqueue, &ar->beacon_work); - break; - - case 0xc2: - /* - * (IBSS) beacon send notification - * bytes: 04 c2 XX YY B4 B3 B2 B1 - * - * XX always 80 - * YY always 00 - * B1-B4 "should" be the number of send out beacons. - */ - break; - - case 0xc3: - /* End of Atim Window */ - break; - - case 0xc4: - case 0xc5: - /* BlockACK events */ - break; - - case 0xc6: - /* Watchdog Interrupt */ - break; - - case 0xc9: - /* retransmission issue / SIFS/EIFS collision ?! */ - break; - - default: - printk(KERN_INFO "received unhandled event %x\n", cmd->type); - print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); - break; - } -} - -/* - * If the frame alignment is right (or the kernel has - * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there - * is only a single MPDU in the USB frame, then we can - * submit to mac80211 the SKB directly. However, since - * there may be multiple packets in one SKB in stream - * mode, and we need to observe the proper ordering, - * this is non-trivial. - */ -static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) -{ - struct sk_buff *skb; - struct ar9170_rx_head *head = (void *)buf; - struct ar9170_rx_tail *tail; - struct ieee80211_rx_status status; - int mpdu_len, i; - u8 error, antennas = 0, decrypt; - __le16 fc; - int reserved; - - if (unlikely(!IS_STARTED(ar))) - return ; - - /* Received MPDU */ - mpdu_len = len; - mpdu_len -= sizeof(struct ar9170_rx_head); - mpdu_len -= sizeof(struct ar9170_rx_tail); - BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); - BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24); - - if (mpdu_len <= FCS_LEN) - return; - - tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len); - - for (i = 0; i < 3; i++) - if (tail->rssi[i] != 0x80) - antennas |= BIT(i); - - /* post-process RSSI */ - for (i = 0; i < 7; i++) - if (tail->rssi[i] & 0x80) - tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f; - - memset(&status, 0, sizeof(status)); - - status.band = ar->channel->band; - status.freq = ar->channel->center_freq; - status.signal = ar->noise[0] + tail->rssi_combined; - status.noise = ar->noise[0]; - status.antenna = antennas; - - switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) { - case AR9170_RX_STATUS_MODULATION_CCK: - if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE) - status.flag |= RX_FLAG_SHORTPRE; - switch (head->plcp[0]) { - case 0x0a: - status.rate_idx = 0; - break; - case 0x14: - status.rate_idx = 1; - break; - case 0x37: - status.rate_idx = 2; - break; - case 0x6e: - status.rate_idx = 3; - break; - default: - if ((!ar->sniffer_enabled) && (net_ratelimit())) - printk(KERN_ERR "%s: invalid plcp cck rate " - "(%x).\n", wiphy_name(ar->hw->wiphy), - head->plcp[0]); - return; - } - break; - case AR9170_RX_STATUS_MODULATION_OFDM: - switch (head->plcp[0] & 0xF) { - case 0xB: - status.rate_idx = 0; - break; - case 0xF: - status.rate_idx = 1; - break; - case 0xA: - status.rate_idx = 2; - break; - case 0xE: - status.rate_idx = 3; - break; - case 0x9: - status.rate_idx = 4; - break; - case 0xD: - status.rate_idx = 5; - break; - case 0x8: - status.rate_idx = 6; - break; - case 0xC: - status.rate_idx = 7; - break; - default: - if ((!ar->sniffer_enabled) && (net_ratelimit())) - printk(KERN_ERR "%s: invalid plcp ofdm rate " - "(%x).\n", wiphy_name(ar->hw->wiphy), - head->plcp[0]); - return; - } - if (status.band == IEEE80211_BAND_2GHZ) - status.rate_idx += 4; - break; - case AR9170_RX_STATUS_MODULATION_HT: - case AR9170_RX_STATUS_MODULATION_DUPOFDM: - /* XXX */ - - if (net_ratelimit()) - printk(KERN_ERR "%s: invalid modulation\n", - wiphy_name(ar->hw->wiphy)); - return; - } - - error = tail->error; - - if (error & AR9170_RX_ERROR_MMIC) { - status.flag |= RX_FLAG_MMIC_ERROR; - error &= ~AR9170_RX_ERROR_MMIC; - } - - if (error & AR9170_RX_ERROR_PLCP) { - status.flag |= RX_FLAG_FAILED_PLCP_CRC; - error &= ~AR9170_RX_ERROR_PLCP; - } - - if (error & AR9170_RX_ERROR_FCS) { - status.flag |= RX_FLAG_FAILED_FCS_CRC; - error &= ~AR9170_RX_ERROR_FCS; - } - - decrypt = ar9170_get_decrypt_type(tail); - if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && - decrypt != AR9170_ENC_ALG_NONE) - status.flag |= RX_FLAG_DECRYPTED; - - /* ignore wrong RA errors */ - error &= ~AR9170_RX_ERROR_WRONG_RA; - - if (error & AR9170_RX_ERROR_DECRYPT) { - error &= ~AR9170_RX_ERROR_DECRYPT; - - /* - * Rx decryption is done in place, - * the original data is lost anyway. - */ - return ; - } - - /* drop any other error frames */ - if ((error) && (net_ratelimit())) { - printk(KERN_DEBUG "%s: errors: %#x\n", - wiphy_name(ar->hw->wiphy), error); - return; - } - - buf += sizeof(struct ar9170_rx_head); - fc = *(__le16 *)buf; - - if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc)) - reserved = 32 + 2; - else - reserved = 32; - - skb = dev_alloc_skb(mpdu_len + reserved); - if (!skb) - return; - - skb_reserve(skb, reserved); - memcpy(skb_put(skb, mpdu_len), buf, mpdu_len); - ieee80211_rx_irqsafe(ar->hw, skb, &status); -} - -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) -{ - unsigned int i, tlen, resplen; - u8 *tbuf, *respbuf; - - tbuf = skb->data; - tlen = skb->len; - - while (tlen >= 4) { - int clen = tbuf[1] << 8 | tbuf[0]; - int wlen = (clen + 3) & ~3; - - /* - * parse stream (if any) - */ - if (tbuf[2] != 0 || tbuf[3] != 0x4e) { - printk(KERN_ERR "%s: missing tag!\n", - wiphy_name(ar->hw->wiphy)); - return ; - } - if (wlen > tlen - 4) { - printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n", - wiphy_name(ar->hw->wiphy), clen, wlen, tlen); - print_hex_dump(KERN_DEBUG, "data: ", - DUMP_PREFIX_OFFSET, - 16, 1, tbuf, tlen, true); - return ; - } - resplen = clen; - respbuf = tbuf + 4; - tbuf += wlen + 4; - tlen -= wlen + 4; - - i = 0; - - /* weird thing, but this is the same in the original driver */ - while (resplen > 2 && i < 12 && - respbuf[0] == 0xff && respbuf[1] == 0xff) { - i += 2; - resplen -= 2; - respbuf += 2; - } - - if (resplen < 4) - continue; - - /* found the 6 * 0xffff marker? */ - if (i == 12) - ar9170_handle_command_response(ar, respbuf, resplen); - else - ar9170_handle_mpdu(ar, respbuf, resplen); - } - - if (tlen) - printk(KERN_ERR "%s: buffer remains!\n", - wiphy_name(ar->hw->wiphy)); -} - -#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ -do { \ - queue.aifs = ai_fs; \ - queue.cw_min = cwmin; \ - queue.cw_max = cwmax; \ - queue.txop = _txop; \ -} while (0) - -static int ar9170_op_start(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err, i; - - mutex_lock(&ar->mutex); - - /* reinitialize queues statistics */ - memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) - ar->tx_stats[i].limit = 8; - - /* reset QoS defaults */ - AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ - AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ - AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ - AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ - AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ - - err = ar->open(ar); - if (err) - goto out; - - err = ar9170_init_mac(ar); - if (err) - goto out; - - err = ar9170_set_qos(ar); - if (err) - goto out; - - err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); - if (err) - goto out; - - err = ar9170_init_rf(ar); - if (err) - goto out; - - /* start DMA */ - err = ar9170_write_reg(ar, 0x1c3d30, 0x100); - if (err) - goto out; - - ar->state = AR9170_STARTED; - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_stop(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - - if (IS_STARTED(ar)) - ar->state = AR9170_IDLE; - - flush_workqueue(ar->hw->workqueue); - - mutex_lock(&ar->mutex); - cancel_delayed_work_sync(&ar->tx_status_janitor); - cancel_work_sync(&ar->filter_config_work); - cancel_work_sync(&ar->beacon_work); - skb_queue_purge(&ar->global_tx_status_waste); - skb_queue_purge(&ar->global_tx_status); - - if (IS_ACCEPTING_CMD(ar)) { - ar9170_set_leds_state(ar, 0); - - /* stop DMA */ - ar9170_write_reg(ar, 0x1c3d30, 0); - ar->stop(ar); - } - - mutex_unlock(&ar->mutex); -} - -int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ar9170 *ar = hw->priv; - struct ieee80211_hdr *hdr; - struct ar9170_tx_control *txc; - struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; - struct ieee80211_tx_rate *txrate; - unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags = 0; - struct ar9170_sta_info *sta_info = NULL; - u32 power, chains; - u16 keytype = 0; - u16 len, icv = 0; - int err; - bool tx_status; - - if (unlikely(!IS_STARTED(ar))) - goto err_free; - - hdr = (void *)skb->data; - info = IEEE80211_SKB_CB(skb); - len = skb->len; - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - return NETDEV_TX_OK; - } - - ar->tx_stats[queue].len++; - ar->tx_stats[queue].count++; - if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) - ieee80211_stop_queue(hw, queue); - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - txc = (void *)skb_push(skb, sizeof(*txc)); - - tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || - ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); - - if (info->control.hw_key) { - icv = info->control.hw_key->icv_len; - - switch (info->control.hw_key->alg) { - case ALG_WEP: - keytype = AR9170_TX_MAC_ENCR_RC4; - break; - case ALG_TKIP: - keytype = AR9170_TX_MAC_ENCR_RC4; - break; - case ALG_CCMP: - keytype = AR9170_TX_MAC_ENCR_AES; - break; - default: - WARN_ON(1); - goto err_dequeue; - } - } - - /* Length */ - txc->length = cpu_to_le16(len + icv + 4); - - txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | - AR9170_TX_MAC_BACKOFF); - txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << - AR9170_TX_MAC_QOS_SHIFT); - txc->mac_control |= cpu_to_le16(keytype); - txc->phy_control = cpu_to_le32(0); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - - if (info->flags & IEEE80211_TX_CTL_AMPDU) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - - txrate = &info->control.rates[0]; - - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); - else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); - - if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); - - if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); - /* this works because 40 MHz is 2 and dup is 3 */ - if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); - - if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); - - if (txrate->flags & IEEE80211_TX_RC_MCS) { - u32 r = txrate->idx; - u8 *txpower; - - r <<= AR9170_TX_PHY_MCS_SHIFT; - if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) - goto err_dequeue; - txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht40; - else - txpower = ar->power_2G_ht40; - } else { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht20; - else - txpower = ar->power_2G_ht20; - } - - power = txpower[(txrate->idx) & 7]; - } else { - u8 *txpower; - u32 mod; - u32 phyrate; - u8 idx = txrate->idx; - - if (info->band != IEEE80211_BAND_2GHZ) { - idx += 4; - txpower = ar->power_5G_leg; - mod = AR9170_TX_PHY_MOD_OFDM; - } else { - if (idx < 4) { - txpower = ar->power_2G_cck; - mod = AR9170_TX_PHY_MOD_CCK; - } else { - mod = AR9170_TX_PHY_MOD_OFDM; - txpower = ar->power_2G_ofdm; - } - } - - rate = &__ar9170_ratetable[idx]; - - phyrate = rate->hw_value & 0xF; - power = txpower[(rate->hw_value & 0x30) >> 4]; - phyrate <<= AR9170_TX_PHY_MCS_SHIFT; - - txc->phy_control |= cpu_to_le32(mod); - txc->phy_control |= cpu_to_le32(phyrate); - } - - power <<= AR9170_TX_PHY_TX_PWR_SHIFT; - power &= AR9170_TX_PHY_TX_PWR_MASK; - txc->phy_control |= cpu_to_le32(power); - - /* set TX chains */ - if (ar->eeprom.tx_mask == 1) { - chains = AR9170_TX_PHY_TXCHAIN_1; - } else { - chains = AR9170_TX_PHY_TXCHAIN_2; - - /* >= 36M legacy OFDM - use only one chain */ - if (rate && rate->bitrate >= 360) - chains = AR9170_TX_PHY_TXCHAIN_1; - } - txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); - - if (tx_status) { - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ - - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); - - if (info->control.sta) { - sta_info = (void *) info->control.sta->drv_priv; - skb_queue_tail(&sta_info->tx_status[queue], skb); - } else { - skb_queue_tail(&ar->global_tx_status, skb); - - queue_delayed_work(ar->hw->workqueue, - &ar->tx_status_janitor, - msecs_to_jiffies(100)); - } - } - - err = ar->tx(ar, skb, tx_status, 0); - if (unlikely(tx_status && err)) { - if (info->control.sta) - skb_unlink(skb, &sta_info->tx_status[queue]); - else - skb_unlink(skb, &ar->global_tx_status); - } - - return NETDEV_TX_OK; - -err_dequeue: - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - ar->tx_stats[queue].count--; - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - -err_free: - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static int ar9170_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (ar->vif) { - err = -EBUSY; - goto unlock; - } - - ar->vif = conf->vif; - memcpy(ar->mac_addr, conf->mac_addr, ETH_ALEN); - - if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { - ar->rx_software_decryption = true; - ar->disable_offload = true; - } - - ar->cur_filter = 0; - ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS; - err = ar9170_update_frame_filter(ar); - if (err) - goto unlock; - - err = ar9170_set_operating_mode(ar); - -unlock: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct ar9170 *ar = hw->priv; - - mutex_lock(&ar->mutex); - ar->vif = NULL; - ar->want_filter = 0; - ar9170_update_frame_filter(ar); - ar9170_set_beacon_timers(ar); - dev_kfree_skb(ar->beacon); - ar->beacon = NULL; - ar->sniffer_enabled = false; - ar->rx_software_decryption = false; - ar9170_set_operating_mode(ar); - mutex_unlock(&ar->mutex); -} - -static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_PS) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - /* - * is it long_frame_max_tx_count or short_frame_max_tx_count? - */ - - err = ar9170_set_hwretry_limit(ar, - ar->hw->conf.long_frame_max_tx_count); - if (err) - goto out; - } - - if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - err = ar9170_set_channel(ar, hw->conf.channel, - AR9170_RFI_NONE, AR9170_BW_20); - if (err) - goto out; - /* adjust slot time for 5 GHz */ - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) - err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, - 9 << 10); - } - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static int ar9170_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (conf->changed & IEEE80211_IFCC_BSSID) { - memcpy(ar->bssid, conf->bssid, ETH_ALEN); - err = ar9170_set_operating_mode(ar); - } - - if (conf->changed & IEEE80211_IFCC_BEACON) { - err = ar9170_update_beacon(ar); - - if (err) - goto out; - err = ar9170_set_beacon_timers(ar); - } - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_set_filters(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - filter_config_work); - int err; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { - err = ar9170_set_operating_mode(ar); - if (err) - goto unlock; - } - - if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { - err = ar9170_update_multicast(ar); - if (err) - goto unlock; - } - - if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) - err = ar9170_update_frame_filter(ar); - -unlock: - mutex_unlock(&ar->mutex); -} - -static void ar9170_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) -{ - struct ar9170 *ar = hw->priv; - - /* mask supported flags */ - *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS; - - /* - * We can support more by setting the sniffer bit and - * then checking the error flags, later. - */ - - if (changed_flags & FIF_ALLMULTI) { - if (*new_flags & FIF_ALLMULTI) { - ar->want_mc_hash = ~0ULL; - } else { - u64 mchash; - int i; - - /* always get broadcast frames */ - mchash = 1ULL << (0xff>>2); - - for (i = 0; i < mc_count; i++) { - if (WARN_ON(!mclist)) - break; - mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); - mclist = mclist->next; - } - ar->want_mc_hash = mchash; - } - ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; - } - - if (changed_flags & FIF_CONTROL) { - u32 filter = AR9170_MAC_REG_FTF_PSPOLL | - AR9170_MAC_REG_FTF_RTS | - AR9170_MAC_REG_FTF_CTS | - AR9170_MAC_REG_FTF_ACK | - AR9170_MAC_REG_FTF_CFE | - AR9170_MAC_REG_FTF_CFE_ACK; - - if (*new_flags & FIF_CONTROL) - ar->want_filter = ar->cur_filter | filter; - else - ar->want_filter = ar->cur_filter & ~filter; - - ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; - } - - if (likely(IS_STARTED(ar))) - queue_work(ar->hw->workqueue, &ar->filter_config_work); -} - -static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - ar9170_regwrite_begin(ar); - - if (changed & BSS_CHANGED_ASSOC) { - ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; - -#ifndef CONFIG_AR9170_LEDS - /* enable assoc LED. */ - err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); -#endif /* CONFIG_AR9170_LEDS */ - } - - if (changed & BSS_CHANGED_HT) { - /* TODO */ - err = 0; - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - u32 slottime = 20; - - if (bss_conf->use_short_slot) - slottime = 9; - - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); - } - - if (changed & BSS_CHANGED_BASIC_RATES) { - u32 cck, ofdm; - - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { - ofdm = bss_conf->basic_rates; - cck = 0; - } else { - /* four cck rates */ - cck = bss_conf->basic_rates & 0xf; - ofdm = bss_conf->basic_rates >> 4; - } - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, - ofdm << 8 | cck); - } - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - mutex_unlock(&ar->mutex); -} - -static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err; - u32 tsf_low; - u32 tsf_high; - u64 tsf; - - mutex_lock(&ar->mutex); - err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_L, &tsf_low); - if (!err) - err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_H, &tsf_high); - mutex_unlock(&ar->mutex); - - if (WARN_ON(err)) - return 0; - - tsf = tsf_high; - tsf = (tsf << 32) | tsf_low; - return tsf; -} - -static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct ar9170 *ar = hw->priv; - int err = 0, i; - u8 ktype; - - if ((!ar->vif) || (ar->disable_offload)) - return -EOPNOTSUPP; - - switch (key->alg) { - case ALG_WEP: - if (key->keylen == LEN_WEP40) - ktype = AR9170_ENC_ALG_WEP64; - else - ktype = AR9170_ENC_ALG_WEP128; - break; - case ALG_TKIP: - ktype = AR9170_ENC_ALG_TKIP; - break; - case ALG_CCMP: - ktype = AR9170_ENC_ALG_AESCCMP; - break; - default: - return -EOPNOTSUPP; - } - - mutex_lock(&ar->mutex); - if (cmd == SET_KEY) { - if (unlikely(!IS_STARTED(ar))) { - err = -EOPNOTSUPP; - goto out; - } - - /* group keys need all-zeroes address */ - if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - sta = NULL; - - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - for (i = 0; i < 64; i++) - if (!(ar->usedkeys & BIT(i))) - break; - if (i == 64) { - ar->rx_software_decryption = true; - ar9170_set_operating_mode(ar); - err = -ENOSPC; - goto out; - } - } else { - i = 64 + key->keyidx; - } - - key->hw_key_idx = i; - - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, - key->key, min_t(u8, 16, key->keylen)); - if (err) - goto out; - - if (key->alg == ALG_TKIP) { - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, - ktype, 1, key->key + 16, 16); - if (err) - goto out; - - /* - * hardware is not capable generating the MMIC - * for fragmented frames! - */ - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - } - - if (i < 64) - ar->usedkeys |= BIT(i); - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - } else { - if (unlikely(!IS_STARTED(ar))) { - /* The device is gone... together with the key ;-) */ - err = 0; - goto out; - } - - err = ar9170_disable_key(ar, key->hw_key_idx); - if (err) - goto out; - - if (key->hw_key_idx < 64) { - ar->usedkeys &= ~BIT(key->hw_key_idx); - } else { - err = ar9170_upload_key(ar, key->hw_key_idx, NULL, - AR9170_ENC_ALG_NONE, 0, - NULL, 0); - if (err) - goto out; - - if (key->alg == ALG_TKIP) { - err = ar9170_upload_key(ar, key->hw_key_idx, - NULL, - AR9170_ENC_ALG_NONE, 1, - NULL, 0); - if (err) - goto out; - } - - } - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - -out: - mutex_unlock(&ar->mutex); - - return err; -} - -static void ar9170_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) -{ - struct ar9170 *ar = hw->priv; - struct ar9170_sta_info *info = (void *) sta->drv_priv; - struct sk_buff *skb; - unsigned int i; - - switch (cmd) { - case STA_NOTIFY_ADD: - for (i = 0; i < ar->hw->queues; i++) - skb_queue_head_init(&info->tx_status[i]); - break; - - case STA_NOTIFY_REMOVE: - - /* - * transfer all outstanding frames that need a tx_status - * reports to the global tx_status queue - */ - - for (i = 0; i < ar->hw->queues; i++) { - while ((skb = skb_dequeue(&info->tx_status[i]))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: queueing frame in " - "global tx_status queue =>\n", - wiphy_name(ar->hw->wiphy)); - - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status, skb); - } - } - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - break; - - default: - break; - } -} - -static int ar9170_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct ar9170 *ar = hw->priv; - u32 val; - int err; - - mutex_lock(&ar->mutex); - err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); - ar->stats.dot11ACKFailureCount += val; - - memcpy(stats, &ar->stats, sizeof(*stats)); - mutex_unlock(&ar->mutex); - - return 0; -} - -static int ar9170_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *tx_stats) -{ - struct ar9170 *ar = hw->priv; - - spin_lock_bh(&ar->tx_stats_lock); - memcpy(tx_stats, ar->tx_stats, sizeof(tx_stats[0]) * hw->queues); - spin_unlock_bh(&ar->tx_stats_lock); - - return 0; -} - -static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *param) -{ - struct ar9170 *ar = hw->priv; - int ret; - - mutex_lock(&ar->mutex); - if ((param) && !(queue > ar->hw->queues)) { - memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], - param, sizeof(*param)); - - ret = ar9170_set_qos(ar); - } else - ret = -EINVAL; - - mutex_unlock(&ar->mutex); - return ret; -} - -static const struct ieee80211_ops ar9170_ops = { - .start = ar9170_op_start, - .stop = ar9170_op_stop, - .tx = ar9170_op_tx, - .add_interface = ar9170_op_add_interface, - .remove_interface = ar9170_op_remove_interface, - .config = ar9170_op_config, - .config_interface = ar9170_op_config_interface, - .configure_filter = ar9170_op_configure_filter, - .conf_tx = ar9170_conf_tx, - .bss_info_changed = ar9170_op_bss_info_changed, - .get_tsf = ar9170_op_get_tsf, - .set_key = ar9170_set_key, - .sta_notify = ar9170_sta_notify, - .get_stats = ar9170_get_stats, - .get_tx_stats = ar9170_get_tx_stats, -}; - -void *ar9170_alloc(size_t priv_size) -{ - struct ieee80211_hw *hw; - struct ar9170 *ar; - int i; - - hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); - if (!hw) - return ERR_PTR(-ENOMEM); - - ar = hw->priv; - ar->hw = hw; - - mutex_init(&ar->mutex); - spin_lock_init(&ar->cmdlock); - spin_lock_init(&ar->tx_stats_lock); - skb_queue_head_init(&ar->global_tx_status); - skb_queue_head_init(&ar->global_tx_status_waste); - INIT_WORK(&ar->filter_config_work, ar9170_set_filters); - INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); - - /* all hw supports 2.4 GHz, so set channel to 1 by default */ - ar->channel = &ar9170_2ghz_chantable[0]; - - /* first part of wiphy init */ - ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_WDS) | - BIT(NL80211_IFTYPE_ADHOC); - ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - ar->hw->queues = __AR9170_NUM_TXQ; - ar->hw->extra_tx_headroom = 8; - ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); - - ar->hw->max_rates = 1; - ar->hw->max_rate_tries = 3; - - for (i = 0; i < ARRAY_SIZE(ar->noise); i++) - ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ - - return ar; -} - -static int ar9170_read_eeprom(struct ar9170 *ar) -{ -#define RW 8 /* number of words to read at once */ -#define RB (sizeof(u32) * RW) - DECLARE_MAC_BUF(mbuf); - u8 *eeprom = (void *)&ar->eeprom; - u8 *addr = ar->eeprom.mac_address; - __le32 offsets[RW]; - int i, j, err, bands = 0; - - BUILD_BUG_ON(sizeof(ar->eeprom) & 3); - - BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); -#ifndef __CHECKER__ - /* don't want to handle trailing remains */ - BUILD_BUG_ON(sizeof(ar->eeprom) % RB); -#endif - - for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { - for (j = 0; j < RW; j++) - offsets[j] = cpu_to_le32(AR9170_EEPROM_START + - RB * i + 4 * j); - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - RB, (u8 *) &offsets, - RB, eeprom + RB * i); - if (err) - return err; - } - -#undef RW -#undef RB - - if (ar->eeprom.length == cpu_to_le16(0xFFFF)) - return -ENODATA; - - if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; - bands++; - } - if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; - bands++; - } - /* - * I measured this, a bandswitch takes roughly - * 135 ms and a frequency switch about 80. - * - * FIXME: measure these values again once EEPROM settings - * are used, that will influence them! - */ - if (bands == 2) - ar->hw->channel_change_time = 135 * 1000; - else - ar->hw->channel_change_time = 80 * 1000; - - ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); - - /* second part of wiphy init */ - SET_IEEE80211_PERM_ADDR(ar->hw, addr); - - return bands ? 0 : -EINVAL; -} - -static int ar9170_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ar9170 *ar = hw->priv; - - return ath_reg_notifier_apply(wiphy, request, &ar->regulatory); -} - -int ar9170_register(struct ar9170 *ar, struct device *pdev) -{ - int err; - - /* try to read EEPROM, init MAC addr */ - err = ar9170_read_eeprom(ar); - if (err) - goto err_out; - - err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, - ar9170_reg_notifier); - - err = ieee80211_register_hw(ar->hw); - if (err) - goto err_out; - - if (!ath_is_world_regd(&ar->regulatory)) - regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2); - - err = ar9170_init_leds(ar); - if (err) - goto err_unreg; - -#ifdef CONFIG_AR9170_LEDS - err = ar9170_register_leds(ar); - if (err) - goto err_unreg; -#endif /* CONFIG_AR9170_LEDS */ - - dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", - wiphy_name(ar->hw->wiphy)); - - return err; - -err_unreg: - ieee80211_unregister_hw(ar->hw); - -err_out: - return err; -} - -void ar9170_unregister(struct ar9170 *ar) -{ -#ifdef CONFIG_AR9170_LEDS - ar9170_unregister_leds(ar); -#endif /* CONFIG_AR9170_LEDS */ - - ieee80211_unregister_hw(ar->hw); - mutex_destroy(&ar->mutex); -} diff --git a/drivers/net/wireless/ar9170/phy.c b/drivers/net/wireless/ar9170/phy.c deleted file mode 100644 index 6ce2075..0000000 --- a/drivers/net/wireless/ar9170/phy.c +++ /dev/null @@ -1,1240 +0,0 @@ -/* - * Atheros AR9170 driver - * - * PHY and RF code - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include "ar9170.h" -#include "cmd.h" - -static int ar9170_init_power_cal(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); - ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -struct ar9170_phy_init { - u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; -}; - -static struct ar9170_phy_init ar5416_phy_init[] = { - { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, - { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, - { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, - { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, - { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, - { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, - { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, - { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, - { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, - { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, - { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, - { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, - { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, - { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, - { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, - { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, - { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, - { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, - { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, - { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, - { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, - { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, - { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, - { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, - { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, - { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, - { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, - { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, - { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, - { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, - { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, - { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, - { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, - { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, - { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, - { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, - { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, - { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, - { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, - { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, - { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, - { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, - { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, - { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, - { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, - { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, - { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, - { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, - { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, - { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, - { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, - { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, - { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, - { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, - { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, - { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, - { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, - { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, - { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, - { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, - { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, - { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, - { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, - { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, - { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, - { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, - { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, - { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, - { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, - { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, - { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, - { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, - { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, - { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, - { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, - { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, - { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, - { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, - { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, - { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, - { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, - { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, - { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, - { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, - { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, - { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, - { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, - { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, - { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, - { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, - { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, - { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, - { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, - { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, - { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, - { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, - { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, - { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, - { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, - { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, - { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, - { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, - { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, - { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, - { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, - { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, - { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, - { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, - { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, - { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, - { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, - { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, - { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, - { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, - { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, - { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, - { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, - { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, - { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, - { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, - { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, - { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, - { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, - { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, - { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, - { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, - { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, - { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, - { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, - { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, - { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, - { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, - { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, - { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, - { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, - { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, - { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, - { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, - { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, - { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, - { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, - { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, - { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, - { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, - { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, - { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, - { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, - { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, - { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, - { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, - { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, - { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, - { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, - { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, - { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, - { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, - { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, -/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ - { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, - { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, - { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, - { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, - { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, - { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, - { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, - { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, - { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, - { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, - { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, - { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, - { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, - { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, - { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, - { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } -}; - -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) -{ - int i, err; - u32 val; - bool is_2ghz = band == IEEE80211_BAND_2GHZ; - bool is_40mhz = false; /* XXX: for now */ - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { - if (is_40mhz) { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_40; - else - val = ar5416_phy_init[i]._5ghz_40; - } else { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_20; - else - val = ar5416_phy_init[i]._5ghz_20; - } - - ar9170_regwrite(ar5416_phy_init[i].reg, val); - } - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - /* XXX: use EEPROM data here! */ - - err = ar9170_init_power_cal(ar); - if (err) - return err; - - /* XXX: remove magic! */ - if (is_2ghz) - err = ar9170_write_reg(ar, 0x1d4014, 0x5163); - else - err = ar9170_write_reg(ar, 0x1d4014, 0x5143); - - return err; -} - -struct ar9170_rf_init { - u32 reg, _5ghz, _2ghz; -}; - -static struct ar9170_rf_init ar9170_rf_init[] = { - /* bank 0 */ - { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, - { 0x1c58e0, 0x02008020, 0x02008020}, - /* bank 1 */ - { 0x1c58b0, 0x02108421, 0x02108421}, - { 0x1c58ec, 0x00000008, 0x00000008}, - /* bank 2 */ - { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, - { 0x1c58e0, 0x00000420, 0x00000420}, - /* bank 3 */ - { 0x1c58f0, 0x01400018, 0x01c00018}, - /* bank 4 */ - { 0x1c58b0, 0x000001a1, 0x000001a1}, - { 0x1c58e8, 0x00000001, 0x00000001}, - /* bank 5 */ - { 0x1c58b0, 0x00000013, 0x00000013}, - { 0x1c58e4, 0x00000002, 0x00000002}, - /* bank 6 */ - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00004800, 0x00004800}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006000, 0x00006000}, - { 0x1c58b0, 0x00001000, 0x00001000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00087c00, 0x00087c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00005400, 0x00005400}, - { 0x1c58b0, 0x00000c00, 0x00000c00}, - { 0x1c58b0, 0x00001800, 0x00001800}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00003c00, 0x00003c00}, - { 0x1c58b0, 0x00003800, 0x00003800}, - { 0x1c58b0, 0x00001c00, 0x00001c00}, - { 0x1c58b0, 0x00000800, 0x00000800}, - { 0x1c58b0, 0x00000408, 0x00000408}, - { 0x1c58b0, 0x00004c15, 0x00004c15}, - { 0x1c58b0, 0x00004188, 0x00004188}, - { 0x1c58b0, 0x0000201e, 0x0000201e}, - { 0x1c58b0, 0x00010408, 0x00010408}, - { 0x1c58b0, 0x00000801, 0x00000801}, - { 0x1c58b0, 0x00000c08, 0x00000c08}, - { 0x1c58b0, 0x0000181e, 0x0000181e}, - { 0x1c58b0, 0x00001016, 0x00001016}, - { 0x1c58b0, 0x00002800, 0x00002800}, - { 0x1c58b0, 0x00004010, 0x00004010}, - { 0x1c58b0, 0x0000081c, 0x0000081c}, - { 0x1c58b0, 0x00000115, 0x00000115}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x00000066, 0x00000066}, - { 0x1c58b0, 0x0000001c, 0x0000001c}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000004, 0x00000004}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x0000001f, 0x0000001f}, - { 0x1c58e0, 0x00000000, 0x00000400}, - /* bank 7 */ - { 0x1c58b0, 0x000000a0, 0x000000a0}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000040, 0x00000040}, - { 0x1c58f0, 0x0000001c, 0x0000001c}, -}; - -static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) -{ - int err, i; - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) - ar9170_regwrite(ar9170_rf_init[i].reg, - band5ghz ? ar9170_rf_init[i]._5ghz - : ar9170_rf_init[i]._2ghz); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - printk(KERN_ERR "%s: rf init failed\n", - wiphy_name(ar->hw->wiphy)); - return err; -} - -static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, - u32 freq, enum ar9170_bw bw) -{ - int err; - u32 d0, d1, td0, td1, fd0, fd1; - u8 chansel; - u8 refsel0 = 1, refsel1 = 0; - u8 lf_synth = 0; - - switch (bw) { - case AR9170_BW_40_ABOVE: - freq += 10; - break; - case AR9170_BW_40_BELOW: - freq -= 10; - break; - case AR9170_BW_20: - break; - case __AR9170_NUM_BW: - BUG(); - } - - if (band5ghz) { - if (freq % 10) { - chansel = (freq - 4800) / 5; - } else { - chansel = ((freq - 4800) / 10) * 2; - refsel0 = 0; - refsel1 = 1; - } - chansel = byte_rev_table[chansel]; - } else { - if (freq == 2484) { - chansel = 10 + (freq - 2274) / 5; - lf_synth = 1; - } else - chansel = 16 + (freq - 2272) / 5; - chansel *= 4; - chansel = byte_rev_table[chansel]; - } - - d1 = chansel; - d0 = 0x21 | - refsel0 << 3 | - refsel1 << 2 | - lf_synth << 1; - td0 = d0 & 0x1f; - td1 = d1 & 0x1f; - fd0 = td1 << 5 | td0; - - td0 = (d0 >> 5) & 0x7; - td1 = (d1 >> 5) & 0x7; - fd1 = td1 << 5 | td0; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1c58b0, fd0); - ar9170_regwrite(0x1c58e8, fd1); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - msleep(10); - - return 0; -} - -struct ar9170_phy_freq_params { - u8 coeff_exp; - u16 coeff_man; - u8 coeff_exp_shgi; - u16 coeff_man_shgi; -}; - -struct ar9170_phy_freq_entry { - u16 freq; - struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; -}; - -/* NB: must be in sync with channel tables in main! */ -static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { -/* - * freq, - * 20MHz, - * 40MHz (below), - * 40Mhz (above), - */ - { 2412, { - { 3, 21737, 3, 19563, }, - { 3, 21827, 3, 19644, }, - { 3, 21647, 3, 19482, }, - } }, - { 2417, { - { 3, 21692, 3, 19523, }, - { 3, 21782, 3, 19604, }, - { 3, 21602, 3, 19442, }, - } }, - { 2422, { - { 3, 21647, 3, 19482, }, - { 3, 21737, 3, 19563, }, - { 3, 21558, 3, 19402, }, - } }, - { 2427, { - { 3, 21602, 3, 19442, }, - { 3, 21692, 3, 19523, }, - { 3, 21514, 3, 19362, }, - } }, - { 2432, { - { 3, 21558, 3, 19402, }, - { 3, 21647, 3, 19482, }, - { 3, 21470, 3, 19323, }, - } }, - { 2437, { - { 3, 21514, 3, 19362, }, - { 3, 21602, 3, 19442, }, - { 3, 21426, 3, 19283, }, - } }, - { 2442, { - { 3, 21470, 3, 19323, }, - { 3, 21558, 3, 19402, }, - { 3, 21382, 3, 19244, }, - } }, - { 2447, { - { 3, 21426, 3, 19283, }, - { 3, 21514, 3, 19362, }, - { 3, 21339, 3, 19205, }, - } }, - { 2452, { - { 3, 21382, 3, 19244, }, - { 3, 21470, 3, 19323, }, - { 3, 21295, 3, 19166, }, - } }, - { 2457, { - { 3, 21339, 3, 19205, }, - { 3, 21426, 3, 19283, }, - { 3, 21252, 3, 19127, }, - } }, - { 2462, { - { 3, 21295, 3, 19166, }, - { 3, 21382, 3, 19244, }, - { 3, 21209, 3, 19088, }, - } }, - { 2467, { - { 3, 21252, 3, 19127, }, - { 3, 21339, 3, 19205, }, - { 3, 21166, 3, 19050, }, - } }, - { 2472, { - { 3, 21209, 3, 19088, }, - { 3, 21295, 3, 19166, }, - { 3, 21124, 3, 19011, }, - } }, - { 2484, { - { 3, 21107, 3, 18996, }, - { 3, 21192, 3, 19073, }, - { 3, 21022, 3, 18920, }, - } }, - { 4920, { - { 4, 21313, 4, 19181, }, - { 4, 21356, 4, 19220, }, - { 4, 21269, 4, 19142, }, - } }, - { 4940, { - { 4, 21226, 4, 19104, }, - { 4, 21269, 4, 19142, }, - { 4, 21183, 4, 19065, }, - } }, - { 4960, { - { 4, 21141, 4, 19027, }, - { 4, 21183, 4, 19065, }, - { 4, 21098, 4, 18988, }, - } }, - { 4980, { - { 4, 21056, 4, 18950, }, - { 4, 21098, 4, 18988, }, - { 4, 21014, 4, 18912, }, - } }, - { 5040, { - { 4, 20805, 4, 18725, }, - { 4, 20846, 4, 18762, }, - { 4, 20764, 4, 18687, }, - } }, - { 5060, { - { 4, 20723, 4, 18651, }, - { 4, 20764, 4, 18687, }, - { 4, 20682, 4, 18614, }, - } }, - { 5080, { - { 4, 20641, 4, 18577, }, - { 4, 20682, 4, 18614, }, - { 4, 20601, 4, 18541, }, - } }, - { 5180, { - { 4, 20243, 4, 18219, }, - { 4, 20282, 4, 18254, }, - { 4, 20204, 4, 18183, }, - } }, - { 5200, { - { 4, 20165, 4, 18148, }, - { 4, 20204, 4, 18183, }, - { 4, 20126, 4, 18114, }, - } }, - { 5220, { - { 4, 20088, 4, 18079, }, - { 4, 20126, 4, 18114, }, - { 4, 20049, 4, 18044, }, - } }, - { 5240, { - { 4, 20011, 4, 18010, }, - { 4, 20049, 4, 18044, }, - { 4, 19973, 4, 17976, }, - } }, - { 5260, { - { 4, 19935, 4, 17941, }, - { 4, 19973, 4, 17976, }, - { 4, 19897, 4, 17907, }, - } }, - { 5280, { - { 4, 19859, 4, 17873, }, - { 4, 19897, 4, 17907, }, - { 4, 19822, 4, 17840, }, - } }, - { 5300, { - { 4, 19784, 4, 17806, }, - { 4, 19822, 4, 17840, }, - { 4, 19747, 4, 17772, }, - } }, - { 5320, { - { 4, 19710, 4, 17739, }, - { 4, 19747, 4, 17772, }, - { 4, 19673, 4, 17706, }, - } }, - { 5500, { - { 4, 19065, 4, 17159, }, - { 4, 19100, 4, 17190, }, - { 4, 19030, 4, 17127, }, - } }, - { 5520, { - { 4, 18996, 4, 17096, }, - { 4, 19030, 4, 17127, }, - { 4, 18962, 4, 17065, }, - } }, - { 5540, { - { 4, 18927, 4, 17035, }, - { 4, 18962, 4, 17065, }, - { 4, 18893, 4, 17004, }, - } }, - { 5560, { - { 4, 18859, 4, 16973, }, - { 4, 18893, 4, 17004, }, - { 4, 18825, 4, 16943, }, - } }, - { 5580, { - { 4, 18792, 4, 16913, }, - { 4, 18825, 4, 16943, }, - { 4, 18758, 4, 16882, }, - } }, - { 5600, { - { 4, 18725, 4, 16852, }, - { 4, 18758, 4, 16882, }, - { 4, 18691, 4, 16822, }, - } }, - { 5620, { - { 4, 18658, 4, 16792, }, - { 4, 18691, 4, 16822, }, - { 4, 18625, 4, 16762, }, - } }, - { 5640, { - { 4, 18592, 4, 16733, }, - { 4, 18625, 4, 16762, }, - { 4, 18559, 4, 16703, }, - } }, - { 5660, { - { 4, 18526, 4, 16673, }, - { 4, 18559, 4, 16703, }, - { 4, 18493, 4, 16644, }, - } }, - { 5680, { - { 4, 18461, 4, 16615, }, - { 4, 18493, 4, 16644, }, - { 4, 18428, 4, 16586, }, - } }, - { 5700, { - { 4, 18396, 4, 16556, }, - { 4, 18428, 4, 16586, }, - { 4, 18364, 4, 16527, }, - } }, - { 5745, { - { 4, 18252, 4, 16427, }, - { 4, 18284, 4, 16455, }, - { 4, 18220, 4, 16398, }, - } }, - { 5765, { - { 4, 18189, 5, 32740, }, - { 4, 18220, 4, 16398, }, - { 4, 18157, 5, 32683, }, - } }, - { 5785, { - { 4, 18126, 5, 32626, }, - { 4, 18157, 5, 32683, }, - { 4, 18094, 5, 32570, }, - } }, - { 5805, { - { 4, 18063, 5, 32514, }, - { 4, 18094, 5, 32570, }, - { 4, 18032, 5, 32458, }, - } }, - { 5825, { - { 4, 18001, 5, 32402, }, - { 4, 18032, 5, 32458, }, - { 4, 17970, 5, 32347, }, - } }, - { 5170, { - { 4, 20282, 4, 18254, }, - { 4, 20321, 4, 18289, }, - { 4, 20243, 4, 18219, }, - } }, - { 5190, { - { 4, 20204, 4, 18183, }, - { 4, 20243, 4, 18219, }, - { 4, 20165, 4, 18148, }, - } }, - { 5210, { - { 4, 20126, 4, 18114, }, - { 4, 20165, 4, 18148, }, - { 4, 20088, 4, 18079, }, - } }, - { 5230, { - { 4, 20049, 4, 18044, }, - { 4, 20088, 4, 18079, }, - { 4, 20011, 4, 18010, }, - } }, -}; - -static const struct ar9170_phy_freq_params * -ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, - enum ar9170_bw bw) -{ - unsigned int chanidx = 0; - u16 freq = 2412; - - if (channel) { - chanidx = channel->hw_value; - freq = channel->center_freq; - } - - BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); - - BUILD_BUG_ON(__AR9170_NUM_BW != 3); - - WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); - - return &ar9170_phy_freq_params[chanidx].params[bw]; -} - - -int ar9170_init_rf(struct ar9170 *ar) -{ - const struct ar9170_phy_freq_params *freqpar; - __le32 cmd[7]; - int err; - - err = ar9170_init_rf_banks_0_7(ar, false); - if (err) - return err; - - err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); - - cmd[0] = cpu_to_le32(2412 * 1000); - cmd[1] = cpu_to_le32(0); - cmd[2] = cpu_to_le32(1); - cmd[3] = cpu_to_le32(freqpar->coeff_exp); - cmd[4] = cpu_to_le32(freqpar->coeff_man); - cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); - - /* RF_INIT echoes the command back to us */ - err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, - sizeof(cmd), (u8 *)cmd, - sizeof(cmd), (u8 *)cmd); - if (err) - return err; - - msleep(1000); - - return ar9170_echo_test(ar, 0xaabbccdd); -} - -static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) -{ - int idx = nfreqs - 2; - - while (idx >= 0) { - if (f >= freqs[idx]) - return idx; - idx--; - } - - return 0; -} - -static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) -{ - /* nothing to interpolate, it's horizontal */ - if (y2 == y1) - return y1; - - /* check if we hit one of the edges */ - if (x == x1) - return y1; - if (x == x2) - return y2; - - /* x1 == x2 is bad, hopefully == x */ - if (x2 == x1) - return y1; - - return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); -} - -static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) -{ -#define SHIFT 8 - s32 y; - - y = ar9170_interpolate_s32(x << SHIFT, - x1 << SHIFT, y1 << SHIFT, - x2 << SHIFT, y2 << SHIFT); - - /* - * XXX: unwrap this expression - * Isn't it just DIV_ROUND_UP(y, 1<> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); -#undef SHIFT -} - -static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) -{ - struct ar9170_calibration_target_power_legacy *ctpl; - struct ar9170_calibration_target_power_ht *ctph; - u8 *ctpres; - int ntargets; - int idx, i, n; - u8 ackpower, ackchains, f; - u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; - - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800)/5; - - /* - * cycle through the various modes - * - * legacy modes first: 5G, 2G CCK, 2G OFDM - */ - for (i = 0; i < 3; i++) { - switch (i) { - case 0: /* 5 GHz legacy */ - ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_leg; - break; - case 1: /* 2.4 GHz CCK */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; - ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; - ctpres = ar->power_2G_cck; - break; - case 2: /* 2.4 GHz OFDM */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ofdm; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctpl[n].freq == 0xff) - break; - pwr_freqs[n] = ctpl[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 4; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctpl[idx + 0].freq, - ctpl[idx + 0].power[n], - ctpl[idx + 1].freq, - ctpl[idx + 1].power[n]); - } - - /* - * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 - */ - for (i = 0; i < 4; i++) { - switch (i) { - case 0: /* 5 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht20; - break; - case 1: /* 5 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht40; - break; - case 2: /* 2.4 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht20; - break; - case 3: /* 2.4 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht40; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctph[n].freq == 0xff) - break; - pwr_freqs[n] = ctph[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 8; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctph[idx + 0].freq, - ctph[idx + 0].power[n], - ctph[idx + 1].freq, - ctph[idx + 1].power[n]); - } - - /* set ACK/CTS TX power */ - ar9170_regwrite_begin(ar); - - if (ar->eeprom.tx_mask != 1) - ackchains = AR9170_TX_PHY_TXCHAIN_2; - else - ackchains = AR9170_TX_PHY_TXCHAIN_1; - - if (freq < 3000) - ackpower = ar->power_2G_ofdm[0] & 0x3f; - else - ackpower = ar->power_5G_leg[0] & 0x3f; - - ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); - ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | - ackpower << 21 | ackchains << 27); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -static int ar9170_calc_noise_dbm(u32 raw_noise) -{ - if (raw_noise & 0x100) - return ~((raw_noise & 0x0ff) >> 1); - else - return (raw_noise & 0xff) >> 1; -} - -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) -{ - const struct ar9170_phy_freq_params *freqpar; - u32 cmd, tmp, offs; - __le32 vals[8]; - int i, err; - bool bandswitch; - - /* clear BB heavy clip enable */ - err = ar9170_write_reg(ar, 0x1c59e0, 0x200); - if (err) - return err; - - /* may be NULL at first setup */ - if (ar->channel) - bandswitch = ar->channel->band != channel->band; - else - bandswitch = true; - - /* HW workaround */ - if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && - channel->center_freq <= 2417) - bandswitch = true; - - err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); - if (err) - return err; - - if (rfi != AR9170_RFI_NONE || bandswitch) { - u32 val = 0x400; - - if (rfi == AR9170_RFI_COLD) - val = 0x800; - - /* warm/cold reset BB/ADDA */ - err = ar9170_write_reg(ar, 0x1d4004, val); - if (err) - return err; - - err = ar9170_write_reg(ar, 0x1d4004, 0x0); - if (err) - return err; - - err = ar9170_init_phy(ar, channel->band); - if (err) - return err; - - err = ar9170_init_rf_banks_0_7(ar, - channel->band == IEEE80211_BAND_5GHZ); - if (err) - return err; - - cmd = AR9170_CMD_RF_INIT; - } else { - cmd = AR9170_CMD_FREQUENCY; - } - - err = ar9170_init_rf_bank4_pwr(ar, - channel->band == IEEE80211_BAND_5GHZ, - channel->center_freq, bw); - if (err) - return err; - - switch (bw) { - case AR9170_BW_20: - tmp = 0x240; - offs = 0; - break; - case AR9170_BW_40_BELOW: - tmp = 0x2c4; - offs = 3; - break; - case AR9170_BW_40_ABOVE: - tmp = 0x2d4; - offs = 1; - break; - default: - BUG(); - return -ENOSYS; - } - - if (0 /* 2 streams capable */) - tmp |= 0x100; - - err = ar9170_write_reg(ar, 0x1c5804, tmp); - if (err) - return err; - - err = ar9170_set_power_cal(ar, channel->center_freq, bw); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(channel, bw); - - vals[0] = cpu_to_le32(channel->center_freq * 1000); - vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1); - vals[2] = cpu_to_le32(offs << 2 | 1); - vals[3] = cpu_to_le32(freqpar->coeff_exp); - vals[4] = cpu_to_le32(freqpar->coeff_man); - vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); - vals[7] = cpu_to_le32(1000); - - err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, - sizeof(vals), (u8 *)vals); - if (err) - return err; - - for (i = 0; i < 2; i++) { - ar->noise[i] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); - - ar->noise[i + 2] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); - } - - ar->channel = channel; - return 0; -} diff --git a/drivers/net/wireless/ar9170/usb.c b/drivers/net/wireless/ar9170/usb.c deleted file mode 100644 index fddda47..0000000 --- a/drivers/net/wireless/ar9170/usb.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * Atheros AR9170 driver - * - * USB - frontend - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include "ar9170.h" -#include "cmd.h" -#include "hw.h" -#include "usb.h" - -MODULE_AUTHOR("Johannes Berg "); -MODULE_AUTHOR("Christian Lamparter "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); -MODULE_FIRMWARE("ar9170-1.fw"); -MODULE_FIRMWARE("ar9170-2.fw"); - -static struct usb_device_id ar9170_usb_ids[] = { - /* Atheros 9170 */ - { USB_DEVICE(0x0cf3, 0x9170) }, - /* Atheros TG121N */ - { USB_DEVICE(0x0cf3, 0x1001) }, - /* Cace Airpcap NX */ - { USB_DEVICE(0xcace, 0x0300) }, - /* D-Link DWA 160A */ - { USB_DEVICE(0x07d1, 0x3c10) }, - /* Netgear WNDA3100 */ - { USB_DEVICE(0x0846, 0x9010) }, - /* Netgear WN111 v2 */ - { USB_DEVICE(0x0846, 0x9001) }, - /* Zydas ZD1221 */ - { USB_DEVICE(0x0ace, 0x1221) }, - /* ZyXEL NWD271N */ - { USB_DEVICE(0x0586, 0x3417) }, - /* Z-Com UB81 BG */ - { USB_DEVICE(0x0cde, 0x0023) }, - /* Z-Com UB82 ABG */ - { USB_DEVICE(0x0cde, 0x0026) }, - /* Arcadyan WN7512 */ - { USB_DEVICE(0x083a, 0xf522) }, - /* Planex GWUS300 */ - { USB_DEVICE(0x2019, 0x5304) }, - /* IO-Data WNGDNUS2 */ - { USB_DEVICE(0x04bb, 0x093f) }, - - /* terminate */ - {} -}; -MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); - -static void ar9170_usb_tx_urb_complete_free(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = (struct ar9170_usb *) - usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - - if (!aru) { - dev_kfree_skb_irq(skb); - return ; - } - - ar9170_handle_tx_status(&aru->common, skb, false, - AR9170_TX_STATUS_COMPLETE); -} - -static void ar9170_usb_tx_urb_complete(struct urb *urb) -{ -} - -static void ar9170_usb_irq_completed(struct urb *urb) -{ - struct ar9170_usb *aru = urb->context; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET, - urb->transfer_buffer, urb->actual_length); - -resubmit: - usb_anchor_urb(urb, &aru->rx_submitted); - if (usb_submit_urb(urb, GFP_ATOMIC)) { - usb_unanchor_urb(urb); - goto free; - } - - return; - -free: - usb_buffer_free(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); -} - -static void ar9170_usb_rx_completed(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = (struct ar9170_usb *) - usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - int err; - - if (!aru) - goto free; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - skb_put(skb, urb->actual_length); - ar9170_rx(&aru->common, skb); - -resubmit: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - usb_unanchor_urb(urb); - dev_kfree_skb_irq(skb); - } - - return ; - -free: - dev_kfree_skb_irq(skb); - return; -} - -static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, - struct urb *urb, gfp_t gfp) -{ - struct sk_buff *skb; - - skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); - if (!skb) - return -ENOMEM; - - /* reserve some space for mac80211's radiotap */ - skb_reserve(skb, 32); - - usb_fill_bulk_urb(urb, aru->udev, - usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), - skb->data, min(skb_tailroom(skb), - AR9170_MAX_RX_BUFFER_SIZE), - ar9170_usb_rx_completed, skb); - - return 0; -} - -static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) -{ - struct urb *urb = NULL; - void *ibuf; - int err = -ENOMEM; - - /* initialize interrupt endpoint */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto out; - - ibuf = usb_buffer_alloc(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); - if (!ibuf) - goto out; - - usb_fill_int_urb(urb, aru->udev, - usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, - 64, ar9170_usb_irq_completed, aru, 1); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - usb_buffer_free(aru->udev, 64, urb->transfer_buffer, - urb->transfer_dma); - } - -out: - usb_free_urb(urb); - return err; -} - -static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) -{ - struct urb *urb; - int i; - int err = -EINVAL; - - for (i = 0; i < AR9170_NUM_RX_URBS; i++) { - err = -ENOMEM; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto err_out; - - err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); - if (err) { - usb_free_urb(urb); - goto err_out; - } - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - dev_kfree_skb_any((void *) urb->transfer_buffer); - usb_free_urb(urb); - goto err_out; - } - usb_free_urb(urb); - } - - /* the device now waiting for a firmware. */ - aru->common.state = AR9170_IDLE; - return 0; - -err_out: - - usb_kill_anchored_urbs(&aru->rx_submitted); - return err; -} - -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) -{ - int ret; - - aru->common.state = AR9170_UNKNOWN_STATE; - - usb_unlink_anchored_urbs(&aru->tx_submitted); - - /* give the LED OFF command and the deauth frame a chance to air. */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(100)); - if (ret == 0) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - usb_poison_anchored_urbs(&aru->tx_submitted); - - usb_poison_anchored_urbs(&aru->rx_submitted); -} - -static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, - unsigned int plen, void *payload, - unsigned int outlen, void *out) -{ - struct ar9170_usb *aru = (void *) ar; - struct urb *urb = NULL; - unsigned long flags; - int err = -ENOMEM; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -EPERM; - - if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) - return -EINVAL; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - goto err_free; - - ar->cmdbuf[0] = cpu_to_le32(plen); - ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); - /* writing multiple regs fills this buffer already */ - if (plen && payload != (u8 *)(&ar->cmdbuf[1])) - memcpy(&ar->cmdbuf[1], payload, plen); - - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = (u8 *)out; - aru->readlen = outlen; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - - usb_fill_int_urb(urb, aru->udev, - usb_sndbulkpipe(aru->udev, AR9170_EP_CMD), - aru->common.cmdbuf, plen + 4, - ar9170_usb_tx_urb_complete, NULL, 1); - - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - usb_unanchor_urb(urb); - usb_free_urb(urb); - goto err_unbuf; - } - usb_free_urb(urb); - - err = wait_for_completion_timeout(&aru->cmd_wait, HZ); - if (err == 0) { - err = -ETIMEDOUT; - goto err_unbuf; - } - - if (outlen >= 0 && aru->readlen != outlen) { - err = -EMSGSIZE; - goto err_unbuf; - } - - return 0; - -err_unbuf: - /* Maybe the device was removed in the second we were waiting? */ - if (IS_STARTED(ar)) { - dev_err(&aru->udev->dev, "no command feedback " - "received (%d).\n", err); - - /* provide some maybe useful debug information */ - print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, - aru->common.cmdbuf, plen + 4); - dump_stack(); - } - - /* invalidate to avoid completing the next prematurely */ - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = NULL; - aru->readlen = 0; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - -err_free: - - return err; -} - -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, - bool txstatus_needed, unsigned int extra_len) -{ - struct ar9170_usb *aru = (struct ar9170_usb *) ar; - struct urb *urb; - int err; - - if (unlikely(!IS_STARTED(ar))) { - /* Seriously, what were you drink... err... thinking!? */ - return -EPERM; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - return -ENOMEM; - - usb_fill_bulk_urb(urb, aru->udev, - usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len + extra_len, (txstatus_needed ? - ar9170_usb_tx_urb_complete : - ar9170_usb_tx_urb_complete_free), skb); - urb->transfer_flags |= URB_ZERO_PACKET; - - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) - usb_unanchor_urb(urb); - - usb_free_urb(urb); - return err; -} - -static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) -{ - struct ar9170_usb *aru = (void *) ar; - unsigned long flags; - u32 in, out; - - if (!buffer) - return ; - - in = le32_to_cpup((__le32 *)buffer); - out = le32_to_cpu(ar->cmdbuf[0]); - - /* mask off length byte */ - out &= ~0xFF; - - if (aru->readlen >= 0) { - /* add expected length */ - out |= aru->readlen; - } else { - /* add obtained length */ - out |= in & 0xFF; - } - - /* - * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response - * length and we cannot predict the correct length in advance. - * So we only check if we provided enough space for the data. - */ - if (unlikely(out < in)) { - dev_warn(&aru->udev->dev, "received invalid command response " - "got %d bytes, instead of %d bytes " - "and the resp length is %d bytes\n", - in, out, len); - print_hex_dump_bytes("ar9170 invalid resp: ", - DUMP_PREFIX_OFFSET, buffer, len); - /* - * Do not complete, then the command times out, - * and we get a stack trace from there. - */ - return ; - } - - spin_lock_irqsave(&aru->common.cmdlock, flags); - if (aru->readbuf && len > 0) { - memcpy(aru->readbuf, buffer + 4, len - 4); - aru->readbuf = NULL; - } - complete(&aru->cmd_wait); - spin_unlock_irqrestore(&aru->common.cmdlock, flags); -} - -static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, - size_t len, u32 addr, bool complete) -{ - int transfer, err; - u8 *buf = kmalloc(4096, GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - while (len) { - transfer = min_t(int, len, 4096); - memcpy(buf, data, transfer); - - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, - addr >> 8, 0, buf, transfer, 1000); - - if (err < 0) { - kfree(buf); - return err; - } - - len -= transfer; - data += transfer; - addr += transfer; - } - kfree(buf); - - if (complete) { - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x31 /* FW DL COMPLETE */, - 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); - } - - return 0; -} - -static int ar9170_usb_request_firmware(struct ar9170_usb *aru) -{ - int err = 0; - - err = request_firmware(&aru->init_values, "ar9170-1.fw", - &aru->udev->dev); - if (err) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - return err; - } - - err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); - if (err) { - release_firmware(aru->init_values); - dev_err(&aru->udev->dev, "firmware file not found.\n"); - return err; - } - - return err; -} - -static int ar9170_usb_reset(struct ar9170_usb *aru) -{ - int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); - - if (lock) { - ret = usb_lock_device_for_reset(aru->udev, aru->intf); - if (ret < 0) { - dev_err(&aru->udev->dev, "unable to lock device " - "for reset (%d).\n", ret); - return ret; - } - } - - ret = usb_reset_device(aru->udev); - if (lock) - usb_unlock_device(aru->udev); - - /* let it rest - for a second - */ - msleep(1000); - - return ret; -} - -static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) -{ - int err; - - /* First, upload initial values to device RAM */ - err = ar9170_usb_upload(aru, aru->init_values->data, - aru->init_values->size, 0x102800, false); - if (err) { - dev_err(&aru->udev->dev, "firmware part 1 " - "upload failed (%d).\n", err); - return err; - } - - /* Then, upload the firmware itself and start it */ - return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, - 0x200000, true); -} - -static int ar9170_usb_init_transport(struct ar9170_usb *aru) -{ - struct ar9170 *ar = (void *) &aru->common; - int err; - - ar9170_regwrite_begin(ar); - - /* Set USB Rx stream mode MAX packet number to 2 */ - ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); - - /* Set USB Rx stream mode timeout to 10us */ - ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); - - ar9170_regwrite_finish(); - - err = ar9170_regwrite_result(); - if (err) - dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); - - return err; -} - -static void ar9170_usb_stop(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int ret; - - if (IS_ACCEPTING_CMD(ar)) - aru->common.state = AR9170_STOPPED; - - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(1000)); - if (ret == 0) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - - usb_poison_anchored_urbs(&aru->tx_submitted); - - /* - * Note: - * So far we freed all tx urbs, but we won't dare to touch any rx urbs. - * Else we would end up with a unresponsive device... - */ -} - -static int ar9170_usb_open(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int err; - - usb_unpoison_anchored_urbs(&aru->tx_submitted); - err = ar9170_usb_init_transport(aru); - if (err) { - usb_poison_anchored_urbs(&aru->tx_submitted); - return err; - } - - aru->common.state = AR9170_IDLE; - return 0; -} - -static int ar9170_usb_init_device(struct ar9170_usb *aru) -{ - int err; - - err = ar9170_usb_alloc_rx_irq_urb(aru); - if (err) - goto err_out; - - err = ar9170_usb_alloc_rx_bulk_urbs(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_upload_firmware(aru); - if (err) { - err = ar9170_echo_test(&aru->common, 0x60d43110); - if (err) { - /* force user invention, by disabling the device */ - err = usb_driver_set_configuration(aru->udev, -1); - dev_err(&aru->udev->dev, "device is in a bad state. " - "please reconnect it!\n"); - goto err_unrx; - } - } - - return 0; - -err_unrx: - ar9170_usb_cancel_urbs(aru); - -err_out: - return err; -} - -static int ar9170_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct ar9170_usb *aru; - struct ar9170 *ar; - struct usb_device *udev; - int err; - - aru = ar9170_alloc(sizeof(*aru)); - if (IS_ERR(aru)) { - err = PTR_ERR(aru); - goto out; - } - - udev = interface_to_usbdev(intf); - usb_get_dev(udev); - aru->udev = udev; - aru->intf = intf; - ar = &aru->common; - - usb_set_intfdata(intf, aru); - SET_IEEE80211_DEV(ar->hw, &udev->dev); - - init_usb_anchor(&aru->rx_submitted); - init_usb_anchor(&aru->tx_submitted); - init_completion(&aru->cmd_wait); - - aru->common.stop = ar9170_usb_stop; - aru->common.open = ar9170_usb_open; - aru->common.tx = ar9170_usb_tx; - aru->common.exec_cmd = ar9170_usb_exec_cmd; - aru->common.callback_cmd = ar9170_usb_callback_cmd; - - err = ar9170_usb_reset(aru); - if (err) - goto err_freehw; - - err = ar9170_usb_request_firmware(aru); - if (err) - goto err_freehw; - - err = ar9170_usb_init_device(aru); - if (err) - goto err_freefw; - - err = ar9170_usb_open(ar); - if (err) - goto err_unrx; - - err = ar9170_register(ar, &udev->dev); - - ar9170_usb_stop(ar); - if (err) - goto err_unrx; - - return 0; - -err_unrx: - ar9170_usb_cancel_urbs(aru); - -err_freefw: - release_firmware(aru->init_values); - release_firmware(aru->firmware); - -err_freehw: - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); - ieee80211_free_hw(ar->hw); -out: - return err; -} - -static void ar9170_usb_disconnect(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return; - - aru->common.state = AR9170_IDLE; - ar9170_unregister(&aru->common); - ar9170_usb_cancel_urbs(aru); - - release_firmware(aru->init_values); - release_firmware(aru->firmware); - - usb_put_dev(aru->udev); - usb_set_intfdata(intf, NULL); - ieee80211_free_hw(aru->common.hw); -} - -#ifdef CONFIG_PM -static int ar9170_suspend(struct usb_interface *intf, - pm_message_t message) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return -ENODEV; - - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return 0; -} - -static int ar9170_resume(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - int err; - - if (!aru) - return -ENODEV; - - usb_unpoison_anchored_urbs(&aru->rx_submitted); - usb_unpoison_anchored_urbs(&aru->tx_submitted); - - /* - * FIXME: firmware upload will fail on resume. - * but this is better than a hang! - */ - - err = ar9170_usb_init_device(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_open(&aru->common); - if (err) - goto err_unrx; - - return 0; - -err_unrx: - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return err; -} -#endif /* CONFIG_PM */ - -static struct usb_driver ar9170_driver = { - .name = "ar9170usb", - .probe = ar9170_usb_probe, - .disconnect = ar9170_usb_disconnect, - .id_table = ar9170_usb_ids, - .soft_unbind = 1, -#ifdef CONFIG_PM - .suspend = ar9170_suspend, - .resume = ar9170_resume, -#endif /* CONFIG_PM */ -}; - -static int __init ar9170_init(void) -{ - return usb_register(&ar9170_driver); -} - -static void __exit ar9170_exit(void) -{ - usb_deregister(&ar9170_driver); -} - -module_init(ar9170_init); -module_exit(ar9170_exit); diff --git a/drivers/net/wireless/ar9170/usb.h b/drivers/net/wireless/ar9170/usb.h deleted file mode 100644 index f585292..0000000 --- a/drivers/net/wireless/ar9170/usb.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Atheros AR9170 USB driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __USB_H -#define __USB_H - -#include -#include -#include -#include -#include -#include -#include -#include "eeprom.h" -#include "hw.h" -#include "ar9170.h" - -#define AR9170_NUM_RX_URBS 16 - -struct firmware; - -struct ar9170_usb { - struct ar9170 common; - struct usb_device *udev; - struct usb_interface *intf; - - struct usb_anchor rx_submitted; - struct usb_anchor tx_submitted; - - spinlock_t cmdlock; - struct completion cmd_wait; - int readlen; - u8 *readbuf; - - const struct firmware *init_values; - const struct firmware *firmware; -}; - -#endif /* __USB_H */ diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 76517a4..d26e7b4 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,4 +1,8 @@ config ATH_COMMON - tristate "Atheros Wireless Cards Shared Support" + tristate "Atheros Wireless Cards" depends on ATH5K || ATH9K || AR9170_USB +source "drivers/net/wireless/ath/ath5k/Kconfig" +source "drivers/net/wireless/ath/ath9k/Kconfig" +source "drivers/net/wireless/ath/ar9170/Kconfig" + diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index bc77646..a005b91 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -1,3 +1,7 @@ +obj-$(CONFIG_ATH5K) += ath5k/ +obj-$(CONFIG_ATH9K) += ath9k/ +obj-$(CONFIG_AR9170_USB) += ar9170/ + obj-$(CONFIG_ATH_COMMON) += ath.o ath-objs := regd.o diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig new file mode 100644 index 0000000..b99e326 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -0,0 +1,18 @@ +config AR9170_USB + tristate "Atheros AR9170 802.11n USB support" + depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL + select FW_LOADER + select ATH_COMMON + help + This is a driver for the Atheros "otus" 802.11n USB devices. + + These devices require additional firmware (2 files). + For now, these files can be downloaded from here: + http://wireless.kernel.org/en/users/Drivers/ar9170 + + If you choose to build a module, it'll be called ar9170usb. + +config AR9170_LEDS + bool + depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) + default y diff --git a/drivers/net/wireless/ath/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile new file mode 100644 index 0000000..8d91c7e --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/Makefile @@ -0,0 +1,3 @@ +ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o + +obj-$(CONFIG_AR9170_USB) += ar9170usb.o diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h new file mode 100644 index 0000000..f797495 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -0,0 +1,212 @@ +/* + * Atheros AR9170 driver + * + * Driver specific definitions + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __AR9170_H +#define __AR9170_H + +#include +#include +#include +#include +#ifdef CONFIG_AR9170_LEDS +#include +#endif /* CONFIG_AR9170_LEDS */ +#include "eeprom.h" +#include "hw.h" + +#include "../regd.h" + +#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) + +enum ar9170_bw { + AR9170_BW_20, + AR9170_BW_40_BELOW, + AR9170_BW_40_ABOVE, + + __AR9170_NUM_BW, +}; + +enum ar9170_rf_init_mode { + AR9170_RFI_NONE, + AR9170_RFI_WARM, + AR9170_RFI_COLD, +}; + +#define AR9170_MAX_RX_BUFFER_SIZE 8192 + +#ifdef CONFIG_AR9170_LEDS +struct ar9170; + +struct ar9170_led { + struct ar9170 *ar; + struct led_classdev l; + char name[32]; + unsigned int toggled; + bool registered; +}; + +#endif /* CONFIG_AR9170_LEDS */ + +enum ar9170_device_state { + AR9170_UNKNOWN_STATE, + AR9170_STOPPED, + AR9170_IDLE, + AR9170_STARTED, + AR9170_ASSOCIATED, +}; + +struct ar9170 { + struct ieee80211_hw *hw; + struct mutex mutex; + enum ar9170_device_state state; + + int (*open)(struct ar9170 *); + void (*stop)(struct ar9170 *); + int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int); + int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , + void *, u32 , void *); + void (*callback_cmd)(struct ar9170 *, u32 , void *); + + /* interface mode settings */ + struct ieee80211_vif *vif; + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + + /* beaconing */ + struct sk_buff *beacon; + struct work_struct beacon_work; + + /* cryptographic engine */ + u64 usedkeys; + bool rx_software_decryption; + bool disable_offload; + + /* filter settings */ + struct work_struct filter_config_work; + u64 cur_mc_hash, want_mc_hash; + u32 cur_filter, want_filter; + unsigned int filter_changed; + bool sniffer_enabled; + + /* PHY */ + struct ieee80211_channel *channel; + int noise[4]; + + /* power calibration data */ + u8 power_5G_leg[4]; + u8 power_2G_cck[4]; + u8 power_2G_ofdm[4]; + u8 power_5G_ht20[8]; + u8 power_5G_ht40[8]; + u8 power_2G_ht20[8]; + u8 power_2G_ht40[8]; + +#ifdef CONFIG_AR9170_LEDS + struct delayed_work led_work; + struct ar9170_led leds[AR9170_NUM_LEDS]; +#endif /* CONFIG_AR9170_LEDS */ + + /* qos queue settings */ + spinlock_t tx_stats_lock; + struct ieee80211_tx_queue_stats tx_stats[5]; + struct ieee80211_tx_queue_params edcf[5]; + + spinlock_t cmdlock; + __le32 cmdbuf[PAYLOAD_MAX + 1]; + + /* MAC statistics */ + struct ieee80211_low_level_stats stats; + + /* EEPROM */ + struct ar9170_eeprom eeprom; + struct ath_regulatory regulatory; + + /* global tx status for unregistered Stations. */ + struct sk_buff_head global_tx_status; + struct sk_buff_head global_tx_status_waste; + struct delayed_work tx_status_janitor; +}; + +struct ar9170_sta_info { + struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; +}; + +#define IS_STARTED(a) (a->state >= AR9170_STARTED) +#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) + +#define AR9170_FILTER_CHANGED_PROMISC BIT(0) +#define AR9170_FILTER_CHANGED_MULTICAST BIT(1) +#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) + +/* exported interface */ +void *ar9170_alloc(size_t priv_size); +int ar9170_register(struct ar9170 *ar, struct device *pdev); +void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); +void ar9170_unregister(struct ar9170 *ar); +void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, + bool update_statistics, u16 tx_status); + +/* MAC */ +int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +int ar9170_init_mac(struct ar9170 *ar); +int ar9170_set_qos(struct ar9170 *ar); +int ar9170_update_multicast(struct ar9170 *ar); +int ar9170_update_frame_filter(struct ar9170 *ar); +int ar9170_set_operating_mode(struct ar9170 *ar); +int ar9170_set_beacon_timers(struct ar9170 *ar); +int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); +int ar9170_update_beacon(struct ar9170 *ar); +void ar9170_new_beacon(struct work_struct *work); +int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, + u8 keyidx, u8 *keydata, int keylen); +int ar9170_disable_key(struct ar9170 *ar, u8 id); + +/* LEDs */ +#ifdef CONFIG_AR9170_LEDS +int ar9170_register_leds(struct ar9170 *ar); +void ar9170_unregister_leds(struct ar9170 *ar); +#endif /* CONFIG_AR9170_LEDS */ +int ar9170_init_leds(struct ar9170 *ar); +int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); + +/* PHY / RF */ +int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); +int ar9170_init_rf(struct ar9170 *ar); +int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, + enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); + +#endif /* __AR9170_H */ diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c new file mode 100644 index 0000000..f57a620 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/cmd.c @@ -0,0 +1,129 @@ +/* + * Atheros AR9170 driver + * + * Basic HW register/memory/command access functions + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ar9170.h" +#include "cmd.h" + +int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) +{ + int err; + + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return 0; + + err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); + if (err) + printk(KERN_DEBUG "%s: writing memory failed\n", + wiphy_name(ar->hw->wiphy)); + return err; +} + +int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) +{ + __le32 buf[2] = { + cpu_to_le32(reg), + cpu_to_le32(val), + }; + int err; + + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return 0; + + err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), + (u8 *) buf, 0, NULL); + if (err) + printk(KERN_DEBUG "%s: writing reg %#x (val %#x) failed\n", + wiphy_name(ar->hw->wiphy), reg, val); + return err; +} + +static int ar9170_read_mreg(struct ar9170 *ar, int nregs, + const u32 *regs, u32 *out) +{ + int i, err; + __le32 *offs, *res; + + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return 0; + + /* abuse "out" for the register offsets, must be same length */ + offs = (__le32 *)out; + for (i = 0; i < nregs; i++) + offs[i] = cpu_to_le32(regs[i]); + + /* also use the same buffer for the input */ + res = (__le32 *)out; + + err = ar->exec_cmd(ar, AR9170_CMD_RREG, + 4 * nregs, (u8 *)offs, + 4 * nregs, (u8 *)res); + if (err) + return err; + + /* convert result to cpu endian */ + for (i = 0; i < nregs; i++) + out[i] = le32_to_cpu(res[i]); + + return 0; +} + +int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) +{ + return ar9170_read_mreg(ar, 1, ®, val); +} + +int ar9170_echo_test(struct ar9170 *ar, u32 v) +{ + __le32 echobuf = cpu_to_le32(v); + __le32 echores; + int err; + + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return -ENODEV; + + err = ar->exec_cmd(ar, AR9170_CMD_ECHO, + 4, (u8 *)&echobuf, + 4, (u8 *)&echores); + if (err) + return err; + + if (echobuf != echores) + return -EINVAL; + + return 0; +} diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h new file mode 100644 index 0000000..a4f0e50 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/cmd.h @@ -0,0 +1,91 @@ +/* + * Atheros AR9170 driver + * + * Basic HW register/memory/command access functions + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __CMD_H +#define __CMD_H + +#include "ar9170.h" + +/* basic HW access */ +int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); +int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); +int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); +int ar9170_echo_test(struct ar9170 *ar, u32 v); + +/* + * Macros to facilitate writing multiple registers in a single + * write-combining USB command. Note that when the first group + * fails the whole thing will fail without any others attempted, + * but you won't know which write in the group failed. + */ +#define ar9170_regwrite_begin(ar) \ +do { \ + int __nreg = 0, __err = 0; \ + struct ar9170 *__ar = ar; + +#define ar9170_regwrite(r, v) do { \ + __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ + __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ + __nreg++; \ + if ((__nreg >= PAYLOAD_MAX/2)) { \ + if (IS_ACCEPTING_CMD(__ar)) \ + __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ + 8 * __nreg, \ + (u8 *) &__ar->cmdbuf[1], \ + 0, NULL); \ + __nreg = 0; \ + if (__err) \ + goto __regwrite_out; \ + } \ +} while (0) + +#define ar9170_regwrite_finish() \ +__regwrite_out : \ + if (__nreg) { \ + if (IS_ACCEPTING_CMD(__ar)) \ + __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ + 8 * __nreg, \ + (u8 *) &__ar->cmdbuf[1], \ + 0, NULL); \ + __nreg = 0; \ + } + +#define ar9170_regwrite_result() \ + __err; \ +} while (0); + +#endif /* __CMD_H */ diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h new file mode 100644 index 0000000..d2c8cc8 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/eeprom.h @@ -0,0 +1,179 @@ +/* + * Atheros AR9170 driver + * + * EEPROM layout + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __AR9170_EEPROM_H +#define __AR9170_EEPROM_H + +#define AR5416_MAX_CHAINS 2 +#define AR5416_MODAL_SPURS 5 + +struct ar9170_eeprom_modal { + __le32 antCtrlChain[AR5416_MAX_CHAINS]; + __le32 antCtrlCommon; + s8 antennaGainCh[AR5416_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_MAX_CHAINS]; + s8 adcDesiredSize; + s8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + s8 iqCalICh[AR5416_MAX_CHAINS]; + s8 iqCalQCh[AR5416_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob; + u8 db; + u8 xpaBiasLvl; + u8 pwrDecreaseFor2Chain; + u8 pwrDecreaseFor3Chain; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_MAX_CHAINS]; + u8 bswMargin[AR5416_MAX_CHAINS]; + u8 swSettleHt40; + u8 reserved[22]; + struct spur_channel { + __le16 spurChan; + u8 spurRangeLow; + u8 spurRangeHigh; + } __packed spur_channels[AR5416_MODAL_SPURS]; +} __packed; + +#define AR5416_NUM_PD_GAINS 4 +#define AR5416_PD_GAIN_ICEPTS 5 + +struct ar9170_calibration_data_per_freq { + u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; + u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; +} __packed; + +#define AR5416_NUM_5G_CAL_PIERS 8 +#define AR5416_NUM_2G_CAL_PIERS 4 + +#define AR5416_NUM_5G_TARGET_PWRS 8 +#define AR5416_NUM_2G_CCK_TARGET_PWRS 3 +#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 +#define AR5416_MAX_NUM_TGT_PWRS 8 + +struct ar9170_calibration_target_power_legacy { + u8 freq; + u8 power[4]; +} __packed; + +struct ar9170_calibration_target_power_ht { + u8 freq; + u8 power[8]; +} __packed; + +#define AR5416_NUM_CTLS 24 + +struct ar9170_calctl_edges { + u8 channel; +#define AR9170_CALCTL_EDGE_FLAGS 0xC0 + u8 power_flags; +} __packed; + +#define AR5416_NUM_BAND_EDGES 8 + +struct ar9170_calctl_data { + struct ar9170_calctl_edges + control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; +} __packed; + + +struct ar9170_eeprom { + __le16 length; + __le16 checksum; + __le16 version; + u8 operating_flags; +#define AR9170_OPFLAG_5GHZ 1 +#define AR9170_OPFLAG_2GHZ 2 + u8 misc; + __le16 reg_domain[2]; + u8 mac_address[6]; + u8 rx_mask; + u8 tx_mask; + __le16 rf_silent; + __le16 bluetooth_options; + __le16 device_capabilities; + __le32 build_number; + u8 deviceType; + u8 reserved[33]; + + u8 customer_data[64]; + + struct ar9170_eeprom_modal + modal_header[2]; + + u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; + u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; + + struct ar9170_calibration_data_per_freq + cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], + cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; + + /* power calibration data */ + struct ar9170_calibration_target_power_legacy + cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; + struct ar9170_calibration_target_power_ht + cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], + cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; + + struct ar9170_calibration_target_power_legacy + cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], + cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; + struct ar9170_calibration_target_power_ht + cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], + cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; + + /* conformance testing limits */ + u8 ctl_index[AR5416_NUM_CTLS]; + struct ar9170_calctl_data + ctl_data[AR5416_NUM_CTLS]; + + u8 pad; + __le16 subsystem_id; +} __packed; + +#endif /* __AR9170_EEPROM_H */ diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h new file mode 100644 index 0000000..53e250a --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -0,0 +1,417 @@ +/* + * Atheros AR9170 driver + * + * Hardware-specific definitions + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __AR9170_HW_H +#define __AR9170_HW_H + +#define AR9170_MAX_CMD_LEN 64 + +enum ar9170_cmd { + AR9170_CMD_RREG = 0x00, + AR9170_CMD_WREG = 0x01, + AR9170_CMD_RMEM = 0x02, + AR9170_CMD_WMEM = 0x03, + AR9170_CMD_BITAND = 0x04, + AR9170_CMD_BITOR = 0x05, + AR9170_CMD_EKEY = 0x28, + AR9170_CMD_DKEY = 0x29, + AR9170_CMD_FREQUENCY = 0x30, + AR9170_CMD_RF_INIT = 0x31, + AR9170_CMD_SYNTH = 0x32, + AR9170_CMD_FREQ_START = 0x33, + AR9170_CMD_ECHO = 0x80, + AR9170_CMD_TALLY = 0x81, + AR9170_CMD_TALLY_APD = 0x82, + AR9170_CMD_CONFIG = 0x83, + AR9170_CMD_RESET = 0x90, + AR9170_CMD_DKRESET = 0x91, + AR9170_CMD_DKTX_STATUS = 0x92, + AR9170_CMD_FDC = 0xA0, + AR9170_CMD_WREEPROM = 0xB0, + AR9170_CMD_WFLASH = 0xB0, + AR9170_CMD_FLASH_ERASE = 0xB1, + AR9170_CMD_FLASH_PROG = 0xB2, + AR9170_CMD_FLASH_CHKSUM = 0xB3, + AR9170_CMD_FLASH_READ = 0xB4, + AR9170_CMD_FW_DL_INIT = 0xB5, + AR9170_CMD_MEM_WREEPROM = 0xBB, +}; + +/* endpoints */ +#define AR9170_EP_TX 1 +#define AR9170_EP_RX 2 +#define AR9170_EP_IRQ 3 +#define AR9170_EP_CMD 4 + +#define AR9170_EEPROM_START 0x1600 + +#define AR9170_GPIO_REG_BASE 0x1d0100 +#define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE +#define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) +#define AR9170_NUM_LEDS 2 + + +#define AR9170_USB_REG_BASE 0x1e1000 +#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) +#define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 +#define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 +#define AR9170_DMA_CTL_HIGH_SPEED 0x4 +#define AR9170_DMA_CTL_PACKET_MODE 0x8 + +#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) +#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) + + + +#define AR9170_MAC_REG_BASE 0x1c3000 + +#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) +#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) + +#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) +#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) +#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) + +#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) +#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) +#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) +#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) + +#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) +#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) + +#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) + +#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) +#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) +#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) +#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) +#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) +#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) + +#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) +#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) +#define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) +#define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 +#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) +#define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) +#define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 + +#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) +#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) + +#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) +#define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) +#define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) +#define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) +#define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) +#define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) +#define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) +#define AR9170_MAC_REG_FTF_BIT6 BIT(6) +#define AR9170_MAC_REG_FTF_BIT7 BIT(7) +#define AR9170_MAC_REG_FTF_BEACON BIT(8) +#define AR9170_MAC_REG_FTF_ATIM BIT(9) +#define AR9170_MAC_REG_FTF_DEASSOC BIT(10) +#define AR9170_MAC_REG_FTF_AUTH BIT(11) +#define AR9170_MAC_REG_FTF_DEAUTH BIT(12) +#define AR9170_MAC_REG_FTF_BIT13 BIT(13) +#define AR9170_MAC_REG_FTF_BIT14 BIT(14) +#define AR9170_MAC_REG_FTF_BIT15 BIT(15) +#define AR9170_MAC_REG_FTF_BAR BIT(24) +#define AR9170_MAC_REG_FTF_BIT25 BIT(25) +#define AR9170_MAC_REG_FTF_PSPOLL BIT(26) +#define AR9170_MAC_REG_FTF_RTS BIT(27) +#define AR9170_MAC_REG_FTF_CTS BIT(28) +#define AR9170_MAC_REG_FTF_ACK BIT(29) +#define AR9170_MAC_REG_FTF_CFE BIT(30) +#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) +#define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff +#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff + +#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) +#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) +#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) +#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) +#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) +#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) +#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) +#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) + + +#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) +#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) + +#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) + +#define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) +#define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 +#define AR9170_MAC_REG_POWERMGT_AP 0xa1 +#define AR9170_MAC_REG_POWERMGT_STA 0x2 +#define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 +#define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) + +#define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) +#define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) + +#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) +#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) +#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) +#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) +#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) +#define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) +#define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) + +#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) + +#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) +#define AR9170_MAC_FCS_SWFCS 0x1 +#define AR9170_MAC_FCS_FIFO_PROT 0x4 + + +#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) + +#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) +#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) + +#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) +#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) + +#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) +#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f +#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 +#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 +#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 + +#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) +#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) +#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) +#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) +#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) +#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) + + +#define AR9170_PWR_REG_BASE 0x1D4000 + +#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) +#define AR9170_PWR_CLK_AHB_40MHZ 0 +#define AR9170_PWR_CLK_AHB_20_22MHZ 1 +#define AR9170_PWR_CLK_AHB_40_44MHZ 2 +#define AR9170_PWR_CLK_AHB_80_88MHZ 3 +#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 + + +/* put beacon here in memory */ +#define AR9170_BEACON_BUFFER_ADDRESS 0x117900 + + +struct ar9170_tx_control { + __le16 length; + __le16 mac_control; + __le32 phy_control; + u8 frame_data[0]; +} __packed; + +/* these are either-or */ +#define AR9170_TX_MAC_PROT_RTS 0x0001 +#define AR9170_TX_MAC_PROT_CTS 0x0002 + +#define AR9170_TX_MAC_NO_ACK 0x0004 +/* if unset, MAC will only do SIFS space before frame */ +#define AR9170_TX_MAC_BACKOFF 0x0008 +#define AR9170_TX_MAC_BURST 0x0010 +#define AR9170_TX_MAC_AGGR 0x0020 + +/* encryption is a two-bit field */ +#define AR9170_TX_MAC_ENCR_NONE 0x0000 +#define AR9170_TX_MAC_ENCR_RC4 0x0040 +#define AR9170_TX_MAC_ENCR_CENC 0x0080 +#define AR9170_TX_MAC_ENCR_AES 0x00c0 + +#define AR9170_TX_MAC_MMIC 0x0100 +#define AR9170_TX_MAC_HW_DURATION 0x0200 +#define AR9170_TX_MAC_QOS_SHIFT 10 +#define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) +#define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 +#define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 +#define AR9170_TX_MAC_DISABLE_TXOP 0x1000 +#define AR9170_TX_MAC_TXOP_RIFS 0x2000 +#define AR9170_TX_MAC_IMM_AMPDU 0x4000 +#define AR9170_TX_MAC_RATE_PROBE 0x8000 + +/* either-or */ +#define AR9170_TX_PHY_MOD_CCK 0x00000000 +#define AR9170_TX_PHY_MOD_OFDM 0x00000001 +#define AR9170_TX_PHY_MOD_HT 0x00000002 + +/* depends on modulation */ +#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 +#define AR9170_TX_PHY_GREENFIELD 0x00000004 + +#define AR9170_TX_PHY_BW_SHIFT 3 +#define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) +#define AR9170_TX_PHY_BW_20MHZ 0 +#define AR9170_TX_PHY_BW_40MHZ 2 +#define AR9170_TX_PHY_BW_40MHZ_DUP 3 + +#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 +#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) + +#define AR9170_TX_PHY_TX_PWR_SHIFT 9 +#define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) + +/* not part of the hw-spec */ +#define AR9170_TX_PHY_QOS_SHIFT 25 +#define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) + +#define AR9170_TX_PHY_TXCHAIN_SHIFT 15 +#define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) +#define AR9170_TX_PHY_TXCHAIN_1 1 +/* use for cck, ofdm 6/9/12/18/24 and HT if capable */ +#define AR9170_TX_PHY_TXCHAIN_2 5 + +#define AR9170_TX_PHY_MCS_SHIFT 18 +#define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) + +#define AR9170_TX_PHY_SHORT_GI 0x80000000 + +struct ar9170_rx_head { + u8 plcp[12]; +} __packed; + +struct ar9170_rx_tail { + union { + struct { + u8 rssi_ant0, rssi_ant1, rssi_ant2, + rssi_ant0x, rssi_ant1x, rssi_ant2x, + rssi_combined; + } __packed; + u8 rssi[7]; + } __packed; + + u8 evm_stream0[6], evm_stream1[6]; + u8 phy_err; + u8 SAidx, DAidx; + u8 error; + u8 status; +} __packed; + +#define AR9170_ENC_ALG_NONE 0x0 +#define AR9170_ENC_ALG_WEP64 0x1 +#define AR9170_ENC_ALG_TKIP 0x2 +#define AR9170_ENC_ALG_AESCCMP 0x4 +#define AR9170_ENC_ALG_WEP128 0x5 +#define AR9170_ENC_ALG_WEP256 0x6 +#define AR9170_ENC_ALG_CENC 0x7 + +#define AR9170_RX_ENC_SOFTWARE 0x8 + +static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) +{ + return (t->SAidx & 0xc0) >> 4 | + (t->DAidx & 0xc0) >> 6; +} + +#define AR9170_RX_STATUS_MODULATION_MASK 0x03 +#define AR9170_RX_STATUS_MODULATION_CCK 0x00 +#define AR9170_RX_STATUS_MODULATION_OFDM 0x01 +#define AR9170_RX_STATUS_MODULATION_HT 0x02 +#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 + +/* depends on modulation */ +#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 +#define AR9170_RX_STATUS_GREENFIELD 0x08 + +#define AR9170_RX_STATUS_MPDU_MASK 0x30 +#define AR9170_RX_STATUS_MPDU_SINGLE 0x00 +#define AR9170_RX_STATUS_MPDU_FIRST 0x10 +#define AR9170_RX_STATUS_MPDU_MIDDLE 0x20 +#define AR9170_RX_STATUS_MPDU_LAST 0x30 + + +#define AR9170_RX_ERROR_RXTO 0x01 +#define AR9170_RX_ERROR_OVERRUN 0x02 +#define AR9170_RX_ERROR_DECRYPT 0x04 +#define AR9170_RX_ERROR_FCS 0x08 +#define AR9170_RX_ERROR_WRONG_RA 0x10 +#define AR9170_RX_ERROR_PLCP 0x20 +#define AR9170_RX_ERROR_MMIC 0x40 + +struct ar9170_cmd_tx_status { + __le16 unkn; + u8 dst[ETH_ALEN]; + __le32 rate; + __le16 status; +} __packed; + +#define AR9170_TX_STATUS_COMPLETE 0x00 +#define AR9170_TX_STATUS_RETRY 0x01 +#define AR9170_TX_STATUS_FAILED 0x02 + +struct ar9170_cmd_ba_failed_count { + __le16 failed; + __le16 rate; +} __packed; + +struct ar9170_cmd_response { + u8 flag; + u8 type; + + union { + struct ar9170_cmd_tx_status tx_status; + struct ar9170_cmd_ba_failed_count ba_fail_cnt; + u8 data[0]; + }; +} __packed; + +/* QoS */ + +/* mac80211 queue to HW/FW map */ +static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; + +/* HW/FW queue to mac80211 map */ +static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; + +enum ar9170_txq { + AR9170_TXQ_BE, + AR9170_TXQ_BK, + AR9170_TXQ_VI, + AR9170_TXQ_VO, + + __AR9170_NUM_TXQ, +}; + +#endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c new file mode 100644 index 0000000..341cead --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/led.c @@ -0,0 +1,171 @@ +/* + * Atheros AR9170 driver + * + * LED handling + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ar9170.h" +#include "cmd.h" + +int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) +{ + return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); +} + +int ar9170_init_leds(struct ar9170 *ar) +{ + int err; + + /* disable LEDs */ + /* GPIO [0/1 mode: output, 2/3: input] */ + err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); + if (err) + goto out; + + /* GPIO 0/1 value: off */ + err = ar9170_set_leds_state(ar, 0); + +out: + return err; +} + +#ifdef CONFIG_AR9170_LEDS +static void ar9170_update_leds(struct work_struct *work) +{ + struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); + int i, tmp, blink_delay = 1000; + u32 led_val = 0; + bool rerun = false; + + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return ; + + mutex_lock(&ar->mutex); + for (i = 0; i < AR9170_NUM_LEDS; i++) + if (ar->leds[i].toggled) { + led_val |= 1 << i; + + tmp = 70 + 200 / (ar->leds[i].toggled); + if (tmp < blink_delay) + blink_delay = tmp; + + if (ar->leds[i].toggled > 1) + ar->leds[i].toggled = 0; + + rerun = true; + } + + ar9170_set_leds_state(ar, led_val); + mutex_unlock(&ar->mutex); + + if (rerun) + queue_delayed_work(ar->hw->workqueue, &ar->led_work, + msecs_to_jiffies(blink_delay)); +} + +static void ar9170_led_brightness_set(struct led_classdev *led, + enum led_brightness brightness) +{ + struct ar9170_led *arl = container_of(led, struct ar9170_led, l); + struct ar9170 *ar = arl->ar; + + arl->toggled++; + + if (likely(IS_ACCEPTING_CMD(ar) && brightness)) + queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); +} + +static int ar9170_register_led(struct ar9170 *ar, int i, char *name, + char *trigger) +{ + int err; + + snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), + "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); + + ar->leds[i].ar = ar; + ar->leds[i].l.name = ar->leds[i].name; + ar->leds[i].l.brightness_set = ar9170_led_brightness_set; + ar->leds[i].l.brightness = 0; + ar->leds[i].l.default_trigger = trigger; + + err = led_classdev_register(wiphy_dev(ar->hw->wiphy), + &ar->leds[i].l); + if (err) + printk(KERN_ERR "%s: failed to register %s LED (%d).\n", + wiphy_name(ar->hw->wiphy), ar->leds[i].name, err); + else + ar->leds[i].registered = true; + + return err; +} + +void ar9170_unregister_leds(struct ar9170 *ar) +{ + int i; + + cancel_delayed_work_sync(&ar->led_work); + + for (i = 0; i < AR9170_NUM_LEDS; i++) + if (ar->leds[i].registered) { + led_classdev_unregister(&ar->leds[i].l); + ar->leds[i].registered = false; + } +} + +int ar9170_register_leds(struct ar9170 *ar) +{ + int err; + + INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); + + err = ar9170_register_led(ar, 0, "tx", + ieee80211_get_tx_led_name(ar->hw)); + if (err) + goto fail; + + err = ar9170_register_led(ar, 1, "assoc", + ieee80211_get_assoc_led_name(ar->hw)); + if (err) + goto fail; + + return 0; + +fail: + ar9170_unregister_leds(ar); + return err; +} + +#endif /* CONFIG_AR9170_LEDS */ diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c new file mode 100644 index 0000000..c8fa307 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -0,0 +1,452 @@ +/* + * Atheros AR9170 driver + * + * MAC programming + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "ar9170.h" +#include "cmd.h" + +int ar9170_set_qos(struct ar9170 *ar) +{ + ar9170_regwrite_begin(ar); + + ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | + (ar->edcf[0].cw_max << 16)); + ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | + (ar->edcf[1].cw_max << 16)); + ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | + (ar->edcf[2].cw_max << 16)); + ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | + (ar->edcf[3].cw_max << 16)); + ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | + (ar->edcf[4].cw_max << 16)); + + ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, + ((ar->edcf[0].aifs * 9 + 10)) | + ((ar->edcf[1].aifs * 9 + 10) << 12) | + ((ar->edcf[2].aifs * 9 + 10) << 24)); + ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, + ((ar->edcf[2].aifs * 9 + 10) >> 8) | + ((ar->edcf[3].aifs * 9 + 10) << 4) | + ((ar->edcf[4].aifs * 9 + 10) << 16)); + + ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, + ar->edcf[0].txop | ar->edcf[1].txop << 16); + ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, + ar->edcf[1].txop | ar->edcf[3].txop << 16); + + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + +int ar9170_init_mac(struct ar9170 *ar) +{ + ar9170_regwrite_begin(ar); + + ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); + + ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); + + /* enable MMIC */ + ar9170_regwrite(AR9170_MAC_REG_SNIFFER, + AR9170_MAC_REG_SNIFFER_DEFAULTS); + + ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); + + ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); + ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); + ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); + + /* CF-END mode */ + ar9170_regwrite(0x1c3b2c, 0x19000000); + + /* NAV protects ACK only (in TXOP) */ + ar9170_regwrite(0x1c3b38, 0x201); + + /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ + /* OTUS set AM to 0x1 */ + ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); + + ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); + + /* AGG test code*/ + /* Aggregation MAX number and timeout */ + ar9170_regwrite(0x1c3b9c, 0x10000a); + + ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, + AR9170_MAC_REG_FTF_DEFAULTS); + + /* Enable deaggregator, response in sniffer mode */ + ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); + + /* rate sets */ + ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); + ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); + ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); + + /* MIMO response control */ + ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ + + /* switch MAC to OTUS interface */ + ar9170_regwrite(0x1c3600, 0x3); + + ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); + + /* set PHY register read timeout (??) */ + ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); + + /* Disable Rx TimeOut, workaround for BB. */ + ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); + + /* Set CPU clock frequency to 88/80MHz */ + ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, + AR9170_PWR_CLK_AHB_80_88MHZ | + AR9170_PWR_CLK_DAC_160_INV_DLY); + + /* Set WLAN DMA interrupt mode: generate int per packet */ + ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); + + ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, + AR9170_MAC_FCS_FIFO_PROT); + + /* Disables the CF_END frame, undocumented register */ + ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, + 0x141E0F48); + + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + +static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) +{ + static const u8 zero[ETH_ALEN] = { 0 }; + + if (!mac) + mac = zero; + + ar9170_regwrite_begin(ar); + + ar9170_regwrite(reg, + (mac[3] << 24) | (mac[2] << 16) | + (mac[1] << 8) | mac[0]); + + ar9170_regwrite(reg + 4, (mac[5] << 8) | mac[4]); + + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + +int ar9170_update_multicast(struct ar9170 *ar) +{ + int err; + + ar9170_regwrite_begin(ar); + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, + ar->want_mc_hash >> 32); + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, + ar->want_mc_hash); + + ar9170_regwrite_finish(); + err = ar9170_regwrite_result(); + + if (err) + return err; + + ar->cur_mc_hash = ar->want_mc_hash; + + return 0; +} + +int ar9170_update_frame_filter(struct ar9170 *ar) +{ + int err; + + err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, + ar->want_filter); + + if (err) + return err; + + ar->cur_filter = ar->want_filter; + + return 0; +} + +static int ar9170_set_promiscouous(struct ar9170 *ar) +{ + u32 encr_mode, sniffer; + int err; + + err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); + if (err) + return err; + + err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); + if (err) + return err; + + if (ar->sniffer_enabled) { + sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; + + /* + * Rx decryption works in place. + * + * If we don't disable it, the hardware will render all + * encrypted frames which are encrypted with an unknown + * key useless. + */ + + encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; + ar->sniffer_enabled = true; + } else { + sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; + + if (ar->rx_software_decryption) + encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; + else + encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; + } + + ar9170_regwrite_begin(ar); + ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); + ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + +int ar9170_set_operating_mode(struct ar9170 *ar) +{ + u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; + u8 *mac_addr, *bssid; + int err; + + if (ar->vif) { + mac_addr = ar->mac_addr; + bssid = ar->bssid; + + switch (ar->vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; + break; +/* case NL80211_IFTYPE_AP: + pm_mode |= AR9170_MAC_REG_POWERMGT_AP; + break;*/ + case NL80211_IFTYPE_WDS: + pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; + break; + case NL80211_IFTYPE_MONITOR: + ar->sniffer_enabled = true; + ar->rx_software_decryption = true; + break; + default: + pm_mode |= AR9170_MAC_REG_POWERMGT_STA; + break; + } + } else { + mac_addr = NULL; + bssid = NULL; + } + + err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); + if (err) + return err; + + err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); + if (err) + return err; + + err = ar9170_set_promiscouous(ar); + if (err) + return err; + + ar9170_regwrite_begin(ar); + + ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + +int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) +{ + u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); + + return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); +} + +int ar9170_set_beacon_timers(struct ar9170 *ar) +{ + u32 v = 0; + u32 pretbtt = 0; + + v |= ar->hw->conf.beacon_int; + + if (ar->vif) { + switch (ar->vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + v |= BIT(25); + break; + case NL80211_IFTYPE_AP: + v |= BIT(24); + pretbtt = (ar->hw->conf.beacon_int - 6) << 16; + break; + default: + break; + } + + v |= ar->vif->bss_conf.dtim_period << 16; + } + + ar9170_regwrite_begin(ar); + + ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); + ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); + ar9170_regwrite_finish(); + return ar9170_regwrite_result(); +} + +int ar9170_update_beacon(struct ar9170 *ar) +{ + struct sk_buff *skb; + __le32 *data, *old = NULL; + u32 word; + int i; + + skb = ieee80211_beacon_get(ar->hw, ar->vif); + if (!skb) + return -ENOMEM; + + data = (__le32 *)skb->data; + if (ar->beacon) + old = (__le32 *)ar->beacon->data; + + ar9170_regwrite_begin(ar); + for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { + /* + * XXX: This accesses beyond skb data for up + * to the last 3 bytes!! + */ + + if (old && (data[i] == old[i])) + continue; + + word = le32_to_cpu(data[i]); + ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); + } + + /* XXX: use skb->cb info */ + if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) + ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, + ((skb->len + 4) << (3+16)) + 0x0400); + else + ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, + ((skb->len + 4) << (3+16)) + 0x0400); + + ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); + ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); + ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); + + ar9170_regwrite_finish(); + + dev_kfree_skb(ar->beacon); + ar->beacon = skb; + + return ar9170_regwrite_result(); +} + +void ar9170_new_beacon(struct work_struct *work) +{ + struct ar9170 *ar = container_of(work, struct ar9170, + beacon_work); + struct sk_buff *skb; + + if (unlikely(!IS_STARTED(ar))) + return ; + + mutex_lock(&ar->mutex); + + if (!ar->vif) + goto out; + + ar9170_update_beacon(ar); + + rcu_read_lock(); + while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) + ar9170_op_tx(ar->hw, skb); + + rcu_read_unlock(); + + out: + mutex_unlock(&ar->mutex); +} + +int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, + u8 keyidx, u8 *keydata, int keylen) +{ + __le32 vals[7]; + static const u8 bcast[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + u8 dummy; + + mac = mac ? : bcast; + + vals[0] = cpu_to_le32((keyidx << 16) + id); + vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); + vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | + mac[3] << 8 | mac[2]); + memset(&vals[3], 0, 16); + if (keydata) + memcpy(&vals[3], keydata, keylen); + + return ar->exec_cmd(ar, AR9170_CMD_EKEY, + sizeof(vals), (u8 *)vals, + 1, &dummy); +} + +int ar9170_disable_key(struct ar9170 *ar, u8 id) +{ + __le32 val = cpu_to_le32(id); + u8 dummy; + + return ar->exec_cmd(ar, AR9170_CMD_EKEY, + sizeof(val), (u8 *)&val, + 1, &dummy); +} diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c new file mode 100644 index 0000000..8de0ff9 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -0,0 +1,1690 @@ +/* + * Atheros AR9170 driver + * + * mac80211 interaction code + * + * Copyright 2008, Johannes Berg + * Copyright 2009, Christian Lamparter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include "ar9170.h" +#include "hw.h" +#include "cmd.h" + +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate) | (_txpidx) << 4, \ +} + +static struct ieee80211_rate __ar9170_ratetable[] = { + RATE(10, 0, 0, 0), + RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0xb, 0, 0), + RATE(90, 0xf, 0, 0), + RATE(120, 0xa, 0, 0), + RATE(180, 0xe, 0, 0), + RATE(240, 0x9, 0, 0), + RATE(360, 0xd, 1, 0), + RATE(480, 0x8, 2, 0), + RATE(540, 0xc, 3, 0), +}; +#undef RATE + +#define ar9170_g_ratetable (__ar9170_ratetable + 0) +#define ar9170_g_ratetable_size 12 +#define ar9170_a_ratetable (__ar9170_ratetable + 4) +#define ar9170_a_ratetable_size 8 + +/* + * NB: The hw_value is used as an index into the ar9170_phy_freq_params + * array in phy.c so that we don't have to do frequency lookups! + */ +#define CHAN(_freq, _idx) { \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 18, /* XXX */ \ +} + +static struct ieee80211_channel ar9170_2ghz_chantable[] = { + CHAN(2412, 0), + CHAN(2417, 1), + CHAN(2422, 2), + CHAN(2427, 3), + CHAN(2432, 4), + CHAN(2437, 5), + CHAN(2442, 6), + CHAN(2447, 7), + CHAN(2452, 8), + CHAN(2457, 9), + CHAN(2462, 10), + CHAN(2467, 11), + CHAN(2472, 12), + CHAN(2484, 13), +}; + +static struct ieee80211_channel ar9170_5ghz_chantable[] = { + CHAN(4920, 14), + CHAN(4940, 15), + CHAN(4960, 16), + CHAN(4980, 17), + CHAN(5040, 18), + CHAN(5060, 19), + CHAN(5080, 20), + CHAN(5180, 21), + CHAN(5200, 22), + CHAN(5220, 23), + CHAN(5240, 24), + CHAN(5260, 25), + CHAN(5280, 26), + CHAN(5300, 27), + CHAN(5320, 28), + CHAN(5500, 29), + CHAN(5520, 30), + CHAN(5540, 31), + CHAN(5560, 32), + CHAN(5580, 33), + CHAN(5600, 34), + CHAN(5620, 35), + CHAN(5640, 36), + CHAN(5660, 37), + CHAN(5680, 38), + CHAN(5700, 39), + CHAN(5745, 40), + CHAN(5765, 41), + CHAN(5785, 42), + CHAN(5805, 43), + CHAN(5825, 44), + CHAN(5170, 45), + CHAN(5190, 46), + CHAN(5210, 47), + CHAN(5230, 48), +}; +#undef CHAN + +static struct ieee80211_supported_band ar9170_band_2GHz = { + .channels = ar9170_2ghz_chantable, + .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), + .bitrates = ar9170_g_ratetable, + .n_bitrates = ar9170_g_ratetable_size, +}; + +#ifdef AR9170_QUEUE_DEBUG +/* + * In case some wants works with AR9170's crazy tx_status queueing techniques. + * He might need this rather useful probing function. + * + * NOTE: caller must hold the queue's spinlock! + */ + +static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *)txc->frame_data; + + printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " + "mac_control:%04x, phy_control:%08x]\n", + wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), + ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), + le32_to_cpu(txc->phy_control)); +} + +static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, + struct sk_buff_head *queue) +{ + struct sk_buff *skb; + int i = 0; + + printk(KERN_DEBUG "---[ cut here ]---\n"); + printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", + wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); + + skb_queue_walk(queue, skb) { + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *)txc->frame_data; + + printk(KERN_DEBUG "index:%d => \n", i); + ar9170_print_txheader(ar, skb); + } + printk(KERN_DEBUG "---[ end ]---\n"); +} +#endif /* AR9170_QUEUE_DEBUG */ + +static struct ieee80211_supported_band ar9170_band_5GHz = { + .channels = ar9170_5ghz_chantable, + .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), + .bitrates = ar9170_a_ratetable, + .n_bitrates = ar9170_a_ratetable_size, +}; + +void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, + bool valid_status, u16 tx_status) +{ + struct ieee80211_tx_info *txinfo; + unsigned int retries = 0, queue = skb_get_queue_mapping(skb); + unsigned long flags; + + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[queue].len--; + if (ieee80211_queue_stopped(ar->hw, queue)) + ieee80211_wake_queue(ar->hw, queue); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + + txinfo = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(txinfo); + + switch (tx_status) { + case AR9170_TX_STATUS_RETRY: + retries = 2; + case AR9170_TX_STATUS_COMPLETE: + txinfo->flags |= IEEE80211_TX_STAT_ACK; + break; + + case AR9170_TX_STATUS_FAILED: + retries = ar->hw->conf.long_frame_max_tx_count; + break; + + default: + printk(KERN_ERR "%s: invalid tx_status response (%x).\n", + wiphy_name(ar->hw->wiphy), tx_status); + break; + } + + if (valid_status) + txinfo->status.rates[0].count = retries + 1; + + skb_pull(skb, sizeof(struct ar9170_tx_control)); + ieee80211_tx_status_irqsafe(ar->hw, skb); +} + +static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, + const u8 *mac, + const u32 queue, + struct sk_buff_head *q) +{ + unsigned long flags; + struct sk_buff *skb; + + spin_lock_irqsave(&q->lock, flags); + skb_queue_walk(q, skb) { + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + u32 txc_queue = (le32_to_cpu(txc->phy_control) & + AR9170_TX_PHY_QOS_MASK) >> + AR9170_TX_PHY_QOS_SHIFT; + + if ((queue != txc_queue) || + (compare_ether_addr(ieee80211_get_DA(hdr), mac))) + continue; + + __skb_unlink(skb, q); + spin_unlock_irqrestore(&q->lock, flags); + return skb; + } + spin_unlock_irqrestore(&q->lock, flags); + return NULL; +} + +static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, + const u32 queue) +{ + struct ieee80211_sta *sta; + struct sk_buff *skb; + + /* + * Unfortunately, the firmware does not tell to which (queued) frame + * this transmission status report belongs to. + * + * So we have to make risky guesses - with the scarce information + * the firmware provided (-> destination MAC, and phy_control) - + * and hope that we picked the right one... + */ + rcu_read_lock(); + sta = ieee80211_find_sta(ar->hw, mac); + + if (likely(sta)) { + struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; + skb = skb_dequeue(&sta_priv->tx_status[queue]); + rcu_read_unlock(); + if (likely(skb)) + return skb; + } else + rcu_read_unlock(); + + /* scan the waste queue for candidates */ + skb = ar9170_find_skb_in_queue(ar, mac, queue, + &ar->global_tx_status_waste); + if (!skb) { + /* so it still _must_ be in the global list. */ + skb = ar9170_find_skb_in_queue(ar, mac, queue, + &ar->global_tx_status); + } + +#ifdef AR9170_QUEUE_DEBUG + if (unlikely((!skb) && net_ratelimit())) { + printk(KERN_ERR "%s: ESS:[%pM] does not have any " + "outstanding frames in this queue (%d).\n", + wiphy_name(ar->hw->wiphy), mac, queue); + } +#endif /* AR9170_QUEUE_DEBUG */ + return skb; +} + +/* + * This worker tries to keep the global tx_status queue empty. + * So we can guarantee that incoming tx_status reports for + * unregistered stations are always synced with the actual + * frame - which we think - belongs to. + */ + +static void ar9170_tx_status_janitor(struct work_struct *work) +{ + struct ar9170 *ar = container_of(work, struct ar9170, + tx_status_janitor.work); + struct sk_buff *skb; + + if (unlikely(!IS_STARTED(ar))) + return ; + + mutex_lock(&ar->mutex); + /* recycle the garbage back to mac80211... one by one. */ + while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: dispose queued frame =>\n", + wiphy_name(ar->hw->wiphy)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + ar9170_handle_tx_status(ar, skb, false, + AR9170_TX_STATUS_FAILED); + } + + while ((skb = skb_dequeue(&ar->global_tx_status))) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", + wiphy_name(ar->hw->wiphy)); + + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + skb_queue_tail(&ar->global_tx_status_waste, skb); + } + + /* recall the janitor in 100ms - if there's garbage in the can. */ + if (skb_queue_len(&ar->global_tx_status_waste) > 0) + queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, + msecs_to_jiffies(100)); + + mutex_unlock(&ar->mutex); +} + +static void ar9170_handle_command_response(struct ar9170 *ar, + void *buf, u32 len) +{ + struct ar9170_cmd_response *cmd = (void *) buf; + + if ((cmd->type & 0xc0) != 0xc0) { + ar->callback_cmd(ar, len, buf); + return; + } + + /* hardware event handlers */ + switch (cmd->type) { + case 0xc1: { + /* + * TX status notification: + * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 + * + * XX always 81 + * YY always 00 + * M1-M6 is the MAC address + * R1-R4 is the transmit rate + * S1-S2 is the transmit status + */ + + struct sk_buff *skb; + u32 queue = (le32_to_cpu(cmd->tx_status.rate) & + AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; + + skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); + if (unlikely(!skb)) + return ; + + ar9170_handle_tx_status(ar, skb, true, + le16_to_cpu(cmd->tx_status.status)); + break; + } + + case 0xc0: + /* + * pre-TBTT event + */ + if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) + queue_work(ar->hw->workqueue, &ar->beacon_work); + break; + + case 0xc2: + /* + * (IBSS) beacon send notification + * bytes: 04 c2 XX YY B4 B3 B2 B1 + * + * XX always 80 + * YY always 00 + * B1-B4 "should" be the number of send out beacons. + */ + break; + + case 0xc3: + /* End of Atim Window */ + break; + + case 0xc4: + case 0xc5: + /* BlockACK events */ + break; + + case 0xc6: + /* Watchdog Interrupt */ + break; + + case 0xc9: + /* retransmission issue / SIFS/EIFS collision ?! */ + break; + + default: + printk(KERN_INFO "received unhandled event %x\n", cmd->type); + print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); + break; + } +} + +/* + * If the frame alignment is right (or the kernel has + * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there + * is only a single MPDU in the USB frame, then we can + * submit to mac80211 the SKB directly. However, since + * there may be multiple packets in one SKB in stream + * mode, and we need to observe the proper ordering, + * this is non-trivial. + */ +static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +{ + struct sk_buff *skb; + struct ar9170_rx_head *head = (void *)buf; + struct ar9170_rx_tail *tail; + struct ieee80211_rx_status status; + int mpdu_len, i; + u8 error, antennas = 0, decrypt; + __le16 fc; + int reserved; + + if (unlikely(!IS_STARTED(ar))) + return ; + + /* Received MPDU */ + mpdu_len = len; + mpdu_len -= sizeof(struct ar9170_rx_head); + mpdu_len -= sizeof(struct ar9170_rx_tail); + BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); + BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24); + + if (mpdu_len <= FCS_LEN) + return; + + tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len); + + for (i = 0; i < 3; i++) + if (tail->rssi[i] != 0x80) + antennas |= BIT(i); + + /* post-process RSSI */ + for (i = 0; i < 7; i++) + if (tail->rssi[i] & 0x80) + tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f; + + memset(&status, 0, sizeof(status)); + + status.band = ar->channel->band; + status.freq = ar->channel->center_freq; + status.signal = ar->noise[0] + tail->rssi_combined; + status.noise = ar->noise[0]; + status.antenna = antennas; + + switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) { + case AR9170_RX_STATUS_MODULATION_CCK: + if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE) + status.flag |= RX_FLAG_SHORTPRE; + switch (head->plcp[0]) { + case 0x0a: + status.rate_idx = 0; + break; + case 0x14: + status.rate_idx = 1; + break; + case 0x37: + status.rate_idx = 2; + break; + case 0x6e: + status.rate_idx = 3; + break; + default: + if ((!ar->sniffer_enabled) && (net_ratelimit())) + printk(KERN_ERR "%s: invalid plcp cck rate " + "(%x).\n", wiphy_name(ar->hw->wiphy), + head->plcp[0]); + return; + } + break; + case AR9170_RX_STATUS_MODULATION_OFDM: + switch (head->plcp[0] & 0xF) { + case 0xB: + status.rate_idx = 0; + break; + case 0xF: + status.rate_idx = 1; + break; + case 0xA: + status.rate_idx = 2; + break; + case 0xE: + status.rate_idx = 3; + break; + case 0x9: + status.rate_idx = 4; + break; + case 0xD: + status.rate_idx = 5; + break; + case 0x8: + status.rate_idx = 6; + break; + case 0xC: + status.rate_idx = 7; + break; + default: + if ((!ar->sniffer_enabled) && (net_ratelimit())) + printk(KERN_ERR "%s: invalid plcp ofdm rate " + "(%x).\n", wiphy_name(ar->hw->wiphy), + head->plcp[0]); + return; + } + if (status.band == IEEE80211_BAND_2GHZ) + status.rate_idx += 4; + break; + case AR9170_RX_STATUS_MODULATION_HT: + case AR9170_RX_STATUS_MODULATION_DUPOFDM: + /* XXX */ + + if (net_ratelimit()) + printk(KERN_ERR "%s: invalid modulation\n", + wiphy_name(ar->hw->wiphy)); + return; + } + + error = tail->error; + + if (error & AR9170_RX_ERROR_MMIC) { + status.flag |= RX_FLAG_MMIC_ERROR; + error &= ~AR9170_RX_ERROR_MMIC; + } + + if (error & AR9170_RX_ERROR_PLCP) { + status.flag |= RX_FLAG_FAILED_PLCP_CRC; + error &= ~AR9170_RX_ERROR_PLCP; + } + + if (error & AR9170_RX_ERROR_FCS) { + status.flag |= RX_FLAG_FAILED_FCS_CRC; + error &= ~AR9170_RX_ERROR_FCS; + } + + decrypt = ar9170_get_decrypt_type(tail); + if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && + decrypt != AR9170_ENC_ALG_NONE) + status.flag |= RX_FLAG_DECRYPTED; + + /* ignore wrong RA errors */ + error &= ~AR9170_RX_ERROR_WRONG_RA; + + if (error & AR9170_RX_ERROR_DECRYPT) { + error &= ~AR9170_RX_ERROR_DECRYPT; + + /* + * Rx decryption is done in place, + * the original data is lost anyway. + */ + return ; + } + + /* drop any other error frames */ + if ((error) && (net_ratelimit())) { + printk(KERN_DEBUG "%s: errors: %#x\n", + wiphy_name(ar->hw->wiphy), error); + return; + } + + buf += sizeof(struct ar9170_rx_head); + fc = *(__le16 *)buf; + + if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc)) + reserved = 32 + 2; + else + reserved = 32; + + skb = dev_alloc_skb(mpdu_len + reserved); + if (!skb) + return; + + skb_reserve(skb, reserved); + memcpy(skb_put(skb, mpdu_len), buf, mpdu_len); + ieee80211_rx_irqsafe(ar->hw, skb, &status); +} + +void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) +{ + unsigned int i, tlen, resplen; + u8 *tbuf, *respbuf; + + tbuf = skb->data; + tlen = skb->len; + + while (tlen >= 4) { + int clen = tbuf[1] << 8 | tbuf[0]; + int wlen = (clen + 3) & ~3; + + /* + * parse stream (if any) + */ + if (tbuf[2] != 0 || tbuf[3] != 0x4e) { + printk(KERN_ERR "%s: missing tag!\n", + wiphy_name(ar->hw->wiphy)); + return ; + } + if (wlen > tlen - 4) { + printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n", + wiphy_name(ar->hw->wiphy), clen, wlen, tlen); + print_hex_dump(KERN_DEBUG, "data: ", + DUMP_PREFIX_OFFSET, + 16, 1, tbuf, tlen, true); + return ; + } + resplen = clen; + respbuf = tbuf + 4; + tbuf += wlen + 4; + tlen -= wlen + 4; + + i = 0; + + /* weird thing, but this is the same in the original driver */ + while (resplen > 2 && i < 12 && + respbuf[0] == 0xff && respbuf[1] == 0xff) { + i += 2; + resplen -= 2; + respbuf += 2; + } + + if (resplen < 4) + continue; + + /* found the 6 * 0xffff marker? */ + if (i == 12) + ar9170_handle_command_response(ar, respbuf, resplen); + else + ar9170_handle_mpdu(ar, respbuf, resplen); + } + + if (tlen) + printk(KERN_ERR "%s: buffer remains!\n", + wiphy_name(ar->hw->wiphy)); +} + +#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ +do { \ + queue.aifs = ai_fs; \ + queue.cw_min = cwmin; \ + queue.cw_max = cwmax; \ + queue.txop = _txop; \ +} while (0) + +static int ar9170_op_start(struct ieee80211_hw *hw) +{ + struct ar9170 *ar = hw->priv; + int err, i; + + mutex_lock(&ar->mutex); + + /* reinitialize queues statistics */ + memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); + for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) + ar->tx_stats[i].limit = 8; + + /* reset QoS defaults */ + AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ + AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ + AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ + AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ + AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ + + err = ar->open(ar); + if (err) + goto out; + + err = ar9170_init_mac(ar); + if (err) + goto out; + + err = ar9170_set_qos(ar); + if (err) + goto out; + + err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); + if (err) + goto out; + + err = ar9170_init_rf(ar); + if (err) + goto out; + + /* start DMA */ + err = ar9170_write_reg(ar, 0x1c3d30, 0x100); + if (err) + goto out; + + ar->state = AR9170_STARTED; + +out: + mutex_unlock(&ar->mutex); + return err; +} + +static void ar9170_op_stop(struct ieee80211_hw *hw) +{ + struct ar9170 *ar = hw->priv; + + if (IS_STARTED(ar)) + ar->state = AR9170_IDLE; + + flush_workqueue(ar->hw->workqueue); + + mutex_lock(&ar->mutex); + cancel_delayed_work_sync(&ar->tx_status_janitor); + cancel_work_sync(&ar->filter_config_work); + cancel_work_sync(&ar->beacon_work); + skb_queue_purge(&ar->global_tx_status_waste); + skb_queue_purge(&ar->global_tx_status); + + if (IS_ACCEPTING_CMD(ar)) { + ar9170_set_leds_state(ar, 0); + + /* stop DMA */ + ar9170_write_reg(ar, 0x1c3d30, 0); + ar->stop(ar); + } + + mutex_unlock(&ar->mutex); +} + +int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ar9170 *ar = hw->priv; + struct ieee80211_hdr *hdr; + struct ar9170_tx_control *txc; + struct ieee80211_tx_info *info; + struct ieee80211_rate *rate = NULL; + struct ieee80211_tx_rate *txrate; + unsigned int queue = skb_get_queue_mapping(skb); + unsigned long flags = 0; + struct ar9170_sta_info *sta_info = NULL; + u32 power, chains; + u16 keytype = 0; + u16 len, icv = 0; + int err; + bool tx_status; + + if (unlikely(!IS_STARTED(ar))) + goto err_free; + + hdr = (void *)skb->data; + info = IEEE80211_SKB_CB(skb); + len = skb->len; + + spin_lock_irqsave(&ar->tx_stats_lock, flags); + if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + return NETDEV_TX_OK; + } + + ar->tx_stats[queue].len++; + ar->tx_stats[queue].count++; + if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) + ieee80211_stop_queue(hw, queue); + + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + + txc = (void *)skb_push(skb, sizeof(*txc)); + + tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || + ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); + + if (info->control.hw_key) { + icv = info->control.hw_key->icv_len; + + switch (info->control.hw_key->alg) { + case ALG_WEP: + keytype = AR9170_TX_MAC_ENCR_RC4; + break; + case ALG_TKIP: + keytype = AR9170_TX_MAC_ENCR_RC4; + break; + case ALG_CCMP: + keytype = AR9170_TX_MAC_ENCR_AES; + break; + default: + WARN_ON(1); + goto err_dequeue; + } + } + + /* Length */ + txc->length = cpu_to_le16(len + icv + 4); + + txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | + AR9170_TX_MAC_BACKOFF); + txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << + AR9170_TX_MAC_QOS_SHIFT); + txc->mac_control |= cpu_to_le16(keytype); + txc->phy_control = cpu_to_le32(0); + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); + + txrate = &info->control.rates[0]; + + if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); + else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); + + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) + txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); + + if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); + + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); + /* this works because 40 MHz is 2 and dup is 3 */ + if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) + txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); + + if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) + txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); + + if (txrate->flags & IEEE80211_TX_RC_MCS) { + u32 r = txrate->idx; + u8 *txpower; + + r <<= AR9170_TX_PHY_MCS_SHIFT; + if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) + goto err_dequeue; + txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); + txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); + + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { + if (info->band == IEEE80211_BAND_5GHZ) + txpower = ar->power_5G_ht40; + else + txpower = ar->power_2G_ht40; + } else { + if (info->band == IEEE80211_BAND_5GHZ) + txpower = ar->power_5G_ht20; + else + txpower = ar->power_2G_ht20; + } + + power = txpower[(txrate->idx) & 7]; + } else { + u8 *txpower; + u32 mod; + u32 phyrate; + u8 idx = txrate->idx; + + if (info->band != IEEE80211_BAND_2GHZ) { + idx += 4; + txpower = ar->power_5G_leg; + mod = AR9170_TX_PHY_MOD_OFDM; + } else { + if (idx < 4) { + txpower = ar->power_2G_cck; + mod = AR9170_TX_PHY_MOD_CCK; + } else { + mod = AR9170_TX_PHY_MOD_OFDM; + txpower = ar->power_2G_ofdm; + } + } + + rate = &__ar9170_ratetable[idx]; + + phyrate = rate->hw_value & 0xF; + power = txpower[(rate->hw_value & 0x30) >> 4]; + phyrate <<= AR9170_TX_PHY_MCS_SHIFT; + + txc->phy_control |= cpu_to_le32(mod); + txc->phy_control |= cpu_to_le32(phyrate); + } + + power <<= AR9170_TX_PHY_TX_PWR_SHIFT; + power &= AR9170_TX_PHY_TX_PWR_MASK; + txc->phy_control |= cpu_to_le32(power); + + /* set TX chains */ + if (ar->eeprom.tx_mask == 1) { + chains = AR9170_TX_PHY_TXCHAIN_1; + } else { + chains = AR9170_TX_PHY_TXCHAIN_2; + + /* >= 36M legacy OFDM - use only one chain */ + if (rate && rate->bitrate >= 360) + chains = AR9170_TX_PHY_TXCHAIN_1; + } + txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); + + if (tx_status) { + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); + /* + * WARNING: + * Putting the QoS queue bits into an unexplored territory is + * certainly not elegant. + * + * In my defense: This idea provides a reasonable way to + * smuggle valuable information to the tx_status callback. + * Also, the idea behind this bit-abuse came straight from + * the original driver code. + */ + + txc->phy_control |= + cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + + if (info->control.sta) { + sta_info = (void *) info->control.sta->drv_priv; + skb_queue_tail(&sta_info->tx_status[queue], skb); + } else { + skb_queue_tail(&ar->global_tx_status, skb); + + queue_delayed_work(ar->hw->workqueue, + &ar->tx_status_janitor, + msecs_to_jiffies(100)); + } + } + + err = ar->tx(ar, skb, tx_status, 0); + if (unlikely(tx_status && err)) { + if (info->control.sta) + skb_unlink(skb, &sta_info->tx_status[queue]); + else + skb_unlink(skb, &ar->global_tx_status); + } + + return NETDEV_TX_OK; + +err_dequeue: + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[queue].len--; + ar->tx_stats[queue].count--; + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + +err_free: + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static int ar9170_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ar9170 *ar = hw->priv; + int err = 0; + + mutex_lock(&ar->mutex); + + if (ar->vif) { + err = -EBUSY; + goto unlock; + } + + ar->vif = conf->vif; + memcpy(ar->mac_addr, conf->mac_addr, ETH_ALEN); + + if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { + ar->rx_software_decryption = true; + ar->disable_offload = true; + } + + ar->cur_filter = 0; + ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS; + err = ar9170_update_frame_filter(ar); + if (err) + goto unlock; + + err = ar9170_set_operating_mode(ar); + +unlock: + mutex_unlock(&ar->mutex); + return err; +} + +static void ar9170_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ar9170 *ar = hw->priv; + + mutex_lock(&ar->mutex); + ar->vif = NULL; + ar->want_filter = 0; + ar9170_update_frame_filter(ar); + ar9170_set_beacon_timers(ar); + dev_kfree_skb(ar->beacon); + ar->beacon = NULL; + ar->sniffer_enabled = false; + ar->rx_software_decryption = false; + ar9170_set_operating_mode(ar); + mutex_unlock(&ar->mutex); +} + +static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ar9170 *ar = hw->priv; + int err = 0; + + mutex_lock(&ar->mutex); + + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { + /* TODO */ + err = 0; + } + + if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { + /* TODO */ + err = 0; + } + + if (changed & IEEE80211_CONF_CHANGE_PS) { + /* TODO */ + err = 0; + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + /* TODO */ + err = 0; + } + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + /* + * is it long_frame_max_tx_count or short_frame_max_tx_count? + */ + + err = ar9170_set_hwretry_limit(ar, + ar->hw->conf.long_frame_max_tx_count); + if (err) + goto out; + } + + if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) { + err = ar9170_set_beacon_timers(ar); + if (err) + goto out; + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + err = ar9170_set_channel(ar, hw->conf.channel, + AR9170_RFI_NONE, AR9170_BW_20); + if (err) + goto out; + /* adjust slot time for 5 GHz */ + if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) + err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, + 9 << 10); + } + +out: + mutex_unlock(&ar->mutex); + return err; +} + +static int ar9170_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct ar9170 *ar = hw->priv; + int err = 0; + + mutex_lock(&ar->mutex); + + if (conf->changed & IEEE80211_IFCC_BSSID) { + memcpy(ar->bssid, conf->bssid, ETH_ALEN); + err = ar9170_set_operating_mode(ar); + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + err = ar9170_update_beacon(ar); + + if (err) + goto out; + err = ar9170_set_beacon_timers(ar); + } + +out: + mutex_unlock(&ar->mutex); + return err; +} + +static void ar9170_set_filters(struct work_struct *work) +{ + struct ar9170 *ar = container_of(work, struct ar9170, + filter_config_work); + int err; + + if (unlikely(!IS_STARTED(ar))) + return ; + + mutex_lock(&ar->mutex); + if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { + err = ar9170_set_operating_mode(ar); + if (err) + goto unlock; + } + + if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { + err = ar9170_update_multicast(ar); + if (err) + goto unlock; + } + + if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) + err = ar9170_update_frame_filter(ar); + +unlock: + mutex_unlock(&ar->mutex); +} + +static void ar9170_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct ar9170 *ar = hw->priv; + + /* mask supported flags */ + *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | + FIF_PROMISC_IN_BSS; + + /* + * We can support more by setting the sniffer bit and + * then checking the error flags, later. + */ + + if (changed_flags & FIF_ALLMULTI) { + if (*new_flags & FIF_ALLMULTI) { + ar->want_mc_hash = ~0ULL; + } else { + u64 mchash; + int i; + + /* always get broadcast frames */ + mchash = 1ULL << (0xff>>2); + + for (i = 0; i < mc_count; i++) { + if (WARN_ON(!mclist)) + break; + mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); + mclist = mclist->next; + } + ar->want_mc_hash = mchash; + } + ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; + } + + if (changed_flags & FIF_CONTROL) { + u32 filter = AR9170_MAC_REG_FTF_PSPOLL | + AR9170_MAC_REG_FTF_RTS | + AR9170_MAC_REG_FTF_CTS | + AR9170_MAC_REG_FTF_ACK | + AR9170_MAC_REG_FTF_CFE | + AR9170_MAC_REG_FTF_CFE_ACK; + + if (*new_flags & FIF_CONTROL) + ar->want_filter = ar->cur_filter | filter; + else + ar->want_filter = ar->cur_filter & ~filter; + + ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; + } + + if (changed_flags & FIF_PROMISC_IN_BSS) { + ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; + ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; + } + + if (likely(IS_STARTED(ar))) + queue_work(ar->hw->workqueue, &ar->filter_config_work); +} + +static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct ar9170 *ar = hw->priv; + int err = 0; + + mutex_lock(&ar->mutex); + + ar9170_regwrite_begin(ar); + + if (changed & BSS_CHANGED_ASSOC) { + ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; + +#ifndef CONFIG_AR9170_LEDS + /* enable assoc LED. */ + err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); +#endif /* CONFIG_AR9170_LEDS */ + } + + if (changed & BSS_CHANGED_HT) { + /* TODO */ + err = 0; + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + u32 slottime = 20; + + if (bss_conf->use_short_slot) + slottime = 9; + + ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + u32 cck, ofdm; + + if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { + ofdm = bss_conf->basic_rates; + cck = 0; + } else { + /* four cck rates */ + cck = bss_conf->basic_rates & 0xf; + ofdm = bss_conf->basic_rates >> 4; + } + ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, + ofdm << 8 | cck); + } + + ar9170_regwrite_finish(); + err = ar9170_regwrite_result(); + mutex_unlock(&ar->mutex); +} + +static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) +{ + struct ar9170 *ar = hw->priv; + int err; + u32 tsf_low; + u32 tsf_high; + u64 tsf; + + mutex_lock(&ar->mutex); + err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_L, &tsf_low); + if (!err) + err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_H, &tsf_high); + mutex_unlock(&ar->mutex); + + if (WARN_ON(err)) + return 0; + + tsf = tsf_high; + tsf = (tsf << 32) | tsf_low; + return tsf; +} + +static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ar9170 *ar = hw->priv; + int err = 0, i; + u8 ktype; + + if ((!ar->vif) || (ar->disable_offload)) + return -EOPNOTSUPP; + + switch (key->alg) { + case ALG_WEP: + if (key->keylen == LEN_WEP40) + ktype = AR9170_ENC_ALG_WEP64; + else + ktype = AR9170_ENC_ALG_WEP128; + break; + case ALG_TKIP: + ktype = AR9170_ENC_ALG_TKIP; + break; + case ALG_CCMP: + ktype = AR9170_ENC_ALG_AESCCMP; + break; + default: + return -EOPNOTSUPP; + } + + mutex_lock(&ar->mutex); + if (cmd == SET_KEY) { + if (unlikely(!IS_STARTED(ar))) { + err = -EOPNOTSUPP; + goto out; + } + + /* group keys need all-zeroes address */ + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + sta = NULL; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + for (i = 0; i < 64; i++) + if (!(ar->usedkeys & BIT(i))) + break; + if (i == 64) { + ar->rx_software_decryption = true; + ar9170_set_operating_mode(ar); + err = -ENOSPC; + goto out; + } + } else { + i = 64 + key->keyidx; + } + + key->hw_key_idx = i; + + err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, + key->key, min_t(u8, 16, key->keylen)); + if (err) + goto out; + + if (key->alg == ALG_TKIP) { + err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, + ktype, 1, key->key + 16, 16); + if (err) + goto out; + + /* + * hardware is not capable generating the MMIC + * for fragmented frames! + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + } + + if (i < 64) + ar->usedkeys |= BIT(i); + + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } else { + if (unlikely(!IS_STARTED(ar))) { + /* The device is gone... together with the key ;-) */ + err = 0; + goto out; + } + + err = ar9170_disable_key(ar, key->hw_key_idx); + if (err) + goto out; + + if (key->hw_key_idx < 64) { + ar->usedkeys &= ~BIT(key->hw_key_idx); + } else { + err = ar9170_upload_key(ar, key->hw_key_idx, NULL, + AR9170_ENC_ALG_NONE, 0, + NULL, 0); + if (err) + goto out; + + if (key->alg == ALG_TKIP) { + err = ar9170_upload_key(ar, key->hw_key_idx, + NULL, + AR9170_ENC_ALG_NONE, 1, + NULL, 0); + if (err) + goto out; + } + + } + } + + ar9170_regwrite_begin(ar); + ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); + ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); + ar9170_regwrite_finish(); + err = ar9170_regwrite_result(); + +out: + mutex_unlock(&ar->mutex); + + return err; +} + +static void ar9170_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct ar9170 *ar = hw->priv; + struct ar9170_sta_info *info = (void *) sta->drv_priv; + struct sk_buff *skb; + unsigned int i; + + switch (cmd) { + case STA_NOTIFY_ADD: + for (i = 0; i < ar->hw->queues; i++) + skb_queue_head_init(&info->tx_status[i]); + break; + + case STA_NOTIFY_REMOVE: + + /* + * transfer all outstanding frames that need a tx_status + * reports to the global tx_status queue + */ + + for (i = 0; i < ar->hw->queues; i++) { + while ((skb = skb_dequeue(&info->tx_status[i]))) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: queueing frame in " + "global tx_status queue =>\n", + wiphy_name(ar->hw->wiphy)); + + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + skb_queue_tail(&ar->global_tx_status, skb); + } + } + queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, + msecs_to_jiffies(100)); + break; + + default: + break; + } +} + +static int ar9170_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct ar9170 *ar = hw->priv; + u32 val; + int err; + + mutex_lock(&ar->mutex); + err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); + ar->stats.dot11ACKFailureCount += val; + + memcpy(stats, &ar->stats, sizeof(*stats)); + mutex_unlock(&ar->mutex); + + return 0; +} + +static int ar9170_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *tx_stats) +{ + struct ar9170 *ar = hw->priv; + + spin_lock_bh(&ar->tx_stats_lock); + memcpy(tx_stats, ar->tx_stats, sizeof(tx_stats[0]) * hw->queues); + spin_unlock_bh(&ar->tx_stats_lock); + + return 0; +} + +static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *param) +{ + struct ar9170 *ar = hw->priv; + int ret; + + mutex_lock(&ar->mutex); + if ((param) && !(queue > ar->hw->queues)) { + memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], + param, sizeof(*param)); + + ret = ar9170_set_qos(ar); + } else + ret = -EINVAL; + + mutex_unlock(&ar->mutex); + return ret; +} + +static const struct ieee80211_ops ar9170_ops = { + .start = ar9170_op_start, + .stop = ar9170_op_stop, + .tx = ar9170_op_tx, + .add_interface = ar9170_op_add_interface, + .remove_interface = ar9170_op_remove_interface, + .config = ar9170_op_config, + .config_interface = ar9170_op_config_interface, + .configure_filter = ar9170_op_configure_filter, + .conf_tx = ar9170_conf_tx, + .bss_info_changed = ar9170_op_bss_info_changed, + .get_tsf = ar9170_op_get_tsf, + .set_key = ar9170_set_key, + .sta_notify = ar9170_sta_notify, + .get_stats = ar9170_get_stats, + .get_tx_stats = ar9170_get_tx_stats, +}; + +void *ar9170_alloc(size_t priv_size) +{ + struct ieee80211_hw *hw; + struct ar9170 *ar; + int i; + + hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); + if (!hw) + return ERR_PTR(-ENOMEM); + + ar = hw->priv; + ar->hw = hw; + + mutex_init(&ar->mutex); + spin_lock_init(&ar->cmdlock); + spin_lock_init(&ar->tx_stats_lock); + skb_queue_head_init(&ar->global_tx_status); + skb_queue_head_init(&ar->global_tx_status_waste); + INIT_WORK(&ar->filter_config_work, ar9170_set_filters); + INIT_WORK(&ar->beacon_work, ar9170_new_beacon); + INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); + + /* all hw supports 2.4 GHz, so set channel to 1 by default */ + ar->channel = &ar9170_2ghz_chantable[0]; + + /* first part of wiphy init */ + ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_WDS) | + BIT(NL80211_IFTYPE_ADHOC); + ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + ar->hw->queues = __AR9170_NUM_TXQ; + ar->hw->extra_tx_headroom = 8; + ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); + + ar->hw->max_rates = 1; + ar->hw->max_rate_tries = 3; + + for (i = 0; i < ARRAY_SIZE(ar->noise); i++) + ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ + + return ar; +} + +static int ar9170_read_eeprom(struct ar9170 *ar) +{ +#define RW 8 /* number of words to read at once */ +#define RB (sizeof(u32) * RW) + DECLARE_MAC_BUF(mbuf); + u8 *eeprom = (void *)&ar->eeprom; + u8 *addr = ar->eeprom.mac_address; + __le32 offsets[RW]; + int i, j, err, bands = 0; + + BUILD_BUG_ON(sizeof(ar->eeprom) & 3); + + BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); +#ifndef __CHECKER__ + /* don't want to handle trailing remains */ + BUILD_BUG_ON(sizeof(ar->eeprom) % RB); +#endif + + for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { + for (j = 0; j < RW; j++) + offsets[j] = cpu_to_le32(AR9170_EEPROM_START + + RB * i + 4 * j); + + err = ar->exec_cmd(ar, AR9170_CMD_RREG, + RB, (u8 *) &offsets, + RB, eeprom + RB * i); + if (err) + return err; + } + +#undef RW +#undef RB + + if (ar->eeprom.length == cpu_to_le16(0xFFFF)) + return -ENODATA; + + if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { + ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; + bands++; + } + if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { + ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; + bands++; + } + /* + * I measured this, a bandswitch takes roughly + * 135 ms and a frequency switch about 80. + * + * FIXME: measure these values again once EEPROM settings + * are used, that will influence them! + */ + if (bands == 2) + ar->hw->channel_change_time = 135 * 1000; + else + ar->hw->channel_change_time = 80 * 1000; + + ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); + ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); + + /* second part of wiphy init */ + SET_IEEE80211_PERM_ADDR(ar->hw, addr); + + return bands ? 0 : -EINVAL; +} + +static int ar9170_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ar9170 *ar = hw->priv; + + return ath_reg_notifier_apply(wiphy, request, &ar->regulatory); +} + +int ar9170_register(struct ar9170 *ar, struct device *pdev) +{ + int err; + + /* try to read EEPROM, init MAC addr */ + err = ar9170_read_eeprom(ar); + if (err) + goto err_out; + + err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, + ar9170_reg_notifier); + + err = ieee80211_register_hw(ar->hw); + if (err) + goto err_out; + + if (!ath_is_world_regd(&ar->regulatory)) + regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2); + + err = ar9170_init_leds(ar); + if (err) + goto err_unreg; + +#ifdef CONFIG_AR9170_LEDS + err = ar9170_register_leds(ar); + if (err) + goto err_unreg; +#endif /* CONFIG_AR9170_LEDS */ + + dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", + wiphy_name(ar->hw->wiphy)); + + return err; + +err_unreg: + ieee80211_unregister_hw(ar->hw); + +err_out: + return err; +} + +void ar9170_unregister(struct ar9170 *ar) +{ +#ifdef CONFIG_AR9170_LEDS + ar9170_unregister_leds(ar); +#endif /* CONFIG_AR9170_LEDS */ + + ieee80211_unregister_hw(ar->hw); + mutex_destroy(&ar->mutex); +} diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c new file mode 100644 index 0000000..6ce2075 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -0,0 +1,1240 @@ +/* + * Atheros AR9170 driver + * + * PHY and RF code + * + * Copyright 2008, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "ar9170.h" +#include "cmd.h" + +static int ar9170_init_power_cal(struct ar9170 *ar) +{ + ar9170_regwrite_begin(ar); + + ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); + ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); + ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); + + ar9170_regwrite_finish(); + return ar9170_regwrite_result(); +} + +struct ar9170_phy_init { + u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; +}; + +static struct ar9170_phy_init ar5416_phy_init[] = { + { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, + { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, + { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, + { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, + { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, + { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, + { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, + { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, + { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, + { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, + { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, + { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, + { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, + { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, + { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, + { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, + { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, + { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, + { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, + { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, + { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, + { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, + { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, + { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, + { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, + { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, + { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, + { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, + { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, + { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, + { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, + { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, + { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, + { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, + { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, + { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, + { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, + { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, + { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, + { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, + { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, + { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, + { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, + { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, + { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, + { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, + { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, + { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, + { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, + { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, + { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, + { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, + { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, + { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, + { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, + { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, + { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, + { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, + { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, + { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, + { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, + { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, + { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, + { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, + { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, + { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, + { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, + { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, + { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, + { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, + { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, + { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, + { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, + { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, + { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, + { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, + { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, + { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, + { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, + { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, + { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, + { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, + { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, + { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, + { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, + { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, + { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, + { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, + { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, + { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, + { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, + { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, + { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, + { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, + { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, + { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, + { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, + { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, + { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, + { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, + { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, + { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, + { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, + { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, + { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, + { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, + { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, + { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, + { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, + { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, + { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, + { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, + { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, + { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, + { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, + { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, + { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, + { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, + { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, + { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, + { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, + { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, + { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, + { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, + { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, + { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, + { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, + { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, + { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, + { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, + { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, + { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, + { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, + { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, + { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, + { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, + { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, + { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, + { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, + { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, + { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, + { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, + { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, + { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, + { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, + { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, + { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, + { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, + { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, + { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, + { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, + { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, + { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, + { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, + { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, + { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, + { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, + { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, + { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, + { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, + { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, + { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, + { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, + { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, + { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, + { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, + { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, + { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, + { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, + { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, + { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, + { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, + { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, + { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, + { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, + { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, + { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, + { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, + { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, + { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, + { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, + { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, + { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, + { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, + { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, + { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, + { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, + { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, + { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, + { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, + { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, + { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, + { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, + { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, + { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, + { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, + { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, + { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, +/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ + { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, + { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, + { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, + { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, + { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, + { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, + { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, + { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, + { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, + { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, + { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, + { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, + { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, + { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, + { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, + { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } +}; + +int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) +{ + int i, err; + u32 val; + bool is_2ghz = band == IEEE80211_BAND_2GHZ; + bool is_40mhz = false; /* XXX: for now */ + + ar9170_regwrite_begin(ar); + + for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { + if (is_40mhz) { + if (is_2ghz) + val = ar5416_phy_init[i]._2ghz_40; + else + val = ar5416_phy_init[i]._5ghz_40; + } else { + if (is_2ghz) + val = ar5416_phy_init[i]._2ghz_20; + else + val = ar5416_phy_init[i]._5ghz_20; + } + + ar9170_regwrite(ar5416_phy_init[i].reg, val); + } + + ar9170_regwrite_finish(); + err = ar9170_regwrite_result(); + if (err) + return err; + + /* XXX: use EEPROM data here! */ + + err = ar9170_init_power_cal(ar); + if (err) + return err; + + /* XXX: remove magic! */ + if (is_2ghz) + err = ar9170_write_reg(ar, 0x1d4014, 0x5163); + else + err = ar9170_write_reg(ar, 0x1d4014, 0x5143); + + return err; +} + +struct ar9170_rf_init { + u32 reg, _5ghz, _2ghz; +}; + +static struct ar9170_rf_init ar9170_rf_init[] = { + /* bank 0 */ + { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, + { 0x1c58e0, 0x02008020, 0x02008020}, + /* bank 1 */ + { 0x1c58b0, 0x02108421, 0x02108421}, + { 0x1c58ec, 0x00000008, 0x00000008}, + /* bank 2 */ + { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, + { 0x1c58e0, 0x00000420, 0x00000420}, + /* bank 3 */ + { 0x1c58f0, 0x01400018, 0x01c00018}, + /* bank 4 */ + { 0x1c58b0, 0x000001a1, 0x000001a1}, + { 0x1c58e8, 0x00000001, 0x00000001}, + /* bank 5 */ + { 0x1c58b0, 0x00000013, 0x00000013}, + { 0x1c58e4, 0x00000002, 0x00000002}, + /* bank 6 */ + { 0x1c58b0, 0x00000000, 0x00000000}, + { 0x1c58b0, 0x00000000, 0x00000000}, + { 0x1c58b0, 0x00000000, 0x00000000}, + { 0x1c58b0, 0x00000000, 0x00000000}, + { 0x1c58b0, 0x00000000, 0x00000000}, + { 0x1c58b0, 0x00004000, 0x00004000}, + { 0x1c58b0, 0x00006c00, 0x00006c00}, + { 0x1c58b0, 0x00002c00, 0x00002c00}, + { 0x1c58b0, 0x00004800, 0x00004800}, + { 0x1c58b0, 0x00004000, 0x00004000}, + { 0x1c58b0, 0x00006000, 0x00006000}, + { 0x1c58b0, 0x00001000, 0x00001000}, + { 0x1c58b0, 0x00004000, 0x00004000}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00087c00, 0x00087c00}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00005400, 0x00005400}, + { 0x1c58b0, 0x00000c00, 0x00000c00}, + { 0x1c58b0, 0x00001800, 0x00001800}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00006c00, 0x00006c00}, + { 0x1c58b0, 0x00006c00, 0x00006c00}, + { 0x1c58b0, 0x00007c00, 0x00007c00}, + { 0x1c58b0, 0x00002c00, 0x00002c00}, + { 0x1c58b0, 0x00003c00, 0x00003c00}, + { 0x1c58b0, 0x00003800, 0x00003800}, + { 0x1c58b0, 0x00001c00, 0x00001c00}, + { 0x1c58b0, 0x00000800, 0x00000800}, + { 0x1c58b0, 0x00000408, 0x00000408}, + { 0x1c58b0, 0x00004c15, 0x00004c15}, + { 0x1c58b0, 0x00004188, 0x00004188}, + { 0x1c58b0, 0x0000201e, 0x0000201e}, + { 0x1c58b0, 0x00010408, 0x00010408}, + { 0x1c58b0, 0x00000801, 0x00000801}, + { 0x1c58b0, 0x00000c08, 0x00000c08}, + { 0x1c58b0, 0x0000181e, 0x0000181e}, + { 0x1c58b0, 0x00001016, 0x00001016}, + { 0x1c58b0, 0x00002800, 0x00002800}, + { 0x1c58b0, 0x00004010, 0x00004010}, + { 0x1c58b0, 0x0000081c, 0x0000081c}, + { 0x1c58b0, 0x00000115, 0x00000115}, + { 0x1c58b0, 0x00000015, 0x00000015}, + { 0x1c58b0, 0x00000066, 0x00000066}, + { 0x1c58b0, 0x0000001c, 0x0000001c}, + { 0x1c58b0, 0x00000000, 0x00000000}, + { 0x1c58b0, 0x00000004, 0x00000004}, + { 0x1c58b0, 0x00000015, 0x00000015}, + { 0x1c58b0, 0x0000001f, 0x0000001f}, + { 0x1c58e0, 0x00000000, 0x00000400}, + /* bank 7 */ + { 0x1c58b0, 0x000000a0, 0x000000a0}, + { 0x1c58b0, 0x00000000, 0x00000000}, + { 0x1c58b0, 0x00000040, 0x00000040}, + { 0x1c58f0, 0x0000001c, 0x0000001c}, +}; + +static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) +{ + int err, i; + + ar9170_regwrite_begin(ar); + + for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) + ar9170_regwrite(ar9170_rf_init[i].reg, + band5ghz ? ar9170_rf_init[i]._5ghz + : ar9170_rf_init[i]._2ghz); + + ar9170_regwrite_finish(); + err = ar9170_regwrite_result(); + if (err) + printk(KERN_ERR "%s: rf init failed\n", + wiphy_name(ar->hw->wiphy)); + return err; +} + +static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, + u32 freq, enum ar9170_bw bw) +{ + int err; + u32 d0, d1, td0, td1, fd0, fd1; + u8 chansel; + u8 refsel0 = 1, refsel1 = 0; + u8 lf_synth = 0; + + switch (bw) { + case AR9170_BW_40_ABOVE: + freq += 10; + break; + case AR9170_BW_40_BELOW: + freq -= 10; + break; + case AR9170_BW_20: + break; + case __AR9170_NUM_BW: + BUG(); + } + + if (band5ghz) { + if (freq % 10) { + chansel = (freq - 4800) / 5; + } else { + chansel = ((freq - 4800) / 10) * 2; + refsel0 = 0; + refsel1 = 1; + } + chansel = byte_rev_table[chansel]; + } else { + if (freq == 2484) { + chansel = 10 + (freq - 2274) / 5; + lf_synth = 1; + } else + chansel = 16 + (freq - 2272) / 5; + chansel *= 4; + chansel = byte_rev_table[chansel]; + } + + d1 = chansel; + d0 = 0x21 | + refsel0 << 3 | + refsel1 << 2 | + lf_synth << 1; + td0 = d0 & 0x1f; + td1 = d1 & 0x1f; + fd0 = td1 << 5 | td0; + + td0 = (d0 >> 5) & 0x7; + td1 = (d1 >> 5) & 0x7; + fd1 = td1 << 5 | td0; + + ar9170_regwrite_begin(ar); + + ar9170_regwrite(0x1c58b0, fd0); + ar9170_regwrite(0x1c58e8, fd1); + + ar9170_regwrite_finish(); + err = ar9170_regwrite_result(); + if (err) + return err; + + msleep(10); + + return 0; +} + +struct ar9170_phy_freq_params { + u8 coeff_exp; + u16 coeff_man; + u8 coeff_exp_shgi; + u16 coeff_man_shgi; +}; + +struct ar9170_phy_freq_entry { + u16 freq; + struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; +}; + +/* NB: must be in sync with channel tables in main! */ +static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { +/* + * freq, + * 20MHz, + * 40MHz (below), + * 40Mhz (above), + */ + { 2412, { + { 3, 21737, 3, 19563, }, + { 3, 21827, 3, 19644, }, + { 3, 21647, 3, 19482, }, + } }, + { 2417, { + { 3, 21692, 3, 19523, }, + { 3, 21782, 3, 19604, }, + { 3, 21602, 3, 19442, }, + } }, + { 2422, { + { 3, 21647, 3, 19482, }, + { 3, 21737, 3, 19563, }, + { 3, 21558, 3, 19402, }, + } }, + { 2427, { + { 3, 21602, 3, 19442, }, + { 3, 21692, 3, 19523, }, + { 3, 21514, 3, 19362, }, + } }, + { 2432, { + { 3, 21558, 3, 19402, }, + { 3, 21647, 3, 19482, }, + { 3, 21470, 3, 19323, }, + } }, + { 2437, { + { 3, 21514, 3, 19362, }, + { 3, 21602, 3, 19442, }, + { 3, 21426, 3, 19283, }, + } }, + { 2442, { + { 3, 21470, 3, 19323, }, + { 3, 21558, 3, 19402, }, + { 3, 21382, 3, 19244, }, + } }, + { 2447, { + { 3, 21426, 3, 19283, }, + { 3, 21514, 3, 19362, }, + { 3, 21339, 3, 19205, }, + } }, + { 2452, { + { 3, 21382, 3, 19244, }, + { 3, 21470, 3, 19323, }, + { 3, 21295, 3, 19166, }, + } }, + { 2457, { + { 3, 21339, 3, 19205, }, + { 3, 21426, 3, 19283, }, + { 3, 21252, 3, 19127, }, + } }, + { 2462, { + { 3, 21295, 3, 19166, }, + { 3, 21382, 3, 19244, }, + { 3, 21209, 3, 19088, }, + } }, + { 2467, { + { 3, 21252, 3, 19127, }, + { 3, 21339, 3, 19205, }, + { 3, 21166, 3, 19050, }, + } }, + { 2472, { + { 3, 21209, 3, 19088, }, + { 3, 21295, 3, 19166, }, + { 3, 21124, 3, 19011, }, + } }, + { 2484, { + { 3, 21107, 3, 18996, }, + { 3, 21192, 3, 19073, }, + { 3, 21022, 3, 18920, }, + } }, + { 4920, { + { 4, 21313, 4, 19181, }, + { 4, 21356, 4, 19220, }, + { 4, 21269, 4, 19142, }, + } }, + { 4940, { + { 4, 21226, 4, 19104, }, + { 4, 21269, 4, 19142, }, + { 4, 21183, 4, 19065, }, + } }, + { 4960, { + { 4, 21141, 4, 19027, }, + { 4, 21183, 4, 19065, }, + { 4, 21098, 4, 18988, }, + } }, + { 4980, { + { 4, 21056, 4, 18950, }, + { 4, 21098, 4, 18988, }, + { 4, 21014, 4, 18912, }, + } }, + { 5040, { + { 4, 20805, 4, 18725, }, + { 4, 20846, 4, 18762, }, + { 4, 20764, 4, 18687, }, + } }, + { 5060, { + { 4, 20723, 4, 18651, }, + { 4, 20764, 4, 18687, }, + { 4, 20682, 4, 18614, }, + } }, + { 5080, { + { 4, 20641, 4, 18577, }, + { 4, 20682, 4, 18614, }, + { 4, 20601, 4, 18541, }, + } }, + { 5180, { + { 4, 20243, 4, 18219, }, + { 4, 20282, 4, 18254, }, + { 4, 20204, 4, 18183, }, + } }, + { 5200, { + { 4, 20165, 4, 18148, }, + { 4, 20204, 4, 18183, }, + { 4, 20126, 4, 18114, }, + } }, + { 5220, { + { 4, 20088, 4, 18079, }, + { 4, 20126, 4, 18114, }, + { 4, 20049, 4, 18044, }, + } }, + { 5240, { + { 4, 20011, 4, 18010, }, + { 4, 20049, 4, 18044, }, + { 4, 19973, 4, 17976, }, + } }, + { 5260, { + { 4, 19935, 4, 17941, }, + { 4, 19973, 4, 17976, }, + { 4, 19897, 4, 17907, }, + } }, + { 5280, { + { 4, 19859, 4, 17873, }, + { 4, 19897, 4, 17907, }, + { 4, 19822, 4, 17840, }, + } }, + { 5300, { + { 4, 19784, 4, 17806, }, + { 4, 19822, 4, 17840, }, + { 4, 19747, 4, 17772, }, + } }, + { 5320, { + { 4, 19710, 4, 17739, }, + { 4, 19747, 4, 17772, }, + { 4, 19673, 4, 17706, }, + } }, + { 5500, { + { 4, 19065, 4, 17159, }, + { 4, 19100, 4, 17190, }, + { 4, 19030, 4, 17127, }, + } }, + { 5520, { + { 4, 18996, 4, 17096, }, + { 4, 19030, 4, 17127, }, + { 4, 18962, 4, 17065, }, + } }, + { 5540, { + { 4, 18927, 4, 17035, }, + { 4, 18962, 4, 17065, }, + { 4, 18893, 4, 17004, }, + } }, + { 5560, { + { 4, 18859, 4, 16973, }, + { 4, 18893, 4, 17004, }, + { 4, 18825, 4, 16943, }, + } }, + { 5580, { + { 4, 18792, 4, 16913, }, + { 4, 18825, 4, 16943, }, + { 4, 18758, 4, 16882, }, + } }, + { 5600, { + { 4, 18725, 4, 16852, }, + { 4, 18758, 4, 16882, }, + { 4, 18691, 4, 16822, }, + } }, + { 5620, { + { 4, 18658, 4, 16792, }, + { 4, 18691, 4, 16822, }, + { 4, 18625, 4, 16762, }, + } }, + { 5640, { + { 4, 18592, 4, 16733, }, + { 4, 18625, 4, 16762, }, + { 4, 18559, 4, 16703, }, + } }, + { 5660, { + { 4, 18526, 4, 16673, }, + { 4, 18559, 4, 16703, }, + { 4, 18493, 4, 16644, }, + } }, + { 5680, { + { 4, 18461, 4, 16615, }, + { 4, 18493, 4, 16644, }, + { 4, 18428, 4, 16586, }, + } }, + { 5700, { + { 4, 18396, 4, 16556, }, + { 4, 18428, 4, 16586, }, + { 4, 18364, 4, 16527, }, + } }, + { 5745, { + { 4, 18252, 4, 16427, }, + { 4, 18284, 4, 16455, }, + { 4, 18220, 4, 16398, }, + } }, + { 5765, { + { 4, 18189, 5, 32740, }, + { 4, 18220, 4, 16398, }, + { 4, 18157, 5, 32683, }, + } }, + { 5785, { + { 4, 18126, 5, 32626, }, + { 4, 18157, 5, 32683, }, + { 4, 18094, 5, 32570, }, + } }, + { 5805, { + { 4, 18063, 5, 32514, }, + { 4, 18094, 5, 32570, }, + { 4, 18032, 5, 32458, }, + } }, + { 5825, { + { 4, 18001, 5, 32402, }, + { 4, 18032, 5, 32458, }, + { 4, 17970, 5, 32347, }, + } }, + { 5170, { + { 4, 20282, 4, 18254, }, + { 4, 20321, 4, 18289, }, + { 4, 20243, 4, 18219, }, + } }, + { 5190, { + { 4, 20204, 4, 18183, }, + { 4, 20243, 4, 18219, }, + { 4, 20165, 4, 18148, }, + } }, + { 5210, { + { 4, 20126, 4, 18114, }, + { 4, 20165, 4, 18148, }, + { 4, 20088, 4, 18079, }, + } }, + { 5230, { + { 4, 20049, 4, 18044, }, + { 4, 20088, 4, 18079, }, + { 4, 20011, 4, 18010, }, + } }, +}; + +static const struct ar9170_phy_freq_params * +ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, + enum ar9170_bw bw) +{ + unsigned int chanidx = 0; + u16 freq = 2412; + + if (channel) { + chanidx = channel->hw_value; + freq = channel->center_freq; + } + + BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); + + BUILD_BUG_ON(__AR9170_NUM_BW != 3); + + WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); + + return &ar9170_phy_freq_params[chanidx].params[bw]; +} + + +int ar9170_init_rf(struct ar9170 *ar) +{ + const struct ar9170_phy_freq_params *freqpar; + __le32 cmd[7]; + int err; + + err = ar9170_init_rf_banks_0_7(ar, false); + if (err) + return err; + + err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); + if (err) + return err; + + freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); + + cmd[0] = cpu_to_le32(2412 * 1000); + cmd[1] = cpu_to_le32(0); + cmd[2] = cpu_to_le32(1); + cmd[3] = cpu_to_le32(freqpar->coeff_exp); + cmd[4] = cpu_to_le32(freqpar->coeff_man); + cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); + cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); + + /* RF_INIT echoes the command back to us */ + err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, + sizeof(cmd), (u8 *)cmd, + sizeof(cmd), (u8 *)cmd); + if (err) + return err; + + msleep(1000); + + return ar9170_echo_test(ar, 0xaabbccdd); +} + +static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) +{ + int idx = nfreqs - 2; + + while (idx >= 0) { + if (f >= freqs[idx]) + return idx; + idx--; + } + + return 0; +} + +static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) +{ + /* nothing to interpolate, it's horizontal */ + if (y2 == y1) + return y1; + + /* check if we hit one of the edges */ + if (x == x1) + return y1; + if (x == x2) + return y2; + + /* x1 == x2 is bad, hopefully == x */ + if (x2 == x1) + return y1; + + return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); +} + +static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) +{ +#define SHIFT 8 + s32 y; + + y = ar9170_interpolate_s32(x << SHIFT, + x1 << SHIFT, y1 << SHIFT, + x2 << SHIFT, y2 << SHIFT); + + /* + * XXX: unwrap this expression + * Isn't it just DIV_ROUND_UP(y, 1<> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); +#undef SHIFT +} + +static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) +{ + struct ar9170_calibration_target_power_legacy *ctpl; + struct ar9170_calibration_target_power_ht *ctph; + u8 *ctpres; + int ntargets; + int idx, i, n; + u8 ackpower, ackchains, f; + u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; + + if (freq < 3000) + f = freq - 2300; + else + f = (freq - 4800)/5; + + /* + * cycle through the various modes + * + * legacy modes first: 5G, 2G CCK, 2G OFDM + */ + for (i = 0; i < 3; i++) { + switch (i) { + case 0: /* 5 GHz legacy */ + ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; + ntargets = AR5416_NUM_5G_TARGET_PWRS; + ctpres = ar->power_5G_leg; + break; + case 1: /* 2.4 GHz CCK */ + ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; + ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; + ctpres = ar->power_2G_cck; + break; + case 2: /* 2.4 GHz OFDM */ + ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; + ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; + ctpres = ar->power_2G_ofdm; + break; + default: + BUG(); + } + + for (n = 0; n < ntargets; n++) { + if (ctpl[n].freq == 0xff) + break; + pwr_freqs[n] = ctpl[n].freq; + } + ntargets = n; + idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); + for (n = 0; n < 4; n++) + ctpres[n] = ar9170_interpolate_u8( + f, + ctpl[idx + 0].freq, + ctpl[idx + 0].power[n], + ctpl[idx + 1].freq, + ctpl[idx + 1].power[n]); + } + + /* + * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 + */ + for (i = 0; i < 4; i++) { + switch (i) { + case 0: /* 5 GHz HT 20 */ + ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; + ntargets = AR5416_NUM_5G_TARGET_PWRS; + ctpres = ar->power_5G_ht20; + break; + case 1: /* 5 GHz HT 40 */ + ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; + ntargets = AR5416_NUM_5G_TARGET_PWRS; + ctpres = ar->power_5G_ht40; + break; + case 2: /* 2.4 GHz HT 20 */ + ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; + ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; + ctpres = ar->power_2G_ht20; + break; + case 3: /* 2.4 GHz HT 40 */ + ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; + ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; + ctpres = ar->power_2G_ht40; + break; + default: + BUG(); + } + + for (n = 0; n < ntargets; n++) { + if (ctph[n].freq == 0xff) + break; + pwr_freqs[n] = ctph[n].freq; + } + ntargets = n; + idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); + for (n = 0; n < 8; n++) + ctpres[n] = ar9170_interpolate_u8( + f, + ctph[idx + 0].freq, + ctph[idx + 0].power[n], + ctph[idx + 1].freq, + ctph[idx + 1].power[n]); + } + + /* set ACK/CTS TX power */ + ar9170_regwrite_begin(ar); + + if (ar->eeprom.tx_mask != 1) + ackchains = AR9170_TX_PHY_TXCHAIN_2; + else + ackchains = AR9170_TX_PHY_TXCHAIN_1; + + if (freq < 3000) + ackpower = ar->power_2G_ofdm[0] & 0x3f; + else + ackpower = ar->power_5G_leg[0] & 0x3f; + + ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); + ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | + ackpower << 21 | ackchains << 27); + + ar9170_regwrite_finish(); + return ar9170_regwrite_result(); +} + +static int ar9170_calc_noise_dbm(u32 raw_noise) +{ + if (raw_noise & 0x100) + return ~((raw_noise & 0x0ff) >> 1); + else + return (raw_noise & 0xff) >> 1; +} + +int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, + enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) +{ + const struct ar9170_phy_freq_params *freqpar; + u32 cmd, tmp, offs; + __le32 vals[8]; + int i, err; + bool bandswitch; + + /* clear BB heavy clip enable */ + err = ar9170_write_reg(ar, 0x1c59e0, 0x200); + if (err) + return err; + + /* may be NULL at first setup */ + if (ar->channel) + bandswitch = ar->channel->band != channel->band; + else + bandswitch = true; + + /* HW workaround */ + if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && + channel->center_freq <= 2417) + bandswitch = true; + + err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); + if (err) + return err; + + if (rfi != AR9170_RFI_NONE || bandswitch) { + u32 val = 0x400; + + if (rfi == AR9170_RFI_COLD) + val = 0x800; + + /* warm/cold reset BB/ADDA */ + err = ar9170_write_reg(ar, 0x1d4004, val); + if (err) + return err; + + err = ar9170_write_reg(ar, 0x1d4004, 0x0); + if (err) + return err; + + err = ar9170_init_phy(ar, channel->band); + if (err) + return err; + + err = ar9170_init_rf_banks_0_7(ar, + channel->band == IEEE80211_BAND_5GHZ); + if (err) + return err; + + cmd = AR9170_CMD_RF_INIT; + } else { + cmd = AR9170_CMD_FREQUENCY; + } + + err = ar9170_init_rf_bank4_pwr(ar, + channel->band == IEEE80211_BAND_5GHZ, + channel->center_freq, bw); + if (err) + return err; + + switch (bw) { + case AR9170_BW_20: + tmp = 0x240; + offs = 0; + break; + case AR9170_BW_40_BELOW: + tmp = 0x2c4; + offs = 3; + break; + case AR9170_BW_40_ABOVE: + tmp = 0x2d4; + offs = 1; + break; + default: + BUG(); + return -ENOSYS; + } + + if (0 /* 2 streams capable */) + tmp |= 0x100; + + err = ar9170_write_reg(ar, 0x1c5804, tmp); + if (err) + return err; + + err = ar9170_set_power_cal(ar, channel->center_freq, bw); + if (err) + return err; + + freqpar = ar9170_get_hw_dyn_params(channel, bw); + + vals[0] = cpu_to_le32(channel->center_freq * 1000); + vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1); + vals[2] = cpu_to_le32(offs << 2 | 1); + vals[3] = cpu_to_le32(freqpar->coeff_exp); + vals[4] = cpu_to_le32(freqpar->coeff_man); + vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); + vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); + vals[7] = cpu_to_le32(1000); + + err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, + sizeof(vals), (u8 *)vals); + if (err) + return err; + + for (i = 0; i < 2; i++) { + ar->noise[i] = ar9170_calc_noise_dbm( + (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); + + ar->noise[i + 2] = ar9170_calc_noise_dbm( + (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); + } + + ar->channel = channel; + return 0; +} diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c new file mode 100644 index 0000000..fddda47 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -0,0 +1,822 @@ +/* + * Atheros AR9170 driver + * + * USB - frontend + * + * Copyright 2008, Johannes Berg + * Copyright 2009, Christian Lamparter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "ar9170.h" +#include "cmd.h" +#include "hw.h" +#include "usb.h" + +MODULE_AUTHOR("Johannes Berg "); +MODULE_AUTHOR("Christian Lamparter "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); +MODULE_FIRMWARE("ar9170-1.fw"); +MODULE_FIRMWARE("ar9170-2.fw"); + +static struct usb_device_id ar9170_usb_ids[] = { + /* Atheros 9170 */ + { USB_DEVICE(0x0cf3, 0x9170) }, + /* Atheros TG121N */ + { USB_DEVICE(0x0cf3, 0x1001) }, + /* Cace Airpcap NX */ + { USB_DEVICE(0xcace, 0x0300) }, + /* D-Link DWA 160A */ + { USB_DEVICE(0x07d1, 0x3c10) }, + /* Netgear WNDA3100 */ + { USB_DEVICE(0x0846, 0x9010) }, + /* Netgear WN111 v2 */ + { USB_DEVICE(0x0846, 0x9001) }, + /* Zydas ZD1221 */ + { USB_DEVICE(0x0ace, 0x1221) }, + /* ZyXEL NWD271N */ + { USB_DEVICE(0x0586, 0x3417) }, + /* Z-Com UB81 BG */ + { USB_DEVICE(0x0cde, 0x0023) }, + /* Z-Com UB82 ABG */ + { USB_DEVICE(0x0cde, 0x0026) }, + /* Arcadyan WN7512 */ + { USB_DEVICE(0x083a, 0xf522) }, + /* Planex GWUS300 */ + { USB_DEVICE(0x2019, 0x5304) }, + /* IO-Data WNGDNUS2 */ + { USB_DEVICE(0x04bb, 0x093f) }, + + /* terminate */ + {} +}; +MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); + +static void ar9170_usb_tx_urb_complete_free(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct ar9170_usb *aru = (struct ar9170_usb *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + + if (!aru) { + dev_kfree_skb_irq(skb); + return ; + } + + ar9170_handle_tx_status(&aru->common, skb, false, + AR9170_TX_STATUS_COMPLETE); +} + +static void ar9170_usb_tx_urb_complete(struct urb *urb) +{ +} + +static void ar9170_usb_irq_completed(struct urb *urb) +{ + struct ar9170_usb *aru = urb->context; + + switch (urb->status) { + /* everything is fine */ + case 0: + break; + + /* disconnect */ + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + goto free; + + default: + goto resubmit; + } + + print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET, + urb->transfer_buffer, urb->actual_length); + +resubmit: + usb_anchor_urb(urb, &aru->rx_submitted); + if (usb_submit_urb(urb, GFP_ATOMIC)) { + usb_unanchor_urb(urb); + goto free; + } + + return; + +free: + usb_buffer_free(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); +} + +static void ar9170_usb_rx_completed(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct ar9170_usb *aru = (struct ar9170_usb *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + int err; + + if (!aru) + goto free; + + switch (urb->status) { + /* everything is fine */ + case 0: + break; + + /* disconnect */ + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + goto free; + + default: + goto resubmit; + } + + skb_put(skb, urb->actual_length); + ar9170_rx(&aru->common, skb); + +resubmit: + skb_reset_tail_pointer(skb); + skb_trim(skb, 0); + + usb_anchor_urb(urb, &aru->rx_submitted); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(urb); + dev_kfree_skb_irq(skb); + } + + return ; + +free: + dev_kfree_skb_irq(skb); + return; +} + +static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, + struct urb *urb, gfp_t gfp) +{ + struct sk_buff *skb; + + skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); + if (!skb) + return -ENOMEM; + + /* reserve some space for mac80211's radiotap */ + skb_reserve(skb, 32); + + usb_fill_bulk_urb(urb, aru->udev, + usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), + skb->data, min(skb_tailroom(skb), + AR9170_MAX_RX_BUFFER_SIZE), + ar9170_usb_rx_completed, skb); + + return 0; +} + +static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) +{ + struct urb *urb = NULL; + void *ibuf; + int err = -ENOMEM; + + /* initialize interrupt endpoint */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + goto out; + + ibuf = usb_buffer_alloc(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); + if (!ibuf) + goto out; + + usb_fill_int_urb(urb, aru->udev, + usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, + 64, ar9170_usb_irq_completed, aru, 1); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_anchor_urb(urb, &aru->rx_submitted); + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + usb_unanchor_urb(urb); + usb_buffer_free(aru->udev, 64, urb->transfer_buffer, + urb->transfer_dma); + } + +out: + usb_free_urb(urb); + return err; +} + +static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) +{ + struct urb *urb; + int i; + int err = -EINVAL; + + for (i = 0; i < AR9170_NUM_RX_URBS; i++) { + err = -ENOMEM; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + goto err_out; + + err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); + if (err) { + usb_free_urb(urb); + goto err_out; + } + + usb_anchor_urb(urb, &aru->rx_submitted); + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + usb_unanchor_urb(urb); + dev_kfree_skb_any((void *) urb->transfer_buffer); + usb_free_urb(urb); + goto err_out; + } + usb_free_urb(urb); + } + + /* the device now waiting for a firmware. */ + aru->common.state = AR9170_IDLE; + return 0; + +err_out: + + usb_kill_anchored_urbs(&aru->rx_submitted); + return err; +} + +static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +{ + int ret; + + aru->common.state = AR9170_UNKNOWN_STATE; + + usb_unlink_anchored_urbs(&aru->tx_submitted); + + /* give the LED OFF command and the deauth frame a chance to air. */ + ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, + msecs_to_jiffies(100)); + if (ret == 0) + dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); + usb_poison_anchored_urbs(&aru->tx_submitted); + + usb_poison_anchored_urbs(&aru->rx_submitted); +} + +static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, + unsigned int plen, void *payload, + unsigned int outlen, void *out) +{ + struct ar9170_usb *aru = (void *) ar; + struct urb *urb = NULL; + unsigned long flags; + int err = -ENOMEM; + + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return -EPERM; + + if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) + return -EINVAL; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (unlikely(!urb)) + goto err_free; + + ar->cmdbuf[0] = cpu_to_le32(plen); + ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); + /* writing multiple regs fills this buffer already */ + if (plen && payload != (u8 *)(&ar->cmdbuf[1])) + memcpy(&ar->cmdbuf[1], payload, plen); + + spin_lock_irqsave(&aru->common.cmdlock, flags); + aru->readbuf = (u8 *)out; + aru->readlen = outlen; + spin_unlock_irqrestore(&aru->common.cmdlock, flags); + + usb_fill_int_urb(urb, aru->udev, + usb_sndbulkpipe(aru->udev, AR9170_EP_CMD), + aru->common.cmdbuf, plen + 4, + ar9170_usb_tx_urb_complete, NULL, 1); + + usb_anchor_urb(urb, &aru->tx_submitted); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(urb); + usb_free_urb(urb); + goto err_unbuf; + } + usb_free_urb(urb); + + err = wait_for_completion_timeout(&aru->cmd_wait, HZ); + if (err == 0) { + err = -ETIMEDOUT; + goto err_unbuf; + } + + if (outlen >= 0 && aru->readlen != outlen) { + err = -EMSGSIZE; + goto err_unbuf; + } + + return 0; + +err_unbuf: + /* Maybe the device was removed in the second we were waiting? */ + if (IS_STARTED(ar)) { + dev_err(&aru->udev->dev, "no command feedback " + "received (%d).\n", err); + + /* provide some maybe useful debug information */ + print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, + aru->common.cmdbuf, plen + 4); + dump_stack(); + } + + /* invalidate to avoid completing the next prematurely */ + spin_lock_irqsave(&aru->common.cmdlock, flags); + aru->readbuf = NULL; + aru->readlen = 0; + spin_unlock_irqrestore(&aru->common.cmdlock, flags); + +err_free: + + return err; +} + +static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, + bool txstatus_needed, unsigned int extra_len) +{ + struct ar9170_usb *aru = (struct ar9170_usb *) ar; + struct urb *urb; + int err; + + if (unlikely(!IS_STARTED(ar))) { + /* Seriously, what were you drink... err... thinking!? */ + return -EPERM; + } + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (unlikely(!urb)) + return -ENOMEM; + + usb_fill_bulk_urb(urb, aru->udev, + usb_sndbulkpipe(aru->udev, AR9170_EP_TX), + skb->data, skb->len + extra_len, (txstatus_needed ? + ar9170_usb_tx_urb_complete : + ar9170_usb_tx_urb_complete_free), skb); + urb->transfer_flags |= URB_ZERO_PACKET; + + usb_anchor_urb(urb, &aru->tx_submitted); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err)) + usb_unanchor_urb(urb); + + usb_free_urb(urb); + return err; +} + +static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) +{ + struct ar9170_usb *aru = (void *) ar; + unsigned long flags; + u32 in, out; + + if (!buffer) + return ; + + in = le32_to_cpup((__le32 *)buffer); + out = le32_to_cpu(ar->cmdbuf[0]); + + /* mask off length byte */ + out &= ~0xFF; + + if (aru->readlen >= 0) { + /* add expected length */ + out |= aru->readlen; + } else { + /* add obtained length */ + out |= in & 0xFF; + } + + /* + * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response + * length and we cannot predict the correct length in advance. + * So we only check if we provided enough space for the data. + */ + if (unlikely(out < in)) { + dev_warn(&aru->udev->dev, "received invalid command response " + "got %d bytes, instead of %d bytes " + "and the resp length is %d bytes\n", + in, out, len); + print_hex_dump_bytes("ar9170 invalid resp: ", + DUMP_PREFIX_OFFSET, buffer, len); + /* + * Do not complete, then the command times out, + * and we get a stack trace from there. + */ + return ; + } + + spin_lock_irqsave(&aru->common.cmdlock, flags); + if (aru->readbuf && len > 0) { + memcpy(aru->readbuf, buffer + 4, len - 4); + aru->readbuf = NULL; + } + complete(&aru->cmd_wait); + spin_unlock_irqrestore(&aru->common.cmdlock, flags); +} + +static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, + size_t len, u32 addr, bool complete) +{ + int transfer, err; + u8 *buf = kmalloc(4096, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + while (len) { + transfer = min_t(int, len, 4096); + memcpy(buf, data, transfer); + + err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), + 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, + addr >> 8, 0, buf, transfer, 1000); + + if (err < 0) { + kfree(buf); + return err; + } + + len -= transfer; + data += transfer; + addr += transfer; + } + kfree(buf); + + if (complete) { + err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), + 0x31 /* FW DL COMPLETE */, + 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); + } + + return 0; +} + +static int ar9170_usb_request_firmware(struct ar9170_usb *aru) +{ + int err = 0; + + err = request_firmware(&aru->init_values, "ar9170-1.fw", + &aru->udev->dev); + if (err) { + dev_err(&aru->udev->dev, "file with init values not found.\n"); + return err; + } + + err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); + if (err) { + release_firmware(aru->init_values); + dev_err(&aru->udev->dev, "firmware file not found.\n"); + return err; + } + + return err; +} + +static int ar9170_usb_reset(struct ar9170_usb *aru) +{ + int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); + + if (lock) { + ret = usb_lock_device_for_reset(aru->udev, aru->intf); + if (ret < 0) { + dev_err(&aru->udev->dev, "unable to lock device " + "for reset (%d).\n", ret); + return ret; + } + } + + ret = usb_reset_device(aru->udev); + if (lock) + usb_unlock_device(aru->udev); + + /* let it rest - for a second - */ + msleep(1000); + + return ret; +} + +static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) +{ + int err; + + /* First, upload initial values to device RAM */ + err = ar9170_usb_upload(aru, aru->init_values->data, + aru->init_values->size, 0x102800, false); + if (err) { + dev_err(&aru->udev->dev, "firmware part 1 " + "upload failed (%d).\n", err); + return err; + } + + /* Then, upload the firmware itself and start it */ + return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, + 0x200000, true); +} + +static int ar9170_usb_init_transport(struct ar9170_usb *aru) +{ + struct ar9170 *ar = (void *) &aru->common; + int err; + + ar9170_regwrite_begin(ar); + + /* Set USB Rx stream mode MAX packet number to 2 */ + ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); + + /* Set USB Rx stream mode timeout to 10us */ + ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); + + ar9170_regwrite_finish(); + + err = ar9170_regwrite_result(); + if (err) + dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); + + return err; +} + +static void ar9170_usb_stop(struct ar9170 *ar) +{ + struct ar9170_usb *aru = (void *) ar; + int ret; + + if (IS_ACCEPTING_CMD(ar)) + aru->common.state = AR9170_STOPPED; + + /* lets wait a while until the tx - queues are dried out */ + ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, + msecs_to_jiffies(1000)); + if (ret == 0) + dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); + + usb_poison_anchored_urbs(&aru->tx_submitted); + + /* + * Note: + * So far we freed all tx urbs, but we won't dare to touch any rx urbs. + * Else we would end up with a unresponsive device... + */ +} + +static int ar9170_usb_open(struct ar9170 *ar) +{ + struct ar9170_usb *aru = (void *) ar; + int err; + + usb_unpoison_anchored_urbs(&aru->tx_submitted); + err = ar9170_usb_init_transport(aru); + if (err) { + usb_poison_anchored_urbs(&aru->tx_submitted); + return err; + } + + aru->common.state = AR9170_IDLE; + return 0; +} + +static int ar9170_usb_init_device(struct ar9170_usb *aru) +{ + int err; + + err = ar9170_usb_alloc_rx_irq_urb(aru); + if (err) + goto err_out; + + err = ar9170_usb_alloc_rx_bulk_urbs(aru); + if (err) + goto err_unrx; + + err = ar9170_usb_upload_firmware(aru); + if (err) { + err = ar9170_echo_test(&aru->common, 0x60d43110); + if (err) { + /* force user invention, by disabling the device */ + err = usb_driver_set_configuration(aru->udev, -1); + dev_err(&aru->udev->dev, "device is in a bad state. " + "please reconnect it!\n"); + goto err_unrx; + } + } + + return 0; + +err_unrx: + ar9170_usb_cancel_urbs(aru); + +err_out: + return err; +} + +static int ar9170_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct ar9170_usb *aru; + struct ar9170 *ar; + struct usb_device *udev; + int err; + + aru = ar9170_alloc(sizeof(*aru)); + if (IS_ERR(aru)) { + err = PTR_ERR(aru); + goto out; + } + + udev = interface_to_usbdev(intf); + usb_get_dev(udev); + aru->udev = udev; + aru->intf = intf; + ar = &aru->common; + + usb_set_intfdata(intf, aru); + SET_IEEE80211_DEV(ar->hw, &udev->dev); + + init_usb_anchor(&aru->rx_submitted); + init_usb_anchor(&aru->tx_submitted); + init_completion(&aru->cmd_wait); + + aru->common.stop = ar9170_usb_stop; + aru->common.open = ar9170_usb_open; + aru->common.tx = ar9170_usb_tx; + aru->common.exec_cmd = ar9170_usb_exec_cmd; + aru->common.callback_cmd = ar9170_usb_callback_cmd; + + err = ar9170_usb_reset(aru); + if (err) + goto err_freehw; + + err = ar9170_usb_request_firmware(aru); + if (err) + goto err_freehw; + + err = ar9170_usb_init_device(aru); + if (err) + goto err_freefw; + + err = ar9170_usb_open(ar); + if (err) + goto err_unrx; + + err = ar9170_register(ar, &udev->dev); + + ar9170_usb_stop(ar); + if (err) + goto err_unrx; + + return 0; + +err_unrx: + ar9170_usb_cancel_urbs(aru); + +err_freefw: + release_firmware(aru->init_values); + release_firmware(aru->firmware); + +err_freehw: + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); + ieee80211_free_hw(ar->hw); +out: + return err; +} + +static void ar9170_usb_disconnect(struct usb_interface *intf) +{ + struct ar9170_usb *aru = usb_get_intfdata(intf); + + if (!aru) + return; + + aru->common.state = AR9170_IDLE; + ar9170_unregister(&aru->common); + ar9170_usb_cancel_urbs(aru); + + release_firmware(aru->init_values); + release_firmware(aru->firmware); + + usb_put_dev(aru->udev); + usb_set_intfdata(intf, NULL); + ieee80211_free_hw(aru->common.hw); +} + +#ifdef CONFIG_PM +static int ar9170_suspend(struct usb_interface *intf, + pm_message_t message) +{ + struct ar9170_usb *aru = usb_get_intfdata(intf); + + if (!aru) + return -ENODEV; + + aru->common.state = AR9170_IDLE; + ar9170_usb_cancel_urbs(aru); + + return 0; +} + +static int ar9170_resume(struct usb_interface *intf) +{ + struct ar9170_usb *aru = usb_get_intfdata(intf); + int err; + + if (!aru) + return -ENODEV; + + usb_unpoison_anchored_urbs(&aru->rx_submitted); + usb_unpoison_anchored_urbs(&aru->tx_submitted); + + /* + * FIXME: firmware upload will fail on resume. + * but this is better than a hang! + */ + + err = ar9170_usb_init_device(aru); + if (err) + goto err_unrx; + + err = ar9170_usb_open(&aru->common); + if (err) + goto err_unrx; + + return 0; + +err_unrx: + aru->common.state = AR9170_IDLE; + ar9170_usb_cancel_urbs(aru); + + return err; +} +#endif /* CONFIG_PM */ + +static struct usb_driver ar9170_driver = { + .name = "ar9170usb", + .probe = ar9170_usb_probe, + .disconnect = ar9170_usb_disconnect, + .id_table = ar9170_usb_ids, + .soft_unbind = 1, +#ifdef CONFIG_PM + .suspend = ar9170_suspend, + .resume = ar9170_resume, +#endif /* CONFIG_PM */ +}; + +static int __init ar9170_init(void) +{ + return usb_register(&ar9170_driver); +} + +static void __exit ar9170_exit(void) +{ + usb_deregister(&ar9170_driver); +} + +module_init(ar9170_init); +module_exit(ar9170_exit); diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h new file mode 100644 index 0000000..f585292 --- /dev/null +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -0,0 +1,74 @@ +/* + * Atheros AR9170 USB driver + * + * Driver specific definitions + * + * Copyright 2008, Johannes Berg + * Copyright 2009, Christian Lamparter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, see + * http://www.gnu.org/licenses/. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __USB_H +#define __USB_H + +#include +#include +#include +#include +#include +#include +#include +#include "eeprom.h" +#include "hw.h" +#include "ar9170.h" + +#define AR9170_NUM_RX_URBS 16 + +struct firmware; + +struct ar9170_usb { + struct ar9170 common; + struct usb_device *udev; + struct usb_interface *intf; + + struct usb_anchor rx_submitted; + struct usb_anchor tx_submitted; + + spinlock_t cmdlock; + struct completion cmd_wait; + int readlen; + u8 *readbuf; + + const struct firmware *init_values; + const struct firmware *firmware; +}; + +#endif /* __USB_H */ diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig new file mode 100644 index 0000000..509b6f9 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -0,0 +1,41 @@ +config ATH5K + tristate "Atheros 5xxx wireless cards support" + depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select ATH_COMMON + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS + ---help--- + This module adds support for wireless adapters based on + Atheros 5xxx chipset. + + Currently the following chip versions are supported: + + MAC: AR5211 AR5212 + PHY: RF5111/2111 RF5112/2112 RF5413/2413 + + This driver uses the kernel's mac80211 subsystem. + + If you choose to build a module, it'll be called ath5k. Say M if + unsure. + +config ATH5K_DEBUG + bool "Atheros 5xxx debugging" + depends on ATH5K + ---help--- + Atheros 5xxx debugging messages. + + Say Y, if and you will get debug options for ath5k. + To use this, you need to mount debugfs: + + mkdir /debug/ + mount -t debugfs debug /debug/ + + You will get access to files under: + /debug/ath5k/phy0/ + + To enable debug, pass the debug level to the debug module + parameter. For example: + + modprobe ath5k debug=0x00000400 + diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile new file mode 100644 index 0000000..84a74c5 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -0,0 +1,15 @@ +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-y += led.o +ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o +obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h new file mode 100644 index 0000000..60c6d2e --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -0,0 +1,1354 @@ +/* + * Copyright (c) 2004-2007 Reyk Floeter + * Copyright (c) 2006-2007 Nick Kossifidis + * + * 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. + */ + +#ifndef _ATH5K_H +#define _ATH5K_H + +/* 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 +#include +#include + +#include "../regd.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 */ +#define PCI_DEVICE_ID_ATHEROS_AR5311 0x0011 /* AR5311 */ +#define PCI_DEVICE_ID_ATHEROS_AR5211 0x0012 /* AR5211 */ +#define PCI_DEVICE_ID_ATHEROS_AR5212 0x0013 /* AR5212 */ +#define PCI_DEVICE_ID_3COM_3CRDAG675 0x0013 /* 3CRDAG675 (Atheros AR5212) */ +#define PCI_DEVICE_ID_3COM_2_3CRPAG175 0x0013 /* 3CRPAG175 (Atheros AR5212) */ +#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 0x0207 /* AR5210 (Early) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM 0x1014 /* AR5212 (IBM MiniPCI) */ +#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 0x1107 /* AR5210 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 0x1113 /* AR5212 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 0x1112 /* AR5211 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 0xf013 /* AR5212 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 0xff12 /* AR5211 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 0xf11b /* AR5211 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 0x0058 /* AR5312 WMAC (AP43-030) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 0x0014 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 0x0015 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 0x0016 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 0x0017 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 0x0018 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 0x0019 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR2413 0x001a /* AR2413 (Griffin-lite) */ +#define PCI_DEVICE_ID_ATHEROS_AR5413 0x001b /* AR5413 (Eagle) */ +#define PCI_DEVICE_ID_ATHEROS_AR5424 0x001c /* AR5424 (Condor PCI-E) */ +#define PCI_DEVICE_ID_ATHEROS_AR5416 0x0023 /* AR5416 */ +#define PCI_DEVICE_ID_ATHEROS_AR5418 0x0024 /* AR5418 */ + +/****************************\ + GENERIC DRIVER DEFINITIONS +\****************************/ + +#define ATH5K_PRINTF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__) + +#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \ + printk(_level "ath5k %s: " _fmt, \ + ((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \ + ##__VA_ARGS__) + +#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \ + if (net_ratelimit()) \ + ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \ + } while (0) + +#define ATH5K_INFO(_sc, _fmt, ...) \ + ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__) + +#define ATH5K_WARN(_sc, _fmt, ...) \ + ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__) + +#define ATH5K_ERR(_sc, _fmt, ...) \ + 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 + +/* 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 +#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 +#define AR5K_TUNE_RADAR_ALERT false +#define AR5K_TUNE_MIN_TX_FIFO_THRES 1 +#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_LEN / 64) + 1) +#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 +/* 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_REGISTER_DWELL_TIME 20000 +#define AR5K_TUNE_BEACON_INTERVAL 100 +#define AR5K_TUNE_AIFS 2 +#define AR5K_TUNE_AIFS_11B 2 +#define AR5K_TUNE_AIFS_XR 0 +#define AR5K_TUNE_CWMIN 15 +#define AR5K_TUNE_CWMIN_11B 31 +#define AR5K_TUNE_CWMIN_XR 3 +#define AR5K_TUNE_CWMAX 1023 +#define AR5K_TUNE_CWMAX_11B 1023 +#define AR5K_TUNE_CWMAX_XR 7 +#define AR5K_TUNE_NOISE_FLOOR -72 +#define AR5K_TUNE_MAX_TXPOWER 63 +#define AR5K_TUNE_DEFAULT_TXPOWER 25 +#define AR5K_TUNE_TPC_TXPOWER false +#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_CYCRSSI_THR1 2 +#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) + +/* GENERIC CHIPSET DEFINITIONS */ + +/* MAC Chips */ +enum ath5k_version { + AR5K_AR5210 = 0, + AR5K_AR5211 = 1, + AR5K_AR5212 = 2, +}; + +/* PHY Chips */ +enum ath5k_radio { + AR5K_RF5110 = 0, + AR5K_RF5111 = 1, + AR5K_RF5112 = 2, + AR5K_RF2413 = 3, + AR5K_RF5413 = 4, + AR5K_RF2316 = 5, + AR5K_RF2317 = 6, + AR5K_RF2425 = 7, +}; + +/* + * Common silicon revision/version values + */ + +enum ath5k_srev_type { + AR5K_VERSION_MAC, + AR5K_VERSION_RAD, +}; + +struct ath5k_srev_name { + const char *sr_name; + enum ath5k_srev_type sr_type; + u_int sr_val; +}; + +#define AR5K_SREV_UNKNOWN 0xffff + +#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 /* Talon */ +#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 +#define AR5K_SREV_RAD_5111A 0x15 +#define AR5K_SREV_RAD_2111 0x20 +#define AR5K_SREV_RAD_5112 0x30 +#define AR5K_SREV_RAD_5112A 0x35 +#define AR5K_SREV_RAD_5112B 0x36 +#define AR5K_SREV_RAD_2112 0x40 +#define AR5K_SREV_RAD_2112A 0x45 +#define AR5K_SREV_RAD_2112B 0x46 +#define AR5K_SREV_RAD_2413 0x50 +#define AR5K_SREV_RAD_5413 0x60 +#define AR5K_SREV_RAD_2316 0x70 /* Cobra SoC */ +#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_5212A 0x42 +#define AR5K_SREV_PHY_5212B 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 */ + +/* + * Some of this information is based on Documentation from: + * + * http://madwifi.org/wiki/ChipsetFeatures/SuperAG + * + * Modulation for Atheros' eXtended Range - range enhancing extension that is + * supposed to double the distance an Atheros client device can keep a + * connection with an Atheros access point. This is achieved by increasing + * the receiver sensitivity up to, -105dBm, which is about 20dB above what + * the 802.11 specifications demand. In addition, new (proprietary) data rates + * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. + * + * Please note that can you either use XR or TURBO but you cannot use both, + * they are exclusive. + * + */ +#define MODULATION_XR 0x00000200 +/* + * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a + * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s + * signaling rate achieved through the bonding of two 54Mbit/s 802.11g + * channels. To use this feature your Access Point must also suport it. + * There is also a distinction between "static" and "dynamic" turbo modes: + * + * - Static: is the dumb version: devices set to this mode stick to it until + * the mode is turned off. + * - Dynamic: is the intelligent version, the network decides itself if it + * is ok to use turbo. As soon as traffic is detected on adjacent channels + * (which would get used in turbo mode), or when a non-turbo station joins + * the network, turbo mode won't be used until the situation changes again. + * Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which + * monitors the used radio band in order to decide whether turbo mode may + * be used or not. + * + * This article claims Super G sticks to bonding of channels 5 and 6 for + * USA: + * + * http://www.pcworld.com/article/id,113428-page,1/article.html + * + * The channel bonding seems to be driver specific though. In addition to + * deciding what channels will be used, these "Turbo" modes are accomplished + * by also enabling the following features: + * + * - Bursting: allows multiple frames to be sent at once, rather than pausing + * after each frame. Bursting is a standards-compliant feature that can be + * used with any Access Point. + * - Fast frames: increases the amount of information that can be sent per + * frame, also resulting in a reduction of transmission overhead. It is a + * proprietary feature that needs to be supported by the Access Point. + * - Compression: data frames are compressed in real time using a Lempel Ziv + * algorithm. This is done transparently. Once this feature is enabled, + * compression and decompression takes place inside the chipset, without + * putting additional load on the host CPU. + * + */ +#define MODULATION_TURBO 0x00000080 + +enum ath5k_driver_mode { + AR5K_MODE_11A = 0, + AR5K_MODE_11A_TURBO = 1, + AR5K_MODE_11B = 2, + AR5K_MODE_11G = 3, + AR5K_MODE_11G_TURBO = 4, + AR5K_MODE_XR = 0, + AR5K_MODE_MAX = 5 +}; + + +/****************\ + TX DEFINITIONS +\****************/ + +/* + * TX Status descriptor + */ +struct ath5k_tx_status { + u16 ts_seqnum; + u16 ts_tstamp; + u8 ts_status; + u8 ts_rate[4]; + u8 ts_retry[4]; + u8 ts_final_idx; + s8 ts_rssi; + u8 ts_shortretry; + u8 ts_longretry; + u8 ts_virtcol; + u8 ts_antenna; +}; + +#define AR5K_TXSTAT_ALTRATE 0x80 +#define AR5K_TXERR_XRETRY 0x01 +#define AR5K_TXERR_FILT 0x02 +#define AR5K_TXERR_FIFO 0x04 + +/** + * enum ath5k_tx_queue - Queue types used to classify tx queues. + * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue + * @AR5K_TX_QUEUE_DATA: A normal data queue + * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue + * @AR5K_TX_QUEUE_BEACON: The beacon queue + * @AR5K_TX_QUEUE_CAB: The after-beacon queue + * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue + */ +enum ath5k_tx_queue { + AR5K_TX_QUEUE_INACTIVE = 0, + AR5K_TX_QUEUE_DATA, + AR5K_TX_QUEUE_XR_DATA, + AR5K_TX_QUEUE_BEACON, + AR5K_TX_QUEUE_CAB, + AR5K_TX_QUEUE_UAPSD, +}; + +#define AR5K_NUM_TX_QUEUES 10 +#define AR5K_NUM_TX_QUEUES_NOQCU 2 + +/* + * Queue syb-types to classify normal data queues. + * These are the 4 Access Categories as defined in + * WME spec. 0 is the lowest priority and 4 is the + * highest. Normal data that hasn't been classified + * goes to the Best Effort AC. + */ +enum ath5k_tx_queue_subtype { + AR5K_WME_AC_BK = 0, /*Background traffic*/ + AR5K_WME_AC_BE, /*Best-effort (normal) traffic)*/ + AR5K_WME_AC_VI, /*Video traffic*/ + AR5K_WME_AC_VO, /*Voice traffic*/ +}; + +/* + * Queue ID numbers as returned by the hw functions, each number + * represents a hw queue. If hw does not support hw queues + * (eg 5210) all data goes in one queue. These match + * d80211 definitions (net80211/MadWiFi don't use them). + */ +enum ath5k_tx_queue_id { + AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, + AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, + AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/ + AR5K_TX_QUEUE_ID_DATA_MAX = 4, /*IEEE80211_TX_QUEUE_DATA4*/ + AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/ + AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/ + AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/ + AR5K_TX_QUEUE_ID_UAPSD = 8, + AR5K_TX_QUEUE_ID_XR_DATA = 9, +}; + +/* + * Flags to set hw queue's parameters... + */ +#define AR5K_TXQ_FLAG_TXOKINT_ENABLE 0x0001 /* Enable TXOK interrupt */ +#define AR5K_TXQ_FLAG_TXERRINT_ENABLE 0x0002 /* Enable TXERR interrupt */ +#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ +#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ +#define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ +#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE 0x0020 /* Enable CBRORN interrupt */ +#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE 0x0040 /* Enable CBRURN interrupt */ +#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE 0x0080 /* Enable QTRIG interrupt */ +#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE 0x0100 /* Enable TXNOFRM interrupt */ +#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0200 /* Disable random post-backoff */ +#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0300 /* Enable ready time expiry policy (?)*/ +#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0800 /* Enable backoff while bursting */ +#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ +#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ + +/* + * A struct to hold tx queue's parameters + */ +struct ath5k_txq_info { + enum ath5k_tx_queue tqi_type; + enum ath5k_tx_queue_subtype tqi_subtype; + u16 tqi_flags; /* Tx queue flags (see above) */ + u32 tqi_aifs; /* Arbitrated Interframe Space */ + s32 tqi_cw_min; /* Minimum Contention Window */ + s32 tqi_cw_max; /* Maximum Contention Window */ + u32 tqi_cbr_period; /* Constant bit rate period */ + u32 tqi_cbr_overflow_limit; + u32 tqi_burst_time; + u32 tqi_ready_time; /* Not used */ +}; + +/* + * Transmit packet types. + * used on tx control descriptor + * TODO: Use them inside base.c corectly + */ +enum ath5k_pkt_type { + AR5K_PKT_TYPE_NORMAL = 0, + AR5K_PKT_TYPE_ATIM = 1, + AR5K_PKT_TYPE_PSPOLL = 2, + AR5K_PKT_TYPE_BEACON = 3, + AR5K_PKT_TYPE_PROBE_RESP = 4, + AR5K_PKT_TYPE_PIFS = 5, +}; + +/* + * TX power and TPC settings + */ +#define AR5K_TXPOWER_OFDM(_r, _v) ( \ + ((0 & 1) << ((_v) + 6)) | \ + (((ah->ah_txpower.txp_rates_power_table[(_r)]) & 0x3f) << (_v)) \ +) + +#define AR5K_TXPOWER_CCK(_r, _v) ( \ + (ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v) \ +) + +/* + * DMA size definitions (2^n+2) + */ +enum ath5k_dmasize { + AR5K_DMASIZE_4B = 0, + AR5K_DMASIZE_8B, + AR5K_DMASIZE_16B, + AR5K_DMASIZE_32B, + AR5K_DMASIZE_64B, + AR5K_DMASIZE_128B, + AR5K_DMASIZE_256B, + AR5K_DMASIZE_512B +}; + + +/****************\ + RX DEFINITIONS +\****************/ + +/* + * RX Status descriptor + */ +struct ath5k_rx_status { + u16 rs_datalen; + u16 rs_tstamp; + u8 rs_status; + u8 rs_phyerr; + s8 rs_rssi; + u8 rs_keyix; + u8 rs_rate; + u8 rs_antenna; + u8 rs_more; +}; + +#define AR5K_RXERR_CRC 0x01 +#define AR5K_RXERR_PHY 0x02 +#define AR5K_RXERR_FIFO 0x04 +#define AR5K_RXERR_DECRYPT 0x08 +#define AR5K_RXERR_MIC 0x10 +#define AR5K_RXKEYIX_INVALID ((u8) - 1) +#define AR5K_TXKEYIX_INVALID ((u32) - 1) + + +/**************************\ + BEACON TIMERS DEFINITIONS +\**************************/ + +#define AR5K_BEACON_PERIOD 0x0000ffff +#define AR5K_BEACON_ENA 0x00800000 /*enable beacon xmit*/ +#define AR5K_BEACON_RESET_TSF 0x01000000 /*force a TSF reset*/ + +#if 0 +/** + * struct ath5k_beacon_state - Per-station beacon timer state. + * @bs_interval: in TU's, can also include the above flags + * @bs_cfp_max_duration: if non-zero hw is setup to coexist with a + * Point Coordination Function capable AP + */ +struct ath5k_beacon_state { + u32 bs_next_beacon; + u32 bs_next_dtim; + u32 bs_interval; + u8 bs_dtim_period; + u8 bs_cfp_period; + u16 bs_cfp_max_duration; + u16 bs_cfp_du_remain; + u16 bs_tim_offset; + u16 bs_sleep_duration; + u16 bs_bmiss_threshold; + u32 bs_cfp_next; +}; +#endif + + +/* + * TSF to TU conversion: + * + * TSF is a 64bit value in usec (microseconds). + * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of + * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024). + */ +#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) + + +/*******************************\ + GAIN OPTIMIZATION DEFINITIONS +\*******************************/ + +enum ath5k_rfgain { + AR5K_RFGAIN_INACTIVE = 0, + AR5K_RFGAIN_ACTIVE, + AR5K_RFGAIN_READ_REQUESTED, + AR5K_RFGAIN_NEED_CHANGE, +}; + +struct ath5k_gain { + u8 g_step_idx; + u8 g_current; + u8 g_target; + u8 g_low; + u8 g_high; + u8 g_f_corr; + u8 g_state; +}; + +/********************\ + COMMON DEFINITIONS +\********************/ + +#define AR5K_SLOT_TIME_9 396 +#define AR5K_SLOT_TIME_20 880 +#define AR5K_SLOT_TIME_MAX 0xffff + +/* channel_flags */ +#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */ +#define CHANNEL_TURBO 0x0010 /* Turbo Channel */ +#define CHANNEL_CCK 0x0020 /* CCK channel */ +#define CHANNEL_OFDM 0x0040 /* OFDM channel */ +#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */ +#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */ +#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */ +#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */ +#define CHANNEL_XR 0x0800 /* XR channel */ + +#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) +#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) +#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO) +#define CHANNEL_TG (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO) +#define CHANNEL_108A CHANNEL_T +#define CHANNEL_108G CHANNEL_TG +#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR) + +#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \ + CHANNEL_TURBO) + +#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL & ~CHANNEL_TURBO) +#define CHANNEL_MODES CHANNEL_ALL + +/* + * 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 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 +\******************/ + +/** + * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32. + * + * 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. + * + * This is the hardware rate map we are aware of: + * + * rate_code 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 + * rate_kbps 3000 1000 ? ? ? 2000 500 48000 + * + * 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 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(). + */ +#define AR5K_MAX_RATES 32 + +/* 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 + */ + +#define AR5K_KEYCACHE_SIZE 8 + +/***********************\ + HW RELATED DEFINITIONS +\***********************/ + +/* + * Misc definitions + */ +#define AR5K_RSSI_EP_MULTIPLIER (1<<7) + +#define AR5K_ASSERT_ENTRY(_e, _s) do { \ + if (_e >= _s) \ + return (false); \ +} while (0) + +/* + * Hardware interrupt abstraction + */ + +/** + * enum ath5k_int - Hardware interrupt masks helpers + * + * @AR5K_INT_RX: mask to identify received frame interrupts, of type + * AR5K_ISR_RXOK or AR5K_ISR_RXERR + * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?) + * @AR5K_INT_RXNOFRM: No frame received (?) + * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The + * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's + * LinkPtr is NULL. For more details, refer to: + * http://www.freepatentsonline.com/20030225739.html + * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors). + * Note that Rx overrun is not always fatal, on some chips we can continue + * operation without reseting the card, that's why int_fatal is not + * common for all chips. + * @AR5K_INT_TX: mask to identify received frame interrupts, of type + * AR5K_ISR_TXOK or AR5K_ISR_TXERR + * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?) + * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold + * We currently do increments on interrupt by + * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 + * @AR5K_INT_MIB: Indicates the Management Information Base counters should be + * checked. We should do this with ath5k_hw_update_mib_counters() but + * it seems we should also then do some noise immunity work. + * @AR5K_INT_RXPHY: RX PHY Error + * @AR5K_INT_RXKCM: RX Key cache miss + * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a + * beacon that must be handled in software. The alternative is if you + * have VEOL support, in that case you let the hardware deal with things. + * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing + * beacons from the AP have associated with, we should probably try to + * reassociate. When in IBSS mode this might mean we have not received + * any beacons from any local stations. Note that every station in an + * IBSS schedules to send beacons at the Target Beacon Transmission Time + * (TBTT) with a random backoff. + * @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? + * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now + * until properly handled + * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA + * errors. These types of errors we can enable seem to be of type + * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. + * @AR5K_INT_GLOBAL: Used to clear and set the IER + * @AR5K_INT_NOCARD: signals the card has been removed + * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same + * bit value + * + * These are mapped to take advantage of some common bits + * between the MACs, to be able to set intr properties + * easier. Some of them are not used yet inside hw.c. Most map + * to the respective hw interrupt value as they are common amogst different + * MACs. + */ +enum ath5k_int { + AR5K_INT_RXOK = 0x00000001, + AR5K_INT_RXDESC = 0x00000002, + AR5K_INT_RXERR = 0x00000004, + AR5K_INT_RXNOFRM = 0x00000008, + AR5K_INT_RXEOL = 0x00000010, + AR5K_INT_RXORN = 0x00000020, + AR5K_INT_TXOK = 0x00000040, + AR5K_INT_TXDESC = 0x00000080, + AR5K_INT_TXERR = 0x00000100, + AR5K_INT_TXNOFRM = 0x00000200, + AR5K_INT_TXEOL = 0x00000400, + AR5K_INT_TXURN = 0x00000800, + AR5K_INT_MIB = 0x00001000, + AR5K_INT_SWI = 0x00002000, + AR5K_INT_RXPHY = 0x00004000, + AR5K_INT_RXKCM = 0x00008000, + AR5K_INT_SWBA = 0x00010000, + AR5K_INT_BRSSI = 0x00020000, + AR5K_INT_BMISS = 0x00040000, + AR5K_INT_FATAL = 0x00080000, /* Non common */ + AR5K_INT_BNR = 0x00100000, /* Non common */ + AR5K_INT_TIM = 0x00200000, /* Non common */ + AR5K_INT_DTIM = 0x00400000, /* Non common */ + AR5K_INT_DTIM_SYNC = 0x00800000, /* Non common */ + AR5K_INT_GPIO = 0x01000000, + AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ + AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ + AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ + AR5K_INT_QCBRORN = 0x10000000, /* Non common */ + AR5K_INT_QCBRURN = 0x20000000, /* Non common */ + AR5K_INT_QTRIG = 0x40000000, /* Non common */ + AR5K_INT_GLOBAL = 0x80000000, + + AR5K_INT_COMMON = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR + | AR5K_INT_RXNOFRM + | AR5K_INT_RXEOL + | AR5K_INT_RXORN + | AR5K_INT_TXOK + | AR5K_INT_TXDESC + | AR5K_INT_TXERR + | AR5K_INT_TXNOFRM + | AR5K_INT_TXEOL + | AR5K_INT_TXURN + | AR5K_INT_MIB + | AR5K_INT_SWI + | AR5K_INT_RXPHY + | AR5K_INT_RXKCM + | AR5K_INT_SWBA + | AR5K_INT_BRSSI + | AR5K_INT_BMISS + | AR5K_INT_GPIO + | AR5K_INT_GLOBAL, + + AR5K_INT_NOCARD = 0xffffffff +}; + +/* + * Power management + */ +enum ath5k_power_mode { + AR5K_PM_UNDEFINED = 0, + AR5K_PM_AUTO, + AR5K_PM_AWAKE, + AR5K_PM_FULL_SLEEP, + AR5K_PM_NETWORK_SLEEP, +}; + +/* + * These match net80211 definitions (not used in + * mac80211). + * TODO: Clean this up + */ +#define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/ +#define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/ +#define AR5K_LED_AUTH 2 /*IEEE80211_S_AUTH*/ +#define AR5K_LED_ASSOC 3 /*IEEE80211_S_ASSOC*/ +#define AR5K_LED_RUN 4 /*IEEE80211_S_RUN*/ + +/* GPIO-controlled software LED */ +#define AR5K_SOFTLED_PIN 0 +#define AR5K_SOFTLED_ON 0 +#define AR5K_SOFTLED_OFF 1 + +/* + * Chipset capabilities -see ath5k_hw_get_capability- + * get_capability function is not yet fully implemented + * 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 */ + AR5K_CAP_TKIP_MIC = 2, /* Can handle TKIP MIC in hardware */ + AR5K_CAP_TKIP_SPLIT = 3, /* TKIP uses split keys */ + AR5K_CAP_PHYCOUNTERS = 4, /* PHY error counters */ + AR5K_CAP_DIVERSITY = 5, /* Supports fast diversity */ + AR5K_CAP_NUM_TXQUEUES = 6, /* Used to get max number of hw txqueues */ + AR5K_CAP_VEOL = 7, /* Supports virtual EOL */ + AR5K_CAP_COMPRESSION = 8, /* Supports compression */ + AR5K_CAP_BURST = 9, /* Supports packet bursting */ + AR5K_CAP_FASTFRAME = 10, /* Supports fast frames */ + AR5K_CAP_TXPOW = 11, /* Used to get global tx power limit */ + AR5K_CAP_TPC = 12, /* Can do per-packet tx power control (needed for 802.11a) */ + AR5K_CAP_BSSIDMASK = 13, /* Supports bssid mask */ + AR5K_CAP_MCAST_KEYSRCH = 14, /* Supports multicast key search */ + AR5K_CAP_TSF_ADJUST = 15, /* Supports beacon tsf adjust */ + AR5K_CAP_XR = 16, /* Supports XR mode */ + AR5K_CAP_WME_TKIPMIC = 17, /* Supports TKIP MIC when using WMM */ + AR5K_CAP_CHAN_HALFRATE = 18, /* Supports half rate channels */ + AR5K_CAP_CHAN_QUARTERRATE = 19, /* Supports quarter rate channels */ + AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */ +}; + + +/* XXX: we *may* move cap_range stuff to struct wiphy */ +struct ath5k_capabilities { + /* + * Supported PHY modes + * (ie. CHANNEL_A, CHANNEL_B, ...) + */ + DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX); + + /* + * Frequency range (without regulation restrictions) + */ + struct { + u16 range_2ghz_min; + u16 range_2ghz_max; + u16 range_5ghz_min; + u16 range_5ghz_max; + } cap_range; + + /* + * Values stored in the EEPROM (some of them...) + */ + struct ath5k_eeprom_info cap_eeprom; + + /* + * Queue information + */ + struct { + u8 q_tx_num; + } cap_queues; +}; + + +/***************************************\ + HARDWARE ABSTRACTION LAYER STRUCTURE +\***************************************/ + +/* + * Misc defines + */ + +#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; + + struct ath5k_softc *ah_sc; + void __iomem *ah_iobase; + + enum ath5k_int ah_imr; + + enum nl80211_iftype ah_op_mode; + enum ath5k_power_mode ah_power_mode; + struct ieee80211_channel ah_current_channel; + bool ah_turbo; + bool ah_calibration; + bool ah_running; + bool ah_single_chip; + bool ah_combined_mic; + + u32 ah_mac_srev; + u16 ah_mac_version; + u16 ah_mac_revision; + u16 ah_phy_revision; + u16 ah_radio_5ghz_revision; + u16 ah_radio_2ghz_revision; + + enum ath5k_version ah_version; + enum ath5k_radio ah_radio; + u32 ah_phy; + + bool ah_5ghz; + bool ah_2ghz; + +#define ah_modes ah_capabilities.cap_mode +#define ah_ee_version ah_capabilities.cap_eeprom.ee_version + + u32 ah_atim_window; + u32 ah_aifs; + u32 ah_cw_min; + u32 ah_cw_max; + bool ah_software_retry; + u32 ah_limit_tx_retries; + + u32 ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; + bool ah_ant_diversity; + + u8 ah_sta_id[ETH_ALEN]; + + /* Current BSSID we are trying to assoc to / create. + * This is passed by mac80211 on config_interface() and cached here for + * use in resets */ + u8 ah_bssid[ETH_ALEN]; + u8 ah_bssid_mask[ETH_ALEN]; + + u32 ah_gpio[AR5K_MAX_GPIO]; + int ah_gpio_npins; + + struct ath_regulatory ah_regulatory; + struct ath5k_capabilities ah_capabilities; + + struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; + u32 ah_txq_status; + u32 ah_txq_imr_txok; + u32 ah_txq_imr_txerr; + u32 ah_txq_imr_txurn; + u32 ah_txq_imr_txdesc; + u32 ah_txq_imr_txeol; + u32 ah_txq_imr_cbrorn; + u32 ah_txq_imr_cbrurn; + u32 ah_txq_imr_qtrig; + u32 ah_txq_imr_nofrm; + u32 ah_txq_isr; + u32 *ah_rf_banks; + size_t ah_rf_banks_size; + size_t ah_rf_regs_count; + struct ath5k_gain ah_gain; + u8 ah_offset[AR5K_MAX_RF_BANKS]; + + + struct { + /* Temporary tables used for interpolation */ + u8 tmpL[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_POWER_TABLE_SIZE]; + u8 tmpR[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_POWER_TABLE_SIZE]; + u8 txp_pd_table[AR5K_EEPROM_POWER_TABLE_SIZE * 2]; + u16 txp_rates_power_table[AR5K_MAX_RATES]; + u8 txp_min_idx; + bool txp_tpc; + /* Values in 0.25dB units */ + s16 txp_min_pwr; + s16 txp_max_pwr; + s16 txp_offset; + s16 txp_ofdm; + /* Values in dB units */ + s16 txp_cck_ofdm_pwr_delta; + s16 txp_cck_ofdm_gainf_delta; + } ah_txpower; + + struct { + bool r_enabled; + int r_last_alert; + struct ieee80211_channel r_last_channel; + } ah_radar; + + /* noise floor from last periodic calibration */ + s32 ah_noise_floor; + + /* + * 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_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 *, + struct ath5k_tx_status *); + int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *, + struct ath5k_rx_status *); +}; + +/* + * Prototypes + */ + +/* Attach/Detach Functions */ +extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); +extern void ath5k_hw_detach(struct ath5k_hw *ah); + +/* LED functions */ +extern int ath5k_init_leds(struct ath5k_softc *sc); +extern void ath5k_led_enable(struct ath5k_softc *sc); +extern void ath5k_led_off(struct ath5k_softc *sc); +extern void ath5k_unregister_leds(struct ath5k_softc *sc); + +/* Reset Functions */ +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_dma(struct ath5k_hw *ah); +extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); +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_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_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_eeprom_init(struct ath5k_hw *ah); +extern void ath5k_eeprom_detach(struct ath5k_hw *ah); +extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); +extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); + +/* Protocol Control Unit Functions */ +extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); +/* BSSID Functions */ +extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac); +extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); +extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); +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_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_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 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_set_tsf64(struct ath5k_hw *ah, u64 tsf64); +extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah); +extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); +#if 0 +extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state); +extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah); +extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr); +#endif +/* ACK bit rate */ +void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); +/* ACK/CTS Timeouts */ +extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); +extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); +extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); +extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); +/* Key table (WEP) functions */ +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_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 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_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_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_init(struct ath5k_hw *ah, + struct ieee80211_channel *channel, + unsigned int mode); +extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq); +extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); +extern int ath5k_hw_rfgain_opt_init(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_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_phy_disable(struct ath5k_hw *ah); +/* TX power setup */ +extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); +extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower); + +/* + * Functions used internaly + */ + +/* + * Translate usec to hw clock units + * TODO: Half/quarter rate + */ +static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) +{ + return turbo ? (usec * 80) : (usec * 40); +} + +/* + * Translate hw clock units to usec + * TODO: Half/quarter rate + */ +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; +} + +static inline int ath5k_pad_size(int hdrlen) +{ + return (hdrlen < 24) ? 0 : hdrlen & 3; +} + +#endif diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c new file mode 100644 index 0000000..70d376c --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * 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 +#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) +{ + + static const u32 static_pattern[4] = { + 0x55555555, 0xaaaaaaaa, + 0x66666666, 0x99999999 + }; + static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) }; + int i, c; + u16 cur_reg; + u32 var_pattern; + 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; + 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); + 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); + break; + case AR5K_SREV_RAD_2413: + ah->ah_radio = AR5K_RF2413; + ah->ah_single_chip = true; + break; + case AR5K_SREV_RAD_5413: + ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; + break; + case AR5K_SREV_RAD_2316: + ah->ah_radio = AR5K_RF2316; + ah->ah_single_chip = true; + break; + case AR5K_SREV_RAD_2317: + ah->ah_radio = AR5K_RF2317; + ah->ah_single_chip = true; + 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; + } else { + ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; + } + 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; + } else if (srev == AR5K_SREV_AR5213A && + ah->ah_phy_revision == AR5K_SREV_PHY_5212B) { + ah->ah_radio = AR5K_RF5112; + ah->ah_single_chip = false; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B; + } 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; + } 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; + } 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; + } 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; + } + + if (srev >= AR5K_SREV_AR2414) { + ah->ah_combined_mic = true; + AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, + AR5K_MISC_MODE_COMBINED_MIC); + } + + /* MAC address is cleared until add_interface */ + ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){}); + + /* 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_rfgain_opt_init(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); + + ath5k_eeprom_detach(ah); + + /* assume interrupts are down */ + kfree(ah); +} diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c new file mode 100644 index 0000000..ff6d4f8 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -0,0 +1,3110 @@ +/*- + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2004-2005 Atheros Communications, Inc. + * Copyright (c) 2006 Devicescape Software, Inc. + * Copyright (c) 2007 Jiri Slaby + * Copyright (c) 2007 Luis R. Rodriguez + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "base.h" +#include "reg.h" +#include "debug.h" + +static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +static int modparam_all_channels; +module_param_named(all_channels, modparam_all_channels, int, 0444); +MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); + + +/******************\ +* Internal defines * +\******************/ + +/* Module info */ +MODULE_AUTHOR("Jiri Slaby"); +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.6.0 (EXPERIMENTAL)"); + + +/* Known PCI ids */ +static const struct pci_device_id ath5k_pci_id_table[] = { + { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */ + { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */ + { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/ + { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */ + { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */ + { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */ + { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */ + { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */ + { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { 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 }, /* 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 const struct ath5k_srev_name srev_names[] = { + { "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 }, + { "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 const 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 + */ +static int __devinit ath5k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void __devexit ath5k_pci_remove(struct pci_dev *pdev); +#ifdef CONFIG_PM +static int ath5k_pci_suspend(struct pci_dev *pdev, + pm_message_t state); +static int ath5k_pci_resume(struct pci_dev *pdev); +#else +#define ath5k_pci_suspend NULL +#define ath5k_pci_resume NULL +#endif /* CONFIG_PM */ + +static struct pci_driver ath5k_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = ath5k_pci_id_table, + .probe = ath5k_pci_probe, + .remove = __devexit_p(ath5k_pci_remove), + .suspend = ath5k_pci_suspend, + .resume = ath5k_pci_resume, +}; + + + +/* + * Prototypes - MAC 802.11 stack related functions + */ +static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +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, + struct ieee80211_if_init_conf *conf); +static void ath5k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +static int ath5k_config(struct ieee80211_hw *hw, u32 changed); +static int ath5k_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf); +static void ath5k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist); +static int ath5k_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); +static int ath5k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats); +static int ath5k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); +static u64 ath5k_get_tsf(struct ieee80211_hw *hw); +static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); +static void ath5k_reset_tsf(struct ieee80211_hw *hw); +static int ath5k_beacon_update(struct ath5k_softc *sc, + struct sk_buff *skb); +static void ath5k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes); + +static const struct ieee80211_ops ath5k_hw_ops = { + .tx = ath5k_tx, + .start = ath5k_start, + .stop = ath5k_stop, + .add_interface = ath5k_add_interface, + .remove_interface = ath5k_remove_interface, + .config = ath5k_config, + .config_interface = ath5k_config_interface, + .configure_filter = ath5k_configure_filter, + .set_key = ath5k_set_key, + .get_stats = ath5k_get_stats, + .conf_tx = NULL, + .get_tx_stats = ath5k_get_tx_stats, + .get_tsf = ath5k_get_tsf, + .set_tsf = ath5k_set_tsf, + .reset_tsf = ath5k_reset_tsf, + .bss_info_changed = ath5k_bss_info_changed, +}; + +/* + * Prototypes - Internal functions + */ +/* Attach detach */ +static int ath5k_attach(struct pci_dev *pdev, + struct ieee80211_hw *hw); +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_channels(struct ath5k_hw *ah, + struct ieee80211_channel *channels, + unsigned int mode, + unsigned int max); +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); + +/* Descriptor setup */ +static int ath5k_desc_alloc(struct ath5k_softc *sc, + struct pci_dev *pdev); +static void ath5k_desc_free(struct ath5k_softc *sc, + struct pci_dev *pdev); +/* Buffers setup */ +static int ath5k_rxbuf_setup(struct ath5k_softc *sc, + struct ath5k_buf *bf); +static int ath5k_txbuf_setup(struct ath5k_softc *sc, + struct ath5k_buf *bf); +static inline void ath5k_txbuf_free(struct ath5k_softc *sc, + struct ath5k_buf *bf) +{ + BUG_ON(!bf); + if (!bf->skb) + return; + pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_any(bf->skb); + bf->skb = NULL; +} + +static inline void ath5k_rxbuf_free(struct ath5k_softc *sc, + struct ath5k_buf *bf) +{ + BUG_ON(!bf); + if (!bf->skb) + return; + pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(bf->skb); + bf->skb = NULL; +} + + +/* Queues setup */ +static struct ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc, + int qtype, int subtype); +static int ath5k_beaconq_setup(struct ath5k_hw *ah); +static int ath5k_beaconq_config(struct ath5k_softc *sc); +static void ath5k_txq_drainq(struct ath5k_softc *sc, + struct ath5k_txq *txq); +static void ath5k_txq_cleanup(struct ath5k_softc *sc); +static void ath5k_txq_release(struct ath5k_softc *sc); +/* Rx handling */ +static int ath5k_rx_start(struct ath5k_softc *sc); +static void ath5k_rx_stop(struct ath5k_softc *sc); +static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, + struct ath5k_desc *ds, + struct sk_buff *skb, + struct ath5k_rx_status *rs); +static void ath5k_tasklet_rx(unsigned long data); +/* Tx handling */ +static void ath5k_tx_processq(struct ath5k_softc *sc, + struct ath5k_txq *txq); +static void ath5k_tasklet_tx(unsigned long data); +/* Beacon handling */ +static int ath5k_beacon_setup(struct ath5k_softc *sc, + struct ath5k_buf *bf); +static void ath5k_beacon_send(struct ath5k_softc *sc); +static void ath5k_beacon_config(struct ath5k_softc *sc); +static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); +static void ath5k_tasklet_beacon(unsigned long data); + +static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) +{ + u64 tsf = ath5k_hw_get_tsf64(ah); + + if ((tsf & 0x7fff) < rstamp) + tsf -= 0x8000; + + return (tsf & ~0x7fff) | rstamp; +} + +/* Interrupt handling */ +static int ath5k_init(struct ath5k_softc *sc); +static int ath5k_stop_locked(struct ath5k_softc *sc); +static int ath5k_stop_hw(struct ath5k_softc *sc); +static irqreturn_t ath5k_intr(int irq, void *dev_id); +static void ath5k_tasklet_reset(unsigned long data); + +static void ath5k_calibrate(unsigned long data); + +/* + * Module init/exit functions + */ +static int __init +init_ath5k_pci(void) +{ + int ret; + + ath5k_debug_init(); + + ret = pci_register_driver(&ath5k_pci_driver); + if (ret) { + printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); + return ret; + } + + return 0; +} + +static void __exit +exit_ath5k_pci(void) +{ + pci_unregister_driver(&ath5k_pci_driver); + + ath5k_debug_finish(); +} + +module_init(init_ath5k_pci); +module_exit(exit_ath5k_pci); + + +/********************\ +* PCI Initialization * +\********************/ + +static const char * +ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) +{ + const char *name = "xxxxx"; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(srev_names); i++) { + if (srev_names[i].sr_type != type) + continue; + + 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; + } + } + + return name; +} + +static int __devinit +ath5k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *mem; + struct ath5k_softc *sc; + struct ieee80211_hw *hw; + int ret; + u8 csz; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "can't enable device\n"); + goto err; + } + + /* XXX 32-bit addressing only */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "32-bit DMA not available\n"); + goto err_dis; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES / sizeof(u32); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* + * Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state. + */ + pci_write_config_byte(pdev, 0x41, 0); + + ret = pci_request_region(pdev, 0, "ath5k"); + if (ret) { + dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); + goto err_dis; + } + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; + ret = -EIO; + goto err_reg; + } + + /* + * Allocate hw (mac80211 main struct) + * and hw->priv (driver private data) + */ + hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); + if (hw == NULL) { + dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); + ret = -ENOMEM; + goto err_map; + } + + dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); + + /* Initialize driver private data */ + SET_IEEE80211_DEV(hw, &pdev->dev); + 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; + sc->hw = hw; + sc->pdev = pdev; + + ath5k_debug_init_device(sc); + + /* + * Mark the device as detached to avoid processing + * interrupts until setup is complete. + */ + __set_bit(ATH_STAT_INVALID, sc->status); + + sc->iobase = mem; /* So we can unmap it on detach */ + sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ + sc->opmode = NL80211_IFTYPE_STATION; + mutex_init(&sc->lock); + spin_lock_init(&sc->rxbuflock); + spin_lock_init(&sc->txbuflock); + spin_lock_init(&sc->block); + + /* Set private data */ + pci_set_drvdata(pdev, hw); + + /* Setup interrupt handler */ + ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); + if (ret) { + ATH5K_ERR(sc, "request_irq failed\n"); + goto err_free; + } + + /* Initialize device */ + sc->ah = ath5k_hw_attach(sc, id->driver_data); + if (IS_ERR(sc->ah)) { + ret = PTR_ERR(sc->ah); + goto err_irq; + } + + /* set up multi-rate retry capabilities */ + if (sc->ah->ah_version == AR5K_AR5212) { + hw->max_rates = 4; + hw->max_rate_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_MAC, sc->ah->ah_mac_srev), + sc->ah->ah_mac_srev, + sc->ah->ah_phy_revision); + + if (!sc->ah->ah_single_chip) { + /* Single chip radio (!RF5111) */ + if (sc->ah->ah_radio_5ghz_revision && + !sc->ah->ah_radio_2ghz_revision) { + /* No 5GHz support -> report 2GHz radio */ + if (!test_bit(AR5K_MODE_11A, + sc->ah->ah_capabilities.cap_mode)) { + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* No 2GHz support (5110 and some + * 5Ghz only cards) -> report 5Ghz radio */ + } else if (!test_bit(AR5K_MODE_11B, + sc->ah->ah_capabilities.cap_mode)) { + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* Multiband radio */ + } else { + ATH5K_INFO(sc, "RF%s multiband radio found" + " (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + } + } + /* Multi chip radio (RF5111 - RF2111) -> + * report both 2GHz/5GHz radios */ + else if (sc->ah->ah_radio_5ghz_revision && + sc->ah->ah_radio_2ghz_revision){ + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_2ghz_revision), + sc->ah->ah_radio_2ghz_revision); + } + } + + + /* ready to process interrupts */ + __clear_bit(ATH_STAT_INVALID, sc->status); + + return 0; +err_ah: + ath5k_hw_detach(sc->ah); +err_irq: + free_irq(pdev->irq, sc); +err_free: + ieee80211_free_hw(hw); +err_map: + pci_iounmap(pdev, mem); +err_reg: + pci_release_region(pdev, 0); +err_dis: + pci_disable_device(pdev); +err: + return ret; +} + +static void __devexit +ath5k_pci_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + + ath5k_debug_finish_device(sc); + ath5k_detach(pdev, hw); + ath5k_hw_detach(sc->ah); + free_irq(pdev->irq, sc); + pci_iounmap(pdev, sc->iobase); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + ieee80211_free_hw(hw); +} + +#ifdef CONFIG_PM +static int +ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + + ath5k_led_off(sc); + + free_irq(pdev->irq, sc); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int +ath5k_pci_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + int err; + + pci_restore_state(pdev); + + err = pci_enable_device(pdev); + if (err) + return err; + + err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); + if (err) { + ATH5K_ERR(sc, "request_irq failed\n"); + goto err_no_irq; + } + + ath5k_led_enable(sc); + return 0; + +err_no_irq: + pci_disable_device(pdev); + return err; +} +#endif /* CONFIG_PM */ + + +/***********************\ +* Driver Initialization * +\***********************/ + +static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath5k_softc *sc = hw->priv; + struct ath_regulatory *reg = &sc->ah->ah_regulatory; + + return ath_reg_notifier_apply(wiphy, request, reg); +} + +static int +ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + u8 mac[ETH_ALEN] = {}; + int ret; + + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); + + /* + * Check if the MAC has multi-rate retry support. + * We do this by trying to setup a fake extended + * descriptor. MAC's that don't have support will + * return false w/o doing anything. MAC's that do + * support it will return true w/o doing anything. + */ + ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); + if (ret < 0) + goto err; + if (ret > 0) + __set_bit(ATH_STAT_MRRETRY, sc->status); + + /* + * Collect the channel list. The 802.11 layer + * is resposible for filtering this list based + * on settings like the phy mode and regulatory + * domain restrictions. + */ + ret = ath5k_setup_bands(hw); + if (ret) { + ATH5K_ERR(sc, "can't get channels\n"); + goto err; + } + + /* NB: setup here so ath5k_rate_update is happy */ + if (test_bit(AR5K_MODE_11A, ah->ah_modes)) + ath5k_setcurmode(sc, AR5K_MODE_11A); + else + ath5k_setcurmode(sc, AR5K_MODE_11B); + + /* + * Allocate tx+rx descriptors and populate the lists. + */ + ret = ath5k_desc_alloc(sc, pdev); + if (ret) { + ATH5K_ERR(sc, "can't allocate descriptors\n"); + goto err; + } + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that hw functions handle reseting + * these queues at the needed time. + */ + ret = ath5k_beaconq_setup(ah); + if (ret < 0) { + ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); + goto err_desc; + } + sc->bhalq = ret; + + sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); + if (IS_ERR(sc->txq)) { + ATH5K_ERR(sc, "can't setup xmit queue\n"); + ret = PTR_ERR(sc->txq); + goto err_bhal; + } + + tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); + tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); + tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); + tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); + setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); + + 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_queues; + } + + SET_IEEE80211_PERM_ADDR(hw, mac); + /* All MAC address bits matter for ACKs */ + memset(sc->bssidmask, 0xff, ETH_ALEN); + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + + ah->ah_regulatory.current_rd = + ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier); + if (ret) { + ATH5K_ERR(sc, "can't initialize regulatory system\n"); + goto err_queues; + } + + ret = ieee80211_register_hw(hw); + if (ret) { + ATH5K_ERR(sc, "can't register ieee80211 hw\n"); + goto err_queues; + } + + if (!ath_is_world_regd(&sc->ah->ah_regulatory)) + regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2); + + ath5k_init_leds(sc); + + return 0; +err_queues: + ath5k_txq_release(sc); +err_bhal: + ath5k_hw_release_tx_queue(ah, sc->bhalq); +err_desc: + ath5k_desc_free(sc, pdev); +err: + return ret; +} + +static void +ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * NB: the order of these is important: + * o call the 802.11 layer before detaching ath5k_hw to + * insure callbacks into the driver to delete global + * key cache entries can be handled + * o reclaim the tx queue data structures after calling + * the 802.11 layer as we'll get called back to reclaim + * node state and potentially want to use them + * o to cleanup the tx queues the hal is called, so detach + * it last + * XXX: ??? detach ath5k_hw ??? + * Other than that, it's straightforward... + */ + ieee80211_unregister_hw(hw); + ath5k_desc_free(sc, pdev); + ath5k_txq_release(sc); + ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); + ath5k_unregister_leds(sc); + + /* + * NB: can't reclaim these until after ieee80211_ifdetach + * returns because we'll get called back to reclaim node + * state and potentially want to use them. + */ +} + + + + +/********************\ +* Channel/mode setup * +\********************/ + +/* + * Convert IEEE channel number to MHz frequency. + */ +static inline short +ath5k_ieee2mhz(short chan) +{ + if (chan <= 14 || chan >= 27) + return ieee80211chan2mhz(chan); + else + return 2212 + chan * 20; +} + +/* + * Returns true for the channel numbers used without all_channels modparam. + */ +static bool ath5k_is_standard_channel(short chan) +{ + return ((chan <= 14) || + /* UNII 1,2 */ + ((chan & 3) == 0 && chan >= 36 && chan <= 64) || + /* midband */ + ((chan & 3) == 0 && chan >= 100 && chan <= 140) || + /* UNII-3 */ + ((chan & 3) == 1 && chan >= 149 && chan <= 165)); +} + +static unsigned int +ath5k_copy_channels(struct ath5k_hw *ah, + struct ieee80211_channel *channels, + unsigned int mode, + unsigned int max) +{ + unsigned int i, count, size, chfreq, freq, ch; + + if (!test_bit(mode, ah->ah_modes)) + return 0; + + switch (mode) { + case AR5K_MODE_11A: + case AR5K_MODE_11A_TURBO: + /* 1..220, but 2GHz frequencies are filtered by check_channel */ + size = 220 ; + chfreq = CHANNEL_5GHZ; + break; + case AR5K_MODE_11B: + case AR5K_MODE_11G: + case AR5K_MODE_11G_TURBO: + size = 26; + chfreq = CHANNEL_2GHZ; + break; + default: + ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); + return 0; + } + + for (i = 0, count = 0; i < size && max > 0; i++) { + ch = i + 1 ; + freq = ath5k_ieee2mhz(ch); + + /* Check if channel is supported by the chipset */ + if (!ath5k_channel_ok(ah, freq, chfreq)) + continue; + + if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) + continue; + + /* Write channel info and increment counter */ + channels[count].center_freq = freq; + channels[count].band = (chfreq == CHANNEL_2GHZ) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + switch (mode) { + case AR5K_MODE_11A: + case AR5K_MODE_11G: + channels[count].hw_value = chfreq | CHANNEL_OFDM; + break; + case AR5K_MODE_11A_TURBO: + case AR5K_MODE_11G_TURBO: + channels[count].hw_value = chfreq | + CHANNEL_OFDM | CHANNEL_TURBO; + break; + case AR5K_MODE_11B: + channels[count].hw_value = CHANNEL_B; + } + + count++; + max--; + } + + 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_setup_bands(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ieee80211_supported_band *sband; + int max_c, count_c = 0; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS); + max_c = ARRAY_SIZE(sc->channels); + + /* 2GHz band */ + sband = &sc->sbands[IEEE80211_BAND_2GHZ]; + sband->band = IEEE80211_BAND_2GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_2GHZ][0]; + + 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->channels = sc->channels; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11G, max_c); + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + count_c = sband->n_channels; + 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; + } + } + + sband->channels = sc->channels; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11B, max_c); + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + count_c = sband->n_channels; + max_c -= count_c; + } + ath5k_setup_rate_idx(sc, sband); + + /* 5GHz band, A mode */ + if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) { + sband = &sc->sbands[IEEE80211_BAND_5GHZ]; + sband->band = IEEE80211_BAND_5GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_5GHZ][0]; + + memcpy(sband->bitrates, &ath5k_rates[4], + sizeof(struct ieee80211_rate) * 8); + sband->n_bitrates = 8; + + sband->channels = &sc->channels[count_c]; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11A, max_c); + + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } + ath5k_setup_rate_idx(sc, sband); + + ath5k_debug_dump_bands(sc); + + return 0; +} + +/* + * Set/change channels. If the channel is really being changed, + * it's done by reseting the chip. To accomplish this we must + * first cleanup any pending DMA, then restart stuff after a la + * ath5k_init. + * + * Called with sc->lock. + */ +static int +ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", + sc->curchan->center_freq, chan->center_freq); + + if (chan->center_freq != sc->curchan->center_freq || + chan->hw_value != sc->curchan->hw_value) { + + sc->curchan = chan; + sc->curband = &sc->sbands[chan->band]; + + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + return ath5k_reset(sc, true, true); + } + + return 0; +} + +static void +ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) +{ + sc->curmode = mode; + + if (mode == AR5K_MODE_11A) { + sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ]; + } else { + sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ]; + } +} + +static void +ath5k_mode_setup(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + u32 rfilt; + + /* configure rx filter */ + rfilt = sc->filter_flags; + ath5k_hw_set_rx_filter(ah, rfilt); + + if (ath5k_hw_hasbssidmask(ah)) + ath5k_hw_set_bssid_mask(ah, sc->bssidmask); + + /* configure operational mode */ + ath5k_hw_set_opmode(ah); + + ath5k_hw_set_mcast_filter(ah, 0, 0); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); +} + +static inline int +ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) +{ + int rix; + + /* return base rate on errors */ + if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES, + "hw_rix out of bounds: %x\n", hw_rix)) + return 0; + + rix = sc->rate_idx[sc->curband->band][hw_rix]; + if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) + rix = 0; + + return rix; +} + +/***************\ +* Buffers setup * +\***************/ + +static +struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) +{ + struct sk_buff *skb; + unsigned int off; + + /* + * Allocate buffer with headroom_needed space for the + * fake physical layer header at the start. + */ + skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); + + if (!skb) { + ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", + sc->rxbufsize + sc->cachelsz - 1); + return NULL; + } + /* + * Cache-line-align. This is important (for the + * 5210 at least) as not doing so causes bogus data + * in rx'd frames. + */ + off = ((unsigned long)skb->data) % sc->cachelsz; + if (off != 0) + skb_reserve(skb, sc->cachelsz - off); + + *skb_addr = pci_map_single(sc->pdev, + skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { + ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); + dev_kfree_skb(skb); + return NULL; + } + return skb; +} + +static int +ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +{ + struct ath5k_hw *ah = sc->ah; + struct sk_buff *skb = bf->skb; + struct ath5k_desc *ds; + + if (!skb) { + skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr); + if (!skb) + return -ENOMEM; + bf->skb = skb; + } + + /* + * Setup descriptors. For receive we always terminate + * the descriptor list with a self-linked entry so we'll + * not get overrun under high load (as can happen with a + * 5212 when ANI processing enables PHY error frames). + * + * To insure the last descriptor is self-linked we create + * each descriptor as self-linked and add it to the end. As + * each additional descriptor is added the previous self-linked + * entry is ``fixed'' naturally. This should be safe even + * if DMA is happening. When processing RX interrupts we + * never remove/process the last, self-linked, entry on the + * descriptor list. This insures the hardware always has + * someplace to write a new frame. + */ + ds = bf->desc; + ds->ds_link = bf->daddr; /* link to self */ + ds->ds_data = bf->skbaddr; + ah->ah_setup_rx_desc(ah, ds, + skb_tailroom(skb), /* buffer size */ + 0); + + if (sc->rxlink != NULL) + *sc->rxlink = bf->daddr; + sc->rxlink = &ds->ds_link; + return 0; +} + +static int +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq *txq = sc->txq; + struct ath5k_desc *ds = bf->desc; + struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; + struct ieee80211_rate *rate; + unsigned int mrr_rate[3], mrr_tries[3]; + int i, ret; + u16 hw_rate; + u16 cts_rate = 0; + u16 duration = 0; + u8 rc_flags; + + flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; + + /* XXX endianness */ + bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + rate = ieee80211_get_tx_rate(sc->hw, info); + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + flags |= AR5K_TXDESC_NOACK; + + rc_flags = info->control.rates[0].flags; + hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? + rate->hw_value_short : rate->hw_value; + + pktlen = skb->len; + + /* FIXME: If we are in g mode and rate is a CCK rate + * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta + * from tx power (value is in dB units already) */ + if (info->control.hw_key) { + keyidx = info->control.hw_key->hw_key_idx; + pktlen += info->control.hw_key->icv_len; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + flags |= AR5K_TXDESC_RTSENA; + cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; + duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, + sc->vif, pktlen, info)); + } + if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + flags |= AR5K_TXDESC_CTSENA; + cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; + duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, + sc->vif, pktlen, info)); + } + ret = ah->ah_setup_tx_desc(ah, ds, pktlen, + ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, + (sc->power_level * 2), + hw_rate, + info->control.rates[0].count, keyidx, 0, flags, + cts_rate, duration); + 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.rates[i + 1].count; + } + + 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; + + spin_lock_bh(&txq->lock); + list_add_tail(&bf->list, &txq->q); + sc->tx_stats[txq->qnum].len++; + if (txq->link == NULL) /* is this first packet? */ + 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_start_tx_dma(ah, txq->qnum); + mmiowb(); + spin_unlock_bh(&txq->lock); + + return 0; +err_unmap: + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); + return ret; +} + +/*******************\ +* Descriptors setup * +\*******************/ + +static int +ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) +{ + struct ath5k_desc *ds; + struct ath5k_buf *bf; + dma_addr_t da; + unsigned int i; + int ret; + + /* allocate descriptors */ + sc->desc_len = sizeof(struct ath5k_desc) * + (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1); + sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr); + if (sc->desc == NULL) { + ATH5K_ERR(sc, "can't allocate descriptors\n"); + ret = -ENOMEM; + goto err; + } + ds = sc->desc; + da = sc->desc_daddr; + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n", + ds, sc->desc_len, (unsigned long long)sc->desc_daddr); + + bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, + sizeof(struct ath5k_buf), GFP_KERNEL); + if (bf == NULL) { + ATH5K_ERR(sc, "can't allocate bufptr\n"); + ret = -ENOMEM; + goto err_free; + } + sc->bufptr = bf; + + INIT_LIST_HEAD(&sc->rxbuf); + for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->rxbuf); + } + + INIT_LIST_HEAD(&sc->txbuf); + sc->txbuf_len = ATH_TXBUF; + for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, + da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->txbuf); + } + + /* beacon buffer */ + bf->desc = ds; + bf->daddr = da; + sc->bbuf = bf; + + return 0; +err_free: + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); +err: + sc->desc = NULL; + return ret; +} + +static void +ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) +{ + struct ath5k_buf *bf; + + ath5k_txbuf_free(sc, sc->bbuf); + list_for_each_entry(bf, &sc->txbuf, list) + ath5k_txbuf_free(sc, bf); + list_for_each_entry(bf, &sc->rxbuf, list) + ath5k_rxbuf_free(sc, bf); + + /* Free memory associated with all descriptors */ + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); + + kfree(sc->bufptr); + sc->bufptr = NULL; +} + + + + + +/**************\ +* Queues setup * +\**************/ + +static struct ath5k_txq * +ath5k_txq_setup(struct ath5k_softc *sc, + int qtype, int subtype) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq *txq; + struct ath5k_txq_info qi = { + .tqi_subtype = subtype, + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT + }; + int qnum; + + /* + * Enable interrupts only for EOL and DESC conditions. + * We mark tx descriptors to receive a DESC interrupt + * when a tx queue gets deep; otherwise waiting for the + * EOL to reap descriptors. Note that this is done to + * reduce interrupt load and this only defers reaping + * descriptors, never transmitting frames. Aside from + * reducing interrupts this also permits more concurrency. + * The only potential downside is if the tx queue backs + * up in which case the top half of the kernel may backup + * due to a lack of tx descriptors. + */ + qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE | + AR5K_TXQ_FLAG_TXDESCINT_ENABLE; + qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi); + if (qnum < 0) { + /* + * NB: don't print a message, this happens + * normally on parts with too few tx queues + */ + return ERR_PTR(qnum); + } + if (qnum >= ARRAY_SIZE(sc->txqs)) { + ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n", + qnum, ARRAY_SIZE(sc->txqs)); + ath5k_hw_release_tx_queue(ah, qnum); + return ERR_PTR(-EINVAL); + } + txq = &sc->txqs[qnum]; + if (!txq->setup) { + txq->qnum = qnum; + txq->link = NULL; + INIT_LIST_HEAD(&txq->q); + spin_lock_init(&txq->lock); + txq->setup = true; + } + return &sc->txqs[qnum]; +} + +static int +ath5k_beaconq_setup(struct ath5k_hw *ah) +{ + struct ath5k_txq_info qi = { + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT, + /* NB: for dynamic turbo, don't enable any other interrupts */ + .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE + }; + + return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); +} + +static int +ath5k_beaconq_config(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq_info qi; + int ret; + + ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) + return ret; + if (sc->opmode == NL80211_IFTYPE_AP || + sc->opmode == NL80211_IFTYPE_MESH_POINT) { + /* + * Always burst out beacon and CAB traffic + * (aifs = cwmin = cwmax = 0) + */ + qi.tqi_aifs = 0; + qi.tqi_cw_min = 0; + qi.tqi_cw_max = 0; + } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { + /* + * Adhoc mode; backoff between 0 and (2 * cw_min). + */ + qi.tqi_aifs = 0; + qi.tqi_cw_min = 0; + qi.tqi_cw_max = 2 * ah->ah_cw_min; + } + + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "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_set_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) { + ATH5K_ERR(sc, "%s: unable to update parameters for beacon " + "hardware queue!\n", __func__); + return ret; + } + + return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */; +} + +static void +ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) +{ + struct ath5k_buf *bf, *bf0; + + /* + * NB: this assumes output has been stopped and + * we do not need to block ath5k_tx_tasklet + */ + spin_lock_bh(&txq->lock); + list_for_each_entry_safe(bf, bf0, &txq->q, list) { + ath5k_debug_printtxbuf(sc, bf); + + ath5k_txbuf_free(sc, bf); + + spin_lock_bh(&sc->txbuflock); + sc->tx_stats[txq->qnum].len--; + list_move_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock_bh(&sc->txbuflock); + } + txq->link = NULL; + spin_unlock_bh(&txq->lock); +} + +/* + * Drain the transmit queues and reclaim resources. + */ +static void +ath5k_txq_cleanup(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + unsigned int i; + + /* XXX return value */ + if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) { + /* 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_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_txdp(ah, + sc->txqs[i].qnum), + sc->txqs[i].link); + } + } + ieee80211_wake_queues(sc->hw); /* XXX move to callers */ + + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) + if (sc->txqs[i].setup) + ath5k_txq_drainq(sc, &sc->txqs[i]); +} + +static void +ath5k_txq_release(struct ath5k_softc *sc) +{ + struct ath5k_txq *txq = sc->txqs; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++) + if (txq->setup) { + ath5k_hw_release_tx_queue(sc->ah, txq->qnum); + txq->setup = false; + } +} + + + + +/*************\ +* RX Handling * +\*************/ + +/* + * Enable the receive h/w following a reset. + */ +static int +ath5k_rx_start(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_buf *bf; + int ret; + + sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", + sc->cachelsz, sc->rxbufsize); + + sc->rxlink = NULL; + + spin_lock_bh(&sc->rxbuflock); + list_for_each_entry(bf, &sc->rxbuf, list) { + ret = ath5k_rxbuf_setup(sc, bf); + if (ret != 0) { + spin_unlock_bh(&sc->rxbuflock); + goto err; + } + } + bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); + spin_unlock_bh(&sc->rxbuflock); + + 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 */ + + return 0; +err: + return ret; +} + +/* + * Disable the receive h/w in preparation for a reset. + */ +static void +ath5k_rx_stop(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + + 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 */ + + ath5k_debug_printrxbuffs(sc, ah); + + sc->rxlink = NULL; /* just in case */ +} + +static unsigned int +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; + + if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && + rs->rs_keyix != AR5K_RXKEYIX_INVALID) + return RX_FLAG_DECRYPTED; + + /* 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) { + keyix = skb->data[hlen + 3] >> 6; + + if (test_bit(keyix, sc->keymap)) + return RX_FLAG_DECRYPTED; + } + + return 0; +} + + +static void +ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, + struct ieee80211_rx_status *rxs) +{ + u64 tsf, bc_tstamp; + u32 hw_tu; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + + if (ieee80211_is_beacon(mgmt->frame_control) && + le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && + memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { + /* + * Received an IBSS beacon with the same BSSID. Hardware *must* + * have updated the local TSF. We have to work around various + * hardware bugs, though... + */ + tsf = ath5k_hw_get_tsf64(sc->ah); + bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp); + hw_tu = TSF_TO_TU(tsf); + + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "beacon %llx mactime %llx (diff %lld) tsf now %llx\n", + (unsigned long long)bc_tstamp, + (unsigned long long)rxs->mactime, + (unsigned long long)(rxs->mactime - bc_tstamp), + (unsigned long long)tsf); + + /* + * Sometimes the HW will give us a wrong tstamp in the rx + * status, causing the timestamp extension to go wrong. + * (This seems to happen especially with beacon frames bigger + * than 78 byte (incl. FCS)) + * But we know that the receive timestamp must be later than the + * timestamp of the beacon since HW must have synced to that. + * + * NOTE: here we assume mactime to be after the frame was + * received, not like mac80211 which defines it at the start. + */ + if (bc_tstamp > rxs->mactime) { + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "fixing mactime from %llx to %llx\n", + (unsigned long long)rxs->mactime, + (unsigned long long)tsf); + rxs->mactime = tsf; + } + + /* + * Local TSF might have moved higher than our beacon timers, + * in that case we have to update them to continue sending + * beacons. This also takes care of synchronizing beacon sending + * times with other stations. + */ + if (hw_tu >= sc->nexttbtt) + ath5k_beacon_update_timers(sc, bc_tstamp); + } +} + +static void ath5k_tasklet_beacon(unsigned long data) +{ + struct ath5k_softc *sc = (struct ath5k_softc *) data; + + /* + * Software beacon alert--time to send a beacon. + * + * In IBSS mode we use this interrupt just to + * keep track of the next TBTT (target beacon + * transmission time) in order to detect wether + * automatic TSF updates happened. + */ + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + /* XXX: only if VEOL suppported */ + u64 tsf = ath5k_hw_get_tsf64(sc->ah); + sc->nexttbtt += sc->bintval; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "SWBA nexttbtt: %x hw_tu: %x " + "TSF: %llx\n", + sc->nexttbtt, + TSF_TO_TU(tsf), + (unsigned long long) tsf); + } else { + spin_lock(&sc->block); + ath5k_beacon_send(sc); + spin_unlock(&sc->block); + } +} + +static void +ath5k_tasklet_rx(unsigned long data) +{ + struct ieee80211_rx_status rxs = {}; + struct ath5k_rx_status rs = {}; + struct sk_buff *skb, *next_skb; + dma_addr_t next_skb_addr; + struct ath5k_softc *sc = (void *)data; + struct ath5k_buf *bf, *bf_last; + struct ath5k_desc *ds; + int ret; + int hdrlen; + int padsize; + + spin_lock(&sc->rxbuflock); + if (list_empty(&sc->rxbuf)) { + ATH5K_WARN(sc, "empty rx buf pool\n"); + goto unlock; + } + bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list); + do { + rxs.flag = 0; + + bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); + BUG_ON(bf->skb == NULL); + skb = bf->skb; + ds = bf->desc; + + /* + * last buffer must not be freed to ensure proper hardware + * function. When the hardware finishes also a packet next to + * it, we are sure, it doesn't use it anymore and we can go on. + */ + if (bf_last == bf) + bf->flags |= 1; + if (bf->flags) { + struct ath5k_buf *bf_next = list_entry(bf->list.next, + struct ath5k_buf, list); + ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc, + &rs); + if (ret) + break; + bf->flags &= ~1; + /* skip the overwritten one (even status is martian) */ + goto next; + } + + ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); + if (unlikely(ret == -EINPROGRESS)) + break; + else if (unlikely(ret)) { + ATH5K_ERR(sc, "error in processing rx descriptor\n"); + spin_unlock(&sc->rxbuflock); + return; + } + + if (unlikely(rs.rs_more)) { + ATH5K_WARN(sc, "unsupported jumbo\n"); + goto next; + } + + if (unlikely(rs.rs_status)) { + if (rs.rs_status & AR5K_RXERR_PHY) + goto next; + if (rs.rs_status & AR5K_RXERR_DECRYPT) { + /* + * Decrypt error. If the error occurred + * because there was no hardware key, then + * let the frame through so the upper layers + * can process it. This is necessary for 5210 + * parts which have no way to setup a ``clear'' + * key cache entry. + * + * XXX do key cache faulting + */ + if (rs.rs_keyix == AR5K_RXKEYIX_INVALID && + !(rs.rs_status & AR5K_RXERR_CRC)) + goto accept; + } + if (rs.rs_status & AR5K_RXERR_MIC) { + rxs.flag |= RX_FLAG_MMIC_ERROR; + goto accept; + } + + /* let crypto-error packets fall through in MNTR */ + if ((rs.rs_status & + ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || + sc->opmode != NL80211_IFTYPE_MONITOR) + goto next; + } +accept: + next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); + + /* + * If we can't replace bf->skb with a new skb under memory + * pressure, just skip this packet + */ + if (!next_skb) + goto next; + + pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, + PCI_DMA_FROMDEVICE); + skb_put(skb, rs.rs_datalen); + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padsize = ath5k_pad_size(hdrlen); + if (padsize) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + + /* + * always extend the mac timestamp, since this information is + * also needed for proper IBSS merging. + * + * XXX: it might be too late to do it here, since rs_tstamp is + * 15bit only. that means TSF extension has to be done within + * 32768usec (about 32ms). it might be necessary to move this to + * the interrupt handler, like it is done in madwifi. + * + * Unfortunately we don't know when the hardware takes the rx + * timestamp (beginning of phy frame, data frame, end of rx?). + * The only thing we know is that it is hardware specific... + * On AR5213 it seems the rx timestamp is at the end of the + * frame, but i'm not sure. + * + * NOTE: mac80211 defines mactime at the beginning of the first + * data symbol. Since we don't have any time references it's + * impossible to comply to that. This affects IBSS merge only + * right now, so it's not too bad... + */ + rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); + rxs.flag |= RX_FLAG_TSFT; + + rxs.freq = sc->curchan->center_freq; + rxs.band = sc->curband->band; + + rxs.noise = sc->ah->ah_noise_floor; + rxs.signal = rxs.noise + rs.rs_rssi; + + /* An rssi of 35 indicates you should be able use + * 54 Mbps reliably. A more elaborate scheme can be used + * here but it requires a map of SNR/throughput for each + * possible mode used */ + rxs.qual = rs.rs_rssi * 100 / 35; + + /* rssi can be more than 35 though, anything above that + * should be considered at 100% */ + if (rxs.qual > 100) + rxs.qual = 100; + + rxs.antenna = rs.rs_antenna; + 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 == NL80211_IFTYPE_ADHOC) + ath5k_check_ibss_tsf(sc, skb, &rxs); + + __ieee80211_rx(sc->hw, skb, &rxs); + + bf->skb = next_skb; + bf->skbaddr = next_skb_addr; +next: + list_move_tail(&bf->list, &sc->rxbuf); + } while (ath5k_rxbuf_setup(sc, bf) == 0); +unlock: + spin_unlock(&sc->rxbuflock); +} + + + + +/*************\ +* TX Handling * +\*************/ + +static void +ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) +{ + struct ath5k_tx_status ts = {}; + struct ath5k_buf *bf, *bf0; + struct ath5k_desc *ds; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + int i, ret; + + spin_lock(&txq->lock); + list_for_each_entry_safe(bf, bf0, &txq->q, list) { + ds = bf->desc; + + ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); + if (unlikely(ret == -EINPROGRESS)) + break; + else if (unlikely(ret)) { + ATH5K_ERR(sc, "error %d while processing queue %u\n", + ret, txq->qnum); + break; + } + + skb = bf->skb; + info = IEEE80211_SKB_CB(skb); + bf->skb = NULL; + + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, + PCI_DMA_TODEVICE); + + ieee80211_tx_info_clear_status(info); + for (i = 0; i < 4; i++) { + struct ieee80211_tx_rate *r = + &info->status.rates[i]; + + if (ts.ts_rate[i]) { + r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); + r->count = ts.ts_retry[i]; + } else { + r->idx = -1; + r->count = 0; + } + } + + /* count the successful attempt as well */ + info->status.rates[ts.ts_final_idx].count++; + + if (unlikely(ts.ts_status)) { + sc->ll_stats.dot11ACKFailureCount++; + if (ts.ts_status & AR5K_TXERR_FILT) + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + } else { + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ts.ts_rssi; + } + + ieee80211_tx_status(sc->hw, skb); + sc->tx_stats[txq->qnum].count++; + + spin_lock(&sc->txbuflock); + sc->tx_stats[txq->qnum].len--; + list_move_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock(&sc->txbuflock); + } + if (likely(list_empty(&txq->q))) + txq->link = NULL; + spin_unlock(&txq->lock); + if (sc->txbuf_len > ATH_TXBUF / 5) + ieee80211_wake_queues(sc->hw); +} + +static void +ath5k_tasklet_tx(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + + ath5k_tx_processq(sc, sc->txq); +} + + +/*****************\ +* Beacon handling * +\*****************/ + +/* + * Setup the beacon frame for transmit. + */ +static int +ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +{ + struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ath5k_hw *ah = sc->ah; + struct ath5k_desc *ds; + int ret, antenna = 0; + u32 flags; + + bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] " + "skbaddr %llx\n", skb, skb->data, skb->len, + (unsigned long long)bf->skbaddr); + if (pci_dma_mapping_error(sc->pdev, bf->skbaddr)) { + ATH5K_ERR(sc, "beacon DMA mapping failed\n"); + return -EIO; + } + + ds = bf->desc; + + flags = AR5K_TXDESC_NOACK; + if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { + ds->ds_link = bf->daddr; /* self-linked */ + flags |= AR5K_TXDESC_VEOL; + /* + * Let hardware handle antenna switching if txantenna is not set + */ + } else { + ds->ds_link = 0; + /* + * Switch antenna every 4 beacons if txantenna is not set + * XXX assumes two antennas + */ + if (antenna == 0) + antenna = sc->bsent & 4 ? 2 : 1; + } + + /* FIXME: If we are in g mode and rate is a CCK rate + * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta + * from tx power (value is in dB units already) */ + ds->ds_data = bf->skbaddr; + ret = ah->ah_setup_tx_desc(ah, ds, skb->len, + ieee80211_get_hdrlen_from_skb(skb), + AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), + ieee80211_get_tx_rate(sc->hw, info)->hw_value, + 1, AR5K_TXKEYIX_INVALID, + antenna, flags, 0, 0); + if (ret) + goto err_unmap; + + return 0; +err_unmap: + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); + return ret; +} + +/* + * Transmit a beacon frame at SWBA. Dynamic updates to the + * frame contents are done as needed and the slot time is + * also adjusted based on current state. + * + * This is called from software irq context (beacontq or restq + * tasklets) or user context from ath5k_beacon_config. + */ +static void +ath5k_beacon_send(struct ath5k_softc *sc) +{ + struct ath5k_buf *bf = sc->bbuf; + struct ath5k_hw *ah = sc->ah; + + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); + + 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; + } + /* + * Check if the previous beacon has gone out. If + * not don't don't try to post another, skip this + * period and wait for the next. Missed beacons + * indicate a problem and should not occur. If we + * miss too many consecutive beacons reset the device. + */ + if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) { + sc->bmisscount++; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "missed %u consecutive beacons\n", sc->bmisscount); + if (sc->bmisscount > 3) { /* NB: 3 is a guess */ + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "stuck beacon time (%u missed)\n", + sc->bmisscount); + tasklet_schedule(&sc->restq); + } + return; + } + if (unlikely(sc->bmisscount != 0)) { + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "resume beacon xmit after %u misses\n", + sc->bmisscount); + sc->bmisscount = 0; + } + + /* + * Stop any current dma and put the new frame on the queue. + * This should never fail since we check above that no frames + * are still pending on the queue. + */ + if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { + ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); + /* NB: hw still stops DMA, so proceed */ + } + + 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); + + sc->bsent++; +} + + +/** + * ath5k_beacon_update_timers - update beacon timers + * + * @sc: struct ath5k_softc pointer we are operating on + * @bc_tsf: the timestamp of the beacon. 0 to reset the TSF. -1 to perform a + * beacon timer update based on the current HW TSF. + * + * Calculate the next target beacon transmit time (TBTT) based on the timestamp + * of a received beacon or the current local hardware TSF and write it to the + * beacon timer registers. + * + * This is called in a variety of situations, e.g. when a beacon is received, + * when a TSF update has been detected, but also when an new IBSS is created or + * when we otherwise know we have to update the timers, but we keep it in this + * function to have it all together in one place. + */ +static void +ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) +{ + struct ath5k_hw *ah = sc->ah; + u32 nexttbtt, intval, hw_tu, bc_tu; + u64 hw_tsf; + + intval = sc->bintval & AR5K_BEACON_PERIOD; + if (WARN_ON(!intval)) + return; + + /* beacon TSF converted to TU */ + bc_tu = TSF_TO_TU(bc_tsf); + + /* current TSF converted to TU */ + hw_tsf = ath5k_hw_get_tsf64(ah); + hw_tu = TSF_TO_TU(hw_tsf); + +#define FUDGE 3 + /* we use FUDGE to make sure the next TBTT is ahead of the current TU */ + if (bc_tsf == -1) { + /* + * no beacons received, called internally. + * just need to refresh timers based on HW TSF. + */ + nexttbtt = roundup(hw_tu + FUDGE, intval); + } else if (bc_tsf == 0) { + /* + * no beacon received, probably called by ath5k_reset_tsf(). + * reset TSF to start with 0. + */ + nexttbtt = intval; + intval |= AR5K_BEACON_RESET_TSF; + } else if (bc_tsf > hw_tsf) { + /* + * beacon received, SW merge happend but HW TSF not yet updated. + * not possible to reconfigure timers yet, but next time we + * receive a beacon with the same BSSID, the hardware will + * automatically update the TSF and then we need to reconfigure + * the timers. + */ + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "need to wait for HW TSF sync\n"); + return; + } else { + /* + * most important case for beacon synchronization between STA. + * + * beacon received and HW TSF has been already updated by HW. + * update next TBTT based on the TSF of the beacon, but make + * sure it is ahead of our local TSF timer. + */ + nexttbtt = bc_tu + roundup(hw_tu + FUDGE - bc_tu, intval); + } +#undef FUDGE + + sc->nexttbtt = nexttbtt; + + intval |= AR5K_BEACON_ENA; + ath5k_hw_init_beacon(ah, nexttbtt, intval); + + /* + * debugging output last in order to preserve the time critical aspect + * of this function + */ + if (bc_tsf == -1) + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "reconfigured timers based on HW TSF\n"); + else if (bc_tsf == 0) + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "reset HW TSF and timers\n"); + else + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "updated timers based on beacon TSF\n"); + + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n", + (unsigned long long) bc_tsf, + (unsigned long long) hw_tsf, bc_tu, hw_tu, nexttbtt); + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "intval %u %s %s\n", + intval & AR5K_BEACON_PERIOD, + intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "", + intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : ""); +} + + +/** + * ath5k_beacon_config - Configure the beacon queues and interrupts + * + * @sc: struct ath5k_softc pointer we are operating on + * + * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA + * interrupts to detect TSF updates only. + */ +static void +ath5k_beacon_config(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + unsigned long flags; + + ath5k_hw_set_imr(ah, 0); + sc->bmisscount = 0; + sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); + + if (sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_MESH_POINT || + sc->opmode == NL80211_IFTYPE_AP) { + /* + * In IBSS mode we use a self-linked tx descriptor and let the + * hardware send the beacons automatically. We have to load it + * only once here. + * We use the SWBA interrupt only to keep track of the beacon + * timers in order to detect automatic TSF updates. + */ + ath5k_beaconq_config(sc); + + sc->imask |= AR5K_INT_SWBA; + + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + if (ath5k_hw_hasveol(ah)) { + spin_lock_irqsave(&sc->block, flags); + ath5k_beacon_send(sc); + spin_unlock_irqrestore(&sc->block, flags); + } + } else + ath5k_beacon_update_timers(sc, -1); + } + + ath5k_hw_set_imr(ah, sc->imask); +} + + +/********************\ +* Interrupt handling * +\********************/ + +static int +ath5k_init(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + int ret, i; + + mutex_lock(&sc->lock); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); + + /* + * Stop anything previously setup. This is safe + * no matter this is the first time through or not. + */ + ath5k_stop_locked(sc); + + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + sc->curchan = sc->hw->conf.channel; + sc->curband = &sc->sbands[sc->curchan->band]; + sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | + AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | + AR5K_INT_FATAL | AR5K_INT_GLOBAL; + ret = ath5k_reset(sc, false, false); + if (ret) + goto done; + + /* + * Reset the key cache since some parts do not reset the + * contents on initial power up or resume from suspend. + */ + for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) + ath5k_hw_reset_key(ah, i); + + /* Set ack to be sent at low bit-rates */ + ath5k_hw_set_ack_bitrate_high(ah, false); + + mod_timer(&sc->calib_tim, round_jiffies(jiffies + + msecs_to_jiffies(ath5k_calinterval * 1000))); + + ret = 0; +done: + mmiowb(); + mutex_unlock(&sc->lock); + return ret; +} + +static int +ath5k_stop_locked(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", + test_bit(ATH_STAT_INVALID, sc->status)); + + /* + * Shutdown the hardware and driver: + * stop output from above + * disable interrupts + * turn off timers + * turn off the radio + * clear transmit machinery + * clear receive machinery + * drain and release tx queues + * reclaim beacon resources + * power down hardware + * + * Note that some of this work is not possible if the + * hardware is gone (invalid). + */ + ieee80211_stop_queues(sc->hw); + + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + ath5k_led_off(sc); + ath5k_hw_set_imr(ah, 0); + synchronize_irq(sc->pdev->irq); + } + ath5k_txq_cleanup(sc); + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + ath5k_rx_stop(sc); + ath5k_hw_phy_disable(ah); + } else + sc->rxlink = NULL; + + return 0; +} + +/* + * Stop the device, grabbing the top-level lock to protect + * against concurrent entry through ath5k_init (which can happen + * if another thread does a system call and the thread doing the + * stop is preempted). + */ +static int +ath5k_stop_hw(struct ath5k_softc *sc) +{ + int ret; + + mutex_lock(&sc->lock); + ret = ath5k_stop_locked(sc); + if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { + /* + * Set the chip in full sleep mode. Note that we are + * careful to do this only when bringing the interface + * completely to a stop. When the chip is in this state + * it must be carefully woken up or references to + * registers in the PCI clock domain may freeze the bus + * (and system). This varies by chip and is mostly an + * issue with newer parts that go to sleep more quickly. + */ + if (sc->ah->ah_mac_srev >= 0x78) { + /* + * XXX + * don't put newer MAC revisions > 7.8 to sleep because + * of the above mentioned problems + */ + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, " + "not putting device to sleep\n"); + } else { + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "putting device to full sleep\n"); + ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); + } + } + ath5k_txbuf_free(sc, sc->bbuf); + + mmiowb(); + mutex_unlock(&sc->lock); + + del_timer_sync(&sc->calib_tim); + tasklet_kill(&sc->rxtq); + tasklet_kill(&sc->txtq); + tasklet_kill(&sc->restq); + tasklet_kill(&sc->beacontq); + + return ret; +} + +static irqreturn_t +ath5k_intr(int irq, void *dev_id) +{ + struct ath5k_softc *sc = dev_id; + struct ath5k_hw *ah = sc->ah; + enum ath5k_int status; + unsigned int counter = 1000; + + if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) || + !ath5k_hw_is_intr_pending(ah))) + return IRQ_NONE; + + do { + ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ + ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", + status, sc->imask); + if (unlikely(status & AR5K_INT_FATAL)) { + /* + * Fatal errors are unrecoverable. + * Typically these are caused by DMA errors. + */ + tasklet_schedule(&sc->restq); + } else if (unlikely(status & AR5K_INT_RXORN)) { + tasklet_schedule(&sc->restq); + } else { + if (status & AR5K_INT_SWBA) { + tasklet_schedule(&sc->beacontq); + } + if (status & AR5K_INT_RXEOL) { + /* + * NB: the hardware should re-read the link when + * RXE bit is written, but it doesn't work at + * least on older hardware revs. + */ + sc->rxlink = NULL; + } + if (status & AR5K_INT_TXURN) { + /* bump tx trigger level */ + ath5k_hw_update_tx_triglevel(ah, true); + } + if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) + tasklet_schedule(&sc->rxtq); + if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC + | AR5K_INT_TXERR | AR5K_INT_TXEOL)) + tasklet_schedule(&sc->txtq); + if (status & AR5K_INT_BMISS) { + /* TODO */ + } + if (status & AR5K_INT_MIB) { + /* + * These stats are also used for ANI i think + * so how about updating them more often ? + */ + ath5k_hw_update_mib_counters(ah, &sc->ll_stats); + } + } + } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0); + + if (unlikely(!counter)) + ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); + + return IRQ_HANDLED; +} + +static void +ath5k_tasklet_reset(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + + ath5k_reset_wake(sc); +} + +/* + * Periodically recalibrate the PHY to account + * for temperature/environment changes. + */ +static void +ath5k_calibrate(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + struct ath5k_hw *ah = sc->ah; + + ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", + ieee80211_frequency_to_channel(sc->curchan->center_freq), + sc->curchan->hw_value); + + if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { + /* + * Rfgain is out of bounds, reset the chip + * to load new gain values. + */ + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); + ath5k_reset_wake(sc); + } + if (ath5k_hw_phy_calibrate(ah, sc->curchan)) + ATH5K_ERR(sc, "calibration of channel %u failed\n", + ieee80211_frequency_to_channel( + sc->curchan->center_freq)); + + mod_timer(&sc->calib_tim, round_jiffies(jiffies + + msecs_to_jiffies(ath5k_calinterval * 1000))); +} + + +/********************\ +* Mac80211 functions * +\********************/ + +static int +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_buf *bf; + unsigned long flags; + int hdrlen; + int padsize; + + ath5k_debug_dump_skb(sc, skb, "TX ", 1); + + if (sc->opmode == NL80211_IFTYPE_MONITOR) + ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n"); + + /* + * the hardware expects the header padded to 4 byte boundaries + * if this is not the case we add the padding after the header + */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padsize = ath5k_pad_size(hdrlen); + if (padsize) { + + if (skb_headroom(skb) < padsize) { + ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" + " headroom to pad %d\n", hdrlen, padsize); + goto drop_packet; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data+padsize, hdrlen); + } + + spin_lock_irqsave(&sc->txbuflock, flags); + if (list_empty(&sc->txbuf)) { + ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); + spin_unlock_irqrestore(&sc->txbuflock, flags); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); + goto drop_packet; + } + bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); + list_del(&bf->list); + sc->txbuf_len--; + if (list_empty(&sc->txbuf)) + ieee80211_stop_queues(hw); + spin_unlock_irqrestore(&sc->txbuflock, flags); + + bf->skb = skb; + + if (ath5k_txbuf_setup(sc, bf)) { + bf->skb = NULL; + spin_lock_irqsave(&sc->txbuflock, flags); + list_add_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock_irqrestore(&sc->txbuflock, flags); + goto drop_packet; + } + return NETDEV_TX_OK; + +drop_packet: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static int +ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel) +{ + struct ath5k_hw *ah = sc->ah; + int ret; + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); + + 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 (ret) { + ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); + goto err; + } + + ret = ath5k_rx_start(sc); + if (ret) { + ATH5K_ERR(sc, "can't start recv logic\n"); + goto err; + } + + /* + * 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 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); +} + +static void ath5k_stop(struct ieee80211_hw *hw) +{ + ath5k_stop_hw(hw->priv); +} + +static int ath5k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath5k_softc *sc = hw->priv; + int ret; + + mutex_lock(&sc->lock); + if (sc->vif) { + ret = 0; + goto end; + } + + sc->vif = conf->vif; + + switch (conf->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_MONITOR: + sc->opmode = conf->type; + break; + default: + ret = -EOPNOTSUPP; + goto end; + } + + /* Set to a reasonable value. Note that this will + * be set to mac80211's value at ath5k_config(). */ + sc->bintval = 1000; + ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); + + ret = 0; +end: + mutex_unlock(&sc->lock); + return ret; +} + +static void +ath5k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath5k_softc *sc = hw->priv; + u8 mac[ETH_ALEN] = {}; + + mutex_lock(&sc->lock); + if (sc->vif != conf->vif) + goto end; + + ath5k_hw_set_lladdr(sc->ah, mac); + sc->vif = NULL; +end: + mutex_unlock(&sc->lock); +} + +/* + * TODO: Phy disable/diversity etc + */ +static int +ath5k_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ath5k_softc *sc = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int ret; + + mutex_lock(&sc->lock); + + sc->bintval = conf->beacon_int; + sc->power_level = conf->power_level; + + ret = ath5k_chan_set(sc, conf->channel); + + mutex_unlock(&sc->lock); + return ret; +} + +static int +ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + int ret = 0; + + mutex_lock(&sc->lock); + if (sc->vif != vif) { + ret = -EIO; + goto unlock; + } + if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { + /* Cache for later use during resets */ + memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); + /* XXX: assoc id is set to 0 for now, mac80211 doesn't have + * a clean way of letting us retrieve this yet. */ + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + mmiowb(); + } + if (conf->changed & IEEE80211_IFCC_BEACON && + (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT || + vif->type == NL80211_IFTYPE_AP)) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if (!beacon) { + ret = -ENOMEM; + goto unlock; + } + ath5k_beacon_update(sc, beacon); + } + +unlock: + mutex_unlock(&sc->lock); + return ret; +} + +#define SUPPORTED_FIF_FLAGS \ + FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ + FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ + FIF_BCN_PRBRESP_PROMISC +/* + * o always accept unicast, broadcast, and multicast traffic + * o multicast traffic for all BSSIDs will be enabled if mac80211 + * says it should be + * o maintain current state of phy ofdm or phy cck error reception. + * If the hardware detects any of these type of errors then + * ath5k_hw_get_rx_filter() will pass to us the respective + * hardware filters to be able to receive these type of frames. + * o probe request frames are accepted only when operating in + * hostap, adhoc, or monitor modes + * o enable promiscuous mode according to the interface state + * o accept beacons: + * - when operating in adhoc mode so the 802.11 layer creates + * node table entries for peers, + * - when operating in station mode for collecting rssi data when + * the station is otherwise quiet, or + * - when scanning + */ +static void ath5k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + u32 mfilt[2], val, rfilt; + u8 pos; + int i; + + mfilt[0] = 0; + mfilt[1] = 0; + + /* Only deal with supported flags */ + changed_flags &= SUPPORTED_FIF_FLAGS; + *new_flags &= SUPPORTED_FIF_FLAGS; + + /* If HW detects any phy or radar errors, leave those filters on. + * Also, always enable Unicast, Broadcasts and Multicast + * XXX: move unicast, bssid broadcasts and multicast to mac80211 */ + rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) | + (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST | + AR5K_RX_FILTER_MCAST); + + if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { + if (*new_flags & FIF_PROMISC_IN_BSS) { + rfilt |= AR5K_RX_FILTER_PROM; + __set_bit(ATH_STAT_PROMISC, sc->status); + } else { + __clear_bit(ATH_STAT_PROMISC, sc->status); + } + } + + /* Note, AR5K_RX_FILTER_MCAST is already enabled */ + if (*new_flags & FIF_ALLMULTI) { + mfilt[0] = ~0; + mfilt[1] = ~0; + } else { + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + /* calculate XOR of eight 6-bit values */ + val = get_unaligned_le32(mclist->dmi_addr + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = get_unaligned_le32(mclist->dmi_addr + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + /* XXX: we might be able to just do this instead, + * but not sure, needs testing, if we do use this we'd + * neet to inform below to not reset the mcast */ + /* ath5k_hw_set_mcast_filterindex(ah, + * mclist->dmi_addr[5]); */ + mclist = mclist->next; + } + } + + /* This is the best we can do */ + if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)) + rfilt |= AR5K_RX_FILTER_PHYERR; + + /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons + * and probes for any BSSID, this needs testing */ + if (*new_flags & FIF_BCN_PRBRESP_PROMISC) + rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ; + + /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not + * set we should only pass on control frames for this + * station. This needs testing. I believe right now this + * enables *all* control frames, which is OK.. but + * but we should see if we can improve on granularity */ + if (*new_flags & FIF_CONTROL) + rfilt |= AR5K_RX_FILTER_CONTROL; + + /* Additional settings per mode -- this is per ath5k */ + + /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ + + 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 != NL80211_IFTYPE_STATION) + rfilt |= AR5K_RX_FILTER_PROBEREQ; + 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 == NL80211_IFTYPE_STATION && sc->assoc) || + sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_AP) + rfilt |= AR5K_RX_FILTER_BEACON; + if (sc->opmode == NL80211_IFTYPE_MESH_POINT) + rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; + + /* Set filters */ + ath5k_hw_set_rx_filter(ah, rfilt); + + /* Set multicast bits */ + ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); + /* Set the cached hw filter flags, this will alter actually + * be set in HW */ + sc->filter_flags = rfilt; +} + +static int +ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ath5k_softc *sc = hw->priv; + int ret = 0; + + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + switch (key->alg) { + case ALG_WEP: + case ALG_TKIP: + break; + case ALG_CCMP: + return -EOPNOTSUPP; + default: + WARN_ON(1); + return -EINVAL; + } + + mutex_lock(&sc->lock); + + switch (cmd) { + case SET_KEY: + ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, + sta ? sta->addr : NULL); + if (ret) { + ATH5K_ERR(sc, "can't set the key\n"); + goto unlock; + } + __set_bit(key->keyidx, sc->keymap); + key->hw_key_idx = key->keyidx; + key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | + IEEE80211_KEY_FLAG_GENERATE_MMIC); + break; + case DISABLE_KEY: + ath5k_hw_reset_key(sc->ah, key->keyidx); + __clear_bit(key->keyidx, sc->keymap); + break; + default: + ret = -EINVAL; + goto unlock; + } + +unlock: + mmiowb(); + mutex_unlock(&sc->lock); + return ret; +} + +static int +ath5k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + + /* Force update */ + ath5k_hw_update_mib_counters(ah, &sc->ll_stats); + + memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); + + return 0; +} + +static int +ath5k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct ath5k_softc *sc = hw->priv; + + memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats)); + + return 0; +} + +static u64 +ath5k_get_tsf(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + return ath5k_hw_get_tsf64(sc->ah); +} + +static void +ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +{ + struct ath5k_softc *sc = hw->priv; + + ath5k_hw_set_tsf64(sc->ah, tsf); +} + +static void +ath5k_reset_tsf(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * 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 == NL80211_IFTYPE_ADHOC) + ath5k_beacon_update_timers(sc, 0); + else + ath5k_hw_reset_tsf(sc->ah); +} + +static int +ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) +{ + unsigned long flags; + int ret; + + ath5k_debug_dump_skb(sc, skb, "BC ", 1); + + spin_lock_irqsave(&sc->block, flags); + ath5k_txbuf_free(sc, sc->bbuf); + sc->bbuf->skb = skb; + ret = ath5k_beacon_setup(sc, sc->bbuf); + if (ret) + sc->bbuf->skb = NULL; + spin_unlock_irqrestore(&sc->block, flags); + if (!ret) { + ath5k_beacon_config(sc); + mmiowb(); + } + + return ret; +} +static void +set_beacon_filter(struct ieee80211_hw *hw, bool enable) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + u32 rfilt; + rfilt = ath5k_hw_get_rx_filter(ah); + if (enable) + rfilt |= AR5K_RX_FILTER_BEACON; + else + rfilt &= ~AR5K_RX_FILTER_BEACON; + ath5k_hw_set_rx_filter(ah, rfilt); + sc->filter_flags = rfilt; +} + +static void ath5k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct ath5k_softc *sc = hw->priv; + if (changes & BSS_CHANGED_ASSOC) { + mutex_lock(&sc->lock); + sc->assoc = bss_conf->assoc; + if (sc->opmode == NL80211_IFTYPE_STATION) + set_beacon_filter(hw, sc->assoc); + mutex_unlock(&sc->lock); + } +} diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h new file mode 100644 index 0000000..8229561 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_ATH_ATHVAR_H +#define _DEV_ATH_ATHVAR_H + +#include +#include +#include +#include +#include + +#include "ath5k.h" +#include "debug.h" + +#define ATH_RXBUF 40 /* number of RX buffers */ +#define ATH_TXBUF 200 /* number of TX buffers */ +#define ATH_BCBUF 1 /* number of beacon buffers */ + +struct ath5k_buf { + struct list_head list; + unsigned int flags; /* rx descriptor flags */ + struct ath5k_desc *desc; /* virtual addr of desc */ + dma_addr_t daddr; /* physical addr of desc */ + struct sk_buff *skb; /* skbuff for buf */ + dma_addr_t skbaddr;/* physical addr of skb data */ +}; + +/* + * Data transmit queue state. One of these exists for each + * hardware transmit queue. Packets sent to us from above + * are assigned to queues based on their priority. Not all + * devices support a complete set of hardware transmit queues. + * For those devices the array sc_ac2q will map multiple + * priorities to fewer hardware queues (typically all to one + * hardware queue). + */ +struct ath5k_txq { + unsigned int qnum; /* hardware q number */ + u32 *link; /* link ptr in last TX desc */ + struct list_head q; /* transmit queue */ + spinlock_t lock; /* lock on q and link */ + bool setup; +}; + +#define ATH5K_LED_MAX_NAME_LEN 31 + +/* + * State for LED triggers + */ +struct ath5k_led +{ + char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */ + struct ath5k_softc *sc; /* driver state */ + struct led_classdev led_dev; /* led classdev */ +}; + + +#if CHAN_DEBUG +#define ATH_CHAN_MAX (26+26+26+200+200) +#else +#define ATH_CHAN_MAX (14+14+14+252+20) +#endif + +/* Software Carrier, keeps track of the driver state + * associated with an instance of a device */ +struct ath5k_softc { + struct pci_dev *pdev; /* for dma mapping */ + void __iomem *iobase; /* address of the device */ + struct mutex lock; /* dev-level lock */ + /* FIXME: how many does it really need? */ + struct ieee80211_tx_queue_stats tx_stats[16]; + struct ieee80211_low_level_stats ll_stats; + 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[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; + s8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; + enum nl80211_iftype opmode; + struct ath5k_hw *ah; /* Atheros HW */ + + struct ieee80211_supported_band *curband; + +#ifdef CONFIG_ATH5K_DEBUG + struct ath5k_dbg_info debug; /* debug info */ +#endif /* CONFIG_ATH5K_DEBUG */ + + struct ath5k_buf *bufptr; /* allocated buffer ptr */ + struct ath5k_desc *desc; /* TX/RX descriptors */ + dma_addr_t desc_daddr; /* DMA (physical) address */ + size_t desc_len; /* size of TX/RX descriptors */ + u16 cachelsz; /* cache line size */ + + DECLARE_BITMAP(status, 5); +#define ATH_STAT_INVALID 0 /* disable hardware accesses */ +#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ +#define ATH_STAT_PROMISC 2 +#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ +#define ATH_STAT_STARTED 4 /* opened & irqs enabled */ + + unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ + unsigned int curmode; /* current phy mode */ + struct ieee80211_channel *curchan; /* current h/w channel */ + + struct ieee80211_vif *vif; + + enum ath5k_int imask; /* interrupt mask copy */ + + DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ + + u8 bssidmask[ETH_ALEN]; + + unsigned int led_pin, /* GPIO pin for driving LED */ + led_on; /* pin setting for LED on */ + + struct tasklet_struct restq; /* reset tasklet */ + + unsigned int rxbufsize; /* rx size based on mtu */ + struct list_head rxbuf; /* receive buffer */ + spinlock_t rxbuflock; + u32 *rxlink; /* link ptr in last RX desc */ + struct tasklet_struct rxtq; /* rx intr tasklet */ + struct ath5k_led rx_led; /* rx led */ + + struct list_head txbuf; /* transmit buffer */ + spinlock_t txbuflock; + unsigned int txbuf_len; /* buf count in txbuf list */ + struct ath5k_txq txqs[2]; /* beacon and tx */ + + struct ath5k_txq *txq; /* beacon and tx*/ + struct tasklet_struct txtq; /* tx intr tasklet */ + struct ath5k_led tx_led; /* tx led */ + + spinlock_t block; /* protects beacon */ + struct tasklet_struct beacontq; /* beacon intr tasklet */ + struct ath5k_buf *bbuf; /* beacon buffer */ + unsigned int bhalq, /* SW q for outgoing beacons */ + bmisscount, /* missed beacon transmits */ + bintval, /* beacon interval in TU */ + bsent; + unsigned int nexttbtt; /* next beacon time in TU */ + + struct timer_list calib_tim; /* calibration timer */ + int power_level; /* Requested tx power in dbm */ + bool assoc; /* assocate state */ +}; + +#define ath5k_hw_hasbssidmask(_ah) \ + (ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0) +#define ath5k_hw_hasveol(_ah) \ + (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) + +#endif diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c new file mode 100644 index 0000000..367a6c7 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Jiri Slaby + * + * 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) && + ah->ah_version != AR5K_AR5211)) { + /* 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) && + ah->ah_version != AR5K_AR5211) + __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/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c new file mode 100644 index 0000000..9770bb3 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2007-2008 Bruno Randolf + * + * This file is free software: you may copy, redistribute 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 file 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, see . + * + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2004-2005 Atheros Communications, Inc. + * Copyright (c) 2006 Devicescape Software, Inc. + * Copyright (c) 2007 Jiri Slaby + * Copyright (c) 2007 Luis R. Rodriguez + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "base.h" +#include "debug.h" + +static unsigned int ath5k_debug; +module_param_named(debug, ath5k_debug, uint, 0); + + +#ifdef CONFIG_ATH5K_DEBUG + +#include +#include "reg.h" + +static struct dentry *ath5k_global_debugfs; + +static int ath5k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + + +/* debugfs: registers */ + +struct reg { + const char *name; + int addr; +}; + +#define REG_STRUCT_INIT(r) { #r, r } + +/* just a few random registers, might want to add more */ +static const struct reg regs[] = { + REG_STRUCT_INIT(AR5K_CR), + REG_STRUCT_INIT(AR5K_RXDP), + REG_STRUCT_INIT(AR5K_CFG), + REG_STRUCT_INIT(AR5K_IER), + REG_STRUCT_INIT(AR5K_BCR), + REG_STRUCT_INIT(AR5K_RTSD0), + REG_STRUCT_INIT(AR5K_RTSD1), + REG_STRUCT_INIT(AR5K_TXCFG), + REG_STRUCT_INIT(AR5K_RXCFG), + REG_STRUCT_INIT(AR5K_RXJLA), + REG_STRUCT_INIT(AR5K_MIBC), + REG_STRUCT_INIT(AR5K_TOPS), + REG_STRUCT_INIT(AR5K_RXNOFRM), + REG_STRUCT_INIT(AR5K_TXNOFRM), + REG_STRUCT_INIT(AR5K_RPGTO), + REG_STRUCT_INIT(AR5K_RFCNT), + REG_STRUCT_INIT(AR5K_MISC), + REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT), + REG_STRUCT_INIT(AR5K_ISR), + REG_STRUCT_INIT(AR5K_PISR), + REG_STRUCT_INIT(AR5K_SISR0), + REG_STRUCT_INIT(AR5K_SISR1), + REG_STRUCT_INIT(AR5K_SISR2), + REG_STRUCT_INIT(AR5K_SISR3), + REG_STRUCT_INIT(AR5K_SISR4), + REG_STRUCT_INIT(AR5K_IMR), + REG_STRUCT_INIT(AR5K_PIMR), + REG_STRUCT_INIT(AR5K_SIMR0), + REG_STRUCT_INIT(AR5K_SIMR1), + REG_STRUCT_INIT(AR5K_SIMR2), + REG_STRUCT_INIT(AR5K_SIMR3), + REG_STRUCT_INIT(AR5K_SIMR4), + REG_STRUCT_INIT(AR5K_DCM_ADDR), + REG_STRUCT_INIT(AR5K_DCCFG), + REG_STRUCT_INIT(AR5K_CCFG), + REG_STRUCT_INIT(AR5K_CPC0), + REG_STRUCT_INIT(AR5K_CPC1), + REG_STRUCT_INIT(AR5K_CPC2), + REG_STRUCT_INIT(AR5K_CPC3), + REG_STRUCT_INIT(AR5K_CPCOVF), + REG_STRUCT_INIT(AR5K_RESET_CTL), + REG_STRUCT_INIT(AR5K_SLEEP_CTL), + REG_STRUCT_INIT(AR5K_INTPEND), + REG_STRUCT_INIT(AR5K_SFR), + REG_STRUCT_INIT(AR5K_PCICFG), + REG_STRUCT_INIT(AR5K_GPIOCR), + REG_STRUCT_INIT(AR5K_GPIODO), + REG_STRUCT_INIT(AR5K_SREV), +}; + +static void *reg_start(struct seq_file *seq, loff_t *pos) +{ + return *pos < ARRAY_SIZE(regs) ? (void *)®s[*pos] : NULL; +} + +static void reg_stop(struct seq_file *seq, void *p) +{ + /* nothing to do */ +} + +static void *reg_next(struct seq_file *seq, void *p, loff_t *pos) +{ + ++*pos; + return *pos < ARRAY_SIZE(regs) ? (void *)®s[*pos] : NULL; +} + +static int reg_show(struct seq_file *seq, void *p) +{ + struct ath5k_softc *sc = seq->private; + struct reg *r = p; + seq_printf(seq, "%-25s0x%08x\n", r->name, + ath5k_hw_reg_read(sc->ah, r->addr)); + return 0; +} + +static const struct seq_operations register_seq_ops = { + .start = reg_start, + .next = reg_next, + .stop = reg_stop, + .show = reg_show +}; + +static int open_file_registers(struct inode *inode, struct file *file) +{ + struct seq_file *s; + int res; + res = seq_open(file, ®ister_seq_ops); + if (res == 0) { + s = file->private_data; + s->private = inode->i_private; + } + return res; +} + +static const struct file_operations fops_registers = { + .open = open_file_registers, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .owner = THIS_MODULE, +}; + + +/* debugfs: beacons */ + +static ssize_t read_file_beacon(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + char buf[500]; + unsigned int len = 0; + unsigned int v; + u64 tsf; + + v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON); + len += snprintf(buf+len, sizeof(buf)-len, + "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n", + "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD, + (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S); + + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n", + "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP)); + + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n", + "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT)); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER0 (TBTT)", v, v); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER1 (DMA)", v, v >> 3); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER2 (SWBA)", v, v >> 3); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER3 (ATIM)", v, v); + + tsf = ath5k_hw_get_tsf64(sc->ah); + len += snprintf(buf+len, sizeof(buf)-len, + "TSF\t\t0x%016llx\tTU: %08x\n", + (unsigned long long)tsf, TSF_TO_TU(tsf)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_beacon(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + char buf[20]; + + if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + return -EFAULT; + + if (strncmp(buf, "disable", 7) == 0) { + AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); + printk(KERN_INFO "debugfs disable beacons\n"); + } else if (strncmp(buf, "enable", 6) == 0) { + AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); + printk(KERN_INFO "debugfs enable beacons\n"); + } + return count; +} + +static const struct file_operations fops_beacon = { + .read = read_file_beacon, + .write = write_file_beacon, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* debugfs: reset */ + +static ssize_t write_file_reset(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + tasklet_schedule(&sc->restq); + return count; +} + +static const struct file_operations fops_reset = { + .write = write_file_reset, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* debugfs: debug level */ + +static const struct { + enum ath5k_debug_level level; + const char *name; + const char *desc; +} dbg_info[] = { + { ATH5K_DEBUG_RESET, "reset", "reset and initialization" }, + { ATH5K_DEBUG_INTR, "intr", "interrupt handling" }, + { ATH5K_DEBUG_MODE, "mode", "mode init/setup" }, + { ATH5K_DEBUG_XMIT, "xmit", "basic xmit operation" }, + { ATH5K_DEBUG_BEACON, "beacon", "beacon handling" }, + { ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" }, + { ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" }, + { ATH5K_DEBUG_LED, "led", "LED management" }, + { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, + { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, + { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, + { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, + { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, +}; + +static ssize_t read_file_debug(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + char buf[700]; + unsigned int len = 0; + unsigned int i; + + len += snprintf(buf+len, sizeof(buf)-len, + "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level); + + for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) { + len += snprintf(buf+len, sizeof(buf)-len, + "%10s %c 0x%08x - %s\n", dbg_info[i].name, + sc->debug.level & dbg_info[i].level ? '+' : ' ', + dbg_info[i].level, dbg_info[i].desc); + } + len += snprintf(buf+len, sizeof(buf)-len, + "%10s %c 0x%08x - %s\n", dbg_info[i].name, + sc->debug.level == dbg_info[i].level ? '+' : ' ', + dbg_info[i].level, dbg_info[i].desc); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_debug(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + unsigned int i; + char buf[20]; + + if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + return -EFAULT; + + for (i = 0; i < ARRAY_SIZE(dbg_info); i++) { + if (strncmp(buf, dbg_info[i].name, + strlen(dbg_info[i].name)) == 0) { + sc->debug.level ^= dbg_info[i].level; /* toggle bit */ + break; + } + } + return count; +} + +static const struct file_operations fops_debug = { + .read = read_file_debug, + .write = write_file_debug, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* init */ + +void +ath5k_debug_init(void) +{ + ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); +} + +void +ath5k_debug_init_device(struct ath5k_softc *sc) +{ + sc->debug.level = ath5k_debug; + + sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), + ath5k_global_debugfs); + + sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO, + sc->debug.debugfs_phydir, sc, &fops_debug); + + sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO, + sc->debug.debugfs_phydir, sc, &fops_registers); + + sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO, + sc->debug.debugfs_phydir, sc, &fops_beacon); + + sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, + sc->debug.debugfs_phydir, sc, &fops_reset); +} + +void +ath5k_debug_finish(void) +{ + debugfs_remove(ath5k_global_debugfs); +} + +void +ath5k_debug_finish_device(struct ath5k_softc *sc) +{ + debugfs_remove(sc->debug.debugfs_debug); + debugfs_remove(sc->debug.debugfs_registers); + debugfs_remove(sc->debug.debugfs_beacon); + debugfs_remove(sc->debug.debugfs_reset); + debugfs_remove(sc->debug.debugfs_phydir); +} + + +/* functions used in other places */ + +void +ath5k_debug_dump_bands(struct ath5k_softc *sc) +{ + unsigned int b, i; + + if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPBANDS))) + return; + + BUG_ON(!sc->sbands); + + for (b = 0; b < IEEE80211_NUM_BANDS; b++) { + struct ieee80211_supported_band *band = &sc->sbands[b]; + char bname[5]; + switch (band->band) { + case IEEE80211_BAND_2GHZ: + strcpy(bname, "2 GHz"); + break; + case IEEE80211_BAND_5GHZ: + strcpy(bname, "5 GHz"); + break; + default: + printk(KERN_DEBUG "Band not supported: %d\n", + band->band); + return; + } + printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname, + band->n_channels, band->n_bitrates); + printk(KERN_DEBUG " channels:\n"); + for (i = 0; i < band->n_channels; i++) + printk(KERN_DEBUG " %3d %d %.4x %.4x\n", + ieee80211_frequency_to_channel( + band->channels[i].center_freq), + band->channels[i].center_freq, + band->channels[i].hw_value, + band->channels[i].flags); + printk(KERN_DEBUG " rates:\n"); + for (i = 0; i < band->n_bitrates; i++) + printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", + band->bitrates[i].bitrate, + band->bitrates[i].hw_value, + band->bitrates[i].flags, + band->bitrates[i].hw_value_short); + } +} + +static inline void +ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done, + struct ath5k_rx_status *rs) +{ + struct ath5k_desc *ds = bf->desc; + struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx; + + printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", + ds, (unsigned long long)bf->daddr, + ds->ds_link, ds->ds_data, + rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1, + rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0, + !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'); +} + +void +ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) +{ + struct ath5k_desc *ds; + struct ath5k_buf *bf; + struct ath5k_rx_status rs = {}; + int status; + + if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) + return; + + printk(KERN_DEBUG "rx queue %x, link %p\n", + ath5k_hw_get_rxdp(ah), sc->rxlink); + + spin_lock_bh(&sc->rxbuflock); + list_for_each_entry(bf, &sc->rxbuf, list) { + ds = bf->desc; + status = ah->ah_proc_rx_desc(ah, ds, &rs); + if (!status) + ath5k_debug_printrxbuf(bf, status == 0, &rs); + } + spin_unlock_bh(&sc->rxbuflock); +} + +void +ath5k_debug_dump_skb(struct ath5k_softc *sc, + struct sk_buff *skb, const char *prefix, int tx) +{ + char buf[16]; + + if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || + (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) + return; + + snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); + + print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, + min(200U, skb->len)); + + printk(KERN_DEBUG "\n"); +} + +void +ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) +{ + struct ath5k_desc *ds = bf->desc; + struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212; + struct ath5k_tx_status ts = {}; + int done; + + if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) + return; + + done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts); + + printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " + "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, + ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1, + td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3, + td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, + done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); +} + +#endif /* ifdef CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h new file mode 100644 index 0000000..66f69f0 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2007 Bruno Randolf + * + * This file is free software: you may copy, redistribute 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 file 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, see . + * + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2004-2005 Atheros Communications, Inc. + * Copyright (c) 2006 Devicescape Software, Inc. + * Copyright (c) 2007 Jiri Slaby + * Copyright (c) 2007 Luis R. Rodriguez + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ATH5K_DEBUG_H +#define _ATH5K_DEBUG_H + +struct ath5k_softc; +struct ath5k_hw; +struct sk_buff; +struct ath5k_buf; + +struct ath5k_dbg_info { + unsigned int level; /* debug level */ + /* debugfs entries */ + struct dentry *debugfs_phydir; + struct dentry *debugfs_debug; + struct dentry *debugfs_registers; + struct dentry *debugfs_beacon; + struct dentry *debugfs_reset; +}; + +/** + * enum ath5k_debug_level - ath5k debug level + * + * @ATH5K_DEBUG_RESET: reset processing + * @ATH5K_DEBUG_INTR: interrupt handling + * @ATH5K_DEBUG_MODE: mode init/setup + * @ATH5K_DEBUG_XMIT: basic xmit operation + * @ATH5K_DEBUG_BEACON: beacon handling + * @ATH5K_DEBUG_CALIBRATE: periodic calibration + * @ATH5K_DEBUG_TXPOWER: transmit power setting + * @ATH5K_DEBUG_LED: led management + * @ATH5K_DEBUG_DUMP_RX: print received skb content + * @ATH5K_DEBUG_DUMP_TX: print transmit skb content + * @ATH5K_DEBUG_DUMPBANDS: dump bands + * @ATH5K_DEBUG_TRACE: trace function calls + * @ATH5K_DEBUG_ANY: show at any debug level + * + * The debug level is used to control the amount and type of debugging output + * we want to see. The debug level is given in calls to ATH5K_DBG to specify + * where the message should appear, and the user can control the debugging + * messages he wants to see, either by the module parameter 'debug' on module + * load, or dynamically by using debugfs 'ath5k/phyX/debug'. these levels can + * be combined together by bitwise OR. + */ +enum ath5k_debug_level { + ATH5K_DEBUG_RESET = 0x00000001, + ATH5K_DEBUG_INTR = 0x00000002, + ATH5K_DEBUG_MODE = 0x00000004, + ATH5K_DEBUG_XMIT = 0x00000008, + ATH5K_DEBUG_BEACON = 0x00000010, + ATH5K_DEBUG_CALIBRATE = 0x00000020, + ATH5K_DEBUG_TXPOWER = 0x00000040, + ATH5K_DEBUG_LED = 0x00000080, + ATH5K_DEBUG_DUMP_RX = 0x00000100, + ATH5K_DEBUG_DUMP_TX = 0x00000200, + ATH5K_DEBUG_DUMPBANDS = 0x00000400, + ATH5K_DEBUG_TRACE = 0x00001000, + ATH5K_DEBUG_ANY = 0xffffffff +}; + +#ifdef CONFIG_ATH5K_DEBUG + +#define ATH5K_TRACE(_sc) do { \ + if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \ + printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \ + } while (0) + +#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \ + if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \ + ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) + +#define ATH5K_DBG_UNLIMIT(_sc, _m, _fmt, ...) do { \ + if (unlikely((_sc)->debug.level & (_m))) \ + ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) + +void +ath5k_debug_init(void); + +void +ath5k_debug_init_device(struct ath5k_softc *sc); + +void +ath5k_debug_finish(void); + +void +ath5k_debug_finish_device(struct ath5k_softc *sc); + +void +ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); + +void +ath5k_debug_dump_bands(struct ath5k_softc *sc); + +void +ath5k_debug_dump_skb(struct ath5k_softc *sc, + struct sk_buff *skb, const char *prefix, int tx); + +void +ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf); + +#else /* no debugging */ + +#include + +#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc)) + +static inline void __attribute__ ((format (printf, 3, 4))) +ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} + +static inline void __attribute__ ((format (printf, 3, 4))) +ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) +{} + +static inline void +ath5k_debug_init(void) {} + +static inline void +ath5k_debug_init_device(struct ath5k_softc *sc) {} + +static inline void +ath5k_debug_finish(void) {} + +static inline void +ath5k_debug_finish_device(struct ath5k_softc *sc) {} + +static inline void +ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} + +static inline void +ath5k_debug_dump_bands(struct ath5k_softc *sc) {} + +static inline void +ath5k_debug_dump_skb(struct ath5k_softc *sc, + struct sk_buff *skb, const char *prefix, int tx) {} + +static inline void +ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {} + +#endif /* ifdef CONFIG_ATH5K_DEBUG */ + +#endif /* ifndef _ATH5K_DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c new file mode 100644 index 0000000..dc30a2b --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Pavel Roskin + * + * 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 - ath5k_pad_size(hdr_len) + 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; + } + + tx_power += ah->ah_txpower.txp_offset; + if (tx_power > AR5K_TUNE_MAX_TXPOWER) + tx_power = AR5K_TUNE_MAX_TXPOWER; + + /* 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 - ath5k_pad_size(hdr_len) + 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 = AR5K_REG_MS(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 = AR5K_REG_MS(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/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h new file mode 100644 index 0000000..56158c8 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/desc.h @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * 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. + * + */ + +/* + * Internal RX/TX descriptor structures + * (rX: reserved fields possibily used by future versions of the ar5k chipset) + */ + +/* + * common hardware RX control descriptor + */ +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 + +/* RX control word 1 fields/flags */ +#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff +#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 + +/* + * common hardware RX status descriptor + * 5210/11 and 5212 differ only in the flags defined below + */ +struct ath5k_hw_rx_status { + u32 rx_status_0; /* RX status word 0 */ + u32 rx_status_1; /* RX status word 1 */ +} __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 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 +#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 +#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 +#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 +#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 +#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 +#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 +#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 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 +#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 +#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 +#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 +#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 +#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 +#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 + +/* + * common hardware RX error descriptor + */ +struct ath5k_hw_rx_error { + 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 + +/* 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 + +/* 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 +#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 +#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 +#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 +#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 +#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 + +/* + * 5210/5211 hardware 2-word TX control descriptor + */ +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 +#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 +#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18 +#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 +#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 +#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/ +#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/ +#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/ +#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_S 25 +#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 +#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 + +/* 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_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 ?]*/ + +/* 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 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 + +/* + * 5212 hardware 4-word TX control descriptor + */ +struct ath5k_hw_4w_tx_ctl { + u32 tx_control_0; /* TX control word 0 */ + +#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff +#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 +#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16 +#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 +#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 +#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 +#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 +#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 +#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 +#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 +#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 + + u32 tx_control_1; /* TX control word 1 */ + +#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff +#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000 +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 +#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 +#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20 +#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25 +#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27 +#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29 + + u32 tx_control_2; /* TX control word 2 */ + +#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff +#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 + + u32 tx_control_3; /* TX control word 3 */ + +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15 +#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 +#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 +} __packed; + +/* + * Common TX status descriptor + */ +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 +#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 +/*??? +#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0 +#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4 +*/ +#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 +#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4 +/*??? +#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00 +#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8 +*/ +#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 +#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8 +#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000 +#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12 +#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 +#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 + +/* 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 +#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 +#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13 +#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000 +#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 + +/* + * 5210/5211 hardware TX descriptor + */ +struct ath5k_hw_5210_tx_desc { + struct ath5k_hw_2w_tx_ctl tx_ctl; + struct ath5k_hw_tx_status tx_stat; +} __packed; + +/* + * 5212 hardware TX descriptor + */ +struct ath5k_hw_5212_tx_desc { + struct ath5k_hw_4w_tx_ctl tx_ctl; + struct ath5k_hw_tx_status tx_stat; +} __packed; + +/* + * common hardware RX descriptor + */ +struct ath5k_hw_all_rx_desc { + struct ath5k_hw_rx_ctl rx_ctl; + union { + struct ath5k_hw_rx_status rx_stat; + struct ath5k_hw_rx_error rx_err; + } u; +} __packed; + +/* + * 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+]*/ + diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c new file mode 100644 index 0000000..b65b4fe --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -0,0 +1,705 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * 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. + */ +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 Interrupt + * Status Register shadow copy (Read And Clear) + * + * Note: PISR/SISR Not available on 5210 + */ + data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } + } + + /* + * Get abstract interrupt mask (driver-compatible) + */ + *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; + + if (ah->ah_version != AR5K_AR5210) { + u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); + + /*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; + + if (unlikely(sisr2 & (AR5K_SISR2_SSERR | + AR5K_SISR2_DPERR | + AR5K_SISR2_MCABT))) + *interrupt_mask |= AR5K_INT_FATAL; + + if (data & AR5K_ISR_TIM) + *interrupt_mask |= AR5K_INT_TIM; + + if (data & AR5K_ISR_BCNMISC) { + if (sisr2 & AR5K_SISR2_TIM) + *interrupt_mask |= AR5K_INT_TIM; + if (sisr2 & AR5K_SISR2_DTIM) + *interrupt_mask |= AR5K_INT_DTIM; + if (sisr2 & AR5K_SISR2_DTIM_SYNC) + *interrupt_mask |= AR5K_INT_DTIM_SYNC; + if (sisr2 & AR5K_SISR2_BCN_TIMEOUT) + *interrupt_mask |= AR5K_INT_BCN_TIMEOUT; + if (sisr2 & AR5K_SISR2_CAB_TIMEOUT) + *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; + } + + if (data & AR5K_ISR_RXDOPPLER) + *interrupt_mask |= AR5K_INT_RX_DOPPLER; + if (data & AR5K_ISR_QCBRORN) { + *interrupt_mask |= AR5K_INT_QCBRORN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRORN); + } + if (data & AR5K_ISR_QCBRURN) { + *interrupt_mask |= AR5K_INT_QCBRURN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRURN); + } + if (data & AR5K_ISR_QTRIG) { + *interrupt_mask |= AR5K_INT_QTRIG; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), + AR5K_SISR4_QTRIG); + } + + if (data & AR5K_ISR_TXOK) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXOK); + + if (data & AR5K_ISR_TXDESC) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXDESC); + + if (data & AR5K_ISR_TXERR) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXERR); + + if (data & AR5K_ISR_TXEOL) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXEOL); + + if (data & AR5K_ISR_TXURN) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR2), + AR5K_SISR2_QCU_TXURN); + } else { + if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT + | AR5K_ISR_HIUERR | AR5K_ISR_DPERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /* + * 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 successful assoc + some jiffies. + interrupt_mask &= ~AR5K_INT_BMISS; + */ + } + + /* + * In case we didn't handle anything, + * print the register value. + */ + if (unlikely(*interrupt_mask == 0 && net_ratelimit())) + ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr); + + 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; + + old_mask = ah->ah_imr; + + /* + * Disable card interrupts to prevent any race conditions + * (they will be re-enabled afterwards if AR5K_INT GLOBAL + * is set again on the new mask). + */ + if (old_mask & AR5K_INT_GLOBAL) { + ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + } + + /* + * Add additional, chipset-dependent interrupt mask flags + * and write them to the IMR (interrupt mask register). + */ + int_mask = new_mask & AR5K_INT_COMMON; + + if (ah->ah_version != AR5K_AR5210) { + /* Preserve per queue TXURN interrupt mask */ + u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) + & AR5K_SIMR2_QCU_TXURN; + + if (new_mask & AR5K_INT_FATAL) { + int_mask |= AR5K_IMR_HIUERR; + simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR + | AR5K_SIMR2_DPERR); + } + + /*Beacon Not Ready*/ + if (new_mask & AR5K_INT_BNR) + int_mask |= AR5K_INT_BNR; + + if (new_mask & AR5K_INT_TIM) + int_mask |= AR5K_IMR_TIM; + + if (new_mask & AR5K_INT_TIM) + simr2 |= AR5K_SISR2_TIM; + if (new_mask & AR5K_INT_DTIM) + simr2 |= AR5K_SISR2_DTIM; + if (new_mask & AR5K_INT_DTIM_SYNC) + simr2 |= AR5K_SISR2_DTIM_SYNC; + if (new_mask & AR5K_INT_BCN_TIMEOUT) + simr2 |= AR5K_SISR2_BCN_TIMEOUT; + if (new_mask & AR5K_INT_CAB_TIMEOUT) + simr2 |= AR5K_SISR2_CAB_TIMEOUT; + + if (new_mask & AR5K_INT_RX_DOPPLER) + int_mask |= AR5K_IMR_RXDOPPLER; + + /* Note: Per queue interrupt masks + * are set via reset_tx_queue (qcu.c) */ + ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); + + } else { + if (new_mask & AR5K_INT_FATAL) + int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT + | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); + + ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); + } + + /* If RXNOFRM interrupt is masked disable it + * by setting AR5K_RXNOFRM to zero */ + if (!(new_mask & AR5K_INT_RXNOFRM)) + ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM); + + /* Store new interrupt mask */ + ah->ah_imr = new_mask; + + /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */ + if (new_mask & AR5K_INT_GLOBAL) { + 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/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c new file mode 100644 index 0000000..c0fb3b0 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -0,0 +1,1769 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2009 Nick Kossifidis + * Copyright (c) 2008-2009 Felix Fietkau + * + * 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_eeprom_info *ee, u16 bin, + unsigned int mode) +{ + u16 val; + + if (bin == AR5K_EEPROM_CHANNEL_DIS) + return bin; + + if (mode == AR5K_EEPROM_MODE_11A) { + if (ee->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 (ee->ee_version > AR5K_EEPROM_VERSION_3_2) + val = bin + 2300; + else + val = bin + 2400; + } + + return val; +} + +/* + * Initialize eeprom & capabilities structs + */ +static int +ath5k_eeprom_init_header(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int ret; + u16 val; + + /* + * 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); + + /* XXX: Don't know which versions include these two */ + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); + + if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) { + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6); + } + } + + 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; + } + + return 0; +} + + +/* + * 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_atn_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); + 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 and some mode-specific calibration data + * 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; + + ee->ee_n_piers[mode] = 0; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + 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(o++, 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; + break; + case AR5K_EEPROM_MODE_11G: + case AR5K_EEPROM_MODE_11B: + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + break; + } + + 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_6) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + } + } + + 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_0) + goto done; + + /* Note: >= v5 have bg freq piers on another location + * so these freq piers are ignored for >= v5 (should be 0xff + * anyway) */ + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) + break; + + AR5K_EEPROM_READ(o++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + break; + case AR5K_EEPROM_MODE_11B: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_b[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_b[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_b[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + break; + case AR5K_EEPROM_MODE_11G: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_g[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_g[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_g[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(o++, 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(o++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; + } + break; + } + +done: + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Read turbo mode information on newer EEPROM versions + */ +static int +ath5k_eeprom_read_turbo_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; + + if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) + return 0; + + switch (mode){ + case AR5K_EEPROM_MODE_11A: + ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; + + ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7; + ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff; + + if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2) + ee->ee_pd_gain_overlap = (val >> 9) & 0xf; + break; + case AR5K_EEPROM_MODE_11G: + ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f; + + ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5; + ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff; + break; + } + + /* return new offset */ + *offset = o; + + return 0; +} + +/* Read mode-specific data (except power calibration data) */ +static int +ath5k_eeprom_init_modes(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 mode_offset[3]; + unsigned int mode; + u32 offset; + int ret; + + /* + * Get values for all modes + */ + mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); + + ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + offset = mode_offset[mode]; + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); + if (ret) + return ret; + } + + /* override for older eeprom versions for better performance */ + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) { + ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15; + ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28; + ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28; + } + + return 0; +} + +/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff + * frequency mask) */ +static inline int +ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, + struct ath5k_chan_pcal_info *pc, unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int o = *offset; + int i = 0; + u8 freq1, freq2; + int ret; + u16 val; + + ee->ee_n_piers[mode] = 0; + while(i < max) { + AR5K_EEPROM_READ(o++, val); + + freq1 = val & 0xff; + if (!freq1) + break; + + pc[i++].freq = ath5k_eeprom_bin2freq(ee, + freq1, mode); + ee->ee_n_piers[mode]++; + + freq2 = (val >> 8) & 0xff; + if (!freq2) + break; + + pc[i++].freq = ath5k_eeprom_bin2freq(ee, + freq2, mode); + ee->ee_n_piers[mode]++; + } + + /* return new offset */ + *offset = o; + + return 0; +} + +/* Read frequency piers for 802.11a */ +static int +ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; + int i, ret; + u16 val; + u8 mask; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_5GHZ_CHAN, pcal, + AR5K_EEPROM_MODE_11A); + } else { + mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); + + AR5K_EEPROM_READ(offset++, val); + pcal[0].freq = (val >> 9) & mask; + pcal[1].freq = (val >> 2) & mask; + pcal[2].freq = (val << 5) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[2].freq |= (val >> 11) & 0x1f; + pcal[3].freq = (val >> 4) & mask; + pcal[4].freq = (val << 3) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[4].freq |= (val >> 13) & 0x7; + pcal[5].freq = (val >> 6) & mask; + pcal[6].freq = (val << 1) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[6].freq |= (val >> 15) & 0x1; + pcal[7].freq = (val >> 8) & mask; + pcal[8].freq = (val >> 1) & mask; + pcal[9].freq = (val << 6) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[9].freq |= (val >> 10) & 0x3f; + + /* Fixed number of piers */ + ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; + + for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) { + pcal[i].freq = ath5k_eeprom_bin2freq(ee, + pcal[i].freq, AR5K_EEPROM_MODE_11A); + } + } + + return 0; +} + +/* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */ +static inline int +ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + + switch(mode) { + case AR5K_EEPROM_MODE_11B: + pcal = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + pcal = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, + mode); + + return 0; +} + +/* + * Read power calibration for RF5111 chips + * + * For RF5111 we have an XPD -eXternal Power Detector- curve + * for each calibrated channel. Each curve has 0,5dB Power steps + * on x axis and PCDAC steps (offsets) on y axis and looks like an + * exponential function. To recreate the curve we read 11 points + * here and interpolate later. + */ + +/* Used to match PCDAC steps with power values on RF5111 chips + * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC + * steps that match with the power values we read from eeprom. On + * older eeprom versions (< 3.2) these steps are equaly spaced at + * 10% of the pcdac curve -until the curve reaches it's maximum- + * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) + * these 11 steps are spaced in a different way. This function returns + * the pcdac steps based on eeprom version and curve min/max so that we + * can have pcdac/pwr points. + */ +static inline void +ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) +{ + const static u16 intercepts3[] = + { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; + const static u16 intercepts3_2[] = + { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; + const u16 *ip; + int i; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) + ip = intercepts3_2; + else + ip = intercepts3; + + for (i = 0; i < ARRAY_SIZE(intercepts3); i++) + vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; +} + +/* Convert RF5111 specific data to generic raw data + * used by interpolation code */ +static int +ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, + struct ath5k_chan_pcal_info *chinfo) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf5111 *pcinfo; + struct ath5k_pdgain_info *pd; + u8 pier, point, idx; + u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; + + /* Fill raw data for each calibration pier */ + for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { + + pcinfo = &chinfo[pier].rf5111_info; + + /* Allocate pd_curves for this cal pier */ + chinfo[pier].pd_curves = + kcalloc(AR5K_EEPROM_N_PD_CURVES, + sizeof(struct ath5k_pdgain_info), + GFP_KERNEL); + + if (!chinfo[pier].pd_curves) + return -ENOMEM; + + /* Only one curve for RF5111 + * find out which one and place + * in in pd_curves. + * Note: ee_x_gain is reversed here */ + for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) { + + if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) { + pdgain_idx[0] = idx; + break; + } + } + + ee->ee_pd_gains[mode] = 1; + + pd = &chinfo[pier].pd_curves[idx]; + + pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111; + + /* Allocate pd points for this curve */ + pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, + sizeof(u8), GFP_KERNEL); + if (!pd->pd_step) + return -ENOMEM; + + pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, + sizeof(s16), GFP_KERNEL); + if (!pd->pd_pwr) + return -ENOMEM; + + /* Fill raw dataset + * (convert power to 0.25dB units + * for RF5112 combatibility) */ + for (point = 0; point < pd->pd_points; point++) { + + /* Absolute values */ + pd->pd_pwr[point] = 2 * pcinfo->pwr[point]; + + /* Already sorted */ + pd->pd_step[point] = pcinfo->pcdac[point]; + } + + /* Set min/max pwr */ + chinfo[pier].min_pwr = pd->pd_pwr[0]; + chinfo[pier].max_pwr = pd->pd_pwr[10]; + + } + + return 0; +} + +/* Parse EEPROM data */ +static int +ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + int offset, ret; + int i; + u16 val; + + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ret = ath5k_eeprom_init_11a_pcal_freq(ah, + offset + AR5K_EEPROM_GROUP1_OFFSET); + if (ret < 0) + return ret; + + offset += AR5K_EEPROM_GROUP2_OFFSET; + pcal = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header) && + !AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_b; + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2412; + pcal[1].freq = 2447; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_g; + offset += AR5K_EEPROM_GROUP4_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2312; + pcal[1].freq = 2412; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + default: + return -EINVAL; + } + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + struct ath5k_chan_pcal_info_rf5111 *cdata = + &pcal[i].rf5111_info; + + AR5K_EEPROM_READ(offset++, val); + cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M); + cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M); + cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M); + + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[0] |= ((val >> 14) & 0x3); + cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M); + cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M); + + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[3] |= ((val >> 12) & 0xf); + cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M); + cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M); + + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M); + cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M); + cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M); + + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[8] |= ((val >> 14) & 0x3); + cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M); + + ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min, + cdata->pcdac_max, cdata->pcdac); + } + + return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal); +} + + +/* + * Read power calibration for RF5112 chips + * + * For RF5112 we have 4 XPD -eXternal Power Detector- curves + * for each calibrated channel on 0, -6, -12 and -18dbm but we only + * use the higher (3) and the lower (0) curves. Each curve has 0.5dB + * power steps on x axis and PCDAC steps on y axis and looks like a + * linear function. To recreate the curve and pass the power values + * on hw, we read 4 points for xpd 0 (lower gain -> max power) + * and 3 points for xpd 3 (higher gain -> lower power) here and + * interpolate later. + * + * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. + */ + +/* Convert RF5112 specific data to generic raw data + * used by interpolation code */ +static int +ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, + struct ath5k_chan_pcal_info *chinfo) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf5112 *pcinfo; + u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; + unsigned int pier, pdg, point; + + /* Fill raw data for each calibration pier */ + for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { + + pcinfo = &chinfo[pier].rf5112_info; + + /* Allocate pd_curves for this cal pier */ + chinfo[pier].pd_curves = + kcalloc(AR5K_EEPROM_N_PD_CURVES, + sizeof(struct ath5k_pdgain_info), + GFP_KERNEL); + + if (!chinfo[pier].pd_curves) + return -ENOMEM; + + /* Fill pd_curves */ + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + + u8 idx = pdgain_idx[pdg]; + struct ath5k_pdgain_info *pd = + &chinfo[pier].pd_curves[idx]; + + /* Lowest gain curve (max power) */ + if (pdg == 0) { + /* One more point for better accuracy */ + pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS; + + /* Allocate pd points for this curve */ + pd->pd_step = kcalloc(pd->pd_points, + sizeof(u8), GFP_KERNEL); + + if (!pd->pd_step) + return -ENOMEM; + + pd->pd_pwr = kcalloc(pd->pd_points, + sizeof(s16), GFP_KERNEL); + + if (!pd->pd_pwr) + return -ENOMEM; + + + /* Fill raw dataset + * (all power levels are in 0.25dB units) */ + pd->pd_step[0] = pcinfo->pcdac_x0[0]; + pd->pd_pwr[0] = pcinfo->pwr_x0[0]; + + for (point = 1; point < pd->pd_points; + point++) { + /* Absolute values */ + pd->pd_pwr[point] = + pcinfo->pwr_x0[point]; + + /* Deltas */ + pd->pd_step[point] = + pd->pd_step[point - 1] + + pcinfo->pcdac_x0[point]; + } + + /* Set min power for this frequency */ + chinfo[pier].min_pwr = pd->pd_pwr[0]; + + /* Highest gain curve (min power) */ + } else if (pdg == 1) { + + pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS; + + /* Allocate pd points for this curve */ + pd->pd_step = kcalloc(pd->pd_points, + sizeof(u8), GFP_KERNEL); + + if (!pd->pd_step) + return -ENOMEM; + + pd->pd_pwr = kcalloc(pd->pd_points, + sizeof(s16), GFP_KERNEL); + + if (!pd->pd_pwr) + return -ENOMEM; + + /* Fill raw dataset + * (all power levels are in 0.25dB units) */ + for (point = 0; point < pd->pd_points; + point++) { + /* Absolute values */ + pd->pd_pwr[point] = + pcinfo->pwr_x3[point]; + + /* Fixed points */ + pd->pd_step[point] = + pcinfo->pcdac_x3[point]; + } + + /* Since we have a higher gain curve + * override min power */ + chinfo[pier].min_pwr = pd->pd_pwr[0]; + } + } + } + + return 0; +} + +/* Parse EEPROM data */ +static int +ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; + struct ath5k_chan_pcal_info *gen_chan_info; + u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; + u32 offset; + u8 i, c; + u16 val; + int ret; + u8 pd_gains = 0; + + /* Count how many curves we have and + * identify them (which one of the 4 + * available curves we have on each count). + * Curves are stored from lower (x0) to + * higher (x3) gain */ + for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) { + /* ee_x_gain[mode] is x gain mask */ + if ((ee->ee_x_gain[mode] >> i) & 0x1) + pdgain_idx[pd_gains++] = i; + } + ee->ee_pd_gains[mode] = pd_gains; + + if (pd_gains == 0 || pd_gains > 2) + return -EINVAL; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + /* + * Read 5GHz EEPROM channels + */ + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + + offset += AR5K_EEPROM_GROUP2_OFFSET; + gen_chan_info = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP4_OFFSET; + else if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += AR5K_EEPROM_GROUP2_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf5112_info; + + /* Power values in quarter dB + * for the lower xpd gain curve + * (0 dBm -> higher output power) */ + for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff); + chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff); + } + + /* PCDAC steps + * corresponding to the above power + * measurements */ + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pcdac_x0[1] = (val & 0x1f); + chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); + chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); + + /* Power values in quarter dB + * for the higher xpd gain curve + * (18 dBm -> lower output power) */ + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff); + chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff); + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_x3[2] = (val & 0xff); + + /* PCDAC steps + * corresponding to the above power + * measurements (fixed) */ + chan_pcal_info->pcdac_x3[0] = 20; + chan_pcal_info->pcdac_x3[1] = 35; + chan_pcal_info->pcdac_x3[2] = 63; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { + chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f); + + /* Last xpd0 power level is also channel maximum */ + gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; + } else { + chan_pcal_info->pcdac_x0[0] = 1; + gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff); + } + + } + + return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info); +} + + +/* + * Read power calibration for RF2413 chips + * + * For RF2413 we have a Power to PDDAC table (Power Detector) + * instead of a PCDAC and 4 pd gain curves for each calibrated channel. + * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y + * axis and looks like an exponential function like the RF5111 curve. + * + * To recreate the curves we read here the points and interpolate + * later. Note that in most cases only 2 (higher and lower) curves are + * used (like RF5112) but vendors have the oportunity to include all + * 4 curves on eeprom. The final curve (higher power) has an extra + * point for better accuracy like RF5112. + */ + +/* For RF2413 power calibration data doesn't start on a fixed location and + * if a mode is not supported, it's section is missing -not zeroed-. + * So we need to calculate the starting offset for each section by using + * these two functions */ + +/* Return the size of each section based on the mode and the number of pd + * gains available (maximum 4). */ +static inline unsigned int +ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) +{ + static const unsigned int pdgains_size[] = { 4, 6, 9, 12 }; + unsigned int sz; + + sz = pdgains_size[ee->ee_pd_gains[mode] - 1]; + sz *= ee->ee_n_piers[mode]; + + return sz; +} + +/* Return the starting offset for a section based on the modes supported + * and each section's size. */ +static unsigned int +ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) +{ + u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4); + + switch(mode) { + case AR5K_EEPROM_MODE_11G: + if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, + AR5K_EEPROM_MODE_11B) + + AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + /* fall through */ + case AR5K_EEPROM_MODE_11B: + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, + AR5K_EEPROM_MODE_11A) + + AR5K_EEPROM_N_5GHZ_CHAN / 2; + /* fall through */ + case AR5K_EEPROM_MODE_11A: + break; + default: + break; + } + + return offset; +} + +/* Convert RF2413 specific data to generic raw data + * used by interpolation code */ +static int +ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, + struct ath5k_chan_pcal_info *chinfo) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf2413 *pcinfo; + u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; + unsigned int pier, pdg, point; + + /* Fill raw data for each calibration pier */ + for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { + + pcinfo = &chinfo[pier].rf2413_info; + + /* Allocate pd_curves for this cal pier */ + chinfo[pier].pd_curves = + kcalloc(AR5K_EEPROM_N_PD_CURVES, + sizeof(struct ath5k_pdgain_info), + GFP_KERNEL); + + if (!chinfo[pier].pd_curves) + return -ENOMEM; + + /* Fill pd_curves */ + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + + u8 idx = pdgain_idx[pdg]; + struct ath5k_pdgain_info *pd = + &chinfo[pier].pd_curves[idx]; + + /* One more point for the highest power + * curve (lowest gain) */ + if (pdg == ee->ee_pd_gains[mode] - 1) + pd->pd_points = AR5K_EEPROM_N_PD_POINTS; + else + pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1; + + /* Allocate pd points for this curve */ + pd->pd_step = kcalloc(pd->pd_points, + sizeof(u8), GFP_KERNEL); + + if (!pd->pd_step) + return -ENOMEM; + + pd->pd_pwr = kcalloc(pd->pd_points, + sizeof(s16), GFP_KERNEL); + + if (!pd->pd_pwr) + return -ENOMEM; + + /* Fill raw dataset + * convert all pwr levels to + * quarter dB for RF5112 combatibility */ + pd->pd_step[0] = pcinfo->pddac_i[pdg]; + pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg]; + + for (point = 1; point < pd->pd_points; point++) { + + pd->pd_pwr[point] = pd->pd_pwr[point - 1] + + 2 * pcinfo->pwr[pdg][point - 1]; + + pd->pd_step[point] = pd->pd_step[point - 1] + + pcinfo->pddac[pdg][point - 1]; + + } + + /* Highest gain curve -> min power */ + if (pdg == 0) + chinfo[pier].min_pwr = pd->pd_pwr[0]; + + /* Lowest gain curve -> max power */ + if (pdg == ee->ee_pd_gains[mode] - 1) + chinfo[pier].max_pwr = + pd->pd_pwr[pd->pd_points - 1]; + } + } + + return 0; +} + +/* Parse EEPROM data */ +static int +ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf2413 *pcinfo; + struct ath5k_chan_pcal_info *chinfo; + u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; + u32 offset; + int idx, i, ret; + u16 val; + u8 pd_gains = 0; + + /* Count how many curves we have and + * identify them (which one of the 4 + * available curves we have on each count). + * Curves are stored from higher to + * lower gain so we go backwards */ + for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) { + /* ee_x_gain[mode] is x gain mask */ + if ((ee->ee_x_gain[mode] >> idx) & 0x1) + pdgain_idx[pd_gains++] = idx; + + } + ee->ee_pd_gains[mode] = pd_gains; + + if (pd_gains == 0) + return -EINVAL; + + offset = ath5k_cal_data_offset_2413(ee, mode); + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; + chinfo = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + chinfo = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + chinfo = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + pcinfo = &chinfo[i].rf2413_info; + + /* + * Read pwr_i, pddac_i and the first + * 2 pd points (pwr, pddac) + */ + AR5K_EEPROM_READ(offset++, val); + pcinfo->pwr_i[0] = val & 0x1f; + pcinfo->pddac_i[0] = (val >> 5) & 0x7f; + pcinfo->pwr[0][0] = (val >> 12) & 0xf; + + AR5K_EEPROM_READ(offset++, val); + pcinfo->pddac[0][0] = val & 0x3f; + pcinfo->pwr[0][1] = (val >> 6) & 0xf; + pcinfo->pddac[0][1] = (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + pcinfo->pwr[0][2] = val & 0xf; + pcinfo->pddac[0][2] = (val >> 4) & 0x3f; + + pcinfo->pwr[0][3] = 0; + pcinfo->pddac[0][3] = 0; + + if (pd_gains > 1) { + /* + * Pd gain 0 is not the last pd gain + * so it only has 2 pd points. + * Continue wih pd gain 1. + */ + pcinfo->pwr_i[1] = (val >> 10) & 0x1f; + + pcinfo->pddac_i[1] = (val >> 15) & 0x1; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pddac_i[1] |= (val & 0x3F) << 1; + + pcinfo->pwr[1][0] = (val >> 6) & 0xf; + pcinfo->pddac[1][0] = (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + pcinfo->pwr[1][1] = val & 0xf; + pcinfo->pddac[1][1] = (val >> 4) & 0x3f; + pcinfo->pwr[1][2] = (val >> 10) & 0xf; + + pcinfo->pddac[1][2] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pddac[1][2] |= (val & 0xF) << 2; + + pcinfo->pwr[1][3] = 0; + pcinfo->pddac[1][3] = 0; + } else if (pd_gains == 1) { + /* + * Pd gain 0 is the last one so + * read the extra point. + */ + pcinfo->pwr[0][3] = (val >> 10) & 0xf; + + pcinfo->pddac[0][3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pddac[0][3] |= (val & 0xF) << 2; + } + + /* + * Proceed with the other pd_gains + * as above. + */ + if (pd_gains > 2) { + pcinfo->pwr_i[2] = (val >> 4) & 0x1f; + pcinfo->pddac_i[2] = (val >> 9) & 0x7f; + + AR5K_EEPROM_READ(offset++, val); + pcinfo->pwr[2][0] = (val >> 0) & 0xf; + pcinfo->pddac[2][0] = (val >> 4) & 0x3f; + pcinfo->pwr[2][1] = (val >> 10) & 0xf; + + pcinfo->pddac[2][1] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pddac[2][1] |= (val & 0xF) << 2; + + pcinfo->pwr[2][2] = (val >> 4) & 0xf; + pcinfo->pddac[2][2] = (val >> 8) & 0x3f; + + pcinfo->pwr[2][3] = 0; + pcinfo->pddac[2][3] = 0; + } else if (pd_gains == 2) { + pcinfo->pwr[1][3] = (val >> 4) & 0xf; + pcinfo->pddac[1][3] = (val >> 8) & 0x3f; + } + + if (pd_gains > 3) { + pcinfo->pwr_i[3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; + + pcinfo->pddac_i[3] = (val >> 3) & 0x7f; + pcinfo->pwr[3][0] = (val >> 10) & 0xf; + pcinfo->pddac[3][0] = (val >> 14) & 0x3; + + AR5K_EEPROM_READ(offset++, val); + pcinfo->pddac[3][0] |= (val & 0xF) << 2; + pcinfo->pwr[3][1] = (val >> 4) & 0xf; + pcinfo->pddac[3][1] = (val >> 8) & 0x3f; + + pcinfo->pwr[3][2] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; + + pcinfo->pddac[3][2] = (val >> 2) & 0x3f; + pcinfo->pwr[3][3] = (val >> 8) & 0xf; + + pcinfo->pddac[3][3] = (val >> 12) & 0xF; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; + } else if (pd_gains == 3) { + pcinfo->pwr[2][3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; + + pcinfo->pddac[2][3] = (val >> 2) & 0x3f; + } + } + + return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo); +} + + +/* + * Read per rate target power (this is the maximum tx power + * supported by the card). This info is used when setting + * tx power, no matter the channel. + * + * This also works for v5 EEPROMs. + */ +static int +ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_rate_pcal_info *rate_pcal_info; + u8 *rate_target_pwr_num; + u32 offset; + u16 val; + int ret, i; + + offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); + rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; + switch (mode) { + case AR5K_EEPROM_MODE_11A: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_a; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN; + break; + case AR5K_EEPROM_MODE_11B: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_b; + ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */ + break; + case AR5K_EEPROM_MODE_11G: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_g; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN; + break; + default: + return -EINVAL; + } + + /* Different freq mask for older eeproms (<= v3.2) */ + if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7); + rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f); + rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f); + } + } else { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf; + rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f); + rate_pcal_info[i].target_power_54 = (val & 0x3f); + } + } + + return 0; +} + +/* + * Read per channel calibration info from EEPROM + * + * This info is used to calibrate the baseband power table. Imagine + * that for each channel there is a power curve that's hw specific + * (depends on amplifier etc) and we try to "correct" this curve using + * offests we pass on to phy chip (baseband -> before amplifier) so that + * it can use accurate power values when setting tx power (takes amplifier's + * performance on each channel into account). + * + * EEPROM provides us with the offsets for some pre-calibrated channels + * and we have to interpolate to create the full table for these channels and + * also the table for any channel. + */ +static int +ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int (*read_pcal)(struct ath5k_hw *hw, int mode); + int mode; + int err; + + if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1)) + read_pcal = ath5k_eeprom_read_pcal_info_5112; + else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2)) + read_pcal = ath5k_eeprom_read_pcal_info_2413; + else + read_pcal = ath5k_eeprom_read_pcal_info_5111; + + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; + mode++) { + err = read_pcal(ah, mode); + if (err) + return err; + + err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode); + if (err < 0) + return err; + } + + return 0; +} + +static int +ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *chinfo; + u8 pier, pdg; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { + if (!chinfo[pier].pd_curves) + continue; + + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + struct ath5k_pdgain_info *pd = + &chinfo[pier].pd_curves[pdg]; + + if (pd != NULL) { + kfree(pd->pd_step); + kfree(pd->pd_pwr); + } + } + + kfree(chinfo[pier].pd_curves); + } + + return 0; +} + +void +ath5k_eeprom_detach(struct ath5k_hw *ah) +{ + u8 mode; + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) + ath5k_eeprom_free_pcal_info(ah, mode); +} + +/* Read conformance test limits used for regulatory control */ +static int +ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_edge_power *rep; + unsigned int fmask, pmask; + unsigned int ctl_mode; + int ret, i, j; + u32 offset; + u16 val; + + pmask = AR5K_EEPROM_POWER_M; + fmask = AR5K_EEPROM_FREQ_M(ee->ee_version); + offset = AR5K_EEPROM_CTL(ee->ee_version); + ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version); + for (i = 0; i < ee->ee_ctls; i += 2) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_ctl[i] = (val >> 8) & 0xff; + ee->ee_ctl[i + 1] = val & 0xff; + } + + offset = AR5K_EEPROM_GROUP8_OFFSET; + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) + offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) - + AR5K_EEPROM_GROUP5_OFFSET; + else + offset += AR5K_EEPROM_GROUPS_START(ee->ee_version); + + rep = ee->ee_ctl_pwr; + for(i = 0; i < ee->ee_ctls; i++) { + switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) { + case AR5K_CTL_11A: + case AR5K_CTL_TURBO: + ctl_mode = AR5K_EEPROM_MODE_11A; + break; + default: + ctl_mode = AR5K_EEPROM_MODE_11G; + break; + } + if (ee->ee_ctl[i] == 0) { + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) + offset += 8; + else + offset += 7; + rep += AR5K_EEPROM_N_EDGES; + continue; + } + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].freq = (val >> 8) & fmask; + rep[j + 1].freq = val & fmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].edge = (val >> 8) & pmask; + rep[j].flag = (val >> 14) & 1; + rep[j + 1].edge = val & pmask; + rep[j + 1].flag = (val >> 6) & 1; + } + } else { + AR5K_EEPROM_READ(offset++, val); + rep[0].freq = (val >> 9) & fmask; + rep[1].freq = (val >> 2) & fmask; + rep[2].freq = (val << 5) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[2].freq |= (val >> 11) & 0x1f; + rep[3].freq = (val >> 4) & fmask; + rep[4].freq = (val << 3) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].freq |= (val >> 13) & 0x7; + rep[5].freq = (val >> 6) & fmask; + rep[6].freq = (val << 1) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].freq |= (val >> 15) & 0x1; + rep[7].freq = (val >> 8) & fmask; + + rep[0].edge = (val >> 2) & pmask; + rep[1].edge = (val << 4) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[1].edge |= (val >> 12) & 0xf; + rep[2].edge = (val >> 6) & pmask; + rep[3].edge = val & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].edge = (val >> 10) & pmask; + rep[5].edge = (val >> 4) & pmask; + rep[6].edge = (val << 2) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].edge |= (val >> 14) & 0x3; + rep[7].edge = (val >> 8) & pmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) { + rep[j].freq = ath5k_eeprom_bin2freq(ee, + rep[j].freq, ctl_mode); + } + rep += AR5K_EEPROM_N_EDGES; + } + + return 0; +} + + +/* + * Initialize eeprom power tables + */ +int +ath5k_eeprom_init(struct ath5k_hw *ah) +{ + int err; + + err = ath5k_eeprom_init_header(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_init_modes(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_pcal_info(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_ctl_info(ah); + if (err < 0) + return err; + + 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; + + 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; + } + + if (!total || total == 3 * 0xffff) + return -EINVAL; + + memcpy(mac, mac_d, ETH_ALEN); + + return 0; +} + +bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah) +{ + u16 data; + + ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data); + + if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data) + return true; + else + return false; +} + diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h new file mode 100644 index 0000000..b0c0606 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * 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_IS_HB63 0x000b /* Talon detect */ +#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ +#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ +#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 /* power calibration changes */ +#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 0x3007 /* 4007 ? */ +#define AR5K_EEPROM_VERSION_4_9 0x4009 /* EAR futureproofing */ +#define AR5K_EEPROM_VERSION_5_0 0x5000 /* Has 2413 PDADC calibration etc */ +#define AR5K_EEPROM_VERSION_5_1 0x5001 /* Has capability values */ +#define AR5K_EEPROM_VERSION_5_3 0x5003 /* Has spur mitigation tables */ + +#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_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ +#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ + +#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) ((s8)(((_v) >> 8) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((s8)((_v) & 0xff)) + +/* Misc values available since EEPROM 4.0 */ +#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4) +#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1) +#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1) +#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) + +#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5) +#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) +#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1) + +#define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6) +#define AR5K_EEPROM_EEP_FILE_VERSION(_v) (((_v) >> 8) & 0xff) +#define AR5K_EEPROM_EAR_FILE_VERSION(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC3 AR5K_EEPROM_INFO(7) +#define AR5K_EEPROM_ART_BUILD_NUM(_v) (((_v) >> 10) & 0x3f) +#define AR5K_EEPROM_EAR_FILE_ID(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8) +#define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff) +#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3) +#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3) + +#define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9) +#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1) +#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1) +#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1) +#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1) +#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf) +#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf) + +#define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10) +#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8) +#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8) +#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1) +#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1) +#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1) +#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1) + +/* 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 */ +#define AR5K_EEPROM_GROUPS_START(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* Start of Groups */ +#define AR5K_EEPROM_GROUP1_OFFSET 0x0 +#define AR5K_EEPROM_GROUP2_OFFSET 0x5 +#define AR5K_EEPROM_GROUP3_OFFSET 0x37 +#define AR5K_EEPROM_GROUP4_OFFSET 0x46 +#define AR5K_EEPROM_GROUP5_OFFSET 0x55 +#define AR5K_EEPROM_GROUP6_OFFSET 0x65 +#define AR5K_EEPROM_GROUP7_OFFSET 0x69 +#define AR5K_EEPROM_GROUP8_OFFSET 0x6f + +#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP5_OFFSET, 0x0000) +#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP6_OFFSET, 0x0010) +#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP7_OFFSET, 0x0014) + +/* [3.1 - 3.3] */ +#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec +#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed + +#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 + +/* 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_N_2GHZ_CHAN_2413 4 +#define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4 +#define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PWR_POINTS_5111 11 +#define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_PHASE_CAL 5 +#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_PD_CURVES 4 +#define AR5K_EEPROM_N_XPD0_POINTS 4 +#define AR5K_EEPROM_N_XPD3_POINTS 3 +#define AR5K_EEPROM_N_PD_GAINS 4 +#define AR5K_EEPROM_N_PD_POINTS 5 +#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); \ + +enum ath5k_ant_setting { + AR5K_ANT_VARIABLE = 0, /* variable by programming */ + AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ + AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ + AR5K_ANT_MAX = 3, +}; + +enum ath5k_ctl_mode { + AR5K_CTL_11A = 0, + AR5K_CTL_11B = 1, + AR5K_CTL_11G = 2, + AR5K_CTL_TURBO = 3, + AR5K_CTL_TURBOG = 4, + AR5K_CTL_2GHT20 = 5, + AR5K_CTL_5GHT20 = 6, + AR5K_CTL_2GHT40 = 7, + AR5K_CTL_5GHT40 = 8, + AR5K_CTL_MODE_M = 15, +}; + +/* Default CTL ids for the 3 main reg domains. + * Atheros only uses these by default but vendors + * can have up to 32 different CTLs for different + * scenarios. Note that theese values are ORed with + * the mode id (above) so we can have up to 24 CTL + * datasets out of these 3 main regdomains. That leaves + * 8 ids that can be used by vendors and since 0x20 is + * missing from HAL sources i guess this is the set of + * custom CTLs vendors can use. */ +#define AR5K_CTL_FCC 0x10 +#define AR5K_CTL_CUSTOM 0x20 +#define AR5K_CTL_ETSI 0x30 +#define AR5K_CTL_MKK 0x40 + +/* Indicates a CTL with only mode set and + * no reg domain mapping, such CTLs are used + * for world roaming domains or simply when + * a reg domain is not set */ +#define AR5K_CTL_NO_REGDOMAIN 0xf0 + +/* Indicates an empty (invalid) CTL */ +#define AR5K_CTL_NO_CTL 0xff + +/* Per channel calibration data, used for power table setup */ +struct ath5k_chan_pcal_info_rf5111 { + /* Power levels in half dbm units + * for one power curve. */ + u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* PCDAC table steps + * for the above values */ + u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* Starting PCDAC step */ + u8 pcdac_min; + /* Final PCDAC step */ + u8 pcdac_max; +}; + +struct ath5k_chan_pcal_info_rf5112 { + /* Power levels in quarter dBm units + * for lower (0) and higher (3) + * level curves in 0.25dB units */ + s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; + s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; + /* PCDAC table steps + * for the above values */ + u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; + u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; +}; + +struct ath5k_chan_pcal_info_rf2413 { + /* Starting pwr/pddac values */ + s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; + u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; + /* (pwr,pddac) points + * power levels in 0.5dB units */ + s8 pwr[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; + u8 pddac[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; +}; + +enum ath5k_powertable_type { + AR5K_PWRTABLE_PWR_TO_PCDAC = 0, + AR5K_PWRTABLE_LINEAR_PCDAC = 1, + AR5K_PWRTABLE_PWR_TO_PDADC = 2, +}; + +struct ath5k_pdgain_info { + u8 pd_points; + u8 *pd_step; + /* Power values are in + * 0.25dB units */ + s16 *pd_pwr; +}; + +struct ath5k_chan_pcal_info { + /* Frequency */ + u16 freq; + /* Tx power boundaries */ + s16 max_pwr; + s16 min_pwr; + union { + struct ath5k_chan_pcal_info_rf5111 rf5111_info; + struct ath5k_chan_pcal_info_rf5112 rf5112_info; + struct ath5k_chan_pcal_info_rf2413 rf2413_info; + }; + /* Raw values used by phy code + * Curves are stored in order from lower + * gain to higher gain (max txpower -> min txpower) */ + struct ath5k_pdgain_info *pd_curves; +}; + +/* Per rate calibration data for each mode, + * used for rate power table setup. + * Note: Values in 0.5dB units */ +struct ath5k_rate_pcal_info { + u16 freq; /* Frequency */ + /* Power level for 6-24Mbit/s rates or + * 1Mb rate */ + u16 target_power_6to24; + /* Power level for 36Mbit rate or + * 2Mb rate */ + u16 target_power_36; + /* Power level for 48Mbit rate or + * 5.5Mbit rate */ + u16 target_power_48; + /* Power level for 54Mbit rate or + * 11Mbit rate */ + u16 target_power_54; +}; + +/* Power edges for conformance test limits */ +struct ath5k_edge_power { + u16 freq; + u16 edge; /* in half dBm */ + bool flag; +}; + +/* EEPROM calibration data */ +struct ath5k_eeprom_info { + + /* Header information */ + 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_misc2; + u16 ee_misc3; + u16 ee_misc4; + u16 ee_misc5; + u16 ee_misc6; + u16 ee_cck_ofdm_gain_delta; + u16 ee_cck_ofdm_power_delta; + u16 ee_scaled_cck_delta; + + /* 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_atn_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]; + u16 ee_switch_settling_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES]; + + /* Power calibration data */ + u16 ee_false_detect[AR5K_EEPROM_N_MODES]; + + /* Number of pd gain curves per mode */ + u8 ee_pd_gains[AR5K_EEPROM_N_MODES]; + /* Back mapping pdcurve number -> pdcurve index in pd->pd_curves */ + u8 ee_pdc_to_idx[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PD_GAINS]; + + u8 ee_n_piers[AR5K_EEPROM_N_MODES]; + struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; + struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; + + /* Per rate target power levels */ + u8 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES]; + struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; + struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; + + /* Conformance test limits (Unused) */ + u8 ee_ctls; + u8 ee_ctl[AR5K_EEPROM_MAX_CTLS]; + struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * 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]; + s8 ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pd_gain_overlap; + + u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; +}; + diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c new file mode 100644 index 0000000..64a27e7 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/gpio.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * 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/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c new file mode 100644 index 0000000..61fb621 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -0,0 +1,1557 @@ +/* + * Initial register settings functions + * + * Copyright (c) 2004-2007 Reyk Floeter + * Copyright (c) 2006-2009 Nick Kossifidis + * Copyright (c) 2007-2008 Jiri Slaby + * + * 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. + * + */ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Mode-independent initial register writes + */ + +struct ath5k_ini { + u16 ini_register; + u32 ini_value; + + enum { + AR5K_INI_WRITE = 0, /* Default */ + AR5K_INI_READ = 1, /* Cleared on read */ + } ini_mode; +}; + +/* + * Mode specific initial register values + */ + +struct ath5k_ini_mode { + u16 mode_register; + u32 mode_value[5]; +}; + +/* Initial register settings for AR5210 */ +static const struct ath5k_ini ar5210_ini[] = { + /* PCU and MAC registers */ + { AR5K_NOQCU_TXDP0, 0 }, + { AR5K_NOQCU_TXDP1, 0 }, + { AR5K_RXDP, 0 }, + { AR5K_CR, 0 }, + { AR5K_ISR, 0, AR5K_INI_READ }, + { AR5K_IMR, 0 }, + { AR5K_IER, AR5K_IER_DISABLE }, + { AR5K_BSR, 0, AR5K_INI_READ }, + { AR5K_TXCFG, AR5K_DMASIZE_128B }, + { AR5K_RXCFG, AR5K_DMASIZE_128B }, + { AR5K_CFG, AR5K_INIT_CFG }, + { AR5K_TOPS, 8 }, + { AR5K_RXNOFRM, 8 }, + { AR5K_RPGTO, 0 }, + { AR5K_TXNOFRM, 0 }, + { AR5K_SFR, 0 }, + { AR5K_MIBC, 0 }, + { AR5K_MISC, 0 }, + { AR5K_RX_FILTER_5210, 0 }, + { AR5K_MCAST_FILTER0_5210, 0 }, + { AR5K_MCAST_FILTER1_5210, 0 }, + { AR5K_TX_MASK0, 0 }, + { AR5K_TX_MASK1, 0 }, + { AR5K_CLR_TMASK, 0 }, + { AR5K_TRIG_LVL, AR5K_TUNE_MIN_TX_FIFO_THRES }, + { AR5K_DIAG_SW_5210, 0 }, + { AR5K_RSSI_THR, AR5K_TUNE_RSSI_THRES }, + { AR5K_TSF_L32_5210, 0 }, + { AR5K_TIMER0_5210, 0 }, + { AR5K_TIMER1_5210, 0xffffffff }, + { AR5K_TIMER2_5210, 0xffffffff }, + { AR5K_TIMER3_5210, 1 }, + { AR5K_CFP_DUR_5210, 0 }, + { AR5K_CFP_PERIOD_5210, 0 }, + /* PHY registers */ + { AR5K_PHY(0), 0x00000047 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY(3), 0x09848ea6 }, + { AR5K_PHY(4), 0x3d32e000 }, + { AR5K_PHY(5), 0x0000076b }, + { AR5K_PHY_ACT, AR5K_PHY_ACT_DISABLE }, + { AR5K_PHY(8), 0x02020200 }, + { AR5K_PHY(9), 0x00000e0e }, + { AR5K_PHY(10), 0x0a020201 }, + { AR5K_PHY(11), 0x00036ffc }, + { AR5K_PHY(12), 0x00000000 }, + { AR5K_PHY(13), 0x00000e0e }, + { AR5K_PHY(14), 0x00000007 }, + { AR5K_PHY(15), 0x00020100 }, + { AR5K_PHY(16), 0x89630000 }, + { AR5K_PHY(17), 0x1372169c }, + { AR5K_PHY(18), 0x0018b633 }, + { AR5K_PHY(19), 0x1284613c }, + { AR5K_PHY(20), 0x0de8b8e0 }, + { AR5K_PHY(21), 0x00074859 }, + { AR5K_PHY(22), 0x7e80beba }, + { AR5K_PHY(23), 0x313a665e }, + { AR5K_PHY_AGCCTL, 0x00001d08 }, + { AR5K_PHY(25), 0x0001ce00 }, + { AR5K_PHY(26), 0x409a4190 }, + { AR5K_PHY(28), 0x0000000f }, + { AR5K_PHY(29), 0x00000080 }, + { AR5K_PHY(30), 0x00000004 }, + { AR5K_PHY(31), 0x00000018 }, /* 0x987c */ + { AR5K_PHY(64), 0x00000000 }, /* 0x9900 */ + { AR5K_PHY(65), 0x00000000 }, + { AR5K_PHY(66), 0x00000000 }, + { AR5K_PHY(67), 0x00800000 }, + { AR5K_PHY(68), 0x00000003 }, + /* BB gain table (64bytes) */ + { AR5K_BB_GAIN(0), 0x00000000 }, + { AR5K_BB_GAIN(1), 0x00000020 }, + { AR5K_BB_GAIN(2), 0x00000010 }, + { AR5K_BB_GAIN(3), 0x00000030 }, + { AR5K_BB_GAIN(4), 0x00000008 }, + { AR5K_BB_GAIN(5), 0x00000028 }, + { AR5K_BB_GAIN(6), 0x00000028 }, + { AR5K_BB_GAIN(7), 0x00000004 }, + { AR5K_BB_GAIN(8), 0x00000024 }, + { AR5K_BB_GAIN(9), 0x00000014 }, + { AR5K_BB_GAIN(10), 0x00000034 }, + { AR5K_BB_GAIN(11), 0x0000000c }, + { AR5K_BB_GAIN(12), 0x0000002c }, + { AR5K_BB_GAIN(13), 0x00000002 }, + { AR5K_BB_GAIN(14), 0x00000022 }, + { AR5K_BB_GAIN(15), 0x00000012 }, + { AR5K_BB_GAIN(16), 0x00000032 }, + { AR5K_BB_GAIN(17), 0x0000000a }, + { AR5K_BB_GAIN(18), 0x0000002a }, + { AR5K_BB_GAIN(19), 0x00000001 }, + { AR5K_BB_GAIN(20), 0x00000021 }, + { AR5K_BB_GAIN(21), 0x00000011 }, + { AR5K_BB_GAIN(22), 0x00000031 }, + { AR5K_BB_GAIN(23), 0x00000009 }, + { AR5K_BB_GAIN(24), 0x00000029 }, + { AR5K_BB_GAIN(25), 0x00000005 }, + { AR5K_BB_GAIN(26), 0x00000025 }, + { AR5K_BB_GAIN(27), 0x00000015 }, + { AR5K_BB_GAIN(28), 0x00000035 }, + { AR5K_BB_GAIN(29), 0x0000000d }, + { AR5K_BB_GAIN(30), 0x0000002d }, + { AR5K_BB_GAIN(31), 0x00000003 }, + { AR5K_BB_GAIN(32), 0x00000023 }, + { AR5K_BB_GAIN(33), 0x00000013 }, + { AR5K_BB_GAIN(34), 0x00000033 }, + { AR5K_BB_GAIN(35), 0x0000000b }, + { AR5K_BB_GAIN(36), 0x0000002b }, + { AR5K_BB_GAIN(37), 0x00000007 }, + { AR5K_BB_GAIN(38), 0x00000027 }, + { AR5K_BB_GAIN(39), 0x00000017 }, + { AR5K_BB_GAIN(40), 0x00000037 }, + { AR5K_BB_GAIN(41), 0x0000000f }, + { AR5K_BB_GAIN(42), 0x0000002f }, + { AR5K_BB_GAIN(43), 0x0000002f }, + { AR5K_BB_GAIN(44), 0x0000002f }, + { AR5K_BB_GAIN(45), 0x0000002f }, + { AR5K_BB_GAIN(46), 0x0000002f }, + { AR5K_BB_GAIN(47), 0x0000002f }, + { AR5K_BB_GAIN(48), 0x0000002f }, + { AR5K_BB_GAIN(49), 0x0000002f }, + { AR5K_BB_GAIN(50), 0x0000002f }, + { AR5K_BB_GAIN(51), 0x0000002f }, + { AR5K_BB_GAIN(52), 0x0000002f }, + { AR5K_BB_GAIN(53), 0x0000002f }, + { AR5K_BB_GAIN(54), 0x0000002f }, + { AR5K_BB_GAIN(55), 0x0000002f }, + { AR5K_BB_GAIN(56), 0x0000002f }, + { AR5K_BB_GAIN(57), 0x0000002f }, + { AR5K_BB_GAIN(58), 0x0000002f }, + { AR5K_BB_GAIN(59), 0x0000002f }, + { AR5K_BB_GAIN(60), 0x0000002f }, + { AR5K_BB_GAIN(61), 0x0000002f }, + { AR5K_BB_GAIN(62), 0x0000002f }, + { AR5K_BB_GAIN(63), 0x0000002f }, + /* 5110 RF gain table (64btes) */ + { AR5K_RF_GAIN(0), 0x0000001d }, + { AR5K_RF_GAIN(1), 0x0000005d }, + { AR5K_RF_GAIN(2), 0x0000009d }, + { AR5K_RF_GAIN(3), 0x000000dd }, + { AR5K_RF_GAIN(4), 0x0000011d }, + { AR5K_RF_GAIN(5), 0x00000021 }, + { AR5K_RF_GAIN(6), 0x00000061 }, + { AR5K_RF_GAIN(7), 0x000000a1 }, + { AR5K_RF_GAIN(8), 0x000000e1 }, + { AR5K_RF_GAIN(9), 0x00000031 }, + { AR5K_RF_GAIN(10), 0x00000071 }, + { AR5K_RF_GAIN(11), 0x000000b1 }, + { AR5K_RF_GAIN(12), 0x0000001c }, + { AR5K_RF_GAIN(13), 0x0000005c }, + { AR5K_RF_GAIN(14), 0x00000029 }, + { AR5K_RF_GAIN(15), 0x00000069 }, + { AR5K_RF_GAIN(16), 0x000000a9 }, + { AR5K_RF_GAIN(17), 0x00000020 }, + { AR5K_RF_GAIN(18), 0x00000019 }, + { AR5K_RF_GAIN(19), 0x00000059 }, + { AR5K_RF_GAIN(20), 0x00000099 }, + { AR5K_RF_GAIN(21), 0x00000030 }, + { AR5K_RF_GAIN(22), 0x00000005 }, + { AR5K_RF_GAIN(23), 0x00000025 }, + { AR5K_RF_GAIN(24), 0x00000065 }, + { AR5K_RF_GAIN(25), 0x000000a5 }, + { AR5K_RF_GAIN(26), 0x00000028 }, + { AR5K_RF_GAIN(27), 0x00000068 }, + { AR5K_RF_GAIN(28), 0x0000001f }, + { AR5K_RF_GAIN(29), 0x0000001e }, + { AR5K_RF_GAIN(30), 0x00000018 }, + { AR5K_RF_GAIN(31), 0x00000058 }, + { AR5K_RF_GAIN(32), 0x00000098 }, + { AR5K_RF_GAIN(33), 0x00000003 }, + { AR5K_RF_GAIN(34), 0x00000004 }, + { AR5K_RF_GAIN(35), 0x00000044 }, + { AR5K_RF_GAIN(36), 0x00000084 }, + { AR5K_RF_GAIN(37), 0x00000013 }, + { AR5K_RF_GAIN(38), 0x00000012 }, + { AR5K_RF_GAIN(39), 0x00000052 }, + { AR5K_RF_GAIN(40), 0x00000092 }, + { AR5K_RF_GAIN(41), 0x000000d2 }, + { AR5K_RF_GAIN(42), 0x0000002b }, + { AR5K_RF_GAIN(43), 0x0000002a }, + { AR5K_RF_GAIN(44), 0x0000006a }, + { AR5K_RF_GAIN(45), 0x000000aa }, + { AR5K_RF_GAIN(46), 0x0000001b }, + { AR5K_RF_GAIN(47), 0x0000001a }, + { AR5K_RF_GAIN(48), 0x0000005a }, + { AR5K_RF_GAIN(49), 0x0000009a }, + { AR5K_RF_GAIN(50), 0x000000da }, + { AR5K_RF_GAIN(51), 0x00000006 }, + { AR5K_RF_GAIN(52), 0x00000006 }, + { AR5K_RF_GAIN(53), 0x00000006 }, + { AR5K_RF_GAIN(54), 0x00000006 }, + { AR5K_RF_GAIN(55), 0x00000006 }, + { AR5K_RF_GAIN(56), 0x00000006 }, + { AR5K_RF_GAIN(57), 0x00000006 }, + { AR5K_RF_GAIN(58), 0x00000006 }, + { AR5K_RF_GAIN(59), 0x00000006 }, + { AR5K_RF_GAIN(60), 0x00000006 }, + { AR5K_RF_GAIN(61), 0x00000006 }, + { AR5K_RF_GAIN(62), 0x00000006 }, + { AR5K_RF_GAIN(63), 0x00000006 }, + /* PHY activation */ + { AR5K_PHY(53), 0x00000020 }, + { AR5K_PHY(51), 0x00000004 }, + { AR5K_PHY(50), 0x00060106 }, + { AR5K_PHY(39), 0x0000006d }, + { AR5K_PHY(48), 0x00000000 }, + { AR5K_PHY(52), 0x00000014 }, + { AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE }, +}; + +/* Initial register settings for AR5211 */ +static const struct ath5k_ini ar5211_ini[] = { + { AR5K_RXDP, 0x00000000 }, + { AR5K_RTSD0, 0x84849c9c }, + { AR5K_RTSD1, 0x7c7c7c7c }, + { AR5K_RXCFG, 0x00000005 }, + { AR5K_MIBC, 0x00000000 }, + { AR5K_TOPS, 0x00000008 }, + { AR5K_RXNOFRM, 0x00000008 }, + { AR5K_TXNOFRM, 0x00000010 }, + { AR5K_RPGTO, 0x00000000 }, + { AR5K_RFCNT, 0x0000001f }, + { AR5K_QUEUE_TXDP(0), 0x00000000 }, + { AR5K_QUEUE_TXDP(1), 0x00000000 }, + { AR5K_QUEUE_TXDP(2), 0x00000000 }, + { AR5K_QUEUE_TXDP(3), 0x00000000 }, + { AR5K_QUEUE_TXDP(4), 0x00000000 }, + { AR5K_QUEUE_TXDP(5), 0x00000000 }, + { AR5K_QUEUE_TXDP(6), 0x00000000 }, + { AR5K_QUEUE_TXDP(7), 0x00000000 }, + { AR5K_QUEUE_TXDP(8), 0x00000000 }, + { AR5K_QUEUE_TXDP(9), 0x00000000 }, + { AR5K_DCU_FP, 0x00000000 }, + { AR5K_STA_ID1, 0x00000000 }, + { AR5K_BSS_ID0, 0x00000000 }, + { AR5K_BSS_ID1, 0x00000000 }, + { AR5K_RSSI_THR, 0x00000000 }, + { AR5K_CFP_PERIOD_5211, 0x00000000 }, + { AR5K_TIMER0_5211, 0x00000030 }, + { AR5K_TIMER1_5211, 0x0007ffff }, + { AR5K_TIMER2_5211, 0x01ffffff }, + { AR5K_TIMER3_5211, 0x00000031 }, + { AR5K_CFP_DUR_5211, 0x00000000 }, + { AR5K_RX_FILTER_5211, 0x00000000 }, + { AR5K_MCAST_FILTER0_5211, 0x00000000 }, + { AR5K_MCAST_FILTER1_5211, 0x00000002 }, + { AR5K_DIAG_SW_5211, 0x00000000 }, + { AR5K_ADDAC_TEST, 0x00000000 }, + { AR5K_DEFAULT_ANTENNA, 0x00000000 }, + /* PHY registers */ + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY(3), 0x2d849093 }, + { AR5K_PHY(4), 0x7d32e000 }, + { AR5K_PHY(5), 0x00000f6b }, + { AR5K_PHY_ACT, 0x00000000 }, + { AR5K_PHY(11), 0x00026ffe }, + { AR5K_PHY(12), 0x00000000 }, + { AR5K_PHY(15), 0x00020100 }, + { AR5K_PHY(16), 0x206a017a }, + { AR5K_PHY(19), 0x1284613c }, + { AR5K_PHY(21), 0x00000859 }, + { AR5K_PHY(26), 0x409a4190 }, /* 0x9868 */ + { AR5K_PHY(27), 0x050cb081 }, + { AR5K_PHY(28), 0x0000000f }, + { AR5K_PHY(29), 0x00000080 }, + { AR5K_PHY(30), 0x0000000c }, + { AR5K_PHY(64), 0x00000000 }, + { AR5K_PHY(65), 0x00000000 }, + { AR5K_PHY(66), 0x00000000 }, + { AR5K_PHY(67), 0x00800000 }, + { AR5K_PHY(68), 0x00000001 }, + { AR5K_PHY(71), 0x0000092a }, + { AR5K_PHY_IQ, 0x00000000 }, + { AR5K_PHY(73), 0x00058a05 }, + { AR5K_PHY(74), 0x00000001 }, + { AR5K_PHY(75), 0x00000000 }, + { AR5K_PHY_PAPD_PROBE, 0x00000000 }, + { AR5K_PHY(77), 0x00000000 }, /* 0x9934 */ + { AR5K_PHY(78), 0x00000000 }, /* 0x9938 */ + { AR5K_PHY(79), 0x0000003f }, /* 0x993c */ + { AR5K_PHY(80), 0x00000004 }, + { AR5K_PHY(82), 0x00000000 }, + { AR5K_PHY(83), 0x00000000 }, + { AR5K_PHY(84), 0x00000000 }, + { AR5K_PHY_RADAR, 0x5d50f14c }, + { AR5K_PHY(86), 0x00000018 }, + { AR5K_PHY(87), 0x004b6a8e }, + /* Initial Power table (32bytes) + * common on all cards/modes. + * Note: Table is rewritten during + * txpower setup later using calibration + * data etc. so next write is non-common */ + { AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff }, + { AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff }, + { AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff }, + { AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff }, + { AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff }, + { AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff }, + { AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff }, + { AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff }, + { AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff }, + { AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff }, + { AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff }, + { AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff }, + { AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff }, + { AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff }, + { AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff }, + { AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff }, + { AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff }, + { AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff }, + { AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff }, + { AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff }, + { AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff }, + { AR5K_PHY_CCKTXCTL, 0x00000000 }, + { AR5K_PHY(642), 0x503e4646 }, + { AR5K_PHY_GAIN_2GHZ, 0x6480416c }, + { AR5K_PHY(644), 0x0199a003 }, + { AR5K_PHY(645), 0x044cd610 }, + { AR5K_PHY(646), 0x13800040 }, + { AR5K_PHY(647), 0x1be00060 }, + { AR5K_PHY(648), 0x0c53800a }, + { AR5K_PHY(649), 0x0014df3b }, + { AR5K_PHY(650), 0x000001b5 }, + { AR5K_PHY(651), 0x00000020 }, +}; + +/* Initial mode-specific settings for AR5211 + * 5211 supports OFDM-only g (draft g) but we + * need to test it ! + */ +static const struct ath5k_ini_mode ar5211_ini_mode[] = { + { AR5K_TXCFG, + /* a aTurbo b g (OFDM) */ + { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(0), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(1), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(2), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(3), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(4), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(5), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(6), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(7), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(8), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(9), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, + { AR5K_DCU_GBL_IFS_SLOT, + { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } }, + { AR5K_DCU_GBL_IFS_SIFS, + { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } }, + { AR5K_DCU_GBL_IFS_EIFS, + { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } }, + { AR5K_DCU_GBL_IFS_MISC, + { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } }, + { AR5K_TIME_OUT, + { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } }, + { AR5K_USEC_5211, + { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } }, + { AR5K_PHY_TURBO, + { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } }, + { AR5K_PHY(8), + { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } }, + { AR5K_PHY(9), + { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } }, + { AR5K_PHY(10), + { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } }, + { AR5K_PHY(13), + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY(14), + { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } }, + { AR5K_PHY(17), + { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } }, + { AR5K_PHY(18), + { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } }, + { AR5K_PHY(20), + { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } }, + { AR5K_PHY_SIG, + { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } }, + { AR5K_PHY_AGCCTL, + { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } }, + { AR5K_PHY_NF, + { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, + { AR5K_PHY_RX_DELAY, + { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } }, + { AR5K_PHY(70), + { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } }, + { AR5K_PHY_PCDAC_TXPOWER_BASE, + { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } }, + { AR5K_RF_BUFFER_CONTROL_4, + { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } }, +}; + +/* Initial register settings for AR5212 */ +static const struct ath5k_ini ar5212_ini_common_start[] = { + { AR5K_RXDP, 0x00000000 }, + { AR5K_RXCFG, 0x00000005 }, + { AR5K_MIBC, 0x00000000 }, + { AR5K_TOPS, 0x00000008 }, + { AR5K_RXNOFRM, 0x00000008 }, + { AR5K_TXNOFRM, 0x00000010 }, + { AR5K_RPGTO, 0x00000000 }, + { AR5K_RFCNT, 0x0000001f }, + { AR5K_QUEUE_TXDP(0), 0x00000000 }, + { AR5K_QUEUE_TXDP(1), 0x00000000 }, + { AR5K_QUEUE_TXDP(2), 0x00000000 }, + { AR5K_QUEUE_TXDP(3), 0x00000000 }, + { AR5K_QUEUE_TXDP(4), 0x00000000 }, + { AR5K_QUEUE_TXDP(5), 0x00000000 }, + { AR5K_QUEUE_TXDP(6), 0x00000000 }, + { AR5K_QUEUE_TXDP(7), 0x00000000 }, + { AR5K_QUEUE_TXDP(8), 0x00000000 }, + { AR5K_QUEUE_TXDP(9), 0x00000000 }, + { AR5K_DCU_FP, 0x00000000 }, + { AR5K_DCU_TXP, 0x00000000 }, + /* Tx filter table 0 (32 entries) */ + { AR5K_DCU_TX_FILTER_0(0), 0x00000000 }, /* DCU 0 */ + { AR5K_DCU_TX_FILTER_0(1), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(2), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(3), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(4), 0x00000000 }, /* DCU 1 */ + { AR5K_DCU_TX_FILTER_0(5), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(6), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(7), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(8), 0x00000000 }, /* DCU 2 */ + { AR5K_DCU_TX_FILTER_0(9), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(10), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(11), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(12), 0x00000000 }, /* DCU 3 */ + { AR5K_DCU_TX_FILTER_0(13), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(14), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(15), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(16), 0x00000000 }, /* DCU 4 */ + { AR5K_DCU_TX_FILTER_0(17), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(18), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(19), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(20), 0x00000000 }, /* DCU 5 */ + { AR5K_DCU_TX_FILTER_0(21), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(22), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(23), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(24), 0x00000000 }, /* DCU 6 */ + { AR5K_DCU_TX_FILTER_0(25), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(26), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(27), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(28), 0x00000000 }, /* DCU 7 */ + { AR5K_DCU_TX_FILTER_0(29), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(30), 0x00000000 }, + { AR5K_DCU_TX_FILTER_0(31), 0x00000000 }, + /* Tx filter table 1 (16 entries) */ + { AR5K_DCU_TX_FILTER_1(0), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(1), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(2), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(3), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(4), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(5), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(6), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(7), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(8), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(9), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(10), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(11), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(12), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(13), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(14), 0x00000000 }, + { AR5K_DCU_TX_FILTER_1(15), 0x00000000 }, + { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, + { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, + { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, + { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, + { AR5K_STA_ID1, 0x00000000 }, + { AR5K_BSS_ID0, 0x00000000 }, + { AR5K_BSS_ID1, 0x00000000 }, + { AR5K_BEACON_5211, 0x00000000 }, + { AR5K_CFP_PERIOD_5211, 0x00000000 }, + { AR5K_TIMER0_5211, 0x00000030 }, + { AR5K_TIMER1_5211, 0x0007ffff }, + { AR5K_TIMER2_5211, 0x01ffffff }, + { AR5K_TIMER3_5211, 0x00000031 }, + { AR5K_CFP_DUR_5211, 0x00000000 }, + { AR5K_RX_FILTER_5211, 0x00000000 }, + { AR5K_DIAG_SW_5211, 0x00000000 }, + { AR5K_ADDAC_TEST, 0x00000000 }, + { AR5K_DEFAULT_ANTENNA, 0x00000000 }, + { AR5K_FRAME_CTL_QOSM, 0x000fc78f }, + { AR5K_XRMODE, 0x2a82301a }, + { AR5K_XRDELAY, 0x05dc01e0 }, + { AR5K_XRTIMEOUT, 0x1f402710 }, + { AR5K_XRCHIRP, 0x01f40000 }, + { AR5K_XRSTOMP, 0x00001e1c }, + { AR5K_SLEEP0, 0x0002aaaa }, + { AR5K_SLEEP1, 0x02005555 }, + { AR5K_SLEEP2, 0x00000000 }, + { AR5K_BSS_IDM0, 0xffffffff }, + { AR5K_BSS_IDM1, 0x0000ffff }, + { AR5K_TXPC, 0x00000000 }, + { AR5K_PROFCNT_TX, 0x00000000 }, + { AR5K_PROFCNT_RX, 0x00000000 }, + { AR5K_PROFCNT_RXCLR, 0x00000000 }, + { AR5K_PROFCNT_CYCLE, 0x00000000 }, + { AR5K_QUIET_CTL1, 0x00000088 }, + /* Initial rate duration table (32 entries )*/ + { AR5K_RATE_DUR(0), 0x00000000 }, + { AR5K_RATE_DUR(1), 0x0000008c }, + { AR5K_RATE_DUR(2), 0x000000e4 }, + { AR5K_RATE_DUR(3), 0x000002d5 }, + { AR5K_RATE_DUR(4), 0x00000000 }, + { AR5K_RATE_DUR(5), 0x00000000 }, + { AR5K_RATE_DUR(6), 0x000000a0 }, + { AR5K_RATE_DUR(7), 0x000001c9 }, + { AR5K_RATE_DUR(8), 0x0000002c }, + { AR5K_RATE_DUR(9), 0x0000002c }, + { AR5K_RATE_DUR(10), 0x00000030 }, + { AR5K_RATE_DUR(11), 0x0000003c }, + { AR5K_RATE_DUR(12), 0x0000002c }, + { AR5K_RATE_DUR(13), 0x0000002c }, + { AR5K_RATE_DUR(14), 0x00000030 }, + { AR5K_RATE_DUR(15), 0x0000003c }, + { AR5K_RATE_DUR(16), 0x00000000 }, + { AR5K_RATE_DUR(17), 0x00000000 }, + { AR5K_RATE_DUR(18), 0x00000000 }, + { AR5K_RATE_DUR(19), 0x00000000 }, + { AR5K_RATE_DUR(20), 0x00000000 }, + { AR5K_RATE_DUR(21), 0x00000000 }, + { AR5K_RATE_DUR(22), 0x00000000 }, + { AR5K_RATE_DUR(23), 0x00000000 }, + { AR5K_RATE_DUR(24), 0x000000d5 }, + { AR5K_RATE_DUR(25), 0x000000df }, + { AR5K_RATE_DUR(26), 0x00000102 }, + { AR5K_RATE_DUR(27), 0x0000013a }, + { AR5K_RATE_DUR(28), 0x00000075 }, + { AR5K_RATE_DUR(29), 0x0000007f }, + { AR5K_RATE_DUR(30), 0x000000a2 }, + { AR5K_RATE_DUR(31), 0x00000000 }, + { AR5K_QUIET_CTL2, 0x00010002 }, + { AR5K_TSF_PARM, 0x00000001 }, + { AR5K_QOS_NOACK, 0x000000c0 }, + { AR5K_PHY_ERR_FIL, 0x00000000 }, + { AR5K_XRLAT_TX, 0x00000168 }, + { AR5K_ACKSIFS, 0x00000000 }, + /* Rate -> db table + * notice ...03<-02<-01<-00 ! */ + { AR5K_RATE2DB(0), 0x03020100 }, + { AR5K_RATE2DB(1), 0x07060504 }, + { AR5K_RATE2DB(2), 0x0b0a0908 }, + { AR5K_RATE2DB(3), 0x0f0e0d0c }, + { AR5K_RATE2DB(4), 0x13121110 }, + { AR5K_RATE2DB(5), 0x17161514 }, + { AR5K_RATE2DB(6), 0x1b1a1918 }, + { AR5K_RATE2DB(7), 0x1f1e1d1c }, + /* Db -> Rate table */ + { AR5K_DB2RATE(0), 0x03020100 }, + { AR5K_DB2RATE(1), 0x07060504 }, + { AR5K_DB2RATE(2), 0x0b0a0908 }, + { AR5K_DB2RATE(3), 0x0f0e0d0c }, + { AR5K_DB2RATE(4), 0x13121110 }, + { AR5K_DB2RATE(5), 0x17161514 }, + { AR5K_DB2RATE(6), 0x1b1a1918 }, + { AR5K_DB2RATE(7), 0x1f1e1d1c }, + /* PHY registers (Common settings + * for all chips/modes) */ + { AR5K_PHY(3), 0xad848e19 }, + { AR5K_PHY(4), 0x7d28e000 }, + { AR5K_PHY_TIMING_3, 0x9c0a9f6b }, + { AR5K_PHY_ACT, 0x00000000 }, + { AR5K_PHY(16), 0x206a017a }, + { AR5K_PHY(21), 0x00000859 }, + { AR5K_PHY_BIN_MASK_1, 0x00000000 }, + { AR5K_PHY_BIN_MASK_2, 0x00000000 }, + { AR5K_PHY_BIN_MASK_3, 0x00000000 }, + { AR5K_PHY_BIN_MASK_CTL, 0x00800000 }, + { AR5K_PHY_ANT_CTL, 0x00000001 }, + /*{ AR5K_PHY(71), 0x0000092a },*/ /* Old value */ + { AR5K_PHY_MAX_RX_LEN, 0x00000c80 }, + { AR5K_PHY_IQ, 0x05100000 }, + { AR5K_PHY_WARM_RESET, 0x00000001 }, + { AR5K_PHY_CTL, 0x00000004 }, + { AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022 }, + { AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d }, + { AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f }, + { AR5K_PHY(82), 0x9280b212 }, + { AR5K_PHY_RADAR, 0x5d50e188 }, + /*{ AR5K_PHY(86), 0x000000ff },*/ + { AR5K_PHY(87), 0x004b6a8e }, + { AR5K_PHY_NFTHRES, 0x000003ce }, + { AR5K_PHY_RESTART, 0x192fb515 }, + { AR5K_PHY(94), 0x00000001 }, + { AR5K_PHY_RFBUS_REQ, 0x00000000 }, + /*{ AR5K_PHY(644), 0x0080a333 },*/ /* Old value */ + /*{ AR5K_PHY(645), 0x00206c10 },*/ /* Old value */ + { AR5K_PHY(644), 0x00806333 }, + { AR5K_PHY(645), 0x00106c10 }, + { AR5K_PHY(646), 0x009c4060 }, + /* { AR5K_PHY(647), 0x1483800a }, */ + /* { AR5K_PHY(648), 0x01831061 }, */ /* Old value */ + { AR5K_PHY(648), 0x018830c6 }, + { AR5K_PHY(649), 0x00000400 }, + /*{ AR5K_PHY(650), 0x000001b5 },*/ + { AR5K_PHY(651), 0x00000000 }, + { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, + { AR5K_PHY_TXPOWER_RATE2, 0x20202020 }, + /*{ AR5K_PHY(655), 0x13c889af },*/ + { AR5K_PHY(656), 0x38490a20 }, + { AR5K_PHY(657), 0x00007bb6 }, + { AR5K_PHY(658), 0x0fff3ffc }, +}; + +/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */ +static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { + { AR5K_QUEUE_DFS_LOCAL_IFS(0), + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(1), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(2), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(3), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(4), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(5), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(6), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(7), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(8), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(9), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_DCU_GBL_IFS_SIFS, + { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } }, + { AR5K_DCU_GBL_IFS_SLOT, + { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } }, + { AR5K_DCU_GBL_IFS_EIFS, + { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } }, + { AR5K_DCU_GBL_IFS_MISC, + { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } }, + { AR5K_TIME_OUT, + { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } }, + { AR5K_PHY_TURBO, + { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } }, + { AR5K_PHY(8), + { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } }, + { AR5K_PHY_RF_CTL2, + { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY_SETTLING, + { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } }, + { AR5K_PHY_AGCCTL, + { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } }, + { AR5K_PHY_NF, + { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, + { AR5K_PHY_WEAK_OFDM_HIGH_THR, + { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } }, + { AR5K_PHY(70), + { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } }, + { AR5K_PHY_OFDM_SELFCORR, + { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } }, + { 0xa230, + { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } }, +}; + +/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */ +static const struct ath5k_ini_mode rf5111_ini_mode_end[] = { + { AR5K_TXCFG, + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, + { AR5K_USEC_5211, + { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } }, + { AR5K_PHY_RF_CTL3, + { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY_RF_CTL4, + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY_PA_CTL, + { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, + { AR5K_PHY_GAIN, + { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } }, + { AR5K_PHY_DESIRED_SIZE, + { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, + { AR5K_PHY_SIG, + { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } }, + { AR5K_PHY_WEAK_OFDM_LOW_THR, + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } }, + { AR5K_PHY_RX_DELAY, + { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } }, + { AR5K_PHY_CCK_RX_CTL_4, + { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, +}; + +static const struct ath5k_ini rf5111_ini_common_end[] = { + { AR5K_DCU_FP, 0x00000000 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY_ADC_CTL, 0x00022ffe }, + { 0x983c, 0x00020100 }, + { AR5K_PHY_GAIN_OFFSET, 0x1284613c }, + { AR5K_PHY_PAPD_PROBE, 0x00004883 }, + { 0x9940, 0x00000004 }, + { 0x9958, 0x000000ff }, + { 0x9974, 0x00000000 }, + { AR5K_PHY_SPENDING, 0x00000018 }, + { AR5K_PHY_CCKTXCTL, 0x00000000 }, + { AR5K_PHY_CCK_CROSSCORR, 0xd03e6788 }, + { AR5K_PHY_DAG_CCK_CTL, 0x000001b5 }, + { 0xa23c, 0x13c889af }, +}; + +/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */ +static const struct ath5k_ini_mode rf5112_ini_mode_end[] = { + { AR5K_TXCFG, + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, + { AR5K_USEC_5211, + { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, + { AR5K_PHY_RF_CTL3, + { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY_RF_CTL4, + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY_PA_CTL, + { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, + { AR5K_PHY_GAIN, + { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } }, + { AR5K_PHY_DESIRED_SIZE, + { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, + { AR5K_PHY_SIG, + { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } }, + { AR5K_PHY_WEAK_OFDM_LOW_THR, + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, + { AR5K_PHY_RX_DELAY, + { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } }, + { AR5K_PHY_CCK_CROSSCORR, + { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } }, + { AR5K_PHY_CCK_RX_CTL_4, + { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, +}; + +static const struct ath5k_ini rf5112_ini_common_end[] = { + { AR5K_DCU_FP, 0x00000000 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY_ADC_CTL, 0x00022ffe }, + { 0x983c, 0x00020100 }, + { AR5K_PHY_GAIN_OFFSET, 0x1284613c }, + { AR5K_PHY_PAPD_PROBE, 0x00004882 }, + { 0x9940, 0x00000004 }, + { 0x9958, 0x000000ff }, + { 0x9974, 0x00000000 }, + { AR5K_PHY_DAG_CCK_CTL, 0x000001b5 }, + { 0xa23c, 0x13c889af }, +}; + +/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */ +static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { + { AR5K_TXCFG, + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, + { AR5K_USEC_5211, + { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, + { AR5K_PHY_RF_CTL3, + { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY_RF_CTL4, + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY_PA_CTL, + { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, + { AR5K_PHY_GAIN, + { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } }, + { AR5K_PHY_DESIRED_SIZE, + { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } }, + { AR5K_PHY_SIG, + { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } }, + { AR5K_PHY_WEAK_OFDM_LOW_THR, + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, + { AR5K_PHY_RX_DELAY, + { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_CCK_CROSSCORR, + { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } }, + { AR5K_PHY_CCK_RX_CTL_4, + { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, + { 0xa300, + { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } }, + { 0xa304, + { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } }, + { 0xa308, + { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } }, + { 0xa30c, + { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } }, + { 0xa310, + { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } }, + { 0xa314, + { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } }, + { 0xa318, + { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } }, + { 0xa31c, + { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } }, + { 0xa320, + { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } }, + { 0xa324, + { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } }, + { 0xa328, + { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } }, + { 0xa32c, + { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } }, + { 0xa330, + { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } }, + { 0xa334, + { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } }, +}; + +static const struct ath5k_ini rf5413_ini_common_end[] = { + { AR5K_DCU_FP, 0x000003e0 }, + { AR5K_5414_CBCFG, 0x00000010 }, + { AR5K_SEQ_MASK, 0x0000000f }, + { 0x809c, 0x00000000 }, + { 0x80a0, 0x00000000 }, + { AR5K_MIC_QOS_CTL, 0x00000000 }, + { AR5K_MIC_QOS_SEL, 0x00000000 }, + { AR5K_MISC_MODE, 0x00000000 }, + { AR5K_OFDM_FIL_CNT, 0x00000000 }, + { AR5K_CCK_FIL_CNT, 0x00000000 }, + { AR5K_PHYERR_CNT1, 0x00000000 }, + { AR5K_PHYERR_CNT1_MASK, 0x00000000 }, + { AR5K_PHYERR_CNT2, 0x00000000 }, + { AR5K_PHYERR_CNT2_MASK, 0x00000000 }, + { AR5K_TSF_THRES, 0x00000000 }, + { 0x8140, 0x800003f9 }, + { 0x8144, 0x00000000 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY_ADC_CTL, 0x0000a000 }, + { 0x983c, 0x00200400 }, + { AR5K_PHY_GAIN_OFFSET, 0x1284233c }, + { AR5K_PHY_SCR, 0x0000001f }, + { AR5K_PHY_SLMT, 0x00000080 }, + { AR5K_PHY_SCAL, 0x0000000e }, + { 0x9958, 0x00081fff }, + { AR5K_PHY_TIMING_7, 0x00000000 }, + { AR5K_PHY_TIMING_8, 0x02800000 }, + { AR5K_PHY_TIMING_11, 0x00000000 }, + { AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 }, + { 0x99e4, 0xaaaaaaaa }, + { 0x99e8, 0x3c466478 }, + { 0x99ec, 0x000000aa }, + { AR5K_PHY_SCLOCK, 0x0000000c }, + { AR5K_PHY_SDELAY, 0x000000ff }, + { AR5K_PHY_SPENDING, 0x00000014 }, + { AR5K_PHY_DAG_CCK_CTL, 0x000009b5 }, + { 0xa23c, 0x93c889af }, + { AR5K_PHY_FAST_ADC, 0x00000001 }, + { 0xa250, 0x0000a000 }, + { AR5K_PHY_BLUETOOTH, 0x00000000 }, + { AR5K_PHY_TPC_RG1, 0x0cc75380 }, + { 0xa25c, 0x0f0f0f01 }, + { 0xa260, 0x5f690f01 }, + { 0xa264, 0x00418a11 }, + { 0xa268, 0x00000000 }, + { AR5K_PHY_TPC_RG5, 0x0c30c16a }, + { 0xa270, 0x00820820 }, + { 0xa274, 0x081b7caa }, + { 0xa278, 0x1ce739ce }, + { 0xa27c, 0x051701ce }, + { 0xa338, 0x00000000 }, + { 0xa33c, 0x00000000 }, + { 0xa340, 0x00000000 }, + { 0xa344, 0x00000000 }, + { 0xa348, 0x3fffffff }, + { 0xa34c, 0x3fffffff }, + { 0xa350, 0x3fffffff }, + { 0xa354, 0x0003ffff }, + { 0xa358, 0x79a8aa1f }, + { 0xa35c, 0x066c420f }, + { 0xa360, 0x0f282207 }, + { 0xa364, 0x17601685 }, + { 0xa368, 0x1f801104 }, + { 0xa36c, 0x37a00c03 }, + { 0xa370, 0x3fc40883 }, + { 0xa374, 0x57c00803 }, + { 0xa378, 0x5fd80682 }, + { 0xa37c, 0x7fe00482 }, + { 0xa380, 0x7f3c7bba }, + { 0xa384, 0xf3307ff0 }, +}; + +/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */ +/* XXX: a mode ? */ +static const struct ath5k_ini_mode rf2413_ini_mode_end[] = { + { AR5K_TXCFG, + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, + { AR5K_USEC_5211, + { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, + { AR5K_PHY_RF_CTL3, + { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY_RF_CTL4, + { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } }, + { AR5K_PHY_PA_CTL, + { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } }, + { AR5K_PHY_GAIN, + { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } }, + { AR5K_PHY_DESIRED_SIZE, + { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } }, + { AR5K_PHY_SIG, + { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } }, + { AR5K_PHY_WEAK_OFDM_LOW_THR, + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, + { AR5K_PHY_RX_DELAY, + { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_CCK_CROSSCORR, + { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } }, + { AR5K_PHY_CCK_RX_CTL_4, + { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, +}; + +static const struct ath5k_ini rf2413_ini_common_end[] = { + { AR5K_DCU_FP, 0x000003e0 }, + { AR5K_SEQ_MASK, 0x0000000f }, + { AR5K_MIC_QOS_CTL, 0x00000000 }, + { AR5K_MIC_QOS_SEL, 0x00000000 }, + { AR5K_MISC_MODE, 0x00000000 }, + { AR5K_OFDM_FIL_CNT, 0x00000000 }, + { AR5K_CCK_FIL_CNT, 0x00000000 }, + { AR5K_PHYERR_CNT1, 0x00000000 }, + { AR5K_PHYERR_CNT1_MASK, 0x00000000 }, + { AR5K_PHYERR_CNT2, 0x00000000 }, + { AR5K_PHYERR_CNT2_MASK, 0x00000000 }, + { AR5K_TSF_THRES, 0x00000000 }, + { 0x8140, 0x800000a8 }, + { 0x8144, 0x00000000 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY_ADC_CTL, 0x0000a000 }, + { 0x983c, 0x00200400 }, + { AR5K_PHY_GAIN_OFFSET, 0x1284233c }, + { AR5K_PHY_SCR, 0x0000001f }, + { AR5K_PHY_SLMT, 0x00000080 }, + { AR5K_PHY_SCAL, 0x0000000e }, + { 0x9958, 0x000000ff }, + { AR5K_PHY_TIMING_7, 0x00000000 }, + { AR5K_PHY_TIMING_8, 0x02800000 }, + { AR5K_PHY_TIMING_11, 0x00000000 }, + { AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 }, + { 0x99e4, 0xaaaaaaaa }, + { 0x99e8, 0x3c466478 }, + { 0x99ec, 0x000000aa }, + { AR5K_PHY_SCLOCK, 0x0000000c }, + { AR5K_PHY_SDELAY, 0x000000ff }, + { AR5K_PHY_SPENDING, 0x00000014 }, + { AR5K_PHY_DAG_CCK_CTL, 0x000009b5 }, + { 0xa23c, 0x93c889af }, + { AR5K_PHY_FAST_ADC, 0x00000001 }, + { 0xa250, 0x0000a000 }, + { AR5K_PHY_BLUETOOTH, 0x00000000 }, + { AR5K_PHY_TPC_RG1, 0x0cc75380 }, + { 0xa25c, 0x0f0f0f01 }, + { 0xa260, 0x5f690f01 }, + { 0xa264, 0x00418a11 }, + { 0xa268, 0x00000000 }, + { AR5K_PHY_TPC_RG5, 0x0c30c16a }, + { 0xa270, 0x00820820 }, + { 0xa274, 0x001b7caa }, + { 0xa278, 0x1ce739ce }, + { 0xa27c, 0x051701ce }, + { 0xa300, 0x18010000 }, + { 0xa304, 0x30032602 }, + { 0xa308, 0x48073e06 }, + { 0xa30c, 0x560b4c0a }, + { 0xa310, 0x641a600f }, + { 0xa314, 0x784f6e1b }, + { 0xa318, 0x868f7c5a }, + { 0xa31c, 0x8ecf865b }, + { 0xa320, 0x9d4f970f }, + { 0xa324, 0xa5cfa18f }, + { 0xa328, 0xb55faf1f }, + { 0xa32c, 0xbddfb99f }, + { 0xa330, 0xcd7fc73f }, + { 0xa334, 0xd5ffd1bf }, + { 0xa338, 0x00000000 }, + { 0xa33c, 0x00000000 }, + { 0xa340, 0x00000000 }, + { 0xa344, 0x00000000 }, + { 0xa348, 0x3fffffff }, + { 0xa34c, 0x3fffffff }, + { 0xa350, 0x3fffffff }, + { 0xa354, 0x0003ffff }, + { 0xa358, 0x79a8aa1f }, + { 0xa35c, 0x066c420f }, + { 0xa360, 0x0f282207 }, + { 0xa364, 0x17601685 }, + { 0xa368, 0x1f801104 }, + { 0xa36c, 0x37a00c03 }, + { 0xa370, 0x3fc40883 }, + { 0xa374, 0x57c00803 }, + { 0xa378, 0x5fd80682 }, + { 0xa37c, 0x7fe00482 }, + { 0xa380, 0x7f3c7bba }, + { 0xa384, 0xf3307ff0 }, +}; + +/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */ +/* XXX: a mode ? */ +static const struct ath5k_ini_mode rf2425_ini_mode_end[] = { + { AR5K_TXCFG, + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, + { AR5K_USEC_5211, + { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, + { AR5K_PHY_TURBO, + { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } }, + { AR5K_PHY_RF_CTL3, + { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY_RF_CTL4, + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY_PA_CTL, + { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } }, + { AR5K_PHY_SETTLING, + { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } }, + { AR5K_PHY_GAIN, + { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } }, + { AR5K_PHY_DESIRED_SIZE, + { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } }, + { AR5K_PHY_SIG, + { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } }, + { AR5K_PHY_WEAK_OFDM_LOW_THR, + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, + { AR5K_PHY_RX_DELAY, + { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_CCK_CROSSCORR, + { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } }, + { AR5K_PHY_CCK_RX_CTL_4, + { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, + { 0xa324, + { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, + { 0xa328, + { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, + { 0xa32c, + { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, + { 0xa330, + { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, + { 0xa334, + { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, +}; + +static const struct ath5k_ini rf2425_ini_common_end[] = { + { AR5K_DCU_FP, 0x000003e0 }, + { AR5K_SEQ_MASK, 0x0000000f }, + { 0x809c, 0x00000000 }, + { 0x80a0, 0x00000000 }, + { AR5K_MIC_QOS_CTL, 0x00000000 }, + { AR5K_MIC_QOS_SEL, 0x00000000 }, + { AR5K_MISC_MODE, 0x00000000 }, + { AR5K_OFDM_FIL_CNT, 0x00000000 }, + { AR5K_CCK_FIL_CNT, 0x00000000 }, + { AR5K_PHYERR_CNT1, 0x00000000 }, + { AR5K_PHYERR_CNT1_MASK, 0x00000000 }, + { AR5K_PHYERR_CNT2, 0x00000000 }, + { AR5K_PHYERR_CNT2_MASK, 0x00000000 }, + { AR5K_TSF_THRES, 0x00000000 }, + { 0x8140, 0x800003f9 }, + { 0x8144, 0x00000000 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY_ADC_CTL, 0x0000a000 }, + { 0x983c, 0x00200400 }, + { AR5K_PHY_GAIN_OFFSET, 0x1284233c }, + { AR5K_PHY_SCR, 0x0000001f }, + { AR5K_PHY_SLMT, 0x00000080 }, + { AR5K_PHY_SCAL, 0x0000000e }, + { 0x9958, 0x00081fff }, + { AR5K_PHY_TIMING_7, 0x00000000 }, + { AR5K_PHY_TIMING_8, 0x02800000 }, + { AR5K_PHY_TIMING_11, 0x00000000 }, + { 0x99dc, 0xfebadbe8 }, + { AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 }, + { 0x99e4, 0xaaaaaaaa }, + { 0x99e8, 0x3c466478 }, + { 0x99ec, 0x000000aa }, + { AR5K_PHY_SCLOCK, 0x0000000c }, + { AR5K_PHY_SDELAY, 0x000000ff }, + { AR5K_PHY_SPENDING, 0x00000014 }, + { AR5K_PHY_DAG_CCK_CTL, 0x000009b5 }, + { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, + { AR5K_PHY_TXPOWER_RATE4, 0x20202020 }, + { 0xa23c, 0x93c889af }, + { AR5K_PHY_FAST_ADC, 0x00000001 }, + { 0xa250, 0x0000a000 }, + { AR5K_PHY_BLUETOOTH, 0x00000000 }, + { AR5K_PHY_TPC_RG1, 0x0cc75380 }, + { 0xa25c, 0x0f0f0f01 }, + { 0xa260, 0x5f690f01 }, + { 0xa264, 0x00418a11 }, + { 0xa268, 0x00000000 }, + { AR5K_PHY_TPC_RG5, 0x0c30c166 }, + { 0xa270, 0x00820820 }, + { 0xa274, 0x081a3caa }, + { 0xa278, 0x1ce739ce }, + { 0xa27c, 0x051701ce }, + { 0xa300, 0x16010000 }, + { 0xa304, 0x2c032402 }, + { 0xa308, 0x48433e42 }, + { 0xa30c, 0x5a0f500b }, + { 0xa310, 0x6c4b624a }, + { 0xa314, 0x7e8b748a }, + { 0xa318, 0x96cf8ccb }, + { 0xa31c, 0xa34f9d0f }, + { 0xa320, 0xa7cfa58f }, + { 0xa348, 0x3fffffff }, + { 0xa34c, 0x3fffffff }, + { 0xa350, 0x3fffffff }, + { 0xa354, 0x0003ffff }, + { 0xa358, 0x79a8aa1f }, + { 0xa35c, 0x066c420f }, + { 0xa360, 0x0f282207 }, + { 0xa364, 0x17601685 }, + { 0xa368, 0x1f801104 }, + { 0xa36c, 0x37a00c03 }, + { 0xa370, 0x3fc40883 }, + { 0xa374, 0x57c00803 }, + { 0xa378, 0x5fd80682 }, + { 0xa37c, 0x7fe00482 }, + { 0xa380, 0x7f3c7bba }, + { 0xa384, 0xf3307ff0 }, +}; + +/* + * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with + * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI) + */ + +/* RF5111 Initial BaseBand Gain settings */ +static const struct ath5k_ini rf5111_ini_bbgain[] = { + { AR5K_BB_GAIN(0), 0x00000000 }, + { AR5K_BB_GAIN(1), 0x00000020 }, + { AR5K_BB_GAIN(2), 0x00000010 }, + { AR5K_BB_GAIN(3), 0x00000030 }, + { AR5K_BB_GAIN(4), 0x00000008 }, + { AR5K_BB_GAIN(5), 0x00000028 }, + { AR5K_BB_GAIN(6), 0x00000004 }, + { AR5K_BB_GAIN(7), 0x00000024 }, + { AR5K_BB_GAIN(8), 0x00000014 }, + { AR5K_BB_GAIN(9), 0x00000034 }, + { AR5K_BB_GAIN(10), 0x0000000c }, + { AR5K_BB_GAIN(11), 0x0000002c }, + { AR5K_BB_GAIN(12), 0x00000002 }, + { AR5K_BB_GAIN(13), 0x00000022 }, + { AR5K_BB_GAIN(14), 0x00000012 }, + { AR5K_BB_GAIN(15), 0x00000032 }, + { AR5K_BB_GAIN(16), 0x0000000a }, + { AR5K_BB_GAIN(17), 0x0000002a }, + { AR5K_BB_GAIN(18), 0x00000006 }, + { AR5K_BB_GAIN(19), 0x00000026 }, + { AR5K_BB_GAIN(20), 0x00000016 }, + { AR5K_BB_GAIN(21), 0x00000036 }, + { AR5K_BB_GAIN(22), 0x0000000e }, + { AR5K_BB_GAIN(23), 0x0000002e }, + { AR5K_BB_GAIN(24), 0x00000001 }, + { AR5K_BB_GAIN(25), 0x00000021 }, + { AR5K_BB_GAIN(26), 0x00000011 }, + { AR5K_BB_GAIN(27), 0x00000031 }, + { AR5K_BB_GAIN(28), 0x00000009 }, + { AR5K_BB_GAIN(29), 0x00000029 }, + { AR5K_BB_GAIN(30), 0x00000005 }, + { AR5K_BB_GAIN(31), 0x00000025 }, + { AR5K_BB_GAIN(32), 0x00000015 }, + { AR5K_BB_GAIN(33), 0x00000035 }, + { AR5K_BB_GAIN(34), 0x0000000d }, + { AR5K_BB_GAIN(35), 0x0000002d }, + { AR5K_BB_GAIN(36), 0x00000003 }, + { AR5K_BB_GAIN(37), 0x00000023 }, + { AR5K_BB_GAIN(38), 0x00000013 }, + { AR5K_BB_GAIN(39), 0x00000033 }, + { AR5K_BB_GAIN(40), 0x0000000b }, + { AR5K_BB_GAIN(41), 0x0000002b }, + { AR5K_BB_GAIN(42), 0x0000002b }, + { AR5K_BB_GAIN(43), 0x0000002b }, + { AR5K_BB_GAIN(44), 0x0000002b }, + { AR5K_BB_GAIN(45), 0x0000002b }, + { AR5K_BB_GAIN(46), 0x0000002b }, + { AR5K_BB_GAIN(47), 0x0000002b }, + { AR5K_BB_GAIN(48), 0x0000002b }, + { AR5K_BB_GAIN(49), 0x0000002b }, + { AR5K_BB_GAIN(50), 0x0000002b }, + { AR5K_BB_GAIN(51), 0x0000002b }, + { AR5K_BB_GAIN(52), 0x0000002b }, + { AR5K_BB_GAIN(53), 0x0000002b }, + { AR5K_BB_GAIN(54), 0x0000002b }, + { AR5K_BB_GAIN(55), 0x0000002b }, + { AR5K_BB_GAIN(56), 0x0000002b }, + { AR5K_BB_GAIN(57), 0x0000002b }, + { AR5K_BB_GAIN(58), 0x0000002b }, + { AR5K_BB_GAIN(59), 0x0000002b }, + { AR5K_BB_GAIN(60), 0x0000002b }, + { AR5K_BB_GAIN(61), 0x0000002b }, + { AR5K_BB_GAIN(62), 0x00000002 }, + { AR5K_BB_GAIN(63), 0x00000016 }, +}; + +/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414+) */ +static const struct ath5k_ini rf5112_ini_bbgain[] = { + { AR5K_BB_GAIN(0), 0x00000000 }, + { AR5K_BB_GAIN(1), 0x00000001 }, + { AR5K_BB_GAIN(2), 0x00000002 }, + { AR5K_BB_GAIN(3), 0x00000003 }, + { AR5K_BB_GAIN(4), 0x00000004 }, + { AR5K_BB_GAIN(5), 0x00000005 }, + { AR5K_BB_GAIN(6), 0x00000008 }, + { AR5K_BB_GAIN(7), 0x00000009 }, + { AR5K_BB_GAIN(8), 0x0000000a }, + { AR5K_BB_GAIN(9), 0x0000000b }, + { AR5K_BB_GAIN(10), 0x0000000c }, + { AR5K_BB_GAIN(11), 0x0000000d }, + { AR5K_BB_GAIN(12), 0x00000010 }, + { AR5K_BB_GAIN(13), 0x00000011 }, + { AR5K_BB_GAIN(14), 0x00000012 }, + { AR5K_BB_GAIN(15), 0x00000013 }, + { AR5K_BB_GAIN(16), 0x00000014 }, + { AR5K_BB_GAIN(17), 0x00000015 }, + { AR5K_BB_GAIN(18), 0x00000018 }, + { AR5K_BB_GAIN(19), 0x00000019 }, + { AR5K_BB_GAIN(20), 0x0000001a }, + { AR5K_BB_GAIN(21), 0x0000001b }, + { AR5K_BB_GAIN(22), 0x0000001c }, + { AR5K_BB_GAIN(23), 0x0000001d }, + { AR5K_BB_GAIN(24), 0x00000020 }, + { AR5K_BB_GAIN(25), 0x00000021 }, + { AR5K_BB_GAIN(26), 0x00000022 }, + { AR5K_BB_GAIN(27), 0x00000023 }, + { AR5K_BB_GAIN(28), 0x00000024 }, + { AR5K_BB_GAIN(29), 0x00000025 }, + { AR5K_BB_GAIN(30), 0x00000028 }, + { AR5K_BB_GAIN(31), 0x00000029 }, + { AR5K_BB_GAIN(32), 0x0000002a }, + { AR5K_BB_GAIN(33), 0x0000002b }, + { AR5K_BB_GAIN(34), 0x0000002c }, + { AR5K_BB_GAIN(35), 0x0000002d }, + { AR5K_BB_GAIN(36), 0x00000030 }, + { AR5K_BB_GAIN(37), 0x00000031 }, + { AR5K_BB_GAIN(38), 0x00000032 }, + { AR5K_BB_GAIN(39), 0x00000033 }, + { AR5K_BB_GAIN(40), 0x00000034 }, + { AR5K_BB_GAIN(41), 0x00000035 }, + { AR5K_BB_GAIN(42), 0x00000035 }, + { AR5K_BB_GAIN(43), 0x00000035 }, + { AR5K_BB_GAIN(44), 0x00000035 }, + { AR5K_BB_GAIN(45), 0x00000035 }, + { AR5K_BB_GAIN(46), 0x00000035 }, + { AR5K_BB_GAIN(47), 0x00000035 }, + { AR5K_BB_GAIN(48), 0x00000035 }, + { AR5K_BB_GAIN(49), 0x00000035 }, + { AR5K_BB_GAIN(50), 0x00000035 }, + { AR5K_BB_GAIN(51), 0x00000035 }, + { AR5K_BB_GAIN(52), 0x00000035 }, + { AR5K_BB_GAIN(53), 0x00000035 }, + { AR5K_BB_GAIN(54), 0x00000035 }, + { AR5K_BB_GAIN(55), 0x00000035 }, + { AR5K_BB_GAIN(56), 0x00000035 }, + { AR5K_BB_GAIN(57), 0x00000035 }, + { AR5K_BB_GAIN(58), 0x00000035 }, + { AR5K_BB_GAIN(59), 0x00000035 }, + { AR5K_BB_GAIN(60), 0x00000035 }, + { AR5K_BB_GAIN(61), 0x00000035 }, + { AR5K_BB_GAIN(62), 0x00000010 }, + { AR5K_BB_GAIN(63), 0x0000001a }, +}; + + +/* + * Write initial register dump + */ +static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, + const struct ath5k_ini *ini_regs, bool change_channel) +{ + unsigned int i; + + /* Write initial registers */ + for (i = 0; i < size; i++) { + /* On channel change there is + * no need to mess with PCU */ + if (change_channel && + ini_regs[i].ini_register >= AR5K_PCU_MIN && + ini_regs[i].ini_register <= AR5K_PCU_MAX) + continue; + + switch (ini_regs[i].ini_mode) { + case AR5K_INI_READ: + /* Cleared on read */ + ath5k_hw_reg_read(ah, ini_regs[i].ini_register); + break; + case AR5K_INI_WRITE: + default: + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, ini_regs[i].ini_value, + ini_regs[i].ini_register); + } + } +} + +static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, + unsigned int size, const struct ath5k_ini_mode *ini_mode, + u8 mode) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode], + (u32)ini_mode[i].mode_register); + } + +} + +int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) +{ + /* + * Write initial register settings + */ + + /* For AR5212 and combatible */ + if (ah->ah_version == AR5K_AR5212) { + + /* First set of mode-specific settings */ + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(ar5212_ini_mode_start), + ar5212_ini_mode_start, mode); + + /* + * Write initial settings common for all modes + */ + ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start), + ar5212_ini_common_start, change_channel); + + /* Second set of mode-specific settings */ + switch (ah->ah_radio) { + case AR5K_RF5111: + + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(rf5111_ini_mode_end), + rf5111_ini_mode_end, mode); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5111_ini_common_end), + rf5111_ini_common_end, change_channel); + + /* Baseband gain table */ + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5111_ini_bbgain), + rf5111_ini_bbgain, change_channel); + + break; + case AR5K_RF5112: + + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(rf5112_ini_mode_end), + rf5112_ini_mode_end, mode); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_common_end), + rf5112_ini_common_end, change_channel); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_bbgain), + rf5112_ini_bbgain, change_channel); + + break; + case AR5K_RF5413: + + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(rf5413_ini_mode_end), + rf5413_ini_mode_end, mode); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5413_ini_common_end), + rf5413_ini_common_end, change_channel); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_bbgain), + rf5112_ini_bbgain, change_channel); + + break; + case AR5K_RF2316: + case AR5K_RF2413: + + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(rf2413_ini_mode_end), + rf2413_ini_mode_end, mode); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf2413_ini_common_end), + rf2413_ini_common_end, change_channel); + + /* Override settings from rf2413_ini_common_end */ + if (ah->ah_radio == AR5K_RF2316) { + ath5k_hw_reg_write(ah, 0x00004000, + AR5K_PHY_AGC); + ath5k_hw_reg_write(ah, 0x081b7caa, + 0xa274); + } + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_bbgain), + rf5112_ini_bbgain, change_channel); + break; + case AR5K_RF2317: + case AR5K_RF2425: + + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(rf2425_ini_mode_end), + rf2425_ini_mode_end, mode); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf2425_ini_common_end), + rf2425_ini_common_end, change_channel); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_bbgain), + rf5112_ini_bbgain, change_channel); + break; + default: + return -EINVAL; + + } + + /* For AR5211 */ + } else if (ah->ah_version == AR5K_AR5211) { + + /* AR5K_MODE_11B */ + if (mode > 2) { + ATH5K_ERR(ah->ah_sc, + "unsupported channel mode: %d\n", mode); + return -EINVAL; + } + + /* Mode-specific settings */ + ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode), + ar5211_ini_mode, mode); + + /* + * Write initial settings common for all modes + */ + ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini), + ar5211_ini, change_channel); + + /* AR5211 only comes with 5111 */ + + /* Baseband gain table */ + ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain), + rf5111_ini_bbgain, change_channel); + /* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */ + } else if (ah->ah_version == AR5K_AR5210) { + ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini), + ar5210_ini, change_channel); + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c new file mode 100644 index 0000000..19555fb --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2004-2005 Atheros Communications, Inc. + * Copyright (c) 2007 Jiri Slaby + * Copyright (c) 2009 Bob Copeland + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +#include +#include "ath5k.h" +#include "base.h" + +#define ATH_SDEVICE(subv,subd) \ + .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ + .subvendor = (subv), .subdevice = (subd) + +#define ATH_LED(pin,polarity) .driver_data = (((pin) << 8) | (polarity)) +#define ATH_PIN(data) ((data) >> 8) +#define ATH_POLARITY(data) ((data) & 0xff) + +/* Devices we match on for LED config info (typically laptops) */ +static const struct pci_device_id ath5k_led_devices[] = { + /* IBM-specific AR5212 */ + { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, + /* AR5211 */ + { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) }, + /* HP Compaq nc6xx, nc4000, nx6000 */ + { ATH_SDEVICE(PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID), ATH_LED(1, 1) }, + /* Acer Aspire One A150 (maximlevitsky@gmail.com) */ + { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe008), ATH_LED(3, 0) }, + /* Acer Ferrari 5000 (russ.dill@gmail.com) */ + { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) }, + /* E-machines E510 (tuliom@gmail.com) */ + { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) }, + /* Acer Extensa 5620z (nekoreeve@gmail.com) */ + { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) }, + { } +}; + +void ath5k_led_enable(struct ath5k_softc *sc) +{ + if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { + ath5k_hw_set_gpio_output(sc->ah, sc->led_pin); + ath5k_led_off(sc); + } +} + +void ath5k_led_on(struct ath5k_softc *sc) +{ + if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) + return; + ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on); +} + +void ath5k_led_off(struct ath5k_softc *sc) +{ + if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) + return; + ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on); +} + +static void +ath5k_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) +{ + struct ath5k_led *led = container_of(led_dev, struct ath5k_led, + led_dev); + + if (brightness == LED_OFF) + ath5k_led_off(led->sc); + else + ath5k_led_on(led->sc); +} + +static int +ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led, + const char *name, char *trigger) +{ + int err; + + led->sc = sc; + strncpy(led->name, name, sizeof(led->name)); + led->led_dev.name = led->name; + led->led_dev.default_trigger = trigger; + led->led_dev.brightness_set = ath5k_led_brightness_set; + + err = led_classdev_register(&sc->pdev->dev, &led->led_dev); + if (err) { + ATH5K_WARN(sc, "could not register LED %s\n", name); + led->sc = NULL; + } + return err; +} + +static void +ath5k_unregister_led(struct ath5k_led *led) +{ + if (!led->sc) + return; + led_classdev_unregister(&led->led_dev); + ath5k_led_off(led->sc); + led->sc = NULL; +} + +void ath5k_unregister_leds(struct ath5k_softc *sc) +{ + ath5k_unregister_led(&sc->rx_led); + ath5k_unregister_led(&sc->tx_led); +} + +int ath5k_init_leds(struct ath5k_softc *sc) +{ + int ret = 0; + struct ieee80211_hw *hw = sc->hw; + struct pci_dev *pdev = sc->pdev; + char name[ATH5K_LED_MAX_NAME_LEN + 1]; + const struct pci_device_id *match; + + match = pci_match_id(&ath5k_led_devices[0], pdev); + if (match) { + __set_bit(ATH_STAT_LEDSOFT, sc->status); + sc->led_pin = ATH_PIN(match->driver_data); + sc->led_on = ATH_POLARITY(match->driver_data); + } + + if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) + goto out; + + ath5k_led_enable(sc); + + snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy)); + ret = ath5k_register_led(sc, &sc->rx_led, name, + ieee80211_get_rx_led_name(hw)); + if (ret) + goto out; + + snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy)); + ret = ath5k_register_led(sc, &sc->tx_led, name, + ieee80211_get_tx_led_name(hw)); +out: + return ret; +} + diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c new file mode 100644 index 0000000..55122f1 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -0,0 +1,1174 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Matthew W. S. Bell + * Copyright (c) 2007-2008 Luis Rodriguez + * Copyright (c) 2007-2008 Pavel Roskin + * Copyright (c) 2007-2008 Jiri Slaby + * + * 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; + + + /* Preserve rest settings */ + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP + | AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? + (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 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_KEYSRCH_MODE; + beacon_reg |= AR5K_BCR_ADHOC; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); + break; + + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; + beacon_reg |= AR5K_BCR_AP; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); + break; + + case NL80211_IFTYPE_STATION: + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_PWR_SV : 0); + case NL80211_IFTYPE_MONITOR: + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (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); + } + + /* TODO: Handle ANI stats */ +} + +/** + * 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; + u32 pcu_reg; + + ATH5K_TRACE(ah->ah_sc); + /* Set new station ID */ + memcpy(ah->ah_sta_id, mac, ETH_ALEN); + + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + + 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, pcu_reg | 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, AR5K_LOW_ID(ah->ah_bssid_mask), + AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), + 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); + + /* Cache bssid mask so that we can restore it + * on reset */ + memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); + 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 (phy error reporting) */ + 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_set_tsf64 - Set a new 64bit TSF + * + * @ah: The &struct ath5k_hw + * @tsf64: The new 64bit TSF + * + * Sets the new TSF + */ +void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) +{ + ATH5K_TRACE(ah->ah_sc); + + ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32); + ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32); +} + +/** + * 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_MONITOR: + case NL80211_IFTYPE_STATION: + /* In STA mode timer1 is used as next wakeup + * timer and timer2 as next CFP duration start + * timer. Both in 1/8TUs. */ + /* TODO: PCF handling */ + if (ah->ah_version == AR5K_AR5210) { + timer1 = 0xffffffff; + timer2 = 0xffffffff; + } else { + timer1 = 0x0000ffff; + timer2 = 0x0007ffff; + } + /* Mark associated AP as PCF incapable for now */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); + break; + case NL80211_IFTYPE_ADHOC: + AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); + default: + /* On non-STA modes timer1 is used as next DMA + * beacon alert (DBA) timer and timer2 as next + * software beacon alert. Both in 1/8TUs. */ + timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; + timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; + break; + } + + /* Timer3 marks the end of our ATIM window + * a zero length window is not allowed because + * we 'll get no beacons */ + timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); + + /* + * Set the beacon register and enable all timers. + */ + /* When in AP mode zero timer0 to start TSF */ + if (ah->ah_op_mode == NL80211_IFTYPE_AP) + ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); + else + 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); + + /* Force a TSF reset if requested and enable beacons */ + if (interval & AR5K_BEACON_RESET_TSF) + ath5k_hw_reset_tsf(ah); + + ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | + AR5K_BEACON_ENABLE), + AR5K_BEACON); + + /* Flush any pending BMISS interrupts on ISR by + * performing a clear-on-write operation on PISR + * register for the BMISS bit (writing a bit on + * ISR togles a reset for that bit and leaves + * the rest bits intact) */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); + else + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); + + /* TODO: Set enchanced sleep registers on AR5212 + * based on vif->bss_conf params, until then + * disable power save reporting.*/ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); + +} + +#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, type; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); + + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + + /* Reset associated MIC entry if TKIP + * is enabled located at offset (entry + 64) */ + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); + for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) + ath5k_hw_reg_write(ah, 0, + AR5K_KEYTABLE_OFF(micentry, 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)); + + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + } + } + + 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; +} + +static +int ath5k_keycache_type(const struct ieee80211_key_conf *key) +{ + switch (key->alg) { + case ALG_TKIP: + return AR5K_KEYTABLE_TYPE_TKIP; + case ALG_CCMP: + return AR5K_KEYTABLE_TYPE_CCM; + case ALG_WEP: + if (key->keylen == LEN_WEP40) + return AR5K_KEYTABLE_TYPE_40; + else if (key->keylen == LEN_WEP104) + return AR5K_KEYTABLE_TYPE_104; + return -EINVAL; + default: + return -EINVAL; + } + return -EINVAL; +} + +/* + * 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; + int keylen; + __le32 key_v[5] = {}; + __le32 key0 = 0, key1 = 0; + __le32 *rxmic, *txmic; + int keytype; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; + bool is_tkip; + const u8 *key_ptr; + + ATH5K_TRACE(ah->ah_sc); + + is_tkip = (key->alg == ALG_TKIP); + + /* + * key->keylen comes in from mac80211 in bytes. + * TKIP is 128 bit + 128 bit mic + */ + keylen = (is_tkip) ? (128 / 8) : key->keylen; + + if (entry > AR5K_KEYTABLE_SIZE || + (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) + return -EOPNOTSUPP; + + if (unlikely(keylen > 16)) + return -EOPNOTSUPP; + + keytype = ath5k_keycache_type(key); + if (keytype < 0) + return keytype; + + /* + * each key block is 6 bytes wide, written as pairs of + * alternating 32 and 16 bit le values. + */ + key_ptr = key->key; + for (i = 0; keylen >= 6; keylen -= 6) { + memcpy(&key_v[i], key_ptr, 6); + i += 2; + key_ptr += 6; + } + if (keylen) + memcpy(&key_v[i], key_ptr, keylen); + + /* intentionally corrupt key until mic is installed */ + if (is_tkip) { + key0 = key_v[0] = ~key_v[0]; + key1 = key_v[1] = ~key_v[1]; + } + + 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)); + + if (is_tkip) { + /* Install rx/tx MIC */ + rxmic = (__le32 *) &key->key[16]; + txmic = (__le32 *) &key->key[24]; + + if (ah->ah_combined_mic) { + key_v[0] = rxmic[0]; + key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); + key_v[2] = rxmic[1]; + key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); + key_v[4] = txmic[1]; + } else { + key_v[0] = rxmic[0]; + key_v[1] = 0; + key_v[2] = rxmic[1]; + key_v[3] = 0; + key_v[4] = 0; + } + for (i = 0; i < ARRAY_SIZE(key_v); i++) + ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), + AR5K_KEYTABLE_OFF(micentry, i)); + + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); + + /* restore first 2 words of key */ + ath5k_hw_reg_write(ah, le32_to_cpu(~key0), + AR5K_KEYTABLE_OFF(entry, 0)); + ath5k_hw_reg_write(ah, le32_to_cpu(~key1), + AR5K_KEYTABLE_OFF(entry, 1)); + } + + 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 (!mac) { + 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/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c new file mode 100644 index 0000000..9e2faae --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -0,0 +1,2599 @@ +/* + * PHY functions + * + * Copyright (c) 2004-2007 Reyk Floeter + * Copyright (c) 2006-2009 Nick Kossifidis + * Copyright (c) 2007-2008 Jiri Slaby + * Copyright (c) 2008-2009 Felix Fietkau + * + * 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_PHY + +#include + +#include "ath5k.h" +#include "reg.h" +#include "base.h" +#include "rfbuffer.h" +#include "rfgain.h" + +/* + * Used to modify RF Banks before writing them to AR5K_RF_BUFFER + */ +static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, + const struct ath5k_rf_reg *rf_regs, + u32 val, u8 reg_id, bool set) +{ + const struct ath5k_rf_reg *rfreg = NULL; + u8 offset, bank, num_bits, col, position; + u16 entry; + u32 mask, data, last_bit, bits_shifted, first_bit; + u32 *rfb; + s32 bits_left; + int i; + + data = 0; + rfb = ah->ah_rf_banks; + + for (i = 0; i < ah->ah_rf_regs_count; i++) { + if (rf_regs[i].index == reg_id) { + rfreg = &rf_regs[i]; + break; + } + } + + if (rfb == NULL || rfreg == NULL) { + ATH5K_PRINTF("Rf register not found!\n"); + /* should not happen */ + return 0; + } + + bank = rfreg->bank; + num_bits = rfreg->field.len; + first_bit = rfreg->field.pos; + col = rfreg->field.col; + + /* first_bit is an offset from bank's + * start. Since we have all banks on + * the same array, we use this offset + * to mark each bank's start */ + offset = ah->ah_offset[bank]; + + /* Boundary check */ + if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) { + ATH5K_PRINTF("invalid values at offset %u\n", offset); + return 0; + } + + entry = ((first_bit - 1) / 8) + offset; + position = (first_bit - 1) % 8; + + if (set) + data = ath5k_hw_bitswap(val, num_bits); + + for (bits_shifted = 0, bits_left = num_bits; bits_left > 0; + position = 0, entry++) { + + last_bit = (position + bits_left > 8) ? 8 : + position + bits_left; + + mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) << + (col * 8); + + if (set) { + rfb[entry] &= ~mask; + rfb[entry] |= ((data << position) << (col * 8)) & mask; + data >>= (8 - position); + } else { + data |= (((rfb[entry] & mask) >> (col * 8)) >> position) + << bits_shifted; + bits_shifted += last_bit - position; + } + + bits_left -= 8 - position; + } + + data = set ? 1 : ath5k_hw_bitswap(data, num_bits); + + return data; +} + +/**********************\ +* RF Gain optimization * +\**********************/ + +/* + * This code is used to optimize rf gain on different environments + * (temprature mostly) based on feedback from a power detector. + * + * It's only used on RF5111 and RF5112, later RF chips seem to have + * auto adjustment on hw -notice they have a much smaller BANK 7 and + * no gain optimization ladder-. + * + * For more infos check out this patent doc + * http://www.freepatentsonline.com/7400691.html + * + * This paper describes power drops as seen on the receiver due to + * probe packets + * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues + * %20of%20Power%20Control.pdf + * + * And this is the MadWiFi bug entry related to the above + * http://madwifi-project.org/ticket/1659 + * with various measurements and diagrams + * + * TODO: Deal with power drops due to probes by setting an apropriate + * tx power on the probe packets ! Make this part of the calibration process. + */ + +/* Initialize ah_gain durring attach */ +int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) +{ + /* Initialize the gain optimization values */ + switch (ah->ah_radio) { + case AR5K_RF5111: + ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; + ah->ah_gain.g_low = 20; + ah->ah_gain.g_high = 35; + ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + break; + case AR5K_RF5112: + ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; + ah->ah_gain.g_low = 20; + ah->ah_gain.g_high = 85; + ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* Schedule a gain probe check on the next transmited packet. + * That means our next packet is going to be sent with lower + * tx power and a Peak to Average Power Detector (PAPD) will try + * to measure the gain. + * + * TODO: Use propper tx power setting for the probe packet so + * that we don't observe a serious power drop on the receiver + * + * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) + * just after we enable the probe so that we don't mess with + * standard traffic ? Maybe it's time to use sw interrupts and + * a probe tasklet !!! + */ +static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) +{ + + /* Skip if gain calibration is inactive or + * we already handle a probe request */ + if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE) + return; + + /* Send the packet with 2dB below max power as + * patent doc suggest */ + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4, + AR5K_PHY_PAPD_PROBE_TXPOWER) | + AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); + + ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED; + +} + +/* Calculate gain_F measurement correction + * based on the current step for RF5112 rev. 2 */ +static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) +{ + u32 mix, step; + u32 *rf; + const struct ath5k_gain_opt *go; + const struct ath5k_gain_opt_step *g_step; + const struct ath5k_rf_reg *rf_regs; + + /* Only RF5112 Rev. 2 supports it */ + if ((ah->ah_radio != AR5K_RF5112) || + (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A)) + return 0; + + go = &rfgain_opt_5112; + rf_regs = rf_regs_5112a; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); + + g_step = &go->go_step[ah->ah_gain.g_step_idx]; + + if (ah->ah_rf_banks == NULL) + return 0; + + rf = ah->ah_rf_banks; + ah->ah_gain.g_f_corr = 0; + + /* No VGA (Variable Gain Amplifier) override, skip */ + if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, false) != 1) + return 0; + + /* Mix gain stepping */ + step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, false); + + /* Mix gain override */ + mix = g_step->gos_param[0]; + + switch (mix) { + case 3: + ah->ah_gain.g_f_corr = step * 2; + break; + case 2: + ah->ah_gain.g_f_corr = (step - 5) * 2; + break; + case 1: + ah->ah_gain.g_f_corr = step; + break; + default: + ah->ah_gain.g_f_corr = 0; + break; + } + + return ah->ah_gain.g_f_corr; +} + +/* Check if current gain_F measurement is in the range of our + * power detector windows. If we get a measurement outside range + * we know it's not accurate (detectors can't measure anything outside + * their detection window) so we must ignore it */ +static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) +{ + const struct ath5k_rf_reg *rf_regs; + u32 step, mix_ovr, level[4]; + u32 *rf; + + if (ah->ah_rf_banks == NULL) + return false; + + rf = ah->ah_rf_banks; + + if (ah->ah_radio == AR5K_RF5111) { + + rf_regs = rf_regs_5111; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); + + step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP, + false); + + level[0] = 0; + level[1] = (step == 63) ? 50 : step + 4; + level[2] = (step != 63) ? 64 : level[0]; + level[3] = level[2] + 50 ; + + ah->ah_gain.g_high = level[3] - + (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); + ah->ah_gain.g_low = level[0] + + (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); + } else { + + rf_regs = rf_regs_5112; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); + + mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, + false); + + level[0] = level[2] = 0; + + if (mix_ovr == 1) { + level[1] = level[3] = 83; + } else { + level[1] = level[3] = 107; + ah->ah_gain.g_high = 55; + } + } + + return (ah->ah_gain.g_current >= level[0] && + ah->ah_gain.g_current <= level[1]) || + (ah->ah_gain.g_current >= level[2] && + ah->ah_gain.g_current <= level[3]); +} + +/* Perform gain_F adjustment by choosing the right set + * of parameters from rf gain optimization ladder */ +static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) +{ + const struct ath5k_gain_opt *go; + const struct ath5k_gain_opt_step *g_step; + int ret = 0; + + switch (ah->ah_radio) { + case AR5K_RF5111: + go = &rfgain_opt_5111; + break; + case AR5K_RF5112: + go = &rfgain_opt_5112; + break; + default: + return 0; + } + + g_step = &go->go_step[ah->ah_gain.g_step_idx]; + + if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { + + /* Reached maximum */ + if (ah->ah_gain.g_step_idx == 0) + return -1; + + for (ah->ah_gain.g_target = ah->ah_gain.g_current; + ah->ah_gain.g_target >= ah->ah_gain.g_high && + ah->ah_gain.g_step_idx > 0; + g_step = &go->go_step[ah->ah_gain.g_step_idx]) + ah->ah_gain.g_target -= 2 * + (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - + g_step->gos_gain); + + ret = 1; + goto done; + } + + if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { + + /* Reached minimum */ + if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) + return -2; + + for (ah->ah_gain.g_target = ah->ah_gain.g_current; + ah->ah_gain.g_target <= ah->ah_gain.g_low && + ah->ah_gain.g_step_idx < go->go_steps_count-1; + g_step = &go->go_step[ah->ah_gain.g_step_idx]) + ah->ah_gain.g_target -= 2 * + (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - + g_step->gos_gain); + + ret = 2; + goto done; + } + +done: + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "ret %d, gain step %u, current gain %u, target gain %u\n", + ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current, + ah->ah_gain.g_target); + + return ret; +} + +/* Main callback for thermal rf gain calibration engine + * Check for a new gain reading and schedule an adjustment + * if needed. + * + * TODO: Use sw interrupt to schedule reset if gain_F needs + * adjustment */ +enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) +{ + u32 data, type; + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_rf_banks == NULL || + ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE) + return AR5K_RFGAIN_INACTIVE; + + /* No check requested, either engine is inactive + * or an adjustment is already requested */ + if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED) + goto done; + + /* Read the PAPD (Peak to Average Power Detector) + * register */ + data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); + + /* No probe is scheduled, read gain_F measurement */ + if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { + ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; + type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); + + /* If tx packet is CCK correct the gain_F measurement + * by cck ofdm gain delta */ + if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) { + if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) + ah->ah_gain.g_current += + ee->ee_cck_ofdm_gain_delta; + else + ah->ah_gain.g_current += + AR5K_GAIN_CCK_PROBE_CORR; + } + + /* Further correct gain_F measurement for + * RF5112A radios */ + if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { + ath5k_hw_rf_gainf_corr(ah); + ah->ah_gain.g_current = + ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? + (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : + 0; + } + + /* Check if measurement is ok and if we need + * to adjust gain, schedule a gain adjustment, + * else switch back to the acive state */ + if (ath5k_hw_rf_check_gainf_readback(ah) && + AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && + ath5k_hw_rf_gainf_adjust(ah)) { + ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE; + } else { + ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + } + } + +done: + return ah->ah_gain.g_state; +} + +/* Write initial rf gain table to set the RF sensitivity + * this one works on all RF chips and has nothing to do + * with gain_F calibration */ +int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq) +{ + const struct ath5k_ini_rfgain *ath5k_rfg; + unsigned int i, size; + + switch (ah->ah_radio) { + case AR5K_RF5111: + ath5k_rfg = rfgain_5111; + size = ARRAY_SIZE(rfgain_5111); + break; + case AR5K_RF5112: + ath5k_rfg = rfgain_5112; + size = ARRAY_SIZE(rfgain_5112); + break; + case AR5K_RF2413: + ath5k_rfg = rfgain_2413; + size = ARRAY_SIZE(rfgain_2413); + break; + case AR5K_RF2316: + ath5k_rfg = rfgain_2316; + size = ARRAY_SIZE(rfgain_2316); + break; + case AR5K_RF5413: + ath5k_rfg = rfgain_5413; + size = ARRAY_SIZE(rfgain_5413); + break; + case AR5K_RF2317: + case AR5K_RF2425: + ath5k_rfg = rfgain_2425; + size = ARRAY_SIZE(rfgain_2425); + break; + default: + return -EINVAL; + } + + switch (freq) { + case AR5K_INI_RFGAIN_2GHZ: + case AR5K_INI_RFGAIN_5GHZ: + break; + default: + return -EINVAL; + } + + for (i = 0; i < size; i++) { + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq], + (u32)ath5k_rfg[i].rfg_register); + } + + return 0; +} + + + +/********************\ +* RF Registers setup * +\********************/ + + +/* + * Setup RF registers by writing rf buffer on hw + */ +int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, + unsigned int mode) +{ + const struct ath5k_rf_reg *rf_regs; + const struct ath5k_ini_rfbuffer *ini_rfb; + const struct ath5k_gain_opt *go = NULL; + const struct ath5k_gain_opt_step *g_step; + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u8 ee_mode = 0; + u32 *rfb; + int i, obdb = -1, bank = -1; + + switch (ah->ah_radio) { + case AR5K_RF5111: + rf_regs = rf_regs_5111; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); + ini_rfb = rfb_5111; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111); + go = &rfgain_opt_5111; + break; + case AR5K_RF5112: + if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { + rf_regs = rf_regs_5112a; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); + ini_rfb = rfb_5112a; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a); + } else { + rf_regs = rf_regs_5112; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); + ini_rfb = rfb_5112; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112); + } + go = &rfgain_opt_5112; + break; + case AR5K_RF2413: + rf_regs = rf_regs_2413; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413); + ini_rfb = rfb_2413; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413); + break; + case AR5K_RF2316: + rf_regs = rf_regs_2316; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316); + ini_rfb = rfb_2316; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316); + break; + case AR5K_RF5413: + rf_regs = rf_regs_5413; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413); + ini_rfb = rfb_5413; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413); + break; + case AR5K_RF2317: + rf_regs = rf_regs_2425; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); + ini_rfb = rfb_2317; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317); + break; + case AR5K_RF2425: + rf_regs = rf_regs_2425; + ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); + if (ah->ah_mac_srev < AR5K_SREV_AR2417) { + ini_rfb = rfb_2425; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425); + } else { + ini_rfb = rfb_2417; + ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417); + } + break; + default: + return -EINVAL; + } + + /* If it's the first time we set rf buffer, allocate + * ah->ah_rf_banks based on ah->ah_rf_banks_size + * we set above */ + if (ah->ah_rf_banks == NULL) { + ah->ah_rf_banks = kmalloc(sizeof(u32) * ah->ah_rf_banks_size, + GFP_KERNEL); + if (ah->ah_rf_banks == NULL) { + ATH5K_ERR(ah->ah_sc, "out of memory\n"); + return -ENOMEM; + } + } + + /* Copy values to modify them */ + rfb = ah->ah_rf_banks; + + for (i = 0; i < ah->ah_rf_banks_size; i++) { + if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) { + ATH5K_ERR(ah->ah_sc, "invalid bank\n"); + return -EINVAL; + } + + /* Bank changed, write down the offset */ + if (bank != ini_rfb[i].rfb_bank) { + bank = ini_rfb[i].rfb_bank; + ah->ah_offset[bank] = i; + } + + rfb[i] = ini_rfb[i].rfb_mode_data[mode]; + } + + /* Set Output and Driver bias current (OB/DB) */ + if (channel->hw_value & CHANNEL_2GHZ) { + + if (channel->hw_value & CHANNEL_CCK) + ee_mode = AR5K_EEPROM_MODE_11B; + else + ee_mode = AR5K_EEPROM_MODE_11G; + + /* For RF511X/RF211X combination we + * use b_OB and b_DB parameters stored + * in eeprom on ee->ee_ob[ee_mode][0] + * + * For all other chips we use OB/DB for 2Ghz + * stored in the b/g modal section just like + * 802.11a on ee->ee_ob[ee_mode][1] */ + if ((ah->ah_radio == AR5K_RF5111) || + (ah->ah_radio == AR5K_RF5112)) + obdb = 0; + else + obdb = 1; + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], + AR5K_RF_OB_2GHZ, true); + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], + AR5K_RF_DB_2GHZ, true); + + /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ + } else if ((channel->hw_value & CHANNEL_5GHZ) || + (ah->ah_radio == AR5K_RF5111)) { + + /* For 11a, Turbo and XR we need to choose + * OB/DB based on frequency range */ + ee_mode = AR5K_EEPROM_MODE_11A; + obdb = channel->center_freq >= 5725 ? 3 : + (channel->center_freq >= 5500 ? 2 : + (channel->center_freq >= 5260 ? 1 : + (channel->center_freq > 4000 ? 0 : -1))); + + if (obdb < 0) + return -EINVAL; + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], + AR5K_RF_OB_5GHZ, true); + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], + AR5K_RF_DB_5GHZ, true); + } + + g_step = &go->go_step[ah->ah_gain.g_step_idx]; + + /* Bank Modifications (chip-specific) */ + if (ah->ah_radio == AR5K_RF5111) { + + /* Set gain_F settings according to current step */ + if (channel->hw_value & CHANNEL_OFDM) { + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, + AR5K_PHY_FRAME_CTL_TX_CLIP, + g_step->gos_param[0]); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], + AR5K_RF_PWD_90, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], + AR5K_RF_PWD_84, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], + AR5K_RF_RFGAIN_SEL, true); + + /* We programmed gain_F parameters, switch back + * to active state */ + ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + + } + + /* Bank 6/7 setup */ + + ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode], + AR5K_RF_PWD_XPD, true); + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode], + AR5K_RF_XPD_GAIN, true); + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], + AR5K_RF_GAIN_I, true); + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], + AR5K_RF_PLO_SEL, true); + + /* TODO: Half/quarter channel support */ + } + + if (ah->ah_radio == AR5K_RF5112) { + + /* Set gain_F settings according to current step */ + if (channel->hw_value & CHANNEL_OFDM) { + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0], + AR5K_RF_MIXGAIN_OVR, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], + AR5K_RF_PWD_138, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], + AR5K_RF_PWD_137, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], + AR5K_RF_PWD_136, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4], + AR5K_RF_PWD_132, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5], + AR5K_RF_PWD_131, true); + + ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6], + AR5K_RF_PWD_130, true); + + /* We programmed gain_F parameters, switch back + * to active state */ + ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; + } + + /* Bank 6/7 setup */ + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], + AR5K_RF_XPD_SEL, true); + + if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { + /* Rev. 1 supports only one xpd */ + ath5k_hw_rfb_op(ah, rf_regs, + ee->ee_x_gain[ee_mode], + AR5K_RF_XPD_GAIN, true); + + } else { + /* TODO: Set high and low gain bits */ + ath5k_hw_rfb_op(ah, rf_regs, + ee->ee_x_gain[ee_mode], + AR5K_RF_PD_GAIN_LO, true); + ath5k_hw_rfb_op(ah, rf_regs, + ee->ee_x_gain[ee_mode], + AR5K_RF_PD_GAIN_HI, true); + + /* Lower synth voltage on Rev 2 */ + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_HIGH_VC_CP, true); + + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_MID_VC_CP, true); + + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_LOW_VC_CP, true); + + ath5k_hw_rfb_op(ah, rf_regs, 2, + AR5K_RF_PUSH_UP, true); + + /* Decrease power consumption on 5213+ BaseBand */ + if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_PAD2GND, true); + + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_XB2_LVL, true); + + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_XB5_LVL, true); + + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_PWD_167, true); + + ath5k_hw_rfb_op(ah, rf_regs, 1, + AR5K_RF_PWD_166, true); + } + } + + ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], + AR5K_RF_GAIN_I, true); + + /* TODO: Half/quarter channel support */ + + } + + if (ah->ah_radio == AR5K_RF5413 && + channel->hw_value & CHANNEL_2GHZ) { + + ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE, + true); + + /* Set optimum value for early revisions (on pci-e chips) */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5424 && + ah->ah_mac_srev < AR5K_SREV_AR5413) + ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3), + AR5K_RF_PWD_ICLOBUF_2G, true); + + } + + /* Write RF banks on hw */ + for (i = 0; i < ah->ah_rf_banks_size; i++) { + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register); + } + + return 0; +} + + +/**************************\ + PHY/RF channel functions +\**************************/ + +/* + * Check if a channel is supported + */ +bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags) +{ + /* Check if the channel is in our supported range */ + if (flags & CHANNEL_2GHZ) { + if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && + (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) + return true; + } else if (flags & CHANNEL_5GHZ) + if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && + (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) + return true; + + return false; +} + +/* + * Convertion needed for RF5110 + */ +static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) +{ + u32 athchan; + + /* + * Convert IEEE channel/MHz to an internal channel value used + * by the AR5210 chipset. This has not been verified with + * newer chipsets like the AR5212A who have a completely + * different RF/PHY part. + */ + athchan = (ath5k_hw_bitswap( + (ieee80211_frequency_to_channel( + channel->center_freq) - 24) / 2, 5) + << 1) | (1 << 6) | 0x1; + return athchan; +} + +/* + * Set channel on RF5110 + */ +static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 data; + + /* + * Set the channel and wait + */ + data = ath5k_hw_rf5110_chan2athchan(channel); + ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); + ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); + mdelay(1); + + return 0; +} + +/* + * Convertion needed for 5111 + */ +static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, + struct ath5k_athchan_2ghz *athchan) +{ + int channel; + + /* Cast this value to catch negative channel numbers (>= -19) */ + channel = (int)ieee; + + /* + * Map 2GHz IEEE channel to 5GHz Atheros channel + */ + if (channel <= 13) { + athchan->a2_athchan = 115 + channel; + athchan->a2_flags = 0x46; + } else if (channel == 14) { + athchan->a2_athchan = 124; + athchan->a2_flags = 0x44; + } else if (channel >= 15 && channel <= 26) { + athchan->a2_athchan = ((channel - 14) * 4) + 132; + athchan->a2_flags = 0x46; + } else + return -EINVAL; + + return 0; +} + +/* + * Set channel on 5111 + */ +static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + struct ath5k_athchan_2ghz ath5k_channel_2ghz; + unsigned int ath5k_channel = + ieee80211_frequency_to_channel(channel->center_freq); + u32 data0, data1, clock; + int ret; + + /* + * Set the channel on the RF5111 radio + */ + data0 = data1 = 0; + + if (channel->hw_value & CHANNEL_2GHZ) { + /* Map 2GHz channel to 5GHz Atheros channel ID */ + ret = ath5k_hw_rf5111_chan2athchan( + ieee80211_frequency_to_channel(channel->center_freq), + &ath5k_channel_2ghz); + if (ret) + return ret; + + ath5k_channel = ath5k_channel_2ghz.a2_athchan; + data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff) + << 5) | (1 << 4); + } + + if (ath5k_channel < 145 || !(ath5k_channel & 1)) { + clock = 1; + data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) | + (clock << 1) | (1 << 10) | 1; + } else { + clock = 0; + data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff) + << 2) | (clock << 1) | (1 << 10) | 1; + } + + ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8), + AR5K_RF_BUFFER); + ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00), + AR5K_RF_BUFFER_CONTROL_3); + + return 0; +} + +/* + * Set channel on 5112 and newer + */ +static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 data, data0, data1, data2; + u16 c; + + data = data0 = data1 = data2 = 0; + c = channel->center_freq; + + if (c < 4800) { + if (!((c - 2224) % 5)) { + data0 = ((2 * (c - 704)) - 3040) / 10; + data1 = 1; + } else if (!((c - 2192) % 5)) { + data0 = ((2 * (c - 672)) - 3040) / 10; + data1 = 0; + } else + return -EINVAL; + + data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); + } else if ((c - (c % 5)) != 2 || c > 5435) { + if (!(c % 20) && c >= 5120) { + data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); + data2 = ath5k_hw_bitswap(3, 2); + } else if (!(c % 10)) { + data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); + data2 = ath5k_hw_bitswap(2, 2); + } else if (!(c % 5)) { + data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); + data2 = ath5k_hw_bitswap(1, 2); + } else + return -EINVAL; + } else { + data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data2 = ath5k_hw_bitswap(0, 2); + } + + data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001; + + ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); + ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); + + return 0; +} + +/* + * Set the channel on the RF2425 + */ +static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 data, data0, data2; + u16 c; + + data = data0 = data2 = 0; + c = channel->center_freq; + + if (c < 4800) { + data0 = ath5k_hw_bitswap((c - 2272), 8); + data2 = 0; + /* ? 5GHz ? */ + } else if ((c - (c % 5)) != 2 || c > 5435) { + if (!(c % 20) && c < 5120) + data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); + else if (!(c % 10)) + data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); + else if (!(c % 5)) + data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); + else + return -EINVAL; + data2 = ath5k_hw_bitswap(1, 2); + } else { + data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data2 = ath5k_hw_bitswap(0, 2); + } + + data = (data0 << 4) | data2 << 2 | 0x1001; + + ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); + ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); + + return 0; +} + +/* + * Set a channel on the radio chip + */ +int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) +{ + int ret; + /* + * Check bounds supported by the PHY (we don't care about regultory + * restrictions at this point). Note: hw_value already has the band + * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok() + * of the band by that */ + if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) { + ATH5K_ERR(ah->ah_sc, + "channel frequency (%u MHz) out of supported " + "band range\n", + channel->center_freq); + return -EINVAL; + } + + /* + * Set the channel and wait + */ + switch (ah->ah_radio) { + case AR5K_RF5110: + ret = ath5k_hw_rf5110_channel(ah, channel); + break; + case AR5K_RF5111: + ret = ath5k_hw_rf5111_channel(ah, channel); + break; + case AR5K_RF2425: + ret = ath5k_hw_rf2425_channel(ah, channel); + break; + default: + ret = ath5k_hw_rf5112_channel(ah, channel); + break; + } + + if (ret) + return ret; + + /* Set JAPAN setting for channel 14 */ + if (channel->center_freq == 2484) { + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, + AR5K_PHY_CCKTXCTL_JAPAN); + } else { + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, + AR5K_PHY_CCKTXCTL_WORLD); + } + + ah->ah_current_channel.center_freq = channel->center_freq; + ah->ah_current_channel.hw_value = channel->hw_value; + ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; + + return 0; +} + +/*****************\ + PHY calibration +\*****************/ + +/** + * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration + * + * @ah: struct ath5k_hw pointer we are operating on + * @freq: the channel frequency, just used for error logging + * + * This function performs a noise floor calibration of the PHY and waits for + * it to complete. Then the noise floor value is compared to some maximum + * noise floor we consider valid. + * + * Note that this is different from what the madwifi HAL does: it reads the + * noise floor and afterwards initiates the calibration. Since the noise floor + * calibration can take some time to finish, depending on the current channel + * use, that avoids the occasional timeout warnings we are seeing now. + * + * See the following link for an Atheros patent on noise floor calibration: + * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ + * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 + * + * XXX: Since during noise floor calibration antennas are detached according to + * the patent, we should stop tx queues here. + */ +int +ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) +{ + int ret; + unsigned int i; + s32 noise_floor; + + /* + * Enable noise floor calibration + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_NF); + + ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_NF, 0, false); + if (ret) { + ATH5K_ERR(ah->ah_sc, + "noise floor calibration timeout (%uMHz)\n", freq); + return -EAGAIN; + } + + /* Wait until the noise floor is calibrated and read the value */ + for (i = 20; i > 0; i--) { + mdelay(1); + noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); + noise_floor = AR5K_PHY_NF_RVAL(noise_floor); + if (noise_floor & AR5K_PHY_NF_ACTIVE) { + noise_floor = AR5K_PHY_NF_AVAL(noise_floor); + + if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) + break; + } + } + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "noise floor %d\n", noise_floor); + + if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { + ATH5K_ERR(ah->ah_sc, + "noise floor calibration failed (%uMHz)\n", freq); + return -EAGAIN; + } + + ah->ah_noise_floor = noise_floor; + + return 0; +} + +/* + * Perform a PHY calibration on RF5110 + * -Fix BPSK/QAM Constellation (I/Q correction) + * -Calculate Noise Floor + */ +static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 phy_sig, phy_agc, phy_sat, beacon; + int ret; + + /* + * Disable beacons and RX/TX queues, wait + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, + AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); + ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); + + mdelay(2); + + /* + * Set the channel (with AGC turned off) + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + udelay(10); + ret = ath5k_hw_channel(ah, channel); + + /* + * Activate PHY and wait + */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + mdelay(1); + + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + + if (ret) + return ret; + + /* + * Calibrate the radio chip + */ + + /* Remember normal state */ + phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG); + phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE); + phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT); + + /* Update radio registers */ + ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) | + AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG); + + ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI | + AR5K_PHY_AGCCOARSE_LO)) | + AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) | + AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE); + + ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT | + AR5K_PHY_ADCSAT_THR)) | + AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) | + AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT); + + udelay(20); + + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + udelay(10); + ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + + mdelay(1); + + /* + * Enable calibration and wait until completion + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL); + + ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL, 0, false); + + /* Reset to normal state */ + ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG); + ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE); + ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT); + + if (ret) { + ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", + channel->center_freq); + return ret; + } + + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + + /* + * Re-enable RX/TX and beacons + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, + AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210); + + return 0; +} + +/* + * Perform a PHY calibration on RF5111/5112 and newer chips + */ +static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 i_pwr, q_pwr; + s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; + int i; + ATH5K_TRACE(ah->ah_sc); + + if (!ah->ah_calibration || + ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) + goto done; + + /* Calibration has finished, get the results and re-run */ + for (i = 0; i <= 10; i++) { + iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); + i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); + q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); + } + + i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; + q_coffd = q_pwr >> 7; + + /* No correction */ + if (i_coffd == 0 || q_coffd == 0) + goto done; + + i_coff = ((-iq_corr) / i_coffd) & 0x3f; + + /* Boundary check */ + if (i_coff > 31) + i_coff = 31; + if (i_coff < -32) + i_coff = -32; + + q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f; + + /* Boundary check */ + if (q_coff > 15) + q_coff = 15; + if (q_coff < -16) + q_coff = -16; + + /* Commit new I/Q value */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | + ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); + + /* Re-enable calibration -if we don't we'll commit + * the same values again and again */ + 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); + +done: + + /* TODO: Separate noise floor calibration from I/Q calibration + * since noise floor calibration interrupts rx path while I/Q + * calibration doesn't. We don't need to run noise floor calibration + * as often as I/Q calibration.*/ + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + + /* Initiate a gain_F calibration */ + ath5k_hw_request_rfgain_probe(ah); + + return 0; +} + +/* + * Perform a PHY calibration + */ +int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + int ret; + + if (ah->ah_radio == AR5K_RF5110) + ret = ath5k_hw_rf5110_calibrate(ah, channel); + else + ret = ath5k_hw_rf511x_calibrate(ah, channel); + + return ret; +} + +int ath5k_hw_phy_disable(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + /*Just a try M.F.*/ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); + + return 0; +} + +/********************\ + Misc PHY functions +\********************/ + +/* + * Get the PHY Chip revision + */ +u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) +{ + unsigned int i; + u32 srev; + u16 ret; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Set the radio chip access register + */ + switch (chan) { + case CHANNEL_2GHZ: + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); + break; + case CHANNEL_5GHZ: + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + break; + default: + return 0; + } + + mdelay(2); + + /* ...wait until PHY is ready and read the selected radio revision */ + ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34)); + + for (i = 0; i < 8; i++) + ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); + + if (ah->ah_version == AR5K_AR5210) { + srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; + ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; + } else { + srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; + ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) | + ((srev & 0x0f) << 4), 8); + } + + /* Reset to the 5GHz mode */ + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + + return ret; +} + +void /*TODO:Boundary check*/ +ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant) +{ + ATH5K_TRACE(ah->ah_sc); + /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) + ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA); +} + +unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) + return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + + return false; /*XXX: What do we return for 5210 ?*/ +} + + +/****************\ +* TX power setup * +\****************/ + +/* + * Helper functions + */ + +/* + * Do linear interpolation between two given (x, y) points + */ +static s16 +ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, + s16 y_left, s16 y_right) +{ + s16 ratio, result; + + /* Avoid divide by zero and skip interpolation + * if we have the same point */ + if ((x_left == x_right) || (y_left == y_right)) + return y_left; + + /* + * Since we use ints and not fps, we need to scale up in + * order to get a sane ratio value (or else we 'll eg. get + * always 1 instead of 1.25, 1.75 etc). We scale up by 100 + * to have some accuracy both for 0.5 and 0.25 steps. + */ + ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left)); + + /* Now scale down to be in range */ + result = y_left + (ratio * (target - x_left) / 100); + + return result; +} + +/* + * Find vertical boundary (min pwr) for the linear PCDAC curve. + * + * Since we have the top of the curve and we draw the line below + * until we reach 1 (1 pcdac step) we need to know which point + * (x value) that is so that we don't go below y axis and have negative + * pcdac values when creating the curve, or fill the table with zeroes. + */ +static s16 +ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, + const s16 *pwrL, const s16 *pwrR) +{ + s8 tmp; + s16 min_pwrL, min_pwrR; + s16 pwr_i = pwrL[0]; + + do { + pwr_i--; + tmp = (s8) ath5k_get_interpolated_value(pwr_i, + pwrL[0], pwrL[1], + stepL[0], stepL[1]); + + } while (tmp > 1); + + min_pwrL = pwr_i; + + pwr_i = pwrR[0]; + do { + pwr_i--; + tmp = (s8) ath5k_get_interpolated_value(pwr_i, + pwrR[0], pwrR[1], + stepR[0], stepR[1]); + + } while (tmp > 1); + + min_pwrR = pwr_i; + + /* Keep the right boundary so that it works for both curves */ + return max(min_pwrL, min_pwrR); +} + +/* + * Interpolate (pwr,vpd) points to create a Power to PDADC or a + * Power to PCDAC curve. + * + * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC + * steps (offsets) on y axis. Power can go up to 31.5dB and max + * PCDAC/PDADC step for each curve is 64 but we can write more than + * one curves on hw so we can go up to 128 (which is the max step we + * can write on the final table). + * + * We write y values (PCDAC/PDADC steps) on hw. + */ +static void +ath5k_create_power_curve(s16 pmin, s16 pmax, + const s16 *pwr, const u8 *vpd, + u8 num_points, + u8 *vpd_table, u8 type) +{ + u8 idx[2] = { 0, 1 }; + s16 pwr_i = 2*pmin; + int i; + + if (num_points < 2) + return; + + /* We want the whole line, so adjust boundaries + * to cover the entire power range. Note that + * power values are already 0.25dB so no need + * to multiply pwr_i by 2 */ + if (type == AR5K_PWRTABLE_LINEAR_PCDAC) { + pwr_i = pmin; + pmin = 0; + pmax = 63; + } + + /* Find surrounding turning points (TPs) + * and interpolate between them */ + for (i = 0; (i <= (u16) (pmax - pmin)) && + (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { + + /* We passed the right TP, move to the next set of TPs + * if we pass the last TP, extrapolate above using the last + * two TPs for ratio */ + if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) { + idx[0]++; + idx[1]++; + } + + vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i, + pwr[idx[0]], pwr[idx[1]], + vpd[idx[0]], vpd[idx[1]]); + + /* Increase by 0.5dB + * (0.25 dB units) */ + pwr_i += 2; + } +} + +/* + * Get the surrounding per-channel power calibration piers + * for a given frequency so that we can interpolate between + * them and come up with an apropriate dataset for our current + * channel. + */ +static void +ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, + struct ieee80211_channel *channel, + struct ath5k_chan_pcal_info **pcinfo_l, + struct ath5k_chan_pcal_info **pcinfo_r) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcinfo; + u8 idx_l, idx_r; + u8 mode, max, i; + u32 target = channel->center_freq; + + idx_l = 0; + idx_r = 0; + + if (!(channel->hw_value & CHANNEL_OFDM)) { + pcinfo = ee->ee_pwr_cal_b; + mode = AR5K_EEPROM_MODE_11B; + } else if (channel->hw_value & CHANNEL_2GHZ) { + pcinfo = ee->ee_pwr_cal_g; + mode = AR5K_EEPROM_MODE_11G; + } else { + pcinfo = ee->ee_pwr_cal_a; + mode = AR5K_EEPROM_MODE_11A; + } + max = ee->ee_n_piers[mode] - 1; + + /* Frequency is below our calibrated + * range. Use the lowest power curve + * we have */ + if (target < pcinfo[0].freq) { + idx_l = idx_r = 0; + goto done; + } + + /* Frequency is above our calibrated + * range. Use the highest power curve + * we have */ + if (target > pcinfo[max].freq) { + idx_l = idx_r = max; + goto done; + } + + /* Frequency is inside our calibrated + * channel range. Pick the surrounding + * calibration piers so that we can + * interpolate */ + for (i = 0; i <= max; i++) { + + /* Frequency matches one of our calibration + * piers, no need to interpolate, just use + * that calibration pier */ + if (pcinfo[i].freq == target) { + idx_l = idx_r = i; + goto done; + } + + /* We found a calibration pier that's above + * frequency, use this pier and the previous + * one to interpolate */ + if (target < pcinfo[i].freq) { + idx_r = i; + idx_l = idx_r - 1; + goto done; + } + } + +done: + *pcinfo_l = &pcinfo[idx_l]; + *pcinfo_r = &pcinfo[idx_r]; + + return; +} + +/* + * Get the surrounding per-rate power calibration data + * for a given frequency and interpolate between power + * values to set max target power supported by hw for + * each rate. + */ +static void +ath5k_get_rate_pcal_data(struct ath5k_hw *ah, + struct ieee80211_channel *channel, + struct ath5k_rate_pcal_info *rates) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_rate_pcal_info *rpinfo; + u8 idx_l, idx_r; + u8 mode, max, i; + u32 target = channel->center_freq; + + idx_l = 0; + idx_r = 0; + + if (!(channel->hw_value & CHANNEL_OFDM)) { + rpinfo = ee->ee_rate_tpwr_b; + mode = AR5K_EEPROM_MODE_11B; + } else if (channel->hw_value & CHANNEL_2GHZ) { + rpinfo = ee->ee_rate_tpwr_g; + mode = AR5K_EEPROM_MODE_11G; + } else { + rpinfo = ee->ee_rate_tpwr_a; + mode = AR5K_EEPROM_MODE_11A; + } + max = ee->ee_rate_target_pwr_num[mode] - 1; + + /* Get the surrounding calibration + * piers - same as above */ + if (target < rpinfo[0].freq) { + idx_l = idx_r = 0; + goto done; + } + + if (target > rpinfo[max].freq) { + idx_l = idx_r = max; + goto done; + } + + for (i = 0; i <= max; i++) { + + if (rpinfo[i].freq == target) { + idx_l = idx_r = i; + goto done; + } + + if (target < rpinfo[i].freq) { + idx_r = i; + idx_l = idx_r - 1; + goto done; + } + } + +done: + /* Now interpolate power value, based on the frequency */ + rates->freq = target; + + rates->target_power_6to24 = + ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, + rpinfo[idx_r].freq, + rpinfo[idx_l].target_power_6to24, + rpinfo[idx_r].target_power_6to24); + + rates->target_power_36 = + ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, + rpinfo[idx_r].freq, + rpinfo[idx_l].target_power_36, + rpinfo[idx_r].target_power_36); + + rates->target_power_48 = + ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, + rpinfo[idx_r].freq, + rpinfo[idx_l].target_power_48, + rpinfo[idx_r].target_power_48); + + rates->target_power_54 = + ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, + rpinfo[idx_r].freq, + rpinfo[idx_l].target_power_54, + rpinfo[idx_r].target_power_54); +} + +/* + * Get the max edge power for this channel if + * we have such data from EEPROM's Conformance Test + * Limits (CTL), and limit max power if needed. + * + * FIXME: Only works for world regulatory domains + */ +static void +ath5k_get_max_ctl_power(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_edge_power *rep = ee->ee_ctl_pwr; + u8 *ctl_val = ee->ee_ctl; + s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4; + s16 edge_pwr = 0; + u8 rep_idx; + u8 i, ctl_mode; + u8 ctl_idx = 0xFF; + u32 target = channel->center_freq; + + /* Find out a CTL for our mode that's not mapped + * on a specific reg domain. + * + * TODO: Map our current reg domain to one of the 3 available + * reg domain ids so that we can support more CTLs. */ + switch (channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN; + break; + case CHANNEL_G: + ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN; + break; + case CHANNEL_B: + ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN; + break; + case CHANNEL_T: + ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN; + break; + case CHANNEL_TG: + ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN; + break; + case CHANNEL_XR: + /* Fall through */ + default: + return; + } + + for (i = 0; i < ee->ee_ctls; i++) { + if (ctl_val[i] == ctl_mode) { + ctl_idx = i; + break; + } + } + + /* If we have a CTL dataset available grab it and find the + * edge power for our frequency */ + if (ctl_idx == 0xFF) + return; + + /* Edge powers are sorted by frequency from lower + * to higher. Each CTL corresponds to 8 edge power + * measurements. */ + rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES; + + /* Don't do boundaries check because we + * might have more that one bands defined + * for this mode */ + + /* Get the edge power that's closer to our + * frequency */ + for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) { + rep_idx += i; + if (target <= rep[rep_idx].freq) + edge_pwr = (s16) rep[rep_idx].edge; + } + + if (edge_pwr) + ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr); +} + + +/* + * Power to PCDAC table functions + */ + +/* + * Fill Power to PCDAC table on RF5111 + * + * No further processing is needed for RF5111, the only thing we have to + * do is fill the values below and above calibration range since eeprom data + * may not cover the entire PCDAC table. + */ +static void +ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, + s16 *table_max) +{ + u8 *pcdac_out = ah->ah_txpower.txp_pd_table; + u8 *pcdac_tmp = ah->ah_txpower.tmpL[0]; + u8 pcdac_0, pcdac_n, pcdac_i, pwr_idx, i; + s16 min_pwr, max_pwr; + + /* Get table boundaries */ + min_pwr = table_min[0]; + pcdac_0 = pcdac_tmp[0]; + + max_pwr = table_max[0]; + pcdac_n = pcdac_tmp[table_max[0] - table_min[0]]; + + /* Extrapolate below minimum using pcdac_0 */ + pcdac_i = 0; + for (i = 0; i < min_pwr; i++) + pcdac_out[pcdac_i++] = pcdac_0; + + /* Copy values from pcdac_tmp */ + pwr_idx = min_pwr; + for (i = 0 ; pwr_idx <= max_pwr && + pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) { + pcdac_out[pcdac_i++] = pcdac_tmp[i]; + pwr_idx++; + } + + /* Extrapolate above maximum */ + while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE) + pcdac_out[pcdac_i++] = pcdac_n; + +} + +/* + * Combine available XPD Curves and fill Linear Power to PCDAC table + * on RF5112 + * + * RFX112 can have up to 2 curves (one for low txpower range and one for + * higher txpower range). We need to put them both on pcdac_out and place + * them in the correct location. In case we only have one curve available + * just fit it on pcdac_out (it's supposed to cover the entire range of + * available pwr levels since it's always the higher power curve). Extrapolate + * below and above final table if needed. + */ +static void +ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, + s16 *table_max, u8 pdcurves) +{ + u8 *pcdac_out = ah->ah_txpower.txp_pd_table; + u8 *pcdac_low_pwr; + u8 *pcdac_high_pwr; + u8 *pcdac_tmp; + u8 pwr; + s16 max_pwr_idx; + s16 min_pwr_idx; + s16 mid_pwr_idx = 0; + /* Edge flag turs on the 7nth bit on the PCDAC + * to delcare the higher power curve (force values + * to be greater than 64). If we only have one curve + * we don't need to set this, if we have 2 curves and + * fill the table backwards this can also be used to + * switch from higher power curve to lower power curve */ + u8 edge_flag; + int i; + + /* When we have only one curve available + * that's the higher power curve. If we have + * two curves the first is the high power curve + * and the next is the low power curve. */ + if (pdcurves > 1) { + pcdac_low_pwr = ah->ah_txpower.tmpL[1]; + pcdac_high_pwr = ah->ah_txpower.tmpL[0]; + mid_pwr_idx = table_max[1] - table_min[1] - 1; + max_pwr_idx = (table_max[0] - table_min[0]) / 2; + + /* If table size goes beyond 31.5dB, keep the + * upper 31.5dB range when setting tx power. + * Note: 126 = 31.5 dB in quarter dB steps */ + if (table_max[0] - table_min[1] > 126) + min_pwr_idx = table_max[0] - 126; + else + min_pwr_idx = table_min[1]; + + /* Since we fill table backwards + * start from high power curve */ + pcdac_tmp = pcdac_high_pwr; + + edge_flag = 0x40; +#if 0 + /* If both min and max power limits are in lower + * power curve's range, only use the low power curve. + * TODO: min/max levels are related to target + * power values requested from driver/user + * XXX: Is this really needed ? */ + if (min_pwr < table_max[1] && + max_pwr < table_max[1]) { + edge_flag = 0; + pcdac_tmp = pcdac_low_pwr; + max_pwr_idx = (table_max[1] - table_min[1])/2; + } +#endif + } else { + pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */ + pcdac_high_pwr = ah->ah_txpower.tmpL[0]; + min_pwr_idx = table_min[0]; + max_pwr_idx = (table_max[0] - table_min[0]) / 2; + pcdac_tmp = pcdac_high_pwr; + edge_flag = 0; + } + + /* This is used when setting tx power*/ + ah->ah_txpower.txp_min_idx = min_pwr_idx/2; + + /* Fill Power to PCDAC table backwards */ + pwr = max_pwr_idx; + for (i = 63; i >= 0; i--) { + /* Entering lower power range, reset + * edge flag and set pcdac_tmp to lower + * power curve.*/ + if (edge_flag == 0x40 && + (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) { + edge_flag = 0x00; + pcdac_tmp = pcdac_low_pwr; + pwr = mid_pwr_idx/2; + } + + /* Don't go below 1, extrapolate below if we have + * already swithced to the lower power curve -or + * we only have one curve and edge_flag is zero + * anyway */ + if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) { + while (i >= 0) { + pcdac_out[i] = pcdac_out[i + 1]; + i--; + } + break; + } + + pcdac_out[i] = pcdac_tmp[pwr] | edge_flag; + + /* Extrapolate above if pcdac is greater than + * 126 -this can happen because we OR pcdac_out + * value with edge_flag on high power curve */ + if (pcdac_out[i] > 126) + pcdac_out[i] = 126; + + /* Decrease by a 0.5dB step */ + pwr--; + } +} + +/* Write PCDAC values on hw */ +static void +ath5k_setup_pcdac_table(struct ath5k_hw *ah) +{ + u8 *pcdac_out = ah->ah_txpower.txp_pd_table; + int i; + + /* + * Write TX power values + */ + for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { + ath5k_hw_reg_write(ah, + (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) | + (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16), + AR5K_PHY_PCDAC_TXPOWER(i)); + } +} + + +/* + * Power to PDADC table functions + */ + +/* + * Set the gain boundaries and create final Power to PDADC table + * + * We can have up to 4 pd curves, we need to do a simmilar process + * as we do for RF5112. This time we don't have an edge_flag but we + * set the gain boundaries on a separate register. + */ +static void +ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, + s16 *pwr_min, s16 *pwr_max, u8 pdcurves) +{ + u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS]; + u8 *pdadc_out = ah->ah_txpower.txp_pd_table; + u8 *pdadc_tmp; + s16 pdadc_0; + u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size; + u8 pd_gain_overlap; + + /* Note: Register value is initialized on initvals + * there is no feedback from hw. + * XXX: What about pd_gain_overlap from EEPROM ? */ + pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) & + AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP; + + /* Create final PDADC table */ + for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) { + pdadc_tmp = ah->ah_txpower.tmpL[pdg]; + + if (pdg == pdcurves - 1) + /* 2 dB boundary stretch for last + * (higher power) curve */ + gain_boundaries[pdg] = pwr_max[pdg] + 4; + else + /* Set gain boundary in the middle + * between this curve and the next one */ + gain_boundaries[pdg] = + (pwr_max[pdg] + pwr_min[pdg + 1]) / 2; + + /* Sanity check in case our 2 db stretch got out of + * range. */ + if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER) + gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER; + + /* For the first curve (lower power) + * start from 0 dB */ + if (pdg == 0) + pdadc_0 = 0; + else + /* For the other curves use the gain overlap */ + pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) - + pd_gain_overlap; + + /* Force each power step to be at least 0.5 dB */ + if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1) + pwr_step = pdadc_tmp[1] - pdadc_tmp[0]; + else + pwr_step = 1; + + /* If pdadc_0 is negative, we need to extrapolate + * below this pdgain by a number of pwr_steps */ + while ((pdadc_0 < 0) && (pdadc_i < 128)) { + s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step; + pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp; + pdadc_0++; + } + + /* Set last pwr level, using gain boundaries */ + pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg]; + /* Limit it to be inside pwr range */ + table_size = pwr_max[pdg] - pwr_min[pdg]; + max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; + + /* Fill pdadc_out table */ + while (pdadc_0 < max_idx) + pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; + + /* Need to extrapolate above this pdgain? */ + if (pdadc_n <= max_idx) + continue; + + /* Force each power step to be at least 0.5 dB */ + if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1) + pwr_step = pdadc_tmp[table_size - 1] - + pdadc_tmp[table_size - 2]; + else + pwr_step = 1; + + /* Extrapolate above */ + while ((pdadc_0 < (s16) pdadc_n) && + (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) { + s16 tmp = pdadc_tmp[table_size - 1] + + (pdadc_0 - max_idx) * pwr_step; + pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp; + pdadc_0++; + } + } + + while (pdg < AR5K_EEPROM_N_PD_GAINS) { + gain_boundaries[pdg] = gain_boundaries[pdg - 1]; + pdg++; + } + + while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) { + pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1]; + pdadc_i++; + } + + /* Set gain boundaries */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(pd_gain_overlap, + AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) | + AR5K_REG_SM(gain_boundaries[0], + AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) | + AR5K_REG_SM(gain_boundaries[1], + AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) | + AR5K_REG_SM(gain_boundaries[2], + AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) | + AR5K_REG_SM(gain_boundaries[3], + AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4), + AR5K_PHY_TPC_RG5); + + /* Used for setting rate power table */ + ah->ah_txpower.txp_min_idx = pwr_min[0]; + +} + +/* Write PDADC values on hw */ +static void +ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah, + u8 pdcurves, u8 *pdg_to_idx) +{ + u8 *pdadc_out = ah->ah_txpower.txp_pd_table; + u32 reg; + u8 i; + + /* Select the right pdgain curves */ + + /* Clear current settings */ + reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1); + reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 | + AR5K_PHY_TPC_RG1_PDGAIN_2 | + AR5K_PHY_TPC_RG1_PDGAIN_3 | + AR5K_PHY_TPC_RG1_NUM_PD_GAIN); + + /* + * Use pd_gains curve from eeprom + * + * This overrides the default setting from initvals + * in case some vendors (e.g. Zcomax) don't use the default + * curves. If we don't honor their settings we 'll get a + * 5dB (1 * gain overlap ?) drop. + */ + reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN); + + switch (pdcurves) { + case 3: + reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3); + /* Fall through */ + case 2: + reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2); + /* Fall through */ + case 1: + reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1); + break; + } + ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1); + + /* + * Write TX power values + */ + for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { + ath5k_hw_reg_write(ah, + ((pdadc_out[4*i + 0] & 0xff) << 0) | + ((pdadc_out[4*i + 1] & 0xff) << 8) | + ((pdadc_out[4*i + 2] & 0xff) << 16) | + ((pdadc_out[4*i + 3] & 0xff) << 24), + AR5K_PHY_PDADC_TXPOWER(i)); + } +} + + +/* + * Common code for PCDAC/PDADC tables + */ + +/* + * This is the main function that uses all of the above + * to set PCDAC/PDADC table on hw for the current channel. + * This table is used for tx power calibration on the basband, + * without it we get weird tx power levels and in some cases + * distorted spectral mask + */ +static int +ath5k_setup_channel_powertable(struct ath5k_hw *ah, + struct ieee80211_channel *channel, + u8 ee_mode, u8 type) +{ + struct ath5k_pdgain_info *pdg_L, *pdg_R; + struct ath5k_chan_pcal_info *pcinfo_L; + struct ath5k_chan_pcal_info *pcinfo_R; + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; + s16 table_min[AR5K_EEPROM_N_PD_GAINS]; + s16 table_max[AR5K_EEPROM_N_PD_GAINS]; + u8 *tmpL; + u8 *tmpR; + u32 target = channel->center_freq; + int pdg, i; + + /* Get surounding freq piers for this channel */ + ath5k_get_chan_pcal_surrounding_piers(ah, channel, + &pcinfo_L, + &pcinfo_R); + + /* Loop over pd gain curves on + * surounding freq piers by index */ + for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) { + + /* Fill curves in reverse order + * from lower power (max gain) + * to higher power. Use curve -> idx + * backmaping we did on eeprom init */ + u8 idx = pdg_curve_to_idx[pdg]; + + /* Grab the needed curves by index */ + pdg_L = &pcinfo_L->pd_curves[idx]; + pdg_R = &pcinfo_R->pd_curves[idx]; + + /* Initialize the temp tables */ + tmpL = ah->ah_txpower.tmpL[pdg]; + tmpR = ah->ah_txpower.tmpR[pdg]; + + /* Set curve's x boundaries and create + * curves so that they cover the same + * range (if we don't do that one table + * will have values on some range and the + * other one won't have any so interpolation + * will fail) */ + table_min[pdg] = min(pdg_L->pd_pwr[0], + pdg_R->pd_pwr[0]) / 2; + + table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1], + pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2; + + /* Now create the curves on surrounding channels + * and interpolate if needed to get the final + * curve for this gain on this channel */ + switch (type) { + case AR5K_PWRTABLE_LINEAR_PCDAC: + /* Override min/max so that we don't loose + * accuracy (don't divide by 2) */ + table_min[pdg] = min(pdg_L->pd_pwr[0], + pdg_R->pd_pwr[0]); + + table_max[pdg] = + max(pdg_L->pd_pwr[pdg_L->pd_points - 1], + pdg_R->pd_pwr[pdg_R->pd_points - 1]); + + /* Override minimum so that we don't get + * out of bounds while extrapolating + * below. Don't do this when we have 2 + * curves and we are on the high power curve + * because table_min is ok in this case */ + if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) { + + table_min[pdg] = + ath5k_get_linear_pcdac_min(pdg_L->pd_step, + pdg_R->pd_step, + pdg_L->pd_pwr, + pdg_R->pd_pwr); + + /* Don't go too low because we will + * miss the upper part of the curve. + * Note: 126 = 31.5dB (max power supported) + * in 0.25dB units */ + if (table_max[pdg] - table_min[pdg] > 126) + table_min[pdg] = table_max[pdg] - 126; + } + + /* Fall through */ + case AR5K_PWRTABLE_PWR_TO_PCDAC: + case AR5K_PWRTABLE_PWR_TO_PDADC: + + ath5k_create_power_curve(table_min[pdg], + table_max[pdg], + pdg_L->pd_pwr, + pdg_L->pd_step, + pdg_L->pd_points, tmpL, type); + + /* We are in a calibration + * pier, no need to interpolate + * between freq piers */ + if (pcinfo_L == pcinfo_R) + continue; + + ath5k_create_power_curve(table_min[pdg], + table_max[pdg], + pdg_R->pd_pwr, + pdg_R->pd_step, + pdg_R->pd_points, tmpR, type); + break; + default: + return -EINVAL; + } + + /* Interpolate between curves + * of surounding freq piers to + * get the final curve for this + * pd gain. Re-use tmpL for interpolation + * output */ + for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) && + (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { + tmpL[i] = (u8) ath5k_get_interpolated_value(target, + (s16) pcinfo_L->freq, + (s16) pcinfo_R->freq, + (s16) tmpL[i], + (s16) tmpR[i]); + } + } + + /* Now we have a set of curves for this + * channel on tmpL (x range is table_max - table_min + * and y values are tmpL[pdg][]) sorted in the same + * order as EEPROM (because we've used the backmaping). + * So for RF5112 it's from higher power to lower power + * and for RF2413 it's from lower power to higher power. + * For RF5111 we only have one curve. */ + + /* Fill min and max power levels for this + * channel by interpolating the values on + * surounding channels to complete the dataset */ + ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target, + (s16) pcinfo_L->freq, + (s16) pcinfo_R->freq, + pcinfo_L->min_pwr, pcinfo_R->min_pwr); + + ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target, + (s16) pcinfo_L->freq, + (s16) pcinfo_R->freq, + pcinfo_L->max_pwr, pcinfo_R->max_pwr); + + /* We are ready to go, fill PCDAC/PDADC + * table and write settings on hardware */ + switch (type) { + case AR5K_PWRTABLE_LINEAR_PCDAC: + /* For RF5112 we can have one or two curves + * and each curve covers a certain power lvl + * range so we need to do some more processing */ + ath5k_combine_linear_pcdac_curves(ah, table_min, table_max, + ee->ee_pd_gains[ee_mode]); + + /* Set txp.offset so that we can + * match max power value with max + * table index */ + ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2); + + /* Write settings on hw */ + ath5k_setup_pcdac_table(ah); + break; + case AR5K_PWRTABLE_PWR_TO_PCDAC: + /* We are done for RF5111 since it has only + * one curve, just fit the curve on the table */ + ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max); + + /* No rate powertable adjustment for RF5111 */ + ah->ah_txpower.txp_min_idx = 0; + ah->ah_txpower.txp_offset = 0; + + /* Write settings on hw */ + ath5k_setup_pcdac_table(ah); + break; + case AR5K_PWRTABLE_PWR_TO_PDADC: + /* Set PDADC boundaries and fill + * final PDADC table */ + ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max, + ee->ee_pd_gains[ee_mode]); + + /* Write settings on hw */ + ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx); + + /* Set txp.offset, note that table_min + * can be negative */ + ah->ah_txpower.txp_offset = table_min[0]; + break; + default: + return -EINVAL; + } + + return 0; +} + + +/* + * Per-rate tx power setting + * + * This is the code that sets the desired tx power (below + * maximum) on hw for each rate (we also have TPC that sets + * power per packet). We do that by providing an index on the + * PCDAC/PDADC table we set up. + */ + +/* + * Set rate power table + * + * For now we only limit txpower based on maximum tx power + * supported by hw (what's inside rate_info). We need to limit + * this even more, based on regulatory domain etc. + * + * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps) + * and is indexed as follows: + * rates[0] - rates[7] -> OFDM rates + * rates[8] - rates[14] -> CCK rates + * rates[15] -> XR rates (they all have the same power) + */ +static void +ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, + struct ath5k_rate_pcal_info *rate_info, + u8 ee_mode) +{ + unsigned int i; + u16 *rates; + + /* max_pwr is power level we got from driver/user in 0.5dB + * units, switch to 0.25dB units so we can compare */ + max_pwr *= 2; + max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2; + + /* apply rate limits */ + rates = ah->ah_txpower.txp_rates_power_table; + + /* OFDM rates 6 to 24Mb/s */ + for (i = 0; i < 5; i++) + rates[i] = min(max_pwr, rate_info->target_power_6to24); + + /* Rest OFDM rates */ + rates[5] = min(rates[0], rate_info->target_power_36); + rates[6] = min(rates[0], rate_info->target_power_48); + rates[7] = min(rates[0], rate_info->target_power_54); + + /* CCK rates */ + /* 1L */ + rates[8] = min(rates[0], rate_info->target_power_6to24); + /* 2L */ + rates[9] = min(rates[0], rate_info->target_power_36); + /* 2S */ + rates[10] = min(rates[0], rate_info->target_power_36); + /* 5L */ + rates[11] = min(rates[0], rate_info->target_power_48); + /* 5S */ + rates[12] = min(rates[0], rate_info->target_power_48); + /* 11L */ + rates[13] = min(rates[0], rate_info->target_power_54); + /* 11S */ + rates[14] = min(rates[0], rate_info->target_power_54); + + /* XR rates */ + rates[15] = min(rates[0], rate_info->target_power_6to24); + + /* CCK rates have different peak to average ratio + * so we have to tweak their power so that gainf + * correction works ok. For this we use OFDM to + * CCK delta from eeprom */ + if ((ee_mode == AR5K_EEPROM_MODE_11G) && + (ah->ah_phy_revision < AR5K_SREV_PHY_5212A)) + for (i = 8; i <= 15; i++) + rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; + + ah->ah_txpower.txp_min_pwr = rates[7]; + ah->ah_txpower.txp_max_pwr = rates[0]; + ah->ah_txpower.txp_ofdm = rates[7]; +} + + +/* + * Set transmition power + */ +int +ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, + u8 ee_mode, u8 txpower) +{ + struct ath5k_rate_pcal_info rate_info; + u8 type; + int ret; + + ATH5K_TRACE(ah->ah_sc); + if (txpower > AR5K_TUNE_MAX_TXPOWER) { + ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); + return -EINVAL; + } + if (txpower == 0) + txpower = AR5K_TUNE_DEFAULT_TXPOWER; + + /* Reset TX power values */ + memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); + ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; + ah->ah_txpower.txp_min_pwr = 0; + ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER; + + /* Initialize TX power table */ + switch (ah->ah_radio) { + case AR5K_RF5111: + type = AR5K_PWRTABLE_PWR_TO_PCDAC; + break; + case AR5K_RF5112: + type = AR5K_PWRTABLE_LINEAR_PCDAC; + break; + case AR5K_RF2413: + case AR5K_RF5413: + case AR5K_RF2316: + case AR5K_RF2317: + case AR5K_RF2425: + type = AR5K_PWRTABLE_PWR_TO_PDADC; + break; + default: + return -EINVAL; + } + + /* FIXME: Only on channel/mode change */ + ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type); + if (ret) + return ret; + + /* Limit max power if we have a CTL available */ + ath5k_get_max_ctl_power(ah, channel); + + /* FIXME: Tx power limit for this regdomain + * XXX: Mac80211/CRDA will do that anyway ? */ + + /* FIXME: Antenna reduction stuff */ + + /* FIXME: Limit power on turbo modes */ + + /* FIXME: TPC scale reduction */ + + /* Get surounding channels for per-rate power table + * calibration */ + ath5k_get_rate_pcal_data(ah, channel, &rate_info); + + /* Setup rate power table */ + ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode); + + /* Write rate power table on hw */ + ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | + AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | + AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) | + AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) | + AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2); + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) | + AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) | + AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3); + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) | + AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | + AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); + + /* FIXME: TPC support */ + if (ah->ah_txpower.txp_tpc) { + ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | + AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); + + ath5k_hw_reg_write(ah, + AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) | + AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) | + AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), + AR5K_TPC); + } else { + ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | + AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); + } + + return 0; +} + +int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower) +{ + /*Just a try M.F.*/ + struct ieee80211_channel *channel = &ah->ah_current_channel; + + ATH5K_TRACE(ah->ah_sc); + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, + "changing txpower to %d\n", txpower); + + return ath5k_hw_txpower(ah, channel, mode, txpower); +} + +#undef _ATH5K_PHY diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c new file mode 100644 index 0000000..5094c39 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * 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) +{ + u32 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 false; + + /* XXX: How about AR5K_CFG_TXCNT ? */ + if (ah->ah_version == AR5K_AR5210) + return false; + + pending = (AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT); + + /* It's possible to have no frames pending even if TXE + * is set. To indicate that q has not stopped return + * true */ + if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) + return true; + + return pending; +} + +/* + * 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 + */ + /* Enable DCU early termination for this queue */ + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_DCU_EARLY); + + /* Enable DCU to wait for next fragment from QCU */ + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + AR5K_DCU_MISC_FRAG_WAIT); + + /* On Maui and Spirit use the global seqnum on DCU */ + if (ah->ah_mac_version < AR5K_SREV_AR5211) + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + AR5K_DCU_MISC_SEQNUM_CTL); + + 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 && + (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB)) + 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); + 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); + + 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)); + + 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; + } + + /* TODO: Handle frame compression */ + + /* + * 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); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); + + /* Update secondary interrupt mask registers */ + + /* Filter out inactive queues */ + 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; + ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; + ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; + ah->ah_txq_imr_qtrig &= ah->ah_txq_status; + ah->ah_txq_imr_nofrm &= 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); + /* Update simr2 but don't overwrite rest simr2 settings */ + AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); + AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, + AR5K_REG_SM(ah->ah_txq_imr_txurn, + AR5K_SIMR2_QCU_TXURN)); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, + AR5K_SIMR3_QCBRORN) | + AR5K_REG_SM(ah->ah_txq_imr_cbrurn, + AR5K_SIMR3_QCBRURN), AR5K_SIMR3); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, + AR5K_SIMR4_QTRIG), AR5K_SIMR4); + /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, + AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); + /* No queue has TXNOFRM enabled, disable the interrupt + * by setting AR5K_TXNOFRM to zero */ + if (ah->ah_txq_imr_nofrm == 0) + ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); + + /* Set QCU mask for this DCU to save power */ + AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue); + } + + 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/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h new file mode 100644 index 0000000..7070d15 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -0,0 +1,2589 @@ +/* + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2007-2008 Michael Taylor + * + * 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. + * + */ + +/* + * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k + * maintained by Reyk Floeter + * + * I tried to document those registers by looking at ar5k code, some + * 802.11 (802.11e mostly) papers and by reading various public available + * Atheros presentations and papers like these: + * + * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf + * 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. + */ + + + +/*====MAC DMA REGISTERS====*/ + +/* + * AR5210-Specific TXDP registers + * 5210 has only 2 transmit queues so no DCU/QCU, just + * 2 transmit descriptor pointers... + */ +#define AR5K_NOQCU_TXDP0 0x0000 /* Queue 0 - data */ +#define AR5K_NOQCU_TXDP1 0x0004 /* Queue 1 - beacons */ + +/* + * Mac Control Register + */ +#define AR5K_CR 0x0008 /* Register Address */ +#define AR5K_CR_TXE0 0x00000001 /* TX Enable for queue 0 on 5210 */ +#define AR5K_CR_TXE1 0x00000002 /* TX Enable for queue 1 on 5210 */ +#define AR5K_CR_RXE 0x00000004 /* RX Enable */ +#define AR5K_CR_TXD0 0x00000008 /* TX Disable for queue 0 on 5210 */ +#define AR5K_CR_TXD1 0x00000010 /* TX Disable for queue 1 on 5210 */ +#define AR5K_CR_RXD 0x00000020 /* RX Disable */ +#define AR5K_CR_SWI 0x00000040 /* Software Interrupt */ + +/* + * RX Descriptor Pointer register + */ +#define AR5K_RXDP 0x000c + +/* + * Configuration and status register + */ +#define AR5K_CFG 0x0014 /* Register Address */ +#define AR5K_CFG_SWTD 0x00000001 /* Byte-swap TX descriptor (for big endian archs) */ +#define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer */ +#define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */ +#define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer */ +#define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register access */ +#define AR5K_CFG_IBSS 0x00000020 /* 0-BSS, 1-IBSS [5211+] */ +#define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */ +#define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ +#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */ +#define AR5K_CFG_TXCNT 0x00007800 /* Tx frame count (?) [5210] */ +#define AR5K_CFG_TXCNT_S 11 +#define AR5K_CFG_TXFSTAT 0x00008000 /* Tx frame status (?) [5210] */ +#define AR5K_CFG_TXFSTRT 0x00010000 /* [5210] */ +#define AR5K_CFG_PCI_THRES 0x00060000 /* PCI Master req q threshold [5211+] */ +#define AR5K_CFG_PCI_THRES_S 17 + +/* + * Interrupt enable register + */ +#define AR5K_IER 0x0024 /* Register Address */ +#define AR5K_IER_DISABLE 0x00000000 /* Disable card interrupts */ +#define AR5K_IER_ENABLE 0x00000001 /* Enable card interrupts */ + + +/* + * 0x0028 is Beacon Control Register on 5210 + * and first RTS duration register on 5211 + */ + +/* + * Beacon control register [5210] + */ +#define AR5K_BCR 0x0028 /* Register Address */ +#define AR5K_BCR_AP 0x00000000 /* AP mode */ +#define AR5K_BCR_ADHOC 0x00000001 /* Ad-Hoc mode */ +#define AR5K_BCR_BDMAE 0x00000002 /* DMA enable */ +#define AR5K_BCR_TQ1FV 0x00000004 /* Use Queue1 for CAB traffic */ +#define AR5K_BCR_TQ1V 0x00000008 /* Use Queue1 for Beacon traffic */ +#define AR5K_BCR_BCGET 0x00000010 + +/* + * First RTS duration register [5211] + */ +#define AR5K_RTSD0 0x0028 /* Register Address */ +#define AR5K_RTSD0_6 0x000000ff /* 6Mb RTS duration mask (?) */ +#define AR5K_RTSD0_6_S 0 /* 6Mb RTS duration shift (?) */ +#define AR5K_RTSD0_9 0x0000ff00 /* 9Mb*/ +#define AR5K_RTSD0_9_S 8 +#define AR5K_RTSD0_12 0x00ff0000 /* 12Mb*/ +#define AR5K_RTSD0_12_S 16 +#define AR5K_RTSD0_18 0xff000000 /* 16Mb*/ +#define AR5K_RTSD0_18_S 24 + + +/* + * 0x002c is Beacon Status Register on 5210 + * and second RTS duration register on 5211 + */ + +/* + * Beacon status register [5210] + * + * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR + * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning + * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR). + * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i + * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what + * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR. + */ +#define AR5K_BSR 0x002c /* Register Address */ +#define AR5K_BSR_BDLYSW 0x00000001 /* SW Beacon delay (?) */ +#define AR5K_BSR_BDLYDMA 0x00000002 /* DMA Beacon delay (?) */ +#define AR5K_BSR_TXQ1F 0x00000004 /* Beacon queue (1) finished */ +#define AR5K_BSR_ATIMDLY 0x00000008 /* ATIM delay (?) */ +#define AR5K_BSR_SNPADHOC 0x00000100 /* Ad-hoc mode set (?) */ +#define AR5K_BSR_SNPBDMAE 0x00000200 /* Beacon DMA enabled (?) */ +#define AR5K_BSR_SNPTQ1FV 0x00000400 /* Queue1 is used for CAB traffic (?) */ +#define AR5K_BSR_SNPTQ1V 0x00000800 /* Queue1 is used for Beacon traffic (?) */ +#define AR5K_BSR_SNAPSHOTSVALID 0x00001000 /* BCR snapshots are valid (?) */ +#define AR5K_BSR_SWBA_CNT 0x00ff0000 + +/* + * Second RTS duration register [5211] + */ +#define AR5K_RTSD1 0x002c /* Register Address */ +#define AR5K_RTSD1_24 0x000000ff /* 24Mb */ +#define AR5K_RTSD1_24_S 0 +#define AR5K_RTSD1_36 0x0000ff00 /* 36Mb */ +#define AR5K_RTSD1_36_S 8 +#define AR5K_RTSD1_48 0x00ff0000 /* 48Mb */ +#define AR5K_RTSD1_48_S 16 +#define AR5K_RTSD1_54 0xff000000 /* 54Mb */ +#define AR5K_RTSD1_54_S 24 + + +/* + * Transmit configuration register + */ +#define AR5K_TXCFG 0x0030 /* Register Address */ +#define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size (read) */ +#define AR5K_TXCFG_SDMAMR_S 0 +#define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */ +#define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */ +#define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */ +#define AR5K_TXCFG_TXFULL_S 4 +#define AR5K_TXCFG_TXFULL_0B 0x00000000 +#define AR5K_TXCFG_TXFULL_64B 0x00000010 +#define AR5K_TXCFG_TXFULL_128B 0x00000020 +#define AR5K_TXCFG_TXFULL_192B 0x00000030 +#define AR5K_TXCFG_TXFULL_256B 0x00000040 +#define AR5K_TXCFG_TXCONT_EN 0x00000080 +#define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */ +#define AR5K_TXCFG_JUMBO_DESC_EN 0x00000400 /* Enable jumbo tx descriptors [5211+] */ +#define AR5K_TXCFG_ADHOC_BCN_ATIM 0x00000800 /* Adhoc Beacon ATIM Policy */ +#define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS 0x00001000 /* Disable ATIM window defer [5211+] */ +#define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */ +#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */ +#define AR5K_TXCFG_RDY_CBR_DIS 0x00004000 /* Ready time CBR disable [5211+] */ +#define AR5K_TXCFG_JUMBO_FRM_MODE 0x00008000 /* Jumbo frame mode [5211+] */ +#define AR5K_TXCFG_DCU_DBL_BUF_DIS 0x00008000 /* Disable double buffering on DCU */ +#define AR5K_TXCFG_DCU_CACHING_DIS 0x00010000 /* Disable DCU caching */ + +/* + * Receive configuration register + */ +#define AR5K_RXCFG 0x0034 /* Register Address */ +#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size (write) */ +#define AR5K_RXCFG_SDMAMW_S 0 +#define AR5K_RXCFG_ZLFDMA 0x00000008 /* Enable Zero-length frame DMA */ +#define AR5K_RXCFG_DEF_ANTENNA 0x00000010 /* Default antenna (?) */ +#define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo rx descriptors [5211+] */ +#define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames [5211+] */ +#define AR5K_RXCFG_SLE_ENTRY 0x00000080 /* Sleep entry policy */ + +/* + * Receive jumbo descriptor last address register + * Only found in 5211 (?) + */ +#define AR5K_RXJLA 0x0038 + +/* + * MIB control register + */ +#define AR5K_MIBC 0x0040 /* Register Address */ +#define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ +#define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ +#define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ +#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ + +/* + * Timeout prescale register + */ +#define AR5K_TOPS 0x0044 +#define AR5K_TOPS_M 0x0000ffff + +/* + * Receive timeout register (no frame received) + */ +#define AR5K_RXNOFRM 0x0048 +#define AR5K_RXNOFRM_M 0x000003ff + +/* + * Transmit timeout register (no frame sent) + */ +#define AR5K_TXNOFRM 0x004c +#define AR5K_TXNOFRM_M 0x000003ff +#define AR5K_TXNOFRM_QCU 0x000ffc00 +#define AR5K_TXNOFRM_QCU_S 10 + +/* + * Receive frame gap timeout register + */ +#define AR5K_RPGTO 0x0050 +#define AR5K_RPGTO_M 0x000003ff + +/* + * Receive frame count limit register + */ +#define AR5K_RFCNT 0x0054 +#define AR5K_RFCNT_M 0x0000001f /* [5211+] (?) */ +#define AR5K_RFCNT_RFCL 0x0000000f /* [5210] */ + +/* + * Misc settings register + * (reserved0-3) + */ +#define AR5K_MISC 0x0058 /* Register Address */ +#define AR5K_MISC_DMA_OBS_M 0x000001e0 +#define AR5K_MISC_DMA_OBS_S 5 +#define AR5K_MISC_MISC_OBS_M 0x00000e00 +#define AR5K_MISC_MISC_OBS_S 9 +#define AR5K_MISC_MAC_OBS_LSB_M 0x00007000 +#define AR5K_MISC_MAC_OBS_LSB_S 12 +#define AR5K_MISC_MAC_OBS_MSB_M 0x00038000 +#define AR5K_MISC_MAC_OBS_MSB_S 15 +#define AR5K_MISC_LED_DECAY 0x001c0000 /* [5210] */ +#define AR5K_MISC_LED_BLINK 0x00e00000 /* [5210] */ + +/* + * QCU/DCU clock gating register (5311) + * (reserved4-5) + */ +#define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */ +#define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */ +#define AR5K_QCUDCU_CLKGT_DCU 0x07ff0000 /* Mask for DCU clock */ + +/* + * Interrupt Status Registers + * + * For 5210 there is only one status register but for + * 5211/5212 we have one primary and 4 secondary registers. + * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. + * Most of these bits are common for all chipsets. + */ +#define AR5K_ISR 0x001c /* Register Address [5210] */ +#define AR5K_PISR 0x0080 /* Register Address [5211+] */ +#define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly recieved */ +#define AR5K_ISR_RXDESC 0x00000002 /* RX descriptor request */ +#define AR5K_ISR_RXERR 0x00000004 /* Receive error */ +#define AR5K_ISR_RXNOFRM 0x00000008 /* No frame received (receive timeout) */ +#define AR5K_ISR_RXEOL 0x00000010 /* Empty RX descriptor */ +#define AR5K_ISR_RXORN 0x00000020 /* Receive FIFO overrun */ +#define AR5K_ISR_TXOK 0x00000040 /* Frame successfuly transmited */ +#define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ +#define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ +#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout) */ +#define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ +#define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ +#define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ +#define AR5K_ISR_SWI 0x00002000 /* Software interrupt */ +#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 /* 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+] */ +#define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ +#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_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) + * + * 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 /* 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_QCBRORN_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+] + */ +#define AR5K_RAC_PISR 0x00c0 /* Read and clear PISR */ +#define AR5K_RAC_SISR0 0x00c4 /* Read and clear SISR0 */ +#define AR5K_RAC_SISR1 0x00c8 /* Read and clear SISR1 */ +#define AR5K_RAC_SISR2 0x00cc /* Read and clear SISR2 */ +#define AR5K_RAC_SISR3 0x00d0 /* Read and clear SISR3 */ +#define AR5K_RAC_SISR4 0x00d4 /* Read and clear SISR4 */ + +/* + * Interrupt Mask Registers + * + * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary + * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match. + */ +#define AR5K_IMR 0x0020 /* Register Address [5210] */ +#define AR5K_PIMR 0x00a0 /* Register Address [5211+] */ +#define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly recieved*/ +#define AR5K_IMR_RXDESC 0x00000002 /* RX descriptor request*/ +#define AR5K_IMR_RXERR 0x00000004 /* Receive error*/ +#define AR5K_IMR_RXNOFRM 0x00000008 /* No frame received (receive timeout)*/ +#define AR5K_IMR_RXEOL 0x00000010 /* Empty RX descriptor*/ +#define AR5K_IMR_RXORN 0x00000020 /* Receive FIFO overrun*/ +#define AR5K_IMR_TXOK 0x00000040 /* Frame successfuly transmited*/ +#define AR5K_IMR_TXDESC 0x00000080 /* TX descriptor request*/ +#define AR5K_IMR_TXERR 0x00000100 /* Transmit error*/ +#define AR5K_IMR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout)*/ +#define AR5K_IMR_TXEOL 0x00000400 /* Empty TX descriptor*/ +#define AR5K_IMR_TXURN 0x00000800 /* Transmit FIFO underrun*/ +#define AR5K_IMR_MIB 0x00001000 /* Update MIB counters*/ +#define AR5K_IMR_SWI 0x00002000 /* Software interrupt */ +#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 /* 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+] */ +#define AR5K_IMR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ +#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 /* '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 /* 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) + */ +#define AR5K_SIMR0 0x00a4 /* Register Address [5211+] */ +#define AR5K_SIMR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ +#define AR5K_SIMR0_QCU_TXOK_S 0 +#define AR5K_SIMR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ +#define AR5K_SIMR0_QCU_TXDESC_S 16 + +#define AR5K_SIMR1 0x00a8 /* Register Address [5211+] */ +#define AR5K_SIMR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ +#define AR5K_SIMR1_QCU_TXERR_S 0 +#define AR5K_SIMR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ +#define AR5K_SIMR1_QCU_TXEOL_S 16 + +#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ +#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ +#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 /* 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 */ +#define AR5K_SIMR3_QCBRORN_S 0 +#define AR5K_SIMR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ +#define AR5K_SIMR3_QCBRURN_S 16 + +#define AR5K_SIMR4 0x00b4 /* Register Address [5211+] */ +#define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */ +#define AR5K_SIMR4_QTRIG_S 0 + +/* + * DMA Debug registers 0-7 + * 0xe0 - 0xfc + */ + +/* + * Decompression mask registers [5212+] + */ +#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (index) */ +#define AR5K_DCM_DATA 0x0404 /*Decompression mask data */ + +/* + * Wake On Wireless pattern control register [5212+] + */ +#define AR5K_WOW_PCFG 0x0410 /* Register Address */ +#define AR5K_WOW_PCFG_PAT_MATCH_EN 0x00000001 /* Pattern match enable */ +#define AR5K_WOW_PCFG_LONG_FRAME_POL 0x00000002 /* Long frame policy */ +#define AR5K_WOW_PCFG_WOBMISS 0x00000004 /* Wake on bea(con) miss (?) */ +#define AR5K_WOW_PCFG_PAT_0_EN 0x00000100 /* Enable pattern 0 */ +#define AR5K_WOW_PCFG_PAT_1_EN 0x00000200 /* Enable pattern 1 */ +#define AR5K_WOW_PCFG_PAT_2_EN 0x00000400 /* Enable pattern 2 */ +#define AR5K_WOW_PCFG_PAT_3_EN 0x00000800 /* Enable pattern 3 */ +#define AR5K_WOW_PCFG_PAT_4_EN 0x00001000 /* Enable pattern 4 */ +#define AR5K_WOW_PCFG_PAT_5_EN 0x00002000 /* Enable pattern 5 */ + +/* + * Wake On Wireless pattern index register (?) [5212+] + */ +#define AR5K_WOW_PAT_IDX 0x0414 + +/* + * Wake On Wireless pattern data register [5212+] + */ +#define AR5K_WOW_PAT_DATA 0x0418 /* Register Address */ +#define AR5K_WOW_PAT_DATA_0_3_V 0x00000001 /* Pattern 0, 3 value */ +#define AR5K_WOW_PAT_DATA_1_4_V 0x00000100 /* Pattern 1, 4 value */ +#define AR5K_WOW_PAT_DATA_2_5_V 0x00010000 /* Pattern 2, 5 value */ +#define AR5K_WOW_PAT_DATA_0_3_M 0x01000000 /* Pattern 0, 3 mask */ +#define AR5K_WOW_PAT_DATA_1_4_M 0x04000000 /* Pattern 1, 4 mask */ +#define AR5K_WOW_PAT_DATA_2_5_M 0x10000000 /* Pattern 2, 5 mask */ + +/* + * Decompression configuration registers [5212+] + */ +#define AR5K_DCCFG 0x0420 /* Register Address */ +#define AR5K_DCCFG_GLOBAL_EN 0x00000001 /* Enable decompression on all queues */ +#define AR5K_DCCFG_BYPASS_EN 0x00000002 /* Bypass decompression */ +#define AR5K_DCCFG_BCAST_EN 0x00000004 /* Enable decompression for bcast frames */ +#define AR5K_DCCFG_MCAST_EN 0x00000008 /* Enable decompression for mcast frames */ + +/* + * Compression configuration registers [5212+] + */ +#define AR5K_CCFG 0x0600 /* Register Address */ +#define AR5K_CCFG_WINDOW_SIZE 0x00000007 /* Compression window size */ +#define AR5K_CCFG_CPC_EN 0x00000008 /* Enable performance counters */ + +#define AR5K_CCFG_CCU 0x0604 /* Register Address */ +#define AR5K_CCFG_CCU_CUP_EN 0x00000001 /* CCU Catchup enable */ +#define AR5K_CCFG_CCU_CREDIT 0x00000002 /* CCU Credit (field) */ +#define AR5K_CCFG_CCU_CD_THRES 0x00000080 /* CCU Cyc(lic?) debt threshold (field) */ +#define AR5K_CCFG_CCU_CUP_LCNT 0x00010000 /* CCU Catchup lit(?) count */ +#define AR5K_CCFG_CCU_INIT 0x00100200 /* Initial value during reset */ + +/* + * Compression performance counter registers [5212+] + */ +#define AR5K_CPC0 0x0610 /* Compression performance counter 0 */ +#define AR5K_CPC1 0x0614 /* Compression performance counter 1*/ +#define AR5K_CPC2 0x0618 /* Compression performance counter 2 */ +#define AR5K_CPC3 0x061c /* Compression performance counter 3 */ +#define AR5K_CPCOVF 0x0620 /* Compression performance overflow */ + + +/* + * Queue control unit (QCU) registers [5211+] + * + * Card has 12 TX Queues but i see that only 0-9 are used (?) + * both in binary HAL (see ah.h) and ar5k. Each queue has it's own + * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) + * configuration register (0x08c0 - 0x08ec), a ready time configuration + * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - + * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some + * global registers, QCU transmit enable/disable and "one shot arm (?)" + * set/clear, which contain status for all queues (we shift by 1 for each + * queue). To access these registers easily we define some macros here + * that are used inside HAL. For more infos check out *_tx_queue functs. + */ + +/* + * Generic QCU Register access macros + */ +#define AR5K_QUEUE_REG(_r, _q) (((_q) << 2) + _r) +#define AR5K_QCU_GLOBAL_READ(_r, _q) (AR5K_REG_READ(_r) & (1 << _q)) +#define AR5K_QCU_GLOBAL_WRITE(_r, _q) AR5K_REG_WRITE(_r, (1 << _q)) + +/* + * QCU Transmit descriptor pointer registers + */ +#define AR5K_QCU_TXDP_BASE 0x0800 /* Register Address - Queue0 TXDP */ +#define AR5K_QUEUE_TXDP(_q) AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q) + +/* + * QCU Transmit enable register + */ +#define AR5K_QCU_TXE 0x0840 +#define AR5K_ENABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q) +#define AR5K_QUEUE_ENABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q) + +/* + * QCU Transmit disable register + */ +#define AR5K_QCU_TXD 0x0880 +#define AR5K_DISABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q) +#define AR5K_QUEUE_DISABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q) + +/* + * QCU Constant Bit Rate configuration registers + */ +#define AR5K_QCU_CBRCFG_BASE 0x08c0 /* Register Address - Queue0 CBRCFG */ +#define AR5K_QCU_CBRCFG_INTVAL 0x00ffffff /* CBR Interval mask */ +#define AR5K_QCU_CBRCFG_INTVAL_S 0 +#define AR5K_QCU_CBRCFG_ORN_THRES 0xff000000 /* CBR overrun threshold mask */ +#define AR5K_QCU_CBRCFG_ORN_THRES_S 24 +#define AR5K_QUEUE_CBRCFG(_q) AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q) + +/* + * QCU Ready time configuration registers + */ +#define AR5K_QCU_RDYTIMECFG_BASE 0x0900 /* Register Address - Queue0 RDYTIMECFG */ +#define AR5K_QCU_RDYTIMECFG_INTVAL 0x00ffffff /* Ready time interval mask */ +#define AR5K_QCU_RDYTIMECFG_INTVAL_S 0 +#define AR5K_QCU_RDYTIMECFG_ENABLE 0x01000000 /* Ready time enable mask */ +#define AR5K_QUEUE_RDYTIMECFG(_q) AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q) + +/* + * QCU one shot arm set registers + */ +#define AR5K_QCU_ONESHOTARM_SET 0x0940 /* Register Address -QCU "one shot arm set (?)" */ +#define AR5K_QCU_ONESHOTARM_SET_M 0x0000ffff + +/* + * QCU one shot arm clear registers + */ +#define AR5K_QCU_ONESHOTARM_CLEAR 0x0980 /* Register Address -QCU "one shot arm clear (?)" */ +#define AR5K_QCU_ONESHOTARM_CLEAR_M 0x0000ffff + +/* + * QCU misc registers + */ +#define AR5K_QCU_MISC_BASE 0x09c0 /* Register Address -Queue0 MISC */ +#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 /* 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_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 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 */ +#define AR5K_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q) + + +/* + * QCU status registers + */ +#define AR5K_QCU_STS_BASE 0x0a00 /* Register Address - Queue0 STS */ +#define AR5K_QCU_STS_FRMPENDCNT 0x00000003 /* Frames pending counter */ +#define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter */ +#define AR5K_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q) + +/* + * QCU ready time shutdown register + */ +#define AR5K_QCU_RDYTIMESHDN 0x0a40 +#define AR5K_QCU_RDYTIMESHDN_M 0x000003ff + +/* + * QCU compression buffer base registers [5212+] + */ +#define AR5K_QCU_CBB_SELECT 0x0b00 +#define AR5K_QCU_CBB_ADDR 0x0b04 +#define AR5K_QCU_CBB_ADDR_S 9 + +/* + * QCU compression buffer configuration register [5212+] + * (buffer size) + */ +#define AR5K_QCU_CBCFG 0x0b08 + + + +/* + * Distributed Coordination Function (DCF) control unit (DCU) + * registers [5211+] + * + * These registers control the various characteristics of each queue + * for 802.11e (WME) combatibility so they go together with + * QCU registers in pairs. For each queue we have a QCU mask register, + * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c), + * a retry limit register (0x1080 - 0x10ac), a channel time register + * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and + * a sequence number register (0x1140 - 0x116c). It seems that "global" + * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k). + * We use the same macros here for easier register access. + * + */ + +/* + * DCU QCU mask registers + */ +#define AR5K_DCU_QCUMASK_BASE 0x1000 /* Register Address -Queue0 DCU_QCUMASK */ +#define AR5K_DCU_QCUMASK_M 0x000003ff +#define AR5K_QUEUE_QCUMASK(_q) AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q) + +/* + * DCU local Inter Frame Space settings register + */ +#define AR5K_DCU_LCL_IFS_BASE 0x1040 /* Register Address -Queue0 DCU_LCL_IFS */ +#define AR5K_DCU_LCL_IFS_CW_MIN 0x000003ff /* Minimum Contention Window */ +#define AR5K_DCU_LCL_IFS_CW_MIN_S 0 +#define AR5K_DCU_LCL_IFS_CW_MAX 0x000ffc00 /* Maximum Contention Window */ +#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) + +/* + * DCU retry limit registers + */ +#define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ +#define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ +#define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 +#define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ +#define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 +#define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ +#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 +#define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ +#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 +#define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) + +/* + * DCU channel time registers + */ +#define AR5K_DCU_CHAN_TIME_BASE 0x10c0 /* Register Address -Queue0 DCU_CHAN_TIME */ +#define AR5K_DCU_CHAN_TIME_DUR 0x000fffff /* Channel time duration */ +#define AR5K_DCU_CHAN_TIME_DUR_S 0 +#define AR5K_DCU_CHAN_TIME_ENABLE 0x00100000 /* Enable channel time */ +#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q) AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q) + +/* + * DCU misc registers [5211+] + * + * 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) + * before we transmit anything else and global lockout means we + * wait for the whole queue to finish before higher priority queues + * can transmit (this is used on beacon and CAB queues). + * No lockout means there is no special handling. + */ +#define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ +#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_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 +#define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */ +#define AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM 1 /* Intra-frame lockout */ +#define AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL 2 /* Global lockout */ +#define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 /* Ignore Arbiter lockout */ +#define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment */ +#define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff */ +#define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision cw policy */ +#define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS policy (?) */ +#define AR5K_DCU_MISC_SEQNUM_CTL 0x01000000 /* Sequence number control (?) */ +#define AR5K_QUEUE_DFS_MISC(_q) AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q) + +/* + * DCU frame sequence number registers + */ +#define AR5K_DCU_SEQNUM_BASE 0x1140 +#define AR5K_DCU_SEQNUM_M 0x00000fff +#define AR5K_QUEUE_DCU_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q) + +/* + * DCU global IFS SIFS register + */ +#define AR5K_DCU_GBL_IFS_SIFS 0x1030 +#define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff + +/* + * DCU global IFS slot interval register + */ +#define AR5K_DCU_GBL_IFS_SLOT 0x1070 +#define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff + +/* + * DCU global IFS EIFS register + */ +#define AR5K_DCU_GBL_IFS_EIFS 0x10b0 +#define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff + +/* + * DCU global IFS misc register + * + * LFSR stands for Linear Feedback Shift Register + * and it's used for generating pseudo-random + * number sequences. + * + * (If i understand corectly, random numbers are + * used for idle sensing -multiplied with cwmin/max etc-) + */ +#define AR5K_DCU_GBL_IFS_MISC 0x10f0 /* Register Address */ +#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 /* LFSR Slice Select */ +#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 /* 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 */ + +/* + * DCU frame prefetch control register + */ +#define AR5K_DCU_FP 0x1230 /* Register Address */ +#define AR5K_DCU_FP_NOBURST_DCU_EN 0x00000001 /* Enable non-burst prefetch on DCU (?) */ +#define AR5K_DCU_FP_NOBURST_EN 0x00000010 /* Enable non-burst prefetch (?) */ +#define AR5K_DCU_FP_BURST_DCU_EN 0x00000020 /* Enable burst prefetch on DCU (?) */ + +/* + * DCU transmit pause control/status register + */ +#define AR5K_DCU_TXP 0x1270 /* Register Address */ +#define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask */ +#define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status */ + +/* + * DCU transmit filter table 0 (32 entries) + * each entry contains a 32bit slice of the + * 128bit tx filter for each DCU (4 slices per DCU) + */ +#define AR5K_DCU_TX_FILTER_0_BASE 0x1038 +#define AR5K_DCU_TX_FILTER_0(_n) (AR5K_DCU_TX_FILTER_0_BASE + (_n * 64)) + +/* + * DCU transmit filter table 1 (16 entries) + */ +#define AR5K_DCU_TX_FILTER_1_BASE 0x103c +#define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + (_n * 64)) + +/* + * DCU clear transmit filter register + */ +#define AR5K_DCU_TX_FILTER_CLR 0x143c + +/* + * DCU set transmit filter register + */ +#define AR5K_DCU_TX_FILTER_SET 0x147c + +/* + * Reset control register + */ +#define AR5K_RESET_CTL 0x4000 /* Register Address */ +#define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ +#define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset [5210] */ +#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset [5211+] */ +#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) */ + +/* + * Sleep control register + */ +#define AR5K_SLEEP_CTL 0x4004 /* Register Address */ +#define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /* Sleep duration mask */ +#define AR5K_SLEEP_CTL_SLDUR_S 0 +#define AR5K_SLEEP_CTL_SLE 0x00030000 /* Sleep enable mask */ +#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 /* Normal sleep policy */ +#define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ +#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 + */ +#define AR5K_INTPEND 0x4008 +#define AR5K_INTPEND_M 0x00000001 + +/* + * Sleep force register + */ +#define AR5K_SFR 0x400c +#define AR5K_SFR_EN 0x00000001 + +/* + * 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_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_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_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ +#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+] */ +#define AR5K_PCICFG_LEDMODE_PROM 0x00020000 /* Default mode (blink on any traffic) [5211+] */ +#define AR5K_PCICFG_LEDMODE_PWR 0x00040000 /* Some other blinking mode (?) [5211+] */ +#define AR5K_PCICFG_LEDMODE_RAND 0x00060000 /* Random blinking (?) [5211+] */ +#define AR5K_PCICFG_LEDBLINK 0x00700000 /* Led blink rate */ +#define AR5K_PCICFG_LEDBLINK_S 20 +#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slowest led blink rate [5211+] */ +#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 */ +#define AR5K_PCICFG_SLEEP_CLOCK_RATE_S 24 + +/* + * "General Purpose Input/Output" (GPIO) control register + * + * I'm not sure about this but after looking at the code + * for all chipsets here is what i got. + * + * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits) + * Mode 0 -> always input + * Mode 1 -> output when GPIODO for this GPIO is set to 0 + * Mode 2 -> output when GPIODO for this GPIO is set to 1 + * Mode 3 -> always output + * + * For more infos check out get_gpio/set_gpio and + * set_gpio_input/set_gpio_output functs. + * For more infos on gpio interrupt check out set_gpio_intr. + */ +#define AR5K_NUM_GPIO 6 + +#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 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 */ +#define AR5K_GPIOCR_OUT(n) (3 << ((n) * 2)) /* Mode 3 for pin n */ +#define AR5K_GPIOCR_INT_SEL(n) ((n) << 12) /* Interrupt for GPIO pin n */ + +/* + * "General Purpose Input/Output" (GPIO) data output register + */ +#define AR5K_GPIODO 0x4018 + +/* + * "General Purpose Input/Output" (GPIO) data input register + */ +#define AR5K_GPIODI 0x401c +#define AR5K_GPIODI_M 0x0000002f + +/* + * Silicon revision register + */ +#define AR5K_SREV 0x4020 /* Register Address */ +#define AR5K_SREV_REV 0x0000000f /* Mask for revision */ +#define AR5K_SREV_REV_S 0 +#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====*/ + +/* + * EEPROM access registers + * + * Here we got a difference between 5210/5211-12 + * read data register for 5210 is at 0x6800 and + * status register is at 0x6c00. There is also + * no eeprom command register on 5210 and the + * offsets are different. + * + * To read eeprom data for a specific offset: + * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) + * read AR5K_EEPROM_BASE +(4 * offset) + * check the eeprom status register + * and read eeprom data register. + * + * 5211 - write offset to AR5K_EEPROM_BASE + * 5212 write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD + * check the eeprom status register + * and read eeprom data register. + * + * To write eeprom data for a specific offset: + * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) + * write data to AR5K_EEPROM_BASE +(4 * offset) + * check the eeprom status register + * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD + * 5212 write offset to AR5K_EEPROM_BASE + * write data to data register + * write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD + * check the eeprom status register + * + * For more infos check eeprom_* functs and the ar5k.c + * file posted in madwifi-devel mailing list. + * http://sourceforge.net/mailarchive/message.php?msg_id=8966525 + * + */ +#define AR5K_EEPROM_BASE 0x6000 + +/* + * EEPROM data register + */ +#define AR5K_EEPROM_DATA_5211 0x6004 +#define AR5K_EEPROM_DATA_5210 0x6800 +#define AR5K_EEPROM_DATA (ah->ah_version == AR5K_AR5210 ? \ + AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211) + +/* + * EEPROM command register + */ +#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ +#define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ +#define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ +#define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ + +/* + * EEPROM status register + */ +#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ +#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ +#define AR5K_EEPROM_STATUS (ah->ah_version == AR5K_AR5210 ? \ + AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211) +#define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */ +#define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */ +#define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */ +#define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ + +/* + * EEPROM config register + */ +#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ +#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_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 + */ +/* + * Used for checking initial register writes + * during channel reset (see reset func) + */ +#define AR5K_PCU_MIN 0x8000 +#define AR5K_PCU_MAX 0x8fff + +/* + * First station id register (Lower 32 bits of MAC address) + */ +#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID0_ARRD_L32 0xffffffff + +/* + * Second station id register (Upper 16 bits of MAC address + PCU settings) + */ +#define AR5K_STA_ID1 0x8004 /* Register Address */ +#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ +#define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ +#define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ +#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ +#define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 /* No key search */ +#define AR5K_STA_ID1_NO_PSPOLL 0x00100000 /* No power save polling [5210] */ +#define AR5K_STA_ID1_PCF_5211 0x00100000 /* Enable PCF on [5211+] */ +#define AR5K_STA_ID1_PCF_5210 0x00200000 /* Enable PCF on [5210]*/ +#define AR5K_STA_ID1_PCF (ah->ah_version == AR5K_AR5210 ? \ + AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211) +#define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ +#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_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 /* 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) + */ +#define AR5K_BSS_ID0 0x8008 + +/* + * Second BSSID register (MAC address in upper 16 bits) + * + * AID: Association ID + */ +#define AR5K_BSS_ID1 0x800c +#define AR5K_BSS_ID1_AID 0xffff0000 +#define AR5K_BSS_ID1_AID_S 16 + +/* + * Backoff slot time register + */ +#define AR5K_SLOT_TIME 0x8010 + +/* + * ACK/CTS timeout register + */ +#define AR5K_TIME_OUT 0x8014 /* Register Address */ +#define AR5K_TIME_OUT_ACK 0x00001fff /* ACK timeout mask */ +#define AR5K_TIME_OUT_ACK_S 0 +#define AR5K_TIME_OUT_CTS 0x1fff0000 /* CTS timeout mask */ +#define AR5K_TIME_OUT_CTS_S 16 + +/* + * RSSI threshold register + */ +#define AR5K_RSSI_THR 0x8018 /* Register Address */ +#define AR5K_RSSI_THR_M 0x000000ff /* Mask for RSSI threshold [5211+] */ +#define AR5K_RSSI_THR_BMISS_5210 0x00000700 /* Mask for Beacon Missed threshold [5210] */ +#define AR5K_RSSI_THR_BMISS_5210_S 8 +#define AR5K_RSSI_THR_BMISS_5211 0x0000ff00 /* Mask for Beacon Missed threshold [5211+] */ +#define AR5K_RSSI_THR_BMISS_5211_S 8 +#define AR5K_RSSI_THR_BMISS (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211) +#define AR5K_RSSI_THR_BMISS_S 8 + +/* + * 5210 has more PCU registers because there is no QCU/DCU + * so queue parameters are set here, this way a lot common + * registers have different address for 5210. To make things + * easier we define a macro based on ah->ah_version for common + * registers with different addresses and common flags. + */ + +/* + * Retry limit register + * + * Retry limit register for 5210 (no QCU/DCU so it's done in PCU) + */ +#define AR5K_NODCU_RETRY_LMT 0x801c /* Register Address */ +#define AR5K_NODCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ +#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S 0 +#define AR5K_NODCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry mask */ +#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S 4 +#define AR5K_NODCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask */ +#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S 8 +#define AR5K_NODCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask */ +#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S 14 +#define AR5K_NODCU_RETRY_LMT_CW_MIN 0x3ff00000 /* Minimum contention window mask */ +#define AR5K_NODCU_RETRY_LMT_CW_MIN_S 20 + +/* + * Transmit latency register + */ +#define AR5K_USEC_5210 0x8020 /* Register Address [5210] */ +#define AR5K_USEC_5211 0x801c /* Register Address [5211+] */ +#define AR5K_USEC (ah->ah_version == AR5K_AR5210 ? \ + AR5K_USEC_5210 : AR5K_USEC_5211) +#define AR5K_USEC_1 0x0000007f /* clock cycles for 1us */ +#define AR5K_USEC_1_S 0 +#define AR5K_USEC_32 0x00003f80 /* clock cycles for 1us while on 32Mhz clock */ +#define AR5K_USEC_32_S 7 +#define AR5K_USEC_TX_LATENCY_5211 0x007fc000 +#define AR5K_USEC_TX_LATENCY_5211_S 14 +#define AR5K_USEC_RX_LATENCY_5211 0x1f800000 +#define AR5K_USEC_RX_LATENCY_5211_S 23 +#define AR5K_USEC_TX_LATENCY_5210 0x000fc000 /* also for 5311 */ +#define AR5K_USEC_TX_LATENCY_5210_S 14 +#define AR5K_USEC_RX_LATENCY_5210 0x03f00000 /* also for 5311 */ +#define AR5K_USEC_RX_LATENCY_5210_S 20 + +/* + * PCU beacon control register + */ +#define AR5K_BEACON_5210 0x8024 /*Register Address [5210] */ +#define AR5K_BEACON_5211 0x8020 /*Register Address [5211+] */ +#define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \ + AR5K_BEACON_5210 : AR5K_BEACON_5211) +#define AR5K_BEACON_PERIOD 0x0000ffff /* Mask for beacon period */ +#define AR5K_BEACON_PERIOD_S 0 +#define AR5K_BEACON_TIM 0x007f0000 /* Mask for TIM offset */ +#define AR5K_BEACON_TIM_S 16 +#define AR5K_BEACON_ENABLE 0x00800000 /* Enable beacons */ +#define AR5K_BEACON_RESET_TSF 0x01000000 /* Force TSF reset */ + +/* + * CFP period register + */ +#define AR5K_CFP_PERIOD_5210 0x8028 +#define AR5K_CFP_PERIOD_5211 0x8024 +#define AR5K_CFP_PERIOD (ah->ah_version == AR5K_AR5210 ? \ + AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211) + +/* + * Next beacon time register + */ +#define AR5K_TIMER0_5210 0x802c +#define AR5K_TIMER0_5211 0x8028 +#define AR5K_TIMER0 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER0_5210 : AR5K_TIMER0_5211) + +/* + * Next DMA beacon alert register + */ +#define AR5K_TIMER1_5210 0x8030 +#define AR5K_TIMER1_5211 0x802c +#define AR5K_TIMER1 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER1_5210 : AR5K_TIMER1_5211) + +/* + * Next software beacon alert register + */ +#define AR5K_TIMER2_5210 0x8034 +#define AR5K_TIMER2_5211 0x8030 +#define AR5K_TIMER2 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER2_5210 : AR5K_TIMER2_5211) + +/* + * Next ATIM window time register + */ +#define AR5K_TIMER3_5210 0x8038 +#define AR5K_TIMER3_5211 0x8034 +#define AR5K_TIMER3 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER3_5210 : AR5K_TIMER3_5211) + + +/* + * 5210 First inter frame spacing register (IFS) + */ +#define AR5K_IFS0 0x8040 +#define AR5K_IFS0_SIFS 0x000007ff +#define AR5K_IFS0_SIFS_S 0 +#define AR5K_IFS0_DIFS 0x007ff800 +#define AR5K_IFS0_DIFS_S 11 + +/* + * 5210 Second inter frame spacing register (IFS) + */ +#define AR5K_IFS1 0x8044 +#define AR5K_IFS1_PIFS 0x00000fff +#define AR5K_IFS1_PIFS_S 0 +#define AR5K_IFS1_EIFS 0x03fff000 +#define AR5K_IFS1_EIFS_S 12 +#define AR5K_IFS1_CS_EN 0x04000000 + + +/* + * CFP duration register + */ +#define AR5K_CFP_DUR_5210 0x8048 +#define AR5K_CFP_DUR_5211 0x8038 +#define AR5K_CFP_DUR (ah->ah_version == AR5K_AR5210 ? \ + AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211) + +/* + * Receive filter register + */ +#define AR5K_RX_FILTER_5210 0x804c /* Register Address [5210] */ +#define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */ +#define AR5K_RX_FILTER (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211) +#define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ +#define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ +#define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ +#define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ +#define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ +#define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ +#define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ +#define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter probe requests [5212+] */ +#define AR5K_RX_FILTER_PHYERR_5212 0x00000100 /* Don't filter phy errors [5212+] */ +#define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ +#define AR5K_RX_FILTER_PHYERR_5211 0x00000040 /* [5211] */ +#define AR5K_RX_FILTER_RADARERR_5211 0x00000080 /* [5211] */ +#define AR5K_RX_FILTER_PHYERR \ + ((ah->ah_version == AR5K_AR5211 ? \ + AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212)) +#define AR5K_RX_FILTER_RADARERR \ + ((ah->ah_version == AR5K_AR5211 ? \ + AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212)) + +/* + * Multicast filter register (lower 32 bits) + */ +#define AR5K_MCAST_FILTER0_5210 0x8050 +#define AR5K_MCAST_FILTER0_5211 0x8040 +#define AR5K_MCAST_FILTER0 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211) + +/* + * Multicast filter register (higher 16 bits) + */ +#define AR5K_MCAST_FILTER1_5210 0x8054 +#define AR5K_MCAST_FILTER1_5211 0x8044 +#define AR5K_MCAST_FILTER1 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211) + + +/* + * Transmit mask register (lower 32 bits) [5210] + */ +#define AR5K_TX_MASK0 0x8058 + +/* + * Transmit mask register (higher 16 bits) [5210] + */ +#define AR5K_TX_MASK1 0x805c + +/* + * Clear transmit mask [5210] + */ +#define AR5K_CLR_TMASK 0x8060 + +/* + * Trigger level register (before transmission) [5210] + */ +#define AR5K_TRIG_LVL 0x8064 + + +/* + * PCU control register + * + * Only DIS_RX is used in the code, the rest i guess are + * for tweaking/diagnostics. + */ +#define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ +#define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ +#define AR5K_DIAG_SW (ah->ah_version == AR5K_AR5210 ? \ + AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211) +#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */ +#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */ +#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */ +#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */ +#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */ +#define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ +#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ +#define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 +#define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ + AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) +#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ +#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 /* 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 /* 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_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+] */ +#define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ +#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */ +#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 /* 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 /* Observation point select (?) */ +#define AR5K_DIAG_SW_OBSPT_S 18 +#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) + */ +#define AR5K_TSF_L32_5210 0x806c +#define AR5K_TSF_L32_5211 0x804c +#define AR5K_TSF_L32 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211) + +/* + * TSF (clock) register (higher 32 bits) + */ +#define AR5K_TSF_U32_5210 0x8070 +#define AR5K_TSF_U32_5211 0x8050 +#define AR5K_TSF_U32 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211) + +/* + * Last beacon timestamp register (Read Only) + */ +#define AR5K_LAST_TSTP 0x8080 + +/* + * ADDAC test register [5211+] + */ +#define AR5K_ADDAC_TEST 0x8054 /* Register Address */ +#define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */ +#define AR5K_ADDAC_TEST_TST_MODE 0x00000002 /* Test mode */ +#define AR5K_ADDAC_TEST_LOOP_EN 0x00000004 /* Enable loop */ +#define AR5K_ADDAC_TEST_LOOP_LEN 0x00000008 /* Loop length (field) */ +#define AR5K_ADDAC_TEST_USE_U8 0x00004000 /* Use upper 8 bits */ +#define AR5K_ADDAC_TEST_MSB 0x00008000 /* State of MSB */ +#define AR5K_ADDAC_TEST_TRIG_SEL 0x00010000 /* Trigger select */ +#define AR5K_ADDAC_TEST_TRIG_PTY 0x00020000 /* Trigger polarity */ +#define AR5K_ADDAC_TEST_RXCONT 0x00040000 /* Continuous capture */ +#define AR5K_ADDAC_TEST_CAPTURE 0x00080000 /* Begin capture */ +#define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* ARM rx buffer for capture */ + +/* + * Default antenna register [5211+] + */ +#define AR5K_DEFAULT_ANTENNA 0x8058 + +/* + * Frame control QoS mask register (?) [5211+] + * (FC_QOS_MASK) + */ +#define AR5K_FRAME_CTL_QOSM 0x805c + +/* + * Seq mask register (?) [5211+] + */ +#define AR5K_SEQ_MASK 0x8060 + +/* + * Retry count register [5210] + */ +#define AR5K_RETRY_CNT 0x8084 /* Register Address [5210] */ +#define AR5K_RETRY_CNT_SSH 0x0000003f /* Station short retry count (?) */ +#define AR5K_RETRY_CNT_SLG 0x00000fc0 /* Station long retry count (?) */ + +/* + * Back-off status register [5210] + */ +#define AR5K_BACKOFF 0x8088 /* Register Address [5210] */ +#define AR5K_BACKOFF_CW 0x000003ff /* Backoff Contention Window (?) */ +#define AR5K_BACKOFF_CNT 0x03ff0000 /* Backoff count (?) */ + + + +/* + * NAV register (current) + */ +#define AR5K_NAV_5210 0x808c +#define AR5K_NAV_5211 0x8084 +#define AR5K_NAV (ah->ah_version == AR5K_AR5210 ? \ + AR5K_NAV_5210 : AR5K_NAV_5211) + +/* + * RTS success register + */ +#define AR5K_RTS_OK_5210 0x8090 +#define AR5K_RTS_OK_5211 0x8088 +#define AR5K_RTS_OK (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) + +/* + * RTS failure register + */ +#define AR5K_RTS_FAIL_5210 0x8094 +#define AR5K_RTS_FAIL_5211 0x808c +#define AR5K_RTS_FAIL (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) + +/* + * ACK failure register + */ +#define AR5K_ACK_FAIL_5210 0x8098 +#define AR5K_ACK_FAIL_5211 0x8090 +#define AR5K_ACK_FAIL (ah->ah_version == AR5K_AR5210 ? \ + AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) + +/* + * FCS failure register + */ +#define AR5K_FCS_FAIL_5210 0x809c +#define AR5K_FCS_FAIL_5211 0x8094 +#define AR5K_FCS_FAIL (ah->ah_version == AR5K_AR5210 ? \ + AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211) + +/* + * Beacon count register + */ +#define AR5K_BEACON_CNT_5210 0x80a0 +#define AR5K_BEACON_CNT_5211 0x8098 +#define AR5K_BEACON_CNT (ah->ah_version == AR5K_AR5210 ? \ + AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211) + + +/*===5212 Specific PCU registers===*/ + +/* + * Transmit power control register + */ +#define AR5K_TPC 0x80e8 +#define AR5K_TPC_ACK 0x0000003f /* ack frames */ +#define AR5K_TPC_ACK_S 0 +#define AR5K_TPC_CTS 0x00003f00 /* cts frames */ +#define AR5K_TPC_CTS_S 8 +#define AR5K_TPC_CHIRP 0x003f0000 /* chirp frames */ +#define AR5K_TPC_CHIRP_S 16 +#define AR5K_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ +#define AR5K_TPC_DOPPLER_S 24 + +/* + * XR (eXtended Range) mode register + */ +#define AR5K_XRMODE 0x80c0 /* Register Address */ +#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f /* Mask for Poll type (?) */ +#define AR5K_XRMODE_POLL_TYPE_S 0 +#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c /* Mask for Poll subtype (?) */ +#define AR5K_XRMODE_POLL_SUBTYPE_S 2 +#define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 /* Wait for poll */ +#define AR5K_XRMODE_SIFS_DELAY 0x000fff00 /* Mask for SIFS delay */ +#define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 /* Mask for frame hold (?) */ +#define AR5K_XRMODE_FRAME_HOLD_S 20 + +/* + * XR delay register + */ +#define AR5K_XRDELAY 0x80c4 /* Register Address */ +#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff /* Mask for slot delay */ +#define AR5K_XRDELAY_SLOT_DELAY_S 0 +#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 /* Mask for CHIRP data delay */ +#define AR5K_XRDELAY_CHIRP_DELAY_S 16 + +/* + * XR timeout register + */ +#define AR5K_XRTIMEOUT 0x80c8 /* Register Address */ +#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff /* Mask for CHIRP timeout */ +#define AR5K_XRTIMEOUT_CHIRP_S 0 +#define AR5K_XRTIMEOUT_POLL_M 0xffff0000 /* Mask for Poll timeout */ +#define AR5K_XRTIMEOUT_POLL_S 16 + +/* + * XR chirp register + */ +#define AR5K_XRCHIRP 0x80cc /* Register Address */ +#define AR5K_XRCHIRP_SEND 0x00000001 /* Send CHIRP */ +#define AR5K_XRCHIRP_GAP 0xffff0000 /* Mask for CHIRP gap (?) */ + +/* + * XR stomp register + */ +#define AR5K_XRSTOMP 0x80d0 /* Register Address */ +#define AR5K_XRSTOMP_TX 0x00000001 /* Stomp Tx (?) */ +#define AR5K_XRSTOMP_RX 0x00000002 /* Stomp Rx (?) */ +#define AR5K_XRSTOMP_TX_RSSI 0x00000004 /* Stomp Tx RSSI (?) */ +#define AR5K_XRSTOMP_TX_BSSID 0x00000008 /* Stomp Tx BSSID (?) */ +#define AR5K_XRSTOMP_DATA 0x00000010 /* Stomp data (?)*/ +#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 /* Mask for XR RSSI threshold */ + +/* + * First enhanced sleep register + */ +#define AR5K_SLEEP0 0x80d4 /* Register Address */ +#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff /* Mask for next DTIM (?) */ +#define AR5K_SLEEP0_NEXT_DTIM_S 0 +#define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 /* Assume DTIM */ +#define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 /* Enable enchanced sleep control */ +#define AR5K_SLEEP0_CABTO 0xff000000 /* Mask for CAB Time Out */ +#define AR5K_SLEEP0_CABTO_S 24 + +/* + * Second enhanced sleep register + */ +#define AR5K_SLEEP1 0x80d8 /* Register Address */ +#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff /* Mask for next TIM (?) */ +#define AR5K_SLEEP1_NEXT_TIM_S 0 +#define AR5K_SLEEP1_BEACON_TO 0xff000000 /* Mask for Beacon Time Out */ +#define AR5K_SLEEP1_BEACON_TO_S 24 + +/* + * Third enhanced sleep register + */ +#define AR5K_SLEEP2 0x80dc /* Register Address */ +#define AR5K_SLEEP2_TIM_PER 0x0000ffff /* Mask for TIM period (?) */ +#define AR5K_SLEEP2_TIM_PER_S 0 +#define AR5K_SLEEP2_DTIM_PER 0xffff0000 /* Mask for DTIM period (?) */ +#define AR5K_SLEEP2_DTIM_PER_S 16 + +/* + * BSSID mask registers + */ +#define AR5K_BSS_IDM0 0x80e0 /* Upper bits */ +#define AR5K_BSS_IDM1 0x80e4 /* Lower bits */ + +/* + * TX power control (TPC) register + * + * XXX: PCDAC steps (0.5dbm) or DBM ? + * + */ +#define AR5K_TXPC 0x80e8 /* Register Address */ +#define AR5K_TXPC_ACK_M 0x0000003f /* ACK tx power */ +#define AR5K_TXPC_ACK_S 0 +#define AR5K_TXPC_CTS_M 0x00003f00 /* CTS tx power */ +#define AR5K_TXPC_CTS_S 8 +#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 + */ +#define AR5K_PROFCNT_TX 0x80ec /* Tx count */ +#define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ +#define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ +#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ + +/* + * Quiet period control registers + */ +#define AR5K_QUIET_CTL1 0x80fc /* Register Address */ +#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 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 + */ +#define AR5K_TSF_PARM 0x8104 /* Register Address */ +#define AR5K_TSF_PARM_INC 0x000000ff /* Mask for TSF increment */ +#define AR5K_TSF_PARM_INC_S 0 + +/* + * QoS NOACK policy + */ +#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 7 + +/* + * PHY error filter register + */ +#define AR5K_PHY_ERR_FIL 0x810c +#define AR5K_PHY_ERR_FIL_RADAR 0x00000020 /* Radar signal */ +#define AR5K_PHY_ERR_FIL_OFDM 0x00020000 /* OFDM false detect (ANI) */ +#define AR5K_PHY_ERR_FIL_CCK 0x02000000 /* CCK false detect (ANI) */ + +/* + * XR latency register + */ +#define AR5K_XRLAT_TX 0x8110 + +/* + * ACK SIFS register + */ +#define AR5K_ACKSIFS 0x8114 /* Register Address */ +#define AR5K_ACKSIFS_INC 0x00000000 /* ACK SIFS Increment (field) */ + +/* + * MIC QoS control register (?) + */ +#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_OFF(_n) (1 << (_n * 4)) + +/* + * Misc mode control register (?) + */ +#define AR5K_MISC_MODE 0x8120 /* Register Address */ +#define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ +#define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ +#define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */ +/* more bits */ + +/* + * OFDM Filter counter + */ +#define AR5K_OFDM_FIL_CNT 0x8124 + +/* + * CCK Filter counter + */ +#define AR5K_CCK_FIL_CNT 0x8128 + +/* + * PHY Error Counters (?) + */ +#define AR5K_PHYERR_CNT1 0x812c +#define AR5K_PHYERR_CNT1_MASK 0x8130 + +#define AR5K_PHYERR_CNT2 0x8134 +#define AR5K_PHYERR_CNT2_MASK 0x8138 + +/* + * TSF Threshold register (?) + */ +#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 */ +#define AR5K_RATE_ACKSIFS(_n) (AR5K_RATE_ACKSIFS_BSE + ((_n) << 2)) +#define AR5K_RATE_ACKSIFS_NORMAL 0x00000001 /* Normal SIFS (field) */ +#define AR5K_RATE_ACKSIFS_TURBO 0x00000400 /* Turbo SIFS (field) */ + +/* + * Rate -> duration mapping table (32 entries) + */ +#define AR5K_RATE_DUR_BASE 0x8700 +#define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2)) + +/* + * Rate -> db mapping table + * (8 entries, each one has 4 8bit fields) + */ +#define AR5K_RATE2DB_BASE 0x87c0 +#define AR5K_RATE2DB(_n) (AR5K_RATE2DB_BASE + ((_n) << 2)) + +/* + * db -> Rate mapping table + * (8 entries, each one has 4 8bit fields) + */ +#define AR5K_DB2RATE_BASE 0x87e0 +#define AR5K_DB2RATE(_n) (AR5K_DB2RATE_BASE + ((_n) << 2)) + +/*===5212 end===*/ + +/* + * Key table (WEP) register + */ +#define AR5K_KEYTABLE_0_5210 0x9000 +#define AR5K_KEYTABLE_0_5211 0x8800 +#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5)) +#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) +#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \ + AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n)) +#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2)) +#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5) +#define AR5K_KEYTABLE_TYPE_40 0x00000000 +#define AR5K_KEYTABLE_TYPE_104 0x00000001 +#define AR5K_KEYTABLE_TYPE_128 0x00000003 +#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */ +#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */ +#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */ +#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */ +#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */ +#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6) +#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) +#define AR5K_KEYTABLE_VALID 0x00008000 + +/* If key type is TKIP and MIC is enabled + * MIC key goes in offset entry + 64 */ +#define AR5K_KEYTABLE_MIC_OFFSET 64 + +/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit + * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit + * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit + * + * Some vendors have introduced bigger WEP keys to address + * security vulnerabilities in WEP. This includes: + * + * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit + * + * We can expand this if we find ar5k Atheros cards with a larger + * key table size. + */ +#define AR5K_KEYTABLE_SIZE_5210 64 +#define AR5K_KEYTABLE_SIZE_5211 128 +#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \ + AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211) + + +/*===PHY REGISTERS===*/ + +/* + * PHY registers start + */ +#define AR5K_PHY_BASE 0x9800 +#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) + +/* + * TST_2 (Misc config parameters) + */ +#define AR5K_PHY_TST2 0x9800 /* Register Address */ +#define AR5K_PHY_TST2_TRIG_SEL 0x00000007 /* Trigger select (?)*/ +#define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) */ +#define AR5K_PHY_TST2_CBUS_MODE 0x00000060 /* Cardbus mode (?) */ +#define AR5K_PHY_TST2_CLK32 0x00000400 /* CLK_OUT is CLK32 (32Khz external) */ +#define AR5K_PHY_TST2_CHANCOR_DUMP_EN 0x00000800 /* Enable Chancor dump (?) */ +#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP 0x00001000 /* Even Chancor dump (?) */ +#define AR5K_PHY_TST2_RFSILENT_EN 0x00002000 /* Enable RFSILENT */ +#define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch ?) */ +#define AR5K_PHY_TST2_MINI_OBS_EN 0x00008000 /* Enable mini OBS (?) */ +#define AR5K_PHY_TST2_RX2_IS_RX5_INV 0x00010000 /* 2GHz rx path is the 5GHz path inverted (?) */ +#define AR5K_PHY_TST2_SLOW_CLK160 0x00020000 /* Slow CLK160 (?) */ +#define AR5K_PHY_TST2_AGC_OBS_SEL_3 0x00040000 /* AGC OBS Select 3 (?) */ +#define AR5K_PHY_TST2_BBB_OBS_SEL 0x00080000 /* BB OBS Select (field ?) */ +#define AR5K_PHY_TST2_ADC_OBS_SEL 0x00800000 /* ADC OBS Select (field ?) */ +#define AR5K_PHY_TST2_RX_CLR_SEL 0x08000000 /* RX Clear Select (?) */ +#define AR5K_PHY_TST2_FORCE_AGC_CLR 0x10000000 /* Force AGC clear (?) */ +#define AR5K_PHY_SHIFT_2GHZ 0x00004007 /* Used to access 2GHz radios */ +#define AR5K_PHY_SHIFT_5GHZ 0x00000007 /* Used to access 5GHz radios (default) */ + +/* + * PHY frame control register [5110] /turbo mode register [5111+] + * + * There is another frame control register for [5111+] + * at address 0x9944 (see below) but the 2 first flags + * are common here between 5110 frame control register + * and [5111+] turbo mode register, so this also works as + * a "turbo mode register" for 5110. We treat this one as + * a frame control register for 5110 below. + */ +#define AR5K_PHY_TURBO 0x9804 /* Register Address */ +#define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ +#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 + * (aka TST_1) + */ +#define AR5K_PHY_AGC 0x9808 /* Register Address */ +#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+] + */ +#define AR5K_PHY_TIMING_3 0x9814 +#define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000 +#define AR5K_PHY_TIMING_3_DSC_MAN_S 17 +#define AR5K_PHY_TIMING_3_DSC_EXP 0x0001e000 +#define AR5K_PHY_TIMING_3_DSC_EXP_S 13 + +/* + * PHY chip revision register + */ +#define AR5K_PHY_CHIP_ID 0x9818 + +/* + * PHY activation register + */ +#define AR5K_PHY_ACT 0x981c /* Register Address */ +#define AR5K_PHY_ACT_ENABLE 0x00000001 /* Activate PHY */ +#define AR5K_PHY_ACT_DISABLE 0x00000002 /* Deactivate PHY */ + +/* + * PHY RF control registers + */ +#define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */ +#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 0x0000ff00 /* TX end to XLNA on */ +#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 8 + +#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) */ +#define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON 0x00000100 /* TX frame to XPA B on (field) */ +#define AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF 0x00010000 /* TX end to XPA A off (field) */ +#define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF 0x01000000 /* TX end to XPA B off (field) */ + +/* + * Pre-Amplifier control register + * (XPA -> external pre-amplifier) + */ +#define AR5K_PHY_PA_CTL 0x9838 /* Register Address */ +#define AR5K_PHY_PA_CTL_XPA_A_HI 0x00000001 /* XPA A high (?) */ +#define AR5K_PHY_PA_CTL_XPA_B_HI 0x00000002 /* XPA B high (?) */ +#define AR5K_PHY_PA_CTL_XPA_A_EN 0x00000004 /* Enable XPA A */ +#define AR5K_PHY_PA_CTL_XPA_B_EN 0x00000008 /* Enable XPA B */ + +/* + * PHY settling register + */ +#define AR5K_PHY_SETTLING 0x9844 /* Register Address */ +#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_SETTLING_SWITCH_S 7 + +/* + * PHY Gain registers + */ +#define AR5K_PHY_GAIN 0x9848 /* Register Address */ +#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 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 /* 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 /* FIRSTEP */ +#define AR5K_PHY_SIG_FIRSTEP_S 12 +#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* FIPWR */ +#define AR5K_PHY_SIG_FIRPWR_S 18 + +/* + * PHY coarse agility control register + * (for more infos read ANI patent) + */ +#define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */ +#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* AGC Coarse low */ +#define AR5K_PHY_AGCCOARSE_LO_S 7 +#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* AGC Coarse high */ +#define AR5K_PHY_AGCCOARSE_HI_S 15 + +/* + * PHY agility control register + */ +#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 + */ +#define AR5K_PHY_NF 0x9864 /* Register address */ +#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ +#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ +#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 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] + */ +#define AR5K_PHY_ADCSAT 0x9868 +#define AR5K_PHY_ADCSAT_ICNT 0x0001f800 +#define AR5K_PHY_ADCSAT_ICNT_S 11 +#define AR5K_PHY_ADCSAT_THR 0x000007e0 +#define AR5K_PHY_ADCSAT_THR_S 5 + +/* + * PHY Weak ofdm signal detection threshold registers (ANI) [5212+] + */ + +/* High thresholds */ +#define AR5K_PHY_WEAK_OFDM_HIGH_THR 0x9868 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT 0x0000001f +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S 0 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1 0x00fe0000 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S 17 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2 0x7f000000 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S 24 + +/* Low thresholds */ +#define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c +#define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN 0x00000001 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT 0x00003f00 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S 8 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1 0x001fc000 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S 14 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2 0x0fe00000 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S 21 + + +/* + * PHY sleep registers [5112+] + */ +#define AR5K_PHY_SCR 0x9870 + +#define AR5K_PHY_SLMT 0x9874 +#define AR5K_PHY_SLMT_32MHZ 0x0000007f + +#define AR5K_PHY_SCAL 0x9878 +#define AR5K_PHY_SCAL_32MHZ 0x0000000e +#define AR5K_PHY_SCAL_32MHZ_2417 0x0000000a +#define AR5K_PHY_SCAL_32MHZ_HB63 0x00000032 + +/* + * PHY PLL (Phase Locked Loop) control register + */ +#define AR5K_PHY_PLL 0x987c +#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) +/* 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 +#define AR5K_PHY_PLL_QUARTER_RATE 0x00000200 + +/* + * RF Buffer register + * + * It's obvious from the code that 0x989c is the buffer register but + * for the other special registers that we write to after sending each + * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers + * for now. It's interesting that they are also used for some other operations. + */ + +#define AR5K_RF_BUFFER 0x989c +#define AR5K_RF_BUFFER_CONTROL_0 0x98c0 /* Channel on 5110 */ +#define AR5K_RF_BUFFER_CONTROL_1 0x98c4 /* Bank 7 on 5112 */ +#define AR5K_RF_BUFFER_CONTROL_2 0x98cc /* Bank 7 on 5111 */ + +#define AR5K_RF_BUFFER_CONTROL_3 0x98d0 /* Bank 2 on 5112 */ + /* Channel set on 5111 */ + /* Used to read radio revision*/ + +#define AR5K_RF_BUFFER_CONTROL_4 0x98d4 /* RF Stage register on 5110 */ + /* Bank 0,1,2,6 on 5111 */ + /* Bank 1 on 5112 */ + /* Used during activation on 5111 */ + +#define AR5K_RF_BUFFER_CONTROL_5 0x98d8 /* Bank 3 on 5111 */ + /* Used during activation on 5111 */ + /* Channel on 5112 */ + /* Bank 6 on 5112 */ + +#define AR5K_RF_BUFFER_CONTROL_6 0x98dc /* Bank 3 on 5112 */ + +/* + * PHY RF stage register [5210] + */ +#define AR5K_PHY_RFSTG 0x98d4 +#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 */ +#define AR5K_PHY_ANT_CTL_TXRX_EN 0x00000001 /* Enable TX/RX (?) */ +#define AR5K_PHY_ANT_CTL_SECTORED_ANT 0x00000004 /* Sectored Antenna */ +#define AR5K_PHY_ANT_CTL_HITUNE5 0x00000008 /* Hitune5 (?) */ +#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x000003f0 /* Switch table idle (?) */ +#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S 4 + +/* + * PHY receiver delay register [5111+] + */ +#define AR5K_PHY_RX_DELAY 0x9914 /* Register Address */ +#define AR5K_PHY_RX_DELAY_M 0x00003fff /* Mask for RX activate to receive delay (/100ns) */ + +/* + * PHY max rx length register (?) [5111] + */ +#define AR5K_PHY_MAX_RX_LEN 0x991c + +/* + * PHY timing register 4 + * I(nphase)/Q(adrature) calibration register [5111+] + */ +#define AR5K_PHY_IQ 0x9920 /* Register Address */ +#define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ +#define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ +#define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 +#define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ +#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 /* Mask for max number of samples in log scale */ +#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S 12 +#define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */ +#define AR5K_PHY_IQ_USE_PT_DF 0x00020000 /* Use pilot track df (?) */ +#define AR5K_PHY_IQ_EARLY_TRIG_THR 0x00200000 /* Early trigger threshold (?) (field) */ +#define AR5K_PHY_IQ_PILOT_MASK_EN 0x10000000 /* Enable pilot mask (?) */ +#define AR5K_PHY_IQ_CHAN_MASK_EN 0x20000000 /* Enable channel mask (?) */ +#define AR5K_PHY_IQ_SPUR_FILT_EN 0x40000000 /* Enable spur filter */ +#define AR5K_PHY_IQ_SPUR_RSSI_EN 0x80000000 /* Enable spur rssi */ + +/* + * PHY timing register 5 + * OFDM Self-correlator Cyclic RSSI threshold params + * (Check out bb_cycpwr_thr1 on ANI patent) + */ +#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 1 +#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) (?) */ +#define AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI 0x00800000 /* Long sc threshold hi rssi (?) */ + +/* + * PHY-only warm reset register + */ +#define AR5K_PHY_WARM_RESET 0x9928 + +/* + * PHY-only control register + */ +#define AR5K_PHY_CTL 0x992c /* Register Address */ +#define AR5K_PHY_CTL_RX_DRAIN_RATE 0x00000001 /* RX drain rate (?) */ +#define AR5K_PHY_CTL_LATE_TX_SIG_SYM 0x00000002 /* Late tx signal symbol (?) */ +#define AR5K_PHY_CTL_GEN_SCRAMBLER 0x00000004 /* Generate scrambler */ +#define AR5K_PHY_CTL_TX_ANT_SEL 0x00000008 /* TX antenna select */ +#define AR5K_PHY_CTL_TX_ANT_STATIC 0x00000010 /* Static TX antenna */ +#define AR5K_PHY_CTL_RX_ANT_SEL 0x00000020 /* RX antenna select */ +#define AR5K_PHY_CTL_RX_ANT_STATIC 0x00000040 /* Static RX antenna */ +#define AR5K_PHY_CTL_LOW_FREQ_SLE_EN 0x00000080 /* Enable low freq sleep */ + +/* + * PHY PAPD probe register [5111+] + */ +#define AR5K_PHY_PAPD_PROBE 0x9930 +#define AR5K_PHY_PAPD_PROBE_SH_HI_PAR 0x00000001 +#define AR5K_PHY_PAPD_PROBE_PCDAC_BIAS 0x00000002 +#define AR5K_PHY_PAPD_PROBE_COMP_GAIN 0x00000040 +#define AR5K_PHY_PAPD_PROBE_TXPOWER 0x00007e00 +#define AR5K_PHY_PAPD_PROBE_TXPOWER_S 9 +#define AR5K_PHY_PAPD_PROBE_TX_NEXT 0x00008000 +#define AR5K_PHY_PAPD_PROBE_PREDIST_EN 0x00010000 +#define AR5K_PHY_PAPD_PROBE_TYPE 0x01800000 /* [5112+] */ +#define AR5K_PHY_PAPD_PROBE_TYPE_S 23 +#define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0 +#define AR5K_PHY_PAPD_PROBE_TYPE_XR 1 +#define AR5K_PHY_PAPD_PROBE_TYPE_CCK 2 +#define AR5K_PHY_PAPD_PROBE_GAINF 0xfe000000 +#define AR5K_PHY_PAPD_PROBE_GAINF_S 25 +#define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ +#define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ + +/* + * PHY TX rate power registers [5112+] + */ +#define AR5K_PHY_TXPOWER_RATE1 0x9934 +#define AR5K_PHY_TXPOWER_RATE2 0x9938 +#define AR5K_PHY_TXPOWER_RATE_MAX 0x993c +#define AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE 0x00000040 +#define AR5K_PHY_TXPOWER_RATE3 0xa234 +#define AR5K_PHY_TXPOWER_RATE4 0xa238 + +/* + * PHY frame control register [5111+] + */ +#define AR5K_PHY_FRAME_CTL_5210 0x9804 +#define AR5K_PHY_FRAME_CTL_5211 0x9944 +#define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \ + AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211) +/*---[5111+]---*/ +#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 */ +#define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* Illegal rate */ +#define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* Illegal length */ +#define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000 +#define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* TX underrun */ +#define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ + AR5K_PHY_FRAME_CTL_TXURN_ERR | \ + AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ + AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ + AR5K_PHY_FRAME_CTL_PARITY_ERR | \ + AR5K_PHY_FRAME_CTL_TIMING_ERR + +/* + * PHY Tx Power adjustment register [5212A+] + */ +#define AR5K_PHY_TX_PWR_ADJ 0x994c +#define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA 0x00000fc0 +#define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S 6 +#define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX 0x00fc0000 +#define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S 18 + +/* + * PHY radar detection register [5111+] + */ +#define AR5K_PHY_RADAR 0x9954 +#define AR5K_PHY_RADAR_ENABLE 0x00000001 +#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 + */ +#define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 +#define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 + +/* + * PHY Noise floor threshold + */ +#define AR5K_PHY_NFTHRES 0x9968 + +/* + * Sigma Delta register (?) [5213] + */ +#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 0x01ffe000 +#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 AR5K_PHY_TIMING_9 0x9998 +#define AR5K_PHY_TIMING_10 0x999c +#define AR5K_PHY_TIMING_10_PILOT_MASK_2 0x000fffff +#define AR5K_PHY_TIMING_10_PILOT_MASK_2_S 0 + +/* + * Spur mitigation control + */ +#define AR5K_PHY_TIMING_11 0x99a0 /* Register address */ +#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */ +#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0 +#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */ +#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S 20 +#define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */ +#define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */ + +/* + * 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)) +#define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */ +#define AR5K_RF_GAIN(_n) (AR5K_RF_GAIN_BASE + ((_n) << 2)) + +/* + * PHY timing IQ calibration result register [5111+] + */ +#define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */ +#define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */ +#define AR5K_PHY_IQRES_CAL_CORR 0x9c18 /* I/Q Correlation */ + +/* + * PHY current RSSI register [5111+] + */ +#define AR5K_PHY_CURRENT_RSSI 0x9c1c + +/* + * PHY RF Bus grant register + */ +#define AR5K_PHY_RFBUS_GRANT 0x9c20 +#define AR5K_PHY_RFBUS_GRANT_OK 0x00000001 + +/* + * PHY ADC test register + */ +#define AR5K_PHY_ADC_TEST 0x9c24 +#define AR5K_PHY_ADC_TEST_I 0x00000001 +#define AR5K_PHY_ADC_TEST_Q 0x00000200 + +/* + * PHY DAC test register + */ +#define AR5K_PHY_DAC_TEST 0x9c28 +#define AR5K_PHY_DAC_TEST_I 0x00000001 +#define AR5K_PHY_DAC_TEST_Q 0x00000200 + +/* + * PHY PTAT register (?) + */ +#define AR5K_PHY_PTAT 0x9c2c + +/* + * PHY Illegal TX rate register [5112+] + */ +#define AR5K_PHY_BAD_TX_RATE 0x9c30 + +/* + * PHY SPUR Power register [5112+] + */ +#define AR5K_PHY_SPUR_PWR 0x9c34 /* Register Address */ +#define AR5K_PHY_SPUR_PWR_I 0x00000001 /* SPUR Power estimate for I (field) */ +#define AR5K_PHY_SPUR_PWR_Q 0x00000100 /* SPUR Power estimate for Q (field) */ +#define AR5K_PHY_SPUR_PWR_FILT 0x00010000 /* Power with SPUR removed (field) */ + +/* + * PHY Channel status register [5112+] (?) + */ +#define AR5K_PHY_CHAN_STATUS 0x9c38 +#define AR5K_PHY_CHAN_STATUS_BT_ACT 0x00000001 +#define AR5K_PHY_CHAN_STATUS_RX_CLR_RAW 0x00000002 +#define AR5K_PHY_CHAN_STATUS_RX_CLR_MAC 0x00000004 +#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 + + +/* + * PHY PAPD I (power?) table (?) + * (92! entries) + */ +#define AR5K_PHY_PAPD_I_BASE 0xa000 +#define AR5K_PHY_PAPD_I(_n) (AR5K_PHY_PAPD_I_BASE + ((_n) << 2)) + +/* + * PHY PCDAC TX power table + */ +#define AR5K_PHY_PCDAC_TXPOWER_BASE 0xa180 +#define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2)) + +/* + * PHY mode register [5111+] + */ +#define AR5K_PHY_MODE 0x0a200 /* Register Address */ +#define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation bit */ +#define AR5K_PHY_MODE_MOD_OFDM 0 +#define AR5K_PHY_MODE_MOD_CCK 1 +#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode bit */ +#define AR5K_PHY_MODE_FREQ_5GHZ 0 +#define AR5K_PHY_MODE_FREQ_2GHZ 2 +#define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Enable Dynamic OFDM/CCK mode [5112+] */ +#define AR5K_PHY_MODE_RAD 0x00000008 /* [5212+] */ +#define AR5K_PHY_MODE_RAD_RF5111 0 +#define AR5K_PHY_MODE_RAD_RF5112 8 +#define AR5K_PHY_MODE_XR 0x00000010 /* Enable XR mode [5112+] */ +#define AR5K_PHY_MODE_HALF_RATE 0x00000020 /* Enable Half rate (test) */ +#define AR5K_PHY_MODE_QUARTER_RATE 0x00000040 /* Enable Quarter rat (test) */ + +/* + * PHY CCK transmit control register [5111+ (?)] + */ +#define AR5K_PHY_CCKTXCTL 0xa204 +#define AR5K_PHY_CCKTXCTL_WORLD 0x00000000 +#define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010 +#define AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS 0x00000001 +#define AR5K_PHY_CCKTXCTK_DAC_SCALE 0x00000004 + +/* + * PHY CCK Cross-correlator Barker RSSI threshold register [5212+] + */ +#define AR5K_PHY_CCK_CROSSCORR 0xa208 +#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_MARGIN_TXRX_S 18 +#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_RG1_PDGAIN_1 0x00030000 +#define AR5K_PHY_TPC_RG1_PDGAIN_1_S 16 +#define AR5K_PHY_TPC_RG1_PDGAIN_2 0x000c0000 +#define AR5K_PHY_TPC_RG1_PDGAIN_2_S 18 +#define AR5K_PHY_TPC_RG1_PDGAIN_3 0x00300000 +#define AR5K_PHY_TPC_RG1_PDGAIN_3_S 20 + +#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 + +/* + * PHY PDADC Tx power table + */ +#define AR5K_PHY_PDADC_TXPOWER_BASE 0xa280 +#define AR5K_PHY_PDADC_TXPOWER(_n) (AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2)) diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c new file mode 100644 index 0000000..775fdf7 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -0,0 +1,1346 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Luis Rodriguez + * Copyright (c) 2007-2008 Pavel Roskin + * Copyright (c) 2007-2008 Jiri Slaby + * + * 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 /* To determine if a card is pci-e */ +#include /* For get_bitmask_order */ +#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 delta slope coefficient (used on pilot tracking ?) for OFDM + * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset(). + * + * Since delta slope is floating point we split it on its exponent and + * mantissa and provide these values on hw. + * + * For more infos i think this patent is related + * http://www.freepatentsonline.com/7184495.html + */ +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; + + BUG_ON(!(ah->ah_version == AR5K_AR5212) || + !(channel->hw_value & CHANNEL_OFDM)); + + /* Get coefficient + * ALGO: coef = (5 * clock * carrier_freq) / 2) + * we scale coef by shifting clock value by 24 for + * better precision since we use integers */ + /* TODO: Half/quarter rate */ + clock = ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO); + + coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq; + + /* Get exponent + * ALGO: coef_exp = 14 - highest set bit position */ + coef_exp = get_bitmask_order(coef_scaled); + + /* Doesn't make sense if it's zero*/ + if (!coef_exp) + return -EINVAL; + + /* Note: we've shifted coef_scaled by 24 */ + coef_exp = 14 - (coef_exp - 24); + + + /* Get mantissa (significant digits) + * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */ + coef_man = coef_scaled + + (1 << (24 - coef_exp - 1)); + + /* Calculate delta slope coefficient exponent + * and mantissa (remove scaling) and set them on hw */ + 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 const unsigned int control_rates[] = + { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; + +/** + * ath5k_hw_write_rate_duration - fill rate code to duration table + * + * @ah: the &struct ath5k_hw + * @mode: one of enum ath5k_driver_mode + * + * Write the rate code to duration table upon hw reset. This is a helper for + * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on + * the hardware, based on current mode, for each rate. The rates which are + * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have + * different rate code so we write their value twice (one for long preample + * and one for short). + * + * Note: Band doesn't matter here, if we set the values for OFDM it works + * on both a and g modes. So all we have to do is set values for all g rates + * that include all OFDM and CCK rates. If we operate in turbo or xr/half/ + * quarter rate mode, we need to use another set of bitrates (that's why we + * need the mode parameter) but we don't handle these proprietary modes yet. + */ +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 and program PLL + * TODO: Half/Quarter rate support + */ +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; + + if (ah->ah_radio == AR5K_RF5413) + clock = AR5K_PHY_PLL_40MHZ_5413; + else + 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) { + + /* ...update PLL if needed */ + if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) { + ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); + udelay(300); + } + + /* ...set the PHY operating mode */ + ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); + ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); + } + + return 0; +} + +/* + * If there is an external 32KHz crystal available, use it + * as ref. clock instead of 32/40MHz clock and baseband clocks + * to save power during sleep or restore normal 32/40MHz + * operation. + * + * XXX: When operating on 32KHz certain PHY registers (27 - 31, + * 123 - 127) require delay on access. + */ +static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 scal, spending, usec32; + + /* Only set 32KHz settings if we have an external + * 32KHz crystal present */ + if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) || + AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) && + enable) { + + /* 1 usec/cycle */ + AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1); + /* Set up tsf increment on each cycle */ + AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61); + + /* Set baseband sleep control registers + * and sleep control rate */ + ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR); + + if ((ah->ah_radio == AR5K_RF5112) || + (ah->ah_radio == AR5K_RF5413) || + (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) + spending = 0x14; + else + spending = 0x18; + ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING); + + if ((ah->ah_radio == AR5K_RF5112) || + (ah->ah_radio == AR5K_RF5413) || + (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) { + ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT); + ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL); + ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK); + ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY); + AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02); + } else { + ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT); + ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL); + ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK); + ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY); + AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03); + } + + /* Enable sleep clock operation */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_SLEEP_CLOCK_EN); + + } else { + + /* Disable sleep clock operation and + * restore default parameters */ + AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_SLEEP_CLOCK_EN); + + AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_SLEEP_CLOCK_RATE, 0); + + ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR); + ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); + + if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) + scal = AR5K_PHY_SCAL_32MHZ_2417; + else if (ath5k_eeprom_is_hb63(ah)) + scal = AR5K_PHY_SCAL_32MHZ_HB63; + else + scal = AR5K_PHY_SCAL_32MHZ; + ath5k_hw_reg_write(ah, scal, 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); + + if ((ah->ah_radio == AR5K_RF5112) || + (ah->ah_radio == AR5K_RF5413) || + (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) + spending = 0x14; + else + spending = 0x18; + ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING); + + if ((ah->ah_radio == AR5K_RF5112) || + (ah->ah_radio == AR5K_RF5413)) + usec32 = 39; + else + usec32 = 31; + AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, usec32); + + AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1); + } + return; +} + +static bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u8 refclk_freq; + + if ((ah->ah_radio == AR5K_RF5112) || + (ah->ah_radio == AR5K_RF5413) || + (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) + refclk_freq = 40; + else + refclk_freq = 32; + + if ((channel->center_freq % refclk_freq != 0) && + ((channel->center_freq % refclk_freq < 10) || + (channel->center_freq % refclk_freq > 22))) + return true; + else + return false; +} + +/* TODO: Half/Quarter rate */ +static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + if (ah->ah_version == AR5K_AR5212 && + ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { + + /* Setup ADC control */ + ath5k_hw_reg_write(ah, + (AR5K_REG_SM(2, + AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) | + AR5K_REG_SM(2, + AR5K_PHY_ADC_CTL_INBUFGAIN_ON) | + AR5K_PHY_ADC_CTL_PWD_DAC_OFF | + AR5K_PHY_ADC_CTL_PWD_ADC_OFF), + AR5K_PHY_ADC_CTL); + + + + /* Disable barker RSSI threshold */ + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL, + AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR); + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL, + AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2); + + /* Set the mute mask */ + ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); + } + + /* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */ + if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B) + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH); + + /* Enable DCU double buffering */ + if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B) + AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_DCU_DBL_BUF_DIS); + + /* Set DAC/ADC delays */ + if (ah->ah_version == AR5K_AR5212) { + u32 scal; + if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) + scal = AR5K_PHY_SCAL_32MHZ_2417; + else if (ath5k_eeprom_is_hb63(ah)) + scal = AR5K_PHY_SCAL_32MHZ_HB63; + else + scal = AR5K_PHY_SCAL_32MHZ; + ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL); + } + + /* Set fast ADC */ + if ((ah->ah_radio == AR5K_RF5413) || + (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) { + u32 fast_adc = true; + + if (channel->center_freq == 2462 || + channel->center_freq == 2467) + fast_adc = 0; + + /* Only update if needed */ + if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc) + ath5k_hw_reg_write(ah, fast_adc, + AR5K_PHY_FAST_ADC); + } + + /* Fix for first revision of the RF5112 RF chipset */ + if (ah->ah_radio == AR5K_RF5112 && + ah->ah_radio_5ghz_revision < + AR5K_SREV_RAD_5112A) { + u32 data; + 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); + } + + if (ah->ah_mac_srev < AR5K_SREV_AR5211) { + u32 usec_reg; + /* 5311 has different tx/rx latency masks + * from 5211, since we deal 5311 the same + * as 5211 when setting initvals, shift + * values here to their proper locations */ + usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211); + ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 | + AR5K_USEC_32 | + AR5K_USEC_TX_LATENCY_5211 | + AR5K_REG_SM(29, + AR5K_USEC_RX_LATENCY_5210)), + AR5K_USEC_5211); + /* Clear QCU/DCU clock gating register */ + ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT); + /* Set DAC/ADC delays */ + ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL); + /* Enable PCU FIFO corruption ECO */ + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211, + AR5K_DIAG_SW_ECO_ENABLE); + } +} + +static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, + struct ieee80211_channel *channel, u8 *ant, u8 ee_mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + s16 cck_ofdm_pwr_delta; + + /* Adjust power delta for channel 14 */ + if (channel->center_freq == 2484) + cck_ofdm_pwr_delta = + ((ee->ee_cck_ofdm_power_delta - + ee->ee_scaled_cck_delta) * 2) / 10; + else + cck_ofdm_pwr_delta = + (ee->ee_cck_ofdm_power_delta * 2) / 10; + + /* Set CCK to OFDM power delta on tx power + * adjustment register */ + if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { + if (channel->hw_value == CHANNEL_G) + ath5k_hw_reg_write(ah, + AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1), + AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) | + AR5K_REG_SM((cck_ofdm_pwr_delta * -1), + AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX), + AR5K_PHY_TX_PWR_ADJ); + else + ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ); + } else { + /* For older revs we scale power on sw during tx power + * setup */ + ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta; + ah->ah_txpower.txp_cck_ofdm_gainf_delta = + ee->ee_cck_ofdm_gain_delta; + } + + /* Set antenna idle switch table */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL, + AR5K_PHY_ANT_CTL_SWTABLE_IDLE, + (ah->ah_antenna[ee_mode][0] | + AR5K_PHY_ANT_CTL_TXRX_EN)); + + /* Set antenna switch table */ + 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); + + /* Noise floor threshold */ + ath5k_hw_reg_write(ah, + AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), + AR5K_PHY_NFTHRES); + + if ((channel->hw_value & CHANNEL_TURBO) && + (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) { + /* Switch settling time (Turbo) */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING, + AR5K_PHY_SETTLING_SWITCH, + ee->ee_switch_settling_turbo[ee_mode]); + + /* Tx/Rx attenuation (Turbo) */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN, + AR5K_PHY_GAIN_TXRX_ATTEN, + ee->ee_atn_tx_rx_turbo[ee_mode]); + + /* ADC/PGA desired size (Turbo) */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, + AR5K_PHY_DESIRED_SIZE_ADC, + ee->ee_adc_desired_size_turbo[ee_mode]); + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, + AR5K_PHY_DESIRED_SIZE_PGA, + ee->ee_pga_desired_size_turbo[ee_mode]); + + /* Tx/Rx margin (Turbo) */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, + AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, + ee->ee_margin_tx_rx_turbo[ee_mode]); + + } else { + /* Switch settling time */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING, + AR5K_PHY_SETTLING_SWITCH, + ee->ee_switch_settling[ee_mode]); + + /* Tx/Rx attenuation */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN, + AR5K_PHY_GAIN_TXRX_ATTEN, + ee->ee_atn_tx_rx[ee_mode]); + + /* ADC/PGA desired size */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, + AR5K_PHY_DESIRED_SIZE_ADC, + ee->ee_adc_desired_size[ee_mode]); + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, + AR5K_PHY_DESIRED_SIZE_PGA, + ee->ee_pga_desired_size[ee_mode]); + + /* Tx/Rx margin */ + 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]); + } + + /* XPA delays */ + 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); + + /* XLNA delay */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3, + AR5K_PHY_RF_CTL3_TXE2XLNA_ON, + ee->ee_tx_end2xlna_enable[ee_mode]); + + /* Thresh64 (ANI) */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF, + AR5K_PHY_NF_THRESH62, + ee->ee_thr_62[ee_mode]); + + + /* False detect backoff for channels + * that have spur noise. Write the new + * cyclic power RSSI threshold. */ + if (ath5k_hw_chan_has_spur_noise(ah, channel)) + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, + AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, + AR5K_INIT_CYCRSSI_THR1 + + ee->ee_false_detect[ee_mode]); + else + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, + AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, + AR5K_INIT_CYCRSSI_THR1); + + /* I/Q correction + * TODO: Per channel i/q infos ? */ + 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]); + + /* Heavy clipping -disable for now */ + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1) + ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE); + + return; +} + +/* + * Main reset function + */ +int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, + struct ieee80211_channel *channel, bool change_channel) +{ + u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo; + u32 phy_tst1; + u8 mode, freq, ee_mode, ant[2]; + int i, ret; + + ATH5K_TRACE(ah->ah_sc); + + s_ant = 0; + ee_mode = 0; + staid1_flags = 0; + tsf_up = 0; + tsf_lo = 0; + freq = 0; + mode = 0; + + /* + * Save some registers before a reset + */ + /*DCU/Antenna selection not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + + 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; + case CHANNEL_TG: + if (ah->ah_version == AR5K_AR5211) { + ATH5K_ERR(ah->ah_sc, + "TurboG mode not available on 5211"); + return -EINVAL; + } + 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; + } + + if (change_channel) { + /* + * Save frame sequence count + * For revs. after Oahu, only save + * seq num for DCU 0 (Global seq num) + */ + if (ah->ah_mac_srev < AR5K_SREV_AR5211) { + + for (i = 0; i < 10; i++) + s_seq[i] = ath5k_hw_reg_read(ah, + AR5K_QUEUE_DCU_SEQNUM(i)); + + } else { + s_seq[0] = ath5k_hw_reg_read(ah, + AR5K_QUEUE_DCU_SEQNUM(0)); + } + + /* TSF accelerates on AR5211 durring reset + * As a workaround save it here and restore + * it later so that it's back in time after + * reset. This way it'll get re-synced on the + * next beacon without breaking ad-hoc. + * + * On AR5212 TSF is almost preserved across a + * reset so it stays back in time anyway and + * we don't have to save/restore it. + * + * XXX: Since this breaks power saving we have + * to disable power saving until we receive the + * next beacon, so we can resync beacon timers */ + if (ah->ah_version == AR5K_AR5211) { + tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32); + } + } + + /* Save default antenna */ + s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + + if (ah->ah_version == AR5K_AR5212) { + /* Restore normal 32/40MHz clock operation + * to avoid register access delay on certain + * PHY registers */ + ath5k_hw_set_sleep_clock(ah, false); + + /* Since we are going to write rf buffer + * check if we have any pending gain_F + * optimization settings */ + if (change_channel && ah->ah_rf_banks != NULL) + ath5k_hw_gainf_calibrate(ah); + } + } + + /*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); + + /* AR5K_STA_ID1 flags, only preserve antenna + * settings and ack/cts rate mode */ + staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & + (AR5K_STA_ID1_DEFAULT_ANTENNA | + AR5K_STA_ID1_DESC_ANTENNA | + AR5K_STA_ID1_RTS_DEF_ANTENNA | + AR5K_STA_ID1_ACKCTS_6MB | + AR5K_STA_ID1_BASE_RATE_11B | + AR5K_STA_ID1_SELFGEN_DEF_ANT); + + /* 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; + + /* PHY access enable */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5211) + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + else + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40, + AR5K_PHY(0)); + + /* Write initial settings */ + 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_init(ah, freq); + if (ret) + return ret; + + mdelay(1); + + /* + * Tweak initval settings for revised + * chipsets and add some more config + * bits + */ + ath5k_hw_tweak_initval_settings(ah, channel); + + /* + * Set TX power (FIXME) + */ + ret = ath5k_hw_txpower(ah, channel, ee_mode, + 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 buffer + */ + ret = ath5k_hw_rfregs_init(ah, channel, mode); + if (ret) + return ret; + + + /* 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); + } + + /* + * 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; + } + + /* Commit values from EEPROM */ + ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode); + + } else { + /* + * For 5210 we do all initialization using + * initvals, so we don't have to modify + * any settings (5210 also only supports + * a/aturbo modes) + */ + 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) { + + if (change_channel) { + if (ah->ah_mac_srev < AR5K_SREV_AR5211) { + for (i = 0; i < 10; i++) + ath5k_hw_reg_write(ah, s_seq[i], + AR5K_QUEUE_DCU_SEQNUM(i)); + } else { + ath5k_hw_reg_write(ah, s_seq[0], + AR5K_QUEUE_DCU_SEQNUM(0)); + } + + + if (ah->ah_version == AR5K_AR5211) { + ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32); + ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32); + } + } + + ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); + } + + /* Ledstate */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); + + /* Gpio settings */ + ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); + ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); + + /* Restore sta_id flags and preserve our mac address*/ + ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id), + AR5K_STA_ID0); + ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id), + AR5K_STA_ID1); + + + /* + * Configure PCU + */ + + /* Restore bssid and bssid mask */ + /* XXX: add ah->aid once mac80211 gives this to us */ + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + + /* Set PCU config */ + ath5k_hw_set_opmode(ah); + + /* Clear any pending interrupts + * PISR/SISR Not available on 5210 */ + if (ah->ah_version != AR5K_AR5210) + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); + + /* Set RSSI/BRSSI thresholds + * + * Note: If we decide to set this value + * dynamicaly, have in mind that when AR5K_RSSI_THR + * register is read it might return 0x40 if we haven't + * wrote anything to it plus BMISS RSSI threshold is zeroed. + * So doing a save/restore procedure here isn't the right + * choice. Instead store it on ath5k_hw */ + ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES | + AR5K_TUNE_BMISS_THRES << + AR5K_RSSI_THR_BMISS_S), + AR5K_RSSI_THR); + + /* MIC QoS support */ + if (ah->ah_mac_srev >= AR5K_SREV_AR2413) { + ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL); + ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL); + } + + /* QoS NOACK Policy */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, + AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) | + AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET) | + AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET), + AR5K_QOS_NOACK); + } + + + /* + * Configure PHY + */ + + /* Set channel on PHY */ + ret = ath5k_hw_channel(ah, channel); + if (ret) + return ret; + + /* + * Enable the PHY and wait until completion + * This includes BaseBand and Synthesizer + * activation. + */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + + /* + * On 5211+ read activation -> rx delay + * and use it. + * + * TODO: Half/quarter rate support + */ + if (ah->ah_version != AR5K_AR5210) { + u32 delay; + delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & + AR5K_PHY_RX_DELAY_M; + delay = (channel->hw_value & CHANNEL_CCK) ? + ((delay << 2) / 22) : (delay / 10); + + udelay(100 + (2 * delay)); + } else { + mdelay(1); + } + + /* + * Perform ADC test to see if baseband is ready + * Set tx hold and check adc test register + */ + phy_tst1 = 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, phy_tst1, AR5K_PHY_TST1); + + /* + * Start automatic gain control calibration + * + * During AGC calibration RX path is re-routed to + * a power 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. + * + * While rx path is re-routed to the power detector we also + * start a noise floor calibration, to measure the + * card's noise floor (the noise we measure when we are not + * transmiting or receiving anything). + * + * If we are in a noisy environment AGC calibration may time + * out and/or noise floor calibration might timeout. + */ + 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); + } + + /* + * 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. Also if AGC or NF cal. + * times out, reset doesn't fail on binary HAL. I believe + * that's wrong because since rx path is routed to a detector, + * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211 + * enables noise floor calibration after offset calibration and if noise + * floor calibration fails, reset fails. I believe that's + * a better approach, we just need to find a polling interval + * that suits best, even if reset continues we need to make + * sure that rx path is ready. + */ + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + + + /* + * Configure QCUs/DCUs + */ + + /* TODO: HW Compression support for data queues */ + /* TODO: Burst prefetch for data queues */ + + /* + * Reset queues and start beacon timers at the end of the reset routine + * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping + * Note: If we want we can assign multiple qcus on one dcu. + */ + for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; 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; + } + } + + + /* + * Configure DMA/Interrupts + */ + + /* + * Set Rx/Tx DMA Configuration + * + * Set standard DMA size (128). Note that + * a DMA size of 512 causes rx overruns and tx errors + * on pci-e cards (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). + * + * 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 ;-) + */ + if (ah->ah_version != AR5K_AR5210) { + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); + AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, + AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B); + } + + /* Pre-enable interrupts on 5211/5212*/ + if (ah->ah_version != AR5K_AR5210) + ath5k_hw_set_imr(ah, ah->ah_imr); + + /* + * Setup RFKill interrupt if rfkill flag is set on eeprom. + * TODO: Use gpio pin and polarity infos from eeprom + * TODO: Handle this in ath5k_intr because it'll result + * a nasty interrupt storm. + */ +#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 + + /* Enable 32KHz clock function for AR5212+ chips + * Set clocks to 32KHz operation and use an + * external 32KHz crystal when sleeping if one + * exists */ + if (ah->ah_version == AR5K_AR5212) + ath5k_hw_set_sleep_clock(ah, true); + + /* + * 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/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h new file mode 100644 index 0000000..e50baff --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h @@ -0,0 +1,1181 @@ +/* + * RF Buffer handling functions + * + * Copyright (c) 2009 Nick Kossifidis + * + * 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. + * + */ + + +/* + * There are some special registers on the RF chip + * that control various operation settings related mostly to + * the analog parts (channel, gain adjustment etc). + * + * We don't write on those registers directly but + * we send a data packet on the chip, using a special register, + * that holds all the settings we need. After we 've sent the + * data packet, we write on another special register to notify hw + * to apply the settings. This is done so that control registers + * can be dynamicaly programmed during operation and the settings + * are applied faster on the hw. + * + * We call each data packet an "RF Bank" and all the data we write + * (all RF Banks) "RF Buffer". This file holds initial RF Buffer + * data for the different RF chips, and various info to match RF + * Buffer offsets with specific RF registers so that we can access + * them. We tweak these settings on rfregs_init function. + * + * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer + * registers and control registers): + * + * http://www.google.com/patents?id=qNURAAAAEBAJ + */ + + +/* + * Struct to hold default mode specific RF + * register values (RF Banks) + */ +struct ath5k_ini_rfbuffer { + u8 rfb_bank; /* RF Bank number */ + u16 rfb_ctrl_register; /* RF Buffer control register */ + u32 rfb_mode_data[5]; /* RF Buffer data for each mode */ +}; + +/* + * Struct to hold RF Buffer field + * infos used to access certain RF + * analog registers + */ +struct ath5k_rfb_field { + u8 len; /* Field length */ + u16 pos; /* Offset on the raw packet */ + u8 col; /* Column -used for shifting */ +}; + +/* + * RF analog register definition + */ +struct ath5k_rf_reg { + u8 bank; /* RF Buffer Bank number */ + u8 index; /* Register's index on rf_regs_idx */ + struct ath5k_rfb_field field; /* RF Buffer field for this register */ +}; + +/* Map RF registers to indexes + * We do this to handle common bits and make our + * life easier by using an index for each register + * instead of a full rfb_field */ +enum ath5k_rf_regs_idx { + /* BANK 6 */ + AR5K_RF_OB_2GHZ = 0, + AR5K_RF_OB_5GHZ, + AR5K_RF_DB_2GHZ, + AR5K_RF_DB_5GHZ, + AR5K_RF_FIXED_BIAS_A, + AR5K_RF_FIXED_BIAS_B, + AR5K_RF_PWD_XPD, + AR5K_RF_XPD_SEL, + AR5K_RF_XPD_GAIN, + AR5K_RF_PD_GAIN_LO, + AR5K_RF_PD_GAIN_HI, + AR5K_RF_HIGH_VC_CP, + AR5K_RF_MID_VC_CP, + AR5K_RF_LOW_VC_CP, + AR5K_RF_PUSH_UP, + AR5K_RF_PAD2GND, + AR5K_RF_XB2_LVL, + AR5K_RF_XB5_LVL, + AR5K_RF_PWD_ICLOBUF_2G, + AR5K_RF_PWD_84, + AR5K_RF_PWD_90, + AR5K_RF_PWD_130, + AR5K_RF_PWD_131, + AR5K_RF_PWD_132, + AR5K_RF_PWD_136, + AR5K_RF_PWD_137, + AR5K_RF_PWD_138, + AR5K_RF_PWD_166, + AR5K_RF_PWD_167, + AR5K_RF_DERBY_CHAN_SEL_MODE, + /* BANK 7 */ + AR5K_RF_GAIN_I, + AR5K_RF_PLO_SEL, + AR5K_RF_RFGAIN_SEL, + AR5K_RF_RFGAIN_STEP, + AR5K_RF_WAIT_S, + AR5K_RF_WAIT_I, + AR5K_RF_MAX_TIME, + AR5K_RF_MIXVGA_OVR, + AR5K_RF_MIXGAIN_OVR, + AR5K_RF_MIXGAIN_STEP, + AR5K_RF_PD_DELAY_A, + AR5K_RF_PD_DELAY_B, + AR5K_RF_PD_DELAY_XR, + AR5K_RF_PD_PERIOD_A, + AR5K_RF_PD_PERIOD_B, + AR5K_RF_PD_PERIOD_XR, +}; + + +/*******************\ +* RF5111 (Sombrero) * +\*******************/ + +/* BANK 6 len pos col */ +#define AR5K_RF5111_OB_2GHZ { 3, 119, 0 } +#define AR5K_RF5111_DB_2GHZ { 3, 122, 0 } + +#define AR5K_RF5111_OB_5GHZ { 3, 104, 0 } +#define AR5K_RF5111_DB_5GHZ { 3, 107, 0 } + +#define AR5K_RF5111_PWD_XPD { 1, 95, 0 } +#define AR5K_RF5111_XPD_GAIN { 4, 96, 0 } + +/* Access to PWD registers */ +#define AR5K_RF5111_PWD(_n) { 1, (135 - _n), 3 } + +/* BANK 7 len pos col */ +#define AR5K_RF5111_GAIN_I { 6, 29, 0 } +#define AR5K_RF5111_PLO_SEL { 1, 4, 0 } +#define AR5K_RF5111_RFGAIN_SEL { 1, 36, 0 } +#define AR5K_RF5111_RFGAIN_STEP { 6, 37, 0 } +/* Only on AR5212 BaseBand and up */ +#define AR5K_RF5111_WAIT_S { 5, 19, 0 } +#define AR5K_RF5111_WAIT_I { 5, 24, 0 } +#define AR5K_RF5111_MAX_TIME { 2, 49, 0 } + +static const struct ath5k_rf_reg rf_regs_5111[] = { + {6, AR5K_RF_OB_2GHZ, AR5K_RF5111_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF5111_DB_2GHZ}, + {6, AR5K_RF_OB_5GHZ, AR5K_RF5111_OB_5GHZ}, + {6, AR5K_RF_DB_5GHZ, AR5K_RF5111_DB_5GHZ}, + {6, AR5K_RF_PWD_XPD, AR5K_RF5111_PWD_XPD}, + {6, AR5K_RF_XPD_GAIN, AR5K_RF5111_XPD_GAIN}, + {6, AR5K_RF_PWD_84, AR5K_RF5111_PWD(84)}, + {6, AR5K_RF_PWD_90, AR5K_RF5111_PWD(90)}, + {7, AR5K_RF_GAIN_I, AR5K_RF5111_GAIN_I}, + {7, AR5K_RF_PLO_SEL, AR5K_RF5111_PLO_SEL}, + {7, AR5K_RF_RFGAIN_SEL, AR5K_RF5111_RFGAIN_SEL}, + {7, AR5K_RF_RFGAIN_STEP, AR5K_RF5111_RFGAIN_STEP}, + {7, AR5K_RF_WAIT_S, AR5K_RF5111_WAIT_S}, + {7, AR5K_RF_WAIT_I, AR5K_RF5111_WAIT_I}, + {7, AR5K_RF_MAX_TIME, AR5K_RF5111_MAX_TIME} +}; + +/* Default mode specific settings */ +static const struct ath5k_ini_rfbuffer rfb_5111[] = { + { 0, 0x989c, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } }, + { 0, 0x989c, + { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } }, + { 0, 0x98d4, + { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } }, + { 1, 0x98d4, + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d4, + { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } }, + { 3, 0x98d8, + { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, + { 6, 0x989c, + { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } }, + { 6, 0x989c, + { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } }, + { 6, 0x989c, + { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } }, + { 6, 0x989c, + { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } }, + { 6, 0x989c, + { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } }, + { 6, 0x98d4, + { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } }, + { 7, 0x989c, + { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } }, + { 7, 0x989c, + { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } }, + { 7, 0x989c, + { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, + { 7, 0x989c, + { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } }, + { 7, 0x989c, + { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } }, + { 7, 0x989c, + { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } }, + { 7, 0x989c, + { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } }, +}; + + + +/***********************\ +* RF5112/RF2112 (Derby) * +\***********************/ + +/* BANK 7 (Common) len pos col */ +#define AR5K_RF5112X_GAIN_I { 6, 14, 0 } +#define AR5K_RF5112X_MIXVGA_OVR { 1, 36, 0 } +#define AR5K_RF5112X_MIXGAIN_OVR { 2, 37, 0 } +#define AR5K_RF5112X_MIXGAIN_STEP { 4, 32, 0 } +#define AR5K_RF5112X_PD_DELAY_A { 4, 58, 0 } +#define AR5K_RF5112X_PD_DELAY_B { 4, 62, 0 } +#define AR5K_RF5112X_PD_DELAY_XR { 4, 66, 0 } +#define AR5K_RF5112X_PD_PERIOD_A { 4, 70, 0 } +#define AR5K_RF5112X_PD_PERIOD_B { 4, 74, 0 } +#define AR5K_RF5112X_PD_PERIOD_XR { 4, 78, 0 } + +/* RFX112 (Derby 1) */ + +/* BANK 6 len pos col */ +#define AR5K_RF5112_OB_2GHZ { 3, 269, 0 } +#define AR5K_RF5112_DB_2GHZ { 3, 272, 0 } + +#define AR5K_RF5112_OB_5GHZ { 3, 261, 0 } +#define AR5K_RF5112_DB_5GHZ { 3, 264, 0 } + +#define AR5K_RF5112_FIXED_BIAS_A { 1, 260, 0 } +#define AR5K_RF5112_FIXED_BIAS_B { 1, 259, 0 } + +#define AR5K_RF5112_XPD_SEL { 1, 284, 0 } +#define AR5K_RF5112_XPD_GAIN { 2, 252, 0 } + +/* Access to PWD registers */ +#define AR5K_RF5112_PWD(_n) { 1, (302 - _n), 3 } + +static const struct ath5k_rf_reg rf_regs_5112[] = { + {6, AR5K_RF_OB_2GHZ, AR5K_RF5112_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF5112_DB_2GHZ}, + {6, AR5K_RF_OB_5GHZ, AR5K_RF5112_OB_5GHZ}, + {6, AR5K_RF_DB_5GHZ, AR5K_RF5112_DB_5GHZ}, + {6, AR5K_RF_FIXED_BIAS_A, AR5K_RF5112_FIXED_BIAS_A}, + {6, AR5K_RF_FIXED_BIAS_B, AR5K_RF5112_FIXED_BIAS_B}, + {6, AR5K_RF_XPD_SEL, AR5K_RF5112_XPD_SEL}, + {6, AR5K_RF_XPD_GAIN, AR5K_RF5112_XPD_GAIN}, + {6, AR5K_RF_PWD_130, AR5K_RF5112_PWD(130)}, + {6, AR5K_RF_PWD_131, AR5K_RF5112_PWD(131)}, + {6, AR5K_RF_PWD_132, AR5K_RF5112_PWD(132)}, + {6, AR5K_RF_PWD_136, AR5K_RF5112_PWD(136)}, + {6, AR5K_RF_PWD_137, AR5K_RF5112_PWD(137)}, + {6, AR5K_RF_PWD_138, AR5K_RF5112_PWD(138)}, + {7, AR5K_RF_GAIN_I, AR5K_RF5112X_GAIN_I}, + {7, AR5K_RF_MIXVGA_OVR, AR5K_RF5112X_MIXVGA_OVR}, + {7, AR5K_RF_MIXGAIN_OVR, AR5K_RF5112X_MIXGAIN_OVR}, + {7, AR5K_RF_MIXGAIN_STEP, AR5K_RF5112X_MIXGAIN_STEP}, + {7, AR5K_RF_PD_DELAY_A, AR5K_RF5112X_PD_DELAY_A}, + {7, AR5K_RF_PD_DELAY_B, AR5K_RF5112X_PD_DELAY_B}, + {7, AR5K_RF_PD_DELAY_XR, AR5K_RF5112X_PD_DELAY_XR}, + {7, AR5K_RF_PD_PERIOD_A, AR5K_RF5112X_PD_PERIOD_A}, + {7, AR5K_RF_PD_PERIOD_B, AR5K_RF5112X_PD_PERIOD_B}, + {7, AR5K_RF_PD_PERIOD_XR, AR5K_RF5112X_PD_PERIOD_XR}, +}; + +/* Default mode specific settings */ +static const struct ath5k_ini_rfbuffer rfb_5112[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, + { 3, 0x98dc, + { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } }, + { 6, 0x989c, + { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } }, + { 6, 0x989c, + { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } }, + { 6, 0x989c, + { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } }, + { 6, 0x989c, + { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } }, + { 6, 0x989c, + { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, + { 6, 0x989c, + { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, + { 6, 0x989c, + { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } }, + { 6, 0x989c, + { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } }, + { 6, 0x989c, + { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, + { 6, 0x989c, + { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, + { 6, 0x989c, + { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } }, + { 6, 0x989c, + { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } }, + { 6, 0x989c, + { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, + { 6, 0x989c, + { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } }, + { 6, 0x989c, + { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, + { 6, 0x989c, + { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, + { 6, 0x989c, + { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } }, + { 6, 0x989c, + { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } }, + { 6, 0x989c, + { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, + { 6, 0x989c, + { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } }, + { 6, 0x989c, + { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } }, + { 6, 0x989c, + { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } }, + { 6, 0x989c, + { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } }, + { 6, 0x989c, + { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } }, + { 6, 0x989c, + { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } }, + { 6, 0x989c, + { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } }, + { 6, 0x989c, + { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } }, + { 6, 0x989c, + { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } }, + { 6, 0x989c, + { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } }, + { 6, 0x98d0, + { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } }, + { 7, 0x989c, + { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, + { 7, 0x989c, + { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, + { 7, 0x989c, + { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } }, + { 7, 0x989c, + { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, + { 7, 0x989c, + { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } }, + { 7, 0x989c, + { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, + { 7, 0x989c, + { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, + { 7, 0x989c, + { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } }, + { 7, 0x989c, + { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } }, + { 7, 0x989c, + { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, + { 7, 0x989c, + { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, + { 7, 0x989c, + { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, + { 7, 0x98c4, + { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, +}; + +/* RFX112A (Derby 2) */ + +/* BANK 6 len pos col */ +#define AR5K_RF5112A_OB_2GHZ { 3, 287, 0 } +#define AR5K_RF5112A_DB_2GHZ { 3, 290, 0 } + +#define AR5K_RF5112A_OB_5GHZ { 3, 279, 0 } +#define AR5K_RF5112A_DB_5GHZ { 3, 282, 0 } + +#define AR5K_RF5112A_FIXED_BIAS_A { 1, 278, 0 } +#define AR5K_RF5112A_FIXED_BIAS_B { 1, 277, 0 } + +#define AR5K_RF5112A_XPD_SEL { 1, 302, 0 } +#define AR5K_RF5112A_PDGAINLO { 2, 270, 0 } +#define AR5K_RF5112A_PDGAINHI { 2, 257, 0 } + +/* Access to PWD registers */ +#define AR5K_RF5112A_PWD(_n) { 1, (306 - _n), 3 } + +/* Voltage regulators */ +#define AR5K_RF5112A_HIGH_VC_CP { 2, 90, 2 } +#define AR5K_RF5112A_MID_VC_CP { 2, 92, 2 } +#define AR5K_RF5112A_LOW_VC_CP { 2, 94, 2 } +#define AR5K_RF5112A_PUSH_UP { 1, 254, 2 } + +/* Power consumption */ +#define AR5K_RF5112A_PAD2GND { 1, 281, 1 } +#define AR5K_RF5112A_XB2_LVL { 2, 1, 3 } +#define AR5K_RF5112A_XB5_LVL { 2, 3, 3 } + +static const struct ath5k_rf_reg rf_regs_5112a[] = { + {6, AR5K_RF_OB_2GHZ, AR5K_RF5112A_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF5112A_DB_2GHZ}, + {6, AR5K_RF_OB_5GHZ, AR5K_RF5112A_OB_5GHZ}, + {6, AR5K_RF_DB_5GHZ, AR5K_RF5112A_DB_5GHZ}, + {6, AR5K_RF_FIXED_BIAS_A, AR5K_RF5112A_FIXED_BIAS_A}, + {6, AR5K_RF_FIXED_BIAS_B, AR5K_RF5112A_FIXED_BIAS_B}, + {6, AR5K_RF_XPD_SEL, AR5K_RF5112A_XPD_SEL}, + {6, AR5K_RF_PD_GAIN_LO, AR5K_RF5112A_PDGAINLO}, + {6, AR5K_RF_PD_GAIN_HI, AR5K_RF5112A_PDGAINHI}, + {6, AR5K_RF_PWD_130, AR5K_RF5112A_PWD(130)}, + {6, AR5K_RF_PWD_131, AR5K_RF5112A_PWD(131)}, + {6, AR5K_RF_PWD_132, AR5K_RF5112A_PWD(132)}, + {6, AR5K_RF_PWD_136, AR5K_RF5112A_PWD(136)}, + {6, AR5K_RF_PWD_137, AR5K_RF5112A_PWD(137)}, + {6, AR5K_RF_PWD_138, AR5K_RF5112A_PWD(138)}, + {6, AR5K_RF_PWD_166, AR5K_RF5112A_PWD(166)}, + {6, AR5K_RF_PWD_167, AR5K_RF5112A_PWD(167)}, + {6, AR5K_RF_HIGH_VC_CP, AR5K_RF5112A_HIGH_VC_CP}, + {6, AR5K_RF_MID_VC_CP, AR5K_RF5112A_MID_VC_CP}, + {6, AR5K_RF_LOW_VC_CP, AR5K_RF5112A_LOW_VC_CP}, + {6, AR5K_RF_PUSH_UP, AR5K_RF5112A_PUSH_UP}, + {6, AR5K_RF_PAD2GND, AR5K_RF5112A_PAD2GND}, + {6, AR5K_RF_XB2_LVL, AR5K_RF5112A_XB2_LVL}, + {6, AR5K_RF_XB5_LVL, AR5K_RF5112A_XB5_LVL}, + {7, AR5K_RF_GAIN_I, AR5K_RF5112X_GAIN_I}, + {7, AR5K_RF_MIXVGA_OVR, AR5K_RF5112X_MIXVGA_OVR}, + {7, AR5K_RF_MIXGAIN_OVR, AR5K_RF5112X_MIXGAIN_OVR}, + {7, AR5K_RF_MIXGAIN_STEP, AR5K_RF5112X_MIXGAIN_STEP}, + {7, AR5K_RF_PD_DELAY_A, AR5K_RF5112X_PD_DELAY_A}, + {7, AR5K_RF_PD_DELAY_B, AR5K_RF5112X_PD_DELAY_B}, + {7, AR5K_RF_PD_DELAY_XR, AR5K_RF5112X_PD_DELAY_XR}, + {7, AR5K_RF_PD_PERIOD_A, AR5K_RF5112X_PD_PERIOD_A}, + {7, AR5K_RF_PD_PERIOD_B, AR5K_RF5112X_PD_PERIOD_B}, + {7, AR5K_RF_PD_PERIOD_XR, AR5K_RF5112X_PD_PERIOD_XR}, +}; + +/* Default mode specific settings */ +static const struct ath5k_ini_rfbuffer rfb_5112a[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, + { 3, 0x98dc, + { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, 0x989c, + { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } }, + { 6, 0x989c, + { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, 0x989c, + { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } }, + { 6, 0x989c, + { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } }, + { 6, 0x989c, + { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } }, + { 6, 0x989c, + { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } }, + { 6, 0x989c, + { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } }, + { 6, 0x989c, + { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } }, + { 6, 0x989c, + { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } }, + { 6, 0x989c, + { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, + { 6, 0x989c, + { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } }, + { 6, 0x989c, + { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, + { 6, 0x989c, + { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } }, + { 6, 0x989c, + { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } }, + { 6, 0x989c, + { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } }, + { 6, 0x989c, + { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, 0x989c, + { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, + { 6, 0x989c, + { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } }, + { 6, 0x989c, + { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } }, + { 6, 0x989c, + { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, + { 6, 0x989c, + { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } }, + { 6, 0x989c, + { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } }, + { 6, 0x989c, + { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } }, + { 6, 0x989c, + { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } }, + { 6, 0x989c, + { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } }, + { 6, 0x989c, + { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } }, + { 6, 0x989c, + { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } }, + { 6, 0x989c, + { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } }, + { 6, 0x989c, + { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } }, + { 6, 0x98d8, + { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } }, + { 7, 0x989c, + { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, + { 7, 0x989c, + { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, + { 7, 0x989c, + { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } }, + { 7, 0x989c, + { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, + { 7, 0x989c, + { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } }, + { 7, 0x989c, + { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, + { 7, 0x989c, + { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, + { 7, 0x989c, + { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } }, + { 7, 0x989c, + { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } }, + { 7, 0x989c, + { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, + { 7, 0x989c, + { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, + { 7, 0x989c, + { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, + { 7, 0x98c4, + { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, +}; + + + +/******************\ +* RF2413 (Griffin) * +\******************/ + +/* BANK 6 len pos col */ +#define AR5K_RF2413_OB_2GHZ { 3, 168, 0 } +#define AR5K_RF2413_DB_2GHZ { 3, 165, 0 } + +static const struct ath5k_rf_reg rf_regs_2413[] = { + {6, AR5K_RF_OB_2GHZ, AR5K_RF2413_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF2413_DB_2GHZ}, +}; + +/* Default mode specific settings + * XXX: a/aTurbo ??? + */ +static const struct ath5k_ini_rfbuffer rfb_2413[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } }, + { 3, 0x98dc, + { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, 0x989c, + { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } }, + { 6, 0x989c, + { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } }, + { 6, 0x989c, + { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } }, + { 6, 0x989c, + { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } }, + { 6, 0x989c, + { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } }, + { 6, 0x989c, + { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } }, + { 6, 0x989c, + { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } }, + { 6, 0x989c, + { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } }, + { 6, 0x989c, + { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } }, + { 6, 0x989c, + { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } }, + { 6, 0x989c, + { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } }, + { 6, 0x989c, + { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } }, + { 6, 0x989c, + { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } }, + { 6, 0x98d8, + { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } }, + { 7, 0x989c, + { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, + { 7, 0x989c, + { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, +}; + + + +/***************************\ +* RF2315/RF2316 (Cobra SoC) * +\***************************/ + +/* BANK 6 len pos col */ +#define AR5K_RF2316_OB_2GHZ { 3, 178, 0 } +#define AR5K_RF2316_DB_2GHZ { 3, 175, 0 } + +static const struct ath5k_rf_reg rf_regs_2316[] = { + {6, AR5K_RF_OB_2GHZ, AR5K_RF2316_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF2316_DB_2GHZ}, +}; + +/* Default mode specific settings */ +static const struct ath5k_ini_rfbuffer rfb_2316[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } }, + { 3, 0x98dc, + { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } }, + { 6, 0x989c, + { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } }, + { 6, 0x989c, + { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } }, + { 6, 0x989c, + { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } }, + { 6, 0x989c, + { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } }, + { 6, 0x989c, + { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } }, + { 6, 0x989c, + { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } }, + { 6, 0x989c, + { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } }, + { 6, 0x989c, + { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } }, + { 6, 0x989c, + { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } }, + { 6, 0x989c, + { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } }, + { 6, 0x989c, + { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } }, + { 6, 0x989c, + { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } }, + { 6, 0x989c, + { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } }, + { 6, 0x989c, + { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, + { 6, 0x989c, + { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, + { 6, 0x989c, + { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } }, + { 6, 0x989c, + { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } }, + { 6, 0x98c0, + { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } }, + { 7, 0x989c, + { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, + { 7, 0x989c, + { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, +}; + + + +/******************************\ +* RF5413/RF5424 (Eagle/Condor) * +\******************************/ + +/* BANK 6 len pos col */ +#define AR5K_RF5413_OB_2GHZ { 3, 241, 0 } +#define AR5K_RF5413_DB_2GHZ { 3, 238, 0 } + +#define AR5K_RF5413_OB_5GHZ { 3, 247, 0 } +#define AR5K_RF5413_DB_5GHZ { 3, 244, 0 } + +#define AR5K_RF5413_PWD_ICLOBUF2G { 3, 131, 3 } +#define AR5K_RF5413_DERBY_CHAN_SEL_MODE { 1, 291, 2 } + +static const struct ath5k_rf_reg rf_regs_5413[] = { + {6, AR5K_RF_OB_2GHZ, AR5K_RF5413_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF5413_DB_2GHZ}, + {6, AR5K_RF_OB_5GHZ, AR5K_RF5413_OB_5GHZ}, + {6, AR5K_RF_DB_5GHZ, AR5K_RF5413_DB_5GHZ}, + {6, AR5K_RF_PWD_ICLOBUF_2G, AR5K_RF5413_PWD_ICLOBUF2G}, + {6, AR5K_RF_DERBY_CHAN_SEL_MODE, AR5K_RF5413_DERBY_CHAN_SEL_MODE}, +}; + +/* Default mode specific settings */ +static const struct ath5k_ini_rfbuffer rfb_5413[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, + { 3, 0x98dc, + { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } }, + { 6, 0x989c, + { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } }, + { 6, 0x989c, + { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } }, + { 6, 0x989c, + { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } }, + { 6, 0x989c, + { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, + { 6, 0x989c, + { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, + { 6, 0x989c, + { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } }, + { 6, 0x989c, + { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } }, + { 6, 0x989c, + { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } }, + { 6, 0x989c, + { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } }, + { 6, 0x989c, + { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } }, + { 6, 0x989c, + { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } }, + { 6, 0x989c, + { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } }, + { 6, 0x989c, + { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } }, + { 6, 0x989c, + { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, + { 6, 0x989c, + { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } }, + { 6, 0x989c, + { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } }, + { 6, 0x989c, + { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } }, + { 6, 0x989c, + { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } }, + { 6, 0x989c, + { 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 } }, + { 6, 0x989c, + { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } }, + { 6, 0x989c, + { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 } }, + { 6, 0x98c8, + { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } }, + { 7, 0x989c, + { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, + { 7, 0x989c, + { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, +}; + + + +/***************************\ +* RF2425/RF2417 (Swan/Nala) * +* AR2317 (Spider SoC) * +\***************************/ + +/* BANK 6 len pos col */ +#define AR5K_RF2425_OB_2GHZ { 3, 193, 0 } +#define AR5K_RF2425_DB_2GHZ { 3, 190, 0 } + +static const struct ath5k_rf_reg rf_regs_2425[] = { + {6, AR5K_RF_OB_2GHZ, AR5K_RF2425_OB_2GHZ}, + {6, AR5K_RF_DB_2GHZ, AR5K_RF2425_DB_2GHZ}, +}; + +/* Default mode specific settings + * XXX: a/aTurbo ? + */ +static const struct ath5k_ini_rfbuffer rfb_2425[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } }, + { 3, 0x98dc, + { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, 0x989c, + { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } }, + { 6, 0x989c, + { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } }, + { 6, 0x989c, + { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, + { 6, 0x989c, + { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } }, + { 6, 0x989c, + { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } }, + { 6, 0x989c, + { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } }, + { 6, 0x989c, + { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } }, + { 6, 0x989c, + { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } }, + { 6, 0x989c, + { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } }, + { 6, 0x989c, + { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } }, + { 6, 0x989c, + { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } }, + { 6, 0x989c, + { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } }, + { 6, 0x98c4, + { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, + { 7, 0x989c, + { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, + { 7, 0x989c, + { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, +}; + +/* + * TODO: Handle the few differences with swan during + * bank modification and get rid of this + */ +static const struct ath5k_ini_rfbuffer rfb_2317[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } }, + { 3, 0x98dc, + { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, 0x989c, + { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } }, + { 6, 0x989c, + { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } }, + { 6, 0x989c, + { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, + { 6, 0x989c, + { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } }, + { 6, 0x989c, + { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } }, + { 6, 0x989c, + { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } }, + { 6, 0x989c, + { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } }, + { 6, 0x989c, + { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } }, + { 6, 0x989c, + { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } }, + { 6, 0x989c, + { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } }, + { 6, 0x989c, + { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } }, + { 6, 0x989c, + { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } }, + { 6, 0x98c4, + { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, + { 7, 0x989c, + { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, + { 7, 0x989c, + { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, +}; + +/* + * TODO: Handle the few differences with swan during + * bank modification and get rid of this + * XXX: a/aTurbo ? + */ +static const struct ath5k_ini_rfbuffer rfb_2417[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } }, + { 3, 0x98dc, + { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, 0x989c, + { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } }, + { 6, 0x989c, + { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } }, + { 6, 0x989c, + { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, + { 6, 0x989c, + { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } }, + { 6, 0x989c, + { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } }, + { 6, 0x989c, + { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } }, + { 6, 0x989c, + { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } }, + { 6, 0x989c, + { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } }, + { 6, 0x989c, + { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } }, + { 6, 0x989c, + { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } }, + { 6, 0x989c, + { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } }, + { 6, 0x989c, + { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } }, + { 6, 0x98c4, + { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, + { 7, 0x989c, + { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, + { 7, 0x989c, + { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, +}; diff --git a/drivers/net/wireless/ath/ath5k/rfgain.h b/drivers/net/wireless/ath/ath5k/rfgain.h new file mode 100644 index 0000000..1354d8c --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/rfgain.h @@ -0,0 +1,516 @@ +/* + * RF Gain optimization + * + * Copyright (c) 2004-2009 Reyk Floeter + * Copyright (c) 2006-2009 Nick Kossifidis + * + * 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. + * + */ + +/* + * Mode-specific RF Gain table (64bytes) for RF5111/5112 + * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial + * RF Gain values are included in AR5K_AR5210_INI) + */ +struct ath5k_ini_rfgain { + u16 rfg_register; /* RF Gain register address */ + u32 rfg_value[2]; /* [freq (see below)] */ +}; + +/* Initial RF Gain settings for RF5111 */ +static const struct ath5k_ini_rfgain rfgain_5111[] = { + /* 5Ghz 2Ghz */ + { AR5K_RF_GAIN(0), { 0x000001a9, 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x000001e9, 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000029, 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x00000069, 0x00000150 } }, + { AR5K_RF_GAIN(4), { 0x00000199, 0x00000190 } }, + { AR5K_RF_GAIN(5), { 0x000001d9, 0x000001d0 } }, + { AR5K_RF_GAIN(6), { 0x00000019, 0x00000010 } }, + { AR5K_RF_GAIN(7), { 0x00000059, 0x00000044 } }, + { AR5K_RF_GAIN(8), { 0x00000099, 0x00000084 } }, + { AR5K_RF_GAIN(9), { 0x000001a5, 0x00000148 } }, + { AR5K_RF_GAIN(10), { 0x000001e5, 0x00000188 } }, + { AR5K_RF_GAIN(11), { 0x00000025, 0x000001c8 } }, + { AR5K_RF_GAIN(12), { 0x000001c8, 0x00000014 } }, + { AR5K_RF_GAIN(13), { 0x00000008, 0x00000042 } }, + { AR5K_RF_GAIN(14), { 0x00000048, 0x00000082 } }, + { AR5K_RF_GAIN(15), { 0x00000088, 0x00000178 } }, + { AR5K_RF_GAIN(16), { 0x00000198, 0x000001b8 } }, + { AR5K_RF_GAIN(17), { 0x000001d8, 0x000001f8 } }, + { AR5K_RF_GAIN(18), { 0x00000018, 0x00000012 } }, + { AR5K_RF_GAIN(19), { 0x00000058, 0x00000052 } }, + { AR5K_RF_GAIN(20), { 0x00000098, 0x00000092 } }, + { AR5K_RF_GAIN(21), { 0x000001a4, 0x0000017c } }, + { AR5K_RF_GAIN(22), { 0x000001e4, 0x000001bc } }, + { AR5K_RF_GAIN(23), { 0x00000024, 0x000001fc } }, + { AR5K_RF_GAIN(24), { 0x00000064, 0x0000000a } }, + { AR5K_RF_GAIN(25), { 0x000000a4, 0x0000004a } }, + { AR5K_RF_GAIN(26), { 0x000000e4, 0x0000008a } }, + { AR5K_RF_GAIN(27), { 0x0000010a, 0x0000015a } }, + { AR5K_RF_GAIN(28), { 0x0000014a, 0x0000019a } }, + { AR5K_RF_GAIN(29), { 0x0000018a, 0x000001da } }, + { AR5K_RF_GAIN(30), { 0x000001ca, 0x0000000e } }, + { AR5K_RF_GAIN(31), { 0x0000000a, 0x0000004e } }, + { AR5K_RF_GAIN(32), { 0x0000004a, 0x0000008e } }, + { AR5K_RF_GAIN(33), { 0x0000008a, 0x0000015e } }, + { AR5K_RF_GAIN(34), { 0x000001ba, 0x0000019e } }, + { AR5K_RF_GAIN(35), { 0x000001fa, 0x000001de } }, + { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000009 } }, + { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000049 } }, + { AR5K_RF_GAIN(38), { 0x00000186, 0x00000089 } }, + { AR5K_RF_GAIN(39), { 0x000001c6, 0x00000179 } }, + { AR5K_RF_GAIN(40), { 0x00000006, 0x000001b9 } }, + { AR5K_RF_GAIN(41), { 0x00000046, 0x000001f9 } }, + { AR5K_RF_GAIN(42), { 0x00000086, 0x00000039 } }, + { AR5K_RF_GAIN(43), { 0x000000c6, 0x00000079 } }, + { AR5K_RF_GAIN(44), { 0x000000c6, 0x000000b9 } }, + { AR5K_RF_GAIN(45), { 0x000000c6, 0x000001bd } }, + { AR5K_RF_GAIN(46), { 0x000000c6, 0x000001fd } }, + { AR5K_RF_GAIN(47), { 0x000000c6, 0x0000003d } }, + { AR5K_RF_GAIN(48), { 0x000000c6, 0x0000007d } }, + { AR5K_RF_GAIN(49), { 0x000000c6, 0x000000bd } }, + { AR5K_RF_GAIN(50), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(51), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(52), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(53), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(54), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(55), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(56), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(57), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(58), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(59), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(60), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(61), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(62), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(63), { 0x000000c6, 0x000000fd } }, +}; + +/* Initial RF Gain settings for RF5112 */ +static const struct ath5k_ini_rfgain rfgain_5112[] = { + /* 5Ghz 2Ghz */ + { AR5K_RF_GAIN(0), { 0x00000007, 0x00000007 } }, + { AR5K_RF_GAIN(1), { 0x00000047, 0x00000047 } }, + { AR5K_RF_GAIN(2), { 0x00000087, 0x00000087 } }, + { AR5K_RF_GAIN(3), { 0x000001a0, 0x000001a0 } }, + { AR5K_RF_GAIN(4), { 0x000001e0, 0x000001e0 } }, + { AR5K_RF_GAIN(5), { 0x00000020, 0x00000020 } }, + { AR5K_RF_GAIN(6), { 0x00000060, 0x00000060 } }, + { AR5K_RF_GAIN(7), { 0x000001a1, 0x000001a1 } }, + { AR5K_RF_GAIN(8), { 0x000001e1, 0x000001e1 } }, + { AR5K_RF_GAIN(9), { 0x00000021, 0x00000021 } }, + { AR5K_RF_GAIN(10), { 0x00000061, 0x00000061 } }, + { AR5K_RF_GAIN(11), { 0x00000162, 0x00000162 } }, + { AR5K_RF_GAIN(12), { 0x000001a2, 0x000001a2 } }, + { AR5K_RF_GAIN(13), { 0x000001e2, 0x000001e2 } }, + { AR5K_RF_GAIN(14), { 0x00000022, 0x00000022 } }, + { AR5K_RF_GAIN(15), { 0x00000062, 0x00000062 } }, + { AR5K_RF_GAIN(16), { 0x00000163, 0x00000163 } }, + { AR5K_RF_GAIN(17), { 0x000001a3, 0x000001a3 } }, + { AR5K_RF_GAIN(18), { 0x000001e3, 0x000001e3 } }, + { AR5K_RF_GAIN(19), { 0x00000023, 0x00000023 } }, + { AR5K_RF_GAIN(20), { 0x00000063, 0x00000063 } }, + { AR5K_RF_GAIN(21), { 0x00000184, 0x00000184 } }, + { AR5K_RF_GAIN(22), { 0x000001c4, 0x000001c4 } }, + { AR5K_RF_GAIN(23), { 0x00000004, 0x00000004 } }, + { AR5K_RF_GAIN(24), { 0x000001ea, 0x0000000b } }, + { AR5K_RF_GAIN(25), { 0x0000002a, 0x0000004b } }, + { AR5K_RF_GAIN(26), { 0x0000006a, 0x0000008b } }, + { AR5K_RF_GAIN(27), { 0x000000aa, 0x000001ac } }, + { AR5K_RF_GAIN(28), { 0x000001ab, 0x000001ec } }, + { AR5K_RF_GAIN(29), { 0x000001eb, 0x0000002c } }, + { AR5K_RF_GAIN(30), { 0x0000002b, 0x00000012 } }, + { AR5K_RF_GAIN(31), { 0x0000006b, 0x00000052 } }, + { AR5K_RF_GAIN(32), { 0x000000ab, 0x00000092 } }, + { AR5K_RF_GAIN(33), { 0x000001ac, 0x00000193 } }, + { AR5K_RF_GAIN(34), { 0x000001ec, 0x000001d3 } }, + { AR5K_RF_GAIN(35), { 0x0000002c, 0x00000013 } }, + { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000053 } }, + { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000093 } }, + { AR5K_RF_GAIN(38), { 0x000000ba, 0x00000194 } }, + { AR5K_RF_GAIN(39), { 0x000001bb, 0x000001d4 } }, + { AR5K_RF_GAIN(40), { 0x000001fb, 0x00000014 } }, + { AR5K_RF_GAIN(41), { 0x0000003b, 0x0000003a } }, + { AR5K_RF_GAIN(42), { 0x0000007b, 0x0000007a } }, + { AR5K_RF_GAIN(43), { 0x000000bb, 0x000000ba } }, + { AR5K_RF_GAIN(44), { 0x000001bc, 0x000001bb } }, + { AR5K_RF_GAIN(45), { 0x000001fc, 0x000001fb } }, + { AR5K_RF_GAIN(46), { 0x0000003c, 0x0000003b } }, + { AR5K_RF_GAIN(47), { 0x0000007c, 0x0000007b } }, + { AR5K_RF_GAIN(48), { 0x000000bc, 0x000000bb } }, + { AR5K_RF_GAIN(49), { 0x000000fc, 0x000001bc } }, + { AR5K_RF_GAIN(50), { 0x000000fc, 0x000001fc } }, + { AR5K_RF_GAIN(51), { 0x000000fc, 0x0000003c } }, + { AR5K_RF_GAIN(52), { 0x000000fc, 0x0000007c } }, + { AR5K_RF_GAIN(53), { 0x000000fc, 0x000000bc } }, + { AR5K_RF_GAIN(54), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(55), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(56), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(57), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(58), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(59), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(60), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(61), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(62), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(63), { 0x000000fc, 0x000000fc } }, +}; + +/* Initial RF Gain settings for RF2413 */ +static const struct ath5k_ini_rfgain rfgain_2413[] = { + { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x00000000, 0x00000181 } }, + { AR5K_RF_GAIN(4), { 0x00000000, 0x000001c1 } }, + { AR5K_RF_GAIN(5), { 0x00000000, 0x00000001 } }, + { AR5K_RF_GAIN(6), { 0x00000000, 0x00000041 } }, + { AR5K_RF_GAIN(7), { 0x00000000, 0x00000081 } }, + { AR5K_RF_GAIN(8), { 0x00000000, 0x00000168 } }, + { AR5K_RF_GAIN(9), { 0x00000000, 0x000001a8 } }, + { AR5K_RF_GAIN(10), { 0x00000000, 0x000001e8 } }, + { AR5K_RF_GAIN(11), { 0x00000000, 0x00000028 } }, + { AR5K_RF_GAIN(12), { 0x00000000, 0x00000068 } }, + { AR5K_RF_GAIN(13), { 0x00000000, 0x00000189 } }, + { AR5K_RF_GAIN(14), { 0x00000000, 0x000001c9 } }, + { AR5K_RF_GAIN(15), { 0x00000000, 0x00000009 } }, + { AR5K_RF_GAIN(16), { 0x00000000, 0x00000049 } }, + { AR5K_RF_GAIN(17), { 0x00000000, 0x00000089 } }, + { AR5K_RF_GAIN(18), { 0x00000000, 0x00000190 } }, + { AR5K_RF_GAIN(19), { 0x00000000, 0x000001d0 } }, + { AR5K_RF_GAIN(20), { 0x00000000, 0x00000010 } }, + { AR5K_RF_GAIN(21), { 0x00000000, 0x00000050 } }, + { AR5K_RF_GAIN(22), { 0x00000000, 0x00000090 } }, + { AR5K_RF_GAIN(23), { 0x00000000, 0x00000191 } }, + { AR5K_RF_GAIN(24), { 0x00000000, 0x000001d1 } }, + { AR5K_RF_GAIN(25), { 0x00000000, 0x00000011 } }, + { AR5K_RF_GAIN(26), { 0x00000000, 0x00000051 } }, + { AR5K_RF_GAIN(27), { 0x00000000, 0x00000091 } }, + { AR5K_RF_GAIN(28), { 0x00000000, 0x00000178 } }, + { AR5K_RF_GAIN(29), { 0x00000000, 0x000001b8 } }, + { AR5K_RF_GAIN(30), { 0x00000000, 0x000001f8 } }, + { AR5K_RF_GAIN(31), { 0x00000000, 0x00000038 } }, + { AR5K_RF_GAIN(32), { 0x00000000, 0x00000078 } }, + { AR5K_RF_GAIN(33), { 0x00000000, 0x00000199 } }, + { AR5K_RF_GAIN(34), { 0x00000000, 0x000001d9 } }, + { AR5K_RF_GAIN(35), { 0x00000000, 0x00000019 } }, + { AR5K_RF_GAIN(36), { 0x00000000, 0x00000059 } }, + { AR5K_RF_GAIN(37), { 0x00000000, 0x00000099 } }, + { AR5K_RF_GAIN(38), { 0x00000000, 0x000000d9 } }, + { AR5K_RF_GAIN(39), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(40), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(41), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(42), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(43), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(44), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(45), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(46), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(47), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(48), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(49), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(50), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(51), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(52), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(53), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(54), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(55), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(56), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(57), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(58), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(59), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(60), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(61), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(62), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } }, +}; + +/* Initial RF Gain settings for AR2316 */ +static const struct ath5k_ini_rfgain rfgain_2316[] = { + { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x00000000, 0x000000c0 } }, + { AR5K_RF_GAIN(4), { 0x00000000, 0x000000e0 } }, + { AR5K_RF_GAIN(5), { 0x00000000, 0x000000e0 } }, + { AR5K_RF_GAIN(6), { 0x00000000, 0x00000128 } }, + { AR5K_RF_GAIN(7), { 0x00000000, 0x00000128 } }, + { AR5K_RF_GAIN(8), { 0x00000000, 0x00000128 } }, + { AR5K_RF_GAIN(9), { 0x00000000, 0x00000168 } }, + { AR5K_RF_GAIN(10), { 0x00000000, 0x000001a8 } }, + { AR5K_RF_GAIN(11), { 0x00000000, 0x000001e8 } }, + { AR5K_RF_GAIN(12), { 0x00000000, 0x00000028 } }, + { AR5K_RF_GAIN(13), { 0x00000000, 0x00000068 } }, + { AR5K_RF_GAIN(14), { 0x00000000, 0x000000a8 } }, + { AR5K_RF_GAIN(15), { 0x00000000, 0x000000e8 } }, + { AR5K_RF_GAIN(16), { 0x00000000, 0x000000e8 } }, + { AR5K_RF_GAIN(17), { 0x00000000, 0x00000130 } }, + { AR5K_RF_GAIN(18), { 0x00000000, 0x00000130 } }, + { AR5K_RF_GAIN(19), { 0x00000000, 0x00000170 } }, + { AR5K_RF_GAIN(20), { 0x00000000, 0x000001b0 } }, + { AR5K_RF_GAIN(21), { 0x00000000, 0x000001f0 } }, + { AR5K_RF_GAIN(22), { 0x00000000, 0x00000030 } }, + { AR5K_RF_GAIN(23), { 0x00000000, 0x00000070 } }, + { AR5K_RF_GAIN(24), { 0x00000000, 0x000000b0 } }, + { AR5K_RF_GAIN(25), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(26), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(27), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(28), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(29), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(30), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(31), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(32), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(33), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(34), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(35), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(36), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(37), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(38), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(39), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(40), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(41), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(42), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(43), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(44), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(45), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(46), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(47), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(48), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(49), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(50), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(51), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(52), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(53), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(54), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(55), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(56), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(57), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(58), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(59), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(60), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(61), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(62), { 0x00000000, 0x000000f0 } }, + { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f0 } }, +}; + + +/* Initial RF Gain settings for RF5413 */ +static const struct ath5k_ini_rfgain rfgain_5413[] = { + /* 5Ghz 2Ghz */ + { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x00000040, 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000080, 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x000001a1, 0x00000161 } }, + { AR5K_RF_GAIN(4), { 0x000001e1, 0x000001a1 } }, + { AR5K_RF_GAIN(5), { 0x00000021, 0x000001e1 } }, + { AR5K_RF_GAIN(6), { 0x00000061, 0x00000021 } }, + { AR5K_RF_GAIN(7), { 0x00000188, 0x00000061 } }, + { AR5K_RF_GAIN(8), { 0x000001c8, 0x00000188 } }, + { AR5K_RF_GAIN(9), { 0x00000008, 0x000001c8 } }, + { AR5K_RF_GAIN(10), { 0x00000048, 0x00000008 } }, + { AR5K_RF_GAIN(11), { 0x00000088, 0x00000048 } }, + { AR5K_RF_GAIN(12), { 0x000001a9, 0x00000088 } }, + { AR5K_RF_GAIN(13), { 0x000001e9, 0x00000169 } }, + { AR5K_RF_GAIN(14), { 0x00000029, 0x000001a9 } }, + { AR5K_RF_GAIN(15), { 0x00000069, 0x000001e9 } }, + { AR5K_RF_GAIN(16), { 0x000001d0, 0x00000029 } }, + { AR5K_RF_GAIN(17), { 0x00000010, 0x00000069 } }, + { AR5K_RF_GAIN(18), { 0x00000050, 0x00000190 } }, + { AR5K_RF_GAIN(19), { 0x00000090, 0x000001d0 } }, + { AR5K_RF_GAIN(20), { 0x000001b1, 0x00000010 } }, + { AR5K_RF_GAIN(21), { 0x000001f1, 0x00000050 } }, + { AR5K_RF_GAIN(22), { 0x00000031, 0x00000090 } }, + { AR5K_RF_GAIN(23), { 0x00000071, 0x00000171 } }, + { AR5K_RF_GAIN(24), { 0x000001b8, 0x000001b1 } }, + { AR5K_RF_GAIN(25), { 0x000001f8, 0x000001f1 } }, + { AR5K_RF_GAIN(26), { 0x00000038, 0x00000031 } }, + { AR5K_RF_GAIN(27), { 0x00000078, 0x00000071 } }, + { AR5K_RF_GAIN(28), { 0x00000199, 0x00000198 } }, + { AR5K_RF_GAIN(29), { 0x000001d9, 0x000001d8 } }, + { AR5K_RF_GAIN(30), { 0x00000019, 0x00000018 } }, + { AR5K_RF_GAIN(31), { 0x00000059, 0x00000058 } }, + { AR5K_RF_GAIN(32), { 0x00000099, 0x00000098 } }, + { AR5K_RF_GAIN(33), { 0x000000d9, 0x00000179 } }, + { AR5K_RF_GAIN(34), { 0x000000f9, 0x000001b9 } }, + { AR5K_RF_GAIN(35), { 0x000000f9, 0x000001f9 } }, + { AR5K_RF_GAIN(36), { 0x000000f9, 0x00000039 } }, + { AR5K_RF_GAIN(37), { 0x000000f9, 0x00000079 } }, + { AR5K_RF_GAIN(38), { 0x000000f9, 0x000000b9 } }, + { AR5K_RF_GAIN(39), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(40), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(41), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(42), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(43), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(44), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(45), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(46), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(47), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(48), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(49), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(50), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(51), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(52), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(53), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(54), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(55), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(56), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(57), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(58), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(59), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(60), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(61), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(62), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } }, +}; + + +/* Initial RF Gain settings for RF2425 */ +static const struct ath5k_ini_rfgain rfgain_2425[] = { + { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x00000000, 0x00000181 } }, + { AR5K_RF_GAIN(4), { 0x00000000, 0x000001c1 } }, + { AR5K_RF_GAIN(5), { 0x00000000, 0x00000001 } }, + { AR5K_RF_GAIN(6), { 0x00000000, 0x00000041 } }, + { AR5K_RF_GAIN(7), { 0x00000000, 0x00000081 } }, + { AR5K_RF_GAIN(8), { 0x00000000, 0x00000188 } }, + { AR5K_RF_GAIN(9), { 0x00000000, 0x000001c8 } }, + { AR5K_RF_GAIN(10), { 0x00000000, 0x00000008 } }, + { AR5K_RF_GAIN(11), { 0x00000000, 0x00000048 } }, + { AR5K_RF_GAIN(12), { 0x00000000, 0x00000088 } }, + { AR5K_RF_GAIN(13), { 0x00000000, 0x00000189 } }, + { AR5K_RF_GAIN(14), { 0x00000000, 0x000001c9 } }, + { AR5K_RF_GAIN(15), { 0x00000000, 0x00000009 } }, + { AR5K_RF_GAIN(16), { 0x00000000, 0x00000049 } }, + { AR5K_RF_GAIN(17), { 0x00000000, 0x00000089 } }, + { AR5K_RF_GAIN(18), { 0x00000000, 0x000001b0 } }, + { AR5K_RF_GAIN(19), { 0x00000000, 0x000001f0 } }, + { AR5K_RF_GAIN(20), { 0x00000000, 0x00000030 } }, + { AR5K_RF_GAIN(21), { 0x00000000, 0x00000070 } }, + { AR5K_RF_GAIN(22), { 0x00000000, 0x00000171 } }, + { AR5K_RF_GAIN(23), { 0x00000000, 0x000001b1 } }, + { AR5K_RF_GAIN(24), { 0x00000000, 0x000001f1 } }, + { AR5K_RF_GAIN(25), { 0x00000000, 0x00000031 } }, + { AR5K_RF_GAIN(26), { 0x00000000, 0x00000071 } }, + { AR5K_RF_GAIN(27), { 0x00000000, 0x000001b8 } }, + { AR5K_RF_GAIN(28), { 0x00000000, 0x000001f8 } }, + { AR5K_RF_GAIN(29), { 0x00000000, 0x00000038 } }, + { AR5K_RF_GAIN(30), { 0x00000000, 0x00000078 } }, + { AR5K_RF_GAIN(31), { 0x00000000, 0x000000b8 } }, + { AR5K_RF_GAIN(32), { 0x00000000, 0x000001b9 } }, + { AR5K_RF_GAIN(33), { 0x00000000, 0x000001f9 } }, + { AR5K_RF_GAIN(34), { 0x00000000, 0x00000039 } }, + { AR5K_RF_GAIN(35), { 0x00000000, 0x00000079 } }, + { AR5K_RF_GAIN(36), { 0x00000000, 0x000000b9 } }, + { AR5K_RF_GAIN(37), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(38), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(39), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(40), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(41), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(42), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(43), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(44), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(45), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(46), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(47), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(48), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(49), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(50), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(51), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(52), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(53), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(54), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(55), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(56), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(57), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(58), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(59), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(60), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(61), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(62), { 0x00000000, 0x000000f9 } }, + { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } }, +}; + +#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 + +/* Check if our current measurement is inside our + * current variable attenuation window */ +#define AR5K_GAIN_CHECK_ADJUST(_g) \ + ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) + +struct ath5k_gain_opt_step { + s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; + s8 gos_gain; +}; + +struct ath5k_gain_opt { + u8 go_default; + u8 go_steps_count; + const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; +}; + +/* + * Parameters on gos_param: + * 1) Tx clip PHY register + * 2) PWD 90 RF register + * 3) PWD 84 RF register + * 4) RFGainSel RF register + */ +static const struct ath5k_gain_opt rfgain_opt_5111 = { + 4, + 9, + { + { { 4, 1, 1, 1 }, 6 }, + { { 4, 0, 1, 1 }, 4 }, + { { 3, 1, 1, 1 }, 3 }, + { { 4, 0, 0, 1 }, 1 }, + { { 4, 1, 1, 0 }, 0 }, + { { 4, 0, 1, 0 }, -2 }, + { { 3, 1, 1, 0 }, -3 }, + { { 4, 0, 0, 0 }, -4 }, + { { 2, 1, 1, 0 }, -6 } + } +}; + +/* + * Parameters on gos_param: + * 1) Mixgain ovr RF register + * 2) PWD 138 RF register + * 3) PWD 137 RF register + * 4) PWD 136 RF register + * 5) PWD 132 RF register + * 6) PWD 131 RF register + * 7) PWD 130 RF register + */ +static const struct ath5k_gain_opt rfgain_opt_5112 = { + 1, + 8, + { + { { 3, 0, 0, 0, 0, 0, 0 }, 6 }, + { { 2, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 0, 0, 0, 0, 0 }, -3 }, + { { 0, 0, 0, 0, 0, 0, 0 }, -6 }, + { { 0, 1, 1, 0, 0, 0, 0 }, -8 }, + { { 0, 1, 1, 0, 1, 1, 0 }, -10 }, + { { 0, 1, 0, 1, 1, 1, 0 }, -13 }, + { { 0, 1, 0, 1, 1, 0, 1 }, -16 }, + } +}; + diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig new file mode 100644 index 0000000..0ed1ac3 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -0,0 +1,24 @@ +config ATH9K + tristate "Atheros 802.11n wireless cards support" + depends on PCI && MAC80211 && WLAN_80211 + depends on RFKILL || RFKILL=n + select ATH_COMMON + 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. + + If you choose to build a module, it'll be called ath9k. + +config ATH9K_DEBUG + bool "Atheros ath9k debugging" + depends on ATH9K + ---help--- + Say Y, if you need ath9k to display debug messages. + Pass the debug mask as a module parameter: + + modprobe ath9k debug=0x00002000 + + Look in ath9k/core.h for possible debug masks diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile new file mode 100644 index 0000000..783bc39 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -0,0 +1,18 @@ +ath9k-y += hw.o \ + eeprom.o \ + mac.o \ + calib.o \ + ani.o \ + phy.o \ + beacon.o \ + main.o \ + recv.o \ + xmit.o \ + virtual.o \ + rc.o + +ath9k-$(CONFIG_PCI) += pci.o +ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o +ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o + +obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c new file mode 100644 index 0000000..0e65c51 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos + * Copyright (c) 2009 Imre Kaloz + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "ath9k.h" + +/* return bus cachesize in 4B word units */ +static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz) +{ + *csz = L1_CACHE_BYTES >> 2; +} + +static void ath_ahb_cleanup(struct ath_softc *sc) +{ + iounmap(sc->mem); +} + +static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) +{ + struct ath_softc *sc = ah->ah_sc; + struct platform_device *pdev = to_platform_device(sc->dev); + struct ath9k_platform_data *pdata; + + pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; + if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "%s: flash read failed, offset %08x is out of range\n", + __func__, off); + return false; + } + + *data = pdata->eeprom_data[off]; + return true; +} + +static struct ath_bus_ops ath_ahb_bus_ops = { + .read_cachesize = ath_ahb_read_cachesize, + .cleanup = ath_ahb_cleanup, + + .eeprom_read = ath_ahb_eeprom_read, +}; + +static int ath_ahb_probe(struct platform_device *pdev) +{ + void __iomem *mem; + struct ath_wiphy *aphy; + struct ath_softc *sc; + struct ieee80211_hw *hw; + struct resource *res; + int irq; + int ret = 0; + struct ath_hw *ah; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data specified\n"); + ret = -EINVAL; + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no memory resource found\n"); + ret = -ENXIO; + goto err_out; + } + + mem = ioremap_nocache(res->start, res->end - res->start + 1); + if (mem == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no IRQ resource found\n"); + ret = -ENXIO; + goto err_iounmap; + } + + irq = res->start; + + hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + + sizeof(struct ath_softc), &ath9k_ops); + if (hw == NULL) { + dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); + ret = -ENOMEM; + goto err_iounmap; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + platform_set_drvdata(pdev, hw); + + aphy = hw->priv; + sc = (struct ath_softc *) (aphy + 1); + aphy->sc = sc; + aphy->hw = hw; + sc->pri_wiphy = aphy; + sc->hw = hw; + sc->dev = &pdev->dev; + sc->mem = mem; + sc->bus_ops = &ath_ahb_bus_ops; + sc->irq = irq; + + ret = ath_attach(AR5416_AR9100_DEVID, sc); + if (ret != 0) { + dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); + ret = -ENODEV; + goto err_free_hw; + } + + ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); + if (ret) { + dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret); + ret = -EIO; + goto err_detach; + } + + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x, " + "AR%s RF Rev:%x, mem=0x%lx, irq=%d\n", + wiphy_name(hw->wiphy), + ath_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev, + ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->hw_version.phyRev, + (unsigned long)mem, irq); + + return 0; + + err_detach: + ath_detach(sc); + err_free_hw: + ieee80211_free_hw(hw); + platform_set_drvdata(pdev, NULL); + err_iounmap: + iounmap(mem); + err_out: + return ret; +} + +static int ath_ahb_remove(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + + if (hw) { + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + ath_cleanup(sc); + platform_set_drvdata(pdev, NULL); + } + + return 0; +} + +static struct platform_driver ath_ahb_driver = { + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ath9k", + .owner = THIS_MODULE, + }, +}; + +int ath_ahb_init(void) +{ + return platform_driver_register(&ath_ahb_driver); +} + +void ath_ahb_exit(void) +{ + platform_driver_unregister(&ath_ahb_driver); +} diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c new file mode 100644 index 0000000..1aeafb5 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -0,0 +1,822 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { + if (ah->ani[i].c && + ah->ani[i].c->channel == chan->channel) + return i; + if (ah->ani[i].c == NULL) { + ah->ani[i].c = chan; + return i; + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "No more channel states left. Using channel 0\n"); + + return 0; +} + +static bool ath9k_hw_ani_control(struct ath_hw *ah, + enum ath9k_ani_cmd cmd, int param) +{ + struct ar5416AniState *aniState = ah->curani; + + switch (cmd & ah->ani_function) { + case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ + u32 level = param; + + if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); + return false; + } + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_TOT_DES, + ah->totalSizeDesired[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_LOW, + ah->coarse_low[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_HIGH, + ah->coarse_high[level]); + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRPWR, + ah->firpwr[level]); + + if (level > aniState->noiseImmunityLevel) + ah->stats.ast_ani_niup++; + else if (level < aniState->noiseImmunityLevel) + ah->stats.ast_ani_nidown++; + aniState->noiseImmunityLevel = level; + break; + } + case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ + const int m1ThreshLow[] = { 127, 50 }; + const int m2ThreshLow[] = { 127, 40 }; + const int m1Thresh[] = { 127, 0x4d }; + const int m2Thresh[] = { 127, 0x40 }; + const int m2CountThr[] = { 31, 16 }; + const int m2CountThrLow[] = { 63, 48 }; + u32 on = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2_THRESH, + m2Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2COUNT_THR, + m2CountThr[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, + m2CountThrLow[on]); + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, + m2Thresh[on]); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + else + REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + + if (!on != aniState->ofdmWeakSigDetectOff) { + if (on) + ah->stats.ast_ani_ofdmon++; + else + ah->stats.ast_ani_ofdmoff++; + aniState->ofdmWeakSigDetectOff = !on; + } + break; + } + case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ + const int weakSigThrCck[] = { 8, 6 }; + u32 high = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, + weakSigThrCck[high]); + if (high != aniState->cckWeakSigThreshold) { + if (high) + ah->stats.ast_ani_cckhigh++; + else + ah->stats.ast_ani_ccklow++; + aniState->cckWeakSigThreshold = high; + } + break; + } + case ATH9K_ANI_FIRSTEP_LEVEL:{ + const int firstep[] = { 0, 4, 8 }; + u32 level = param; + + if (level >= ARRAY_SIZE(firstep)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(firstep)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, + firstep[level]); + if (level > aniState->firstepLevel) + ah->stats.ast_ani_stepup++; + else if (level < aniState->firstepLevel) + ah->stats.ast_ani_stepdown++; + aniState->firstepLevel = level; + break; + } + case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ + const int cycpwrThr1[] = + { 2, 4, 6, 8, 10, 12, 14, 16 }; + u32 level = param; + + if (level >= ARRAY_SIZE(cycpwrThr1)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) + ARRAY_SIZE(cycpwrThr1)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, + cycpwrThr1[level]); + if (level > aniState->spurImmunityLevel) + ah->stats.ast_ani_spurup++; + else if (level < aniState->spurImmunityLevel) + ah->stats.ast_ani_spurdown++; + aniState->spurImmunityLevel = level; + break; + } + case ATH9K_ANI_PRESENT: + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "invalid cmd %u\n", cmd); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n"); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "noiseImmunityLevel=%d, spurImmunityLevel=%d, " + "ofdmWeakSigDetectOff=%d\n", + aniState->noiseImmunityLevel, aniState->spurImmunityLevel, + !aniState->ofdmWeakSigDetectOff); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cckWeakSigThreshold=%d, " + "firstepLevel=%d, listenTime=%d\n", + aniState->cckWeakSigThreshold, aniState->firstepLevel, + aniState->listenTime); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", + aniState->cycleCount, aniState->ofdmPhyErrCount, + aniState->cckPhyErrCount); + + return true; +} + +static void ath9k_hw_update_mibstats(struct ath_hw *ah, + struct ath9k_mib_stats *stats) +{ + stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += REG_READ(ah, AR_RTS_OK); + stats->beacons += REG_READ(ah, AR_BEACON_CNT); +} + +static void ath9k_ani_restart(struct ath_hw *ah) +{ + struct ar5416AniState *aniState; + + if (!DO_ANI(ah)) + return; + + aniState = ah->curani; + + aniState->listenTime = 0; + if (ah->has_hw_phycounters) { + if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { + aniState->ofdmPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "OFDM Trigger is too high for hw counters\n"); + } else { + aniState->ofdmPhyErrBase = + AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; + } + if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { + aniState->cckPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "CCK Trigger is too high for hw counters\n"); + } else { + aniState->cckPhyErrBase = + AR_PHY_COUNTMAX - aniState->cckTrigHigh; + } + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Writing ofdmbase=%u cckbase=%u\n", + aniState->ofdmPhyErrBase, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + } + aniState->ofdmPhyErrCount = 0; + aniState->cckPhyErrCount = 0; +} + +static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ar5416AniState *aniState; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ah->curani; + + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + + if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel + 1)) { + return; + } + } + + if (ah->opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ah); + if (rssi > aniState->rssiThrHigh) { + if (!aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false)) { + ath9k_hw_ani_control(ah, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + return; + } + } + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true); + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } else { + if (conf->channel->band == IEEE80211_BAND_2GHZ) { + if (!aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false); + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + return; + } + } +} + +static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ar5416AniState *aniState; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ah->curani; + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + if (ah->opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ah); + if (rssi > aniState->rssiThrLow) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } else { + if (conf->channel->band == IEEE80211_BAND_2GHZ) { + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + } + } +} + +static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) +{ + struct ar5416AniState *aniState; + int32_t rssi; + + aniState = ah->curani; + + if (ah->opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1)) + return; + } + } else { + rssi = BEACON_RSSI(ah); + if (rssi > aniState->rssiThrHigh) { + /* XXX: Handle me */ + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true) == true) + return; + } + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } else { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } + } + + if (aniState->spurImmunityLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel - 1)) + return; + } + + if (aniState->noiseImmunityLevel > 0) { + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel - 1); + return; + } +} + +static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) +{ + struct ar5416AniState *aniState; + u32 txFrameCount, rxFrameCount, cycleCount; + int32_t listenTime; + + txFrameCount = REG_READ(ah, AR_TFCNT); + rxFrameCount = REG_READ(ah, AR_RFCNT); + cycleCount = REG_READ(ah, AR_CCCNT); + + aniState = ah->curani; + if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { + + listenTime = 0; + ah->stats.ast_ani_lzero++; + } else { + int32_t ccdelta = cycleCount - aniState->cycleCount; + int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; + int32_t tfdelta = txFrameCount - aniState->txFrameCount; + listenTime = (ccdelta - rfdelta - tfdelta) / 44000; + } + aniState->cycleCount = cycleCount; + aniState->txFrameCount = txFrameCount; + aniState->rxFrameCount = rxFrameCount; + + return listenTime; +} + +void ath9k_ani_reset(struct ath_hw *ah) +{ + struct ar5416AniState *aniState; + struct ath9k_channel *chan = ah->curchan; + int index; + + if (!DO_ANI(ah)) + return; + + index = ath9k_hw_get_ani_channel_idx(ah, chan); + aniState = &ah->ani[index]; + ah->curani = aniState; + + if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION + && ah->opmode != NL80211_IFTYPE_ADHOC) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Reset ANI state opmode %u\n", ah->opmode); + ah->stats.ast_ani_reset++; + + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !ATH9K_ANI_USE_OFDM_WEAK_SIG); + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + ATH9K_ANI_CCK_WEAK_SIG_THR); + + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + + if (ah->opmode == NL80211_IFTYPE_AP) { + ah->curani->ofdmTrigHigh = + ah->config.ofdm_trig_high; + ah->curani->ofdmTrigLow = + ah->config.ofdm_trig_low; + ah->curani->cckTrigHigh = + ah->config.cck_trig_high; + ah->curani->cckTrigLow = + ah->config.cck_trig_low; + } + ath9k_ani_restart(ah); + return; + } + + if (aniState->noiseImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel); + if (aniState->spurImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel); + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !aniState->ofdmWeakSigDetectOff); + if (aniState->cckWeakSigThreshold) + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + aniState->cckWeakSigThreshold); + if (aniState->firstepLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel); + if (ah->has_hw_phycounters) { + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & + ~ATH9K_RX_FILTER_PHYERR); + ath9k_ani_restart(ah); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + } else { + ath9k_ani_restart(ah); + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + } +} + +void ath9k_hw_ani_monitor(struct ath_hw *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan) +{ + struct ar5416AniState *aniState; + int32_t listenTime; + + if (!DO_ANI(ah)) + return; + + aniState = ah->curani; + ah->stats.ast_nodestats = *stats; + + listenTime = ath9k_hw_ani_get_listen_time(ah); + if (listenTime < 0) { + ah->stats.ast_ani_lneg++; + ath9k_ani_restart(ah); + return; + } + + aniState->listenTime += listenTime; + + if (ah->has_hw_phycounters) { + u32 phyCnt1, phyCnt2; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + + if (phyCnt1 < aniState->ofdmPhyErrBase || + phyCnt2 < aniState->cckPhyErrBase) { + if (phyCnt1 < aniState->ofdmPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, + AR_PHY_ERR_OFDM_TIMING); + } + if (phyCnt2 < aniState->cckPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, + AR_PHY_ERR_CCK_TIMING); + } + return; + } + + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ah->stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ah->stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + } + + if (aniState->listenTime > 5 * ah->aniperiod) { + if (aniState->ofdmPhyErrCount <= aniState->listenTime * + aniState->ofdmTrigLow / 1000 && + aniState->cckPhyErrCount <= aniState->listenTime * + aniState->cckTrigLow / 1000) + ath9k_hw_ani_lower_immunity(ah); + ath9k_ani_restart(ah); + } else if (aniState->listenTime > ah->aniperiod) { + if (aniState->ofdmPhyErrCount > aniState->listenTime * + aniState->ofdmTrigHigh / 1000) { + ath9k_hw_ani_ofdm_err_trigger(ah); + ath9k_ani_restart(ah); + } else if (aniState->cckPhyErrCount > + aniState->listenTime * aniState->cckTrigHigh / + 1000) { + ath9k_hw_ani_cck_err_trigger(ah); + ath9k_ani_restart(ah); + } + } +} + +bool ath9k_hw_phycounters(struct ath_hw *ah) +{ + return ah->has_hw_phycounters ? true : false; +} + +void ath9k_enable_mib_counters(struct ath_hw *ah) +{ + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); + + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); + REG_WRITE(ah, AR_MIBC, + ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) + & 0x0f); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); +} + +/* Freeze the MIB counters, get the stats and then clear them */ +void ath9k_hw_disable_mib_counters(struct ath_hw *ah) +{ + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); +} + +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, + u32 *rxc_pcnt, + u32 *rxf_pcnt, + u32 *txf_pcnt) +{ + static u32 cycles, rx_clear, rx_frame, tx_frame; + u32 good = 1; + + u32 rc = REG_READ(ah, AR_RCCNT); + u32 rf = REG_READ(ah, AR_RFCNT); + u32 tf = REG_READ(ah, AR_TFCNT); + u32 cc = REG_READ(ah, AR_CCCNT); + + if (cycles == 0 || cycles > cc) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cycle counter wrap. ExtBusy = 0\n"); + good = 0; + } else { + u32 cc_d = cc - cycles; + u32 rc_d = rc - rx_clear; + u32 rf_d = rf - rx_frame; + u32 tf_d = tf - tx_frame; + + if (cc_d != 0) { + *rxc_pcnt = rc_d * 100 / cc_d; + *rxf_pcnt = rf_d * 100 / cc_d; + *txf_pcnt = tf_d * 100 / cc_d; + } else { + good = 0; + } + } + + cycles = cc; + rx_frame = rf; + rx_clear = rc; + tx_frame = tf; + + return good; +} + +/* + * 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_hw *ah, + const struct ath9k_node_stats *stats) +{ + u32 phyCnt1, phyCnt2; + + /* 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, &ah->ah_mibStats); + 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) || + ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { + struct ar5416AniState *aniState = ah->curani; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ah->stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ah->stats.ast_ani_cckerrs += + 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); + } +} + +void ath9k_hw_ani_setup(struct ath_hw *ah) +{ + int i; + + const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; + const int coarseHigh[] = { -14, -14, -14, -14, -12 }; + const int coarseLow[] = { -64, -64, -64, -64, -70 }; + const int firpwr[] = { -78, -78, -78, -78, -80 }; + + for (i = 0; i < 5; i++) { + ah->totalSizeDesired[i] = totalSizeDesired[i]; + ah->coarse_high[i] = coarseHigh[i]; + ah->coarse_low[i] = coarseLow[i]; + ah->firpwr[i] = firpwr[i]; + } +} + +void ath9k_hw_ani_attach(struct ath_hw *ah) +{ + int i; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); + + ah->has_hw_phycounters = 1; + + memset(ah->ani, 0, sizeof(ah->ani)); + for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { + ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; + ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; + ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; + ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; + ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; + ah->ani[i].ofdmWeakSigDetectOff = + !ATH9K_ANI_USE_OFDM_WEAK_SIG; + ah->ani[i].cckWeakSigThreshold = + ATH9K_ANI_CCK_WEAK_SIG_THR; + ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; + ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; + if (ah->has_hw_phycounters) { + ah->ani[i].ofdmPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; + ah->ani[i].cckPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; + } + } + if (ah->has_hw_phycounters) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Setting OfdmErrBase = 0x%08x\n", + ah->ani[0].ofdmPhyErrBase); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + ah->ani[0].cckPhyErrBase); + + REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); + ath9k_enable_mib_counters(ah); + } + ah->aniperiod = ATH9K_ANI_PERIOD; + if (ah->config.enable_ani) + ah->proc_phyerr |= HAL_PROCESS_ANI; +} + +void ath9k_hw_ani_detach(struct ath_hw *ah) +{ + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); + + if (ah->has_hw_phycounters) { + ath9k_hw_disable_mib_counters(ah); + REG_WRITE(ah, AR_PHY_ERR_1, 0); + REG_WRITE(ah, AR_PHY_ERR_2, 0); + } +} diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h new file mode 100644 index 0000000..08b4e7e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ANI_H +#define ANI_H + +#define HAL_PROCESS_ANI 0x00000001 +#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) + +#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) + +#define HAL_EP_RND(x, mul) \ + ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) +#define BEACON_RSSI(ahp) \ + HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \ + ATH9K_RSSI_EP_MULTIPLIER) + +#define ATH9K_ANI_OFDM_TRIG_HIGH 500 +#define ATH9K_ANI_OFDM_TRIG_LOW 200 +#define ATH9K_ANI_CCK_TRIG_HIGH 200 +#define ATH9K_ANI_CCK_TRIG_LOW 100 +#define ATH9K_ANI_NOISE_IMMUNE_LVL 4 +#define ATH9K_ANI_USE_OFDM_WEAK_SIG true +#define ATH9K_ANI_CCK_WEAK_SIG_THR false +#define ATH9K_ANI_SPUR_IMMUNE_LVL 7 +#define ATH9K_ANI_FIRSTEP_LVL 0 +#define ATH9K_ANI_RSSI_THR_HIGH 40 +#define ATH9K_ANI_RSSI_THR_LOW 7 +#define ATH9K_ANI_PERIOD 100 + +#define HAL_NOISE_IMMUNE_MAX 4 +#define HAL_SPUR_IMMUNE_MAX 7 +#define HAL_FIRST_STEP_MAX 2 + +enum ath9k_ani_cmd { + ATH9K_ANI_PRESENT = 0x1, + ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4, + ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8, + ATH9K_ANI_FIRSTEP_LEVEL = 0x10, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20, + ATH9K_ANI_MODE = 0x40, + ATH9K_ANI_PHYERR_RESET = 0x80, + ATH9K_ANI_ALL = 0xff +}; + +struct ath9k_mib_stats { + u32 ackrcv_bad; + u32 rts_bad; + u32 rts_good; + u32 fcs_bad; + u32 beacons; +}; + +struct ath9k_node_stats { + u32 ns_avgbrssi; + u32 ns_avgrssi; + u32 ns_avgtxrssi; + u32 ns_avgtxrate; +}; + +struct ar5416AniState { + struct ath9k_channel *c; + u8 noiseImmunityLevel; + u8 spurImmunityLevel; + u8 firstepLevel; + u8 ofdmWeakSigDetectOff; + u8 cckWeakSigThreshold; + u32 listenTime; + u32 ofdmTrigHigh; + u32 ofdmTrigLow; + int32_t cckTrigHigh; + int32_t cckTrigLow; + int32_t rssiThrLow; + int32_t rssiThrHigh; + u32 noiseFloor; + u32 txFrameCount; + u32 rxFrameCount; + u32 cycleCount; + u32 ofdmPhyErrCount; + u32 cckPhyErrCount; + u32 ofdmPhyErrBase; + u32 cckPhyErrBase; + int16_t pktRssi[2]; + int16_t ofdmErrRssi[2]; + int16_t cckErrRssi[2]; +}; + +struct ar5416Stats { + u32 ast_ani_niup; + u32 ast_ani_nidown; + u32 ast_ani_spurup; + u32 ast_ani_spurdown; + u32 ast_ani_ofdmon; + u32 ast_ani_ofdmoff; + u32 ast_ani_cckhigh; + u32 ast_ani_ccklow; + u32 ast_ani_stepup; + u32 ast_ani_stepdown; + u32 ast_ani_ofdmerrs; + u32 ast_ani_cckerrs; + u32 ast_ani_reset; + u32 ast_ani_lzero; + u32 ast_ani_lneg; + struct ath9k_mib_stats ast_mibstats; + struct ath9k_node_stats ast_nodestats; +}; +#define ah_mibStats stats.ast_mibstats + +void ath9k_ani_reset(struct ath_hw *ah); +void ath9k_hw_ani_monitor(struct ath_hw *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan); +bool ath9k_hw_phycounters(struct ath_hw *ah); +void ath9k_enable_mib_counters(struct ath_hw *ah); +void ath9k_hw_disable_mib_counters(struct ath_hw *ah); +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, + u32 *rxf_pcnt, u32 *txf_pcnt); +void ath9k_hw_procmibevent(struct ath_hw *ah, + const struct ath9k_node_stats *stats); +void ath9k_hw_ani_setup(struct ath_hw *ah); +void ath9k_hw_ani_attach(struct ath_hw *ah); +void ath9k_hw_ani_detach(struct ath_hw *ah); + +#endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h new file mode 100644 index 0000000..c92d46f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -0,0 +1,730 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ATH9K_H +#define ATH9K_H + +#include +#include +#include +#include +#include + +#include "hw.h" +#include "rc.h" +#include "debug.h" + +struct ath_node; + +/* Macro to expand scalars to 64-bit objects */ + +#define ito64(x) (sizeof(x) == 8) ? \ + (((unsigned long long int)(x)) & (0xff)) : \ + (sizeof(x) == 16) ? \ + (((unsigned long long int)(x)) & 0xffff) : \ + ((sizeof(x) == 32) ? \ + (((unsigned long long int)(x)) & 0xffffffff) : \ + (unsigned long long int)(x)) + +/* increment with wrap-around */ +#define INCR(_l, _sz) do { \ + (_l)++; \ + (_l) &= ((_sz) - 1); \ + } while (0) + +/* decrement with wrap-around */ +#define DECR(_l, _sz) do { \ + (_l)--; \ + (_l) &= ((_sz) - 1); \ + } while (0) + +#define A_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define ASSERT(exp) BUG_ON(!(exp)) + +#define TSF_TO_TU(_h,_l) \ + ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) + +#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<bf_stale = false; \ + (_bf)->bf_lastbf = NULL; \ + (_bf)->bf_next = NULL; \ + memset(&((_bf)->bf_state), 0, \ + sizeof(struct ath_buf_state)); \ + } while (0) + +#define ATH_RXBUF_RESET(_bf) do { \ + (_bf)->bf_stale = false; \ + } while (0) + +/** + * enum buffer_type - Buffer type flags + * + * @BUF_HT: Send this buffer using HT capabilities + * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) + * @BUF_AGGR: Indicates whether the buffer can be aggregated + * (used in aggregation scheduling) + * @BUF_RETRY: Indicates whether the buffer is retried + * @BUF_XRETRY: To denote excessive retries of the buffer + */ +enum buffer_type { + BUF_HT = BIT(1), + BUF_AMPDU = BIT(2), + BUF_AGGR = BIT(3), + BUF_RETRY = BIT(4), + BUF_XRETRY = BIT(5), +}; + +struct ath_buf_state { + int bfs_nframes; + u16 bfs_al; + u16 bfs_frmlen; + int bfs_seqno; + int bfs_tidno; + int bfs_retries; + u8 bf_type; + u32 bfs_keyix; + enum ath9k_key_type bfs_keytype; +}; + +#define bf_nframes bf_state.bfs_nframes +#define bf_al bf_state.bfs_al +#define bf_frmlen bf_state.bfs_frmlen +#define bf_retries bf_state.bfs_retries +#define bf_seqno bf_state.bfs_seqno +#define bf_tidno bf_state.bfs_tidno +#define bf_keyix bf_state.bfs_keyix +#define bf_keytype bf_state.bfs_keytype +#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) +#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) +#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) +#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) +#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) + +struct ath_buf { + struct list_head list; + struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or + an aggregate) */ + struct ath_buf *bf_next; /* next subframe in the aggregate */ + struct sk_buff *bf_mpdu; /* enclosing frame structure */ + struct ath_desc *bf_desc; /* virtual addr of desc */ + dma_addr_t bf_daddr; /* physical addr of desc */ + dma_addr_t bf_buf_addr; /* physical addr of data buffer */ + bool bf_stale; + u16 bf_flags; + struct ath_buf_state bf_state; + dma_addr_t bf_dmacontext; +}; + +struct ath_descdma { + struct ath_desc *dd_desc; + dma_addr_t dd_desc_paddr; + u32 dd_desc_len; + struct ath_buf *dd_bufptr; +}; + +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc); +void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head); + +/***********/ +/* RX / TX */ +/***********/ + +#define ATH_MAX_ANTENNA 3 +#define ATH_RXBUF 512 +#define WME_NUM_TID 16 +#define ATH_TXBUF 512 +#define ATH_TXMAXTRY 13 +#define ATH_11N_TXMAXTRY 10 +#define ATH_MGT_TXMAXTRY 4 +#define WME_BA_BMP_SIZE 64 +#define WME_MAX_BA WME_BA_BMP_SIZE +#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) + +#define TID_TO_WME_AC(_tid) \ + ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ + WME_AC_VO) + +#define WME_AC_BE 0 +#define WME_AC_BK 1 +#define WME_AC_VI 2 +#define WME_AC_VO 3 +#define WME_NUM_AC 4 + +#define ADDBA_EXCHANGE_ATTEMPTS 10 +#define ATH_AGGR_DELIM_SZ 4 +#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ +/* number of delimiters for encryption padding */ +#define ATH_AGGR_ENCRYPTDELIM 10 +/* minimum h/w qdepth to be sustained to maximize aggregation */ +#define ATH_AGGR_MIN_QDEPTH 2 +#define ATH_AMPDU_SUBFRAME_DEFAULT 32 +#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) +#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX + +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 +#define IEEE80211_WEP_IVLEN 3 +#define IEEE80211_WEP_KIDLEN 1 +#define IEEE80211_WEP_CRCLEN 4 +#define IEEE80211_MAX_MPDU_LEN (3840 + FCS_LEN + \ + (IEEE80211_WEP_IVLEN + \ + IEEE80211_WEP_KIDLEN + \ + IEEE80211_WEP_CRCLEN)) + +/* return whether a bit at index _n in bitmap _bm is set + * _sz is the size of the bitmap */ +#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ + ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) + +/* return block-ack bitmap index given sequence and starting sequence */ +#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) + +/* returns delimiter padding required given the packet length */ +#define ATH_AGGR_GET_NDELIM(_len) \ + (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ + (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) + +#define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 4095) < (_bawsz)) + +#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) +#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) +#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) +#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) + +enum ATH_AGGR_STATUS { + ATH_AGGR_DONE, + ATH_AGGR_BAW_CLOSED, + ATH_AGGR_LIMITED, +}; + +struct ath_txq { + u32 axq_qnum; + u32 *axq_link; + struct list_head axq_q; + spinlock_t axq_lock; + u32 axq_depth; + u8 axq_aggr_depth; + u32 axq_totalqueued; + bool stopped; + struct ath_buf *axq_linkbuf; + + /* first desc of the last descriptor that contains CTS */ + struct ath_desc *axq_lastdsWithCTS; + + /* final desc of the gating desc that determines whether + lastdsWithCTS has been DMA'ed or not */ + struct ath_desc *axq_gatingds; + + struct list_head axq_acq; +}; + +#define AGGR_CLEANUP BIT(1) +#define AGGR_ADDBA_COMPLETE BIT(2) +#define AGGR_ADDBA_PROGRESS BIT(3) + +struct ath_atx_tid { + struct list_head list; + struct list_head buf_q; + struct ath_node *an; + struct ath_atx_ac *ac; + struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; + u16 seq_start; + u16 seq_next; + u16 baw_size; + int tidno; + int baw_head; /* first un-acked tx buffer */ + int baw_tail; /* next unused tx buffer slot */ + int sched; + int paused; + u8 state; + int addba_exchangeattempts; +}; + +struct ath_atx_ac { + int sched; + int qnum; + struct list_head list; + struct list_head tid_q; +}; + +struct ath_tx_control { + struct ath_txq *txq; + int if_id; + enum ath9k_internal_frame_type frame_type; +}; + +#define ATH_TX_ERROR 0x01 +#define ATH_TX_XRETRY 0x02 +#define ATH_TX_BAR 0x04 + +struct ath_node { + struct ath_softc *an_sc; + struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_ac ac[WME_NUM_AC]; + u16 maxampdu; + u8 mpdudensity; +}; + +struct ath_tx { + u16 seq_no; + u32 txqsetup; + int hwq_map[ATH9K_WME_AC_VO+1]; + spinlock_t txbuflock; + struct list_head txbuf; + struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; + struct ath_descdma txdma; +}; + +struct ath_rx { + u8 defant; + u8 rxotherant; + u32 *rxlink; + int bufsize; + unsigned int rxfilter; + spinlock_t rxflushlock; + spinlock_t rxbuflock; + struct list_head rxbuf; + struct ath_descdma rxdma; +}; + +int ath_startrecv(struct ath_softc *sc); +bool ath_stoprecv(struct ath_softc *sc); +void ath_flushrecv(struct ath_softc *sc); +u32 ath_calcrxfilter(struct ath_softc *sc); +int ath_rx_init(struct ath_softc *sc, int nbufs); +void ath_rx_cleanup(struct ath_softc *sc); +int ath_rx_tasklet(struct ath_softc *sc, int flush); +struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); +void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); +int ath_tx_setup(struct ath_softc *sc, int haltype); +void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); +void ath_draintxq(struct ath_softc *sc, + 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); +void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); +int ath_tx_init(struct ath_softc *sc, int nbufs); +void ath_tx_cleanup(struct ath_softc *sc); +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); +int ath_txq_update(struct ath_softc *sc, int qnum, + struct ath9k_tx_queue_info *q); +int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath_tx_control *txctl); +void ath_tx_tasklet(struct ath_softc *sc); +void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); + +/********/ +/* VIFs */ +/********/ + +struct ath_vif { + int av_bslot; + __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ + enum nl80211_iftype av_opmode; + struct ath_buf *av_bcbuf; + struct ath_tx_control av_btxctl; + u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ +}; + +/*******************/ +/* Beacon Handling */ +/*******************/ + +/* + * Regardless of the number of beacons we stagger, (i.e. regardless of the + * number of BSSIDs) if a given beacon does not go out even after waiting this + * number of beacon intervals, the game's up. + */ +#define BSTUCK_THRESH (9 * ATH_BCBUF) +#define ATH_BCBUF 4 +#define ATH_DEFAULT_BINTVAL 100 /* TU */ +#define ATH_DEFAULT_BMISS_LIMIT 10 +#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) + +struct ath_beacon_config { + u16 beacon_interval; + u16 listen_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; +}; + +struct ath_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + + u32 beaconq; + u32 bmisscnt; + u32 ast_be_xmit; + u64 bc_tstamp; + struct ieee80211_vif *bslot[ATH_BCBUF]; + struct ath_wiphy *bslot_aphy[ATH_BCBUF]; + int slottime; + int slotupdate; + struct ath9k_tx_queue_info beacon_qi; + struct ath_descdma bdma; + struct ath_txq *cabq; + struct list_head bbuf; +}; + +void ath_beacon_tasklet(unsigned long data); +void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); +int ath_beaconq_setup(struct ath_hw *ah); +int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); +void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); + +/*******/ +/* ANI */ +/*******/ + +#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ +#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */ +#define ATH_ANI_POLLINTERVAL 100 /* 100 ms */ +#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ +#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ + +struct ath_ani { + bool caldone; + int16_t noise_floor; + unsigned int longcal_timer; + unsigned int shortcal_timer; + unsigned int resetcal_timer; + unsigned int checkani_timer; + struct timer_list timer; +}; + +/********************/ +/* LED Control */ +/********************/ + +#define ATH_LED_PIN 1 +#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ +#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ + +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 */ +/********************/ + +/* + * Default cache line size, in bytes. + * Used when PCI device not fully initialized by bootrom/BIOS +*/ +#define DEFAULT_CACHELINE 32 +#define ATH_DEFAULT_NOISE_FLOOR -95 +#define ATH_REGCLASSIDS_MAX 10 +#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ +#define ATH_MAX_SW_RETRIES 10 +#define ATH_CHAN_MAX 255 +#define IEEE80211_WEP_NKID 4 /* number of key ids */ + +/* + * The key cache is used for h/w cipher state and also for + * tracking station state such as the current tx antenna. + * We also setup a mapping table between key cache slot indices + * and station state to short-circuit node lookups on rx. + * Different parts have different size key caches. We handle + * up to ATH_KEYMAX entries (could dynamically allocate state). + */ +#define ATH_KEYMAX 128 /* max key cache size we handle */ + +#define ATH_TXPOWER_MAX 100 /* .5 dBm units */ +#define ATH_RSSI_DUMMY_MARKER 0x127 +#define ATH_RATE_DUMMY_MARKER 0 + +#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_FULL_RESET BIT(4) +#define SC_OP_PREAMBLE_SHORT BIT(5) +#define SC_OP_PROTECT_ENABLE BIT(6) +#define SC_OP_RXFLUSH BIT(7) +#define SC_OP_LED_ASSOCIATED BIT(8) +#define SC_OP_RFKILL_REGISTERED BIT(9) +#define SC_OP_RFKILL_SW_BLOCKED BIT(10) +#define SC_OP_RFKILL_HW_BLOCKED BIT(11) +#define SC_OP_WAIT_FOR_BEACON BIT(12) +#define SC_OP_LED_ON BIT(13) +#define SC_OP_SCANNING BIT(14) +#define SC_OP_TSF_RESET BIT(15) + +struct ath_bus_ops { + void (*read_cachesize)(struct ath_softc *sc, int *csz); + void (*cleanup)(struct ath_softc *sc); + bool (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data); +}; + +struct ath_wiphy; + +struct ath_softc { + struct ieee80211_hw *hw; + struct device *dev; + + spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ + struct ath_wiphy *pri_wiphy; + struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may + * have NULL entries */ + int num_sec_wiphy; /* number of sec_wiphy pointers in the array */ + int chan_idx; + int chan_is_ht; + struct ath_wiphy *next_wiphy; + struct work_struct chan_work; + int wiphy_select_failures; + unsigned long wiphy_select_first_fail; + struct delayed_work wiphy_work; + unsigned long wiphy_scheduler_int; + int wiphy_scheduler_index; + + struct tasklet_struct intr_tq; + struct tasklet_struct bcon_tasklet; + struct ath_hw *sc_ah; + void __iomem *mem; + int irq; + spinlock_t sc_resetlock; + spinlock_t sc_serial_rw; + struct mutex mutex; + + u8 curbssid[ETH_ALEN]; + u8 bssidmask[ETH_ALEN]; + u32 intrstatus; + u32 sc_flags; /* SC_OP_* */ + u16 curtxpow; + u16 curaid; + u16 cachelsz; + u8 nbcnvifs; + u16 nvifs; + u8 tx_chainmask; + u8 rx_chainmask; + u32 keymax; + DECLARE_BITMAP(keymap, ATH_KEYMAX); + u8 splitmic; + atomic_t ps_usecount; + enum ath9k_int imask; + enum ath9k_ht_extprotspacing ht_extprotspacing; + enum ath9k_ht_macmode tx_chan_width; + + struct ath_config config; + struct ath_rx rx; + struct ath_tx tx; + struct ath_beacon beacon; + struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; + struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + struct ath_rate_table *cur_rate_table; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + + struct ath_led radio_led; + struct ath_led assoc_led; + struct ath_led tx_led; + struct ath_led rx_led; + struct delayed_work ath_led_blink_work; + int led_on_duration; + int led_off_duration; + int led_on_cnt; + int led_off_cnt; + + struct ath_rfkill rf_kill; + struct ath_ani ani; + struct ath9k_node_stats nodestats; +#ifdef CONFIG_ATH9K_DEBUG + struct ath9k_debug debug; +#endif + struct ath_bus_ops *bus_ops; +}; + +struct ath_wiphy { + struct ath_softc *sc; /* shared for all virtual wiphys */ + struct ieee80211_hw *hw; + enum ath_wiphy_state { + ATH_WIPHY_INACTIVE, + ATH_WIPHY_ACTIVE, + ATH_WIPHY_PAUSING, + ATH_WIPHY_PAUSED, + ATH_WIPHY_SCAN, + } state; + int chan_idx; + int chan_is_ht; +}; + +int ath_reset(struct ath_softc *sc, bool retry_tx); +int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); +int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); +int ath_cabq_update(struct ath_softc *); + +static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) +{ + sc->bus_ops->read_cachesize(sc, csz); +} + +static inline void ath_bus_cleanup(struct ath_softc *sc) +{ + sc->bus_ops->cleanup(sc); +} + +extern struct ieee80211_ops ath9k_ops; + +irqreturn_t ath_isr(int irq, void *dev); +void ath_cleanup(struct ath_softc *sc); +int ath_attach(u16 devid, struct ath_softc *sc); +void ath_detach(struct ath_softc *sc); +const char *ath_mac_bb_name(u32 mac_bb_version); +const char *ath_rf_name(u16 rf_version); +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); +void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *ichan); +void ath_update_chainmask(struct ath_softc *sc, int is_ht); +int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *hchan); +void ath_radio_enable(struct ath_softc *sc); +void ath_radio_disable(struct ath_softc *sc); + +#ifdef CONFIG_PCI +int ath_pci_init(void); +void ath_pci_exit(void); +#else +static inline int ath_pci_init(void) { return 0; }; +static inline void ath_pci_exit(void) {}; +#endif + +#ifdef CONFIG_ATHEROS_AR71XX +int ath_ahb_init(void); +void ath_ahb_exit(void); +#else +static inline int ath_ahb_init(void) { return 0; }; +static inline void ath_ahb_exit(void) {}; +#endif + +static inline void ath9k_ps_wakeup(struct ath_softc *sc) +{ + if (atomic_inc_return(&sc->ps_usecount) == 1) + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { + sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + } +} + +static inline void ath9k_ps_restore(struct ath_softc *sc) +{ + if (atomic_dec_and_test(&sc->ps_usecount)) + if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && + !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) + ath9k_hw_setpower(sc->sc_ah, + sc->sc_ah->restore_mode); +} + + +void ath9k_set_bssid_mask(struct ieee80211_hw *hw); +int ath9k_wiphy_add(struct ath_softc *sc); +int ath9k_wiphy_del(struct ath_wiphy *aphy); +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); +int ath9k_wiphy_pause(struct ath_wiphy *aphy); +int ath9k_wiphy_unpause(struct ath_wiphy *aphy); +int ath9k_wiphy_select(struct ath_wiphy *aphy); +void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int); +void ath9k_wiphy_chan_work(struct work_struct *work); +bool ath9k_wiphy_started(struct ath_softc *sc); +void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, + struct ath_wiphy *selected); +bool ath9k_wiphy_scanning(struct ath_softc *sc); +void ath9k_wiphy_work(struct work_struct *work); + +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. After + * that the device goes bananas. Serializing the reads/writes prevents this + * from happening. + */ + +static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) +{ + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + iowrite32(val, ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + iowrite32(val, ah->ah_sc->mem + reg_offset); +} + +static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) +{ + u32 val; + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + val = ioread32(ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + val = ioread32(ah->ah_sc->mem + reg_offset); + return val; +} + +#endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c new file mode 100644 index 0000000..eb4759f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +#define FUDGE 2 + +/* + * This function will modify certain transmit queue properties depending on + * 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_hw *ah = sc->sc_ah; + struct ath9k_tx_queue_info qi; + + ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { + /* Always burst out beacon and CAB traffic. */ + qi.tqi_aifs = 1; + qi.tqi_cwmin = 0; + qi.tqi_cwmax = 0; + } else { + /* Adhoc mode; important thing is to use 2x cwmin. */ + qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs; + qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin; + qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax; + } + + if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to update h/w beacon queue parameters\n"); + return 0; + } else { + ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); + return 1; + } +} + +/* + * Associates the beacon frame buffer with a transmit descriptor. Will set + * up all required antenna switch parameters, rate codes, and channel flags. + * Beacons are always sent out at the lowest rate, and are not retried. +*/ +static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, + struct ath_buf *bf) +{ + struct sk_buff *skb = bf->bf_mpdu; + struct ath_hw *ah = sc->sc_ah; + struct ath_desc *ds; + struct ath9k_11n_rate_series series[4]; + struct ath_rate_table *rt; + int flags, antenna, ctsrate = 0, ctsduration = 0; + u8 rate; + + ds = bf->bf_desc; + flags = ATH9K_TXDESC_NOACK; + + if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || + (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) && + (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { + ds->ds_link = bf->bf_daddr; /* self-linked */ + flags |= ATH9K_TXDESC_VEOL; + /* Let hardware handle antenna switching. */ + antenna = 0; + } else { + ds->ds_link = 0; + /* + * Switch antenna every beacon. + * Should only switch every beacon period, not for every SWBA + * XXX assumes two antennae + */ + antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); + } + + ds->ds_data = bf->bf_buf_addr; + + rt = sc->cur_rate_table; + rate = rt->info[0].ratecode; + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) + rate |= rt->info[0].short_preamble; + + ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, + ATH9K_PKT_TYPE_BEACON, + MAX_RATE_POWER, + ATH9K_TXKEYIX_INVALID, + ATH9K_KEY_TYPE_CLEAR, + flags); + + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4), + true, true, ds); + + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); + series[0].Tries = 1; + series[0].Rate = rate; + series[0].ChSel = sc->tx_chainmask; + series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; + ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, + series, 4, 0); +} + +static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_buf *bf; + struct ath_vif *avp; + struct sk_buff *skb; + struct ath_txq *cabq; + struct ieee80211_tx_info *info; + int cabq_depth; + + if (aphy->state != ATH_WIPHY_ACTIVE) + return NULL; + + avp = (void *)vif->drv_priv; + cabq = sc->beacon.cabq; + + if (avp->av_bcbuf == NULL) + return NULL; + + /* Release the old beacon first */ + + bf = avp->av_bcbuf; + skb = bf->bf_mpdu; + if (skb) { + dma_unmap_single(sc->dev, bf->bf_dmacontext, + skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + } + + /* Get a new beacon from mac80211 */ + + skb = ieee80211_beacon_get(hw, vif); + bf->bf_mpdu = skb; + if (skb == NULL) + return NULL; + ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = + avp->tsf_adjust; + + 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->tx.seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); + } + + bf->bf_buf_addr = bf->bf_dmacontext = + dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n"); + return NULL; + } + + skb = ieee80211_get_buffered_bc(hw, vif); + + /* + * if the CABQ traffic from previous DTIM is pending and the current + * beacon is also a DTIM. + * 1) if there is only one vif let the cab traffic continue. + * 2) if there are more than one vif and we are using staggered + * beacons, then drain the cabq by dropping all the frames in + * the cabq so that the current vifs cab traffic can be scheduled. + */ + spin_lock_bh(&cabq->axq_lock); + cabq_depth = cabq->axq_depth; + spin_unlock_bh(&cabq->axq_lock); + + if (skb && cabq_depth) { + if (sc->nvifs > 1) { + DPRINTF(sc, ATH_DBG_BEACON, + "Flushing previous cabq traffic\n"); + ath_draintxq(sc, cabq, false); + } + } + + ath_beacon_setup(sc, avp, bf); + + while (skb) { + ath_tx_cabq(hw, skb); + skb = ieee80211_get_buffered_bc(hw, vif); + } + + return bf; +} + +/* + * 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, + struct ieee80211_vif *vif) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_buf *bf; + struct ath_vif *avp; + struct sk_buff *skb; + + avp = (void *)vif->drv_priv; + + if (avp->av_bcbuf == NULL) + return; + + bf = avp->av_bcbuf; + skb = bf->bf_mpdu; + + ath_beacon_setup(sc, avp, bf); + + /* NB: caller is known to have already stopped tx dma */ + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); + DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", + sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); +} + +int ath_beaconq_setup(struct ath_hw *ah) +{ + struct ath9k_tx_queue_info qi; + + memset(&qi, 0, sizeof(qi)); + qi.tqi_aifs = 1; + qi.tqi_cwmin = 0; + qi.tqi_cwmax = 0; + /* NB: don't enable any interrupts */ + return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); +} + +int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = aphy->sc; + struct ath_vif *avp; + struct ath_buf *bf; + struct sk_buff *skb; + __le64 tstamp; + + avp = (void *)vif->drv_priv; + + /* 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. */ + avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, + struct ath_buf, list); + list_del(&avp->av_bcbuf->list); + + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || + !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { + int slot; + /* + * Assign the vif to a beacon xmit slot. As + * above, this cannot fail to find one. + */ + avp->av_bslot = 0; + for (slot = 0; slot < ATH_BCBUF; slot++) + if (sc->beacon.bslot[slot] == NULL) { + /* + * XXX hack, space out slots to better + * deal with misses + */ + if (slot+1 < ATH_BCBUF && + sc->beacon.bslot[slot+1] == NULL) { + avp->av_bslot = slot+1; + break; + } + avp->av_bslot = slot; + /* NB: keep looking for a double slot */ + } + BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); + sc->beacon.bslot[avp->av_bslot] = vif; + sc->beacon.bslot_aphy[avp->av_bslot] = aphy; + sc->nbcnvifs++; + } + } + + /* release the previous beacon frame, if it already exists. */ + bf = avp->av_bcbuf; + if (bf->bf_mpdu != NULL) { + skb = bf->bf_mpdu; + dma_unmap_single(sc->dev, bf->bf_dmacontext, + skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + } + + /* NB: the beacon data buffer must be 32-bit aligned. */ + skb = ieee80211_beacon_get(sc->hw, vif); + if (skb == NULL) { + DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); + return -ENOMEM; + } + + tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + sc->beacon.bc_tstamp = le64_to_cpu(tstamp); + /* Calculate a TSF adjustment factor required for staggered beacons. */ + if (avp->av_bslot > 0) { + u64 tsfadjust; + int intval; + + intval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; + + /* + * Calculate the TSF offset for this beacon slot, i.e., the + * number of usecs that need to be added to the timestamp field + * in Beacon and Probe Response frames. Beacon slot 0 is + * processed at the correct offset, so it does not require TSF + * adjustment. Other slots are adjusted to get the timestamp + * close to the TBTT for the BSS. + */ + tsfadjust = intval * avp->av_bslot / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + + DPRINTF(sc, ATH_DBG_BEACON, + "stagger beacons, bslot %d intval %u tsfadjust %llu\n", + avp->av_bslot, intval, (unsigned long long)tsfadjust); + + ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = + avp->tsf_adjust; + } else + avp->tsf_adjust = cpu_to_le64(0); + + bf->bf_mpdu = skb; + bf->bf_buf_addr = bf->bf_dmacontext = + dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_FATAL, + "dma_mapping_error on beacon alloc\n"); + return -ENOMEM; + } + + return 0; +} + +void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) +{ + if (avp->av_bcbuf != NULL) { + struct ath_buf *bf; + + if (avp->av_bslot != -1) { + sc->beacon.bslot[avp->av_bslot] = NULL; + sc->beacon.bslot_aphy[avp->av_bslot] = NULL; + sc->nbcnvifs--; + } + + bf = avp->av_bcbuf; + if (bf->bf_mpdu != NULL) { + struct sk_buff *skb = bf->bf_mpdu; + dma_unmap_single(sc->dev, bf->bf_dmacontext, + skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + } + list_add_tail(&bf->list, &sc->beacon.bbuf); + + avp->av_bcbuf = NULL; + } +} + +void ath_beacon_tasklet(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + struct ath_hw *ah = sc->sc_ah; + struct ath_buf *bf = NULL; + struct ieee80211_vif *vif; + struct ath_wiphy *aphy; + int slot; + u32 bfaddr, bc = 0, tsftu; + u64 tsf; + u16 intval; + + /* + * Check if the previous beacon has gone out. If + * not don't try to post another, skip this period + * and wait for the next. Missed beacons indicate + * a problem and should not occur. If we miss too + * many consecutive beacons reset the device. + */ + if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { + sc->beacon.bmisscnt++; + + if (sc->beacon.bmisscnt < BSTUCK_THRESH) { + DPRINTF(sc, ATH_DBG_BEACON, + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); + } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { + DPRINTF(sc, ATH_DBG_BEACON, + "beacon is officially stuck\n"); + ath_reset(sc, false); + } + + return; + } + + if (sc->beacon.bmisscnt != 0) { + DPRINTF(sc, ATH_DBG_BEACON, + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); + sc->beacon.bmisscnt = 0; + } + + /* + * Generate beacon frames. we are sending frames + * staggered so calculate the slot for this frame based + * on the tsf to safeguard against missing an swba. + */ + + 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; + /* + * Reverse the slot order to get slot 0 on the TBTT offset that does + * not require TSF adjustment and other slots adding + * slot/ATH_BCBUF * beacon_int to timestamp. For example, with + * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. + * and slot 0 is at correct offset to TBTT. + */ + slot = ATH_BCBUF - slot - 1; + vif = sc->beacon.bslot[slot]; + aphy = sc->beacon.bslot_aphy[slot]; + + DPRINTF(sc, ATH_DBG_BEACON, + "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", + slot, tsf, tsftu, intval, vif); + + bfaddr = 0; + if (vif) { + bf = ath_beacon_generate(aphy->hw, vif); + if (bf != NULL) { + bfaddr = bf->bf_daddr; + bc = 1; + } + } + + /* + * Handle slot time change when a non-ERP station joins/leaves + * an 11g network. The 802.11 layer notifies us via callback, + * we mark updateslot, then wait one beacon before effecting + * the change. This gives associated stations at least one + * beacon interval to note the state change. + * + * NB: The slot time change state machine is clocked according + * to whether we are bursting or staggering beacons. We + * recognize the request to update and record the current + * slot then don't transition until that slot is reached + * again. If we miss a beacon for that slot then we'll be + * slow to transition but we'll be sure at least one beacon + * interval has passed. When bursting slot is always left + * set to ATH_BCBUF so this check is a noop. + */ + if (sc->beacon.updateslot == UPDATE) { + sc->beacon.updateslot = COMMIT; /* commit next beacon */ + sc->beacon.slotupdate = slot; + } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { + ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); + sc->beacon.updateslot = OK; + } + if (bfaddr != 0) { + /* + * Stop any current dma and put the new frame(s) on the queue. + * This should never fail since we check above that no frames + * are still pending on the queue. + */ + if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { + DPRINTF(sc, ATH_DBG_FATAL, + "beacon queue %u did not stop?\n", sc->beacon.beaconq); + } + + /* NB: cabq traffic should already be queued and primed */ + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); + + sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ + } +} + +/* + * For multi-bss ap support beacons are either staggered evenly over N slots or + * burst together. For the former arrange for the SWBA to be delivered for each + * slot. Slots that are not occupied will generate nothing. + */ +static void ath_beacon_config_ap(struct ath_softc *sc, + struct ath_beacon_config *conf, + struct ath_vif *avp) +{ + u32 nexttbtt, intval; + + /* Configure the timers only when the TSF has to be reset */ + + if (!(sc->sc_flags & SC_OP_TSF_RESET)) + return; + + /* NB: the beacon interval is kept internally in TU's */ + intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval /= ATH_BCBUF; /* for staggered beacons */ + nexttbtt = intval; + intval |= ATH9K_BEACON_RESET_TSF; + + /* + * In AP mode we enable the beacon timers and SWBA interrupts to + * prepare beacon frames. + */ + intval |= ATH9K_BEACON_ENA; + sc->imask |= ATH9K_INT_SWBA; + ath_beaconq_config(sc); + + /* Set the computed AP beacon timers */ + + ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + + /* Clear the reset TSF flag, so that subsequent beacon updation + will not reset the HW TSF. */ + + sc->sc_flags &= ~SC_OP_TSF_RESET; +} + +/* + * This sets up the beacon timers according to the timestamp of the last + * received beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware will wakeup in + * time to receive beacons, and configures the beacon miss handling so + * we'll receive a BMISS interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +static void ath_beacon_config_sta(struct ath_softc *sc, + struct ath_beacon_config *conf, + struct ath_vif *avp) +{ + struct ath9k_beacon_state bs; + int dtimperiod, dtimcount, sleepduration; + int cfpperiod, cfpcount; + u32 nexttbtt = 0, intval, tsftu; + u64 tsf; + + memset(&bs, 0, sizeof(bs)); + intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + + /* + * Setup dtim and cfp parameters according to + * last beacon we received (which may be none). + */ + dtimperiod = conf->dtim_period; + if (dtimperiod <= 0) /* NB: 0 if not known */ + dtimperiod = 1; + dtimcount = conf->dtim_count; + 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; + + /* + * Pull nexttbtt forward to reflect the current + * TSF and calculate dtim+cfp state for the result. + */ + tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; + do { + nexttbtt += intval; + if (--dtimcount < 0) { + dtimcount = dtimperiod - 1; + if (--cfpcount < 0) + cfpcount = cfpperiod - 1; + } + } while (nexttbtt < tsftu); + + bs.bs_intval = intval; + bs.bs_nexttbtt = nexttbtt; + bs.bs_dtimperiod = dtimperiod*intval; + bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; + 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 is specified in TU so we only + * need calculate based on the beacon interval. Note that we clamp the + * result to at most 15 beacons. + */ + if (sleepduration > intval) { + bs.bs_bmissthreshold = conf->listen_interval * + ATH_DEFAULT_BMISS_LIMIT / 2; + } else { + bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); + if (bs.bs_bmissthreshold > 15) + bs.bs_bmissthreshold = 15; + else if (bs.bs_bmissthreshold <= 0) + bs.bs_bmissthreshold = 1; + } + + /* + * Calculate sleep duration. The configuration is given in ms. + * We ensure a multiple of the beacon period is used. Also, if the sleep + * duration is greater than the DTIM period then it makes senses + * to make it a multiple of that. + * + * XXX fixed at 100ms + */ + + bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); + if (bs.bs_sleepduration > bs.bs_dtimperiod) + bs.bs_sleepduration = bs.bs_dtimperiod; + + /* TSF out of range threshold fixed at 1 second */ + bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + + DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); + DPRINTF(sc, ATH_DBG_BEACON, + "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", + bs.bs_bmissthreshold, bs.bs_sleepduration, + bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); + + /* Set the computed STA beacon timers */ + + ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs); + sc->imask |= ATH9K_INT_BMISS; + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); +} + +static void ath_beacon_config_adhoc(struct ath_softc *sc, + struct ath_beacon_config *conf, + struct ath_vif *avp, + struct ieee80211_vif *vif) +{ + u64 tsf; + u32 tsftu, intval, nexttbtt; + + intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + + /* Pull nexttbtt forward to reflect the current TSF */ + + nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); + if (nexttbtt == 0) + nexttbtt = intval; + else if (intval) + nexttbtt = roundup(nexttbtt, intval); + + tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; + do { + nexttbtt += intval; + } while (nexttbtt < tsftu); + + DPRINTF(sc, ATH_DBG_BEACON, + "IBSS nexttbtt %u intval %u (%u)\n", + nexttbtt, intval, conf->beacon_interval); + + /* + * In IBSS mode enable the beacon timers but only enable SWBA interrupts + * if we need to manually prepare beacon frames. Otherwise we use a + * self-linked tx descriptor and let the hardware deal with things. + */ + intval |= ATH9K_BEACON_ENA; + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) + sc->imask |= ATH9K_INT_SWBA; + + ath_beaconq_config(sc); + + /* Set the computed ADHOC beacon timers */ + + ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) + ath_beacon_start_adhoc(sc, vif); +} + +void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_beacon_config conf; + + /* Setup the beacon configuration parameters */ + + memset(&conf, 0, sizeof(struct ath_beacon_config)); + 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; + + if (vif) { + struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; + + switch(avp->av_opmode) { + case NL80211_IFTYPE_AP: + ath_beacon_config_ap(sc, &conf, avp); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + ath_beacon_config_adhoc(sc, &conf, avp, vif); + break; + case NL80211_IFTYPE_STATION: + ath_beacon_config_sta(sc, &conf, avp); + break; + default: + DPRINTF(sc, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); + return; + } + + sc->sc_flags |= SC_OP_BEACONS; + } +} diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c new file mode 100644 index 0000000..e2d62e9 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -0,0 +1,1060 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +/* 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_hw *ah, s16 nf) +{ + if (nf > ATH9K_NF_TOO_LOW) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + nf, ATH9K_NF_TOO_LOW); + return false; + } + return true; +} + +static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) +{ + int16_t nfval; + int16_t sort[ATH9K_NF_CAL_HIST_MAX]; + int i, j; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) + sort[i] = nfCalBuffer[i]; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { + for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { + if (sort[j] > sort[j - 1]) { + nfval = sort[j]; + sort[j] = sort[j - 1]; + sort[j - 1] = nfval; + } + } + } + nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; + + return nfval; +} + +static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, + int16_t *nfarray) +{ + int i; + + for (i = 0; i < NUM_NF_READINGS; i++) { + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; + + if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) + h[i].currIndex = 0; + + if (h[i].invalidNFcount > 0) { + if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || + nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { + h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; + } else { + h[i].invalidNFcount--; + h[i].privNF = nfarray[i]; + } + } else { + h[i].privNF = + ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); + } + } + return; +} + +static void ath9k_hw_do_getnf(struct ath_hw *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + int16_t nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + if (!AR_SREV_9285(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR9280_PHY_CH1_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR_PHY_CH1_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), + AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[2] = nf; + } + } + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR9280_PHY_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR_PHY_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[3] = nf; + + if (!AR_SREV_9285(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR9280_PHY_CH1_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR_PHY_CH1_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), + AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; + } + } +} + +static bool getNoiseFloorThresh(struct ath_hw *ah, + enum ieee80211_band band, + int16_t *nft) +{ + switch (band) { + case IEEE80211_BAND_5GHZ: + *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5); + break; + case IEEE80211_BAND_2GHZ: + *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2); + break; + default: + BUG_ON(1); + return false; + } + + return true; +} + +static void ath9k_hw_setup_calibration(struct ath_hw *ah, + struct hal_cal_list *currCal) +{ + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + currCal->calData->calCountMax); + + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting IQ Mismatch Calibration\n"); + break; + case ADC_GAIN_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting ADC Gain Calibration\n"); + break; + case ADC_DC_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting ADC DC Calibration\n"); + break; + case ADC_DC_INIT_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting Init ADC DC Calibration\n"); + break; + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_DO_CAL); +} + +static void ath9k_hw_reset_calibration(struct ath_hw *ah, + struct hal_cal_list *currCal) +{ + int i; + + ath9k_hw_setup_calibration(ah, currCal); + + currCal->calState = CAL_RUNNING; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->meas0.sign[i] = 0; + ah->meas1.sign[i] = 0; + ah->meas2.sign[i] = 0; + ah->meas3.sign[i] = 0; + } + + ah->cal_samples = 0; +} + +static void ath9k_hw_per_calibration(struct ath_hw *ah, + struct ath9k_channel *ichan, + u8 rxchainmask, + struct hal_cal_list *currCal, + bool *isCalDone) +{ + *isCalDone = false; + + if (currCal->calState == CAL_RUNNING) { + if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & + AR_PHY_TIMING_CTRL4_DO_CAL)) { + + currCal->calData->calCollect(ah); + ah->cal_samples++; + + if (ah->cal_samples >= currCal->calData->calNumSamples) { + int i, numChains = 0; + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + + currCal->calData->calPostProc(ah, numChains); + ichan->CalValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + *isCalDone = true; + } else { + ath9k_hw_setup_calibration(ah, currCal); + } + } + } else if (!(ichan->CalValid & currCal->calData->calType)) { + ath9k_hw_reset_calibration(ah, currCal); + } +} + +/* Assumes you are talking about the currently configured channel */ +static bool ath9k_hw_iscal_supported(struct ath_hw *ah, + enum hal_cal_types calType) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + + switch (calType & ah->supp_cals) { + case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ + return true; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + if (conf->channel->band == IEEE80211_BAND_5GHZ && + conf_is_ht20(conf)) + return true; + break; + } + return false; +} + +static void ath9k_hw_iqcal_collect(struct ath_hw *ah) +{ + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); + } +} + +static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah) +{ + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->totalAdcIOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalAdcIEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalAdcQOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ah->totalAdcQEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ah->cal_samples, i, + ah->totalAdcIOddPhase[i], + ah->totalAdcIEvenPhase[i], + ah->totalAdcQOddPhase[i], + ah->totalAdcQEvenPhase[i]); + } +} + +static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah) +{ + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->totalAdcDcOffsetIOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalAdcDcOffsetIEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalAdcDcOffsetQOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ah->totalAdcDcOffsetQEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ah->cal_samples, i, + ah->totalAdcDcOffsetIOddPhase[i], + ah->totalAdcDcOffsetIEvenPhase[i], + ah->totalAdcDcOffsetQOddPhase[i], + ah->totalAdcDcOffsetQEvenPhase[i]); + } +} + +static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) +{ + u32 powerMeasQ, powerMeasI, iqCorrMeas; + u32 qCoffDenom, iCoffDenom; + int32_t qCoff, iCoff; + int iqCorrNeg, i; + + for (i = 0; i < numChains; i++) { + powerMeasI = ah->totalPowerMeasI[i]; + powerMeasQ = ah->totalPowerMeasQ[i]; + iqCorrMeas = ah->totalIqCorrMeas[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", + i, ah->totalIqCorrMeas[i]); + + iqCorrNeg = 0; + + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 64; + + if (powerMeasQ != 0) { + iCoff = iqCorrMeas / iCoffDenom; + qCoff = powerMeasI / qCoffDenom - 64; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); + + iCoff = iCoff & 0x3f; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "New: Chn %d iCoff = 0x%08x\n", i, iCoff); + if (iqCorrNeg == 0x0) + iCoff = 0x40 - iCoff; + + if (qCoff > 15) + qCoff = 15; + else if (qCoff <= -16) + qCoff = 16; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", + i, iCoff, qCoff); + + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, + iCoff); + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, + qCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "IQ Cal and Correction done for Chain %d\n", + i); + } + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); +} + +static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) +{ + u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; + u32 qGainMismatch, iGainMismatch, val, i; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ah->totalAdcIOddPhase[i]; + iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; + qOddMeasOffset = ah->totalAdcQOddPhase[i]; + qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC Gain Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = 0x%08x\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = 0x%08x\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = 0x%08x\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = 0x%08x\n", i, + qEvenMeasOffset); + + if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { + iGainMismatch = + ((iEvenMeasOffset * 32) / + iOddMeasOffset) & 0x3f; + qGainMismatch = + ((qOddMeasOffset * 32) / + qEvenMeasOffset) & 0x3f; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_i = 0x%08x\n", i, + iGainMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_q = 0x%08x\n", i, + qGainMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xfffff000; + val |= (qGainMismatch) | (iGainMismatch << 6); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC Gain Cal done for Chain %d\n", i); + } + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); +} + +static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) +{ + u32 iOddMeasOffset, iEvenMeasOffset, val, i; + int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; + const struct hal_percal_data *calData = + ah->cal_list_curr->calData; + u32 numSamples = + (1 << (calData->calCountMax + 5)) * calData->calNumSamples; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; + iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; + qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; + qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = %d\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = %d\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = %d\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = %d\n", i, + qEvenMeasOffset); + + iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / + numSamples) & 0x1ff; + qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / + numSamples) & 0x1ff; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, + iDcMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, + qDcMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xc0000fff; + val |= (qDcMismatch << 12) | (iDcMismatch << 21); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC DC Offset Cal done for Chain %d\n", i); + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); +} + +/* This is done for the currently configured channel */ +bool ath9k_hw_reset_calvalid(struct ath_hw *ah) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct hal_cal_list *currCal = ah->cal_list_curr; + + if (!ah->curchan) + return true; + + if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) + return true; + + if (currCal == NULL) + return true; + + if (currCal->calState != CAL_DONE) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Calibration state incorrect, %d\n", + currCal->calState); + return true; + } + + if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) + return true; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Resetting Cal %d state for channel %u\n", + currCal->calData->calType, conf->channel->center_freq); + + ah->curchan->CalValid &= ~currCal->calData->calType; + currCal->calState = CAL_WAITING; + + return false; +} + +void ath9k_hw_start_nfcal(struct ath_hw *ah) +{ + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); +} + +void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath9k_nfcal_hist *h; + int i, j; + int32_t val; + const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, + AR_PHY_CH2_CCA, + AR_PHY_EXT_CCA, + AR_PHY_CH1_EXT_CCA, + AR_PHY_CH2_EXT_CCA + }; + u8 chainmask; + + if (AR_SREV_9285(ah)) + chainmask = 0x9; + else if (AR_SREV_9280(ah)) + chainmask = 0x1B; + else + chainmask = 0x3F; + + h = ah->nfCalHist; + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (h[i].privNF) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } + + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + for (j = 0; j < 1000; j++) { + if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_NF) == 0) + break; + udelay(10); + } + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (-50) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } +} + +int16_t ath9k_hw_getnf(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int16_t nf, nfThresh; + int16_t nfarray[NUM_NF_READINGS] = { 0 }; + struct ath9k_nfcal_hist *h; + struct ieee80211_channel *c = chan->chan; + + chan->channelFlags &= (~CHANNEL_CW_INT); + if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF did not complete in calibration window\n"); + nf = 0; + chan->rawNoiseFloor = nf; + return chan->rawNoiseFloor; + } else { + ath9k_hw_do_getnf(ah, nfarray); + nf = nfarray[0]; + if (getNoiseFloorThresh(ah, c->band, &nfThresh) + && nf > nfThresh) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "noise floor failed detected; " + "detected %d, threshold %d\n", + nf, nfThresh); + chan->channelFlags |= CHANNEL_CW_INT; + } + } + + h = ah->nfCalHist; + + ath9k_hw_update_nfcal_hist_buffer(h, nfarray); + chan->rawNoiseFloor = h[0].privNF; + + return chan->rawNoiseFloor; +} + +void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) +{ + int i, j; + + for (i = 0; i < NUM_NF_READINGS; i++) { + ah->nfCalHist[i].currIndex = 0; + ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].invalidNFcount = + AR_PHY_CCA_FILTERWINDOW_LENGTH; + for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { + ah->nfCalHist[i].nfCalBuffer[j] = + AR_PHY_CCA_MAX_GOOD_VALUE; + } + } +} + +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) +{ + s16 nf; + + if (chan->rawNoiseFloor == 0) + nf = -96; + else + nf = chan->rawNoiseFloor; + + if (!ath9k_hw_nf_in_range(ah, nf)) + nf = ATH_DEFAULT_NOISE_FLOOR; + + return nf; +} + +static void ath9k_olc_temp_compensation(struct ath_hw *ah) +{ + u32 rddata, i; + int delta, currPDADC, regval; + + rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); + + currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); + + if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) + delta = (currPDADC - ah->initPDADC + 4) / 8; + else + delta = (currPDADC - ah->initPDADC + 5) / 10; + + if (delta != ah->PDADCdelta) { + ah->PDADCdelta = delta; + for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { + regval = ah->originalGain[i] - delta; + if (regval < 0) + regval = 0; + + REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, + AR_PHY_TX_GAIN, regval); + } + } +} + +static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) +{ + + u32 regVal; + int i, offset, offs_6_1, offs_0; + u32 ccomp_org, reg_field; + u32 regList[][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 }, + }; + + if (AR_SREV_9285_11(ah)) { + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + udelay(10); + } + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); + + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); + + for (i = 6; i > 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1 << (19 + i))); + reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); + regVal |= (reg_field << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); + udelay(1); + reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); + offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); + offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); + + offset = (offs_6_1<<1) | offs_0; + offset = offset - 0; + offs_6_1 = offset>>1; + offs_0 = offset & 1; + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + +} + +bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone) +{ + struct hal_cal_list *currCal = ah->cal_list_curr; + + *isCalDone = true; + + if (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal, + isCalDone); + if (*isCalDone) { + ah->cal_list_curr = currCal = currCal->calNext; + + if (currCal->calState == CAL_WAITING) { + *isCalDone = false; + ath9k_hw_reset_calibration(ah, currCal); + } + } + } + + if (longcal) { + if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + ath9k_hw_9285_pa_cal(ah); + + if (OLC_FOR_AR9280_20_LATER) + ath9k_olc_temp_compensation(ah); + ath9k_hw_getnf(ah, chan); + ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah); + + if (chan->channelFlags & CHANNEL_CW_INT) + chan->channelFlags &= ~CHANNEL_CW_INT; + } + + return true; +} + +static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) +{ + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + if (chan->channelFlags & CHANNEL_HT20) { + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset " + "calibration failed to complete in " + "1ms; noisy ??\n"); + return false; + } + REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration " + "failed to complete in 1ms; noisy ??\n"); + return false; + } + + REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + + return true; +} + +bool ath9k_hw_init_cal(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { + if (!ar9285_clc(ah, chan)) + return false; + } else if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + + /* Kick off the cal */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, 0, + AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "offset calibration failed to complete in 1ms; " + "noisy environment?\n"); + return false; + } + + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } + + /* Calibrate the AGC */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "offset calibration failed to complete in 1ms; " + "noisy environment?\n"); + return false; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + } + + /* Do PA Calibration */ + if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + ath9k_hw_9285_pa_cal(ah); + + /* Do NF Calibration */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_NF); + + ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { + if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { + INIT_CAL(&ah->adcgain_caldata); + INSERT_CAL(ah, &ah->adcgain_caldata); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling ADC Gain Calibration.\n"); + } + if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { + INIT_CAL(&ah->adcdc_caldata); + INSERT_CAL(ah, &ah->adcdc_caldata); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling ADC DC Calibration.\n"); + } + if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } + + ah->cal_list_curr = ah->cal_list; + + if (ah->cal_list_curr) + ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + } + + chan->CalValid = 0; + + return true; +} + +const struct hal_percal_data iq_cal_multi_sample = { + IQ_MISMATCH_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data iq_cal_single_sample = { + IQ_MISMATCH_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data adc_gain_cal_multi_sample = { + ADC_GAIN_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_gain_cal_single_sample = { + ADC_GAIN_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_dc_cal_multi_sample = { + ADC_DC_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_dc_cal_single_sample = { + ADC_DC_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_init_dc_cal = { + ADC_DC_INIT_CAL, + MIN_CAL_SAMPLES, + INIT_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h new file mode 100644 index 0000000..1c74bd5 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CALIB_H +#define CALIB_H + +extern const struct hal_percal_data iq_cal_multi_sample; +extern const struct hal_percal_data iq_cal_single_sample; +extern const struct hal_percal_data adc_gain_cal_multi_sample; +extern const struct hal_percal_data adc_gain_cal_single_sample; +extern const struct hal_percal_data adc_dc_cal_multi_sample; +extern const struct hal_percal_data adc_dc_cal_single_sample; +extern const struct hal_percal_data adc_init_dc_cal; + +#define AR_PHY_CCA_MAX_GOOD_VALUE -85 +#define AR_PHY_CCA_MAX_HIGH_VALUE -62 +#define AR_PHY_CCA_MIN_BAD_VALUE -140 +#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 +#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 + +#define NUM_NF_READINGS 6 +#define ATH9K_NF_CAL_HIST_MAX 5 + +struct ar5416IniArray { + u32 *ia_array; + u32 ia_rows; + u32 ia_columns; +}; + +#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ + (iniarray)->ia_array = (u32 *)(array); \ + (iniarray)->ia_rows = (rows); \ + (iniarray)->ia_columns = (columns); \ + } while (0) + +#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; \ + } while (0) + +#define INSERT_CAL(_ahp, _perCal) \ + do { \ + if ((_ahp)->cal_list_last == NULL) { \ + (_ahp)->cal_list = \ + (_ahp)->cal_list_last = (_perCal); \ + ((_ahp)->cal_list_last)->calNext = (_perCal); \ + } else { \ + ((_ahp)->cal_list_last)->calNext = (_perCal); \ + (_ahp)->cal_list_last = (_perCal); \ + (_perCal)->calNext = (_ahp)->cal_list; \ + } \ + } while (0) + +enum hal_cal_types { + ADC_DC_INIT_CAL = 0x1, + ADC_GAIN_CAL = 0x2, + ADC_DC_CAL = 0x4, + IQ_MISMATCH_CAL = 0x8 +}; + +enum hal_cal_state { + CAL_INACTIVE, + CAL_WAITING, + CAL_RUNNING, + CAL_DONE +}; + +#define MIN_CAL_SAMPLES 1 +#define MAX_CAL_SAMPLES 64 +#define INIT_LOG_COUNT 5 +#define PER_MIN_LOG_COUNT 2 +#define PER_MAX_LOG_COUNT 10 + +struct hal_percal_data { + enum hal_cal_types calType; + u32 calNumSamples; + u32 calCountMax; + void (*calCollect) (struct ath_hw *); + void (*calPostProc) (struct ath_hw *, u8); +}; + +struct hal_cal_list { + const struct hal_percal_data *calData; + enum hal_cal_state calState; + struct hal_cal_list *calNext; +}; + +struct ath9k_nfcal_hist { + int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX]; + u8 currIndex; + int16_t privNF; + u8 invalidNFcount; +}; + +bool ath9k_hw_reset_calvalid(struct ath_hw *ah); +void ath9k_hw_start_nfcal(struct ath_hw *ah); +void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); +int16_t ath9k_hw_getnf(struct ath_hw *ah, + struct ath9k_channel *chan); +void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah); +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); +bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone); +bool ath9k_hw_init_cal(struct ath_hw *ah, + struct ath9k_channel *chan); + +#endif /* CALIB_H */ diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c new file mode 100644 index 0000000..97df20c --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "ath9k.h" + +static unsigned int ath9k_debug = DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); + +static struct dentry *ath9k_debugfs_root; + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) +{ + if (!sc) + return; + + if (sc->debug.debug_mask & dbg_mask) { + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "ath9k: "); + vprintk(fmt, args); + va_end(args); + } +} + +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_dma(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + char buf[1024]; + unsigned int len = 0; + u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; + int i, qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase = &val[0], *dcuBase = &val[4]; + + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + len += snprintf(buf + len, sizeof(buf) - len, + "Raw DMA Debug values:\n"); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { + if (i % 4 == 0) + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); + len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", + i, val[i]); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); + len += snprintf(buf + len, sizeof(buf) - len, + "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + + for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + + len += snprintf(buf + len, sizeof(buf) - len, + "%2d %2x %1x %2x %2x\n", + i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), + val[2] & (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_stitch state: %2x qcu_fetch state: %2x\n", + (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_complete state: %2x dcu_complete state: %2x\n", + (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); + len += snprintf(buf + len, sizeof(buf) - len, + "dcu_arb state: %2x dcu_fp state: %2x\n", + (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); + len += snprintf(buf + len, sizeof(buf) - len, + "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", + (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", + (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", + (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); + + len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", + REG_READ(ah, AR_OBS_BUS_1)); + len += snprintf(buf + len, sizeof(buf) - len, + "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_dma = { + .read = read_file_dma, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + + +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) +{ + if (status) + sc->debug.stats.istats.total++; + if (status & ATH9K_INT_RX) + sc->debug.stats.istats.rxok++; + if (status & ATH9K_INT_RXEOL) + sc->debug.stats.istats.rxeol++; + if (status & ATH9K_INT_RXORN) + sc->debug.stats.istats.rxorn++; + if (status & ATH9K_INT_TX) + sc->debug.stats.istats.txok++; + if (status & ATH9K_INT_TXURN) + sc->debug.stats.istats.txurn++; + if (status & ATH9K_INT_MIB) + sc->debug.stats.istats.mib++; + if (status & ATH9K_INT_RXPHY) + sc->debug.stats.istats.rxphyerr++; + if (status & ATH9K_INT_RXKCM) + sc->debug.stats.istats.rx_keycache_miss++; + if (status & ATH9K_INT_SWBA) + sc->debug.stats.istats.swba++; + if (status & ATH9K_INT_BMISS) + sc->debug.stats.istats.bmiss++; + if (status & ATH9K_INT_BNR) + sc->debug.stats.istats.bnr++; + if (status & ATH9K_INT_CST) + sc->debug.stats.istats.cst++; + if (status & ATH9K_INT_GTT) + sc->debug.stats.istats.gtt++; + if (status & ATH9K_INT_TIM) + sc->debug.stats.istats.tim++; + if (status & ATH9K_INT_CABEND) + sc->debug.stats.istats.cabend++; + if (status & ATH9K_INT_DTIMSYNC) + sc->debug.stats.istats.dtimsync++; + if (status & ATH9K_INT_DTIM) + sc->debug.stats.istats.dtim++; +} + +static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_interrupt = { + .read = read_file_interrupt, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_tx_info_priv *tx_info_priv = NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->status.rates; + int final_ts_idx, idx; + + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; + idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; + + sc->debug.stats.n_rcstats[idx].success++; +} + +static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_tx_info_priv *tx_info_priv = NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->status.rates; + int final_ts_idx, idx; + + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; + idx = rates[final_ts_idx].idx; + + sc->debug.stats.legacy_rcstats[idx].success++; +} + +void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) +{ + if (conf_is_ht(&sc->hw->conf)) + ath_debug_stat_11n_rc(sc, skb); + else + ath_debug_stat_legacy_rc(sc, skb); +} + +/* FIXME: legacy rates, later on .. */ +void ath_debug_stat_retries(struct ath_softc *sc, int rix, + int xretries, int retries, u8 per) +{ + if (conf_is_ht(&sc->hw->conf)) { + int idx = sc->cur_rate_table->info[rix].dot11rate; + + sc->debug.stats.n_rcstats[idx].xretries += xretries; + sc->debug.stats.n_rcstats[idx].retries += retries; + sc->debug.stats.n_rcstats[idx].per = per; + } +} + +static ssize_t ath_read_file_stat_11n_rc(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[1024]; + unsigned int len = 0; + int i = 0; + + len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", + "Retries", "XRetries", "PER"); + + for (i = 0; i <= 15; i++) { + len += snprintf(buf + len, sizeof(buf) - len, + "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, + sc->debug.stats.n_rcstats[i].success, + sc->debug.stats.n_rcstats[i].retries, + sc->debug.stats.n_rcstats[i].xretries, + sc->debug.stats.n_rcstats[i].per); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath_read_file_stat_legacy_rc(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + int i = 0; + + len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); + + for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { + len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", + sc->cur_rate_table->info[i].ratekbps / 1000, + sc->debug.stats.legacy_rcstats[i].success); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + + if (sc->cur_rate_table == NULL) + return 0; + + if (conf_is_ht(&sc->hw->conf)) + return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); + else + return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); +} + +static const struct file_operations fops_rcstat = { + .read = read_file_rcstat, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static const char * ath_wiphy_state_str(enum ath_wiphy_state state) +{ + switch (state) { + case ATH_WIPHY_INACTIVE: + return "INACTIVE"; + case ATH_WIPHY_ACTIVE: + return "ACTIVE"; + case ATH_WIPHY_PAUSING: + return "PAUSING"; + case ATH_WIPHY_PAUSED: + return "PAUSED"; + case ATH_WIPHY_SCAN: + return "SCAN"; + } + return "?"; +} + +static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + int i; + u8 addr[ETH_ALEN]; + + len += snprintf(buf + len, sizeof(buf) - len, + "primary: %s (%s chan=%d ht=%d)\n", + wiphy_name(sc->pri_wiphy->hw->wiphy), + ath_wiphy_state_str(sc->pri_wiphy->state), + sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + len += snprintf(buf + len, sizeof(buf) - len, + "secondary: %s (%s chan=%d ht=%d)\n", + wiphy_name(aphy->hw->wiphy), + ath_wiphy_state_str(aphy->state), + aphy->chan_idx, aphy->chan_is_ht); + } + + put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); + put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); + len += snprintf(buf + len, sizeof(buf) - len, + "addr: %pM\n", addr); + put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); + put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); + len += snprintf(buf + len, sizeof(buf) - len, + "addrmask: %pM\n", addr); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) +{ + int i; + if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) + return sc->pri_wiphy; + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) + return aphy; + } + return NULL; +} + +static int del_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_del(aphy); +} + +static int pause_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_pause(aphy); +} + +static int unpause_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_unpause(aphy); +} + +static int select_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_select(aphy); +} + +static int schedule_wiphy(struct ath_softc *sc, const char *msec) +{ + ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); + return 0; +} + +static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[50]; + size_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + if (strncmp(buf, "add", 3) == 0) { + int res = ath9k_wiphy_add(sc); + if (res < 0) + return res; + } else if (strncmp(buf, "del=", 4) == 0) { + int res = del_wiphy(sc, buf + 4); + if (res < 0) + return res; + } else if (strncmp(buf, "pause=", 6) == 0) { + int res = pause_wiphy(sc, buf + 6); + if (res < 0) + return res; + } else if (strncmp(buf, "unpause=", 8) == 0) { + int res = unpause_wiphy(sc, buf + 8); + if (res < 0) + return res; + } else if (strncmp(buf, "select=", 7) == 0) { + int res = select_wiphy(sc, buf + 7); + if (res < 0) + return res; + } else if (strncmp(buf, "schedule=", 9) == 0) { + int res = schedule_wiphy(sc, buf + 9); + if (res < 0) + return res; + } else + return -EOPNOTSUPP; + + return count; +} + +static const struct file_operations fops_wiphy = { + .read = read_file_wiphy, + .write = write_file_wiphy, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + + +int ath9k_init_debug(struct ath_softc *sc) +{ + sc->debug.debug_mask = ath9k_debug; + + if (!ath9k_debugfs_root) + return -ENOENT; + + sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), + ath9k_debugfs_root); + if (!sc->debug.debugfs_phy) + goto err; + + sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, + sc->debug.debugfs_phy, sc, &fops_dma); + if (!sc->debug.debugfs_dma) + goto err; + + sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", + S_IRUGO, + sc->debug.debugfs_phy, + sc, &fops_interrupt); + if (!sc->debug.debugfs_interrupt) + goto err; + + sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", + S_IRUGO, + sc->debug.debugfs_phy, + sc, &fops_rcstat); + if (!sc->debug.debugfs_rcstat) + goto err; + + sc->debug.debugfs_wiphy = debugfs_create_file( + "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, + &fops_wiphy); + if (!sc->debug.debugfs_wiphy) + goto err; + + return 0; +err: + ath9k_exit_debug(sc); + return -ENOMEM; +} + +void ath9k_exit_debug(struct ath_softc *sc) +{ + debugfs_remove(sc->debug.debugfs_wiphy); + debugfs_remove(sc->debug.debugfs_rcstat); + debugfs_remove(sc->debug.debugfs_interrupt); + debugfs_remove(sc->debug.debugfs_dma); + debugfs_remove(sc->debug.debugfs_phy); +} + +int ath9k_debug_create_root(void) +{ + ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!ath9k_debugfs_root) + return -ENOENT; + + return 0; +} + +void ath9k_debug_remove_root(void) +{ + debugfs_remove(ath9k_debugfs_root); + ath9k_debugfs_root = NULL; +} diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h new file mode 100644 index 0000000..23298b9 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DEBUG_H +#define DEBUG_H + +enum ATH_DEBUG { + ATH_DBG_RESET = 0x00000001, + ATH_DBG_QUEUE = 0x00000002, + ATH_DBG_EEPROM = 0x00000004, + ATH_DBG_CALIBRATE = 0x00000008, + ATH_DBG_INTERRUPT = 0x00000010, + ATH_DBG_REGULATORY = 0x00000020, + ATH_DBG_ANI = 0x00000040, + ATH_DBG_XMIT = 0x00000080, + ATH_DBG_BEACON = 0x00000100, + ATH_DBG_CONFIG = 0x00000200, + ATH_DBG_FATAL = 0x00000400, + ATH_DBG_ANY = 0xffffffff +}; + +#define DBG_DEFAULT (ATH_DBG_FATAL) + +#ifdef CONFIG_ATH9K_DEBUG + +/** + * struct ath_interrupt_stats - Contains statistics about interrupts + * @total: Total no. of interrupts generated so far + * @rxok: RX with no errors + * @rxeol: RX with no more RXDESC available + * @rxorn: RX FIFO overrun + * @txok: TX completed at the requested rate + * @txurn: TX FIFO underrun + * @mib: MIB regs reaching its threshold + * @rxphyerr: RX with phy errors + * @rx_keycache_miss: RX with key cache misses + * @swba: Software Beacon Alert + * @bmiss: Beacon Miss + * @bnr: Beacon Not Ready + * @cst: Carrier Sense TImeout + * @gtt: Global TX Timeout + * @tim: RX beacon TIM occurrence + * @cabend: RX End of CAB traffic + * @dtimsync: DTIM sync lossage + * @dtim: RX Beacon with DTIM + */ +struct ath_interrupt_stats { + u32 total; + u32 rxok; + u32 rxeol; + u32 rxorn; + u32 txok; + u32 txeol; + u32 txurn; + u32 mib; + u32 rxphyerr; + u32 rx_keycache_miss; + u32 swba; + u32 bmiss; + u32 bnr; + u32 cst; + u32 gtt; + u32 tim; + u32 cabend; + u32 dtimsync; + u32 dtim; +}; + +struct ath_legacy_rc_stats { + u32 success; +}; + +struct ath_11n_rc_stats { + u32 success; + u32 retries; + u32 xretries; + u8 per; +}; + +struct ath_stats { + struct ath_interrupt_stats istats; + struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ + struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ +}; + +struct ath9k_debug { + int debug_mask; + struct dentry *debugfs_phy; + struct dentry *debugfs_dma; + struct dentry *debugfs_interrupt; + struct dentry *debugfs_rcstat; + struct dentry *debugfs_wiphy; + struct ath_stats stats; +}; + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); +int ath9k_init_debug(struct ath_softc *sc); +void ath9k_exit_debug(struct ath_softc *sc); +int ath9k_debug_create_root(void); +void ath9k_debug_remove_root(void); +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); +void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); +void ath_debug_stat_retries(struct ath_softc *sc, int rix, + int xretries, int retries, u8 per); + +#else + +static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, + const char *fmt, ...) +{ +} + +static inline int ath9k_init_debug(struct ath_softc *sc) +{ + return 0; +} + +static inline void ath9k_exit_debug(struct ath_softc *sc) +{ +} + +static inline int ath9k_debug_create_root(void) +{ + return 0; +} + +static inline void ath9k_debug_remove_root(void) +{ +} + +static inline void ath_debug_stat_interrupt(struct ath_softc *sc, + enum ath9k_int status) +{ +} + +static inline void ath_debug_stat_rc(struct ath_softc *sc, + struct sk_buff *skb) +{ +} + +static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, + int xretries, int retries, u8 per) +{ +} + +#endif /* CONFIG_ATH9K_DEBUG */ + +#endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c new file mode 100644 index 0000000..44fee5a --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -0,0 +1,2813 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, + u32 reg, u32 mask, + u32 shift, u32 val) +{ + u32 regVal; + + regVal = REG_READ(ah, reg) & ~mask; + regVal |= (val << shift) & mask; + + REG_WRITE(ah, reg, regVal); + + if (ah->config.analog_shiftreg) + udelay(100); + + return; +} + +static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) +{ + + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + + return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +static inline int16_t ath9k_hw_interpolate(u16 target, + u16 srcLeft, u16 srcRight, + int16_t targetLeft, + int16_t targetRight) +{ + int16_t rv; + + if (srcRight == srcLeft) { + rv = targetLeft; + } else { + rv = (int16_t) (((target - srcLeft) * targetRight + + (srcRight - target) * targetLeft) / + (srcRight - srcLeft)); + } + return rv; +} + +static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, + u16 listSize, u16 *indexL, + u16 *indexR) +{ + u16 i; + + if (target <= pList[0]) { + *indexL = *indexR = 0; + return true; + } + if (target >= pList[listSize - 1]) { + *indexL = *indexR = (u16) (listSize - 1); + return true; + } + + for (i = 0; i < listSize - 1; i++) { + if (pList[i] == target) { + *indexL = *indexR = i; + return true; + } + if (target < pList[i + 1]) { + *indexL = i; + *indexR = (u16) (i + 1); + return false; + } + } + return false; +} + +static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) +{ + struct ath_softc *sc = ah->ah_sc; + + return sc->bus_ops->eeprom_read(ah, off, data); +} + +static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList) +{ + u16 i, k; + u8 currPwr = pwrMin; + u16 idxL = 0, idxR = 0; + + for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { + ath9k_hw_get_lower_upper_index(currPwr, pPwrList, + numIntercepts, &(idxL), + &(idxR)); + if (idxR < 1) + idxR = 1; + if (idxL == numIntercepts - 1) + idxL = (u16) (numIntercepts - 2); + if (pPwrList[idxL] == pPwrList[idxR]) + k = pVpdList[idxL]; + else + k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / + (pPwrList[idxR] - pPwrList[idxL])); + pRetVpdList[i] = (u8) k; + currPwr += 2; + } + + return true; +} + +static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = + (u8)ath9k_hw_interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static void ath9k_get_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct calDataPerFreqOpLoop *rawDatasetOpLoop, + u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) +{ + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) + if (calChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + calChans, numPiers, &idxL, &idxR); + if (match) { + pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; + *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; + *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + + rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } + + while (pcdac > ah->originalGain[i] && + i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) + i++; + + *pcdacIdx = i; + return; +} + +static void ath9k_olc_get_pdadcs(struct ath_hw *ah, + u32 initTxGain, + int txPower, + u8 *pPDADCValues) +{ + u32 i; + u32 offset; + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, + AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); + + offset = txPower; + for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) + if (i < offset) + pPDADCValues[i] = 0x0; + else + pPDADCValues[i] = 0xFF; +} + + + + +static void ath9k_hw_get_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = isHt40Target ? centers.synth_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else + if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, + clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static u16 ath9k_hw_get_max_edge_power(u16 freq, + struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges) +{ + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + + for (i = 0; (i < num_band_edges) && + (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { + twiceMaxEdgePower = pRdEdgesPower[i].tPower; + break; + } else if ((i > 0) && + (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, + is2GHz))) { + if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, + is2GHz) < freq && + pRdEdgesPower[i - 1].flag) { + twiceMaxEdgePower = + pRdEdgesPower[i - 1].tPower; + } + break; + } + } + + return twiceMaxEdgePower; +} + +/****************************************/ +/* EEPROM Operations for 4K sized cards */ +/****************************************/ + +static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); +} + +static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); +} + +static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.map4k; + int addr, eep_start_loc = 0; + + eep_start_loc = 64; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + + return true; +#undef SIZE_EEPROM_4K +} + +static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) +{ +#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ar5416_eeprom_4k *eep = + (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr; + + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); + + for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.map4k.baseEepHeader.length); + else + el = ah->eeprom.map4k.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_4k)) + el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing\n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +#undef EEPROM_4K_SIZE +} + +static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_2: + return pModal->ob_01; + case EEP_DB_2: + return pModal->db1_01; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_FRAC_N_5G: + return 0; + default: + return 0; + } +} + +static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_4k *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; +#define PD_GAIN_BOUNDARY_DEFAULT 58; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex >= maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +#undef TMP_VAL_VPD_TABLE +} + +static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + struct cal_data_per_freq_4k *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; + u32 reg32, regOffset, regChainOffset; + + xpdMask = pEepData->modalHeader.xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader.pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; + + numXpdGain = 0; + + for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); + + for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDataset = pEepData->calPierData2G[i]; + + ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_4k *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = max((u16)0, scaledPower); + + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && + pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | + SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = + ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains + (tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = + min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + return true; +} + +static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + return 0; +} + +static void ath9k_hw_4k_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 biaslevel; + + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; + + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &eep->modalHeader; + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ah->iniAddac, 7, 1) = + (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + } +} + +static void ath9k_hw_4k_set_gain(struct ath_hw *ah, + struct modal_eep_4k_header *pModal, + struct ar5416_eeprom_4k *eep, + u8 txRxAttenLocal, int regChainOffset) +{ + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[0]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[0]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + } + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); +} + +static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 txRxAttenLocal; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; + u32 regVal; + + pModal = &eep->modalHeader; + txRxAttenLocal = 23; + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + /* Single chain for 4K EEPROM*/ + ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); + + /* Initialize Ant Diversity settings from EEPROM */ + if (pModal->version == 3) { + ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); + ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); + regVal = REG_READ(ah, 0x99ac); + regVal &= (~(0x7f000000)); + regVal |= ((ant_div_control1 & 0x1) << 24); + regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); + regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); + regVal |= ((ant_div_control2 & 0x3) << 25); + regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); + REG_WRITE(ah, 0x99ac, regVal); + regVal = REG_READ(ah, 0x99ac); + regVal = REG_READ(ah, 0xa208); + regVal &= (~(0x1 << 13)); + regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); + REG_WRITE(ah, 0xa208, regVal); + regVal = REG_READ(ah, 0xa208); + } + + if (pModal->version >= 2) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = (pModal->ob_01 >> 4) & 0xf; + ob[2] = (pModal->ob_234 & 0xf); + ob[3] = ((pModal->ob_234 >> 4) & 0xf); + ob[4] = ((pModal->ob_234 >> 8) & 0xf); + + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = ((pModal->db1_01 >> 4) & 0xf); + db1[2] = (pModal->db1_234 & 0xf); + db1[3] = ((pModal->db1_234 >> 4) & 0xf); + db1[4] = ((pModal->db1_234 >> 8) & 0xf); + + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = ((pModal->db2_01 >> 4) & 0xf); + db2[2] = (pModal->db2_234 & 0xf); + db2[3] = ((pModal->db2_234 >> 4) & 0xf); + db2[4] = ((pModal->db2_234 >> 8) & 0xf); + + } else if (pModal->version == 1) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = db1[2] = db1[3] = + db1[4] = ((pModal->db1_01 >> 4) & 0xf); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = db2[2] = db2[3] = + db2[4] = ((pModal->db2_01 >> 4) & 0xf); + } else { + int i; + for (i = 0; i < 5; i++) { + ob[i] = pModal->ob_01; + db1[i] = pModal->db1_01; + db2[i] = pModal->db1_01; + } + } + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); + + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } +} + +static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +{ +#define EEP_MAP4K_SPURCHAN \ + (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) + + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP4K_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_MAP4K_SPURCHAN +} + +static struct eeprom_ops eep_4k_ops = { + .check_eeprom = ath9k_hw_4k_check_eeprom, + .get_eeprom = ath9k_hw_4k_get_eeprom, + .fill_eeprom = ath9k_hw_4k_fill_eeprom, + .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_4k_set_board_values, + .set_addac = ath9k_hw_4k_set_addac, + .set_txpower = ath9k_hw_4k_set_txpower, + .get_spur_channel = ath9k_hw_4k_get_spur_channel +}; + +/************************************************/ +/* EEPROM Operations for non-4K (Default) cards */ +/************************************************/ + +static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); +} + +static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); +} + +static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.def; + int addr, ar5416_eep_start_loc = 0x100; + + for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Unable to read eeprom region\n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_DEF +} + +static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) +{ + struct ar5416_eeprom_def *eep = + (struct ar5416_eeprom_def *) &ah->eeprom.def; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr, size; + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); + return false; + } + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + size = sizeof(struct ar5416_eeprom_def); + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); + + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "Endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.def.baseEepHeader.length); + else + el = ah->eeprom.def.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer, j; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing.\n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { + struct modal_eep_header *pModal = + &eep->modalHeader[j]; + integer = swab32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +} + +static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = eep->modalHeader; + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_5: + return pModal[0].noiseFloorThreshCh[0]; + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_5: + return pModal[0].ob; + case EEP_DB_5: + return pModal[0].db; + case EEP_OB_2: + return pModal[1].ob; + case EEP_DB_2: + return pModal[1].db; + case EEP_MINOR_REV: + return AR5416_VER_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + case EEP_OL_PWRCTRL: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->openLoopPwrCntl ? true : false; + else + return false; + case EEP_RC_CHAIN_MASK: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->rcChainMask; + else + return 0; + case EEP_DAC_HPWR_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) + return pBase->dacHiPwrMode_5G; + else + return 0; + case EEP_FRAC_N_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) + return pBase->frac_n_5g; + else + return 0; + default: + return 0; + } +} + +static void ath9k_hw_def_set_gain(struct ath_hw *ah, + struct modal_eep_header *pModal, + struct ar5416_eeprom_def *eep, + u8 txRxAttenLocal, int regChainOffset, int i) +{ + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[i]; + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[i]); + } else { + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) + | SM(pModal-> bswMargin[i], + AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) + | SM(pModal->bswAtten[i], + AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); + } else { + REG_WRITE(ah, + AR_PHY_RXGAIN + regChainOffset, + (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & + ~AR_PHY_RXGAIN_TXRX_ATTEN) + | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } +} + +static void ath9k_hw_def_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_header *pModal; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + int i, regChainOffset; + u8 txRxAttenLocal; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_9280(ah)) { + if (i >= 2) + break; + } + + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + else + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) + ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, + regChainOffset, i); + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (IS_CHAN_2GHZ(chan)) { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_OB, + AR_AN_RF2G1_CH0_OB_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_DB, + AR_AN_RF2G1_CH0_DB_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_OB, + AR_AN_RF2G1_CH1_OB_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_DB, + AR_AN_RF2G1_CH1_DB_S, + pModal->db_ch1); + } else { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_OB5, + AR_AN_RF5G1_CH0_OB5_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_DB5, + AR_AN_RF5G1_CH0_DB5_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_OB5, + AR_AN_RF5G1_CH1_OB5_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_DB5, + AR_AN_RF5G1_CH1_DB5_S, + pModal->db_ch1); + } + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_XPABIAS_LVL, + AR_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_LOCALBIAS, + AR_AN_TOP2_LOCALBIAS_S, + pModal->local_bias); + REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, + pModal->force_xpaon); + } + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + if (!AR_SREV_9280_10_OR_LATER(ah)) + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_PGA, + pModal->pgaDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, + AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + if (AR_SREV_9280_20_OR_LATER(ah) && + AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, + AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, + pModal->miscBits); + + + if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { + if (IS_CHAN_2GHZ(chan)) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + else if (eep->baseEepHeader.dacHiPwrMode_5G) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); + else + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + + REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, + pModal->miscBits >> 2); + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_DESIRED_SCALE_CCK, + eep->baseEepHeader.desiredScaleCCK); + } +} + +static void ath9k_hw_def_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ +#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) + struct modal_eep_header *pModal; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + u8 biaslevel; + + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; + + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); + + freqCount++; + + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) + break; + + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); + else + break; + freqCount++; + } + } + + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, + 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, + 6, 1) & (~0xc0)) | biaslevel << 6; + } +#undef XPA_LVL_FREQ +} + +static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +} + +static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ +#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) +#define SM_PDGAIN_B(x, y) \ + SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) + + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; + + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { + pRawDataset = pEepData->calPierData2G[0]; + ah->initPDADC = ((struct calDataPerFreqOpLoop *) + pRawDataset)->vpdPdg[0][0]; + } + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; + + + if (OLC_FOR_AR9280_20_LATER) { + u8 pcdacIdx; + u8 txPower; + + ath9k_get_txgain_index(ah, chan, + (struct calDataPerFreqOpLoop *)pRawDataset, + pCalBChans, numPiers, &txPower, &pcdacIdx); + ath9k_olc_get_pdadcs(ah, pcdacIdx, + txPower/2, pdadcValues); + } else { + ath9k_hw_get_def_gain_boundaries_pdadcs(ah, + chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, + gainBoundaries, + pdadcValues, + numXpdGain); + } + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(0x6, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM_PD_GAIN(1) | SM_PD_GAIN(2) | + SM_PD_GAIN(3) | SM_PD_GAIN(4)); + } else { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| + SM_PDGAIN_B(0, 1) | + SM_PDGAIN_B(1, 2) | + SM_PDGAIN_B(2, 3) | + SM_PDGAIN_B(3, 4)); + } + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +#undef SM_PD_GAIN +#undef SM_PDGAIN_B +} + +static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11a[] = + { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max( + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + twiceLargestAntenna = max((u8)twiceLargestAntenna, + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } else { + numCtlModes = ARRAY_SIZE(ctlModesFor11a) - + SUB_NUM_CTL_MODES_AT_5G_40; + pCtlMode = ctlModesFor11a; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11a); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + ; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = + targetPowerCckExt.tPow2x[0]; + } + } + return true; +} + +static int ath9k_hw_def_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ +#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i, cck_ofdm_delta = 0; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + if (OLC_FOR_AR9280_20_LATER) { + cck_ofdm_delta = 2; + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch(ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } + + return 0; +} + +static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); + struct base_eep_header *pBase = &eep->baseEepHeader; + u8 num_ant_config; + + num_ant_config = 1; + + if (pBase->version >= 0x0E0D) + if (pModal->useAnt1) + num_ant_config += 1; + + return num_ant_config; +} + +static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +{ +#define EEP_DEF_SPURCHAN \ + (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) + + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_DEF_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_DEF_SPURCHAN +} + +static struct eeprom_ops eep_def_ops = { + .check_eeprom = ath9k_hw_def_check_eeprom, + .get_eeprom = ath9k_hw_def_get_eeprom, + .fill_eeprom = ath9k_hw_def_fill_eeprom, + .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_def_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_def_set_board_values, + .set_addac = ath9k_hw_def_set_addac, + .set_txpower = ath9k_hw_def_set_txpower, + .get_spur_channel = ath9k_hw_def_get_spur_channel +}; + +int ath9k_hw_eeprom_attach(struct ath_hw *ah) +{ + int status; + + if (AR_SREV_9285(ah)) { + ah->eep_map = EEP_MAP_4KBITS; + ah->eep_ops = &eep_4k_ops; + } else { + ah->eep_map = EEP_MAP_DEFAULT; + ah->eep_ops = &eep_def_ops; + } + + if (!ah->eep_ops->fill_eeprom(ah)) + return -EIO; + + status = ah->eep_ops->check_eeprom(ah); + + return status; +} diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h new file mode 100644 index 0000000..9a7715d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef EEPROM_H +#define EEPROM_H + +#include + +#define AH_USE_EEPROM 0x1 + +#ifdef __BIG_ENDIAN +#define AR5416_EEPROM_MAGIC 0x5aa5 +#else +#define AR5416_EEPROM_MAGIC 0xa55a +#endif + +#define CTRY_DEBUG 0x1ff +#define CTRY_DEFAULT 0 + +#define AR_EEPROM_EEPCAP_COMPRESS_DIS 0x0001 +#define AR_EEPROM_EEPCAP_AES_DIS 0x0002 +#define AR_EEPROM_EEPCAP_FASTFRAME_DIS 0x0004 +#define AR_EEPROM_EEPCAP_BURST_DIS 0x0008 +#define AR_EEPROM_EEPCAP_MAXQCU 0x01F0 +#define AR_EEPROM_EEPCAP_MAXQCU_S 4 +#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN 0x0200 +#define AR_EEPROM_EEPCAP_KC_ENTRIES 0xF000 +#define AR_EEPROM_EEPCAP_KC_ENTRIES_S 12 + +#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040 +#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 +#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100 +#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 +#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 +#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800 + +#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000 +#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000 + +#define AR5416_EEPROM_MAGIC_OFFSET 0x0 +#define AR5416_EEPROM_S 2 +#define AR5416_EEPROM_OFFSET 0x2000 +#define AR5416_EEPROM_MAX 0xae0 + +#define AR5416_EEPROM_START_ADDR \ + (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 + +#define SD_NO_CTL 0xE0 +#define NO_CTL 0xff +#define CTL_MODE_M 7 +#define CTL_11A 0 +#define CTL_11B 1 +#define CTL_11G 2 +#define CTL_2GHT20 5 +#define CTL_5GHT20 6 +#define CTL_2GHT40 7 +#define CTL_5GHT40 8 + +#define EXT_ADDITIVE (0x8000) +#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) +#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) +#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) + +#define SUB_NUM_CTL_MODES_AT_5G_40 2 +#define SUB_NUM_CTL_MODES_AT_2G_40 3 + +#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + +/* + * For AR9285 and later chipsets, the following bits are not being programmed + * in EEPROM and so need to be enabled always. + * + * Bit 0: en_fcc_mid + * Bit 1: en_jap_mid + * Bit 2: en_fcc_dfs_ht40 + * Bit 3: en_jap_ht40 + * Bit 4: en_jap_dfs_ht40 + */ +#define AR9285_RDEXT_DEFAULT 0x1F + +#define AR_EEPROM_MAC(i) (0x1d+(i)) +#define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) +#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) +#define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) + +#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) +#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ + ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) + +#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c +#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 +#define AR_EEPROM_RFSILENT_POLARITY 0x0002 +#define AR_EEPROM_RFSILENT_POLARITY_S 1 + +#define EEP_RFSILENT_ENABLED 0x0001 +#define EEP_RFSILENT_ENABLED_S 0 +#define EEP_RFSILENT_POLARITY 0x0002 +#define EEP_RFSILENT_POLARITY_S 1 +#define EEP_RFSILENT_GPIO_SEL 0x001c +#define EEP_RFSILENT_GPIO_SEL_S 2 + +#define AR5416_OPFLAGS_11A 0x01 +#define AR5416_OPFLAGS_11G 0x02 +#define AR5416_OPFLAGS_N_5G_HT40 0x04 +#define AR5416_OPFLAGS_N_2G_HT40 0x08 +#define AR5416_OPFLAGS_N_5G_HT20 0x10 +#define AR5416_OPFLAGS_N_2G_HT20 0x20 + +#define AR5416_EEP_NO_BACK_VER 0x1 +#define AR5416_EEP_VER 0xE +#define AR5416_EEP_VER_MINOR_MASK 0x0FFF +#define AR5416_EEP_MINOR_VER_2 0x2 +#define AR5416_EEP_MINOR_VER_3 0x3 +#define AR5416_EEP_MINOR_VER_7 0x7 +#define AR5416_EEP_MINOR_VER_9 0x9 +#define AR5416_EEP_MINOR_VER_16 0x10 +#define AR5416_EEP_MINOR_VER_17 0x11 +#define AR5416_EEP_MINOR_VER_19 0x13 +#define AR5416_EEP_MINOR_VER_20 0x14 +#define AR5416_EEP_MINOR_VER_22 0x16 + +#define AR5416_NUM_5G_CAL_PIERS 8 +#define AR5416_NUM_2G_CAL_PIERS 4 +#define AR5416_NUM_5G_20_TARGET_POWERS 8 +#define AR5416_NUM_5G_40_TARGET_POWERS 8 +#define AR5416_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_NUM_2G_20_TARGET_POWERS 4 +#define AR5416_NUM_2G_40_TARGET_POWERS 4 +#define AR5416_NUM_CTLS 24 +#define AR5416_NUM_BAND_EDGES 8 +#define AR5416_NUM_PD_GAINS 4 +#define AR5416_PD_GAINS_IN_MASK 4 +#define AR5416_PD_GAIN_ICEPTS 5 +#define AR5416_EEPROM_MODAL_SPURS 5 +#define AR5416_MAX_RATE_POWER 63 +#define AR5416_NUM_PDADC_VALUES 128 +#define AR5416_BCHAN_UNUSED 0xFF +#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 +#define AR5416_MAX_CHAINS 3 +#define AR5416_PWR_TABLE_OFFSET -5 + +/* Rx gain type values */ +#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 +#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1 +#define AR5416_EEP_RXGAIN_ORIG 2 + +/* Tx gain type values */ +#define AR5416_EEP_TXGAIN_ORIGINAL 0 +#define AR5416_EEP_TXGAIN_HIGH_POWER 1 + +#define AR5416_EEP4K_START_LOC 64 +#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 +#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_CTLS 12 +#define AR5416_EEP4K_NUM_BAND_EDGES 4 +#define AR5416_EEP4K_NUM_PD_GAINS 2 +#define AR5416_EEP4K_PD_GAINS_IN_MASK 4 +#define AR5416_EEP4K_PD_GAIN_ICEPTS 5 +#define AR5416_EEP4K_MAX_CHAINS 1 + +#define AR9280_TX_GAIN_TABLE_SIZE 22 + +enum eeprom_param { + EEP_NFTHRESH_5, + EEP_NFTHRESH_2, + EEP_MAC_MSW, + EEP_MAC_MID, + EEP_MAC_LSW, + EEP_REG_0, + EEP_REG_1, + EEP_OP_CAP, + EEP_OP_MODE, + EEP_RF_SILENT, + EEP_OB_5, + EEP_DB_5, + EEP_OB_2, + EEP_DB_2, + EEP_MINOR_REV, + EEP_TX_MASK, + EEP_RX_MASK, + EEP_RXGAIN_TYPE, + EEP_TXGAIN_TYPE, + EEP_OL_PWRCTRL, + EEP_RC_CHAIN_MASK, + EEP_DAC_HPWR_5G, + EEP_FRAC_N_5G +}; + +enum ar5416_rates { + rate6mb, rate9mb, rate12mb, rate18mb, + rate24mb, rate36mb, rate48mb, rate54mb, + rate1l, rate2l, rate2s, rate5_5l, + rate5_5s, rate11l, rate11s, rateXr, + rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3, + rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7, + rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3, + rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7, + rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm, + Ar5416RateSize +}; + +enum ath9k_hal_freq_band { + ATH9K_HAL_FREQ_BAND_5GHZ = 0, + ATH9K_HAL_FREQ_BAND_2GHZ = 1 +}; + +struct base_eep_header { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 pwdclkind; + u8 futureBase_1[2]; + u8 rxGainType; + u8 dacHiPwrMode_5G; + u8 openLoopPwrCntl; + u8 dacLpMode; + u8 txGainType; + u8 rcChainMask; + u8 desiredScaleCCK; + u8 power_table_offset; + u8 frac_n_5g; + u8 futureBase_3[21]; +} __packed; + +struct base_eep_header_4k { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 txGainType; +} __packed; + + +struct spur_chan { + u16 spurChan; + u8 spurRangeLow; + u8 spurRangeHigh; +} __packed; + +struct modal_eep_header { + u32 antCtrlChain[AR5416_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_MAX_CHAINS]; + u8 iqCalQCh[AR5416_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob; + u8 db; + u8 xpaBiasLvl; + u8 pwrDecreaseFor2Chain; + u8 pwrDecreaseFor3Chain; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_MAX_CHAINS]; + u8 bswMargin[AR5416_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_MAX_CHAINS]; + u8 xatten2Margin[AR5416_MAX_CHAINS]; + u8 ob_ch1; + u8 db_ch1; + u8 useAnt1:1, + force_xpaon:1, + local_bias:1, + femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1; + u8 miscBits; + u16 xpaBiasLvlFreq[3]; + u8 futureModal[6]; + + struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + +struct calDataPerFreqOpLoop { + u8 pwrPdg[2][5]; + u8 vpdPdg[2][5]; + u8 pcdac[2][5]; + u8 empty[2][5]; +} __packed; + +struct modal_eep_4k_header { + u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; + u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob_01; + u8 db1_01; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; + u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; + u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; + u8 db2_01; + u8 version; + u16 ob_234; + u16 db1_234; + u16 db2_234; + u8 futureModal[4]; + + struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + + +struct cal_data_per_freq { + u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; +} __packed; + +struct cal_data_per_freq_4k { + u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; +} __packed; + +struct cal_target_power_leg { + u8 bChannel; + u8 tPow2x[4]; +} __packed; + +struct cal_target_power_ht { + u8 bChannel; + u8 tPow2x[8]; +} __packed; + + +#ifdef __BIG_ENDIAN_BITFIELD +struct cal_ctl_edges { + u8 bChannel; + u8 flag:2, tPower:6; +} __packed; +#else +struct cal_ctl_edges { + u8 bChannel; + u8 tPower:6, flag:2; +} __packed; +#endif + +struct cal_ctl_data { + struct cal_ctl_edges + ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; +} __packed; + +struct cal_ctl_data_4k { + struct cal_ctl_edges + ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; +} __packed; + +struct ar5416_eeprom_def { + struct base_eep_header baseEepHeader; + u8 custData[64]; + struct modal_eep_header modalHeader[2]; + u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS]; + u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS]; + struct cal_data_per_freq + calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS]; + struct cal_data_per_freq + calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR5416_NUM_CTLS]; + struct cal_ctl_data ctlData[AR5416_NUM_CTLS]; + u8 padding; +} __packed; + +struct ar5416_eeprom_4k { + struct base_eep_header_4k baseEepHeader; + u8 custData[20]; + struct modal_eep_4k_header modalHeader; + u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_data_per_freq_4k + calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR5416_EEP4K_NUM_CTLS]; + struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS]; + u8 padding; +} __packed; + +enum reg_ext_bitmap { + REG_EXT_JAPAN_MIDBAND = 1, + REG_EXT_FCC_DFS_HT40 = 2, + REG_EXT_JAPAN_NONDFS_HT40 = 3, + REG_EXT_JAPAN_DFS_HT40 = 4 +}; + +struct ath9k_country_entry { + u16 countryCode; + u16 regDmnEnum; + u16 regDmn5G; + u16 regDmn2G; + u8 isMultidomain; + u8 iso[3]; +}; + +enum ath9k_eep_map { + EEP_MAP_DEFAULT = 0x0, + EEP_MAP_4KBITS, + EEP_MAP_MAX +}; + +struct eeprom_ops { + int (*check_eeprom)(struct ath_hw *hw); + u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param); + bool (*fill_eeprom)(struct ath_hw *hw); + int (*get_eeprom_ver)(struct ath_hw *hw); + int (*get_eeprom_rev)(struct ath_hw *hw); + u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band); + u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw, + struct ath9k_channel *chan); + void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); + void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); + int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, + u16 cfgCtl, u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, u8 powerLimit); + u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); +}; + +#define ar5416_get_ntxchains(_txchainmask) \ + (((_txchainmask >> 2) & 1) + \ + ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) + +int ath9k_hw_eeprom_attach(struct ath_hw *ah); + +#endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c new file mode 100644 index 0000000..24299e6 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -0,0 +1,3861 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "ath9k.h" +#include "initvals.h" + +static int btcoex_enable; +module_param(btcoex_enable, bool, 0); +MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support"); + +#define ATH9K_CLOCK_RATE_CCK 22 +#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 +#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 + +static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode); +static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value); +static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); +static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); + +/********************/ +/* Helper Functions */ +/********************/ + +static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + + if (!ah->curchan) /* should really check for CCK instead */ + return clks / ATH9K_CLOCK_RATE_CCK; + if (conf->channel->band == IEEE80211_BAND_2GHZ) + return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM; + + return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM; +} + +static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + + if (conf_is_ht40(conf)) + return ath9k_hw_mac_usec(ah, clks) / 2; + else + return ath9k_hw_mac_usec(ah, clks); +} + +static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + + if (!ah->curchan) /* should really check for CCK instead */ + return usecs *ATH9K_CLOCK_RATE_CCK; + if (conf->channel->band == IEEE80211_BAND_2GHZ) + return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM; + return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM; +} + +static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) +{ + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + + if (conf_is_ht40(conf)) + return ath9k_hw_mac_clks(ah, usecs) * 2; + else + return ath9k_hw_mac_clks(ah, usecs); +} + +bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) +{ + int i; + + BUG_ON(timeout < AH_TIME_QUANTUM); + + for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) { + if ((REG_READ(ah, reg) & mask) == val) + return true; + + udelay(AH_TIME_QUANTUM); + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + timeout, reg, REG_READ(ah, reg), mask, val); + + return false; +} + +u32 ath9k_hw_reverse_bits(u32 val, u32 n) +{ + u32 retval; + int i; + + for (i = 0, retval = 0; i < n; i++) { + retval = (retval << 1) | (val & 1); + val >>= 1; + } + return retval; +} + +bool ath9k_get_channel_edges(struct ath_hw *ah, + u16 flags, u16 *low, + u16 *high) +{ + struct ath9k_hw_capabilities *pCap = &ah->caps; + + if (flags & CHANNEL_5GHZ) { + *low = pCap->low_5ghz_chan; + *high = pCap->high_5ghz_chan; + return true; + } + if ((flags & CHANNEL_2GHZ)) { + *low = pCap->low_2ghz_chan; + *high = pCap->high_2ghz_chan; + return true; + } + return false; +} + +u16 ath9k_hw_computetxtime(struct ath_hw *ah, + struct ath_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble) +{ + u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; + u32 kbps; + + kbps = rates->info[rateix].ratekbps; + + if (kbps == 0) + return 0; + + switch (rates->info[rateix].phy) { + case WLAN_RC_PHY_CCK: + phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; + if (shortPreamble && rates->info[rateix].short_preamble) + phyTime >>= 1; + numBits = frameLen << 3; + txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); + break; + case WLAN_RC_PHY_OFDM: + if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_QUARTER + + OFDM_PREAMBLE_TIME_QUARTER + + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); + } else if (ah->curchan && + IS_CHAN_HALF_RATE(ah->curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_HALF + + OFDM_PREAMBLE_TIME_HALF + + (numSymbols * OFDM_SYMBOL_TIME_HALF); + } else { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME + + (numSymbols * OFDM_SYMBOL_TIME); + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Unknown phy %u (rate ix %u)\n", + rates->info[rateix].phy, rateix); + txTime = 0; + break; + } + + return txTime; +} + +void ath9k_hw_get_channel_centers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct chan_centers *centers) +{ + int8_t extoff; + + if (!IS_CHAN_HT40(chan)) { + centers->ctl_center = centers->ext_center = + centers->synth_center = chan->channel; + return; + } + + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) { + centers->synth_center = + chan->channel + HT40_CHANNEL_CENTER_SHIFT; + extoff = 1; + } else { + centers->synth_center = + chan->channel - HT40_CHANNEL_CENTER_SHIFT; + extoff = -1; + } + + centers->ctl_center = + centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); + centers->ext_center = + centers->synth_center + (extoff * + ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? + HT40_CHANNEL_CENTER_SHIFT : 15)); +} + +/******************/ +/* Chip Revisions */ +/******************/ + +static void ath9k_hw_read_revisions(struct ath_hw *ah) +{ + u32 val; + + val = REG_READ(ah, AR_SREV) & AR_SREV_ID; + + if (val == 0xFF) { + val = REG_READ(ah, AR_SREV); + ah->hw_version.macVersion = + (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; + ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); + ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; + } else { + if (!AR_SREV_9100(ah)) + ah->hw_version.macVersion = MS(val, AR_SREV_VERSION); + + ah->hw_version.macRev = val & AR_SREV_REVISION; + + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) + ah->is_pciexpress = true; + } +} + +static int ath9k_hw_get_radiorev(struct ath_hw *ah) +{ + u32 val; + int i; + + REG_WRITE(ah, AR_PHY(0x36), 0x00007058); + + for (i = 0; i < 8; i++) + REG_WRITE(ah, AR_PHY(0x20), 0x00010000); + val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); + + return ath9k_hw_reverse_bits(val, 8); +} + +/************************************/ +/* HW Attach, Detach, Init Routines */ +/************************************/ + +static void ath9k_hw_disablepcie(struct ath_hw *ah) +{ + if (AR_SREV_9100(ah)) + return; + + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); + REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); + + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); +} + +static bool ath9k_hw_chip_test(struct ath_hw *ah) +{ + u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; + u32 regHold[2]; + u32 patternData[4] = { 0x55555555, + 0xaaaaaaaa, + 0x66666666, + 0x99999999 }; + int i, j; + + for (i = 0; i < 2; i++) { + u32 addr = regAddr[i]; + u32 wrData, rdData; + + regHold[i] = REG_READ(ah, addr); + for (j = 0; j < 0x100; j++) { + wrData = (j << 16) | j; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (rdData != wrData) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); + return false; + } + } + for (j = 0; j < 4; j++) { + wrData = patternData[j]; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (wrData != rdData) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); + return false; + } + } + REG_WRITE(ah, regAddr[i], regHold[i]); + } + udelay(100); + + return true; +} + +static const char *ath9k_hw_devname(u16 devid) +{ + switch (devid) { + case AR5416_DEVID_PCI: + return "Atheros 5416"; + case AR5416_DEVID_PCIE: + return "Atheros 5418"; + case AR9160_DEVID_PCI: + return "Atheros 9160"; + case AR5416_AR9100_DEVID: + return "Atheros 9100"; + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + return "Atheros 9280"; + case AR9285_DEVID_PCIE: + return "Atheros 9285"; + } + + return NULL; +} + +static void ath9k_hw_set_defaults(struct ath_hw *ah) +{ + int i; + + ah->config.dma_beacon_response_time = 2; + ah->config.sw_beacon_response_time = 10; + ah->config.additional_swba_backoff = 0; + ah->config.ack_6mb = 0x0; + ah->config.cwm_ignore_extcca = 0; + ah->config.pcie_powersave_enable = 0; + ah->config.pcie_clock_req = 0; + ah->config.pcie_waen = 0; + ah->config.analog_shiftreg = 1; + ah->config.ht_enable = 1; + ah->config.ofdm_trig_low = 200; + ah->config.ofdm_trig_high = 500; + ah->config.cck_trig_high = 200; + ah->config.cck_trig_low = 100; + ah->config.enable_ani = 1; + ah->config.diversity_control = 0; + ah->config.antenna_switch_swap = 0; + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + ah->config.spurchans[i][0] = AR_NO_SPUR; + ah->config.spurchans[i][1] = AR_NO_SPUR; + } + + ah->config.intr_mitigation = true; + + /* + * We need this for PCI devices only (Cardbus, PCI, miniPCI) + * _and_ if on non-uniprocessor systems (Multiprocessor/HT). + * This means we use it for all AR5416 devices, and the few + * minor PCI AR9280 devices out there. + * + * Serialization is required because these devices do not handle + * well the case of two concurrent reads/writes due to the latency + * involved. During one read/write another read/write can be issued + * on another CPU while the previous read/write may still be working + * on our hardware, if we hit this case the hardware poops in a loop. + * We prevent this by serializing reads and writes. + * + * This issue is not present on PCI-Express devices or pre-AR5416 + * devices (legacy, 802.11abg). + */ + if (num_possible_cpus() > 1) + ah->config.serialize_regmode = SER_REG_MODE_AUTO; +} + +static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, + int *status) +{ + struct ath_hw *ah; + + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (ah == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Cannot allocate memory for state block\n"); + *status = -ENOMEM; + return NULL; + } + + ah->ah_sc = sc; + ah->hw_version.magic = AR5416_MAGIC; + ah->regulatory.country_code = CTRY_DEFAULT; + ah->hw_version.devid = devid; + ah->hw_version.subvendorid = 0; + + ah->ah_flags = 0; + if ((devid == AR5416_AR9100_DEVID)) + ah->hw_version.macVersion = AR_SREV_VERSION_9100; + if (!AR_SREV_9100(ah)) + ah->ah_flags = AH_USE_EEPROM; + + ah->regulatory.power_limit = MAX_RATE_POWER; + ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; + ah->atim_window = 0; + ah->diversity_control = ah->config.diversity_control; + ah->antenna_switch_swap = + ah->config.antenna_switch_swap; + ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; + ah->beacon_interval = 100; + ah->enable_32kHz_clock = DONT_USE_32KHZ; + ah->slottime = (u32) -1; + ah->acktimeout = (u32) -1; + ah->ctstimeout = (u32) -1; + ah->globaltxtimeout = (u32) -1; + + ah->gbeacon_rate = 0; + + return ah; +} + +static int ath9k_hw_rfattach(struct ath_hw *ah) +{ + bool rfStatus = false; + int ecode = 0; + + rfStatus = ath9k_hw_init_rf(ah, &ecode); + if (!rfStatus) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "RF setup failed, status: %u\n", ecode); + return ecode; + } + + return 0; +} + +static int ath9k_hw_rf_claim(struct ath_hw *ah) +{ + u32 val; + + REG_WRITE(ah, AR_PHY(0), 0x00000007); + + val = ath9k_hw_get_radiorev(ah); + switch (val & AR_RADIO_SREV_MAJOR) { + case 0: + val = AR_RAD5133_SREV_MAJOR; + break; + case AR_RAD5133_SREV_MAJOR: + case AR_RAD5122_SREV_MAJOR: + case AR_RAD2133_SREV_MAJOR: + case AR_RAD2122_SREV_MAJOR: + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Radio Chip Rev 0x%02X not supported\n", + val & AR_RADIO_SREV_MAJOR); + return -EOPNOTSUPP; + } + + ah->hw_version.analog5GhzRev = val; + + return 0; +} + +static int ath9k_hw_init_macaddr(struct ath_hw *ah) +{ + u32 sum; + int i; + u16 eeval; + + sum = 0; + for (i = 0; i < 3; i++) { + eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i)); + sum += eeval; + ah->macaddr[2 * i] = eeval >> 8; + ah->macaddr[2 * i + 1] = eeval & 0xff; + } + if (sum == 0 || sum == 0xffff * 3) + return -EADDRNOTAVAIL; + + return 0; +} + +static void ath9k_hw_init_rxgain_ini(struct ath_hw *ah) +{ + u32 rxgain_type; + + if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { + rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE); + + if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_backoff_13db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); + else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_backoff_23db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); + else + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } +} + +static void ath9k_hw_init_txgain_ini(struct ath_hw *ah) +{ + u32 txgain_type; + + if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { + txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9280Modes_high_power_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } +} + +static int ath9k_hw_post_attach(struct ath_hw *ah) +{ + int ecode; + + if (!ath9k_hw_chip_test(ah)) + return -ENODEV; + + ecode = ath9k_hw_rf_claim(ah); + if (ecode != 0) + return ecode; + + ecode = ath9k_hw_eeprom_attach(ah); + if (ecode != 0) + return ecode; + + DPRINTF(ah->ah_sc, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n", + ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); + + ecode = ath9k_hw_rfattach(ah); + if (ecode != 0) + return ecode; + + if (!AR_SREV_9100(ah)) { + ath9k_hw_ani_setup(ah); + ath9k_hw_ani_attach(ah); + } + + return 0; +} + +static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, + int *status) +{ + struct ath_hw *ah; + int ecode; + u32 i, j; + + ah = ath9k_hw_newstate(devid, sc, status); + if (ah == NULL) + return NULL; + + ath9k_hw_set_defaults(ah); + + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { + DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); + ecode = -EIO; + goto bad; + } + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); + ecode = -EIO; + goto bad; + } + + if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || + (AR_SREV_9280(ah) && !ah->is_pciexpress)) { + ah->config.serialize_regmode = + SER_REG_MODE_ON; + } else { + ah->config.serialize_regmode = + SER_REG_MODE_OFF; + } + } + + DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n", + ah->config.serialize_regmode); + + if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && + (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { + DPRINTF(sc, ATH_DBG_FATAL, + "Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", ah->hw_version.macVersion, + ah->hw_version.macRev); + ecode = -EOPNOTSUPP; + goto bad; + } + + if (AR_SREV_9100(ah)) { + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->supp_cals = IQ_MISMATCH_CAL; + ah->is_pciexpress = false; + } + ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); + + if (AR_SREV_9160_10_OR_LATER(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) { + ah->iq_caldata.calData = &iq_cal_single_sample; + ah->adcgain_caldata.calData = + &adc_gain_cal_single_sample; + ah->adcdc_caldata.calData = + &adc_dc_cal_single_sample; + ah->adcdc_calinitdata.calData = + &adc_init_dc_cal; + } else { + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->adcgain_caldata.calData = + &adc_gain_cal_multi_sample; + ah->adcdc_caldata.calData = + &adc_dc_cal_multi_sample; + ah->adcdc_calinitdata.calData = + &adc_init_dc_cal; + } + ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + } + + ah->ani_function = ATH9K_ANI_ALL; + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + + if (AR_SREV_9285_12_OR_LATER(ah)) { + + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, + ARRAY_SIZE(ar9285Modes_9285_1_2), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, + ARRAY_SIZE(ar9285Common_9285_1_2), 2); + + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), + 2); + } + } else if (AR_SREV_9285_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285, + ARRAY_SIZE(ar9285Modes_9285), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285, + ARRAY_SIZE(ar9285Common_9285), 2); + + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); + } + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, + ARRAY_SIZE(ar9280Modes_9280_2), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, + ARRAY_SIZE(ar9280Common_9280_2), 2); + + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_off_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + } + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9280Modes_fast_clock_9280_2, + ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); + } else if (AR_SREV_9280_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280, + ARRAY_SIZE(ar9280Modes_9280), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280, + ARRAY_SIZE(ar9280Common_9280), 2); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160, + ARRAY_SIZE(ar5416Modes_9160), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, + ARRAY_SIZE(ar5416Common_9160), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, + ARRAY_SIZE(ar5416Bank0_9160), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160, + ARRAY_SIZE(ar5416BB_RfGain_9160), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160, + ARRAY_SIZE(ar5416Bank1_9160), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160, + ARRAY_SIZE(ar5416Bank2_9160), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160, + ARRAY_SIZE(ar5416Bank3_9160), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160, + ARRAY_SIZE(ar5416Bank6_9160), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160, + ARRAY_SIZE(ar5416Bank6TPC_9160), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160, + ARRAY_SIZE(ar5416Bank7_9160), 2); + if (AR_SREV_9160_11(ah)) { + INIT_INI_ARRAY(&ah->iniAddac, + ar5416Addac_91601_1, + ARRAY_SIZE(ar5416Addac_91601_1), 2); + } else { + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160, + ARRAY_SIZE(ar5416Addac_9160), 2); + } + } else if (AR_SREV_9100_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100, + ARRAY_SIZE(ar5416Modes_9100), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, + ARRAY_SIZE(ar5416Common_9100), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, + ARRAY_SIZE(ar5416Bank0_9100), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100, + ARRAY_SIZE(ar5416BB_RfGain_9100), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100, + ARRAY_SIZE(ar5416Bank1_9100), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100, + ARRAY_SIZE(ar5416Bank2_9100), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100, + ARRAY_SIZE(ar5416Bank3_9100), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, + ARRAY_SIZE(ar5416Bank6_9100), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, + ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100, + ARRAY_SIZE(ar5416Bank7_9100), 2); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, + ARRAY_SIZE(ar5416Addac_9100), 2); + } else { + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes, + ARRAY_SIZE(ar5416Modes), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, + ARRAY_SIZE(ar5416Common), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, + ARRAY_SIZE(ar5416Bank0), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, + ARRAY_SIZE(ar5416BB_RfGain), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, + ARRAY_SIZE(ar5416Bank1), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, + ARRAY_SIZE(ar5416Bank2), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, + ARRAY_SIZE(ar5416Bank3), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, + ARRAY_SIZE(ar5416Bank6), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, + ARRAY_SIZE(ar5416Bank6TPC), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, + ARRAY_SIZE(ar5416Bank7), 2); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, + ARRAY_SIZE(ar5416Addac), 2); + } + + if (ah->is_pciexpress) + ath9k_hw_configpcipowersave(ah, 0); + else + ath9k_hw_disablepcie(ah); + + ecode = ath9k_hw_post_attach(ah); + if (ecode != 0) + goto bad; + + if (AR_SREV_9285_12_OR_LATER(ah)) { + u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + + /* txgain table */ + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_high_power_tx_gain_9285_1_2, + ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_original_tx_gain_9285_1_2, + ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6); + } + + } + + /* rxgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_rxgain_ini(ah); + + /* txgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_txgain_ini(ah); + + ath9k_hw_fill_cap_info(ah); + + if ((ah->hw_version.devid == AR9280_DEVID_PCI) && + test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { + + /* EEPROM Fixup */ + for (i = 0; i < ah->iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniModes, i, 0); + + for (j = 1; j < ah->iniModes.ia_columns; j++) { + u32 val = INI_RA(&ah->iniModes, i, j); + + INI_RA(&ah->iniModes, i, j) = + ath9k_hw_ini_fixup(ah, + &ah->eeprom.def, + reg, val); + } + } + } + + ecode = ath9k_hw_init_macaddr(ah); + if (ecode != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to initialize MAC address\n"); + goto bad; + } + + if (AR_SREV_9285(ah)) + ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); + else + ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); + + ath9k_init_nfcal_hist_buffer(ah); + + return ah; +bad: + if (ah) + ath9k_hw_detach(ah); + if (status) + *status = ecode; + + return NULL; +} + +static void ath9k_hw_init_bb(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 synthDelay; + + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + udelay(synthDelay + BASE_ACTIVATE_DELAY); +} + +static void ath9k_hw_init_qos(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); + REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); + + REG_WRITE(ah, AR_QOS_NO_ACK, + SM(2, AR_QOS_NO_ACK_TWO_BIT) | + SM(5, AR_QOS_NO_ACK_BIT_OFF) | + SM(0, AR_QOS_NO_ACK_BYTE_OFF)); + + REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); + REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); +} + +static void ath9k_hw_init_pll(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 pll; + + if (AR_SREV_9100(ah)) { + if (chan && IS_CHAN_5GHZ(chan)) + pll = 0x1450; + else + pll = 0x1458; + } else { + if (AR_SREV_9280_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + + if (chan && IS_CHAN_5GHZ(chan)) { + pll |= SM(0x28, AR_RTC_9160_PLL_DIV); + + + if (AR_SREV_9280_20(ah)) { + if (((chan->channel % 20) == 0) + || ((chan->channel % 10) == 0)) + pll = 0x2850; + else + pll = 0x142c; + } + } else { + pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); + } + + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0x50, AR_RTC_9160_PLL_DIV); + else + pll |= SM(0x58, AR_RTC_9160_PLL_DIV); + } else { + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); + + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0xa, AR_RTC_PLL_DIV); + else + pll |= SM(0xb, AR_RTC_PLL_DIV); + } + } + REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + + udelay(RTC_PLL_SETTLE_DELAY); + + REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); +} + +static void ath9k_hw_init_chain_masks(struct ath_hw *ah) +{ + int rx_chainmask, tx_chainmask; + + rx_chainmask = ah->rxchainmask; + tx_chainmask = ah->txchainmask; + + switch (rx_chainmask) { + case 0x5: + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); + case 0x3: + if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) { + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); + break; + } + case 0x1: + case 0x2: + case 0x7: + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); + break; + default: + break; + } + + REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); + if (tx_chainmask == 0x5) { + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); + } + if (AR_SREV_9100(ah)) + REG_WRITE(ah, AR_PHY_ANALOG_SWAP, + REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); +} + +static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, + enum nl80211_iftype opmode) +{ + ah->mask_reg = AR_IMR_TXERR | + AR_IMR_TXURN | + AR_IMR_RXERR | + AR_IMR_RXORN | + AR_IMR_BCNMISC; + + if (ah->config.intr_mitigation) + ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; + else + ah->mask_reg |= AR_IMR_RXOK; + + ah->mask_reg |= AR_IMR_TXOK; + + if (opmode == NL80211_IFTYPE_AP) + ah->mask_reg |= AR_IMR_MIB; + + REG_WRITE(ah, AR_IMR, ah->mask_reg); + REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); + + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + } +} + +static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) +{ + if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); + ah->acktimeout = (u32) -1; + return false; + } else { + REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); + ah->acktimeout = us; + return true; + } +} + +static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) +{ + if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); + ah->ctstimeout = (u32) -1; + return false; + } else { + REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); + ah->ctstimeout = us; + return true; + } +} + +static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) +{ + if (tu > 0xFFFF) { + DPRINTF(ah->ah_sc, ATH_DBG_XMIT, + "bad global tx timeout %u\n", tu); + ah->globaltxtimeout = (u32) -1; + return false; + } else { + REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); + ah->globaltxtimeout = tu; + return true; + } +} + +static void ath9k_hw_init_user_settings(struct ath_hw *ah) +{ + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n", + ah->misc_mode); + + if (ah->misc_mode != 0) + REG_WRITE(ah, AR_PCU_MISC, + REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); + if (ah->slottime != (u32) -1) + ath9k_hw_setslottime(ah, ah->slottime); + if (ah->acktimeout != (u32) -1) + ath9k_hw_set_ack_timeout(ah, ah->acktimeout); + if (ah->ctstimeout != (u32) -1) + ath9k_hw_set_cts_timeout(ah, ah->ctstimeout); + if (ah->globaltxtimeout != (u32) -1) + ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); +} + +const char *ath9k_hw_probe(u16 vendorid, u16 devid) +{ + return vendorid == ATHEROS_VENDOR_ID ? + ath9k_hw_devname(devid) : NULL; +} + +void ath9k_hw_detach(struct ath_hw *ah) +{ + if (!AR_SREV_9100(ah)) + ath9k_hw_ani_detach(ah); + + ath9k_hw_rfdetach(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + kfree(ah); +} + +struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) +{ + struct ath_hw *ah = NULL; + + switch (devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: + case AR9160_DEVID_PCI: + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + case AR9285_DEVID_PCIE: + ah = ath9k_hw_do_attach(devid, sc, error); + break; + default: + *error = -ENXIO; + break; + } + + return ah; +} + +/*******/ +/* INI */ +/*******/ + +static void ath9k_hw_override_ini(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + /* + * Set the RX_ABORT and RX_DIS and clear if off only after + * RXE is set for MAC. This prevents frames with corrupted + * descriptor status. + */ + REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + + if (!AR_SREV_5416_20_OR_LATER(ah) || + AR_SREV_9280_10_OR_LATER(ah)) + return; + + REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); +} + +static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) +{ + struct base_eep_header *pBase = &(pEepData->baseEepHeader); + + switch (ah->hw_version.devid) { + case AR9280_DEVID_PCI: + if (reg == 0x7894) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ini VAL: %x EEPROM: %x\n", value, + (pBase->version & 0xff)); + + if ((pBase->version & 0xff) > 0x0a) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PWDCLKIND: %d\n", + pBase->pwdclkind); + value &= ~AR_AN_TOP2_PWDCLKIND; + value |= AR_AN_TOP2_PWDCLKIND & + (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); + } else { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PWDCLKIND Earlier Rev\n"); + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "final ini VAL: %x\n", value); + } + break; + } + + return value; +} + +static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) +{ + if (ah->eep_map == EEP_MAP_4KBITS) + return value; + else + return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); +} + +static void ath9k_olc_init(struct ath_hw *ah) +{ + u32 i; + + for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) + ah->originalGain[i] = + MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), + AR_PHY_TX_GAIN); + ah->PDADCdelta = 0; +} + +static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, + struct ath9k_channel *chan) +{ + u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band); + + if (IS_CHAN_B(chan)) + ctl |= CTL_11B; + else if (IS_CHAN_G(chan)) + ctl |= CTL_11G; + else + ctl |= CTL_11A; + + return ctl; +} + +static int ath9k_hw_process_ini(struct ath_hw *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) +{ + int i, regWrites = 0; + struct ieee80211_channel *channel = chan->chan; + u32 modesIndex, freqIndex; + int status; + + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_B: + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + modesIndex = 3; + freqIndex = 2; + break; + + default: + return -EINVAL; + } + + REG_WRITE(ah, AR_PHY(0), 0x00000007); + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); + ah->eep_ops->set_addac(ah, chan); + + if (AR_SREV_5416_22_OR_LATER(ah)) { + REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); + } else { + struct ar5416IniArray temp; + u32 addacSize = + sizeof(u32) * ah->iniAddac.ia_rows * + ah->iniAddac.ia_columns; + + memcpy(ah->addac5416_21, + ah->iniAddac.ia_array, addacSize); + + (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; + + temp.ia_array = ah->addac5416_21; + temp.ia_columns = ah->iniAddac.ia_columns; + temp.ia_rows = ah->iniAddac.ia_rows; + REG_WRITE_ARRAY(&temp, 1, regWrites); + } + + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); + + for (i = 0; i < ah->iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniModes, i, 0); + u32 val = INI_RA(&ah->iniModes, i, modesIndex); + + REG_WRITE(ah, reg, val); + + if (reg >= 0x7800 && reg < 0x78a0 + && ah->config.analog_shiftreg) { + udelay(100); + } + + DO_DELAY(regWrites); + } + + if (AR_SREV_9280(ah)) + REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); + + if (AR_SREV_9280(ah) || (AR_SREV_9285(ah) && + AR_SREV_9285_12_OR_LATER(ah))) + REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + + for (i = 0; i < ah->iniCommon.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniCommon, i, 0); + u32 val = INI_RA(&ah->iniCommon, i, 1); + + REG_WRITE(ah, reg, val); + + if (reg >= 0x7800 && reg < 0x78a0 + && ah->config.analog_shiftreg) { + udelay(100); + } + + DO_DELAY(regWrites); + } + + ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites); + + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { + REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, + regWrites); + } + + ath9k_hw_override_ini(ah, chan); + ath9k_hw_set_regs(ah, chan, macmode); + ath9k_hw_init_chain_masks(ah); + + if (OLC_FOR_AR9280_20_LATER) + ath9k_olc_init(ah); + + status = ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)); + if (status != 0) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Error initializing transmit power\n"); + return -EIO; + } + + if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "ar5416SetRfRegs failed\n"); + return -EIO; + } + + return 0; +} + +/****************************************/ +/* Reset and Channel Switching Routines */ +/****************************************/ + +static void ath9k_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan) +{ + u32 rfMode = 0; + + if (chan == NULL) + return; + + rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) + ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + + if (!AR_SREV_9280_10_OR_LATER(ah)) + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; + + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) + rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + + REG_WRITE(ah, AR_PHY_MODE, rfMode); +} + +static void ath9k_hw_mark_phy_inactive(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +} + +static inline void ath9k_hw_set_dma(struct ath_hw *ah) +{ + u32 regval; + + regval = REG_READ(ah, AR_AHB_MODE); + REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + + regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + + REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level); + + regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + + REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + + if (AR_SREV_9285(ah)) { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); + } else { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_PCU_TXBUF_CTRL_USABLE_SIZE); + } +} + +static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) +{ + u32 val; + + val = REG_READ(ah, AR_STA_ID1); + val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); + switch (opmode) { + case NL80211_IFTYPE_AP: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP + | AR_STA_ID1_KSRCH_MODE); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC + | AR_STA_ID1_KSRCH_MODE); + REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + break; + } +} + +static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, + u32 coef_scaled, + u32 *coef_mantissa, + u32 *coef_exponent) +{ + u32 coef_exp, coef_man; + + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + + coef_exp = 14 - (coef_exp - COEF_SCALE_S); + + coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); + + *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); + *coef_exponent = coef_exp - 16; +} + +static void ath9k_hw_set_delta_slope(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 coef_scaled, ds_coef_exp, ds_coef_man; + u32 clockMhzScaled = 0x64000000; + struct chan_centers centers; + + if (IS_CHAN_HALF_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 1; + else if (IS_CHAN_QUARTER_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 2; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); + + coef_scaled = (9 * coef_scaled) / 10; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); +} + +static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) +{ + u32 rst_flags; + u32 tmpReg; + + if (AR_SREV_9100(ah)) { + u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); + val &= ~AR_RTC_DERIVED_CLK_PERIOD; + val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); + REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); + (void)REG_READ(ah, AR_RTC_DERIVED_CLK); + } + + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + AR_RTC_FORCE_WAKE_ON_INT); + + if (AR_SREV_9100(ah)) { + rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | + AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; + } else { + tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (tmpReg & + (AR_INTR_SYNC_LOCAL_TIMEOUT | + AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); + } else { + REG_WRITE(ah, AR_RC, AR_RC_AHB); + } + + rst_flags = AR_RTC_RC_MAC_WARM; + if (type == ATH9K_RESET_COLD) + rst_flags |= AR_RTC_RC_MAC_COLD; + } + + REG_WRITE(ah, AR_RTC_RC, rst_flags); + udelay(50); + + REG_WRITE(ah, AR_RTC_RC, 0); + if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "RTC stuck in MAC reset\n"); + return false; + } + + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + + ath9k_hw_init_pll(ah, NULL); + + if (AR_SREV_9100(ah)) + udelay(50); + + return true; +} + +static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + AR_RTC_FORCE_WAKE_ON_INT); + + REG_WRITE(ah, AR_RTC_RESET, 0); + udelay(2); + REG_WRITE(ah, AR_RTC_RESET, 1); + + if (!ath9k_hw_wait(ah, + AR_RTC_STATUS, + AR_RTC_STATUS_M, + AR_RTC_STATUS_ON, + AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); + return false; + } + + ath9k_hw_read_revisions(ah); + + return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); +} + +static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) +{ + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + switch (type) { + case ATH9K_RESET_POWER_ON: + return ath9k_hw_set_reset_power_on(ah); + break; + case ATH9K_RESET_WARM: + case ATH9K_RESET_COLD: + return ath9k_hw_set_reset(ah, type); + break; + default: + return false; + } +} + +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) +{ + u32 phymode; + u32 enableDacFifo = 0; + + if (AR_SREV_9285_10_OR_LATER(ah)) + enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & + AR_PHY_FC_ENABLE_DAC_FIFO); + + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; + + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN; + + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; + + if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25) + phymode |= AR_PHY_FC_DYN2040_EXT_CH; + } + REG_WRITE(ah, AR_PHY_TURBO, phymode); + + ath9k_hw_set11nmac2040(ah, macmode); + + REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); + REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); +} + +static bool ath9k_hw_chip_reset(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + if (OLC_FOR_AR9280_20_LATER) { + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) + return false; + } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) + return false; + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; + + ah->chip_fullsleep = false; + ath9k_hw_init_pll(ah, chan); + ath9k_hw_set_rfmode(ah, chan); + + return true; +} + +static bool ath9k_hw_channel_change(struct ath_hw *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) +{ + struct ieee80211_channel *channel = chan->chan; + u32 synthDelay, qnum; + + for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { + if (ath9k_hw_numtxpending(ah, qnum)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "Transmit frames pending on queue %d\n", qnum); + return false; + } + } + + REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); + if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, + AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Could not kill baseband RX\n"); + return false; + } + + ath9k_hw_set_regs(ah, chan, macmode); + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Failed to set channel\n"); + return false; + } + } else { + if (!(ath9k_hw_set_channel(ah, chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Failed to set channel\n"); + return false; + } + } + + if (ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)) != 0) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Error initializing transmit power\n"); + return false; + } + + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + udelay(synthDelay + BASE_ACTIVATE_DELAY); + + REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); + + if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) + ath9k_hw_set_delta_slope(ah, chan); + + if (AR_SREV_9280_10_OR_LATER(ah)) + ath9k_hw_9280_spur_mitigate(ah, chan); + else + ath9k_hw_spur_mitigate(ah, chan); + + if (!chan->oneTimeCalsDone) + chan->oneTimeCalsDone = true; + + return true; +} + +static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + struct chan_centers centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + ah->config.spurmode = SPUR_ENABLE_EEPROM; + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + + if (is2GHz) + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + else + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(chan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + return; + } else { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + if (IS_CHAN_HT40(chan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + if (IS_CHAN_HT40(chan)) + spur_delta_phase = + ((bb_spur * 262144) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = + ((bb_spur * 524288) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp_v = abs(cur_vit_mask - bin); + + if (tmp_v < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} + +static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) + return; + + bin = bb_spur * 32; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); + + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); + + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; + + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp_v = abs(cur_vit_mask - bin); + + if (tmp_v < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} + +int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, + bool bChannelChange) +{ + u32 saveLedState; + struct ath_softc *sc = ah->ah_sc; + struct ath9k_channel *curchan = ah->curchan; + u32 saveDefAntenna; + u32 macStaId1; + int i, rx_chainmask, r; + + ah->extprotspacing = sc->ht_extprotspacing; + ah->txchainmask = sc->tx_chainmask; + ah->rxchainmask = sc->rx_chainmask; + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return -EIO; + + if (curchan) + ath9k_hw_getnf(ah, curchan); + + if (bChannelChange && + (ah->chip_fullsleep != true) && + (ah->curchan != NULL) && + (chan->channel != ah->curchan->channel) && + ((chan->channelFlags & CHANNEL_ALL) == + (ah->curchan->channelFlags & CHANNEL_ALL)) && + (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) && + !IS_CHAN_A_5MHZ_SPACED(ah->curchan)))) { + + if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) { + ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah); + return 0; + } + } + + saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA); + if (saveDefAntenna == 0) + saveDefAntenna = 1; + + macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; + + saveLedState = REG_READ(ah, AR_CFG_LED) & + (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | + AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW); + + ath9k_hw_mark_phy_inactive(ah); + + if (!ath9k_hw_chip_reset(ah, chan)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n"); + return -EINVAL; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); + + r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width); + if (r) + return r; + + /* Setup MFP options for CCMP */ + if (AR_SREV_9280_20_OR_LATER(ah)) { + /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt + * frames when constructing CCMP AAD. */ + REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, + 0xc7ff); + ah->sw_mgmt_crypto = false; + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + /* Disable hardware crypto for management frames */ + REG_CLR_BIT(ah, AR_PCU_MISC_MODE2, + AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); + REG_SET_BIT(ah, AR_PCU_MISC_MODE2, + AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); + ah->sw_mgmt_crypto = true; + } else + ah->sw_mgmt_crypto = true; + + if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) + ath9k_hw_set_delta_slope(ah, chan); + + if (AR_SREV_9280_10_OR_LATER(ah)) + ath9k_hw_9280_spur_mitigate(ah, chan); + else + ath9k_hw_spur_mitigate(ah, chan); + + ah->eep_ops->set_board_values(ah, chan); + + ath9k_hw_decrease_chain_power(ah, chan); + + REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr)); + REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4) + | macStaId1 + | AR_STA_ID1_RTS_USE_DEF + | (ah->config. + ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) + | ah->sta_id1_defaults); + ath9k_hw_set_operating_mode(ah, ah->opmode); + + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); + + REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); + + REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); + REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | + ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); + + REG_WRITE(ah, AR_ISR, ~0); + + 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))) + return -EIO; + } else { + if (!(ath9k_hw_set_channel(ah, chan))) + return -EIO; + } + + for (i = 0; i < AR_NUM_DCU; i++) + REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); + + ah->intr_txqs = 0; + for (i = 0; i < ah->caps.total_queues; i++) + ath9k_hw_resettxqueue(ah, i); + + ath9k_hw_init_interrupt_masks(ah, ah->opmode); + ath9k_hw_init_qos(ah); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + ath9k_enable_rfkill(ah); +#endif + ath9k_hw_init_user_settings(ah); + + REG_WRITE(ah, AR_STA_ID1, + REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); + + ath9k_hw_set_dma(ah); + + REG_WRITE(ah, AR_OBS, 8); + + if (ah->config.intr_mitigation) { + REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); + REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); + } + + ath9k_hw_init_bb(ah, chan); + + if (!ath9k_hw_init_cal(ah, chan)) + return -EIO;; + + rx_chainmask = ah->rxchainmask; + if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); + } + + REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ); + + if (AR_SREV_9100(ah)) { + u32 mask; + mask = REG_READ(ah, AR_CFG); + if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "CFG Byte Swap Set 0x%x\n", mask); + } else { + mask = + INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; + REG_WRITE(ah, AR_CFG, mask); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); + } + } else { +#ifdef __BIG_ENDIAN + REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); +#endif + } + + return 0; +} + +/************************/ +/* Key Cache Management */ +/************************/ + +bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) +{ + u32 keyType; + + if (entry >= ah->caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); + return false; + } + + keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); + + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); + + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; + + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); + + } + + if (ah->curchan == NULL) + return true; + + return true; +} + +bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) +{ + u32 macHi, macLo; + + if (entry >= ah->caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); + return false; + } + + if (mac != NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24) | + (mac[2] << 16) | + (mac[1] << 8) | + mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; + macHi >>= 1; + } else { + macLo = macHi = 0; + } + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); + + return true; +} + +bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac) +{ + const struct ath9k_hw_capabilities *pCap = &ah->caps; + u32 key0, key1, key2, key3, key4; + u32 keyType; + + if (entry >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keycache entry %u out of range\n", entry); + return false; + } + + switch (k->kv_type) { + case ATH9K_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case ATH9K_CIPHER_AES_CCM: + if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "AES-CCM not supported by mac rev 0x%x\n", + ah->hw_version.macRev); + return false; + } + keyType = AR_KEYTABLE_TYPE_CCM; + break; + case ATH9K_CIPHER_TKIP: + keyType = AR_KEYTABLE_TYPE_TKIP; + if (ATH9K_IS_MIC_ENABLED(ah) + && entry + 64 >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "entry %u inappropriate for TKIP\n", entry); + return false; + } + break; + case ATH9K_CIPHER_WEP: + if (k->kv_len < LEN_WEP40) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "WEP key length %u too small\n", k->kv_len); + return false; + } + if (k->kv_len <= LEN_WEP40) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= LEN_WEP104) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + break; + case ATH9K_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "cipher %u not supported\n", k->kv_type); + return false; + } + + key0 = get_unaligned_le32(k->kv_val + 0); + key1 = get_unaligned_le16(k->kv_val + 4); + key2 = get_unaligned_le32(k->kv_val + 6); + key3 = get_unaligned_le16(k->kv_val + 10); + key4 = get_unaligned_le32(k->kv_val + 12); + if (k->kv_len <= LEN_WEP104) + key4 &= 0xff; + + /* + * Note: Key cache registers access special memory area that requires + * two 32-bit writes to actually update the values in the internal + * memory. Consequently, the exact order and pairs used here must be + * maintained. + */ + + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; + + /* + * Write inverted key[47:0] first to avoid Michael MIC errors + * on frames that could be sent or received at the same time. + * The correct key will be written in the end once everything + * else is ready. + */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); + + /* Write key[95:48] */ + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + + /* Write key[127:96] and key type */ + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + + /* Write MAC address for the entry */ + (void) ath9k_hw_keysetmac(ah, entry, mac); + + if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) { + /* + * TKIP uses two key cache entries: + * Michael MIC TX/RX keys in the same key cache entry + * (idx = main index + 64): + * key0 [31:0] = RX key [31:0] + * key1 [15:0] = TX key [31:16] + * key1 [31:16] = reserved + * key2 [31:0] = RX key [63:32] + * key3 [15:0] = TX key [15:0] + * key3 [31:16] = reserved + * key4 [31:0] = TX key [63:32] + */ + u32 mic0, mic1, mic2, mic3, mic4; + + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; + mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; + mic4 = get_unaligned_le32(k->kv_txmic + 4); + + /* Write RX[31:0] and TX[31:16] */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); + + /* Write RX[63:32] and TX[15:0] */ + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); + + /* Write TX[63:32] and keyType(reserved) */ + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + + } else { + /* + * TKIP uses four key cache entries (two for group + * keys): + * Michael MIC TX/RX keys are in different key cache + * entries (idx = main index + 64 for TX and + * main index + 32 + 96 for RX): + * key0 [31:0] = TX/RX MIC key [31:0] + * key1 [31:0] = reserved + * key2 [31:0] = TX/RX MIC key [63:32] + * key3 [31:0] = reserved + * key4 [31:0] = reserved + * + * Upper layer code will call this function separately + * for TX and RX keys when these registers offsets are + * used. + */ + u32 mic0, mic2; + + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + + /* Write MIC key[31:0] */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + + /* Write MIC key[63:32] */ + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); + + /* Write TX[63:32] and keyType(reserved) */ + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + } + + /* MAC address registers are reserved for the MIC entry */ + REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); + + /* + * Write the correct (un-inverted) key[47:0] last to enable + * TKIP now that all other registers are set with correct + * values. + */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + } else { + /* Write key[47:0] */ + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + + /* Write key[95:48] */ + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + + /* Write key[127:96] and key type */ + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + + /* Write MAC address for the entry */ + (void) ath9k_hw_keysetmac(ah, entry, mac); + } + + return true; +} + +bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry) +{ + if (entry < ah->caps.keycache_size) { + u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return true; + } + return false; +} + +/******************************/ +/* Power Management (Chipset) */ +/******************************/ + +static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) +{ + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); + + REG_CLR_BIT(ah, (AR_RTC_RESET), + AR_RTC_RESET_EN); + } +} + +static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) +{ + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + struct ath9k_hw_capabilities *pCap = &ah->caps; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_ON_INT); + } else { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + } + } +} + +static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) +{ + u32 val; + int i; + + if (setChip) { + if ((REG_READ(ah, AR_RTC_STATUS) & + AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { + if (ath9k_hw_set_reset_reg(ah, + ATH9K_RESET_POWER_ON) != true) { + return false; + } + } + if (AR_SREV_9100(ah)) + REG_SET_BIT(ah, AR_RTC_RESET, + AR_RTC_RESET_EN); + + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + udelay(50); + + for (i = POWER_UP_TIME / 50; i > 0; i--) { + val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; + if (val == AR_RTC_STATUS_ON) + break; + udelay(50); + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + } + if (i == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); + return false; + } + } + + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + + return true; +} + +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) +{ + int status = true, setChip = true; + static const char *modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; + + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", + modes[ah->power_mode], modes[mode]); + + switch (mode) { + case ATH9K_PM_AWAKE: + status = ath9k_hw_set_power_awake(ah, setChip); + break; + case ATH9K_PM_FULL_SLEEP: + ath9k_set_power_sleep(ah, setChip); + ah->chip_fullsleep = true; + break; + case ATH9K_PM_NETWORK_SLEEP: + ath9k_set_power_network_sleep(ah, setChip); + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Unknown power mode %u\n", mode); + return false; + } + ah->power_mode = mode; + + return status; +} + +/* + * Helper for ASPM support. + * + * Disable PLL when in L0s as well as receiver clock when in L1. + * This power saving option must be enabled through the SerDes. + * + * Programming the SerDes must go through the same 288 bit serial shift + * register as the other analog registers. Hence the 9 writes. + */ +void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) +{ + u8 i; + + if (ah->is_pciexpress != true) + return; + + /* Do not touch SerDes registers */ + if (ah->config.pcie_powersave_enable == 2) + return; + + /* Nothing to do on restore for 11N */ + if (restore) + return; + + if (AR_SREV_9280_20_OR_LATER(ah)) { + /* + * AR9280 2.0 or later chips use SerDes values from the + * initvals.h initialized depending on chipset during + * ath9k_hw_do_attach() + */ + for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { + REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), + INI_RA(&ah->iniPcieSerdes, i, 1)); + } + } else if (AR_SREV_9280(ah) && + (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + /* RX shut off when elecidle is asserted */ + REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); + REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); + + /* Shut off CLKREQ active in L1 */ + if (ah->config.pcie_clock_req) + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); + else + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); + + /* Load the new settings */ + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + + } else { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + /* RX shut off when elecidle is asserted */ + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); + REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); + + /* + * Ignore ah->ah_config.pcie_clock_req setting for + * pre-AR9280 11n + */ + REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); + + /* Load the new settings */ + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + } + + udelay(1000); + + /* set bit 19 to allow forcing of pcie core into L1 state */ + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + + /* Several PCIe massages to ensure proper behaviour */ + if (ah->config.pcie_waen) { + REG_WRITE(ah, AR_WA, ah->config.pcie_waen); + } else { + if (AR_SREV_9285(ah)) + REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); + /* + * On AR9280 chips bit 22 of 0x4004 needs to be set to + * otherwise card may disappear. + */ + else if (AR_SREV_9280(ah)) + REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT); + else + REG_WRITE(ah, AR_WA, AR_WA_DEFAULT); + } +} + +/**********************/ +/* Interrupt Handling */ +/**********************/ + +bool ath9k_hw_intrpend(struct ath_hw *ah) +{ + u32 host_isr; + + if (AR_SREV_9100(ah)) + return true; + + host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); + if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS)) + return true; + + host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); + if ((host_isr & AR_INTR_SYNC_DEFAULT) + && (host_isr != AR_INTR_SPURIOUS)) + return true; + + return false; +} + +bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) +{ + u32 isr = 0; + u32 mask2 = 0; + struct ath9k_hw_capabilities *pCap = &ah->caps; + u32 sync_cause = 0; + bool fatal_int = false; + + if (!AR_SREV_9100(ah)) { + if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { + if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) + == AR_RTC_STATUS_ON) { + isr = REG_READ(ah, AR_ISR); + } + } + + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & + AR_INTR_SYNC_DEFAULT; + + *masked = 0; + + if (!isr && !sync_cause) + return false; + } else { + *masked = 0; + isr = REG_READ(ah, AR_ISR); + } + + if (isr) { + if (isr & AR_ISR_BCNMISC) { + u32 isr2; + isr2 = REG_READ(ah, AR_ISR_S2); + if (isr2 & AR_ISR_S2_TIM) + mask2 |= ATH9K_INT_TIM; + if (isr2 & AR_ISR_S2_DTIM) + mask2 |= ATH9K_INT_DTIM; + if (isr2 & AR_ISR_S2_DTIMSYNC) + mask2 |= ATH9K_INT_DTIMSYNC; + if (isr2 & (AR_ISR_S2_CABEND)) + mask2 |= ATH9K_INT_CABEND; + if (isr2 & AR_ISR_S2_GTT) + mask2 |= ATH9K_INT_GTT; + if (isr2 & AR_ISR_S2_CST) + mask2 |= ATH9K_INT_CST; + if (isr2 & AR_ISR_S2_TSFOOR) + mask2 |= ATH9K_INT_TSFOOR; + } + + isr = REG_READ(ah, AR_ISR_RAC); + if (isr == 0xffffffff) { + *masked = 0; + return false; + } + + *masked = isr & ATH9K_INT_COMMON; + + if (ah->config.intr_mitigation) { + if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) + *masked |= ATH9K_INT_RX; + } + + if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) + *masked |= ATH9K_INT_RX; + if (isr & + (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | + AR_ISR_TXEOL)) { + u32 s0_s, s1_s; + + *masked |= ATH9K_INT_TX; + + s0_s = REG_READ(ah, AR_ISR_S0_S); + ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); + ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); + + s1_s = REG_READ(ah, AR_ISR_S1_S); + ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); + ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); + } + + if (isr & AR_ISR_RXORN) { + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + "receive FIFO overrun interrupt\n"); + } + + if (!AR_SREV_9100(ah)) { + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + u32 isr5 = REG_READ(ah, AR_ISR_S5_S); + if (isr5 & AR_ISR_S5_TIM_TIMER) + *masked |= ATH9K_INT_TIM_TIMER; + } + } + + *masked |= mask2; + } + + if (AR_SREV_9100(ah)) + return true; + + if (sync_cause) { + fatal_int = + (sync_cause & + (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) + ? true : false; + + if (fatal_int) { + if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "received PCI FATAL interrupt\n"); + } + if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "received PCI PERR interrupt\n"); + } + } + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); + REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); + REG_WRITE(ah, AR_RC, 0); + *masked |= ATH9K_INT_FATAL; + } + if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); + } + + REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); + (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); + } + + return true; +} + +enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah) +{ + return ah->mask_reg; +} + +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) +{ + u32 omask = ah->mask_reg; + u32 mask, mask2; + struct ath9k_hw_capabilities *pCap = &ah->caps; + + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); + + if (omask & ATH9K_INT_GLOBAL) { + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n"); + REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + (void) REG_READ(ah, AR_IER); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); + (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); + + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); + } + } + + mask = ints & ATH9K_INT_COMMON; + mask2 = 0; + + if (ints & ATH9K_INT_TX) { + if (ah->txok_interrupt_mask) + mask |= AR_IMR_TXOK; + if (ah->txdesc_interrupt_mask) + mask |= AR_IMR_TXDESC; + if (ah->txerr_interrupt_mask) + mask |= AR_IMR_TXERR; + if (ah->txeol_interrupt_mask) + mask |= AR_IMR_TXEOL; + } + if (ints & ATH9K_INT_RX) { + mask |= AR_IMR_RXERR; + if (ah->config.intr_mitigation) + mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; + else + mask |= AR_IMR_RXOK | AR_IMR_RXDESC; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + mask |= AR_IMR_GENTMR; + } + + if (ints & (ATH9K_INT_BMISC)) { + mask |= AR_IMR_BCNMISC; + if (ints & ATH9K_INT_TIM) + mask2 |= AR_IMR_S2_TIM; + if (ints & ATH9K_INT_DTIM) + mask2 |= AR_IMR_S2_DTIM; + if (ints & ATH9K_INT_DTIMSYNC) + mask2 |= AR_IMR_S2_DTIMSYNC; + if (ints & ATH9K_INT_CABEND) + mask2 |= AR_IMR_S2_CABEND; + if (ints & ATH9K_INT_TSFOOR) + mask2 |= AR_IMR_S2_TSFOOR; + } + + if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { + mask |= AR_IMR_BCNMISC; + if (ints & ATH9K_INT_GTT) + mask2 |= AR_IMR_S2_GTT; + if (ints & ATH9K_INT_CST) + mask2 |= AR_IMR_S2_CST; + } + + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); + REG_WRITE(ah, AR_IMR, mask); + mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | + AR_IMR_S2_DTIM | + AR_IMR_S2_DTIMSYNC | + AR_IMR_S2_CABEND | + AR_IMR_S2_CABTO | + AR_IMR_S2_TSFOOR | + AR_IMR_S2_GTT | AR_IMR_S2_CST); + REG_WRITE(ah, AR_IMR_S2, mask | mask2); + ah->mask_reg = ints; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + if (ints & ATH9K_INT_TIM_TIMER) + REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); + else + REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); + } + + if (ints & ATH9K_INT_GLOBAL) { + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n"); + REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, + AR_INTR_MAC_IRQ); + REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); + + + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, + AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_MASK, + AR_INTR_SYNC_DEFAULT); + } + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); + } + + return omask; +} + +/*******************/ +/* Beacon Handling */ +/*******************/ + +void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) +{ + int flags = 0; + + ah->beacon_interval = beacon_period; + + switch (ah->opmode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); + REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff); + REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff); + flags |= AR_TBTT_TIMER_EN; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + REG_SET_BIT(ah, AR_TXCFG, + AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); + REG_WRITE(ah, AR_NEXT_NDP_TIMER, + TU_TO_USEC(next_beacon + + (ah->atim_window ? ah-> + atim_window : 1))); + flags |= AR_NDP_TIMER_EN; + case NL80211_IFTYPE_AP: + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); + REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, + TU_TO_USEC(next_beacon - + ah->config. + dma_beacon_response_time)); + REG_WRITE(ah, AR_NEXT_SWBA, + TU_TO_USEC(next_beacon - + ah->config. + sw_beacon_response_time)); + flags |= + AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, + "%s: unsupported opmode: %d\n", + __func__, ah->opmode); + return; + break; + } + + REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); + REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period)); + REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); + REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); + + beacon_period &= ~ATH9K_BEACON_ENA; + if (beacon_period & ATH9K_BEACON_RESET_TSF) { + beacon_period &= ~ATH9K_BEACON_RESET_TSF; + ath9k_hw_reset_tsf(ah); + } + + REG_SET_BIT(ah, AR_TIMER_MODE, flags); +} + +void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, + const struct ath9k_beacon_state *bs) +{ + u32 nextTbtt, beaconintval, dtimperiod, beacontimeout; + struct ath9k_hw_capabilities *pCap = &ah->caps; + + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); + + REG_WRITE(ah, AR_BEACON_PERIOD, + TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); + REG_WRITE(ah, AR_DMA_BEACON_PERIOD, + TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); + + REG_RMW_FIELD(ah, AR_RSSI_THR, + AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); + + beaconintval = bs->bs_intval & ATH9K_BEACON_PERIOD; + + if (bs->bs_sleepduration > beaconintval) + beaconintval = bs->bs_sleepduration; + + dtimperiod = bs->bs_dtimperiod; + if (bs->bs_sleepduration > dtimperiod) + dtimperiod = bs->bs_sleepduration; + + if (beaconintval == dtimperiod) + nextTbtt = bs->bs_nextdtim; + else + nextTbtt = bs->bs_nexttbtt; + + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); + + REG_WRITE(ah, AR_NEXT_DTIM, + TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); + REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); + + REG_WRITE(ah, AR_SLEEP1, + SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) + | AR_SLEEP1_ASSUME_DTIM); + + if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) + beacontimeout = (BEACON_TIMEOUT_VAL << 3); + else + beacontimeout = MIN_BEACON_TIMEOUT_VAL; + + REG_WRITE(ah, AR_SLEEP2, + SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); + + REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); + REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); + + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | + AR_DTIM_TIMER_EN); + + /* TSF Out of Range Threshold */ + REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); +} + +/*******************/ +/* HW Capabilities */ +/*******************/ + +void ath9k_hw_fill_cap_info(struct ath_hw *ah) +{ + struct ath9k_hw_capabilities *pCap = &ah->caps; + u16 capField = 0, eeval; + + eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); + ah->regulatory.current_rd = eeval; + + eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); + if (AR_SREV_9285_10_OR_LATER(ah)) + eeval |= AR9285_RDEXT_DEFAULT; + ah->regulatory.current_rd_ext = eeval; + + capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); + + if (ah->opmode != NL80211_IFTYPE_AP && + ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { + if (ah->regulatory.current_rd == 0x64 || + ah->regulatory.current_rd == 0x65) + ah->regulatory.current_rd += 5; + else if (ah->regulatory.current_rd == 0x41) + ah->regulatory.current_rd = 0x43; + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, + "regdomain mapped to 0x%x\n", ah->regulatory.current_rd); + } + + eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); + bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); + + if (eeval & AR5416_OPFLAGS_11A) { + set_bit(ATH9K_MODE_11A, pCap->wireless_modes); + if (ah->config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) + set_bit(ATH9K_MODE_11NA_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { + set_bit(ATH9K_MODE_11NA_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NA_HT40MINUS, + pCap->wireless_modes); + } + } + } + + if (eeval & AR5416_OPFLAGS_11G) { + set_bit(ATH9K_MODE_11B, pCap->wireless_modes); + set_bit(ATH9K_MODE_11G, pCap->wireless_modes); + if (ah->config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) + set_bit(ATH9K_MODE_11NG_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { + set_bit(ATH9K_MODE_11NG_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NG_HT40MINUS, + pCap->wireless_modes); + } + } + } + + pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); + if ((ah->hw_version.devid == AR5416_DEVID_PCI) && + !(eeval & AR5416_OPFLAGS_11A)) + pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; + else + pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); + + if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) + ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; + + pCap->low_2ghz_chan = 2312; + pCap->high_2ghz_chan = 2732; + + pCap->low_5ghz_chan = 4920; + pCap->high_5ghz_chan = 6100; + + pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; + + pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; + + if (ah->config.ht_enable) + pCap->hw_caps |= ATH9K_HW_CAP_HT; + else + pCap->hw_caps &= ~ATH9K_HW_CAP_HT; + + pCap->hw_caps |= ATH9K_HW_CAP_GTT; + pCap->hw_caps |= ATH9K_HW_CAP_VEOL; + pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; + pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; + + if (capField & AR_EEPROM_EEPCAP_MAXQCU) + pCap->total_queues = + MS(capField, AR_EEPROM_EEPCAP_MAXQCU); + else + pCap->total_queues = ATH9K_NUM_TX_QUEUES; + + if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) + pCap->keycache_size = + 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); + else + pCap->keycache_size = AR_KEYTABLE_SIZE; + + pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; + + if (AR_SREV_9285_10_OR_LATER(ah)) + pCap->num_gpio_pins = AR9285_NUM_GPIO; + else if (AR_SREV_9280_10_OR_LATER(ah)) + pCap->num_gpio_pins = AR928X_NUM_GPIO; + else + pCap->num_gpio_pins = AR_NUM_GPIO; + + if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_CST; + pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; + } else { + pCap->rts_aggr_limit = (8 * 1024); + } + + pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); + if (ah->rfsilent & EEP_RFSILENT_ENABLED) { + ah->rfkill_gpio = + MS(ah->rfsilent, EEP_RFSILENT_GPIO_SEL); + ah->rfkill_polarity = + MS(ah->rfsilent, EEP_RFSILENT_POLARITY); + + pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; + } +#endif + + if ((ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || + (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9160) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9100) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9280)) + pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; + else + pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; + + if (AR_SREV_9280(ah) || AR_SREV_9285(ah)) + pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; + else + pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; + + if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | + AR_EEPROM_EEREGCAP_EN_KK_U2 | + AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; + } else { + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; + } + + pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; + + pCap->num_antcfg_5ghz = + ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); + pCap->num_antcfg_2ghz = + ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); + + if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { + pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; + ah->btactive_gpio = 6; + ah->wlanactive_gpio = 5; + } +} + +bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, + u32 capability, u32 *result) +{ + switch (type) { + case ATH9K_CAP_CIPHER: + switch (capability) { + case ATH9K_CIPHER_AES_CCM: + case ATH9K_CIPHER_AES_OCB: + case ATH9K_CIPHER_TKIP: + case ATH9K_CIPHER_WEP: + case ATH9K_CIPHER_MIC: + case ATH9K_CIPHER_CLR: + return true; + default: + return false; + } + case ATH9K_CAP_TKIP_MIC: + switch (capability) { + case 0: + return true; + case 1: + return (ah->sta_id1_defaults & + AR_STA_ID1_CRPT_MIC_ENABLE) ? true : + false; + } + case ATH9K_CAP_TKIP_SPLIT: + return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ? + false : true; + case ATH9K_CAP_DIVERSITY: + return (REG_READ(ah, AR_PHY_CCK_DETECT) & + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? + true : false; + case ATH9K_CAP_MCAST_KEYSRCH: + switch (capability) { + case 0: + return true; + case 1: + if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { + return false; + } else { + return (ah->sta_id1_defaults & + AR_STA_ID1_MCAST_KSRCH) ? true : + false; + } + } + return false; + case ATH9K_CAP_TXPOW: + switch (capability) { + case 0: + return 0; + case 1: + *result = ah->regulatory.power_limit; + return 0; + case 2: + *result = ah->regulatory.max_power_level; + return 0; + case 3: + *result = ah->regulatory.tp_scale; + return 0; + } + return false; + case ATH9K_CAP_DS: + return (AR_SREV_9280_20_OR_LATER(ah) && + (ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1)) + ? false : true; + default: + return false; + } +} + +bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status) +{ + u32 v; + + switch (type) { + case ATH9K_CAP_TKIP_MIC: + if (setting) + ah->sta_id1_defaults |= + AR_STA_ID1_CRPT_MIC_ENABLE; + else + ah->sta_id1_defaults &= + ~AR_STA_ID1_CRPT_MIC_ENABLE; + return true; + case ATH9K_CAP_DIVERSITY: + v = REG_READ(ah, AR_PHY_CCK_DETECT); + if (setting) + v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + else + v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + REG_WRITE(ah, AR_PHY_CCK_DETECT, v); + return true; + case ATH9K_CAP_MCAST_KEYSRCH: + if (setting) + ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH; + else + ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH; + return true; + default: + return false; + } +} + +/****************************/ +/* GPIO / RFKILL / Antennae */ +/****************************/ + +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, + u32 gpio, u32 type) +{ + int addr; + u32 gpio_shift, tmp; + + if (gpio > 11) + addr = AR_GPIO_OUTPUT_MUX3; + else if (gpio > 5) + addr = AR_GPIO_OUTPUT_MUX2; + else + addr = AR_GPIO_OUTPUT_MUX1; + + gpio_shift = (gpio % 6) * 5; + + if (AR_SREV_9280_20_OR_LATER(ah) + || (addr != AR_GPIO_OUTPUT_MUX1)) { + REG_RMW(ah, addr, (type << gpio_shift), + (0x1f << gpio_shift)); + } else { + tmp = REG_READ(ah, addr); + tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); + tmp &= ~(0x1f << gpio_shift); + tmp |= (type << gpio_shift); + REG_WRITE(ah, addr, tmp); + } +} + +void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio) +{ + u32 gpio_shift; + + ASSERT(gpio < 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)); +} + +u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) +{ +#define MS_REG_READ(x, y) \ + (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y))) + + if (gpio >= ah->caps.num_gpio_pins) + return 0xffffffff; + + if (AR_SREV_9285_10_OR_LATER(ah)) + return MS_REG_READ(AR9285, gpio) != 0; + else if (AR_SREV_9280_10_OR_LATER(ah)) + return MS_REG_READ(AR928X, gpio) != 0; + else + return MS_REG_READ(AR, gpio) != 0; +} + +void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, + u32 ah_signal_type) +{ + u32 gpio_shift; + + ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); + + gpio_shift = 2 * gpio; + + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); +} + +void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) +{ + REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), + AR_GPIO_BIT(gpio)); +} + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hw *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->rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); +} +#endif + +u32 ath9k_hw_getdefantenna(struct ath_hw *ah) +{ + return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; +} + +void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) +{ + REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); +} + +bool ath9k_hw_setantennaswitch(struct ath_hw *ah, + enum ath9k_ant_setting settings, + struct ath9k_channel *chan, + u8 *tx_chainmask, + u8 *rx_chainmask, + u8 *antenna_cfgd) +{ + static u8 tx_chainmask_cfg, rx_chainmask_cfg; + + if (AR_SREV_9280(ah)) { + if (!tx_chainmask_cfg) { + + tx_chainmask_cfg = *tx_chainmask; + rx_chainmask_cfg = *rx_chainmask; + } + + switch (settings) { + case ATH9K_ANT_FIXED_A: + *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_FIXED_B: + if (ah->caps.tx_chainmask > + ATH9K_ANTENNA1_CHAINMASK) { + *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + } + *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_VARIABLE: + *tx_chainmask = tx_chainmask_cfg; + *rx_chainmask = rx_chainmask_cfg; + *antenna_cfgd = true; + break; + default: + break; + } + } else { + ah->diversity_control = settings; + } + + return true; +} + +/*********************/ +/* General Operation */ +/*********************/ + +u32 ath9k_hw_getrxfilter(struct ath_hw *ah) +{ + u32 bits = REG_READ(ah, AR_RX_FILTER); + u32 phybits = REG_READ(ah, AR_PHY_ERR); + + if (phybits & AR_PHY_ERR_RADAR) + bits |= ATH9K_RX_FILTER_PHYRADAR; + if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) + bits |= ATH9K_RX_FILTER_PHYERR; + + return bits; +} + +void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) +{ + u32 phybits; + + REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); + phybits = 0; + if (bits & ATH9K_RX_FILTER_PHYRADAR) + phybits |= AR_PHY_ERR_RADAR; + if (bits & ATH9K_RX_FILTER_PHYERR) + phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; + REG_WRITE(ah, AR_PHY_ERR, phybits); + + if (phybits) + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + else + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); +} + +bool ath9k_hw_phy_disable(struct ath_hw *ah) +{ + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); +} + +bool ath9k_hw_disable(struct ath_hw *ah) +{ + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; + + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); +} + +bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) +{ + struct ath9k_channel *chan = ah->curchan; + struct ieee80211_channel *channel = chan->chan; + + ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); + + if (ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)) != 0) + return false; + + return true; +} + +void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) +{ + memcpy(ah->macaddr, mac, ETH_ALEN); +} + +void ath9k_hw_setopmode(struct ath_hw *ah) +{ + ath9k_hw_set_operating_mode(ah, ah->opmode); +} + +void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) +{ + REG_WRITE(ah, AR_MCAST_FIL0, filter0); + REG_WRITE(ah, AR_MCAST_FIL1, filter1); +} + +void ath9k_hw_setbssidmask(struct ath_softc *sc) +{ + REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); + REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); +} + +void ath9k_hw_write_associd(struct ath_softc *sc) +{ + REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); + REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | + ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); +} + +u64 ath9k_hw_gettsf64(struct ath_hw *ah) +{ + u64 tsf; + + tsf = REG_READ(ah, AR_TSF_U32); + tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); + + return tsf; +} + +void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64) +{ + REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); + REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); +} + +void ath9k_hw_reset_tsf(struct ath_hw *ah) +{ + int count; + + count = 0; + while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { + count++; + if (count > 10) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); + break; + } + udelay(10); + } + REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); +} + +bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) +{ + if (setting) + ah->misc_mode |= AR_PCU_TX_ADD_TSF; + else + ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; + + return true; +} + +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) +{ + if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us); + ah->slottime = (u32) -1; + return false; + } else { + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); + ah->slottime = us; + return true; + } +} + +void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) +{ + u32 macmode; + + if (mode == ATH9K_HT_MACMODE_2040 && + !ah->config.cwm_ignore_extcca) + macmode = AR_2040_JOINED_RX_CLEAR; + else + macmode = 0; + + REG_WRITE(ah, AR_2040_MODE, macmode); +} + +/***************************/ +/* Bluetooth Coexistence */ +/***************************/ + +void ath9k_hw_btcoex_enable(struct ath_hw *ah) +{ + /* connect bt_active to baseband */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | + AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + + /* Set input mux for bt_active to gpio pin */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + ah->btactive_gpio); + + /* Configure the desired gpio port for input */ + ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); + + /* Configure the desired GPIO port for TX_FRAME output */ + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); +} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h new file mode 100644 index 0000000..5c4127e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef HW_H +#define HW_H + +#include +#include +#include + +#include "mac.h" +#include "ani.h" +#include "eeprom.h" +#include "calib.h" +#include "reg.h" +#include "phy.h" + +#include "../regd.h" + +#define ATHEROS_VENDOR_ID 0x168c +#define AR5416_DEVID_PCI 0x0023 +#define AR5416_DEVID_PCIE 0x0024 +#define AR9160_DEVID_PCI 0x0027 +#define AR9280_DEVID_PCI 0x0029 +#define AR9280_DEVID_PCIE 0x002a +#define AR9285_DEVID_PCIE 0x002b +#define AR5416_AR9100_DEVID 0x000b +#define AR_SUBVENDOR_ID_NOG 0x0e11 +#define AR_SUBVENDOR_ID_NEW_A 0x7065 +#define AR5416_MAGIC 0x19641014 + +/* Register read/write primitives */ +#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) +#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) + +#define SM(_v, _f) (((_v) << _f##_S) & _f) +#define MS(_v, _f) (((_v) & _f) >> _f##_S) +#define REG_RMW(_a, _r, _set, _clr) \ + REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) +#define REG_RMW_FIELD(_a, _r, _f, _v) \ + REG_WRITE(_a, _r, \ + (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) +#define REG_SET_BIT(_a, _r, _f) \ + REG_WRITE(_a, _r, REG_READ(_a, _r) | _f) +#define REG_CLR_BIT(_a, _r, _f) \ + REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) + +#define DO_DELAY(x) do { \ + if ((++(x) % 64) == 0) \ + udelay(1); \ + } while (0) + +#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ + int r; \ + for (r = 0; r < ((iniarray)->ia_rows); r++) { \ + REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ + INI_RA((iniarray), r, (column))); \ + DO_DELAY(regWr); \ + } \ + } while (0) + +#define 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_TX_FRAME 3 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 + +#define AR_GPIOD_MASK 0x00001FFF +#define AR_GPIO_BIT(_gpio) (1 << (_gpio)) + +#define BASE_ACTIVATE_DELAY 100 +#define RTC_PLL_SETTLE_DELAY 1000 +#define COEF_SCALE_S 24 +#define HT40_CHANNEL_CENTER_SHIFT 10 + +#define ATH9K_ANTENNA0_CHAINMASK 0x1 +#define ATH9K_ANTENNA1_CHAINMASK 0x2 + +#define ATH9K_NUM_DMA_DEBUG_REGS 8 +#define ATH9K_NUM_QUEUES 10 + +#define MAX_RATE_POWER 63 +#define AH_WAIT_TIMEOUT 100000 /* (us) */ +#define AH_TIME_QUANTUM 10 +#define AR_KEYTABLE_SIZE 128 +#define POWER_UP_TIME 200000 +#define SPUR_RSSI_THRESH 40 + +#define CAB_TIMEOUT_VAL 10 +#define BEACON_TIMEOUT_VAL 10 +#define MIN_BEACON_TIMEOUT_VAL 1 +#define SLEEP_SLOP 3 + +#define INIT_CONFIG_STATUS 0x00000000 +#define INIT_RSSI_THR 0x00000700 +#define INIT_BCON_CNTRL_REG 0x00000000 + +#define TU_TO_USEC(_tu) ((_tu) << 10) + +enum wireless_mode { + ATH9K_MODE_11A = 0, + ATH9K_MODE_11B = 2, + ATH9K_MODE_11G = 3, + ATH9K_MODE_11NA_HT20 = 6, + ATH9K_MODE_11NG_HT20 = 7, + ATH9K_MODE_11NA_HT40PLUS = 8, + ATH9K_MODE_11NA_HT40MINUS = 9, + ATH9K_MODE_11NG_HT40PLUS = 10, + ATH9K_MODE_11NG_HT40MINUS = 11, + ATH9K_MODE_MAX +}; + +enum ath9k_hw_caps { + ATH9K_HW_CAP_MIC_AESCCM = BIT(0), + ATH9K_HW_CAP_MIC_CKIP = BIT(1), + ATH9K_HW_CAP_MIC_TKIP = BIT(2), + ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3), + ATH9K_HW_CAP_CIPHER_CKIP = BIT(4), + ATH9K_HW_CAP_CIPHER_TKIP = BIT(5), + ATH9K_HW_CAP_VEOL = BIT(6), + ATH9K_HW_CAP_BSSIDMASK = BIT(7), + ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8), + ATH9K_HW_CAP_HT = BIT(9), + ATH9K_HW_CAP_GTT = BIT(10), + ATH9K_HW_CAP_FASTCC = BIT(11), + ATH9K_HW_CAP_RFSILENT = BIT(12), + ATH9K_HW_CAP_CST = BIT(13), + ATH9K_HW_CAP_ENHANCEDPM = BIT(14), + ATH9K_HW_CAP_AUTOSLEEP = BIT(15), + ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16), + ATH9K_HW_CAP_BT_COEX = BIT(17) +}; + +enum ath9k_capability_type { + ATH9K_CAP_CIPHER = 0, + ATH9K_CAP_TKIP_MIC, + ATH9K_CAP_TKIP_SPLIT, + ATH9K_CAP_DIVERSITY, + ATH9K_CAP_TXPOW, + ATH9K_CAP_MCAST_KEYSRCH, + ATH9K_CAP_DS +}; + +struct ath9k_hw_capabilities { + u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ + DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */ + u16 total_queues; + u16 keycache_size; + u16 low_5ghz_chan, high_5ghz_chan; + u16 low_2ghz_chan, high_2ghz_chan; + u16 rts_aggr_limit; + u8 tx_chainmask; + u8 rx_chainmask; + u16 tx_triglevel_max; + u16 reg_cap; + u8 num_gpio_pins; + u8 num_antcfg_2ghz; + u8 num_antcfg_5ghz; +}; + +struct ath9k_ops_config { + int dma_beacon_response_time; + int sw_beacon_response_time; + int additional_swba_backoff; + int ack_6mb; + int cwm_ignore_extcca; + u8 pcie_powersave_enable; + u8 pcie_clock_req; + u32 pcie_waen; + u8 analog_shiftreg; + u8 ht_enable; + u32 ofdm_trig_low; + u32 ofdm_trig_high; + u32 cck_trig_high; + u32 cck_trig_low; + u32 enable_ani; + u16 diversity_control; + u16 antenna_switch_swap; + int serialize_regmode; + bool intr_mitigation; +#define SPUR_DISABLE 0 +#define SPUR_ENABLE_IOCTL 1 +#define SPUR_ENABLE_EEPROM 2 +#define AR_EEPROM_MODAL_SPURS 5 +#define AR_SPUR_5413_1 1640 +#define AR_SPUR_5413_2 1200 +#define AR_NO_SPUR 0x8000 +#define AR_BASE_FREQ_2GHZ 2300 +#define AR_BASE_FREQ_5GHZ 4900 +#define AR_SPUR_FEEQ_BOUND_HT40 19 +#define AR_SPUR_FEEQ_BOUND_HT20 10 + int spurmode; + u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; +}; + +enum ath9k_int { + ATH9K_INT_RX = 0x00000001, + ATH9K_INT_RXDESC = 0x00000002, + ATH9K_INT_RXNOFRM = 0x00000008, + ATH9K_INT_RXEOL = 0x00000010, + ATH9K_INT_RXORN = 0x00000020, + ATH9K_INT_TX = 0x00000040, + ATH9K_INT_TXDESC = 0x00000080, + ATH9K_INT_TIM_TIMER = 0x00000100, + ATH9K_INT_TXURN = 0x00000800, + ATH9K_INT_MIB = 0x00001000, + ATH9K_INT_RXPHY = 0x00004000, + ATH9K_INT_RXKCM = 0x00008000, + ATH9K_INT_SWBA = 0x00010000, + ATH9K_INT_BMISS = 0x00040000, + ATH9K_INT_BNR = 0x00100000, + ATH9K_INT_TIM = 0x00200000, + ATH9K_INT_DTIM = 0x00400000, + ATH9K_INT_DTIMSYNC = 0x00800000, + ATH9K_INT_GPIO = 0x01000000, + ATH9K_INT_CABEND = 0x02000000, + ATH9K_INT_TSFOOR = 0x04000000, + ATH9K_INT_CST = 0x10000000, + ATH9K_INT_GTT = 0x20000000, + ATH9K_INT_FATAL = 0x40000000, + ATH9K_INT_GLOBAL = 0x80000000, + ATH9K_INT_BMISC = ATH9K_INT_TIM | + ATH9K_INT_DTIM | + ATH9K_INT_DTIMSYNC | + ATH9K_INT_TSFOOR | + ATH9K_INT_CABEND, + ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM | + ATH9K_INT_RXDESC | + ATH9K_INT_RXEOL | + ATH9K_INT_RXORN | + ATH9K_INT_TXURN | + ATH9K_INT_TXDESC | + ATH9K_INT_MIB | + ATH9K_INT_RXPHY | + ATH9K_INT_RXKCM | + ATH9K_INT_SWBA | + ATH9K_INT_BMISS | + ATH9K_INT_GPIO, + ATH9K_INT_NOCARD = 0xffffffff +}; + +#define CHANNEL_CW_INT 0x00002 +#define CHANNEL_CCK 0x00020 +#define CHANNEL_OFDM 0x00040 +#define CHANNEL_2GHZ 0x00080 +#define CHANNEL_5GHZ 0x00100 +#define CHANNEL_PASSIVE 0x00200 +#define CHANNEL_DYN 0x00400 +#define CHANNEL_HALF 0x04000 +#define CHANNEL_QUARTER 0x08000 +#define CHANNEL_HT20 0x10000 +#define CHANNEL_HT40PLUS 0x20000 +#define CHANNEL_HT40MINUS 0x40000 + +#define CHANNEL_INTERFERENCE 0x01 +#define CHANNEL_DFS 0x02 +#define CHANNEL_4MS_LIMIT 0x04 +#define CHANNEL_DFS_CLEAR 0x08 +#define CHANNEL_DISALLOW_ADHOC 0x10 +#define CHANNEL_PER_11D_ADHOC 0x20 + +#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) +#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) +#define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20) +#define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20) +#define CHANNEL_G_HT40PLUS (CHANNEL_2GHZ|CHANNEL_HT40PLUS) +#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS) +#define CHANNEL_A_HT40PLUS (CHANNEL_5GHZ|CHANNEL_HT40PLUS) +#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS) +#define CHANNEL_ALL \ + (CHANNEL_OFDM| \ + CHANNEL_CCK| \ + CHANNEL_2GHZ | \ + CHANNEL_5GHZ | \ + CHANNEL_HT20 | \ + CHANNEL_HT40PLUS | \ + CHANNEL_HT40MINUS) + +struct ath9k_channel { + struct ieee80211_channel *chan; + u16 channel; + u32 channelFlags; + u32 chanmode; + int32_t CalValid; + bool oneTimeCalsDone; + int8_t iCoff; + int8_t qCoff; + int16_t rawNoiseFloor; +}; + +#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \ + (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ + (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ + (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) +#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ + (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ + (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ + (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) +#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) +#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) +#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) +#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0) +#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) +#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) +#define IS_CHAN_A_5MHZ_SPACED(_c) \ + ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \ + (((_c)->channel % 20) != 0) && \ + (((_c)->channel % 10) != 0)) + +/* These macros check chanmode and not channelFlags */ +#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) +#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ + ((_c)->chanmode == CHANNEL_G_HT20)) +#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ + ((_c)->chanmode == CHANNEL_A_HT40MINUS) || \ + ((_c)->chanmode == CHANNEL_G_HT40PLUS) || \ + ((_c)->chanmode == CHANNEL_G_HT40MINUS)) +#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c))) + +enum ath9k_power_mode { + ATH9K_PM_AWAKE = 0, + ATH9K_PM_FULL_SLEEP, + ATH9K_PM_NETWORK_SLEEP, + ATH9K_PM_UNDEFINED +}; + +enum ath9k_ant_setting { + ATH9K_ANT_VARIABLE = 0, + ATH9K_ANT_FIXED_A, + ATH9K_ANT_FIXED_B +}; + +enum ath9k_tp_scale { + ATH9K_TP_SCALE_MAX = 0, + ATH9K_TP_SCALE_50, + ATH9K_TP_SCALE_25, + ATH9K_TP_SCALE_12, + ATH9K_TP_SCALE_MIN +}; + +enum ser_reg_mode { + SER_REG_MODE_OFF = 0, + SER_REG_MODE_ON = 1, + SER_REG_MODE_AUTO = 2, +}; + +struct ath9k_beacon_state { + u32 bs_nexttbtt; + u32 bs_nextdtim; + u32 bs_intval; +#define ATH9K_BEACON_PERIOD 0x0000ffff +#define ATH9K_BEACON_ENA 0x00800000 +#define ATH9K_BEACON_RESET_TSF 0x01000000 +#define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ + u32 bs_dtimperiod; + u16 bs_cfpperiod; + u16 bs_cfpmaxduration; + u32 bs_cfpnext; + u16 bs_timoffset; + u16 bs_bmissthreshold; + u32 bs_sleepduration; + u32 bs_tsfoor_threshold; +}; + +struct chan_centers { + u16 synth_center; + u16 ctl_center; + u16 ext_center; +}; + +enum { + ATH9K_RESET_POWER_ON, + ATH9K_RESET_WARM, + ATH9K_RESET_COLD, +}; + +struct ath9k_hw_version { + u32 magic; + u16 devid; + u16 subvendorid; + u32 macVersion; + u16 macRev; + u16 phyRev; + u16 analog5GhzRev; + u16 analog2GhzRev; +}; + +struct ath_hw { + struct ath_softc *ah_sc; + struct ath9k_hw_version hw_version; + struct ath9k_ops_config config; + struct ath9k_hw_capabilities caps; + struct ath_regulatory regulatory; + struct ath9k_channel channels[38]; + struct ath9k_channel *curchan; + + union { + struct ar5416_eeprom_def def; + struct ar5416_eeprom_4k map4k; + } eeprom; + const struct eeprom_ops *eep_ops; + enum ath9k_eep_map eep_map; + + bool sw_mgmt_crypto; + bool is_pciexpress; + u8 macaddr[ETH_ALEN]; + u16 tx_trig_level; + u16 rfsilent; + u32 rfkill_gpio; + u32 rfkill_polarity; + u32 btactive_gpio; + u32 wlanactive_gpio; + u32 ah_flags; + + enum nl80211_iftype opmode; + enum ath9k_power_mode power_mode; + enum ath9k_power_mode restore_mode; + + struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; + struct ar5416Stats stats; + struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; + + int16_t curchan_rad_index; + u32 mask_reg; + u32 txok_interrupt_mask; + u32 txerr_interrupt_mask; + u32 txdesc_interrupt_mask; + u32 txeol_interrupt_mask; + u32 txurn_interrupt_mask; + bool chip_fullsleep; + u32 atim_window; + u16 antenna_switch_swap; + enum ath9k_ant_setting diversity_control; + + /* Calibration */ + enum hal_cal_types supp_cals; + struct hal_cal_list iq_caldata; + struct hal_cal_list adcgain_caldata; + struct hal_cal_list adcdc_calinitdata; + struct hal_cal_list adcdc_caldata; + struct hal_cal_list *cal_list; + struct hal_cal_list *cal_list_last; + struct hal_cal_list *cal_list_curr; +#define totalPowerMeasI meas0.unsign +#define totalPowerMeasQ meas1.unsign +#define totalIqCorrMeas meas2.sign +#define totalAdcIOddPhase meas0.unsign +#define totalAdcIEvenPhase meas1.unsign +#define totalAdcQOddPhase meas2.unsign +#define totalAdcQEvenPhase meas3.unsign +#define totalAdcDcOffsetIOddPhase meas0.sign +#define totalAdcDcOffsetIEvenPhase meas1.sign +#define totalAdcDcOffsetQOddPhase meas2.sign +#define totalAdcDcOffsetQEvenPhase meas3.sign + union { + u32 unsign[AR5416_MAX_CHAINS]; + int32_t sign[AR5416_MAX_CHAINS]; + } meas0; + union { + u32 unsign[AR5416_MAX_CHAINS]; + int32_t sign[AR5416_MAX_CHAINS]; + } meas1; + union { + u32 unsign[AR5416_MAX_CHAINS]; + int32_t sign[AR5416_MAX_CHAINS]; + } meas2; + union { + u32 unsign[AR5416_MAX_CHAINS]; + int32_t sign[AR5416_MAX_CHAINS]; + } meas3; + u16 cal_samples; + + u32 sta_id1_defaults; + u32 misc_mode; + enum { + AUTO_32KHZ, + USE_32KHZ, + DONT_USE_32KHZ, + } enable_32kHz_clock; + + /* RF */ + u32 *analogBank0Data; + u32 *analogBank1Data; + u32 *analogBank2Data; + u32 *analogBank3Data; + u32 *analogBank6Data; + u32 *analogBank6TPCData; + u32 *analogBank7Data; + u32 *addac5416_21; + u32 *bank6Temp; + + int16_t txpower_indexoffset; + u32 beacon_interval; + u32 slottime; + u32 acktimeout; + u32 ctstimeout; + u32 globaltxtimeout; + u8 gbeacon_rate; + + /* ANI */ + u32 proc_phyerr; + bool has_hw_phycounters; + u32 aniperiod; + struct ar5416AniState *curani; + struct ar5416AniState ani[255]; + int totalSizeDesired[5]; + int coarse_high[5]; + int coarse_low[5]; + int firpwr[5]; + enum ath9k_ani_cmd ani_function; + + u32 intr_txqs; + enum ath9k_ht_extprotspacing extprotspacing; + u8 txchainmask; + u8 rxchainmask; + + u32 originalGain[22]; + int initPDADC; + int PDADCdelta; + + struct ar5416IniArray iniModes; + struct ar5416IniArray iniCommon; + struct ar5416IniArray iniBank0; + struct ar5416IniArray iniBB_RfGain; + struct ar5416IniArray iniBank1; + struct ar5416IniArray iniBank2; + struct ar5416IniArray iniBank3; + struct ar5416IniArray iniBank6; + struct ar5416IniArray iniBank6TPC; + struct ar5416IniArray iniBank7; + struct ar5416IniArray iniAddac; + struct ar5416IniArray iniPcieSerdes; + struct ar5416IniArray iniModesAdditional; + struct ar5416IniArray iniModesRxGain; + struct ar5416IniArray iniModesTxGain; +}; + +/* Attach, Detach, Reset */ +const char *ath9k_hw_probe(u16 vendorid, u16 devid); +void ath9k_hw_detach(struct ath_hw *ah); +struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error); +void ath9k_hw_rfdetach(struct ath_hw *ah); +int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, + bool bChannelChange); +void ath9k_hw_fill_cap_info(struct ath_hw *ah); +bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, + u32 capability, u32 *result); +bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status); + +/* Key Cache Management */ +bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry); +bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac); +bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac); +bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry); + +/* GPIO / RFKILL / Antennae */ +void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio); +u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); +void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, + u32 ah_signal_type); +void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hw *ah); +#endif +u32 ath9k_hw_getdefantenna(struct ath_hw *ah); +void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); +bool ath9k_hw_setantennaswitch(struct ath_hw *ah, + enum ath9k_ant_setting settings, + struct ath9k_channel *chan, + u8 *tx_chainmask, u8 *rx_chainmask, + u8 *antenna_cfgd); + +/* General Operation */ +bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); +u32 ath9k_hw_reverse_bits(u32 val, u32 n); +bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); +u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, + u32 frameLen, u16 rateix, bool shortPreamble); +void ath9k_hw_get_channel_centers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct chan_centers *centers); +u32 ath9k_hw_getrxfilter(struct ath_hw *ah); +void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits); +bool ath9k_hw_phy_disable(struct ath_hw *ah); +bool ath9k_hw_disable(struct ath_hw *ah); +bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); +void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac); +void ath9k_hw_setopmode(struct ath_hw *ah); +void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); +void ath9k_hw_setbssidmask(struct ath_softc *sc); +void ath9k_hw_write_associd(struct ath_softc *sc); +u64 ath9k_hw_gettsf64(struct ath_hw *ah); +void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); +void ath9k_hw_reset_tsf(struct ath_hw *ah); +bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); +void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); +void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); +void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, + const struct ath9k_beacon_state *bs); +bool ath9k_hw_setpower(struct ath_hw *ah, + enum ath9k_power_mode mode); +void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore); + +/* Interrupt Handling */ +bool ath9k_hw_intrpend(struct ath_hw *ah); +bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); +enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah); +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); + +void ath9k_hw_btcoex_enable(struct ath_hw *ah); + +#endif diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h new file mode 100644 index 0000000..e2f0a34 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -0,0 +1,4848 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +static const u32 ar5416Modes[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, + { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, + { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u32 ar5416Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00007010, 0x00000000 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00070000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a002e }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5d50e188 }, + { 0x00009958, 0x00081fff }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x001fff00 }, + { 0x000099ac, 0x00000000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x00000bb5 }, + { 0x0000a22c, 0x00000011 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x08000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const u32 ar5416Bank0[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const u32 ar5416BB_RfGain[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 0x00009aa0, 0x000000f9, 0x000000f9 }, + { 0x00009aa4, 0x000000f9, 0x000000f9 }, + { 0x00009aa8, 0x000000f9, 0x000000f9 }, + { 0x00009aac, 0x000000f9, 0x000000f9 }, + { 0x00009ab0, 0x000000f9, 0x000000f9 }, + { 0x00009ab4, 0x000000f9, 0x000000f9 }, + { 0x00009ab8, 0x000000f9, 0x000000f9 }, + { 0x00009abc, 0x000000f9, 0x000000f9 }, + { 0x00009ac0, 0x000000f9, 0x000000f9 }, + { 0x00009ac4, 0x000000f9, 0x000000f9 }, + { 0x00009ac8, 0x000000f9, 0x000000f9 }, + { 0x00009acc, 0x000000f9, 0x000000f9 }, + { 0x00009ad0, 0x000000f9, 0x000000f9 }, + { 0x00009ad4, 0x000000f9, 0x000000f9 }, + { 0x00009ad8, 0x000000f9, 0x000000f9 }, + { 0x00009adc, 0x000000f9, 0x000000f9 }, + { 0x00009ae0, 0x000000f9, 0x000000f9 }, + { 0x00009ae4, 0x000000f9, 0x000000f9 }, + { 0x00009ae8, 0x000000f9, 0x000000f9 }, + { 0x00009aec, 0x000000f9, 0x000000f9 }, + { 0x00009af0, 0x000000f9, 0x000000f9 }, + { 0x00009af4, 0x000000f9, 0x000000f9 }, + { 0x00009af8, 0x000000f9, 0x000000f9 }, + { 0x00009afc, 0x000000f9, 0x000000f9 }, +}; + +static const u32 ar5416Bank1[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const u32 ar5416Bank2[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const u32 ar5416Bank3[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const u32 ar5416Bank6[][3] = { + + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank6TPC[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x201400df, 0x201400df }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007081, 0x00007081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank7[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static const u32 ar5416Addac[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000003 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x0000000c }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000030 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000060 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000058 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +static const u32 ar5416Modes_9100[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 }, + { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e }, + { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff }, +#ifdef TB243 + { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 }, +#else + { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, + { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, + { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, + { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, +#endif + { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u32 ar5416Common_9100[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00020010, 0x00000003 }, + { 0x00020038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00004000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a01ae }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x001a0bb5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889ae }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000001 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa33 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const u32 ar5416Bank0_9100[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const u32 ar5416BB_RfGain_9100[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 0x00009aa0, 0x000000f9, 0x000000f9 }, + { 0x00009aa4, 0x000000f9, 0x000000f9 }, + { 0x00009aa8, 0x000000f9, 0x000000f9 }, + { 0x00009aac, 0x000000f9, 0x000000f9 }, + { 0x00009ab0, 0x000000f9, 0x000000f9 }, + { 0x00009ab4, 0x000000f9, 0x000000f9 }, + { 0x00009ab8, 0x000000f9, 0x000000f9 }, + { 0x00009abc, 0x000000f9, 0x000000f9 }, + { 0x00009ac0, 0x000000f9, 0x000000f9 }, + { 0x00009ac4, 0x000000f9, 0x000000f9 }, + { 0x00009ac8, 0x000000f9, 0x000000f9 }, + { 0x00009acc, 0x000000f9, 0x000000f9 }, + { 0x00009ad0, 0x000000f9, 0x000000f9 }, + { 0x00009ad4, 0x000000f9, 0x000000f9 }, + { 0x00009ad8, 0x000000f9, 0x000000f9 }, + { 0x00009adc, 0x000000f9, 0x000000f9 }, + { 0x00009ae0, 0x000000f9, 0x000000f9 }, + { 0x00009ae4, 0x000000f9, 0x000000f9 }, + { 0x00009ae8, 0x000000f9, 0x000000f9 }, + { 0x00009aec, 0x000000f9, 0x000000f9 }, + { 0x00009af0, 0x000000f9, 0x000000f9 }, + { 0x00009af4, 0x000000f9, 0x000000f9 }, + { 0x00009af8, 0x000000f9, 0x000000f9 }, + { 0x00009afc, 0x000000f9, 0x000000f9 }, +}; + +static const u32 ar5416Bank1_9100[][2] = { + { 0x000098b0, 0x02108421}, + { 0x000098ec, 0x00000008}, +}; + +static const u32 ar5416Bank2_9100[][2] = { + { 0x000098b0, 0x0e73ff17}, + { 0x000098e0, 0x00000420}, +}; + +static const u32 ar5416Bank3_9100[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const u32 ar5416Bank6_9100[][3] = { + + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014000f, 0x0014000f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x000180d6, 0x000180d6 }, + { 0x0000989c, 0x0000c0aa, 0x0000c0aa }, + { 0x0000989c, 0x000000b1, 0x000000b1 }, + { 0x0000989c, 0x00002000, 0x00002000 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + + +static const u32 ar5416Bank6TPC_9100[][3] = { + + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x2014008f, 0x2014008f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007080, 0x00007080 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank7_9100[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static const u32 ar5416Addac_9100[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000010 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000015 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +static const u32 ar5416Modes_9160[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, + { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u32 ar5416Common_9160[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00007010, 0x00000020 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a01ae }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009940, 0x00750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x001a0bb5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000e000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000001 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79bfaa03 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const u32 ar5416Bank0_9160[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const u32 ar5416BB_RfGain_9160[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 0x00009aa0, 0x000000f9, 0x000000f9 }, + { 0x00009aa4, 0x000000f9, 0x000000f9 }, + { 0x00009aa8, 0x000000f9, 0x000000f9 }, + { 0x00009aac, 0x000000f9, 0x000000f9 }, + { 0x00009ab0, 0x000000f9, 0x000000f9 }, + { 0x00009ab4, 0x000000f9, 0x000000f9 }, + { 0x00009ab8, 0x000000f9, 0x000000f9 }, + { 0x00009abc, 0x000000f9, 0x000000f9 }, + { 0x00009ac0, 0x000000f9, 0x000000f9 }, + { 0x00009ac4, 0x000000f9, 0x000000f9 }, + { 0x00009ac8, 0x000000f9, 0x000000f9 }, + { 0x00009acc, 0x000000f9, 0x000000f9 }, + { 0x00009ad0, 0x000000f9, 0x000000f9 }, + { 0x00009ad4, 0x000000f9, 0x000000f9 }, + { 0x00009ad8, 0x000000f9, 0x000000f9 }, + { 0x00009adc, 0x000000f9, 0x000000f9 }, + { 0x00009ae0, 0x000000f9, 0x000000f9 }, + { 0x00009ae4, 0x000000f9, 0x000000f9 }, + { 0x00009ae8, 0x000000f9, 0x000000f9 }, + { 0x00009aec, 0x000000f9, 0x000000f9 }, + { 0x00009af0, 0x000000f9, 0x000000f9 }, + { 0x00009af4, 0x000000f9, 0x000000f9 }, + { 0x00009af8, 0x000000f9, 0x000000f9 }, + { 0x00009afc, 0x000000f9, 0x000000f9 }, +}; + +static const u32 ar5416Bank1_9160[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const u32 ar5416Bank2_9160[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const u32 ar5416Bank3_9160[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const u32 ar5416Bank6_9160[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank6TPC_9160[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x2014008f, 0x2014008f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007080, 0x00007080 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank7_9160[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static u32 ar5416Addac_9160[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000003 }, + {0x0000989c, 0x00000008 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +static u32 ar5416Addac_91601_1[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +/* XXX 9280 1 */ +static const u32 ar9280Modes_9280[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801080, 0x08400840, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 }, + { 0x00009848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 }, + { 0x0000a848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d20, 0x00049d20, 0x00049d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 }, + { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, + { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, + { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, + { 0x0000c9b8, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a }, + { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00008184, 0x00008184, 0x00000214, 0x00000214, 0x00000214 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000218, 0x00000218, 0x00000218 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000224, 0x00000224, 0x00000224 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000228, 0x00000228, 0x00000228 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000022c, 0x0000022c, 0x0000022c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00000230, 0x00000230, 0x00000230 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x000002a4, 0x000002a4, 0x000002a4 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x000002a8, 0x000002a8, 0x000002a8 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x000002ac, 0x000002ac, 0x000002ac }, + { 0x00009a24, 0x00008210, 0x00008210, 0x000002b0, 0x000002b0, 0x000002b0 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x000002b4, 0x000002b4, 0x000002b4 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x000002b8, 0x000002b8, 0x000002b8 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x00000390, 0x00000390, 0x00000390 }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00000394, 0x00000394, 0x00000394 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00000398, 0x00000398, 0x00000398 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00000334, 0x00000334, 0x00000334 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x00000338, 0x00000338, 0x00000338 }, + { 0x00009a44, 0x00008304, 0x00008304, 0x000003ac, 0x000003ac, 0x000003ac }, + { 0x00009a48, 0x00008308, 0x00008308, 0x000003b0, 0x000003b0, 0x000003b0 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x000003b4, 0x000003b4, 0x000003b4 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x000003b8, 0x000003b8, 0x000003b8 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x000003a5, 0x000003a5, 0x000003a5 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x000003a9, 0x000003a9, 0x000003a9 }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x000003ad, 0x000003ad, 0x000003ad }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, + { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 }, + { 0x0000a20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 }, + { 0x0000b20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, + { 0x0000784c, 0x0e4f048c, 0x0e4f048c, 0x0e4d048c, 0x0e4d048c, 0x0e4d048c }, + { 0x00007854, 0x12031828, 0x12031828, 0x12035828, 0x12035828, 0x12035828 }, + { 0x00007870, 0x807ec400, 0x807ec400, 0x807ec000, 0x807ec000, 0x807ec000 }, + { 0x0000788c, 0x00010000, 0x00010000, 0x00110000, 0x00110000, 0x00110000 }, +}; + +static const u32 ar9280Common_9280[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00007010, 0x00000033 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00008344, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xaf268e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a01ae }, + { 0x0000984c, 0x0040233c }, + { 0x0000a84c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x0000a920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0xe250a51e }, + { 0x00009958, 0x3388ffff }, + { 0x00009940, 0x00781204 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190fb514 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f00c4 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099fc, 0x00001042 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x40206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x23277200 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x001da000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cdbd380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000a358, 0x7999aa0f }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f38081 }, + { 0x00007800, 0x00040000 }, + { 0x00007804, 0xdb005012 }, + { 0x00007808, 0x04924914 }, + { 0x0000780c, 0x21084210 }, + { 0x00007810, 0x6d801300 }, + { 0x00007814, 0x0019beff }, + { 0x00007818, 0x07e40000 }, + { 0x0000781c, 0x00492000 }, + { 0x00007820, 0x92492480 }, + { 0x00007824, 0x00040000 }, + { 0x00007828, 0xdb005012 }, + { 0x0000782c, 0x04924914 }, + { 0x00007830, 0x21084210 }, + { 0x00007834, 0x6d801300 }, + { 0x00007838, 0x0019beff }, + { 0x0000783c, 0x07e40000 }, + { 0x00007840, 0x00492000 }, + { 0x00007844, 0x92492480 }, + { 0x00007848, 0x00120000 }, + { 0x00007850, 0x54214514 }, + { 0x00007858, 0x92592692 }, + { 0x00007860, 0x52802000 }, + { 0x00007864, 0x0a8e370e }, + { 0x00007868, 0xc0102850 }, + { 0x0000786c, 0x812d4000 }, + { 0x00007874, 0x001b6db0 }, + { 0x00007878, 0x00376b63 }, + { 0x0000787c, 0x06db6db6 }, + { 0x00007880, 0x006d8000 }, + { 0x00007884, 0xffeffffe }, + { 0x00007888, 0xffeffffe }, + { 0x00007890, 0x00060aeb }, + { 0x00007894, 0x5a108000 }, + { 0x00007898, 0x2a850160 }, +}; + +/* XXX 9280 2 */ +static const u32 ar9280Modes_9280_2[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 }, + { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, + { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, + { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, + { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, + { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, + { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, +}; + +static const u32 ar9280Common_9280_2[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000033 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafa68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x0000a84c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x0000a920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009940, 0x14750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x000099fc, 0x00001042 }, + { 0x0000a208, 0x803e4788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x40206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x233f7180 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c88000 }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cdbd380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00040000 }, + { 0x00007804, 0xdb005012 }, + { 0x00007808, 0x04924914 }, + { 0x0000780c, 0x21084210 }, + { 0x00007810, 0x6d801300 }, + { 0x00007818, 0x07e41000 }, + { 0x00007824, 0x00040000 }, + { 0x00007828, 0xdb005012 }, + { 0x0000782c, 0x04924914 }, + { 0x00007830, 0x21084210 }, + { 0x00007834, 0x6d801300 }, + { 0x0000783c, 0x07e40000 }, + { 0x00007848, 0x00100000 }, + { 0x0000784c, 0x773f0567 }, + { 0x00007850, 0x54214514 }, + { 0x00007854, 0x12035828 }, + { 0x00007858, 0x9259269a }, + { 0x00007860, 0x52802000 }, + { 0x00007864, 0x0a8e370e }, + { 0x00007868, 0xc0102850 }, + { 0x0000786c, 0x812d4000 }, + { 0x00007870, 0x807ec400 }, + { 0x00007874, 0x001b6db0 }, + { 0x00007878, 0x00376b63 }, + { 0x0000787c, 0x06db6db6 }, + { 0x00007880, 0x006d8000 }, + { 0x00007884, 0xffeffffe }, + { 0x00007888, 0xffeffffe }, + { 0x0000788c, 0x00010000 }, + { 0x00007890, 0x02060aeb }, + { 0x00007898, 0x2a850160 }, +}; + +static const u32 ar9280Modes_fast_clock_9280_2[][3] = { + { 0x00001030, 0x00000268, 0x000004d0 }, + { 0x00001070, 0x0000018c, 0x00000318 }, + { 0x000010b0, 0x00000fd0, 0x00001fa0 }, + { 0x00008014, 0x044c044c, 0x08980898 }, + { 0x0000801c, 0x148ec02b, 0x148ec057 }, + { 0x00008318, 0x000044c0, 0x00008980 }, + { 0x00009820, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000f0f, 0x00000f0f }, + { 0x00009828, 0x0b020001, 0x0b020001 }, + { 0x00009834, 0x00000f0f, 0x00000f0f }, + { 0x00009844, 0x03721821, 0x03721821 }, + { 0x00009914, 0x00000898, 0x00001130 }, + { 0x00009918, 0x0000000b, 0x00000016 }, +}; + +static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, +}; + +static const u32 ar9280Modes_original_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, +}; + +static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, + { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, +}; + +static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411 }, + { 0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413 }, + { 0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811 }, + { 0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813 }, + { 0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14 }, + { 0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50 }, + { 0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c }, + { 0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a }, + { 0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92 }, + { 0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 }, + { 0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 }, + { 0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 }, + { 0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5 }, + { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 }, + { 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 }, + { 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, + { 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, + { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, + { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, +}; + +static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, + { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 }, + { 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 }, + { 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, + { 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, + { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, + { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, +}; + +static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +/* AR9285 */ +static const u_int32_t ar9285Modes_9285[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 }, + { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 }, + { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 }, + { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x1927b515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def0a00 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e6788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x39ce739c }, + { 0x0000a27c, 0x050e039c }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x39ce739c }, + { 0x0000a398, 0x0000039c }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96c }, + { 0x00007834, 0x71400086 }, + { 0x00007838, 0xfac68800 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */ +static const u_int32_t ar9285Modes_9285_1_2[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285_1_2[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04810 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x0000320a }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x192bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def0400 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e68c8 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96e }, + { 0x00007834, 0x71400087 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, + { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, + { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, + { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, + { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, + { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, + { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, +}; + +static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 }, + { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, + { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, + { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, + { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c }, + { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, + { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c new file mode 100644 index 0000000..8ae4ec2 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -0,0 +1,976 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, + struct ath9k_tx_queue_info *qi) +{ + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", + ah->txok_interrupt_mask, ah->txerr_interrupt_mask, + ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, + ah->txurn_interrupt_mask); + + REG_WRITE(ah, AR_IMR_S0, + SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK) + | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC)); + REG_WRITE(ah, AR_IMR_S1, + SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR) + | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL)); + REG_RMW_FIELD(ah, AR_IMR_S2, + AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask); +} + +u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) +{ + return REG_READ(ah, AR_QTXDP(q)); +} + +bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) +{ + REG_WRITE(ah, AR_QTXDP(q), txdp); + + return true; +} + +bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) +{ + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); + + REG_WRITE(ah, AR_Q_TXE, 1 << q); + + return true; +} + +u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) +{ + u32 npend; + + npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; + if (npend == 0) { + + if (REG_READ(ah, AR_Q_TXE) & (1 << q)) + npend = 1; + } + + return npend; +} + +bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) +{ + u32 txcfg, curLevel, newLevel; + enum ath9k_int omask; + + if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD) + return false; + + omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); + + txcfg = REG_READ(ah, AR_TXCFG); + curLevel = MS(txcfg, AR_FTRIG); + newLevel = curLevel; + if (bIncTrigLevel) { + if (curLevel < MAX_TX_FIFO_THRESHOLD) + newLevel++; + } else if (curLevel > MIN_TX_FIFO_THRESHOLD) + newLevel--; + if (newLevel != curLevel) + REG_WRITE(ah, AR_TXCFG, + (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); + + ath9k_hw_set_interrupts(ah, omask); + + ah->tx_trig_level = newLevel; + + return newLevel != curLevel; +} + +bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) +{ +#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */ +#define ATH9K_TIME_QUANTUM 100 /* usec */ + + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_tx_queue_info *qi; + u32 tsfLow, j, wait; + u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + "invalid queue: %u\n", q); + return false; + } + + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + "inactive queue: %u\n", q); + return false; + } + + REG_WRITE(ah, AR_Q_TXD, 1 << q); + + for (wait = wait_time; wait != 0; wait--) { + if (ath9k_hw_numtxpending(ah, q) == 0) + break; + udelay(ATH9K_TIME_QUANTUM); + } + + if (ath9k_hw_numtxpending(ah, q)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: Num of pending TX Frames %d on Q %d\n", + __func__, ath9k_hw_numtxpending(ah, q), q); + + for (j = 0; j < 2; j++) { + tsfLow = REG_READ(ah, AR_TSF_L32); + REG_WRITE(ah, AR_QUIET2, + SM(10, AR_QUIET2_QUIET_DUR)); + REG_WRITE(ah, AR_QUIET_PERIOD, 100); + REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_QUIET_TIMER_EN); + + if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) + break; + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "TSF has moved while trying to set " + "quiet time TSF: 0x%08x\n", tsfLow); + } + + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + + udelay(200); + REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); + + wait = wait_time; + while (ath9k_hw_numtxpending(ah, q)) { + if ((--wait) == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "Failed to stop TX DMA in 100 " + "msec after killing last frame\n"); + break; + } + udelay(ATH9K_TIME_QUANTUM); + } + + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + } + + REG_WRITE(ah, AR_Q_TXD, 0); + return wait != 0; + +#undef ATH9K_TX_STOP_DMA_TIMEOUT +#undef ATH9K_TIME_QUANTUM +} + +bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (firstSeg) { + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); + } else if (lastSeg) { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen; + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + } else { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_TxMore; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; + + return true; +} + +void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; +} + +int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if ((ads->ds_txstatus9 & AR_TxDone) == 0) + return -EINPROGRESS; + + ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); + ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; + ds->ds_txstat.ts_status = 0; + ds->ds_txstat.ts_flags = 0; + + if (ads->ds_txstatus1 & AR_ExcessiveRetries) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; + if (ads->ds_txstatus1 & AR_Filtered) + ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; + if (ads->ds_txstatus1 & AR_FIFOUnderrun) { + ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus9 & AR_TxOpExceeded) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; + if (ads->ds_txstatus1 & AR_TxTimerExpired) + ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; + + if (ads->ds_txstatus1 & AR_DescCfgErr) + ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; + if (ads->ds_txstatus1 & AR_TxDataUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus0 & AR_TxBaStatus) { + ds->ds_txstat.ts_flags |= ATH9K_TX_BA; + ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; + ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; + } + + ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); + switch (ds->ds_txstat.ts_rateindex) { + case 0: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); + break; + case 1: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); + break; + case 2: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); + break; + case 3: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); + break; + } + + ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); + ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); + ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); + ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); + ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); + ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); + ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); + ds->ds_txstat.evm0 = ads->AR_TxEVM0; + ds->ds_txstat.evm1 = ads->AR_TxEVM1; + ds->ds_txstat.evm2 = ads->AR_TxEVM2; + ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); + ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); + ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); + ds->ds_txstat.ts_antenna = 0; + + return 0; +} + +void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + txPower += ah->txpower_indexoffset; + if (txPower > 63) + txPower = 63; + + ads->ds_ctl0 = (pktLen & AR_FrameLen) + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txPower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); + + ads->ds_ctl1 = + (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) + | SM(type, AR_FrameType) + | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + ads->ds_ctl6 = SM(keyType, AR_EncrType); + + if (AR_SREV_9285(ah)) { + ads->ds_ctl8 = 0; + ads->ds_ctl9 = 0; + ads->ds_ctl10 = 0; + ads->ds_ctl11 = 0; + } +} + +void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, + struct ath_desc *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ar5416_desc *last_ads = AR5416DESC(lastds); + u32 ds_ctl0; + + if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { + ds_ctl0 = ads->ds_ctl0; + + if (flags & ATH9K_TXDESC_RTSENA) { + ds_ctl0 &= ~AR_CTSEnable; + ds_ctl0 |= AR_RTSEnable; + } else { + ds_ctl0 &= ~AR_RTSEnable; + ds_ctl0 |= AR_CTSEnable; + } + + ads->ds_ctl0 = ds_ctl0; + } else { + ads->ds_ctl0 = + (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); + } + + ads->ds_ctl2 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEna : 0) + | SM(0, AR_BurstDur); + + ads->ds_ctl3 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ds_ctl7 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + last_ads->ds_ctl2 = ads->ds_ctl2; + last_ads->ds_ctl3 = ads->ds_ctl3; +} + +void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, + u32 aggrLen) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + ads->ds_ctl6 &= ~AR_AggrLen; + ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); +} + +void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, + u32 numDelims) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + unsigned int ctl6; + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + + ctl6 = ads->ds_ctl6; + ctl6 &= ~AR_PadDelim; + ctl6 |= SM(numDelims, AR_PadDelim); + ads->ds_ctl6 = ctl6; +} + +void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= AR_IsAggr; + ads->ds_ctl1 &= ~AR_MoreAggr; + ads->ds_ctl6 &= ~AR_PadDelim; +} + +void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); +} + +void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, + u32 burstDuration) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl2 &= ~AR_BurstDur; + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); +} + +void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, + u32 vmf) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (vmf) + ads->ds_ctl0 |= AR_VirtMoreFrag; + else + ads->ds_ctl0 &= ~AR_VirtMoreFrag; +} + +void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) +{ + *txqs &= ah->intr_txqs; + ah->intr_txqs &= ~(*txqs); +} + +bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, + const struct ath9k_tx_queue_info *qinfo) +{ + u32 cw; + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + "invalid queue: %u\n", q); + return false; + } + + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + "inactive queue: %u\n", q); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); + + qi->tqi_ver = qinfo->tqi_ver; + qi->tqi_subtype = qinfo->tqi_subtype; + qi->tqi_qflags = qinfo->tqi_qflags; + qi->tqi_priority = qinfo->tqi_priority; + if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) + qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); + else + qi->tqi_aifs = INIT_AIFS; + if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmin, 1024U); + qi->tqi_cwmin = 1; + while (qi->tqi_cwmin < cw) + qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; + } else + qi->tqi_cwmin = qinfo->tqi_cwmin; + if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmax, 1024U); + qi->tqi_cwmax = 1; + while (qi->tqi_cwmax < cw) + qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; + } else + qi->tqi_cwmax = INIT_CWMAX; + + if (qinfo->tqi_shretry != 0) + qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); + else + qi->tqi_shretry = INIT_SH_RETRY; + if (qinfo->tqi_lgretry != 0) + qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); + else + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; + qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; + qi->tqi_burstTime = qinfo->tqi_burstTime; + qi->tqi_readyTime = qinfo->tqi_readyTime; + + switch (qinfo->tqi_subtype) { + case ATH9K_WME_UPSD: + if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) + qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; + break; + default: + break; + } + + return true; +} + +bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, + struct ath9k_tx_queue_info *qinfo) +{ + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + "invalid queue: %u\n", q); + return false; + } + + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + "inactive queue: %u\n", q); + return false; + } + + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_ver = qi->tqi_ver; + qinfo->tqi_subtype = qi->tqi_subtype; + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_priority = qi->tqi_priority; + qinfo->tqi_aifs = qi->tqi_aifs; + qinfo->tqi_cwmin = qi->tqi_cwmin; + qinfo->tqi_cwmax = qi->tqi_cwmax; + qinfo->tqi_shretry = qi->tqi_shretry; + qinfo->tqi_lgretry = qi->tqi_lgretry; + qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; + qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; + qinfo->tqi_burstTime = qi->tqi_burstTime; + qinfo->tqi_readyTime = qi->tqi_readyTime; + + return true; +} + +int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo) +{ + struct ath9k_tx_queue_info *qi; + struct ath9k_hw_capabilities *pCap = &ah->caps; + int q; + + switch (type) { + case ATH9K_TX_QUEUE_BEACON: + q = pCap->total_queues - 1; + break; + case ATH9K_TX_QUEUE_CAB: + q = pCap->total_queues - 2; + break; + case ATH9K_TX_QUEUE_PSPOLL: + q = 1; + break; + case ATH9K_TX_QUEUE_UAPSD: + q = pCap->total_queues - 3; + break; + case ATH9K_TX_QUEUE_DATA: + for (q = 0; q < pCap->total_queues; q++) + if (ah->txq[q].tqi_type == + ATH9K_TX_QUEUE_INACTIVE) + break; + if (q == pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "No available TX queue\n"); + return -1; + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n", + type); + return -1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); + + qi = &ah->txq[q]; + if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "TX queue: %u already active\n", q); + return -1; + } + memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); + qi->tqi_type = type; + if (qinfo == NULL) { + qi->tqi_qflags = + TXQ_FLAG_TXOKINT_ENABLE + | TXQ_FLAG_TXERRINT_ENABLE + | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; + qi->tqi_aifs = INIT_AIFS; + qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; + qi->tqi_cwmax = INIT_CWMAX; + qi->tqi_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_physCompBuf = 0; + } else { + qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; + (void) ath9k_hw_set_txq_props(ah, q, qinfo); + } + + return q; +} + +bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) +{ + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + "invalid queue: %u\n", q); + return false; + } + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + "inactive queue: %u\n", q); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); + + qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; + ah->txok_interrupt_mask &= ~(1 << q); + ah->txerr_interrupt_mask &= ~(1 << q); + ah->txdesc_interrupt_mask &= ~(1 << q); + ah->txeol_interrupt_mask &= ~(1 << q); + ah->txurn_interrupt_mask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) +{ + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_channel *chan = ah->curchan; + struct ath9k_tx_queue_info *qi; + u32 cwMin, chanCwMin, value; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + "invalid queue: %u\n", q); + return false; + } + + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + "inactive queue: %u\n", q); + return true; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); + + if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { + if (chan && IS_CHAN_B(chan)) + chanCwMin = INIT_CWMIN_11B; + else + chanCwMin = INIT_CWMIN; + + for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); + } else + cwMin = qi->tqi_cwmin; + + REG_WRITE(ah, AR_DLCL_IFS(q), + SM(cwMin, AR_D_LCL_IFS_CWMIN) | + SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | + SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + + 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)); + + REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); + + if (qi->tqi_cbrPeriod) { + REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | + SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + } + if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { + REG_WRITE(ah, AR_QRDYTIMECFG(q), + SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | + AR_Q_RDYTIMECFG_EN); + } + + REG_WRITE(ah, AR_DCHNTIME(q), + SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | + (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); + + if (qi->tqi_burstTime + && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_RDYTIME_EXP_POLICY); + + } + + if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_FRAG_BKOFF_EN); + } + switch (qi->tqi_type) { + case ATH9K_TX_QUEUE_BEACON: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); + + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S) + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS); + break; + case ATH9K_TX_QUEUE_CAB: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0); + value = (qi->tqi_readyTime - + (ah->config.sw_beacon_response_time - + ah->config.dma_beacon_response_time) - + ah->config.additional_swba_backoff) * 1024; + REG_WRITE(ah, AR_QRDYTIMECFG(q), + value | AR_Q_RDYTIMECFG_EN); + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); + break; + case ATH9K_TX_QUEUE_PSPOLL: + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); + break; + case ATH9K_TX_QUEUE_UAPSD: + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + break; + default: + break; + } + + if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + + if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) + ah->txok_interrupt_mask |= 1 << q; + else + ah->txok_interrupt_mask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) + ah->txerr_interrupt_mask |= 1 << q; + else + ah->txerr_interrupt_mask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) + ah->txdesc_interrupt_mask |= 1 << q; + else + ah->txdesc_interrupt_mask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) + ah->txeol_interrupt_mask |= 1 << q; + else + ah->txeol_interrupt_mask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) + ah->txurn_interrupt_mask |= 1 << q; + else + ah->txurn_interrupt_mask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf) +{ + struct ar5416_desc ads; + struct ar5416_desc *adsp = AR5416DESC(ds); + u32 phyerr; + + if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) + return -EINPROGRESS; + + ads.u.rx = adsp->u.rx; + + ds->ds_rxstat.rs_status = 0; + ds->ds_rxstat.rs_flags = 0; + + ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; + ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + + ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); + ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); + ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); + ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); + ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); + ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); + if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) + ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); + else + ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; + + ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); + ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + + ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + ds->ds_rxstat.rs_moreaggr = + (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); + ds->ds_rxstat.rs_flags = + (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; + ds->ds_rxstat.rs_flags |= + (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; + + if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; + if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; + if (ads.ds_rxstatus8 & AR_DecryptBusyErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; + + if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { + if (ads.ds_rxstatus8 & AR_CRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; + else if (ads.ds_rxstatus8 & AR_PHYErr) { + ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; + phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); + ds->ds_rxstat.rs_phyerr = phyerr; + } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; + else if (ads.ds_rxstatus8 & AR_MichaelErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; + } + + return 0; +} + +bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 size, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath9k_hw_capabilities *pCap = &ah->caps; + + ads->ds_ctl1 = size & AR_BufLen; + if (flags & ATH9K_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxIntrReq; + + ads->ds_rxstatus8 &= ~AR_RxDone; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + memset(&(ads->u), 0, sizeof(ads->u)); + + return true; +} + +bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) +{ + u32 reg; + + if (set) { + REG_SET_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, + 0, AH_WAIT_TIMEOUT)) { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | + AR_DIAG_RX_ABORT)); + + reg = REG_READ(ah, AR_OBS_BUS_1); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "RX failed to go idle in 10 ms RXSM=0x%x\n", reg); + + return false; + } + } else { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + } + + return true; +} + +void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp) +{ + REG_WRITE(ah, AR_RXDP, rxdp); +} + +void ath9k_hw_rxena(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +void ath9k_hw_startpcureceive(struct ath_hw *ah) +{ + ath9k_enable_mib_counters(ah); + + ath9k_ani_reset(ah); + + REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); +} + +void ath9k_hw_stoppcurecv(struct ath_hw *ah) +{ + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + + ath9k_hw_disable_mib_counters(ah); +} + +bool ath9k_hw_stopdmarecv(struct ath_hw *ah) +{ +#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ +#define AH_RX_TIME_QUANTUM 100 /* usec */ + + int i; + + REG_WRITE(ah, AR_CR, AR_CR_RXD); + + /* Wait for rx enable bit to go low */ + for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { + if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) + break; + udelay(AH_TIME_QUANTUM); + } + + if (i == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "DMA failed to stop in %d ms " + "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + AH_RX_STOP_DMA_TIMEOUT / 1000, + REG_READ(ah, AR_CR), + REG_READ(ah, AR_DIAG_SW)); + return false; + } else { + return true; + } + +#undef AH_RX_TIME_QUANTUM +#undef AH_RX_STOP_DMA_TIMEOUT +} diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h new file mode 100644 index 0000000..1176bce --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MAC_H +#define MAC_H + +#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ? \ + MS(ads->ds_rxstatus0, AR_RxRate) : \ + (ads->ds_rxstatus3 >> 2) & 0xFF) + +#define set11nTries(_series, _index) \ + (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) + +#define set11nRate(_series, _index) \ + (SM((_series)[_index].Rate, AR_XmitRate##_index)) + +#define set11nPktDurRTSCTS(_series, _index) \ + (SM((_series)[_index].PktDuration, AR_PacketDur##_index) | \ + ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS ? \ + 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)) + +#define CCK_SIFS_TIME 10 +#define CCK_PREAMBLE_BITS 144 +#define CCK_PLCP_BITS 48 + +#define OFDM_SIFS_TIME 16 +#define OFDM_PREAMBLE_TIME 20 +#define OFDM_PLCP_BITS 22 +#define OFDM_SYMBOL_TIME 4 + +#define OFDM_SIFS_TIME_HALF 32 +#define OFDM_PREAMBLE_TIME_HALF 40 +#define OFDM_PLCP_BITS_HALF 22 +#define OFDM_SYMBOL_TIME_HALF 8 + +#define OFDM_SIFS_TIME_QUARTER 64 +#define OFDM_PREAMBLE_TIME_QUARTER 80 +#define OFDM_PLCP_BITS_QUARTER 22 +#define OFDM_SYMBOL_TIME_QUARTER 16 + +#define INIT_AIFS 2 +#define INIT_CWMIN 15 +#define INIT_CWMIN_11B 31 +#define INIT_CWMAX 1023 +#define INIT_SH_RETRY 10 +#define INIT_LG_RETRY 10 +#define INIT_SSH_RETRY 32 +#define INIT_SLG_RETRY 32 + +#define ATH9K_SLOT_TIME_6 6 +#define ATH9K_SLOT_TIME_9 9 +#define ATH9K_SLOT_TIME_20 20 + +#define ATH9K_TXERR_XRETRY 0x01 +#define ATH9K_TXERR_FILT 0x02 +#define ATH9K_TXERR_FIFO 0x04 +#define ATH9K_TXERR_XTXOP 0x08 +#define ATH9K_TXERR_TIMER_EXPIRED 0x10 + +#define ATH9K_TX_BA 0x01 +#define ATH9K_TX_PWRMGMT 0x02 +#define ATH9K_TX_DESC_CFG_ERR 0x04 +#define ATH9K_TX_DATA_UNDERRUN 0x08 +#define ATH9K_TX_DELIM_UNDERRUN 0x10 +#define ATH9K_TX_SW_ABORTED 0x40 +#define ATH9K_TX_SW_FILTERED 0x80 + +#define MIN_TX_FIFO_THRESHOLD 0x1 +#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) +#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD + +struct ath_tx_status { + u32 ts_tstamp; + u16 ts_seqnum; + u8 ts_status; + u8 ts_ratecode; + u8 ts_rateindex; + int8_t ts_rssi; + u8 ts_shortretry; + u8 ts_longretry; + u8 ts_virtcol; + u8 ts_antenna; + u8 ts_flags; + int8_t ts_rssi_ctl0; + int8_t ts_rssi_ctl1; + int8_t ts_rssi_ctl2; + int8_t ts_rssi_ext0; + int8_t ts_rssi_ext1; + int8_t ts_rssi_ext2; + u8 pad[3]; + u32 ba_low; + u32 ba_high; + u32 evm0; + u32 evm1; + u32 evm2; +}; + +struct ath_rx_status { + u32 rs_tstamp; + u16 rs_datalen; + u8 rs_status; + u8 rs_phyerr; + int8_t rs_rssi; + u8 rs_keyix; + u8 rs_rate; + u8 rs_antenna; + u8 rs_more; + int8_t rs_rssi_ctl0; + int8_t rs_rssi_ctl1; + int8_t rs_rssi_ctl2; + int8_t rs_rssi_ext0; + int8_t rs_rssi_ext1; + int8_t rs_rssi_ext2; + u8 rs_isaggr; + u8 rs_moreaggr; + u8 rs_num_delims; + u8 rs_flags; + u32 evm0; + u32 evm1; + u32 evm2; +}; + +#define ATH9K_RXERR_CRC 0x01 +#define ATH9K_RXERR_PHY 0x02 +#define ATH9K_RXERR_FIFO 0x04 +#define ATH9K_RXERR_DECRYPT 0x08 +#define ATH9K_RXERR_MIC 0x10 + +#define ATH9K_RX_MORE 0x01 +#define ATH9K_RX_MORE_AGGR 0x02 +#define ATH9K_RX_GI 0x04 +#define ATH9K_RX_2040 0x08 +#define ATH9K_RX_DELIM_CRC_PRE 0x10 +#define ATH9K_RX_DELIM_CRC_POST 0x20 +#define ATH9K_RX_DECRYPT_BUSY 0x40 + +#define ATH9K_RXKEYIX_INVALID ((u8)-1) +#define ATH9K_TXKEYIX_INVALID ((u32)-1) + +struct ath_desc { + u32 ds_link; + u32 ds_data; + u32 ds_ctl0; + u32 ds_ctl1; + u32 ds_hw[20]; + union { + struct ath_tx_status tx; + struct ath_rx_status rx; + void *stats; + } ds_us; + void *ds_vdata; +} __packed; + +#define ds_txstat ds_us.tx +#define ds_rxstat ds_us.rx +#define ds_stat ds_us.stats + +#define ATH9K_TXDESC_CLRDMASK 0x0001 +#define ATH9K_TXDESC_NOACK 0x0002 +#define ATH9K_TXDESC_RTSENA 0x0004 +#define ATH9K_TXDESC_CTSENA 0x0008 +/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for + * the descriptor its marked on. We take a tx interrupt to reap + * descriptors when the h/w hits an EOL condition or + * when the descriptor is specifically marked to generate + * an interrupt with this flag. Descriptors should be + * marked periodically to insure timely replenishing of the + * supply needed for sending frames. Defering interrupts + * reduces system load and potentially allows more concurrent + * work to be done but if done to aggressively can cause + * senders to backup. When the hardware queue is left too + * large rate control information may also be too out of + * date. An Alternative for this is TX interrupt mitigation + * but this needs more testing. */ +#define ATH9K_TXDESC_INTREQ 0x0010 +#define ATH9K_TXDESC_VEOL 0x0020 +#define ATH9K_TXDESC_EXT_ONLY 0x0040 +#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 + +struct ar5416_desc { + u32 ds_link; + u32 ds_data; + u32 ds_ctl0; + u32 ds_ctl1; + union { + struct { + u32 ctl2; + u32 ctl3; + u32 ctl4; + u32 ctl5; + u32 ctl6; + u32 ctl7; + u32 ctl8; + u32 ctl9; + u32 ctl10; + u32 ctl11; + u32 status0; + u32 status1; + u32 status2; + u32 status3; + u32 status4; + u32 status5; + u32 status6; + u32 status7; + u32 status8; + u32 status9; + } tx; + struct { + u32 status0; + u32 status1; + u32 status2; + u32 status3; + u32 status4; + u32 status5; + u32 status6; + u32 status7; + u32 status8; + } rx; + } u; +} __packed; + +#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds)) +#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds)) + +#define ds_ctl2 u.tx.ctl2 +#define ds_ctl3 u.tx.ctl3 +#define ds_ctl4 u.tx.ctl4 +#define ds_ctl5 u.tx.ctl5 +#define ds_ctl6 u.tx.ctl6 +#define ds_ctl7 u.tx.ctl7 +#define ds_ctl8 u.tx.ctl8 +#define ds_ctl9 u.tx.ctl9 +#define ds_ctl10 u.tx.ctl10 +#define ds_ctl11 u.tx.ctl11 + +#define ds_txstatus0 u.tx.status0 +#define ds_txstatus1 u.tx.status1 +#define ds_txstatus2 u.tx.status2 +#define ds_txstatus3 u.tx.status3 +#define ds_txstatus4 u.tx.status4 +#define ds_txstatus5 u.tx.status5 +#define ds_txstatus6 u.tx.status6 +#define ds_txstatus7 u.tx.status7 +#define ds_txstatus8 u.tx.status8 +#define ds_txstatus9 u.tx.status9 + +#define ds_rxstatus0 u.rx.status0 +#define ds_rxstatus1 u.rx.status1 +#define ds_rxstatus2 u.rx.status2 +#define ds_rxstatus3 u.rx.status3 +#define ds_rxstatus4 u.rx.status4 +#define ds_rxstatus5 u.rx.status5 +#define ds_rxstatus6 u.rx.status6 +#define ds_rxstatus7 u.rx.status7 +#define ds_rxstatus8 u.rx.status8 + +#define AR_FrameLen 0x00000fff +#define AR_VirtMoreFrag 0x00001000 +#define AR_TxCtlRsvd00 0x0000e000 +#define AR_XmitPower 0x003f0000 +#define AR_XmitPower_S 16 +#define AR_RTSEnable 0x00400000 +#define AR_VEOL 0x00800000 +#define AR_ClrDestMask 0x01000000 +#define AR_TxCtlRsvd01 0x1e000000 +#define AR_TxIntrReq 0x20000000 +#define AR_DestIdxValid 0x40000000 +#define AR_CTSEnable 0x80000000 + +#define AR_BufLen 0x00000fff +#define AR_TxMore 0x00001000 +#define AR_DestIdx 0x000fe000 +#define AR_DestIdx_S 13 +#define AR_FrameType 0x00f00000 +#define AR_FrameType_S 20 +#define AR_NoAck 0x01000000 +#define AR_InsertTS 0x02000000 +#define AR_CorruptFCS 0x04000000 +#define AR_ExtOnly 0x08000000 +#define AR_ExtAndCtl 0x10000000 +#define AR_MoreAggr 0x20000000 +#define AR_IsAggr 0x40000000 + +#define AR_BurstDur 0x00007fff +#define AR_BurstDur_S 0 +#define AR_DurUpdateEna 0x00008000 +#define AR_XmitDataTries0 0x000f0000 +#define AR_XmitDataTries0_S 16 +#define AR_XmitDataTries1 0x00f00000 +#define AR_XmitDataTries1_S 20 +#define AR_XmitDataTries2 0x0f000000 +#define AR_XmitDataTries2_S 24 +#define AR_XmitDataTries3 0xf0000000 +#define AR_XmitDataTries3_S 28 + +#define AR_XmitRate0 0x000000ff +#define AR_XmitRate0_S 0 +#define AR_XmitRate1 0x0000ff00 +#define AR_XmitRate1_S 8 +#define AR_XmitRate2 0x00ff0000 +#define AR_XmitRate2_S 16 +#define AR_XmitRate3 0xff000000 +#define AR_XmitRate3_S 24 + +#define AR_PacketDur0 0x00007fff +#define AR_PacketDur0_S 0 +#define AR_RTSCTSQual0 0x00008000 +#define AR_PacketDur1 0x7fff0000 +#define AR_PacketDur1_S 16 +#define AR_RTSCTSQual1 0x80000000 + +#define AR_PacketDur2 0x00007fff +#define AR_PacketDur2_S 0 +#define AR_RTSCTSQual2 0x00008000 +#define AR_PacketDur3 0x7fff0000 +#define AR_PacketDur3_S 16 +#define AR_RTSCTSQual3 0x80000000 + +#define AR_AggrLen 0x0000ffff +#define AR_AggrLen_S 0 +#define AR_TxCtlRsvd60 0x00030000 +#define AR_PadDelim 0x03fc0000 +#define AR_PadDelim_S 18 +#define AR_EncrType 0x0c000000 +#define AR_EncrType_S 26 +#define AR_TxCtlRsvd61 0xf0000000 + +#define AR_2040_0 0x00000001 +#define AR_GI0 0x00000002 +#define AR_ChainSel0 0x0000001c +#define AR_ChainSel0_S 2 +#define AR_2040_1 0x00000020 +#define AR_GI1 0x00000040 +#define AR_ChainSel1 0x00000380 +#define AR_ChainSel1_S 7 +#define AR_2040_2 0x00000400 +#define AR_GI2 0x00000800 +#define AR_ChainSel2 0x00007000 +#define AR_ChainSel2_S 12 +#define AR_2040_3 0x00008000 +#define AR_GI3 0x00010000 +#define AR_ChainSel3 0x000e0000 +#define AR_ChainSel3_S 17 +#define AR_RTSCTSRate 0x0ff00000 +#define AR_RTSCTSRate_S 20 +#define AR_TxCtlRsvd70 0xf0000000 + +#define AR_TxRSSIAnt00 0x000000ff +#define AR_TxRSSIAnt00_S 0 +#define AR_TxRSSIAnt01 0x0000ff00 +#define AR_TxRSSIAnt01_S 8 +#define AR_TxRSSIAnt02 0x00ff0000 +#define AR_TxRSSIAnt02_S 16 +#define AR_TxStatusRsvd00 0x3f000000 +#define AR_TxBaStatus 0x40000000 +#define AR_TxStatusRsvd01 0x80000000 + +#define AR_FrmXmitOK 0x00000001 +#define AR_ExcessiveRetries 0x00000002 +#define AR_FIFOUnderrun 0x00000004 +#define AR_Filtered 0x00000008 +#define AR_RTSFailCnt 0x000000f0 +#define AR_RTSFailCnt_S 4 +#define AR_DataFailCnt 0x00000f00 +#define AR_DataFailCnt_S 8 +#define AR_VirtRetryCnt 0x0000f000 +#define AR_VirtRetryCnt_S 12 +#define AR_TxDelimUnderrun 0x00010000 +#define AR_TxDataUnderrun 0x00020000 +#define AR_DescCfgErr 0x00040000 +#define AR_TxTimerExpired 0x00080000 +#define AR_TxStatusRsvd10 0xfff00000 + +#define AR_SendTimestamp ds_txstatus2 +#define AR_BaBitmapLow ds_txstatus3 +#define AR_BaBitmapHigh ds_txstatus4 + +#define AR_TxRSSIAnt10 0x000000ff +#define AR_TxRSSIAnt10_S 0 +#define AR_TxRSSIAnt11 0x0000ff00 +#define AR_TxRSSIAnt11_S 8 +#define AR_TxRSSIAnt12 0x00ff0000 +#define AR_TxRSSIAnt12_S 16 +#define AR_TxRSSICombined 0xff000000 +#define AR_TxRSSICombined_S 24 + +#define AR_TxEVM0 ds_txstatus5 +#define AR_TxEVM1 ds_txstatus6 +#define AR_TxEVM2 ds_txstatus7 + +#define AR_TxDone 0x00000001 +#define AR_SeqNum 0x00001ffe +#define AR_SeqNum_S 1 +#define AR_TxStatusRsvd80 0x0001e000 +#define AR_TxOpExceeded 0x00020000 +#define AR_TxStatusRsvd81 0x001c0000 +#define AR_FinalTxIdx 0x00600000 +#define AR_FinalTxIdx_S 21 +#define AR_TxStatusRsvd82 0x01800000 +#define AR_PowerMgmt 0x02000000 +#define AR_TxStatusRsvd83 0xfc000000 + +#define AR_RxCTLRsvd00 0xffffffff + +#define AR_BufLen 0x00000fff +#define AR_RxCtlRsvd00 0x00001000 +#define AR_RxIntrReq 0x00002000 +#define AR_RxCtlRsvd01 0xffffc000 + +#define AR_RxRSSIAnt00 0x000000ff +#define AR_RxRSSIAnt00_S 0 +#define AR_RxRSSIAnt01 0x0000ff00 +#define AR_RxRSSIAnt01_S 8 +#define AR_RxRSSIAnt02 0x00ff0000 +#define AR_RxRSSIAnt02_S 16 +#define AR_RxRate 0xff000000 +#define AR_RxRate_S 24 +#define AR_RxStatusRsvd00 0xff000000 + +#define AR_DataLen 0x00000fff +#define AR_RxMore 0x00001000 +#define AR_NumDelim 0x003fc000 +#define AR_NumDelim_S 14 +#define AR_RxStatusRsvd10 0xff800000 + +#define AR_RcvTimestamp ds_rxstatus2 + +#define AR_GI 0x00000001 +#define AR_2040 0x00000002 +#define AR_Parallel40 0x00000004 +#define AR_Parallel40_S 2 +#define AR_RxStatusRsvd30 0x000000f8 +#define AR_RxAntenna 0xffffff00 +#define AR_RxAntenna_S 8 + +#define AR_RxRSSIAnt10 0x000000ff +#define AR_RxRSSIAnt10_S 0 +#define AR_RxRSSIAnt11 0x0000ff00 +#define AR_RxRSSIAnt11_S 8 +#define AR_RxRSSIAnt12 0x00ff0000 +#define AR_RxRSSIAnt12_S 16 +#define AR_RxRSSICombined 0xff000000 +#define AR_RxRSSICombined_S 24 + +#define AR_RxEVM0 ds_rxstatus4 +#define AR_RxEVM1 ds_rxstatus5 +#define AR_RxEVM2 ds_rxstatus6 + +#define AR_RxDone 0x00000001 +#define AR_RxFrameOK 0x00000002 +#define AR_CRCErr 0x00000004 +#define AR_DecryptCRCErr 0x00000008 +#define AR_PHYErr 0x00000010 +#define AR_MichaelErr 0x00000020 +#define AR_PreDelimCRCErr 0x00000040 +#define AR_RxStatusRsvd70 0x00000080 +#define AR_RxKeyIdxValid 0x00000100 +#define AR_KeyIdx 0x0000fe00 +#define AR_KeyIdx_S 9 +#define AR_PHYErrCode 0x0000ff00 +#define AR_PHYErrCode_S 8 +#define AR_RxMoreAggr 0x00010000 +#define AR_RxAggr 0x00020000 +#define AR_PostDelimCRCErr 0x00040000 +#define AR_RxStatusRsvd71 0x3ff80000 +#define AR_DecryptBusyErr 0x40000000 +#define AR_KeyMiss 0x80000000 + +enum ath9k_tx_queue { + ATH9K_TX_QUEUE_INACTIVE = 0, + ATH9K_TX_QUEUE_DATA, + ATH9K_TX_QUEUE_BEACON, + ATH9K_TX_QUEUE_CAB, + ATH9K_TX_QUEUE_UAPSD, + ATH9K_TX_QUEUE_PSPOLL +}; + +#define ATH9K_NUM_TX_QUEUES 10 + +enum ath9k_tx_queue_subtype { + ATH9K_WME_AC_BK = 0, + ATH9K_WME_AC_BE, + ATH9K_WME_AC_VI, + ATH9K_WME_AC_VO, + ATH9K_WME_UPSD +}; + +enum ath9k_tx_queue_flags { + TXQ_FLAG_TXOKINT_ENABLE = 0x0001, + TXQ_FLAG_TXERRINT_ENABLE = 0x0001, + TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, + TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, + TXQ_FLAG_TXURNINT_ENABLE = 0x0008, + TXQ_FLAG_BACKOFF_DISABLE = 0x0010, + TXQ_FLAG_COMPRESSION_ENABLE = 0x0020, + TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040, + TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080, +}; + +#define ATH9K_TXQ_USEDEFAULT ((u32) -1) +#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 + +#define ATH9K_DECOMP_MASK_SIZE 128 +#define ATH9K_READY_TIME_LO_BOUND 50 +#define ATH9K_READY_TIME_HI_BOUND 96 + +enum ath9k_pkt_type { + ATH9K_PKT_TYPE_NORMAL = 0, + ATH9K_PKT_TYPE_ATIM, + ATH9K_PKT_TYPE_PSPOLL, + ATH9K_PKT_TYPE_BEACON, + ATH9K_PKT_TYPE_PROBE_RESP, + ATH9K_PKT_TYPE_CHIRP, + ATH9K_PKT_TYPE_GRP_POLL, +}; + +struct ath9k_tx_queue_info { + u32 tqi_ver; + enum ath9k_tx_queue tqi_type; + enum ath9k_tx_queue_subtype tqi_subtype; + enum ath9k_tx_queue_flags tqi_qflags; + u32 tqi_priority; + u32 tqi_aifs; + u32 tqi_cwmin; + u32 tqi_cwmax; + u16 tqi_shretry; + u16 tqi_lgretry; + u32 tqi_cbrPeriod; + u32 tqi_cbrOverflowLimit; + u32 tqi_burstTime; + u32 tqi_readyTime; + u32 tqi_physCompBuf; + u32 tqi_intFlags; +}; + +enum ath9k_rx_filter { + ATH9K_RX_FILTER_UCAST = 0x00000001, + ATH9K_RX_FILTER_MCAST = 0x00000002, + ATH9K_RX_FILTER_BCAST = 0x00000004, + ATH9K_RX_FILTER_CONTROL = 0x00000008, + ATH9K_RX_FILTER_BEACON = 0x00000010, + ATH9K_RX_FILTER_PROM = 0x00000020, + ATH9K_RX_FILTER_PROBEREQ = 0x00000080, + ATH9K_RX_FILTER_PHYERR = 0x00000100, + ATH9K_RX_FILTER_MYBEACON = 0x00000200, + ATH9K_RX_FILTER_PSPOLL = 0x00004000, + ATH9K_RX_FILTER_PHYRADAR = 0x00002000, + ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, +}; + +#define ATH9K_RATESERIES_RTS_CTS 0x0001 +#define ATH9K_RATESERIES_2040 0x0002 +#define ATH9K_RATESERIES_HALFGI 0x0004 + +struct ath9k_11n_rate_series { + u32 Tries; + u32 Rate; + u32 PktDuration; + u32 ChSel; + u32 RateFlags; +}; + +struct ath9k_keyval { + u8 kv_type; + u8 kv_pad; + u16 kv_len; + u8 kv_val[16]; /* TK */ + u8 kv_mic[8]; /* Michael MIC key */ + u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware + * supports both MIC keys in the same key cache entry; + * in that case, kv_mic is the RX key) */ +}; + +enum ath9k_key_type { + ATH9K_KEY_TYPE_CLEAR, + ATH9K_KEY_TYPE_WEP, + ATH9K_KEY_TYPE_AES, + ATH9K_KEY_TYPE_TKIP, +}; + +enum ath9k_cipher { + ATH9K_CIPHER_WEP = 0, + ATH9K_CIPHER_AES_OCB = 1, + ATH9K_CIPHER_AES_CCM = 2, + ATH9K_CIPHER_CKIP = 3, + ATH9K_CIPHER_TKIP = 4, + ATH9K_CIPHER_CLR = 5, + ATH9K_CIPHER_MIC = 127 +}; + +enum ath9k_ht_macmode { + ATH9K_HT_MACMODE_20 = 0, + ATH9K_HT_MACMODE_2040 = 1, +}; + +enum ath9k_ht_extprotspacing { + ATH9K_HT_EXTPROTSPACING_20 = 0, + ATH9K_HT_EXTPROTSPACING_25 = 1, +}; + +struct ath_hw; +struct ath9k_channel; +struct ath_rate_table; + +u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); +bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); +bool ath9k_hw_txstart(struct ath_hw *ah, u32 q); +u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); +bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); +bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); +bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0); +void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); +int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds); +void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags); +void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, + struct ath_desc *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags); +void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, + u32 aggrLen); +void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, + u32 numDelims); +void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds); +void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds); +void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, + u32 burstDuration); +void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, + u32 vmf); +void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); +bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, + const struct ath9k_tx_queue_info *qinfo); +bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, + struct ath9k_tx_queue_info *qinfo); +int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo); +bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); +bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); +int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf); +bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 size, u32 flags); +bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); +void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); +void ath9k_hw_rxena(struct ath_hw *ah); +void ath9k_hw_startpcureceive(struct ath_hw *ah); +void ath9k_hw_stoppcurecv(struct ath_hw *ah); +bool ath9k_hw_stopdmarecv(struct ath_hw *ah); + +#endif /* MAC_H */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c new file mode 100644 index 0000000..8b6a7ea --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -0,0 +1,2890 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "ath9k.h" + +#define ATH_PCI_VERSION "0.1" + +static char *dev_info = "ath9k"; + +MODULE_AUTHOR("Atheros Communications"); +MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); +MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); +MODULE_LICENSE("Dual BSD/GPL"); + +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +/* We use the hw_value as an index into our private channel structure */ + +#define CHAN2G(_freq, _idx) { \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; + +static void ath_cache_conf_rate(struct ath_softc *sc, + struct ieee80211_conf *conf) +{ + switch (conf->channel->band) { + case IEEE80211_BAND_2GHZ: + if (conf_is_ht20(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NG_HT20]; + else if (conf_is_ht40_minus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS]; + else if (conf_is_ht40_plus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS]; + else + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11G]; + break; + case IEEE80211_BAND_5GHZ: + if (conf_is_ht20(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NA_HT20]; + else if (conf_is_ht40_minus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS]; + else if (conf_is_ht40_plus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS]; + else + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11A]; + break; + default: + BUG_ON(1); + break; + } +} + +static void ath_update_txpow(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + u32 txpow; + + if (sc->curtxpow != sc->config.txpowlimit) { + ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit); + /* read back in case value is clamped */ + ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); + sc->curtxpow = txpow; + } +} + +static u8 parse_mpdudensity(u8 mpdudensity) +{ + /* + * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": + * 0 for no restriction + * 1 for 1/4 us + * 2 for 1/2 us + * 3 for 1 us + * 4 for 2 us + * 5 for 4 us + * 6 for 8 us + * 7 for 16 us + */ + switch (mpdudensity) { + case 0: + return 0; + case 1: + case 2: + case 3: + /* Our lower layer calculations limit our precision to + 1 microsecond */ + return 1; + case 4: + return 2; + case 5: + return 4; + case 6: + return 8; + case 7: + return 16; + default: + return 0; + } +} + +static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) +{ + struct ath_rate_table *rate_table = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + int i, maxrates; + + switch (band) { + case IEEE80211_BAND_2GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; + break; + case IEEE80211_BAND_5GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; + break; + default: + break; + } + + if (rate_table == NULL) + return; + + sband = &sc->sbands[band]; + rate = sc->rates[band]; + + if (rate_table->rate_cnt > ATH_RATE_MAX) + maxrates = ATH_RATE_MAX; + else + maxrates = rate_table->rate_cnt; + + for (i = 0; i < maxrates; i++) { + rate[i].bitrate = rate_table->info[i].ratekbps / 100; + rate[i].hw_value = rate_table->info[i].ratecode; + if (rate_table->info[i].short_preamble) { + rate[i].hw_value_short = rate_table->info[i].ratecode | + rate_table->info[i].short_preamble; + rate[i].flags = IEEE80211_RATE_SHORT_PREAMBLE; + } + sband->n_bitrates++; + + DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", + rate[i].bitrate / 10, rate[i].hw_value); + } +} + +/* + * Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending + * DMA, then restart stuff. +*/ +int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *hchan) +{ + struct ath_hw *ah = sc->sc_ah; + bool fastcc = true, stopped; + struct ieee80211_channel *channel = hw->conf.channel; + int r; + + if (sc->sc_flags & SC_OP_INVALID) + return -EIO; + + ath9k_ps_wakeup(sc); + + /* + * This is only performed if the channel settings have + * actually changed. + * + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath9k_hw_set_interrupts(ah, 0); + ath_drain_all_txq(sc, false); + stopped = ath_stoprecv(sc); + + /* XXX: do not flush receive queue here. We don't want + * to flush data frames already in queue because of + * changing channel. */ + + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) + fastcc = false; + + DPRINTF(sc, ATH_DBG_CONFIG, + "(%u MHz) -> (%u MHz), chanwidth: %d\n", + sc->sc_ah->curchan->channel, + channel->center_freq, sc->tx_chan_width); + + spin_lock_bh(&sc->sc_resetlock); + + r = ath9k_hw_reset(ah, hchan, fastcc); + if (r) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset channel (%u Mhz) " + "reset status %u\n", + channel->center_freq, r); + spin_unlock_bh(&sc->sc_resetlock); + return r; + } + spin_unlock_bh(&sc->sc_resetlock); + + sc->sc_flags &= ~SC_OP_FULL_RESET; + + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to restart recv logic\n"); + return -EIO; + } + + ath_cache_conf_rate(sc, &hw->conf); + ath_update_txpow(sc); + ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_ps_restore(sc); + return 0; +} + +/* + * 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. + */ +static void ath_ani_calibrate(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + struct ath_hw *ah = sc->sc_ah; + bool longcal = false; + bool shortcal = false; + bool aniflag = false; + unsigned int timestamp = jiffies_to_msecs(jiffies); + u32 cal_interval, short_cal_interval; + + short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? + ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; + + /* + * don't calibrate when we're scanning. + * we are most likely not on our home channel. + */ + if (sc->sc_flags & SC_OP_SCANNING) + goto set_timer; + + /* Long calibration runs independently of short calibration. */ + if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { + longcal = true; + DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); + sc->ani.longcal_timer = timestamp; + } + + /* Short calibration applies only while caldone is false */ + if (!sc->ani.caldone) { + if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { + shortcal = true; + DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); + sc->ani.shortcal_timer = timestamp; + sc->ani.resetcal_timer = timestamp; + } + } else { + if ((timestamp - sc->ani.resetcal_timer) >= + ATH_RESTART_CALINTERVAL) { + sc->ani.caldone = ath9k_hw_reset_calvalid(ah); + if (sc->ani.caldone) + sc->ani.resetcal_timer = timestamp; + } + } + + /* Verify whether we must check ANI */ + if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { + aniflag = true; + sc->ani.checkani_timer = timestamp; + } + + /* 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->nodestats, ah->curchan); + + /* Perform calibration if necessary */ + if (longcal || shortcal) { + bool iscaldone = false; + + if (ath9k_hw_calibrate(ah, ah->curchan, + sc->rx_chainmask, longcal, + &iscaldone)) { + if (longcal) + sc->ani.noise_floor = + ath9k_hw_getchan_noise(ah, + ah->curchan); + + DPRINTF(sc, ATH_DBG_ANI, + "calibrate chan %u/%x nf: %d\n", + ah->curchan->channel, + ah->curchan->channelFlags, + sc->ani.noise_floor); + } else { + DPRINTF(sc, ATH_DBG_ANY, + "calibrate chan %u/%x failed\n", + ah->curchan->channel, + ah->curchan->channelFlags); + } + sc->ani.caldone = iscaldone; + } + } + +set_timer: + /* + * Set timer interval based on previous results. + * The interval must be the shortest necessary to satisfy ANI, + * short calibration and long calibration. + */ + cal_interval = ATH_LONG_CALINTERVAL; + if (sc->sc_ah->config.enable_ani) + cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); + if (!sc->ani.caldone) + cal_interval = min(cal_interval, (u32)short_cal_interval); + + mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); +} + +/* + * Update tx/rx chainmask. For legacy association, + * hard code chainmask to 1x1, for 11n association, use + * the chainmask configuration, for bt coexistence, use + * the chainmask configuration even in legacy mode. + */ +void ath_update_chainmask(struct ath_softc *sc, int is_ht) +{ + if (is_ht || + (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { + sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; + sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; + } else { + sc->tx_chainmask = 1; + sc->rx_chainmask = 1; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", + sc->tx_chainmask, sc->rx_chainmask); +} + +static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) +{ + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) { + ath_tx_node_init(sc, an); + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + } +} + +static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_cleanup(sc, an); +} + +static void ath9k_tasklet(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + u32 status = sc->intrstatus; + + if (status & ATH9K_INT_FATAL) { + ath_reset(sc, false); + return; + } + + if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { + spin_lock_bh(&sc->rx.rxflushlock); + ath_rx_tasklet(sc, 0); + spin_unlock_bh(&sc->rx.rxflushlock); + } + + if (status & ATH9K_INT_TX) + ath_tx_tasklet(sc); + + /* re-enable hardware interrupt */ + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); +} + +irqreturn_t ath_isr(int irq, void *dev) +{ +#define SCHED_INTR ( \ + ATH9K_INT_FATAL | \ + ATH9K_INT_RXORN | \ + ATH9K_INT_RXEOL | \ + ATH9K_INT_RX | \ + ATH9K_INT_TX | \ + ATH9K_INT_BMISS | \ + ATH9K_INT_CST | \ + ATH9K_INT_TSFOOR) + + struct ath_softc *sc = dev; + struct ath_hw *ah = sc->sc_ah; + enum ath9k_int status; + bool sched = false; + + /* + * The hardware is not ready/present, don't + * touch anything. Note this can happen early + * on if the IRQ is shared. + */ + if (sc->sc_flags & SC_OP_INVALID) + return IRQ_NONE; + + ath9k_ps_wakeup(sc); + + /* shared irq, not for us */ + + if (!ath9k_hw_intrpend(ah)) { + ath9k_ps_restore(sc); + return IRQ_NONE; + } + + /* + * Figure out the reason(s) for the interrupt. Note + * that the hal returns a pseudo-ISR that may include + * bits we haven't explicitly enabled so we mask the + * value to insure we only process bits we requested. + */ + ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + status &= sc->imask; /* discard unasked-for bits */ + + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). + */ + if (!status) { + ath9k_ps_restore(sc); + return IRQ_NONE; + } + + /* Cache the status */ + sc->intrstatus = status; + + if (status & SCHED_INTR) + sched = true; + + /* + * If a FATAL or RXORN interrupt is received, we have to reset the + * chip immediately. + */ + if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN)) + goto chip_reset; + + if (status & ATH9K_INT_SWBA) + tasklet_schedule(&sc->bcon_tasklet); + + if (status & ATH9K_INT_TXURN) + ath9k_hw_updatetxtriglevel(ah, true); + + if (status & ATH9K_INT_MIB) { + /* + * Disable interrupts until we service the MIB + * interrupt; otherwise it will continue to + * fire. + */ + ath9k_hw_set_interrupts(ah, 0); + /* + * Let the hal handle the event. We assume + * it will clear whatever condition caused + * the interrupt. + */ + ath9k_hw_procmibevent(ah, &sc->nodestats); + ath9k_hw_set_interrupts(ah, sc->imask); + } + + if (status & ATH9K_INT_TIM_TIMER) { + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + /* Clear RxAbort bit so that we can + * receive frames */ + ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); + ath9k_hw_setrxabort(ah, 0); + sched = true; + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; + } + } + +chip_reset: + + ath9k_ps_restore(sc); + ath_debug_stat_interrupt(sc, status); + + if (sched) { + /* turn off every interrupt except SWBA */ + ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA)); + tasklet_schedule(&sc->intr_tq); + } + + return IRQ_HANDLED; + +#undef SCHED_INTR +} + +static u32 ath_get_extchanmode(struct ath_softc *sc, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + u32 chanmode = 0; + + switch (chan->band) { + case IEEE80211_BAND_2GHZ: + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_G_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_G_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_G_HT40MINUS; + break; + } + break; + case IEEE80211_BAND_5GHZ: + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_A_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_A_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_A_HT40MINUS; + break; + } + break; + default: + break; + } + + return chanmode; +} + +static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, + struct ath9k_keyval *hk, const u8 *addr, + bool authenticator) +{ + const u8 *key_rxmic; + const u8 *key_txmic; + + key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; + key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; + + if (addr == NULL) { + /* + * Group key installation - only two key cache entries are used + * regardless of splitmic capability since group key is only + * used either for TX or RX. + */ + if (authenticator) { + memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); + } else { + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); + } + return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); + } + if (!sc->splitmic) { + /* TX and RX keys share the same key cache entry. */ + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); + return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); + } + + /* Separate key cache entries for TX and RX */ + + /* TX key goes at first index, RX key at +32. */ + memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); + if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { + /* TX MIC entry failed. No need to proceed further */ + DPRINTF(sc, ATH_DBG_FATAL, + "Setting TX MIC Key Failed\n"); + return 0; + } + + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + /* XXX delete tx key on failure? */ + return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr); +} + +static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) +{ + int i; + + for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { + if (test_bit(i, sc->keymap) || + test_bit(i + 64, sc->keymap)) + continue; /* At least one part of TKIP key allocated */ + if (sc->splitmic && + (test_bit(i + 32, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) + continue; /* At least one part of TKIP key allocated */ + + /* Found a free slot for a TKIP key */ + return i; + } + return -1; +} + +static int ath_reserve_key_cache_slot(struct ath_softc *sc) +{ + int i; + + /* First, try to find slots that would not be available for TKIP. */ + if (sc->splitmic) { + for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) { + if (!test_bit(i, sc->keymap) && + (test_bit(i + 32, sc->keymap) || + test_bit(i + 64, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) + return i; + if (!test_bit(i + 32, sc->keymap) && + (test_bit(i, sc->keymap) || + test_bit(i + 64, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) + return i + 32; + if (!test_bit(i + 64, sc->keymap) && + (test_bit(i , sc->keymap) || + test_bit(i + 32, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) + return i + 64; + if (!test_bit(i + 64 + 32, sc->keymap) && + (test_bit(i, sc->keymap) || + test_bit(i + 32, sc->keymap) || + test_bit(i + 64, sc->keymap))) + return i + 64 + 32; + } + } else { + for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { + if (!test_bit(i, sc->keymap) && + test_bit(i + 64, sc->keymap)) + return i; + if (test_bit(i, sc->keymap) && + !test_bit(i + 64, sc->keymap)) + return i + 64; + } + } + + /* No partially used TKIP slots, pick any available slot */ + for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) { + /* Do not allow slots that could be needed for TKIP group keys + * to be used. This limitation could be removed if we know that + * TKIP will not be used. */ + if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) + continue; + if (sc->splitmic) { + if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) + continue; + if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) + continue; + } + + if (!test_bit(i, sc->keymap)) + return i; /* Found a free slot for a key */ + } + + /* No free slot found */ + return -1; +} + +static int ath_key_config(struct ath_softc *sc, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ath9k_keyval hk; + const u8 *mac = NULL; + int ret = 0; + int idx; + + memset(&hk, 0, sizeof(hk)); + + switch (key->alg) { + case ALG_WEP: + hk.kv_type = ATH9K_CIPHER_WEP; + break; + case ALG_TKIP: + hk.kv_type = ATH9K_CIPHER_TKIP; + break; + case ALG_CCMP: + hk.kv_type = ATH9K_CIPHER_AES_CCM; + break; + default: + return -EOPNOTSUPP; + } + + hk.kv_len = key->keylen; + memcpy(hk.kv_val, key->key, key->keylen); + + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* For now, use the default keys for broadcast keys. This may + * need to change with virtual interfaces. */ + idx = key->keyidx; + } else if (key->keyidx) { + if (WARN_ON(!sta)) + return -EOPNOTSUPP; + mac = sta->addr; + + if (vif->type != NL80211_IFTYPE_AP) { + /* Only keyidx 0 should be used with unicast key, but + * allow this for client mode for now. */ + idx = key->keyidx; + } else + return -EIO; + } else { + if (WARN_ON(!sta)) + return -EOPNOTSUPP; + mac = sta->addr; + + if (key->alg == ALG_TKIP) + idx = ath_reserve_key_cache_slot_tkip(sc); + else + idx = ath_reserve_key_cache_slot(sc); + if (idx < 0) + return -ENOSPC; /* no free key cache entries */ + } + + if (key->alg == ALG_TKIP) + ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac, + vif->type == NL80211_IFTYPE_AP); + else + ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac); + + if (!ret) + return -EIO; + + set_bit(idx, sc->keymap); + if (key->alg == ALG_TKIP) { + set_bit(idx + 64, sc->keymap); + if (sc->splitmic) { + set_bit(idx + 32, sc->keymap); + set_bit(idx + 64 + 32, sc->keymap); + } + } + + return idx; +} + +static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) +{ + ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx); + if (key->hw_key_idx < IEEE80211_WEP_NKID) + return; + + clear_bit(key->hw_key_idx, sc->keymap); + if (key->alg != ALG_TKIP) + return; + + clear_bit(key->hw_key_idx + 64, sc->keymap); + if (sc->splitmic) { + clear_bit(key->hw_key_idx + 32, sc->keymap); + clear_bit(key->hw_key_idx + 64 + 32, sc->keymap); + } +} + +static void setup_ht_cap(struct ath_softc *sc, + struct ieee80211_sta_ht_cap *ht_info) +{ +#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ +#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; + ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; + + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + + switch(sc->rx_chainmask) { + case 1: + ht_info->mcs.rx_mask[0] = 0xff; + break; + case 3: + case 5: + case 7: + default: + ht_info->mcs.rx_mask[0] = 0xff; + ht_info->mcs.rx_mask[1] = 0xff; + break; + } + + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +} + +static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) +{ + struct ath_vif *avp = (void *)vif->drv_priv; + + if (bss_conf->assoc) { + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, sc->curbssid); + + /* New association, store aid */ + if (avp->av_opmode == NL80211_IFTYPE_STATION) { + sc->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc); + } + + /* Configure the beacon */ + ath_beacon_config(sc, vif); + + /* Reset rssi stats */ + sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + + /* Start ANI */ + mod_timer(&sc->ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + } else { + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); + sc->curaid = 0; + } +} + +/********************************/ +/* LED functions */ +/********************************/ + +static void ath_led_blink_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + ath_led_blink_work.work); + + if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) + return; + + if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || + (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + else + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); + + queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work, + (sc->sc_flags & SC_OP_LED_ON) ? + msecs_to_jiffies(sc->led_off_duration) : + msecs_to_jiffies(sc->led_on_duration)); + + sc->led_on_duration = sc->led_on_cnt ? + max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : + ATH_LED_ON_DURATION_IDLE; + sc->led_off_duration = sc->led_off_cnt ? + max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : + ATH_LED_OFF_DURATION_IDLE; + sc->led_on_cnt = sc->led_off_cnt = 0; + if (sc->sc_flags & SC_OP_LED_ON) + sc->sc_flags &= ~SC_OP_LED_ON; + else + sc->sc_flags |= SC_OP_LED_ON; +} + +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) { + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (led->led_type == ATH_LED_RADIO)); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + if (led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ON; + } else { + sc->led_off_cnt++; + } + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) { + sc->sc_flags |= SC_OP_LED_ASSOCIATED; + queue_delayed_work(sc->hw->workqueue, + &sc->ath_led_blink_work, 0); + } else if (led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + sc->sc_flags |= SC_OP_LED_ON; + } else { + sc->led_on_cnt++; + } + 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) +{ + cancel_delayed_work_sync(&sc->ath_led_blink_work); + 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); + + INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); + + 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); +} + +void ath_radio_enable(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_channel *channel = sc->hw->conf.channel; + int r; + + ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_resetlock); + + r = ath9k_hw_reset(ah, ah->curchan, false); + + if (r) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset channel %u (%uMhz) ", + "reset status %u\n", + channel->center_freq, r); + } + spin_unlock_bh(&sc->sc_resetlock); + + ath_update_txpow(sc); + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to restart recv logic\n"); + return; + } + + if (sc->sc_flags & SC_OP_BEACONS) + ath_beacon_config(sc, NULL); /* restart beacons */ + + /* Re-Enable interrupts */ + ath9k_hw_set_interrupts(ah, 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); + ath9k_ps_restore(sc); +} + +void ath_radio_disable(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_channel *channel = sc->hw->conf.channel; + int r; + + ath9k_ps_wakeup(sc); + 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_drain_all_txq(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); + r = ath9k_hw_reset(ah, ah->curchan, false); + if (r) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset channel %u (%uMhz) " + "reset status %u\n", + channel->center_freq, r); + } + spin_unlock_bh(&sc->sc_resetlock); + + ath9k_hw_phy_disable(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + ath9k_ps_restore(sc); +} + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + +/*******************/ +/* Rfkill */ +/*******************/ + +static bool ath_is_rfkill_set(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == + 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; + + return 0; +} + +/* Deinitialize rfkill */ +static void ath_deinit_rfkill(struct ath_softc *sc) +{ + if (sc->sc_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; + } +} + +static int ath_start_rfkill_poll(struct ath_softc *sc) +{ + if (sc->sc_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 */ + ath_cleanup(sc); + return -EIO; + } else { + sc->sc_flags |= SC_OP_RFKILL_REGISTERED; + } + } + + return 0; +} +#endif /* CONFIG_RFKILL */ + +void ath_cleanup(struct ath_softc *sc) +{ + ath_detach(sc); + free_irq(sc->irq, sc); + ath_bus_cleanup(sc); + kfree(sc->sec_wiphy); + ieee80211_free_hw(sc->hw); +} + +void ath_detach(struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + int i = 0; + + ath9k_ps_wakeup(sc); + + DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + ath_deinit_rfkill(sc); +#endif + ath_deinit_leds(sc); + cancel_work_sync(&sc->chan_work); + cancel_delayed_work_sync(&sc->wiphy_work); + + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + sc->sec_wiphy[i] = NULL; + ieee80211_unregister_hw(aphy->hw); + ieee80211_free_hw(aphy->hw); + } + ieee80211_unregister_hw(hw); + ath_rx_cleanup(sc); + ath_tx_cleanup(sc); + + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); + + if (!(sc->sc_flags & SC_OP_INVALID)) + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + ath9k_hw_detach(sc->sc_ah); + ath9k_exit_debug(sc); + ath9k_ps_restore(sc); +} + +static int ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_regulatory *reg = &sc->sc_ah->regulatory; + + return ath_reg_notifier_apply(wiphy, request, reg); +} + +static int ath_init(u16 devid, struct ath_softc *sc) +{ + struct ath_hw *ah = NULL; + int status; + int error = 0, i; + int csz = 0; + + /* XXX: hardware will not be ready until ath_open() being called */ + sc->sc_flags |= SC_OP_INVALID; + + if (ath9k_init_debug(sc) < 0) + printk(KERN_ERR "Unable to create debugfs files\n"); + + spin_lock_init(&sc->wiphy_lock); + spin_lock_init(&sc->sc_resetlock); + spin_lock_init(&sc->sc_serial_rw); + mutex_init(&sc->mutex); + tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); + tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, + (unsigned long)sc); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + ath_read_cachesize(sc, &csz); + /* XXX assert csz is non-zero */ + sc->cachelsz = csz << 2; /* convert to bytes */ + + ah = ath9k_hw_attach(devid, sc, &status); + if (ah == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to attach hardware; HAL status %d\n", status); + error = -ENXIO; + goto bad; + } + sc->sc_ah = ah; + + /* Get the hardware key cache size. */ + sc->keymax = ah->caps.keycache_size; + if (sc->keymax > ATH_KEYMAX) { + DPRINTF(sc, ATH_DBG_ANY, + "Warning, using only %u entries in %u key cache\n", + ATH_KEYMAX, sc->keymax); + sc->keymax = ATH_KEYMAX; + } + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < sc->keymax; i++) + ath9k_hw_keyreset(ah, (u16) i); + + if (ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + ath9k_reg_notifier)) + goto bad; + + /* default to MONITOR mode */ + sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; + + /* Setup rate tables */ + + ath_rate_attach(sc); + ath_setup_rates(sc, IEEE80211_BAND_2GHZ); + ath_setup_rates(sc, IEEE80211_BAND_5GHZ); + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that the hal handles reseting + * these queues at the needed time. + */ + sc->beacon.beaconq = ath_beaconq_setup(ah); + if (sc->beacon.beaconq == -1) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup a beacon xmit queue\n"); + error = -EIO; + goto bad2; + } + sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); + if (sc->beacon.cabq == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup CAB xmit queue\n"); + error = -EIO; + goto bad2; + } + + sc->config.cabqReadytime = ATH_CABQ_READY_TIME; + ath_cabq_update(sc); + + for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) + sc->tx.hwq_map[i] = -1; + + /* Setup data queues */ + /* NB: ensure BK queue is the lowest priority h/w queue */ + if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for BK traffic\n"); + error = -EIO; + goto bad2; + } + + if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for BE traffic\n"); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for VI traffic\n"); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for VO traffic\n"); + error = -EIO; + goto bad2; + } + + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + + sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc); + + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, + 0, 1, NULL); + } + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + sc->splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, + 1, NULL); + + sc->config.txpowlimit = ATH_TXPOWER_MAX; + + /* 11n Capabilities */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; + } + + sc->tx_chainmask = ah->caps.tx_chainmask; + sc->rx_chainmask = ah->caps.rx_chainmask; + + ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + sc->rx.defant = ath9k_hw_getdefantenna(ah); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); + + sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + + /* initialize beacon slots */ + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + sc->beacon.bslot[i] = NULL; + sc->beacon.bslot_aphy[i] = NULL; + } + + /* setup channels and rates */ + + sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = + sc->rates[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + sc->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + sc->rates[IEEE80211_BAND_5GHZ]; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + sc->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + } + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) + ath9k_hw_btcoex_enable(sc->sc_ah); + + return 0; +bad2: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); +bad: + if (ah) + ath9k_hw_detach(ah); + ath9k_exit_debug(sc); + + return error; +} + +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) +{ + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_SPECTRUM_MGMT; + + if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + + hw->queues = 4; + hw->max_rates = 4; + hw->channel_change_time = 5000; + hw->max_listen_interval = 10; + hw->max_rate_tries = ATH_11N_TXMAXTRY; + hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vif); + + hw->rate_control_algorithm = "ath9k_rate_control"; + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; +} + +int ath_attach(u16 devid, struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + int error = 0, i; + struct ath_regulatory *reg; + + DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); + + error = ath_init(devid, sc); + if (error != 0) + return error; + + reg = &sc->sc_ah->regulatory; + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); + + ath_set_hw_capab(sc, hw); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } + + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto error_attach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto error_attach; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /* Initialze h/w Rfkill */ + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); + + /* Initialize s/w rfkill */ + error = ath_init_sw_rfkill(sc); + if (error) + goto error_attach; +#endif + + INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); + INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); + sc->wiphy_scheduler_int = msecs_to_jiffies(500); + + error = ieee80211_register_hw(hw); + + if (!ath_is_world_regd(reg)) { + error = regulatory_hint(hw->wiphy, reg->alpha2); + if (error) + goto error_attach; + } + + /* Initialize LED control */ + ath_init_leds(sc); + + + return 0; + +error_attach: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + ath9k_hw_detach(sc->sc_ah); + ath9k_exit_debug(sc); + + return error; +} + +int ath_reset(struct ath_softc *sc, bool retry_tx) +{ + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_hw *hw = sc->hw; + int r; + + ath9k_hw_set_interrupts(ah, 0); + ath_drain_all_txq(sc, retry_tx); + ath_stoprecv(sc); + ath_flushrecv(sc); + + spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); + if (r) + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %u\n", r); + spin_unlock_bh(&sc->sc_resetlock); + + if (ath_startrecv(sc) != 0) + DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); + + /* + * We may be doing a reset in response to a request + * that changes the channel so update any state that + * might change as a result. + */ + ath_cache_conf_rate(sc, &hw->conf); + + ath_update_txpow(sc); + + if (sc->sc_flags & SC_OP_BEACONS) + ath_beacon_config(sc, NULL); /* restart beacons */ + + ath9k_hw_set_interrupts(ah, sc->imask); + + if (retry_tx) { + int i; + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) { + spin_lock_bh(&sc->tx.txq[i].axq_lock); + ath_txq_schedule(sc, &sc->tx.txq[i]); + spin_unlock_bh(&sc->tx.txq[i].axq_lock); + } + } + } + + return r; +} + +/* + * This function will allocate both the DMA descriptor structure, and the + * buffers it contains. These are used to contain the descriptors used + * by the system. +*/ +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc) +{ +#define DS2PHYS(_dd, _ds) \ + ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) +#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) + + struct ath_desc *ds; + struct ath_buf *bf; + int i, bsize, error; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + name, nbuf, ndesc); + + INIT_LIST_HEAD(head); + /* ath_desc must be a multiple of DWORDs */ + if ((sizeof(struct ath_desc) % 4) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); + ASSERT((sizeof(struct ath_desc) % 4) == 0); + error = -ENOMEM; + goto fail; + } + + dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + + /* + * Need additional DMA memory because we can't use + * descriptors that cross the 4K page boundary. Assume + * one skipped descriptor per 4K page. + */ + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { + u32 ndesc_skipped = + ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); + u32 dma_len; + + while (ndesc_skipped) { + dma_len = ndesc_skipped * sizeof(struct ath_desc); + dd->dd_desc_len += dma_len; + + ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); + }; + } + + /* allocate descriptors */ + dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, + &dd->dd_desc_paddr, GFP_KERNEL); + if (dd->dd_desc == NULL) { + error = -ENOMEM; + goto fail; + } + ds = dd->dd_desc; + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + name, ds, (u32) dd->dd_desc_len, + ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); + + /* allocate buffers */ + bsize = sizeof(struct ath_buf) * nbuf; + bf = kzalloc(bsize, GFP_KERNEL); + if (bf == NULL) { + error = -ENOMEM; + goto fail2; + } + dd->dd_bufptr = bf; + + for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + + if (!(sc->sc_ah->caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + ASSERT((caddr_t) bf->bf_desc < + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += ndesc; + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } + list_add_tail(&bf->list, head); + } + return 0; +fail2: + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); +fail: + memset(dd, 0, sizeof(*dd)); + return error; +#undef ATH_DESC_4KB_BOUND_CHECK +#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED +#undef DS2PHYS +} + +void ath_descdma_cleanup(struct ath_softc *sc, + struct ath_descdma *dd, + struct list_head *head) +{ + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); + + INIT_LIST_HEAD(head); + kfree(dd->dd_bufptr); + memset(dd, 0, sizeof(*dd)); +} + +int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) +{ + int qnum; + + switch (queue) { + case 0: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; + break; + case 1: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; + break; + case 2: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; + break; + case 3: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; + break; + default: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; + break; + } + + return qnum; +} + +int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) +{ + int qnum; + + switch (queue) { + case ATH9K_WME_AC_VO: + qnum = 0; + break; + case ATH9K_WME_AC_VI: + qnum = 1; + break; + case ATH9K_WME_AC_BE: + qnum = 2; + break; + case ATH9K_WME_AC_BK: + qnum = 3; + break; + default: + qnum = -1; + break; + } + + return qnum; +} + +/* XXX: Remove me once we don't depend on ath9k_channel for all + * this redundant data */ +void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *ichan) +{ + struct ieee80211_channel *chan = hw->conf.channel; + struct ieee80211_conf *conf = &hw->conf; + + ichan->channel = chan->center_freq; + ichan->chan = chan; + + if (chan->band == IEEE80211_BAND_2GHZ) { + ichan->chanmode = CHANNEL_G; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; + } else { + ichan->chanmode = CHANNEL_A; + ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; + } + + sc->tx_chan_width = ATH9K_HT_MACMODE_20; + + if (conf_is_ht(conf)) { + if (conf_is_ht40(conf)) + sc->tx_chan_width = ATH9K_HT_MACMODE_2040; + + ichan->chanmode = ath_get_extchanmode(sc, chan, + conf->channel_type); + } +} + +/**********************/ +/* mac80211 callbacks */ +/**********************/ + +static int ath9k_start(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ieee80211_channel *curchan = hw->conf.channel; + struct ath9k_channel *init_channel; + int r, pos; + + DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " + "initial channel: %d MHz\n", curchan->center_freq); + + mutex_lock(&sc->mutex); + + if (ath9k_wiphy_started(sc)) { + if (sc->chan_idx == curchan->hw_value) { + /* + * Already on the operational channel, the new wiphy + * can be marked active. + */ + aphy->state = ATH_WIPHY_ACTIVE; + ieee80211_wake_queues(hw); + } else { + /* + * Another wiphy is on another channel, start the new + * wiphy in paused state. + */ + aphy->state = ATH_WIPHY_PAUSED; + ieee80211_stop_queues(hw); + } + mutex_unlock(&sc->mutex); + return 0; + } + aphy->state = ATH_WIPHY_ACTIVE; + + /* setup initial channel */ + + pos = curchan->hw_value; + + sc->chan_idx = pos; + init_channel = &sc->sc_ah->channels[pos]; + ath9k_update_ichannel(sc, hw, init_channel); + + /* Reset SERDES registers */ + ath9k_hw_configpcipowersave(sc->sc_ah, 0); + + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(sc->sc_ah, init_channel, false); + if (r) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %u " + "(freq %u MHz)\n", r, + curchan->center_freq); + spin_unlock_bh(&sc->sc_resetlock); + goto mutex_unlock; + } + spin_unlock_bh(&sc->sc_resetlock); + + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ + ath_update_txpow(sc); + + /* + * Setup the hardware after reset: + * 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. + */ + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); + r = -EIO; + goto mutex_unlock; + } + + /* Setup our intr mask. */ + sc->imask = ATH9K_INT_RX | ATH9K_INT_TX + | ATH9K_INT_RXEOL | ATH9K_INT_RXORN + | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT) + sc->imask |= ATH9K_INT_GTT; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + sc->imask |= ATH9K_INT_CST; + + ath_cache_conf_rate(sc, &hw->conf); + + sc->sc_flags &= ~SC_OP_INVALID; + + /* Disable BMISS interrupt when we're not associated */ + sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + + ieee80211_wake_queues(hw); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + r = ath_start_rfkill_poll(sc); +#endif + +mutex_unlock: + mutex_unlock(&sc->mutex); + + return r; +} + +static int ath9k_tx(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_tx_control txctl; + int hdrlen, padsize; + + if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { + printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state " + "%d\n", wiphy_name(hw->wiphy), aphy->state); + goto exit; + } + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + + /* + * 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->tx.seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.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) + return -1; + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, hdrlen); + } + + /* Check if a tx queue is available */ + + txctl.txq = ath_test_get_txq(sc, skb); + if (!txctl.txq) + goto exit; + + DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); + + if (ath_tx_start(hw, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); + goto exit; + } + + return 0; +exit: + dev_kfree_skb_any(skb); + return 0; +} + +static void ath9k_stop(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + aphy->state = ATH_WIPHY_INACTIVE; + + if (sc->sc_flags & SC_OP_INVALID) { + DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + return; + } + + mutex_lock(&sc->mutex); + + ieee80211_stop_queues(hw); + + if (ath9k_wiphy_started(sc)) { + mutex_unlock(&sc->mutex); + return; /* another wiphy still in use */ + } + + /* make sure h/w will not generate any interrupt + * before setting the invalid flag. */ + ath9k_hw_set_interrupts(sc->sc_ah, 0); + + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_drain_all_txq(sc, false); + ath_stoprecv(sc); + ath9k_hw_phy_disable(sc->sc_ah); + } else + sc->rx.rxlink = NULL; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif + /* disable HAL and put h/w to sleep */ + ath9k_hw_disable(sc->sc_ah); + ath9k_hw_configpcipowersave(sc->sc_ah, 1); + + sc->sc_flags |= SC_OP_INVALID; + + mutex_unlock(&sc->mutex); + + DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); +} + +static int ath9k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_vif *avp = (void *)conf->vif->drv_priv; + enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; + int ret = 0; + + mutex_lock(&sc->mutex); + + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) && + sc->nvifs > 0) { + ret = -ENOBUFS; + goto out; + } + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + ic_opmode = NL80211_IFTYPE_STATION; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + if (sc->nbcnvifs >= ATH_BCBUF) { + ret = -ENOBUFS; + goto out; + } + ic_opmode = conf->type; + break; + default: + DPRINTF(sc, ATH_DBG_FATAL, + "Interface type %d not yet supported\n", conf->type); + ret = -EOPNOTSUPP; + goto out; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode); + + /* Set the VIF opmode */ + avp->av_opmode = ic_opmode; + avp->av_bslot = -1; + + sc->nvifs++; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + ath9k_set_bssid_mask(hw); + + if (sc->nvifs > 1) + goto out; /* skip global settings for secondary vif */ + + if (ic_opmode == NL80211_IFTYPE_AP) { + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + sc->sc_flags |= SC_OP_TSF_RESET; + } + + /* Set the device opmode */ + sc->sc_ah->opmode = ic_opmode; + + /* + * Enable MIB interrupts when there are hardware phy counters. + * Note we only do this (at the moment) for station mode. + */ + if ((conf->type == NL80211_IFTYPE_STATION) || + (conf->type == NL80211_IFTYPE_ADHOC) || + (conf->type == NL80211_IFTYPE_MESH_POINT)) { + if (ath9k_hw_phycounters(sc->sc_ah)) + sc->imask |= ATH9K_INT_MIB; + sc->imask |= ATH9K_INT_TSFOOR; + } + + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + + if (conf->type == NL80211_IFTYPE_AP) { + /* TODO: is this a suitable place to start ANI for AP mode? */ + /* Start ANI */ + mod_timer(&sc->ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + } + +out: + mutex_unlock(&sc->mutex); + return ret; +} + +static void ath9k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_vif *avp = (void *)conf->vif->drv_priv; + int i; + + DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); + + mutex_lock(&sc->mutex); + + /* Stop ANI */ + del_timer_sync(&sc->ani.timer); + + /* Reclaim beacon resources */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || + (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || + (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + ath_beacon_return(sc, avp); + } + + sc->sc_flags &= ~SC_OP_BEACONS; + + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + if (sc->beacon.bslot[i] == conf->vif) { + printk(KERN_DEBUG "%s: vif had allocated beacon " + "slot\n", __func__); + sc->beacon.bslot[i] = NULL; + sc->beacon.bslot_aphy[i] = NULL; + } + } + + sc->nvifs--; + + mutex_unlock(&sc->mutex); +} + +static int ath9k_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ieee80211_conf *conf = &hw->conf; + struct ath_hw *ah = sc->sc_ah; + + mutex_lock(&sc->mutex); + + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (conf->flags & IEEE80211_CONF_PS) { + if (!(ah->caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { + sc->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } + ath9k_hw_setrxabort(sc->sc_ah, 1); + } + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + } else { + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + if (!(ah->caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + ath9k_hw_setrxabort(sc->sc_ah, 0); + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + if (sc->imask & ATH9K_INT_TIM_TIMER) { + sc->imask &= ~ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } + } + } + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + struct ieee80211_channel *curchan = hw->conf.channel; + int pos = curchan->hw_value; + + aphy->chan_idx = pos; + aphy->chan_is_ht = conf_is_ht(conf); + + if (aphy->state == ATH_WIPHY_SCAN || + aphy->state == ATH_WIPHY_ACTIVE) + ath9k_wiphy_pause_all_forced(sc, aphy); + else { + /* + * Do not change operational channel based on a paused + * wiphy changes. + */ + goto skip_chan_change; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + curchan->center_freq); + + /* XXX: remove me eventualy */ + ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]); + + ath_update_chainmask(sc, conf_is_ht(conf)); + + if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { + DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); + mutex_unlock(&sc->mutex); + return -EINVAL; + } + } + +skip_chan_change: + if (changed & IEEE80211_CONF_CHANGE_POWER) + sc->config.txpowlimit = 2 * conf->power_level; + + /* + * The HW TSF has to be reset when the beacon interval changes. + * We set the flag here, and ath_beacon_config_ap() would take this + * into account when it gets called through the subsequent + * config_interface() call - with IFCC_BEACON in the changed field. + */ + + if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) + sc->sc_flags |= SC_OP_TSF_RESET; + + mutex_unlock(&sc->mutex); + + return 0; +} + +static int ath9k_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; + struct ath_vif *avp = (void *)vif->drv_priv; + u32 rfilt = 0; + int error, i; + + mutex_lock(&sc->mutex); + + /* TODO: Need to decide which hw opmode to use for multi-interface + * cases */ + if (vif->type == NL80211_IFTYPE_AP && + ah->opmode != NL80211_IFTYPE_AP) { + ah->opmode = NL80211_IFTYPE_STATION; + ath9k_hw_setopmode(ah); + memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); + /* 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 NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + /* Set BSSID */ + memcpy(sc->curbssid, conf->bssid, ETH_ALEN); + memcpy(avp->bssid, conf->bssid, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); + + /* Set aggregation protection mode parameters */ + sc->config.ath_aggr_prot = 0; + + DPRINTF(sc, ATH_DBG_CONFIG, + "RX filter 0x%x bssid %pM aid 0x%x\n", + rfilt, sc->curbssid, sc->curaid); + + /* need to reconfigure the beacon */ + sc->sc_flags &= ~SC_OP_BEACONS ; + + break; + default: + break; + } + } + + if ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((conf->changed & IEEE80211_IFCC_BEACON) || + (conf->changed & IEEE80211_IFCC_BEACON_ENABLED && + conf->enable_beacon)) { + /* + * Allocate and setup the beacon frame. + * + * Stop any previous beacon DMA. This may be + * necessary, for example, when an ibss merge + * causes reconfiguration; we may be called + * with beacon transmission active. + */ + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + + error = ath_beacon_alloc(aphy, vif); + if (error != 0) { + mutex_unlock(&sc->mutex); + return error; + } + + ath_beacon_config(sc, vif); + } + } + + /* Check for WLAN_CAPABILITY_PRIVACY ? */ + 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, + (u16)i, + sc->curbssid); + } + + /* Only legacy IBSS for now */ + if (vif->type == NL80211_IFTYPE_ADHOC) + ath_update_chainmask(sc, 0); + + mutex_unlock(&sc->mutex); + + return 0; +} + +#define SUPPORTED_FILTERS \ + (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_CONTROL | \ + FIF_OTHER_BSS | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_FCSFAIL) + +/* FIXME: sc->sc_full_reset ? */ +static void ath9k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_mc_list *mclist) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + u32 rfilt; + + changed_flags &= SUPPORTED_FILTERS; + *total_flags &= SUPPORTED_FILTERS; + + sc->rx.rxfilter = *total_flags; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(sc->sc_ah, rfilt); + + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); +} + +static void ath9k_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + switch (cmd) { + case STA_NOTIFY_ADD: + ath_node_attach(sc, sta); + break; + case STA_NOTIFY_REMOVE: + ath_node_detach(sc, sta); + break; + default: + break; + } +} + +static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath9k_tx_queue_info qi; + int ret = 0, qnum; + + if (queue >= WME_NUM_AC) + return 0; + + mutex_lock(&sc->mutex); + + memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); + + qi.tqi_aifs = params->aifs; + qi.tqi_cwmin = params->cw_min; + qi.tqi_cwmax = params->cw_max; + qi.tqi_burstTime = params->txop; + qnum = ath_get_hal_qnum(queue, sc); + + DPRINTF(sc, ATH_DBG_CONFIG, + "Configure tx [queue/halq] [%d/%d], " + "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", + queue, qnum, params->aifs, params->cw_min, + params->cw_max, params->txop); + + ret = ath_txq_update(sc, qnum, &qi); + if (ret) + DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); + + mutex_unlock(&sc->mutex); + + return ret; +} + +static int ath9k_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + int ret = 0; + + if (modparam_nohwcrypt) + return -ENOSPC; + + mutex_lock(&sc->mutex); + ath9k_ps_wakeup(sc); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n"); + + switch (cmd) { + case SET_KEY: + ret = ath_key_config(sc, vif, sta, key); + if (ret >= 0) { + key->hw_key_idx = ret; + /* push IV and Michael MIC generation to stack */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + if (key->alg == ALG_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP) + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; + ret = 0; + } + break; + case DISABLE_KEY: + ath_key_delete(sc, key); + break; + default: + ret = -EINVAL; + } + + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); + + return ret; +} + +static void ath9k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + sc->sc_flags |= SC_OP_PREAMBLE_SHORT; + else + sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", + bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && + hw->conf.channel->band != IEEE80211_BAND_5GHZ) + sc->sc_flags |= SC_OP_PROTECT_ENABLE; + else + sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; + } + + if (changed & BSS_CHANGED_ASSOC) { + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", + bss_conf->assoc); + ath9k_bss_assoc_info(sc, vif, bss_conf); + } + + mutex_unlock(&sc->mutex); +} + +static u64 ath9k_get_tsf(struct ieee80211_hw *hw) +{ + u64 tsf; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); + tsf = ath9k_hw_gettsf64(sc->sc_ah); + mutex_unlock(&sc->mutex); + + return tsf; +} + +static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); + ath9k_hw_settsf64(sc->sc_ah, tsf); + mutex_unlock(&sc->mutex); +} + +static void ath9k_reset_tsf(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); + ath9k_hw_reset_tsf(sc->sc_ah); + mutex_unlock(&sc->mutex); +} + +static int ath9k_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, + u16 tid, u16 *ssn) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + int ret = 0; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + if (!(sc->sc_flags & SC_OP_RXAGGR)) + ret = -ENOTSUPP; + break; + case IEEE80211_AMPDU_RX_STOP: + break; + case IEEE80211_AMPDU_TX_START: + ret = ath_tx_aggr_start(sc, sta, tid, ssn); + if (ret < 0) + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to start TX aggregation\n"); + else + ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP: + ret = ath_tx_aggr_stop(sc, sta, tid); + if (ret < 0) + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to stop TX aggregation\n"); + + ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + ath_tx_aggr_resume(sc, sta, tid); + break; + default: + DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); + } + + return ret; +} + +static void ath9k_sw_scan_start(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + if (ath9k_wiphy_scanning(sc)) { + printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the " + "same time\n"); + /* + * Do not allow the concurrent scanning state for now. This + * could be improved with scanning control moved into ath9k. + */ + return; + } + + aphy->state = ATH_WIPHY_SCAN; + ath9k_wiphy_pause_all_forced(sc, aphy); + + mutex_lock(&sc->mutex); + sc->sc_flags |= SC_OP_SCANNING; + mutex_unlock(&sc->mutex); +} + +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); + aphy->state = ATH_WIPHY_ACTIVE; + sc->sc_flags &= ~SC_OP_SCANNING; + mutex_unlock(&sc->mutex); +} + +struct ieee80211_ops ath9k_ops = { + .tx = ath9k_tx, + .start = ath9k_start, + .stop = ath9k_stop, + .add_interface = ath9k_add_interface, + .remove_interface = ath9k_remove_interface, + .config = ath9k_config, + .config_interface = ath9k_config_interface, + .configure_filter = ath9k_configure_filter, + .sta_notify = ath9k_sta_notify, + .conf_tx = ath9k_conf_tx, + .bss_info_changed = ath9k_bss_info_changed, + .set_key = ath9k_set_key, + .get_tsf = ath9k_get_tsf, + .set_tsf = ath9k_set_tsf, + .reset_tsf = ath9k_reset_tsf, + .ampdu_action = ath9k_ampdu_action, + .sw_scan_start = ath9k_sw_scan_start, + .sw_scan_complete = ath9k_sw_scan_complete, +}; + +static struct { + u32 version; + const char * name; +} ath_mac_bb_names[] = { + { AR_SREV_VERSION_5416_PCI, "5416" }, + { AR_SREV_VERSION_5416_PCIE, "5418" }, + { AR_SREV_VERSION_9100, "9100" }, + { AR_SREV_VERSION_9160, "9160" }, + { AR_SREV_VERSION_9280, "9280" }, + { AR_SREV_VERSION_9285, "9285" } +}; + +static struct { + u16 version; + const char * name; +} ath_rf_names[] = { + { 0, "5133" }, + { AR_RAD5133_SREV_MAJOR, "5133" }, + { AR_RAD5122_SREV_MAJOR, "5122" }, + { AR_RAD2133_SREV_MAJOR, "2133" }, + { AR_RAD2122_SREV_MAJOR, "2122" } +}; + +/* + * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. + */ +const char * +ath_mac_bb_name(u32 mac_bb_version) +{ + int i; + + for (i=0; i +#include +#include "ath9k.h" + +static struct pci_device_id ath_pci_id_table[] __devinitdata = { + { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ + { 0 } +}; + +/* return bus cachesize in 4B word units */ +static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) +{ + u8 u8tmp; + + pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, + (u8 *)&u8tmp); + *csz = (int)u8tmp; + + /* + * This check was put in to avoid "unplesant" consequences if + * the bootrom has not fully initialized all PCI devices. + * Sometimes the cache line size register is not set + */ + + if (*csz == 0) + *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ +} + +static void ath_pci_cleanup(struct ath_softc *sc) +{ + struct pci_dev *pdev = to_pci_dev(sc->dev); + + pci_iounmap(pdev, sc->mem); + pci_disable_device(pdev); + pci_release_region(pdev, 0); +} + +static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) +{ + (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, + AH_WAIT_TIMEOUT)) { + return false; + } + + *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + + return true; +} + +static struct ath_bus_ops ath_pci_bus_ops = { + .read_cachesize = ath_pci_read_cachesize, + .cleanup = ath_pci_cleanup, + .eeprom_read = ath_pci_eeprom_read, +}; + +static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + void __iomem *mem; + struct ath_wiphy *aphy; + struct ath_softc *sc; + struct ieee80211_hw *hw; + u8 csz; + int ret = 0; + struct ath_hw *ah; + + if (pci_enable_device(pdev)) + return -EIO; + + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { + printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); + goto bad; + } + + ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { + printk(KERN_ERR "ath9k: 32-bit DMA consistent " + "DMA enable failed\n"); + goto bad; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES / sizeof(u32); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + pci_set_master(pdev); + + ret = pci_request_region(pdev, 0, "ath9k"); + if (ret) { + dev_err(&pdev->dev, "PCI memory region reserve error\n"); + ret = -ENODEV; + goto bad; + } + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + printk(KERN_ERR "PCI memory map error\n") ; + ret = -EIO; + goto bad1; + } + + hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + + sizeof(struct ath_softc), &ath9k_ops); + if (hw == NULL) { + printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); + goto bad2; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); + + aphy = hw->priv; + sc = (struct ath_softc *) (aphy + 1); + aphy->sc = sc; + aphy->hw = hw; + sc->pri_wiphy = aphy; + sc->hw = hw; + sc->dev = &pdev->dev; + sc->mem = mem; + sc->bus_ops = &ath_pci_bus_ops; + + if (ath_attach(id->device, sc) != 0) { + ret = -ENODEV; + goto bad3; + } + + /* setup interrupt service routine */ + + if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { + printk(KERN_ERR "%s: request_irq failed\n", + wiphy_name(hw->wiphy)); + ret = -EIO; + goto bad4; + } + + sc->irq = pdev->irq; + + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x " + "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", + wiphy_name(hw->wiphy), + ath_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev, + ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->hw_version.phyRev, + (unsigned long)mem, pdev->irq); + + return 0; +bad4: + ath_detach(sc); +bad3: + ieee80211_free_hw(hw); +bad2: + pci_iounmap(pdev, mem); +bad1: + pci_release_region(pdev, 0); +bad: + pci_disable_device(pdev); + return ret; +} + +static void ath_pci_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + ath_cleanup(sc); +} + +#ifdef CONFIG_PM + +static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + if (sc->sc_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, PCI_D3hot); + + return 0; +} + +static int ath_pci_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + pci_restore_state(pdev); + + /* 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); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /* + * check the h/w rfkill state on resume + * and start the rfkill poll timer + */ + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); +#endif + + return 0; +} + +#endif /* CONFIG_PM */ + +MODULE_DEVICE_TABLE(pci, ath_pci_id_table); + +static struct pci_driver ath_pci_driver = { + .name = "ath9k", + .id_table = ath_pci_id_table, + .probe = ath_pci_probe, + .remove = ath_pci_remove, +#ifdef CONFIG_PM + .suspend = ath_pci_suspend, + .resume = ath_pci_resume, +#endif /* CONFIG_PM */ +}; + +int ath_pci_init(void) +{ + return pci_register_driver(&ath_pci_driver); +} + +void ath_pci_exit(void) +{ + pci_unregister_driver(&ath_pci_driver); +} diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c new file mode 100644 index 0000000..5ec9ce9 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +void +ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, + int regWrites) +{ + REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); +} + +bool +ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) +{ + u32 channelSel = 0; + u32 bModeSynth = 0; + u32 aModeRefSel = 0; + u32 reg32 = 0; + u16 freq; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + if (freq < 4800) { + u32 txctl; + + if (((freq - 2192) % 5) == 0) { + channelSel = ((freq - 672) * 2 - 3040) / 10; + bModeSynth = 0; + } else if (((freq - 2224) % 5) == 0) { + channelSel = ((freq - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); + return false; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath9k_hw_reverse_bits(channelSel, 8); + + txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 2484) { + + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); + } + + } else if ((freq % 20) == 0 && freq >= 5120) { + channelSel = + ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8); + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else if ((freq % 10) == 0) { + channelSel = + ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8); + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) + aModeRefSel = ath9k_hw_reverse_bits(2, 2); + else + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else if ((freq % 5) == 0) { + channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); + return false; + } + + reg32 = + (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 5) | 0x1; + + REG_WRITE(ah, AR_PHY(0x37), reg32); + + ah->curchan = chan; + ah->curchan_rad_index = -1; + + return true; +} + +bool +ath9k_hw_ar9280_set_channel(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u16 bMode, fracMode, aModeRefSel = 0; + u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; + struct chan_centers centers; + u32 refDivA = 24; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL); + reg32 &= 0xc0000000; + + if (freq < 4800) { + u32 txctl; + + bMode = 1; + fracMode = 1; + aModeRefSel = 0; + channelSel = (freq * 0x10000) / 15; + + txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 2484) { + + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); + } + } else { + bMode = 0; + fracMode = 0; + + switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) { + case 0: + if ((freq % 20) == 0) { + aModeRefSel = 3; + } else if ((freq % 10) == 0) { + aModeRefSel = 2; + } + if (aModeRefSel) + break; + case 1: + default: + aModeRefSel = 0; + fracMode = 1; + refDivA = 1; + channelSel = (freq * 0x8000) / 15; + + REG_RMW_FIELD(ah, AR_AN_SYNTH9, + AR_AN_SYNTH9_REFDIVA, refDivA); + + } + + if (!fracMode) { + ndiv = (freq * (refDivA >> aModeRefSel)) / 60; + channelSel = ndiv & 0x1ff; + channelFrac = (ndiv & 0xfffffe00) * 2; + channelSel = (channelSel << 17) | channelFrac; + } + } + + reg32 = reg32 | + (bMode << 29) | + (fracMode << 28) | (aModeRefSel << 26) | (channelSel); + + REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); + + ah->curchan = chan; + ah->curchan_rad_index = -1; + + return true; +} + +static void +ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, + u32 numBits, u32 firstBit, + u32 column) +{ + u32 tmp32, mask, arrayEntry, lastBit; + int32_t bitPosition, bitsLeft; + + tmp32 = ath9k_hw_reverse_bits(reg32, numBits); + arrayEntry = (firstBit - 1) / 8; + bitPosition = (firstBit - 1) % 8; + bitsLeft = numBits; + while (bitsLeft > 0) { + lastBit = (bitPosition + bitsLeft > 8) ? + 8 : bitPosition + bitsLeft; + mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << + (column * 8); + rfBuf[arrayEntry] &= ~mask; + rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << + (column * 8)) & mask; + bitsLeft -= 8 - bitPosition; + tmp32 = tmp32 >> (8 - bitPosition); + bitPosition = 0; + arrayEntry++; + } +} + +bool +ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, + u16 modesIndex) +{ + u32 eepMinorRev; + u32 ob5GHz = 0, db5GHz = 0; + u32 ob2GHz = 0, db2GHz = 0; + int regWrites = 0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + return true; + + eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); + + RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); + + RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); + + RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); + + RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, + modesIndex); + { + int i; + for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) { + ah->analogBank6Data[i] = + INI_RA(&ah->iniBank6TPC, i, modesIndex); + } + } + + if (eepMinorRev >= 2) { + if (IS_CHAN_2GHZ(chan)) { + ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); + db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2); + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, + ob2GHz, 3, 197, 0); + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, + db2GHz, 3, 194, 0); + } else { + ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5); + db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5); + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, + ob5GHz, 3, 203, 0); + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, + db5GHz, 3, 200, 0); + } + } + + RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); + + REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, + regWrites); + + return true; +} + +void +ath9k_hw_rfdetach(struct ath_hw *ah) +{ + if (ah->analogBank0Data != NULL) { + kfree(ah->analogBank0Data); + ah->analogBank0Data = NULL; + } + if (ah->analogBank1Data != NULL) { + kfree(ah->analogBank1Data); + ah->analogBank1Data = NULL; + } + if (ah->analogBank2Data != NULL) { + kfree(ah->analogBank2Data); + ah->analogBank2Data = NULL; + } + if (ah->analogBank3Data != NULL) { + kfree(ah->analogBank3Data); + ah->analogBank3Data = NULL; + } + if (ah->analogBank6Data != NULL) { + kfree(ah->analogBank6Data); + ah->analogBank6Data = NULL; + } + if (ah->analogBank6TPCData != NULL) { + kfree(ah->analogBank6TPCData); + ah->analogBank6TPCData = NULL; + } + if (ah->analogBank7Data != NULL) { + kfree(ah->analogBank7Data); + ah->analogBank7Data = NULL; + } + if (ah->addac5416_21 != NULL) { + kfree(ah->addac5416_21); + ah->addac5416_21 = NULL; + } + if (ah->bank6Temp != NULL) { + kfree(ah->bank6Temp); + ah->bank6Temp = NULL; + } +} + +bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) +{ + if (!AR_SREV_9280_10_OR_LATER(ah)) { + ah->analogBank0Data = + kzalloc((sizeof(u32) * + ah->iniBank0.ia_rows), GFP_KERNEL); + ah->analogBank1Data = + kzalloc((sizeof(u32) * + ah->iniBank1.ia_rows), GFP_KERNEL); + ah->analogBank2Data = + kzalloc((sizeof(u32) * + ah->iniBank2.ia_rows), GFP_KERNEL); + ah->analogBank3Data = + kzalloc((sizeof(u32) * + ah->iniBank3.ia_rows), GFP_KERNEL); + ah->analogBank6Data = + kzalloc((sizeof(u32) * + ah->iniBank6.ia_rows), GFP_KERNEL); + ah->analogBank6TPCData = + kzalloc((sizeof(u32) * + ah->iniBank6TPC.ia_rows), GFP_KERNEL); + ah->analogBank7Data = + kzalloc((sizeof(u32) * + ah->iniBank7.ia_rows), GFP_KERNEL); + + if (ah->analogBank0Data == NULL + || ah->analogBank1Data == NULL + || ah->analogBank2Data == NULL + || ah->analogBank3Data == NULL + || ah->analogBank6Data == NULL + || ah->analogBank6TPCData == NULL + || ah->analogBank7Data == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Cannot allocate RF banks\n"); + *status = -ENOMEM; + return false; + } + + ah->addac5416_21 = + kzalloc((sizeof(u32) * + ah->iniAddac.ia_rows * + ah->iniAddac.ia_columns), GFP_KERNEL); + if (ah->addac5416_21 == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Cannot allocate addac5416_21\n"); + *status = -ENOMEM; + return false; + } + + ah->bank6Temp = + kzalloc((sizeof(u32) * + ah->iniBank6.ia_rows), GFP_KERNEL); + if (ah->bank6Temp == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Cannot allocate bank6Temp\n"); + *status = -ENOMEM; + return false; + } + } + + return true; +} + +void +ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int i, regWrites = 0; + u32 bank6SelMask; + u32 *bank6Temp = ah->bank6Temp; + + switch (ah->diversity_control) { + case ATH9K_ANT_FIXED_A: + bank6SelMask = + (ah-> + antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : + REDUCE_CHAIN_1; + break; + case ATH9K_ANT_FIXED_B: + bank6SelMask = + (ah-> + antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : + REDUCE_CHAIN_0; + break; + case ATH9K_ANT_VARIABLE: + return; + break; + default: + return; + break; + } + + for (i = 0; i < ah->iniBank6.ia_rows; i++) + bank6Temp[i] = ah->analogBank6Data[i]; + + REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); + + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); + + REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); + + REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); +#ifdef ALTER_SWITCH + REG_WRITE(ah, PHY_SWITCH_CHAIN_0, + (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38) + | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38)); +#endif +} diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h new file mode 100644 index 0000000..296d0e9 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef PHY_H +#define PHY_H + +bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah, + struct ath9k_channel + *chan); +bool ath9k_hw_set_channel(struct ath_hw *ah, + struct ath9k_channel *chan); +void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, + u32 freqIndex, int regWrites); +bool ath9k_hw_set_rf_regs(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 modesIndex); +void ath9k_hw_decrease_chain_power(struct ath_hw *ah, + struct ath9k_channel *chan); +bool ath9k_hw_init_rf(struct ath_hw *ah, + int *status); + +#define AR_PHY_BASE 0x9800 +#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) + +#define AR_PHY_TEST 0x9800 +#define PHY_AGC_CLR 0x10000000 +#define RFSILENT_BB 0x00002000 + +#define AR_PHY_TURBO 0x9804 +#define AR_PHY_FC_TURBO_MODE 0x00000001 +#define AR_PHY_FC_TURBO_SHORT 0x00000002 +#define AR_PHY_FC_DYN2040_EN 0x00000004 +#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 +#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 +#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 +#define AR_PHY_FC_HT_EN 0x00000040 +#define AR_PHY_FC_SHORT_GI_40 0x00000080 +#define AR_PHY_FC_WALSH 0x00000100 +#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 +#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800 + +#define AR_PHY_TEST2 0x9808 + +#define AR_PHY_TIMING2 0x9810 +#define AR_PHY_TIMING3 0x9814 +#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 +#define AR_PHY_TIMING3_DSC_MAN_S 17 +#define AR_PHY_TIMING3_DSC_EXP 0x0001E000 +#define AR_PHY_TIMING3_DSC_EXP_S 13 + +#define AR_PHY_CHIP_ID 0x9818 +#define AR_PHY_CHIP_ID_REV_0 0x80 +#define AR_PHY_CHIP_ID_REV_1 0x81 +#define AR_PHY_CHIP_ID_9160_REV_0 0xb0 + +#define AR_PHY_ACTIVE 0x981C +#define AR_PHY_ACTIVE_EN 0x00000001 +#define AR_PHY_ACTIVE_DIS 0x00000000 + +#define AR_PHY_RF_CTL2 0x9824 +#define AR_PHY_TX_END_DATA_START 0x000000FF +#define AR_PHY_TX_END_DATA_START_S 0 +#define AR_PHY_TX_END_PA_ON 0x0000FF00 +#define AR_PHY_TX_END_PA_ON_S 8 + +#define AR_PHY_RF_CTL3 0x9828 +#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 +#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 + +#define AR_PHY_ADC_CTL 0x982C +#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 +#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S 0 +#define AR_PHY_ADC_CTL_OFF_PWDDAC 0x00002000 +#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000 +#define AR_PHY_ADC_CTL_OFF_PWDADC 0x00008000 +#define AR_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000 +#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S 16 + +#define AR_PHY_ADC_SERIAL_CTL 0x9830 +#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000 +#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001 + +#define AR_PHY_RF_CTL4 0x9834 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8 +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 + +#define AR_PHY_TSTDAC_CONST 0x983c + +#define AR_PHY_SETTLING 0x9844 +#define AR_PHY_SETTLING_SWITCH 0x00003F80 +#define AR_PHY_SETTLING_SWITCH_S 7 + +#define AR_PHY_RXGAIN 0x9848 +#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000 +#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12 +#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000 +#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18 +#define AR9280_PHY_RXGAIN_TXRX_ATTEN 0x00003F80 +#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S 7 +#define AR9280_PHY_RXGAIN_TXRX_MARGIN 0x001FC000 +#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14 + +#define AR_PHY_DESIRED_SZ 0x9850 +#define AR_PHY_DESIRED_SZ_ADC 0x000000FF +#define AR_PHY_DESIRED_SZ_ADC_S 0 +#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00 +#define AR_PHY_DESIRED_SZ_PGA_S 8 +#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000 +#define AR_PHY_DESIRED_SZ_TOT_DES_S 20 + +#define AR_PHY_FIND_SIG 0x9858 +#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000 +#define AR_PHY_FIND_SIG_FIRSTEP_S 12 +#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000 +#define AR_PHY_FIND_SIG_FIRPWR_S 18 + +#define AR_PHY_AGC_CTL1 0x985C +#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80 +#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7 +#define AR_PHY_AGC_CTL1_COARSE_HIGH 0x003F8000 +#define AR_PHY_AGC_CTL1_COARSE_HIGH_S 15 + +#define AR_PHY_AGC_CONTROL 0x9860 +#define AR_PHY_AGC_CONTROL_CAL 0x00000001 +#define AR_PHY_AGC_CONTROL_NF 0x00000002 +#define AR_PHY_AGC_CONTROL_ENABLE_NF 0x00008000 +#define AR_PHY_AGC_CONTROL_FLTR_CAL 0x00010000 +#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 + +#define AR_PHY_CCA 0x9864 +#define AR_PHY_MINCCA_PWR 0x0FF80000 +#define AR_PHY_MINCCA_PWR_S 19 +#define AR_PHY_CCA_THRESH62 0x0007F000 +#define AR_PHY_CCA_THRESH62_S 12 +#define AR9280_PHY_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_MINCCA_PWR_S 20 +#define AR9280_PHY_CCA_THRESH62 0x000FF000 +#define AR9280_PHY_CCA_THRESH62_S 12 + +#define AR_PHY_SFCORR_LOW 0x986C +#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21 + +#define AR_PHY_SFCORR 0x9868 +#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F +#define AR_PHY_SFCORR_M2COUNT_THR_S 0 +#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000 +#define AR_PHY_SFCORR_M1_THRESH_S 17 +#define AR_PHY_SFCORR_M2_THRESH 0x7F000000 +#define AR_PHY_SFCORR_M2_THRESH_S 24 + +#define AR_PHY_SLEEP_CTR_CONTROL 0x9870 +#define AR_PHY_SLEEP_CTR_LIMIT 0x9874 +#define AR_PHY_SYNTH_CONTROL 0x9874 +#define AR_PHY_SLEEP_SCAL 0x9878 + +#define AR_PHY_PLL_CTL 0x987c +#define AR_PHY_PLL_CTL_40 0xaa +#define AR_PHY_PLL_CTL_40_5413 0x04 +#define AR_PHY_PLL_CTL_44 0xab +#define AR_PHY_PLL_CTL_44_2133 0xeb +#define AR_PHY_PLL_CTL_40_2133 0xea + +#define AR_PHY_RX_DELAY 0x9914 +#define AR_PHY_SEARCH_START_DELAY 0x9918 +#define AR_PHY_RX_DELAY_DELAY 0x00003FFF + +#define AR_PHY_TIMING_CTRL4(_i) (0x9920 + ((_i) << 12)) +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0 +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0 +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 +#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800 +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000 +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 +#define AR_PHY_TIMING_CTRL4_DO_CAL 0x10000 + +#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI 0x80000000 +#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000 +#define AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000 +#define AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000 + +#define AR_PHY_TIMING5 0x9924 +#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE +#define AR_PHY_TIMING5_CYCPWR_THR1_S 1 + +#define AR_PHY_POWER_TX_RATE1 0x9934 +#define AR_PHY_POWER_TX_RATE2 0x9938 +#define AR_PHY_POWER_TX_RATE_MAX 0x993c +#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 + +#define AR_PHY_FRAME_CTL 0x9944 +#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 +#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 + +#define AR_PHY_TXPWRADJ 0x994C +#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA 0x00000FC0 +#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S 6 +#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX 0x00FC0000 +#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18 + +#define AR_PHY_RADAR_EXT 0x9940 +#define AR_PHY_RADAR_EXT_ENA 0x00004000 + +#define AR_PHY_RADAR_0 0x9954 +#define AR_PHY_RADAR_0_ENA 0x00000001 +#define AR_PHY_RADAR_0_FFT_ENA 0x80000000 +#define AR_PHY_RADAR_0_INBAND 0x0000003e +#define AR_PHY_RADAR_0_INBAND_S 1 +#define AR_PHY_RADAR_0_PRSSI 0x00000FC0 +#define AR_PHY_RADAR_0_PRSSI_S 6 +#define AR_PHY_RADAR_0_HEIGHT 0x0003F000 +#define AR_PHY_RADAR_0_HEIGHT_S 12 +#define AR_PHY_RADAR_0_RRSSI 0x00FC0000 +#define AR_PHY_RADAR_0_RRSSI_S 18 +#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 +#define AR_PHY_RADAR_0_FIRPWR_S 24 + +#define AR_PHY_RADAR_1 0x9958 +#define AR_PHY_RADAR_1_RELPWR_ENA 0x00800000 +#define AR_PHY_RADAR_1_USE_FIR128 0x00400000 +#define AR_PHY_RADAR_1_RELPWR_THRESH 0x003F0000 +#define AR_PHY_RADAR_1_RELPWR_THRESH_S 16 +#define AR_PHY_RADAR_1_BLOCK_CHECK 0x00008000 +#define AR_PHY_RADAR_1_MAX_RRSSI 0x00004000 +#define AR_PHY_RADAR_1_RELSTEP_CHECK 0x00002000 +#define AR_PHY_RADAR_1_RELSTEP_THRESH 0x00001F00 +#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8 +#define AR_PHY_RADAR_1_MAXLEN 0x000000FF +#define AR_PHY_RADAR_1_MAXLEN_S 0 + +#define AR_PHY_SWITCH_CHAIN_0 0x9960 +#define AR_PHY_SWITCH_COM 0x9964 + +#define AR_PHY_SIGMA_DELTA 0x996C +#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 +#define AR_PHY_SIGMA_DELTA_ADC_SEL_S 0 +#define AR_PHY_SIGMA_DELTA_FILT2 0x000000F8 +#define AR_PHY_SIGMA_DELTA_FILT2_S 3 +#define AR_PHY_SIGMA_DELTA_FILT1 0x00001F00 +#define AR_PHY_SIGMA_DELTA_FILT1_S 8 +#define AR_PHY_SIGMA_DELTA_ADC_CLIP 0x01FFE000 +#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13 + +#define AR_PHY_RESTART 0x9970 +#define AR_PHY_RESTART_DIV_GC 0x001C0000 +#define AR_PHY_RESTART_DIV_GC_S 18 + +#define AR_PHY_RFBUS_REQ 0x997C +#define AR_PHY_RFBUS_REQ_EN 0x00000001 + +#define AR_PHY_TIMING7 0x9980 +#define AR_PHY_TIMING8 0x9984 +#define AR_PHY_TIMING8_PILOT_MASK_2 0x000FFFFF +#define AR_PHY_TIMING8_PILOT_MASK_2_S 0 + +#define AR_PHY_BIN_MASK2_1 0x9988 +#define AR_PHY_BIN_MASK2_2 0x998c +#define AR_PHY_BIN_MASK2_3 0x9990 +#define AR_PHY_BIN_MASK2_4 0x9994 + +#define AR_PHY_BIN_MASK_1 0x9900 +#define AR_PHY_BIN_MASK_2 0x9904 +#define AR_PHY_BIN_MASK_3 0x9908 + +#define AR_PHY_MASK_CTL 0x990c + +#define AR_PHY_BIN_MASK2_4_MASK_4 0x00003FFF +#define AR_PHY_BIN_MASK2_4_MASK_4_S 0 + +#define AR_PHY_TIMING9 0x9998 +#define AR_PHY_TIMING10 0x999c +#define AR_PHY_TIMING10_PILOT_MASK_2 0x000FFFFF +#define AR_PHY_TIMING10_PILOT_MASK_2_S 0 + +#define AR_PHY_TIMING11 0x99a0 +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0 +#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 +#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 +#define AR_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000 +#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000 + +#define AR_PHY_RX_CHAINMASK 0x99a4 +#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) +#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 +#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 +#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac + +#define AR_PHY_EXT_CCA0 0x99b8 +#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF +#define AR_PHY_EXT_CCA0_THRESH62_S 0 + +#define AR_PHY_EXT_CCA 0x99bc +#define AR_PHY_EXT_CCA_CYCPWR_THR1 0x0000FE00 +#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9 +#define AR_PHY_EXT_CCA_THRESH62 0x007F0000 +#define AR_PHY_EXT_CCA_THRESH62_S 16 +#define AR_PHY_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_EXT_MINCCA_PWR_S 23 +#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_SFCORR_EXT 0x99c0 +#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F +#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0 +#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80 +#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21 +#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 + +#define AR_PHY_HALFGI 0x99D0 +#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0 +#define AR_PHY_HALFGI_DSC_MAN_S 4 +#define AR_PHY_HALFGI_DSC_EXP 0x0000000F +#define AR_PHY_HALFGI_DSC_EXP_S 0 + +#define AR_PHY_CHAN_INFO_MEMORY 0x99DC +#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001 + +#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0 + +#define AR_PHY_M_SLEEP 0x99f0 +#define AR_PHY_REFCLKDLY 0x99f4 +#define AR_PHY_REFCLKPD 0x99f8 + +#define AR_PHY_CALMODE 0x99f0 + +#define AR_PHY_CALMODE_IQ 0x00000000 +#define AR_PHY_CALMODE_ADC_GAIN 0x00000001 +#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002 +#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003 + +#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12)) + +#define AR_PHY_CURRENT_RSSI 0x9c1c +#define AR9280_PHY_CURRENT_RSSI 0x9c3c + +#define AR_PHY_RFBUS_GRANT 0x9C20 +#define AR_PHY_RFBUS_GRANT_EN 0x00000001 + +#define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 +#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 + +#define AR_PHY_CHAN_INFO_GAIN 0x9CFC + +#define AR_PHY_MODE 0xA200 +#define AR_PHY_MODE_AR2133 0x08 +#define AR_PHY_MODE_AR5111 0x00 +#define AR_PHY_MODE_AR5112 0x08 +#define AR_PHY_MODE_DYNAMIC 0x04 +#define AR_PHY_MODE_RF2GHZ 0x02 +#define AR_PHY_MODE_RF5GHZ 0x00 +#define AR_PHY_MODE_CCK 0x01 +#define AR_PHY_MODE_OFDM 0x00 +#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100 + +#define AR_PHY_CCK_TX_CTRL 0xA204 +#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 +#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000C +#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2 + +#define AR_PHY_CCK_DETECT 0xA208 +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 +/* [12:6] settling time for antenna switch */ +#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 +#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 +#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 + +#define AR_PHY_GAIN_2GHZ 0xA20C +#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 +#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18 +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00 +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10 +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0 + +#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN 0x003E0000 +#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S 17 +#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN 0x0001F000 +#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S 12 +#define AR_PHY_GAIN_2GHZ_XATTEN2_DB 0x00000FC0 +#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S 6 +#define AR_PHY_GAIN_2GHZ_XATTEN1_DB 0x0000003F +#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S 0 + +#define AR_PHY_CCK_RXCTRL4 0xA21C +#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01F80000 +#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19 + +#define AR_PHY_DAG_CTRLCCK 0xA228 +#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200 +#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00 +#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 + +#define AR_PHY_FORCE_CLKEN_CCK 0xA22C +#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX 0x00000040 + +#define AR_PHY_POWER_TX_RATE3 0xA234 +#define AR_PHY_POWER_TX_RATE4 0xA238 + +#define AR_PHY_SCRM_SEQ_XR 0xA23C +#define AR_PHY_HEADER_DETECT_XR 0xA240 +#define AR_PHY_CHIRP_DETECTED_XR 0xA244 +#define AR_PHY_BLUETOOTH 0xA254 + +#define AR_PHY_TPCRG1 0xA258 +#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000 +#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14 + +#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 +#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 +#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 +#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 +#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 +#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 + +#define AR_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000 +#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22 + +#define AR_PHY_TX_PWRCTRL4 0xa264 +#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001 +#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0 +#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001FE +#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1 + +#define AR_PHY_TX_PWRCTRL6_0 0xa270 +#define AR_PHY_TX_PWRCTRL6_1 0xb270 +#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000 +#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24 + +#define AR_PHY_TX_PWRCTRL7 0xa274 +#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 +#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 + +#define AR_PHY_TX_PWRCTRL9 0xa27C +#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 +#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 + +#define AR_PHY_TX_GAIN_TBL1 0xa300 +#define AR_PHY_TX_GAIN 0x0007F000 +#define AR_PHY_TX_GAIN_S 12 + +#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 +#define AR_PHY_MASK2_M_31_45 0xa3a4 +#define AR_PHY_MASK2_M_16_30 0xa3a8 +#define AR_PHY_MASK2_M_00_15 0xa3ac +#define AR_PHY_MASK2_P_15_01 0xa3b8 +#define AR_PHY_MASK2_P_30_16 0xa3bc +#define AR_PHY_MASK2_P_45_31 0xa3c0 +#define AR_PHY_MASK2_P_61_45 0xa3c4 +#define AR_PHY_SPUR_REG 0x994c + +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL (0xFF << 18) +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18 + +#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000 +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT (0xFF << 9) +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S 9 +#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100 +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7F +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0 + +#define AR_PHY_PILOT_MASK_01_30 0xa3b0 +#define AR_PHY_PILOT_MASK_31_60 0xa3b4 + +#define AR_PHY_CHANNEL_MASK_01_30 0x99d4 +#define AR_PHY_CHANNEL_MASK_31_60 0x99d8 + +#define AR_PHY_ANALOG_SWAP 0xa268 +#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 + +#define AR_PHY_TPCRG5 0xA26C +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 + +/* Carrier leak calibration control, do it after AGC calibration */ +#define AR_PHY_CL_CAL_CTL 0xA358 +#define AR_PHY_CL_CAL_ENABLE 0x00000002 +#define AR_PHY_PARALLEL_CAL_ENABLE 0x00000001 + +#define AR_PHY_POWER_TX_RATE5 0xA38C +#define AR_PHY_POWER_TX_RATE6 0xA390 + +#define AR_PHY_CAL_CHAINMASK 0xA39C + +#define AR_PHY_POWER_TX_SUB 0xA3C8 +#define AR_PHY_POWER_TX_RATE7 0xA3CC +#define AR_PHY_POWER_TX_RATE8 0xA3D0 +#define AR_PHY_POWER_TX_RATE9 0xA3D4 + +#define AR_PHY_XPA_CFG 0xA3D8 +#define AR_PHY_FORCE_XPA_CFG 0x000000001 +#define AR_PHY_FORCE_XPA_CFG_S 0 + +#define AR_PHY_CH1_CCA 0xa864 +#define AR_PHY_CH1_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH1_MINCCA_PWR_S 19 +#define AR9280_PHY_CH1_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_CH1_MINCCA_PWR_S 20 + +#define AR_PHY_CH2_CCA 0xb864 +#define AR_PHY_CH2_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH2_MINCCA_PWR_S 19 + +#define AR_PHY_CH1_EXT_CCA 0xa9bc +#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_CH2_EXT_CCA 0xb9bc +#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 + +#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ + int r; \ + for (r = 0; r < ((iniarray)->ia_rows); r++) { \ + REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ + DO_DELAY(regWr); \ + } \ + } while (0) + +#define ATH9K_IS_MIC_ENABLED(ah) \ + ((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE) + +#define ANTSWAP_AB 0x0001 +#define REDUCE_CHAIN_0 0x00000050 +#define REDUCE_CHAIN_1 0x00000051 + +#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ + int i; \ + for (i = 0; i < (_iniarray)->ia_rows; i++) \ + (_bank)[i] = INI_RA((_iniarray), i, _col);; \ + } while (0) + +#endif diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c new file mode 100644 index 0000000..a13668b --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -0,0 +1,1752 @@ +/* + * Copyright (c) 2004 Video54 Technologies, Inc. + * Copyright (c) 2004-2009 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static struct ath_rate_table ar5416_11na_ratetable = { + 42, + { + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ + 5400, 0x0b, 0x00, 12, + 0, 2, 1, 0, 0, 0, 0, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ + 7800, 0x0f, 0x00, 18, + 0, 3, 1, 1, 1, 1, 1, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ + 10000, 0x0a, 0x00, 24, + 2, 4, 2, 2, 2, 2, 2, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ + 13900, 0x0e, 0x00, 36, + 2, 6, 2, 3, 3, 3, 3, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ + 17300, 0x09, 0x00, 48, + 4, 10, 3, 4, 4, 4, 4, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ + 23000, 0x0d, 0x00, 72, + 4, 14, 3, 5, 5, 5, 5, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ + 27400, 0x08, 0x00, 96, + 4, 20, 3, 6, 6, 6, 6, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ + 29300, 0x0c, 0x00, 108, + 4, 23, 3, 7, 7, 7, 7, 0 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + 6400, 0x80, 0x00, 0, + 0, 2, 3, 8, 24, 8, 24, 3216 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ + 12700, 0x81, 0x00, 1, + 2, 4, 3, 9, 25, 9, 25, 6434 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + 18800, 0x82, 0x00, 2, + 2, 6, 3, 10, 26, 10, 26, 9650 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ + 25000, 0x83, 0x00, 3, + 4, 10, 3, 11, 27, 11, 27, 12868 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ + 36700, 0x84, 0x00, 4, + 4, 14, 3, 12, 28, 12, 28, 19304 }, + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ + 48100, 0x85, 0x00, 5, + 4, 20, 3, 13, 29, 13, 29, 25740 }, + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + 53500, 0x86, 0x00, 6, + 4, 23, 3, 14, 30, 14, 30, 28956 }, + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ + 59000, 0x87, 0x00, 7, + 4, 25, 3, 15, 31, 15, 32, 32180 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ + 12700, 0x88, 0x00, + 8, 0, 2, 3, 16, 33, 16, 33, 6430 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ + 24800, 0x89, 0x00, 9, + 2, 4, 3, 17, 34, 17, 34, 12860 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ + 36600, 0x8a, 0x00, 10, + 2, 6, 3, 18, 35, 18, 35, 19300 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ + 48100, 0x8b, 0x00, 11, + 4, 10, 3, 19, 36, 19, 36, 25736 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ + 69500, 0x8c, 0x00, 12, + 4, 14, 3, 20, 37, 20, 37, 38600 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ + 89500, 0x8d, 0x00, 13, + 4, 20, 3, 21, 38, 21, 38, 51472 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ + 98900, 0x8e, 0x00, 14, + 4, 23, 3, 22, 39, 22, 39, 57890 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ + 108300, 0x8f, 0x00, 15, + 4, 25, 3, 23, 40, 23, 41, 64320 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + 13200, 0x80, 0x00, 0, + 0, 2, 3, 8, 24, 24, 24, 6684 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + 25900, 0x81, 0x00, 1, + 2, 4, 3, 9, 25, 25, 25, 13368 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + 38600, 0x82, 0x00, 2, + 2, 6, 3, 10, 26, 26, 26, 20052 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ + 49800, 0x83, 0x00, 3, + 4, 10, 3, 11, 27, 27, 27, 26738 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ + 72200, 0x84, 0x00, 4, + 4, 14, 3, 12, 28, 28, 28, 40104 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ + 92900, 0x85, 0x00, 5, + 4, 20, 3, 13, 29, 29, 29, 53476 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + 102700, 0x86, 0x00, 6, + 4, 23, 3, 14, 30, 30, 30, 60156 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ + 112000, 0x87, 0x00, 7, + 4, 25, 3, 15, 31, 32, 32, 66840 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + 122000, 0x87, 0x00, 7, + 4, 25, 3, 15, 31, 32, 32, 74200 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ + 25800, 0x88, 0x00, 8, + 0, 2, 3, 16, 33, 33, 33, 13360 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ + 49800, 0x89, 0x00, 9, + 2, 4, 3, 17, 34, 34, 34, 26720 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ + 71900, 0x8a, 0x00, 10, + 2, 6, 3, 18, 35, 35, 35, 40080 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ + 92500, 0x8b, 0x00, 11, + 4, 10, 3, 19, 36, 36, 36, 53440 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ + 130300, 0x8c, 0x00, 12, + 4, 14, 3, 20, 37, 37, 37, 80160 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ + 162800, 0x8d, 0x00, 13, + 4, 20, 3, 21, 38, 38, 38, 106880 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ + 178200, 0x8e, 0x00, 14, + 4, 23, 3, 22, 39, 39, 39, 120240 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ + 192100, 0x8f, 0x00, 15, + 4, 25, 3, 23, 40, 41, 41, 133600 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + 207000, 0x8f, 0x00, 15, + 4, 25, 3, 23, 40, 41, 41, 148400 }, + }, + 50, /* probe interval */ + 50, /* rssi reduce interval */ + WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ +}; + +/* 4ms frame limit not used for NG mode. The values filled + * for HT are the 64K max aggregate limit */ + +static struct ath_rate_table ar5416_11ng_ratetable = { + 46, + { + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ + 900, 0x1b, 0x00, 2, + 0, 0, 1, 0, 0, 0, 0, 0 }, + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ + 1900, 0x1a, 0x04, 4, + 1, 1, 1, 1, 1, 1, 1, 0 }, + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ + 4900, 0x19, 0x04, 11, + 2, 2, 2, 2, 2, 2, 2, 0 }, + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ + 8100, 0x18, 0x04, 22, + 3, 3, 2, 3, 3, 3, 3, 0 }, + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ + 5400, 0x0b, 0x00, 12, + 4, 2, 1, 4, 4, 4, 4, 0 }, + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ + 7800, 0x0f, 0x00, 18, + 4, 3, 1, 5, 5, 5, 5, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ + 10100, 0x0a, 0x00, 24, + 6, 4, 1, 6, 6, 6, 6, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ + 14100, 0x0e, 0x00, 36, + 6, 6, 2, 7, 7, 7, 7, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ + 17700, 0x09, 0x00, 48, + 8, 10, 3, 8, 8, 8, 8, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ + 23700, 0x0d, 0x00, 72, + 8, 14, 3, 9, 9, 9, 9, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ + 27400, 0x08, 0x00, 96, + 8, 20, 3, 10, 10, 10, 10, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ + 30900, 0x0c, 0x00, 108, + 8, 23, 3, 11, 11, 11, 11, 0 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + 6400, 0x80, 0x00, 0, + 4, 2, 3, 12, 28, 12, 28, 3216 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ + 12700, 0x81, 0x00, 1, + 6, 4, 3, 13, 29, 13, 29, 6434 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + 18800, 0x82, 0x00, 2, + 6, 6, 3, 14, 30, 14, 30, 9650 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ + 25000, 0x83, 0x00, 3, + 8, 10, 3, 15, 31, 15, 31, 12868 }, + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ + 36700, 0x84, 0x00, 4, + 8, 14, 3, 16, 32, 16, 32, 19304 }, + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ + 48100, 0x85, 0x00, 5, + 8, 20, 3, 17, 33, 17, 33, 25740 }, + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + 53500, 0x86, 0x00, 6, + 8, 23, 3, 18, 34, 18, 34, 28956 }, + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ + 59000, 0x87, 0x00, 7, + 8, 25, 3, 19, 35, 19, 36, 32180 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ + 12700, 0x88, 0x00, 8, + 4, 2, 3, 20, 37, 20, 37, 6430 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ + 24800, 0x89, 0x00, 9, + 6, 4, 3, 21, 38, 21, 38, 12860 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ + 36600, 0x8a, 0x00, 10, + 6, 6, 3, 22, 39, 22, 39, 19300 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ + 48100, 0x8b, 0x00, 11, + 8, 10, 3, 23, 40, 23, 40, 25736 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ + 69500, 0x8c, 0x00, 12, + 8, 14, 3, 24, 41, 24, 41, 38600 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ + 89500, 0x8d, 0x00, 13, + 8, 20, 3, 25, 42, 25, 42, 51472 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ + 98900, 0x8e, 0x00, 14, + 8, 23, 3, 26, 43, 26, 44, 57890 }, + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ + 108300, 0x8f, 0x00, 15, + 8, 25, 3, 27, 44, 27, 45, 64320 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + 13200, 0x80, 0x00, 0, + 8, 2, 3, 12, 28, 28, 28, 6684 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + 25900, 0x81, 0x00, 1, + 8, 4, 3, 13, 29, 29, 29, 13368 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + 38600, 0x82, 0x00, 2, + 8, 6, 3, 14, 30, 30, 30, 20052 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ + 49800, 0x83, 0x00, 3, + 8, 10, 3, 15, 31, 31, 31, 26738 }, + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ + 72200, 0x84, 0x00, 4, + 8, 14, 3, 16, 32, 32, 32, 40104 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ + 92900, 0x85, 0x00, 5, + 8, 20, 3, 17, 33, 33, 33, 53476 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + 102700, 0x86, 0x00, 6, + 8, 23, 3, 18, 34, 34, 34, 60156 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ + 112000, 0x87, 0x00, 7, + 8, 23, 3, 19, 35, 36, 36, 66840 }, + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + 122000, 0x87, 0x00, 7, + 8, 25, 3, 19, 35, 36, 36, 74200 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ + 25800, 0x88, 0x00, 8, + 8, 2, 3, 20, 37, 37, 37, 13360 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ + 49800, 0x89, 0x00, 9, + 8, 4, 3, 21, 38, 38, 38, 26720 }, + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ + 71900, 0x8a, 0x00, 10, + 8, 6, 3, 22, 39, 39, 39, 40080 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ + 92500, 0x8b, 0x00, 11, + 8, 10, 3, 23, 40, 40, 40, 53440 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ + 130300, 0x8c, 0x00, 12, + 8, 14, 3, 24, 41, 41, 41, 80160 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ + 162800, 0x8d, 0x00, 13, + 8, 20, 3, 25, 42, 42, 42, 106880 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ + 178200, 0x8e, 0x00, 14, + 8, 23, 3, 26, 43, 43, 43, 120240 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ + 192100, 0x8f, 0x00, 15, + 8, 23, 3, 27, 44, 45, 45, 133600 }, + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + 207000, 0x8f, 0x00, 15, + 8, 25, 3, 27, 44, 45, 45, 148400 }, + }, + 50, /* probe interval */ + 50, /* rssi reduce interval */ + WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ +}; + +static struct ath_rate_table ar5416_11a_ratetable = { + 8, + { + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ + 5400, 0x0b, 0x00, (0x80|12), + 0, 2, 1, 0, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ + 7800, 0x0f, 0x00, 18, + 0, 3, 1, 1, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ + 10000, 0x0a, 0x00, (0x80|24), + 2, 4, 2, 2, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ + 13900, 0x0e, 0x00, 36, + 2, 6, 2, 3, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ + 17300, 0x09, 0x00, (0x80|48), + 4, 10, 3, 4, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ + 23000, 0x0d, 0x00, 72, + 4, 14, 3, 5, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ + 27400, 0x08, 0x00, 96, + 4, 19, 3, 6, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ + 29300, 0x0c, 0x00, 108, + 4, 23, 3, 7, 0 }, + }, + 50, /* probe interval */ + 50, /* rssi reduce interval */ + 0, /* Phy rates allowed initially */ +}; + +static struct ath_rate_table ar5416_11g_ratetable = { + 12, + { + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ + 900, 0x1b, 0x00, 2, + 0, 0, 1, 0, 0 }, + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ + 1900, 0x1a, 0x04, 4, + 1, 1, 1, 1, 0 }, + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ + 4900, 0x19, 0x04, 11, + 2, 2, 2, 2, 0 }, + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ + 8100, 0x18, 0x04, 22, + 3, 3, 2, 3, 0 }, + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ + 5400, 0x0b, 0x00, 12, + 4, 2, 1, 4, 0 }, + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ + 7800, 0x0f, 0x00, 18, + 4, 3, 1, 5, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ + 10000, 0x0a, 0x00, 24, + 6, 4, 1, 6, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ + 13900, 0x0e, 0x00, 36, + 6, 6, 2, 7, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ + 17300, 0x09, 0x00, 48, + 8, 10, 3, 8, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ + 23000, 0x0d, 0x00, 72, + 8, 14, 3, 9, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ + 27400, 0x08, 0x00, 96, + 8, 19, 3, 10, 0 }, + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ + 29300, 0x0c, 0x00, 108, + 8, 23, 3, 11, 0 }, + }, + 50, /* probe interval */ + 50, /* rssi reduce interval */ + 0, /* Phy rates allowed initially */ +}; + +static struct ath_rate_table ar5416_11b_ratetable = { + 4, + { + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ + 900, 0x1b, 0x00, (0x80|2), + 0, 0, 1, 0, 0 }, + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ + 1800, 0x1a, 0x04, (0x80|4), + 1, 1, 1, 1, 0 }, + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ + 4300, 0x19, 0x04, (0x80|11), + 1, 2, 2, 2, 0 }, + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ + 7100, 0x18, 0x04, (0x80|22), + 1, 4, 100, 3, 0 }, + }, + 100, /* probe interval */ + 100, /* rssi reduce interval */ + 0, /* Phy rates allowed initially */ +}; + +static inline int8_t median(int8_t a, int8_t b, int8_t c) +{ + if (a >= b) { + if (b >= c) + return b; + else if (a > c) + return c; + else + return a; + } else { + if (a >= c) + return a; + else if (b >= c) + return c; + else + return b; + } +} + +static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv) +{ + u8 i, j, idx, idx_next; + + for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { + for (j = 0; j <= i-1; j++) { + idx = ath_rc_priv->valid_rate_index[j]; + idx_next = ath_rc_priv->valid_rate_index[j+1]; + + if (rate_table->info[idx].ratekbps > + rate_table->info[idx_next].ratekbps) { + ath_rc_priv->valid_rate_index[j] = idx_next; + ath_rc_priv->valid_rate_index[j+1] = idx; + } + } + } +} + +static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) +{ + u8 i; + + for (i = 0; i < ath_rc_priv->rate_table_size; i++) + ath_rc_priv->valid_rate_index[i] = 0; +} + +static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, + u8 index, int valid_tx_rate) +{ + ASSERT(index <= ath_rc_priv->rate_table_size); + ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; +} + +static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, + u8 index) +{ + ASSERT(index <= ath_rc_priv->rate_table_size); + return ath_rc_priv->valid_rate_index[index]; +} + +static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, + u8 *next_idx) +{ + u8 i; + + for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i+1]; + return 1; + } + } + + /* No more valid rates */ + *next_idx = 0; + + return 0; +} + +/* Return true only for single stream */ + +static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) +{ + if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG)) + return 0; + if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) + return 0; + if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) + return 0; + if (!ignore_cw && WLAN_RC_PHY_HT(phy)) + if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) + return 0; + if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) + return 0; + return 1; +} + +static inline int +ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, u8 *next_idx) +{ + int8_t i; + + for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i-1]; + return 1; + } + } + + return 0; +} + +static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u32 capflag) +{ + u8 i, hi = 0; + u32 valid; + + for (i = 0; i < rate_table->rate_cnt; i++) { + valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? + rate_table->info[i].valid_single_stream : + rate_table->info[i].valid); + if (valid == 1) { + u32 phy = rate_table->info[i].phy; + u8 valid_rate_count = 0; + + if (!ath_rc_valid_phyrate(phy, capflag, 0)) + continue; + + valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; + + ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, i, 1); + hi = A_MAX(hi, i); + } + } + + return hi; +} + +static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + struct ath_rateset *rateset, + u32 capflag) +{ + u8 i, j, hi = 0; + + /* Use intersection of working rates and valid rates */ + for (i = 0; i < rateset->rs_nrates; i++) { + for (j = 0; j < rate_table->rate_cnt; j++) { + u32 phy = rate_table->info[j].phy; + u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? + rate_table->info[j].valid_single_stream : + rate_table->info[j].valid); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; + + /* We allow a rate only if its valid and the + * capflag matches one of the validity + * (VALID/VALID_20/VALID_40) flags */ + + if (((rate & 0x7F) == (dot11rate & 0x7F)) && + ((valid & WLAN_RC_CAP_MODE(capflag)) == + WLAN_RC_CAP_MODE(capflag)) && + !WLAN_RC_PHY_HT(phy)) { + u8 valid_rate_count = 0; + + if (!ath_rc_valid_phyrate(phy, capflag, 0)) + continue; + + valid_rate_count = + ath_rc_priv->valid_phy_ratecnt[phy]; + + ath_rc_priv->valid_phy_rateidx[phy] + [valid_rate_count] = j; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); + hi = A_MAX(hi, j); + } + } + } + + return hi; +} + +static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u8 *mcs_set, u32 capflag) +{ + struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; + + u8 i, j, hi = 0; + + /* Use intersection of working rates and valid rates */ + for (i = 0; i < rateset->rs_nrates; i++) { + for (j = 0; j < rate_table->rate_cnt; j++) { + u32 phy = rate_table->info[j].phy; + u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? + rate_table->info[j].valid_single_stream : + rate_table->info[j].valid); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; + + if (((rate & 0x7F) != (dot11rate & 0x7F)) || + !WLAN_RC_PHY_HT(phy) || + !WLAN_RC_PHY_HT_VALID(valid, capflag)) + continue; + + if (!ath_rc_valid_phyrate(phy, capflag, 0)) + continue; + + ath_rc_priv->valid_phy_rateidx[phy] + [ath_rc_priv->valid_phy_ratecnt[phy]] = j; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); + hi = A_MAX(hi, j); + } + } + + return hi; +} + +static u8 ath_rc_ratefind_ht(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + int *is_probing) +{ + u32 dt, best_thruput, this_thruput, now_msec; + u8 rate, next_rate, best_rate, maxindex, minindex; + int8_t rssi_last, rssi_reduce = 0, index = 0; + + *is_probing = 0; + + rssi_last = median(ath_rc_priv->rssi_last, + ath_rc_priv->rssi_last_prev, + ath_rc_priv->rssi_last_prev2); + + /* + * Age (reduce) last ack rssi based on how old it is. + * The bizarre numbers are so the delta is 160msec, + * meaning we divide by 16. + * 0msec <= dt <= 25msec: don't derate + * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB + * 185msec <= dt: derate by 10dB + */ + + now_msec = jiffies_to_msecs(jiffies); + dt = now_msec - ath_rc_priv->rssi_time; + + if (dt >= 185) + rssi_reduce = 10; + else if (dt >= 25) + rssi_reduce = (u8)((dt - 25) >> 4); + + /* Now reduce rssi_last by rssi_reduce */ + if (rssi_last < rssi_reduce) + rssi_last = 0; + else + rssi_last -= rssi_reduce; + + /* + * Now look up the rate in the rssi table and return it. + * If no rates match then we return 0 (lowest rate) + */ + + best_thruput = 0; + maxindex = ath_rc_priv->max_valid_rate-1; + + minindex = 0; + best_rate = minindex; + + /* + * Try the higher rate first. It will reduce memory moving time + * if we have very good channel characteristics. + */ + for (index = maxindex; index >= minindex ; index--) { + u8 per_thres; + + rate = ath_rc_priv->valid_rate_index[index]; + if (rate > ath_rc_priv->rate_max_phy) + continue; + + /* + * For TCP the average collision rate is around 11%, + * so we ignore PERs less than this. This is to + * prevent the rate we are currently using (whose + * PER might be in the 10-15 range because of TCP + * collisions) looking worse than the next lower + * rate whose PER has decayed close to 0. If we + * used to next lower rate, its PER would grow to + * 10-15 and we would be worse off then staying + * at the current rate. + */ + per_thres = ath_rc_priv->state[rate].per; + if (per_thres < 12) + per_thres = 12; + + this_thruput = rate_table->info[rate].user_ratekbps * + (100 - per_thres); + + if (best_thruput <= this_thruput) { + best_thruput = this_thruput; + best_rate = rate; + } + } + + rate = best_rate; + ath_rc_priv->rssi_last_lookup = rssi_last; + + /* + * Must check the actual rate (ratekbps) to account for + * non-monoticity of 11g's rate table + */ + + if (rate >= ath_rc_priv->rate_max_phy) { + rate = ath_rc_priv->rate_max_phy; + + /* Probe the next allowed phy state */ + if (ath_rc_get_nextvalid_txrate(rate_table, + ath_rc_priv, rate, &next_rate) && + (now_msec - ath_rc_priv->probe_time > + rate_table->probe_interval) && + (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { + rate = next_rate; + ath_rc_priv->probe_rate = rate; + ath_rc_priv->probe_time = now_msec; + ath_rc_priv->hw_maxretry_pktcnt = 0; + *is_probing = 1; + } + } + + if (rate > (ath_rc_priv->rate_table_size - 1)) + rate = ath_rc_priv->rate_table_size - 1; + + ASSERT((rate_table->info[rate].valid && + (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) || + (rate_table->info[rate].valid_single_stream && + !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))); + + return rate; +} + +static void ath_rc_rate_set_series(struct ath_rate_table *rate_table, + struct ieee80211_tx_rate *rate, + struct ieee80211_tx_rate_control *txrc, + u8 tries, u8 rix, int rtsctsenable) +{ + rate->count = tries; + rate->idx = rix; + + if (txrc->short_preamble) + rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; + if (txrc->rts || rtsctsenable) + rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_MCS; +} + +static void ath_rc_rate_set_rtscts(struct ath_softc *sc, + struct ath_rate_table *rate_table, + struct ieee80211_tx_info *tx_info) +{ + struct ieee80211_tx_rate *rates = tx_info->control.rates; + int i = 0, rix = 0, cix, enable_g_protection = 0; + + /* get the cix for the lowest valid rix */ + for (i = 3; i >= 0; i--) { + if (rates[i].count && (rates[i].idx >= 0)) { + rix = rates[i].idx; + break; + } + } + cix = rate_table->info[rix].ctrl_rate; + + /* All protection frames are transmited at 2Mb/s for 802.11g, + * otherwise we transmit them at 1Mb/s */ + if (sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ && + !conf_is_ht(&sc->hw->conf)) + enable_g_protection = 1; + + /* + * If 802.11g protection is enabled, determine whether to use RTS/CTS or + * just CTS. Note that this is only done for OFDM/HT unicast frames. + */ + if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) && + !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && + (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM || + WLAN_RC_PHY_HT(rate_table->info[rix].phy))) { + rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; + cix = rate_table->info[enable_g_protection].ctrl_rate; + } + + tx_info->control.rts_cts_rate_idx = cix; +} + +static u8 ath_rc_rate_getidx(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u8 rix, u16 stepdown, + u16 min_rate) +{ + u32 j; + u8 nextindex; + + if (min_rate) { + for (j = RATE_TABLE_SIZE; j > 0; j--) { + if (ath_rc_get_nextlowervalid_txrate(rate_table, + ath_rc_priv, rix, &nextindex)) + rix = nextindex; + else + break; + } + } else { + for (j = stepdown; j > 0; j--) { + if (ath_rc_get_nextlowervalid_txrate(rate_table, + ath_rc_priv, rix, &nextindex)) + rix = nextindex; + else + break; + } + } + return rix; +} + +static void ath_rc_ratefind(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_tx_rate_control *txrc) +{ + struct ath_rate_table *rate_table; + struct sk_buff *skb = txrc->skb; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->control.rates; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + __le16 fc = hdr->frame_control; + u8 try_per_rate = 0, i = 0, rix, nrix; + int is_probe = 0; + + rate_table = sc->cur_rate_table; + rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe); + nrix = rix; + + if (is_probe) { + /* set one try for probe rates. For the + * probes don't enable rts */ + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, + 1, nrix, 0); + + try_per_rate = (ATH_11N_TXMAXTRY/4); + /* Get the next tried/allowed rate. No RTS for the next series + * after the probe rate + */ + nrix = ath_rc_rate_getidx(sc, ath_rc_priv, + rate_table, nrix, 1, 0); + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, + try_per_rate, nrix, 0); + + tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + } else { + try_per_rate = (ATH_11N_TXMAXTRY/4); + /* Set the choosen rate. No RTS for first series entry. */ + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, + try_per_rate, nrix, 0); + } + + /* Fill in the other rates for multirate retry */ + for ( ; i < 4; i++) { + u8 try_num; + u8 min_rate; + + try_num = ((i + 1) == 4) ? + ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ; + min_rate = (((i + 1) == 4) && 0); + + nrix = ath_rc_rate_getidx(sc, ath_rc_priv, + rate_table, nrix, 1, min_rate); + /* All other rates in the series have RTS enabled */ + ath_rc_rate_set_series(rate_table, &rates[i], txrc, + try_num, nrix, 1); + } + + /* + * NB:Change rate series to enable aggregation when operating + * at lower MCS rates. When first rate in series is MCS2 + * in HT40 @ 2.4GHz, series should look like: + * + * {MCS2, MCS1, MCS0, MCS0}. + * + * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should + * look like: + * + * {MCS3, MCS2, MCS1, MCS1} + * + * So, set fourth rate in series to be same as third one for + * above conditions. + */ + if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) && + (conf_is_ht(&sc->hw->conf))) { + 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))) { + rates[3].idx = rates[2].idx; + rates[3].flags = rates[2].flags; + } + } + + /* + * Force hardware to use computed duration for next + * fragment by disabling multi-rate retry, which + * updates duration based on the multi-rate duration table. + * + * FIXME: Fix duration + */ + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && + (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) { + rates[1].count = rates[2].count = rates[3].count = 0; + rates[1].idx = rates[2].idx = rates[3].idx = 0; + rates[0].count = ATH_TXMAXTRY; + } + + /* Setup RTS/CTS */ + ath_rc_rate_set_rtscts(sc, rate_table, tx_info); +} + +static bool ath_rc_update_per(struct ath_softc *sc, + struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries, + u32 now_msec) +{ + bool state_change = false; + int count; + u8 last_per; + static u32 nretry_to_per_lookup[10] = { + 100 * 0 / 1, + 100 * 1 / 4, + 100 * 1 / 2, + 100 * 3 / 4, + 100 * 4 / 5, + 100 * 5 / 6, + 100 * 6 / 7, + 100 * 7 / 8, + 100 * 8 / 9, + 100 * 9 / 10 + }; + + last_per = ath_rc_priv->state[tx_rate].per; + + if (xretries) { + if (xretries == 1) { + ath_rc_priv->state[tx_rate].per += 30; + if (ath_rc_priv->state[tx_rate].per > 100) + ath_rc_priv->state[tx_rate].per = 100; + } else { + /* xretries == 2 */ + count = ARRAY_SIZE(nretry_to_per_lookup); + if (retries >= count) + retries = count - 1; + + /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_per >> 3) + (100 >> 3)); + } + + /* xretries == 1 or 2 */ + + if (ath_rc_priv->probe_rate == tx_rate) + ath_rc_priv->probe_rate = 0; + + } else { /* xretries == 0 */ + count = ARRAY_SIZE(nretry_to_per_lookup); + if (retries >= count) + retries = count - 1; + + if (tx_info_priv->n_bad_frames) { + /* 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 + * next one worked. For the one that worked, + * n_bad_frames subframes out of n_frames wored, + * so the PER for that part is + * 100 * n_bad_frames / n_frames, and it contributes + * 100 * n_bad_frames / (n_frames * (retries+1)) to + * the above PER. The expression below is a + * simplified version of the sum of these two terms. + */ + if (tx_info_priv->n_frames > 0) { + int n_frames, n_bad_frames; + u8 cur_per, new_per; + + n_bad_frames = retries * tx_info_priv->n_frames + + tx_info_priv->n_bad_frames; + n_frames = tx_info_priv->n_frames * (retries + 1); + cur_per = (100 * n_bad_frames / n_frames) >> 3; + new_per = (u8)(last_per - (last_per >> 3) + cur_per); + ath_rc_priv->state[tx_rate].per = new_per; + } + } else { + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_per >> 3) + + (nretry_to_per_lookup[retries] >> 3)); + } + + ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; + ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; + ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi; + ath_rc_priv->rssi_time = now_msec; + + /* + * If we got at most one retry then increase the max rate if + * this was a probe. Otherwise, ignore the probe. + */ + if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { + if (retries > 0 || 2 * tx_info_priv->n_bad_frames > + tx_info_priv->n_frames) { + /* + * Since we probed with just a single attempt, + * any retries means the probe failed. Also, + * if the attempt worked, but more than half + * the subframes were bad then also consider + * the probe a failure. + */ + ath_rc_priv->probe_rate = 0; + } else { + u8 probe_rate = 0; + + ath_rc_priv->rate_max_phy = + ath_rc_priv->probe_rate; + probe_rate = ath_rc_priv->probe_rate; + + if (ath_rc_priv->state[probe_rate].per > 30) + ath_rc_priv->state[probe_rate].per = 20; + + ath_rc_priv->probe_rate = 0; + + /* + * Since this probe succeeded, we allow the next + * probe twice as soon. This allows the maxRate + * to move up faster if the probes are + * succesful. + */ + ath_rc_priv->probe_time = + now_msec - rate_table->probe_interval / 2; + } + } + + if (retries > 0) { + /* + * Don't update anything. We don't know if + * this was because of collisions or poor signal. + * + * Later: if rssi_ack is close to + * ath_rc_priv->state[txRate].rssi_thres and we see lots + * of retries, then we could increase + * ath_rc_priv->state[txRate].rssi_thres. + */ + ath_rc_priv->hw_maxretry_pktcnt = 0; + } else { + int32_t rssi_ackAvg; + int8_t rssi_thres; + int8_t rssi_ack_vmin; + + /* + * It worked with no retries. First ignore bogus (small) + * rssi_ack values. + */ + if (tx_rate == ath_rc_priv->rate_max_phy && + ath_rc_priv->hw_maxretry_pktcnt < 255) { + ath_rc_priv->hw_maxretry_pktcnt++; + } + + if (tx_info_priv->tx.ts_rssi < + rate_table->info[tx_rate].rssi_ack_validmin) + goto exit; + + /* Average the rssi */ + if (tx_rate != ath_rc_priv->rssi_sum_rate) { + ath_rc_priv->rssi_sum_rate = tx_rate; + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; + } + + ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; + ath_rc_priv->rssi_sum_cnt++; + + if (ath_rc_priv->rssi_sum_cnt < 4) + goto exit; + + rssi_ackAvg = + (ath_rc_priv->rssi_sum + 2) / 4; + rssi_thres = + ath_rc_priv->state[tx_rate].rssi_thres; + rssi_ack_vmin = + rate_table->info[tx_rate].rssi_ack_validmin; + + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; + + /* Now reduce the current rssi threshold */ + if ((rssi_ackAvg < rssi_thres + 2) && + (rssi_thres > rssi_ack_vmin)) { + ath_rc_priv->state[tx_rate].rssi_thres--; + } + + state_change = true; + } + } +exit: + return state_change; +} + +/* Update PER, RSSI and whatever else that the code thinks it is doing. + If you can make sense of all this, you really need to go out more. */ + +static void ath_rc_update_ht(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries) +{ +#define CHK_RSSI(rate) \ + ((ath_rc_priv->state[(rate)].rssi_thres + \ + rate_table->info[(rate)].rssi_ack_deltamin) > \ + ath_rc_priv->state[(rate)+1].rssi_thres) + + u32 now_msec = jiffies_to_msecs(jiffies); + int rate; + u8 last_per; + bool state_change = false; + struct ath_rate_table *rate_table = sc->cur_rate_table; + int size = ath_rc_priv->rate_table_size; + + if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) + return; + + /* To compensate for some imbalance between ctrl and ext. channel */ + + if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) + tx_info_priv->tx.ts_rssi = + tx_info_priv->tx.ts_rssi < 3 ? 0 : + tx_info_priv->tx.ts_rssi - 3; + + last_per = ath_rc_priv->state[tx_rate].per; + + /* Update PER first */ + state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, + tx_info_priv, tx_rate, xretries, + retries, now_msec); + + /* + * If this rate looks bad (high PER) then stop using it for + * a while (except if we are probing). + */ + if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && + rate_table->info[tx_rate].ratekbps <= + rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + (u8)tx_rate, &ath_rc_priv->rate_max_phy); + + /* Don't probe for a little while. */ + ath_rc_priv->probe_time = now_msec; + } + + if (state_change) { + /* + * Make sure the rates above this have higher rssi thresholds. + * (Note: Monotonicity is kept within the OFDM rates and + * within the CCK rates. However, no adjustment is + * made to keep the rssi thresholds monotonically + * increasing between the CCK and OFDM rates.) + */ + for (rate = tx_rate; rate < size - 1; rate++) { + if (rate_table->info[rate+1].phy != + rate_table->info[tx_rate].phy) + break; + + if (CHK_RSSI(rate)) { + ath_rc_priv->state[rate+1].rssi_thres = + ath_rc_priv->state[rate].rssi_thres + + rate_table->info[rate].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) + break; + + if (CHK_RSSI(rate)) { + if (ath_rc_priv->state[rate+1].rssi_thres < + rate_table->info[rate].rssi_ack_deltamin) + ath_rc_priv->state[rate].rssi_thres = 0; + else { + ath_rc_priv->state[rate].rssi_thres = + ath_rc_priv->state[rate+1].rssi_thres - + rate_table->info[rate].rssi_ack_deltamin; + } + + if (ath_rc_priv->state[rate].rssi_thres < + rate_table->info[rate].rssi_ack_validmin) { + ath_rc_priv->state[rate].rssi_thres = + rate_table->info[rate].rssi_ack_validmin; + } + } + } + } + + /* Make sure the rates below this have lower PER */ + /* Monotonicity is kept only for rates below the current rate. */ + if (ath_rc_priv->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) + break; + + if (ath_rc_priv->state[rate].per > + ath_rc_priv->state[rate+1].per) { + ath_rc_priv->state[rate].per = + ath_rc_priv->state[rate+1].per; + } + } + } + + /* Maintain monotonicity for rates above the current rate */ + for (rate = tx_rate; rate < size - 1; rate++) { + if (ath_rc_priv->state[rate+1].per < + ath_rc_priv->state[rate].per) + ath_rc_priv->state[rate+1].per = + ath_rc_priv->state[rate].per; + } + + /* Every so often, we reduce the thresholds and + * PER (different for CCK and OFDM). */ + if (now_msec - ath_rc_priv->rssi_down_time >= + rate_table->rssi_reduce_interval) { + + for (rate = 0; rate < size; rate++) { + if (ath_rc_priv->state[rate].rssi_thres > + rate_table->info[rate].rssi_ack_validmin) + ath_rc_priv->state[rate].rssi_thres -= 1; + } + ath_rc_priv->rssi_down_time = now_msec; + } + + /* Every so often, we reduce the thresholds + * and PER (different for CCK and OFDM). */ + if (now_msec - ath_rc_priv->per_down_time >= + rate_table->rssi_reduce_interval) { + for (rate = 0; rate < size; rate++) { + ath_rc_priv->state[rate].per = + 7 * ath_rc_priv->state[rate].per / 8; + } + + ath_rc_priv->per_down_time = now_msec; + } + + ath_debug_stat_retries(sc, tx_rate, xretries, retries, + ath_rc_priv->state[tx_rate].per); + +#undef CHK_RSSI +} + +static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, + struct ieee80211_tx_rate *rate) +{ + int rix; + + if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (rate->flags & IEEE80211_TX_RC_SHORT_GI)) + rix = rate_table->info[rate->idx].ht_index; + else if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rix = rate_table->info[rate->idx].sgi_index; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + rix = rate_table->info[rate->idx].cw40index; + else + rix = rate_table->info[rate->idx].base_index; + + return rix; +} + +static void ath_rc_tx_status(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_tx_info *tx_info, + int final_ts_idx, int xretries, int long_retry) +{ + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + struct ath_rate_table *rate_table; + struct ieee80211_tx_rate *rates = tx_info->status.rates; + u8 flags; + u32 i = 0, rix; + + rate_table = sc->cur_rate_table; + + /* + * If the first rate is not the final index, there + * are intermediate rate failures to be processed. + */ + if (final_ts_idx != 0) { + /* Process intermediate rates that failed.*/ + for (i = 0; i < final_ts_idx ; i++) { + if (rates[i].count != 0 && (rates[i].idx >= 0)) { + flags = rates[i].flags; + + /* If HT40 and we have switched mode from + * 40 to 20 => don't update */ + + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) + return; + + rix = ath_rc_get_rateindex(rate_table, &rates[i]); + ath_rc_update_ht(sc, ath_rc_priv, + tx_info_priv, rix, + xretries ? 1 : 2, + rates[i].count); + } + } + } else { + /* + * Handle the special case of MIMO PS burst, where the second + * aggregate is sent out with only one rate and one try. + * Treating it as an excessive retry penalizes the rate + * inordinately. + */ + if (rates[0].count == 1 && xretries == 1) + xretries = 2; + } + + flags = rates[i].flags; + + /* If HT40 and we have switched mode from 40 to 20 => don't update */ + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) + return; + + rix = ath_rc_get_rateindex(rate_table, &rates[i]); + ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, + xretries, long_retry); +} + +static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, + enum ieee80211_band band, + bool is_ht, bool is_cw_40) +{ + int mode = 0; + + switch(band) { + case IEEE80211_BAND_2GHZ: + mode = ATH9K_MODE_11G; + if (is_ht) + mode = ATH9K_MODE_11NG_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NG_HT40PLUS; + break; + case IEEE80211_BAND_5GHZ: + mode = ATH9K_MODE_11A; + if (is_ht) + mode = ATH9K_MODE_11NA_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NA_HT40PLUS; + break; + default: + DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n"); + return NULL; + } + + BUG_ON(mode >= ATH9K_MODE_MAX); + + DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); + return sc->hw_rate_table[mode]; +} + +static void ath_rc_init(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, + struct ath_rate_table *rate_table) +{ + struct ath_rateset *rateset = &ath_rc_priv->neg_rates; + u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; + u8 i, j, k, hi = 0, hthi = 0; + + if (!rate_table) { + DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); + return; + } + + /* Initial rate table size. Will change depending + * on the working rate set */ + ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; + + /* Initialize thresholds according to the global rate table */ + for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { + ath_rc_priv->state[i].rssi_thres = + rate_table->info[i].rssi_ack_validmin; + ath_rc_priv->state[i].per = 0; + } + + /* Determine the valid rates */ + ath_rc_init_valid_txmask(ath_rc_priv); + + for (i = 0; i < WLAN_RC_PHY_MAX; i++) { + for (j = 0; j < MAX_TX_RATE_PHY; j++) + ath_rc_priv->valid_phy_rateidx[i][j] = 0; + ath_rc_priv->valid_phy_ratecnt[i] = 0; + } + + if (!rateset->rs_nrates) { + /* No working rate, just initialize valid rates */ + hi = ath_rc_init_validrates(ath_rc_priv, rate_table, + ath_rc_priv->ht_cap); + } else { + /* Use intersection of working rates and valid rates */ + hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table, + rateset, ath_rc_priv->ht_cap); + if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) { + hthi = ath_rc_setvalid_htrates(ath_rc_priv, + rate_table, + ht_mcs, + ath_rc_priv->ht_cap); + } + hi = A_MAX(hi, hthi); + } + + ath_rc_priv->rate_table_size = hi + 1; + ath_rc_priv->rate_max_phy = 0; + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); + + for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { + for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { + ath_rc_priv->valid_rate_index[k++] = + ath_rc_priv->valid_phy_rateidx[i][j]; + } + + if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) + || !ath_rc_priv->valid_phy_ratecnt[i]) + continue; + + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; + } + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); + ASSERT(k <= RATE_TABLE_SIZE); + + ath_rc_priv->max_valid_rate = k; + ath_rc_sort_validrates(rate_table, ath_rc_priv); + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + sc->cur_rate_table = rate_table; + + DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n", + ath_rc_priv->ht_cap); +} + +static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, + bool is_cw40, bool is_sgi40) +{ + u8 caps = 0; + + if (sta->ht_cap.ht_supported) { + caps = WLAN_RC_HT_FLAG; + if (sc->sc_ah->caps.tx_chainmask != 1 && + ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) { + if (sta->ht_cap.mcs.rx_mask[1]) + caps |= WLAN_RC_DS_FLAG; + } + if (is_cw40) + caps |= WLAN_RC_40_FLAG; + if (is_sgi40) + caps |= WLAN_RC_SGI_FLAG; + } + + return caps; +} + +/***********************************/ +/* mac80211 Rate Control callbacks */ +/***********************************/ + +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_rate_priv *ath_rc_priv = priv_sta; + struct ath_tx_info_priv *tx_info_priv = NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; + int final_ts_idx, tx_status = 0, is_underrun = 0; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; + + if (!priv_sta || !ieee80211_is_data(fc) || + !tx_info_priv->update_rc) + goto exit; + + if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) + goto exit; + + /* + * If underrun error is seen assume it as an excessive retry only + * if prefetch trigger level have reached the max (0x3f for 5416) + * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY + * times. This affects how ratectrl updates PER for the failed rate. + */ + if (tx_info_priv->tx.ts_flags & + (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && + ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) { + tx_status = 1; + is_underrun = 1; + } + + if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || + (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) + tx_status = 1; + + ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, + (is_underrun) ? ATH_11N_TXMAXTRY : + tx_info_priv->tx.ts_longretry); + + /* Check if aggregation has to be enabled for this tid */ + if (conf_is_ht(&sc->hw->conf) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath_node *an; + + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + an = (struct ath_node *)sta->drv_priv; + + if(ath_tx_aggr_check(sc, an, tid)) + ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid); + } + } + + ath_debug_stat_rc(sc, skb); +exit: + kfree(tx_info_priv); +} + +static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) +{ + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_softc *sc = priv; + struct ath_rate_priv *ath_rc_priv = priv_sta; + __le16 fc = hdr->frame_control; + + /* lowest rate for management and multicast/broadcast frames */ + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || + !sta) { + tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); + tx_info->control.rates[0].count = + is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; + return; + } + + /* Find tx rate for unicast frames */ + ath_rc_ratefind(sc, ath_rc_priv, txrc); +} + +static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) +{ + struct ath_softc *sc = priv; + struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_rate_table *rate_table = NULL; + bool is_cw40, is_sgi40; + int i, j = 0; + + for (i = 0; i < sband->n_bitrates; i++) { + if (sta->supp_rates[sband->band] & BIT(i)) { + ath_rc_priv->neg_rates.rs_rates[j] + = (sband->bitrates[i].bitrate * 2) / 10; + j++; + } + } + ath_rc_priv->neg_rates.rs_nrates = j; + + if (sta->ht_cap.ht_supported) { + for (i = 0, j = 0; i < 77; i++) { + if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) + ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; + if (j == ATH_RATE_MAX) + break; + } + ath_rc_priv->neg_ht_rates.rs_nrates = j; + } + + is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + + /* Choose rate table first */ + + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) || + (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, + is_cw40); + } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { + /* cur_rate_table would be set on init through config() */ + rate_table = sc->cur_rate_table; + } + + ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40); + ath_rc_init(sc, priv_sta, sband, sta, rate_table); +} + +static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed) +{ + struct ath_softc *sc = priv; + struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_rate_table *rate_table = NULL; + bool oper_cw40 = false, oper_sgi40; + bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? + true : false; + bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ? + true : false; + + /* FIXME: Handle AP mode later when we support CWM */ + + if (changed & IEEE80211_RC_HT_CHANGED) { + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + return; + + if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || + sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) + oper_cw40 = true; + + oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + true : false; + + if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, + oper_cw40); + ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, + oper_cw40, oper_sgi40); + ath_rc_init(sc, priv_sta, sband, sta, rate_table); + + DPRINTF(sc, ATH_DBG_CONFIG, + "Operating HT Bandwidth changed to: %d\n", + sc->hw->conf.channel_type); + } + } +} + +static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) +{ + struct ath_wiphy *aphy = hw->priv; + return aphy->sc; +} + +static void ath_rate_free(void *priv) +{ + return; +} + +static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) +{ + struct ath_softc *sc = priv; + struct ath_rate_priv *rate_priv; + + rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); + if (!rate_priv) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to allocate private rc structure\n"); + return NULL; + } + + rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); + rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max; + + return rate_priv; +} + +static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, + void *priv_sta) +{ + struct ath_rate_priv *rate_priv = priv_sta; + kfree(rate_priv); +} + +static struct rate_control_ops ath_rate_ops = { + .module = NULL, + .name = "ath9k_rate_control", + .tx_status = ath_tx_status, + .get_rate = ath_get_rate, + .rate_init = ath_rate_init, + .rate_update = ath_rate_update, + .alloc = ath_rate_alloc, + .free = ath_rate_free, + .alloc_sta = ath_rate_alloc_sta, + .free_sta = ath_rate_free_sta, +}; + +void ath_rate_attach(struct ath_softc *sc) +{ + sc->hw_rate_table[ATH9K_MODE_11B] = + &ar5416_11b_ratetable; + sc->hw_rate_table[ATH9K_MODE_11A] = + &ar5416_11a_ratetable; + sc->hw_rate_table[ATH9K_MODE_11G] = + &ar5416_11g_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = + &ar5416_11ng_ratetable; +} + +int ath_rate_control_register(void) +{ + return ieee80211_rate_control_register(&ath_rate_ops); +} + +void ath_rate_control_unregister(void) +{ + ieee80211_rate_control_unregister(&ath_rate_ops); +} diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h new file mode 100644 index 0000000..e3abd76 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2004 Sam Leffler, Errno Consulting + * Copyright (c) 2004 Video54 Technologies, Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef RC_H +#define RC_H + +struct ath_softc; + +#define ATH_RATE_MAX 30 +#define RATE_TABLE_SIZE 64 +#define MAX_TX_RATE_PHY 48 + +/* VALID_ALL - valid for 20/40/Legacy, + * VALID - Legacy only, + * VALID_20 - HT 20 only, + * VALID_40 - HT 40 only */ + +#define INVALID 0x0 +#define VALID 0x1 +#define VALID_20 0x2 +#define VALID_40 0x4 +#define VALID_2040 (VALID_20|VALID_40) +#define VALID_ALL (VALID_2040|VALID) + +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, + WLAN_RC_PHY_HT_20_SS, + WLAN_RC_PHY_HT_20_DS, + WLAN_RC_PHY_HT_40_SS, + WLAN_RC_PHY_HT_40_DS, + WLAN_RC_PHY_HT_20_SS_HGI, + WLAN_RC_PHY_HT_20_DS_HGI, + WLAN_RC_PHY_HT_40_SS_HGI, + WLAN_RC_PHY_HT_40_DS_HGI, + 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_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)) + +#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) + +#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ + (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID)) + +/* Return TRUE if flag supports HT20 && client supports HT20 or + * return TRUE if flag supports HT40 && client supports HT40. + * This is used becos some rates overlap between HT20/HT40. + */ +#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ + (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \ + ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG))) + +#define WLAN_RC_DS_FLAG (0x01) +#define WLAN_RC_40_FLAG (0x02) +#define WLAN_RC_SGI_FLAG (0x04) +#define WLAN_RC_HT_FLAG (0x08) + +/** + * 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 + */ +struct ath_rate_table { + int rate_cnt; + struct { + 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; + u32 rssi_reduce_interval; + u8 initial_ratemax; +}; + +struct ath_tx_ratectrl_state { + int8_t rssi_thres; /* required rssi for this rate (dB) */ + u8 per; /* recent estimate of packet error rate (%) */ +}; + +struct ath_rateset { + u8 rs_nrates; + u8 rs_rates[ATH_RATE_MAX]; +}; + +/** + * struct ath_rate_priv - Rate Control priv data + * @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 + * @prev_data_rix: rate idx of last data frame + * @ht_cap: HT capabilities + * @neg_rates: Negotatied rates + * @neg_ht_rates: Negotiated HT rates + */ +struct ath_rate_priv { + 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; + u8 hw_maxretry_pktcnt; + u8 max_valid_rate; + u8 valid_rate_index[RATE_TABLE_SIZE]; + u8 ht_cap; + u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; + u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; + u8 rate_max_phy; + u32 rssi_time; + u32 rssi_down_time; + u32 probe_time; + u32 per_down_time; + u32 probe_interval; + u32 prev_data_rix; + u32 tx_triglevel_max; + struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; + struct ath_rateset neg_rates; + struct ath_rateset neg_ht_rates; + struct ath_rate_softc *asc; +}; + +enum ath9k_internal_frame_type { + ATH9K_NOT_INTERNAL, + ATH9K_INT_PAUSE, + ATH9K_INT_UNPAUSE +}; + +struct ath_tx_info_priv { + struct ath_wiphy *aphy; + struct ath_tx_status tx; + int n_frames; + int n_bad_frames; + bool update_rc; + enum ath9k_internal_frame_type frame_type; +}; + +#define ATH_TX_INFO_PRIV(tx_info) \ + ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0])) + +void ath_rate_attach(struct ath_softc *sc); +u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); +int ath_rate_control_register(void); +void ath_rate_control_unregister(void); + +#endif /* RC_H */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c new file mode 100644 index 0000000..b46badd --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, + struct ieee80211_hdr *hdr) +{ + struct ieee80211_hw *hw = sc->pri_wiphy->hw; + int i; + + spin_lock_bh(&sc->wiphy_lock); + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr) + == 0) { + hw = aphy->hw; + break; + } + } + spin_unlock_bh(&sc->wiphy_lock); + return hw; +} + +/* + * Setup and link descriptors. + * + * 11N: we can no longer afford to self link the last descriptor. + * MAC acknowledges BA status as long as it copies frames to host + * buffer (or rx fifo). This can incorrectly acknowledge packets + * to a sender if last desc is self-linked. + */ +static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_desc *ds; + struct sk_buff *skb; + + ATH_RXBUF_RESET(bf); + + ds = bf->bf_desc; + ds->ds_link = 0; /* link to null */ + ds->ds_data = bf->bf_buf_addr; + + /* virtual addr of the beginning of the buffer. */ + skb = bf->bf_mpdu; + ASSERT(skb != NULL); + ds->ds_vdata = skb->data; + + /* setup rx descriptors. The rx.bufsize here tells the harware + * how much data it can DMA to us and that we are prepared + * to process */ + ath9k_hw_setuprxdesc(ah, ds, + sc->rx.bufsize, + 0); + + if (sc->rx.rxlink == NULL) + ath9k_hw_putrxbuf(ah, bf->bf_daddr); + else + *sc->rx.rxlink = bf->bf_daddr; + + sc->rx.rxlink = &ds->ds_link; + ath9k_hw_rxena(ah); +} + +static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) +{ + /* XXX block beacon interrupts */ + ath9k_hw_setantenna(sc->sc_ah, antenna); + sc->rx.defant = antenna; + sc->rx.rxotherant = 0; +} + +/* + * Extend 15-bit time stamp from rx descriptor to + * a full 64-bit TSF using the current h/w TSF. +*/ +static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) +{ + u64 tsf; + + tsf = ath9k_hw_gettsf64(sc->sc_ah); + if ((tsf & 0x7fff) < rstamp) + tsf -= 0x8000; + return (tsf & ~0x7fff) | rstamp; +} + +static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask) +{ + struct sk_buff *skb; + u32 off; + + /* + * Cache-line-align. This is important (for the + * 5210 at least) as not doing so causes bogus data + * in rx'd frames. + */ + + /* Note: the kernel can allocate a value greater than + * what we ask it to give us. We really only need 4 KB as that + * is this hardware supports and in fact we need at least 3849 + * as that is the MAX AMSDU size this hardware supports. + * Unfortunately this means we may get 8 KB here from the + * kernel... and that is actually what is observed on some + * systems :( */ + skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask); + if (skb != NULL) { + off = ((unsigned long) skb->data) % sc->cachelsz; + if (off != 0) + skb_reserve(skb, sc->cachelsz - off); + } else { + DPRINTF(sc, ATH_DBG_FATAL, + "skbuff alloc of size %u failed\n", len); + return NULL; + } + + return skb; +} + +/* + * For Decrypt or Demic errors, we only mark packet status here and always push + * up the frame up to let mac80211 handle the actual error case, be it no + * decryption key or real decryption error. This let us keep statistics there. + */ +static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, + struct ieee80211_rx_status *rx_status, bool *decrypt_error, + struct ath_softc *sc) +{ + struct ieee80211_hdr *hdr; + u8 ratecode; + __le16 fc; + struct ieee80211_hw *hw; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + hw = ath_get_virt_hw(sc, hdr); + + if (ds->ds_rxstat.rs_more) { + /* + * Frame spans multiple descriptors; this cannot happen yet + * as we don't support jumbograms. If not in monitor mode, + * discard the frame. Enable this if you want to see + * error frames in Monitor mode. + */ + if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR) + goto rx_next; + } else if (ds->ds_rxstat.rs_status != 0) { + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) + goto rx_next; + + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { + *decrypt_error = true; + } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { + if (ieee80211_is_ctl(fc)) + /* + * Sometimes, we get invalid + * MIC failures on valid control frames. + * Remove these mic errors. + */ + ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC; + else + rx_status->flag |= RX_FLAG_MMIC_ERROR; + } + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_CRC)) + goto rx_next; + } else { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { + goto rx_next; + } + } + } + + ratecode = ds->ds_rxstat.rs_rate; + + if (ratecode & 0x80) { + /* HT rate */ + rx_status->flag |= RX_FLAG_HT; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) + rx_status->flag |= RX_FLAG_40MHZ; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) + rx_status->flag |= RX_FLAG_SHORT_GI; + rx_status->rate_idx = ratecode & 0x7f; + } else { + int i = 0, cur_band, n_rates; + + cur_band = hw->conf.channel->band; + n_rates = sc->sbands[cur_band].n_bitrates; + + for (i = 0; i < n_rates; i++) { + if (sc->sbands[cur_band].bitrates[i].hw_value == + ratecode) { + rx_status->rate_idx = i; + break; + } + + if (sc->sbands[cur_band].bitrates[i].hw_value_short == + ratecode) { + rx_status->rate_idx = i; + rx_status->flag |= RX_FLAG_SHORTPRE; + break; + } + } + } + + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); + rx_status->band = hw->conf.channel->band; + rx_status->freq = hw->conf.channel->center_freq; + rx_status->noise = sc->ani.noise_floor; + rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; + rx_status->antenna = ds->ds_rxstat.rs_antenna; + + /* at 45 you will be able to use MCS 15 reliably. A more elaborate + * scheme can be used here but it requires tables of SNR/throughput for + * each possible mode used. */ + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + + /* rssi can be more than 45 though, anything above that + * should be considered at 100% */ + if (rx_status->qual > 100) + rx_status->qual = 100; + + rx_status->flag |= RX_FLAG_TSFT; + + return 1; +rx_next: + return 0; +} + +static void ath_opmode_init(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + u32 rfilt, mfilt[2]; + + /* configure rx filter */ + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(ah, rfilt); + + /* configure bssid mask */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + ath9k_hw_setbssidmask(sc); + + /* configure operational mode */ + ath9k_hw_setopmode(ah); + + /* Handle any link-level address change. */ + ath9k_hw_setmac(ah, sc->sc_ah->macaddr); + + /* calculate and install multicast filter */ + mfilt[0] = mfilt[1] = ~0; + ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); +} + +int ath_rx_init(struct ath_softc *sc, int nbufs) +{ + struct sk_buff *skb; + struct ath_buf *bf; + int error = 0; + + spin_lock_init(&sc->rx.rxflushlock); + sc->sc_flags &= ~SC_OP_RXFLUSH; + spin_lock_init(&sc->rx.rxbuflock); + + sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, + min(sc->cachelsz, (u16)64)); + + DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + sc->cachelsz, sc->rx.bufsize); + + /* Initialize rx descriptors */ + + error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, + "rx", nbufs, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "failed to allocate rx descriptors: %d\n", error); + goto err; + } + + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); + if (skb == NULL) { + error = -ENOMEM; + goto err; + } + + bf->bf_mpdu = skb; + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, + sc->rx.bufsize, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_FATAL, + "dma_mapping_error() on RX init\n"); + error = -ENOMEM; + goto err; + } + bf->bf_dmacontext = bf->bf_buf_addr; + } + sc->rx.rxlink = NULL; + +err: + if (error) + ath_rx_cleanup(sc); + + return error; +} + +void ath_rx_cleanup(struct ath_softc *sc) +{ + struct sk_buff *skb; + struct ath_buf *bf; + + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = bf->bf_mpdu; + if (skb) { + dma_unmap_single(sc->dev, bf->bf_buf_addr, + sc->rx.bufsize, DMA_FROM_DEVICE); + dev_kfree_skb(skb); + } + } + + if (sc->rx.rxdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); +} + +/* + * Calculate the receive filter according to the + * operating mode and state: + * + * o always accept unicast, broadcast, and multicast traffic + * o maintain current state of phy error reception (the hal + * may enable phy error frames for noise immunity work) + * o probe request frames are accepted only when operating in + * hostap, adhoc, or monitor modes + * o enable promiscuous mode according to the interface state + * o accept beacons: + * - when operating in adhoc mode so the 802.11 layer creates + * node table entries for peers, + * - when operating in station mode for collecting rssi data when + * the station is otherwise quiet, or + * - when operating as a repeater so we see repeater-sta beacons + * - when scanning + */ + +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) + | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST + | ATH9K_RX_FILTER_MCAST; + + /* If not a STA, enable processing of Probe Requests */ + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + rfilt |= ATH9K_RX_FILTER_PROBEREQ; + + /* + * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station + * mode interface or when in monitor mode. AP mode does not need this + * since it receives all in-BSS frames anyway. + */ + if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) && + (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || + (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR)) + rfilt |= ATH9K_RX_FILTER_PROM; + + if (sc->rx.rxfilter & FIF_CONTROL) + rfilt |= ATH9K_RX_FILTER_CONTROL; + + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)) + rfilt |= ATH9K_RX_FILTER_MYBEACON; + else + rfilt |= ATH9K_RX_FILTER_BEACON; + + /* If in HOSTAP mode, want to enable reception of PSPOLL frames */ + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) + rfilt |= ATH9K_RX_FILTER_PSPOLL; + + if (sc->sec_wiphy) { + /* TODO: only needed if more than one BSSID is in use in + * station/adhoc mode */ + /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM + */ + rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; + } + + return rfilt; + +#undef RX_FILTER_PRESERVE +} + +int ath_startrecv(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_buf *bf, *tbf; + + spin_lock_bh(&sc->rx.rxbuflock); + if (list_empty(&sc->rx.rxbuf)) + goto start_recv; + + sc->rx.rxlink = NULL; + list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { + ath_rx_buf_link(sc, bf); + } + + /* We could have deleted elements so the list may be empty now */ + if (list_empty(&sc->rx.rxbuf)) + goto start_recv; + + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + ath9k_hw_putrxbuf(ah, bf->bf_daddr); + ath9k_hw_rxena(ah); + +start_recv: + spin_unlock_bh(&sc->rx.rxbuflock); + ath_opmode_init(sc); + ath9k_hw_startpcureceive(ah); + + return 0; +} + +bool ath_stoprecv(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + bool stopped; + + ath9k_hw_stoppcurecv(ah); + ath9k_hw_setrxfilter(ah, 0); + stopped = ath9k_hw_stopdmarecv(ah); + sc->rx.rxlink = NULL; + + return stopped; +} + +void ath_flushrecv(struct ath_softc *sc) +{ + spin_lock_bh(&sc->rx.rxflushlock); + sc->sc_flags |= SC_OP_RXFLUSH; + ath_rx_tasklet(sc, 1); + sc->sc_flags &= ~SC_OP_RXFLUSH; + spin_unlock_bh(&sc->rx.rxflushlock); +} + +int ath_rx_tasklet(struct ath_softc *sc, int flush) +{ +#define PA2DESC(_sc, _pa) \ + ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc + \ + ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr))) + + struct ath_buf *bf; + struct ath_desc *ds; + struct sk_buff *skb = NULL, *requeue_skb; + struct ieee80211_rx_status rx_status; + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_hdr *hdr; + int hdrlen, padsize, retval; + bool decrypt_error = false; + u8 keyix; + __le16 fc; + + spin_lock_bh(&sc->rx.rxbuflock); + + do { + /* If handling rx interrupt and flush is in progress => exit */ + if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) + break; + + if (list_empty(&sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; + break; + } + + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + ds = bf->bf_desc; + + /* + * Must provide the virtual address of the current + * descriptor, the physical address, and the virtual + * address of the next descriptor in the h/w chain. + * This allows the HAL to look ahead to see if the + * hardware is done with a descriptor by checking the + * done bit in the following descriptor and the address + * of the current descriptor the DMA engine is working + * on. All this is necessary because of our use of + * a self-linked list to avoid rx overruns. + */ + retval = ath9k_hw_rxprocdesc(ah, ds, + bf->bf_daddr, + PA2DESC(sc, ds->ds_link), + 0); + if (retval == -EINPROGRESS) { + struct ath_buf *tbf; + struct ath_desc *tds; + + if (list_is_last(&bf->list, &sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; + break; + } + + tbf = list_entry(bf->list.next, struct ath_buf, list); + + /* + * On some hardware the descriptor status words could + * get corrupted, including the done bit. Because of + * this, check if the next descriptor's done bit is + * set or not. + * + * If the next descriptor's done bit is set, the current + * descriptor has been corrupted. Force s/w to discard + * this descriptor and continue... + */ + + tds = tbf->bf_desc; + retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, + PA2DESC(sc, tds->ds_link), 0); + if (retval == -EINPROGRESS) { + break; + } + } + + skb = bf->bf_mpdu; + if (!skb) + continue; + + /* + * Synchronize the DMA transfer with CPU before + * 1. accessing the frame + * 2. requeueing the same buffer to h/w + */ + dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, + sc->rx.bufsize, + DMA_FROM_DEVICE); + + /* + * If we're asked to flush receive queue, directly + * chain it back at the queue without processing it. + */ + if (flush) + goto requeue; + + if (!ds->ds_rxstat.rs_datalen) + goto requeue; + + /* The status portion of the descriptor could get corrupted. */ + if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) + goto requeue; + + if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) + goto requeue; + + /* Ensure we always have an skb to requeue once we are done + * processing the current buffer's skb */ + requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC); + + /* If there is no memory we ignore the current RX'd frame, + * tell hardware it can give us a new frame using the old + * skb and put it at the tail of the sc->rx.rxbuf list for + * processing. */ + if (!requeue_skb) + goto requeue; + + /* Unmap the frame */ + dma_unmap_single(sc->dev, bf->bf_buf_addr, + sc->rx.bufsize, + DMA_FROM_DEVICE); + + skb_put(skb, ds->ds_rxstat.rs_datalen); + skb->protocol = cpu_to_be16(ETH_P_CONTROL); + + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *)skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + + keyix = ds->ds_rxstat.rs_keyix; + + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + rx_status.flag |= RX_FLAG_DECRYPTED; + } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, sc->keymap)) + rx_status.flag |= RX_FLAG_DECRYPTED; + } + if (ah->sw_mgmt_crypto && + (rx_status.flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(hdr->frame_control)) { + /* Use software decrypt for management frames. */ + rx_status.flag &= ~RX_FLAG_DECRYPTED; + } + + /* Send the frame to mac80211 */ + if (hdr->addr1[5] & 0x01) { + int i; + /* + * Deliver broadcast/multicast frames to all suitable + * virtual wiphys. + */ + /* TODO: filter based on channel configuration */ + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + struct sk_buff *nskb; + if (aphy == NULL) + continue; + nskb = skb_copy(skb, GFP_ATOMIC); + if (nskb) + __ieee80211_rx(aphy->hw, nskb, + &rx_status); + } + __ieee80211_rx(sc->hw, skb, &rx_status); + } else { + /* Deliver unicast frames based on receiver address */ + __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, + &rx_status); + } + + /* We will now give hardware our shiny new allocated skb */ + bf->bf_mpdu = requeue_skb; + bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, + sc->rx.bufsize, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(requeue_skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_FATAL, + "dma_mapping_error() on RX\n"); + break; + } + bf->bf_dmacontext = bf->bf_buf_addr; + + /* + * change the default rx antenna if rx diversity chooses the + * other antenna 3 times in a row. + */ + if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { + if (++sc->rx.rxotherant >= 3) + ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); + } else { + sc->rx.rxotherant = 0; + } + + if (ieee80211_is_beacon(fc) && + (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + } +requeue: + list_move_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_buf_link(sc, bf); + } while (1); + + spin_unlock_bh(&sc->rx.rxbuflock); + + return 0; +#undef PA2DESC +} diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h new file mode 100644 index 0000000..5260524 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -0,0 +1,1511 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_H +#define REG_H + +#define AR_CR 0x0008 +#define AR_CR_RXE 0x00000004 +#define AR_CR_RXD 0x00000020 +#define AR_CR_SWI 0x00000040 + +#define AR_RXDP 0x000C + +#define AR_CFG 0x0014 +#define AR_CFG_SWTD 0x00000001 +#define AR_CFG_SWTB 0x00000002 +#define AR_CFG_SWRD 0x00000004 +#define AR_CFG_SWRB 0x00000008 +#define AR_CFG_SWRG 0x00000010 +#define AR_CFG_AP_ADHOC_INDICATION 0x00000020 +#define AR_CFG_PHOK 0x00000100 +#define AR_CFG_CLK_GATE_DIS 0x00000400 +#define AR_CFG_EEBS 0x00000200 +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000 +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 + +#define AR_MIRT 0x0020 +#define AR_MIRT_VAL 0x0000ffff +#define AR_MIRT_VAL_S 16 + +#define AR_IER 0x0024 +#define AR_IER_ENABLE 0x00000001 +#define AR_IER_DISABLE 0x00000000 + +#define AR_TIMT 0x0028 +#define AR_TIMT_LAST 0x0000ffff +#define AR_TIMT_LAST_S 0 +#define AR_TIMT_FIRST 0xffff0000 +#define AR_TIMT_FIRST_S 16 + +#define AR_RIMT 0x002C +#define AR_RIMT_LAST 0x0000ffff +#define AR_RIMT_LAST_S 0 +#define AR_RIMT_FIRST 0xffff0000 +#define AR_RIMT_FIRST_S 16 + +#define AR_DMASIZE_4B 0x00000000 +#define AR_DMASIZE_8B 0x00000001 +#define AR_DMASIZE_16B 0x00000002 +#define AR_DMASIZE_32B 0x00000003 +#define AR_DMASIZE_64B 0x00000004 +#define AR_DMASIZE_128B 0x00000005 +#define AR_DMASIZE_256B 0x00000006 +#define AR_DMASIZE_512B 0x00000007 + +#define AR_TXCFG 0x0030 +#define AR_TXCFG_DMASZ_MASK 0x00000007 +#define AR_TXCFG_DMASZ_4B 0 +#define AR_TXCFG_DMASZ_8B 1 +#define AR_TXCFG_DMASZ_16B 2 +#define AR_TXCFG_DMASZ_32B 3 +#define AR_TXCFG_DMASZ_64B 4 +#define AR_TXCFG_DMASZ_128B 5 +#define AR_TXCFG_DMASZ_256B 6 +#define AR_TXCFG_DMASZ_512B 7 +#define AR_FTRIG 0x000003F0 +#define AR_FTRIG_S 4 +#define AR_FTRIG_IMMED 0x00000000 +#define AR_FTRIG_64B 0x00000010 +#define AR_FTRIG_128B 0x00000020 +#define AR_FTRIG_192B 0x00000030 +#define AR_FTRIG_256B 0x00000040 +#define AR_FTRIG_512B 0x00000080 +#define AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY 0x00000800 + +#define AR_RXCFG 0x0034 +#define AR_RXCFG_CHIRP 0x00000008 +#define AR_RXCFG_ZLFDMA 0x00000010 +#define AR_RXCFG_DMASZ_MASK 0x00000007 +#define AR_RXCFG_DMASZ_4B 0 +#define AR_RXCFG_DMASZ_8B 1 +#define AR_RXCFG_DMASZ_16B 2 +#define AR_RXCFG_DMASZ_32B 3 +#define AR_RXCFG_DMASZ_64B 4 +#define AR_RXCFG_DMASZ_128B 5 +#define AR_RXCFG_DMASZ_256B 6 +#define AR_RXCFG_DMASZ_512B 7 + +#define AR_MIBC 0x0040 +#define AR_MIBC_COW 0x00000001 +#define AR_MIBC_FMC 0x00000002 +#define AR_MIBC_CMC 0x00000004 +#define AR_MIBC_MCS 0x00000008 + +#define AR_TOPS 0x0044 +#define AR_TOPS_MASK 0x0000FFFF + +#define AR_RXNPTO 0x0048 +#define AR_RXNPTO_MASK 0x000003FF + +#define AR_TXNPTO 0x004C +#define AR_TXNPTO_MASK 0x000003FF +#define AR_TXNPTO_QCU_MASK 0x000FFC00 + +#define AR_RPGTO 0x0050 +#define AR_RPGTO_MASK 0x000003FF + +#define AR_RPCNT 0x0054 +#define AR_RPCNT_MASK 0x0000001F + +#define AR_MACMISC 0x0058 +#define AR_MACMISC_PCI_EXT_FORCE 0x00000010 +#define AR_MACMISC_DMA_OBS 0x000001E0 +#define AR_MACMISC_DMA_OBS_S 5 +#define AR_MACMISC_DMA_OBS_LINE_0 0 +#define AR_MACMISC_DMA_OBS_LINE_1 1 +#define AR_MACMISC_DMA_OBS_LINE_2 2 +#define AR_MACMISC_DMA_OBS_LINE_3 3 +#define AR_MACMISC_DMA_OBS_LINE_4 4 +#define AR_MACMISC_DMA_OBS_LINE_5 5 +#define AR_MACMISC_DMA_OBS_LINE_6 6 +#define AR_MACMISC_DMA_OBS_LINE_7 7 +#define AR_MACMISC_DMA_OBS_LINE_8 8 +#define AR_MACMISC_MISC_OBS 0x00000E00 +#define AR_MACMISC_MISC_OBS_S 9 +#define AR_MACMISC_MISC_OBS_BUS_LSB 0x00007000 +#define AR_MACMISC_MISC_OBS_BUS_LSB_S 12 +#define AR_MACMISC_MISC_OBS_BUS_MSB 0x00038000 +#define AR_MACMISC_MISC_OBS_BUS_MSB_S 15 +#define AR_MACMISC_MISC_OBS_BUS_1 1 + +#define AR_GTXTO 0x0064 +#define AR_GTXTO_TIMEOUT_COUNTER 0x0000FFFF +#define AR_GTXTO_TIMEOUT_LIMIT 0xFFFF0000 +#define AR_GTXTO_TIMEOUT_LIMIT_S 16 + +#define AR_GTTM 0x0068 +#define AR_GTTM_USEC 0x00000001 +#define AR_GTTM_IGNORE_IDLE 0x00000002 +#define AR_GTTM_RESET_IDLE 0x00000004 +#define AR_GTTM_CST_USEC 0x00000008 + +#define AR_CST 0x006C +#define AR_CST_TIMEOUT_COUNTER 0x0000FFFF +#define AR_CST_TIMEOUT_LIMIT 0xFFFF0000 +#define AR_CST_TIMEOUT_LIMIT_S 16 + +#define AR_ISR 0x0080 +#define AR_ISR_RXOK 0x00000001 +#define AR_ISR_RXDESC 0x00000002 +#define AR_ISR_RXERR 0x00000004 +#define AR_ISR_RXNOPKT 0x00000008 +#define AR_ISR_RXEOL 0x00000010 +#define AR_ISR_RXORN 0x00000020 +#define AR_ISR_TXOK 0x00000040 +#define AR_ISR_TXDESC 0x00000080 +#define AR_ISR_TXERR 0x00000100 +#define AR_ISR_TXNOPKT 0x00000200 +#define AR_ISR_TXEOL 0x00000400 +#define AR_ISR_TXURN 0x00000800 +#define AR_ISR_MIB 0x00001000 +#define AR_ISR_SWI 0x00002000 +#define AR_ISR_RXPHY 0x00004000 +#define AR_ISR_RXKCM 0x00008000 +#define AR_ISR_SWBA 0x00010000 +#define AR_ISR_BRSSI 0x00020000 +#define AR_ISR_BMISS 0x00040000 +#define AR_ISR_BNR 0x00100000 +#define AR_ISR_RXCHIRP 0x00200000 +#define AR_ISR_BCNMISC 0x00800000 +#define AR_ISR_TIM 0x00800000 +#define AR_ISR_QCBROVF 0x02000000 +#define AR_ISR_QCBRURN 0x04000000 +#define AR_ISR_QTRIG 0x08000000 +#define AR_ISR_GENTMR 0x10000000 + +#define AR_ISR_TXMINTR 0x00080000 +#define AR_ISR_RXMINTR 0x01000000 +#define AR_ISR_TXINTM 0x40000000 +#define AR_ISR_RXINTM 0x80000000 + +#define AR_ISR_S0 0x0084 +#define AR_ISR_S0_QCU_TXOK 0x000003FF +#define AR_ISR_S0_QCU_TXOK_S 0 +#define AR_ISR_S0_QCU_TXDESC 0x03FF0000 +#define AR_ISR_S0_QCU_TXDESC_S 16 + +#define AR_ISR_S1 0x0088 +#define AR_ISR_S1_QCU_TXERR 0x000003FF +#define AR_ISR_S1_QCU_TXERR_S 0 +#define AR_ISR_S1_QCU_TXEOL 0x03FF0000 +#define AR_ISR_S1_QCU_TXEOL_S 16 + +#define AR_ISR_S2 0x008c +#define AR_ISR_S2_QCU_TXURN 0x000003FF +#define AR_ISR_S2_CST 0x00400000 +#define AR_ISR_S2_GTT 0x00800000 +#define AR_ISR_S2_TIM 0x01000000 +#define AR_ISR_S2_CABEND 0x02000000 +#define AR_ISR_S2_DTIMSYNC 0x04000000 +#define AR_ISR_S2_BCNTO 0x08000000 +#define AR_ISR_S2_CABTO 0x10000000 +#define AR_ISR_S2_DTIM 0x20000000 +#define AR_ISR_S2_TSFOOR 0x40000000 +#define AR_ISR_S2_TBTT_TIME 0x80000000 + +#define AR_ISR_S3 0x0090 +#define AR_ISR_S3_QCU_QCBROVF 0x000003FF +#define AR_ISR_S3_QCU_QCBRURN 0x03FF0000 + +#define AR_ISR_S4 0x0094 +#define AR_ISR_S4_QCU_QTRIG 0x000003FF +#define AR_ISR_S4_RESV0 0xFFFFFC00 + +#define AR_ISR_S5 0x0098 +#define AR_ISR_S5_TIMER_TRIG 0x000000FF +#define AR_ISR_S5_TIMER_THRESH 0x0007FE00 +#define AR_ISR_S5_TIM_TIMER 0x00000010 +#define AR_ISR_S5_DTIM_TIMER 0x00000020 +#define AR_ISR_S5_S 0x00d8 +#define AR_IMR_S5 0x00b8 +#define AR_IMR_S5_TIM_TIMER 0x00000010 +#define AR_IMR_S5_DTIM_TIMER 0x00000020 + + +#define AR_IMR 0x00a0 +#define AR_IMR_RXOK 0x00000001 +#define AR_IMR_RXDESC 0x00000002 +#define AR_IMR_RXERR 0x00000004 +#define AR_IMR_RXNOPKT 0x00000008 +#define AR_IMR_RXEOL 0x00000010 +#define AR_IMR_RXORN 0x00000020 +#define AR_IMR_TXOK 0x00000040 +#define AR_IMR_TXDESC 0x00000080 +#define AR_IMR_TXERR 0x00000100 +#define AR_IMR_TXNOPKT 0x00000200 +#define AR_IMR_TXEOL 0x00000400 +#define AR_IMR_TXURN 0x00000800 +#define AR_IMR_MIB 0x00001000 +#define AR_IMR_SWI 0x00002000 +#define AR_IMR_RXPHY 0x00004000 +#define AR_IMR_RXKCM 0x00008000 +#define AR_IMR_SWBA 0x00010000 +#define AR_IMR_BRSSI 0x00020000 +#define AR_IMR_BMISS 0x00040000 +#define AR_IMR_BNR 0x00100000 +#define AR_IMR_RXCHIRP 0x00200000 +#define AR_IMR_BCNMISC 0x00800000 +#define AR_IMR_TIM 0x00800000 +#define AR_IMR_QCBROVF 0x02000000 +#define AR_IMR_QCBRURN 0x04000000 +#define AR_IMR_QTRIG 0x08000000 +#define AR_IMR_GENTMR 0x10000000 + +#define AR_IMR_TXMINTR 0x00080000 +#define AR_IMR_RXMINTR 0x01000000 +#define AR_IMR_TXINTM 0x40000000 +#define AR_IMR_RXINTM 0x80000000 + +#define AR_IMR_S0 0x00a4 +#define AR_IMR_S0_QCU_TXOK 0x000003FF +#define AR_IMR_S0_QCU_TXOK_S 0 +#define AR_IMR_S0_QCU_TXDESC 0x03FF0000 +#define AR_IMR_S0_QCU_TXDESC_S 16 + +#define AR_IMR_S1 0x00a8 +#define AR_IMR_S1_QCU_TXERR 0x000003FF +#define AR_IMR_S1_QCU_TXERR_S 0 +#define AR_IMR_S1_QCU_TXEOL 0x03FF0000 +#define AR_IMR_S1_QCU_TXEOL_S 16 + +#define AR_IMR_S2 0x00ac +#define AR_IMR_S2_QCU_TXURN 0x000003FF +#define AR_IMR_S2_QCU_TXURN_S 0 +#define AR_IMR_S2_CST 0x00400000 +#define AR_IMR_S2_GTT 0x00800000 +#define AR_IMR_S2_TIM 0x01000000 +#define AR_IMR_S2_CABEND 0x02000000 +#define AR_IMR_S2_DTIMSYNC 0x04000000 +#define AR_IMR_S2_BCNTO 0x08000000 +#define AR_IMR_S2_CABTO 0x10000000 +#define AR_IMR_S2_DTIM 0x20000000 +#define AR_IMR_S2_TSFOOR 0x40000000 + +#define AR_IMR_S3 0x00b0 +#define AR_IMR_S3_QCU_QCBROVF 0x000003FF +#define AR_IMR_S3_QCU_QCBRURN 0x03FF0000 +#define AR_IMR_S3_QCU_QCBRURN_S 16 + +#define AR_IMR_S4 0x00b4 +#define AR_IMR_S4_QCU_QTRIG 0x000003FF +#define AR_IMR_S4_RESV0 0xFFFFFC00 + +#define AR_IMR_S5 0x00b8 +#define AR_IMR_S5_TIMER_TRIG 0x000000FF +#define AR_IMR_S5_TIMER_THRESH 0x0000FF00 + + +#define AR_ISR_RAC 0x00c0 +#define AR_ISR_S0_S 0x00c4 +#define AR_ISR_S0_QCU_TXOK 0x000003FF +#define AR_ISR_S0_QCU_TXOK_S 0 +#define AR_ISR_S0_QCU_TXDESC 0x03FF0000 +#define AR_ISR_S0_QCU_TXDESC_S 16 + +#define AR_ISR_S1_S 0x00c8 +#define AR_ISR_S1_QCU_TXERR 0x000003FF +#define AR_ISR_S1_QCU_TXERR_S 0 +#define AR_ISR_S1_QCU_TXEOL 0x03FF0000 +#define AR_ISR_S1_QCU_TXEOL_S 16 + +#define AR_ISR_S2_S 0x00cc +#define AR_ISR_S3_S 0x00d0 +#define AR_ISR_S4_S 0x00d4 +#define AR_ISR_S5_S 0x00d8 +#define AR_DMADBG_0 0x00e0 +#define AR_DMADBG_1 0x00e4 +#define AR_DMADBG_2 0x00e8 +#define AR_DMADBG_3 0x00ec +#define AR_DMADBG_4 0x00f0 +#define AR_DMADBG_5 0x00f4 +#define AR_DMADBG_6 0x00f8 +#define AR_DMADBG_7 0x00fc + +#define AR_NUM_QCU 10 +#define AR_QCU_0 0x0001 +#define AR_QCU_1 0x0002 +#define AR_QCU_2 0x0004 +#define AR_QCU_3 0x0008 +#define AR_QCU_4 0x0010 +#define AR_QCU_5 0x0020 +#define AR_QCU_6 0x0040 +#define AR_QCU_7 0x0080 +#define AR_QCU_8 0x0100 +#define AR_QCU_9 0x0200 + +#define AR_Q0_TXDP 0x0800 +#define AR_Q1_TXDP 0x0804 +#define AR_Q2_TXDP 0x0808 +#define AR_Q3_TXDP 0x080c +#define AR_Q4_TXDP 0x0810 +#define AR_Q5_TXDP 0x0814 +#define AR_Q6_TXDP 0x0818 +#define AR_Q7_TXDP 0x081c +#define AR_Q8_TXDP 0x0820 +#define AR_Q9_TXDP 0x0824 +#define AR_QTXDP(_i) (AR_Q0_TXDP + ((_i)<<2)) + +#define AR_Q_TXE 0x0840 +#define AR_Q_TXE_M 0x000003FF + +#define AR_Q_TXD 0x0880 +#define AR_Q_TXD_M 0x000003FF + +#define AR_Q0_CBRCFG 0x08c0 +#define AR_Q1_CBRCFG 0x08c4 +#define AR_Q2_CBRCFG 0x08c8 +#define AR_Q3_CBRCFG 0x08cc +#define AR_Q4_CBRCFG 0x08d0 +#define AR_Q5_CBRCFG 0x08d4 +#define AR_Q6_CBRCFG 0x08d8 +#define AR_Q7_CBRCFG 0x08dc +#define AR_Q8_CBRCFG 0x08e0 +#define AR_Q9_CBRCFG 0x08e4 +#define AR_QCBRCFG(_i) (AR_Q0_CBRCFG + ((_i)<<2)) +#define AR_Q_CBRCFG_INTERVAL 0x00FFFFFF +#define AR_Q_CBRCFG_INTERVAL_S 0 +#define AR_Q_CBRCFG_OVF_THRESH 0xFF000000 +#define AR_Q_CBRCFG_OVF_THRESH_S 24 + +#define AR_Q0_RDYTIMECFG 0x0900 +#define AR_Q1_RDYTIMECFG 0x0904 +#define AR_Q2_RDYTIMECFG 0x0908 +#define AR_Q3_RDYTIMECFG 0x090c +#define AR_Q4_RDYTIMECFG 0x0910 +#define AR_Q5_RDYTIMECFG 0x0914 +#define AR_Q6_RDYTIMECFG 0x0918 +#define AR_Q7_RDYTIMECFG 0x091c +#define AR_Q8_RDYTIMECFG 0x0920 +#define AR_Q9_RDYTIMECFG 0x0924 +#define AR_QRDYTIMECFG(_i) (AR_Q0_RDYTIMECFG + ((_i)<<2)) +#define AR_Q_RDYTIMECFG_DURATION 0x00FFFFFF +#define AR_Q_RDYTIMECFG_DURATION_S 0 +#define AR_Q_RDYTIMECFG_EN 0x01000000 + +#define AR_Q_ONESHOTARM_SC 0x0940 +#define AR_Q_ONESHOTARM_SC_M 0x000003FF +#define AR_Q_ONESHOTARM_SC_RESV0 0xFFFFFC00 + +#define AR_Q_ONESHOTARM_CC 0x0980 +#define AR_Q_ONESHOTARM_CC_M 0x000003FF +#define AR_Q_ONESHOTARM_CC_RESV0 0xFFFFFC00 + +#define AR_Q0_MISC 0x09c0 +#define AR_Q1_MISC 0x09c4 +#define AR_Q2_MISC 0x09c8 +#define AR_Q3_MISC 0x09cc +#define AR_Q4_MISC 0x09d0 +#define AR_Q5_MISC 0x09d4 +#define AR_Q6_MISC 0x09d8 +#define AR_Q7_MISC 0x09dc +#define AR_Q8_MISC 0x09e0 +#define AR_Q9_MISC 0x09e4 +#define AR_QMISC(_i) (AR_Q0_MISC + ((_i)<<2)) +#define AR_Q_MISC_FSP 0x0000000F +#define AR_Q_MISC_FSP_ASAP 0 +#define AR_Q_MISC_FSP_CBR 1 +#define AR_Q_MISC_FSP_DBA_GATED 2 +#define AR_Q_MISC_FSP_TIM_GATED 3 +#define AR_Q_MISC_FSP_BEACON_SENT_GATED 4 +#define AR_Q_MISC_FSP_BEACON_RCVD_GATED 5 +#define AR_Q_MISC_ONE_SHOT_EN 0x00000010 +#define AR_Q_MISC_CBR_INCR_DIS1 0x00000020 +#define AR_Q_MISC_CBR_INCR_DIS0 0x00000040 +#define AR_Q_MISC_BEACON_USE 0x00000080 +#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN 0x00000100 +#define AR_Q_MISC_RDYTIME_EXP_POLICY 0x00000200 +#define AR_Q_MISC_RESET_CBR_EXP_CTR 0x00000400 +#define AR_Q_MISC_DCU_EARLY_TERM_REQ 0x00000800 +#define AR_Q_MISC_RESV0 0xFFFFF000 + +#define AR_Q0_STS 0x0a00 +#define AR_Q1_STS 0x0a04 +#define AR_Q2_STS 0x0a08 +#define AR_Q3_STS 0x0a0c +#define AR_Q4_STS 0x0a10 +#define AR_Q5_STS 0x0a14 +#define AR_Q6_STS 0x0a18 +#define AR_Q7_STS 0x0a1c +#define AR_Q8_STS 0x0a20 +#define AR_Q9_STS 0x0a24 +#define AR_QSTS(_i) (AR_Q0_STS + ((_i)<<2)) +#define AR_Q_STS_PEND_FR_CNT 0x00000003 +#define AR_Q_STS_RESV0 0x000000FC +#define AR_Q_STS_CBR_EXP_CNT 0x0000FF00 +#define AR_Q_STS_RESV1 0xFFFF0000 + +#define AR_Q_RDYTIMESHDN 0x0a40 +#define AR_Q_RDYTIMESHDN_M 0x000003FF + + +#define AR_NUM_DCU 10 +#define AR_DCU_0 0x0001 +#define AR_DCU_1 0x0002 +#define AR_DCU_2 0x0004 +#define AR_DCU_3 0x0008 +#define AR_DCU_4 0x0010 +#define AR_DCU_5 0x0020 +#define AR_DCU_6 0x0040 +#define AR_DCU_7 0x0080 +#define AR_DCU_8 0x0100 +#define AR_DCU_9 0x0200 + +#define AR_D0_QCUMASK 0x1000 +#define AR_D1_QCUMASK 0x1004 +#define AR_D2_QCUMASK 0x1008 +#define AR_D3_QCUMASK 0x100c +#define AR_D4_QCUMASK 0x1010 +#define AR_D5_QCUMASK 0x1014 +#define AR_D6_QCUMASK 0x1018 +#define AR_D7_QCUMASK 0x101c +#define AR_D8_QCUMASK 0x1020 +#define AR_D9_QCUMASK 0x1024 +#define AR_DQCUMASK(_i) (AR_D0_QCUMASK + ((_i)<<2)) +#define AR_D_QCUMASK 0x000003FF +#define AR_D_QCUMASK_RESV0 0xFFFFFC00 + +#define AR_D_TXBLK_CMD 0x1038 +#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) + +#define AR_D0_LCL_IFS 0x1040 +#define AR_D1_LCL_IFS 0x1044 +#define AR_D2_LCL_IFS 0x1048 +#define AR_D3_LCL_IFS 0x104c +#define AR_D4_LCL_IFS 0x1050 +#define AR_D5_LCL_IFS 0x1054 +#define AR_D6_LCL_IFS 0x1058 +#define AR_D7_LCL_IFS 0x105c +#define AR_D8_LCL_IFS 0x1060 +#define AR_D9_LCL_IFS 0x1064 +#define AR_DLCL_IFS(_i) (AR_D0_LCL_IFS + ((_i)<<2)) +#define AR_D_LCL_IFS_CWMIN 0x000003FF +#define AR_D_LCL_IFS_CWMIN_S 0 +#define AR_D_LCL_IFS_CWMAX 0x000FFC00 +#define AR_D_LCL_IFS_CWMAX_S 10 +#define AR_D_LCL_IFS_AIFS 0x0FF00000 +#define AR_D_LCL_IFS_AIFS_S 20 + +#define AR_D_LCL_IFS_RESV0 0xF0000000 + +#define AR_D0_RETRY_LIMIT 0x1080 +#define AR_D1_RETRY_LIMIT 0x1084 +#define AR_D2_RETRY_LIMIT 0x1088 +#define AR_D3_RETRY_LIMIT 0x108c +#define AR_D4_RETRY_LIMIT 0x1090 +#define AR_D5_RETRY_LIMIT 0x1094 +#define AR_D6_RETRY_LIMIT 0x1098 +#define AR_D7_RETRY_LIMIT 0x109c +#define AR_D8_RETRY_LIMIT 0x10a0 +#define AR_D9_RETRY_LIMIT 0x10a4 +#define AR_DRETRY_LIMIT(_i) (AR_D0_RETRY_LIMIT + ((_i)<<2)) +#define AR_D_RETRY_LIMIT_FR_SH 0x0000000F +#define AR_D_RETRY_LIMIT_FR_SH_S 0 +#define AR_D_RETRY_LIMIT_STA_SH 0x00003F00 +#define AR_D_RETRY_LIMIT_STA_SH_S 8 +#define AR_D_RETRY_LIMIT_STA_LG 0x000FC000 +#define AR_D_RETRY_LIMIT_STA_LG_S 14 +#define AR_D_RETRY_LIMIT_RESV0 0xFFF00000 + +#define AR_D0_CHNTIME 0x10c0 +#define AR_D1_CHNTIME 0x10c4 +#define AR_D2_CHNTIME 0x10c8 +#define AR_D3_CHNTIME 0x10cc +#define AR_D4_CHNTIME 0x10d0 +#define AR_D5_CHNTIME 0x10d4 +#define AR_D6_CHNTIME 0x10d8 +#define AR_D7_CHNTIME 0x10dc +#define AR_D8_CHNTIME 0x10e0 +#define AR_D9_CHNTIME 0x10e4 +#define AR_DCHNTIME(_i) (AR_D0_CHNTIME + ((_i)<<2)) +#define AR_D_CHNTIME_DUR 0x000FFFFF +#define AR_D_CHNTIME_DUR_S 0 +#define AR_D_CHNTIME_EN 0x00100000 +#define AR_D_CHNTIME_RESV0 0xFFE00000 + +#define AR_D0_MISC 0x1100 +#define AR_D1_MISC 0x1104 +#define AR_D2_MISC 0x1108 +#define AR_D3_MISC 0x110c +#define AR_D4_MISC 0x1110 +#define AR_D5_MISC 0x1114 +#define AR_D6_MISC 0x1118 +#define AR_D7_MISC 0x111c +#define AR_D8_MISC 0x1120 +#define AR_D9_MISC 0x1124 +#define AR_DMISC(_i) (AR_D0_MISC + ((_i)<<2)) +#define AR_D_MISC_BKOFF_THRESH 0x0000003F +#define AR_D_MISC_RETRY_CNT_RESET_EN 0x00000040 +#define AR_D_MISC_CW_RESET_EN 0x00000080 +#define AR_D_MISC_FRAG_WAIT_EN 0x00000100 +#define AR_D_MISC_FRAG_BKOFF_EN 0x00000200 +#define AR_D_MISC_CW_BKOFF_EN 0x00001000 +#define AR_D_MISC_VIR_COL_HANDLING 0x0000C000 +#define AR_D_MISC_VIR_COL_HANDLING_S 14 +#define AR_D_MISC_VIR_COL_HANDLING_DEFAULT 0 +#define AR_D_MISC_VIR_COL_HANDLING_IGNORE 1 +#define AR_D_MISC_BEACON_USE 0x00010000 +#define AR_D_MISC_ARB_LOCKOUT_CNTRL 0x00060000 +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17 +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE 0 +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1 +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL 2 +#define AR_D_MISC_ARB_LOCKOUT_IGNORE 0x00080000 +#define AR_D_MISC_SEQ_NUM_INCR_DIS 0x00100000 +#define AR_D_MISC_POST_FR_BKOFF_DIS 0x00200000 +#define AR_D_MISC_VIT_COL_CW_BKOFF_EN 0x00400000 +#define AR_D_MISC_BLOWN_IFS_RETRY_EN 0x00800000 +#define AR_D_MISC_RESV0 0xFF000000 + +#define AR_D_SEQNUM 0x1140 + +#define AR_D_GBL_IFS_SIFS 0x1030 +#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF +#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF + +#define AR_D_TXBLK_BASE 0x1038 +#define AR_D_TXBLK_WRITE_BITMASK 0x0000FFFF +#define AR_D_TXBLK_WRITE_BITMASK_S 0 +#define AR_D_TXBLK_WRITE_SLICE 0x000F0000 +#define AR_D_TXBLK_WRITE_SLICE_S 16 +#define AR_D_TXBLK_WRITE_DCU 0x00F00000 +#define AR_D_TXBLK_WRITE_DCU_S 20 +#define AR_D_TXBLK_WRITE_COMMAND 0x0F000000 +#define AR_D_TXBLK_WRITE_COMMAND_S 24 + +#define AR_D_GBL_IFS_SLOT 0x1070 +#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF +#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000 + +#define AR_D_GBL_IFS_EIFS 0x10b0 +#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF +#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000 + +#define AR_D_GBL_IFS_MISC 0x10f0 +#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 +#define AR_D_GBL_IFS_MISC_TURBO_MODE 0x00000008 +#define AR_D_GBL_IFS_MISC_USEC_DURATION 0x000FFC00 +#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY 0x00300000 +#define AR_D_GBL_IFS_MISC_RANDOM_LFSR_SLICE_DIS 0x01000000 +#define AR_D_GBL_IFS_MISC_SLOT_XMIT_WIND_LEN 0x06000000 +#define AR_D_GBL_IFS_MISC_FORCE_XMIT_SLOT_BOUND 0x08000000 +#define AR_D_GBL_IFS_MISC_IGNORE_BACKOFF 0x10000000 + +#define AR_D_FPCTL 0x1230 +#define AR_D_FPCTL_DCU 0x0000000F +#define AR_D_FPCTL_DCU_S 0 +#define AR_D_FPCTL_PREFETCH_EN 0x00000010 +#define AR_D_FPCTL_BURST_PREFETCH 0x00007FE0 +#define AR_D_FPCTL_BURST_PREFETCH_S 5 + +#define AR_D_TXPSE 0x1270 +#define AR_D_TXPSE_CTRL 0x000003FF +#define AR_D_TXPSE_RESV0 0x0000FC00 +#define AR_D_TXPSE_STATUS 0x00010000 +#define AR_D_TXPSE_RESV1 0xFFFE0000 + +#define AR_D_TXSLOTMASK 0x12f0 +#define AR_D_TXSLOTMASK_NUM 0x0000000F + +#define AR_CFG_LED 0x1f04 +#define AR_CFG_SCLK_RATE_IND 0x00000003 +#define AR_CFG_SCLK_RATE_IND_S 0 +#define AR_CFG_SCLK_32MHZ 0x00000000 +#define AR_CFG_SCLK_4MHZ 0x00000001 +#define AR_CFG_SCLK_1MHZ 0x00000002 +#define AR_CFG_SCLK_32KHZ 0x00000003 +#define AR_CFG_LED_BLINK_SLOW 0x00000008 +#define AR_CFG_LED_BLINK_THRESH_SEL 0x00000070 +#define AR_CFG_LED_MODE_SEL 0x00000380 +#define AR_CFG_LED_MODE_SEL_S 7 +#define AR_CFG_LED_POWER 0x00000280 +#define AR_CFG_LED_POWER_S 7 +#define AR_CFG_LED_NETWORK 0x00000300 +#define AR_CFG_LED_NETWORK_S 7 +#define AR_CFG_LED_MODE_PROP 0x0 +#define AR_CFG_LED_MODE_RPROP 0x1 +#define AR_CFG_LED_MODE_SPLIT 0x2 +#define AR_CFG_LED_MODE_RAND 0x3 +#define AR_CFG_LED_MODE_POWER_OFF 0x4 +#define AR_CFG_LED_MODE_POWER_ON 0x5 +#define AR_CFG_LED_MODE_NETWORK_OFF 0x4 +#define AR_CFG_LED_MODE_NETWORK_ON 0x6 +#define AR_CFG_LED_ASSOC_CTL 0x00000c00 +#define AR_CFG_LED_ASSOC_CTL_S 10 +#define AR_CFG_LED_ASSOC_NONE 0x0 +#define AR_CFG_LED_ASSOC_ACTIVE 0x1 +#define AR_CFG_LED_ASSOC_PENDING 0x2 + +#define AR_CFG_LED_BLINK_SLOW 0x00000008 +#define AR_CFG_LED_BLINK_SLOW_S 3 + +#define AR_CFG_LED_BLINK_THRESH_SEL 0x00000070 +#define AR_CFG_LED_BLINK_THRESH_SEL_S 4 + +#define AR_MAC_SLEEP 0x1f00 +#define AR_MAC_SLEEP_MAC_AWAKE 0x00000000 +#define AR_MAC_SLEEP_MAC_ASLEEP 0x00000001 + +#define AR_RC 0x4000 +#define AR_RC_AHB 0x00000001 +#define AR_RC_APB 0x00000002 +#define AR_RC_HOSTIF 0x00000100 + +#define AR_WA 0x4004 +#define AR9285_WA_DEFAULT 0x004a05cb +#define AR9280_WA_DEFAULT 0x0040073f +#define AR_WA_DEFAULT 0x0000073f + + +#define AR_PM_STATE 0x4008 +#define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 + +#define AR_HOST_TIMEOUT 0x4018 +#define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF +#define AR_HOST_TIMEOUT_APB_CNTR_S 0 +#define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000 +#define AR_HOST_TIMEOUT_LCL_CNTR_S 16 + +#define AR_EEPROM 0x401c +#define AR_EEPROM_ABSENT 0x00000100 +#define AR_EEPROM_CORRUPT 0x00000200 +#define AR_EEPROM_PROT_MASK 0x03FFFC00 +#define AR_EEPROM_PROT_MASK_S 10 + +#define EEPROM_PROTECT_RP_0_31 0x0001 +#define EEPROM_PROTECT_WP_0_31 0x0002 +#define EEPROM_PROTECT_RP_32_63 0x0004 +#define EEPROM_PROTECT_WP_32_63 0x0008 +#define EEPROM_PROTECT_RP_64_127 0x0010 +#define EEPROM_PROTECT_WP_64_127 0x0020 +#define EEPROM_PROTECT_RP_128_191 0x0040 +#define EEPROM_PROTECT_WP_128_191 0x0080 +#define EEPROM_PROTECT_RP_192_255 0x0100 +#define EEPROM_PROTECT_WP_192_255 0x0200 +#define EEPROM_PROTECT_RP_256_511 0x0400 +#define EEPROM_PROTECT_WP_256_511 0x0800 +#define EEPROM_PROTECT_RP_512_1023 0x1000 +#define EEPROM_PROTECT_WP_512_1023 0x2000 +#define EEPROM_PROTECT_RP_1024_2047 0x4000 +#define EEPROM_PROTECT_WP_1024_2047 0x8000 + +#define AR_SREV \ + ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020) + +#define AR_SREV_ID \ + ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF) +#define AR_SREV_VERSION 0x000000F0 +#define AR_SREV_VERSION_S 4 +#define AR_SREV_REVISION 0x00000007 + +#define AR_SREV_ID2 0xFFFFFFFF +#define AR_SREV_VERSION2 0xFFFC0000 +#define AR_SREV_VERSION2_S 18 +#define AR_SREV_TYPE2 0x0003F000 +#define AR_SREV_TYPE2_S 12 +#define AR_SREV_TYPE2_CHAIN 0x00001000 +#define AR_SREV_TYPE2_HOST_MODE 0x00002000 +#define AR_SREV_REVISION2 0x00000F00 +#define AR_SREV_REVISION2_S 8 + +#define AR_SREV_VERSION_5416_PCI 0xD +#define AR_SREV_VERSION_5416_PCIE 0xC +#define AR_SREV_REVISION_5416_10 0 +#define AR_SREV_REVISION_5416_20 1 +#define AR_SREV_REVISION_5416_22 2 +#define AR_SREV_VERSION_9100 0x14 +#define AR_SREV_VERSION_9160 0x40 +#define AR_SREV_REVISION_9160_10 0 +#define AR_SREV_REVISION_9160_11 1 +#define AR_SREV_VERSION_9280 0x80 +#define AR_SREV_REVISION_9280_10 0 +#define AR_SREV_REVISION_9280_20 1 +#define AR_SREV_REVISION_9280_21 2 +#define AR_SREV_VERSION_9285 0xC0 +#define AR_SREV_REVISION_9285_10 0 +#define AR_SREV_REVISION_9285_11 1 +#define AR_SREV_REVISION_9285_12 2 + +#define AR_SREV_5416(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ + ((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)) +#define AR_SREV_5416_20_OR_LATER(_ah) \ + (((AR_SREV_5416(_ah)) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \ + ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) +#define AR_SREV_5416_22_OR_LATER(_ah) \ + (((AR_SREV_5416(_ah)) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \ + ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) + +#define AR_SREV_9100(ah) \ + ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100) +#define AR_SREV_9100_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) + +#define AR_SREV_9160(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9160)) +#define AR_SREV_9160_10_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160)) +#define AR_SREV_9160_11(_ah) \ + (AR_SREV_9160(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11)) +#define AR_SREV_9280(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280)) +#define AR_SREV_9280_10_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280)) +#define AR_SREV_9280_20(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20)) +#define AR_SREV_9280_20_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9280) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20))) + +#define AR_SREV_9285(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285)) +#define AR_SREV_9285_10_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285)) +#define AR_SREV_9285_11(_ah) \ + (AR_SREV_9285(ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11)) +#define AR_SREV_9285_11_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ + AR_SREV_REVISION_9285_11))) +#define AR_SREV_9285_12(_ah) \ + (AR_SREV_9285(ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12)) +#define AR_SREV_9285_12_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ + AR_SREV_REVISION_9285_12))) + +#define AR_RADIO_SREV_MAJOR 0xf0 +#define AR_RAD5133_SREV_MAJOR 0xc0 +#define AR_RAD2133_SREV_MAJOR 0xd0 +#define AR_RAD5122_SREV_MAJOR 0xe0 +#define AR_RAD2122_SREV_MAJOR 0xf0 + +#define AR_AHB_MODE 0x4024 +#define AR_AHB_EXACT_WR_EN 0x00000000 +#define AR_AHB_BUF_WR_EN 0x00000001 +#define AR_AHB_EXACT_RD_EN 0x00000000 +#define AR_AHB_CACHELINE_RD_EN 0x00000002 +#define AR_AHB_PREFETCH_RD_EN 0x00000004 +#define AR_AHB_PAGE_SIZE_1K 0x00000000 +#define AR_AHB_PAGE_SIZE_2K 0x00000008 +#define AR_AHB_PAGE_SIZE_4K 0x00000010 + +#define AR_INTR_RTC_IRQ 0x00000001 +#define AR_INTR_MAC_IRQ 0x00000002 +#define AR_INTR_EEP_PROT_ACCESS 0x00000004 +#define AR_INTR_MAC_AWAKE 0x00020000 +#define AR_INTR_MAC_ASLEEP 0x00040000 +#define AR_INTR_SPURIOUS 0xFFFFFFFF + + +#define AR_INTR_SYNC_CAUSE_CLR 0x4028 + +#define AR_INTR_SYNC_CAUSE 0x4028 + +#define AR_INTR_SYNC_ENABLE 0x402c +#define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000 +#define AR_INTR_SYNC_ENABLE_GPIO_S 18 + +enum { + AR_INTR_SYNC_RTC_IRQ = 0x00000001, + AR_INTR_SYNC_MAC_IRQ = 0x00000002, + AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS = 0x00000004, + AR_INTR_SYNC_APB_TIMEOUT = 0x00000008, + AR_INTR_SYNC_PCI_MODE_CONFLICT = 0x00000010, + AR_INTR_SYNC_HOST1_FATAL = 0x00000020, + AR_INTR_SYNC_HOST1_PERR = 0x00000040, + AR_INTR_SYNC_TRCV_FIFO_PERR = 0x00000080, + AR_INTR_SYNC_RADM_CPL_EP = 0x00000100, + AR_INTR_SYNC_RADM_CPL_DLLP_ABORT = 0x00000200, + AR_INTR_SYNC_RADM_CPL_TLP_ABORT = 0x00000400, + AR_INTR_SYNC_RADM_CPL_ECRC_ERR = 0x00000800, + AR_INTR_SYNC_RADM_CPL_TIMEOUT = 0x00001000, + AR_INTR_SYNC_LOCAL_TIMEOUT = 0x00002000, + AR_INTR_SYNC_PM_ACCESS = 0x00004000, + AR_INTR_SYNC_MAC_AWAKE = 0x00008000, + AR_INTR_SYNC_MAC_ASLEEP = 0x00010000, + AR_INTR_SYNC_MAC_SLEEP_ACCESS = 0x00020000, + AR_INTR_SYNC_ALL = 0x0003FFFF, + + + AR_INTR_SYNC_DEFAULT = (AR_INTR_SYNC_HOST1_FATAL | + AR_INTR_SYNC_HOST1_PERR | + AR_INTR_SYNC_RADM_CPL_EP | + AR_INTR_SYNC_RADM_CPL_DLLP_ABORT | + AR_INTR_SYNC_RADM_CPL_TLP_ABORT | + AR_INTR_SYNC_RADM_CPL_ECRC_ERR | + AR_INTR_SYNC_RADM_CPL_TIMEOUT | + AR_INTR_SYNC_LOCAL_TIMEOUT | + AR_INTR_SYNC_MAC_SLEEP_ACCESS), + + AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF, + +}; + +#define AR_INTR_ASYNC_MASK 0x4030 +#define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 +#define AR_INTR_ASYNC_MASK_GPIO_S 18 + +#define AR_INTR_SYNC_MASK 0x4034 +#define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 +#define AR_INTR_SYNC_MASK_GPIO_S 18 + +#define AR_INTR_ASYNC_CAUSE_CLR 0x4038 +#define AR_INTR_ASYNC_CAUSE 0x4038 + +#define AR_INTR_ASYNC_ENABLE 0x403c +#define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 +#define AR_INTR_ASYNC_ENABLE_GPIO_S 18 + +#define AR_PCIE_SERDES 0x4040 +#define AR_PCIE_SERDES2 0x4044 +#define AR_PCIE_PM_CTRL 0x4014 +#define AR_PCIE_PM_CTRL_ENA 0x00080000 + +#define AR_NUM_GPIO 14 +#define AR928X_NUM_GPIO 10 +#define AR9285_NUM_GPIO 12 + +#define AR_GPIO_IN_OUT 0x4048 +#define AR_GPIO_IN_VAL 0x0FFFC000 +#define AR_GPIO_IN_VAL_S 14 +#define AR928X_GPIO_IN_VAL 0x000FFC00 +#define AR928X_GPIO_IN_VAL_S 10 +#define AR9285_GPIO_IN_VAL 0x00FFF000 +#define AR9285_GPIO_IN_VAL_S 12 + +#define AR_GPIO_OE_OUT 0x404c +#define AR_GPIO_OE_OUT_DRV 0x3 +#define AR_GPIO_OE_OUT_DRV_NO 0x0 +#define AR_GPIO_OE_OUT_DRV_LOW 0x1 +#define AR_GPIO_OE_OUT_DRV_HI 0x2 +#define AR_GPIO_OE_OUT_DRV_ALL 0x3 + +#define AR_GPIO_INTR_POL 0x4050 +#define AR_GPIO_INTR_POL_VAL 0x00001FFF +#define AR_GPIO_INTR_POL_VAL_S 0 + +#define AR_GPIO_INPUT_EN_VAL 0x4054 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 +#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 +#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_S 3 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_DEF 0x00000010 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 +#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 +#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 +#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 +#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 +#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 +#define AR_GPIO_JTAG_DISABLE 0x00020000 + +#define AR_GPIO_INPUT_MUX1 0x4058 +#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 +#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 + +#define AR_GPIO_INPUT_MUX2 0x405c +#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f +#define AR_GPIO_INPUT_MUX2_CLK25_S 0 +#define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 +#define AR_GPIO_INPUT_MUX2_RFSILENT_S 4 +#define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 +#define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 + +#define AR_GPIO_OUTPUT_MUX1 0x4060 +#define AR_GPIO_OUTPUT_MUX2 0x4064 +#define AR_GPIO_OUTPUT_MUX3 0x4068 + +#define AR_INPUT_STATE 0x406c + +#define AR_EEPROM_STATUS_DATA 0x407c +#define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff +#define AR_EEPROM_STATUS_DATA_VAL_S 0 +#define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 +#define AR_EEPROM_STATUS_DATA_BUSY_ACCESS 0x00020000 +#define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 +#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 + +#define AR_OBS 0x4080 + +#define AR_PCIE_MSI 0x4094 +#define AR_PCIE_MSI_ENABLE 0x00000001 + + +#define AR_RTC_9160_PLL_DIV 0x000003ff +#define AR_RTC_9160_PLL_DIV_S 0 +#define AR_RTC_9160_PLL_REFDIV 0x00003C00 +#define AR_RTC_9160_PLL_REFDIV_S 10 +#define AR_RTC_9160_PLL_CLKSEL 0x0000C000 +#define AR_RTC_9160_PLL_CLKSEL_S 14 + +#define AR_RTC_BASE 0x00020000 +#define AR_RTC_RC \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000) +#define AR_RTC_RC_M 0x00000003 +#define AR_RTC_RC_MAC_WARM 0x00000001 +#define AR_RTC_RC_MAC_COLD 0x00000002 +#define AR_RTC_RC_COLD_RESET 0x00000004 +#define AR_RTC_RC_WARM_RESET 0x00000008 + +#define AR_RTC_PLL_CONTROL \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014) + +#define AR_RTC_PLL_DIV 0x0000001f +#define AR_RTC_PLL_DIV_S 0 +#define AR_RTC_PLL_DIV2 0x00000020 +#define AR_RTC_PLL_REFDIV_5 0x000000c0 +#define AR_RTC_PLL_CLKSEL 0x00000300 +#define AR_RTC_PLL_CLKSEL_S 8 + +#define AR_RTC_RESET \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) +#define AR_RTC_RESET_EN (0x00000001) + +#define AR_RTC_STATUS \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0044) : 0x7044) + +#define AR_RTC_STATUS_M \ + ((AR_SREV_9100(ah)) ? 0x0000003f : 0x0000000f) + +#define AR_RTC_PM_STATUS_M 0x0000000f + +#define AR_RTC_STATUS_SHUTDOWN 0x00000001 +#define AR_RTC_STATUS_ON 0x00000002 +#define AR_RTC_STATUS_SLEEP 0x00000004 +#define AR_RTC_STATUS_WAKEUP 0x00000008 + +#define AR_RTC_SLEEP_CLK \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048) +#define AR_RTC_FORCE_DERIVED_CLK 0x2 + +#define AR_RTC_FORCE_WAKE \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c) +#define AR_RTC_FORCE_WAKE_EN 0x00000001 +#define AR_RTC_FORCE_WAKE_ON_INT 0x00000002 + + +#define AR_RTC_INTR_CAUSE \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0050) : 0x7050) + +#define AR_RTC_INTR_ENABLE \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0054) : 0x7054) + +#define AR_RTC_INTR_MASK \ + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) + +/* RTC_DERIVED_* - only for AR9100 */ + +#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) +#define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe +#define AR_RTC_DERIVED_CLK_PERIOD_S 1 + +#define AR_SEQ_MASK 0x8060 + +#define AR_AN_RF2G1_CH0 0x7810 +#define AR_AN_RF2G1_CH0_OB 0x03800000 +#define AR_AN_RF2G1_CH0_OB_S 23 +#define AR_AN_RF2G1_CH0_DB 0x1C000000 +#define AR_AN_RF2G1_CH0_DB_S 26 + +#define AR_AN_RF5G1_CH0 0x7818 +#define AR_AN_RF5G1_CH0_OB5 0x00070000 +#define AR_AN_RF5G1_CH0_OB5_S 16 +#define AR_AN_RF5G1_CH0_DB5 0x00380000 +#define AR_AN_RF5G1_CH0_DB5_S 19 + +#define AR_AN_RF2G1_CH1 0x7834 +#define AR_AN_RF2G1_CH1_OB 0x03800000 +#define AR_AN_RF2G1_CH1_OB_S 23 +#define AR_AN_RF2G1_CH1_DB 0x1C000000 +#define AR_AN_RF2G1_CH1_DB_S 26 + +#define AR_AN_RF5G1_CH1 0x783C +#define AR_AN_RF5G1_CH1_OB5 0x00070000 +#define AR_AN_RF5G1_CH1_OB5_S 16 +#define AR_AN_RF5G1_CH1_DB5 0x00380000 +#define AR_AN_RF5G1_CH1_DB5_S 19 + +#define AR_AN_TOP1 0x7890 +#define AR_AN_TOP1_DACIPMODE 0x00040000 +#define AR_AN_TOP1_DACIPMODE_S 18 + +#define AR_AN_TOP2 0x7894 +#define AR_AN_TOP2_XPABIAS_LVL 0xC0000000 +#define AR_AN_TOP2_XPABIAS_LVL_S 30 +#define AR_AN_TOP2_LOCALBIAS 0x00200000 +#define AR_AN_TOP2_LOCALBIAS_S 21 +#define AR_AN_TOP2_PWDCLKIND 0x00400000 +#define AR_AN_TOP2_PWDCLKIND_S 22 + +#define AR_AN_SYNTH9 0x7868 +#define AR_AN_SYNTH9_REFDIVA 0xf8000000 +#define AR_AN_SYNTH9_REFDIVA_S 27 + +#define AR9285_AN_RF2G1 0x7820 +#define AR9285_AN_RF2G1_ENPACAL 0x00000800 +#define AR9285_AN_RF2G1_ENPACAL_S 11 +#define AR9285_AN_RF2G1_PDPADRV1 0x02000000 +#define AR9285_AN_RF2G1_PDPADRV1_S 25 +#define AR9285_AN_RF2G1_PDPADRV2 0x01000000 +#define AR9285_AN_RF2G1_PDPADRV2_S 24 +#define AR9285_AN_RF2G1_PDPAOUT 0x00800000 +#define AR9285_AN_RF2G1_PDPAOUT_S 23 + + +#define AR9285_AN_RF2G2 0x7824 +#define AR9285_AN_RF2G2_OFFCAL 0x00001000 +#define AR9285_AN_RF2G2_OFFCAL_S 12 + +#define AR9285_AN_RF2G3 0x7828 +#define AR9285_AN_RF2G3_PDVCCOMP 0x02000000 +#define AR9285_AN_RF2G3_PDVCCOMP_S 25 +#define AR9285_AN_RF2G3_OB_0 0x00E00000 +#define AR9285_AN_RF2G3_OB_0_S 21 +#define AR9285_AN_RF2G3_OB_1 0x001C0000 +#define AR9285_AN_RF2G3_OB_1_S 18 +#define AR9285_AN_RF2G3_OB_2 0x00038000 +#define AR9285_AN_RF2G3_OB_2_S 15 +#define AR9285_AN_RF2G3_OB_3 0x00007000 +#define AR9285_AN_RF2G3_OB_3_S 12 +#define AR9285_AN_RF2G3_OB_4 0x00000E00 +#define AR9285_AN_RF2G3_OB_4_S 9 + +#define AR9285_AN_RF2G3_DB1_0 0x000001C0 +#define AR9285_AN_RF2G3_DB1_0_S 6 +#define AR9285_AN_RF2G3_DB1_1 0x00000038 +#define AR9285_AN_RF2G3_DB1_1_S 3 +#define AR9285_AN_RF2G3_DB1_2 0x00000007 +#define AR9285_AN_RF2G3_DB1_2_S 0 +#define AR9285_AN_RF2G4 0x782C +#define AR9285_AN_RF2G4_DB1_3 0xE0000000 +#define AR9285_AN_RF2G4_DB1_3_S 29 +#define AR9285_AN_RF2G4_DB1_4 0x1C000000 +#define AR9285_AN_RF2G4_DB1_4_S 26 + +#define AR9285_AN_RF2G4_DB2_0 0x03800000 +#define AR9285_AN_RF2G4_DB2_0_S 23 +#define AR9285_AN_RF2G4_DB2_1 0x00700000 +#define AR9285_AN_RF2G4_DB2_1_S 20 +#define AR9285_AN_RF2G4_DB2_2 0x000E0000 +#define AR9285_AN_RF2G4_DB2_2_S 17 +#define AR9285_AN_RF2G4_DB2_3 0x0001C000 +#define AR9285_AN_RF2G4_DB2_3_S 14 +#define AR9285_AN_RF2G4_DB2_4 0x00003800 +#define AR9285_AN_RF2G4_DB2_4_S 11 + +#define AR9285_AN_RF2G6 0x7834 +#define AR9285_AN_RF2G6_CCOMP 0x00007800 +#define AR9285_AN_RF2G6_CCOMP_S 11 +#define AR9285_AN_RF2G6_OFFS 0x03f00000 +#define AR9285_AN_RF2G6_OFFS_S 20 + +#define AR9285_AN_RF2G7 0x7838 +#define AR9285_AN_RF2G7_PWDDB 0x00000002 +#define AR9285_AN_RF2G7_PWDDB_S 1 +#define AR9285_AN_RF2G7_PADRVGN2TAB0 0xE0000000 +#define AR9285_AN_RF2G7_PADRVGN2TAB0_S 29 + +#define AR9285_AN_RF2G8 0x783C +#define AR9285_AN_RF2G8_PADRVGN2TAB0 0x0001C000 +#define AR9285_AN_RF2G8_PADRVGN2TAB0_S 14 + + +#define AR9285_AN_RF2G9 0x7840 +#define AR9285_AN_RXTXBB1 0x7854 +#define AR9285_AN_RXTXBB1_PDRXTXBB1 0x00000020 +#define AR9285_AN_RXTXBB1_PDRXTXBB1_S 5 +#define AR9285_AN_RXTXBB1_PDV2I 0x00000080 +#define AR9285_AN_RXTXBB1_PDV2I_S 7 +#define AR9285_AN_RXTXBB1_PDDACIF 0x00000100 +#define AR9285_AN_RXTXBB1_PDDACIF_S 8 +#define AR9285_AN_RXTXBB1_SPARE9 0x00000001 +#define AR9285_AN_RXTXBB1_SPARE9_S 0 + +#define AR9285_AN_TOP2 0x7868 + +#define AR9285_AN_TOP3 0x786c +#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C +#define AR9285_AN_TOP3_XPABIAS_LVL_S 2 +#define AR9285_AN_TOP3_PWDDAC 0x00800000 +#define AR9285_AN_TOP3_PWDDAC_S 23 + +#define AR9285_AN_TOP4 0x7870 +#define AR9285_AN_TOP4_DEFAULT 0x10142c00 + +#define AR_STA_ID0 0x8000 +#define AR_STA_ID1 0x8004 +#define AR_STA_ID1_SADH_MASK 0x0000FFFF +#define AR_STA_ID1_STA_AP 0x00010000 +#define AR_STA_ID1_ADHOC 0x00020000 +#define AR_STA_ID1_PWR_SAV 0x00040000 +#define AR_STA_ID1_KSRCHDIS 0x00080000 +#define AR_STA_ID1_PCF 0x00100000 +#define AR_STA_ID1_USE_DEFANT 0x00200000 +#define AR_STA_ID1_DEFANT_UPDATE 0x00400000 +#define AR_STA_ID1_RTS_USE_DEF 0x00800000 +#define AR_STA_ID1_ACKCTS_6MB 0x01000000 +#define AR_STA_ID1_BASE_RATE_11B 0x02000000 +#define AR_STA_ID1_SECTOR_SELF_GEN 0x04000000 +#define AR_STA_ID1_CRPT_MIC_ENABLE 0x08000000 +#define AR_STA_ID1_KSRCH_MODE 0x10000000 +#define AR_STA_ID1_PRESERVE_SEQNUM 0x20000000 +#define AR_STA_ID1_CBCIV_ENDIAN 0x40000000 +#define AR_STA_ID1_MCAST_KSRCH 0x80000000 + +#define AR_BSS_ID0 0x8008 +#define AR_BSS_ID1 0x800C +#define AR_BSS_ID1_U16 0x0000FFFF +#define AR_BSS_ID1_AID 0x07FF0000 +#define AR_BSS_ID1_AID_S 16 + +#define AR_BCN_RSSI_AVE 0x8010 +#define AR_BCN_RSSI_AVE_MASK 0x00000FFF + +#define AR_TIME_OUT 0x8014 +#define AR_TIME_OUT_ACK 0x00003FFF +#define AR_TIME_OUT_ACK_S 0 +#define AR_TIME_OUT_CTS 0x3FFF0000 +#define AR_TIME_OUT_CTS_S 16 + +#define AR_RSSI_THR 0x8018 +#define AR_RSSI_THR_MASK 0x000000FF +#define AR_RSSI_THR_BM_THR 0x0000FF00 +#define AR_RSSI_THR_BM_THR_S 8 +#define AR_RSSI_BCN_WEIGHT 0x1F000000 +#define AR_RSSI_BCN_WEIGHT_S 24 +#define AR_RSSI_BCN_RSSI_RST 0x20000000 + +#define AR_USEC 0x801c +#define AR_USEC_USEC 0x0000007F +#define AR_USEC_TX_LAT 0x007FC000 +#define AR_USEC_TX_LAT_S 14 +#define AR_USEC_RX_LAT 0x1F800000 +#define AR_USEC_RX_LAT_S 23 + +#define AR_RESET_TSF 0x8020 +#define AR_RESET_TSF_ONCE 0x01000000 + +#define AR_MAX_CFP_DUR 0x8038 +#define AR_CFP_VAL 0x0000FFFF + +#define AR_RX_FILTER 0x803C +#define AR_RX_COMPR_BAR 0x00000400 + +#define AR_MCAST_FIL0 0x8040 +#define AR_MCAST_FIL1 0x8044 + +#define AR_DIAG_SW 0x8048 +#define AR_DIAG_CACHE_ACK 0x00000001 +#define AR_DIAG_ACK_DIS 0x00000002 +#define AR_DIAG_CTS_DIS 0x00000004 +#define AR_DIAG_ENCRYPT_DIS 0x00000008 +#define AR_DIAG_DECRYPT_DIS 0x00000010 +#define AR_DIAG_RX_DIS 0x00000020 +#define AR_DIAG_LOOP_BACK 0x00000040 +#define AR_DIAG_CORR_FCS 0x00000080 +#define AR_DIAG_CHAN_INFO 0x00000100 +#define AR_DIAG_SCRAM_SEED 0x0001FE00 +#define AR_DIAG_SCRAM_SEED_S 8 +#define AR_DIAG_FRAME_NV0 0x00020000 +#define AR_DIAG_OBS_PT_SEL1 0x000C0000 +#define AR_DIAG_OBS_PT_SEL1_S 18 +#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 +#define AR_DIAG_IGNORE_VIRT_CS 0x00200000 +#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000 +#define AR_DIAG_EIFS_CTRL_ENA 0x00800000 +#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000 +#define AR_DIAG_RX_ABORT 0x02000000 +#define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000 +#define AR_DIAG_OBS_PT_SEL2 0x08000000 +#define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000 +#define AR_DIAG_RX_CLEAR_EXT_LOW 0x20000000 + +#define AR_TSF_L32 0x804c +#define AR_TSF_U32 0x8050 + +#define AR_TST_ADDAC 0x8054 +#define AR_DEF_ANTENNA 0x8058 + +#define AR_AES_MUTE_MASK0 0x805c +#define AR_AES_MUTE_MASK0_FC 0x0000FFFF +#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000 +#define AR_AES_MUTE_MASK0_QOS_S 16 + +#define AR_AES_MUTE_MASK1 0x8060 +#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF +#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000 +#define AR_AES_MUTE_MASK1_FC_MGMT_S 16 + +#define AR_GATED_CLKS 0x8064 +#define AR_GATED_CLKS_TX 0x00000002 +#define AR_GATED_CLKS_RX 0x00000004 +#define AR_GATED_CLKS_REG 0x00000008 + +#define AR_OBS_BUS_CTRL 0x8068 +#define AR_OBS_BUS_SEL_1 0x00040000 +#define AR_OBS_BUS_SEL_2 0x00080000 +#define AR_OBS_BUS_SEL_3 0x000C0000 +#define AR_OBS_BUS_SEL_4 0x08040000 +#define AR_OBS_BUS_SEL_5 0x08080000 + +#define AR_OBS_BUS_1 0x806c +#define AR_OBS_BUS_1_PCU 0x00000001 +#define AR_OBS_BUS_1_RX_END 0x00000002 +#define AR_OBS_BUS_1_RX_WEP 0x00000004 +#define AR_OBS_BUS_1_RX_BEACON 0x00000008 +#define AR_OBS_BUS_1_RX_FILTER 0x00000010 +#define AR_OBS_BUS_1_TX_HCF 0x00000020 +#define AR_OBS_BUS_1_QUIET_TIME 0x00000040 +#define AR_OBS_BUS_1_CHAN_IDLE 0x00000080 +#define AR_OBS_BUS_1_TX_HOLD 0x00000100 +#define AR_OBS_BUS_1_TX_FRAME 0x00000200 +#define AR_OBS_BUS_1_RX_FRAME 0x00000400 +#define AR_OBS_BUS_1_RX_CLEAR 0x00000800 +#define AR_OBS_BUS_1_WEP_STATE 0x0003F000 +#define AR_OBS_BUS_1_WEP_STATE_S 12 +#define AR_OBS_BUS_1_RX_STATE 0x01F00000 +#define AR_OBS_BUS_1_RX_STATE_S 20 +#define AR_OBS_BUS_1_TX_STATE 0x7E000000 +#define AR_OBS_BUS_1_TX_STATE_S 25 + +#define AR_LAST_TSTP 0x8080 +#define AR_NAV 0x8084 +#define AR_RTS_OK 0x8088 +#define AR_RTS_FAIL 0x808c +#define AR_ACK_FAIL 0x8090 +#define AR_FCS_FAIL 0x8094 +#define AR_BEACON_CNT 0x8098 + +#define AR_SLEEP1 0x80d4 +#define AR_SLEEP1_ASSUME_DTIM 0x00080000 +#define AR_SLEEP1_CAB_TIMEOUT 0xFFE00000 +#define AR_SLEEP1_CAB_TIMEOUT_S 21 + +#define AR_SLEEP2 0x80d8 +#define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000 +#define AR_SLEEP2_BEACON_TIMEOUT_S 21 + +#define AR_BSSMSKL 0x80e0 +#define AR_BSSMSKU 0x80e4 + +#define AR_TPC 0x80e8 +#define AR_TPC_ACK 0x0000003f +#define AR_TPC_ACK_S 0x00 +#define AR_TPC_CTS 0x00003f00 +#define AR_TPC_CTS_S 0x08 +#define AR_TPC_CHIRP 0x003f0000 +#define AR_TPC_CHIRP_S 0x16 + +#define AR_TFCNT 0x80ec +#define AR_RFCNT 0x80f0 +#define AR_RCCNT 0x80f4 +#define AR_CCCNT 0x80f8 + +#define AR_QUIET1 0x80fc +#define AR_QUIET1_NEXT_QUIET_S 0 +#define AR_QUIET1_NEXT_QUIET_M 0x0000ffff +#define AR_QUIET1_QUIET_ENABLE 0x00010000 +#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000 +#define AR_QUIET2 0x8100 +#define AR_QUIET2_QUIET_PERIOD_S 0 +#define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff +#define AR_QUIET2_QUIET_DUR_S 16 +#define AR_QUIET2_QUIET_DUR 0xffff0000 + +#define AR_TSF_PARM 0x8104 +#define AR_TSF_INCREMENT_M 0x000000ff +#define AR_TSF_INCREMENT_S 0x00 + +#define AR_QOS_NO_ACK 0x8108 +#define AR_QOS_NO_ACK_TWO_BIT 0x0000000f +#define AR_QOS_NO_ACK_TWO_BIT_S 0 +#define AR_QOS_NO_ACK_BIT_OFF 0x00000070 +#define AR_QOS_NO_ACK_BIT_OFF_S 4 +#define AR_QOS_NO_ACK_BYTE_OFF 0x00000180 +#define AR_QOS_NO_ACK_BYTE_OFF_S 7 + +#define AR_PHY_ERR 0x810c + +#define AR_PHY_ERR_DCHIRP 0x00000008 +#define AR_PHY_ERR_RADAR 0x00000020 +#define AR_PHY_ERR_OFDM_TIMING 0x00020000 +#define AR_PHY_ERR_CCK_TIMING 0x02000000 + +#define AR_RXFIFO_CFG 0x8114 + + +#define AR_MIC_QOS_CONTROL 0x8118 +#define AR_MIC_QOS_SELECT 0x811c + +#define AR_PCU_MISC 0x8120 +#define AR_PCU_FORCE_BSSID_MATCH 0x00000001 +#define AR_PCU_MIC_NEW_LOC_ENA 0x00000004 +#define AR_PCU_TX_ADD_TSF 0x00000008 +#define AR_PCU_CCK_SIFS_MODE 0x00000010 +#define AR_PCU_RX_ANT_UPDT 0x00000800 +#define AR_PCU_TXOP_TBTT_LIMIT_ENA 0x00001000 +#define AR_PCU_MISS_BCN_IN_SLEEP 0x00004000 +#define AR_PCU_BUG_12306_FIX_ENA 0x00020000 +#define AR_PCU_FORCE_QUIET_COLL 0x00040000 +#define AR_PCU_TBTT_PROTECT 0x00200000 +#define AR_PCU_CLEAR_VMF 0x01000000 +#define AR_PCU_CLEAR_BA_VALID 0x04000000 + + +#define AR_FILT_OFDM 0x8124 +#define AR_FILT_OFDM_COUNT 0x00FFFFFF + +#define AR_FILT_CCK 0x8128 +#define AR_FILT_CCK_COUNT 0x00FFFFFF + +#define AR_PHY_ERR_1 0x812c +#define AR_PHY_ERR_1_COUNT 0x00FFFFFF +#define AR_PHY_ERR_MASK_1 0x8130 + +#define AR_PHY_ERR_2 0x8134 +#define AR_PHY_ERR_2_COUNT 0x00FFFFFF +#define AR_PHY_ERR_MASK_2 0x8138 + +#define AR_PHY_COUNTMAX (3 << 22) +#define AR_MIBCNT_INTRMASK (3 << 22) + +#define AR_TSFOOR_THRESHOLD 0x813c +#define AR_TSFOOR_THRESHOLD_VAL 0x0000FFFF + +#define AR_PHY_ERR_EIFS_MASK 8144 + +#define AR_PHY_ERR_3 0x8168 +#define AR_PHY_ERR_3_COUNT 0x00FFFFFF +#define AR_PHY_ERR_MASK_3 0x816c + +#define AR_TXSIFS 0x81d0 +#define AR_TXSIFS_TIME 0x000000FF +#define AR_TXSIFS_TX_LATENCY 0x00000F00 +#define AR_TXSIFS_TX_LATENCY_S 8 +#define AR_TXSIFS_ACK_SHIFT 0x00007000 +#define AR_TXSIFS_ACK_SHIFT_S 12 + +#define AR_TXOP_X 0x81ec +#define AR_TXOP_X_VAL 0x000000FF + + +#define AR_TXOP_0_3 0x81f0 +#define AR_TXOP_4_7 0x81f4 +#define AR_TXOP_8_11 0x81f8 +#define AR_TXOP_12_15 0x81fc + + +#define AR_NEXT_TBTT_TIMER 0x8200 +#define AR_NEXT_DMA_BEACON_ALERT 0x8204 +#define AR_NEXT_SWBA 0x8208 +#define AR_NEXT_CFP 0x8208 +#define AR_NEXT_HCF 0x820C +#define AR_NEXT_TIM 0x8210 +#define AR_NEXT_DTIM 0x8214 +#define AR_NEXT_QUIET_TIMER 0x8218 +#define AR_NEXT_NDP_TIMER 0x821C + +#define AR_BEACON_PERIOD 0x8220 +#define AR_DMA_BEACON_PERIOD 0x8224 +#define AR_SWBA_PERIOD 0x8228 +#define AR_HCF_PERIOD 0x822C +#define AR_TIM_PERIOD 0x8230 +#define AR_DTIM_PERIOD 0x8234 +#define AR_QUIET_PERIOD 0x8238 +#define AR_NDP_PERIOD 0x823C + +#define AR_TIMER_MODE 0x8240 +#define AR_TBTT_TIMER_EN 0x00000001 +#define AR_DBA_TIMER_EN 0x00000002 +#define AR_SWBA_TIMER_EN 0x00000004 +#define AR_HCF_TIMER_EN 0x00000008 +#define AR_TIM_TIMER_EN 0x00000010 +#define AR_DTIM_TIMER_EN 0x00000020 +#define AR_QUIET_TIMER_EN 0x00000040 +#define AR_NDP_TIMER_EN 0x00000080 +#define AR_TIMER_OVERFLOW_INDEX 0x00000700 +#define AR_TIMER_OVERFLOW_INDEX_S 8 +#define AR_TIMER_THRESH 0xFFFFF000 +#define AR_TIMER_THRESH_S 12 + +#define AR_SLP32_MODE 0x8244 +#define AR_SLP32_HALF_CLK_LATENCY 0x000FFFFF +#define AR_SLP32_ENA 0x00100000 +#define AR_SLP32_TSF_WRITE_STATUS 0x00200000 + +#define AR_SLP32_WAKE 0x8248 +#define AR_SLP32_WAKE_XTL_TIME 0x0000FFFF + +#define AR_SLP32_INC 0x824c +#define AR_SLP32_TST_INC 0x000FFFFF + +#define AR_SLP_CNT 0x8250 +#define AR_SLP_CYCLE_CNT 0x8254 + +#define AR_SLP_MIB_CTRL 0x8258 +#define AR_SLP_MIB_CLEAR 0x00000001 +#define AR_SLP_MIB_PENDING 0x00000002 + +#define AR_2040_MODE 0x8318 +#define AR_2040_JOINED_RX_CLEAR 0x00000001 + + +#define AR_EXTRCCNT 0x8328 + +#define AR_SELFGEN_MASK 0x832c + +#define AR_PCU_TXBUF_CTRL 0x8340 +#define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF +#define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700 +#define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380 + +#define AR_PCU_MISC_MODE2 0x8344 +#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 +#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004 + +#define AR_KEYTABLE_0 0x8800 +#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) +#define AR_KEY_CACHE_SIZE 128 +#define AR_RSVD_KEYTABLE_ENTRIES 4 +#define AR_KEY_TYPE 0x00000007 +#define AR_KEYTABLE_TYPE_40 0x00000000 +#define AR_KEYTABLE_TYPE_104 0x00000001 +#define AR_KEYTABLE_TYPE_128 0x00000003 +#define AR_KEYTABLE_TYPE_TKIP 0x00000004 +#define AR_KEYTABLE_TYPE_AES 0x00000005 +#define AR_KEYTABLE_TYPE_CCM 0x00000006 +#define AR_KEYTABLE_TYPE_CLR 0x00000007 +#define AR_KEYTABLE_ANT 0x00000008 +#define AR_KEYTABLE_VALID 0x00008000 +#define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0) +#define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4) +#define AR_KEYTABLE_KEY2(_n) (AR_KEYTABLE(_n) + 8) +#define AR_KEYTABLE_KEY3(_n) (AR_KEYTABLE(_n) + 12) +#define AR_KEYTABLE_KEY4(_n) (AR_KEYTABLE(_n) + 16) +#define AR_KEYTABLE_TYPE(_n) (AR_KEYTABLE(_n) + 20) +#define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24) +#define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28) + +#endif diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c new file mode 100644 index 0000000..1ff429b --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +struct ath9k_vif_iter_data { + int count; + u8 *addr; +}; + +static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath9k_vif_iter_data *iter_data = data; + u8 *nbuf; + + nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN, + GFP_ATOMIC); + if (nbuf == NULL) + return; + + memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN); + iter_data->addr = nbuf; + iter_data->count++; +} + +void ath9k_set_bssid_mask(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath9k_vif_iter_data iter_data; + int i, j; + u8 mask[ETH_ALEN]; + + /* + * Add primary MAC address even if it is not in active use since it + * will be configured to the hardware as the starting point and the + * BSSID mask will need to be changed if another address is active. + */ + iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); + if (iter_data.addr) { + memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN); + iter_data.count = 1; + } else + iter_data.count = 0; + + /* Get list of all active MAC addresses */ + spin_lock_bh(&sc->wiphy_lock); + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, + &iter_data); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] == NULL) + continue; + ieee80211_iterate_active_interfaces_atomic( + sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); + } + spin_unlock_bh(&sc->wiphy_lock); + + /* Generate an address mask to cover all active addresses */ + memset(mask, 0, ETH_ALEN); + for (i = 0; i < iter_data.count; i++) { + u8 *a1 = iter_data.addr + i * ETH_ALEN; + for (j = i + 1; j < iter_data.count; j++) { + u8 *a2 = iter_data.addr + j * ETH_ALEN; + mask[0] |= a1[0] ^ a2[0]; + mask[1] |= a1[1] ^ a2[1]; + mask[2] |= a1[2] ^ a2[2]; + mask[3] |= a1[3] ^ a2[3]; + mask[4] |= a1[4] ^ a2[4]; + mask[5] |= a1[5] ^ a2[5]; + } + } + + kfree(iter_data.addr); + + /* Invert the mask and configure hardware */ + sc->bssidmask[0] = ~mask[0]; + sc->bssidmask[1] = ~mask[1]; + sc->bssidmask[2] = ~mask[2]; + sc->bssidmask[3] = ~mask[3]; + sc->bssidmask[4] = ~mask[4]; + sc->bssidmask[5] = ~mask[5]; + + ath9k_hw_setbssidmask(sc); +} + +int ath9k_wiphy_add(struct ath_softc *sc) +{ + int i, error; + struct ath_wiphy *aphy; + struct ieee80211_hw *hw; + u8 addr[ETH_ALEN]; + + hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); + if (hw == NULL) + return -ENOMEM; + + spin_lock_bh(&sc->wiphy_lock); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] == NULL) + break; + } + + if (i == sc->num_sec_wiphy) { + /* No empty slot available; increase array length */ + struct ath_wiphy **n; + n = krealloc(sc->sec_wiphy, + (sc->num_sec_wiphy + 1) * + sizeof(struct ath_wiphy *), + GFP_ATOMIC); + if (n == NULL) { + spin_unlock_bh(&sc->wiphy_lock); + ieee80211_free_hw(hw); + return -ENOMEM; + } + n[i] = NULL; + sc->sec_wiphy = n; + sc->num_sec_wiphy++; + } + + SET_IEEE80211_DEV(hw, sc->dev); + + aphy = hw->priv; + aphy->sc = sc; + aphy->hw = hw; + sc->sec_wiphy[i] = aphy; + spin_unlock_bh(&sc->wiphy_lock); + + memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); + addr[0] |= 0x02; /* Locally managed address */ + /* + * XOR virtual wiphy index into the least significant bits to generate + * a different MAC address for each virtual wiphy. + */ + addr[5] ^= i & 0xff; + addr[4] ^= (i & 0xff00) >> 8; + addr[3] ^= (i & 0xff0000) >> 16; + + SET_IEEE80211_PERM_ADDR(hw, addr); + + ath_set_hw_capab(sc, hw); + + error = ieee80211_register_hw(hw); + + if (error == 0) { + /* Make sure wiphy scheduler is started (if enabled) */ + ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int); + } + + return error; +} + +int ath9k_wiphy_del(struct ath_wiphy *aphy) +{ + struct ath_softc *sc = aphy->sc; + int i; + + spin_lock_bh(&sc->wiphy_lock); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (aphy == sc->sec_wiphy[i]) { + sc->sec_wiphy[i] = NULL; + spin_unlock_bh(&sc->wiphy_lock); + ieee80211_unregister_hw(aphy->hw); + ieee80211_free_hw(aphy->hw); + return 0; + } + } + spin_unlock_bh(&sc->wiphy_lock); + return -ENOENT; +} + +static int ath9k_send_nullfunc(struct ath_wiphy *aphy, + struct ieee80211_vif *vif, const u8 *bssid, + int ps) +{ + struct ath_softc *sc = aphy->sc; + struct ath_tx_control txctl; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + __le16 fc; + struct ieee80211_tx_info *info; + + skb = dev_alloc_skb(24); + if (skb == NULL) + return -ENOMEM; + hdr = (struct ieee80211_hdr *) skb_put(skb, 24); + memset(hdr, 0, 24); + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + if (ps) + fc |= cpu_to_le16(IEEE80211_FCTL_PM); + hdr->frame_control = fc; + memcpy(hdr->addr1, bssid, ETH_ALEN); + memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN); + memcpy(hdr->addr3, bssid, ETH_ALEN); + + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS; + info->control.vif = vif; + info->control.rates[0].idx = 0; + info->control.rates[0].count = 4; + info->control.rates[1].idx = -1; + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]]; + txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE; + + if (ath_tx_start(aphy->hw, skb, &txctl) != 0) + goto exit; + + return 0; +exit: + dev_kfree_skb_any(skb); + return -1; +} + +static bool __ath9k_wiphy_pausing(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING) + return true; + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING) + return true; + } + return false; +} + +static bool ath9k_wiphy_pausing(struct ath_softc *sc) +{ + bool ret; + spin_lock_bh(&sc->wiphy_lock); + ret = __ath9k_wiphy_pausing(sc); + spin_unlock_bh(&sc->wiphy_lock); + return ret; +} + +static bool __ath9k_wiphy_scanning(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state == ATH_WIPHY_SCAN) + return true; + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN) + return true; + } + return false; +} + +bool ath9k_wiphy_scanning(struct ath_softc *sc) +{ + bool ret; + spin_lock_bh(&sc->wiphy_lock); + ret = __ath9k_wiphy_scanning(sc); + spin_unlock_bh(&sc->wiphy_lock); + return ret; +} + +static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); + +/* caller must hold wiphy_lock */ +static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy) +{ + if (aphy == NULL) + return; + if (aphy->chan_idx != aphy->sc->chan_idx) + return; /* wiphy not on the selected channel */ + __ath9k_wiphy_unpause(aphy); +} + +static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) +{ + int i; + spin_lock_bh(&sc->wiphy_lock); + __ath9k_wiphy_unpause_ch(sc->pri_wiphy); + for (i = 0; i < sc->num_sec_wiphy; i++) + __ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]); + spin_unlock_bh(&sc->wiphy_lock); +} + +void ath9k_wiphy_chan_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); + struct ath_wiphy *aphy = sc->next_wiphy; + + if (aphy == NULL) + return; + + /* + * All pending interfaces paused; ready to change + * channels. + */ + + /* Change channels */ + mutex_lock(&sc->mutex); + /* XXX: remove me eventually */ + ath9k_update_ichannel(sc, aphy->hw, + &sc->sc_ah->channels[sc->chan_idx]); + ath_update_chainmask(sc, sc->chan_is_ht); + if (ath_set_channel(sc, aphy->hw, + &sc->sc_ah->channels[sc->chan_idx]) < 0) { + printk(KERN_DEBUG "ath9k: Failed to set channel for new " + "virtual wiphy\n"); + mutex_unlock(&sc->mutex); + return; + } + mutex_unlock(&sc->mutex); + + ath9k_wiphy_unpause_channel(sc); +} + +/* + * ath9k version of ieee80211_tx_status() for TX frames that are generated + * internally in the driver. + */ +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath_wiphy *aphy = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + + if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE && + aphy->state == ATH_WIPHY_PAUSING) { + if (!(info->flags & IEEE80211_TX_STAT_ACK)) { + printk(KERN_DEBUG "ath9k: %s: no ACK for pause " + "frame\n", wiphy_name(hw->wiphy)); + /* + * The AP did not reply; ignore this to allow us to + * continue. + */ + } + aphy->state = ATH_WIPHY_PAUSED; + if (!ath9k_wiphy_pausing(aphy->sc)) { + /* + * Drop from tasklet to work to allow mutex for channel + * change. + */ + queue_work(aphy->sc->hw->workqueue, + &aphy->sc->chan_work); + } + } + + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + + dev_kfree_skb(skb); +} + +static void ath9k_mark_paused(struct ath_wiphy *aphy) +{ + struct ath_softc *sc = aphy->sc; + aphy->state = ATH_WIPHY_PAUSED; + if (!__ath9k_wiphy_pausing(sc)) + queue_work(sc->hw->workqueue, &sc->chan_work); +} + +static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_wiphy *aphy = data; + struct ath_vif *avp = (void *) vif->drv_priv; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!vif->bss_conf.assoc) { + ath9k_mark_paused(aphy); + break; + } + /* TODO: could avoid this if already in PS mode */ + if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) { + printk(KERN_DEBUG "%s: failed to send PS nullfunc\n", + __func__); + ath9k_mark_paused(aphy); + } + break; + case NL80211_IFTYPE_AP: + /* Beacon transmission is paused by aphy->state change */ + ath9k_mark_paused(aphy); + break; + default: + break; + } +} + +/* caller must hold wiphy_lock */ +static int __ath9k_wiphy_pause(struct ath_wiphy *aphy) +{ + ieee80211_stop_queues(aphy->hw); + aphy->state = ATH_WIPHY_PAUSING; + /* + * TODO: handle PAUSING->PAUSED for the case where there are multiple + * active vifs (now we do it on the first vif getting ready; should be + * on the last) + */ + ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter, + aphy); + return 0; +} + +int ath9k_wiphy_pause(struct ath_wiphy *aphy) +{ + int ret; + spin_lock_bh(&aphy->sc->wiphy_lock); + ret = __ath9k_wiphy_pause(aphy); + spin_unlock_bh(&aphy->sc->wiphy_lock); + return ret; +} + +static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_wiphy *aphy = data; + struct ath_vif *avp = (void *) vif->drv_priv; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!vif->bss_conf.assoc) + break; + ath9k_send_nullfunc(aphy, vif, avp->bssid, 0); + break; + case NL80211_IFTYPE_AP: + /* Beacon transmission is re-enabled by aphy->state change */ + break; + default: + break; + } +} + +/* caller must hold wiphy_lock */ +static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy) +{ + ieee80211_iterate_active_interfaces_atomic(aphy->hw, + ath9k_unpause_iter, aphy); + aphy->state = ATH_WIPHY_ACTIVE; + ieee80211_wake_queues(aphy->hw); + return 0; +} + +int ath9k_wiphy_unpause(struct ath_wiphy *aphy) +{ + int ret; + spin_lock_bh(&aphy->sc->wiphy_lock); + ret = __ath9k_wiphy_unpause(aphy); + spin_unlock_bh(&aphy->sc->wiphy_lock); + return ret; +} + +static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) + sc->pri_wiphy->state = ATH_WIPHY_PAUSED; + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) + sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED; + } +} + +/* caller must hold wiphy_lock */ +static void __ath9k_wiphy_pause_all(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) + __ath9k_wiphy_pause(sc->pri_wiphy); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) + __ath9k_wiphy_pause(sc->sec_wiphy[i]); + } +} + +int ath9k_wiphy_select(struct ath_wiphy *aphy) +{ + struct ath_softc *sc = aphy->sc; + bool now; + + spin_lock_bh(&sc->wiphy_lock); + if (__ath9k_wiphy_scanning(sc)) { + /* + * For now, we are using mac80211 sw scan and it expects to + * have full control over channel changes, so avoid wiphy + * scheduling during a scan. This could be optimized if the + * scanning control were moved into the driver. + */ + spin_unlock_bh(&sc->wiphy_lock); + return -EBUSY; + } + if (__ath9k_wiphy_pausing(sc)) { + if (sc->wiphy_select_failures == 0) + sc->wiphy_select_first_fail = jiffies; + sc->wiphy_select_failures++; + if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2)) + { + printk(KERN_DEBUG "ath9k: Previous wiphy select timed " + "out; disable/enable hw to recover\n"); + __ath9k_wiphy_mark_all_paused(sc); + /* + * TODO: this workaround to fix hardware is unlikely to + * be specific to virtual wiphy changes. It can happen + * on normal channel change, too, and as such, this + * should really be made more generic. For example, + * tricker radio disable/enable on GTT interrupt burst + * (say, 10 GTT interrupts received without any TX + * frame being completed) + */ + spin_unlock_bh(&sc->wiphy_lock); + ath_radio_disable(sc); + ath_radio_enable(sc); + queue_work(aphy->sc->hw->workqueue, + &aphy->sc->chan_work); + return -EBUSY; /* previous select still in progress */ + } + spin_unlock_bh(&sc->wiphy_lock); + return -EBUSY; /* previous select still in progress */ + } + sc->wiphy_select_failures = 0; + + /* Store the new channel */ + sc->chan_idx = aphy->chan_idx; + sc->chan_is_ht = aphy->chan_is_ht; + sc->next_wiphy = aphy; + + __ath9k_wiphy_pause_all(sc); + now = !__ath9k_wiphy_pausing(aphy->sc); + spin_unlock_bh(&sc->wiphy_lock); + + if (now) { + /* Ready to request channel change immediately */ + queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); + } + + /* + * wiphys will be unpaused in ath9k_tx_status() once channel has been + * changed if any wiphy needs time to become paused. + */ + + return 0; +} + +bool ath9k_wiphy_started(struct ath_softc *sc) +{ + int i; + spin_lock_bh(&sc->wiphy_lock); + if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { + spin_unlock_bh(&sc->wiphy_lock); + return true; + } + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) { + spin_unlock_bh(&sc->wiphy_lock); + return true; + } + } + spin_unlock_bh(&sc->wiphy_lock); + return false; +} + +static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, + struct ath_wiphy *selected) +{ + if (selected->state == ATH_WIPHY_SCAN) { + if (aphy == selected) + return; + /* + * Pause all other wiphys for the duration of the scan even if + * they are on the current channel now. + */ + } else if (aphy->chan_idx == selected->chan_idx) + return; + aphy->state = ATH_WIPHY_PAUSED; + ieee80211_stop_queues(aphy->hw); +} + +void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, + struct ath_wiphy *selected) +{ + int i; + spin_lock_bh(&sc->wiphy_lock); + if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) + ath9k_wiphy_pause_chan(sc->pri_wiphy, selected); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) + ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected); + } + spin_unlock_bh(&sc->wiphy_lock); +} + +void ath9k_wiphy_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + wiphy_work.work); + struct ath_wiphy *aphy = NULL; + bool first = true; + + spin_lock_bh(&sc->wiphy_lock); + + if (sc->wiphy_scheduler_int == 0) { + /* wiphy scheduler is disabled */ + spin_unlock_bh(&sc->wiphy_lock); + return; + } + +try_again: + sc->wiphy_scheduler_index++; + while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) { + aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1]; + if (aphy && aphy->state != ATH_WIPHY_INACTIVE) + break; + + sc->wiphy_scheduler_index++; + aphy = NULL; + } + if (aphy == NULL) { + sc->wiphy_scheduler_index = 0; + if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) { + if (first) { + first = false; + goto try_again; + } + /* No wiphy is ready to be scheduled */ + } else + aphy = sc->pri_wiphy; + } + + spin_unlock_bh(&sc->wiphy_lock); + + if (aphy && + aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN && + ath9k_wiphy_select(aphy)) { + printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy " + "change\n"); + } + + queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, + sc->wiphy_scheduler_int); +} + +void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) +{ + cancel_delayed_work_sync(&sc->wiphy_work); + sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); + if (sc->wiphy_scheduler_int) + queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, + sc->wiphy_scheduler_int); +} diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c new file mode 100644 index 0000000..628b780 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -0,0 +1,2171 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +#define BITS_PER_BYTE 8 +#define OFDM_PLCP_BITS 22 +#define HT_RC_2_MCS(_rc) ((_rc) & 0x0f) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) +#define L_STF 8 +#define L_LTF 8 +#define L_SIG 4 +#define HT_SIG 8 +#define HT_STF 4 +#define HT_LTF(_ns) (4 * (_ns)) +#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */ +#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */ +#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) +#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) + +#define OFDM_SIFS_TIME 16 + +static u32 bits_per_symbol[][2] = { + /* 20MHz 40MHz */ + { 26, 54 }, /* 0: BPSK */ + { 52, 108 }, /* 1: QPSK 1/2 */ + { 78, 162 }, /* 2: QPSK 3/4 */ + { 104, 216 }, /* 3: 16-QAM 1/2 */ + { 156, 324 }, /* 4: 16-QAM 3/4 */ + { 208, 432 }, /* 5: 64-QAM 2/3 */ + { 234, 486 }, /* 6: 64-QAM 3/4 */ + { 260, 540 }, /* 7: 64-QAM 5/6 */ + { 52, 108 }, /* 8: BPSK */ + { 104, 216 }, /* 9: QPSK 1/2 */ + { 156, 324 }, /* 10: QPSK 3/4 */ + { 208, 432 }, /* 11: 16-QAM 1/2 */ + { 312, 648 }, /* 12: 16-QAM 3/4 */ + { 416, 864 }, /* 13: 64-QAM 2/3 */ + { 468, 972 }, /* 14: 64-QAM 3/4 */ + { 520, 1080 }, /* 15: 64-QAM 5/6 */ +}; + +#define IS_HT_RATE(_rate) ((_rate) & 0x80) + +static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, + struct list_head *bf_head); +static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct list_head *bf_q, + int txok, int sendbar); +static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *head); +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); +static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, + int txok); +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, + int nbad, int txok, bool update_rc); + +/*********************/ +/* Aggregation logic */ +/*********************/ + +static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) +{ + struct ath_atx_tid *tid; + tid = ATH_AN_2_TID(an, tidno); + + if (tid->state & AGGR_ADDBA_COMPLETE || + tid->state & AGGR_ADDBA_PROGRESS) + return 1; + else + return 0; +} + +static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) +{ + struct ath_atx_ac *ac = tid->ac; + + if (tid->paused) + return; + + if (tid->sched) + return; + + tid->sched = true; + list_add_tail(&tid->list, &ac->tid_q); + + if (ac->sched) + return; + + ac->sched = true; + list_add_tail(&ac->list, &txq->axq_acq); +} + +static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) +{ + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; + + spin_lock_bh(&txq->axq_lock); + tid->paused++; + spin_unlock_bh(&txq->axq_lock); +} + +static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) +{ + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; + + ASSERT(tid->paused > 0); + spin_lock_bh(&txq->axq_lock); + + tid->paused--; + + if (tid->paused > 0) + goto unlock; + + if (list_empty(&tid->buf_q)) + goto unlock; + + ath_tx_queue_tid(txq, tid); + ath_txq_schedule(sc, txq); +unlock: + spin_unlock_bh(&txq->axq_lock); +} + +static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) +{ + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; + struct ath_buf *bf; + struct list_head bf_head; + INIT_LIST_HEAD(&bf_head); + + ASSERT(tid->paused > 0); + spin_lock_bh(&txq->axq_lock); + + tid->paused--; + + if (tid->paused > 0) { + spin_unlock_bh(&txq->axq_lock); + return; + } + + while (!list_empty(&tid->buf_q)) { + bf = list_first_entry(&tid->buf_q, struct ath_buf, list); + ASSERT(!bf_isretried(bf)); + list_move_tail(&bf->list, &bf_head); + ath_tx_send_ht_normal(sc, txq, tid, &bf_head); + } + + spin_unlock_bh(&txq->axq_lock); +} + +static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, + int seqno) +{ + int index, cindex; + + index = ATH_BA_INDEX(tid->seq_start, seqno); + cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); + + tid->tx_buf[cindex] = NULL; + + while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) { + INCR(tid->seq_start, IEEE80211_SEQ_MAX); + INCR(tid->baw_head, ATH_TID_MAX_BUFS); + } +} + +static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, + struct ath_buf *bf) +{ + int index, cindex; + + if (bf_isretried(bf)) + return; + + index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); + cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); + + ASSERT(tid->tx_buf[cindex] == NULL); + tid->tx_buf[cindex] = bf; + + if (index >= ((tid->baw_tail - tid->baw_head) & + (ATH_TID_MAX_BUFS - 1))) { + tid->baw_tail = cindex; + INCR(tid->baw_tail, ATH_TID_MAX_BUFS); + } +} + +/* + * TODO: For frame(s) that are in the retry state, we will reuse the + * sequence number(s) without setting the retry bit. The + * alternative is to give up on these and BAR the receiver's window + * forward. + */ +static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid) + +{ + struct ath_buf *bf; + struct list_head bf_head; + INIT_LIST_HEAD(&bf_head); + + for (;;) { + if (list_empty(&tid->buf_q)) + break; + + bf = list_first_entry(&tid->buf_q, struct ath_buf, list); + list_move_tail(&bf->list, &bf_head); + + if (bf_isretried(bf)) + ath_tx_update_baw(sc, tid, bf->bf_seqno); + + spin_unlock(&txq->axq_lock); + ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + spin_lock(&txq->axq_lock); + } + + tid->seq_next = tid->seq_start; + tid->baw_tail = tid->baw_head; +} + +static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) +{ + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + + bf->bf_state.bf_type |= BUF_RETRY; + bf->bf_retries++; + + skb = bf->bf_mpdu; + hdr = (struct ieee80211_hdr *)skb->data; + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); +} + +static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) +{ + struct ath_buf *tbf; + + spin_lock_bh(&sc->tx.txbuflock); + ASSERT(!list_empty((&sc->tx.txbuf))); + tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&tbf->list); + spin_unlock_bh(&sc->tx.txbuflock); + + ATH_TXBUF_RESET(tbf); + + tbf->bf_mpdu = bf->bf_mpdu; + tbf->bf_buf_addr = bf->bf_buf_addr; + *(tbf->bf_desc) = *(bf->bf_desc); + tbf->bf_state = bf->bf_state; + tbf->bf_dmacontext = bf->bf_dmacontext; + + return tbf; +} + +static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf, struct list_head *bf_q, + int txok) +{ + struct ath_node *an = NULL; + struct sk_buff *skb; + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr; + struct ath_atx_tid *tid = NULL; + struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; + struct ath_desc *ds = bf_last->bf_desc; + struct list_head bf_head, bf_pending; + u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; + u32 ba[WME_BA_BMP_SIZE >> 5]; + int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; + bool rc_update = true; + + skb = bf->bf_mpdu; + hdr = (struct ieee80211_hdr *)skb->data; + + rcu_read_lock(); + + sta = ieee80211_find_sta(sc->hw, hdr->addr1); + if (!sta) { + rcu_read_unlock(); + return; + } + + an = (struct ath_node *)sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + + isaggr = bf_isaggr(bf); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); + + if (isaggr && txok) { + if (ATH_DS_TX_BA(ds)) { + seq_st = ATH_DS_BA_SEQ(ds); + memcpy(ba, ATH_DS_BA_BITMAP(ds), + WME_BA_BMP_SIZE >> 3); + } else { + /* + * AR5416 can become deaf/mute when BA + * issue happens. Chip needs to be reset. + * But AP code may have sychronization issues + * when perform internal reset in this routine. + * Only enable reset in STA mode for now. + */ + if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) + needreset = 1; + } + } + + INIT_LIST_HEAD(&bf_pending); + INIT_LIST_HEAD(&bf_head); + + nbad = ath_tx_num_badfrms(sc, bf, txok); + while (bf) { + txfail = txpending = 0; + bf_next = bf->bf_next; + + if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { + /* transmit completion, subframe is + * acked by block ack */ + acked_cnt++; + } else if (!isaggr && txok) { + /* transmit completion */ + acked_cnt++; + } else { + if (!(tid->state & AGGR_CLEANUP) && + ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { + if (bf->bf_retries < ATH_MAX_SW_RETRIES) { + ath_tx_set_retry(sc, bf); + txpending = 1; + } else { + bf->bf_state.bf_type |= BUF_XRETRY; + txfail = 1; + sendbar = 1; + txfail_cnt++; + } + } else { + /* + * cleanup in progress, just fail + * the un-acked sub-frames + */ + txfail = 1; + } + } + + if (bf_next == NULL) { + INIT_LIST_HEAD(&bf_head); + } else { + ASSERT(!list_empty(bf_q)); + list_move_tail(&bf->list, &bf_head); + } + + if (!txpending) { + /* + * complete the acked-ones/xretried ones; update + * block-ack window + */ + spin_lock_bh(&txq->axq_lock); + ath_tx_update_baw(sc, tid, bf->bf_seqno); + spin_unlock_bh(&txq->axq_lock); + + if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { + ath_tx_rc_status(bf, ds, nbad, txok, true); + rc_update = false; + } else { + ath_tx_rc_status(bf, ds, nbad, txok, false); + } + + ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); + } else { + /* retry the un-acked ones */ + if (bf->bf_next == NULL && bf_last->bf_stale) { + struct ath_buf *tbf; + + tbf = ath_clone_txbuf(sc, bf_last); + ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); + list_add_tail(&tbf->list, &bf_head); + } else { + /* + * Clear descriptor status words for + * software retry + */ + ath9k_hw_cleartxdesc(sc->sc_ah, bf->bf_desc); + } + + /* + * Put this buffer to the temporary pending + * queue to retain ordering + */ + list_splice_tail_init(&bf_head, &bf_pending); + } + + bf = bf_next; + } + + if (tid->state & AGGR_CLEANUP) { + if (tid->baw_head == tid->baw_tail) { + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->addba_exchangeattempts = 0; + tid->state &= ~AGGR_CLEANUP; + + /* send buffered frames as singles */ + ath_tx_flush_tid(sc, tid); + } + rcu_read_unlock(); + return; + } + + /* prepend un-acked frames to the beginning of the pending frame queue */ + if (!list_empty(&bf_pending)) { + spin_lock_bh(&txq->axq_lock); + list_splice(&bf_pending, &tid->buf_q); + ath_tx_queue_tid(txq, tid); + spin_unlock_bh(&txq->axq_lock); + } + + rcu_read_unlock(); + + if (needreset) + ath_reset(sc, false); +} + +static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, + struct ath_atx_tid *tid) +{ + struct ath_rate_table *rate_table = sc->cur_rate_table; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; + struct ath_tx_info_priv *tx_info_priv; + u32 max_4ms_framelen, frmlen; + u16 aggr_limit, legacy = 0, maxampdu; + int i; + + skb = bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->control.rates; + tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; + + /* + * Find the lowest frame length among the rate series that will have a + * 4ms transmit duration. + * TODO - TXOP limit needs to be considered. + */ + max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; + + for (i = 0; i < 4; i++) { + if (rates[i].count) { + if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { + legacy = 1; + break; + } + + frmlen = rate_table->info[rates[i].idx].max_4ms_framelen; + max_4ms_framelen = min(max_4ms_framelen, frmlen); + } + } + + /* + * limit aggregate size by the minimum rate if rate selected is + * not a probe rate, if rate selected is a probe rate then + * avoid aggregation of this packet. + */ + if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) + return 0; + + aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT); + + /* + * h/w can accept aggregates upto 16 bit lengths (65535). + * The IE, however can hold upto 65536, which shows up here + * as zero. Ignore 65536 since we are constrained by hw. + */ + maxampdu = tid->an->maxampdu; + if (maxampdu) + aggr_limit = min(aggr_limit, maxampdu); + + return aggr_limit; +} + +/* + * Returns the number of delimiters to be added to + * meet the minimum required mpdudensity. + * caller should make sure that the rate is HT rate . + */ +static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, + struct ath_buf *bf, u16 frmlen) +{ + struct ath_rate_table *rt = sc->cur_rate_table; + struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + u32 nsymbits, nsymbols, mpdudensity; + u16 minlen; + u8 rc, flags, rix; + int width, half_gi, ndelim, mindelim; + + /* Select standard number of delimiters based on frame length alone */ + ndelim = ATH_AGGR_GET_NDELIM(frmlen); + + /* + * If encryption enabled, hardware requires some more padding between + * subframes. + * TODO - this could be improved to be dependent on the rate. + * The hardware can keep up at lower rates, but not higher rates + */ + if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) + ndelim += ATH_AGGR_ENCRYPTDELIM; + + /* + * Convert desired mpdu density from microeconds to bytes based + * on highest rate in rate series (i.e. first rate) to determine + * required minimum length for subframe. Take into account + * whether high rate is 20 or 40Mhz and half or full GI. + */ + mpdudensity = tid->an->mpdudensity; + + /* + * If there is no mpdu density restriction, no further calculation + * is needed. + */ + if (mpdudensity == 0) + return ndelim; + + rix = tx_info->control.rates[0].idx; + flags = tx_info->control.rates[0].flags; + rc = rt->info[rix].ratecode; + width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; + half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; + + if (half_gi) + nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); + else + nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity); + + if (nsymbols == 0) + nsymbols = 1; + + nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; + minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; + + if (frmlen < minlen) { + mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ; + ndelim = max(mindelim, ndelim); + } + + return ndelim; +} + +static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, + struct ath_atx_tid *tid, + struct list_head *bf_q) +{ +#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) + struct ath_buf *bf, *bf_first, *bf_prev = NULL; + int rl = 0, nframes = 0, ndelim, prev_al = 0; + u16 aggr_limit = 0, al = 0, bpad = 0, + al_delta, h_baw = tid->baw_size / 2; + enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; + + bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); + + do { + bf = list_first_entry(&tid->buf_q, struct ath_buf, list); + + /* do not step over block-ack window */ + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) { + status = ATH_AGGR_BAW_CLOSED; + break; + } + + if (!rl) { + aggr_limit = ath_lookup_rate(sc, bf, tid); + rl = 1; + } + + /* do not exceed aggregation limit */ + al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen; + + if (nframes && + (aggr_limit < (al + bpad + al_delta + prev_al))) { + status = ATH_AGGR_LIMITED; + break; + } + + /* do not exceed subframe limit */ + if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) { + status = ATH_AGGR_LIMITED; + break; + } + nframes++; + + /* add padding for previous frame to aggregation length */ + al += bpad + al_delta; + + /* + * Get the delimiters needed to meet the MPDU + * density for this node. + */ + ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen); + bpad = PADBYTES(al_delta) + (ndelim << 2); + + bf->bf_next = NULL; + bf->bf_desc->ds_link = 0; + + /* link buffers of this frame to the aggregate */ + ath_tx_addto_baw(sc, tid, bf); + ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); + list_move_tail(&bf->list, bf_q); + if (bf_prev) { + bf_prev->bf_next = bf; + bf_prev->bf_desc->ds_link = bf->bf_daddr; + } + bf_prev = bf; + } while (!list_empty(&tid->buf_q)); + + bf_first->bf_al = al; + bf_first->bf_nframes = nframes; + + return status; +#undef PADBYTES +} + +static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid) +{ + struct ath_buf *bf; + enum ATH_AGGR_STATUS status; + struct list_head bf_q; + + do { + if (list_empty(&tid->buf_q)) + return; + + INIT_LIST_HEAD(&bf_q); + + status = ath_tx_form_aggr(sc, tid, &bf_q); + + /* + * no frames picked up to be aggregated; + * block-ack window is not open. + */ + if (list_empty(&bf_q)) + break; + + bf = list_first_entry(&bf_q, struct ath_buf, list); + bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); + + /* if only one frame, send as non-aggregate */ + if (bf->bf_nframes == 1) { + bf->bf_state.bf_type &= ~BUF_AGGR; + ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txq, &bf_q); + continue; + } + + /* setup first desc of aggregate */ + 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); + + /* anchor last desc of aggregate */ + ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); + + txq->axq_aggr_depth++; + ath_tx_txqaddbuf(sc, txq, &bf_q); + + } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH && + status != ATH_AGGR_BAW_CLOSED); +} + +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) +{ + struct ath_atx_tid *txtid; + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->state |= AGGR_ADDBA_PROGRESS; + ath_tx_pause_tid(sc, txtid); + *ssn = txtid->seq_start; + } + + return 0; +} + +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); + struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; + struct ath_buf *bf; + struct list_head bf_head; + INIT_LIST_HEAD(&bf_head); + + if (txtid->state & AGGR_CLEANUP) + return 0; + + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + txtid->addba_exchangeattempts = 0; + return 0; + } + + ath_tx_pause_tid(sc, txtid); + + /* drop all software retried frames and mark this TID */ + 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_isretried(bf)) { + /* + * NB: it's based on the assumption that + * software retried frame will always stay + * at the head of software queue. + */ + break; + } + list_move_tail(&bf->list, &bf_head); + ath_tx_update_baw(sc, txtid, bf->bf_seqno); + ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + } + spin_unlock_bh(&txq->axq_lock); + + if (txtid->baw_head != txtid->baw_tail) { + txtid->state |= AGGR_CLEANUP; + } else { + txtid->state &= ~AGGR_ADDBA_COMPLETE; + txtid->addba_exchangeattempts = 0; + ath_tx_flush_tid(sc, txtid); + } + + return 0; +} + +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +{ + struct ath_atx_tid *txtid; + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->baw_size = + IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; + ath_tx_resume_tid(sc, txtid); + } +} + +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) +{ + struct ath_atx_tid *txtid; + + if (!(sc->sc_flags & SC_OP_TXAGGR)) + return false; + + txtid = ATH_AN_2_TID(an, tidno); + + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + if (!(txtid->state & AGGR_ADDBA_PROGRESS) && + (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { + txtid->addba_exchangeattempts++; + return true; + } + } + + return false; +} + +/********************/ +/* Queue Management */ +/********************/ + +static void ath_txq_drain_pending_buffers(struct ath_softc *sc, + struct ath_txq *txq) +{ + struct ath_atx_ac *ac, *ac_tmp; + struct ath_atx_tid *tid, *tid_tmp; + + list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { + list_del(&ac->list); + ac->sched = false; + list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { + list_del(&tid->list); + tid->sched = false; + ath_tid_drain(sc, txq, tid); + } + } +} + +struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_tx_queue_info qi; + int qnum; + + memset(&qi, 0, sizeof(qi)); + qi.tqi_subtype = subtype; + qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; + qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; + qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; + qi.tqi_physCompBuf = 0; + + /* + * Enable interrupts only for EOL and DESC conditions. + * We mark tx descriptors to receive a DESC interrupt + * when a tx queue gets deep; otherwise waiting for the + * EOL to reap descriptors. Note that this is done to + * reduce interrupt load and this only defers reaping + * descriptors, never transmitting frames. Aside from + * reducing interrupts this also permits more concurrency. + * The only potential downside is if the tx queue backs + * up in which case the top half of the kernel may backup + * due to a lack of tx descriptors. + * + * The UAPSD queue is an exception, since we take a desc- + * based intr on the EOSP frames. + */ + if (qtype == ATH9K_TX_QUEUE_UAPSD) + qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; + else + qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | + TXQ_FLAG_TXDESCINT_ENABLE; + qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); + if (qnum == -1) { + /* + * NB: don't print a message, this happens + * normally on parts with too few tx queues + */ + return NULL; + } + if (qnum >= ARRAY_SIZE(sc->tx.txq)) { + DPRINTF(sc, ATH_DBG_FATAL, + "qnum %u out of range, max %u!\n", + qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); + ath9k_hw_releasetxqueue(ah, qnum); + return NULL; + } + if (!ATH_TXQ_SETUP(sc, qnum)) { + struct ath_txq *txq = &sc->tx.txq[qnum]; + + txq->axq_qnum = qnum; + txq->axq_link = NULL; + INIT_LIST_HEAD(&txq->axq_q); + INIT_LIST_HEAD(&txq->axq_acq); + spin_lock_init(&txq->axq_lock); + txq->axq_depth = 0; + txq->axq_aggr_depth = 0; + txq->axq_totalqueued = 0; + txq->axq_linkbuf = NULL; + sc->tx.txqsetup |= 1<tx.txq[qnum]; +} + +static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) +{ + int qnum; + + switch (qtype) { + case ATH9K_TX_QUEUE_DATA: + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { + DPRINTF(sc, ATH_DBG_FATAL, + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); + return -1; + } + qnum = sc->tx.hwq_map[haltype]; + break; + case ATH9K_TX_QUEUE_BEACON: + qnum = sc->beacon.beaconq; + break; + case ATH9K_TX_QUEUE_CAB: + qnum = sc->beacon.cabq->axq_qnum; + break; + default: + qnum = -1; + } + return qnum; +} + +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_txq *txq = NULL; + int qnum; + + qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + txq = &sc->tx.txq[qnum]; + + spin_lock_bh(&txq->axq_lock); + + if (txq->axq_depth >= (ATH_TXBUF - 20)) { + DPRINTF(sc, ATH_DBG_XMIT, + "TX queue: %d is full, depth: %d\n", + qnum, txq->axq_depth); + ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); + txq->stopped = 1; + spin_unlock_bh(&txq->axq_lock); + return NULL; + } + + spin_unlock_bh(&txq->axq_lock); + + return txq; +} + +int ath_txq_update(struct ath_softc *sc, int qnum, + struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hw *ah = sc->sc_ah; + int error = 0; + struct ath9k_tx_queue_info qi; + + if (qnum == sc->beacon.beaconq) { + /* + * XXX: for beacon queue, we just save the parameter. + * It will be picked up by ath_beaconq_config when + * it's necessary. + */ + sc->beacon.beacon_qi = *qinfo; + return 0; + } + + ASSERT(sc->tx.txq[qnum].axq_qnum == qnum); + + ath9k_hw_get_txq_props(ah, qnum, &qi); + qi.tqi_aifs = qinfo->tqi_aifs; + qi.tqi_cwmin = qinfo->tqi_cwmin; + qi.tqi_cwmax = qinfo->tqi_cwmax; + qi.tqi_burstTime = qinfo->tqi_burstTime; + qi.tqi_readyTime = qinfo->tqi_readyTime; + + if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to update hardware queue %u!\n", qnum); + error = -EIO; + } else { + ath9k_hw_resettxqueue(ah, qnum); + } + + return error; +} + +int ath_cabq_update(struct ath_softc *sc) +{ + struct ath9k_tx_queue_info qi; + int qnum = sc->beacon.cabq->axq_qnum; + + ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); + /* + * Ensure the readytime % is within the bounds. + */ + if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND) + sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND; + else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) + sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; + + qi.tqi_readyTime = (sc->hw->conf.beacon_int * + sc->config.cabqReadytime) / 100; + ath_txq_update(sc, qnum, &qi); + + return 0; +} + +/* + * Drain a given TX queue (could be Beacon or Data) + * + * This assumes output has been stopped and + * we do not need to block ath_tx_tasklet. + */ +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) +{ + struct ath_buf *bf, *lastbf; + struct list_head bf_head; + + INIT_LIST_HEAD(&bf_head); + + for (;;) { + spin_lock_bh(&txq->axq_lock); + + if (list_empty(&txq->axq_q)) { + txq->axq_link = NULL; + txq->axq_linkbuf = NULL; + spin_unlock_bh(&txq->axq_lock); + break; + } + + bf = list_first_entry(&txq->axq_q, struct ath_buf, list); + + if (bf->bf_stale) { + list_del(&bf->list); + spin_unlock_bh(&txq->axq_lock); + + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + continue; + } + + lastbf = bf->bf_lastbf; + if (!retry_tx) + lastbf->bf_desc->ds_txstat.ts_flags = + ATH9K_TX_SW_ABORTED; + + /* remove ath_buf's of the same mpdu from txq */ + list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); + txq->axq_depth--; + + spin_unlock_bh(&txq->axq_lock); + + if (bf_isampdu(bf)) + ath_tx_complete_aggr(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_flags & SC_OP_TXAGGR) { + if (!retry_tx) { + spin_lock_bh(&txq->axq_lock); + ath_txq_drain_pending_buffers(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } + } +} + +void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_txq *txq; + int i, npend = 0; + + if (sc->sc_flags & SC_OP_INVALID) + return; + + /* Stop beacon queue */ + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + + /* Stop data queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) { + txq = &sc->tx.txq[i]; + ath9k_hw_stoptxdma(ah, txq->axq_qnum); + npend += ath9k_hw_numtxpending(ah, txq->axq_qnum); + } + } + + if (npend) { + int r; + + DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); + + spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); + if (r) + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %u\n", + r); + spin_unlock_bh(&sc->sc_resetlock); + } + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) + ath_draintxq(sc, &sc->tx.txq[i], retry_tx); + } +} + +void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) +{ + ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); + sc->tx.txqsetup &= ~(1<axq_qnum); +} + +void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) +{ + struct ath_atx_ac *ac; + struct ath_atx_tid *tid; + + if (list_empty(&txq->axq_acq)) + return; + + ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); + list_del(&ac->list); + ac->sched = false; + + do { + if (list_empty(&ac->tid_q)) + return; + + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); + list_del(&tid->list); + tid->sched = false; + + if (tid->paused) + continue; + + if ((txq->axq_depth % 2) == 0) + ath_tx_sched_aggr(sc, txq, tid); + + /* + * add tid to round-robin queue if more frames + * are pending for the tid + */ + if (!list_empty(&tid->buf_q)) + ath_tx_queue_tid(txq, tid); + + break; + } while (!list_empty(&ac->tid_q)); + + if (!list_empty(&ac->tid_q)) { + if (!ac->sched) { + ac->sched = true; + list_add_tail(&ac->list, &txq->axq_acq); + } + } +} + +int ath_tx_setup(struct ath_softc *sc, int haltype) +{ + struct ath_txq *txq; + + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { + DPRINTF(sc, ATH_DBG_FATAL, + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); + return 0; + } + txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); + if (txq != NULL) { + sc->tx.hwq_map[haltype] = txq->axq_qnum; + return 1; + } else + return 0; +} + +/***********/ +/* TX, DMA */ +/***********/ + +/* + * Insert a chain of ath_buf (descriptors) on a txq and + * assume the descriptors are already chained together by caller. + */ +static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *head) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_buf *bf; + + /* + * Insert the frame on the outbound list and + * pass it on to the hardware. + */ + + if (list_empty(head)) + return; + + bf = list_first_entry(head, struct ath_buf, list); + + 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, + "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); + + if (txq->axq_link == NULL) { + ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); + DPRINTF(sc, ATH_DBG_XMIT, + "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); + } else { + *txq->axq_link = bf->bf_daddr; + DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", + 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_txstart(ah, txq->axq_qnum); +} + +static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) +{ + struct ath_buf *bf = NULL; + + spin_lock_bh(&sc->tx.txbuflock); + + if (unlikely(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); + return NULL; + } + + bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&bf->list); + + spin_unlock_bh(&sc->tx.txbuflock); + + return bf; +} + +static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, + struct list_head *bf_head, + struct ath_tx_control *txctl) +{ + struct ath_buf *bf; + + bf = list_first_entry(bf_head, struct ath_buf, list); + bf->bf_state.bf_type |= BUF_AMPDU; + + /* + * Do not queue to h/w when any of the following conditions is true: + * - there are pending frames in software queue + * - the TID is currently paused for ADDBA/BAR request + * - seqno is not within block-ack window + * - h/w queue depth exceeds low water mark + */ + if (!list_empty(&tid->buf_q) || tid->paused || + !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || + txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { + /* + * Add this frame to software queue for scheduling later + * for aggregation. + */ + list_move_tail(&bf->list, &tid->buf_q); + ath_tx_queue_tid(txctl->txq, tid); + return; + } + + /* Add sub-frame to BAW */ + ath_tx_addto_baw(sc, tid, bf); + + /* Queue to h/w without aggregation */ + bf->bf_nframes = 1; + bf->bf_lastbf = bf; + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txctl->txq, bf_head); +} + +static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, + struct list_head *bf_head) +{ + struct ath_buf *bf; + + bf = list_first_entry(bf_head, struct ath_buf, list); + bf->bf_state.bf_type &= ~BUF_AMPDU; + + /* update starting sequence number for subsequent ADDBA request */ + INCR(tid->seq_start, IEEE80211_SEQ_MAX); + + bf->bf_nframes = 1; + bf->bf_lastbf = bf; + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txq, bf_head); +} + +static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *bf_head) +{ + struct ath_buf *bf; + + bf = list_first_entry(bf_head, struct ath_buf, list); + + bf->bf_lastbf = bf; + bf->bf_nframes = 1; + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txq, bf_head); +} + +static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + enum ath9k_pkt_type htype; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_beacon(fc)) + htype = ATH9K_PKT_TYPE_BEACON; + else if (ieee80211_is_probe_resp(fc)) + htype = ATH9K_PKT_TYPE_PROBE_RESP; + else if (ieee80211_is_atim(fc)) + htype = ATH9K_PKT_TYPE_ATIM; + else if (ieee80211_is_pspoll(fc)) + htype = ATH9K_PKT_TYPE_PSPOLL; + else + htype = ATH9K_PKT_TYPE_NORMAL; + + return htype; +} + +static bool is_pae(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_data(fc)) { + if (ieee80211_is_nullfunc(fc) || + /* Port Access Entity (IEEE 802.1X) */ + (skb->protocol == cpu_to_be16(ETH_P_PAE))) { + return true; + } + } + + return false; +} + +static int get_hw_crypto_keytype(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + + if (tx_info->control.hw_key) { + if (tx_info->control.hw_key->alg == ALG_WEP) + return ATH9K_KEY_TYPE_WEP; + else if (tx_info->control.hw_key->alg == ALG_TKIP) + return ATH9K_KEY_TYPE_TKIP; + else if (tx_info->control.hw_key->alg == ALG_CCMP) + return ATH9K_KEY_TYPE_AES; + } + + return ATH9K_KEY_TYPE_CLEAR; +} + +static void assign_aggr_tid_seqno(struct sk_buff *skb, + struct ath_buf *bf) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; + struct ath_node *an; + struct ath_atx_tid *tid; + __le16 fc; + u8 *qc; + + if (!tx_info->control.sta) + return; + + an = (struct ath_node *)tx_info->control.sta->drv_priv; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + bf->bf_tidno = qc[0] & 0xf; + } + + /* + * For HT capable stations, we save tidno for later use. + * We also override seqno set by upper layer with the one + * in tx aggregation state. + * + * If fragmentation is on, the sequence number is + * not overridden, since it has been + * incremented by the fragmentation routine. + * + * FIXME: check if the fragmentation threshold exceeds + * IEEE80211 max. + */ + tid = ATH_AN_2_TID(an, bf->bf_tidno); + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << + IEEE80211_SEQ_SEQ_SHIFT); + bf->bf_seqno = tid->seq_next; + INCR(tid->seq_next, IEEE80211_SEQ_MAX); +} + +static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, + struct ath_txq *txq) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + int flags = 0; + + flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + flags |= ATH9K_TXDESC_INTREQ; + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + flags |= ATH9K_TXDESC_NOACK; + + return flags; +} + +/* + * rix - rate index + * pktlen - total bytes (delims + data + fcs + pads + pad delims) + * width - 0 for 20 MHz, 1 for 40 MHz + * half_gi - to use 4us v/s 3.6 us for symbol time + */ +static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, + int width, int half_gi, bool shortPreamble) +{ + struct ath_rate_table *rate_table = sc->cur_rate_table; + u32 nbits, nsymbits, duration, nsymbols; + u8 rc; + int streams, pktlen; + + pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; + rc = rate_table->info[rix].ratecode; + + /* for legacy rates, use old function to compute packet duration */ + if (!IS_HT_RATE(rc)) + return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, + rix, shortPreamble); + + /* find number of symbols: PLCP + data */ + nbits = (pktlen << 3) + OFDM_PLCP_BITS; + nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; + nsymbols = (nbits + nsymbits - 1) / nsymbits; + + if (!half_gi) + duration = SYMBOL_TIME(nsymbols); + else + duration = SYMBOL_TIME_HALFGI(nsymbols); + + /* addup duration for legacy/ht training and signal fields */ + streams = HT_RC_2_STREAMS(rc); + duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + + return duration; +} + +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) +{ + struct ath_rate_table *rt = sc->cur_rate_table; + struct ath9k_11n_rate_series series[4]; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; + struct ieee80211_hdr *hdr; + int i, flags = 0; + u8 rix = 0, ctsrate = 0; + bool is_pspoll; + + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); + + skb = bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->control.rates; + hdr = (struct ieee80211_hdr *)skb->data; + is_pspoll = ieee80211_is_pspoll(hdr->frame_control); + + /* + * We check if Short Preamble is needed for the CTS rate by + * checking the BSS's global flag. + * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. + */ + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) + ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode | + rt->info[tx_info->control.rts_cts_rate_idx].short_preamble; + else + ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode; + + /* + * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. + * Check the first rate in the series to decide whether RTS/CTS + * or CTS-to-self has to be used. + */ + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + flags = ATH9K_TXDESC_CTSENA; + else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + flags = ATH9K_TXDESC_RTSENA; + + /* FIXME: Handle aggregation protection */ + if (sc->config.ath_aggr_prot && + (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { + flags = ATH9K_TXDESC_RTSENA; + } + + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) + flags &= ~(ATH9K_TXDESC_RTSENA); + + for (i = 0; i < 4; i++) { + if (!rates[i].count || (rates[i].idx < 0)) + continue; + + rix = rates[i].idx; + series[i].Tries = rates[i].count; + series[i].ChSel = sc->tx_chainmask; + + if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + series[i].Rate = rt->info[rix].ratecode | + rt->info[rix].short_preamble; + else + series[i].Rate = rt->info[rix].ratecode; + + if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) + series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; + if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + series[i].RateFlags |= ATH9K_RATESERIES_2040; + if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) + series[i].RateFlags |= ATH9K_RATESERIES_HALFGI; + + series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, + (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), + (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)); + } + + /* set dur_update_en for l-sig computation except for PS-Poll frames */ + ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc, + bf->bf_lastbf->bf_desc, + !is_pspoll, ctsrate, + 0, series, 4, flags); + + if (sc->config.ath_aggr_prot && flags) + ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); +} + +static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, + struct sk_buff *skb, + struct ath_tx_control *txctl) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath_tx_info_priv *tx_info_priv; + int hdrlen; + __le16 fc; + + tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); + if (unlikely(!tx_info_priv)) + return -ENOMEM; + tx_info->rate_driver_data[0] = tx_info_priv; + tx_info_priv->aphy = aphy; + tx_info_priv->frame_type = txctl->frame_type; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + + ATH_TXBUF_RESET(bf); + + bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); + + if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) + bf->bf_state.bf_type |= BUF_HT; + + bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); + + bf->bf_keytype = get_hw_crypto_keytype(skb); + if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { + bf->bf_frmlen += tx_info->control.hw_key->icv_len; + bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; + } else { + bf->bf_keyix = ATH9K_TXKEYIX_INVALID; + } + + if (ieee80211_is_data_qos(fc) && (sc->sc_flags & SC_OP_TXAGGR)) + assign_aggr_tid_seqno(skb, bf); + + bf->bf_mpdu = skb; + + bf->bf_dmacontext = dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) { + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "dma_mapping_error() on TX\n"); + return -ENOMEM; + } + + bf->bf_buf_addr = bf->bf_dmacontext; + return 0; +} + +/* FIXME: tx power */ +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_control *txctl) +{ + struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath_node *an = NULL; + struct list_head bf_head; + struct ath_desc *ds; + struct ath_atx_tid *tid; + struct ath_hw *ah = sc->sc_ah; + int frm_type; + __le16 fc; + + frm_type = get_hw_packet_type(skb); + fc = hdr->frame_control; + + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); + + ds = bf->bf_desc; + ds->ds_link = 0; + ds->ds_data = bf->bf_buf_addr; + + ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, + bf->bf_keyix, bf->bf_keytype, bf->bf_flags); + + ath9k_hw_filltxdesc(ah, ds, + skb->len, /* segment length */ + true, /* first segment */ + true, /* last segment */ + ds); /* first descriptor */ + + spin_lock_bh(&txctl->txq->axq_lock); + + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && + tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + + if (!ieee80211_is_data_qos(fc)) { + ath_tx_send_normal(sc, txctl->txq, &bf_head); + goto tx_done; + } + + if (ath_aggr_query(sc, an, bf->bf_tidno)) { + /* + * Try aggregation if it's a unicast data frame + * and the destination is HT capable. + */ + ath_tx_send_ampdu(sc, tid, &bf_head, txctl); + } else { + /* + * Send this frame as regular when ADDBA + * exchange is neither complete nor pending. + */ + ath_tx_send_ht_normal(sc, txctl->txq, + tid, &bf_head); + } + } else { + ath_tx_send_normal(sc, txctl->txq, &bf_head); + } + +tx_done: + spin_unlock_bh(&txctl->txq->axq_lock); +} + +/* Upon failure caller should free skb */ +int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath_tx_control *txctl) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_buf *bf; + int r; + + bf = ath_tx_get_buffer(sc); + if (!bf) { + DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); + return -1; + } + + r = ath_tx_setup_buffer(hw, bf, skb, txctl); + if (unlikely(r)) { + struct ath_txq *txq = txctl->txq; + + DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); + + /* upon ath_tx_processq() this TX queue will be resumed, we + * guarantee this will happen by knowing beforehand that + * we will at least have to run TX completionon one buffer + * on the queue */ + spin_lock_bh(&txq->axq_lock); + if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { + ieee80211_stop_queue(sc->hw, + skb_get_queue_mapping(skb)); + txq->stopped = 1; + } + spin_unlock_bh(&txq->axq_lock); + + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + + return r; + } + + ath_tx_start_dma(sc, bf, txctl); + + return 0; +} + +void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ath_tx_control txctl; + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + + /* + * 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->tx.seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.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, "TX CABQ padding failed\n"); + dev_kfree_skb_any(skb); + return; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, hdrlen); + } + + txctl.txq = sc->beacon.cabq; + + DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); + + if (ath_tx_start(hw, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); + goto exit; + } + + return; +exit: + dev_kfree_skb_any(skb); +} + +/*****************/ +/* TX Completion */ +/*****************/ + +static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + int tx_flags) +{ + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + int hdrlen, padsize; + int frame_type = ATH9K_NOT_INTERNAL; + + DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); + + if (tx_info_priv) { + hw = tx_info_priv->aphy->hw; + frame_type = tx_info_priv->frame_type; + } + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || + tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + } + + if (tx_flags & ATH_TX_BAR) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + + if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } + + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + /* + * Remove MAC header padding before giving the frame back to + * mac80211. + */ + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + + if (frame_type == ATH9K_NOT_INTERNAL) + ieee80211_tx_status(hw, skb); + else + ath9k_tx_status(hw, skb); +} + +static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct list_head *bf_q, + int txok, int sendbar) +{ + struct sk_buff *skb = bf->bf_mpdu; + unsigned long flags; + int tx_flags = 0; + + + if (sendbar) + tx_flags = ATH_TX_BAR; + + if (!txok) { + tx_flags |= ATH_TX_ERROR; + + if (bf_isxretried(bf)) + tx_flags |= ATH_TX_XRETRY; + } + + dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); + ath_tx_complete(sc, skb, tx_flags); + + /* + * Return the list of ath_buf of this mpdu to free queue + */ + spin_lock_irqsave(&sc->tx.txbuflock, flags); + list_splice_tail_init(bf_q, &sc->tx.txbuf); + spin_unlock_irqrestore(&sc->tx.txbuflock, flags); +} + +static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, + int txok) +{ + struct ath_buf *bf_last = bf->bf_lastbf; + struct ath_desc *ds = bf_last->bf_desc; + u16 seq_st = 0; + u32 ba[WME_BA_BMP_SIZE >> 5]; + int ba_index; + int nbad = 0; + int isaggr = 0; + + if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) + return 0; + + 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); + } + + while (bf) { + ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno); + if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) + nbad++; + + bf = bf->bf_next; + } + + return nbad; +} + +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, + int nbad, int txok, bool update_rc) +{ + struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + struct ieee80211_hw *hw = tx_info_priv->aphy->hw; + u8 i, tx_rateindex; + + if (txok) + tx_info->status.ack_signal = ds->ds_txstat.ts_rssi; + + tx_rateindex = ds->ds_txstat.ts_rateindex; + WARN_ON(tx_rateindex >= hw->max_rates); + + tx_info_priv->update_rc = update_rc; + if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + + if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && + (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { + if (ieee80211_is_data(hdr->frame_control)) { + memcpy(&tx_info_priv->tx, &ds->ds_txstat, + sizeof(tx_info_priv->tx)); + tx_info_priv->n_frames = bf->bf_nframes; + tx_info_priv->n_bad_frames = nbad; + } + } + + for (i = tx_rateindex + 1; i < hw->max_rates; i++) + tx_info->status.rates[i].count = 0; + + tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1; +} + +static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) +{ + int qnum; + + spin_lock_bh(&txq->axq_lock); + if (txq->stopped && + sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) { + qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); + if (qnum != -1) { + ieee80211_wake_queue(sc->hw, qnum); + txq->stopped = 0; + } + } + spin_unlock_bh(&txq->axq_lock); +} + +static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_buf *bf, *lastbf, *bf_held = NULL; + struct list_head bf_head; + struct ath_desc *ds; + int txok; + int status; + + DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", + txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), + txq->axq_link); + + for (;;) { + spin_lock_bh(&txq->axq_lock); + if (list_empty(&txq->axq_q)) { + txq->axq_link = NULL; + txq->axq_linkbuf = NULL; + spin_unlock_bh(&txq->axq_lock); + break; + } + bf = list_first_entry(&txq->axq_q, struct ath_buf, list); + + /* + * There is a race condition that a BH gets scheduled + * after sw writes TxE and before hw re-load the last + * descriptor to get the newly chained one. + * Software must keep the last DONE descriptor as a + * holding descriptor - software does so by marking + * it with the STALE flag. + */ + bf_held = NULL; + if (bf->bf_stale) { + bf_held = bf; + if (list_is_last(&bf_held->list, &txq->axq_q)) { + txq->axq_link = NULL; + txq->axq_linkbuf = NULL; + spin_unlock_bh(&txq->axq_lock); + + /* + * The holding descriptor is the last + * descriptor in queue. It's safe to remove + * the last holding descriptor in BH context. + */ + spin_lock_bh(&sc->tx.txbuflock); + list_move_tail(&bf_held->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + + break; + } else { + bf = list_entry(bf_held->list.next, + struct ath_buf, list); + } + } + + lastbf = bf->bf_lastbf; + ds = lastbf->bf_desc; + + status = ath9k_hw_txprocdesc(ah, ds); + if (status == -EINPROGRESS) { + spin_unlock_bh(&txq->axq_lock); + break; + } + if (bf->bf_desc == txq->axq_lastdsWithCTS) + txq->axq_lastdsWithCTS = NULL; + if (ds == txq->axq_gatingds) + txq->axq_gatingds = NULL; + + /* + * Remove ath_buf's of the same transmit unit from txq, + * however leave the last descriptor back as the holding + * descriptor for hw. + */ + lastbf->bf_stale = true; + INIT_LIST_HEAD(&bf_head); + if (!list_is_singular(&lastbf->list)) + list_cut_position(&bf_head, + &txq->axq_q, lastbf->list.prev); + + txq->axq_depth--; + if (bf_isaggr(bf)) + txq->axq_aggr_depth--; + + txok = (ds->ds_txstat.ts_status == 0); + spin_unlock_bh(&txq->axq_lock); + + if (bf_held) { + spin_lock_bh(&sc->tx.txbuflock); + list_move_tail(&bf_held->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + } + + 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_state.bf_type |= BUF_XRETRY; + ath_tx_rc_status(bf, ds, 0, txok, true); + } + + if (bf_isampdu(bf)) + ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); + else + ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); + + ath_wake_mac80211_queue(sc, txq); + + spin_lock_bh(&txq->axq_lock); + if (sc->sc_flags & SC_OP_TXAGGR) + ath_txq_schedule(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } +} + + +void ath_tx_tasklet(struct ath_softc *sc) +{ + int i; + u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); + + ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) + ath_tx_processq(sc, &sc->tx.txq[i]); + } +} + +/*****************/ +/* Init, Cleanup */ +/*****************/ + +int ath_tx_init(struct ath_softc *sc, int nbufs) +{ + int error = 0; + + spin_lock_init(&sc->tx.txbuflock); + + error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, + "tx", nbufs, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate tx descriptors: %d\n", error); + goto err; + } + + error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, + "beacon", ATH_BCBUF, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate beacon descriptors: %d\n", error); + goto err; + } + +err: + if (error != 0) + ath_tx_cleanup(sc); + + return error; +} + +void ath_tx_cleanup(struct ath_softc *sc) +{ + if (sc->beacon.bdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); + + if (sc->tx.txdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); +} + +void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) +{ + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + int tidno, acno; + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < WME_NUM_TID; + tidno++, tid++) { + tid->an = an; + tid->tidno = tidno; + tid->seq_start = tid->seq_next = 0; + tid->baw_size = WME_MAX_BA; + tid->baw_head = tid->baw_tail = 0; + tid->sched = false; + tid->paused = false; + tid->state &= ~AGGR_CLEANUP; + INIT_LIST_HEAD(&tid->buf_q); + acno = TID_TO_WME_AC(tidno); + tid->ac = &an->ac[acno]; + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->state &= ~AGGR_ADDBA_PROGRESS; + tid->addba_exchangeattempts = 0; + } + + for (acno = 0, ac = &an->ac[acno]; + acno < WME_NUM_AC; acno++, ac++) { + ac->sched = false; + INIT_LIST_HEAD(&ac->tid_q); + + switch (acno) { + case WME_AC_BE: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + break; + case WME_AC_BK: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); + break; + case WME_AC_VI: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); + break; + case WME_AC_VO: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); + break; + } + } +} + +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) +{ + int i; + struct ath_atx_ac *ac, *ac_tmp; + struct ath_atx_tid *tid, *tid_tmp; + struct ath_txq *txq; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) { + txq = &sc->tx.txq[i]; + + spin_lock(&txq->axq_lock); + + list_for_each_entry_safe(ac, + ac_tmp, &txq->axq_acq, list) { + tid = list_first_entry(&ac->tid_q, + struct ath_atx_tid, list); + if (tid && tid->an != an) + continue; + list_del(&ac->list); + ac->sched = false; + + list_for_each_entry_safe(tid, + tid_tmp, &ac->tid_q, list) { + list_del(&tid->list); + tid->sched = false; + ath_tid_drain(sc, txq, tid); + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->addba_exchangeattempts = 0; + tid->state &= ~AGGR_CLEANUP; + } + } + + spin_unlock(&txq->axq_lock); + } + } +} diff --git a/drivers/net/wireless/ath5k/Kconfig b/drivers/net/wireless/ath5k/Kconfig deleted file mode 100644 index 509b6f9..0000000 --- a/drivers/net/wireless/ath5k/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -config ATH5K - tristate "Atheros 5xxx wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL - select ATH_COMMON - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - ---help--- - This module adds support for wireless adapters based on - Atheros 5xxx chipset. - - Currently the following chip versions are supported: - - MAC: AR5211 AR5212 - PHY: RF5111/2111 RF5112/2112 RF5413/2413 - - This driver uses the kernel's mac80211 subsystem. - - If you choose to build a module, it'll be called ath5k. Say M if - unsure. - -config ATH5K_DEBUG - bool "Atheros 5xxx debugging" - depends on ATH5K - ---help--- - Atheros 5xxx debugging messages. - - Say Y, if and you will get debug options for ath5k. - To use this, you need to mount debugfs: - - mkdir /debug/ - mount -t debugfs debug /debug/ - - You will get access to files under: - /debug/ath5k/phy0/ - - To enable debug, pass the debug level to the debug module - parameter. For example: - - modprobe ath5k debug=0x00000400 - diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile deleted file mode 100644 index 84a74c5..0000000 --- a/drivers/net/wireless/ath5k/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -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-y += led.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 deleted file mode 100644 index 48c18d1..0000000 --- a/drivers/net/wireless/ath5k/ath5k.h +++ /dev/null @@ -1,1354 +0,0 @@ -/* - * Copyright (c) 2004-2007 Reyk Floeter - * Copyright (c) 2006-2007 Nick Kossifidis - * - * 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. - */ - -#ifndef _ATH5K_H -#define _ATH5K_H - -/* 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 -#include -#include - -#include "../ath/regd.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 */ -#define PCI_DEVICE_ID_ATHEROS_AR5311 0x0011 /* AR5311 */ -#define PCI_DEVICE_ID_ATHEROS_AR5211 0x0012 /* AR5211 */ -#define PCI_DEVICE_ID_ATHEROS_AR5212 0x0013 /* AR5212 */ -#define PCI_DEVICE_ID_3COM_3CRDAG675 0x0013 /* 3CRDAG675 (Atheros AR5212) */ -#define PCI_DEVICE_ID_3COM_2_3CRPAG175 0x0013 /* 3CRPAG175 (Atheros AR5212) */ -#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 0x0207 /* AR5210 (Early) */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM 0x1014 /* AR5212 (IBM MiniPCI) */ -#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 0x1107 /* AR5210 (no eeprom) */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 0x1113 /* AR5212 (no eeprom) */ -#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 0x1112 /* AR5211 (no eeprom) */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 0xf013 /* AR5212 (emulation board) */ -#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 0xff12 /* AR5211 (emulation board) */ -#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 0xf11b /* AR5211 (emulation board) */ -#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ -#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ -#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 0x0058 /* AR5312 WMAC (AP43-030) */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 0x0014 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 0x0015 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 0x0016 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 0x0017 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 0x0018 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 0x0019 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR2413 0x001a /* AR2413 (Griffin-lite) */ -#define PCI_DEVICE_ID_ATHEROS_AR5413 0x001b /* AR5413 (Eagle) */ -#define PCI_DEVICE_ID_ATHEROS_AR5424 0x001c /* AR5424 (Condor PCI-E) */ -#define PCI_DEVICE_ID_ATHEROS_AR5416 0x0023 /* AR5416 */ -#define PCI_DEVICE_ID_ATHEROS_AR5418 0x0024 /* AR5418 */ - -/****************************\ - GENERIC DRIVER DEFINITIONS -\****************************/ - -#define ATH5K_PRINTF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__) - -#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \ - printk(_level "ath5k %s: " _fmt, \ - ((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \ - ##__VA_ARGS__) - -#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \ - if (net_ratelimit()) \ - ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \ - } while (0) - -#define ATH5K_INFO(_sc, _fmt, ...) \ - ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__) - -#define ATH5K_WARN(_sc, _fmt, ...) \ - ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__) - -#define ATH5K_ERR(_sc, _fmt, ...) \ - 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 - -/* 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 -#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 -#define AR5K_TUNE_RADAR_ALERT false -#define AR5K_TUNE_MIN_TX_FIFO_THRES 1 -#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_LEN / 64) + 1) -#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 -/* 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_REGISTER_DWELL_TIME 20000 -#define AR5K_TUNE_BEACON_INTERVAL 100 -#define AR5K_TUNE_AIFS 2 -#define AR5K_TUNE_AIFS_11B 2 -#define AR5K_TUNE_AIFS_XR 0 -#define AR5K_TUNE_CWMIN 15 -#define AR5K_TUNE_CWMIN_11B 31 -#define AR5K_TUNE_CWMIN_XR 3 -#define AR5K_TUNE_CWMAX 1023 -#define AR5K_TUNE_CWMAX_11B 1023 -#define AR5K_TUNE_CWMAX_XR 7 -#define AR5K_TUNE_NOISE_FLOOR -72 -#define AR5K_TUNE_MAX_TXPOWER 63 -#define AR5K_TUNE_DEFAULT_TXPOWER 25 -#define AR5K_TUNE_TPC_TXPOWER false -#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_CYCRSSI_THR1 2 -#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) - -/* GENERIC CHIPSET DEFINITIONS */ - -/* MAC Chips */ -enum ath5k_version { - AR5K_AR5210 = 0, - AR5K_AR5211 = 1, - AR5K_AR5212 = 2, -}; - -/* PHY Chips */ -enum ath5k_radio { - AR5K_RF5110 = 0, - AR5K_RF5111 = 1, - AR5K_RF5112 = 2, - AR5K_RF2413 = 3, - AR5K_RF5413 = 4, - AR5K_RF2316 = 5, - AR5K_RF2317 = 6, - AR5K_RF2425 = 7, -}; - -/* - * Common silicon revision/version values - */ - -enum ath5k_srev_type { - AR5K_VERSION_MAC, - AR5K_VERSION_RAD, -}; - -struct ath5k_srev_name { - const char *sr_name; - enum ath5k_srev_type sr_type; - u_int sr_val; -}; - -#define AR5K_SREV_UNKNOWN 0xffff - -#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 /* Talon */ -#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 -#define AR5K_SREV_RAD_5111A 0x15 -#define AR5K_SREV_RAD_2111 0x20 -#define AR5K_SREV_RAD_5112 0x30 -#define AR5K_SREV_RAD_5112A 0x35 -#define AR5K_SREV_RAD_5112B 0x36 -#define AR5K_SREV_RAD_2112 0x40 -#define AR5K_SREV_RAD_2112A 0x45 -#define AR5K_SREV_RAD_2112B 0x46 -#define AR5K_SREV_RAD_2413 0x50 -#define AR5K_SREV_RAD_5413 0x60 -#define AR5K_SREV_RAD_2316 0x70 /* Cobra SoC */ -#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_5212A 0x42 -#define AR5K_SREV_PHY_5212B 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 */ - -/* - * Some of this information is based on Documentation from: - * - * http://madwifi.org/wiki/ChipsetFeatures/SuperAG - * - * Modulation for Atheros' eXtended Range - range enhancing extension that is - * supposed to double the distance an Atheros client device can keep a - * connection with an Atheros access point. This is achieved by increasing - * the receiver sensitivity up to, -105dBm, which is about 20dB above what - * the 802.11 specifications demand. In addition, new (proprietary) data rates - * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. - * - * Please note that can you either use XR or TURBO but you cannot use both, - * they are exclusive. - * - */ -#define MODULATION_XR 0x00000200 -/* - * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a - * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s - * signaling rate achieved through the bonding of two 54Mbit/s 802.11g - * channels. To use this feature your Access Point must also suport it. - * There is also a distinction between "static" and "dynamic" turbo modes: - * - * - Static: is the dumb version: devices set to this mode stick to it until - * the mode is turned off. - * - Dynamic: is the intelligent version, the network decides itself if it - * is ok to use turbo. As soon as traffic is detected on adjacent channels - * (which would get used in turbo mode), or when a non-turbo station joins - * the network, turbo mode won't be used until the situation changes again. - * Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which - * monitors the used radio band in order to decide whether turbo mode may - * be used or not. - * - * This article claims Super G sticks to bonding of channels 5 and 6 for - * USA: - * - * http://www.pcworld.com/article/id,113428-page,1/article.html - * - * The channel bonding seems to be driver specific though. In addition to - * deciding what channels will be used, these "Turbo" modes are accomplished - * by also enabling the following features: - * - * - Bursting: allows multiple frames to be sent at once, rather than pausing - * after each frame. Bursting is a standards-compliant feature that can be - * used with any Access Point. - * - Fast frames: increases the amount of information that can be sent per - * frame, also resulting in a reduction of transmission overhead. It is a - * proprietary feature that needs to be supported by the Access Point. - * - Compression: data frames are compressed in real time using a Lempel Ziv - * algorithm. This is done transparently. Once this feature is enabled, - * compression and decompression takes place inside the chipset, without - * putting additional load on the host CPU. - * - */ -#define MODULATION_TURBO 0x00000080 - -enum ath5k_driver_mode { - AR5K_MODE_11A = 0, - AR5K_MODE_11A_TURBO = 1, - AR5K_MODE_11B = 2, - AR5K_MODE_11G = 3, - AR5K_MODE_11G_TURBO = 4, - AR5K_MODE_XR = 0, - AR5K_MODE_MAX = 5 -}; - - -/****************\ - TX DEFINITIONS -\****************/ - -/* - * TX Status descriptor - */ -struct ath5k_tx_status { - u16 ts_seqnum; - u16 ts_tstamp; - u8 ts_status; - u8 ts_rate[4]; - u8 ts_retry[4]; - u8 ts_final_idx; - s8 ts_rssi; - u8 ts_shortretry; - u8 ts_longretry; - u8 ts_virtcol; - u8 ts_antenna; -}; - -#define AR5K_TXSTAT_ALTRATE 0x80 -#define AR5K_TXERR_XRETRY 0x01 -#define AR5K_TXERR_FILT 0x02 -#define AR5K_TXERR_FIFO 0x04 - -/** - * enum ath5k_tx_queue - Queue types used to classify tx queues. - * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue - * @AR5K_TX_QUEUE_DATA: A normal data queue - * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue - * @AR5K_TX_QUEUE_BEACON: The beacon queue - * @AR5K_TX_QUEUE_CAB: The after-beacon queue - * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue - */ -enum ath5k_tx_queue { - AR5K_TX_QUEUE_INACTIVE = 0, - AR5K_TX_QUEUE_DATA, - AR5K_TX_QUEUE_XR_DATA, - AR5K_TX_QUEUE_BEACON, - AR5K_TX_QUEUE_CAB, - AR5K_TX_QUEUE_UAPSD, -}; - -#define AR5K_NUM_TX_QUEUES 10 -#define AR5K_NUM_TX_QUEUES_NOQCU 2 - -/* - * Queue syb-types to classify normal data queues. - * These are the 4 Access Categories as defined in - * WME spec. 0 is the lowest priority and 4 is the - * highest. Normal data that hasn't been classified - * goes to the Best Effort AC. - */ -enum ath5k_tx_queue_subtype { - AR5K_WME_AC_BK = 0, /*Background traffic*/ - AR5K_WME_AC_BE, /*Best-effort (normal) traffic)*/ - AR5K_WME_AC_VI, /*Video traffic*/ - AR5K_WME_AC_VO, /*Voice traffic*/ -}; - -/* - * Queue ID numbers as returned by the hw functions, each number - * represents a hw queue. If hw does not support hw queues - * (eg 5210) all data goes in one queue. These match - * d80211 definitions (net80211/MadWiFi don't use them). - */ -enum ath5k_tx_queue_id { - AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, - AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, - AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/ - AR5K_TX_QUEUE_ID_DATA_MAX = 4, /*IEEE80211_TX_QUEUE_DATA4*/ - AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/ - AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/ - AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/ - AR5K_TX_QUEUE_ID_UAPSD = 8, - AR5K_TX_QUEUE_ID_XR_DATA = 9, -}; - -/* - * Flags to set hw queue's parameters... - */ -#define AR5K_TXQ_FLAG_TXOKINT_ENABLE 0x0001 /* Enable TXOK interrupt */ -#define AR5K_TXQ_FLAG_TXERRINT_ENABLE 0x0002 /* Enable TXERR interrupt */ -#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ -#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ -#define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ -#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE 0x0020 /* Enable CBRORN interrupt */ -#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE 0x0040 /* Enable CBRURN interrupt */ -#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE 0x0080 /* Enable QTRIG interrupt */ -#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE 0x0100 /* Enable TXNOFRM interrupt */ -#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0200 /* Disable random post-backoff */ -#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0300 /* Enable ready time expiry policy (?)*/ -#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0800 /* Enable backoff while bursting */ -#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ -#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ - -/* - * A struct to hold tx queue's parameters - */ -struct ath5k_txq_info { - enum ath5k_tx_queue tqi_type; - enum ath5k_tx_queue_subtype tqi_subtype; - u16 tqi_flags; /* Tx queue flags (see above) */ - u32 tqi_aifs; /* Arbitrated Interframe Space */ - s32 tqi_cw_min; /* Minimum Contention Window */ - s32 tqi_cw_max; /* Maximum Contention Window */ - u32 tqi_cbr_period; /* Constant bit rate period */ - u32 tqi_cbr_overflow_limit; - u32 tqi_burst_time; - u32 tqi_ready_time; /* Not used */ -}; - -/* - * Transmit packet types. - * used on tx control descriptor - * TODO: Use them inside base.c corectly - */ -enum ath5k_pkt_type { - AR5K_PKT_TYPE_NORMAL = 0, - AR5K_PKT_TYPE_ATIM = 1, - AR5K_PKT_TYPE_PSPOLL = 2, - AR5K_PKT_TYPE_BEACON = 3, - AR5K_PKT_TYPE_PROBE_RESP = 4, - AR5K_PKT_TYPE_PIFS = 5, -}; - -/* - * TX power and TPC settings - */ -#define AR5K_TXPOWER_OFDM(_r, _v) ( \ - ((0 & 1) << ((_v) + 6)) | \ - (((ah->ah_txpower.txp_rates_power_table[(_r)]) & 0x3f) << (_v)) \ -) - -#define AR5K_TXPOWER_CCK(_r, _v) ( \ - (ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v) \ -) - -/* - * DMA size definitions (2^n+2) - */ -enum ath5k_dmasize { - AR5K_DMASIZE_4B = 0, - AR5K_DMASIZE_8B, - AR5K_DMASIZE_16B, - AR5K_DMASIZE_32B, - AR5K_DMASIZE_64B, - AR5K_DMASIZE_128B, - AR5K_DMASIZE_256B, - AR5K_DMASIZE_512B -}; - - -/****************\ - RX DEFINITIONS -\****************/ - -/* - * RX Status descriptor - */ -struct ath5k_rx_status { - u16 rs_datalen; - u16 rs_tstamp; - u8 rs_status; - u8 rs_phyerr; - s8 rs_rssi; - u8 rs_keyix; - u8 rs_rate; - u8 rs_antenna; - u8 rs_more; -}; - -#define AR5K_RXERR_CRC 0x01 -#define AR5K_RXERR_PHY 0x02 -#define AR5K_RXERR_FIFO 0x04 -#define AR5K_RXERR_DECRYPT 0x08 -#define AR5K_RXERR_MIC 0x10 -#define AR5K_RXKEYIX_INVALID ((u8) - 1) -#define AR5K_TXKEYIX_INVALID ((u32) - 1) - - -/**************************\ - BEACON TIMERS DEFINITIONS -\**************************/ - -#define AR5K_BEACON_PERIOD 0x0000ffff -#define AR5K_BEACON_ENA 0x00800000 /*enable beacon xmit*/ -#define AR5K_BEACON_RESET_TSF 0x01000000 /*force a TSF reset*/ - -#if 0 -/** - * struct ath5k_beacon_state - Per-station beacon timer state. - * @bs_interval: in TU's, can also include the above flags - * @bs_cfp_max_duration: if non-zero hw is setup to coexist with a - * Point Coordination Function capable AP - */ -struct ath5k_beacon_state { - u32 bs_next_beacon; - u32 bs_next_dtim; - u32 bs_interval; - u8 bs_dtim_period; - u8 bs_cfp_period; - u16 bs_cfp_max_duration; - u16 bs_cfp_du_remain; - u16 bs_tim_offset; - u16 bs_sleep_duration; - u16 bs_bmiss_threshold; - u32 bs_cfp_next; -}; -#endif - - -/* - * TSF to TU conversion: - * - * TSF is a 64bit value in usec (microseconds). - * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of - * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024). - */ -#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) - - -/*******************************\ - GAIN OPTIMIZATION DEFINITIONS -\*******************************/ - -enum ath5k_rfgain { - AR5K_RFGAIN_INACTIVE = 0, - AR5K_RFGAIN_ACTIVE, - AR5K_RFGAIN_READ_REQUESTED, - AR5K_RFGAIN_NEED_CHANGE, -}; - -struct ath5k_gain { - u8 g_step_idx; - u8 g_current; - u8 g_target; - u8 g_low; - u8 g_high; - u8 g_f_corr; - u8 g_state; -}; - -/********************\ - COMMON DEFINITIONS -\********************/ - -#define AR5K_SLOT_TIME_9 396 -#define AR5K_SLOT_TIME_20 880 -#define AR5K_SLOT_TIME_MAX 0xffff - -/* channel_flags */ -#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */ -#define CHANNEL_TURBO 0x0010 /* Turbo Channel */ -#define CHANNEL_CCK 0x0020 /* CCK channel */ -#define CHANNEL_OFDM 0x0040 /* OFDM channel */ -#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */ -#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */ -#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */ -#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */ -#define CHANNEL_XR 0x0800 /* XR channel */ - -#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) -#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) -#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) -#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO) -#define CHANNEL_TG (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO) -#define CHANNEL_108A CHANNEL_T -#define CHANNEL_108G CHANNEL_TG -#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR) - -#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \ - CHANNEL_TURBO) - -#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL & ~CHANNEL_TURBO) -#define CHANNEL_MODES CHANNEL_ALL - -/* - * 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 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 -\******************/ - -/** - * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32. - * - * 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. - * - * This is the hardware rate map we are aware of: - * - * rate_code 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 - * rate_kbps 3000 1000 ? ? ? 2000 500 48000 - * - * 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 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(). - */ -#define AR5K_MAX_RATES 32 - -/* 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 - */ - -#define AR5K_KEYCACHE_SIZE 8 - -/***********************\ - HW RELATED DEFINITIONS -\***********************/ - -/* - * Misc definitions - */ -#define AR5K_RSSI_EP_MULTIPLIER (1<<7) - -#define AR5K_ASSERT_ENTRY(_e, _s) do { \ - if (_e >= _s) \ - return (false); \ -} while (0) - -/* - * Hardware interrupt abstraction - */ - -/** - * enum ath5k_int - Hardware interrupt masks helpers - * - * @AR5K_INT_RX: mask to identify received frame interrupts, of type - * AR5K_ISR_RXOK or AR5K_ISR_RXERR - * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?) - * @AR5K_INT_RXNOFRM: No frame received (?) - * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The - * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's - * LinkPtr is NULL. For more details, refer to: - * http://www.freepatentsonline.com/20030225739.html - * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors). - * Note that Rx overrun is not always fatal, on some chips we can continue - * operation without reseting the card, that's why int_fatal is not - * common for all chips. - * @AR5K_INT_TX: mask to identify received frame interrupts, of type - * AR5K_ISR_TXOK or AR5K_ISR_TXERR - * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?) - * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold - * We currently do increments on interrupt by - * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 - * @AR5K_INT_MIB: Indicates the Management Information Base counters should be - * checked. We should do this with ath5k_hw_update_mib_counters() but - * it seems we should also then do some noise immunity work. - * @AR5K_INT_RXPHY: RX PHY Error - * @AR5K_INT_RXKCM: RX Key cache miss - * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a - * beacon that must be handled in software. The alternative is if you - * have VEOL support, in that case you let the hardware deal with things. - * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing - * beacons from the AP have associated with, we should probably try to - * reassociate. When in IBSS mode this might mean we have not received - * any beacons from any local stations. Note that every station in an - * IBSS schedules to send beacons at the Target Beacon Transmission Time - * (TBTT) with a random backoff. - * @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? - * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now - * until properly handled - * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA - * errors. These types of errors we can enable seem to be of type - * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. - * @AR5K_INT_GLOBAL: Used to clear and set the IER - * @AR5K_INT_NOCARD: signals the card has been removed - * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same - * bit value - * - * These are mapped to take advantage of some common bits - * between the MACs, to be able to set intr properties - * easier. Some of them are not used yet inside hw.c. Most map - * to the respective hw interrupt value as they are common amogst different - * MACs. - */ -enum ath5k_int { - AR5K_INT_RXOK = 0x00000001, - AR5K_INT_RXDESC = 0x00000002, - AR5K_INT_RXERR = 0x00000004, - AR5K_INT_RXNOFRM = 0x00000008, - AR5K_INT_RXEOL = 0x00000010, - AR5K_INT_RXORN = 0x00000020, - AR5K_INT_TXOK = 0x00000040, - AR5K_INT_TXDESC = 0x00000080, - AR5K_INT_TXERR = 0x00000100, - AR5K_INT_TXNOFRM = 0x00000200, - AR5K_INT_TXEOL = 0x00000400, - AR5K_INT_TXURN = 0x00000800, - AR5K_INT_MIB = 0x00001000, - AR5K_INT_SWI = 0x00002000, - AR5K_INT_RXPHY = 0x00004000, - AR5K_INT_RXKCM = 0x00008000, - AR5K_INT_SWBA = 0x00010000, - AR5K_INT_BRSSI = 0x00020000, - AR5K_INT_BMISS = 0x00040000, - AR5K_INT_FATAL = 0x00080000, /* Non common */ - AR5K_INT_BNR = 0x00100000, /* Non common */ - AR5K_INT_TIM = 0x00200000, /* Non common */ - AR5K_INT_DTIM = 0x00400000, /* Non common */ - AR5K_INT_DTIM_SYNC = 0x00800000, /* Non common */ - AR5K_INT_GPIO = 0x01000000, - AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ - AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ - AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ - AR5K_INT_QCBRORN = 0x10000000, /* Non common */ - AR5K_INT_QCBRURN = 0x20000000, /* Non common */ - AR5K_INT_QTRIG = 0x40000000, /* Non common */ - AR5K_INT_GLOBAL = 0x80000000, - - AR5K_INT_COMMON = AR5K_INT_RXOK - | AR5K_INT_RXDESC - | AR5K_INT_RXERR - | AR5K_INT_RXNOFRM - | AR5K_INT_RXEOL - | AR5K_INT_RXORN - | AR5K_INT_TXOK - | AR5K_INT_TXDESC - | AR5K_INT_TXERR - | AR5K_INT_TXNOFRM - | AR5K_INT_TXEOL - | AR5K_INT_TXURN - | AR5K_INT_MIB - | AR5K_INT_SWI - | AR5K_INT_RXPHY - | AR5K_INT_RXKCM - | AR5K_INT_SWBA - | AR5K_INT_BRSSI - | AR5K_INT_BMISS - | AR5K_INT_GPIO - | AR5K_INT_GLOBAL, - - AR5K_INT_NOCARD = 0xffffffff -}; - -/* - * Power management - */ -enum ath5k_power_mode { - AR5K_PM_UNDEFINED = 0, - AR5K_PM_AUTO, - AR5K_PM_AWAKE, - AR5K_PM_FULL_SLEEP, - AR5K_PM_NETWORK_SLEEP, -}; - -/* - * These match net80211 definitions (not used in - * mac80211). - * TODO: Clean this up - */ -#define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/ -#define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/ -#define AR5K_LED_AUTH 2 /*IEEE80211_S_AUTH*/ -#define AR5K_LED_ASSOC 3 /*IEEE80211_S_ASSOC*/ -#define AR5K_LED_RUN 4 /*IEEE80211_S_RUN*/ - -/* GPIO-controlled software LED */ -#define AR5K_SOFTLED_PIN 0 -#define AR5K_SOFTLED_ON 0 -#define AR5K_SOFTLED_OFF 1 - -/* - * Chipset capabilities -see ath5k_hw_get_capability- - * get_capability function is not yet fully implemented - * 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 */ - AR5K_CAP_TKIP_MIC = 2, /* Can handle TKIP MIC in hardware */ - AR5K_CAP_TKIP_SPLIT = 3, /* TKIP uses split keys */ - AR5K_CAP_PHYCOUNTERS = 4, /* PHY error counters */ - AR5K_CAP_DIVERSITY = 5, /* Supports fast diversity */ - AR5K_CAP_NUM_TXQUEUES = 6, /* Used to get max number of hw txqueues */ - AR5K_CAP_VEOL = 7, /* Supports virtual EOL */ - AR5K_CAP_COMPRESSION = 8, /* Supports compression */ - AR5K_CAP_BURST = 9, /* Supports packet bursting */ - AR5K_CAP_FASTFRAME = 10, /* Supports fast frames */ - AR5K_CAP_TXPOW = 11, /* Used to get global tx power limit */ - AR5K_CAP_TPC = 12, /* Can do per-packet tx power control (needed for 802.11a) */ - AR5K_CAP_BSSIDMASK = 13, /* Supports bssid mask */ - AR5K_CAP_MCAST_KEYSRCH = 14, /* Supports multicast key search */ - AR5K_CAP_TSF_ADJUST = 15, /* Supports beacon tsf adjust */ - AR5K_CAP_XR = 16, /* Supports XR mode */ - AR5K_CAP_WME_TKIPMIC = 17, /* Supports TKIP MIC when using WMM */ - AR5K_CAP_CHAN_HALFRATE = 18, /* Supports half rate channels */ - AR5K_CAP_CHAN_QUARTERRATE = 19, /* Supports quarter rate channels */ - AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */ -}; - - -/* XXX: we *may* move cap_range stuff to struct wiphy */ -struct ath5k_capabilities { - /* - * Supported PHY modes - * (ie. CHANNEL_A, CHANNEL_B, ...) - */ - DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX); - - /* - * Frequency range (without regulation restrictions) - */ - struct { - u16 range_2ghz_min; - u16 range_2ghz_max; - u16 range_5ghz_min; - u16 range_5ghz_max; - } cap_range; - - /* - * Values stored in the EEPROM (some of them...) - */ - struct ath5k_eeprom_info cap_eeprom; - - /* - * Queue information - */ - struct { - u8 q_tx_num; - } cap_queues; -}; - - -/***************************************\ - HARDWARE ABSTRACTION LAYER STRUCTURE -\***************************************/ - -/* - * Misc defines - */ - -#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; - - struct ath5k_softc *ah_sc; - void __iomem *ah_iobase; - - enum ath5k_int ah_imr; - - enum nl80211_iftype ah_op_mode; - enum ath5k_power_mode ah_power_mode; - struct ieee80211_channel ah_current_channel; - bool ah_turbo; - bool ah_calibration; - bool ah_running; - bool ah_single_chip; - bool ah_combined_mic; - - u32 ah_mac_srev; - u16 ah_mac_version; - u16 ah_mac_revision; - u16 ah_phy_revision; - u16 ah_radio_5ghz_revision; - u16 ah_radio_2ghz_revision; - - enum ath5k_version ah_version; - enum ath5k_radio ah_radio; - u32 ah_phy; - - bool ah_5ghz; - bool ah_2ghz; - -#define ah_modes ah_capabilities.cap_mode -#define ah_ee_version ah_capabilities.cap_eeprom.ee_version - - u32 ah_atim_window; - u32 ah_aifs; - u32 ah_cw_min; - u32 ah_cw_max; - bool ah_software_retry; - u32 ah_limit_tx_retries; - - u32 ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; - bool ah_ant_diversity; - - u8 ah_sta_id[ETH_ALEN]; - - /* Current BSSID we are trying to assoc to / create. - * This is passed by mac80211 on config_interface() and cached here for - * use in resets */ - u8 ah_bssid[ETH_ALEN]; - u8 ah_bssid_mask[ETH_ALEN]; - - u32 ah_gpio[AR5K_MAX_GPIO]; - int ah_gpio_npins; - - struct ath_regulatory ah_regulatory; - struct ath5k_capabilities ah_capabilities; - - struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; - u32 ah_txq_status; - u32 ah_txq_imr_txok; - u32 ah_txq_imr_txerr; - u32 ah_txq_imr_txurn; - u32 ah_txq_imr_txdesc; - u32 ah_txq_imr_txeol; - u32 ah_txq_imr_cbrorn; - u32 ah_txq_imr_cbrurn; - u32 ah_txq_imr_qtrig; - u32 ah_txq_imr_nofrm; - u32 ah_txq_isr; - u32 *ah_rf_banks; - size_t ah_rf_banks_size; - size_t ah_rf_regs_count; - struct ath5k_gain ah_gain; - u8 ah_offset[AR5K_MAX_RF_BANKS]; - - - struct { - /* Temporary tables used for interpolation */ - u8 tmpL[AR5K_EEPROM_N_PD_GAINS] - [AR5K_EEPROM_POWER_TABLE_SIZE]; - u8 tmpR[AR5K_EEPROM_N_PD_GAINS] - [AR5K_EEPROM_POWER_TABLE_SIZE]; - u8 txp_pd_table[AR5K_EEPROM_POWER_TABLE_SIZE * 2]; - u16 txp_rates_power_table[AR5K_MAX_RATES]; - u8 txp_min_idx; - bool txp_tpc; - /* Values in 0.25dB units */ - s16 txp_min_pwr; - s16 txp_max_pwr; - s16 txp_offset; - s16 txp_ofdm; - /* Values in dB units */ - s16 txp_cck_ofdm_pwr_delta; - s16 txp_cck_ofdm_gainf_delta; - } ah_txpower; - - struct { - bool r_enabled; - int r_last_alert; - struct ieee80211_channel r_last_channel; - } ah_radar; - - /* noise floor from last periodic calibration */ - s32 ah_noise_floor; - - /* - * 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_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 *, - struct ath5k_tx_status *); - int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_rx_status *); -}; - -/* - * Prototypes - */ - -/* Attach/Detach Functions */ -extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); -extern void ath5k_hw_detach(struct ath5k_hw *ah); - -/* LED functions */ -extern int ath5k_init_leds(struct ath5k_softc *sc); -extern void ath5k_led_enable(struct ath5k_softc *sc); -extern void ath5k_led_off(struct ath5k_softc *sc); -extern void ath5k_unregister_leds(struct ath5k_softc *sc); - -/* Reset Functions */ -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_dma(struct ath5k_hw *ah); -extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); -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_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_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_eeprom_init(struct ath5k_hw *ah); -extern void ath5k_eeprom_detach(struct ath5k_hw *ah); -extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); -extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); - -/* Protocol Control Unit Functions */ -extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); -/* BSSID Functions */ -extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac); -extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); -extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); -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_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_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 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_set_tsf64(struct ath5k_hw *ah, u64 tsf64); -extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah); -extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); -#if 0 -extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state); -extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah); -extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr); -#endif -/* ACK bit rate */ -void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); -/* ACK/CTS Timeouts */ -extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); -extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); -extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); -extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); -/* Key table (WEP) functions */ -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_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 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_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_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_init(struct ath5k_hw *ah, - struct ieee80211_channel *channel, - unsigned int mode); -extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq); -extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); -extern int ath5k_hw_rfgain_opt_init(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_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_phy_disable(struct ath5k_hw *ah); -/* TX power setup */ -extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); -extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower); - -/* - * Functions used internaly - */ - -/* - * Translate usec to hw clock units - * TODO: Half/quarter rate - */ -static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) -{ - return turbo ? (usec * 80) : (usec * 40); -} - -/* - * Translate hw clock units to usec - * TODO: Half/quarter rate - */ -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; -} - -static inline int ath5k_pad_size(int hdrlen) -{ - return (hdrlen < 24) ? 0 : hdrlen & 3; -} - -#endif diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c deleted file mode 100644 index 70d376c..0000000 --- a/drivers/net/wireless/ath5k/attach.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * - * 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 -#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) -{ - - static const u32 static_pattern[4] = { - 0x55555555, 0xaaaaaaaa, - 0x66666666, 0x99999999 - }; - static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) }; - int i, c; - u16 cur_reg; - u32 var_pattern; - 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; - 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); - 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); - break; - case AR5K_SREV_RAD_2413: - ah->ah_radio = AR5K_RF2413; - ah->ah_single_chip = true; - break; - case AR5K_SREV_RAD_5413: - ah->ah_radio = AR5K_RF5413; - ah->ah_single_chip = true; - break; - case AR5K_SREV_RAD_2316: - ah->ah_radio = AR5K_RF2316; - ah->ah_single_chip = true; - break; - case AR5K_SREV_RAD_2317: - ah->ah_radio = AR5K_RF2317; - ah->ah_single_chip = true; - 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; - } else { - ah->ah_radio = AR5K_RF5413; - ah->ah_single_chip = true; - } - 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; - } else if (srev == AR5K_SREV_AR5213A && - ah->ah_phy_revision == AR5K_SREV_PHY_5212B) { - ah->ah_radio = AR5K_RF5112; - ah->ah_single_chip = false; - ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B; - } 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; - } 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; - } 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; - } 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; - } - - if (srev >= AR5K_SREV_AR2414) { - ah->ah_combined_mic = true; - AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, - AR5K_MISC_MODE_COMBINED_MIC); - } - - /* MAC address is cleared until add_interface */ - ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){}); - - /* 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_rfgain_opt_init(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); - - ath5k_eeprom_detach(ah); - - /* assume interrupts are down */ - kfree(ah); -} diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c deleted file mode 100644 index ff6d4f8..0000000 --- a/drivers/net/wireless/ath5k/base.c +++ /dev/null @@ -1,3110 +0,0 @@ -/*- - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting - * Copyright (c) 2004-2005 Atheros Communications, Inc. - * Copyright (c) 2006 Devicescape Software, Inc. - * Copyright (c) 2007 Jiri Slaby - * Copyright (c) 2007 Luis R. Rodriguez - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any - * redistribution must be conditioned upon including a substantially - * similar Disclaimer requirement for further binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGES. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "base.h" -#include "reg.h" -#include "debug.h" - -static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); - -static int modparam_all_channels; -module_param_named(all_channels, modparam_all_channels, int, 0444); -MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); - - -/******************\ -* Internal defines * -\******************/ - -/* Module info */ -MODULE_AUTHOR("Jiri Slaby"); -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.6.0 (EXPERIMENTAL)"); - - -/* Known PCI ids */ -static const struct pci_device_id ath5k_pci_id_table[] = { - { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */ - { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */ - { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/ - { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */ - { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */ - { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */ - { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */ - { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */ - { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { 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 }, /* 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 const struct ath5k_srev_name srev_names[] = { - { "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 }, - { "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 const 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 - */ -static int __devinit ath5k_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id); -static void __devexit ath5k_pci_remove(struct pci_dev *pdev); -#ifdef CONFIG_PM -static int ath5k_pci_suspend(struct pci_dev *pdev, - pm_message_t state); -static int ath5k_pci_resume(struct pci_dev *pdev); -#else -#define ath5k_pci_suspend NULL -#define ath5k_pci_resume NULL -#endif /* CONFIG_PM */ - -static struct pci_driver ath5k_pci_driver = { - .name = KBUILD_MODNAME, - .id_table = ath5k_pci_id_table, - .probe = ath5k_pci_probe, - .remove = __devexit_p(ath5k_pci_remove), - .suspend = ath5k_pci_suspend, - .resume = ath5k_pci_resume, -}; - - - -/* - * Prototypes - MAC 802.11 stack related functions - */ -static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -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, - struct ieee80211_if_init_conf *conf); -static void ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf); -static int ath5k_config(struct ieee80211_hw *hw, u32 changed); -static int ath5k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf); -static void ath5k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist); -static int ath5k_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); -static int ath5k_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats); -static int ath5k_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats); -static u64 ath5k_get_tsf(struct ieee80211_hw *hw); -static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); -static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ath5k_softc *sc, - struct sk_buff *skb); -static void ath5k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes); - -static const struct ieee80211_ops ath5k_hw_ops = { - .tx = ath5k_tx, - .start = ath5k_start, - .stop = ath5k_stop, - .add_interface = ath5k_add_interface, - .remove_interface = ath5k_remove_interface, - .config = ath5k_config, - .config_interface = ath5k_config_interface, - .configure_filter = ath5k_configure_filter, - .set_key = ath5k_set_key, - .get_stats = ath5k_get_stats, - .conf_tx = NULL, - .get_tx_stats = ath5k_get_tx_stats, - .get_tsf = ath5k_get_tsf, - .set_tsf = ath5k_set_tsf, - .reset_tsf = ath5k_reset_tsf, - .bss_info_changed = ath5k_bss_info_changed, -}; - -/* - * Prototypes - Internal functions - */ -/* Attach detach */ -static int ath5k_attach(struct pci_dev *pdev, - struct ieee80211_hw *hw); -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_channels(struct ath5k_hw *ah, - struct ieee80211_channel *channels, - unsigned int mode, - unsigned int max); -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); - -/* Descriptor setup */ -static int ath5k_desc_alloc(struct ath5k_softc *sc, - struct pci_dev *pdev); -static void ath5k_desc_free(struct ath5k_softc *sc, - struct pci_dev *pdev); -/* Buffers setup */ -static int ath5k_rxbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); -static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); -static inline void ath5k_txbuf_free(struct ath5k_softc *sc, - struct ath5k_buf *bf) -{ - BUG_ON(!bf); - if (!bf->skb) - return; - pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(bf->skb); - bf->skb = NULL; -} - -static inline void ath5k_rxbuf_free(struct ath5k_softc *sc, - struct ath5k_buf *bf) -{ - BUG_ON(!bf); - if (!bf->skb) - return; - pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(bf->skb); - bf->skb = NULL; -} - - -/* Queues setup */ -static struct ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc, - int qtype, int subtype); -static int ath5k_beaconq_setup(struct ath5k_hw *ah); -static int ath5k_beaconq_config(struct ath5k_softc *sc); -static void ath5k_txq_drainq(struct ath5k_softc *sc, - struct ath5k_txq *txq); -static void ath5k_txq_cleanup(struct ath5k_softc *sc); -static void ath5k_txq_release(struct ath5k_softc *sc); -/* Rx handling */ -static int ath5k_rx_start(struct ath5k_softc *sc); -static void ath5k_rx_stop(struct ath5k_softc *sc); -static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, - struct ath5k_desc *ds, - struct sk_buff *skb, - struct ath5k_rx_status *rs); -static void ath5k_tasklet_rx(unsigned long data); -/* Tx handling */ -static void ath5k_tx_processq(struct ath5k_softc *sc, - struct ath5k_txq *txq); -static void ath5k_tasklet_tx(unsigned long data); -/* Beacon handling */ -static int ath5k_beacon_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); -static void ath5k_beacon_send(struct ath5k_softc *sc); -static void ath5k_beacon_config(struct ath5k_softc *sc); -static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); -static void ath5k_tasklet_beacon(unsigned long data); - -static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) -{ - u64 tsf = ath5k_hw_get_tsf64(ah); - - if ((tsf & 0x7fff) < rstamp) - tsf -= 0x8000; - - return (tsf & ~0x7fff) | rstamp; -} - -/* Interrupt handling */ -static int ath5k_init(struct ath5k_softc *sc); -static int ath5k_stop_locked(struct ath5k_softc *sc); -static int ath5k_stop_hw(struct ath5k_softc *sc); -static irqreturn_t ath5k_intr(int irq, void *dev_id); -static void ath5k_tasklet_reset(unsigned long data); - -static void ath5k_calibrate(unsigned long data); - -/* - * Module init/exit functions - */ -static int __init -init_ath5k_pci(void) -{ - int ret; - - ath5k_debug_init(); - - ret = pci_register_driver(&ath5k_pci_driver); - if (ret) { - printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); - return ret; - } - - return 0; -} - -static void __exit -exit_ath5k_pci(void) -{ - pci_unregister_driver(&ath5k_pci_driver); - - ath5k_debug_finish(); -} - -module_init(init_ath5k_pci); -module_exit(exit_ath5k_pci); - - -/********************\ -* PCI Initialization * -\********************/ - -static const char * -ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) -{ - const char *name = "xxxxx"; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(srev_names); i++) { - if (srev_names[i].sr_type != type) - continue; - - 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; - } - } - - return name; -} - -static int __devinit -ath5k_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *mem; - struct ath5k_softc *sc; - struct ieee80211_hw *hw; - int ret; - u8 csz; - - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "can't enable device\n"); - goto err; - } - - /* XXX 32-bit addressing only */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, "32-bit DMA not available\n"); - goto err_dis; - } - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); - if (csz == 0) { - /* - * Linux 2.4.18 (at least) writes the cache line size - * register as a 16-bit wide register which is wrong. - * We must have this setup properly for rx buffer - * DMA to work so force a reasonable value here if it - * comes up zero. - */ - csz = L1_CACHE_BYTES / sizeof(u32); - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); - } - /* - * The default setting of latency timer yields poor results, - * set it to the value used by other systems. It may be worth - * tweaking this setting more. - */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); - - /* Enable bus mastering */ - pci_set_master(pdev); - - /* - * Disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state. - */ - pci_write_config_byte(pdev, 0x41, 0); - - ret = pci_request_region(pdev, 0, "ath5k"); - if (ret) { - dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); - goto err_dis; - } - - mem = pci_iomap(pdev, 0, 0); - if (!mem) { - dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; - ret = -EIO; - goto err_reg; - } - - /* - * Allocate hw (mac80211 main struct) - * and hw->priv (driver private data) - */ - hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); - if (hw == NULL) { - dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); - ret = -ENOMEM; - goto err_map; - } - - dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); - - /* Initialize driver private data */ - SET_IEEE80211_DEV(hw, &pdev->dev); - 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; - sc->hw = hw; - sc->pdev = pdev; - - ath5k_debug_init_device(sc); - - /* - * Mark the device as detached to avoid processing - * interrupts until setup is complete. - */ - __set_bit(ATH_STAT_INVALID, sc->status); - - sc->iobase = mem; /* So we can unmap it on detach */ - sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ - sc->opmode = NL80211_IFTYPE_STATION; - mutex_init(&sc->lock); - spin_lock_init(&sc->rxbuflock); - spin_lock_init(&sc->txbuflock); - spin_lock_init(&sc->block); - - /* Set private data */ - pci_set_drvdata(pdev, hw); - - /* Setup interrupt handler */ - ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); - if (ret) { - ATH5K_ERR(sc, "request_irq failed\n"); - goto err_free; - } - - /* Initialize device */ - sc->ah = ath5k_hw_attach(sc, id->driver_data); - if (IS_ERR(sc->ah)) { - ret = PTR_ERR(sc->ah); - goto err_irq; - } - - /* set up multi-rate retry capabilities */ - if (sc->ah->ah_version == AR5K_AR5212) { - hw->max_rates = 4; - hw->max_rate_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_MAC, sc->ah->ah_mac_srev), - sc->ah->ah_mac_srev, - sc->ah->ah_phy_revision); - - if (!sc->ah->ah_single_chip) { - /* Single chip radio (!RF5111) */ - if (sc->ah->ah_radio_5ghz_revision && - !sc->ah->ah_radio_2ghz_revision) { - /* No 5GHz support -> report 2GHz radio */ - if (!test_bit(AR5K_MODE_11A, - sc->ah->ah_capabilities.cap_mode)) { - ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - /* No 2GHz support (5110 and some - * 5Ghz only cards) -> report 5Ghz radio */ - } else if (!test_bit(AR5K_MODE_11B, - sc->ah->ah_capabilities.cap_mode)) { - ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - /* Multiband radio */ - } else { - ATH5K_INFO(sc, "RF%s multiband radio found" - " (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - } - } - /* Multi chip radio (RF5111 - RF2111) -> - * report both 2GHz/5GHz radios */ - else if (sc->ah->ah_radio_5ghz_revision && - sc->ah->ah_radio_2ghz_revision){ - ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_2ghz_revision), - sc->ah->ah_radio_2ghz_revision); - } - } - - - /* ready to process interrupts */ - __clear_bit(ATH_STAT_INVALID, sc->status); - - return 0; -err_ah: - ath5k_hw_detach(sc->ah); -err_irq: - free_irq(pdev->irq, sc); -err_free: - ieee80211_free_hw(hw); -err_map: - pci_iounmap(pdev, mem); -err_reg: - pci_release_region(pdev, 0); -err_dis: - pci_disable_device(pdev); -err: - return ret; -} - -static void __devexit -ath5k_pci_remove(struct pci_dev *pdev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath5k_softc *sc = hw->priv; - - ath5k_debug_finish_device(sc); - ath5k_detach(pdev, hw); - ath5k_hw_detach(sc->ah); - free_irq(pdev->irq, sc); - pci_iounmap(pdev, sc->iobase); - pci_release_region(pdev, 0); - pci_disable_device(pdev); - ieee80211_free_hw(hw); -} - -#ifdef CONFIG_PM -static int -ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath5k_softc *sc = hw->priv; - - ath5k_led_off(sc); - - free_irq(pdev->irq, sc); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int -ath5k_pci_resume(struct pci_dev *pdev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath5k_softc *sc = hw->priv; - int err; - - pci_restore_state(pdev); - - err = pci_enable_device(pdev); - if (err) - return err; - - err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); - if (err) { - ATH5K_ERR(sc, "request_irq failed\n"); - goto err_no_irq; - } - - ath5k_led_enable(sc); - return 0; - -err_no_irq: - pci_disable_device(pdev); - return err; -} -#endif /* CONFIG_PM */ - - -/***********************\ -* Driver Initialization * -\***********************/ - -static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath5k_softc *sc = hw->priv; - struct ath_regulatory *reg = &sc->ah->ah_regulatory; - - return ath_reg_notifier_apply(wiphy, request, reg); -} - -static int -ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - u8 mac[ETH_ALEN] = {}; - int ret; - - ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); - - /* - * Check if the MAC has multi-rate retry support. - * We do this by trying to setup a fake extended - * descriptor. MAC's that don't have support will - * return false w/o doing anything. MAC's that do - * support it will return true w/o doing anything. - */ - ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); - if (ret < 0) - goto err; - if (ret > 0) - __set_bit(ATH_STAT_MRRETRY, sc->status); - - /* - * Collect the channel list. The 802.11 layer - * is resposible for filtering this list based - * on settings like the phy mode and regulatory - * domain restrictions. - */ - ret = ath5k_setup_bands(hw); - if (ret) { - ATH5K_ERR(sc, "can't get channels\n"); - goto err; - } - - /* NB: setup here so ath5k_rate_update is happy */ - if (test_bit(AR5K_MODE_11A, ah->ah_modes)) - ath5k_setcurmode(sc, AR5K_MODE_11A); - else - ath5k_setcurmode(sc, AR5K_MODE_11B); - - /* - * Allocate tx+rx descriptors and populate the lists. - */ - ret = ath5k_desc_alloc(sc, pdev); - if (ret) { - ATH5K_ERR(sc, "can't allocate descriptors\n"); - goto err; - } - - /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that hw functions handle reseting - * these queues at the needed time. - */ - ret = ath5k_beaconq_setup(ah); - if (ret < 0) { - ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); - goto err_desc; - } - sc->bhalq = ret; - - sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); - if (IS_ERR(sc->txq)) { - ATH5K_ERR(sc, "can't setup xmit queue\n"); - ret = PTR_ERR(sc->txq); - goto err_bhal; - } - - tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); - tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); - tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); - tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); - setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); - - 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_queues; - } - - SET_IEEE80211_PERM_ADDR(hw, mac); - /* All MAC address bits matter for ACKs */ - memset(sc->bssidmask, 0xff, ETH_ALEN); - ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); - - ah->ah_regulatory.current_rd = - ah->ah_capabilities.cap_eeprom.ee_regdomain; - ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier); - if (ret) { - ATH5K_ERR(sc, "can't initialize regulatory system\n"); - goto err_queues; - } - - ret = ieee80211_register_hw(hw); - if (ret) { - ATH5K_ERR(sc, "can't register ieee80211 hw\n"); - goto err_queues; - } - - if (!ath_is_world_regd(&sc->ah->ah_regulatory)) - regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2); - - ath5k_init_leds(sc); - - return 0; -err_queues: - ath5k_txq_release(sc); -err_bhal: - ath5k_hw_release_tx_queue(ah, sc->bhalq); -err_desc: - ath5k_desc_free(sc, pdev); -err: - return ret; -} - -static void -ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - - /* - * NB: the order of these is important: - * o call the 802.11 layer before detaching ath5k_hw to - * insure callbacks into the driver to delete global - * key cache entries can be handled - * o reclaim the tx queue data structures after calling - * the 802.11 layer as we'll get called back to reclaim - * node state and potentially want to use them - * o to cleanup the tx queues the hal is called, so detach - * it last - * XXX: ??? detach ath5k_hw ??? - * Other than that, it's straightforward... - */ - ieee80211_unregister_hw(hw); - ath5k_desc_free(sc, pdev); - ath5k_txq_release(sc); - ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); - ath5k_unregister_leds(sc); - - /* - * NB: can't reclaim these until after ieee80211_ifdetach - * returns because we'll get called back to reclaim node - * state and potentially want to use them. - */ -} - - - - -/********************\ -* Channel/mode setup * -\********************/ - -/* - * Convert IEEE channel number to MHz frequency. - */ -static inline short -ath5k_ieee2mhz(short chan) -{ - if (chan <= 14 || chan >= 27) - return ieee80211chan2mhz(chan); - else - return 2212 + chan * 20; -} - -/* - * Returns true for the channel numbers used without all_channels modparam. - */ -static bool ath5k_is_standard_channel(short chan) -{ - return ((chan <= 14) || - /* UNII 1,2 */ - ((chan & 3) == 0 && chan >= 36 && chan <= 64) || - /* midband */ - ((chan & 3) == 0 && chan >= 100 && chan <= 140) || - /* UNII-3 */ - ((chan & 3) == 1 && chan >= 149 && chan <= 165)); -} - -static unsigned int -ath5k_copy_channels(struct ath5k_hw *ah, - struct ieee80211_channel *channels, - unsigned int mode, - unsigned int max) -{ - unsigned int i, count, size, chfreq, freq, ch; - - if (!test_bit(mode, ah->ah_modes)) - return 0; - - switch (mode) { - case AR5K_MODE_11A: - case AR5K_MODE_11A_TURBO: - /* 1..220, but 2GHz frequencies are filtered by check_channel */ - size = 220 ; - chfreq = CHANNEL_5GHZ; - break; - case AR5K_MODE_11B: - case AR5K_MODE_11G: - case AR5K_MODE_11G_TURBO: - size = 26; - chfreq = CHANNEL_2GHZ; - break; - default: - ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); - return 0; - } - - for (i = 0, count = 0; i < size && max > 0; i++) { - ch = i + 1 ; - freq = ath5k_ieee2mhz(ch); - - /* Check if channel is supported by the chipset */ - if (!ath5k_channel_ok(ah, freq, chfreq)) - continue; - - if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) - continue; - - /* Write channel info and increment counter */ - channels[count].center_freq = freq; - channels[count].band = (chfreq == CHANNEL_2GHZ) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - switch (mode) { - case AR5K_MODE_11A: - case AR5K_MODE_11G: - channels[count].hw_value = chfreq | CHANNEL_OFDM; - break; - case AR5K_MODE_11A_TURBO: - case AR5K_MODE_11G_TURBO: - channels[count].hw_value = chfreq | - CHANNEL_OFDM | CHANNEL_TURBO; - break; - case AR5K_MODE_11B: - channels[count].hw_value = CHANNEL_B; - } - - count++; - max--; - } - - 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_setup_bands(struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - struct ieee80211_supported_band *sband; - int max_c, count_c = 0; - int i; - - BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS); - max_c = ARRAY_SIZE(sc->channels); - - /* 2GHz band */ - sband = &sc->sbands[IEEE80211_BAND_2GHZ]; - sband->band = IEEE80211_BAND_2GHZ; - sband->bitrates = &sc->rates[IEEE80211_BAND_2GHZ][0]; - - 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->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, - AR5K_MODE_11G, max_c); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; - count_c = sband->n_channels; - 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; - } - } - - sband->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, - AR5K_MODE_11B, max_c); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; - count_c = sband->n_channels; - max_c -= count_c; - } - ath5k_setup_rate_idx(sc, sband); - - /* 5GHz band, A mode */ - if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) { - sband = &sc->sbands[IEEE80211_BAND_5GHZ]; - sband->band = IEEE80211_BAND_5GHZ; - sband->bitrates = &sc->rates[IEEE80211_BAND_5GHZ][0]; - - memcpy(sband->bitrates, &ath5k_rates[4], - sizeof(struct ieee80211_rate) * 8); - sband->n_bitrates = 8; - - sband->channels = &sc->channels[count_c]; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, - AR5K_MODE_11A, max_c); - - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; - } - ath5k_setup_rate_idx(sc, sband); - - ath5k_debug_dump_bands(sc); - - return 0; -} - -/* - * Set/change channels. If the channel is really being changed, - * it's done by reseting the chip. To accomplish this we must - * first cleanup any pending DMA, then restart stuff after a la - * ath5k_init. - * - * Called with sc->lock. - */ -static int -ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) -{ - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", - sc->curchan->center_freq, chan->center_freq); - - if (chan->center_freq != sc->curchan->center_freq || - chan->hw_value != sc->curchan->hw_value) { - - sc->curchan = chan; - sc->curband = &sc->sbands[chan->band]; - - /* - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - return ath5k_reset(sc, true, true); - } - - return 0; -} - -static void -ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) -{ - sc->curmode = mode; - - if (mode == AR5K_MODE_11A) { - sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ]; - } else { - sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ]; - } -} - -static void -ath5k_mode_setup(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - u32 rfilt; - - /* configure rx filter */ - rfilt = sc->filter_flags; - ath5k_hw_set_rx_filter(ah, rfilt); - - if (ath5k_hw_hasbssidmask(ah)) - ath5k_hw_set_bssid_mask(ah, sc->bssidmask); - - /* configure operational mode */ - ath5k_hw_set_opmode(ah); - - ath5k_hw_set_mcast_filter(ah, 0, 0); - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); -} - -static inline int -ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) -{ - int rix; - - /* return base rate on errors */ - if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES, - "hw_rix out of bounds: %x\n", hw_rix)) - return 0; - - rix = sc->rate_idx[sc->curband->band][hw_rix]; - if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) - rix = 0; - - return rix; -} - -/***************\ -* Buffers setup * -\***************/ - -static -struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) -{ - struct sk_buff *skb; - unsigned int off; - - /* - * Allocate buffer with headroom_needed space for the - * fake physical layer header at the start. - */ - skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); - - if (!skb) { - ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - sc->rxbufsize + sc->cachelsz - 1); - return NULL; - } - /* - * Cache-line-align. This is important (for the - * 5210 at least) as not doing so causes bogus data - * in rx'd frames. - */ - off = ((unsigned long)skb->data) % sc->cachelsz; - if (off != 0) - skb_reserve(skb, sc->cachelsz - off); - - *skb_addr = pci_map_single(sc->pdev, - skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { - ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); - dev_kfree_skb(skb); - return NULL; - } - return skb; -} - -static int -ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) -{ - struct ath5k_hw *ah = sc->ah; - struct sk_buff *skb = bf->skb; - struct ath5k_desc *ds; - - if (!skb) { - skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr); - if (!skb) - return -ENOMEM; - bf->skb = skb; - } - - /* - * Setup descriptors. For receive we always terminate - * the descriptor list with a self-linked entry so we'll - * not get overrun under high load (as can happen with a - * 5212 when ANI processing enables PHY error frames). - * - * To insure the last descriptor is self-linked we create - * each descriptor as self-linked and add it to the end. As - * each additional descriptor is added the previous self-linked - * entry is ``fixed'' naturally. This should be safe even - * if DMA is happening. When processing RX interrupts we - * never remove/process the last, self-linked, entry on the - * descriptor list. This insures the hardware always has - * someplace to write a new frame. - */ - ds = bf->desc; - ds->ds_link = bf->daddr; /* link to self */ - ds->ds_data = bf->skbaddr; - ah->ah_setup_rx_desc(ah, ds, - skb_tailroom(skb), /* buffer size */ - 0); - - if (sc->rxlink != NULL) - *sc->rxlink = bf->daddr; - sc->rxlink = &ds->ds_link; - return 0; -} - -static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) -{ - struct ath5k_hw *ah = sc->ah; - struct ath5k_txq *txq = sc->txq; - struct ath5k_desc *ds = bf->desc; - struct sk_buff *skb = bf->skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; - struct ieee80211_rate *rate; - unsigned int mrr_rate[3], mrr_tries[3]; - int i, ret; - u16 hw_rate; - u16 cts_rate = 0; - u16 duration = 0; - u8 rc_flags; - - flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; - - /* XXX endianness */ - bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - - rate = ieee80211_get_tx_rate(sc->hw, info); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - flags |= AR5K_TXDESC_NOACK; - - rc_flags = info->control.rates[0].flags; - hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? - rate->hw_value_short : rate->hw_value; - - pktlen = skb->len; - - /* FIXME: If we are in g mode and rate is a CCK rate - * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta - * from tx power (value is in dB units already) */ - if (info->control.hw_key) { - keyidx = info->control.hw_key->hw_key_idx; - pktlen += info->control.hw_key->icv_len; - } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - flags |= AR5K_TXDESC_RTSENA; - cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; - duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, - sc->vif, pktlen, info)); - } - if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - flags |= AR5K_TXDESC_CTSENA; - cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; - duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, - sc->vif, pktlen, info)); - } - ret = ah->ah_setup_tx_desc(ah, ds, pktlen, - ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, - (sc->power_level * 2), - hw_rate, - info->control.rates[0].count, keyidx, 0, flags, - cts_rate, duration); - 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.rates[i + 1].count; - } - - 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; - - spin_lock_bh(&txq->lock); - list_add_tail(&bf->list, &txq->q); - sc->tx_stats[txq->qnum].len++; - if (txq->link == NULL) /* is this first packet? */ - 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_start_tx_dma(ah, txq->qnum); - mmiowb(); - spin_unlock_bh(&txq->lock); - - return 0; -err_unmap: - pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - return ret; -} - -/*******************\ -* Descriptors setup * -\*******************/ - -static int -ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) -{ - struct ath5k_desc *ds; - struct ath5k_buf *bf; - dma_addr_t da; - unsigned int i; - int ret; - - /* allocate descriptors */ - sc->desc_len = sizeof(struct ath5k_desc) * - (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1); - sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr); - if (sc->desc == NULL) { - ATH5K_ERR(sc, "can't allocate descriptors\n"); - ret = -ENOMEM; - goto err; - } - ds = sc->desc; - da = sc->desc_daddr; - ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n", - ds, sc->desc_len, (unsigned long long)sc->desc_daddr); - - bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, - sizeof(struct ath5k_buf), GFP_KERNEL); - if (bf == NULL) { - ATH5K_ERR(sc, "can't allocate bufptr\n"); - ret = -ENOMEM; - goto err_free; - } - sc->bufptr = bf; - - INIT_LIST_HEAD(&sc->rxbuf); - for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { - bf->desc = ds; - bf->daddr = da; - list_add_tail(&bf->list, &sc->rxbuf); - } - - INIT_LIST_HEAD(&sc->txbuf); - sc->txbuf_len = ATH_TXBUF; - for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, - da += sizeof(*ds)) { - bf->desc = ds; - bf->daddr = da; - list_add_tail(&bf->list, &sc->txbuf); - } - - /* beacon buffer */ - bf->desc = ds; - bf->daddr = da; - sc->bbuf = bf; - - return 0; -err_free: - pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); -err: - sc->desc = NULL; - return ret; -} - -static void -ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) -{ - struct ath5k_buf *bf; - - ath5k_txbuf_free(sc, sc->bbuf); - list_for_each_entry(bf, &sc->txbuf, list) - ath5k_txbuf_free(sc, bf); - list_for_each_entry(bf, &sc->rxbuf, list) - ath5k_rxbuf_free(sc, bf); - - /* Free memory associated with all descriptors */ - pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); - - kfree(sc->bufptr); - sc->bufptr = NULL; -} - - - - - -/**************\ -* Queues setup * -\**************/ - -static struct ath5k_txq * -ath5k_txq_setup(struct ath5k_softc *sc, - int qtype, int subtype) -{ - struct ath5k_hw *ah = sc->ah; - struct ath5k_txq *txq; - struct ath5k_txq_info qi = { - .tqi_subtype = subtype, - .tqi_aifs = AR5K_TXQ_USEDEFAULT, - .tqi_cw_min = AR5K_TXQ_USEDEFAULT, - .tqi_cw_max = AR5K_TXQ_USEDEFAULT - }; - int qnum; - - /* - * Enable interrupts only for EOL and DESC conditions. - * We mark tx descriptors to receive a DESC interrupt - * when a tx queue gets deep; otherwise waiting for the - * EOL to reap descriptors. Note that this is done to - * reduce interrupt load and this only defers reaping - * descriptors, never transmitting frames. Aside from - * reducing interrupts this also permits more concurrency. - * The only potential downside is if the tx queue backs - * up in which case the top half of the kernel may backup - * due to a lack of tx descriptors. - */ - qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE | - AR5K_TXQ_FLAG_TXDESCINT_ENABLE; - qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi); - if (qnum < 0) { - /* - * NB: don't print a message, this happens - * normally on parts with too few tx queues - */ - return ERR_PTR(qnum); - } - if (qnum >= ARRAY_SIZE(sc->txqs)) { - ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n", - qnum, ARRAY_SIZE(sc->txqs)); - ath5k_hw_release_tx_queue(ah, qnum); - return ERR_PTR(-EINVAL); - } - txq = &sc->txqs[qnum]; - if (!txq->setup) { - txq->qnum = qnum; - txq->link = NULL; - INIT_LIST_HEAD(&txq->q); - spin_lock_init(&txq->lock); - txq->setup = true; - } - return &sc->txqs[qnum]; -} - -static int -ath5k_beaconq_setup(struct ath5k_hw *ah) -{ - struct ath5k_txq_info qi = { - .tqi_aifs = AR5K_TXQ_USEDEFAULT, - .tqi_cw_min = AR5K_TXQ_USEDEFAULT, - .tqi_cw_max = AR5K_TXQ_USEDEFAULT, - /* NB: for dynamic turbo, don't enable any other interrupts */ - .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE - }; - - return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); -} - -static int -ath5k_beaconq_config(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - struct ath5k_txq_info qi; - int ret; - - ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); - if (ret) - return ret; - if (sc->opmode == NL80211_IFTYPE_AP || - sc->opmode == NL80211_IFTYPE_MESH_POINT) { - /* - * Always burst out beacon and CAB traffic - * (aifs = cwmin = cwmax = 0) - */ - qi.tqi_aifs = 0; - qi.tqi_cw_min = 0; - qi.tqi_cw_max = 0; - } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { - /* - * Adhoc mode; backoff between 0 and (2 * cw_min). - */ - qi.tqi_aifs = 0; - qi.tqi_cw_min = 0; - qi.tqi_cw_max = 2 * ah->ah_cw_min; - } - - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "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_set_tx_queueprops(ah, sc->bhalq, &qi); - if (ret) { - ATH5K_ERR(sc, "%s: unable to update parameters for beacon " - "hardware queue!\n", __func__); - return ret; - } - - return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */; -} - -static void -ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) -{ - struct ath5k_buf *bf, *bf0; - - /* - * NB: this assumes output has been stopped and - * we do not need to block ath5k_tx_tasklet - */ - spin_lock_bh(&txq->lock); - list_for_each_entry_safe(bf, bf0, &txq->q, list) { - ath5k_debug_printtxbuf(sc, bf); - - ath5k_txbuf_free(sc, bf); - - spin_lock_bh(&sc->txbuflock); - sc->tx_stats[txq->qnum].len--; - list_move_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock_bh(&sc->txbuflock); - } - txq->link = NULL; - spin_unlock_bh(&txq->lock); -} - -/* - * Drain the transmit queues and reclaim resources. - */ -static void -ath5k_txq_cleanup(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - unsigned int i; - - /* XXX return value */ - if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) { - /* 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_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_txdp(ah, - sc->txqs[i].qnum), - sc->txqs[i].link); - } - } - ieee80211_wake_queues(sc->hw); /* XXX move to callers */ - - for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) - if (sc->txqs[i].setup) - ath5k_txq_drainq(sc, &sc->txqs[i]); -} - -static void -ath5k_txq_release(struct ath5k_softc *sc) -{ - struct ath5k_txq *txq = sc->txqs; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++) - if (txq->setup) { - ath5k_hw_release_tx_queue(sc->ah, txq->qnum); - txq->setup = false; - } -} - - - - -/*************\ -* RX Handling * -\*************/ - -/* - * Enable the receive h/w following a reset. - */ -static int -ath5k_rx_start(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - struct ath5k_buf *bf; - int ret; - - sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz); - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rxbufsize); - - sc->rxlink = NULL; - - spin_lock_bh(&sc->rxbuflock); - list_for_each_entry(bf, &sc->rxbuf, list) { - ret = ath5k_rxbuf_setup(sc, bf); - if (ret != 0) { - spin_unlock_bh(&sc->rxbuflock); - goto err; - } - } - bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); - spin_unlock_bh(&sc->rxbuflock); - - 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 */ - - return 0; -err: - return ret; -} - -/* - * Disable the receive h/w in preparation for a reset. - */ -static void -ath5k_rx_stop(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - - 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 */ - - ath5k_debug_printrxbuffs(sc, ah); - - sc->rxlink = NULL; /* just in case */ -} - -static unsigned int -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; - - if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && - rs->rs_keyix != AR5K_RXKEYIX_INVALID) - return RX_FLAG_DECRYPTED; - - /* 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) { - keyix = skb->data[hlen + 3] >> 6; - - if (test_bit(keyix, sc->keymap)) - return RX_FLAG_DECRYPTED; - } - - return 0; -} - - -static void -ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, - struct ieee80211_rx_status *rxs) -{ - u64 tsf, bc_tstamp; - u32 hw_tu; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - - if (ieee80211_is_beacon(mgmt->frame_control) && - le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && - memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { - /* - * Received an IBSS beacon with the same BSSID. Hardware *must* - * have updated the local TSF. We have to work around various - * hardware bugs, though... - */ - tsf = ath5k_hw_get_tsf64(sc->ah); - bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp); - hw_tu = TSF_TO_TU(tsf); - - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "beacon %llx mactime %llx (diff %lld) tsf now %llx\n", - (unsigned long long)bc_tstamp, - (unsigned long long)rxs->mactime, - (unsigned long long)(rxs->mactime - bc_tstamp), - (unsigned long long)tsf); - - /* - * Sometimes the HW will give us a wrong tstamp in the rx - * status, causing the timestamp extension to go wrong. - * (This seems to happen especially with beacon frames bigger - * than 78 byte (incl. FCS)) - * But we know that the receive timestamp must be later than the - * timestamp of the beacon since HW must have synced to that. - * - * NOTE: here we assume mactime to be after the frame was - * received, not like mac80211 which defines it at the start. - */ - if (bc_tstamp > rxs->mactime) { - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "fixing mactime from %llx to %llx\n", - (unsigned long long)rxs->mactime, - (unsigned long long)tsf); - rxs->mactime = tsf; - } - - /* - * Local TSF might have moved higher than our beacon timers, - * in that case we have to update them to continue sending - * beacons. This also takes care of synchronizing beacon sending - * times with other stations. - */ - if (hw_tu >= sc->nexttbtt) - ath5k_beacon_update_timers(sc, bc_tstamp); - } -} - -static void ath5k_tasklet_beacon(unsigned long data) -{ - struct ath5k_softc *sc = (struct ath5k_softc *) data; - - /* - * Software beacon alert--time to send a beacon. - * - * In IBSS mode we use this interrupt just to - * keep track of the next TBTT (target beacon - * transmission time) in order to detect wether - * automatic TSF updates happened. - */ - if (sc->opmode == NL80211_IFTYPE_ADHOC) { - /* XXX: only if VEOL suppported */ - u64 tsf = ath5k_hw_get_tsf64(sc->ah); - sc->nexttbtt += sc->bintval; - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "SWBA nexttbtt: %x hw_tu: %x " - "TSF: %llx\n", - sc->nexttbtt, - TSF_TO_TU(tsf), - (unsigned long long) tsf); - } else { - spin_lock(&sc->block); - ath5k_beacon_send(sc); - spin_unlock(&sc->block); - } -} - -static void -ath5k_tasklet_rx(unsigned long data) -{ - struct ieee80211_rx_status rxs = {}; - struct ath5k_rx_status rs = {}; - struct sk_buff *skb, *next_skb; - dma_addr_t next_skb_addr; - struct ath5k_softc *sc = (void *)data; - struct ath5k_buf *bf, *bf_last; - struct ath5k_desc *ds; - int ret; - int hdrlen; - int padsize; - - spin_lock(&sc->rxbuflock); - if (list_empty(&sc->rxbuf)) { - ATH5K_WARN(sc, "empty rx buf pool\n"); - goto unlock; - } - bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list); - do { - rxs.flag = 0; - - bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); - BUG_ON(bf->skb == NULL); - skb = bf->skb; - ds = bf->desc; - - /* - * last buffer must not be freed to ensure proper hardware - * function. When the hardware finishes also a packet next to - * it, we are sure, it doesn't use it anymore and we can go on. - */ - if (bf_last == bf) - bf->flags |= 1; - if (bf->flags) { - struct ath5k_buf *bf_next = list_entry(bf->list.next, - struct ath5k_buf, list); - ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc, - &rs); - if (ret) - break; - bf->flags &= ~1; - /* skip the overwritten one (even status is martian) */ - goto next; - } - - ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); - if (unlikely(ret == -EINPROGRESS)) - break; - else if (unlikely(ret)) { - ATH5K_ERR(sc, "error in processing rx descriptor\n"); - spin_unlock(&sc->rxbuflock); - return; - } - - if (unlikely(rs.rs_more)) { - ATH5K_WARN(sc, "unsupported jumbo\n"); - goto next; - } - - if (unlikely(rs.rs_status)) { - if (rs.rs_status & AR5K_RXERR_PHY) - goto next; - if (rs.rs_status & AR5K_RXERR_DECRYPT) { - /* - * Decrypt error. If the error occurred - * because there was no hardware key, then - * let the frame through so the upper layers - * can process it. This is necessary for 5210 - * parts which have no way to setup a ``clear'' - * key cache entry. - * - * XXX do key cache faulting - */ - if (rs.rs_keyix == AR5K_RXKEYIX_INVALID && - !(rs.rs_status & AR5K_RXERR_CRC)) - goto accept; - } - if (rs.rs_status & AR5K_RXERR_MIC) { - rxs.flag |= RX_FLAG_MMIC_ERROR; - goto accept; - } - - /* let crypto-error packets fall through in MNTR */ - if ((rs.rs_status & - ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || - sc->opmode != NL80211_IFTYPE_MONITOR) - goto next; - } -accept: - next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); - - /* - * If we can't replace bf->skb with a new skb under memory - * pressure, just skip this packet - */ - if (!next_skb) - goto next; - - pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, - PCI_DMA_FROMDEVICE); - skb_put(skb, rs.rs_datalen); - - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - hdrlen % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = ath5k_pad_size(hdrlen); - if (padsize) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - /* - * always extend the mac timestamp, since this information is - * also needed for proper IBSS merging. - * - * XXX: it might be too late to do it here, since rs_tstamp is - * 15bit only. that means TSF extension has to be done within - * 32768usec (about 32ms). it might be necessary to move this to - * the interrupt handler, like it is done in madwifi. - * - * Unfortunately we don't know when the hardware takes the rx - * timestamp (beginning of phy frame, data frame, end of rx?). - * The only thing we know is that it is hardware specific... - * On AR5213 it seems the rx timestamp is at the end of the - * frame, but i'm not sure. - * - * NOTE: mac80211 defines mactime at the beginning of the first - * data symbol. Since we don't have any time references it's - * impossible to comply to that. This affects IBSS merge only - * right now, so it's not too bad... - */ - rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); - rxs.flag |= RX_FLAG_TSFT; - - rxs.freq = sc->curchan->center_freq; - rxs.band = sc->curband->band; - - rxs.noise = sc->ah->ah_noise_floor; - rxs.signal = rxs.noise + rs.rs_rssi; - - /* An rssi of 35 indicates you should be able use - * 54 Mbps reliably. A more elaborate scheme can be used - * here but it requires a map of SNR/throughput for each - * possible mode used */ - rxs.qual = rs.rs_rssi * 100 / 35; - - /* rssi can be more than 35 though, anything above that - * should be considered at 100% */ - if (rxs.qual > 100) - rxs.qual = 100; - - rxs.antenna = rs.rs_antenna; - 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 == NL80211_IFTYPE_ADHOC) - ath5k_check_ibss_tsf(sc, skb, &rxs); - - __ieee80211_rx(sc->hw, skb, &rxs); - - bf->skb = next_skb; - bf->skbaddr = next_skb_addr; -next: - list_move_tail(&bf->list, &sc->rxbuf); - } while (ath5k_rxbuf_setup(sc, bf) == 0); -unlock: - spin_unlock(&sc->rxbuflock); -} - - - - -/*************\ -* TX Handling * -\*************/ - -static void -ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) -{ - struct ath5k_tx_status ts = {}; - struct ath5k_buf *bf, *bf0; - struct ath5k_desc *ds; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - int i, ret; - - spin_lock(&txq->lock); - list_for_each_entry_safe(bf, bf0, &txq->q, list) { - ds = bf->desc; - - ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); - if (unlikely(ret == -EINPROGRESS)) - break; - else if (unlikely(ret)) { - ATH5K_ERR(sc, "error %d while processing queue %u\n", - ret, txq->qnum); - break; - } - - skb = bf->skb; - info = IEEE80211_SKB_CB(skb); - bf->skb = NULL; - - pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, - PCI_DMA_TODEVICE); - - ieee80211_tx_info_clear_status(info); - for (i = 0; i < 4; i++) { - struct ieee80211_tx_rate *r = - &info->status.rates[i]; - - if (ts.ts_rate[i]) { - r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); - r->count = ts.ts_retry[i]; - } else { - r->idx = -1; - r->count = 0; - } - } - - /* count the successful attempt as well */ - info->status.rates[ts.ts_final_idx].count++; - - if (unlikely(ts.ts_status)) { - sc->ll_stats.dot11ACKFailureCount++; - if (ts.ts_status & AR5K_TXERR_FILT) - info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - } else { - info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ts.ts_rssi; - } - - ieee80211_tx_status(sc->hw, skb); - sc->tx_stats[txq->qnum].count++; - - spin_lock(&sc->txbuflock); - sc->tx_stats[txq->qnum].len--; - list_move_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock(&sc->txbuflock); - } - if (likely(list_empty(&txq->q))) - txq->link = NULL; - spin_unlock(&txq->lock); - if (sc->txbuf_len > ATH_TXBUF / 5) - ieee80211_wake_queues(sc->hw); -} - -static void -ath5k_tasklet_tx(unsigned long data) -{ - struct ath5k_softc *sc = (void *)data; - - ath5k_tx_processq(sc, sc->txq); -} - - -/*****************\ -* Beacon handling * -\*****************/ - -/* - * Setup the beacon frame for transmit. - */ -static int -ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) -{ - struct sk_buff *skb = bf->skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath5k_hw *ah = sc->ah; - struct ath5k_desc *ds; - int ret, antenna = 0; - u32 flags; - - bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] " - "skbaddr %llx\n", skb, skb->data, skb->len, - (unsigned long long)bf->skbaddr); - if (pci_dma_mapping_error(sc->pdev, bf->skbaddr)) { - ATH5K_ERR(sc, "beacon DMA mapping failed\n"); - return -EIO; - } - - ds = bf->desc; - - flags = AR5K_TXDESC_NOACK; - if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { - ds->ds_link = bf->daddr; /* self-linked */ - flags |= AR5K_TXDESC_VEOL; - /* - * Let hardware handle antenna switching if txantenna is not set - */ - } else { - ds->ds_link = 0; - /* - * Switch antenna every 4 beacons if txantenna is not set - * XXX assumes two antennas - */ - if (antenna == 0) - antenna = sc->bsent & 4 ? 2 : 1; - } - - /* FIXME: If we are in g mode and rate is a CCK rate - * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta - * from tx power (value is in dB units already) */ - ds->ds_data = bf->skbaddr; - ret = ah->ah_setup_tx_desc(ah, ds, skb->len, - ieee80211_get_hdrlen_from_skb(skb), - AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ieee80211_get_tx_rate(sc->hw, info)->hw_value, - 1, AR5K_TXKEYIX_INVALID, - antenna, flags, 0, 0); - if (ret) - goto err_unmap; - - return 0; -err_unmap: - pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - return ret; -} - -/* - * Transmit a beacon frame at SWBA. Dynamic updates to the - * frame contents are done as needed and the slot time is - * also adjusted based on current state. - * - * This is called from software irq context (beacontq or restq - * tasklets) or user context from ath5k_beacon_config. - */ -static void -ath5k_beacon_send(struct ath5k_softc *sc) -{ - struct ath5k_buf *bf = sc->bbuf; - struct ath5k_hw *ah = sc->ah; - - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); - - 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; - } - /* - * Check if the previous beacon has gone out. If - * not don't don't try to post another, skip this - * period and wait for the next. Missed beacons - * indicate a problem and should not occur. If we - * miss too many consecutive beacons reset the device. - */ - if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) { - sc->bmisscount++; - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "missed %u consecutive beacons\n", sc->bmisscount); - if (sc->bmisscount > 3) { /* NB: 3 is a guess */ - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "stuck beacon time (%u missed)\n", - sc->bmisscount); - tasklet_schedule(&sc->restq); - } - return; - } - if (unlikely(sc->bmisscount != 0)) { - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "resume beacon xmit after %u misses\n", - sc->bmisscount); - sc->bmisscount = 0; - } - - /* - * Stop any current dma and put the new frame on the queue. - * This should never fail since we check above that no frames - * are still pending on the queue. - */ - if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { - ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); - /* NB: hw still stops DMA, so proceed */ - } - - 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); - - sc->bsent++; -} - - -/** - * ath5k_beacon_update_timers - update beacon timers - * - * @sc: struct ath5k_softc pointer we are operating on - * @bc_tsf: the timestamp of the beacon. 0 to reset the TSF. -1 to perform a - * beacon timer update based on the current HW TSF. - * - * Calculate the next target beacon transmit time (TBTT) based on the timestamp - * of a received beacon or the current local hardware TSF and write it to the - * beacon timer registers. - * - * This is called in a variety of situations, e.g. when a beacon is received, - * when a TSF update has been detected, but also when an new IBSS is created or - * when we otherwise know we have to update the timers, but we keep it in this - * function to have it all together in one place. - */ -static void -ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) -{ - struct ath5k_hw *ah = sc->ah; - u32 nexttbtt, intval, hw_tu, bc_tu; - u64 hw_tsf; - - intval = sc->bintval & AR5K_BEACON_PERIOD; - if (WARN_ON(!intval)) - return; - - /* beacon TSF converted to TU */ - bc_tu = TSF_TO_TU(bc_tsf); - - /* current TSF converted to TU */ - hw_tsf = ath5k_hw_get_tsf64(ah); - hw_tu = TSF_TO_TU(hw_tsf); - -#define FUDGE 3 - /* we use FUDGE to make sure the next TBTT is ahead of the current TU */ - if (bc_tsf == -1) { - /* - * no beacons received, called internally. - * just need to refresh timers based on HW TSF. - */ - nexttbtt = roundup(hw_tu + FUDGE, intval); - } else if (bc_tsf == 0) { - /* - * no beacon received, probably called by ath5k_reset_tsf(). - * reset TSF to start with 0. - */ - nexttbtt = intval; - intval |= AR5K_BEACON_RESET_TSF; - } else if (bc_tsf > hw_tsf) { - /* - * beacon received, SW merge happend but HW TSF not yet updated. - * not possible to reconfigure timers yet, but next time we - * receive a beacon with the same BSSID, the hardware will - * automatically update the TSF and then we need to reconfigure - * the timers. - */ - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "need to wait for HW TSF sync\n"); - return; - } else { - /* - * most important case for beacon synchronization between STA. - * - * beacon received and HW TSF has been already updated by HW. - * update next TBTT based on the TSF of the beacon, but make - * sure it is ahead of our local TSF timer. - */ - nexttbtt = bc_tu + roundup(hw_tu + FUDGE - bc_tu, intval); - } -#undef FUDGE - - sc->nexttbtt = nexttbtt; - - intval |= AR5K_BEACON_ENA; - ath5k_hw_init_beacon(ah, nexttbtt, intval); - - /* - * debugging output last in order to preserve the time critical aspect - * of this function - */ - if (bc_tsf == -1) - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "reconfigured timers based on HW TSF\n"); - else if (bc_tsf == 0) - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "reset HW TSF and timers\n"); - else - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "updated timers based on beacon TSF\n"); - - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n", - (unsigned long long) bc_tsf, - (unsigned long long) hw_tsf, bc_tu, hw_tu, nexttbtt); - ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "intval %u %s %s\n", - intval & AR5K_BEACON_PERIOD, - intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "", - intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : ""); -} - - -/** - * ath5k_beacon_config - Configure the beacon queues and interrupts - * - * @sc: struct ath5k_softc pointer we are operating on - * - * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA - * interrupts to detect TSF updates only. - */ -static void -ath5k_beacon_config(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - unsigned long flags; - - ath5k_hw_set_imr(ah, 0); - sc->bmisscount = 0; - sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); - - if (sc->opmode == NL80211_IFTYPE_ADHOC || - sc->opmode == NL80211_IFTYPE_MESH_POINT || - sc->opmode == NL80211_IFTYPE_AP) { - /* - * In IBSS mode we use a self-linked tx descriptor and let the - * hardware send the beacons automatically. We have to load it - * only once here. - * We use the SWBA interrupt only to keep track of the beacon - * timers in order to detect automatic TSF updates. - */ - ath5k_beaconq_config(sc); - - sc->imask |= AR5K_INT_SWBA; - - if (sc->opmode == NL80211_IFTYPE_ADHOC) { - if (ath5k_hw_hasveol(ah)) { - spin_lock_irqsave(&sc->block, flags); - ath5k_beacon_send(sc); - spin_unlock_irqrestore(&sc->block, flags); - } - } else - ath5k_beacon_update_timers(sc, -1); - } - - ath5k_hw_set_imr(ah, sc->imask); -} - - -/********************\ -* Interrupt handling * -\********************/ - -static int -ath5k_init(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - int ret, i; - - mutex_lock(&sc->lock); - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); - - /* - * Stop anything previously setup. This is safe - * no matter this is the first time through or not. - */ - ath5k_stop_locked(sc); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - sc->curchan = sc->hw->conf.channel; - sc->curband = &sc->sbands[sc->curchan->band]; - sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | - AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL; - ret = ath5k_reset(sc, false, false); - if (ret) - goto done; - - /* - * Reset the key cache since some parts do not reset the - * contents on initial power up or resume from suspend. - */ - for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) - ath5k_hw_reset_key(ah, i); - - /* Set ack to be sent at low bit-rates */ - ath5k_hw_set_ack_bitrate_high(ah, false); - - mod_timer(&sc->calib_tim, round_jiffies(jiffies + - msecs_to_jiffies(ath5k_calinterval * 1000))); - - ret = 0; -done: - mmiowb(); - mutex_unlock(&sc->lock); - return ret; -} - -static int -ath5k_stop_locked(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", - test_bit(ATH_STAT_INVALID, sc->status)); - - /* - * Shutdown the hardware and driver: - * stop output from above - * disable interrupts - * turn off timers - * turn off the radio - * clear transmit machinery - * clear receive machinery - * drain and release tx queues - * reclaim beacon resources - * power down hardware - * - * Note that some of this work is not possible if the - * hardware is gone (invalid). - */ - ieee80211_stop_queues(sc->hw); - - if (!test_bit(ATH_STAT_INVALID, sc->status)) { - ath5k_led_off(sc); - ath5k_hw_set_imr(ah, 0); - synchronize_irq(sc->pdev->irq); - } - ath5k_txq_cleanup(sc); - if (!test_bit(ATH_STAT_INVALID, sc->status)) { - ath5k_rx_stop(sc); - ath5k_hw_phy_disable(ah); - } else - sc->rxlink = NULL; - - return 0; -} - -/* - * Stop the device, grabbing the top-level lock to protect - * against concurrent entry through ath5k_init (which can happen - * if another thread does a system call and the thread doing the - * stop is preempted). - */ -static int -ath5k_stop_hw(struct ath5k_softc *sc) -{ - int ret; - - mutex_lock(&sc->lock); - ret = ath5k_stop_locked(sc); - if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { - /* - * Set the chip in full sleep mode. Note that we are - * careful to do this only when bringing the interface - * completely to a stop. When the chip is in this state - * it must be carefully woken up or references to - * registers in the PCI clock domain may freeze the bus - * (and system). This varies by chip and is mostly an - * issue with newer parts that go to sleep more quickly. - */ - if (sc->ah->ah_mac_srev >= 0x78) { - /* - * XXX - * don't put newer MAC revisions > 7.8 to sleep because - * of the above mentioned problems - */ - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, " - "not putting device to sleep\n"); - } else { - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, - "putting device to full sleep\n"); - ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); - } - } - ath5k_txbuf_free(sc, sc->bbuf); - - mmiowb(); - mutex_unlock(&sc->lock); - - del_timer_sync(&sc->calib_tim); - tasklet_kill(&sc->rxtq); - tasklet_kill(&sc->txtq); - tasklet_kill(&sc->restq); - tasklet_kill(&sc->beacontq); - - return ret; -} - -static irqreturn_t -ath5k_intr(int irq, void *dev_id) -{ - struct ath5k_softc *sc = dev_id; - struct ath5k_hw *ah = sc->ah; - enum ath5k_int status; - unsigned int counter = 1000; - - if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) || - !ath5k_hw_is_intr_pending(ah))) - return IRQ_NONE; - - do { - ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ - ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", - status, sc->imask); - if (unlikely(status & AR5K_INT_FATAL)) { - /* - * Fatal errors are unrecoverable. - * Typically these are caused by DMA errors. - */ - tasklet_schedule(&sc->restq); - } else if (unlikely(status & AR5K_INT_RXORN)) { - tasklet_schedule(&sc->restq); - } else { - if (status & AR5K_INT_SWBA) { - tasklet_schedule(&sc->beacontq); - } - if (status & AR5K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work at - * least on older hardware revs. - */ - sc->rxlink = NULL; - } - if (status & AR5K_INT_TXURN) { - /* bump tx trigger level */ - ath5k_hw_update_tx_triglevel(ah, true); - } - if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) - tasklet_schedule(&sc->rxtq); - if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC - | AR5K_INT_TXERR | AR5K_INT_TXEOL)) - tasklet_schedule(&sc->txtq); - if (status & AR5K_INT_BMISS) { - /* TODO */ - } - if (status & AR5K_INT_MIB) { - /* - * These stats are also used for ANI i think - * so how about updating them more often ? - */ - ath5k_hw_update_mib_counters(ah, &sc->ll_stats); - } - } - } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0); - - if (unlikely(!counter)) - ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); - - return IRQ_HANDLED; -} - -static void -ath5k_tasklet_reset(unsigned long data) -{ - struct ath5k_softc *sc = (void *)data; - - ath5k_reset_wake(sc); -} - -/* - * Periodically recalibrate the PHY to account - * for temperature/environment changes. - */ -static void -ath5k_calibrate(unsigned long data) -{ - struct ath5k_softc *sc = (void *)data; - struct ath5k_hw *ah = sc->ah; - - ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", - ieee80211_frequency_to_channel(sc->curchan->center_freq), - sc->curchan->hw_value); - - if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { - /* - * Rfgain is out of bounds, reset the chip - * to load new gain values. - */ - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); - ath5k_reset_wake(sc); - } - if (ath5k_hw_phy_calibrate(ah, sc->curchan)) - ATH5K_ERR(sc, "calibration of channel %u failed\n", - ieee80211_frequency_to_channel( - sc->curchan->center_freq)); - - mod_timer(&sc->calib_tim, round_jiffies(jiffies + - msecs_to_jiffies(ath5k_calinterval * 1000))); -} - - -/********************\ -* Mac80211 functions * -\********************/ - -static int -ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_buf *bf; - unsigned long flags; - int hdrlen; - int padsize; - - ath5k_debug_dump_skb(sc, skb, "TX ", 1); - - if (sc->opmode == NL80211_IFTYPE_MONITOR) - ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n"); - - /* - * the hardware expects the header padded to 4 byte boundaries - * if this is not the case we add the padding after the header - */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = ath5k_pad_size(hdrlen); - if (padsize) { - - if (skb_headroom(skb) < padsize) { - ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" - " headroom to pad %d\n", hdrlen, padsize); - goto drop_packet; - } - skb_push(skb, padsize); - memmove(skb->data, skb->data+padsize, hdrlen); - } - - spin_lock_irqsave(&sc->txbuflock, flags); - if (list_empty(&sc->txbuf)) { - ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); - spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); - goto drop_packet; - } - bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); - list_del(&bf->list); - sc->txbuf_len--; - if (list_empty(&sc->txbuf)) - ieee80211_stop_queues(hw); - spin_unlock_irqrestore(&sc->txbuflock, flags); - - bf->skb = skb; - - if (ath5k_txbuf_setup(sc, bf)) { - bf->skb = NULL; - spin_lock_irqsave(&sc->txbuflock, flags); - list_add_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock_irqrestore(&sc->txbuflock, flags); - goto drop_packet; - } - return NETDEV_TX_OK; - -drop_packet: - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; -} - -static int -ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel) -{ - struct ath5k_hw *ah = sc->ah; - int ret; - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); - - 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 (ret) { - ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); - goto err; - } - - ret = ath5k_rx_start(sc); - if (ret) { - ATH5K_ERR(sc, "can't start recv logic\n"); - goto err; - } - - /* - * 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 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); -} - -static void ath5k_stop(struct ieee80211_hw *hw) -{ - ath5k_stop_hw(hw->priv); -} - -static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct ath5k_softc *sc = hw->priv; - int ret; - - mutex_lock(&sc->lock); - if (sc->vif) { - ret = 0; - goto end; - } - - sc->vif = conf->vif; - - switch (conf->type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_MONITOR: - sc->opmode = conf->type; - break; - default: - ret = -EOPNOTSUPP; - goto end; - } - - /* Set to a reasonable value. Note that this will - * be set to mac80211's value at ath5k_config(). */ - sc->bintval = 1000; - ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); - - ret = 0; -end: - mutex_unlock(&sc->lock); - return ret; -} - -static void -ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct ath5k_softc *sc = hw->priv; - u8 mac[ETH_ALEN] = {}; - - mutex_lock(&sc->lock); - if (sc->vif != conf->vif) - goto end; - - ath5k_hw_set_lladdr(sc->ah, mac); - sc->vif = NULL; -end: - mutex_unlock(&sc->lock); -} - -/* - * TODO: Phy disable/diversity etc - */ -static int -ath5k_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ath5k_softc *sc = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int ret; - - mutex_lock(&sc->lock); - - sc->bintval = conf->beacon_int; - sc->power_level = conf->power_level; - - ret = ath5k_chan_set(sc, conf->channel); - - mutex_unlock(&sc->lock); - return ret; -} - -static int -ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - int ret = 0; - - mutex_lock(&sc->lock); - if (sc->vif != vif) { - ret = -EIO; - goto unlock; - } - if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { - /* Cache for later use during resets */ - memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); - /* XXX: assoc id is set to 0 for now, mac80211 doesn't have - * a clean way of letting us retrieve this yet. */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); - mmiowb(); - } - if (conf->changed & IEEE80211_IFCC_BEACON && - (vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_AP)) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) { - ret = -ENOMEM; - goto unlock; - } - ath5k_beacon_update(sc, beacon); - } - -unlock: - mutex_unlock(&sc->lock); - return ret; -} - -#define SUPPORTED_FIF_FLAGS \ - FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ - FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ - FIF_BCN_PRBRESP_PROMISC -/* - * o always accept unicast, broadcast, and multicast traffic - * o multicast traffic for all BSSIDs will be enabled if mac80211 - * says it should be - * o maintain current state of phy ofdm or phy cck error reception. - * If the hardware detects any of these type of errors then - * ath5k_hw_get_rx_filter() will pass to us the respective - * hardware filters to be able to receive these type of frames. - * o probe request frames are accepted only when operating in - * hostap, adhoc, or monitor modes - * o enable promiscuous mode according to the interface state - * o accept beacons: - * - when operating in adhoc mode so the 802.11 layer creates - * node table entries for peers, - * - when operating in station mode for collecting rssi data when - * the station is otherwise quiet, or - * - when scanning - */ -static void ath5k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - u32 mfilt[2], val, rfilt; - u8 pos; - int i; - - mfilt[0] = 0; - mfilt[1] = 0; - - /* Only deal with supported flags */ - changed_flags &= SUPPORTED_FIF_FLAGS; - *new_flags &= SUPPORTED_FIF_FLAGS; - - /* If HW detects any phy or radar errors, leave those filters on. - * Also, always enable Unicast, Broadcasts and Multicast - * XXX: move unicast, bssid broadcasts and multicast to mac80211 */ - rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) | - (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST | - AR5K_RX_FILTER_MCAST); - - if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { - if (*new_flags & FIF_PROMISC_IN_BSS) { - rfilt |= AR5K_RX_FILTER_PROM; - __set_bit(ATH_STAT_PROMISC, sc->status); - } else { - __clear_bit(ATH_STAT_PROMISC, sc->status); - } - } - - /* Note, AR5K_RX_FILTER_MCAST is already enabled */ - if (*new_flags & FIF_ALLMULTI) { - mfilt[0] = ~0; - mfilt[1] = ~0; - } else { - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - /* calculate XOR of eight 6-bit values */ - val = get_unaligned_le32(mclist->dmi_addr + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = get_unaligned_le32(mclist->dmi_addr + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); - /* XXX: we might be able to just do this instead, - * but not sure, needs testing, if we do use this we'd - * neet to inform below to not reset the mcast */ - /* ath5k_hw_set_mcast_filterindex(ah, - * mclist->dmi_addr[5]); */ - mclist = mclist->next; - } - } - - /* This is the best we can do */ - if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)) - rfilt |= AR5K_RX_FILTER_PHYERR; - - /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons - * and probes for any BSSID, this needs testing */ - if (*new_flags & FIF_BCN_PRBRESP_PROMISC) - rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ; - - /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not - * set we should only pass on control frames for this - * station. This needs testing. I believe right now this - * enables *all* control frames, which is OK.. but - * but we should see if we can improve on granularity */ - if (*new_flags & FIF_CONTROL) - rfilt |= AR5K_RX_FILTER_CONTROL; - - /* Additional settings per mode -- this is per ath5k */ - - /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ - - 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 != NL80211_IFTYPE_STATION) - rfilt |= AR5K_RX_FILTER_PROBEREQ; - 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 == NL80211_IFTYPE_STATION && sc->assoc) || - sc->opmode == NL80211_IFTYPE_ADHOC || - sc->opmode == NL80211_IFTYPE_AP) - rfilt |= AR5K_RX_FILTER_BEACON; - if (sc->opmode == NL80211_IFTYPE_MESH_POINT) - rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | - AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; - - /* Set filters */ - ath5k_hw_set_rx_filter(ah, rfilt); - - /* Set multicast bits */ - ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); - /* Set the cached hw filter flags, this will alter actually - * be set in HW */ - sc->filter_flags = rfilt; -} - -static int -ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct ath5k_softc *sc = hw->priv; - int ret = 0; - - if (modparam_nohwcrypt) - return -EOPNOTSUPP; - - switch (key->alg) { - case ALG_WEP: - case ALG_TKIP: - break; - case ALG_CCMP: - return -EOPNOTSUPP; - default: - WARN_ON(1); - return -EINVAL; - } - - mutex_lock(&sc->lock); - - switch (cmd) { - case SET_KEY: - ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, - sta ? sta->addr : NULL); - if (ret) { - ATH5K_ERR(sc, "can't set the key\n"); - goto unlock; - } - __set_bit(key->keyidx, sc->keymap); - key->hw_key_idx = key->keyidx; - key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | - IEEE80211_KEY_FLAG_GENERATE_MMIC); - break; - case DISABLE_KEY: - ath5k_hw_reset_key(sc->ah, key->keyidx); - __clear_bit(key->keyidx, sc->keymap); - break; - default: - ret = -EINVAL; - goto unlock; - } - -unlock: - mmiowb(); - mutex_unlock(&sc->lock); - return ret; -} - -static int -ath5k_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - - /* Force update */ - ath5k_hw_update_mib_counters(ah, &sc->ll_stats); - - memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); - - return 0; -} - -static int -ath5k_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) -{ - struct ath5k_softc *sc = hw->priv; - - memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats)); - - return 0; -} - -static u64 -ath5k_get_tsf(struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - - return ath5k_hw_get_tsf64(sc->ah); -} - -static void -ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) -{ - struct ath5k_softc *sc = hw->priv; - - ath5k_hw_set_tsf64(sc->ah, tsf); -} - -static void -ath5k_reset_tsf(struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - - /* - * 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 == NL80211_IFTYPE_ADHOC) - ath5k_beacon_update_timers(sc, 0); - else - ath5k_hw_reset_tsf(sc->ah); -} - -static int -ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) -{ - unsigned long flags; - int ret; - - ath5k_debug_dump_skb(sc, skb, "BC ", 1); - - spin_lock_irqsave(&sc->block, flags); - ath5k_txbuf_free(sc, sc->bbuf); - sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf); - if (ret) - sc->bbuf->skb = NULL; - spin_unlock_irqrestore(&sc->block, flags); - if (!ret) { - ath5k_beacon_config(sc); - mmiowb(); - } - - return ret; -} -static void -set_beacon_filter(struct ieee80211_hw *hw, bool enable) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - u32 rfilt; - rfilt = ath5k_hw_get_rx_filter(ah); - if (enable) - rfilt |= AR5K_RX_FILTER_BEACON; - else - rfilt &= ~AR5K_RX_FILTER_BEACON; - ath5k_hw_set_rx_filter(ah, rfilt); - sc->filter_flags = rfilt; -} - -static void ath5k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct ath5k_softc *sc = hw->priv; - if (changes & BSS_CHANGED_ASSOC) { - mutex_lock(&sc->lock); - sc->assoc = bss_conf->assoc; - if (sc->opmode == NL80211_IFTYPE_STATION) - set_beacon_filter(hw, sc->assoc); - mutex_unlock(&sc->lock); - } -} diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h deleted file mode 100644 index 8229561..0000000 --- a/drivers/net/wireless/ath5k/base.h +++ /dev/null @@ -1,190 +0,0 @@ -/*- - * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any - * redistribution must be conditioned upon including a substantially - * similar Disclaimer requirement for further binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGES. - * - */ - -/* - * Defintions for the Atheros Wireless LAN controller driver. - */ -#ifndef _DEV_ATH_ATHVAR_H -#define _DEV_ATH_ATHVAR_H - -#include -#include -#include -#include -#include - -#include "ath5k.h" -#include "debug.h" - -#define ATH_RXBUF 40 /* number of RX buffers */ -#define ATH_TXBUF 200 /* number of TX buffers */ -#define ATH_BCBUF 1 /* number of beacon buffers */ - -struct ath5k_buf { - struct list_head list; - unsigned int flags; /* rx descriptor flags */ - struct ath5k_desc *desc; /* virtual addr of desc */ - dma_addr_t daddr; /* physical addr of desc */ - struct sk_buff *skb; /* skbuff for buf */ - dma_addr_t skbaddr;/* physical addr of skb data */ -}; - -/* - * Data transmit queue state. One of these exists for each - * hardware transmit queue. Packets sent to us from above - * are assigned to queues based on their priority. Not all - * devices support a complete set of hardware transmit queues. - * For those devices the array sc_ac2q will map multiple - * priorities to fewer hardware queues (typically all to one - * hardware queue). - */ -struct ath5k_txq { - unsigned int qnum; /* hardware q number */ - u32 *link; /* link ptr in last TX desc */ - struct list_head q; /* transmit queue */ - spinlock_t lock; /* lock on q and link */ - bool setup; -}; - -#define ATH5K_LED_MAX_NAME_LEN 31 - -/* - * State for LED triggers - */ -struct ath5k_led -{ - char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */ - struct ath5k_softc *sc; /* driver state */ - struct led_classdev led_dev; /* led classdev */ -}; - - -#if CHAN_DEBUG -#define ATH_CHAN_MAX (26+26+26+200+200) -#else -#define ATH_CHAN_MAX (14+14+14+252+20) -#endif - -/* Software Carrier, keeps track of the driver state - * associated with an instance of a device */ -struct ath5k_softc { - struct pci_dev *pdev; /* for dma mapping */ - void __iomem *iobase; /* address of the device */ - struct mutex lock; /* dev-level lock */ - /* FIXME: how many does it really need? */ - struct ieee80211_tx_queue_stats tx_stats[16]; - struct ieee80211_low_level_stats ll_stats; - 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[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; - s8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; - enum nl80211_iftype opmode; - struct ath5k_hw *ah; /* Atheros HW */ - - struct ieee80211_supported_band *curband; - -#ifdef CONFIG_ATH5K_DEBUG - struct ath5k_dbg_info debug; /* debug info */ -#endif /* CONFIG_ATH5K_DEBUG */ - - struct ath5k_buf *bufptr; /* allocated buffer ptr */ - struct ath5k_desc *desc; /* TX/RX descriptors */ - dma_addr_t desc_daddr; /* DMA (physical) address */ - size_t desc_len; /* size of TX/RX descriptors */ - u16 cachelsz; /* cache line size */ - - DECLARE_BITMAP(status, 5); -#define ATH_STAT_INVALID 0 /* disable hardware accesses */ -#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ -#define ATH_STAT_PROMISC 2 -#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ -#define ATH_STAT_STARTED 4 /* opened & irqs enabled */ - - unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ - unsigned int curmode; /* current phy mode */ - struct ieee80211_channel *curchan; /* current h/w channel */ - - struct ieee80211_vif *vif; - - enum ath5k_int imask; /* interrupt mask copy */ - - DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ - - u8 bssidmask[ETH_ALEN]; - - unsigned int led_pin, /* GPIO pin for driving LED */ - led_on; /* pin setting for LED on */ - - struct tasklet_struct restq; /* reset tasklet */ - - unsigned int rxbufsize; /* rx size based on mtu */ - struct list_head rxbuf; /* receive buffer */ - spinlock_t rxbuflock; - u32 *rxlink; /* link ptr in last RX desc */ - struct tasklet_struct rxtq; /* rx intr tasklet */ - struct ath5k_led rx_led; /* rx led */ - - struct list_head txbuf; /* transmit buffer */ - spinlock_t txbuflock; - unsigned int txbuf_len; /* buf count in txbuf list */ - struct ath5k_txq txqs[2]; /* beacon and tx */ - - struct ath5k_txq *txq; /* beacon and tx*/ - struct tasklet_struct txtq; /* tx intr tasklet */ - struct ath5k_led tx_led; /* tx led */ - - spinlock_t block; /* protects beacon */ - struct tasklet_struct beacontq; /* beacon intr tasklet */ - struct ath5k_buf *bbuf; /* beacon buffer */ - unsigned int bhalq, /* SW q for outgoing beacons */ - bmisscount, /* missed beacon transmits */ - bintval, /* beacon interval in TU */ - bsent; - unsigned int nexttbtt; /* next beacon time in TU */ - - struct timer_list calib_tim; /* calibration timer */ - int power_level; /* Requested tx power in dbm */ - bool assoc; /* assocate state */ -}; - -#define ath5k_hw_hasbssidmask(_ah) \ - (ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0) -#define ath5k_hw_hasveol(_ah) \ - (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) - -#endif diff --git a/drivers/net/wireless/ath5k/caps.c b/drivers/net/wireless/ath5k/caps.c deleted file mode 100644 index 367a6c7..0000000 --- a/drivers/net/wireless/ath5k/caps.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * Copyright (c) 2007-2008 Jiri Slaby - * - * 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) && - ah->ah_version != AR5K_AR5211)) { - /* 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) && - ah->ah_version != AR5K_AR5211) - __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 deleted file mode 100644 index 9770bb3..0000000 --- a/drivers/net/wireless/ath5k/debug.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright (c) 2007-2008 Bruno Randolf - * - * This file is free software: you may copy, redistribute 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 file 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, see . - * - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting - * Copyright (c) 2004-2005 Atheros Communications, Inc. - * Copyright (c) 2006 Devicescape Software, Inc. - * Copyright (c) 2007 Jiri Slaby - * Copyright (c) 2007 Luis R. Rodriguez - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any - * redistribution must be conditioned upon including a substantially - * similar Disclaimer requirement for further binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGES. - */ - -#include "base.h" -#include "debug.h" - -static unsigned int ath5k_debug; -module_param_named(debug, ath5k_debug, uint, 0); - - -#ifdef CONFIG_ATH5K_DEBUG - -#include -#include "reg.h" - -static struct dentry *ath5k_global_debugfs; - -static int ath5k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - - -/* debugfs: registers */ - -struct reg { - const char *name; - int addr; -}; - -#define REG_STRUCT_INIT(r) { #r, r } - -/* just a few random registers, might want to add more */ -static const struct reg regs[] = { - REG_STRUCT_INIT(AR5K_CR), - REG_STRUCT_INIT(AR5K_RXDP), - REG_STRUCT_INIT(AR5K_CFG), - REG_STRUCT_INIT(AR5K_IER), - REG_STRUCT_INIT(AR5K_BCR), - REG_STRUCT_INIT(AR5K_RTSD0), - REG_STRUCT_INIT(AR5K_RTSD1), - REG_STRUCT_INIT(AR5K_TXCFG), - REG_STRUCT_INIT(AR5K_RXCFG), - REG_STRUCT_INIT(AR5K_RXJLA), - REG_STRUCT_INIT(AR5K_MIBC), - REG_STRUCT_INIT(AR5K_TOPS), - REG_STRUCT_INIT(AR5K_RXNOFRM), - REG_STRUCT_INIT(AR5K_TXNOFRM), - REG_STRUCT_INIT(AR5K_RPGTO), - REG_STRUCT_INIT(AR5K_RFCNT), - REG_STRUCT_INIT(AR5K_MISC), - REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT), - REG_STRUCT_INIT(AR5K_ISR), - REG_STRUCT_INIT(AR5K_PISR), - REG_STRUCT_INIT(AR5K_SISR0), - REG_STRUCT_INIT(AR5K_SISR1), - REG_STRUCT_INIT(AR5K_SISR2), - REG_STRUCT_INIT(AR5K_SISR3), - REG_STRUCT_INIT(AR5K_SISR4), - REG_STRUCT_INIT(AR5K_IMR), - REG_STRUCT_INIT(AR5K_PIMR), - REG_STRUCT_INIT(AR5K_SIMR0), - REG_STRUCT_INIT(AR5K_SIMR1), - REG_STRUCT_INIT(AR5K_SIMR2), - REG_STRUCT_INIT(AR5K_SIMR3), - REG_STRUCT_INIT(AR5K_SIMR4), - REG_STRUCT_INIT(AR5K_DCM_ADDR), - REG_STRUCT_INIT(AR5K_DCCFG), - REG_STRUCT_INIT(AR5K_CCFG), - REG_STRUCT_INIT(AR5K_CPC0), - REG_STRUCT_INIT(AR5K_CPC1), - REG_STRUCT_INIT(AR5K_CPC2), - REG_STRUCT_INIT(AR5K_CPC3), - REG_STRUCT_INIT(AR5K_CPCOVF), - REG_STRUCT_INIT(AR5K_RESET_CTL), - REG_STRUCT_INIT(AR5K_SLEEP_CTL), - REG_STRUCT_INIT(AR5K_INTPEND), - REG_STRUCT_INIT(AR5K_SFR), - REG_STRUCT_INIT(AR5K_PCICFG), - REG_STRUCT_INIT(AR5K_GPIOCR), - REG_STRUCT_INIT(AR5K_GPIODO), - REG_STRUCT_INIT(AR5K_SREV), -}; - -static void *reg_start(struct seq_file *seq, loff_t *pos) -{ - return *pos < ARRAY_SIZE(regs) ? (void *)®s[*pos] : NULL; -} - -static void reg_stop(struct seq_file *seq, void *p) -{ - /* nothing to do */ -} - -static void *reg_next(struct seq_file *seq, void *p, loff_t *pos) -{ - ++*pos; - return *pos < ARRAY_SIZE(regs) ? (void *)®s[*pos] : NULL; -} - -static int reg_show(struct seq_file *seq, void *p) -{ - struct ath5k_softc *sc = seq->private; - struct reg *r = p; - seq_printf(seq, "%-25s0x%08x\n", r->name, - ath5k_hw_reg_read(sc->ah, r->addr)); - return 0; -} - -static const struct seq_operations register_seq_ops = { - .start = reg_start, - .next = reg_next, - .stop = reg_stop, - .show = reg_show -}; - -static int open_file_registers(struct inode *inode, struct file *file) -{ - struct seq_file *s; - int res; - res = seq_open(file, ®ister_seq_ops); - if (res == 0) { - s = file->private_data; - s->private = inode->i_private; - } - return res; -} - -static const struct file_operations fops_registers = { - .open = open_file_registers, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, - .owner = THIS_MODULE, -}; - - -/* debugfs: beacons */ - -static ssize_t read_file_beacon(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath5k_softc *sc = file->private_data; - struct ath5k_hw *ah = sc->ah; - char buf[500]; - unsigned int len = 0; - unsigned int v; - u64 tsf; - - v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON); - len += snprintf(buf+len, sizeof(buf)-len, - "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n", - "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD, - (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S); - - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n", - "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP)); - - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n", - "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT)); - - v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", - "AR5K_TIMER0 (TBTT)", v, v); - - v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", - "AR5K_TIMER1 (DMA)", v, v >> 3); - - v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", - "AR5K_TIMER2 (SWBA)", v, v >> 3); - - v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", - "AR5K_TIMER3 (ATIM)", v, v); - - tsf = ath5k_hw_get_tsf64(sc->ah); - len += snprintf(buf+len, sizeof(buf)-len, - "TSF\t\t0x%016llx\tTU: %08x\n", - (unsigned long long)tsf, TSF_TO_TU(tsf)); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_beacon(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ath5k_softc *sc = file->private_data; - struct ath5k_hw *ah = sc->ah; - char buf[20]; - - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) - return -EFAULT; - - if (strncmp(buf, "disable", 7) == 0) { - AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); - printk(KERN_INFO "debugfs disable beacons\n"); - } else if (strncmp(buf, "enable", 6) == 0) { - AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); - printk(KERN_INFO "debugfs enable beacons\n"); - } - return count; -} - -static const struct file_operations fops_beacon = { - .read = read_file_beacon, - .write = write_file_beacon, - .open = ath5k_debugfs_open, - .owner = THIS_MODULE, -}; - - -/* debugfs: reset */ - -static ssize_t write_file_reset(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ath5k_softc *sc = file->private_data; - tasklet_schedule(&sc->restq); - return count; -} - -static const struct file_operations fops_reset = { - .write = write_file_reset, - .open = ath5k_debugfs_open, - .owner = THIS_MODULE, -}; - - -/* debugfs: debug level */ - -static const struct { - enum ath5k_debug_level level; - const char *name; - const char *desc; -} dbg_info[] = { - { ATH5K_DEBUG_RESET, "reset", "reset and initialization" }, - { ATH5K_DEBUG_INTR, "intr", "interrupt handling" }, - { ATH5K_DEBUG_MODE, "mode", "mode init/setup" }, - { ATH5K_DEBUG_XMIT, "xmit", "basic xmit operation" }, - { ATH5K_DEBUG_BEACON, "beacon", "beacon handling" }, - { ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" }, - { ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" }, - { ATH5K_DEBUG_LED, "led", "LED management" }, - { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, - { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, - { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, - { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, - { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, -}; - -static ssize_t read_file_debug(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath5k_softc *sc = file->private_data; - char buf[700]; - unsigned int len = 0; - unsigned int i; - - len += snprintf(buf+len, sizeof(buf)-len, - "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level); - - for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) { - len += snprintf(buf+len, sizeof(buf)-len, - "%10s %c 0x%08x - %s\n", dbg_info[i].name, - sc->debug.level & dbg_info[i].level ? '+' : ' ', - dbg_info[i].level, dbg_info[i].desc); - } - len += snprintf(buf+len, sizeof(buf)-len, - "%10s %c 0x%08x - %s\n", dbg_info[i].name, - sc->debug.level == dbg_info[i].level ? '+' : ' ', - dbg_info[i].level, dbg_info[i].desc); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_debug(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ath5k_softc *sc = file->private_data; - unsigned int i; - char buf[20]; - - if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(dbg_info); i++) { - if (strncmp(buf, dbg_info[i].name, - strlen(dbg_info[i].name)) == 0) { - sc->debug.level ^= dbg_info[i].level; /* toggle bit */ - break; - } - } - return count; -} - -static const struct file_operations fops_debug = { - .read = read_file_debug, - .write = write_file_debug, - .open = ath5k_debugfs_open, - .owner = THIS_MODULE, -}; - - -/* init */ - -void -ath5k_debug_init(void) -{ - ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); -} - -void -ath5k_debug_init_device(struct ath5k_softc *sc) -{ - sc->debug.level = ath5k_debug; - - sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), - ath5k_global_debugfs); - - sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO, - sc->debug.debugfs_phydir, sc, &fops_debug); - - sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO, - sc->debug.debugfs_phydir, sc, &fops_registers); - - sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO, - sc->debug.debugfs_phydir, sc, &fops_beacon); - - sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, - sc->debug.debugfs_phydir, sc, &fops_reset); -} - -void -ath5k_debug_finish(void) -{ - debugfs_remove(ath5k_global_debugfs); -} - -void -ath5k_debug_finish_device(struct ath5k_softc *sc) -{ - debugfs_remove(sc->debug.debugfs_debug); - debugfs_remove(sc->debug.debugfs_registers); - debugfs_remove(sc->debug.debugfs_beacon); - debugfs_remove(sc->debug.debugfs_reset); - debugfs_remove(sc->debug.debugfs_phydir); -} - - -/* functions used in other places */ - -void -ath5k_debug_dump_bands(struct ath5k_softc *sc) -{ - unsigned int b, i; - - if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPBANDS))) - return; - - BUG_ON(!sc->sbands); - - for (b = 0; b < IEEE80211_NUM_BANDS; b++) { - struct ieee80211_supported_band *band = &sc->sbands[b]; - char bname[5]; - switch (band->band) { - case IEEE80211_BAND_2GHZ: - strcpy(bname, "2 GHz"); - break; - case IEEE80211_BAND_5GHZ: - strcpy(bname, "5 GHz"); - break; - default: - printk(KERN_DEBUG "Band not supported: %d\n", - band->band); - return; - } - printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname, - band->n_channels, band->n_bitrates); - printk(KERN_DEBUG " channels:\n"); - for (i = 0; i < band->n_channels; i++) - printk(KERN_DEBUG " %3d %d %.4x %.4x\n", - ieee80211_frequency_to_channel( - band->channels[i].center_freq), - band->channels[i].center_freq, - band->channels[i].hw_value, - band->channels[i].flags); - printk(KERN_DEBUG " rates:\n"); - for (i = 0; i < band->n_bitrates; i++) - printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", - band->bitrates[i].bitrate, - band->bitrates[i].hw_value, - band->bitrates[i].flags, - band->bitrates[i].hw_value_short); - } -} - -static inline void -ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done, - struct ath5k_rx_status *rs) -{ - struct ath5k_desc *ds = bf->desc; - struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx; - - printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", - ds, (unsigned long long)bf->daddr, - ds->ds_link, ds->ds_data, - rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1, - rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0, - !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'); -} - -void -ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) -{ - struct ath5k_desc *ds; - struct ath5k_buf *bf; - struct ath5k_rx_status rs = {}; - int status; - - if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) - return; - - printk(KERN_DEBUG "rx queue %x, link %p\n", - ath5k_hw_get_rxdp(ah), sc->rxlink); - - spin_lock_bh(&sc->rxbuflock); - list_for_each_entry(bf, &sc->rxbuf, list) { - ds = bf->desc; - status = ah->ah_proc_rx_desc(ah, ds, &rs); - if (!status) - ath5k_debug_printrxbuf(bf, status == 0, &rs); - } - spin_unlock_bh(&sc->rxbuflock); -} - -void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx) -{ - char buf[16]; - - if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || - (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) - return; - - snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); - - print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, - min(200U, skb->len)); - - printk(KERN_DEBUG "\n"); -} - -void -ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) -{ - struct ath5k_desc *ds = bf->desc; - struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212; - struct ath5k_tx_status ts = {}; - int done; - - if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) - return; - - done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts); - - printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " - "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, - ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1, - td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3, - td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, - done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); -} - -#endif /* ifdef CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h deleted file mode 100644 index 66f69f0..0000000 --- a/drivers/net/wireless/ath5k/debug.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2007 Bruno Randolf - * - * This file is free software: you may copy, redistribute 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 file 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, see . - * - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting - * Copyright (c) 2004-2005 Atheros Communications, Inc. - * Copyright (c) 2006 Devicescape Software, Inc. - * Copyright (c) 2007 Jiri Slaby - * Copyright (c) 2007 Luis R. Rodriguez - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any - * redistribution must be conditioned upon including a substantially - * similar Disclaimer requirement for further binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef _ATH5K_DEBUG_H -#define _ATH5K_DEBUG_H - -struct ath5k_softc; -struct ath5k_hw; -struct sk_buff; -struct ath5k_buf; - -struct ath5k_dbg_info { - unsigned int level; /* debug level */ - /* debugfs entries */ - struct dentry *debugfs_phydir; - struct dentry *debugfs_debug; - struct dentry *debugfs_registers; - struct dentry *debugfs_beacon; - struct dentry *debugfs_reset; -}; - -/** - * enum ath5k_debug_level - ath5k debug level - * - * @ATH5K_DEBUG_RESET: reset processing - * @ATH5K_DEBUG_INTR: interrupt handling - * @ATH5K_DEBUG_MODE: mode init/setup - * @ATH5K_DEBUG_XMIT: basic xmit operation - * @ATH5K_DEBUG_BEACON: beacon handling - * @ATH5K_DEBUG_CALIBRATE: periodic calibration - * @ATH5K_DEBUG_TXPOWER: transmit power setting - * @ATH5K_DEBUG_LED: led management - * @ATH5K_DEBUG_DUMP_RX: print received skb content - * @ATH5K_DEBUG_DUMP_TX: print transmit skb content - * @ATH5K_DEBUG_DUMPBANDS: dump bands - * @ATH5K_DEBUG_TRACE: trace function calls - * @ATH5K_DEBUG_ANY: show at any debug level - * - * The debug level is used to control the amount and type of debugging output - * we want to see. The debug level is given in calls to ATH5K_DBG to specify - * where the message should appear, and the user can control the debugging - * messages he wants to see, either by the module parameter 'debug' on module - * load, or dynamically by using debugfs 'ath5k/phyX/debug'. these levels can - * be combined together by bitwise OR. - */ -enum ath5k_debug_level { - ATH5K_DEBUG_RESET = 0x00000001, - ATH5K_DEBUG_INTR = 0x00000002, - ATH5K_DEBUG_MODE = 0x00000004, - ATH5K_DEBUG_XMIT = 0x00000008, - ATH5K_DEBUG_BEACON = 0x00000010, - ATH5K_DEBUG_CALIBRATE = 0x00000020, - ATH5K_DEBUG_TXPOWER = 0x00000040, - ATH5K_DEBUG_LED = 0x00000080, - ATH5K_DEBUG_DUMP_RX = 0x00000100, - ATH5K_DEBUG_DUMP_TX = 0x00000200, - ATH5K_DEBUG_DUMPBANDS = 0x00000400, - ATH5K_DEBUG_TRACE = 0x00001000, - ATH5K_DEBUG_ANY = 0xffffffff -}; - -#ifdef CONFIG_ATH5K_DEBUG - -#define ATH5K_TRACE(_sc) do { \ - if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \ - printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \ - } while (0) - -#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \ - if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \ - ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ - __func__, __LINE__, ##__VA_ARGS__); \ - } while (0) - -#define ATH5K_DBG_UNLIMIT(_sc, _m, _fmt, ...) do { \ - if (unlikely((_sc)->debug.level & (_m))) \ - ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ - __func__, __LINE__, ##__VA_ARGS__); \ - } while (0) - -void -ath5k_debug_init(void); - -void -ath5k_debug_init_device(struct ath5k_softc *sc); - -void -ath5k_debug_finish(void); - -void -ath5k_debug_finish_device(struct ath5k_softc *sc); - -void -ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); - -void -ath5k_debug_dump_bands(struct ath5k_softc *sc); - -void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx); - -void -ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf); - -#else /* no debugging */ - -#include - -#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc)) - -static inline void __attribute__ ((format (printf, 3, 4))) -ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} - -static inline void __attribute__ ((format (printf, 3, 4))) -ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) -{} - -static inline void -ath5k_debug_init(void) {} - -static inline void -ath5k_debug_init_device(struct ath5k_softc *sc) {} - -static inline void -ath5k_debug_finish(void) {} - -static inline void -ath5k_debug_finish_device(struct ath5k_softc *sc) {} - -static inline void -ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} - -static inline void -ath5k_debug_dump_bands(struct ath5k_softc *sc) {} - -static inline void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx) {} - -static inline void -ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {} - -#endif /* ifdef CONFIG_ATH5K_DEBUG */ - -#endif /* ifndef _ATH5K_DEBUG_H */ diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c deleted file mode 100644 index dc30a2b..0000000 --- a/drivers/net/wireless/ath5k/desc.c +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * Copyright (c) 2007-2008 Pavel Roskin - * - * 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 - ath5k_pad_size(hdr_len) + 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; - } - - tx_power += ah->ah_txpower.txp_offset; - if (tx_power > AR5K_TUNE_MAX_TXPOWER) - tx_power = AR5K_TUNE_MAX_TXPOWER; - - /* 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 - ath5k_pad_size(hdr_len) + 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 = AR5K_REG_MS(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 = AR5K_REG_MS(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/desc.h b/drivers/net/wireless/ath5k/desc.h deleted file mode 100644 index 56158c8..0000000 --- a/drivers/net/wireless/ath5k/desc.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * - * 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. - * - */ - -/* - * Internal RX/TX descriptor structures - * (rX: reserved fields possibily used by future versions of the ar5k chipset) - */ - -/* - * common hardware RX control descriptor - */ -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 - -/* RX control word 1 fields/flags */ -#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff -#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 - -/* - * common hardware RX status descriptor - * 5210/11 and 5212 differ only in the flags defined below - */ -struct ath5k_hw_rx_status { - u32 rx_status_0; /* RX status word 0 */ - u32 rx_status_1; /* RX status word 1 */ -} __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 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 -#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 -#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 -#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 -#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 -#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 -#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 -#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 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 -#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 -#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 -#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 -#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 -#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 -#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 - -/* - * common hardware RX error descriptor - */ -struct ath5k_hw_rx_error { - 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 - -/* 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 - -/* 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 -#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 -#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 -#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 -#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 -#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 - -/* - * 5210/5211 hardware 2-word TX control descriptor - */ -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 -#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 -#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18 -#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 -#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 -#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/ -#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/ -#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/ -#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_S 25 -#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 -#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 - -/* 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_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 ?]*/ - -/* 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 -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 - -/* - * 5212 hardware 4-word TX control descriptor - */ -struct ath5k_hw_4w_tx_ctl { - u32 tx_control_0; /* TX control word 0 */ - -#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff -#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 -#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16 -#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 -#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 -#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 -#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 -#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 -#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 -#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 -#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 - - u32 tx_control_1; /* TX control word 1 */ - -#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff -#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 -#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000 -#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 -#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 -#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20 -#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25 -#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27 -#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29 - - u32 tx_control_2; /* TX control word 2 */ - -#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff -#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 - - u32 tx_control_3; /* TX control word 3 */ - -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15 -#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 -#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 -} __packed; - -/* - * Common TX status descriptor - */ -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 -#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 -/*??? -#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0 -#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4 -*/ -#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 -#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4 -/*??? -#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00 -#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8 -*/ -#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 -#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8 -#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000 -#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12 -#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 -#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 - -/* 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 -#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 -#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13 -#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000 -#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 - -/* - * 5210/5211 hardware TX descriptor - */ -struct ath5k_hw_5210_tx_desc { - struct ath5k_hw_2w_tx_ctl tx_ctl; - struct ath5k_hw_tx_status tx_stat; -} __packed; - -/* - * 5212 hardware TX descriptor - */ -struct ath5k_hw_5212_tx_desc { - struct ath5k_hw_4w_tx_ctl tx_ctl; - struct ath5k_hw_tx_status tx_stat; -} __packed; - -/* - * common hardware RX descriptor - */ -struct ath5k_hw_all_rx_desc { - struct ath5k_hw_rx_ctl rx_ctl; - union { - struct ath5k_hw_rx_status rx_stat; - struct ath5k_hw_rx_error rx_err; - } u; -} __packed; - -/* - * 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+]*/ - diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c deleted file mode 100644 index b65b4fe..0000000 --- a/drivers/net/wireless/ath5k/dma.c +++ /dev/null @@ -1,705 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * - * 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. - */ -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 Interrupt - * Status Register shadow copy (Read And Clear) - * - * Note: PISR/SISR Not available on 5210 - */ - data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); - if (unlikely(data == AR5K_INT_NOCARD)) { - *interrupt_mask = data; - return -ENODEV; - } - } - - /* - * Get abstract interrupt mask (driver-compatible) - */ - *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; - - if (ah->ah_version != AR5K_AR5210) { - u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); - - /*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; - - if (unlikely(sisr2 & (AR5K_SISR2_SSERR | - AR5K_SISR2_DPERR | - AR5K_SISR2_MCABT))) - *interrupt_mask |= AR5K_INT_FATAL; - - if (data & AR5K_ISR_TIM) - *interrupt_mask |= AR5K_INT_TIM; - - if (data & AR5K_ISR_BCNMISC) { - if (sisr2 & AR5K_SISR2_TIM) - *interrupt_mask |= AR5K_INT_TIM; - if (sisr2 & AR5K_SISR2_DTIM) - *interrupt_mask |= AR5K_INT_DTIM; - if (sisr2 & AR5K_SISR2_DTIM_SYNC) - *interrupt_mask |= AR5K_INT_DTIM_SYNC; - if (sisr2 & AR5K_SISR2_BCN_TIMEOUT) - *interrupt_mask |= AR5K_INT_BCN_TIMEOUT; - if (sisr2 & AR5K_SISR2_CAB_TIMEOUT) - *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; - } - - if (data & AR5K_ISR_RXDOPPLER) - *interrupt_mask |= AR5K_INT_RX_DOPPLER; - if (data & AR5K_ISR_QCBRORN) { - *interrupt_mask |= AR5K_INT_QCBRORN; - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), - AR5K_SISR3_QCBRORN); - } - if (data & AR5K_ISR_QCBRURN) { - *interrupt_mask |= AR5K_INT_QCBRURN; - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), - AR5K_SISR3_QCBRURN); - } - if (data & AR5K_ISR_QTRIG) { - *interrupt_mask |= AR5K_INT_QTRIG; - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), - AR5K_SISR4_QTRIG); - } - - if (data & AR5K_ISR_TXOK) - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), - AR5K_SISR0_QCU_TXOK); - - if (data & AR5K_ISR_TXDESC) - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), - AR5K_SISR0_QCU_TXDESC); - - if (data & AR5K_ISR_TXERR) - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), - AR5K_SISR1_QCU_TXERR); - - if (data & AR5K_ISR_TXEOL) - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), - AR5K_SISR1_QCU_TXEOL); - - if (data & AR5K_ISR_TXURN) - ah->ah_txq_isr |= AR5K_REG_MS( - ath5k_hw_reg_read(ah, AR5K_RAC_SISR2), - AR5K_SISR2_QCU_TXURN); - } else { - if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT - | AR5K_ISR_HIUERR | AR5K_ISR_DPERR))) - *interrupt_mask |= AR5K_INT_FATAL; - - /* - * 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 successful assoc + some jiffies. - interrupt_mask &= ~AR5K_INT_BMISS; - */ - } - - /* - * In case we didn't handle anything, - * print the register value. - */ - if (unlikely(*interrupt_mask == 0 && net_ratelimit())) - ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr); - - 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; - - old_mask = ah->ah_imr; - - /* - * Disable card interrupts to prevent any race conditions - * (they will be re-enabled afterwards if AR5K_INT GLOBAL - * is set again on the new mask). - */ - if (old_mask & AR5K_INT_GLOBAL) { - ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); - } - - /* - * Add additional, chipset-dependent interrupt mask flags - * and write them to the IMR (interrupt mask register). - */ - int_mask = new_mask & AR5K_INT_COMMON; - - if (ah->ah_version != AR5K_AR5210) { - /* Preserve per queue TXURN interrupt mask */ - u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) - & AR5K_SIMR2_QCU_TXURN; - - if (new_mask & AR5K_INT_FATAL) { - int_mask |= AR5K_IMR_HIUERR; - simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR - | AR5K_SIMR2_DPERR); - } - - /*Beacon Not Ready*/ - if (new_mask & AR5K_INT_BNR) - int_mask |= AR5K_INT_BNR; - - if (new_mask & AR5K_INT_TIM) - int_mask |= AR5K_IMR_TIM; - - if (new_mask & AR5K_INT_TIM) - simr2 |= AR5K_SISR2_TIM; - if (new_mask & AR5K_INT_DTIM) - simr2 |= AR5K_SISR2_DTIM; - if (new_mask & AR5K_INT_DTIM_SYNC) - simr2 |= AR5K_SISR2_DTIM_SYNC; - if (new_mask & AR5K_INT_BCN_TIMEOUT) - simr2 |= AR5K_SISR2_BCN_TIMEOUT; - if (new_mask & AR5K_INT_CAB_TIMEOUT) - simr2 |= AR5K_SISR2_CAB_TIMEOUT; - - if (new_mask & AR5K_INT_RX_DOPPLER) - int_mask |= AR5K_IMR_RXDOPPLER; - - /* Note: Per queue interrupt masks - * are set via reset_tx_queue (qcu.c) */ - ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); - ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); - - } else { - if (new_mask & AR5K_INT_FATAL) - int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT - | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); - - ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); - } - - /* If RXNOFRM interrupt is masked disable it - * by setting AR5K_RXNOFRM to zero */ - if (!(new_mask & AR5K_INT_RXNOFRM)) - ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM); - - /* Store new interrupt mask */ - ah->ah_imr = new_mask; - - /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */ - if (new_mask & AR5K_INT_GLOBAL) { - 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 deleted file mode 100644 index c0fb3b0..0000000 --- a/drivers/net/wireless/ath5k/eeprom.c +++ /dev/null @@ -1,1769 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2009 Nick Kossifidis - * Copyright (c) 2008-2009 Felix Fietkau - * - * 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_eeprom_info *ee, u16 bin, - unsigned int mode) -{ - u16 val; - - if (bin == AR5K_EEPROM_CHANNEL_DIS) - return bin; - - if (mode == AR5K_EEPROM_MODE_11A) { - if (ee->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 (ee->ee_version > AR5K_EEPROM_VERSION_3_2) - val = bin + 2300; - else - val = bin + 2400; - } - - return val; -} - -/* - * Initialize eeprom & capabilities structs - */ -static int -ath5k_eeprom_init_header(struct ath5k_hw *ah) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int ret; - u16 val; - - /* - * 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); - - /* XXX: Don't know which versions include these two */ - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); - - if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); - - if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) { - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6); - } - } - - 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; - } - - return 0; -} - - -/* - * 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_atn_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); - 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 and some mode-specific calibration data - * 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; - - ee->ee_n_piers[mode] = 0; - AR5K_EEPROM_READ(o++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - switch(mode) { - case AR5K_EEPROM_MODE_11A: - 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(o++, 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; - break; - case AR5K_EEPROM_MODE_11G: - case AR5K_EEPROM_MODE_11B: - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; - break; - } - - 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_6) - ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; - } - } - - 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_0) - goto done; - - /* Note: >= v5 have bg freq piers on another location - * so these freq piers are ignored for >= v5 (should be 0xff - * anyway) */ - switch(mode) { - case AR5K_EEPROM_MODE_11A: - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) - break; - - AR5K_EEPROM_READ(o++, val); - ee->ee_margin_tx_rx[mode] = val & 0x3f; - break; - case AR5K_EEPROM_MODE_11B: - AR5K_EEPROM_READ(o++, val); - - ee->ee_pwr_cal_b[0].freq = - ath5k_eeprom_bin2freq(ee, val & 0xff, mode); - if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS) - ee->ee_n_piers[mode]++; - - ee->ee_pwr_cal_b[1].freq = - ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); - if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS) - ee->ee_n_piers[mode]++; - - AR5K_EEPROM_READ(o++, val); - ee->ee_pwr_cal_b[2].freq = - ath5k_eeprom_bin2freq(ee, val & 0xff, mode); - if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS) - ee->ee_n_piers[mode]++; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; - break; - case AR5K_EEPROM_MODE_11G: - AR5K_EEPROM_READ(o++, val); - - ee->ee_pwr_cal_g[0].freq = - ath5k_eeprom_bin2freq(ee, val & 0xff, mode); - if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS) - ee->ee_n_piers[mode]++; - - ee->ee_pwr_cal_g[1].freq = - ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); - if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS) - ee->ee_n_piers[mode]++; - - AR5K_EEPROM_READ(o++, val); - ee->ee_turbo_max_power[mode] = val & 0x7f; - ee->ee_xr_power[mode] = (val >> 7) & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_pwr_cal_g[2].freq = - ath5k_eeprom_bin2freq(ee, val & 0xff, mode); - if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS) - ee->ee_n_piers[mode]++; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; - - AR5K_EEPROM_READ(o++, 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(o++, val); - ee->ee_cck_ofdm_gain_delta = val & 0xff; - } - break; - } - -done: - /* return new offset */ - *offset = o; - - return 0; -} - -/* - * Read turbo mode information on newer EEPROM versions - */ -static int -ath5k_eeprom_read_turbo_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; - - if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) - return 0; - - switch (mode){ - case AR5K_EEPROM_MODE_11A: - ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; - - ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7; - AR5K_EEPROM_READ(o++, val); - ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3; - ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f; - - ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f; - AR5K_EEPROM_READ(o++, val); - ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7; - ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff; - - if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2) - ee->ee_pd_gain_overlap = (val >> 9) & 0xf; - break; - case AR5K_EEPROM_MODE_11G: - ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f; - - ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7; - AR5K_EEPROM_READ(o++, val); - ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1; - ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f; - - ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f; - AR5K_EEPROM_READ(o++, val); - ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5; - ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff; - break; - } - - /* return new offset */ - *offset = o; - - return 0; -} - -/* Read mode-specific data (except power calibration data) */ -static int -ath5k_eeprom_init_modes(struct ath5k_hw *ah) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 mode_offset[3]; - unsigned int mode; - u32 offset; - int ret; - - /* - * Get values for all modes - */ - mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); - mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); - mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); - - ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] = - AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); - - for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { - offset = mode_offset[mode]; - - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; - - ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); - if (ret) - return ret; - } - - /* override for older eeprom versions for better performance */ - if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) { - ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15; - ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28; - ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28; - } - - return 0; -} - -/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff - * frequency mask) */ -static inline int -ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, - struct ath5k_chan_pcal_info *pc, unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int o = *offset; - int i = 0; - u8 freq1, freq2; - int ret; - u16 val; - - ee->ee_n_piers[mode] = 0; - while(i < max) { - AR5K_EEPROM_READ(o++, val); - - freq1 = val & 0xff; - if (!freq1) - break; - - pc[i++].freq = ath5k_eeprom_bin2freq(ee, - freq1, mode); - ee->ee_n_piers[mode]++; - - freq2 = (val >> 8) & 0xff; - if (!freq2) - break; - - pc[i++].freq = ath5k_eeprom_bin2freq(ee, - freq2, mode); - ee->ee_n_piers[mode]++; - } - - /* return new offset */ - *offset = o; - - return 0; -} - -/* Read frequency piers for 802.11a */ -static int -ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; - int i, ret; - u16 val; - u8 mask; - - if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { - ath5k_eeprom_read_freq_list(ah, &offset, - AR5K_EEPROM_N_5GHZ_CHAN, pcal, - AR5K_EEPROM_MODE_11A); - } else { - mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); - - AR5K_EEPROM_READ(offset++, val); - pcal[0].freq = (val >> 9) & mask; - pcal[1].freq = (val >> 2) & mask; - pcal[2].freq = (val << 5) & mask; - - AR5K_EEPROM_READ(offset++, val); - pcal[2].freq |= (val >> 11) & 0x1f; - pcal[3].freq = (val >> 4) & mask; - pcal[4].freq = (val << 3) & mask; - - AR5K_EEPROM_READ(offset++, val); - pcal[4].freq |= (val >> 13) & 0x7; - pcal[5].freq = (val >> 6) & mask; - pcal[6].freq = (val << 1) & mask; - - AR5K_EEPROM_READ(offset++, val); - pcal[6].freq |= (val >> 15) & 0x1; - pcal[7].freq = (val >> 8) & mask; - pcal[8].freq = (val >> 1) & mask; - pcal[9].freq = (val << 6) & mask; - - AR5K_EEPROM_READ(offset++, val); - pcal[9].freq |= (val >> 10) & 0x3f; - - /* Fixed number of piers */ - ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; - - for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) { - pcal[i].freq = ath5k_eeprom_bin2freq(ee, - pcal[i].freq, AR5K_EEPROM_MODE_11A); - } - } - - return 0; -} - -/* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */ -static inline int -ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *pcal; - - switch(mode) { - case AR5K_EEPROM_MODE_11B: - pcal = ee->ee_pwr_cal_b; - break; - case AR5K_EEPROM_MODE_11G: - pcal = ee->ee_pwr_cal_g; - break; - default: - return -EINVAL; - } - - ath5k_eeprom_read_freq_list(ah, &offset, - AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, - mode); - - return 0; -} - -/* - * Read power calibration for RF5111 chips - * - * For RF5111 we have an XPD -eXternal Power Detector- curve - * for each calibrated channel. Each curve has 0,5dB Power steps - * on x axis and PCDAC steps (offsets) on y axis and looks like an - * exponential function. To recreate the curve we read 11 points - * here and interpolate later. - */ - -/* Used to match PCDAC steps with power values on RF5111 chips - * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC - * steps that match with the power values we read from eeprom. On - * older eeprom versions (< 3.2) these steps are equaly spaced at - * 10% of the pcdac curve -until the curve reaches it's maximum- - * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) - * these 11 steps are spaced in a different way. This function returns - * the pcdac steps based on eeprom version and curve min/max so that we - * can have pcdac/pwr points. - */ -static inline void -ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) -{ - const static u16 intercepts3[] = - { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; - const static u16 intercepts3_2[] = - { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; - const u16 *ip; - int i; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) - ip = intercepts3_2; - else - ip = intercepts3; - - for (i = 0; i < ARRAY_SIZE(intercepts3); i++) - vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; -} - -/* Convert RF5111 specific data to generic raw data - * used by interpolation code */ -static int -ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, - struct ath5k_chan_pcal_info *chinfo) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info_rf5111 *pcinfo; - struct ath5k_pdgain_info *pd; - u8 pier, point, idx; - u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; - - /* Fill raw data for each calibration pier */ - for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { - - pcinfo = &chinfo[pier].rf5111_info; - - /* Allocate pd_curves for this cal pier */ - chinfo[pier].pd_curves = - kcalloc(AR5K_EEPROM_N_PD_CURVES, - sizeof(struct ath5k_pdgain_info), - GFP_KERNEL); - - if (!chinfo[pier].pd_curves) - return -ENOMEM; - - /* Only one curve for RF5111 - * find out which one and place - * in in pd_curves. - * Note: ee_x_gain is reversed here */ - for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) { - - if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) { - pdgain_idx[0] = idx; - break; - } - } - - ee->ee_pd_gains[mode] = 1; - - pd = &chinfo[pier].pd_curves[idx]; - - pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111; - - /* Allocate pd points for this curve */ - pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, - sizeof(u8), GFP_KERNEL); - if (!pd->pd_step) - return -ENOMEM; - - pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, - sizeof(s16), GFP_KERNEL); - if (!pd->pd_pwr) - return -ENOMEM; - - /* Fill raw dataset - * (convert power to 0.25dB units - * for RF5112 combatibility) */ - for (point = 0; point < pd->pd_points; point++) { - - /* Absolute values */ - pd->pd_pwr[point] = 2 * pcinfo->pwr[point]; - - /* Already sorted */ - pd->pd_step[point] = pcinfo->pcdac[point]; - } - - /* Set min/max pwr */ - chinfo[pier].min_pwr = pd->pd_pwr[0]; - chinfo[pier].max_pwr = pd->pd_pwr[10]; - - } - - return 0; -} - -/* Parse EEPROM data */ -static int -ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *pcal; - int offset, ret; - int i; - u16 val; - - offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); - switch(mode) { - case AR5K_EEPROM_MODE_11A: - if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) - return 0; - - ret = ath5k_eeprom_init_11a_pcal_freq(ah, - offset + AR5K_EEPROM_GROUP1_OFFSET); - if (ret < 0) - return ret; - - offset += AR5K_EEPROM_GROUP2_OFFSET; - pcal = ee->ee_pwr_cal_a; - break; - case AR5K_EEPROM_MODE_11B: - if (!AR5K_EEPROM_HDR_11B(ee->ee_header) && - !AR5K_EEPROM_HDR_11G(ee->ee_header)) - return 0; - - pcal = ee->ee_pwr_cal_b; - offset += AR5K_EEPROM_GROUP3_OFFSET; - - /* fixed piers */ - pcal[0].freq = 2412; - pcal[1].freq = 2447; - pcal[2].freq = 2484; - ee->ee_n_piers[mode] = 3; - break; - case AR5K_EEPROM_MODE_11G: - if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) - return 0; - - pcal = ee->ee_pwr_cal_g; - offset += AR5K_EEPROM_GROUP4_OFFSET; - - /* fixed piers */ - pcal[0].freq = 2312; - pcal[1].freq = 2412; - pcal[2].freq = 2484; - ee->ee_n_piers[mode] = 3; - break; - default: - return -EINVAL; - } - - for (i = 0; i < ee->ee_n_piers[mode]; i++) { - struct ath5k_chan_pcal_info_rf5111 *cdata = - &pcal[i].rf5111_info; - - AR5K_EEPROM_READ(offset++, val); - cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M); - cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M); - cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M); - - AR5K_EEPROM_READ(offset++, val); - cdata->pwr[0] |= ((val >> 14) & 0x3); - cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M); - cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M); - cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M); - - AR5K_EEPROM_READ(offset++, val); - cdata->pwr[3] |= ((val >> 12) & 0xf); - cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M); - cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M); - - AR5K_EEPROM_READ(offset++, val); - cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M); - cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M); - cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M); - - AR5K_EEPROM_READ(offset++, val); - cdata->pwr[8] |= ((val >> 14) & 0x3); - cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M); - cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M); - - ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min, - cdata->pcdac_max, cdata->pcdac); - } - - return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal); -} - - -/* - * Read power calibration for RF5112 chips - * - * For RF5112 we have 4 XPD -eXternal Power Detector- curves - * for each calibrated channel on 0, -6, -12 and -18dbm but we only - * use the higher (3) and the lower (0) curves. Each curve has 0.5dB - * power steps on x axis and PCDAC steps on y axis and looks like a - * linear function. To recreate the curve and pass the power values - * on hw, we read 4 points for xpd 0 (lower gain -> max power) - * and 3 points for xpd 3 (higher gain -> lower power) here and - * interpolate later. - * - * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. - */ - -/* Convert RF5112 specific data to generic raw data - * used by interpolation code */ -static int -ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, - struct ath5k_chan_pcal_info *chinfo) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info_rf5112 *pcinfo; - u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; - unsigned int pier, pdg, point; - - /* Fill raw data for each calibration pier */ - for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { - - pcinfo = &chinfo[pier].rf5112_info; - - /* Allocate pd_curves for this cal pier */ - chinfo[pier].pd_curves = - kcalloc(AR5K_EEPROM_N_PD_CURVES, - sizeof(struct ath5k_pdgain_info), - GFP_KERNEL); - - if (!chinfo[pier].pd_curves) - return -ENOMEM; - - /* Fill pd_curves */ - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { - - u8 idx = pdgain_idx[pdg]; - struct ath5k_pdgain_info *pd = - &chinfo[pier].pd_curves[idx]; - - /* Lowest gain curve (max power) */ - if (pdg == 0) { - /* One more point for better accuracy */ - pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS; - - /* Allocate pd points for this curve */ - pd->pd_step = kcalloc(pd->pd_points, - sizeof(u8), GFP_KERNEL); - - if (!pd->pd_step) - return -ENOMEM; - - pd->pd_pwr = kcalloc(pd->pd_points, - sizeof(s16), GFP_KERNEL); - - if (!pd->pd_pwr) - return -ENOMEM; - - - /* Fill raw dataset - * (all power levels are in 0.25dB units) */ - pd->pd_step[0] = pcinfo->pcdac_x0[0]; - pd->pd_pwr[0] = pcinfo->pwr_x0[0]; - - for (point = 1; point < pd->pd_points; - point++) { - /* Absolute values */ - pd->pd_pwr[point] = - pcinfo->pwr_x0[point]; - - /* Deltas */ - pd->pd_step[point] = - pd->pd_step[point - 1] + - pcinfo->pcdac_x0[point]; - } - - /* Set min power for this frequency */ - chinfo[pier].min_pwr = pd->pd_pwr[0]; - - /* Highest gain curve (min power) */ - } else if (pdg == 1) { - - pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS; - - /* Allocate pd points for this curve */ - pd->pd_step = kcalloc(pd->pd_points, - sizeof(u8), GFP_KERNEL); - - if (!pd->pd_step) - return -ENOMEM; - - pd->pd_pwr = kcalloc(pd->pd_points, - sizeof(s16), GFP_KERNEL); - - if (!pd->pd_pwr) - return -ENOMEM; - - /* Fill raw dataset - * (all power levels are in 0.25dB units) */ - for (point = 0; point < pd->pd_points; - point++) { - /* Absolute values */ - pd->pd_pwr[point] = - pcinfo->pwr_x3[point]; - - /* Fixed points */ - pd->pd_step[point] = - pcinfo->pcdac_x3[point]; - } - - /* Since we have a higher gain curve - * override min power */ - chinfo[pier].min_pwr = pd->pd_pwr[0]; - } - } - } - - return 0; -} - -/* Parse EEPROM data */ -static int -ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; - struct ath5k_chan_pcal_info *gen_chan_info; - u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; - u32 offset; - u8 i, c; - u16 val; - int ret; - u8 pd_gains = 0; - - /* Count how many curves we have and - * identify them (which one of the 4 - * available curves we have on each count). - * Curves are stored from lower (x0) to - * higher (x3) gain */ - for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) { - /* ee_x_gain[mode] is x gain mask */ - if ((ee->ee_x_gain[mode] >> i) & 0x1) - pdgain_idx[pd_gains++] = i; - } - ee->ee_pd_gains[mode] = pd_gains; - - if (pd_gains == 0 || pd_gains > 2) - return -EINVAL; - - switch (mode) { - case AR5K_EEPROM_MODE_11A: - /* - * Read 5GHz EEPROM channels - */ - offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); - ath5k_eeprom_init_11a_pcal_freq(ah, offset); - - offset += AR5K_EEPROM_GROUP2_OFFSET; - gen_chan_info = ee->ee_pwr_cal_a; - break; - case AR5K_EEPROM_MODE_11B: - offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); - if (AR5K_EEPROM_HDR_11A(ee->ee_header)) - offset += AR5K_EEPROM_GROUP3_OFFSET; - - /* NB: frequency piers parsed during mode init */ - gen_chan_info = ee->ee_pwr_cal_b; - break; - case AR5K_EEPROM_MODE_11G: - offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); - if (AR5K_EEPROM_HDR_11A(ee->ee_header)) - offset += AR5K_EEPROM_GROUP4_OFFSET; - else if (AR5K_EEPROM_HDR_11B(ee->ee_header)) - offset += AR5K_EEPROM_GROUP2_OFFSET; - - /* NB: frequency piers parsed during mode init */ - gen_chan_info = ee->ee_pwr_cal_g; - break; - default: - return -EINVAL; - } - - for (i = 0; i < ee->ee_n_piers[mode]; i++) { - chan_pcal_info = &gen_chan_info[i].rf5112_info; - - /* Power values in quarter dB - * for the lower xpd gain curve - * (0 dBm -> higher output power) */ - for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { - AR5K_EEPROM_READ(offset++, val); - chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff); - chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff); - } - - /* PCDAC steps - * corresponding to the above power - * measurements */ - AR5K_EEPROM_READ(offset++, val); - chan_pcal_info->pcdac_x0[1] = (val & 0x1f); - chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); - chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); - - /* Power values in quarter dB - * for the higher xpd gain curve - * (18 dBm -> lower output power) */ - AR5K_EEPROM_READ(offset++, val); - chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff); - chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff); - - AR5K_EEPROM_READ(offset++, val); - chan_pcal_info->pwr_x3[2] = (val & 0xff); - - /* PCDAC steps - * corresponding to the above power - * measurements (fixed) */ - chan_pcal_info->pcdac_x3[0] = 20; - chan_pcal_info->pcdac_x3[1] = 35; - chan_pcal_info->pcdac_x3[2] = 63; - - if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { - chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f); - - /* Last xpd0 power level is also channel maximum */ - gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; - } else { - chan_pcal_info->pcdac_x0[0] = 1; - gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff); - } - - } - - return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info); -} - - -/* - * Read power calibration for RF2413 chips - * - * For RF2413 we have a Power to PDDAC table (Power Detector) - * instead of a PCDAC and 4 pd gain curves for each calibrated channel. - * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y - * axis and looks like an exponential function like the RF5111 curve. - * - * To recreate the curves we read here the points and interpolate - * later. Note that in most cases only 2 (higher and lower) curves are - * used (like RF5112) but vendors have the oportunity to include all - * 4 curves on eeprom. The final curve (higher power) has an extra - * point for better accuracy like RF5112. - */ - -/* For RF2413 power calibration data doesn't start on a fixed location and - * if a mode is not supported, it's section is missing -not zeroed-. - * So we need to calculate the starting offset for each section by using - * these two functions */ - -/* Return the size of each section based on the mode and the number of pd - * gains available (maximum 4). */ -static inline unsigned int -ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) -{ - static const unsigned int pdgains_size[] = { 4, 6, 9, 12 }; - unsigned int sz; - - sz = pdgains_size[ee->ee_pd_gains[mode] - 1]; - sz *= ee->ee_n_piers[mode]; - - return sz; -} - -/* Return the starting offset for a section based on the modes supported - * and each section's size. */ -static unsigned int -ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) -{ - u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4); - - switch(mode) { - case AR5K_EEPROM_MODE_11G: - if (AR5K_EEPROM_HDR_11B(ee->ee_header)) - offset += ath5k_pdgains_size_2413(ee, - AR5K_EEPROM_MODE_11B) + - AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; - /* fall through */ - case AR5K_EEPROM_MODE_11B: - if (AR5K_EEPROM_HDR_11A(ee->ee_header)) - offset += ath5k_pdgains_size_2413(ee, - AR5K_EEPROM_MODE_11A) + - AR5K_EEPROM_N_5GHZ_CHAN / 2; - /* fall through */ - case AR5K_EEPROM_MODE_11A: - break; - default: - break; - } - - return offset; -} - -/* Convert RF2413 specific data to generic raw data - * used by interpolation code */ -static int -ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, - struct ath5k_chan_pcal_info *chinfo) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info_rf2413 *pcinfo; - u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; - unsigned int pier, pdg, point; - - /* Fill raw data for each calibration pier */ - for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { - - pcinfo = &chinfo[pier].rf2413_info; - - /* Allocate pd_curves for this cal pier */ - chinfo[pier].pd_curves = - kcalloc(AR5K_EEPROM_N_PD_CURVES, - sizeof(struct ath5k_pdgain_info), - GFP_KERNEL); - - if (!chinfo[pier].pd_curves) - return -ENOMEM; - - /* Fill pd_curves */ - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { - - u8 idx = pdgain_idx[pdg]; - struct ath5k_pdgain_info *pd = - &chinfo[pier].pd_curves[idx]; - - /* One more point for the highest power - * curve (lowest gain) */ - if (pdg == ee->ee_pd_gains[mode] - 1) - pd->pd_points = AR5K_EEPROM_N_PD_POINTS; - else - pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1; - - /* Allocate pd points for this curve */ - pd->pd_step = kcalloc(pd->pd_points, - sizeof(u8), GFP_KERNEL); - - if (!pd->pd_step) - return -ENOMEM; - - pd->pd_pwr = kcalloc(pd->pd_points, - sizeof(s16), GFP_KERNEL); - - if (!pd->pd_pwr) - return -ENOMEM; - - /* Fill raw dataset - * convert all pwr levels to - * quarter dB for RF5112 combatibility */ - pd->pd_step[0] = pcinfo->pddac_i[pdg]; - pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg]; - - for (point = 1; point < pd->pd_points; point++) { - - pd->pd_pwr[point] = pd->pd_pwr[point - 1] + - 2 * pcinfo->pwr[pdg][point - 1]; - - pd->pd_step[point] = pd->pd_step[point - 1] + - pcinfo->pddac[pdg][point - 1]; - - } - - /* Highest gain curve -> min power */ - if (pdg == 0) - chinfo[pier].min_pwr = pd->pd_pwr[0]; - - /* Lowest gain curve -> max power */ - if (pdg == ee->ee_pd_gains[mode] - 1) - chinfo[pier].max_pwr = - pd->pd_pwr[pd->pd_points - 1]; - } - } - - return 0; -} - -/* Parse EEPROM data */ -static int -ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info_rf2413 *pcinfo; - struct ath5k_chan_pcal_info *chinfo; - u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; - u32 offset; - int idx, i, ret; - u16 val; - u8 pd_gains = 0; - - /* Count how many curves we have and - * identify them (which one of the 4 - * available curves we have on each count). - * Curves are stored from higher to - * lower gain so we go backwards */ - for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) { - /* ee_x_gain[mode] is x gain mask */ - if ((ee->ee_x_gain[mode] >> idx) & 0x1) - pdgain_idx[pd_gains++] = idx; - - } - ee->ee_pd_gains[mode] = pd_gains; - - if (pd_gains == 0) - return -EINVAL; - - offset = ath5k_cal_data_offset_2413(ee, mode); - switch (mode) { - case AR5K_EEPROM_MODE_11A: - if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) - return 0; - - ath5k_eeprom_init_11a_pcal_freq(ah, offset); - offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; - chinfo = ee->ee_pwr_cal_a; - break; - case AR5K_EEPROM_MODE_11B: - if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) - return 0; - - ath5k_eeprom_init_11bg_2413(ah, mode, offset); - offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; - chinfo = ee->ee_pwr_cal_b; - break; - case AR5K_EEPROM_MODE_11G: - if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) - return 0; - - ath5k_eeprom_init_11bg_2413(ah, mode, offset); - offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; - chinfo = ee->ee_pwr_cal_g; - break; - default: - return -EINVAL; - } - - for (i = 0; i < ee->ee_n_piers[mode]; i++) { - pcinfo = &chinfo[i].rf2413_info; - - /* - * Read pwr_i, pddac_i and the first - * 2 pd points (pwr, pddac) - */ - AR5K_EEPROM_READ(offset++, val); - pcinfo->pwr_i[0] = val & 0x1f; - pcinfo->pddac_i[0] = (val >> 5) & 0x7f; - pcinfo->pwr[0][0] = (val >> 12) & 0xf; - - AR5K_EEPROM_READ(offset++, val); - pcinfo->pddac[0][0] = val & 0x3f; - pcinfo->pwr[0][1] = (val >> 6) & 0xf; - pcinfo->pddac[0][1] = (val >> 10) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); - pcinfo->pwr[0][2] = val & 0xf; - pcinfo->pddac[0][2] = (val >> 4) & 0x3f; - - pcinfo->pwr[0][3] = 0; - pcinfo->pddac[0][3] = 0; - - if (pd_gains > 1) { - /* - * Pd gain 0 is not the last pd gain - * so it only has 2 pd points. - * Continue wih pd gain 1. - */ - pcinfo->pwr_i[1] = (val >> 10) & 0x1f; - - pcinfo->pddac_i[1] = (val >> 15) & 0x1; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pddac_i[1] |= (val & 0x3F) << 1; - - pcinfo->pwr[1][0] = (val >> 6) & 0xf; - pcinfo->pddac[1][0] = (val >> 10) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); - pcinfo->pwr[1][1] = val & 0xf; - pcinfo->pddac[1][1] = (val >> 4) & 0x3f; - pcinfo->pwr[1][2] = (val >> 10) & 0xf; - - pcinfo->pddac[1][2] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pddac[1][2] |= (val & 0xF) << 2; - - pcinfo->pwr[1][3] = 0; - pcinfo->pddac[1][3] = 0; - } else if (pd_gains == 1) { - /* - * Pd gain 0 is the last one so - * read the extra point. - */ - pcinfo->pwr[0][3] = (val >> 10) & 0xf; - - pcinfo->pddac[0][3] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pddac[0][3] |= (val & 0xF) << 2; - } - - /* - * Proceed with the other pd_gains - * as above. - */ - if (pd_gains > 2) { - pcinfo->pwr_i[2] = (val >> 4) & 0x1f; - pcinfo->pddac_i[2] = (val >> 9) & 0x7f; - - AR5K_EEPROM_READ(offset++, val); - pcinfo->pwr[2][0] = (val >> 0) & 0xf; - pcinfo->pddac[2][0] = (val >> 4) & 0x3f; - pcinfo->pwr[2][1] = (val >> 10) & 0xf; - - pcinfo->pddac[2][1] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pddac[2][1] |= (val & 0xF) << 2; - - pcinfo->pwr[2][2] = (val >> 4) & 0xf; - pcinfo->pddac[2][2] = (val >> 8) & 0x3f; - - pcinfo->pwr[2][3] = 0; - pcinfo->pddac[2][3] = 0; - } else if (pd_gains == 2) { - pcinfo->pwr[1][3] = (val >> 4) & 0xf; - pcinfo->pddac[1][3] = (val >> 8) & 0x3f; - } - - if (pd_gains > 3) { - pcinfo->pwr_i[3] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; - - pcinfo->pddac_i[3] = (val >> 3) & 0x7f; - pcinfo->pwr[3][0] = (val >> 10) & 0xf; - pcinfo->pddac[3][0] = (val >> 14) & 0x3; - - AR5K_EEPROM_READ(offset++, val); - pcinfo->pddac[3][0] |= (val & 0xF) << 2; - pcinfo->pwr[3][1] = (val >> 4) & 0xf; - pcinfo->pddac[3][1] = (val >> 8) & 0x3f; - - pcinfo->pwr[3][2] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; - - pcinfo->pddac[3][2] = (val >> 2) & 0x3f; - pcinfo->pwr[3][3] = (val >> 8) & 0xf; - - pcinfo->pddac[3][3] = (val >> 12) & 0xF; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; - } else if (pd_gains == 3) { - pcinfo->pwr[2][3] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); - pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; - - pcinfo->pddac[2][3] = (val >> 2) & 0x3f; - } - } - - return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo); -} - - -/* - * Read per rate target power (this is the maximum tx power - * supported by the card). This info is used when setting - * tx power, no matter the channel. - * - * This also works for v5 EEPROMs. - */ -static int -ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_rate_pcal_info *rate_pcal_info; - u8 *rate_target_pwr_num; - u32 offset; - u16 val; - int ret, i; - - offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); - rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; - switch (mode) { - case AR5K_EEPROM_MODE_11A: - offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); - rate_pcal_info = ee->ee_rate_tpwr_a; - ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN; - break; - case AR5K_EEPROM_MODE_11B: - offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); - rate_pcal_info = ee->ee_rate_tpwr_b; - ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */ - break; - case AR5K_EEPROM_MODE_11G: - offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version); - rate_pcal_info = ee->ee_rate_tpwr_g; - ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN; - break; - default: - return -EINVAL; - } - - /* Different freq mask for older eeproms (<= v3.2) */ - if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) { - for (i = 0; i < (*rate_target_pwr_num); i++) { - AR5K_EEPROM_READ(offset++, val); - rate_pcal_info[i].freq = - ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode); - - rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f); - rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); - - if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || - val == 0) { - (*rate_target_pwr_num) = i; - break; - } - - rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7); - rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f); - rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f); - } - } else { - for (i = 0; i < (*rate_target_pwr_num); i++) { - AR5K_EEPROM_READ(offset++, val); - rate_pcal_info[i].freq = - ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); - - rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f); - rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); - - if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || - val == 0) { - (*rate_target_pwr_num) = i; - break; - } - - rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf; - rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f); - rate_pcal_info[i].target_power_54 = (val & 0x3f); - } - } - - return 0; -} - -/* - * Read per channel calibration info from EEPROM - * - * This info is used to calibrate the baseband power table. Imagine - * that for each channel there is a power curve that's hw specific - * (depends on amplifier etc) and we try to "correct" this curve using - * offests we pass on to phy chip (baseband -> before amplifier) so that - * it can use accurate power values when setting tx power (takes amplifier's - * performance on each channel into account). - * - * EEPROM provides us with the offsets for some pre-calibrated channels - * and we have to interpolate to create the full table for these channels and - * also the table for any channel. - */ -static int -ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int (*read_pcal)(struct ath5k_hw *hw, int mode); - int mode; - int err; - - if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) && - (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1)) - read_pcal = ath5k_eeprom_read_pcal_info_5112; - else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) && - (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2)) - read_pcal = ath5k_eeprom_read_pcal_info_2413; - else - read_pcal = ath5k_eeprom_read_pcal_info_5111; - - - for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; - mode++) { - err = read_pcal(ah, mode); - if (err) - return err; - - err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode); - if (err < 0) - return err; - } - - return 0; -} - -static int -ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *chinfo; - u8 pier, pdg; - - switch (mode) { - case AR5K_EEPROM_MODE_11A: - if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_a; - break; - case AR5K_EEPROM_MODE_11B: - if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_b; - break; - case AR5K_EEPROM_MODE_11G: - if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_g; - break; - default: - return -EINVAL; - } - - for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { - if (!chinfo[pier].pd_curves) - continue; - - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { - struct ath5k_pdgain_info *pd = - &chinfo[pier].pd_curves[pdg]; - - if (pd != NULL) { - kfree(pd->pd_step); - kfree(pd->pd_pwr); - } - } - - kfree(chinfo[pier].pd_curves); - } - - return 0; -} - -void -ath5k_eeprom_detach(struct ath5k_hw *ah) -{ - u8 mode; - - for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) - ath5k_eeprom_free_pcal_info(ah, mode); -} - -/* Read conformance test limits used for regulatory control */ -static int -ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_edge_power *rep; - unsigned int fmask, pmask; - unsigned int ctl_mode; - int ret, i, j; - u32 offset; - u16 val; - - pmask = AR5K_EEPROM_POWER_M; - fmask = AR5K_EEPROM_FREQ_M(ee->ee_version); - offset = AR5K_EEPROM_CTL(ee->ee_version); - ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version); - for (i = 0; i < ee->ee_ctls; i += 2) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_ctl[i] = (val >> 8) & 0xff; - ee->ee_ctl[i + 1] = val & 0xff; - } - - offset = AR5K_EEPROM_GROUP8_OFFSET; - if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) - offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) - - AR5K_EEPROM_GROUP5_OFFSET; - else - offset += AR5K_EEPROM_GROUPS_START(ee->ee_version); - - rep = ee->ee_ctl_pwr; - for(i = 0; i < ee->ee_ctls; i++) { - switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) { - case AR5K_CTL_11A: - case AR5K_CTL_TURBO: - ctl_mode = AR5K_EEPROM_MODE_11A; - break; - default: - ctl_mode = AR5K_EEPROM_MODE_11G; - break; - } - if (ee->ee_ctl[i] == 0) { - if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) - offset += 8; - else - offset += 7; - rep += AR5K_EEPROM_N_EDGES; - continue; - } - if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { - for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { - AR5K_EEPROM_READ(offset++, val); - rep[j].freq = (val >> 8) & fmask; - rep[j + 1].freq = val & fmask; - } - for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { - AR5K_EEPROM_READ(offset++, val); - rep[j].edge = (val >> 8) & pmask; - rep[j].flag = (val >> 14) & 1; - rep[j + 1].edge = val & pmask; - rep[j + 1].flag = (val >> 6) & 1; - } - } else { - AR5K_EEPROM_READ(offset++, val); - rep[0].freq = (val >> 9) & fmask; - rep[1].freq = (val >> 2) & fmask; - rep[2].freq = (val << 5) & fmask; - - AR5K_EEPROM_READ(offset++, val); - rep[2].freq |= (val >> 11) & 0x1f; - rep[3].freq = (val >> 4) & fmask; - rep[4].freq = (val << 3) & fmask; - - AR5K_EEPROM_READ(offset++, val); - rep[4].freq |= (val >> 13) & 0x7; - rep[5].freq = (val >> 6) & fmask; - rep[6].freq = (val << 1) & fmask; - - AR5K_EEPROM_READ(offset++, val); - rep[6].freq |= (val >> 15) & 0x1; - rep[7].freq = (val >> 8) & fmask; - - rep[0].edge = (val >> 2) & pmask; - rep[1].edge = (val << 4) & pmask; - - AR5K_EEPROM_READ(offset++, val); - rep[1].edge |= (val >> 12) & 0xf; - rep[2].edge = (val >> 6) & pmask; - rep[3].edge = val & pmask; - - AR5K_EEPROM_READ(offset++, val); - rep[4].edge = (val >> 10) & pmask; - rep[5].edge = (val >> 4) & pmask; - rep[6].edge = (val << 2) & pmask; - - AR5K_EEPROM_READ(offset++, val); - rep[6].edge |= (val >> 14) & 0x3; - rep[7].edge = (val >> 8) & pmask; - } - for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) { - rep[j].freq = ath5k_eeprom_bin2freq(ee, - rep[j].freq, ctl_mode); - } - rep += AR5K_EEPROM_N_EDGES; - } - - return 0; -} - - -/* - * Initialize eeprom power tables - */ -int -ath5k_eeprom_init(struct ath5k_hw *ah) -{ - int err; - - err = ath5k_eeprom_init_header(ah); - if (err < 0) - return err; - - err = ath5k_eeprom_init_modes(ah); - if (err < 0) - return err; - - err = ath5k_eeprom_read_pcal_info(ah); - if (err < 0) - return err; - - err = ath5k_eeprom_read_ctl_info(ah); - if (err < 0) - return err; - - 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; - - 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; - } - - if (!total || total == 3 * 0xffff) - return -EINVAL; - - memcpy(mac, mac_d, ETH_ALEN); - - return 0; -} - -bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah) -{ - u16 data; - - ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data); - - if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data) - return true; - else - return false; -} - diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h deleted file mode 100644 index b0c0606..0000000 --- a/drivers/net/wireless/ath5k/eeprom.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * - * 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_IS_HB63 0x000b /* Talon detect */ -#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ -#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ -#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 /* power calibration changes */ -#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 0x3007 /* 4007 ? */ -#define AR5K_EEPROM_VERSION_4_9 0x4009 /* EAR futureproofing */ -#define AR5K_EEPROM_VERSION_5_0 0x5000 /* Has 2413 PDADC calibration etc */ -#define AR5K_EEPROM_VERSION_5_1 0x5001 /* Has capability values */ -#define AR5K_EEPROM_VERSION_5_3 0x5003 /* Has spur mitigation tables */ - -#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_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ -#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ - -#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) ((s8)(((_v) >> 8) & 0xff)) -#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((s8)((_v) & 0xff)) - -/* Misc values available since EEPROM 4.0 */ -#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4) -#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1) -#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1) -#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) - -#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5) -#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) -#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1) - -#define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6) -#define AR5K_EEPROM_EEP_FILE_VERSION(_v) (((_v) >> 8) & 0xff) -#define AR5K_EEPROM_EAR_FILE_VERSION(_v) ((_v) & 0xff) - -#define AR5K_EEPROM_MISC3 AR5K_EEPROM_INFO(7) -#define AR5K_EEPROM_ART_BUILD_NUM(_v) (((_v) >> 10) & 0x3f) -#define AR5K_EEPROM_EAR_FILE_ID(_v) ((_v) & 0xff) - -#define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8) -#define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff) -#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3) -#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3) - -#define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9) -#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1) -#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1) -#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1) -#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1) -#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf) -#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1) -#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf) - -#define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10) -#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8) -#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8) -#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1) -#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1) -#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1) -#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1) -#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1) - -/* 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 */ -#define AR5K_EEPROM_GROUPS_START(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* Start of Groups */ -#define AR5K_EEPROM_GROUP1_OFFSET 0x0 -#define AR5K_EEPROM_GROUP2_OFFSET 0x5 -#define AR5K_EEPROM_GROUP3_OFFSET 0x37 -#define AR5K_EEPROM_GROUP4_OFFSET 0x46 -#define AR5K_EEPROM_GROUP5_OFFSET 0x55 -#define AR5K_EEPROM_GROUP6_OFFSET 0x65 -#define AR5K_EEPROM_GROUP7_OFFSET 0x69 -#define AR5K_EEPROM_GROUP8_OFFSET 0x6f - -#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ - AR5K_EEPROM_GROUP5_OFFSET, 0x0000) -#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ - AR5K_EEPROM_GROUP6_OFFSET, 0x0010) -#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ - AR5K_EEPROM_GROUP7_OFFSET, 0x0014) - -/* [3.1 - 3.3] */ -#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec -#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed - -#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 - -/* 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_N_2GHZ_CHAN_2413 4 -#define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4 -#define AR5K_EEPROM_MAX_CHAN 10 -#define AR5K_EEPROM_N_PWR_POINTS_5111 11 -#define AR5K_EEPROM_N_PCDAC 11 -#define AR5K_EEPROM_N_PHASE_CAL 5 -#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_PD_CURVES 4 -#define AR5K_EEPROM_N_XPD0_POINTS 4 -#define AR5K_EEPROM_N_XPD3_POINTS 3 -#define AR5K_EEPROM_N_PD_GAINS 4 -#define AR5K_EEPROM_N_PD_POINTS 5 -#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); \ - -enum ath5k_ant_setting { - AR5K_ANT_VARIABLE = 0, /* variable by programming */ - AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ - AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ - AR5K_ANT_MAX = 3, -}; - -enum ath5k_ctl_mode { - AR5K_CTL_11A = 0, - AR5K_CTL_11B = 1, - AR5K_CTL_11G = 2, - AR5K_CTL_TURBO = 3, - AR5K_CTL_TURBOG = 4, - AR5K_CTL_2GHT20 = 5, - AR5K_CTL_5GHT20 = 6, - AR5K_CTL_2GHT40 = 7, - AR5K_CTL_5GHT40 = 8, - AR5K_CTL_MODE_M = 15, -}; - -/* Default CTL ids for the 3 main reg domains. - * Atheros only uses these by default but vendors - * can have up to 32 different CTLs for different - * scenarios. Note that theese values are ORed with - * the mode id (above) so we can have up to 24 CTL - * datasets out of these 3 main regdomains. That leaves - * 8 ids that can be used by vendors and since 0x20 is - * missing from HAL sources i guess this is the set of - * custom CTLs vendors can use. */ -#define AR5K_CTL_FCC 0x10 -#define AR5K_CTL_CUSTOM 0x20 -#define AR5K_CTL_ETSI 0x30 -#define AR5K_CTL_MKK 0x40 - -/* Indicates a CTL with only mode set and - * no reg domain mapping, such CTLs are used - * for world roaming domains or simply when - * a reg domain is not set */ -#define AR5K_CTL_NO_REGDOMAIN 0xf0 - -/* Indicates an empty (invalid) CTL */ -#define AR5K_CTL_NO_CTL 0xff - -/* Per channel calibration data, used for power table setup */ -struct ath5k_chan_pcal_info_rf5111 { - /* Power levels in half dbm units - * for one power curve. */ - u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111]; - /* PCDAC table steps - * for the above values */ - u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111]; - /* Starting PCDAC step */ - u8 pcdac_min; - /* Final PCDAC step */ - u8 pcdac_max; -}; - -struct ath5k_chan_pcal_info_rf5112 { - /* Power levels in quarter dBm units - * for lower (0) and higher (3) - * level curves in 0.25dB units */ - s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; - s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; - /* PCDAC table steps - * for the above values */ - u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; - u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; -}; - -struct ath5k_chan_pcal_info_rf2413 { - /* Starting pwr/pddac values */ - s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; - u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; - /* (pwr,pddac) points - * power levels in 0.5dB units */ - s8 pwr[AR5K_EEPROM_N_PD_GAINS] - [AR5K_EEPROM_N_PD_POINTS]; - u8 pddac[AR5K_EEPROM_N_PD_GAINS] - [AR5K_EEPROM_N_PD_POINTS]; -}; - -enum ath5k_powertable_type { - AR5K_PWRTABLE_PWR_TO_PCDAC = 0, - AR5K_PWRTABLE_LINEAR_PCDAC = 1, - AR5K_PWRTABLE_PWR_TO_PDADC = 2, -}; - -struct ath5k_pdgain_info { - u8 pd_points; - u8 *pd_step; - /* Power values are in - * 0.25dB units */ - s16 *pd_pwr; -}; - -struct ath5k_chan_pcal_info { - /* Frequency */ - u16 freq; - /* Tx power boundaries */ - s16 max_pwr; - s16 min_pwr; - union { - struct ath5k_chan_pcal_info_rf5111 rf5111_info; - struct ath5k_chan_pcal_info_rf5112 rf5112_info; - struct ath5k_chan_pcal_info_rf2413 rf2413_info; - }; - /* Raw values used by phy code - * Curves are stored in order from lower - * gain to higher gain (max txpower -> min txpower) */ - struct ath5k_pdgain_info *pd_curves; -}; - -/* Per rate calibration data for each mode, - * used for rate power table setup. - * Note: Values in 0.5dB units */ -struct ath5k_rate_pcal_info { - u16 freq; /* Frequency */ - /* Power level for 6-24Mbit/s rates or - * 1Mb rate */ - u16 target_power_6to24; - /* Power level for 36Mbit rate or - * 2Mb rate */ - u16 target_power_36; - /* Power level for 48Mbit rate or - * 5.5Mbit rate */ - u16 target_power_48; - /* Power level for 54Mbit rate or - * 11Mbit rate */ - u16 target_power_54; -}; - -/* Power edges for conformance test limits */ -struct ath5k_edge_power { - u16 freq; - u16 edge; /* in half dBm */ - bool flag; -}; - -/* EEPROM calibration data */ -struct ath5k_eeprom_info { - - /* Header information */ - 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_misc2; - u16 ee_misc3; - u16 ee_misc4; - u16 ee_misc5; - u16 ee_misc6; - u16 ee_cck_ofdm_gain_delta; - u16 ee_cck_ofdm_power_delta; - u16 ee_scaled_cck_delta; - - /* 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_atn_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]; - u16 ee_switch_settling_turbo[AR5K_EEPROM_N_MODES]; - u16 ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES]; - u16 ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES]; - - /* Power calibration data */ - u16 ee_false_detect[AR5K_EEPROM_N_MODES]; - - /* Number of pd gain curves per mode */ - u8 ee_pd_gains[AR5K_EEPROM_N_MODES]; - /* Back mapping pdcurve number -> pdcurve index in pd->pd_curves */ - u8 ee_pdc_to_idx[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PD_GAINS]; - - u8 ee_n_piers[AR5K_EEPROM_N_MODES]; - struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; - struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; - struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; - - /* Per rate target power levels */ - u8 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES]; - struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; - struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; - struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; - - /* Conformance test limits (Unused) */ - u8 ee_ctls; - u8 ee_ctl[AR5K_EEPROM_MAX_CTLS]; - struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * 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]; - s8 ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES]; - s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES]; - s8 ee_pd_gain_overlap; - - u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; -}; - diff --git a/drivers/net/wireless/ath5k/gpio.c b/drivers/net/wireless/ath5k/gpio.c deleted file mode 100644 index 64a27e7..0000000 --- a/drivers/net/wireless/ath5k/gpio.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * - * 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/initvals.c b/drivers/net/wireless/ath5k/initvals.c deleted file mode 100644 index 61fb621..0000000 --- a/drivers/net/wireless/ath5k/initvals.c +++ /dev/null @@ -1,1557 +0,0 @@ -/* - * Initial register settings functions - * - * Copyright (c) 2004-2007 Reyk Floeter - * Copyright (c) 2006-2009 Nick Kossifidis - * Copyright (c) 2007-2008 Jiri Slaby - * - * 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. - * - */ - -#include "ath5k.h" -#include "reg.h" -#include "debug.h" -#include "base.h" - -/* - * Mode-independent initial register writes - */ - -struct ath5k_ini { - u16 ini_register; - u32 ini_value; - - enum { - AR5K_INI_WRITE = 0, /* Default */ - AR5K_INI_READ = 1, /* Cleared on read */ - } ini_mode; -}; - -/* - * Mode specific initial register values - */ - -struct ath5k_ini_mode { - u16 mode_register; - u32 mode_value[5]; -}; - -/* Initial register settings for AR5210 */ -static const struct ath5k_ini ar5210_ini[] = { - /* PCU and MAC registers */ - { AR5K_NOQCU_TXDP0, 0 }, - { AR5K_NOQCU_TXDP1, 0 }, - { AR5K_RXDP, 0 }, - { AR5K_CR, 0 }, - { AR5K_ISR, 0, AR5K_INI_READ }, - { AR5K_IMR, 0 }, - { AR5K_IER, AR5K_IER_DISABLE }, - { AR5K_BSR, 0, AR5K_INI_READ }, - { AR5K_TXCFG, AR5K_DMASIZE_128B }, - { AR5K_RXCFG, AR5K_DMASIZE_128B }, - { AR5K_CFG, AR5K_INIT_CFG }, - { AR5K_TOPS, 8 }, - { AR5K_RXNOFRM, 8 }, - { AR5K_RPGTO, 0 }, - { AR5K_TXNOFRM, 0 }, - { AR5K_SFR, 0 }, - { AR5K_MIBC, 0 }, - { AR5K_MISC, 0 }, - { AR5K_RX_FILTER_5210, 0 }, - { AR5K_MCAST_FILTER0_5210, 0 }, - { AR5K_MCAST_FILTER1_5210, 0 }, - { AR5K_TX_MASK0, 0 }, - { AR5K_TX_MASK1, 0 }, - { AR5K_CLR_TMASK, 0 }, - { AR5K_TRIG_LVL, AR5K_TUNE_MIN_TX_FIFO_THRES }, - { AR5K_DIAG_SW_5210, 0 }, - { AR5K_RSSI_THR, AR5K_TUNE_RSSI_THRES }, - { AR5K_TSF_L32_5210, 0 }, - { AR5K_TIMER0_5210, 0 }, - { AR5K_TIMER1_5210, 0xffffffff }, - { AR5K_TIMER2_5210, 0xffffffff }, - { AR5K_TIMER3_5210, 1 }, - { AR5K_CFP_DUR_5210, 0 }, - { AR5K_CFP_PERIOD_5210, 0 }, - /* PHY registers */ - { AR5K_PHY(0), 0x00000047 }, - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY(3), 0x09848ea6 }, - { AR5K_PHY(4), 0x3d32e000 }, - { AR5K_PHY(5), 0x0000076b }, - { AR5K_PHY_ACT, AR5K_PHY_ACT_DISABLE }, - { AR5K_PHY(8), 0x02020200 }, - { AR5K_PHY(9), 0x00000e0e }, - { AR5K_PHY(10), 0x0a020201 }, - { AR5K_PHY(11), 0x00036ffc }, - { AR5K_PHY(12), 0x00000000 }, - { AR5K_PHY(13), 0x00000e0e }, - { AR5K_PHY(14), 0x00000007 }, - { AR5K_PHY(15), 0x00020100 }, - { AR5K_PHY(16), 0x89630000 }, - { AR5K_PHY(17), 0x1372169c }, - { AR5K_PHY(18), 0x0018b633 }, - { AR5K_PHY(19), 0x1284613c }, - { AR5K_PHY(20), 0x0de8b8e0 }, - { AR5K_PHY(21), 0x00074859 }, - { AR5K_PHY(22), 0x7e80beba }, - { AR5K_PHY(23), 0x313a665e }, - { AR5K_PHY_AGCCTL, 0x00001d08 }, - { AR5K_PHY(25), 0x0001ce00 }, - { AR5K_PHY(26), 0x409a4190 }, - { AR5K_PHY(28), 0x0000000f }, - { AR5K_PHY(29), 0x00000080 }, - { AR5K_PHY(30), 0x00000004 }, - { AR5K_PHY(31), 0x00000018 }, /* 0x987c */ - { AR5K_PHY(64), 0x00000000 }, /* 0x9900 */ - { AR5K_PHY(65), 0x00000000 }, - { AR5K_PHY(66), 0x00000000 }, - { AR5K_PHY(67), 0x00800000 }, - { AR5K_PHY(68), 0x00000003 }, - /* BB gain table (64bytes) */ - { AR5K_BB_GAIN(0), 0x00000000 }, - { AR5K_BB_GAIN(1), 0x00000020 }, - { AR5K_BB_GAIN(2), 0x00000010 }, - { AR5K_BB_GAIN(3), 0x00000030 }, - { AR5K_BB_GAIN(4), 0x00000008 }, - { AR5K_BB_GAIN(5), 0x00000028 }, - { AR5K_BB_GAIN(6), 0x00000028 }, - { AR5K_BB_GAIN(7), 0x00000004 }, - { AR5K_BB_GAIN(8), 0x00000024 }, - { AR5K_BB_GAIN(9), 0x00000014 }, - { AR5K_BB_GAIN(10), 0x00000034 }, - { AR5K_BB_GAIN(11), 0x0000000c }, - { AR5K_BB_GAIN(12), 0x0000002c }, - { AR5K_BB_GAIN(13), 0x00000002 }, - { AR5K_BB_GAIN(14), 0x00000022 }, - { AR5K_BB_GAIN(15), 0x00000012 }, - { AR5K_BB_GAIN(16), 0x00000032 }, - { AR5K_BB_GAIN(17), 0x0000000a }, - { AR5K_BB_GAIN(18), 0x0000002a }, - { AR5K_BB_GAIN(19), 0x00000001 }, - { AR5K_BB_GAIN(20), 0x00000021 }, - { AR5K_BB_GAIN(21), 0x00000011 }, - { AR5K_BB_GAIN(22), 0x00000031 }, - { AR5K_BB_GAIN(23), 0x00000009 }, - { AR5K_BB_GAIN(24), 0x00000029 }, - { AR5K_BB_GAIN(25), 0x00000005 }, - { AR5K_BB_GAIN(26), 0x00000025 }, - { AR5K_BB_GAIN(27), 0x00000015 }, - { AR5K_BB_GAIN(28), 0x00000035 }, - { AR5K_BB_GAIN(29), 0x0000000d }, - { AR5K_BB_GAIN(30), 0x0000002d }, - { AR5K_BB_GAIN(31), 0x00000003 }, - { AR5K_BB_GAIN(32), 0x00000023 }, - { AR5K_BB_GAIN(33), 0x00000013 }, - { AR5K_BB_GAIN(34), 0x00000033 }, - { AR5K_BB_GAIN(35), 0x0000000b }, - { AR5K_BB_GAIN(36), 0x0000002b }, - { AR5K_BB_GAIN(37), 0x00000007 }, - { AR5K_BB_GAIN(38), 0x00000027 }, - { AR5K_BB_GAIN(39), 0x00000017 }, - { AR5K_BB_GAIN(40), 0x00000037 }, - { AR5K_BB_GAIN(41), 0x0000000f }, - { AR5K_BB_GAIN(42), 0x0000002f }, - { AR5K_BB_GAIN(43), 0x0000002f }, - { AR5K_BB_GAIN(44), 0x0000002f }, - { AR5K_BB_GAIN(45), 0x0000002f }, - { AR5K_BB_GAIN(46), 0x0000002f }, - { AR5K_BB_GAIN(47), 0x0000002f }, - { AR5K_BB_GAIN(48), 0x0000002f }, - { AR5K_BB_GAIN(49), 0x0000002f }, - { AR5K_BB_GAIN(50), 0x0000002f }, - { AR5K_BB_GAIN(51), 0x0000002f }, - { AR5K_BB_GAIN(52), 0x0000002f }, - { AR5K_BB_GAIN(53), 0x0000002f }, - { AR5K_BB_GAIN(54), 0x0000002f }, - { AR5K_BB_GAIN(55), 0x0000002f }, - { AR5K_BB_GAIN(56), 0x0000002f }, - { AR5K_BB_GAIN(57), 0x0000002f }, - { AR5K_BB_GAIN(58), 0x0000002f }, - { AR5K_BB_GAIN(59), 0x0000002f }, - { AR5K_BB_GAIN(60), 0x0000002f }, - { AR5K_BB_GAIN(61), 0x0000002f }, - { AR5K_BB_GAIN(62), 0x0000002f }, - { AR5K_BB_GAIN(63), 0x0000002f }, - /* 5110 RF gain table (64btes) */ - { AR5K_RF_GAIN(0), 0x0000001d }, - { AR5K_RF_GAIN(1), 0x0000005d }, - { AR5K_RF_GAIN(2), 0x0000009d }, - { AR5K_RF_GAIN(3), 0x000000dd }, - { AR5K_RF_GAIN(4), 0x0000011d }, - { AR5K_RF_GAIN(5), 0x00000021 }, - { AR5K_RF_GAIN(6), 0x00000061 }, - { AR5K_RF_GAIN(7), 0x000000a1 }, - { AR5K_RF_GAIN(8), 0x000000e1 }, - { AR5K_RF_GAIN(9), 0x00000031 }, - { AR5K_RF_GAIN(10), 0x00000071 }, - { AR5K_RF_GAIN(11), 0x000000b1 }, - { AR5K_RF_GAIN(12), 0x0000001c }, - { AR5K_RF_GAIN(13), 0x0000005c }, - { AR5K_RF_GAIN(14), 0x00000029 }, - { AR5K_RF_GAIN(15), 0x00000069 }, - { AR5K_RF_GAIN(16), 0x000000a9 }, - { AR5K_RF_GAIN(17), 0x00000020 }, - { AR5K_RF_GAIN(18), 0x00000019 }, - { AR5K_RF_GAIN(19), 0x00000059 }, - { AR5K_RF_GAIN(20), 0x00000099 }, - { AR5K_RF_GAIN(21), 0x00000030 }, - { AR5K_RF_GAIN(22), 0x00000005 }, - { AR5K_RF_GAIN(23), 0x00000025 }, - { AR5K_RF_GAIN(24), 0x00000065 }, - { AR5K_RF_GAIN(25), 0x000000a5 }, - { AR5K_RF_GAIN(26), 0x00000028 }, - { AR5K_RF_GAIN(27), 0x00000068 }, - { AR5K_RF_GAIN(28), 0x0000001f }, - { AR5K_RF_GAIN(29), 0x0000001e }, - { AR5K_RF_GAIN(30), 0x00000018 }, - { AR5K_RF_GAIN(31), 0x00000058 }, - { AR5K_RF_GAIN(32), 0x00000098 }, - { AR5K_RF_GAIN(33), 0x00000003 }, - { AR5K_RF_GAIN(34), 0x00000004 }, - { AR5K_RF_GAIN(35), 0x00000044 }, - { AR5K_RF_GAIN(36), 0x00000084 }, - { AR5K_RF_GAIN(37), 0x00000013 }, - { AR5K_RF_GAIN(38), 0x00000012 }, - { AR5K_RF_GAIN(39), 0x00000052 }, - { AR5K_RF_GAIN(40), 0x00000092 }, - { AR5K_RF_GAIN(41), 0x000000d2 }, - { AR5K_RF_GAIN(42), 0x0000002b }, - { AR5K_RF_GAIN(43), 0x0000002a }, - { AR5K_RF_GAIN(44), 0x0000006a }, - { AR5K_RF_GAIN(45), 0x000000aa }, - { AR5K_RF_GAIN(46), 0x0000001b }, - { AR5K_RF_GAIN(47), 0x0000001a }, - { AR5K_RF_GAIN(48), 0x0000005a }, - { AR5K_RF_GAIN(49), 0x0000009a }, - { AR5K_RF_GAIN(50), 0x000000da }, - { AR5K_RF_GAIN(51), 0x00000006 }, - { AR5K_RF_GAIN(52), 0x00000006 }, - { AR5K_RF_GAIN(53), 0x00000006 }, - { AR5K_RF_GAIN(54), 0x00000006 }, - { AR5K_RF_GAIN(55), 0x00000006 }, - { AR5K_RF_GAIN(56), 0x00000006 }, - { AR5K_RF_GAIN(57), 0x00000006 }, - { AR5K_RF_GAIN(58), 0x00000006 }, - { AR5K_RF_GAIN(59), 0x00000006 }, - { AR5K_RF_GAIN(60), 0x00000006 }, - { AR5K_RF_GAIN(61), 0x00000006 }, - { AR5K_RF_GAIN(62), 0x00000006 }, - { AR5K_RF_GAIN(63), 0x00000006 }, - /* PHY activation */ - { AR5K_PHY(53), 0x00000020 }, - { AR5K_PHY(51), 0x00000004 }, - { AR5K_PHY(50), 0x00060106 }, - { AR5K_PHY(39), 0x0000006d }, - { AR5K_PHY(48), 0x00000000 }, - { AR5K_PHY(52), 0x00000014 }, - { AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE }, -}; - -/* Initial register settings for AR5211 */ -static const struct ath5k_ini ar5211_ini[] = { - { AR5K_RXDP, 0x00000000 }, - { AR5K_RTSD0, 0x84849c9c }, - { AR5K_RTSD1, 0x7c7c7c7c }, - { AR5K_RXCFG, 0x00000005 }, - { AR5K_MIBC, 0x00000000 }, - { AR5K_TOPS, 0x00000008 }, - { AR5K_RXNOFRM, 0x00000008 }, - { AR5K_TXNOFRM, 0x00000010 }, - { AR5K_RPGTO, 0x00000000 }, - { AR5K_RFCNT, 0x0000001f }, - { AR5K_QUEUE_TXDP(0), 0x00000000 }, - { AR5K_QUEUE_TXDP(1), 0x00000000 }, - { AR5K_QUEUE_TXDP(2), 0x00000000 }, - { AR5K_QUEUE_TXDP(3), 0x00000000 }, - { AR5K_QUEUE_TXDP(4), 0x00000000 }, - { AR5K_QUEUE_TXDP(5), 0x00000000 }, - { AR5K_QUEUE_TXDP(6), 0x00000000 }, - { AR5K_QUEUE_TXDP(7), 0x00000000 }, - { AR5K_QUEUE_TXDP(8), 0x00000000 }, - { AR5K_QUEUE_TXDP(9), 0x00000000 }, - { AR5K_DCU_FP, 0x00000000 }, - { AR5K_STA_ID1, 0x00000000 }, - { AR5K_BSS_ID0, 0x00000000 }, - { AR5K_BSS_ID1, 0x00000000 }, - { AR5K_RSSI_THR, 0x00000000 }, - { AR5K_CFP_PERIOD_5211, 0x00000000 }, - { AR5K_TIMER0_5211, 0x00000030 }, - { AR5K_TIMER1_5211, 0x0007ffff }, - { AR5K_TIMER2_5211, 0x01ffffff }, - { AR5K_TIMER3_5211, 0x00000031 }, - { AR5K_CFP_DUR_5211, 0x00000000 }, - { AR5K_RX_FILTER_5211, 0x00000000 }, - { AR5K_MCAST_FILTER0_5211, 0x00000000 }, - { AR5K_MCAST_FILTER1_5211, 0x00000002 }, - { AR5K_DIAG_SW_5211, 0x00000000 }, - { AR5K_ADDAC_TEST, 0x00000000 }, - { AR5K_DEFAULT_ANTENNA, 0x00000000 }, - /* PHY registers */ - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY(3), 0x2d849093 }, - { AR5K_PHY(4), 0x7d32e000 }, - { AR5K_PHY(5), 0x00000f6b }, - { AR5K_PHY_ACT, 0x00000000 }, - { AR5K_PHY(11), 0x00026ffe }, - { AR5K_PHY(12), 0x00000000 }, - { AR5K_PHY(15), 0x00020100 }, - { AR5K_PHY(16), 0x206a017a }, - { AR5K_PHY(19), 0x1284613c }, - { AR5K_PHY(21), 0x00000859 }, - { AR5K_PHY(26), 0x409a4190 }, /* 0x9868 */ - { AR5K_PHY(27), 0x050cb081 }, - { AR5K_PHY(28), 0x0000000f }, - { AR5K_PHY(29), 0x00000080 }, - { AR5K_PHY(30), 0x0000000c }, - { AR5K_PHY(64), 0x00000000 }, - { AR5K_PHY(65), 0x00000000 }, - { AR5K_PHY(66), 0x00000000 }, - { AR5K_PHY(67), 0x00800000 }, - { AR5K_PHY(68), 0x00000001 }, - { AR5K_PHY(71), 0x0000092a }, - { AR5K_PHY_IQ, 0x00000000 }, - { AR5K_PHY(73), 0x00058a05 }, - { AR5K_PHY(74), 0x00000001 }, - { AR5K_PHY(75), 0x00000000 }, - { AR5K_PHY_PAPD_PROBE, 0x00000000 }, - { AR5K_PHY(77), 0x00000000 }, /* 0x9934 */ - { AR5K_PHY(78), 0x00000000 }, /* 0x9938 */ - { AR5K_PHY(79), 0x0000003f }, /* 0x993c */ - { AR5K_PHY(80), 0x00000004 }, - { AR5K_PHY(82), 0x00000000 }, - { AR5K_PHY(83), 0x00000000 }, - { AR5K_PHY(84), 0x00000000 }, - { AR5K_PHY_RADAR, 0x5d50f14c }, - { AR5K_PHY(86), 0x00000018 }, - { AR5K_PHY(87), 0x004b6a8e }, - /* Initial Power table (32bytes) - * common on all cards/modes. - * Note: Table is rewritten during - * txpower setup later using calibration - * data etc. so next write is non-common */ - { AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff }, - { AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff }, - { AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff }, - { AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff }, - { AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff }, - { AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff }, - { AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff }, - { AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff }, - { AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff }, - { AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff }, - { AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff }, - { AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff }, - { AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff }, - { AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff }, - { AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff }, - { AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff }, - { AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff }, - { AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff }, - { AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff }, - { AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff }, - { AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff }, - { AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff }, - { AR5K_PHY_CCKTXCTL, 0x00000000 }, - { AR5K_PHY(642), 0x503e4646 }, - { AR5K_PHY_GAIN_2GHZ, 0x6480416c }, - { AR5K_PHY(644), 0x0199a003 }, - { AR5K_PHY(645), 0x044cd610 }, - { AR5K_PHY(646), 0x13800040 }, - { AR5K_PHY(647), 0x1be00060 }, - { AR5K_PHY(648), 0x0c53800a }, - { AR5K_PHY(649), 0x0014df3b }, - { AR5K_PHY(650), 0x000001b5 }, - { AR5K_PHY(651), 0x00000020 }, -}; - -/* Initial mode-specific settings for AR5211 - * 5211 supports OFDM-only g (draft g) but we - * need to test it ! - */ -static const struct ath5k_ini_mode ar5211_ini_mode[] = { - { AR5K_TXCFG, - /* a aTurbo b g (OFDM) */ - { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(0), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(1), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(2), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(3), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(4), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(5), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(6), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(7), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(8), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(9), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, - { AR5K_DCU_GBL_IFS_SLOT, - { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } }, - { AR5K_DCU_GBL_IFS_SIFS, - { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } }, - { AR5K_DCU_GBL_IFS_EIFS, - { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } }, - { AR5K_DCU_GBL_IFS_MISC, - { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } }, - { AR5K_TIME_OUT, - { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } }, - { AR5K_USEC_5211, - { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } }, - { AR5K_PHY_TURBO, - { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } }, - { AR5K_PHY(8), - { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } }, - { AR5K_PHY(9), - { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } }, - { AR5K_PHY(10), - { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } }, - { AR5K_PHY(13), - { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, - { AR5K_PHY(14), - { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } }, - { AR5K_PHY(17), - { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } }, - { AR5K_PHY(18), - { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } }, - { AR5K_PHY(20), - { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } }, - { AR5K_PHY_SIG, - { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } }, - { AR5K_PHY_AGCCOARSE, - { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } }, - { AR5K_PHY_AGCCTL, - { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } }, - { AR5K_PHY_NF, - { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, - { AR5K_PHY_RX_DELAY, - { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } }, - { AR5K_PHY(70), - { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } }, - { AR5K_PHY_FRAME_CTL_5211, - { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } }, - { AR5K_PHY_PCDAC_TXPOWER_BASE, - { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } }, - { AR5K_RF_BUFFER_CONTROL_4, - { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } }, -}; - -/* Initial register settings for AR5212 */ -static const struct ath5k_ini ar5212_ini_common_start[] = { - { AR5K_RXDP, 0x00000000 }, - { AR5K_RXCFG, 0x00000005 }, - { AR5K_MIBC, 0x00000000 }, - { AR5K_TOPS, 0x00000008 }, - { AR5K_RXNOFRM, 0x00000008 }, - { AR5K_TXNOFRM, 0x00000010 }, - { AR5K_RPGTO, 0x00000000 }, - { AR5K_RFCNT, 0x0000001f }, - { AR5K_QUEUE_TXDP(0), 0x00000000 }, - { AR5K_QUEUE_TXDP(1), 0x00000000 }, - { AR5K_QUEUE_TXDP(2), 0x00000000 }, - { AR5K_QUEUE_TXDP(3), 0x00000000 }, - { AR5K_QUEUE_TXDP(4), 0x00000000 }, - { AR5K_QUEUE_TXDP(5), 0x00000000 }, - { AR5K_QUEUE_TXDP(6), 0x00000000 }, - { AR5K_QUEUE_TXDP(7), 0x00000000 }, - { AR5K_QUEUE_TXDP(8), 0x00000000 }, - { AR5K_QUEUE_TXDP(9), 0x00000000 }, - { AR5K_DCU_FP, 0x00000000 }, - { AR5K_DCU_TXP, 0x00000000 }, - /* Tx filter table 0 (32 entries) */ - { AR5K_DCU_TX_FILTER_0(0), 0x00000000 }, /* DCU 0 */ - { AR5K_DCU_TX_FILTER_0(1), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(2), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(3), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(4), 0x00000000 }, /* DCU 1 */ - { AR5K_DCU_TX_FILTER_0(5), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(6), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(7), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(8), 0x00000000 }, /* DCU 2 */ - { AR5K_DCU_TX_FILTER_0(9), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(10), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(11), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(12), 0x00000000 }, /* DCU 3 */ - { AR5K_DCU_TX_FILTER_0(13), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(14), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(15), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(16), 0x00000000 }, /* DCU 4 */ - { AR5K_DCU_TX_FILTER_0(17), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(18), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(19), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(20), 0x00000000 }, /* DCU 5 */ - { AR5K_DCU_TX_FILTER_0(21), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(22), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(23), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(24), 0x00000000 }, /* DCU 6 */ - { AR5K_DCU_TX_FILTER_0(25), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(26), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(27), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(28), 0x00000000 }, /* DCU 7 */ - { AR5K_DCU_TX_FILTER_0(29), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(30), 0x00000000 }, - { AR5K_DCU_TX_FILTER_0(31), 0x00000000 }, - /* Tx filter table 1 (16 entries) */ - { AR5K_DCU_TX_FILTER_1(0), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(1), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(2), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(3), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(4), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(5), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(6), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(7), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(8), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(9), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(10), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(11), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(12), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(13), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(14), 0x00000000 }, - { AR5K_DCU_TX_FILTER_1(15), 0x00000000 }, - { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, - { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, - { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, - { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, - { AR5K_STA_ID1, 0x00000000 }, - { AR5K_BSS_ID0, 0x00000000 }, - { AR5K_BSS_ID1, 0x00000000 }, - { AR5K_BEACON_5211, 0x00000000 }, - { AR5K_CFP_PERIOD_5211, 0x00000000 }, - { AR5K_TIMER0_5211, 0x00000030 }, - { AR5K_TIMER1_5211, 0x0007ffff }, - { AR5K_TIMER2_5211, 0x01ffffff }, - { AR5K_TIMER3_5211, 0x00000031 }, - { AR5K_CFP_DUR_5211, 0x00000000 }, - { AR5K_RX_FILTER_5211, 0x00000000 }, - { AR5K_DIAG_SW_5211, 0x00000000 }, - { AR5K_ADDAC_TEST, 0x00000000 }, - { AR5K_DEFAULT_ANTENNA, 0x00000000 }, - { AR5K_FRAME_CTL_QOSM, 0x000fc78f }, - { AR5K_XRMODE, 0x2a82301a }, - { AR5K_XRDELAY, 0x05dc01e0 }, - { AR5K_XRTIMEOUT, 0x1f402710 }, - { AR5K_XRCHIRP, 0x01f40000 }, - { AR5K_XRSTOMP, 0x00001e1c }, - { AR5K_SLEEP0, 0x0002aaaa }, - { AR5K_SLEEP1, 0x02005555 }, - { AR5K_SLEEP2, 0x00000000 }, - { AR5K_BSS_IDM0, 0xffffffff }, - { AR5K_BSS_IDM1, 0x0000ffff }, - { AR5K_TXPC, 0x00000000 }, - { AR5K_PROFCNT_TX, 0x00000000 }, - { AR5K_PROFCNT_RX, 0x00000000 }, - { AR5K_PROFCNT_RXCLR, 0x00000000 }, - { AR5K_PROFCNT_CYCLE, 0x00000000 }, - { AR5K_QUIET_CTL1, 0x00000088 }, - /* Initial rate duration table (32 entries )*/ - { AR5K_RATE_DUR(0), 0x00000000 }, - { AR5K_RATE_DUR(1), 0x0000008c }, - { AR5K_RATE_DUR(2), 0x000000e4 }, - { AR5K_RATE_DUR(3), 0x000002d5 }, - { AR5K_RATE_DUR(4), 0x00000000 }, - { AR5K_RATE_DUR(5), 0x00000000 }, - { AR5K_RATE_DUR(6), 0x000000a0 }, - { AR5K_RATE_DUR(7), 0x000001c9 }, - { AR5K_RATE_DUR(8), 0x0000002c }, - { AR5K_RATE_DUR(9), 0x0000002c }, - { AR5K_RATE_DUR(10), 0x00000030 }, - { AR5K_RATE_DUR(11), 0x0000003c }, - { AR5K_RATE_DUR(12), 0x0000002c }, - { AR5K_RATE_DUR(13), 0x0000002c }, - { AR5K_RATE_DUR(14), 0x00000030 }, - { AR5K_RATE_DUR(15), 0x0000003c }, - { AR5K_RATE_DUR(16), 0x00000000 }, - { AR5K_RATE_DUR(17), 0x00000000 }, - { AR5K_RATE_DUR(18), 0x00000000 }, - { AR5K_RATE_DUR(19), 0x00000000 }, - { AR5K_RATE_DUR(20), 0x00000000 }, - { AR5K_RATE_DUR(21), 0x00000000 }, - { AR5K_RATE_DUR(22), 0x00000000 }, - { AR5K_RATE_DUR(23), 0x00000000 }, - { AR5K_RATE_DUR(24), 0x000000d5 }, - { AR5K_RATE_DUR(25), 0x000000df }, - { AR5K_RATE_DUR(26), 0x00000102 }, - { AR5K_RATE_DUR(27), 0x0000013a }, - { AR5K_RATE_DUR(28), 0x00000075 }, - { AR5K_RATE_DUR(29), 0x0000007f }, - { AR5K_RATE_DUR(30), 0x000000a2 }, - { AR5K_RATE_DUR(31), 0x00000000 }, - { AR5K_QUIET_CTL2, 0x00010002 }, - { AR5K_TSF_PARM, 0x00000001 }, - { AR5K_QOS_NOACK, 0x000000c0 }, - { AR5K_PHY_ERR_FIL, 0x00000000 }, - { AR5K_XRLAT_TX, 0x00000168 }, - { AR5K_ACKSIFS, 0x00000000 }, - /* Rate -> db table - * notice ...03<-02<-01<-00 ! */ - { AR5K_RATE2DB(0), 0x03020100 }, - { AR5K_RATE2DB(1), 0x07060504 }, - { AR5K_RATE2DB(2), 0x0b0a0908 }, - { AR5K_RATE2DB(3), 0x0f0e0d0c }, - { AR5K_RATE2DB(4), 0x13121110 }, - { AR5K_RATE2DB(5), 0x17161514 }, - { AR5K_RATE2DB(6), 0x1b1a1918 }, - { AR5K_RATE2DB(7), 0x1f1e1d1c }, - /* Db -> Rate table */ - { AR5K_DB2RATE(0), 0x03020100 }, - { AR5K_DB2RATE(1), 0x07060504 }, - { AR5K_DB2RATE(2), 0x0b0a0908 }, - { AR5K_DB2RATE(3), 0x0f0e0d0c }, - { AR5K_DB2RATE(4), 0x13121110 }, - { AR5K_DB2RATE(5), 0x17161514 }, - { AR5K_DB2RATE(6), 0x1b1a1918 }, - { AR5K_DB2RATE(7), 0x1f1e1d1c }, - /* PHY registers (Common settings - * for all chips/modes) */ - { AR5K_PHY(3), 0xad848e19 }, - { AR5K_PHY(4), 0x7d28e000 }, - { AR5K_PHY_TIMING_3, 0x9c0a9f6b }, - { AR5K_PHY_ACT, 0x00000000 }, - { AR5K_PHY(16), 0x206a017a }, - { AR5K_PHY(21), 0x00000859 }, - { AR5K_PHY_BIN_MASK_1, 0x00000000 }, - { AR5K_PHY_BIN_MASK_2, 0x00000000 }, - { AR5K_PHY_BIN_MASK_3, 0x00000000 }, - { AR5K_PHY_BIN_MASK_CTL, 0x00800000 }, - { AR5K_PHY_ANT_CTL, 0x00000001 }, - /*{ AR5K_PHY(71), 0x0000092a },*/ /* Old value */ - { AR5K_PHY_MAX_RX_LEN, 0x00000c80 }, - { AR5K_PHY_IQ, 0x05100000 }, - { AR5K_PHY_WARM_RESET, 0x00000001 }, - { AR5K_PHY_CTL, 0x00000004 }, - { AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022 }, - { AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d }, - { AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f }, - { AR5K_PHY(82), 0x9280b212 }, - { AR5K_PHY_RADAR, 0x5d50e188 }, - /*{ AR5K_PHY(86), 0x000000ff },*/ - { AR5K_PHY(87), 0x004b6a8e }, - { AR5K_PHY_NFTHRES, 0x000003ce }, - { AR5K_PHY_RESTART, 0x192fb515 }, - { AR5K_PHY(94), 0x00000001 }, - { AR5K_PHY_RFBUS_REQ, 0x00000000 }, - /*{ AR5K_PHY(644), 0x0080a333 },*/ /* Old value */ - /*{ AR5K_PHY(645), 0x00206c10 },*/ /* Old value */ - { AR5K_PHY(644), 0x00806333 }, - { AR5K_PHY(645), 0x00106c10 }, - { AR5K_PHY(646), 0x009c4060 }, - /* { AR5K_PHY(647), 0x1483800a }, */ - /* { AR5K_PHY(648), 0x01831061 }, */ /* Old value */ - { AR5K_PHY(648), 0x018830c6 }, - { AR5K_PHY(649), 0x00000400 }, - /*{ AR5K_PHY(650), 0x000001b5 },*/ - { AR5K_PHY(651), 0x00000000 }, - { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, - { AR5K_PHY_TXPOWER_RATE2, 0x20202020 }, - /*{ AR5K_PHY(655), 0x13c889af },*/ - { AR5K_PHY(656), 0x38490a20 }, - { AR5K_PHY(657), 0x00007bb6 }, - { AR5K_PHY(658), 0x0fff3ffc }, -}; - -/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */ -static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { - { AR5K_QUEUE_DFS_LOCAL_IFS(0), - /* a/XR aTurbo b g (DYN) gTurbo */ - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(1), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(2), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(3), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(4), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(5), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(6), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(7), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(8), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_QUEUE_DFS_LOCAL_IFS(9), - { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, - { AR5K_DCU_GBL_IFS_SIFS, - { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } }, - { AR5K_DCU_GBL_IFS_SLOT, - { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } }, - { AR5K_DCU_GBL_IFS_EIFS, - { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } }, - { AR5K_DCU_GBL_IFS_MISC, - { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } }, - { AR5K_TIME_OUT, - { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } }, - { AR5K_PHY_TURBO, - { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } }, - { AR5K_PHY(8), - { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } }, - { AR5K_PHY_RF_CTL2, - { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } }, - { AR5K_PHY_SETTLING, - { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } }, - { AR5K_PHY_AGCCTL, - { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } }, - { AR5K_PHY_NF, - { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, - { AR5K_PHY_WEAK_OFDM_HIGH_THR, - { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } }, - { AR5K_PHY(70), - { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } }, - { AR5K_PHY_OFDM_SELFCORR, - { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } }, - { 0xa230, - { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } }, -}; - -/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */ -static const struct ath5k_ini_mode rf5111_ini_mode_end[] = { - { AR5K_TXCFG, - /* a/XR aTurbo b g (DYN) gTurbo */ - { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, - { AR5K_USEC_5211, - { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } }, - { AR5K_PHY_RF_CTL3, - { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } }, - { AR5K_PHY_RF_CTL4, - { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, - { AR5K_PHY_PA_CTL, - { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, - { AR5K_PHY_GAIN, - { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } }, - { AR5K_PHY_DESIRED_SIZE, - { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, - { AR5K_PHY_SIG, - { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } }, - { AR5K_PHY_AGCCOARSE, - { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } }, - { AR5K_PHY_WEAK_OFDM_LOW_THR, - { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } }, - { AR5K_PHY_RX_DELAY, - { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } }, - { AR5K_PHY_FRAME_CTL_5211, - { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } }, - { AR5K_PHY_GAIN_2GHZ, - { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } }, - { AR5K_PHY_CCK_RX_CTL_4, - { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, -}; - -static const struct ath5k_ini rf5111_ini_common_end[] = { - { AR5K_DCU_FP, 0x00000000 }, - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY_ADC_CTL, 0x00022ffe }, - { 0x983c, 0x00020100 }, - { AR5K_PHY_GAIN_OFFSET, 0x1284613c }, - { AR5K_PHY_PAPD_PROBE, 0x00004883 }, - { 0x9940, 0x00000004 }, - { 0x9958, 0x000000ff }, - { 0x9974, 0x00000000 }, - { AR5K_PHY_SPENDING, 0x00000018 }, - { AR5K_PHY_CCKTXCTL, 0x00000000 }, - { AR5K_PHY_CCK_CROSSCORR, 0xd03e6788 }, - { AR5K_PHY_DAG_CCK_CTL, 0x000001b5 }, - { 0xa23c, 0x13c889af }, -}; - -/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */ -static const struct ath5k_ini_mode rf5112_ini_mode_end[] = { - { AR5K_TXCFG, - /* a/XR aTurbo b g (DYN) gTurbo */ - { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, - { AR5K_USEC_5211, - { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, - { AR5K_PHY_RF_CTL3, - { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, - { AR5K_PHY_RF_CTL4, - { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, - { AR5K_PHY_PA_CTL, - { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, - { AR5K_PHY_GAIN, - { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } }, - { AR5K_PHY_DESIRED_SIZE, - { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, - { AR5K_PHY_SIG, - { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } }, - { AR5K_PHY_AGCCOARSE, - { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } }, - { AR5K_PHY_WEAK_OFDM_LOW_THR, - { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, - { AR5K_PHY_RX_DELAY, - { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, - { AR5K_PHY_FRAME_CTL_5211, - { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } }, - { AR5K_PHY_CCKTXCTL, - { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } }, - { AR5K_PHY_CCK_CROSSCORR, - { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, - { AR5K_PHY_GAIN_2GHZ, - { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } }, - { AR5K_PHY_CCK_RX_CTL_4, - { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, -}; - -static const struct ath5k_ini rf5112_ini_common_end[] = { - { AR5K_DCU_FP, 0x00000000 }, - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY_ADC_CTL, 0x00022ffe }, - { 0x983c, 0x00020100 }, - { AR5K_PHY_GAIN_OFFSET, 0x1284613c }, - { AR5K_PHY_PAPD_PROBE, 0x00004882 }, - { 0x9940, 0x00000004 }, - { 0x9958, 0x000000ff }, - { 0x9974, 0x00000000 }, - { AR5K_PHY_DAG_CCK_CTL, 0x000001b5 }, - { 0xa23c, 0x13c889af }, -}; - -/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */ -static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { - { AR5K_TXCFG, - /* a/XR aTurbo b g (DYN) gTurbo */ - { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, - { AR5K_USEC_5211, - { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, - { AR5K_PHY_RF_CTL3, - { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, - { AR5K_PHY_RF_CTL4, - { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, - { AR5K_PHY_PA_CTL, - { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, - { AR5K_PHY_GAIN, - { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } }, - { AR5K_PHY_DESIRED_SIZE, - { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } }, - { AR5K_PHY_SIG, - { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } }, - { AR5K_PHY_AGCCOARSE, - { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } }, - { AR5K_PHY_WEAK_OFDM_LOW_THR, - { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, - { AR5K_PHY_RX_DELAY, - { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, - { AR5K_PHY_FRAME_CTL_5211, - { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, - { AR5K_PHY_CCKTXCTL, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { AR5K_PHY_CCK_CROSSCORR, - { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, - { AR5K_PHY_GAIN_2GHZ, - { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } }, - { AR5K_PHY_CCK_RX_CTL_4, - { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, - { 0xa300, - { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } }, - { 0xa304, - { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } }, - { 0xa308, - { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } }, - { 0xa30c, - { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } }, - { 0xa310, - { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } }, - { 0xa314, - { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } }, - { 0xa318, - { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } }, - { 0xa31c, - { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } }, - { 0xa320, - { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } }, - { 0xa324, - { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } }, - { 0xa328, - { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } }, - { 0xa32c, - { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } }, - { 0xa330, - { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } }, - { 0xa334, - { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } }, -}; - -static const struct ath5k_ini rf5413_ini_common_end[] = { - { AR5K_DCU_FP, 0x000003e0 }, - { AR5K_5414_CBCFG, 0x00000010 }, - { AR5K_SEQ_MASK, 0x0000000f }, - { 0x809c, 0x00000000 }, - { 0x80a0, 0x00000000 }, - { AR5K_MIC_QOS_CTL, 0x00000000 }, - { AR5K_MIC_QOS_SEL, 0x00000000 }, - { AR5K_MISC_MODE, 0x00000000 }, - { AR5K_OFDM_FIL_CNT, 0x00000000 }, - { AR5K_CCK_FIL_CNT, 0x00000000 }, - { AR5K_PHYERR_CNT1, 0x00000000 }, - { AR5K_PHYERR_CNT1_MASK, 0x00000000 }, - { AR5K_PHYERR_CNT2, 0x00000000 }, - { AR5K_PHYERR_CNT2_MASK, 0x00000000 }, - { AR5K_TSF_THRES, 0x00000000 }, - { 0x8140, 0x800003f9 }, - { 0x8144, 0x00000000 }, - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY_ADC_CTL, 0x0000a000 }, - { 0x983c, 0x00200400 }, - { AR5K_PHY_GAIN_OFFSET, 0x1284233c }, - { AR5K_PHY_SCR, 0x0000001f }, - { AR5K_PHY_SLMT, 0x00000080 }, - { AR5K_PHY_SCAL, 0x0000000e }, - { 0x9958, 0x00081fff }, - { AR5K_PHY_TIMING_7, 0x00000000 }, - { AR5K_PHY_TIMING_8, 0x02800000 }, - { AR5K_PHY_TIMING_11, 0x00000000 }, - { AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 }, - { 0x99e4, 0xaaaaaaaa }, - { 0x99e8, 0x3c466478 }, - { 0x99ec, 0x000000aa }, - { AR5K_PHY_SCLOCK, 0x0000000c }, - { AR5K_PHY_SDELAY, 0x000000ff }, - { AR5K_PHY_SPENDING, 0x00000014 }, - { AR5K_PHY_DAG_CCK_CTL, 0x000009b5 }, - { 0xa23c, 0x93c889af }, - { AR5K_PHY_FAST_ADC, 0x00000001 }, - { 0xa250, 0x0000a000 }, - { AR5K_PHY_BLUETOOTH, 0x00000000 }, - { AR5K_PHY_TPC_RG1, 0x0cc75380 }, - { 0xa25c, 0x0f0f0f01 }, - { 0xa260, 0x5f690f01 }, - { 0xa264, 0x00418a11 }, - { 0xa268, 0x00000000 }, - { AR5K_PHY_TPC_RG5, 0x0c30c16a }, - { 0xa270, 0x00820820 }, - { 0xa274, 0x081b7caa }, - { 0xa278, 0x1ce739ce }, - { 0xa27c, 0x051701ce }, - { 0xa338, 0x00000000 }, - { 0xa33c, 0x00000000 }, - { 0xa340, 0x00000000 }, - { 0xa344, 0x00000000 }, - { 0xa348, 0x3fffffff }, - { 0xa34c, 0x3fffffff }, - { 0xa350, 0x3fffffff }, - { 0xa354, 0x0003ffff }, - { 0xa358, 0x79a8aa1f }, - { 0xa35c, 0x066c420f }, - { 0xa360, 0x0f282207 }, - { 0xa364, 0x17601685 }, - { 0xa368, 0x1f801104 }, - { 0xa36c, 0x37a00c03 }, - { 0xa370, 0x3fc40883 }, - { 0xa374, 0x57c00803 }, - { 0xa378, 0x5fd80682 }, - { 0xa37c, 0x7fe00482 }, - { 0xa380, 0x7f3c7bba }, - { 0xa384, 0xf3307ff0 }, -}; - -/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */ -/* XXX: a mode ? */ -static const struct ath5k_ini_mode rf2413_ini_mode_end[] = { - { AR5K_TXCFG, - /* a/XR aTurbo b g (DYN) gTurbo */ - { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, - { AR5K_USEC_5211, - { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, - { AR5K_PHY_RF_CTL3, - { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } }, - { AR5K_PHY_RF_CTL4, - { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } }, - { AR5K_PHY_PA_CTL, - { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } }, - { AR5K_PHY_GAIN, - { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } }, - { AR5K_PHY_DESIRED_SIZE, - { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } }, - { AR5K_PHY_SIG, - { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } }, - { AR5K_PHY_AGCCOARSE, - { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } }, - { AR5K_PHY_WEAK_OFDM_LOW_THR, - { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, - { AR5K_PHY_RX_DELAY, - { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, - { AR5K_PHY_FRAME_CTL_5211, - { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, - { AR5K_PHY_CCKTXCTL, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { AR5K_PHY_CCK_CROSSCORR, - { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, - { AR5K_PHY_GAIN_2GHZ, - { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } }, - { AR5K_PHY_CCK_RX_CTL_4, - { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, -}; - -static const struct ath5k_ini rf2413_ini_common_end[] = { - { AR5K_DCU_FP, 0x000003e0 }, - { AR5K_SEQ_MASK, 0x0000000f }, - { AR5K_MIC_QOS_CTL, 0x00000000 }, - { AR5K_MIC_QOS_SEL, 0x00000000 }, - { AR5K_MISC_MODE, 0x00000000 }, - { AR5K_OFDM_FIL_CNT, 0x00000000 }, - { AR5K_CCK_FIL_CNT, 0x00000000 }, - { AR5K_PHYERR_CNT1, 0x00000000 }, - { AR5K_PHYERR_CNT1_MASK, 0x00000000 }, - { AR5K_PHYERR_CNT2, 0x00000000 }, - { AR5K_PHYERR_CNT2_MASK, 0x00000000 }, - { AR5K_TSF_THRES, 0x00000000 }, - { 0x8140, 0x800000a8 }, - { 0x8144, 0x00000000 }, - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY_ADC_CTL, 0x0000a000 }, - { 0x983c, 0x00200400 }, - { AR5K_PHY_GAIN_OFFSET, 0x1284233c }, - { AR5K_PHY_SCR, 0x0000001f }, - { AR5K_PHY_SLMT, 0x00000080 }, - { AR5K_PHY_SCAL, 0x0000000e }, - { 0x9958, 0x000000ff }, - { AR5K_PHY_TIMING_7, 0x00000000 }, - { AR5K_PHY_TIMING_8, 0x02800000 }, - { AR5K_PHY_TIMING_11, 0x00000000 }, - { AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 }, - { 0x99e4, 0xaaaaaaaa }, - { 0x99e8, 0x3c466478 }, - { 0x99ec, 0x000000aa }, - { AR5K_PHY_SCLOCK, 0x0000000c }, - { AR5K_PHY_SDELAY, 0x000000ff }, - { AR5K_PHY_SPENDING, 0x00000014 }, - { AR5K_PHY_DAG_CCK_CTL, 0x000009b5 }, - { 0xa23c, 0x93c889af }, - { AR5K_PHY_FAST_ADC, 0x00000001 }, - { 0xa250, 0x0000a000 }, - { AR5K_PHY_BLUETOOTH, 0x00000000 }, - { AR5K_PHY_TPC_RG1, 0x0cc75380 }, - { 0xa25c, 0x0f0f0f01 }, - { 0xa260, 0x5f690f01 }, - { 0xa264, 0x00418a11 }, - { 0xa268, 0x00000000 }, - { AR5K_PHY_TPC_RG5, 0x0c30c16a }, - { 0xa270, 0x00820820 }, - { 0xa274, 0x001b7caa }, - { 0xa278, 0x1ce739ce }, - { 0xa27c, 0x051701ce }, - { 0xa300, 0x18010000 }, - { 0xa304, 0x30032602 }, - { 0xa308, 0x48073e06 }, - { 0xa30c, 0x560b4c0a }, - { 0xa310, 0x641a600f }, - { 0xa314, 0x784f6e1b }, - { 0xa318, 0x868f7c5a }, - { 0xa31c, 0x8ecf865b }, - { 0xa320, 0x9d4f970f }, - { 0xa324, 0xa5cfa18f }, - { 0xa328, 0xb55faf1f }, - { 0xa32c, 0xbddfb99f }, - { 0xa330, 0xcd7fc73f }, - { 0xa334, 0xd5ffd1bf }, - { 0xa338, 0x00000000 }, - { 0xa33c, 0x00000000 }, - { 0xa340, 0x00000000 }, - { 0xa344, 0x00000000 }, - { 0xa348, 0x3fffffff }, - { 0xa34c, 0x3fffffff }, - { 0xa350, 0x3fffffff }, - { 0xa354, 0x0003ffff }, - { 0xa358, 0x79a8aa1f }, - { 0xa35c, 0x066c420f }, - { 0xa360, 0x0f282207 }, - { 0xa364, 0x17601685 }, - { 0xa368, 0x1f801104 }, - { 0xa36c, 0x37a00c03 }, - { 0xa370, 0x3fc40883 }, - { 0xa374, 0x57c00803 }, - { 0xa378, 0x5fd80682 }, - { 0xa37c, 0x7fe00482 }, - { 0xa380, 0x7f3c7bba }, - { 0xa384, 0xf3307ff0 }, -}; - -/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */ -/* XXX: a mode ? */ -static const struct ath5k_ini_mode rf2425_ini_mode_end[] = { - { AR5K_TXCFG, - /* a/XR aTurbo b g (DYN) gTurbo */ - { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, - { AR5K_USEC_5211, - { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, - { AR5K_PHY_TURBO, - { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } }, - { AR5K_PHY_RF_CTL3, - { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, - { AR5K_PHY_RF_CTL4, - { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, - { AR5K_PHY_PA_CTL, - { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } }, - { AR5K_PHY_SETTLING, - { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } }, - { AR5K_PHY_GAIN, - { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } }, - { AR5K_PHY_DESIRED_SIZE, - { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } }, - { AR5K_PHY_SIG, - { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } }, - { AR5K_PHY_AGCCOARSE, - { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } }, - { AR5K_PHY_WEAK_OFDM_LOW_THR, - { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, - { AR5K_PHY_RX_DELAY, - { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, - { AR5K_PHY_FRAME_CTL_5211, - { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, - { AR5K_PHY_CCKTXCTL, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { AR5K_PHY_CCK_CROSSCORR, - { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, - { AR5K_PHY_GAIN_2GHZ, - { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } }, - { AR5K_PHY_CCK_RX_CTL_4, - { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, - { 0xa324, - { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, - { 0xa328, - { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, - { 0xa32c, - { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, - { 0xa330, - { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, - { 0xa334, - { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } }, -}; - -static const struct ath5k_ini rf2425_ini_common_end[] = { - { AR5K_DCU_FP, 0x000003e0 }, - { AR5K_SEQ_MASK, 0x0000000f }, - { 0x809c, 0x00000000 }, - { 0x80a0, 0x00000000 }, - { AR5K_MIC_QOS_CTL, 0x00000000 }, - { AR5K_MIC_QOS_SEL, 0x00000000 }, - { AR5K_MISC_MODE, 0x00000000 }, - { AR5K_OFDM_FIL_CNT, 0x00000000 }, - { AR5K_CCK_FIL_CNT, 0x00000000 }, - { AR5K_PHYERR_CNT1, 0x00000000 }, - { AR5K_PHYERR_CNT1_MASK, 0x00000000 }, - { AR5K_PHYERR_CNT2, 0x00000000 }, - { AR5K_PHYERR_CNT2_MASK, 0x00000000 }, - { AR5K_TSF_THRES, 0x00000000 }, - { 0x8140, 0x800003f9 }, - { 0x8144, 0x00000000 }, - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY_ADC_CTL, 0x0000a000 }, - { 0x983c, 0x00200400 }, - { AR5K_PHY_GAIN_OFFSET, 0x1284233c }, - { AR5K_PHY_SCR, 0x0000001f }, - { AR5K_PHY_SLMT, 0x00000080 }, - { AR5K_PHY_SCAL, 0x0000000e }, - { 0x9958, 0x00081fff }, - { AR5K_PHY_TIMING_7, 0x00000000 }, - { AR5K_PHY_TIMING_8, 0x02800000 }, - { AR5K_PHY_TIMING_11, 0x00000000 }, - { 0x99dc, 0xfebadbe8 }, - { AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000 }, - { 0x99e4, 0xaaaaaaaa }, - { 0x99e8, 0x3c466478 }, - { 0x99ec, 0x000000aa }, - { AR5K_PHY_SCLOCK, 0x0000000c }, - { AR5K_PHY_SDELAY, 0x000000ff }, - { AR5K_PHY_SPENDING, 0x00000014 }, - { AR5K_PHY_DAG_CCK_CTL, 0x000009b5 }, - { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, - { AR5K_PHY_TXPOWER_RATE4, 0x20202020 }, - { 0xa23c, 0x93c889af }, - { AR5K_PHY_FAST_ADC, 0x00000001 }, - { 0xa250, 0x0000a000 }, - { AR5K_PHY_BLUETOOTH, 0x00000000 }, - { AR5K_PHY_TPC_RG1, 0x0cc75380 }, - { 0xa25c, 0x0f0f0f01 }, - { 0xa260, 0x5f690f01 }, - { 0xa264, 0x00418a11 }, - { 0xa268, 0x00000000 }, - { AR5K_PHY_TPC_RG5, 0x0c30c166 }, - { 0xa270, 0x00820820 }, - { 0xa274, 0x081a3caa }, - { 0xa278, 0x1ce739ce }, - { 0xa27c, 0x051701ce }, - { 0xa300, 0x16010000 }, - { 0xa304, 0x2c032402 }, - { 0xa308, 0x48433e42 }, - { 0xa30c, 0x5a0f500b }, - { 0xa310, 0x6c4b624a }, - { 0xa314, 0x7e8b748a }, - { 0xa318, 0x96cf8ccb }, - { 0xa31c, 0xa34f9d0f }, - { 0xa320, 0xa7cfa58f }, - { 0xa348, 0x3fffffff }, - { 0xa34c, 0x3fffffff }, - { 0xa350, 0x3fffffff }, - { 0xa354, 0x0003ffff }, - { 0xa358, 0x79a8aa1f }, - { 0xa35c, 0x066c420f }, - { 0xa360, 0x0f282207 }, - { 0xa364, 0x17601685 }, - { 0xa368, 0x1f801104 }, - { 0xa36c, 0x37a00c03 }, - { 0xa370, 0x3fc40883 }, - { 0xa374, 0x57c00803 }, - { 0xa378, 0x5fd80682 }, - { 0xa37c, 0x7fe00482 }, - { 0xa380, 0x7f3c7bba }, - { 0xa384, 0xf3307ff0 }, -}; - -/* - * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with - * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI) - */ - -/* RF5111 Initial BaseBand Gain settings */ -static const struct ath5k_ini rf5111_ini_bbgain[] = { - { AR5K_BB_GAIN(0), 0x00000000 }, - { AR5K_BB_GAIN(1), 0x00000020 }, - { AR5K_BB_GAIN(2), 0x00000010 }, - { AR5K_BB_GAIN(3), 0x00000030 }, - { AR5K_BB_GAIN(4), 0x00000008 }, - { AR5K_BB_GAIN(5), 0x00000028 }, - { AR5K_BB_GAIN(6), 0x00000004 }, - { AR5K_BB_GAIN(7), 0x00000024 }, - { AR5K_BB_GAIN(8), 0x00000014 }, - { AR5K_BB_GAIN(9), 0x00000034 }, - { AR5K_BB_GAIN(10), 0x0000000c }, - { AR5K_BB_GAIN(11), 0x0000002c }, - { AR5K_BB_GAIN(12), 0x00000002 }, - { AR5K_BB_GAIN(13), 0x00000022 }, - { AR5K_BB_GAIN(14), 0x00000012 }, - { AR5K_BB_GAIN(15), 0x00000032 }, - { AR5K_BB_GAIN(16), 0x0000000a }, - { AR5K_BB_GAIN(17), 0x0000002a }, - { AR5K_BB_GAIN(18), 0x00000006 }, - { AR5K_BB_GAIN(19), 0x00000026 }, - { AR5K_BB_GAIN(20), 0x00000016 }, - { AR5K_BB_GAIN(21), 0x00000036 }, - { AR5K_BB_GAIN(22), 0x0000000e }, - { AR5K_BB_GAIN(23), 0x0000002e }, - { AR5K_BB_GAIN(24), 0x00000001 }, - { AR5K_BB_GAIN(25), 0x00000021 }, - { AR5K_BB_GAIN(26), 0x00000011 }, - { AR5K_BB_GAIN(27), 0x00000031 }, - { AR5K_BB_GAIN(28), 0x00000009 }, - { AR5K_BB_GAIN(29), 0x00000029 }, - { AR5K_BB_GAIN(30), 0x00000005 }, - { AR5K_BB_GAIN(31), 0x00000025 }, - { AR5K_BB_GAIN(32), 0x00000015 }, - { AR5K_BB_GAIN(33), 0x00000035 }, - { AR5K_BB_GAIN(34), 0x0000000d }, - { AR5K_BB_GAIN(35), 0x0000002d }, - { AR5K_BB_GAIN(36), 0x00000003 }, - { AR5K_BB_GAIN(37), 0x00000023 }, - { AR5K_BB_GAIN(38), 0x00000013 }, - { AR5K_BB_GAIN(39), 0x00000033 }, - { AR5K_BB_GAIN(40), 0x0000000b }, - { AR5K_BB_GAIN(41), 0x0000002b }, - { AR5K_BB_GAIN(42), 0x0000002b }, - { AR5K_BB_GAIN(43), 0x0000002b }, - { AR5K_BB_GAIN(44), 0x0000002b }, - { AR5K_BB_GAIN(45), 0x0000002b }, - { AR5K_BB_GAIN(46), 0x0000002b }, - { AR5K_BB_GAIN(47), 0x0000002b }, - { AR5K_BB_GAIN(48), 0x0000002b }, - { AR5K_BB_GAIN(49), 0x0000002b }, - { AR5K_BB_GAIN(50), 0x0000002b }, - { AR5K_BB_GAIN(51), 0x0000002b }, - { AR5K_BB_GAIN(52), 0x0000002b }, - { AR5K_BB_GAIN(53), 0x0000002b }, - { AR5K_BB_GAIN(54), 0x0000002b }, - { AR5K_BB_GAIN(55), 0x0000002b }, - { AR5K_BB_GAIN(56), 0x0000002b }, - { AR5K_BB_GAIN(57), 0x0000002b }, - { AR5K_BB_GAIN(58), 0x0000002b }, - { AR5K_BB_GAIN(59), 0x0000002b }, - { AR5K_BB_GAIN(60), 0x0000002b }, - { AR5K_BB_GAIN(61), 0x0000002b }, - { AR5K_BB_GAIN(62), 0x00000002 }, - { AR5K_BB_GAIN(63), 0x00000016 }, -}; - -/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414+) */ -static const struct ath5k_ini rf5112_ini_bbgain[] = { - { AR5K_BB_GAIN(0), 0x00000000 }, - { AR5K_BB_GAIN(1), 0x00000001 }, - { AR5K_BB_GAIN(2), 0x00000002 }, - { AR5K_BB_GAIN(3), 0x00000003 }, - { AR5K_BB_GAIN(4), 0x00000004 }, - { AR5K_BB_GAIN(5), 0x00000005 }, - { AR5K_BB_GAIN(6), 0x00000008 }, - { AR5K_BB_GAIN(7), 0x00000009 }, - { AR5K_BB_GAIN(8), 0x0000000a }, - { AR5K_BB_GAIN(9), 0x0000000b }, - { AR5K_BB_GAIN(10), 0x0000000c }, - { AR5K_BB_GAIN(11), 0x0000000d }, - { AR5K_BB_GAIN(12), 0x00000010 }, - { AR5K_BB_GAIN(13), 0x00000011 }, - { AR5K_BB_GAIN(14), 0x00000012 }, - { AR5K_BB_GAIN(15), 0x00000013 }, - { AR5K_BB_GAIN(16), 0x00000014 }, - { AR5K_BB_GAIN(17), 0x00000015 }, - { AR5K_BB_GAIN(18), 0x00000018 }, - { AR5K_BB_GAIN(19), 0x00000019 }, - { AR5K_BB_GAIN(20), 0x0000001a }, - { AR5K_BB_GAIN(21), 0x0000001b }, - { AR5K_BB_GAIN(22), 0x0000001c }, - { AR5K_BB_GAIN(23), 0x0000001d }, - { AR5K_BB_GAIN(24), 0x00000020 }, - { AR5K_BB_GAIN(25), 0x00000021 }, - { AR5K_BB_GAIN(26), 0x00000022 }, - { AR5K_BB_GAIN(27), 0x00000023 }, - { AR5K_BB_GAIN(28), 0x00000024 }, - { AR5K_BB_GAIN(29), 0x00000025 }, - { AR5K_BB_GAIN(30), 0x00000028 }, - { AR5K_BB_GAIN(31), 0x00000029 }, - { AR5K_BB_GAIN(32), 0x0000002a }, - { AR5K_BB_GAIN(33), 0x0000002b }, - { AR5K_BB_GAIN(34), 0x0000002c }, - { AR5K_BB_GAIN(35), 0x0000002d }, - { AR5K_BB_GAIN(36), 0x00000030 }, - { AR5K_BB_GAIN(37), 0x00000031 }, - { AR5K_BB_GAIN(38), 0x00000032 }, - { AR5K_BB_GAIN(39), 0x00000033 }, - { AR5K_BB_GAIN(40), 0x00000034 }, - { AR5K_BB_GAIN(41), 0x00000035 }, - { AR5K_BB_GAIN(42), 0x00000035 }, - { AR5K_BB_GAIN(43), 0x00000035 }, - { AR5K_BB_GAIN(44), 0x00000035 }, - { AR5K_BB_GAIN(45), 0x00000035 }, - { AR5K_BB_GAIN(46), 0x00000035 }, - { AR5K_BB_GAIN(47), 0x00000035 }, - { AR5K_BB_GAIN(48), 0x00000035 }, - { AR5K_BB_GAIN(49), 0x00000035 }, - { AR5K_BB_GAIN(50), 0x00000035 }, - { AR5K_BB_GAIN(51), 0x00000035 }, - { AR5K_BB_GAIN(52), 0x00000035 }, - { AR5K_BB_GAIN(53), 0x00000035 }, - { AR5K_BB_GAIN(54), 0x00000035 }, - { AR5K_BB_GAIN(55), 0x00000035 }, - { AR5K_BB_GAIN(56), 0x00000035 }, - { AR5K_BB_GAIN(57), 0x00000035 }, - { AR5K_BB_GAIN(58), 0x00000035 }, - { AR5K_BB_GAIN(59), 0x00000035 }, - { AR5K_BB_GAIN(60), 0x00000035 }, - { AR5K_BB_GAIN(61), 0x00000035 }, - { AR5K_BB_GAIN(62), 0x00000010 }, - { AR5K_BB_GAIN(63), 0x0000001a }, -}; - - -/* - * Write initial register dump - */ -static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, - const struct ath5k_ini *ini_regs, bool change_channel) -{ - unsigned int i; - - /* Write initial registers */ - for (i = 0; i < size; i++) { - /* On channel change there is - * no need to mess with PCU */ - if (change_channel && - ini_regs[i].ini_register >= AR5K_PCU_MIN && - ini_regs[i].ini_register <= AR5K_PCU_MAX) - continue; - - switch (ini_regs[i].ini_mode) { - case AR5K_INI_READ: - /* Cleared on read */ - ath5k_hw_reg_read(ah, ini_regs[i].ini_register); - break; - case AR5K_INI_WRITE: - default: - AR5K_REG_WAIT(i); - ath5k_hw_reg_write(ah, ini_regs[i].ini_value, - ini_regs[i].ini_register); - } - } -} - -static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, - unsigned int size, const struct ath5k_ini_mode *ini_mode, - u8 mode) -{ - unsigned int i; - - for (i = 0; i < size; i++) { - AR5K_REG_WAIT(i); - ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode], - (u32)ini_mode[i].mode_register); - } - -} - -int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) -{ - /* - * Write initial register settings - */ - - /* For AR5212 and combatible */ - if (ah->ah_version == AR5K_AR5212) { - - /* First set of mode-specific settings */ - ath5k_hw_ini_mode_registers(ah, - ARRAY_SIZE(ar5212_ini_mode_start), - ar5212_ini_mode_start, mode); - - /* - * Write initial settings common for all modes - */ - ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start), - ar5212_ini_common_start, change_channel); - - /* Second set of mode-specific settings */ - switch (ah->ah_radio) { - case AR5K_RF5111: - - ath5k_hw_ini_mode_registers(ah, - ARRAY_SIZE(rf5111_ini_mode_end), - rf5111_ini_mode_end, mode); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5111_ini_common_end), - rf5111_ini_common_end, change_channel); - - /* Baseband gain table */ - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5111_ini_bbgain), - rf5111_ini_bbgain, change_channel); - - break; - case AR5K_RF5112: - - ath5k_hw_ini_mode_registers(ah, - ARRAY_SIZE(rf5112_ini_mode_end), - rf5112_ini_mode_end, mode); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5112_ini_common_end), - rf5112_ini_common_end, change_channel); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5112_ini_bbgain), - rf5112_ini_bbgain, change_channel); - - break; - case AR5K_RF5413: - - ath5k_hw_ini_mode_registers(ah, - ARRAY_SIZE(rf5413_ini_mode_end), - rf5413_ini_mode_end, mode); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5413_ini_common_end), - rf5413_ini_common_end, change_channel); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5112_ini_bbgain), - rf5112_ini_bbgain, change_channel); - - break; - case AR5K_RF2316: - case AR5K_RF2413: - - ath5k_hw_ini_mode_registers(ah, - ARRAY_SIZE(rf2413_ini_mode_end), - rf2413_ini_mode_end, mode); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf2413_ini_common_end), - rf2413_ini_common_end, change_channel); - - /* Override settings from rf2413_ini_common_end */ - if (ah->ah_radio == AR5K_RF2316) { - ath5k_hw_reg_write(ah, 0x00004000, - AR5K_PHY_AGC); - ath5k_hw_reg_write(ah, 0x081b7caa, - 0xa274); - } - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5112_ini_bbgain), - rf5112_ini_bbgain, change_channel); - break; - case AR5K_RF2317: - case AR5K_RF2425: - - ath5k_hw_ini_mode_registers(ah, - ARRAY_SIZE(rf2425_ini_mode_end), - rf2425_ini_mode_end, mode); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf2425_ini_common_end), - rf2425_ini_common_end, change_channel); - - ath5k_hw_ini_registers(ah, - ARRAY_SIZE(rf5112_ini_bbgain), - rf5112_ini_bbgain, change_channel); - break; - default: - return -EINVAL; - - } - - /* For AR5211 */ - } else if (ah->ah_version == AR5K_AR5211) { - - /* AR5K_MODE_11B */ - if (mode > 2) { - ATH5K_ERR(ah->ah_sc, - "unsupported channel mode: %d\n", mode); - return -EINVAL; - } - - /* Mode-specific settings */ - ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode), - ar5211_ini_mode, mode); - - /* - * Write initial settings common for all modes - */ - ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini), - ar5211_ini, change_channel); - - /* AR5211 only comes with 5111 */ - - /* Baseband gain table */ - ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain), - rf5111_ini_bbgain, change_channel); - /* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */ - } else if (ah->ah_version == AR5K_AR5210) { - ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini), - ar5210_ini, change_channel); - } - - return 0; -} diff --git a/drivers/net/wireless/ath5k/led.c b/drivers/net/wireless/ath5k/led.c deleted file mode 100644 index 19555fb..0000000 --- a/drivers/net/wireless/ath5k/led.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting - * Copyright (c) 2004-2005 Atheros Communications, Inc. - * Copyright (c) 2007 Jiri Slaby - * Copyright (c) 2009 Bob Copeland - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any - * redistribution must be conditioned upon including a substantially - * similar Disclaimer requirement for further binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGES. - * - */ - -#include -#include "ath5k.h" -#include "base.h" - -#define ATH_SDEVICE(subv,subd) \ - .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ - .subvendor = (subv), .subdevice = (subd) - -#define ATH_LED(pin,polarity) .driver_data = (((pin) << 8) | (polarity)) -#define ATH_PIN(data) ((data) >> 8) -#define ATH_POLARITY(data) ((data) & 0xff) - -/* Devices we match on for LED config info (typically laptops) */ -static const struct pci_device_id ath5k_led_devices[] = { - /* IBM-specific AR5212 */ - { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, - /* AR5211 */ - { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) }, - /* HP Compaq nc6xx, nc4000, nx6000 */ - { ATH_SDEVICE(PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID), ATH_LED(1, 1) }, - /* Acer Aspire One A150 (maximlevitsky@gmail.com) */ - { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe008), ATH_LED(3, 0) }, - /* Acer Ferrari 5000 (russ.dill@gmail.com) */ - { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) }, - /* E-machines E510 (tuliom@gmail.com) */ - { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) }, - /* Acer Extensa 5620z (nekoreeve@gmail.com) */ - { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) }, - { } -}; - -void ath5k_led_enable(struct ath5k_softc *sc) -{ - if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { - ath5k_hw_set_gpio_output(sc->ah, sc->led_pin); - ath5k_led_off(sc); - } -} - -void ath5k_led_on(struct ath5k_softc *sc) -{ - if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) - return; - ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on); -} - -void ath5k_led_off(struct ath5k_softc *sc) -{ - if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) - return; - ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on); -} - -static void -ath5k_led_brightness_set(struct led_classdev *led_dev, - enum led_brightness brightness) -{ - struct ath5k_led *led = container_of(led_dev, struct ath5k_led, - led_dev); - - if (brightness == LED_OFF) - ath5k_led_off(led->sc); - else - ath5k_led_on(led->sc); -} - -static int -ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led, - const char *name, char *trigger) -{ - int err; - - led->sc = sc; - strncpy(led->name, name, sizeof(led->name)); - led->led_dev.name = led->name; - led->led_dev.default_trigger = trigger; - led->led_dev.brightness_set = ath5k_led_brightness_set; - - err = led_classdev_register(&sc->pdev->dev, &led->led_dev); - if (err) { - ATH5K_WARN(sc, "could not register LED %s\n", name); - led->sc = NULL; - } - return err; -} - -static void -ath5k_unregister_led(struct ath5k_led *led) -{ - if (!led->sc) - return; - led_classdev_unregister(&led->led_dev); - ath5k_led_off(led->sc); - led->sc = NULL; -} - -void ath5k_unregister_leds(struct ath5k_softc *sc) -{ - ath5k_unregister_led(&sc->rx_led); - ath5k_unregister_led(&sc->tx_led); -} - -int ath5k_init_leds(struct ath5k_softc *sc) -{ - int ret = 0; - struct ieee80211_hw *hw = sc->hw; - struct pci_dev *pdev = sc->pdev; - char name[ATH5K_LED_MAX_NAME_LEN + 1]; - const struct pci_device_id *match; - - match = pci_match_id(&ath5k_led_devices[0], pdev); - if (match) { - __set_bit(ATH_STAT_LEDSOFT, sc->status); - sc->led_pin = ATH_PIN(match->driver_data); - sc->led_on = ATH_POLARITY(match->driver_data); - } - - if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) - goto out; - - ath5k_led_enable(sc); - - snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy)); - ret = ath5k_register_led(sc, &sc->rx_led, name, - ieee80211_get_rx_led_name(hw)); - if (ret) - goto out; - - snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy)); - ret = ath5k_register_led(sc, &sc->tx_led, name, - ieee80211_get_tx_led_name(hw)); -out: - return ret; -} - diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c deleted file mode 100644 index 55122f1..0000000 --- a/drivers/net/wireless/ath5k/pcu.c +++ /dev/null @@ -1,1174 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * Copyright (c) 2007-2008 Matthew W. S. Bell - * Copyright (c) 2007-2008 Luis Rodriguez - * Copyright (c) 2007-2008 Pavel Roskin - * Copyright (c) 2007-2008 Jiri Slaby - * - * 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; - - - /* Preserve rest settings */ - pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; - pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP - | AR5K_STA_ID1_KEYSRCH_MODE - | (ah->ah_version == AR5K_AR5210 ? - (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 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_KEYSRCH_MODE; - beacon_reg |= AR5K_BCR_ADHOC; - if (ah->ah_version == AR5K_AR5210) - pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; - else - AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); - break; - - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_MESH_POINT: - pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; - beacon_reg |= AR5K_BCR_AP; - if (ah->ah_version == AR5K_AR5210) - pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; - else - AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); - break; - - case NL80211_IFTYPE_STATION: - pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE - | (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_PWR_SV : 0); - case NL80211_IFTYPE_MONITOR: - pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE - | (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); - } - - /* TODO: Handle ANI stats */ -} - -/** - * 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; - u32 pcu_reg; - - ATH5K_TRACE(ah->ah_sc); - /* Set new station ID */ - memcpy(ah->ah_sta_id, mac, ETH_ALEN); - - pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; - - 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, pcu_reg | 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, AR5K_LOW_ID(ah->ah_bssid_mask), - AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), - 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); - - /* Cache bssid mask so that we can restore it - * on reset */ - memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); - 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 (phy error reporting) */ - 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_set_tsf64 - Set a new 64bit TSF - * - * @ah: The &struct ath5k_hw - * @tsf64: The new 64bit TSF - * - * Sets the new TSF - */ -void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) -{ - ATH5K_TRACE(ah->ah_sc); - - ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32); - ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32); -} - -/** - * 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_MONITOR: - case NL80211_IFTYPE_STATION: - /* In STA mode timer1 is used as next wakeup - * timer and timer2 as next CFP duration start - * timer. Both in 1/8TUs. */ - /* TODO: PCF handling */ - if (ah->ah_version == AR5K_AR5210) { - timer1 = 0xffffffff; - timer2 = 0xffffffff; - } else { - timer1 = 0x0000ffff; - timer2 = 0x0007ffff; - } - /* Mark associated AP as PCF incapable for now */ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); - break; - case NL80211_IFTYPE_ADHOC: - AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); - default: - /* On non-STA modes timer1 is used as next DMA - * beacon alert (DBA) timer and timer2 as next - * software beacon alert. Both in 1/8TUs. */ - timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; - timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; - break; - } - - /* Timer3 marks the end of our ATIM window - * a zero length window is not allowed because - * we 'll get no beacons */ - timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); - - /* - * Set the beacon register and enable all timers. - */ - /* When in AP mode zero timer0 to start TSF */ - if (ah->ah_op_mode == NL80211_IFTYPE_AP) - ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); - else - 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); - - /* Force a TSF reset if requested and enable beacons */ - if (interval & AR5K_BEACON_RESET_TSF) - ath5k_hw_reset_tsf(ah); - - ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | - AR5K_BEACON_ENABLE), - AR5K_BEACON); - - /* Flush any pending BMISS interrupts on ISR by - * performing a clear-on-write operation on PISR - * register for the BMISS bit (writing a bit on - * ISR togles a reset for that bit and leaves - * the rest bits intact) */ - if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); - else - ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); - - /* TODO: Set enchanced sleep registers on AR5212 - * based on vif->bss_conf params, until then - * disable power save reporting.*/ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); - -} - -#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, type; - u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); - - for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); - - /* Reset associated MIC entry if TKIP - * is enabled located at offset (entry + 64) */ - if (type == AR5K_KEYTABLE_TYPE_TKIP) { - AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); - for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) - ath5k_hw_reg_write(ah, 0, - AR5K_KEYTABLE_OFF(micentry, 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)); - - if (type == AR5K_KEYTABLE_TYPE_TKIP) { - ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, - AR5K_KEYTABLE_TYPE(micentry)); - } - } - - 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; -} - -static -int ath5k_keycache_type(const struct ieee80211_key_conf *key) -{ - switch (key->alg) { - case ALG_TKIP: - return AR5K_KEYTABLE_TYPE_TKIP; - case ALG_CCMP: - return AR5K_KEYTABLE_TYPE_CCM; - case ALG_WEP: - if (key->keylen == LEN_WEP40) - return AR5K_KEYTABLE_TYPE_40; - else if (key->keylen == LEN_WEP104) - return AR5K_KEYTABLE_TYPE_104; - return -EINVAL; - default: - return -EINVAL; - } - return -EINVAL; -} - -/* - * 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; - int keylen; - __le32 key_v[5] = {}; - __le32 key0 = 0, key1 = 0; - __le32 *rxmic, *txmic; - int keytype; - u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; - bool is_tkip; - const u8 *key_ptr; - - ATH5K_TRACE(ah->ah_sc); - - is_tkip = (key->alg == ALG_TKIP); - - /* - * key->keylen comes in from mac80211 in bytes. - * TKIP is 128 bit + 128 bit mic - */ - keylen = (is_tkip) ? (128 / 8) : key->keylen; - - if (entry > AR5K_KEYTABLE_SIZE || - (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) - return -EOPNOTSUPP; - - if (unlikely(keylen > 16)) - return -EOPNOTSUPP; - - keytype = ath5k_keycache_type(key); - if (keytype < 0) - return keytype; - - /* - * each key block is 6 bytes wide, written as pairs of - * alternating 32 and 16 bit le values. - */ - key_ptr = key->key; - for (i = 0; keylen >= 6; keylen -= 6) { - memcpy(&key_v[i], key_ptr, 6); - i += 2; - key_ptr += 6; - } - if (keylen) - memcpy(&key_v[i], key_ptr, keylen); - - /* intentionally corrupt key until mic is installed */ - if (is_tkip) { - key0 = key_v[0] = ~key_v[0]; - key1 = key_v[1] = ~key_v[1]; - } - - 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)); - - if (is_tkip) { - /* Install rx/tx MIC */ - rxmic = (__le32 *) &key->key[16]; - txmic = (__le32 *) &key->key[24]; - - if (ah->ah_combined_mic) { - key_v[0] = rxmic[0]; - key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); - key_v[2] = rxmic[1]; - key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); - key_v[4] = txmic[1]; - } else { - key_v[0] = rxmic[0]; - key_v[1] = 0; - key_v[2] = rxmic[1]; - key_v[3] = 0; - key_v[4] = 0; - } - for (i = 0; i < ARRAY_SIZE(key_v); i++) - ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), - AR5K_KEYTABLE_OFF(micentry, i)); - - ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, - AR5K_KEYTABLE_TYPE(micentry)); - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); - - /* restore first 2 words of key */ - ath5k_hw_reg_write(ah, le32_to_cpu(~key0), - AR5K_KEYTABLE_OFF(entry, 0)); - ath5k_hw_reg_write(ah, le32_to_cpu(~key1), - AR5K_KEYTABLE_OFF(entry, 1)); - } - - 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 (!mac) { - 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 deleted file mode 100644 index 9e2faae..0000000 --- a/drivers/net/wireless/ath5k/phy.c +++ /dev/null @@ -1,2599 +0,0 @@ -/* - * PHY functions - * - * Copyright (c) 2004-2007 Reyk Floeter - * Copyright (c) 2006-2009 Nick Kossifidis - * Copyright (c) 2007-2008 Jiri Slaby - * Copyright (c) 2008-2009 Felix Fietkau - * - * 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_PHY - -#include - -#include "ath5k.h" -#include "reg.h" -#include "base.h" -#include "rfbuffer.h" -#include "rfgain.h" - -/* - * Used to modify RF Banks before writing them to AR5K_RF_BUFFER - */ -static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, - const struct ath5k_rf_reg *rf_regs, - u32 val, u8 reg_id, bool set) -{ - const struct ath5k_rf_reg *rfreg = NULL; - u8 offset, bank, num_bits, col, position; - u16 entry; - u32 mask, data, last_bit, bits_shifted, first_bit; - u32 *rfb; - s32 bits_left; - int i; - - data = 0; - rfb = ah->ah_rf_banks; - - for (i = 0; i < ah->ah_rf_regs_count; i++) { - if (rf_regs[i].index == reg_id) { - rfreg = &rf_regs[i]; - break; - } - } - - if (rfb == NULL || rfreg == NULL) { - ATH5K_PRINTF("Rf register not found!\n"); - /* should not happen */ - return 0; - } - - bank = rfreg->bank; - num_bits = rfreg->field.len; - first_bit = rfreg->field.pos; - col = rfreg->field.col; - - /* first_bit is an offset from bank's - * start. Since we have all banks on - * the same array, we use this offset - * to mark each bank's start */ - offset = ah->ah_offset[bank]; - - /* Boundary check */ - if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) { - ATH5K_PRINTF("invalid values at offset %u\n", offset); - return 0; - } - - entry = ((first_bit - 1) / 8) + offset; - position = (first_bit - 1) % 8; - - if (set) - data = ath5k_hw_bitswap(val, num_bits); - - for (bits_shifted = 0, bits_left = num_bits; bits_left > 0; - position = 0, entry++) { - - last_bit = (position + bits_left > 8) ? 8 : - position + bits_left; - - mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) << - (col * 8); - - if (set) { - rfb[entry] &= ~mask; - rfb[entry] |= ((data << position) << (col * 8)) & mask; - data >>= (8 - position); - } else { - data |= (((rfb[entry] & mask) >> (col * 8)) >> position) - << bits_shifted; - bits_shifted += last_bit - position; - } - - bits_left -= 8 - position; - } - - data = set ? 1 : ath5k_hw_bitswap(data, num_bits); - - return data; -} - -/**********************\ -* RF Gain optimization * -\**********************/ - -/* - * This code is used to optimize rf gain on different environments - * (temprature mostly) based on feedback from a power detector. - * - * It's only used on RF5111 and RF5112, later RF chips seem to have - * auto adjustment on hw -notice they have a much smaller BANK 7 and - * no gain optimization ladder-. - * - * For more infos check out this patent doc - * http://www.freepatentsonline.com/7400691.html - * - * This paper describes power drops as seen on the receiver due to - * probe packets - * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues - * %20of%20Power%20Control.pdf - * - * And this is the MadWiFi bug entry related to the above - * http://madwifi-project.org/ticket/1659 - * with various measurements and diagrams - * - * TODO: Deal with power drops due to probes by setting an apropriate - * tx power on the probe packets ! Make this part of the calibration process. - */ - -/* Initialize ah_gain durring attach */ -int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) -{ - /* Initialize the gain optimization values */ - switch (ah->ah_radio) { - case AR5K_RF5111: - ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; - ah->ah_gain.g_low = 20; - ah->ah_gain.g_high = 35; - ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; - break; - case AR5K_RF5112: - ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; - ah->ah_gain.g_low = 20; - ah->ah_gain.g_high = 85; - ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* Schedule a gain probe check on the next transmited packet. - * That means our next packet is going to be sent with lower - * tx power and a Peak to Average Power Detector (PAPD) will try - * to measure the gain. - * - * TODO: Use propper tx power setting for the probe packet so - * that we don't observe a serious power drop on the receiver - * - * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) - * just after we enable the probe so that we don't mess with - * standard traffic ? Maybe it's time to use sw interrupts and - * a probe tasklet !!! - */ -static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) -{ - - /* Skip if gain calibration is inactive or - * we already handle a probe request */ - if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE) - return; - - /* Send the packet with 2dB below max power as - * patent doc suggest */ - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4, - AR5K_PHY_PAPD_PROBE_TXPOWER) | - AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); - - ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED; - -} - -/* Calculate gain_F measurement correction - * based on the current step for RF5112 rev. 2 */ -static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) -{ - u32 mix, step; - u32 *rf; - const struct ath5k_gain_opt *go; - const struct ath5k_gain_opt_step *g_step; - const struct ath5k_rf_reg *rf_regs; - - /* Only RF5112 Rev. 2 supports it */ - if ((ah->ah_radio != AR5K_RF5112) || - (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A)) - return 0; - - go = &rfgain_opt_5112; - rf_regs = rf_regs_5112a; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); - - g_step = &go->go_step[ah->ah_gain.g_step_idx]; - - if (ah->ah_rf_banks == NULL) - return 0; - - rf = ah->ah_rf_banks; - ah->ah_gain.g_f_corr = 0; - - /* No VGA (Variable Gain Amplifier) override, skip */ - if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, false) != 1) - return 0; - - /* Mix gain stepping */ - step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, false); - - /* Mix gain override */ - mix = g_step->gos_param[0]; - - switch (mix) { - case 3: - ah->ah_gain.g_f_corr = step * 2; - break; - case 2: - ah->ah_gain.g_f_corr = (step - 5) * 2; - break; - case 1: - ah->ah_gain.g_f_corr = step; - break; - default: - ah->ah_gain.g_f_corr = 0; - break; - } - - return ah->ah_gain.g_f_corr; -} - -/* Check if current gain_F measurement is in the range of our - * power detector windows. If we get a measurement outside range - * we know it's not accurate (detectors can't measure anything outside - * their detection window) so we must ignore it */ -static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) -{ - const struct ath5k_rf_reg *rf_regs; - u32 step, mix_ovr, level[4]; - u32 *rf; - - if (ah->ah_rf_banks == NULL) - return false; - - rf = ah->ah_rf_banks; - - if (ah->ah_radio == AR5K_RF5111) { - - rf_regs = rf_regs_5111; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); - - step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP, - false); - - level[0] = 0; - level[1] = (step == 63) ? 50 : step + 4; - level[2] = (step != 63) ? 64 : level[0]; - level[3] = level[2] + 50 ; - - ah->ah_gain.g_high = level[3] - - (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); - ah->ah_gain.g_low = level[0] + - (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); - } else { - - rf_regs = rf_regs_5112; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); - - mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, - false); - - level[0] = level[2] = 0; - - if (mix_ovr == 1) { - level[1] = level[3] = 83; - } else { - level[1] = level[3] = 107; - ah->ah_gain.g_high = 55; - } - } - - return (ah->ah_gain.g_current >= level[0] && - ah->ah_gain.g_current <= level[1]) || - (ah->ah_gain.g_current >= level[2] && - ah->ah_gain.g_current <= level[3]); -} - -/* Perform gain_F adjustment by choosing the right set - * of parameters from rf gain optimization ladder */ -static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) -{ - const struct ath5k_gain_opt *go; - const struct ath5k_gain_opt_step *g_step; - int ret = 0; - - switch (ah->ah_radio) { - case AR5K_RF5111: - go = &rfgain_opt_5111; - break; - case AR5K_RF5112: - go = &rfgain_opt_5112; - break; - default: - return 0; - } - - g_step = &go->go_step[ah->ah_gain.g_step_idx]; - - if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { - - /* Reached maximum */ - if (ah->ah_gain.g_step_idx == 0) - return -1; - - for (ah->ah_gain.g_target = ah->ah_gain.g_current; - ah->ah_gain.g_target >= ah->ah_gain.g_high && - ah->ah_gain.g_step_idx > 0; - g_step = &go->go_step[ah->ah_gain.g_step_idx]) - ah->ah_gain.g_target -= 2 * - (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - - g_step->gos_gain); - - ret = 1; - goto done; - } - - if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { - - /* Reached minimum */ - if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) - return -2; - - for (ah->ah_gain.g_target = ah->ah_gain.g_current; - ah->ah_gain.g_target <= ah->ah_gain.g_low && - ah->ah_gain.g_step_idx < go->go_steps_count-1; - g_step = &go->go_step[ah->ah_gain.g_step_idx]) - ah->ah_gain.g_target -= 2 * - (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - - g_step->gos_gain); - - ret = 2; - goto done; - } - -done: - ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, - "ret %d, gain step %u, current gain %u, target gain %u\n", - ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current, - ah->ah_gain.g_target); - - return ret; -} - -/* Main callback for thermal rf gain calibration engine - * Check for a new gain reading and schedule an adjustment - * if needed. - * - * TODO: Use sw interrupt to schedule reset if gain_F needs - * adjustment */ -enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) -{ - u32 data, type; - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_rf_banks == NULL || - ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE) - return AR5K_RFGAIN_INACTIVE; - - /* No check requested, either engine is inactive - * or an adjustment is already requested */ - if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED) - goto done; - - /* Read the PAPD (Peak to Average Power Detector) - * register */ - data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); - - /* No probe is scheduled, read gain_F measurement */ - if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { - ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; - type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); - - /* If tx packet is CCK correct the gain_F measurement - * by cck ofdm gain delta */ - if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) { - if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) - ah->ah_gain.g_current += - ee->ee_cck_ofdm_gain_delta; - else - ah->ah_gain.g_current += - AR5K_GAIN_CCK_PROBE_CORR; - } - - /* Further correct gain_F measurement for - * RF5112A radios */ - if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { - ath5k_hw_rf_gainf_corr(ah); - ah->ah_gain.g_current = - ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? - (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : - 0; - } - - /* Check if measurement is ok and if we need - * to adjust gain, schedule a gain adjustment, - * else switch back to the acive state */ - if (ath5k_hw_rf_check_gainf_readback(ah) && - AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && - ath5k_hw_rf_gainf_adjust(ah)) { - ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE; - } else { - ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; - } - } - -done: - return ah->ah_gain.g_state; -} - -/* Write initial rf gain table to set the RF sensitivity - * this one works on all RF chips and has nothing to do - * with gain_F calibration */ -int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq) -{ - const struct ath5k_ini_rfgain *ath5k_rfg; - unsigned int i, size; - - switch (ah->ah_radio) { - case AR5K_RF5111: - ath5k_rfg = rfgain_5111; - size = ARRAY_SIZE(rfgain_5111); - break; - case AR5K_RF5112: - ath5k_rfg = rfgain_5112; - size = ARRAY_SIZE(rfgain_5112); - break; - case AR5K_RF2413: - ath5k_rfg = rfgain_2413; - size = ARRAY_SIZE(rfgain_2413); - break; - case AR5K_RF2316: - ath5k_rfg = rfgain_2316; - size = ARRAY_SIZE(rfgain_2316); - break; - case AR5K_RF5413: - ath5k_rfg = rfgain_5413; - size = ARRAY_SIZE(rfgain_5413); - break; - case AR5K_RF2317: - case AR5K_RF2425: - ath5k_rfg = rfgain_2425; - size = ARRAY_SIZE(rfgain_2425); - break; - default: - return -EINVAL; - } - - switch (freq) { - case AR5K_INI_RFGAIN_2GHZ: - case AR5K_INI_RFGAIN_5GHZ: - break; - default: - return -EINVAL; - } - - for (i = 0; i < size; i++) { - AR5K_REG_WAIT(i); - ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq], - (u32)ath5k_rfg[i].rfg_register); - } - - return 0; -} - - - -/********************\ -* RF Registers setup * -\********************/ - - -/* - * Setup RF registers by writing rf buffer on hw - */ -int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, - unsigned int mode) -{ - const struct ath5k_rf_reg *rf_regs; - const struct ath5k_ini_rfbuffer *ini_rfb; - const struct ath5k_gain_opt *go = NULL; - const struct ath5k_gain_opt_step *g_step; - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u8 ee_mode = 0; - u32 *rfb; - int i, obdb = -1, bank = -1; - - switch (ah->ah_radio) { - case AR5K_RF5111: - rf_regs = rf_regs_5111; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111); - ini_rfb = rfb_5111; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111); - go = &rfgain_opt_5111; - break; - case AR5K_RF5112: - if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { - rf_regs = rf_regs_5112a; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a); - ini_rfb = rfb_5112a; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a); - } else { - rf_regs = rf_regs_5112; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112); - ini_rfb = rfb_5112; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112); - } - go = &rfgain_opt_5112; - break; - case AR5K_RF2413: - rf_regs = rf_regs_2413; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413); - ini_rfb = rfb_2413; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413); - break; - case AR5K_RF2316: - rf_regs = rf_regs_2316; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316); - ini_rfb = rfb_2316; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316); - break; - case AR5K_RF5413: - rf_regs = rf_regs_5413; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413); - ini_rfb = rfb_5413; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413); - break; - case AR5K_RF2317: - rf_regs = rf_regs_2425; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); - ini_rfb = rfb_2317; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317); - break; - case AR5K_RF2425: - rf_regs = rf_regs_2425; - ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425); - if (ah->ah_mac_srev < AR5K_SREV_AR2417) { - ini_rfb = rfb_2425; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425); - } else { - ini_rfb = rfb_2417; - ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417); - } - break; - default: - return -EINVAL; - } - - /* If it's the first time we set rf buffer, allocate - * ah->ah_rf_banks based on ah->ah_rf_banks_size - * we set above */ - if (ah->ah_rf_banks == NULL) { - ah->ah_rf_banks = kmalloc(sizeof(u32) * ah->ah_rf_banks_size, - GFP_KERNEL); - if (ah->ah_rf_banks == NULL) { - ATH5K_ERR(ah->ah_sc, "out of memory\n"); - return -ENOMEM; - } - } - - /* Copy values to modify them */ - rfb = ah->ah_rf_banks; - - for (i = 0; i < ah->ah_rf_banks_size; i++) { - if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) { - ATH5K_ERR(ah->ah_sc, "invalid bank\n"); - return -EINVAL; - } - - /* Bank changed, write down the offset */ - if (bank != ini_rfb[i].rfb_bank) { - bank = ini_rfb[i].rfb_bank; - ah->ah_offset[bank] = i; - } - - rfb[i] = ini_rfb[i].rfb_mode_data[mode]; - } - - /* Set Output and Driver bias current (OB/DB) */ - if (channel->hw_value & CHANNEL_2GHZ) { - - if (channel->hw_value & CHANNEL_CCK) - ee_mode = AR5K_EEPROM_MODE_11B; - else - ee_mode = AR5K_EEPROM_MODE_11G; - - /* For RF511X/RF211X combination we - * use b_OB and b_DB parameters stored - * in eeprom on ee->ee_ob[ee_mode][0] - * - * For all other chips we use OB/DB for 2Ghz - * stored in the b/g modal section just like - * 802.11a on ee->ee_ob[ee_mode][1] */ - if ((ah->ah_radio == AR5K_RF5111) || - (ah->ah_radio == AR5K_RF5112)) - obdb = 0; - else - obdb = 1; - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], - AR5K_RF_OB_2GHZ, true); - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], - AR5K_RF_DB_2GHZ, true); - - /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ - } else if ((channel->hw_value & CHANNEL_5GHZ) || - (ah->ah_radio == AR5K_RF5111)) { - - /* For 11a, Turbo and XR we need to choose - * OB/DB based on frequency range */ - ee_mode = AR5K_EEPROM_MODE_11A; - obdb = channel->center_freq >= 5725 ? 3 : - (channel->center_freq >= 5500 ? 2 : - (channel->center_freq >= 5260 ? 1 : - (channel->center_freq > 4000 ? 0 : -1))); - - if (obdb < 0) - return -EINVAL; - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb], - AR5K_RF_OB_5GHZ, true); - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb], - AR5K_RF_DB_5GHZ, true); - } - - g_step = &go->go_step[ah->ah_gain.g_step_idx]; - - /* Bank Modifications (chip-specific) */ - if (ah->ah_radio == AR5K_RF5111) { - - /* Set gain_F settings according to current step */ - if (channel->hw_value & CHANNEL_OFDM) { - - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, - AR5K_PHY_FRAME_CTL_TX_CLIP, - g_step->gos_param[0]); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], - AR5K_RF_PWD_90, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], - AR5K_RF_PWD_84, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], - AR5K_RF_RFGAIN_SEL, true); - - /* We programmed gain_F parameters, switch back - * to active state */ - ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; - - } - - /* Bank 6/7 setup */ - - ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode], - AR5K_RF_PWD_XPD, true); - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode], - AR5K_RF_XPD_GAIN, true); - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], - AR5K_RF_GAIN_I, true); - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], - AR5K_RF_PLO_SEL, true); - - /* TODO: Half/quarter channel support */ - } - - if (ah->ah_radio == AR5K_RF5112) { - - /* Set gain_F settings according to current step */ - if (channel->hw_value & CHANNEL_OFDM) { - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0], - AR5K_RF_MIXGAIN_OVR, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1], - AR5K_RF_PWD_138, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2], - AR5K_RF_PWD_137, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3], - AR5K_RF_PWD_136, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4], - AR5K_RF_PWD_132, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5], - AR5K_RF_PWD_131, true); - - ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6], - AR5K_RF_PWD_130, true); - - /* We programmed gain_F parameters, switch back - * to active state */ - ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; - } - - /* Bank 6/7 setup */ - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode], - AR5K_RF_XPD_SEL, true); - - if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { - /* Rev. 1 supports only one xpd */ - ath5k_hw_rfb_op(ah, rf_regs, - ee->ee_x_gain[ee_mode], - AR5K_RF_XPD_GAIN, true); - - } else { - /* TODO: Set high and low gain bits */ - ath5k_hw_rfb_op(ah, rf_regs, - ee->ee_x_gain[ee_mode], - AR5K_RF_PD_GAIN_LO, true); - ath5k_hw_rfb_op(ah, rf_regs, - ee->ee_x_gain[ee_mode], - AR5K_RF_PD_GAIN_HI, true); - - /* Lower synth voltage on Rev 2 */ - ath5k_hw_rfb_op(ah, rf_regs, 2, - AR5K_RF_HIGH_VC_CP, true); - - ath5k_hw_rfb_op(ah, rf_regs, 2, - AR5K_RF_MID_VC_CP, true); - - ath5k_hw_rfb_op(ah, rf_regs, 2, - AR5K_RF_LOW_VC_CP, true); - - ath5k_hw_rfb_op(ah, rf_regs, 2, - AR5K_RF_PUSH_UP, true); - - /* Decrease power consumption on 5213+ BaseBand */ - if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { - ath5k_hw_rfb_op(ah, rf_regs, 1, - AR5K_RF_PAD2GND, true); - - ath5k_hw_rfb_op(ah, rf_regs, 1, - AR5K_RF_XB2_LVL, true); - - ath5k_hw_rfb_op(ah, rf_regs, 1, - AR5K_RF_XB5_LVL, true); - - ath5k_hw_rfb_op(ah, rf_regs, 1, - AR5K_RF_PWD_167, true); - - ath5k_hw_rfb_op(ah, rf_regs, 1, - AR5K_RF_PWD_166, true); - } - } - - ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode], - AR5K_RF_GAIN_I, true); - - /* TODO: Half/quarter channel support */ - - } - - if (ah->ah_radio == AR5K_RF5413 && - channel->hw_value & CHANNEL_2GHZ) { - - ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE, - true); - - /* Set optimum value for early revisions (on pci-e chips) */ - if (ah->ah_mac_srev >= AR5K_SREV_AR5424 && - ah->ah_mac_srev < AR5K_SREV_AR5413) - ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3), - AR5K_RF_PWD_ICLOBUF_2G, true); - - } - - /* Write RF banks on hw */ - for (i = 0; i < ah->ah_rf_banks_size; i++) { - AR5K_REG_WAIT(i); - ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register); - } - - return 0; -} - - -/**************************\ - PHY/RF channel functions -\**************************/ - -/* - * Check if a channel is supported - */ -bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags) -{ - /* Check if the channel is in our supported range */ - if (flags & CHANNEL_2GHZ) { - if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && - (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) - return true; - } else if (flags & CHANNEL_5GHZ) - if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && - (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) - return true; - - return false; -} - -/* - * Convertion needed for RF5110 - */ -static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) -{ - u32 athchan; - - /* - * Convert IEEE channel/MHz to an internal channel value used - * by the AR5210 chipset. This has not been verified with - * newer chipsets like the AR5212A who have a completely - * different RF/PHY part. - */ - athchan = (ath5k_hw_bitswap( - (ieee80211_frequency_to_channel( - channel->center_freq) - 24) / 2, 5) - << 1) | (1 << 6) | 0x1; - return athchan; -} - -/* - * Set channel on RF5110 - */ -static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u32 data; - - /* - * Set the channel and wait - */ - data = ath5k_hw_rf5110_chan2athchan(channel); - ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); - ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); - mdelay(1); - - return 0; -} - -/* - * Convertion needed for 5111 - */ -static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, - struct ath5k_athchan_2ghz *athchan) -{ - int channel; - - /* Cast this value to catch negative channel numbers (>= -19) */ - channel = (int)ieee; - - /* - * Map 2GHz IEEE channel to 5GHz Atheros channel - */ - if (channel <= 13) { - athchan->a2_athchan = 115 + channel; - athchan->a2_flags = 0x46; - } else if (channel == 14) { - athchan->a2_athchan = 124; - athchan->a2_flags = 0x44; - } else if (channel >= 15 && channel <= 26) { - athchan->a2_athchan = ((channel - 14) * 4) + 132; - athchan->a2_flags = 0x46; - } else - return -EINVAL; - - return 0; -} - -/* - * Set channel on 5111 - */ -static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - struct ath5k_athchan_2ghz ath5k_channel_2ghz; - unsigned int ath5k_channel = - ieee80211_frequency_to_channel(channel->center_freq); - u32 data0, data1, clock; - int ret; - - /* - * Set the channel on the RF5111 radio - */ - data0 = data1 = 0; - - if (channel->hw_value & CHANNEL_2GHZ) { - /* Map 2GHz channel to 5GHz Atheros channel ID */ - ret = ath5k_hw_rf5111_chan2athchan( - ieee80211_frequency_to_channel(channel->center_freq), - &ath5k_channel_2ghz); - if (ret) - return ret; - - ath5k_channel = ath5k_channel_2ghz.a2_athchan; - data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff) - << 5) | (1 << 4); - } - - if (ath5k_channel < 145 || !(ath5k_channel & 1)) { - clock = 1; - data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) | - (clock << 1) | (1 << 10) | 1; - } else { - clock = 0; - data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff) - << 2) | (clock << 1) | (1 << 10) | 1; - } - - ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8), - AR5K_RF_BUFFER); - ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00), - AR5K_RF_BUFFER_CONTROL_3); - - return 0; -} - -/* - * Set channel on 5112 and newer - */ -static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u32 data, data0, data1, data2; - u16 c; - - data = data0 = data1 = data2 = 0; - c = channel->center_freq; - - if (c < 4800) { - if (!((c - 2224) % 5)) { - data0 = ((2 * (c - 704)) - 3040) / 10; - data1 = 1; - } else if (!((c - 2192) % 5)) { - data0 = ((2 * (c - 672)) - 3040) / 10; - data1 = 0; - } else - return -EINVAL; - - data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); - } else if ((c - (c % 5)) != 2 || c > 5435) { - if (!(c % 20) && c >= 5120) { - data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); - data2 = ath5k_hw_bitswap(3, 2); - } else if (!(c % 10)) { - data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); - data2 = ath5k_hw_bitswap(2, 2); - } else if (!(c % 5)) { - data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); - data2 = ath5k_hw_bitswap(1, 2); - } else - return -EINVAL; - } else { - data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); - data2 = ath5k_hw_bitswap(0, 2); - } - - data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001; - - ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); - ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); - - return 0; -} - -/* - * Set the channel on the RF2425 - */ -static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u32 data, data0, data2; - u16 c; - - data = data0 = data2 = 0; - c = channel->center_freq; - - if (c < 4800) { - data0 = ath5k_hw_bitswap((c - 2272), 8); - data2 = 0; - /* ? 5GHz ? */ - } else if ((c - (c % 5)) != 2 || c > 5435) { - if (!(c % 20) && c < 5120) - data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); - else if (!(c % 10)) - data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); - else if (!(c % 5)) - data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); - else - return -EINVAL; - data2 = ath5k_hw_bitswap(1, 2); - } else { - data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); - data2 = ath5k_hw_bitswap(0, 2); - } - - data = (data0 << 4) | data2 << 2 | 0x1001; - - ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); - ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); - - return 0; -} - -/* - * Set a channel on the radio chip - */ -int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) -{ - int ret; - /* - * Check bounds supported by the PHY (we don't care about regultory - * restrictions at this point). Note: hw_value already has the band - * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok() - * of the band by that */ - if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) { - ATH5K_ERR(ah->ah_sc, - "channel frequency (%u MHz) out of supported " - "band range\n", - channel->center_freq); - return -EINVAL; - } - - /* - * Set the channel and wait - */ - switch (ah->ah_radio) { - case AR5K_RF5110: - ret = ath5k_hw_rf5110_channel(ah, channel); - break; - case AR5K_RF5111: - ret = ath5k_hw_rf5111_channel(ah, channel); - break; - case AR5K_RF2425: - ret = ath5k_hw_rf2425_channel(ah, channel); - break; - default: - ret = ath5k_hw_rf5112_channel(ah, channel); - break; - } - - if (ret) - return ret; - - /* Set JAPAN setting for channel 14 */ - if (channel->center_freq == 2484) { - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, - AR5K_PHY_CCKTXCTL_JAPAN); - } else { - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, - AR5K_PHY_CCKTXCTL_WORLD); - } - - ah->ah_current_channel.center_freq = channel->center_freq; - ah->ah_current_channel.hw_value = channel->hw_value; - ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; - - return 0; -} - -/*****************\ - PHY calibration -\*****************/ - -/** - * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration - * - * @ah: struct ath5k_hw pointer we are operating on - * @freq: the channel frequency, just used for error logging - * - * This function performs a noise floor calibration of the PHY and waits for - * it to complete. Then the noise floor value is compared to some maximum - * noise floor we consider valid. - * - * Note that this is different from what the madwifi HAL does: it reads the - * noise floor and afterwards initiates the calibration. Since the noise floor - * calibration can take some time to finish, depending on the current channel - * use, that avoids the occasional timeout warnings we are seeing now. - * - * See the following link for an Atheros patent on noise floor calibration: - * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ - * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 - * - * XXX: Since during noise floor calibration antennas are detached according to - * the patent, we should stop tx queues here. - */ -int -ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) -{ - int ret; - unsigned int i; - s32 noise_floor; - - /* - * Enable noise floor calibration - */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_NF); - - ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_NF, 0, false); - if (ret) { - ATH5K_ERR(ah->ah_sc, - "noise floor calibration timeout (%uMHz)\n", freq); - return -EAGAIN; - } - - /* Wait until the noise floor is calibrated and read the value */ - for (i = 20; i > 0; i--) { - mdelay(1); - noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); - noise_floor = AR5K_PHY_NF_RVAL(noise_floor); - if (noise_floor & AR5K_PHY_NF_ACTIVE) { - noise_floor = AR5K_PHY_NF_AVAL(noise_floor); - - if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) - break; - } - } - - ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, - "noise floor %d\n", noise_floor); - - if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { - ATH5K_ERR(ah->ah_sc, - "noise floor calibration failed (%uMHz)\n", freq); - return -EAGAIN; - } - - ah->ah_noise_floor = noise_floor; - - return 0; -} - -/* - * Perform a PHY calibration on RF5110 - * -Fix BPSK/QAM Constellation (I/Q correction) - * -Calculate Noise Floor - */ -static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u32 phy_sig, phy_agc, phy_sat, beacon; - int ret; - - /* - * Disable beacons and RX/TX queues, wait - */ - AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, - AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); - beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); - ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - - mdelay(2); - - /* - * Set the channel (with AGC turned off) - */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); - udelay(10); - ret = ath5k_hw_channel(ah, channel); - - /* - * Activate PHY and wait - */ - ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - mdelay(1); - - AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); - - if (ret) - return ret; - - /* - * Calibrate the radio chip - */ - - /* Remember normal state */ - phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG); - phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE); - phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT); - - /* Update radio registers */ - ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) | - AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG); - - ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI | - AR5K_PHY_AGCCOARSE_LO)) | - AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) | - AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE); - - ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT | - AR5K_PHY_ADCSAT_THR)) | - AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) | - AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT); - - udelay(20); - - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); - udelay(10); - ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); - AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); - - mdelay(1); - - /* - * Enable calibration and wait until completion - */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL); - - ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL, 0, false); - - /* Reset to normal state */ - ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG); - ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE); - ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT); - - if (ret) { - ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", - channel->center_freq); - return ret; - } - - ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - - /* - * Re-enable RX/TX and beacons - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, - AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); - ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210); - - return 0; -} - -/* - * Perform a PHY calibration on RF5111/5112 and newer chips - */ -static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u32 i_pwr, q_pwr; - s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; - int i; - ATH5K_TRACE(ah->ah_sc); - - if (!ah->ah_calibration || - ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) - goto done; - - /* Calibration has finished, get the results and re-run */ - for (i = 0; i <= 10; i++) { - iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); - i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); - q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); - } - - i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; - q_coffd = q_pwr >> 7; - - /* No correction */ - if (i_coffd == 0 || q_coffd == 0) - goto done; - - i_coff = ((-iq_corr) / i_coffd) & 0x3f; - - /* Boundary check */ - if (i_coff > 31) - i_coff = 31; - if (i_coff < -32) - i_coff = -32; - - q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f; - - /* Boundary check */ - if (q_coff > 15) - q_coff = 15; - if (q_coff < -16) - q_coff = -16; - - /* Commit new I/Q value */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | - ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); - - /* Re-enable calibration -if we don't we'll commit - * the same values again and again */ - 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); - -done: - - /* TODO: Separate noise floor calibration from I/Q calibration - * since noise floor calibration interrupts rx path while I/Q - * calibration doesn't. We don't need to run noise floor calibration - * as often as I/Q calibration.*/ - ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - - /* Initiate a gain_F calibration */ - ath5k_hw_request_rfgain_probe(ah); - - return 0; -} - -/* - * Perform a PHY calibration - */ -int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - int ret; - - if (ah->ah_radio == AR5K_RF5110) - ret = ath5k_hw_rf5110_calibrate(ah, channel); - else - ret = ath5k_hw_rf511x_calibrate(ah, channel); - - return ret; -} - -int ath5k_hw_phy_disable(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - /*Just a try M.F.*/ - ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); - - return 0; -} - -/********************\ - Misc PHY functions -\********************/ - -/* - * Get the PHY Chip revision - */ -u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) -{ - unsigned int i; - u32 srev; - u16 ret; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Set the radio chip access register - */ - switch (chan) { - case CHANNEL_2GHZ: - ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); - break; - case CHANNEL_5GHZ: - ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); - break; - default: - return 0; - } - - mdelay(2); - - /* ...wait until PHY is ready and read the selected radio revision */ - ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34)); - - for (i = 0; i < 8; i++) - ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); - - if (ah->ah_version == AR5K_AR5210) { - srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; - ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; - } else { - srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; - ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) | - ((srev & 0x0f) << 4), 8); - } - - /* Reset to the 5GHz mode */ - ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); - - return ret; -} - -void /*TODO:Boundary check*/ -ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant) -{ - ATH5K_TRACE(ah->ah_sc); - /*Just a try M.F.*/ - if (ah->ah_version != AR5K_AR5210) - ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA); -} - -unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - /*Just a try M.F.*/ - if (ah->ah_version != AR5K_AR5210) - return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); - - return false; /*XXX: What do we return for 5210 ?*/ -} - - -/****************\ -* TX power setup * -\****************/ - -/* - * Helper functions - */ - -/* - * Do linear interpolation between two given (x, y) points - */ -static s16 -ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, - s16 y_left, s16 y_right) -{ - s16 ratio, result; - - /* Avoid divide by zero and skip interpolation - * if we have the same point */ - if ((x_left == x_right) || (y_left == y_right)) - return y_left; - - /* - * Since we use ints and not fps, we need to scale up in - * order to get a sane ratio value (or else we 'll eg. get - * always 1 instead of 1.25, 1.75 etc). We scale up by 100 - * to have some accuracy both for 0.5 and 0.25 steps. - */ - ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left)); - - /* Now scale down to be in range */ - result = y_left + (ratio * (target - x_left) / 100); - - return result; -} - -/* - * Find vertical boundary (min pwr) for the linear PCDAC curve. - * - * Since we have the top of the curve and we draw the line below - * until we reach 1 (1 pcdac step) we need to know which point - * (x value) that is so that we don't go below y axis and have negative - * pcdac values when creating the curve, or fill the table with zeroes. - */ -static s16 -ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, - const s16 *pwrL, const s16 *pwrR) -{ - s8 tmp; - s16 min_pwrL, min_pwrR; - s16 pwr_i = pwrL[0]; - - do { - pwr_i--; - tmp = (s8) ath5k_get_interpolated_value(pwr_i, - pwrL[0], pwrL[1], - stepL[0], stepL[1]); - - } while (tmp > 1); - - min_pwrL = pwr_i; - - pwr_i = pwrR[0]; - do { - pwr_i--; - tmp = (s8) ath5k_get_interpolated_value(pwr_i, - pwrR[0], pwrR[1], - stepR[0], stepR[1]); - - } while (tmp > 1); - - min_pwrR = pwr_i; - - /* Keep the right boundary so that it works for both curves */ - return max(min_pwrL, min_pwrR); -} - -/* - * Interpolate (pwr,vpd) points to create a Power to PDADC or a - * Power to PCDAC curve. - * - * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC - * steps (offsets) on y axis. Power can go up to 31.5dB and max - * PCDAC/PDADC step for each curve is 64 but we can write more than - * one curves on hw so we can go up to 128 (which is the max step we - * can write on the final table). - * - * We write y values (PCDAC/PDADC steps) on hw. - */ -static void -ath5k_create_power_curve(s16 pmin, s16 pmax, - const s16 *pwr, const u8 *vpd, - u8 num_points, - u8 *vpd_table, u8 type) -{ - u8 idx[2] = { 0, 1 }; - s16 pwr_i = 2*pmin; - int i; - - if (num_points < 2) - return; - - /* We want the whole line, so adjust boundaries - * to cover the entire power range. Note that - * power values are already 0.25dB so no need - * to multiply pwr_i by 2 */ - if (type == AR5K_PWRTABLE_LINEAR_PCDAC) { - pwr_i = pmin; - pmin = 0; - pmax = 63; - } - - /* Find surrounding turning points (TPs) - * and interpolate between them */ - for (i = 0; (i <= (u16) (pmax - pmin)) && - (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { - - /* We passed the right TP, move to the next set of TPs - * if we pass the last TP, extrapolate above using the last - * two TPs for ratio */ - if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) { - idx[0]++; - idx[1]++; - } - - vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i, - pwr[idx[0]], pwr[idx[1]], - vpd[idx[0]], vpd[idx[1]]); - - /* Increase by 0.5dB - * (0.25 dB units) */ - pwr_i += 2; - } -} - -/* - * Get the surrounding per-channel power calibration piers - * for a given frequency so that we can interpolate between - * them and come up with an apropriate dataset for our current - * channel. - */ -static void -ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, - struct ieee80211_channel *channel, - struct ath5k_chan_pcal_info **pcinfo_l, - struct ath5k_chan_pcal_info **pcinfo_r) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *pcinfo; - u8 idx_l, idx_r; - u8 mode, max, i; - u32 target = channel->center_freq; - - idx_l = 0; - idx_r = 0; - - if (!(channel->hw_value & CHANNEL_OFDM)) { - pcinfo = ee->ee_pwr_cal_b; - mode = AR5K_EEPROM_MODE_11B; - } else if (channel->hw_value & CHANNEL_2GHZ) { - pcinfo = ee->ee_pwr_cal_g; - mode = AR5K_EEPROM_MODE_11G; - } else { - pcinfo = ee->ee_pwr_cal_a; - mode = AR5K_EEPROM_MODE_11A; - } - max = ee->ee_n_piers[mode] - 1; - - /* Frequency is below our calibrated - * range. Use the lowest power curve - * we have */ - if (target < pcinfo[0].freq) { - idx_l = idx_r = 0; - goto done; - } - - /* Frequency is above our calibrated - * range. Use the highest power curve - * we have */ - if (target > pcinfo[max].freq) { - idx_l = idx_r = max; - goto done; - } - - /* Frequency is inside our calibrated - * channel range. Pick the surrounding - * calibration piers so that we can - * interpolate */ - for (i = 0; i <= max; i++) { - - /* Frequency matches one of our calibration - * piers, no need to interpolate, just use - * that calibration pier */ - if (pcinfo[i].freq == target) { - idx_l = idx_r = i; - goto done; - } - - /* We found a calibration pier that's above - * frequency, use this pier and the previous - * one to interpolate */ - if (target < pcinfo[i].freq) { - idx_r = i; - idx_l = idx_r - 1; - goto done; - } - } - -done: - *pcinfo_l = &pcinfo[idx_l]; - *pcinfo_r = &pcinfo[idx_r]; - - return; -} - -/* - * Get the surrounding per-rate power calibration data - * for a given frequency and interpolate between power - * values to set max target power supported by hw for - * each rate. - */ -static void -ath5k_get_rate_pcal_data(struct ath5k_hw *ah, - struct ieee80211_channel *channel, - struct ath5k_rate_pcal_info *rates) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_rate_pcal_info *rpinfo; - u8 idx_l, idx_r; - u8 mode, max, i; - u32 target = channel->center_freq; - - idx_l = 0; - idx_r = 0; - - if (!(channel->hw_value & CHANNEL_OFDM)) { - rpinfo = ee->ee_rate_tpwr_b; - mode = AR5K_EEPROM_MODE_11B; - } else if (channel->hw_value & CHANNEL_2GHZ) { - rpinfo = ee->ee_rate_tpwr_g; - mode = AR5K_EEPROM_MODE_11G; - } else { - rpinfo = ee->ee_rate_tpwr_a; - mode = AR5K_EEPROM_MODE_11A; - } - max = ee->ee_rate_target_pwr_num[mode] - 1; - - /* Get the surrounding calibration - * piers - same as above */ - if (target < rpinfo[0].freq) { - idx_l = idx_r = 0; - goto done; - } - - if (target > rpinfo[max].freq) { - idx_l = idx_r = max; - goto done; - } - - for (i = 0; i <= max; i++) { - - if (rpinfo[i].freq == target) { - idx_l = idx_r = i; - goto done; - } - - if (target < rpinfo[i].freq) { - idx_r = i; - idx_l = idx_r - 1; - goto done; - } - } - -done: - /* Now interpolate power value, based on the frequency */ - rates->freq = target; - - rates->target_power_6to24 = - ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, - rpinfo[idx_r].freq, - rpinfo[idx_l].target_power_6to24, - rpinfo[idx_r].target_power_6to24); - - rates->target_power_36 = - ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, - rpinfo[idx_r].freq, - rpinfo[idx_l].target_power_36, - rpinfo[idx_r].target_power_36); - - rates->target_power_48 = - ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, - rpinfo[idx_r].freq, - rpinfo[idx_l].target_power_48, - rpinfo[idx_r].target_power_48); - - rates->target_power_54 = - ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, - rpinfo[idx_r].freq, - rpinfo[idx_l].target_power_54, - rpinfo[idx_r].target_power_54); -} - -/* - * Get the max edge power for this channel if - * we have such data from EEPROM's Conformance Test - * Limits (CTL), and limit max power if needed. - * - * FIXME: Only works for world regulatory domains - */ -static void -ath5k_get_max_ctl_power(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_edge_power *rep = ee->ee_ctl_pwr; - u8 *ctl_val = ee->ee_ctl; - s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4; - s16 edge_pwr = 0; - u8 rep_idx; - u8 i, ctl_mode; - u8 ctl_idx = 0xFF; - u32 target = channel->center_freq; - - /* Find out a CTL for our mode that's not mapped - * on a specific reg domain. - * - * TODO: Map our current reg domain to one of the 3 available - * reg domain ids so that we can support more CTLs. */ - switch (channel->hw_value & CHANNEL_MODES) { - case CHANNEL_A: - ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN; - break; - case CHANNEL_G: - ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN; - break; - case CHANNEL_B: - ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN; - break; - case CHANNEL_T: - ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN; - break; - case CHANNEL_TG: - ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN; - break; - case CHANNEL_XR: - /* Fall through */ - default: - return; - } - - for (i = 0; i < ee->ee_ctls; i++) { - if (ctl_val[i] == ctl_mode) { - ctl_idx = i; - break; - } - } - - /* If we have a CTL dataset available grab it and find the - * edge power for our frequency */ - if (ctl_idx == 0xFF) - return; - - /* Edge powers are sorted by frequency from lower - * to higher. Each CTL corresponds to 8 edge power - * measurements. */ - rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES; - - /* Don't do boundaries check because we - * might have more that one bands defined - * for this mode */ - - /* Get the edge power that's closer to our - * frequency */ - for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) { - rep_idx += i; - if (target <= rep[rep_idx].freq) - edge_pwr = (s16) rep[rep_idx].edge; - } - - if (edge_pwr) - ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr); -} - - -/* - * Power to PCDAC table functions - */ - -/* - * Fill Power to PCDAC table on RF5111 - * - * No further processing is needed for RF5111, the only thing we have to - * do is fill the values below and above calibration range since eeprom data - * may not cover the entire PCDAC table. - */ -static void -ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, - s16 *table_max) -{ - u8 *pcdac_out = ah->ah_txpower.txp_pd_table; - u8 *pcdac_tmp = ah->ah_txpower.tmpL[0]; - u8 pcdac_0, pcdac_n, pcdac_i, pwr_idx, i; - s16 min_pwr, max_pwr; - - /* Get table boundaries */ - min_pwr = table_min[0]; - pcdac_0 = pcdac_tmp[0]; - - max_pwr = table_max[0]; - pcdac_n = pcdac_tmp[table_max[0] - table_min[0]]; - - /* Extrapolate below minimum using pcdac_0 */ - pcdac_i = 0; - for (i = 0; i < min_pwr; i++) - pcdac_out[pcdac_i++] = pcdac_0; - - /* Copy values from pcdac_tmp */ - pwr_idx = min_pwr; - for (i = 0 ; pwr_idx <= max_pwr && - pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) { - pcdac_out[pcdac_i++] = pcdac_tmp[i]; - pwr_idx++; - } - - /* Extrapolate above maximum */ - while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE) - pcdac_out[pcdac_i++] = pcdac_n; - -} - -/* - * Combine available XPD Curves and fill Linear Power to PCDAC table - * on RF5112 - * - * RFX112 can have up to 2 curves (one for low txpower range and one for - * higher txpower range). We need to put them both on pcdac_out and place - * them in the correct location. In case we only have one curve available - * just fit it on pcdac_out (it's supposed to cover the entire range of - * available pwr levels since it's always the higher power curve). Extrapolate - * below and above final table if needed. - */ -static void -ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, - s16 *table_max, u8 pdcurves) -{ - u8 *pcdac_out = ah->ah_txpower.txp_pd_table; - u8 *pcdac_low_pwr; - u8 *pcdac_high_pwr; - u8 *pcdac_tmp; - u8 pwr; - s16 max_pwr_idx; - s16 min_pwr_idx; - s16 mid_pwr_idx = 0; - /* Edge flag turs on the 7nth bit on the PCDAC - * to delcare the higher power curve (force values - * to be greater than 64). If we only have one curve - * we don't need to set this, if we have 2 curves and - * fill the table backwards this can also be used to - * switch from higher power curve to lower power curve */ - u8 edge_flag; - int i; - - /* When we have only one curve available - * that's the higher power curve. If we have - * two curves the first is the high power curve - * and the next is the low power curve. */ - if (pdcurves > 1) { - pcdac_low_pwr = ah->ah_txpower.tmpL[1]; - pcdac_high_pwr = ah->ah_txpower.tmpL[0]; - mid_pwr_idx = table_max[1] - table_min[1] - 1; - max_pwr_idx = (table_max[0] - table_min[0]) / 2; - - /* If table size goes beyond 31.5dB, keep the - * upper 31.5dB range when setting tx power. - * Note: 126 = 31.5 dB in quarter dB steps */ - if (table_max[0] - table_min[1] > 126) - min_pwr_idx = table_max[0] - 126; - else - min_pwr_idx = table_min[1]; - - /* Since we fill table backwards - * start from high power curve */ - pcdac_tmp = pcdac_high_pwr; - - edge_flag = 0x40; -#if 0 - /* If both min and max power limits are in lower - * power curve's range, only use the low power curve. - * TODO: min/max levels are related to target - * power values requested from driver/user - * XXX: Is this really needed ? */ - if (min_pwr < table_max[1] && - max_pwr < table_max[1]) { - edge_flag = 0; - pcdac_tmp = pcdac_low_pwr; - max_pwr_idx = (table_max[1] - table_min[1])/2; - } -#endif - } else { - pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */ - pcdac_high_pwr = ah->ah_txpower.tmpL[0]; - min_pwr_idx = table_min[0]; - max_pwr_idx = (table_max[0] - table_min[0]) / 2; - pcdac_tmp = pcdac_high_pwr; - edge_flag = 0; - } - - /* This is used when setting tx power*/ - ah->ah_txpower.txp_min_idx = min_pwr_idx/2; - - /* Fill Power to PCDAC table backwards */ - pwr = max_pwr_idx; - for (i = 63; i >= 0; i--) { - /* Entering lower power range, reset - * edge flag and set pcdac_tmp to lower - * power curve.*/ - if (edge_flag == 0x40 && - (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) { - edge_flag = 0x00; - pcdac_tmp = pcdac_low_pwr; - pwr = mid_pwr_idx/2; - } - - /* Don't go below 1, extrapolate below if we have - * already swithced to the lower power curve -or - * we only have one curve and edge_flag is zero - * anyway */ - if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) { - while (i >= 0) { - pcdac_out[i] = pcdac_out[i + 1]; - i--; - } - break; - } - - pcdac_out[i] = pcdac_tmp[pwr] | edge_flag; - - /* Extrapolate above if pcdac is greater than - * 126 -this can happen because we OR pcdac_out - * value with edge_flag on high power curve */ - if (pcdac_out[i] > 126) - pcdac_out[i] = 126; - - /* Decrease by a 0.5dB step */ - pwr--; - } -} - -/* Write PCDAC values on hw */ -static void -ath5k_setup_pcdac_table(struct ath5k_hw *ah) -{ - u8 *pcdac_out = ah->ah_txpower.txp_pd_table; - int i; - - /* - * Write TX power values - */ - for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { - ath5k_hw_reg_write(ah, - (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) | - (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16), - AR5K_PHY_PCDAC_TXPOWER(i)); - } -} - - -/* - * Power to PDADC table functions - */ - -/* - * Set the gain boundaries and create final Power to PDADC table - * - * We can have up to 4 pd curves, we need to do a simmilar process - * as we do for RF5112. This time we don't have an edge_flag but we - * set the gain boundaries on a separate register. - */ -static void -ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, - s16 *pwr_min, s16 *pwr_max, u8 pdcurves) -{ - u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS]; - u8 *pdadc_out = ah->ah_txpower.txp_pd_table; - u8 *pdadc_tmp; - s16 pdadc_0; - u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size; - u8 pd_gain_overlap; - - /* Note: Register value is initialized on initvals - * there is no feedback from hw. - * XXX: What about pd_gain_overlap from EEPROM ? */ - pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) & - AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP; - - /* Create final PDADC table */ - for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) { - pdadc_tmp = ah->ah_txpower.tmpL[pdg]; - - if (pdg == pdcurves - 1) - /* 2 dB boundary stretch for last - * (higher power) curve */ - gain_boundaries[pdg] = pwr_max[pdg] + 4; - else - /* Set gain boundary in the middle - * between this curve and the next one */ - gain_boundaries[pdg] = - (pwr_max[pdg] + pwr_min[pdg + 1]) / 2; - - /* Sanity check in case our 2 db stretch got out of - * range. */ - if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER) - gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER; - - /* For the first curve (lower power) - * start from 0 dB */ - if (pdg == 0) - pdadc_0 = 0; - else - /* For the other curves use the gain overlap */ - pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) - - pd_gain_overlap; - - /* Force each power step to be at least 0.5 dB */ - if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1) - pwr_step = pdadc_tmp[1] - pdadc_tmp[0]; - else - pwr_step = 1; - - /* If pdadc_0 is negative, we need to extrapolate - * below this pdgain by a number of pwr_steps */ - while ((pdadc_0 < 0) && (pdadc_i < 128)) { - s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step; - pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp; - pdadc_0++; - } - - /* Set last pwr level, using gain boundaries */ - pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg]; - /* Limit it to be inside pwr range */ - table_size = pwr_max[pdg] - pwr_min[pdg]; - max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; - - /* Fill pdadc_out table */ - while (pdadc_0 < max_idx) - pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; - - /* Need to extrapolate above this pdgain? */ - if (pdadc_n <= max_idx) - continue; - - /* Force each power step to be at least 0.5 dB */ - if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1) - pwr_step = pdadc_tmp[table_size - 1] - - pdadc_tmp[table_size - 2]; - else - pwr_step = 1; - - /* Extrapolate above */ - while ((pdadc_0 < (s16) pdadc_n) && - (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) { - s16 tmp = pdadc_tmp[table_size - 1] + - (pdadc_0 - max_idx) * pwr_step; - pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp; - pdadc_0++; - } - } - - while (pdg < AR5K_EEPROM_N_PD_GAINS) { - gain_boundaries[pdg] = gain_boundaries[pdg - 1]; - pdg++; - } - - while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) { - pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1]; - pdadc_i++; - } - - /* Set gain boundaries */ - ath5k_hw_reg_write(ah, - AR5K_REG_SM(pd_gain_overlap, - AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) | - AR5K_REG_SM(gain_boundaries[0], - AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) | - AR5K_REG_SM(gain_boundaries[1], - AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) | - AR5K_REG_SM(gain_boundaries[2], - AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) | - AR5K_REG_SM(gain_boundaries[3], - AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4), - AR5K_PHY_TPC_RG5); - - /* Used for setting rate power table */ - ah->ah_txpower.txp_min_idx = pwr_min[0]; - -} - -/* Write PDADC values on hw */ -static void -ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah, - u8 pdcurves, u8 *pdg_to_idx) -{ - u8 *pdadc_out = ah->ah_txpower.txp_pd_table; - u32 reg; - u8 i; - - /* Select the right pdgain curves */ - - /* Clear current settings */ - reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1); - reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 | - AR5K_PHY_TPC_RG1_PDGAIN_2 | - AR5K_PHY_TPC_RG1_PDGAIN_3 | - AR5K_PHY_TPC_RG1_NUM_PD_GAIN); - - /* - * Use pd_gains curve from eeprom - * - * This overrides the default setting from initvals - * in case some vendors (e.g. Zcomax) don't use the default - * curves. If we don't honor their settings we 'll get a - * 5dB (1 * gain overlap ?) drop. - */ - reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN); - - switch (pdcurves) { - case 3: - reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3); - /* Fall through */ - case 2: - reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2); - /* Fall through */ - case 1: - reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1); - break; - } - ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1); - - /* - * Write TX power values - */ - for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { - ath5k_hw_reg_write(ah, - ((pdadc_out[4*i + 0] & 0xff) << 0) | - ((pdadc_out[4*i + 1] & 0xff) << 8) | - ((pdadc_out[4*i + 2] & 0xff) << 16) | - ((pdadc_out[4*i + 3] & 0xff) << 24), - AR5K_PHY_PDADC_TXPOWER(i)); - } -} - - -/* - * Common code for PCDAC/PDADC tables - */ - -/* - * This is the main function that uses all of the above - * to set PCDAC/PDADC table on hw for the current channel. - * This table is used for tx power calibration on the basband, - * without it we get weird tx power levels and in some cases - * distorted spectral mask - */ -static int -ath5k_setup_channel_powertable(struct ath5k_hw *ah, - struct ieee80211_channel *channel, - u8 ee_mode, u8 type) -{ - struct ath5k_pdgain_info *pdg_L, *pdg_R; - struct ath5k_chan_pcal_info *pcinfo_L; - struct ath5k_chan_pcal_info *pcinfo_R; - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; - s16 table_min[AR5K_EEPROM_N_PD_GAINS]; - s16 table_max[AR5K_EEPROM_N_PD_GAINS]; - u8 *tmpL; - u8 *tmpR; - u32 target = channel->center_freq; - int pdg, i; - - /* Get surounding freq piers for this channel */ - ath5k_get_chan_pcal_surrounding_piers(ah, channel, - &pcinfo_L, - &pcinfo_R); - - /* Loop over pd gain curves on - * surounding freq piers by index */ - for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) { - - /* Fill curves in reverse order - * from lower power (max gain) - * to higher power. Use curve -> idx - * backmaping we did on eeprom init */ - u8 idx = pdg_curve_to_idx[pdg]; - - /* Grab the needed curves by index */ - pdg_L = &pcinfo_L->pd_curves[idx]; - pdg_R = &pcinfo_R->pd_curves[idx]; - - /* Initialize the temp tables */ - tmpL = ah->ah_txpower.tmpL[pdg]; - tmpR = ah->ah_txpower.tmpR[pdg]; - - /* Set curve's x boundaries and create - * curves so that they cover the same - * range (if we don't do that one table - * will have values on some range and the - * other one won't have any so interpolation - * will fail) */ - table_min[pdg] = min(pdg_L->pd_pwr[0], - pdg_R->pd_pwr[0]) / 2; - - table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1], - pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2; - - /* Now create the curves on surrounding channels - * and interpolate if needed to get the final - * curve for this gain on this channel */ - switch (type) { - case AR5K_PWRTABLE_LINEAR_PCDAC: - /* Override min/max so that we don't loose - * accuracy (don't divide by 2) */ - table_min[pdg] = min(pdg_L->pd_pwr[0], - pdg_R->pd_pwr[0]); - - table_max[pdg] = - max(pdg_L->pd_pwr[pdg_L->pd_points - 1], - pdg_R->pd_pwr[pdg_R->pd_points - 1]); - - /* Override minimum so that we don't get - * out of bounds while extrapolating - * below. Don't do this when we have 2 - * curves and we are on the high power curve - * because table_min is ok in this case */ - if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) { - - table_min[pdg] = - ath5k_get_linear_pcdac_min(pdg_L->pd_step, - pdg_R->pd_step, - pdg_L->pd_pwr, - pdg_R->pd_pwr); - - /* Don't go too low because we will - * miss the upper part of the curve. - * Note: 126 = 31.5dB (max power supported) - * in 0.25dB units */ - if (table_max[pdg] - table_min[pdg] > 126) - table_min[pdg] = table_max[pdg] - 126; - } - - /* Fall through */ - case AR5K_PWRTABLE_PWR_TO_PCDAC: - case AR5K_PWRTABLE_PWR_TO_PDADC: - - ath5k_create_power_curve(table_min[pdg], - table_max[pdg], - pdg_L->pd_pwr, - pdg_L->pd_step, - pdg_L->pd_points, tmpL, type); - - /* We are in a calibration - * pier, no need to interpolate - * between freq piers */ - if (pcinfo_L == pcinfo_R) - continue; - - ath5k_create_power_curve(table_min[pdg], - table_max[pdg], - pdg_R->pd_pwr, - pdg_R->pd_step, - pdg_R->pd_points, tmpR, type); - break; - default: - return -EINVAL; - } - - /* Interpolate between curves - * of surounding freq piers to - * get the final curve for this - * pd gain. Re-use tmpL for interpolation - * output */ - for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) && - (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { - tmpL[i] = (u8) ath5k_get_interpolated_value(target, - (s16) pcinfo_L->freq, - (s16) pcinfo_R->freq, - (s16) tmpL[i], - (s16) tmpR[i]); - } - } - - /* Now we have a set of curves for this - * channel on tmpL (x range is table_max - table_min - * and y values are tmpL[pdg][]) sorted in the same - * order as EEPROM (because we've used the backmaping). - * So for RF5112 it's from higher power to lower power - * and for RF2413 it's from lower power to higher power. - * For RF5111 we only have one curve. */ - - /* Fill min and max power levels for this - * channel by interpolating the values on - * surounding channels to complete the dataset */ - ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target, - (s16) pcinfo_L->freq, - (s16) pcinfo_R->freq, - pcinfo_L->min_pwr, pcinfo_R->min_pwr); - - ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target, - (s16) pcinfo_L->freq, - (s16) pcinfo_R->freq, - pcinfo_L->max_pwr, pcinfo_R->max_pwr); - - /* We are ready to go, fill PCDAC/PDADC - * table and write settings on hardware */ - switch (type) { - case AR5K_PWRTABLE_LINEAR_PCDAC: - /* For RF5112 we can have one or two curves - * and each curve covers a certain power lvl - * range so we need to do some more processing */ - ath5k_combine_linear_pcdac_curves(ah, table_min, table_max, - ee->ee_pd_gains[ee_mode]); - - /* Set txp.offset so that we can - * match max power value with max - * table index */ - ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2); - - /* Write settings on hw */ - ath5k_setup_pcdac_table(ah); - break; - case AR5K_PWRTABLE_PWR_TO_PCDAC: - /* We are done for RF5111 since it has only - * one curve, just fit the curve on the table */ - ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max); - - /* No rate powertable adjustment for RF5111 */ - ah->ah_txpower.txp_min_idx = 0; - ah->ah_txpower.txp_offset = 0; - - /* Write settings on hw */ - ath5k_setup_pcdac_table(ah); - break; - case AR5K_PWRTABLE_PWR_TO_PDADC: - /* Set PDADC boundaries and fill - * final PDADC table */ - ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max, - ee->ee_pd_gains[ee_mode]); - - /* Write settings on hw */ - ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx); - - /* Set txp.offset, note that table_min - * can be negative */ - ah->ah_txpower.txp_offset = table_min[0]; - break; - default: - return -EINVAL; - } - - return 0; -} - - -/* - * Per-rate tx power setting - * - * This is the code that sets the desired tx power (below - * maximum) on hw for each rate (we also have TPC that sets - * power per packet). We do that by providing an index on the - * PCDAC/PDADC table we set up. - */ - -/* - * Set rate power table - * - * For now we only limit txpower based on maximum tx power - * supported by hw (what's inside rate_info). We need to limit - * this even more, based on regulatory domain etc. - * - * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps) - * and is indexed as follows: - * rates[0] - rates[7] -> OFDM rates - * rates[8] - rates[14] -> CCK rates - * rates[15] -> XR rates (they all have the same power) - */ -static void -ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, - struct ath5k_rate_pcal_info *rate_info, - u8 ee_mode) -{ - unsigned int i; - u16 *rates; - - /* max_pwr is power level we got from driver/user in 0.5dB - * units, switch to 0.25dB units so we can compare */ - max_pwr *= 2; - max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2; - - /* apply rate limits */ - rates = ah->ah_txpower.txp_rates_power_table; - - /* OFDM rates 6 to 24Mb/s */ - for (i = 0; i < 5; i++) - rates[i] = min(max_pwr, rate_info->target_power_6to24); - - /* Rest OFDM rates */ - rates[5] = min(rates[0], rate_info->target_power_36); - rates[6] = min(rates[0], rate_info->target_power_48); - rates[7] = min(rates[0], rate_info->target_power_54); - - /* CCK rates */ - /* 1L */ - rates[8] = min(rates[0], rate_info->target_power_6to24); - /* 2L */ - rates[9] = min(rates[0], rate_info->target_power_36); - /* 2S */ - rates[10] = min(rates[0], rate_info->target_power_36); - /* 5L */ - rates[11] = min(rates[0], rate_info->target_power_48); - /* 5S */ - rates[12] = min(rates[0], rate_info->target_power_48); - /* 11L */ - rates[13] = min(rates[0], rate_info->target_power_54); - /* 11S */ - rates[14] = min(rates[0], rate_info->target_power_54); - - /* XR rates */ - rates[15] = min(rates[0], rate_info->target_power_6to24); - - /* CCK rates have different peak to average ratio - * so we have to tweak their power so that gainf - * correction works ok. For this we use OFDM to - * CCK delta from eeprom */ - if ((ee_mode == AR5K_EEPROM_MODE_11G) && - (ah->ah_phy_revision < AR5K_SREV_PHY_5212A)) - for (i = 8; i <= 15; i++) - rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; - - ah->ah_txpower.txp_min_pwr = rates[7]; - ah->ah_txpower.txp_max_pwr = rates[0]; - ah->ah_txpower.txp_ofdm = rates[7]; -} - - -/* - * Set transmition power - */ -int -ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, - u8 ee_mode, u8 txpower) -{ - struct ath5k_rate_pcal_info rate_info; - u8 type; - int ret; - - ATH5K_TRACE(ah->ah_sc); - if (txpower > AR5K_TUNE_MAX_TXPOWER) { - ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); - return -EINVAL; - } - if (txpower == 0) - txpower = AR5K_TUNE_DEFAULT_TXPOWER; - - /* Reset TX power values */ - memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); - ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; - ah->ah_txpower.txp_min_pwr = 0; - ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER; - - /* Initialize TX power table */ - switch (ah->ah_radio) { - case AR5K_RF5111: - type = AR5K_PWRTABLE_PWR_TO_PCDAC; - break; - case AR5K_RF5112: - type = AR5K_PWRTABLE_LINEAR_PCDAC; - break; - case AR5K_RF2413: - case AR5K_RF5413: - case AR5K_RF2316: - case AR5K_RF2317: - case AR5K_RF2425: - type = AR5K_PWRTABLE_PWR_TO_PDADC; - break; - default: - return -EINVAL; - } - - /* FIXME: Only on channel/mode change */ - ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type); - if (ret) - return ret; - - /* Limit max power if we have a CTL available */ - ath5k_get_max_ctl_power(ah, channel); - - /* FIXME: Tx power limit for this regdomain - * XXX: Mac80211/CRDA will do that anyway ? */ - - /* FIXME: Antenna reduction stuff */ - - /* FIXME: Limit power on turbo modes */ - - /* FIXME: TPC scale reduction */ - - /* Get surounding channels for per-rate power table - * calibration */ - ath5k_get_rate_pcal_data(ah, channel, &rate_info); - - /* Setup rate power table */ - ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode); - - /* Write rate power table on hw */ - ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | - AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | - AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); - - ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) | - AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) | - AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2); - - ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) | - AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) | - AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3); - - ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) | - AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | - AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); - - /* FIXME: TPC support */ - if (ah->ah_txpower.txp_tpc) { - ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | - AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); - - ath5k_hw_reg_write(ah, - AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) | - AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) | - AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), - AR5K_TPC); - } else { - ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | - AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); - } - - return 0; -} - -int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower) -{ - /*Just a try M.F.*/ - struct ieee80211_channel *channel = &ah->ah_current_channel; - - ATH5K_TRACE(ah->ah_sc); - ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, - "changing txpower to %d\n", txpower); - - return ath5k_hw_txpower(ah, channel, mode, txpower); -} - -#undef _ATH5K_PHY diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c deleted file mode 100644 index 5094c39..0000000 --- a/drivers/net/wireless/ath5k/qcu.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * - * 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) -{ - u32 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 false; - - /* XXX: How about AR5K_CFG_TXCNT ? */ - if (ah->ah_version == AR5K_AR5210) - return false; - - pending = (AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT); - - /* It's possible to have no frames pending even if TXE - * is set. To indicate that q has not stopped return - * true */ - if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) - return true; - - return pending; -} - -/* - * 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 - */ - /* Enable DCU early termination for this queue */ - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_DCU_EARLY); - - /* Enable DCU to wait for next fragment from QCU */ - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), - AR5K_DCU_MISC_FRAG_WAIT); - - /* On Maui and Spirit use the global seqnum on DCU */ - if (ah->ah_mac_version < AR5K_SREV_AR5211) - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), - AR5K_DCU_MISC_SEQNUM_CTL); - - 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 && - (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB)) - 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); - 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); - - 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)); - - 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; - } - - /* TODO: Handle frame compression */ - - /* - * 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); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); - - /* Update secondary interrupt mask registers */ - - /* Filter out inactive queues */ - 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; - ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; - ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; - ah->ah_txq_imr_qtrig &= ah->ah_txq_status; - ah->ah_txq_imr_nofrm &= 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); - /* Update simr2 but don't overwrite rest simr2 settings */ - AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); - AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, - AR5K_REG_SM(ah->ah_txq_imr_txurn, - AR5K_SIMR2_QCU_TXURN)); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, - AR5K_SIMR3_QCBRORN) | - AR5K_REG_SM(ah->ah_txq_imr_cbrurn, - AR5K_SIMR3_QCBRURN), AR5K_SIMR3); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, - AR5K_SIMR4_QTRIG), AR5K_SIMR4); - /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, - AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); - /* No queue has TXNOFRM enabled, disable the interrupt - * by setting AR5K_TXNOFRM to zero */ - if (ah->ah_txq_imr_nofrm == 0) - ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); - - /* Set QCU mask for this DCU to save power */ - AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue); - } - - 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 deleted file mode 100644 index 7070d15..0000000 --- a/drivers/net/wireless/ath5k/reg.h +++ /dev/null @@ -1,2589 +0,0 @@ -/* - * Copyright (c) 2006-2008 Nick Kossifidis - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2007-2008 Michael Taylor - * - * 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. - * - */ - -/* - * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k - * maintained by Reyk Floeter - * - * I tried to document those registers by looking at ar5k code, some - * 802.11 (802.11e mostly) papers and by reading various public available - * Atheros presentations and papers like these: - * - * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf - * 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. - */ - - - -/*====MAC DMA REGISTERS====*/ - -/* - * AR5210-Specific TXDP registers - * 5210 has only 2 transmit queues so no DCU/QCU, just - * 2 transmit descriptor pointers... - */ -#define AR5K_NOQCU_TXDP0 0x0000 /* Queue 0 - data */ -#define AR5K_NOQCU_TXDP1 0x0004 /* Queue 1 - beacons */ - -/* - * Mac Control Register - */ -#define AR5K_CR 0x0008 /* Register Address */ -#define AR5K_CR_TXE0 0x00000001 /* TX Enable for queue 0 on 5210 */ -#define AR5K_CR_TXE1 0x00000002 /* TX Enable for queue 1 on 5210 */ -#define AR5K_CR_RXE 0x00000004 /* RX Enable */ -#define AR5K_CR_TXD0 0x00000008 /* TX Disable for queue 0 on 5210 */ -#define AR5K_CR_TXD1 0x00000010 /* TX Disable for queue 1 on 5210 */ -#define AR5K_CR_RXD 0x00000020 /* RX Disable */ -#define AR5K_CR_SWI 0x00000040 /* Software Interrupt */ - -/* - * RX Descriptor Pointer register - */ -#define AR5K_RXDP 0x000c - -/* - * Configuration and status register - */ -#define AR5K_CFG 0x0014 /* Register Address */ -#define AR5K_CFG_SWTD 0x00000001 /* Byte-swap TX descriptor (for big endian archs) */ -#define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer */ -#define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */ -#define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer */ -#define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register access */ -#define AR5K_CFG_IBSS 0x00000020 /* 0-BSS, 1-IBSS [5211+] */ -#define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */ -#define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ -#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */ -#define AR5K_CFG_TXCNT 0x00007800 /* Tx frame count (?) [5210] */ -#define AR5K_CFG_TXCNT_S 11 -#define AR5K_CFG_TXFSTAT 0x00008000 /* Tx frame status (?) [5210] */ -#define AR5K_CFG_TXFSTRT 0x00010000 /* [5210] */ -#define AR5K_CFG_PCI_THRES 0x00060000 /* PCI Master req q threshold [5211+] */ -#define AR5K_CFG_PCI_THRES_S 17 - -/* - * Interrupt enable register - */ -#define AR5K_IER 0x0024 /* Register Address */ -#define AR5K_IER_DISABLE 0x00000000 /* Disable card interrupts */ -#define AR5K_IER_ENABLE 0x00000001 /* Enable card interrupts */ - - -/* - * 0x0028 is Beacon Control Register on 5210 - * and first RTS duration register on 5211 - */ - -/* - * Beacon control register [5210] - */ -#define AR5K_BCR 0x0028 /* Register Address */ -#define AR5K_BCR_AP 0x00000000 /* AP mode */ -#define AR5K_BCR_ADHOC 0x00000001 /* Ad-Hoc mode */ -#define AR5K_BCR_BDMAE 0x00000002 /* DMA enable */ -#define AR5K_BCR_TQ1FV 0x00000004 /* Use Queue1 for CAB traffic */ -#define AR5K_BCR_TQ1V 0x00000008 /* Use Queue1 for Beacon traffic */ -#define AR5K_BCR_BCGET 0x00000010 - -/* - * First RTS duration register [5211] - */ -#define AR5K_RTSD0 0x0028 /* Register Address */ -#define AR5K_RTSD0_6 0x000000ff /* 6Mb RTS duration mask (?) */ -#define AR5K_RTSD0_6_S 0 /* 6Mb RTS duration shift (?) */ -#define AR5K_RTSD0_9 0x0000ff00 /* 9Mb*/ -#define AR5K_RTSD0_9_S 8 -#define AR5K_RTSD0_12 0x00ff0000 /* 12Mb*/ -#define AR5K_RTSD0_12_S 16 -#define AR5K_RTSD0_18 0xff000000 /* 16Mb*/ -#define AR5K_RTSD0_18_S 24 - - -/* - * 0x002c is Beacon Status Register on 5210 - * and second RTS duration register on 5211 - */ - -/* - * Beacon status register [5210] - * - * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR - * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning - * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR). - * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i - * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what - * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR. - */ -#define AR5K_BSR 0x002c /* Register Address */ -#define AR5K_BSR_BDLYSW 0x00000001 /* SW Beacon delay (?) */ -#define AR5K_BSR_BDLYDMA 0x00000002 /* DMA Beacon delay (?) */ -#define AR5K_BSR_TXQ1F 0x00000004 /* Beacon queue (1) finished */ -#define AR5K_BSR_ATIMDLY 0x00000008 /* ATIM delay (?) */ -#define AR5K_BSR_SNPADHOC 0x00000100 /* Ad-hoc mode set (?) */ -#define AR5K_BSR_SNPBDMAE 0x00000200 /* Beacon DMA enabled (?) */ -#define AR5K_BSR_SNPTQ1FV 0x00000400 /* Queue1 is used for CAB traffic (?) */ -#define AR5K_BSR_SNPTQ1V 0x00000800 /* Queue1 is used for Beacon traffic (?) */ -#define AR5K_BSR_SNAPSHOTSVALID 0x00001000 /* BCR snapshots are valid (?) */ -#define AR5K_BSR_SWBA_CNT 0x00ff0000 - -/* - * Second RTS duration register [5211] - */ -#define AR5K_RTSD1 0x002c /* Register Address */ -#define AR5K_RTSD1_24 0x000000ff /* 24Mb */ -#define AR5K_RTSD1_24_S 0 -#define AR5K_RTSD1_36 0x0000ff00 /* 36Mb */ -#define AR5K_RTSD1_36_S 8 -#define AR5K_RTSD1_48 0x00ff0000 /* 48Mb */ -#define AR5K_RTSD1_48_S 16 -#define AR5K_RTSD1_54 0xff000000 /* 54Mb */ -#define AR5K_RTSD1_54_S 24 - - -/* - * Transmit configuration register - */ -#define AR5K_TXCFG 0x0030 /* Register Address */ -#define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size (read) */ -#define AR5K_TXCFG_SDMAMR_S 0 -#define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */ -#define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */ -#define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */ -#define AR5K_TXCFG_TXFULL_S 4 -#define AR5K_TXCFG_TXFULL_0B 0x00000000 -#define AR5K_TXCFG_TXFULL_64B 0x00000010 -#define AR5K_TXCFG_TXFULL_128B 0x00000020 -#define AR5K_TXCFG_TXFULL_192B 0x00000030 -#define AR5K_TXCFG_TXFULL_256B 0x00000040 -#define AR5K_TXCFG_TXCONT_EN 0x00000080 -#define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */ -#define AR5K_TXCFG_JUMBO_DESC_EN 0x00000400 /* Enable jumbo tx descriptors [5211+] */ -#define AR5K_TXCFG_ADHOC_BCN_ATIM 0x00000800 /* Adhoc Beacon ATIM Policy */ -#define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS 0x00001000 /* Disable ATIM window defer [5211+] */ -#define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */ -#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */ -#define AR5K_TXCFG_RDY_CBR_DIS 0x00004000 /* Ready time CBR disable [5211+] */ -#define AR5K_TXCFG_JUMBO_FRM_MODE 0x00008000 /* Jumbo frame mode [5211+] */ -#define AR5K_TXCFG_DCU_DBL_BUF_DIS 0x00008000 /* Disable double buffering on DCU */ -#define AR5K_TXCFG_DCU_CACHING_DIS 0x00010000 /* Disable DCU caching */ - -/* - * Receive configuration register - */ -#define AR5K_RXCFG 0x0034 /* Register Address */ -#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size (write) */ -#define AR5K_RXCFG_SDMAMW_S 0 -#define AR5K_RXCFG_ZLFDMA 0x00000008 /* Enable Zero-length frame DMA */ -#define AR5K_RXCFG_DEF_ANTENNA 0x00000010 /* Default antenna (?) */ -#define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo rx descriptors [5211+] */ -#define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames [5211+] */ -#define AR5K_RXCFG_SLE_ENTRY 0x00000080 /* Sleep entry policy */ - -/* - * Receive jumbo descriptor last address register - * Only found in 5211 (?) - */ -#define AR5K_RXJLA 0x0038 - -/* - * MIB control register - */ -#define AR5K_MIBC 0x0040 /* Register Address */ -#define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ -#define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ -#define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ -#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ - -/* - * Timeout prescale register - */ -#define AR5K_TOPS 0x0044 -#define AR5K_TOPS_M 0x0000ffff - -/* - * Receive timeout register (no frame received) - */ -#define AR5K_RXNOFRM 0x0048 -#define AR5K_RXNOFRM_M 0x000003ff - -/* - * Transmit timeout register (no frame sent) - */ -#define AR5K_TXNOFRM 0x004c -#define AR5K_TXNOFRM_M 0x000003ff -#define AR5K_TXNOFRM_QCU 0x000ffc00 -#define AR5K_TXNOFRM_QCU_S 10 - -/* - * Receive frame gap timeout register - */ -#define AR5K_RPGTO 0x0050 -#define AR5K_RPGTO_M 0x000003ff - -/* - * Receive frame count limit register - */ -#define AR5K_RFCNT 0x0054 -#define AR5K_RFCNT_M 0x0000001f /* [5211+] (?) */ -#define AR5K_RFCNT_RFCL 0x0000000f /* [5210] */ - -/* - * Misc settings register - * (reserved0-3) - */ -#define AR5K_MISC 0x0058 /* Register Address */ -#define AR5K_MISC_DMA_OBS_M 0x000001e0 -#define AR5K_MISC_DMA_OBS_S 5 -#define AR5K_MISC_MISC_OBS_M 0x00000e00 -#define AR5K_MISC_MISC_OBS_S 9 -#define AR5K_MISC_MAC_OBS_LSB_M 0x00007000 -#define AR5K_MISC_MAC_OBS_LSB_S 12 -#define AR5K_MISC_MAC_OBS_MSB_M 0x00038000 -#define AR5K_MISC_MAC_OBS_MSB_S 15 -#define AR5K_MISC_LED_DECAY 0x001c0000 /* [5210] */ -#define AR5K_MISC_LED_BLINK 0x00e00000 /* [5210] */ - -/* - * QCU/DCU clock gating register (5311) - * (reserved4-5) - */ -#define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */ -#define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */ -#define AR5K_QCUDCU_CLKGT_DCU 0x07ff0000 /* Mask for DCU clock */ - -/* - * Interrupt Status Registers - * - * For 5210 there is only one status register but for - * 5211/5212 we have one primary and 4 secondary registers. - * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. - * Most of these bits are common for all chipsets. - */ -#define AR5K_ISR 0x001c /* Register Address [5210] */ -#define AR5K_PISR 0x0080 /* Register Address [5211+] */ -#define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly recieved */ -#define AR5K_ISR_RXDESC 0x00000002 /* RX descriptor request */ -#define AR5K_ISR_RXERR 0x00000004 /* Receive error */ -#define AR5K_ISR_RXNOFRM 0x00000008 /* No frame received (receive timeout) */ -#define AR5K_ISR_RXEOL 0x00000010 /* Empty RX descriptor */ -#define AR5K_ISR_RXORN 0x00000020 /* Receive FIFO overrun */ -#define AR5K_ISR_TXOK 0x00000040 /* Frame successfuly transmited */ -#define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ -#define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ -#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout) */ -#define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ -#define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ -#define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ -#define AR5K_ISR_SWI 0x00002000 /* Software interrupt */ -#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 /* 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+] */ -#define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ -#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_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) - * - * 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 /* 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_QCBRORN_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+] - */ -#define AR5K_RAC_PISR 0x00c0 /* Read and clear PISR */ -#define AR5K_RAC_SISR0 0x00c4 /* Read and clear SISR0 */ -#define AR5K_RAC_SISR1 0x00c8 /* Read and clear SISR1 */ -#define AR5K_RAC_SISR2 0x00cc /* Read and clear SISR2 */ -#define AR5K_RAC_SISR3 0x00d0 /* Read and clear SISR3 */ -#define AR5K_RAC_SISR4 0x00d4 /* Read and clear SISR4 */ - -/* - * Interrupt Mask Registers - * - * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary - * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match. - */ -#define AR5K_IMR 0x0020 /* Register Address [5210] */ -#define AR5K_PIMR 0x00a0 /* Register Address [5211+] */ -#define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly recieved*/ -#define AR5K_IMR_RXDESC 0x00000002 /* RX descriptor request*/ -#define AR5K_IMR_RXERR 0x00000004 /* Receive error*/ -#define AR5K_IMR_RXNOFRM 0x00000008 /* No frame received (receive timeout)*/ -#define AR5K_IMR_RXEOL 0x00000010 /* Empty RX descriptor*/ -#define AR5K_IMR_RXORN 0x00000020 /* Receive FIFO overrun*/ -#define AR5K_IMR_TXOK 0x00000040 /* Frame successfuly transmited*/ -#define AR5K_IMR_TXDESC 0x00000080 /* TX descriptor request*/ -#define AR5K_IMR_TXERR 0x00000100 /* Transmit error*/ -#define AR5K_IMR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout)*/ -#define AR5K_IMR_TXEOL 0x00000400 /* Empty TX descriptor*/ -#define AR5K_IMR_TXURN 0x00000800 /* Transmit FIFO underrun*/ -#define AR5K_IMR_MIB 0x00001000 /* Update MIB counters*/ -#define AR5K_IMR_SWI 0x00002000 /* Software interrupt */ -#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 /* 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+] */ -#define AR5K_IMR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ -#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 /* '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 /* 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) - */ -#define AR5K_SIMR0 0x00a4 /* Register Address [5211+] */ -#define AR5K_SIMR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ -#define AR5K_SIMR0_QCU_TXOK_S 0 -#define AR5K_SIMR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ -#define AR5K_SIMR0_QCU_TXDESC_S 16 - -#define AR5K_SIMR1 0x00a8 /* Register Address [5211+] */ -#define AR5K_SIMR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ -#define AR5K_SIMR1_QCU_TXERR_S 0 -#define AR5K_SIMR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ -#define AR5K_SIMR1_QCU_TXEOL_S 16 - -#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ -#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ -#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 /* 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 */ -#define AR5K_SIMR3_QCBRORN_S 0 -#define AR5K_SIMR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ -#define AR5K_SIMR3_QCBRURN_S 16 - -#define AR5K_SIMR4 0x00b4 /* Register Address [5211+] */ -#define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */ -#define AR5K_SIMR4_QTRIG_S 0 - -/* - * DMA Debug registers 0-7 - * 0xe0 - 0xfc - */ - -/* - * Decompression mask registers [5212+] - */ -#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (index) */ -#define AR5K_DCM_DATA 0x0404 /*Decompression mask data */ - -/* - * Wake On Wireless pattern control register [5212+] - */ -#define AR5K_WOW_PCFG 0x0410 /* Register Address */ -#define AR5K_WOW_PCFG_PAT_MATCH_EN 0x00000001 /* Pattern match enable */ -#define AR5K_WOW_PCFG_LONG_FRAME_POL 0x00000002 /* Long frame policy */ -#define AR5K_WOW_PCFG_WOBMISS 0x00000004 /* Wake on bea(con) miss (?) */ -#define AR5K_WOW_PCFG_PAT_0_EN 0x00000100 /* Enable pattern 0 */ -#define AR5K_WOW_PCFG_PAT_1_EN 0x00000200 /* Enable pattern 1 */ -#define AR5K_WOW_PCFG_PAT_2_EN 0x00000400 /* Enable pattern 2 */ -#define AR5K_WOW_PCFG_PAT_3_EN 0x00000800 /* Enable pattern 3 */ -#define AR5K_WOW_PCFG_PAT_4_EN 0x00001000 /* Enable pattern 4 */ -#define AR5K_WOW_PCFG_PAT_5_EN 0x00002000 /* Enable pattern 5 */ - -/* - * Wake On Wireless pattern index register (?) [5212+] - */ -#define AR5K_WOW_PAT_IDX 0x0414 - -/* - * Wake On Wireless pattern data register [5212+] - */ -#define AR5K_WOW_PAT_DATA 0x0418 /* Register Address */ -#define AR5K_WOW_PAT_DATA_0_3_V 0x00000001 /* Pattern 0, 3 value */ -#define AR5K_WOW_PAT_DATA_1_4_V 0x00000100 /* Pattern 1, 4 value */ -#define AR5K_WOW_PAT_DATA_2_5_V 0x00010000 /* Pattern 2, 5 value */ -#define AR5K_WOW_PAT_DATA_0_3_M 0x01000000 /* Pattern 0, 3 mask */ -#define AR5K_WOW_PAT_DATA_1_4_M 0x04000000 /* Pattern 1, 4 mask */ -#define AR5K_WOW_PAT_DATA_2_5_M 0x10000000 /* Pattern 2, 5 mask */ - -/* - * Decompression configuration registers [5212+] - */ -#define AR5K_DCCFG 0x0420 /* Register Address */ -#define AR5K_DCCFG_GLOBAL_EN 0x00000001 /* Enable decompression on all queues */ -#define AR5K_DCCFG_BYPASS_EN 0x00000002 /* Bypass decompression */ -#define AR5K_DCCFG_BCAST_EN 0x00000004 /* Enable decompression for bcast frames */ -#define AR5K_DCCFG_MCAST_EN 0x00000008 /* Enable decompression for mcast frames */ - -/* - * Compression configuration registers [5212+] - */ -#define AR5K_CCFG 0x0600 /* Register Address */ -#define AR5K_CCFG_WINDOW_SIZE 0x00000007 /* Compression window size */ -#define AR5K_CCFG_CPC_EN 0x00000008 /* Enable performance counters */ - -#define AR5K_CCFG_CCU 0x0604 /* Register Address */ -#define AR5K_CCFG_CCU_CUP_EN 0x00000001 /* CCU Catchup enable */ -#define AR5K_CCFG_CCU_CREDIT 0x00000002 /* CCU Credit (field) */ -#define AR5K_CCFG_CCU_CD_THRES 0x00000080 /* CCU Cyc(lic?) debt threshold (field) */ -#define AR5K_CCFG_CCU_CUP_LCNT 0x00010000 /* CCU Catchup lit(?) count */ -#define AR5K_CCFG_CCU_INIT 0x00100200 /* Initial value during reset */ - -/* - * Compression performance counter registers [5212+] - */ -#define AR5K_CPC0 0x0610 /* Compression performance counter 0 */ -#define AR5K_CPC1 0x0614 /* Compression performance counter 1*/ -#define AR5K_CPC2 0x0618 /* Compression performance counter 2 */ -#define AR5K_CPC3 0x061c /* Compression performance counter 3 */ -#define AR5K_CPCOVF 0x0620 /* Compression performance overflow */ - - -/* - * Queue control unit (QCU) registers [5211+] - * - * Card has 12 TX Queues but i see that only 0-9 are used (?) - * both in binary HAL (see ah.h) and ar5k. Each queue has it's own - * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) - * configuration register (0x08c0 - 0x08ec), a ready time configuration - * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - - * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some - * global registers, QCU transmit enable/disable and "one shot arm (?)" - * set/clear, which contain status for all queues (we shift by 1 for each - * queue). To access these registers easily we define some macros here - * that are used inside HAL. For more infos check out *_tx_queue functs. - */ - -/* - * Generic QCU Register access macros - */ -#define AR5K_QUEUE_REG(_r, _q) (((_q) << 2) + _r) -#define AR5K_QCU_GLOBAL_READ(_r, _q) (AR5K_REG_READ(_r) & (1 << _q)) -#define AR5K_QCU_GLOBAL_WRITE(_r, _q) AR5K_REG_WRITE(_r, (1 << _q)) - -/* - * QCU Transmit descriptor pointer registers - */ -#define AR5K_QCU_TXDP_BASE 0x0800 /* Register Address - Queue0 TXDP */ -#define AR5K_QUEUE_TXDP(_q) AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q) - -/* - * QCU Transmit enable register - */ -#define AR5K_QCU_TXE 0x0840 -#define AR5K_ENABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q) -#define AR5K_QUEUE_ENABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q) - -/* - * QCU Transmit disable register - */ -#define AR5K_QCU_TXD 0x0880 -#define AR5K_DISABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q) -#define AR5K_QUEUE_DISABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q) - -/* - * QCU Constant Bit Rate configuration registers - */ -#define AR5K_QCU_CBRCFG_BASE 0x08c0 /* Register Address - Queue0 CBRCFG */ -#define AR5K_QCU_CBRCFG_INTVAL 0x00ffffff /* CBR Interval mask */ -#define AR5K_QCU_CBRCFG_INTVAL_S 0 -#define AR5K_QCU_CBRCFG_ORN_THRES 0xff000000 /* CBR overrun threshold mask */ -#define AR5K_QCU_CBRCFG_ORN_THRES_S 24 -#define AR5K_QUEUE_CBRCFG(_q) AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q) - -/* - * QCU Ready time configuration registers - */ -#define AR5K_QCU_RDYTIMECFG_BASE 0x0900 /* Register Address - Queue0 RDYTIMECFG */ -#define AR5K_QCU_RDYTIMECFG_INTVAL 0x00ffffff /* Ready time interval mask */ -#define AR5K_QCU_RDYTIMECFG_INTVAL_S 0 -#define AR5K_QCU_RDYTIMECFG_ENABLE 0x01000000 /* Ready time enable mask */ -#define AR5K_QUEUE_RDYTIMECFG(_q) AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q) - -/* - * QCU one shot arm set registers - */ -#define AR5K_QCU_ONESHOTARM_SET 0x0940 /* Register Address -QCU "one shot arm set (?)" */ -#define AR5K_QCU_ONESHOTARM_SET_M 0x0000ffff - -/* - * QCU one shot arm clear registers - */ -#define AR5K_QCU_ONESHOTARM_CLEAR 0x0980 /* Register Address -QCU "one shot arm clear (?)" */ -#define AR5K_QCU_ONESHOTARM_CLEAR_M 0x0000ffff - -/* - * QCU misc registers - */ -#define AR5K_QCU_MISC_BASE 0x09c0 /* Register Address -Queue0 MISC */ -#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 /* 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_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 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 */ -#define AR5K_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q) - - -/* - * QCU status registers - */ -#define AR5K_QCU_STS_BASE 0x0a00 /* Register Address - Queue0 STS */ -#define AR5K_QCU_STS_FRMPENDCNT 0x00000003 /* Frames pending counter */ -#define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter */ -#define AR5K_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q) - -/* - * QCU ready time shutdown register - */ -#define AR5K_QCU_RDYTIMESHDN 0x0a40 -#define AR5K_QCU_RDYTIMESHDN_M 0x000003ff - -/* - * QCU compression buffer base registers [5212+] - */ -#define AR5K_QCU_CBB_SELECT 0x0b00 -#define AR5K_QCU_CBB_ADDR 0x0b04 -#define AR5K_QCU_CBB_ADDR_S 9 - -/* - * QCU compression buffer configuration register [5212+] - * (buffer size) - */ -#define AR5K_QCU_CBCFG 0x0b08 - - - -/* - * Distributed Coordination Function (DCF) control unit (DCU) - * registers [5211+] - * - * These registers control the various characteristics of each queue - * for 802.11e (WME) combatibility so they go together with - * QCU registers in pairs. For each queue we have a QCU mask register, - * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c), - * a retry limit register (0x1080 - 0x10ac), a channel time register - * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and - * a sequence number register (0x1140 - 0x116c). It seems that "global" - * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k). - * We use the same macros here for easier register access. - * - */ - -/* - * DCU QCU mask registers - */ -#define AR5K_DCU_QCUMASK_BASE 0x1000 /* Register Address -Queue0 DCU_QCUMASK */ -#define AR5K_DCU_QCUMASK_M 0x000003ff -#define AR5K_QUEUE_QCUMASK(_q) AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q) - -/* - * DCU local Inter Frame Space settings register - */ -#define AR5K_DCU_LCL_IFS_BASE 0x1040 /* Register Address -Queue0 DCU_LCL_IFS */ -#define AR5K_DCU_LCL_IFS_CW_MIN 0x000003ff /* Minimum Contention Window */ -#define AR5K_DCU_LCL_IFS_CW_MIN_S 0 -#define AR5K_DCU_LCL_IFS_CW_MAX 0x000ffc00 /* Maximum Contention Window */ -#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) - -/* - * DCU retry limit registers - */ -#define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ -#define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ -#define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 -#define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ -#define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 -#define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ -#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 -#define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ -#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 -#define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) - -/* - * DCU channel time registers - */ -#define AR5K_DCU_CHAN_TIME_BASE 0x10c0 /* Register Address -Queue0 DCU_CHAN_TIME */ -#define AR5K_DCU_CHAN_TIME_DUR 0x000fffff /* Channel time duration */ -#define AR5K_DCU_CHAN_TIME_DUR_S 0 -#define AR5K_DCU_CHAN_TIME_ENABLE 0x00100000 /* Enable channel time */ -#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q) AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q) - -/* - * DCU misc registers [5211+] - * - * 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) - * before we transmit anything else and global lockout means we - * wait for the whole queue to finish before higher priority queues - * can transmit (this is used on beacon and CAB queues). - * No lockout means there is no special handling. - */ -#define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ -#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_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 -#define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */ -#define AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM 1 /* Intra-frame lockout */ -#define AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL 2 /* Global lockout */ -#define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 /* Ignore Arbiter lockout */ -#define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment */ -#define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff */ -#define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision cw policy */ -#define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS policy (?) */ -#define AR5K_DCU_MISC_SEQNUM_CTL 0x01000000 /* Sequence number control (?) */ -#define AR5K_QUEUE_DFS_MISC(_q) AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q) - -/* - * DCU frame sequence number registers - */ -#define AR5K_DCU_SEQNUM_BASE 0x1140 -#define AR5K_DCU_SEQNUM_M 0x00000fff -#define AR5K_QUEUE_DCU_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q) - -/* - * DCU global IFS SIFS register - */ -#define AR5K_DCU_GBL_IFS_SIFS 0x1030 -#define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff - -/* - * DCU global IFS slot interval register - */ -#define AR5K_DCU_GBL_IFS_SLOT 0x1070 -#define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff - -/* - * DCU global IFS EIFS register - */ -#define AR5K_DCU_GBL_IFS_EIFS 0x10b0 -#define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff - -/* - * DCU global IFS misc register - * - * LFSR stands for Linear Feedback Shift Register - * and it's used for generating pseudo-random - * number sequences. - * - * (If i understand corectly, random numbers are - * used for idle sensing -multiplied with cwmin/max etc-) - */ -#define AR5K_DCU_GBL_IFS_MISC 0x10f0 /* Register Address */ -#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 /* LFSR Slice Select */ -#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 /* 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 */ - -/* - * DCU frame prefetch control register - */ -#define AR5K_DCU_FP 0x1230 /* Register Address */ -#define AR5K_DCU_FP_NOBURST_DCU_EN 0x00000001 /* Enable non-burst prefetch on DCU (?) */ -#define AR5K_DCU_FP_NOBURST_EN 0x00000010 /* Enable non-burst prefetch (?) */ -#define AR5K_DCU_FP_BURST_DCU_EN 0x00000020 /* Enable burst prefetch on DCU (?) */ - -/* - * DCU transmit pause control/status register - */ -#define AR5K_DCU_TXP 0x1270 /* Register Address */ -#define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask */ -#define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status */ - -/* - * DCU transmit filter table 0 (32 entries) - * each entry contains a 32bit slice of the - * 128bit tx filter for each DCU (4 slices per DCU) - */ -#define AR5K_DCU_TX_FILTER_0_BASE 0x1038 -#define AR5K_DCU_TX_FILTER_0(_n) (AR5K_DCU_TX_FILTER_0_BASE + (_n * 64)) - -/* - * DCU transmit filter table 1 (16 entries) - */ -#define AR5K_DCU_TX_FILTER_1_BASE 0x103c -#define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + (_n * 64)) - -/* - * DCU clear transmit filter register - */ -#define AR5K_DCU_TX_FILTER_CLR 0x143c - -/* - * DCU set transmit filter register - */ -#define AR5K_DCU_TX_FILTER_SET 0x147c - -/* - * Reset control register - */ -#define AR5K_RESET_CTL 0x4000 /* Register Address */ -#define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ -#define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset [5210] */ -#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset [5211+] */ -#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) */ - -/* - * Sleep control register - */ -#define AR5K_SLEEP_CTL 0x4004 /* Register Address */ -#define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /* Sleep duration mask */ -#define AR5K_SLEEP_CTL_SLDUR_S 0 -#define AR5K_SLEEP_CTL_SLE 0x00030000 /* Sleep enable mask */ -#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 /* Normal sleep policy */ -#define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ -#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 - */ -#define AR5K_INTPEND 0x4008 -#define AR5K_INTPEND_M 0x00000001 - -/* - * Sleep force register - */ -#define AR5K_SFR 0x400c -#define AR5K_SFR_EN 0x00000001 - -/* - * 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_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_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_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ -#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+] */ -#define AR5K_PCICFG_LEDMODE_PROM 0x00020000 /* Default mode (blink on any traffic) [5211+] */ -#define AR5K_PCICFG_LEDMODE_PWR 0x00040000 /* Some other blinking mode (?) [5211+] */ -#define AR5K_PCICFG_LEDMODE_RAND 0x00060000 /* Random blinking (?) [5211+] */ -#define AR5K_PCICFG_LEDBLINK 0x00700000 /* Led blink rate */ -#define AR5K_PCICFG_LEDBLINK_S 20 -#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slowest led blink rate [5211+] */ -#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 */ -#define AR5K_PCICFG_SLEEP_CLOCK_RATE_S 24 - -/* - * "General Purpose Input/Output" (GPIO) control register - * - * I'm not sure about this but after looking at the code - * for all chipsets here is what i got. - * - * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits) - * Mode 0 -> always input - * Mode 1 -> output when GPIODO for this GPIO is set to 0 - * Mode 2 -> output when GPIODO for this GPIO is set to 1 - * Mode 3 -> always output - * - * For more infos check out get_gpio/set_gpio and - * set_gpio_input/set_gpio_output functs. - * For more infos on gpio interrupt check out set_gpio_intr. - */ -#define AR5K_NUM_GPIO 6 - -#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 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 */ -#define AR5K_GPIOCR_OUT(n) (3 << ((n) * 2)) /* Mode 3 for pin n */ -#define AR5K_GPIOCR_INT_SEL(n) ((n) << 12) /* Interrupt for GPIO pin n */ - -/* - * "General Purpose Input/Output" (GPIO) data output register - */ -#define AR5K_GPIODO 0x4018 - -/* - * "General Purpose Input/Output" (GPIO) data input register - */ -#define AR5K_GPIODI 0x401c -#define AR5K_GPIODI_M 0x0000002f - -/* - * Silicon revision register - */ -#define AR5K_SREV 0x4020 /* Register Address */ -#define AR5K_SREV_REV 0x0000000f /* Mask for revision */ -#define AR5K_SREV_REV_S 0 -#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====*/ - -/* - * EEPROM access registers - * - * Here we got a difference between 5210/5211-12 - * read data register for 5210 is at 0x6800 and - * status register is at 0x6c00. There is also - * no eeprom command register on 5210 and the - * offsets are different. - * - * To read eeprom data for a specific offset: - * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) - * read AR5K_EEPROM_BASE +(4 * offset) - * check the eeprom status register - * and read eeprom data register. - * - * 5211 - write offset to AR5K_EEPROM_BASE - * 5212 write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD - * check the eeprom status register - * and read eeprom data register. - * - * To write eeprom data for a specific offset: - * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) - * write data to AR5K_EEPROM_BASE +(4 * offset) - * check the eeprom status register - * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD - * 5212 write offset to AR5K_EEPROM_BASE - * write data to data register - * write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD - * check the eeprom status register - * - * For more infos check eeprom_* functs and the ar5k.c - * file posted in madwifi-devel mailing list. - * http://sourceforge.net/mailarchive/message.php?msg_id=8966525 - * - */ -#define AR5K_EEPROM_BASE 0x6000 - -/* - * EEPROM data register - */ -#define AR5K_EEPROM_DATA_5211 0x6004 -#define AR5K_EEPROM_DATA_5210 0x6800 -#define AR5K_EEPROM_DATA (ah->ah_version == AR5K_AR5210 ? \ - AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211) - -/* - * EEPROM command register - */ -#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ -#define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ -#define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ -#define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ - -/* - * EEPROM status register - */ -#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ -#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ -#define AR5K_EEPROM_STATUS (ah->ah_version == AR5K_AR5210 ? \ - AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211) -#define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */ -#define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */ -#define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */ -#define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ - -/* - * EEPROM config register - */ -#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ -#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_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 - */ -/* - * Used for checking initial register writes - * during channel reset (see reset func) - */ -#define AR5K_PCU_MIN 0x8000 -#define AR5K_PCU_MAX 0x8fff - -/* - * First station id register (Lower 32 bits of MAC address) - */ -#define AR5K_STA_ID0 0x8000 -#define AR5K_STA_ID0_ARRD_L32 0xffffffff - -/* - * Second station id register (Upper 16 bits of MAC address + PCU settings) - */ -#define AR5K_STA_ID1 0x8004 /* Register Address */ -#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ -#define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ -#define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ -#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ -#define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 /* No key search */ -#define AR5K_STA_ID1_NO_PSPOLL 0x00100000 /* No power save polling [5210] */ -#define AR5K_STA_ID1_PCF_5211 0x00100000 /* Enable PCF on [5211+] */ -#define AR5K_STA_ID1_PCF_5210 0x00200000 /* Enable PCF on [5210]*/ -#define AR5K_STA_ID1_PCF (ah->ah_version == AR5K_AR5210 ? \ - AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211) -#define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ -#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_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 /* 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) - */ -#define AR5K_BSS_ID0 0x8008 - -/* - * Second BSSID register (MAC address in upper 16 bits) - * - * AID: Association ID - */ -#define AR5K_BSS_ID1 0x800c -#define AR5K_BSS_ID1_AID 0xffff0000 -#define AR5K_BSS_ID1_AID_S 16 - -/* - * Backoff slot time register - */ -#define AR5K_SLOT_TIME 0x8010 - -/* - * ACK/CTS timeout register - */ -#define AR5K_TIME_OUT 0x8014 /* Register Address */ -#define AR5K_TIME_OUT_ACK 0x00001fff /* ACK timeout mask */ -#define AR5K_TIME_OUT_ACK_S 0 -#define AR5K_TIME_OUT_CTS 0x1fff0000 /* CTS timeout mask */ -#define AR5K_TIME_OUT_CTS_S 16 - -/* - * RSSI threshold register - */ -#define AR5K_RSSI_THR 0x8018 /* Register Address */ -#define AR5K_RSSI_THR_M 0x000000ff /* Mask for RSSI threshold [5211+] */ -#define AR5K_RSSI_THR_BMISS_5210 0x00000700 /* Mask for Beacon Missed threshold [5210] */ -#define AR5K_RSSI_THR_BMISS_5210_S 8 -#define AR5K_RSSI_THR_BMISS_5211 0x0000ff00 /* Mask for Beacon Missed threshold [5211+] */ -#define AR5K_RSSI_THR_BMISS_5211_S 8 -#define AR5K_RSSI_THR_BMISS (ah->ah_version == AR5K_AR5210 ? \ - AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211) -#define AR5K_RSSI_THR_BMISS_S 8 - -/* - * 5210 has more PCU registers because there is no QCU/DCU - * so queue parameters are set here, this way a lot common - * registers have different address for 5210. To make things - * easier we define a macro based on ah->ah_version for common - * registers with different addresses and common flags. - */ - -/* - * Retry limit register - * - * Retry limit register for 5210 (no QCU/DCU so it's done in PCU) - */ -#define AR5K_NODCU_RETRY_LMT 0x801c /* Register Address */ -#define AR5K_NODCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ -#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S 0 -#define AR5K_NODCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry mask */ -#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S 4 -#define AR5K_NODCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask */ -#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S 8 -#define AR5K_NODCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask */ -#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S 14 -#define AR5K_NODCU_RETRY_LMT_CW_MIN 0x3ff00000 /* Minimum contention window mask */ -#define AR5K_NODCU_RETRY_LMT_CW_MIN_S 20 - -/* - * Transmit latency register - */ -#define AR5K_USEC_5210 0x8020 /* Register Address [5210] */ -#define AR5K_USEC_5211 0x801c /* Register Address [5211+] */ -#define AR5K_USEC (ah->ah_version == AR5K_AR5210 ? \ - AR5K_USEC_5210 : AR5K_USEC_5211) -#define AR5K_USEC_1 0x0000007f /* clock cycles for 1us */ -#define AR5K_USEC_1_S 0 -#define AR5K_USEC_32 0x00003f80 /* clock cycles for 1us while on 32Mhz clock */ -#define AR5K_USEC_32_S 7 -#define AR5K_USEC_TX_LATENCY_5211 0x007fc000 -#define AR5K_USEC_TX_LATENCY_5211_S 14 -#define AR5K_USEC_RX_LATENCY_5211 0x1f800000 -#define AR5K_USEC_RX_LATENCY_5211_S 23 -#define AR5K_USEC_TX_LATENCY_5210 0x000fc000 /* also for 5311 */ -#define AR5K_USEC_TX_LATENCY_5210_S 14 -#define AR5K_USEC_RX_LATENCY_5210 0x03f00000 /* also for 5311 */ -#define AR5K_USEC_RX_LATENCY_5210_S 20 - -/* - * PCU beacon control register - */ -#define AR5K_BEACON_5210 0x8024 /*Register Address [5210] */ -#define AR5K_BEACON_5211 0x8020 /*Register Address [5211+] */ -#define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \ - AR5K_BEACON_5210 : AR5K_BEACON_5211) -#define AR5K_BEACON_PERIOD 0x0000ffff /* Mask for beacon period */ -#define AR5K_BEACON_PERIOD_S 0 -#define AR5K_BEACON_TIM 0x007f0000 /* Mask for TIM offset */ -#define AR5K_BEACON_TIM_S 16 -#define AR5K_BEACON_ENABLE 0x00800000 /* Enable beacons */ -#define AR5K_BEACON_RESET_TSF 0x01000000 /* Force TSF reset */ - -/* - * CFP period register - */ -#define AR5K_CFP_PERIOD_5210 0x8028 -#define AR5K_CFP_PERIOD_5211 0x8024 -#define AR5K_CFP_PERIOD (ah->ah_version == AR5K_AR5210 ? \ - AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211) - -/* - * Next beacon time register - */ -#define AR5K_TIMER0_5210 0x802c -#define AR5K_TIMER0_5211 0x8028 -#define AR5K_TIMER0 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_TIMER0_5210 : AR5K_TIMER0_5211) - -/* - * Next DMA beacon alert register - */ -#define AR5K_TIMER1_5210 0x8030 -#define AR5K_TIMER1_5211 0x802c -#define AR5K_TIMER1 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_TIMER1_5210 : AR5K_TIMER1_5211) - -/* - * Next software beacon alert register - */ -#define AR5K_TIMER2_5210 0x8034 -#define AR5K_TIMER2_5211 0x8030 -#define AR5K_TIMER2 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_TIMER2_5210 : AR5K_TIMER2_5211) - -/* - * Next ATIM window time register - */ -#define AR5K_TIMER3_5210 0x8038 -#define AR5K_TIMER3_5211 0x8034 -#define AR5K_TIMER3 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_TIMER3_5210 : AR5K_TIMER3_5211) - - -/* - * 5210 First inter frame spacing register (IFS) - */ -#define AR5K_IFS0 0x8040 -#define AR5K_IFS0_SIFS 0x000007ff -#define AR5K_IFS0_SIFS_S 0 -#define AR5K_IFS0_DIFS 0x007ff800 -#define AR5K_IFS0_DIFS_S 11 - -/* - * 5210 Second inter frame spacing register (IFS) - */ -#define AR5K_IFS1 0x8044 -#define AR5K_IFS1_PIFS 0x00000fff -#define AR5K_IFS1_PIFS_S 0 -#define AR5K_IFS1_EIFS 0x03fff000 -#define AR5K_IFS1_EIFS_S 12 -#define AR5K_IFS1_CS_EN 0x04000000 - - -/* - * CFP duration register - */ -#define AR5K_CFP_DUR_5210 0x8048 -#define AR5K_CFP_DUR_5211 0x8038 -#define AR5K_CFP_DUR (ah->ah_version == AR5K_AR5210 ? \ - AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211) - -/* - * Receive filter register - */ -#define AR5K_RX_FILTER_5210 0x804c /* Register Address [5210] */ -#define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */ -#define AR5K_RX_FILTER (ah->ah_version == AR5K_AR5210 ? \ - AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211) -#define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ -#define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ -#define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ -#define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ -#define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ -#define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ -#define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ -#define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter probe requests [5212+] */ -#define AR5K_RX_FILTER_PHYERR_5212 0x00000100 /* Don't filter phy errors [5212+] */ -#define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ -#define AR5K_RX_FILTER_PHYERR_5211 0x00000040 /* [5211] */ -#define AR5K_RX_FILTER_RADARERR_5211 0x00000080 /* [5211] */ -#define AR5K_RX_FILTER_PHYERR \ - ((ah->ah_version == AR5K_AR5211 ? \ - AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212)) -#define AR5K_RX_FILTER_RADARERR \ - ((ah->ah_version == AR5K_AR5211 ? \ - AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212)) - -/* - * Multicast filter register (lower 32 bits) - */ -#define AR5K_MCAST_FILTER0_5210 0x8050 -#define AR5K_MCAST_FILTER0_5211 0x8040 -#define AR5K_MCAST_FILTER0 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211) - -/* - * Multicast filter register (higher 16 bits) - */ -#define AR5K_MCAST_FILTER1_5210 0x8054 -#define AR5K_MCAST_FILTER1_5211 0x8044 -#define AR5K_MCAST_FILTER1 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211) - - -/* - * Transmit mask register (lower 32 bits) [5210] - */ -#define AR5K_TX_MASK0 0x8058 - -/* - * Transmit mask register (higher 16 bits) [5210] - */ -#define AR5K_TX_MASK1 0x805c - -/* - * Clear transmit mask [5210] - */ -#define AR5K_CLR_TMASK 0x8060 - -/* - * Trigger level register (before transmission) [5210] - */ -#define AR5K_TRIG_LVL 0x8064 - - -/* - * PCU control register - * - * Only DIS_RX is used in the code, the rest i guess are - * for tweaking/diagnostics. - */ -#define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ -#define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ -#define AR5K_DIAG_SW (ah->ah_version == AR5K_AR5210 ? \ - AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211) -#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */ -#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */ -#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */ -#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */ -#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */ -#define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ -#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ -#define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 -#define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ - AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) -#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ -#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 /* 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 /* 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_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+] */ -#define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ -#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */ -#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 /* 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 /* Observation point select (?) */ -#define AR5K_DIAG_SW_OBSPT_S 18 -#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) - */ -#define AR5K_TSF_L32_5210 0x806c -#define AR5K_TSF_L32_5211 0x804c -#define AR5K_TSF_L32 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211) - -/* - * TSF (clock) register (higher 32 bits) - */ -#define AR5K_TSF_U32_5210 0x8070 -#define AR5K_TSF_U32_5211 0x8050 -#define AR5K_TSF_U32 (ah->ah_version == AR5K_AR5210 ? \ - AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211) - -/* - * Last beacon timestamp register (Read Only) - */ -#define AR5K_LAST_TSTP 0x8080 - -/* - * ADDAC test register [5211+] - */ -#define AR5K_ADDAC_TEST 0x8054 /* Register Address */ -#define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */ -#define AR5K_ADDAC_TEST_TST_MODE 0x00000002 /* Test mode */ -#define AR5K_ADDAC_TEST_LOOP_EN 0x00000004 /* Enable loop */ -#define AR5K_ADDAC_TEST_LOOP_LEN 0x00000008 /* Loop length (field) */ -#define AR5K_ADDAC_TEST_USE_U8 0x00004000 /* Use upper 8 bits */ -#define AR5K_ADDAC_TEST_MSB 0x00008000 /* State of MSB */ -#define AR5K_ADDAC_TEST_TRIG_SEL 0x00010000 /* Trigger select */ -#define AR5K_ADDAC_TEST_TRIG_PTY 0x00020000 /* Trigger polarity */ -#define AR5K_ADDAC_TEST_RXCONT 0x00040000 /* Continuous capture */ -#define AR5K_ADDAC_TEST_CAPTURE 0x00080000 /* Begin capture */ -#define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* ARM rx buffer for capture */ - -/* - * Default antenna register [5211+] - */ -#define AR5K_DEFAULT_ANTENNA 0x8058 - -/* - * Frame control QoS mask register (?) [5211+] - * (FC_QOS_MASK) - */ -#define AR5K_FRAME_CTL_QOSM 0x805c - -/* - * Seq mask register (?) [5211+] - */ -#define AR5K_SEQ_MASK 0x8060 - -/* - * Retry count register [5210] - */ -#define AR5K_RETRY_CNT 0x8084 /* Register Address [5210] */ -#define AR5K_RETRY_CNT_SSH 0x0000003f /* Station short retry count (?) */ -#define AR5K_RETRY_CNT_SLG 0x00000fc0 /* Station long retry count (?) */ - -/* - * Back-off status register [5210] - */ -#define AR5K_BACKOFF 0x8088 /* Register Address [5210] */ -#define AR5K_BACKOFF_CW 0x000003ff /* Backoff Contention Window (?) */ -#define AR5K_BACKOFF_CNT 0x03ff0000 /* Backoff count (?) */ - - - -/* - * NAV register (current) - */ -#define AR5K_NAV_5210 0x808c -#define AR5K_NAV_5211 0x8084 -#define AR5K_NAV (ah->ah_version == AR5K_AR5210 ? \ - AR5K_NAV_5210 : AR5K_NAV_5211) - -/* - * RTS success register - */ -#define AR5K_RTS_OK_5210 0x8090 -#define AR5K_RTS_OK_5211 0x8088 -#define AR5K_RTS_OK (ah->ah_version == AR5K_AR5210 ? \ - AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) - -/* - * RTS failure register - */ -#define AR5K_RTS_FAIL_5210 0x8094 -#define AR5K_RTS_FAIL_5211 0x808c -#define AR5K_RTS_FAIL (ah->ah_version == AR5K_AR5210 ? \ - AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) - -/* - * ACK failure register - */ -#define AR5K_ACK_FAIL_5210 0x8098 -#define AR5K_ACK_FAIL_5211 0x8090 -#define AR5K_ACK_FAIL (ah->ah_version == AR5K_AR5210 ? \ - AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) - -/* - * FCS failure register - */ -#define AR5K_FCS_FAIL_5210 0x809c -#define AR5K_FCS_FAIL_5211 0x8094 -#define AR5K_FCS_FAIL (ah->ah_version == AR5K_AR5210 ? \ - AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211) - -/* - * Beacon count register - */ -#define AR5K_BEACON_CNT_5210 0x80a0 -#define AR5K_BEACON_CNT_5211 0x8098 -#define AR5K_BEACON_CNT (ah->ah_version == AR5K_AR5210 ? \ - AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211) - - -/*===5212 Specific PCU registers===*/ - -/* - * Transmit power control register - */ -#define AR5K_TPC 0x80e8 -#define AR5K_TPC_ACK 0x0000003f /* ack frames */ -#define AR5K_TPC_ACK_S 0 -#define AR5K_TPC_CTS 0x00003f00 /* cts frames */ -#define AR5K_TPC_CTS_S 8 -#define AR5K_TPC_CHIRP 0x003f0000 /* chirp frames */ -#define AR5K_TPC_CHIRP_S 16 -#define AR5K_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ -#define AR5K_TPC_DOPPLER_S 24 - -/* - * XR (eXtended Range) mode register - */ -#define AR5K_XRMODE 0x80c0 /* Register Address */ -#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f /* Mask for Poll type (?) */ -#define AR5K_XRMODE_POLL_TYPE_S 0 -#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c /* Mask for Poll subtype (?) */ -#define AR5K_XRMODE_POLL_SUBTYPE_S 2 -#define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 /* Wait for poll */ -#define AR5K_XRMODE_SIFS_DELAY 0x000fff00 /* Mask for SIFS delay */ -#define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 /* Mask for frame hold (?) */ -#define AR5K_XRMODE_FRAME_HOLD_S 20 - -/* - * XR delay register - */ -#define AR5K_XRDELAY 0x80c4 /* Register Address */ -#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff /* Mask for slot delay */ -#define AR5K_XRDELAY_SLOT_DELAY_S 0 -#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 /* Mask for CHIRP data delay */ -#define AR5K_XRDELAY_CHIRP_DELAY_S 16 - -/* - * XR timeout register - */ -#define AR5K_XRTIMEOUT 0x80c8 /* Register Address */ -#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff /* Mask for CHIRP timeout */ -#define AR5K_XRTIMEOUT_CHIRP_S 0 -#define AR5K_XRTIMEOUT_POLL_M 0xffff0000 /* Mask for Poll timeout */ -#define AR5K_XRTIMEOUT_POLL_S 16 - -/* - * XR chirp register - */ -#define AR5K_XRCHIRP 0x80cc /* Register Address */ -#define AR5K_XRCHIRP_SEND 0x00000001 /* Send CHIRP */ -#define AR5K_XRCHIRP_GAP 0xffff0000 /* Mask for CHIRP gap (?) */ - -/* - * XR stomp register - */ -#define AR5K_XRSTOMP 0x80d0 /* Register Address */ -#define AR5K_XRSTOMP_TX 0x00000001 /* Stomp Tx (?) */ -#define AR5K_XRSTOMP_RX 0x00000002 /* Stomp Rx (?) */ -#define AR5K_XRSTOMP_TX_RSSI 0x00000004 /* Stomp Tx RSSI (?) */ -#define AR5K_XRSTOMP_TX_BSSID 0x00000008 /* Stomp Tx BSSID (?) */ -#define AR5K_XRSTOMP_DATA 0x00000010 /* Stomp data (?)*/ -#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 /* Mask for XR RSSI threshold */ - -/* - * First enhanced sleep register - */ -#define AR5K_SLEEP0 0x80d4 /* Register Address */ -#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff /* Mask for next DTIM (?) */ -#define AR5K_SLEEP0_NEXT_DTIM_S 0 -#define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 /* Assume DTIM */ -#define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 /* Enable enchanced sleep control */ -#define AR5K_SLEEP0_CABTO 0xff000000 /* Mask for CAB Time Out */ -#define AR5K_SLEEP0_CABTO_S 24 - -/* - * Second enhanced sleep register - */ -#define AR5K_SLEEP1 0x80d8 /* Register Address */ -#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff /* Mask for next TIM (?) */ -#define AR5K_SLEEP1_NEXT_TIM_S 0 -#define AR5K_SLEEP1_BEACON_TO 0xff000000 /* Mask for Beacon Time Out */ -#define AR5K_SLEEP1_BEACON_TO_S 24 - -/* - * Third enhanced sleep register - */ -#define AR5K_SLEEP2 0x80dc /* Register Address */ -#define AR5K_SLEEP2_TIM_PER 0x0000ffff /* Mask for TIM period (?) */ -#define AR5K_SLEEP2_TIM_PER_S 0 -#define AR5K_SLEEP2_DTIM_PER 0xffff0000 /* Mask for DTIM period (?) */ -#define AR5K_SLEEP2_DTIM_PER_S 16 - -/* - * BSSID mask registers - */ -#define AR5K_BSS_IDM0 0x80e0 /* Upper bits */ -#define AR5K_BSS_IDM1 0x80e4 /* Lower bits */ - -/* - * TX power control (TPC) register - * - * XXX: PCDAC steps (0.5dbm) or DBM ? - * - */ -#define AR5K_TXPC 0x80e8 /* Register Address */ -#define AR5K_TXPC_ACK_M 0x0000003f /* ACK tx power */ -#define AR5K_TXPC_ACK_S 0 -#define AR5K_TXPC_CTS_M 0x00003f00 /* CTS tx power */ -#define AR5K_TXPC_CTS_S 8 -#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 - */ -#define AR5K_PROFCNT_TX 0x80ec /* Tx count */ -#define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ -#define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ -#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ - -/* - * Quiet period control registers - */ -#define AR5K_QUIET_CTL1 0x80fc /* Register Address */ -#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 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 - */ -#define AR5K_TSF_PARM 0x8104 /* Register Address */ -#define AR5K_TSF_PARM_INC 0x000000ff /* Mask for TSF increment */ -#define AR5K_TSF_PARM_INC_S 0 - -/* - * QoS NOACK policy - */ -#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 7 - -/* - * PHY error filter register - */ -#define AR5K_PHY_ERR_FIL 0x810c -#define AR5K_PHY_ERR_FIL_RADAR 0x00000020 /* Radar signal */ -#define AR5K_PHY_ERR_FIL_OFDM 0x00020000 /* OFDM false detect (ANI) */ -#define AR5K_PHY_ERR_FIL_CCK 0x02000000 /* CCK false detect (ANI) */ - -/* - * XR latency register - */ -#define AR5K_XRLAT_TX 0x8110 - -/* - * ACK SIFS register - */ -#define AR5K_ACKSIFS 0x8114 /* Register Address */ -#define AR5K_ACKSIFS_INC 0x00000000 /* ACK SIFS Increment (field) */ - -/* - * MIC QoS control register (?) - */ -#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_OFF(_n) (1 << (_n * 4)) - -/* - * Misc mode control register (?) - */ -#define AR5K_MISC_MODE 0x8120 /* Register Address */ -#define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ -#define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ -#define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */ -/* more bits */ - -/* - * OFDM Filter counter - */ -#define AR5K_OFDM_FIL_CNT 0x8124 - -/* - * CCK Filter counter - */ -#define AR5K_CCK_FIL_CNT 0x8128 - -/* - * PHY Error Counters (?) - */ -#define AR5K_PHYERR_CNT1 0x812c -#define AR5K_PHYERR_CNT1_MASK 0x8130 - -#define AR5K_PHYERR_CNT2 0x8134 -#define AR5K_PHYERR_CNT2_MASK 0x8138 - -/* - * TSF Threshold register (?) - */ -#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 */ -#define AR5K_RATE_ACKSIFS(_n) (AR5K_RATE_ACKSIFS_BSE + ((_n) << 2)) -#define AR5K_RATE_ACKSIFS_NORMAL 0x00000001 /* Normal SIFS (field) */ -#define AR5K_RATE_ACKSIFS_TURBO 0x00000400 /* Turbo SIFS (field) */ - -/* - * Rate -> duration mapping table (32 entries) - */ -#define AR5K_RATE_DUR_BASE 0x8700 -#define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2)) - -/* - * Rate -> db mapping table - * (8 entries, each one has 4 8bit fields) - */ -#define AR5K_RATE2DB_BASE 0x87c0 -#define AR5K_RATE2DB(_n) (AR5K_RATE2DB_BASE + ((_n) << 2)) - -/* - * db -> Rate mapping table - * (8 entries, each one has 4 8bit fields) - */ -#define AR5K_DB2RATE_BASE 0x87e0 -#define AR5K_DB2RATE(_n) (AR5K_DB2RATE_BASE + ((_n) << 2)) - -/*===5212 end===*/ - -/* - * Key table (WEP) register - */ -#define AR5K_KEYTABLE_0_5210 0x9000 -#define AR5K_KEYTABLE_0_5211 0x8800 -#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5)) -#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) -#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \ - AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n)) -#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2)) -#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5) -#define AR5K_KEYTABLE_TYPE_40 0x00000000 -#define AR5K_KEYTABLE_TYPE_104 0x00000001 -#define AR5K_KEYTABLE_TYPE_128 0x00000003 -#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */ -#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */ -#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */ -#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */ -#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */ -#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6) -#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) -#define AR5K_KEYTABLE_VALID 0x00008000 - -/* If key type is TKIP and MIC is enabled - * MIC key goes in offset entry + 64 */ -#define AR5K_KEYTABLE_MIC_OFFSET 64 - -/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit - * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit - * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit - * - * Some vendors have introduced bigger WEP keys to address - * security vulnerabilities in WEP. This includes: - * - * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit - * - * We can expand this if we find ar5k Atheros cards with a larger - * key table size. - */ -#define AR5K_KEYTABLE_SIZE_5210 64 -#define AR5K_KEYTABLE_SIZE_5211 128 -#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \ - AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211) - - -/*===PHY REGISTERS===*/ - -/* - * PHY registers start - */ -#define AR5K_PHY_BASE 0x9800 -#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) - -/* - * TST_2 (Misc config parameters) - */ -#define AR5K_PHY_TST2 0x9800 /* Register Address */ -#define AR5K_PHY_TST2_TRIG_SEL 0x00000007 /* Trigger select (?)*/ -#define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) */ -#define AR5K_PHY_TST2_CBUS_MODE 0x00000060 /* Cardbus mode (?) */ -#define AR5K_PHY_TST2_CLK32 0x00000400 /* CLK_OUT is CLK32 (32Khz external) */ -#define AR5K_PHY_TST2_CHANCOR_DUMP_EN 0x00000800 /* Enable Chancor dump (?) */ -#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP 0x00001000 /* Even Chancor dump (?) */ -#define AR5K_PHY_TST2_RFSILENT_EN 0x00002000 /* Enable RFSILENT */ -#define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch ?) */ -#define AR5K_PHY_TST2_MINI_OBS_EN 0x00008000 /* Enable mini OBS (?) */ -#define AR5K_PHY_TST2_RX2_IS_RX5_INV 0x00010000 /* 2GHz rx path is the 5GHz path inverted (?) */ -#define AR5K_PHY_TST2_SLOW_CLK160 0x00020000 /* Slow CLK160 (?) */ -#define AR5K_PHY_TST2_AGC_OBS_SEL_3 0x00040000 /* AGC OBS Select 3 (?) */ -#define AR5K_PHY_TST2_BBB_OBS_SEL 0x00080000 /* BB OBS Select (field ?) */ -#define AR5K_PHY_TST2_ADC_OBS_SEL 0x00800000 /* ADC OBS Select (field ?) */ -#define AR5K_PHY_TST2_RX_CLR_SEL 0x08000000 /* RX Clear Select (?) */ -#define AR5K_PHY_TST2_FORCE_AGC_CLR 0x10000000 /* Force AGC clear (?) */ -#define AR5K_PHY_SHIFT_2GHZ 0x00004007 /* Used to access 2GHz radios */ -#define AR5K_PHY_SHIFT_5GHZ 0x00000007 /* Used to access 5GHz radios (default) */ - -/* - * PHY frame control register [5110] /turbo mode register [5111+] - * - * There is another frame control register for [5111+] - * at address 0x9944 (see below) but the 2 first flags - * are common here between 5110 frame control register - * and [5111+] turbo mode register, so this also works as - * a "turbo mode register" for 5110. We treat this one as - * a frame control register for 5110 below. - */ -#define AR5K_PHY_TURBO 0x9804 /* Register Address */ -#define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ -#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 - * (aka TST_1) - */ -#define AR5K_PHY_AGC 0x9808 /* Register Address */ -#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+] - */ -#define AR5K_PHY_TIMING_3 0x9814 -#define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000 -#define AR5K_PHY_TIMING_3_DSC_MAN_S 17 -#define AR5K_PHY_TIMING_3_DSC_EXP 0x0001e000 -#define AR5K_PHY_TIMING_3_DSC_EXP_S 13 - -/* - * PHY chip revision register - */ -#define AR5K_PHY_CHIP_ID 0x9818 - -/* - * PHY activation register - */ -#define AR5K_PHY_ACT 0x981c /* Register Address */ -#define AR5K_PHY_ACT_ENABLE 0x00000001 /* Activate PHY */ -#define AR5K_PHY_ACT_DISABLE 0x00000002 /* Deactivate PHY */ - -/* - * PHY RF control registers - */ -#define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */ -#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 0x0000ff00 /* TX end to XLNA on */ -#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 8 - -#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) */ -#define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON 0x00000100 /* TX frame to XPA B on (field) */ -#define AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF 0x00010000 /* TX end to XPA A off (field) */ -#define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF 0x01000000 /* TX end to XPA B off (field) */ - -/* - * Pre-Amplifier control register - * (XPA -> external pre-amplifier) - */ -#define AR5K_PHY_PA_CTL 0x9838 /* Register Address */ -#define AR5K_PHY_PA_CTL_XPA_A_HI 0x00000001 /* XPA A high (?) */ -#define AR5K_PHY_PA_CTL_XPA_B_HI 0x00000002 /* XPA B high (?) */ -#define AR5K_PHY_PA_CTL_XPA_A_EN 0x00000004 /* Enable XPA A */ -#define AR5K_PHY_PA_CTL_XPA_B_EN 0x00000008 /* Enable XPA B */ - -/* - * PHY settling register - */ -#define AR5K_PHY_SETTLING 0x9844 /* Register Address */ -#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_SETTLING_SWITCH_S 7 - -/* - * PHY Gain registers - */ -#define AR5K_PHY_GAIN 0x9848 /* Register Address */ -#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 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 /* 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 /* FIRSTEP */ -#define AR5K_PHY_SIG_FIRSTEP_S 12 -#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* FIPWR */ -#define AR5K_PHY_SIG_FIRPWR_S 18 - -/* - * PHY coarse agility control register - * (for more infos read ANI patent) - */ -#define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */ -#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* AGC Coarse low */ -#define AR5K_PHY_AGCCOARSE_LO_S 7 -#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* AGC Coarse high */ -#define AR5K_PHY_AGCCOARSE_HI_S 15 - -/* - * PHY agility control register - */ -#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 - */ -#define AR5K_PHY_NF 0x9864 /* Register address */ -#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ -#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ -#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 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] - */ -#define AR5K_PHY_ADCSAT 0x9868 -#define AR5K_PHY_ADCSAT_ICNT 0x0001f800 -#define AR5K_PHY_ADCSAT_ICNT_S 11 -#define AR5K_PHY_ADCSAT_THR 0x000007e0 -#define AR5K_PHY_ADCSAT_THR_S 5 - -/* - * PHY Weak ofdm signal detection threshold registers (ANI) [5212+] - */ - -/* High thresholds */ -#define AR5K_PHY_WEAK_OFDM_HIGH_THR 0x9868 -#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT 0x0000001f -#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S 0 -#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1 0x00fe0000 -#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S 17 -#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2 0x7f000000 -#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S 24 - -/* Low thresholds */ -#define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c -#define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN 0x00000001 -#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT 0x00003f00 -#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S 8 -#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1 0x001fc000 -#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S 14 -#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2 0x0fe00000 -#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S 21 - - -/* - * PHY sleep registers [5112+] - */ -#define AR5K_PHY_SCR 0x9870 - -#define AR5K_PHY_SLMT 0x9874 -#define AR5K_PHY_SLMT_32MHZ 0x0000007f - -#define AR5K_PHY_SCAL 0x9878 -#define AR5K_PHY_SCAL_32MHZ 0x0000000e -#define AR5K_PHY_SCAL_32MHZ_2417 0x0000000a -#define AR5K_PHY_SCAL_32MHZ_HB63 0x00000032 - -/* - * PHY PLL (Phase Locked Loop) control register - */ -#define AR5K_PHY_PLL 0x987c -#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) -/* 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 -#define AR5K_PHY_PLL_QUARTER_RATE 0x00000200 - -/* - * RF Buffer register - * - * It's obvious from the code that 0x989c is the buffer register but - * for the other special registers that we write to after sending each - * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers - * for now. It's interesting that they are also used for some other operations. - */ - -#define AR5K_RF_BUFFER 0x989c -#define AR5K_RF_BUFFER_CONTROL_0 0x98c0 /* Channel on 5110 */ -#define AR5K_RF_BUFFER_CONTROL_1 0x98c4 /* Bank 7 on 5112 */ -#define AR5K_RF_BUFFER_CONTROL_2 0x98cc /* Bank 7 on 5111 */ - -#define AR5K_RF_BUFFER_CONTROL_3 0x98d0 /* Bank 2 on 5112 */ - /* Channel set on 5111 */ - /* Used to read radio revision*/ - -#define AR5K_RF_BUFFER_CONTROL_4 0x98d4 /* RF Stage register on 5110 */ - /* Bank 0,1,2,6 on 5111 */ - /* Bank 1 on 5112 */ - /* Used during activation on 5111 */ - -#define AR5K_RF_BUFFER_CONTROL_5 0x98d8 /* Bank 3 on 5111 */ - /* Used during activation on 5111 */ - /* Channel on 5112 */ - /* Bank 6 on 5112 */ - -#define AR5K_RF_BUFFER_CONTROL_6 0x98dc /* Bank 3 on 5112 */ - -/* - * PHY RF stage register [5210] - */ -#define AR5K_PHY_RFSTG 0x98d4 -#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 */ -#define AR5K_PHY_ANT_CTL_TXRX_EN 0x00000001 /* Enable TX/RX (?) */ -#define AR5K_PHY_ANT_CTL_SECTORED_ANT 0x00000004 /* Sectored Antenna */ -#define AR5K_PHY_ANT_CTL_HITUNE5 0x00000008 /* Hitune5 (?) */ -#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x000003f0 /* Switch table idle (?) */ -#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S 4 - -/* - * PHY receiver delay register [5111+] - */ -#define AR5K_PHY_RX_DELAY 0x9914 /* Register Address */ -#define AR5K_PHY_RX_DELAY_M 0x00003fff /* Mask for RX activate to receive delay (/100ns) */ - -/* - * PHY max rx length register (?) [5111] - */ -#define AR5K_PHY_MAX_RX_LEN 0x991c - -/* - * PHY timing register 4 - * I(nphase)/Q(adrature) calibration register [5111+] - */ -#define AR5K_PHY_IQ 0x9920 /* Register Address */ -#define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ -#define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ -#define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 -#define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ -#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 /* Mask for max number of samples in log scale */ -#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S 12 -#define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */ -#define AR5K_PHY_IQ_USE_PT_DF 0x00020000 /* Use pilot track df (?) */ -#define AR5K_PHY_IQ_EARLY_TRIG_THR 0x00200000 /* Early trigger threshold (?) (field) */ -#define AR5K_PHY_IQ_PILOT_MASK_EN 0x10000000 /* Enable pilot mask (?) */ -#define AR5K_PHY_IQ_CHAN_MASK_EN 0x20000000 /* Enable channel mask (?) */ -#define AR5K_PHY_IQ_SPUR_FILT_EN 0x40000000 /* Enable spur filter */ -#define AR5K_PHY_IQ_SPUR_RSSI_EN 0x80000000 /* Enable spur rssi */ - -/* - * PHY timing register 5 - * OFDM Self-correlator Cyclic RSSI threshold params - * (Check out bb_cycpwr_thr1 on ANI patent) - */ -#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 1 -#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) (?) */ -#define AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI 0x00800000 /* Long sc threshold hi rssi (?) */ - -/* - * PHY-only warm reset register - */ -#define AR5K_PHY_WARM_RESET 0x9928 - -/* - * PHY-only control register - */ -#define AR5K_PHY_CTL 0x992c /* Register Address */ -#define AR5K_PHY_CTL_RX_DRAIN_RATE 0x00000001 /* RX drain rate (?) */ -#define AR5K_PHY_CTL_LATE_TX_SIG_SYM 0x00000002 /* Late tx signal symbol (?) */ -#define AR5K_PHY_CTL_GEN_SCRAMBLER 0x00000004 /* Generate scrambler */ -#define AR5K_PHY_CTL_TX_ANT_SEL 0x00000008 /* TX antenna select */ -#define AR5K_PHY_CTL_TX_ANT_STATIC 0x00000010 /* Static TX antenna */ -#define AR5K_PHY_CTL_RX_ANT_SEL 0x00000020 /* RX antenna select */ -#define AR5K_PHY_CTL_RX_ANT_STATIC 0x00000040 /* Static RX antenna */ -#define AR5K_PHY_CTL_LOW_FREQ_SLE_EN 0x00000080 /* Enable low freq sleep */ - -/* - * PHY PAPD probe register [5111+] - */ -#define AR5K_PHY_PAPD_PROBE 0x9930 -#define AR5K_PHY_PAPD_PROBE_SH_HI_PAR 0x00000001 -#define AR5K_PHY_PAPD_PROBE_PCDAC_BIAS 0x00000002 -#define AR5K_PHY_PAPD_PROBE_COMP_GAIN 0x00000040 -#define AR5K_PHY_PAPD_PROBE_TXPOWER 0x00007e00 -#define AR5K_PHY_PAPD_PROBE_TXPOWER_S 9 -#define AR5K_PHY_PAPD_PROBE_TX_NEXT 0x00008000 -#define AR5K_PHY_PAPD_PROBE_PREDIST_EN 0x00010000 -#define AR5K_PHY_PAPD_PROBE_TYPE 0x01800000 /* [5112+] */ -#define AR5K_PHY_PAPD_PROBE_TYPE_S 23 -#define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0 -#define AR5K_PHY_PAPD_PROBE_TYPE_XR 1 -#define AR5K_PHY_PAPD_PROBE_TYPE_CCK 2 -#define AR5K_PHY_PAPD_PROBE_GAINF 0xfe000000 -#define AR5K_PHY_PAPD_PROBE_GAINF_S 25 -#define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ -#define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ - -/* - * PHY TX rate power registers [5112+] - */ -#define AR5K_PHY_TXPOWER_RATE1 0x9934 -#define AR5K_PHY_TXPOWER_RATE2 0x9938 -#define AR5K_PHY_TXPOWER_RATE_MAX 0x993c -#define AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE 0x00000040 -#define AR5K_PHY_TXPOWER_RATE3 0xa234 -#define AR5K_PHY_TXPOWER_RATE4 0xa238 - -/* - * PHY frame control register [5111+] - */ -#define AR5K_PHY_FRAME_CTL_5210 0x9804 -#define AR5K_PHY_FRAME_CTL_5211 0x9944 -#define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \ - AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211) -/*---[5111+]---*/ -#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 */ -#define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* Illegal rate */ -#define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* Illegal length */ -#define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000 -#define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* TX underrun */ -#define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ - AR5K_PHY_FRAME_CTL_TXURN_ERR | \ - AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ - AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ - AR5K_PHY_FRAME_CTL_PARITY_ERR | \ - AR5K_PHY_FRAME_CTL_TIMING_ERR - -/* - * PHY Tx Power adjustment register [5212A+] - */ -#define AR5K_PHY_TX_PWR_ADJ 0x994c -#define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA 0x00000fc0 -#define AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S 6 -#define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX 0x00fc0000 -#define AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S 18 - -/* - * PHY radar detection register [5111+] - */ -#define AR5K_PHY_RADAR 0x9954 -#define AR5K_PHY_RADAR_ENABLE 0x00000001 -#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 - */ -#define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 -#define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 - -/* - * PHY Noise floor threshold - */ -#define AR5K_PHY_NFTHRES 0x9968 - -/* - * Sigma Delta register (?) [5213] - */ -#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 0x01ffe000 -#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 AR5K_PHY_TIMING_9 0x9998 -#define AR5K_PHY_TIMING_10 0x999c -#define AR5K_PHY_TIMING_10_PILOT_MASK_2 0x000fffff -#define AR5K_PHY_TIMING_10_PILOT_MASK_2_S 0 - -/* - * Spur mitigation control - */ -#define AR5K_PHY_TIMING_11 0x99a0 /* Register address */ -#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */ -#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0 -#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */ -#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S 20 -#define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */ -#define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */ - -/* - * 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)) -#define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */ -#define AR5K_RF_GAIN(_n) (AR5K_RF_GAIN_BASE + ((_n) << 2)) - -/* - * PHY timing IQ calibration result register [5111+] - */ -#define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */ -#define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */ -#define AR5K_PHY_IQRES_CAL_CORR 0x9c18 /* I/Q Correlation */ - -/* - * PHY current RSSI register [5111+] - */ -#define AR5K_PHY_CURRENT_RSSI 0x9c1c - -/* - * PHY RF Bus grant register - */ -#define AR5K_PHY_RFBUS_GRANT 0x9c20 -#define AR5K_PHY_RFBUS_GRANT_OK 0x00000001 - -/* - * PHY ADC test register - */ -#define AR5K_PHY_ADC_TEST 0x9c24 -#define AR5K_PHY_ADC_TEST_I 0x00000001 -#define AR5K_PHY_ADC_TEST_Q 0x00000200 - -/* - * PHY DAC test register - */ -#define AR5K_PHY_DAC_TEST 0x9c28 -#define AR5K_PHY_DAC_TEST_I 0x00000001 -#define AR5K_PHY_DAC_TEST_Q 0x00000200 - -/* - * PHY PTAT register (?) - */ -#define AR5K_PHY_PTAT 0x9c2c - -/* - * PHY Illegal TX rate register [5112+] - */ -#define AR5K_PHY_BAD_TX_RATE 0x9c30 - -/* - * PHY SPUR Power register [5112+] - */ -#define AR5K_PHY_SPUR_PWR 0x9c34 /* Register Address */ -#define AR5K_PHY_SPUR_PWR_I 0x00000001 /* SPUR Power estimate for I (field) */ -#define AR5K_PHY_SPUR_PWR_Q 0x00000100 /* SPUR Power estimate for Q (field) */ -#define AR5K_PHY_SPUR_PWR_FILT 0x00010000 /* Power with SPUR removed (field) */ - -/* - * PHY Channel status register [5112+] (?) - */ -#define AR5K_PHY_CHAN_STATUS 0x9c38 -#define AR5K_PHY_CHAN_STATUS_BT_ACT 0x00000001 -#define AR5K_PHY_CHAN_STATUS_RX_CLR_RAW 0x00000002 -#define AR5K_PHY_CHAN_STATUS_RX_CLR_MAC 0x00000004 -#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 - - -/* - * PHY PAPD I (power?) table (?) - * (92! entries) - */ -#define AR5K_PHY_PAPD_I_BASE 0xa000 -#define AR5K_PHY_PAPD_I(_n) (AR5K_PHY_PAPD_I_BASE + ((_n) << 2)) - -/* - * PHY PCDAC TX power table - */ -#define AR5K_PHY_PCDAC_TXPOWER_BASE 0xa180 -#define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2)) - -/* - * PHY mode register [5111+] - */ -#define AR5K_PHY_MODE 0x0a200 /* Register Address */ -#define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation bit */ -#define AR5K_PHY_MODE_MOD_OFDM 0 -#define AR5K_PHY_MODE_MOD_CCK 1 -#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode bit */ -#define AR5K_PHY_MODE_FREQ_5GHZ 0 -#define AR5K_PHY_MODE_FREQ_2GHZ 2 -#define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Enable Dynamic OFDM/CCK mode [5112+] */ -#define AR5K_PHY_MODE_RAD 0x00000008 /* [5212+] */ -#define AR5K_PHY_MODE_RAD_RF5111 0 -#define AR5K_PHY_MODE_RAD_RF5112 8 -#define AR5K_PHY_MODE_XR 0x00000010 /* Enable XR mode [5112+] */ -#define AR5K_PHY_MODE_HALF_RATE 0x00000020 /* Enable Half rate (test) */ -#define AR5K_PHY_MODE_QUARTER_RATE 0x00000040 /* Enable Quarter rat (test) */ - -/* - * PHY CCK transmit control register [5111+ (?)] - */ -#define AR5K_PHY_CCKTXCTL 0xa204 -#define AR5K_PHY_CCKTXCTL_WORLD 0x00000000 -#define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010 -#define AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS 0x00000001 -#define AR5K_PHY_CCKTXCTK_DAC_SCALE 0x00000004 - -/* - * PHY CCK Cross-correlator Barker RSSI threshold register [5212+] - */ -#define AR5K_PHY_CCK_CROSSCORR 0xa208 -#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_MARGIN_TXRX_S 18 -#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_RG1_PDGAIN_1 0x00030000 -#define AR5K_PHY_TPC_RG1_PDGAIN_1_S 16 -#define AR5K_PHY_TPC_RG1_PDGAIN_2 0x000c0000 -#define AR5K_PHY_TPC_RG1_PDGAIN_2_S 18 -#define AR5K_PHY_TPC_RG1_PDGAIN_3 0x00300000 -#define AR5K_PHY_TPC_RG1_PDGAIN_3_S 20 - -#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 - -/* - * PHY PDADC Tx power table - */ -#define AR5K_PHY_PDADC_TXPOWER_BASE 0xa280 -#define AR5K_PHY_PDADC_TXPOWER(_n) (AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2)) diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c deleted file mode 100644 index 775fdf7..0000000 --- a/drivers/net/wireless/ath5k/reset.c +++ /dev/null @@ -1,1346 +0,0 @@ -/* - * Copyright (c) 2004-2008 Reyk Floeter - * Copyright (c) 2006-2008 Nick Kossifidis - * Copyright (c) 2007-2008 Luis Rodriguez - * Copyright (c) 2007-2008 Pavel Roskin - * Copyright (c) 2007-2008 Jiri Slaby - * - * 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 /* To determine if a card is pci-e */ -#include /* For get_bitmask_order */ -#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 delta slope coefficient (used on pilot tracking ?) for OFDM - * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset(). - * - * Since delta slope is floating point we split it on its exponent and - * mantissa and provide these values on hw. - * - * For more infos i think this patent is related - * http://www.freepatentsonline.com/7184495.html - */ -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; - - BUG_ON(!(ah->ah_version == AR5K_AR5212) || - !(channel->hw_value & CHANNEL_OFDM)); - - /* Get coefficient - * ALGO: coef = (5 * clock * carrier_freq) / 2) - * we scale coef by shifting clock value by 24 for - * better precision since we use integers */ - /* TODO: Half/quarter rate */ - clock = ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO); - - coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq; - - /* Get exponent - * ALGO: coef_exp = 14 - highest set bit position */ - coef_exp = get_bitmask_order(coef_scaled); - - /* Doesn't make sense if it's zero*/ - if (!coef_exp) - return -EINVAL; - - /* Note: we've shifted coef_scaled by 24 */ - coef_exp = 14 - (coef_exp - 24); - - - /* Get mantissa (significant digits) - * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */ - coef_man = coef_scaled + - (1 << (24 - coef_exp - 1)); - - /* Calculate delta slope coefficient exponent - * and mantissa (remove scaling) and set them on hw */ - 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 const unsigned int control_rates[] = - { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; - -/** - * ath5k_hw_write_rate_duration - fill rate code to duration table - * - * @ah: the &struct ath5k_hw - * @mode: one of enum ath5k_driver_mode - * - * Write the rate code to duration table upon hw reset. This is a helper for - * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on - * the hardware, based on current mode, for each rate. The rates which are - * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have - * different rate code so we write their value twice (one for long preample - * and one for short). - * - * Note: Band doesn't matter here, if we set the values for OFDM it works - * on both a and g modes. So all we have to do is set values for all g rates - * that include all OFDM and CCK rates. If we operate in turbo or xr/half/ - * quarter rate mode, we need to use another set of bitrates (that's why we - * need the mode parameter) but we don't handle these proprietary modes yet. - */ -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 and program PLL - * TODO: Half/Quarter rate support - */ -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; - - if (ah->ah_radio == AR5K_RF5413) - clock = AR5K_PHY_PLL_40MHZ_5413; - else - 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) { - - /* ...update PLL if needed */ - if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) { - ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); - udelay(300); - } - - /* ...set the PHY operating mode */ - ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); - ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); - } - - return 0; -} - -/* - * If there is an external 32KHz crystal available, use it - * as ref. clock instead of 32/40MHz clock and baseband clocks - * to save power during sleep or restore normal 32/40MHz - * operation. - * - * XXX: When operating on 32KHz certain PHY registers (27 - 31, - * 123 - 127) require delay on access. - */ -static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 scal, spending, usec32; - - /* Only set 32KHz settings if we have an external - * 32KHz crystal present */ - if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) || - AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) && - enable) { - - /* 1 usec/cycle */ - AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1); - /* Set up tsf increment on each cycle */ - AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61); - - /* Set baseband sleep control registers - * and sleep control rate */ - ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR); - - if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413) || - (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) - spending = 0x14; - else - spending = 0x18; - ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING); - - if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413) || - (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) { - ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT); - ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL); - ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK); - ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY); - AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG, - AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02); - } else { - ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT); - ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL); - ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK); - ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY); - AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG, - AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03); - } - - /* Enable sleep clock operation */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, - AR5K_PCICFG_SLEEP_CLOCK_EN); - - } else { - - /* Disable sleep clock operation and - * restore default parameters */ - AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, - AR5K_PCICFG_SLEEP_CLOCK_EN); - - AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG, - AR5K_PCICFG_SLEEP_CLOCK_RATE, 0); - - ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR); - ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); - - if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) - scal = AR5K_PHY_SCAL_32MHZ_2417; - else if (ath5k_eeprom_is_hb63(ah)) - scal = AR5K_PHY_SCAL_32MHZ_HB63; - else - scal = AR5K_PHY_SCAL_32MHZ; - ath5k_hw_reg_write(ah, scal, 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); - - if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413) || - (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) - spending = 0x14; - else - spending = 0x18; - ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING); - - if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413)) - usec32 = 39; - else - usec32 = 31; - AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, usec32); - - AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1); - } - return; -} - -static bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u8 refclk_freq; - - if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413) || - (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) - refclk_freq = 40; - else - refclk_freq = 32; - - if ((channel->center_freq % refclk_freq != 0) && - ((channel->center_freq % refclk_freq < 10) || - (channel->center_freq % refclk_freq > 22))) - return true; - else - return false; -} - -/* TODO: Half/Quarter rate */ -static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - if (ah->ah_version == AR5K_AR5212 && - ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { - - /* Setup ADC control */ - ath5k_hw_reg_write(ah, - (AR5K_REG_SM(2, - AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) | - AR5K_REG_SM(2, - AR5K_PHY_ADC_CTL_INBUFGAIN_ON) | - AR5K_PHY_ADC_CTL_PWD_DAC_OFF | - AR5K_PHY_ADC_CTL_PWD_ADC_OFF), - AR5K_PHY_ADC_CTL); - - - - /* Disable barker RSSI threshold */ - AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL, - AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR); - - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL, - AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2); - - /* Set the mute mask */ - ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); - } - - /* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */ - if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B) - ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH); - - /* Enable DCU double buffering */ - if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B) - AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_DCU_DBL_BUF_DIS); - - /* Set DAC/ADC delays */ - if (ah->ah_version == AR5K_AR5212) { - u32 scal; - if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) - scal = AR5K_PHY_SCAL_32MHZ_2417; - else if (ath5k_eeprom_is_hb63(ah)) - scal = AR5K_PHY_SCAL_32MHZ_HB63; - else - scal = AR5K_PHY_SCAL_32MHZ; - ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL); - } - - /* Set fast ADC */ - if ((ah->ah_radio == AR5K_RF5413) || - (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) { - u32 fast_adc = true; - - if (channel->center_freq == 2462 || - channel->center_freq == 2467) - fast_adc = 0; - - /* Only update if needed */ - if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc) - ath5k_hw_reg_write(ah, fast_adc, - AR5K_PHY_FAST_ADC); - } - - /* Fix for first revision of the RF5112 RF chipset */ - if (ah->ah_radio == AR5K_RF5112 && - ah->ah_radio_5ghz_revision < - AR5K_SREV_RAD_5112A) { - u32 data; - 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); - } - - if (ah->ah_mac_srev < AR5K_SREV_AR5211) { - u32 usec_reg; - /* 5311 has different tx/rx latency masks - * from 5211, since we deal 5311 the same - * as 5211 when setting initvals, shift - * values here to their proper locations */ - usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211); - ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 | - AR5K_USEC_32 | - AR5K_USEC_TX_LATENCY_5211 | - AR5K_REG_SM(29, - AR5K_USEC_RX_LATENCY_5210)), - AR5K_USEC_5211); - /* Clear QCU/DCU clock gating register */ - ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT); - /* Set DAC/ADC delays */ - ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL); - /* Enable PCU FIFO corruption ECO */ - AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211, - AR5K_DIAG_SW_ECO_ENABLE); - } -} - -static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, - struct ieee80211_channel *channel, u8 *ant, u8 ee_mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - s16 cck_ofdm_pwr_delta; - - /* Adjust power delta for channel 14 */ - if (channel->center_freq == 2484) - cck_ofdm_pwr_delta = - ((ee->ee_cck_ofdm_power_delta - - ee->ee_scaled_cck_delta) * 2) / 10; - else - cck_ofdm_pwr_delta = - (ee->ee_cck_ofdm_power_delta * 2) / 10; - - /* Set CCK to OFDM power delta on tx power - * adjustment register */ - if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { - if (channel->hw_value == CHANNEL_G) - ath5k_hw_reg_write(ah, - AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1), - AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) | - AR5K_REG_SM((cck_ofdm_pwr_delta * -1), - AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX), - AR5K_PHY_TX_PWR_ADJ); - else - ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ); - } else { - /* For older revs we scale power on sw during tx power - * setup */ - ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta; - ah->ah_txpower.txp_cck_ofdm_gainf_delta = - ee->ee_cck_ofdm_gain_delta; - } - - /* Set antenna idle switch table */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL, - AR5K_PHY_ANT_CTL_SWTABLE_IDLE, - (ah->ah_antenna[ee_mode][0] | - AR5K_PHY_ANT_CTL_TXRX_EN)); - - /* Set antenna switch table */ - 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); - - /* Noise floor threshold */ - ath5k_hw_reg_write(ah, - AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), - AR5K_PHY_NFTHRES); - - if ((channel->hw_value & CHANNEL_TURBO) && - (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) { - /* Switch settling time (Turbo) */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING, - AR5K_PHY_SETTLING_SWITCH, - ee->ee_switch_settling_turbo[ee_mode]); - - /* Tx/Rx attenuation (Turbo) */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN, - AR5K_PHY_GAIN_TXRX_ATTEN, - ee->ee_atn_tx_rx_turbo[ee_mode]); - - /* ADC/PGA desired size (Turbo) */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, - AR5K_PHY_DESIRED_SIZE_ADC, - ee->ee_adc_desired_size_turbo[ee_mode]); - - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, - AR5K_PHY_DESIRED_SIZE_PGA, - ee->ee_pga_desired_size_turbo[ee_mode]); - - /* Tx/Rx margin (Turbo) */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, - AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, - ee->ee_margin_tx_rx_turbo[ee_mode]); - - } else { - /* Switch settling time */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING, - AR5K_PHY_SETTLING_SWITCH, - ee->ee_switch_settling[ee_mode]); - - /* Tx/Rx attenuation */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN, - AR5K_PHY_GAIN_TXRX_ATTEN, - ee->ee_atn_tx_rx[ee_mode]); - - /* ADC/PGA desired size */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, - AR5K_PHY_DESIRED_SIZE_ADC, - ee->ee_adc_desired_size[ee_mode]); - - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, - AR5K_PHY_DESIRED_SIZE_PGA, - ee->ee_pga_desired_size[ee_mode]); - - /* Tx/Rx margin */ - 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]); - } - - /* XPA delays */ - 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); - - /* XLNA delay */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3, - AR5K_PHY_RF_CTL3_TXE2XLNA_ON, - ee->ee_tx_end2xlna_enable[ee_mode]); - - /* Thresh64 (ANI) */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF, - AR5K_PHY_NF_THRESH62, - ee->ee_thr_62[ee_mode]); - - - /* False detect backoff for channels - * that have spur noise. Write the new - * cyclic power RSSI threshold. */ - if (ath5k_hw_chan_has_spur_noise(ah, channel)) - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, - AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, - AR5K_INIT_CYCRSSI_THR1 + - ee->ee_false_detect[ee_mode]); - else - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, - AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, - AR5K_INIT_CYCRSSI_THR1); - - /* I/Q correction - * TODO: Per channel i/q infos ? */ - 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]); - - /* Heavy clipping -disable for now */ - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1) - ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE); - - return; -} - -/* - * Main reset function - */ -int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, - struct ieee80211_channel *channel, bool change_channel) -{ - u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo; - u32 phy_tst1; - u8 mode, freq, ee_mode, ant[2]; - int i, ret; - - ATH5K_TRACE(ah->ah_sc); - - s_ant = 0; - ee_mode = 0; - staid1_flags = 0; - tsf_up = 0; - tsf_lo = 0; - freq = 0; - mode = 0; - - /* - * Save some registers before a reset - */ - /*DCU/Antenna selection not available on 5210*/ - if (ah->ah_version != AR5K_AR5210) { - - 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; - case CHANNEL_TG: - if (ah->ah_version == AR5K_AR5211) { - ATH5K_ERR(ah->ah_sc, - "TurboG mode not available on 5211"); - return -EINVAL; - } - 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; - } - - if (change_channel) { - /* - * Save frame sequence count - * For revs. after Oahu, only save - * seq num for DCU 0 (Global seq num) - */ - if (ah->ah_mac_srev < AR5K_SREV_AR5211) { - - for (i = 0; i < 10; i++) - s_seq[i] = ath5k_hw_reg_read(ah, - AR5K_QUEUE_DCU_SEQNUM(i)); - - } else { - s_seq[0] = ath5k_hw_reg_read(ah, - AR5K_QUEUE_DCU_SEQNUM(0)); - } - - /* TSF accelerates on AR5211 durring reset - * As a workaround save it here and restore - * it later so that it's back in time after - * reset. This way it'll get re-synced on the - * next beacon without breaking ad-hoc. - * - * On AR5212 TSF is almost preserved across a - * reset so it stays back in time anyway and - * we don't have to save/restore it. - * - * XXX: Since this breaks power saving we have - * to disable power saving until we receive the - * next beacon, so we can resync beacon timers */ - if (ah->ah_version == AR5K_AR5211) { - tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32); - tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32); - } - } - - /* Save default antenna */ - s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); - - if (ah->ah_version == AR5K_AR5212) { - /* Restore normal 32/40MHz clock operation - * to avoid register access delay on certain - * PHY registers */ - ath5k_hw_set_sleep_clock(ah, false); - - /* Since we are going to write rf buffer - * check if we have any pending gain_F - * optimization settings */ - if (change_channel && ah->ah_rf_banks != NULL) - ath5k_hw_gainf_calibrate(ah); - } - } - - /*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); - - /* AR5K_STA_ID1 flags, only preserve antenna - * settings and ack/cts rate mode */ - staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & - (AR5K_STA_ID1_DEFAULT_ANTENNA | - AR5K_STA_ID1_DESC_ANTENNA | - AR5K_STA_ID1_RTS_DEF_ANTENNA | - AR5K_STA_ID1_ACKCTS_6MB | - AR5K_STA_ID1_BASE_RATE_11B | - AR5K_STA_ID1_SELFGEN_DEF_ANT); - - /* 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; - - /* PHY access enable */ - if (ah->ah_mac_srev >= AR5K_SREV_AR5211) - ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); - else - ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40, - AR5K_PHY(0)); - - /* Write initial settings */ - 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_init(ah, freq); - if (ret) - return ret; - - mdelay(1); - - /* - * Tweak initval settings for revised - * chipsets and add some more config - * bits - */ - ath5k_hw_tweak_initval_settings(ah, channel); - - /* - * Set TX power (FIXME) - */ - ret = ath5k_hw_txpower(ah, channel, ee_mode, - 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 buffer - */ - ret = ath5k_hw_rfregs_init(ah, channel, mode); - if (ret) - return ret; - - - /* 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); - } - - /* - * 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; - } - - /* Commit values from EEPROM */ - ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode); - - } else { - /* - * For 5210 we do all initialization using - * initvals, so we don't have to modify - * any settings (5210 also only supports - * a/aturbo modes) - */ - 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) { - - if (change_channel) { - if (ah->ah_mac_srev < AR5K_SREV_AR5211) { - for (i = 0; i < 10; i++) - ath5k_hw_reg_write(ah, s_seq[i], - AR5K_QUEUE_DCU_SEQNUM(i)); - } else { - ath5k_hw_reg_write(ah, s_seq[0], - AR5K_QUEUE_DCU_SEQNUM(0)); - } - - - if (ah->ah_version == AR5K_AR5211) { - ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32); - ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32); - } - } - - ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); - } - - /* Ledstate */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); - - /* Gpio settings */ - ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); - ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); - - /* Restore sta_id flags and preserve our mac address*/ - ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id), - AR5K_STA_ID0); - ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id), - AR5K_STA_ID1); - - - /* - * Configure PCU - */ - - /* Restore bssid and bssid mask */ - /* XXX: add ah->aid once mac80211 gives this to us */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); - - /* Set PCU config */ - ath5k_hw_set_opmode(ah); - - /* Clear any pending interrupts - * PISR/SISR Not available on 5210 */ - if (ah->ah_version != AR5K_AR5210) - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); - - /* Set RSSI/BRSSI thresholds - * - * Note: If we decide to set this value - * dynamicaly, have in mind that when AR5K_RSSI_THR - * register is read it might return 0x40 if we haven't - * wrote anything to it plus BMISS RSSI threshold is zeroed. - * So doing a save/restore procedure here isn't the right - * choice. Instead store it on ath5k_hw */ - ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES | - AR5K_TUNE_BMISS_THRES << - AR5K_RSSI_THR_BMISS_S), - AR5K_RSSI_THR); - - /* MIC QoS support */ - if (ah->ah_mac_srev >= AR5K_SREV_AR2413) { - ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL); - ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL); - } - - /* QoS NOACK Policy */ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, - AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) | - AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET) | - AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET), - AR5K_QOS_NOACK); - } - - - /* - * Configure PHY - */ - - /* Set channel on PHY */ - ret = ath5k_hw_channel(ah, channel); - if (ret) - return ret; - - /* - * Enable the PHY and wait until completion - * This includes BaseBand and Synthesizer - * activation. - */ - ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - - /* - * On 5211+ read activation -> rx delay - * and use it. - * - * TODO: Half/quarter rate support - */ - if (ah->ah_version != AR5K_AR5210) { - u32 delay; - delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & - AR5K_PHY_RX_DELAY_M; - delay = (channel->hw_value & CHANNEL_CCK) ? - ((delay << 2) / 22) : (delay / 10); - - udelay(100 + (2 * delay)); - } else { - mdelay(1); - } - - /* - * Perform ADC test to see if baseband is ready - * Set tx hold and check adc test register - */ - phy_tst1 = 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, phy_tst1, AR5K_PHY_TST1); - - /* - * Start automatic gain control calibration - * - * During AGC calibration RX path is re-routed to - * a power 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. - * - * While rx path is re-routed to the power detector we also - * start a noise floor calibration, to measure the - * card's noise floor (the noise we measure when we are not - * transmiting or receiving anything). - * - * If we are in a noisy environment AGC calibration may time - * out and/or noise floor calibration might timeout. - */ - 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); - } - - /* - * 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. Also if AGC or NF cal. - * times out, reset doesn't fail on binary HAL. I believe - * that's wrong because since rx path is routed to a detector, - * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211 - * enables noise floor calibration after offset calibration and if noise - * floor calibration fails, reset fails. I believe that's - * a better approach, we just need to find a polling interval - * that suits best, even if reset continues we need to make - * sure that rx path is ready. - */ - ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - - - /* - * Configure QCUs/DCUs - */ - - /* TODO: HW Compression support for data queues */ - /* TODO: Burst prefetch for data queues */ - - /* - * Reset queues and start beacon timers at the end of the reset routine - * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping - * Note: If we want we can assign multiple qcus on one dcu. - */ - for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; 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; - } - } - - - /* - * Configure DMA/Interrupts - */ - - /* - * Set Rx/Tx DMA Configuration - * - * Set standard DMA size (128). Note that - * a DMA size of 512 causes rx overruns and tx errors - * on pci-e cards (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). - * - * 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 ;-) - */ - if (ah->ah_version != AR5K_AR5210) { - AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); - AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, - AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B); - } - - /* Pre-enable interrupts on 5211/5212*/ - if (ah->ah_version != AR5K_AR5210) - ath5k_hw_set_imr(ah, ah->ah_imr); - - /* - * Setup RFKill interrupt if rfkill flag is set on eeprom. - * TODO: Use gpio pin and polarity infos from eeprom - * TODO: Handle this in ath5k_intr because it'll result - * a nasty interrupt storm. - */ -#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 - - /* Enable 32KHz clock function for AR5212+ chips - * Set clocks to 32KHz operation and use an - * external 32KHz crystal when sleeping if one - * exists */ - if (ah->ah_version == AR5K_AR5212) - ath5k_hw_set_sleep_clock(ah, true); - - /* - * 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/ath5k/rfbuffer.h b/drivers/net/wireless/ath5k/rfbuffer.h deleted file mode 100644 index e50baff..0000000 --- a/drivers/net/wireless/ath5k/rfbuffer.h +++ /dev/null @@ -1,1181 +0,0 @@ -/* - * RF Buffer handling functions - * - * Copyright (c) 2009 Nick Kossifidis - * - * 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. - * - */ - - -/* - * There are some special registers on the RF chip - * that control various operation settings related mostly to - * the analog parts (channel, gain adjustment etc). - * - * We don't write on those registers directly but - * we send a data packet on the chip, using a special register, - * that holds all the settings we need. After we 've sent the - * data packet, we write on another special register to notify hw - * to apply the settings. This is done so that control registers - * can be dynamicaly programmed during operation and the settings - * are applied faster on the hw. - * - * We call each data packet an "RF Bank" and all the data we write - * (all RF Banks) "RF Buffer". This file holds initial RF Buffer - * data for the different RF chips, and various info to match RF - * Buffer offsets with specific RF registers so that we can access - * them. We tweak these settings on rfregs_init function. - * - * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer - * registers and control registers): - * - * http://www.google.com/patents?id=qNURAAAAEBAJ - */ - - -/* - * Struct to hold default mode specific RF - * register values (RF Banks) - */ -struct ath5k_ini_rfbuffer { - u8 rfb_bank; /* RF Bank number */ - u16 rfb_ctrl_register; /* RF Buffer control register */ - u32 rfb_mode_data[5]; /* RF Buffer data for each mode */ -}; - -/* - * Struct to hold RF Buffer field - * infos used to access certain RF - * analog registers - */ -struct ath5k_rfb_field { - u8 len; /* Field length */ - u16 pos; /* Offset on the raw packet */ - u8 col; /* Column -used for shifting */ -}; - -/* - * RF analog register definition - */ -struct ath5k_rf_reg { - u8 bank; /* RF Buffer Bank number */ - u8 index; /* Register's index on rf_regs_idx */ - struct ath5k_rfb_field field; /* RF Buffer field for this register */ -}; - -/* Map RF registers to indexes - * We do this to handle common bits and make our - * life easier by using an index for each register - * instead of a full rfb_field */ -enum ath5k_rf_regs_idx { - /* BANK 6 */ - AR5K_RF_OB_2GHZ = 0, - AR5K_RF_OB_5GHZ, - AR5K_RF_DB_2GHZ, - AR5K_RF_DB_5GHZ, - AR5K_RF_FIXED_BIAS_A, - AR5K_RF_FIXED_BIAS_B, - AR5K_RF_PWD_XPD, - AR5K_RF_XPD_SEL, - AR5K_RF_XPD_GAIN, - AR5K_RF_PD_GAIN_LO, - AR5K_RF_PD_GAIN_HI, - AR5K_RF_HIGH_VC_CP, - AR5K_RF_MID_VC_CP, - AR5K_RF_LOW_VC_CP, - AR5K_RF_PUSH_UP, - AR5K_RF_PAD2GND, - AR5K_RF_XB2_LVL, - AR5K_RF_XB5_LVL, - AR5K_RF_PWD_ICLOBUF_2G, - AR5K_RF_PWD_84, - AR5K_RF_PWD_90, - AR5K_RF_PWD_130, - AR5K_RF_PWD_131, - AR5K_RF_PWD_132, - AR5K_RF_PWD_136, - AR5K_RF_PWD_137, - AR5K_RF_PWD_138, - AR5K_RF_PWD_166, - AR5K_RF_PWD_167, - AR5K_RF_DERBY_CHAN_SEL_MODE, - /* BANK 7 */ - AR5K_RF_GAIN_I, - AR5K_RF_PLO_SEL, - AR5K_RF_RFGAIN_SEL, - AR5K_RF_RFGAIN_STEP, - AR5K_RF_WAIT_S, - AR5K_RF_WAIT_I, - AR5K_RF_MAX_TIME, - AR5K_RF_MIXVGA_OVR, - AR5K_RF_MIXGAIN_OVR, - AR5K_RF_MIXGAIN_STEP, - AR5K_RF_PD_DELAY_A, - AR5K_RF_PD_DELAY_B, - AR5K_RF_PD_DELAY_XR, - AR5K_RF_PD_PERIOD_A, - AR5K_RF_PD_PERIOD_B, - AR5K_RF_PD_PERIOD_XR, -}; - - -/*******************\ -* RF5111 (Sombrero) * -\*******************/ - -/* BANK 6 len pos col */ -#define AR5K_RF5111_OB_2GHZ { 3, 119, 0 } -#define AR5K_RF5111_DB_2GHZ { 3, 122, 0 } - -#define AR5K_RF5111_OB_5GHZ { 3, 104, 0 } -#define AR5K_RF5111_DB_5GHZ { 3, 107, 0 } - -#define AR5K_RF5111_PWD_XPD { 1, 95, 0 } -#define AR5K_RF5111_XPD_GAIN { 4, 96, 0 } - -/* Access to PWD registers */ -#define AR5K_RF5111_PWD(_n) { 1, (135 - _n), 3 } - -/* BANK 7 len pos col */ -#define AR5K_RF5111_GAIN_I { 6, 29, 0 } -#define AR5K_RF5111_PLO_SEL { 1, 4, 0 } -#define AR5K_RF5111_RFGAIN_SEL { 1, 36, 0 } -#define AR5K_RF5111_RFGAIN_STEP { 6, 37, 0 } -/* Only on AR5212 BaseBand and up */ -#define AR5K_RF5111_WAIT_S { 5, 19, 0 } -#define AR5K_RF5111_WAIT_I { 5, 24, 0 } -#define AR5K_RF5111_MAX_TIME { 2, 49, 0 } - -static const struct ath5k_rf_reg rf_regs_5111[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF5111_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF5111_DB_2GHZ}, - {6, AR5K_RF_OB_5GHZ, AR5K_RF5111_OB_5GHZ}, - {6, AR5K_RF_DB_5GHZ, AR5K_RF5111_DB_5GHZ}, - {6, AR5K_RF_PWD_XPD, AR5K_RF5111_PWD_XPD}, - {6, AR5K_RF_XPD_GAIN, AR5K_RF5111_XPD_GAIN}, - {6, AR5K_RF_PWD_84, AR5K_RF5111_PWD(84)}, - {6, AR5K_RF_PWD_90, AR5K_RF5111_PWD(90)}, - {7, AR5K_RF_GAIN_I, AR5K_RF5111_GAIN_I}, - {7, AR5K_RF_PLO_SEL, AR5K_RF5111_PLO_SEL}, - {7, AR5K_RF_RFGAIN_SEL, AR5K_RF5111_RFGAIN_SEL}, - {7, AR5K_RF_RFGAIN_STEP, AR5K_RF5111_RFGAIN_STEP}, - {7, AR5K_RF_WAIT_S, AR5K_RF5111_WAIT_S}, - {7, AR5K_RF_WAIT_I, AR5K_RF5111_WAIT_I}, - {7, AR5K_RF_MAX_TIME, AR5K_RF5111_MAX_TIME} -}; - -/* Default mode specific settings */ -static const struct ath5k_ini_rfbuffer rfb_5111[] = { - { 0, 0x989c, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 0, 0x989c, - { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } }, - { 0, 0x989c, - { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } }, - { 0, 0x98d4, - { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } }, - { 1, 0x98d4, - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d4, - { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } }, - { 3, 0x98d8, - { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, - { 6, 0x989c, - { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } }, - { 6, 0x989c, - { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } }, - { 6, 0x989c, - { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } }, - { 6, 0x989c, - { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } }, - { 6, 0x989c, - { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } }, - { 6, 0x98d4, - { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } }, - { 7, 0x989c, - { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } }, - { 7, 0x989c, - { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } }, - { 7, 0x989c, - { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, - { 7, 0x989c, - { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } }, - { 7, 0x989c, - { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } }, - { 7, 0x989c, - { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } }, - { 7, 0x989c, - { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } }, - { 7, 0x98cc, - { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } }, -}; - - - -/***********************\ -* RF5112/RF2112 (Derby) * -\***********************/ - -/* BANK 7 (Common) len pos col */ -#define AR5K_RF5112X_GAIN_I { 6, 14, 0 } -#define AR5K_RF5112X_MIXVGA_OVR { 1, 36, 0 } -#define AR5K_RF5112X_MIXGAIN_OVR { 2, 37, 0 } -#define AR5K_RF5112X_MIXGAIN_STEP { 4, 32, 0 } -#define AR5K_RF5112X_PD_DELAY_A { 4, 58, 0 } -#define AR5K_RF5112X_PD_DELAY_B { 4, 62, 0 } -#define AR5K_RF5112X_PD_DELAY_XR { 4, 66, 0 } -#define AR5K_RF5112X_PD_PERIOD_A { 4, 70, 0 } -#define AR5K_RF5112X_PD_PERIOD_B { 4, 74, 0 } -#define AR5K_RF5112X_PD_PERIOD_XR { 4, 78, 0 } - -/* RFX112 (Derby 1) */ - -/* BANK 6 len pos col */ -#define AR5K_RF5112_OB_2GHZ { 3, 269, 0 } -#define AR5K_RF5112_DB_2GHZ { 3, 272, 0 } - -#define AR5K_RF5112_OB_5GHZ { 3, 261, 0 } -#define AR5K_RF5112_DB_5GHZ { 3, 264, 0 } - -#define AR5K_RF5112_FIXED_BIAS_A { 1, 260, 0 } -#define AR5K_RF5112_FIXED_BIAS_B { 1, 259, 0 } - -#define AR5K_RF5112_XPD_SEL { 1, 284, 0 } -#define AR5K_RF5112_XPD_GAIN { 2, 252, 0 } - -/* Access to PWD registers */ -#define AR5K_RF5112_PWD(_n) { 1, (302 - _n), 3 } - -static const struct ath5k_rf_reg rf_regs_5112[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF5112_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF5112_DB_2GHZ}, - {6, AR5K_RF_OB_5GHZ, AR5K_RF5112_OB_5GHZ}, - {6, AR5K_RF_DB_5GHZ, AR5K_RF5112_DB_5GHZ}, - {6, AR5K_RF_FIXED_BIAS_A, AR5K_RF5112_FIXED_BIAS_A}, - {6, AR5K_RF_FIXED_BIAS_B, AR5K_RF5112_FIXED_BIAS_B}, - {6, AR5K_RF_XPD_SEL, AR5K_RF5112_XPD_SEL}, - {6, AR5K_RF_XPD_GAIN, AR5K_RF5112_XPD_GAIN}, - {6, AR5K_RF_PWD_130, AR5K_RF5112_PWD(130)}, - {6, AR5K_RF_PWD_131, AR5K_RF5112_PWD(131)}, - {6, AR5K_RF_PWD_132, AR5K_RF5112_PWD(132)}, - {6, AR5K_RF_PWD_136, AR5K_RF5112_PWD(136)}, - {6, AR5K_RF_PWD_137, AR5K_RF5112_PWD(137)}, - {6, AR5K_RF_PWD_138, AR5K_RF5112_PWD(138)}, - {7, AR5K_RF_GAIN_I, AR5K_RF5112X_GAIN_I}, - {7, AR5K_RF_MIXVGA_OVR, AR5K_RF5112X_MIXVGA_OVR}, - {7, AR5K_RF_MIXGAIN_OVR, AR5K_RF5112X_MIXGAIN_OVR}, - {7, AR5K_RF_MIXGAIN_STEP, AR5K_RF5112X_MIXGAIN_STEP}, - {7, AR5K_RF_PD_DELAY_A, AR5K_RF5112X_PD_DELAY_A}, - {7, AR5K_RF_PD_DELAY_B, AR5K_RF5112X_PD_DELAY_B}, - {7, AR5K_RF_PD_DELAY_XR, AR5K_RF5112X_PD_DELAY_XR}, - {7, AR5K_RF_PD_PERIOD_A, AR5K_RF5112X_PD_PERIOD_A}, - {7, AR5K_RF_PD_PERIOD_B, AR5K_RF5112X_PD_PERIOD_B}, - {7, AR5K_RF_PD_PERIOD_XR, AR5K_RF5112X_PD_PERIOD_XR}, -}; - -/* Default mode specific settings */ -static const struct ath5k_ini_rfbuffer rfb_5112[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, - { 3, 0x98dc, - { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } }, - { 6, 0x989c, - { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } }, - { 6, 0x989c, - { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } }, - { 6, 0x989c, - { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } }, - { 6, 0x989c, - { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } }, - { 6, 0x989c, - { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, - { 6, 0x989c, - { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, - { 6, 0x989c, - { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, - { 6, 0x989c, - { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, - { 6, 0x989c, - { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, - { 6, 0x989c, - { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } }, - { 6, 0x989c, - { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } }, - { 6, 0x989c, - { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, - { 6, 0x989c, - { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, - { 6, 0x989c, - { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } }, - { 6, 0x989c, - { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } }, - { 6, 0x989c, - { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, - { 6, 0x989c, - { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } }, - { 6, 0x989c, - { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, - { 6, 0x989c, - { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, - { 6, 0x989c, - { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } }, - { 6, 0x989c, - { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } }, - { 6, 0x989c, - { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, - { 6, 0x989c, - { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } }, - { 6, 0x989c, - { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } }, - { 6, 0x989c, - { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } }, - { 6, 0x989c, - { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } }, - { 6, 0x989c, - { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } }, - { 6, 0x989c, - { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } }, - { 6, 0x989c, - { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } }, - { 6, 0x989c, - { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } }, - { 6, 0x989c, - { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } }, - { 6, 0x989c, - { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } }, - { 6, 0x98d0, - { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } }, - { 7, 0x989c, - { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, - { 7, 0x989c, - { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, - { 7, 0x989c, - { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } }, - { 7, 0x989c, - { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, - { 7, 0x989c, - { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } }, - { 7, 0x989c, - { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, - { 7, 0x989c, - { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, - { 7, 0x989c, - { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } }, - { 7, 0x989c, - { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } }, - { 7, 0x989c, - { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, - { 7, 0x989c, - { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, - { 7, 0x989c, - { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, - { 7, 0x98c4, - { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, -}; - -/* RFX112A (Derby 2) */ - -/* BANK 6 len pos col */ -#define AR5K_RF5112A_OB_2GHZ { 3, 287, 0 } -#define AR5K_RF5112A_DB_2GHZ { 3, 290, 0 } - -#define AR5K_RF5112A_OB_5GHZ { 3, 279, 0 } -#define AR5K_RF5112A_DB_5GHZ { 3, 282, 0 } - -#define AR5K_RF5112A_FIXED_BIAS_A { 1, 278, 0 } -#define AR5K_RF5112A_FIXED_BIAS_B { 1, 277, 0 } - -#define AR5K_RF5112A_XPD_SEL { 1, 302, 0 } -#define AR5K_RF5112A_PDGAINLO { 2, 270, 0 } -#define AR5K_RF5112A_PDGAINHI { 2, 257, 0 } - -/* Access to PWD registers */ -#define AR5K_RF5112A_PWD(_n) { 1, (306 - _n), 3 } - -/* Voltage regulators */ -#define AR5K_RF5112A_HIGH_VC_CP { 2, 90, 2 } -#define AR5K_RF5112A_MID_VC_CP { 2, 92, 2 } -#define AR5K_RF5112A_LOW_VC_CP { 2, 94, 2 } -#define AR5K_RF5112A_PUSH_UP { 1, 254, 2 } - -/* Power consumption */ -#define AR5K_RF5112A_PAD2GND { 1, 281, 1 } -#define AR5K_RF5112A_XB2_LVL { 2, 1, 3 } -#define AR5K_RF5112A_XB5_LVL { 2, 3, 3 } - -static const struct ath5k_rf_reg rf_regs_5112a[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF5112A_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF5112A_DB_2GHZ}, - {6, AR5K_RF_OB_5GHZ, AR5K_RF5112A_OB_5GHZ}, - {6, AR5K_RF_DB_5GHZ, AR5K_RF5112A_DB_5GHZ}, - {6, AR5K_RF_FIXED_BIAS_A, AR5K_RF5112A_FIXED_BIAS_A}, - {6, AR5K_RF_FIXED_BIAS_B, AR5K_RF5112A_FIXED_BIAS_B}, - {6, AR5K_RF_XPD_SEL, AR5K_RF5112A_XPD_SEL}, - {6, AR5K_RF_PD_GAIN_LO, AR5K_RF5112A_PDGAINLO}, - {6, AR5K_RF_PD_GAIN_HI, AR5K_RF5112A_PDGAINHI}, - {6, AR5K_RF_PWD_130, AR5K_RF5112A_PWD(130)}, - {6, AR5K_RF_PWD_131, AR5K_RF5112A_PWD(131)}, - {6, AR5K_RF_PWD_132, AR5K_RF5112A_PWD(132)}, - {6, AR5K_RF_PWD_136, AR5K_RF5112A_PWD(136)}, - {6, AR5K_RF_PWD_137, AR5K_RF5112A_PWD(137)}, - {6, AR5K_RF_PWD_138, AR5K_RF5112A_PWD(138)}, - {6, AR5K_RF_PWD_166, AR5K_RF5112A_PWD(166)}, - {6, AR5K_RF_PWD_167, AR5K_RF5112A_PWD(167)}, - {6, AR5K_RF_HIGH_VC_CP, AR5K_RF5112A_HIGH_VC_CP}, - {6, AR5K_RF_MID_VC_CP, AR5K_RF5112A_MID_VC_CP}, - {6, AR5K_RF_LOW_VC_CP, AR5K_RF5112A_LOW_VC_CP}, - {6, AR5K_RF_PUSH_UP, AR5K_RF5112A_PUSH_UP}, - {6, AR5K_RF_PAD2GND, AR5K_RF5112A_PAD2GND}, - {6, AR5K_RF_XB2_LVL, AR5K_RF5112A_XB2_LVL}, - {6, AR5K_RF_XB5_LVL, AR5K_RF5112A_XB5_LVL}, - {7, AR5K_RF_GAIN_I, AR5K_RF5112X_GAIN_I}, - {7, AR5K_RF_MIXVGA_OVR, AR5K_RF5112X_MIXVGA_OVR}, - {7, AR5K_RF_MIXGAIN_OVR, AR5K_RF5112X_MIXGAIN_OVR}, - {7, AR5K_RF_MIXGAIN_STEP, AR5K_RF5112X_MIXGAIN_STEP}, - {7, AR5K_RF_PD_DELAY_A, AR5K_RF5112X_PD_DELAY_A}, - {7, AR5K_RF_PD_DELAY_B, AR5K_RF5112X_PD_DELAY_B}, - {7, AR5K_RF_PD_DELAY_XR, AR5K_RF5112X_PD_DELAY_XR}, - {7, AR5K_RF_PD_PERIOD_A, AR5K_RF5112X_PD_PERIOD_A}, - {7, AR5K_RF_PD_PERIOD_B, AR5K_RF5112X_PD_PERIOD_B}, - {7, AR5K_RF_PD_PERIOD_XR, AR5K_RF5112X_PD_PERIOD_XR}, -}; - -/* Default mode specific settings */ -static const struct ath5k_ini_rfbuffer rfb_5112a[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, - { 3, 0x98dc, - { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, - { 6, 0x989c, - { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } }, - { 6, 0x989c, - { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, - { 6, 0x989c, - { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } }, - { 6, 0x989c, - { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } }, - { 6, 0x989c, - { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } }, - { 6, 0x989c, - { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } }, - { 6, 0x989c, - { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } }, - { 6, 0x989c, - { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } }, - { 6, 0x989c, - { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } }, - { 6, 0x989c, - { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, - { 6, 0x989c, - { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } }, - { 6, 0x989c, - { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, - { 6, 0x989c, - { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } }, - { 6, 0x989c, - { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, - { 6, 0x989c, - { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } }, - { 6, 0x989c, - { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } }, - { 6, 0x989c, - { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } }, - { 6, 0x989c, - { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, - { 6, 0x989c, - { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, - { 6, 0x989c, - { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } }, - { 6, 0x989c, - { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } }, - { 6, 0x989c, - { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, - { 6, 0x989c, - { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } }, - { 6, 0x989c, - { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } }, - { 6, 0x989c, - { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } }, - { 6, 0x989c, - { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } }, - { 6, 0x989c, - { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } }, - { 6, 0x989c, - { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } }, - { 6, 0x989c, - { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } }, - { 6, 0x989c, - { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } }, - { 6, 0x989c, - { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } }, - { 6, 0x98d8, - { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } }, - { 7, 0x989c, - { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, - { 7, 0x989c, - { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, - { 7, 0x989c, - { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } }, - { 7, 0x989c, - { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, - { 7, 0x989c, - { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } }, - { 7, 0x989c, - { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, - { 7, 0x989c, - { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, - { 7, 0x989c, - { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } }, - { 7, 0x989c, - { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } }, - { 7, 0x989c, - { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, - { 7, 0x989c, - { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, - { 7, 0x989c, - { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, - { 7, 0x98c4, - { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, -}; - - - -/******************\ -* RF2413 (Griffin) * -\******************/ - -/* BANK 6 len pos col */ -#define AR5K_RF2413_OB_2GHZ { 3, 168, 0 } -#define AR5K_RF2413_DB_2GHZ { 3, 165, 0 } - -static const struct ath5k_rf_reg rf_regs_2413[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF2413_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF2413_DB_2GHZ}, -}; - -/* Default mode specific settings - * XXX: a/aTurbo ??? - */ -static const struct ath5k_ini_rfbuffer rfb_2413[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } }, - { 3, 0x98dc, - { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, - { 6, 0x989c, - { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } }, - { 6, 0x989c, - { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } }, - { 6, 0x989c, - { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } }, - { 6, 0x989c, - { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } }, - { 6, 0x989c, - { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } }, - { 6, 0x989c, - { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } }, - { 6, 0x989c, - { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } }, - { 6, 0x989c, - { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } }, - { 6, 0x989c, - { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } }, - { 6, 0x989c, - { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } }, - { 6, 0x989c, - { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } }, - { 6, 0x989c, - { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } }, - { 6, 0x989c, - { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } }, - { 6, 0x98d8, - { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } }, - { 7, 0x989c, - { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, - { 7, 0x989c, - { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, - { 7, 0x98cc, - { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, -}; - - - -/***************************\ -* RF2315/RF2316 (Cobra SoC) * -\***************************/ - -/* BANK 6 len pos col */ -#define AR5K_RF2316_OB_2GHZ { 3, 178, 0 } -#define AR5K_RF2316_DB_2GHZ { 3, 175, 0 } - -static const struct ath5k_rf_reg rf_regs_2316[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF2316_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF2316_DB_2GHZ}, -}; - -/* Default mode specific settings */ -static const struct ath5k_ini_rfbuffer rfb_2316[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } }, - { 3, 0x98dc, - { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } }, - { 6, 0x989c, - { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } }, - { 6, 0x989c, - { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } }, - { 6, 0x989c, - { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } }, - { 6, 0x989c, - { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } }, - { 6, 0x989c, - { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } }, - { 6, 0x989c, - { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } }, - { 6, 0x989c, - { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } }, - { 6, 0x989c, - { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } }, - { 6, 0x989c, - { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } }, - { 6, 0x989c, - { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } }, - { 6, 0x989c, - { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } }, - { 6, 0x989c, - { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } }, - { 6, 0x989c, - { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } }, - { 6, 0x989c, - { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, - { 6, 0x989c, - { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, - { 6, 0x989c, - { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } }, - { 6, 0x989c, - { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } }, - { 6, 0x98c0, - { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } }, - { 7, 0x989c, - { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, - { 7, 0x989c, - { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, - { 7, 0x98cc, - { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, -}; - - - -/******************************\ -* RF5413/RF5424 (Eagle/Condor) * -\******************************/ - -/* BANK 6 len pos col */ -#define AR5K_RF5413_OB_2GHZ { 3, 241, 0 } -#define AR5K_RF5413_DB_2GHZ { 3, 238, 0 } - -#define AR5K_RF5413_OB_5GHZ { 3, 247, 0 } -#define AR5K_RF5413_DB_5GHZ { 3, 244, 0 } - -#define AR5K_RF5413_PWD_ICLOBUF2G { 3, 131, 3 } -#define AR5K_RF5413_DERBY_CHAN_SEL_MODE { 1, 291, 2 } - -static const struct ath5k_rf_reg rf_regs_5413[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF5413_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF5413_DB_2GHZ}, - {6, AR5K_RF_OB_5GHZ, AR5K_RF5413_OB_5GHZ}, - {6, AR5K_RF_DB_5GHZ, AR5K_RF5413_DB_5GHZ}, - {6, AR5K_RF_PWD_ICLOBUF_2G, AR5K_RF5413_PWD_ICLOBUF2G}, - {6, AR5K_RF_DERBY_CHAN_SEL_MODE, AR5K_RF5413_DERBY_CHAN_SEL_MODE}, -}; - -/* Default mode specific settings */ -static const struct ath5k_ini_rfbuffer rfb_5413[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, - { 3, 0x98dc, - { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } }, - { 6, 0x989c, - { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } }, - { 6, 0x989c, - { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } }, - { 6, 0x989c, - { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } }, - { 6, 0x989c, - { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, - { 6, 0x989c, - { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, - { 6, 0x989c, - { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } }, - { 6, 0x989c, - { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, - { 6, 0x989c, - { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, - { 6, 0x989c, - { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, - { 6, 0x989c, - { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, - { 6, 0x989c, - { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } }, - { 6, 0x989c, - { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } }, - { 6, 0x989c, - { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } }, - { 6, 0x989c, - { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } }, - { 6, 0x989c, - { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } }, - { 6, 0x989c, - { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } }, - { 6, 0x989c, - { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } }, - { 6, 0x989c, - { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } }, - { 6, 0x989c, - { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, - { 6, 0x989c, - { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } }, - { 6, 0x989c, - { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } }, - { 6, 0x989c, - { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } }, - { 6, 0x989c, - { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } }, - { 6, 0x989c, - { 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 } }, - { 6, 0x989c, - { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } }, - { 6, 0x989c, - { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 } }, - { 6, 0x98c8, - { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } }, - { 7, 0x989c, - { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, - { 7, 0x989c, - { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, - { 7, 0x98cc, - { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, -}; - - - -/***************************\ -* RF2425/RF2417 (Swan/Nala) * -* AR2317 (Spider SoC) * -\***************************/ - -/* BANK 6 len pos col */ -#define AR5K_RF2425_OB_2GHZ { 3, 193, 0 } -#define AR5K_RF2425_DB_2GHZ { 3, 190, 0 } - -static const struct ath5k_rf_reg rf_regs_2425[] = { - {6, AR5K_RF_OB_2GHZ, AR5K_RF2425_OB_2GHZ}, - {6, AR5K_RF_DB_2GHZ, AR5K_RF2425_DB_2GHZ}, -}; - -/* Default mode specific settings - * XXX: a/aTurbo ? - */ -static const struct ath5k_ini_rfbuffer rfb_2425[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } }, - { 3, 0x98dc, - { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, - { 6, 0x989c, - { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } }, - { 6, 0x989c, - { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } }, - { 6, 0x989c, - { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, - { 6, 0x989c, - { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } }, - { 6, 0x989c, - { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } }, - { 6, 0x989c, - { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } }, - { 6, 0x989c, - { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } }, - { 6, 0x989c, - { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } }, - { 6, 0x989c, - { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } }, - { 6, 0x989c, - { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } }, - { 6, 0x989c, - { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } }, - { 6, 0x989c, - { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } }, - { 6, 0x98c4, - { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, - { 7, 0x989c, - { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, - { 7, 0x989c, - { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, - { 7, 0x98cc, - { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, -}; - -/* - * TODO: Handle the few differences with swan during - * bank modification and get rid of this - */ -static const struct ath5k_ini_rfbuffer rfb_2317[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } }, - { 3, 0x98dc, - { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, - { 6, 0x989c, - { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } }, - { 6, 0x989c, - { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } }, - { 6, 0x989c, - { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, - { 6, 0x989c, - { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } }, - { 6, 0x989c, - { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } }, - { 6, 0x989c, - { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } }, - { 6, 0x989c, - { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } }, - { 6, 0x989c, - { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } }, - { 6, 0x989c, - { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } }, - { 6, 0x989c, - { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } }, - { 6, 0x989c, - { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } }, - { 6, 0x989c, - { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } }, - { 6, 0x98c4, - { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, - { 7, 0x989c, - { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, - { 7, 0x989c, - { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, - { 7, 0x98cc, - { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, -}; - -/* - * TODO: Handle the few differences with swan during - * bank modification and get rid of this - * XXX: a/aTurbo ? - */ -static const struct ath5k_ini_rfbuffer rfb_2417[] = { - { 1, 0x98d4, - /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ - { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, - { 2, 0x98d0, - { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } }, - { 3, 0x98dc, - { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, - { 6, 0x989c, - { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } }, - { 6, 0x989c, - { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } }, - { 6, 0x989c, - { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, - { 6, 0x989c, - { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } }, - { 6, 0x989c, - { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } }, - { 6, 0x989c, - { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } }, - { 6, 0x989c, - { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } }, - { 6, 0x989c, - { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } }, - { 6, 0x989c, - { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } }, - { 6, 0x989c, - { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } }, - { 6, 0x989c, - { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, - { 6, 0x989c, - { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } }, - { 6, 0x989c, - { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } }, - { 6, 0x98c4, - { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, - { 7, 0x989c, - { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, - { 7, 0x989c, - { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, - { 7, 0x98cc, - { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, -}; diff --git a/drivers/net/wireless/ath5k/rfgain.h b/drivers/net/wireless/ath5k/rfgain.h deleted file mode 100644 index 1354d8c..0000000 --- a/drivers/net/wireless/ath5k/rfgain.h +++ /dev/null @@ -1,516 +0,0 @@ -/* - * RF Gain optimization - * - * Copyright (c) 2004-2009 Reyk Floeter - * Copyright (c) 2006-2009 Nick Kossifidis - * - * 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. - * - */ - -/* - * Mode-specific RF Gain table (64bytes) for RF5111/5112 - * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial - * RF Gain values are included in AR5K_AR5210_INI) - */ -struct ath5k_ini_rfgain { - u16 rfg_register; /* RF Gain register address */ - u32 rfg_value[2]; /* [freq (see below)] */ -}; - -/* Initial RF Gain settings for RF5111 */ -static const struct ath5k_ini_rfgain rfgain_5111[] = { - /* 5Ghz 2Ghz */ - { AR5K_RF_GAIN(0), { 0x000001a9, 0x00000000 } }, - { AR5K_RF_GAIN(1), { 0x000001e9, 0x00000040 } }, - { AR5K_RF_GAIN(2), { 0x00000029, 0x00000080 } }, - { AR5K_RF_GAIN(3), { 0x00000069, 0x00000150 } }, - { AR5K_RF_GAIN(4), { 0x00000199, 0x00000190 } }, - { AR5K_RF_GAIN(5), { 0x000001d9, 0x000001d0 } }, - { AR5K_RF_GAIN(6), { 0x00000019, 0x00000010 } }, - { AR5K_RF_GAIN(7), { 0x00000059, 0x00000044 } }, - { AR5K_RF_GAIN(8), { 0x00000099, 0x00000084 } }, - { AR5K_RF_GAIN(9), { 0x000001a5, 0x00000148 } }, - { AR5K_RF_GAIN(10), { 0x000001e5, 0x00000188 } }, - { AR5K_RF_GAIN(11), { 0x00000025, 0x000001c8 } }, - { AR5K_RF_GAIN(12), { 0x000001c8, 0x00000014 } }, - { AR5K_RF_GAIN(13), { 0x00000008, 0x00000042 } }, - { AR5K_RF_GAIN(14), { 0x00000048, 0x00000082 } }, - { AR5K_RF_GAIN(15), { 0x00000088, 0x00000178 } }, - { AR5K_RF_GAIN(16), { 0x00000198, 0x000001b8 } }, - { AR5K_RF_GAIN(17), { 0x000001d8, 0x000001f8 } }, - { AR5K_RF_GAIN(18), { 0x00000018, 0x00000012 } }, - { AR5K_RF_GAIN(19), { 0x00000058, 0x00000052 } }, - { AR5K_RF_GAIN(20), { 0x00000098, 0x00000092 } }, - { AR5K_RF_GAIN(21), { 0x000001a4, 0x0000017c } }, - { AR5K_RF_GAIN(22), { 0x000001e4, 0x000001bc } }, - { AR5K_RF_GAIN(23), { 0x00000024, 0x000001fc } }, - { AR5K_RF_GAIN(24), { 0x00000064, 0x0000000a } }, - { AR5K_RF_GAIN(25), { 0x000000a4, 0x0000004a } }, - { AR5K_RF_GAIN(26), { 0x000000e4, 0x0000008a } }, - { AR5K_RF_GAIN(27), { 0x0000010a, 0x0000015a } }, - { AR5K_RF_GAIN(28), { 0x0000014a, 0x0000019a } }, - { AR5K_RF_GAIN(29), { 0x0000018a, 0x000001da } }, - { AR5K_RF_GAIN(30), { 0x000001ca, 0x0000000e } }, - { AR5K_RF_GAIN(31), { 0x0000000a, 0x0000004e } }, - { AR5K_RF_GAIN(32), { 0x0000004a, 0x0000008e } }, - { AR5K_RF_GAIN(33), { 0x0000008a, 0x0000015e } }, - { AR5K_RF_GAIN(34), { 0x000001ba, 0x0000019e } }, - { AR5K_RF_GAIN(35), { 0x000001fa, 0x000001de } }, - { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000009 } }, - { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000049 } }, - { AR5K_RF_GAIN(38), { 0x00000186, 0x00000089 } }, - { AR5K_RF_GAIN(39), { 0x000001c6, 0x00000179 } }, - { AR5K_RF_GAIN(40), { 0x00000006, 0x000001b9 } }, - { AR5K_RF_GAIN(41), { 0x00000046, 0x000001f9 } }, - { AR5K_RF_GAIN(42), { 0x00000086, 0x00000039 } }, - { AR5K_RF_GAIN(43), { 0x000000c6, 0x00000079 } }, - { AR5K_RF_GAIN(44), { 0x000000c6, 0x000000b9 } }, - { AR5K_RF_GAIN(45), { 0x000000c6, 0x000001bd } }, - { AR5K_RF_GAIN(46), { 0x000000c6, 0x000001fd } }, - { AR5K_RF_GAIN(47), { 0x000000c6, 0x0000003d } }, - { AR5K_RF_GAIN(48), { 0x000000c6, 0x0000007d } }, - { AR5K_RF_GAIN(49), { 0x000000c6, 0x000000bd } }, - { AR5K_RF_GAIN(50), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(51), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(52), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(53), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(54), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(55), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(56), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(57), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(58), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(59), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(60), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(61), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(62), { 0x000000c6, 0x000000fd } }, - { AR5K_RF_GAIN(63), { 0x000000c6, 0x000000fd } }, -}; - -/* Initial RF Gain settings for RF5112 */ -static const struct ath5k_ini_rfgain rfgain_5112[] = { - /* 5Ghz 2Ghz */ - { AR5K_RF_GAIN(0), { 0x00000007, 0x00000007 } }, - { AR5K_RF_GAIN(1), { 0x00000047, 0x00000047 } }, - { AR5K_RF_GAIN(2), { 0x00000087, 0x00000087 } }, - { AR5K_RF_GAIN(3), { 0x000001a0, 0x000001a0 } }, - { AR5K_RF_GAIN(4), { 0x000001e0, 0x000001e0 } }, - { AR5K_RF_GAIN(5), { 0x00000020, 0x00000020 } }, - { AR5K_RF_GAIN(6), { 0x00000060, 0x00000060 } }, - { AR5K_RF_GAIN(7), { 0x000001a1, 0x000001a1 } }, - { AR5K_RF_GAIN(8), { 0x000001e1, 0x000001e1 } }, - { AR5K_RF_GAIN(9), { 0x00000021, 0x00000021 } }, - { AR5K_RF_GAIN(10), { 0x00000061, 0x00000061 } }, - { AR5K_RF_GAIN(11), { 0x00000162, 0x00000162 } }, - { AR5K_RF_GAIN(12), { 0x000001a2, 0x000001a2 } }, - { AR5K_RF_GAIN(13), { 0x000001e2, 0x000001e2 } }, - { AR5K_RF_GAIN(14), { 0x00000022, 0x00000022 } }, - { AR5K_RF_GAIN(15), { 0x00000062, 0x00000062 } }, - { AR5K_RF_GAIN(16), { 0x00000163, 0x00000163 } }, - { AR5K_RF_GAIN(17), { 0x000001a3, 0x000001a3 } }, - { AR5K_RF_GAIN(18), { 0x000001e3, 0x000001e3 } }, - { AR5K_RF_GAIN(19), { 0x00000023, 0x00000023 } }, - { AR5K_RF_GAIN(20), { 0x00000063, 0x00000063 } }, - { AR5K_RF_GAIN(21), { 0x00000184, 0x00000184 } }, - { AR5K_RF_GAIN(22), { 0x000001c4, 0x000001c4 } }, - { AR5K_RF_GAIN(23), { 0x00000004, 0x00000004 } }, - { AR5K_RF_GAIN(24), { 0x000001ea, 0x0000000b } }, - { AR5K_RF_GAIN(25), { 0x0000002a, 0x0000004b } }, - { AR5K_RF_GAIN(26), { 0x0000006a, 0x0000008b } }, - { AR5K_RF_GAIN(27), { 0x000000aa, 0x000001ac } }, - { AR5K_RF_GAIN(28), { 0x000001ab, 0x000001ec } }, - { AR5K_RF_GAIN(29), { 0x000001eb, 0x0000002c } }, - { AR5K_RF_GAIN(30), { 0x0000002b, 0x00000012 } }, - { AR5K_RF_GAIN(31), { 0x0000006b, 0x00000052 } }, - { AR5K_RF_GAIN(32), { 0x000000ab, 0x00000092 } }, - { AR5K_RF_GAIN(33), { 0x000001ac, 0x00000193 } }, - { AR5K_RF_GAIN(34), { 0x000001ec, 0x000001d3 } }, - { AR5K_RF_GAIN(35), { 0x0000002c, 0x00000013 } }, - { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000053 } }, - { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000093 } }, - { AR5K_RF_GAIN(38), { 0x000000ba, 0x00000194 } }, - { AR5K_RF_GAIN(39), { 0x000001bb, 0x000001d4 } }, - { AR5K_RF_GAIN(40), { 0x000001fb, 0x00000014 } }, - { AR5K_RF_GAIN(41), { 0x0000003b, 0x0000003a } }, - { AR5K_RF_GAIN(42), { 0x0000007b, 0x0000007a } }, - { AR5K_RF_GAIN(43), { 0x000000bb, 0x000000ba } }, - { AR5K_RF_GAIN(44), { 0x000001bc, 0x000001bb } }, - { AR5K_RF_GAIN(45), { 0x000001fc, 0x000001fb } }, - { AR5K_RF_GAIN(46), { 0x0000003c, 0x0000003b } }, - { AR5K_RF_GAIN(47), { 0x0000007c, 0x0000007b } }, - { AR5K_RF_GAIN(48), { 0x000000bc, 0x000000bb } }, - { AR5K_RF_GAIN(49), { 0x000000fc, 0x000001bc } }, - { AR5K_RF_GAIN(50), { 0x000000fc, 0x000001fc } }, - { AR5K_RF_GAIN(51), { 0x000000fc, 0x0000003c } }, - { AR5K_RF_GAIN(52), { 0x000000fc, 0x0000007c } }, - { AR5K_RF_GAIN(53), { 0x000000fc, 0x000000bc } }, - { AR5K_RF_GAIN(54), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(55), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(56), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(57), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(58), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(59), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(60), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(61), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(62), { 0x000000fc, 0x000000fc } }, - { AR5K_RF_GAIN(63), { 0x000000fc, 0x000000fc } }, -}; - -/* Initial RF Gain settings for RF2413 */ -static const struct ath5k_ini_rfgain rfgain_2413[] = { - { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, - { AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } }, - { AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } }, - { AR5K_RF_GAIN(3), { 0x00000000, 0x00000181 } }, - { AR5K_RF_GAIN(4), { 0x00000000, 0x000001c1 } }, - { AR5K_RF_GAIN(5), { 0x00000000, 0x00000001 } }, - { AR5K_RF_GAIN(6), { 0x00000000, 0x00000041 } }, - { AR5K_RF_GAIN(7), { 0x00000000, 0x00000081 } }, - { AR5K_RF_GAIN(8), { 0x00000000, 0x00000168 } }, - { AR5K_RF_GAIN(9), { 0x00000000, 0x000001a8 } }, - { AR5K_RF_GAIN(10), { 0x00000000, 0x000001e8 } }, - { AR5K_RF_GAIN(11), { 0x00000000, 0x00000028 } }, - { AR5K_RF_GAIN(12), { 0x00000000, 0x00000068 } }, - { AR5K_RF_GAIN(13), { 0x00000000, 0x00000189 } }, - { AR5K_RF_GAIN(14), { 0x00000000, 0x000001c9 } }, - { AR5K_RF_GAIN(15), { 0x00000000, 0x00000009 } }, - { AR5K_RF_GAIN(16), { 0x00000000, 0x00000049 } }, - { AR5K_RF_GAIN(17), { 0x00000000, 0x00000089 } }, - { AR5K_RF_GAIN(18), { 0x00000000, 0x00000190 } }, - { AR5K_RF_GAIN(19), { 0x00000000, 0x000001d0 } }, - { AR5K_RF_GAIN(20), { 0x00000000, 0x00000010 } }, - { AR5K_RF_GAIN(21), { 0x00000000, 0x00000050 } }, - { AR5K_RF_GAIN(22), { 0x00000000, 0x00000090 } }, - { AR5K_RF_GAIN(23), { 0x00000000, 0x00000191 } }, - { AR5K_RF_GAIN(24), { 0x00000000, 0x000001d1 } }, - { AR5K_RF_GAIN(25), { 0x00000000, 0x00000011 } }, - { AR5K_RF_GAIN(26), { 0x00000000, 0x00000051 } }, - { AR5K_RF_GAIN(27), { 0x00000000, 0x00000091 } }, - { AR5K_RF_GAIN(28), { 0x00000000, 0x00000178 } }, - { AR5K_RF_GAIN(29), { 0x00000000, 0x000001b8 } }, - { AR5K_RF_GAIN(30), { 0x00000000, 0x000001f8 } }, - { AR5K_RF_GAIN(31), { 0x00000000, 0x00000038 } }, - { AR5K_RF_GAIN(32), { 0x00000000, 0x00000078 } }, - { AR5K_RF_GAIN(33), { 0x00000000, 0x00000199 } }, - { AR5K_RF_GAIN(34), { 0x00000000, 0x000001d9 } }, - { AR5K_RF_GAIN(35), { 0x00000000, 0x00000019 } }, - { AR5K_RF_GAIN(36), { 0x00000000, 0x00000059 } }, - { AR5K_RF_GAIN(37), { 0x00000000, 0x00000099 } }, - { AR5K_RF_GAIN(38), { 0x00000000, 0x000000d9 } }, - { AR5K_RF_GAIN(39), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(40), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(41), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(42), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(43), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(44), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(45), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(46), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(47), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(48), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(49), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(50), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(51), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(52), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(53), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(54), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(55), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(56), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(57), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(58), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(59), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(60), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(61), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(62), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } }, -}; - -/* Initial RF Gain settings for AR2316 */ -static const struct ath5k_ini_rfgain rfgain_2316[] = { - { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, - { AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } }, - { AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } }, - { AR5K_RF_GAIN(3), { 0x00000000, 0x000000c0 } }, - { AR5K_RF_GAIN(4), { 0x00000000, 0x000000e0 } }, - { AR5K_RF_GAIN(5), { 0x00000000, 0x000000e0 } }, - { AR5K_RF_GAIN(6), { 0x00000000, 0x00000128 } }, - { AR5K_RF_GAIN(7), { 0x00000000, 0x00000128 } }, - { AR5K_RF_GAIN(8), { 0x00000000, 0x00000128 } }, - { AR5K_RF_GAIN(9), { 0x00000000, 0x00000168 } }, - { AR5K_RF_GAIN(10), { 0x00000000, 0x000001a8 } }, - { AR5K_RF_GAIN(11), { 0x00000000, 0x000001e8 } }, - { AR5K_RF_GAIN(12), { 0x00000000, 0x00000028 } }, - { AR5K_RF_GAIN(13), { 0x00000000, 0x00000068 } }, - { AR5K_RF_GAIN(14), { 0x00000000, 0x000000a8 } }, - { AR5K_RF_GAIN(15), { 0x00000000, 0x000000e8 } }, - { AR5K_RF_GAIN(16), { 0x00000000, 0x000000e8 } }, - { AR5K_RF_GAIN(17), { 0x00000000, 0x00000130 } }, - { AR5K_RF_GAIN(18), { 0x00000000, 0x00000130 } }, - { AR5K_RF_GAIN(19), { 0x00000000, 0x00000170 } }, - { AR5K_RF_GAIN(20), { 0x00000000, 0x000001b0 } }, - { AR5K_RF_GAIN(21), { 0x00000000, 0x000001f0 } }, - { AR5K_RF_GAIN(22), { 0x00000000, 0x00000030 } }, - { AR5K_RF_GAIN(23), { 0x00000000, 0x00000070 } }, - { AR5K_RF_GAIN(24), { 0x00000000, 0x000000b0 } }, - { AR5K_RF_GAIN(25), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(26), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(27), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(28), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(29), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(30), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(31), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(32), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(33), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(34), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(35), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(36), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(37), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(38), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(39), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(40), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(41), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(42), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(43), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(44), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(45), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(46), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(47), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(48), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(49), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(50), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(51), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(52), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(53), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(54), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(55), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(56), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(57), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(58), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(59), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(60), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(61), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(62), { 0x00000000, 0x000000f0 } }, - { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f0 } }, -}; - - -/* Initial RF Gain settings for RF5413 */ -static const struct ath5k_ini_rfgain rfgain_5413[] = { - /* 5Ghz 2Ghz */ - { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, - { AR5K_RF_GAIN(1), { 0x00000040, 0x00000040 } }, - { AR5K_RF_GAIN(2), { 0x00000080, 0x00000080 } }, - { AR5K_RF_GAIN(3), { 0x000001a1, 0x00000161 } }, - { AR5K_RF_GAIN(4), { 0x000001e1, 0x000001a1 } }, - { AR5K_RF_GAIN(5), { 0x00000021, 0x000001e1 } }, - { AR5K_RF_GAIN(6), { 0x00000061, 0x00000021 } }, - { AR5K_RF_GAIN(7), { 0x00000188, 0x00000061 } }, - { AR5K_RF_GAIN(8), { 0x000001c8, 0x00000188 } }, - { AR5K_RF_GAIN(9), { 0x00000008, 0x000001c8 } }, - { AR5K_RF_GAIN(10), { 0x00000048, 0x00000008 } }, - { AR5K_RF_GAIN(11), { 0x00000088, 0x00000048 } }, - { AR5K_RF_GAIN(12), { 0x000001a9, 0x00000088 } }, - { AR5K_RF_GAIN(13), { 0x000001e9, 0x00000169 } }, - { AR5K_RF_GAIN(14), { 0x00000029, 0x000001a9 } }, - { AR5K_RF_GAIN(15), { 0x00000069, 0x000001e9 } }, - { AR5K_RF_GAIN(16), { 0x000001d0, 0x00000029 } }, - { AR5K_RF_GAIN(17), { 0x00000010, 0x00000069 } }, - { AR5K_RF_GAIN(18), { 0x00000050, 0x00000190 } }, - { AR5K_RF_GAIN(19), { 0x00000090, 0x000001d0 } }, - { AR5K_RF_GAIN(20), { 0x000001b1, 0x00000010 } }, - { AR5K_RF_GAIN(21), { 0x000001f1, 0x00000050 } }, - { AR5K_RF_GAIN(22), { 0x00000031, 0x00000090 } }, - { AR5K_RF_GAIN(23), { 0x00000071, 0x00000171 } }, - { AR5K_RF_GAIN(24), { 0x000001b8, 0x000001b1 } }, - { AR5K_RF_GAIN(25), { 0x000001f8, 0x000001f1 } }, - { AR5K_RF_GAIN(26), { 0x00000038, 0x00000031 } }, - { AR5K_RF_GAIN(27), { 0x00000078, 0x00000071 } }, - { AR5K_RF_GAIN(28), { 0x00000199, 0x00000198 } }, - { AR5K_RF_GAIN(29), { 0x000001d9, 0x000001d8 } }, - { AR5K_RF_GAIN(30), { 0x00000019, 0x00000018 } }, - { AR5K_RF_GAIN(31), { 0x00000059, 0x00000058 } }, - { AR5K_RF_GAIN(32), { 0x00000099, 0x00000098 } }, - { AR5K_RF_GAIN(33), { 0x000000d9, 0x00000179 } }, - { AR5K_RF_GAIN(34), { 0x000000f9, 0x000001b9 } }, - { AR5K_RF_GAIN(35), { 0x000000f9, 0x000001f9 } }, - { AR5K_RF_GAIN(36), { 0x000000f9, 0x00000039 } }, - { AR5K_RF_GAIN(37), { 0x000000f9, 0x00000079 } }, - { AR5K_RF_GAIN(38), { 0x000000f9, 0x000000b9 } }, - { AR5K_RF_GAIN(39), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(40), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(41), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(42), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(43), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(44), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(45), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(46), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(47), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(48), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(49), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(50), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(51), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(52), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(53), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(54), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(55), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(56), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(57), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(58), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(59), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(60), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(61), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(62), { 0x000000f9, 0x000000f9 } }, - { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } }, -}; - - -/* Initial RF Gain settings for RF2425 */ -static const struct ath5k_ini_rfgain rfgain_2425[] = { - { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, - { AR5K_RF_GAIN(1), { 0x00000000, 0x00000040 } }, - { AR5K_RF_GAIN(2), { 0x00000000, 0x00000080 } }, - { AR5K_RF_GAIN(3), { 0x00000000, 0x00000181 } }, - { AR5K_RF_GAIN(4), { 0x00000000, 0x000001c1 } }, - { AR5K_RF_GAIN(5), { 0x00000000, 0x00000001 } }, - { AR5K_RF_GAIN(6), { 0x00000000, 0x00000041 } }, - { AR5K_RF_GAIN(7), { 0x00000000, 0x00000081 } }, - { AR5K_RF_GAIN(8), { 0x00000000, 0x00000188 } }, - { AR5K_RF_GAIN(9), { 0x00000000, 0x000001c8 } }, - { AR5K_RF_GAIN(10), { 0x00000000, 0x00000008 } }, - { AR5K_RF_GAIN(11), { 0x00000000, 0x00000048 } }, - { AR5K_RF_GAIN(12), { 0x00000000, 0x00000088 } }, - { AR5K_RF_GAIN(13), { 0x00000000, 0x00000189 } }, - { AR5K_RF_GAIN(14), { 0x00000000, 0x000001c9 } }, - { AR5K_RF_GAIN(15), { 0x00000000, 0x00000009 } }, - { AR5K_RF_GAIN(16), { 0x00000000, 0x00000049 } }, - { AR5K_RF_GAIN(17), { 0x00000000, 0x00000089 } }, - { AR5K_RF_GAIN(18), { 0x00000000, 0x000001b0 } }, - { AR5K_RF_GAIN(19), { 0x00000000, 0x000001f0 } }, - { AR5K_RF_GAIN(20), { 0x00000000, 0x00000030 } }, - { AR5K_RF_GAIN(21), { 0x00000000, 0x00000070 } }, - { AR5K_RF_GAIN(22), { 0x00000000, 0x00000171 } }, - { AR5K_RF_GAIN(23), { 0x00000000, 0x000001b1 } }, - { AR5K_RF_GAIN(24), { 0x00000000, 0x000001f1 } }, - { AR5K_RF_GAIN(25), { 0x00000000, 0x00000031 } }, - { AR5K_RF_GAIN(26), { 0x00000000, 0x00000071 } }, - { AR5K_RF_GAIN(27), { 0x00000000, 0x000001b8 } }, - { AR5K_RF_GAIN(28), { 0x00000000, 0x000001f8 } }, - { AR5K_RF_GAIN(29), { 0x00000000, 0x00000038 } }, - { AR5K_RF_GAIN(30), { 0x00000000, 0x00000078 } }, - { AR5K_RF_GAIN(31), { 0x00000000, 0x000000b8 } }, - { AR5K_RF_GAIN(32), { 0x00000000, 0x000001b9 } }, - { AR5K_RF_GAIN(33), { 0x00000000, 0x000001f9 } }, - { AR5K_RF_GAIN(34), { 0x00000000, 0x00000039 } }, - { AR5K_RF_GAIN(35), { 0x00000000, 0x00000079 } }, - { AR5K_RF_GAIN(36), { 0x00000000, 0x000000b9 } }, - { AR5K_RF_GAIN(37), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(38), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(39), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(40), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(41), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(42), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(43), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(44), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(45), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(46), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(47), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(48), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(49), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(50), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(51), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(52), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(53), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(54), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(55), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(56), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(57), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(58), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(59), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(60), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(61), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(62), { 0x00000000, 0x000000f9 } }, - { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } }, -}; - -#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 - -/* Check if our current measurement is inside our - * current variable attenuation window */ -#define AR5K_GAIN_CHECK_ADJUST(_g) \ - ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) - -struct ath5k_gain_opt_step { - s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; - s8 gos_gain; -}; - -struct ath5k_gain_opt { - u8 go_default; - u8 go_steps_count; - const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; -}; - -/* - * Parameters on gos_param: - * 1) Tx clip PHY register - * 2) PWD 90 RF register - * 3) PWD 84 RF register - * 4) RFGainSel RF register - */ -static const struct ath5k_gain_opt rfgain_opt_5111 = { - 4, - 9, - { - { { 4, 1, 1, 1 }, 6 }, - { { 4, 0, 1, 1 }, 4 }, - { { 3, 1, 1, 1 }, 3 }, - { { 4, 0, 0, 1 }, 1 }, - { { 4, 1, 1, 0 }, 0 }, - { { 4, 0, 1, 0 }, -2 }, - { { 3, 1, 1, 0 }, -3 }, - { { 4, 0, 0, 0 }, -4 }, - { { 2, 1, 1, 0 }, -6 } - } -}; - -/* - * Parameters on gos_param: - * 1) Mixgain ovr RF register - * 2) PWD 138 RF register - * 3) PWD 137 RF register - * 4) PWD 136 RF register - * 5) PWD 132 RF register - * 6) PWD 131 RF register - * 7) PWD 130 RF register - */ -static const struct ath5k_gain_opt rfgain_opt_5112 = { - 1, - 8, - { - { { 3, 0, 0, 0, 0, 0, 0 }, 6 }, - { { 2, 0, 0, 0, 0, 0, 0 }, 0 }, - { { 1, 0, 0, 0, 0, 0, 0 }, -3 }, - { { 0, 0, 0, 0, 0, 0, 0 }, -6 }, - { { 0, 1, 1, 0, 0, 0, 0 }, -8 }, - { { 0, 1, 1, 0, 1, 1, 0 }, -10 }, - { { 0, 1, 0, 1, 1, 1, 0 }, -13 }, - { { 0, 1, 0, 1, 1, 0, 1 }, -16 }, - } -}; - diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig deleted file mode 100644 index 0ed1ac3..0000000 --- a/drivers/net/wireless/ath9k/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config ATH9K - tristate "Atheros 802.11n wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 - depends on RFKILL || RFKILL=n - select ATH_COMMON - 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. - - If you choose to build a module, it'll be called ath9k. - -config ATH9K_DEBUG - bool "Atheros ath9k debugging" - depends on ATH9K - ---help--- - Say Y, if you need ath9k to display debug messages. - Pass the debug mask as a module parameter: - - modprobe ath9k debug=0x00002000 - - Look in ath9k/core.h for possible debug masks diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile deleted file mode 100644 index 783bc39..0000000 --- a/drivers/net/wireless/ath9k/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -ath9k-y += hw.o \ - eeprom.o \ - mac.o \ - calib.o \ - ani.o \ - phy.o \ - beacon.o \ - main.o \ - recv.o \ - xmit.o \ - virtual.o \ - rc.o - -ath9k-$(CONFIG_PCI) += pci.o -ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o -ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o - -obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath9k/ahb.c deleted file mode 100644 index 0e65c51..0000000 --- a/drivers/net/wireless/ath9k/ahb.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * Copyright (c) 2009 Gabor Juhos - * Copyright (c) 2009 Imre Kaloz - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include "ath9k.h" - -/* return bus cachesize in 4B word units */ -static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz) -{ - *csz = L1_CACHE_BYTES >> 2; -} - -static void ath_ahb_cleanup(struct ath_softc *sc) -{ - iounmap(sc->mem); -} - -static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) -{ - struct ath_softc *sc = ah->ah_sc; - struct platform_device *pdev = to_platform_device(sc->dev); - struct ath9k_platform_data *pdata; - - pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; - if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: flash read failed, offset %08x is out of range\n", - __func__, off); - return false; - } - - *data = pdata->eeprom_data[off]; - return true; -} - -static struct ath_bus_ops ath_ahb_bus_ops = { - .read_cachesize = ath_ahb_read_cachesize, - .cleanup = ath_ahb_cleanup, - - .eeprom_read = ath_ahb_eeprom_read, -}; - -static int ath_ahb_probe(struct platform_device *pdev) -{ - void __iomem *mem; - struct ath_wiphy *aphy; - struct ath_softc *sc; - struct ieee80211_hw *hw; - struct resource *res; - int irq; - int ret = 0; - struct ath_hw *ah; - - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "no platform data specified\n"); - ret = -EINVAL; - goto err_out; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no memory resource found\n"); - ret = -ENXIO; - goto err_out; - } - - mem = ioremap_nocache(res->start, res->end - res->start + 1); - if (mem == NULL) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_out; - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no IRQ resource found\n"); - ret = -ENXIO; - goto err_iounmap; - } - - irq = res->start; - - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + - sizeof(struct ath_softc), &ath9k_ops); - if (hw == NULL) { - dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); - ret = -ENOMEM; - goto err_iounmap; - } - - SET_IEEE80211_DEV(hw, &pdev->dev); - platform_set_drvdata(pdev, hw); - - aphy = hw->priv; - sc = (struct ath_softc *) (aphy + 1); - aphy->sc = sc; - aphy->hw = hw; - sc->pri_wiphy = aphy; - sc->hw = hw; - sc->dev = &pdev->dev; - sc->mem = mem; - sc->bus_ops = &ath_ahb_bus_ops; - sc->irq = irq; - - ret = ath_attach(AR5416_AR9100_DEVID, sc); - if (ret != 0) { - dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); - ret = -ENODEV; - goto err_free_hw; - } - - ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); - if (ret) { - dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret); - ret = -EIO; - goto err_detach; - } - - ah = sc->sc_ah; - printk(KERN_INFO - "%s: Atheros AR%s MAC/BB Rev:%x, " - "AR%s RF Rev:%x, mem=0x%lx, irq=%d\n", - wiphy_name(hw->wiphy), - ath_mac_bb_name(ah->hw_version.macVersion), - ah->hw_version.macRev, - ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), - ah->hw_version.phyRev, - (unsigned long)mem, irq); - - return 0; - - err_detach: - ath_detach(sc); - err_free_hw: - ieee80211_free_hw(hw); - platform_set_drvdata(pdev, NULL); - err_iounmap: - iounmap(mem); - err_out: - return ret; -} - -static int ath_ahb_remove(struct platform_device *pdev) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - - if (hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - ath_cleanup(sc); - platform_set_drvdata(pdev, NULL); - } - - return 0; -} - -static struct platform_driver ath_ahb_driver = { - .probe = ath_ahb_probe, - .remove = ath_ahb_remove, - .driver = { - .name = "ath9k", - .owner = THIS_MODULE, - }, -}; - -int ath_ahb_init(void) -{ - return platform_driver_register(&ath_ahb_driver); -} - -void ath_ahb_exit(void) -{ - platform_driver_unregister(&ath_ahb_driver); -} diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c deleted file mode 100644 index 1aeafb5..0000000 --- a/drivers/net/wireless/ath9k/ani.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { - if (ah->ani[i].c && - ah->ani[i].c->channel == chan->channel) - return i; - if (ah->ani[i].c == NULL) { - ah->ani[i].c = chan; - return i; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "No more channel states left. Using channel 0\n"); - - return 0; -} - -static bool ath9k_hw_ani_control(struct ath_hw *ah, - enum ath9k_ani_cmd cmd, int param) -{ - struct ar5416AniState *aniState = ah->curani; - - switch (cmd & ah->ani_function) { - case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ - u32 level = param; - - if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); - return false; - } - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_TOT_DES, - ah->totalSizeDesired[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_LOW, - ah->coarse_low[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_HIGH, - ah->coarse_high[level]); - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRPWR, - ah->firpwr[level]); - - if (level > aniState->noiseImmunityLevel) - ah->stats.ast_ani_niup++; - else if (level < aniState->noiseImmunityLevel) - ah->stats.ast_ani_nidown++; - aniState->noiseImmunityLevel = level; - break; - } - case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - const int m1ThreshLow[] = { 127, 50 }; - const int m2ThreshLow[] = { 127, 40 }; - const int m1Thresh[] = { 127, 0x4d }; - const int m2Thresh[] = { 127, 0x40 }; - const int m2CountThr[] = { 31, 16 }; - const int m2CountThrLow[] = { 63, 48 }; - u32 on = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2_THRESH, - m2Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2COUNT_THR, - m2CountThr[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, - m2CountThrLow[on]); - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH, - m2Thresh[on]); - - if (on) - REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - else - REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - - if (!on != aniState->ofdmWeakSigDetectOff) { - if (on) - ah->stats.ast_ani_ofdmon++; - else - ah->stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; - } - break; - } - case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ - const int weakSigThrCck[] = { 8, 6 }; - u32 high = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, - weakSigThrCck[high]); - if (high != aniState->cckWeakSigThreshold) { - if (high) - ah->stats.ast_ani_cckhigh++; - else - ah->stats.ast_ani_ccklow++; - aniState->cckWeakSigThreshold = high; - } - break; - } - case ATH9K_ANI_FIRSTEP_LEVEL:{ - const int firstep[] = { 0, 4, 8 }; - u32 level = param; - - if (level >= ARRAY_SIZE(firstep)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned) ARRAY_SIZE(firstep)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - firstep[level]); - if (level > aniState->firstepLevel) - ah->stats.ast_ani_stepup++; - else if (level < aniState->firstepLevel) - ah->stats.ast_ani_stepdown++; - aniState->firstepLevel = level; - break; - } - case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ - const int cycpwrThr1[] = - { 2, 4, 6, 8, 10, 12, 14, 16 }; - u32 level = param; - - if (level >= ARRAY_SIZE(cycpwrThr1)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned) - ARRAY_SIZE(cycpwrThr1)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - cycpwrThr1[level]); - if (level > aniState->spurImmunityLevel) - ah->stats.ast_ani_spurup++; - else if (level < aniState->spurImmunityLevel) - ah->stats.ast_ani_spurdown++; - aniState->spurImmunityLevel = level; - break; - } - case ATH9K_ANI_PRESENT: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "invalid cmd %u\n", cmd); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n"); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "noiseImmunityLevel=%d, spurImmunityLevel=%d, " - "ofdmWeakSigDetectOff=%d\n", - aniState->noiseImmunityLevel, aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cckWeakSigThreshold=%d, " - "firstepLevel=%d, listenTime=%d\n", - aniState->cckWeakSigThreshold, aniState->firstepLevel, - aniState->listenTime); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->cycleCount, aniState->ofdmPhyErrCount, - aniState->cckPhyErrCount); - - return true; -} - -static void ath9k_hw_update_mibstats(struct ath_hw *ah, - struct ath9k_mib_stats *stats) -{ - stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); - stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); - stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); - stats->rts_good += REG_READ(ah, AR_RTS_OK); - stats->beacons += REG_READ(ah, AR_BEACON_CNT); -} - -static void ath9k_ani_restart(struct ath_hw *ah) -{ - struct ar5416AniState *aniState; - - if (!DO_ANI(ah)) - return; - - aniState = ah->curani; - - aniState->listenTime = 0; - if (ah->has_hw_phycounters) { - if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { - aniState->ofdmPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); - } else { - aniState->ofdmPhyErrBase = - AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; - } - if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { - aniState->cckPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); - } else { - aniState->cckPhyErrBase = - AR_PHY_COUNTMAX - aniState->cckTrigHigh; - } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Writing ofdmbase=%u cckbase=%u\n", - aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - } - aniState->ofdmPhyErrCount = 0; - aniState->cckPhyErrCount = 0; -} - -static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - struct ar5416AniState *aniState; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ah->curani; - - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - - if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel + 1)) { - return; - } - } - - if (ah->opmode == NL80211_IFTYPE_AP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ah); - if (rssi > aniState->rssiThrHigh) { - if (!aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false)) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); - return; - } - } - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true); - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } else { - if (conf->channel->band == IEEE80211_BAND_2GHZ) { - if (!aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false); - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, 0); - return; - } - } -} - -static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - struct ar5416AniState *aniState; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ah->curani; - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - if (ah->opmode == NL80211_IFTYPE_AP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ah); - if (rssi > aniState->rssiThrLow) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } else { - if (conf->channel->band == IEEE80211_BAND_2GHZ) { - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, 0); - } - } -} - -static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) -{ - struct ar5416AniState *aniState; - int32_t rssi; - - aniState = ah->curani; - - if (ah->opmode == NL80211_IFTYPE_AP) { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) - return; - } - } else { - rssi = BEACON_RSSI(ah); - if (rssi > aniState->rssiThrHigh) { - /* XXX: Handle me */ - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true) == true) - return; - } - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == true) - return; - } - } else { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == true) - return; - } - } - } - - if (aniState->spurImmunityLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel - 1)) - return; - } - - if (aniState->noiseImmunityLevel > 0) { - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel - 1); - return; - } -} - -static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) -{ - struct ar5416AniState *aniState; - u32 txFrameCount, rxFrameCount, cycleCount; - int32_t listenTime; - - txFrameCount = REG_READ(ah, AR_TFCNT); - rxFrameCount = REG_READ(ah, AR_RFCNT); - cycleCount = REG_READ(ah, AR_CCCNT); - - aniState = ah->curani; - if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { - - listenTime = 0; - ah->stats.ast_ani_lzero++; - } else { - int32_t ccdelta = cycleCount - aniState->cycleCount; - int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; - int32_t tfdelta = txFrameCount - aniState->txFrameCount; - listenTime = (ccdelta - rfdelta - tfdelta) / 44000; - } - aniState->cycleCount = cycleCount; - aniState->txFrameCount = txFrameCount; - aniState->rxFrameCount = rxFrameCount; - - return listenTime; -} - -void ath9k_ani_reset(struct ath_hw *ah) -{ - struct ar5416AniState *aniState; - struct ath9k_channel *chan = ah->curchan; - int index; - - if (!DO_ANI(ah)) - return; - - index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ah->ani[index]; - ah->curani = aniState; - - if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION - && ah->opmode != NL80211_IFTYPE_ADHOC) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Reset ANI state opmode %u\n", ah->opmode); - ah->stats.ast_ani_reset++; - - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !ATH9K_ANI_USE_OFDM_WEAK_SIG); - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - ATH9K_ANI_CCK_WEAK_SIG_THR); - - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - - if (ah->opmode == NL80211_IFTYPE_AP) { - ah->curani->ofdmTrigHigh = - ah->config.ofdm_trig_high; - ah->curani->ofdmTrigLow = - ah->config.ofdm_trig_low; - ah->curani->cckTrigHigh = - ah->config.cck_trig_high; - ah->curani->cckTrigLow = - ah->config.cck_trig_low; - } - ath9k_ani_restart(ah); - return; - } - - if (aniState->noiseImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel); - if (aniState->spurImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel); - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !aniState->ofdmWeakSigDetectOff); - if (aniState->cckWeakSigThreshold) - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - aniState->cckWeakSigThreshold); - if (aniState->firstepLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel); - if (ah->has_hw_phycounters) { - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - } else { - ath9k_ani_restart(ah); - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - } -} - -void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan) -{ - struct ar5416AniState *aniState; - int32_t listenTime; - - if (!DO_ANI(ah)) - return; - - aniState = ah->curani; - ah->stats.ast_nodestats = *stats; - - listenTime = ath9k_hw_ani_get_listen_time(ah); - if (listenTime < 0) { - ah->stats.ast_ani_lneg++; - ath9k_ani_restart(ah); - return; - } - - aniState->listenTime += listenTime; - - if (ah->has_hw_phycounters) { - u32 phyCnt1, phyCnt2; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return; - } - - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ah->stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ah->stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - } - - if (aniState->listenTime > 5 * ah->aniperiod) { - if (aniState->ofdmPhyErrCount <= aniState->listenTime * - aniState->ofdmTrigLow / 1000 && - aniState->cckPhyErrCount <= aniState->listenTime * - aniState->cckTrigLow / 1000) - ath9k_hw_ani_lower_immunity(ah); - ath9k_ani_restart(ah); - } else if (aniState->listenTime > ah->aniperiod) { - if (aniState->ofdmPhyErrCount > aniState->listenTime * - aniState->ofdmTrigHigh / 1000) { - ath9k_hw_ani_ofdm_err_trigger(ah); - ath9k_ani_restart(ah); - } else if (aniState->cckPhyErrCount > - aniState->listenTime * aniState->cckTrigHigh / - 1000) { - ath9k_hw_ani_cck_err_trigger(ah); - ath9k_ani_restart(ah); - } - } -} - -bool ath9k_hw_phycounters(struct ath_hw *ah) -{ - return ah->has_hw_phycounters ? true : false; -} - -void ath9k_enable_mib_counters(struct ath_hw *ah) -{ - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); - - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - REG_WRITE(ah, AR_MIBC, - ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) - & 0x0f); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); -} - -/* Freeze the MIB counters, get the stats and then clear them */ -void ath9k_hw_disable_mib_counters(struct ath_hw *ah) -{ - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); - REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); -} - -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt) -{ - static u32 cycles, rx_clear, rx_frame, tx_frame; - u32 good = 1; - - u32 rc = REG_READ(ah, AR_RCCNT); - u32 rf = REG_READ(ah, AR_RFCNT); - u32 tf = REG_READ(ah, AR_TFCNT); - u32 cc = REG_READ(ah, AR_CCCNT); - - if (cycles == 0 || cycles > cc) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cycle counter wrap. ExtBusy = 0\n"); - good = 0; - } else { - u32 cc_d = cc - cycles; - u32 rc_d = rc - rx_clear; - u32 rf_d = rf - rx_frame; - u32 tf_d = tf - tx_frame; - - if (cc_d != 0) { - *rxc_pcnt = rc_d * 100 / cc_d; - *rxf_pcnt = rf_d * 100 / cc_d; - *txf_pcnt = tf_d * 100 / cc_d; - } else { - good = 0; - } - } - - cycles = cc; - rx_frame = rf; - rx_clear = rc; - tx_frame = tf; - - return good; -} - -/* - * 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_hw *ah, - const struct ath9k_node_stats *stats) -{ - u32 phyCnt1, phyCnt2; - - /* 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, &ah->ah_mibStats); - 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) || - ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - struct ar5416AniState *aniState = ah->curani; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ah->stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ah->stats.ast_ani_cckerrs += - 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); - } -} - -void ath9k_hw_ani_setup(struct ath_hw *ah) -{ - int i; - - const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; - const int coarseHigh[] = { -14, -14, -14, -14, -12 }; - const int coarseLow[] = { -64, -64, -64, -64, -70 }; - const int firpwr[] = { -78, -78, -78, -78, -80 }; - - for (i = 0; i < 5; i++) { - ah->totalSizeDesired[i] = totalSizeDesired[i]; - ah->coarse_high[i] = coarseHigh[i]; - ah->coarse_low[i] = coarseLow[i]; - ah->firpwr[i] = firpwr[i]; - } -} - -void ath9k_hw_ani_attach(struct ath_hw *ah) -{ - int i; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); - - ah->has_hw_phycounters = 1; - - memset(ah->ani, 0, sizeof(ah->ani)); - for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { - ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; - ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; - ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; - ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; - ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; - ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; - ah->ani[i].ofdmWeakSigDetectOff = - !ATH9K_ANI_USE_OFDM_WEAK_SIG; - ah->ani[i].cckWeakSigThreshold = - ATH9K_ANI_CCK_WEAK_SIG_THR; - ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; - ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (ah->has_hw_phycounters) { - ah->ani[i].ofdmPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; - ah->ani[i].cckPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; - } - } - if (ah->has_hw_phycounters) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ah->ani[0].ofdmPhyErrBase); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ah->ani[0].cckPhyErrBase); - - REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); - ath9k_enable_mib_counters(ah); - } - ah->aniperiod = ATH9K_ANI_PERIOD; - if (ah->config.enable_ani) - ah->proc_phyerr |= HAL_PROCESS_ANI; -} - -void ath9k_hw_ani_detach(struct ath_hw *ah) -{ - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); - - if (ah->has_hw_phycounters) { - ath9k_hw_disable_mib_counters(ah); - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - } -} diff --git a/drivers/net/wireless/ath9k/ani.h b/drivers/net/wireless/ath9k/ani.h deleted file mode 100644 index 08b4e7e..0000000 --- a/drivers/net/wireless/ath9k/ani.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef ANI_H -#define ANI_H - -#define HAL_PROCESS_ANI 0x00000001 -#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) - -#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) - -#define HAL_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define BEACON_RSSI(ahp) \ - HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \ - ATH9K_RSSI_EP_MULTIPLIER) - -#define ATH9K_ANI_OFDM_TRIG_HIGH 500 -#define ATH9K_ANI_OFDM_TRIG_LOW 200 -#define ATH9K_ANI_CCK_TRIG_HIGH 200 -#define ATH9K_ANI_CCK_TRIG_LOW 100 -#define ATH9K_ANI_NOISE_IMMUNE_LVL 4 -#define ATH9K_ANI_USE_OFDM_WEAK_SIG true -#define ATH9K_ANI_CCK_WEAK_SIG_THR false -#define ATH9K_ANI_SPUR_IMMUNE_LVL 7 -#define ATH9K_ANI_FIRSTEP_LVL 0 -#define ATH9K_ANI_RSSI_THR_HIGH 40 -#define ATH9K_ANI_RSSI_THR_LOW 7 -#define ATH9K_ANI_PERIOD 100 - -#define HAL_NOISE_IMMUNE_MAX 4 -#define HAL_SPUR_IMMUNE_MAX 7 -#define HAL_FIRST_STEP_MAX 2 - -enum ath9k_ani_cmd { - ATH9K_ANI_PRESENT = 0x1, - ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4, - ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8, - ATH9K_ANI_FIRSTEP_LEVEL = 0x10, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20, - ATH9K_ANI_MODE = 0x40, - ATH9K_ANI_PHYERR_RESET = 0x80, - ATH9K_ANI_ALL = 0xff -}; - -struct ath9k_mib_stats { - u32 ackrcv_bad; - u32 rts_bad; - u32 rts_good; - u32 fcs_bad; - u32 beacons; -}; - -struct ath9k_node_stats { - u32 ns_avgbrssi; - u32 ns_avgrssi; - u32 ns_avgtxrssi; - u32 ns_avgtxrate; -}; - -struct ar5416AniState { - struct ath9k_channel *c; - u8 noiseImmunityLevel; - u8 spurImmunityLevel; - u8 firstepLevel; - u8 ofdmWeakSigDetectOff; - u8 cckWeakSigThreshold; - u32 listenTime; - u32 ofdmTrigHigh; - u32 ofdmTrigLow; - int32_t cckTrigHigh; - int32_t cckTrigLow; - int32_t rssiThrLow; - int32_t rssiThrHigh; - u32 noiseFloor; - u32 txFrameCount; - u32 rxFrameCount; - u32 cycleCount; - u32 ofdmPhyErrCount; - u32 cckPhyErrCount; - u32 ofdmPhyErrBase; - u32 cckPhyErrBase; - int16_t pktRssi[2]; - int16_t ofdmErrRssi[2]; - int16_t cckErrRssi[2]; -}; - -struct ar5416Stats { - u32 ast_ani_niup; - u32 ast_ani_nidown; - u32 ast_ani_spurup; - u32 ast_ani_spurdown; - u32 ast_ani_ofdmon; - u32 ast_ani_ofdmoff; - u32 ast_ani_cckhigh; - u32 ast_ani_ccklow; - u32 ast_ani_stepup; - u32 ast_ani_stepdown; - u32 ast_ani_ofdmerrs; - u32 ast_ani_cckerrs; - u32 ast_ani_reset; - u32 ast_ani_lzero; - u32 ast_ani_lneg; - struct ath9k_mib_stats ast_mibstats; - struct ath9k_node_stats ast_nodestats; -}; -#define ah_mibStats stats.ast_mibstats - -void ath9k_ani_reset(struct ath_hw *ah); -void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan); -bool ath9k_hw_phycounters(struct ath_hw *ah); -void ath9k_enable_mib_counters(struct ath_hw *ah); -void ath9k_hw_disable_mib_counters(struct ath_hw *ah); -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, - u32 *rxf_pcnt, u32 *txf_pcnt); -void ath9k_hw_procmibevent(struct ath_hw *ah, - const struct ath9k_node_stats *stats); -void ath9k_hw_ani_setup(struct ath_hw *ah); -void ath9k_hw_ani_attach(struct ath_hw *ah); -void ath9k_hw_ani_detach(struct ath_hw *ah); - -#endif /* ANI_H */ diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h deleted file mode 100644 index c92d46f..0000000 --- a/drivers/net/wireless/ath9k/ath9k.h +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef ATH9K_H -#define ATH9K_H - -#include -#include -#include -#include -#include - -#include "hw.h" -#include "rc.h" -#include "debug.h" - -struct ath_node; - -/* Macro to expand scalars to 64-bit objects */ - -#define ito64(x) (sizeof(x) == 8) ? \ - (((unsigned long long int)(x)) & (0xff)) : \ - (sizeof(x) == 16) ? \ - (((unsigned long long int)(x)) & 0xffff) : \ - ((sizeof(x) == 32) ? \ - (((unsigned long long int)(x)) & 0xffffffff) : \ - (unsigned long long int)(x)) - -/* increment with wrap-around */ -#define INCR(_l, _sz) do { \ - (_l)++; \ - (_l) &= ((_sz) - 1); \ - } while (0) - -/* decrement with wrap-around */ -#define DECR(_l, _sz) do { \ - (_l)--; \ - (_l) &= ((_sz) - 1); \ - } while (0) - -#define A_MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define ASSERT(exp) BUG_ON(!(exp)) - -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) - -#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<bf_stale = false; \ - (_bf)->bf_lastbf = NULL; \ - (_bf)->bf_next = NULL; \ - memset(&((_bf)->bf_state), 0, \ - sizeof(struct ath_buf_state)); \ - } while (0) - -#define ATH_RXBUF_RESET(_bf) do { \ - (_bf)->bf_stale = false; \ - } while (0) - -/** - * enum buffer_type - Buffer type flags - * - * @BUF_HT: Send this buffer using HT capabilities - * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) - * @BUF_AGGR: Indicates whether the buffer can be aggregated - * (used in aggregation scheduling) - * @BUF_RETRY: Indicates whether the buffer is retried - * @BUF_XRETRY: To denote excessive retries of the buffer - */ -enum buffer_type { - BUF_HT = BIT(1), - BUF_AMPDU = BIT(2), - BUF_AGGR = BIT(3), - BUF_RETRY = BIT(4), - BUF_XRETRY = BIT(5), -}; - -struct ath_buf_state { - int bfs_nframes; - u16 bfs_al; - u16 bfs_frmlen; - int bfs_seqno; - int bfs_tidno; - int bfs_retries; - u8 bf_type; - u32 bfs_keyix; - enum ath9k_key_type bfs_keytype; -}; - -#define bf_nframes bf_state.bfs_nframes -#define bf_al bf_state.bfs_al -#define bf_frmlen bf_state.bfs_frmlen -#define bf_retries bf_state.bfs_retries -#define bf_seqno bf_state.bfs_seqno -#define bf_tidno bf_state.bfs_tidno -#define bf_keyix bf_state.bfs_keyix -#define bf_keytype bf_state.bfs_keytype -#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) -#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) -#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) -#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) -#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) - -struct ath_buf { - struct list_head list; - struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or - an aggregate) */ - struct ath_buf *bf_next; /* next subframe in the aggregate */ - struct sk_buff *bf_mpdu; /* enclosing frame structure */ - struct ath_desc *bf_desc; /* virtual addr of desc */ - dma_addr_t bf_daddr; /* physical addr of desc */ - dma_addr_t bf_buf_addr; /* physical addr of data buffer */ - bool bf_stale; - u16 bf_flags; - struct ath_buf_state bf_state; - dma_addr_t bf_dmacontext; -}; - -struct ath_descdma { - struct ath_desc *dd_desc; - dma_addr_t dd_desc_paddr; - u32 dd_desc_len; - struct ath_buf *dd_bufptr; -}; - -int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head, const char *name, - int nbuf, int ndesc); -void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head); - -/***********/ -/* RX / TX */ -/***********/ - -#define ATH_MAX_ANTENNA 3 -#define ATH_RXBUF 512 -#define WME_NUM_TID 16 -#define ATH_TXBUF 512 -#define ATH_TXMAXTRY 13 -#define ATH_11N_TXMAXTRY 10 -#define ATH_MGT_TXMAXTRY 4 -#define WME_BA_BMP_SIZE 64 -#define WME_MAX_BA WME_BA_BMP_SIZE -#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) - -#define TID_TO_WME_AC(_tid) \ - ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ - (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ - (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ - WME_AC_VO) - -#define WME_AC_BE 0 -#define WME_AC_BK 1 -#define WME_AC_VI 2 -#define WME_AC_VO 3 -#define WME_NUM_AC 4 - -#define ADDBA_EXCHANGE_ATTEMPTS 10 -#define ATH_AGGR_DELIM_SZ 4 -#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ -/* number of delimiters for encryption padding */ -#define ATH_AGGR_ENCRYPTDELIM 10 -/* minimum h/w qdepth to be sustained to maximize aggregation */ -#define ATH_AGGR_MIN_QDEPTH 2 -#define ATH_AMPDU_SUBFRAME_DEFAULT 32 -#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) -#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX - -#define IEEE80211_SEQ_SEQ_SHIFT 4 -#define IEEE80211_SEQ_MAX 4096 -#define IEEE80211_MIN_AMPDU_BUF 0x8 -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 -#define IEEE80211_WEP_IVLEN 3 -#define IEEE80211_WEP_KIDLEN 1 -#define IEEE80211_WEP_CRCLEN 4 -#define IEEE80211_MAX_MPDU_LEN (3840 + FCS_LEN + \ - (IEEE80211_WEP_IVLEN + \ - IEEE80211_WEP_KIDLEN + \ - IEEE80211_WEP_CRCLEN)) - -/* return whether a bit at index _n in bitmap _bm is set - * _sz is the size of the bitmap */ -#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ - ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) - -/* return block-ack bitmap index given sequence and starting sequence */ -#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) - -/* returns delimiter padding required given the packet length */ -#define ATH_AGGR_GET_NDELIM(_len) \ - (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ - (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) - -#define BAW_WITHIN(_start, _bawsz, _seqno) \ - ((((_seqno) - (_start)) & 4095) < (_bawsz)) - -#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) -#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) -#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) -#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) - -enum ATH_AGGR_STATUS { - ATH_AGGR_DONE, - ATH_AGGR_BAW_CLOSED, - ATH_AGGR_LIMITED, -}; - -struct ath_txq { - u32 axq_qnum; - u32 *axq_link; - struct list_head axq_q; - spinlock_t axq_lock; - u32 axq_depth; - u8 axq_aggr_depth; - u32 axq_totalqueued; - bool stopped; - struct ath_buf *axq_linkbuf; - - /* first desc of the last descriptor that contains CTS */ - struct ath_desc *axq_lastdsWithCTS; - - /* final desc of the gating desc that determines whether - lastdsWithCTS has been DMA'ed or not */ - struct ath_desc *axq_gatingds; - - struct list_head axq_acq; -}; - -#define AGGR_CLEANUP BIT(1) -#define AGGR_ADDBA_COMPLETE BIT(2) -#define AGGR_ADDBA_PROGRESS BIT(3) - -struct ath_atx_tid { - struct list_head list; - struct list_head buf_q; - struct ath_node *an; - struct ath_atx_ac *ac; - struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; - u16 seq_start; - u16 seq_next; - u16 baw_size; - int tidno; - int baw_head; /* first un-acked tx buffer */ - int baw_tail; /* next unused tx buffer slot */ - int sched; - int paused; - u8 state; - int addba_exchangeattempts; -}; - -struct ath_atx_ac { - int sched; - int qnum; - struct list_head list; - struct list_head tid_q; -}; - -struct ath_tx_control { - struct ath_txq *txq; - int if_id; - enum ath9k_internal_frame_type frame_type; -}; - -#define ATH_TX_ERROR 0x01 -#define ATH_TX_XRETRY 0x02 -#define ATH_TX_BAR 0x04 - -struct ath_node { - struct ath_softc *an_sc; - struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; - u16 maxampdu; - u8 mpdudensity; -}; - -struct ath_tx { - u16 seq_no; - u32 txqsetup; - int hwq_map[ATH9K_WME_AC_VO+1]; - spinlock_t txbuflock; - struct list_head txbuf; - struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; - struct ath_descdma txdma; -}; - -struct ath_rx { - u8 defant; - u8 rxotherant; - u32 *rxlink; - int bufsize; - unsigned int rxfilter; - spinlock_t rxflushlock; - spinlock_t rxbuflock; - struct list_head rxbuf; - struct ath_descdma rxdma; -}; - -int ath_startrecv(struct ath_softc *sc); -bool ath_stoprecv(struct ath_softc *sc); -void ath_flushrecv(struct ath_softc *sc); -u32 ath_calcrxfilter(struct ath_softc *sc); -int ath_rx_init(struct ath_softc *sc, int nbufs); -void ath_rx_cleanup(struct ath_softc *sc); -int ath_rx_tasklet(struct ath_softc *sc, int flush); -struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); -void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); -int ath_tx_setup(struct ath_softc *sc, int haltype); -void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); -void ath_draintxq(struct ath_softc *sc, - 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); -void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); -int ath_tx_init(struct ath_softc *sc, int nbufs); -void ath_tx_cleanup(struct ath_softc *sc); -struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); -int ath_txq_update(struct ath_softc *sc, int qnum, - struct ath9k_tx_queue_info *q); -int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath_tx_control *txctl); -void ath_tx_tasklet(struct ath_softc *sc); -void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); -bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn); -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); - -/********/ -/* VIFs */ -/********/ - -struct ath_vif { - int av_bslot; - __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ - enum nl80211_iftype av_opmode; - struct ath_buf *av_bcbuf; - struct ath_tx_control av_btxctl; - u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ -}; - -/*******************/ -/* Beacon Handling */ -/*******************/ - -/* - * Regardless of the number of beacons we stagger, (i.e. regardless of the - * number of BSSIDs) if a given beacon does not go out even after waiting this - * number of beacon intervals, the game's up. - */ -#define BSTUCK_THRESH (9 * ATH_BCBUF) -#define ATH_BCBUF 4 -#define ATH_DEFAULT_BINTVAL 100 /* TU */ -#define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) - -struct ath_beacon_config { - u16 beacon_interval; - u16 listen_interval; - u16 dtim_period; - u16 bmiss_timeout; - u8 dtim_count; -}; - -struct ath_beacon { - enum { - OK, /* no change needed */ - UPDATE, /* update pending */ - COMMIT /* beacon sent, commit change */ - } updateslot; /* slot time update fsm */ - - u32 beaconq; - u32 bmisscnt; - u32 ast_be_xmit; - u64 bc_tstamp; - struct ieee80211_vif *bslot[ATH_BCBUF]; - struct ath_wiphy *bslot_aphy[ATH_BCBUF]; - int slottime; - int slotupdate; - struct ath9k_tx_queue_info beacon_qi; - struct ath_descdma bdma; - struct ath_txq *cabq; - struct list_head bbuf; -}; - -void ath_beacon_tasklet(unsigned long data); -void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); -int ath_beaconq_setup(struct ath_hw *ah); -int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); -void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); - -/*******/ -/* ANI */ -/*******/ - -#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ -#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */ -#define ATH_ANI_POLLINTERVAL 100 /* 100 ms */ -#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ -#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ - -struct ath_ani { - bool caldone; - int16_t noise_floor; - unsigned int longcal_timer; - unsigned int shortcal_timer; - unsigned int resetcal_timer; - unsigned int checkani_timer; - struct timer_list timer; -}; - -/********************/ -/* LED Control */ -/********************/ - -#define ATH_LED_PIN 1 -#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ -#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ - -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 */ -/********************/ - -/* - * Default cache line size, in bytes. - * Used when PCI device not fully initialized by bootrom/BIOS -*/ -#define DEFAULT_CACHELINE 32 -#define ATH_DEFAULT_NOISE_FLOOR -95 -#define ATH_REGCLASSIDS_MAX 10 -#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_MAX_SW_RETRIES 10 -#define ATH_CHAN_MAX 255 -#define IEEE80211_WEP_NKID 4 /* number of key ids */ - -/* - * The key cache is used for h/w cipher state and also for - * tracking station state such as the current tx antenna. - * We also setup a mapping table between key cache slot indices - * and station state to short-circuit node lookups on rx. - * Different parts have different size key caches. We handle - * up to ATH_KEYMAX entries (could dynamically allocate state). - */ -#define ATH_KEYMAX 128 /* max key cache size we handle */ - -#define ATH_TXPOWER_MAX 100 /* .5 dBm units */ -#define ATH_RSSI_DUMMY_MARKER 0x127 -#define ATH_RATE_DUMMY_MARKER 0 - -#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_FULL_RESET BIT(4) -#define SC_OP_PREAMBLE_SHORT BIT(5) -#define SC_OP_PROTECT_ENABLE BIT(6) -#define SC_OP_RXFLUSH BIT(7) -#define SC_OP_LED_ASSOCIATED BIT(8) -#define SC_OP_RFKILL_REGISTERED BIT(9) -#define SC_OP_RFKILL_SW_BLOCKED BIT(10) -#define SC_OP_RFKILL_HW_BLOCKED BIT(11) -#define SC_OP_WAIT_FOR_BEACON BIT(12) -#define SC_OP_LED_ON BIT(13) -#define SC_OP_SCANNING BIT(14) -#define SC_OP_TSF_RESET BIT(15) - -struct ath_bus_ops { - void (*read_cachesize)(struct ath_softc *sc, int *csz); - void (*cleanup)(struct ath_softc *sc); - bool (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data); -}; - -struct ath_wiphy; - -struct ath_softc { - struct ieee80211_hw *hw; - struct device *dev; - - spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ - struct ath_wiphy *pri_wiphy; - struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may - * have NULL entries */ - int num_sec_wiphy; /* number of sec_wiphy pointers in the array */ - int chan_idx; - int chan_is_ht; - struct ath_wiphy *next_wiphy; - struct work_struct chan_work; - int wiphy_select_failures; - unsigned long wiphy_select_first_fail; - struct delayed_work wiphy_work; - unsigned long wiphy_scheduler_int; - int wiphy_scheduler_index; - - struct tasklet_struct intr_tq; - struct tasklet_struct bcon_tasklet; - struct ath_hw *sc_ah; - void __iomem *mem; - int irq; - spinlock_t sc_resetlock; - spinlock_t sc_serial_rw; - struct mutex mutex; - - u8 curbssid[ETH_ALEN]; - u8 bssidmask[ETH_ALEN]; - u32 intrstatus; - u32 sc_flags; /* SC_OP_* */ - u16 curtxpow; - u16 curaid; - u16 cachelsz; - u8 nbcnvifs; - u16 nvifs; - u8 tx_chainmask; - u8 rx_chainmask; - u32 keymax; - DECLARE_BITMAP(keymap, ATH_KEYMAX); - u8 splitmic; - atomic_t ps_usecount; - enum ath9k_int imask; - enum ath9k_ht_extprotspacing ht_extprotspacing; - enum ath9k_ht_macmode tx_chan_width; - - struct ath_config config; - struct ath_rx rx; - struct ath_tx tx; - struct ath_beacon beacon; - struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; - struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; - struct ath_rate_table *cur_rate_table; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - - struct ath_led radio_led; - struct ath_led assoc_led; - struct ath_led tx_led; - struct ath_led rx_led; - struct delayed_work ath_led_blink_work; - int led_on_duration; - int led_off_duration; - int led_on_cnt; - int led_off_cnt; - - struct ath_rfkill rf_kill; - struct ath_ani ani; - struct ath9k_node_stats nodestats; -#ifdef CONFIG_ATH9K_DEBUG - struct ath9k_debug debug; -#endif - struct ath_bus_ops *bus_ops; -}; - -struct ath_wiphy { - struct ath_softc *sc; /* shared for all virtual wiphys */ - struct ieee80211_hw *hw; - enum ath_wiphy_state { - ATH_WIPHY_INACTIVE, - ATH_WIPHY_ACTIVE, - ATH_WIPHY_PAUSING, - ATH_WIPHY_PAUSED, - ATH_WIPHY_SCAN, - } state; - int chan_idx; - int chan_is_ht; -}; - -int ath_reset(struct ath_softc *sc, bool retry_tx); -int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); -int ath_cabq_update(struct ath_softc *); - -static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) -{ - sc->bus_ops->read_cachesize(sc, csz); -} - -static inline void ath_bus_cleanup(struct ath_softc *sc) -{ - sc->bus_ops->cleanup(sc); -} - -extern struct ieee80211_ops ath9k_ops; - -irqreturn_t ath_isr(int irq, void *dev); -void ath_cleanup(struct ath_softc *sc); -int ath_attach(u16 devid, struct ath_softc *sc); -void ath_detach(struct ath_softc *sc); -const char *ath_mac_bb_name(u32 mac_bb_version); -const char *ath_rf_name(u16 rf_version); -void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); -void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *ichan); -void ath_update_chainmask(struct ath_softc *sc, int is_ht); -int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *hchan); -void ath_radio_enable(struct ath_softc *sc); -void ath_radio_disable(struct ath_softc *sc); - -#ifdef CONFIG_PCI -int ath_pci_init(void); -void ath_pci_exit(void); -#else -static inline int ath_pci_init(void) { return 0; }; -static inline void ath_pci_exit(void) {}; -#endif - -#ifdef CONFIG_ATHEROS_AR71XX -int ath_ahb_init(void); -void ath_ahb_exit(void); -#else -static inline int ath_ahb_init(void) { return 0; }; -static inline void ath_ahb_exit(void) {}; -#endif - -static inline void ath9k_ps_wakeup(struct ath_softc *sc) -{ - if (atomic_inc_return(&sc->ps_usecount) == 1) - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { - sc->sc_ah->restore_mode = sc->sc_ah->power_mode; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - } -} - -static inline void ath9k_ps_restore(struct ath_softc *sc) -{ - if (atomic_dec_and_test(&sc->ps_usecount)) - if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) - ath9k_hw_setpower(sc->sc_ah, - sc->sc_ah->restore_mode); -} - - -void ath9k_set_bssid_mask(struct ieee80211_hw *hw); -int ath9k_wiphy_add(struct ath_softc *sc); -int ath9k_wiphy_del(struct ath_wiphy *aphy); -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); -int ath9k_wiphy_pause(struct ath_wiphy *aphy); -int ath9k_wiphy_unpause(struct ath_wiphy *aphy); -int ath9k_wiphy_select(struct ath_wiphy *aphy); -void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int); -void ath9k_wiphy_chan_work(struct work_struct *work); -bool ath9k_wiphy_started(struct ath_softc *sc); -void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, - struct ath_wiphy *selected); -bool ath9k_wiphy_scanning(struct ath_softc *sc); -void ath9k_wiphy_work(struct work_struct *work); - -/* - * Read and write, they both share the same lock. We do this to serialize - * reads and writes on Atheros 802.11n PCI devices only. This is required - * as the FIFO on these devices can only accept sanely 2 requests. After - * that the device goes bananas. Serializing the reads/writes prevents this - * from happening. - */ - -static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) -{ - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - iowrite32(val, ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - iowrite32(val, ah->ah_sc->mem + reg_offset); -} - -static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) -{ - u32 val; - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - val = ioread32(ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - val = ioread32(ah->ah_sc->mem + reg_offset); - return val; -} - -#endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c deleted file mode 100644 index eb4759f..0000000 --- a/drivers/net/wireless/ath9k/beacon.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -#define FUDGE 2 - -/* - * This function will modify certain transmit queue properties depending on - * 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_hw *ah = sc->sc_ah; - struct ath9k_tx_queue_info qi; - - ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { - /* Always burst out beacon and CAB traffic. */ - qi.tqi_aifs = 1; - qi.tqi_cwmin = 0; - qi.tqi_cwmax = 0; - } else { - /* Adhoc mode; important thing is to use 2x cwmin. */ - qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs; - qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin; - qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax; - } - - if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to update h/w beacon queue parameters\n"); - return 0; - } else { - ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); - return 1; - } -} - -/* - * Associates the beacon frame buffer with a transmit descriptor. Will set - * up all required antenna switch parameters, rate codes, and channel flags. - * Beacons are always sent out at the lowest rate, and are not retried. -*/ -static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, - struct ath_buf *bf) -{ - struct sk_buff *skb = bf->bf_mpdu; - struct ath_hw *ah = sc->sc_ah; - struct ath_desc *ds; - struct ath9k_11n_rate_series series[4]; - struct ath_rate_table *rt; - int flags, antenna, ctsrate = 0, ctsduration = 0; - u8 rate; - - ds = bf->bf_desc; - flags = ATH9K_TXDESC_NOACK; - - if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) && - (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { - ds->ds_link = bf->bf_daddr; /* self-linked */ - flags |= ATH9K_TXDESC_VEOL; - /* Let hardware handle antenna switching. */ - antenna = 0; - } else { - ds->ds_link = 0; - /* - * Switch antenna every beacon. - * Should only switch every beacon period, not for every SWBA - * XXX assumes two antennae - */ - antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); - } - - ds->ds_data = bf->bf_buf_addr; - - rt = sc->cur_rate_table; - rate = rt->info[0].ratecode; - if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - rate |= rt->info[0].short_preamble; - - ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, - ATH9K_PKT_TYPE_BEACON, - MAX_RATE_POWER, - ATH9K_TXKEYIX_INVALID, - ATH9K_KEY_TYPE_CLEAR, - flags); - - /* NB: beacon's BufLen must be a multiple of 4 bytes */ - ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4), - true, true, ds); - - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - series[0].Tries = 1; - series[0].Rate = rate; - series[0].ChSel = sc->tx_chainmask; - series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; - ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, - series, 4, 0); -} - -static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_buf *bf; - struct ath_vif *avp; - struct sk_buff *skb; - struct ath_txq *cabq; - struct ieee80211_tx_info *info; - int cabq_depth; - - if (aphy->state != ATH_WIPHY_ACTIVE) - return NULL; - - avp = (void *)vif->drv_priv; - cabq = sc->beacon.cabq; - - if (avp->av_bcbuf == NULL) - return NULL; - - /* Release the old beacon first */ - - bf = avp->av_bcbuf; - skb = bf->bf_mpdu; - if (skb) { - dma_unmap_single(sc->dev, bf->bf_dmacontext, - skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - } - - /* Get a new beacon from mac80211 */ - - skb = ieee80211_beacon_get(hw, vif); - bf->bf_mpdu = skb; - if (skb == NULL) - return NULL; - ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = - avp->tsf_adjust; - - 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->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } - - bf->bf_buf_addr = bf->bf_dmacontext = - dma_map_single(sc->dev, skb->data, - skb->len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n"); - return NULL; - } - - skb = ieee80211_get_buffered_bc(hw, vif); - - /* - * if the CABQ traffic from previous DTIM is pending and the current - * beacon is also a DTIM. - * 1) if there is only one vif let the cab traffic continue. - * 2) if there are more than one vif and we are using staggered - * beacons, then drain the cabq by dropping all the frames in - * the cabq so that the current vifs cab traffic can be scheduled. - */ - spin_lock_bh(&cabq->axq_lock); - cabq_depth = cabq->axq_depth; - spin_unlock_bh(&cabq->axq_lock); - - if (skb && cabq_depth) { - if (sc->nvifs > 1) { - DPRINTF(sc, ATH_DBG_BEACON, - "Flushing previous cabq traffic\n"); - ath_draintxq(sc, cabq, false); - } - } - - ath_beacon_setup(sc, avp, bf); - - while (skb) { - ath_tx_cabq(hw, skb); - skb = ieee80211_get_buffered_bc(hw, vif); - } - - return bf; -} - -/* - * 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, - struct ieee80211_vif *vif) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_buf *bf; - struct ath_vif *avp; - struct sk_buff *skb; - - avp = (void *)vif->drv_priv; - - if (avp->av_bcbuf == NULL) - return; - - bf = avp->av_bcbuf; - skb = bf->bf_mpdu; - - ath_beacon_setup(sc, avp, bf); - - /* NB: caller is known to have already stopped tx dma */ - ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); - ath9k_hw_txstart(ah, sc->beacon.beaconq); - DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", - sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); -} - -int ath_beaconq_setup(struct ath_hw *ah) -{ - struct ath9k_tx_queue_info qi; - - memset(&qi, 0, sizeof(qi)); - qi.tqi_aifs = 1; - qi.tqi_cwmin = 0; - qi.tqi_cwmax = 0; - /* NB: don't enable any interrupts */ - return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); -} - -int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) -{ - struct ath_softc *sc = aphy->sc; - struct ath_vif *avp; - struct ath_buf *bf; - struct sk_buff *skb; - __le64 tstamp; - - avp = (void *)vif->drv_priv; - - /* 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. */ - avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, - struct ath_buf, list); - list_del(&avp->av_bcbuf->list); - - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || - !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { - int slot; - /* - * Assign the vif to a beacon xmit slot. As - * above, this cannot fail to find one. - */ - avp->av_bslot = 0; - for (slot = 0; slot < ATH_BCBUF; slot++) - if (sc->beacon.bslot[slot] == NULL) { - /* - * XXX hack, space out slots to better - * deal with misses - */ - if (slot+1 < ATH_BCBUF && - sc->beacon.bslot[slot+1] == NULL) { - avp->av_bslot = slot+1; - break; - } - avp->av_bslot = slot; - /* NB: keep looking for a double slot */ - } - BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); - sc->beacon.bslot[avp->av_bslot] = vif; - sc->beacon.bslot_aphy[avp->av_bslot] = aphy; - sc->nbcnvifs++; - } - } - - /* release the previous beacon frame, if it already exists. */ - bf = avp->av_bcbuf; - if (bf->bf_mpdu != NULL) { - skb = bf->bf_mpdu; - dma_unmap_single(sc->dev, bf->bf_dmacontext, - skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - } - - /* NB: the beacon data buffer must be 32-bit aligned. */ - skb = ieee80211_beacon_get(sc->hw, vif); - if (skb == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); - return -ENOMEM; - } - - tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->beacon.bc_tstamp = le64_to_cpu(tstamp); - /* Calculate a TSF adjustment factor required for staggered beacons. */ - if (avp->av_bslot > 0) { - u64 tsfadjust; - int intval; - - intval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; - - /* - * Calculate the TSF offset for this beacon slot, i.e., the - * number of usecs that need to be added to the timestamp field - * in Beacon and Probe Response frames. Beacon slot 0 is - * processed at the correct offset, so it does not require TSF - * adjustment. Other slots are adjusted to get the timestamp - * close to the TBTT for the BSS. - */ - tsfadjust = intval * avp->av_bslot / ATH_BCBUF; - avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); - - DPRINTF(sc, ATH_DBG_BEACON, - "stagger beacons, bslot %d intval %u tsfadjust %llu\n", - avp->av_bslot, intval, (unsigned long long)tsfadjust); - - ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = - avp->tsf_adjust; - } else - avp->tsf_adjust = cpu_to_le64(0); - - bf->bf_mpdu = skb; - bf->bf_buf_addr = bf->bf_dmacontext = - dma_map_single(sc->dev, skb->data, - skb->len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, - "dma_mapping_error on beacon alloc\n"); - return -ENOMEM; - } - - return 0; -} - -void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) -{ - if (avp->av_bcbuf != NULL) { - struct ath_buf *bf; - - if (avp->av_bslot != -1) { - sc->beacon.bslot[avp->av_bslot] = NULL; - sc->beacon.bslot_aphy[avp->av_bslot] = NULL; - sc->nbcnvifs--; - } - - bf = avp->av_bcbuf; - if (bf->bf_mpdu != NULL) { - struct sk_buff *skb = bf->bf_mpdu; - dma_unmap_single(sc->dev, bf->bf_dmacontext, - skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - } - list_add_tail(&bf->list, &sc->beacon.bbuf); - - avp->av_bcbuf = NULL; - } -} - -void ath_beacon_tasklet(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - struct ath_hw *ah = sc->sc_ah; - struct ath_buf *bf = NULL; - struct ieee80211_vif *vif; - struct ath_wiphy *aphy; - int slot; - u32 bfaddr, bc = 0, tsftu; - u64 tsf; - u16 intval; - - /* - * Check if the previous beacon has gone out. If - * not don't try to post another, skip this period - * and wait for the next. Missed beacons indicate - * a problem and should not occur. If we miss too - * many consecutive beacons reset the device. - */ - if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { - sc->beacon.bmisscnt++; - - if (sc->beacon.bmisscnt < BSTUCK_THRESH) { - DPRINTF(sc, ATH_DBG_BEACON, - "missed %u consecutive beacons\n", - sc->beacon.bmisscnt); - } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { - DPRINTF(sc, ATH_DBG_BEACON, - "beacon is officially stuck\n"); - ath_reset(sc, false); - } - - return; - } - - if (sc->beacon.bmisscnt != 0) { - DPRINTF(sc, ATH_DBG_BEACON, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); - sc->beacon.bmisscnt = 0; - } - - /* - * Generate beacon frames. we are sending frames - * staggered so calculate the slot for this frame based - * on the tsf to safeguard against missing an swba. - */ - - 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; - /* - * Reverse the slot order to get slot 0 on the TBTT offset that does - * not require TSF adjustment and other slots adding - * slot/ATH_BCBUF * beacon_int to timestamp. For example, with - * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. - * and slot 0 is at correct offset to TBTT. - */ - slot = ATH_BCBUF - slot - 1; - vif = sc->beacon.bslot[slot]; - aphy = sc->beacon.bslot_aphy[slot]; - - DPRINTF(sc, ATH_DBG_BEACON, - "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", - slot, tsf, tsftu, intval, vif); - - bfaddr = 0; - if (vif) { - bf = ath_beacon_generate(aphy->hw, vif); - if (bf != NULL) { - bfaddr = bf->bf_daddr; - bc = 1; - } - } - - /* - * Handle slot time change when a non-ERP station joins/leaves - * an 11g network. The 802.11 layer notifies us via callback, - * we mark updateslot, then wait one beacon before effecting - * the change. This gives associated stations at least one - * beacon interval to note the state change. - * - * NB: The slot time change state machine is clocked according - * to whether we are bursting or staggering beacons. We - * recognize the request to update and record the current - * slot then don't transition until that slot is reached - * again. If we miss a beacon for that slot then we'll be - * slow to transition but we'll be sure at least one beacon - * interval has passed. When bursting slot is always left - * set to ATH_BCBUF so this check is a noop. - */ - if (sc->beacon.updateslot == UPDATE) { - sc->beacon.updateslot = COMMIT; /* commit next beacon */ - sc->beacon.slotupdate = slot; - } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { - ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); - sc->beacon.updateslot = OK; - } - if (bfaddr != 0) { - /* - * Stop any current dma and put the new frame(s) on the queue. - * This should never fail since we check above that no frames - * are still pending on the queue. - */ - if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { - DPRINTF(sc, ATH_DBG_FATAL, - "beacon queue %u did not stop?\n", sc->beacon.beaconq); - } - - /* NB: cabq traffic should already be queued and primed */ - ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); - ath9k_hw_txstart(ah, sc->beacon.beaconq); - - sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ - } -} - -/* - * For multi-bss ap support beacons are either staggered evenly over N slots or - * burst together. For the former arrange for the SWBA to be delivered for each - * slot. Slots that are not occupied will generate nothing. - */ -static void ath_beacon_config_ap(struct ath_softc *sc, - struct ath_beacon_config *conf, - struct ath_vif *avp) -{ - u32 nexttbtt, intval; - - /* Configure the timers only when the TSF has to be reset */ - - if (!(sc->sc_flags & SC_OP_TSF_RESET)) - return; - - /* NB: the beacon interval is kept internally in TU's */ - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - intval /= ATH_BCBUF; /* for staggered beacons */ - nexttbtt = intval; - intval |= ATH9K_BEACON_RESET_TSF; - - /* - * In AP mode we enable the beacon timers and SWBA interrupts to - * prepare beacon frames. - */ - intval |= ATH9K_BEACON_ENA; - sc->imask |= ATH9K_INT_SWBA; - ath_beaconq_config(sc); - - /* Set the computed AP beacon timers */ - - ath9k_hw_set_interrupts(sc->sc_ah, 0); - ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); - sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - - /* Clear the reset TSF flag, so that subsequent beacon updation - will not reset the HW TSF. */ - - sc->sc_flags &= ~SC_OP_TSF_RESET; -} - -/* - * This sets up the beacon timers according to the timestamp of the last - * received beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware will wakeup in - * time to receive beacons, and configures the beacon miss handling so - * we'll receive a BMISS interrupt when we stop seeing beacons from the AP - * we've associated with. - */ -static void ath_beacon_config_sta(struct ath_softc *sc, - struct ath_beacon_config *conf, - struct ath_vif *avp) -{ - struct ath9k_beacon_state bs; - int dtimperiod, dtimcount, sleepduration; - int cfpperiod, cfpcount; - u32 nexttbtt = 0, intval, tsftu; - u64 tsf; - - memset(&bs, 0, sizeof(bs)); - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - - /* - * Setup dtim and cfp parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = conf->dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ - dtimperiod = 1; - dtimcount = conf->dtim_count; - 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; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim+cfp state for the result. - */ - tsf = ath9k_hw_gettsf64(sc->sc_ah); - tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - do { - nexttbtt += intval; - if (--dtimcount < 0) { - dtimcount = dtimperiod - 1; - if (--cfpcount < 0) - cfpcount = cfpperiod - 1; - } - } while (nexttbtt < tsftu); - - bs.bs_intval = intval; - bs.bs_nexttbtt = nexttbtt; - bs.bs_dtimperiod = dtimperiod*intval; - bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; - 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 is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = conf->listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure a multiple of the beacon period is used. Also, if the sleep - * duration is greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - - bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); - DPRINTF(sc, ATH_DBG_BEACON, - "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration, - bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); - - /* Set the computed STA beacon timers */ - - ath9k_hw_set_interrupts(sc->sc_ah, 0); - ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs); - sc->imask |= ATH9K_INT_BMISS; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); -} - -static void ath_beacon_config_adhoc(struct ath_softc *sc, - struct ath_beacon_config *conf, - struct ath_vif *avp, - struct ieee80211_vif *vif) -{ - u64 tsf; - u32 tsftu, intval, nexttbtt; - - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - - /* Pull nexttbtt forward to reflect the current TSF */ - - nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); - if (nexttbtt == 0) - nexttbtt = intval; - else if (intval) - nexttbtt = roundup(nexttbtt, intval); - - tsf = ath9k_hw_gettsf64(sc->sc_ah); - tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - - DPRINTF(sc, ATH_DBG_BEACON, - "IBSS nexttbtt %u intval %u (%u)\n", - nexttbtt, intval, conf->beacon_interval); - - /* - * In IBSS mode enable the beacon timers but only enable SWBA interrupts - * if we need to manually prepare beacon frames. Otherwise we use a - * self-linked tx descriptor and let the hardware deal with things. - */ - intval |= ATH9K_BEACON_ENA; - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) - sc->imask |= ATH9K_INT_SWBA; - - ath_beaconq_config(sc); - - /* Set the computed ADHOC beacon timers */ - - ath9k_hw_set_interrupts(sc->sc_ah, 0); - ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); - sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) - ath_beacon_start_adhoc(sc, vif); -} - -void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) -{ - struct ath_beacon_config conf; - - /* Setup the beacon configuration parameters */ - - memset(&conf, 0, sizeof(struct ath_beacon_config)); - 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; - - if (vif) { - struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; - - switch(avp->av_opmode) { - case NL80211_IFTYPE_AP: - ath_beacon_config_ap(sc, &conf, avp); - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - ath_beacon_config_adhoc(sc, &conf, avp, vif); - break; - case NL80211_IFTYPE_STATION: - ath_beacon_config_sta(sc, &conf, avp); - break; - default: - DPRINTF(sc, ATH_DBG_CONFIG, - "Unsupported beaconing mode\n"); - return; - } - - sc->sc_flags |= SC_OP_BEACONS; - } -} diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c deleted file mode 100644 index e2d62e9..0000000 --- a/drivers/net/wireless/ath9k/calib.c +++ /dev/null @@ -1,1060 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -/* 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_hw *ah, s16 nf) -{ - if (nf > ATH9K_NF_TOO_LOW) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "noise floor value detected (%d) is " - "lower than what we think is a " - "reasonable value (%d)\n", - nf, ATH9K_NF_TOO_LOW); - return false; - } - return true; -} - -static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) -{ - int16_t nfval; - int16_t sort[ATH9K_NF_CAL_HIST_MAX]; - int i, j; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) - sort[i] = nfCalBuffer[i]; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { - for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { - if (sort[j] > sort[j - 1]) { - nfval = sort[j]; - sort[j] = sort[j - 1]; - sort[j - 1] = nfval; - } - } - } - nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; - - return nfval; -} - -static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, - int16_t *nfarray) -{ - int i; - - for (i = 0; i < NUM_NF_READINGS; i++) { - h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; - - if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) - h[i].currIndex = 0; - - if (h[i].invalidNFcount > 0) { - if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || - nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { - h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; - } else { - h[i].invalidNFcount--; - h[i].privNF = nfarray[i]; - } - } else { - h[i].privNF = - ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); - } - } - return; -} - -static void ath9k_hw_do_getnf(struct ath_hw *ah, - int16_t nfarray[NUM_NF_READINGS]) -{ - int16_t nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 0] is %d\n", nf); - nfarray[0] = nf; - - if (!AR_SREV_9285(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR9280_PHY_CH1_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR_PHY_CH1_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 1] is %d\n", nf); - nfarray[1] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), - AR_PHY_CH2_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 2] is %d\n", nf); - nfarray[2] = nf; - } - } - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR9280_PHY_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR_PHY_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 0] is %d\n", nf); - nfarray[3] = nf; - - if (!AR_SREV_9285(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR9280_PHY_CH1_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR_PHY_CH1_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 1] is %d\n", nf); - nfarray[4] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), - AR_PHY_CH2_EXT_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 2] is %d\n", nf); - nfarray[5] = nf; - } - } -} - -static bool getNoiseFloorThresh(struct ath_hw *ah, - enum ieee80211_band band, - int16_t *nft) -{ - switch (band) { - case IEEE80211_BAND_5GHZ: - *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5); - break; - case IEEE80211_BAND_2GHZ: - *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2); - break; - default: - BUG_ON(1); - return false; - } - - return true; -} - -static void ath9k_hw_setup_calibration(struct ath_hw *ah, - struct hal_cal_list *currCal) -{ - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, - currCal->calData->calCountMax); - - switch (currCal->calData->calType) { - case IQ_MISMATCH_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "starting IQ Mismatch Calibration\n"); - break; - case ADC_GAIN_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "starting ADC Gain Calibration\n"); - break; - case ADC_DC_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "starting ADC DC Calibration\n"); - break; - case ADC_DC_INIT_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "starting Init ADC DC Calibration\n"); - break; - } - - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL); -} - -static void ath9k_hw_reset_calibration(struct ath_hw *ah, - struct hal_cal_list *currCal) -{ - int i; - - ath9k_hw_setup_calibration(ah, currCal); - - currCal->calState = CAL_RUNNING; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->meas0.sign[i] = 0; - ah->meas1.sign[i] = 0; - ah->meas2.sign[i] = 0; - ah->meas3.sign[i] = 0; - } - - ah->cal_samples = 0; -} - -static void ath9k_hw_per_calibration(struct ath_hw *ah, - struct ath9k_channel *ichan, - u8 rxchainmask, - struct hal_cal_list *currCal, - bool *isCalDone) -{ - *isCalDone = false; - - if (currCal->calState == CAL_RUNNING) { - if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & - AR_PHY_TIMING_CTRL4_DO_CAL)) { - - currCal->calData->calCollect(ah); - ah->cal_samples++; - - if (ah->cal_samples >= currCal->calData->calNumSamples) { - int i, numChains = 0; - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (rxchainmask & (1 << i)) - numChains++; - } - - currCal->calData->calPostProc(ah, numChains); - ichan->CalValid |= currCal->calData->calType; - currCal->calState = CAL_DONE; - *isCalDone = true; - } else { - ath9k_hw_setup_calibration(ah, currCal); - } - } - } else if (!(ichan->CalValid & currCal->calData->calType)) { - ath9k_hw_reset_calibration(ah, currCal); - } -} - -/* Assumes you are talking about the currently configured channel */ -static bool ath9k_hw_iscal_supported(struct ath_hw *ah, - enum hal_cal_types calType) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - - switch (calType & ah->supp_cals) { - case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ - return true; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - if (conf->channel->band == IEEE80211_BAND_5GHZ && - conf_is_ht20(conf)) - return true; - break; - } - return false; -} - -static void ath9k_hw_iqcal_collect(struct ath_hw *ah) -{ - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ah->cal_samples, i, ah->totalPowerMeasI[i], - ah->totalPowerMeasQ[i], - ah->totalIqCorrMeas[i]); - } -} - -static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah) -{ - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalAdcIOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalAdcIEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalAdcQOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ah->totalAdcQEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ah->cal_samples, i, - ah->totalAdcIOddPhase[i], - ah->totalAdcIEvenPhase[i], - ah->totalAdcQOddPhase[i], - ah->totalAdcQEvenPhase[i]); - } -} - -static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah) -{ - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalAdcDcOffsetIOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalAdcDcOffsetIEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalAdcDcOffsetQOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ah->totalAdcDcOffsetQEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ah->cal_samples, i, - ah->totalAdcDcOffsetIOddPhase[i], - ah->totalAdcDcOffsetIEvenPhase[i], - ah->totalAdcDcOffsetQOddPhase[i], - ah->totalAdcDcOffsetQEvenPhase[i]); - } -} - -static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) -{ - u32 powerMeasQ, powerMeasI, iqCorrMeas; - u32 qCoffDenom, iCoffDenom; - int32_t qCoff, iCoff; - int iqCorrNeg, i; - - for (i = 0; i < numChains; i++) { - powerMeasI = ah->totalPowerMeasI[i]; - powerMeasQ = ah->totalPowerMeasQ[i]; - iqCorrMeas = ah->totalIqCorrMeas[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting IQ Cal and Correction for Chain %d\n", - i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", - i, ah->totalIqCorrMeas[i]); - - iqCorrNeg = 0; - - if (iqCorrMeas > 0x80000000) { - iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; - iqCorrNeg = 1; - } - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", - iqCorrNeg); - - iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; - qCoffDenom = powerMeasQ / 64; - - if (powerMeasQ != 0) { - iCoff = iqCorrMeas / iCoffDenom; - qCoff = powerMeasI / qCoffDenom - 64; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d iCoff = 0x%08x\n", i, iCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d qCoff = 0x%08x\n", i, qCoff); - - iCoff = iCoff & 0x3f; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "New: Chn %d iCoff = 0x%08x\n", i, iCoff); - if (iqCorrNeg == 0x0) - iCoff = 0x40 - iCoff; - - if (qCoff > 15) - qCoff = 15; - else if (qCoff <= -16) - qCoff = 16; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", - i, iCoff, qCoff); - - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, - iCoff); - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, - qCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "IQ Cal and Correction done for Chain %d\n", - i); - } - } - - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); -} - -static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) -{ - u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; - u32 qGainMismatch, iGainMismatch, val, i; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ah->totalAdcIOddPhase[i]; - iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; - qOddMeasOffset = ah->totalAdcQOddPhase[i]; - qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC Gain Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = 0x%08x\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = 0x%08x\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = 0x%08x\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = 0x%08x\n", i, - qEvenMeasOffset); - - if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { - iGainMismatch = - ((iEvenMeasOffset * 32) / - iOddMeasOffset) & 0x3f; - qGainMismatch = - ((qOddMeasOffset * 32) / - qEvenMeasOffset) & 0x3f; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_i = 0x%08x\n", i, - iGainMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_q = 0x%08x\n", i, - qGainMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xfffff000; - val |= (qGainMismatch) | (iGainMismatch << 6); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC Gain Cal done for Chain %d\n", i); - } - } - - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); -} - -static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) -{ - u32 iOddMeasOffset, iEvenMeasOffset, val, i; - int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; - const struct hal_percal_data *calData = - ah->cal_list_curr->calData; - u32 numSamples = - (1 << (calData->calCountMax + 5)) * calData->calNumSamples; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; - iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; - qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; - qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC DC Offset Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = %d\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = %d\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = %d\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = %d\n", i, - qEvenMeasOffset); - - iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / - numSamples) & 0x1ff; - qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / - numSamples) & 0x1ff; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, - iDcMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, - qDcMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xc0000fff; - val |= (qDcMismatch << 12) | (iDcMismatch << 21); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC DC Offset Cal done for Chain %d\n", i); - } - - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); -} - -/* This is done for the currently configured channel */ -bool ath9k_hw_reset_calvalid(struct ath_hw *ah) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - struct hal_cal_list *currCal = ah->cal_list_curr; - - if (!ah->curchan) - return true; - - if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) - return true; - - if (currCal == NULL) - return true; - - if (currCal->calState != CAL_DONE) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Calibration state incorrect, %d\n", - currCal->calState); - return true; - } - - if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) - return true; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Resetting Cal %d state for channel %u\n", - currCal->calData->calType, conf->channel->center_freq); - - ah->curchan->CalValid &= ~currCal->calData->calType; - currCal->calState = CAL_WAITING; - - return false; -} - -void ath9k_hw_start_nfcal(struct ath_hw *ah) -{ - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); -} - -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath9k_nfcal_hist *h; - int i, j; - int32_t val; - const u32 ar5416_cca_regs[6] = { - AR_PHY_CCA, - AR_PHY_CH1_CCA, - AR_PHY_CH2_CCA, - AR_PHY_EXT_CCA, - AR_PHY_CH1_EXT_CCA, - AR_PHY_CH2_EXT_CCA - }; - u8 chainmask; - - if (AR_SREV_9285(ah)) - chainmask = 0x9; - else if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; - - h = ah->nfCalHist; - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (h[i].privNF) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } - - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); - - for (j = 0; j < 1000; j++) { - if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_NF) == 0) - break; - udelay(10); - } - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (-50) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } -} - -int16_t ath9k_hw_getnf(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - int16_t nf, nfThresh; - int16_t nfarray[NUM_NF_READINGS] = { 0 }; - struct ath9k_nfcal_hist *h; - struct ieee80211_channel *c = chan->chan; - - chan->channelFlags &= (~CHANNEL_CW_INT); - if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF did not complete in calibration window\n"); - nf = 0; - chan->rawNoiseFloor = nf; - return chan->rawNoiseFloor; - } else { - ath9k_hw_do_getnf(ah, nfarray); - nf = nfarray[0]; - if (getNoiseFloorThresh(ah, c->band, &nfThresh) - && nf > nfThresh) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "noise floor failed detected; " - "detected %d, threshold %d\n", - nf, nfThresh); - chan->channelFlags |= CHANNEL_CW_INT; - } - } - - h = ah->nfCalHist; - - ath9k_hw_update_nfcal_hist_buffer(h, nfarray); - chan->rawNoiseFloor = h[0].privNF; - - return chan->rawNoiseFloor; -} - -void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) -{ - int i, j; - - for (i = 0; i < NUM_NF_READINGS; i++) { - ah->nfCalHist[i].currIndex = 0; - ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; - ah->nfCalHist[i].invalidNFcount = - AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ah->nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; - } - } -} - -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) -{ - s16 nf; - - if (chan->rawNoiseFloor == 0) - nf = -96; - else - nf = chan->rawNoiseFloor; - - if (!ath9k_hw_nf_in_range(ah, nf)) - nf = ATH_DEFAULT_NOISE_FLOOR; - - return nf; -} - -static void ath9k_olc_temp_compensation(struct ath_hw *ah) -{ - u32 rddata, i; - int delta, currPDADC, regval; - - rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); - - currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); - - if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) - delta = (currPDADC - ah->initPDADC + 4) / 8; - else - delta = (currPDADC - ah->initPDADC + 5) / 10; - - if (delta != ah->PDADCdelta) { - ah->PDADCdelta = delta; - for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { - regval = ah->originalGain[i] - delta; - if (regval < 0) - regval = 0; - - REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, - AR_PHY_TX_GAIN, regval); - } - } -} - -static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) -{ - - u32 regVal; - int i, offset, offs_6_1, offs_0; - u32 ccomp_org, reg_field; - u32 regList[][2] = { - { 0x786c, 0 }, - { 0x7854, 0 }, - { 0x7820, 0 }, - { 0x7824, 0 }, - { 0x7868, 0 }, - { 0x783c, 0 }, - { 0x7838, 0 }, - }; - - if (AR_SREV_9285_11(ah)) { - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); - udelay(10); - } - - for (i = 0; i < ARRAY_SIZE(regList); i++) - regList[i][1] = REG_READ(ah, regList[i][0]); - - regVal = REG_READ(ah, 0x7834); - regVal &= (~(0x1)); - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal |= (0x1 << 27); - REG_WRITE(ah, 0x9808, regVal); - - REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); - REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); - REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); - ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); - - REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); - udelay(30); - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); - - for (i = 6; i > 0; i--) { - regVal = REG_READ(ah, 0x7834); - regVal |= (1 << (19 + i)); - REG_WRITE(ah, 0x7834, regVal); - udelay(1); - regVal = REG_READ(ah, 0x7834); - regVal &= (~(0x1 << (19 + i))); - reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); - regVal |= (reg_field << (19 + i)); - REG_WRITE(ah, 0x7834, regVal); - } - - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); - udelay(1); - reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); - offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); - offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); - - offset = (offs_6_1<<1) | offs_0; - offset = offset - 0; - offs_6_1 = offset>>1; - offs_0 = offset & 1; - - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); - - regVal = REG_READ(ah, 0x7834); - regVal |= 0x1; - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal &= (~(0x1 << 27)); - REG_WRITE(ah, 0x9808, regVal); - - for (i = 0; i < ARRAY_SIZE(regList); i++) - REG_WRITE(ah, regList[i][0], regList[i][1]); - - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); - -} - -bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone) -{ - struct hal_cal_list *currCal = ah->cal_list_curr; - - *isCalDone = true; - - if (currCal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal, - isCalDone); - if (*isCalDone) { - ah->cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - *isCalDone = false; - ath9k_hw_reset_calibration(ah, currCal); - } - } - } - - if (longcal) { - if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) - ath9k_hw_9285_pa_cal(ah); - - if (OLC_FOR_AR9280_20_LATER) - ath9k_olc_temp_compensation(ah); - ath9k_hw_getnf(ah, chan); - ath9k_hw_loadnf(ah, ah->curchan); - ath9k_hw_start_nfcal(ah); - - if (chan->channelFlags & CHANNEL_CW_INT) - chan->channelFlags &= ~CHANNEL_CW_INT; - } - - return true; -} - -static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) -{ - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - if (chan->channelFlags & CHANNEL_HT20) { - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset " - "calibration failed to complete in " - "1ms; noisy ??\n"); - return false; - } - REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - } - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration " - "failed to complete in 1ms; noisy ??\n"); - return false; - } - - REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - - return true; -} - -bool ath9k_hw_init_cal(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { - if (!ar9285_clc(ah, chan)) - return false; - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - - /* Kick off the cal */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_CAL, 0, - AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "offset calibration failed to complete in 1ms; " - "noisy environment?\n"); - return false; - } - - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - } - - /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "offset calibration failed to complete in 1ms; " - "noisy environment?\n"); - return false; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - } - - /* Do PA Calibration */ - if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) - ath9k_hw_9285_pa_cal(ah); - - /* Do NF Calibration */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_NF); - - ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; - - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { - if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { - INIT_CAL(&ah->adcgain_caldata); - INSERT_CAL(ah, &ah->adcgain_caldata); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); - } - if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { - INIT_CAL(&ah->adcdc_caldata); - INSERT_CAL(ah, &ah->adcdc_caldata); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); - } - if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); - } - - ah->cal_list_curr = ah->cal_list; - - if (ah->cal_list_curr) - ath9k_hw_reset_calibration(ah, ah->cal_list_curr); - } - - chan->CalValid = 0; - - return true; -} - -const struct hal_percal_data iq_cal_multi_sample = { - IQ_MISMATCH_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -const struct hal_percal_data iq_cal_single_sample = { - IQ_MISMATCH_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -const struct hal_percal_data adc_gain_cal_multi_sample = { - ADC_GAIN_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -const struct hal_percal_data adc_gain_cal_single_sample = { - ADC_GAIN_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -const struct hal_percal_data adc_dc_cal_multi_sample = { - ADC_DC_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -const struct hal_percal_data adc_dc_cal_single_sample = { - ADC_DC_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -const struct hal_percal_data adc_init_dc_cal = { - ADC_DC_INIT_CAL, - MIN_CAL_SAMPLES, - INIT_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; diff --git a/drivers/net/wireless/ath9k/calib.h b/drivers/net/wireless/ath9k/calib.h deleted file mode 100644 index 1c74bd5..0000000 --- a/drivers/net/wireless/ath9k/calib.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef CALIB_H -#define CALIB_H - -extern const struct hal_percal_data iq_cal_multi_sample; -extern const struct hal_percal_data iq_cal_single_sample; -extern const struct hal_percal_data adc_gain_cal_multi_sample; -extern const struct hal_percal_data adc_gain_cal_single_sample; -extern const struct hal_percal_data adc_dc_cal_multi_sample; -extern const struct hal_percal_data adc_dc_cal_single_sample; -extern const struct hal_percal_data adc_init_dc_cal; - -#define AR_PHY_CCA_MAX_GOOD_VALUE -85 -#define AR_PHY_CCA_MAX_HIGH_VALUE -62 -#define AR_PHY_CCA_MIN_BAD_VALUE -140 -#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 -#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 - -#define NUM_NF_READINGS 6 -#define ATH9K_NF_CAL_HIST_MAX 5 - -struct ar5416IniArray { - u32 *ia_array; - u32 ia_rows; - u32 ia_columns; -}; - -#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ - (iniarray)->ia_array = (u32 *)(array); \ - (iniarray)->ia_rows = (rows); \ - (iniarray)->ia_columns = (columns); \ - } while (0) - -#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; \ - } while (0) - -#define INSERT_CAL(_ahp, _perCal) \ - do { \ - if ((_ahp)->cal_list_last == NULL) { \ - (_ahp)->cal_list = \ - (_ahp)->cal_list_last = (_perCal); \ - ((_ahp)->cal_list_last)->calNext = (_perCal); \ - } else { \ - ((_ahp)->cal_list_last)->calNext = (_perCal); \ - (_ahp)->cal_list_last = (_perCal); \ - (_perCal)->calNext = (_ahp)->cal_list; \ - } \ - } while (0) - -enum hal_cal_types { - ADC_DC_INIT_CAL = 0x1, - ADC_GAIN_CAL = 0x2, - ADC_DC_CAL = 0x4, - IQ_MISMATCH_CAL = 0x8 -}; - -enum hal_cal_state { - CAL_INACTIVE, - CAL_WAITING, - CAL_RUNNING, - CAL_DONE -}; - -#define MIN_CAL_SAMPLES 1 -#define MAX_CAL_SAMPLES 64 -#define INIT_LOG_COUNT 5 -#define PER_MIN_LOG_COUNT 2 -#define PER_MAX_LOG_COUNT 10 - -struct hal_percal_data { - enum hal_cal_types calType; - u32 calNumSamples; - u32 calCountMax; - void (*calCollect) (struct ath_hw *); - void (*calPostProc) (struct ath_hw *, u8); -}; - -struct hal_cal_list { - const struct hal_percal_data *calData; - enum hal_cal_state calState; - struct hal_cal_list *calNext; -}; - -struct ath9k_nfcal_hist { - int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX]; - u8 currIndex; - int16_t privNF; - u8 invalidNFcount; -}; - -bool ath9k_hw_reset_calvalid(struct ath_hw *ah); -void ath9k_hw_start_nfcal(struct ath_hw *ah); -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); -int16_t ath9k_hw_getnf(struct ath_hw *ah, - struct ath9k_channel *chan); -void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah); -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); -bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone); -bool ath9k_hw_init_cal(struct ath_hw *ah, - struct ath9k_channel *chan); - -#endif /* CALIB_H */ diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c deleted file mode 100644 index 97df20c..0000000 --- a/drivers/net/wireless/ath9k/debug.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include "ath9k.h" - -static unsigned int ath9k_debug = DBG_DEFAULT; -module_param_named(debug, ath9k_debug, uint, 0); - -static struct dentry *ath9k_debugfs_root; - -void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) -{ - if (!sc) - return; - - if (sc->debug.debug_mask & dbg_mask) { - va_list args; - - va_start(args, fmt); - printk(KERN_DEBUG "ath9k: "); - vprintk(fmt, args); - va_end(args); - } -} - -static int ath9k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t read_file_dma(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - char buf[1024]; - unsigned int len = 0; - u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; - int i, qcuOffset = 0, dcuOffset = 0; - u32 *qcuBase = &val[0], *dcuBase = &val[4]; - - REG_WRITE(ah, AR_MACMISC, - ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | - (AR_MACMISC_MISC_OBS_BUS_1 << - AR_MACMISC_MISC_OBS_BUS_MSB_S))); - - len += snprintf(buf + len, sizeof(buf) - len, - "Raw DMA Debug values:\n"); - - for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { - if (i % 4 == 0) - len += snprintf(buf + len, sizeof(buf) - len, "\n"); - - val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); - len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", - i, val[i]); - } - - len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); - len += snprintf(buf + len, sizeof(buf) - len, - "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); - - for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { - if (i == 8) { - qcuOffset = 0; - qcuBase++; - } - - if (i == 6) { - dcuOffset = 0; - dcuBase++; - } - - len += snprintf(buf + len, sizeof(buf) - len, - "%2d %2x %1x %2x %2x\n", - i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, - (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), - val[2] & (0x7 << (i * 3)) >> (i * 3), - (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); - } - - len += snprintf(buf + len, sizeof(buf) - len, "\n"); - - len += snprintf(buf + len, sizeof(buf) - len, - "qcu_stitch state: %2x qcu_fetch state: %2x\n", - (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - len += snprintf(buf + len, sizeof(buf) - len, - "qcu_complete state: %2x dcu_complete state: %2x\n", - (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - len += snprintf(buf + len, sizeof(buf) - len, - "dcu_arb state: %2x dcu_fp state: %2x\n", - (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - len += snprintf(buf + len, sizeof(buf) - len, - "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", - (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - len += snprintf(buf + len, sizeof(buf) - len, - "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", - (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - len += snprintf(buf + len, sizeof(buf) - len, - "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", - (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - - len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", - REG_READ(ah, AR_OBS_BUS_1)); - len += snprintf(buf + len, sizeof(buf) - len, - "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_dma = { - .read = read_file_dma, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE -}; - - -void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) -{ - if (status) - sc->debug.stats.istats.total++; - if (status & ATH9K_INT_RX) - sc->debug.stats.istats.rxok++; - if (status & ATH9K_INT_RXEOL) - sc->debug.stats.istats.rxeol++; - if (status & ATH9K_INT_RXORN) - sc->debug.stats.istats.rxorn++; - if (status & ATH9K_INT_TX) - sc->debug.stats.istats.txok++; - if (status & ATH9K_INT_TXURN) - sc->debug.stats.istats.txurn++; - if (status & ATH9K_INT_MIB) - sc->debug.stats.istats.mib++; - if (status & ATH9K_INT_RXPHY) - sc->debug.stats.istats.rxphyerr++; - if (status & ATH9K_INT_RXKCM) - sc->debug.stats.istats.rx_keycache_miss++; - if (status & ATH9K_INT_SWBA) - sc->debug.stats.istats.swba++; - if (status & ATH9K_INT_BMISS) - sc->debug.stats.istats.bmiss++; - if (status & ATH9K_INT_BNR) - sc->debug.stats.istats.bnr++; - if (status & ATH9K_INT_CST) - sc->debug.stats.istats.cst++; - if (status & ATH9K_INT_GTT) - sc->debug.stats.istats.gtt++; - if (status & ATH9K_INT_TIM) - sc->debug.stats.istats.tim++; - if (status & ATH9K_INT_CABEND) - sc->debug.stats.istats.cabend++; - if (status & ATH9K_INT_DTIMSYNC) - sc->debug.stats.istats.dtimsync++; - if (status & ATH9K_INT_DTIM) - sc->debug.stats.istats.dtim++; -} - -static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; - - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_interrupt = { - .read = read_file_interrupt, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE -}; - -static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_tx_info_priv *tx_info_priv = NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - int final_ts_idx, idx; - - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; - idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; - - sc->debug.stats.n_rcstats[idx].success++; -} - -static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_tx_info_priv *tx_info_priv = NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - int final_ts_idx, idx; - - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; - idx = rates[final_ts_idx].idx; - - sc->debug.stats.legacy_rcstats[idx].success++; -} - -void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - if (conf_is_ht(&sc->hw->conf)) - ath_debug_stat_11n_rc(sc, skb); - else - ath_debug_stat_legacy_rc(sc, skb); -} - -/* FIXME: legacy rates, later on .. */ -void ath_debug_stat_retries(struct ath_softc *sc, int rix, - int xretries, int retries, u8 per) -{ - if (conf_is_ht(&sc->hw->conf)) { - int idx = sc->cur_rate_table->info[rix].dot11rate; - - sc->debug.stats.n_rcstats[idx].xretries += xretries; - sc->debug.stats.n_rcstats[idx].retries += retries; - sc->debug.stats.n_rcstats[idx].per = per; - } -} - -static ssize_t ath_read_file_stat_11n_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[1024]; - unsigned int len = 0; - int i = 0; - - len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", - "Retries", "XRetries", "PER"); - - for (i = 0; i <= 15; i++) { - len += snprintf(buf + len, sizeof(buf) - len, - "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, - sc->debug.stats.n_rcstats[i].success, - sc->debug.stats.n_rcstats[i].retries, - sc->debug.stats.n_rcstats[i].xretries, - sc->debug.stats.n_rcstats[i].per); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t ath_read_file_stat_legacy_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; - int i = 0; - - len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); - - for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { - len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", - sc->cur_rate_table->info[i].ratekbps / 1000, - sc->debug.stats.legacy_rcstats[i].success); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - - if (sc->cur_rate_table == NULL) - return 0; - - if (conf_is_ht(&sc->hw->conf)) - return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); - else - return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); -} - -static const struct file_operations fops_rcstat = { - .read = read_file_rcstat, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE -}; - -static const char * ath_wiphy_state_str(enum ath_wiphy_state state) -{ - switch (state) { - case ATH_WIPHY_INACTIVE: - return "INACTIVE"; - case ATH_WIPHY_ACTIVE: - return "ACTIVE"; - case ATH_WIPHY_PAUSING: - return "PAUSING"; - case ATH_WIPHY_PAUSED: - return "PAUSED"; - case ATH_WIPHY_SCAN: - return "SCAN"; - } - return "?"; -} - -static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; - int i; - u8 addr[ETH_ALEN]; - - len += snprintf(buf + len, sizeof(buf) - len, - "primary: %s (%s chan=%d ht=%d)\n", - wiphy_name(sc->pri_wiphy->hw->wiphy), - ath_wiphy_state_str(sc->pri_wiphy->state), - sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - len += snprintf(buf + len, sizeof(buf) - len, - "secondary: %s (%s chan=%d ht=%d)\n", - wiphy_name(aphy->hw->wiphy), - ath_wiphy_state_str(aphy->state), - aphy->chan_idx, aphy->chan_is_ht); - } - - put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); - put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); - len += snprintf(buf + len, sizeof(buf) - len, - "addr: %pM\n", addr); - put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); - put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); - len += snprintf(buf + len, sizeof(buf) - len, - "addrmask: %pM\n", addr); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) -{ - int i; - if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) - return sc->pri_wiphy; - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) - return aphy; - } - return NULL; -} - -static int del_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_del(aphy); -} - -static int pause_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_pause(aphy); -} - -static int unpause_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_unpause(aphy); -} - -static int select_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_select(aphy); -} - -static int schedule_wiphy(struct ath_softc *sc, const char *msec) -{ - ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); - return 0; -} - -static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[50]; - size_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - if (strncmp(buf, "add", 3) == 0) { - int res = ath9k_wiphy_add(sc); - if (res < 0) - return res; - } else if (strncmp(buf, "del=", 4) == 0) { - int res = del_wiphy(sc, buf + 4); - if (res < 0) - return res; - } else if (strncmp(buf, "pause=", 6) == 0) { - int res = pause_wiphy(sc, buf + 6); - if (res < 0) - return res; - } else if (strncmp(buf, "unpause=", 8) == 0) { - int res = unpause_wiphy(sc, buf + 8); - if (res < 0) - return res; - } else if (strncmp(buf, "select=", 7) == 0) { - int res = select_wiphy(sc, buf + 7); - if (res < 0) - return res; - } else if (strncmp(buf, "schedule=", 9) == 0) { - int res = schedule_wiphy(sc, buf + 9); - if (res < 0) - return res; - } else - return -EOPNOTSUPP; - - return count; -} - -static const struct file_operations fops_wiphy = { - .read = read_file_wiphy, - .write = write_file_wiphy, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE -}; - - -int ath9k_init_debug(struct ath_softc *sc) -{ - sc->debug.debug_mask = ath9k_debug; - - if (!ath9k_debugfs_root) - return -ENOENT; - - sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), - ath9k_debugfs_root); - if (!sc->debug.debugfs_phy) - goto err; - - sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, - sc->debug.debugfs_phy, sc, &fops_dma); - if (!sc->debug.debugfs_dma) - goto err; - - sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", - S_IRUGO, - sc->debug.debugfs_phy, - sc, &fops_interrupt); - if (!sc->debug.debugfs_interrupt) - goto err; - - sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", - S_IRUGO, - sc->debug.debugfs_phy, - sc, &fops_rcstat); - if (!sc->debug.debugfs_rcstat) - goto err; - - sc->debug.debugfs_wiphy = debugfs_create_file( - "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, - &fops_wiphy); - if (!sc->debug.debugfs_wiphy) - goto err; - - return 0; -err: - ath9k_exit_debug(sc); - return -ENOMEM; -} - -void ath9k_exit_debug(struct ath_softc *sc) -{ - debugfs_remove(sc->debug.debugfs_wiphy); - debugfs_remove(sc->debug.debugfs_rcstat); - debugfs_remove(sc->debug.debugfs_interrupt); - debugfs_remove(sc->debug.debugfs_dma); - debugfs_remove(sc->debug.debugfs_phy); -} - -int ath9k_debug_create_root(void) -{ - ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!ath9k_debugfs_root) - return -ENOENT; - - return 0; -} - -void ath9k_debug_remove_root(void) -{ - debugfs_remove(ath9k_debugfs_root); - ath9k_debugfs_root = NULL; -} diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath9k/debug.h deleted file mode 100644 index 23298b9..0000000 --- a/drivers/net/wireless/ath9k/debug.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DEBUG_H -#define DEBUG_H - -enum ATH_DEBUG { - ATH_DBG_RESET = 0x00000001, - ATH_DBG_QUEUE = 0x00000002, - ATH_DBG_EEPROM = 0x00000004, - ATH_DBG_CALIBRATE = 0x00000008, - ATH_DBG_INTERRUPT = 0x00000010, - ATH_DBG_REGULATORY = 0x00000020, - ATH_DBG_ANI = 0x00000040, - ATH_DBG_XMIT = 0x00000080, - ATH_DBG_BEACON = 0x00000100, - ATH_DBG_CONFIG = 0x00000200, - ATH_DBG_FATAL = 0x00000400, - ATH_DBG_ANY = 0xffffffff -}; - -#define DBG_DEFAULT (ATH_DBG_FATAL) - -#ifdef CONFIG_ATH9K_DEBUG - -/** - * struct ath_interrupt_stats - Contains statistics about interrupts - * @total: Total no. of interrupts generated so far - * @rxok: RX with no errors - * @rxeol: RX with no more RXDESC available - * @rxorn: RX FIFO overrun - * @txok: TX completed at the requested rate - * @txurn: TX FIFO underrun - * @mib: MIB regs reaching its threshold - * @rxphyerr: RX with phy errors - * @rx_keycache_miss: RX with key cache misses - * @swba: Software Beacon Alert - * @bmiss: Beacon Miss - * @bnr: Beacon Not Ready - * @cst: Carrier Sense TImeout - * @gtt: Global TX Timeout - * @tim: RX beacon TIM occurrence - * @cabend: RX End of CAB traffic - * @dtimsync: DTIM sync lossage - * @dtim: RX Beacon with DTIM - */ -struct ath_interrupt_stats { - u32 total; - u32 rxok; - u32 rxeol; - u32 rxorn; - u32 txok; - u32 txeol; - u32 txurn; - u32 mib; - u32 rxphyerr; - u32 rx_keycache_miss; - u32 swba; - u32 bmiss; - u32 bnr; - u32 cst; - u32 gtt; - u32 tim; - u32 cabend; - u32 dtimsync; - u32 dtim; -}; - -struct ath_legacy_rc_stats { - u32 success; -}; - -struct ath_11n_rc_stats { - u32 success; - u32 retries; - u32 xretries; - u8 per; -}; - -struct ath_stats { - struct ath_interrupt_stats istats; - struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ - struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ -}; - -struct ath9k_debug { - int debug_mask; - struct dentry *debugfs_phy; - struct dentry *debugfs_dma; - struct dentry *debugfs_interrupt; - struct dentry *debugfs_rcstat; - struct dentry *debugfs_wiphy; - struct ath_stats stats; -}; - -void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); -int ath9k_init_debug(struct ath_softc *sc); -void ath9k_exit_debug(struct ath_softc *sc); -int ath9k_debug_create_root(void); -void ath9k_debug_remove_root(void); -void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); -void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); -void ath_debug_stat_retries(struct ath_softc *sc, int rix, - int xretries, int retries, u8 per); - -#else - -static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, - const char *fmt, ...) -{ -} - -static inline int ath9k_init_debug(struct ath_softc *sc) -{ - return 0; -} - -static inline void ath9k_exit_debug(struct ath_softc *sc) -{ -} - -static inline int ath9k_debug_create_root(void) -{ - return 0; -} - -static inline void ath9k_debug_remove_root(void) -{ -} - -static inline void ath_debug_stat_interrupt(struct ath_softc *sc, - enum ath9k_int status) -{ -} - -static inline void ath_debug_stat_rc(struct ath_softc *sc, - struct sk_buff *skb) -{ -} - -static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, - int xretries, int retries, u8 per) -{ -} - -#endif /* CONFIG_ATH9K_DEBUG */ - -#endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c deleted file mode 100644 index 44fee5a..0000000 --- a/drivers/net/wireless/ath9k/eeprom.c +++ /dev/null @@ -1,2813 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, - u32 reg, u32 mask, - u32 shift, u32 val) -{ - u32 regVal; - - regVal = REG_READ(ah, reg) & ~mask; - regVal |= (val << shift) & mask; - - REG_WRITE(ah, reg, regVal); - - if (ah->config.analog_shiftreg) - udelay(100); - - return; -} - -static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) -{ - - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - -static inline int16_t ath9k_hw_interpolate(u16 target, - u16 srcLeft, u16 srcRight, - int16_t targetLeft, - int16_t targetRight) -{ - int16_t rv; - - if (srcRight == srcLeft) { - rv = targetLeft; - } else { - rv = (int16_t) (((target - srcLeft) * targetRight + - (srcRight - target) * targetLeft) / - (srcRight - srcLeft)); - } - return rv; -} - -static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, - u16 listSize, u16 *indexL, - u16 *indexR) -{ - u16 i; - - if (target <= pList[0]) { - *indexL = *indexR = 0; - return true; - } - if (target >= pList[listSize - 1]) { - *indexL = *indexR = (u16) (listSize - 1); - return true; - } - - for (i = 0; i < listSize - 1; i++) { - if (pList[i] == target) { - *indexL = *indexR = i; - return true; - } - if (target < pList[i + 1]) { - *indexL = i; - *indexR = (u16) (i + 1); - return false; - } - } - return false; -} - -static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) -{ - struct ath_softc *sc = ah->ah_sc; - - return sc->bus_ops->eeprom_read(ah, off, data); -} - -static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, - u8 *pVpdList, u16 numIntercepts, - u8 *pRetVpdList) -{ - u16 i, k; - u8 currPwr = pwrMin; - u16 idxL = 0, idxR = 0; - - for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { - ath9k_hw_get_lower_upper_index(currPwr, pPwrList, - numIntercepts, &(idxL), - &(idxR)); - if (idxR < 1) - idxR = 1; - if (idxL == numIntercepts - 1) - idxL = (u16) (numIntercepts - 2); - if (pPwrList[idxL] == pPwrList[idxR]) - k = pVpdList[idxL]; - else - k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + - (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / - (pPwrList[idxR] - pPwrList[idxL])); - pRetVpdList[i] = (u8) k; - currPwr += 2; - } - - return true; -} - -static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, bool isExtTarget) -{ - struct chan_centers centers; - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; - - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) && - (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8)ath9k_hw_interpolate(freq, clo, chi, - powInfo[lowIndex].tPow2x[i], - powInfo[lowIndex + 1].tPow2x[i]); - } - } -} - -static void ath9k_get_txgain_index(struct ath_hw *ah, - struct ath9k_channel *chan, - struct calDataPerFreqOpLoop *rawDatasetOpLoop, - u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) -{ - u8 pcdac, i = 0; - u16 idxL = 0, idxR = 0, numPiers; - bool match; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) - if (calChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), - calChans, numPiers, &idxL, &idxR); - if (match) { - pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; - *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; - } else { - pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; - *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + - rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; - } - - while (pcdac > ah->originalGain[i] && - i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) - i++; - - *pcdacIdx = i; - return; -} - -static void ath9k_olc_get_pdadcs(struct ath_hw *ah, - u32 initTxGain, - int txPower, - u8 *pPDADCValues) -{ - u32 i; - u32 offset; - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, - AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, - AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, - AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); - - offset = txPower; - for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) - if (i < offset) - pPDADCValues[i] = 0x0; - else - pPDADCValues[i] = 0xFF; -} - - - - -static void ath9k_hw_get_target_powers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, bool isHt40Target) -{ - struct chan_centers centers; - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = isHt40Target ? centers.synth_center : centers.ctl_center; - - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) && - (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else - if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, - clo, chi, - powInfo[lowIndex].tPow2x[i], - powInfo[lowIndex + 1].tPow2x[i]); - } - } -} - -static u16 ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz, int num_band_edges) -{ - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - int i; - - for (i = 0; (i < num_band_edges) && - (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { - twiceMaxEdgePower = pRdEdgesPower[i].tPower; - break; - } else if ((i > 0) && - (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, - is2GHz))) { - if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, - is2GHz) < freq && - pRdEdgesPower[i - 1].flag) { - twiceMaxEdgePower = - pRdEdgesPower[i - 1].tPower; - } - break; - } - } - - return twiceMaxEdgePower; -} - -/****************************************/ -/* EEPROM Operations for 4K sized cards */ -/****************************************/ - -static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) -{ - return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); -} - -static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) -{ - return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); -} - -static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) -{ -#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - u16 *eep_data = (u16 *)&ah->eeprom.map4k; - int addr, eep_start_loc = 0; - - eep_start_loc = 64; - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } - - for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); - return false; - } - eep_data++; - } - - return true; -#undef SIZE_EEPROM_4K -} - -static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) -{ -#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - struct ar5416_eeprom_4k *eep = - (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr; - - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Reading Magic # failed\n"); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; - } - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.map4k.baseEepHeader.length); - else - el = ah->eeprom.map4k.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_4k)) - el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - integer = swab32(eep->modalHeader.antCtrlCommon); - eep->modalHeader.antCtrlCommon = integer; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(eep->modalHeader.antCtrlChain[i]); - eep->modalHeader.antCtrlChain[i] = integer; - } - - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(eep->modalHeader.spurChans[i].spurChan); - eep->modalHeader.spurChans[i].spurChan = word; - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -#undef EEPROM_4K_SIZE -} - -static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; - struct base_eep_header_4k *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_2: - return pModal->noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_2: - return pModal->ob_01; - case EEP_DB_2: - return pModal->db1_01; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_FRAC_N_5G: - return 0; - default: - return 0; - } -} - -static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq_4k *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ -#define TMP_VAL_VPD_TABLE \ - ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; -#define PD_GAIN_BOUNDARY_DEFAULT 58; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), bChans, numPiers, - &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t)((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) - pPDADCValues[k++] = vpdTableI[i][ss++]; - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex >= maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) TMP_VAL_VPD_TABLE; - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - - return; -#undef TMP_VAL_VPD_TABLE -} - -static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - struct cal_data_per_freq_4k *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; - u32 reg32, regOffset, regChainOffset; - - xpdMask = pEepData->modalHeader.xpdGain; - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader.pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; - - numXpdGain = 0; - - for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); - - for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - pRawDataset = pEepData->calPierData2G[i]; - - ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, - pRawDataset, pCalBChans, - numPiers, pdGainOverlap_t2, - &tMinCalPower, gainBoundaries, - pdadcValues, numXpdGain); - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16)| - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - - *pTxPowerIndexOffset = 0; - - return true; -} - -static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data_4k *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - scaledPower = max((u16)0, scaledPower); - - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR5416_NUM_CTLS) && - pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | - SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains - (tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), - AR5416_EEP4K_NUM_BAND_EDGES); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = - min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = - min((u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = - min((u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = - min((u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = - min((u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; - ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; - - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; - } - return true; -} - -static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &pEepData->modalHeader; - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } - - if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - - return 0; -} - -static void ath9k_hw_4k_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_4k_header *pModal; - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u8 biaslevel; - - if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) - return; - - if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &eep->modalHeader; - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - INI_RA(&ah->iniAddac, 7, 1) = - (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; - } -} - -static void ath9k_hw_4k_set_gain(struct ath_hw *ah, - struct modal_eep_4k_header *pModal, - struct ar5416_eeprom_4k *eep, - u8 txRxAttenLocal, int regChainOffset) -{ - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[0]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[0]; - - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); - } - - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); -} - -static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_4k_header *pModal; - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u8 txRxAttenLocal; - u8 ob[5], db1[5], db2[5]; - u8 ant_div_control1, ant_div_control2; - u32 regVal; - - pModal = &eep->modalHeader; - txRxAttenLocal = 23; - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - /* Single chain for 4K EEPROM*/ - ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); - - /* Initialize Ant Diversity settings from EEPROM */ - if (pModal->version == 3) { - ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); - ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); - regVal = REG_READ(ah, 0x99ac); - regVal &= (~(0x7f000000)); - regVal |= ((ant_div_control1 & 0x1) << 24); - regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); - regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); - regVal |= ((ant_div_control2 & 0x3) << 25); - regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); - REG_WRITE(ah, 0x99ac, regVal); - regVal = REG_READ(ah, 0x99ac); - regVal = REG_READ(ah, 0xa208); - regVal &= (~(0x1 << 13)); - regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); - REG_WRITE(ah, 0xa208, regVal); - regVal = REG_READ(ah, 0xa208); - } - - if (pModal->version >= 2) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = (pModal->ob_01 >> 4) & 0xf; - ob[2] = (pModal->ob_234 & 0xf); - ob[3] = ((pModal->ob_234 >> 4) & 0xf); - ob[4] = ((pModal->ob_234 >> 8) & 0xf); - - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = ((pModal->db1_01 >> 4) & 0xf); - db1[2] = (pModal->db1_234 & 0xf); - db1[3] = ((pModal->db1_234 >> 4) & 0xf); - db1[4] = ((pModal->db1_234 >> 8) & 0xf); - - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = ((pModal->db2_01 >> 4) & 0xf); - db2[2] = (pModal->db2_234 & 0xf); - db2[3] = ((pModal->db2_234 >> 4) & 0xf); - db2[4] = ((pModal->db2_234 >> 8) & 0xf); - - } else if (pModal->version == 1) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = db1[2] = db1[3] = - db1[4] = ((pModal->db1_01 >> 4) & 0xf); - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = db2[2] = db2[3] = - db2[4] = ((pModal->db2_01 >> 4) & 0xf); - } else { - int i; - for (i = 0; i < 5; i++) { - ob[i] = pModal->ob_01; - db1[i] = pModal->db1_01; - db2[i] = pModal->db1_01; - } - } - - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); - - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); - - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); - - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); - - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); - } - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } -} - -static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - return 1; -} - -static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) -{ -#define EEP_MAP4K_SPURCHAN \ - (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) - - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_MAP4K_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_MAP4K_SPURCHAN -} - -static struct eeprom_ops eep_4k_ops = { - .check_eeprom = ath9k_hw_4k_check_eeprom, - .get_eeprom = ath9k_hw_4k_get_eeprom, - .fill_eeprom = ath9k_hw_4k_fill_eeprom, - .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_4k_set_board_values, - .set_addac = ath9k_hw_4k_set_addac, - .set_txpower = ath9k_hw_4k_set_txpower, - .get_spur_channel = ath9k_hw_4k_get_spur_channel -}; - -/************************************************/ -/* EEPROM Operations for non-4K (Default) cards */ -/************************************************/ - -static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) -{ - return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); -} - -static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) -{ - return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); -} - -static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) -{ -#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) - u16 *eep_data = (u16 *)&ah->eeprom.def; - int addr, ar5416_eep_start_loc = 0x100; - - for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, - eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Unable to read eeprom region\n"); - return false; - } - eep_data++; - } - return true; -#undef SIZE_EEPROM_DEF -} - -static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) -{ - struct ar5416_eeprom_def *eep = - (struct ar5416_eeprom_def *) &ah->eeprom.def; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr, size; - - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); - return false; - } - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - size = sizeof(struct ar5416_eeprom_def); - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < size / sizeof(u16); addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.def.baseEepHeader.length); - else - el = ah->eeprom.def.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_def)) - el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer, j; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing.\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } - - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; - } - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -} - -static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = eep->modalHeader; - struct base_eep_header *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_5: - return pModal[0].noiseFloorThreshCh[0]; - case EEP_NFTHRESH_2: - return pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_5: - return pModal[0].ob; - case EEP_DB_5: - return pModal[0].db; - case EEP_OB_2: - return pModal[1].ob; - case EEP_DB_2: - return pModal[1].db; - case EEP_MINOR_REV: - return AR5416_VER_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_RXGAIN_TYPE: - return pBase->rxGainType; - case EEP_TXGAIN_TYPE: - return pBase->txGainType; - case EEP_OL_PWRCTRL: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - return pBase->openLoopPwrCntl ? true : false; - else - return false; - case EEP_RC_CHAIN_MASK: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - return pBase->rcChainMask; - else - return 0; - case EEP_DAC_HPWR_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) - return pBase->dacHiPwrMode_5G; - else - return 0; - case EEP_FRAC_N_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) - return pBase->frac_n_5g; - else - return 0; - default: - return 0; - } -} - -static void ath9k_hw_def_set_gain(struct ath_hw *ah, - struct modal_eep_header *pModal, - struct ar5416_eeprom_def *eep, - u8 txRxAttenLocal, int regChainOffset, int i) -{ - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[i]; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal->bswMargin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal->bswAtten[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal->xatten2Db[i]); - } else { - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); - } - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); - } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) - | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); - } -} - -static void ath9k_hw_def_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_header *pModal; - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - int i, regChainOffset; - u8 txRxAttenLocal; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_9280(ah)) { - if (i >= 2) - break; - } - - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - else - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) - ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, - regChainOffset, i); - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (IS_CHAN_2GHZ(chan)) { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_OB, - AR_AN_RF2G1_CH0_OB_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_DB, - AR_AN_RF2G1_CH0_DB_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_OB, - AR_AN_RF2G1_CH1_OB_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_DB, - AR_AN_RF2G1_CH1_DB_S, - pModal->db_ch1); - } else { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_OB5, - AR_AN_RF5G1_CH0_OB5_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_DB5, - AR_AN_RF5G1_CH0_DB5_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_OB5, - AR_AN_RF5G1_CH1_OB5_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_DB5, - AR_AN_RF5G1_CH1_DB5_S, - pModal->db_ch1); - } - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_XPABIAS_LVL, - AR_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_LOCALBIAS, - AR_AN_TOP2_LOCALBIAS_S, - pModal->local_bias); - REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, - pModal->force_xpaon); - } - - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); - - if (!AR_SREV_9280_10_OR_LATER(ah)) - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_PGA, - pModal->pgaDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, - AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - } else { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_CCA_THRESH62, - pModal->thresh62); - } - - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); - } - - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } - - if (AR_SREV_9280_20_OR_LATER(ah) && - AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, - AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, - pModal->miscBits); - - - if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { - if (IS_CHAN_2GHZ(chan)) - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, - eep->baseEepHeader.dacLpMode); - else if (eep->baseEepHeader.dacHiPwrMode_5G) - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); - else - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, - eep->baseEepHeader.dacLpMode); - - REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, - pModal->miscBits >> 2); - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, - AR_PHY_TX_DESIRED_SCALE_CCK, - eep->baseEepHeader.desiredScaleCCK); - } -} - -static void ath9k_hw_def_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ -#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) - struct modal_eep_header *pModal; - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - u8 biaslevel; - - if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) - return; - - if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - resetFreqBin = FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)); - freqBin = XPA_LVL_FREQ(0) & 0xff; - biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); - - freqCount++; - - while (freqCount < 3) { - if (XPA_LVL_FREQ(freqCount) == 0x0) - break; - - freqBin = XPA_LVL_FREQ(freqCount) & 0xff; - if (resetFreqBin >= freqBin) - biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); - else - break; - freqCount++; - } - } - - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, - 7, 1) & (~0x18)) | biaslevel << 3; - } else { - INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, - 6, 1) & (~0xc0)) | biaslevel << 6; - } -#undef XPA_LVL_FREQ -} - -static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), - bChans, numPiers, &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t)((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + - (ss - maxIndex + 1) * vpdStep)); - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - - return; -} - -static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ -#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) -#define SM_PDGAIN_B(x, y) \ - SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) - - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } - - if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { - pRawDataset = pEepData->calPierData2G[0]; - ah->initPDADC = ((struct calDataPerFreqOpLoop *) - pRawDataset)->vpdPdg[0][0]; - } - - numXpdGain = 0; - - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; - - - if (OLC_FOR_AR9280_20_LATER) { - u8 pcdacIdx; - u8 txPower; - - ath9k_get_txgain_index(ah, chan, - (struct calDataPerFreqOpLoop *)pRawDataset, - pCalBChans, numPiers, &txPower, &pcdacIdx); - ath9k_olc_get_pdadcs(ah, pcdacIdx, - txPower/2, pdadcValues); - } else { - ath9k_hw_get_def_gain_boundaries_pdadcs(ah, - chan, pRawDataset, - pCalBChans, numPiers, - pdGainOverlap_t2, - &tMinCalPower, - gainBoundaries, - pdadcValues, - numXpdGain); - } - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - if (OLC_FOR_AR9280_20_LATER) { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(0x6, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM_PD_GAIN(1) | SM_PD_GAIN(2) | - SM_PD_GAIN(3) | SM_PD_GAIN(4)); - } else { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| - SM_PDGAIN_B(0, 1) | - SM_PDGAIN_B(1, 2) | - SM_PDGAIN_B(2, 3) | - SM_PDGAIN_B(3, 4)); - } - } - - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16)| - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | PDADC %3d " - "Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d " - "Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - - *pTxPowerIndexOffset = 0; - - return true; -#undef SM_PD_GAIN -#undef SM_PDGAIN_B -} - -static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ - - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8)twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - break; - case 3: - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - break; - } - - scaledPower = max((u16)0, scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } else { - numCtlModes = ARRAY_SIZE(ctlModesFor11a) - - SUB_NUM_CTL_MODES_AT_5G_40; - pCtlMode = ctlModesFor11a; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT20, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11a); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT40, - AR5416_NUM_5G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = min(twiceMaxEdgePower, scaledPower); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { - targetPowerCck.tPow2x[i] = - min((u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { - targetPowerOfdm.tPow2x[i] = - min((u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { - targetPowerHt20.tPow2x[i] = - min((u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - targetPowerHt40.tPow2x[i] = - min((u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - ; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rateExtCck] = - targetPowerCckExt.tPow2x[0]; - } - } - return true; -} - -static int ath9k_hw_def_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ -#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i, cck_ofdm_delta = 0; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } - - if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - if (OLC_FOR_AR9280_20_LATER) { - cck_ofdm_delta = 2; - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) - | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) - | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) - | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) - | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - if (OLC_FOR_AR9280_20_LATER) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - } - - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - - switch(ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; - break; - case 3: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); - break; - } - - return 0; -} - -static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); - struct base_eep_header *pBase = &eep->baseEepHeader; - u8 num_ant_config; - - num_ant_config = 1; - - if (pBase->version >= 0x0E0D) - if (pModal->useAnt1) - num_ant_config += 1; - - return num_ant_config; -} - -static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) -{ -#define EEP_DEF_SPURCHAN \ - (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) - - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_DEF_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_DEF_SPURCHAN -} - -static struct eeprom_ops eep_def_ops = { - .check_eeprom = ath9k_hw_def_check_eeprom, - .get_eeprom = ath9k_hw_def_get_eeprom, - .fill_eeprom = ath9k_hw_def_fill_eeprom, - .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_def_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_def_set_board_values, - .set_addac = ath9k_hw_def_set_addac, - .set_txpower = ath9k_hw_def_set_txpower, - .get_spur_channel = ath9k_hw_def_get_spur_channel -}; - -int ath9k_hw_eeprom_attach(struct ath_hw *ah) -{ - int status; - - if (AR_SREV_9285(ah)) { - ah->eep_map = EEP_MAP_4KBITS; - ah->eep_ops = &eep_4k_ops; - } else { - ah->eep_map = EEP_MAP_DEFAULT; - ah->eep_ops = &eep_def_ops; - } - - if (!ah->eep_ops->fill_eeprom(ah)) - return -EIO; - - status = ah->eep_ops->check_eeprom(ah); - - return status; -} diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath9k/eeprom.h deleted file mode 100644 index 9a7715d..0000000 --- a/drivers/net/wireless/ath9k/eeprom.h +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef EEPROM_H -#define EEPROM_H - -#include - -#define AH_USE_EEPROM 0x1 - -#ifdef __BIG_ENDIAN -#define AR5416_EEPROM_MAGIC 0x5aa5 -#else -#define AR5416_EEPROM_MAGIC 0xa55a -#endif - -#define CTRY_DEBUG 0x1ff -#define CTRY_DEFAULT 0 - -#define AR_EEPROM_EEPCAP_COMPRESS_DIS 0x0001 -#define AR_EEPROM_EEPCAP_AES_DIS 0x0002 -#define AR_EEPROM_EEPCAP_FASTFRAME_DIS 0x0004 -#define AR_EEPROM_EEPCAP_BURST_DIS 0x0008 -#define AR_EEPROM_EEPCAP_MAXQCU 0x01F0 -#define AR_EEPROM_EEPCAP_MAXQCU_S 4 -#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN 0x0200 -#define AR_EEPROM_EEPCAP_KC_ENTRIES 0xF000 -#define AR_EEPROM_EEPCAP_KC_ENTRIES_S 12 - -#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040 -#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 -#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100 -#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 -#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 -#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800 - -#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000 -#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000 - -#define AR5416_EEPROM_MAGIC_OFFSET 0x0 -#define AR5416_EEPROM_S 2 -#define AR5416_EEPROM_OFFSET 0x2000 -#define AR5416_EEPROM_MAX 0xae0 - -#define AR5416_EEPROM_START_ADDR \ - (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 - -#define SD_NO_CTL 0xE0 -#define NO_CTL 0xff -#define CTL_MODE_M 7 -#define CTL_11A 0 -#define CTL_11B 1 -#define CTL_11G 2 -#define CTL_2GHT20 5 -#define CTL_5GHT20 6 -#define CTL_2GHT40 7 -#define CTL_5GHT40 8 - -#define EXT_ADDITIVE (0x8000) -#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) -#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) -#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) - -#define SUB_NUM_CTL_MODES_AT_5G_40 2 -#define SUB_NUM_CTL_MODES_AT_2G_40 3 - -#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ - -/* - * For AR9285 and later chipsets, the following bits are not being programmed - * in EEPROM and so need to be enabled always. - * - * Bit 0: en_fcc_mid - * Bit 1: en_jap_mid - * Bit 2: en_fcc_dfs_ht40 - * Bit 3: en_jap_ht40 - * Bit 4: en_jap_dfs_ht40 - */ -#define AR9285_RDEXT_DEFAULT 0x1F - -#define AR_EEPROM_MAC(i) (0x1d+(i)) -#define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) -#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) -#define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) - -#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) -#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ - ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) - -#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c -#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 -#define AR_EEPROM_RFSILENT_POLARITY 0x0002 -#define AR_EEPROM_RFSILENT_POLARITY_S 1 - -#define EEP_RFSILENT_ENABLED 0x0001 -#define EEP_RFSILENT_ENABLED_S 0 -#define EEP_RFSILENT_POLARITY 0x0002 -#define EEP_RFSILENT_POLARITY_S 1 -#define EEP_RFSILENT_GPIO_SEL 0x001c -#define EEP_RFSILENT_GPIO_SEL_S 2 - -#define AR5416_OPFLAGS_11A 0x01 -#define AR5416_OPFLAGS_11G 0x02 -#define AR5416_OPFLAGS_N_5G_HT40 0x04 -#define AR5416_OPFLAGS_N_2G_HT40 0x08 -#define AR5416_OPFLAGS_N_5G_HT20 0x10 -#define AR5416_OPFLAGS_N_2G_HT20 0x20 - -#define AR5416_EEP_NO_BACK_VER 0x1 -#define AR5416_EEP_VER 0xE -#define AR5416_EEP_VER_MINOR_MASK 0x0FFF -#define AR5416_EEP_MINOR_VER_2 0x2 -#define AR5416_EEP_MINOR_VER_3 0x3 -#define AR5416_EEP_MINOR_VER_7 0x7 -#define AR5416_EEP_MINOR_VER_9 0x9 -#define AR5416_EEP_MINOR_VER_16 0x10 -#define AR5416_EEP_MINOR_VER_17 0x11 -#define AR5416_EEP_MINOR_VER_19 0x13 -#define AR5416_EEP_MINOR_VER_20 0x14 -#define AR5416_EEP_MINOR_VER_22 0x16 - -#define AR5416_NUM_5G_CAL_PIERS 8 -#define AR5416_NUM_2G_CAL_PIERS 4 -#define AR5416_NUM_5G_20_TARGET_POWERS 8 -#define AR5416_NUM_5G_40_TARGET_POWERS 8 -#define AR5416_NUM_2G_CCK_TARGET_POWERS 3 -#define AR5416_NUM_2G_20_TARGET_POWERS 4 -#define AR5416_NUM_2G_40_TARGET_POWERS 4 -#define AR5416_NUM_CTLS 24 -#define AR5416_NUM_BAND_EDGES 8 -#define AR5416_NUM_PD_GAINS 4 -#define AR5416_PD_GAINS_IN_MASK 4 -#define AR5416_PD_GAIN_ICEPTS 5 -#define AR5416_EEPROM_MODAL_SPURS 5 -#define AR5416_MAX_RATE_POWER 63 -#define AR5416_NUM_PDADC_VALUES 128 -#define AR5416_BCHAN_UNUSED 0xFF -#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 -#define AR5416_MAX_CHAINS 3 -#define AR5416_PWR_TABLE_OFFSET -5 - -/* Rx gain type values */ -#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 -#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1 -#define AR5416_EEP_RXGAIN_ORIG 2 - -/* Tx gain type values */ -#define AR5416_EEP_TXGAIN_ORIGINAL 0 -#define AR5416_EEP_TXGAIN_HIGH_POWER 1 - -#define AR5416_EEP4K_START_LOC 64 -#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 -#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 -#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3 -#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3 -#define AR5416_EEP4K_NUM_CTLS 12 -#define AR5416_EEP4K_NUM_BAND_EDGES 4 -#define AR5416_EEP4K_NUM_PD_GAINS 2 -#define AR5416_EEP4K_PD_GAINS_IN_MASK 4 -#define AR5416_EEP4K_PD_GAIN_ICEPTS 5 -#define AR5416_EEP4K_MAX_CHAINS 1 - -#define AR9280_TX_GAIN_TABLE_SIZE 22 - -enum eeprom_param { - EEP_NFTHRESH_5, - EEP_NFTHRESH_2, - EEP_MAC_MSW, - EEP_MAC_MID, - EEP_MAC_LSW, - EEP_REG_0, - EEP_REG_1, - EEP_OP_CAP, - EEP_OP_MODE, - EEP_RF_SILENT, - EEP_OB_5, - EEP_DB_5, - EEP_OB_2, - EEP_DB_2, - EEP_MINOR_REV, - EEP_TX_MASK, - EEP_RX_MASK, - EEP_RXGAIN_TYPE, - EEP_TXGAIN_TYPE, - EEP_OL_PWRCTRL, - EEP_RC_CHAIN_MASK, - EEP_DAC_HPWR_5G, - EEP_FRAC_N_5G -}; - -enum ar5416_rates { - rate6mb, rate9mb, rate12mb, rate18mb, - rate24mb, rate36mb, rate48mb, rate54mb, - rate1l, rate2l, rate2s, rate5_5l, - rate5_5s, rate11l, rate11s, rateXr, - rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3, - rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7, - rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3, - rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7, - rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm, - Ar5416RateSize -}; - -enum ath9k_hal_freq_band { - ATH9K_HAL_FREQ_BAND_5GHZ = 0, - ATH9K_HAL_FREQ_BAND_2GHZ = 1 -}; - -struct base_eep_header { - u16 length; - u16 checksum; - u16 version; - u8 opCapFlags; - u8 eepMisc; - u16 regDmn[2]; - u8 macAddr[6]; - u8 rxMask; - u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; - u8 deviceType; - u8 pwdclkind; - u8 futureBase_1[2]; - u8 rxGainType; - u8 dacHiPwrMode_5G; - u8 openLoopPwrCntl; - u8 dacLpMode; - u8 txGainType; - u8 rcChainMask; - u8 desiredScaleCCK; - u8 power_table_offset; - u8 frac_n_5g; - u8 futureBase_3[21]; -} __packed; - -struct base_eep_header_4k { - u16 length; - u16 checksum; - u16 version; - u8 opCapFlags; - u8 eepMisc; - u16 regDmn[2]; - u8 macAddr[6]; - u8 rxMask; - u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; - u8 deviceType; - u8 txGainType; -} __packed; - - -struct spur_chan { - u16 spurChan; - u8 spurRangeLow; - u8 spurRangeHigh; -} __packed; - -struct modal_eep_header { - u32 antCtrlChain[AR5416_MAX_CHAINS]; - u32 antCtrlCommon; - u8 antennaGainCh[AR5416_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_MAX_CHAINS]; - u8 adcDesiredSize; - u8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - u8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - u8 iqCalICh[AR5416_MAX_CHAINS]; - u8 iqCalQCh[AR5416_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob; - u8 db; - u8 xpaBiasLvl; - u8 pwrDecreaseFor2Chain; - u8 pwrDecreaseFor3Chain; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_MAX_CHAINS]; - u8 bswMargin[AR5416_MAX_CHAINS]; - u8 swSettleHt40; - u8 xatten2Db[AR5416_MAX_CHAINS]; - u8 xatten2Margin[AR5416_MAX_CHAINS]; - u8 ob_ch1; - u8 db_ch1; - u8 useAnt1:1, - force_xpaon:1, - local_bias:1, - femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1; - u8 miscBits; - u16 xpaBiasLvlFreq[3]; - u8 futureModal[6]; - - struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; -} __packed; - -struct calDataPerFreqOpLoop { - u8 pwrPdg[2][5]; - u8 vpdPdg[2][5]; - u8 pcdac[2][5]; - u8 empty[2][5]; -} __packed; - -struct modal_eep_4k_header { - u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; - u32 antCtrlCommon; - u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; - u8 adcDesiredSize; - u8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; - u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob_01; - u8 db1_01; - u8 xpaBiasLvl; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; - u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; - u8 swSettleHt40; - u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; - u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; - u8 db2_01; - u8 version; - u16 ob_234; - u16 db1_234; - u16 db2_234; - u8 futureModal[4]; - - struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; -} __packed; - - -struct cal_data_per_freq { - u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; - u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; -} __packed; - -struct cal_data_per_freq_4k { - u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; - u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; -} __packed; - -struct cal_target_power_leg { - u8 bChannel; - u8 tPow2x[4]; -} __packed; - -struct cal_target_power_ht { - u8 bChannel; - u8 tPow2x[8]; -} __packed; - - -#ifdef __BIG_ENDIAN_BITFIELD -struct cal_ctl_edges { - u8 bChannel; - u8 flag:2, tPower:6; -} __packed; -#else -struct cal_ctl_edges { - u8 bChannel; - u8 tPower:6, flag:2; -} __packed; -#endif - -struct cal_ctl_data { - struct cal_ctl_edges - ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; -} __packed; - -struct cal_ctl_data_4k { - struct cal_ctl_edges - ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; -} __packed; - -struct ar5416_eeprom_def { - struct base_eep_header baseEepHeader; - u8 custData[64]; - struct modal_eep_header modalHeader[2]; - u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS]; - u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS]; - struct cal_data_per_freq - calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS]; - struct cal_data_per_freq - calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; - struct cal_target_power_leg - calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS]; - struct cal_target_power_leg - calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS]; - struct cal_target_power_leg - calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS]; - u8 ctlIndex[AR5416_NUM_CTLS]; - struct cal_ctl_data ctlData[AR5416_NUM_CTLS]; - u8 padding; -} __packed; - -struct ar5416_eeprom_4k { - struct base_eep_header_4k baseEepHeader; - u8 custData[20]; - struct modal_eep_4k_header modalHeader; - u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS]; - struct cal_data_per_freq_4k - calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS]; - struct cal_target_power_leg - calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS]; - struct cal_target_power_leg - calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS]; - u8 ctlIndex[AR5416_EEP4K_NUM_CTLS]; - struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS]; - u8 padding; -} __packed; - -enum reg_ext_bitmap { - REG_EXT_JAPAN_MIDBAND = 1, - REG_EXT_FCC_DFS_HT40 = 2, - REG_EXT_JAPAN_NONDFS_HT40 = 3, - REG_EXT_JAPAN_DFS_HT40 = 4 -}; - -struct ath9k_country_entry { - u16 countryCode; - u16 regDmnEnum; - u16 regDmn5G; - u16 regDmn2G; - u8 isMultidomain; - u8 iso[3]; -}; - -enum ath9k_eep_map { - EEP_MAP_DEFAULT = 0x0, - EEP_MAP_4KBITS, - EEP_MAP_MAX -}; - -struct eeprom_ops { - int (*check_eeprom)(struct ath_hw *hw); - u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param); - bool (*fill_eeprom)(struct ath_hw *hw); - int (*get_eeprom_ver)(struct ath_hw *hw); - int (*get_eeprom_rev)(struct ath_hw *hw); - u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band); - u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw, - struct ath9k_channel *chan); - void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); - void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); - int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, - u16 cfgCtl, u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, u8 powerLimit); - u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); -}; - -#define ar5416_get_ntxchains(_txchainmask) \ - (((_txchainmask >> 2) & 1) + \ - ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) - -int ath9k_hw_eeprom_attach(struct ath_hw *ah); - -#endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c deleted file mode 100644 index 24299e6..0000000 --- a/drivers/net/wireless/ath9k/hw.c +++ /dev/null @@ -1,3861 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include - -#include "ath9k.h" -#include "initvals.h" - -static int btcoex_enable; -module_param(btcoex_enable, bool, 0); -MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support"); - -#define ATH9K_CLOCK_RATE_CCK 22 -#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 -#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 - -static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); -static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode); -static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value); -static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); -static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); - -/********************/ -/* Helper Functions */ -/********************/ - -static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - - if (!ah->curchan) /* should really check for CCK instead */ - return clks / ATH9K_CLOCK_RATE_CCK; - if (conf->channel->band == IEEE80211_BAND_2GHZ) - return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM; - - return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM; -} - -static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - - if (conf_is_ht40(conf)) - return ath9k_hw_mac_usec(ah, clks) / 2; - else - return ath9k_hw_mac_usec(ah, clks); -} - -static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - - if (!ah->curchan) /* should really check for CCK instead */ - return usecs *ATH9K_CLOCK_RATE_CCK; - if (conf->channel->band == IEEE80211_BAND_2GHZ) - return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM; - return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM; -} - -static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) -{ - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - - if (conf_is_ht40(conf)) - return ath9k_hw_mac_clks(ah, usecs) * 2; - else - return ath9k_hw_mac_clks(ah, usecs); -} - -bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) -{ - int i; - - BUG_ON(timeout < AH_TIME_QUANTUM); - - for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) { - if ((REG_READ(ah, reg) & mask) == val) - return true; - - udelay(AH_TIME_QUANTUM); - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", - timeout, reg, REG_READ(ah, reg), mask, val); - - return false; -} - -u32 ath9k_hw_reverse_bits(u32 val, u32 n) -{ - u32 retval; - int i; - - for (i = 0, retval = 0; i < n; i++) { - retval = (retval << 1) | (val & 1); - val >>= 1; - } - return retval; -} - -bool ath9k_get_channel_edges(struct ath_hw *ah, - u16 flags, u16 *low, - u16 *high) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - - if (flags & CHANNEL_5GHZ) { - *low = pCap->low_5ghz_chan; - *high = pCap->high_5ghz_chan; - return true; - } - if ((flags & CHANNEL_2GHZ)) { - *low = pCap->low_2ghz_chan; - *high = pCap->high_2ghz_chan; - return true; - } - return false; -} - -u16 ath9k_hw_computetxtime(struct ath_hw *ah, - struct ath_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble) -{ - u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; - u32 kbps; - - kbps = rates->info[rateix].ratekbps; - - if (kbps == 0) - return 0; - - switch (rates->info[rateix].phy) { - case WLAN_RC_PHY_CCK: - phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; - if (shortPreamble && rates->info[rateix].short_preamble) - phyTime >>= 1; - numBits = frameLen << 3; - txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); - break; - case WLAN_RC_PHY_OFDM: - if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_QUARTER - + OFDM_PREAMBLE_TIME_QUARTER - + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); - } else if (ah->curchan && - IS_CHAN_HALF_RATE(ah->curchan)) { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_HALF + - OFDM_PREAMBLE_TIME_HALF - + (numSymbols * OFDM_SYMBOL_TIME_HALF); - } else { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME - + (numSymbols * OFDM_SYMBOL_TIME); - } - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Unknown phy %u (rate ix %u)\n", - rates->info[rateix].phy, rateix); - txTime = 0; - break; - } - - return txTime; -} - -void ath9k_hw_get_channel_centers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct chan_centers *centers) -{ - int8_t extoff; - - if (!IS_CHAN_HT40(chan)) { - centers->ctl_center = centers->ext_center = - centers->synth_center = chan->channel; - return; - } - - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) { - centers->synth_center = - chan->channel + HT40_CHANNEL_CENTER_SHIFT; - extoff = 1; - } else { - centers->synth_center = - chan->channel - HT40_CHANNEL_CENTER_SHIFT; - extoff = -1; - } - - centers->ctl_center = - centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); - centers->ext_center = - centers->synth_center + (extoff * - ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? - HT40_CHANNEL_CENTER_SHIFT : 15)); -} - -/******************/ -/* Chip Revisions */ -/******************/ - -static void ath9k_hw_read_revisions(struct ath_hw *ah) -{ - u32 val; - - val = REG_READ(ah, AR_SREV) & AR_SREV_ID; - - if (val == 0xFF) { - val = REG_READ(ah, AR_SREV); - ah->hw_version.macVersion = - (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; - ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); - ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; - } else { - if (!AR_SREV_9100(ah)) - ah->hw_version.macVersion = MS(val, AR_SREV_VERSION); - - ah->hw_version.macRev = val & AR_SREV_REVISION; - - if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) - ah->is_pciexpress = true; - } -} - -static int ath9k_hw_get_radiorev(struct ath_hw *ah) -{ - u32 val; - int i; - - REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - - for (i = 0; i < 8; i++) - REG_WRITE(ah, AR_PHY(0x20), 0x00010000); - val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; - val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - - return ath9k_hw_reverse_bits(val, 8); -} - -/************************************/ -/* HW Attach, Detach, Init Routines */ -/************************************/ - -static void ath9k_hw_disablepcie(struct ath_hw *ah) -{ - if (AR_SREV_9100(ah)) - return; - - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); - REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); - - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); -} - -static bool ath9k_hw_chip_test(struct ath_hw *ah) -{ - u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; - u32 regHold[2]; - u32 patternData[4] = { 0x55555555, - 0xaaaaaaaa, - 0x66666666, - 0x99999999 }; - int i, j; - - for (i = 0; i < 2; i++) { - u32 addr = regAddr[i]; - u32 wrData, rdData; - - regHold[i] = REG_READ(ah, addr); - for (j = 0; j < 0x100; j++) { - wrData = (j << 16) | j; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (rdData != wrData) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - addr, wrData, rdData); - return false; - } - } - for (j = 0; j < 4; j++) { - wrData = patternData[j]; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (wrData != rdData) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - addr, wrData, rdData); - return false; - } - } - REG_WRITE(ah, regAddr[i], regHold[i]); - } - udelay(100); - - return true; -} - -static const char *ath9k_hw_devname(u16 devid) -{ - switch (devid) { - case AR5416_DEVID_PCI: - return "Atheros 5416"; - case AR5416_DEVID_PCIE: - return "Atheros 5418"; - case AR9160_DEVID_PCI: - return "Atheros 9160"; - case AR5416_AR9100_DEVID: - return "Atheros 9100"; - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - return "Atheros 9280"; - case AR9285_DEVID_PCIE: - return "Atheros 9285"; - } - - return NULL; -} - -static void ath9k_hw_set_defaults(struct ath_hw *ah) -{ - int i; - - ah->config.dma_beacon_response_time = 2; - ah->config.sw_beacon_response_time = 10; - ah->config.additional_swba_backoff = 0; - ah->config.ack_6mb = 0x0; - ah->config.cwm_ignore_extcca = 0; - ah->config.pcie_powersave_enable = 0; - ah->config.pcie_clock_req = 0; - ah->config.pcie_waen = 0; - ah->config.analog_shiftreg = 1; - ah->config.ht_enable = 1; - ah->config.ofdm_trig_low = 200; - ah->config.ofdm_trig_high = 500; - ah->config.cck_trig_high = 200; - ah->config.cck_trig_low = 100; - ah->config.enable_ani = 1; - ah->config.diversity_control = 0; - ah->config.antenna_switch_swap = 0; - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - ah->config.spurchans[i][0] = AR_NO_SPUR; - ah->config.spurchans[i][1] = AR_NO_SPUR; - } - - ah->config.intr_mitigation = true; - - /* - * We need this for PCI devices only (Cardbus, PCI, miniPCI) - * _and_ if on non-uniprocessor systems (Multiprocessor/HT). - * This means we use it for all AR5416 devices, and the few - * minor PCI AR9280 devices out there. - * - * Serialization is required because these devices do not handle - * well the case of two concurrent reads/writes due to the latency - * involved. During one read/write another read/write can be issued - * on another CPU while the previous read/write may still be working - * on our hardware, if we hit this case the hardware poops in a loop. - * We prevent this by serializing reads and writes. - * - * This issue is not present on PCI-Express devices or pre-AR5416 - * devices (legacy, 802.11abg). - */ - if (num_possible_cpus() > 1) - ah->config.serialize_regmode = SER_REG_MODE_AUTO; -} - -static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, - int *status) -{ - struct ath_hw *ah; - - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); - if (ah == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "Cannot allocate memory for state block\n"); - *status = -ENOMEM; - return NULL; - } - - ah->ah_sc = sc; - ah->hw_version.magic = AR5416_MAGIC; - ah->regulatory.country_code = CTRY_DEFAULT; - ah->hw_version.devid = devid; - ah->hw_version.subvendorid = 0; - - ah->ah_flags = 0; - if ((devid == AR5416_AR9100_DEVID)) - ah->hw_version.macVersion = AR_SREV_VERSION_9100; - if (!AR_SREV_9100(ah)) - ah->ah_flags = AH_USE_EEPROM; - - ah->regulatory.power_limit = MAX_RATE_POWER; - ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; - ah->atim_window = 0; - ah->diversity_control = ah->config.diversity_control; - ah->antenna_switch_swap = - ah->config.antenna_switch_swap; - ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; - ah->beacon_interval = 100; - ah->enable_32kHz_clock = DONT_USE_32KHZ; - ah->slottime = (u32) -1; - ah->acktimeout = (u32) -1; - ah->ctstimeout = (u32) -1; - ah->globaltxtimeout = (u32) -1; - - ah->gbeacon_rate = 0; - - return ah; -} - -static int ath9k_hw_rfattach(struct ath_hw *ah) -{ - bool rfStatus = false; - int ecode = 0; - - rfStatus = ath9k_hw_init_rf(ah, &ecode); - if (!rfStatus) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "RF setup failed, status: %u\n", ecode); - return ecode; - } - - return 0; -} - -static int ath9k_hw_rf_claim(struct ath_hw *ah) -{ - u32 val; - - REG_WRITE(ah, AR_PHY(0), 0x00000007); - - val = ath9k_hw_get_radiorev(ah); - switch (val & AR_RADIO_SREV_MAJOR) { - case 0: - val = AR_RAD5133_SREV_MAJOR; - break; - case AR_RAD5133_SREV_MAJOR: - case AR_RAD5122_SREV_MAJOR: - case AR_RAD2133_SREV_MAJOR: - case AR_RAD2122_SREV_MAJOR: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Radio Chip Rev 0x%02X not supported\n", - val & AR_RADIO_SREV_MAJOR); - return -EOPNOTSUPP; - } - - ah->hw_version.analog5GhzRev = val; - - return 0; -} - -static int ath9k_hw_init_macaddr(struct ath_hw *ah) -{ - u32 sum; - int i; - u16 eeval; - - sum = 0; - for (i = 0; i < 3; i++) { - eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i)); - sum += eeval; - ah->macaddr[2 * i] = eeval >> 8; - ah->macaddr[2 * i + 1] = eeval & 0xff; - } - if (sum == 0 || sum == 0xffff * 3) - return -EADDRNOTAVAIL; - - return 0; -} - -static void ath9k_hw_init_rxgain_ini(struct ath_hw *ah) -{ - u32 rxgain_type; - - if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { - rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE); - - if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_backoff_13db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); - else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_backoff_23db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); - else - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); - } else { - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); - } -} - -static void ath9k_hw_init_txgain_ini(struct ath_hw *ah) -{ - u32 txgain_type; - - if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { - txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); - - if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_high_power_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); - } else { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); - } -} - -static int ath9k_hw_post_attach(struct ath_hw *ah) -{ - int ecode; - - if (!ath9k_hw_chip_test(ah)) - return -ENODEV; - - ecode = ath9k_hw_rf_claim(ah); - if (ecode != 0) - return ecode; - - ecode = ath9k_hw_eeprom_attach(ah); - if (ecode != 0) - return ecode; - - DPRINTF(ah->ah_sc, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n", - ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); - - ecode = ath9k_hw_rfattach(ah); - if (ecode != 0) - return ecode; - - if (!AR_SREV_9100(ah)) { - ath9k_hw_ani_setup(ah); - ath9k_hw_ani_attach(ah); - } - - return 0; -} - -static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, - int *status) -{ - struct ath_hw *ah; - int ecode; - u32 i, j; - - ah = ath9k_hw_newstate(devid, sc, status); - if (ah == NULL) - return NULL; - - ath9k_hw_set_defaults(ah); - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); - ecode = -EIO; - goto bad; - } - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); - ecode = -EIO; - goto bad; - } - - if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || - (AR_SREV_9280(ah) && !ah->is_pciexpress)) { - ah->config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - - DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n", - ah->config.serialize_regmode); - - if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && - (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { - DPRINTF(sc, ATH_DBG_FATAL, - "Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", ah->hw_version.macVersion, - ah->hw_version.macRev); - ecode = -EOPNOTSUPP; - goto bad; - } - - if (AR_SREV_9100(ah)) { - ah->iq_caldata.calData = &iq_cal_multi_sample; - ah->supp_cals = IQ_MISMATCH_CAL; - ah->is_pciexpress = false; - } - ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - - if (AR_SREV_9160_10_OR_LATER(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) { - ah->iq_caldata.calData = &iq_cal_single_sample; - ah->adcgain_caldata.calData = - &adc_gain_cal_single_sample; - ah->adcdc_caldata.calData = - &adc_dc_cal_single_sample; - ah->adcdc_calinitdata.calData = - &adc_init_dc_cal; - } else { - ah->iq_caldata.calData = &iq_cal_multi_sample; - ah->adcgain_caldata.calData = - &adc_gain_cal_multi_sample; - ah->adcdc_caldata.calData = - &adc_dc_cal_multi_sample; - ah->adcdc_calinitdata.calData = - &adc_init_dc_cal; - } - ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; - } - - ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - - if (AR_SREV_9285_12_OR_LATER(ah)) { - - INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, - ARRAY_SIZE(ar9285Modes_9285_1_2), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, - ARRAY_SIZE(ar9285Common_9285_1_2), 2); - - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_off_L1_9285_1_2, - ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_always_on_L1_9285_1_2, - ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), - 2); - } - } else if (AR_SREV_9285_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285, - ARRAY_SIZE(ar9285Modes_9285), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285, - ARRAY_SIZE(ar9285Common_9285), 2); - - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_off_L1_9285, - ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_always_on_L1_9285, - ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); - } - } else if (AR_SREV_9280_20_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, - ARRAY_SIZE(ar9280Modes_9280_2), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, - ARRAY_SIZE(ar9280Common_9280_2), 2); - - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); - } - INIT_INI_ARRAY(&ah->iniModesAdditional, - ar9280Modes_fast_clock_9280_2, - ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280, - ARRAY_SIZE(ar9280Modes_9280), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280, - ARRAY_SIZE(ar9280Common_9280), 2); - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160, - ARRAY_SIZE(ar5416Modes_9160), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, - ARRAY_SIZE(ar5416Common_9160), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, - ARRAY_SIZE(ar5416Bank0_9160), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160, - ARRAY_SIZE(ar5416BB_RfGain_9160), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160, - ARRAY_SIZE(ar5416Bank1_9160), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160, - ARRAY_SIZE(ar5416Bank2_9160), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160, - ARRAY_SIZE(ar5416Bank3_9160), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160, - ARRAY_SIZE(ar5416Bank6_9160), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160, - ARRAY_SIZE(ar5416Bank6TPC_9160), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160, - ARRAY_SIZE(ar5416Bank7_9160), 2); - if (AR_SREV_9160_11(ah)) { - INIT_INI_ARRAY(&ah->iniAddac, - ar5416Addac_91601_1, - ARRAY_SIZE(ar5416Addac_91601_1), 2); - } else { - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160, - ARRAY_SIZE(ar5416Addac_9160), 2); - } - } else if (AR_SREV_9100_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100, - ARRAY_SIZE(ar5416Modes_9100), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, - ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, - ARRAY_SIZE(ar5416Bank0_9100), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100, - ARRAY_SIZE(ar5416BB_RfGain_9100), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100, - ARRAY_SIZE(ar5416Bank1_9100), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100, - ARRAY_SIZE(ar5416Bank2_9100), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100, - ARRAY_SIZE(ar5416Bank3_9100), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, - ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100, - ARRAY_SIZE(ar5416Bank7_9100), 2); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, - ARRAY_SIZE(ar5416Addac_9100), 2); - } else { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes, - ARRAY_SIZE(ar5416Modes), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, - ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, - ARRAY_SIZE(ar5416Bank0), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, - ARRAY_SIZE(ar5416BB_RfGain), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, - ARRAY_SIZE(ar5416Bank1), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, - ARRAY_SIZE(ar5416Bank2), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, - ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, - ARRAY_SIZE(ar5416Bank7), 2); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); - } - - if (ah->is_pciexpress) - ath9k_hw_configpcipowersave(ah, 0); - else - ath9k_hw_disablepcie(ah); - - ecode = ath9k_hw_post_attach(ah); - if (ecode != 0) - goto bad; - - if (AR_SREV_9285_12_OR_LATER(ah)) { - u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); - - /* txgain table */ - if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_high_power_tx_gain_9285_1_2, - ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6); - } else { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_original_tx_gain_9285_1_2, - ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6); - } - - } - - /* rxgain table */ - if (AR_SREV_9280_20(ah)) - ath9k_hw_init_rxgain_ini(ah); - - /* txgain table */ - if (AR_SREV_9280_20(ah)) - ath9k_hw_init_txgain_ini(ah); - - ath9k_hw_fill_cap_info(ah); - - if ((ah->hw_version.devid == AR9280_DEVID_PCI) && - test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { - - /* EEPROM Fixup */ - for (i = 0; i < ah->iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ah->iniModes, i, 0); - - for (j = 1; j < ah->iniModes.ia_columns; j++) { - u32 val = INI_RA(&ah->iniModes, i, j); - - INI_RA(&ah->iniModes, i, j) = - ath9k_hw_ini_fixup(ah, - &ah->eeprom.def, - reg, val); - } - } - } - - ecode = ath9k_hw_init_macaddr(ah); - if (ecode != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to initialize MAC address\n"); - goto bad; - } - - if (AR_SREV_9285(ah)) - ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); - else - ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); - - ath9k_init_nfcal_hist_buffer(ah); - - return ah; -bad: - if (ah) - ath9k_hw_detach(ah); - if (status) - *status = ecode; - - return NULL; -} - -static void ath9k_hw_init_bb(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - u32 synthDelay; - - synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - - udelay(synthDelay + BASE_ACTIVATE_DELAY); -} - -static void ath9k_hw_init_qos(struct ath_hw *ah) -{ - REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); - REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); - - REG_WRITE(ah, AR_QOS_NO_ACK, - SM(2, AR_QOS_NO_ACK_TWO_BIT) | - SM(5, AR_QOS_NO_ACK_BIT_OFF) | - SM(0, AR_QOS_NO_ACK_BYTE_OFF)); - - REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); - REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); -} - -static void ath9k_hw_init_pll(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - u32 pll; - - if (AR_SREV_9100(ah)) { - if (chan && IS_CHAN_5GHZ(chan)) - pll = 0x1450; - else - pll = 0x1458; - } else { - if (AR_SREV_9280_10_OR_LATER(ah)) { - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) { - pll |= SM(0x28, AR_RTC_9160_PLL_DIV); - - - if (AR_SREV_9280_20(ah)) { - if (((chan->channel % 20) == 0) - || ((chan->channel % 10) == 0)) - pll = 0x2850; - else - pll = 0x142c; - } - } else { - pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); - } - - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0x50, AR_RTC_9160_PLL_DIV); - else - pll |= SM(0x58, AR_RTC_9160_PLL_DIV); - } else { - pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0xa, AR_RTC_PLL_DIV); - else - pll |= SM(0xb, AR_RTC_PLL_DIV); - } - } - REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); - - udelay(RTC_PLL_SETTLE_DELAY); - - REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); -} - -static void ath9k_hw_init_chain_masks(struct ath_hw *ah) -{ - int rx_chainmask, tx_chainmask; - - rx_chainmask = ah->rxchainmask; - tx_chainmask = ah->txchainmask; - - switch (rx_chainmask) { - case 0x5: - REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, - AR_PHY_SWAP_ALT_CHAIN); - case 0x3: - if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) { - REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); - REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); - break; - } - case 0x1: - case 0x2: - case 0x7: - REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); - REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); - break; - default: - break; - } - - REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); - if (tx_chainmask == 0x5) { - REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, - AR_PHY_SWAP_ALT_CHAIN); - } - if (AR_SREV_9100(ah)) - REG_WRITE(ah, AR_PHY_ANALOG_SWAP, - REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); -} - -static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, - enum nl80211_iftype opmode) -{ - ah->mask_reg = AR_IMR_TXERR | - AR_IMR_TXURN | - AR_IMR_RXERR | - AR_IMR_RXORN | - AR_IMR_BCNMISC; - - if (ah->config.intr_mitigation) - ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; - else - ah->mask_reg |= AR_IMR_RXOK; - - ah->mask_reg |= AR_IMR_TXOK; - - if (opmode == NL80211_IFTYPE_AP) - ah->mask_reg |= AR_IMR_MIB; - - REG_WRITE(ah, AR_IMR, ah->mask_reg); - REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); - - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); - } -} - -static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) -{ - if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); - ah->acktimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_TIME_OUT, - AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); - ah->acktimeout = us; - return true; - } -} - -static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) -{ - if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); - ah->ctstimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_TIME_OUT, - AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); - ah->ctstimeout = us; - return true; - } -} - -static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) -{ - if (tu > 0xFFFF) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "bad global tx timeout %u\n", tu); - ah->globaltxtimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); - ah->globaltxtimeout = tu; - return true; - } -} - -static void ath9k_hw_init_user_settings(struct ath_hw *ah) -{ - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n", - ah->misc_mode); - - if (ah->misc_mode != 0) - REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); - if (ah->slottime != (u32) -1) - ath9k_hw_setslottime(ah, ah->slottime); - if (ah->acktimeout != (u32) -1) - ath9k_hw_set_ack_timeout(ah, ah->acktimeout); - if (ah->ctstimeout != (u32) -1) - ath9k_hw_set_cts_timeout(ah, ah->ctstimeout); - if (ah->globaltxtimeout != (u32) -1) - ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); -} - -const char *ath9k_hw_probe(u16 vendorid, u16 devid) -{ - return vendorid == ATHEROS_VENDOR_ID ? - ath9k_hw_devname(devid) : NULL; -} - -void ath9k_hw_detach(struct ath_hw *ah) -{ - if (!AR_SREV_9100(ah)) - ath9k_hw_ani_detach(ah); - - ath9k_hw_rfdetach(ah); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); - kfree(ah); -} - -struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) -{ - struct ath_hw *ah = NULL; - - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - case AR5416_AR9100_DEVID: - case AR9160_DEVID_PCI: - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - case AR9285_DEVID_PCIE: - ah = ath9k_hw_do_attach(devid, sc, error); - break; - default: - *error = -ENXIO; - break; - } - - return ah; -} - -/*******/ -/* INI */ -/*******/ - -static void ath9k_hw_override_ini(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - /* - * Set the RX_ABORT and RX_DIS and clear if off only after - * RXE is set for MAC. This prevents frames with corrupted - * descriptor status. - */ - REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - - - if (!AR_SREV_5416_20_OR_LATER(ah) || - AR_SREV_9280_10_OR_LATER(ah)) - return; - - REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); -} - -static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value) -{ - struct base_eep_header *pBase = &(pEepData->baseEepHeader); - - switch (ah->hw_version.devid) { - case AR9280_DEVID_PCI: - if (reg == 0x7894) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ini VAL: %x EEPROM: %x\n", value, - (pBase->version & 0xff)); - - if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PWDCLKIND: %d\n", - pBase->pwdclkind); - value &= ~AR_AN_TOP2_PWDCLKIND; - value |= AR_AN_TOP2_PWDCLKIND & - (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); - } else { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PWDCLKIND Earlier Rev\n"); - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "final ini VAL: %x\n", value); - } - break; - } - - return value; -} - -static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value) -{ - if (ah->eep_map == EEP_MAP_4KBITS) - return value; - else - return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); -} - -static void ath9k_olc_init(struct ath_hw *ah) -{ - u32 i; - - for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) - ah->originalGain[i] = - MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), - AR_PHY_TX_GAIN); - ah->PDADCdelta = 0; -} - -static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, - struct ath9k_channel *chan) -{ - u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band); - - if (IS_CHAN_B(chan)) - ctl |= CTL_11B; - else if (IS_CHAN_G(chan)) - ctl |= CTL_11G; - else - ctl |= CTL_11A; - - return ctl; -} - -static int ath9k_hw_process_ini(struct ath_hw *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) -{ - int i, regWrites = 0; - struct ieee80211_channel *channel = chan->chan; - u32 modesIndex, freqIndex; - int status; - - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - modesIndex = 1; - freqIndex = 1; - break; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - modesIndex = 2; - freqIndex = 1; - break; - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - modesIndex = 4; - freqIndex = 2; - break; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - modesIndex = 3; - freqIndex = 2; - break; - - default: - return -EINVAL; - } - - REG_WRITE(ah, AR_PHY(0), 0x00000007); - REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); - ah->eep_ops->set_addac(ah, chan); - - if (AR_SREV_5416_22_OR_LATER(ah)) { - REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); - } else { - struct ar5416IniArray temp; - u32 addacSize = - sizeof(u32) * ah->iniAddac.ia_rows * - ah->iniAddac.ia_columns; - - memcpy(ah->addac5416_21, - ah->iniAddac.ia_array, addacSize); - - (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; - - temp.ia_array = ah->addac5416_21; - temp.ia_columns = ah->iniAddac.ia_columns; - temp.ia_rows = ah->iniAddac.ia_rows; - REG_WRITE_ARRAY(&temp, 1, regWrites); - } - - REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); - - for (i = 0; i < ah->iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ah->iniModes, i, 0); - u32 val = INI_RA(&ah->iniModes, i, modesIndex); - - REG_WRITE(ah, reg, val); - - if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { - udelay(100); - } - - DO_DELAY(regWrites); - } - - if (AR_SREV_9280(ah)) - REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); - - if (AR_SREV_9280(ah) || (AR_SREV_9285(ah) && - AR_SREV_9285_12_OR_LATER(ah))) - REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); - - for (i = 0; i < ah->iniCommon.ia_rows; i++) { - u32 reg = INI_RA(&ah->iniCommon, i, 0); - u32 val = INI_RA(&ah->iniCommon, i, 1); - - REG_WRITE(ah, reg, val); - - if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { - udelay(100); - } - - DO_DELAY(regWrites); - } - - ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites); - - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { - REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, - regWrites); - } - - ath9k_hw_override_ini(ah, chan); - ath9k_hw_set_regs(ah, chan, macmode); - ath9k_hw_init_chain_masks(ah); - - if (OLC_FOR_AR9280_20_LATER) - ath9k_olc_init(ah); - - status = ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); - if (status != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Error initializing transmit power\n"); - return -EIO; - } - - if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "ar5416SetRfRegs failed\n"); - return -EIO; - } - - return 0; -} - -/****************************************/ -/* Reset and Channel Switching Routines */ -/****************************************/ - -static void ath9k_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan) -{ - u32 rfMode = 0; - - if (chan == NULL) - return; - - rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) - ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; - - if (!AR_SREV_9280_10_OR_LATER(ah)) - rfMode |= (IS_CHAN_5GHZ(chan)) ? - AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; - - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) - rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - - REG_WRITE(ah, AR_PHY_MODE, rfMode); -} - -static void ath9k_hw_mark_phy_inactive(struct ath_hw *ah) -{ - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); -} - -static inline void ath9k_hw_set_dma(struct ath_hw *ah) -{ - u32 regval; - - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); - - regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); - - REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level); - - regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); - - REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); - - if (AR_SREV_9285(ah)) { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); - } else { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_PCU_TXBUF_CTRL_USABLE_SIZE); - } -} - -static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) -{ - u32 val; - - val = REG_READ(ah, AR_STA_ID1); - val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); - switch (opmode) { - case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP - | AR_STA_ID1_KSRCH_MODE); - REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC - | AR_STA_ID1_KSRCH_MODE); - REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_MONITOR: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); - break; - } -} - -static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, - u32 coef_scaled, - u32 *coef_mantissa, - u32 *coef_exponent) -{ - u32 coef_exp, coef_man; - - for (coef_exp = 31; coef_exp > 0; coef_exp--) - if ((coef_scaled >> coef_exp) & 0x1) - break; - - coef_exp = 14 - (coef_exp - COEF_SCALE_S); - - coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); - - *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); - *coef_exponent = coef_exp - 16; -} - -static void ath9k_hw_set_delta_slope(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - u32 coef_scaled, ds_coef_exp, ds_coef_man; - u32 clockMhzScaled = 0x64000000; - struct chan_centers centers; - - if (IS_CHAN_HALF_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 1; - else if (IS_CHAN_QUARTER_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 2; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - coef_scaled = clockMhzScaled / centers.synth_center; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); - - coef_scaled = (9 * coef_scaled) / 10; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); -} - -static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) -{ - u32 rst_flags; - u32 tmpReg; - - if (AR_SREV_9100(ah)) { - u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); - val &= ~AR_RTC_DERIVED_CLK_PERIOD; - val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); - REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); - (void)REG_READ(ah, AR_RTC_DERIVED_CLK); - } - - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); - - if (AR_SREV_9100(ah)) { - rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | - AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; - } else { - tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); - if (tmpReg & - (AR_INTR_SYNC_LOCAL_TIMEOUT | - AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - } else { - REG_WRITE(ah, AR_RC, AR_RC_AHB); - } - - rst_flags = AR_RTC_RC_MAC_WARM; - if (type == ATH9K_RESET_COLD) - rst_flags |= AR_RTC_RC_MAC_COLD; - } - - REG_WRITE(ah, AR_RTC_RC, rst_flags); - udelay(50); - - REG_WRITE(ah, AR_RTC_RC, 0); - if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "RTC stuck in MAC reset\n"); - return false; - } - - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, 0); - - ath9k_hw_init_pll(ah, NULL); - - if (AR_SREV_9100(ah)) - udelay(50); - - return true; -} - -static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) -{ - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); - - REG_WRITE(ah, AR_RTC_RESET, 0); - udelay(2); - REG_WRITE(ah, AR_RTC_RESET, 1); - - if (!ath9k_hw_wait(ah, - AR_RTC_STATUS, - AR_RTC_STATUS_M, - AR_RTC_STATUS_ON, - AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); - return false; - } - - ath9k_hw_read_revisions(ah); - - return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); -} - -static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) -{ - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); - - switch (type) { - case ATH9K_RESET_POWER_ON: - return ath9k_hw_set_reset_power_on(ah); - break; - case ATH9K_RESET_WARM: - case ATH9K_RESET_COLD: - return ath9k_hw_set_reset(ah, type); - break; - default: - return false; - } -} - -static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) -{ - u32 phymode; - u32 enableDacFifo = 0; - - if (AR_SREV_9285_10_OR_LATER(ah)) - enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & - AR_PHY_FC_ENABLE_DAC_FIFO); - - phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 - | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; - - if (IS_CHAN_HT40(chan)) { - phymode |= AR_PHY_FC_DYN2040_EN; - - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) - phymode |= AR_PHY_FC_DYN2040_PRI_CH; - - if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25) - phymode |= AR_PHY_FC_DYN2040_EXT_CH; - } - REG_WRITE(ah, AR_PHY_TURBO, phymode); - - ath9k_hw_set11nmac2040(ah, macmode); - - REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); - REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); -} - -static bool ath9k_hw_chip_reset(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - if (OLC_FOR_AR9280_20_LATER) { - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) - return false; - } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) - return false; - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; - - ah->chip_fullsleep = false; - ath9k_hw_init_pll(ah, chan); - ath9k_hw_set_rfmode(ah, chan); - - return true; -} - -static bool ath9k_hw_channel_change(struct ath_hw *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) -{ - struct ieee80211_channel *channel = chan->chan; - u32 synthDelay, qnum; - - for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { - if (ath9k_hw_numtxpending(ah, qnum)) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "Transmit frames pending on queue %d\n", qnum); - return false; - } - } - - REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); - if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, - AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Could not kill baseband RX\n"); - return false; - } - - ath9k_hw_set_regs(ah, chan, macmode); - - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Failed to set channel\n"); - return false; - } - } else { - if (!(ath9k_hw_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Failed to set channel\n"); - return false; - } - } - - if (ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)) != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Error initializing transmit power\n"); - return false; - } - - synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - - udelay(synthDelay + BASE_ACTIVATE_DELAY); - - REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); - - if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) - ath9k_hw_set_delta_slope(ah, chan); - - if (AR_SREV_9280_10_OR_LATER(ah)) - ath9k_hw_9280_spur_mitigate(ah, chan); - else - ath9k_hw_spur_mitigate(ah, chan); - - if (!chan->oneTimeCalsDone) - chan->oneTimeCalsDone = true; - - return true; -} - -static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int freq; - int bin, cur_bin; - int bb_spur_off, spur_subchannel_sd; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, newVal; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - struct chan_centers centers; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - ah->config.spurmode = SPUR_ENABLE_EEPROM; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - - if (is2GHz) - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; - else - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; - - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - freq; - - if (IS_CHAN_HT40(chan)) { - if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { - bb_spur = cur_bb_spur; - break; - } - } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - return; - } else { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - } - - bin = bb_spur * 320; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - - newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); - - newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); - - if (IS_CHAN_HT40(chan)) { - if (bb_spur < 0) { - spur_subchannel_sd = 1; - bb_spur_off = bb_spur + 10; - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur - 10; - } - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur; - } - - if (IS_CHAN_HT40(chan)) - spur_delta_phase = - ((bb_spur * 262144) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - else - spur_delta_phase = - ((bb_spur * 524288) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; - spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; - - newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, newVal); - - newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; - REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, new; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, - bool bChannelChange) -{ - u32 saveLedState; - struct ath_softc *sc = ah->ah_sc; - struct ath9k_channel *curchan = ah->curchan; - u32 saveDefAntenna; - u32 macStaId1; - int i, rx_chainmask, r; - - ah->extprotspacing = sc->ht_extprotspacing; - ah->txchainmask = sc->tx_chainmask; - ah->rxchainmask = sc->rx_chainmask; - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return -EIO; - - if (curchan) - ath9k_hw_getnf(ah, curchan); - - if (bChannelChange && - (ah->chip_fullsleep != true) && - (ah->curchan != NULL) && - (chan->channel != ah->curchan->channel) && - ((chan->channelFlags & CHANNEL_ALL) == - (ah->curchan->channelFlags & CHANNEL_ALL)) && - (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) && - !IS_CHAN_A_5MHZ_SPACED(ah->curchan)))) { - - if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) { - ath9k_hw_loadnf(ah, ah->curchan); - ath9k_hw_start_nfcal(ah); - return 0; - } - } - - saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA); - if (saveDefAntenna == 0) - saveDefAntenna = 1; - - macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; - - saveLedState = REG_READ(ah, AR_CFG_LED) & - (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | - AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW); - - ath9k_hw_mark_phy_inactive(ah); - - if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n"); - return -EINVAL; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); - - r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width); - if (r) - return r; - - /* Setup MFP options for CCMP */ - if (AR_SREV_9280_20_OR_LATER(ah)) { - /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt - * frames when constructing CCMP AAD. */ - REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, - 0xc7ff); - ah->sw_mgmt_crypto = false; - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - /* Disable hardware crypto for management frames */ - REG_CLR_BIT(ah, AR_PCU_MISC_MODE2, - AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); - REG_SET_BIT(ah, AR_PCU_MISC_MODE2, - AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); - ah->sw_mgmt_crypto = true; - } else - ah->sw_mgmt_crypto = true; - - if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) - ath9k_hw_set_delta_slope(ah, chan); - - if (AR_SREV_9280_10_OR_LATER(ah)) - ath9k_hw_9280_spur_mitigate(ah, chan); - else - ath9k_hw_spur_mitigate(ah, chan); - - ah->eep_ops->set_board_values(ah, chan); - - ath9k_hw_decrease_chain_power(ah, chan); - - REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr)); - REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4) - | macStaId1 - | AR_STA_ID1_RTS_USE_DEF - | (ah->config. - ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) - | ah->sta_id1_defaults); - ath9k_hw_set_operating_mode(ah, ah->opmode); - - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); - - REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); - - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | - ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); - - REG_WRITE(ah, AR_ISR, ~0); - - 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))) - return -EIO; - } else { - if (!(ath9k_hw_set_channel(ah, chan))) - return -EIO; - } - - for (i = 0; i < AR_NUM_DCU; i++) - REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); - - ah->intr_txqs = 0; - for (i = 0; i < ah->caps.total_queues; i++) - ath9k_hw_resettxqueue(ah, i); - - ath9k_hw_init_interrupt_masks(ah, ah->opmode); - ath9k_hw_init_qos(ah); - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - ath9k_enable_rfkill(ah); -#endif - ath9k_hw_init_user_settings(ah); - - REG_WRITE(ah, AR_STA_ID1, - REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); - - ath9k_hw_set_dma(ah); - - REG_WRITE(ah, AR_OBS, 8); - - if (ah->config.intr_mitigation) { - REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); - REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); - } - - ath9k_hw_init_bb(ah, chan); - - if (!ath9k_hw_init_cal(ah, chan)) - return -EIO;; - - rx_chainmask = ah->rxchainmask; - if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { - REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); - REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); - } - - REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ); - - if (AR_SREV_9100(ah)) { - u32 mask; - mask = REG_READ(ah, AR_CFG); - if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "CFG Byte Swap Set 0x%x\n", mask); - } else { - mask = - INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; - REG_WRITE(ah, AR_CFG, mask); - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); - } - } else { -#ifdef __BIG_ENDIAN - REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); -#endif - } - - return 0; -} - -/************************/ -/* Key Cache Management */ -/************************/ - -bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) -{ - u32 keyType; - - if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "keychache entry %u out of range\n", entry); - return false; - } - - keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - - } - - if (ah->curchan == NULL) - return true; - - return true; -} - -bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) -{ - u32 macHi, macLo; - - if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "keychache entry %u out of range\n", entry); - return false; - } - - if (mac != NULL) { - macHi = (mac[5] << 8) | mac[4]; - macLo = (mac[3] << 24) | - (mac[2] << 16) | - (mac[1] << 8) | - mac[0]; - macLo >>= 1; - macLo |= (macHi & 1) << 31; - macHi >>= 1; - } else { - macLo = macHi = 0; - } - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - - return true; -} - -bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, - const struct ath9k_keyval *k, - const u8 *mac) -{ - const struct ath9k_hw_capabilities *pCap = &ah->caps; - u32 key0, key1, key2, key3, key4; - u32 keyType; - - if (entry >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "keycache entry %u out of range\n", entry); - return false; - } - - switch (k->kv_type) { - case ATH9K_CIPHER_AES_OCB: - keyType = AR_KEYTABLE_TYPE_AES; - break; - case ATH9K_CIPHER_AES_CCM: - if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "AES-CCM not supported by mac rev 0x%x\n", - ah->hw_version.macRev); - return false; - } - keyType = AR_KEYTABLE_TYPE_CCM; - break; - case ATH9K_CIPHER_TKIP: - keyType = AR_KEYTABLE_TYPE_TKIP; - if (ATH9K_IS_MIC_ENABLED(ah) - && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "entry %u inappropriate for TKIP\n", entry); - return false; - } - break; - case ATH9K_CIPHER_WEP: - if (k->kv_len < LEN_WEP40) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "WEP key length %u too small\n", k->kv_len); - return false; - } - if (k->kv_len <= LEN_WEP40) - keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= LEN_WEP104) - keyType = AR_KEYTABLE_TYPE_104; - else - keyType = AR_KEYTABLE_TYPE_128; - break; - case ATH9K_CIPHER_CLR: - keyType = AR_KEYTABLE_TYPE_CLR; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "cipher %u not supported\n", k->kv_type); - return false; - } - - key0 = get_unaligned_le32(k->kv_val + 0); - key1 = get_unaligned_le16(k->kv_val + 4); - key2 = get_unaligned_le32(k->kv_val + 6); - key3 = get_unaligned_le16(k->kv_val + 10); - key4 = get_unaligned_le32(k->kv_val + 12); - if (k->kv_len <= LEN_WEP104) - key4 &= 0xff; - - /* - * Note: Key cache registers access special memory area that requires - * two 32-bit writes to actually update the values in the internal - * memory. Consequently, the exact order and pairs used here must be - * maintained. - */ - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - /* - * Write inverted key[47:0] first to avoid Michael MIC errors - * on frames that could be sent or received at the same time. - * The correct key will be written in the end once everything - * else is ready. - */ - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); - - /* Write key[95:48] */ - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - - /* Write key[127:96] and key type */ - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - - /* Write MAC address for the entry */ - (void) ath9k_hw_keysetmac(ah, entry, mac); - - if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) { - /* - * TKIP uses two key cache entries: - * Michael MIC TX/RX keys in the same key cache entry - * (idx = main index + 64): - * key0 [31:0] = RX key [31:0] - * key1 [15:0] = TX key [31:16] - * key1 [31:16] = reserved - * key2 [31:0] = RX key [63:32] - * key3 [15:0] = TX key [15:0] - * key3 [31:16] = reserved - * key4 [31:0] = TX key [63:32] - */ - u32 mic0, mic1, mic2, mic3, mic4; - - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; - mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; - mic4 = get_unaligned_le32(k->kv_txmic + 4); - - /* Write RX[31:0] and TX[31:16] */ - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); - - /* Write RX[63:32] and TX[15:0] */ - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); - - /* Write TX[63:32] and keyType(reserved) */ - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); - - } else { - /* - * TKIP uses four key cache entries (two for group - * keys): - * Michael MIC TX/RX keys are in different key cache - * entries (idx = main index + 64 for TX and - * main index + 32 + 96 for RX): - * key0 [31:0] = TX/RX MIC key [31:0] - * key1 [31:0] = reserved - * key2 [31:0] = TX/RX MIC key [63:32] - * key3 [31:0] = reserved - * key4 [31:0] = reserved - * - * Upper layer code will call this function separately - * for TX and RX keys when these registers offsets are - * used. - */ - u32 mic0, mic2; - - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - - /* Write MIC key[31:0] */ - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - - /* Write MIC key[63:32] */ - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - - /* Write TX[63:32] and keyType(reserved) */ - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); - } - - /* MAC address registers are reserved for the MIC entry */ - REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); - - /* - * Write the correct (un-inverted) key[47:0] last to enable - * TKIP now that all other registers are set with correct - * values. - */ - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - } else { - /* Write key[47:0] */ - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - - /* Write key[95:48] */ - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - - /* Write key[127:96] and key type */ - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - - /* Write MAC address for the entry */ - (void) ath9k_hw_keysetmac(ah, entry, mac); - } - - return true; -} - -bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry) -{ - if (entry < ah->caps.keycache_size) { - u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); - if (val & AR_KEYTABLE_VALID) - return true; - } - return false; -} - -/******************************/ -/* Power Management (Chipset) */ -/******************************/ - -static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - - REG_CLR_BIT(ah, (AR_RTC_RESET), - AR_RTC_RESET_EN); - } -} - -static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - struct ath9k_hw_capabilities *pCap = &ah->caps; - - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_ON_INT); - } else { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - } -} - -static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) -{ - u32 val; - int i; - - if (setChip) { - if ((REG_READ(ah, AR_RTC_STATUS) & - AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { - if (ath9k_hw_set_reset_reg(ah, - ATH9K_RESET_POWER_ON) != true) { - return false; - } - } - if (AR_SREV_9100(ah)) - REG_SET_BIT(ah, AR_RTC_RESET, - AR_RTC_RESET_EN); - - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - udelay(50); - - for (i = POWER_UP_TIME / 50; i > 0; i--) { - val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; - if (val == AR_RTC_STATUS_ON) - break; - udelay(50); - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); - return false; - } - } - - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - - return true; -} - -bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) -{ - int status = true, setChip = true; - static const char *modes[] = { - "AWAKE", - "FULL-SLEEP", - "NETWORK SLEEP", - "UNDEFINED" - }; - - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", - modes[ah->power_mode], modes[mode]); - - switch (mode) { - case ATH9K_PM_AWAKE: - status = ath9k_hw_set_power_awake(ah, setChip); - break; - case ATH9K_PM_FULL_SLEEP: - ath9k_set_power_sleep(ah, setChip); - ah->chip_fullsleep = true; - break; - case ATH9K_PM_NETWORK_SLEEP: - ath9k_set_power_network_sleep(ah, setChip); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Unknown power mode %u\n", mode); - return false; - } - ah->power_mode = mode; - - return status; -} - -/* - * Helper for ASPM support. - * - * Disable PLL when in L0s as well as receiver clock when in L1. - * This power saving option must be enabled through the SerDes. - * - * Programming the SerDes must go through the same 288 bit serial shift - * register as the other analog registers. Hence the 9 writes. - */ -void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) -{ - u8 i; - - if (ah->is_pciexpress != true) - return; - - /* Do not touch SerDes registers */ - if (ah->config.pcie_powersave_enable == 2) - return; - - /* Nothing to do on restore for 11N */ - if (restore) - return; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - /* - * AR9280 2.0 or later chips use SerDes values from the - * initvals.h initialized depending on chipset during - * ath9k_hw_do_attach() - */ - for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { - REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), - INI_RA(&ah->iniPcieSerdes, i, 1)); - } - } else if (AR_SREV_9280(ah) && - (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - - /* RX shut off when elecidle is asserted */ - REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); - REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); - - /* Shut off CLKREQ active in L1 */ - if (ah->config.pcie_clock_req) - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); - else - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); - - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); - - /* Load the new settings */ - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - - } else { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - - /* RX shut off when elecidle is asserted */ - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); - REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); - - /* - * Ignore ah->ah_config.pcie_clock_req setting for - * pre-AR9280 11n - */ - REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); - - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); - - /* Load the new settings */ - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - } - - udelay(1000); - - /* set bit 19 to allow forcing of pcie core into L1 state */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - - /* Several PCIe massages to ensure proper behaviour */ - if (ah->config.pcie_waen) { - REG_WRITE(ah, AR_WA, ah->config.pcie_waen); - } else { - if (AR_SREV_9285(ah)) - REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); - /* - * On AR9280 chips bit 22 of 0x4004 needs to be set to - * otherwise card may disappear. - */ - else if (AR_SREV_9280(ah)) - REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT); - else - REG_WRITE(ah, AR_WA, AR_WA_DEFAULT); - } -} - -/**********************/ -/* Interrupt Handling */ -/**********************/ - -bool ath9k_hw_intrpend(struct ath_hw *ah) -{ - u32 host_isr; - - if (AR_SREV_9100(ah)) - return true; - - host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); - if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS)) - return true; - - host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); - if ((host_isr & AR_INTR_SYNC_DEFAULT) - && (host_isr != AR_INTR_SPURIOUS)) - return true; - - return false; -} - -bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) -{ - u32 isr = 0; - u32 mask2 = 0; - struct ath9k_hw_capabilities *pCap = &ah->caps; - u32 sync_cause = 0; - bool fatal_int = false; - - if (!AR_SREV_9100(ah)) { - if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { - if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) - == AR_RTC_STATUS_ON) { - isr = REG_READ(ah, AR_ISR); - } - } - - sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & - AR_INTR_SYNC_DEFAULT; - - *masked = 0; - - if (!isr && !sync_cause) - return false; - } else { - *masked = 0; - isr = REG_READ(ah, AR_ISR); - } - - if (isr) { - if (isr & AR_ISR_BCNMISC) { - u32 isr2; - isr2 = REG_READ(ah, AR_ISR_S2); - if (isr2 & AR_ISR_S2_TIM) - mask2 |= ATH9K_INT_TIM; - if (isr2 & AR_ISR_S2_DTIM) - mask2 |= ATH9K_INT_DTIM; - if (isr2 & AR_ISR_S2_DTIMSYNC) - mask2 |= ATH9K_INT_DTIMSYNC; - if (isr2 & (AR_ISR_S2_CABEND)) - mask2 |= ATH9K_INT_CABEND; - if (isr2 & AR_ISR_S2_GTT) - mask2 |= ATH9K_INT_GTT; - if (isr2 & AR_ISR_S2_CST) - mask2 |= ATH9K_INT_CST; - if (isr2 & AR_ISR_S2_TSFOOR) - mask2 |= ATH9K_INT_TSFOOR; - } - - isr = REG_READ(ah, AR_ISR_RAC); - if (isr == 0xffffffff) { - *masked = 0; - return false; - } - - *masked = isr & ATH9K_INT_COMMON; - - if (ah->config.intr_mitigation) { - if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) - *masked |= ATH9K_INT_RX; - } - - if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) - *masked |= ATH9K_INT_RX; - if (isr & - (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | - AR_ISR_TXEOL)) { - u32 s0_s, s1_s; - - *masked |= ATH9K_INT_TX; - - s0_s = REG_READ(ah, AR_ISR_S0_S); - ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); - ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); - - s1_s = REG_READ(ah, AR_ISR_S1_S); - ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); - ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); - } - - if (isr & AR_ISR_RXORN) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "receive FIFO overrun interrupt\n"); - } - - if (!AR_SREV_9100(ah)) { - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - u32 isr5 = REG_READ(ah, AR_ISR_S5_S); - if (isr5 & AR_ISR_S5_TIM_TIMER) - *masked |= ATH9K_INT_TIM_TIMER; - } - } - - *masked |= mask2; - } - - if (AR_SREV_9100(ah)) - return true; - - if (sync_cause) { - fatal_int = - (sync_cause & - (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) - ? true : false; - - if (fatal_int) { - if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "received PCI FATAL interrupt\n"); - } - if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "received PCI PERR interrupt\n"); - } - } - if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); - REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); - REG_WRITE(ah, AR_RC, 0); - *masked |= ATH9K_INT_FATAL; - } - if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); - } - - REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); - (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); - } - - return true; -} - -enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah) -{ - return ah->mask_reg; -} - -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) -{ - u32 omask = ah->mask_reg; - u32 mask, mask2; - struct ath9k_hw_capabilities *pCap = &ah->caps; - - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); - - if (omask & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n"); - REG_WRITE(ah, AR_IER, AR_IER_DISABLE); - (void) REG_READ(ah, AR_IER); - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); - - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); - } - } - - mask = ints & ATH9K_INT_COMMON; - mask2 = 0; - - if (ints & ATH9K_INT_TX) { - if (ah->txok_interrupt_mask) - mask |= AR_IMR_TXOK; - if (ah->txdesc_interrupt_mask) - mask |= AR_IMR_TXDESC; - if (ah->txerr_interrupt_mask) - mask |= AR_IMR_TXERR; - if (ah->txeol_interrupt_mask) - mask |= AR_IMR_TXEOL; - } - if (ints & ATH9K_INT_RX) { - mask |= AR_IMR_RXERR; - if (ah->config.intr_mitigation) - mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; - else - mask |= AR_IMR_RXOK | AR_IMR_RXDESC; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - mask |= AR_IMR_GENTMR; - } - - if (ints & (ATH9K_INT_BMISC)) { - mask |= AR_IMR_BCNMISC; - if (ints & ATH9K_INT_TIM) - mask2 |= AR_IMR_S2_TIM; - if (ints & ATH9K_INT_DTIM) - mask2 |= AR_IMR_S2_DTIM; - if (ints & ATH9K_INT_DTIMSYNC) - mask2 |= AR_IMR_S2_DTIMSYNC; - if (ints & ATH9K_INT_CABEND) - mask2 |= AR_IMR_S2_CABEND; - if (ints & ATH9K_INT_TSFOOR) - mask2 |= AR_IMR_S2_TSFOOR; - } - - if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { - mask |= AR_IMR_BCNMISC; - if (ints & ATH9K_INT_GTT) - mask2 |= AR_IMR_S2_GTT; - if (ints & ATH9K_INT_CST) - mask2 |= AR_IMR_S2_CST; - } - - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); - REG_WRITE(ah, AR_IMR, mask); - mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | - AR_IMR_S2_DTIM | - AR_IMR_S2_DTIMSYNC | - AR_IMR_S2_CABEND | - AR_IMR_S2_CABTO | - AR_IMR_S2_TSFOOR | - AR_IMR_S2_GTT | AR_IMR_S2_CST); - REG_WRITE(ah, AR_IMR_S2, mask | mask2); - ah->mask_reg = ints; - - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - if (ints & ATH9K_INT_TIM_TIMER) - REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); - else - REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); - } - - if (ints & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n"); - REG_WRITE(ah, AR_IER, AR_IER_ENABLE); - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, - AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - - - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, - AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, - AR_INTR_SYNC_DEFAULT); - } - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", - REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); - } - - return omask; -} - -/*******************/ -/* Beacon Handling */ -/*******************/ - -void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) -{ - int flags = 0; - - ah->beacon_interval = beacon_period; - - switch (ah->opmode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_MONITOR: - REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); - REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff); - REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff); - flags |= AR_TBTT_TIMER_EN; - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - REG_SET_BIT(ah, AR_TXCFG, - AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); - REG_WRITE(ah, AR_NEXT_NDP_TIMER, - TU_TO_USEC(next_beacon + - (ah->atim_window ? ah-> - atim_window : 1))); - flags |= AR_NDP_TIMER_EN; - case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); - REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, - TU_TO_USEC(next_beacon - - ah->config. - dma_beacon_response_time)); - REG_WRITE(ah, AR_NEXT_SWBA, - TU_TO_USEC(next_beacon - - ah->config. - sw_beacon_response_time)); - flags |= - AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, - "%s: unsupported opmode: %d\n", - __func__, ah->opmode); - return; - break; - } - - REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); - - beacon_period &= ~ATH9K_BEACON_ENA; - if (beacon_period & ATH9K_BEACON_RESET_TSF) { - beacon_period &= ~ATH9K_BEACON_RESET_TSF; - ath9k_hw_reset_tsf(ah); - } - - REG_SET_BIT(ah, AR_TIMER_MODE, flags); -} - -void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, - const struct ath9k_beacon_state *bs) -{ - u32 nextTbtt, beaconintval, dtimperiod, beacontimeout; - struct ath9k_hw_capabilities *pCap = &ah->caps; - - REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); - - REG_WRITE(ah, AR_BEACON_PERIOD, - TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); - REG_WRITE(ah, AR_DMA_BEACON_PERIOD, - TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); - - REG_RMW_FIELD(ah, AR_RSSI_THR, - AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); - - beaconintval = bs->bs_intval & ATH9K_BEACON_PERIOD; - - if (bs->bs_sleepduration > beaconintval) - beaconintval = bs->bs_sleepduration; - - dtimperiod = bs->bs_dtimperiod; - if (bs->bs_sleepduration > dtimperiod) - dtimperiod = bs->bs_sleepduration; - - if (beaconintval == dtimperiod) - nextTbtt = bs->bs_nextdtim; - else - nextTbtt = bs->bs_nexttbtt; - - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); - - REG_WRITE(ah, AR_NEXT_DTIM, - TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); - REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); - - REG_WRITE(ah, AR_SLEEP1, - SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) - | AR_SLEEP1_ASSUME_DTIM); - - if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) - beacontimeout = (BEACON_TIMEOUT_VAL << 3); - else - beacontimeout = MIN_BEACON_TIMEOUT_VAL; - - REG_WRITE(ah, AR_SLEEP2, - SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - - REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); - REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); - - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | - AR_DTIM_TIMER_EN); - - /* TSF Out of Range Threshold */ - REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); -} - -/*******************/ -/* HW Capabilities */ -/*******************/ - -void ath9k_hw_fill_cap_info(struct ath_hw *ah) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - u16 capField = 0, eeval; - - eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); - ah->regulatory.current_rd = eeval; - - eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); - if (AR_SREV_9285_10_OR_LATER(ah)) - eeval |= AR9285_RDEXT_DEFAULT; - ah->regulatory.current_rd_ext = eeval; - - capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); - - if (ah->opmode != NL80211_IFTYPE_AP && - ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->regulatory.current_rd == 0x64 || - ah->regulatory.current_rd == 0x65) - ah->regulatory.current_rd += 5; - else if (ah->regulatory.current_rd == 0x41) - ah->regulatory.current_rd = 0x43; - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "regdomain mapped to 0x%x\n", ah->regulatory.current_rd); - } - - eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); - bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); - - if (eeval & AR5416_OPFLAGS_11A) { - set_bit(ATH9K_MODE_11A, pCap->wireless_modes); - if (ah->config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) - set_bit(ATH9K_MODE_11NA_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { - set_bit(ATH9K_MODE_11NA_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NA_HT40MINUS, - pCap->wireless_modes); - } - } - } - - if (eeval & AR5416_OPFLAGS_11G) { - set_bit(ATH9K_MODE_11B, pCap->wireless_modes); - set_bit(ATH9K_MODE_11G, pCap->wireless_modes); - if (ah->config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) - set_bit(ATH9K_MODE_11NG_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { - set_bit(ATH9K_MODE_11NG_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NG_HT40MINUS, - pCap->wireless_modes); - } - } - } - - pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); - if ((ah->hw_version.devid == AR5416_DEVID_PCI) && - !(eeval & AR5416_OPFLAGS_11A)) - pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; - else - pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); - - if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) - ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; - - pCap->low_2ghz_chan = 2312; - pCap->high_2ghz_chan = 2732; - - pCap->low_5ghz_chan = 4920; - pCap->high_5ghz_chan = 6100; - - pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; - - pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - - if (ah->config.ht_enable) - pCap->hw_caps |= ATH9K_HW_CAP_HT; - else - pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - - pCap->hw_caps |= ATH9K_HW_CAP_GTT; - pCap->hw_caps |= ATH9K_HW_CAP_VEOL; - pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; - pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; - - if (capField & AR_EEPROM_EEPCAP_MAXQCU) - pCap->total_queues = - MS(capField, AR_EEPROM_EEPCAP_MAXQCU); - else - pCap->total_queues = ATH9K_NUM_TX_QUEUES; - - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) - pCap->keycache_size = - 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); - else - pCap->keycache_size = AR_KEYTABLE_SIZE; - - pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - - if (AR_SREV_9285_10_OR_LATER(ah)) - pCap->num_gpio_pins = AR9285_NUM_GPIO; - else if (AR_SREV_9280_10_OR_LATER(ah)) - pCap->num_gpio_pins = AR928X_NUM_GPIO; - else - pCap->num_gpio_pins = AR_NUM_GPIO; - - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_CST; - pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; - } else { - pCap->rts_aggr_limit = (8 * 1024); - } - - pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); - if (ah->rfsilent & EEP_RFSILENT_ENABLED) { - ah->rfkill_gpio = - MS(ah->rfsilent, EEP_RFSILENT_GPIO_SEL); - ah->rfkill_polarity = - MS(ah->rfsilent, EEP_RFSILENT_POLARITY); - - pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; - } -#endif - - if ((ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || - (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) || - (ah->hw_version.macVersion == AR_SREV_VERSION_9160) || - (ah->hw_version.macVersion == AR_SREV_VERSION_9100) || - (ah->hw_version.macVersion == AR_SREV_VERSION_9280)) - pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; - else - pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; - - if (AR_SREV_9280(ah) || AR_SREV_9285(ah)) - pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; - else - pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - - if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; - } else { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; - } - - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; - - pCap->num_antcfg_5ghz = - ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); - pCap->num_antcfg_2ghz = - ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - - if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { - pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; - ah->btactive_gpio = 6; - ah->wlanactive_gpio = 5; - } -} - -bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, - u32 capability, u32 *result) -{ - switch (type) { - case ATH9K_CAP_CIPHER: - switch (capability) { - case ATH9K_CIPHER_AES_CCM: - case ATH9K_CIPHER_AES_OCB: - case ATH9K_CIPHER_TKIP: - case ATH9K_CIPHER_WEP: - case ATH9K_CIPHER_MIC: - case ATH9K_CIPHER_CLR: - return true; - default: - return false; - } - case ATH9K_CAP_TKIP_MIC: - switch (capability) { - case 0: - return true; - case 1: - return (ah->sta_id1_defaults & - AR_STA_ID1_CRPT_MIC_ENABLE) ? true : - false; - } - case ATH9K_CAP_TKIP_SPLIT: - return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ? - false : true; - case ATH9K_CAP_DIVERSITY: - return (REG_READ(ah, AR_PHY_CCK_DETECT) & - AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? - true : false; - case ATH9K_CAP_MCAST_KEYSRCH: - switch (capability) { - case 0: - return true; - case 1: - if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { - return false; - } else { - return (ah->sta_id1_defaults & - AR_STA_ID1_MCAST_KSRCH) ? true : - false; - } - } - return false; - case ATH9K_CAP_TXPOW: - switch (capability) { - case 0: - return 0; - case 1: - *result = ah->regulatory.power_limit; - return 0; - case 2: - *result = ah->regulatory.max_power_level; - return 0; - case 3: - *result = ah->regulatory.tp_scale; - return 0; - } - return false; - case ATH9K_CAP_DS: - return (AR_SREV_9280_20_OR_LATER(ah) && - (ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1)) - ? false : true; - default: - return false; - } -} - -bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, - u32 capability, u32 setting, int *status) -{ - u32 v; - - switch (type) { - case ATH9K_CAP_TKIP_MIC: - if (setting) - ah->sta_id1_defaults |= - AR_STA_ID1_CRPT_MIC_ENABLE; - else - ah->sta_id1_defaults &= - ~AR_STA_ID1_CRPT_MIC_ENABLE; - return true; - case ATH9K_CAP_DIVERSITY: - v = REG_READ(ah, AR_PHY_CCK_DETECT); - if (setting) - v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - else - v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - REG_WRITE(ah, AR_PHY_CCK_DETECT, v); - return true; - case ATH9K_CAP_MCAST_KEYSRCH: - if (setting) - ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH; - else - ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH; - return true; - default: - return false; - } -} - -/****************************/ -/* GPIO / RFKILL / Antennae */ -/****************************/ - -static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, - u32 gpio, u32 type) -{ - int addr; - u32 gpio_shift, tmp; - - if (gpio > 11) - addr = AR_GPIO_OUTPUT_MUX3; - else if (gpio > 5) - addr = AR_GPIO_OUTPUT_MUX2; - else - addr = AR_GPIO_OUTPUT_MUX1; - - gpio_shift = (gpio % 6) * 5; - - if (AR_SREV_9280_20_OR_LATER(ah) - || (addr != AR_GPIO_OUTPUT_MUX1)) { - REG_RMW(ah, addr, (type << gpio_shift), - (0x1f << gpio_shift)); - } else { - tmp = REG_READ(ah, addr); - tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); - tmp &= ~(0x1f << gpio_shift); - tmp |= (type << gpio_shift); - REG_WRITE(ah, addr, tmp); - } -} - -void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio) -{ - u32 gpio_shift; - - ASSERT(gpio < 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)); -} - -u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) -{ -#define MS_REG_READ(x, y) \ - (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y))) - - if (gpio >= ah->caps.num_gpio_pins) - return 0xffffffff; - - if (AR_SREV_9285_10_OR_LATER(ah)) - return MS_REG_READ(AR9285, gpio) != 0; - else if (AR_SREV_9280_10_OR_LATER(ah)) - return MS_REG_READ(AR928X, gpio) != 0; - else - return MS_REG_READ(AR, gpio) != 0; -} - -void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, - u32 ah_signal_type) -{ - u32 gpio_shift; - - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - - gpio_shift = 2 * gpio; - - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); -} - -void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) -{ - REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), - AR_GPIO_BIT(gpio)); -} - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) -void ath9k_enable_rfkill(struct ath_hw *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->rfkill_gpio); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); -} -#endif - -u32 ath9k_hw_getdefantenna(struct ath_hw *ah) -{ - return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; -} - -void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) -{ - REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); -} - -bool ath9k_hw_setantennaswitch(struct ath_hw *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, - u8 *rx_chainmask, - u8 *antenna_cfgd) -{ - static u8 tx_chainmask_cfg, rx_chainmask_cfg; - - if (AR_SREV_9280(ah)) { - if (!tx_chainmask_cfg) { - - tx_chainmask_cfg = *tx_chainmask; - rx_chainmask_cfg = *rx_chainmask; - } - - switch (settings) { - case ATH9K_ANT_FIXED_A: - *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_FIXED_B: - if (ah->caps.tx_chainmask > - ATH9K_ANTENNA1_CHAINMASK) { - *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - } - *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_VARIABLE: - *tx_chainmask = tx_chainmask_cfg; - *rx_chainmask = rx_chainmask_cfg; - *antenna_cfgd = true; - break; - default: - break; - } - } else { - ah->diversity_control = settings; - } - - return true; -} - -/*********************/ -/* General Operation */ -/*********************/ - -u32 ath9k_hw_getrxfilter(struct ath_hw *ah) -{ - u32 bits = REG_READ(ah, AR_RX_FILTER); - u32 phybits = REG_READ(ah, AR_PHY_ERR); - - if (phybits & AR_PHY_ERR_RADAR) - bits |= ATH9K_RX_FILTER_PHYRADAR; - if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) - bits |= ATH9K_RX_FILTER_PHYERR; - - return bits; -} - -void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) -{ - u32 phybits; - - REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); - phybits = 0; - if (bits & ATH9K_RX_FILTER_PHYRADAR) - phybits |= AR_PHY_ERR_RADAR; - if (bits & ATH9K_RX_FILTER_PHYERR) - phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; - REG_WRITE(ah, AR_PHY_ERR, phybits); - - if (phybits) - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); - else - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); -} - -bool ath9k_hw_phy_disable(struct ath_hw *ah) -{ - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); -} - -bool ath9k_hw_disable(struct ath_hw *ah) -{ - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; - - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); -} - -bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) -{ - struct ath9k_channel *chan = ah->curchan; - struct ieee80211_channel *channel = chan->chan; - - ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); - - if (ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)) != 0) - return false; - - return true; -} - -void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) -{ - memcpy(ah->macaddr, mac, ETH_ALEN); -} - -void ath9k_hw_setopmode(struct ath_hw *ah) -{ - ath9k_hw_set_operating_mode(ah, ah->opmode); -} - -void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) -{ - REG_WRITE(ah, AR_MCAST_FIL0, filter0); - REG_WRITE(ah, AR_MCAST_FIL1, filter1); -} - -void ath9k_hw_setbssidmask(struct ath_softc *sc) -{ - REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); - REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); -} - -void ath9k_hw_write_associd(struct ath_softc *sc) -{ - REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); - REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | - ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); -} - -u64 ath9k_hw_gettsf64(struct ath_hw *ah) -{ - u64 tsf; - - tsf = REG_READ(ah, AR_TSF_U32); - tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); - - return tsf; -} - -void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64) -{ - REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); - REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); -} - -void ath9k_hw_reset_tsf(struct ath_hw *ah) -{ - int count; - - count = 0; - while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { - count++; - if (count > 10) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); - break; - } - udelay(10); - } - REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); -} - -bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) -{ - if (setting) - ah->misc_mode |= AR_PCU_TX_ADD_TSF; - else - ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; - - return true; -} - -bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) -{ - if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us); - ah->slottime = (u32) -1; - return false; - } else { - REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); - ah->slottime = us; - return true; - } -} - -void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) -{ - u32 macmode; - - if (mode == ATH9K_HT_MACMODE_2040 && - !ah->config.cwm_ignore_extcca) - macmode = AR_2040_JOINED_RX_CLEAR; - else - macmode = 0; - - REG_WRITE(ah, AR_2040_MODE, macmode); -} - -/***************************/ -/* Bluetooth Coexistence */ -/***************************/ - -void ath9k_hw_btcoex_enable(struct ath_hw *ah) -{ - /* connect bt_active to baseband */ - REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, - (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | - AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); - - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); - - /* Set input mux for bt_active to gpio pin */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - ah->btactive_gpio); - - /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); - - /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); -} diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h deleted file mode 100644 index 984ac7d..0000000 --- a/drivers/net/wireless/ath9k/hw.h +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef HW_H -#define HW_H - -#include -#include -#include - -#include "mac.h" -#include "ani.h" -#include "eeprom.h" -#include "calib.h" -#include "reg.h" -#include "phy.h" - -#include "../ath/regd.h" - -#define ATHEROS_VENDOR_ID 0x168c -#define AR5416_DEVID_PCI 0x0023 -#define AR5416_DEVID_PCIE 0x0024 -#define AR9160_DEVID_PCI 0x0027 -#define AR9280_DEVID_PCI 0x0029 -#define AR9280_DEVID_PCIE 0x002a -#define AR9285_DEVID_PCIE 0x002b -#define AR5416_AR9100_DEVID 0x000b -#define AR_SUBVENDOR_ID_NOG 0x0e11 -#define AR_SUBVENDOR_ID_NEW_A 0x7065 -#define AR5416_MAGIC 0x19641014 - -/* Register read/write primitives */ -#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) -#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) - -#define SM(_v, _f) (((_v) << _f##_S) & _f) -#define MS(_v, _f) (((_v) & _f) >> _f##_S) -#define REG_RMW(_a, _r, _set, _clr) \ - REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) -#define REG_RMW_FIELD(_a, _r, _f, _v) \ - REG_WRITE(_a, _r, \ - (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) -#define REG_SET_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) | _f) -#define REG_CLR_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) - -#define DO_DELAY(x) do { \ - if ((++(x) % 64) == 0) \ - udelay(1); \ - } while (0) - -#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ - int r; \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ - INI_RA((iniarray), r, (column))); \ - DO_DELAY(regWr); \ - } \ - } while (0) - -#define 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_TX_FRAME 3 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 - -#define AR_GPIOD_MASK 0x00001FFF -#define AR_GPIO_BIT(_gpio) (1 << (_gpio)) - -#define BASE_ACTIVATE_DELAY 100 -#define RTC_PLL_SETTLE_DELAY 1000 -#define COEF_SCALE_S 24 -#define HT40_CHANNEL_CENTER_SHIFT 10 - -#define ATH9K_ANTENNA0_CHAINMASK 0x1 -#define ATH9K_ANTENNA1_CHAINMASK 0x2 - -#define ATH9K_NUM_DMA_DEBUG_REGS 8 -#define ATH9K_NUM_QUEUES 10 - -#define MAX_RATE_POWER 63 -#define AH_WAIT_TIMEOUT 100000 /* (us) */ -#define AH_TIME_QUANTUM 10 -#define AR_KEYTABLE_SIZE 128 -#define POWER_UP_TIME 200000 -#define SPUR_RSSI_THRESH 40 - -#define CAB_TIMEOUT_VAL 10 -#define BEACON_TIMEOUT_VAL 10 -#define MIN_BEACON_TIMEOUT_VAL 1 -#define SLEEP_SLOP 3 - -#define INIT_CONFIG_STATUS 0x00000000 -#define INIT_RSSI_THR 0x00000700 -#define INIT_BCON_CNTRL_REG 0x00000000 - -#define TU_TO_USEC(_tu) ((_tu) << 10) - -enum wireless_mode { - ATH9K_MODE_11A = 0, - ATH9K_MODE_11B = 2, - ATH9K_MODE_11G = 3, - ATH9K_MODE_11NA_HT20 = 6, - ATH9K_MODE_11NG_HT20 = 7, - ATH9K_MODE_11NA_HT40PLUS = 8, - ATH9K_MODE_11NA_HT40MINUS = 9, - ATH9K_MODE_11NG_HT40PLUS = 10, - ATH9K_MODE_11NG_HT40MINUS = 11, - ATH9K_MODE_MAX -}; - -enum ath9k_hw_caps { - ATH9K_HW_CAP_MIC_AESCCM = BIT(0), - ATH9K_HW_CAP_MIC_CKIP = BIT(1), - ATH9K_HW_CAP_MIC_TKIP = BIT(2), - ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3), - ATH9K_HW_CAP_CIPHER_CKIP = BIT(4), - ATH9K_HW_CAP_CIPHER_TKIP = BIT(5), - ATH9K_HW_CAP_VEOL = BIT(6), - ATH9K_HW_CAP_BSSIDMASK = BIT(7), - ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8), - ATH9K_HW_CAP_HT = BIT(9), - ATH9K_HW_CAP_GTT = BIT(10), - ATH9K_HW_CAP_FASTCC = BIT(11), - ATH9K_HW_CAP_RFSILENT = BIT(12), - ATH9K_HW_CAP_CST = BIT(13), - ATH9K_HW_CAP_ENHANCEDPM = BIT(14), - ATH9K_HW_CAP_AUTOSLEEP = BIT(15), - ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16), - ATH9K_HW_CAP_BT_COEX = BIT(17) -}; - -enum ath9k_capability_type { - ATH9K_CAP_CIPHER = 0, - ATH9K_CAP_TKIP_MIC, - ATH9K_CAP_TKIP_SPLIT, - ATH9K_CAP_DIVERSITY, - ATH9K_CAP_TXPOW, - ATH9K_CAP_MCAST_KEYSRCH, - ATH9K_CAP_DS -}; - -struct ath9k_hw_capabilities { - u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */ - u16 total_queues; - u16 keycache_size; - u16 low_5ghz_chan, high_5ghz_chan; - u16 low_2ghz_chan, high_2ghz_chan; - u16 rts_aggr_limit; - u8 tx_chainmask; - u8 rx_chainmask; - u16 tx_triglevel_max; - u16 reg_cap; - u8 num_gpio_pins; - u8 num_antcfg_2ghz; - u8 num_antcfg_5ghz; -}; - -struct ath9k_ops_config { - int dma_beacon_response_time; - int sw_beacon_response_time; - int additional_swba_backoff; - int ack_6mb; - int cwm_ignore_extcca; - u8 pcie_powersave_enable; - u8 pcie_clock_req; - u32 pcie_waen; - u8 analog_shiftreg; - u8 ht_enable; - u32 ofdm_trig_low; - u32 ofdm_trig_high; - u32 cck_trig_high; - u32 cck_trig_low; - u32 enable_ani; - u16 diversity_control; - u16 antenna_switch_swap; - int serialize_regmode; - bool intr_mitigation; -#define SPUR_DISABLE 0 -#define SPUR_ENABLE_IOCTL 1 -#define SPUR_ENABLE_EEPROM 2 -#define AR_EEPROM_MODAL_SPURS 5 -#define AR_SPUR_5413_1 1640 -#define AR_SPUR_5413_2 1200 -#define AR_NO_SPUR 0x8000 -#define AR_BASE_FREQ_2GHZ 2300 -#define AR_BASE_FREQ_5GHZ 4900 -#define AR_SPUR_FEEQ_BOUND_HT40 19 -#define AR_SPUR_FEEQ_BOUND_HT20 10 - int spurmode; - u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; -}; - -enum ath9k_int { - ATH9K_INT_RX = 0x00000001, - ATH9K_INT_RXDESC = 0x00000002, - ATH9K_INT_RXNOFRM = 0x00000008, - ATH9K_INT_RXEOL = 0x00000010, - ATH9K_INT_RXORN = 0x00000020, - ATH9K_INT_TX = 0x00000040, - ATH9K_INT_TXDESC = 0x00000080, - ATH9K_INT_TIM_TIMER = 0x00000100, - ATH9K_INT_TXURN = 0x00000800, - ATH9K_INT_MIB = 0x00001000, - ATH9K_INT_RXPHY = 0x00004000, - ATH9K_INT_RXKCM = 0x00008000, - ATH9K_INT_SWBA = 0x00010000, - ATH9K_INT_BMISS = 0x00040000, - ATH9K_INT_BNR = 0x00100000, - ATH9K_INT_TIM = 0x00200000, - ATH9K_INT_DTIM = 0x00400000, - ATH9K_INT_DTIMSYNC = 0x00800000, - ATH9K_INT_GPIO = 0x01000000, - ATH9K_INT_CABEND = 0x02000000, - ATH9K_INT_TSFOOR = 0x04000000, - ATH9K_INT_CST = 0x10000000, - ATH9K_INT_GTT = 0x20000000, - ATH9K_INT_FATAL = 0x40000000, - ATH9K_INT_GLOBAL = 0x80000000, - ATH9K_INT_BMISC = ATH9K_INT_TIM | - ATH9K_INT_DTIM | - ATH9K_INT_DTIMSYNC | - ATH9K_INT_TSFOOR | - ATH9K_INT_CABEND, - ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM | - ATH9K_INT_RXDESC | - ATH9K_INT_RXEOL | - ATH9K_INT_RXORN | - ATH9K_INT_TXURN | - ATH9K_INT_TXDESC | - ATH9K_INT_MIB | - ATH9K_INT_RXPHY | - ATH9K_INT_RXKCM | - ATH9K_INT_SWBA | - ATH9K_INT_BMISS | - ATH9K_INT_GPIO, - ATH9K_INT_NOCARD = 0xffffffff -}; - -#define CHANNEL_CW_INT 0x00002 -#define CHANNEL_CCK 0x00020 -#define CHANNEL_OFDM 0x00040 -#define CHANNEL_2GHZ 0x00080 -#define CHANNEL_5GHZ 0x00100 -#define CHANNEL_PASSIVE 0x00200 -#define CHANNEL_DYN 0x00400 -#define CHANNEL_HALF 0x04000 -#define CHANNEL_QUARTER 0x08000 -#define CHANNEL_HT20 0x10000 -#define CHANNEL_HT40PLUS 0x20000 -#define CHANNEL_HT40MINUS 0x40000 - -#define CHANNEL_INTERFERENCE 0x01 -#define CHANNEL_DFS 0x02 -#define CHANNEL_4MS_LIMIT 0x04 -#define CHANNEL_DFS_CLEAR 0x08 -#define CHANNEL_DISALLOW_ADHOC 0x10 -#define CHANNEL_PER_11D_ADHOC 0x20 - -#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) -#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) -#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) -#define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20) -#define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20) -#define CHANNEL_G_HT40PLUS (CHANNEL_2GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_A_HT40PLUS (CHANNEL_5GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_ALL \ - (CHANNEL_OFDM| \ - CHANNEL_CCK| \ - CHANNEL_2GHZ | \ - CHANNEL_5GHZ | \ - CHANNEL_HT20 | \ - CHANNEL_HT40PLUS | \ - CHANNEL_HT40MINUS) - -struct ath9k_channel { - struct ieee80211_channel *chan; - u16 channel; - u32 channelFlags; - u32 chanmode; - int32_t CalValid; - bool oneTimeCalsDone; - int8_t iCoff; - int8_t qCoff; - int16_t rawNoiseFloor; -}; - -#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \ - (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ - (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ - (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) -#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ - (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ - (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ - (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) -#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) -#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) -#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0) -#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) -#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) -#define IS_CHAN_A_5MHZ_SPACED(_c) \ - ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \ - (((_c)->channel % 20) != 0) && \ - (((_c)->channel % 10) != 0)) - -/* These macros check chanmode and not channelFlags */ -#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) -#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ - ((_c)->chanmode == CHANNEL_G_HT20)) -#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ - ((_c)->chanmode == CHANNEL_A_HT40MINUS) || \ - ((_c)->chanmode == CHANNEL_G_HT40PLUS) || \ - ((_c)->chanmode == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c))) - -enum ath9k_power_mode { - ATH9K_PM_AWAKE = 0, - ATH9K_PM_FULL_SLEEP, - ATH9K_PM_NETWORK_SLEEP, - ATH9K_PM_UNDEFINED -}; - -enum ath9k_ant_setting { - ATH9K_ANT_VARIABLE = 0, - ATH9K_ANT_FIXED_A, - ATH9K_ANT_FIXED_B -}; - -enum ath9k_tp_scale { - ATH9K_TP_SCALE_MAX = 0, - ATH9K_TP_SCALE_50, - ATH9K_TP_SCALE_25, - ATH9K_TP_SCALE_12, - ATH9K_TP_SCALE_MIN -}; - -enum ser_reg_mode { - SER_REG_MODE_OFF = 0, - SER_REG_MODE_ON = 1, - SER_REG_MODE_AUTO = 2, -}; - -struct ath9k_beacon_state { - u32 bs_nexttbtt; - u32 bs_nextdtim; - u32 bs_intval; -#define ATH9K_BEACON_PERIOD 0x0000ffff -#define ATH9K_BEACON_ENA 0x00800000 -#define ATH9K_BEACON_RESET_TSF 0x01000000 -#define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ - u32 bs_dtimperiod; - u16 bs_cfpperiod; - u16 bs_cfpmaxduration; - u32 bs_cfpnext; - u16 bs_timoffset; - u16 bs_bmissthreshold; - u32 bs_sleepduration; - u32 bs_tsfoor_threshold; -}; - -struct chan_centers { - u16 synth_center; - u16 ctl_center; - u16 ext_center; -}; - -enum { - ATH9K_RESET_POWER_ON, - ATH9K_RESET_WARM, - ATH9K_RESET_COLD, -}; - -struct ath9k_hw_version { - u32 magic; - u16 devid; - u16 subvendorid; - u32 macVersion; - u16 macRev; - u16 phyRev; - u16 analog5GhzRev; - u16 analog2GhzRev; -}; - -struct ath_hw { - struct ath_softc *ah_sc; - struct ath9k_hw_version hw_version; - struct ath9k_ops_config config; - struct ath9k_hw_capabilities caps; - struct ath_regulatory regulatory; - struct ath9k_channel channels[38]; - struct ath9k_channel *curchan; - - union { - struct ar5416_eeprom_def def; - struct ar5416_eeprom_4k map4k; - } eeprom; - const struct eeprom_ops *eep_ops; - enum ath9k_eep_map eep_map; - - bool sw_mgmt_crypto; - bool is_pciexpress; - u8 macaddr[ETH_ALEN]; - u16 tx_trig_level; - u16 rfsilent; - u32 rfkill_gpio; - u32 rfkill_polarity; - u32 btactive_gpio; - u32 wlanactive_gpio; - u32 ah_flags; - - enum nl80211_iftype opmode; - enum ath9k_power_mode power_mode; - enum ath9k_power_mode restore_mode; - - struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; - struct ar5416Stats stats; - struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; - - int16_t curchan_rad_index; - u32 mask_reg; - u32 txok_interrupt_mask; - u32 txerr_interrupt_mask; - u32 txdesc_interrupt_mask; - u32 txeol_interrupt_mask; - u32 txurn_interrupt_mask; - bool chip_fullsleep; - u32 atim_window; - u16 antenna_switch_swap; - enum ath9k_ant_setting diversity_control; - - /* Calibration */ - enum hal_cal_types supp_cals; - struct hal_cal_list iq_caldata; - struct hal_cal_list adcgain_caldata; - struct hal_cal_list adcdc_calinitdata; - struct hal_cal_list adcdc_caldata; - struct hal_cal_list *cal_list; - struct hal_cal_list *cal_list_last; - struct hal_cal_list *cal_list_curr; -#define totalPowerMeasI meas0.unsign -#define totalPowerMeasQ meas1.unsign -#define totalIqCorrMeas meas2.sign -#define totalAdcIOddPhase meas0.unsign -#define totalAdcIEvenPhase meas1.unsign -#define totalAdcQOddPhase meas2.unsign -#define totalAdcQEvenPhase meas3.unsign -#define totalAdcDcOffsetIOddPhase meas0.sign -#define totalAdcDcOffsetIEvenPhase meas1.sign -#define totalAdcDcOffsetQOddPhase meas2.sign -#define totalAdcDcOffsetQEvenPhase meas3.sign - union { - u32 unsign[AR5416_MAX_CHAINS]; - int32_t sign[AR5416_MAX_CHAINS]; - } meas0; - union { - u32 unsign[AR5416_MAX_CHAINS]; - int32_t sign[AR5416_MAX_CHAINS]; - } meas1; - union { - u32 unsign[AR5416_MAX_CHAINS]; - int32_t sign[AR5416_MAX_CHAINS]; - } meas2; - union { - u32 unsign[AR5416_MAX_CHAINS]; - int32_t sign[AR5416_MAX_CHAINS]; - } meas3; - u16 cal_samples; - - u32 sta_id1_defaults; - u32 misc_mode; - enum { - AUTO_32KHZ, - USE_32KHZ, - DONT_USE_32KHZ, - } enable_32kHz_clock; - - /* RF */ - u32 *analogBank0Data; - u32 *analogBank1Data; - u32 *analogBank2Data; - u32 *analogBank3Data; - u32 *analogBank6Data; - u32 *analogBank6TPCData; - u32 *analogBank7Data; - u32 *addac5416_21; - u32 *bank6Temp; - - int16_t txpower_indexoffset; - u32 beacon_interval; - u32 slottime; - u32 acktimeout; - u32 ctstimeout; - u32 globaltxtimeout; - u8 gbeacon_rate; - - /* ANI */ - u32 proc_phyerr; - bool has_hw_phycounters; - u32 aniperiod; - struct ar5416AniState *curani; - struct ar5416AniState ani[255]; - int totalSizeDesired[5]; - int coarse_high[5]; - int coarse_low[5]; - int firpwr[5]; - enum ath9k_ani_cmd ani_function; - - u32 intr_txqs; - enum ath9k_ht_extprotspacing extprotspacing; - u8 txchainmask; - u8 rxchainmask; - - u32 originalGain[22]; - int initPDADC; - int PDADCdelta; - - struct ar5416IniArray iniModes; - struct ar5416IniArray iniCommon; - struct ar5416IniArray iniBank0; - struct ar5416IniArray iniBB_RfGain; - struct ar5416IniArray iniBank1; - struct ar5416IniArray iniBank2; - struct ar5416IniArray iniBank3; - struct ar5416IniArray iniBank6; - struct ar5416IniArray iniBank6TPC; - struct ar5416IniArray iniBank7; - struct ar5416IniArray iniAddac; - struct ar5416IniArray iniPcieSerdes; - struct ar5416IniArray iniModesAdditional; - struct ar5416IniArray iniModesRxGain; - struct ar5416IniArray iniModesTxGain; -}; - -/* Attach, Detach, Reset */ -const char *ath9k_hw_probe(u16 vendorid, u16 devid); -void ath9k_hw_detach(struct ath_hw *ah); -struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error); -void ath9k_hw_rfdetach(struct ath_hw *ah); -int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, - bool bChannelChange); -void ath9k_hw_fill_cap_info(struct ath_hw *ah); -bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, - u32 capability, u32 *result); -bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, - u32 capability, u32 setting, int *status); - -/* Key Cache Management */ -bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry); -bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac); -bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, - const struct ath9k_keyval *k, - const u8 *mac); -bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry); - -/* GPIO / RFKILL / Antennae */ -void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio); -u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); -void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, - u32 ah_signal_type); -void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) -void ath9k_enable_rfkill(struct ath_hw *ah); -#endif -u32 ath9k_hw_getdefantenna(struct ath_hw *ah); -void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); -bool ath9k_hw_setantennaswitch(struct ath_hw *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, u8 *rx_chainmask, - u8 *antenna_cfgd); - -/* General Operation */ -bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); -u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); -u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, - u32 frameLen, u16 rateix, bool shortPreamble); -void ath9k_hw_get_channel_centers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct chan_centers *centers); -u32 ath9k_hw_getrxfilter(struct ath_hw *ah); -void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits); -bool ath9k_hw_phy_disable(struct ath_hw *ah); -bool ath9k_hw_disable(struct ath_hw *ah); -bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); -void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac); -void ath9k_hw_setopmode(struct ath_hw *ah); -void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); -void ath9k_hw_setbssidmask(struct ath_softc *sc); -void ath9k_hw_write_associd(struct ath_softc *sc); -u64 ath9k_hw_gettsf64(struct ath_hw *ah); -void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); -void ath9k_hw_reset_tsf(struct ath_hw *ah); -bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); -bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); -void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); -void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); -void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, - const struct ath9k_beacon_state *bs); -bool ath9k_hw_setpower(struct ath_hw *ah, - enum ath9k_power_mode mode); -void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore); - -/* Interrupt Handling */ -bool ath9k_hw_intrpend(struct ath_hw *ah); -bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); -enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah); -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); - -void ath9k_hw_btcoex_enable(struct ath_hw *ah); - -#endif diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h deleted file mode 100644 index e2f0a34..0000000 --- a/drivers/net/wireless/ath9k/initvals.h +++ /dev/null @@ -1,4848 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -static const u32 ar5416Modes[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 }, - { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de }, - { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, - { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, - { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, - { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, - { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, - { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, - { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, - { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, - { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, - { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, - { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, - { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, - { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, - { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, - { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, - { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, - { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, - { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, - { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, - { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, - { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, - { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, - { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, - { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, - { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, -}; - -static const u32 ar5416Common[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00007010, 0x00000000 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x000080c0, 0x2a82301a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0xffffffff }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c4, 0x00000000 }, - { 0x000081d0, 0x00003210 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x00008300, 0x00000000 }, - { 0x00008304, 0x00000000 }, - { 0x00008308, 0x00000000 }, - { 0x0000830c, 0x00000000 }, - { 0x00008310, 0x00000000 }, - { 0x00008314, 0x00000000 }, - { 0x00008318, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00070000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xad848e19 }, - { 0x00009810, 0x7d14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x00009840, 0x206a002e }, - { 0x0000984c, 0x1284233c }, - { 0x00009854, 0x00000859 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x05100000 }, - { 0x0000a920, 0x05100000 }, - { 0x0000b920, 0x05100000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280b212 }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0x5d50e188 }, - { 0x00009958, 0x00081fff }, - { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x001fff00 }, - { 0x000099ac, 0x00000000 }, - { 0x000099b0, 0x03051000 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000200 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x000000aa }, - { 0x000099fc, 0x00001042 }, - { 0x00009b00, 0x00000000 }, - { 0x00009b04, 0x00000001 }, - { 0x00009b08, 0x00000002 }, - { 0x00009b0c, 0x00000003 }, - { 0x00009b10, 0x00000004 }, - { 0x00009b14, 0x00000005 }, - { 0x00009b18, 0x00000008 }, - { 0x00009b1c, 0x00000009 }, - { 0x00009b20, 0x0000000a }, - { 0x00009b24, 0x0000000b }, - { 0x00009b28, 0x0000000c }, - { 0x00009b2c, 0x0000000d }, - { 0x00009b30, 0x00000010 }, - { 0x00009b34, 0x00000011 }, - { 0x00009b38, 0x00000012 }, - { 0x00009b3c, 0x00000013 }, - { 0x00009b40, 0x00000014 }, - { 0x00009b44, 0x00000015 }, - { 0x00009b48, 0x00000018 }, - { 0x00009b4c, 0x00000019 }, - { 0x00009b50, 0x0000001a }, - { 0x00009b54, 0x0000001b }, - { 0x00009b58, 0x0000001c }, - { 0x00009b5c, 0x0000001d }, - { 0x00009b60, 0x00000020 }, - { 0x00009b64, 0x00000021 }, - { 0x00009b68, 0x00000022 }, - { 0x00009b6c, 0x00000023 }, - { 0x00009b70, 0x00000024 }, - { 0x00009b74, 0x00000025 }, - { 0x00009b78, 0x00000028 }, - { 0x00009b7c, 0x00000029 }, - { 0x00009b80, 0x0000002a }, - { 0x00009b84, 0x0000002b }, - { 0x00009b88, 0x0000002c }, - { 0x00009b8c, 0x0000002d }, - { 0x00009b90, 0x00000030 }, - { 0x00009b94, 0x00000031 }, - { 0x00009b98, 0x00000032 }, - { 0x00009b9c, 0x00000033 }, - { 0x00009ba0, 0x00000034 }, - { 0x00009ba4, 0x00000035 }, - { 0x00009ba8, 0x00000035 }, - { 0x00009bac, 0x00000035 }, - { 0x00009bb0, 0x00000035 }, - { 0x00009bb4, 0x00000035 }, - { 0x00009bb8, 0x00000035 }, - { 0x00009bbc, 0x00000035 }, - { 0x00009bc0, 0x00000035 }, - { 0x00009bc4, 0x00000035 }, - { 0x00009bc8, 0x00000035 }, - { 0x00009bcc, 0x00000035 }, - { 0x00009bd0, 0x00000035 }, - { 0x00009bd4, 0x00000035 }, - { 0x00009bd8, 0x00000035 }, - { 0x00009bdc, 0x00000035 }, - { 0x00009be0, 0x00000035 }, - { 0x00009be4, 0x00000035 }, - { 0x00009be8, 0x00000035 }, - { 0x00009bec, 0x00000035 }, - { 0x00009bf0, 0x00000035 }, - { 0x00009bf4, 0x00000035 }, - { 0x00009bf8, 0x00000010 }, - { 0x00009bfc, 0x0000001a }, - { 0x0000a210, 0x40806333 }, - { 0x0000a214, 0x00106c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x018830c6 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x00000bb5 }, - { 0x0000a22c, 0x00000011 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c889af }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000a000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cc75380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000c26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x051701ce }, - { 0x0000a338, 0x00000000 }, - { 0x0000a33c, 0x00000000 }, - { 0x0000a340, 0x00000000 }, - { 0x0000a344, 0x00000000 }, - { 0x0000a348, 0x3fffffff }, - { 0x0000a34c, 0x3fffffff }, - { 0x0000a350, 0x3fffffff }, - { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79a8aa1f }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x08000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, -}; - -static const u32 ar5416Bank0[][2] = { - { 0x000098b0, 0x1e5795e5 }, - { 0x000098e0, 0x02008020 }, -}; - -static const u32 ar5416BB_RfGain[][3] = { - { 0x00009a00, 0x00000000, 0x00000000 }, - { 0x00009a04, 0x00000040, 0x00000040 }, - { 0x00009a08, 0x00000080, 0x00000080 }, - { 0x00009a0c, 0x000001a1, 0x00000141 }, - { 0x00009a10, 0x000001e1, 0x00000181 }, - { 0x00009a14, 0x00000021, 0x000001c1 }, - { 0x00009a18, 0x00000061, 0x00000001 }, - { 0x00009a1c, 0x00000168, 0x00000041 }, - { 0x00009a20, 0x000001a8, 0x000001a8 }, - { 0x00009a24, 0x000001e8, 0x000001e8 }, - { 0x00009a28, 0x00000028, 0x00000028 }, - { 0x00009a2c, 0x00000068, 0x00000068 }, - { 0x00009a30, 0x00000189, 0x000000a8 }, - { 0x00009a34, 0x000001c9, 0x00000169 }, - { 0x00009a38, 0x00000009, 0x000001a9 }, - { 0x00009a3c, 0x00000049, 0x000001e9 }, - { 0x00009a40, 0x00000089, 0x00000029 }, - { 0x00009a44, 0x00000170, 0x00000069 }, - { 0x00009a48, 0x000001b0, 0x00000190 }, - { 0x00009a4c, 0x000001f0, 0x000001d0 }, - { 0x00009a50, 0x00000030, 0x00000010 }, - { 0x00009a54, 0x00000070, 0x00000050 }, - { 0x00009a58, 0x00000191, 0x00000090 }, - { 0x00009a5c, 0x000001d1, 0x00000151 }, - { 0x00009a60, 0x00000011, 0x00000191 }, - { 0x00009a64, 0x00000051, 0x000001d1 }, - { 0x00009a68, 0x00000091, 0x00000011 }, - { 0x00009a6c, 0x000001b8, 0x00000051 }, - { 0x00009a70, 0x000001f8, 0x00000198 }, - { 0x00009a74, 0x00000038, 0x000001d8 }, - { 0x00009a78, 0x00000078, 0x00000018 }, - { 0x00009a7c, 0x00000199, 0x00000058 }, - { 0x00009a80, 0x000001d9, 0x00000098 }, - { 0x00009a84, 0x00000019, 0x00000159 }, - { 0x00009a88, 0x00000059, 0x00000199 }, - { 0x00009a8c, 0x00000099, 0x000001d9 }, - { 0x00009a90, 0x000000d9, 0x00000019 }, - { 0x00009a94, 0x000000f9, 0x00000059 }, - { 0x00009a98, 0x000000f9, 0x00000099 }, - { 0x00009a9c, 0x000000f9, 0x000000d9 }, - { 0x00009aa0, 0x000000f9, 0x000000f9 }, - { 0x00009aa4, 0x000000f9, 0x000000f9 }, - { 0x00009aa8, 0x000000f9, 0x000000f9 }, - { 0x00009aac, 0x000000f9, 0x000000f9 }, - { 0x00009ab0, 0x000000f9, 0x000000f9 }, - { 0x00009ab4, 0x000000f9, 0x000000f9 }, - { 0x00009ab8, 0x000000f9, 0x000000f9 }, - { 0x00009abc, 0x000000f9, 0x000000f9 }, - { 0x00009ac0, 0x000000f9, 0x000000f9 }, - { 0x00009ac4, 0x000000f9, 0x000000f9 }, - { 0x00009ac8, 0x000000f9, 0x000000f9 }, - { 0x00009acc, 0x000000f9, 0x000000f9 }, - { 0x00009ad0, 0x000000f9, 0x000000f9 }, - { 0x00009ad4, 0x000000f9, 0x000000f9 }, - { 0x00009ad8, 0x000000f9, 0x000000f9 }, - { 0x00009adc, 0x000000f9, 0x000000f9 }, - { 0x00009ae0, 0x000000f9, 0x000000f9 }, - { 0x00009ae4, 0x000000f9, 0x000000f9 }, - { 0x00009ae8, 0x000000f9, 0x000000f9 }, - { 0x00009aec, 0x000000f9, 0x000000f9 }, - { 0x00009af0, 0x000000f9, 0x000000f9 }, - { 0x00009af4, 0x000000f9, 0x000000f9 }, - { 0x00009af8, 0x000000f9, 0x000000f9 }, - { 0x00009afc, 0x000000f9, 0x000000f9 }, -}; - -static const u32 ar5416Bank1[][2] = { - { 0x000098b0, 0x02108421 }, - { 0x000098ec, 0x00000008 }, -}; - -static const u32 ar5416Bank2[][2] = { - { 0x000098b0, 0x0e73ff17 }, - { 0x000098e0, 0x00000420 }, -}; - -static const u32 ar5416Bank3[][3] = { - { 0x000098f0, 0x01400018, 0x01c00018 }, -}; - -static const u32 ar5416Bank6[][3] = { - - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x004210a2, 0x004210a2 }, - { 0x0000989c, 0x0014008f, 0x0014008f }, - { 0x0000989c, 0x00c40003, 0x00c40003 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000f1, 0x000000f1 }, - { 0x0000989c, 0x00002081, 0x00002081 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank6TPC[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x00423022, 0x00423022 }, - { 0x0000989c, 0x201400df, 0x201400df }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000e1, 0x000000e1 }, - { 0x0000989c, 0x00007081, 0x00007081 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank7[][2] = { - { 0x0000989c, 0x00000500 }, - { 0x0000989c, 0x00000800 }, - { 0x000098cc, 0x0000000e }, -}; - -static const u32 ar5416Addac[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000003 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x0000000c }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000030 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000060 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000058 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -static const u32 ar5416Modes_9100[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, - { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, - { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, - { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, - { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e }, - { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff }, -#ifdef TB243 - { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, - { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, - { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, - { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 }, -#else - { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, - { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, - { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, - { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, -#endif - { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 }, - { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, - { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, - { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, - { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, - { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, - { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, - { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, - { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, - { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, - { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, - { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, - { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, - { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, - { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, -}; - -static const u32 ar5416Common_9100[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00020010, 0x00000003 }, - { 0x00020038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00004000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x000080c0, 0x2a82301a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c4, 0x00000000 }, - { 0x000081d0, 0x00003210 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x00008300, 0x00000000 }, - { 0x00008304, 0x00000000 }, - { 0x00008308, 0x00000000 }, - { 0x0000830c, 0x00000000 }, - { 0x00008310, 0x00000000 }, - { 0x00008314, 0x00000000 }, - { 0x00008318, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xad848e19 }, - { 0x00009810, 0x7d14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x00009840, 0x206a01ae }, - { 0x0000984c, 0x1284233c }, - { 0x00009854, 0x00000859 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x05100000 }, - { 0x0000a920, 0x05100000 }, - { 0x0000b920, 0x05100000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280b212 }, - { 0x0000994c, 0x00020028 }, - { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x006f0000 }, - { 0x000099b0, 0x03051000 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000200 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099fc, 0x00001042 }, - { 0x00009b00, 0x00000000 }, - { 0x00009b04, 0x00000001 }, - { 0x00009b08, 0x00000002 }, - { 0x00009b0c, 0x00000003 }, - { 0x00009b10, 0x00000004 }, - { 0x00009b14, 0x00000005 }, - { 0x00009b18, 0x00000008 }, - { 0x00009b1c, 0x00000009 }, - { 0x00009b20, 0x0000000a }, - { 0x00009b24, 0x0000000b }, - { 0x00009b28, 0x0000000c }, - { 0x00009b2c, 0x0000000d }, - { 0x00009b30, 0x00000010 }, - { 0x00009b34, 0x00000011 }, - { 0x00009b38, 0x00000012 }, - { 0x00009b3c, 0x00000013 }, - { 0x00009b40, 0x00000014 }, - { 0x00009b44, 0x00000015 }, - { 0x00009b48, 0x00000018 }, - { 0x00009b4c, 0x00000019 }, - { 0x00009b50, 0x0000001a }, - { 0x00009b54, 0x0000001b }, - { 0x00009b58, 0x0000001c }, - { 0x00009b5c, 0x0000001d }, - { 0x00009b60, 0x00000020 }, - { 0x00009b64, 0x00000021 }, - { 0x00009b68, 0x00000022 }, - { 0x00009b6c, 0x00000023 }, - { 0x00009b70, 0x00000024 }, - { 0x00009b74, 0x00000025 }, - { 0x00009b78, 0x00000028 }, - { 0x00009b7c, 0x00000029 }, - { 0x00009b80, 0x0000002a }, - { 0x00009b84, 0x0000002b }, - { 0x00009b88, 0x0000002c }, - { 0x00009b8c, 0x0000002d }, - { 0x00009b90, 0x00000030 }, - { 0x00009b94, 0x00000031 }, - { 0x00009b98, 0x00000032 }, - { 0x00009b9c, 0x00000033 }, - { 0x00009ba0, 0x00000034 }, - { 0x00009ba4, 0x00000035 }, - { 0x00009ba8, 0x00000035 }, - { 0x00009bac, 0x00000035 }, - { 0x00009bb0, 0x00000035 }, - { 0x00009bb4, 0x00000035 }, - { 0x00009bb8, 0x00000035 }, - { 0x00009bbc, 0x00000035 }, - { 0x00009bc0, 0x00000035 }, - { 0x00009bc4, 0x00000035 }, - { 0x00009bc8, 0x00000035 }, - { 0x00009bcc, 0x00000035 }, - { 0x00009bd0, 0x00000035 }, - { 0x00009bd4, 0x00000035 }, - { 0x00009bd8, 0x00000035 }, - { 0x00009bdc, 0x00000035 }, - { 0x00009be0, 0x00000035 }, - { 0x00009be4, 0x00000035 }, - { 0x00009be8, 0x00000035 }, - { 0x00009bec, 0x00000035 }, - { 0x00009bf0, 0x00000035 }, - { 0x00009bf4, 0x00000035 }, - { 0x00009bf8, 0x00000010 }, - { 0x00009bfc, 0x0000001a }, - { 0x0000a210, 0x40806333 }, - { 0x0000a214, 0x00106c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x018830c6 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x001a0bb5 }, - { 0x0000a22c, 0x00000000 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c889ae }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000a000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cc75380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000001 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000c26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, - { 0x0000a338, 0x00000000 }, - { 0x0000a33c, 0x00000000 }, - { 0x0000a340, 0x00000000 }, - { 0x0000a344, 0x00000000 }, - { 0x0000a348, 0x3fffffff }, - { 0x0000a34c, 0x3fffffff }, - { 0x0000a350, 0x3fffffff }, - { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79a8aa33 }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, -}; - -static const u32 ar5416Bank0_9100[][2] = { - { 0x000098b0, 0x1e5795e5 }, - { 0x000098e0, 0x02008020 }, -}; - -static const u32 ar5416BB_RfGain_9100[][3] = { - { 0x00009a00, 0x00000000, 0x00000000 }, - { 0x00009a04, 0x00000040, 0x00000040 }, - { 0x00009a08, 0x00000080, 0x00000080 }, - { 0x00009a0c, 0x000001a1, 0x00000141 }, - { 0x00009a10, 0x000001e1, 0x00000181 }, - { 0x00009a14, 0x00000021, 0x000001c1 }, - { 0x00009a18, 0x00000061, 0x00000001 }, - { 0x00009a1c, 0x00000168, 0x00000041 }, - { 0x00009a20, 0x000001a8, 0x000001a8 }, - { 0x00009a24, 0x000001e8, 0x000001e8 }, - { 0x00009a28, 0x00000028, 0x00000028 }, - { 0x00009a2c, 0x00000068, 0x00000068 }, - { 0x00009a30, 0x00000189, 0x000000a8 }, - { 0x00009a34, 0x000001c9, 0x00000169 }, - { 0x00009a38, 0x00000009, 0x000001a9 }, - { 0x00009a3c, 0x00000049, 0x000001e9 }, - { 0x00009a40, 0x00000089, 0x00000029 }, - { 0x00009a44, 0x00000170, 0x00000069 }, - { 0x00009a48, 0x000001b0, 0x00000190 }, - { 0x00009a4c, 0x000001f0, 0x000001d0 }, - { 0x00009a50, 0x00000030, 0x00000010 }, - { 0x00009a54, 0x00000070, 0x00000050 }, - { 0x00009a58, 0x00000191, 0x00000090 }, - { 0x00009a5c, 0x000001d1, 0x00000151 }, - { 0x00009a60, 0x00000011, 0x00000191 }, - { 0x00009a64, 0x00000051, 0x000001d1 }, - { 0x00009a68, 0x00000091, 0x00000011 }, - { 0x00009a6c, 0x000001b8, 0x00000051 }, - { 0x00009a70, 0x000001f8, 0x00000198 }, - { 0x00009a74, 0x00000038, 0x000001d8 }, - { 0x00009a78, 0x00000078, 0x00000018 }, - { 0x00009a7c, 0x00000199, 0x00000058 }, - { 0x00009a80, 0x000001d9, 0x00000098 }, - { 0x00009a84, 0x00000019, 0x00000159 }, - { 0x00009a88, 0x00000059, 0x00000199 }, - { 0x00009a8c, 0x00000099, 0x000001d9 }, - { 0x00009a90, 0x000000d9, 0x00000019 }, - { 0x00009a94, 0x000000f9, 0x00000059 }, - { 0x00009a98, 0x000000f9, 0x00000099 }, - { 0x00009a9c, 0x000000f9, 0x000000d9 }, - { 0x00009aa0, 0x000000f9, 0x000000f9 }, - { 0x00009aa4, 0x000000f9, 0x000000f9 }, - { 0x00009aa8, 0x000000f9, 0x000000f9 }, - { 0x00009aac, 0x000000f9, 0x000000f9 }, - { 0x00009ab0, 0x000000f9, 0x000000f9 }, - { 0x00009ab4, 0x000000f9, 0x000000f9 }, - { 0x00009ab8, 0x000000f9, 0x000000f9 }, - { 0x00009abc, 0x000000f9, 0x000000f9 }, - { 0x00009ac0, 0x000000f9, 0x000000f9 }, - { 0x00009ac4, 0x000000f9, 0x000000f9 }, - { 0x00009ac8, 0x000000f9, 0x000000f9 }, - { 0x00009acc, 0x000000f9, 0x000000f9 }, - { 0x00009ad0, 0x000000f9, 0x000000f9 }, - { 0x00009ad4, 0x000000f9, 0x000000f9 }, - { 0x00009ad8, 0x000000f9, 0x000000f9 }, - { 0x00009adc, 0x000000f9, 0x000000f9 }, - { 0x00009ae0, 0x000000f9, 0x000000f9 }, - { 0x00009ae4, 0x000000f9, 0x000000f9 }, - { 0x00009ae8, 0x000000f9, 0x000000f9 }, - { 0x00009aec, 0x000000f9, 0x000000f9 }, - { 0x00009af0, 0x000000f9, 0x000000f9 }, - { 0x00009af4, 0x000000f9, 0x000000f9 }, - { 0x00009af8, 0x000000f9, 0x000000f9 }, - { 0x00009afc, 0x000000f9, 0x000000f9 }, -}; - -static const u32 ar5416Bank1_9100[][2] = { - { 0x000098b0, 0x02108421}, - { 0x000098ec, 0x00000008}, -}; - -static const u32 ar5416Bank2_9100[][2] = { - { 0x000098b0, 0x0e73ff17}, - { 0x000098e0, 0x00000420}, -}; - -static const u32 ar5416Bank3_9100[][3] = { - { 0x000098f0, 0x01400018, 0x01c00018 }, -}; - -static const u32 ar5416Bank6_9100[][3] = { - - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x004210a2, 0x004210a2 }, - { 0x0000989c, 0x0014000f, 0x0014000f }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x000180d6, 0x000180d6 }, - { 0x0000989c, 0x0000c0aa, 0x0000c0aa }, - { 0x0000989c, 0x000000b1, 0x000000b1 }, - { 0x0000989c, 0x00002000, 0x00002000 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - - -static const u32 ar5416Bank6TPC_9100[][3] = { - - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x00423022, 0x00423022 }, - { 0x0000989c, 0x2014008f, 0x2014008f }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000e1, 0x000000e1 }, - { 0x0000989c, 0x00007080, 0x00007080 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank7_9100[][2] = { - { 0x0000989c, 0x00000500 }, - { 0x0000989c, 0x00000800 }, - { 0x000098cc, 0x0000000e }, -}; - -static const u32 ar5416Addac_9100[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000010 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000015 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -static const u32 ar5416Modes_9160[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 }, - { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, - { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, - { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, - { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, - { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, - { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, - { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, - { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, - { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, - { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, - { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, - { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, - { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, - { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, - { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, - { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, - { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, - { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, - { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, - { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, - { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, - { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, - { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, -}; - -static const u32 ar5416Common_9160[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00007010, 0x00000020 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x000080c0, 0x2a82301a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0xffffffff }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c4, 0x00000000 }, - { 0x000081d0, 0x00003210 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x00008300, 0x00000000 }, - { 0x00008304, 0x00000000 }, - { 0x00008308, 0x00000000 }, - { 0x0000830c, 0x00000000 }, - { 0x00008310, 0x00000000 }, - { 0x00008314, 0x00000000 }, - { 0x00008318, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00ff0000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xad848e19 }, - { 0x00009810, 0x7d14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x00009840, 0x206a01ae }, - { 0x0000984c, 0x1284233c }, - { 0x00009854, 0x00000859 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x05100000 }, - { 0x0000a920, 0x05100000 }, - { 0x0000b920, 0x05100000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280b212 }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0x5f3ca3de }, - { 0x00009958, 0x2108ecff }, - { 0x00009940, 0x00750604 }, - { 0x0000c95c, 0x004b6a8e }, - { 0x00009970, 0x190fb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x006f0000 }, - { 0x000099b0, 0x03051000 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000200 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099fc, 0x00001042 }, - { 0x00009b00, 0x00000000 }, - { 0x00009b04, 0x00000001 }, - { 0x00009b08, 0x00000002 }, - { 0x00009b0c, 0x00000003 }, - { 0x00009b10, 0x00000004 }, - { 0x00009b14, 0x00000005 }, - { 0x00009b18, 0x00000008 }, - { 0x00009b1c, 0x00000009 }, - { 0x00009b20, 0x0000000a }, - { 0x00009b24, 0x0000000b }, - { 0x00009b28, 0x0000000c }, - { 0x00009b2c, 0x0000000d }, - { 0x00009b30, 0x00000010 }, - { 0x00009b34, 0x00000011 }, - { 0x00009b38, 0x00000012 }, - { 0x00009b3c, 0x00000013 }, - { 0x00009b40, 0x00000014 }, - { 0x00009b44, 0x00000015 }, - { 0x00009b48, 0x00000018 }, - { 0x00009b4c, 0x00000019 }, - { 0x00009b50, 0x0000001a }, - { 0x00009b54, 0x0000001b }, - { 0x00009b58, 0x0000001c }, - { 0x00009b5c, 0x0000001d }, - { 0x00009b60, 0x00000020 }, - { 0x00009b64, 0x00000021 }, - { 0x00009b68, 0x00000022 }, - { 0x00009b6c, 0x00000023 }, - { 0x00009b70, 0x00000024 }, - { 0x00009b74, 0x00000025 }, - { 0x00009b78, 0x00000028 }, - { 0x00009b7c, 0x00000029 }, - { 0x00009b80, 0x0000002a }, - { 0x00009b84, 0x0000002b }, - { 0x00009b88, 0x0000002c }, - { 0x00009b8c, 0x0000002d }, - { 0x00009b90, 0x00000030 }, - { 0x00009b94, 0x00000031 }, - { 0x00009b98, 0x00000032 }, - { 0x00009b9c, 0x00000033 }, - { 0x00009ba0, 0x00000034 }, - { 0x00009ba4, 0x00000035 }, - { 0x00009ba8, 0x00000035 }, - { 0x00009bac, 0x00000035 }, - { 0x00009bb0, 0x00000035 }, - { 0x00009bb4, 0x00000035 }, - { 0x00009bb8, 0x00000035 }, - { 0x00009bbc, 0x00000035 }, - { 0x00009bc0, 0x00000035 }, - { 0x00009bc4, 0x00000035 }, - { 0x00009bc8, 0x00000035 }, - { 0x00009bcc, 0x00000035 }, - { 0x00009bd0, 0x00000035 }, - { 0x00009bd4, 0x00000035 }, - { 0x00009bd8, 0x00000035 }, - { 0x00009bdc, 0x00000035 }, - { 0x00009be0, 0x00000035 }, - { 0x00009be4, 0x00000035 }, - { 0x00009be8, 0x00000035 }, - { 0x00009bec, 0x00000035 }, - { 0x00009bf0, 0x00000035 }, - { 0x00009bf4, 0x00000035 }, - { 0x00009bf8, 0x00000010 }, - { 0x00009bfc, 0x0000001a }, - { 0x0000a210, 0x40806333 }, - { 0x0000a214, 0x00106c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x018830c6 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x001a0bb5 }, - { 0x0000a22c, 0x00000000 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c889af }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000e000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cc75380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000001 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000c26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, - { 0x0000a338, 0x00000000 }, - { 0x0000a33c, 0x00000000 }, - { 0x0000a340, 0x00000000 }, - { 0x0000a344, 0x00000000 }, - { 0x0000a348, 0x3fffffff }, - { 0x0000a34c, 0x3fffffff }, - { 0x0000a350, 0x3fffffff }, - { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79bfaa03 }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, -}; - -static const u32 ar5416Bank0_9160[][2] = { - { 0x000098b0, 0x1e5795e5 }, - { 0x000098e0, 0x02008020 }, -}; - -static const u32 ar5416BB_RfGain_9160[][3] = { - { 0x00009a00, 0x00000000, 0x00000000 }, - { 0x00009a04, 0x00000040, 0x00000040 }, - { 0x00009a08, 0x00000080, 0x00000080 }, - { 0x00009a0c, 0x000001a1, 0x00000141 }, - { 0x00009a10, 0x000001e1, 0x00000181 }, - { 0x00009a14, 0x00000021, 0x000001c1 }, - { 0x00009a18, 0x00000061, 0x00000001 }, - { 0x00009a1c, 0x00000168, 0x00000041 }, - { 0x00009a20, 0x000001a8, 0x000001a8 }, - { 0x00009a24, 0x000001e8, 0x000001e8 }, - { 0x00009a28, 0x00000028, 0x00000028 }, - { 0x00009a2c, 0x00000068, 0x00000068 }, - { 0x00009a30, 0x00000189, 0x000000a8 }, - { 0x00009a34, 0x000001c9, 0x00000169 }, - { 0x00009a38, 0x00000009, 0x000001a9 }, - { 0x00009a3c, 0x00000049, 0x000001e9 }, - { 0x00009a40, 0x00000089, 0x00000029 }, - { 0x00009a44, 0x00000170, 0x00000069 }, - { 0x00009a48, 0x000001b0, 0x00000190 }, - { 0x00009a4c, 0x000001f0, 0x000001d0 }, - { 0x00009a50, 0x00000030, 0x00000010 }, - { 0x00009a54, 0x00000070, 0x00000050 }, - { 0x00009a58, 0x00000191, 0x00000090 }, - { 0x00009a5c, 0x000001d1, 0x00000151 }, - { 0x00009a60, 0x00000011, 0x00000191 }, - { 0x00009a64, 0x00000051, 0x000001d1 }, - { 0x00009a68, 0x00000091, 0x00000011 }, - { 0x00009a6c, 0x000001b8, 0x00000051 }, - { 0x00009a70, 0x000001f8, 0x00000198 }, - { 0x00009a74, 0x00000038, 0x000001d8 }, - { 0x00009a78, 0x00000078, 0x00000018 }, - { 0x00009a7c, 0x00000199, 0x00000058 }, - { 0x00009a80, 0x000001d9, 0x00000098 }, - { 0x00009a84, 0x00000019, 0x00000159 }, - { 0x00009a88, 0x00000059, 0x00000199 }, - { 0x00009a8c, 0x00000099, 0x000001d9 }, - { 0x00009a90, 0x000000d9, 0x00000019 }, - { 0x00009a94, 0x000000f9, 0x00000059 }, - { 0x00009a98, 0x000000f9, 0x00000099 }, - { 0x00009a9c, 0x000000f9, 0x000000d9 }, - { 0x00009aa0, 0x000000f9, 0x000000f9 }, - { 0x00009aa4, 0x000000f9, 0x000000f9 }, - { 0x00009aa8, 0x000000f9, 0x000000f9 }, - { 0x00009aac, 0x000000f9, 0x000000f9 }, - { 0x00009ab0, 0x000000f9, 0x000000f9 }, - { 0x00009ab4, 0x000000f9, 0x000000f9 }, - { 0x00009ab8, 0x000000f9, 0x000000f9 }, - { 0x00009abc, 0x000000f9, 0x000000f9 }, - { 0x00009ac0, 0x000000f9, 0x000000f9 }, - { 0x00009ac4, 0x000000f9, 0x000000f9 }, - { 0x00009ac8, 0x000000f9, 0x000000f9 }, - { 0x00009acc, 0x000000f9, 0x000000f9 }, - { 0x00009ad0, 0x000000f9, 0x000000f9 }, - { 0x00009ad4, 0x000000f9, 0x000000f9 }, - { 0x00009ad8, 0x000000f9, 0x000000f9 }, - { 0x00009adc, 0x000000f9, 0x000000f9 }, - { 0x00009ae0, 0x000000f9, 0x000000f9 }, - { 0x00009ae4, 0x000000f9, 0x000000f9 }, - { 0x00009ae8, 0x000000f9, 0x000000f9 }, - { 0x00009aec, 0x000000f9, 0x000000f9 }, - { 0x00009af0, 0x000000f9, 0x000000f9 }, - { 0x00009af4, 0x000000f9, 0x000000f9 }, - { 0x00009af8, 0x000000f9, 0x000000f9 }, - { 0x00009afc, 0x000000f9, 0x000000f9 }, -}; - -static const u32 ar5416Bank1_9160[][2] = { - { 0x000098b0, 0x02108421 }, - { 0x000098ec, 0x00000008 }, -}; - -static const u32 ar5416Bank2_9160[][2] = { - { 0x000098b0, 0x0e73ff17 }, - { 0x000098e0, 0x00000420 }, -}; - -static const u32 ar5416Bank3_9160[][3] = { - { 0x000098f0, 0x01400018, 0x01c00018 }, -}; - -static const u32 ar5416Bank6_9160[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x004210a2, 0x004210a2 }, - { 0x0000989c, 0x0014008f, 0x0014008f }, - { 0x0000989c, 0x00c40003, 0x00c40003 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000f1, 0x000000f1 }, - { 0x0000989c, 0x00002081, 0x00002081 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank6TPC_9160[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x00423022, 0x00423022 }, - { 0x0000989c, 0x2014008f, 0x2014008f }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000e1, 0x000000e1 }, - { 0x0000989c, 0x00007080, 0x00007080 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank7_9160[][2] = { - { 0x0000989c, 0x00000500 }, - { 0x0000989c, 0x00000800 }, - { 0x000098cc, 0x0000000e }, -}; - -static u32 ar5416Addac_9160[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000018 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000019 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000003 }, - {0x0000989c, 0x00000008 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -static u32 ar5416Addac_91601_1[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000018 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000019 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -/* XXX 9280 1 */ -static const u32 ar9280Modes_9280[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801080, 0x08400840, 0x06e006e0 }, - { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 }, - { 0x00009848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 }, - { 0x0000a848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 }, - { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, - { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, - { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d20, 0x00049d20, 0x00049d18 }, - { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190 }, - { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 }, - { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, - { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, - { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, - { 0x0000c9b8, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a }, - { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, - { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009a00, 0x00008184, 0x00008184, 0x00000214, 0x00000214, 0x00000214 }, - { 0x00009a04, 0x00008188, 0x00008188, 0x00000218, 0x00000218, 0x00000218 }, - { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000224, 0x00000224, 0x00000224 }, - { 0x00009a0c, 0x00008190, 0x00008190, 0x00000228, 0x00000228, 0x00000228 }, - { 0x00009a10, 0x00008194, 0x00008194, 0x0000022c, 0x0000022c, 0x0000022c }, - { 0x00009a14, 0x00008200, 0x00008200, 0x00000230, 0x00000230, 0x00000230 }, - { 0x00009a18, 0x00008204, 0x00008204, 0x000002a4, 0x000002a4, 0x000002a4 }, - { 0x00009a1c, 0x00008208, 0x00008208, 0x000002a8, 0x000002a8, 0x000002a8 }, - { 0x00009a20, 0x0000820c, 0x0000820c, 0x000002ac, 0x000002ac, 0x000002ac }, - { 0x00009a24, 0x00008210, 0x00008210, 0x000002b0, 0x000002b0, 0x000002b0 }, - { 0x00009a28, 0x00008214, 0x00008214, 0x000002b4, 0x000002b4, 0x000002b4 }, - { 0x00009a2c, 0x00008280, 0x00008280, 0x000002b8, 0x000002b8, 0x000002b8 }, - { 0x00009a30, 0x00008284, 0x00008284, 0x00000390, 0x00000390, 0x00000390 }, - { 0x00009a34, 0x00008288, 0x00008288, 0x00000394, 0x00000394, 0x00000394 }, - { 0x00009a38, 0x0000828c, 0x0000828c, 0x00000398, 0x00000398, 0x00000398 }, - { 0x00009a3c, 0x00008290, 0x00008290, 0x00000334, 0x00000334, 0x00000334 }, - { 0x00009a40, 0x00008300, 0x00008300, 0x00000338, 0x00000338, 0x00000338 }, - { 0x00009a44, 0x00008304, 0x00008304, 0x000003ac, 0x000003ac, 0x000003ac }, - { 0x00009a48, 0x00008308, 0x00008308, 0x000003b0, 0x000003b0, 0x000003b0 }, - { 0x00009a4c, 0x0000830c, 0x0000830c, 0x000003b4, 0x000003b4, 0x000003b4 }, - { 0x00009a50, 0x00008310, 0x00008310, 0x000003b8, 0x000003b8, 0x000003b8 }, - { 0x00009a54, 0x00008314, 0x00008314, 0x000003a5, 0x000003a5, 0x000003a5 }, - { 0x00009a58, 0x00008380, 0x00008380, 0x000003a9, 0x000003a9, 0x000003a9 }, - { 0x00009a5c, 0x00008384, 0x00008384, 0x000003ad, 0x000003ad, 0x000003ad }, - { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, - { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, - { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, - { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, - { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, - { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, - { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, - { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, - { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, - { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, - { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, - { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, - { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, - { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, - { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, - { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, - { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, - { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, - { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, - { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, - { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, - { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, - { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, - { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, - { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, - { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, - { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, - { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, - { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, - { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, - { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, - { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, - { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, - { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, - { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, - { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, - { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, - { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, - { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, - { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, - { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, - { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, - { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, - { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, - { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, - { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, - { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, - { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, - { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, - { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, - { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, - { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, - { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, - { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, - { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, - { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, - { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, - { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, - { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, - { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, - { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, - { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, - { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, - { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, - { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, - { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, - { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, - { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, - { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, - { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, - { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, - { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, - { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, - { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, - { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, - { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, - { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 }, - { 0x0000a20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 }, - { 0x0000b20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, - { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, - { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, - { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, - { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, - { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, - { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, - { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, - { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, - { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, - { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, - { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, - { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, - { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, - { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, - { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, - { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, - { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, - { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, - { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, - { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, - { 0x0000784c, 0x0e4f048c, 0x0e4f048c, 0x0e4d048c, 0x0e4d048c, 0x0e4d048c }, - { 0x00007854, 0x12031828, 0x12031828, 0x12035828, 0x12035828, 0x12035828 }, - { 0x00007870, 0x807ec400, 0x807ec400, 0x807ec000, 0x807ec000, 0x807ec000 }, - { 0x0000788c, 0x00010000, 0x00010000, 0x00110000, 0x00110000, 0x00110000 }, -}; - -static const u32 ar9280Common_9280[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00004024, 0x0000001f }, - { 0x00007010, 0x00000033 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x00008070, 0x00000000 }, - { 0x000080c0, 0x2a82301a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c4, 0x00000000 }, - { 0x000081d0, 0x00003210 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x00008300, 0x00000000 }, - { 0x00008304, 0x00000000 }, - { 0x00008308, 0x00000000 }, - { 0x0000830c, 0x00000000 }, - { 0x00008310, 0x00000000 }, - { 0x00008314, 0x00000000 }, - { 0x00008318, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00008344, 0x00000000 }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xaf268e30 }, - { 0x00009810, 0xfd14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x00009840, 0x206a01ae }, - { 0x0000984c, 0x0040233c }, - { 0x0000a84c, 0x0040233c }, - { 0x00009854, 0x00000044 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x04900000 }, - { 0x0000a920, 0x04900000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280c00a }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0xe250a51e }, - { 0x00009958, 0x3388ffff }, - { 0x00009940, 0x00781204 }, - { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb514 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x006f00c4 }, - { 0x000099b0, 0x03051000 }, - { 0x000099b4, 0x00000820 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000000 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099fc, 0x00001042 }, - { 0x0000a210, 0x4080a333 }, - { 0x0000a214, 0x40206c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x01834061 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x23277200 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c889af }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x001da000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cdbd380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, - { 0x0000a358, 0x7999aa0f }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, - { 0x0000a3e4, 0x00000000 }, - { 0x0000a3e8, 0x18c43433 }, - { 0x0000a3ec, 0x00f38081 }, - { 0x00007800, 0x00040000 }, - { 0x00007804, 0xdb005012 }, - { 0x00007808, 0x04924914 }, - { 0x0000780c, 0x21084210 }, - { 0x00007810, 0x6d801300 }, - { 0x00007814, 0x0019beff }, - { 0x00007818, 0x07e40000 }, - { 0x0000781c, 0x00492000 }, - { 0x00007820, 0x92492480 }, - { 0x00007824, 0x00040000 }, - { 0x00007828, 0xdb005012 }, - { 0x0000782c, 0x04924914 }, - { 0x00007830, 0x21084210 }, - { 0x00007834, 0x6d801300 }, - { 0x00007838, 0x0019beff }, - { 0x0000783c, 0x07e40000 }, - { 0x00007840, 0x00492000 }, - { 0x00007844, 0x92492480 }, - { 0x00007848, 0x00120000 }, - { 0x00007850, 0x54214514 }, - { 0x00007858, 0x92592692 }, - { 0x00007860, 0x52802000 }, - { 0x00007864, 0x0a8e370e }, - { 0x00007868, 0xc0102850 }, - { 0x0000786c, 0x812d4000 }, - { 0x00007874, 0x001b6db0 }, - { 0x00007878, 0x00376b63 }, - { 0x0000787c, 0x06db6db6 }, - { 0x00007880, 0x006d8000 }, - { 0x00007884, 0xffeffffe }, - { 0x00007888, 0xffeffffe }, - { 0x00007890, 0x00060aeb }, - { 0x00007894, 0x5a108000 }, - { 0x00007898, 0x2a850160 }, -}; - -/* XXX 9280 2 */ -static const u32 ar9280Modes_9280_2[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, - { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, - { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a }, - { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, - { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, - { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e }, - { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, - { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, - { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 }, - { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, - { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, - { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, - { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c }, - { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 }, - { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, - { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, - { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, - { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, - { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, -}; - -static const u32 ar9280Common_9280_2[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00004024, 0x0000001f }, - { 0x00004060, 0x00000000 }, - { 0x00004064, 0x00000000 }, - { 0x00007010, 0x00000033 }, - { 0x00007034, 0x00000002 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x00008070, 0x00000000 }, - { 0x000080c0, 0x2a80001a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0xffffffff }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c0, 0x00000000 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x0000829c, 0x00000000 }, - { 0x00008300, 0x00000040 }, - { 0x00008314, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00ff0000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00008344, 0x00581043 }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xafa68e30 }, - { 0x00009810, 0xfd14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x0000984c, 0x0040233c }, - { 0x0000a84c, 0x0040233c }, - { 0x00009854, 0x00000044 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x00009910, 0x01002310 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x04900000 }, - { 0x0000a920, 0x04900000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280c00a }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0x5f3ca3de }, - { 0x00009958, 0x2108ecff }, - { 0x00009940, 0x14750604 }, - { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x006f0000 }, - { 0x000099b0, 0x03051000 }, - { 0x000099b4, 0x00000820 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000000 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099f0, 0x00000000 }, - { 0x000099fc, 0x00001042 }, - { 0x0000a208, 0x803e4788 }, - { 0x0000a210, 0x4080a333 }, - { 0x0000a214, 0x40206c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x01834061 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x233f7180 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c88000 }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cdbd380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, - { 0x0000a3e4, 0x00000000 }, - { 0x0000a3e8, 0x18c43433 }, - { 0x0000a3ec, 0x00f70081 }, - { 0x00007800, 0x00040000 }, - { 0x00007804, 0xdb005012 }, - { 0x00007808, 0x04924914 }, - { 0x0000780c, 0x21084210 }, - { 0x00007810, 0x6d801300 }, - { 0x00007818, 0x07e41000 }, - { 0x00007824, 0x00040000 }, - { 0x00007828, 0xdb005012 }, - { 0x0000782c, 0x04924914 }, - { 0x00007830, 0x21084210 }, - { 0x00007834, 0x6d801300 }, - { 0x0000783c, 0x07e40000 }, - { 0x00007848, 0x00100000 }, - { 0x0000784c, 0x773f0567 }, - { 0x00007850, 0x54214514 }, - { 0x00007854, 0x12035828 }, - { 0x00007858, 0x9259269a }, - { 0x00007860, 0x52802000 }, - { 0x00007864, 0x0a8e370e }, - { 0x00007868, 0xc0102850 }, - { 0x0000786c, 0x812d4000 }, - { 0x00007870, 0x807ec400 }, - { 0x00007874, 0x001b6db0 }, - { 0x00007878, 0x00376b63 }, - { 0x0000787c, 0x06db6db6 }, - { 0x00007880, 0x006d8000 }, - { 0x00007884, 0xffeffffe }, - { 0x00007888, 0xffeffffe }, - { 0x0000788c, 0x00010000 }, - { 0x00007890, 0x02060aeb }, - { 0x00007898, 0x2a850160 }, -}; - -static const u32 ar9280Modes_fast_clock_9280_2[][3] = { - { 0x00001030, 0x00000268, 0x000004d0 }, - { 0x00001070, 0x0000018c, 0x00000318 }, - { 0x000010b0, 0x00000fd0, 0x00001fa0 }, - { 0x00008014, 0x044c044c, 0x08980898 }, - { 0x0000801c, 0x148ec02b, 0x148ec057 }, - { 0x00008318, 0x000044c0, 0x00008980 }, - { 0x00009820, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000f0f, 0x00000f0f }, - { 0x00009828, 0x0b020001, 0x0b020001 }, - { 0x00009834, 0x00000f0f, 0x00000f0f }, - { 0x00009844, 0x03721821, 0x03721821 }, - { 0x00009914, 0x00000898, 0x00001130 }, - { 0x00009918, 0x0000000b, 0x00000016 }, -}; - -static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = { - { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, - { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, - { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, - { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, - { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, - { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, - { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, - { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, - { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, - { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, - { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, - { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, - { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, - { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, - { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, - { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, - { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, - { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, - { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, - { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, - { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, - { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, - { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, - { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, - { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, - { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, - { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, - { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, - { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, - { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, - { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, - { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, - { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, - { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, - { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, - { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, - { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, - { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, - { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, - { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, - { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, - { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, - { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, - { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, - { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, - { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, - { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, - { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, - { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 }, - { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 }, - { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 }, - { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 }, - { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 }, - { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d }, - { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 }, - { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 }, - { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 }, - { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 }, - { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a }, - { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e }, - { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 }, - { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 }, - { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 }, - { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 }, - { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b }, - { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f }, - { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 }, - { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 }, - { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 }, - { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 }, - { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b }, - { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f }, - { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 }, - { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 }, - { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 }, - { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 }, - { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b }, - { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f }, - { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 }, - { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 }, - { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, - { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, - { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, -}; - -static const u32 ar9280Modes_original_rxgain_9280_2[][6] = { - { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, - { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, - { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, - { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, - { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, - { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, - { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, - { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, - { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, - { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, - { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, - { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, - { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, - { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, - { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, - { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, - { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, - { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, - { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, - { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, - { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, - { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, - { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, - { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, - { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, - { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, - { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, - { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, - { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, - { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, - { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, - { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, - { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, - { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, - { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, - { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, - { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, - { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, - { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, - { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, - { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, - { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, - { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, - { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, - { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, - { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, - { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, - { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, - { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, - { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, - { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, - { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, - { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, - { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, - { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, - { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, - { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, - { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, - { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, - { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, - { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, - { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, - { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, - { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, - { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, - { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, - { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, - { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, - { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, - { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, - { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, - { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, - { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, - { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, - { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, - { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, - { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, - { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, - { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, - { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, - { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, - { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, - { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, - { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, - { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, - { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, - { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, - { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, - { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, - { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, - { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, - { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, - { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, - { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, - { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, - { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, - { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, - { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, - { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, - { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, - { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, -}; - -static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = { - { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, - { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, - { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, - { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, - { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, - { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, - { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, - { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, - { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, - { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, - { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, - { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, - { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, - { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, - { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, - { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, - { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, - { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, - { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, - { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, - { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, - { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, - { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, - { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, - { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, - { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, - { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, - { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, - { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, - { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, - { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, - { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, - { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, - { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, - { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, - { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, - { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, - { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, - { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, - { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, - { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, - { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, - { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, - { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, - { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, - { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, - { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, - { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, - { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, - { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, - { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, - { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, - { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, - { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, - { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, - { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, - { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, - { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, - { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 }, - { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 }, - { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 }, - { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 }, - { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 }, - { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c }, - { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 }, - { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 }, - { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 }, - { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 }, - { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 }, - { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d }, - { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 }, - { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 }, - { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 }, - { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 }, - { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a }, - { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e }, - { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 }, - { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 }, - { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 }, - { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 }, - { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b }, - { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f }, - { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 }, - { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 }, - { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 }, - { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 }, - { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b }, - { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f }, - { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 }, - { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 }, - { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, - { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, - { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, -}; - -static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 }, - { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 }, - { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 }, - { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 }, - { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 }, - { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a }, - { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 }, - { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, - { 0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411 }, - { 0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413 }, - { 0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811 }, - { 0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813 }, - { 0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14 }, - { 0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50 }, - { 0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c }, - { 0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a }, - { 0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92 }, - { 0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 }, - { 0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 }, - { 0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 }, - { 0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5 }, - { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, - { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, - { 0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 }, - { 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 }, - { 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, - { 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, - { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, -}; - -static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, - { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, - { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, - { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, - { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, - { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, - { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, - { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, - { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, - { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, - { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, - { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, - { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, - { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, - { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, - { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, - { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, - { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, - { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, - { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, - { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, - { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, - { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, - { 0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 }, - { 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 }, - { 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, - { 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, - { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, -}; - -static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0xc01dcffc }, - {0x00004040, 0x1aaabe41 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, -}; - -static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0xc01dcffd }, - {0x00004040, 0x1aaabe41 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, -}; - -/* AR9285 */ -static const u_int32_t ar9285Modes_9285[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, - { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, - { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 }, - { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, - { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, - { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, - { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, - { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, - { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, - { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 }, - { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c }, - { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, - { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, - { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, - { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, - { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, - { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, - { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, - { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, - { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, - { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, - { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, - { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, - { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, - { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, - { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, - { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, - { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, - { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, - { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, - { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, - { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, - { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, - { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, - { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, - { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, - { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, - { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, - { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, - { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, - { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, - { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, - { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, - { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, - { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, - { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, - { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, - { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, - { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, - { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, - { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, - { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, - { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, - { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, - { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, - { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, - { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, - { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, - { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, - { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, - { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, - { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, - { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, - { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, - { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, - { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, - { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, - { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, - { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, - { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, - { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, - { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, - { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, - { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, - { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, - { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, - { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, - { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, - { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, - { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, - { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, - { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, - { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, - { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, - { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, - { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, - { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, - { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, - { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, - { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, - { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, - { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, - { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, - { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, - { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, - { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, - { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, - { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, - { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, - { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, - { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, - { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, - { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, - { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, - { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, - { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, - { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, - { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, - { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, - { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, - { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, - { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, - { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, - { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, - { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, - { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, - { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, - { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, - { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, - { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, - { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, - { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, - { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, - { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, - { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, - { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, - { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, - { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, - { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, - { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, - { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, - { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, - { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, - { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, - { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, - { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, - { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, - { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, - { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, - { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, - { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, - { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, - { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, - { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, - { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, - { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, - { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, - { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, - { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, - { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, - { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, - { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, - { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, - { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, - { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, - { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, - { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, - { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, - { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, - { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, - { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, - { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, - { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, - { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, - { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, - { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, - { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, - { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, - { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, - { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, - { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, - { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, - { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, - { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, - { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, - { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, - { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, - { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, - { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, - { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, - { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, - { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, - { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, - { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, - { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, - { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, - { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, - { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, - { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, - { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, - { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 }, - { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, - { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, - { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, - { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, - { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, - { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, - { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, - { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 }, - { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 }, - { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 }, - { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 }, - { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 }, - { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 }, - { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, -}; - -static const u_int32_t ar9285Common_9285[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020045 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00004024, 0x0000001f }, - { 0x00004060, 0x00000000 }, - { 0x00004064, 0x00000000 }, - { 0x00007010, 0x00000031 }, - { 0x00007034, 0x00000002 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x00000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x00008070, 0x00000000 }, - { 0x000080c0, 0x2a80001a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c0, 0x00000000 }, - { 0x000081d0, 0x00003210 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x0000829c, 0x00000000 }, - { 0x00008300, 0x00000040 }, - { 0x00008314, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000001 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x00010380 }, - { 0x00008344, 0x00581043 }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xafe68e30 }, - { 0x00009810, 0xfd14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x0000984c, 0x0040233c }, - { 0x00009854, 0x00000044 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x00009910, 0x01002310 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x04900000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009940, 0x14750604 }, - { 0x00009948, 0x9280c00a }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0x5f3ca3de }, - { 0x00009958, 0x2108ecff }, - { 0x00009968, 0x000003ce }, - { 0x00009970, 0x1927b515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x2def0a00 }, - { 0x000099b0, 0x03051000 }, - { 0x000099b4, 0x00000820 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000000 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099f0, 0x00000000 }, - { 0x0000a208, 0x803e6788 }, - { 0x0000a210, 0x4080a333 }, - { 0x0000a214, 0x00206c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x01834061 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x00000000 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a244, 0x00000000 }, - { 0x0000a248, 0xfffffffc }, - { 0x0000a24c, 0x00000000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0ccb5380 }, - { 0x0000a25c, 0x15151501 }, - { 0x0000a260, 0xdfa90f01 }, - { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9e6 }, - { 0x0000d270, 0x0d820820 }, - { 0x0000a278, 0x39ce739c }, - { 0x0000a27c, 0x050e039c }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x39ce739c }, - { 0x0000a398, 0x0000039c }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x39ce739c }, - { 0x0000a3e0, 0x0000039c }, - { 0x0000a3e4, 0x00000000 }, - { 0x0000a3e8, 0x18c43433 }, - { 0x0000a3ec, 0x00f70081 }, - { 0x00007800, 0x00140000 }, - { 0x00007804, 0x0e4548d8 }, - { 0x00007808, 0x54214514 }, - { 0x0000780c, 0x02025820 }, - { 0x00007810, 0x71c0d388 }, - { 0x00007814, 0x924934a8 }, - { 0x0000781c, 0x00000000 }, - { 0x00007820, 0x00000c04 }, - { 0x00007824, 0x00d86fff }, - { 0x00007828, 0x26d2491b }, - { 0x0000782c, 0x6e36d97b }, - { 0x00007830, 0xedb6d96c }, - { 0x00007834, 0x71400086 }, - { 0x00007838, 0xfac68800 }, - { 0x0000783c, 0x0001fffe }, - { 0x00007840, 0xffeb1a20 }, - { 0x00007844, 0x000c0db6 }, - { 0x00007848, 0x6db61b6f }, - { 0x0000784c, 0x6d9b66db }, - { 0x00007850, 0x6d8c6dba }, - { 0x00007854, 0x00040000 }, - { 0x00007858, 0xdb003012 }, - { 0x0000785c, 0x04924914 }, - { 0x00007860, 0x21084210 }, - { 0x00007864, 0xf7d7ffde }, - { 0x00007868, 0xc2034080 }, - { 0x0000786c, 0x48609eb4 }, - { 0x00007870, 0x10142c00 }, -}; - -static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0xc01dcffd }, - {0x00004040, 0x1aaabe41 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, -}; - -static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0xc01dcffc }, - {0x00004040, 0x1aaabe41 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, -}; - -/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */ -static const u_int32_t ar9285Modes_9285_1_2[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, - { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, - { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, - { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, - { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, - { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, - { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, - { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, - { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, - { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 }, - { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c }, - { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, - { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, - { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, - { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, - { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, - { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, - { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, - { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, - { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, - { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, - { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, - { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, - { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, - { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, - { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, - { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, - { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, - { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, - { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, - { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, - { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, - { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, - { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, - { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, - { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, - { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, - { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, - { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, - { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, - { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, - { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, - { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, - { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, - { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, - { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, - { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, - { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, - { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, - { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, - { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, - { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, - { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, - { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, - { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, - { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, - { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, - { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, - { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, - { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, - { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, - { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, - { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, - { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, - { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, - { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, - { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, - { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, - { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, - { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, - { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, - { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, - { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, - { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, - { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, - { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, - { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, - { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, - { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, - { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, - { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, - { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, - { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, - { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, - { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, - { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, - { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, - { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, - { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, - { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, - { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, - { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, - { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, - { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, - { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, - { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, - { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, - { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, - { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, - { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, - { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, - { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, - { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, - { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, - { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, - { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, - { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, - { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, - { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, - { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, - { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, - { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, - { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, - { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, - { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, - { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, - { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, - { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, - { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, - { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, - { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, - { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, - { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, - { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, - { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, - { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, - { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, - { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, - { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, - { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, - { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, - { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, - { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, - { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, - { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, - { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, - { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, - { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, - { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, - { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, - { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, - { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, - { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, - { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, - { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, - { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, - { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, - { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, - { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, - { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, - { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, - { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, - { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, - { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, - { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, - { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, - { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, - { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, - { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, - { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, - { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, - { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, - { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, - { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, - { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, - { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, - { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, - { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, - { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, - { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, - { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, - { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, - { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, - { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, - { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, - { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, - { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, - { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, - { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, - { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, - { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, - { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, - { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, - { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, - { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, - { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, - { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, - { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, -}; - -static const u_int32_t ar9285Common_9285_1_2[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020045 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00004024, 0x0000001f }, - { 0x00004060, 0x00000000 }, - { 0x00004064, 0x00000000 }, - { 0x00007010, 0x00000031 }, - { 0x00007034, 0x00000002 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x00000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x00008070, 0x00000000 }, - { 0x000080c0, 0x2a80001a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04810 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0xffffffff }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c0, 0x00000000 }, - { 0x000081d0, 0x0000320a }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x0000829c, 0x00000000 }, - { 0x00008300, 0x00000040 }, - { 0x00008314, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000001 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00ff0000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x00010380 }, - { 0x00008344, 0x00581043 }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xafe68e30 }, - { 0x00009810, 0xfd14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x0000984c, 0x0040233c }, - { 0x00009854, 0x00000044 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x00009910, 0x01002310 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x04900000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009940, 0x14750604 }, - { 0x00009948, 0x9280c00a }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0x5f3ca3de }, - { 0x00009958, 0x2108ecff }, - { 0x00009968, 0x000003ce }, - { 0x00009970, 0x192bb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x2def0400 }, - { 0x000099b0, 0x03051000 }, - { 0x000099b4, 0x00000820 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000000 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099f0, 0x00000000 }, - { 0x0000a208, 0x803e68c8 }, - { 0x0000a210, 0x4080a333 }, - { 0x0000a214, 0x00206c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x01834061 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x00000000 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a244, 0x00000000 }, - { 0x0000a248, 0xfffffffc }, - { 0x0000a24c, 0x00000000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0ccb5380 }, - { 0x0000a25c, 0x15151501 }, - { 0x0000a260, 0xdfa90f01 }, - { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9e6 }, - { 0x0000d270, 0x0d820820 }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3e4, 0x00000000 }, - { 0x0000a3e8, 0x18c43433 }, - { 0x0000a3ec, 0x00f70081 }, - { 0x00007800, 0x00140000 }, - { 0x00007804, 0x0e4548d8 }, - { 0x00007808, 0x54214514 }, - { 0x0000780c, 0x02025820 }, - { 0x00007810, 0x71c0d388 }, - { 0x00007814, 0x924934a8 }, - { 0x0000781c, 0x00000000 }, - { 0x00007824, 0x00d86fff }, - { 0x00007828, 0x26d2491b }, - { 0x0000782c, 0x6e36d97b }, - { 0x00007830, 0xedb6d96e }, - { 0x00007834, 0x71400087 }, - { 0x0000783c, 0x0001fffe }, - { 0x00007840, 0xffeb1a20 }, - { 0x00007844, 0x000c0db6 }, - { 0x00007848, 0x6db61b6f }, - { 0x0000784c, 0x6d9b66db }, - { 0x00007850, 0x6d8c6dba }, - { 0x00007854, 0x00040000 }, - { 0x00007858, 0xdb003012 }, - { 0x0000785c, 0x04924914 }, - { 0x00007860, 0x21084210 }, - { 0x00007864, 0xf7d7ffde }, - { 0x00007868, 0xc2034080 }, - { 0x00007870, 0x10142c00 }, -}; - -static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { - /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 }, - { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, - { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, - { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, - { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 }, - { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 }, - { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 }, - { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 }, - { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 }, - { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, - { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, - { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, - { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, - { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, - { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, - { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, - { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, - { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, - { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, -}; - -static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { - /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, - { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, - { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, - { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 }, - { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 }, - { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 }, - { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 }, - { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 }, - { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 }, - { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 }, - { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, - { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, - { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 }, - { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, - { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, - { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, - { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, - { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c }, - { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, - { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, - { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, - { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, -}; - -static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0xc01dcffd }, - {0x00004040, 0x1aaabe41 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, -}; - -static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0xc01dcffc }, - {0x00004040, 0x1aaabe41 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, -}; diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c deleted file mode 100644 index 8ae4ec2..0000000 --- a/drivers/net/wireless/ath9k/mac.c +++ /dev/null @@ -1,976 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, - struct ath9k_tx_queue_info *qi) -{ - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", - ah->txok_interrupt_mask, ah->txerr_interrupt_mask, - ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, - ah->txurn_interrupt_mask); - - REG_WRITE(ah, AR_IMR_S0, - SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK) - | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC)); - REG_WRITE(ah, AR_IMR_S1, - SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR) - | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL)); - REG_RMW_FIELD(ah, AR_IMR_S2, - AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask); -} - -u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) -{ - return REG_READ(ah, AR_QTXDP(q)); -} - -bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) -{ - REG_WRITE(ah, AR_QTXDP(q), txdp); - - return true; -} - -bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) -{ - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); - - REG_WRITE(ah, AR_Q_TXE, 1 << q); - - return true; -} - -u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) -{ - u32 npend; - - npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; - if (npend == 0) { - - if (REG_READ(ah, AR_Q_TXE) & (1 << q)) - npend = 1; - } - - return npend; -} - -bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) -{ - u32 txcfg, curLevel, newLevel; - enum ath9k_int omask; - - if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD) - return false; - - omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); - - txcfg = REG_READ(ah, AR_TXCFG); - curLevel = MS(txcfg, AR_FTRIG); - newLevel = curLevel; - if (bIncTrigLevel) { - if (curLevel < MAX_TX_FIFO_THRESHOLD) - newLevel++; - } else if (curLevel > MIN_TX_FIFO_THRESHOLD) - newLevel--; - if (newLevel != curLevel) - REG_WRITE(ah, AR_TXCFG, - (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); - - ath9k_hw_set_interrupts(ah, omask); - - ah->tx_trig_level = newLevel; - - return newLevel != curLevel; -} - -bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) -{ -#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */ -#define ATH9K_TIME_QUANTUM 100 /* usec */ - - struct ath9k_hw_capabilities *pCap = &ah->caps; - struct ath9k_tx_queue_info *qi; - u32 tsfLow, j, wait; - u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; - - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " - "invalid queue: %u\n", q); - return false; - } - - qi = &ah->txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " - "inactive queue: %u\n", q); - return false; - } - - REG_WRITE(ah, AR_Q_TXD, 1 << q); - - for (wait = wait_time; wait != 0; wait--) { - if (ath9k_hw_numtxpending(ah, q) == 0) - break; - udelay(ATH9K_TIME_QUANTUM); - } - - if (ath9k_hw_numtxpending(ah, q)) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Num of pending TX Frames %d on Q %d\n", - __func__, ath9k_hw_numtxpending(ah, q), q); - - for (j = 0; j < 2; j++) { - tsfLow = REG_READ(ah, AR_TSF_L32); - REG_WRITE(ah, AR_QUIET2, - SM(10, AR_QUIET2_QUIET_DUR)); - REG_WRITE(ah, AR_QUIET_PERIOD, 100); - REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_QUIET_TIMER_EN); - - if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) - break; - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "TSF has moved while trying to set " - "quiet time TSF: 0x%08x\n", tsfLow); - } - - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); - - udelay(200); - REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); - - wait = wait_time; - while (ath9k_hw_numtxpending(ah, q)) { - if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "Failed to stop TX DMA in 100 " - "msec after killing last frame\n"); - break; - } - udelay(ATH9K_TIME_QUANTUM); - } - - REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); - } - - REG_WRITE(ah, AR_Q_TXD, 0); - return wait != 0; - -#undef ATH9K_TX_STOP_DMA_TIMEOUT -#undef ATH9K_TIME_QUANTUM -} - -bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (firstSeg) { - ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); - } else if (lastSeg) { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen; - ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; - ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; - } else { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen | AR_TxMore; - ads->ds_ctl2 = 0; - ads->ds_ctl3 = 0; - } - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - - return true; -} - -void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; -} - -int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if ((ads->ds_txstatus9 & AR_TxDone) == 0) - return -EINPROGRESS; - - ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); - ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; - ds->ds_txstat.ts_status = 0; - ds->ds_txstat.ts_flags = 0; - - if (ads->ds_txstatus1 & AR_ExcessiveRetries) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; - if (ads->ds_txstatus1 & AR_Filtered) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; - if (ads->ds_txstatus1 & AR_FIFOUnderrun) { - ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus9 & AR_TxOpExceeded) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; - if (ads->ds_txstatus1 & AR_TxTimerExpired) - ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; - - if (ads->ds_txstatus1 & AR_DescCfgErr) - ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; - if (ads->ds_txstatus1 & AR_TxDataUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus0 & AR_TxBaStatus) { - ds->ds_txstat.ts_flags |= ATH9K_TX_BA; - ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; - ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; - } - - ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); - switch (ds->ds_txstat.ts_rateindex) { - case 0: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); - break; - case 1: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); - break; - case 2: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); - break; - case 3: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); - break; - } - - ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); - ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); - ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); - ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); - ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); - ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); - ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); - ds->ds_txstat.evm0 = ads->AR_TxEVM0; - ds->ds_txstat.evm1 = ads->AR_TxEVM1; - ds->ds_txstat.evm2 = ads->AR_TxEVM2; - ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); - ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); - ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ds->ds_txstat.ts_antenna = 0; - - return 0; -} - -void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - txPower += ah->txpower_indexoffset; - if (txPower > 63) - txPower = 63; - - ads->ds_ctl0 = (pktLen & AR_FrameLen) - | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(txPower, AR_XmitPower) - | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) - | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) - | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); - - ads->ds_ctl1 = - (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) - | SM(type, AR_FrameType) - | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) - | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) - | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); - - ads->ds_ctl6 = SM(keyType, AR_EncrType); - - if (AR_SREV_9285(ah)) { - ads->ds_ctl8 = 0; - ads->ds_ctl9 = 0; - ads->ds_ctl10 = 0; - ads->ds_ctl11 = 0; - } -} - -void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - struct ar5416_desc *last_ads = AR5416DESC(lastds); - u32 ds_ctl0; - - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { - ds_ctl0 = ads->ds_ctl0; - - if (flags & ATH9K_TXDESC_RTSENA) { - ds_ctl0 &= ~AR_CTSEnable; - ds_ctl0 |= AR_RTSEnable; - } else { - ds_ctl0 &= ~AR_RTSEnable; - ds_ctl0 |= AR_CTSEnable; - } - - ads->ds_ctl0 = ds_ctl0; - } else { - ads->ds_ctl0 = - (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); - } - - ads->ds_ctl2 = set11nTries(series, 0) - | set11nTries(series, 1) - | set11nTries(series, 2) - | set11nTries(series, 3) - | (durUpdateEn ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); - - ads->ds_ctl3 = set11nRate(series, 0) - | set11nRate(series, 1) - | set11nRate(series, 2) - | set11nRate(series, 3); - - ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) - | set11nPktDurRTSCTS(series, 1); - - ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) - | set11nPktDurRTSCTS(series, 3); - - ads->ds_ctl7 = set11nRateFlags(series, 0) - | set11nRateFlags(series, 1) - | set11nRateFlags(series, 2) - | set11nRateFlags(series, 3) - | SM(rtsctsRate, AR_RTSCTSRate); - last_ads->ds_ctl2 = ads->ds_ctl2; - last_ads->ds_ctl3 = ads->ds_ctl3; -} - -void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, - u32 aggrLen) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); - ads->ds_ctl6 &= ~AR_AggrLen; - ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); -} - -void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, - u32 numDelims) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - unsigned int ctl6; - - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); - - ctl6 = ads->ds_ctl6; - ctl6 &= ~AR_PadDelim; - ctl6 |= SM(numDelims, AR_PadDelim); - ads->ds_ctl6 = ctl6; -} - -void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= AR_IsAggr; - ads->ds_ctl1 &= ~AR_MoreAggr; - ads->ds_ctl6 &= ~AR_PadDelim; -} - -void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); -} - -void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, - u32 burstDuration) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); -} - -void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; -} - -void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) -{ - *txqs &= ah->intr_txqs; - ah->intr_txqs &= ~(*txqs); -} - -bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, - const struct ath9k_tx_queue_info *qinfo) -{ - u32 cw; - struct ath9k_hw_capabilities *pCap = &ah->caps; - struct ath9k_tx_queue_info *qi; - - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " - "invalid queue: %u\n", q); - return false; - } - - qi = &ah->txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " - "inactive queue: %u\n", q); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); - - qi->tqi_ver = qinfo->tqi_ver; - qi->tqi_subtype = qinfo->tqi_subtype; - qi->tqi_qflags = qinfo->tqi_qflags; - qi->tqi_priority = qinfo->tqi_priority; - if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) - qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); - else - qi->tqi_aifs = INIT_AIFS; - if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmin, 1024U); - qi->tqi_cwmin = 1; - while (qi->tqi_cwmin < cw) - qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; - } else - qi->tqi_cwmin = qinfo->tqi_cwmin; - if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmax, 1024U); - qi->tqi_cwmax = 1; - while (qi->tqi_cwmax < cw) - qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; - } else - qi->tqi_cwmax = INIT_CWMAX; - - if (qinfo->tqi_shretry != 0) - qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); - else - qi->tqi_shretry = INIT_SH_RETRY; - if (qinfo->tqi_lgretry != 0) - qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); - else - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; - qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; - qi->tqi_burstTime = qinfo->tqi_burstTime; - qi->tqi_readyTime = qinfo->tqi_readyTime; - - switch (qinfo->tqi_subtype) { - case ATH9K_WME_UPSD: - if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) - qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; - break; - default: - break; - } - - return true; -} - -bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, - struct ath9k_tx_queue_info *qinfo) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - struct ath9k_tx_queue_info *qi; - - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " - "invalid queue: %u\n", q); - return false; - } - - qi = &ah->txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " - "inactive queue: %u\n", q); - return false; - } - - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_ver = qi->tqi_ver; - qinfo->tqi_subtype = qi->tqi_subtype; - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_priority = qi->tqi_priority; - qinfo->tqi_aifs = qi->tqi_aifs; - qinfo->tqi_cwmin = qi->tqi_cwmin; - qinfo->tqi_cwmax = qi->tqi_cwmax; - qinfo->tqi_shretry = qi->tqi_shretry; - qinfo->tqi_lgretry = qi->tqi_lgretry; - qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; - qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; - qinfo->tqi_burstTime = qi->tqi_burstTime; - qinfo->tqi_readyTime = qi->tqi_readyTime; - - return true; -} - -int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo) -{ - struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->caps; - int q; - - switch (type) { - case ATH9K_TX_QUEUE_BEACON: - q = pCap->total_queues - 1; - break; - case ATH9K_TX_QUEUE_CAB: - q = pCap->total_queues - 2; - break; - case ATH9K_TX_QUEUE_PSPOLL: - q = 1; - break; - case ATH9K_TX_QUEUE_UAPSD: - q = pCap->total_queues - 3; - break; - case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < pCap->total_queues; q++) - if (ah->txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "No available TX queue\n"); - return -1; - } - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n", - type); - return -1; - } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); - - qi = &ah->txq[q]; - if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "TX queue: %u already active\n", q); - return -1; - } - memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); - qi->tqi_type = type; - if (qinfo == NULL) { - qi->tqi_qflags = - TXQ_FLAG_TXOKINT_ENABLE - | TXQ_FLAG_TXERRINT_ENABLE - | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; - qi->tqi_aifs = INIT_AIFS; - qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; - qi->tqi_cwmax = INIT_CWMAX; - qi->tqi_shretry = INIT_SH_RETRY; - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_physCompBuf = 0; - } else { - qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; - (void) ath9k_hw_set_txq_props(ah, q, qinfo); - } - - return q; -} - -bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - struct ath9k_tx_queue_info *qi; - - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " - "invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " - "inactive queue: %u\n", q); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); - - qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ah->txok_interrupt_mask &= ~(1 << q); - ah->txerr_interrupt_mask &= ~(1 << q); - ah->txdesc_interrupt_mask &= ~(1 << q); - ah->txeol_interrupt_mask &= ~(1 << q); - ah->txurn_interrupt_mask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); - - return true; -} - -bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - struct ath9k_channel *chan = ah->curchan; - struct ath9k_tx_queue_info *qi; - u32 cwMin, chanCwMin, value; - - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " - "invalid queue: %u\n", q); - return false; - } - - qi = &ah->txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " - "inactive queue: %u\n", q); - return true; - } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); - - if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { - if (chan && IS_CHAN_B(chan)) - chanCwMin = INIT_CWMIN_11B; - else - chanCwMin = INIT_CWMIN; - - for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); - } else - cwMin = qi->tqi_cwmin; - - REG_WRITE(ah, AR_DLCL_IFS(q), - SM(cwMin, AR_D_LCL_IFS_CWMIN) | - SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | - SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); - - 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)); - - REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); - REG_WRITE(ah, AR_DMISC(q), - AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); - - if (qi->tqi_cbrPeriod) { - REG_WRITE(ah, AR_QCBRCFG(q), - SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | - SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | - (qi->tqi_cbrOverflowLimit ? - AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); - } - if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { - REG_WRITE(ah, AR_QRDYTIMECFG(q), - SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | - AR_Q_RDYTIMECFG_EN); - } - - REG_WRITE(ah, AR_DCHNTIME(q), - SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | - (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); - - if (qi->tqi_burstTime - && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | - AR_Q_MISC_RDYTIME_EXP_POLICY); - - } - - if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } - if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_FRAG_BKOFF_EN); - } - switch (qi->tqi_type) { - case ATH9K_TX_QUEUE_BEACON: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_BEACON_USE - | AR_Q_MISC_CBR_INCR_DIS1); - - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S) - | AR_D_MISC_BEACON_USE - | AR_D_MISC_POST_FR_BKOFF_DIS); - break; - case ATH9K_TX_QUEUE_CAB: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_CBR_INCR_DIS1 - | AR_Q_MISC_CBR_INCR_DIS0); - value = (qi->tqi_readyTime - - (ah->config.sw_beacon_response_time - - ah->config.dma_beacon_response_time) - - ah->config.additional_swba_backoff) * 1024; - REG_WRITE(ah, AR_QRDYTIMECFG(q), - value | AR_Q_RDYTIMECFG_EN); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); - break; - case ATH9K_TX_QUEUE_PSPOLL: - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); - break; - case ATH9K_TX_QUEUE_UAPSD: - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - break; - default: - break; - } - - if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, - AR_D_MISC_ARB_LOCKOUT_CNTRL) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } - - if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) - ah->txok_interrupt_mask |= 1 << q; - else - ah->txok_interrupt_mask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) - ah->txerr_interrupt_mask |= 1 << q; - else - ah->txerr_interrupt_mask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) - ah->txdesc_interrupt_mask |= 1 << q; - else - ah->txdesc_interrupt_mask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) - ah->txeol_interrupt_mask |= 1 << q; - else - ah->txeol_interrupt_mask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) - ah->txurn_interrupt_mask |= 1 << q; - else - ah->txurn_interrupt_mask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); - - return true; -} - -int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf) -{ - struct ar5416_desc ads; - struct ar5416_desc *adsp = AR5416DESC(ds); - u32 phyerr; - - if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) - return -EINPROGRESS; - - ads.u.rx = adsp->u.rx; - - ds->ds_rxstat.rs_status = 0; - ds->ds_rxstat.rs_flags = 0; - - ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; - ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; - - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); - if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) - ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); - else - ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; - - ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); - ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; - - ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - ds->ds_rxstat.rs_moreaggr = - (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; - ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); - ds->ds_rxstat.rs_flags = - (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; - ds->ds_rxstat.rs_flags |= - (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; - - if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; - if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; - if (ads.ds_rxstatus8 & AR_DecryptBusyErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; - - if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { - if (ads.ds_rxstatus8 & AR_CRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; - else if (ads.ds_rxstatus8 & AR_PHYErr) { - ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; - phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); - ds->ds_rxstat.rs_phyerr = phyerr; - } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; - else if (ads.ds_rxstatus8 & AR_MichaelErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; - } - - return 0; -} - -bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 size, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->caps; - - ads->ds_ctl1 = size & AR_BufLen; - if (flags & ATH9K_RXDESC_INTREQ) - ads->ds_ctl1 |= AR_RxIntrReq; - - ads->ds_rxstatus8 &= ~AR_RxDone; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - memset(&(ads->u), 0, sizeof(ads->u)); - - return true; -} - -bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) -{ - u32 reg; - - if (set) { - REG_SET_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - - if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, - 0, AH_WAIT_TIMEOUT)) { - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | - AR_DIAG_RX_ABORT)); - - reg = REG_READ(ah, AR_OBS_BUS_1); - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "RX failed to go idle in 10 ms RXSM=0x%x\n", reg); - - return false; - } - } else { - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - } - - return true; -} - -void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp) -{ - REG_WRITE(ah, AR_RXDP, rxdp); -} - -void ath9k_hw_rxena(struct ath_hw *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXE); -} - -void ath9k_hw_startpcureceive(struct ath_hw *ah) -{ - ath9k_enable_mib_counters(ah); - - ath9k_ani_reset(ah); - - REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); -} - -void ath9k_hw_stoppcurecv(struct ath_hw *ah) -{ - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); - - ath9k_hw_disable_mib_counters(ah); -} - -bool ath9k_hw_stopdmarecv(struct ath_hw *ah) -{ -#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ -#define AH_RX_TIME_QUANTUM 100 /* usec */ - - int i; - - REG_WRITE(ah, AR_CR, AR_CR_RXD); - - /* Wait for rx enable bit to go low */ - for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { - if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) - break; - udelay(AH_TIME_QUANTUM); - } - - if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "DMA failed to stop in %d ms " - "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", - AH_RX_STOP_DMA_TIMEOUT / 1000, - REG_READ(ah, AR_CR), - REG_READ(ah, AR_DIAG_SW)); - return false; - } else { - return true; - } - -#undef AH_RX_TIME_QUANTUM -#undef AH_RX_STOP_DMA_TIMEOUT -} diff --git a/drivers/net/wireless/ath9k/mac.h b/drivers/net/wireless/ath9k/mac.h deleted file mode 100644 index 1176bce..0000000 --- a/drivers/net/wireless/ath9k/mac.h +++ /dev/null @@ -1,680 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MAC_H -#define MAC_H - -#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ? \ - MS(ads->ds_rxstatus0, AR_RxRate) : \ - (ads->ds_rxstatus3 >> 2) & 0xFF) - -#define set11nTries(_series, _index) \ - (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) - -#define set11nRate(_series, _index) \ - (SM((_series)[_index].Rate, AR_XmitRate##_index)) - -#define set11nPktDurRTSCTS(_series, _index) \ - (SM((_series)[_index].PktDuration, AR_PacketDur##_index) | \ - ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS ? \ - 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)) - -#define CCK_SIFS_TIME 10 -#define CCK_PREAMBLE_BITS 144 -#define CCK_PLCP_BITS 48 - -#define OFDM_SIFS_TIME 16 -#define OFDM_PREAMBLE_TIME 20 -#define OFDM_PLCP_BITS 22 -#define OFDM_SYMBOL_TIME 4 - -#define OFDM_SIFS_TIME_HALF 32 -#define OFDM_PREAMBLE_TIME_HALF 40 -#define OFDM_PLCP_BITS_HALF 22 -#define OFDM_SYMBOL_TIME_HALF 8 - -#define OFDM_SIFS_TIME_QUARTER 64 -#define OFDM_PREAMBLE_TIME_QUARTER 80 -#define OFDM_PLCP_BITS_QUARTER 22 -#define OFDM_SYMBOL_TIME_QUARTER 16 - -#define INIT_AIFS 2 -#define INIT_CWMIN 15 -#define INIT_CWMIN_11B 31 -#define INIT_CWMAX 1023 -#define INIT_SH_RETRY 10 -#define INIT_LG_RETRY 10 -#define INIT_SSH_RETRY 32 -#define INIT_SLG_RETRY 32 - -#define ATH9K_SLOT_TIME_6 6 -#define ATH9K_SLOT_TIME_9 9 -#define ATH9K_SLOT_TIME_20 20 - -#define ATH9K_TXERR_XRETRY 0x01 -#define ATH9K_TXERR_FILT 0x02 -#define ATH9K_TXERR_FIFO 0x04 -#define ATH9K_TXERR_XTXOP 0x08 -#define ATH9K_TXERR_TIMER_EXPIRED 0x10 - -#define ATH9K_TX_BA 0x01 -#define ATH9K_TX_PWRMGMT 0x02 -#define ATH9K_TX_DESC_CFG_ERR 0x04 -#define ATH9K_TX_DATA_UNDERRUN 0x08 -#define ATH9K_TX_DELIM_UNDERRUN 0x10 -#define ATH9K_TX_SW_ABORTED 0x40 -#define ATH9K_TX_SW_FILTERED 0x80 - -#define MIN_TX_FIFO_THRESHOLD 0x1 -#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) -#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD - -struct ath_tx_status { - u32 ts_tstamp; - u16 ts_seqnum; - u8 ts_status; - u8 ts_ratecode; - u8 ts_rateindex; - int8_t ts_rssi; - u8 ts_shortretry; - u8 ts_longretry; - u8 ts_virtcol; - u8 ts_antenna; - u8 ts_flags; - int8_t ts_rssi_ctl0; - int8_t ts_rssi_ctl1; - int8_t ts_rssi_ctl2; - int8_t ts_rssi_ext0; - int8_t ts_rssi_ext1; - int8_t ts_rssi_ext2; - u8 pad[3]; - u32 ba_low; - u32 ba_high; - u32 evm0; - u32 evm1; - u32 evm2; -}; - -struct ath_rx_status { - u32 rs_tstamp; - u16 rs_datalen; - u8 rs_status; - u8 rs_phyerr; - int8_t rs_rssi; - u8 rs_keyix; - u8 rs_rate; - u8 rs_antenna; - u8 rs_more; - int8_t rs_rssi_ctl0; - int8_t rs_rssi_ctl1; - int8_t rs_rssi_ctl2; - int8_t rs_rssi_ext0; - int8_t rs_rssi_ext1; - int8_t rs_rssi_ext2; - u8 rs_isaggr; - u8 rs_moreaggr; - u8 rs_num_delims; - u8 rs_flags; - u32 evm0; - u32 evm1; - u32 evm2; -}; - -#define ATH9K_RXERR_CRC 0x01 -#define ATH9K_RXERR_PHY 0x02 -#define ATH9K_RXERR_FIFO 0x04 -#define ATH9K_RXERR_DECRYPT 0x08 -#define ATH9K_RXERR_MIC 0x10 - -#define ATH9K_RX_MORE 0x01 -#define ATH9K_RX_MORE_AGGR 0x02 -#define ATH9K_RX_GI 0x04 -#define ATH9K_RX_2040 0x08 -#define ATH9K_RX_DELIM_CRC_PRE 0x10 -#define ATH9K_RX_DELIM_CRC_POST 0x20 -#define ATH9K_RX_DECRYPT_BUSY 0x40 - -#define ATH9K_RXKEYIX_INVALID ((u8)-1) -#define ATH9K_TXKEYIX_INVALID ((u32)-1) - -struct ath_desc { - u32 ds_link; - u32 ds_data; - u32 ds_ctl0; - u32 ds_ctl1; - u32 ds_hw[20]; - union { - struct ath_tx_status tx; - struct ath_rx_status rx; - void *stats; - } ds_us; - void *ds_vdata; -} __packed; - -#define ds_txstat ds_us.tx -#define ds_rxstat ds_us.rx -#define ds_stat ds_us.stats - -#define ATH9K_TXDESC_CLRDMASK 0x0001 -#define ATH9K_TXDESC_NOACK 0x0002 -#define ATH9K_TXDESC_RTSENA 0x0004 -#define ATH9K_TXDESC_CTSENA 0x0008 -/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for - * the descriptor its marked on. We take a tx interrupt to reap - * descriptors when the h/w hits an EOL condition or - * when the descriptor is specifically marked to generate - * an interrupt with this flag. Descriptors should be - * marked periodically to insure timely replenishing of the - * supply needed for sending frames. Defering interrupts - * reduces system load and potentially allows more concurrent - * work to be done but if done to aggressively can cause - * senders to backup. When the hardware queue is left too - * large rate control information may also be too out of - * date. An Alternative for this is TX interrupt mitigation - * but this needs more testing. */ -#define ATH9K_TXDESC_INTREQ 0x0010 -#define ATH9K_TXDESC_VEOL 0x0020 -#define ATH9K_TXDESC_EXT_ONLY 0x0040 -#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 - -struct ar5416_desc { - u32 ds_link; - u32 ds_data; - u32 ds_ctl0; - u32 ds_ctl1; - union { - struct { - u32 ctl2; - u32 ctl3; - u32 ctl4; - u32 ctl5; - u32 ctl6; - u32 ctl7; - u32 ctl8; - u32 ctl9; - u32 ctl10; - u32 ctl11; - u32 status0; - u32 status1; - u32 status2; - u32 status3; - u32 status4; - u32 status5; - u32 status6; - u32 status7; - u32 status8; - u32 status9; - } tx; - struct { - u32 status0; - u32 status1; - u32 status2; - u32 status3; - u32 status4; - u32 status5; - u32 status6; - u32 status7; - u32 status8; - } rx; - } u; -} __packed; - -#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds)) -#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds)) - -#define ds_ctl2 u.tx.ctl2 -#define ds_ctl3 u.tx.ctl3 -#define ds_ctl4 u.tx.ctl4 -#define ds_ctl5 u.tx.ctl5 -#define ds_ctl6 u.tx.ctl6 -#define ds_ctl7 u.tx.ctl7 -#define ds_ctl8 u.tx.ctl8 -#define ds_ctl9 u.tx.ctl9 -#define ds_ctl10 u.tx.ctl10 -#define ds_ctl11 u.tx.ctl11 - -#define ds_txstatus0 u.tx.status0 -#define ds_txstatus1 u.tx.status1 -#define ds_txstatus2 u.tx.status2 -#define ds_txstatus3 u.tx.status3 -#define ds_txstatus4 u.tx.status4 -#define ds_txstatus5 u.tx.status5 -#define ds_txstatus6 u.tx.status6 -#define ds_txstatus7 u.tx.status7 -#define ds_txstatus8 u.tx.status8 -#define ds_txstatus9 u.tx.status9 - -#define ds_rxstatus0 u.rx.status0 -#define ds_rxstatus1 u.rx.status1 -#define ds_rxstatus2 u.rx.status2 -#define ds_rxstatus3 u.rx.status3 -#define ds_rxstatus4 u.rx.status4 -#define ds_rxstatus5 u.rx.status5 -#define ds_rxstatus6 u.rx.status6 -#define ds_rxstatus7 u.rx.status7 -#define ds_rxstatus8 u.rx.status8 - -#define AR_FrameLen 0x00000fff -#define AR_VirtMoreFrag 0x00001000 -#define AR_TxCtlRsvd00 0x0000e000 -#define AR_XmitPower 0x003f0000 -#define AR_XmitPower_S 16 -#define AR_RTSEnable 0x00400000 -#define AR_VEOL 0x00800000 -#define AR_ClrDestMask 0x01000000 -#define AR_TxCtlRsvd01 0x1e000000 -#define AR_TxIntrReq 0x20000000 -#define AR_DestIdxValid 0x40000000 -#define AR_CTSEnable 0x80000000 - -#define AR_BufLen 0x00000fff -#define AR_TxMore 0x00001000 -#define AR_DestIdx 0x000fe000 -#define AR_DestIdx_S 13 -#define AR_FrameType 0x00f00000 -#define AR_FrameType_S 20 -#define AR_NoAck 0x01000000 -#define AR_InsertTS 0x02000000 -#define AR_CorruptFCS 0x04000000 -#define AR_ExtOnly 0x08000000 -#define AR_ExtAndCtl 0x10000000 -#define AR_MoreAggr 0x20000000 -#define AR_IsAggr 0x40000000 - -#define AR_BurstDur 0x00007fff -#define AR_BurstDur_S 0 -#define AR_DurUpdateEna 0x00008000 -#define AR_XmitDataTries0 0x000f0000 -#define AR_XmitDataTries0_S 16 -#define AR_XmitDataTries1 0x00f00000 -#define AR_XmitDataTries1_S 20 -#define AR_XmitDataTries2 0x0f000000 -#define AR_XmitDataTries2_S 24 -#define AR_XmitDataTries3 0xf0000000 -#define AR_XmitDataTries3_S 28 - -#define AR_XmitRate0 0x000000ff -#define AR_XmitRate0_S 0 -#define AR_XmitRate1 0x0000ff00 -#define AR_XmitRate1_S 8 -#define AR_XmitRate2 0x00ff0000 -#define AR_XmitRate2_S 16 -#define AR_XmitRate3 0xff000000 -#define AR_XmitRate3_S 24 - -#define AR_PacketDur0 0x00007fff -#define AR_PacketDur0_S 0 -#define AR_RTSCTSQual0 0x00008000 -#define AR_PacketDur1 0x7fff0000 -#define AR_PacketDur1_S 16 -#define AR_RTSCTSQual1 0x80000000 - -#define AR_PacketDur2 0x00007fff -#define AR_PacketDur2_S 0 -#define AR_RTSCTSQual2 0x00008000 -#define AR_PacketDur3 0x7fff0000 -#define AR_PacketDur3_S 16 -#define AR_RTSCTSQual3 0x80000000 - -#define AR_AggrLen 0x0000ffff -#define AR_AggrLen_S 0 -#define AR_TxCtlRsvd60 0x00030000 -#define AR_PadDelim 0x03fc0000 -#define AR_PadDelim_S 18 -#define AR_EncrType 0x0c000000 -#define AR_EncrType_S 26 -#define AR_TxCtlRsvd61 0xf0000000 - -#define AR_2040_0 0x00000001 -#define AR_GI0 0x00000002 -#define AR_ChainSel0 0x0000001c -#define AR_ChainSel0_S 2 -#define AR_2040_1 0x00000020 -#define AR_GI1 0x00000040 -#define AR_ChainSel1 0x00000380 -#define AR_ChainSel1_S 7 -#define AR_2040_2 0x00000400 -#define AR_GI2 0x00000800 -#define AR_ChainSel2 0x00007000 -#define AR_ChainSel2_S 12 -#define AR_2040_3 0x00008000 -#define AR_GI3 0x00010000 -#define AR_ChainSel3 0x000e0000 -#define AR_ChainSel3_S 17 -#define AR_RTSCTSRate 0x0ff00000 -#define AR_RTSCTSRate_S 20 -#define AR_TxCtlRsvd70 0xf0000000 - -#define AR_TxRSSIAnt00 0x000000ff -#define AR_TxRSSIAnt00_S 0 -#define AR_TxRSSIAnt01 0x0000ff00 -#define AR_TxRSSIAnt01_S 8 -#define AR_TxRSSIAnt02 0x00ff0000 -#define AR_TxRSSIAnt02_S 16 -#define AR_TxStatusRsvd00 0x3f000000 -#define AR_TxBaStatus 0x40000000 -#define AR_TxStatusRsvd01 0x80000000 - -#define AR_FrmXmitOK 0x00000001 -#define AR_ExcessiveRetries 0x00000002 -#define AR_FIFOUnderrun 0x00000004 -#define AR_Filtered 0x00000008 -#define AR_RTSFailCnt 0x000000f0 -#define AR_RTSFailCnt_S 4 -#define AR_DataFailCnt 0x00000f00 -#define AR_DataFailCnt_S 8 -#define AR_VirtRetryCnt 0x0000f000 -#define AR_VirtRetryCnt_S 12 -#define AR_TxDelimUnderrun 0x00010000 -#define AR_TxDataUnderrun 0x00020000 -#define AR_DescCfgErr 0x00040000 -#define AR_TxTimerExpired 0x00080000 -#define AR_TxStatusRsvd10 0xfff00000 - -#define AR_SendTimestamp ds_txstatus2 -#define AR_BaBitmapLow ds_txstatus3 -#define AR_BaBitmapHigh ds_txstatus4 - -#define AR_TxRSSIAnt10 0x000000ff -#define AR_TxRSSIAnt10_S 0 -#define AR_TxRSSIAnt11 0x0000ff00 -#define AR_TxRSSIAnt11_S 8 -#define AR_TxRSSIAnt12 0x00ff0000 -#define AR_TxRSSIAnt12_S 16 -#define AR_TxRSSICombined 0xff000000 -#define AR_TxRSSICombined_S 24 - -#define AR_TxEVM0 ds_txstatus5 -#define AR_TxEVM1 ds_txstatus6 -#define AR_TxEVM2 ds_txstatus7 - -#define AR_TxDone 0x00000001 -#define AR_SeqNum 0x00001ffe -#define AR_SeqNum_S 1 -#define AR_TxStatusRsvd80 0x0001e000 -#define AR_TxOpExceeded 0x00020000 -#define AR_TxStatusRsvd81 0x001c0000 -#define AR_FinalTxIdx 0x00600000 -#define AR_FinalTxIdx_S 21 -#define AR_TxStatusRsvd82 0x01800000 -#define AR_PowerMgmt 0x02000000 -#define AR_TxStatusRsvd83 0xfc000000 - -#define AR_RxCTLRsvd00 0xffffffff - -#define AR_BufLen 0x00000fff -#define AR_RxCtlRsvd00 0x00001000 -#define AR_RxIntrReq 0x00002000 -#define AR_RxCtlRsvd01 0xffffc000 - -#define AR_RxRSSIAnt00 0x000000ff -#define AR_RxRSSIAnt00_S 0 -#define AR_RxRSSIAnt01 0x0000ff00 -#define AR_RxRSSIAnt01_S 8 -#define AR_RxRSSIAnt02 0x00ff0000 -#define AR_RxRSSIAnt02_S 16 -#define AR_RxRate 0xff000000 -#define AR_RxRate_S 24 -#define AR_RxStatusRsvd00 0xff000000 - -#define AR_DataLen 0x00000fff -#define AR_RxMore 0x00001000 -#define AR_NumDelim 0x003fc000 -#define AR_NumDelim_S 14 -#define AR_RxStatusRsvd10 0xff800000 - -#define AR_RcvTimestamp ds_rxstatus2 - -#define AR_GI 0x00000001 -#define AR_2040 0x00000002 -#define AR_Parallel40 0x00000004 -#define AR_Parallel40_S 2 -#define AR_RxStatusRsvd30 0x000000f8 -#define AR_RxAntenna 0xffffff00 -#define AR_RxAntenna_S 8 - -#define AR_RxRSSIAnt10 0x000000ff -#define AR_RxRSSIAnt10_S 0 -#define AR_RxRSSIAnt11 0x0000ff00 -#define AR_RxRSSIAnt11_S 8 -#define AR_RxRSSIAnt12 0x00ff0000 -#define AR_RxRSSIAnt12_S 16 -#define AR_RxRSSICombined 0xff000000 -#define AR_RxRSSICombined_S 24 - -#define AR_RxEVM0 ds_rxstatus4 -#define AR_RxEVM1 ds_rxstatus5 -#define AR_RxEVM2 ds_rxstatus6 - -#define AR_RxDone 0x00000001 -#define AR_RxFrameOK 0x00000002 -#define AR_CRCErr 0x00000004 -#define AR_DecryptCRCErr 0x00000008 -#define AR_PHYErr 0x00000010 -#define AR_MichaelErr 0x00000020 -#define AR_PreDelimCRCErr 0x00000040 -#define AR_RxStatusRsvd70 0x00000080 -#define AR_RxKeyIdxValid 0x00000100 -#define AR_KeyIdx 0x0000fe00 -#define AR_KeyIdx_S 9 -#define AR_PHYErrCode 0x0000ff00 -#define AR_PHYErrCode_S 8 -#define AR_RxMoreAggr 0x00010000 -#define AR_RxAggr 0x00020000 -#define AR_PostDelimCRCErr 0x00040000 -#define AR_RxStatusRsvd71 0x3ff80000 -#define AR_DecryptBusyErr 0x40000000 -#define AR_KeyMiss 0x80000000 - -enum ath9k_tx_queue { - ATH9K_TX_QUEUE_INACTIVE = 0, - ATH9K_TX_QUEUE_DATA, - ATH9K_TX_QUEUE_BEACON, - ATH9K_TX_QUEUE_CAB, - ATH9K_TX_QUEUE_UAPSD, - ATH9K_TX_QUEUE_PSPOLL -}; - -#define ATH9K_NUM_TX_QUEUES 10 - -enum ath9k_tx_queue_subtype { - ATH9K_WME_AC_BK = 0, - ATH9K_WME_AC_BE, - ATH9K_WME_AC_VI, - ATH9K_WME_AC_VO, - ATH9K_WME_UPSD -}; - -enum ath9k_tx_queue_flags { - TXQ_FLAG_TXOKINT_ENABLE = 0x0001, - TXQ_FLAG_TXERRINT_ENABLE = 0x0001, - TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, - TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, - TXQ_FLAG_TXURNINT_ENABLE = 0x0008, - TXQ_FLAG_BACKOFF_DISABLE = 0x0010, - TXQ_FLAG_COMPRESSION_ENABLE = 0x0020, - TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040, - TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080, -}; - -#define ATH9K_TXQ_USEDEFAULT ((u32) -1) -#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 - -#define ATH9K_DECOMP_MASK_SIZE 128 -#define ATH9K_READY_TIME_LO_BOUND 50 -#define ATH9K_READY_TIME_HI_BOUND 96 - -enum ath9k_pkt_type { - ATH9K_PKT_TYPE_NORMAL = 0, - ATH9K_PKT_TYPE_ATIM, - ATH9K_PKT_TYPE_PSPOLL, - ATH9K_PKT_TYPE_BEACON, - ATH9K_PKT_TYPE_PROBE_RESP, - ATH9K_PKT_TYPE_CHIRP, - ATH9K_PKT_TYPE_GRP_POLL, -}; - -struct ath9k_tx_queue_info { - u32 tqi_ver; - enum ath9k_tx_queue tqi_type; - enum ath9k_tx_queue_subtype tqi_subtype; - enum ath9k_tx_queue_flags tqi_qflags; - u32 tqi_priority; - u32 tqi_aifs; - u32 tqi_cwmin; - u32 tqi_cwmax; - u16 tqi_shretry; - u16 tqi_lgretry; - u32 tqi_cbrPeriod; - u32 tqi_cbrOverflowLimit; - u32 tqi_burstTime; - u32 tqi_readyTime; - u32 tqi_physCompBuf; - u32 tqi_intFlags; -}; - -enum ath9k_rx_filter { - ATH9K_RX_FILTER_UCAST = 0x00000001, - ATH9K_RX_FILTER_MCAST = 0x00000002, - ATH9K_RX_FILTER_BCAST = 0x00000004, - ATH9K_RX_FILTER_CONTROL = 0x00000008, - ATH9K_RX_FILTER_BEACON = 0x00000010, - ATH9K_RX_FILTER_PROM = 0x00000020, - ATH9K_RX_FILTER_PROBEREQ = 0x00000080, - ATH9K_RX_FILTER_PHYERR = 0x00000100, - ATH9K_RX_FILTER_MYBEACON = 0x00000200, - ATH9K_RX_FILTER_PSPOLL = 0x00004000, - ATH9K_RX_FILTER_PHYRADAR = 0x00002000, - ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, -}; - -#define ATH9K_RATESERIES_RTS_CTS 0x0001 -#define ATH9K_RATESERIES_2040 0x0002 -#define ATH9K_RATESERIES_HALFGI 0x0004 - -struct ath9k_11n_rate_series { - u32 Tries; - u32 Rate; - u32 PktDuration; - u32 ChSel; - u32 RateFlags; -}; - -struct ath9k_keyval { - u8 kv_type; - u8 kv_pad; - u16 kv_len; - u8 kv_val[16]; /* TK */ - u8 kv_mic[8]; /* Michael MIC key */ - u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware - * supports both MIC keys in the same key cache entry; - * in that case, kv_mic is the RX key) */ -}; - -enum ath9k_key_type { - ATH9K_KEY_TYPE_CLEAR, - ATH9K_KEY_TYPE_WEP, - ATH9K_KEY_TYPE_AES, - ATH9K_KEY_TYPE_TKIP, -}; - -enum ath9k_cipher { - ATH9K_CIPHER_WEP = 0, - ATH9K_CIPHER_AES_OCB = 1, - ATH9K_CIPHER_AES_CCM = 2, - ATH9K_CIPHER_CKIP = 3, - ATH9K_CIPHER_TKIP = 4, - ATH9K_CIPHER_CLR = 5, - ATH9K_CIPHER_MIC = 127 -}; - -enum ath9k_ht_macmode { - ATH9K_HT_MACMODE_20 = 0, - ATH9K_HT_MACMODE_2040 = 1, -}; - -enum ath9k_ht_extprotspacing { - ATH9K_HT_EXTPROTSPACING_20 = 0, - ATH9K_HT_EXTPROTSPACING_25 = 1, -}; - -struct ath_hw; -struct ath9k_channel; -struct ath_rate_table; - -u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); -bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); -bool ath9k_hw_txstart(struct ath_hw *ah, u32 q); -u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); -bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); -bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); -bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0); -void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); -int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds); -void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags); -void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags); -void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, - u32 aggrLen); -void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, - u32 numDelims); -void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds); -void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds); -void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, - u32 burstDuration); -void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, - u32 vmf); -void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); -bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, - const struct ath9k_tx_queue_info *qinfo); -bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, - struct ath9k_tx_queue_info *qinfo); -int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo); -bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); -bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); -int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf); -bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 size, u32 flags); -bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); -void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); -void ath9k_hw_rxena(struct ath_hw *ah); -void ath9k_hw_startpcureceive(struct ath_hw *ah); -void ath9k_hw_stoppcurecv(struct ath_hw *ah); -bool ath9k_hw_stopdmarecv(struct ath_hw *ah); - -#endif /* MAC_H */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c deleted file mode 100644 index 8b6a7ea..0000000 --- a/drivers/net/wireless/ath9k/main.c +++ /dev/null @@ -1,2890 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include "ath9k.h" - -#define ATH_PCI_VERSION "0.1" - -static char *dev_info = "ath9k"; - -MODULE_AUTHOR("Atheros Communications"); -MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); -MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); -MODULE_LICENSE("Dual BSD/GPL"); - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); - -/* We use the hw_value as an index into our private channel structure */ - -#define CHAN2G(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 30, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 30, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static struct ieee80211_channel ath9k_2ghz_chantable[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static struct ieee80211_channel ath9k_5ghz_chantable[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -static void ath_cache_conf_rate(struct ath_softc *sc, - struct ieee80211_conf *conf) -{ - switch (conf->channel->band) { - case IEEE80211_BAND_2GHZ: - if (conf_is_ht20(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NG_HT20]; - else if (conf_is_ht40_minus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS]; - else if (conf_is_ht40_plus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS]; - else - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11G]; - break; - case IEEE80211_BAND_5GHZ: - if (conf_is_ht20(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NA_HT20]; - else if (conf_is_ht40_minus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS]; - else if (conf_is_ht40_plus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS]; - else - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11A]; - break; - default: - BUG_ON(1); - break; - } -} - -static void ath_update_txpow(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - u32 txpow; - - if (sc->curtxpow != sc->config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit); - /* read back in case value is clamped */ - ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); - sc->curtxpow = txpow; - } -} - -static u8 parse_mpdudensity(u8 mpdudensity) -{ - /* - * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": - * 0 for no restriction - * 1 for 1/4 us - * 2 for 1/2 us - * 3 for 1 us - * 4 for 2 us - * 5 for 4 us - * 6 for 8 us - * 7 for 16 us - */ - switch (mpdudensity) { - case 0: - return 0; - case 1: - case 2: - case 3: - /* Our lower layer calculations limit our precision to - 1 microsecond */ - return 1; - case 4: - return 2; - case 5: - return 4; - case 6: - return 8; - case 7: - return 16; - default: - return 0; - } -} - -static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) -{ - struct ath_rate_table *rate_table = NULL; - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; - int i, maxrates; - - switch (band) { - case IEEE80211_BAND_2GHZ: - rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; - break; - case IEEE80211_BAND_5GHZ: - rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; - break; - default: - break; - } - - if (rate_table == NULL) - return; - - sband = &sc->sbands[band]; - rate = sc->rates[band]; - - if (rate_table->rate_cnt > ATH_RATE_MAX) - maxrates = ATH_RATE_MAX; - else - maxrates = rate_table->rate_cnt; - - for (i = 0; i < maxrates; i++) { - rate[i].bitrate = rate_table->info[i].ratekbps / 100; - rate[i].hw_value = rate_table->info[i].ratecode; - if (rate_table->info[i].short_preamble) { - rate[i].hw_value_short = rate_table->info[i].ratecode | - rate_table->info[i].short_preamble; - rate[i].flags = IEEE80211_RATE_SHORT_PREAMBLE; - } - sband->n_bitrates++; - - DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", - rate[i].bitrate / 10, rate[i].hw_value); - } -} - -/* - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff. -*/ -int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *hchan) -{ - struct ath_hw *ah = sc->sc_ah; - bool fastcc = true, stopped; - struct ieee80211_channel *channel = hw->conf.channel; - int r; - - if (sc->sc_flags & SC_OP_INVALID) - return -EIO; - - ath9k_ps_wakeup(sc); - - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_set_interrupts(ah, 0); - ath_drain_all_txq(sc, false); - stopped = ath_stoprecv(sc); - - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ - - if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) - fastcc = false; - - DPRINTF(sc, ATH_DBG_CONFIG, - "(%u MHz) -> (%u MHz), chanwidth: %d\n", - sc->sc_ah->curchan->channel, - channel->center_freq, sc->tx_chan_width); - - spin_lock_bh(&sc->sc_resetlock); - - r = ath9k_hw_reset(ah, hchan, fastcc); - if (r) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset channel (%u Mhz) " - "reset status %u\n", - channel->center_freq, r); - spin_unlock_bh(&sc->sc_resetlock); - return r; - } - spin_unlock_bh(&sc->sc_resetlock); - - sc->sc_flags &= ~SC_OP_FULL_RESET; - - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to restart recv logic\n"); - return -EIO; - } - - ath_cache_conf_rate(sc, &hw->conf); - ath_update_txpow(sc); - ath9k_hw_set_interrupts(ah, sc->imask); - ath9k_ps_restore(sc); - return 0; -} - -/* - * 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. - */ -static void ath_ani_calibrate(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - struct ath_hw *ah = sc->sc_ah; - bool longcal = false; - bool shortcal = false; - bool aniflag = false; - unsigned int timestamp = jiffies_to_msecs(jiffies); - u32 cal_interval, short_cal_interval; - - short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? - ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; - - /* - * don't calibrate when we're scanning. - * we are most likely not on our home channel. - */ - if (sc->sc_flags & SC_OP_SCANNING) - goto set_timer; - - /* Long calibration runs independently of short calibration. */ - if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { - longcal = true; - DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); - sc->ani.longcal_timer = timestamp; - } - - /* Short calibration applies only while caldone is false */ - if (!sc->ani.caldone) { - if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { - shortcal = true; - DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); - sc->ani.shortcal_timer = timestamp; - sc->ani.resetcal_timer = timestamp; - } - } else { - if ((timestamp - sc->ani.resetcal_timer) >= - ATH_RESTART_CALINTERVAL) { - sc->ani.caldone = ath9k_hw_reset_calvalid(ah); - if (sc->ani.caldone) - sc->ani.resetcal_timer = timestamp; - } - } - - /* Verify whether we must check ANI */ - if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { - aniflag = true; - sc->ani.checkani_timer = timestamp; - } - - /* 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->nodestats, ah->curchan); - - /* Perform calibration if necessary */ - if (longcal || shortcal) { - bool iscaldone = false; - - if (ath9k_hw_calibrate(ah, ah->curchan, - sc->rx_chainmask, longcal, - &iscaldone)) { - if (longcal) - sc->ani.noise_floor = - ath9k_hw_getchan_noise(ah, - ah->curchan); - - DPRINTF(sc, ATH_DBG_ANI, - "calibrate chan %u/%x nf: %d\n", - ah->curchan->channel, - ah->curchan->channelFlags, - sc->ani.noise_floor); - } else { - DPRINTF(sc, ATH_DBG_ANY, - "calibrate chan %u/%x failed\n", - ah->curchan->channel, - ah->curchan->channelFlags); - } - sc->ani.caldone = iscaldone; - } - } - -set_timer: - /* - * Set timer interval based on previous results. - * The interval must be the shortest necessary to satisfy ANI, - * short calibration and long calibration. - */ - cal_interval = ATH_LONG_CALINTERVAL; - if (sc->sc_ah->config.enable_ani) - cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); - if (!sc->ani.caldone) - cal_interval = min(cal_interval, (u32)short_cal_interval); - - mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); -} - -/* - * Update tx/rx chainmask. For legacy association, - * hard code chainmask to 1x1, for 11n association, use - * the chainmask configuration, for bt coexistence, use - * the chainmask configuration even in legacy mode. - */ -void ath_update_chainmask(struct ath_softc *sc, int is_ht) -{ - if (is_ht || - (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { - sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; - sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; - } else { - sc->tx_chainmask = 1; - sc->rx_chainmask = 1; - } - - DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", - sc->tx_chainmask, sc->rx_chainmask); -} - -static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) -{ - struct ath_node *an; - - an = (struct ath_node *)sta->drv_priv; - - if (sc->sc_flags & SC_OP_TXAGGR) { - ath_tx_node_init(sc, an); - an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); - } -} - -static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - - if (sc->sc_flags & SC_OP_TXAGGR) - ath_tx_node_cleanup(sc, an); -} - -static void ath9k_tasklet(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - u32 status = sc->intrstatus; - - if (status & ATH9K_INT_FATAL) { - ath_reset(sc, false); - return; - } - - if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { - spin_lock_bh(&sc->rx.rxflushlock); - ath_rx_tasklet(sc, 0); - spin_unlock_bh(&sc->rx.rxflushlock); - } - - if (status & ATH9K_INT_TX) - ath_tx_tasklet(sc); - - /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); -} - -irqreturn_t ath_isr(int irq, void *dev) -{ -#define SCHED_INTR ( \ - ATH9K_INT_FATAL | \ - ATH9K_INT_RXORN | \ - ATH9K_INT_RXEOL | \ - ATH9K_INT_RX | \ - ATH9K_INT_TX | \ - ATH9K_INT_BMISS | \ - ATH9K_INT_CST | \ - ATH9K_INT_TSFOOR) - - struct ath_softc *sc = dev; - struct ath_hw *ah = sc->sc_ah; - enum ath9k_int status; - bool sched = false; - - /* - * The hardware is not ready/present, don't - * touch anything. Note this can happen early - * on if the IRQ is shared. - */ - if (sc->sc_flags & SC_OP_INVALID) - return IRQ_NONE; - - ath9k_ps_wakeup(sc); - - /* shared irq, not for us */ - - if (!ath9k_hw_intrpend(ah)) { - ath9k_ps_restore(sc); - return IRQ_NONE; - } - - /* - * Figure out the reason(s) for the interrupt. Note - * that the hal returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. - */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - status &= sc->imask; /* discard unasked-for bits */ - - /* - * If there are no status bits set, then this interrupt was not - * for me (should have been caught above). - */ - if (!status) { - ath9k_ps_restore(sc); - return IRQ_NONE; - } - - /* Cache the status */ - sc->intrstatus = status; - - if (status & SCHED_INTR) - sched = true; - - /* - * If a FATAL or RXORN interrupt is received, we have to reset the - * chip immediately. - */ - if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN)) - goto chip_reset; - - if (status & ATH9K_INT_SWBA) - tasklet_schedule(&sc->bcon_tasklet); - - if (status & ATH9K_INT_TXURN) - ath9k_hw_updatetxtriglevel(ah, true); - - if (status & ATH9K_INT_MIB) { - /* - * Disable interrupts until we service the MIB - * interrupt; otherwise it will continue to - * fire. - */ - ath9k_hw_set_interrupts(ah, 0); - /* - * Let the hal handle the event. We assume - * it will clear whatever condition caused - * the interrupt. - */ - ath9k_hw_procmibevent(ah, &sc->nodestats); - ath9k_hw_set_interrupts(ah, sc->imask); - } - - if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - /* Clear RxAbort bit so that we can - * receive frames */ - ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); - ath9k_hw_setrxabort(ah, 0); - sched = true; - sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; - } - } - -chip_reset: - - ath9k_ps_restore(sc); - ath_debug_stat_interrupt(sc, status); - - if (sched) { - /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA)); - tasklet_schedule(&sc->intr_tq); - } - - return IRQ_HANDLED; - -#undef SCHED_INTR -} - -static u32 ath_get_extchanmode(struct ath_softc *sc, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - u32 chanmode = 0; - - switch (chan->band) { - case IEEE80211_BAND_2GHZ: - switch(channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_G_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_G_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_G_HT40MINUS; - break; - } - break; - case IEEE80211_BAND_5GHZ: - switch(channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_A_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_A_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_A_HT40MINUS; - break; - } - break; - default: - break; - } - - return chanmode; -} - -static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, - struct ath9k_keyval *hk, const u8 *addr, - bool authenticator) -{ - const u8 *key_rxmic; - const u8 *key_txmic; - - key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; - key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; - - if (addr == NULL) { - /* - * Group key installation - only two key cache entries are used - * regardless of splitmic capability since group key is only - * used either for TX or RX. - */ - if (authenticator) { - memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); - memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); - } else { - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); - } - return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); - } - if (!sc->splitmic) { - /* TX and RX keys share the same key cache entry. */ - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); - return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); - } - - /* Separate key cache entries for TX and RX */ - - /* TX key goes at first index, RX key at +32. */ - memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); - if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { - /* TX MIC entry failed. No need to proceed further */ - DPRINTF(sc, ATH_DBG_FATAL, - "Setting TX MIC Key Failed\n"); - return 0; - } - - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - /* XXX delete tx key on failure? */ - return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr); -} - -static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) -{ - int i; - - for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { - if (test_bit(i, sc->keymap) || - test_bit(i + 64, sc->keymap)) - continue; /* At least one part of TKIP key allocated */ - if (sc->splitmic && - (test_bit(i + 32, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) - continue; /* At least one part of TKIP key allocated */ - - /* Found a free slot for a TKIP key */ - return i; - } - return -1; -} - -static int ath_reserve_key_cache_slot(struct ath_softc *sc) -{ - int i; - - /* First, try to find slots that would not be available for TKIP. */ - if (sc->splitmic) { - for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) { - if (!test_bit(i, sc->keymap) && - (test_bit(i + 32, sc->keymap) || - test_bit(i + 64, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) - return i; - if (!test_bit(i + 32, sc->keymap) && - (test_bit(i, sc->keymap) || - test_bit(i + 64, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) - return i + 32; - if (!test_bit(i + 64, sc->keymap) && - (test_bit(i , sc->keymap) || - test_bit(i + 32, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) - return i + 64; - if (!test_bit(i + 64 + 32, sc->keymap) && - (test_bit(i, sc->keymap) || - test_bit(i + 32, sc->keymap) || - test_bit(i + 64, sc->keymap))) - return i + 64 + 32; - } - } else { - for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { - if (!test_bit(i, sc->keymap) && - test_bit(i + 64, sc->keymap)) - return i; - if (test_bit(i, sc->keymap) && - !test_bit(i + 64, sc->keymap)) - return i + 64; - } - } - - /* No partially used TKIP slots, pick any available slot */ - for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) { - /* Do not allow slots that could be needed for TKIP group keys - * to be used. This limitation could be removed if we know that - * TKIP will not be used. */ - if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) - continue; - if (sc->splitmic) { - if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) - continue; - if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) - continue; - } - - if (!test_bit(i, sc->keymap)) - return i; /* Found a free slot for a key */ - } - - /* No free slot found */ - return -1; -} - -static int ath_key_config(struct ath_softc *sc, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct ath9k_keyval hk; - const u8 *mac = NULL; - int ret = 0; - int idx; - - memset(&hk, 0, sizeof(hk)); - - switch (key->alg) { - case ALG_WEP: - hk.kv_type = ATH9K_CIPHER_WEP; - break; - case ALG_TKIP: - hk.kv_type = ATH9K_CIPHER_TKIP; - break; - case ALG_CCMP: - hk.kv_type = ATH9K_CIPHER_AES_CCM; - break; - default: - return -EOPNOTSUPP; - } - - hk.kv_len = key->keylen; - memcpy(hk.kv_val, key->key, key->keylen); - - if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { - /* For now, use the default keys for broadcast keys. This may - * need to change with virtual interfaces. */ - idx = key->keyidx; - } else if (key->keyidx) { - if (WARN_ON(!sta)) - return -EOPNOTSUPP; - mac = sta->addr; - - if (vif->type != NL80211_IFTYPE_AP) { - /* Only keyidx 0 should be used with unicast key, but - * allow this for client mode for now. */ - idx = key->keyidx; - } else - return -EIO; - } else { - if (WARN_ON(!sta)) - return -EOPNOTSUPP; - mac = sta->addr; - - if (key->alg == ALG_TKIP) - idx = ath_reserve_key_cache_slot_tkip(sc); - else - idx = ath_reserve_key_cache_slot(sc); - if (idx < 0) - return -ENOSPC; /* no free key cache entries */ - } - - if (key->alg == ALG_TKIP) - ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac, - vif->type == NL80211_IFTYPE_AP); - else - ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac); - - if (!ret) - return -EIO; - - set_bit(idx, sc->keymap); - if (key->alg == ALG_TKIP) { - set_bit(idx + 64, sc->keymap); - if (sc->splitmic) { - set_bit(idx + 32, sc->keymap); - set_bit(idx + 64 + 32, sc->keymap); - } - } - - return idx; -} - -static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) -{ - ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx); - if (key->hw_key_idx < IEEE80211_WEP_NKID) - return; - - clear_bit(key->hw_key_idx, sc->keymap); - if (key->alg != ALG_TKIP) - return; - - clear_bit(key->hw_key_idx + 64, sc->keymap); - if (sc->splitmic) { - clear_bit(key->hw_key_idx + 32, sc->keymap); - clear_bit(key->hw_key_idx + 64 + 32, sc->keymap); - } -} - -static void setup_ht_cap(struct ath_softc *sc, - struct ieee80211_sta_ht_cap *ht_info) -{ -#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; - - /* set up supported mcs set */ - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - - switch(sc->rx_chainmask) { - case 1: - ht_info->mcs.rx_mask[0] = 0xff; - break; - case 3: - case 5: - case 7: - default: - ht_info->mcs.rx_mask[0] = 0xff; - ht_info->mcs.rx_mask[1] = 0xff; - break; - } - - ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; -} - -static void ath9k_bss_assoc_info(struct ath_softc *sc, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf) -{ - struct ath_vif *avp = (void *)vif->drv_priv; - - if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, sc->curbssid); - - /* New association, store aid */ - if (avp->av_opmode == NL80211_IFTYPE_STATION) { - sc->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc); - } - - /* Configure the beacon */ - ath_beacon_config(sc, vif); - - /* Reset rssi stats */ - sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; - - /* Start ANI */ - mod_timer(&sc->ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); - } else { - DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); - sc->curaid = 0; - } -} - -/********************************/ -/* LED functions */ -/********************************/ - -static void ath_led_blink_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - ath_led_blink_work.work); - - if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) - return; - - if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || - (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); - else - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, - (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); - - queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work, - (sc->sc_flags & SC_OP_LED_ON) ? - msecs_to_jiffies(sc->led_off_duration) : - msecs_to_jiffies(sc->led_on_duration)); - - sc->led_on_duration = sc->led_on_cnt ? - max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : - ATH_LED_ON_DURATION_IDLE; - sc->led_off_duration = sc->led_off_cnt ? - max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : - ATH_LED_OFF_DURATION_IDLE; - sc->led_on_cnt = sc->led_off_cnt = 0; - if (sc->sc_flags & SC_OP_LED_ON) - sc->sc_flags &= ~SC_OP_LED_ON; - else - sc->sc_flags |= SC_OP_LED_ON; -} - -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) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, - (led->led_type == ATH_LED_RADIO)); - sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - if (led->led_type == ATH_LED_RADIO) - sc->sc_flags &= ~SC_OP_LED_ON; - } else { - sc->led_off_cnt++; - } - break; - case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) { - sc->sc_flags |= SC_OP_LED_ASSOCIATED; - queue_delayed_work(sc->hw->workqueue, - &sc->ath_led_blink_work, 0); - } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); - sc->sc_flags |= SC_OP_LED_ON; - } else { - sc->led_on_cnt++; - } - 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) -{ - cancel_delayed_work_sync(&sc->ath_led_blink_work); - 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); - - INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); - - 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); -} - -void ath_radio_enable(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ieee80211_channel *channel = sc->hw->conf.channel; - int r; - - ath9k_ps_wakeup(sc); - spin_lock_bh(&sc->sc_resetlock); - - r = ath9k_hw_reset(ah, ah->curchan, false); - - if (r) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) ", - "reset status %u\n", - channel->center_freq, r); - } - spin_unlock_bh(&sc->sc_resetlock); - - ath_update_txpow(sc); - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to restart recv logic\n"); - return; - } - - if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); /* restart beacons */ - - /* Re-Enable interrupts */ - ath9k_hw_set_interrupts(ah, 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); - ath9k_ps_restore(sc); -} - -void ath_radio_disable(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ieee80211_channel *channel = sc->hw->conf.channel; - int r; - - ath9k_ps_wakeup(sc); - 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_drain_all_txq(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); - r = ath9k_hw_reset(ah, ah->curchan, false); - if (r) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) " - "reset status %u\n", - channel->center_freq, r); - } - spin_unlock_bh(&sc->sc_resetlock); - - ath9k_hw_phy_disable(ah); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); - ath9k_ps_restore(sc); -} - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - -/*******************/ -/* Rfkill */ -/*******************/ - -static bool ath_is_rfkill_set(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == - 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; - - return 0; -} - -/* Deinitialize rfkill */ -static void ath_deinit_rfkill(struct ath_softc *sc) -{ - if (sc->sc_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; - } -} - -static int ath_start_rfkill_poll(struct ath_softc *sc) -{ - if (sc->sc_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 */ - ath_cleanup(sc); - return -EIO; - } else { - sc->sc_flags |= SC_OP_RFKILL_REGISTERED; - } - } - - return 0; -} -#endif /* CONFIG_RFKILL */ - -void ath_cleanup(struct ath_softc *sc) -{ - ath_detach(sc); - free_irq(sc->irq, sc); - ath_bus_cleanup(sc); - kfree(sc->sec_wiphy); - ieee80211_free_hw(sc->hw); -} - -void ath_detach(struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; - int i = 0; - - ath9k_ps_wakeup(sc); - - DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - ath_deinit_rfkill(sc); -#endif - ath_deinit_leds(sc); - cancel_work_sync(&sc->chan_work); - cancel_delayed_work_sync(&sc->wiphy_work); - - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - sc->sec_wiphy[i] = NULL; - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - } - ieee80211_unregister_hw(hw); - ath_rx_cleanup(sc); - ath_tx_cleanup(sc); - - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - - if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - ath9k_hw_detach(sc->sc_ah); - ath9k_exit_debug(sc); - ath9k_ps_restore(sc); -} - -static int ath9k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = &sc->sc_ah->regulatory; - - return ath_reg_notifier_apply(wiphy, request, reg); -} - -static int ath_init(u16 devid, struct ath_softc *sc) -{ - struct ath_hw *ah = NULL; - int status; - int error = 0, i; - int csz = 0; - - /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_flags |= SC_OP_INVALID; - - if (ath9k_init_debug(sc) < 0) - printk(KERN_ERR "Unable to create debugfs files\n"); - - spin_lock_init(&sc->wiphy_lock); - spin_lock_init(&sc->sc_resetlock); - spin_lock_init(&sc->sc_serial_rw); - mutex_init(&sc->mutex); - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, - (unsigned long)sc); - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - ath_read_cachesize(sc, &csz); - /* XXX assert csz is non-zero */ - sc->cachelsz = csz << 2; /* convert to bytes */ - - ah = ath9k_hw_attach(devid, sc, &status); - if (ah == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to attach hardware; HAL status %d\n", status); - error = -ENXIO; - goto bad; - } - sc->sc_ah = ah; - - /* Get the hardware key cache size. */ - sc->keymax = ah->caps.keycache_size; - if (sc->keymax > ATH_KEYMAX) { - DPRINTF(sc, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, sc->keymax); - sc->keymax = ATH_KEYMAX; - } - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < sc->keymax; i++) - ath9k_hw_keyreset(ah, (u16) i); - - if (ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, - ath9k_reg_notifier)) - goto bad; - - /* default to MONITOR mode */ - sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; - - /* Setup rate tables */ - - ath_rate_attach(sc); - ath_setup_rates(sc, IEEE80211_BAND_2GHZ); - ath_setup_rates(sc, IEEE80211_BAND_5GHZ); - - /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that the hal handles reseting - * these queues at the needed time. - */ - sc->beacon.beaconq = ath_beaconq_setup(ah); - if (sc->beacon.beaconq == -1) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to setup a beacon xmit queue\n"); - error = -EIO; - goto bad2; - } - sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->beacon.cabq == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to setup CAB xmit queue\n"); - error = -EIO; - goto bad2; - } - - sc->config.cabqReadytime = ATH_CABQ_READY_TIME; - ath_cabq_update(sc); - - for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) - sc->tx.hwq_map[i] = -1; - - /* Setup data queues */ - /* NB: ensure BK queue is the lowest priority h/w queue */ - if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to setup xmit queue for BK traffic\n"); - error = -EIO; - goto bad2; - } - - if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to setup xmit queue for BE traffic\n"); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to setup xmit queue for VI traffic\n"); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to setup xmit queue for VO traffic\n"); - error = -EIO; - goto bad2; - } - - /* Initializes the noise floor to a reasonable default value. - * Later on this will be updated during ANI processing. */ - - sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; - setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc); - - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL)) { - /* - * Whether we should enable h/w TKIP MIC. - * XXX: if we don't support WME TKIP MIC, then we wouldn't - * report WMM capable, so it's always safe to turn on - * TKIP MIC in this case. - */ - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, - 0, 1, NULL); - } - - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_MIC, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) - sc->splitmic = 1; - - /* turn on mcast key search if possible */ - if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) - (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, - 1, NULL); - - sc->config.txpowlimit = ATH_TXPOWER_MAX; - - /* 11n Capabilities */ - if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_flags |= SC_OP_TXAGGR; - sc->sc_flags |= SC_OP_RXAGGR; - } - - sc->tx_chainmask = ah->caps.tx_chainmask; - sc->rx_chainmask = ah->caps.rx_chainmask; - - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->rx.defant = ath9k_hw_getdefantenna(ah); - - if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); - - sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ - - /* initialize beacon slots */ - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { - sc->beacon.bslot[i] = NULL; - sc->beacon.bslot_aphy[i] = NULL; - } - - /* setup channels and rates */ - - sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = - sc->rates[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - sc->rates[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - } - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) - ath9k_hw_btcoex_enable(sc->sc_ah); - - return 0; -bad2: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); -bad: - if (ah) - ath9k_hw_detach(ah); - ath9k_exit_debug(sc); - - return error; -} - -void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) -{ - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK | - IEEE80211_HW_SPECTRUM_MGMT; - - if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) - hw->flags |= IEEE80211_HW_MFP_CAPABLE; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); - - hw->queues = 4; - hw->max_rates = 4; - hw->channel_change_time = 5000; - hw->max_listen_interval = 10; - hw->max_rate_tries = ATH_11N_TXMAXTRY; - hw->sta_data_size = sizeof(struct ath_node); - hw->vif_data_size = sizeof(struct ath_vif); - - hw->rate_control_algorithm = "ath9k_rate_control"; - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; -} - -int ath_attach(u16 devid, struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; - int error = 0, i; - struct ath_regulatory *reg; - - DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); - - error = ath_init(devid, sc); - if (error != 0) - return error; - - reg = &sc->sc_ah->regulatory; - - /* get mac address from hardware and set in mac80211 */ - - SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); - - ath_set_hw_capab(sc, hw); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } - - /* initialize tx/rx engine */ - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto error_attach; - - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto error_attach; - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* Initialze h/w Rfkill */ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); - - /* Initialize s/w rfkill */ - error = ath_init_sw_rfkill(sc); - if (error) - goto error_attach; -#endif - - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); - INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(500); - - error = ieee80211_register_hw(hw); - - if (!ath_is_world_regd(reg)) { - error = regulatory_hint(hw->wiphy, reg->alpha2); - if (error) - goto error_attach; - } - - /* Initialize LED control */ - ath_init_leds(sc); - - - return 0; - -error_attach: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - ath9k_hw_detach(sc->sc_ah); - ath9k_exit_debug(sc); - - return error; -} - -int ath_reset(struct ath_softc *sc, bool retry_tx) -{ - struct ath_hw *ah = sc->sc_ah; - struct ieee80211_hw *hw = sc->hw; - int r; - - ath9k_hw_set_interrupts(ah, 0); - ath_drain_all_txq(sc, retry_tx); - ath_stoprecv(sc); - ath_flushrecv(sc); - - spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); - if (r) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u\n", r); - spin_unlock_bh(&sc->sc_resetlock); - - if (ath_startrecv(sc) != 0) - DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); - - /* - * We may be doing a reset in response to a request - * that changes the channel so update any state that - * might change as a result. - */ - ath_cache_conf_rate(sc, &hw->conf); - - ath_update_txpow(sc); - - if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); /* restart beacons */ - - ath9k_hw_set_interrupts(ah, sc->imask); - - if (retry_tx) { - int i; - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - spin_lock_bh(&sc->tx.txq[i].axq_lock); - ath_txq_schedule(sc, &sc->tx.txq[i]); - spin_unlock_bh(&sc->tx.txq[i].axq_lock); - } - } - } - - return r; -} - -/* - * This function will allocate both the DMA descriptor structure, and the - * buffers it contains. These are used to contain the descriptors used - * by the system. -*/ -int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head, const char *name, - int nbuf, int ndesc) -{ -#define DS2PHYS(_dd, _ds) \ - ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) -#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) -#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) - - struct ath_desc *ds; - struct ath_buf *bf; - int i, bsize, error; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", - name, nbuf, ndesc); - - INIT_LIST_HEAD(head); - /* ath_desc must be a multiple of DWORDs */ - if ((sizeof(struct ath_desc) % 4) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); - ASSERT((sizeof(struct ath_desc) % 4) == 0); - error = -ENOMEM; - goto fail; - } - - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; - - /* - * Need additional DMA memory because we can't use - * descriptors that cross the 4K page boundary. Assume - * one skipped descriptor per 4K page. - */ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { - u32 ndesc_skipped = - ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); - u32 dma_len; - - while (ndesc_skipped) { - dma_len = ndesc_skipped * sizeof(struct ath_desc); - dd->dd_desc_len += dma_len; - - ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); - }; - } - - /* allocate descriptors */ - dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, - &dd->dd_desc_paddr, GFP_KERNEL); - if (dd->dd_desc == NULL) { - error = -ENOMEM; - goto fail; - } - ds = dd->dd_desc; - DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", - name, ds, (u32) dd->dd_desc_len, - ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); - - /* allocate buffers */ - bsize = sizeof(struct ath_buf) * nbuf; - bf = kzalloc(bsize, GFP_KERNEL); - if (bf == NULL) { - error = -ENOMEM; - goto fail2; - } - dd->dd_bufptr = bf; - - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - - if (!(sc->sc_ah->caps.hw_caps & - ATH9K_HW_CAP_4KB_SPLITTRANS)) { - /* - * Skip descriptor addresses which can cause 4KB - * boundary crossing (addr + length) with a 32 dword - * descriptor fetch. - */ - while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - ASSERT((caddr_t) bf->bf_desc < - ((caddr_t) dd->dd_desc + - dd->dd_desc_len)); - - ds += ndesc; - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - } - } - list_add_tail(&bf->list, head); - } - return 0; -fail2: - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); -fail: - memset(dd, 0, sizeof(*dd)); - return error; -#undef ATH_DESC_4KB_BOUND_CHECK -#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED -#undef DS2PHYS -} - -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head) -{ - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); - - INIT_LIST_HEAD(head); - kfree(dd->dd_bufptr); - memset(dd, 0, sizeof(*dd)); -} - -int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case 0: - qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; - break; - case 1: - qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; - break; - case 2: - qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; - break; - case 3: - qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; - break; - default: - qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; - break; - } - - return qnum; -} - -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case ATH9K_WME_AC_VO: - qnum = 0; - break; - case ATH9K_WME_AC_VI: - qnum = 1; - break; - case ATH9K_WME_AC_BE: - qnum = 2; - break; - case ATH9K_WME_AC_BK: - qnum = 3; - break; - default: - qnum = -1; - break; - } - - return qnum; -} - -/* XXX: Remove me once we don't depend on ath9k_channel for all - * this redundant data */ -void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *ichan) -{ - struct ieee80211_channel *chan = hw->conf.channel; - struct ieee80211_conf *conf = &hw->conf; - - ichan->channel = chan->center_freq; - ichan->chan = chan; - - if (chan->band == IEEE80211_BAND_2GHZ) { - ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; - } else { - ichan->chanmode = CHANNEL_A; - ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; - } - - sc->tx_chan_width = ATH9K_HT_MACMODE_20; - - if (conf_is_ht(conf)) { - if (conf_is_ht40(conf)) - sc->tx_chan_width = ATH9K_HT_MACMODE_2040; - - ichan->chanmode = ath_get_extchanmode(sc, chan, - conf->channel_type); - } -} - -/**********************/ -/* mac80211 callbacks */ -/**********************/ - -static int ath9k_start(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ieee80211_channel *curchan = hw->conf.channel; - struct ath9k_channel *init_channel; - int r, pos; - - DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " - "initial channel: %d MHz\n", curchan->center_freq); - - mutex_lock(&sc->mutex); - - if (ath9k_wiphy_started(sc)) { - if (sc->chan_idx == curchan->hw_value) { - /* - * Already on the operational channel, the new wiphy - * can be marked active. - */ - aphy->state = ATH_WIPHY_ACTIVE; - ieee80211_wake_queues(hw); - } else { - /* - * Another wiphy is on another channel, start the new - * wiphy in paused state. - */ - aphy->state = ATH_WIPHY_PAUSED; - ieee80211_stop_queues(hw); - } - mutex_unlock(&sc->mutex); - return 0; - } - aphy->state = ATH_WIPHY_ACTIVE; - - /* setup initial channel */ - - pos = curchan->hw_value; - - sc->chan_idx = pos; - init_channel = &sc->sc_ah->channels[pos]; - ath9k_update_ichannel(sc, hw, init_channel); - - /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(sc->sc_ah, 0); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(sc->sc_ah, init_channel, false); - if (r) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u " - "(freq %u MHz)\n", r, - curchan->center_freq); - spin_unlock_bh(&sc->sc_resetlock); - goto mutex_unlock; - } - spin_unlock_bh(&sc->sc_resetlock); - - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath_update_txpow(sc); - - /* - * Setup the hardware after reset: - * 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. - */ - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); - r = -EIO; - goto mutex_unlock; - } - - /* Setup our intr mask. */ - sc->imask = ATH9K_INT_RX | ATH9K_INT_TX - | ATH9K_INT_RXEOL | ATH9K_INT_RXORN - | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT) - sc->imask |= ATH9K_INT_GTT; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) - sc->imask |= ATH9K_INT_CST; - - ath_cache_conf_rate(sc, &hw->conf); - - sc->sc_flags &= ~SC_OP_INVALID; - - /* Disable BMISS interrupt when we're not associated */ - sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - - ieee80211_wake_queues(hw); - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - r = ath_start_rfkill_poll(sc); -#endif - -mutex_unlock: - mutex_unlock(&sc->mutex); - - return r; -} - -static int ath9k_tx(struct ieee80211_hw *hw, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_tx_control txctl; - int hdrlen, padsize; - - if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { - printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state " - "%d\n", wiphy_name(hw->wiphy), aphy->state); - goto exit; - } - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - - /* - * 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->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.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) - return -1; - skb_push(skb, padsize); - memmove(skb->data, skb->data + padsize, hdrlen); - } - - /* Check if a tx queue is available */ - - txctl.txq = ath_test_get_txq(sc, skb); - if (!txctl.txq) - goto exit; - - DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); - - if (ath_tx_start(hw, skb, &txctl) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); - goto exit; - } - - return 0; -exit: - dev_kfree_skb_any(skb); - return 0; -} - -static void ath9k_stop(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - aphy->state = ATH_WIPHY_INACTIVE; - - if (sc->sc_flags & SC_OP_INVALID) { - DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); - return; - } - - mutex_lock(&sc->mutex); - - ieee80211_stop_queues(hw); - - if (ath9k_wiphy_started(sc)) { - mutex_unlock(&sc->mutex); - return; /* another wiphy still in use */ - } - - /* make sure h/w will not generate any interrupt - * before setting the invalid flag. */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); - - if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_drain_all_txq(sc, false); - ath_stoprecv(sc); - ath9k_hw_phy_disable(sc->sc_ah); - } else - sc->rx.rxlink = NULL; - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(sc->sc_ah); - ath9k_hw_configpcipowersave(sc->sc_ah, 1); - - sc->sc_flags |= SC_OP_INVALID; - - mutex_unlock(&sc->mutex); - - DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); -} - -static int ath9k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_vif *avp = (void *)conf->vif->drv_priv; - enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; - int ret = 0; - - mutex_lock(&sc->mutex); - - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) && - sc->nvifs > 0) { - ret = -ENOBUFS; - goto out; - } - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - ic_opmode = NL80211_IFTYPE_STATION; - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_MESH_POINT: - if (sc->nbcnvifs >= ATH_BCBUF) { - ret = -ENOBUFS; - goto out; - } - ic_opmode = conf->type; - break; - default: - DPRINTF(sc, ATH_DBG_FATAL, - "Interface type %d not yet supported\n", conf->type); - ret = -EOPNOTSUPP; - goto out; - } - - DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode); - - /* Set the VIF opmode */ - avp->av_opmode = ic_opmode; - avp->av_bslot = -1; - - sc->nvifs++; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - ath9k_set_bssid_mask(hw); - - if (sc->nvifs > 1) - goto out; /* skip global settings for secondary vif */ - - if (ic_opmode == NL80211_IFTYPE_AP) { - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); - sc->sc_flags |= SC_OP_TSF_RESET; - } - - /* Set the device opmode */ - sc->sc_ah->opmode = ic_opmode; - - /* - * Enable MIB interrupts when there are hardware phy counters. - * Note we only do this (at the moment) for station mode. - */ - if ((conf->type == NL80211_IFTYPE_STATION) || - (conf->type == NL80211_IFTYPE_ADHOC) || - (conf->type == NL80211_IFTYPE_MESH_POINT)) { - if (ath9k_hw_phycounters(sc->sc_ah)) - sc->imask |= ATH9K_INT_MIB; - sc->imask |= ATH9K_INT_TSFOOR; - } - - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - - if (conf->type == NL80211_IFTYPE_AP) { - /* TODO: is this a suitable place to start ANI for AP mode? */ - /* Start ANI */ - mod_timer(&sc->ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); - } - -out: - mutex_unlock(&sc->mutex); - return ret; -} - -static void ath9k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_vif *avp = (void *)conf->vif->drv_priv; - int i; - - DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); - - mutex_lock(&sc->mutex); - - /* Stop ANI */ - del_timer_sync(&sc->ani.timer); - - /* Reclaim beacon resources */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || - (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - ath_beacon_return(sc, avp); - } - - sc->sc_flags &= ~SC_OP_BEACONS; - - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { - if (sc->beacon.bslot[i] == conf->vif) { - printk(KERN_DEBUG "%s: vif had allocated beacon " - "slot\n", __func__); - sc->beacon.bslot[i] = NULL; - sc->beacon.bslot_aphy[i] = NULL; - } - } - - sc->nvifs--; - - mutex_unlock(&sc->mutex); -} - -static int ath9k_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ieee80211_conf *conf = &hw->conf; - struct ath_hw *ah = sc->sc_ah; - - mutex_lock(&sc->mutex); - - if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) { - if (!(ah->caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { - sc->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); - } - ath9k_hw_setrxabort(sc->sc_ah, 1); - } - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); - } else { - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - if (!(ah->caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; - if (sc->imask & ATH9K_INT_TIM_TIMER) { - sc->imask &= ~ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); - } - } - } - } - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - struct ieee80211_channel *curchan = hw->conf.channel; - int pos = curchan->hw_value; - - aphy->chan_idx = pos; - aphy->chan_is_ht = conf_is_ht(conf); - - if (aphy->state == ATH_WIPHY_SCAN || - aphy->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_all_forced(sc, aphy); - else { - /* - * Do not change operational channel based on a paused - * wiphy changes. - */ - goto skip_chan_change; - } - - DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", - curchan->center_freq); - - /* XXX: remove me eventualy */ - ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]); - - ath_update_chainmask(sc, conf_is_ht(conf)); - - if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { - DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); - mutex_unlock(&sc->mutex); - return -EINVAL; - } - } - -skip_chan_change: - if (changed & IEEE80211_CONF_CHANGE_POWER) - sc->config.txpowlimit = 2 * conf->power_level; - - /* - * The HW TSF has to be reset when the beacon interval changes. - * We set the flag here, and ath_beacon_config_ap() would take this - * into account when it gets called through the subsequent - * config_interface() call - with IFCC_BEACON in the changed field. - */ - - if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - sc->sc_flags |= SC_OP_TSF_RESET; - - mutex_unlock(&sc->mutex); - - return 0; -} - -static int ath9k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; - struct ath_vif *avp = (void *)vif->drv_priv; - u32 rfilt = 0; - int error, i; - - mutex_lock(&sc->mutex); - - /* TODO: Need to decide which hw opmode to use for multi-interface - * cases */ - if (vif->type == NL80211_IFTYPE_AP && - ah->opmode != NL80211_IFTYPE_AP) { - ah->opmode = NL80211_IFTYPE_STATION; - ath9k_hw_setopmode(ah); - memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); - sc->curaid = 0; - ath9k_hw_write_associd(sc); - /* 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 NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - /* Set BSSID */ - memcpy(sc->curbssid, conf->bssid, ETH_ALEN); - memcpy(avp->bssid, conf->bssid, ETH_ALEN); - sc->curaid = 0; - ath9k_hw_write_associd(sc); - - /* Set aggregation protection mode parameters */ - sc->config.ath_aggr_prot = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, - "RX filter 0x%x bssid %pM aid 0x%x\n", - rfilt, sc->curbssid, sc->curaid); - - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; - - break; - default: - break; - } - } - - if ((vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_AP) || - (vif->type == NL80211_IFTYPE_MESH_POINT)) { - if ((conf->changed & IEEE80211_IFCC_BEACON) || - (conf->changed & IEEE80211_IFCC_BEACON_ENABLED && - conf->enable_beacon)) { - /* - * Allocate and setup the beacon frame. - * - * Stop any previous beacon DMA. This may be - * necessary, for example, when an ibss merge - * causes reconfiguration; we may be called - * with beacon transmission active. - */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - - error = ath_beacon_alloc(aphy, vif); - if (error != 0) { - mutex_unlock(&sc->mutex); - return error; - } - - ath_beacon_config(sc, vif); - } - } - - /* Check for WLAN_CAPABILITY_PRIVACY ? */ - 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, - (u16)i, - sc->curbssid); - } - - /* Only legacy IBSS for now */ - if (vif->type == NL80211_IFTYPE_ADHOC) - ath_update_chainmask(sc, 0); - - mutex_unlock(&sc->mutex); - - return 0; -} - -#define SUPPORTED_FILTERS \ - (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_CONTROL | \ - FIF_OTHER_BSS | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_FCSFAIL) - -/* FIXME: sc->sc_full_reset ? */ -static void ath9k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_mc_list *mclist) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - u32 rfilt; - - changed_flags &= SUPPORTED_FILTERS; - *total_flags &= SUPPORTED_FILTERS; - - sc->rx.rxfilter = *total_flags; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(sc->sc_ah, rfilt); - - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); -} - -static void ath9k_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - switch (cmd) { - case STA_NOTIFY_ADD: - ath_node_attach(sc, sta); - break; - case STA_NOTIFY_REMOVE: - ath_node_detach(sc, sta); - break; - default: - break; - } -} - -static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath9k_tx_queue_info qi; - int ret = 0, qnum; - - if (queue >= WME_NUM_AC) - return 0; - - mutex_lock(&sc->mutex); - - memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); - - qi.tqi_aifs = params->aifs; - qi.tqi_cwmin = params->cw_min; - qi.tqi_cwmax = params->cw_max; - qi.tqi_burstTime = params->txop; - qnum = ath_get_hal_qnum(queue, sc); - - DPRINTF(sc, ATH_DBG_CONFIG, - "Configure tx [queue/halq] [%d/%d], " - "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", - queue, qnum, params->aifs, params->cw_min, - params->cw_max, params->txop); - - ret = ath_txq_update(sc, qnum, &qi); - if (ret) - DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); - - mutex_unlock(&sc->mutex); - - return ret; -} - -static int ath9k_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - int ret = 0; - - if (modparam_nohwcrypt) - return -ENOSPC; - - mutex_lock(&sc->mutex); - ath9k_ps_wakeup(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n"); - - switch (cmd) { - case SET_KEY: - ret = ath_key_config(sc, vif, sta, key); - if (ret >= 0) { - key->hw_key_idx = ret; - /* push IV and Michael MIC generation to stack */ - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - if (key->alg == ALG_TKIP) - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP) - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; - ret = 0; - } - break; - case DISABLE_KEY: - ath_key_delete(sc, key); - break; - default: - ret = -EINVAL; - } - - ath9k_ps_restore(sc); - mutex_unlock(&sc->mutex); - - return ret; -} - -static void ath9k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - sc->sc_flags |= SC_OP_PREAMBLE_SHORT; - else - sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", - bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && - hw->conf.channel->band != IEEE80211_BAND_5GHZ) - sc->sc_flags |= SC_OP_PROTECT_ENABLE; - else - sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; - } - - if (changed & BSS_CHANGED_ASSOC) { - DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", - bss_conf->assoc); - ath9k_bss_assoc_info(sc, vif, bss_conf); - } - - mutex_unlock(&sc->mutex); -} - -static u64 ath9k_get_tsf(struct ieee80211_hw *hw) -{ - u64 tsf; - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - tsf = ath9k_hw_gettsf64(sc->sc_ah); - mutex_unlock(&sc->mutex); - - return tsf; -} - -static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - ath9k_hw_settsf64(sc->sc_ah, tsf); - mutex_unlock(&sc->mutex); -} - -static void ath9k_reset_tsf(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - ath9k_hw_reset_tsf(sc->sc_ah); - mutex_unlock(&sc->mutex); -} - -static int ath9k_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - int ret = 0; - - switch (action) { - case IEEE80211_AMPDU_RX_START: - if (!(sc->sc_flags & SC_OP_RXAGGR)) - ret = -ENOTSUPP; - break; - case IEEE80211_AMPDU_RX_STOP: - break; - case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, sta, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to start TX aggregation\n"); - else - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); - break; - case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, sta, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to stop TX aggregation\n"); - - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - ath_tx_aggr_resume(sc, sta, tid); - break; - default: - DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); - } - - return ret; -} - -static void ath9k_sw_scan_start(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - if (ath9k_wiphy_scanning(sc)) { - printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the " - "same time\n"); - /* - * Do not allow the concurrent scanning state for now. This - * could be improved with scanning control moved into ath9k. - */ - return; - } - - aphy->state = ATH_WIPHY_SCAN; - ath9k_wiphy_pause_all_forced(sc, aphy); - - mutex_lock(&sc->mutex); - sc->sc_flags |= SC_OP_SCANNING; - mutex_unlock(&sc->mutex); -} - -static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - aphy->state = ATH_WIPHY_ACTIVE; - sc->sc_flags &= ~SC_OP_SCANNING; - mutex_unlock(&sc->mutex); -} - -struct ieee80211_ops ath9k_ops = { - .tx = ath9k_tx, - .start = ath9k_start, - .stop = ath9k_stop, - .add_interface = ath9k_add_interface, - .remove_interface = ath9k_remove_interface, - .config = ath9k_config, - .config_interface = ath9k_config_interface, - .configure_filter = ath9k_configure_filter, - .sta_notify = ath9k_sta_notify, - .conf_tx = ath9k_conf_tx, - .bss_info_changed = ath9k_bss_info_changed, - .set_key = ath9k_set_key, - .get_tsf = ath9k_get_tsf, - .set_tsf = ath9k_set_tsf, - .reset_tsf = ath9k_reset_tsf, - .ampdu_action = ath9k_ampdu_action, - .sw_scan_start = ath9k_sw_scan_start, - .sw_scan_complete = ath9k_sw_scan_complete, -}; - -static struct { - u32 version; - const char * name; -} ath_mac_bb_names[] = { - { AR_SREV_VERSION_5416_PCI, "5416" }, - { AR_SREV_VERSION_5416_PCIE, "5418" }, - { AR_SREV_VERSION_9100, "9100" }, - { AR_SREV_VERSION_9160, "9160" }, - { AR_SREV_VERSION_9280, "9280" }, - { AR_SREV_VERSION_9285, "9285" } -}; - -static struct { - u16 version; - const char * name; -} ath_rf_names[] = { - { 0, "5133" }, - { AR_RAD5133_SREV_MAJOR, "5133" }, - { AR_RAD5122_SREV_MAJOR, "5122" }, - { AR_RAD2133_SREV_MAJOR, "2133" }, - { AR_RAD2122_SREV_MAJOR, "2122" } -}; - -/* - * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. - */ -const char * -ath_mac_bb_name(u32 mac_bb_version) -{ - int i; - - for (i=0; i -#include -#include "ath9k.h" - -static struct pci_device_id ath_pci_id_table[] __devinitdata = { - { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ - { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ - { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ - { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ - { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ - { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ - { 0 } -}; - -/* return bus cachesize in 4B word units */ -static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) -{ - u8 u8tmp; - - pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, - (u8 *)&u8tmp); - *csz = (int)u8tmp; - - /* - * This check was put in to avoid "unplesant" consequences if - * the bootrom has not fully initialized all PCI devices. - * Sometimes the cache line size register is not set - */ - - if (*csz == 0) - *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ -} - -static void ath_pci_cleanup(struct ath_softc *sc) -{ - struct pci_dev *pdev = to_pci_dev(sc->dev); - - pci_iounmap(pdev, sc->mem); - pci_disable_device(pdev); - pci_release_region(pdev, 0); -} - -static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) -{ - (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); - - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, - AH_WAIT_TIMEOUT)) { - return false; - } - - *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); - - return true; -} - -static struct ath_bus_ops ath_pci_bus_ops = { - .read_cachesize = ath_pci_read_cachesize, - .cleanup = ath_pci_cleanup, - .eeprom_read = ath_pci_eeprom_read, -}; - -static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - void __iomem *mem; - struct ath_wiphy *aphy; - struct ath_softc *sc; - struct ieee80211_hw *hw; - u8 csz; - int ret = 0; - struct ath_hw *ah; - - if (pci_enable_device(pdev)) - return -EIO; - - ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - - if (ret) { - printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); - goto bad; - } - - ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - - if (ret) { - printk(KERN_ERR "ath9k: 32-bit DMA consistent " - "DMA enable failed\n"); - goto bad; - } - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); - if (csz == 0) { - /* - * Linux 2.4.18 (at least) writes the cache line size - * register as a 16-bit wide register which is wrong. - * We must have this setup properly for rx buffer - * DMA to work so force a reasonable value here if it - * comes up zero. - */ - csz = L1_CACHE_BYTES / sizeof(u32); - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); - } - /* - * The default setting of latency timer yields poor results, - * set it to the value used by other systems. It may be worth - * tweaking this setting more. - */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); - - pci_set_master(pdev); - - ret = pci_request_region(pdev, 0, "ath9k"); - if (ret) { - dev_err(&pdev->dev, "PCI memory region reserve error\n"); - ret = -ENODEV; - goto bad; - } - - mem = pci_iomap(pdev, 0, 0); - if (!mem) { - printk(KERN_ERR "PCI memory map error\n") ; - ret = -EIO; - goto bad1; - } - - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + - sizeof(struct ath_softc), &ath9k_ops); - if (hw == NULL) { - printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); - goto bad2; - } - - SET_IEEE80211_DEV(hw, &pdev->dev); - pci_set_drvdata(pdev, hw); - - aphy = hw->priv; - sc = (struct ath_softc *) (aphy + 1); - aphy->sc = sc; - aphy->hw = hw; - sc->pri_wiphy = aphy; - sc->hw = hw; - sc->dev = &pdev->dev; - sc->mem = mem; - sc->bus_ops = &ath_pci_bus_ops; - - if (ath_attach(id->device, sc) != 0) { - ret = -ENODEV; - goto bad3; - } - - /* setup interrupt service routine */ - - if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { - printk(KERN_ERR "%s: request_irq failed\n", - wiphy_name(hw->wiphy)); - ret = -EIO; - goto bad4; - } - - sc->irq = pdev->irq; - - ah = sc->sc_ah; - printk(KERN_INFO - "%s: Atheros AR%s MAC/BB Rev:%x " - "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", - wiphy_name(hw->wiphy), - ath_mac_bb_name(ah->hw_version.macVersion), - ah->hw_version.macRev, - ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), - ah->hw_version.phyRev, - (unsigned long)mem, pdev->irq); - - return 0; -bad4: - ath_detach(sc); -bad3: - ieee80211_free_hw(hw); -bad2: - pci_iounmap(pdev, mem); -bad1: - pci_release_region(pdev, 0); -bad: - pci_disable_device(pdev); - return ret; -} - -static void ath_pci_remove(struct pci_dev *pdev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - ath_cleanup(sc); -} - -#ifdef CONFIG_PM - -static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_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, PCI_D3hot); - - return 0; -} - -static int ath_pci_resume(struct pci_dev *pdev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - int err; - - err = pci_enable_device(pdev); - if (err) - return err; - pci_restore_state(pdev); - - /* 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); - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* - * check the h/w rfkill state on resume - * and start the rfkill poll timer - */ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); -#endif - - return 0; -} - -#endif /* CONFIG_PM */ - -MODULE_DEVICE_TABLE(pci, ath_pci_id_table); - -static struct pci_driver ath_pci_driver = { - .name = "ath9k", - .id_table = ath_pci_id_table, - .probe = ath_pci_probe, - .remove = ath_pci_remove, -#ifdef CONFIG_PM - .suspend = ath_pci_suspend, - .resume = ath_pci_resume, -#endif /* CONFIG_PM */ -}; - -int ath_pci_init(void) -{ - return pci_register_driver(&ath_pci_driver); -} - -void ath_pci_exit(void) -{ - pci_unregister_driver(&ath_pci_driver); -} diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c deleted file mode 100644 index 5ec9ce9..0000000 --- a/drivers/net/wireless/ath9k/phy.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -void -ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, - int regWrites) -{ - REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); -} - -bool -ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) -{ - u32 channelSel = 0; - u32 bModeSynth = 0; - u32 aModeRefSel = 0; - u32 reg32 = 0; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - if (freq < 4800) { - u32 txctl; - - if (((freq - 2192) % 5) == 0) { - channelSel = ((freq - 672) * 2 - 3040) / 10; - bModeSynth = 0; - } else if (((freq - 2224) % 5) == 0) { - channelSel = ((freq - 704) * 2 - 3040) / 10; - bModeSynth = 1; - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); - return false; - } - - channelSel = (channelSel << 2) & 0xff; - channelSel = ath9k_hw_reverse_bits(channelSel, 8); - - txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); - if (freq == 2484) { - - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl | AR_PHY_CCK_TX_CTRL_JAPAN); - } else { - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); - } - - } else if ((freq % 20) == 0 && freq >= 5120) { - channelSel = - ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8); - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else if ((freq % 10) == 0) { - channelSel = - ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8); - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) - aModeRefSel = ath9k_hw_reverse_bits(2, 2); - else - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else if ((freq % 5) == 0) { - channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); - return false; - } - - reg32 = - (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | - (1 << 5) | 0x1; - - REG_WRITE(ah, AR_PHY(0x37), reg32); - - ah->curchan = chan; - ah->curchan_rad_index = -1; - - return true; -} - -bool -ath9k_hw_ar9280_set_channel(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - u16 bMode, fracMode, aModeRefSel = 0; - u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; - struct chan_centers centers; - u32 refDivA = 24; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL); - reg32 &= 0xc0000000; - - if (freq < 4800) { - u32 txctl; - - bMode = 1; - fracMode = 1; - aModeRefSel = 0; - channelSel = (freq * 0x10000) / 15; - - txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); - if (freq == 2484) { - - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl | AR_PHY_CCK_TX_CTRL_JAPAN); - } else { - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); - } - } else { - bMode = 0; - fracMode = 0; - - switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) { - case 0: - if ((freq % 20) == 0) { - aModeRefSel = 3; - } else if ((freq % 10) == 0) { - aModeRefSel = 2; - } - if (aModeRefSel) - break; - case 1: - default: - aModeRefSel = 0; - fracMode = 1; - refDivA = 1; - channelSel = (freq * 0x8000) / 15; - - REG_RMW_FIELD(ah, AR_AN_SYNTH9, - AR_AN_SYNTH9_REFDIVA, refDivA); - - } - - if (!fracMode) { - ndiv = (freq * (refDivA >> aModeRefSel)) / 60; - channelSel = ndiv & 0x1ff; - channelFrac = (ndiv & 0xfffffe00) * 2; - channelSel = (channelSel << 17) | channelFrac; - } - } - - reg32 = reg32 | - (bMode << 29) | - (fracMode << 28) | (aModeRefSel << 26) | (channelSel); - - REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); - - ah->curchan = chan; - ah->curchan_rad_index = -1; - - return true; -} - -static void -ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, - u32 numBits, u32 firstBit, - u32 column) -{ - u32 tmp32, mask, arrayEntry, lastBit; - int32_t bitPosition, bitsLeft; - - tmp32 = ath9k_hw_reverse_bits(reg32, numBits); - arrayEntry = (firstBit - 1) / 8; - bitPosition = (firstBit - 1) % 8; - bitsLeft = numBits; - while (bitsLeft > 0) { - lastBit = (bitPosition + bitsLeft > 8) ? - 8 : bitPosition + bitsLeft; - mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << - (column * 8); - rfBuf[arrayEntry] &= ~mask; - rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << - (column * 8)) & mask; - bitsLeft -= 8 - bitPosition; - tmp32 = tmp32 >> (8 - bitPosition); - bitPosition = 0; - arrayEntry++; - } -} - -bool -ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, - u16 modesIndex) -{ - u32 eepMinorRev; - u32 ob5GHz = 0, db5GHz = 0; - u32 ob2GHz = 0, db2GHz = 0; - int regWrites = 0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - return true; - - eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); - - RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); - - RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); - - RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); - - RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, - modesIndex); - { - int i; - for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) { - ah->analogBank6Data[i] = - INI_RA(&ah->iniBank6TPC, i, modesIndex); - } - } - - if (eepMinorRev >= 2) { - if (IS_CHAN_2GHZ(chan)) { - ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); - db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - ob2GHz, 3, 197, 0); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - db2GHz, 3, 194, 0); - } else { - ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5); - db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - ob5GHz, 3, 203, 0); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - db5GHz, 3, 200, 0); - } - } - - RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); - - REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, - regWrites); - - return true; -} - -void -ath9k_hw_rfdetach(struct ath_hw *ah) -{ - if (ah->analogBank0Data != NULL) { - kfree(ah->analogBank0Data); - ah->analogBank0Data = NULL; - } - if (ah->analogBank1Data != NULL) { - kfree(ah->analogBank1Data); - ah->analogBank1Data = NULL; - } - if (ah->analogBank2Data != NULL) { - kfree(ah->analogBank2Data); - ah->analogBank2Data = NULL; - } - if (ah->analogBank3Data != NULL) { - kfree(ah->analogBank3Data); - ah->analogBank3Data = NULL; - } - if (ah->analogBank6Data != NULL) { - kfree(ah->analogBank6Data); - ah->analogBank6Data = NULL; - } - if (ah->analogBank6TPCData != NULL) { - kfree(ah->analogBank6TPCData); - ah->analogBank6TPCData = NULL; - } - if (ah->analogBank7Data != NULL) { - kfree(ah->analogBank7Data); - ah->analogBank7Data = NULL; - } - if (ah->addac5416_21 != NULL) { - kfree(ah->addac5416_21); - ah->addac5416_21 = NULL; - } - if (ah->bank6Temp != NULL) { - kfree(ah->bank6Temp); - ah->bank6Temp = NULL; - } -} - -bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) -{ - if (!AR_SREV_9280_10_OR_LATER(ah)) { - ah->analogBank0Data = - kzalloc((sizeof(u32) * - ah->iniBank0.ia_rows), GFP_KERNEL); - ah->analogBank1Data = - kzalloc((sizeof(u32) * - ah->iniBank1.ia_rows), GFP_KERNEL); - ah->analogBank2Data = - kzalloc((sizeof(u32) * - ah->iniBank2.ia_rows), GFP_KERNEL); - ah->analogBank3Data = - kzalloc((sizeof(u32) * - ah->iniBank3.ia_rows), GFP_KERNEL); - ah->analogBank6Data = - kzalloc((sizeof(u32) * - ah->iniBank6.ia_rows), GFP_KERNEL); - ah->analogBank6TPCData = - kzalloc((sizeof(u32) * - ah->iniBank6TPC.ia_rows), GFP_KERNEL); - ah->analogBank7Data = - kzalloc((sizeof(u32) * - ah->iniBank7.ia_rows), GFP_KERNEL); - - if (ah->analogBank0Data == NULL - || ah->analogBank1Data == NULL - || ah->analogBank2Data == NULL - || ah->analogBank3Data == NULL - || ah->analogBank6Data == NULL - || ah->analogBank6TPCData == NULL - || ah->analogBank7Data == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Cannot allocate RF banks\n"); - *status = -ENOMEM; - return false; - } - - ah->addac5416_21 = - kzalloc((sizeof(u32) * - ah->iniAddac.ia_rows * - ah->iniAddac.ia_columns), GFP_KERNEL); - if (ah->addac5416_21 == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Cannot allocate addac5416_21\n"); - *status = -ENOMEM; - return false; - } - - ah->bank6Temp = - kzalloc((sizeof(u32) * - ah->iniBank6.ia_rows), GFP_KERNEL); - if (ah->bank6Temp == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Cannot allocate bank6Temp\n"); - *status = -ENOMEM; - return false; - } - } - - return true; -} - -void -ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int i, regWrites = 0; - u32 bank6SelMask; - u32 *bank6Temp = ah->bank6Temp; - - switch (ah->diversity_control) { - case ATH9K_ANT_FIXED_A: - bank6SelMask = - (ah-> - antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : - REDUCE_CHAIN_1; - break; - case ATH9K_ANT_FIXED_B: - bank6SelMask = - (ah-> - antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : - REDUCE_CHAIN_0; - break; - case ATH9K_ANT_VARIABLE: - return; - break; - default: - return; - break; - } - - for (i = 0; i < ah->iniBank6.ia_rows; i++) - bank6Temp[i] = ah->analogBank6Data[i]; - - REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); - - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); - - REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); - - REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); -#ifdef ALTER_SWITCH - REG_WRITE(ah, PHY_SWITCH_CHAIN_0, - (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38) - | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38)); -#endif -} diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h deleted file mode 100644 index 296d0e9..0000000 --- a/drivers/net/wireless/ath9k/phy.h +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef PHY_H -#define PHY_H - -bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah, - struct ath9k_channel - *chan); -bool ath9k_hw_set_channel(struct ath_hw *ah, - struct ath9k_channel *chan); -void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, - u32 freqIndex, int regWrites); -bool ath9k_hw_set_rf_regs(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 modesIndex); -void ath9k_hw_decrease_chain_power(struct ath_hw *ah, - struct ath9k_channel *chan); -bool ath9k_hw_init_rf(struct ath_hw *ah, - int *status); - -#define AR_PHY_BASE 0x9800 -#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) - -#define AR_PHY_TEST 0x9800 -#define PHY_AGC_CLR 0x10000000 -#define RFSILENT_BB 0x00002000 - -#define AR_PHY_TURBO 0x9804 -#define AR_PHY_FC_TURBO_MODE 0x00000001 -#define AR_PHY_FC_TURBO_SHORT 0x00000002 -#define AR_PHY_FC_DYN2040_EN 0x00000004 -#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 -#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 -#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 -#define AR_PHY_FC_HT_EN 0x00000040 -#define AR_PHY_FC_SHORT_GI_40 0x00000080 -#define AR_PHY_FC_WALSH 0x00000100 -#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 -#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800 - -#define AR_PHY_TEST2 0x9808 - -#define AR_PHY_TIMING2 0x9810 -#define AR_PHY_TIMING3 0x9814 -#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 -#define AR_PHY_TIMING3_DSC_MAN_S 17 -#define AR_PHY_TIMING3_DSC_EXP 0x0001E000 -#define AR_PHY_TIMING3_DSC_EXP_S 13 - -#define AR_PHY_CHIP_ID 0x9818 -#define AR_PHY_CHIP_ID_REV_0 0x80 -#define AR_PHY_CHIP_ID_REV_1 0x81 -#define AR_PHY_CHIP_ID_9160_REV_0 0xb0 - -#define AR_PHY_ACTIVE 0x981C -#define AR_PHY_ACTIVE_EN 0x00000001 -#define AR_PHY_ACTIVE_DIS 0x00000000 - -#define AR_PHY_RF_CTL2 0x9824 -#define AR_PHY_TX_END_DATA_START 0x000000FF -#define AR_PHY_TX_END_DATA_START_S 0 -#define AR_PHY_TX_END_PA_ON 0x0000FF00 -#define AR_PHY_TX_END_PA_ON_S 8 - -#define AR_PHY_RF_CTL3 0x9828 -#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 -#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 - -#define AR_PHY_ADC_CTL 0x982C -#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 -#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S 0 -#define AR_PHY_ADC_CTL_OFF_PWDDAC 0x00002000 -#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000 -#define AR_PHY_ADC_CTL_OFF_PWDADC 0x00008000 -#define AR_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000 -#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S 16 - -#define AR_PHY_ADC_SERIAL_CTL 0x9830 -#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000 -#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001 - -#define AR_PHY_RF_CTL4 0x9834 -#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000 -#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24 -#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000 -#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16 -#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00 -#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8 -#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF -#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 - -#define AR_PHY_TSTDAC_CONST 0x983c - -#define AR_PHY_SETTLING 0x9844 -#define AR_PHY_SETTLING_SWITCH 0x00003F80 -#define AR_PHY_SETTLING_SWITCH_S 7 - -#define AR_PHY_RXGAIN 0x9848 -#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000 -#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12 -#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000 -#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18 -#define AR9280_PHY_RXGAIN_TXRX_ATTEN 0x00003F80 -#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S 7 -#define AR9280_PHY_RXGAIN_TXRX_MARGIN 0x001FC000 -#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14 - -#define AR_PHY_DESIRED_SZ 0x9850 -#define AR_PHY_DESIRED_SZ_ADC 0x000000FF -#define AR_PHY_DESIRED_SZ_ADC_S 0 -#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00 -#define AR_PHY_DESIRED_SZ_PGA_S 8 -#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000 -#define AR_PHY_DESIRED_SZ_TOT_DES_S 20 - -#define AR_PHY_FIND_SIG 0x9858 -#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000 -#define AR_PHY_FIND_SIG_FIRSTEP_S 12 -#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000 -#define AR_PHY_FIND_SIG_FIRPWR_S 18 - -#define AR_PHY_AGC_CTL1 0x985C -#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80 -#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7 -#define AR_PHY_AGC_CTL1_COARSE_HIGH 0x003F8000 -#define AR_PHY_AGC_CTL1_COARSE_HIGH_S 15 - -#define AR_PHY_AGC_CONTROL 0x9860 -#define AR_PHY_AGC_CONTROL_CAL 0x00000001 -#define AR_PHY_AGC_CONTROL_NF 0x00000002 -#define AR_PHY_AGC_CONTROL_ENABLE_NF 0x00008000 -#define AR_PHY_AGC_CONTROL_FLTR_CAL 0x00010000 -#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 - -#define AR_PHY_CCA 0x9864 -#define AR_PHY_MINCCA_PWR 0x0FF80000 -#define AR_PHY_MINCCA_PWR_S 19 -#define AR_PHY_CCA_THRESH62 0x0007F000 -#define AR_PHY_CCA_THRESH62_S 12 -#define AR9280_PHY_MINCCA_PWR 0x1FF00000 -#define AR9280_PHY_MINCCA_PWR_S 20 -#define AR9280_PHY_CCA_THRESH62 0x000FF000 -#define AR9280_PHY_CCA_THRESH62_S 12 - -#define AR_PHY_SFCORR_LOW 0x986C -#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001 -#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00 -#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8 -#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000 -#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14 -#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000 -#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21 - -#define AR_PHY_SFCORR 0x9868 -#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F -#define AR_PHY_SFCORR_M2COUNT_THR_S 0 -#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000 -#define AR_PHY_SFCORR_M1_THRESH_S 17 -#define AR_PHY_SFCORR_M2_THRESH 0x7F000000 -#define AR_PHY_SFCORR_M2_THRESH_S 24 - -#define AR_PHY_SLEEP_CTR_CONTROL 0x9870 -#define AR_PHY_SLEEP_CTR_LIMIT 0x9874 -#define AR_PHY_SYNTH_CONTROL 0x9874 -#define AR_PHY_SLEEP_SCAL 0x9878 - -#define AR_PHY_PLL_CTL 0x987c -#define AR_PHY_PLL_CTL_40 0xaa -#define AR_PHY_PLL_CTL_40_5413 0x04 -#define AR_PHY_PLL_CTL_44 0xab -#define AR_PHY_PLL_CTL_44_2133 0xeb -#define AR_PHY_PLL_CTL_40_2133 0xea - -#define AR_PHY_RX_DELAY 0x9914 -#define AR_PHY_SEARCH_START_DELAY 0x9918 -#define AR_PHY_RX_DELAY_DELAY 0x00003FFF - -#define AR_PHY_TIMING_CTRL4(_i) (0x9920 + ((_i) << 12)) -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0 -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0 -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 -#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800 -#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000 -#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 -#define AR_PHY_TIMING_CTRL4_DO_CAL 0x10000 - -#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI 0x80000000 -#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000 -#define AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000 -#define AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000 - -#define AR_PHY_TIMING5 0x9924 -#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE -#define AR_PHY_TIMING5_CYCPWR_THR1_S 1 - -#define AR_PHY_POWER_TX_RATE1 0x9934 -#define AR_PHY_POWER_TX_RATE2 0x9938 -#define AR_PHY_POWER_TX_RATE_MAX 0x993c -#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 - -#define AR_PHY_FRAME_CTL 0x9944 -#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 -#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 - -#define AR_PHY_TXPWRADJ 0x994C -#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA 0x00000FC0 -#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S 6 -#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX 0x00FC0000 -#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18 - -#define AR_PHY_RADAR_EXT 0x9940 -#define AR_PHY_RADAR_EXT_ENA 0x00004000 - -#define AR_PHY_RADAR_0 0x9954 -#define AR_PHY_RADAR_0_ENA 0x00000001 -#define AR_PHY_RADAR_0_FFT_ENA 0x80000000 -#define AR_PHY_RADAR_0_INBAND 0x0000003e -#define AR_PHY_RADAR_0_INBAND_S 1 -#define AR_PHY_RADAR_0_PRSSI 0x00000FC0 -#define AR_PHY_RADAR_0_PRSSI_S 6 -#define AR_PHY_RADAR_0_HEIGHT 0x0003F000 -#define AR_PHY_RADAR_0_HEIGHT_S 12 -#define AR_PHY_RADAR_0_RRSSI 0x00FC0000 -#define AR_PHY_RADAR_0_RRSSI_S 18 -#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 -#define AR_PHY_RADAR_0_FIRPWR_S 24 - -#define AR_PHY_RADAR_1 0x9958 -#define AR_PHY_RADAR_1_RELPWR_ENA 0x00800000 -#define AR_PHY_RADAR_1_USE_FIR128 0x00400000 -#define AR_PHY_RADAR_1_RELPWR_THRESH 0x003F0000 -#define AR_PHY_RADAR_1_RELPWR_THRESH_S 16 -#define AR_PHY_RADAR_1_BLOCK_CHECK 0x00008000 -#define AR_PHY_RADAR_1_MAX_RRSSI 0x00004000 -#define AR_PHY_RADAR_1_RELSTEP_CHECK 0x00002000 -#define AR_PHY_RADAR_1_RELSTEP_THRESH 0x00001F00 -#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8 -#define AR_PHY_RADAR_1_MAXLEN 0x000000FF -#define AR_PHY_RADAR_1_MAXLEN_S 0 - -#define AR_PHY_SWITCH_CHAIN_0 0x9960 -#define AR_PHY_SWITCH_COM 0x9964 - -#define AR_PHY_SIGMA_DELTA 0x996C -#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 -#define AR_PHY_SIGMA_DELTA_ADC_SEL_S 0 -#define AR_PHY_SIGMA_DELTA_FILT2 0x000000F8 -#define AR_PHY_SIGMA_DELTA_FILT2_S 3 -#define AR_PHY_SIGMA_DELTA_FILT1 0x00001F00 -#define AR_PHY_SIGMA_DELTA_FILT1_S 8 -#define AR_PHY_SIGMA_DELTA_ADC_CLIP 0x01FFE000 -#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13 - -#define AR_PHY_RESTART 0x9970 -#define AR_PHY_RESTART_DIV_GC 0x001C0000 -#define AR_PHY_RESTART_DIV_GC_S 18 - -#define AR_PHY_RFBUS_REQ 0x997C -#define AR_PHY_RFBUS_REQ_EN 0x00000001 - -#define AR_PHY_TIMING7 0x9980 -#define AR_PHY_TIMING8 0x9984 -#define AR_PHY_TIMING8_PILOT_MASK_2 0x000FFFFF -#define AR_PHY_TIMING8_PILOT_MASK_2_S 0 - -#define AR_PHY_BIN_MASK2_1 0x9988 -#define AR_PHY_BIN_MASK2_2 0x998c -#define AR_PHY_BIN_MASK2_3 0x9990 -#define AR_PHY_BIN_MASK2_4 0x9994 - -#define AR_PHY_BIN_MASK_1 0x9900 -#define AR_PHY_BIN_MASK_2 0x9904 -#define AR_PHY_BIN_MASK_3 0x9908 - -#define AR_PHY_MASK_CTL 0x990c - -#define AR_PHY_BIN_MASK2_4_MASK_4 0x00003FFF -#define AR_PHY_BIN_MASK2_4_MASK_4_S 0 - -#define AR_PHY_TIMING9 0x9998 -#define AR_PHY_TIMING10 0x999c -#define AR_PHY_TIMING10_PILOT_MASK_2 0x000FFFFF -#define AR_PHY_TIMING10_PILOT_MASK_2_S 0 - -#define AR_PHY_TIMING11 0x99a0 -#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF -#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0 -#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 -#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 -#define AR_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000 -#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000 - -#define AR_PHY_RX_CHAINMASK 0x99a4 -#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) -#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 -#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 -#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac - -#define AR_PHY_EXT_CCA0 0x99b8 -#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF -#define AR_PHY_EXT_CCA0_THRESH62_S 0 - -#define AR_PHY_EXT_CCA 0x99bc -#define AR_PHY_EXT_CCA_CYCPWR_THR1 0x0000FE00 -#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9 -#define AR_PHY_EXT_CCA_THRESH62 0x007F0000 -#define AR_PHY_EXT_CCA_THRESH62_S 16 -#define AR_PHY_EXT_MINCCA_PWR 0xFF800000 -#define AR_PHY_EXT_MINCCA_PWR_S 23 -#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000 -#define AR9280_PHY_EXT_MINCCA_PWR_S 16 - -#define AR_PHY_SFCORR_EXT 0x99c0 -#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F -#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0 -#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80 -#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7 -#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000 -#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14 -#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000 -#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21 -#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 - -#define AR_PHY_HALFGI 0x99D0 -#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0 -#define AR_PHY_HALFGI_DSC_MAN_S 4 -#define AR_PHY_HALFGI_DSC_EXP 0x0000000F -#define AR_PHY_HALFGI_DSC_EXP_S 0 - -#define AR_PHY_CHAN_INFO_MEMORY 0x99DC -#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001 - -#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0 - -#define AR_PHY_M_SLEEP 0x99f0 -#define AR_PHY_REFCLKDLY 0x99f4 -#define AR_PHY_REFCLKPD 0x99f8 - -#define AR_PHY_CALMODE 0x99f0 - -#define AR_PHY_CALMODE_IQ 0x00000000 -#define AR_PHY_CALMODE_ADC_GAIN 0x00000001 -#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002 -#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003 - -#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12)) -#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12)) -#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12)) -#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12)) - -#define AR_PHY_CURRENT_RSSI 0x9c1c -#define AR9280_PHY_CURRENT_RSSI 0x9c3c - -#define AR_PHY_RFBUS_GRANT 0x9C20 -#define AR_PHY_RFBUS_GRANT_EN 0x00000001 - -#define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 -#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 - -#define AR_PHY_CHAN_INFO_GAIN 0x9CFC - -#define AR_PHY_MODE 0xA200 -#define AR_PHY_MODE_AR2133 0x08 -#define AR_PHY_MODE_AR5111 0x00 -#define AR_PHY_MODE_AR5112 0x08 -#define AR_PHY_MODE_DYNAMIC 0x04 -#define AR_PHY_MODE_RF2GHZ 0x02 -#define AR_PHY_MODE_RF5GHZ 0x00 -#define AR_PHY_MODE_CCK 0x01 -#define AR_PHY_MODE_OFDM 0x00 -#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100 - -#define AR_PHY_CCK_TX_CTRL 0xA204 -#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 -#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000C -#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2 - -#define AR_PHY_CCK_DETECT 0xA208 -#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F -#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 -/* [12:6] settling time for antenna switch */ -#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 -#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 -#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 - -#define AR_PHY_GAIN_2GHZ 0xA20C -#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 -#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18 -#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00 -#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10 -#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F -#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0 - -#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN 0x003E0000 -#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S 17 -#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN 0x0001F000 -#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S 12 -#define AR_PHY_GAIN_2GHZ_XATTEN2_DB 0x00000FC0 -#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S 6 -#define AR_PHY_GAIN_2GHZ_XATTEN1_DB 0x0000003F -#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S 0 - -#define AR_PHY_CCK_RXCTRL4 0xA21C -#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01F80000 -#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19 - -#define AR_PHY_DAG_CTRLCCK 0xA228 -#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200 -#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00 -#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 - -#define AR_PHY_FORCE_CLKEN_CCK 0xA22C -#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX 0x00000040 - -#define AR_PHY_POWER_TX_RATE3 0xA234 -#define AR_PHY_POWER_TX_RATE4 0xA238 - -#define AR_PHY_SCRM_SEQ_XR 0xA23C -#define AR_PHY_HEADER_DETECT_XR 0xA240 -#define AR_PHY_CHIRP_DETECTED_XR 0xA244 -#define AR_PHY_BLUETOOTH 0xA254 - -#define AR_PHY_TPCRG1 0xA258 -#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000 -#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14 - -#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 -#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 -#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 -#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 -#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 -#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 - -#define AR_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000 -#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22 - -#define AR_PHY_TX_PWRCTRL4 0xa264 -#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001 -#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0 -#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001FE -#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1 - -#define AR_PHY_TX_PWRCTRL6_0 0xa270 -#define AR_PHY_TX_PWRCTRL6_1 0xb270 -#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000 -#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24 - -#define AR_PHY_TX_PWRCTRL7 0xa274 -#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 -#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 - -#define AR_PHY_TX_PWRCTRL9 0xa27C -#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 -#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 - -#define AR_PHY_TX_GAIN_TBL1 0xa300 -#define AR_PHY_TX_GAIN 0x0007F000 -#define AR_PHY_TX_GAIN_S 12 - -#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 -#define AR_PHY_MASK2_M_31_45 0xa3a4 -#define AR_PHY_MASK2_M_16_30 0xa3a8 -#define AR_PHY_MASK2_M_00_15 0xa3ac -#define AR_PHY_MASK2_P_15_01 0xa3b8 -#define AR_PHY_MASK2_P_30_16 0xa3bc -#define AR_PHY_MASK2_P_45_31 0xa3c0 -#define AR_PHY_MASK2_P_61_45 0xa3c4 -#define AR_PHY_SPUR_REG 0x994c - -#define AR_PHY_SPUR_REG_MASK_RATE_CNTL (0xFF << 18) -#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18 - -#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000 -#define AR_PHY_SPUR_REG_MASK_RATE_SELECT (0xFF << 9) -#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S 9 -#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100 -#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7F -#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0 - -#define AR_PHY_PILOT_MASK_01_30 0xa3b0 -#define AR_PHY_PILOT_MASK_31_60 0xa3b4 - -#define AR_PHY_CHANNEL_MASK_01_30 0x99d4 -#define AR_PHY_CHANNEL_MASK_31_60 0x99d8 - -#define AR_PHY_ANALOG_SWAP 0xa268 -#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 - -#define AR_PHY_TPCRG5 0xA26C -#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F -#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 - -/* Carrier leak calibration control, do it after AGC calibration */ -#define AR_PHY_CL_CAL_CTL 0xA358 -#define AR_PHY_CL_CAL_ENABLE 0x00000002 -#define AR_PHY_PARALLEL_CAL_ENABLE 0x00000001 - -#define AR_PHY_POWER_TX_RATE5 0xA38C -#define AR_PHY_POWER_TX_RATE6 0xA390 - -#define AR_PHY_CAL_CHAINMASK 0xA39C - -#define AR_PHY_POWER_TX_SUB 0xA3C8 -#define AR_PHY_POWER_TX_RATE7 0xA3CC -#define AR_PHY_POWER_TX_RATE8 0xA3D0 -#define AR_PHY_POWER_TX_RATE9 0xA3D4 - -#define AR_PHY_XPA_CFG 0xA3D8 -#define AR_PHY_FORCE_XPA_CFG 0x000000001 -#define AR_PHY_FORCE_XPA_CFG_S 0 - -#define AR_PHY_CH1_CCA 0xa864 -#define AR_PHY_CH1_MINCCA_PWR 0x0FF80000 -#define AR_PHY_CH1_MINCCA_PWR_S 19 -#define AR9280_PHY_CH1_MINCCA_PWR 0x1FF00000 -#define AR9280_PHY_CH1_MINCCA_PWR_S 20 - -#define AR_PHY_CH2_CCA 0xb864 -#define AR_PHY_CH2_MINCCA_PWR 0x0FF80000 -#define AR_PHY_CH2_MINCCA_PWR_S 19 - -#define AR_PHY_CH1_EXT_CCA 0xa9bc -#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 -#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 -#define AR9280_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000 -#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16 - -#define AR_PHY_CH2_EXT_CCA 0xb9bc -#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 -#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 - -#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ - int r; \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ - DO_DELAY(regWr); \ - } \ - } while (0) - -#define ATH9K_IS_MIC_ENABLED(ah) \ - ((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE) - -#define ANTSWAP_AB 0x0001 -#define REDUCE_CHAIN_0 0x00000050 -#define REDUCE_CHAIN_1 0x00000051 - -#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ - int i; \ - for (i = 0; i < (_iniarray)->ia_rows; i++) \ - (_bank)[i] = INI_RA((_iniarray), i, _col);; \ - } while (0) - -#endif diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c deleted file mode 100644 index a13668b..0000000 --- a/drivers/net/wireless/ath9k/rc.c +++ /dev/null @@ -1,1752 +0,0 @@ -/* - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2004-2009 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -static struct ath_rate_table ar5416_11na_ratetable = { - 42, - { - { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, 12, - 0, 2, 1, 0, 0, 0, 0, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, - 0, 3, 1, 1, 1, 1, 1, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 0x0a, 0x00, 24, - 2, 4, 2, 2, 2, 2, 2, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 0x0e, 0x00, 36, - 2, 6, 2, 3, 3, 3, 3, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 0x09, 0x00, 48, - 4, 10, 3, 4, 4, 4, 4, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 0x0d, 0x00, 72, - 4, 14, 3, 5, 5, 5, 5, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, - 4, 20, 3, 6, 6, 6, 6, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 0x0c, 0x00, 108, - 4, 23, 3, 7, 7, 7, 7, 0 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ - 6400, 0x80, 0x00, 0, - 0, 2, 3, 8, 24, 8, 24, 3216 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ - 12700, 0x81, 0x00, 1, - 2, 4, 3, 9, 25, 9, 25, 6434 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ - 18800, 0x82, 0x00, 2, - 2, 6, 3, 10, 26, 10, 26, 9650 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ - 25000, 0x83, 0x00, 3, - 4, 10, 3, 11, 27, 11, 27, 12868 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ - 36700, 0x84, 0x00, 4, - 4, 14, 3, 12, 28, 12, 28, 19304 }, - { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ - 48100, 0x85, 0x00, 5, - 4, 20, 3, 13, 29, 13, 29, 25740 }, - { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ - 53500, 0x86, 0x00, 6, - 4, 23, 3, 14, 30, 14, 30, 28956 }, - { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ - 59000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 15, 32, 32180 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ - 12700, 0x88, 0x00, - 8, 0, 2, 3, 16, 33, 16, 33, 6430 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ - 24800, 0x89, 0x00, 9, - 2, 4, 3, 17, 34, 17, 34, 12860 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ - 36600, 0x8a, 0x00, 10, - 2, 6, 3, 18, 35, 18, 35, 19300 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ - 48100, 0x8b, 0x00, 11, - 4, 10, 3, 19, 36, 19, 36, 25736 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ - 69500, 0x8c, 0x00, 12, - 4, 14, 3, 20, 37, 20, 37, 38600 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ - 89500, 0x8d, 0x00, 13, - 4, 20, 3, 21, 38, 21, 38, 51472 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ - 98900, 0x8e, 0x00, 14, - 4, 23, 3, 22, 39, 22, 39, 57890 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ - 108300, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 23, 41, 64320 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ - 13200, 0x80, 0x00, 0, - 0, 2, 3, 8, 24, 24, 24, 6684 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ - 25900, 0x81, 0x00, 1, - 2, 4, 3, 9, 25, 25, 25, 13368 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ - 38600, 0x82, 0x00, 2, - 2, 6, 3, 10, 26, 26, 26, 20052 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ - 49800, 0x83, 0x00, 3, - 4, 10, 3, 11, 27, 27, 27, 26738 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ - 72200, 0x84, 0x00, 4, - 4, 14, 3, 12, 28, 28, 28, 40104 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ - 92900, 0x85, 0x00, 5, - 4, 20, 3, 13, 29, 29, 29, 53476 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ - 102700, 0x86, 0x00, 6, - 4, 23, 3, 14, 30, 30, 30, 60156 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ - 112000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 32, 32, 66840 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ - 122000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 32, 32, 74200 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ - 25800, 0x88, 0x00, 8, - 0, 2, 3, 16, 33, 33, 33, 13360 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ - 49800, 0x89, 0x00, 9, - 2, 4, 3, 17, 34, 34, 34, 26720 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ - 71900, 0x8a, 0x00, 10, - 2, 6, 3, 18, 35, 35, 35, 40080 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ - 92500, 0x8b, 0x00, 11, - 4, 10, 3, 19, 36, 36, 36, 53440 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ - 130300, 0x8c, 0x00, 12, - 4, 14, 3, 20, 37, 37, 37, 80160 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ - 162800, 0x8d, 0x00, 13, - 4, 20, 3, 21, 38, 38, 38, 106880 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ - 178200, 0x8e, 0x00, 14, - 4, 23, 3, 22, 39, 39, 39, 120240 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ - 192100, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 41, 41, 133600 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ - 207000, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 41, 41, 148400 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -/* 4ms frame limit not used for NG mode. The values filled - * for HT are the 64K max aggregate limit */ - -static struct ath_rate_table ar5416_11ng_ratetable = { - 46, - { - { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0x1b, 0x00, 2, - 0, 0, 1, 0, 0, 0, 0, 0 }, - { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 0x1a, 0x04, 4, - 1, 1, 1, 1, 1, 1, 1, 0 }, - { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 0x19, 0x04, 11, - 2, 2, 2, 2, 2, 2, 2, 0 }, - { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 0x18, 0x04, 22, - 3, 3, 2, 3, 3, 3, 3, 0 }, - { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, 12, - 4, 2, 1, 4, 4, 4, 4, 0 }, - { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, - 4, 3, 1, 5, 5, 5, 5, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10100, 0x0a, 0x00, 24, - 6, 4, 1, 6, 6, 6, 6, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 14100, 0x0e, 0x00, 36, - 6, 6, 2, 7, 7, 7, 7, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17700, 0x09, 0x00, 48, - 8, 10, 3, 8, 8, 8, 8, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23700, 0x0d, 0x00, 72, - 8, 14, 3, 9, 9, 9, 9, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, - 8, 20, 3, 10, 10, 10, 10, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 30900, 0x0c, 0x00, 108, - 8, 23, 3, 11, 11, 11, 11, 0 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ - 6400, 0x80, 0x00, 0, - 4, 2, 3, 12, 28, 12, 28, 3216 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ - 12700, 0x81, 0x00, 1, - 6, 4, 3, 13, 29, 13, 29, 6434 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ - 18800, 0x82, 0x00, 2, - 6, 6, 3, 14, 30, 14, 30, 9650 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ - 25000, 0x83, 0x00, 3, - 8, 10, 3, 15, 31, 15, 31, 12868 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ - 36700, 0x84, 0x00, 4, - 8, 14, 3, 16, 32, 16, 32, 19304 }, - { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ - 48100, 0x85, 0x00, 5, - 8, 20, 3, 17, 33, 17, 33, 25740 }, - { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ - 53500, 0x86, 0x00, 6, - 8, 23, 3, 18, 34, 18, 34, 28956 }, - { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ - 59000, 0x87, 0x00, 7, - 8, 25, 3, 19, 35, 19, 36, 32180 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ - 12700, 0x88, 0x00, 8, - 4, 2, 3, 20, 37, 20, 37, 6430 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ - 24800, 0x89, 0x00, 9, - 6, 4, 3, 21, 38, 21, 38, 12860 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ - 36600, 0x8a, 0x00, 10, - 6, 6, 3, 22, 39, 22, 39, 19300 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ - 48100, 0x8b, 0x00, 11, - 8, 10, 3, 23, 40, 23, 40, 25736 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ - 69500, 0x8c, 0x00, 12, - 8, 14, 3, 24, 41, 24, 41, 38600 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ - 89500, 0x8d, 0x00, 13, - 8, 20, 3, 25, 42, 25, 42, 51472 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ - 98900, 0x8e, 0x00, 14, - 8, 23, 3, 26, 43, 26, 44, 57890 }, - { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ - 108300, 0x8f, 0x00, 15, - 8, 25, 3, 27, 44, 27, 45, 64320 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ - 13200, 0x80, 0x00, 0, - 8, 2, 3, 12, 28, 28, 28, 6684 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ - 25900, 0x81, 0x00, 1, - 8, 4, 3, 13, 29, 29, 29, 13368 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ - 38600, 0x82, 0x00, 2, - 8, 6, 3, 14, 30, 30, 30, 20052 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ - 49800, 0x83, 0x00, 3, - 8, 10, 3, 15, 31, 31, 31, 26738 }, - { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ - 72200, 0x84, 0x00, 4, - 8, 14, 3, 16, 32, 32, 32, 40104 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ - 92900, 0x85, 0x00, 5, - 8, 20, 3, 17, 33, 33, 33, 53476 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ - 102700, 0x86, 0x00, 6, - 8, 23, 3, 18, 34, 34, 34, 60156 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ - 112000, 0x87, 0x00, 7, - 8, 23, 3, 19, 35, 36, 36, 66840 }, - { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ - 122000, 0x87, 0x00, 7, - 8, 25, 3, 19, 35, 36, 36, 74200 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ - 25800, 0x88, 0x00, 8, - 8, 2, 3, 20, 37, 37, 37, 13360 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ - 49800, 0x89, 0x00, 9, - 8, 4, 3, 21, 38, 38, 38, 26720 }, - { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ - 71900, 0x8a, 0x00, 10, - 8, 6, 3, 22, 39, 39, 39, 40080 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ - 92500, 0x8b, 0x00, 11, - 8, 10, 3, 23, 40, 40, 40, 53440 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ - 130300, 0x8c, 0x00, 12, - 8, 14, 3, 24, 41, 41, 41, 80160 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ - 162800, 0x8d, 0x00, 13, - 8, 20, 3, 25, 42, 42, 42, 106880 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ - 178200, 0x8e, 0x00, 14, - 8, 23, 3, 26, 43, 43, 43, 120240 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ - 192100, 0x8f, 0x00, 15, - 8, 23, 3, 27, 44, 45, 45, 133600 }, - { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ - 207000, 0x8f, 0x00, 15, - 8, 25, 3, 27, 44, 45, 45, 148400 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -static struct ath_rate_table ar5416_11a_ratetable = { - 8, - { - { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, (0x80|12), - 0, 2, 1, 0, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, - 0, 3, 1, 1, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 0x0a, 0x00, (0x80|24), - 2, 4, 2, 2, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 0x0e, 0x00, 36, - 2, 6, 2, 3, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 0x09, 0x00, (0x80|48), - 4, 10, 3, 4, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 0x0d, 0x00, 72, - 4, 14, 3, 5, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, - 4, 19, 3, 6, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 0x0c, 0x00, 108, - 4, 23, 3, 7, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - -static struct ath_rate_table ar5416_11g_ratetable = { - 12, - { - { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0x1b, 0x00, 2, - 0, 0, 1, 0, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 0x1a, 0x04, 4, - 1, 1, 1, 1, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 0x19, 0x04, 11, - 2, 2, 2, 2, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 0x18, 0x04, 22, - 3, 3, 2, 3, 0 }, - { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, 12, - 4, 2, 1, 4, 0 }, - { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, - 4, 3, 1, 5, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 0x0a, 0x00, 24, - 6, 4, 1, 6, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 0x0e, 0x00, 36, - 6, 6, 2, 7, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 0x09, 0x00, 48, - 8, 10, 3, 8, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 0x0d, 0x00, 72, - 8, 14, 3, 9, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, - 8, 19, 3, 10, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 0x0c, 0x00, 108, - 8, 23, 3, 11, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - -static struct ath_rate_table ar5416_11b_ratetable = { - 4, - { - { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0x1b, 0x00, (0x80|2), - 0, 0, 1, 0, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1800, 0x1a, 0x04, (0x80|4), - 1, 1, 1, 1, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4300, 0x19, 0x04, (0x80|11), - 1, 2, 2, 2, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 7100, 0x18, 0x04, (0x80|22), - 1, 4, 100, 3, 0 }, - }, - 100, /* probe interval */ - 100, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - -static inline int8_t median(int8_t a, int8_t b, int8_t c) -{ - if (a >= b) { - if (b >= c) - return b; - else if (a > c) - return c; - else - return a; - } else { - if (a >= c) - return a; - else if (b >= c) - return c; - else - return b; - } -} - -static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv) -{ - u8 i, j, idx, idx_next; - - for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { - for (j = 0; j <= i-1; j++) { - idx = ath_rc_priv->valid_rate_index[j]; - idx_next = ath_rc_priv->valid_rate_index[j+1]; - - if (rate_table->info[idx].ratekbps > - rate_table->info[idx_next].ratekbps) { - ath_rc_priv->valid_rate_index[j] = idx_next; - ath_rc_priv->valid_rate_index[j+1] = idx; - } - } - } -} - -static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) -{ - u8 i; - - for (i = 0; i < ath_rc_priv->rate_table_size; i++) - ath_rc_priv->valid_rate_index[i] = 0; -} - -static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, - u8 index, int valid_tx_rate) -{ - ASSERT(index <= ath_rc_priv->rate_table_size); - ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; -} - -static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, - u8 index) -{ - ASSERT(index <= ath_rc_priv->rate_table_size); - return ath_rc_priv->valid_rate_index[index]; -} - -static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, - u8 *next_idx) -{ - u8 i; - - for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i+1]; - return 1; - } - } - - /* No more valid rates */ - *next_idx = 0; - - return 0; -} - -/* Return true only for single stream */ - -static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) -{ - if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG)) - return 0; - if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) - return 0; - if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) - return 0; - if (!ignore_cw && WLAN_RC_PHY_HT(phy)) - if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) - return 0; - if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) - return 0; - return 1; -} - -static inline int -ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, u8 *next_idx) -{ - int8_t i; - - for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i-1]; - return 1; - } - } - - return 0; -} - -static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - u32 capflag) -{ - u8 i, hi = 0; - u32 valid; - - for (i = 0; i < rate_table->rate_cnt; i++) { - valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? - rate_table->info[i].valid_single_stream : - rate_table->info[i].valid); - if (valid == 1) { - u32 phy = rate_table->info[i].phy; - u8 valid_rate_count = 0; - - if (!ath_rc_valid_phyrate(phy, capflag, 0)) - continue; - - valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - - ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(ath_rc_priv, i, 1); - hi = A_MAX(hi, i); - } - } - - return hi; -} - -static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - struct ath_rateset *rateset, - u32 capflag) -{ - u8 i, j, hi = 0; - - /* Use intersection of working rates and valid rates */ - for (i = 0; i < rateset->rs_nrates; i++) { - for (j = 0; j < rate_table->rate_cnt; j++) { - u32 phy = rate_table->info[j].phy; - u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? - rate_table->info[j].valid_single_stream : - rate_table->info[j].valid); - u8 rate = rateset->rs_rates[i]; - u8 dot11rate = rate_table->info[j].dot11rate; - - /* We allow a rate only if its valid and the - * capflag matches one of the validity - * (VALID/VALID_20/VALID_40) flags */ - - if (((rate & 0x7F) == (dot11rate & 0x7F)) && - ((valid & WLAN_RC_CAP_MODE(capflag)) == - WLAN_RC_CAP_MODE(capflag)) && - !WLAN_RC_PHY_HT(phy)) { - u8 valid_rate_count = 0; - - if (!ath_rc_valid_phyrate(phy, capflag, 0)) - continue; - - valid_rate_count = - ath_rc_priv->valid_phy_ratecnt[phy]; - - ath_rc_priv->valid_phy_rateidx[phy] - [valid_rate_count] = j; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(ath_rc_priv, j, 1); - hi = A_MAX(hi, j); - } - } - } - - return hi; -} - -static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - u8 *mcs_set, u32 capflag) -{ - struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; - - u8 i, j, hi = 0; - - /* Use intersection of working rates and valid rates */ - for (i = 0; i < rateset->rs_nrates; i++) { - for (j = 0; j < rate_table->rate_cnt; j++) { - u32 phy = rate_table->info[j].phy; - u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? - rate_table->info[j].valid_single_stream : - rate_table->info[j].valid); - u8 rate = rateset->rs_rates[i]; - u8 dot11rate = rate_table->info[j].dot11rate; - - if (((rate & 0x7F) != (dot11rate & 0x7F)) || - !WLAN_RC_PHY_HT(phy) || - !WLAN_RC_PHY_HT_VALID(valid, capflag)) - continue; - - if (!ath_rc_valid_phyrate(phy, capflag, 0)) - continue; - - ath_rc_priv->valid_phy_rateidx[phy] - [ath_rc_priv->valid_phy_ratecnt[phy]] = j; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(ath_rc_priv, j, 1); - hi = A_MAX(hi, j); - } - } - - return hi; -} - -static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - int *is_probing) -{ - u32 dt, best_thruput, this_thruput, now_msec; - u8 rate, next_rate, best_rate, maxindex, minindex; - int8_t rssi_last, rssi_reduce = 0, index = 0; - - *is_probing = 0; - - rssi_last = median(ath_rc_priv->rssi_last, - ath_rc_priv->rssi_last_prev, - ath_rc_priv->rssi_last_prev2); - - /* - * Age (reduce) last ack rssi based on how old it is. - * The bizarre numbers are so the delta is 160msec, - * meaning we divide by 16. - * 0msec <= dt <= 25msec: don't derate - * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB - * 185msec <= dt: derate by 10dB - */ - - now_msec = jiffies_to_msecs(jiffies); - dt = now_msec - ath_rc_priv->rssi_time; - - if (dt >= 185) - rssi_reduce = 10; - else if (dt >= 25) - rssi_reduce = (u8)((dt - 25) >> 4); - - /* Now reduce rssi_last by rssi_reduce */ - if (rssi_last < rssi_reduce) - rssi_last = 0; - else - rssi_last -= rssi_reduce; - - /* - * Now look up the rate in the rssi table and return it. - * If no rates match then we return 0 (lowest rate) - */ - - best_thruput = 0; - maxindex = ath_rc_priv->max_valid_rate-1; - - minindex = 0; - best_rate = minindex; - - /* - * Try the higher rate first. It will reduce memory moving time - * if we have very good channel characteristics. - */ - for (index = maxindex; index >= minindex ; index--) { - u8 per_thres; - - rate = ath_rc_priv->valid_rate_index[index]; - if (rate > ath_rc_priv->rate_max_phy) - continue; - - /* - * For TCP the average collision rate is around 11%, - * so we ignore PERs less than this. This is to - * prevent the rate we are currently using (whose - * PER might be in the 10-15 range because of TCP - * collisions) looking worse than the next lower - * rate whose PER has decayed close to 0. If we - * used to next lower rate, its PER would grow to - * 10-15 and we would be worse off then staying - * at the current rate. - */ - per_thres = ath_rc_priv->state[rate].per; - if (per_thres < 12) - per_thres = 12; - - this_thruput = rate_table->info[rate].user_ratekbps * - (100 - per_thres); - - if (best_thruput <= this_thruput) { - best_thruput = this_thruput; - best_rate = rate; - } - } - - rate = best_rate; - ath_rc_priv->rssi_last_lookup = rssi_last; - - /* - * Must check the actual rate (ratekbps) to account for - * non-monoticity of 11g's rate table - */ - - if (rate >= ath_rc_priv->rate_max_phy) { - rate = ath_rc_priv->rate_max_phy; - - /* Probe the next allowed phy state */ - if (ath_rc_get_nextvalid_txrate(rate_table, - ath_rc_priv, rate, &next_rate) && - (now_msec - ath_rc_priv->probe_time > - rate_table->probe_interval) && - (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { - rate = next_rate; - ath_rc_priv->probe_rate = rate; - ath_rc_priv->probe_time = now_msec; - ath_rc_priv->hw_maxretry_pktcnt = 0; - *is_probing = 1; - } - } - - if (rate > (ath_rc_priv->rate_table_size - 1)) - rate = ath_rc_priv->rate_table_size - 1; - - ASSERT((rate_table->info[rate].valid && - (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) || - (rate_table->info[rate].valid_single_stream && - !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))); - - return rate; -} - -static void ath_rc_rate_set_series(struct ath_rate_table *rate_table, - struct ieee80211_tx_rate *rate, - struct ieee80211_tx_rate_control *txrc, - u8 tries, u8 rix, int rtsctsenable) -{ - rate->count = tries; - rate->idx = rix; - - if (txrc->short_preamble) - rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; - if (txrc->rts || rtsctsenable) - rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; - if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_SHORT_GI; - if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_MCS; -} - -static void ath_rc_rate_set_rtscts(struct ath_softc *sc, - struct ath_rate_table *rate_table, - struct ieee80211_tx_info *tx_info) -{ - struct ieee80211_tx_rate *rates = tx_info->control.rates; - int i = 0, rix = 0, cix, enable_g_protection = 0; - - /* get the cix for the lowest valid rix */ - for (i = 3; i >= 0; i--) { - if (rates[i].count && (rates[i].idx >= 0)) { - rix = rates[i].idx; - break; - } - } - cix = rate_table->info[rix].ctrl_rate; - - /* All protection frames are transmited at 2Mb/s for 802.11g, - * otherwise we transmit them at 1Mb/s */ - if (sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ && - !conf_is_ht(&sc->hw->conf)) - enable_g_protection = 1; - - /* - * If 802.11g protection is enabled, determine whether to use RTS/CTS or - * just CTS. Note that this is only done for OFDM/HT unicast frames. - */ - if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) && - !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && - (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM || - WLAN_RC_PHY_HT(rate_table->info[rix].phy))) { - rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; - cix = rate_table->info[enable_g_protection].ctrl_rate; - } - - tx_info->control.rts_cts_rate_idx = cix; -} - -static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - u8 rix, u16 stepdown, - u16 min_rate) -{ - u32 j; - u8 nextindex; - - if (min_rate) { - for (j = RATE_TABLE_SIZE; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } - } else { - for (j = stepdown; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } - } - return rix; -} - -static void ath_rc_ratefind(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_rate_control *txrc) -{ - struct ath_rate_table *rate_table; - struct sk_buff *skb = txrc->skb; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - u8 try_per_rate = 0, i = 0, rix, nrix; - int is_probe = 0; - - rate_table = sc->cur_rate_table; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe); - nrix = rix; - - if (is_probe) { - /* set one try for probe rates. For the - * probes don't enable rts */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - 1, nrix, 0); - - try_per_rate = (ATH_11N_TXMAXTRY/4); - /* Get the next tried/allowed rate. No RTS for the next series - * after the probe rate - */ - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, 0); - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, nrix, 0); - - tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } else { - try_per_rate = (ATH_11N_TXMAXTRY/4); - /* Set the choosen rate. No RTS for first series entry. */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, nrix, 0); - } - - /* Fill in the other rates for multirate retry */ - for ( ; i < 4; i++) { - u8 try_num; - u8 min_rate; - - try_num = ((i + 1) == 4) ? - ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ; - min_rate = (((i + 1) == 4) && 0); - - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, min_rate); - /* All other rates in the series have RTS enabled */ - ath_rc_rate_set_series(rate_table, &rates[i], txrc, - try_num, nrix, 1); - } - - /* - * NB:Change rate series to enable aggregation when operating - * at lower MCS rates. When first rate in series is MCS2 - * in HT40 @ 2.4GHz, series should look like: - * - * {MCS2, MCS1, MCS0, MCS0}. - * - * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should - * look like: - * - * {MCS3, MCS2, MCS1, MCS1} - * - * So, set fourth rate in series to be same as third one for - * above conditions. - */ - if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) && - (conf_is_ht(&sc->hw->conf))) { - 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))) { - rates[3].idx = rates[2].idx; - rates[3].flags = rates[2].flags; - } - } - - /* - * Force hardware to use computed duration for next - * fragment by disabling multi-rate retry, which - * updates duration based on the multi-rate duration table. - * - * FIXME: Fix duration - */ - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && - (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) { - rates[1].count = rates[2].count = rates[3].count = 0; - rates[1].idx = rates[2].idx = rates[3].idx = 0; - rates[0].count = ATH_TXMAXTRY; - } - - /* Setup RTS/CTS */ - ath_rc_rate_set_rtscts(sc, rate_table, tx_info); -} - -static bool ath_rc_update_per(struct ath_softc *sc, - struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - struct ath_tx_info_priv *tx_info_priv, - int tx_rate, int xretries, int retries, - u32 now_msec) -{ - bool state_change = false; - int count; - u8 last_per; - static u32 nretry_to_per_lookup[10] = { - 100 * 0 / 1, - 100 * 1 / 4, - 100 * 1 / 2, - 100 * 3 / 4, - 100 * 4 / 5, - 100 * 5 / 6, - 100 * 6 / 7, - 100 * 7 / 8, - 100 * 8 / 9, - 100 * 9 / 10 - }; - - last_per = ath_rc_priv->state[tx_rate].per; - - if (xretries) { - if (xretries == 1) { - ath_rc_priv->state[tx_rate].per += 30; - if (ath_rc_priv->state[tx_rate].per > 100) - ath_rc_priv->state[tx_rate].per = 100; - } else { - /* xretries == 2 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - ath_rc_priv->state[tx_rate].per = - (u8)(last_per - (last_per >> 3) + (100 >> 3)); - } - - /* xretries == 1 or 2 */ - - if (ath_rc_priv->probe_rate == tx_rate) - ath_rc_priv->probe_rate = 0; - - } else { /* xretries == 0 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - if (tx_info_priv->n_bad_frames) { - /* 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 - * next one worked. For the one that worked, - * n_bad_frames subframes out of n_frames wored, - * so the PER for that part is - * 100 * n_bad_frames / n_frames, and it contributes - * 100 * n_bad_frames / (n_frames * (retries+1)) to - * the above PER. The expression below is a - * simplified version of the sum of these two terms. - */ - if (tx_info_priv->n_frames > 0) { - int n_frames, n_bad_frames; - u8 cur_per, new_per; - - n_bad_frames = retries * tx_info_priv->n_frames + - tx_info_priv->n_bad_frames; - n_frames = tx_info_priv->n_frames * (retries + 1); - cur_per = (100 * n_bad_frames / n_frames) >> 3; - new_per = (u8)(last_per - (last_per >> 3) + cur_per); - ath_rc_priv->state[tx_rate].per = new_per; - } - } else { - ath_rc_priv->state[tx_rate].per = - (u8)(last_per - (last_per >> 3) + - (nretry_to_per_lookup[retries] >> 3)); - } - - ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; - ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; - ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi; - ath_rc_priv->rssi_time = now_msec; - - /* - * If we got at most one retry then increase the max rate if - * this was a probe. Otherwise, ignore the probe. - */ - if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { - if (retries > 0 || 2 * tx_info_priv->n_bad_frames > - tx_info_priv->n_frames) { - /* - * Since we probed with just a single attempt, - * any retries means the probe failed. Also, - * if the attempt worked, but more than half - * the subframes were bad then also consider - * the probe a failure. - */ - ath_rc_priv->probe_rate = 0; - } else { - u8 probe_rate = 0; - - ath_rc_priv->rate_max_phy = - ath_rc_priv->probe_rate; - probe_rate = ath_rc_priv->probe_rate; - - if (ath_rc_priv->state[probe_rate].per > 30) - ath_rc_priv->state[probe_rate].per = 20; - - ath_rc_priv->probe_rate = 0; - - /* - * Since this probe succeeded, we allow the next - * probe twice as soon. This allows the maxRate - * to move up faster if the probes are - * succesful. - */ - ath_rc_priv->probe_time = - now_msec - rate_table->probe_interval / 2; - } - } - - if (retries > 0) { - /* - * Don't update anything. We don't know if - * this was because of collisions or poor signal. - * - * Later: if rssi_ack is close to - * ath_rc_priv->state[txRate].rssi_thres and we see lots - * of retries, then we could increase - * ath_rc_priv->state[txRate].rssi_thres. - */ - ath_rc_priv->hw_maxretry_pktcnt = 0; - } else { - int32_t rssi_ackAvg; - int8_t rssi_thres; - int8_t rssi_ack_vmin; - - /* - * It worked with no retries. First ignore bogus (small) - * rssi_ack values. - */ - if (tx_rate == ath_rc_priv->rate_max_phy && - ath_rc_priv->hw_maxretry_pktcnt < 255) { - ath_rc_priv->hw_maxretry_pktcnt++; - } - - if (tx_info_priv->tx.ts_rssi < - rate_table->info[tx_rate].rssi_ack_validmin) - goto exit; - - /* Average the rssi */ - if (tx_rate != ath_rc_priv->rssi_sum_rate) { - ath_rc_priv->rssi_sum_rate = tx_rate; - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - } - - ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; - ath_rc_priv->rssi_sum_cnt++; - - if (ath_rc_priv->rssi_sum_cnt < 4) - goto exit; - - rssi_ackAvg = - (ath_rc_priv->rssi_sum + 2) / 4; - rssi_thres = - ath_rc_priv->state[tx_rate].rssi_thres; - rssi_ack_vmin = - rate_table->info[tx_rate].rssi_ack_validmin; - - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - - /* Now reduce the current rssi threshold */ - if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { - ath_rc_priv->state[tx_rate].rssi_thres--; - } - - state_change = true; - } - } -exit: - return state_change; -} - -/* Update PER, RSSI and whatever else that the code thinks it is doing. - If you can make sense of all this, you really need to go out more. */ - -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ath_tx_info_priv *tx_info_priv, - int tx_rate, int xretries, int retries) -{ -#define CHK_RSSI(rate) \ - ((ath_rc_priv->state[(rate)].rssi_thres + \ - rate_table->info[(rate)].rssi_ack_deltamin) > \ - ath_rc_priv->state[(rate)+1].rssi_thres) - - u32 now_msec = jiffies_to_msecs(jiffies); - int rate; - u8 last_per; - bool state_change = false; - struct ath_rate_table *rate_table = sc->cur_rate_table; - int size = ath_rc_priv->rate_table_size; - - if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) - return; - - /* To compensate for some imbalance between ctrl and ext. channel */ - - if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) - tx_info_priv->tx.ts_rssi = - tx_info_priv->tx.ts_rssi < 3 ? 0 : - tx_info_priv->tx.ts_rssi - 3; - - last_per = ath_rc_priv->state[tx_rate].per; - - /* Update PER first */ - state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info_priv, tx_rate, xretries, - retries, now_msec); - - /* - * If this rate looks bad (high PER) then stop using it for - * a while (except if we are probing). - */ - if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && - rate_table->info[tx_rate].ratekbps <= - rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { - ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - (u8)tx_rate, &ath_rc_priv->rate_max_phy); - - /* Don't probe for a little while. */ - ath_rc_priv->probe_time = now_msec; - } - - if (state_change) { - /* - * Make sure the rates above this have higher rssi thresholds. - * (Note: Monotonicity is kept within the OFDM rates and - * within the CCK rates. However, no adjustment is - * made to keep the rssi thresholds monotonically - * increasing between the CCK and OFDM rates.) - */ - for (rate = tx_rate; rate < size - 1; rate++) { - if (rate_table->info[rate+1].phy != - rate_table->info[tx_rate].phy) - break; - - if (CHK_RSSI(rate)) { - ath_rc_priv->state[rate+1].rssi_thres = - ath_rc_priv->state[rate].rssi_thres + - rate_table->info[rate].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) - break; - - if (CHK_RSSI(rate)) { - if (ath_rc_priv->state[rate+1].rssi_thres < - rate_table->info[rate].rssi_ack_deltamin) - ath_rc_priv->state[rate].rssi_thres = 0; - else { - ath_rc_priv->state[rate].rssi_thres = - ath_rc_priv->state[rate+1].rssi_thres - - rate_table->info[rate].rssi_ack_deltamin; - } - - if (ath_rc_priv->state[rate].rssi_thres < - rate_table->info[rate].rssi_ack_validmin) { - ath_rc_priv->state[rate].rssi_thres = - rate_table->info[rate].rssi_ack_validmin; - } - } - } - } - - /* Make sure the rates below this have lower PER */ - /* Monotonicity is kept only for rates below the current rate. */ - if (ath_rc_priv->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) - break; - - if (ath_rc_priv->state[rate].per > - ath_rc_priv->state[rate+1].per) { - ath_rc_priv->state[rate].per = - ath_rc_priv->state[rate+1].per; - } - } - } - - /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < size - 1; rate++) { - if (ath_rc_priv->state[rate+1].per < - ath_rc_priv->state[rate].per) - ath_rc_priv->state[rate+1].per = - ath_rc_priv->state[rate].per; - } - - /* Every so often, we reduce the thresholds and - * PER (different for CCK and OFDM). */ - if (now_msec - ath_rc_priv->rssi_down_time >= - rate_table->rssi_reduce_interval) { - - for (rate = 0; rate < size; rate++) { - if (ath_rc_priv->state[rate].rssi_thres > - rate_table->info[rate].rssi_ack_validmin) - ath_rc_priv->state[rate].rssi_thres -= 1; - } - ath_rc_priv->rssi_down_time = now_msec; - } - - /* Every so often, we reduce the thresholds - * and PER (different for CCK and OFDM). */ - if (now_msec - ath_rc_priv->per_down_time >= - rate_table->rssi_reduce_interval) { - for (rate = 0; rate < size; rate++) { - ath_rc_priv->state[rate].per = - 7 * ath_rc_priv->state[rate].per / 8; - } - - ath_rc_priv->per_down_time = now_msec; - } - - ath_debug_stat_retries(sc, tx_rate, xretries, retries, - ath_rc_priv->state[tx_rate].per); - -#undef CHK_RSSI -} - -static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, - struct ieee80211_tx_rate *rate) -{ - int rix; - - if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (rate->flags & IEEE80211_TX_RC_SHORT_GI)) - rix = rate_table->info[rate->idx].ht_index; - else if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - rix = rate_table->info[rate->idx].sgi_index; - else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - rix = rate_table->info[rate->idx].cw40index; - else - rix = rate_table->info[rate->idx].base_index; - - return rix; -} - -static void ath_rc_tx_status(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_info *tx_info, - int final_ts_idx, int xretries, int long_retry) -{ - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - struct ath_rate_table *rate_table; - struct ieee80211_tx_rate *rates = tx_info->status.rates; - u8 flags; - u32 i = 0, rix; - - rate_table = sc->cur_rate_table; - - /* - * If the first rate is not the final index, there - * are intermediate rate failures to be processed. - */ - if (final_ts_idx != 0) { - /* Process intermediate rates that failed.*/ - for (i = 0; i < final_ts_idx ; i++) { - if (rates[i].count != 0 && (rates[i].idx >= 0)) { - flags = rates[i].flags; - - /* If HT40 and we have switched mode from - * 40 to 20 => don't update */ - - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(rate_table, &rates[i]); - ath_rc_update_ht(sc, ath_rc_priv, - tx_info_priv, rix, - xretries ? 1 : 2, - rates[i].count); - } - } - } else { - /* - * Handle the special case of MIMO PS burst, where the second - * aggregate is sent out with only one rate and one try. - * Treating it as an excessive retry penalizes the rate - * inordinately. - */ - if (rates[0].count == 1 && xretries == 1) - xretries = 2; - } - - flags = rates[i].flags; - - /* If HT40 and we have switched mode from 40 to 20 => don't update */ - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(rate_table, &rates[i]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, - xretries, long_retry); -} - -static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, - enum ieee80211_band band, - bool is_ht, bool is_cw_40) -{ - int mode = 0; - - switch(band) { - case IEEE80211_BAND_2GHZ: - mode = ATH9K_MODE_11G; - if (is_ht) - mode = ATH9K_MODE_11NG_HT20; - if (is_cw_40) - mode = ATH9K_MODE_11NG_HT40PLUS; - break; - case IEEE80211_BAND_5GHZ: - mode = ATH9K_MODE_11A; - if (is_ht) - mode = ATH9K_MODE_11NA_HT20; - if (is_cw_40) - mode = ATH9K_MODE_11NA_HT40PLUS; - break; - default: - DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n"); - return NULL; - } - - BUG_ON(mode >= ATH9K_MODE_MAX); - - DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); - return sc->hw_rate_table[mode]; -} - -static void ath_rc_init(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct ath_rate_table *rate_table) -{ - struct ath_rateset *rateset = &ath_rc_priv->neg_rates; - u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; - u8 i, j, k, hi = 0, hthi = 0; - - if (!rate_table) { - DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); - return; - } - - /* Initial rate table size. Will change depending - * on the working rate set */ - ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; - - /* Initialize thresholds according to the global rate table */ - for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->state[i].rssi_thres = - rate_table->info[i].rssi_ack_validmin; - ath_rc_priv->state[i].per = 0; - } - - /* Determine the valid rates */ - ath_rc_init_valid_txmask(ath_rc_priv); - - for (i = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < MAX_TX_RATE_PHY; j++) - ath_rc_priv->valid_phy_rateidx[i][j] = 0; - ath_rc_priv->valid_phy_ratecnt[i] = 0; - } - - if (!rateset->rs_nrates) { - /* No working rate, just initialize valid rates */ - hi = ath_rc_init_validrates(ath_rc_priv, rate_table, - ath_rc_priv->ht_cap); - } else { - /* Use intersection of working rates and valid rates */ - hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table, - rateset, ath_rc_priv->ht_cap); - if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) { - hthi = ath_rc_setvalid_htrates(ath_rc_priv, - rate_table, - ht_mcs, - ath_rc_priv->ht_cap); - } - hi = A_MAX(hi, hthi); - } - - ath_rc_priv->rate_table_size = hi + 1; - ath_rc_priv->rate_max_phy = 0; - ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); - - for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { - ath_rc_priv->valid_rate_index[k++] = - ath_rc_priv->valid_phy_rateidx[i][j]; - } - - if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) - || !ath_rc_priv->valid_phy_ratecnt[i]) - continue; - - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; - } - ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); - ASSERT(k <= RATE_TABLE_SIZE); - - ath_rc_priv->max_valid_rate = k; - ath_rc_sort_validrates(rate_table, ath_rc_priv); - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; - sc->cur_rate_table = rate_table; - - DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n", - ath_rc_priv->ht_cap); -} - -static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, - bool is_cw40, bool is_sgi40) -{ - u8 caps = 0; - - if (sta->ht_cap.ht_supported) { - caps = WLAN_RC_HT_FLAG; - if (sc->sc_ah->caps.tx_chainmask != 1 && - ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) { - if (sta->ht_cap.mcs.rx_mask[1]) - caps |= WLAN_RC_DS_FLAG; - } - if (is_cw40) - caps |= WLAN_RC_40_FLAG; - if (is_sgi40) - caps |= WLAN_RC_SGI_FLAG; - } - - return caps; -} - -/***********************************/ -/* mac80211 Rate Control callbacks */ -/***********************************/ - -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_rate_priv *ath_rc_priv = priv_sta; - struct ath_tx_info_priv *tx_info_priv = NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr; - int final_ts_idx, tx_status = 0, is_underrun = 0; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; - - if (!priv_sta || !ieee80211_is_data(fc) || - !tx_info_priv->update_rc) - goto exit; - - if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) - goto exit; - - /* - * If underrun error is seen assume it as an excessive retry only - * if prefetch trigger level have reached the max (0x3f for 5416) - * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY - * times. This affects how ratectrl updates PER for the failed rate. - */ - if (tx_info_priv->tx.ts_flags & - (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && - ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) { - tx_status = 1; - is_underrun = 1; - } - - if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || - (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) - tx_status = 1; - - ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, - (is_underrun) ? ATH_11N_TXMAXTRY : - tx_info_priv->tx.ts_longretry); - - /* Check if aggregation has to be enabled for this tid */ - if (conf_is_ht(&sc->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc)) { - u8 *qc, tid; - struct ath_node *an; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - an = (struct ath_node *)sta->drv_priv; - - if(ath_tx_aggr_check(sc, an, tid)) - ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid); - } - } - - ath_debug_stat_rc(sc, skb); -exit: - kfree(tx_info_priv); -} - -static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct ieee80211_supported_band *sband = txrc->sband; - struct sk_buff *skb = txrc->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - __le16 fc = hdr->frame_control; - - /* lowest rate for management and multicast/broadcast frames */ - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta) { - tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); - tx_info->control.rates[0].count = - is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; - return; - } - - /* Find tx rate for unicast frames */ - ath_rc_ratefind(sc, ath_rc_priv, txrc); -} - -static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ath_rate_table *rate_table = NULL; - bool is_cw40, is_sgi40; - int i, j = 0; - - for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { - ath_rc_priv->neg_rates.rs_rates[j] - = (sband->bitrates[i].bitrate * 2) / 10; - j++; - } - } - ath_rc_priv->neg_rates.rs_nrates = j; - - if (sta->ht_cap.ht_supported) { - for (i = 0, j = 0; i < 77; i++) { - if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) - ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; - if (j == ATH_RATE_MAX) - break; - } - ath_rc_priv->neg_ht_rates.rs_nrates = j; - } - - is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; - is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; - - /* Choose rate table first */ - - if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) || - (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { - rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported, - is_cw40); - } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { - /* cur_rate_table would be set on init through config() */ - rate_table = sc->cur_rate_table; - } - - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40); - ath_rc_init(sc, priv_sta, sband, sta, rate_table); -} - -static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - u32 changed) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ath_rate_table *rate_table = NULL; - bool oper_cw40 = false, oper_sgi40; - bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? - true : false; - bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ? - true : false; - - /* FIXME: Handle AP mode later when we support CWM */ - - if (changed & IEEE80211_RC_HT_CHANGED) { - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) - return; - - if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || - sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) - oper_cw40 = true; - - oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? - true : false; - - if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { - rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported, - oper_cw40); - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, - oper_cw40, oper_sgi40); - ath_rc_init(sc, priv_sta, sband, sta, rate_table); - - DPRINTF(sc, ATH_DBG_CONFIG, - "Operating HT Bandwidth changed to: %d\n", - sc->hw->conf.channel_type); - } - } -} - -static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ - struct ath_wiphy *aphy = hw->priv; - return aphy->sc; -} - -static void ath_rate_free(void *priv) -{ - return; -} - -static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *rate_priv; - - rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); - if (!rate_priv) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to allocate private rc structure\n"); - return NULL; - } - - rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); - rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max; - - return rate_priv; -} - -static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, - void *priv_sta) -{ - struct ath_rate_priv *rate_priv = priv_sta; - kfree(rate_priv); -} - -static struct rate_control_ops ath_rate_ops = { - .module = NULL, - .name = "ath9k_rate_control", - .tx_status = ath_tx_status, - .get_rate = ath_get_rate, - .rate_init = ath_rate_init, - .rate_update = ath_rate_update, - .alloc = ath_rate_alloc, - .free = ath_rate_free, - .alloc_sta = ath_rate_alloc_sta, - .free_sta = ath_rate_free_sta, -}; - -void ath_rate_attach(struct ath_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11B] = - &ar5416_11b_ratetable; - sc->hw_rate_table[ATH9K_MODE_11A] = - &ar5416_11a_ratetable; - sc->hw_rate_table[ATH9K_MODE_11G] = - &ar5416_11g_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = - &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = - &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = - &ar5416_11ng_ratetable; -} - -int ath_rate_control_register(void) -{ - return ieee80211_rate_control_register(&ath_rate_ops); -} - -void ath_rate_control_unregister(void) -{ - ieee80211_rate_control_unregister(&ath_rate_ops); -} diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h deleted file mode 100644 index e3abd76..0000000 --- a/drivers/net/wireless/ath9k/rc.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2004 Sam Leffler, Errno Consulting - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef RC_H -#define RC_H - -struct ath_softc; - -#define ATH_RATE_MAX 30 -#define RATE_TABLE_SIZE 64 -#define MAX_TX_RATE_PHY 48 - -/* VALID_ALL - valid for 20/40/Legacy, - * VALID - Legacy only, - * VALID_20 - HT 20 only, - * VALID_40 - HT 40 only */ - -#define INVALID 0x0 -#define VALID 0x1 -#define VALID_20 0x2 -#define VALID_40 0x4 -#define VALID_2040 (VALID_20|VALID_40) -#define VALID_ALL (VALID_2040|VALID) - -enum { - WLAN_RC_PHY_OFDM, - WLAN_RC_PHY_CCK, - WLAN_RC_PHY_HT_20_SS, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - 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_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)) - -#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) - -#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ - (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID)) - -/* Return TRUE if flag supports HT20 && client supports HT20 or - * return TRUE if flag supports HT40 && client supports HT40. - * This is used becos some rates overlap between HT20/HT40. - */ -#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ - (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \ - ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG))) - -#define WLAN_RC_DS_FLAG (0x01) -#define WLAN_RC_40_FLAG (0x02) -#define WLAN_RC_SGI_FLAG (0x04) -#define WLAN_RC_HT_FLAG (0x08) - -/** - * 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 - */ -struct ath_rate_table { - int rate_cnt; - struct { - 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; - u32 rssi_reduce_interval; - u8 initial_ratemax; -}; - -struct ath_tx_ratectrl_state { - int8_t rssi_thres; /* required rssi for this rate (dB) */ - u8 per; /* recent estimate of packet error rate (%) */ -}; - -struct ath_rateset { - u8 rs_nrates; - u8 rs_rates[ATH_RATE_MAX]; -}; - -/** - * struct ath_rate_priv - Rate Control priv data - * @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 - * @prev_data_rix: rate idx of last data frame - * @ht_cap: HT capabilities - * @neg_rates: Negotatied rates - * @neg_ht_rates: Negotiated HT rates - */ -struct ath_rate_priv { - 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; - u8 hw_maxretry_pktcnt; - u8 max_valid_rate; - u8 valid_rate_index[RATE_TABLE_SIZE]; - u8 ht_cap; - u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; - u8 rate_max_phy; - u32 rssi_time; - u32 rssi_down_time; - u32 probe_time; - u32 per_down_time; - u32 probe_interval; - u32 prev_data_rix; - u32 tx_triglevel_max; - struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; - struct ath_rateset neg_rates; - struct ath_rateset neg_ht_rates; - struct ath_rate_softc *asc; -}; - -enum ath9k_internal_frame_type { - ATH9K_NOT_INTERNAL, - ATH9K_INT_PAUSE, - ATH9K_INT_UNPAUSE -}; - -struct ath_tx_info_priv { - struct ath_wiphy *aphy; - struct ath_tx_status tx; - int n_frames; - int n_bad_frames; - bool update_rc; - enum ath9k_internal_frame_type frame_type; -}; - -#define ATH_TX_INFO_PRIV(tx_info) \ - ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0])) - -void ath_rate_attach(struct ath_softc *sc); -u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); -int ath_rate_control_register(void); -void ath_rate_control_unregister(void); - -#endif /* RC_H */ diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c deleted file mode 100644 index b46badd..0000000 --- a/drivers/net/wireless/ath9k/recv.c +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, - struct ieee80211_hdr *hdr) -{ - struct ieee80211_hw *hw = sc->pri_wiphy->hw; - int i; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr) - == 0) { - hw = aphy->hw; - break; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return hw; -} - -/* - * Setup and link descriptors. - * - * 11N: we can no longer afford to self link the last descriptor. - * MAC acknowledges BA status as long as it copies frames to host - * buffer (or rx fifo). This can incorrectly acknowledge packets - * to a sender if last desc is self-linked. - */ -static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_desc *ds; - struct sk_buff *skb; - - ATH_RXBUF_RESET(bf); - - ds = bf->bf_desc; - ds->ds_link = 0; /* link to null */ - ds->ds_data = bf->bf_buf_addr; - - /* virtual addr of the beginning of the buffer. */ - skb = bf->bf_mpdu; - ASSERT(skb != NULL); - ds->ds_vdata = skb->data; - - /* setup rx descriptors. The rx.bufsize here tells the harware - * how much data it can DMA to us and that we are prepared - * to process */ - ath9k_hw_setuprxdesc(ah, ds, - sc->rx.bufsize, - 0); - - if (sc->rx.rxlink == NULL) - ath9k_hw_putrxbuf(ah, bf->bf_daddr); - else - *sc->rx.rxlink = bf->bf_daddr; - - sc->rx.rxlink = &ds->ds_link; - ath9k_hw_rxena(ah); -} - -static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) -{ - /* XXX block beacon interrupts */ - ath9k_hw_setantenna(sc->sc_ah, antenna); - sc->rx.defant = antenna; - sc->rx.rxotherant = 0; -} - -/* - * Extend 15-bit time stamp from rx descriptor to - * a full 64-bit TSF using the current h/w TSF. -*/ -static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) -{ - u64 tsf; - - tsf = ath9k_hw_gettsf64(sc->sc_ah); - if ((tsf & 0x7fff) < rstamp) - tsf -= 0x8000; - return (tsf & ~0x7fff) | rstamp; -} - -static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask) -{ - struct sk_buff *skb; - u32 off; - - /* - * Cache-line-align. This is important (for the - * 5210 at least) as not doing so causes bogus data - * in rx'd frames. - */ - - /* Note: the kernel can allocate a value greater than - * what we ask it to give us. We really only need 4 KB as that - * is this hardware supports and in fact we need at least 3849 - * as that is the MAX AMSDU size this hardware supports. - * Unfortunately this means we may get 8 KB here from the - * kernel... and that is actually what is observed on some - * systems :( */ - skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask); - if (skb != NULL) { - off = ((unsigned long) skb->data) % sc->cachelsz; - if (off != 0) - skb_reserve(skb, sc->cachelsz - off); - } else { - DPRINTF(sc, ATH_DBG_FATAL, - "skbuff alloc of size %u failed\n", len); - return NULL; - } - - return skb; -} - -/* - * For Decrypt or Demic errors, we only mark packet status here and always push - * up the frame up to let mac80211 handle the actual error case, be it no - * decryption key or real decryption error. This let us keep statistics there. - */ -static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, - struct ieee80211_rx_status *rx_status, bool *decrypt_error, - struct ath_softc *sc) -{ - struct ieee80211_hdr *hdr; - u8 ratecode; - __le16 fc; - struct ieee80211_hw *hw; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - hw = ath_get_virt_hw(sc, hdr); - - if (ds->ds_rxstat.rs_more) { - /* - * Frame spans multiple descriptors; this cannot happen yet - * as we don't support jumbograms. If not in monitor mode, - * discard the frame. Enable this if you want to see - * error frames in Monitor mode. - */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR) - goto rx_next; - } else if (ds->ds_rxstat.rs_status != 0) { - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) - goto rx_next; - - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { - *decrypt_error = true; - } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC; - else - rx_status->flag |= RX_FLAG_MMIC_ERROR; - } - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - goto rx_next; - } else { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; - } - } - } - - ratecode = ds->ds_rxstat.rs_rate; - - if (ratecode & 0x80) { - /* HT rate */ - rx_status->flag |= RX_FLAG_HT; - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) - rx_status->flag |= RX_FLAG_40MHZ; - if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) - rx_status->flag |= RX_FLAG_SHORT_GI; - rx_status->rate_idx = ratecode & 0x7f; - } else { - int i = 0, cur_band, n_rates; - - cur_band = hw->conf.channel->band; - n_rates = sc->sbands[cur_band].n_bitrates; - - for (i = 0; i < n_rates; i++) { - if (sc->sbands[cur_band].bitrates[i].hw_value == - ratecode) { - rx_status->rate_idx = i; - break; - } - - if (sc->sbands[cur_band].bitrates[i].hw_value_short == - ratecode) { - rx_status->rate_idx = i; - rx_status->flag |= RX_FLAG_SHORTPRE; - break; - } - } - } - - rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); - rx_status->band = hw->conf.channel->band; - rx_status->freq = hw->conf.channel->center_freq; - rx_status->noise = sc->ani.noise_floor; - rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; - rx_status->antenna = ds->ds_rxstat.rs_antenna; - - /* at 45 you will be able to use MCS 15 reliably. A more elaborate - * scheme can be used here but it requires tables of SNR/throughput for - * each possible mode used. */ - rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; - - /* rssi can be more than 45 though, anything above that - * should be considered at 100% */ - if (rx_status->qual > 100) - rx_status->qual = 100; - - rx_status->flag |= RX_FLAG_TSFT; - - return 1; -rx_next: - return 0; -} - -static void ath_opmode_init(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - u32 rfilt, mfilt[2]; - - /* configure rx filter */ - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - - /* configure bssid mask */ - if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - ath9k_hw_setbssidmask(sc); - - /* configure operational mode */ - ath9k_hw_setopmode(ah); - - /* Handle any link-level address change. */ - ath9k_hw_setmac(ah, sc->sc_ah->macaddr); - - /* calculate and install multicast filter */ - mfilt[0] = mfilt[1] = ~0; - ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); -} - -int ath_rx_init(struct ath_softc *sc, int nbufs) -{ - struct sk_buff *skb; - struct ath_buf *bf; - int error = 0; - - spin_lock_init(&sc->rx.rxflushlock); - sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_lock_init(&sc->rx.rxbuflock); - - sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(sc->cachelsz, (u16)64)); - - DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rx.bufsize); - - /* Initialize rx descriptors */ - - error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, - "rx", nbufs, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "failed to allocate rx descriptors: %d\n", error); - goto err; - } - - list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); - if (skb == NULL) { - error = -ENOMEM; - goto err; - } - - bf->bf_mpdu = skb; - bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, - sc->rx.bufsize, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, - bf->bf_buf_addr))) { - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, - "dma_mapping_error() on RX init\n"); - error = -ENOMEM; - goto err; - } - bf->bf_dmacontext = bf->bf_buf_addr; - } - sc->rx.rxlink = NULL; - -err: - if (error) - ath_rx_cleanup(sc); - - return error; -} - -void ath_rx_cleanup(struct ath_softc *sc) -{ - struct sk_buff *skb; - struct ath_buf *bf; - - list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = bf->bf_mpdu; - if (skb) { - dma_unmap_single(sc->dev, bf->bf_buf_addr, - sc->rx.bufsize, DMA_FROM_DEVICE); - dev_kfree_skb(skb); - } - } - - if (sc->rx.rxdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); -} - -/* - * Calculate the receive filter according to the - * operating mode and state: - * - * o always accept unicast, broadcast, and multicast traffic - * o maintain current state of phy error reception (the hal - * may enable phy error frames for noise immunity work) - * o probe request frames are accepted only when operating in - * hostap, adhoc, or monitor modes - * o enable promiscuous mode according to the interface state - * o accept beacons: - * - when operating in adhoc mode so the 802.11 layer creates - * node table entries for peers, - * - when operating in station mode for collecting rssi data when - * the station is otherwise quiet, or - * - when operating as a repeater so we see repeater-sta beacons - * - when scanning - */ - -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) - | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST - | ATH9K_RX_FILTER_MCAST; - - /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) - rfilt |= ATH9K_RX_FILTER_PROBEREQ; - - /* - * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station - * mode interface or when in monitor mode. AP mode does not need this - * since it receives all in-BSS frames anyway. - */ - if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) && - (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR)) - rfilt |= ATH9K_RX_FILTER_PROM; - - if (sc->rx.rxfilter & FIF_CONTROL) - rfilt |= ATH9K_RX_FILTER_CONTROL; - - if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && - !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)) - rfilt |= ATH9K_RX_FILTER_MYBEACON; - else - rfilt |= ATH9K_RX_FILTER_BEACON; - - /* If in HOSTAP mode, want to enable reception of PSPOLL frames */ - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) - rfilt |= ATH9K_RX_FILTER_PSPOLL; - - if (sc->sec_wiphy) { - /* TODO: only needed if more than one BSSID is in use in - * station/adhoc mode */ - /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM - */ - rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; - } - - return rfilt; - -#undef RX_FILTER_PRESERVE -} - -int ath_startrecv(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_buf *bf, *tbf; - - spin_lock_bh(&sc->rx.rxbuflock); - if (list_empty(&sc->rx.rxbuf)) - goto start_recv; - - sc->rx.rxlink = NULL; - list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { - ath_rx_buf_link(sc, bf); - } - - /* We could have deleted elements so the list may be empty now */ - if (list_empty(&sc->rx.rxbuf)) - goto start_recv; - - bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); - ath9k_hw_putrxbuf(ah, bf->bf_daddr); - ath9k_hw_rxena(ah); - -start_recv: - spin_unlock_bh(&sc->rx.rxbuflock); - ath_opmode_init(sc); - ath9k_hw_startpcureceive(ah); - - return 0; -} - -bool ath_stoprecv(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - bool stopped; - - ath9k_hw_stoppcurecv(ah); - ath9k_hw_setrxfilter(ah, 0); - stopped = ath9k_hw_stopdmarecv(ah); - sc->rx.rxlink = NULL; - - return stopped; -} - -void ath_flushrecv(struct ath_softc *sc) -{ - spin_lock_bh(&sc->rx.rxflushlock); - sc->sc_flags |= SC_OP_RXFLUSH; - ath_rx_tasklet(sc, 1); - sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->rx.rxflushlock); -} - -int ath_rx_tasklet(struct ath_softc *sc, int flush) -{ -#define PA2DESC(_sc, _pa) \ - ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc + \ - ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr))) - - struct ath_buf *bf; - struct ath_desc *ds; - struct sk_buff *skb = NULL, *requeue_skb; - struct ieee80211_rx_status rx_status; - struct ath_hw *ah = sc->sc_ah; - struct ieee80211_hdr *hdr; - int hdrlen, padsize, retval; - bool decrypt_error = false; - u8 keyix; - __le16 fc; - - spin_lock_bh(&sc->rx.rxbuflock); - - do { - /* If handling rx interrupt and flush is in progress => exit */ - if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) - break; - - if (list_empty(&sc->rx.rxbuf)) { - sc->rx.rxlink = NULL; - break; - } - - bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); - ds = bf->bf_desc; - - /* - * Must provide the virtual address of the current - * descriptor, the physical address, and the virtual - * address of the next descriptor in the h/w chain. - * This allows the HAL to look ahead to see if the - * hardware is done with a descriptor by checking the - * done bit in the following descriptor and the address - * of the current descriptor the DMA engine is working - * on. All this is necessary because of our use of - * a self-linked list to avoid rx overruns. - */ - retval = ath9k_hw_rxprocdesc(ah, ds, - bf->bf_daddr, - PA2DESC(sc, ds->ds_link), - 0); - if (retval == -EINPROGRESS) { - struct ath_buf *tbf; - struct ath_desc *tds; - - if (list_is_last(&bf->list, &sc->rx.rxbuf)) { - sc->rx.rxlink = NULL; - break; - } - - tbf = list_entry(bf->list.next, struct ath_buf, list); - - /* - * On some hardware the descriptor status words could - * get corrupted, including the done bit. Because of - * this, check if the next descriptor's done bit is - * set or not. - * - * If the next descriptor's done bit is set, the current - * descriptor has been corrupted. Force s/w to discard - * this descriptor and continue... - */ - - tds = tbf->bf_desc; - retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, - PA2DESC(sc, tds->ds_link), 0); - if (retval == -EINPROGRESS) { - break; - } - } - - skb = bf->bf_mpdu; - if (!skb) - continue; - - /* - * Synchronize the DMA transfer with CPU before - * 1. accessing the frame - * 2. requeueing the same buffer to h/w - */ - dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, - sc->rx.bufsize, - DMA_FROM_DEVICE); - - /* - * If we're asked to flush receive queue, directly - * chain it back at the queue without processing it. - */ - if (flush) - goto requeue; - - if (!ds->ds_rxstat.rs_datalen) - goto requeue; - - /* The status portion of the descriptor could get corrupted. */ - if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) - goto requeue; - - if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) - goto requeue; - - /* Ensure we always have an skb to requeue once we are done - * processing the current buffer's skb */ - requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC); - - /* If there is no memory we ignore the current RX'd frame, - * tell hardware it can give us a new frame using the old - * skb and put it at the tail of the sc->rx.rxbuf list for - * processing. */ - if (!requeue_skb) - goto requeue; - - /* Unmap the frame */ - dma_unmap_single(sc->dev, bf->bf_buf_addr, - sc->rx.bufsize, - DMA_FROM_DEVICE); - - skb_put(skb, ds->ds_rxstat.rs_datalen); - skb->protocol = cpu_to_be16(ETH_P_CONTROL); - - /* see if any padding is done by the hw and remove it */ - hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - hdrlen % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - keyix = ds->ds_rxstat.rs_keyix; - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { - rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) - && !decrypt_error && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, sc->keymap)) - rx_status.flag |= RX_FLAG_DECRYPTED; - } - if (ah->sw_mgmt_crypto && - (rx_status.flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(hdr->frame_control)) { - /* Use software decrypt for management frames. */ - rx_status.flag &= ~RX_FLAG_DECRYPTED; - } - - /* Send the frame to mac80211 */ - if (hdr->addr1[5] & 0x01) { - int i; - /* - * Deliver broadcast/multicast frames to all suitable - * virtual wiphys. - */ - /* TODO: filter based on channel configuration */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - struct sk_buff *nskb; - if (aphy == NULL) - continue; - nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb) - __ieee80211_rx(aphy->hw, nskb, - &rx_status); - } - __ieee80211_rx(sc->hw, skb, &rx_status); - } else { - /* Deliver unicast frames based on receiver address */ - __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, - &rx_status); - } - - /* We will now give hardware our shiny new allocated skb */ - bf->bf_mpdu = requeue_skb; - bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, - sc->rx.bufsize, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, - bf->bf_buf_addr))) { - dev_kfree_skb_any(requeue_skb); - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, - "dma_mapping_error() on RX\n"); - break; - } - bf->bf_dmacontext = bf->bf_buf_addr; - - /* - * change the default rx antenna if rx diversity chooses the - * other antenna 3 times in a row. - */ - if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { - if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); - } else { - sc->rx.rxotherant = 0; - } - - if (ieee80211_is_beacon(fc) && - (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); - } -requeue: - list_move_tail(&bf->list, &sc->rx.rxbuf); - ath_rx_buf_link(sc, bf); - } while (1); - - spin_unlock_bh(&sc->rx.rxbuflock); - - return 0; -#undef PA2DESC -} diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h deleted file mode 100644 index 5260524..0000000 --- a/drivers/net/wireless/ath9k/reg.h +++ /dev/null @@ -1,1511 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef REG_H -#define REG_H - -#define AR_CR 0x0008 -#define AR_CR_RXE 0x00000004 -#define AR_CR_RXD 0x00000020 -#define AR_CR_SWI 0x00000040 - -#define AR_RXDP 0x000C - -#define AR_CFG 0x0014 -#define AR_CFG_SWTD 0x00000001 -#define AR_CFG_SWTB 0x00000002 -#define AR_CFG_SWRD 0x00000004 -#define AR_CFG_SWRB 0x00000008 -#define AR_CFG_SWRG 0x00000010 -#define AR_CFG_AP_ADHOC_INDICATION 0x00000020 -#define AR_CFG_PHOK 0x00000100 -#define AR_CFG_CLK_GATE_DIS 0x00000400 -#define AR_CFG_EEBS 0x00000200 -#define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000 -#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 - -#define AR_MIRT 0x0020 -#define AR_MIRT_VAL 0x0000ffff -#define AR_MIRT_VAL_S 16 - -#define AR_IER 0x0024 -#define AR_IER_ENABLE 0x00000001 -#define AR_IER_DISABLE 0x00000000 - -#define AR_TIMT 0x0028 -#define AR_TIMT_LAST 0x0000ffff -#define AR_TIMT_LAST_S 0 -#define AR_TIMT_FIRST 0xffff0000 -#define AR_TIMT_FIRST_S 16 - -#define AR_RIMT 0x002C -#define AR_RIMT_LAST 0x0000ffff -#define AR_RIMT_LAST_S 0 -#define AR_RIMT_FIRST 0xffff0000 -#define AR_RIMT_FIRST_S 16 - -#define AR_DMASIZE_4B 0x00000000 -#define AR_DMASIZE_8B 0x00000001 -#define AR_DMASIZE_16B 0x00000002 -#define AR_DMASIZE_32B 0x00000003 -#define AR_DMASIZE_64B 0x00000004 -#define AR_DMASIZE_128B 0x00000005 -#define AR_DMASIZE_256B 0x00000006 -#define AR_DMASIZE_512B 0x00000007 - -#define AR_TXCFG 0x0030 -#define AR_TXCFG_DMASZ_MASK 0x00000007 -#define AR_TXCFG_DMASZ_4B 0 -#define AR_TXCFG_DMASZ_8B 1 -#define AR_TXCFG_DMASZ_16B 2 -#define AR_TXCFG_DMASZ_32B 3 -#define AR_TXCFG_DMASZ_64B 4 -#define AR_TXCFG_DMASZ_128B 5 -#define AR_TXCFG_DMASZ_256B 6 -#define AR_TXCFG_DMASZ_512B 7 -#define AR_FTRIG 0x000003F0 -#define AR_FTRIG_S 4 -#define AR_FTRIG_IMMED 0x00000000 -#define AR_FTRIG_64B 0x00000010 -#define AR_FTRIG_128B 0x00000020 -#define AR_FTRIG_192B 0x00000030 -#define AR_FTRIG_256B 0x00000040 -#define AR_FTRIG_512B 0x00000080 -#define AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY 0x00000800 - -#define AR_RXCFG 0x0034 -#define AR_RXCFG_CHIRP 0x00000008 -#define AR_RXCFG_ZLFDMA 0x00000010 -#define AR_RXCFG_DMASZ_MASK 0x00000007 -#define AR_RXCFG_DMASZ_4B 0 -#define AR_RXCFG_DMASZ_8B 1 -#define AR_RXCFG_DMASZ_16B 2 -#define AR_RXCFG_DMASZ_32B 3 -#define AR_RXCFG_DMASZ_64B 4 -#define AR_RXCFG_DMASZ_128B 5 -#define AR_RXCFG_DMASZ_256B 6 -#define AR_RXCFG_DMASZ_512B 7 - -#define AR_MIBC 0x0040 -#define AR_MIBC_COW 0x00000001 -#define AR_MIBC_FMC 0x00000002 -#define AR_MIBC_CMC 0x00000004 -#define AR_MIBC_MCS 0x00000008 - -#define AR_TOPS 0x0044 -#define AR_TOPS_MASK 0x0000FFFF - -#define AR_RXNPTO 0x0048 -#define AR_RXNPTO_MASK 0x000003FF - -#define AR_TXNPTO 0x004C -#define AR_TXNPTO_MASK 0x000003FF -#define AR_TXNPTO_QCU_MASK 0x000FFC00 - -#define AR_RPGTO 0x0050 -#define AR_RPGTO_MASK 0x000003FF - -#define AR_RPCNT 0x0054 -#define AR_RPCNT_MASK 0x0000001F - -#define AR_MACMISC 0x0058 -#define AR_MACMISC_PCI_EXT_FORCE 0x00000010 -#define AR_MACMISC_DMA_OBS 0x000001E0 -#define AR_MACMISC_DMA_OBS_S 5 -#define AR_MACMISC_DMA_OBS_LINE_0 0 -#define AR_MACMISC_DMA_OBS_LINE_1 1 -#define AR_MACMISC_DMA_OBS_LINE_2 2 -#define AR_MACMISC_DMA_OBS_LINE_3 3 -#define AR_MACMISC_DMA_OBS_LINE_4 4 -#define AR_MACMISC_DMA_OBS_LINE_5 5 -#define AR_MACMISC_DMA_OBS_LINE_6 6 -#define AR_MACMISC_DMA_OBS_LINE_7 7 -#define AR_MACMISC_DMA_OBS_LINE_8 8 -#define AR_MACMISC_MISC_OBS 0x00000E00 -#define AR_MACMISC_MISC_OBS_S 9 -#define AR_MACMISC_MISC_OBS_BUS_LSB 0x00007000 -#define AR_MACMISC_MISC_OBS_BUS_LSB_S 12 -#define AR_MACMISC_MISC_OBS_BUS_MSB 0x00038000 -#define AR_MACMISC_MISC_OBS_BUS_MSB_S 15 -#define AR_MACMISC_MISC_OBS_BUS_1 1 - -#define AR_GTXTO 0x0064 -#define AR_GTXTO_TIMEOUT_COUNTER 0x0000FFFF -#define AR_GTXTO_TIMEOUT_LIMIT 0xFFFF0000 -#define AR_GTXTO_TIMEOUT_LIMIT_S 16 - -#define AR_GTTM 0x0068 -#define AR_GTTM_USEC 0x00000001 -#define AR_GTTM_IGNORE_IDLE 0x00000002 -#define AR_GTTM_RESET_IDLE 0x00000004 -#define AR_GTTM_CST_USEC 0x00000008 - -#define AR_CST 0x006C -#define AR_CST_TIMEOUT_COUNTER 0x0000FFFF -#define AR_CST_TIMEOUT_LIMIT 0xFFFF0000 -#define AR_CST_TIMEOUT_LIMIT_S 16 - -#define AR_ISR 0x0080 -#define AR_ISR_RXOK 0x00000001 -#define AR_ISR_RXDESC 0x00000002 -#define AR_ISR_RXERR 0x00000004 -#define AR_ISR_RXNOPKT 0x00000008 -#define AR_ISR_RXEOL 0x00000010 -#define AR_ISR_RXORN 0x00000020 -#define AR_ISR_TXOK 0x00000040 -#define AR_ISR_TXDESC 0x00000080 -#define AR_ISR_TXERR 0x00000100 -#define AR_ISR_TXNOPKT 0x00000200 -#define AR_ISR_TXEOL 0x00000400 -#define AR_ISR_TXURN 0x00000800 -#define AR_ISR_MIB 0x00001000 -#define AR_ISR_SWI 0x00002000 -#define AR_ISR_RXPHY 0x00004000 -#define AR_ISR_RXKCM 0x00008000 -#define AR_ISR_SWBA 0x00010000 -#define AR_ISR_BRSSI 0x00020000 -#define AR_ISR_BMISS 0x00040000 -#define AR_ISR_BNR 0x00100000 -#define AR_ISR_RXCHIRP 0x00200000 -#define AR_ISR_BCNMISC 0x00800000 -#define AR_ISR_TIM 0x00800000 -#define AR_ISR_QCBROVF 0x02000000 -#define AR_ISR_QCBRURN 0x04000000 -#define AR_ISR_QTRIG 0x08000000 -#define AR_ISR_GENTMR 0x10000000 - -#define AR_ISR_TXMINTR 0x00080000 -#define AR_ISR_RXMINTR 0x01000000 -#define AR_ISR_TXINTM 0x40000000 -#define AR_ISR_RXINTM 0x80000000 - -#define AR_ISR_S0 0x0084 -#define AR_ISR_S0_QCU_TXOK 0x000003FF -#define AR_ISR_S0_QCU_TXOK_S 0 -#define AR_ISR_S0_QCU_TXDESC 0x03FF0000 -#define AR_ISR_S0_QCU_TXDESC_S 16 - -#define AR_ISR_S1 0x0088 -#define AR_ISR_S1_QCU_TXERR 0x000003FF -#define AR_ISR_S1_QCU_TXERR_S 0 -#define AR_ISR_S1_QCU_TXEOL 0x03FF0000 -#define AR_ISR_S1_QCU_TXEOL_S 16 - -#define AR_ISR_S2 0x008c -#define AR_ISR_S2_QCU_TXURN 0x000003FF -#define AR_ISR_S2_CST 0x00400000 -#define AR_ISR_S2_GTT 0x00800000 -#define AR_ISR_S2_TIM 0x01000000 -#define AR_ISR_S2_CABEND 0x02000000 -#define AR_ISR_S2_DTIMSYNC 0x04000000 -#define AR_ISR_S2_BCNTO 0x08000000 -#define AR_ISR_S2_CABTO 0x10000000 -#define AR_ISR_S2_DTIM 0x20000000 -#define AR_ISR_S2_TSFOOR 0x40000000 -#define AR_ISR_S2_TBTT_TIME 0x80000000 - -#define AR_ISR_S3 0x0090 -#define AR_ISR_S3_QCU_QCBROVF 0x000003FF -#define AR_ISR_S3_QCU_QCBRURN 0x03FF0000 - -#define AR_ISR_S4 0x0094 -#define AR_ISR_S4_QCU_QTRIG 0x000003FF -#define AR_ISR_S4_RESV0 0xFFFFFC00 - -#define AR_ISR_S5 0x0098 -#define AR_ISR_S5_TIMER_TRIG 0x000000FF -#define AR_ISR_S5_TIMER_THRESH 0x0007FE00 -#define AR_ISR_S5_TIM_TIMER 0x00000010 -#define AR_ISR_S5_DTIM_TIMER 0x00000020 -#define AR_ISR_S5_S 0x00d8 -#define AR_IMR_S5 0x00b8 -#define AR_IMR_S5_TIM_TIMER 0x00000010 -#define AR_IMR_S5_DTIM_TIMER 0x00000020 - - -#define AR_IMR 0x00a0 -#define AR_IMR_RXOK 0x00000001 -#define AR_IMR_RXDESC 0x00000002 -#define AR_IMR_RXERR 0x00000004 -#define AR_IMR_RXNOPKT 0x00000008 -#define AR_IMR_RXEOL 0x00000010 -#define AR_IMR_RXORN 0x00000020 -#define AR_IMR_TXOK 0x00000040 -#define AR_IMR_TXDESC 0x00000080 -#define AR_IMR_TXERR 0x00000100 -#define AR_IMR_TXNOPKT 0x00000200 -#define AR_IMR_TXEOL 0x00000400 -#define AR_IMR_TXURN 0x00000800 -#define AR_IMR_MIB 0x00001000 -#define AR_IMR_SWI 0x00002000 -#define AR_IMR_RXPHY 0x00004000 -#define AR_IMR_RXKCM 0x00008000 -#define AR_IMR_SWBA 0x00010000 -#define AR_IMR_BRSSI 0x00020000 -#define AR_IMR_BMISS 0x00040000 -#define AR_IMR_BNR 0x00100000 -#define AR_IMR_RXCHIRP 0x00200000 -#define AR_IMR_BCNMISC 0x00800000 -#define AR_IMR_TIM 0x00800000 -#define AR_IMR_QCBROVF 0x02000000 -#define AR_IMR_QCBRURN 0x04000000 -#define AR_IMR_QTRIG 0x08000000 -#define AR_IMR_GENTMR 0x10000000 - -#define AR_IMR_TXMINTR 0x00080000 -#define AR_IMR_RXMINTR 0x01000000 -#define AR_IMR_TXINTM 0x40000000 -#define AR_IMR_RXINTM 0x80000000 - -#define AR_IMR_S0 0x00a4 -#define AR_IMR_S0_QCU_TXOK 0x000003FF -#define AR_IMR_S0_QCU_TXOK_S 0 -#define AR_IMR_S0_QCU_TXDESC 0x03FF0000 -#define AR_IMR_S0_QCU_TXDESC_S 16 - -#define AR_IMR_S1 0x00a8 -#define AR_IMR_S1_QCU_TXERR 0x000003FF -#define AR_IMR_S1_QCU_TXERR_S 0 -#define AR_IMR_S1_QCU_TXEOL 0x03FF0000 -#define AR_IMR_S1_QCU_TXEOL_S 16 - -#define AR_IMR_S2 0x00ac -#define AR_IMR_S2_QCU_TXURN 0x000003FF -#define AR_IMR_S2_QCU_TXURN_S 0 -#define AR_IMR_S2_CST 0x00400000 -#define AR_IMR_S2_GTT 0x00800000 -#define AR_IMR_S2_TIM 0x01000000 -#define AR_IMR_S2_CABEND 0x02000000 -#define AR_IMR_S2_DTIMSYNC 0x04000000 -#define AR_IMR_S2_BCNTO 0x08000000 -#define AR_IMR_S2_CABTO 0x10000000 -#define AR_IMR_S2_DTIM 0x20000000 -#define AR_IMR_S2_TSFOOR 0x40000000 - -#define AR_IMR_S3 0x00b0 -#define AR_IMR_S3_QCU_QCBROVF 0x000003FF -#define AR_IMR_S3_QCU_QCBRURN 0x03FF0000 -#define AR_IMR_S3_QCU_QCBRURN_S 16 - -#define AR_IMR_S4 0x00b4 -#define AR_IMR_S4_QCU_QTRIG 0x000003FF -#define AR_IMR_S4_RESV0 0xFFFFFC00 - -#define AR_IMR_S5 0x00b8 -#define AR_IMR_S5_TIMER_TRIG 0x000000FF -#define AR_IMR_S5_TIMER_THRESH 0x0000FF00 - - -#define AR_ISR_RAC 0x00c0 -#define AR_ISR_S0_S 0x00c4 -#define AR_ISR_S0_QCU_TXOK 0x000003FF -#define AR_ISR_S0_QCU_TXOK_S 0 -#define AR_ISR_S0_QCU_TXDESC 0x03FF0000 -#define AR_ISR_S0_QCU_TXDESC_S 16 - -#define AR_ISR_S1_S 0x00c8 -#define AR_ISR_S1_QCU_TXERR 0x000003FF -#define AR_ISR_S1_QCU_TXERR_S 0 -#define AR_ISR_S1_QCU_TXEOL 0x03FF0000 -#define AR_ISR_S1_QCU_TXEOL_S 16 - -#define AR_ISR_S2_S 0x00cc -#define AR_ISR_S3_S 0x00d0 -#define AR_ISR_S4_S 0x00d4 -#define AR_ISR_S5_S 0x00d8 -#define AR_DMADBG_0 0x00e0 -#define AR_DMADBG_1 0x00e4 -#define AR_DMADBG_2 0x00e8 -#define AR_DMADBG_3 0x00ec -#define AR_DMADBG_4 0x00f0 -#define AR_DMADBG_5 0x00f4 -#define AR_DMADBG_6 0x00f8 -#define AR_DMADBG_7 0x00fc - -#define AR_NUM_QCU 10 -#define AR_QCU_0 0x0001 -#define AR_QCU_1 0x0002 -#define AR_QCU_2 0x0004 -#define AR_QCU_3 0x0008 -#define AR_QCU_4 0x0010 -#define AR_QCU_5 0x0020 -#define AR_QCU_6 0x0040 -#define AR_QCU_7 0x0080 -#define AR_QCU_8 0x0100 -#define AR_QCU_9 0x0200 - -#define AR_Q0_TXDP 0x0800 -#define AR_Q1_TXDP 0x0804 -#define AR_Q2_TXDP 0x0808 -#define AR_Q3_TXDP 0x080c -#define AR_Q4_TXDP 0x0810 -#define AR_Q5_TXDP 0x0814 -#define AR_Q6_TXDP 0x0818 -#define AR_Q7_TXDP 0x081c -#define AR_Q8_TXDP 0x0820 -#define AR_Q9_TXDP 0x0824 -#define AR_QTXDP(_i) (AR_Q0_TXDP + ((_i)<<2)) - -#define AR_Q_TXE 0x0840 -#define AR_Q_TXE_M 0x000003FF - -#define AR_Q_TXD 0x0880 -#define AR_Q_TXD_M 0x000003FF - -#define AR_Q0_CBRCFG 0x08c0 -#define AR_Q1_CBRCFG 0x08c4 -#define AR_Q2_CBRCFG 0x08c8 -#define AR_Q3_CBRCFG 0x08cc -#define AR_Q4_CBRCFG 0x08d0 -#define AR_Q5_CBRCFG 0x08d4 -#define AR_Q6_CBRCFG 0x08d8 -#define AR_Q7_CBRCFG 0x08dc -#define AR_Q8_CBRCFG 0x08e0 -#define AR_Q9_CBRCFG 0x08e4 -#define AR_QCBRCFG(_i) (AR_Q0_CBRCFG + ((_i)<<2)) -#define AR_Q_CBRCFG_INTERVAL 0x00FFFFFF -#define AR_Q_CBRCFG_INTERVAL_S 0 -#define AR_Q_CBRCFG_OVF_THRESH 0xFF000000 -#define AR_Q_CBRCFG_OVF_THRESH_S 24 - -#define AR_Q0_RDYTIMECFG 0x0900 -#define AR_Q1_RDYTIMECFG 0x0904 -#define AR_Q2_RDYTIMECFG 0x0908 -#define AR_Q3_RDYTIMECFG 0x090c -#define AR_Q4_RDYTIMECFG 0x0910 -#define AR_Q5_RDYTIMECFG 0x0914 -#define AR_Q6_RDYTIMECFG 0x0918 -#define AR_Q7_RDYTIMECFG 0x091c -#define AR_Q8_RDYTIMECFG 0x0920 -#define AR_Q9_RDYTIMECFG 0x0924 -#define AR_QRDYTIMECFG(_i) (AR_Q0_RDYTIMECFG + ((_i)<<2)) -#define AR_Q_RDYTIMECFG_DURATION 0x00FFFFFF -#define AR_Q_RDYTIMECFG_DURATION_S 0 -#define AR_Q_RDYTIMECFG_EN 0x01000000 - -#define AR_Q_ONESHOTARM_SC 0x0940 -#define AR_Q_ONESHOTARM_SC_M 0x000003FF -#define AR_Q_ONESHOTARM_SC_RESV0 0xFFFFFC00 - -#define AR_Q_ONESHOTARM_CC 0x0980 -#define AR_Q_ONESHOTARM_CC_M 0x000003FF -#define AR_Q_ONESHOTARM_CC_RESV0 0xFFFFFC00 - -#define AR_Q0_MISC 0x09c0 -#define AR_Q1_MISC 0x09c4 -#define AR_Q2_MISC 0x09c8 -#define AR_Q3_MISC 0x09cc -#define AR_Q4_MISC 0x09d0 -#define AR_Q5_MISC 0x09d4 -#define AR_Q6_MISC 0x09d8 -#define AR_Q7_MISC 0x09dc -#define AR_Q8_MISC 0x09e0 -#define AR_Q9_MISC 0x09e4 -#define AR_QMISC(_i) (AR_Q0_MISC + ((_i)<<2)) -#define AR_Q_MISC_FSP 0x0000000F -#define AR_Q_MISC_FSP_ASAP 0 -#define AR_Q_MISC_FSP_CBR 1 -#define AR_Q_MISC_FSP_DBA_GATED 2 -#define AR_Q_MISC_FSP_TIM_GATED 3 -#define AR_Q_MISC_FSP_BEACON_SENT_GATED 4 -#define AR_Q_MISC_FSP_BEACON_RCVD_GATED 5 -#define AR_Q_MISC_ONE_SHOT_EN 0x00000010 -#define AR_Q_MISC_CBR_INCR_DIS1 0x00000020 -#define AR_Q_MISC_CBR_INCR_DIS0 0x00000040 -#define AR_Q_MISC_BEACON_USE 0x00000080 -#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN 0x00000100 -#define AR_Q_MISC_RDYTIME_EXP_POLICY 0x00000200 -#define AR_Q_MISC_RESET_CBR_EXP_CTR 0x00000400 -#define AR_Q_MISC_DCU_EARLY_TERM_REQ 0x00000800 -#define AR_Q_MISC_RESV0 0xFFFFF000 - -#define AR_Q0_STS 0x0a00 -#define AR_Q1_STS 0x0a04 -#define AR_Q2_STS 0x0a08 -#define AR_Q3_STS 0x0a0c -#define AR_Q4_STS 0x0a10 -#define AR_Q5_STS 0x0a14 -#define AR_Q6_STS 0x0a18 -#define AR_Q7_STS 0x0a1c -#define AR_Q8_STS 0x0a20 -#define AR_Q9_STS 0x0a24 -#define AR_QSTS(_i) (AR_Q0_STS + ((_i)<<2)) -#define AR_Q_STS_PEND_FR_CNT 0x00000003 -#define AR_Q_STS_RESV0 0x000000FC -#define AR_Q_STS_CBR_EXP_CNT 0x0000FF00 -#define AR_Q_STS_RESV1 0xFFFF0000 - -#define AR_Q_RDYTIMESHDN 0x0a40 -#define AR_Q_RDYTIMESHDN_M 0x000003FF - - -#define AR_NUM_DCU 10 -#define AR_DCU_0 0x0001 -#define AR_DCU_1 0x0002 -#define AR_DCU_2 0x0004 -#define AR_DCU_3 0x0008 -#define AR_DCU_4 0x0010 -#define AR_DCU_5 0x0020 -#define AR_DCU_6 0x0040 -#define AR_DCU_7 0x0080 -#define AR_DCU_8 0x0100 -#define AR_DCU_9 0x0200 - -#define AR_D0_QCUMASK 0x1000 -#define AR_D1_QCUMASK 0x1004 -#define AR_D2_QCUMASK 0x1008 -#define AR_D3_QCUMASK 0x100c -#define AR_D4_QCUMASK 0x1010 -#define AR_D5_QCUMASK 0x1014 -#define AR_D6_QCUMASK 0x1018 -#define AR_D7_QCUMASK 0x101c -#define AR_D8_QCUMASK 0x1020 -#define AR_D9_QCUMASK 0x1024 -#define AR_DQCUMASK(_i) (AR_D0_QCUMASK + ((_i)<<2)) -#define AR_D_QCUMASK 0x000003FF -#define AR_D_QCUMASK_RESV0 0xFFFFFC00 - -#define AR_D_TXBLK_CMD 0x1038 -#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) - -#define AR_D0_LCL_IFS 0x1040 -#define AR_D1_LCL_IFS 0x1044 -#define AR_D2_LCL_IFS 0x1048 -#define AR_D3_LCL_IFS 0x104c -#define AR_D4_LCL_IFS 0x1050 -#define AR_D5_LCL_IFS 0x1054 -#define AR_D6_LCL_IFS 0x1058 -#define AR_D7_LCL_IFS 0x105c -#define AR_D8_LCL_IFS 0x1060 -#define AR_D9_LCL_IFS 0x1064 -#define AR_DLCL_IFS(_i) (AR_D0_LCL_IFS + ((_i)<<2)) -#define AR_D_LCL_IFS_CWMIN 0x000003FF -#define AR_D_LCL_IFS_CWMIN_S 0 -#define AR_D_LCL_IFS_CWMAX 0x000FFC00 -#define AR_D_LCL_IFS_CWMAX_S 10 -#define AR_D_LCL_IFS_AIFS 0x0FF00000 -#define AR_D_LCL_IFS_AIFS_S 20 - -#define AR_D_LCL_IFS_RESV0 0xF0000000 - -#define AR_D0_RETRY_LIMIT 0x1080 -#define AR_D1_RETRY_LIMIT 0x1084 -#define AR_D2_RETRY_LIMIT 0x1088 -#define AR_D3_RETRY_LIMIT 0x108c -#define AR_D4_RETRY_LIMIT 0x1090 -#define AR_D5_RETRY_LIMIT 0x1094 -#define AR_D6_RETRY_LIMIT 0x1098 -#define AR_D7_RETRY_LIMIT 0x109c -#define AR_D8_RETRY_LIMIT 0x10a0 -#define AR_D9_RETRY_LIMIT 0x10a4 -#define AR_DRETRY_LIMIT(_i) (AR_D0_RETRY_LIMIT + ((_i)<<2)) -#define AR_D_RETRY_LIMIT_FR_SH 0x0000000F -#define AR_D_RETRY_LIMIT_FR_SH_S 0 -#define AR_D_RETRY_LIMIT_STA_SH 0x00003F00 -#define AR_D_RETRY_LIMIT_STA_SH_S 8 -#define AR_D_RETRY_LIMIT_STA_LG 0x000FC000 -#define AR_D_RETRY_LIMIT_STA_LG_S 14 -#define AR_D_RETRY_LIMIT_RESV0 0xFFF00000 - -#define AR_D0_CHNTIME 0x10c0 -#define AR_D1_CHNTIME 0x10c4 -#define AR_D2_CHNTIME 0x10c8 -#define AR_D3_CHNTIME 0x10cc -#define AR_D4_CHNTIME 0x10d0 -#define AR_D5_CHNTIME 0x10d4 -#define AR_D6_CHNTIME 0x10d8 -#define AR_D7_CHNTIME 0x10dc -#define AR_D8_CHNTIME 0x10e0 -#define AR_D9_CHNTIME 0x10e4 -#define AR_DCHNTIME(_i) (AR_D0_CHNTIME + ((_i)<<2)) -#define AR_D_CHNTIME_DUR 0x000FFFFF -#define AR_D_CHNTIME_DUR_S 0 -#define AR_D_CHNTIME_EN 0x00100000 -#define AR_D_CHNTIME_RESV0 0xFFE00000 - -#define AR_D0_MISC 0x1100 -#define AR_D1_MISC 0x1104 -#define AR_D2_MISC 0x1108 -#define AR_D3_MISC 0x110c -#define AR_D4_MISC 0x1110 -#define AR_D5_MISC 0x1114 -#define AR_D6_MISC 0x1118 -#define AR_D7_MISC 0x111c -#define AR_D8_MISC 0x1120 -#define AR_D9_MISC 0x1124 -#define AR_DMISC(_i) (AR_D0_MISC + ((_i)<<2)) -#define AR_D_MISC_BKOFF_THRESH 0x0000003F -#define AR_D_MISC_RETRY_CNT_RESET_EN 0x00000040 -#define AR_D_MISC_CW_RESET_EN 0x00000080 -#define AR_D_MISC_FRAG_WAIT_EN 0x00000100 -#define AR_D_MISC_FRAG_BKOFF_EN 0x00000200 -#define AR_D_MISC_CW_BKOFF_EN 0x00001000 -#define AR_D_MISC_VIR_COL_HANDLING 0x0000C000 -#define AR_D_MISC_VIR_COL_HANDLING_S 14 -#define AR_D_MISC_VIR_COL_HANDLING_DEFAULT 0 -#define AR_D_MISC_VIR_COL_HANDLING_IGNORE 1 -#define AR_D_MISC_BEACON_USE 0x00010000 -#define AR_D_MISC_ARB_LOCKOUT_CNTRL 0x00060000 -#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17 -#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE 0 -#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1 -#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL 2 -#define AR_D_MISC_ARB_LOCKOUT_IGNORE 0x00080000 -#define AR_D_MISC_SEQ_NUM_INCR_DIS 0x00100000 -#define AR_D_MISC_POST_FR_BKOFF_DIS 0x00200000 -#define AR_D_MISC_VIT_COL_CW_BKOFF_EN 0x00400000 -#define AR_D_MISC_BLOWN_IFS_RETRY_EN 0x00800000 -#define AR_D_MISC_RESV0 0xFF000000 - -#define AR_D_SEQNUM 0x1140 - -#define AR_D_GBL_IFS_SIFS 0x1030 -#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF -#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF - -#define AR_D_TXBLK_BASE 0x1038 -#define AR_D_TXBLK_WRITE_BITMASK 0x0000FFFF -#define AR_D_TXBLK_WRITE_BITMASK_S 0 -#define AR_D_TXBLK_WRITE_SLICE 0x000F0000 -#define AR_D_TXBLK_WRITE_SLICE_S 16 -#define AR_D_TXBLK_WRITE_DCU 0x00F00000 -#define AR_D_TXBLK_WRITE_DCU_S 20 -#define AR_D_TXBLK_WRITE_COMMAND 0x0F000000 -#define AR_D_TXBLK_WRITE_COMMAND_S 24 - -#define AR_D_GBL_IFS_SLOT 0x1070 -#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF -#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000 - -#define AR_D_GBL_IFS_EIFS 0x10b0 -#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF -#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000 - -#define AR_D_GBL_IFS_MISC 0x10f0 -#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 -#define AR_D_GBL_IFS_MISC_TURBO_MODE 0x00000008 -#define AR_D_GBL_IFS_MISC_USEC_DURATION 0x000FFC00 -#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY 0x00300000 -#define AR_D_GBL_IFS_MISC_RANDOM_LFSR_SLICE_DIS 0x01000000 -#define AR_D_GBL_IFS_MISC_SLOT_XMIT_WIND_LEN 0x06000000 -#define AR_D_GBL_IFS_MISC_FORCE_XMIT_SLOT_BOUND 0x08000000 -#define AR_D_GBL_IFS_MISC_IGNORE_BACKOFF 0x10000000 - -#define AR_D_FPCTL 0x1230 -#define AR_D_FPCTL_DCU 0x0000000F -#define AR_D_FPCTL_DCU_S 0 -#define AR_D_FPCTL_PREFETCH_EN 0x00000010 -#define AR_D_FPCTL_BURST_PREFETCH 0x00007FE0 -#define AR_D_FPCTL_BURST_PREFETCH_S 5 - -#define AR_D_TXPSE 0x1270 -#define AR_D_TXPSE_CTRL 0x000003FF -#define AR_D_TXPSE_RESV0 0x0000FC00 -#define AR_D_TXPSE_STATUS 0x00010000 -#define AR_D_TXPSE_RESV1 0xFFFE0000 - -#define AR_D_TXSLOTMASK 0x12f0 -#define AR_D_TXSLOTMASK_NUM 0x0000000F - -#define AR_CFG_LED 0x1f04 -#define AR_CFG_SCLK_RATE_IND 0x00000003 -#define AR_CFG_SCLK_RATE_IND_S 0 -#define AR_CFG_SCLK_32MHZ 0x00000000 -#define AR_CFG_SCLK_4MHZ 0x00000001 -#define AR_CFG_SCLK_1MHZ 0x00000002 -#define AR_CFG_SCLK_32KHZ 0x00000003 -#define AR_CFG_LED_BLINK_SLOW 0x00000008 -#define AR_CFG_LED_BLINK_THRESH_SEL 0x00000070 -#define AR_CFG_LED_MODE_SEL 0x00000380 -#define AR_CFG_LED_MODE_SEL_S 7 -#define AR_CFG_LED_POWER 0x00000280 -#define AR_CFG_LED_POWER_S 7 -#define AR_CFG_LED_NETWORK 0x00000300 -#define AR_CFG_LED_NETWORK_S 7 -#define AR_CFG_LED_MODE_PROP 0x0 -#define AR_CFG_LED_MODE_RPROP 0x1 -#define AR_CFG_LED_MODE_SPLIT 0x2 -#define AR_CFG_LED_MODE_RAND 0x3 -#define AR_CFG_LED_MODE_POWER_OFF 0x4 -#define AR_CFG_LED_MODE_POWER_ON 0x5 -#define AR_CFG_LED_MODE_NETWORK_OFF 0x4 -#define AR_CFG_LED_MODE_NETWORK_ON 0x6 -#define AR_CFG_LED_ASSOC_CTL 0x00000c00 -#define AR_CFG_LED_ASSOC_CTL_S 10 -#define AR_CFG_LED_ASSOC_NONE 0x0 -#define AR_CFG_LED_ASSOC_ACTIVE 0x1 -#define AR_CFG_LED_ASSOC_PENDING 0x2 - -#define AR_CFG_LED_BLINK_SLOW 0x00000008 -#define AR_CFG_LED_BLINK_SLOW_S 3 - -#define AR_CFG_LED_BLINK_THRESH_SEL 0x00000070 -#define AR_CFG_LED_BLINK_THRESH_SEL_S 4 - -#define AR_MAC_SLEEP 0x1f00 -#define AR_MAC_SLEEP_MAC_AWAKE 0x00000000 -#define AR_MAC_SLEEP_MAC_ASLEEP 0x00000001 - -#define AR_RC 0x4000 -#define AR_RC_AHB 0x00000001 -#define AR_RC_APB 0x00000002 -#define AR_RC_HOSTIF 0x00000100 - -#define AR_WA 0x4004 -#define AR9285_WA_DEFAULT 0x004a05cb -#define AR9280_WA_DEFAULT 0x0040073f -#define AR_WA_DEFAULT 0x0000073f - - -#define AR_PM_STATE 0x4008 -#define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 - -#define AR_HOST_TIMEOUT 0x4018 -#define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF -#define AR_HOST_TIMEOUT_APB_CNTR_S 0 -#define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000 -#define AR_HOST_TIMEOUT_LCL_CNTR_S 16 - -#define AR_EEPROM 0x401c -#define AR_EEPROM_ABSENT 0x00000100 -#define AR_EEPROM_CORRUPT 0x00000200 -#define AR_EEPROM_PROT_MASK 0x03FFFC00 -#define AR_EEPROM_PROT_MASK_S 10 - -#define EEPROM_PROTECT_RP_0_31 0x0001 -#define EEPROM_PROTECT_WP_0_31 0x0002 -#define EEPROM_PROTECT_RP_32_63 0x0004 -#define EEPROM_PROTECT_WP_32_63 0x0008 -#define EEPROM_PROTECT_RP_64_127 0x0010 -#define EEPROM_PROTECT_WP_64_127 0x0020 -#define EEPROM_PROTECT_RP_128_191 0x0040 -#define EEPROM_PROTECT_WP_128_191 0x0080 -#define EEPROM_PROTECT_RP_192_255 0x0100 -#define EEPROM_PROTECT_WP_192_255 0x0200 -#define EEPROM_PROTECT_RP_256_511 0x0400 -#define EEPROM_PROTECT_WP_256_511 0x0800 -#define EEPROM_PROTECT_RP_512_1023 0x1000 -#define EEPROM_PROTECT_WP_512_1023 0x2000 -#define EEPROM_PROTECT_RP_1024_2047 0x4000 -#define EEPROM_PROTECT_WP_1024_2047 0x8000 - -#define AR_SREV \ - ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020) - -#define AR_SREV_ID \ - ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF) -#define AR_SREV_VERSION 0x000000F0 -#define AR_SREV_VERSION_S 4 -#define AR_SREV_REVISION 0x00000007 - -#define AR_SREV_ID2 0xFFFFFFFF -#define AR_SREV_VERSION2 0xFFFC0000 -#define AR_SREV_VERSION2_S 18 -#define AR_SREV_TYPE2 0x0003F000 -#define AR_SREV_TYPE2_S 12 -#define AR_SREV_TYPE2_CHAIN 0x00001000 -#define AR_SREV_TYPE2_HOST_MODE 0x00002000 -#define AR_SREV_REVISION2 0x00000F00 -#define AR_SREV_REVISION2_S 8 - -#define AR_SREV_VERSION_5416_PCI 0xD -#define AR_SREV_VERSION_5416_PCIE 0xC -#define AR_SREV_REVISION_5416_10 0 -#define AR_SREV_REVISION_5416_20 1 -#define AR_SREV_REVISION_5416_22 2 -#define AR_SREV_VERSION_9100 0x14 -#define AR_SREV_VERSION_9160 0x40 -#define AR_SREV_REVISION_9160_10 0 -#define AR_SREV_REVISION_9160_11 1 -#define AR_SREV_VERSION_9280 0x80 -#define AR_SREV_REVISION_9280_10 0 -#define AR_SREV_REVISION_9280_20 1 -#define AR_SREV_REVISION_9280_21 2 -#define AR_SREV_VERSION_9285 0xC0 -#define AR_SREV_REVISION_9285_10 0 -#define AR_SREV_REVISION_9285_11 1 -#define AR_SREV_REVISION_9285_12 2 - -#define AR_SREV_5416(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ - ((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)) -#define AR_SREV_5416_20_OR_LATER(_ah) \ - (((AR_SREV_5416(_ah)) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \ - ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) -#define AR_SREV_5416_22_OR_LATER(_ah) \ - (((AR_SREV_5416(_ah)) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \ - ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) - -#define AR_SREV_9100(ah) \ - ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100) -#define AR_SREV_9100_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) - -#define AR_SREV_9160(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9160)) -#define AR_SREV_9160_10_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160)) -#define AR_SREV_9160_11(_ah) \ - (AR_SREV_9160(_ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11)) -#define AR_SREV_9280(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280)) -#define AR_SREV_9280_10_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280)) -#define AR_SREV_9280_20(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20)) -#define AR_SREV_9280_20_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9280) || \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20))) - -#define AR_SREV_9285(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285)) -#define AR_SREV_9285_10_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285)) -#define AR_SREV_9285_11(_ah) \ - (AR_SREV_9285(ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11)) -#define AR_SREV_9285_11_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ - (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ - AR_SREV_REVISION_9285_11))) -#define AR_SREV_9285_12(_ah) \ - (AR_SREV_9285(ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12)) -#define AR_SREV_9285_12_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ - (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ - AR_SREV_REVISION_9285_12))) - -#define AR_RADIO_SREV_MAJOR 0xf0 -#define AR_RAD5133_SREV_MAJOR 0xc0 -#define AR_RAD2133_SREV_MAJOR 0xd0 -#define AR_RAD5122_SREV_MAJOR 0xe0 -#define AR_RAD2122_SREV_MAJOR 0xf0 - -#define AR_AHB_MODE 0x4024 -#define AR_AHB_EXACT_WR_EN 0x00000000 -#define AR_AHB_BUF_WR_EN 0x00000001 -#define AR_AHB_EXACT_RD_EN 0x00000000 -#define AR_AHB_CACHELINE_RD_EN 0x00000002 -#define AR_AHB_PREFETCH_RD_EN 0x00000004 -#define AR_AHB_PAGE_SIZE_1K 0x00000000 -#define AR_AHB_PAGE_SIZE_2K 0x00000008 -#define AR_AHB_PAGE_SIZE_4K 0x00000010 - -#define AR_INTR_RTC_IRQ 0x00000001 -#define AR_INTR_MAC_IRQ 0x00000002 -#define AR_INTR_EEP_PROT_ACCESS 0x00000004 -#define AR_INTR_MAC_AWAKE 0x00020000 -#define AR_INTR_MAC_ASLEEP 0x00040000 -#define AR_INTR_SPURIOUS 0xFFFFFFFF - - -#define AR_INTR_SYNC_CAUSE_CLR 0x4028 - -#define AR_INTR_SYNC_CAUSE 0x4028 - -#define AR_INTR_SYNC_ENABLE 0x402c -#define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000 -#define AR_INTR_SYNC_ENABLE_GPIO_S 18 - -enum { - AR_INTR_SYNC_RTC_IRQ = 0x00000001, - AR_INTR_SYNC_MAC_IRQ = 0x00000002, - AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS = 0x00000004, - AR_INTR_SYNC_APB_TIMEOUT = 0x00000008, - AR_INTR_SYNC_PCI_MODE_CONFLICT = 0x00000010, - AR_INTR_SYNC_HOST1_FATAL = 0x00000020, - AR_INTR_SYNC_HOST1_PERR = 0x00000040, - AR_INTR_SYNC_TRCV_FIFO_PERR = 0x00000080, - AR_INTR_SYNC_RADM_CPL_EP = 0x00000100, - AR_INTR_SYNC_RADM_CPL_DLLP_ABORT = 0x00000200, - AR_INTR_SYNC_RADM_CPL_TLP_ABORT = 0x00000400, - AR_INTR_SYNC_RADM_CPL_ECRC_ERR = 0x00000800, - AR_INTR_SYNC_RADM_CPL_TIMEOUT = 0x00001000, - AR_INTR_SYNC_LOCAL_TIMEOUT = 0x00002000, - AR_INTR_SYNC_PM_ACCESS = 0x00004000, - AR_INTR_SYNC_MAC_AWAKE = 0x00008000, - AR_INTR_SYNC_MAC_ASLEEP = 0x00010000, - AR_INTR_SYNC_MAC_SLEEP_ACCESS = 0x00020000, - AR_INTR_SYNC_ALL = 0x0003FFFF, - - - AR_INTR_SYNC_DEFAULT = (AR_INTR_SYNC_HOST1_FATAL | - AR_INTR_SYNC_HOST1_PERR | - AR_INTR_SYNC_RADM_CPL_EP | - AR_INTR_SYNC_RADM_CPL_DLLP_ABORT | - AR_INTR_SYNC_RADM_CPL_TLP_ABORT | - AR_INTR_SYNC_RADM_CPL_ECRC_ERR | - AR_INTR_SYNC_RADM_CPL_TIMEOUT | - AR_INTR_SYNC_LOCAL_TIMEOUT | - AR_INTR_SYNC_MAC_SLEEP_ACCESS), - - AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF, - -}; - -#define AR_INTR_ASYNC_MASK 0x4030 -#define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 -#define AR_INTR_ASYNC_MASK_GPIO_S 18 - -#define AR_INTR_SYNC_MASK 0x4034 -#define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 -#define AR_INTR_SYNC_MASK_GPIO_S 18 - -#define AR_INTR_ASYNC_CAUSE_CLR 0x4038 -#define AR_INTR_ASYNC_CAUSE 0x4038 - -#define AR_INTR_ASYNC_ENABLE 0x403c -#define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 -#define AR_INTR_ASYNC_ENABLE_GPIO_S 18 - -#define AR_PCIE_SERDES 0x4040 -#define AR_PCIE_SERDES2 0x4044 -#define AR_PCIE_PM_CTRL 0x4014 -#define AR_PCIE_PM_CTRL_ENA 0x00080000 - -#define AR_NUM_GPIO 14 -#define AR928X_NUM_GPIO 10 -#define AR9285_NUM_GPIO 12 - -#define AR_GPIO_IN_OUT 0x4048 -#define AR_GPIO_IN_VAL 0x0FFFC000 -#define AR_GPIO_IN_VAL_S 14 -#define AR928X_GPIO_IN_VAL 0x000FFC00 -#define AR928X_GPIO_IN_VAL_S 10 -#define AR9285_GPIO_IN_VAL 0x00FFF000 -#define AR9285_GPIO_IN_VAL_S 12 - -#define AR_GPIO_OE_OUT 0x404c -#define AR_GPIO_OE_OUT_DRV 0x3 -#define AR_GPIO_OE_OUT_DRV_NO 0x0 -#define AR_GPIO_OE_OUT_DRV_LOW 0x1 -#define AR_GPIO_OE_OUT_DRV_HI 0x2 -#define AR_GPIO_OE_OUT_DRV_ALL 0x3 - -#define AR_GPIO_INTR_POL 0x4050 -#define AR_GPIO_INTR_POL_VAL 0x00001FFF -#define AR_GPIO_INTR_POL_VAL_S 0 - -#define AR_GPIO_INPUT_EN_VAL 0x4054 -#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 -#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 -#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 -#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_S 3 -#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_DEF 0x00000010 -#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 -#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 -#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 -#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 -#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 -#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 -#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 -#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 -#define AR_GPIO_JTAG_DISABLE 0x00020000 - -#define AR_GPIO_INPUT_MUX1 0x4058 -#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 -#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 - -#define AR_GPIO_INPUT_MUX2 0x405c -#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f -#define AR_GPIO_INPUT_MUX2_CLK25_S 0 -#define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 -#define AR_GPIO_INPUT_MUX2_RFSILENT_S 4 -#define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 -#define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 - -#define AR_GPIO_OUTPUT_MUX1 0x4060 -#define AR_GPIO_OUTPUT_MUX2 0x4064 -#define AR_GPIO_OUTPUT_MUX3 0x4068 - -#define AR_INPUT_STATE 0x406c - -#define AR_EEPROM_STATUS_DATA 0x407c -#define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff -#define AR_EEPROM_STATUS_DATA_VAL_S 0 -#define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 -#define AR_EEPROM_STATUS_DATA_BUSY_ACCESS 0x00020000 -#define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 -#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 - -#define AR_OBS 0x4080 - -#define AR_PCIE_MSI 0x4094 -#define AR_PCIE_MSI_ENABLE 0x00000001 - - -#define AR_RTC_9160_PLL_DIV 0x000003ff -#define AR_RTC_9160_PLL_DIV_S 0 -#define AR_RTC_9160_PLL_REFDIV 0x00003C00 -#define AR_RTC_9160_PLL_REFDIV_S 10 -#define AR_RTC_9160_PLL_CLKSEL 0x0000C000 -#define AR_RTC_9160_PLL_CLKSEL_S 14 - -#define AR_RTC_BASE 0x00020000 -#define AR_RTC_RC \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000) -#define AR_RTC_RC_M 0x00000003 -#define AR_RTC_RC_MAC_WARM 0x00000001 -#define AR_RTC_RC_MAC_COLD 0x00000002 -#define AR_RTC_RC_COLD_RESET 0x00000004 -#define AR_RTC_RC_WARM_RESET 0x00000008 - -#define AR_RTC_PLL_CONTROL \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014) - -#define AR_RTC_PLL_DIV 0x0000001f -#define AR_RTC_PLL_DIV_S 0 -#define AR_RTC_PLL_DIV2 0x00000020 -#define AR_RTC_PLL_REFDIV_5 0x000000c0 -#define AR_RTC_PLL_CLKSEL 0x00000300 -#define AR_RTC_PLL_CLKSEL_S 8 - -#define AR_RTC_RESET \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) -#define AR_RTC_RESET_EN (0x00000001) - -#define AR_RTC_STATUS \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0044) : 0x7044) - -#define AR_RTC_STATUS_M \ - ((AR_SREV_9100(ah)) ? 0x0000003f : 0x0000000f) - -#define AR_RTC_PM_STATUS_M 0x0000000f - -#define AR_RTC_STATUS_SHUTDOWN 0x00000001 -#define AR_RTC_STATUS_ON 0x00000002 -#define AR_RTC_STATUS_SLEEP 0x00000004 -#define AR_RTC_STATUS_WAKEUP 0x00000008 - -#define AR_RTC_SLEEP_CLK \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048) -#define AR_RTC_FORCE_DERIVED_CLK 0x2 - -#define AR_RTC_FORCE_WAKE \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c) -#define AR_RTC_FORCE_WAKE_EN 0x00000001 -#define AR_RTC_FORCE_WAKE_ON_INT 0x00000002 - - -#define AR_RTC_INTR_CAUSE \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0050) : 0x7050) - -#define AR_RTC_INTR_ENABLE \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0054) : 0x7054) - -#define AR_RTC_INTR_MASK \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) - -/* RTC_DERIVED_* - only for AR9100 */ - -#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) -#define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe -#define AR_RTC_DERIVED_CLK_PERIOD_S 1 - -#define AR_SEQ_MASK 0x8060 - -#define AR_AN_RF2G1_CH0 0x7810 -#define AR_AN_RF2G1_CH0_OB 0x03800000 -#define AR_AN_RF2G1_CH0_OB_S 23 -#define AR_AN_RF2G1_CH0_DB 0x1C000000 -#define AR_AN_RF2G1_CH0_DB_S 26 - -#define AR_AN_RF5G1_CH0 0x7818 -#define AR_AN_RF5G1_CH0_OB5 0x00070000 -#define AR_AN_RF5G1_CH0_OB5_S 16 -#define AR_AN_RF5G1_CH0_DB5 0x00380000 -#define AR_AN_RF5G1_CH0_DB5_S 19 - -#define AR_AN_RF2G1_CH1 0x7834 -#define AR_AN_RF2G1_CH1_OB 0x03800000 -#define AR_AN_RF2G1_CH1_OB_S 23 -#define AR_AN_RF2G1_CH1_DB 0x1C000000 -#define AR_AN_RF2G1_CH1_DB_S 26 - -#define AR_AN_RF5G1_CH1 0x783C -#define AR_AN_RF5G1_CH1_OB5 0x00070000 -#define AR_AN_RF5G1_CH1_OB5_S 16 -#define AR_AN_RF5G1_CH1_DB5 0x00380000 -#define AR_AN_RF5G1_CH1_DB5_S 19 - -#define AR_AN_TOP1 0x7890 -#define AR_AN_TOP1_DACIPMODE 0x00040000 -#define AR_AN_TOP1_DACIPMODE_S 18 - -#define AR_AN_TOP2 0x7894 -#define AR_AN_TOP2_XPABIAS_LVL 0xC0000000 -#define AR_AN_TOP2_XPABIAS_LVL_S 30 -#define AR_AN_TOP2_LOCALBIAS 0x00200000 -#define AR_AN_TOP2_LOCALBIAS_S 21 -#define AR_AN_TOP2_PWDCLKIND 0x00400000 -#define AR_AN_TOP2_PWDCLKIND_S 22 - -#define AR_AN_SYNTH9 0x7868 -#define AR_AN_SYNTH9_REFDIVA 0xf8000000 -#define AR_AN_SYNTH9_REFDIVA_S 27 - -#define AR9285_AN_RF2G1 0x7820 -#define AR9285_AN_RF2G1_ENPACAL 0x00000800 -#define AR9285_AN_RF2G1_ENPACAL_S 11 -#define AR9285_AN_RF2G1_PDPADRV1 0x02000000 -#define AR9285_AN_RF2G1_PDPADRV1_S 25 -#define AR9285_AN_RF2G1_PDPADRV2 0x01000000 -#define AR9285_AN_RF2G1_PDPADRV2_S 24 -#define AR9285_AN_RF2G1_PDPAOUT 0x00800000 -#define AR9285_AN_RF2G1_PDPAOUT_S 23 - - -#define AR9285_AN_RF2G2 0x7824 -#define AR9285_AN_RF2G2_OFFCAL 0x00001000 -#define AR9285_AN_RF2G2_OFFCAL_S 12 - -#define AR9285_AN_RF2G3 0x7828 -#define AR9285_AN_RF2G3_PDVCCOMP 0x02000000 -#define AR9285_AN_RF2G3_PDVCCOMP_S 25 -#define AR9285_AN_RF2G3_OB_0 0x00E00000 -#define AR9285_AN_RF2G3_OB_0_S 21 -#define AR9285_AN_RF2G3_OB_1 0x001C0000 -#define AR9285_AN_RF2G3_OB_1_S 18 -#define AR9285_AN_RF2G3_OB_2 0x00038000 -#define AR9285_AN_RF2G3_OB_2_S 15 -#define AR9285_AN_RF2G3_OB_3 0x00007000 -#define AR9285_AN_RF2G3_OB_3_S 12 -#define AR9285_AN_RF2G3_OB_4 0x00000E00 -#define AR9285_AN_RF2G3_OB_4_S 9 - -#define AR9285_AN_RF2G3_DB1_0 0x000001C0 -#define AR9285_AN_RF2G3_DB1_0_S 6 -#define AR9285_AN_RF2G3_DB1_1 0x00000038 -#define AR9285_AN_RF2G3_DB1_1_S 3 -#define AR9285_AN_RF2G3_DB1_2 0x00000007 -#define AR9285_AN_RF2G3_DB1_2_S 0 -#define AR9285_AN_RF2G4 0x782C -#define AR9285_AN_RF2G4_DB1_3 0xE0000000 -#define AR9285_AN_RF2G4_DB1_3_S 29 -#define AR9285_AN_RF2G4_DB1_4 0x1C000000 -#define AR9285_AN_RF2G4_DB1_4_S 26 - -#define AR9285_AN_RF2G4_DB2_0 0x03800000 -#define AR9285_AN_RF2G4_DB2_0_S 23 -#define AR9285_AN_RF2G4_DB2_1 0x00700000 -#define AR9285_AN_RF2G4_DB2_1_S 20 -#define AR9285_AN_RF2G4_DB2_2 0x000E0000 -#define AR9285_AN_RF2G4_DB2_2_S 17 -#define AR9285_AN_RF2G4_DB2_3 0x0001C000 -#define AR9285_AN_RF2G4_DB2_3_S 14 -#define AR9285_AN_RF2G4_DB2_4 0x00003800 -#define AR9285_AN_RF2G4_DB2_4_S 11 - -#define AR9285_AN_RF2G6 0x7834 -#define AR9285_AN_RF2G6_CCOMP 0x00007800 -#define AR9285_AN_RF2G6_CCOMP_S 11 -#define AR9285_AN_RF2G6_OFFS 0x03f00000 -#define AR9285_AN_RF2G6_OFFS_S 20 - -#define AR9285_AN_RF2G7 0x7838 -#define AR9285_AN_RF2G7_PWDDB 0x00000002 -#define AR9285_AN_RF2G7_PWDDB_S 1 -#define AR9285_AN_RF2G7_PADRVGN2TAB0 0xE0000000 -#define AR9285_AN_RF2G7_PADRVGN2TAB0_S 29 - -#define AR9285_AN_RF2G8 0x783C -#define AR9285_AN_RF2G8_PADRVGN2TAB0 0x0001C000 -#define AR9285_AN_RF2G8_PADRVGN2TAB0_S 14 - - -#define AR9285_AN_RF2G9 0x7840 -#define AR9285_AN_RXTXBB1 0x7854 -#define AR9285_AN_RXTXBB1_PDRXTXBB1 0x00000020 -#define AR9285_AN_RXTXBB1_PDRXTXBB1_S 5 -#define AR9285_AN_RXTXBB1_PDV2I 0x00000080 -#define AR9285_AN_RXTXBB1_PDV2I_S 7 -#define AR9285_AN_RXTXBB1_PDDACIF 0x00000100 -#define AR9285_AN_RXTXBB1_PDDACIF_S 8 -#define AR9285_AN_RXTXBB1_SPARE9 0x00000001 -#define AR9285_AN_RXTXBB1_SPARE9_S 0 - -#define AR9285_AN_TOP2 0x7868 - -#define AR9285_AN_TOP3 0x786c -#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C -#define AR9285_AN_TOP3_XPABIAS_LVL_S 2 -#define AR9285_AN_TOP3_PWDDAC 0x00800000 -#define AR9285_AN_TOP3_PWDDAC_S 23 - -#define AR9285_AN_TOP4 0x7870 -#define AR9285_AN_TOP4_DEFAULT 0x10142c00 - -#define AR_STA_ID0 0x8000 -#define AR_STA_ID1 0x8004 -#define AR_STA_ID1_SADH_MASK 0x0000FFFF -#define AR_STA_ID1_STA_AP 0x00010000 -#define AR_STA_ID1_ADHOC 0x00020000 -#define AR_STA_ID1_PWR_SAV 0x00040000 -#define AR_STA_ID1_KSRCHDIS 0x00080000 -#define AR_STA_ID1_PCF 0x00100000 -#define AR_STA_ID1_USE_DEFANT 0x00200000 -#define AR_STA_ID1_DEFANT_UPDATE 0x00400000 -#define AR_STA_ID1_RTS_USE_DEF 0x00800000 -#define AR_STA_ID1_ACKCTS_6MB 0x01000000 -#define AR_STA_ID1_BASE_RATE_11B 0x02000000 -#define AR_STA_ID1_SECTOR_SELF_GEN 0x04000000 -#define AR_STA_ID1_CRPT_MIC_ENABLE 0x08000000 -#define AR_STA_ID1_KSRCH_MODE 0x10000000 -#define AR_STA_ID1_PRESERVE_SEQNUM 0x20000000 -#define AR_STA_ID1_CBCIV_ENDIAN 0x40000000 -#define AR_STA_ID1_MCAST_KSRCH 0x80000000 - -#define AR_BSS_ID0 0x8008 -#define AR_BSS_ID1 0x800C -#define AR_BSS_ID1_U16 0x0000FFFF -#define AR_BSS_ID1_AID 0x07FF0000 -#define AR_BSS_ID1_AID_S 16 - -#define AR_BCN_RSSI_AVE 0x8010 -#define AR_BCN_RSSI_AVE_MASK 0x00000FFF - -#define AR_TIME_OUT 0x8014 -#define AR_TIME_OUT_ACK 0x00003FFF -#define AR_TIME_OUT_ACK_S 0 -#define AR_TIME_OUT_CTS 0x3FFF0000 -#define AR_TIME_OUT_CTS_S 16 - -#define AR_RSSI_THR 0x8018 -#define AR_RSSI_THR_MASK 0x000000FF -#define AR_RSSI_THR_BM_THR 0x0000FF00 -#define AR_RSSI_THR_BM_THR_S 8 -#define AR_RSSI_BCN_WEIGHT 0x1F000000 -#define AR_RSSI_BCN_WEIGHT_S 24 -#define AR_RSSI_BCN_RSSI_RST 0x20000000 - -#define AR_USEC 0x801c -#define AR_USEC_USEC 0x0000007F -#define AR_USEC_TX_LAT 0x007FC000 -#define AR_USEC_TX_LAT_S 14 -#define AR_USEC_RX_LAT 0x1F800000 -#define AR_USEC_RX_LAT_S 23 - -#define AR_RESET_TSF 0x8020 -#define AR_RESET_TSF_ONCE 0x01000000 - -#define AR_MAX_CFP_DUR 0x8038 -#define AR_CFP_VAL 0x0000FFFF - -#define AR_RX_FILTER 0x803C -#define AR_RX_COMPR_BAR 0x00000400 - -#define AR_MCAST_FIL0 0x8040 -#define AR_MCAST_FIL1 0x8044 - -#define AR_DIAG_SW 0x8048 -#define AR_DIAG_CACHE_ACK 0x00000001 -#define AR_DIAG_ACK_DIS 0x00000002 -#define AR_DIAG_CTS_DIS 0x00000004 -#define AR_DIAG_ENCRYPT_DIS 0x00000008 -#define AR_DIAG_DECRYPT_DIS 0x00000010 -#define AR_DIAG_RX_DIS 0x00000020 -#define AR_DIAG_LOOP_BACK 0x00000040 -#define AR_DIAG_CORR_FCS 0x00000080 -#define AR_DIAG_CHAN_INFO 0x00000100 -#define AR_DIAG_SCRAM_SEED 0x0001FE00 -#define AR_DIAG_SCRAM_SEED_S 8 -#define AR_DIAG_FRAME_NV0 0x00020000 -#define AR_DIAG_OBS_PT_SEL1 0x000C0000 -#define AR_DIAG_OBS_PT_SEL1_S 18 -#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 -#define AR_DIAG_IGNORE_VIRT_CS 0x00200000 -#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000 -#define AR_DIAG_EIFS_CTRL_ENA 0x00800000 -#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000 -#define AR_DIAG_RX_ABORT 0x02000000 -#define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000 -#define AR_DIAG_OBS_PT_SEL2 0x08000000 -#define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000 -#define AR_DIAG_RX_CLEAR_EXT_LOW 0x20000000 - -#define AR_TSF_L32 0x804c -#define AR_TSF_U32 0x8050 - -#define AR_TST_ADDAC 0x8054 -#define AR_DEF_ANTENNA 0x8058 - -#define AR_AES_MUTE_MASK0 0x805c -#define AR_AES_MUTE_MASK0_FC 0x0000FFFF -#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000 -#define AR_AES_MUTE_MASK0_QOS_S 16 - -#define AR_AES_MUTE_MASK1 0x8060 -#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF -#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000 -#define AR_AES_MUTE_MASK1_FC_MGMT_S 16 - -#define AR_GATED_CLKS 0x8064 -#define AR_GATED_CLKS_TX 0x00000002 -#define AR_GATED_CLKS_RX 0x00000004 -#define AR_GATED_CLKS_REG 0x00000008 - -#define AR_OBS_BUS_CTRL 0x8068 -#define AR_OBS_BUS_SEL_1 0x00040000 -#define AR_OBS_BUS_SEL_2 0x00080000 -#define AR_OBS_BUS_SEL_3 0x000C0000 -#define AR_OBS_BUS_SEL_4 0x08040000 -#define AR_OBS_BUS_SEL_5 0x08080000 - -#define AR_OBS_BUS_1 0x806c -#define AR_OBS_BUS_1_PCU 0x00000001 -#define AR_OBS_BUS_1_RX_END 0x00000002 -#define AR_OBS_BUS_1_RX_WEP 0x00000004 -#define AR_OBS_BUS_1_RX_BEACON 0x00000008 -#define AR_OBS_BUS_1_RX_FILTER 0x00000010 -#define AR_OBS_BUS_1_TX_HCF 0x00000020 -#define AR_OBS_BUS_1_QUIET_TIME 0x00000040 -#define AR_OBS_BUS_1_CHAN_IDLE 0x00000080 -#define AR_OBS_BUS_1_TX_HOLD 0x00000100 -#define AR_OBS_BUS_1_TX_FRAME 0x00000200 -#define AR_OBS_BUS_1_RX_FRAME 0x00000400 -#define AR_OBS_BUS_1_RX_CLEAR 0x00000800 -#define AR_OBS_BUS_1_WEP_STATE 0x0003F000 -#define AR_OBS_BUS_1_WEP_STATE_S 12 -#define AR_OBS_BUS_1_RX_STATE 0x01F00000 -#define AR_OBS_BUS_1_RX_STATE_S 20 -#define AR_OBS_BUS_1_TX_STATE 0x7E000000 -#define AR_OBS_BUS_1_TX_STATE_S 25 - -#define AR_LAST_TSTP 0x8080 -#define AR_NAV 0x8084 -#define AR_RTS_OK 0x8088 -#define AR_RTS_FAIL 0x808c -#define AR_ACK_FAIL 0x8090 -#define AR_FCS_FAIL 0x8094 -#define AR_BEACON_CNT 0x8098 - -#define AR_SLEEP1 0x80d4 -#define AR_SLEEP1_ASSUME_DTIM 0x00080000 -#define AR_SLEEP1_CAB_TIMEOUT 0xFFE00000 -#define AR_SLEEP1_CAB_TIMEOUT_S 21 - -#define AR_SLEEP2 0x80d8 -#define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000 -#define AR_SLEEP2_BEACON_TIMEOUT_S 21 - -#define AR_BSSMSKL 0x80e0 -#define AR_BSSMSKU 0x80e4 - -#define AR_TPC 0x80e8 -#define AR_TPC_ACK 0x0000003f -#define AR_TPC_ACK_S 0x00 -#define AR_TPC_CTS 0x00003f00 -#define AR_TPC_CTS_S 0x08 -#define AR_TPC_CHIRP 0x003f0000 -#define AR_TPC_CHIRP_S 0x16 - -#define AR_TFCNT 0x80ec -#define AR_RFCNT 0x80f0 -#define AR_RCCNT 0x80f4 -#define AR_CCCNT 0x80f8 - -#define AR_QUIET1 0x80fc -#define AR_QUIET1_NEXT_QUIET_S 0 -#define AR_QUIET1_NEXT_QUIET_M 0x0000ffff -#define AR_QUIET1_QUIET_ENABLE 0x00010000 -#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000 -#define AR_QUIET2 0x8100 -#define AR_QUIET2_QUIET_PERIOD_S 0 -#define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff -#define AR_QUIET2_QUIET_DUR_S 16 -#define AR_QUIET2_QUIET_DUR 0xffff0000 - -#define AR_TSF_PARM 0x8104 -#define AR_TSF_INCREMENT_M 0x000000ff -#define AR_TSF_INCREMENT_S 0x00 - -#define AR_QOS_NO_ACK 0x8108 -#define AR_QOS_NO_ACK_TWO_BIT 0x0000000f -#define AR_QOS_NO_ACK_TWO_BIT_S 0 -#define AR_QOS_NO_ACK_BIT_OFF 0x00000070 -#define AR_QOS_NO_ACK_BIT_OFF_S 4 -#define AR_QOS_NO_ACK_BYTE_OFF 0x00000180 -#define AR_QOS_NO_ACK_BYTE_OFF_S 7 - -#define AR_PHY_ERR 0x810c - -#define AR_PHY_ERR_DCHIRP 0x00000008 -#define AR_PHY_ERR_RADAR 0x00000020 -#define AR_PHY_ERR_OFDM_TIMING 0x00020000 -#define AR_PHY_ERR_CCK_TIMING 0x02000000 - -#define AR_RXFIFO_CFG 0x8114 - - -#define AR_MIC_QOS_CONTROL 0x8118 -#define AR_MIC_QOS_SELECT 0x811c - -#define AR_PCU_MISC 0x8120 -#define AR_PCU_FORCE_BSSID_MATCH 0x00000001 -#define AR_PCU_MIC_NEW_LOC_ENA 0x00000004 -#define AR_PCU_TX_ADD_TSF 0x00000008 -#define AR_PCU_CCK_SIFS_MODE 0x00000010 -#define AR_PCU_RX_ANT_UPDT 0x00000800 -#define AR_PCU_TXOP_TBTT_LIMIT_ENA 0x00001000 -#define AR_PCU_MISS_BCN_IN_SLEEP 0x00004000 -#define AR_PCU_BUG_12306_FIX_ENA 0x00020000 -#define AR_PCU_FORCE_QUIET_COLL 0x00040000 -#define AR_PCU_TBTT_PROTECT 0x00200000 -#define AR_PCU_CLEAR_VMF 0x01000000 -#define AR_PCU_CLEAR_BA_VALID 0x04000000 - - -#define AR_FILT_OFDM 0x8124 -#define AR_FILT_OFDM_COUNT 0x00FFFFFF - -#define AR_FILT_CCK 0x8128 -#define AR_FILT_CCK_COUNT 0x00FFFFFF - -#define AR_PHY_ERR_1 0x812c -#define AR_PHY_ERR_1_COUNT 0x00FFFFFF -#define AR_PHY_ERR_MASK_1 0x8130 - -#define AR_PHY_ERR_2 0x8134 -#define AR_PHY_ERR_2_COUNT 0x00FFFFFF -#define AR_PHY_ERR_MASK_2 0x8138 - -#define AR_PHY_COUNTMAX (3 << 22) -#define AR_MIBCNT_INTRMASK (3 << 22) - -#define AR_TSFOOR_THRESHOLD 0x813c -#define AR_TSFOOR_THRESHOLD_VAL 0x0000FFFF - -#define AR_PHY_ERR_EIFS_MASK 8144 - -#define AR_PHY_ERR_3 0x8168 -#define AR_PHY_ERR_3_COUNT 0x00FFFFFF -#define AR_PHY_ERR_MASK_3 0x816c - -#define AR_TXSIFS 0x81d0 -#define AR_TXSIFS_TIME 0x000000FF -#define AR_TXSIFS_TX_LATENCY 0x00000F00 -#define AR_TXSIFS_TX_LATENCY_S 8 -#define AR_TXSIFS_ACK_SHIFT 0x00007000 -#define AR_TXSIFS_ACK_SHIFT_S 12 - -#define AR_TXOP_X 0x81ec -#define AR_TXOP_X_VAL 0x000000FF - - -#define AR_TXOP_0_3 0x81f0 -#define AR_TXOP_4_7 0x81f4 -#define AR_TXOP_8_11 0x81f8 -#define AR_TXOP_12_15 0x81fc - - -#define AR_NEXT_TBTT_TIMER 0x8200 -#define AR_NEXT_DMA_BEACON_ALERT 0x8204 -#define AR_NEXT_SWBA 0x8208 -#define AR_NEXT_CFP 0x8208 -#define AR_NEXT_HCF 0x820C -#define AR_NEXT_TIM 0x8210 -#define AR_NEXT_DTIM 0x8214 -#define AR_NEXT_QUIET_TIMER 0x8218 -#define AR_NEXT_NDP_TIMER 0x821C - -#define AR_BEACON_PERIOD 0x8220 -#define AR_DMA_BEACON_PERIOD 0x8224 -#define AR_SWBA_PERIOD 0x8228 -#define AR_HCF_PERIOD 0x822C -#define AR_TIM_PERIOD 0x8230 -#define AR_DTIM_PERIOD 0x8234 -#define AR_QUIET_PERIOD 0x8238 -#define AR_NDP_PERIOD 0x823C - -#define AR_TIMER_MODE 0x8240 -#define AR_TBTT_TIMER_EN 0x00000001 -#define AR_DBA_TIMER_EN 0x00000002 -#define AR_SWBA_TIMER_EN 0x00000004 -#define AR_HCF_TIMER_EN 0x00000008 -#define AR_TIM_TIMER_EN 0x00000010 -#define AR_DTIM_TIMER_EN 0x00000020 -#define AR_QUIET_TIMER_EN 0x00000040 -#define AR_NDP_TIMER_EN 0x00000080 -#define AR_TIMER_OVERFLOW_INDEX 0x00000700 -#define AR_TIMER_OVERFLOW_INDEX_S 8 -#define AR_TIMER_THRESH 0xFFFFF000 -#define AR_TIMER_THRESH_S 12 - -#define AR_SLP32_MODE 0x8244 -#define AR_SLP32_HALF_CLK_LATENCY 0x000FFFFF -#define AR_SLP32_ENA 0x00100000 -#define AR_SLP32_TSF_WRITE_STATUS 0x00200000 - -#define AR_SLP32_WAKE 0x8248 -#define AR_SLP32_WAKE_XTL_TIME 0x0000FFFF - -#define AR_SLP32_INC 0x824c -#define AR_SLP32_TST_INC 0x000FFFFF - -#define AR_SLP_CNT 0x8250 -#define AR_SLP_CYCLE_CNT 0x8254 - -#define AR_SLP_MIB_CTRL 0x8258 -#define AR_SLP_MIB_CLEAR 0x00000001 -#define AR_SLP_MIB_PENDING 0x00000002 - -#define AR_2040_MODE 0x8318 -#define AR_2040_JOINED_RX_CLEAR 0x00000001 - - -#define AR_EXTRCCNT 0x8328 - -#define AR_SELFGEN_MASK 0x832c - -#define AR_PCU_TXBUF_CTRL 0x8340 -#define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF -#define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700 -#define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380 - -#define AR_PCU_MISC_MODE2 0x8344 -#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 -#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004 - -#define AR_KEYTABLE_0 0x8800 -#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) -#define AR_KEY_CACHE_SIZE 128 -#define AR_RSVD_KEYTABLE_ENTRIES 4 -#define AR_KEY_TYPE 0x00000007 -#define AR_KEYTABLE_TYPE_40 0x00000000 -#define AR_KEYTABLE_TYPE_104 0x00000001 -#define AR_KEYTABLE_TYPE_128 0x00000003 -#define AR_KEYTABLE_TYPE_TKIP 0x00000004 -#define AR_KEYTABLE_TYPE_AES 0x00000005 -#define AR_KEYTABLE_TYPE_CCM 0x00000006 -#define AR_KEYTABLE_TYPE_CLR 0x00000007 -#define AR_KEYTABLE_ANT 0x00000008 -#define AR_KEYTABLE_VALID 0x00008000 -#define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0) -#define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4) -#define AR_KEYTABLE_KEY2(_n) (AR_KEYTABLE(_n) + 8) -#define AR_KEYTABLE_KEY3(_n) (AR_KEYTABLE(_n) + 12) -#define AR_KEYTABLE_KEY4(_n) (AR_KEYTABLE(_n) + 16) -#define AR_KEYTABLE_TYPE(_n) (AR_KEYTABLE(_n) + 20) -#define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24) -#define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28) - -#endif diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c deleted file mode 100644 index 1ff429b..0000000 --- a/drivers/net/wireless/ath9k/virtual.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -struct ath9k_vif_iter_data { - int count; - u8 *addr; -}; - -static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath9k_vif_iter_data *iter_data = data; - u8 *nbuf; - - nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN, - GFP_ATOMIC); - if (nbuf == NULL) - return; - - memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN); - iter_data->addr = nbuf; - iter_data->count++; -} - -void ath9k_set_bssid_mask(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath9k_vif_iter_data iter_data; - int i, j; - u8 mask[ETH_ALEN]; - - /* - * Add primary MAC address even if it is not in active use since it - * will be configured to the hardware as the starting point and the - * BSSID mask will need to be changed if another address is active. - */ - iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); - if (iter_data.addr) { - memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN); - iter_data.count = 1; - } else - iter_data.count = 0; - - /* Get list of all active MAC addresses */ - spin_lock_bh(&sc->wiphy_lock); - ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, - &iter_data); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] == NULL) - continue; - ieee80211_iterate_active_interfaces_atomic( - sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); - } - spin_unlock_bh(&sc->wiphy_lock); - - /* Generate an address mask to cover all active addresses */ - memset(mask, 0, ETH_ALEN); - for (i = 0; i < iter_data.count; i++) { - u8 *a1 = iter_data.addr + i * ETH_ALEN; - for (j = i + 1; j < iter_data.count; j++) { - u8 *a2 = iter_data.addr + j * ETH_ALEN; - mask[0] |= a1[0] ^ a2[0]; - mask[1] |= a1[1] ^ a2[1]; - mask[2] |= a1[2] ^ a2[2]; - mask[3] |= a1[3] ^ a2[3]; - mask[4] |= a1[4] ^ a2[4]; - mask[5] |= a1[5] ^ a2[5]; - } - } - - kfree(iter_data.addr); - - /* Invert the mask and configure hardware */ - sc->bssidmask[0] = ~mask[0]; - sc->bssidmask[1] = ~mask[1]; - sc->bssidmask[2] = ~mask[2]; - sc->bssidmask[3] = ~mask[3]; - sc->bssidmask[4] = ~mask[4]; - sc->bssidmask[5] = ~mask[5]; - - ath9k_hw_setbssidmask(sc); -} - -int ath9k_wiphy_add(struct ath_softc *sc) -{ - int i, error; - struct ath_wiphy *aphy; - struct ieee80211_hw *hw; - u8 addr[ETH_ALEN]; - - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); - if (hw == NULL) - return -ENOMEM; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] == NULL) - break; - } - - if (i == sc->num_sec_wiphy) { - /* No empty slot available; increase array length */ - struct ath_wiphy **n; - n = krealloc(sc->sec_wiphy, - (sc->num_sec_wiphy + 1) * - sizeof(struct ath_wiphy *), - GFP_ATOMIC); - if (n == NULL) { - spin_unlock_bh(&sc->wiphy_lock); - ieee80211_free_hw(hw); - return -ENOMEM; - } - n[i] = NULL; - sc->sec_wiphy = n; - sc->num_sec_wiphy++; - } - - SET_IEEE80211_DEV(hw, sc->dev); - - aphy = hw->priv; - aphy->sc = sc; - aphy->hw = hw; - sc->sec_wiphy[i] = aphy; - spin_unlock_bh(&sc->wiphy_lock); - - memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); - addr[0] |= 0x02; /* Locally managed address */ - /* - * XOR virtual wiphy index into the least significant bits to generate - * a different MAC address for each virtual wiphy. - */ - addr[5] ^= i & 0xff; - addr[4] ^= (i & 0xff00) >> 8; - addr[3] ^= (i & 0xff0000) >> 16; - - SET_IEEE80211_PERM_ADDR(hw, addr); - - ath_set_hw_capab(sc, hw); - - error = ieee80211_register_hw(hw); - - if (error == 0) { - /* Make sure wiphy scheduler is started (if enabled) */ - ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int); - } - - return error; -} - -int ath9k_wiphy_del(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - int i; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (aphy == sc->sec_wiphy[i]) { - sc->sec_wiphy[i] = NULL; - spin_unlock_bh(&sc->wiphy_lock); - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - return 0; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return -ENOENT; -} - -static int ath9k_send_nullfunc(struct ath_wiphy *aphy, - struct ieee80211_vif *vif, const u8 *bssid, - int ps) -{ - struct ath_softc *sc = aphy->sc; - struct ath_tx_control txctl; - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - __le16 fc; - struct ieee80211_tx_info *info; - - skb = dev_alloc_skb(24); - if (skb == NULL) - return -ENOMEM; - hdr = (struct ieee80211_hdr *) skb_put(skb, 24); - memset(hdr, 0, 24); - fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - if (ps) - fc |= cpu_to_le16(IEEE80211_FCTL_PM); - hdr->frame_control = fc; - memcpy(hdr->addr1, bssid, ETH_ALEN); - memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN); - memcpy(hdr->addr3, bssid, ETH_ALEN); - - info = IEEE80211_SKB_CB(skb); - memset(info, 0, sizeof(*info)); - info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS; - info->control.vif = vif; - info->control.rates[0].idx = 0; - info->control.rates[0].count = 4; - info->control.rates[1].idx = -1; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]]; - txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE; - - if (ath_tx_start(aphy->hw, skb, &txctl) != 0) - goto exit; - - return 0; -exit: - dev_kfree_skb_any(skb); - return -1; -} - -static bool __ath9k_wiphy_pausing(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING) - return true; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING) - return true; - } - return false; -} - -static bool ath9k_wiphy_pausing(struct ath_softc *sc) -{ - bool ret; - spin_lock_bh(&sc->wiphy_lock); - ret = __ath9k_wiphy_pausing(sc); - spin_unlock_bh(&sc->wiphy_lock); - return ret; -} - -static bool __ath9k_wiphy_scanning(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_SCAN) - return true; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN) - return true; - } - return false; -} - -bool ath9k_wiphy_scanning(struct ath_softc *sc) -{ - bool ret; - spin_lock_bh(&sc->wiphy_lock); - ret = __ath9k_wiphy_scanning(sc); - spin_unlock_bh(&sc->wiphy_lock); - return ret; -} - -static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); - -/* caller must hold wiphy_lock */ -static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy) -{ - if (aphy == NULL) - return; - if (aphy->chan_idx != aphy->sc->chan_idx) - return; /* wiphy not on the selected channel */ - __ath9k_wiphy_unpause(aphy); -} - -static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - __ath9k_wiphy_unpause_ch(sc->pri_wiphy); - for (i = 0; i < sc->num_sec_wiphy; i++) - __ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]); - spin_unlock_bh(&sc->wiphy_lock); -} - -void ath9k_wiphy_chan_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); - struct ath_wiphy *aphy = sc->next_wiphy; - - if (aphy == NULL) - return; - - /* - * All pending interfaces paused; ready to change - * channels. - */ - - /* Change channels */ - mutex_lock(&sc->mutex); - /* XXX: remove me eventually */ - ath9k_update_ichannel(sc, aphy->hw, - &sc->sc_ah->channels[sc->chan_idx]); - ath_update_chainmask(sc, sc->chan_is_ht); - if (ath_set_channel(sc, aphy->hw, - &sc->sc_ah->channels[sc->chan_idx]) < 0) { - printk(KERN_DEBUG "ath9k: Failed to set channel for new " - "virtual wiphy\n"); - mutex_unlock(&sc->mutex); - return; - } - mutex_unlock(&sc->mutex); - - ath9k_wiphy_unpause_channel(sc); -} - -/* - * ath9k version of ieee80211_tx_status() for TX frames that are generated - * internally in the driver. - */ -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ath_wiphy *aphy = hw->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - - if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE && - aphy->state == ATH_WIPHY_PAUSING) { - if (!(info->flags & IEEE80211_TX_STAT_ACK)) { - printk(KERN_DEBUG "ath9k: %s: no ACK for pause " - "frame\n", wiphy_name(hw->wiphy)); - /* - * The AP did not reply; ignore this to allow us to - * continue. - */ - } - aphy->state = ATH_WIPHY_PAUSED; - if (!ath9k_wiphy_pausing(aphy->sc)) { - /* - * Drop from tasklet to work to allow mutex for channel - * change. - */ - queue_work(aphy->sc->hw->workqueue, - &aphy->sc->chan_work); - } - } - - kfree(tx_info_priv); - tx_info->rate_driver_data[0] = NULL; - - dev_kfree_skb(skb); -} - -static void ath9k_mark_paused(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - aphy->state = ATH_WIPHY_PAUSED; - if (!__ath9k_wiphy_pausing(sc)) - queue_work(sc->hw->workqueue, &sc->chan_work); -} - -static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = data; - struct ath_vif *avp = (void *) vif->drv_priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->bss_conf.assoc) { - ath9k_mark_paused(aphy); - break; - } - /* TODO: could avoid this if already in PS mode */ - if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) { - printk(KERN_DEBUG "%s: failed to send PS nullfunc\n", - __func__); - ath9k_mark_paused(aphy); - } - break; - case NL80211_IFTYPE_AP: - /* Beacon transmission is paused by aphy->state change */ - ath9k_mark_paused(aphy); - break; - default: - break; - } -} - -/* caller must hold wiphy_lock */ -static int __ath9k_wiphy_pause(struct ath_wiphy *aphy) -{ - ieee80211_stop_queues(aphy->hw); - aphy->state = ATH_WIPHY_PAUSING; - /* - * TODO: handle PAUSING->PAUSED for the case where there are multiple - * active vifs (now we do it on the first vif getting ready; should be - * on the last) - */ - ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter, - aphy); - return 0; -} - -int ath9k_wiphy_pause(struct ath_wiphy *aphy) -{ - int ret; - spin_lock_bh(&aphy->sc->wiphy_lock); - ret = __ath9k_wiphy_pause(aphy); - spin_unlock_bh(&aphy->sc->wiphy_lock); - return ret; -} - -static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = data; - struct ath_vif *avp = (void *) vif->drv_priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->bss_conf.assoc) - break; - ath9k_send_nullfunc(aphy, vif, avp->bssid, 0); - break; - case NL80211_IFTYPE_AP: - /* Beacon transmission is re-enabled by aphy->state change */ - break; - default: - break; - } -} - -/* caller must hold wiphy_lock */ -static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy) -{ - ieee80211_iterate_active_interfaces_atomic(aphy->hw, - ath9k_unpause_iter, aphy); - aphy->state = ATH_WIPHY_ACTIVE; - ieee80211_wake_queues(aphy->hw); - return 0; -} - -int ath9k_wiphy_unpause(struct ath_wiphy *aphy) -{ - int ret; - spin_lock_bh(&aphy->sc->wiphy_lock); - ret = __ath9k_wiphy_unpause(aphy); - spin_unlock_bh(&aphy->sc->wiphy_lock); - return ret; -} - -static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) - sc->pri_wiphy->state = ATH_WIPHY_PAUSED; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) - sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED; - } -} - -/* caller must hold wiphy_lock */ -static void __ath9k_wiphy_pause_all(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) - __ath9k_wiphy_pause(sc->pri_wiphy); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) - __ath9k_wiphy_pause(sc->sec_wiphy[i]); - } -} - -int ath9k_wiphy_select(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - bool now; - - spin_lock_bh(&sc->wiphy_lock); - if (__ath9k_wiphy_scanning(sc)) { - /* - * For now, we are using mac80211 sw scan and it expects to - * have full control over channel changes, so avoid wiphy - * scheduling during a scan. This could be optimized if the - * scanning control were moved into the driver. - */ - spin_unlock_bh(&sc->wiphy_lock); - return -EBUSY; - } - if (__ath9k_wiphy_pausing(sc)) { - if (sc->wiphy_select_failures == 0) - sc->wiphy_select_first_fail = jiffies; - sc->wiphy_select_failures++; - if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2)) - { - printk(KERN_DEBUG "ath9k: Previous wiphy select timed " - "out; disable/enable hw to recover\n"); - __ath9k_wiphy_mark_all_paused(sc); - /* - * TODO: this workaround to fix hardware is unlikely to - * be specific to virtual wiphy changes. It can happen - * on normal channel change, too, and as such, this - * should really be made more generic. For example, - * tricker radio disable/enable on GTT interrupt burst - * (say, 10 GTT interrupts received without any TX - * frame being completed) - */ - spin_unlock_bh(&sc->wiphy_lock); - ath_radio_disable(sc); - ath_radio_enable(sc); - queue_work(aphy->sc->hw->workqueue, - &aphy->sc->chan_work); - return -EBUSY; /* previous select still in progress */ - } - spin_unlock_bh(&sc->wiphy_lock); - return -EBUSY; /* previous select still in progress */ - } - sc->wiphy_select_failures = 0; - - /* Store the new channel */ - sc->chan_idx = aphy->chan_idx; - sc->chan_is_ht = aphy->chan_is_ht; - sc->next_wiphy = aphy; - - __ath9k_wiphy_pause_all(sc); - now = !__ath9k_wiphy_pausing(aphy->sc); - spin_unlock_bh(&sc->wiphy_lock); - - if (now) { - /* Ready to request channel change immediately */ - queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); - } - - /* - * wiphys will be unpaused in ath9k_tx_status() once channel has been - * changed if any wiphy needs time to become paused. - */ - - return 0; -} - -bool ath9k_wiphy_started(struct ath_softc *sc) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { - spin_unlock_bh(&sc->wiphy_lock); - return true; - } - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) { - spin_unlock_bh(&sc->wiphy_lock); - return true; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return false; -} - -static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, - struct ath_wiphy *selected) -{ - if (selected->state == ATH_WIPHY_SCAN) { - if (aphy == selected) - return; - /* - * Pause all other wiphys for the duration of the scan even if - * they are on the current channel now. - */ - } else if (aphy->chan_idx == selected->chan_idx) - return; - aphy->state = ATH_WIPHY_PAUSED; - ieee80211_stop_queues(aphy->hw); -} - -void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, - struct ath_wiphy *selected) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_chan(sc->pri_wiphy, selected); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected); - } - spin_unlock_bh(&sc->wiphy_lock); -} - -void ath9k_wiphy_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - wiphy_work.work); - struct ath_wiphy *aphy = NULL; - bool first = true; - - spin_lock_bh(&sc->wiphy_lock); - - if (sc->wiphy_scheduler_int == 0) { - /* wiphy scheduler is disabled */ - spin_unlock_bh(&sc->wiphy_lock); - return; - } - -try_again: - sc->wiphy_scheduler_index++; - while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) { - aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1]; - if (aphy && aphy->state != ATH_WIPHY_INACTIVE) - break; - - sc->wiphy_scheduler_index++; - aphy = NULL; - } - if (aphy == NULL) { - sc->wiphy_scheduler_index = 0; - if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) { - if (first) { - first = false; - goto try_again; - } - /* No wiphy is ready to be scheduled */ - } else - aphy = sc->pri_wiphy; - } - - spin_unlock_bh(&sc->wiphy_lock); - - if (aphy && - aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN && - ath9k_wiphy_select(aphy)) { - printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy " - "change\n"); - } - - queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, - sc->wiphy_scheduler_int); -} - -void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) -{ - cancel_delayed_work_sync(&sc->wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); - if (sc->wiphy_scheduler_int) - queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, - sc->wiphy_scheduler_int); -} diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c deleted file mode 100644 index 628b780..0000000 --- a/drivers/net/wireless/ath9k/xmit.c +++ /dev/null @@ -1,2171 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -#define BITS_PER_BYTE 8 -#define OFDM_PLCP_BITS 22 -#define HT_RC_2_MCS(_rc) ((_rc) & 0x0f) -#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) -#define L_STF 8 -#define L_LTF 8 -#define L_SIG 4 -#define HT_SIG 8 -#define HT_STF 4 -#define HT_LTF(_ns) (4 * (_ns)) -#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */ -#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */ -#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) -#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) - -#define OFDM_SIFS_TIME 16 - -static u32 bits_per_symbol[][2] = { - /* 20MHz 40MHz */ - { 26, 54 }, /* 0: BPSK */ - { 52, 108 }, /* 1: QPSK 1/2 */ - { 78, 162 }, /* 2: QPSK 3/4 */ - { 104, 216 }, /* 3: 16-QAM 1/2 */ - { 156, 324 }, /* 4: 16-QAM 3/4 */ - { 208, 432 }, /* 5: 64-QAM 2/3 */ - { 234, 486 }, /* 6: 64-QAM 3/4 */ - { 260, 540 }, /* 7: 64-QAM 5/6 */ - { 52, 108 }, /* 8: BPSK */ - { 104, 216 }, /* 9: QPSK 1/2 */ - { 156, 324 }, /* 10: QPSK 3/4 */ - { 208, 432 }, /* 11: 16-QAM 1/2 */ - { 312, 648 }, /* 12: 16-QAM 3/4 */ - { 416, 864 }, /* 13: 64-QAM 2/3 */ - { 468, 972 }, /* 14: 64-QAM 3/4 */ - { 520, 1080 }, /* 15: 64-QAM 5/6 */ -}; - -#define IS_HT_RATE(_rate) ((_rate) & 0x80) - -static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head); -static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, - struct list_head *bf_q, - int txok, int sendbar); -static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, - struct list_head *head); -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); -static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - int txok); -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, - int nbad, int txok, bool update_rc); - -/*********************/ -/* Aggregation logic */ -/*********************/ - -static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) -{ - struct ath_atx_tid *tid; - tid = ATH_AN_2_TID(an, tidno); - - if (tid->state & AGGR_ADDBA_COMPLETE || - tid->state & AGGR_ADDBA_PROGRESS) - return 1; - else - return 0; -} - -static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) -{ - struct ath_atx_ac *ac = tid->ac; - - if (tid->paused) - return; - - if (tid->sched) - return; - - tid->sched = true; - list_add_tail(&tid->list, &ac->tid_q); - - if (ac->sched) - return; - - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); -} - -static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) -{ - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; - - spin_lock_bh(&txq->axq_lock); - tid->paused++; - spin_unlock_bh(&txq->axq_lock); -} - -static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) -{ - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; - - ASSERT(tid->paused > 0); - spin_lock_bh(&txq->axq_lock); - - tid->paused--; - - if (tid->paused > 0) - goto unlock; - - if (list_empty(&tid->buf_q)) - goto unlock; - - ath_tx_queue_tid(txq, tid); - ath_txq_schedule(sc, txq); -unlock: - spin_unlock_bh(&txq->axq_lock); -} - -static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) -{ - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; - struct ath_buf *bf; - struct list_head bf_head; - INIT_LIST_HEAD(&bf_head); - - ASSERT(tid->paused > 0); - spin_lock_bh(&txq->axq_lock); - - tid->paused--; - - if (tid->paused > 0) { - spin_unlock_bh(&txq->axq_lock); - return; - } - - while (!list_empty(&tid->buf_q)) { - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - ASSERT(!bf_isretried(bf)); - list_move_tail(&bf->list, &bf_head); - ath_tx_send_ht_normal(sc, txq, tid, &bf_head); - } - - spin_unlock_bh(&txq->axq_lock); -} - -static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - int seqno) -{ - int index, cindex; - - index = ATH_BA_INDEX(tid->seq_start, seqno); - cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - - tid->tx_buf[cindex] = NULL; - - while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) { - INCR(tid->seq_start, IEEE80211_SEQ_MAX); - INCR(tid->baw_head, ATH_TID_MAX_BUFS); - } -} - -static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf) -{ - int index, cindex; - - if (bf_isretried(bf)) - return; - - index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); - cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - - ASSERT(tid->tx_buf[cindex] == NULL); - tid->tx_buf[cindex] = bf; - - if (index >= ((tid->baw_tail - tid->baw_head) & - (ATH_TID_MAX_BUFS - 1))) { - tid->baw_tail = cindex; - INCR(tid->baw_tail, ATH_TID_MAX_BUFS); - } -} - -/* - * TODO: For frame(s) that are in the retry state, we will reuse the - * sequence number(s) without setting the retry bit. The - * alternative is to give up on these and BAR the receiver's window - * forward. - */ -static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid) - -{ - struct ath_buf *bf; - struct list_head bf_head; - INIT_LIST_HEAD(&bf_head); - - for (;;) { - if (list_empty(&tid->buf_q)) - break; - - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - list_move_tail(&bf->list, &bf_head); - - if (bf_isretried(bf)) - ath_tx_update_baw(sc, tid, bf->bf_seqno); - - spin_unlock(&txq->axq_lock); - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); - spin_lock(&txq->axq_lock); - } - - tid->seq_next = tid->seq_start; - tid->baw_tail = tid->baw_head; -} - -static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) -{ - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - - bf->bf_state.bf_type |= BUF_RETRY; - bf->bf_retries++; - - skb = bf->bf_mpdu; - hdr = (struct ieee80211_hdr *)skb->data; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); -} - -static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) -{ - struct ath_buf *tbf; - - spin_lock_bh(&sc->tx.txbuflock); - ASSERT(!list_empty((&sc->tx.txbuf))); - tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - list_del(&tbf->list); - spin_unlock_bh(&sc->tx.txbuflock); - - ATH_TXBUF_RESET(tbf); - - tbf->bf_mpdu = bf->bf_mpdu; - tbf->bf_buf_addr = bf->bf_buf_addr; - *(tbf->bf_desc) = *(bf->bf_desc); - tbf->bf_state = bf->bf_state; - tbf->bf_dmacontext = bf->bf_dmacontext; - - return tbf; -} - -static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf, struct list_head *bf_q, - int txok) -{ - struct ath_node *an = NULL; - struct sk_buff *skb; - struct ieee80211_sta *sta; - struct ieee80211_hdr *hdr; - struct ath_atx_tid *tid = NULL; - struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; - struct ath_desc *ds = bf_last->bf_desc; - struct list_head bf_head, bf_pending; - u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; - u32 ba[WME_BA_BMP_SIZE >> 5]; - int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; - bool rc_update = true; - - skb = bf->bf_mpdu; - hdr = (struct ieee80211_hdr *)skb->data; - - rcu_read_lock(); - - sta = ieee80211_find_sta(sc->hw, hdr->addr1); - if (!sta) { - rcu_read_unlock(); - return; - } - - an = (struct ath_node *)sta->drv_priv; - tid = ATH_AN_2_TID(an, bf->bf_tidno); - - isaggr = bf_isaggr(bf); - memset(ba, 0, WME_BA_BMP_SIZE >> 3); - - if (isaggr && txok) { - if (ATH_DS_TX_BA(ds)) { - seq_st = ATH_DS_BA_SEQ(ds); - memcpy(ba, ATH_DS_BA_BITMAP(ds), - WME_BA_BMP_SIZE >> 3); - } else { - /* - * AR5416 can become deaf/mute when BA - * issue happens. Chip needs to be reset. - * But AP code may have sychronization issues - * when perform internal reset in this routine. - * Only enable reset in STA mode for now. - */ - if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) - needreset = 1; - } - } - - INIT_LIST_HEAD(&bf_pending); - INIT_LIST_HEAD(&bf_head); - - nbad = ath_tx_num_badfrms(sc, bf, txok); - while (bf) { - txfail = txpending = 0; - bf_next = bf->bf_next; - - if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { - /* transmit completion, subframe is - * acked by block ack */ - acked_cnt++; - } else if (!isaggr && txok) { - /* transmit completion */ - acked_cnt++; - } else { - if (!(tid->state & AGGR_CLEANUP) && - ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { - if (bf->bf_retries < ATH_MAX_SW_RETRIES) { - ath_tx_set_retry(sc, bf); - txpending = 1; - } else { - bf->bf_state.bf_type |= BUF_XRETRY; - txfail = 1; - sendbar = 1; - txfail_cnt++; - } - } else { - /* - * cleanup in progress, just fail - * the un-acked sub-frames - */ - txfail = 1; - } - } - - if (bf_next == NULL) { - INIT_LIST_HEAD(&bf_head); - } else { - ASSERT(!list_empty(bf_q)); - list_move_tail(&bf->list, &bf_head); - } - - if (!txpending) { - /* - * complete the acked-ones/xretried ones; update - * block-ack window - */ - spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, bf->bf_seqno); - spin_unlock_bh(&txq->axq_lock); - - if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { - ath_tx_rc_status(bf, ds, nbad, txok, true); - rc_update = false; - } else { - ath_tx_rc_status(bf, ds, nbad, txok, false); - } - - ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); - } else { - /* retry the un-acked ones */ - if (bf->bf_next == NULL && bf_last->bf_stale) { - struct ath_buf *tbf; - - tbf = ath_clone_txbuf(sc, bf_last); - ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); - list_add_tail(&tbf->list, &bf_head); - } else { - /* - * Clear descriptor status words for - * software retry - */ - ath9k_hw_cleartxdesc(sc->sc_ah, bf->bf_desc); - } - - /* - * Put this buffer to the temporary pending - * queue to retain ordering - */ - list_splice_tail_init(&bf_head, &bf_pending); - } - - bf = bf_next; - } - - if (tid->state & AGGR_CLEANUP) { - if (tid->baw_head == tid->baw_tail) { - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->addba_exchangeattempts = 0; - tid->state &= ~AGGR_CLEANUP; - - /* send buffered frames as singles */ - ath_tx_flush_tid(sc, tid); - } - rcu_read_unlock(); - return; - } - - /* prepend un-acked frames to the beginning of the pending frame queue */ - if (!list_empty(&bf_pending)) { - spin_lock_bh(&txq->axq_lock); - list_splice(&bf_pending, &tid->buf_q); - ath_tx_queue_tid(txq, tid); - spin_unlock_bh(&txq->axq_lock); - } - - rcu_read_unlock(); - - if (needreset) - ath_reset(sc, false); -} - -static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, - struct ath_atx_tid *tid) -{ - struct ath_rate_table *rate_table = sc->cur_rate_table; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ieee80211_tx_rate *rates; - struct ath_tx_info_priv *tx_info_priv; - u32 max_4ms_framelen, frmlen; - u16 aggr_limit, legacy = 0, maxampdu; - int i; - - skb = bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - rates = tx_info->control.rates; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; - - /* - * Find the lowest frame length among the rate series that will have a - * 4ms transmit duration. - * TODO - TXOP limit needs to be considered. - */ - max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; - - for (i = 0; i < 4; i++) { - if (rates[i].count) { - if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { - legacy = 1; - break; - } - - frmlen = rate_table->info[rates[i].idx].max_4ms_framelen; - max_4ms_framelen = min(max_4ms_framelen, frmlen); - } - } - - /* - * limit aggregate size by the minimum rate if rate selected is - * not a probe rate, if rate selected is a probe rate then - * avoid aggregation of this packet. - */ - if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) - return 0; - - aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT); - - /* - * h/w can accept aggregates upto 16 bit lengths (65535). - * The IE, however can hold upto 65536, which shows up here - * as zero. Ignore 65536 since we are constrained by hw. - */ - maxampdu = tid->an->maxampdu; - if (maxampdu) - aggr_limit = min(aggr_limit, maxampdu); - - return aggr_limit; -} - -/* - * Returns the number of delimiters to be added to - * meet the minimum required mpdudensity. - * caller should make sure that the rate is HT rate . - */ -static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf, u16 frmlen) -{ - struct ath_rate_table *rt = sc->cur_rate_table; - struct sk_buff *skb = bf->bf_mpdu; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - u32 nsymbits, nsymbols, mpdudensity; - u16 minlen; - u8 rc, flags, rix; - int width, half_gi, ndelim, mindelim; - - /* Select standard number of delimiters based on frame length alone */ - ndelim = ATH_AGGR_GET_NDELIM(frmlen); - - /* - * If encryption enabled, hardware requires some more padding between - * subframes. - * TODO - this could be improved to be dependent on the rate. - * The hardware can keep up at lower rates, but not higher rates - */ - if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) - ndelim += ATH_AGGR_ENCRYPTDELIM; - - /* - * Convert desired mpdu density from microeconds to bytes based - * on highest rate in rate series (i.e. first rate) to determine - * required minimum length for subframe. Take into account - * whether high rate is 20 or 40Mhz and half or full GI. - */ - mpdudensity = tid->an->mpdudensity; - - /* - * If there is no mpdu density restriction, no further calculation - * is needed. - */ - if (mpdudensity == 0) - return ndelim; - - rix = tx_info->control.rates[0].idx; - flags = tx_info->control.rates[0].flags; - rc = rt->info[rix].ratecode; - width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; - half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; - - if (half_gi) - nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); - else - nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity); - - if (nsymbols == 0) - nsymbols = 1; - - nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; - minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; - - if (frmlen < minlen) { - mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ; - ndelim = max(mindelim, ndelim); - } - - return ndelim; -} - -static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, - struct ath_atx_tid *tid, - struct list_head *bf_q) -{ -#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) - struct ath_buf *bf, *bf_first, *bf_prev = NULL; - int rl = 0, nframes = 0, ndelim, prev_al = 0; - u16 aggr_limit = 0, al = 0, bpad = 0, - al_delta, h_baw = tid->baw_size / 2; - enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; - - bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); - - do { - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - - /* do not step over block-ack window */ - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) { - status = ATH_AGGR_BAW_CLOSED; - break; - } - - if (!rl) { - aggr_limit = ath_lookup_rate(sc, bf, tid); - rl = 1; - } - - /* do not exceed aggregation limit */ - al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen; - - if (nframes && - (aggr_limit < (al + bpad + al_delta + prev_al))) { - status = ATH_AGGR_LIMITED; - break; - } - - /* do not exceed subframe limit */ - if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) { - status = ATH_AGGR_LIMITED; - break; - } - nframes++; - - /* add padding for previous frame to aggregation length */ - al += bpad + al_delta; - - /* - * Get the delimiters needed to meet the MPDU - * density for this node. - */ - ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen); - bpad = PADBYTES(al_delta) + (ndelim << 2); - - bf->bf_next = NULL; - bf->bf_desc->ds_link = 0; - - /* link buffers of this frame to the aggregate */ - ath_tx_addto_baw(sc, tid, bf); - ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); - list_move_tail(&bf->list, bf_q); - if (bf_prev) { - bf_prev->bf_next = bf; - bf_prev->bf_desc->ds_link = bf->bf_daddr; - } - bf_prev = bf; - } while (!list_empty(&tid->buf_q)); - - bf_first->bf_al = al; - bf_first->bf_nframes = nframes; - - return status; -#undef PADBYTES -} - -static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid) -{ - struct ath_buf *bf; - enum ATH_AGGR_STATUS status; - struct list_head bf_q; - - do { - if (list_empty(&tid->buf_q)) - return; - - INIT_LIST_HEAD(&bf_q); - - status = ath_tx_form_aggr(sc, tid, &bf_q); - - /* - * no frames picked up to be aggregated; - * block-ack window is not open. - */ - if (list_empty(&bf_q)) - break; - - bf = list_first_entry(&bf_q, struct ath_buf, list); - bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); - - /* if only one frame, send as non-aggregate */ - if (bf->bf_nframes == 1) { - bf->bf_state.bf_type &= ~BUF_AGGR; - ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, &bf_q); - continue; - } - - /* setup first desc of aggregate */ - 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); - - /* anchor last desc of aggregate */ - ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); - - txq->axq_aggr_depth++; - ath_tx_txqaddbuf(sc, txq, &bf_q); - - } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH && - status != ATH_AGGR_BAW_CLOSED); -} - -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) -{ - struct ath_atx_tid *txtid; - struct ath_node *an; - - an = (struct ath_node *)sta->drv_priv; - - if (sc->sc_flags & SC_OP_TXAGGR) { - txtid = ATH_AN_2_TID(an, tid); - txtid->state |= AGGR_ADDBA_PROGRESS; - ath_tx_pause_tid(sc, txtid); - *ssn = txtid->seq_start; - } - - return 0; -} - -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; - struct ath_buf *bf; - struct list_head bf_head; - INIT_LIST_HEAD(&bf_head); - - if (txtid->state & AGGR_CLEANUP) - return 0; - - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - txtid->addba_exchangeattempts = 0; - return 0; - } - - ath_tx_pause_tid(sc, txtid); - - /* drop all software retried frames and mark this TID */ - 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_isretried(bf)) { - /* - * NB: it's based on the assumption that - * software retried frame will always stay - * at the head of software queue. - */ - break; - } - list_move_tail(&bf->list, &bf_head); - ath_tx_update_baw(sc, txtid, bf->bf_seqno); - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); - } - spin_unlock_bh(&txq->axq_lock); - - if (txtid->baw_head != txtid->baw_tail) { - txtid->state |= AGGR_CLEANUP; - } else { - txtid->state &= ~AGGR_ADDBA_COMPLETE; - txtid->addba_exchangeattempts = 0; - ath_tx_flush_tid(sc, txtid); - } - - return 0; -} - -void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) -{ - struct ath_atx_tid *txtid; - struct ath_node *an; - - an = (struct ath_node *)sta->drv_priv; - - if (sc->sc_flags & SC_OP_TXAGGR) { - txtid = ATH_AN_2_TID(an, tid); - txtid->baw_size = - IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; - txtid->state |= AGGR_ADDBA_COMPLETE; - txtid->state &= ~AGGR_ADDBA_PROGRESS; - ath_tx_resume_tid(sc, txtid); - } -} - -bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) -{ - struct ath_atx_tid *txtid; - - if (!(sc->sc_flags & SC_OP_TXAGGR)) - return false; - - txtid = ATH_AN_2_TID(an, tidno); - - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - if (!(txtid->state & AGGR_ADDBA_PROGRESS) && - (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { - txtid->addba_exchangeattempts++; - return true; - } - } - - return false; -} - -/********************/ -/* Queue Management */ -/********************/ - -static void ath_txq_drain_pending_buffers(struct ath_softc *sc, - struct ath_txq *txq) -{ - struct ath_atx_ac *ac, *ac_tmp; - struct ath_atx_tid *tid, *tid_tmp; - - list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { - list_del(&ac->list); - ac->sched = false; - list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { - list_del(&tid->list); - tid->sched = false; - ath_tid_drain(sc, txq, tid); - } - } -} - -struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath9k_tx_queue_info qi; - int qnum; - - memset(&qi, 0, sizeof(qi)); - qi.tqi_subtype = subtype; - qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; - qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; - qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; - qi.tqi_physCompBuf = 0; - - /* - * Enable interrupts only for EOL and DESC conditions. - * We mark tx descriptors to receive a DESC interrupt - * when a tx queue gets deep; otherwise waiting for the - * EOL to reap descriptors. Note that this is done to - * reduce interrupt load and this only defers reaping - * descriptors, never transmitting frames. Aside from - * reducing interrupts this also permits more concurrency. - * The only potential downside is if the tx queue backs - * up in which case the top half of the kernel may backup - * due to a lack of tx descriptors. - * - * The UAPSD queue is an exception, since we take a desc- - * based intr on the EOSP frames. - */ - if (qtype == ATH9K_TX_QUEUE_UAPSD) - qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; - else - qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | - TXQ_FLAG_TXDESCINT_ENABLE; - qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); - if (qnum == -1) { - /* - * NB: don't print a message, this happens - * normally on parts with too few tx queues - */ - return NULL; - } - if (qnum >= ARRAY_SIZE(sc->tx.txq)) { - DPRINTF(sc, ATH_DBG_FATAL, - "qnum %u out of range, max %u!\n", - qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); - ath9k_hw_releasetxqueue(ah, qnum); - return NULL; - } - if (!ATH_TXQ_SETUP(sc, qnum)) { - struct ath_txq *txq = &sc->tx.txq[qnum]; - - txq->axq_qnum = qnum; - txq->axq_link = NULL; - INIT_LIST_HEAD(&txq->axq_q); - INIT_LIST_HEAD(&txq->axq_acq); - spin_lock_init(&txq->axq_lock); - txq->axq_depth = 0; - txq->axq_aggr_depth = 0; - txq->axq_totalqueued = 0; - txq->axq_linkbuf = NULL; - sc->tx.txqsetup |= 1<tx.txq[qnum]; -} - -static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) -{ - int qnum; - - switch (qtype) { - case ATH9K_TX_QUEUE_DATA: - if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - DPRINTF(sc, ATH_DBG_FATAL, - "HAL AC %u out of range, max %zu!\n", - haltype, ARRAY_SIZE(sc->tx.hwq_map)); - return -1; - } - qnum = sc->tx.hwq_map[haltype]; - break; - case ATH9K_TX_QUEUE_BEACON: - qnum = sc->beacon.beaconq; - break; - case ATH9K_TX_QUEUE_CAB: - qnum = sc->beacon.cabq->axq_qnum; - break; - default: - qnum = -1; - } - return qnum; -} - -struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_txq *txq = NULL; - int qnum; - - qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->tx.txq[qnum]; - - spin_lock_bh(&txq->axq_lock); - - if (txq->axq_depth >= (ATH_TXBUF - 20)) { - DPRINTF(sc, ATH_DBG_XMIT, - "TX queue: %d is full, depth: %d\n", - qnum, txq->axq_depth); - ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); - txq->stopped = 1; - spin_unlock_bh(&txq->axq_lock); - return NULL; - } - - spin_unlock_bh(&txq->axq_lock); - - return txq; -} - -int ath_txq_update(struct ath_softc *sc, int qnum, - struct ath9k_tx_queue_info *qinfo) -{ - struct ath_hw *ah = sc->sc_ah; - int error = 0; - struct ath9k_tx_queue_info qi; - - if (qnum == sc->beacon.beaconq) { - /* - * XXX: for beacon queue, we just save the parameter. - * It will be picked up by ath_beaconq_config when - * it's necessary. - */ - sc->beacon.beacon_qi = *qinfo; - return 0; - } - - ASSERT(sc->tx.txq[qnum].axq_qnum == qnum); - - ath9k_hw_get_txq_props(ah, qnum, &qi); - qi.tqi_aifs = qinfo->tqi_aifs; - qi.tqi_cwmin = qinfo->tqi_cwmin; - qi.tqi_cwmax = qinfo->tqi_cwmax; - qi.tqi_burstTime = qinfo->tqi_burstTime; - qi.tqi_readyTime = qinfo->tqi_readyTime; - - if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to update hardware queue %u!\n", qnum); - error = -EIO; - } else { - ath9k_hw_resettxqueue(ah, qnum); - } - - return error; -} - -int ath_cabq_update(struct ath_softc *sc) -{ - struct ath9k_tx_queue_info qi; - int qnum = sc->beacon.cabq->axq_qnum; - - ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); - /* - * Ensure the readytime % is within the bounds. - */ - if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND) - sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND; - else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) - sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; - - qi.tqi_readyTime = (sc->hw->conf.beacon_int * - sc->config.cabqReadytime) / 100; - ath_txq_update(sc, qnum, &qi); - - return 0; -} - -/* - * Drain a given TX queue (could be Beacon or Data) - * - * This assumes output has been stopped and - * we do not need to block ath_tx_tasklet. - */ -void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) -{ - struct ath_buf *bf, *lastbf; - struct list_head bf_head; - - INIT_LIST_HEAD(&bf_head); - - for (;;) { - spin_lock_bh(&txq->axq_lock); - - if (list_empty(&txq->axq_q)) { - txq->axq_link = NULL; - txq->axq_linkbuf = NULL; - spin_unlock_bh(&txq->axq_lock); - break; - } - - bf = list_first_entry(&txq->axq_q, struct ath_buf, list); - - if (bf->bf_stale) { - list_del(&bf->list); - spin_unlock_bh(&txq->axq_lock); - - spin_lock_bh(&sc->tx.txbuflock); - list_add_tail(&bf->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - continue; - } - - lastbf = bf->bf_lastbf; - if (!retry_tx) - lastbf->bf_desc->ds_txstat.ts_flags = - ATH9K_TX_SW_ABORTED; - - /* remove ath_buf's of the same mpdu from txq */ - list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); - txq->axq_depth--; - - spin_unlock_bh(&txq->axq_lock); - - if (bf_isampdu(bf)) - ath_tx_complete_aggr(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_flags & SC_OP_TXAGGR) { - if (!retry_tx) { - spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq); - spin_unlock_bh(&txq->axq_lock); - } - } -} - -void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_txq *txq; - int i, npend = 0; - - if (sc->sc_flags & SC_OP_INVALID) - return; - - /* Stop beacon queue */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - - /* Stop data queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - txq = &sc->tx.txq[i]; - ath9k_hw_stoptxdma(ah, txq->axq_qnum); - npend += ath9k_hw_numtxpending(ah, txq->axq_qnum); - } - } - - if (npend) { - int r; - - DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); - - spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); - if (r) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u\n", - r); - spin_unlock_bh(&sc->sc_resetlock); - } - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) - ath_draintxq(sc, &sc->tx.txq[i], retry_tx); - } -} - -void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) -{ - ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); - sc->tx.txqsetup &= ~(1<axq_qnum); -} - -void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) -{ - struct ath_atx_ac *ac; - struct ath_atx_tid *tid; - - if (list_empty(&txq->axq_acq)) - return; - - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); - list_del(&ac->list); - ac->sched = false; - - do { - if (list_empty(&ac->tid_q)) - return; - - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); - list_del(&tid->list); - tid->sched = false; - - if (tid->paused) - continue; - - if ((txq->axq_depth % 2) == 0) - ath_tx_sched_aggr(sc, txq, tid); - - /* - * add tid to round-robin queue if more frames - * are pending for the tid - */ - if (!list_empty(&tid->buf_q)) - ath_tx_queue_tid(txq, tid); - - break; - } while (!list_empty(&ac->tid_q)); - - if (!list_empty(&ac->tid_q)) { - if (!ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); - } - } -} - -int ath_tx_setup(struct ath_softc *sc, int haltype) -{ - struct ath_txq *txq; - - if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - DPRINTF(sc, ATH_DBG_FATAL, - "HAL AC %u out of range, max %zu!\n", - haltype, ARRAY_SIZE(sc->tx.hwq_map)); - return 0; - } - txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); - if (txq != NULL) { - sc->tx.hwq_map[haltype] = txq->axq_qnum; - return 1; - } else - return 0; -} - -/***********/ -/* TX, DMA */ -/***********/ - -/* - * Insert a chain of ath_buf (descriptors) on a txq and - * assume the descriptors are already chained together by caller. - */ -static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, - struct list_head *head) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_buf *bf; - - /* - * Insert the frame on the outbound list and - * pass it on to the hardware. - */ - - if (list_empty(head)) - return; - - bf = list_first_entry(head, struct ath_buf, list); - - 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, - "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); - - if (txq->axq_link == NULL) { - ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - DPRINTF(sc, ATH_DBG_XMIT, - "TXDP[%u] = %llx (%p)\n", - txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); - } else { - *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", - 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_txstart(ah, txq->axq_qnum); -} - -static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) -{ - struct ath_buf *bf = NULL; - - spin_lock_bh(&sc->tx.txbuflock); - - if (unlikely(list_empty(&sc->tx.txbuf))) { - spin_unlock_bh(&sc->tx.txbuflock); - return NULL; - } - - bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - list_del(&bf->list); - - spin_unlock_bh(&sc->tx.txbuflock); - - return bf; -} - -static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, - struct list_head *bf_head, - struct ath_tx_control *txctl) -{ - struct ath_buf *bf; - - bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_state.bf_type |= BUF_AMPDU; - - /* - * Do not queue to h/w when any of the following conditions is true: - * - there are pending frames in software queue - * - the TID is currently paused for ADDBA/BAR request - * - seqno is not within block-ack window - * - h/w queue depth exceeds low water mark - */ - if (!list_empty(&tid->buf_q) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || - txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { - /* - * Add this frame to software queue for scheduling later - * for aggregation. - */ - list_move_tail(&bf->list, &tid->buf_q); - ath_tx_queue_tid(txctl->txq, tid); - return; - } - - /* Add sub-frame to BAW */ - ath_tx_addto_baw(sc, tid, bf); - - /* Queue to h/w without aggregation */ - bf->bf_nframes = 1; - bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txctl->txq, bf_head); -} - -static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head) -{ - struct ath_buf *bf; - - bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_state.bf_type &= ~BUF_AMPDU; - - /* update starting sequence number for subsequent ADDBA request */ - INCR(tid->seq_start, IEEE80211_SEQ_MAX); - - bf->bf_nframes = 1; - bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, bf_head); -} - -static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, - struct list_head *bf_head) -{ - struct ath_buf *bf; - - bf = list_first_entry(bf_head, struct ath_buf, list); - - bf->bf_lastbf = bf; - bf->bf_nframes = 1; - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, bf_head); -} - -static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - enum ath9k_pkt_type htype; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_beacon(fc)) - htype = ATH9K_PKT_TYPE_BEACON; - else if (ieee80211_is_probe_resp(fc)) - htype = ATH9K_PKT_TYPE_PROBE_RESP; - else if (ieee80211_is_atim(fc)) - htype = ATH9K_PKT_TYPE_ATIM; - else if (ieee80211_is_pspoll(fc)) - htype = ATH9K_PKT_TYPE_PSPOLL; - else - htype = ATH9K_PKT_TYPE_NORMAL; - - return htype; -} - -static bool is_pae(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_data(fc)) { - if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(ETH_P_PAE))) { - return true; - } - } - - return false; -} - -static int get_hw_crypto_keytype(struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - if (tx_info->control.hw_key) { - if (tx_info->control.hw_key->alg == ALG_WEP) - return ATH9K_KEY_TYPE_WEP; - else if (tx_info->control.hw_key->alg == ALG_TKIP) - return ATH9K_KEY_TYPE_TKIP; - else if (tx_info->control.hw_key->alg == ALG_CCMP) - return ATH9K_KEY_TYPE_AES; - } - - return ATH9K_KEY_TYPE_CLEAR; -} - -static void assign_aggr_tid_seqno(struct sk_buff *skb, - struct ath_buf *bf) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr; - struct ath_node *an; - struct ath_atx_tid *tid; - __le16 fc; - u8 *qc; - - if (!tx_info->control.sta) - return; - - an = (struct ath_node *)tx_info->control.sta->drv_priv; - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - bf->bf_tidno = qc[0] & 0xf; - } - - /* - * For HT capable stations, we save tidno for later use. - * We also override seqno set by upper layer with the one - * in tx aggregation state. - * - * If fragmentation is on, the sequence number is - * not overridden, since it has been - * incremented by the fragmentation routine. - * - * FIXME: check if the fragmentation threshold exceeds - * IEEE80211 max. - */ - tid = ATH_AN_2_TID(an, bf->bf_tidno); - hdr->seq_ctrl = cpu_to_le16(tid->seq_next << - IEEE80211_SEQ_SEQ_SHIFT); - bf->bf_seqno = tid->seq_next; - INCR(tid->seq_next, IEEE80211_SEQ_MAX); -} - -static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, - struct ath_txq *txq) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int flags = 0; - - flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ - flags |= ATH9K_TXDESC_INTREQ; - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - flags |= ATH9K_TXDESC_NOACK; - - return flags; -} - -/* - * rix - rate index - * pktlen - total bytes (delims + data + fcs + pads + pad delims) - * width - 0 for 20 MHz, 1 for 40 MHz - * half_gi - to use 4us v/s 3.6 us for symbol time - */ -static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, - int width, int half_gi, bool shortPreamble) -{ - struct ath_rate_table *rate_table = sc->cur_rate_table; - u32 nbits, nsymbits, duration, nsymbols; - u8 rc; - int streams, pktlen; - - pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; - rc = rate_table->info[rix].ratecode; - - /* for legacy rates, use old function to compute packet duration */ - if (!IS_HT_RATE(rc)) - return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, - rix, shortPreamble); - - /* find number of symbols: PLCP + data */ - nbits = (pktlen << 3) + OFDM_PLCP_BITS; - nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; - nsymbols = (nbits + nsymbits - 1) / nsymbits; - - if (!half_gi) - duration = SYMBOL_TIME(nsymbols); - else - duration = SYMBOL_TIME_HALFGI(nsymbols); - - /* addup duration for legacy/ht training and signal fields */ - streams = HT_RC_2_STREAMS(rc); - duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); - - return duration; -} - -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) -{ - struct ath_rate_table *rt = sc->cur_rate_table; - struct ath9k_11n_rate_series series[4]; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ieee80211_tx_rate *rates; - struct ieee80211_hdr *hdr; - int i, flags = 0; - u8 rix = 0, ctsrate = 0; - bool is_pspoll; - - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - - skb = bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - rates = tx_info->control.rates; - hdr = (struct ieee80211_hdr *)skb->data; - is_pspoll = ieee80211_is_pspoll(hdr->frame_control); - - /* - * We check if Short Preamble is needed for the CTS rate by - * checking the BSS's global flag. - * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. - */ - if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode | - rt->info[tx_info->control.rts_cts_rate_idx].short_preamble; - else - ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode; - - /* - * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. - * Check the first rate in the series to decide whether RTS/CTS - * or CTS-to-self has to be used. - */ - if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - flags = ATH9K_TXDESC_CTSENA; - else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - flags = ATH9K_TXDESC_RTSENA; - - /* FIXME: Handle aggregation protection */ - if (sc->config.ath_aggr_prot && - (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { - flags = ATH9K_TXDESC_RTSENA; - } - - /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ - if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) - flags &= ~(ATH9K_TXDESC_RTSENA); - - for (i = 0; i < 4; i++) { - if (!rates[i].count || (rates[i].idx < 0)) - continue; - - rix = rates[i].idx; - series[i].Tries = rates[i].count; - series[i].ChSel = sc->tx_chainmask; - - if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - series[i].Rate = rt->info[rix].ratecode | - rt->info[rix].short_preamble; - else - series[i].Rate = rt->info[rix].ratecode; - - if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - series[i].RateFlags |= ATH9K_RATESERIES_2040; - if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) - series[i].RateFlags |= ATH9K_RATESERIES_HALFGI; - - series[i].PktDuration = ath_pkt_duration(sc, rix, bf, - (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, - (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), - (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)); - } - - /* set dur_update_en for l-sig computation except for PS-Poll frames */ - ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc, - bf->bf_lastbf->bf_desc, - !is_pspoll, ctsrate, - 0, series, 4, flags); - - if (sc->config.ath_aggr_prot && flags) - ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); -} - -static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, - struct sk_buff *skb, - struct ath_tx_control *txctl) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ath_tx_info_priv *tx_info_priv; - int hdrlen; - __le16 fc; - - tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - if (unlikely(!tx_info_priv)) - return -ENOMEM; - tx_info->rate_driver_data[0] = tx_info_priv; - tx_info_priv->aphy = aphy; - tx_info_priv->frame_type = txctl->frame_type; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - ATH_TXBUF_RESET(bf); - - bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); - - if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) - bf->bf_state.bf_type |= BUF_HT; - - bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); - - bf->bf_keytype = get_hw_crypto_keytype(skb); - if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { - bf->bf_frmlen += tx_info->control.hw_key->icv_len; - bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; - } else { - bf->bf_keyix = ATH9K_TXKEYIX_INVALID; - } - - if (ieee80211_is_data_qos(fc) && (sc->sc_flags & SC_OP_TXAGGR)) - assign_aggr_tid_seqno(skb, bf); - - bf->bf_mpdu = skb; - - bf->bf_dmacontext = dma_map_single(sc->dev, skb->data, - skb->len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) { - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, - "dma_mapping_error() on TX\n"); - return -ENOMEM; - } - - bf->bf_buf_addr = bf->bf_dmacontext; - return 0; -} - -/* FIXME: tx power */ -static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_control *txctl) -{ - struct sk_buff *skb = bf->bf_mpdu; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ath_node *an = NULL; - struct list_head bf_head; - struct ath_desc *ds; - struct ath_atx_tid *tid; - struct ath_hw *ah = sc->sc_ah; - int frm_type; - __le16 fc; - - frm_type = get_hw_packet_type(skb); - fc = hdr->frame_control; - - INIT_LIST_HEAD(&bf_head); - list_add_tail(&bf->list, &bf_head); - - ds = bf->bf_desc; - ds->ds_link = 0; - ds->ds_data = bf->bf_buf_addr; - - ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, - bf->bf_keyix, bf->bf_keytype, bf->bf_flags); - - ath9k_hw_filltxdesc(ah, ds, - skb->len, /* segment length */ - true, /* first segment */ - true, /* last segment */ - ds); /* first descriptor */ - - spin_lock_bh(&txctl->txq->axq_lock); - - if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && - tx_info->control.sta) { - an = (struct ath_node *)tx_info->control.sta->drv_priv; - tid = ATH_AN_2_TID(an, bf->bf_tidno); - - if (!ieee80211_is_data_qos(fc)) { - ath_tx_send_normal(sc, txctl->txq, &bf_head); - goto tx_done; - } - - if (ath_aggr_query(sc, an, bf->bf_tidno)) { - /* - * Try aggregation if it's a unicast data frame - * and the destination is HT capable. - */ - ath_tx_send_ampdu(sc, tid, &bf_head, txctl); - } else { - /* - * Send this frame as regular when ADDBA - * exchange is neither complete nor pending. - */ - ath_tx_send_ht_normal(sc, txctl->txq, - tid, &bf_head); - } - } else { - ath_tx_send_normal(sc, txctl->txq, &bf_head); - } - -tx_done: - spin_unlock_bh(&txctl->txq->axq_lock); -} - -/* Upon failure caller should free skb */ -int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath_tx_control *txctl) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_buf *bf; - int r; - - bf = ath_tx_get_buffer(sc); - if (!bf) { - DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); - return -1; - } - - r = ath_tx_setup_buffer(hw, bf, skb, txctl); - if (unlikely(r)) { - struct ath_txq *txq = txctl->txq; - - DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); - - /* upon ath_tx_processq() this TX queue will be resumed, we - * guarantee this will happen by knowing beforehand that - * we will at least have to run TX completionon one buffer - * on the queue */ - spin_lock_bh(&txq->axq_lock); - if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { - ieee80211_stop_queue(sc->hw, - skb_get_queue_mapping(skb)); - txq->stopped = 1; - } - spin_unlock_bh(&txq->axq_lock); - - spin_lock_bh(&sc->tx.txbuflock); - list_add_tail(&bf->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - - return r; - } - - ath_tx_start_dma(sc, bf, txctl); - - return 0; -} - -void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - int hdrlen, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath_tx_control txctl; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - - /* - * 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->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.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, "TX CABQ padding failed\n"); - dev_kfree_skb_any(skb); - return; - } - skb_push(skb, padsize); - memmove(skb->data, skb->data + padsize, hdrlen); - } - - txctl.txq = sc->beacon.cabq; - - DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); - - if (ath_tx_start(hw, skb, &txctl) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); - goto exit; - } - - return; -exit: - dev_kfree_skb_any(skb); -} - -/*****************/ -/* TX Completion */ -/*****************/ - -static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - int tx_flags) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - int hdrlen, padsize; - int frame_type = ATH9K_NOT_INTERNAL; - - DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); - - if (tx_info_priv) { - hw = tx_info_priv->aphy->hw; - frame_type = tx_info_priv->frame_type; - } - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - kfree(tx_info_priv); - tx_info->rate_driver_data[0] = NULL; - } - - if (tx_flags & ATH_TX_BAR) - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - - if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; - } - - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { - /* - * Remove MAC header padding before giving the frame back to - * mac80211. - */ - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - if (frame_type == ATH9K_NOT_INTERNAL) - ieee80211_tx_status(hw, skb); - else - ath9k_tx_status(hw, skb); -} - -static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, - struct list_head *bf_q, - int txok, int sendbar) -{ - struct sk_buff *skb = bf->bf_mpdu; - unsigned long flags; - int tx_flags = 0; - - - if (sendbar) - tx_flags = ATH_TX_BAR; - - if (!txok) { - tx_flags |= ATH_TX_ERROR; - - if (bf_isxretried(bf)) - tx_flags |= ATH_TX_XRETRY; - } - - dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); - ath_tx_complete(sc, skb, tx_flags); - - /* - * Return the list of ath_buf of this mpdu to free queue - */ - spin_lock_irqsave(&sc->tx.txbuflock, flags); - list_splice_tail_init(bf_q, &sc->tx.txbuf); - spin_unlock_irqrestore(&sc->tx.txbuflock, flags); -} - -static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - int txok) -{ - struct ath_buf *bf_last = bf->bf_lastbf; - struct ath_desc *ds = bf_last->bf_desc; - u16 seq_st = 0; - u32 ba[WME_BA_BMP_SIZE >> 5]; - int ba_index; - int nbad = 0; - int isaggr = 0; - - if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) - return 0; - - 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); - } - - while (bf) { - ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno); - if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) - nbad++; - - bf = bf->bf_next; - } - - return nbad; -} - -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, - int nbad, int txok, bool update_rc) -{ - struct sk_buff *skb = bf->bf_mpdu; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - struct ieee80211_hw *hw = tx_info_priv->aphy->hw; - u8 i, tx_rateindex; - - if (txok) - tx_info->status.ack_signal = ds->ds_txstat.ts_rssi; - - tx_rateindex = ds->ds_txstat.ts_rateindex; - WARN_ON(tx_rateindex >= hw->max_rates); - - tx_info_priv->update_rc = update_rc; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { - if (ieee80211_is_data(hdr->frame_control)) { - memcpy(&tx_info_priv->tx, &ds->ds_txstat, - sizeof(tx_info_priv->tx)); - tx_info_priv->n_frames = bf->bf_nframes; - tx_info_priv->n_bad_frames = nbad; - } - } - - for (i = tx_rateindex + 1; i < hw->max_rates; i++) - tx_info->status.rates[i].count = 0; - - tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1; -} - -static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) -{ - int qnum; - - spin_lock_bh(&txq->axq_lock); - if (txq->stopped && - sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) { - qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); - if (qnum != -1) { - ieee80211_wake_queue(sc->hw, qnum); - txq->stopped = 0; - } - } - spin_unlock_bh(&txq->axq_lock); -} - -static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_buf *bf, *lastbf, *bf_held = NULL; - struct list_head bf_head; - struct ath_desc *ds; - int txok; - int status; - - DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", - txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), - txq->axq_link); - - for (;;) { - spin_lock_bh(&txq->axq_lock); - if (list_empty(&txq->axq_q)) { - txq->axq_link = NULL; - txq->axq_linkbuf = NULL; - spin_unlock_bh(&txq->axq_lock); - break; - } - bf = list_first_entry(&txq->axq_q, struct ath_buf, list); - - /* - * There is a race condition that a BH gets scheduled - * after sw writes TxE and before hw re-load the last - * descriptor to get the newly chained one. - * Software must keep the last DONE descriptor as a - * holding descriptor - software does so by marking - * it with the STALE flag. - */ - bf_held = NULL; - if (bf->bf_stale) { - bf_held = bf; - if (list_is_last(&bf_held->list, &txq->axq_q)) { - txq->axq_link = NULL; - txq->axq_linkbuf = NULL; - spin_unlock_bh(&txq->axq_lock); - - /* - * The holding descriptor is the last - * descriptor in queue. It's safe to remove - * the last holding descriptor in BH context. - */ - spin_lock_bh(&sc->tx.txbuflock); - list_move_tail(&bf_held->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - - break; - } else { - bf = list_entry(bf_held->list.next, - struct ath_buf, list); - } - } - - lastbf = bf->bf_lastbf; - ds = lastbf->bf_desc; - - status = ath9k_hw_txprocdesc(ah, ds); - if (status == -EINPROGRESS) { - spin_unlock_bh(&txq->axq_lock); - break; - } - if (bf->bf_desc == txq->axq_lastdsWithCTS) - txq->axq_lastdsWithCTS = NULL; - if (ds == txq->axq_gatingds) - txq->axq_gatingds = NULL; - - /* - * Remove ath_buf's of the same transmit unit from txq, - * however leave the last descriptor back as the holding - * descriptor for hw. - */ - lastbf->bf_stale = true; - INIT_LIST_HEAD(&bf_head); - if (!list_is_singular(&lastbf->list)) - list_cut_position(&bf_head, - &txq->axq_q, lastbf->list.prev); - - txq->axq_depth--; - if (bf_isaggr(bf)) - txq->axq_aggr_depth--; - - txok = (ds->ds_txstat.ts_status == 0); - spin_unlock_bh(&txq->axq_lock); - - if (bf_held) { - spin_lock_bh(&sc->tx.txbuflock); - list_move_tail(&bf_held->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - } - - 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_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ds, 0, txok, true); - } - - if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); - else - ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); - - ath_wake_mac80211_queue(sc, txq); - - spin_lock_bh(&txq->axq_lock); - if (sc->sc_flags & SC_OP_TXAGGR) - ath_txq_schedule(sc, txq); - spin_unlock_bh(&txq->axq_lock); - } -} - - -void ath_tx_tasklet(struct ath_softc *sc) -{ - int i; - u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); - - ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) - ath_tx_processq(sc, &sc->tx.txq[i]); - } -} - -/*****************/ -/* Init, Cleanup */ -/*****************/ - -int ath_tx_init(struct ath_softc *sc, int nbufs) -{ - int error = 0; - - spin_lock_init(&sc->tx.txbuflock); - - error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, - "tx", nbufs, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate tx descriptors: %d\n", error); - goto err; - } - - error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, - "beacon", ATH_BCBUF, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate beacon descriptors: %d\n", error); - goto err; - } - -err: - if (error != 0) - ath_tx_cleanup(sc); - - return error; -} - -void ath_tx_cleanup(struct ath_softc *sc) -{ - if (sc->beacon.bdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); - - if (sc->tx.txdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); -} - -void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_atx_tid *tid; - struct ath_atx_ac *ac; - int tidno, acno; - - for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; - tidno++, tid++) { - tid->an = an; - tid->tidno = tidno; - tid->seq_start = tid->seq_next = 0; - tid->baw_size = WME_MAX_BA; - tid->baw_head = tid->baw_tail = 0; - tid->sched = false; - tid->paused = false; - tid->state &= ~AGGR_CLEANUP; - INIT_LIST_HEAD(&tid->buf_q); - acno = TID_TO_WME_AC(tidno); - tid->ac = &an->ac[acno]; - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_ADDBA_PROGRESS; - tid->addba_exchangeattempts = 0; - } - - for (acno = 0, ac = &an->ac[acno]; - acno < WME_NUM_AC; acno++, ac++) { - ac->sched = false; - INIT_LIST_HEAD(&ac->tid_q); - - switch (acno) { - case WME_AC_BE: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - break; - case WME_AC_BK: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); - break; - case WME_AC_VI: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); - break; - case WME_AC_VO: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); - break; - } - } -} - -void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) -{ - int i; - struct ath_atx_ac *ac, *ac_tmp; - struct ath_atx_tid *tid, *tid_tmp; - struct ath_txq *txq; - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - txq = &sc->tx.txq[i]; - - spin_lock(&txq->axq_lock); - - list_for_each_entry_safe(ac, - ac_tmp, &txq->axq_acq, list) { - tid = list_first_entry(&ac->tid_q, - struct ath_atx_tid, list); - if (tid && tid->an != an) - continue; - list_del(&ac->list); - ac->sched = false; - - list_for_each_entry_safe(tid, - tid_tmp, &ac->tid_q, list) { - list_del(&tid->list); - tid->sched = false; - ath_tid_drain(sc, txq, tid); - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->addba_exchangeattempts = 0; - tid->state &= ~AGGR_CLEANUP; - } - } - - spin_unlock(&txq->axq_lock); - } - } -} -- cgit v0.10.2 From 6b2b2ffbef7750e51bfa74e92229ecee10b59307 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 30 Mar 2009 22:30:34 -0400 Subject: ath: space cleanup Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 3ccf21c..4b5c851 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -173,9 +173,9 @@ static bool ath_is_radar_freq(u16 center_freq) * received a beacon on a channel we can enable active scan and * adhoc (or beaconing). */ -static void ath_reg_apply_beaconing_flags( - struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) +static void +ath_reg_apply_beaconing_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) { enum ieee80211_band band; struct ieee80211_supported_band *sband; @@ -232,9 +232,9 @@ static void ath_reg_apply_beaconing_flags( } /* Allows active scan scan on Ch 12 and 13 */ -static void ath_reg_apply_active_scan_flags( - struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) +static void +ath_reg_apply_active_scan_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; @@ -316,8 +316,8 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy) } static void ath_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator, - struct ath_regulatory *reg) + enum nl80211_reg_initiator initiator, + struct ath_regulatory *reg) { switch (reg->regpair->regDmnEnum) { case 0x60: @@ -335,7 +335,8 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, } int ath_reg_notifier_apply(struct wiphy *wiphy, - struct regulatory_request *request, struct ath_regulatory *reg) + struct regulatory_request *request, + struct ath_regulatory *reg) { /* We always apply this */ ath_reg_apply_radar_flags(wiphy); @@ -433,8 +434,10 @@ ath_get_regpair(int regdmn) return NULL; } -static int ath_regd_init_wiphy(struct ath_regulatory *reg, struct wiphy *wiphy, - int (*reg_notifier)(struct wiphy *wiphy, +static int +ath_regd_init_wiphy(struct ath_regulatory *reg, + struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)) { const struct ieee80211_regdomain *regd; @@ -464,9 +467,11 @@ static int ath_regd_init_wiphy(struct ath_regulatory *reg, struct wiphy *wiphy, return 0; } -int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, - int (*reg_notifier)(struct wiphy *wiphy, - struct regulatory_request *request)) +int +ath_regd_init(struct ath_regulatory *reg, + struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) { struct country_code_to_enum_rd *country = NULL; u16 regdmn; -- cgit v0.10.2 From 75c2148fa5330c6de741fc96e3308f57d846a6b4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 30 Mar 2009 22:30:35 -0400 Subject: ath5k: sparse fix ath5k_led_on needs to be static drivers/net/wireless/ath/ath5k/led.c:81:6: warning: symbol 'ath5k_led_on' was not declared. Should it be static? Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 19555fb..006f771 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -78,7 +78,7 @@ void ath5k_led_enable(struct ath5k_softc *sc) } } -void ath5k_led_on(struct ath5k_softc *sc) +static void ath5k_led_on(struct ath5k_softc *sc) { if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) return; -- cgit v0.10.2 From 18a8365992a8041aa178ae9ad5f0d951d0457230 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 Mar 2009 12:12:05 +0200 Subject: cfg80211: introduce scan IE limit attribute This patch introduces a new attribute for a wiphy that tells userspace how long the information elements added to a probe request frame can be at most. It also updates the at76 to advertise that it cannot support that, and, for now until I can fix that, iwlwifi too. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 69248de..55f947a 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -2250,6 +2250,7 @@ static int at76_init_new_device(struct at76_priv *priv, /* mac80211 initialisation */ priv->hw->wiphy->max_scan_ssids = 1; + priv->hw->wiphy->max_scan_ie_len = 0; priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band; priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 82abb1f..ef55f91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1306,6 +1306,7 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->wiphy->custom_regulatory = true; hw->wiphy->max_scan_ssids = 1; + hw->wiphy->max_scan_ie_len = 0; /* XXX for now */ /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 27f230f..209cace 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -390,6 +390,8 @@ enum nl80211_commands { * * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with * a single scan request, a wiphy attribute. + * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements + * that can be added to a scan request * * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive @@ -507,6 +509,8 @@ enum nl80211_attrs { NL80211_ATTR_KEY_TYPE, + NL80211_ATTR_MAX_SCAN_IE_LEN, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/wireless.h b/include/net/wireless.h index 64a7620..2bcdeda 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -222,6 +222,7 @@ struct wiphy { int bss_priv_size; u8 max_scan_ssids; + u16 max_scan_ie_len; /* If multiple wiphys are registered and you're handed e.g. * a regular netdev with assigned ieee80211_ptr, you won't diff --git a/net/mac80211/main.c b/net/mac80211/main.c index fbcbed6..ee58a78 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -728,7 +728,18 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, return NULL; wiphy->privid = mac80211_wiphy_privid; - wiphy->max_scan_ssids = 4; + + if (!ops->hw_scan) { + /* For hw_scan, driver needs to set these up. */ + wiphy->max_scan_ssids = 4; + + /* we support a maximum of 32 rates in cfg80211 */ + wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN + - 2 - 32 /* SSID */ + - 4 - 32 /* (ext) supp rates */; + + } + /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - sizeof(struct cfg80211_bss); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fdf432f..05caf34 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -890,6 +890,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, *pos = rate->bitrate / 5; } + /* if adding more here, adjust max_scan_ie_len */ + if (ie) memcpy(skb_put(skb, ie_len), ie, ie_len); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1394115..447fa17 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -181,6 +181,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, dev->wiphy.max_scan_ssids); + NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, + dev->wiphy.max_scan_ie_len); nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); if (!nl_modes) @@ -2528,6 +2530,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) else ie_len = 0; + if (ie_len > wiphy->max_scan_ie_len) { + err = -EINVAL; + goto out; + } + request = kzalloc(sizeof(*request) + sizeof(*ssid) * n_ssids + sizeof(channel) * n_channels -- cgit v0.10.2 From de95a54b1aebe5592cae971ca5e5d9ec6a381a17 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Apr 2009 11:58:36 +0200 Subject: mac80211: pass all probe request IEs to driver Instead of just passing the cfg80211-requested IEs, pass the locally generated ones as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2b1f6c6..d303c26 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -503,7 +503,7 @@ struct cfg80211_scan_request { int n_ssids; struct ieee80211_channel **channels; u32 n_channels; - u8 *ie; + const u8 *ie; size_t ie_len; /* internal */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3b83a80..2c6f976 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1330,11 +1330,14 @@ enum ieee80211_ampdu_mlme_action { * the scan state machine in stack. The scan must honour the channel * configuration done by the regulatory agent in the wiphy's * registered bands. The hardware (or the driver) needs to make sure - * that power save is disabled. When the scan finishes, - * ieee80211_scan_completed() must be called; note that it also must - * be called when the scan cannot finish because the hardware is - * turned off! Anything else is a bug! Returns a negative error code - * which will be seen in userspace. + * that power save is disabled. + * The @req ie/ie_len members are rewritten by mac80211 to contain the + * entire IEs after the SSID, so that drivers need not look at these + * at all but just send them after the SSID -- mac80211 includes the + * (extended) supported rates and HT information (where applicable). + * When the scan finishes, ieee80211_scan_completed() must be called; + * note that it also must be called when the scan cannot finish due to + * any error unless this callback returned a negative error code. * * @sw_scan_start: Notifier function that is called just before a software scan * is started. Can be NULL, if the driver doesn't need this notification. diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 73d9f89..cb80a80 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -671,7 +671,10 @@ struct ieee80211_local { struct cfg80211_scan_request int_scan_req; struct cfg80211_scan_request *scan_req; struct ieee80211_channel *scan_channel; + const u8 *orig_ies; + int orig_ies_len; int scan_channel_idx; + int scan_ies_len; enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; unsigned long last_scan_completed; @@ -1090,9 +1093,11 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, u8 *extra, size_t extra_len, const u8 *bssid, int encrypt); +int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, + const u8 *ie, size_t ie_len); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, - u8 *ssid, size_t ssid_len, - u8 *ie, size_t ie_len); + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len); void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, const size_t supp_rates_len, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ee58a78..b3bbe78 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -729,22 +729,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, wiphy->privid = mac80211_wiphy_privid; - if (!ops->hw_scan) { - /* For hw_scan, driver needs to set these up. */ - wiphy->max_scan_ssids = 4; - - /* we support a maximum of 32 rates in cfg80211 */ - wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN - - 2 - 32 /* SSID */ - - 4 - 32 /* (ext) supp rates */; - - } - /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - sizeof(struct cfg80211_bss); local = wiphy_priv(wiphy); + local->hw.wiphy = wiphy; local->hw.priv = (char *)local + @@ -831,7 +821,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) enum ieee80211_band band; struct net_device *mdev; struct ieee80211_master_priv *mpriv; - int channels, i, j; + int channels, i, j, max_bitrates; /* * generic code guarantees at least one band, @@ -839,18 +829,23 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * that hw.conf.channel is assigned */ channels = 0; + max_bitrates = 0; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; sband = local->hw.wiphy->bands[band]; - if (sband && !local->oper_channel) { + if (!sband) + continue; + if (!local->oper_channel) { /* init channel we're on */ local->hw.conf.channel = local->oper_channel = local->scan_channel = &sband->channels[0]; } - if (sband) - channels += sband->n_channels; + channels += sband->n_channels; + + if (max_bitrates < sband->n_bitrates) + max_bitrates = sband->n_bitrates; } local->int_scan_req.n_channels = channels; @@ -870,6 +865,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + /* + * Calculate scan IE length -- we need this to alloc + * memory and to subtract from the driver limit. It + * includes the (extended) supported rates and HT + * information -- SSID is the driver's responsibility. + */ + local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */ + + if (!local->ops->hw_scan) { + /* For hw_scan, driver needs to set these up. */ + local->hw.wiphy->max_scan_ssids = 4; + local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + } + + /* + * If the driver supports any scan IEs, then assume the + * limit includes the IEs mac80211 will add, otherwise + * leave it at zero and let the driver sort it out; we + * still pass our IEs to the driver but userspace will + * not be allowed to in that case. + */ + if (local->hw.wiphy->max_scan_ie_len) + local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; + result = wiphy_register(local->hw.wiphy); if (result < 0) goto fail_wiphy_register; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 3bf9839..4ec1bfc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -285,6 +285,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (WARN_ON(!local->scan_req)) return; + if (local->hw_scanning) { + kfree(local->scan_req->ie); + local->scan_req->ie = local->orig_ies; + local->scan_req->ie_len = local->orig_ies_len; + } + if (local->scan_req != &local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; @@ -457,12 +463,28 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, } if (local->ops->hw_scan) { - int rc; + u8 *ies; + int rc, ielen; + + ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len + req->ie_len, GFP_KERNEL); + if (!ies) + return -ENOMEM; + + ielen = ieee80211_build_preq_ies(local, ies, + req->ie, req->ie_len); + local->orig_ies = req->ie; + local->orig_ies_len = req->ie_len; + req->ie = ies; + req->ie_len = ielen; local->hw_scanning = true; rc = local->ops->hw_scan(local_to_hw(local), req); if (rc) { local->hw_scanning = false; + kfree(ies); + req->ie_len = local->orig_ies_len; + req->ie = local->orig_ies; return rc; } local->scan_sdata = scan_sdata; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 05caf34..72b0913 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -831,16 +831,57 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, ieee80211_tx_skb(sdata, skb, encrypt); } +int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, + const u8 *ie, size_t ie_len) +{ + struct ieee80211_supported_band *sband; + u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; + int i; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + pos = buffer; + + *pos++ = WLAN_EID_SUPP_RATES; + supp_rates_len = pos; + *pos++ = 0; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + + if (esupp_rates_len) { + *esupp_rates_len += 1; + } else if (*supp_rates_len == 8) { + *pos++ = WLAN_EID_EXT_SUPP_RATES; + esupp_rates_len = pos; + *pos++ = 1; + } else + *supp_rates_len += 1; + + *pos++ = rate->bitrate / 5; + } + + /* + * If adding more here, adjust code in main.c + * that calculates local->scan_ies_len. + */ + + if (ie) { + memcpy(pos, ie, ie_len); + pos += ie_len; + } + + return pos - buffer; +} + void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, - u8 *ssid, size_t ssid_len, - u8 *ie, size_t ie_len) + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len) { struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos, *supp_rates, *esupp_rates = NULL; - int i; + u8 *pos; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + ie_len); @@ -867,33 +908,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, *pos++ = WLAN_EID_SSID; *pos++ = ssid_len; memcpy(pos, ssid, ssid_len); + pos += ssid_len; - supp_rates = skb_put(skb, 2); - supp_rates[0] = WLAN_EID_SUPP_RATES; - supp_rates[1] = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - if (esupp_rates) { - pos = skb_put(skb, 1); - esupp_rates[1]++; - } else if (supp_rates[1] == 8) { - esupp_rates = skb_put(skb, 3); - esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; - esupp_rates[1] = 1; - pos = &esupp_rates[2]; - } else { - pos = skb_put(skb, 1); - supp_rates[1]++; - } - *pos = rate->bitrate / 5; - } - - /* if adding more here, adjust max_scan_ie_len */ - - if (ie) - memcpy(skb_put(skb, ie_len), ie, ie_len); + skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); ieee80211_tx_skb(sdata, skb, 0); } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 447fa17..68c5102 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2597,7 +2597,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_IE]) { request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); - memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), + memcpy((void *)request->ie, + nla_data(info->attrs[NL80211_ATTR_IE]), request->ie_len); } -- cgit v0.10.2 From 5ef2d41afb7fce2315d12a8aaebe0c9f1b50755b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 Mar 2009 12:12:07 +0200 Subject: mac80211: include HT capabilities in probe request Include the HT capabilities in the probe request frame. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b3bbe78..679b3a1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -822,6 +822,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) struct net_device *mdev; struct ieee80211_master_priv *mpriv; int channels, i, j, max_bitrates; + bool supp_ht; /* * generic code guarantees at least one band, @@ -830,6 +831,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) */ channels = 0; max_bitrates = 0; + supp_ht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; @@ -846,6 +848,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; + supp_ht = supp_ht || sband->ht_cap.ht_supported; } local->int_scan_req.n_channels = channels; @@ -872,6 +875,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * information -- SSID is the driver's responsibility. */ local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */ + if (supp_ht) + local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 72b0913..1ff8353 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -861,6 +861,22 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, *pos++ = rate->bitrate / 5; } + if (sband->ht_cap.ht_supported) { + __le16 tmp = cpu_to_le16(sband->ht_cap.cap); + + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_cap); + memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + memcpy(pos, &tmp, sizeof(u16)); + pos += sizeof(u16); + /* TODO: needs a define here for << 2 */ + *pos++ = sband->ht_cap.ampdu_factor | + (sband->ht_cap.ampdu_density << 2); + memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); + pos += sizeof(sband->ht_cap.mcs); + pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ + } + /* * If adding more here, adjust code in main.c * that calculates local->scan_ies_len. -- cgit v0.10.2 From 66174bbea0b9c5bd4b7d060fed26bf5ec912c422 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 1 Apr 2009 17:23:54 +0300 Subject: mac80211: Report rejected association to user space SME When using nl80211 association, we need to send association response with a failure code to user space SME instead of just internally trying to send out the same (re)association request again couple of times. This fixes problems in association process getting stuck on a failure when user space is not notified in any way that something actually failed. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4ce5b9c..90267af 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1374,6 +1374,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * association next time. This works around some broken APs * which do not correctly reject reassociation requests. */ ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); + if (ifmgd->flags & IEEE80211_STA_EXT_SME) { + /* Wait for SME to decide what to do next */ + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + } return; } -- cgit v0.10.2 From 910cfee363feda81cd5af4939ed9e0d27677b43f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 1 Apr 2009 10:42:36 -0500 Subject: b43legacy: Do not select HW_RANDOM Auto-depend on HW_RANDOM, rather than "select"ing it. This way the user has the choice to enable or disable HWRNG support. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index aef2298..d4f628a 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -3,7 +3,6 @@ config B43LEGACY depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA select SSB select FW_LOADER - select HW_RANDOM ---help--- b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the @@ -51,6 +50,13 @@ config B43LEGACY_RFKILL depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) default y +# This config option automatically enables b43 HW-RNG support, +# if the HW-RNG core is enabled. +config B43LEGACY_HWRNG + bool + depends on B43LEGACY && (HW_RANDOM = y || HW_RANDOM = B43LEGACY) + default y + config B43LEGACY_DEBUG bool "Broadcom 43xx-legacy debugging" depends on B43LEGACY diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 97b0e06..4cdde4a 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -596,9 +596,11 @@ struct b43legacy_wl { /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; +#ifdef CONFIG_B43LEGACY_HWRNG struct hwrng rng; u8 rng_initialized; char rng_name[30 + 1]; +#endif /* The RF-kill button */ struct b43legacy_rfkill rfkill; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 879edc7..81dbbc1 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2297,6 +2297,7 @@ static void b43legacy_security_init(struct b43legacy_wldev *dev) dev->max_nr_keys - 8); } +#ifdef CONFIG_B43LEGACY_HWRNG static int b43legacy_rng_read(struct hwrng *rng, u32 *data) { struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv; @@ -2312,17 +2313,21 @@ static int b43legacy_rng_read(struct hwrng *rng, u32 *data) return (sizeof(u16)); } +#endif static void b43legacy_rng_exit(struct b43legacy_wl *wl) { +#ifdef CONFIG_B43LEGACY_HWRNG if (wl->rng_initialized) hwrng_unregister(&wl->rng); +#endif } static int b43legacy_rng_init(struct b43legacy_wl *wl) { - int err; + int err = 0; +#ifdef CONFIG_B43LEGACY_HWRNG snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); wl->rng.name = wl->rng_name; @@ -2336,6 +2341,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) "number generator (%d)\n", err); } +#endif return err; } -- cgit v0.10.2 From 64cdb0e3b8a5e5393cb64328ce0c844b7cf3a40e Mon Sep 17 00:00:00 2001 From: Fabio Rossi Date: Wed, 1 Apr 2009 20:37:50 +0200 Subject: ath5k: fix interpolation with equal power levels When the EEPROM contains weird values for the power levels we have to fix the interpolation process. Signed-off-by: Fabio Rossi Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 9e2faae..b48b29d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1487,28 +1487,35 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, { s8 tmp; s16 min_pwrL, min_pwrR; - s16 pwr_i = pwrL[0]; - - do { - pwr_i--; - tmp = (s8) ath5k_get_interpolated_value(pwr_i, - pwrL[0], pwrL[1], - stepL[0], stepL[1]); - - } while (tmp > 1); - - min_pwrL = pwr_i; - - pwr_i = pwrR[0]; - do { - pwr_i--; - tmp = (s8) ath5k_get_interpolated_value(pwr_i, - pwrR[0], pwrR[1], - stepR[0], stepR[1]); - - } while (tmp > 1); + s16 pwr_i; + + if (pwrL[0] == pwrL[1]) + min_pwrL = pwrL[0]; + else { + pwr_i = pwrL[0]; + do { + pwr_i--; + tmp = (s8) ath5k_get_interpolated_value(pwr_i, + pwrL[0], pwrL[1], + stepL[0], stepL[1]); + } while (tmp > 1); + + min_pwrL = pwr_i; + } - min_pwrR = pwr_i; + if (pwrR[0] == pwrR[1]) + min_pwrR = pwrR[0]; + else { + pwr_i = pwrR[0]; + do { + pwr_i--; + tmp = (s8) ath5k_get_interpolated_value(pwr_i, + pwrR[0], pwrR[1], + stepR[0], stepR[1]); + } while (tmp > 1); + + min_pwrR = pwr_i; + } /* Keep the right boundary so that it works for both curves */ return max(min_pwrL, min_pwrR); -- cgit v0.10.2 From 11397a656f14466421bac503f0f3aaadf9486120 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 1 Apr 2009 14:33:23 -0700 Subject: iwlwifi: adding triple stream rate support for MIMO3 Adding ht triple_stream_basic_rates for MIMO3 supports Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ef55f91..84ac1ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1117,6 +1117,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; + priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff; } EXPORT_SYMBOL(iwl_connection_init_rx_config); -- cgit v0.10.2 From 584a0f00636d34f71a80f5b550a305f1a1620693 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 1 Apr 2009 14:33:24 -0700 Subject: iwlwifi: adding MIMO3 support in rate scaling Separated the MIMO tpt matrix into MIMO2 and MIMO3, adding MIMO3 support in rate scaling algorithm. If the device support 3x3, then utilize all three antenna (A/B/C) for tx to improve throughput. Adding rs_switch_to_mimo3() function to allow switch to mimo3 modulation mode from other modes(legacy/siso/mimo2). Adding rs_move_mimo3_to_other() function to allow switch from mimo3 modulation mode to either siso or mimo2; also support toggle between SGI and NGI. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index cab7842..7cdbcfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -191,7 +191,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits * "G" is the only table that supports CCK (the first 4 rates). */ -/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/ + static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -208,11 +208,11 @@ static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 }; -static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = { 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 }; -static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 }; @@ -224,14 +224,31 @@ static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 }; -static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = { 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 }; -static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 }; +/* Expected throughput metric MIMO3 */ +static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268 +}; + +static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273 +}; + +static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297 +}; + +static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300 +}; + static inline u8 rs_extract_rate(u32 rate_n_flags) { return (u8)(rate_n_flags & 0xFF); @@ -1011,17 +1028,26 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, tbl->expected_tpt = expected_tpt_siso20MHzSGI; else tbl->expected_tpt = expected_tpt_siso20MHz; - - } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */ + } else if (is_mimo2(tbl->lq_type)) { + if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo2_40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo2_20MHz; + } else if (is_mimo3(tbl->lq_type)) { if (tbl->is_fat && !lq_sta->is_dup) if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo40MHzSGI; + tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; else - tbl->expected_tpt = expected_tpt_mimo40MHz; + tbl->expected_tpt = expected_tpt_mimo3_40MHz; else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo20MHzSGI; + tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI; else - tbl->expected_tpt = expected_tpt_mimo20MHz; + tbl->expected_tpt = expected_tpt_mimo3_20MHz; } else tbl->expected_tpt = expected_tpt_G; } @@ -1130,7 +1156,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, } /* - * Set up search table for MIMO + * Set up search table for MIMO2 */ static int rs_switch_to_mimo2(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, @@ -1183,7 +1209,73 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n", + rate, rate_mask); + return -1; + } + tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green); + + IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate, is_green); + return 0; +} + +/* + * Set up search table for MIMO3 + */ +static int rs_switch_to_mimo3(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl, int index) +{ + u16 rate_mask; + s32 rate; + s8 is_green = lq_sta->is_green; + + if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) + return -1; + + if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + == WLAN_HT_CAP_SM_PS_STATIC) + return -1; + + /* Need both Tx chains/antennas to support MIMO */ + if (priv->hw_params.tx_chains_num < 3) + return -1; + + IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n"); + + tbl->lq_type = LQ_MIMO3; + tbl->is_dup = lq_sta->is_dup; + tbl->action = 0; + rate_mask = lq_sta->active_mimo3_rate; + + if (priv->current_ht_config.supported_chan_width + == IWL_CHANNEL_WIDTH_40MHZ) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + /* FIXME: - don't toggle SGI here + if (tbl->is_fat) { + if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + */ + + rs_set_expected_tpt_table(lq_sta, tbl); + + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); + + IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n", + rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n", rate, rate_mask); @@ -1342,9 +1434,29 @@ static int rs_move_legacy_other(struct iwl_priv *priv, goto out; } break; + + case IWL_LEGACY_SWITCH_MIMO3_ABC: + IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n"); + + /* Set up search table to try MIMO3 */ + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + + search_tbl->ant_type = ANT_ABC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) { + lq_sta->action_counter = 0; + goto out; + } + break; } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1357,7 +1469,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; return 0; @@ -1457,9 +1569,23 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, rate_n_flags_from_tbl(priv, search_tbl, index, is_green); goto out; + case IWL_SISO_SWITCH_MIMO3_ABC: + IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + search_tbl->ant_type = ANT_ABC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) + goto out; + break; } tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_GI) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1471,15 +1597,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_GI) + if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC) tbl->action = IWL_SISO_SWITCH_ANTENNA1; return 0; } /* - * Try to switch to new modulation mode from MIMO + * Try to switch to new modulation mode from MIMO2 */ -static int rs_move_mimo_to_other(struct iwl_priv *priv, +static int rs_move_mimo2_to_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, struct ieee80211_sta *sta, int index) @@ -1501,7 +1627,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, switch (tbl->action) { case IWL_MIMO2_SWITCH_ANTENNA1: case IWL_MIMO2_SWITCH_ANTENNA2: - IWL_DEBUG_RATE(priv, "LQ: MIMO toggle Antennas\n"); + IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n"); if (tx_chains_num <= 2) break; @@ -1549,9 +1675,9 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, HT_SHORT_GI_40MHZ)) break; - IWL_DEBUG_RATE(priv, "LQ: MIMO toggle SGI/NGI\n"); + IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n"); - /* Set up new search table for MIMO */ + /* Set up new search table for MIMO2 */ memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = !tbl->is_SGI; rs_set_expected_tpt_table(lq_sta, search_tbl); @@ -1571,9 +1697,24 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, index, is_green); goto out; + case IWL_MIMO2_SWITCH_MIMO3_ABC: + IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + search_tbl->ant_type = ANT_ABC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) + goto out; + + break; } tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_GI) + if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1584,13 +1725,150 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_GI) + if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; return 0; } /* + * Try to switch to new modulation mode from MIMO3 + */ +static int rs_move_mimo3_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + 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 tx_chains_num = priv->hw_params.tx_chains_num; + int ret; + + for (;;) { + lq_sta->action_counter++; + switch (tbl->action) { + case IWL_MIMO3_SWITCH_ANTENNA1: + case IWL_MIMO3_SWITCH_ANTENNA2: + IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n"); + + if (tx_chains_num <= 3) + 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_MIMO3_SWITCH_SISO_A: + case IWL_MIMO3_SWITCH_SISO_B: + case IWL_MIMO3_SWITCH_SISO_C: + IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n"); + + /* Set up new search table for SISO */ + memcpy(search_tbl, tbl, sz); + + if (tbl->action == IWL_MIMO3_SWITCH_SISO_A) + search_tbl->ant_type = ANT_A; + else if (tbl->action == IWL_MIMO3_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) + goto out; + + break; + + case IWL_MIMO3_SWITCH_MIMO2_AB: + case IWL_MIMO3_SWITCH_MIMO2_AC: + case IWL_MIMO3_SWITCH_MIMO2_BC: + IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n"); + + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB) + search_tbl->ant_type = ANT_AB; + else if (tbl->action == IWL_MIMO3_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) + goto out; + + break; + + case IWL_MIMO3_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + + IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n"); + + /* Set up new search table for MIMO */ + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = !tbl->is_SGI; + rs_set_expected_tpt_table(lq_sta, search_tbl); + /* + * If active table already uses the fastest possible + * modulation (dual stream with short guard interval), + * and it's working well, there's no need to look + * for a better type of modulation! + */ + if (tbl->is_SGI) { + s32 tpt = lq_sta->last_tpt / 100; + if (tpt >= search_tbl->expected_tpt[index]) + break; + } + search_tbl->current_rate = + rate_n_flags_from_tbl(priv, search_tbl, + index, is_green); + goto out; + } + tbl->action++; + if (tbl->action > IWL_MIMO3_SWITCH_GI) + tbl->action = IWL_MIMO3_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_MIMO3_SWITCH_GI) + tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; + return 0; + +} + +/* * Check whether we should continue using same modulation mode, or * begin search for a new mode, based on: * 1) # tx successes or failures while using this mode @@ -1997,8 +2275,10 @@ lq_update: rs_move_legacy_other(priv, lq_sta, conf, sta, index); else if (is_siso(tbl->lq_type)) rs_move_siso_to_other(priv, lq_sta, conf, sta, index); + else if (is_mimo2(tbl->lq_type)) + rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index); else - rs_move_mimo_to_other(priv, lq_sta, conf, sta, index); + rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index); /* If new "search" mode was selected, set up in uCode table */ if (lq_sta->search_better_tbl) { @@ -2362,6 +2642,9 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, } else if (num_of_ant(tbl_type.ant_type) == 2) { lq_cmd->general_params.dual_stream_ant_msk = tbl_type.ant_type; + } else if (num_of_ant(tbl_type.ant_type) == 3) { + lq_cmd->general_params.dual_stream_ant_msk = + tbl_type.ant_type; } /* otherwise we don't modify the existing value */ index++; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index ab59acc..9cd90ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -241,6 +241,7 @@ enum { #define IWL_LEGACY_SWITCH_MIMO2_AB 3 #define IWL_LEGACY_SWITCH_MIMO2_AC 4 #define IWL_LEGACY_SWITCH_MIMO2_BC 5 +#define IWL_LEGACY_SWITCH_MIMO3_ABC 6 /* possible actions when in siso mode */ #define IWL_SISO_SWITCH_ANTENNA1 0 @@ -249,6 +250,8 @@ enum { #define IWL_SISO_SWITCH_MIMO2_AC 3 #define IWL_SISO_SWITCH_MIMO2_BC 4 #define IWL_SISO_SWITCH_GI 5 +#define IWL_SISO_SWITCH_MIMO3_ABC 6 + /* possible actions when in mimo mode */ #define IWL_MIMO2_SWITCH_ANTENNA1 0 @@ -257,6 +260,21 @@ enum { #define IWL_MIMO2_SWITCH_SISO_B 3 #define IWL_MIMO2_SWITCH_SISO_C 4 #define IWL_MIMO2_SWITCH_GI 5 +#define IWL_MIMO2_SWITCH_MIMO3_ABC 6 + + +/* possible actions when in mimo3 mode */ +#define IWL_MIMO3_SWITCH_ANTENNA1 0 +#define IWL_MIMO3_SWITCH_ANTENNA2 1 +#define IWL_MIMO3_SWITCH_SISO_A 2 +#define IWL_MIMO3_SWITCH_SISO_B 3 +#define IWL_MIMO3_SWITCH_SISO_C 4 +#define IWL_MIMO3_SWITCH_MIMO2_AB 5 +#define IWL_MIMO3_SWITCH_MIMO2_AC 6 +#define IWL_MIMO3_SWITCH_MIMO2_BC 7 +#define IWL_MIMO3_SWITCH_GI 8 + + /*FIXME:RS:add possible actions for MIMO3*/ -- cgit v0.10.2 From 3eb9296970e70902593b15ed3080e389954cf5f5 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 1 Apr 2009 14:33:25 -0700 Subject: iwlwifi: add debug messages when start aggregation queue This patch adding few more debug messages if encounter error when driver try to start tx aggregation queue. Also change from IWL_ERR to IWL_DEBUG_HT is the HW legacy queue is empty when driver request to move to aggregation queue. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 1f117a4..c734c5f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1170,8 +1170,10 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) __func__, ra, tid); sta_id = iwl_find_station(priv, ra); - if (sta_id == IWL_INVALID_STATION) + if (sta_id == IWL_INVALID_STATION) { + IWL_ERR(priv, "Start AGG on invalid station\n"); return -ENXIO; + } if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n"); @@ -1179,8 +1181,10 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) } txq_id = iwl_txq_ctx_activate_free(priv); - if (txq_id == -1) + if (txq_id == -1) { + IWL_ERR(priv, "No free aggregation queue available\n"); return -ENXIO; + } spin_lock_irqsave(&priv->sta_lock, flags); tid_data = &priv->stations[sta_id].tid[tid]; @@ -1194,7 +1198,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) return ret; if (tid_data->tfds_in_queue == 0) { - IWL_ERR(priv, "HW queue is empty\n"); + IWL_DEBUG_HT(priv, "HW queue is empty\n"); tid_data->agg.state = IWL_AGG_ON; ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); } else { -- cgit v0.10.2 From a4ed90d60c39c5aef9a170d7693f61175acb22e0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 2 Apr 2009 14:08:07 -0400 Subject: cfg80211: respect API on orig_flags on channel for beacon hint As part of our documented API we always respect the orig_flag settings on a channel. We forgot to follow this for the beacon hints. Acked-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6c1993d..4af4304 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1070,12 +1070,14 @@ static void handle_reg_beacon(struct wiphy *wiphy, if (likely(chan->center_freq != reg_beacon->chan.center_freq)) return; - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { + if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) && + !(chan->orig_flags & IEEE80211_CHAN_PASSIVE_SCAN)) { chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; REG_DEBUG_BEACON_FLAG("active scanning"); } - if (chan->flags & IEEE80211_CHAN_NO_IBSS) { + if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && + !(chan->orig_flags & IEEE80211_CHAN_NO_IBSS)) { chan->flags &= ~IEEE80211_CHAN_NO_IBSS; REG_DEBUG_BEACON_FLAG("beaconing"); } -- cgit v0.10.2 From 5dab3b8a68cc97a7e6b9f79f5de05803c8e55a3c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 2 Apr 2009 14:08:08 -0400 Subject: cfg80211: add netlink channel put helper This adds a netlink channel put helper, nl80211_msg_put_channel(), which we will also make use of later for the beacon hints events. Acked-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 68c5102..7285bdc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -156,6 +156,30 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); } +static int nl80211_msg_put_channel(struct sk_buff *msg, + struct ieee80211_channel *chan) +{ + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, + chan->center_freq); + + if (chan->flags & IEEE80211_CHAN_DISABLED) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); + if (chan->flags & IEEE80211_CHAN_RADAR) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, + DBM_TO_MBM(chan->max_power)); + + return 0; + + nla_put_failure: + return -ENOBUFS; +} + /* netlink command implementations */ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, @@ -234,20 +258,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, goto nla_put_failure; chan = &dev->wiphy.bands[band]->channels[i]; - NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, - chan->center_freq); - - if (chan->flags & IEEE80211_CHAN_DISABLED) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); - if (chan->flags & IEEE80211_CHAN_NO_IBSS) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); - if (chan->flags & IEEE80211_CHAN_RADAR) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); - - NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, - DBM_TO_MBM(chan->max_power)); + + if (nl80211_msg_put_channel(msg, chan)) + goto nla_put_failure; nla_nest_end(msg, nl_freq); } -- cgit v0.10.2 From 6bad8766620a3c8b64afa981502fdb543e3cfd6c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 2 Apr 2009 14:08:09 -0400 Subject: cfg80211: send regulatory beacon hint events to userspace This informs userspace when a change has occured on a world roaming wiphy's channel which has lifted some restrictions due to a regulatory beacon hint. Because this is now sent to userspace through the regulatory multicast group we remove the debug prints we used to use as they are no longer necessary. Acked-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 209cace..05ba353 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -7,7 +7,7 @@ * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch - * Copyright 2008 Luis R. Rodriguez + * Copyright 2008, 2009 Luis R. Rodriguez * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * @@ -166,6 +166,22 @@ * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on * to (%NL80211_ATTR_REG_ALPHA2). + * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon + * has been found while world roaming thus enabling active scan or + * any mode of operation that initiates TX (beacons) on a channel + * where we would not have been able to do either before. As an example + * if you are world roaming (regulatory domain set to world or if your + * driver is using a custom world roaming regulatory domain) and while + * doing a passive scan on the 5 GHz band you find an AP there (if not + * on a DFS channel) you will now be able to actively scan for that AP + * or use AP mode on your card on that same channel. Note that this will + * never be used for channels 1-11 on the 2 GHz band as they are always + * enabled world wide. This beacon hint is only sent if your device had + * either disabled active scanning or beaconing on a channel. We send to + * userspace the wiphy on which we removed a restriction from + * (%NL80211_ATTR_WIPHY) and the channel on which this occurred + * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER) + * the beacon hint was processed. * * @NL80211_CMD_AUTHENTICATE: authentication request and notification. * This command is used both as a command (request to authenticate) and @@ -270,6 +286,8 @@ enum nl80211_commands { NL80211_CMD_MICHAEL_MIC_FAILURE, + NL80211_CMD_REG_BEACON_HINT, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -288,6 +306,7 @@ enum nl80211_commands { #define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE #define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE +#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT /** * enum nl80211_attrs - nl80211 netlink attributes @@ -423,6 +442,17 @@ enum nl80211_commands { * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as * a u32 * + * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change + * due to considerations from a beacon hint. This attribute reflects + * the state of the channel _before_ the beacon hint processing. This + * attributes consists of a nested attribute containing + * NL80211_FREQUENCY_ATTR_* + * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change + * due to considerations from a beacon hint. This attribute reflects + * the state of the channel _after_ the beacon hint processing. This + * attributes consists of a nested attribute containing + * NL80211_FREQUENCY_ATTR_* + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -511,6 +541,8 @@ enum nl80211_attrs { NL80211_ATTR_MAX_SCAN_IE_LEN, + NL80211_ATTR_FREQ_BEFORE, + NL80211_ATTR_FREQ_AFTER, /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7285bdc..85b5aa3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3491,6 +3491,60 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, nlmsg_free(msg); } +void nl80211_send_beacon_hint_event(struct wiphy *wiphy, + struct ieee80211_channel *channel_before, + struct ieee80211_channel *channel_after) +{ + struct sk_buff *msg; + void *hdr; + struct nlattr *nl_freq; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + /* + * Since we are applying the beacon hint to a wiphy we know its + * wiphy_idx is valid + */ + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); + + /* Before */ + nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); + if (!nl_freq) + goto nla_put_failure; + if (nl80211_msg_put_channel(msg, channel_before)) + goto nla_put_failure; + nla_nest_end(msg, nl_freq); + + /* After */ + nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); + if (!nl_freq) + goto nla_put_failure; + if (nl80211_msg_put_channel(msg, channel_after)) + goto nla_put_failure; + nla_nest_end(msg, nl_freq); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); + + return; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + /* initialisation/exit functions */ int nl80211_init(void) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index e4b92cc..b3aaa59 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -29,4 +29,9 @@ nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, enum nl80211_key_type key_type, int key_id, const u8 *tsc); +extern void +nl80211_send_beacon_hint_event(struct wiphy *wiphy, + struct ieee80211_channel *channel_before, + struct ieee80211_channel *channel_after); + #endif /* __NET_WIRELESS_NL80211_H */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4af4304..574e217 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1049,18 +1049,10 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, struct reg_beacon *reg_beacon) { -#ifdef CONFIG_CFG80211_REG_DEBUG -#define REG_DEBUG_BEACON_FLAG(desc) \ - printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \ - "frequency: %d MHz (Ch %d) on %s\n", \ - reg_beacon->chan.center_freq, \ - ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \ - wiphy_name(wiphy)); -#else -#define REG_DEBUG_BEACON_FLAG(desc) do {} while (0) -#endif struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; + bool channel_changed = false; + struct ieee80211_channel chan_before; assert_cfg80211_lock(); @@ -1070,20 +1062,28 @@ static void handle_reg_beacon(struct wiphy *wiphy, if (likely(chan->center_freq != reg_beacon->chan.center_freq)) return; + if (chan->beacon_found) + return; + + chan->beacon_found = true; + + chan_before.center_freq = chan->center_freq; + chan_before.flags = chan->flags; + if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) && !(chan->orig_flags & IEEE80211_CHAN_PASSIVE_SCAN)) { chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - REG_DEBUG_BEACON_FLAG("active scanning"); + channel_changed = true; } if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && !(chan->orig_flags & IEEE80211_CHAN_NO_IBSS)) { chan->flags &= ~IEEE80211_CHAN_NO_IBSS; - REG_DEBUG_BEACON_FLAG("beaconing"); + channel_changed = true; } - chan->beacon_found = true; -#undef REG_DEBUG_BEACON_FLAG + if (channel_changed) + nl80211_send_beacon_hint_event(wiphy, &chan_before, chan); } /* -- cgit v0.10.2 From 25e47c18ac4d8ad09c2ed4b99c1dbbcb7e3d2c51 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Apr 2009 20:14:06 +0200 Subject: cfg80211: add cipher capabilities This adds the necessary code and fields to let drivers specify their cipher capabilities and exports them to userspace. Also update mac80211 to export the ciphers it has. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 05ba353..c014238 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -453,6 +453,9 @@ enum nl80211_commands { * attributes consists of a nested attribute containing * NL80211_FREQUENCY_ATTR_* * + * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported + * cipher suites + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -540,6 +543,7 @@ enum nl80211_attrs { NL80211_ATTR_KEY_TYPE, NL80211_ATTR_MAX_SCAN_IE_LEN, + NL80211_ATTR_CIPHER_SUITES, NL80211_ATTR_FREQ_BEFORE, NL80211_ATTR_FREQ_AFTER, diff --git a/include/net/wireless.h b/include/net/wireless.h index 2bcdeda..44c2642 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -205,6 +205,8 @@ struct ieee80211_supported_band { * on the reg_notifier() if it chooses to ignore future * regulatory domain changes caused by other drivers. * @signal_type: signal type reported in &struct cfg80211_bss. + * @cipher_suites: supported cipher suites + * @n_cipher_suites: number of supported cipher suites */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -224,6 +226,9 @@ struct wiphy { u8 max_scan_ssids; u16 max_scan_ie_len; + int n_cipher_suites; + const u32 *cipher_suites; + /* If multiple wiphys are registered and you're handed e.g. * a regular netdev with assigned ieee80211_ptr, you won't * know whether it points to a wiphy your driver has registered diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 679b3a1..c1145be 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -823,6 +823,15 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) struct ieee80211_master_priv *mpriv; int channels, i, j, max_bitrates; bool supp_ht; + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + + /* keep last -- depends on hw flags! */ + WLAN_CIPHER_SUITE_AES_CMAC + }; /* * generic code guarantees at least one band, @@ -894,6 +903,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (local->hw.wiphy->max_scan_ie_len) local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; + local->hw.wiphy->cipher_suites = cipher_suites; + local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) + local->hw.wiphy->n_cipher_suites--; + result = wiphy_register(local->hw.wiphy); if (result < 0) goto fail_wiphy_register; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 85b5aa3..d33cab0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -208,6 +208,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, dev->wiphy.max_scan_ie_len); + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, + sizeof(u32) * dev->wiphy.n_cipher_suites, + dev->wiphy.cipher_suites); + nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); if (!nl_modes) goto nla_put_failure; @@ -979,7 +983,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; - int err; + int err, i; struct net_device *dev; struct key_params params; u8 key_idx = 0; @@ -1048,6 +1052,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; + for (i = 0; i < drv->wiphy.n_cipher_suites; i++) + if (params.cipher == drv->wiphy.cipher_suites[i]) + break; + if (i == drv->wiphy.n_cipher_suites) { + err = -EINVAL; + goto out; + } + if (!drv->ops->add_key) { err = -EOPNOTSUPP; goto out; -- cgit v0.10.2 From b26ed97c75e1538176c09f29c423a3f8a75868a7 Mon Sep 17 00:00:00 2001 From: Anna Neal Date: Thu, 2 Apr 2009 14:44:09 -0700 Subject: libertas: increase spi driver thread priority Currently, the libertas main thread contends with the spi driver thread in the TX path. To improve throughput, ensure that the driver thread has higher scheduling priority than the libertas main thread. Do this by making the libertas spi driver thread a low priority real time thread. We measured an average throughput improvement of 13%. Signed-off-by: Anna Neal Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 07311e7..97493e2f 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -1020,6 +1020,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) struct libertas_spi_platform_data *pdata = spi->dev.platform_data; int err = 0; u32 scratch; + struct sched_param param = { .sched_priority = 1 }; lbs_deb_enter(LBS_DEB_SPI); @@ -1123,6 +1124,9 @@ static int __devinit if_spi_probe(struct spi_device *spi) lbs_pr_err("error creating SPI thread: err=%d\n", err); goto remove_card; } + if (sched_setscheduler(card->spi_thread, SCHED_FIFO, ¶m)) + lbs_pr_err("Error setting scheduler, using default.\n"); + err = request_irq(spi->irq, if_spi_host_interrupt, IRQF_TRIGGER_FALLING, "libertas_spi", card); if (err) { -- cgit v0.10.2 From 6a362bb1c9f900f7e6daeee52ff2d538badae49b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sun, 5 Apr 2009 11:01:20 -0400 Subject: ath5k: add support for Fukato Datacask Jupiter LEDs This adds support for the LEDs on the Jupiter netbook. Reported-by: Martin Bammer Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 006f771..cbdc0b3 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -67,6 +67,8 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) }, /* Acer Extensa 5620z (nekoreeve@gmail.com) */ { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) }, + /* Fukato Datacask Jupiter 1014a (mrb74@gmx.at) */ + { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) }, { } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ee98cd5..ea061e2 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2313,6 +2313,8 @@ #define PCI_VENDOR_ID_QMI 0x1a32 +#define PCI_VENDOR_ID_AZWAVE 0x1a3b + #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 -- cgit v0.10.2 From 87cbfd06889256cac945b37c7f62f4ce7f44b34a Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 6 Apr 2009 01:03:09 +0400 Subject: p54spi: get rid of busy-wait loops p54spi_wakeup and p54spi_tx_frame used busy-waiting loop to poll for 'ready' bits in SPI_ADRS_HOST_INTERRUPTS register. With this change in place 'WR_READY timeout' messages do not show anymore. Signed-off-by: Max Filippov Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 52023127..59a5e77 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -167,14 +167,13 @@ static const struct p54spi_spi_reg p54spi_registers_array[] = static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) { int i; - __le32 buffer; for (i = 0; i < 2000; i++) { - p54spi_spi_read(priv, reg, &buffer, sizeof(buffer)); + __le32 buffer = p54spi_read32(priv, reg); if ((buffer & bits) == bits) return 1; - msleep(1); + msleep(0); } return 0; } @@ -185,10 +184,10 @@ static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); - if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le32(HOST_ALLOWED)) == 0) { + if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le32(HOST_ALLOWED))) { dev_err(&priv->spi->dev, "spi_write_dma not allowed " - "to DMA write."); + "to DMA write.\n"); return -EAGAIN; } @@ -330,21 +329,15 @@ static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val) static void p54spi_wakeup(struct p54s_priv *priv) { - unsigned long timeout; - u32 ints; - /* wake the chip */ p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, cpu_to_le32(SPI_TARGET_INT_WAKEUP)); /* And wait for the READY interrupt */ - timeout = jiffies + HZ; - - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - while (!(ints & SPI_HOST_INT_READY)) { - if (time_after(jiffies, timeout)) - goto out; - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); + if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, + cpu_to_le32(SPI_HOST_INT_READY))) { + dev_err(&priv->spi->dev, "INT_READY timeout\n"); + goto out; } p54spi_int_ack(priv, SPI_HOST_INT_READY); @@ -432,9 +425,7 @@ static irqreturn_t p54spi_interrupt(int irq, void *config) static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) { struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - unsigned long timeout; int ret = 0; - u32 ints; p54spi_wakeup(priv); @@ -442,15 +433,11 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) if (ret < 0) goto out; - timeout = jiffies + 2 * HZ; - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - while (!(ints & SPI_HOST_INT_WR_READY)) { - if (time_after(jiffies, timeout)) { - dev_err(&priv->spi->dev, "WR_READY timeout\n"); - ret = -1; - goto out; - } - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); + if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, + cpu_to_le32(SPI_HOST_INT_WR_READY))) { + dev_err(&priv->spi->dev, "WR_READY timeout\n"); + ret = -1; + goto out; } p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); -- cgit v0.10.2 From e45d8e534b67580eedd9b4910ccc16d6dd3cceff Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 6 Apr 2009 15:50:56 -0700 Subject: libertas: add support for Marvell SD8688 chip libertas: add support for Marvell SD8688 chip Use RxPD->pkt_ptr to locate eth803 header in the packet received since SD8688/v10 firmware allows a gap between RxPD and eth803 header. Set SDIO block size to 256 for CMD53. The maximum block size for SD8688 WLAN function is set to 512 in TPLFE_MAX_BLK_SIZE. But using 512 as block size results upto 2K bytes data (4 blocks) being transferred and causes buffer overflow in firmware. Both changes above are backward compatible with earlier firmware versions for SD8385/SD8686. The SDIO_DEVICE_IDs for SD8688 chip are added in include/linux/mmc/sdio_ids.h Signed-off-by: Kiran Divekar Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8f279e7..ad99470 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -146,10 +146,10 @@ config LIBERTAS_CS A driver for Marvell Libertas 8385 CompactFlash devices. config LIBERTAS_SDIO - tristate "Marvell Libertas 8385 and 8686 SDIO 802.11b/g cards" + tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" depends on LIBERTAS && MMC ---help--- - A driver for Marvell Libertas 8385 and 8686 SDIO devices. + A driver for Marvell Libertas 8385/8686/8688 SDIO devices. config LIBERTAS_SPI tristate "Marvell Libertas 8686 SPI 802.11b/g cards" diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 76f4c65..55864c1 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -48,8 +48,11 @@ static char *lbs_fw_name = NULL; module_param_named(fw_name, lbs_fw_name, charp, 0644); static const struct sdio_device_id if_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, - { /* end: all zeroes */ }, + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, + SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, + SDIO_DEVICE_ID_MARVELL_8688WLAN) }, + { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, if_sdio_ids); @@ -73,6 +76,12 @@ static struct if_sdio_model if_sdio_models[] = { .helper = "sd8686_helper.bin", .firmware = "sd8686.bin", }, + { + /* 8688 */ + .model = 0x10, + .helper = "sd8688_helper.bin", + .firmware = "sd8688.bin", + }, }; struct if_sdio_packet { @@ -488,7 +497,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card) ret = 0; release: - sdio_set_block_size(card->func, 0); + sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); sdio_release_host(card->func); kfree(chunk_buffer); release_fw: @@ -624,7 +633,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card) ret = 0; release: - sdio_set_block_size(card->func, 0); + sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); sdio_release_host(card->func); kfree(chunk_buffer); release_fw: diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index 533bdfb..37ada2c 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h @@ -42,4 +42,6 @@ #define IF_SDIO_EVENT 0x80fc +#define IF_SDIO_BLOCK_SIZE 256 + #endif diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 820c22d..bd845d0 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -25,7 +25,6 @@ struct rfc1042hdr { } __attribute__ ((packed)); struct rxpackethdr { - struct rxpd rx_pd; struct eth803hdr eth803_hdr; struct rfc1042hdr rfc1042_hdr; } __attribute__ ((packed)); @@ -158,8 +157,9 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) if (priv->monitormode) return process_rxed_802_11_packet(priv, skb); - p_rx_pkt = (struct rxpackethdr *) skb->data; - p_rx_pd = &p_rx_pkt->rx_pd; + p_rx_pd = (struct rxpd *) skb->data; + p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd + + le32_to_cpu(p_rx_pd->pkt_ptr)); if (priv->mesh_dev) { if (priv->mesh_fw_ver == MESH_FW_OLD) { if (p_rx_pd->rx_control & RxPD_MESH_FRAME) @@ -181,8 +181,9 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) goto done; } - lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", - skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); + lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n", + skb->len, le32_to_cpu(p_rx_pd->pkt_ptr), + skb->len - le32_to_cpu(p_rx_pd->pkt_ptr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); @@ -216,14 +217,14 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header * that was removed */ - hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; + hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd; } else { lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); /* Chop off the rxpd */ - hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt; + hdrchop = (u8 *)&p_rx_pkt->eth803_hdr - (u8 *)p_rx_pd; } /* Chop off the leading header bytes so the skb points to the start of diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index ea1bf5b..c7211ab 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -25,5 +25,7 @@ #define SDIO_VENDOR_ID_MARVELL 0x02df #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 +#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104 +#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 #endif -- cgit v0.10.2 From 4499b23933b44bf9e56d1a29b51d9a62941f9fa4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 8 Apr 2009 02:55:34 +0200 Subject: mac80211: re-upload keys only after telling driver about association In the normal WPA or RSN case keys are only configured after associating, so we should do that in that order when resuming as well. It shouldn't really matter since we do not send any data at either point, but iwlwifi prefers it this way and it does seem more natural. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 0273023..2b4c95c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -127,11 +127,6 @@ int __ieee80211_resume(struct ieee80211_hw *hw) rcu_read_unlock(); - /* add back keys */ - list_for_each_entry(sdata, &local->interfaces, list) - if (netif_running(sdata->dev)) - ieee80211_enable_keys(sdata); - /* setup RTS threshold */ if (local->ops->set_rts_threshold) local->ops->set_rts_threshold(hw, local->rts_threshold); @@ -172,6 +167,11 @@ int __ieee80211_resume(struct ieee80211_hw *hw) } } + /* add back keys */ + list_for_each_entry(sdata, &local->interfaces, list) + if (netif_running(sdata->dev)) + ieee80211_enable_keys(sdata); + ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); -- cgit v0.10.2 From de2b3e864aa908e613dd9912def88af7877d85f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 8 Apr 2009 12:54:41 +0200 Subject: mac80211: update injection documentation We don't currently support antenna or rate setting, so remove that. Also update the link -- the current one is dead and the wiki can be kept updated easier. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt index 84906ef..b30e81a 100644 --- a/Documentation/networking/mac80211-injection.txt +++ b/Documentation/networking/mac80211-injection.txt @@ -12,38 +12,22 @@ following format: The radiotap format is discussed in ./Documentation/networking/radiotap-headers.txt. -Despite 13 radiotap argument types are currently defined, most only make sense +Despite many radiotap parameters being currently defined, most only make sense to appear on received packets. The following information is parsed from the radiotap headers and used to control injection: - * IEEE80211_RADIOTAP_RATE - - rate in 500kbps units, automatic if invalid or not present - - - * IEEE80211_RADIOTAP_ANTENNA - - antenna to use, automatic if not present - - - * IEEE80211_RADIOTAP_DBM_TX_POWER - - transmit power in dBm, automatic if not present - - * IEEE80211_RADIOTAP_FLAGS IEEE80211_RADIOTAP_F_FCS: FCS will be removed and recalculated IEEE80211_RADIOTAP_F_WEP: frame will be encrypted if key available IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the - current fragmentation threshold. Note that - this flag is only reliable when software - fragmentation is enabled) + current fragmentation threshold. + The injection code can also skip all other currently defined radiotap fields facilitating replay of captured radiotap headers directly. -Here is an example valid radiotap header defining these three parameters +Here is an example valid radiotap header defining some parameters 0x00, 0x00, // <-- radiotap version 0x0b, 0x00, // <- radiotap header length @@ -72,8 +56,8 @@ interface), along the following lines: ... r = pcap_inject(ppcap, u8aSendBuffer, nLength); -You can also find sources for a complete inject test applet here: +You can also find a link to a complete inject application here: -http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer +http://wireless.kernel.org/en/users/Documentation/packetspammer Andy Green -- cgit v0.10.2 From 5bbe233b9bafabc08a5404d54b9fa086e8390fc7 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:35 -0700 Subject: iwl3945: use iwl_bss_info_changed 3945 can use iwl_bss_info_changed. A new lib op is created for post_assoicate to distinguish between 3945 and iwlwifi's post_associate operations. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 2399328..519e892 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1964,6 +1964,50 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) return 0; } +static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res = NULL; + struct iwl3945_rxon_assoc_cmd rxon_assoc; + struct iwl_host_cmd cmd = { + .id = REPLY_RXON_ASSOC, + .len = sizeof(rxon_assoc), + .meta.flags = CMD_WANT_SKB, + .data = &rxon_assoc, + }; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = priv->staging_rxon.flags; + rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; + rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; + rxon_assoc.reserved = 0; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); + rc = -EIO; + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + /* will add 3945 channel switch cmd handling later */ int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel) { @@ -2729,6 +2773,10 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) return 0; } +static struct iwl_hcmd_ops iwl3945_hcmd = { + .rxon_assoc = iwl3945_send_rxon_assoc, +}; + static struct iwl_lib_ops iwl3945_lib = { .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl3945_hw_txq_free_tfd, @@ -2758,6 +2806,7 @@ static struct iwl_lib_ops iwl3945_lib = { }, .send_tx_power = iwl3945_send_tx_power, .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, + .post_associate = iwl3945_post_associate, }; static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { @@ -2767,6 +2816,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { static struct iwl_ops iwl3945_ops = { .lib = &iwl3945_lib, + .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 29bc0d2..13b191f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -276,7 +276,7 @@ extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); extern void iwl3945_disable_events(struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv); - +extern void iwl3945_post_associate(struct iwl_priv *priv); /** * iwl3945_hw_find_station - Find station id for a given BSSID * @bssid: MAC address of station ID to find diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 847a622..37544af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2324,6 +2324,7 @@ static struct iwl_lib_ops iwl4965_lib = { .send_tx_power = iwl4965_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .temperature = iwl4965_temperature_calib, + .post_associate = iwl_post_associate, }; static struct iwl_ops iwl4965_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e5ca251..837dbad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1527,6 +1527,7 @@ struct iwl_lib_ops iwl5000_lib = { .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, }, + .post_associate = iwl_post_associate, }; struct iwl_ops iwl5000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1f5ee55..d14146f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -531,76 +531,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, * ******************************************************************************/ -static void iwl_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) -{ - struct ieee80211_sta_ht_cap *ht_conf; - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; - struct ieee80211_sta *sta; - - IWL_DEBUG_MAC80211(priv, "enter: \n"); - - if (!iwl_conf->is_ht) - return; - - - /* - * It is totally wrong to base global information on something - * that is valid only when associated, alas, this driver works - * that way and I don't know how to fix it. - */ - - rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, priv->bssid); - if (!sta) { - rcu_read_unlock(); - return; - } - ht_conf = &sta->ht_cap; - - 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) - iwl_conf->sgf |= HT_SHORT_GI_40MHZ; - - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); - - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - - /* - * XXX: The HT configuration needs to be moved into iwl_mac_config() - * to be done there correctly. - */ - - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - if (conf_is_ht40_minus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - else if (conf_is_ht40_plus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - - /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) - iwl_conf->supported_chan_width = 0; - - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - - memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - - iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; - iwl_conf->ht_protection = - bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; - iwl_conf->non_GF_STA_present = - !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - - rcu_read_unlock(); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - #define MAX_UCODE_BEACON_INTERVAL 4096 static u16 iwl_adjust_beacon_interval(u16 beacon_val) @@ -1911,7 +1841,7 @@ static void iwl_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl_post_associate(struct iwl_priv *priv) +void iwl_post_associate(struct iwl_priv *priv) { struct ieee80211_conf *conf = NULL; int ret = 0; @@ -2482,70 +2412,6 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw, } -#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -static void iwl_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - - if (changes & BSS_CHANGED_ERP_PREAMBLE) { - IWL_DEBUG_MAC80211(priv, "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(priv, "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_HT) { - iwl_ht_conf(priv, bss_conf); - iwl_set_rxon_chain(priv); - } - - if (changes & BSS_CHANGED_ASSOC) { - IWL_DEBUG_MAC80211(priv, "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->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); - iwl_post_associate(priv); - mutex_unlock(&priv->mutex); - } else { - priv->assoc_id = 0; - IWL_DEBUG_MAC80211(priv, "DISASSOC %d\n", bss_conf->assoc); - } - } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { - IWL_DEBUG_MAC80211(priv, "Associated Changes %d\n", changes); - iwl_send_rxon_assoc(priv); - } - -} - static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) @@ -2825,7 +2691,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) iwl_reset_qos(priv); - iwl_post_associate(priv); + priv->cfg->ops->lib->post_associate(priv); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 84ac1ce..1569182 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2157,6 +2157,142 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } EXPORT_SYMBOL(iwl_mac_conf_tx); + +static void iwl_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_sta_ht_cap *ht_conf; + struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct ieee80211_sta *sta; + + IWL_DEBUG_MAC80211(priv, "enter: \n"); + + if (!iwl_conf->is_ht) + return; + + + /* + * It is totally wrong to base global information on something + * that is valid only when associated, alas, this driver works + * that way and I don't know how to fix it. + */ + + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, priv->bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + ht_conf = &sta->ht_cap; + + 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) + iwl_conf->sgf |= HT_SHORT_GI_40MHZ; + + iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); + iwl_conf->max_amsdu_size = + !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); + + iwl_conf->supported_chan_width = + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); + + /* + * XXX: The HT configuration needs to be moved into iwl_mac_config() + * to be done there correctly. + */ + + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + if (conf_is_ht40_minus(&priv->hw->conf)) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; + else if (conf_is_ht40_plus(&priv->hw->conf)) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + + /* If no above or below channel supplied disable FAT channel */ + if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && + iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) + iwl_conf->supported_chan_width = 0; + + iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); + + memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); + + iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; + iwl_conf->ht_protection = + bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; + iwl_conf->non_GF_STA_present = + !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + + rcu_read_unlock(); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) +void iwl_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + IWL_DEBUG_MAC80211(priv, "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(priv, "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_HT) { + iwl_ht_conf(priv, bss_conf); + iwl_set_rxon_chain(priv); + } + + if (changes & BSS_CHANGED_ASSOC) { + IWL_DEBUG_MAC80211(priv, "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->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); + priv->cfg->ops->lib->post_associate(priv); + mutex_unlock(&priv->mutex); + } else { + priv->assoc_id = 0; + IWL_DEBUG_MAC80211(priv, "DISASSOC %d\n", bss_conf->assoc); + } + } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { + IWL_DEBUG_MAC80211(priv, "Associated Changes %d\n", changes); + iwl_send_rxon_assoc(priv); + } + +} +EXPORT_SYMBOL(iwl_bss_info_changed); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d56edcd..4ad8465 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -149,6 +149,8 @@ struct iwl_lib_ops { int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); void (*temperature) (struct iwl_priv *priv); + void (*post_associate) (struct iwl_priv *priv); + /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; }; @@ -251,6 +253,11 @@ int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); +void iwl_post_associate(struct iwl_priv *priv); +void iwl_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ed31030..6f44abc 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -233,50 +233,6 @@ u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flag } -static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) -{ - int rc = 0; - struct iwl_rx_packet *res = NULL; - struct iwl3945_rxon_assoc_cmd rxon_assoc; - struct iwl_host_cmd cmd = { - .id = REPLY_RXON_ASSOC, - .len = sizeof(rxon_assoc), - .meta.flags = CMD_WANT_SKB, - .data = &rxon_assoc, - }; - const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = priv->staging_rxon.flags; - rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; - rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; - rxon_assoc.reserved = 0; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); - rc = -EIO; - } - - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - /** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags @@ -352,7 +308,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) * iwl3945_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv)) { - rc = iwl3945_send_rxon_assoc(priv); + rc = iwl_send_rxon_assoc(priv); if (rc) { IWL_ERR(priv, "Error setting RXON_ASSOC " "configuration (%d).\n", rc); @@ -3450,9 +3406,11 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) mutex_unlock(&priv->mutex); } +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); + #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl3945_post_associate(struct iwl_priv *priv) +void iwl3945_post_associate(struct iwl_priv *priv) { int rc = 0; struct ieee80211_conf *conf = NULL; @@ -3542,8 +3500,6 @@ static void iwl3945_post_associate(struct iwl_priv *priv) priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; } -static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); - /***************************************************************************** * * mac80211 entry point functions @@ -3982,66 +3938,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "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 iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - - if (changes & BSS_CHANGED_ERP_PREAMBLE) { - IWL_DEBUG_MAC80211(priv, "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(priv, "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(priv, "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->timestamp = bss_conf->timestamp; - priv->assoc_capability = bss_conf->assoc_capability; - priv->power_data.dtim_period = bss_conf->dtim_period; - 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(priv, - "DISASSOC %d\n", bss_conf->assoc); - } - } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { - IWL_DEBUG_MAC80211(priv, - "Associated Changes %d\n", changes); - iwl3945_send_rxon_assoc(priv); - } - -} - static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -4227,7 +4123,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl_reset_qos(priv); - iwl3945_post_associate(priv); + priv->cfg->ops->lib->post_associate(priv); return 0; @@ -4765,7 +4661,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .get_tx_stats = iwl3945_mac_get_tx_stats, .conf_tx = iwl_mac_conf_tx, .reset_tsf = iwl3945_mac_reset_tsf, - .bss_info_changed = iwl3945_bss_info_changed, + .bss_info_changed = iwl_bss_info_changed, .hw_scan = iwl_mac_hw_scan }; -- cgit v0.10.2 From 9944b938f23fdd1ce2f5da190f771f176bb51eef Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:36 -0700 Subject: iwl3945: use iwl_mac_beacon_update 3945 can use iwl_mac_beacon_update. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d14146f..124a477 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1443,10 +1443,6 @@ static int iwl_read_ucode(struct iwl_priv *priv) return ret; } -/* temporary */ -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb); - /** * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -2657,45 +2653,6 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "leave\n"); } -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - __le64 timestamp; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { - IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = skb; - - priv->assoc_id = 0; - timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - priv->cfg->ops->lib->post_associate(priv); - - - return 0; -} /***************************************************************************** * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1569182..eaeeb4d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2293,6 +2293,47 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_bss_info_changed); +int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + __le64 timestamp; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { + IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = skb; + + priv->assoc_id = 0; + timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + priv->timestamp = le64_to_cpu(timestamp); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_reset_qos(priv); + + priv->cfg->ops->lib->post_associate(priv); + + + return 0; +} +EXPORT_SYMBOL(iwl_mac_beacon_update); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4ad8465..0447385 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -258,6 +258,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 6f44abc..857393a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2792,11 +2792,6 @@ static void iwl3945_init_alive_start(struct iwl_priv *priv) queue_work(priv->workqueue, &priv->restart); } - -/* temporary */ -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb); - /** * iwl3945_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -2904,7 +2899,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (beacon) - iwl3945_mac_beacon_update(priv->hw, beacon); + iwl_mac_beacon_update(priv->hw, beacon); } return; @@ -3837,7 +3832,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (!beacon) return -ENOMEM; mutex_lock(&priv->mutex); - rc = iwl3945_mac_beacon_update(hw, beacon); + rc = iwl_mac_beacon_update(hw, beacon); mutex_unlock(&priv->mutex); if (rc) return rc; @@ -4089,46 +4084,6 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) } -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - __le64 timestamp; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { - IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = skb; - - priv->assoc_id = 0; - timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - priv->cfg->ops->lib->post_associate(priv); - - - return 0; -} - /***************************************************************************** * * sysfs attributes -- cgit v0.10.2 From e0158e61108bdadd70865c2149dc829a5c84dd73 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:37 -0700 Subject: iwlwifi: add commit_rxon lib Patch adds commit_rxon lib operation to iwlwifi and iwl3945 drivers. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 519e892..9a0fb80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2008,6 +2008,150 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) return rc; } +/** + * iwl3945_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is committed to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +static int iwl3945_commit_rxon(struct iwl_priv *priv) +{ + /* cast away the const for active_rxon in this function */ + struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon; + int rc = 0; + bool new_assoc = + !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); + + if (!iwl_is_alive(priv)) + return -1; + + /* always get timestamp with Rx frame */ + staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK; + + /* select antenna */ + staging_rxon->flags &= + ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); + staging_rxon->flags |= iwl3945_get_antenna_flags(priv); + + rc = iwl_check_rxon_cmd(priv); + if (rc) { + IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* If we don't need to send a full RXON, we can use + * iwl3945_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl_full_rxon_required(priv)) { + rc = iwl_send_rxon_assoc(priv); + if (rc) { + IWL_ERR(priv, "Error setting RXON_ASSOC " + "configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); + + return 0; + } + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated(priv) && new_assoc) { + IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + /* + * reserved4 and 5 could have been filled by the iwlcore code. + * Let's clear them before pushing to the 3945. + */ + active_rxon->reserved4 = 0; + active_rxon->reserved5 = 0; + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl3945_rxon_cmd), + &priv->active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (rc) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERR(priv, "Error clearing ASSOC_MSK on current " + "configuration (%d).\n", rc); + return rc; + } + } + + IWL_DEBUG_INFO(priv, "Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = %pM\n", + (new_assoc ? "" : "out"), + le16_to_cpu(staging_rxon->channel), + staging_rxon->bssid_addr); + + /* + * reserved4 and 5 could have been filled by the iwlcore code. + * Let's clear them before pushing to the 3945. + */ + staging_rxon->reserved4 = 0; + staging_rxon->reserved5 = 0; + + iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + + /* Apply the new configuration */ + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl3945_rxon_cmd), + staging_rxon); + if (rc) { + IWL_ERR(priv, "Error setting new configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); + + iwl3945_clear_stations_table(priv); + + /* If we issue a new RXON command which required a tune then we must + * send a new TXPOWER command or we won't be able to Tx any frames */ + rc = priv->cfg->ops->lib->send_tx_power(priv); + if (rc) { + IWL_ERR(priv, "Error setting Tx power (%d).\n", rc); + return rc; + } + + /* Add the broadcast address so we can send broadcast frames */ + if (iwl3945_add_station(priv, iwl_bcast_addr, 0, 0) == + IWL_INVALID_STATION) { + IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); + return -EIO; + } + + /* 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 (iwl_is_associated(priv) && + (priv->iw_mode == NL80211_IFTYPE_STATION)) + if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, + 1, 0) + == IWL_INVALID_STATION) { + IWL_ERR(priv, "Error adding AP address for transmit\n"); + return -EIO; + } + + /* Init the hardware's rate fallback order based on the band */ + rc = iwl3945_init_hw_rate_table(priv); + if (rc) { + IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc); + return -EIO; + } + + return 0; +} + /* will add 3945 channel switch cmd handling later */ int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel) { @@ -2775,6 +2919,7 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) static struct iwl_hcmd_ops iwl3945_hcmd = { .rxon_assoc = iwl3945_send_rxon_assoc, + .commit_rxon = iwl3945_commit_rxon, }; static struct iwl_lib_ops iwl3945_lib = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 13b191f..8e3e816 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -207,6 +207,7 @@ extern int iwl3945_send_add_station(struct iwl_priv *priv, struct iwl3945_addsta_cmd *sta, u8 flags); extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid, int is_ap, u8 flags); +extern void iwl3945_clear_stations_table(struct iwl_priv *priv); extern int iwl3945_power_init_handle(struct iwl_priv *priv); extern int iwl3945_eeprom_init(struct iwl_priv *priv); extern int iwl3945_calc_db_from_ratio(int sig_ratio); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 37544af..053e420 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2271,6 +2271,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, + .commit_rxon = iwl_commit_rxon, }; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 837dbad..410cba2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1474,6 +1474,7 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, + .commit_rxon = iwl_commit_rxon, }; struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 124a477..50ef649 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -102,7 +102,7 @@ MODULE_ALIAS("iwl4965"); * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -static int iwl_commit_rxon(struct iwl_priv *priv) +int iwl_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; @@ -247,7 +247,7 @@ void iwl_update_chain_flags(struct iwl_priv *priv) { iwl_set_rxon_chain(priv); - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } static void iwl_clear_free_frames(struct iwl_priv *priv) @@ -606,7 +606,7 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode) return -EAGAIN; } - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); return 0; } @@ -1000,7 +1000,7 @@ static void iwl_error_recovery(struct iwl_priv *priv) memcpy(&priv->staging_rxon, &priv->recovery_rxon, sizeof(priv->staging_rxon)); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); iwl_rxon_add_station(priv, priv->bssid, 1); @@ -1509,7 +1509,7 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_reset_run_time_calib(priv); /* Configure the adapter for unassociated operation */ - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); @@ -1865,7 +1865,7 @@ void iwl_post_associate(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, @@ -1900,7 +1900,7 @@ void iwl_post_associate(struct iwl_priv *priv) } - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: @@ -2211,7 +2211,7 @@ static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); else IWL_DEBUG_INFO(priv, "No re-sending same RXON configuration.\n"); @@ -2235,7 +2235,7 @@ static void iwl_config_ap(struct iwl_priv *priv) /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); /* RXON Timing */ iwl_setup_rxon_timing(priv); @@ -2271,7 +2271,7 @@ static void iwl_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); @@ -2365,7 +2365,7 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, if (priv->iw_mode == NL80211_IFTYPE_AP) iwl_config_ap(priv); else { - rc = iwl_commit_rxon(priv); + rc = iwlcore_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); @@ -2374,7 +2374,7 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, } else { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } done: @@ -2396,7 +2396,7 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw, if (iwl_is_ready_rf(priv)) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } if (priv->vif == conf->vif) { priv->vif = NULL; @@ -2623,7 +2623,7 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } iwl_power_update_mode(priv, 0); @@ -2803,7 +2803,7 @@ static ssize_t store_flags(struct device *d, else { IWL_DEBUG_INFO(priv, "Commit rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -2844,7 +2844,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); priv->staging_rxon.filter_flags = cpu_to_le32(filter_flags); - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 0447385..c7e0595 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -85,6 +85,7 @@ struct iwl_cmd; struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); + int (*commit_rxon)(struct iwl_priv *priv); }; struct iwl_hcmd_utils_ops { u16 (*get_hcmd_size)(u8 cmd_id, u16 len); @@ -259,6 +260,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changes); int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); +int iwl_commit_rxon(struct iwl_priv *priv); /***************************************************** * RX handlers. @@ -541,6 +543,10 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) { return priv->cfg->ops->hcmd->rxon_assoc(priv); } +static inline int iwlcore_commit_rxon(struct iwl_priv *priv) +{ + return priv->cfg->ops->hcmd->commit_rxon(priv); +} static inline const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 857393a..e96a726 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -149,7 +149,7 @@ out: * * NOTE: This does not clear or otherwise alter the device's station table. */ -static void iwl3945_clear_stations_table(struct iwl_priv *priv) +void iwl3945_clear_stations_table(struct iwl_priv *priv) { unsigned long flags; @@ -270,150 +270,6 @@ __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) return 0; /* "diversity" is default if error */ } -/** - * iwl3945_commit_rxon - commit staging_rxon to hardware - * - * The RXON command in staging_rxon is committed to the hardware and - * the active_rxon structure is updated with the new data. This - * function correctly transitions out of the RXON_ASSOC_MSK state if - * a HW tune is required based on the RXON structure changes. - */ -static int iwl3945_commit_rxon(struct iwl_priv *priv) -{ - /* cast away the const for active_rxon in this function */ - struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; - struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon; - int rc = 0; - bool new_assoc = - !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); - - if (!iwl_is_alive(priv)) - return -1; - - /* always get timestamp with Rx frame */ - staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK; - - /* select antenna */ - staging_rxon->flags &= - ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); - staging_rxon->flags |= iwl3945_get_antenna_flags(priv); - - rc = iwl_check_rxon_cmd(priv); - if (rc) { - IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); - return -EINVAL; - } - - /* If we don't need to send a full RXON, we can use - * iwl3945_rxon_assoc_cmd which is used to reconfigure filter - * and other flags for the current radio configuration. */ - if (!iwl_full_rxon_required(priv)) { - rc = iwl_send_rxon_assoc(priv); - if (rc) { - IWL_ERR(priv, "Error setting RXON_ASSOC " - "configuration (%d).\n", rc); - return rc; - } - - memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - - return 0; - } - - /* If we are currently associated and the new config requires - * an RXON_ASSOC and the new config wants the associated mask enabled, - * we must clear the associated from the active configuration - * before we apply the new config */ - if (iwl_is_associated(priv) && new_assoc) { - IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - /* - * reserved4 and 5 could have been filled by the iwlcore code. - * Let's clear them before pushing to the 3945. - */ - active_rxon->reserved4 = 0; - active_rxon->reserved5 = 0; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl3945_rxon_cmd), - &priv->active_rxon); - - /* If the mask clearing failed then we set - * active_rxon back to what it was previously */ - if (rc) { - active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERR(priv, "Error clearing ASSOC_MSK on current " - "configuration (%d).\n", rc); - return rc; - } - } - - IWL_DEBUG_INFO(priv, "Sending RXON\n" - "* with%s RXON_FILTER_ASSOC_MSK\n" - "* channel = %d\n" - "* bssid = %pM\n", - (new_assoc ? "" : "out"), - le16_to_cpu(staging_rxon->channel), - staging_rxon->bssid_addr); - - /* - * reserved4 and 5 could have been filled by the iwlcore code. - * Let's clear them before pushing to the 3945. - */ - staging_rxon->reserved4 = 0; - staging_rxon->reserved5 = 0; - - iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); - - /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl3945_rxon_cmd), - staging_rxon); - if (rc) { - IWL_ERR(priv, "Error setting new configuration (%d).\n", rc); - return rc; - } - - memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - - iwl3945_clear_stations_table(priv); - - /* If we issue a new RXON command which required a tune then we must - * send a new TXPOWER command or we won't be able to Tx any frames */ - rc = priv->cfg->ops->lib->send_tx_power(priv); - if (rc) { - IWL_ERR(priv, "Error setting Tx power (%d).\n", rc); - return rc; - } - - /* Add the broadcast address so we can send broadcast frames */ - if (iwl3945_add_station(priv, iwl_bcast_addr, 0, 0) == - IWL_INVALID_STATION) { - IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); - return -EIO; - } - - /* 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 (iwl_is_associated(priv) && - (priv->iw_mode == NL80211_IFTYPE_STATION)) - if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, - 1, 0) - == IWL_INVALID_STATION) { - IWL_ERR(priv, "Error adding AP address for transmit\n"); - return -EIO; - } - - /* Init the hardware's rate fallback order based on the band */ - rc = iwl3945_init_hw_rate_table(priv); - if (rc) { - IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc); - return -EIO; - } - - return 0; -} - static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) @@ -745,7 +601,7 @@ static int iwl3945_set_mode(struct iwl_priv *priv, int mode) return -EAGAIN; } - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); return 0; } @@ -2025,7 +1881,7 @@ static void iwl3945_error_recovery(struct iwl_priv *priv) memcpy(&priv->staging_rxon, &priv->recovery_rxon, sizeof(priv->staging_rxon)); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); iwl3945_add_station(priv, priv->bssid, 1, 0); @@ -2881,7 +2737,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) iwl_send_bt_config(priv); /* Configure the adapter for unassociated operation */ - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); iwl3945_reg_txpower_periodic(priv); @@ -3430,7 +3286,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); iwl3945_setup_rxon_timing(priv); @@ -3463,7 +3319,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) } - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: @@ -3740,7 +3596,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); else IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration\n"); @@ -3764,7 +3620,7 @@ static void iwl3945_config_ap(struct iwl_priv *priv) /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); /* RXON Timing */ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); @@ -3800,7 +3656,7 @@ static void iwl3945_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); iwl3945_add_station(priv, iwl_bcast_addr, 0, 0); } iwl3945_send_beacon_cmd(priv); @@ -3891,7 +3747,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (priv->iw_mode == NL80211_IFTYPE_AP) iwl3945_config_ap(priv); else { - rc = iwl3945_commit_rxon(priv); + rc = iwlcore_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0); @@ -3900,7 +3756,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, } else { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); } done: @@ -3922,7 +3778,7 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, if (iwl_is_ready_rf(priv)) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); } if (priv->vif == conf->vif) { priv->vif = NULL; @@ -4065,7 +3921,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); } /* Per mac80211.h: This is only used in IBSS mode... */ @@ -4191,7 +4047,7 @@ static ssize_t store_flags(struct device *d, IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -4227,7 +4083,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); priv->staging_rxon.filter_flags = cpu_to_le32(filter_flags); - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); -- cgit v0.10.2 From f45c271493c37d2d80177582191acc1a4e446297 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:38 -0700 Subject: iwl3945: delay mode setting Delay mode setting till uCode is ready. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e96a726..0ad89fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2758,6 +2758,9 @@ static void iwl3945_alive_start(struct iwl_priv *priv) iwl_mac_beacon_update(priv->hw, beacon); } + if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) + iwl3945_set_mode(priv, priv->iw_mode); + return; restart: @@ -3497,8 +3500,8 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl_is_ready(priv)) - iwl3945_set_mode(priv, conf->type); + if (iwl3945_set_mode(priv, conf->type) == -EAGAIN) + set_bit(STATUS_MODE_PENDING, &priv->status); mutex_unlock(&priv->mutex); -- cgit v0.10.2 From 79fa455a995057b6559fcd2a02e8b089b2e2e288 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:39 -0700 Subject: iwlwifi: add station management ops This patch adds declarations for station management ops to iwlwifi drivers. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 9a0fb80..fb08295 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2954,6 +2954,15 @@ static struct iwl_lib_ops iwl3945_lib = { .post_associate = iwl3945_post_associate, }; +static struct iwl_station_mgmt_ops iwl3945_station_mgmt = { + .add_station = iwl3945_add_station, +#if 0 + .remove_station = iwl3945_remove_station, +#endif + .find_station = iwl3945_hw_find_station, + .clear_station_table = iwl3945_clear_stations_table, +}; + static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .get_hcmd_size = iwl3945_get_hcmd_size, .build_addsta_hcmd = iwl3945_build_addsta_hcmd, @@ -2963,6 +2972,7 @@ static struct iwl_ops iwl3945_ops = { .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, + .smgmt = &iwl3945_station_mgmt, }; static struct iwl_cfg iwl3945_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 053e420..e3d1e30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2268,6 +2268,12 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->txpower_work); } +static struct iwl_station_mgmt_ops iwl4965_station_mgmt = { + .add_station_ht = iwl_add_station_flags, + .remove_station = iwl_remove_station, + .find_station = iwl_find_station, + .clear_station_table = iwl_clear_stations_table, +}; static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, @@ -2332,6 +2338,7 @@ static struct iwl_ops iwl4965_ops = { .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, + .smgmt = &iwl4965_station_mgmt, }; struct iwl_cfg iwl4965_agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 410cba2..1344943 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1472,6 +1472,13 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWL49_RSSI_OFFSET; } +struct iwl_station_mgmt_ops iwl5000_station_mgmt = { + .add_station_ht = iwl_add_station_flags, + .remove_station = iwl_remove_station, + .find_station = iwl_find_station, + .clear_station_table = iwl_clear_stations_table, +}; + struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -1535,6 +1542,7 @@ struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .smgmt = &iwl5000_station_mgmt, }; struct iwl_mod_params iwl50_mod_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index edfa5e1..ee271d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -72,6 +72,7 @@ static struct iwl_ops iwl6000_ops = { .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl6000_hcmd_utils, + .smgmt = &iwl5000_station_mgmt, }; struct iwl_cfg iwl6000_2ag_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c7e0595..8b7f5bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -83,10 +83,22 @@ struct iwl_cmd; #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 +struct iwl_station_mgmt_ops { + u8 (*add_station_ht)(struct iwl_priv *priv, const u8 *addr, + int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); + u8 (*add_station)(struct iwl_priv *priv, const u8 *addr, + int is_ap, u8 flags); + int (*remove_station)(struct iwl_priv *priv, const u8 *addr, + int is_ap); + u8 (*find_station)(struct iwl_priv *priv, const u8 *addr); + void (*clear_station_table)(struct iwl_priv *priv); +}; + struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); }; + struct iwl_hcmd_utils_ops { u16 (*get_hcmd_size)(u8 cmd_id, u16 len); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); @@ -160,6 +172,7 @@ struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; + const struct iwl_station_mgmt_ops *smgmt; }; struct iwl_mod_params { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ec9a138..59930f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -70,6 +70,7 @@ extern struct iwl_ops iwl5000_ops; extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_hcmd_ops iwl5000_hcmd; extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; +extern struct iwl_station_mgmt_ops iwl5000_station_mgmt; /* shared functions from iwl-5000.c */ extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len); -- cgit v0.10.2 From 40ace5b385ccf8a4d4d096b353b7f1baac1d014b Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:40 -0700 Subject: iwl3945: replace station function with station ops Patch replaces station function used in driver by station management ops in 3945. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index fb08295..7c0c799 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2114,7 +2114,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - iwl3945_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ @@ -2125,7 +2125,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl3945_add_station(priv, iwl_bcast_addr, 0, 0) == + if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -2135,8 +2135,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == NL80211_IFTYPE_STATION)) - if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, - 1, 0) + if (priv->cfg->ops->smgmt->add_station(priv, + priv->active_rxon.bssid_addr, 1, 0) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding AP address for transmit\n"); return -EIO; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0ad89fb..f5f39cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -588,7 +588,7 @@ static int iwl3945_set_mode(struct iwl_priv *priv, int mode) iwl_connection_init_rx_config(priv, mode); - iwl3945_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /* don't commit rxon if rf-kill is on*/ if (!iwl_is_ready_rf(priv)) @@ -734,7 +734,7 @@ static int iwl3945_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If we are an AP, then find the station, or use BCAST */ case NL80211_IFTYPE_AP: - sta_id = iwl3945_hw_find_station(priv, hdr->addr1); + sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; return priv->hw_params.bcast_sta_id; @@ -743,11 +743,12 @@ static int iwl3945_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) * or create a new station table entry */ case NL80211_IFTYPE_ADHOC: { /* Create new station table entry */ - sta_id = iwl3945_hw_find_station(priv, hdr->addr1); + sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; - sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC); + sta_id = priv->cfg->ops->smgmt->add_station(priv, + hdr->addr1, 0, CMD_ASYNC); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -1883,7 +1884,7 @@ static void iwl3945_error_recovery(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); - iwl3945_add_station(priv, priv->bssid, 1, 0); + priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 1, 0); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -2678,7 +2679,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) goto restart; } - iwl3945_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); rc = iwl_grab_nic_access(priv); if (rc) { @@ -2783,7 +2784,7 @@ static void __iwl3945_down(struct iwl_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); iwl3945_led_unregister(priv); - iwl3945_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -2940,7 +2941,7 @@ static int __iwl3945_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwl3945_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -3332,7 +3333,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) case NL80211_IFTYPE_ADHOC: priv->assoc_id = 1; - iwl3945_add_station(priv, priv->bssid, 0, 0); + priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -3660,7 +3661,7 @@ static void iwl3945_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); - iwl3945_add_station(priv, iwl_bcast_addr, 0, 0); + priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0); } iwl3945_send_beacon_cmd(priv); @@ -3752,7 +3753,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, else { rc = iwlcore_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) - iwl3945_add_station(priv, + priv->cfg->ops->smgmt->add_station(priv, priv->active_rxon.bssid_addr, 1, 0); } @@ -3814,7 +3815,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static_key = !iwl_is_associated(priv); if (!static_key) { - sta_id = iwl3945_hw_find_station(priv, addr); + sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -4497,7 +4498,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - iwl3945_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -4860,7 +4861,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_hw_txq_ctx_free(priv); iwl3945_unset_hw_params(priv); - iwl3945_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); -- cgit v0.10.2 From e11bc0286a4ff8f4e5cdefbcce0878d29c03c630 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:41 -0700 Subject: iwlwifi: use station management ops Patch replaces station management functions with ops declared. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 1344943..26f30a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -678,7 +678,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv) goto restart; } - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 7cdbcfe..a995128 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2453,13 +2453,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { - u8 sta_id = iwl_find_station(priv, hdr->addr1); + u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, + hdr->addr1); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); - sta_id = iwl_add_station_flags(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); + sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, + hdr->addr1, 0, + CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2526,15 +2528,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { - u8 sta_id = iwl_find_station(priv, sta->addr); + u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, + sta->addr); /* for IBSS the call are from tasklet */ IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); - sta_id = iwl_add_station_flags(priv, sta->addr, - 0, CMD_ASYNC, NULL); + sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, + sta->addr, 0, + CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 50ef649..565a441 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -188,7 +188,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); if (!priv->error_recovering) priv->start_calib = 0; @@ -593,7 +593,7 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode) iwl_set_rxon_chain(priv); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /* dont commit rxon if rf-kill is on*/ if (!iwl_is_ready_rf(priv)) @@ -1471,7 +1471,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, @@ -1557,7 +1557,7 @@ static void __iwl_down(struct iwl_priv *priv) iwl_leds_unregister(priv); - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -1708,7 +1708,7 @@ static int __iwl_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -2439,7 +2439,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } addr = sta ? sta->addr : iwl_bcast_addr; - sta_id = iwl_find_station(priv, addr); + sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -3311,7 +3311,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_rx_queue_free(priv, &priv->rxq); iwl_hw_txq_ctx_free(priv); - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); iwl_eeprom_free(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index eaeeb4d..0532d99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1368,7 +1368,7 @@ int iwl_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - iwl_clear_stations_table(priv); + priv->cfg->ops->smgmt->clear_station_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 5798fe4..5816368 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) return IWL_AP_ID; } else { u8 *da = ieee80211_get_DA(hdr); - return iwl_find_station(priv, da); + return priv->cfg->ops->smgmt->find_station(priv, da); } } EXPORT_SYMBOL(iwl_get_ra_sta_id); @@ -300,7 +300,7 @@ EXPORT_SYMBOL(iwl_add_station_flags); static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - u8 sta_id = iwl_find_station(priv, addr); + u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); BUG_ON(sta_id == IWL_INVALID_STATION); @@ -758,7 +758,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, int i; DECLARE_MAC_BUF(mac); - sta_id = iwl_find_station(priv, addr); + sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -1019,7 +1019,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rcu_read_unlock(); } - sta_id = iwl_add_station_flags(priv, addr, is_ap, + sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, addr, is_ap, 0, cur_ht_config); /* Set up default rate scaling table in device's station table */ @@ -1053,7 +1053,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If we are an AP, then find the station, or use BCAST */ case NL80211_IFTYPE_AP: - sta_id = iwl_find_station(priv, hdr->addr1); + sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; return priv->hw_params.bcast_sta_id; @@ -1061,12 +1061,12 @@ 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 NL80211_IFTYPE_ADHOC: - sta_id = iwl_find_station(priv, hdr->addr1); + sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; /* Create new station table entry */ - sta_id = iwl_add_station_flags(priv, hdr->addr1, + sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, hdr->addr1, 0, CMD_ASYNC, NULL); if (sta_id != IWL_INVALID_STATION) @@ -1115,7 +1115,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, unsigned long flags; int sta_id; - sta_id = iwl_find_station(priv, addr); + sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -1137,7 +1137,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) unsigned long flags; int sta_id; - sta_id = iwl_find_station(priv, addr); + sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); return -ENXIO; @@ -1172,7 +1172,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) { /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); + u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); if (sta_id != IWL_INVALID_STATION) { u8 sta_awake = priv->stations[sta_id]. -- cgit v0.10.2 From 06fd3d86a426848dbd8db27b7257a4eb4be8cfae Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:42 -0700 Subject: iwl3945/iwlwifi: unify add_station function Patch unifies the add_station function for 3945 and iwlwifi drivers. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index af6b9d4..f63a9c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -719,7 +719,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n", hdr->addr1); sta_id = iwl3945_add_station(priv, - hdr->addr1, 0, CMD_ASYNC); + hdr->addr1, 0, CMD_ASYNC, NULL); } if (sta_id != IWL_INVALID_STATION) rs_sta->ibss_sta_added = 1; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7c0c799..a854feb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2125,7 +2125,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0) == + if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -2136,7 +2136,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) if (iwl_is_associated(priv) && (priv->iw_mode == NL80211_IFTYPE_STATION)) if (priv->cfg->ops->smgmt->add_station(priv, - priv->active_rxon.bssid_addr, 1, 0) + priv->active_rxon.bssid_addr, 1, 0, NULL) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding AP address for transmit\n"); return -EIO; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 8e3e816..88628b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -206,7 +206,7 @@ struct iwl3945_addsta_cmd; extern int iwl3945_send_add_station(struct iwl_priv *priv, struct iwl3945_addsta_cmd *sta, u8 flags); extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid, - int is_ap, u8 flags); + int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); extern void iwl3945_clear_stations_table(struct iwl_priv *priv); extern int iwl3945_power_init_handle(struct iwl_priv *priv); extern int iwl3945_eeprom_init(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e3d1e30..e98849e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2269,7 +2269,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) } static struct iwl_station_mgmt_ops iwl4965_station_mgmt = { - .add_station_ht = iwl_add_station_flags, + .add_station = iwl_add_station_flags, .remove_station = iwl_remove_station, .find_station = iwl_find_station, .clear_station_table = iwl_clear_stations_table, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 26f30a7..52ee773 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1473,7 +1473,7 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, } struct iwl_station_mgmt_ops iwl5000_station_mgmt = { - .add_station_ht = iwl_add_station_flags, + .add_station = iwl_add_station_flags, .remove_station = iwl_remove_station, .find_station = iwl_find_station, .clear_station_table = iwl_clear_stations_table, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index a995128..b1818a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2459,7 +2459,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); - sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, + sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1, 0, CMD_ASYNC, NULL); } @@ -2536,7 +2536,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); - sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, + sta_id = priv->cfg->ops->smgmt->add_station(priv, sta->addr, 0, CMD_ASYNC, NULL); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8b7f5bd..383590c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -84,10 +84,8 @@ struct iwl_cmd; #define IWL_SKU_N 0x8 struct iwl_station_mgmt_ops { - u8 (*add_station_ht)(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); u8 (*add_station)(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags); + int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); int (*remove_station)(struct iwl_priv *priv, const u8 *addr, int is_ap); u8 (*find_station)(struct iwl_priv *priv, const u8 *addr); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 5816368..b8f18c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1019,7 +1019,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rcu_read_unlock(); } - sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, addr, is_ap, + sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap, 0, cur_ht_config); /* Set up default rate scaling table in device's station table */ @@ -1066,7 +1066,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) return sta_id; /* Create new station table entry */ - sta_id = priv->cfg->ops->smgmt->add_station_ht(priv, hdr->addr1, + sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1, 0, CMD_ASYNC, NULL); if (sta_id != IWL_INVALID_STATION) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f5f39cc..5669145 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -164,7 +164,7 @@ void iwl3945_clear_stations_table(struct iwl_priv *priv) /** * iwl3945_add_station - Add station to station tables in driver and device */ -u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) +u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info) { int i; int index = IWL_INVALID_STATION; @@ -748,7 +748,7 @@ static int iwl3945_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) return sta_id; sta_id = priv->cfg->ops->smgmt->add_station(priv, - hdr->addr1, 0, CMD_ASYNC); + hdr->addr1, 0, CMD_ASYNC, NULL); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -1884,7 +1884,7 @@ static void iwl3945_error_recovery(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); - priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 1, 0); + priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 1, 0, NULL); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -3333,7 +3333,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) case NL80211_IFTYPE_ADHOC: priv->assoc_id = 1; - priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0); + priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -3661,7 +3661,7 @@ static void iwl3945_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); - priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0); + priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL); } iwl3945_send_beacon_cmd(priv); @@ -3754,7 +3754,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, rc = iwlcore_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) priv->cfg->ops->smgmt->add_station(priv, - priv->active_rxon.bssid_addr, 1, 0); + priv->active_rxon.bssid_addr, 1, 0, NULL); } } else { -- cgit v0.10.2 From f5d3026683da45e00c49a24999ad0d256e4651d5 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:43 -0700 Subject: iwl3945: use iwl_get_sta_id from iwlwifi iwl3945 can now use iwl_get_sta_id. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5669145..7f35017 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -712,65 +712,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx->next_frame_len = 0; } -/** - * iwl3945_get_sta_id - Find station's index within station table - */ -static int iwl3945_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) -{ - int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); - - /* If this frame is broadcast or management, use broadcast station id */ - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - is_multicast_ether_addr(hdr->addr1)) - return priv->hw_params.bcast_sta_id; - - switch (priv->iw_mode) { - - /* 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 NL80211_IFTYPE_STATION: - return IWL_AP_ID; - - /* If we are an AP, then find the station, or use BCAST */ - case NL80211_IFTYPE_AP: - sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - return priv->hw_params.bcast_sta_id; - - /* If this frame is going out to an IBSS network, find the station, - * or create a new station table entry */ - case NL80211_IFTYPE_ADHOC: { - /* Create new station table entry */ - sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - sta_id = priv->cfg->ops->smgmt->add_station(priv, - hdr->addr1, 0, CMD_ASYNC, NULL); - - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - IWL_DEBUG_DROP(priv, "Station %pM not in station map. " - "Defaulting to broadcast...\n", - hdr->addr1); - 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_WARN(priv, "Unknown mode of operation: %d\n", - priv->iw_mode); - return priv->hw_params.bcast_sta_id; - } -} - /* * start REPLY_TX command process */ @@ -836,7 +777,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl3945_get_sta_id(priv, hdr); + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); -- cgit v0.10.2 From 45823531662028a8cbd68906c20e887bb287c85e Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:44 -0700 Subject: iwlwifi: add set_rxon_chain op add set_rxon_chain op to iwlwifi cfg ops in preparation of future 3945 porting work. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e98849e..ab25e6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2278,6 +2278,7 @@ static struct iwl_station_mgmt_ops iwl4965_station_mgmt = { static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, + .set_rxon_chain = iwl_set_rxon_chain, }; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 52ee773..cf622a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1482,6 +1482,7 @@ struct iwl_station_mgmt_ops iwl5000_station_mgmt = { struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, + .set_rxon_chain = iwl_set_rxon_chain, }; struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 565a441..11e1792 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -246,7 +246,8 @@ int iwl_commit_rxon(struct iwl_priv *priv) void iwl_update_chain_flags(struct iwl_priv *priv) { - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); iwlcore_commit_rxon(priv); } @@ -590,7 +591,10 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) static int iwl_set_mode(struct iwl_priv *priv, int mode) { iwl_connection_init_rx_config(priv, mode); - iwl_set_rxon_chain(priv); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); priv->cfg->ops->smgmt->clear_station_table(priv); @@ -1499,7 +1503,10 @@ static void iwl_alive_start(struct iwl_priv *priv) } else { /* Initialize our rx_config data */ iwl_connection_init_rx_config(priv, priv->iw_mode); - iwl_set_rxon_chain(priv); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } @@ -1878,7 +1885,9 @@ void iwl_post_associate(struct iwl_priv *priv) iwl_set_rxon_ht(priv, &priv->current_ht_config); - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n", @@ -2182,7 +2191,8 @@ static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) } /* call to ensure that 4965 rx_chain is set properly in monitor mode */ - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { if (conf->radio_enabled && @@ -2245,7 +2255,8 @@ static void iwl_config_ap(struct iwl_priv *priv) IWL_WARN(priv, "REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); /* FIXME: what should be the assoc_id for AP? */ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0532d99..cca37af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -821,7 +821,8 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " @@ -1380,7 +1381,9 @@ int iwl_init_drv(struct iwl_priv *priv) priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + iwl_init_scan_params(priv); iwl_reset_qos(priv); @@ -2257,7 +2260,9 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_HT) { iwl_ht_conf(priv, bss_conf); - iwl_set_rxon_chain(priv); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); } if (changes & BSS_CHANGED_ASSOC) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 383590c..f5eff74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -95,6 +95,7 @@ struct iwl_station_mgmt_ops { struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); + void (*set_rxon_chain)(struct iwl_priv *priv); }; struct iwl_hcmd_utils_ops { -- cgit v0.10.2 From 727882d62477ed45d248e8cd6d53cf794537b073 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:45 -0700 Subject: iwl3945: use iwl_set_mode in 3945 3945 can now use iwl_set_mode from iwlcore library. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 11e1792..479fcf1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -588,33 +588,6 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl_set_mode(struct iwl_priv *priv, int mode) -{ - iwl_connection_init_rx_config(priv, mode); - - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv); - - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - - priv->cfg->ops->smgmt->clear_station_table(priv); - - /* dont commit rxon if rf-kill is on*/ - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - - cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - return -EAGAIN; - } - - iwlcore_commit_rxon(priv); - - return 0; -} - /****************************************************************************** * * Generic RX handler implementations diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index cca37af..01e7604 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2339,6 +2339,48 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) } EXPORT_SYMBOL(iwl_mac_beacon_update); +int iwl_set_mode(struct iwl_priv *priv, int mode) +{ + if (mode == NL80211_IFTYPE_ADHOC) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, + priv->band, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info || !is_channel_ibss(ch_info)) { + IWL_ERR(priv, "channel %d not IBSS channel\n", + le16_to_cpu(priv->staging_rxon.channel)); + return -EINVAL; + } + } + + iwl_connection_init_rx_config(priv, mode); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + priv->cfg->ops->smgmt->clear_station_table(priv); + + /* dont commit rxon if rf-kill is on*/ + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + + cancel_delayed_work(&priv->scan_check); + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); + return -EAGAIN; + } + + iwlcore_commit_rxon(priv); + + return 0; +} +EXPORT_SYMBOL(iwl_set_mode); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f5eff74..49df47a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -273,6 +273,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, u32 changes); int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); int iwl_commit_rxon(struct iwl_priv *priv); +int iwl_set_mode(struct iwl_priv *priv, int mode); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7f35017..666c1ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -570,42 +570,6 @@ static void iwl3945_setup_rxon_timing(struct iwl_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl3945_set_mode(struct iwl_priv *priv, int mode) -{ - if (mode == NL80211_IFTYPE_ADHOC) { - const struct iwl_channel_info *ch_info; - - ch_info = iwl_get_channel_info(priv, - priv->band, - le16_to_cpu(priv->staging_rxon.channel)); - - if (!ch_info || !is_channel_ibss(ch_info)) { - IWL_ERR(priv, "channel %d not IBSS channel\n", - le16_to_cpu(priv->staging_rxon.channel)); - return -EINVAL; - } - } - - iwl_connection_init_rx_config(priv, mode); - - priv->cfg->ops->smgmt->clear_station_table(priv); - - /* don't commit rxon if rf-kill is on*/ - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - - cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - return -EAGAIN; - } - - iwlcore_commit_rxon(priv); - - return 0; -} - static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_info *info, struct iwl_cmd *cmd, @@ -2701,7 +2665,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) } if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) - iwl3945_set_mode(priv, priv->iw_mode); + iwl_set_mode(priv, priv->iw_mode); return; @@ -3442,7 +3406,7 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl3945_set_mode(priv, conf->type) == -EAGAIN) + if (iwl_set_mode(priv, conf->type) == -EAGAIN) set_bit(STATUS_MODE_PENDING, &priv->status); mutex_unlock(&priv->mutex); -- cgit v0.10.2 From cbb6ab94b66cfb7136e640191a9628c5a71220a3 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:46 -0700 Subject: iwl3945: use iwl_mac_add_interface from iwlwifi Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 479fcf1..7e7b584 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2036,42 +2036,6 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static int iwl_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); - - if (priv->vif) { - IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); - return -EOPNOTSUPP; - } - - spin_lock_irqsave(&priv->lock, flags); - priv->vif = conf->vif; - priv->iw_mode = conf->type; - - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - - if (conf->mac_addr) { - IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr); - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - } - - if (iwl_set_mode(priv, conf->type) == -EAGAIN) - /* we are not ready, will run again when ready */ - set_bit(STATUS_MODE_PENDING, &priv->status); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - /** * iwl_mac_config - mac80211 config callback * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 01e7604..e08aee9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2381,6 +2381,43 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) } EXPORT_SYMBOL(iwl_set_mode); +int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); + + if (priv->vif) { + IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); + return -EOPNOTSUPP; + } + + spin_lock_irqsave(&priv->lock, flags); + priv->vif = conf->vif; + priv->iw_mode = conf->type; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + + if (conf->mac_addr) { + IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr); + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); + } + + if (iwl_set_mode(priv, conf->type) == -EAGAIN) + /* we are not ready, will run again when ready */ + set_bit(STATUS_MODE_PENDING, &priv->status); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + return 0; +} +EXPORT_SYMBOL(iwl_mac_add_interface); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 49df47a..7df54405 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -274,6 +274,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); int iwl_commit_rxon(struct iwl_priv *priv); int iwl_set_mode(struct iwl_priv *priv, int mode); +int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 666c1ff..955e50a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3380,41 +3380,6 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); - - if (priv->vif) { - IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); - return -EOPNOTSUPP; - } - - spin_lock_irqsave(&priv->lock, flags); - priv->vif = conf->vif; - priv->iw_mode = conf->type; - - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - - if (conf->mac_addr) { - IWL_DEBUG_MAC80211(priv, "Set: %pM\n", conf->mac_addr); - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - } - - if (iwl_set_mode(priv, conf->type) == -EAGAIN) - set_bit(STATUS_MODE_PENDING, &priv->status); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - /** * iwl3945_mac_config - mac80211 config callback * @@ -4372,7 +4337,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .tx = iwl3945_mac_tx, .start = iwl3945_mac_start, .stop = iwl3945_mac_stop, - .add_interface = iwl3945_mac_add_interface, + .add_interface = iwl_mac_add_interface, .remove_interface = iwl3945_mac_remove_interface, .config = iwl3945_mac_config, .config_interface = iwl3945_mac_config_interface, -- cgit v0.10.2 From d8052319f2a7d1ee86248df00193110ad1946a33 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:47 -0700 Subject: iwl3945: use iwl_mac_remove_interface from iwlwifi 3945 can now use iwl_mac_remove_interface from iwlwifi Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7e7b584..5cc30a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2332,30 +2332,6 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, return 0; } -static void iwl_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - mutex_lock(&priv->mutex); - - if (iwl_is_ready_rf(priv)) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - } - if (priv->vif == conf->vif) { - priv->vif = NULL; - memset(priv->bssid, 0, ETH_ALEN); - } - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - -} - static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e08aee9..b8afd9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2418,6 +2418,31 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_mac_add_interface); +void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + mutex_lock(&priv->mutex); + + if (iwl_is_ready_rf(priv)) { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv); + } + if (priv->vif == conf->vif) { + priv->vif = NULL; + memset(priv->bssid, 0, ETH_ALEN); + } + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + +} +EXPORT_SYMBOL(iwl_mac_remove_interface); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7df54405..5dc3306 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -276,6 +276,8 @@ int iwl_commit_rxon(struct iwl_priv *priv); int iwl_set_mode(struct iwl_priv *priv, int mode); int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); +void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 955e50a..f82a9dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3640,29 +3640,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, return 0; } -static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - mutex_lock(&priv->mutex); - - if (iwl_is_ready_rf(priv)) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - } - if (priv->vif == conf->vif) { - priv->vif = NULL; - memset(priv->bssid, 0, ETH_ALEN); - } - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -4338,7 +4315,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .start = iwl3945_mac_start, .stop = iwl3945_mac_stop, .add_interface = iwl_mac_add_interface, - .remove_interface = iwl3945_mac_remove_interface, + .remove_interface = iwl_mac_remove_interface, .config = iwl3945_mac_config, .config_interface = iwl3945_mac_config_interface, .configure_filter = iwl_configure_filter, -- cgit v0.10.2 From 4808368dad3263ac46e71f037c0dcd2dcf082525 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:48 -0700 Subject: iwl3945: use iwl_mac_config from iwlwifi 3945 can now use iwl_mac_config from iwlwifi Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 5cc30a2..4640996 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2036,139 +2036,6 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -/** - * iwl_mac_config - mac80211 config callback - * - * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to - * be set inappropriately and the driver currently sets the hardware up to - * use it whenever needed. - */ -static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - struct ieee80211_conf *conf = &hw->conf; - unsigned long flags = 0; - int ret = 0; - u16 ch; - int scan_active = 0; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", - conf->channel->hw_value, changed); - - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { - scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); - } - - - /* during scanning mac80211 will delay channel setting until - * scan finish with changed = 0 - */ - if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { - if (scan_active) - goto set_ch_out; - - ch = ieee80211_frequency_to_channel(conf->channel->center_freq); - ch_info = iwl_get_channel_info(priv, conf->channel->band, ch); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); - ret = -EINVAL; - goto set_ch_out; - } - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC && - !is_channel_ibss(ch_info)) { - IWL_ERR(priv, "channel %d in band %d not " - "IBSS channel\n", - conf->channel->hw_value, conf->channel->band); - ret = -EINVAL; - goto set_ch_out; - } - - priv->current_ht_config.is_ht = conf_is_ht(conf); - - spin_lock_irqsave(&priv->lock, flags); - - - /* if we are switching from ht to 2.4 clear flags - * from any ht related info since 2.4 does not - * support ht */ - if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) - priv->staging_rxon.flags = 0; - - iwl_set_rxon_channel(priv, conf->channel); - - iwl_set_flags_for_band(priv, conf->channel->band); - spin_unlock_irqrestore(&priv->lock, flags); - set_ch_out: - /* The list of supported rates and rate mask can be different - * for each band; since the band may have changed, reset - * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); - } - - if (changed & IEEE80211_CONF_CHANGE_PS) { - 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(priv, "Error setting power level\n"); - - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", - priv->tx_power_user_lmt, conf->power_level); - - iwl_set_tx_power(priv, conf->power_level, false); - } - - /* call to ensure that 4965 rx_chain is set properly in monitor mode */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv); - - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - if (conf->radio_enabled && - iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " - "waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) - iwl_radio_kill_sw_disable_radio(priv); - } - - if (!conf->radio_enabled) { - IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); - goto out; - } - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - goto out; - } - - if (scan_active) - goto out; - - if (memcmp(&priv->active_rxon, - &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwlcore_commit_rxon(priv); - else - IWL_DEBUG_INFO(priv, "No re-sending same RXON configuration.\n"); - - -out: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - return ret; -} - static void iwl_config_ap(struct iwl_priv *priv) { int ret = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b8afd9b..4369fc8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2443,6 +2443,142 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_mac_remove_interface); +/** + * iwl_mac_config - mac80211 config callback + * + * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to + * be set inappropriately and the driver currently sets the hardware up to + * use it whenever needed. + */ +int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; + unsigned long flags = 0; + int ret = 0; + u16 ch; + int scan_active = 0; + + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + ret = -EIO; + goto out; + } + + IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", + conf->channel->hw_value, changed); + + if (unlikely(!priv->cfg->mod_params->disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + scan_active = 1; + IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + } + + + /* during scanning mac80211 will delay channel setting until + * scan finish with changed = 0 + */ + if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + if (scan_active) + goto set_ch_out; + + ch = ieee80211_frequency_to_channel(conf->channel->center_freq); + ch_info = iwl_get_channel_info(priv, conf->channel->band, ch); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); + ret = -EINVAL; + goto set_ch_out; + } + + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + !is_channel_ibss(ch_info)) { + IWL_ERR(priv, "channel %d in band %d not " + "IBSS channel\n", + conf->channel->hw_value, conf->channel->band); + ret = -EINVAL; + goto set_ch_out; + } + + priv->current_ht_config.is_ht = conf_is_ht(conf); + + spin_lock_irqsave(&priv->lock, flags); + + + /* if we are switching from ht to 2.4 clear flags + * from any ht related info since 2.4 does not + * support ht */ + if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) + priv->staging_rxon.flags = 0; + + iwl_set_rxon_channel(priv, conf->channel); + + iwl_set_flags_for_band(priv, conf->channel->band); + spin_unlock_irqrestore(&priv->lock, flags); + set_ch_out: + /* The list of supported rates and rate mask can be different + * for each band; since the band may have changed, reset + * the rate mask to what mac80211 lists */ + iwl_set_rate(priv); + } + + if (changed & IEEE80211_CONF_CHANGE_PS) { + 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(priv, "Error setting power level\n"); + + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", + priv->tx_power_user_lmt, conf->power_level); + + iwl_set_tx_power(priv, conf->power_level, false); + } + + /* call to ensure that 4965 rx_chain is set properly in monitor mode */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { + if (conf->radio_enabled && + iwl_radio_kill_sw_enable_radio(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " + "waiting for uCode\n"); + goto out; + } + + if (!conf->radio_enabled) + iwl_radio_kill_sw_disable_radio(priv); + } + + if (!conf->radio_enabled) { + IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); + goto out; + } + + if (scan_active) + goto out; + + if (memcmp(&priv->active_rxon, + &priv->staging_rxon, sizeof(priv->staging_rxon))) + iwlcore_commit_rxon(priv); + else + IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n"); + + +out: + IWL_DEBUG_MAC80211(priv, "leave\n"); + mutex_unlock(&priv->mutex); + return ret; +} +EXPORT_SYMBOL(iwl_mac_config); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 5dc3306..da8fae5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -278,6 +278,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); +int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f82a9dc..c5644a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3166,8 +3166,6 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) mutex_unlock(&priv->mutex); } -static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); - #define IWL_DELAY_NEXT_SCAN (HZ*2) void iwl3945_post_associate(struct iwl_priv *priv) @@ -3380,108 +3378,6 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -/** - * iwl3945_mac_config - mac80211 config callback - * - * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to - * be set inappropriately and the driver currently sets the hardware up to - * use it whenever needed. - */ -static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - struct ieee80211_conf *conf = &hw->conf; - unsigned long flags; - int ret = 0; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter to channel %d\n", - conf->channel->hw_value); - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - ret = -EIO; - goto out; - } - - if (unlikely(!iwl3945_mod_params.disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); - set_bit(STATUS_CONF_PENDING, &priv->status); - mutex_unlock(&priv->mutex); - return 0; - } - - spin_lock_irqsave(&priv->lock, flags); - - ch_info = iwl_get_channel_info(priv, conf->channel->band, - conf->channel->hw_value); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN(priv, - "Channel %d [%d] is INVALID for this band.\n", - conf->channel->hw_value, conf->channel->band); - IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); - spin_unlock_irqrestore(&priv->lock, flags); - ret = -EINVAL; - goto out; - } - - iwl_set_rxon_channel(priv, conf->channel); - - iwl_set_flags_for_band(priv, conf->channel->band); - - /* The list of supported rates and rate mask can be different - * for each phymode; since the phymode may have changed, reset - * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - -#ifdef IEEE80211_CONF_CHANNEL_SWITCH - if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl3945_hw_channel_switch(priv, conf->channel); - goto out; - } -#endif - - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - if (conf->radio_enabled && - iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " - "waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) { - iwl_radio_kill_sw_disable_radio(priv); - IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); - goto out; - } - } - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF kill\n"); - ret = -EIO; - goto out; - } - - iwl_set_rate(priv); - - if (memcmp(&priv->active_rxon, - &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwlcore_commit_rxon(priv); - else - IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration\n"); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - -out: - clear_bit(STATUS_CONF_PENDING, &priv->status); - mutex_unlock(&priv->mutex); - return ret; -} - static void iwl3945_config_ap(struct iwl_priv *priv) { int rc = 0; @@ -4316,7 +4212,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .stop = iwl3945_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, - .config = iwl3945_mac_config, + .config = iwl_mac_config, .config_interface = iwl3945_mac_config_interface, .configure_filter = iwl_configure_filter, .set_key = iwl3945_mac_set_key, -- cgit v0.10.2 From 60690a6a38cc03142a0c5aaed64cf043e707457d Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:49 -0700 Subject: iwlwifi: add config_ap lib op add config_ap lib op to iwlwifi and iwl3945 in preparation of future 3945 porting actions. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index a854feb..edc0cb3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2952,6 +2952,7 @@ static struct iwl_lib_ops iwl3945_lib = { .send_tx_power = iwl3945_send_tx_power, .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, .post_associate = iwl3945_post_associate, + .config_ap = iwl3945_config_ap, }; static struct iwl_station_mgmt_ops iwl3945_station_mgmt = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 88628b2..4f5473e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -278,6 +278,8 @@ extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv, extern void iwl3945_disable_events(struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv); extern void iwl3945_post_associate(struct iwl_priv *priv); +extern void iwl3945_config_ap(struct iwl_priv *priv); + /** * iwl3945_hw_find_station - Find station id for a given BSSID * @bssid: MAC address of station ID to find diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ab25e6a..e4762e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2333,6 +2333,7 @@ static struct iwl_lib_ops iwl4965_lib = { .update_chain_flags = iwl_update_chain_flags, .temperature = iwl4965_temperature_calib, .post_associate = iwl_post_associate, + .config_ap = iwl_config_ap, }; static struct iwl_ops iwl4965_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cf622a1..5bbb4f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1537,6 +1537,7 @@ struct iwl_lib_ops iwl5000_lib = { .query_addr = iwl5000_eeprom_query_addr, }, .post_associate = iwl_post_associate, + .config_ap = iwl_config_ap, }; struct iwl_ops iwl5000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4640996..97f8322 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2036,7 +2036,7 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static void iwl_config_ap(struct iwl_priv *priv) +void iwl_config_ap(struct iwl_priv *priv) { int ret = 0; unsigned long flags; @@ -2178,7 +2178,7 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, memcpy(priv->bssid, conf->bssid, ETH_ALEN); if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl_config_ap(priv); + iwlcore_config_ap(priv); else { rc = iwlcore_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index da8fae5..af559b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -162,6 +162,7 @@ struct iwl_lib_ops { void (*update_chain_flags)(struct iwl_priv *priv); void (*temperature) (struct iwl_priv *priv); void (*post_associate) (struct iwl_priv *priv); + void (*config_ap) (struct iwl_priv *priv); /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; @@ -279,6 +280,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); +void iwl_config_ap(struct iwl_priv *priv); /***************************************************** * RX handlers. @@ -565,7 +567,10 @@ static inline int iwlcore_commit_rxon(struct iwl_priv *priv) { return priv->cfg->ops->hcmd->commit_rxon(priv); } - +static inline void iwlcore_config_ap(struct iwl_priv *priv) +{ + priv->cfg->ops->lib->config_ap(priv); +} static inline const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) { diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c5644a5..ad6f5ebe 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3378,7 +3378,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static void iwl3945_config_ap(struct iwl_priv *priv) +void iwl3945_config_ap(struct iwl_priv *priv) { int rc = 0; @@ -3515,7 +3515,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, memcpy(priv->bssid, conf->bssid, ETH_ALEN); if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl3945_config_ap(priv); + iwlcore_config_ap(priv); else { rc = iwlcore_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) -- cgit v0.10.2 From 5ee5811e24b20d49ea553fda568433effbab7a62 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:50 -0700 Subject: iwl3945: use iwl_mac_config_interface from iwlwifi 3945 can now use iwl_mac_config_interface from iwlwifi. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 97f8322..edfece6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2099,106 +2099,6 @@ void iwl_config_ap(struct iwl_priv *priv) * clear sta table, add BCAST sta... */ } - -static int iwl_mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - int rc; - - if (conf == NULL) - return -EIO; - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n"); - return 0; - } - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC && - conf->changed & IEEE80211_IFCC_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) - return -ENOMEM; - mutex_lock(&priv->mutex); - rc = iwl_mac_beacon_update(hw, beacon); - mutex_unlock(&priv->mutex); - if (rc) - return rc; - } - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - mutex_lock(&priv->mutex); - - if (conf->bssid) - IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid); - -/* - * very dubious code was here; the probe filtering flag is never set: - * - if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && - !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { - */ - - if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (!conf->bssid) { - conf->bssid = priv->mac_addr; - memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n", - conf->bssid); - } - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = ieee80211_beacon_get(hw, vif); - } - - if (iwl_is_rfkill(priv)) - goto done; - - if (conf->bssid && !is_zero_ether_addr(conf->bssid) && - !is_multicast_ether_addr(conf->bssid)) { - /* If there is currently a HW scan going on in the background - * then we need to cancel it else the RXON below will fail. */ - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress " - "after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - mutex_unlock(&priv->mutex); - return -EAGAIN; - } - memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); - - /* TODO: Audit driver for usage of these members and see - * if mac80211 deprecates them (priv->bssid looks like it - * shouldn't be there, but I haven't scanned the IBSS code - * to verify) - jpk */ - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwlcore_config_ap(priv); - else { - rc = iwlcore_commit_rxon(priv); - if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) - iwl_rxon_add_station( - priv, priv->active_rxon.bssid_addr, 1); - } - - } else { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - } - - done: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - - return 0; -} - static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4369fc8..e8b74fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2579,6 +2579,106 @@ out: } EXPORT_SYMBOL(iwl_mac_config); +int iwl_mac_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + int rc; + + if (conf == NULL) + return -EIO; + + if (priv->vif != vif) { + IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n"); + return 0; + } + + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + conf->changed & IEEE80211_IFCC_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if (!beacon) + return -ENOMEM; + mutex_lock(&priv->mutex); + rc = iwl_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); + if (rc) + return rc; + } + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + mutex_lock(&priv->mutex); + + if (conf->bssid) + IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid); + +/* + * very dubious code was here; the probe filtering flag is never set: + * + if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && + !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + + if (priv->iw_mode == NL80211_IFTYPE_AP) { + if (!conf->bssid) { + conf->bssid = priv->mac_addr; + memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); + IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n", + conf->bssid); + } + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = ieee80211_beacon_get(hw, vif); + } + + if (iwl_is_rfkill(priv)) + goto done; + + if (conf->bssid && !is_zero_ether_addr(conf->bssid) && + !is_multicast_ether_addr(conf->bssid)) { + /* If there is currently a HW scan going on in the background + * then we need to cancel it else the RXON below will fail. */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARN(priv, "Aborted scan still in progress " + "after 100ms\n"); + IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return -EAGAIN; + } + memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); + + /* TODO: Audit driver for usage of these members and see + * if mac80211 deprecates them (priv->bssid looks like it + * shouldn't be there, but I haven't scanned the IBSS code + * to verify) - jpk */ + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + + if (priv->iw_mode == NL80211_IFTYPE_AP) + iwlcore_config_ap(priv); + else { + rc = iwlcore_commit_rxon(priv); + if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) + iwl_rxon_add_station( + priv, priv->active_rxon.bssid_addr, 1); + } + + } else { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv); + } + + done: + IWL_DEBUG_MAC80211(priv, "leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} +EXPORT_SYMBOL(iwl_mac_config_interface); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index af559b0..92a42c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -281,6 +281,9 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); void iwl_config_ap(struct iwl_priv *priv); +int iwl_mac_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ad6f5ebe..3461768 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3436,106 +3436,6 @@ void iwl3945_config_ap(struct iwl_priv *priv) * clear sta table, add BCAST sta... */ } -static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - int rc; - - if (conf == NULL) - return -EIO; - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n"); - return 0; - } - - /* handle this temporarily here */ - if (priv->iw_mode == NL80211_IFTYPE_ADHOC && - conf->changed & IEEE80211_IFCC_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) - return -ENOMEM; - mutex_lock(&priv->mutex); - rc = iwl_mac_beacon_update(hw, beacon); - mutex_unlock(&priv->mutex); - if (rc) - return rc; - } - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - mutex_lock(&priv->mutex); - - if (conf->bssid) - IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid); - -/* - * very dubious code was here; the probe filtering flag is never set: - * - if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && - !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { - */ - - if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (!conf->bssid) { - conf->bssid = priv->mac_addr; - memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n", - conf->bssid); - } - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = ieee80211_beacon_get(hw, vif); - } - - if (iwl_is_rfkill(priv)) - goto done; - - if (conf->bssid && !is_zero_ether_addr(conf->bssid) && - !is_multicast_ether_addr(conf->bssid)) { - /* If there is currently a HW scan going on in the background - * then we need to cancel it else the RXON below will fail. */ - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress " - "after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving:scan abort failed\n"); - mutex_unlock(&priv->mutex); - return -EAGAIN; - } - memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); - - /* TODO: Audit driver for usage of these members and see - * if mac80211 deprecates them (priv->bssid looks like it - * shouldn't be there, but I haven't scanned the IBSS code - * to verify) - jpk */ - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwlcore_config_ap(priv); - else { - rc = iwlcore_commit_rxon(priv); - if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) - priv->cfg->ops->smgmt->add_station(priv, - priv->active_rxon.bssid_addr, 1, 0, NULL); - } - - } else { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - } - - done: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - - return 0; -} - static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -4213,7 +4113,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .config_interface = iwl3945_mac_config_interface, + .config_interface = iwl_mac_config_interface, .configure_filter = iwl_configure_filter, .set_key = iwl3945_mac_set_key, .get_tx_stats = iwl3945_mac_get_tx_stats, -- cgit v0.10.2 From aa89f31e708d469f5dd824c59c98e4856a2e3572 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:51 -0700 Subject: iwl3945: use iwl_mac_get_tx_stats from iwlwifi 3945 can now use iwl_mac_get_tx_stats from iwlwifi. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index edfece6..3ebf80f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2223,41 +2223,6 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, return 0; } -static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) -{ - struct iwl_priv *priv = hw->priv; - int i, avail; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - for (i = 0; i < AC_NUM; i++) { - txq = &priv->txq[i]; - q = &txq->q; - avail = iwl_queue_space(q); - - stats[i].len = q->n_window - avail; - stats[i].limit = q->n_window - q->high_mark; - stats[i].count = q->n_window; - - } - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return 0; -} - static int iwl_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e8b74fc..144630b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2679,6 +2679,42 @@ int iwl_mac_config_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_mac_config_interface); +int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats[i].len = q->n_window - avail; + stats[i].limit = q->n_window - q->high_mark; + stats[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return 0; +} +EXPORT_SYMBOL(iwl_mac_get_tx_stats); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 92a42c8..7e0d0ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -284,6 +284,8 @@ void iwl_config_ap(struct iwl_priv *priv); int iwl_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); +int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3461768..07883b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3494,41 +3494,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) -{ - struct iwl_priv *priv = hw->priv; - int i, avail; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - for (i = 0; i < AC_NUM; i++) { - txq = &priv->txq[i]; - q = &txq->q; - avail = iwl_queue_space(q); - - stats[i].len = q->n_window - avail; - stats[i].limit = q->n_window - q->high_mark; - stats[i].count = q->n_window; - - } - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return 0; -} - static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -4116,7 +4081,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .config_interface = iwl_mac_config_interface, .configure_filter = iwl_configure_filter, .set_key = iwl3945_mac_set_key, - .get_tx_stats = iwl3945_mac_get_tx_stats, + .get_tx_stats = iwl_mac_get_tx_stats, .conf_tx = iwl_mac_conf_tx, .reset_tsf = iwl3945_mac_reset_tsf, .bss_info_changed = iwl_bss_info_changed, -- cgit v0.10.2 From bd564261d7dd3660f7a5ba308a867c6bb23de6a2 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 8 Apr 2009 11:26:52 -0700 Subject: iwl3945: use iwl_mac_reset_tsf from iwlwifi 3945 can now use iwl_mac_reset_tsf from iwlwifi. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3ebf80f..9dda3d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2235,81 +2235,6 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = 0; - priv->assoc_capability = 0; - priv->assoc_station_added = 0; - - /* new association get rid of ibss beacon skb */ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = NULL; - - priv->beacon_int = priv->hw->conf.beacon_int; - priv->timestamp = 0; - if ((priv->iw_mode == NL80211_IFTYPE_STATION)) - priv->beacon_int = 0; - - spin_unlock_irqrestore(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* we are restarting association process - * clear RXON_FILTER_ASSOC_MSK bit - */ - if (priv->iw_mode != NL80211_IFTYPE_AP) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - } - - iwl_power_update_mode(priv, 0); - - /* Per mac80211.h: This is only used in IBSS mode... */ - 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(priv, "leave - not in IBSS\n"); - mutex_unlock(&priv->mutex); - return; - } - - iwl_set_rate(priv); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - - /***************************************************************************** * * sysfs attributes diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 144630b..c523cc3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2715,6 +2715,81 @@ int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_mac_get_tx_stats); +void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_reset_qos(priv); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = 0; + priv->assoc_capability = 0; + priv->assoc_station_added = 0; + + /* new association get rid of ibss beacon skb */ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = NULL; + + priv->beacon_int = priv->hw->conf.beacon_int; + priv->timestamp = 0; + if ((priv->iw_mode == NL80211_IFTYPE_STATION)) + priv->beacon_int = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + /* we are restarting association process + * clear RXON_FILTER_ASSOC_MSK bit + */ + if (priv->iw_mode != NL80211_IFTYPE_AP) { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv); + } + + iwl_power_update_mode(priv, 0); + + /* Per mac80211.h: This is only used in IBSS mode... */ + 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(priv, "leave - not in IBSS\n"); + mutex_unlock(&priv->mutex); + return; + } + + iwl_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} +EXPORT_SYMBOL(iwl_mac_reset_tsf); + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7e0d0ed..df90c26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -286,6 +286,7 @@ int iwl_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf); int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); +void iwl_mac_reset_tsf(struct ieee80211_hw *hw); /***************************************************** * RX handlers. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 07883b2..ed49755 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3494,64 +3494,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - iwl_reset_qos(priv); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = 0; - priv->assoc_capability = 0; - - /* new association get rid of ibss beacon skb */ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = NULL; - - priv->beacon_int = priv->hw->conf.beacon_int; - priv->timestamp = 0; - if ((priv->iw_mode == NL80211_IFTYPE_STATION)) - priv->beacon_int = 0; - - spin_unlock_irqrestore(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* we are restarting association process - * clear RXON_FILTER_ASSOC_MSK bit - */ - if (priv->iw_mode != NL80211_IFTYPE_AP) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - } - - /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { - - IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n"); - mutex_unlock(&priv->mutex); - return; - } - - iwl_set_rate(priv); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - -} - /***************************************************************************** * * sysfs attributes @@ -4083,7 +4025,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .set_key = iwl3945_mac_set_key, .get_tx_stats = iwl_mac_get_tx_stats, .conf_tx = iwl_mac_conf_tx, - .reset_tsf = iwl3945_mac_reset_tsf, + .reset_tsf = iwl_mac_reset_tsf, .bss_info_changed = iwl_bss_info_changed, .hw_scan = iwl_mac_hw_scan }; -- cgit v0.10.2 From 12b9681721adb34b7ec42aa973ab96692998153d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 8 Apr 2009 11:39:27 -0700 Subject: iwlwifi: Display decoded rate/mcs information This patch adding MCS information in rate_scale_table, it help for debugging rate scaling algorithm, easy to understand what is the current rate scale table and matching modulation, plus the last mcs used for tx. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index b1818a3..786b11d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -167,6 +167,8 @@ struct iwl_lq_sta { /* used to be in sta_info */ int last_txrate_idx; + /* last tx rate_n_flags */ + u32 last_rate_n_flags; }; static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -249,6 +251,23 @@ static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300 }; +/* mbps, mcs */ +const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { + {"1", ""}, + {"2", ""}, + {"5.5", ""}, + {"11", ""}, + {"6", "BPSK 1/2"}, + {"9", "BPSK 1/2"}, + {"12", "QPSK 1/2"}, + {"18", "QPSK 3/4"}, + {"24", "16QAM 1/2"}, + {"36", "16QAM 3/4"}, + {"48", "64QAM 2/3"}, + {"54", "64QAM 3/4"}, + {"60", "64QAM 5/6"} +}; + static inline u8 rs_extract_rate(u32 rate_n_flags) { return (u8)(rate_n_flags & 0xFF); @@ -919,6 +938,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, * else look up the rate that was, finally, successful. */ tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + lq_sta->last_rate_n_flags = tx_rate; rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ @@ -2826,6 +2846,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char *buff; int desc = 0; int i = 0; + int index = 0; ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; @@ -2857,6 +2878,8 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (tbl->is_fat) ? "40MHz" : "20MHz"); desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : ""); } + desc += sprintf(buff+desc, "last tx rate=0x%X\n", + lq_sta->last_rate_n_flags); desc += sprintf(buff+desc, "general:" "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", lq_sta->lq.general_params.flags, @@ -2877,10 +2900,19 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, lq_sta->lq.general_params.start_rate_index[2], lq_sta->lq.general_params.start_rate_index[3]); - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) - desc += sprintf(buff+desc, " rate[%d] 0x%X\n", - i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + index = iwl_hwrate_to_plcp_idx( + le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); + if (is_legacy(tbl->lq_type)) { + desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n", + i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags), + iwl_rate_mcs[index].mbps); + } else { + desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n", + i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags), + iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs); + } + } ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); kfree(buff); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 9cd90ba..f875136 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -325,6 +325,13 @@ enum iwl_table_type { #define ANT_BC (ANT_B | ANT_C) #define ANT_ABC (ANT_AB | ANT_C) +#define IWL_MAX_MCS_DISPLAY_SIZE 12 + +struct iwl_rate_mcs_info { + char mbps[IWL_MAX_MCS_DISPLAY_SIZE]; + char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; +}; + static inline u8 num_of_ant(u8 mask) { return !!((mask) & ANT_A) + -- cgit v0.10.2 From ddfcf999274838a8dfb0ccf8e69fc1e50eea3341 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Wed, 8 Apr 2009 11:39:28 -0700 Subject: iwlwifi: do not set dual_stream_ant_msk for 3 streams This patch fixes a bug introduced by commit "iwlwifi: adding MIMO3 support in rate scaling". We should not set the dual_stream_ant_msk (for 2x2 MIMO) when using a 3x3 rate, this will cause a SYSASSERT in uCode. Note: there is no triple_stream_ant_msk, because all three antennas are used. Signed-off-by: Daniel C Halperin Acked-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 786b11d..98b6b37 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2666,9 +2666,6 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, } else if (num_of_ant(tbl_type.ant_type) == 2) { lq_cmd->general_params.dual_stream_ant_msk = tbl_type.ant_type; - } else if (num_of_ant(tbl_type.ant_type) == 3) { - lq_cmd->general_params.dual_stream_ant_msk = - tbl_type.ant_type; } /* otherwise we don't modify the existing value */ index++; -- cgit v0.10.2 From 3a6502927f763f05069d1b84af3a05b38eb1a818 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Wed, 8 Apr 2009 11:39:29 -0700 Subject: iwlagn: Sync rxon active with changes We need to sync rxon_active with changes after we commit rxon_assoc, without rxon_active will still have the old data that cause iwl_send_rxon_assoc to fail with no change in rxon command. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c523cc3..8f121fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2238,6 +2238,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct iwl_priv *priv = hw->priv; + int ret; IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); @@ -2292,7 +2293,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, } } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { IWL_DEBUG_MAC80211(priv, "Associated Changes %d\n", changes); - iwl_send_rxon_assoc(priv); + ret = iwl_send_rxon_assoc(priv); + if (!ret) + /* Sync active_rxon with latest change. */ + memcpy((void *)&priv->active_rxon, + &priv->staging_rxon, + sizeof(struct iwl_rxon_cmd)); } } -- cgit v0.10.2 From c2105fa7b68547a414095cfbf59bf513a9aae3ce Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Wed, 8 Apr 2009 11:39:30 -0700 Subject: iwlwifi: check triple_stream_basic_rates in iwl_full_rxon_required For completeness, we should also make sure that the 3x3 MIMO rates are also checked when seeing if one rxon struct matches another. Signed-off-by: Daniel C Halperin Acked-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8f121fa..5877293 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -735,6 +735,8 @@ int iwl_full_rxon_required(struct iwl_priv *priv) priv->active_rxon.ofdm_ht_single_stream_basic_rates) || (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || + (priv->staging_rxon.ofdm_ht_triple_stream_basic_rates != + priv->active_rxon.ofdm_ht_triple_stream_basic_rates) || (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) return 1; -- cgit v0.10.2 From 1620108910b07bc41f4ad462ca56e899faf7e61a Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Wed, 8 Apr 2009 11:39:31 -0700 Subject: iwlcore: fix channel display in debugfs Fix displaying of wrong channel information when user query channel through debugfs Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index af1d121..5b8c839 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -389,7 +389,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, channels[i].max_power, channels[i].flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", - (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) || (channels[i].flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", -- cgit v0.10.2 From a83b9141b540f96dd59409c6487828e880113a29 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 8 Apr 2009 11:39:32 -0700 Subject: iwlwifi: adding interrupt counter in debugfs for debugging This patch adds interrupt statistics report to debugfs, this can help to understand number of interrupts happened which including HW/SW error for easier and better debugging. in /sys/kernel/debug/ieee80211/phyN/iwlagn/data directory use "cat interrupt" to view the current interrupt counter use "echo 0 > interrupt" to clear interrupt counter Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 9dda3d5..12de63e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -911,6 +911,7 @@ void iwl_rx_handle(struct iwl_priv *priv) IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ IWL_DEBUG_RX(priv, @@ -1035,6 +1036,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); + priv->isr_stats.hw++; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -1047,13 +1049,17 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) + if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " "the frame/frames.\n"); + priv->isr_stats.sch++; + } /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) + if (inta & CSR_INT_BIT_ALIVE) { IWL_DEBUG_ISR(priv, "Alive interrupt\n"); + priv->isr_stats.alive++; + } } #endif /* Safely ignore these bits for debug checks below */ @@ -1069,6 +1075,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio" : "enable radio"); + priv->isr_stats.rfkill++; + /* driver only loads ucode once setting the interface up. * the driver allows loading the ucode even if the radio * is killed. Hence update the killswitch state here. The @@ -1088,6 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Chip got too hot and stopped itself */ if (inta & CSR_INT_BIT_CT_KILL) { IWL_ERR(priv, "Microcode CT kill error detected.\n"); + priv->isr_stats.ctkill++; handled |= CSR_INT_BIT_CT_KILL; } @@ -1095,6 +1104,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERR(priv, "Microcode SW error detected. " " Restarting 0x%X.\n", inta); + priv->isr_stats.sw++; + priv->isr_stats.sw_err = inta; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_SW_ERR; } @@ -1110,6 +1121,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) iwl_txq_update_write_ptr(priv, &priv->txq[4]); iwl_txq_update_write_ptr(priv, &priv->txq[5]); + priv->isr_stats.wakeup++; + handled |= CSR_INT_BIT_WAKEUP; } @@ -1118,19 +1131,23 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) * notifications from uCode come through here*/ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl_rx_handle(priv); + priv->isr_stats.rx++; handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } if (inta & CSR_INT_BIT_FH_TX) { IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; /* FH finished to write, send event */ priv->ucode_write_complete = 1; wake_up_interruptible(&priv->wait_command_queue); } - if (inta & ~handled) + if (inta & ~handled) { IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); + priv->isr_stats.unhandled++; + } if (inta & ~CSR_INI_SET_MASK) { IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", @@ -1155,6 +1172,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } + /****************************************************************************** * * uCode download functions @@ -1983,6 +2001,8 @@ static int iwl_mac_start(struct ieee80211_hw *hw) out: priv->is_open = 1; + /* default to MONITOR mode */ + priv->iw_mode = NL80211_IFTYPE_MONITOR; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5877293..f231752 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2119,6 +2119,12 @@ void iwl_rx_reply_error(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_reply_error); +void iwl_clear_isr_stats(struct iwl_priv *priv) +{ + memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); +} +EXPORT_SYMBOL(iwl_clear_isr_stats); + int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index df90c26..8773d73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -480,6 +480,7 @@ int iwl_pci_resume(struct pci_dev *pdev); ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); +void iwl_clear_isr_stats(struct iwl_priv *priv); /***************************************************** * GEOS diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 65d1a7f..db06980 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -75,6 +75,7 @@ struct iwl_debugfs { struct dentry *file_log_event; struct dentry *file_channels; struct dentry *file_status; + struct dentry *file_interrupt; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 5b8c839..ffc4be3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -473,6 +473,95 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_interrupt_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = 24 * 64; /* 24 items * 64 char per item */ + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, + "Interrupt Statistics Report:\n"); + + pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n", + priv->isr_stats.hw); + pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n", + priv->isr_stats.sw); + if (priv->isr_stats.sw > 0) { + pos += scnprintf(buf + pos, bufsz - pos, + "\tLast Restarting Code: 0x%X\n", + priv->isr_stats.sw_err); + } +#ifdef CONFIG_IWLWIFI_DEBUG + pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n", + priv->isr_stats.sch); + pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n", + priv->isr_stats.alive); +#endif + pos += scnprintf(buf + pos, bufsz - pos, + "HW RF KILL switch toggled:\t %u\n", + priv->isr_stats.rfkill); + + pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n", + priv->isr_stats.ctkill); + + pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n", + priv->isr_stats.wakeup); + + pos += scnprintf(buf + pos, bufsz - pos, + "Rx command responses:\t\t %u\n", + priv->isr_stats.rx); + for (cnt = 0; cnt < REPLY_MAX; cnt++) { + if (priv->isr_stats.rx_handlers[cnt] > 0) + pos += scnprintf(buf + pos, bufsz - pos, + "\tRx handler[%36s]:\t\t %u\n", + get_cmd_string(cnt), + priv->isr_stats.rx_handlers[cnt]); + } + + pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n", + priv->isr_stats.tx); + + pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n", + priv->isr_stats.unhandled); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_interrupt_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + u32 reset_flag; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &reset_flag) != 1) + return -EFAULT; + if (reset_flag == 0) + iwl_clear_isr_stats(priv); + + return count; +} + + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(eeprom); @@ -481,6 +570,7 @@ DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); +DEBUGFS_READ_WRITE_FILE_OPS(interrupt); /* * Create the debugfs files and directories @@ -516,6 +606,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(tx_statistics, data); DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(status, data); + DEBUGFS_ADD_FILE(interrupt, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -546,6 +637,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 59930f3..0922e33 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -819,6 +819,21 @@ enum { MEASUREMENT_ACTIVE = (1 << 1), }; +/* interrupt statistics */ +struct isr_statistics { + u32 hw; + u32 sw; + u32 sw_err; + u32 sch; + u32 alive; + u32 rfkill; + u32 ctkill; + u32 wakeup; + u32 rx; + u32 rx_handlers[REPLY_MAX]; + u32 tx; + u32 unhandled; +}; #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ @@ -975,6 +990,9 @@ struct iwl_priv { u64 bytes; } tx_stats[3], rx_stats[3]; + /* counts interrupts */ + struct isr_statistics isr_stats; + struct iwl_power_mgr power_data; struct iwl_notif_statistics statistics; -- cgit v0.10.2 From a2caba6b5fc4e046edfefb1db82f52b939b526a5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 14 Apr 2009 11:45:57 -0400 Subject: libertas: fix warning about %zd: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/libertas/rx.c: In function ‘lbs_process_rxed_packet’: drivers/net/wireless/libertas/rx.c:184: warning: format ‘%zd’ expects type ‘signed size_t’, but argument 4 has type ‘__le32’ drivers/net/wireless/libertas/rx.c:184: warning: format ‘%zd’ expects type ‘signed size_t’, but argument 5 has type ‘unsigned int’ Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index bd845d0..65f02cc 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -182,8 +182,8 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) } lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n", - skb->len, le32_to_cpu(p_rx_pd->pkt_ptr), - skb->len - le32_to_cpu(p_rx_pd->pkt_ptr)); + skb->len, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr), + skb->len - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); -- cgit v0.10.2 From 137907287789607f2a2586ad625e7b8c646b3425 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Apr 2009 21:26:27 +0200 Subject: b43: Remove unnecessary MMIO in interrupt hotpath This removes unnecessary MMIO accesses in the interrupt hotpath. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index cc1db7e..4e8ad84 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -778,8 +778,8 @@ struct b43_wldev { /* Reason code of the last interrupt. */ u32 irq_reason; u32 dma_reason[6]; - /* saved irq enable/disable state bitfield. */ - u32 irq_savedstate; + /* The currently active generic-interrupt mask. */ + u32 irq_mask; /* Link Quality calculation context. */ struct b43_noise_calculation noisecalc; /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 09e0c60..a97c6ff 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -673,32 +673,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) b43_set_slot_time(dev, 20); } -/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask) -{ - u32 old_mask; - - old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask); - - return old_mask; -} - -/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask) -{ - u32 old_mask; - - old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask); - - return old_mask; -} - /* Synchronize IRQ top- and bottom-half. * IRQs must be masked before calling this. * This must not be called with the irq_lock held. @@ -1593,7 +1567,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) /* This is the bottom half of the asynchronous beacon update. */ /* Ignore interrupt in the future. */ - dev->irq_savedstate &= ~B43_IRQ_BEACON; + dev->irq_mask &= ~B43_IRQ_BEACON; cmd = b43_read32(dev, B43_MMIO_MACCMD); beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID); @@ -1602,7 +1576,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) /* Schedule interrupt manually, if busy. */ if (beacon0_valid && beacon1_valid) { b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); - dev->irq_savedstate |= B43_IRQ_BEACON; + dev->irq_mask |= B43_IRQ_BEACON; return; } @@ -1641,11 +1615,9 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { spin_lock_irq(&wl->irq_lock); /* update beacon right away or defer to irq */ - dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); handle_irq_beacon(dev); /* The handler might have updated the IRQ mask. */ - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, - dev->irq_savedstate); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irq(&wl->irq_lock); } @@ -1879,7 +1851,7 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); - b43_interrupt_enable(dev, dev->irq_savedstate); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } @@ -1893,7 +1865,9 @@ static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); +/* Unused ring b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); +*/ } /* Interrupt handler top-half */ @@ -1903,18 +1877,19 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) struct b43_wldev *dev = dev_id; u32 reason; - if (!dev) - return IRQ_NONE; + B43_WARN_ON(!dev); spin_lock(&dev->wl->irq_lock); - if (b43_status(dev) < B43_STAT_STARTED) + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) { + /* This can only happen on shared IRQ lines. */ goto out; + } reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ goto out; ret = IRQ_HANDLED; - reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + reason &= dev->irq_mask; if (!reason) goto out; @@ -1928,16 +1903,18 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) & 0x0001DC00; dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON) & 0x0000DC00; +/* Unused ring dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON) & 0x0000DC00; +*/ b43_interrupt_ack(dev, reason); /* disable all IRQs. They are enabled again in the bottom half. */ - dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); /* save the reason code and call our bottom half. */ dev->irq_reason = reason; tasklet_schedule(&dev->isr_tasklet); - out: +out: mmiowb(); spin_unlock(&dev->wl->irq_lock); @@ -3799,7 +3776,7 @@ static void b43_wireless_core_stop(struct b43_wldev *dev) * setting the status to INITIALIZED, as the interrupt handler * won't care about IRQs then. */ spin_lock_irqsave(&wl->irq_lock, flags); - dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ spin_unlock_irqrestore(&wl->irq_lock, flags); b43_synchronize_irq(dev); @@ -3840,7 +3817,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev) /* Start data flow (TX/RX). */ b43_mac_enable(dev); - b43_interrupt_enable(dev, dev->irq_savedstate); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); /* Start maintainance work */ b43_periodic_tasks_setup(dev); @@ -4003,9 +3980,9 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev) /* IRQ related flags */ dev->irq_reason = 0; memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); - dev->irq_savedstate = B43_IRQ_MASKTEMPLATE; + dev->irq_mask = B43_IRQ_MASKTEMPLATE; if (b43_modparam_verbose < B43_VERBOSITY_DEBUG) - dev->irq_savedstate &= ~B43_IRQ_PHY_TXERR; + dev->irq_mask &= ~B43_IRQ_PHY_TXERR; dev->mac_suspended = 1; -- cgit v0.10.2 From 492301fb5d12e4a77a1010ad2b6f1ed306014123 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 9 Apr 2009 22:14:19 -0500 Subject: rfkill: Fix broken rfkill LED in 2.6.30-rc1 The rfkill system fails to issue a LED trigger event when the rfkill state changes. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index df1269c..e2d4510 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -96,6 +96,7 @@ static void update_rfkill_state(struct rfkill *rfkill) } mutex_unlock(&rfkill->mutex); } + rfkill_led_trigger(rfkill, rfkill->state); } /** @@ -136,8 +137,9 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, oldstate = rfkill->state; if (rfkill->get_state && !force && - !rfkill->get_state(rfkill->data, &newstate)) + !rfkill->get_state(rfkill->data, &newstate)) { rfkill->state = newstate; + } switch (state) { case RFKILL_STATE_HARD_BLOCKED: @@ -172,6 +174,7 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, if (force || rfkill->state != oldstate) rfkill_uevent(rfkill); + rfkill_led_trigger(rfkill, rfkill->state); return retval; } @@ -204,6 +207,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, mutex_lock(&rfkill->mutex); rfkill_toggle_radio(rfkill, state, 0); mutex_unlock(&rfkill->mutex); + rfkill_led_trigger(rfkill, rfkill->state); } } } @@ -256,6 +260,7 @@ void rfkill_epo(void) RFKILL_STATE_SOFT_BLOCKED; } mutex_unlock(&rfkill_global_mutex); + rfkill_led_trigger(rfkill, rfkill->state); } EXPORT_SYMBOL_GPL(rfkill_epo); @@ -358,6 +363,7 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) rfkill_uevent(rfkill); mutex_unlock(&rfkill->mutex); + rfkill_led_trigger(rfkill, rfkill->state); return 0; } @@ -520,6 +526,7 @@ static int rfkill_resume(struct device *dev) 1); mutex_unlock(&rfkill->mutex); + rfkill_led_trigger(rfkill, rfkill->state); } return 0; -- cgit v0.10.2 From 6dfe9a884fec67070fc7502ad82f7eb328950b72 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 11 Apr 2009 03:58:01 +0200 Subject: p54: utilize all available key slots for decryption offload This patch takes care of outstanding TODOs: /* TODO: some devices have 4 more free slots for rx keys */ Now the driver can utilize all available key slots instead of just 4. Obviously, this helps most in AP/IBSS(/MESH) mode, when we have to use more different keys. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index d6354fa..7fda1a9 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -186,6 +186,7 @@ struct p54_common { /* cryptographic engine information */ u8 privacy_caps; u8 rx_keycache_size; + unsigned long *used_rxkeys; /* LED management */ #ifdef CONFIG_MAC80211_LEDS diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index cb49058..7bd4fdf 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -249,7 +249,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) dev->queues = P54_QUEUE_AC_NUM; } - if (!modparam_nohwcrypt) + if (!modparam_nohwcrypt) { printk(KERN_INFO "%s: cryptographic accelerator " "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(dev->wiphy), @@ -259,6 +259,26 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? "YES" : "no"); + if (priv->rx_keycache_size) { + /* + * NOTE: + * + * The firmware provides at most 255 (0 - 254) slots + * for keys which are then used to offload decryption. + * As a result the 255 entry (aka 0xff) can be used + * safely by the driver to mark keys that didn't fit + * into the full cache. This trick saves us from + * keeping a extra list for uploaded keys. + */ + + priv->used_rxkeys = kzalloc(BITS_TO_LONGS( + priv->rx_keycache_size), GFP_KERNEL); + + if (!priv->used_rxkeys) + return -ENOMEM; + } + } + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -2355,61 +2375,84 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_keycache *rxkey; + int slot, ret = 0; u8 algo = 0; if (modparam_nohwcrypt) return -EOPNOTSUPP; - if (cmd == DISABLE_KEY) - algo = 0; - else { + mutex_lock(&priv->conf_mutex); + if (cmd == SET_KEY) { switch (key->alg) { case ALG_TKIP: if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | - BR_DESC_PRIV_CAP_TKIP))) - return -EOPNOTSUPP; + BR_DESC_PRIV_CAP_TKIP))) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_TKIPMICHAEL; break; case ALG_WEP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) - return -EOPNOTSUPP; + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_WEP; break; case ALG_CCMP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) - return -EOPNOTSUPP; + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_AESCCMP; break; default: - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto out_unlock; } - } + slot = bitmap_find_free_region(priv->used_rxkeys, + priv->rx_keycache_size, 0); - if (key->keyidx > priv->rx_keycache_size) { - /* - * The device supports the choosen algorithm, but the firmware - * does not provide enough key slots to store all of them. - * So, incoming frames have to be decoded by the mac80211 stack, - * but we can still offload encryption for outgoing frames. - */ + if (slot < 0) { + /* + * The device supports the choosen algorithm, but the + * firmware does not provide enough key slots to store + * all of them. + * But encryption offload for outgoing frames is always + * possible, so we just pretend that the upload was + * successful and do the decryption in software. + */ - return 0; + /* mark the key as invalid. */ + key->hw_key_idx = 0xff; + goto out_unlock; + } + } else { + slot = key->hw_key_idx; + + if (slot == 0xff) { + /* This key was not uploaded into the rx key cache. */ + + goto out_unlock; + } + + bitmap_release_region(priv->used_rxkeys, slot, 0); + algo = 0; } - mutex_lock(&priv->conf_mutex); skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), - P54_CONTROL_TYPE_RX_KEYCACHE, GFP_ATOMIC); + P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); if (!skb) { - mutex_unlock(&priv->conf_mutex); - return -ENOMEM; + bitmap_release_region(priv->used_rxkeys, slot, 0); + ret = -ENOSPC; + goto out_unlock; } - /* TODO: some devices have 4 more free slots for rx keys */ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); - rxkey->entry = key->keyidx; + rxkey->entry = slot; rxkey->key_id = key->keyidx; rxkey->key_type = algo; if (sta) @@ -2427,8 +2470,11 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, } priv->tx(dev, skb); + key->hw_key_idx = slot; + +out_unlock: mutex_unlock(&priv->conf_mutex); - return 0; + return ret; } #ifdef CONFIG_P54_LEDS @@ -2662,6 +2708,7 @@ void p54_free_common(struct ieee80211_hw *dev) kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); + kfree(priv->used_rxkeys); #ifdef CONFIG_P54_LEDS p54_unregister_leds(dev); -- cgit v0.10.2 From 4312a86b6840bca503603e918996b139fa3293ba Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 11 Apr 2009 03:58:14 +0200 Subject: p54: remove obsolet signal quality calculation The signal quality percentage is now calculated by mac80211 stack. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 7bd4fdf..b18fc93 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -769,8 +769,6 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); rx_status.noise = priv->noise; - /* XX correct? */ - rx_status.qual = (100 * hdr->rssi) / 127; if (hdr->rate & 0x10) rx_status.flag |= RX_FLAG_SHORTPRE; if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) -- cgit v0.10.2 From 7edfab7adef45a09b459cb7f5957f476108f5e77 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 11 Apr 2009 13:32:46 +0200 Subject: cfg80211: convert mutex assert to macro That will make the various cases where the WARN_ON can happen distinguishable. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.h b/net/wireless/core.h index fcee83a..02668b02 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -73,10 +73,7 @@ bool wiphy_idx_valid(int wiphy_idx) extern struct mutex cfg80211_mutex; extern struct list_head cfg80211_drv_list; -static inline void assert_cfg80211_lock(void) -{ - WARN_ON(!mutex_is_locked(&cfg80211_mutex)); -} +#define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) /* * You can use this to mark a wiphy_idx as not having an associated wiphy. -- cgit v0.10.2 From 7858e07b7ccf1d2fd5898a405c93d022d3f1f42d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 11 Apr 2009 11:25:24 -0500 Subject: b43legacy: Fixes for beaconing This patch ports the beaconing fixes from commit a82d992261f "b43: Beaconing fixes" to b43legacy. Basically it prevents the card from triggering the beacon IRQ over and over again. Signed-off-by: Larry Finger Acked-by: Michael Buesch Tested-by: David Ellingsworth Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 4cdde4a..ad4794a 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -59,7 +59,8 @@ #define B43legacy_MMIO_XMITSTAT_1 0x174 #define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ #define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ - +#define B43legacy_MMIO_TSF_CFP_REP 0x188 +#define B43legacy_MMIO_TSF_CFP_START 0x18C /* 32-bit DMA */ #define B43legacy_MMIO_DMA32_BASE0 0x200 #define B43legacy_MMIO_DMA32_BASE1 0x220 @@ -616,6 +617,7 @@ struct b43legacy_wl { struct sk_buff *current_beacon; bool beacon0_uploaded; bool beacon1_uploaded; + struct work_struct beacon_update_trigger; }; /* Pointers to the firmware data and meta information about it. */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 81dbbc1..4f3f016 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1013,7 +1013,8 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, b43legacywarn(dev->wl, "Did not find a valid TIM IE in the " "beacon template packet. AP or IBSS operation " "may be broken.\n"); - } + } else + b43legacydbg(dev->wl, "Updated beacon template\n"); } static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, @@ -1133,6 +1134,27 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, kfree(probe_resp_data); } +static void b43legacy_beacon_update_trigger_work(struct work_struct *work) +{ + struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl, + beacon_update_trigger); + struct b43legacy_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) { + /* Force the microcode to trigger the + * beacon update bottom-half IRQ. */ + spin_lock_irq(&wl->irq_lock); + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, + b43legacy_read32(dev, B43legacy_MMIO_MACCMD) + | B43legacy_MACCMD_BEACON0_VALID + | B43legacy_MACCMD_BEACON1_VALID); + spin_unlock_irq(&wl->irq_lock); + } + mutex_unlock(&wl->mutex); +} + /* Asynchronously update the packet templates in template RAM. * Locking: Requires wl->irq_lock to be locked. */ static void b43legacy_update_templates(struct b43legacy_wl *wl) @@ -1156,25 +1178,31 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) wl->current_beacon = beacon; wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; + queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); } static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, u16 beacon_int) { b43legacy_time_lock(dev); - if (dev->dev->id.revision >= 3) - b43legacy_write32(dev, 0x188, (beacon_int << 16)); - else { + if (dev->dev->id.revision >= 3) { + b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_REP, + (beacon_int << 16)); + b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_START, + (beacon_int << 10)); + } else { b43legacy_write16(dev, 0x606, (beacon_int >> 6)); b43legacy_write16(dev, 0x610, beacon_int); } b43legacy_time_unlock(dev); + b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } static void handle_irq_beacon(struct b43legacy_wldev *dev) { struct b43legacy_wl *wl = dev->wl; u32 cmd; + u32 beacon0_valid, beacon1_valid; if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) return; @@ -1182,7 +1210,11 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) /* This is the bottom half of the asynchronous beacon update. */ cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); - if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) { + beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID); + beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID); + cmd &= ~(B43legacy_MACCMD_BEACON0_VALID | B43legacy_MACCMD_BEACON1_VALID); + + if (!beacon0_valid) { if (!wl->beacon0_uploaded) { b43legacy_write_beacon_template(dev, 0x68, B43legacy_SHM_SH_BTL0, @@ -1193,8 +1225,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) wl->beacon0_uploaded = 1; } cmd |= B43legacy_MACCMD_BEACON0_VALID; - } - if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) { + } else if (!beacon1_valid) { if (!wl->beacon1_uploaded) { b43legacy_write_beacon_template(dev, 0x468, B43legacy_SHM_SH_BTL1, @@ -3435,6 +3466,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) struct b43legacy_wldev *dev = wl->current_dev; b43legacy_rfkill_exit(dev); + cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) @@ -3766,6 +3798,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) spin_lock_init(&wl->leds_lock); mutex_init(&wl->mutex); INIT_LIST_HEAD(&wl->devlist); + INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); ssb_set_devtypedata(dev, wl); b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); -- cgit v0.10.2 From 2d1f96dd90a20c25243cc3b13e9f21d72f00aba0 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 11 Apr 2009 11:26:01 -0500 Subject: b43legacy: Clean up beacon IRQ This patch ports commit c97a4ccc1fad35d3 "b43: Fix beacon BH update" to b43legacy. It fixes beacon updating in the bottomhalf. In case the device is busy, we will defer to later in the IRQ handler. Signed-off-by: Larry Finger Acked-by: Michael Buesch Tested-by: David Ellingsworth Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index ad4794a..da59ef0 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -259,7 +259,6 @@ #define B43legacy_IRQ_ALL 0xFFFFFFFF #define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \ - B43legacy_IRQ_BEACON | \ B43legacy_IRQ_TBTT_INDI | \ B43legacy_IRQ_ATIM_END | \ B43legacy_IRQ_PMQ | \ @@ -617,6 +616,7 @@ struct b43legacy_wl { struct sk_buff *current_beacon; bool beacon0_uploaded; bool beacon1_uploaded; + bool beacon_templates_virgin; /* Never wrote the templates? */ struct work_struct beacon_update_trigger; }; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 4f3f016..ee202b4 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -955,23 +955,54 @@ static void b43legacy_write_template_common(struct b43legacy_wldev *dev, size + sizeof(struct b43legacy_plcp_hdr6)); } +/* Convert a b43legacy antenna number value to the PHY TX control value. */ +static u16 b43legacy_antenna_to_phyctl(int antenna) +{ + switch (antenna) { + case B43legacy_ANTENNA0: + return B43legacy_TX4_PHY_ANT0; + case B43legacy_ANTENNA1: + return B43legacy_TX4_PHY_ANT1; + } + return B43legacy_TX4_PHY_ANTLAST; +} + static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset) { unsigned int i, len, variable_len; const struct ieee80211_mgmt *bcn; const u8 *ie; bool tim_found = 0; + unsigned int rate; + u16 ctl; + int antenna; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t)dev->wl->current_beacon->len, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); + rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); + /* Write the PHY TX control parameters. */ + antenna = B43legacy_ANTENNA_DEFAULT; + antenna = b43legacy_antenna_to_phyctl(antenna); + ctl = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL); + /* We can't send beacons with short preamble. Would get PHY errors. */ + ctl &= ~B43legacy_TX4_PHY_SHORTPRMBL; + ctl &= ~B43legacy_TX4_PHY_ANT; + ctl &= ~B43legacy_TX4_PHY_ENC; + ctl |= antenna; + ctl |= B43legacy_TX4_PHY_ENC_CCK; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL, ctl); + /* Find the position of the TIM and the DTIM_period value * and write them to SHM. */ ie = bcn->u.beacon.variable; @@ -1026,7 +1057,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, __le16 dur; plcp.data = 0; - b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate); + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, size, @@ -1130,10 +1161,82 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); b43legacy_write_template_common(dev, probe_resp_data, size, ram_offset, - shm_size_offset, rate->bitrate); + shm_size_offset, rate->hw_value); kfree(probe_resp_data); } +static void b43legacy_upload_beacon0(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + + if (wl->beacon0_uploaded) + return; + b43legacy_write_beacon_template(dev, 0x68, 0x18); + /* FIXME: Probe resp upload doesn't really belong here, + * but we don't use that feature anyway. */ + b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, + &__b43legacy_ratetable[3]); + wl->beacon0_uploaded = 1; +} + +static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + + if (wl->beacon1_uploaded) + return; + b43legacy_write_beacon_template(dev, 0x468, 0x1A); + wl->beacon1_uploaded = 1; +} + +static void handle_irq_beacon(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + u32 cmd, beacon0_valid, beacon1_valid; + + if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) + return; + + /* This is the bottom half of the asynchronous beacon update. */ + + /* Ignore interrupt in the future. */ + dev->irq_savedstate &= ~B43legacy_IRQ_BEACON; + + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID); + beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID); + + /* Schedule interrupt manually, if busy. */ + if (beacon0_valid && beacon1_valid) { + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON); + dev->irq_savedstate |= B43legacy_IRQ_BEACON; + return; + } + + if (unlikely(wl->beacon_templates_virgin)) { + /* We never uploaded a beacon before. + * Upload both templates now, but only mark one valid. */ + wl->beacon_templates_virgin = 0; + b43legacy_upload_beacon0(dev); + b43legacy_upload_beacon1(dev); + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + cmd |= B43legacy_MACCMD_BEACON0_VALID; + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); + } else { + if (!beacon0_valid) { + b43legacy_upload_beacon0(dev); + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + cmd |= B43legacy_MACCMD_BEACON0_VALID; + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); + } else if (!beacon1_valid) { + b43legacy_upload_beacon1(dev); + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + cmd |= B43legacy_MACCMD_BEACON1_VALID; + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); + } + } +} + static void b43legacy_beacon_update_trigger_work(struct work_struct *work) { struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl, @@ -1143,13 +1246,14 @@ static void b43legacy_beacon_update_trigger_work(struct work_struct *work) mutex_lock(&wl->mutex); dev = wl->current_dev; if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) { - /* Force the microcode to trigger the - * beacon update bottom-half IRQ. */ spin_lock_irq(&wl->irq_lock); - b43legacy_write32(dev, B43legacy_MMIO_MACCMD, - b43legacy_read32(dev, B43legacy_MMIO_MACCMD) - | B43legacy_MACCMD_BEACON0_VALID - | B43legacy_MACCMD_BEACON1_VALID); + /* update beacon right away or defer to irq */ + dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + handle_irq_beacon(dev); + /* The handler might have updated the IRQ mask. */ + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, + dev->irq_savedstate); + mmiowb(); spin_unlock_irq(&wl->irq_lock); } mutex_unlock(&wl->mutex); @@ -1198,45 +1302,6 @@ static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } -static void handle_irq_beacon(struct b43legacy_wldev *dev) -{ - struct b43legacy_wl *wl = dev->wl; - u32 cmd; - u32 beacon0_valid, beacon1_valid; - - if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) - return; - - /* This is the bottom half of the asynchronous beacon update. */ - - cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); - beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID); - beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID); - cmd &= ~(B43legacy_MACCMD_BEACON0_VALID | B43legacy_MACCMD_BEACON1_VALID); - - if (!beacon0_valid) { - if (!wl->beacon0_uploaded) { - b43legacy_write_beacon_template(dev, 0x68, - B43legacy_SHM_SH_BTL0, - B43legacy_CCK_RATE_1MB); - b43legacy_write_probe_resp_template(dev, 0x268, - B43legacy_SHM_SH_PRTLEN, - &__b43legacy_ratetable[3]); - wl->beacon0_uploaded = 1; - } - cmd |= B43legacy_MACCMD_BEACON0_VALID; - } else if (!beacon1_valid) { - if (!wl->beacon1_uploaded) { - b43legacy_write_beacon_template(dev, 0x468, - B43legacy_SHM_SH_BTL1, - B43legacy_CCK_RATE_1MB); - wl->beacon1_uploaded = 1; - } - cmd |= B43legacy_MACCMD_BEACON1_VALID; - } - b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); -} - static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) { } @@ -3429,6 +3494,9 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) memset(wl->bssid, 0, ETH_ALEN); memset(wl->mac_addr, 0, ETH_ALEN); wl->filter_flags = 0; + wl->beacon0_uploaded = 0; + wl->beacon1_uploaded = 0; + wl->beacon_templates_virgin = 1; mutex_lock(&wl->mutex); diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 12fca99..b8e39dd 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -274,7 +274,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) - phy_ctl |= B43legacy_TX4_PHY_OFDM; + phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM; if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; switch (info->antenna_sel_tx) { diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index 62e09d0..9163308 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -67,7 +67,9 @@ struct b43legacy_txhdr_fw3 { #define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ /* PHY TX control word */ -#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ +#define B43legacy_TX4_PHY_ENC 0x0003 /* Data frame encoding */ +#define B43legacy_TX4_PHY_ENC_CCK 0x0000 /* CCK */ +#define B43legacy_TX4_PHY_ENC_OFDM 0x0001 /* Data frame rate type */ #define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ #define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */ #define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ -- cgit v0.10.2 From a89bff9a78b2bf51e21a961b473b5be94b22f12e Mon Sep 17 00:00:00 2001 From: Steven Luo Date: Sun, 12 Apr 2009 02:57:54 -0700 Subject: ath9k: reset after PCI FATAL/PERR interrupts ath9k_hw_getisr() doesn't appear to set anything in the status mask for PCI FATAL or PERR interrupts (AR_INTR_SYNC_HOST1_FATAL/PERR), which the open-source HAL seems to do. This means that the card isn't reset after these interrupts. This patch seems to fix a problem where the wireless drops out with an "ath9k: received PCI FATAL interrupt" in dmesg after some time; the hardware is an AR5416 in an ASUS WL-500W running 2.6.28.7 (OpenWRT) and compat-wireless 2009-03-31. Signed-off-by: Steven Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 24299e6..9cb85b0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2976,6 +2976,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) DPRINTF(ah->ah_sc, ATH_DBG_ANY, "received PCI PERR interrupt\n"); } + *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, -- cgit v0.10.2 From d2f5b3a6778ae86fd93cb01ccac16aa0b079e441 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:25 +0530 Subject: ath9k: Handle ASPM properly for RFKILL Radio enable/disable have to handle ASPM state properly. This patch fixes it. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8b6a7ea..1a9bf7e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1089,10 +1089,10 @@ void ath_radio_enable(struct ath_softc *sc) int r; ath9k_ps_wakeup(sc); - spin_lock_bh(&sc->sc_resetlock); + ath9k_hw_configpcipowersave(ah, 0); + spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, false); - if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) ", @@ -1154,6 +1154,7 @@ void ath_radio_disable(struct ath_softc *sc) spin_unlock_bh(&sc->sc_resetlock); ath9k_hw_phy_disable(ah); + ath9k_hw_configpcipowersave(ah, 1); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); ath9k_ps_restore(sc); } -- cgit v0.10.2 From 675902ef822c114c0dac17ed10eed43eb8f5c9ec Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:34 +0530 Subject: ath9k: Fix memleak on TX DMA failure The driver-specific region has to be freed in case of a DMA mapping failure. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 628b780..faf2cab 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1572,8 +1572,9 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) { bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, - "dma_mapping_error() on TX\n"); + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); return -ENOMEM; } -- cgit v0.10.2 From 9c07a7777f44c7e39accec5ad8c4293d6a9b2a47 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:36 +0530 Subject: ath9k: Fix bug in scan termination A full HW reset needs to be done on termination of a scan run. Not setting SC_OP_FULL_RESET resulted in doing a fast channel change. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1a9bf7e..b2d129f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2749,6 +2749,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; + sc->sc_flags |= SC_OP_FULL_RESET; mutex_unlock(&sc->mutex); } -- cgit v0.10.2 From 822b0dfc135cf205379ea62aae7a5b393811b238 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:38 +0530 Subject: ath9k: Remove unused channel flags Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5c4127e..7e37570 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -266,13 +266,6 @@ enum ath9k_int { #define CHANNEL_HT40PLUS 0x20000 #define CHANNEL_HT40MINUS 0x40000 -#define CHANNEL_INTERFERENCE 0x01 -#define CHANNEL_DFS 0x02 -#define CHANNEL_4MS_LIMIT 0x04 -#define CHANNEL_DFS_CLEAR 0x08 -#define CHANNEL_DISALLOW_ADHOC 0x10 -#define CHANNEL_PER_11D_ADHOC 0x20 - #define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) #define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) #define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) @@ -303,10 +296,6 @@ struct ath9k_channel { int16_t rawNoiseFloor; }; -#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \ - (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ - (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ - (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ @@ -314,7 +303,6 @@ struct ath9k_channel { #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) -#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0) #define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) #define IS_CHAN_A_5MHZ_SPACED(_c) \ -- cgit v0.10.2 From db2f63f60a087ed29ae04310c1076c61f77a5d20 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:41 +0530 Subject: ath9k: Fix bug in checking HT flag The operating HT mode is stored in chanmode and not channelFlags. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index e2d62e9..d0b6755 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -883,7 +883,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) { REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - if (chan->channelFlags & CHANNEL_HT20) { + if (IS_CHAN_HT20(chan)) { REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, -- cgit v0.10.2 From a451aa66dcb14efcb7addf1d8edcac8df76a97b6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:43 +0530 Subject: ath9k: Fix bug in determining calibration support ADC gain calibration has to be done for all non 2GHZ-HT20 channels. Regression from "ath9k: use ieee80211_conf on ath9k_hw_iscal_supported()" Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index d0b6755..3195c0b 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -284,8 +284,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hw *ah, return true; case ADC_GAIN_CAL: case ADC_DC_CAL: - if (conf->channel->band == IEEE80211_BAND_5GHZ && - conf_is_ht20(conf)) + if (!(conf->channel->band == IEEE80211_BAND_2GHZ && + conf_is_ht20(conf))) return true; break; } -- cgit v0.10.2 From 415f738ecf41b427921b503ecfd427e26f89dc23 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:46 +0530 Subject: ath9k: Initialize ANI timers The various ANI timers have to be initialized properly when starting the calibration timer. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b2d129f..9564b73 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -407,6 +407,18 @@ set_timer: mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } +static void ath_start_ani(struct ath_softc *sc) +{ + unsigned long timestamp = jiffies_to_msecs(jiffies); + + sc->ani.longcal_timer = timestamp; + sc->ani.shortcal_timer = timestamp; + sc->ani.checkani_timer = timestamp; + + mod_timer(&sc->ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); +} + /* * Update tx/rx chainmask. For legacy association, * hard code chainmask to 1x1, for 11n association, use @@ -911,9 +923,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; - /* Start ANI */ - mod_timer(&sc->ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + ath_start_ani(sc); } else { DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); sc->curaid = 0; @@ -2239,12 +2249,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (conf->type == NL80211_IFTYPE_AP) { - /* TODO: is this a suitable place to start ANI for AP mode? */ - /* Start ANI */ - mod_timer(&sc->ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); - } + if (conf->type == NL80211_IFTYPE_AP) + ath_start_ani(sc); out: mutex_unlock(&sc->mutex); -- cgit v0.10.2 From 379f04407c92d84f2506385b66fb9fc89ecd96c3 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:48 +0530 Subject: ath9k: Cleanup calibration interface This patch cleans up the functions dealing with calibration, using proper return values. ath9k_hw_per_calibration(), ath9k_hw_calibrate now return bool values instead of setting error values in the function arguments. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 3195c0b..a0661bb 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -238,13 +238,12 @@ static void ath9k_hw_reset_calibration(struct ath_hw *ah, ah->cal_samples = 0; } -static void ath9k_hw_per_calibration(struct ath_hw *ah, +static bool ath9k_hw_per_calibration(struct ath_hw *ah, struct ath9k_channel *ichan, u8 rxchainmask, - struct hal_cal_list *currCal, - bool *isCalDone) + struct hal_cal_list *currCal) { - *isCalDone = false; + bool iscaldone = false; if (currCal->calState == CAL_RUNNING) { if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & @@ -263,7 +262,7 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah, currCal->calData->calPostProc(ah, numChains); ichan->CalValid |= currCal->calData->calType; currCal->calState = CAL_DONE; - *isCalDone = true; + iscaldone = true; } else { ath9k_hw_setup_calibration(ah, currCal); } @@ -271,6 +270,8 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah, } else if (!(ichan->CalValid & currCal->calData->calType)) { ath9k_hw_reset_calibration(ah, currCal); } + + return iscaldone; } /* Assumes you are talking about the currently configured channel */ @@ -841,23 +842,21 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) } bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone) + u8 rxchainmask, bool longcal) { + bool iscaldone = true; struct hal_cal_list *currCal = ah->cal_list_curr; - *isCalDone = true; - if (currCal && (currCal->calState == CAL_RUNNING || currCal->calState == CAL_WAITING)) { - ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal, - isCalDone); - if (*isCalDone) { + iscaldone = ath9k_hw_per_calibration(ah, chan, + rxchainmask, currCal); + if (iscaldone) { ah->cal_list_curr = currCal = currCal->calNext; if (currCal->calState == CAL_WAITING) { - *isCalDone = false; + iscaldone = false; ath9k_hw_reset_calibration(ah, currCal); } } @@ -877,7 +876,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, chan->channelFlags &= ~CHANNEL_CW_INT; } - return true; + return iscaldone; } static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 1c74bd5..ac71ed9 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -116,8 +116,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah); s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone); + u8 rxchainmask, bool longcal); bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9564b73..8bf2bf3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -367,28 +367,16 @@ static void ath_ani_calibrate(unsigned long data) /* Perform calibration if necessary */ if (longcal || shortcal) { - bool iscaldone = false; - - if (ath9k_hw_calibrate(ah, ah->curchan, - sc->rx_chainmask, longcal, - &iscaldone)) { - if (longcal) - sc->ani.noise_floor = - ath9k_hw_getchan_noise(ah, - ah->curchan); - - DPRINTF(sc, ATH_DBG_ANI, - "calibrate chan %u/%x nf: %d\n", - ah->curchan->channel, - ah->curchan->channelFlags, - sc->ani.noise_floor); - } else { - DPRINTF(sc, ATH_DBG_ANY, - "calibrate chan %u/%x failed\n", - ah->curchan->channel, - ah->curchan->channelFlags); - } - sc->ani.caldone = iscaldone; + sc->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, + sc->rx_chainmask, longcal); + + if (longcal) + sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, + ah->curchan); + + DPRINTF(sc, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n", + ah->curchan->channel, ah->curchan->channelFlags, + sc->ani.noise_floor); } } -- cgit v0.10.2 From cbfe946860ffc718c5d99a6b740e33ac95fe8b8d Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:56 +0530 Subject: ath9k: Use a consistent naming convention This patch replaces old 'hal_' prefixes with 'ath9k_'. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index a0661bb..67375ad 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -186,7 +186,7 @@ static bool getNoiseFloorThresh(struct ath_hw *ah, } static void ath9k_hw_setup_calibration(struct ath_hw *ah, - struct hal_cal_list *currCal) + struct ath9k_cal_list *currCal) { REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, @@ -220,7 +220,7 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah, } static void ath9k_hw_reset_calibration(struct ath_hw *ah, - struct hal_cal_list *currCal) + struct ath9k_cal_list *currCal) { int i; @@ -241,7 +241,7 @@ static void ath9k_hw_reset_calibration(struct ath_hw *ah, static bool ath9k_hw_per_calibration(struct ath_hw *ah, struct ath9k_channel *ichan, u8 rxchainmask, - struct hal_cal_list *currCal) + struct ath9k_cal_list *currCal) { bool iscaldone = false; @@ -276,7 +276,7 @@ static bool ath9k_hw_per_calibration(struct ath_hw *ah, /* Assumes you are talking about the currently configured channel */ static bool ath9k_hw_iscal_supported(struct ath_hw *ah, - enum hal_cal_types calType) + enum ath9k_cal_types calType) { struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; @@ -499,7 +499,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) { u32 iOddMeasOffset, iEvenMeasOffset, val, i; int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; - const struct hal_percal_data *calData = + const struct ath9k_percal_data *calData = ah->cal_list_curr->calData; u32 numSamples = (1 << (calData->calCountMax + 5)) * calData->calNumSamples; @@ -556,7 +556,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - struct hal_cal_list *currCal = ah->cal_list_curr; + struct ath9k_cal_list *currCal = ah->cal_list_curr; if (!ah->curchan) return true; @@ -845,7 +845,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, u8 rxchainmask, bool longcal) { bool iscaldone = true; - struct hal_cal_list *currCal = ah->cal_list_curr; + struct ath9k_cal_list *currCal = ah->cal_list_curr; if (currCal && (currCal->calState == CAL_RUNNING || @@ -1008,49 +1008,49 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, return true; } -const struct hal_percal_data iq_cal_multi_sample = { +const struct ath9k_percal_data iq_cal_multi_sample = { IQ_MISMATCH_CAL, MAX_CAL_SAMPLES, PER_MIN_LOG_COUNT, ath9k_hw_iqcal_collect, ath9k_hw_iqcalibrate }; -const struct hal_percal_data iq_cal_single_sample = { +const struct ath9k_percal_data iq_cal_single_sample = { IQ_MISMATCH_CAL, MIN_CAL_SAMPLES, PER_MAX_LOG_COUNT, ath9k_hw_iqcal_collect, ath9k_hw_iqcalibrate }; -const struct hal_percal_data adc_gain_cal_multi_sample = { +const struct ath9k_percal_data adc_gain_cal_multi_sample = { ADC_GAIN_CAL, MAX_CAL_SAMPLES, PER_MIN_LOG_COUNT, ath9k_hw_adc_gaincal_collect, ath9k_hw_adc_gaincal_calibrate }; -const struct hal_percal_data adc_gain_cal_single_sample = { +const struct ath9k_percal_data adc_gain_cal_single_sample = { ADC_GAIN_CAL, MIN_CAL_SAMPLES, PER_MAX_LOG_COUNT, ath9k_hw_adc_gaincal_collect, ath9k_hw_adc_gaincal_calibrate }; -const struct hal_percal_data adc_dc_cal_multi_sample = { +const struct ath9k_percal_data adc_dc_cal_multi_sample = { ADC_DC_CAL, MAX_CAL_SAMPLES, PER_MIN_LOG_COUNT, ath9k_hw_adc_dccal_collect, ath9k_hw_adc_dccal_calibrate }; -const struct hal_percal_data adc_dc_cal_single_sample = { +const struct ath9k_percal_data adc_dc_cal_single_sample = { ADC_DC_CAL, MIN_CAL_SAMPLES, PER_MAX_LOG_COUNT, ath9k_hw_adc_dccal_collect, ath9k_hw_adc_dccal_calibrate }; -const struct hal_percal_data adc_init_dc_cal = { +const struct ath9k_percal_data adc_init_dc_cal = { ADC_DC_INIT_CAL, MIN_CAL_SAMPLES, INIT_LOG_COUNT, diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index ac71ed9..fe5367f 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -17,13 +17,13 @@ #ifndef CALIB_H #define CALIB_H -extern const struct hal_percal_data iq_cal_multi_sample; -extern const struct hal_percal_data iq_cal_single_sample; -extern const struct hal_percal_data adc_gain_cal_multi_sample; -extern const struct hal_percal_data adc_gain_cal_single_sample; -extern const struct hal_percal_data adc_dc_cal_multi_sample; -extern const struct hal_percal_data adc_dc_cal_single_sample; -extern const struct hal_percal_data adc_init_dc_cal; +extern const struct ath9k_percal_data iq_cal_multi_sample; +extern const struct ath9k_percal_data iq_cal_single_sample; +extern const struct ath9k_percal_data adc_gain_cal_multi_sample; +extern const struct ath9k_percal_data adc_gain_cal_single_sample; +extern const struct ath9k_percal_data adc_dc_cal_multi_sample; +extern const struct ath9k_percal_data adc_dc_cal_single_sample; +extern const struct ath9k_percal_data adc_init_dc_cal; #define AR_PHY_CCA_MAX_GOOD_VALUE -85 #define AR_PHY_CCA_MAX_HIGH_VALUE -62 @@ -67,14 +67,14 @@ struct ar5416IniArray { } \ } while (0) -enum hal_cal_types { +enum ath9k_cal_types { ADC_DC_INIT_CAL = 0x1, ADC_GAIN_CAL = 0x2, ADC_DC_CAL = 0x4, IQ_MISMATCH_CAL = 0x8 }; -enum hal_cal_state { +enum ath9k_cal_state { CAL_INACTIVE, CAL_WAITING, CAL_RUNNING, @@ -87,18 +87,18 @@ enum hal_cal_state { #define PER_MIN_LOG_COUNT 2 #define PER_MAX_LOG_COUNT 10 -struct hal_percal_data { - enum hal_cal_types calType; +struct ath9k_percal_data { + enum ath9k_cal_types calType; u32 calNumSamples; u32 calCountMax; void (*calCollect) (struct ath_hw *); void (*calPostProc) (struct ath_hw *, u8); }; -struct hal_cal_list { - const struct hal_percal_data *calData; - enum hal_cal_state calState; - struct hal_cal_list *calNext; +struct ath9k_cal_list { + const struct ath9k_percal_data *calData; + enum ath9k_cal_state calState; + struct ath9k_cal_list *calNext; }; struct ath9k_nfcal_hist { diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7e37570..ab34126 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -436,14 +436,14 @@ struct ath_hw { enum ath9k_ant_setting diversity_control; /* Calibration */ - enum hal_cal_types supp_cals; - struct hal_cal_list iq_caldata; - struct hal_cal_list adcgain_caldata; - struct hal_cal_list adcdc_calinitdata; - struct hal_cal_list adcdc_caldata; - struct hal_cal_list *cal_list; - struct hal_cal_list *cal_list_last; - struct hal_cal_list *cal_list_curr; + enum ath9k_cal_types supp_cals; + struct ath9k_cal_list iq_caldata; + struct ath9k_cal_list adcgain_caldata; + struct ath9k_cal_list adcdc_calinitdata; + struct ath9k_cal_list adcdc_caldata; + struct ath9k_cal_list *cal_list; + struct ath9k_cal_list *cal_list_last; + struct ath9k_cal_list *cal_list_curr; #define totalPowerMeasI meas0.unsign #define totalPowerMeasQ meas1.unsign #define totalIqCorrMeas meas2.sign -- cgit v0.10.2 From 04d19ddd254b404703151ab25aa5041e50ff40f7 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:56:59 +0530 Subject: ath9k: Fix bug in calibration initialization This patch fixes a bug in ath9k_hw_init_cal() where the wrong calibration was being done for non-AR9285 chipsets. Also add a few helpful comments. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 67375ad..08f6902 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -918,83 +918,66 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) return true; } -bool ath9k_hw_init_cal(struct ath_hw *ah, - struct ath9k_channel *chan) +bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { if (!ar9285_clc(ah, chan)) return false; - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } else { + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + } - /* Kick off the cal */ + /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_CAL, 0, - AH_WAIT_TIMEOUT)) { + /* Poll for offset calibration complete */ + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration failed to complete in 1ms; " "noisy environment?\n"); return false; } - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - } - - /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "offset calibration failed to complete in 1ms; " - "noisy environment?\n"); - return false; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + } } /* Do PA Calibration */ if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); - /* Do NF Calibration */ + /* Do NF Calibration after DC offset and other calibrations */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_NF); + REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + /* Enable IQ, ADC Gain and ADC DC offset CALs */ if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); + "enabling ADC Gain Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); + "enabling ADC DC Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); + "enabling IQ Calibration.\n"); } ah->cal_list_curr = ah->cal_list; -- cgit v0.10.2 From 386aeacfa8912e1accffc47e30ffe0c0ecfe71e5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 13 Apr 2009 21:57:01 +0530 Subject: ath9k: Remove CHANNEL_CW_INT handling in ath9k_hw_calibrate It is already handled properly in ath9k_hw_getnf. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 08f6902..a197041 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -871,9 +871,6 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_getnf(ah, chan); ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_start_nfcal(ah); - - if (chan->channelFlags & CHANNEL_CW_INT) - chan->channelFlags &= ~CHANNEL_CW_INT; } return iscaldone; -- cgit v0.10.2 From 06bfd0d3dbe965de4f60079955cca19d7e853c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Mon, 13 Apr 2009 21:54:27 +0200 Subject: rtl8187: Remove the "8187B chip detected" message when probing RTL8187B cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This message appears to be nothing more than a leftover of the experimental-8187B era. Also, we print the HW type in the hwaddr line, making this message reduntant. And it's definitely not important enough to be a KERN_WARNING. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index fd81884..d6d4001 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1470,9 +1470,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*channel++).hw_value = txpwr >> 8; } - if (priv->is_rtl8187b) - printk(KERN_WARNING "rtl8187: 8187B chip detected.\n"); - /* * XXX: Once this driver supports anything that requires * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. -- cgit v0.10.2 From a1c555802a62c845520d2486d783c9bb1d5e68a9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 14 Apr 2009 22:11:20 +0200 Subject: ath: add module information This patch adds licensing, author information and a description to the module. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index a005b91..4bb0132 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -3,5 +3,4 @@ obj-$(CONFIG_ATH9K) += ath9k/ obj-$(CONFIG_AR9170_USB) += ar9170/ obj-$(CONFIG_ATH_COMMON) += ath.o -ath-objs := regd.o - +ath-objs := main.o regd.o diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c new file mode 100644 index 0000000..9949b11 --- /dev/null +++ b/drivers/net/wireless/ath/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +MODULE_AUTHOR("Atheros Communications"); +MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards."); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v0.10.2 From f2753ddbadb0873a98421415882318251bbd9eaa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Apr 2009 10:09:24 +0200 Subject: mac80211: add hardware restart function Some hardware defects may require the hardware to be re-initialised completely from scratch. Drivers would need much information (for instance the current MAC address, crypto keys, beaconing information, etc.) stored duplicated from mac80211 to be able to do this, so let mac80211 help them. The new ieee80211_restart_hw() function requires the same code as resuming, so move that code into a new ieee80211_reconfig() function in util.c and leave only the suspend code in pm.c. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2c6f976..a593bed 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1575,6 +1575,20 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw); */ void ieee80211_free_hw(struct ieee80211_hw *hw); +/** + * ieee80211_restart_hw - restart hardware completely + * + * Call this function when the hardware was restarted for some reason + * (hardware error, ...) and the driver is unable to restore its state + * by itself. mac80211 assumes that at this point the driver/hardware + * is completely uninitialised and stopped, it starts the process by + * calling the ->start() operation. The driver will need to reset all + * internal state that it has prior to calling this function. + * + * @hw: the hardware to restart + */ +void ieee80211_restart_hw(struct ieee80211_hw *hw); + /* trick to avoid symbol clashes with the ieee80211 subsystem */ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status *status); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cb80a80..13d6f89 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -748,6 +748,8 @@ struct ieee80211_local { int user_power_level; /* in dBm */ int power_constr_level; /* in dBm */ + struct work_struct restart_work; + #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *rcdir; @@ -1036,15 +1038,22 @@ void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, u16 capab_info, u8 *pwr_constr_elem, u8 pwr_constr_elem_len); -/* Suspend/resume */ +/* Suspend/resume and hw reconfiguration */ +int ieee80211_reconfig(struct ieee80211_local *local); + #ifdef CONFIG_PM int __ieee80211_suspend(struct ieee80211_hw *hw); -int __ieee80211_resume(struct ieee80211_hw *hw); + +static inline int __ieee80211_resume(struct ieee80211_hw *hw) +{ + return ieee80211_reconfig(hw_to_local(hw)); +} #else static inline int __ieee80211_suspend(struct ieee80211_hw *hw) { return 0; } + static inline int __ieee80211_resume(struct ieee80211_hw *hw) { return 0; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c1145be..80c0e28 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -696,6 +696,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_tx_status); +static void ieee80211_restart_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, restart_work); + + rtnl_lock(); + ieee80211_reconfig(local); + rtnl_unlock(); +} + +void ieee80211_restart_hw(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + /* use this reason, __ieee80211_resume will unblock it */ + ieee80211_stop_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); + + schedule_work(&local->restart_work); +} +EXPORT_SYMBOL(ieee80211_restart_hw); + struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { @@ -768,6 +790,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); + INIT_WORK(&local->restart_work, ieee80211_restart_work); + INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 2b4c95c..b38986c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -72,108 +72,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) return 0; } -int __ieee80211_resume(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_init_conf conf; - struct sta_info *sta; - unsigned long flags; - int res; - - /* restart hardware */ - if (local->open_count) { - res = local->ops->start(hw); - - ieee80211_led_radio(local, hw->conf.radio_enabled); - } - - /* add interfaces */ - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sdata->vif.type != NL80211_IFTYPE_MONITOR && - netif_running(sdata->dev)) { - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->dev->dev_addr; - res = local->ops->add_interface(hw, &conf); - } - } - - /* add STAs back */ - if (local->ops->sta_notify) { - spin_lock_irqsave(&local->sta_lock, flags); - list_for_each_entry(sta, &local->sta_list, list) { - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - - local->ops->sta_notify(hw, &sdata->vif, - STA_NOTIFY_ADD, &sta->sta); - } - spin_unlock_irqrestore(&local->sta_lock, flags); - } - - /* Clear Suspend state so that ADDBA requests can be processed */ - - rcu_read_lock(); - - if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { - list_for_each_entry_rcu(sta, &local->sta_list, list) { - clear_sta_flags(sta, WLAN_STA_SUSPEND); - } - } - - rcu_read_unlock(); - - /* setup RTS threshold */ - if (local->ops->set_rts_threshold) - local->ops->set_rts_threshold(hw, local->rts_threshold); - - /* reconfigure hardware */ - ieee80211_hw_config(local, ~0); - - netif_addr_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); - - /* Finally also reconfigure all the BSS information */ - list_for_each_entry(sdata, &local->interfaces, list) { - u32 changed = ~0; - if (!netif_running(sdata->dev)) - continue; - switch (sdata->vif.type) { - case NL80211_IFTYPE_STATION: - /* disable beacon change bits */ - changed &= ~IEEE80211_IFCC_BEACON; - /* fall through */ - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_MESH_POINT: - WARN_ON(ieee80211_if_config(sdata, changed)); - ieee80211_bss_info_change_notify(sdata, ~0); - break; - case NL80211_IFTYPE_WDS: - break; - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_MONITOR: - /* ignore virtual */ - break; - case NL80211_IFTYPE_UNSPECIFIED: - case __NL80211_IFTYPE_AFTER_LAST: - WARN_ON(1); - break; - } - } - - /* add back keys */ - list_for_each_entry(sdata, &local->interfaces, list) - if (netif_running(sdata->dev)) - ieee80211_enable_keys(sdata); - - ieee80211_wake_queues_by_reason(hw, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); - - return 0; -} +/* + * __ieee80211_resume() is a static inline which just calls + * ieee80211_reconfig(), which is also needed for hardware + * hang/firmware failure/etc. recovery. + */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1ff8353..b361e2a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -28,6 +28,7 @@ #include "rate.h" #include "mesh.h" #include "wme.h" +#include "led.h" /* privid for wiphys to determine whether they belong to us or not */ void *mac80211_wiphy_privid = &mac80211_wiphy_privid; @@ -966,3 +967,120 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, } return supp_rates; } + +int ieee80211_reconfig(struct ieee80211_local *local) +{ + struct ieee80211_hw *hw = &local->hw; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_init_conf conf; + struct sta_info *sta; + unsigned long flags; + int res; + + /* restart hardware */ + if (local->open_count) { + res = local->ops->start(hw); + + ieee80211_led_radio(local, hw->conf.radio_enabled); + } + + /* add interfaces */ + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_MONITOR && + netif_running(sdata->dev)) { + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = sdata->dev->dev_addr; + res = local->ops->add_interface(hw, &conf); + } + } + + /* add STAs back */ + if (local->ops->sta_notify) { + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) { + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); + + local->ops->sta_notify(hw, &sdata->vif, + STA_NOTIFY_ADD, &sta->sta); + } + spin_unlock_irqrestore(&local->sta_lock, flags); + } + + /* Clear Suspend state so that ADDBA requests can be processed */ + + rcu_read_lock(); + + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { + list_for_each_entry_rcu(sta, &local->sta_list, list) { + clear_sta_flags(sta, WLAN_STA_SUSPEND); + } + } + + rcu_read_unlock(); + + /* setup RTS threshold */ + if (local->ops->set_rts_threshold) + local->ops->set_rts_threshold(hw, local->rts_threshold); + + /* reconfigure hardware */ + ieee80211_hw_config(local, ~0); + + netif_addr_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_addr_unlock_bh(local->mdev); + + /* Finally also reconfigure all the BSS information */ + list_for_each_entry(sdata, &local->interfaces, list) { + u32 changed = ~0; + if (!netif_running(sdata->dev)) + continue; + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: + /* disable beacon change bits */ + changed &= ~IEEE80211_IFCC_BEACON; + /* fall through */ + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + /* + * Driver's config_interface can fail if rfkill is + * enabled. Accommodate this return code. + * FIXME: When mac80211 has knowledge of rfkill + * state the code below can change back to: + * WARN(ieee80211_if_config(sdata, changed)); + * ieee80211_bss_info_change_notify(sdata, ~0); + */ + if (ieee80211_if_config(sdata, changed)) + printk(KERN_DEBUG "%s: failed to configure interface during resume\n", + sdata->dev->name); + else + ieee80211_bss_info_change_notify(sdata, ~0); + break; + case NL80211_IFTYPE_WDS: + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: + /* ignore virtual */ + break; + case NL80211_IFTYPE_UNSPECIFIED: + case __NL80211_IFTYPE_AFTER_LAST: + WARN_ON(1); + break; + } + } + + /* add back keys */ + list_for_each_entry(sdata, &local->interfaces, list) + if (netif_running(sdata->dev)) + ieee80211_enable_keys(sdata); + + ieee80211_wake_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); + + return 0; +} -- cgit v0.10.2 From 882b709230246de3359b04b195ad3e80b93b73ef Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 14 Apr 2009 16:21:01 +0530 Subject: ath9k: Disable autosleep feature for AR9285 based chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9cb85b0..ec2a7a40 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3377,7 +3377,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) || (ah->hw_version.macVersion == AR_SREV_VERSION_9160) || (ah->hw_version.macVersion == AR_SREV_VERSION_9100) || - (ah->hw_version.macVersion == AR_SREV_VERSION_9280)) + (ah->hw_version.macVersion == AR_SREV_VERSION_9280) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9285)) pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; else pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; -- cgit v0.10.2 From 45f483c00299807a1635d6ee327957b796b60076 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 14 Apr 2009 22:19:29 +0200 Subject: p54: remove module_ stubs Christoph Hellwig pointed out that these stubs are unnecessary. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b18fc93..bc1bd72 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -2713,15 +2713,3 @@ void p54_free_common(struct ieee80211_hw *dev) #endif /* CONFIG_P54_LEDS */ } EXPORT_SYMBOL_GPL(p54_free_common); - -static int __init p54_init(void) -{ - return 0; -} - -static void __exit p54_exit(void) -{ -} - -module_init(p54_init); -module_exit(p54_exit); -- cgit v0.10.2 From 77ded01cc25744245c58a369d24e251833e995bd Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 15 Apr 2009 07:57:32 -0400 Subject: ath5k: fix initvals errors This patch corrects a few errors in the initvals tables to match those in the HAL tables. Namely, remove a couple of repetitions, fix some turbo mode errors, and correct a register for the CCK rate power table. Changes-licensed-under: ISC Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index 61fb621..18eb519 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -537,8 +537,6 @@ static const struct ath5k_ini ar5212_ini_common_start[] = { { AR5K_DCU_TX_FILTER_1(15), 0x00000000 }, { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, - { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, - { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, { AR5K_STA_ID1, 0x00000000 }, { AR5K_BSS_ID0, 0x00000000 }, { AR5K_BSS_ID1, 0x00000000 }, @@ -669,7 +667,7 @@ static const struct ath5k_ini ar5212_ini_common_start[] = { /*{ AR5K_PHY(650), 0x000001b5 },*/ { AR5K_PHY(651), 0x00000000 }, { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, - { AR5K_PHY_TXPOWER_RATE2, 0x20202020 }, + { AR5K_PHY_TXPOWER_RATE4, 0x20202020 }, /*{ AR5K_PHY(655), 0x13c889af },*/ { AR5K_PHY(656), 0x38490a20 }, { AR5K_PHY(657), 0x00007bb6 }, @@ -718,7 +716,7 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { { AR5K_PHY_SETTLING, { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } }, { AR5K_PHY_AGCCTL, - { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } }, + { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } }, { AR5K_PHY_NF, { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, { AR5K_PHY_WEAK_OFDM_HIGH_THR, @@ -799,7 +797,7 @@ static const struct ath5k_ini_mode rf5112_ini_mode_end[] = { { AR5K_PHY_DESIRED_SIZE, { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, { AR5K_PHY_SIG, - { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } }, + { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } }, { AR5K_PHY_AGCCOARSE, { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } }, { AR5K_PHY_WEAK_OFDM_LOW_THR, -- cgit v0.10.2 From 56d2ac763829d2443075e8266dd00166ee11c80d Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 15 Apr 2009 07:57:33 -0400 Subject: ath5k: use tasklet_hi_schedule for beacon queue For embedded platforms, beacon transmission can be starved when flooded with data packets. Prioritize beacons by giving the beacon queue the first shot when the isr completes. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ff6d4f8..ef8523e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2496,7 +2496,7 @@ ath5k_intr(int irq, void *dev_id) tasklet_schedule(&sc->restq); } else { if (status & AR5K_INT_SWBA) { - tasklet_schedule(&sc->beacontq); + tasklet_hi_schedule(&sc->beacontq); } if (status & AR5K_INT_RXEOL) { /* -- cgit v0.10.2 From 46802a4f07cd2367d584bb1a2e6998d22d4d4f3a Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 15 Apr 2009 07:57:34 -0400 Subject: ath5k: use bool for modparams Current code uses int types, but both modparams are boolean values. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ef8523e..3bde18f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -61,11 +61,11 @@ static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); static int modparam_all_channels; -module_param_named(all_channels, modparam_all_channels, int, 0444); +module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); -- cgit v0.10.2 From c57ca81576e7ca0369ea52c9ac5f35d0f6ca1270 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 15 Apr 2009 07:57:35 -0400 Subject: ath5k: use rx hw descriptor pointer for self-linked check This patch simplifies the code used to detect when the self-linked DMA buffer is still in use by hardware, by checking the hardware's rxdp register instead of looking at the software buffer list. Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3bde18f..1a6e72f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1780,7 +1780,7 @@ ath5k_tasklet_rx(unsigned long data) struct sk_buff *skb, *next_skb; dma_addr_t next_skb_addr; struct ath5k_softc *sc = (void *)data; - struct ath5k_buf *bf, *bf_last; + struct ath5k_buf *bf; struct ath5k_desc *ds; int ret; int hdrlen; @@ -1791,7 +1791,6 @@ ath5k_tasklet_rx(unsigned long data) ATH5K_WARN(sc, "empty rx buf pool\n"); goto unlock; } - bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list); do { rxs.flag = 0; @@ -1800,24 +1799,9 @@ ath5k_tasklet_rx(unsigned long data) skb = bf->skb; ds = bf->desc; - /* - * last buffer must not be freed to ensure proper hardware - * function. When the hardware finishes also a packet next to - * it, we are sure, it doesn't use it anymore and we can go on. - */ - if (bf_last == bf) - bf->flags |= 1; - if (bf->flags) { - struct ath5k_buf *bf_next = list_entry(bf->list.next, - struct ath5k_buf, list); - ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc, - &rs); - if (ret) - break; - bf->flags &= ~1; - /* skip the overwritten one (even status is martian) */ - goto next; - } + /* bail if HW is still using self-linked descriptor */ + if (ath5k_hw_get_rxdp(sc->ah) == bf->daddr) + break; ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); if (unlikely(ret == -EINPROGRESS)) diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 8229561..852b2c1 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -56,7 +56,6 @@ struct ath5k_buf { struct list_head list; - unsigned int flags; /* rx descriptor flags */ struct ath5k_desc *desc; /* virtual addr of desc */ dma_addr_t daddr; /* physical addr of desc */ struct sk_buff *skb; /* skbuff for buf */ diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index b65b4fe..941b511 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -80,8 +80,6 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) * 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) { -- cgit v0.10.2 From 26925042b6b105995ee54c6015e95f0caf9632d6 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 15 Apr 2009 07:57:36 -0400 Subject: ath5k: manipulate rxlink and descriptor address under rxbuf lock Grabbing an ath5k_buf then dropping the lock is racy because the referenced descriptor can be obtained in another thread and released before the buffer is handed to the hardware. Likewise, manipulating sc->rxlink without the lock can lead to having multiple self-linked hardware descriptors. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 1a6e72f..c8c658b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1618,9 +1618,8 @@ ath5k_rx_start(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", sc->cachelsz, sc->rxbufsize); - sc->rxlink = NULL; - spin_lock_bh(&sc->rxbuflock); + sc->rxlink = NULL; list_for_each_entry(bf, &sc->rxbuf, list) { ret = ath5k_rxbuf_setup(sc, bf); if (ret != 0) { @@ -1629,9 +1628,9 @@ ath5k_rx_start(struct ath5k_softc *sc) } } bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); + ath5k_hw_set_rxdp(ah, bf->daddr); spin_unlock_bh(&sc->rxbuflock); - 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 */ -- cgit v0.10.2 From 85efc86eb7c6cbb1c8ce8d99b10b948be033fbb9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 13 Apr 2009 21:41:46 -0400 Subject: atheros: fix propagation of bad EEPROM on regulatory init When the EEPROM is not in good condition we cannot continue so we currently bail out but only ath5k is bailing out properly. Both ath9k and ar9170 were proceeding and if a user were to run into this they'd see an obscure panic. Lets propagate the error as intended and make sure we inform the user by lifting the error message from debug to a kernel error. Stable note: You can find a port of this page here: http://bombadil.infradead.org/~mcgrof/patches/ath9k/ath9k-fix-eeprom.patch.txt Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 8de0ff9..857416c 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1649,6 +1649,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, ar9170_reg_notifier); + if (err) + goto err_out; err = ieee80211_register_hw(ar->hw); if (err) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8bf2bf3..2398d4f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1416,8 +1416,9 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, - ath9k_reg_notifier)) + error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + ath9k_reg_notifier); + if (error) goto bad; /* default to MONITOR mode */ diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 4b5c851..526c7f1 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -477,7 +477,7 @@ ath_regd_init(struct ath_regulatory *reg, u16 regdmn; if (!ath_regd_is_eeprom_valid(reg)) { - printk(KERN_DEBUG "ath: Invalid EEPROM contents\n"); + printk(KERN_ERR "ath: Invalid EEPROM contents\n"); return -EINVAL; } -- cgit v0.10.2 From fade5db4f227bf59874efd6023f39d345e17e2a4 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 17 Apr 2009 15:14:22 +0200 Subject: p54: deactivate broken powersave function (part 2) This patch deactivates powersave in station mode. It does not work correctly yet, so the code does more harm than good. (I split the original patch and sent part of it for 2.6.30, which didn't have the IEEE80211_HW_BEACON_FILTER flag. -- JWL) Reported-by: Johannes Berg Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index bc1bd72..5368aa3 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -2642,8 +2642,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_queue); dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_BEACON_FILTER; + IEEE80211_HW_NOISE_DBM; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | -- cgit v0.10.2 From dc7d243d75b906cc964c12caa3b2eebe953a69be Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 24 Mar 2009 21:33:43 +0100 Subject: Add support for CF8381 WiFi card. A detection function was added for identifying CF8381. Signed-off-by: Marek Vasut Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index cedeac6..2a5b083 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -273,7 +273,28 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r */ #define IF_CS_PRODUCT_ID 0x0000001C #define IF_CS_CF8385_B1_REV 0x12 +#define IF_CS_CF8381_B3_REV 0x04 +/* + * Used to detect other cards than CF8385 since their revisions of silicon + * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. + */ +#define CF8381_MANFID 0x02db +#define CF8381_CARDID 0x6064 +#define CF8385_MANFID 0x02df +#define CF8385_CARDID 0x8103 + +static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev) +{ + return (p_dev->manf_id == CF8381_MANFID && + p_dev->card_id == CF8381_CARDID); +} + +static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev) +{ + return (p_dev->manf_id == CF8385_MANFID && + p_dev->card_id == CF8385_CARDID); +} /********************************************************************/ /* I/O and interrupt handling */ @@ -757,6 +778,7 @@ static void if_cs_release(struct pcmcia_device *p_dev) static int if_cs_probe(struct pcmcia_device *p_dev) { int ret = -ENOMEM; + unsigned int prod_id; struct lbs_private *priv; struct if_cs_card *card; /* CIS parsing */ @@ -859,7 +881,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); /* Check if we have a current silicon */ - if (if_cs_read8(card, IF_CS_PRODUCT_ID) < IF_CS_CF8385_B1_REV) { + prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); + if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) { + lbs_pr_err("old chips like 8381 rev B3 aren't supported\n"); + ret = -ENODEV; + goto out2; + } + + if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) { lbs_pr_err("old chips like 8385 rev B1 aren't supported\n"); ret = -ENODEV; goto out2; @@ -950,7 +979,8 @@ static void if_cs_detach(struct pcmcia_device *p_dev) /********************************************************************/ static struct pcmcia_device_id if_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103), + PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), + PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); -- cgit v0.10.2 From 965bedadc01d34027455d5d5b67063ef0209c955 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Apr 2009 13:17:24 +0200 Subject: mac80211: improve powersave implementation When you have multiple virtual interfaces the current implementation requires setting them up properly from userspace, which is undesirable when we want to default to power save mode. Keep track of powersave requested from userspace per managed mode interface, and only enable powersave globally when exactly one managed mode interface is active and has powersave turned on. Second, only start the dynPS timer when PS is turned on, and properly turn it off when PS is turned off. Third, fix the scan_sdata abuse in the dynps code. Finally, also reorder the code and refactor the code that enables PS or the dynps timer instead of having it copied in two places. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 13d6f89..ff40dd7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -295,6 +295,8 @@ struct ieee80211_if_managed { int auth_tries; /* retries for auth req */ int assoc_tries; /* retries for assoc req */ + bool powersave; /* powersave requested for this iface */ + unsigned long request; unsigned long last_probe; @@ -739,8 +741,12 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - bool powersave; bool pspolling; + /* + * PS can only be enabled when we have exactly one managed + * interface (and monitors) in PS, this then points there. + */ + struct ieee80211_sub_if_data *ps_sdata; struct work_struct dynamic_ps_enable_work; struct work_struct dynamic_ps_disable_work; struct timer_list dynamic_ps_timer; @@ -932,6 +938,7 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_ps(struct ieee80211_local *local); /* IBSS code */ int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 91e8e1b..6240f76 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -317,6 +317,8 @@ static int ieee80211_open(struct net_device *dev) ieee80211_set_wmm_default(sdata); } + ieee80211_recalc_ps(local); + /* * ieee80211_sta_work is disabled while network interface * is down. Therefore, some configuration changes may not @@ -572,6 +574,8 @@ static int ieee80211_stop(struct net_device *dev) hw_reconf_flags = 0; } + ieee80211_recalc_ps(local); + /* do after stop to avoid reconfiguring when we stop anyway */ if (hw_reconf_flags) ieee80211_hw_config(local, hw_reconf_flags); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 90267af..06d9a1d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -446,6 +446,145 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, ieee80211_tx_skb(sdata, skb, 0); } +void ieee80211_send_nullfunc(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int powersave) +{ + struct sk_buff *skb; + struct ieee80211_hdr *nullfunc; + __le16 fc; + + if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) + return; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " + "frame\n", sdata->dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); + memset(nullfunc, 0, 24); + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + if (powersave) + fc |= cpu_to_le16(IEEE80211_FCTL_PM); + nullfunc->frame_control = fc; + memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); + memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); + + ieee80211_tx_skb(sdata, skb, 0); +} + +/* powersave */ +static void ieee80211_enable_ps(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_conf *conf = &local->hw.conf; + + if (conf->dynamic_ps_timeout > 0 && + !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(conf->dynamic_ps_timeout)); + } else { + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + ieee80211_send_nullfunc(local, sdata, 1); + conf->flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } +} + +static void ieee80211_change_ps(struct ieee80211_local *local) +{ + struct ieee80211_conf *conf = &local->hw.conf; + + if (local->ps_sdata) { + if (!(local->ps_sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) + return; + + ieee80211_enable_ps(local, local->ps_sdata); + } else if (conf->flags & IEEE80211_CONF_PS) { + conf->flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + del_timer_sync(&local->dynamic_ps_timer); + cancel_work_sync(&local->dynamic_ps_enable_work); + } +} + +/* need to hold RTNL or interface lock */ +void ieee80211_recalc_ps(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata, *found = NULL; + int count = 0; + + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) { + local->ps_sdata = NULL; + return; + } + + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + if (sdata->vif.type != NL80211_IFTYPE_STATION) + continue; + found = sdata; + count++; + } + + if (count == 1 && found->u.mgd.powersave) + local->ps_sdata = found; + else + local->ps_sdata = NULL; + + ieee80211_change_ps(local); +} + +void ieee80211_dynamic_ps_disable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_disable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + + ieee80211_wake_queues_by_reason(&local->hw, + IEEE80211_QUEUE_STOP_REASON_PS); +} + +void ieee80211_dynamic_ps_enable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_enable_work); + struct ieee80211_sub_if_data *sdata = local->ps_sdata; + + /* can only happen when PS was just disabled anyway */ + if (!sdata) + return; + + if (local->hw.conf.flags & IEEE80211_CONF_PS) + return; + + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + ieee80211_send_nullfunc(local, sdata, 1); + + local->hw.conf.flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); +} + +void ieee80211_dynamic_ps_timer(unsigned long data) +{ + struct ieee80211_local *local = (void *) data; + + queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); +} + /* MLME */ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, struct ieee80211_if_managed *ifmgd, @@ -721,19 +860,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= BSS_CHANGED_BASIC_RATES; ieee80211_bss_info_change_notify(sdata, bss_info_changed); - if (local->powersave) { - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) && - local->hw.conf.dynamic_ps_timeout > 0) { - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies( - local->hw.conf.dynamic_ps_timeout)); - } else { - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) - ieee80211_send_nullfunc(local, sdata, 1); - conf->flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } - } + /* will be same as sdata */ + if (local->ps_sdata) + ieee80211_enable_ps(local, sdata); netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); @@ -2195,76 +2324,3 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) ieee80211_restart_sta_timer(sdata); rcu_read_unlock(); } - -void ieee80211_dynamic_ps_disable_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, - dynamic_ps_disable_work); - - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } - - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_QUEUE_STOP_REASON_PS); -} - -void ieee80211_dynamic_ps_enable_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, - dynamic_ps_enable_work); - /* XXX: using scan_sdata is completely broken! */ - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - - if (local->hw.conf.flags & IEEE80211_CONF_PS) - return; - - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && sdata) - ieee80211_send_nullfunc(local, sdata, 1); - - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); -} - -void ieee80211_dynamic_ps_timer(unsigned long data) -{ - struct ieee80211_local *local = (void *) data; - - queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); -} - -void ieee80211_send_nullfunc(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - int powersave) -{ - struct sk_buff *skb; - struct ieee80211_hdr *nullfunc; - __le16 fc; - - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) - return; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " - "frame\n", sdata->dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); - memset(nullfunc, 0, 24); - fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - if (powersave) - fc |= cpu_to_le16(IEEE80211_FCTL_PM); - nullfunc->frame_control = fc; - memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); - memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); - memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); - - ieee80211_tx_skb(sdata, skb, 0); -} diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4ec1bfc..20df861 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -253,7 +253,7 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - if (!local->powersave) + if (!local->ps_sdata) ieee80211_send_nullfunc(local, sdata, 0); else { /* diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index a52fb3a..81f63e5 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -747,7 +747,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_conf *conf = &local->hw.conf; - int ret = 0, timeout = 0; + int timeout = 0; bool ps; if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) @@ -779,42 +779,19 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, timeout = wrq->value / 1000; set: - if (ps == local->powersave && timeout == conf->dynamic_ps_timeout) - return ret; + if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout) + return 0; - local->powersave = ps; + sdata->u.mgd.powersave = ps; conf->dynamic_ps_timeout = timeout; if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) - ret = ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); - - if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) - return ret; + ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); - if (conf->dynamic_ps_timeout > 0 && - !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(conf->dynamic_ps_timeout)); - } else { - if (local->powersave) { - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) - ieee80211_send_nullfunc(local, sdata, 1); - conf->flags |= IEEE80211_CONF_PS; - ret = ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_PS); - } else { - conf->flags &= ~IEEE80211_CONF_PS; - ret = ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_PS); - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) - ieee80211_send_nullfunc(local, sdata, 0); - del_timer_sync(&local->dynamic_ps_timer); - cancel_work_sync(&local->dynamic_ps_enable_work); - } - } + ieee80211_recalc_ps(local); - return ret; + return 0; } static int ieee80211_ioctl_giwpower(struct net_device *dev, @@ -822,9 +799,9 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - wrqu->power.disabled = !local->powersave; + wrqu->power.disabled = !sdata->u.mgd.powersave; return 0; } -- cgit v0.10.2 From 10f644a47b76d3e61b98f2d02ce9690b94c51ee5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Apr 2009 13:17:25 +0200 Subject: mac80211: disable powersave if pm_qos asks for low latency When an application asks for a latency lower than the beacon interval there's nothing we can do -- we need to stay awake and not have the AP buffer frames for us. Add code to automatically calculate this constraint in mac80211 so drivers need not concern themselves with it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 4b501b4..53563d5 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1383,4 +1383,13 @@ static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq) return -1; } +/** + * ieee80211_tu_to_usec - convert time units (TU) to microseconds + * @tu: the TUs + */ +static inline unsigned long ieee80211_tu_to_usec(unsigned long tu) +{ + return 1024 * tu; +} + #endif /* LINUX_IEEE80211_H */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ff40dd7..b1d18d9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -750,6 +750,7 @@ struct ieee80211_local { struct work_struct dynamic_ps_enable_work; struct work_struct dynamic_ps_disable_work; struct timer_list dynamic_ps_timer; + struct notifier_block network_latency_notifier; int user_power_level; /* in dBm */ int power_constr_level; /* in dBm */ @@ -938,7 +939,9 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); -void ieee80211_recalc_ps(struct ieee80211_local *local); +void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); +int ieee80211_max_network_latency(struct notifier_block *nb, + unsigned long data, void *dummy); /* IBSS code */ int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6240f76..5d60deb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -317,7 +317,7 @@ static int ieee80211_open(struct net_device *dev) ieee80211_set_wmm_default(sdata); } - ieee80211_recalc_ps(local); + ieee80211_recalc_ps(local, -1); /* * ieee80211_sta_work is disabled while network interface @@ -574,7 +574,7 @@ static int ieee80211_stop(struct net_device *dev) hw_reconf_flags = 0; } - ieee80211_recalc_ps(local); + ieee80211_recalc_ps(local, -1); /* do after stop to avoid reconfiguring when we stop anyway */ if (hw_reconf_flags) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 80c0e28..049ce86 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1038,25 +1039,38 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } } + local->network_latency_notifier.notifier_call = + ieee80211_max_network_latency; + result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, + &local->network_latency_notifier); + + if (result) { + rtnl_lock(); + goto fail_pm_qos; + } + return 0; -fail_wep: + fail_pm_qos: + ieee80211_led_exit(local); + ieee80211_remove_interfaces(local); + fail_wep: rate_control_deinitialize(local); -fail_rate: + fail_rate: unregister_netdevice(local->mdev); local->mdev = NULL; -fail_dev: + fail_dev: rtnl_unlock(); sta_info_stop(local); -fail_sta_info: + fail_sta_info: debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); -fail_workqueue: + fail_workqueue: if (local->mdev) free_netdev(local->mdev); -fail_mdev_alloc: + fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); -fail_wiphy_register: + fail_wiphy_register: kfree(local->int_scan_req.channels); return result; } @@ -1069,6 +1083,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); + pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, + &local->network_latency_notifier); + rtnl_lock(); /* diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 06d9a1d..c39a214 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -515,7 +516,7 @@ static void ieee80211_change_ps(struct ieee80211_local *local) } /* need to hold RTNL or interface lock */ -void ieee80211_recalc_ps(struct ieee80211_local *local) +void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) { struct ieee80211_sub_if_data *sdata, *found = NULL; int count = 0; @@ -534,10 +535,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local) count++; } - if (count == 1 && found->u.mgd.powersave) - local->ps_sdata = found; - else + if (count == 1 && found->u.mgd.powersave) { + s32 beaconint_us; + + if (latency < 0) + latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY); + + beaconint_us = ieee80211_tu_to_usec( + found->vif.bss_conf.beacon_int); + + if (beaconint_us > latency) + local->ps_sdata = NULL; + else + local->ps_sdata = found; + } else { local->ps_sdata = NULL; + } ieee80211_change_ps(local); } @@ -2324,3 +2337,18 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) ieee80211_restart_sta_timer(sdata); rcu_read_unlock(); } + +int ieee80211_max_network_latency(struct notifier_block *nb, + unsigned long data, void *dummy) +{ + s32 latency_usec = (s32) data; + struct ieee80211_local *local = + container_of(nb, struct ieee80211_local, + network_latency_notifier); + + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, latency_usec); + mutex_unlock(&local->iflist_mtx); + + return 0; +} diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 81f63e5..1c4664b 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -789,7 +789,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); - ieee80211_recalc_ps(local); + ieee80211_recalc_ps(local, -1); return 0; } -- cgit v0.10.2 From d91f36db51661018f6d54ff5966e283bcec4c545 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Apr 2009 13:17:26 +0200 Subject: mac80211: implement beacon filtering in software Regardless of whether the hardware implements beacon filtering, there's no need to process all beacons in software all the time throughout the stack (mac80211 does a lot, then cfg80211, then in the future possibly userspace). This patch implements the "best possible" beacon filtering in mac80211. "Best possible" means that it can look for changes in all requested information elements, and distinguish vendor IEs by their OUI. In the future, we will add nl80211 API for userspace to request information elements and vendor IE OUIs to watch -- drivers can then implement the best they can do while software implements it fully. It is unclear whether or not this actually saves CPU time, but the data is all in the cache already so it should be fairly cheap. The additional _testing_, however, has great benefit; Without this, and on hardware that doesn't implement beacon filtering, wrong assumptions about, for example, scan result updates could quickly creep into code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b1d18d9..38c9806 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -308,6 +308,8 @@ struct ieee80211_if_managed { int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ int auth_transaction; + u32 beacon_crc; + enum { IEEE80211_MFP_DISABLED, IEEE80211_MFP_OPTIONAL, @@ -1085,6 +1087,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int encrypt); void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems); +u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, + struct ieee802_11_elems *elems, + u64 filter, u32 crc); int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); u32 ieee80211_mandatory_rates(struct ieee80211_local *local, enum ieee80211_band band); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c39a214..7a8d4c4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1752,46 +1753,73 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; } +/* + * This is the canonical list of information elements we care about, + * the filter code also gives us all changes to the Microsoft OUI + * (00:50:F2) vendor IE which is used for WMM which we need to track. + * + * We implement beacon filtering in software since that means we can + * avoid processing the frame here and in cfg80211, and userspace + * will not be able to tell whether the hardware supports it or not. + * + * XXX: This list needs to be dynamic -- userspace needs to be able to + * add items it requires. It also needs to be able to tell us to + * look out for other vendor IEs. + */ +static const u64 care_about_ies = + BIT(WLAN_EID_COUNTRY) | + BIT(WLAN_EID_ERP_INFO) | + BIT(WLAN_EID_CHANNEL_SWITCH) | + BIT(WLAN_EID_PWR_CONSTRAINT) | + BIT(WLAN_EID_HT_CAPABILITY) | + BIT(WLAN_EID_HT_INFORMATION); + static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { - struct ieee80211_if_managed *ifmgd; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; size_t baselen; struct ieee802_11_elems elems; struct ieee80211_local *local = sdata->local; u32 changed = 0; - bool erp_valid, directed_tim; + bool erp_valid, directed_tim = false; u8 erp_value = 0; + u32 ncrc; /* Process beacon from the current BSS */ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; if (baselen > len) return; - ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); - - if (sdata->vif.type != NL80211_IFTYPE_STATION) + if (rx_status->freq != local->hw.conf.channel->center_freq) return; - ifmgd = &sdata->u.mgd; - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) return; - if (rx_status->freq != local->hw.conf.channel->center_freq) + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); + ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, + len - baselen, &elems, + care_about_ies, ncrc); + + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); + + ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim)); + + if (ncrc == ifmgd->beacon_crc) return; + ifmgd->beacon_crc = ncrc; + + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, elems.wmm_param_len); if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { - directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); - if (directed_tim) { if (local->hw.conf.dynamic_ps_timeout > 0) { local->hw.conf.flags &= ~IEEE80211_CONF_PS; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b361e2a..3dd490f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -537,8 +538,16 @@ EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) { + ieee802_11_parse_elems_crc(start, len, elems, 0, 0); +} + +u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, + struct ieee802_11_elems *elems, + u64 filter, u32 crc) +{ size_t left = len; u8 *pos = start; + bool calc_crc = filter != 0; memset(elems, 0, sizeof(*elems)); elems->ie_start = start; @@ -552,7 +561,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len, left -= 2; if (elen > left) - return; + break; + + if (calc_crc && id < 64 && (filter & BIT(id))) + crc = crc32_be(crc, pos - 2, elen + 2); switch (id) { case WLAN_EID_SSID: @@ -587,15 +599,20 @@ void ieee802_11_parse_elems(u8 *start, size_t len, elems->challenge = pos; elems->challenge_len = elen; break; - case WLAN_EID_WPA: + case WLAN_EID_VENDOR_SPECIFIC: if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && pos[2] == 0xf2) { /* Microsoft OUI (00:50:F2) */ + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + if (pos[3] == 1) { /* OUI Type 1 - WPA IE */ elems->wpa = pos; elems->wpa_len = elen; } else if (elen >= 5 && pos[3] == 2) { + /* OUI Type 2 - WMM IE */ if (pos[4] == 0) { elems->wmm_info = pos; elems->wmm_info_len = elen; @@ -680,6 +697,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len, left -= elen; pos += elen; } + + return crc; } void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) -- cgit v0.10.2 From bbbdff9e00449928f228867076a07bdfecd3dca8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Apr 2009 13:27:42 +0200 Subject: mac80211: enable PS by default Enable PS by default (depending on Kconfig) -- rely on drivers to control the level using pm_qos. Due to the previous patch we turn off PS when necessary due to latency requirements. This has a Kconfig symbol so people can, if they really want, configure the default in their kernels. We may want to keep it at "default y" only in wireless-testing for a while. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index ecc3faf..9cbf545 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -11,6 +11,22 @@ config MAC80211 This option enables the hardware independent IEEE 802.11 networking stack. +config MAC80211_DEFAULT_PS + bool "enable powersave by default" + depends on MAC80211 + default y + help + This option enables powersave mode by default. + + If this causes your applications to misbehave you should fix your + applications instead -- they need to register their network + latency requirement, see Documentation/power/pm_qos_interface.txt. + +config MAC80211_DEFAULT_PS_VALUE + int + default 1 if MAC80211_DEFAULT_PS + default 0 + menu "Rate control algorithm selection" depends on MAC80211 != n diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7a8d4c4..a16c9d7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2192,6 +2192,7 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd; + u32 hw_flags; ifmgd = &sdata->u.mgd; INIT_WORK(&ifmgd->work, ieee80211_sta_work); @@ -2211,6 +2212,13 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) IEEE80211_STA_AUTO_CHANNEL_SEL; if (sdata->local->hw.queues >= 4) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; + + hw_flags = sdata->local->hw.flags; + + if (hw_flags & IEEE80211_HW_SUPPORTS_PS) { + ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE; + sdata->local->hw.conf.dynamic_ps_timeout = 500; + } } /* configuration hooks */ -- cgit v0.10.2 From 955394c98c9cb79bdb3e6b479695af3a90ea0623 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Apr 2009 17:04:25 +0200 Subject: mac80211: document powersaving/beacon filter future Document what mac80211 will do in the future to help save power. We're not quite there yet, but a plan helps. Also, while at it, fix the docs wrt. multicast traffic. Signed-off-by: Johannes Berg Reviewed-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a593bed..52808bd 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1109,11 +1109,9 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * need software support for parsing the TIM bitmap. This is also supported * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still - * required to pass up beacons. Additionally, in this case, mac80211 will - * wake up the hardware when multicast traffic is announced in the beacon. - * - * FIXME: I don't think we can be fast enough in software when we want to - * receive multicast traffic? + * required to pass up beacons. The hardware is still required to handle + * waking up for multicast traffic; if it cannot the driver must handle that + * as best as it can, mac80211 is too slow. * * Dynamic powersave mode is an extension to normal powersave mode in which * the hardware stays awake for a user-specified period of time after sending @@ -1134,11 +1132,53 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * way the host will only receive beacons where some relevant information * (for example ERP protection or WMM settings) have changed. * - * Beacon filter support is informed with %IEEE80211_HW_BEACON_FILTER flag. - * The driver needs to enable beacon filter support whenever power save is - * enabled, that is %IEEE80211_CONF_PS is set. When power save is enabled, - * the stack will not check for beacon miss at all and the driver needs to - * notify about complete loss of beacons with ieee80211_beacon_loss(). + * Beacon filter support is advertised with the %IEEE80211_HW_BEACON_FILTER + * hardware capability. The driver needs to enable beacon filter support + * whenever power save is enabled, that is %IEEE80211_CONF_PS is set. When + * power save is enabled, the stack will not check for beacon loss and the + * driver needs to notify about loss of beacons with ieee80211_beacon_loss(). + * + * The time (or number of beacons missed) until the firmware notifies the + * driver of a beacon loss event (which in turn causes the driver to call + * ieee80211_beacon_loss()) should be configurable and will be controlled + * by mac80211 and the roaming algorithm in the future. + * + * Since there may be constantly changing information elements that nothing + * in the software stack cares about, we will, in the future, have mac80211 + * tell the driver which information elements are interesting in the sense + * that we want to see changes in them. This will include + * - a list of information element IDs + * - a list of OUIs for the vendor information element + * + * Ideally, the hardware would filter out any beacons without changes in the + * requested elements, but if it cannot support that it may, at the expense + * of some efficiency, filter out only a subset. For example, if the device + * doesn't support checking for OUIs it should pass up all changes in all + * vendor information elements. + * + * Note that change, for the sake of simplification, also includes information + * elements appearing or disappearing from the beacon. + * + * Some hardware supports an "ignore list" instead, just make sure nothing + * that was requested is on the ignore list, and include commonly changing + * information element IDs in the ignore list, for example 11 (BSS load) and + * the various vendor-assigned IEs with unknown contents (128, 129, 133-136, + * 149, 150, 155, 156, 173, 176, 178, 179, 219); for forward compatibility + * it could also include some currently unused IDs. + * + * + * In addition to these capabilities, hardware should support notifying the + * host of changes in the beacon RSSI. This is relevant to implement roaming + * when no traffic is flowing (when traffic is flowing we see the RSSI of + * the received data packets). This can consist in notifying the host when + * the RSSI changes significantly or when it drops below or rises above + * configurable thresholds. In the future these thresholds will also be + * configured by mac80211 (which gets them from userspace) to implement + * them as the roaming algorithm requires. + * + * If the hardware cannot implement this, the driver should ask it to + * periodically pass beacon frames to the host so that software can do the + * signal strength threshold checking. */ /** -- cgit v0.10.2 From 357303e2b61272b191f2e5d782d94fdd8f50fd71 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 16 Apr 2009 18:44:53 +0300 Subject: mac80211: Allow scan to be requested in AP mode We can allow scan requests in AP mode as long as the interface has not yet been configured to send out Beacon frames (or if beaconing has been disabled prior to the scan request). This makes it easier to scan for neighboring BSSes during AP initialization and makes it possible to run a scan without setting the interface down, if needed. Without this change, the only available option would be to set the interface down, move into station mode, and set the interface up, prior to requesting the scan. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e677b75..520efa8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1167,7 +1167,8 @@ static int ieee80211_scan(struct wiphy *wiphy, if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_ADHOC && - sdata->vif.type != NL80211_IFTYPE_MESH_POINT) + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon)) return -EOPNOTSUPP; return ieee80211_request_scan(sdata, req); -- cgit v0.10.2 From a027087a6b4c7d985b872cac3e19ce023670792e Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 16 Apr 2009 19:56:38 -0500 Subject: rtl8187: Implement TX/RX blink for LED The following patch implements some control over the LED on RTL8187B and RTL8187L devices. Triggers are registered for TX and RX. Whenever the trigger event occurs, the LED is turned off for 1/20 second, then turned back on. Note: For those RTL8187X devices that are built into the computer and have a LED that is expected to be controlled with a radio switch, this patch will not operate that LED. That will take a separate patch to be prepared later. Signed-off-by: Larry Finger Signed-off-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ad99470..11c2481 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -433,6 +433,13 @@ config RTL8187 Thanks to Realtek for their support! +# If possible, automatically enable LEDs for RTL8187. + +config RTL8187_LEDS + bool + depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187) + default y + config ADM8211 tristate "ADMtek ADM8211 support" depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile index c113b3e..37e3d4d 100644 --- a/drivers/net/wireless/rtl818x/Makefile +++ b/drivers/net/wireless/rtl818x/Makefile @@ -1,5 +1,5 @@ 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 +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o obj-$(CONFIG_RTL8180) += rtl8180.o obj-$(CONFIG_RTL8187) += rtl8187.o diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index 9718f61..622196d 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -16,6 +16,7 @@ #define RTL8187_H #include "rtl818x.h" +#include "rtl8187_leds.h" #define RTL8187_EEPROM_TXPWR_BASE 0x05 #define RTL8187_EEPROM_MAC_ADDR 0x07 @@ -102,6 +103,12 @@ struct rtl8187_priv { struct usb_anchor anchored; struct delayed_work work; struct ieee80211_hw *dev; +#ifdef CONFIG_RTL8187_LEDS + struct rtl8187_led led_tx; + struct rtl8187_led led_rx; + struct delayed_work led_on; + struct delayed_work led_off; +#endif u16 txpwr_base; u8 asic_rev; u8 is_rtl8187b; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index d6d4001..ac558da 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -29,6 +29,9 @@ #include "rtl8187.h" #include "rtl8187_rtl8225.h" +#ifdef CONFIG_RTL8187_LEDS +#include "rtl8187_leds.h" +#endif MODULE_AUTHOR("Michael Wu "); MODULE_AUTHOR("Andrea Merello "); @@ -734,10 +737,10 @@ static const u8 rtl8187b_reg_table[][3] = { {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, - {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0}, + {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x4C, 0x00, 2}, - {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, - {0x8E, 0x08, 0}, {0x8F, 0x00, 0} + {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, {0x8E, 0x08, 0}, + {0x8F, 0x00, 0} }; static int rtl8187b_init_hw(struct ieee80211_hw *dev) @@ -1501,6 +1504,12 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->asic_rev, priv->rf->name); +#ifdef CONFIG_RTL8187_LEDS + eeprom_93cx6_read(&eeprom, 0x3F, ®); + reg &= 0xFF; + rtl8187_leds_init(dev, reg); +#endif + return 0; err_free_dev: @@ -1518,6 +1527,9 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf) if (!dev) return; +#ifdef CONFIG_RTL8187_LEDS + rtl8187_leds_exit(dev); +#endif ieee80211_unregister_hw(dev); priv = dev->priv; diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c new file mode 100644 index 0000000..b442535 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -0,0 +1,218 @@ +/* + * Linux LED driver for RTL8187 + * + * Copyright 2009 Larry Finger + * + * Based on the LED handling in the r8187 driver, which is: + * Copyright (c) Realtek Semiconductor Corp. All rights reserved. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifdef CONFIG_RTL8187_LEDS + +#include +#include +#include + +#include "rtl8187.h" +#include "rtl8187_leds.h" + +static void led_turn_on(struct work_struct *work) +{ + /* As this routine does read/write operations on the hardware, it must + * be run from a work queue. + */ + u8 reg; + struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv, + led_on.work); + struct rtl8187_led *led = &priv->led_tx; + + /* Don't change the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + /* Skip if the LED is not registered. */ + if (!led->dev) + return; + mutex_lock(&priv->conf_mutex); + switch (led->ledpin) { + case LED_PIN_GPIO0: + rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00); + break; + case LED_PIN_LED0: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 4); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_LED1: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 5); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_HW: + default: + break; + } + mutex_unlock(&priv->conf_mutex); +} + +static void led_turn_off(struct work_struct *work) +{ + /* As this routine does read/write operations on the hardware, it must + * be run from a work queue. + */ + u8 reg; + struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv, + led_off.work); + struct rtl8187_led *led = &priv->led_tx; + + /* Don't change the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + /* Skip if the LED is not registered. */ + if (!led->dev) + return; + mutex_lock(&priv->conf_mutex); + switch (led->ledpin) { + case LED_PIN_GPIO0: + rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01); + break; + case LED_PIN_LED0: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 4); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_LED1: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 5); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_HW: + default: + break; + } + mutex_unlock(&priv->conf_mutex); +} + +/* Callback from the LED subsystem. */ +static void rtl8187_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) +{ + struct rtl8187_led *led = container_of(led_dev, struct rtl8187_led, + led_dev); + struct ieee80211_hw *hw = led->dev; + struct rtl8187_priv *priv = hw->priv; + + if (brightness == LED_OFF) { + queue_delayed_work(hw->workqueue, &priv->led_off, 0); + /* The LED is off for 1/20 sec so that it just blinks. */ + queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20); + } else + queue_delayed_work(hw->workqueue, &priv->led_on, 0); +} + +static int rtl8187_register_led(struct ieee80211_hw *dev, + struct rtl8187_led *led, const char *name, + const char *default_trigger, u8 ledpin) +{ + int err; + struct rtl8187_priv *priv = dev->priv; + + if (led->dev) + return -EEXIST; + if (!default_trigger) + return -EINVAL; + led->dev = dev; + led->ledpin = ledpin; + strncpy(led->name, name, sizeof(led->name)); + + led->led_dev.name = led->name; + led->led_dev.default_trigger = default_trigger; + led->led_dev.brightness_set = rtl8187_led_brightness_set; + + err = led_classdev_register(&priv->udev->dev, &led->led_dev); + if (err) { + printk(KERN_INFO "LEDs: Failed to register %s\n", name); + led->dev = NULL; + return err; + } + return 0; +} + +static void rtl8187_unregister_led(struct rtl8187_led *led) +{ + led_classdev_unregister(&led->led_dev); + led->dev = NULL; +} + +void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid) +{ + struct rtl8187_priv *priv = dev->priv; + char name[RTL8187_LED_MAX_NAME_LEN + 1]; + u8 ledpin; + int err; + + /* According to the vendor driver, the LED operation depends on the + * customer ID encoded in the EEPROM + */ + printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid); + switch (custid) { + case EEPROM_CID_RSVD0: + case EEPROM_CID_RSVD1: + case EEPROM_CID_SERCOMM_PS: + case EEPROM_CID_QMI: + case EEPROM_CID_DELL: + case EEPROM_CID_TOSHIBA: + ledpin = LED_PIN_GPIO0; + break; + case EEPROM_CID_ALPHA0: + ledpin = LED_PIN_LED0; + break; + case EEPROM_CID_HW: + ledpin = LED_PIN_HW; + break; + default: + ledpin = LED_PIN_GPIO0; + } + + INIT_DELAYED_WORK(&priv->led_on, led_turn_on); + INIT_DELAYED_WORK(&priv->led_off, led_turn_off); + + snprintf(name, sizeof(name), + "rtl8187-%s::tx", wiphy_name(dev->wiphy)); + err = rtl8187_register_led(dev, &priv->led_tx, name, + ieee80211_get_tx_led_name(dev), ledpin); + if (err) + goto error; + snprintf(name, sizeof(name), + "rtl8187-%s::rx", wiphy_name(dev->wiphy)); + err = rtl8187_register_led(dev, &priv->led_rx, name, + ieee80211_get_rx_led_name(dev), ledpin); + if (!err) { + queue_delayed_work(dev->workqueue, &priv->led_on, 0); + return; + } + /* registration of RX LED failed - unregister TX */ + rtl8187_unregister_led(&priv->led_tx); +error: + /* If registration of either failed, cancel delayed work */ + cancel_delayed_work_sync(&priv->led_off); + cancel_delayed_work_sync(&priv->led_on); +} + +void rtl8187_leds_exit(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + + rtl8187_unregister_led(&priv->led_tx); + /* turn the LED off before exiting */ + queue_delayed_work(dev->workqueue, &priv->led_off, 0); + cancel_delayed_work_sync(&priv->led_off); + rtl8187_unregister_led(&priv->led_rx); +} +#endif /* def CONFIG_RTL8187_LED */ + diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.h b/drivers/net/wireless/rtl818x/rtl8187_leds.h new file mode 100644 index 0000000..a033202 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.h @@ -0,0 +1,57 @@ +/* + * Definitions for RTL8187 leds + * + * Copyright 2009 Larry Finger + * + * Based on the LED handling in the r8187 driver, which is: + * Copyright (c) Realtek Semiconductor Corp. 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 version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL8187_LED_H +#define RTL8187_LED_H + +#ifdef CONFIG_RTL8187_LEDS + +#define RTL8187_LED_MAX_NAME_LEN 21 + +#include +#include + +enum { + LED_PIN_LED0, + LED_PIN_LED1, + LED_PIN_GPIO0, + LED_PIN_HW +}; + +enum { + EEPROM_CID_RSVD0 = 0x00, + EEPROM_CID_RSVD1 = 0xFF, + EEPROM_CID_ALPHA0 = 0x01, + EEPROM_CID_SERCOMM_PS = 0x02, + EEPROM_CID_HW = 0x03, + EEPROM_CID_TOSHIBA = 0x04, + EEPROM_CID_QMI = 0x07, + EEPROM_CID_DELL = 0x08 +}; + +struct rtl8187_led { + struct ieee80211_hw *dev; + /* The LED class device */ + struct led_classdev led_dev; + /* The pin/method used to control the led */ + u8 ledpin; + /* The unique name string for this LED device. */ + char name[RTL8187_LED_MAX_NAME_LEN + 1]; +}; + +void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code); +void rtl8187_leds_exit(struct ieee80211_hw *dev); + +#endif /* def CONFIG_RTL8187_LED */ + +#endif /* RTL8187_LED_H */ -- cgit v0.10.2 From d577e7cdb1be027bc51ee1030bc7fd647ea6d0da Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Apr 2009 18:30:13 +0200 Subject: p54: fix ps-poll delivery in ap mode PS-Polled frames must be sent with OUT_NOCANCEL flag set, or the firmware will reject all of them, at the station is still blacklisted. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 5368aa3..7139496 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1473,7 +1473,8 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, if (info->control.sta) *aid = info->control.sta->aid; - else + + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; break; } -- cgit v0.10.2 From fef99929cd6b409a67a35e41f7c177bade5bca34 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Apr 2009 19:39:15 +0200 Subject: mac80211: set CLEAR_PS for pspolled frames This patch sets IEEE80211_TX_CTL_CLEAR_PS_FILT for outgoing frames for a half-wake station. this is necessary if one wants to get ps-poll working properly with a p54 ap. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3fb04a8..f336cc7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -409,8 +409,24 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - clear_sta_flags(sta, WLAN_STA_PSPOLL); + if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { + /* + * The sleeping station with pending data is now snoozing. + * It queried us for its buffered frames and will go back + * to deep sleep once it got everything. + * + * inform the driver, in case the hardware does powersave + * frame filtering and keeps a station blacklist on its own + * (e.g: p54), so that frames can be delivered unimpeded. + * + * Note: It should be save to disable the filter now. + * As, it is really unlikely that we still have any pending + * frame for this station in the hw's buffers/fifos left, + * that is not rejected with a unsuccessful tx_status yet. + */ + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + } return TX_CONTINUE; } -- cgit v0.10.2 From d726405af6c8c81d2ee5e6a29301c68b9d4c574f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Apr 2009 16:23:20 +0200 Subject: nl80211: send wiphy along with netdev When listing all wireless netdevs in the system this is useful to print which wiphy they belong to. Just add the attribute, any program that doesn't care will just ignore it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d33cab0..d2cfde6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -538,6 +538,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, + struct cfg80211_registered_device *rdev, struct net_device *dev) { void *hdr; @@ -547,6 +548,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, return -1; NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); return genlmsg_end(msg, hdr); @@ -581,7 +583,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * } if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - wdev->netdev) < 0) { + dev, wdev->netdev) < 0) { mutex_unlock(&dev->devlist_mtx); goto out; } @@ -615,7 +617,8 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) if (!msg) goto out_err; - if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) + if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, + dev, netdev) < 0) goto out_free; dev_put(netdev); -- cgit v0.10.2 From 691597cb26f236ac7471f1adf925a134c86799d6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Apr 2009 19:57:45 +0200 Subject: cfg80211/mac80211: move wext SIWMLME into cfg80211 Since we have ->deauth and ->disassoc we can support the wext SIWMLME call directly without driver wext handlers. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d303c26..019a41e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -833,6 +833,9 @@ int cfg80211_wext_siwscan(struct net_device *dev, int cfg80211_wext_giwscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra); +int cfg80211_wext_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); int cfg80211_wext_giwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 520efa8..daf7528 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1268,22 +1268,18 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) { - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - /* TODO: req->ie */ + /* TODO: req->ie, req->peer_addr */ return ieee80211_sta_deauthenticate(sdata, req->reason_code); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) { - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - /* TODO: req->ie */ + /* TODO: req->ie, req->peer_addr */ return ieee80211_sta_disassociate(sdata, req->reason_code); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a16c9d7..428742d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2338,9 +2338,6 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", sdata->dev->name, reason); - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EINVAL; - ieee80211_set_disassoc(sdata, true, true, reason); return 0; } @@ -2352,9 +2349,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", sdata->dev->name, reason); - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EINVAL; - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) return -ENOLINK; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 1c4664b..896704c 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -612,29 +612,6 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - struct iw_mlme *mlme = (struct iw_mlme *) extra; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!(sdata->vif.type == NL80211_IFTYPE_STATION)) - return -EINVAL; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* TODO: mlme->addr.sa_data */ - return ieee80211_sta_deauthenticate(sdata, mlme->reason_code); - case IW_MLME_DISASSOC: - /* TODO: mlme->addr.sa_data */ - return ieee80211_sta_disassociate(sdata, mlme->reason_code); - default: - return -EOPNOTSUPP; - } -} - static int ieee80211_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, @@ -1076,7 +1053,7 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWTHRSPY */ (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ - (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ + (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 0fd1db6..6fd7bf7 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -206,7 +207,6 @@ int cfg80211_wext_giwrange(struct net_device *dev, range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { int i; struct ieee80211_supported_band *sband; @@ -241,3 +241,47 @@ int cfg80211_wext_giwrange(struct net_device *dev, return 0; } EXPORT_SYMBOL(cfg80211_wext_giwrange); + +int cfg80211_wext_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + struct cfg80211_registered_device *rdev; + union { + struct cfg80211_disassoc_request disassoc; + struct cfg80211_deauth_request deauth; + } cmd; + + if (!wdev) + return -EOPNOTSUPP; + + rdev = wiphy_to_dev(wdev->wiphy); + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (mlme->addr.sa_family != ARPHRD_ETHER) + return -EINVAL; + + memset(&cmd, 0, sizeof(cmd)); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + if (!rdev->ops->deauth) + return -EOPNOTSUPP; + cmd.deauth.peer_addr = mlme->addr.sa_data; + cmd.deauth.reason_code = mlme->reason_code; + return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth); + case IW_MLME_DISASSOC: + if (!rdev->ops->disassoc) + return -EOPNOTSUPP; + cmd.disassoc.peer_addr = mlme->addr.sa_data; + cmd.disassoc.reason_code = mlme->reason_code; + return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL(cfg80211_wext_siwmlme); -- cgit v0.10.2 From 04a773ade0680d862b479d7219973df60f7a3834 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Apr 2009 21:24:32 +0200 Subject: cfg80211/nl80211: add IBSS API This adds IBSS API along with (preliminary) wext handlers. The wext handlers can only do IBSS so you need to call them from your own wext handlers if the mode is IBSS. The nl80211 API requires * an SSID * a channel (frequency) for the case that a new IBSS has to be created It optionally supports * a flag to fix the channel * a fixed BSSID The cfg80211 code also takes care to leave the IBSS before the netdev is set down. If wireless extensions are used, it also caches values when the interface is down and instructs the driver to join when the interface is set up. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c014238..25ce3e4 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -223,6 +223,15 @@ * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this * event matches with MLME-MICHAELMICFAILURE.indication() primitive * + * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a + * FREQ attribute (for the initial frequency if no peer can be found) + * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those + * should be fixed rather than automatically determined. Can only be + * executed on a network interface that is UP, and fixed BSSID/FREQ + * may be rejected. + * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is + * determined by the network interface. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -288,6 +297,9 @@ enum nl80211_commands { NL80211_CMD_REG_BEACON_HINT, + NL80211_CMD_JOIN_IBSS, + NL80211_CMD_LEAVE_IBSS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -456,6 +468,9 @@ enum nl80211_commands { * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported * cipher suites * + * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look + * for other networks on different channels + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -547,6 +562,9 @@ enum nl80211_attrs { NL80211_ATTR_FREQ_BEFORE, NL80211_ATTR_FREQ_AFTER, + + NL80211_ATTR_FREQ_FIXED, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 019a41e..5287a3e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -658,6 +658,31 @@ struct cfg80211_disassoc_request { }; /** + * struct cfg80211_ibss_params - IBSS parameters + * + * This structure defines the IBSS parameters for the join_ibss() + * method. + * + * @ssid: The SSID, will always be non-null. + * @ssid_len: The length of the SSID, will always be non-zero. + * @bssid: Fixed BSSID requested, maybe be %NULL, if set do not + * search for IBSSs with a different BSSID. + * @channel: The channel to use if no IBSS can be found to join. + * @channel_fixed: The channel should be fixed -- do not search for + * IBSSs to join on other channels. + * @ie: information element(s) to include in the beacon + * @ie_len: length of that + */ +struct cfg80211_ibss_params { + u8 *ssid; + u8 *bssid; + struct ieee80211_channel *channel; + u8 *ie; + u8 ssid_len, ie_len; + bool channel_fixed; +}; + +/** * struct cfg80211_ops - backend description for wireless configuration * * This struct is registered by fullmac card drivers and/or wireless stacks @@ -732,6 +757,11 @@ struct cfg80211_disassoc_request { * @assoc: Request to (re)associate with the specified peer * @deauth: Request to deauthenticate from the specified peer * @disassoc: Request to disassociate from the specified peer + * + * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call + * cfg80211_ibss_joined(), also call that function when changing BSSID due + * to a merge. + * @leave_ibss: Leave the IBSS. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy); @@ -817,6 +847,10 @@ struct cfg80211_ops { struct cfg80211_deauth_request *req); int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req); + + int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); + int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); }; /* temporary wext handlers */ @@ -839,6 +873,28 @@ int cfg80211_wext_siwmlme(struct net_device *dev, int cfg80211_wext_giwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra); +int cfg80211_ibss_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_ibss_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_ibss_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_ibss_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); + +/* wext helper for now (to be removed) */ +struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, + struct iw_freq *freq); /** * cfg80211_scan_done - notify that scan finished @@ -984,4 +1040,20 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, enum nl80211_key_type key_type, int key_id, const u8 *tsc); +/** + * cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS + * + * @dev: network device + * @bssid: the BSSID of the IBSS joined + * @gfp: allocation flags + * + * This function notifies cfg80211 that the device joined an IBSS or + * switched to a different BSSID. Before this function can be called, + * either a beacon has to have been received from the IBSS, or one of + * the cfg80211_inform_bss{,_frame} functions must have been called + * with the locally generated beacon -- this guarantees that there is + * always a scan result for this IBSS. cfg80211 will handle the rest. + */ +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); + #endif /* __NET_CFG80211_H */ diff --git a/include/net/wireless.h b/include/net/wireless.h index 44c2642..abd27b0 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -265,6 +265,8 @@ struct wiphy { * * @wiphy: pointer to hardware description * @iftype: interface type + * @list: (private) + * @netdev (private) */ struct wireless_dev { struct wiphy *wiphy; @@ -273,6 +275,18 @@ struct wireless_dev { /* private to the generic wireless code */ struct list_head list; struct net_device *netdev; + + /* currently used for IBSS - might be rearranged in the future */ + struct cfg80211_bss *current_bss; + u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + +#ifdef CONFIG_WIRELESS_EXT + /* wext data */ + struct cfg80211_ibss_params wext; + u8 wext_bssid[ETH_ALEN]; +#endif }; /** diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 6d1e7b2..14ea01c 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o -cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/wireless/core.c b/net/wireless/core.c index d1f5565..de1ac51 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -450,6 +450,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, dev->ieee80211_ptr->netdev = dev; mutex_unlock(&rdev->devlist_mtx); break; + case NETDEV_GOING_DOWN: + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + break; + if (!dev->ieee80211_ptr->ssid_len) + break; + cfg80211_leave_ibss(rdev, dev); + break; + case NETDEV_UP: +#ifdef CONFIG_WIRELESS_EXT + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + break; + if (!dev->ieee80211_ptr->wext.ssid_len) + break; + cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext); + break; +#endif case NETDEV_UNREGISTER: mutex_lock(&rdev->devlist_mtx); if (!list_empty(&dev->ieee80211_ptr->list)) { diff --git a/net/wireless/core.h b/net/wireless/core.h index 02668b02..2ef3595 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -144,4 +144,12 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev); void cfg80211_bss_age(struct cfg80211_registered_device *dev, unsigned long age_secs); +/* IBSS */ +int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params); +void cfg80211_clear_ibss(struct net_device *dev); +int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c new file mode 100644 index 0000000..2bf42fd --- /dev/null +++ b/net/wireless/ibss.c @@ -0,0 +1,360 @@ +/* + * Some IBSS support code for cfg80211. + * + * Copyright 2009 Johannes Berg + */ + +#include +#include +#include +#include +#include "nl80211.h" + + +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_bss *bss; +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; +#endif + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return; + + if (WARN_ON(!wdev->ssid_len)) + return; + + if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0) + return; + + bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); + + if (WARN_ON(!bss)) + return; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->current_bss); + } + + cfg80211_hold_bss(bss); + wdev->current_bss = bss; + memcpy(wdev->bssid, bssid, ETH_ALEN); + + nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); +#ifdef CONFIG_WIRELESS_EXT + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} +EXPORT_SYMBOL(cfg80211_ibss_joined); + +int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + if (wdev->ssid_len) + return -EALREADY; + +#ifdef CONFIG_WIRELESS_EXT + wdev->wext.channel = params->channel; +#endif + err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); + + if (err) + return err; + + memcpy(wdev->ssid, params->ssid, params->ssid_len); + wdev->ssid_len = params->ssid_len; + + return 0; +} + +void cfg80211_clear_ibss(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->current_bss); + } + + wdev->current_bss = NULL; + wdev->ssid_len = 0; + memset(wdev->bssid, 0, ETH_ALEN); +} + +int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + int err; + + err = rdev->ops->leave_ibss(&rdev->wiphy, dev); + + if (err) + return err; + + cfg80211_clear_ibss(dev); + + return 0; +} + +#ifdef CONFIG_WIRELESS_EXT +static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + enum ieee80211_band band; + int i; + + /* try to find an IBSS channel if none requested ... */ + if (!wdev->wext.channel) { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + + sband = rdev->wiphy.bands[band]; + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + continue; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + wdev->wext.channel = chan; + break; + } + + if (wdev->wext.channel) + break; + } + + if (!wdev->wext.channel) + return -EINVAL; + } + + /* don't join -- SSID is not there */ + if (!wdev->wext.ssid_len) + return 0; + + if (!netif_running(wdev->netdev)) + return 0; + + return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy), + wdev->netdev, &wdev->wext); +} + +int cfg80211_ibss_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + return -EOPNOTSUPP; + + chan = cfg80211_wext_freq(wdev->wiphy, freq); + if (chan && IS_ERR(chan)) + return PTR_ERR(chan); + + if (chan && + (chan->flags & IEEE80211_CHAN_NO_IBSS || + chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; + + if (wdev->wext.channel == chan) + return 0; + + if (wdev->ssid_len) { + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev); + if (err) + return err; + } + + if (chan) { + wdev->wext.channel = chan; + wdev->wext.channel_fixed = true; + } else { + /* cfg80211_ibss_wext_join will pick one if needed */ + wdev->wext.channel_fixed = false; + } + + return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); + +int cfg80211_ibss_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan = NULL; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (wdev->current_bss) + chan = wdev->current_bss->channel; + else if (wdev->wext.channel) + chan = wdev->wext.channel; + + if (chan) { + freq->m = chan->center_freq; + freq->e = 6; + return 0; + } + + /* no channel if not joining */ + return -EINVAL; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq); + +int cfg80211_ibss_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + size_t len = data->length; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + return -EOPNOTSUPP; + + if (wdev->ssid_len) { + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev); + if (err) + return err; + } + + /* iwconfig uses nul termination in SSID.. */ + if (len > 0 && ssid[len - 1] == '\0') + len--; + + wdev->wext.ssid = wdev->ssid; + memcpy(wdev->wext.ssid, ssid, len); + wdev->wext.ssid_len = len; + + return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); + +int cfg80211_ibss_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + data->flags = 0; + + if (wdev->ssid_len) { + data->flags = 1; + data->length = wdev->ssid_len; + memcpy(ssid, wdev->ssid, data->length); + } else if (wdev->wext.ssid) { + data->flags = 1; + data->length = wdev->wext.ssid_len; + memcpy(ssid, wdev->wext.ssid, data->length); + } + + return 0; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid); + +int cfg80211_ibss_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + u8 *bssid = ap_addr->sa_data; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + return -EOPNOTSUPP; + + if (ap_addr->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* automatic mode */ + if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) + bssid = NULL; + + /* both automatic */ + if (!bssid && !wdev->wext.bssid) + return 0; + + /* fixed already - and no change */ + if (wdev->wext.bssid && bssid && + compare_ether_addr(bssid, wdev->wext.bssid) == 0) + return 0; + + if (wdev->ssid_len) { + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev); + if (err) + return err; + } + + if (bssid) { + memcpy(wdev->wext_bssid, bssid, ETH_ALEN); + wdev->wext.bssid = wdev->wext_bssid; + } else + wdev->wext.bssid = NULL; + + return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); + +int cfg80211_ibss_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + ap_addr->sa_family = ARPHRD_ETHER; + + if (wdev->wext.bssid) { + memcpy(ap_addr->sa_data, wdev->wext.bssid, ETH_ALEN); + return 0; + } + + memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN); + return 0; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap); +#endif diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d2cfde6..16f8635 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -116,6 +116,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { .len = IEEE80211_MAX_SSID_LEN }, [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, + [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, }; /* IE validation */ @@ -322,6 +323,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(assoc, ASSOCIATE); CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); + CMD(join_ibss, JOIN_IBSS); #undef CMD nla_nest_end(msg, nl_cmds); @@ -668,7 +670,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *drv; struct vif_params params; int err, ifindex; - enum nl80211_iftype type; + enum nl80211_iftype otype, ntype; struct net_device *dev; u32 _flags, *flags = NULL; bool change = false; @@ -682,30 +684,27 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) goto unlock_rtnl; ifindex = dev->ifindex; - type = dev->ieee80211_ptr->iftype; + otype = ntype = dev->ieee80211_ptr->iftype; dev_put(dev); if (info->attrs[NL80211_ATTR_IFTYPE]) { - enum nl80211_iftype ntype; - ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); - if (type != ntype) + if (otype != ntype) change = true; - type = ntype; - if (type > NL80211_IFTYPE_MAX) { + if (ntype > NL80211_IFTYPE_MAX) { err = -EINVAL; goto unlock; } } if (!drv->ops->change_virtual_intf || - !(drv->wiphy.interface_modes & (1 << type))) { + !(drv->wiphy.interface_modes & (1 << ntype))) { err = -EOPNOTSUPP; goto unlock; } if (info->attrs[NL80211_ATTR_MESH_ID]) { - if (type != NL80211_IFTYPE_MESH_POINT) { + if (ntype != NL80211_IFTYPE_MESH_POINT) { err = -EINVAL; goto unlock; } @@ -715,7 +714,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { - if (type != NL80211_IFTYPE_MONITOR) { + if (ntype != NL80211_IFTYPE_MONITOR) { err = -EINVAL; goto unlock; } @@ -730,12 +729,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (change) err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, - type, flags, ¶ms); + ntype, flags, ¶ms); else err = 0; dev = __dev_get_by_index(&init_net, ifindex); - WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); + WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype)); + + if (dev && !err && (ntype != otype)) { + if (otype == NL80211_IFTYPE_ADHOC) + cfg80211_clear_ibss(dev); + } unlock: cfg80211_put_dev(drv); @@ -3052,6 +3056,114 @@ unlock_rtnl: return err; } +static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + struct net_device *dev; + struct cfg80211_ibss_params ibss; + struct wiphy *wiphy; + int err; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || + !info->attrs[NL80211_ATTR_SSID] || + !nla_len(info->attrs[NL80211_ATTR_SSID])) + return -EINVAL; + + rtnl_lock(); + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + goto unlock_rtnl; + + if (!drv->ops->join_ibss) { + err = -EOPNOTSUPP; + goto out; + } + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + wiphy = &drv->wiphy; + memset(&ibss, 0, sizeof(ibss)); + + if (info->attrs[NL80211_ATTR_MAC]) + ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + + if (info->attrs[NL80211_ATTR_IE]) { + ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + ibss.channel = ieee80211_get_channel(wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!ibss.channel || + ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || + ibss.channel->flags & IEEE80211_CHAN_DISABLED) { + err = -EINVAL; + goto out; + } + + ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; + + err = cfg80211_join_ibss(drv, dev, &ibss); + +out: + cfg80211_put_dev(drv); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + return err; +} + +static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + struct net_device *dev; + int err; + + rtnl_lock(); + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + goto unlock_rtnl; + + if (!drv->ops->leave_ibss) { + err = -EOPNOTSUPP; + goto out; + } + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + err = cfg80211_leave_ibss(drv, dev); + +out: + cfg80211_put_dev(drv); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -3253,6 +3365,18 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_JOIN_IBSS, + .doit = nl80211_join_ibss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_LEAVE_IBSS, + .doit = nl80211_leave_ibss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", @@ -3466,6 +3590,40 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, NL80211_CMD_DISASSOCIATE); } +void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, enum nl80211_key_type key_type, int key_id, diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b3aaa59..17d2d8b 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -34,4 +34,8 @@ nl80211_send_beacon_hint_event(struct wiphy *wiphy, struct ieee80211_channel *channel_before, struct ieee80211_channel *channel_after); +void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + gfp_t gfp); + #endif /* __NET_WIRELESS_NL80211_H */ diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6fd7bf7..57eaea26 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -285,3 +285,33 @@ int cfg80211_wext_siwmlme(struct net_device *dev, } } EXPORT_SYMBOL(cfg80211_wext_siwmlme); + + +/** + * cfg80211_wext_freq - get wext frequency for non-"auto" + * @wiphy: the wiphy + * @freq: the wext freq encoding + * + * Returns a channel, %NULL for auto, or an ERR_PTR for errors! + */ +struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, + struct iw_freq *freq) +{ + if (freq->e == 0) { + if (freq->m < 0) + return NULL; + else + return ieee80211_get_channel(wiphy, + ieee80211_channel_to_frequency(freq->m)); + } else { + int i, div = 1000000; + for (i = 0; i < freq->e; i++) + div /= 10; + if (div > 0) + return ieee80211_get_channel(wiphy, freq->m / div); + else + return ERR_PTR(-EINVAL); + } + +} +EXPORT_SYMBOL(cfg80211_wext_freq); -- cgit v0.10.2 From af8cdcd828ad751fae8e6cbfe94eef9f2f23b14b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 19 Apr 2009 21:25:43 +0200 Subject: mac80211: convert to cfg80211 IBSS API This converts mac80211 to the new cfg80211 IBSS API, the wext handling functions are called where appropriate. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index daf7528..14013dc 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1283,6 +1283,21 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, return ieee80211_sta_disassociate(sdata, req->reason_code); } +static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return ieee80211_ibss_join(sdata, params); +} + +static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return ieee80211_ibss_leave(sdata); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1319,4 +1334,6 @@ struct cfg80211_ops mac80211_config_ops = { .assoc = ieee80211_assoc, .deauth = ieee80211_deauth, .disassoc = ieee80211_disassoc, + .join_ibss = ieee80211_join_ibss, + .leave_ibss = ieee80211_leave_ibss, }; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3201e1f..4f7a545 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -59,74 +59,59 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.bssid, 0); } -static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, const int beacon_int, - const int freq, - const size_t supp_rates_len, - const u8 *supp_rates, - const u16 capability, u64 tsf) +static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, + const u8 *bssid, const int beacon_int, + struct ieee80211_channel *chan, + const size_t supp_rates_len, + const u8 *supp_rates, + const u16 capability, u64 tsf) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; - int res = 0, rates, i, j; + int rates, i, j; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos; struct ieee80211_supported_band *sband; - union iwreq_data wrqu; if (local->ops->reset_tsf) { /* Reset own TSF to allow time synchronization work. */ local->ops->reset_tsf(local_to_hw(local)); } - if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) && - memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0) - return res; + skb = ifibss->skb; + rcu_assign_pointer(ifibss->presp, NULL); + synchronize_rcu(); + skb->data = skb->head; + skb->len = 0; + skb_reset_tail_pointer(skb); + skb_reserve(skb, sdata->local->hw.extra_tx_headroom); - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for probe " - "response\n", sdata->dev->name); - return -ENOMEM; - } - - if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) { - /* Remove possible STA entries from other IBSS networks. */ - sta_info_flush_delayed(sdata); - } + if (memcmp(ifibss->bssid, bssid, ETH_ALEN)) + sta_info_flush(sdata->local, sdata); memcpy(ifibss->bssid, bssid, ETH_ALEN); - res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); - if (res) - return res; local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; - sdata->drop_unencrypted = capability & - WLAN_CAPABILITY_PRIVACY ? 1 : 0; - - res = ieee80211_set_freq(sdata, freq); + sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - if (res) - return res; + ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + local->oper_channel = chan; + local->oper_channel_type = NL80211_CHAN_NO_HT; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + sband = local->hw.wiphy->bands[chan->band]; /* Build IBSS probe response */ - - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) - skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); - mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int); mgmt->u.beacon.timestamp = cpu_to_le64(tsf); mgmt->u.beacon.capab_info = cpu_to_le16(capability); @@ -147,7 +132,7 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2 + 1); *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; - *pos++ = ieee80211_frequency_to_channel(freq); + *pos++ = ieee80211_frequency_to_channel(chan->center_freq); } pos = skb_put(skb, 2 + 2); @@ -165,12 +150,15 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, memcpy(pos, &supp_rates[8], rates); } - ifibss->probe_resp = skb; + if (ifibss->ie_len) + memcpy(skb_put(skb, ifibss->ie_len), + ifibss->ie, ifibss->ie_len); + + rcu_assign_pointer(ifibss->presp, skb); ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | IEEE80211_IFCC_BEACON_ENABLED); - rates = 0; for (i = 0; i < supp_rates_len; i++) { int bitrate = (supp_rates[i] & 0x7f) * 5; @@ -181,27 +169,24 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); - ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET; ifibss->state = IEEE80211_IBSS_MLME_JOINED; - mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + mod_timer(&ifibss->timer, + round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); - - return res; + cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, + mgmt, skb->len, 0, GFP_KERNEL); + cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); } -static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss *bss) +static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss *bss) { - return __ieee80211_sta_join_ibss(sdata, - bss->cbss.bssid, - bss->cbss.beacon_interval, - bss->cbss.channel->center_freq, - bss->supp_rates_len, bss->supp_rates, - bss->cbss.capability, - bss->cbss.tsf); + __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, + bss->cbss.beacon_interval, + bss->cbss.channel, + bss->supp_rates_len, bss->supp_rates, + bss->cbss.capability, + bss->cbss.tsf); } static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, @@ -277,7 +262,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* we use a fixed BSSID */ - if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET) + if (sdata->u.ibss.bssid) goto put_bss; /* not an IBSS */ @@ -369,13 +354,14 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, struct sta_info *sta; int band = local->hw.conf.channel->band; - /* TODO: Could consider removing the least recently used entry and - * allow new one to be added. */ + /* + * XXX: Consider removing the least recently used entry and + * allow new one to be added. + */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry %pM\n", sdata->dev->name, addr); - } + if (net_ratelimit()) + printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", + sdata->dev->name, addr); return NULL; } @@ -432,14 +418,15 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + mod_timer(&ifibss->timer, + round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); + if (ieee80211_sta_active_ibss(sdata)) return; - if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) && - (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL))) + if (ifibss->fixed_channel) return; printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " @@ -455,7 +442,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) ieee80211_request_scan(sdata, &sdata->local->int_scan_req); } -static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) +static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; @@ -466,7 +453,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) u16 capability; int i; - if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) { + if (ifibss->fixed_bssid) { memcpy(bssid, ifibss->bssid, ETH_ALEN); } else { /* Generate random, not broadcast, locally administered BSSID. Mix in @@ -482,7 +469,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", sdata->dev->name, bssid); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[ifibss->channel->band]; if (local->hw.conf.beacon_int == 0) local->hw.conf.beacon_int = 100; @@ -500,24 +487,20 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) *pos++ = (u8) (rate / 5); } - return __ieee80211_sta_join_ibss(sdata, - bssid, local->hw.conf.beacon_int, - local->hw.conf.channel->center_freq, - sband->n_bitrates, supp_rates, - capability, 0); + __ieee80211_sta_join_ibss(sdata, bssid, local->hw.conf.beacon_int, + ifibss->channel, sband->n_bitrates, + supp_rates, capability, 0); } -static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) +static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct ieee80211_bss *bss; + struct ieee80211_channel *chan = NULL; const u8 *bssid = NULL; int active_ibss; - if (ifibss->ssid_len == 0) - return -EINVAL; - active_ibss = ieee80211_sta_active_ibss(sdata); #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", @@ -525,11 +508,15 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (active_ibss) - return 0; + return; - if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) + if (ifibss->fixed_bssid) + bssid = ifibss->bssid; + if (ifibss->fixed_channel) + chan = ifibss->channel; + if (!is_zero_ether_addr(ifibss->bssid)) bssid = ifibss->bssid; - bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid, + bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, ifibss->ssid, ifibss->ssid_len, WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); @@ -540,18 +527,14 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) "%pM\n", bss->cbss.bssid, ifibss->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (bss && - (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) || - memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN))) { - int ret; - + if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) { printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", sdata->dev->name, bss->cbss.bssid); - ret = ieee80211_sta_join_ibss(sdata, bss); + ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); - return ret; + return; } else if (bss) ieee80211_rx_bss_put(local, bss); @@ -562,29 +545,31 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) /* Selected IBSS not found in current scan results - try to scan */ if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && !ieee80211_sta_active_ibss(sdata)) { - mod_timer(&ifibss->timer, jiffies + - IEEE80211_IBSS_MERGE_INTERVAL); - } else if (time_after(jiffies, local->last_scan_completed + + mod_timer(&ifibss->timer, + round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); + } else if (time_after(jiffies, ifibss->last_scan_completed + IEEE80211_SCAN_INTERVAL)) { printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " "join\n", sdata->dev->name); /* XXX maybe racy? */ if (local->scan_req) - return -EBUSY; + return; memcpy(local->int_scan_req.ssids[0].ssid, ifibss->ssid, IEEE80211_MAX_SSID_LEN); - local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; - return ieee80211_request_scan(sdata, &local->int_scan_req); + local->int_scan_req.ssids[0].ssid_len = + ifibss->ssid_len; + ieee80211_request_scan(sdata, &local->int_scan_req); } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { int interval = IEEE80211_SCAN_INTERVAL; if (time_after(jiffies, ifibss->ibss_join_req + IEEE80211_IBSS_JOIN_TIMEOUT)) { - if (!(local->oper_channel->flags & - IEEE80211_CHAN_NO_IBSS)) - return ieee80211_sta_create_ibss(sdata); + if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) { + ieee80211_sta_create_ibss(sdata); + return; + } printk(KERN_DEBUG "%s: IBSS not allowed on" " %d MHz\n", sdata->dev->name, local->hw.conf.channel->center_freq); @@ -595,11 +580,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) } ifibss->state = IEEE80211_IBSS_MLME_SEARCH; - mod_timer(&ifibss->timer, jiffies + interval); - return 0; + mod_timer(&ifibss->timer, + round_jiffies(jiffies + interval)); } - - return 0; } static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, @@ -614,7 +597,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, u8 *pos, *end; if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || - len < 24 + 2 || !ifibss->probe_resp) + len < 24 + 2 || !ifibss->presp) return; if (local->ops->tx_last_beacon) @@ -649,13 +632,13 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, } if (pos[1] != 0 && (pos[1] != ifibss->ssid_len || - memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) { + !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { /* Ignore ProbeReq for foreign SSID */ return; } /* Reply with ProbeResp */ - skb = skb_copy(ifibss->probe_resp, GFP_KERNEL); + skb = skb_copy(ifibss->presp, GFP_KERNEL); if (!skb) return; @@ -794,89 +777,21 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) setup_timer(&ifibss->timer, ieee80211_ibss_timer, (unsigned long) sdata); skb_queue_head_init(&ifibss->skb_queue); - - ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | - IEEE80211_IBSS_AUTO_CHANNEL_SEL; -} - -int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; - - if (ifibss->ssid_len) - ifibss->flags |= IEEE80211_IBSS_SSID_SET; - else - ifibss->flags &= ~IEEE80211_IBSS_SSID_SET; - - ifibss->ibss_join_req = jiffies; - ifibss->state = IEEE80211_IBSS_MLME_SEARCH; - set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); - - return 0; -} - -int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - if (len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - - if (ifibss->ssid_len != len || memcmp(ifibss->ssid, ssid, len) != 0) { - memset(ifibss->ssid, 0, sizeof(ifibss->ssid)); - memcpy(ifibss->ssid, ssid, len); - ifibss->ssid_len = len; - } - - return ieee80211_ibss_commit(sdata); -} - -int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - memcpy(ssid, ifibss->ssid, ifibss->ssid_len); - *len = ifibss->ssid_len; - - return 0; -} - -int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - if (is_valid_ether_addr(bssid)) { - memcpy(ifibss->bssid, bssid, ETH_ALEN); - ifibss->flags |= IEEE80211_IBSS_BSSID_SET; - } else { - memset(ifibss->bssid, 0, ETH_ALEN); - ifibss->flags &= ~IEEE80211_IBSS_BSSID_SET; - } - - if (netif_running(sdata->dev)) { - if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { - printk(KERN_DEBUG "%s: Failed to config new BSSID to " - "the low-level driver\n", sdata->dev->name); - } - } - - return ieee80211_ibss_commit(sdata); } /* scan finished notification */ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - struct ieee80211_if_ibss *ifibss; + struct ieee80211_sub_if_data *sdata; - if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { - ifibss = &sdata->u.ibss; - if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) || - !ieee80211_sta_active_ibss(sdata)) - ieee80211_sta_find_ibss(sdata); + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (sdata->vif.type != NL80211_IFTYPE_ADHOC) + continue; + sdata->u.ibss.last_scan_completed = jiffies; + ieee80211_sta_find_ibss(sdata); } + rcu_read_unlock(); } ieee80211_rx_result @@ -906,3 +821,71 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, return RX_DROP_MONITOR; } + +int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, + struct cfg80211_ibss_params *params) +{ + struct sk_buff *skb; + + memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); + sdata->u.ibss.ssid_len = params->ssid_len; + + if (params->bssid) { + memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); + sdata->u.ibss.fixed_bssid = true; + } else + sdata->u.ibss.fixed_bssid = false; + + sdata->u.ibss.channel = params->channel; + sdata->u.ibss.fixed_channel = params->channel_fixed; + + if (params->ie) { + sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len, + GFP_KERNEL); + if (sdata->u.ibss.ie) + sdata->u.ibss.ie_len = params->ie_len; + } + + skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + + 36 /* bitrates */ + + 34 /* SSID */ + + 3 /* DS params */ + + 4 /* IBSS params */ + + params->ie_len); + if (!skb) + return -ENOMEM; + + sdata->u.ibss.skb = skb; + sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; + sdata->u.ibss.ibss_join_req = jiffies; + + set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); + queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); + + return 0; +} + +int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) +{ + struct sk_buff *skb; + + del_timer_sync(&sdata->u.ibss.timer); + clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); + cancel_work_sync(&sdata->u.ibss.work); + clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); + + sta_info_flush(sdata->local, sdata); + + /* remove beacon */ + kfree(sdata->u.ibss.ie); + skb = sdata->u.ibss.presp; + rcu_assign_pointer(sdata->u.ibss.presp, NULL); + ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); + synchronize_rcu(); + kfree_skb(skb); + + skb_queue_purge(&sdata->u.ibss.skb_queue); + memset(sdata->u.ibss.bssid, 0, ETH_ALEN); + + return 0; +} diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 38c9806..e770c1e8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -323,14 +323,6 @@ struct ieee80211_if_managed { size_t sme_auth_ie_len; }; -enum ieee80211_ibss_flags { - IEEE80211_IBSS_AUTO_CHANNEL_SEL = BIT(0), - IEEE80211_IBSS_AUTO_BSSID_SEL = BIT(1), - IEEE80211_IBSS_BSSID_SET = BIT(2), - IEEE80211_IBSS_PREV_BSSID_SET = BIT(3), - IEEE80211_IBSS_SSID_SET = BIT(4), -}; - enum ieee80211_ibss_request { IEEE80211_IBSS_REQ_RUN = 0, }; @@ -341,17 +333,20 @@ struct ieee80211_if_ibss { struct sk_buff_head skb_queue; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - - u32 flags; + unsigned long request; + unsigned long last_scan_completed; + bool fixed_bssid; + bool fixed_channel; u8 bssid[ETH_ALEN]; - - unsigned long request; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len, ie_len; + u8 *ie; + struct ieee80211_channel *channel; unsigned long ibss_join_req; - struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ + /* probe response/beacon for IBSS */ + struct sk_buff *presp, *skb; enum { IEEE80211_IBSS_MLME_SEARCH, @@ -630,8 +625,6 @@ struct ieee80211_local { spinlock_t sta_lock; unsigned long num_sta; struct list_head sta_list; - struct list_head sta_flush_list; - struct work_struct sta_flush_work; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; @@ -681,7 +674,6 @@ struct ieee80211_local { int scan_ies_len; enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; - unsigned long last_scan_completed; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; @@ -946,10 +938,6 @@ int ieee80211_max_network_latency(struct notifier_block *nb, unsigned long data, void *dummy); /* IBSS code */ -int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata); -int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); -int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); -int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result @@ -957,6 +945,9 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_rx_status *rx_status); struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, u8 *bssid, u8 *addr, u32 supp_rates); +int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, + struct cfg80211_ibss_params *params); +int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); /* scan/BSS handling */ void ieee80211_scan_work(struct work_struct *work); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5d60deb..5242597 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -235,11 +235,7 @@ static int ieee80211_open(struct net_device *dev) netif_addr_unlock_bh(local->mdev); break; case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - else - sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; + sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; /* fall through */ default: conf.vif = &sdata->vif; @@ -327,8 +323,6 @@ static int ieee80211_open(struct net_device *dev) */ if (sdata->vif.type == NL80211_IFTYPE_STATION) queue_work(local->hw.workqueue, &sdata->u.mgd.work); - else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - queue_work(local->hw.workqueue, &sdata->u.ibss.work); netif_tx_start_all_queues(dev); @@ -499,7 +493,6 @@ static int ieee80211_stop(struct net_device *dev) /* fall through */ case NL80211_IFTYPE_ADHOC: if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - memset(sdata->u.ibss.bssid, 0, ETH_ALEN); del_timer_sync(&sdata->u.ibss.timer); cancel_work_sync(&sdata->u.ibss.work); synchronize_rcu(); @@ -653,7 +646,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) mesh_rmc_free(sdata); break; case NL80211_IFTYPE_ADHOC: - kfree_skb(sdata->u.ibss.probe_resp); + if (WARN_ON(sdata->u.ibss.presp)) + kfree_skb(sdata->u.ibss.presp); break; case NL80211_IFTYPE_STATION: kfree(sdata->u.mgd.extra_ie); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 049ce86..d26fc39 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -209,7 +209,7 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) !!rcu_dereference(sdata->u.ap.beacon); break; case NL80211_IFTYPE_ADHOC: - conf.enable_beacon = !!sdata->u.ibss.probe_resp; + conf.enable_beacon = !!sdata->u.ibss.presp; break; case NL80211_IFTYPE_MESH_POINT: conf.enable_beacon = true; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 20df861..f25b07f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -295,8 +295,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - local->last_scan_completed = jiffies; - if (local->hw_scanning) { local->hw_scanning = false; /* diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c5f14e6..654a8e9 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -686,41 +686,10 @@ static void sta_info_debugfs_add_work(struct work_struct *work) } #endif -static void __ieee80211_run_pending_flush(struct ieee80211_local *local) -{ - struct sta_info *sta; - unsigned long flags; - - ASSERT_RTNL(); - - spin_lock_irqsave(&local->sta_lock, flags); - while (!list_empty(&local->sta_flush_list)) { - sta = list_first_entry(&local->sta_flush_list, - struct sta_info, list); - list_del(&sta->list); - spin_unlock_irqrestore(&local->sta_lock, flags); - sta_info_destroy(sta); - spin_lock_irqsave(&local->sta_lock, flags); - } - spin_unlock_irqrestore(&local->sta_lock, flags); -} - -static void ieee80211_sta_flush_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, sta_flush_work); - - rtnl_lock(); - __ieee80211_run_pending_flush(local); - rtnl_unlock(); -} - void sta_info_init(struct ieee80211_local *local) { spin_lock_init(&local->sta_lock); INIT_LIST_HEAD(&local->sta_list); - INIT_LIST_HEAD(&local->sta_flush_list); - INIT_WORK(&local->sta_flush_work, ieee80211_sta_flush_work); setup_timer(&local->sta_cleanup, sta_info_cleanup, (unsigned long)local); @@ -741,7 +710,6 @@ int sta_info_start(struct ieee80211_local *local) void sta_info_stop(struct ieee80211_local *local) { del_timer(&local->sta_cleanup); - cancel_work_sync(&local->sta_flush_work); #ifdef CONFIG_MAC80211_DEBUGFS /* * Make sure the debugfs adding work isn't pending after this @@ -752,10 +720,7 @@ void sta_info_stop(struct ieee80211_local *local) cancel_work_sync(&local->sta_debugfs_add); #endif - rtnl_lock(); sta_info_flush(local, NULL); - __ieee80211_run_pending_flush(local); - rtnl_unlock(); } /** @@ -767,7 +732,7 @@ void sta_info_stop(struct ieee80211_local *local) * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs */ int sta_info_flush(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata) { struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); @@ -775,7 +740,6 @@ int sta_info_flush(struct ieee80211_local *local, unsigned long flags; might_sleep(); - ASSERT_RTNL(); spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { @@ -795,39 +759,6 @@ int sta_info_flush(struct ieee80211_local *local, return ret; } -/** - * sta_info_flush_delayed - flush matching STA entries from the STA table - * - * This function unlinks all stations for a given interface and queues - * them for freeing. Note that the workqueue function scheduled here has - * to run before any new keys can be added to the system to avoid set_key() - * callback ordering issues. - * - * @sdata: the interface - */ -void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - struct sta_info *sta, *tmp; - unsigned long flags; - bool work = false; - - spin_lock_irqsave(&local->sta_lock, flags); - list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - if (sdata == sta->sdata) { - __sta_info_unlink(&sta); - if (sta) { - list_add_tail(&sta->list, - &local->sta_flush_list); - work = true; - } - } - } - if (work) - schedule_work(&local->sta_flush_work); - spin_unlock_irqrestore(&local->sta_lock, flags); -} - void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5534d48..31a8990 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -442,8 +442,7 @@ void sta_info_init(struct ieee80211_local *local); int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); int sta_info_flush(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata); -void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata); + struct ieee80211_sub_if_data *sdata); void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f336cc7..c53d77d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2102,18 +2102,18 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_hdr *hdr; + struct sk_buff *presp = rcu_dereference(ifibss->presp); - if (!ifibss->probe_resp) + if (!presp) goto out; - skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC); + skb = skb_copy(presp, GFP_ATOMIC); if (!skb) goto out; hdr = (struct ieee80211_hdr *) skb->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { struct ieee80211_mgmt *mgmt; u8 *pos; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 896704c..eb63fc1 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -149,17 +149,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL; + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); else if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { if (freq->m < 0) { - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - sdata->u.ibss.flags |= - IEEE80211_IBSS_AUTO_CHANNEL_SEL; - else if (sdata->vif.type == NL80211_IFTYPE_STATION) + if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; @@ -183,6 +180,10 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, struct iw_freq *freq, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); freq->m = local->hw.conf.channel->center_freq; freq->e = 6; @@ -195,15 +196,17 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); size_t len = data->length; int ret; + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + /* iwconfig uses nul termination in SSID.. */ if (len > 0 && ssid[len - 1] == '\0') len--; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (data->flags) sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; @@ -217,8 +220,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; ieee80211_sta_req_auth(sdata); return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return ieee80211_ibss_set_ssid(sdata, ssid, len); + } return -EOPNOTSUPP; } @@ -229,9 +231,13 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, struct iw_point *data, char *ssid) { size_t len; - struct ieee80211_sub_if_data *sdata; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + if (sdata->vif.type == NL80211_IFTYPE_STATION) { int res = ieee80211_sta_get_ssid(sdata, ssid, &len); if (res == 0) { @@ -240,14 +246,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, } else data->flags = 0; return res; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - int res = ieee80211_ibss_get_ssid(sdata, ssid, &len); - if (res == 0) { - data->length = len; - data->flags = 1; - } else - data->flags = 0; - return res; } return -EOPNOTSUPP; @@ -258,9 +256,11 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION) { int ret; @@ -277,16 +277,6 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; ieee80211_sta_req_auth(sdata); return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | - IEEE80211_IBSS_AUTO_CHANNEL_SEL; - else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL; - else - sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL; - - return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data); } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { /* * If it is necessary to update the WDS peer address @@ -312,9 +302,11 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { ap_addr->sa_family = ARPHRD_ETHER; @@ -322,13 +314,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, } else memset(&ap_addr->sa_data, 0, ETH_ALEN); return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN); - } else - memset(&ap_addr->sa_data, 0, ETH_ALEN); - return 0; } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); -- cgit v0.10.2 From d323655372590c533c275b1d798f9d1221efb5c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 14:31:42 +0200 Subject: cfg80211: clean up includes Trying to separate header files into net/wireless.h and net/cfg80211.h has been a source of confusion. Remove net/wireless.h (because there also is the linux/wireless.h) and subsume everything into net/cfg80211.h -- except the definitions for regulatory structures which get moved to a new header net/regulatory.h. The "new" net/cfg80211.h is now divided into sections. There are no real changes in this patch but code shuffling and some very minor documentation fixes. I have also, to make things reflect reality, put in a copyright line for Luis to net/regulatory.h since that is probably exclusively written by him but was formerly in a file that only had my copyright line. Signed-off-by: Johannes Berg Cc: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index f797495..2522a19 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -40,7 +40,7 @@ #include #include -#include +#include #include #ifdef CONFIG_AR9170_LEDS #include diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index f585292..ac42586 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include "eeprom.h" diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 9a7715d..7c59dc4 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -17,7 +17,7 @@ #ifndef EEPROM_H #define EEPROM_H -#include +#include #define AH_USE_EEPROM 0x1 diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 526c7f1..fdf07c8 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "regd.h" #include "regd_common.h" diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index eba7c71..07291cc 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -20,7 +20,6 @@ #include #include -#include #define NO_CTL 0xff #define SD_NO_CTL 0xE0 diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 239e6a1..43e0ba6 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5287a3e..601eac6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1,70 +1,217 @@ #ifndef __NET_CFG80211_H #define __NET_CFG80211_H +/* + * 802.11 device and configuration interface + * + * Copyright 2006-2009 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include #include #include #include #include #include -#include -#include -#include +#include + /* remove once we remove the wext stuff */ +#include +#include + /* - * 802.11 configuration in-kernel interface + * wireless hardware capability structures + */ + +/** + * enum ieee80211_band - supported frequency bands + * + * The bands are assigned this way because the supported + * bitrates differ in these bands. * - * Copyright 2006, 2007 Johannes Berg + * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band + * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) */ +enum ieee80211_band { + IEEE80211_BAND_2GHZ, + IEEE80211_BAND_5GHZ, + + /* keep last */ + IEEE80211_NUM_BANDS +}; /** - * struct vif_params - describes virtual interface parameters - * @mesh_id: mesh ID to use - * @mesh_id_len: length of the mesh ID + * enum ieee80211_channel_flags - channel flags + * + * Channel flags set by the regulatory control code. + * + * @IEEE80211_CHAN_DISABLED: This channel is disabled. + * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted + * on this channel. + * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. + * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. + * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel + * is not permitted. + * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel + * is not permitted. */ -struct vif_params { - u8 *mesh_id; - int mesh_id_len; +enum ieee80211_channel_flags { + IEEE80211_CHAN_DISABLED = 1<<0, + IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, + IEEE80211_CHAN_NO_IBSS = 1<<2, + IEEE80211_CHAN_RADAR = 1<<3, + IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4, + IEEE80211_CHAN_NO_FAT_BELOW = 1<<5, }; -/* Radiotap header iteration - * implemented in net/wireless/radiotap.c - * docs in Documentation/networking/radiotap-headers.txt +/** + * struct ieee80211_channel - channel definition + * + * This structure describes a single channel for use + * with cfg80211. + * + * @center_freq: center frequency in MHz + * @max_bandwidth: maximum allowed bandwidth for this channel, in MHz + * @hw_value: hardware-specific value for the channel + * @flags: channel flags from &enum ieee80211_channel_flags. + * @orig_flags: channel flags at registration time, used by regulatory + * code to support devices with additional restrictions + * @band: band this channel belongs to. + * @max_antenna_gain: maximum antenna gain in dBi + * @max_power: maximum transmission power (in dBm) + * @beacon_found: helper to regulatory code to indicate when a beacon + * has been found on this channel. Use regulatory_hint_found_beacon() + * to enable this, this is is useful only on 5 GHz band. + * @orig_mag: internal use + * @orig_mpwr: internal use */ +struct ieee80211_channel { + enum ieee80211_band band; + u16 center_freq; + u8 max_bandwidth; + u16 hw_value; + u32 flags; + int max_antenna_gain; + int max_power; + bool beacon_found; + u32 orig_flags; + int orig_mag, orig_mpwr; +}; + /** - * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args - * @rtheader: pointer to the radiotap header we are walking through - * @max_length: length of radiotap header in cpu byte ordering - * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg - * @this_arg: pointer to current radiotap arg - * @arg_index: internal next argument index - * @arg: internal next argument pointer - * @next_bitmap: internal pointer to next present u32 - * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present + * enum ieee80211_rate_flags - rate flags + * + * Hardware/specification flags for rates. These are structured + * in a way that allows using the same bitrate structure for + * different bands/PHY modes. + * + * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short + * preamble on this bitrate; only relevant in 2.4GHz band and + * with CCK rates. + * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate + * when used with 802.11a (on the 5 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate + * when used with 802.11b (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate + * when used with 802.11g (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. */ +enum ieee80211_rate_flags { + IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, + IEEE80211_RATE_MANDATORY_A = 1<<1, + IEEE80211_RATE_MANDATORY_B = 1<<2, + IEEE80211_RATE_MANDATORY_G = 1<<3, + IEEE80211_RATE_ERP_G = 1<<4, +}; -struct ieee80211_radiotap_iterator { - struct ieee80211_radiotap_header *rtheader; - int max_length; - int this_arg_index; - u8 *this_arg; +/** + * struct ieee80211_rate - bitrate definition + * + * This structure describes a bitrate that an 802.11 PHY can + * operate with. The two values @hw_value and @hw_value_short + * are only for driver use when pointers to this structure are + * passed around. + * + * @flags: rate-specific flags + * @bitrate: bitrate in units of 100 Kbps + * @hw_value: driver/hardware value for this rate + * @hw_value_short: driver/hardware value for this rate when + * short preamble is used + */ +struct ieee80211_rate { + u32 flags; + u16 bitrate; + u16 hw_value, hw_value_short; +}; - int arg_index; - u8 *arg; - __le32 *next_bitmap; - u32 bitmap_shifter; +/** + * struct ieee80211_sta_ht_cap - STA's HT capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11n HT capabilities for an STA. + * + * @ht_supported: is HT supported by the STA + * @cap: HT capabilities map as described in 802.11n spec + * @ampdu_factor: Maximum A-MPDU length factor + * @ampdu_density: Minimum A-MPDU spacing + * @mcs: Supported MCS rates + */ +struct ieee80211_sta_ht_cap { + u16 cap; /* use IEEE80211_HT_CAP_ */ + bool ht_supported; + u8 ampdu_factor; + u8 ampdu_density; + struct ieee80211_mcs_info mcs; }; -extern int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length); +/** + * struct ieee80211_supported_band - frequency band definition + * + * This structure describes a frequency band a wiphy + * is able to operate in. + * + * @channels: Array of channels the hardware can operate in + * in this band. + * @band: the band this structure represents + * @n_channels: Number of channels in @channels + * @bitrates: Array of bitrates the hardware can operate with + * in this band. Must be sorted to give a valid "supported + * rates" IE, i.e. CCK rates first, then OFDM. + * @n_bitrates: Number of bitrates in @bitrates + */ +struct ieee80211_supported_band { + struct ieee80211_channel *channels; + struct ieee80211_rate *bitrates; + enum ieee80211_band band; + int n_channels; + int n_bitrates; + struct ieee80211_sta_ht_cap ht_cap; +}; -extern int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator); +/* + * Wireless hardware/device configuration structures and methods + */ +/** + * struct vif_params - describes virtual interface parameters + * @mesh_id: mesh ID to use + * @mesh_id_len: length of the mesh ID + */ +struct vif_params { + u8 *mesh_id; + int mesh_id_len; +}; - /** +/** * struct key_params - key information * * Information about a key @@ -347,92 +494,6 @@ struct bss_parameters { u8 basic_rates_len; }; -/** - * enum environment_cap - Environment parsed from country IE - * @ENVIRON_ANY: indicates country IE applies to both indoor and - * outdoor operation. - * @ENVIRON_INDOOR: indicates country IE applies only to indoor operation - * @ENVIRON_OUTDOOR: indicates country IE applies only to outdoor operation - */ -enum environment_cap { - ENVIRON_ANY, - ENVIRON_INDOOR, - ENVIRON_OUTDOOR, -}; - -/** - * struct regulatory_request - used to keep track of regulatory requests - * - * @wiphy_idx: this is set if this request's initiator is - * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This - * can be used by the wireless core to deal with conflicts - * and potentially inform users of which devices specifically - * cased the conflicts. - * @initiator: indicates who sent this request, could be any of - * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) - * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested - * regulatory domain. We have a few special codes: - * 00 - World regulatory domain - * 99 - built by driver but a specific alpha2 cannot be determined - * 98 - result of an intersection between two regulatory domains - * @intersect: indicates whether the wireless core should intersect - * the requested regulatory domain with the presently set regulatory - * domain. - * @country_ie_checksum: checksum of the last processed and accepted - * country IE - * @country_ie_env: lets us know if the AP is telling us we are outdoor, - * indoor, or if it doesn't matter - * @list: used to insert into the reg_requests_list linked list - */ -struct regulatory_request { - int wiphy_idx; - enum nl80211_reg_initiator initiator; - char alpha2[2]; - bool intersect; - u32 country_ie_checksum; - enum environment_cap country_ie_env; - struct list_head list; -}; - -struct ieee80211_freq_range { - u32 start_freq_khz; - u32 end_freq_khz; - u32 max_bandwidth_khz; -}; - -struct ieee80211_power_rule { - u32 max_antenna_gain; - u32 max_eirp; -}; - -struct ieee80211_reg_rule { - struct ieee80211_freq_range freq_range; - struct ieee80211_power_rule power_rule; - u32 flags; -}; - -struct ieee80211_regdomain { - u32 n_reg_rules; - char alpha2[2]; - struct ieee80211_reg_rule reg_rules[]; -}; - -#define MHZ_TO_KHZ(freq) ((freq) * 1000) -#define KHZ_TO_MHZ(freq) ((freq) / 1000) -#define DBI_TO_MBI(gain) ((gain) * 100) -#define MBI_TO_DBI(gain) ((gain) / 100) -#define DBM_TO_MBM(gain) ((gain) * 100) -#define MBM_TO_DBM(gain) ((gain) / 100) - -#define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \ - .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ - .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ - .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ - .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \ - .power_rule.max_eirp = DBM_TO_MBM(eirp), \ - .flags = reg_flags, \ - } - struct mesh_config { /* Timeouts in ms */ /* Mesh plink management parameters */ @@ -853,7 +914,396 @@ struct cfg80211_ops { int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); }; -/* temporary wext handlers */ +/* + * wireless hardware and networking interfaces structures + * and registration/helper functions + */ + +/** + * struct wiphy - wireless hardware description + * @idx: the wiphy index assigned to this item + * @class_dev: the class device representing /sys/class/ieee80211/ + * @custom_regulatory: tells us the driver for this device + * has its own custom regulatory domain and cannot identify the + * ISO / IEC 3166 alpha2 it belongs to. When this is enabled + * we will disregard the first regulatory hint (when the + * initiator is %REGDOM_SET_BY_CORE). + * @strict_regulatory: tells us the driver for this device will ignore + * regulatory domain settings until it gets its own regulatory domain + * via its regulatory_hint(). After its gets its own regulatory domain + * it will only allow further regulatory domain settings to further + * enhance compliance. For example if channel 13 and 14 are disabled + * by this regulatory domain no user regulatory domain can enable these + * channels at a later time. This can be used for devices which do not + * have calibration information gauranteed for frequencies or settings + * outside of its regulatory domain. + * @reg_notifier: the driver's regulatory notification callback + * @regd: the driver's regulatory domain, if one was requested via + * the regulatory_hint() API. This can be used by the driver + * on the reg_notifier() if it chooses to ignore future + * regulatory domain changes caused by other drivers. + * @signal_type: signal type reported in &struct cfg80211_bss. + * @cipher_suites: supported cipher suites + * @n_cipher_suites: number of supported cipher suites + */ +struct wiphy { + /* assign these fields before you register the wiphy */ + + /* permanent MAC address */ + u8 perm_addr[ETH_ALEN]; + + /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ + u16 interface_modes; + + bool custom_regulatory; + bool strict_regulatory; + + enum cfg80211_signal_type signal_type; + + int bss_priv_size; + u8 max_scan_ssids; + u16 max_scan_ie_len; + + int n_cipher_suites; + const u32 *cipher_suites; + + /* If multiple wiphys are registered and you're handed e.g. + * a regular netdev with assigned ieee80211_ptr, you won't + * know whether it points to a wiphy your driver has registered + * or not. Assign this to something global to your driver to + * help determine whether you own this wiphy or not. */ + void *privid; + + struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; + + /* Lets us get back the wiphy on the callback */ + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request); + + /* fields below are read-only, assigned by cfg80211 */ + + const struct ieee80211_regdomain *regd; + + /* the item in /sys/class/ieee80211/ points to this, + * you need use set_wiphy_dev() (see below) */ + struct device dev; + + /* dir in debugfs: ieee80211/ */ + struct dentry *debugfsdir; + + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +/** + * wiphy_priv - return priv from wiphy + * + * @wiphy: the wiphy whose priv pointer to return + */ +static inline void *wiphy_priv(struct wiphy *wiphy) +{ + BUG_ON(!wiphy); + return &wiphy->priv; +} + +/** + * set_wiphy_dev - set device pointer for wiphy + * + * @wiphy: The wiphy whose device to bind + * @dev: The device to parent it to + */ +static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev) +{ + wiphy->dev.parent = dev; +} + +/** + * wiphy_dev - get wiphy dev pointer + * + * @wiphy: The wiphy whose device struct to look up + */ +static inline struct device *wiphy_dev(struct wiphy *wiphy) +{ + return wiphy->dev.parent; +} + +/** + * wiphy_name - get wiphy name + * + * @wiphy: The wiphy whose name to return + */ +static inline const char *wiphy_name(struct wiphy *wiphy) +{ + return dev_name(&wiphy->dev); +} + +/** + * wiphy_new - create a new wiphy for use with cfg80211 + * + * @ops: The configuration operations for this device + * @sizeof_priv: The size of the private area to allocate + * + * Create a new wiphy and associate the given operations with it. + * @sizeof_priv bytes are allocated for private use. + * + * The returned pointer must be assigned to each netdev's + * ieee80211_ptr for proper operation. + */ +struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv); + +/** + * wiphy_register - register a wiphy with cfg80211 + * + * @wiphy: The wiphy to register. + * + * Returns a non-negative wiphy index or a negative error code. + */ +extern int wiphy_register(struct wiphy *wiphy); + +/** + * wiphy_unregister - deregister a wiphy from cfg80211 + * + * @wiphy: The wiphy to unregister. + * + * After this call, no more requests can be made with this priv + * pointer, but the call may sleep to wait for an outstanding + * request that is being handled. + */ +extern void wiphy_unregister(struct wiphy *wiphy); + +/** + * wiphy_free - free wiphy + * + * @wiphy: The wiphy to free + */ +extern void wiphy_free(struct wiphy *wiphy); + +/** + * struct wireless_dev - wireless per-netdev state + * + * This structure must be allocated by the driver/stack + * that uses the ieee80211_ptr field in struct net_device + * (this is intentional so it can be allocated along with + * the netdev.) + * + * @wiphy: pointer to hardware description + * @iftype: interface type + * @list: (private) Used to collect the interfaces + * @netdev: (private) Used to reference back to the netdev + * @current_bss: (private) Used by the internal configuration code + * @bssid: (private) Used by the internal configuration code + * @ssid: (private) Used by the internal configuration code + * @ssid_len: (private) Used by the internal configuration code + * @wext: (private) Used by the internal wireless extensions compat code + * @wext_bssid: (private) Used by the internal wireless extensions compat code + */ +struct wireless_dev { + struct wiphy *wiphy; + enum nl80211_iftype iftype; + + /* private to the generic wireless code */ + struct list_head list; + struct net_device *netdev; + + /* currently used for IBSS - might be rearranged in the future */ + struct cfg80211_bss *current_bss; + u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + +#ifdef CONFIG_WIRELESS_EXT + /* wext data */ + struct cfg80211_ibss_params wext; + u8 wext_bssid[ETH_ALEN]; +#endif +}; + +/** + * wdev_priv - return wiphy priv from wireless_dev + * + * @wdev: The wireless device whose wiphy's priv pointer to return + */ +static inline void *wdev_priv(struct wireless_dev *wdev) +{ + BUG_ON(!wdev); + return wiphy_priv(wdev->wiphy); +} + +/* + * Utility functions + */ + +/** + * ieee80211_channel_to_frequency - convert channel number to frequency + */ +extern int ieee80211_channel_to_frequency(int chan); + +/** + * ieee80211_frequency_to_channel - convert frequency to channel number + */ +extern int ieee80211_frequency_to_channel(int freq); + +/* + * Name indirection necessary because the ieee80211 code also has + * a function named "ieee80211_get_channel", so if you include + * cfg80211's header file you get cfg80211's version, if you try + * to include both header files you'll (rightfully!) get a symbol + * clash. + */ +extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, + int freq); +/** + * ieee80211_get_channel - get channel struct from wiphy for specified frequency + */ +static inline struct ieee80211_channel * +ieee80211_get_channel(struct wiphy *wiphy, int freq) +{ + return __ieee80211_get_channel(wiphy, freq); +} + +/** + * ieee80211_get_response_rate - get basic rate for a given rate + * + * @sband: the band to look for rates in + * @basic_rates: bitmap of basic rates + * @bitrate: the bitrate for which to find the basic rate + * + * This function returns the basic rate corresponding to a given + * bitrate, that is the next lower bitrate contained in the basic + * rate map, which is, for this function, given as a bitmap of + * indices of rates in the band's bitrate table. + */ +struct ieee80211_rate * +ieee80211_get_response_rate(struct ieee80211_supported_band *sband, + u32 basic_rates, int bitrate); + +/* + * Radiotap parsing functions -- for controlled injection support + * + * Implemented in net/wireless/radiotap.c + * Documentation in Documentation/networking/radiotap-headers.txt + */ + +/** + * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args + * @rtheader: pointer to the radiotap header we are walking through + * @max_length: length of radiotap header in cpu byte ordering + * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg + * @this_arg: pointer to current radiotap arg + * @arg_index: internal next argument index + * @arg: internal next argument pointer + * @next_bitmap: internal pointer to next present u32 + * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present + */ + +struct ieee80211_radiotap_iterator { + struct ieee80211_radiotap_header *rtheader; + int max_length; + int this_arg_index; + u8 *this_arg; + + int arg_index; + u8 *arg; + __le32 *next_bitmap; + u32 bitmap_shifter; +}; + +extern int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length); + +extern int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator); + +/* + * Regulatory helper functions for wiphys + */ + +/** + * regulatory_hint - driver hint to the wireless core a regulatory domain + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) + * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain + * should be in. If @rd is set this should be NULL. Note that if you + * set this to NULL you should still set rd->alpha2 to some accepted + * alpha2. + * + * Wireless drivers can use this function to hint to the wireless core + * what it believes should be the current regulatory domain by + * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory + * domain should be in or by providing a completely build regulatory domain. + * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried + * for a regulatory domain structure for the respective country. + * + * The wiphy must have been registered to cfg80211 prior to this call. + * For cfg80211 drivers this means you must first use wiphy_register(), + * for mac80211 drivers you must first use ieee80211_register_hw(). + * + * Drivers should check the return value, its possible you can get + * an -ENOMEM. + */ +extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2); + +/** + * regulatory_hint_11d - hints a country IE as a regulatory domain + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) + * @country_ie: pointer to the country IE + * @country_ie_len: length of the country IE + * + * We will intersect the rd with the what CRDA tells us should apply + * for the alpha2 this country IE belongs to, this prevents APs from + * sending us incorrect or outdated information against a country. + */ +extern void regulatory_hint_11d(struct wiphy *wiphy, + u8 *country_ie, + u8 country_ie_len); +/** + * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain + * @wiphy: the wireless device we want to process the regulatory domain on + * @regd: the custom regulatory domain to use for this wiphy + * + * Drivers can sometimes have custom regulatory domains which do not apply + * to a specific country. Drivers can use this to apply such custom regulatory + * domains. This routine must be called prior to wiphy registration. The + * custom regulatory domain will be trusted completely and as such previous + * default channel settings will be disregarded. If no rule is found for a + * channel on the regulatory domain the channel will be disabled. + */ +extern void wiphy_apply_custom_regulatory( + struct wiphy *wiphy, + const struct ieee80211_regdomain *regd); + +/** + * freq_reg_info - get regulatory information for the given frequency + * @wiphy: the wiphy for which we want to process this rule for + * @center_freq: Frequency in KHz for which we want regulatory information for + * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one + * you can set this to 0. If this frequency is allowed we then set + * this value to the maximum allowed bandwidth. + * @reg_rule: the regulatory rule which we have for this frequency + * + * Use this function to get the regulatory rule for a specific frequency on + * a given wireless device. If the device has a specific regulatory domain + * it wants to follow we respect that unless a country IE has been received + * and processed already. + * + * Returns 0 if it was able to find a valid regulatory rule which does + * apply to the given center_freq otherwise it returns non-zero. It will + * also return -ERANGE if we determine the given center_freq does not even have + * a regulatory rule for a frequency range in the center_freq's band. See + * freq_in_rule_band() for our current definition of a band -- this is purely + * subjective and right now its 802.11 specific. + */ +extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, + const struct ieee80211_reg_rule **reg_rule); + +/* + * Temporary wext handlers & helper functions + * + * In the future cfg80211 will simply assign the entire wext handler + * structure to netdevs it manages, but we're not there yet. + */ int cfg80211_wext_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra); @@ -892,10 +1342,14 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra); -/* wext helper for now (to be removed) */ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); +/* + * callbacks for asynchronous cfg80211 methods, notification + * functions and BSS handling helpers + */ + /** * cfg80211_scan_done - notify that scan finished * @@ -949,6 +1403,7 @@ struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, const u8 *meshid, size_t meshidlen, const u8 *meshcfg); void cfg80211_put_bss(struct cfg80211_bss *bss); + /** * cfg80211_unlink_bss - unlink BSS from internal data structures * @wiphy: the wiphy diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 52808bd..d968691 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -19,7 +19,6 @@ #include #include #include -#include #include /** diff --git a/include/net/regulatory.h b/include/net/regulatory.h new file mode 100644 index 0000000..47995b8 --- /dev/null +++ b/include/net/regulatory.h @@ -0,0 +1,101 @@ +#ifndef __NET_REGULATORY_H +#define __NET_REGULATORY_H +/* + * regulatory support structures + * + * Copyright 2008-2009 Luis R. Rodriguez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +/** + * enum environment_cap - Environment parsed from country IE + * @ENVIRON_ANY: indicates country IE applies to both indoor and + * outdoor operation. + * @ENVIRON_INDOOR: indicates country IE applies only to indoor operation + * @ENVIRON_OUTDOOR: indicates country IE applies only to outdoor operation + */ +enum environment_cap { + ENVIRON_ANY, + ENVIRON_INDOOR, + ENVIRON_OUTDOOR, +}; + +/** + * struct regulatory_request - used to keep track of regulatory requests + * + * @wiphy_idx: this is set if this request's initiator is + * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This + * can be used by the wireless core to deal with conflicts + * and potentially inform users of which devices specifically + * cased the conflicts. + * @initiator: indicates who sent this request, could be any of + * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) + * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested + * regulatory domain. We have a few special codes: + * 00 - World regulatory domain + * 99 - built by driver but a specific alpha2 cannot be determined + * 98 - result of an intersection between two regulatory domains + * @intersect: indicates whether the wireless core should intersect + * the requested regulatory domain with the presently set regulatory + * domain. + * @country_ie_checksum: checksum of the last processed and accepted + * country IE + * @country_ie_env: lets us know if the AP is telling us we are outdoor, + * indoor, or if it doesn't matter + * @list: used to insert into the reg_requests_list linked list + */ +struct regulatory_request { + int wiphy_idx; + enum nl80211_reg_initiator initiator; + char alpha2[2]; + bool intersect; + u32 country_ie_checksum; + enum environment_cap country_ie_env; + struct list_head list; +}; + +struct ieee80211_freq_range { + u32 start_freq_khz; + u32 end_freq_khz; + u32 max_bandwidth_khz; +}; + +struct ieee80211_power_rule { + u32 max_antenna_gain; + u32 max_eirp; +}; + +struct ieee80211_reg_rule { + struct ieee80211_freq_range freq_range; + struct ieee80211_power_rule power_rule; + u32 flags; +}; + +struct ieee80211_regdomain { + u32 n_reg_rules; + char alpha2[2]; + struct ieee80211_reg_rule reg_rules[]; +}; + +#define MHZ_TO_KHZ(freq) ((freq) * 1000) +#define KHZ_TO_MHZ(freq) ((freq) / 1000) +#define DBI_TO_MBI(gain) ((gain) * 100) +#define MBI_TO_DBI(gain) ((gain) / 100) +#define DBM_TO_MBM(gain) ((gain) * 100) +#define MBM_TO_DBM(gain) ((gain) / 100) + +#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ +{ \ + .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ + .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ + .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ + .power_rule.max_antenna_gain = DBI_TO_MBI(gain),\ + .power_rule.max_eirp = DBM_TO_MBM(eirp), \ + .flags = reg_flags, \ +} + +#endif diff --git a/include/net/wireless.h b/include/net/wireless.h deleted file mode 100644 index abd27b0..0000000 --- a/include/net/wireless.h +++ /dev/null @@ -1,492 +0,0 @@ -#ifndef __NET_WIRELESS_H -#define __NET_WIRELESS_H - -/* - * 802.11 device management - * - * Copyright 2007 Johannes Berg - */ - -#include -#include -#include -#include -#include - -/** - * enum ieee80211_band - supported frequency bands - * - * The bands are assigned this way because the supported - * bitrates differ in these bands. - * - * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band - * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) - */ -enum ieee80211_band { - IEEE80211_BAND_2GHZ, - IEEE80211_BAND_5GHZ, - - /* keep last */ - IEEE80211_NUM_BANDS -}; - -/** - * enum ieee80211_channel_flags - channel flags - * - * Channel flags set by the regulatory control code. - * - * @IEEE80211_CHAN_DISABLED: This channel is disabled. - * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted - * on this channel. - * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. - * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. - * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel - * is not permitted. - * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel - * is not permitted. - */ -enum ieee80211_channel_flags { - IEEE80211_CHAN_DISABLED = 1<<0, - IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, - IEEE80211_CHAN_NO_IBSS = 1<<2, - IEEE80211_CHAN_RADAR = 1<<3, - IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4, - IEEE80211_CHAN_NO_FAT_BELOW = 1<<5, -}; - -/** - * struct ieee80211_channel - channel definition - * - * This structure describes a single channel for use - * with cfg80211. - * - * @center_freq: center frequency in MHz - * @max_bandwidth: maximum allowed bandwidth for this channel, in MHz - * @hw_value: hardware-specific value for the channel - * @flags: channel flags from &enum ieee80211_channel_flags. - * @orig_flags: channel flags at registration time, used by regulatory - * code to support devices with additional restrictions - * @band: band this channel belongs to. - * @max_antenna_gain: maximum antenna gain in dBi - * @max_power: maximum transmission power (in dBm) - * @beacon_found: helper to regulatory code to indicate when a beacon - * has been found on this channel. Use regulatory_hint_found_beacon() - * to enable this, this is is useful only on 5 GHz band. - * @orig_mag: internal use - * @orig_mpwr: internal use - */ -struct ieee80211_channel { - enum ieee80211_band band; - u16 center_freq; - u8 max_bandwidth; - u16 hw_value; - u32 flags; - int max_antenna_gain; - int max_power; - bool beacon_found; - u32 orig_flags; - int orig_mag, orig_mpwr; -}; - -/** - * enum ieee80211_rate_flags - rate flags - * - * Hardware/specification flags for rates. These are structured - * in a way that allows using the same bitrate structure for - * different bands/PHY modes. - * - * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short - * preamble on this bitrate; only relevant in 2.4GHz band and - * with CCK rates. - * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate - * when used with 802.11a (on the 5 GHz band); filled by the - * core code when registering the wiphy. - * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate - * when used with 802.11b (on the 2.4 GHz band); filled by the - * core code when registering the wiphy. - * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate - * when used with 802.11g (on the 2.4 GHz band); filled by the - * core code when registering the wiphy. - * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. - */ -enum ieee80211_rate_flags { - IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, - IEEE80211_RATE_MANDATORY_A = 1<<1, - IEEE80211_RATE_MANDATORY_B = 1<<2, - IEEE80211_RATE_MANDATORY_G = 1<<3, - IEEE80211_RATE_ERP_G = 1<<4, -}; - -/** - * struct ieee80211_rate - bitrate definition - * - * This structure describes a bitrate that an 802.11 PHY can - * operate with. The two values @hw_value and @hw_value_short - * are only for driver use when pointers to this structure are - * passed around. - * - * @flags: rate-specific flags - * @bitrate: bitrate in units of 100 Kbps - * @hw_value: driver/hardware value for this rate - * @hw_value_short: driver/hardware value for this rate when - * short preamble is used - */ -struct ieee80211_rate { - u32 flags; - u16 bitrate; - u16 hw_value, hw_value_short; -}; - -/** - * struct ieee80211_sta_ht_cap - STA's HT capabilities - * - * This structure describes most essential parameters needed - * to describe 802.11n HT capabilities for an STA. - * - * @ht_supported: is HT supported by the STA - * @cap: HT capabilities map as described in 802.11n spec - * @ampdu_factor: Maximum A-MPDU length factor - * @ampdu_density: Minimum A-MPDU spacing - * @mcs: Supported MCS rates - */ -struct ieee80211_sta_ht_cap { - u16 cap; /* use IEEE80211_HT_CAP_ */ - bool ht_supported; - u8 ampdu_factor; - u8 ampdu_density; - struct ieee80211_mcs_info mcs; -}; - -/** - * struct ieee80211_supported_band - frequency band definition - * - * This structure describes a frequency band a wiphy - * is able to operate in. - * - * @channels: Array of channels the hardware can operate in - * in this band. - * @band: the band this structure represents - * @n_channels: Number of channels in @channels - * @bitrates: Array of bitrates the hardware can operate with - * in this band. Must be sorted to give a valid "supported - * rates" IE, i.e. CCK rates first, then OFDM. - * @n_bitrates: Number of bitrates in @bitrates - */ -struct ieee80211_supported_band { - struct ieee80211_channel *channels; - struct ieee80211_rate *bitrates; - enum ieee80211_band band; - int n_channels; - int n_bitrates; - struct ieee80211_sta_ht_cap ht_cap; -}; - -/** - * struct wiphy - wireless hardware description - * @idx: the wiphy index assigned to this item - * @class_dev: the class device representing /sys/class/ieee80211/ - * @custom_regulatory: tells us the driver for this device - * has its own custom regulatory domain and cannot identify the - * ISO / IEC 3166 alpha2 it belongs to. When this is enabled - * we will disregard the first regulatory hint (when the - * initiator is %REGDOM_SET_BY_CORE). - * @strict_regulatory: tells us the driver for this device will ignore - * regulatory domain settings until it gets its own regulatory domain - * via its regulatory_hint(). After its gets its own regulatory domain - * it will only allow further regulatory domain settings to further - * enhance compliance. For example if channel 13 and 14 are disabled - * by this regulatory domain no user regulatory domain can enable these - * channels at a later time. This can be used for devices which do not - * have calibration information gauranteed for frequencies or settings - * outside of its regulatory domain. - * @reg_notifier: the driver's regulatory notification callback - * @regd: the driver's regulatory domain, if one was requested via - * the regulatory_hint() API. This can be used by the driver - * on the reg_notifier() if it chooses to ignore future - * regulatory domain changes caused by other drivers. - * @signal_type: signal type reported in &struct cfg80211_bss. - * @cipher_suites: supported cipher suites - * @n_cipher_suites: number of supported cipher suites - */ -struct wiphy { - /* assign these fields before you register the wiphy */ - - /* permanent MAC address */ - u8 perm_addr[ETH_ALEN]; - - /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ - u16 interface_modes; - - bool custom_regulatory; - bool strict_regulatory; - - enum cfg80211_signal_type signal_type; - - int bss_priv_size; - u8 max_scan_ssids; - u16 max_scan_ie_len; - - int n_cipher_suites; - const u32 *cipher_suites; - - /* If multiple wiphys are registered and you're handed e.g. - * a regular netdev with assigned ieee80211_ptr, you won't - * know whether it points to a wiphy your driver has registered - * or not. Assign this to something global to your driver to - * help determine whether you own this wiphy or not. */ - void *privid; - - struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; - - /* Lets us get back the wiphy on the callback */ - int (*reg_notifier)(struct wiphy *wiphy, - struct regulatory_request *request); - - /* fields below are read-only, assigned by cfg80211 */ - - const struct ieee80211_regdomain *regd; - - /* the item in /sys/class/ieee80211/ points to this, - * you need use set_wiphy_dev() (see below) */ - struct device dev; - - /* dir in debugfs: ieee80211/ */ - struct dentry *debugfsdir; - - char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); -}; - -/** struct wireless_dev - wireless per-netdev state - * - * This structure must be allocated by the driver/stack - * that uses the ieee80211_ptr field in struct net_device - * (this is intentional so it can be allocated along with - * the netdev.) - * - * @wiphy: pointer to hardware description - * @iftype: interface type - * @list: (private) - * @netdev (private) - */ -struct wireless_dev { - struct wiphy *wiphy; - enum nl80211_iftype iftype; - - /* private to the generic wireless code */ - struct list_head list; - struct net_device *netdev; - - /* currently used for IBSS - might be rearranged in the future */ - struct cfg80211_bss *current_bss; - u8 bssid[ETH_ALEN]; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - -#ifdef CONFIG_WIRELESS_EXT - /* wext data */ - struct cfg80211_ibss_params wext; - u8 wext_bssid[ETH_ALEN]; -#endif -}; - -/** - * wiphy_priv - return priv from wiphy - */ -static inline void *wiphy_priv(struct wiphy *wiphy) -{ - BUG_ON(!wiphy); - return &wiphy->priv; -} - -/** - * set_wiphy_dev - set device pointer for wiphy - */ -static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev) -{ - wiphy->dev.parent = dev; -} - -/** - * wiphy_dev - get wiphy dev pointer - */ -static inline struct device *wiphy_dev(struct wiphy *wiphy) -{ - return wiphy->dev.parent; -} - -/** - * wiphy_name - get wiphy name - */ -static inline const char *wiphy_name(struct wiphy *wiphy) -{ - return dev_name(&wiphy->dev); -} - -/** - * wdev_priv - return wiphy priv from wireless_dev - */ -static inline void *wdev_priv(struct wireless_dev *wdev) -{ - BUG_ON(!wdev); - return wiphy_priv(wdev->wiphy); -} - -/** - * wiphy_new - create a new wiphy for use with cfg80211 - * - * create a new wiphy and associate the given operations with it. - * @sizeof_priv bytes are allocated for private use. - * - * the returned pointer must be assigned to each netdev's - * ieee80211_ptr for proper operation. - */ -struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv); - -/** - * wiphy_register - register a wiphy with cfg80211 - * - * register the given wiphy - * - * Returns a non-negative wiphy index or a negative error code. - */ -extern int wiphy_register(struct wiphy *wiphy); - -/** - * wiphy_unregister - deregister a wiphy from cfg80211 - * - * unregister a device with the given priv pointer. - * After this call, no more requests can be made with this priv - * pointer, but the call may sleep to wait for an outstanding - * request that is being handled. - */ -extern void wiphy_unregister(struct wiphy *wiphy); - -/** - * wiphy_free - free wiphy - */ -extern void wiphy_free(struct wiphy *wiphy); - -/** - * ieee80211_channel_to_frequency - convert channel number to frequency - */ -extern int ieee80211_channel_to_frequency(int chan); - -/** - * ieee80211_frequency_to_channel - convert frequency to channel number - */ -extern int ieee80211_frequency_to_channel(int freq); - -/* - * Name indirection necessary because the ieee80211 code also has - * a function named "ieee80211_get_channel", so if you include - * cfg80211's header file you get cfg80211's version, if you try - * to include both header files you'll (rightfully!) get a symbol - * clash. - */ -extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, - int freq); -/** - * ieee80211_get_channel - get channel struct from wiphy for specified frequency - */ -static inline struct ieee80211_channel * -ieee80211_get_channel(struct wiphy *wiphy, int freq) -{ - return __ieee80211_get_channel(wiphy, freq); -} - -/** - * ieee80211_get_response_rate - get basic rate for a given rate - * - * @sband: the band to look for rates in - * @basic_rates: bitmap of basic rates - * @bitrate: the bitrate for which to find the basic rate - * - * This function returns the basic rate corresponding to a given - * bitrate, that is the next lower bitrate contained in the basic - * rate map, which is, for this function, given as a bitmap of - * indices of rates in the band's bitrate table. - */ -struct ieee80211_rate * -ieee80211_get_response_rate(struct ieee80211_supported_band *sband, - u32 basic_rates, int bitrate); - -/** - * regulatory_hint - driver hint to the wireless core a regulatory domain - * @wiphy: the wireless device giving the hint (used only for reporting - * conflicts) - * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain - * should be in. If @rd is set this should be NULL. Note that if you - * set this to NULL you should still set rd->alpha2 to some accepted - * alpha2. - * - * Wireless drivers can use this function to hint to the wireless core - * what it believes should be the current regulatory domain by - * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory - * domain should be in or by providing a completely build regulatory domain. - * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried - * for a regulatory domain structure for the respective country. - * - * The wiphy must have been registered to cfg80211 prior to this call. - * For cfg80211 drivers this means you must first use wiphy_register(), - * for mac80211 drivers you must first use ieee80211_register_hw(). - * - * Drivers should check the return value, its possible you can get - * an -ENOMEM. - */ -extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2); - -/** - * regulatory_hint_11d - hints a country IE as a regulatory domain - * @wiphy: the wireless device giving the hint (used only for reporting - * conflicts) - * @country_ie: pointer to the country IE - * @country_ie_len: length of the country IE - * - * We will intersect the rd with the what CRDA tells us should apply - * for the alpha2 this country IE belongs to, this prevents APs from - * sending us incorrect or outdated information against a country. - */ -extern void regulatory_hint_11d(struct wiphy *wiphy, - u8 *country_ie, - u8 country_ie_len); -/** - * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain - * @wiphy: the wireless device we want to process the regulatory domain on - * @regd: the custom regulatory domain to use for this wiphy - * - * Drivers can sometimes have custom regulatory domains which do not apply - * to a specific country. Drivers can use this to apply such custom regulatory - * domains. This routine must be called prior to wiphy registration. The - * custom regulatory domain will be trusted completely and as such previous - * default channel settings will be disregarded. If no rule is found for a - * channel on the regulatory domain the channel will be disabled. - */ -extern void wiphy_apply_custom_regulatory( - struct wiphy *wiphy, - const struct ieee80211_regdomain *regd); - -/** - * freq_reg_info - get regulatory information for the given frequency - * @wiphy: the wiphy for which we want to process this rule for - * @center_freq: Frequency in KHz for which we want regulatory information for - * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one - * you can set this to 0. If this frequency is allowed we then set - * this value to the maximum allowed bandwidth. - * @reg_rule: the regulatory rule which we have for this frequency - * - * Use this function to get the regulatory rule for a specific frequency on - * a given wireless device. If the device has a specific regulatory domain - * it wants to follow we respect that unless a country IE has been received - * and processed already. - * - * Returns 0 if it was able to find a valid regulatory rule which does - * apply to the given center_freq otherwise it returns non-zero. It will - * also return -ERANGE if we determine the given center_freq does not even have - * a regulatory rule for a frequency range in the center_freq's band. See - * freq_in_rule_band() for our current definition of a band -- this is purely - * subjective and right now its 802.11 specific. - */ -extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, - const struct ieee80211_reg_rule **reg_rule); - -#endif /* __NET_WIRELESS_H */ diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 73bd4277..0891bfb 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -14,7 +14,6 @@ */ #include -#include #include #include "ieee80211_i.h" #include "rate.h" diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e770c1e8..92a573b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include "key.h" diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 5f7a262..48bf78e 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -15,7 +15,7 @@ */ #include -#include +#include #include #include "ieee80211_i.h" #include "sta_info.h" diff --git a/net/wireless/core.c b/net/wireless/core.c index de1ac51..827a562 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "nl80211.h" #include "core.h" #include "sysfs.h" diff --git a/net/wireless/core.h b/net/wireless/core.h index 2ef3595..89a8159 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "reg.h" diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 2bf42fd..4e1fcb0 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -7,7 +7,6 @@ #include #include #include -#include #include "nl80211.h" diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 574e217..f38cc39 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include "core.h" #include "reg.h" diff --git a/net/wireless/util.c b/net/wireless/util.c index 487cdd9..5f7e997 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1,10 +1,10 @@ /* * Wireless utility functions * - * Copyright 2007 Johannes Berg + * Copyright 2007-2009 Johannes Berg */ -#include -#include +#include +#include #include "core.h" struct ieee80211_rate * diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 57eaea26..4e054ea 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include "core.h" -- cgit v0.10.2 From 314bd7503b1e96841931311f28a8925dab66ed83 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 15:17:01 +0200 Subject: rndis_wlan: remove nickname support Supporting wireless extension nickname is pointless and no other modern driver supports this, so remove it. Signed-off-by: Johannes Berg Acked-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 43e0ba6..109e603 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -372,9 +372,6 @@ struct rndis_wext_private { struct iw_statistics iwstats; struct iw_statistics privstats; - int nick_len; - char nick[32]; - int caps; int multicast_size; @@ -1798,39 +1795,6 @@ static int rndis_iw_get_frag(struct net_device *dev, } -static int rndis_iw_set_nick(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - devdbg(usbdev, "SIOCSIWNICK"); - - priv->nick_len = wrqu->data.length; - if (priv->nick_len > 32) - priv->nick_len = 32; - - memcpy(priv->nick, extra, priv->nick_len); - return 0; -} - - -static int rndis_iw_get_nick(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - wrqu->data.flags = 1; - wrqu->data.length = priv->nick_len; - memcpy(extra, priv->nick, priv->nick_len); - - devdbg(usbdev, "SIOCGIWNICK: '%s'", priv->nick); - - return 0; -} - - static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2039,8 +2003,6 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, - IW_IOCTL(SIOCSIWNICKN) = rndis_iw_set_nick, - IW_IOCTL(SIOCGIWNICKN) = rndis_iw_get_nick, IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts, IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts, -- cgit v0.10.2 From 9e52b0623c6eb49c3f23a326c1fb97bdecc49ba1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 18:27:04 +0200 Subject: ar9170: support HT receive and channel config This patch adds support for configuring HT40 channels and receiving HT40 to ar9170. Receiving aggregation doesn't seem to work right now, so it's not enabled. Same goes for TX aggregation, but that probably needs even more work. With this, I can receive roughly 33 Mbits/sec. The HT capabilities are a little odd, I tried following otus here -- in particular having SGI_40 but not SGI_20 is a little weird but afaict that's what otus does. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 2522a19..b6a1bff 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -60,6 +60,21 @@ enum ar9170_bw { __AR9170_NUM_BW, }; +static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type) +{ + switch (type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + return AR9170_BW_20; + case NL80211_CHAN_HT40MINUS: + return AR9170_BW_40_BELOW; + case NL80211_CHAN_HT40PLUS: + return AR9170_BW_40_ABOVE; + default: + BUG(); + } +} + enum ar9170_rf_init_mode { AR9170_RFI_NONE, AR9170_RFI_WARM, diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 857416c..4682fe2 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -142,11 +142,36 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { }; #undef CHAN +#define AR9170_HT_CAP \ +{ \ + .ht_supported = true, \ + .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ + IEEE80211_HT_CAP_SM_PS | \ + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ + IEEE80211_HT_CAP_SGI_40 | \ + IEEE80211_HT_CAP_DSSSCCK40 | \ + IEEE80211_HT_CAP_SM_PS, \ + .ampdu_factor = 3, /* ?? */ \ + .ampdu_density = 7, /* ?? */ \ + .mcs = { \ + .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \ + }, \ +} + static struct ieee80211_supported_band ar9170_band_2GHz = { .channels = ar9170_2ghz_chantable, .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), .bitrates = ar9170_g_ratetable, .n_bitrates = ar9170_g_ratetable_size, + .ht_cap = AR9170_HT_CAP, +}; + +static struct ieee80211_supported_band ar9170_band_5GHz = { + .channels = ar9170_5ghz_chantable, + .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), + .bitrates = ar9170_a_ratetable, + .n_bitrates = ar9170_a_ratetable_size, + .ht_cap = AR9170_HT_CAP, }; #ifdef AR9170_QUEUE_DEBUG @@ -190,13 +215,6 @@ static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, } #endif /* AR9170_QUEUE_DEBUG */ -static struct ieee80211_supported_band ar9170_band_5GHz = { - .channels = ar9170_5ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), - .bitrates = ar9170_a_ratetable, - .n_bitrates = ar9170_a_ratetable_size, -}; - void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, bool valid_status, u16 tx_status) { @@ -1077,7 +1095,8 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { err = ar9170_set_channel(ar, hw->conf.channel, - AR9170_RFI_NONE, AR9170_BW_20); + AR9170_RFI_NONE, + nl80211_to_ar9170(hw->conf.channel_type)); if (err) goto out; /* adjust slot time for 5 GHz */ @@ -1499,6 +1518,24 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, return ret; } +static int ar9170_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ + switch (action) { + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: + /* + * Something goes wrong -- RX locks up + * after a while of receiving aggregated + * frames -- not enabling for now. + */ + return -EOPNOTSUPP; + default: + return -EOPNOTSUPP; + } +} + static const struct ieee80211_ops ar9170_ops = { .start = ar9170_op_start, .stop = ar9170_op_stop, @@ -1515,6 +1552,7 @@ static const struct ieee80211_ops ar9170_ops = { .sta_notify = ar9170_sta_notify, .get_stats = ar9170_get_stats, .get_tx_stats = ar9170_get_tx_stats, + .ampdu_action = ar9170_ampdu_action, }; void *ar9170_alloc(size_t priv_size) -- cgit v0.10.2 From b9a5f8cab751d362f7c2d94899ca788c22fcd1ef Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 20 Apr 2009 18:39:05 +0200 Subject: nl80211: Add set/get for frag/rts threshold and retry limits Add new nl80211 attributes that can be used with NL80211_CMD_SET_WIPHY and NL80211_CMD_GET_WIPHY to manage fragmentation/RTS threshold and retry limits. Since these values are stored in struct wiphy, remove the local copy from mac80211 where feasible (frag & rts threshold). The retry limits are currently needed in struct ieee80211_conf, but these could be eventually removed since the driver should have access to the values in struct wiphy. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 25ce3e4..dc9d9ec 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -46,8 +46,10 @@ * to get a list of all present wiphys. * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, - * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or - * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, + * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT, + * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request * or rename notification. Has attributes %NL80211_ATTR_WIPHY and * %NL80211_ATTR_WIPHY_NAME. @@ -337,6 +339,18 @@ enum nl80211_commands { * NL80211_CHAN_HT20 = HT20 only * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel + * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is + * less than or equal to the RTS threshold; allowed range: 1..255; + * dot11ShortRetryLimit; u8 + * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is + * greater than the RTS threshold; allowed range: 1..255; + * dot11ShortLongLimit; u8 + * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum + * length in octets for frames; allowed range: 256..8000, disable + * fragmentation with (u32)-1; dot11FragmentationThreshold; u32 + * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length + * larger than or equal to this use RTS/CTS handshake); allowed range: + * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 * * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on * @NL80211_ATTR_IFNAME: network interface name @@ -565,6 +579,12 @@ enum nl80211_attrs { NL80211_ATTR_FREQ_FIXED, + + NL80211_ATTR_WIPHY_RETRY_SHORT, + NL80211_ATTR_WIPHY_RETRY_LONG, + NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + NL80211_ATTR_WIPHY_RTS_THRESHOLD, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 601eac6..54bc69c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -744,6 +744,20 @@ struct cfg80211_ibss_params { }; /** + * enum wiphy_params_flags - set_wiphy_params bitfield values + * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed + * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed + * WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed + * WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed + */ +enum wiphy_params_flags { + WIPHY_PARAM_RETRY_SHORT = 1 << 0, + WIPHY_PARAM_RETRY_LONG = 1 << 1, + WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, + WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, +}; + +/** * struct cfg80211_ops - backend description for wireless configuration * * This struct is registered by fullmac card drivers and/or wireless stacks @@ -823,6 +837,11 @@ struct cfg80211_ibss_params { * cfg80211_ibss_joined(), also call that function when changing BSSID due * to a merge. * @leave_ibss: Leave the IBSS. + * + * @set_wiphy_params: Notify that wiphy parameters have changed; + * @changed bitfield (see &enum wiphy_params_flags) describes which values + * have changed. The actual parameter values are available in + * struct wiphy. If returning an error, no value should be changed. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy); @@ -912,6 +931,8 @@ struct cfg80211_ops { int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params); int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); + + int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); }; /* @@ -945,6 +966,11 @@ struct cfg80211_ops { * @signal_type: signal type reported in &struct cfg80211_bss. * @cipher_suites: supported cipher suites * @n_cipher_suites: number of supported cipher suites + * @retry_short: Retry limit for short frames (dot11ShortRetryLimit) + * @retry_long: Retry limit for long frames (dot11LongRetryLimit) + * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); + * -1 = fragmentation disabled, only odd values >= 256 used + * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -967,6 +993,11 @@ struct wiphy { int n_cipher_suites; const u32 *cipher_suites; + u8 retry_short; + u8 retry_long; + u32 frag_threshold; + u32 rts_threshold; + /* If multiple wiphys are registered and you're handed e.g. * a regular netdev with assigned ieee80211_ptr, you won't * know whether it points to a wiphy your driver has registered @@ -1345,6 +1376,25 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); +int cfg80211_wext_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra); +int cfg80211_wext_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra); +int cfg80211_wext_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra); +int cfg80211_wext_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra); +int cfg80211_wext_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra); +int cfg80211_wext_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra); + /* * callbacks for asynchronous cfg80211 methods, notification * functions and BSS handling helpers diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 14013dc..5e1c230 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1298,6 +1298,32 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return ieee80211_ibss_leave(sdata); } +static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + int err; + + if (local->ops->set_rts_threshold) { + err = local->ops->set_rts_threshold( + local_to_hw(local), wiphy->rts_threshold); + if (err) + return err; + } + } + + if (changed & WIPHY_PARAM_RETRY_SHORT) + local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; + if (changed & WIPHY_PARAM_RETRY_LONG) + local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; + if (changed & + (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1336,4 +1362,5 @@ struct cfg80211_ops mac80211_config_ops = { .disassoc = ieee80211_disassoc, .join_ibss = ieee80211_join_ibss, .leave_ibss = ieee80211_leave_ibss, + .set_wiphy_params = ieee80211_set_wiphy_params, }; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 210b9b6..5001328 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -52,13 +52,13 @@ static const struct file_operations name## _ops = { \ DEBUGFS_READONLY_FILE(frequency, 20, "%d", local->hw.conf.channel->center_freq); DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", - local->rts_threshold); + local->hw.wiphy->rts_threshold); DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", - local->fragmentation_threshold); + local->hw.wiphy->frag_threshold); DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", - local->hw.conf.short_frame_max_tx_count); + local->hw.wiphy->retry_short); DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", - local->hw.conf.long_frame_max_tx_count); + local->hw.wiphy->retry_long); DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", local->total_ps_buffered); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 92a573b..dba78d8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -643,9 +643,6 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - int rts_threshold; - int fragmentation_threshold; - struct crypto_blkcipher *wep_tx_tfm; struct crypto_blkcipher *wep_rx_tfm; u32 wep_iv; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d26fc39..5320e08 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -776,10 +776,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, /* set up some defaults */ local->hw.queues = 1; local->hw.max_rates = 1; - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - local->hw.conf.long_frame_max_tx_count = 4; - local->hw.conf.short_frame_max_tx_count = 7; + local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; + local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; local->hw.conf.radio_enabled = true; INIT_LIST_HEAD(&local->interfaces); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c53d77d..9ab4982 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -516,7 +516,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) sband = tx->local->hw.wiphy->bands[tx->channel->band]; len = min_t(int, tx->skb->len + FCS_LEN, - tx->local->fragmentation_threshold); + tx->local->hw.wiphy->frag_threshold); /* set up the tx rate control struct we give the RC algo */ txrc.hw = local_to_hw(tx->local); @@ -527,8 +527,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; /* set up RTS protection if desired */ - if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD && - len > tx->local->rts_threshold) { + if (len > tx->local->hw.wiphy->rts_threshold) { txrc.rts = rts = true; } @@ -770,7 +769,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) struct sk_buff *skb = tx->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *)skb->data; - int frag_threshold = tx->local->fragmentation_threshold; + int frag_threshold = tx->local->hw.wiphy->frag_threshold; int hdrlen; int fragnum; @@ -1088,7 +1087,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (tx->flags & IEEE80211_TX_FRAGMENTED) { if ((tx->flags & IEEE80211_TX_UNICAST) && - skb->len + FCS_LEN > local->fragmentation_threshold && + skb->len + FCS_LEN > local->hw.wiphy->frag_threshold && !(info->flags & IEEE80211_TX_CTL_AMPDU)) tx->flags |= IEEE80211_TX_FRAGMENTED; else diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3dd490f..1124421 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1044,7 +1044,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* setup RTS threshold */ if (local->ops->set_rts_threshold) - local->ops->set_rts_threshold(hw, local->rts_threshold); + local->ops->set_rts_threshold(hw, hw->wiphy->rts_threshold); /* reconfigure hardware */ ieee80211_hw_config(local, ~0); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index eb63fc1..1eb6d86 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -472,132 +472,6 @@ static int ieee80211_ioctl_giwtxpower(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (rts->disabled) - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - else if (!rts->fixed) - /* if the rts value is not fixed, then take default */ - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) - return -EINVAL; - else - local->rts_threshold = rts->value; - - /* If the wlan card performs RTS/CTS in hardware/firmware, - * configure it here */ - - if (local->ops->set_rts_threshold) - local->ops->set_rts_threshold(local_to_hw(local), - local->rts_threshold); - - return 0; -} - -static int ieee80211_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - rts->value = local->rts_threshold; - rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); - rts->fixed = 1; - - return 0; -} - - -static int ieee80211_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (frag->disabled) - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - else if (!frag->fixed) - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - else if (frag->value < 256 || - frag->value > IEEE80211_MAX_FRAG_THRESHOLD) - return -EINVAL; - else { - /* Fragment length must be even, so strip LSB. */ - local->fragmentation_threshold = frag->value & ~0x1; - } - - return 0; -} - -static int ieee80211_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - frag->value = local->fragmentation_threshold; - frag->disabled = (frag->value >= IEEE80211_MAX_FRAG_THRESHOLD); - frag->fixed = 1; - - return 0; -} - - -static int ieee80211_ioctl_siwretry(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *retry, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (retry->disabled || - (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) - return -EINVAL; - - if (retry->flags & IW_RETRY_MAX) { - local->hw.conf.long_frame_max_tx_count = retry->value; - } else if (retry->flags & IW_RETRY_MIN) { - local->hw.conf.short_frame_max_tx_count = retry->value; - } else { - local->hw.conf.long_frame_max_tx_count = retry->value; - local->hw.conf.short_frame_max_tx_count = retry->value; - } - - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); - - return 0; -} - - -static int ieee80211_ioctl_giwretry(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *retry, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - retry->disabled = 0; - if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { - /* first return min value, iwconfig will ask max value - * later if needed */ - retry->flags |= IW_RETRY_LIMIT; - retry->value = local->hw.conf.short_frame_max_tx_count; - if (local->hw.conf.long_frame_max_tx_count != - local->hw.conf.short_frame_max_tx_count) - retry->flags |= IW_RETRY_MIN; - return 0; - } - if (retry->flags & IW_RETRY_MAX) { - retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - retry->value = local->hw.conf.long_frame_max_tx_count; - } - - return 0; -} - - static int ieee80211_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf) @@ -1050,14 +924,14 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* -- hole -- */ (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ - (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ - (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ - (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ + (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ + (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ - (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ + (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ + (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ diff --git a/net/wireless/core.c b/net/wireless/core.c index 827a562..f256b4f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -273,6 +273,16 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) drv->wiphy.dev.class = &ieee80211_class; drv->wiphy.dev.platform_data = drv; + /* + * Initialize wiphy parameters to IEEE 802.11 MIB default values. + * Fragmentation and RTS threshold are disabled by default with the + * special -1 value. + */ + drv->wiphy.retry_short = 7; + drv->wiphy.retry_long = 4; + drv->wiphy.frag_threshold = (u32) -1; + drv->wiphy.rts_threshold = (u32) -1; + return &drv->wiphy; } EXPORT_SYMBOL(wiphy_new); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 16f8635..5a9a5c6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -61,6 +61,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -204,6 +208,16 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, + dev->wiphy.retry_short); + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, + dev->wiphy.retry_long); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + dev->wiphy.frag_threshold); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, + dev->wiphy.rts_threshold); + NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, dev->wiphy.max_scan_ssids); NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, @@ -416,6 +430,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev; int result = 0, rem_txq_params = 0; struct nlattr *nl_txq_params; + u32 changed; + u8 retry_short = 0, retry_long = 0; + u32 frag_threshold = 0, rts_threshold = 0; rtnl_lock(); @@ -530,6 +547,84 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) goto bad_res; } + changed = 0; + + if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { + retry_short = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); + if (retry_short == 0) { + result = -EINVAL; + goto bad_res; + } + changed |= WIPHY_PARAM_RETRY_SHORT; + } + + if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { + retry_long = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); + if (retry_long == 0) { + result = -EINVAL; + goto bad_res; + } + changed |= WIPHY_PARAM_RETRY_LONG; + } + + if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { + frag_threshold = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); + if (frag_threshold < 256) { + result = -EINVAL; + goto bad_res; + } + if (frag_threshold != (u32) -1) { + /* + * Fragments (apart from the last one) are required to + * have even length. Make the fragmentation code + * simpler by stripping LSB should someone try to use + * odd threshold value. + */ + frag_threshold &= ~0x1; + } + changed |= WIPHY_PARAM_FRAG_THRESHOLD; + } + + if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { + rts_threshold = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); + changed |= WIPHY_PARAM_RTS_THRESHOLD; + } + + if (changed) { + u8 old_retry_short, old_retry_long; + u32 old_frag_threshold, old_rts_threshold; + + if (!rdev->ops->set_wiphy_params) { + result = -EOPNOTSUPP; + goto bad_res; + } + + old_retry_short = rdev->wiphy.retry_short; + old_retry_long = rdev->wiphy.retry_long; + old_frag_threshold = rdev->wiphy.frag_threshold; + old_rts_threshold = rdev->wiphy.rts_threshold; + + if (changed & WIPHY_PARAM_RETRY_SHORT) + rdev->wiphy.retry_short = retry_short; + if (changed & WIPHY_PARAM_RETRY_LONG) + rdev->wiphy.retry_long = retry_long; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + rdev->wiphy.frag_threshold = frag_threshold; + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + rdev->wiphy.rts_threshold = rts_threshold; + + result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); + if (result) { + rdev->wiphy.retry_short = old_retry_short; + rdev->wiphy.retry_long = old_retry_long; + rdev->wiphy.frag_threshold = old_frag_threshold; + rdev->wiphy.rts_threshold = old_rts_threshold; + } + } bad_res: mutex_unlock(&rdev->mtx); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 4e054ea..3279e7f 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -314,3 +314,154 @@ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_wext_freq); + +int cfg80211_wext_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 orts = wdev->wiphy->rts_threshold; + int err; + + if (rts->disabled || !rts->fixed) + wdev->wiphy->rts_threshold = (u32) -1; + else if (rts->value < 0) + return -EINVAL; + else + wdev->wiphy->rts_threshold = rts->value; + + err = rdev->ops->set_wiphy_params(wdev->wiphy, + WIPHY_PARAM_RTS_THRESHOLD); + if (err) + wdev->wiphy->rts_threshold = orts; + + return err; +} +EXPORT_SYMBOL(cfg80211_wext_siwrts); + +int cfg80211_wext_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + rts->value = wdev->wiphy->rts_threshold; + rts->disabled = rts->value == (u32) -1; + rts->fixed = 1; + + return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwrts); + +int cfg80211_wext_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 ofrag = wdev->wiphy->frag_threshold; + int err; + + if (frag->disabled || !frag->fixed) + wdev->wiphy->frag_threshold = (u32) -1; + else if (frag->value < 256) + return -EINVAL; + else { + /* Fragment length must be even, so strip LSB. */ + wdev->wiphy->frag_threshold = frag->value & ~0x1; + } + + err = rdev->ops->set_wiphy_params(wdev->wiphy, + WIPHY_PARAM_FRAG_THRESHOLD); + if (err) + wdev->wiphy->frag_threshold = ofrag; + + return err; +} +EXPORT_SYMBOL(cfg80211_wext_siwfrag); + +int cfg80211_wext_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + frag->value = wdev->wiphy->frag_threshold; + frag->disabled = frag->value == (u32) -1; + frag->fixed = 1; + + return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwfrag); + +int cfg80211_wext_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 changed = 0; + u8 olong = wdev->wiphy->retry_long; + u8 oshort = wdev->wiphy->retry_short; + int err; + + if (retry->disabled || + (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) + return -EINVAL; + + if (retry->flags & IW_RETRY_LONG) { + wdev->wiphy->retry_long = retry->value; + changed |= WIPHY_PARAM_RETRY_LONG; + } else if (retry->flags & IW_RETRY_SHORT) { + wdev->wiphy->retry_short = retry->value; + changed |= WIPHY_PARAM_RETRY_SHORT; + } else { + wdev->wiphy->retry_short = retry->value; + wdev->wiphy->retry_long = retry->value; + changed |= WIPHY_PARAM_RETRY_LONG; + changed |= WIPHY_PARAM_RETRY_SHORT; + } + + if (!changed) + return 0; + + err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); + if (err) { + wdev->wiphy->retry_short = oshort; + wdev->wiphy->retry_long = olong; + } + + return err; +} +EXPORT_SYMBOL(cfg80211_wext_siwretry); + +int cfg80211_wext_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + retry->disabled = 0; + + if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) { + /* + * First return short value, iwconfig will ask long value + * later if needed + */ + retry->flags |= IW_RETRY_LIMIT; + retry->value = wdev->wiphy->retry_short; + if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) + retry->flags |= IW_RETRY_LONG; + + return 0; + } + + if (retry->flags & IW_RETRY_LONG) { + retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + retry->value = wdev->wiphy->retry_long; + } + + return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwretry); -- cgit v0.10.2 From 9d308429a9fd0fa644f0b748f6241631f74a6cda Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 18:43:46 +0200 Subject: cfg80211: clear WEXT SSID when clearing IBSS When we leave an IBSS, we should clear the SSID and not just the BSSID, but since WEXT allows configuring while the interface is down we must not clear it when leaving due to taking the iface down, so some complications are needed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index f256b4f..2006a4e 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -464,7 +464,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; if (!dev->ieee80211_ptr->ssid_len) break; - cfg80211_leave_ibss(rdev, dev); + cfg80211_leave_ibss(rdev, dev, true); break; case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT diff --git a/net/wireless/core.h b/net/wireless/core.h index 89a8159..3e49d33 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -147,8 +147,8 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_ibss_params *params); -void cfg80211_clear_ibss(struct net_device *dev); +void cfg80211_clear_ibss(struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, - struct net_device *dev); + struct net_device *dev, bool nowext); #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 4e1fcb0..b5c601e 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -76,7 +76,7 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, return 0; } -void cfg80211_clear_ibss(struct net_device *dev) +void cfg80211_clear_ibss(struct net_device *dev, bool nowext) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -88,10 +88,14 @@ void cfg80211_clear_ibss(struct net_device *dev) wdev->current_bss = NULL; wdev->ssid_len = 0; memset(wdev->bssid, 0, ETH_ALEN); +#ifdef CONFIG_WIRELESS_EXT + if (!nowext) + wdev->wext.ssid_len = 0; +#endif } int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, - struct net_device *dev) + struct net_device *dev, bool nowext) { int err; @@ -100,7 +104,7 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, if (err) return err; - cfg80211_clear_ibss(dev); + cfg80211_clear_ibss(dev, nowext); return 0; } @@ -179,7 +183,8 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, return 0; if (wdev->ssid_len) { - err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev); + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); if (err) return err; } @@ -241,7 +246,8 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, return -EOPNOTSUPP; if (wdev->ssid_len) { - err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev); + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); if (err) return err; } @@ -275,7 +281,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, data->flags = 1; data->length = wdev->ssid_len; memcpy(ssid, wdev->ssid, data->length); - } else if (wdev->wext.ssid) { + } else if (wdev->wext.ssid && wdev->wext.ssid_len) { data->flags = 1; data->length = wdev->wext.ssid_len; memcpy(ssid, wdev->wext.ssid, data->length); @@ -318,7 +324,8 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, return 0; if (wdev->ssid_len) { - err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev); + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); if (err) return err; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5a9a5c6..97bb5c8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -833,7 +833,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (dev && !err && (ntype != otype)) { if (otype == NL80211_IFTYPE_ADHOC) - cfg80211_clear_ibss(dev); + cfg80211_clear_ibss(dev, false); } unlock: @@ -3249,7 +3249,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) goto out; } - err = cfg80211_leave_ibss(drv, dev); + err = cfg80211_leave_ibss(drv, dev, false); out: cfg80211_put_dev(drv); -- cgit v0.10.2 From ba44cb7226afd4e19308c1d8a90e8b7c566c0d8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 18:49:39 +0200 Subject: cfg80211: mark all WEXT handlers _GPL The fact that these are exported is a technical detail of the conversion period -- we don't want anybody to start relying on these. Ultimately we want things to use cfg80211 only, and once everything that is in wext is converted to cfg80211 drivers will not need to touch wext _at all_. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 1396248..723aeb3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -653,7 +653,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, cfg80211_put_dev(rdev); return err; } -EXPORT_SYMBOL(cfg80211_wext_siwscan); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); static void ieee80211_scan_add_ies(struct iw_request_info *info, struct cfg80211_bss *bss, @@ -962,5 +962,5 @@ int cfg80211_wext_giwscan(struct net_device *dev, cfg80211_put_dev(rdev); return res; } -EXPORT_SYMBOL(cfg80211_wext_giwscan); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); #endif diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 3279e7f..5ef82f2 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -57,7 +57,7 @@ int cfg80211_wext_giwname(struct net_device *dev, return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwname); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, u32 *mode, char *extra) @@ -108,7 +108,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, return ret; } -EXPORT_SYMBOL(cfg80211_wext_siwmode); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, u32 *mode, char *extra) @@ -143,7 +143,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, } return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwmode); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); int cfg80211_wext_giwrange(struct net_device *dev, @@ -239,7 +239,7 @@ int cfg80211_wext_giwrange(struct net_device *dev, return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwrange); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); int cfg80211_wext_siwmlme(struct net_device *dev, struct iw_request_info *info, @@ -283,7 +283,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev, return -EOPNOTSUPP; } } -EXPORT_SYMBOL(cfg80211_wext_siwmlme); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); /** @@ -313,7 +313,7 @@ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, } } -EXPORT_SYMBOL(cfg80211_wext_freq); +EXPORT_SYMBOL_GPL(cfg80211_wext_freq); int cfg80211_wext_siwrts(struct net_device *dev, struct iw_request_info *info, @@ -338,7 +338,7 @@ int cfg80211_wext_siwrts(struct net_device *dev, return err; } -EXPORT_SYMBOL(cfg80211_wext_siwrts); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); int cfg80211_wext_giwrts(struct net_device *dev, struct iw_request_info *info, @@ -352,7 +352,7 @@ int cfg80211_wext_giwrts(struct net_device *dev, return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwrts); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); int cfg80211_wext_siwfrag(struct net_device *dev, struct iw_request_info *info, @@ -379,7 +379,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev, return err; } -EXPORT_SYMBOL(cfg80211_wext_siwfrag); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); int cfg80211_wext_giwfrag(struct net_device *dev, struct iw_request_info *info, @@ -393,7 +393,7 @@ int cfg80211_wext_giwfrag(struct net_device *dev, return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwfrag); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); int cfg80211_wext_siwretry(struct net_device *dev, struct iw_request_info *info, @@ -434,7 +434,7 @@ int cfg80211_wext_siwretry(struct net_device *dev, return err; } -EXPORT_SYMBOL(cfg80211_wext_siwretry); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry); int cfg80211_wext_giwretry(struct net_device *dev, struct iw_request_info *info, @@ -464,4 +464,4 @@ int cfg80211_wext_giwretry(struct net_device *dev, return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwretry); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); -- cgit v0.10.2 From e7ec86f54e519e8e86f1cf328db13263f3ef8bd4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 18 Apr 2009 17:33:24 +0200 Subject: mac80211: validate TIM IE length (redux) The TIM IE must not be shorter than 4 bytes, so verify that when parsing it and use the proper type. To ease that adjust struct ieee80211_tim_ie to have a virtual bitmap of size at least 1. Also check that the TIM IE is actually present before trying to parse it! Because other people may need the function, make it a static inline in ieee80211.h. (The original "mac80211: validate TIM IE length" was a minimal fix for 2.6.30. This purports to be the full, correct fix. -- JWL) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 53563d5..c52e7fb 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -540,7 +540,7 @@ struct ieee80211_tim_ie { u8 dtim_period; u8 bitmap_ctrl; /* variable size: 1 - 251 bytes */ - u8 virtual_map[0]; + u8 virtual_map[1]; } __attribute__ ((packed)); #define WLAN_SA_QUERY_TR_ID_LEN 16 @@ -1392,4 +1392,34 @@ static inline unsigned long ieee80211_tu_to_usec(unsigned long tu) return 1024 * tu; } +/** + * ieee80211_check_tim - check if AID bit is set in TIM + * @tim: the TIM IE + * @tim_len: length of the TIM IE + * @aid: the AID to look for + */ +static inline bool ieee80211_check_tim(struct ieee80211_tim_ie *tim, + u8 tim_len, u16 aid) +{ + u8 mask; + u8 index, indexn1, indexn2; + + if (unlikely(!tim || tim_len < sizeof(*tim))) + return false; + + aid &= 0x3fff; + index = aid / 8; + mask = 1 << (aid & 7); + + indexn1 = tim->bitmap_ctrl & 0xfe; + indexn2 = tim_len + indexn1 - 4; + + if (index < indexn1 || index > indexn2) + return false; + + index -= indexn1; + + return !!(tim->virtual_map[index] & mask); +} + #endif /* LINUX_IEEE80211_H */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index dba78d8..1579bc9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -832,7 +832,7 @@ struct ieee802_11_elems { u8 *fh_params; u8 *ds_params; u8 *cf_params; - u8 *tim; + struct ieee80211_tim_ie *tim; u8 *ibss_params; u8 *challenge; u8 *wpa; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 428742d..1b0b7aa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -675,30 +675,6 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, } } -static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid) -{ - u8 mask; - u8 index, indexn1, indexn2; - struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim; - - if (unlikely(!tim || elems->tim_len < 4)) - return false; - - aid &= 0x3fff; - index = aid / 8; - mask = 1 << (aid & 7); - - indexn1 = tim->bitmap_ctrl & 0xfe; - indexn2 = elems->tim_len + indexn1 - 4; - - if (index < indexn1 || index > indexn2) - return false; - - index -= indexn1; - - return !!(tim->virtual_map[index] & mask); -} - static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, u16 capab, bool erp_valid, u8 erp) { @@ -1806,7 +1782,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, care_about_ies, ncrc); if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) - directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); + directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, + ifmgd->aid); ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim)); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1124421..61876eb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -588,8 +588,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, elems->cf_params_len = elen; break; case WLAN_EID_TIM: - elems->tim = pos; - elems->tim_len = elen; + if (elen >= sizeof(struct ieee80211_tim_ie)) { + elems->tim = (void *)pos; + elems->tim_len = elen; + } break; case WLAN_EID_IBSS_PARAMS: elems->ibss_params = pos; -- cgit v0.10.2 From cca84799dfe9f5201ae9c69eb8ed15fd26b72b37 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 19 Apr 2009 01:28:12 +0200 Subject: ar9170: rework rxstream code With this patch ar9170 is capable of receiving aggregated 802.11n frames and sniffing on most networks without having a "debug message overhead". (Includes phy initialization requested by Johannes Berg -- JWL) Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index b6a1bff..17bd3ea 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -104,10 +104,16 @@ enum ar9170_device_state { AR9170_ASSOCIATED, }; +struct ar9170_rxstream_mpdu_merge { + struct ar9170_rx_head plcp; + bool has_plcp; +}; + struct ar9170 { struct ieee80211_hw *hw; struct mutex mutex; enum ar9170_device_state state; + unsigned long bad_hw_nagger; int (*open)(struct ar9170 *); void (*stop)(struct ar9170 *); @@ -135,6 +141,7 @@ struct ar9170 { u64 cur_mc_hash, want_mc_hash; u32 cur_filter, want_filter; unsigned int filter_changed; + unsigned int filter_state; bool sniffer_enabled; /* PHY */ @@ -174,6 +181,11 @@ struct ar9170 { struct sk_buff_head global_tx_status; struct sk_buff_head global_tx_status_waste; struct delayed_work tx_status_janitor; + + /* rxstream mpdu merge */ + struct ar9170_rxstream_mpdu_merge rx_mpdu; + struct sk_buff *rx_failover; + int rx_failover_missing; }; struct ar9170_sta_info { diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 53e250a..95bf812 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -312,7 +312,7 @@ struct ar9170_rx_head { u8 plcp[12]; } __packed; -struct ar9170_rx_tail { +struct ar9170_rx_phystatus { union { struct { u8 rssi_ant0, rssi_ant1, rssi_ant2, @@ -324,6 +324,9 @@ struct ar9170_rx_tail { u8 evm_stream0[6], evm_stream1[6]; u8 phy_err; +} __packed; + +struct ar9170_rx_macstatus { u8 SAidx, DAidx; u8 error; u8 status; @@ -339,7 +342,7 @@ struct ar9170_rx_tail { #define AR9170_RX_ENC_SOFTWARE 0x8 -static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) +static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) { return (t->SAidx & 0xc0) >> 4 | (t->DAidx & 0xc0) >> 6; @@ -357,10 +360,9 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) #define AR9170_RX_STATUS_MPDU_MASK 0x30 #define AR9170_RX_STATUS_MPDU_SINGLE 0x00 -#define AR9170_RX_STATUS_MPDU_FIRST 0x10 -#define AR9170_RX_STATUS_MPDU_MIDDLE 0x20 -#define AR9170_RX_STATUS_MPDU_LAST 0x30 - +#define AR9170_RX_STATUS_MPDU_FIRST 0x20 +#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 +#define AR9170_RX_STATUS_MPDU_LAST 0x10 #define AR9170_RX_ERROR_RXTO 0x01 #define AR9170_RX_ERROR_OVERRUN 0x02 @@ -369,6 +371,7 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) #define AR9170_RX_ERROR_WRONG_RA 0x10 #define AR9170_RX_ERROR_PLCP 0x20 #define AR9170_RX_ERROR_MMIC 0x40 +#define AR9170_RX_ERROR_FATAL 0x80 struct ar9170_cmd_tx_status { __le16 unkn; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 4682fe2..1b60906 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -454,214 +454,430 @@ static void ar9170_handle_command_response(struct ar9170 *ar, } } -/* - * If the frame alignment is right (or the kernel has - * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there - * is only a single MPDU in the USB frame, then we can - * submit to mac80211 the SKB directly. However, since - * there may be multiple packets in one SKB in stream - * mode, and we need to observe the proper ordering, - * this is non-trivial. - */ -static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) { - struct sk_buff *skb; - struct ar9170_rx_head *head = (void *)buf; - struct ar9170_rx_tail *tail; - struct ieee80211_rx_status status; - int mpdu_len, i; - u8 error, antennas = 0, decrypt; - __le16 fc; - int reserved; + memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head)); + ar->rx_mpdu.has_plcp = false; +} - if (unlikely(!IS_STARTED(ar))) - return ; +static int ar9170_nag_limiter(struct ar9170 *ar) +{ + bool print_message; + + /* + * we expect all sorts of errors in promiscuous mode. + * don't bother with it, it's OK! + */ + if (ar->sniffer_enabled) + return false; + + /* + * only go for frequent errors! The hardware tends to + * do some stupid thing once in a while under load, in + * noisy environments or just for fun! + */ + if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit()) + print_message = true; + else + print_message = false; + + /* reset threshold for "once in a while" */ + ar->bad_hw_nagger = jiffies + HZ / 4; + return print_message; +} + +static int ar9170_rx_mac_status(struct ar9170 *ar, + struct ar9170_rx_head *head, + struct ar9170_rx_macstatus *mac, + struct ieee80211_rx_status *status) +{ + u8 error, decrypt; - /* Received MPDU */ - mpdu_len = len; - mpdu_len -= sizeof(struct ar9170_rx_head); - mpdu_len -= sizeof(struct ar9170_rx_tail); BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); - BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24); + BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); - if (mpdu_len <= FCS_LEN) - return; + error = mac->error; + if (error & AR9170_RX_ERROR_MMIC) { + status->flag |= RX_FLAG_MMIC_ERROR; + error &= ~AR9170_RX_ERROR_MMIC; + } - tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len); + if (error & AR9170_RX_ERROR_PLCP) { + status->flag |= RX_FLAG_FAILED_PLCP_CRC; + error &= ~AR9170_RX_ERROR_PLCP; - for (i = 0; i < 3; i++) - if (tail->rssi[i] != 0x80) - antennas |= BIT(i); + if (!(ar->filter_state & FIF_PLCPFAIL)) + return -EINVAL; + } - /* post-process RSSI */ - for (i = 0; i < 7; i++) - if (tail->rssi[i] & 0x80) - tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f; + if (error & AR9170_RX_ERROR_FCS) { + status->flag |= RX_FLAG_FAILED_FCS_CRC; + error &= ~AR9170_RX_ERROR_FCS; - memset(&status, 0, sizeof(status)); + if (!(ar->filter_state & FIF_FCSFAIL)) + return -EINVAL; + } + + decrypt = ar9170_get_decrypt_type(mac); + if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && + decrypt != AR9170_ENC_ALG_NONE) + status->flag |= RX_FLAG_DECRYPTED; - status.band = ar->channel->band; - status.freq = ar->channel->center_freq; - status.signal = ar->noise[0] + tail->rssi_combined; - status.noise = ar->noise[0]; - status.antenna = antennas; + /* ignore wrong RA errors */ + error &= ~AR9170_RX_ERROR_WRONG_RA; - switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) { + if (error & AR9170_RX_ERROR_DECRYPT) { + error &= ~AR9170_RX_ERROR_DECRYPT; + /* + * Rx decryption is done in place, + * the original data is lost anyway. + */ + + return -EINVAL; + } + + /* drop any other error frames */ + if (unlikely(error)) { + /* TODO: update netdevice's RX dropped/errors statistics */ + + if (ar9170_nag_limiter(ar)) + printk(KERN_DEBUG "%s: received frame with " + "suspicious error code (%#x).\n", + wiphy_name(ar->hw->wiphy), error); + + return -EINVAL; + } + + status->band = ar->channel->band; + status->freq = ar->channel->center_freq; + + switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) { case AR9170_RX_STATUS_MODULATION_CCK: - if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE) - status.flag |= RX_FLAG_SHORTPRE; + if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) + status->flag |= RX_FLAG_SHORTPRE; switch (head->plcp[0]) { case 0x0a: - status.rate_idx = 0; + status->rate_idx = 0; break; case 0x14: - status.rate_idx = 1; + status->rate_idx = 1; break; case 0x37: - status.rate_idx = 2; + status->rate_idx = 2; break; case 0x6e: - status.rate_idx = 3; + status->rate_idx = 3; break; default: - if ((!ar->sniffer_enabled) && (net_ratelimit())) + if (ar9170_nag_limiter(ar)) printk(KERN_ERR "%s: invalid plcp cck rate " "(%x).\n", wiphy_name(ar->hw->wiphy), head->plcp[0]); - return; + return -EINVAL; } break; + case AR9170_RX_STATUS_MODULATION_OFDM: - switch (head->plcp[0] & 0xF) { - case 0xB: - status.rate_idx = 0; + switch (head->plcp[0] & 0xf) { + case 0xb: + status->rate_idx = 0; break; - case 0xF: - status.rate_idx = 1; + case 0xf: + status->rate_idx = 1; break; - case 0xA: - status.rate_idx = 2; + case 0xa: + status->rate_idx = 2; break; - case 0xE: - status.rate_idx = 3; + case 0xe: + status->rate_idx = 3; break; case 0x9: - status.rate_idx = 4; + status->rate_idx = 4; break; - case 0xD: - status.rate_idx = 5; + case 0xd: + status->rate_idx = 5; break; case 0x8: - status.rate_idx = 6; + status->rate_idx = 6; break; - case 0xC: - status.rate_idx = 7; + case 0xc: + status->rate_idx = 7; break; default: - if ((!ar->sniffer_enabled) && (net_ratelimit())) + if (ar9170_nag_limiter(ar)) printk(KERN_ERR "%s: invalid plcp ofdm rate " "(%x).\n", wiphy_name(ar->hw->wiphy), head->plcp[0]); - return; + return -EINVAL; } - if (status.band == IEEE80211_BAND_2GHZ) - status.rate_idx += 4; + if (status->band == IEEE80211_BAND_2GHZ) + status->rate_idx += 4; break; + case AR9170_RX_STATUS_MODULATION_HT: + if (head->plcp[3] & 0x80) + status->flag |= RX_FLAG_40MHZ; + if (head->plcp[6] & 0x80) + status->flag |= RX_FLAG_SHORT_GI; + + status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f); + status->flag |= RX_FLAG_HT; + break; + case AR9170_RX_STATUS_MODULATION_DUPOFDM: /* XXX */ - - if (net_ratelimit()) + if (ar9170_nag_limiter(ar)) printk(KERN_ERR "%s: invalid modulation\n", wiphy_name(ar->hw->wiphy)); - return; + return -EINVAL; } - error = tail->error; + return 0; +} - if (error & AR9170_RX_ERROR_MMIC) { - status.flag |= RX_FLAG_MMIC_ERROR; - error &= ~AR9170_RX_ERROR_MMIC; - } +static void ar9170_rx_phy_status(struct ar9170 *ar, + struct ar9170_rx_phystatus *phy, + struct ieee80211_rx_status *status) +{ + int i; - if (error & AR9170_RX_ERROR_PLCP) { - status.flag |= RX_FLAG_FAILED_PLCP_CRC; - error &= ~AR9170_RX_ERROR_PLCP; + BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); + + for (i = 0; i < 3; i++) + if (phy->rssi[i] != 0x80) + status->antenna |= BIT(i); + + /* post-process RSSI */ + for (i = 0; i < 7; i++) + if (phy->rssi[i] & 0x80) + phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; + + /* TODO: we could do something with phy_errors */ + status->signal = ar->noise[0] + phy->rssi_combined; + status->noise = ar->noise[0]; +} + +static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) +{ + struct sk_buff *skb; + int reserved = 0; + struct ieee80211_hdr *hdr = (void *) buf; + + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + reserved += NET_IP_ALIGN; + + if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + reserved += NET_IP_ALIGN; } - if (error & AR9170_RX_ERROR_FCS) { - status.flag |= RX_FLAG_FAILED_FCS_CRC; - error &= ~AR9170_RX_ERROR_FCS; + if (ieee80211_has_a4(hdr->frame_control)) + reserved += NET_IP_ALIGN; + + reserved = 32 + (reserved & NET_IP_ALIGN); + + skb = dev_alloc_skb(len + reserved); + if (likely(skb)) { + skb_reserve(skb, reserved); + memcpy(skb_put(skb, len), buf, len); } - decrypt = ar9170_get_decrypt_type(tail); - if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && - decrypt != AR9170_ENC_ALG_NONE) - status.flag |= RX_FLAG_DECRYPTED; + return skb; +} - /* ignore wrong RA errors */ - error &= ~AR9170_RX_ERROR_WRONG_RA; +/* + * If the frame alignment is right (or the kernel has + * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there + * is only a single MPDU in the USB frame, then we could + * submit to mac80211 the SKB directly. However, since + * there may be multiple packets in one SKB in stream + * mode, and we need to observe the proper ordering, + * this is non-trivial. + */ - if (error & AR9170_RX_ERROR_DECRYPT) { - error &= ~AR9170_RX_ERROR_DECRYPT; +static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +{ + struct ar9170_rx_head *head; + struct ar9170_rx_macstatus *mac; + struct ar9170_rx_phystatus *phy = NULL; + struct ieee80211_rx_status status; + struct sk_buff *skb; + int mpdu_len; + + if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac)))) + return ; + + /* Received MPDU */ + mpdu_len = len - sizeof(*mac); + + mac = (void *)(buf + mpdu_len); + if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { + /* this frame is too damaged and can't be used - drop it */ - /* - * Rx decryption is done in place, - * the original data is lost anyway. - */ return ; } - /* drop any other error frames */ - if ((error) && (net_ratelimit())) { - printk(KERN_DEBUG "%s: errors: %#x\n", - wiphy_name(ar->hw->wiphy), error); - return; + switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) { + case AR9170_RX_STATUS_MPDU_FIRST: + /* first mpdu packet has the plcp header */ + if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { + head = (void *) buf; + memcpy(&ar->rx_mpdu.plcp, (void *) buf, + sizeof(struct ar9170_rx_head)); + + mpdu_len -= sizeof(struct ar9170_rx_head); + buf += sizeof(struct ar9170_rx_head); + ar->rx_mpdu.has_plcp = true; + } else { + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: plcp info is clipped.\n", + wiphy_name(ar->hw->wiphy)); + return ; + } + break; + + case AR9170_RX_STATUS_MPDU_LAST: + /* last mpdu has a extra tail with phy status information */ + + if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { + mpdu_len -= sizeof(struct ar9170_rx_phystatus); + phy = (void *)(buf + mpdu_len); + } else { + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: frame tail is clipped.\n", + wiphy_name(ar->hw->wiphy)); + return ; + } + + case AR9170_RX_STATUS_MPDU_MIDDLE: + /* middle mpdus are just data */ + if (unlikely(!ar->rx_mpdu.has_plcp)) { + if (!ar9170_nag_limiter(ar)) + return ; + + printk(KERN_ERR "%s: rx stream did not start " + "with a first_mpdu frame tag.\n", + wiphy_name(ar->hw->wiphy)); + + return ; + } + + head = &ar->rx_mpdu.plcp; + break; + + case AR9170_RX_STATUS_MPDU_SINGLE: + /* single mpdu - has plcp (head) and phy status (tail) */ + head = (void *) buf; + + mpdu_len -= sizeof(struct ar9170_rx_head); + mpdu_len -= sizeof(struct ar9170_rx_phystatus); + + buf += sizeof(struct ar9170_rx_head); + phy = (void *)(buf + mpdu_len); + break; + + default: + BUG_ON(1); + break; } - buf += sizeof(struct ar9170_rx_head); - fc = *(__le16 *)buf; + if (unlikely(mpdu_len < FCS_LEN)) + return ; - if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc)) - reserved = 32 + 2; - else - reserved = 32; + memset(&status, 0, sizeof(status)); + if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status))) + return ; - skb = dev_alloc_skb(mpdu_len + reserved); - if (!skb) - return; + if (phy) + ar9170_rx_phy_status(ar, phy, &status); - skb_reserve(skb, reserved); - memcpy(skb_put(skb, mpdu_len), buf, mpdu_len); - ieee80211_rx_irqsafe(ar->hw, skb, &status); + skb = ar9170_rx_copy_data(buf, mpdu_len); + if (likely(skb)) + ieee80211_rx_irqsafe(ar->hw, skb, &status); } void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) { - unsigned int i, tlen, resplen; + unsigned int i, tlen, resplen, wlen = 0, clen = 0; u8 *tbuf, *respbuf; tbuf = skb->data; tlen = skb->len; while (tlen >= 4) { - int clen = tbuf[1] << 8 | tbuf[0]; - int wlen = (clen + 3) & ~3; + clen = tbuf[1] << 8 | tbuf[0]; + wlen = ALIGN(clen, 4); - /* - * parse stream (if any) - */ + /* check if this is stream has a valid tag.*/ if (tbuf[2] != 0 || tbuf[3] != 0x4e) { - printk(KERN_ERR "%s: missing tag!\n", - wiphy_name(ar->hw->wiphy)); + /* + * TODO: handle the highly unlikely event that the + * corrupted stream has the TAG at the right position. + */ + + /* check if the frame can be repaired. */ + if (!ar->rx_failover_missing) { + /* this is no "short read". */ + if (ar9170_nag_limiter(ar)) { + printk(KERN_ERR "%s: missing tag!\n", + wiphy_name(ar->hw->wiphy)); + goto err_telluser; + } else + goto err_silent; + } + + if (ar->rx_failover_missing > tlen) { + if (ar9170_nag_limiter(ar)) { + printk(KERN_ERR "%s: possible multi " + "stream corruption!\n", + wiphy_name(ar->hw->wiphy)); + goto err_telluser; + } else + goto err_silent; + } + + memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + ar->rx_failover_missing -= tlen; + + if (ar->rx_failover_missing <= 0) { + /* + * nested ar9170_rx call! + * termination is guranteed, even when the + * combined frame also have a element with + * a bad tag. + */ + + ar->rx_failover_missing = 0; + ar9170_rx(ar, ar->rx_failover); + + skb_reset_tail_pointer(ar->rx_failover); + skb_trim(ar->rx_failover, 0); + } + return ; } + + /* check if stream is clipped */ if (wlen > tlen - 4) { - printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n", - wiphy_name(ar->hw->wiphy), clen, wlen, tlen); - print_hex_dump(KERN_DEBUG, "data: ", - DUMP_PREFIX_OFFSET, - 16, 1, tbuf, tlen, true); + if (ar->rx_failover_missing) { + /* TODO: handle double stream corruption. */ + if (ar9170_nag_limiter(ar)) { + printk(KERN_ERR "%s: double rx stream " + "corruption!\n", + wiphy_name(ar->hw->wiphy)); + goto err_telluser; + } else + goto err_silent; + } + + /* + * save incomplete data set. + * the firmware will resend the missing bits when + * the rx - descriptor comes round again. + */ + + memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + ar->rx_failover_missing = clen - tlen; return ; } resplen = clen; @@ -686,12 +902,44 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) if (i == 12) ar9170_handle_command_response(ar, respbuf, resplen); else - ar9170_handle_mpdu(ar, respbuf, resplen); + ar9170_handle_mpdu(ar, respbuf, clen); } - if (tlen) - printk(KERN_ERR "%s: buffer remains!\n", - wiphy_name(ar->hw->wiphy)); + if (tlen) { + if (net_ratelimit()) + printk(KERN_ERR "%s: %d bytes of unprocessed " + "data left in rx stream!\n", + wiphy_name(ar->hw->wiphy), tlen); + + goto err_telluser; + } + + return ; + +err_telluser: + printk(KERN_ERR "%s: damaged RX stream data [want:%d, " + "data:%d, rx:%d, pending:%d ]\n", + wiphy_name(ar->hw->wiphy), clen, wlen, tlen, + ar->rx_failover_missing); + + if (ar->rx_failover_missing) + print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, + ar->rx_failover->data, + ar->rx_failover->len); + + print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, + skb->data, skb->len); + + printk(KERN_ERR "%s: please check your hardware and cables, if " + "you see this message frequently.\n", + wiphy_name(ar->hw->wiphy)); + +err_silent: + if (ar->rx_failover_missing) { + skb_reset_tail_pointer(ar->rx_failover); + skb_trim(ar->rx_failover, 0); + ar->rx_failover_missing = 0; + } } #define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ @@ -721,6 +969,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw) AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ + ar->bad_hw_nagger = jiffies; + err = ar->open(ar); if (err) goto out; @@ -1175,8 +1425,8 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, /* mask supported flags */ *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS; - + FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; + ar->filter_state = *new_flags; /* * We can support more by setting the sniffer bit and * then checking the error flags, later. @@ -1559,20 +1809,33 @@ void *ar9170_alloc(size_t priv_size) { struct ieee80211_hw *hw; struct ar9170 *ar; + struct sk_buff *skb; int i; + /* + * this buffer is used for rx stream reconstruction. + * Under heavy load this device (or the transport layer?) + * tends to split the streams into seperate rx descriptors. + */ + + skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL); + if (!skb) + goto err_nomem; + hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); if (!hw) - return ERR_PTR(-ENOMEM); + goto err_nomem; ar = hw->priv; ar->hw = hw; + ar->rx_failover = skb; mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); skb_queue_head_init(&ar->global_tx_status); skb_queue_head_init(&ar->global_tx_status_waste); + ar9170_rx_reset_rx_mpdu(ar); INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); @@ -1600,6 +1863,10 @@ void *ar9170_alloc(size_t priv_size) ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ return ar; + +err_nomem: + kfree_skb(skb); + return ERR_PTR(-ENOMEM); } static int ar9170_read_eeprom(struct ar9170 *ar) @@ -1725,6 +1992,7 @@ void ar9170_unregister(struct ar9170 *ar) ar9170_unregister_leds(ar); #endif /* CONFIG_AR9170_LEDS */ + kfree_skb(ar->rx_failover); ieee80211_unregister_hw(ar->hw); mutex_destroy(&ar->mutex); } -- cgit v0.10.2 From 9b3bf06abad70db820c74c90118ea49358549d22 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 14:36:55 -0700 Subject: iwlwifi: rename PROBE_OPTION_MAX_API1 to PROBE_OPTION_MAX_3945 This limit applies to current (APIv1 and APIv2) 3945 firmware only, not supported firmware of any of the other cards. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 29d4074..411a5d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2469,8 +2469,8 @@ struct iwl_ssid_ie { u8 ssid[32]; } __attribute__ ((packed)); -#define PROBE_OPTION_MAX_API1 0x4 -#define PROBE_OPTION_MAX 0x14 +#define PROBE_OPTION_MAX_3945 4 +#define PROBE_OPTION_MAX 20 #define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) #define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 @@ -2552,7 +2552,7 @@ struct iwl3945_scan_cmd { struct iwl3945_tx_cmd tx_cmd; /* For directed active scans (set to all-0s otherwise) */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_API1]; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; /* * Probe request frame, followed by channel list. -- cgit v0.10.2 From 1ecf9fc1317f8df91eb1d74360f408558d657478 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 14:36:56 -0700 Subject: iwlwifi: improve scan support This modifies iwlwifi to * no longer build its own probe request, but use mac80211's * therefore, support arbitrary scan IEs (up to the max len) * support multiple scan SSIDs * support passive scanning Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 411a5d2..7b84d52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2474,6 +2474,7 @@ struct iwl_ssid_ie { #define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) #define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 +#define IWL_MAX_PROBE_REQUEST 200 /* * REPLY_SCAN_CMD = 0x80 (command) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f231752..c43c57d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1309,8 +1309,10 @@ int iwl_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->custom_regulatory = true; - hw->wiphy->max_scan_ssids = 1; - hw->wiphy->max_scan_ie_len = 0; /* XXX for now */ + + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; + /* we create the 802.11 header and a zero-length SSID element */ + hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8773d73..8ab60df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -396,8 +396,8 @@ int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); int iwl_scan_initiate(struct iwl_priv *priv); int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); -u16 iwl_fill_probe_req(struct iwl_priv *priv, enum ieee80211_band band, - struct ieee80211_mgmt *frame, int left); +u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, + const u8 *ie, int ie_len, int left); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); u16 iwl_get_active_dwell_time(struct iwl_priv *priv, enum ieee80211_band band, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0922e33..e363d9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -889,9 +889,7 @@ struct iwl_priv { unsigned long scan_start_tsf; void *scan; int scan_bands; - int one_direct_scan; - u8 direct_ssid_len; - u8 direct_ssid[IW_ESSID_MAX_SIZE]; + struct cfg80211_scan_request *scan_request; u8 scan_tx_ant[IEEE80211_NUM_BANDS]; u8 mgmt_tx_ant; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 23644cf..9edcf8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -448,13 +448,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, unsigned long flags; struct iwl_priv *priv = hw->priv; int ret; - u8 *ssid = NULL; - size_t ssid_len = 0; - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; - } IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -488,13 +481,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } - if (ssid_len) { - priv->one_direct_scan = 1; - priv->direct_ssid_len = ssid_len; - memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); - } else { - priv->one_direct_scan = 0; - } + priv->scan_request = req; ret = iwl_scan_initiate(priv); @@ -533,73 +520,14 @@ void iwl_bg_scan_check(struct work_struct *data) EXPORT_SYMBOL(iwl_bg_scan_check); /** - * iwl_supported_rate_to_ie - fill in the supported rate in IE field - * - * return : set the bit for each supported rate insert in ie - */ -static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, - u16 basic_rate, int *left) -{ - u16 ret_rates = 0, bit; - int i; - u8 *cnt = ie; - u8 *rates = ie + 1; - - for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { - if (bit & supported_rate) { - ret_rates |= bit; - rates[*cnt] = iwl_rates[i].ieee | - ((bit & basic_rate) ? 0x80 : 0x00); - (*cnt)++; - (*left)--; - if ((*left <= 0) || - (*cnt >= IWL_SUPPORTED_RATES_IE_LEN)) - break; - } - } - - return ret_rates; -} - - -static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, - u8 *pos, int *left) -{ - struct ieee80211_ht_cap *ht_cap; - - if (!sband || !sband->ht_cap.ht_supported) - return; - - if (*left < sizeof(struct ieee80211_ht_cap)) - return; - - *pos++ = sizeof(struct ieee80211_ht_cap); - ht_cap = (struct ieee80211_ht_cap *) pos; - - ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); - memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16); - ht_cap->ampdu_params_info = - (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | - ((sband->ht_cap.ampdu_density << 2) & - IEEE80211_HT_AMPDU_PARM_DENSITY); - *left -= sizeof(struct ieee80211_ht_cap); -} - -/** * iwl_fill_probe_req - fill in all required fields and IE for probe request */ -u16 iwl_fill_probe_req(struct iwl_priv *priv, - enum ieee80211_band band, - struct ieee80211_mgmt *frame, - int left) +u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, + const u8 *ies, int ie_len, int left) { int len = 0; u8 *pos = NULL; - u16 active_rates, ret_rates, cck_rates, active_rate_basic; - const struct ieee80211_supported_band *sband = - iwl_get_hw_mode(priv, band); - /* Make sure there is enough space for the probe request, * two mandatory IEs and the data */ @@ -627,62 +555,12 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, len += 2; - /* fill in supported rate */ - left -= 2; - if (left < 0) - return 0; - - *pos++ = WLAN_EID_SUPP_RATES; - *pos = 0; - - /* exclude 60M rate */ - active_rates = priv->rates_mask; - active_rates &= ~IWL_RATE_60M_MASK; - - active_rate_basic = active_rates & IWL_BASIC_RATES_MASK; - - cck_rates = IWL_CCK_RATES_MASK & active_rates; - ret_rates = iwl_supported_rate_to_ie(pos, cck_rates, - active_rate_basic, &left); - active_rates &= ~ret_rates; - - ret_rates = iwl_supported_rate_to_ie(pos, active_rates, - active_rate_basic, &left); - active_rates &= ~ret_rates; + if (WARN_ON(left < ie_len)) + return len; - len += 2 + *pos; - pos += (*pos) + 1; - - if (active_rates == 0) - goto fill_end; - - /* fill in supported extended rate */ - /* ...next IE... */ - left -= 2; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos = 0; - iwl_supported_rate_to_ie(pos, active_rates, active_rate_basic, &left); - if (*pos > 0) { - len += 2 + *pos; - pos += (*pos) + 1; - } else { - pos--; - } - - fill_end: - - left -= 2; - if (left < 0) - return 0; - - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos = 0; - iwl_ht_cap_to_ie(sband, pos, &left); - if (*pos > 0) - len += 2 + *pos; + memcpy(pos, ies, ie_len); + len += ie_len; + left -= ie_len; return (u16)len; } @@ -703,10 +581,10 @@ static void iwl_bg_request_scan(struct work_struct *data) u32 rate_flags = 0; u16 cmd_len; enum ieee80211_band band; - u8 n_probes = 2; + u8 n_probes = 0; u8 rx_chain = priv->hw_params.valid_rx_ant; u8 rate; - DECLARE_SSID_BUF(ssid); + bool is_active = false; conf = ieee80211_get_hw_conf(priv->hw); @@ -796,19 +674,25 @@ static void iwl_bg_request_scan(struct work_struct *data) scan_suspend_time, interval); } - /* We should add the ability for user to lock to PASSIVE ONLY */ - if (priv->one_direct_scan) { - IWL_DEBUG_SCAN(priv, "Start direct scan for '%s'\n", - print_ssid(ssid, priv->direct_ssid, - priv->direct_ssid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->direct_ssid_len; - memcpy(scan->direct_scan[0].ssid, - priv->direct_ssid, priv->direct_ssid_len); - n_probes++; - } else { - IWL_DEBUG_SCAN(priv, "Start indirect scan.\n"); - } + if (priv->scan_request->n_ssids) { + int i, p = 0; + IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; + } + is_active = true; + } else + IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; @@ -850,10 +734,11 @@ static void iwl_bg_request_scan(struct work_struct *data) cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); - - cmd_len = iwl_fill_probe_req(priv, band, - (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); + cmd_len = iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + priv->scan_request->ie, + priv->scan_request->ie_len, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); scan->tx_cmd.len = cpu_to_le16(cmd_len); @@ -864,8 +749,7 @@ static void iwl_bg_request_scan(struct work_struct *data) RXON_FILTER_BCON_AWARE_MSK); scan->channel_count = - iwl_get_channels_for_scan(priv, band, 1, /* active */ - n_probes, + iwl_get_channels_for_scan(priv, band, is_active, n_probes, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); if (scan->channel_count == 0) { @@ -928,6 +812,7 @@ void iwl_bg_scan_completed(struct work_struct *work) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + priv->scan_request = NULL; ieee80211_scan_completed(priv->hw, false); /* Since setting the TXPOWER may have been deferred while diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ed49755..4df9b4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2942,9 +2942,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data) int rc = 0; struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; - u8 n_probes = 2; + u8 n_probes = 0; enum ieee80211_band band; - DECLARE_SSID_BUF(ssid); + bool is_active = false; conf = ieee80211_get_hw_conf(priv->hw); @@ -3043,18 +3043,25 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan_suspend_time, interval); } - /* We should add the ability for user to lock to PASSIVE ONLY */ - if (priv->one_direct_scan) { - IWL_DEBUG_SCAN(priv, "Kicking off one direct scan for '%s'\n", - print_ssid(ssid, priv->direct_ssid, - priv->direct_ssid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->direct_ssid_len; - memcpy(scan->direct_scan[0].ssid, - priv->direct_ssid, priv->direct_ssid_len); - n_probes++; + if (priv->scan_request->n_ssids) { + int i, p = 0; + IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; + } + is_active = true; } else - IWL_DEBUG_SCAN(priv, "Kicking off one indirect scan.\n"); + IWL_DEBUG_SCAN(priv, "Kicking off passive scan.\n"); /* We don't build a direct scan probe request; the uCode will do * that based on the direct_mask added to each channel entry */ @@ -3079,9 +3086,11 @@ static void iwl3945_bg_request_scan(struct work_struct *data) } scan->tx_cmd.len = cpu_to_le16( - iwl_fill_probe_req(priv, band, - (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan))); + iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + priv->scan_request->ie, + priv->scan_request->ie_len, + IWL_MAX_SCAN_SIZE - sizeof(*scan))); /* select Rx antennas */ scan->flags |= iwl3945_get_antenna_flags(priv); @@ -3090,8 +3099,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->channel_count = - iwl3945_get_channels_for_scan(priv, band, 1, /* active */ - n_probes, + iwl3945_get_channels_for_scan(priv, band, is_active, n_probes, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); if (scan->channel_count == 0) { @@ -4119,7 +4127,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) hw->wiphy->custom_regulatory = true; - hw->wiphy->max_scan_ssids = 1; /* WILL FIX */ + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; + /* we create the 802.11 header and a zero-length SSID element */ + hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; -- cgit v0.10.2 From b097ad29752f909ec1121ac3dc57d348f08dd8d7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2009 14:36:57 -0700 Subject: iwlwifi: support truly passive scanning If passive scanning is requested we should not ask the microcode to do active scanning after detecting traffic on a channel -- that should only be used when an active scan is requested but some channels are marked passive. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 9edcf8c..25311e1c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -712,7 +712,12 @@ static void iwl_bg_request_scan(struct work_struct *data) } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { band = IEEE80211_BAND_5GHZ; rate = IWL_RATE_6M_PLCP; - scan->good_CRC_th = IWL_GOOD_CRC_TH; + /* + * If active scaning is requested but a certain channel + * is marked passive, we can do active scanning if we + * detect transmissions. + */ + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0; /* 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. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4df9b4b..c15d0cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3078,7 +3078,12 @@ static void iwl3945_bg_request_scan(struct work_struct *data) band = IEEE80211_BAND_2GHZ; } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { scan->tx_cmd.rate = IWL_RATE_6M_PLCP; - scan->good_CRC_th = IWL_GOOD_CRC_TH; + /* + * If active scaning is requested but a certain channel + * is marked passive, we can do active scanning if we + * detect transmissions. + */ + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0; band = IEEE80211_BAND_5GHZ; } else { IWL_WARN(priv, "Invalid scan band count\n"); -- cgit v0.10.2 From a75fbe8d68ceace836b27c216a5eda1c4687be4b Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Mon, 20 Apr 2009 14:36:58 -0700 Subject: iwl3945: add debugfs to 3945 Patch adds debugfs to 3945. Also fix debugfs registration in iwlagn to return error code if it fails. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 12de63e..2751736 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2829,7 +2829,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = iwl_dbgfs_register(priv, DRV_NAME); if (err) - IWL_ERR(priv, "failed to create debugfs files\n"); + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c15d0cf..bcfe199 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4346,6 +4346,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) goto out_remove_sysfs; + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); + err = iwl_rfkill_init(priv); if (err) IWL_ERR(priv, "Unable to initialize RFKILL system. " @@ -4396,6 +4400,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); + iwl_dbgfs_unregister(priv); + set_bit(STATUS_EXIT_PENDING, &priv->status); if (priv->mac80211_registered) { -- cgit v0.10.2 From 86ddbf62c2daefebba13e3c79f88cbdfde766176 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Mon, 20 Apr 2009 14:36:59 -0700 Subject: iwl3945: calculate debugfs isr statistics This patch calculates interrupt statistics for debugfs. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bcfe199..562dd76 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1543,6 +1543,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, @@ -1845,6 +1846,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); + priv->isr_stats.hw++; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -1857,13 +1859,17 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) + if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " "the frame/frames.\n"); + priv->isr_stats.sch++; + } /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) + if (inta & CSR_INT_BIT_ALIVE) { IWL_DEBUG_ISR(priv, "Alive interrupt\n"); + priv->isr_stats.alive++; + } } #endif /* Safely ignore these bits for debug checks below */ @@ -1873,6 +1879,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERR(priv, "Microcode SW error detected. " "Restarting 0x%X.\n", inta); + priv->isr_stats.sw++; + priv->isr_stats.sw_err = inta; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_SW_ERR; } @@ -1888,6 +1896,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_txq_update_write_ptr(priv, &priv->txq[4]); iwl_txq_update_write_ptr(priv, &priv->txq[5]); + priv->isr_stats.wakeup++; handled |= CSR_INT_BIT_WAKEUP; } @@ -1896,11 +1905,13 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) * notifications from uCode come through here*/ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl3945_rx_handle(priv); + priv->isr_stats.rx++; handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } if (inta & CSR_INT_BIT_FH_TX) { IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + priv->isr_stats.tx++; iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); if (!iwl_grab_nic_access(priv)) { @@ -1911,8 +1922,10 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_FH_TX; } - if (inta & ~handled) + if (inta & ~handled) { IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); + priv->isr_stats.unhandled++; + } if (inta & ~CSR_INI_SET_MASK) { IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", -- cgit v0.10.2 From 279b05d4362472ae9269f982f00e644265bdbf94 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 20 Apr 2009 14:37:00 -0700 Subject: iwlwifi: clean up unused NL80211_IFTYPE_MONITOR for Monitor mode This patch clean up the code for NL80211_IFTYPE_MONITOR mode, priv->iw_mode is set in add_interface, but add_interface is never called for monitor mode. The only way mac80211 informs us about monitor mode is through configuring filter; since iw_mode will never set to NL80211_IFTYPE_MONITOR, modify and remove all the code refer to NL80211_IFTYPE_MONITOR and replace with iwl_is_monitor_mode() function call. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2751736..fc52d32 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2001,8 +2001,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw) out: priv->is_open = 1; - /* default to MONITOR mode */ - priv->iw_mode = NL80211_IFTYPE_MONITOR; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c43c57d..bf7ad51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -904,10 +904,11 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap) * never called for monitor mode. The only way mac80211 informs us about * monitor mode is through configuring filters (call to configure_filter). */ -static bool iwl_is_monitor_mode(struct iwl_priv *priv) +bool iwl_is_monitor_mode(struct iwl_priv *priv) { return !!(priv->staging_rxon.filter_flags & RXON_FILTER_PROMISC_MSK); } +EXPORT_SYMBOL(iwl_is_monitor_mode); /** * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image @@ -1071,11 +1072,6 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) RXON_FILTER_ACCEPT_GRP_MSK; break; - 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; - break; default: IWL_ERR(priv, "Unsupported interface type %d\n", mode); break; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8ab60df..3bc2f6c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -267,6 +267,7 @@ int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); +bool iwl_is_monitor_mode(struct iwl_priv *priv); void iwl_post_associate(struct iwl_priv *priv); void iwl_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 8f65908..fae8426 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1102,13 +1102,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, 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 == NL80211_IFTYPE_MONITOR) { - iwl_pass_packet_to_mac80211(priv, include_phy, - rxb, &rx_status); - return; - } - network_packet = iwl_is_network_packet(priv, header); if (network_packet) { priv->last_rx_rssi = rx_status.signal; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 25311e1c..799f5eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -747,7 +747,7 @@ static void iwl_bg_request_scan(struct work_struct *data) scan->tx_cmd.len = cpu_to_le16(cmd_len); - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) + if (iwl_is_monitor_mode(priv)) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index b8f18c6..17a4dd2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1078,11 +1078,6 @@ 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_WARN(priv, "Unknown mode of operation: %d\n", priv->iw_mode); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c734c5f..58cdd32 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -728,7 +728,7 @@ 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) && - (priv->iw_mode != NL80211_IFTYPE_MONITOR || + (!iwl_is_monitor_mode(priv) || !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) || diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 562dd76..c9fde0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -729,7 +729,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */ + (!iwl_is_monitor_mode(priv)) && /* packet injection */ (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) { IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n"); @@ -3113,7 +3113,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) /* select Rx antennas */ scan->flags |= iwl3945_get_antenna_flags(priv); - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) + if (iwl_is_monitor_mode(priv)) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->channel_count = -- cgit v0.10.2 From 447fee700f6cb7ada906c5db61c6c045741893e8 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Mon, 20 Apr 2009 14:37:02 -0700 Subject: iwlcore: Fix stay in table function. Function rs_stay_in_table was flushing the rate scale table way to early. time_after macro in expecting long value and was failing because we passing u32 value. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 98b6b37..3504279 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -52,7 +52,7 @@ /* max allowed rate miss before sync LQ cmd */ #define IWL_MISSED_RATE_MAX 15 /* max time to accum history 2 seconds */ -#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) +#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) static u8 rs_ht_to_legacy[] = { IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, @@ -135,7 +135,7 @@ struct iwl_lq_sta { u32 table_count; u32 total_failed; /* total failed frames, any/all rates */ u32 total_success; /* total successful frames, any/all rates */ - u32 flush_timer; /* time staying in mode before new search */ + u64 flush_timer; /* time staying in mode before new search */ u8 action_counter; /* # mode-switch actions tried */ u8 is_green; @@ -1025,6 +1025,7 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, lq_sta->table_count = 0; lq_sta->total_failed = 0; lq_sta->total_success = 0; + lq_sta->flush_timer = jiffies; } /* @@ -1914,8 +1915,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) /* Elapsed time using current modulation mode */ if (lq_sta->flush_timer) flush_interval_passed = - time_after(jiffies, - (unsigned long)(lq_sta->flush_timer + + time_after(jiffies, + (unsigned long)(lq_sta->flush_timer + IWL_RATE_SCALE_FLUSH_INTVL)); /* @@ -2249,6 +2250,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, update_lq = 1; index = low; } + break; case 1: /* Increase starting rate, update uCode's rate table */ @@ -2314,8 +2316,11 @@ lq_update: tbl->current_rate, index); rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } + } else + done_search = 1; + } + if (done_search && !lq_sta->stay_in_tbl) { /* If the "active" (non-search) mode was legacy, * and we've tried switching antennas, * but we haven't been able to try HT modes (not available), @@ -2350,17 +2355,6 @@ lq_update: lq_sta->action_counter = 0; rs_set_stay_in_table(priv, 0, lq_sta); } - - /* - * Else, don't search for a new modulation mode. - * Put new timestamp in stay-in-modulation-mode flush timer if: - * 1) Not changing rates right now - * 2) Not just finishing up a search - * 3) flush timer is empty - */ - } else { - if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer)) - lq_sta->flush_timer = jiffies; } out: -- cgit v0.10.2 From 09f9bf79b7870ac017a94f7f9b603c2e28ac73f7 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Mon, 20 Apr 2009 14:37:03 -0700 Subject: iwlwifi: remove radio disable parameter. Patch removes the "manual radio disable" parameter as there is no usage scenario of disabling radio using this module parameter. User can use iwconfig's txpower to enable and disable radio. This module parameter also does not work as expected. During module load the status of radio is set, the radio is not actually disabled. Even so, the moment mac80211 requests the interface to be up the radio will be enabled again. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e4762e5..a98ff4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2361,8 +2361,6 @@ MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(disable, iwl4965_mod_params.disable, int, 0444); -MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named(debug, iwl4965_mod_params.debug, uint, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5bbb4f9..d731a83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1655,9 +1655,6 @@ struct iwl_cfg iwl5150_agn_cfg = { MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); -module_param_named(disable50, iwl50_mod_params.disable, int, 0444); -MODULE_PARM_DESC(disable50, - "manually disable the 50XX radio (default 0 [radio on])"); module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fc52d32..9e41e1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2774,18 +2774,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_free_eeprom; /* At this point both hw and priv are initialized. */ - /********************************** - * 7. Initialize module parameters - **********************************/ - - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (priv->cfg->mod_params->disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO(priv, "Radio disabled.\n"); - } - /******************** - * 8. Setup services + * 7. Setup services ********************/ spin_lock_irqsave(&priv->lock, flags); iwl_disable_interrupts(priv); @@ -2809,7 +2799,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_setup_rx_handlers(priv); /********************************** - * 9. Setup and register mac80211 + * 8. Setup and register mac80211 **********************************/ /* enable interrupts if needed: hw bug w/a */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3bc2f6c..d4c60af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -176,7 +176,6 @@ struct iwl_ops { }; struct iwl_mod_params { - int disable; /* def: 0 = enable radio */ int sw_crypto; /* def: 0 = using hardware encryption */ u32 debug; /* def: 0 = minimal debug log messages */ int disable_hw_scan; /* def: 0 = use h/w scan */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c9fde0e..a5efb3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4309,20 +4309,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); - /*********************************** - * 7. Initialize Module Parameters - * **********************************/ - - /* Initialize module parameter values here */ - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (iwl3945_mod_params.disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO(priv, "Radio disabled.\n"); - } - - /*********************** - * 8. Setup Services + * 7. Setup Services * ********************/ spin_lock_irqsave(&priv->lock, flags); @@ -4350,7 +4338,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e iwl3945_setup_rx_handlers(priv); /********************************* - * 9. Setup and Register mac80211 + * 8. Setup and Register mac80211 * *******************************/ iwl_enable_interrupts(priv); @@ -4528,8 +4516,6 @@ MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(disable, iwl3945_mod_params.disable, int, 0444); -MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])\n"); -- cgit v0.10.2 From 0cf4c01ebe2ccf4487fe9301bab905365dca06c3 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Mon, 20 Apr 2009 14:37:04 -0700 Subject: iwlwifi: allow config if device not ready Allow user to config the device all the time but only allow commiting these changes to card if the card is up and running. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index bf7ad51..3dec2d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2474,12 +2474,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&priv->mutex); - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - ret = -EIO; - goto out; - } - IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", conf->channel->hw_value, changed); @@ -2574,6 +2568,11 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto out; } + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + goto out; + } + if (scan_active) goto out; -- cgit v0.10.2 From 29b4a4f7c7b588b5568edd0da42f38623b81fc66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Apr 2009 00:30:49 +0200 Subject: mac80211: fix IBSS code to not sleep while atomic With the RCU locking here we sleep while in an atomic context, since we can sleep just use mutex locking for the interface list instead of RCU. Sorry, seems I didn't get that in my UML test. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 4f7a545..6030e00 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -784,14 +784,14 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_ADHOC) continue; sdata->u.ibss.last_scan_completed = jiffies; ieee80211_sta_find_ibss(sdata); } - rcu_read_unlock(); + mutex_unlock(&local->iflist_mtx); } ieee80211_rx_result -- cgit v0.10.2 From caa6dfadebee2098e9c5ece1d5efae96a6926d0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Apr 2009 10:55:10 +0200 Subject: rndis_wlan: make some symbols static sparse complains, correctly, about these: drivers/net/wireless/rndis_wlan.c:418:21: warning: symbol 'rndis_config_ops' was not declared. Should it be static? drivers/net/wireless/rndis_wlan.c:423:6: warning: symbol 'rndis_wiphy_privid' was not declared. Should it be static? Fix that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 109e603..4b11cea 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -415,12 +415,12 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request); -struct cfg80211_ops rndis_config_ops = { +static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, }; -void *rndis_wiphy_privid = &rndis_wiphy_privid; +static void *rndis_wiphy_privid = &rndis_wiphy_privid; static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; -- cgit v0.10.2 From 8d4d99ae89a8845a1d63b0529dd98da28dc0ff65 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 21 Apr 2009 19:48:07 +0300 Subject: rndis_wlan: fix initialization order for workqueue&workers rndis_wext_link_change() might be called from rndis_command() at initialization stage and priv->workqueue/priv->work have not been initialized yet. This causes invalid opcode at rndis_wext_bind on some brands of bcm4320. Fix by initializing workqueue/workers in rndis_wext_bind() before rndis_command is used. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 4b11cea..9ef547d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2384,6 +2384,12 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) mutex_init(&priv->command_lock); spin_lock_init(&priv->stats_lock); + /* because rndis_command() sleeps we need to use workqueue */ + priv->workqueue = create_singlethread_workqueue("rndis_wlan"); + INIT_WORK(&priv->work, rndis_wext_worker); + INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); + INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); + /* try bind rndis_host */ retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS); if (retval < 0) @@ -2454,17 +2460,18 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) disassociate(usbdev, 1); netif_carrier_off(usbdev->net); - /* because rndis_command() sleeps we need to use workqueue */ - priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); queue_delayed_work(priv->workqueue, &priv->stats_work, round_jiffies_relative(STATS_UPDATE_JIFFIES)); - INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); - INIT_WORK(&priv->work, rndis_wext_worker); return 0; fail: + cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->scan_work); + cancel_work_sync(&priv->work); + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + kfree(priv); return retval; } -- cgit v0.10.2 From eb1a685e07310b5137c561e25ab738292db2c8a5 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 21 Apr 2009 19:48:15 +0300 Subject: rndis_wlan: free priv correctly when rndis_wext_bind fails Private structure is allocated by wiphy_new now, so use wiphy_free instead of kfree. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9ef547d..52fc647 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2449,8 +2449,8 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) set_wiphy_dev(wiphy, &usbdev->udev->dev); if (wiphy_register(wiphy)) { - wiphy_free(wiphy); - return -ENODEV; + retval = -ENODEV; + goto fail; } set_default_iw_params(usbdev); @@ -2472,7 +2472,7 @@ fail: flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); - kfree(priv); + wiphy_free(wiphy); return retval; } -- cgit v0.10.2 From 1d4df3a50f40a731fc03c86a76535ed141b0e4bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Apr 2009 11:25:43 +0200 Subject: mac80211: fix variable truncation on 32-bit Stephen Rothwell reported these warnings from a 32-bit build: net/mac80211/mlme.c:1771: warning: left shift count >= width of type net/mac80211/mlme.c:1772: warning: left shift count >= width of type net/mac80211/mlme.c:1773: warning: left shift count >= width of type net/mac80211/mlme.c:1774: warning: left shift count >= width of type net/mac80211/mlme.c:1775: warning: left shift count >= width of type This shows a bug in my code -- BIT(X) uses just "1 << X" which means a 32-bit integer on 32-bit platforms, but the code here needs a u64 on all platforms. Fix this by using "1ULL << X" instead of BIT(X). Thanks Stephen! Reported-by: Stephen Rothwell Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1b0b7aa..e819c02 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1743,12 +1743,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, * look out for other vendor IEs. */ static const u64 care_about_ies = - BIT(WLAN_EID_COUNTRY) | - BIT(WLAN_EID_ERP_INFO) | - BIT(WLAN_EID_CHANNEL_SWITCH) | - BIT(WLAN_EID_PWR_CONSTRAINT) | - BIT(WLAN_EID_HT_CAPABILITY) | - BIT(WLAN_EID_HT_INFORMATION); + (1ULL << WLAN_EID_COUNTRY) | + (1ULL << WLAN_EID_ERP_INFO) | + (1ULL << WLAN_EID_CHANNEL_SWITCH) | + (1ULL << WLAN_EID_PWR_CONSTRAINT) | + (1ULL << WLAN_EID_HT_CAPABILITY) | + (1ULL << WLAN_EID_HT_INFORMATION); static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, -- cgit v0.10.2 From e255d5eb2b478eec1416b46aea03798b64355402 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Apr 2009 12:40:07 +0200 Subject: mac80211: remove IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT Just setting IEEE80211_CONF_CHANGE_PS should be sufficient for changes in the power saving things. The driver already tells us whether it wants notification of dynps via the "have dynps support" hw flag. Signed-off-by: Johannes Berg Reviewed-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d968691..183956e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -532,8 +532,7 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed - * @IEEE80211_CONF_CHANGE_PS: the PS flag changed - * @IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT: the dynamic PS timeout changed + * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed * @IEEE80211_CONF_CHANGE_POWER: the TX power changed * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed @@ -544,10 +543,9 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), - IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT = BIT(5), - IEEE80211_CONF_CHANGE_POWER = BIT(6), - IEEE80211_CONF_CHANGE_CHANNEL = BIT(7), - IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(8), + IEEE80211_CONF_CHANGE_POWER = BIT(5), + IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), + IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), }; /** diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 1eb6d86..1a649da 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -622,8 +622,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, conf->dynamic_ps_timeout = timeout; if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) - ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); ieee80211_recalc_ps(local, -1); -- cgit v0.10.2 From 8e30bc55de98c000b0b836cb42525c82f605f191 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Apr 2009 17:45:38 +0200 Subject: nl80211: allow configuring IBSS beacon interval Make the JOIN_IBSS command look at the beacon interval attribute to see if the user requested a specific beacon interval, if not default to 100 TU (wext too). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index dc9d9ec..b6a48dd 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -230,7 +230,9 @@ * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those * should be fixed rather than automatically determined. Can only be * executed on a network interface that is UP, and fixed BSSID/FREQ - * may be rejected. + * may be rejected. Another optional parameter is the beacon interval, + * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not + * given defaults to 100 TU (102.4ms). * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is * determined by the network interface. * diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 54bc69c..7f7b53b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -733,6 +733,7 @@ struct cfg80211_disassoc_request { * IBSSs to join on other channels. * @ie: information element(s) to include in the beacon * @ie_len: length of that + * @beacon_interval: beacon interval to use */ struct cfg80211_ibss_params { u8 *ssid; @@ -740,6 +741,7 @@ struct cfg80211_ibss_params { struct ieee80211_channel *channel; u8 *ie; u8 ssid_len, ie_len; + u16 beacon_interval; bool channel_fixed; }; diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index b5c601e..3c38afa 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -116,6 +116,9 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, enum ieee80211_band band; int i; + if (!wdev->wext.beacon_interval) + wdev->wext.beacon_interval = 100; + /* try to find an IBSS channel if none requested ... */ if (!wdev->wext.channel) { for (band = 0; band < IEEE80211_NUM_BANDS; band++) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 97bb5c8..3b21b3e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3159,6 +3159,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + memset(&ibss, 0, sizeof(ibss)); + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3167,6 +3169,15 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) !nla_len(info->attrs[NL80211_ATTR_SSID])) return -EINVAL; + ibss.beacon_interval = 100; + + if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { + ibss.beacon_interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) + return -EINVAL; + } + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -3189,7 +3200,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) } wiphy = &drv->wiphy; - memset(&ibss, 0, sizeof(ibss)); if (info->attrs[NL80211_ATTR_MAC]) ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); -- cgit v0.10.2 From 04fe20372e70685d9f15966216cdffd3795fe590 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Apr 2009 18:44:37 +0200 Subject: mac80211: calculate maximum sleep interval The maximum sleep interval, for powersave purposes, is determined by the DTIM period (it may not be larger) and the required networking latency (it must be small enough to fulfil those constraints). This makes mac80211 calculate the maximum sleep interval based on those constraints, and pass it to the driver. Then the driver should instruct the device to sleep at most that long. Note that the device is responsible for aligning the maximum sleep interval between DTIMs, we make sure it's not longer but it needs to make sure it's between them. Also, group some powersave documentation together and make it more explicit that we support managed mode only, and no IBSS powersaving (yet). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 183956e..446dbf7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -517,7 +517,7 @@ struct ieee80211_rx_status { * Flags to define PHY configuration options * * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) - * @IEEE80211_CONF_PS: Enable 802.11 power save mode + * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only) */ enum ieee80211_conf_flags { IEEE80211_CONF_RADIOTAP = (1<<0), @@ -553,14 +553,26 @@ enum ieee80211_conf_changed { * * This struct indicates how the driver shall configure the hardware. * + * @flags: configuration flags defined above + * * @radio_enabled: when zero, driver is required to switch off the radio. * @beacon_int: beacon interval (TODO make interface config) + * * @listen_interval: listen interval in units of beacon interval - * @flags: configuration flags defined above + * @max_sleep_interval: the maximum number of beacon intervals to sleep for + * before checking the beacon for a TIM bit (managed mode only); this + * value will be only achievable between DTIM frames, the hardware + * needs to check for the multicast traffic bit in DTIM beacons. + * This variable is valid only when the CONF_PS flag is set. + * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the + * powersave documentation below. This variable is valid only when + * the CONF_PS flag is set. + * * @power_level: requested transmit power (in dBm) - * @dynamic_ps_timeout: dynamic powersave timeout (in ms) + * * @channel: the channel to tune to * @channel_type: the channel (HT) type + * * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, * but actually means the number of transmissions not the number of retries @@ -572,6 +584,7 @@ struct ieee80211_conf { int beacon_int; u32 flags; int power_level, dynamic_ps_timeout; + int max_sleep_interval; u16 listen_interval; bool radio_enabled; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e819c02..df27c68 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -545,10 +545,19 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) beaconint_us = ieee80211_tu_to_usec( found->vif.bss_conf.beacon_int); - if (beaconint_us > latency) + if (beaconint_us > latency) { local->ps_sdata = NULL; - else + } else { + u8 dtimper = found->vif.bss_conf.dtim_period; + int maxslp = 1; + + if (dtimper > 1) + maxslp = min_t(int, dtimper, + latency / beaconint_us); + + local->hw.conf.max_sleep_interval = maxslp; local->ps_sdata = found; + } } else { local->ps_sdata = NULL; } @@ -851,8 +860,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, bss_info_changed); /* will be same as sdata */ - if (local->ps_sdata) - ieee80211_enable_ps(local, sdata); + if (local->ps_sdata) { + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); + } netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); -- cgit v0.10.2 From ff2ba188fc5eaae529cb2ef9b127c3ca2a7df4b9 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 22 Apr 2009 13:27:08 -0400 Subject: rndis_wlan: select CFG80211 in Kconfig Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 11c2481..2d8434f 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -337,6 +337,7 @@ config USB_NET_RNDIS_WLAN select USB_NET_CDCETHER select USB_NET_RNDIS_HOST select WIRELESS_EXT + select CFG80211 ---help--- This is a driver for wireless RNDIS devices. These are USB based adapters found in devices such as: -- cgit v0.10.2 From 1965c85331ed29dc4fd32479ff31663e3e9a518f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 22 Apr 2009 21:38:25 +0300 Subject: nl80211: Add event for authentication/association timeout SME needs to be notified when the authentication or association attempt times out and MLME has stopped processing in order to allow the SME to decide what to do next. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index b6a48dd..e9fd13a 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -203,8 +203,12 @@ * frame, i.e., it was for the local STA and was received in correct * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the * MLME SAP interface (kernel providing MLME, userspace SME). The - * included NL80211_ATTR_FRAME attribute contains the management frame - * (including both the header and frame body, but not FCS). + * included %NL80211_ATTR_FRAME attribute contains the management frame + * (including both the header and frame body, but not FCS). This event is + * also used to indicate if the authentication attempt timed out. In that + * case the %NL80211_ATTR_FRAME attribute is replaced with a + * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which + * pending authentication timed out). * @NL80211_CMD_ASSOCIATE: association request and notification; like * NL80211_CMD_AUTHENTICATE but for Association and Reassociation * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request, @@ -487,6 +491,9 @@ enum nl80211_commands { * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look * for other networks on different channels * + * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this + * is used, e.g., with %NL80211_CMD_AUTHENTICATE event + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -587,6 +594,8 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_FRAG_THRESHOLD, NL80211_ATTR_WIPHY_RTS_THRESHOLD, + NL80211_ATTR_TIMED_OUT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7f7b53b..b8a7676 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1475,22 +1475,40 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); * @len: length of the frame data * * This function is called whenever an authentication has been processed in - * station mode. + * station mode. The driver is required to call either this function or + * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth() + * call. */ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); /** + * cfg80211_send_auth_timeout - notification of timed out authentication + * @dev: network device + * @addr: The MAC address of the device with which the authentication timed out + */ +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); + +/** * cfg80211_send_rx_assoc - notification of processed association * @dev: network device * @buf: (re)association response frame (header + body) * @len: length of the frame data * * This function is called whenever a (re)association response has been - * processed in station mode. + * processed in station mode. The driver is required to call either this + * function or cfg80211_send_assoc_timeout() to indicate the result of + * cfg80211_ops::assoc() call. */ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); /** + * cfg80211_send_assoc_timeout - notification of timed out association + * @dev: network device + * @addr: The MAC address of the device with which the association timed out + */ +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); + +/** * cfg80211_send_deauth - notification of processed deauthentication * @dev: network device * @buf: deauthentication frame (header + body) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index df27c68..3610c11 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -932,7 +932,7 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) " timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_sta_send_apinfo(sdata); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); @@ -1115,7 +1115,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) " timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_sta_send_apinfo(sdata); + cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 1407244..4218436 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -44,6 +44,33 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) } EXPORT_SYMBOL(cfg80211_send_disassoc); +static void cfg80211_wext_disconnected(struct net_device *dev) +{ +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof(wrqu)); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} + +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + nl80211_send_auth_timeout(rdev, dev, addr); + cfg80211_wext_disconnected(dev); +} +EXPORT_SYMBOL(cfg80211_send_auth_timeout); + +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + nl80211_send_assoc_timeout(rdev, dev, addr); + cfg80211_wext_disconnected(dev); +} +EXPORT_SYMBOL(cfg80211_send_assoc_timeout); + void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, enum nl80211_key_type key_type, int key_id, const u8 *tsc) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3b21b3e..b1fc982 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -121,6 +121,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, + [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, }; /* IE validation */ @@ -3695,6 +3696,54 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, NL80211_CMD_DISASSOCIATE); } +void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int cmd, + const u8 *addr) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr) +{ + nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, + addr); +} + +void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr) +{ + nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr); +} + void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, gfp_t gfp) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 17d2d8b..5c12ad1 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -23,6 +23,12 @@ extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev, extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len); +extern void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr); +extern void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr); extern void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, -- cgit v0.10.2 From 42e1b4c2c6c823ae26e64c557addf5329a7735b7 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 21 Apr 2009 23:26:20 +0000 Subject: iucv: provide second per-cpu IUCV command parameter block Some of the IUCV commands can be invoked in interrupt context. Those commands need a different per-cpu IUCV command parameter block, otherwise they might overwrite an IUCV command parameter of a not yet finished IUCV command invocation in process context. Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index a35240f..fcf4040 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -280,6 +280,7 @@ union iucv_param { * Anchor for per-cpu IUCV command parameter block. */ static union iucv_param *iucv_param[NR_CPUS]; +static union iucv_param *iucv_param_irq[NR_CPUS]; /** * iucv_call_b2f0 @@ -358,7 +359,7 @@ static void iucv_allow_cpu(void *data) * 0x10 - Flag to allow priority message completion interrupts * 0x08 - Flag to allow IUCV control interrupts */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETMASK, parm); @@ -379,7 +380,7 @@ static void iucv_block_cpu(void *data) union iucv_param *parm; /* Disable all iucv interrupts. */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); iucv_call_b2f0(IUCV_SETMASK, parm); @@ -403,7 +404,7 @@ static void iucv_declare_cpu(void *data) return; /* Declare interrupt buffer. */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]); rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); @@ -460,7 +461,7 @@ static void iucv_retrieve_cpu(void *data) iucv_block_cpu(NULL); /* Retrieve interrupt buffer. */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); /* Clear indication that an iucv buffer exists for this cpu. */ @@ -574,11 +575,22 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self, iucv_irq_data[cpu] = NULL; return NOTIFY_BAD; } + iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_param_irq[cpu]) { + kfree(iucv_param[cpu]); + iucv_param[cpu] = NULL; + kfree(iucv_irq_data[cpu]); + iucv_irq_data[cpu] = NULL; + return NOTIFY_BAD; + } break; case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: + kfree(iucv_param_irq[cpu]); + iucv_param_irq[cpu] = NULL; kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); @@ -625,7 +637,7 @@ static int iucv_sever_pathid(u16 pathid, u8 userdata[16]) { union iucv_param *parm; - parm = iucv_param[smp_processor_id()]; + parm = iucv_param_irq[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); @@ -918,10 +930,8 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) if (iucv_active_cpu != smp_processor_id()) spin_lock_bh(&iucv_table_lock); rc = iucv_sever_pathid(path->pathid, userdata); - if (!rc) { - iucv_path_table[path->pathid] = NULL; - list_del_init(&path->list); - } + iucv_path_table[path->pathid] = NULL; + list_del_init(&path->list); if (iucv_active_cpu != smp_processor_id()) spin_unlock_bh(&iucv_table_lock); preempt_enable(); @@ -1413,7 +1423,7 @@ static void iucv_path_severed(struct iucv_irq_data *data) else { iucv_sever_pathid(path->pathid, NULL); iucv_path_table[path->pathid] = NULL; - list_del_init(&path->list); + list_del(&path->list); iucv_path_free(path); } } @@ -1717,6 +1727,13 @@ static int __init iucv_init(void) rc = -ENOMEM; goto out_free; } + iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_param_irq[cpu]) { + rc = -ENOMEM; + goto out_free; + } + } rc = register_hotcpu_notifier(&iucv_cpu_notifier); if (rc) @@ -1734,6 +1751,8 @@ out_cpu: unregister_hotcpu_notifier(&iucv_cpu_notifier); out_free: for_each_possible_cpu(cpu) { + kfree(iucv_param_irq[cpu]); + iucv_param_irq[cpu] = NULL; kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); @@ -1764,6 +1783,8 @@ static void __exit iucv_exit(void) spin_unlock_irq(&iucv_queue_lock); unregister_hotcpu_notifier(&iucv_cpu_notifier); for_each_possible_cpu(cpu) { + kfree(iucv_param_irq[cpu]); + iucv_param_irq[cpu] = NULL; kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); -- cgit v0.10.2 From af88b52def76679c8c5bcdbed199fbe62b6a16d4 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 21 Apr 2009 23:26:21 +0000 Subject: af_iucv: sync sk shutdown flag if iucv path is quiesced If the af_iucv communication partner quiesces the path to shutdown its receive direction, provide a quiesce callback implementation to shutdown the (local) send direction. This ensures that both sides are synchronized. Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 49e7865..6cf02b4 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -54,6 +54,7 @@ static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]); static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); +static void iucv_callback_shutdown(struct iucv_path *, u8 ipuser[16]); static struct iucv_sock_list iucv_sk_list = { .lock = __RW_LOCK_UNLOCKED(iucv_sk_list.lock), @@ -65,7 +66,8 @@ static struct iucv_handler af_iucv_handler = { .path_complete = iucv_callback_connack, .path_severed = iucv_callback_connrej, .message_pending = iucv_callback_rx, - .message_complete = iucv_callback_txdone + .message_complete = iucv_callback_txdone, + .path_quiesced = iucv_callback_shutdown, }; static inline void high_nmcpy(unsigned char *dst, char *src) @@ -1196,6 +1198,21 @@ static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) sk->sk_state_change(sk); } +/* called if the other communication side shuts down its RECV direction; + * in turn, the callback sets SEND_SHUTDOWN to disable sending of data. + */ +static void iucv_callback_shutdown(struct iucv_path *path, u8 ipuser[16]) +{ + struct sock *sk = path->private; + + bh_lock_sock(sk); + if (sk->sk_state != IUCV_CLOSED) { + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + } + bh_unlock_sock(sk); +} + static struct proto_ops iucv_sock_ops = { .family = PF_IUCV, .owner = THIS_MODULE, -- cgit v0.10.2 From 9d5c5d8f4105dc56ec10864b195dd1714f282c22 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 21 Apr 2009 23:26:22 +0000 Subject: af_iucv: add sockopt() to enable/disable use of IPRM_DATA msgs Provide the socket operations getsocktopt() and setsockopt() to enable/disable sending of data in the parameter list of IUCV messages. The patch sets respective flag only. Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/include/linux/socket.h b/include/linux/socket.h index 42a0396..d2310cb 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -303,6 +303,7 @@ struct ucred { #define SOL_BLUETOOTH 274 #define SOL_PNPIPE 275 #define SOL_RDS 276 +#define SOL_IUCV 277 /* IPX options */ #define IPX_TYPE 1 diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index 85f80ea..78a7276 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -73,8 +73,12 @@ struct iucv_sock { struct sk_buff_head backlog_skb_q; struct sock_msg_q message_q; unsigned int send_tag; + u8 flags; }; +/* iucv socket options (SOL_IUCV) */ +#define SO_IPRMDATA_MSG 0x0080 /* send/recv IPRM_DATA msgs */ + struct iucv_sock_list { struct hlist_head head; rwlock_t lock; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 6cf02b4..b7c40c9 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -32,7 +32,7 @@ #define CONFIG_IUCV_SOCK_DEBUG 1 #define IPRMDATA 0x80 -#define VERSION "1.0" +#define VERSION "1.1" static char iucv_userid[80]; @@ -226,6 +226,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) spin_lock_init(&iucv_sk(sk)->message_q.lock); skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q); iucv_sk(sk)->send_tag = 0; + iucv_sk(sk)->flags = 0; sk->sk_destruct = iucv_sock_destruct; sk->sk_sndtimeo = IUCV_CONN_TIMEOUT; @@ -1003,6 +1004,78 @@ static int iucv_sock_release(struct socket *sock) return err; } +/* getsockopt and setsockopt */ +static int iucv_sock_setsockopt(struct socket *sock, int level, int optname, + char __user *optval, int optlen) +{ + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + int val; + int rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (get_user(val, (int __user *) optval)) + return -EFAULT; + + rc = 0; + + lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + if (val) + iucv->flags |= IUCV_IPRMDATA; + else + iucv->flags &= ~IUCV_IPRMDATA; + break; + default: + rc = -ENOPROTOOPT; + break; + } + release_sock(sk); + + return rc; +} + +static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) +{ + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + int val, len; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; + + if (get_user(len, optlen)) + return -EFAULT; + + if (len < 0) + return -EINVAL; + + len = min_t(unsigned int, len, sizeof(int)); + + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + + /* Callback wrappers - called from iucv base support */ static int iucv_callback_connreq(struct iucv_path *path, u8 ipvmid[8], u8 ipuser[16]) @@ -1229,8 +1302,8 @@ static struct proto_ops iucv_sock_ops = { .mmap = sock_no_mmap, .socketpair = sock_no_socketpair, .shutdown = iucv_sock_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt + .setsockopt = iucv_sock_setsockopt, + .getsockopt = iucv_sock_getsockopt, }; static struct net_proto_family iucv_sock_family_ops = { -- cgit v0.10.2 From b8942e3b6c4b35dda5e8ca75aec5e2f027fe39a9 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 21 Apr 2009 23:26:23 +0000 Subject: af_iucv: Support data in IUCV msg parameter lists (IPRMDATA) The patch allows to send and receive data in the parameter list of an iucv message. The parameter list is an arry of 8 bytes that are used by af_iucv as follows: 0..6 7 bytes for socket data and 7 1 byte to store the data length. Instead of storing the data length directly, the difference between 0xFF and the data length is used. This convention does not interfere with the existing use of PRM messages for shutting down the send direction of an AF_IUCV socket (shutdown() operation). Data lenghts greater than 7 (or PRM message byte 8 is less than 0xF8) denotes to special messages. Currently, the special SEND_SHUTDOWN message is supported only. To use IPRM messages, both communicators must set the IUCV_IPRMDATA flag during path negotiation, i.e. in iucv_connect() and path_pending(). To be compatible to older af_iucv implementations, sending PRM messages is controlled by the socket option SO_IPRMDATA_MSG. Receiving PRM messages does not depend on the socket option (but requires the IUCV_IPRMDATA path flag to be set). Sending/Receiving data in the parameter list improves performance for small amounts of data by reducing message_completion() interrupts and memory copy operations. Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index b7c40c9..5fc077e 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -29,9 +29,6 @@ #include #include -#define CONFIG_IUCV_SOCK_DEBUG 1 - -#define IPRMDATA 0x80 #define VERSION "1.1" static char iucv_userid[80]; @@ -44,6 +41,10 @@ static struct proto iucv_proto = { .obj_size = sizeof(struct iucv_sock), }; +/* special AF_IUCV IPRM messages */ +static const u8 iprm_shutdown[8] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + static void iucv_sock_kill(struct sock *sk); static void iucv_sock_close(struct sock *sk); @@ -80,6 +81,37 @@ static inline void low_nmcpy(unsigned char *dst, char *src) memcpy(&dst[8], src, 8); } +/** + * iucv_msg_length() - Returns the length of an iucv message. + * @msg: Pointer to struct iucv_message, MUST NOT be NULL + * + * The function returns the length of the specified iucv message @msg of data + * stored in a buffer and of data stored in the parameter list (PRMDATA). + * + * For IUCV_IPRMDATA, AF_IUCV uses the following convention to transport socket + * data: + * PRMDATA[0..6] socket data (max 7 bytes); + * PRMDATA[7] socket data length value (len is 0xff - PRMDATA[7]) + * + * The socket data length is computed by substracting the socket data length + * value from 0xFF. + * If the socket data len is greater 7, then PRMDATA can be used for special + * notifications (see iucv_sock_shutdown); and further, + * if the socket data len is > 7, the function returns 8. + * + * Use this function to allocate socket buffers to store iucv message data. + */ +static inline size_t iucv_msg_length(struct iucv_message *msg) +{ + size_t datalen; + + if (msg->flags & IUCV_IPRMDATA) { + datalen = 0xff - msg->rmmsg[7]; + return (datalen < 8) ? datalen : 8; + } + return msg->length; +} + /* Timers */ static void iucv_sock_timeout(unsigned long arg) { @@ -487,7 +519,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, iucv = iucv_sk(sk); /* Create path. */ iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT, - IPRMDATA, GFP_KERNEL); + IUCV_IPRMDATA, GFP_KERNEL); if (!iucv->path) { err = -ENOMEM; goto done; @@ -521,8 +553,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, } if (sk->sk_state == IUCV_DISCONN) { - release_sock(sk); - return -ECONNREFUSED; + err = -ECONNREFUSED; } if (err) { @@ -636,6 +667,30 @@ static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr, return 0; } +/** + * iucv_send_iprm() - Send socket data in parameter list of an iucv message. + * @path: IUCV path + * @msg: Pointer to a struct iucv_message + * @skb: The socket data to send, skb->len MUST BE <= 7 + * + * Send the socket data in the parameter list in the iucv message + * (IUCV_IPRMDATA). The socket data is stored at index 0 to 6 in the parameter + * list and the socket data len at index 7 (last byte). + * See also iucv_msg_length(). + * + * Returns the error code from the iucv_message_send() call. + */ +static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg, + struct sk_buff *skb) +{ + u8 prmdata[8]; + + memcpy(prmdata, (void *) skb->data, skb->len); + prmdata[7] = 0xff - (u8) skb->len; + return iucv_message_send(path, msg, IUCV_IPRMDATA, 0, + (void *) prmdata, 8); +} + static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { @@ -677,8 +732,29 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, txmsg.tag = iucv->send_tag++; memcpy(skb->cb, &txmsg.tag, 4); skb_queue_tail(&iucv->send_skb_q, skb); - err = iucv_message_send(iucv->path, &txmsg, 0, 0, - (void *) skb->data, skb->len); + + if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags) + && skb->len <= 7) { + err = iucv_send_iprm(iucv->path, &txmsg, skb); + + /* on success: there is no message_complete callback + * for an IPRMDATA msg; remove skb from send queue */ + if (err == 0) { + skb_unlink(skb, &iucv->send_skb_q); + kfree_skb(skb); + } + + /* this error should never happen since the + * IUCV_IPRMDATA path flag is set... sever path */ + if (err == 0x15) { + iucv_path_sever(iucv->path, NULL); + skb_unlink(skb, &iucv->send_skb_q); + err = -EPIPE; + goto fail; + } + } else + err = iucv_message_send(iucv->path, &txmsg, 0, 0, + (void *) skb->data, skb->len); if (err) { if (err == 3) { user_id[8] = 0; @@ -744,19 +820,25 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, struct iucv_message *msg) { int rc; + unsigned int len; + + len = iucv_msg_length(msg); - if (msg->flags & IPRMDATA) { - skb->data = NULL; - skb->len = 0; + /* check for special IPRM messages (e.g. iucv_sock_shutdown) */ + if ((msg->flags & IUCV_IPRMDATA) && len > 7) { + if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) { + skb->data = NULL; + skb->len = 0; + } } else { - rc = iucv_message_receive(path, msg, 0, skb->data, - msg->length, NULL); + rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA, + skb->data, len, NULL); if (rc) { kfree_skb(skb); return; } if (skb->truesize >= sk->sk_rcvbuf / 4) { - rc = iucv_fragment_skb(sk, skb, msg->length); + rc = iucv_fragment_skb(sk, skb, len); kfree_skb(skb); skb = NULL; if (rc) { @@ -767,7 +849,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, } else { skb_reset_transport_header(skb); skb_reset_network_header(skb); - skb->len = msg->length; + skb->len = len; } } @@ -782,7 +864,7 @@ static void iucv_process_message_q(struct sock *sk) struct sock_msg_q *p, *n; list_for_each_entry_safe(p, n, &iucv->message_q.list, list) { - skb = alloc_skb(p->msg.length, GFP_ATOMIC | GFP_DMA); + skb = alloc_skb(iucv_msg_length(&p->msg), GFP_ATOMIC | GFP_DMA); if (!skb) break; iucv_process_message(sk, skb, p->path, &p->msg); @@ -928,7 +1010,6 @@ static int iucv_sock_shutdown(struct socket *sock, int how) struct iucv_sock *iucv = iucv_sk(sk); struct iucv_message txmsg; int err = 0; - u8 prmmsg[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; how++; @@ -950,7 +1031,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how) txmsg.class = 0; txmsg.tag = 0; err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0, - (void *) prmmsg, 8); + (void *) iprm_shutdown, 8); if (err) { switch (err) { case 1: @@ -1196,11 +1277,11 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) goto save_message; len = atomic_read(&sk->sk_rmem_alloc); - len += msg->length + sizeof(struct sk_buff); + len += iucv_msg_length(msg) + sizeof(struct sk_buff); if (len > sk->sk_rcvbuf) goto save_message; - skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA); + skb = alloc_skb(iucv_msg_length(msg), GFP_ATOMIC | GFP_DMA); if (!skb) goto save_message; diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index fcf4040..61e8038 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -1388,6 +1388,8 @@ static void iucv_path_complete(struct iucv_irq_data *data) struct iucv_path_complete *ipc = (void *) data; struct iucv_path *path = iucv_path_table[ipc->ippathid]; + if (path) + path->flags = ipc->ipflags1; if (path && path->handler && path->handler->path_complete) path->handler->path_complete(path, ipc->ipuser); } -- cgit v0.10.2 From 44b1e6b5f9a93cc2ba024e09cf137d5f1b5f8426 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 21 Apr 2009 23:26:24 +0000 Subject: af_iucv: Modify iucv msg target class using control msghdr Allow 'classification' of socket data that is sent or received over an af_iucv socket. For classification of data, the target class of an (native) iucv message is used. This patch provides the cmsg interface for iucv_sock_recvmsg() and iucv_sock_sendmsg(). Applications can use the msg_control field of struct msghdr to set or get the target class as a "socket control message" (SCM/CMSG). Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index 78a7276..b57739e 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -79,6 +79,9 @@ struct iucv_sock { /* iucv socket options (SOL_IUCV) */ #define SO_IPRMDATA_MSG 0x0080 /* send/recv IPRM_DATA msgs */ +/* iucv related control messages (scm) */ +#define SCM_IUCV_TRGCLS 0x0001 /* target class control message */ + struct iucv_sock_list { struct hlist_head head; rwlock_t lock; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 5fc077e..47c5c8d 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -45,6 +45,15 @@ static struct proto iucv_proto = { static const u8 iprm_shutdown[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +#define TRGCLS_SIZE (sizeof(((struct iucv_message *)0)->class)) + +/* macros to set/get socket control buffer at correct offset */ +#define CB_TAG(skb) ((skb)->cb) /* iucv message tag */ +#define CB_TAG_LEN (sizeof(((struct iucv_message *) 0)->tag)) +#define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */ +#define CB_TRGCLS_LEN (TRGCLS_SIZE) + + static void iucv_sock_kill(struct sock *sk); static void iucv_sock_close(struct sock *sk); @@ -698,6 +707,8 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct iucv_sock *iucv = iucv_sk(sk); struct sk_buff *skb; struct iucv_message txmsg; + struct cmsghdr *cmsg; + int cmsg_done; char user_id[9]; char appl_id[9]; int err; @@ -717,6 +728,48 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } if (sk->sk_state == IUCV_CONNECTED) { + /* initialize defaults */ + cmsg_done = 0; /* check for duplicate headers */ + txmsg.class = 0; + + /* iterate over control messages */ + for (cmsg = CMSG_FIRSTHDR(msg); cmsg; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + + if (!CMSG_OK(msg, cmsg)) { + err = -EINVAL; + goto out; + } + + if (cmsg->cmsg_level != SOL_IUCV) + continue; + + if (cmsg->cmsg_type & cmsg_done) { + err = -EINVAL; + goto out; + } + cmsg_done |= cmsg->cmsg_type; + + switch (cmsg->cmsg_type) { + case SCM_IUCV_TRGCLS: + if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) { + err = -EINVAL; + goto out; + } + + /* set iucv message target class */ + memcpy(&txmsg.class, + (void *) CMSG_DATA(cmsg), TRGCLS_SIZE); + + break; + + default: + err = -EINVAL; + goto out; + break; + } + } + if (!(skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) @@ -727,10 +780,9 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, goto fail; } - txmsg.class = 0; - memcpy(&txmsg.class, skb->data, skb->len >= 4 ? 4 : skb->len); + /* increment and save iucv message tag for msg_completion cbk */ txmsg.tag = iucv->send_tag++; - memcpy(skb->cb, &txmsg.tag, 4); + memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN); skb_queue_tail(&iucv->send_skb_q, skb); if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags) @@ -801,6 +853,10 @@ static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len) if (!nskb) return -ENOMEM; + /* copy target class to control buffer of new skb */ + memcpy(CB_TRGCLS(nskb), CB_TRGCLS(skb), CB_TRGCLS_LEN); + + /* copy data fragment */ memcpy(nskb->data, skb->data + copied, size); copied += size; dataleft -= size; @@ -824,6 +880,10 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, len = iucv_msg_length(msg); + /* store msg target class in the second 4 bytes of skb ctrl buffer */ + /* Note: the first 4 bytes are reserved for msg tag */ + memcpy(CB_TRGCLS(skb), &msg->class, CB_TRGCLS_LEN); + /* check for special IPRM messages (e.g. iucv_sock_shutdown) */ if ((msg->flags & IUCV_IPRMDATA) && len > 7) { if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) { @@ -915,6 +975,17 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, len -= copied; + /* create control message to store iucv msg target class: + * get the trgcls from the control buffer of the skb due to + * fragmentation of original iucv message. */ + err = put_cmsg(msg, SOL_IUCV, SCM_IUCV_TRGCLS, + CB_TRGCLS_LEN, CB_TRGCLS(skb)); + if (err) { + if (!(flags & MSG_PEEK)) + skb_queue_head(&sk->sk_receive_queue, skb); + return err; + } + /* Mark read part of skb as used */ if (!(flags & MSG_PEEK)) { skb_pull(skb, copied); @@ -1316,7 +1387,7 @@ static void iucv_callback_txdone(struct iucv_path *path, spin_lock_irqsave(&list->lock, flags); while (list_skb != (struct sk_buff *)list) { - if (!memcmp(&msg->tag, list_skb->cb, 4)) { + if (!memcmp(&msg->tag, CB_TAG(list_skb), CB_TAG_LEN)) { this = list_skb; break; } -- cgit v0.10.2 From aa8e71f58ab8e01d63c33df40ff1bcb997c9df92 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 21 Apr 2009 23:26:25 +0000 Subject: af_iucv: Provide new socket type SOCK_SEQPACKET This patch provides the socket type SOCK_SEQPACKET in addition to SOCK_STREAM. AF_IUCV sockets of type SOCK_SEQPACKET supports an 1:1 mapping of socket read or write operations to complete IUCV messages. Socket data or IUCV message data is not fragmented as this is the case for SOCK_STREAM sockets. The intention is to help application developers who write applications or device drivers using native IUCV interfaces (Linux kernel or z/VM IUCV interfaces). Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 47c5c8d..95e38d3 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -289,11 +289,22 @@ static int iucv_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; - if (sock->type != SOCK_STREAM) - return -ESOCKTNOSUPPORT; + if (protocol && protocol != PF_IUCV) + return -EPROTONOSUPPORT; sock->state = SS_UNCONNECTED; - sock->ops = &iucv_sock_ops; + + switch (sock->type) { + case SOCK_STREAM: + sock->ops = &iucv_sock_ops; + break; + case SOCK_SEQPACKET: + /* currently, proto ops can handle both sk types */ + sock->ops = &iucv_sock_ops; + break; + default: + return -ESOCKTNOSUPPORT; + } sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL); if (!sk) @@ -504,11 +515,9 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND) return -EBADFD; - if (sk->sk_type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_SEQPACKET) return -EINVAL; - iucv = iucv_sk(sk); - if (sk->sk_state == IUCV_OPEN) { err = iucv_sock_autobind(sk); if (unlikely(err)) @@ -585,7 +594,10 @@ static int iucv_sock_listen(struct socket *sock, int backlog) lock_sock(sk); err = -EINVAL; - if (sk->sk_state != IUCV_BOUND || sock->type != SOCK_STREAM) + if (sk->sk_state != IUCV_BOUND) + goto done; + + if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) goto done; sk->sk_max_ack_backlog = backlog; @@ -720,6 +732,10 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; + /* SOCK_SEQPACKET: we do not support segmented records */ + if (sk->sk_type == SOCK_SEQPACKET && !(msg->msg_flags & MSG_EOR)) + return -EOPNOTSUPP; + lock_sock(sk); if (sk->sk_shutdown & SEND_SHUTDOWN) { @@ -770,6 +786,10 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } } + /* allocate one skb for each iucv message: + * this is fine for SOCK_SEQPACKET (unless we want to support + * segmented records using the MSG_EOR flag), but + * for SOCK_STREAM we might want to improve it in future */ if (!(skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) @@ -897,7 +917,11 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, kfree_skb(skb); return; } - if (skb->truesize >= sk->sk_rcvbuf / 4) { + /* we need to fragment iucv messages for SOCK_STREAM only; + * for SOCK_SEQPACKET, it is only relevant if we support + * record segmentation using MSG_EOR (see also recvmsg()) */ + if (sk->sk_type == SOCK_STREAM && + skb->truesize >= sk->sk_rcvbuf / 4) { rc = iucv_fragment_skb(sk, skb, len); kfree_skb(skb); skb = NULL; @@ -941,7 +965,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, int noblock = flags & MSG_DONTWAIT; struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk); - int target, copied = 0; + int target; + unsigned int copied, rlen; struct sk_buff *skb, *rskb, *cskb; int err = 0; @@ -963,7 +988,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, return err; } - copied = min_t(unsigned int, skb->len, len); + rlen = skb->len; /* real length of skb */ + copied = min_t(unsigned int, rlen, len); cskb = skb; if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) { @@ -973,7 +999,13 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, goto done; } - len -= copied; + /* SOCK_SEQPACKET: set MSG_TRUNC if recv buf size is too small */ + if (sk->sk_type == SOCK_SEQPACKET) { + if (copied < rlen) + msg->msg_flags |= MSG_TRUNC; + /* each iucv message contains a complete record */ + msg->msg_flags |= MSG_EOR; + } /* create control message to store iucv msg target class: * get the trgcls from the control buffer of the skb due to @@ -988,11 +1020,14 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, /* Mark read part of skb as used */ if (!(flags & MSG_PEEK)) { - skb_pull(skb, copied); - if (skb->len) { - skb_queue_head(&sk->sk_receive_queue, skb); - goto done; + /* SOCK_STREAM: re-queue skb if it contains unreceived data */ + if (sk->sk_type == SOCK_STREAM) { + skb_pull(skb, copied); + if (skb->len) { + skb_queue_head(&sk->sk_receive_queue, skb); + goto done; + } } kfree_skb(skb); @@ -1019,7 +1054,11 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, skb_queue_head(&sk->sk_receive_queue, skb); done: - return err ? : copied; + /* SOCK_SEQPACKET: return real length if MSG_TRUNC is set */ + if (sk->sk_type == SOCK_SEQPACKET && (flags & MSG_TRUNC)) + copied = rlen; + + return copied; } static inline unsigned int iucv_accept_poll(struct sock *parent) @@ -1281,7 +1320,7 @@ static int iucv_callback_connreq(struct iucv_path *path, } /* Create the new socket */ - nsk = iucv_sock_alloc(NULL, SOCK_STREAM, GFP_ATOMIC); + nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC); if (!nsk) { err = iucv_path_sever(path, user_data); iucv_path_free(path); -- cgit v0.10.2 From 802788bf90f78e7f248e78d4d0510bb00e976db8 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 21 Apr 2009 23:26:26 +0000 Subject: af_iucv: cleanup and refactor recvmsg() EFAULT handling If the skb cannot be copied to user iovec, always return -EFAULT. The skb is enqueued again, except MSG_PEEK flag is set, to allow user space applications to correct its iovec pointer. Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 95e38d3..f0dea1b 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -965,7 +965,6 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, int noblock = flags & MSG_DONTWAIT; struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk); - int target; unsigned int copied, rlen; struct sk_buff *skb, *rskb, *cskb; int err = 0; @@ -979,8 +978,6 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (flags & (MSG_OOB)) return -EOPNOTSUPP; - target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); - skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) { if (sk->sk_shutdown & RCV_SHUTDOWN) @@ -993,10 +990,9 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, cskb = skb; if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) { - skb_queue_head(&sk->sk_receive_queue, skb); - if (copied == 0) - return -EFAULT; - goto done; + if (!(flags & MSG_PEEK)) + skb_queue_head(&sk->sk_receive_queue, skb); + return -EFAULT; } /* SOCK_SEQPACKET: set MSG_TRUNC if recv buf size is too small */ -- cgit v0.10.2 From 09488e2e0fab14ebe41135f0d066cfe2c56ba9e5 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 21 Apr 2009 23:26:27 +0000 Subject: af_iucv: New socket option for setting IUCV MSGLIMITs The SO_MSGLIMIT socket option modifies the message limit for new IUCV communication paths. The message limit specifies the maximum number of outstanding messages that are allowed for connections. This setting can be lowered by z/VM when an IUCV connection is established. Expects an integer value in the range of 1 to 65535. The default value is 65535. The message limit must be set before calling connect() or listen() for sockets. If sockets are already connected or in state listen, changing the message limit is not supported. For reading the message limit value, unconnected sockets return the limit that has been set or the default limit. For connected sockets, the actual message limit is returned. The actual message limit is assigned by z/VM for each connection and it depends on IUCV MSGLIMIT authorizations specified for the z/VM guest virtual machine. Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index b57739e..21ee49f 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -74,10 +74,12 @@ struct iucv_sock { struct sock_msg_q message_q; unsigned int send_tag; u8 flags; + u16 msglimit; }; /* iucv socket options (SOL_IUCV) */ #define SO_IPRMDATA_MSG 0x0080 /* send/recv IPRM_DATA msgs */ +#define SO_MSGLIMIT 0x1000 /* get/set IUCV MSGLIMIT */ /* iucv related control messages (scm) */ #define SCM_IUCV_TRGCLS 0x0001 /* target class control message */ diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index f0dea1b..264c6b3 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -268,6 +268,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q); iucv_sk(sk)->send_tag = 0; iucv_sk(sk)->flags = 0; + iucv_sk(sk)->msglimit = IUCV_QUEUELEN_DEFAULT; sk->sk_destruct = iucv_sock_destruct; sk->sk_sndtimeo = IUCV_CONN_TIMEOUT; @@ -536,7 +537,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, iucv = iucv_sk(sk); /* Create path. */ - iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT, + iucv->path = iucv_path_alloc(iucv->msglimit, IUCV_IPRMDATA, GFP_KERNEL); if (!iucv->path) { err = -ENOMEM; @@ -1219,6 +1220,20 @@ static int iucv_sock_setsockopt(struct socket *sock, int level, int optname, else iucv->flags &= ~IUCV_IPRMDATA; break; + case SO_MSGLIMIT: + switch (sk->sk_state) { + case IUCV_OPEN: + case IUCV_BOUND: + if (val < 1 || val > (u16)(~0)) + rc = -EINVAL; + else + iucv->msglimit = val; + break; + default: + rc = -EINVAL; + break; + } + break; default: rc = -ENOPROTOOPT; break; @@ -1250,6 +1265,12 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, case SO_IPRMDATA_MSG: val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; break; + case SO_MSGLIMIT: + lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ + release_sock(sk); + break; default: return -ENOPROTOOPT; } @@ -1339,7 +1360,9 @@ static int iucv_callback_connreq(struct iucv_path *path, memcpy(nuser_data + 8, niucv->src_name, 8); ASCEBC(nuser_data + 8, 8); - path->msglim = IUCV_QUEUELEN_DEFAULT; + /* set message limit for path based on msglimit of accepting socket */ + niucv->msglimit = iucv->msglimit; + path->msglim = iucv->msglimit; err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk); if (err) { err = iucv_path_sever(path, user_data); -- cgit v0.10.2 From d93fe1a144c1a4312972bedbefc2213aa8b88612 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Thu, 23 Apr 2009 06:37:16 -0700 Subject: af_iucv: Fix merge. From: Ursula Braun net/iucv/af_iucv.c in net-next-2.6 is almost correct. 4 lines should still be deleted. These are the remaining changes: Signed-off-by: David S. Miller diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 0fc0008..a9b3a6f 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -982,8 +982,6 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (flags & (MSG_OOB)) return -EOPNOTSUPP; - target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); - /* receive/dequeue next skb: * the function understands MSG_PEEK and, thus, does not dequeue skb */ skb = skb_recv_datagram(sk, flags, noblock, &err); @@ -1429,8 +1427,6 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) iucv_process_message(sk, skb, path, msg); goto out_unlock; - return; - save_message: save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA); if (!save_msg) -- cgit v0.10.2 From ad8affd972a705a38e769859c50ee8e749b631da Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 24 Apr 2009 04:45:33 -0700 Subject: 8390p: fix build breakage Fix this build error caused by 362b76edb789 "8390p: Get rid of init_module/cleanup_module" drivers/net/8390p.c:94:19: error: invalid suffix "p_init_module" on integer constant drivers/net/8390p.c:94: error: expected identifier or '(' before numeric constant drivers/net/8390p.c:99:20: error: invalid suffix "p_cleanup_module" on integer constant Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index cacdd86..d225c29 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -91,15 +91,15 @@ void NS8390p_init(struct net_device *dev, int startp) } EXPORT_SYMBOL(NS8390p_init); -static int __init 8390p_init_module(void) +static int __init NS8390p_init_module(void) { return 0; } -static void __exit 8390p_cleanup_module(void) +static void __exit NS8390p_cleanup_module(void) { } -module_init(8390p_init_module); -module_exit(8390p_cleanup_module); +module_init(NS8390p_init_module); +module_exit(NS8390p_cleanup_module); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 9b171ffe1b3004587f4a90ef293531a4a262e538 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 24 Apr 2009 15:30:28 -0400 Subject: libertas: fix format warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/libertas/if_spi.c: In function ‘if_spi_c2h_data’: drivers/net/wireless/libertas/if_spi.c:733: warning: format ‘%u’ expects type ‘unsigned int’, but argument 4 has type ‘long unsigned int’ Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 97493e2f..dccd01f 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -731,7 +731,7 @@ static int if_spi_c2h_data(struct if_spi_card *card) goto out; } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_pr_err("%s: error: card has %d bytes of data, but " - "our maximum skb size is %u\n", + "our maximum skb size is %lu\n", __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); err = -EINVAL; goto out; -- cgit v0.10.2 From d3feaf5ad12259927039a675cfb25dc342b403ab Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 24 Apr 2009 15:35:42 -0400 Subject: wireless: remove some (bogus?) 'may be used uninitialized' warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/mac80211/tx.c: In function ‘ieee80211_tx_h_select_key’: net/mac80211/tx.c:448: warning: ‘key’ may be used uninitialized in this function drivers/net/wireless/ath/ath9k/rc.c: In function ‘ath_rc_rate_getidx’: drivers/net/wireless/ath/ath9k/rc.c:815: warning: ‘nextindex’ may be used uninitialized in this function drivers/net/wireless/hostap/hostap_plx.c: In function ‘prism2_plx_probe’: drivers/net/wireless/hostap/hostap_plx.c:438: warning: ‘cor_index’ may be used uninitialized in this function drivers/net/wireless/hostap/hostap_plx.c:438: warning: ‘cor_offset’ may be used uninitialized in this function Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a13668b..8f3cf10 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -812,7 +812,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, u16 min_rate) { u32 j; - u8 nextindex; + u8 nextindex = 0; if (min_rate) { for (j = RATE_TABLE_SIZE; j > 0; j--) { diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index cbf15d7..0e5d510 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -435,7 +435,7 @@ static int prism2_plx_probe(struct pci_dev *pdev, unsigned long pccard_attr_mem; unsigned int pccard_attr_len; void __iomem *attr_mem = NULL; - unsigned int cor_offset, cor_index; + unsigned int cor_offset = 0, cor_index = 0; u32 reg; local_info_t *local = NULL; struct net_device *dev = NULL; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9ab4982..1865622 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -445,7 +445,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { - struct ieee80211_key *key; + struct ieee80211_key *key = NULL; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; -- cgit v0.10.2 From 92ae3efa53b481ad669d8b85c6cfa37d774bb21e Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Mon, 27 Apr 2009 02:35:32 -0700 Subject: ipv4: remove unused member in fib_table. This patch removes an unused parameter (tb_stamp) from fib_table structure in include/net/ip_fib.h. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 8b12667..34855ee 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -145,7 +145,6 @@ struct fib_result_nl { struct fib_table { struct hlist_node tb_hlist; u32 tb_id; - unsigned tb_stamp; int tb_default; int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res); int (*tb_insert)(struct fib_table *, struct fib_config *); -- cgit v0.10.2 From 06bd12c3b861f8ca9e1215428b19dc0026c6268f Mon Sep 17 00:00:00 2001 From: John Dykstra Date: Mon, 27 Apr 2009 02:42:20 -0700 Subject: pcnet32: Remove redundant set of skb->dev Remove redundant set of skb->dev (now handled for ethernet drivers by eth_type_trans()). Signed-off-by: John Dykstra Signed-off-by: David S. Miller diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 80124fa..e5e8c59 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1227,7 +1227,6 @@ static void pcnet32_rx_entry(struct net_device *dev, dev->stats.rx_dropped++; return; } - skb->dev = dev; if (!rx_in_place) { skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pkt_len); /* Make room */ -- cgit v0.10.2 From edf391ff17232f097d72441c9ad467bcb3b5db18 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 27 Apr 2009 02:45:02 -0700 Subject: snmp: add missing counters for RFC 4293 The IP MIB (RFC 4293) defines stats for InOctets, OutOctets, InMcastOctets and OutMcastOctets: http://tools.ietf.org/html/rfc4293 But it seems we don't track those in any way that easy to separate from other protocols. This patch adds those missing counters to the stats file. Tested successfully by me With help from Eric Dumazet. Signed-off-by: Neil Horman Signed-off-by: David S. Miller diff --git a/include/linux/snmp.h b/include/linux/snmp.h index aee3f1e..0f953fe 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -18,7 +18,7 @@ enum { IPSTATS_MIB_NUM = 0, - IPSTATS_MIB_INRECEIVES, /* InReceives */ + IPSTATS_MIB_INPKTS, /* InReceives */ IPSTATS_MIB_INHDRERRORS, /* InHdrErrors */ IPSTATS_MIB_INTOOBIGERRORS, /* InTooBigErrors */ IPSTATS_MIB_INNOROUTES, /* InNoRoutes */ @@ -28,7 +28,7 @@ enum IPSTATS_MIB_INDISCARDS, /* InDiscards */ IPSTATS_MIB_INDELIVERS, /* InDelivers */ IPSTATS_MIB_OUTFORWDATAGRAMS, /* OutForwDatagrams */ - IPSTATS_MIB_OUTREQUESTS, /* OutRequests */ + IPSTATS_MIB_OUTPKTS, /* OutRequests */ IPSTATS_MIB_OUTDISCARDS, /* OutDiscards */ IPSTATS_MIB_OUTNOROUTES, /* OutNoRoutes */ IPSTATS_MIB_REASMTIMEOUT, /* ReasmTimeout */ @@ -42,6 +42,12 @@ enum IPSTATS_MIB_OUTMCASTPKTS, /* OutMcastPkts */ IPSTATS_MIB_INBCASTPKTS, /* InBcastPkts */ IPSTATS_MIB_OUTBCASTPKTS, /* OutBcastPkts */ + IPSTATS_MIB_INOCTETS, /* InOctets */ + IPSTATS_MIB_OUTOCTETS, /* OutOctets */ + IPSTATS_MIB_INMCASTOCTETS, /* InMcastOctets */ + IPSTATS_MIB_OUTMCASTOCTETS, /* OutMcastOctets */ + IPSTATS_MIB_INBCASTOCTETS, /* InBcastOctets */ + IPSTATS_MIB_OUTBCASTOCTETS, /* OutBcastOctets */ __IPSTATS_MIB_MAX }; diff --git a/include/net/ip.h b/include/net/ip.h index 4ac7577..72c3692 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -168,7 +168,10 @@ struct ipv4_config extern struct ipv4_config ipv4_config; #define IP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.ip_statistics, field) #define IP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.ip_statistics, field) +#define IP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.ip_statistics, field, val) #define IP_ADD_STATS_BH(net, field, val) SNMP_ADD_STATS_BH((net)->mib.ip_statistics, field, val) +#define IP_UPD_PO_STATS(net, field, val) SNMP_UPD_PO_STATS((net)->mib.ip_statistics, field, val) +#define IP_UPD_PO_STATS_BH(net, field, val) SNMP_UPD_PO_STATS_BH((net)->mib.ip_statistics, field, val) #define NET_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.net_statistics, field) #define NET_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.net_statistics, field) #define NET_INC_STATS_USER(net, field) SNMP_INC_STATS_USER((net)->mib.net_statistics, field) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index c1f16fc..f27fd83 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -126,15 +126,28 @@ extern struct ctl_path net_ipv6_ctl_path[]; SNMP_ADD_STATS##modifier((net)->mib.statname##_statistics, (field), (val));\ }) +#define _DEVUPD(net, statname, modifier, idev, field, val) \ +({ \ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_UPD_PO_STATS##modifier((_idev)->stats.statname, field, (val)); \ + SNMP_UPD_PO_STATS##modifier((net)->mib.statname##_statistics, field, (val));\ +}) + /* MIBs */ #define IP6_INC_STATS(net, idev,field) \ _DEVINC(net, ipv6, , idev, field) #define IP6_INC_STATS_BH(net, idev,field) \ _DEVINC(net, ipv6, _BH, idev, field) +#define IP6_ADD_STATS(net, idev,field,val) \ + _DEVADD(net, ipv6, , idev, field, val) #define IP6_ADD_STATS_BH(net, idev,field,val) \ _DEVADD(net, ipv6, _BH, idev, field, val) - +#define IP6_UPD_PO_STATS(net, idev,field,val) \ + _DEVUPD(net, ipv6, , idev, field, val) +#define IP6_UPD_PO_STATS_BH(net, idev,field,val) \ + _DEVUPD(net, ipv6, _BH, idev, field, val) #define ICMP6_INC_STATS(net, idev, field) \ _DEVINC(net, icmpv6, , idev, field) #define ICMP6_INC_STATS_BH(net, idev, field) \ diff --git a/include/net/snmp.h b/include/net/snmp.h index 57c9362..8c842e0 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -153,6 +153,11 @@ struct linux_xfrm_mib { per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field]--; \ put_cpu(); \ } while (0) +#define SNMP_ADD_STATS(mib, field, addend) \ + do { \ + per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field] += addend; \ + put_cpu(); \ + } while (0) #define SNMP_ADD_STATS_BH(mib, field, addend) \ (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend) #define SNMP_ADD_STATS_USER(mib, field, addend) \ @@ -160,5 +165,17 @@ struct linux_xfrm_mib { per_cpu_ptr(mib[1], get_cpu())->mibs[field] += addend; \ put_cpu(); \ } while (0) - +#define SNMP_UPD_PO_STATS(mib, basefield, addend) \ + do { \ + __typeof__(mib[0]) ptr = per_cpu_ptr(mib[!in_softirq()], get_cpu());\ + ptr->mibs[basefield##PKTS]++; \ + ptr->mibs[basefield##OCTETS] += addend;\ + put_cpu(); \ + } while (0) +#define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \ + do { \ + __typeof__(mib[0]) ptr = per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id());\ + ptr->mibs[basefield##PKTS]++; \ + ptr->mibs[basefield##OCTETS] += addend;\ + } while (0) #endif diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 1a58a6f..40f6206 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -358,10 +358,12 @@ static int ip_rcv_finish(struct sk_buff *skb) goto drop; rt = skb->rtable; - if (rt->rt_type == RTN_MULTICAST) - IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCASTPKTS); - else if (rt->rt_type == RTN_BROADCAST) - IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCASTPKTS); + if (rt->rt_type == RTN_MULTICAST) { + IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST, + skb->len); + } else if (rt->rt_type == RTN_BROADCAST) + IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST, + skb->len); return dst_input(skb); @@ -384,7 +386,8 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, if (skb->pkt_type == PACKET_OTHERHOST) goto drop; - IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INRECEIVES); + + IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 3e7e910..ea19c37 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -181,10 +181,10 @@ static inline int ip_finish_output2(struct sk_buff *skb) struct net_device *dev = dst->dev; unsigned int hh_len = LL_RESERVED_SPACE(dev); - if (rt->rt_type == RTN_MULTICAST) - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTMCASTPKTS); - else if (rt->rt_type == RTN_BROADCAST) - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTBCASTPKTS); + if (rt->rt_type == RTN_MULTICAST) { + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len); + } else if (rt->rt_type == RTN_BROADCAST) + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTBCAST, skb->len); /* Be paranoid, rather than too clever. */ if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { @@ -244,7 +244,7 @@ int ip_mc_output(struct sk_buff *skb) /* * If the indicated interface is up and running, send the packet. */ - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS); + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len); skb->dev = dev; skb->protocol = htons(ETH_P_IP); @@ -298,7 +298,7 @@ int ip_output(struct sk_buff *skb) { struct net_device *dev = skb->dst->dev; - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS); + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len); skb->dev = dev; skb->protocol = htons(ETH_P_IP); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index cf0cdee..f25542c 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -90,14 +90,14 @@ static const struct file_operations sockstat_seq_fops = { /* snmp items */ static const struct snmp_mib snmp4_ipstats_list[] = { - SNMP_MIB_ITEM("InReceives", IPSTATS_MIB_INRECEIVES), + SNMP_MIB_ITEM("InReceives", IPSTATS_MIB_INPKTS), SNMP_MIB_ITEM("InHdrErrors", IPSTATS_MIB_INHDRERRORS), SNMP_MIB_ITEM("InAddrErrors", IPSTATS_MIB_INADDRERRORS), SNMP_MIB_ITEM("ForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS), SNMP_MIB_ITEM("InUnknownProtos", IPSTATS_MIB_INUNKNOWNPROTOS), SNMP_MIB_ITEM("InDiscards", IPSTATS_MIB_INDISCARDS), SNMP_MIB_ITEM("InDelivers", IPSTATS_MIB_INDELIVERS), - SNMP_MIB_ITEM("OutRequests", IPSTATS_MIB_OUTREQUESTS), + SNMP_MIB_ITEM("OutRequests", IPSTATS_MIB_OUTPKTS), SNMP_MIB_ITEM("OutDiscards", IPSTATS_MIB_OUTDISCARDS), SNMP_MIB_ITEM("OutNoRoutes", IPSTATS_MIB_OUTNOROUTES), SNMP_MIB_ITEM("ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT), @@ -118,6 +118,12 @@ static const struct snmp_mib snmp4_ipextstats_list[] = { SNMP_MIB_ITEM("OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS), SNMP_MIB_ITEM("InBcastPkts", IPSTATS_MIB_INBCASTPKTS), SNMP_MIB_ITEM("OutBcastPkts", IPSTATS_MIB_OUTBCASTPKTS), + SNMP_MIB_ITEM("InOctets", IPSTATS_MIB_INOCTETS), + SNMP_MIB_ITEM("OutOctets", IPSTATS_MIB_OUTOCTETS), + SNMP_MIB_ITEM("InMcastOctets", IPSTATS_MIB_INMCASTOCTETS), + SNMP_MIB_ITEM("OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS), + SNMP_MIB_ITEM("InBcastOctets", IPSTATS_MIB_INBCASTOCTETS), + SNMP_MIB_ITEM("OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS), SNMP_MIB_SENTINEL }; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 8f04bd9..bc1a920 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -70,7 +70,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt idev = __in6_dev_get(skb->dev); - IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INRECEIVES); + IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_IN, skb->len); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || !idev || unlikely(idev->cnf.disable_ipv6)) { @@ -242,8 +242,9 @@ int ip6_mc_input(struct sk_buff *skb) struct ipv6hdr *hdr; int deliver; - IP6_INC_STATS_BH(dev_net(skb->dst->dev), - ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS); + IP6_UPD_PO_STATS_BH(dev_net(skb->dst->dev), + ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCAST, + skb->len); hdr = ipv6_hdr(skb); deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9fb49c3..735a2bf 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -159,7 +159,8 @@ static int ip6_output2(struct sk_buff *skb) } } - IP6_INC_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCASTPKTS); + IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST, + skb->len); } return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev, @@ -275,8 +276,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, mtu = dst_mtu(dst); if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) { - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), - IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, ip6_dst_idev(skb->dst), + IPSTATS_MIB_OUT, skb->len); return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, dst_output); } @@ -1516,7 +1517,7 @@ int ip6_push_pending_frames(struct sock *sk) skb->mark = sk->sk_mark; skb->dst = dst_clone(&rt->u.dst); - IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); if (proto == IPPROTO_ICMPV6) { struct inet6_dev *idev = ip6_dst_idev(skb->dst); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index a51fb33..4b48819 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1449,7 +1449,8 @@ static void mld_sendpack(struct sk_buff *skb) int err; struct flowi fl; - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); + payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); mldlen = skb->tail - skb->transport_header; pip6->payload_len = htons(payload_len); @@ -1473,13 +1474,15 @@ static void mld_sendpack(struct sk_buff *skb) if (err) goto err_out; + payload_len = skb->len; + err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, dst_output); out: if (!err) { ICMP6MSGOUT_INC_STATS_BH(net, idev, ICMPV6_MLD2_REPORT); ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); - IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTMCASTPKTS); + IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_OUTMCAST, payload_len); } else IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS); @@ -1773,10 +1776,6 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) IPV6_TLV_PADN, 0 }; struct flowi fl; - rcu_read_lock(); - IP6_INC_STATS(net, __in6_dev_get(dev), - IPSTATS_MIB_OUTREQUESTS); - rcu_read_unlock(); if (type == ICMPV6_MGM_REDUCTION) snd_addr = &in6addr_linklocal_allrouters; else @@ -1786,6 +1785,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) payload_len = len + sizeof(ra); full_len = sizeof(struct ipv6hdr) + payload_len; + rcu_read_lock(); + IP6_UPD_PO_STATS(net, __in6_dev_get(dev), + IPSTATS_MIB_OUT, full_len); + rcu_read_unlock(); + skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err); if (skb == NULL) { @@ -1838,13 +1842,14 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) if (err) goto err_out; + err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, dst_output); out: if (!err) { ICMP6MSGOUT_INC_STATS(net, idev, type); ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTMCASTPKTS); + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len); } else IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 9f061d1..ab65cc5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -533,7 +533,7 @@ void ndisc_send_skb(struct sk_buff *skb, skb->dst = dst; idev = in6_dev_get(dst->dev); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, dst_output); @@ -1613,7 +1613,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, buff->dst = dst; idev = in6_dev_get(dst->dev); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, dst_output); if (!err) { diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 97c17fd..590ddef 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -61,7 +61,7 @@ static const struct file_operations sockstat6_seq_fops = { static struct snmp_mib snmp6_ipstats_list[] = { /* ipv6 mib according to RFC 2465 */ - SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INRECEIVES), + SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), SNMP_MIB_ITEM("Ip6InTooBigErrors", IPSTATS_MIB_INTOOBIGERRORS), SNMP_MIB_ITEM("Ip6InNoRoutes", IPSTATS_MIB_INNOROUTES), @@ -71,7 +71,7 @@ static struct snmp_mib snmp6_ipstats_list[] = { SNMP_MIB_ITEM("Ip6InDiscards", IPSTATS_MIB_INDISCARDS), SNMP_MIB_ITEM("Ip6InDelivers", IPSTATS_MIB_INDELIVERS), SNMP_MIB_ITEM("Ip6OutForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS), - SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTREQUESTS), + SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTPKTS), SNMP_MIB_ITEM("Ip6OutDiscards", IPSTATS_MIB_OUTDISCARDS), SNMP_MIB_ITEM("Ip6OutNoRoutes", IPSTATS_MIB_OUTNOROUTES), SNMP_MIB_ITEM("Ip6ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT), @@ -83,6 +83,12 @@ static struct snmp_mib snmp6_ipstats_list[] = { SNMP_MIB_ITEM("Ip6FragCreates", IPSTATS_MIB_FRAGCREATES), SNMP_MIB_ITEM("Ip6InMcastPkts", IPSTATS_MIB_INMCASTPKTS), SNMP_MIB_ITEM("Ip6OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS), + SNMP_MIB_ITEM("Ip6InOctets", IPSTATS_MIB_INOCTETS), + SNMP_MIB_ITEM("Ip6OutOctets", IPSTATS_MIB_OUTOCTETS), + SNMP_MIB_ITEM("Ip6InMcastOctets", IPSTATS_MIB_INMCASTOCTETS), + SNMP_MIB_ITEM("Ip6OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS), + SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS), + SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS), SNMP_MIB_SENTINEL }; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 61f6827..e99307f 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -638,7 +638,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, if (err) goto error_fault; - IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); if (err > 0) -- cgit v0.10.2 From 739649c53d7f78f5bf41bdfd1a858ee90c7a687a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:52:40 +0000 Subject: of: add of_parse_phandle() helper for parsing phandle properties of_parse_phandle() is a helper function to read and parse a phandle property and return a pointer to the resulting device_node. Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/of/base.c b/drivers/of/base.c index 41c5dfd..ddf224d 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -495,6 +495,30 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) EXPORT_SYMBOL_GPL(of_modalias_node); /** + * of_parse_phandle - Resolve a phandle property to a device_node pointer + * @np: Pointer to device node holding phandle property + * @phandle_name: Name of property holding a phandle value + * @index: For properties holding a table of phandles, this is the index into + * the table + * + * Returns the device_node pointer with refcount incremented. Use + * of_node_put() on it when done. + */ +struct device_node * +of_parse_phandle(struct device_node *np, const char *phandle_name, int index) +{ + const phandle *phandle; + int size; + + phandle = of_get_property(np, phandle_name, &size); + if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) + return NULL; + + return of_find_node_by_phandle(phandle[index]); +} +EXPORT_SYMBOL(of_parse_phandle); + +/** * of_parse_phandles_with_args - Find a node pointed by phandle in a list * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list diff --git a/include/linux/of.h b/include/linux/of.h index 6a7efa2..7be2d10 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -77,6 +77,9 @@ extern int of_n_size_cells(struct device_node *np); extern const struct of_device_id *of_match_node( const struct of_device_id *matches, const struct device_node *node); extern int of_modalias_node(struct device_node *node, char *modalias, int len); +extern struct device_node *of_parse_phandle(struct device_node *np, + const char *phandle_name, + int index); extern int of_parse_phandles_with_args(struct device_node *np, const char *list_name, const char *cells_name, int index, struct device_node **out_node, const void **out_args); -- cgit v0.10.2 From 4dea547fef1ba23f9d23f5e7f5218187a7dcf1b3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:52:46 +0000 Subject: phylib: rework to prepare for OF registration of PHYs This patch makes changes in preparation for supporting open firmware device tree descriptions of MDIO busses. Changes include: - Cleanup handling of phy_map[] entries; they are already NULLed when registering and so don't need to be re-cleared, and it is good practice to clear them out when unregistering. - Split phy_device registration out into a new function so that the OF helpers can do two stage registration (separate allocation and registration steps). Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index b754020..bd4e8d7 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -113,7 +113,6 @@ int mdiobus_register(struct mii_bus *bus) bus->reset(bus); for (i = 0; i < PHY_MAX_ADDR; i++) { - bus->phy_map[i] = NULL; if ((bus->phy_mask & (1 << i)) == 0) { struct phy_device *phydev; @@ -150,6 +149,7 @@ void mdiobus_unregister(struct mii_bus *bus) for (i = 0; i < PHY_MAX_ADDR; i++) { if (bus->phy_map[i]) device_unregister(&bus->phy_map[i]->dev); + bus->phy_map[i] = NULL; } } EXPORT_SYMBOL(mdiobus_unregister); @@ -188,35 +188,12 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int 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; - dev_set_name(&phydev->dev, 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); + err = phy_device_register(phydev); if (err) { - printk(KERN_ERR "phy %d failed to register\n", addr); phy_device_free(phydev); - phydev = NULL; + return NULL; } - bus->phy_map[addr] = phydev; - return phydev; } EXPORT_SYMBOL(mdiobus_scan); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 0a06e4f..9352ca8 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -39,20 +39,21 @@ MODULE_DESCRIPTION("PHY library"); MODULE_AUTHOR("Andy Fleming"); MODULE_LICENSE("GPL"); -static struct phy_driver genphy_driver; -extern int mdio_bus_init(void); -extern void mdio_bus_exit(void); - void phy_device_free(struct phy_device *phydev) { kfree(phydev); } +EXPORT_SYMBOL(phy_device_free); static void phy_device_release(struct device *dev) { phy_device_free(to_phy_device(dev)); } +static struct phy_driver genphy_driver; +extern int mdio_bus_init(void); +extern void mdio_bus_exit(void); + static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); @@ -166,6 +167,10 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) dev->addr = addr; dev->phy_id = phy_id; dev->bus = bus; + dev->dev.parent = bus->parent; + dev->dev.bus = &mdio_bus_type; + dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; + dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); dev->state = PHY_DOWN; @@ -235,6 +240,38 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return dev; } +EXPORT_SYMBOL(get_phy_device); + +/** + * phy_device_register - Register the phy device on the MDIO bus + * @phy_device: phy_device structure to be added to the MDIO bus + */ +int phy_device_register(struct phy_device *phydev) +{ + int err; + + /* Don't register a phy if one is already registered at this + * address */ + if (phydev->bus->phy_map[phydev->addr]) + return -EINVAL; + phydev->bus->phy_map[phydev->addr] = phydev; + + /* Run all of the fixups for this PHY */ + phy_scan_fixups(phydev); + + err = device_register(&phydev->dev); + if (err) { + pr_err("phy %d failed to register\n", phydev->addr); + goto out; + } + + return 0; + + out: + phydev->bus->phy_map[phydev->addr] = NULL; + return err; +} +EXPORT_SYMBOL(phy_device_register); /** * phy_prepare_link - prepares the PHY layer to monitor link status diff --git a/include/linux/phy.h b/include/linux/phy.h index 97e40cb..bf0b5f1 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -444,6 +444,7 @@ static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val) int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id); struct phy_device* get_phy_device(struct mii_bus *bus, int addr); +int phy_device_register(struct phy_device *phy); int phy_clear_interrupt(struct phy_device *phydev); int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); struct phy_device * phy_attach(struct net_device *dev, -- cgit v0.10.2 From fa94f6d93c5382810ff41f010f12ca8698fc775e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:52:51 +0000 Subject: phylib: add *_direct() variants of phy_connect and phy_attach functions Add phy_connect_direct() and phy_attach_direct() functions so that drivers can use a pointer to the phy_device instead of trying to determine the phy's bus_id string. This patch is useful for OF device tree descriptions of phy devices where the driver doesn't need or know what the bus_id value in order to get a phy_device pointer. Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 9352ca8..a2ece89 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -292,6 +292,33 @@ void phy_prepare_link(struct phy_device *phydev, } /** + * phy_connect_direct - connect an ethernet device to a specific phy_device + * @dev: the network device to connect + * @phydev: the pointer to the phy device + * @handler: callback function for state change notifications + * @flags: PHY device's dev_flags + * @interface: PHY device's interface + */ +int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, + void (*handler)(struct net_device *), u32 flags, + phy_interface_t interface) +{ + int rc; + + rc = phy_attach_direct(dev, phydev, flags, interface); + if (rc) + return rc; + + phy_prepare_link(phydev, handler); + phy_start_machine(phydev, NULL); + if (phydev->irq > 0) + phy_start_interrupts(phydev); + + return 0; +} +EXPORT_SYMBOL(phy_connect_direct); + +/** * phy_connect - connect an ethernet device to a PHY device * @dev: the network device to connect * @bus_id: the id string of the PHY device to connect @@ -312,18 +339,21 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, phy_interface_t interface) { struct phy_device *phydev; + struct device *d; + int rc; - phydev = phy_attach(dev, bus_id, flags, interface); - - if (IS_ERR(phydev)) - return phydev; - - phy_prepare_link(phydev, handler); - - phy_start_machine(phydev, NULL); + /* Search the list of PHY devices on the mdio bus for the + * PHY with the requested name */ + d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id); + if (!d) { + pr_err("PHY %s not found\n", bus_id); + return ERR_PTR(-ENODEV); + } + phydev = to_phy_device(d); - if (phydev->irq > 0) - phy_start_interrupts(phydev); + rc = phy_connect_direct(dev, phydev, handler, flags, interface); + if (rc) + return ERR_PTR(rc); return phydev; } @@ -347,9 +377,9 @@ void phy_disconnect(struct phy_device *phydev) EXPORT_SYMBOL(phy_disconnect); /** - * phy_attach - attach a network device to a particular PHY device + * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach - * @bus_id: PHY device to attach + * @phydev: Pointer to phy_device to attach * @flags: PHY device's dev_flags * @interface: PHY device's interface * @@ -360,22 +390,10 @@ EXPORT_SYMBOL(phy_disconnect); * the attaching device, and given a callback for link status * change. The phy_device is returned to the attaching driver. */ -struct phy_device *phy_attach(struct net_device *dev, - const char *bus_id, u32 flags, phy_interface_t interface) +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + u32 flags, phy_interface_t interface) { - struct bus_type *bus = &mdio_bus_type; - struct phy_device *phydev; - struct device *d; - - /* Search the list of PHY devices on the mdio bus for the - * PHY with the requested name */ - d = bus_find_device_by_name(bus, NULL, bus_id); - if (d) { - phydev = to_phy_device(d); - } else { - printk(KERN_ERR "%s not found\n", bus_id); - return ERR_PTR(-ENODEV); - } + struct device *d = &phydev->dev; /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ @@ -388,13 +406,12 @@ struct phy_device *phy_attach(struct net_device *dev, err = device_bind_driver(d); if (err) - return ERR_PTR(err); + return err; } if (phydev->attached_dev) { - printk(KERN_ERR "%s: %s already attached\n", - dev->name, bus_id); - return ERR_PTR(-EBUSY); + dev_err(&dev->dev, "PHY already attached\n"); + return -EBUSY; } phydev->attached_dev = dev; @@ -412,13 +429,48 @@ struct phy_device *phy_attach(struct net_device *dev, err = phy_scan_fixups(phydev); if (err < 0) - return ERR_PTR(err); + return err; err = phydev->drv->config_init(phydev); if (err < 0) - return ERR_PTR(err); + return err; + } + + return 0; +} +EXPORT_SYMBOL(phy_attach_direct); + +/** + * phy_attach - attach a network device to a particular PHY device + * @dev: network device to attach + * @bus_id: Bus ID of PHY device to attach + * @flags: PHY device's dev_flags + * @interface: PHY device's interface + * + * Description: Same as phy_attach_direct() except that a PHY bus_id + * string is passed instead of a pointer to a struct phy_device. + */ +struct phy_device *phy_attach(struct net_device *dev, + const char *bus_id, u32 flags, phy_interface_t interface) +{ + struct bus_type *bus = &mdio_bus_type; + struct phy_device *phydev; + struct device *d; + int rc; + + /* Search the list of PHY devices on the mdio bus for the + * PHY with the requested name */ + d = bus_find_device_by_name(bus, NULL, bus_id); + if (!d) { + pr_err("PHY %s not found\n", bus_id); + return ERR_PTR(-ENODEV); } + phydev = to_phy_device(d); + + rc = phy_attach_direct(dev, phydev, flags, interface); + if (rc) + return ERR_PTR(rc); return phydev; } diff --git a/include/linux/phy.h b/include/linux/phy.h index bf0b5f1..c216e4e 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -447,8 +447,13 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr); int phy_device_register(struct phy_device *phy); int phy_clear_interrupt(struct phy_device *phydev); int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + u32 flags, phy_interface_t interface); struct phy_device * phy_attach(struct net_device *dev, const char *bus_id, u32 flags, phy_interface_t interface); +int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, + void (*handler)(struct net_device *), u32 flags, + phy_interface_t interface); struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, void (*handler)(struct net_device *), u32 flags, phy_interface_t interface); -- cgit v0.10.2 From 8bc487d150b939e69830c39322df4ee486efe381 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:52:56 +0000 Subject: openfirmware: Add OF phylib support code Add support for parsing the device tree for PHY devices on an MDIO bus. Currently many of the PowerPC ethernet drivers are open coding a solution for reading data out of the device tree to find the correct PHY device. This patch implements a set of common routines to: a) let MDIO bus drivers register phy_devices described in the tree, and b) let MAC drivers find the correct phy_device via the tree. Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index f821dbc..6fe043b 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -19,3 +19,9 @@ config OF_SPI depends on OF && PPC_OF && SPI help OpenFirmware SPI accessors + +config OF_MDIO + def_tristate PHYLIB + depends on OF && PHYLIB + help + OpenFirmware MDIO bus (Ethernet PHY) accessors diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 4c3c6f8..bdfb5f5 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_SPI) += of_spi.o +obj-$(CONFIG_OF_MDIO) += of_mdio.o diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c new file mode 100644 index 0000000..aee967d --- /dev/null +++ b/drivers/of/of_mdio.c @@ -0,0 +1,139 @@ +/* + * OF helpers for the MDIO (Ethernet PHY) API + * + * Copyright (c) 2009 Secret Lab Technologies, Ltd. + * + * This file is released under the GPLv2 + * + * This file provides helper functions for extracting PHY device information + * out of the OpenFirmware device tree and using it to populate an mii_bus. + */ + +#include +#include +#include +#include + +MODULE_AUTHOR("Grant Likely "); +MODULE_LICENSE("GPL"); + +/** + * of_mdiobus_register - Register mii_bus and create PHYs from the device tree + * @mdio: pointer to mii_bus structure + * @np: pointer to device_node of MDIO bus. + * + * This function registers the mii_bus structure and registers a phy_device + * for each child node of @np. + */ +int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) +{ + struct phy_device *phy; + struct device_node *child; + int rc, i; + + /* Mask out all PHYs from auto probing. Instead the PHYs listed in + * the device tree are populated after the bus has been registered */ + mdio->phy_mask = ~0; + + /* Clear all the IRQ properties */ + if (mdio->irq) + for (i=0; iirq[i] = PHY_POLL; + + /* Register the MDIO bus */ + rc = mdiobus_register(mdio); + if (rc) + return rc; + + /* Loop over the child nodes and register a phy_device for each one */ + for_each_child_of_node(np, child) { + const u32 *addr; + int len; + + /* A PHY must have a reg property in the range [0-31] */ + addr = of_get_property(child, "reg", &len); + if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) { + dev_err(&mdio->dev, "%s has invalid PHY address\n", + child->full_name); + continue; + } + + if (mdio->irq) { + mdio->irq[*addr] = irq_of_parse_and_map(child, 0); + if (!mdio->irq[*addr]) + mdio->irq[*addr] = PHY_POLL; + } + + phy = get_phy_device(mdio, *addr); + if (!phy) { + dev_err(&mdio->dev, "error probing PHY at address %i\n", + *addr); + continue; + } + phy_scan_fixups(phy); + + /* Associate the OF node with the device structure so it + * can be looked up later */ + of_node_get(child); + dev_archdata_set_node(&phy->dev.archdata, child); + + /* All data is now stored in the phy struct; register it */ + rc = phy_device_register(phy); + if (rc) { + phy_device_free(phy); + of_node_put(child); + continue; + } + + dev_dbg(&mdio->dev, "registered phy %s at address %i\n", + child->name, *addr); + } + + return 0; +} +EXPORT_SYMBOL(of_mdiobus_register); + +/** + * of_phy_find_device - Give a PHY node, find the phy_device + * @phy_np: Pointer to the phy's device tree node + * + * Returns a pointer to the phy_device. + */ +struct phy_device *of_phy_find_device(struct device_node *phy_np) +{ + struct device *d; + int match(struct device *dev, void *phy_np) + { + return dev_archdata_get_node(&dev->archdata) == phy_np; + } + + if (!phy_np) + return NULL; + + d = bus_find_device(&mdio_bus_type, NULL, phy_np, match); + return d ? to_phy_device(d) : NULL; +} +EXPORT_SYMBOL(of_phy_find_device); + +/** + * of_phy_connect - Connect to the phy described in the device tree + * @dev: pointer to net_device claiming the phy + * @phy_np: Pointer to device tree node for the PHY + * @hndlr: Link state callback for the network device + * @iface: PHY data interface type + * + * Returns a pointer to the phy_device if successfull. NULL otherwise + */ +struct phy_device *of_phy_connect(struct net_device *dev, + struct device_node *phy_np, + void (*hndlr)(struct net_device *), u32 flags, + phy_interface_t iface) +{ + struct phy_device *phy = of_phy_find_device(phy_np); + + if (!phy) + return NULL; + + return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy; +} +EXPORT_SYMBOL(of_phy_connect); diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h new file mode 100644 index 0000000..c9663c6 --- /dev/null +++ b/include/linux/of_mdio.h @@ -0,0 +1,22 @@ +/* + * OF helpers for the MDIO (Ethernet PHY) API + * + * Copyright (c) 2009 Secret Lab Technologies, Ltd. + * + * This file is released under the GPLv2 + */ + +#ifndef __LINUX_OF_MDIO_H +#define __LINUX_OF_MDIO_H + +#include +#include + +extern int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np); +extern struct phy_device *of_phy_find_device(struct device_node *phy_np); +extern struct phy_device *of_phy_connect(struct net_device *dev, + struct device_node *phy_np, + void (*hndlr)(struct net_device *), + u32 flags, phy_interface_t iface); + +#endif /* __LINUX_OF_MDIO_H */ -- cgit v0.10.2 From ca816d98170942371535b3e862813b0aba9b7d90 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:02 +0000 Subject: net: Rework mpc5200 fec driver to use of_mdio infrastructure. The patch reworks the MPC5200 Fast Ethernet Controller (FEC) driver to use the of_mdio infrastructure for registering PHY devices from data out openfirmware device tree, and eliminates the assumption that the PHY for the FEC is always attached to the FEC's own MDIO bus. With this patch, the FEC can use a PHY attached to any MDIO bus if it is described in the device tree. Tested on Freescale Lite5200b eval board Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 8bbe7f6..7d44340 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -43,11 +44,9 @@ #define DRIVER_NAME "mpc52xx-fec" -#define FEC5200_PHYADDR_NONE (-1) -#define FEC5200_PHYADDR_7WIRE (-2) - /* Private driver data structure */ struct mpc52xx_fec_priv { + struct net_device *ndev; int duplex; int speed; int r_irq; @@ -59,10 +58,11 @@ struct mpc52xx_fec_priv { int msg_enable; /* MDIO link details */ - int phy_addr; - unsigned int phy_speed; + unsigned int mdio_speed; + struct device_node *phy_node; struct phy_device *phydev; enum phy_state link; + int seven_wire_mode; }; @@ -211,85 +211,25 @@ static void mpc52xx_fec_adjust_link(struct net_device *dev) phy_print_status(phydev); } -static int mpc52xx_fec_init_phy(struct net_device *dev) -{ - struct mpc52xx_fec_priv *priv = netdev_priv(dev); - struct phy_device *phydev; - char phy_id[BUS_ID_SIZE]; - - snprintf(phy_id, sizeof(phy_id), "%x:%02x", - (unsigned int)dev->base_addr, priv->phy_addr); - - priv->link = PHY_DOWN; - priv->speed = 0; - priv->duplex = -1; - - phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII); - if (IS_ERR(phydev)) { - dev_err(&dev->dev, "phy_connect failed\n"); - return PTR_ERR(phydev); - } - dev_info(&dev->dev, "attached phy %i to driver %s\n", - phydev->addr, phydev->drv->name); - - priv->phydev = phydev; - - return 0; -} - -static int mpc52xx_fec_phy_start(struct net_device *dev) -{ - struct mpc52xx_fec_priv *priv = netdev_priv(dev); - int err; - - if (priv->phy_addr < 0) - return 0; - - err = mpc52xx_fec_init_phy(dev); - if (err) { - dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n"); - return err; - } - - /* reset phy - this also wakes it from PDOWN */ - phy_write(priv->phydev, MII_BMCR, BMCR_RESET); - phy_start(priv->phydev); - - return 0; -} - -static void mpc52xx_fec_phy_stop(struct net_device *dev) -{ - struct mpc52xx_fec_priv *priv = netdev_priv(dev); - - if (!priv->phydev) - return; - - phy_disconnect(priv->phydev); - /* power down phy */ - phy_stop(priv->phydev); - phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN); -} - -static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv) -{ - struct mpc52xx_fec __iomem *fec = priv->fec; - - if (priv->phydev) - return; - - out_be32(&fec->mii_speed, priv->phy_speed); -} - static int mpc52xx_fec_open(struct net_device *dev) { struct mpc52xx_fec_priv *priv = netdev_priv(dev); int err = -EBUSY; + if (priv->phy_node) { + priv->phydev = of_phy_connect(priv->ndev, priv->phy_node, + mpc52xx_fec_adjust_link, 0, 0); + if (!priv->phydev) { + dev_err(&dev->dev, "of_phy_connect failed\n"); + return -ENODEV; + } + phy_start(priv->phydev); + } + if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED, DRIVER_NAME "_ctrl", dev)) { dev_err(&dev->dev, "ctrl interrupt request failed\n"); - goto out; + goto free_phy; } if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0, DRIVER_NAME "_rx", dev)) { @@ -311,10 +251,6 @@ static int mpc52xx_fec_open(struct net_device *dev) goto free_irqs; } - err = mpc52xx_fec_phy_start(dev); - if (err) - goto free_skbs; - bcom_enable(priv->rx_dmatsk); bcom_enable(priv->tx_dmatsk); @@ -324,16 +260,18 @@ static int mpc52xx_fec_open(struct net_device *dev) return 0; - free_skbs: - mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); - free_irqs: free_irq(priv->t_irq, dev); free_2irqs: free_irq(priv->r_irq, dev); free_ctrl_irq: free_irq(dev->irq, dev); - out: + free_phy: + if (priv->phydev) { + phy_stop(priv->phydev); + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } return err; } @@ -352,7 +290,12 @@ static int mpc52xx_fec_close(struct net_device *dev) free_irq(priv->r_irq, dev); free_irq(priv->t_irq, dev); - mpc52xx_fec_phy_stop(dev); + if (priv->phydev) { + /* power down phy */ + phy_stop(priv->phydev); + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } return 0; } @@ -696,7 +639,7 @@ static void mpc52xx_fec_hw_init(struct net_device *dev) /* set phy speed. * this can't be done in phy driver, since it needs to be called * before fec stuff (even on resume) */ - mpc52xx_fec_phy_hw_init(priv); + out_be32(&fec->mii_speed, priv->mdio_speed); } /** @@ -732,7 +675,7 @@ static void mpc52xx_fec_start(struct net_device *dev) rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ rcntrl |= FEC_RCNTRL_FCE; - if (priv->phy_addr != FEC5200_PHYADDR_7WIRE) + if (!priv->seven_wire_mode) rcntrl |= FEC_RCNTRL_MII_MODE; if (priv->duplex == DUPLEX_FULL) @@ -798,8 +741,6 @@ static void mpc52xx_fec_stop(struct net_device *dev) /* Stop FEC */ out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN); - - return; } /* reset fec and bestcomm tasks */ @@ -817,9 +758,11 @@ static void mpc52xx_fec_reset(struct net_device *dev) mpc52xx_fec_hw_init(dev); - phy_stop(priv->phydev); - phy_write(priv->phydev, MII_BMCR, BMCR_RESET); - phy_start(priv->phydev); + if (priv->phydev) { + phy_stop(priv->phydev); + phy_write(priv->phydev, MII_BMCR, BMCR_RESET); + phy_start(priv->phydev); + } bcom_fec_rx_reset(priv->rx_dmatsk); bcom_fec_tx_reset(priv->tx_dmatsk); @@ -919,8 +862,6 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) struct net_device *ndev; struct mpc52xx_fec_priv *priv = NULL; struct resource mem; - struct device_node *phy_node; - const phandle *phy_handle; const u32 *prop; int prop_size; @@ -933,6 +874,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) return -ENOMEM; priv = netdev_priv(ndev); + priv->ndev = ndev; /* Reserve FEC control zone */ rv = of_address_to_resource(op->node, 0, &mem); @@ -956,6 +898,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops; ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; ndev->base_addr = mem.start; + SET_NETDEV_DEV(ndev, &op->dev); spin_lock_init(&priv->lock); @@ -1003,14 +946,9 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) */ /* Start with safe defaults for link connection */ - priv->phy_addr = FEC5200_PHYADDR_NONE; priv->speed = 100; priv->duplex = DUPLEX_HALF; - priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; - - /* the 7-wire property means don't use MII mode */ - if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) - priv->phy_addr = FEC5200_PHYADDR_7WIRE; + priv->mdio_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; /* The current speed preconfigures the speed of the MII link */ prop = of_get_property(op->node, "current-speed", &prop_size); @@ -1019,43 +957,23 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF; } - /* If there is a phy handle, setup link to that phy */ - phy_handle = of_get_property(op->node, "phy-handle", &prop_size); - if (phy_handle && (prop_size >= sizeof(phandle))) { - phy_node = of_find_node_by_phandle(*phy_handle); - prop = of_get_property(phy_node, "reg", &prop_size); - if (prop && (prop_size >= sizeof(u32))) - if ((*prop >= 0) && (*prop < PHY_MAX_ADDR)) - priv->phy_addr = *prop; - of_node_put(phy_node); + /* If there is a phy handle, then get the PHY node */ + priv->phy_node = of_parse_phandle(op->node, "phy-handle", 0); + + /* the 7-wire property means don't use MII mode */ + if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) { + priv->seven_wire_mode = 1; + dev_info(&ndev->dev, "using 7-wire PHY mode\n"); } /* Hardware init */ mpc52xx_fec_hw_init(ndev); - mpc52xx_fec_reset_stats(ndev); - SET_NETDEV_DEV(ndev, &op->dev); - - /* Register the new network device */ rv = register_netdev(ndev); if (rv < 0) goto probe_error; - /* Now report the link setup */ - switch (priv->phy_addr) { - case FEC5200_PHYADDR_NONE: - dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n", - priv->speed, priv->duplex ? 'F' : 'H'); - break; - case FEC5200_PHYADDR_7WIRE: - dev_info(&ndev->dev, "using 7-wire PHY mode\n"); - break; - default: - dev_info(&ndev->dev, "Using PHY at MDIO address %i\n", - priv->phy_addr); - } - /* We're done ! */ dev_set_drvdata(&op->dev, ndev); @@ -1065,6 +983,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) /* Error handling - free everything that might be allocated */ probe_error: + if (priv->phy_node) + of_node_put(priv->phy_node); + priv->phy_node = NULL; + irq_dispose_mapping(ndev->irq); if (priv->rx_dmatsk) @@ -1093,6 +1015,10 @@ mpc52xx_fec_remove(struct of_device *op) unregister_netdev(ndev); + if (priv->phy_node) + of_node_put(priv->phy_node); + priv->phy_node = NULL; + irq_dispose_mapping(ndev->irq); bcom_fec_rx_release(priv->rx_dmatsk); diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index dd9bfa4..fec9f245 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -14,12 +14,14 @@ #include #include #include +#include #include #include #include "fec_mpc52xx.h" struct mpc52xx_fec_mdio_priv { struct mpc52xx_fec __iomem *regs; + int mdio_irqs[PHY_MAX_ADDR]; }; static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id, @@ -27,7 +29,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id, { struct mpc52xx_fec_mdio_priv *priv = bus->priv; struct mpc52xx_fec __iomem *fec; - int tries = 100; + int tries = 3; value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; @@ -38,7 +40,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id, /* wait for it to finish, this takes about 23 us on lite5200b */ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries) - udelay(5); + msleep(1); if (!tries) return -ETIMEDOUT; @@ -64,7 +66,6 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, { struct device *dev = &of->dev; struct device_node *np = of->node; - struct device_node *child = NULL; struct mii_bus *bus; struct mpc52xx_fec_mdio_priv *priv; struct resource res = {}; @@ -85,22 +86,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, bus->write = mpc52xx_fec_mdio_write; /* setup irqs */ - bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL); - if (bus->irq == NULL) { - err = -ENOMEM; - goto out_free; - } - for (i=0; iirq[i] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - if (irq != NO_IRQ) { - const u32 *id = of_get_property(child, "reg", NULL); - if (id) - bus->irq[*id] = irq; - } - } + bus->irq = priv->mdio_irqs; /* setup registers */ err = of_address_to_resource(np, 0, &res); @@ -122,7 +108,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1); - err = mdiobus_register(bus); + err = of_mdiobus_register(bus, np); if (err) goto out_unmap; -- cgit v0.10.2 From 324931ba21858c34787dee7d222388ef3fb41ee0 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:07 +0000 Subject: net: rework fsl_pq_mdio driver to use of_mdio infrastructure This patch simplifies the driver by making use of more common code. Tested on Freescale MPC8349emitxgp eval board Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index aa1eb88..b01daa1 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -154,44 +155,6 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus) return 0; } -/* Allocate an array which provides irq #s for each PHY on the given bus */ -static int *create_irq_map(struct device_node *np) -{ - int *irqs; - int i; - struct device_node *child = NULL; - - irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); - - if (!irqs) - return NULL; - - for (i = 0; i < PHY_MAX_ADDR; i++) - irqs[i] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - const u32 *id; - - if (irq == NO_IRQ) - continue; - - id = of_get_property(child, "reg", NULL); - - if (!id) - continue; - - if (*id < PHY_MAX_ADDR && *id >= 0) - irqs[*id] = irq; - else - printk(KERN_WARNING "%s: " - "%d is not a valid PHY address\n", - np->full_name, *id); - } - - return irqs; -} - void fsl_pq_mdio_bus_name(char *name, struct device_node *np) { const u32 *addr; @@ -315,7 +278,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, new_bus->priv = (void __force *)regs; - new_bus->irq = create_irq_map(np); + new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); if (NULL == new_bus->irq) { err = -ENOMEM; @@ -384,15 +347,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, out_be32(tbipa, tbiaddr); - /* - * The TBIPHY-only buses will find PHYs at every address, - * so we mask them all but the TBI - */ - if (of_device_is_compatible(np, "fsl,gianfar-tbi")) - new_bus->phy_mask = ~(1 << tbiaddr); - - err = mdiobus_register(new_bus); - + err = of_mdiobus_register(new_bus, np); if (err) { printk (KERN_ERR "%s: Cannot register as MDIO bus\n", new_bus->name); -- cgit v0.10.2 From fe192a49118f5b1272317d60c7930ece4e13ae49 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:12 +0000 Subject: net: Rework gianfar driver to use of_mdio infrastructure. This patch simplifies the driver by making use of more common code. Tested on Freescale MPC8349emitxgp eval board Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index b2c4967..dae1437 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -168,17 +169,13 @@ static inline int gfar_uses_fcb(struct gfar_private *priv) static int gfar_of_init(struct net_device *dev) { - struct device_node *phy, *mdio; - const unsigned int *id; const char *model; const char *ctype; const void *mac_addr; - const phandle *ph; u64 addr, size; int err = 0; struct gfar_private *priv = netdev_priv(dev); struct device_node *np = priv->node; - char bus_name[MII_BUS_ID_SIZE]; const u32 *stash; const u32 *stash_len; const u32 *stash_idx; @@ -264,8 +261,8 @@ static int gfar_of_init(struct net_device *dev) if (of_get_property(np, "fsl,magic-packet", NULL)) priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; - ph = of_get_property(np, "phy-handle", NULL); - if (ph == NULL) { + priv->phy_node = of_parse_phandle(np, "phy-handle", 0); + if (!priv->phy_node) { u32 *fixed_link; fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL); @@ -273,57 +270,10 @@ static int gfar_of_init(struct net_device *dev) err = -ENODEV; goto err_out; } - - snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), - PHY_ID_FMT, "0", fixed_link[0]); - } else { - phy = of_find_node_by_phandle(*ph); - - if (phy == NULL) { - err = -ENODEV; - goto err_out; - } - - mdio = of_get_parent(phy); - - id = of_get_property(phy, "reg", NULL); - - of_node_put(phy); - - fsl_pq_mdio_bus_name(bus_name, mdio); - of_node_put(mdio); - snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x", - bus_name, *id); } /* Find the TBI PHY. If it's not there, we don't support SGMII */ - ph = of_get_property(np, "tbi-handle", NULL); - if (ph) { - struct device_node *tbi = of_find_node_by_phandle(*ph); - struct of_device *ofdev; - struct mii_bus *bus; - - if (!tbi) - return 0; - - mdio = of_get_parent(tbi); - if (!mdio) - return 0; - - ofdev = of_find_device_by_node(mdio); - - of_node_put(mdio); - - id = of_get_property(tbi, "reg", NULL); - if (!id) - return 0; - - of_node_put(tbi); - - bus = dev_get_drvdata(&ofdev->dev); - - priv->tbiphy = bus->phy_map[*id]; - } + priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0); return 0; @@ -529,6 +479,10 @@ static int gfar_probe(struct of_device *ofdev, register_fail: iounmap(priv->regs); regs_fail: + if (priv->phy_node) + of_node_put(priv->phy_node); + if (priv->tbi_node) + of_node_put(priv->tbi_node); free_netdev(dev); return err; } @@ -537,6 +491,11 @@ static int gfar_remove(struct of_device *ofdev) { struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); + if (priv->phy_node) + of_node_put(priv->phy_node); + if (priv->tbi_node) + of_node_put(priv->tbi_node); + dev_set_drvdata(&ofdev->dev, NULL); iounmap(priv->regs); @@ -690,7 +649,6 @@ static int init_phy(struct net_device *dev) uint gigabit_support = priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0; - struct phy_device *phydev; phy_interface_t interface; priv->oldlink = 0; @@ -699,21 +657,21 @@ static int init_phy(struct net_device *dev) interface = gfar_get_interface(dev); - phydev = phy_connect(dev, priv->phy_bus_id, &adjust_link, 0, interface); + if (priv->phy_node) { + priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link, + 0, interface); + if (!priv->phydev) { + dev_err(&dev->dev, "error: Could not attach to PHY\n"); + return -ENODEV; + } + } if (interface == PHY_INTERFACE_MODE_SGMII) gfar_configure_serdes(dev); - if (IS_ERR(phydev)) { - printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(phydev); - } - /* Remove any features not supported by the controller */ - phydev->supported &= (GFAR_SUPPORTED | gigabit_support); - phydev->advertising = phydev->supported; - - priv->phydev = phydev; + priv->phydev->supported &= (GFAR_SUPPORTED | gigabit_support); + priv->phydev->advertising = priv->phydev->supported; return 0; } @@ -730,10 +688,17 @@ static int init_phy(struct net_device *dev) static void gfar_configure_serdes(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct phy_device *tbiphy; + + if (!priv->tbi_node) { + dev_warn(&dev->dev, "error: SGMII mode requires that the " + "device tree specify a tbi-handle\n"); + return; + } - if (!priv->tbiphy) { - printk(KERN_WARNING "SGMII mode requires that the device " - "tree specify a tbi-handle\n"); + tbiphy = of_phy_find_device(priv->tbi_node); + if (!tbiphy) { + dev_err(&dev->dev, "error: Could not get TBI device\n"); return; } @@ -743,17 +708,17 @@ static void gfar_configure_serdes(struct net_device *dev) * everything for us? Resetting it takes the link down and requires * several seconds for it to come back. */ - if (phy_read(priv->tbiphy, MII_BMSR) & BMSR_LSTATUS) + if (phy_read(tbiphy, MII_BMSR) & BMSR_LSTATUS) return; /* Single clk mode, mii mode off(for serdes communication) */ - phy_write(priv->tbiphy, MII_TBICON, TBICON_CLK_SELECT); + phy_write(tbiphy, MII_TBICON, TBICON_CLK_SELECT); - phy_write(priv->tbiphy, MII_ADVERTISE, + phy_write(tbiphy, MII_ADVERTISE, ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM); - phy_write(priv->tbiphy, MII_BMCR, BMCR_ANENABLE | + phy_write(tbiphy, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000); } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 0642d52..91317bc 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -779,7 +779,8 @@ struct gfar_private { spinlock_t bflock; phy_interface_t interface; - char phy_bus_id[BUS_ID_SIZE]; + struct device_node *phy_node; + struct device_node *tbi_node; u32 device_flags; unsigned char rx_csum_enable:1, extended_hash:1, @@ -793,7 +794,6 @@ struct gfar_private { /* PHY stuff */ struct phy_device *phydev; - struct phy_device *tbiphy; struct mii_bus *mii_bus; int oldspeed; int oldduplex; -- cgit v0.10.2 From 1dd2d06c0459a2f1bffc56765e3cc57427818867 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:17 +0000 Subject: net: Rework pasemi_mac driver to use of_mdio infrastructure This patch simplifies the driver by making use of more common code. Signed-off-by: Grant Likely Tested-by: Olof Johansson Acked-by: Olof Johansson Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index 75cc165..3bf5467 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #define DELAY 1 @@ -39,6 +39,7 @@ static void __iomem *gpio_regs; struct gpio_priv { int mdc_pin; int mdio_pin; + int mdio_irqs[PHY_MAX_ADDR]; }; #define MDC_PIN(bus) (((struct gpio_priv *)bus->priv)->mdc_pin) @@ -218,12 +219,11 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { struct device *dev = &ofdev->dev; - struct device_node *phy_dn, *np = ofdev->node; + struct device_node *np = ofdev->node; struct mii_bus *new_bus; struct gpio_priv *priv; const unsigned int *prop; int err; - int i; err = -ENOMEM; priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL); @@ -244,27 +244,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop); new_bus->priv = priv; - new_bus->phy_mask = 0; - - new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - - if (!new_bus->irq) - goto out_free_bus; - - for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = NO_IRQ; - - for (phy_dn = of_get_next_child(np, NULL); - phy_dn != NULL; - phy_dn = of_get_next_child(np, phy_dn)) { - const unsigned int *ip, *regp; - - ip = of_get_property(phy_dn, "interrupts", NULL); - regp = of_get_property(phy_dn, "reg", NULL); - if (!ip || !regp || *regp >= PHY_MAX_ADDR) - continue; - new_bus->irq[*regp] = irq_create_mapping(NULL, *ip); - } + new_bus->irq = priv->mdio_irqs; prop = of_get_property(np, "mdc-pin", NULL); priv->mdc_pin = *prop; @@ -275,7 +255,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, new_bus->parent = dev; dev_set_drvdata(dev, new_bus); - err = mdiobus_register(new_bus); + err = of_mdiobus_register(new_bus, np); if (err != 0) { printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n", @@ -286,8 +266,6 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, return 0; out_free_irq: - kfree(new_bus->irq); -out_free_bus: kfree(new_bus); out_free_priv: kfree(priv); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 067caba..6ea4539 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1086,34 +1087,17 @@ static int pasemi_mac_phy_init(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); struct device_node *dn, *phy_dn; struct phy_device *phydev; - unsigned int phy_id; - const phandle *ph; - const unsigned int *prop; - struct resource r; - int ret; dn = pci_device_to_OF_node(mac->pdev); - ph = of_get_property(dn, "phy-handle", NULL); - if (!ph) - return -ENODEV; - phy_dn = of_find_node_by_phandle(*ph); - - prop = of_get_property(phy_dn, "reg", NULL); - ret = of_address_to_resource(phy_dn->parent, 0, &r); - if (ret) - goto err; - - phy_id = *prop; - snprintf(mac->phy_id, sizeof(mac->phy_id), "%x:%02x", - (int)r.start, phy_id); - + phy_dn = of_parse_phandle(dn, "phy-handle", 0); of_node_put(phy_dn); mac->link = 0; mac->speed = 0; mac->duplex = -1; - phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII); + phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0, + PHY_INTERFACE_MODE_SGMII); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); @@ -1123,10 +1107,6 @@ static int pasemi_mac_phy_init(struct net_device *dev) mac->phydev = phydev; return 0; - -err: - of_node_put(phy_dn); - return -ENODEV; } diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 1a115ec..e2f4efa 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -100,7 +100,6 @@ struct pasemi_mac { int duplex; unsigned int msg_enable; - char phy_id[BUS_ID_SIZE]; }; /* Software status descriptor (ring_info) */ -- cgit v0.10.2 From 0b9da337dca972e7a4144e298ec3adb8f244d4a4 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:23 +0000 Subject: net: Rework ucc_geth driver to use of_mdio infrastructure This patch simplifies the driver by making use of more common code. Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 811f97c..a536284 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -1543,12 +1544,14 @@ static int init_phy(struct net_device *dev) priv->oldspeed = 0; priv->oldduplex = -1; - phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0, - priv->phy_interface); + if (!ug_info->phy_node) + return 0; - if (IS_ERR(phydev)) { + phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0, + priv->phy_interface); + if (!phydev) { printk("%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(phydev); + return -ENODEV; } phydev->supported &= (ADVERTISED_10baseT_Half | @@ -3511,14 +3514,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma { struct device *device = &ofdev->dev; struct device_node *np = ofdev->node; - struct device_node *mdio; struct net_device *dev = NULL; struct ucc_geth_private *ugeth = NULL; struct ucc_geth_info *ug_info; struct resource res; struct device_node *phy; int err, ucc_num, max_speed = 0; - const phandle *ph; const u32 *fixed_link; const unsigned int *prop; const char *sprop; @@ -3618,45 +3619,21 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); fixed_link = of_get_property(np, "fixed-link", NULL); if (fixed_link) { - snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), - PHY_ID_FMT, "0", fixed_link[0]); phy = NULL; } else { - char bus_name[MII_BUS_ID_SIZE]; - - ph = of_get_property(np, "phy-handle", NULL); - phy = of_find_node_by_phandle(*ph); - + phy = of_parse_phandle(np, "phy-handle", 0); if (phy == NULL) return -ENODEV; - - /* set the PHY address */ - prop = of_get_property(phy, "reg", NULL); - if (prop == NULL) - return -1; - - /* Set the bus id */ - mdio = of_get_parent(phy); - - if (mdio == NULL) - return -ENODEV; - - err = of_address_to_resource(mdio, 0, &res); - - if (err) { - of_node_put(mdio); - return err; - } - fsl_pq_mdio_bus_name(bus_name, mdio); - of_node_put(mdio); - snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), - "%s:%02x", bus_name, *prop); } + ug_info->phy_node = phy; /* get the phy interface type, or default to MII */ prop = of_get_property(np, "phy-connection-type", NULL); if (!prop) { /* handle interface property present in old trees */ + if (!phy) + return -ENODEV; + prop = of_get_property(phy, "interface", NULL); if (prop != NULL) { phy_interface = enet_to_phy_interface[*prop]; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 6027647..dca628a 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1099,7 +1099,7 @@ struct ucc_geth_info { u32 eventRegMask; u16 pausePeriod; u16 extensionField; - char phy_bus_id[BUS_ID_SIZE]; + struct device_node *phy_node; u8 weightfactor[NUM_TX_QUEUES]; u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; -- cgit v0.10.2 From fd84f0ee50d3abedd11454b016823aa3ffcdc919 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:28 +0000 Subject: powerpc/82xx: Rework Embedded Planet ep8248e platform to use of_mdio This patch modifies the bitbanged MDIO driver in the ep8248e platform code to use the common of_mdio infrastructure. Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index 0eb6d7f6..51fcae4 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -115,7 +116,7 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, struct mii_bus *bus; struct resource res; struct device_node *node; - int ret, i; + int ret; node = of_get_parent(ofdev->node); of_node_put(node); @@ -130,17 +131,13 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, if (!bus) return -ENOMEM; - bus->phy_mask = 0; bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - for (i = 0; i < PHY_MAX_ADDR; i++) - bus->irq[i] = -1; - bus->name = "ep8248e-mdio-bitbang"; bus->parent = &ofdev->dev; snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); - return mdiobus_register(bus); + return of_mdiobus_register(bus, ofdev->node); } static int ep8248e_mdio_remove(struct of_device *ofdev) -- cgit v0.10.2 From aa73832c5a80d6c52c69b18af858d88fa595dd3c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:33 +0000 Subject: net: Rework fs_enet driver to use of_mdio infrastructure This patch simplifies the driver by making use of more common code. Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a9cbc31..9604aae 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -752,9 +754,10 @@ static int fs_init_phy(struct net_device *dev) fep->oldlink = 0; fep->oldspeed = 0; fep->oldduplex = -1; - if(fep->fpi->bus_id) - phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0, - PHY_INTERFACE_MODE_MII); + if(fep->fpi->phy_node) + phydev = of_phy_connect(dev, fep->fpi->phy_node, + &fs_adjust_link, 0, + PHY_INTERFACE_MODE_MII); else { printk("No phy bus ID specified in BSP code\n"); return -EINVAL; @@ -962,57 +965,6 @@ static void cleanup_immap(void) /**************************************************************************************/ -static int __devinit find_phy(struct device_node *np, - struct fs_platform_info *fpi) -{ - struct device_node *phynode, *mdionode; - int ret = 0, len, bus_id; - const u32 *data; - - data = of_get_property(np, "fixed-link", NULL); - if (data) { - snprintf(fpi->bus_id, 16, "%x:%02x", 0, *data); - return 0; - } - - data = of_get_property(np, "phy-handle", &len); - if (!data || len != 4) - return -EINVAL; - - phynode = of_find_node_by_phandle(*data); - if (!phynode) - return -EINVAL; - - data = of_get_property(phynode, "reg", &len); - if (!data || len != 4) { - ret = -EINVAL; - goto out_put_phy; - } - - mdionode = of_get_parent(phynode); - if (!mdionode) { - ret = -EINVAL; - goto out_put_phy; - } - - bus_id = of_get_gpio(mdionode, 0); - if (bus_id < 0) { - struct resource res; - ret = of_address_to_resource(mdionode, 0, &res); - if (ret) - goto out_put_mdio; - bus_id = res.start; - } - - snprintf(fpi->bus_id, 16, "%x:%02x", bus_id, *data); - -out_put_mdio: - of_node_put(mdionode); -out_put_phy: - of_node_put(phynode); - return ret; -} - #ifdef CONFIG_FS_ENET_HAS_FEC #define IS_FEC(match) ((match)->data == &fs_fec_ops) #else @@ -1062,9 +1014,9 @@ static int __devinit fs_enet_probe(struct of_device *ofdev, fpi->rx_copybreak = 240; fpi->use_napi = 1; fpi->napi_weight = 17; - - ret = find_phy(ofdev->node, fpi); - if (ret) + fpi->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0); + if ((!fpi->phy_node) && (!of_get_property(ofdev->node, "fixed-link", + NULL))) goto out_free_fpi; privsize = sizeof(*fep) + @@ -1136,6 +1088,7 @@ out_cleanup_data: out_free_dev: free_netdev(ndev); dev_set_drvdata(&ofdev->dev, NULL); + of_node_put(fpi->phy_node); out_free_fpi: kfree(fpi); return ret; @@ -1151,7 +1104,7 @@ static int fs_enet_remove(struct of_device *ofdev) fep->ops->free_bd(ndev); fep->ops->cleanup_data(ndev); dev_set_drvdata(fep->dev, NULL); - + of_node_put(fep->fpi->phy_node); free_netdev(ndev); return 0; } diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 49b6645..93b481b 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "fs_enet.h" @@ -149,31 +150,12 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, return 0; } -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) -{ - const u32 *data; - int len, id, irq; - - data = of_get_property(np, "reg", &len); - if (!data || len != 4) - return; - - id = *data; - bus->phy_mask &= ~(1 << id); - - irq = of_irq_to_resource(np, 0, NULL); - if (irq != NO_IRQ) - bus->irq[id] = irq; -} - static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = NULL; struct mii_bus *new_bus; struct bb_info *bitbang; int ret = -ENOMEM; - int i; bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); if (!bitbang) @@ -196,17 +178,10 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!new_bus->irq) goto out_unmap_regs; - for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = -1; - - while ((np = of_get_next_child(ofdev->node, np))) - if (!strcmp(np->type, "ethernet-phy")) - add_phy(new_bus, np); - new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); - ret = mdiobus_register(new_bus); + ret = of_mdiobus_register(new_bus, ofdev->node); if (ret) goto out_free_irqs; diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 61aaae4..75a0999 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -100,23 +100,6 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) return 0; } -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) -{ - const u32 *data; - int len, id, irq; - - data = of_get_property(np, "reg", &len); - if (!data || len != 4) - return; - - id = *data; - bus->phy_mask &= ~(1 << id); - - irq = of_irq_to_resource(np, 0, NULL); - if (irq != NO_IRQ) - bus->irq[id] = irq; -} - static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { @@ -163,17 +146,10 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!new_bus->irq) goto out_unmap_regs; - for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = -1; - - while ((np = of_get_next_child(ofdev->node, np))) - if (!strcmp(np->type, "ethernet-phy")) - add_phy(new_bus, np); - new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); - ret = mdiobus_register(new_bus); + ret = of_mdiobus_register(new_bus, ofdev->node); if (ret) goto out_free_irqs; diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h index 8300cab..51b7934 100644 --- a/include/linux/fs_enet_pd.h +++ b/include/linux/fs_enet_pd.h @@ -17,6 +17,7 @@ #define FS_ENET_PD_H #include +#include #include #define FS_ENET_NAME "fs_enet" @@ -130,10 +131,7 @@ struct fs_platform_info { u32 device_flags; - int phy_addr; /* the phy address (-1 no phy) */ - char bus_id[16]; - int phy_irq; /* the phy irq (if it exists) */ - + struct device_node *phy_node; const struct fs_mii_bus_info *bus_info; int rx_ring, tx_ring; /* number of buffers on rx */ -- cgit v0.10.2 From 92744989533cbe85e8057935d230e128810168ce Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:39 +0000 Subject: net: add Xilinx ll_temac device driver This patch adds support for the Xilinx ll_temac 10/100/1000 Ethernet device. The ll_temac ipcore is typically used on Xilinx Virtex and Spartan designs attached to either a PowerPC 4xx or Microblaze processor. At the present moment, this driver only works with Virtex5 PowerPC designs because it assumes DCR is used to access the DMA registers. However, the low level access to DMA registers is abstracted and it should be easy to adapt for the other implementations. I'm posting this driver now as an RFC. There are still some things that need to be tightened up, but it does appear to be stable. Derived from driver code written by Yoshio Kashiwagi and David H. Lynch Jr. Tested on Xilinx ML507 eval board with Base System Builder generated FPGA design. Signed-off-by: Grant Likely Acked-by: Andy Fleming Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 214a92d..3320e77 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2362,6 +2362,14 @@ config MV643XX_ETH Some boards that use the Discovery chipset are the Momenco Ocelot C and Jaguar ATX and Pegasos II. +config XILINX_LL_TEMAC + tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" + select PHYLIB + depends on PPC_DCR_NATIVE + help + This driver supports the Xilinx 10/100/1000 LocalLink TEMAC + core used in Xilinx Spartan and Virtex FPGAs + config QLA3XXX tristate "QLogic QLA3XXX Network Driver Support" depends on PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1fc4602..80420f6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -134,6 +134,8 @@ obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o +ll_temac-objs := ll_temac_main.o ll_temac_mdio.o +obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o obj-$(CONFIG_QLA3XXX) += qla3xxx.o obj-$(CONFIG_QLGE) += qlge/ diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h new file mode 100644 index 0000000..1af66a1 --- /dev/null +++ b/drivers/net/ll_temac.h @@ -0,0 +1,374 @@ + +#ifndef XILINX_LL_TEMAC_H +#define XILINX_LL_TEMAC_H + +#include +#include +#include +#include +#include + +/* packet size info */ +#define XTE_HDR_SIZE 14 /* size of Ethernet header */ +#define XTE_TRL_SIZE 4 /* size of Ethernet trailer (FCS) */ +#define XTE_JUMBO_MTU 9000 +#define XTE_MAX_JUMBO_FRAME_SIZE (XTE_JUMBO_MTU + XTE_HDR_SIZE + XTE_TRL_SIZE) + +/* Configuration options */ + +/* Accept all incoming packets. + * This option defaults to disabled (cleared) */ +#define XTE_OPTION_PROMISC (1 << 0) +/* Jumbo frame support for Tx & Rx. + * This option defaults to disabled (cleared) */ +#define XTE_OPTION_JUMBO (1 << 1) +/* VLAN Rx & Tx frame support. + * This option defaults to disabled (cleared) */ +#define XTE_OPTION_VLAN (1 << 2) +/* Enable recognition of flow control frames on Rx + * This option defaults to enabled (set) */ +#define XTE_OPTION_FLOW_CONTROL (1 << 4) +/* Strip FCS and PAD from incoming frames. + * Note: PAD from VLAN frames is not stripped. + * This option defaults to disabled (set) */ +#define XTE_OPTION_FCS_STRIP (1 << 5) +/* Generate FCS field and add PAD automatically for outgoing frames. + * This option defaults to enabled (set) */ +#define XTE_OPTION_FCS_INSERT (1 << 6) +/* Enable Length/Type error checking for incoming frames. When this option is +set, the MAC will filter frames that have a mismatched type/length field +and if XTE_OPTION_REPORT_RXERR is set, the user is notified when these +types of frames are encountered. When this option is cleared, the MAC will +allow these types of frames to be received. +This option defaults to enabled (set) */ +#define XTE_OPTION_LENTYPE_ERR (1 << 7) +/* Enable the transmitter. + * This option defaults to enabled (set) */ +#define XTE_OPTION_TXEN (1 << 11) +/* Enable the receiver +* This option defaults to enabled (set) */ +#define XTE_OPTION_RXEN (1 << 12) + +/* Default options set when device is initialized or reset */ +#define XTE_OPTION_DEFAULTS \ + (XTE_OPTION_TXEN | \ + XTE_OPTION_FLOW_CONTROL | \ + XTE_OPTION_RXEN) + +/* XPS_LL_TEMAC SDMA registers definition */ + +#define TX_NXTDESC_PTR 0x00 /* r */ +#define TX_CURBUF_ADDR 0x01 /* r */ +#define TX_CURBUF_LENGTH 0x02 /* r */ +#define TX_CURDESC_PTR 0x03 /* rw */ +#define TX_TAILDESC_PTR 0x04 /* rw */ +#define TX_CHNL_CTRL 0x05 /* rw */ +/* + 0:7 24:31 IRQTimeout + 8:15 16:23 IRQCount + 16:20 11:15 Reserved + 21 10 0 + 22 9 UseIntOnEnd + 23 8 LdIRQCnt + 24 7 IRQEn + 25:28 3:6 Reserved + 29 2 IrqErrEn + 30 1 IrqDlyEn + 31 0 IrqCoalEn +*/ +#define CHNL_CTRL_IRQ_IOE (1 << 9) +#define CHNL_CTRL_IRQ_EN (1 << 7) +#define CHNL_CTRL_IRQ_ERR_EN (1 << 2) +#define CHNL_CTRL_IRQ_DLY_EN (1 << 1) +#define CHNL_CTRL_IRQ_COAL_EN (1 << 0) +#define TX_IRQ_REG 0x06 /* rw */ +/* + 0:7 24:31 DltTmrValue + 8:15 16:23 ClscCntrValue + 16:17 14:15 Reserved + 18:21 10:13 ClscCnt + 22:23 8:9 DlyCnt + 24:28 3::7 Reserved + 29 2 ErrIrq + 30 1 DlyIrq + 31 0 CoalIrq + */ +#define TX_CHNL_STS 0x07 /* r */ +/* + 0:9 22:31 Reserved + 10 21 TailPErr + 11 20 CmpErr + 12 19 AddrErr + 13 18 NxtPErr + 14 17 CurPErr + 15 16 BsyWr + 16:23 8:15 Reserved + 24 7 Error + 25 6 IOE + 26 5 SOE + 27 4 Cmplt + 28 3 SOP + 29 2 EOP + 30 1 EngBusy + 31 0 Reserved +*/ + +#define RX_NXTDESC_PTR 0x08 /* r */ +#define RX_CURBUF_ADDR 0x09 /* r */ +#define RX_CURBUF_LENGTH 0x0a /* r */ +#define RX_CURDESC_PTR 0x0b /* rw */ +#define RX_TAILDESC_PTR 0x0c /* rw */ +#define RX_CHNL_CTRL 0x0d /* rw */ +/* + 0:7 24:31 IRQTimeout + 8:15 16:23 IRQCount + 16:20 11:15 Reserved + 21 10 0 + 22 9 UseIntOnEnd + 23 8 LdIRQCnt + 24 7 IRQEn + 25:28 3:6 Reserved + 29 2 IrqErrEn + 30 1 IrqDlyEn + 31 0 IrqCoalEn + */ +#define RX_IRQ_REG 0x0e /* rw */ +#define IRQ_COAL (1 << 0) +#define IRQ_DLY (1 << 1) +#define IRQ_ERR (1 << 2) +#define IRQ_DMAERR (1 << 7) /* this is not documented ??? */ +/* + 0:7 24:31 DltTmrValue + 8:15 16:23 ClscCntrValue + 16:17 14:15 Reserved + 18:21 10:13 ClscCnt + 22:23 8:9 DlyCnt + 24:28 3::7 Reserved +*/ +#define RX_CHNL_STS 0x0f /* r */ +#define CHNL_STS_ENGBUSY (1 << 1) +#define CHNL_STS_EOP (1 << 2) +#define CHNL_STS_SOP (1 << 3) +#define CHNL_STS_CMPLT (1 << 4) +#define CHNL_STS_SOE (1 << 5) +#define CHNL_STS_IOE (1 << 6) +#define CHNL_STS_ERR (1 << 7) + +#define CHNL_STS_BSYWR (1 << 16) +#define CHNL_STS_CURPERR (1 << 17) +#define CHNL_STS_NXTPERR (1 << 18) +#define CHNL_STS_ADDRERR (1 << 19) +#define CHNL_STS_CMPERR (1 << 20) +#define CHNL_STS_TAILERR (1 << 21) +/* + 0:9 22:31 Reserved + 10 21 TailPErr + 11 20 CmpErr + 12 19 AddrErr + 13 18 NxtPErr + 14 17 CurPErr + 15 16 BsyWr + 16:23 8:15 Reserved + 24 7 Error + 25 6 IOE + 26 5 SOE + 27 4 Cmplt + 28 3 SOP + 29 2 EOP + 30 1 EngBusy + 31 0 Reserved +*/ + +#define DMA_CONTROL_REG 0x10 /* rw */ +#define DMA_CONTROL_RST (1 << 0) +#define DMA_TAIL_ENABLE (1 << 2) + +/* XPS_LL_TEMAC direct registers definition */ + +#define XTE_RAF0_OFFSET 0x00 +#define RAF0_RST (1 << 0) +#define RAF0_MCSTREJ (1 << 1) +#define RAF0_BCSTREJ (1 << 2) +#define XTE_TPF0_OFFSET 0x04 +#define XTE_IFGP0_OFFSET 0x08 +#define XTE_ISR0_OFFSET 0x0c +#define ISR0_HARDACSCMPLT (1 << 0) +#define ISR0_AUTONEG (1 << 1) +#define ISR0_RXCMPLT (1 << 2) +#define ISR0_RXREJ (1 << 3) +#define ISR0_RXFIFOOVR (1 << 4) +#define ISR0_TXCMPLT (1 << 5) +#define ISR0_RXDCMLCK (1 << 6) + +#define XTE_IPR0_OFFSET 0x10 +#define XTE_IER0_OFFSET 0x14 + +#define XTE_MSW0_OFFSET 0x20 +#define XTE_LSW0_OFFSET 0x24 +#define XTE_CTL0_OFFSET 0x28 +#define XTE_RDY0_OFFSET 0x2c + +#define XTE_RSE_MIIM_RR_MASK 0x0002 +#define XTE_RSE_MIIM_WR_MASK 0x0004 +#define XTE_RSE_CFG_RR_MASK 0x0020 +#define XTE_RSE_CFG_WR_MASK 0x0040 +#define XTE_RDY0_HARD_ACS_RDY_MASK (0x10000) + +/* XPS_LL_TEMAC indirect registers offset definition */ + +#define XTE_RXC0_OFFSET 0x00000200 /* Rx configuration word 0 */ +#define XTE_RXC1_OFFSET 0x00000240 /* Rx configuration word 1 */ +#define XTE_RXC1_RXRST_MASK (1 << 31) /* Receiver reset */ +#define XTE_RXC1_RXJMBO_MASK (1 << 30) /* Jumbo frame enable */ +#define XTE_RXC1_RXFCS_MASK (1 << 29) /* FCS not stripped */ +#define XTE_RXC1_RXEN_MASK (1 << 28) /* Receiver enable */ +#define XTE_RXC1_RXVLAN_MASK (1 << 27) /* VLAN enable */ +#define XTE_RXC1_RXHD_MASK (1 << 26) /* Half duplex */ +#define XTE_RXC1_RXLT_MASK (1 << 25) /* Length/type check disable */ + +#define XTE_TXC_OFFSET 0x00000280 /* Tx configuration */ +#define XTE_TXC_TXRST_MASK (1 << 31) /* Transmitter reset */ +#define XTE_TXC_TXJMBO_MASK (1 << 30) /* Jumbo frame enable */ +#define XTE_TXC_TXFCS_MASK (1 << 29) /* Generate FCS */ +#define XTE_TXC_TXEN_MASK (1 << 28) /* Transmitter enable */ +#define XTE_TXC_TXVLAN_MASK (1 << 27) /* VLAN enable */ +#define XTE_TXC_TXHD_MASK (1 << 26) /* Half duplex */ + +#define XTE_FCC_OFFSET 0x000002C0 /* Flow control config */ +#define XTE_FCC_RXFLO_MASK (1 << 29) /* Rx flow control enable */ +#define XTE_FCC_TXFLO_MASK (1 << 30) /* Tx flow control enable */ + +#define XTE_EMCFG_OFFSET 0x00000300 /* EMAC configuration */ +#define XTE_EMCFG_LINKSPD_MASK 0xC0000000 /* Link speed */ +#define XTE_EMCFG_HOSTEN_MASK (1 << 26) /* Host interface enable */ +#define XTE_EMCFG_LINKSPD_10 0x00000000 /* 10 Mbit LINKSPD_MASK */ +#define XTE_EMCFG_LINKSPD_100 (1 << 30) /* 100 Mbit LINKSPD_MASK */ +#define XTE_EMCFG_LINKSPD_1000 (1 << 31) /* 1000 Mbit LINKSPD_MASK */ + +#define XTE_GMIC_OFFSET 0x00000320 /* RGMII/SGMII config */ +#define XTE_MC_OFFSET 0x00000340 /* MDIO configuration */ +#define XTE_UAW0_OFFSET 0x00000380 /* Unicast address word 0 */ +#define XTE_UAW1_OFFSET 0x00000384 /* Unicast address word 1 */ + +#define XTE_MAW0_OFFSET 0x00000388 /* Multicast addr word 0 */ +#define XTE_MAW1_OFFSET 0x0000038C /* Multicast addr word 1 */ +#define XTE_AFM_OFFSET 0x00000390 /* Promiscuous mode */ +#define XTE_AFM_EPPRM_MASK (1 << 31) /* Promiscuous mode enable */ + +/* Interrupt Request status */ +#define XTE_TIS_OFFSET 0x000003A0 +#define TIS_FRIS (1 << 0) +#define TIS_MRIS (1 << 1) +#define TIS_MWIS (1 << 2) +#define TIS_ARIS (1 << 3) +#define TIS_AWIS (1 << 4) +#define TIS_CRIS (1 << 5) +#define TIS_CWIS (1 << 6) + +#define XTE_TIE_OFFSET 0x000003A4 /* Interrupt enable */ + +/** MII Mamagement Control register (MGTCR) */ +#define XTE_MGTDR_OFFSET 0x000003B0 /* MII data */ +#define XTE_MIIMAI_OFFSET 0x000003B4 /* MII control */ + +#define CNTLREG_WRITE_ENABLE_MASK 0x8000 +#define CNTLREG_EMAC1SEL_MASK 0x0400 +#define CNTLREG_ADDRESSCODE_MASK 0x03ff + +/* CDMAC descriptor status bit definitions */ + +#define STS_CTRL_APP0_ERR (1 << 31) +#define STS_CTRL_APP0_IRQONEND (1 << 30) +/* undoccumented */ +#define STS_CTRL_APP0_STOPONEND (1 << 29) +#define STS_CTRL_APP0_CMPLT (1 << 28) +#define STS_CTRL_APP0_SOP (1 << 27) +#define STS_CTRL_APP0_EOP (1 << 26) +#define STS_CTRL_APP0_ENGBUSY (1 << 25) +/* undocumented */ +#define STS_CTRL_APP0_ENGRST (1 << 24) + +#define TX_CONTROL_CALC_CSUM_MASK 1 + +#define XTE_ALIGN 32 +#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN) + +#define MULTICAST_CAM_TABLE_NUM 4 + +/* TX/RX CURDESC_PTR points to first descriptor */ +/* TX/RX TAILDESC_PTR points to last descriptor in linked list */ + +/** + * struct cdmac_bd - LocalLink buffer descriptor format + * + * app0 bits: + * 0 Error + * 1 IrqOnEnd generate an interrupt at completion of DMA op + * 2 reserved + * 3 completed Current descriptor completed + * 4 SOP TX - marks first desc/ RX marks first desct + * 5 EOP TX marks last desc/RX marks last desc + * 6 EngBusy DMA is processing + * 7 reserved + * 8:31 application specific + */ +struct cdmac_bd { + u32 next; /* Physical address of next buffer descriptor */ + u32 phys; + u32 len; + u32 app0; + u32 app1; /* TX start << 16 | insert */ + u32 app2; /* TX csum */ + u32 app3; + u32 app4; /* skb for TX length for RX */ +}; + +struct temac_local { + struct net_device *ndev; + struct device *dev; + + /* Connection to PHY device */ + struct phy_device *phy_dev; /* Pointer to PHY device */ + struct device_node *phy_node; + + /* MDIO bus data */ + struct mii_bus *mii_bus; /* MII bus reference */ + int mdio_irqs[PHY_MAX_ADDR]; /* IRQs table for MDIO bus */ + + /* IO registers and IRQs */ + void __iomem *regs; + dcr_host_t sdma_dcrs; + int tx_irq; + int rx_irq; + int emac_num; + + struct sk_buff **rx_skb; + spinlock_t rx_lock; + struct mutex indirect_mutex; + u32 options; /* Current options word */ + int last_link; + + /* Buffer descriptors */ + struct cdmac_bd *tx_bd_v; + dma_addr_t tx_bd_p; + struct cdmac_bd *rx_bd_v; + dma_addr_t rx_bd_p; + int tx_bd_ci; + int tx_bd_next; + int tx_bd_tail; + int rx_bd_ci; +}; + +/* xilinx_temac.c */ +u32 temac_ior(struct temac_local *lp, int offset); +void temac_iow(struct temac_local *lp, int offset, u32 value); +int temac_indirect_busywait(struct temac_local *lp); +u32 temac_indirect_in32(struct temac_local *lp, int reg); +void temac_indirect_out32(struct temac_local *lp, int reg, u32 value); + + +/* xilinx_temac_mdio.c */ +int temac_mdio_setup(struct temac_local *lp, struct device_node *np); +void temac_mdio_teardown(struct temac_local *lp); + +#endif /* XILINX_LL_TEMAC_H */ diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c new file mode 100644 index 0000000..96e7248 --- /dev/null +++ b/drivers/net/ll_temac_main.c @@ -0,0 +1,969 @@ +/* + * Driver for Xilinx TEMAC Ethernet device + * + * Copyright (c) 2008 Nissin Systems Co., Ltd., Yoshio Kashiwagi + * Copyright (c) 2005-2008 DLA Systems, David H. Lynch Jr. + * Copyright (c) 2008-2009 Secret Lab Technologies Ltd. + * + * This is a driver for the Xilinx ll_temac ipcore which is often used + * in the Virtex and Spartan series of chips. + * + * Notes: + * - The ll_temac hardware uses indirect access for many of the TEMAC + * registers, include the MDIO bus. However, indirect access to MDIO + * registers take considerably more clock cycles than to TEMAC registers. + * MDIO accesses are long, so threads doing them should probably sleep + * rather than busywait. However, since only one indirect access can be + * in progress at any given time, that means that *all* indirect accesses + * could end up sleeping (to wait for an MDIO access to complete). + * Fortunately none of the indirect accesses are on the 'hot' path for tx + * or rx, so this should be okay. + * + * TODO: + * - Fix driver to work on more than just Virtex5. Right now the driver + * assumes that the locallink DMA registers are accessed via DCR + * instructions. + * - Factor out locallink DMA code into separate driver + * - Fix multicast assignment. + * - Fix support for hardware checksumming. + * - Testing. Lots and lots of testing. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* needed for sizeof(tcphdr) */ +#include /* needed for sizeof(udphdr) */ +#include +#include +#include +#include + +#include "ll_temac.h" + +#define TX_BD_NUM 64 +#define RX_BD_NUM 128 + +/* --------------------------------------------------------------------- + * Low level register access functions + */ + +u32 temac_ior(struct temac_local *lp, int offset) +{ + return in_be32((u32 *)(lp->regs + offset)); +} + +void temac_iow(struct temac_local *lp, int offset, u32 value) +{ + out_be32((u32 *) (lp->regs + offset), value); +} + +int temac_indirect_busywait(struct temac_local *lp) +{ + long end = jiffies + 2; + + while (!(temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_HARD_ACS_RDY_MASK)) { + if (end - jiffies <= 0) { + WARN_ON(1); + return -ETIMEDOUT; + } + msleep(1); + } + return 0; +} + +/** + * temac_indirect_in32 + * + * lp->indirect_mutex must be held when calling this function + */ +u32 temac_indirect_in32(struct temac_local *lp, int reg) +{ + u32 val; + + if (temac_indirect_busywait(lp)) + return -ETIMEDOUT; + temac_iow(lp, XTE_CTL0_OFFSET, reg); + if (temac_indirect_busywait(lp)) + return -ETIMEDOUT; + val = temac_ior(lp, XTE_LSW0_OFFSET); + + return val; +} + +/** + * temac_indirect_out32 + * + * lp->indirect_mutex must be held when calling this function + */ +void temac_indirect_out32(struct temac_local *lp, int reg, u32 value) +{ + if (temac_indirect_busywait(lp)) + return; + temac_iow(lp, XTE_LSW0_OFFSET, value); + temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg); +} + +static u32 temac_dma_in32(struct temac_local *lp, int reg) +{ + return dcr_read(lp->sdma_dcrs, reg); +} + +static void temac_dma_out32(struct temac_local *lp, int reg, u32 value) +{ + dcr_write(lp->sdma_dcrs, reg, value); +} + +/** + * temac_dma_bd_init - Setup buffer descriptor rings + */ +static int temac_dma_bd_init(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct sk_buff *skb; + int i; + + lp->rx_skb = kzalloc(sizeof(struct sk_buff)*RX_BD_NUM, GFP_KERNEL); + /* allocate the tx and rx ring buffer descriptors. */ + /* returns a virtual addres and a physical address. */ + lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->tx_bd_v) * TX_BD_NUM, + &lp->tx_bd_p, GFP_KERNEL); + lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->rx_bd_v) * RX_BD_NUM, + &lp->rx_bd_p, GFP_KERNEL); + + memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM); + for (i = 0; i < TX_BD_NUM; i++) { + lp->tx_bd_v[i].next = lp->tx_bd_p + + sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM); + } + + memset(lp->rx_bd_v, 0, sizeof(*lp->rx_bd_v) * RX_BD_NUM); + for (i = 0; i < RX_BD_NUM; i++) { + lp->rx_bd_v[i].next = lp->rx_bd_p + + sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM); + + skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + + XTE_ALIGN, GFP_ATOMIC); + if (skb == 0) { + dev_err(&ndev->dev, "alloc_skb error %d\n", i); + return -1; + } + lp->rx_skb[i] = skb; + skb_reserve(skb, BUFFER_ALIGN(skb->data)); + /* returns physical address of skb->data */ + lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent, + skb->data, + XTE_MAX_JUMBO_FRAME_SIZE, + DMA_FROM_DEVICE); + lp->rx_bd_v[i].len = XTE_MAX_JUMBO_FRAME_SIZE; + lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND; + } + + temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 | + CHNL_CTRL_IRQ_EN | + CHNL_CTRL_IRQ_DLY_EN | + CHNL_CTRL_IRQ_COAL_EN); + /* 0x10220483 */ + /* 0x00100483 */ + temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 | + CHNL_CTRL_IRQ_EN | + CHNL_CTRL_IRQ_DLY_EN | + CHNL_CTRL_IRQ_COAL_EN | + CHNL_CTRL_IRQ_IOE); + /* 0xff010283 */ + + temac_dma_out32(lp, RX_CURDESC_PTR, lp->rx_bd_p); + temac_dma_out32(lp, RX_TAILDESC_PTR, + lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); + temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p); + + return 0; +} + +/* --------------------------------------------------------------------- + * net_device_ops + */ + +static int temac_set_mac_address(struct net_device *ndev, void *address) +{ + struct temac_local *lp = netdev_priv(ndev); + + if (address) + memcpy(ndev->dev_addr, address, ETH_ALEN); + + if (!is_valid_ether_addr(ndev->dev_addr)) + random_ether_addr(ndev->dev_addr); + + /* set up unicast MAC address filter set its mac address */ + mutex_lock(&lp->indirect_mutex); + temac_indirect_out32(lp, XTE_UAW0_OFFSET, + (ndev->dev_addr[0]) | + (ndev->dev_addr[1] << 8) | + (ndev->dev_addr[2] << 16) | + (ndev->dev_addr[3] << 24)); + /* There are reserved bits in EUAW1 + * so don't affect them Set MAC bits [47:32] in EUAW1 */ + temac_indirect_out32(lp, XTE_UAW1_OFFSET, + (ndev->dev_addr[4] & 0x000000ff) | + (ndev->dev_addr[5] << 8)); + mutex_unlock(&lp->indirect_mutex); + + return 0; +} + +static void temac_set_multicast_list(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + u32 multi_addr_msw, multi_addr_lsw, val; + int i; + + mutex_lock(&lp->indirect_mutex); + if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) + || ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { + /* + * We must make the kernel realise we had to move + * into promisc mode or we start all out war on + * the cable. If it was a promisc request the + * flag is already set. If not we assert it. + */ + ndev->flags |= IFF_PROMISC; + temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); + dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); + } else if (ndev->mc_count) { + struct dev_mc_list *mclist = ndev->mc_list; + for (i = 0; mclist && i < ndev->mc_count; i++) { + + if (i >= MULTICAST_CAM_TABLE_NUM) + break; + multi_addr_msw = ((mclist->dmi_addr[3] << 24) | + (mclist->dmi_addr[2] << 16) | + (mclist->dmi_addr[1] << 8) | + (mclist->dmi_addr[0])); + temac_indirect_out32(lp, XTE_MAW0_OFFSET, + multi_addr_msw); + multi_addr_lsw = ((mclist->dmi_addr[5] << 8) | + (mclist->dmi_addr[4]) | (i << 16)); + temac_indirect_out32(lp, XTE_MAW1_OFFSET, + multi_addr_lsw); + mclist = mclist->next; + } + } else { + val = temac_indirect_in32(lp, XTE_AFM_OFFSET); + temac_indirect_out32(lp, XTE_AFM_OFFSET, + val & ~XTE_AFM_EPPRM_MASK); + temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0); + temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0); + dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); + } + mutex_unlock(&lp->indirect_mutex); +} + +struct temac_option { + int flg; + u32 opt; + u32 reg; + u32 m_or; + u32 m_and; +} temac_options[] = { + /* Turn on jumbo packet support for both Rx and Tx */ + { + .opt = XTE_OPTION_JUMBO, + .reg = XTE_TXC_OFFSET, + .m_or = XTE_TXC_TXJMBO_MASK, + }, + { + .opt = XTE_OPTION_JUMBO, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXJMBO_MASK, + }, + /* Turn on VLAN packet support for both Rx and Tx */ + { + .opt = XTE_OPTION_VLAN, + .reg = XTE_TXC_OFFSET, + .m_or =XTE_TXC_TXVLAN_MASK, + }, + { + .opt = XTE_OPTION_VLAN, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXVLAN_MASK, + }, + /* Turn on FCS stripping on receive packets */ + { + .opt = XTE_OPTION_FCS_STRIP, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXFCS_MASK, + }, + /* Turn on FCS insertion on transmit packets */ + { + .opt = XTE_OPTION_FCS_INSERT, + .reg = XTE_TXC_OFFSET, + .m_or =XTE_TXC_TXFCS_MASK, + }, + /* Turn on length/type field checking on receive packets */ + { + .opt = XTE_OPTION_LENTYPE_ERR, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXLT_MASK, + }, + /* Turn on flow control */ + { + .opt = XTE_OPTION_FLOW_CONTROL, + .reg = XTE_FCC_OFFSET, + .m_or =XTE_FCC_RXFLO_MASK, + }, + /* Turn on flow control */ + { + .opt = XTE_OPTION_FLOW_CONTROL, + .reg = XTE_FCC_OFFSET, + .m_or =XTE_FCC_TXFLO_MASK, + }, + /* Turn on promiscuous frame filtering (all frames are received ) */ + { + .opt = XTE_OPTION_PROMISC, + .reg = XTE_AFM_OFFSET, + .m_or =XTE_AFM_EPPRM_MASK, + }, + /* Enable transmitter if not already enabled */ + { + .opt = XTE_OPTION_TXEN, + .reg = XTE_TXC_OFFSET, + .m_or =XTE_TXC_TXEN_MASK, + }, + /* Enable receiver? */ + { + .opt = XTE_OPTION_RXEN, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXEN_MASK, + }, + {} +}; + +/** + * temac_setoptions + */ +static u32 temac_setoptions(struct net_device *ndev, u32 options) +{ + struct temac_local *lp = netdev_priv(ndev); + struct temac_option *tp = &temac_options[0]; + int reg; + + mutex_lock(&lp->indirect_mutex); + while (tp->opt) { + reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or; + if (options & tp->opt) + reg |= tp->m_or; + temac_indirect_out32(lp, tp->reg, reg); + tp++; + } + lp->options |= options; + mutex_unlock(&lp->indirect_mutex); + + return (0); +} + +/* Initilize temac */ +static void temac_device_reset(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + u32 timeout; + u32 val; + + /* Perform a software reset */ + + /* 0x300 host enable bit ? */ + /* reset PHY through control register ?:1 */ + + dev_dbg(&ndev->dev, "%s()\n", __func__); + + mutex_lock(&lp->indirect_mutex); + /* Reset the receiver and wait for it to finish reset */ + temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK); + timeout = 1000; + while (temac_indirect_in32(lp, XTE_RXC1_OFFSET) & XTE_RXC1_RXRST_MASK) { + udelay(1); + if (--timeout == 0) { + dev_err(&ndev->dev, + "temac_device_reset RX reset timeout!!\n"); + break; + } + } + + /* Reset the transmitter and wait for it to finish reset */ + temac_indirect_out32(lp, XTE_TXC_OFFSET, XTE_TXC_TXRST_MASK); + timeout = 1000; + while (temac_indirect_in32(lp, XTE_TXC_OFFSET) & XTE_TXC_TXRST_MASK) { + udelay(1); + if (--timeout == 0) { + dev_err(&ndev->dev, + "temac_device_reset TX reset timeout!!\n"); + break; + } + } + + /* Disable the receiver */ + val = temac_indirect_in32(lp, XTE_RXC1_OFFSET); + temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK); + + /* Reset Local Link (DMA) */ + temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); + timeout = 1000; + while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) { + udelay(1); + if (--timeout == 0) { + dev_err(&ndev->dev, + "temac_device_reset DMA reset timeout!!\n"); + break; + } + } + temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE); + + temac_dma_bd_init(ndev); + + temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0); + temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0); + temac_indirect_out32(lp, XTE_TXC_OFFSET, 0); + temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK); + + mutex_unlock(&lp->indirect_mutex); + + /* Sync default options with HW + * but leave receiver and transmitter disabled. */ + temac_setoptions(ndev, + lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN)); + + temac_set_mac_address(ndev, NULL); + + /* Set address filter table */ + temac_set_multicast_list(ndev); + if (temac_setoptions(ndev, lp->options)) + dev_err(&ndev->dev, "Error setting TEMAC options\n"); + + /* Init Driver variable */ + ndev->trans_start = 0; +} + +void temac_adjust_link(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct phy_device *phy = lp->phy_dev; + u32 mii_speed; + int link_state; + + /* hash together the state values to decide if something has changed */ + link_state = phy->speed | (phy->duplex << 1) | phy->link; + + mutex_lock(&lp->indirect_mutex); + if (lp->last_link != link_state) { + mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET); + mii_speed &= ~XTE_EMCFG_LINKSPD_MASK; + + switch (phy->speed) { + case SPEED_1000: mii_speed |= XTE_EMCFG_LINKSPD_1000; break; + case SPEED_100: mii_speed |= XTE_EMCFG_LINKSPD_100; break; + case SPEED_10: mii_speed |= XTE_EMCFG_LINKSPD_10; break; + } + + /* Write new speed setting out to TEMAC */ + temac_indirect_out32(lp, XTE_EMCFG_OFFSET, mii_speed); + lp->last_link = link_state; + phy_print_status(phy); + } + mutex_unlock(&lp->indirect_mutex); +} + +static void temac_start_xmit_done(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct cdmac_bd *cur_p; + unsigned int stat = 0; + + cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; + stat = cur_p->app0; + + while (stat & STS_CTRL_APP0_CMPLT) { + dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len, + DMA_TO_DEVICE); + if (cur_p->app4) + dev_kfree_skb_irq((struct sk_buff *)cur_p->app4); + cur_p->app0 = 0; + + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += cur_p->len; + + lp->tx_bd_ci++; + if (lp->tx_bd_ci >= TX_BD_NUM) + lp->tx_bd_ci = 0; + + cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; + stat = cur_p->app0; + } + + netif_wake_queue(ndev); +} + +static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct cdmac_bd *cur_p; + dma_addr_t start_p, tail_p; + int ii; + unsigned long num_frag; + skb_frag_t *frag; + + num_frag = skb_shinfo(skb)->nr_frags; + frag = &skb_shinfo(skb)->frags[0]; + start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; + cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; + + if (cur_p->app0 & STS_CTRL_APP0_CMPLT) { + if (!netif_queue_stopped(ndev)) { + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } + return NETDEV_TX_BUSY; + } + + cur_p->app0 = 0; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + const struct iphdr *ip = ip_hdr(skb); + int length = 0, start = 0, insert = 0; + + switch (ip->protocol) { + case IPPROTO_TCP: + start = sizeof(struct iphdr) + ETH_HLEN; + insert = sizeof(struct iphdr) + ETH_HLEN + 16; + length = ip->tot_len - sizeof(struct iphdr); + break; + case IPPROTO_UDP: + start = sizeof(struct iphdr) + ETH_HLEN; + insert = sizeof(struct iphdr) + ETH_HLEN + 6; + length = ip->tot_len - sizeof(struct iphdr); + break; + default: + break; + } + cur_p->app1 = ((start << 16) | insert); + cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr, + length, ip->protocol, 0); + skb->data[insert] = 0; + skb->data[insert + 1] = 0; + } + cur_p->app0 |= STS_CTRL_APP0_SOP; + cur_p->len = skb_headlen(skb); + cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, + DMA_TO_DEVICE); + cur_p->app4 = (unsigned long)skb; + + for (ii = 0; ii < num_frag; ii++) { + lp->tx_bd_tail++; + if (lp->tx_bd_tail >= TX_BD_NUM) + lp->tx_bd_tail = 0; + + cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; + cur_p->phys = dma_map_single(ndev->dev.parent, + (void *)page_address(frag->page) + + frag->page_offset, + frag->size, DMA_TO_DEVICE); + cur_p->len = frag->size; + cur_p->app0 = 0; + frag++; + } + cur_p->app0 |= STS_CTRL_APP0_EOP; + + tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; + lp->tx_bd_tail++; + if (lp->tx_bd_tail >= TX_BD_NUM) + lp->tx_bd_tail = 0; + + /* Kick off the transfer */ + temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ + + return 0; +} + + +static void ll_temac_recv(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct sk_buff *skb, *new_skb; + unsigned int bdstat; + struct cdmac_bd *cur_p; + dma_addr_t tail_p; + int length; + unsigned long skb_vaddr; + unsigned long flags; + + spin_lock_irqsave(&lp->rx_lock, flags); + + tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; + + bdstat = cur_p->app0; + while ((bdstat & STS_CTRL_APP0_CMPLT)) { + + skb = lp->rx_skb[lp->rx_bd_ci]; + length = cur_p->app4; + + skb_vaddr = virt_to_bus(skb->data); + dma_unmap_single(ndev->dev.parent, skb_vaddr, length, + DMA_FROM_DEVICE); + + skb_put(skb, length); + skb->dev = ndev; + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_NONE; + + netif_rx(skb); + + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += length; + + new_skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN, + GFP_ATOMIC); + if (new_skb == 0) { + dev_err(&ndev->dev, "no memory for new sk_buff\n"); + spin_unlock_irqrestore(&lp->rx_lock, flags); + return; + } + + skb_reserve(new_skb, BUFFER_ALIGN(new_skb->data)); + + cur_p->app0 = STS_CTRL_APP0_IRQONEND; + cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data, + XTE_MAX_JUMBO_FRAME_SIZE, + DMA_FROM_DEVICE); + cur_p->len = XTE_MAX_JUMBO_FRAME_SIZE; + lp->rx_skb[lp->rx_bd_ci] = new_skb; + + lp->rx_bd_ci++; + if (lp->rx_bd_ci >= RX_BD_NUM) + lp->rx_bd_ci = 0; + + cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; + bdstat = cur_p->app0; + } + temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p); + + spin_unlock_irqrestore(&lp->rx_lock, flags); +} + +static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev) +{ + struct net_device *ndev = _ndev; + struct temac_local *lp = netdev_priv(ndev); + unsigned int status; + + status = temac_dma_in32(lp, TX_IRQ_REG); + temac_dma_out32(lp, TX_IRQ_REG, status); + + if (status & (IRQ_COAL | IRQ_DLY)) + temac_start_xmit_done(lp->ndev); + if (status & 0x080) + dev_err(&ndev->dev, "DMA error 0x%x\n", status); + + return IRQ_HANDLED; +} + +static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev) +{ + struct net_device *ndev = _ndev; + struct temac_local *lp = netdev_priv(ndev); + unsigned int status; + + /* Read and clear the status registers */ + status = temac_dma_in32(lp, RX_IRQ_REG); + temac_dma_out32(lp, RX_IRQ_REG, status); + + if (status & (IRQ_COAL | IRQ_DLY)) + ll_temac_recv(lp->ndev); + + return IRQ_HANDLED; +} + +static int temac_open(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + int rc; + + dev_dbg(&ndev->dev, "temac_open()\n"); + + if (lp->phy_node) { + lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, + temac_adjust_link, 0, 0); + if (!lp->phy_dev) { + dev_err(lp->dev, "of_phy_connect() failed\n"); + return -ENODEV; + } + + phy_start(lp->phy_dev); + } + + rc = request_irq(lp->tx_irq, ll_temac_tx_irq, 0, ndev->name, ndev); + if (rc) + goto err_tx_irq; + rc = request_irq(lp->rx_irq, ll_temac_rx_irq, 0, ndev->name, ndev); + if (rc) + goto err_rx_irq; + + temac_device_reset(ndev); + return 0; + + err_rx_irq: + free_irq(lp->tx_irq, ndev); + err_tx_irq: + if (lp->phy_dev) + phy_disconnect(lp->phy_dev); + lp->phy_dev = NULL; + dev_err(lp->dev, "request_irq() failed\n"); + return rc; +} + +static int temac_stop(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + + dev_dbg(&ndev->dev, "temac_close()\n"); + + free_irq(lp->tx_irq, ndev); + free_irq(lp->rx_irq, ndev); + + if (lp->phy_dev) + phy_disconnect(lp->phy_dev); + lp->phy_dev = NULL; + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void +temac_poll_controller(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + + disable_irq(lp->tx_irq); + disable_irq(lp->rx_irq); + + ll_temac_rx_irq(lp->tx_irq, lp); + ll_temac_tx_irq(lp->rx_irq, lp); + + enable_irq(lp->tx_irq); + enable_irq(lp->rx_irq); +} +#endif + +static const struct net_device_ops temac_netdev_ops = { + .ndo_open = temac_open, + .ndo_stop = temac_stop, + .ndo_start_xmit = temac_start_xmit, + .ndo_set_mac_address = temac_set_mac_address, + //.ndo_set_multicast_list = temac_set_multicast_list, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = temac_poll_controller, +#endif +}; + +/* --------------------------------------------------------------------- + * SYSFS device attributes + */ +static ssize_t temac_show_llink_regs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct temac_local *lp = netdev_priv(ndev); + int i, len = 0; + + for (i = 0; i < 0x11; i++) + len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp, i), + (i % 8) == 7 ? "\n" : " "); + len += sprintf(buf + len, "\n"); + + return len; +} + +static DEVICE_ATTR(llink_regs, 0440, temac_show_llink_regs, NULL); + +static struct attribute *temac_device_attrs[] = { + &dev_attr_llink_regs.attr, + NULL, +}; + +static const struct attribute_group temac_attr_group = { + .attrs = temac_device_attrs, +}; + +static int __init +temac_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *np; + struct temac_local *lp; + struct net_device *ndev; + const void *addr; + int size, rc = 0; + unsigned int dcrs; + + /* Init network device structure */ + ndev = alloc_etherdev(sizeof(*lp)); + if (!ndev) { + dev_err(&op->dev, "could not allocate device.\n"); + return -ENOMEM; + } + ether_setup(ndev); + dev_set_drvdata(&op->dev, ndev); + SET_NETDEV_DEV(ndev, &op->dev); + ndev->flags &= ~IFF_MULTICAST; /* clear multicast */ + ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST; + ndev->netdev_ops = &temac_netdev_ops; +#if 0 + ndev->features |= NETIF_F_IP_CSUM; /* Can checksum TCP/UDP over IPv4. */ + ndev->features |= NETIF_F_HW_CSUM; /* Can checksum all the packets. */ + ndev->features |= NETIF_F_IPV6_CSUM; /* Can checksum IPV6 TCP/UDP */ + ndev->features |= NETIF_F_HIGHDMA; /* Can DMA to high memory. */ + ndev->features |= NETIF_F_HW_VLAN_TX; /* Transmit VLAN hw accel */ + ndev->features |= NETIF_F_HW_VLAN_RX; /* Receive VLAN hw acceleration */ + ndev->features |= NETIF_F_HW_VLAN_FILTER; /* Receive VLAN filtering */ + ndev->features |= NETIF_F_VLAN_CHALLENGED; /* cannot handle VLAN pkts */ + ndev->features |= NETIF_F_GSO; /* Enable software GSO. */ + ndev->features |= NETIF_F_MULTI_QUEUE; /* Has multiple TX/RX queues */ + ndev->features |= NETIF_F_LRO; /* large receive offload */ +#endif + + /* setup temac private info structure */ + lp = netdev_priv(ndev); + lp->ndev = ndev; + lp->dev = &op->dev; + lp->options = XTE_OPTION_DEFAULTS; + spin_lock_init(&lp->rx_lock); + mutex_init(&lp->indirect_mutex); + + /* map device registers */ + lp->regs = of_iomap(op->node, 0); + if (!lp->regs) { + dev_err(&op->dev, "could not map temac regs.\n"); + goto nodev; + } + + /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ + np = of_parse_phandle(op->node, "llink-connected", 0); + if (!np) { + dev_err(&op->dev, "could not find DMA node\n"); + goto nodev; + } + + dcrs = dcr_resource_start(np, 0); + if (dcrs == 0) { + dev_err(&op->dev, "could not get DMA register address\n"); + goto nodev;; + } + lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); + dev_dbg(&op->dev, "DCR base: %x\n", dcrs); + + lp->rx_irq = irq_of_parse_and_map(np, 0); + lp->tx_irq = irq_of_parse_and_map(np, 1); + if (!lp->rx_irq || !lp->tx_irq) { + dev_err(&op->dev, "could not determine irqs\n"); + rc = -ENOMEM; + goto nodev; + } + + of_node_put(np); /* Finished with the DMA node; drop the reference */ + + /* Retrieve the MAC address */ + addr = of_get_property(op->node, "local-mac-address", &size); + if ((!addr) || (size != 6)) { + dev_err(&op->dev, "could not find MAC address\n"); + rc = -ENODEV; + goto nodev; + } + temac_set_mac_address(ndev, (void *)addr); + + rc = temac_mdio_setup(lp, op->node); + if (rc) + dev_warn(&op->dev, "error registering MDIO bus\n"); + + lp->phy_node = of_parse_phandle(op->node, "phy-handle", 0); + if (lp->phy_node) + dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np); + + /* Add the device attributes */ + rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group); + if (rc) { + dev_err(lp->dev, "Error creating sysfs files\n"); + goto nodev; + } + + rc = register_netdev(lp->ndev); + if (rc) { + dev_err(lp->dev, "register_netdev() error (%i)\n", rc); + goto err_register_ndev; + } + + return 0; + + err_register_ndev: + sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); + nodev: + free_netdev(ndev); + ndev = NULL; + return rc; +} + +static int __devexit temac_of_remove(struct of_device *op) +{ + struct net_device *ndev = dev_get_drvdata(&op->dev); + struct temac_local *lp = netdev_priv(ndev); + + temac_mdio_teardown(lp); + unregister_netdev(ndev); + sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); + if (lp->phy_node) + of_node_put(lp->phy_node); + lp->phy_node = NULL; + dev_set_drvdata(&op->dev, NULL); + free_netdev(ndev); + return 0; +} + +static struct of_device_id temac_of_match[] __devinitdata = { + { .compatible = "xlnx,xps-ll-temac-1.01.b", }, + {}, +}; +MODULE_DEVICE_TABLE(of, temac_of_match); + +static struct of_platform_driver temac_of_driver = { + .match_table = temac_of_match, + .probe = temac_of_probe, + .remove = __devexit_p(temac_of_remove), + .driver = { + .owner = THIS_MODULE, + .name = "xilinx_temac", + }, +}; + +static int __init temac_init(void) +{ + return of_register_platform_driver(&temac_of_driver); +} +module_init(temac_init); + +static void __exit temac_exit(void) +{ + of_unregister_platform_driver(&temac_of_driver); +} +module_exit(temac_exit); + +MODULE_DESCRIPTION("Xilinx LL_TEMAC Ethernet driver"); +MODULE_AUTHOR("Yoshio Kashiwagi"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ll_temac_mdio.c b/drivers/net/ll_temac_mdio.c new file mode 100644 index 0000000..da0e462 --- /dev/null +++ b/drivers/net/ll_temac_mdio.c @@ -0,0 +1,120 @@ +/* + * MDIO bus driver for the Xilinx TEMAC device + * + * Copyright (c) 2009 Secret Lab Technologies, Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ll_temac.h" + +/* --------------------------------------------------------------------- + * MDIO Bus functions + */ +static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct temac_local *lp = bus->priv; + u32 rc; + + /* Write the PHY address to the MIIM Access Initiator register. + * When the transfer completes, the PHY register value will appear + * in the LSW0 register */ + mutex_lock(&lp->indirect_mutex); + temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg); + rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET); + mutex_unlock(&lp->indirect_mutex); + + dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n", + phy_id, reg, rc); + + return rc; +} + +static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +{ + struct temac_local *lp = bus->priv; + + dev_dbg(lp->dev, "temac_mdio_write(phy_id=%i, reg=%x, val=%x)\n", + phy_id, reg, val); + + /* First write the desired value into the write data register + * and then write the address into the access initiator register + */ + mutex_lock(&lp->indirect_mutex); + temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val); + temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg); + mutex_unlock(&lp->indirect_mutex); + + return 0; +} + +int temac_mdio_setup(struct temac_local *lp, struct device_node *np) +{ + struct mii_bus *bus; + const u32 *bus_hz; + int clk_div; + int rc, size; + struct resource res; + + /* Calculate a reasonable divisor for the clock rate */ + clk_div = 0x3f; /* worst-case default setting */ + bus_hz = of_get_property(np, "clock-frequency", &size); + if (bus_hz && size >= sizeof(*bus_hz)) { + clk_div = (*bus_hz) / (2500 * 1000 * 2) - 1; + if (clk_div < 1) + clk_div = 1; + if (clk_div > 0x3f) + clk_div = 0x3f; + } + + /* Enable the MDIO bus by asserting the enable bit and writing + * in the clock config */ + mutex_lock(&lp->indirect_mutex); + temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div); + mutex_unlock(&lp->indirect_mutex); + + bus = mdiobus_alloc(); + if (!bus) + return -ENOMEM; + + of_address_to_resource(np, 0, &res); + snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", + (unsigned long long)res.start); + bus->priv = lp; + bus->name = "Xilinx TEMAC MDIO"; + bus->read = temac_mdio_read; + bus->write = temac_mdio_write; + bus->parent = lp->dev; + bus->irq = lp->mdio_irqs; /* preallocated IRQ table */ + + lp->mii_bus = bus; + + rc = of_mdiobus_register(bus, np); + if (rc) + goto err_register; + + mutex_lock(&lp->indirect_mutex); + dev_dbg(lp->dev, "MDIO bus registered; MC:%x\n", + temac_indirect_in32(lp, XTE_MC_OFFSET)); + mutex_unlock(&lp->indirect_mutex); + return 0; + + err_register: + mdiobus_free(bus); + return rc; +} + +void temac_mdio_teardown(struct temac_local *lp) +{ + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); + lp->mii_bus = NULL; +} + -- cgit v0.10.2 From 434e7b0d12f4e2de6686841a42bd344325b4d756 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 25 Apr 2009 12:53:44 +0000 Subject: net: fix fsl_pq_mdio driver to use module_init() Modules are not supposed to use any of the *_initcall*() hooks as the entry point. fsl_pq_mdio.c was using subsys_initcall_sync() instead of module_init() to guarantee that the MDIO bus was initialized before the Ethernet driver goes looking for the phy. However, the recent OF helpers rework happens to also make sure PHY connection is deferred to .open time, so using an initcall is no longer necessary. This patch replaces the initcall with a more traditional an accepted module_init() call. Tested on Freescale MPC8349emitxgp eval board. Signed-off-by: Grant Likely Signed-off-by: David S. Miller diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index b01daa1..d12e0e0 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -415,10 +415,10 @@ int __init fsl_pq_mdio_init(void) { return of_register_platform_driver(&fsl_pq_mdio_driver); } +module_init(fsl_pq_mdio_init); void fsl_pq_mdio_exit(void) { of_unregister_platform_driver(&fsl_pq_mdio_driver); } -subsys_initcall_sync(fsl_pq_mdio_init); module_exit(fsl_pq_mdio_exit); -- cgit v0.10.2 From 29112f4e248ca6941f2233f6ed96a7283a67cced Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 24 Apr 2009 01:58:23 +0000 Subject: bonding: use ethtool for link checking first This patch only changes the order of interfaces to use for checking slave link status in bond_check_dev_link() to priorize ethtool interface. Should safe some troubles as ethtool seems to be more supported. Jirka Signed-off-by: Jiri Pirko drivers/net/bonding/bond_main.c | 26 ++++++++++++-------------- 1 files changed, 12 insertions(+), 14 deletions(-) Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 63369b6..e4166ee 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -695,6 +695,18 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de if (bond->params.use_carrier) return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; + /* Try to get link status using Ethtool first. */ + if (slave_dev->ethtool_ops) { + if (slave_dev->ethtool_ops->get_link) { + u32 link; + + link = slave_dev->ethtool_ops->get_link(slave_dev); + + return link ? BMSR_LSTATUS : 0; + } + } + + /* Ethtool can't be used, fallback to MII ioclts. */ ioctl = slave_ops->ndo_do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ @@ -721,20 +733,6 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de } /* - * Some drivers cache ETHTOOL_GLINK for a period of time so we only - * attempt to get link status from it if the above MII ioctls fail. - */ - if (slave_dev->ethtool_ops) { - if (slave_dev->ethtool_ops->get_link) { - u32 link; - - link = slave_dev->ethtool_ops->get_link(slave_dev); - - return link ? BMSR_LSTATUS : 0; - } - } - - /* * If reporting, report that either there's no dev->do_ioctl, * or both SIOCGMIIREG and get_link failed (meaning that we * cannot report link status). If not reporting, pretend -- cgit v0.10.2 From 41f8910040639eb106b1a5b5301aab79ecde4940 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 24 Apr 2009 03:57:29 +0000 Subject: bonding: ignore updelay param when there is no active slave Pointed out by Sean E. Millichamp. Quote from Documentation/networking/bonding.txt: "Note that when a bonding interface has no active links, the driver will immediately reuse the first link that goes up, even if the updelay parameter has been specified (the updelay is ignored in this case). If there are slave interfaces waiting for the updelay timeout to expire, the interface that first went into that state will be immediately reused. This reduces down time of the network if the value of updelay has been overestimated, and since this occurs only in cases with no connectivity, there is no additional penalty for ignoring the updelay." This patch actually changes the behaviour in this way. Signed-off-by: Jiri Pirko drivers/net/bonding/bond_main.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e4166ee..fd73836 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2247,6 +2247,9 @@ static int bond_miimon_inspect(struct bonding *bond) { struct slave *slave; int i, link_state, commit = 0; + bool ignore_updelay; + + ignore_updelay = !bond->curr_active_slave ? true : false; bond_for_each_slave(bond, slave, i) { slave->new_link = BOND_LINK_NOCHANGE; @@ -2311,6 +2314,7 @@ static int bond_miimon_inspect(struct bonding *bond) ": %s: link status up for " "interface %s, enabling it in %d ms.\n", bond->dev->name, slave->dev->name, + ignore_updelay ? 0 : bond->params.updelay * bond->params.miimon); } @@ -2329,9 +2333,13 @@ static int bond_miimon_inspect(struct bonding *bond) continue; } + if (ignore_updelay) + slave->delay = 0; + if (slave->delay <= 0) { slave->new_link = BOND_LINK_UP; commit++; + ignore_updelay = false; continue; } -- cgit v0.10.2 From 4e204c1000561ddb1a62a9df857cb0457dd868a7 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Thu, 23 Apr 2009 15:31:38 +0000 Subject: vxge: fix possible NULL dereference in vxge-traffic.c If vpath is NULL then hldev is NULL also. Signed-off-by: Alexander Beregalov Acked-by: Ram Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 7be0ae10..506625b 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -1923,7 +1923,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( if (vpath == NULL) { alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, alarm_event); - goto out; + goto out2; } hldev = vpath->hldev; @@ -2161,7 +2161,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( } out: hldev->stats.sw_dev_err_stats.vpath_alarms++; - +out2: if ((alarm_event == VXGE_HW_EVENT_ALARM_CLEARED) || (alarm_event == VXGE_HW_EVENT_UNKNOWN)) return VXGE_HW_OK; -- cgit v0.10.2 From 011983048a120e520147361be1067dd82343038e Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Thu, 23 Apr 2009 15:53:21 +0000 Subject: vxge: use max() instead of VXGE_HW_SET_LEVEL Signed-off-by: Alexander Beregalov Acked-by: Ram Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 506625b..cf4ebb5 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -505,7 +505,7 @@ enum vxge_hw_status vxge_hw_device_begin_irq(struct __vxge_hw_device *hldev, ret = __vxge_hw_vpath_alarm_process( &hldev->virtual_paths[i], skip_alarms); - error_level = VXGE_HW_SET_LEVEL(ret, error_level); + error_level = max(ret, error_level); if (unlikely((ret == VXGE_HW_ERR_CRITICAL) || (ret == VXGE_HW_ERR_SLOT_FREEZE))) @@ -1921,7 +1921,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( struct vxge_hw_vpath_reg __iomem *vp_reg; if (vpath == NULL) { - alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, + alarm_event = max(VXGE_HW_EVENT_UNKNOWN, alarm_event); goto out2; } @@ -1931,7 +1931,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( alarm_status = readq(&vp_reg->vpath_general_int_status); if (alarm_status == VXGE_HW_ALL_FOXES) { - alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_SLOT_FREEZE, + alarm_event = max(VXGE_HW_EVENT_SLOT_FREEZE, alarm_event); goto out; } @@ -1945,7 +1945,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) { sw_stats->error_stats.unknown_alarms++; - alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, + alarm_event = max(VXGE_HW_EVENT_UNKNOWN, alarm_event); goto out; } @@ -1975,8 +1975,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( &vp_reg->asic_ntwk_vp_err_mask); __vxge_hw_device_handle_link_down_ind(hldev); - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_LINK_DOWN, alarm_event); + alarm_event = max(VXGE_HW_EVENT_LINK_DOWN, + alarm_event); } if (((val64 & @@ -1996,15 +1996,15 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( &vp_reg->asic_ntwk_vp_err_mask); __vxge_hw_device_handle_link_up_ind(hldev); - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_LINK_UP, alarm_event); + alarm_event = max(VXGE_HW_EVENT_LINK_UP, + alarm_event); } writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->asic_ntwk_vp_err_reg); - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); + alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event); if (skip_alarms) return VXGE_HW_OK; @@ -2026,8 +2026,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.ini_serr_det++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_SERR, alarm_event); + alarm_event = max(VXGE_HW_EVENT_SERR, + alarm_event); } if ((val64 & @@ -2035,8 +2035,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.dblgen_fifo0_overflow++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_FIFO_ERR, alarm_event); + alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, + alarm_event); } if ((val64 & @@ -2057,8 +2057,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( if (!skip_alarms) { writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->general_errors_reg); - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); } } @@ -2074,8 +2073,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.kdfcctl_fifo0_overwrite++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_FIFO_ERR, + alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, alarm_event); } @@ -2084,8 +2082,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.kdfcctl_fifo0_poison++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_FIFO_ERR, + alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, alarm_event); } @@ -2094,16 +2091,14 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.kdfcctl_fifo0_dma_error++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_FIFO_ERR, + alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, alarm_event); } if (!skip_alarms) { writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_reg); - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); } } @@ -2127,8 +2122,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.prc_rxdcm_sc_err++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_VPATH_ERR, + alarm_event = max(VXGE_HW_EVENT_VPATH_ERR, alarm_event); } @@ -2136,8 +2130,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( & ~mask64) { sw_stats->error_stats.prc_rxdcm_sc_abort++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_VPATH_ERR, + alarm_event = max(VXGE_HW_EVENT_VPATH_ERR, alarm_event); } @@ -2145,16 +2138,14 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( & ~mask64) { sw_stats->error_stats.prc_quanta_size_err++; - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_VPATH_ERR, + alarm_event = max(VXGE_HW_EVENT_VPATH_ERR, alarm_event); } if (!skip_alarms) { writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->prc_alarm_reg); - alarm_event = VXGE_HW_SET_LEVEL( - VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); } } diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 7567a11..d03f3d3 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -110,8 +110,6 @@ enum vxge_hw_event { VXGE_HW_EVENT_SLOT_FREEZE = VXGE_HW_EVENT_BASE + 14, }; -#define VXGE_HW_SET_LEVEL(a, b) (((a) > (b)) ? (a) : (b)) - /* * struct vxge_hw_mempool_dma - Represents DMA objects passed to the caller. -- cgit v0.10.2 From 78b1f6070fa16cb442a7c48e8f5364cd84a88b90 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Apr 2009 11:20:29 +0000 Subject: igb: always use adapter->itr as EITR value The igb driver was switching between adapter->itr containing the EITR value and the number of interrupts per second. This resulted in high latencies being seen after brining the interface down and then back up. To resolve the issue the itr value will now only contain the value that should be programmed into EITR. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 183235d..ab846ec6 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2898,13 +2898,13 @@ static void igb_set_itr(struct igb_adapter *adapter) switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ case lowest_latency: - new_itr = 70000; + new_itr = 56; /* aka 70,000 ints/sec */ break; case low_latency: - new_itr = 20000; /* aka hwitr = ~200 */ + new_itr = 196; /* aka 20,000 ints/sec */ break; case bulk_latency: - new_itr = 4000; + new_itr = 980; /* aka 4,000 ints/sec */ break; default: break; @@ -2923,7 +2923,8 @@ set_itr_now: * by adding intermediate steps when interrupt rate is * increasing */ new_itr = new_itr > adapter->itr ? - min(adapter->itr + (new_itr >> 2), new_itr) : + max((new_itr * adapter->itr) / + (new_itr + (adapter->itr >> 2)), new_itr) : new_itr; /* Don't write the value here; it resets the adapter's * internal timer, and causes us to delay far longer than @@ -2932,7 +2933,7 @@ set_itr_now: * ends up being correct. */ adapter->itr = new_itr; - adapter->rx_ring->itr_val = 1000000000 / (new_itr * 256); + adapter->rx_ring->itr_val = new_itr; adapter->rx_ring->set_itr = 1; } -- cgit v0.10.2 From fa466e91bdf214e6e136e9da9a46a52775a1e884 Mon Sep 17 00:00:00 2001 From: "Waskiewicz Jr, Peter P" Date: Thu, 23 Apr 2009 11:31:37 +0000 Subject: ixgbe: Disallow SFP 1G modules in the SFP+ cages for 82598 and 82599 82598 and 82599 do not support SFP 1G modules. Instead of allowing the driver to load, but never get link, rejecting the module and displaying a useful message is more preferrable. The framework for displaying the failure message already exists, now we just need to detect and reject the SFP modules. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index f3258ec..2543c32 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -673,11 +673,22 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) break; } } - if (hw->mac.type == ixgbe_mac_82598EB || - (hw->phy.sfp_type != ixgbe_sfp_type_sr && - hw->phy.sfp_type != ixgbe_sfp_type_lr && - hw->phy.sfp_type != ixgbe_sfp_type_srlr_core0 && - hw->phy.sfp_type != ixgbe_sfp_type_srlr_core1)) { + + /* All DA cables are supported */ + if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) { + status = 0; + goto out; + } + + /* 1G SFP modules are not supported */ + if (comp_codes_10g == 0) { + hw->phy.type = ixgbe_phy_sfp_unsupported; + status = IXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + + /* Anything else 82598-based is supported */ + if (hw->mac.type == ixgbe_mac_82598EB) { status = 0; goto out; } @@ -690,6 +701,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) status = 0; } else { hw_dbg(hw, "SFP+ module not supported\n"); + hw->phy.type = ixgbe_phy_sfp_unsupported; status = IXGBE_ERR_SFP_NOT_SUPPORTED; } } else { diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index a3317d8..375f0d4 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1904,6 +1904,7 @@ enum ixgbe_phy_type { ixgbe_phy_sfp_ftl, ixgbe_phy_sfp_unknown, ixgbe_phy_sfp_intel, + ixgbe_phy_sfp_unsupported, ixgbe_phy_generic }; -- cgit v0.10.2 From 683703a26e4677db437a1480682851e27c7a154f Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 27 Apr 2009 03:17:31 -0700 Subject: drop_monitor: Update netlink protocol to include netlink attribute header in alert message When I initially implemented this protocol, I disregarded the use of netlink attribute headers, thinking for my purposes they weren't needed. I've come to find out that, as I'm starting to work with sending down messages with associated data (like config messages), the kernel code spits out warnings about trailing data in a netlink skb that doesn't have an associated header on it. As such, I'm going to start including attribute headers in my netlink transaction, and so for completeness, I should likely include them on messages bound from the kernel to user space. This patch adds that header to the kernel, and bumps the protocol version accordingly Signed-off-by: Neil Horman Signed-off-by: David S. Miller diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 9fd0dc3..2797b71 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -51,7 +51,7 @@ static struct genl_family net_drop_monitor_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = "NET_DM", - .version = 1, + .version = 2, .maxattr = NET_DM_CMD_MAX, }; @@ -65,13 +65,17 @@ static void reset_per_cpu_data(struct per_cpu_dm_data *data) { size_t al; struct net_dm_alert_msg *msg; + struct nlattr *nla; al = sizeof(struct net_dm_alert_msg); al += dm_hit_limit * sizeof(struct net_dm_drop_point); + al += sizeof(struct nlattr); + data->skb = genlmsg_new(al, GFP_KERNEL); genlmsg_put(data->skb, 0, 0, &net_drop_monitor_family, 0, NET_DM_CMD_ALERT); - msg = __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_alert_msg)); + nla = nla_reserve(data->skb, NLA_UNSPEC, sizeof(struct net_dm_alert_msg)); + msg = nla_data(nla); memset(msg, 0, al); atomic_set(&data->dm_hit_count, dm_hit_limit); } @@ -115,6 +119,7 @@ static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) { struct net_dm_alert_msg *msg; struct nlmsghdr *nlh; + struct nlattr *nla; int i; struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data); @@ -127,7 +132,8 @@ static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) } nlh = (struct nlmsghdr *)data->skb->data; - msg = genlmsg_data(nlmsg_data(nlh)); + nla = genlmsg_data(nlmsg_data(nlh)); + msg = nla_data(nla); for (i = 0; i < msg->entries; i++) { if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) { msg->points[i].count++; @@ -139,6 +145,7 @@ static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) * We need to create a new entry */ __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_drop_point)); + nla->nla_len += NLA_ALIGN(sizeof(struct net_dm_drop_point)); memcpy(msg->points[msg->entries].pc, &location, sizeof(void *)); msg->points[msg->entries].count = 1; msg->entries++; -- cgit v0.10.2 From 15b8e19131486856373592e45793a79aefb6fbe7 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Thu, 23 Apr 2009 08:53:20 +0000 Subject: pasemi_mac: mac_to_intf() error not noticed mac_to_intf() can return -1 when no device or function is found, but when mac->dma_if is unsigned. The error wasn't noticed. Signed-off-by: Roel Kluin Acked-by: Olof Johansson Signed-off-by: David S. Miller diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 6ea4539..c254a7f 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1733,7 +1733,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; struct pasemi_mac *mac; - int err; + int err, ret; err = pci_enable_device(pdev); if (err) @@ -1791,12 +1791,13 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr)); - mac->dma_if = mac_to_intf(mac); - if (mac->dma_if < 0) { + ret = mac_to_intf(mac); + if (ret < 0) { dev_err(&mac->pdev->dev, "Can't map DMA interface\n"); err = -ENODEV; goto out; } + mac->dma_if = ret; switch (pdev->device) { case 0xa005: -- cgit v0.10.2 From 0456b4f8b742006c2b79fcbe6b0736aa1ad39180 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Mon, 27 Apr 2009 03:22:15 -0700 Subject: cxacru: Fix negative dB output Values of dB between -0.99 and -0.01 will be output with the wrong sign. This converts the negative value to positive and outputs it with a "-" prefix. Signed-off-by: Simon Arlott Signed-off-by: David S. Miller diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 6789089..56802d2 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -227,8 +227,14 @@ static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf) static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d.%02u\n", - value / 100, abs(value) % 100); + if (likely(value >= 0)) { + return snprintf(buf, PAGE_SIZE, "%u.%02u\n", + value / 100, value % 100); + } else { + value = -value; + return snprintf(buf, PAGE_SIZE, "-%u.%02u\n", + value / 100, value % 100); + } } static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) -- cgit v0.10.2 From f85ba78068ac137fe9c1f50d25405d2783d75c77 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 27 Apr 2009 03:23:54 -0700 Subject: tun: add IFF_TUN_EXCL flag to avoid opening a persistent device. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When creating a certain types of VPN, NetworkManager will first attempt to find an available tun device by iterating through 'vpn%d' until it finds one that isn't already busy. Then it'll set that to be persistent and owned by the otherwise unprivileged user that the VPN dæmon itself runs as. There's a race condition here -- during the period where the vpn%d device is created and we're waiting for the VPN dæmon to actually connect and use it, if we try to create _another_ device we could end up re-using the same one -- because trying to open it again doesn't get -EBUSY as it would while it's _actually_ busy. So solve this, we add an IFF_TUN_EXCL flag which causes tun_set_iff() to fail if it would be opening an existing persistent tundevice -- so that we can make sure we're getting an entirely _new_ device. Signed-off-by: David Woodhouse Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 589f0ca..94622e5 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -874,6 +874,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) dev = __dev_get_by_name(net, ifr->ifr_name); if (dev) { + if (ifr->ifr_flags & IFF_TUN_EXCL) + return -EBUSY; if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) tun = netdev_priv(dev); else if ((ifr->ifr_flags & IFF_TAP) && dev->netdev_ops == &tap_netdev_ops) diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 049d6c9..915ba57 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -55,6 +55,7 @@ #define IFF_NO_PI 0x1000 #define IFF_ONE_QUEUE 0x2000 #define IFF_VNET_HDR 0x4000 +#define IFF_TUN_EXCL 0x8000 /* Features for GSO (TUNSETOFFLOAD). */ #define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ -- cgit v0.10.2 From ec9323f417e803f07a99a15a9cfb207662ad2c55 Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Mon, 27 Apr 2009 03:26:13 -0700 Subject: bnx2x: FW 4.8.53.0 Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/firmware/bnx2x-e1-4.8.53.0.fw.ihex b/firmware/bnx2x-e1-4.8.53.0.fw.ihex new file mode 100644 index 0000000..f1edb1e --- /dev/null +++ b/firmware/bnx2x-e1-4.8.53.0.fw.ihex @@ -0,0 +1,10364 @@ +:10000000000028600000006000000630000028C8E2 +:100010000000160800002F000000009400004510AA +:10002000000073C8000045A8000000C40000B978B3 +:100030000000A4680000BA400000007400015EB037 +:100040000000559000015F28000000B80001B4C016 +:100050000000D1F80001B580000000040002878094 +:10006000020400480000000F020400540000004594 +:1000700002040058000000840204005C0000000636 +:100080000204007000000004020400780000000078 +:100090000204007C121700000204008022170000F6 +:1000A00002040084321700000604008800000005E6 +:1000B0000204009C12150000020400A0221500009A +:1000C000020400A432150000060400A80000000489 +:1000D000020400B802100000020400BC001000007E +:1000E000020400C010100000020400C42010000030 +:1000F000020400C830100000060400CC0000000418 +:10010000020400DC00100000020400E012140000F1 +:10011000020400E422140000020400E8321400008B +:10012000060400EC000000040104012400000000AB +:1001300001040128000000000104012C000000005F +:10014000010401300000000002040004000000FF70 +:1001500002040008000000FF0204000C000000FF81 +:1001600002040010000000FF02040014000000FF61 +:1001700002040018000000FF0204001C000000FF41 +:1001800002040020000000FF020400240000003EE2 +:1001900002040028000000000204002C0000003FC0 +:1001A000020400300000003F020400340000003F61 +:1001B00002040038000000000204003C0000003F80 +:1001C000020400400000003F020400440000003F21 +:1001D00002042008000004110204200C00000400A6 +:1001E000020420100000040402042014000004197A +:1001F0000204201C0000FFFF020420200000FFFF7B +:10020000020420240000FFFF020420280000FFFF5A +:1002100006042038000000020204204000000034E0 +:100220000204204400000035060420480000007C41 +:100230000204223807FFFFFF0204223C0000003FB7 +:100240000204224007FFFFFF020422440000000FC7 +:1002500001042248000000000104224C00000000BC +:10026000010422500000000001042254000000009C +:1002700001042258000000000104225C000000007C +:10028000010422600000000001042264000000005C +:1002900001042268000000000104226C000000003C +:1002A000010422700000000001042274000000001C +:1002B00001042278000000000104227C00000000FC +:1002C000020424BC000000010C042000000003E82C +:1002D0000A042000000000010B0420000000000AB6 +:1002E0000205004400000020020500480000003222 +:1002F000020500900215002002050094021500205E +:1003000002050098000000300205009C0810000063 +:10031000020500A000000033020500A40000003028 +:10032000020500A800000031020500AC0000000238 +:10033000020500B000000005020500B40000000640 +:10034000020500B800000002020500BC0000000227 +:10035000020500C000000000020500C40000000506 +:10036000020500C800000002020500CC00000002E7 +:10037000020500D000000002020500D400000001C8 +:1003800002050114000000010205011C000000012B +:100390000205012000000002020502040000000125 +:1003A0000205020C0000004002050210000000409F +:1003B0000205021C000000200205022000000013BC +:1003C0000205022400000020060502400000000A89 +:1003D0000405028000200000020500500000000714 +:1003E0000205005400000007020500580000000844 +:1003F0000205005C00000008060500600000000423 +:10040000020500D800000006020500E00000000D13 +:10041000020500E40000002D020500E800000007CE +:10042000020500EC00000027020500F000000007B4 +:10043000020500F400000027020500F80000000794 +:10044000020500FC00000027020500040000000176 +:1004500002050008000000010205000C0000000178 +:100460000205001000000001020500140000000158 +:1004700002050018000000010205001C0000000138 +:100480000205002000000001020500240000000118 +:1004900002050028000000010205002C00000001F8 +:1004A00002050030000000010205003400000001D8 +:1004B00002050038000000010205003C00000001B8 +:1004C00002050040000000010406100002000020A8 +:1004D000020600DC00000001010600D80000000058 +:1004E0000406020000030220020600DC00000000F7 +:1004F00002060068000000B802060078000001143F +:10050000010600B800000000010600C8000000005D +:100510000206006C000000B80206007C0000011416 +:10052000010600BC00000000010600CC0000000035 +:100530000718040000930000081807600014022345 +:10054000071C0000324F0000071C800033250C946C +:10055000071D00000E4D195E081D1E005C4002259F +:100560000118000000000000011800040000000055 +:1005700001180008000000000118000C0000000035 +:100580000118001000000000011800140000000015 +:1005900002180020000000010218002400000002E0 +:1005A00002180028000000030218002C00000000C0 +:1005B000021800300000000402180034000000019E +:1005C00002180038000000000218003C0000000182 +:1005D000021800400000000402180044000000005F +:1005E00002180048000000010218004C000000033F +:1005F0000218005000000000021800540000000122 +:1006000002180058000000040218005C00000000FE +:1006100002180060000000010218006400000003DE +:1006200002180068000000000218006C00000001C1 +:10063000021800700000000402180074000000009E +:1006400002180078000000040218007C000000037B +:100650000618008000000002021800A400003FFFFE +:10066000021800A8000003FF021802240000000086 +:1006700002180234000000000218024C00000000C2 +:10068000021802E4000000FF061810000000040039 +:10069000021B8BC000000001021B80000000003420 +:1006A000021B804000000018021B80800000000C2C +:1006B000021B80C0000000200C1B83000007A1204B +:1006C0000A1B8300000001380B1B83000000138805 +:1006D000021B83C0000001F4061A2000000000B2D3 +:1006E000061A23C8000000C1041A26CC0001022704 +:1006F000061A1020000000C8061A100000000002B0 +:10070000061A1C1800000004061A1C100000000243 +:10071000061A080000000002061A0808000000027D +:10072000061A081000000004041A1FB00004022872 +:10073000041A4CB00008022C061A22C8000000203F +:10074000061A40000000016C021A4B600000000015 +:10075000061A14000000000A061A145000000006D1 +:10076000061A150000000002041A150800050234DC +:10077000061A151C00000007061A1570000000126A +:10078000061A09C00000004C061A0800000000020A +:10079000061A08200000000E041A1FB000020239D9 +:1007A000061A290800000002061A2348000000204B +:1007B000061A45B00000016C021A4B6400000000EC +:1007C000061A14280000000A061A14680000000621 +:1007D000061A153800000002041A15400005023BF5 +:1007E000061A155400000007061A15B8000000127A +:1007F000061A0AF00000004C061A08080000000261 +:10080000061A08580000000E041A1FB80002024021 +:10081000061A2910000000020200A2800000000158 +:100820000200A294071D29110200A29800000000F6 +:100830000200A29C009C04240200A2A00000000070 +:100840000200A2A4000002090200A4FCFF000000B4 +:10085000020100B400000001020100B80000000124 +:10086000020100DC000000010201010000000001A3 +:1008700002010104000000010201007C00300000C0 +:1008800002010084000000280201008C000000002A +:1008900002010130000000040201025C00000001BE +:1008A000020103280000000002010554000000308E +:1008B000020100C400000001020100CC00000001A0 +:1008C000020100F800000001020100F00000000138 +:1008D00002010080003000000201008800000028B2 +:1008E0000201009000000000020101340000000439 +:1008F000020102DC000000010201032C00000000E4 +:100900000201056400000030020100C8000000017F +:10091000020100D000000001020100FC0000000103 +:10092000020100F400000001020C10000000002091 +:10093000020C200800000A11020C200C00000A0022 +:10094000020C201000000A04020C201C0000FFFF13 +:10095000020C20200000FFFF020C20240000FFFFFB +:10096000020C20280000FFFF020C2038000000C607 +:10097000020C203C00000000020C2040000000346B +:10098000020C204400000035060C20480000001C2A +:10099000020C20B800000001060C20BC0000005F23 +:1009A000020C223807FFFFFF020C223C0000003F30 +:1009B000020C224007FFFFFF020C22440000000F40 +:1009C000010C224800000000010C224C0000000035 +:1009D000010C225000000000010C22540000000015 +:1009E000010C225800000000010C225C00000000F5 +:1009F000010C226000000000010C226400000000D5 +:100A0000010C226800000000010C226C00000000B4 +:100A1000010C227000000000010C22740000000094 +:100A2000010C227800000000010C227C0000000074 +:100A3000020C24BC000000010C0C2000000003E8A4 +:100A40000A0C2000000000010B0C20000000000A2E +:100A5000020C400800000A11020C400C00000A00C1 +:100A6000020C401000000A04020C401400000A218D +:100A7000020C401C0000FFFF020C40200000FFFFA2 +:100A8000020C40240000FFFF020C40280000FFFF82 +:100A9000020C403800000046020C403C00000005FB +:100AA000020C404000000034020C404400000035BD +:100AB000060C40480000005C020C41B80000000138 +:100AC000060C41BC0000001F020C423807FFFFFF6C +:100AD000020C423C0000003F020C424007FFFFFFB7 +:100AE000020C42440000000F010C424800000000CC +:100AF000010C424C00000000010C425000000000BC +:100B0000010C425400000000010C4258000000009B +:100B1000010C425C00000000010C4260000000007B +:100B2000010C426400000000010C4268000000005B +:100B3000010C426C00000000010C4270000000003B +:100B4000010C427400000000010C4278000000001B +:100B5000010C427C00000000010C428000000000FB +:100B6000020C44C0000000010C0C4000000003E82F +:100B70000A0C4000000000010B0C40000000000ABD +:100B8000020D004400000032020D008C021500200E +:100B9000020D009002150020020D009408100000C4 +:100BA000020D009800000033020D009C00000002BE +:100BB000020D00A000000000020D00A400000005CE +:100BC000020D00A800000005060D00AC00000002A8 +:100BD000020D00B400000002020D00B80000000386 +:100BE000020D00BC00000002020D00C00000000168 +:100BF000020D00C800000002020D00CC000000023F +:100C0000020D010800000001020D015C000000015E +:100C1000020D016400000001020D016800000002E5 +:100C2000020D020400000001020D020C0000002071 +:100C3000020D021000000040020D021400000040EE +:100C4000020D022000000003020D02240000001823 +:100C5000060D028000000012040D03000024024271 +:100C6000020D004C00000001020D005000000002C7 +:100C7000020D005400000008020D0058000000089A +:100C8000060D005C00000004020D00C4000000041A +:100C9000020D011400000009020D011800000029D6 +:100CA000020D011C0000000A020D01200000002AB4 +:100CB000020D012400000007020D0128000000279A +:100CC000020D012C00000007020D0130000000277A +:100CD000020D01340000000C020D01380000002C50 +:100CE000020D013C0000000C020D01400000002C30 +:100CF000020D01440000000C020D01480000002C10 +:100D0000020D000400000001020D000800000001B7 +:100D1000020D000C00000001020D00100000000197 +:100D2000020D001400000001020D00180000000177 +:100D3000020D001C00000001020D00200000000157 +:100D4000020D002400000001020D00280000000137 +:100D5000020D002C00000001020D00300000000117 +:100D6000020D003400000001020D003800000001F7 +:100D7000020D003C00000001020E004C0000003299 +:100D8000020E009402150020020E009802150020A9 +:100D9000020E009C00000030020E00A008100000AF +:100DA000020E00A400000033020E00A80000003074 +:100DB000020E00AC00000031020E00B00000000284 +:100DC000020E00B400000004020E00B80000000093 +:100DD000020E00BC00000002020E00C00000000273 +:100DE000020E00C400000000020E00C80000000255 +:100DF000020E00CC00000007020E00D0000000022E +:100E0000020E00D400000002020E00D80000000113 +:100E1000020E00E400000001020E01440000000187 +:100E2000020E014C00000001020E01500000000201 +:100E3000020E020400000001020E020C000000403D +:100E4000020E021000000040020E021C000000040E +:100E5000020E022000000020020E02240000000EFC +:100E6000020E02280000001B060E03000000001204 +:100E7000040E0280001B0266020E005400000010E7 +:100E8000020E005800000007020E005C0000000F78 +:100E9000020E006000000010060E00640000000456 +:100EA000020E00DC00000003020E01100000000F23 +:100EB000020E01140000002F020E01180000000EA7 +:100EC000020E011C0000002E020E000400000001B2 +:100ED000020E000800000001020E000C00000001DC +:100EE000020E001000000001020E001400000001BC +:100EF000020E001800000001020E001C000000019C +:100F0000020E002000000001020E0024000000017B +:100F1000020E002800000001020E002C000000015B +:100F2000020E003000000001020E0034000000013B +:100F3000020E003800000001020E003C000000011B +:100F4000020E004000000001020E004400000001FB +:100F50000730040000C30000083007680013028156 +:100F600007340000314C00000734800035EF0C548A +:100F700007350000361319D00735800007112755B3 +:100F800008358EE04E24028301300000000000008E +:100F900001300004000000000130000800000000E3 +:100FA0000130000C000000000130001000000000C3 +:100FB0000130001400000000023000200000000199 +:100FC000023000240000000202300028000000036C +:100FD0000230002C0000000002300030000000044D +:100FE0000230003400000001023000380000000030 +:100FF0000230003C0000000102300040000000040C +:1010000002300044000000000230004800000001EF +:101010000230004C000000030230005000000000CD +:1010200002300054000000010230005800000004AB +:101030000230005C0000000002300060000000018F +:10104000023000640000000302300068000000006D +:101050000230006C0000000102300070000000044B +:10106000023000740000000002300078000000042C +:101070000230007C00000003063000800000000207 +:10108000023000A400003FFF023000A8000003FF70 +:101090000230022400000000023002340000000090 +:1010A0000230024C00000000023002E40000FFFFAA +:1010B000063020000000080002338BC00000000151 +:1010C000023380000000001A023380400000004E0E +:1010D0000233808000000010023380C00000002036 +:1010E0000C3383000007A1200A338300000001387D +:1010F0000B33830000001388023383C0000001F427 +:101100000C3383801DCD65000A3383800004C4B492 +:101110000B338380004C4B4006325000000000C26D +:1011200006321020000000C8063210000000000245 +:101130000632464000000040063257F0000000042E +:10114000063257D800000005043257EC0001028532 +:1011500006321C60000000200432283000020286A3 +:10116000023308000100000004330C000010028864 +:10117000023308000000000004330C400010029805 +:1011800006321400000000A0063219000000001012 +:10119000063219800000003006324740000000B4DB +:1011A00002321D900000000006321B4000000004C7 +:1011B00006321B6000000020063253180000009821 +:1011C00006321680000000A0063219400000001010 +:1011D00006321A400000003006324A10000000B407 +:1011E00002321D940000000006321B500000000473 +:1011F00006321BE0000000200632557800000098FF +:10120000072004000071000008200780001002A8D9 +:1012100007240000322900000724800023630C8B80 +:101220000824C930654002AA012000000000000027 +:101230000120000400000000012000080000000060 +:101240000120000C00000000012000100000000040 +:101250000120001400000000022000200000000116 +:1012600002200024000000020220002800000003E9 +:101270000220002C000000000220003000000004CA +:1012800002200034000000010220003800000000AD +:101290000220003C00000001022000400000000489 +:1012A000022000440000000002200048000000016D +:1012B0000220004C0000000302200050000000004B +:1012C0000220005400000001022000580000000429 +:1012D0000220005C0000000002200060000000010D +:1012E00002200064000000030220006800000000EB +:1012F0000220006C000000010220007000000004C9 +:1013000002200074000000000220007800000004A9 +:101310000220007C00000003062000800000000284 +:10132000022000A400003FFF022000A8000003FFED +:10133000022002240000000002200234000000000D +:101340000220024C00000000022002E40000FFFF27 +:10135000062020000000080002238BC000000001CE +:1013600002238000000000100223804000000012D1 +:101370000223808000000030022380C00000000EA5 +:10138000022383C0000001F4062250000000004246 +:1013900006221020000000C80622100000000002F3 +:1013A00006222000000000C00622307000000080ED +:1013B0000622428000000004062225C000000240F0 +:1013C00004222EC8000802AC02230800013FFFFFE0 +:1013D00004230C00001002B40223080000000000E7 +:1013E00004230C40001002C406221400000000A0D8 +:1013F00006221900000000100622198000000030AB +:101400000222511800000000062223000000000EF6 +:1014100006223040000000060622241000000030A2 +:1014200006221680000000A00622194000000010CD +:1014300006221A40000000300222511C0000000069 +:10144000062223380000000E062230580000000655 +:10145000062224D0000000300216100000000020F8 +:1014600002170008000000020217002C0000000311 +:101470000217003C000000040217004400000008AE +:1014800002170048000000020217004C0000009004 +:1014900002170050000000900217005400800090D6 +:1014A0000217005808140000021700600000008AAC +:1014B000021700640000008002170068000000901E +:1014C0000217006C00000080021700700000000688 +:1014D00002170078000007D00217007C0000076C9C +:1014E00002170038007C1004021700040000000FEF +:1014F0000616402400000002021640700000001C86 +:10150000021642080000000102164210000000010D +:1015100002164220000000010216422800000001CD +:10152000021642300000000102164238000000019D +:1015300002164260000000010C16401C0003D0900F +:101540000A16401C0000009C0B16401C000009C439 +:101550000216403000000008021640340000000C63 +:10156000021640380000001002164044000000201F +:101570000216400000000001021640D800000001E1 +:1015800002164008000000010216400C0000000195 +:101590000216401000000001021642400000000048 +:1015A00002164248000000000616427000000002C9 +:1015B00002164250000000000216425800000000CF +:1015C00006164280000000020216600800000614A1 +:1015D0000216600C000006000216601000000604EF +:1015E0000216601C0000FFFF021660200000FFFFD3 +:1015F000021660240000FFFF021660280000FFFFB3 +:1016000002166038000000200216603C0000002036 +:1016100002166040000000340216604400000035ED +:1016200002166048000000230216604C00000024EF +:1016300002166050000000250216605400000026CB +:1016400002166058000000270216605C00000029A6 +:10165000021660600000002A021660640000002B81 +:10166000021660680000002C0216606C0000002D5D +:101670000616607000000052021661B800000001FA +:10168000061661BC0000001F0216623807FFFFFF4C +:101690000216623C0000003F0216624007FFFFFF97 +:1016A000021662440000000F0116624800000000AC +:1016B0000116624C0000000001166250000000009C +:1016C000011662540000000001166258000000007C +:1016D0000116625C0000000001166260000000005C +:1016E000011662640000000001166268000000003C +:1016F0000116626C0000000001166270000000001C +:1017000001166274000000000116627800000000FB +:101710000116627C00000000021664BC000000019B +:101720000C166000000003E80A16600000000001CB +:101730000B1660000000000A021680400000000640 +:101740000216804400000005021680480000000ACE +:101750000216804C000000050216805400000002B2 +:10176000021680CC00000004021680D000000004A5 +:10177000021680D400000004021680D80000000485 +:10178000021680DC00000004021680E00000000465 +:10179000021680E400000004021680E80000000445 +:1017A0000216880400000004021680300000007C4D +:1017B000021680340000003D021680380000003F11 +:1017C0000216803C0000009C021680F0000000071A +:1017D000061680F4000000050216880C01010101C4 +:1017E00002168108000000000216810C00000004AF +:1017F000021681100000000402168114000000028D +:101800000216881008012004021681180000000545 +:101810000216811C00000005021681200000000550 +:1018200002168124000000050216882C20081001F1 +:1018300002168128000000080216812C0000000614 +:1018400002168130000000070216813400000000FB +:1018500002168830010101200616813800000004BC +:1018600002168834010101010616814800000004B7 +:101870000216883801010101061681580000000493 +:101880000216883C01010101061681680000000370 +:101890000216817400000001021688400101010156 +:1018A00002168178000000010216817C0000000110 +:1018B00002168180000000010216818400000001F0 +:1018C000021688440101010102168188000000010E +:1018D0000216818C000000040216819000000004B2 +:1018E00002168194000000020216884808012004B4 +:1018F00002168198000000050216819C0000000578 +:10190000021681A000000005021681A40000000557 +:101910000216881420081001021681A80000000891 +:10192000021681AC00000006021681B0000000071C +:10193000021681B40000000102168818010101207E +:10194000021681B800000001021681BC00000001EF +:10195000021681C000000001021681C400000001CF +:101960000216881C01010101021681C80000000155 +:10197000021681CC00000001021681D00000000197 +:10198000021681D400000001021688200101010125 +:10199000021681D800000001021681DC000000015F +:1019A000021681E000000001021681E4000000013F +:1019B0000216882401010101021681E800000001DD +:1019C000021681EC00000001021681F00000000107 +:1019D000021688280101010102168240FFFF003F24 +:1019E00006168244000000020216824CFFFF003FF0 +:1019F000021682500000010002168254000001000D +:101A0000061682580000000202168260000000C024 +:101A100002168264000000C00216826800001E00E8 +:101A20000216826C00001E00021682700000400048 +:101A300002168274000040000216827800008000C6 +:101A40000216827C000080000216828000002000C6 +:101A5000021682840000200006168288000000071B +:101A6000021682A400000001061682A80000000AE7 +:101A7000021681F400000C08021681F800000040F4 +:101A8000021681FC00000100021682000000002006 +:101A9000021682040000001702168208000000806F +:101AA0000216820C000002000216821000000000E4 +:101AB00002168218FFFF01FF02168214FFFF01FFCA +:101AC0000216823C00000013021680900000013FC5 +:101AD0000216806000000140021680640000014090 +:101AE000061680680000000202168070000000C028 +:101AF00006168074000000070216809C0000004853 +:101B0000021680A000000048061680A40000000213 +:101B1000021680AC00000048061680B000000007E6 +:101B2000021682380000800002168234000025E48C +:101B30000216809400007FFF02168220000000073A +:101B40000216821C00000007021682280000000016 +:101B500002168224FFFFFFFF021682300000000001 +:101B60000216822CFFFFFFFF021680EC000000FF30 +:101B700002140000000000010214000C000000012B +:101B800002140040000000010214004400007FFF26 +:101B90000214000C0000000002140000000000000D +:101BA0000214006C00000000021400040000000198 +:101BB00002140030000000010214000400000000C4 +:101BC0000214005C00000000021400080000000184 +:101BD000021400340000000102140008000000009C +:101BE00002140060000000000202005800000032F1 +:101BF000020200A003150020020200A40315002029 +:101C0000020200A801000030020200AC081000002F +:101C1000020200B000000033020200B400000030F5 +:101C2000020200B800000031020200BC0000000304 +:101C3000020200C000000006020200C4000000030F +:101C4000020200C800000003020200CC00000002F3 +:101C5000020200D000000000020200D400000002D6 +:101C6000020200DC00000000020200E000000006AA +:101C7000020200E400000004020200E8000000028A +:101C8000020200EC00000002020200F0000000016D +:101C9000020200FC00000006020201200000000019 +:101CA0000202013400000002020201B00000000143 +:101CB0000202020C000000010202021400000001F6 +:101CC00002020218000000020202040400000001E7 +:101CD0000202040C00000040020204100000004058 +:101CE0000202041C00000004020204200000002084 +:101CF0000202042400000002020204280000001F67 +:101D0000060205000000001204020480001F02D435 +:101D1000020200600000000F0202006400000007E1 +:101D2000020200680000000B0202006C0000000EBE +:101D30000602007000000004020200F4000000042B +:101D4000020200040000000102020008000000017D +:101D50000202000C0000000102020010000000015D +:101D6000020200140000000102020018000000013D +:101D70000202001C0000000102020020000000011D +:101D800002020024000000010202002800000001FD +:101D90000202002C000000010202003000000001DD +:101DA00002020034000000010202003800000001BD +:101DB0000202003C0000000102020040000000019D +:101DC000020200440000000102020048000000017D +:101DD0000202004C0000000102020050000000015D +:101DE00002020108000000C80202011800000002FF +:101DF000020201C400000000020201CC0000000049 +:101E0000020201D400000002020201DC0000000214 +:101E1000020201E4000000FF020201EC000000FFEA +:101E20000202010C000000C80202011C00000002B6 +:101E3000020201C800000000020201D00000000000 +:101E4000020201D800000002020201E000000002CC +:101E5000020201E8000000FF020201F0000000FFA2 +:101E60000728040000B5000008280768001302F3E3 +:101E7000072C000033660000072C800038B30CDA12 +:101E8000072D00003BB11B07072D80002A2629F4EF +:101E9000082DD6C0452802F50128000000000000EA +:101EA00001280004000000000128000800000000D4 +:101EB0000128000C000000000128001000000000B4 +:101EC000012800140000000002280020000000018A +:101ED000022800240000000202280028000000035D +:101EE0000228002C0000000002280030000000043E +:101EF0000228003400000001022800380000000021 +:101F00000228003C000000010228004000000004FC +:101F100002280044000000000228004800000001E0 +:101F20000228004C000000030228005000000000BE +:101F3000022800540000000102280058000000049C +:101F40000228005C00000000022800600000000180 +:101F5000022800640000000302280068000000005E +:101F60000228006C0000000102280070000000043C +:101F7000022800740000000002280078000000041D +:101F80000228007C000000030628008000000002F8 +:101F9000022800A400003FFF022800A8000003FF61 +:101FA0000228022400000000022802340000000081 +:101FB0000228024C00000000022802E40000FFFF9B +:101FC0000628200000000800022B8BC00000000142 +:101FD000022B800000000000022B8040000000184F +:101FE000022B80800000000C022B80C000000066E5 +:101FF0000C2B83000007A1200A2B8300000001386E +:102000000B2B830000001388022B83C0000001F417 +:102010000C2B8340000001F40A2B834000000000D9 +:102020000B2B8340000000050A2B83800004C4B4FE +:102030000C2B83801DCD65000B2B8380004C4B4007 +:10204000062A3D6000000004042A3D70000202F7E9 +:10205000062A300000000048062A1020000000C8B0 +:10206000062A100000000002062A31280000008E17 +:10207000022A336800000000042A3370000202F9CB +:10208000042A3B90000402FB042A3E20000202FFC7 +:10209000022A151800000001022A18300000000072 +:1020A000022A183800000000042A18200002030148 +:1020B000062A4AC000000002062A4B000000000465 +:1020C000042A1F4800020303022B0800000000003E +:1020D000042B0C0000100305022B08000100000077 +:1020E000042B0C4000080315022B0800020000001E +:1020F000042B0C600008031D062A3BA000000014FE +:10210000062A3C4000000024062A14000000000AB1 +:10211000062A145000000006062A3378000000FC4E +:10212000022A3B5800000000042A3D7800020325E3 +:10213000042A3D8800100327022A15000000000031 +:10214000022A150800000001062A502000000002A3 +:10215000062A503000000002062A5000000000024B +:10216000062A501000000002022A50400000000021 +:10217000062A50480000000E022A50B80000000154 +:10218000042A4AC800020337062A4B100000004206 +:10219000062A4D2000000004062A3BF0000000142F +:1021A000062A3CD000000024062A14280000000A59 +:1021B000062A146800000006062A3768000000FCA2 +:1021C000022A3B5C00000000042A3D800002033923 +:1021D000042A3DC80010033B022A15040000000039 +:1021E000022A150C00000001062A502800000002F7 +:1021F000062A503800000002062A5008000000029B +:10220000062A501800000002022A50440000000074 +:10221000062A50800000000E022A50BC0000000177 +:10222000042A4AD00002034B062A4C180000004240 +:10223000062A4D30000000040210100800000001C2 +:10224000021010000003D000021010040000003D36 +:10225000091018000200034D091011000020054D5F +:102260000610118000000002091011880006056D9B +:10227000061011A00000001806102400000000E065 +:102280000210201C000000000210202000000001AD +:10229000021020C000000001021020040000000114 +:1022A000021020080000000109103C000005057321 +:1022B00009103C2000050578091038000005057D4F +:1022C00002104028000000100210404400003FFFB0 +:1022D0000210405800280000021040840084924AF6 +:1022E0000210405800000000061080680000000442 +:1022F00002108000000010800610802800000002FC +:102300000210803800000010021080400000FFFF23 +:10231000021080440000FFFF021080500000000007 +:102320000210810000000000061081200000000261 +:1023300002108008000002B50210801000000000AA +:10234000061082000000004A021081080001FFFF11 +:1023500006108140000000020210800000001A8078 +:102360000610900000000024061091200000004A92 +:10237000061093700000004A061095C00000004A45 +:10238000021080040000108006108030000000025F +:102390000210803C00000010021080480000FFFF87 +:1023A0000210804C0000FFFF02108054000000006B +:1023B00002108104000000000610812800000002C5 +:1023C0000210800C000002B5021080140000000012 +:1023D000061084000000004A0210810C0001FFFF7B +:1023E00006108148000000020210800400001A80DC +:1023F0000610909000000024061092480000004A49 +:10240000061094980000004A061096E80000004A62 +:102410000212049000E383400212051400003C10F5 +:1024200002120494FFFFFFFF02120498FFFFFFFF58 +:102430000212049CFFFFFFFF021204A0FFFFFFFF38 +:10244000021204A4FFFFFFFF021204A8FFFFFFFF18 +:10245000021204ACFFFFFFFF021204B0FFFFFFFFF8 +:10246000021204B8FFFFFFFF021204BCFFFFFFFFD0 +:10247000021204C0FFFFFFFF021204C4FFFFFFFFB0 +:10248000021204C8FFFFFFFF021204CCFFFFFFFF90 +:10249000021204D0FFFFFFFF021204DCFFFFFFFF68 +:1024A000021204E0FFFFFFFF021204E4FFFFFFFF40 +:1024B000021204E8FFFFFFFF021204ECFFFFFFFF20 +:1024C000021204F0FFFFFFFF021204F4FFFFFFFF00 +:1024D000021204F8FFFFFFFF021204FCFFFFFFFFE0 +:1024E00002120500FFFFFFFF02120504FFFFFFFFBE +:1024F00002120508FFFFFFFF0212050CFFFFFFFF9E +:1025000002120510FFFFFFFF021204D4FFFF333059 +:10251000021204D8FFFF3340021204B4F00030006E +:1025200002120390000000080212039C0000000841 +:10253000021203A000000008021203A4000000021F +:10254000021203BC00000004021203C000000005D8 +:10255000021203C400000004021203D000000000B5 +:102560000212036C00000001021203680000003F29 +:10257000021201BC00000040021201C00000180855 +:10258000021201C400000803021201C8000008037F +:10259000021201CC00000040021201D00000000332 +:1025A000021201D400000803021201D8000008033F +:1025B000021201DC00000803021201E00001000326 +:1025C000021201E400000803021201E800000803FF +:1025D000021201EC00000003021201F000000003EF +:1025E000021201F400000003021201F800000003CF +:1025F000021201FC000000030212020000000003AE +:10260000021202040000000302120208000000038C +:102610000212020C0000000302120210000000036C +:10262000021202140000000302120218000000034C +:102630000212021C0000000302120220000000032C +:1026400002120224000000030212022800002403E8 +:102650000212022C0000002F0212023000000009BA +:102660000212023400000019021202380000018434 +:102670000212023C00000183021202400000030625 +:102680000212024400000019021202480000000673 +:102690000212024C00000306021202500000030660 +:1026A00002120254000003060212025800000C86B7 +:1026B0000212025C00000306021202600000030620 +:1026C0000212026400000006021202680000000606 +:1026D0000212026C000000060212027000000006E6 +:1026E00002120274000000060212027800000006C6 +:1026F0000212027C000000060212028000000006A6 +:102700000212028400000006021202880000000685 +:102710000212028C00000006021202900000000665 +:102720000212029400000006021202980000000645 +:102730000212029C00000006021202A00000030622 +:10274000021202A400000013021202A800000006F8 +:10275000021202B000001004021202B400001004C1 +:102760000212032400106440021203280010644087 +:10277000021201B0000000010600A00000000016D7 +:102780000200A06CBF5C00000200A070FFF51FEF0C +:102790000200A0740000FFFF0200A078500003E0D8 +:1027A0000200A07C000000000200A0800000A00049 +:1027B0000600A084000000050200A0980FE00000C1 +:1027C0000600A09C000000140200A0EC555400007C +:1027D0000200A0F0555555550200A0F400005555D3 +:1027E0000200A0F8000000000200A0FC5554000008 +:1027F0000200A100555555550200A1040000555591 +:102800000200A108000000000200A22C000000004D +:102810000600A230000000030200A06000000007D4 +:102820000200A10CBF5C00000200A110FFF51FEF29 +:102830000200A1140000FFFF0200A118500003E0F5 +:102840000200A11C000000000200A1200000A00066 +:102850000600A124000000050200A1380FE00000DE +:102860000600A13C000000140200A18C5554000099 +:102870000200A190555555550200A19400005555F0 +:102880000200A198000000000200A19C5554000025 +:102890000200A1A0555555550200A1A400005555B0 +:1028A0000200A1A8000000000200A23C00000000FD +:1028B0000600A240000000030200A0640000000720 +:1028C00000000000000000000000002E00000000DA +:1028D00000000000000000000000000000000000F8 +:1028E00000000000000000000000000000000000E8 +:1028F00000000000000000000000000000000000D8 +:1029000000000000000000000000000000000000C7 +:1029100000000000000000000000000000000000B7 +:10292000002E005000000000000000000000000029 +:102930000000000000000000000000000000000097 +:102940000000000000000000000000000050008DAA +:102950000000000000000000000000000000000077 +:102960000000000000000000000000000000000067 +:102970000000000000000000008D00920092009610 +:102980000096009A00000000000000000000000017 +:102990000000000000000000000000000000000037 +:1029A00000000000009A00DB00DB00E900E900F70E +:1029B0000000000000000000000000000000000017 +:1029C0000000000000000000000000000000000007 +:1029D00000000000000000000000000000000000F7 +:1029E00000000000000000000000000000000000E7 +:1029F00000000000000000000000000000000000D7 +:102A000000000000000000000000000000000000C6 +:102A100000000000000000000000000000000000B6 +:102A200000000000000000000000000000000000A6 +:102A30000000000000000000000000000000000096 +:102A40000000000000000000000000000000000086 +:102A50000000000000000000000000000000000076 +:102A60000000000000000000000000000000000066 +:102A70000000000000000000000000000000000056 +:102A800000F700FE00000000000000000000000051 +:102A90000000000000000000000000000000000036 +:102AA0000000000000000000000000000000000026 +:102AB0000000000000000000000000000000000016 +:102AC0000000000000000000000000000000000006 +:102AD000000000000000000000FE01030103010EE1 +:102AE000010E0119000000000000000000000000BD +:102AF00000000000000000000000000000000000D6 +:102B000000000000000000000000000000000000C5 +:102B100000000000000000000000000000000000B5 +:102B200000000000000000000000000000000000A5 +:102B30000119011A00000000000000000000000060 +:102B40000000000000000000000000000000000085 +:102B5000000000000000000000000000011A013E1B +:102B60000000000000000000000000000000000065 +:102B70000000000000000000000000000000000055 +:102B80000000000000000000013E016400000000A1 +:102B90000000000000000000000000000000000035 +:102BA0000000000000000000000000000000000025 +:102BB00000000000016401A300000000000000000C +:102BC0000000000000000000000000000000000005 +:102BD00000000000000000000000000000000000F5 +:102BE00001A301DE00000000000000000000000062 +:102BF00000000000000000000000000000000000D5 +:102C000000000000000000000000000001DE0224BF +:102C10000224022C022C02340000000000000000FC +:102C200000000000000000000000000000000000A4 +:102C300000000000000000000234027102710278FE +:102C40000278027F00000000000000000000000089 +:102C50000000000000000000000000000000000074 +:102C600000000000027F0280000000000000000061 +:102C70000000000000000000000000000000000054 +:102C80000000000000000000000000000000000044 +:102C9000028002920000000000000000000000001E +:102CA0000000000000000000000000000000000024 +:102CB000000000000000000000000000029202A7D7 +:102CC00002A702AA02AA02AD000000000000000054 +:102CD00000000000000000000000000000000000F4 +:102CE000000000000000000002AD02DB0000000058 +:102CF00000000000000000000000000000000000D4 +:102D000000000000000000000000000000000000C3 +:102D10000000000002DB0362000000000000000071 +:102D200000000000000000000000000000000000A3 +:102D30000000000000000000000000000000000093 +:102D4000036203690369036D036D037100000000F2 +:102D50000000000000000000000000000000000073 +:102D6000000000000000000000000000037103B03C +:102D700003B003B803B803C0000000000000000067 +:102D80000000000000000000000000000000000043 +:102D9000000000000000000003C004130413042717 +:102DA0000427043B000000000000000000000000B9 +:102DB0000000000000000000000000000000000013 +:102DC00000000000043B044300000000000000007D +:102DD00000000000000000000000000000000000F3 +:102DE00000000000000000000000000000000000E3 +:102DF000044304490000000000000000000000003F +:102E000000000000000000000000000000000000C2 +:102E10000000000000000000000000000449044C15 +:102E200000000000000000000000000000000000A2 +:102E30000000000000000000000000000000000092 +:102E40000000000000000000044C045100000000DD +:102E50000000000000000000000000000000000072 +:102E60000000000000000000000000000000000062 +:102E70000000000004510452045204640464047607 +:102E80000000000000000000000000000000000042 +:102E90000000000000000000000000000000000032 +:102EA000047604E3000000000000000000000000C1 +:102EB0000000000000000000000000000000000012 +:102EC00000000000000000000000000004E304E433 +:102ED00004E404F804F8050C000000000000000001 +:102EE00000000000000000000000000000000000E2 +:102EF00000000000000000000000000000000000D2 +:102F000000010000000204C00003098000040E401C +:102F100000051300000617C000071C8000082140B0 +:102F200000092600000A2AC0000B2F80000C344044 +:102F3000000D3900000E3DC0000F428000104740D8 +:102F400000114C00001250C00013558000145A406C +:102F500000155F00001663C00017688000186D4000 +:102F600000197200001A76C0001B7B80001C804094 +:102F7000001D8500001E89C0001F8E800020934028 +:102F80000000200000004000000060000000800001 +:102F90000000A0000000C0000000E00000010000F0 +:102FA00000012000000140000001600000018000DD +:102FB0000001A0000001C0000001E00000020000CC +:102FC00000022000000240000002600000028000B9 +:102FD0000002A0000002C0000002E00000030000A8 +:102FE0000003200000034000000360000003800095 +:102FF0000003A0000003C0000003E0000004000084 +:103000000004200000044000000460000004800070 +:103010000004A0000004C0000004E000000500005F +:10302000000520000005400000056000000580004C +:103030000005A0000005C0000005E000000600003B +:103040000006200000064000000660000006800028 +:103050000006A0000006C0000006E0000007000017 +:103060000007200000074000000760000007800004 +:103070000007A0000007C0000007E00000080000F3 +:1030800000082000000840000008600000088000E0 +:103090000008A0000008C0000008E00000090000CF +:1030A00000092000000940000009600000098000BC +:1030B0000009A0000009C0000009E000000A0000AB +:1030C000000A2000000A4000000A6000000A800098 +:1030D000000AA000000AC000000AE000000B000087 +:1030E000000B2000000B4000000B6000000B800074 +:1030F000000BA000000BC000000BE000000C000063 +:10310000000C2000000C4000000C6000000C80004F +:10311000000CA000000CC000000CE000000D00003E +:10312000000D2000000D4000000D6000000D80002B +:10313000000DA000000DC000000DE000000E00001A +:10314000000E2000000E4000000E6000000E800007 +:10315000000EA000000EC000000EE000000F0000F6 +:10316000000F2000000F4000000F6000000F8000E3 +:10317000000FA000000FC000000FE00000100000D2 +:1031800000102000001040000010600000108000BF +:103190000010A0000010C0000010E00000110000AE +:1031A000001120000011400000116000001180009B +:1031B0000011A0000011C0000011E000001200008A +:1031C0000012200000124000001260000012800077 +:1031D0000012A0000012C0000012E0000013000066 +:1031E0000013200000134000001360000013800053 +:1031F0000013A0000013C0000013E0000014000042 +:10320000001420000014400000146000001480002E +:103210000014A0000014C0000014E000001500001D +:10322000001520000015400000156000001580000A +:103230000015A0000015C0000015E00000160000F9 +:1032400000162000001640000016600000168000E6 +:103250000016A0000016C0000016E00000170000D5 +:1032600000172000001740000017600000178000C2 +:103270000017A0000017C0000017E00000180000B1 +:10328000001820000018400000186000001880009E +:103290000018A0000018C0000018E000001900008D +:1032A000001920000019400000196000001980007A +:1032B0000019A0000019C0000019E000001A000069 +:1032C000001A2000001A4000001A6000001A800056 +:1032D000001AA000001AC000001AE000001B000045 +:1032E000001B2000001B4000001B6000001B800032 +:1032F000001BA000001BC000001BE000001C000021 +:10330000001C2000001C4000001C6000001C80000D +:10331000001CA000001CC000001CE000001D0000FC +:10332000001D2000001D4000001D6000001D8000E9 +:10333000001DA000001DC000001DE000001E0000D8 +:10334000001E2000001E4000001E6000001E8000C5 +:10335000001EA000001EC000001EE000001F0000B4 +:10336000001F2000001F4000001F6000001F8000A1 +:10337000001FA000001FC000001FE0000020000090 +:10338000002020000020400000206000002080007D +:103390000020A0000020C0000020E000002100006C +:1033A0000021200000214000002160000021800059 +:1033B0000021A0000021C0000021E0000022000048 +:1033C0000022200000224000002260000022800035 +:1033D0000022A0000022C0000022E0000023000024 +:1033E0000023200000234000002360000023800011 +:1033F0000023A0000023C0000023E0000024000000 +:1034000000242000002440000024600000248000EC +:103410000024A0000024C0000024E00000250000DB +:1034200000252000002540000025600000258000C8 +:103430000025A0000025C0000025E00000260000B7 +:1034400000262000002640000026600000268000A4 +:103450000026A0000026C0000026E0000027000093 +:103460000027200000274000002760000027800080 +:103470000027A0000027C0000027E000002800006F +:10348000002820000028400000286000002880005C +:103490000028A0000028C0000028E000002900004B +:1034A0000029200000294000002960000029800038 +:1034B0000029A0000029C0000029E000002A000027 +:1034C000002A2000002A4000002A6000002A800014 +:1034D000002AA000002AC000002AE000002B000003 +:1034E000002B2000002B4000002B6000002B8000F0 +:1034F000002BA000002BC000002BE000002C0000DF +:10350000002C2000002C4000002C6000002C8000CB +:10351000002CA000002CC000002CE000002D0000BA +:10352000002D2000002D4000002D6000002D8000A7 +:10353000002DA000002DC000002DE000002E000096 +:10354000002E2000002E4000002E6000002E800083 +:10355000002EA000002EC000002EE000002F000072 +:10356000002F2000002F4000002F6000002F80005F +:10357000002FA000002FC000002FE000003000004E +:10358000003020000030400000306000003080003B +:103590000030A0000030C0000030E000003100002A +:1035A0000031200000314000003160000031800017 +:1035B0000031A0000031C0000031E0000032000006 +:1035C00000322000003240000032600000328000F3 +:1035D0000032A0000032C0000032E00000330000E2 +:1035E00000332000003340000033600000338000CF +:1035F0000033A0000033C0000033E00000340000BE +:1036000000342000003440000034600000348000AA +:103610000034A0000034C0000034E0000035000099 +:103620000035200000354000003560000035800086 +:103630000035A0000035C0000035E0000036000075 +:103640000036200000364000003660000036800062 +:103650000036A0000036C0000036E0000037000051 +:10366000003720000037400000376000003780003E +:103670000037A0000037C0000037E000003800002D +:10368000003820000038400000386000003880001A +:103690000038A0000038C0000038E0000039000009 +:1036A00000392000003940000039600000398000F6 +:1036B0000039A0000039C0000039E000003A0000E5 +:1036C000003A2000003A4000003A6000003A8000D2 +:1036D000003AA000003AC000003AE000003B0000C1 +:1036E000003B2000003B4000003B6000003B8000AE +:1036F000003BA000003BC000003BE000003C00009D +:10370000003C2000003C4000003C6000003C800089 +:10371000003CA000003CC000003CE000003D000078 +:10372000003D2000003D4000003D6000003D800065 +:10373000003DA000003DC000003DE000003E000054 +:10374000003E2000003E4000003E6000003E800041 +:10375000003EA000003EC000003EE000003F000030 +:10376000003F2000003F4000003F6000003F80001D +:10377000003FA000003FC000003FE000003FE0012C +:1037800000000000000001FF0000020000007FF8C0 +:1037900000007FF8000002920000350000000001E8 +:1037A0000000000300BEBC200000000300BEBC20DF +:1037B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:1037C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +:1037D000FFFFFFFF00000000FFFFFFFF00000000F1 +:1037E000FFFFFFFF0000000300BEBC20FFFFFFFF44 +:1037F00000000000FFFFFFFF00000000FFFFFFFFD1 +:103800000000000300BEBC2000002000000040C0FB +:1038100000006180000082400000A3000000C3C0DF +:103820000000E4800001054000012600000146C0C0 +:1038300000016780000188400001A9000001C9C0A3 +:103840000001EA8000020B4000022C0000024CC084 +:1038500000026D8000028E400002AF000002CFC067 +:103860000002F0800003114000033200000352C048 +:1038700000037380000394400003B5000003D5C02B +:103880000003F6800004174000043800000458C00C +:103890000004798000049A40000080000001038049 +:1038A0000001870000020A8000028E0000031180E0 +:1038B000000395000004188000049C0000051F8090 +:1038C0000005A300000626800006AA0000072D8040 +:1038D0000007B100000834800008B80000093B80F0 +:1038E0000009BF00000A4280000AC600000B4980A0 +:1038F000000BCD00000C5080000CD400000D578050 +:10390000000DDB0000007FF800007FF8000003E5F9 +:10391000000015000000190000000000FFFFFFFF7D +:103920004000000040000000400000004000000097 +:103930004000000040000000400000004000000087 +:103940004000000040000000400000004000000077 +:103950004000000040000000400000004000000067 +:103960004000000040000000400000004000000057 +:103970004000000040000000400000004000000047 +:103980004000000040000000400000004000000037 +:103990004000000040000000400000004000000027 +:1039A00000007FF800007FF8000003C80000150049 +:1039B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:1039C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 +:1039D00040000000400000004000000040000000E7 +:1039E00040000000400000004000000040000000D7 +:1039F00040000000400000004000000040000000C7 +:103A000040000000400000004000000040000000B6 +:103A100040000000400000004000000040000000A6 +:103A20004000000040000000400000004000000096 +:103A30004000000040000000400000004000000086 +:103A40004000000040000000400000004000000076 +:103A500000001000000020800000310000004180C4 +:103A600000005200000062800000730000008380AC +:103A7000000094000000A4800000B5000000C58094 +:103A80000000D6000000E6800000F700000107807B +:103A90000001180000012880000139000001498060 +:103AA00000015A0000016A8000017B0000018B8048 +:103AB00000019C000001AC800001BD000001CD8030 +:103AC0000001DE000001EE800001FF0000007FF831 +:103AD00000007FF800000207000035001000000021 +:103AE000000028AD000000000001000100350804BE +:103AF000CCCCCCC1FFFFFFFFFFFFFFFF7058103C95 +:103B000000000000CCCC0201CCCCCCCC00000000EA +:103B1000FFFFFFFF400000004000000040000000E9 +:103B20004000000040000000400000004000000095 +:103B30004000000040000000400000004000000085 +:103B40004000000040000000400000004000000075 +:103B50004000000040000000400000004000000065 +:103B60004000000040000000400000004000000055 +:103B70004000000040000000400000004000000045 +:103B80004000000040000000400000004000000035 +:103B900040000000000E01B7011600D60000FFFF34 +:103BA000000000000000FFFF000000000000FFFF19 +:103BB000000000000000FFFF000000000000FFFF09 +:103BC000000000000000FFFF000000000000FFFFF9 +:103BD000000000000000FFFF0000000000100000D7 +:103BE00000000000007201BB012300F30000FFFF92 +:103BF000000000000000FFFF000000000000FFFFC9 +:103C0000000000000000FFFF000000000000FFFFB8 +:103C1000000000000000FFFF000000000000FFFFA8 +:103C2000000000000000FFFF000000000010000086 +:103C300000000000FFFFFFF3320FFFFF0C30C30C4A +:103C4000C30C30C3CF3CF300F3CF3CF30000CF3CB8 +:103C5000CDCDCDCDFFFFFFF130EFFFFF0C30C30C1A +:103C6000C30C30C3CF3CF300F3CF3CF30001CF3C97 +:103C7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C85 +:103C8000C30C30C3CF3CF300F3CF3CF30002CF3C76 +:103C9000CDCDCDCDFFFFF4061CBFFFFF0C30C3051B +:103CA000C30C30C3CF300014F3CF3CF30004CF3C3F +:103CB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C59 +:103CC000C30C30C3CF3CF300F3CF3CF30008CF3C30 +:103CD000CDCDCDCDFFFFFFFA302FFFFF0C30C30C51 +:103CE000C30C30C3CF3CF300F3CF3CF30010CF3C08 +:103CF000CDCDCDCDFFFFFFF731EFFFFF0C30C30C73 +:103D0000C30C30C3CF3CF300F3CF3CF30020CF3CD7 +:103D1000CDCDCDCDFFFFFFF5302FFFFF0C30C30C15 +:103D2000C30C30C3CF3CF300F3CF3CF30040CF3C97 +:103D3000CDCDCDCDFFFFFFF3310FFFFF0C30C30C16 +:103D4000C30C30C3CF3CF300F3CF3CF30000CF3CB7 +:103D5000CDCDCDCDFFFFFFF1310FFFFF0C30C30CF8 +:103D6000C30C30C3CF3CF300F3CF3CF30001CF3C96 +:103D7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C84 +:103D8000C30C30C3CF3CF300F3CF3CF30002CF3C75 +:103D9000CDCDCDCDFFFFF4061CBFFFFF0C30C3051A +:103DA000C30C30C3CF300014F3CF3CF30004CF3C3E +:103DB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C58 +:103DC000C30C30C3CF3CF300F3CF3CF30008CF3C2F +:103DD000CDCDCDCDFFFFFFFA302FFFFF0C30C30C50 +:103DE000C30C30C3CF3CF300F3CF3CF30010CF3C07 +:103DF000CDCDCDCDFFFFFFF730EFFFFF0C30C30C73 +:103E0000C30C30C3CF3CF300F3CF3CF30020CF3CD6 +:103E1000CDCDCDCDFFFFFFF5304FFFFF0C30C30CF4 +:103E2000C30C30C3CF3CF300F3CF3CF30040CF3C96 +:103E3000CDCDCDCDFFFFFFF331EFFFFF0C30C30C35 +:103E4000C30C30C3CF3CF300F3CF3CF30000CF3CB6 +:103E5000CDCDCDCDFFFFFFF1310FFFFF0C30C30CF7 +:103E6000C30C30C3CF3CF300F3CF3CF30001CF3C95 +:103E7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C83 +:103E8000C30C30C3CF3CF300F3CF3CF30002CF3C74 +:103E9000CDCDCDCDFFFFF4061CBFFFFF0C30C30519 +:103EA000C30C30C3CF300014F3CF3CF30004CF3C3D +:103EB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C57 +:103EC000C30C30C3CF3CF300F3CF3CF30008CF3C2E +:103ED000CDCDCDCDFFFFFFFA302FFFFF0C30C30C4F +:103EE000C30C30C3CF3CF300F3CF3CF30010CF3C06 +:103EF000CDCDCDCDFFFFFF97056FFFFF0C30C30C7D +:103F0000C30C30C3CF3CC000F3CF3CF30020CF3C08 +:103F1000CDCDCDCDFFFFFFF5310FFFFF0C30C30C32 +:103F2000C30C30C3CF3CF300F3CF3CF30040CF3C95 +:103F3000CDCDCDCDFFFFFFF3320FFFFF0C30C30C13 +:103F4000C30C30C3CF3CF300F3CF3CF30000CF3CB5 +:103F5000CDCDCDCDFFFFFFF1310FFFFF0C30C30CF6 +:103F6000C30C30C3CF3CF300F3CF3CF30001CF3C94 +:103F7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C82 +:103F8000C30C30C3CF3CF300F3CF3CF30002CF3C73 +:103F9000CDCDCDCDFFFFF4061CBFFFFF0C30C30518 +:103FA000C30C30C3CF300014F3CF3CF30004CF3C3C +:103FB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C56 +:103FC000C30C30C3CF3CF300F3CF3CF30008CF3C2D +:103FD000CDCDCDCDFFFFFF8A042FFFFF0C30C30CEA +:103FE000C30C30C3CF3CC000F3CF3CF30010CF3C38 +:103FF000CDCDCDCDFFFFFF9705CFFFFF0C30C30C1C +:10400000C30C30C3CF3CC000F3CF3CF30020CF3C07 +:10401000CDCDCDCDFFFFFFF5310FFFFF0C30C30C31 +:10402000C30C30C3CF3CF300F3CF3CF30040CF3C94 +:10403000CDCDCDCDFFFFFFF3300FFFFF0C30C30C14 +:10404000C30C30C3CF3CF300F3CF3CF30000CF3CB4 +:10405000CDCDCDCDFFFFFFF1300FFFFF0C30C30CF6 +:10406000C30C30C3CF3CF300F3CF3CF30001CF3C93 +:10407000CDCDCDCDFFFFFFF6305FFFFF0C30C30C81 +:10408000C30C30C3CF3CF300F3CF3CF30002CF3C72 +:10409000CDCDCDCDFFFFF4061CBFFFFF0C30C30517 +:1040A000C30C30C3CF300014F3CF3CF30004CF3C3B +:1040B000CDCDCDCDFFFFFFF2304FFFFF0C30C30C55 +:1040C000C30C30C3CF3CF300F3CF3CF30008CF3C2C +:1040D000CDCDCDCDFFFFFFFA302FFFFF0C30C30C4D +:1040E000C30C30C3CF3CF300F3CF3CF30010CF3C04 +:1040F000CDCDCDCDFFFFFF97040FFFFF0C30C30CDC +:10410000C30C30C3CF3CC000F3CF3CF30020CF3C06 +:10411000CDCDCDCDFFFFFFF5300FFFFF0C30C30C31 +:10412000C30C30C3CF3CF300F3CF3CF30040CF3C93 +:10413000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C47 +:10414000C30C30C3CF3CF3CCF3CF3CF30000CF3CE7 +:10415000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C27 +:10416000C30C30C3CF3CF3CCF3CF3CF30001CF3CC6 +:10417000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C07 +:10418000C30C30C3CF3CF3CCF3CF3CF30002CF3CA5 +:10419000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CE7 +:1041A000C30C30C3CF3CF3CCF3CF3CF30004CF3C83 +:1041B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CC7 +:1041C000C30C30C3CF3CF3CCF3CF3CF30008CF3C5F +:1041D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CA7 +:1041E000C30C30C3CF3CF3CCF3CF3CF30010CF3C37 +:1041F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C87 +:10420000C30C30C3CF3CF3CCF3CF3CF30020CF3C06 +:10421000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C66 +:10422000C30C30C3CF3CF3CCF3CF3CF30040CF3CC6 +:10423000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C46 +:10424000C30C30C3CF3CF3CCF3CF3CF30000CF3CE6 +:10425000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C26 +:10426000C30C30C3CF3CF3CCF3CF3CF30001CF3CC5 +:10427000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C06 +:10428000C30C30C3CF3CF3CCF3CF3CF30002CF3CA4 +:10429000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CE6 +:1042A000C30C30C3CF3CF3CCF3CF3CF30004CF3C82 +:1042B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CC6 +:1042C000C30C30C3CF3CF3CCF3CF3CF30008CF3C5E +:1042D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CA6 +:1042E000C30C30C3CF3CF3CCF3CF3CF30010CF3C36 +:1042F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C86 +:10430000C30C30C3CF3CF3CCF3CF3CF30020CF3C05 +:10431000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C65 +:10432000C30C30C3CF3CF3CCF3CF3CF30040CF3CC5 +:10433000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C45 +:10434000C30C30C3CF3CF3CCF3CF3CF30000CF3CE5 +:10435000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C25 +:10436000C30C30C3CF3CF3CCF3CF3CF30001CF3CC4 +:10437000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C05 +:10438000C30C30C3CF3CF3CCF3CF3CF30002CF3CA3 +:10439000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CE5 +:1043A000C30C30C3CF3CF3CCF3CF3CF30004CF3C81 +:1043B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CC5 +:1043C000C30C30C3CF3CF3CCF3CF3CF30008CF3C5D +:1043D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CA5 +:1043E000C30C30C3CF3CF3CCF3CF3CF30010CF3C35 +:1043F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C85 +:10440000C30C30C3CF3CF3CCF3CF3CF30020CF3C04 +:10441000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C64 +:10442000C30C30C3CF3CF3CCF3CF3CF30040CF3CC4 +:10443000CDCDCDCD0010000000070100000281703D +:10444000000B81980002025000010270000F0280F0 +:1044500000010370000800000008008000028100D5 +:10446000000B8128000201E0000102000007021099 +:1044700000020280000F0000000800F000028170BE +:10448000000B81980002025000010270000B828034 +:1044900000080338001000000008010000028180BD +:1044A000000B81A80002026000018280000E829849 +:1044B0000008038000028000000B8028000200E05A +:1044C000000101000000811000000118CCCCCCCC10 +:1044D000CCCCCCCCCCCCCCCCCCCCCCCC000020002C +:1044E000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC0C +:1044F00000002000CCCCCCCCCCCCCCCCCCCCCCCC0C +:10450000CCCCCCCC0000200000000000000000005B +:104510001F8B08000000000000FFFB51CFC0F0031C +:104520008A45D91918FC3811FCA18059981918D856 +:10453000809803883D80B8819181A1919178FDDABE +:10454000620876BF3003C36E20E611029A23821000 +:104550009F0254F306C85F0F15B312656038263A00 +:10456000F07EA706DE2A8D29364512C1DE86451E5D +:10457000196F4793FF2289CADF4140FF40632965D5 +:1045800054BE9D22845EA604A1A5D1E4EDA1F2D77C +:10459000A1FE9251C66EEE0DA83C00F85C49656024 +:1045A00003000000000000001F8B08000000000056 +:1045B00000FFED7D0B7854D5B5F03E73CE9C994944 +:1045C000CE4C4E4212F2224C1288A0210CAF808AAF +:1045D0007F270122F539202858D40142087983D455 +:1045E0004BAFEDCD8424101135F447058B76885000 +:1045F000D1A20D34D260C10E20147B6D6FF0FAC0D1 +:10460000EAF50B4841312FB1207EC5CBBFD6DAE7A2 +:1046100064E64C2680D8DBAFFFFFFDB4B8D9E7ECE9 +:10462000B3F7DAEBB5D75A7BED3D92750293BFC76E +:10463000D845FC03E54F4D8CB109C1F26766F680A1 +:104640002787B1C9BDFE3A473C63556D193BA29D12 +:104650008C25EC9921142850FED5232C5082DFBFE5 +:1046600065C397F0FFB619423E7C97D0E911E6C3C7 +:10467000FBE4D5026B873A939C310CEA8CB9194B59 +:10468000642C6B12A33F224B8D82FFE07325398F80 +:10469000B134FC2774754661AEC078C6321E535CD7 +:1046A000D4D0A93815783F847FC6D2BC25B731074E +:1046B00063CF03BCC971F0BC5A3ADE61E5EF2EC28C +:1046C000DFA1F33A6ACD58AE303E7732A789654113 +:1046D000BF3EE3F3AC46633D9BD9E34F46C33FEC9B +:1046E000CC7E518C308F13B18C013CCB540E2F6398 +:1046F000BDB26754101F9B6A58A2322C580F2F85E9 +:1047000065873356035E97ED165C16F8FE396C2FFD +:1047100031E6D7BE6BD6EA153E5962A3A10404B5B3 +:10472000E4F4EF6711CBBF11F1FE302BA0B24AEADF +:10473000955580AFAA5A76FB95FEED673389E8540C +:1047400029B9F65B61FCDE5AE66A86F19799D502D3 +:10475000AC2FFB91D3E5837A6663472183FAD03689 +:10476000818919C1EFAF009EDB917F001E2A2BA526 +:10477000DE420674ECDD2BB0E60C1C87F7BB6C77D1 +:1047800006F3650C0CE758662638E732413A89741F +:10479000713007D2C1BC24F38942A8CE54DCF3B0F7 +:1047A0007F9FE29D87EDF4E7490BE638BD0057F2A5 +:1047B0005066A057B1B53A9D653256EA692944BEA4 +:1047C00038B5EC8D5558029E1324C0F77C8BA70892 +:1047D000FBA998579DCD80A7E659188D3FB42DFFB2 +:1047E0003309F80CBAF3C5C4213F31763C844FF04D +:1047F000CFF1115A5D1C98DE972B8BB01F09F10584 +:104800007217011F3F42A026E0284D543A57FC2959 +:104810006BD8A0D0FA5B59C3C66900E511BC0C3F48 +:1048200061AC4308E54BBD1CBA3BFFB0943B303C48 +:10483000FFD3F30474127EAB00B7C81F1576D9BF3F +:1048400012F861CAABE6C0F7803F2A360B7E0BD464 +:104850004DAFDBE87DF7265E0FD86537F24FD716F0 +:10486000A80BF0BDA5FDF11B91BF5E155933763B3A +:1048700022CA84FAE5A4063B1B0F75C047B18D57C9 +:104880002B36EFBB1FBF2F69B3301BF457B17BF141 +:104890001D37427DF16133C326155B6BE514A82FEC +:1048A000F10B2D58EF29E0F0F97689FEADD0BEC7A7 +:1048B000D19E381BE873BAC6CA9C326375F6F6C43B +:1048C00059C067A5FE1D85F85DE976C185689FF230 +:1048D000EAD643C938AF17B97C976D8B664E1D7FFA +:1048E000F0F764AB18F81EBC5F06F364D0EF62D635 +:1048F00054887AB062EB3AD9690FE2EB748D4AE3DF +:10490000F4C9DF8B300E7C57F98AE0C229569A9899 +:1049100017E5B07BB76DCEF30ACEAF56CEB6E3BC8B +:1049200056CBD86EB17FFE2E54CDA5FECD7221BCE4 +:104930002FDDB4592E0E91DBB26D838C706DC81AC9 +:10494000EC8D20D7417880D7B283F552D403A80FDD +:1049500025BF3C2384CF2A8558E2CBB26D22731A3F +:10496000F888D3DDF72EFC13F0E5DB6B27BCEA7487 +:10497000EBD3A71ADDCEA81A1DA5DEBC1911F8F8D5 +:1049800071A403C0D384788272AD069F6332CB9743 +:10499000A07F879BA902BB3C5F3699D97C0663F553 +:1049A000B007DDD2F55097D952E682F550FAB17BC7 +:1049B0002AD49304EF67389F7AC15BC2D7AB9624A1 +:1049C0000FE07995C0E6E0FC8F21D030AF55C9C02B +:1049D0009F80F7A66979CF8B82067B3CD68B7FB10F +:1049E0002683FA3943FD98A19FACCBF7A3164E322C +:1049F000F4A31696E8FDFC8DFAB15D593F4D85375D +:104A000018E1292CD5FB910468576FBFB279A937FB +:104A10004F36C2737339F5133BD5C5BC0AAEE71ADE +:104A20003FB076B708EF95EDB163D7B050BE2850D0 +:104A30000580DB0E5212CA173193A20C7C18EB8E44 +:104A400033D4A127F5E47541FD138895697C394578 +:104A500026BD909F62A5FA43290AE985876EF05E1C +:104A600083EB208ECD92A12E7B47AB11F81AE01478 +:104A7000581296601724F57FBFDACCF150907A2156 +:104A8000FB187C5F65EACD8E85FA35A6FC6B116F4D +:104A90002E81EBE528915563BB280B23FDB43A2307 +:104AA000EF795F089E1A8700FD8560BF8D666F12E3 +:104AB000F2D7F8DA677C12C0B76A08CC2705BA12B9 +:104AC0009E09F8603D5A3DA43809F1699141BE4301 +:104AD000C79761FC1C1AFF06C4A31BC74FE83FBE63 +:104AE000257392617C6B7A89617CAB0CE303BF4FC9 +:104AF000AD6DD6C607FCDDC0D834A199C6B7A49762 +:104B0000D0F8AB655662183FAA6FFC5B70FE9E81C1 +:104B1000E69F798371FEE9A5C6F9CB7CFEB36A5F97 +:104B2000D2C68FA2F9CF165EE2F34F2FE5F3B7F0AE +:104B30007EFBC677F4E1FF5E9CBF7780F12D599331 +:104B40008DF31F5A6E9CBF858F5F54BB531B5FA1B3 +:104B5000F117093BF9FC8796D3F8B2C5EB423E92B8 +:104B600053A3AAFD684FA481400C261DE5A672043C +:104B70001805A01F860A9904C743519CEFCE450132 +:104B8000BF29417DC7FC2051A0CF2A359E2FDB9E37 +:104B90002FA39EA5F7896837F13F456D22AD376C8D +:104BA000BDC53F1CE0ED6E137D582F5A7F935FA467 +:104BB000F58EDBE560C605F0F95F9E1CD51C3AAFAB +:104BC000F0725193F96487418E383CBE0236A21AC6 +:104BD000E06B47269810AC9F043D0AC62F3B0E7A27 +:104BE00014CB53666E8F9C003DCBE450B9A9E5F61B +:104BF000888FBD9303F3BA5B83FFA4C4F17D72B9C0 +:104C0000E047FC9F5BB75446FDB4A8098CE91079D6 +:104C1000AFD2E8D4BBDBE26F16089F4EC4CF3D2471 +:104C20008A8CFD9766D72FDE30C8F0DD3CE66F48F2 +:104C300082F60BD7CE1FA2C2FC7F30C73216ED53CF +:104C400090845413C9314B35816F31A7759D391547 +:104C50002AF7CC311BECFAB95E63FD0725C67AB79B +:104C6000D96F36A1BDB144609BA1DFFBAA8DEFF5E2 +:104C7000713609719CAEDA7877277278EFC3722C9F +:104C80003E5689AEF7ABFC5B1D9EAA87CD2C40EB50 +:104C9000654702433AFA12C85EF3AA7CDEE1F0DE11 +:104CA0006FB6BA3D00CFFD3F12099FE1F077BC1E01 +:104CB000ED36811DD7B1E14B33DAB7E1F30987FF58 +:104CC0008115E1F35165D4F7F37DE1CF399F84F38A +:104CD00053555BFEA01321ED2A5ABE3FE844087FDE +:104CE000956D9B61A82FF1CF35B45FBC61BEE1FD2E +:104CF000A2A62586F70B1B971AEAF37D3F32B47FF5 +:104D00006045ADE1FD7DD58F18DEFFA0649DA13E1D +:104D1000D7BBD1D0FE9E399B0DEF4DAF8FBC13E5B5 +:104D2000A8EE5D91E1BA715639F938DA836715C991 +:104D300085F4F8B42689E4E0748D93CAEEB6715612 +:104D40002FD783C50C4C9C5EE19CAF7132EA65465F +:104D5000FAF3AFC2059F0FEA7F139C843F7183CCA7 +:104D600002C0C2028BEBE3E35E31E47DC765DE6F18 +:104D700000411FD7FFBDD811F97955F3FCA16A0492 +:104D8000FF2128B72C15D7B91E6D7D0F7F5F2E3000 +:104D90004FE873C656929CD769EB4CB9CCF541F9F4 +:104DA000CEE402F4BFCBE54076F5A5C66B01A4A224 +:104DB0009E44EB3C01F901A4C0C02F5906F9EEDC7A +:104DC00027125C95A81340AFAE639EC126D43381F1 +:104DD00003E9778D4238DC49546F4BA075BDB3664B +:104DE000FAA01312D2C743E5A73573A83C59E3A52F +:104DF000F2444D0995C76BAAA9ECA85941E5C735FE +:104E00003E2A3FAA69A4F2CF354D541EADD940E5E4 +:104E10007B357E2ABB6BDC54F6F92BBAFE8DD7ECC2 +:104E200055CDAF809587EA67B4B9D443DB769273EA +:104E30005712CAF919E55C36DAE3678E8263993155 +:104E400030BEC2F96D603ABAC95E29F603FDC7F5F6 +:104E50007F6F8BE274B299D87470A6D923C37FE1B7 +:104E60005A9043750959061624D70C7B847E61ED50 +:104E7000437A5D8E4ECCDD9B3B13E871F299BFE522 +:104E800061BF75DAFA177540A47598059E7721BD44 +:104E900042F046EB5AEFAB9ABEBF0CFEBAFAF0D71F +:104EA0009E8EFEFB4141A5FECFB45A988478DC1358 +:104EB000ED07E667670E3FEF40795C9664524F441A +:104EC000C0835E56B464A84AE8FAD366AC9F691200 +:104ED000A6B7D07AEC8C99350AF94A554F0C43FAAB +:104EE0002751A9F7B32C49564F80BC9EDE9615C3B7 +:104EF000D76F3F5F07B7C712BF825F48EDFFDEF095 +:104F00000CD48F0E0F63ADEC132BEA037897F5EDFD +:104F1000FD7226FD95E2576C8FF91CDA0B16F87BB3 +:104F200091E20712D5F57EAB5A449F65343EDF6EA1 +:104F3000180FBE73EA3EF7C5CC4BF1ADC44E86C424 +:104F400011D669F1C6B26D36D5B8AEC41AEA556D40 +:104F5000C9AA619DC17F80FCB36A4142BE29D7B80E +:104F6000A847521A0580AFDCE4A47EAB04DEAEC2D3 +:104F7000DA217BE151572BA7DB40F09DAE39EC9451 +:104F800040DE4BACE001027C252D23A7A29EEB6AFC +:104F9000AD4B447BB04C3CF39027C2F73B4D028DA8 +:104FA000B7C46FEE35AEA31A7F30E8577F4E7E163A +:104FB000534E86D43B4DDCCE0EEFF780D6EFE5F0B6 +:104FC00053B9FD48E18DCEFE78AA6CFB42F6921CE7 +:104FD000C1FFF28278D2F1576EF21C407D5ABAEDD1 +:104FE00018D9A39F9A7DD90F5F423FF59F9F9244A6 +:104FF00071527D5E3E3029619C055A7C17F8F79E00 +:105000000F613DFDECDFCD6C0DC0C72E402B786FDE +:10501000D65F331333417DA1565BD05A4671DDCF45 +:105020004CDC8E2A621E07D18135E5A11DD9C54C05 +:10503000D3114F5DEC6DC7B8103A9C32C9A4671606 +:10504000361AED18B07F0DF5C51B8CF5623633119D +:10505000F549F17A33F30B343FC3FBF74D2AE17F77 +:1050600031AB5E85EBAAA4F9230B5426A5027C156F +:10507000BF79366F3EC65F4CDC0FD1E3234BE2387D +:10508000FCA5F17ED90DEF3F691D77F78D48068BA2 +:105090007F15C689580C736D65FDF1FB6DE10F87B7 +:1050A000575FAFFBC5693438C46D82DB1F817F2F2A +:1050B000687CA6EBEB5B44D5E017DC8DF510BF21D7 +:1050C00046D4E2B2221391EE5DAAD5678AA1F71405 +:1050D000B7F7EDB4B8EA80DE3F3779068913C84EDA +:1050E000C86521ED7E6EF2D2F34EE1AD62B45B99FC +:1050F00014C8453B14D618E25359E30731CA918BC3 +:10510000F1663B837514E86F41F8A09F55F692DB7A +:10511000582EC6BB41DEA1BFC71C858705A8DB94FE +:105120005686FD59928CF17C9BD358AFC27F201DCF +:1051300046308A3F458F90C2F01860A80FED2EE3ED +:10514000F351E88491DD1F203E76108B43695502B0 +:10515000228CCF26499D7DFE5626FA7B1C7E8A2F07 +:1051600040FBE52A6F5FA9C5CF977F503038EE121C +:10517000FAA8EA3C68904121753DBE7F5E62FE71EF +:10518000DF416F3A61550DD19B734DDE69480FD4F5 +:1051900093089F00E3780D76609A1A2AE70BC2F80D +:1051A000E3AAE1886706FD5D6EF2DE2D26F487E353 +:1051B000AAFB4FEAD7FF8248F3BCEAFE87F5EBBFB4 +:1051C0003252FF15BF7979970FF8A9F4574F3A80FB +:1051D00099D9675253A20BE85EBEB5C18172F9A995 +:1051E000E473205D3FF38BD323C9E71651974FB784 +:1051F00022E411FF101F9D7EE9D13BD0AE3AB7D516 +:10520000AC527C609B256001A6AC6C5DC2E5639BE3 +:10521000E518AFAFFE02F9B3AACDA82F4A5F7832E6 +:1052200011E3CD4049CD7F0E907F50B9E52F8568C1 +:105230007755B15ED27BE1DFE1F8E7E3C81E982F36 +:10524000C7F47FAFEFF3556978A96A7DF40B9184B9 +:10525000A583FCCDF0F6259ABDFFA4688FA738DFA3 +:10526000443611F94CC707F3737BBFEEC5A7738FA4 +:10527000013C9D5BFEDD21E484F227D77B675A1653 +:10528000FEFC35E7C0F2D40D7A31D4AED6D76767CD +:105290009BE6A7ECE165B939E0403FB07CB3D9E5C6 +:1052A00043BABEFCFC2F9EC1B8CC0716D770E8BF2E +:1052B000ECE583EFDD00F5B21DE6F8DBF8341421F0 +:1052C0003148972AF8BB626C900EA5BF3E283B4739 +:1052D000F1E73F8E0BD2A36CC73E998DEA8F8F29E1 +:1052E0002DFBE40E25025D5A8E15A23F51F7E257C1 +:1052F00032EAAFCF5E17D8E08C08F8DC7C90EC6225 +:10530000C413D151A3531FDDC2DA57015D50BFEA68 +:10531000740A7FFF2F9AFEC7FE9C39C4CFAFBC86AC +:10532000FB287FB6B870FE25AF3CE8C0799C92AAF6 +:10533000395F3FDB90E886714BCCBE44954AFEBC9A +:10534000E4B91F12BF2D3EF2C3448A7F3077B28981 +:105350006C055F32CE6FD1A6D934BF62E625BE2B75 +:105360007956F4E0FEE059894DDF11412E5224AE0A +:105370008F4F355B704D65A770E1C07D85B745FFE8 +:10538000568AFF2DA5F8CA0FF5FD20B68CEA67AD49 +:105390009C4E5F88FABE1AAC3CA1FCBA65753BD244 +:1053A000E7F410F7608C1B5731C9A7E143B808FD3B +:1053B0008A47A60DE6F4614E294FFB0EF4FD147CDE +:1053C0008EEDDBCD6E5BAEE13B76312338FE726D48 +:1053D0007C803B0AEDD5538960FF45985FA1A4AF5F +:1053E00037605785F057887C7379DFF208976F5DD7 +:1053F000DEFD33A6E3FBBFBEC3E507BF437B05E08D +:105400000A0CA6F7FB6609A40F2C2C1049AEB7981E +:1054100035B936BED7F904E09670DDEDE317EC3F01 +:105420008EF04F766CF17AF82E445F56E1788EFE5E +:10543000FDE972BB5893FF04C928FF6C1397FB81E9 +:10544000FD091F8F4B98FDBF7806E515E413F7AFF4 +:10545000CB5F367B70DE9F6F3FF0DEBD20A79FB72E +:10546000E8726AD49FE1725AB273028B24A79F63D9 +:105470001A42243985E711E554E9203EFE47E94FF9 +:105480001D7F3785E14FD78703E1315C1FFE5974DB +:1054900046D487F0E71D96D79FFF74BED3F9ADF4CD +:1054A000971543293EA6F3A5CE777D7CA9F35DBF72 +:1054B00078A3017FE1EF2D188301B83CBBCD1447E1 +:1054C00028DFC3F77FE1BB43A9E3094F6E5AC658F3 +:1054D000D3A1D4F8D0BA3FACDE12D6DE1D56F78485 +:1054E000B5F786D5AB0DEDCBDB0EC83CAF256068BC +:1054F00027AE78867D322812BFFAB95FDAFA85ECDA +:1055000043BE507AE97BF34AE6B3633C7CAF48F193 +:10551000911EC0F12A18A7677B861FF3241A6C3CE2 +:10552000EED4A3F63AD05E6C88E5F5DE047915EA90 +:105530003DFD79AF8DC7F57A3CBD8ED810FBEDD817 +:105540001E91F476879F4D8FE467C28A4272D4C160 +:10555000067ACFE3FDD344257D05C65F9A441786BE +:10556000748A6AEF71609E41CF9EAC3BE7C0F34501 +:105570006F8AB48DD883767B0C92C72D2587F877F8 +:105580009F32DF5393317EBF87FB79456BC3EC11AC +:10559000B696F8A958592EA33E05BFECB871FF8204 +:1055A000CB45A9D65FC926E37BFD7BDCC145FBBDAE +:1055B000748BF1BD578B0734EB7232868DD1FC7141 +:1055C0001E8FD2F4F23431E7CE39408F9EC322C30E +:1055D000FDFB337B44A2C799ED7CBF9EE2F6D72347 +:1055E0007FF7923ED4F1D489F2240FACAF3A5FFD3D +:1055F000AFBC87916F767D98FB33283B777D90FD1C +:105600005BACFFE6FDF40F59FFF6535EB7D13E49A0 +:10561000CFEB76E2F79EBD7F4C7F18EBBB2D149F3E +:10562000EE79FDAB5CE49F9E959612D4773D438066 +:10563000FE681FECFD2AB783D6D77AA2DB1F259917 +:10564000DB477BFEF6B1108F25CC0AED86D7A34948 +:105650009EAA5EB3513CAD67EF5779A176FF779D67 +:105660004FA5B67FD963677376227CB17CDFA7EA4A +:10567000B7D73F5F8BF917ADFBE485F07ECAEFBE6D +:10568000C9453DDAB393DB43DDE68EE7707FEE6814 +:10569000FDDC9566C073370A550AAC9B0DCF14A08C +:1056A000DCF4C7CB371427BC527CF4FC5F830FC1FA +:1056B000CDF59DDD6F1570DE5F7FFC21EA85D72D6E +:1056C000C497FA7C3F6FA9257BE572F37698799CA5 +:1056D000E4FF9D790B812B99F728F33F37BD7F2D90 +:1056E00039892EE172D09FCFF73E44F597ED2E8297 +:1056F000F70AF9FDF67FF2F97F6BBAEF04BA3B2E99 +:105700003FEFF27FF2790F4CF737EFD7E8AE627ECA +:105710004BD5EFBE21F8BEAD9E5BFB4F2EEF03CD08 +:105720005FB7EBD7985C4D99189F43AF01D669C519 +:105730003EB311C3856B46CC54D1CE14C3F62BF5C2 +:1057400072AF99FB4D22EE5B629C6F088FF331CDF7 +:105750008FA22D3D185A528AC98E959455DCBE965B +:105760005CED6EC0CB9A6B17B82877888D3DEAC583 +:105770007ADA6417C5AFC3FCC97A81B905B06FA5E1 +:105780006B6F398CFE8D79842960C9A5F21896ABB0 +:10579000B5B8A459950D7E8F9263ACDB9CC6BA4513 +:1057A000EBCFCA38FCD624E6C7F8B43872BF8A7982 +:1057B0006DE218890950B7B1261FFA179624E3F74E +:1057C0001B31C01E12CFBD5A3CF6F6E1716CBB1BFB +:1057D000F138D244716B4A2E25BCB8FC6B789E8D93 +:1057E000D588D755ED884F09FD5F6E7F91DFCC34AA +:1057F0007F59D2BA904698DC36633BCD4FBE2C9D84 +:10580000385DD2CB353A2D33D045A74304FA18E89A +:10581000A2E3F9DBD2279C2EE1F8DF6F7612FE07B8 +:10582000A2974E9734C5CD505ECD9ABF3015FD4935 +:10583000ACA77918ED336BFE8214EF663EA493EAB1 +:1058400062482FF4DB02E0B7FD7EFBF31427EA7A0F +:10585000E9D81D084FD96F456605FC756FB7B300D1 +:105860007E2FF965F4434B5B458AFB3329907757CC +:10587000C8BEAF6EF797FDCA4EF329DD69F1DF06AA +:10588000DF97EEFA2497ECB095BDE4D7F85E1238B6 +:10589000DD7D1DB9B8AF5B2A71FF239C5F62659EF9 +:1058A00027D0B93B7A0EC66D846D3CDFB6B4E51ED9 +:1058B000B3C5907F66D6DB915EF0BD2850BE13C2A3 +:1058C000179AE7A9FB1D9D2F0A1CBE36B31FF3765E +:1058D0004BB7EDE8C6F853E9518B0BC3D255DBBE8D +:1058E000A0FD8D29BF7AD9D141FEB668883FF4F377 +:1058F000FBB789C41F95AD15E487409DF8A2B2257A +:1059000072FCEB72FE69D9AFF6EEF2010ACB7EFDB6 +:105910008203E35BA7DBB73AC8FFDF76E9B85B3FFA +:105920003FBFE5914BFAF9A7F11FE0BFDC2087C527 +:1059300049B60D227F04E0CB8B94EFADF35BD9CB5E +:10594000679FC33874E7CECF9F4378CBFFFBCBE78D +:10595000D09F60AFDBD4AD889797DEA5389EFEDD83 +:105960002C99C79DBB5F7C81E29FDD1F80DF017F9B +:10597000BAF79E4A477FB27BC7D789182F59BE779F +:10598000DA609CEFF257A70C6611F4885E22DFFA0A +:10599000AF20FE1A4EAF03AD07C8EFE9027AA3DFCE +:1059A000D917B769A9E07130A716AFD91E39CEDD76 +:1059B0002F3ED37AD79D378DC7D2EC72B22B88D3C6 +:1059C000BC03741C7D05F4DBFE88E67F46A65F17EA +:1059D000FE03E8B42C8C7E675B17FDFC197CD73A7C +:1059E00068C0384DE00AF0A6C7D1BF27BB7F22A30D +:1059F0007CEDFC25C5C5906EB7C144BB5F3E9B8E58 +:105A0000FB0F9F9A7BEFE7E7322C2AC61B4AF7BEB3 +:105A10004FF2D3FDEA118A53332D9EDDCDFAFEF00D +:105A2000F8A3965359B5C5CEE33B1AFE31FEE37495 +:105A3000D0732DCEC3F9588FFF0C14F7699579DE1A +:105A4000881EDFAFD8F2A1164F09D24B9884743A62 +:105A500076C9FD081D0F2AE26162681C33727CADB5 +:105A60002FDEADD10BE987F1CBBE3825D4D3306E14 +:105A7000E517DE6711F441F7661EFFEC3647CEA34B +:105A8000D2E39ABF0A9753FF95C5332F07FFB7C5D7 +:105A90008F5F7652BFE178EABC10598FBF2DF37546 +:105AA000FFAAF7C5CA0543BE41B9C97B04F9B1A233 +:105AB000F598CCCFA5F0F352FA7C3BB5BCD1CE978C +:105AC000448A77AD6A39407A3C5C5FE8FBA6E1F036 +:105AD0009ED0E0AD6CE3EB44E74EBB5F817E3AF7CE +:105AE000EF267EAEDC7E8CE26D87B6FD5AEE08595D +:105AF00057719DF087C0DFF9CABE5C1EB7E579EC2F +:105B0000E1E39CD1F461D59EC8E3546DFFC2304EF1 +:105B100099AF45E6EBFDA5C73B2DB9EFC1FE4EB7EA +:105B20009B19E6799E6E11A7473A17F5AEB66EEA55 +:105B3000E77E70BDA47CFD23FC5CCCF8B7A3281FD6 +:105B40007EF991E91FC6C463098487FE5A6B399FA9 +:105B5000B6FEC49D8AF46E3D72AF88EBD42EC46F3E +:105B6000889D9FF74EF5143BE885BC8F3CE3915D23 +:105B7000C3F5CDC4A32603FC30CE605C07EAA11FA9 +:105B80003CA782F96E088FE8289C8EF088AA49B558 +:105B900009FDE761563C745E40EFD7AC1ACF03B005 +:105BA0000BE39CD84FD24C1E474CBE8B973EFD3C1E +:105BB0004E7194BF0EE659A078D32CF07D927D7D76 +:105BC000C64186E7BF2651DE7696C5786EAC4B554A +:105BD0007C26D0DFCFE46C5937D949F907D7584232 +:105BE000F30F582017F9516FD7EF7D587E421A7E78 +:105BF00002FD881A7C595A7EC210D621A07DBDC9EB +:105C0000CECF270E55E24DF8FDF39ABDA99F3FEC8C +:105C1000775E31EC9CE2E5CE27C64FC95F3AD405EA +:105C2000FCB47ACF14CC5F8FBF277F47AA8A791242 +:105C30007F9E82E757E25FC81F930CF513AB1F9C52 +:105C40004AF5FFC81F930EF56F1AFF8DD7CB04CA14 +:105C5000572D583D7A2AF2EB55CBF92CC08851CEFE +:105C6000EF40BC75793EBA7B9113F31F7A658E5F66 +:105C7000E6C176432671BCA5291FED403C0D357564 +:105C8000D4227FFE7CEF57B1A8179C4C25FCA8AC12 +:105C90005E45FAC1A349172F9147179E4FA6EB9374 +:105CA000CD8AF70184E391F923E85CE0332533AD35 +:105CB0003C5FCF98C7C0D478A26791464F84D31A6F +:105CC000928FBF58F4C9FC5C4C93A6AFA6AA389E2D +:105CD000E02B172F5EF7EDE17A50E74BED5C69C8DA +:105CE00079C687105E9FE27DC892D0FF3CE31D1607 +:105CF000CF0A7C9F5C7C3E1DF95B3F9F187ECE9156 +:105D000049BDA648F65FB376CE7120783D56EF2A9E +:105D10001C37F377CE9D8741BE4617C92E4CCD1C4C +:105D2000BD627C82C4CF15529E439546BF24139713 +:105D300043F610A37DD61E8BE046BFB9E74195F42C +:105D4000775AD16DE457F54467B4603E50CFC3FC39 +:105D50005C29664CA31C0DD9131340BF0FE4E05C13 +:105D6000981C9C33AE73C6717B2E3ADB3AA83F5524 +:105D7000EB0F0CB0C4E0B9E01E91EBE59E1A27C111 +:105D80003184F9F6E1FA7EA5E36DB518CFFD02DEA8 +:105D90005F40BCE878FFE5C0F47B45A3DF2B91E8CA +:105DA000177EFE74BEC5FB6B6C7FAAF8D02A7415F3 +:105DB000C3CF9D86D3B54A6ADA88AE78E29E2F6853 +:105DC0009DD1E9367A852B411A64A0E3EBD8EFE840 +:105DD0003D5F98105E9D7E4F0F90EFFD070B5FCFEC +:105DE000C2C74B9CD391E28DB4FE60102E2158CFD8 +:105DF000B5E6D1F8834D3CDED3BFBD10713ED07FF8 +:105E0000E6A5F2307355DE2FE0FFFD50BEFF10F126 +:105E10003F2222FE3F46BC03FE3FC6F65780FF4F9F +:105E20002E857FDDAE2FD3F44219EE2B01FFFCC58A +:105E300039333113C62D1415E2FF255B456D1FD292 +:105E40007D5B7262508F2CB9BE7A9F19F870C9B30E +:105E500002F16991765EFD73ED5C4B785E5FF11C3B +:105E60001FE9C9CBE7F7F9490F956D333EBF10E441 +:105E7000DB74CAC7F5F1F393A22617E1F83FA368D4 +:105E8000FAA228D6D02E9C0E43AA4D863CF0E429D7 +:105E90007DFD909F976472BE4FF1B53F9819C6077C +:105EA000DC52FCF800E263BC3015FBCDD7E456EFC2 +:105EB0006FE80AE33A9FE1339EFBCB6A349EFB1BFB +:105EC000DE9462687FCD864CC3FB91FE6B0DEFAF15 +:105ED000DB36D6501FD57283A1FDE8B602437D4C58 +:105EE000E01643FB7187671AEA13DAEF35B49F783F +:105EF0007481E1FDF51DA586F7377EBACC50BFA9A8 +:105F0000F75F0DED038BB85EDC5F939486E70A7450 +:105F1000BCEC5F2A9B547CBE34DBA4E6863E4F7407 +:105F20003B73B1CC73A37F3590BC4CB126A785AE33 +:105F3000CFF9CC6CD06B53ACC67A8155E39774E043 +:105F40001720FECD56A35CA556CF6B02B39BA52CA4 +:105F50001946F9D2205FB758B97EBBC57A65FAED0C +:105F60004E6C7FAA3240E7ECC3E54B44F9CAA2D29B +:105F700047FBA9CC45F9961B6D463E4D1A40AFCC68 +:105F8000B31ACFC38BEA619B649013FDF9F9A8D0D3 +:105F9000E7C2E2DB286F67A07EE5A405B76E017D4E +:105FA00029277BA9D49FAF9A638A9897F790F53BEE +:105FB000FA491BFAD94F0F217EBB92DE7E0AF3CC41 +:105FC0002AE7F592BF946C31E22558770DE67954B3 +:105FD0004E7E8E50E5FFDC54D3782BAEF7FA3C179B +:105FE0007D303311F303D206F09F5ED5E6F15C4DB0 +:105FF000C9AD45C3B03FD5147ABF457AA0AA10FDFC +:1060000098A15A1EF453A6C8F94A3FD5FA198C0A2A +:1060100014ED035521FBA0ABF8238704F3F8779325 +:10602000F7A7C8170B46B7E7F173CB6ED74CB2ABE7 +:1060300054825FD743E98AE729D42BE94912736672 +:10604000F48767F03C6F6306BCAF8F33B914AAF7CF +:106050000A389EE5C78C0D82F1EAFF5B24F8EAF767 +:106060005F4FF93C16A59AE2A7FA3C99B6DFAFC795 +:106070008BCF26CD8A413CD65FDB776E8761FDAC46 +:10608000E26DC77ECFAE37D3B8F50582E1BD3E6F76 +:1060900069C31D741E2B5DE1F32E867923DC9634D3 +:1060A0000E57FD73024B23B8FEF7D243E8BFEC8ACC +:1060B0007661BC0DF0B189E8EDCE3867D2270FF3D9 +:1060C000AA18A434AF21FB25B21FFA9695AFDB4C7A +:1060D0009D9588F654F23546B8C5F566F20717C5A2 +:1060E0002A94AFE0AF59A1D1D538EF554933EF9C91 +:1060F0000BF0D4BD23324CFD7176342D3D04DF15F9 +:10610000B746BBFCCEFE78EF72723801EEB7106E68 +:10611000714321CD9BDA21DC3F17D83319C877DED4 +:10612000E944FF1413C37D9770F8FFD3CAE3C4EFAB +:1061300058559A879C547CEB9641581691DC1DB5B6 +:106140000EB8CE7F68E5EBFC87D608EBFCE5EEFDEC +:10615000289FD37E084BD16DD2ECDAEAEC507B1944 +:10616000F4D649EC57AF8B313FCEC57E07B6CB3C5A +:106170004DD91997B7CBD01E43FED3EDB1BF5A8D81 +:106180007664889EFD4AD3B35F5DA19EBD80ED4ECF +:10619000DD1B8868C724C891F5DC381BC77F952AAA +:1061A00033CAE31B209E9F6D8B6C1F0EB40E5DCE19 +:1061B000CFC88CD6F954D7EFDCDF60C532ED2F9C09 +:1061C000D9E07F241BF729E38751DEED40FDA4AE23 +:1061D000F8830DF1ABE36D88CD884FC0A3D3C6F92A +:1061E000C4698B640F96031E4D063C0EC7F603D997 +:1061F0008357ADDF4B8CE76EBA357C839E9771BCBD +:10620000AEBB3ECEC3B845E5EC73A4E7AF7A9C398C +:10621000C67544F7BF611C01E7DF7DD77F6B71B79F +:106220000E8A17D5BD7A4D0CC6A72A0AFAF48695B0 +:10623000DB8599A407BB7659DC0867571CCFE7ECD0 +:10624000DA35F110C6393EAF399C2985D82D5DAFBE +:106250001CC933437F5D3B8FE4499420E7277ED1FF +:10626000DF575CFCCF3C8F123C27D0C76F56BE0E69 +:10627000ADB7F1F8C9D398C7369AB1F7A363F9FA65 +:1062800091687A1C9F47BFE3F3A17E7F5470E5C7F6 +:10629000002B26DD554C66ABE58DA600968F0A6E69 +:1062A00011E355BE91FC3C4D52161B9101FD284750 +:1062B000DB03088EA3A3D78DDB29EAA7EA3E2C0BCC +:1062C00014EF02C47B5CAF2B097DFC37878DB3A133 +:1062D0005F214DE17AB7777E941FEF294A34B98F59 +:1062E00080AA67670E2F8CC5F77F8BE6F2F258D233 +:1062F00089265C8E7039A038D49B665ADF960D7162 +:10630000272F82EF974D88E77EE905987DC839965B +:10631000C7E367091407B9007881E714FA023EB5AC +:106320004BCC173316F4B089B955F00BEC9342EE11 +:10633000D9C1FF6876FC604DFFF6384D3E33E0452D +:106340007619DBD509EE0C5C4F7781FC0D03FAB4AE +:10635000D558A97CAD464D1806F2B8A72689EAAFF4 +:10636000D738A90CD48CA0E7FB6B5C548F36B5A74B +:10637000D37A2C55AF9B87FEF5FD120BBDB723BC1E +:10638000C47B568E87C8F9972EE69300AE2F353D15 +:1063900052FBD638E2AFA7C600D431FDBFFFD98A81 +:1063A0003F644D053D98FAA3C35953418E9F12781F +:1063B000FE021E188E742E552F9F32B7C4A2A9F06C +:1063C0006B1BF34D4DC2BCC8DE3F158E61CCF6E8A9 +:1063D0009FA64E1D09F3C7FDFE14C6F6DADEABC755 +:1063E00073D8A9FB3FAB8B81F9C86DFC3E9F8982B6 +:1063F000A756407D339BF30B933CB598CFD97337A9 +:1064000073E2FEBE3ECE5E1BB71376DBB89D3951FC +:10641000E0FCC1E6CA5A1E416F6EE8BA11DE3EEFDB +:10642000C0D7748F0F8CB72FD5305E2FC51107FAE8 +:106430002E75FFD7B48E5CE9773D1F49FC7C84C480 +:10644000F32BBAE6266EA6FD78681FBA8FDA2347CB +:10645000B6D7DED2D68106EDBEB79F65F07283A6B1 +:106460005724C6F5FF6BD105BF47B961DE38DA5F47 +:10647000AAD3E209933A7AE5F9767E2F5C3ED413EB +:106480004E78043C0FD7A5D13355601ECCFF486031 +:1064900033840228DD36CFDBD84FD2C24DBE97D130 +:1064A0005ED86571A2D9A3E3ABEE03D98AFA216164 +:1064B000CF31DA8FAA133A64A4F7978F7C4D71CB52 +:1064C0003A737532D56D171BB0FEB4BD7A23D699D9 +:1064D000EFEBA96F003F0CD6CEE1E313D463BB9082 +:1064E000E829583B57EF067ED865E6F52F1F394B54 +:1064F000FCB1CB5C3D9F8DE1F57A98EFAE586FAA69 +:1065000009549052FB65FDE19BB0AEB7FF92DA777C +:10651000DB546E3F2ADE0CA47F5F5D85BA3DA42E5E +:10652000F13AB3F2529F5FC581AF297FB8720FE78E +:1065300047C41BCE13EFCDC375E98C7AD451EBA4BD +:10654000B87336D7D701039FE9E753B798BC2C2A15 +:1065500044CF5E085BFF42CED9B1A88490FEB43828 +:10656000763A03BB342B186FCD642E2A87310F95F2 +:10657000D9DB96EE47B42DBBAFD5897A2B3ED7FA3F +:106580008097E868F41F9ED0F4E2FAE8FC1BA301B0 +:106590009EF582778D887AF165B34AE72F3A24B267 +:1065A000373BB5358CAD3053BD5C3BF76D5EE95D77 +:1065B0003312F5EE2293AB19D7B30C4FBE19BE2F91 +:1065C000DB9DE1AA65C1BCE7B2D896C4B14A30EF01 +:1065D00059AF3FAAF1D946B5C986F7D2E8FB439532 +:1065E0006DEBD2717FFBB37D1F903CBD1F95417C4D +:1065F0005CD17A44F6DA69BF4CC6F3299FD9FAD642 +:106600003F5AF7BE6C19740BEAF52FEB4D74B8794D +:10661000203DF406E83F3738C8876AAC54FEC25DB7 +:106620007D2D9ADE055129D36C60B4BF90E9569157 +:106630008FE6ADB9A6C10A7CF482AC8E443E9B17AE +:10664000954B7C5B162B72BE64B907DD92B6CF0DFD +:10665000F5D43565D3BE533CBEC8686F546D5288BF +:106660000FC00EC8473EA8DC60F2E17EA2C9DA4E38 +:10667000E77DE74531CD8F369E4F5CAFE93BDF6C60 +:106680001EDFBDDC39C592F351741E51AFBF1FE54B +:1066900024BE28917CB4FF5572DE41E718BFFB3859 +:1066A00056C379C8FEE32804873E4E79701CD25742 +:1066B000E51FEC273FF88D6B757BD64D71ACE53B44 +:1066C000B4FC059B7B30F6F3B4A62718FAB18077AB +:1066D00029A3AFEE9340CF1CECD333F90D53D390E5 +:1066E000BEC1F76C92410FB925A0D3C128ADEEFB16 +:1066F0007EE4F65161ED33F5FACC86A993FBC3F342 +:10670000B42D58B7427BE91B4B5F1DE1A373F5A184 +:10671000FDC5E9E3DF4BFDE9FC971AB5F0A00FF8E2 +:10672000EF60AC271FF37C7A673327CAE166498D97 +:106730007285D021358AAF3725E7AF35E03F88F73E +:106740005C03FD4FD5380DFB8A8B8B96D17998541D +:106750009D5ECCC7CF776DCA32EC27FE7F38AE1670 +:106760000EF700704CFD07C331C2305E108E1C0363 +:106770007C570B87183B6B7A06DA6B8F98280F28AB +:10678000D1E4B366A25DF66F268AA70C673C0F883A +:1067900029E30DFBB4997B2CF331FE9E29B1C3D2C2 +:1067A000589427B7B316D7A99F48645FC173AB3914 +:1067B0000E876E72E3FD4F2095D45F66B9B7821FD6 +:1067C000F2E6FB82FA3ED37095E5E3BDA09BA3E71A +:1067D000DF188DFB66731EAAC23C98E795F12F3532 +:1067E0003083BC921DD2202C253BE3ABA8871B70C5 +:1067F000BF767014B75B04F670C3E1E448EFB9BC30 +:106800009E5BF3F0348C1B34AF745E8BFE53B3CDC0 +:10681000DFB21FF3761E53E8DED6AC47FD8D9950EC +:1068200017D79968BD1463FDDB9A71DFFDC96C173A +:10683000DA11CD68BF60FB4714F26B56D538D3F040 +:106840007E923A6D1DD8B276B28A79C1F58A1487E4 +:10685000EBDD2A73F55C3C7731EED18D0DD6EB5133 +:106860008FB91A07A9BC9E948CEB9A33D33A467B16 +:106870000FC868AE75A6A8B1C1FAF06FC0FA203D86 +:10688000B3B1C19D86FD2E2BD5FA3B88718A17E2E4 +:1068900034BC68EF33FBF4D2C606CCCB126B83F565 +:1068A000A930DFADCF723D3518FA47FB0BE6E3C3E5 +:1068B0007B057B874B744ECA06633B607EB691991D +:1068C000B4DFD70C7A11EF2BEE1DC9DFEBFB34F2EE +:1068D0007013EDD3607B5C6F6CC9BCBD3C83DF572C +:1068E00020DB158A37C07A3015F39E14A6FF71F3AA +:1068F000B8A4B68F1185F70184F0A375ED323AF78D +:10690000691D66DC9F97D38C75897916A0BF27AA6D +:10691000C6E737466BF94183580ADA6DC34D3E131B +:10692000B61BC9FC545EC702648F8D621D541F8D57 +:106930005E63161E5B72D241AB71CC2DF238AA4752 +:10694000443B3171AE1E47F24E41BE74476B7661D7 +:106950000AEF3F7EC62CCAF7F569EFCD33863D318D +:106960000DE6B57EC6DDCE50FB4E5F2F75FBAD4804 +:1069700083F9CB6821A2BDA0DB7545365E4F98E553 +:106980007E7A14C611DBCD26BC9FAD588B63166F83 +:10699000C84F44BBAC68DF5CB287D74473BB6CD1D3 +:1069A000FA19B277149EF79A4F767FFEBA0931181A +:1069B000A76FB0B962AE47FEFD23BFDFF54AEDB168 +:1069C000E6C46B0A501E9BC1AFC6FB8F0E9ADDCA90 +:1069D00018E48B75C3C8CE6C8EF2D6C742BFCDFF0C +:1069E000EA74D541FD6736F7F823384E43147F8F9C +:1069F000F726216FF6EDF73F2F5C8C1E78FCF0FD3B +:106A0000FE83B191EFF1BD43C35FD0FEF090DDD9BD +:106A100060F6C4DC87F0BDCBE779D6EA89512F1147 +:106A200067FBB486E70376D6B85840E6F7D162BD77 +:106A3000A4683FDDAF5CD22250DC7C096B223D3A7A +:106A40004C89D5EEA731E6C59616BD4DED4B5B7969 +:106A5000FB32D642ED757AE1BDB501831D3ACEF029 +:106A6000FD1DD1DC6FDDAC781F43FBFF9119D9C44C +:106A70004FC06711F32DE207D877B9319AAF1F37AE +:106A800062DBC8F628F163B87DB85CE0E7B307C203 +:106A900053D57993613D0ADE9F21D37AD4ADF9496C +:106AA00087937CEB6F84F97F9FF54A24A7DABD2397 +:106AB00075825F42F9FABE33ECDE1B2D0F68BAA671 +:106AC00025FE43CBEFF93E6B79C30DFDDCCE02F41E +:106AD000DD61ED9E1214A4487919D0AF411FDC3A54 +:106AE000C258BFDD65ACDF3929F23D7D6B6BD4B494 +:106AF000D07BAAD60E708EF32D8D5E577FDF120BE2 +:106B0000CFEB7B0BE95E81F994B47FC1F3FA141BE0 +:106B1000F3A01ED9BFCF46FB21558ABC1943165599 +:106B2000E0EFE2BDF08A9D9F3740FF17E3058A99A9 +:106B3000B70FDE97C4F751123C495A3CC3953463F2 +:106B4000D4B7871BFD2ACA0B96D846DC770DE627FB +:106B50001AEFEDE88AFE380FFD6398CF6C8C4FE892 +:106B6000715A7D3EFF287F2C5ABBCF399C6E6B3407 +:106B7000F9A80BA3733DD23907DF73B9F952BB876C +:106B8000FF29C143796889261E17ACB3B98E529C80 +:106B900044F30FEAB4B806F37D5DEF56C2EC9510EE +:106BA000FF227DEDD7F5F539E477F338882D6A15A6 +:106BB000AEC30D36BD6EA6FAD3E6A600F9FDAF5AF8 +:106BC0009C181F83EFDD1867F3CD1D417E5D5D06C8 +:106BD0004BC17B0EDEB0CBB4FED6BD6A69C6F5D81C +:106BE0006DF376DB42F249BAECEFD1F9A608FDF974 +:106BF0000CFD0DF976FDC1F8AD8877FDFD1BF6A7FC +:106C00000222FFCE49F91B69ED1F7BA19EB8CB4242 +:106C1000714FFDF70FCACFE7D1FD8C7A7F13144E69 +:106C200087CE1AD5908F5D8E7A3707E5A09DF467E1 +:106C300045CB2083DED4F569C5F91B68BF2C4857C6 +:106C40002D2E21B5935EAA38FFBF68BC3B909E34C1 +:106C50004E12E9F781C74935E8E3E038930C70F745 +:106C60001F6732C1A18FC3DAA20CE79FEBCC3CAE09 +:106C7000726698332636821ED14B7183C970FF60CD +:106C80009DE4B262FF75CA4E35347F287C5F00EF09 +:106C9000C56421F0D5C17A86C1720BF3525E403DC6 +:106CA000F6132207A2D9A562BF62C2F8E9F92EC67F +:106CB000FE45B9BD107D7233F22DD88B3F583B7E17 +:106CC000950FEC49C9EC6947BA4A769313F3686BA0 +:106CD0001513C545EB92AC64FFAD12CA559473BD54 +:106CE0005FA9432238F47D8F81E6299F77D03CC38A +:106CF000EF3BFB9F1B4FA176FDEE573B30D7930F29 +:106D0000FD5B54930B455D4E53D82721F40FEF479D +:106D1000DA2045EC27BC9D8EFF01E96CEE70203D2A +:106D2000BAE3A58879101B95EF9807312F4C1F27E0 +:106D30001CCD0EE0F74287232383F4E54605F5A535 +:106D4000FDCC9FDC4ED2CBB4EFADAF7FE684A9562D +:106D50009E4F6CBC576F20FED3F1627DF341C6F3AA +:106D600053BD947F72393C4882CB43FB007629E2C5 +:106D7000BE36584286FC384931E64F35481EE2633C +:106D8000F34DD556DA27495B69C57D92D592330616 +:106D9000FDD8DE37C1FE83F9353A79BE6A78FF6BDC +:106DA000F01E66B4731553C4FB79A306B0AFBA34B2 +:106DB000FAACD97769FE01F5E1C175372A4E5271F7 +:106DC000DD359B39BC03AD4B7ABF03E1EBD17DFCD4 +:106DD000F71B2C39563FAEFFE1E3354A1E4F3EBC50 +:106DE0006F047870DFAC31CD4DF86D542515FDD5AD +:106DF000E81151CC1AEA6F65CCA2F767E2E3F1CC57 +:106E0000226B8C8F9C97A3E369B7F21DED1D6F1861 +:106E10005F0E7F8FE2E8217CD9A94CE8CF97BB9128 +:106E2000171338FCA1F7A65A338645BC7FB21F7FE3 +:106E300086F14DDE6446E7F70643B919FA6ED5EEE2 +:106E400043AAC0B50BFCF4F27B14A6C2FAE677E4C1 +:106E50005F4039C96BDFCFCFD1B426F07B1EB5EFD1 +:106E6000C3C75D62E7FEC812BB4A65CC51F72FF17C +:106E7000F7375ADBA39C785EB1352EB21F9363D7E8 +:106E8000F3689AB473081DB44FA1B7CF9BC7DCCD8C +:106E90000AC53D1BADE07F25F4B5FFA9B63F0282D0 +:106EA0000BE3DCF9DBEB9AF9F9513E7F8CAB62FB2B +:106EB000C4C48E5C41FC0E74DBC60CF7DB55583B3A +:106EC000B251CEE79ABC997618A7EA684722D65BFA +:106ED000DF3E9D4E7E6F1DB7377B774753DCA03F6B +:106EE0007D6AF979F2F329CC37A83FDDCAA500AD58 +:106EF000ABE5E7D3996F1CCDDB678D0BBEBFD3C26B +:106F0000D8A4B1C8001C4F889F48F430DB4D067AE6 +:106F1000803C5E67D7E88178EAA3B776EF4BA77627 +:106F2000BFE071CD5F612AF7D7F5FBA58E67F7E566 +:106F30005BD07D5BE536F713784F0B3B2252BEE604 +:106F4000C229FCFEC48516770CDA570BFF53146A6E +:106F5000697F93F3FD220D7F9DCC45F70EF8D6DABD +:106F6000F8BE4E987F96F154FEB83FC2F78BDA44D4 +:106F7000CA1B5F3045F161BF79ED05BFC4FDF9E281 +:106F8000C6683A77BEF07BAE9368D72D7CC2E6C464 +:106F9000DF7B59FE41667E32F4BBFCC90CD507DFAE +:106FA00045AFF024595DA0271FDB53887E45833011 +:106FB0007FBE3006FCCAC70EACC2B898F4CD94CFE1 +:106FC0006D507FF4B1775661BCE9B718E7263BF600 +:106FD000DD42B4635F42D0F4FD3FC0C14B874D5AE0 +:106FE000FDC4AAA9A0F2AF4D6835292AFA65275633 +:106FF000E139D9C438F718138CF78EFDB342EC6F22 +:10700000C113A3CE6D80F7E7ED17C8BE003A69DF64 +:107010000B374F01BBBB78B25E972D588F8F6686BA +:1070200038BE3933383EDAD9AD7A7C8B45DD8C7188 +:10703000F7E305D55324E83FC3A1AECE19C9D8C4A0 +:10704000F5F9AA1BC6CF76C4DD8CF198D6BE7D8338 +:10705000F8D5181F6B65DE0366787FD3E3436EB601 +:107060000262E30779C6A830FF41D629ABA7DFF457 +:107070001DE46344BFF3590DF60492934388D2F4A0 +:1070800015FCDEC23EF94EE37CDB571FD1C1CFC3F6 +:10709000E8F5245E6F5D19595FDC12C3F9BA352A31 +:1070A000F2FB664D3F00BE03147F6D8BF60FCF08D9 +:1070B000EA0F901FEB2492A7755C7F801CCDB493E0 +:1070C000DC46ECEFDBCA6BAB76AF79ABE48EC6F88F +:1070D00082AEC7308286E3CCB53B0DFA39AF7D0175 +:1070E000E9D751312A87C7C9F19330C5A84798B568 +:1070F0003D3B74DFFE77DA3C33AED3E33F013974B6 +:10710000DF69F98EFC4B9E9F2DC7387F88BD1D9C83 +:10711000C7548A67F4EB17FA736AFDBB72AE045F5B +:10712000EA65F0154FF8BADC3C83FD19E32FFDFB4F +:1071300093B57DC126E33A224786F3A4CE27807F0C +:107140005388FE2CD6F4A99E07D1BD6B24E54F06CB +:10715000C7E5E73181BEBFC4DF5DF2813E453D96A4 +:1071600027B96FC5F679ED712ADAEFC06FF51ABF4E +:1071700049C86F3A9D5BE3AAF369BEEB04B24BFAD0 +:10718000D941DA3A9AD724D0EF990D9EE715E787CF +:10719000C0A7EB7BE8BF55EB7F3CE7E767FBF8F95F +:1071A0003E941FCD9F67AE0EBA5F3D1CFE852873CF +:1071B0000921EBD5AB368AEBEB78BB5AFED7ED85D0 +:1071C000F201D725077D37F868C0E184768B511E20 +:1071D000505FB57C42F764B6B6890C7FB200E78D8C +:1071E0007A234FD793BE95870A24B25B827AD94916 +:1071F000F68BAE3703566BB0FDB9B52B0BEB51AF29 +:107200006AF7ECC78BA0C5C706E1487370BB7792DD +:107210009745FCDDB81CBB5DD723348F8D2B0AE866 +:107220005E852A6D3D9DD4E1A3785334E27142100E +:107230001FFA7A7DA7A5E315EDBC97811FF53AD813 +:107240002595A6AC60FFF87E6608DFE739381F8415 +:10725000D3E7BBEA27C0830FF1F0430DEF0950C716 +:107260007B2D9804EB17E6FDCC505C6B3242E05668 +:10727000B83E4E104D5C8F5D462EE20731EDF7585B +:10728000EC24CF417C70BBE5018716E7D5EE293FA2 +:10729000680239A17D363ECFEE5DC9D4EF6CADDD1D +:1072A000DF4B2F6FD6F296747BB1E2B5D4CD46F8A2 +:1072B000797FBB1C1C2F7947DD63D08E19EE515CA2 +:1072C000E81FE4B5CFDC8FF924D97BF00704827C7A +:1072D0009EDDC2E514B84BC3CB9BDB43FBAD74D83A +:1072E0007539FBBBCC23FB28E757A4CB7D21725A11 +:1072F000E35038BE607E16C4A764D4A37AF9F7833E +:10730000C3B31FCF2595033E506DEB786B6D99BFCE +:10731000D286727C94B9508EBB5BE69B46215D3170 +:1073200011CC19A21FD6F379E87628F0650BF2E5A7 +:107330003AC7101A6FF85177740EBC1F8E7613C6B9 +:107340007D5BEC7EF423FC0EEF2E07E27356EF1408 +:10735000DC4FAD8CAEAEB5853CEF6BDF06ED898FB3 +:10736000BD22EE1F953FC0F8BDF1DA7CA0A9CF0287 +:10737000E355C820A759540F20DE5A65DEBEF73EFC +:10738000FAA5115629F27BF960FDBE95F8F36D530D +:107390001CD217FD24B493CB454F1AEE7BB2C11615 +:1073A00017AE03E07710BF1FB431C906FDFF1E4AB8 +:1073B000D4D3D3C4A5748E6B5A9640FB44BA7F8F46 +:1073C0007A0BFDA43BBF174DFCC82E3C380CE3D311 +:1073D00009D19C4ED08F55EBC76A1D1B94BFFF4847 +:1073E0001F49FE8EBEBE1D1404EAE7E04DD735D717 +:1073F00085F841D81FEAFF83C28CB4A5C8FF9A1F45 +:1074000047F6617C70DD457B65AC21CEE6D3E0EBD1 +:1074100048473E0AB547D13EEDB3677DF357DF0CD1 +:107420007A76E2F496005E715FCB8A6EFE17E86FA3 +:107430001AD8B336C0C33E8D2F0E66F844DC4F3DDC +:10744000385CA0FBDC0F457973AA95E038895A5C5B +:107450002051CB334F8CE2E50F62B81EFC3C86AF67 +:10746000D737A8BC9EE8881C4798ADBDFFA989EB1B +:10747000F735F991F3D14F68FAF5AAEDDE1C21FC3E +:10748000BEEE138E09DA7DDD946FC7E3FD0B34FE8B +:10749000063B87E814B4ABF87E9D6E879E6D9F4DCA +:1074A000F51382F7BD7B042C3D4F909FF4AE48F15D +:1074B000A1E2586F22E6A55544458ECB0CD2F0F4DC +:1074C000590DA338EF29DCCFCBE6BFB785F5251BD7 +:1074D0009EA47B1D4A999FE2BD451B1A68BFAEC89A +:1074E0002F30A780FE9987C781353A946E110D71B0 +:1074F000E7C552B51C9B13E45BFC1DAED0F7259B82 +:10750000C619EA576F971618F23B827AA790ECBF1C +:10751000F07E753E0FB74F8FD7380DF1EE051B8605 +:1075200017F2CD78DE7E2173D17C17366619EF1104 +:107530006E4CB8B27B82C11EF545845326FDA83F30 +:107540003F0EF8F785C4F7177C3A8CE0F88BC37BC5 +:107550005D8C018E68E633C4CF26F3DF29B4F1F8E1 +:1075600023F08FEF5276407ECC77F507AE1DC01F1B +:10757000C8FD87FA037993B9FE654D02E5E04C9C9E +:107580006AB4CF66C7F0756E764CB4C13E2B9A676D +:107590006C37576B37576B77B9384AA85D2664A1AB +:1075A0003EE3FDE9BF1F9571FA6DCAFFDC10C3ED24 +:1075B000D79FAA6E6F0CF4BB563B77D06FDEDAEF25 +:1075C0004AAD35F7E585525EE0E66F1EACC3DF09D4 +:1075D000E9DD01F63FE8C1FC67DFA07BBAF4EF6E9E +:1075E0005FD132B408F054A9C973B98BCFAFDC15A1 +:1075F0009087413F29E51CAEB4967D8214F25D5A16 +:10760000096FB722C66CF02F7FA2D5FF35C649653A +:107610005A49401806ED52366D1124EC0F7F570B76 +:10762000E049A966FED0DF934A19CFED9ADBC76F18 +:107630001616E604F1D0689A91A3625C3531DA85BA +:10764000EBCC47AAB70EF150FE5180CE494CFCA8B6 +:107650005D42BBBD5B75D7237FEB78708A6A0AAE4B +:10766000A3D11F71389BFAFC62BEBE30F6A86647F4 +:1076700037EB76E961C6ED425AA712578E30FC3ED1 +:1076800061629CB64E2432EF4E85DA3732A227A3D0 +:10769000F924AECC6EE6762CA7F7B42CCF167C3E40 +:1076A0006DF0C8B178DF47D6DA8084BF3BFEDA26BA +:1076B00053C4FB519A35FCC33C9EC5F9E9F3B89C11 +:1076C0005ED0DB9907884FE8F2103D3DB2DFC1D8AC +:1076D000E3F43EFFD9F87BE9FECA7A997E4F4EC7A4 +:1076E0007FB7EA6941BCA6B46C160837DA787ADC51 +:1076F0000E9FA35C1E978DE73A0794FB153B8716F8 +:1077000085CA7DBD4CF4D91C96E7AFDBF77F88E1D5 +:10771000EBEA9058CF3EC44B65DB3A8AEF2CD9C2D6 +:107720007FF76740FC5C21FE8412EE0794CFE1FBFB +:107730005EF9CF4A44FFB27AFEFBACE5DB77F0B8E6 +:10774000CE8F990BF54379CB0EA128077F0773875E +:10775000B028049FA9E57ECA83BFC6AECB1FD75B06 +:10776000E1FC8E7162B4530ED9B87EE8CC577CB878 +:107770001FDC69F69663BBCEE46817E677E9F8FF8D +:10778000FD8E9BE9DCB57DA7258065A3A939C98A53 +:10779000FB0ED7CA2EE4AB6ED57B12E91327795ABC +:1077A000F1FBD878BBAB16BE755AD85855B9723CA8 +:1077B0004C0CE38F893FE67293A43AF4BC86B12463 +:1077C00037AA9DEB2D13D76787CC7C1E3B1987F713 +:1077D0000731EEB3248787E368DC94F2009D1FCA6B +:1077E00038BDD370CE30C85FEEBF7D1B7EFF3F2C0F +:1077F000A14B2800800000001F8B08000000000043 +:1078000000FFD57D7B7C54C5F5F8DCBDFB0AD90DA6 +:107810009BF73BDC100C28246C9E0401D924848740 +:10782000206E0228C86B7947926C02D2FED0FA6DA6 +:10783000168331E56B6BD41645A92E8896B65A830C +:10784000A2060DB82822D64723A58A2DDAA5202224 +:1078500084641BFBC056CB6FCE9999ECDE9B0D0F59 +:107860006BFBF97CE18FC9DC799F73E69C33E79C65 +:10787000991D33B5CDA88C22A4A69A38BC342DFD11 +:10788000E90EE98485900BF06F2221836C3221F19F +:1078900084A43CBD4D522C58BE7F5A1CD6272605C9 +:1078A000BE4BD8AE8696AFA0A95B22848C25E4A0FF +:1078B0008178CC3184B4E82A47D968FD9684487B26 +:1078C000132D3B667345DB687F96639D07ACB4EA76 +:1078D00098633EA38BF64BDAE9C76442DE3012129E +:1078E00041DB1D8C60EDD36D74902242261B89070D +:1078F000BF1B3D2314DADFC1A183B0BF97B7EAA64F +:107900007A697BC320B2D81932EF749B0EDBA56C69 +:10791000DD21E9E8F7B8485A1E323F51EF015B59C3 +:1079200026CC67CCD44E8443DD563DAEA7C2E81CBE +:10793000B66654B0DE68E88FD67BEDE64F8C7EFAF3 +:10794000FDC72FBD6F2450BF5572B4C1FC5BDF373C +:10795000CEC9A1A9E7E7324920643A61FF36BFF0FA +:10796000BE51A1DFA7EFA670A2F5EA76EFD22FA352 +:107970006957A9C5238D2624F3CC6B8B4821FDDEE6 +:10798000662211746EDD3657918DCEFBCD5D530EA0 +:10799000495184589F33F92015F021C49FE1B40662 +:1079A000E725523A30CE2F722AFDB310B246EF557A +:1079B00099F0DD955945EBB7C630F8CC1FCCE042C5 +:1079C0002CEC7B155F97800B1D7F0A8C5F91E5DCAB +:1079D00001FD542446D89B32619EF9AF9929DCEB16 +:1079E000EC923D82568D2B67F00C9D57654EB87911 +:1079F0006DC0F1E263D9F844EFCF807109F1B2EFC5 +:107A0000326921F9C1F67338BEE9771FFB4E863A19 +:107A10007382F3D7E26F834DC2FA61E86C11ACA3B5 +:107A2000F698CFC7E8AC530F749679E630E243D0AE +:107A3000CDCFB6EA3115FDD5D98CD85F9D4D8F706D +:107A4000D90C781A4C53032C9AA61BCC5E0F85C711 +:107A50009BF3261F9272297E6E31FA207D43B7B4C4 +:107A600016CADF4861E3B7E8746B21DF729785348B +:107A7000215E1D6E98CF6B3747217E6AE71ABD26BF +:107A8000DACF8F9F9758DE63F112FA67AD6BF6720B +:107A90006847E222EC4F02FE5C078C73ACFDE94ABA +:107AA000796EBF51A1DFA7B7B1FD27F050DBC6E863 +:107AB0004BEC0701D7203CBDAAFD24F0317FB08DEF +:107AC000D105A5178077CDCE08DB49331BEB02012A +:107AD000FA8C56E5EBDB936D274704F335F007D0BE +:107AE000C10E628179D6F279CED3B9EE83FD5567A6 +:107AF000F61F3450D4161F0DE07E1F887E6BD6FF14 +:107B00003AFB640121AB930E612AF6AD61A87A7F3E +:107B10006FE5786F8294B67B82D34D4D611BEECBBF +:107B20009A930DB89F2D53195FB31C238E503C13AD +:107B3000F243BEDE7BB17D4564DB6499C2BDE27178 +:107B4000C9D644FACF4FA4AB24E26CA3FD7DB6F5B1 +:107B5000F5A82500DFAF2EC8A498AE3782AD7737E1 +:107B6000E73B5D3B29C091DE1B8C24CC7A2FB73FCD +:107B7000E23B22013C6B38ECBB9E2E1FFB29A51774 +:107B8000CFCEC1F6ABE892CF3E3DEBF64FE9BCBBA2 +:107B9000764CB4CB40364D4EA49F407C847D3BA5B3 +:107BA0009F38994C9528DE37B4BD1E358EB6FBFC48 +:107BB00097A3F3816FBFCDF7FD99E7E5F50097BB7C +:107BC0007EF6EC75505EE395624D30CECEC7FF95E4 +:107BD00042FBA9DE510F10264DBF7CD5E8A7F574F6 +:107BE000DE6DECFBCEC136A8F7F913F75F07F06E38 +:107BF0006A6BC2F2334F6CC3FC6B3F7B76DF3F682E +:107C0000BD5A67941DEA9D797E3FE2A5D6A577C04F +:107C10007A07A2EBCDBBF6337ED926E17E2373191A +:107C20001F13742DE8F7F39F2D1E1B2A37C4F71678 +:107C300023973B83981C39CBF76F4D99A505D2B399 +:107C4000CF44CC85F5BA8DFEEC6898CF2846171F37 +:107C50007178D4B6AD31B82DD81EFBF980EE7B48D3 +:107C600073287D9EA2F44E6BEDB85000E3FD0AEB45 +:107C7000D37A251114BE372F382EC17C22473518F0 +:107C80006A709EBF64E574D5A1E5C5EB183D6AE94D +:107C9000E00B9B05EB8B7D90B2BB324D413E60B259 +:107CA000333ECED69752ED6AB2D2EFD7AF73D965D5 +:107CB0008AC7974F1F9E9C4AF33F1B211520FE65E4 +:107CC00089C9398F05C7A95B5F464ED0F9EAA2D9A9 +:107CD0007E49B011FDB5C807B631BAD713BD05F25C +:107CE000FA00F289BA162E0777B0791273206396DC +:107CF00015DB59AE8D09CE83B6B358301FC8B829ED +:107D000007E48E672ECA1DC588F33D23F801F1E410 +:107D10002ECC09EEB7041D7101FE138C34B5307EF4 +:107D20005349FB4F8F2E4D8A2E0AA6098358B91648 +:107D30004EB7F0F21F453B92A2015E3B6355F260E5 +:107D400020BEF2DACDDD4C6EBF721CE9D00D740896 +:107D5000E3BB4EAAE4F67264AE940EF71C473A5C9D +:107D6000DECEF8ABBBBDD4B88CA69B253217E6EFB0 +:107D7000E6F4047464A7F99BA2A3717DEEEBFCD931 +:107D8000C0A7BA39DD75EF61F4F6864EE701F8BC9D +:107D9000B17DE43690075AF928553B11DF6E8A6FA2 +:107DA00093047AD6BAC3A067D555133BEC57F76E48 +:107DB000BE1F1A08EE07777BE572E82F356E9A5DD5 +:107DC00096502F999C4AF3EE5A5204FB2D656BD9BD +:107DD0001EA00BD22E91AB205FEDDC0DEDAF8FAB73 +:107DE000B3CB9920F7B6279969FDEB471463FBCD18 +:107DF000E94A29F4E7A920B627216F70A13CDB9C52 +:107E00003CD20EF2CEEDDA887A175106D9A19CB891 +:107E1000F46BA1BEDBB3806C92C2ECE33D9203CB6A +:107E2000BD91DE08DA7E7A3BD37FDCED6C1F9F13B9 +:107E3000F011A9A173118CD7FD828978A4209DBD72 +:107E4000B9670A93B32F9A50CE9E6D749013543431 +:107E50008F8C5610AF028E35AD993AA05B42669971 +:107E6000601ECBF83C5A0D4C6E44733990752F9BB5 +:107E7000C772BE1F9647EB786AE4FBAF95C9059BB6 +:107E80002717E4E0393E1E924502977374E8BAE57D +:107E90003EDC27B54FB3FEE24C8EBCDB42E855E832 +:107EA000475A7A6CE2E3A66C3D20013349D95AA5C2 +:107EB000DAE7D757135F3D5DE7F55B75BE89B9A873 +:107EC00037DD82FC7C83916C97FAF7774F34E35B64 +:107ED00015B1CE3C09E4D7CD16D43FFAF6E9208798 +:107EE0002E02F4B87CC9DE84AB7016EA68BDD309F3 +:107EF000563BE0ED471C8E5A7DABAFBD460F9CD183 +:107F0000EAC9254369E9864173019E545FB798A188 +:107F10009D8DB6A7F512B68F7B6213F2AB26ECF7F8 +:107F2000F6681BEB27D659D8002C2ECBB98EC92763 +:107F3000AB3DDC7AD2A3859EBD284F07F433DB82AC +:107F4000FBE1C7AF484B19BD514128013DB2FD418E +:107F5000E8FE7852417A443DCADDE0F486A747B690 +:107F60005FDC54AF023D9BD2E35AA6275B08DB4F90 +:107F70008C2E23A73279007C2B549F15FB54BBEF2A +:107F800005FDF6EDFBCBDCEFDD06B61FBB291C8043 +:107F9000DEFBE8FC6546E79B36D0FD48CB37D1FDDC +:107FA000D814C2FFB5E71F98279C0704BF3D66732E +:107FB00076005F746F7FAB19C996F347F7CB3FC864 +:107FC000BE98DE6586CAB45F33DDAFA1F463A6E078 +:107FD000B6E663EA013911B95EAD4789F4836826D4 +:107FE000BFBEB1DE3842D2A3DEC3F155AB737D0014 +:107FF0007C1EF4464A1124633DD31B1340E600DE89 +:10800000B6477A413F4E4820AEE7C2CC673FDF67B4 +:10801000029FE2FC9010C5EAF7F27DFF29AFF74F0F +:108020009E869C4B703F283AD771220F2C8F443B81 +:108030003A2F2C17F3E93BD798D97C13EECADEBE52 +:1080400029048FC17D75753EE037EB5E9F7EA925C3 +:10805000388E908B5ABA81F983FC81F5548E1AB808 +:108060005EEB7E7E3ED3D07104DF5F7BA8B882B426 +:10807000D5E0FB2BEEC7355602FA222507472C9D8B +:1080800057FDBEE16C1F8D086443FBEA58D74D31A4 +:10809000B4DF3193F8FEA0DFABE09CA0271E530CA9 +:1080A000E0DDE0F587E0F9D318D67F8FD5EC91E9D4 +:1080B000FEB823D6150DED3D65C4EE03397307E513 +:1080C00027B06F89AF08F84D3DF147019CC7585D57 +:1080D000F13140BF726736C9A2FC57F2E7C2F763BD +:1080E0001151B984F6F371FB6F9F7985B65AF8CABE +:1080F000B985DF03FA7A312203E8E218D5973B51BC +:10810000DF560683BEDD4B94C1B630FC57A40BCCC2 +:108110003AB3BE20983F66559F2F447A4D0CC36FEB +:10812000FDF914E28985FE099EBF7B6214F65D1F8E +:108130003082EA567F3E8378687F1FEB48755B98F4 +:108140007137C5307ADB4DC8D470E5F7F171760F21 +:1081500065FB30B04DF2027FAC5EBFE1CF32E50788 +:10816000D5EBAC3E4C6931E86FD5368F4F47F3C73E +:108170000C8C1FD17FB3CDC541B947EBE9C7030EC6 +:108180003CF4204BF9E0522EB79635BCF925D813B4 +:10819000AAF5C43C9EF6B3DCEC3C984A8B3EB32C6B +:1081A0008F02B6BFF23BB725805C4A5CD0CAEC3286 +:1081B00064920DF45EC93143BE1079313D4B8FFAA4 +:1081C00031E29FE2EB8B18E74CC0F782C104F580E7 +:1081D00005B7457A3D217CD0CCE1A1A59B4FB87E67 +:1081E000A5ED7F766C1981FE3AA29C73813E16DC68 +:1081F000764EC5CFBA25FF538F025DADB1DA9F64CD +:10820000DD653843E8FE3B62BCF33AC4534F5E671A +:10821000F6FA4CA0DF40C68760CFEA30D93C0A941A +:108220001B11CFA2DD9F1A29E3CB0EE6979E1E36C7 +:1082300019E86B19B13703DE97B544124F083F03B5 +:108240000518E8C37D9E603F4B3BDE3C0AFCDCAD7D +:10825000F7239D2C355B108FEEF37A9C0769317400 +:10826000F9457B8AFB23518EDB607D9E7BC6479F51 +:108270001A493F26D2EFB87ED7EDF0FDA1C828E21B +:1082800000FA784BF60EA7F3EF352B836328BCEA90 +:108290008D940E4663374E7388FE43D2AC6AFC77EA +:1082A000BCF525CC67B9D9650439BEC241CFA73228 +:1082B000E0C957641B158AEFF1F28591978FEF455E +:1082C0007CBF7F6CA4F41F661FDDC7E1DF23EAA536 +:1082D000B07DF27106A97E0ED26B684ADB7D3C94BC +:1082E000E7F3793E9BD74B60F91D7C9F7C9CCBEAE2 +:1082F00069C7F1C530FE363BD6B115E045DBF98CD8 +:108300004017FB22BCA8B716527E07FC6D6D3AEAF7 +:10831000AD94AFEDC07AD9C4178DF54C28574803FA +:10832000E57BB0CF8B1484CFA6524A27B43CB0D79C +:1083300064DBAE04F12AF0A9C5637B8CF4EFC9C3FA +:1083400051923ED48E42E5617B0CB3A318617FD27B +:108350009918999E360CF18574225F3EBE6E8C6032 +:1083600078A0FBF4B518D47B7D39A1FBE504C79751 +:10837000E0671F0F52E3B58AE3E16D5E6F518C8DAC +:10838000C94F7B00F7DDC731AC7E5C169343420FCB +:10839000FF0387CB4D9A54C8953153D5FAC54D1C70 +:1083A0009F37C54409BC7E08F315F288F2175F3485 +:1083B000DD0F0B5E35217F211B03D9B0FF68BD6344 +:1083C000586E0A2C8AA572E426AADF18F3B1DD22C2 +:1083D00068DFEF3C3F4AD08595809C3E25D65318F8 +:1083E000407E4FE51DAE6B29A17C43BA34FE37D0E9 +:1083F0003AC994D6870C56D8F94EA60302ED8F20C1 +:108400000AF447E1FEE750B86BC73BC6E9E09F318D +:10841000921EF19647F2709FBDFF857521EDF29C8B +:10842000CDECD151BEFFB8CE7501FAE9BAFD2DD41D +:10843000CB8F197DD9AD9630E546DF630F49C1F288 +:10844000C53F973D46CA2F767776FDE466BAEEA51E +:108450009DB21D865C7AE75FDF1D037A75A7C10EAA +:10846000E7462ADFEFD5C3BC1B981E794CA7A6832D +:10847000B3DF559F73D26219BEA8DE83FA9CE03B3E +:10848000427EDF4A7C57815C5F461C4648FFB466EB +:10849000D50C42E1B7C2B20EF9D1E76BA7A11EBC61 +:1084A0009278B07C598BE14FA1F26145AB3ABFEABB +:1084B0006175FE56AF3ADF677F2E0F2FDFA7C732F9 +:1084C0003A3E4BD93EE03FB0C1E4053D485BAF9832 +:1084D000D7CBA43CB113F82495FB60475817E1486B +:1084E00004BEBE6E6F69E2C5EC7CF5E7AF21DE101D +:1084F0007D23A837E4126F6CFF7ECB63158423F4D1 +:10850000ABF071E0BC71B62CFC3A26C60A3D651092 +:10851000F627BE8B7E82E345E13CEACF9B07988F2E +:1085200005DB9F5D197E9C1BFAC6B1A9E464B07D92 +:108530001C936BFC1C2DE8A3FE7C127E1779A1070F +:1085400007DBA531FD8AA4D94E4506F994B0638BAB +:10855000FD704222E664B43BDDCFCFEBF65CB05F4A +:108560009F003D08F6E314659F9F4E71D9F7C666DC +:10857000EB8706F78B761D94AECEF843F8EEB25833 +:108580006B1C8E6B27761857D0FBA2DB2B06BBE843 +:108590007CFF786779A26B54283FF530BF8951E89A +:1085A0005F16959C251A39BCACFD2DD4BBA8BE9591 +:1085B0000D4CE7D3BDB723BDAF24CE04A0F39EBDC1 +:1085C000C3335CFF86FC15F399E559622098A79B9D +:1085D00098EEBF2A3E9F591D4CEFD3991D061CC72C +:1085E00041145B021EA5D97C29F3D4D3FC84BEF9C7 +:1085F00083918E90F17CFE12B4A7F09DC053B2D44B +:108600009504F336C1B874BC08E24D82B469AC5D20 +:108610008174A2E4D4B379303C4F260D69505F6772 +:10862000F6CB6C9D740609D0BE0F5E98B7F2FCC6FF +:10863000D9BD8B56C0778B15F98891CF63472CE550 +:108640008766E42F6658B7C9E2FB1CFD643CF594CD +:1086500029B88F3D4309DA3B06913602E35A2CE7ED +:108660003CB0581BB149908FB0F5FAE0FC70CE6673 +:10867000F1E846239FDC190B7C527A6725E085F2EE +:108680006566FF19A85CEFC373B7E073317C7E4D5C +:108690009CCF2513068758E2C0F11EB0AE9C414026 +:1086A0008459D649D07E4BD454F4EF2500E0697943 +:1086B000EC54BD8A6FC53BD5F9C4B9EA7CB24B9D79 +:1086C00037D3933FE88B92CF99742116CF5923C0AB +:1086D000DE62E0FCA299CFEB08A4743DEF713EFD91 +:1086E0008DF513BBFABCEE8E3112B4E32598CDD0D4 +:1086F0003FD557DE8B65FACA271E289703C8CFF3EC +:1087000026B6F9C0AED37C8364BF8B7E6FB62A1BBE +:10871000F494543DD32466C7D1DB4AF5B47C5B8620 +:10872000CDBE89E6EBC17E1D0BF3B7D53C8DF64976 +:1087300013AB4702CDE08FDCB6C966837A71E58161 +:10874000C946D08B5710DB761286BEBFA2FB86CE01 +:10875000F709C853BC489C5E220F29F3710DBC7CFD +:1087600007FC9DC5F2138BE15CCAFE6575E4753AA2 +:10877000C0EEE090512ED677E4BD6EA1E365CDCE7C +:10878000433BBCB39CF97309DFF76334FB6A5C902D +:10879000CEB13C8FE7877570BB6E9C89F96B6D74A9 +:1087A00088626636C0FA718CFEED44FC63FBF25AB7 +:1087B00012FC07FD9507FB473E3429581CDC677403 +:1087C000A87CB3BDA996D61BA3F7ED877D3C8EA7E9 +:1087D000793C7DA3F40694BF9D3A8B62D4B17D6D44 +:1087E000CE0213865306B814DB7ED004FD4C907C79 +:1087F00098664CBDBF09A65FC5ED47D14946EF0657 +:10880000BA8EA6128A67B477FCF920D8A5E5074985 +:1088100001E0E98841C839079ED3157A1CFB1A3A52 +:10882000986C40FDFC2F932AF03B01D58CCEBBD237 +:10883000C61621BE0F2C5F75283F6AE364E437B388 +:10884000A632BF6AFD5CB3579240CE10E677D2BB2A +:10885000326F0AB197083FC4FB0632775798F3444A +:108860006D1CD34FAB66303B6FFD46A3CA7F531DD3 +:10887000C7EC5E33E3268F8C4379C4FCA779715C27 +:108880006F1B4146009F0AE1234550AFABF4ED81D9 +:10889000F88CBA9CF399398E0203EAFD9CDF08BE7E +:1088A000EE1CC4F6F33C42D281AE679306E4FF8728 +:1088B0004B6F457E7313F118006F1F95B17802312D +:1088C000EF5953D57AD21CA73A7FF35CAD1EC5F0A1 +:1088D00021C69DE7529757093D78AA5A0F5EF0FFCF +:1088E000BE8A46B99AF854DD8521E0E760F600C0FB +:1088F0000BF373E8916EDC1B993FBCBE3DEF8D38E6 +:10890000D8677712BECF7649CBD1FFB24B5A1182CE +:10891000FFD45AAF047264B855D87D98DEE4347938 +:10892000F783DFC359831291BCCEE3490E403C4923 +:108930007E90BEAD65561657411CB5309F345BA482 +:108940001DF4FE165D3EDA655BA2AC2A3BFAA60D6D +:108950004A05D413F658C544F26D9C6EC29D77D774 +:10896000C531FEBA59627671CF3C339E2BE3B39C7E +:108970002A3F41BC4C8E829D70649C22EAA3FD6319 +:10898000B3C1955C4053AF44971117D25E261BD1FB +:10899000AEA8E14FF1B176B4EBC70FCE413BFD9CE1 +:1089A0008E3CB42F124B84FD2A29D8FF9CD9DBF4CE +:1089B00010A753DFB14DBFDC12A4BB7BE2B85C8DC6 +:1089C000249140AF7D76BAE74C68A77B5CE7FC5FFB +:1089D000A0CB5AA30FED7121F48ADF07928BAB383D +:1089E000BD18CA9CF356D0F9F5BC6BB4C3F9191D78 +:1089F0006DB4FFE7F744A39D515F45503E6D2C6574 +:108A00007CA407EC5F741D9F4557E3F960A3D48AEB +:108A1000F2A33B6632D2F16ACB013C07576FA574D3 +:108A200018229F56EF50E76B48279EDF6B9FEE475B +:108A3000CFC817051F76EF56B723C3D47C378FCB2B +:108A40008B7CA77D56054C7DAE3D8B9DC3E9418651 +:108A5000AEA3E81D23B7EF2EB09D8A0056FB947499 +:108A600031FDADC77A5A66FB9FC983223E8E566E92 +:108A70001571BDED3ACABFE0FC2AF4B022C2F2077C +:108A8000741D72922E38DF42DE4EE87F424E087C23 +:108A90009596105242F743A7E04F43C950C037EDB7 +:108AA0001FF78904914331D8BF07CE7DE3F878944E +:108AB0001E3C20B73D3AB317E8AB596A4039690606 +:108AC0003D9FA69B2417CA8397AA3D32C07B2C6981 +:108AD000983583D61B6FEE8C0438513A39124A3FD1 +:108AE0004DC497B14B52D111967745BF1D968E84D8 +:108AF0003CF37DC4F498E974C5D04F05387E687A9C +:108B00004062E7C829961FEBA1FDDBBA69482753ED +:108B100089570FF3ABB0A9F13F25499D9FA6F4A358 +:108B20000F8CC37070784E1FA12E77087E47D4FC3F +:108B30002E937C857A18F9C1C1EF805D21723D19B1 +:108B400001FA0DD544711F6AE9E0EBB86FDD6FF2F1 +:108B5000755C18BF490FB7135F4BFC2B9F96FAD378 +:108B600059F71BEBE5A4107A14FBE265038B7F90A9 +:108B70005E65FEA9123319E503FA2A647645B13F12 +:108B8000AE05FA8C09D25D31FF9E11CFE96C081950 +:108B9000027436A13DC22753BCE4F1FEAE05BACB48 +:108BA0000FEA23E25CD154D28FBE32A52CD45F7081 +:108BB000DF097DA4406A6BD267021FB9A709E61BD3 +:108BC000424F43E38B802F517AC27DDA4FCEAACB3E +:108BD00035F426F02EF4E552D28074365BA760EAB5 +:108BE000AB5C85F2B5DC325B0FEDDFAC62F43609CD +:108BF000E8310BEAABE9A5DCACCE6BE9918EA80BB2 +:108C00001D574B9F03D1DB10A037215F632F4D6FA2 +:108C1000D3E3BF757A9B1E7F117AD3D299E05FBBF5 +:108C2000226CE5A03FD7574B280F0ADE1DD604F96A +:108C3000E17599A84FEF8AB6A37E5DDFC0CA0B3BF2 +:108C40001D32C4BD64ADE3E599CE72C8D7AFA7E5C8 +:108C5000B4EBA2232C2E66D89DAC3CEFAE86D7ADEC +:108C6000A0677858FB973F6F96A368B9B799B72F5D +:108C70006D2D877C7D0B6BFF19F8A946437C9AB755 +:108C800009BE5F7D6FA69D1DAB99FE3E91AF7797A4 +:108C9000F4DCEBD8AE95B55B75D03C88E0F99FE984 +:108CA000E5D7F1754EDCCAD61977E2FAA90AA58B89 +:108CB00015010FEA6FA774B5C5C8DF06383F974A9C +:108CC000AD69904EA1EC175287D9DE220F657ECC9C +:108CD000ED74887BE299FD45F8FF20CEA032449FD9 +:108CE000B8279ED96345BD84188A01A08747ACA8E0 +:108CF0005F0BFFA4EF212281BC8735723D24ACBFFE +:108D0000724A5603EA115386083FA55FBF948E9BB3 +:108D100077E18BC9E1EC433FE2E39EE671137D7A94 +:108D2000B237530774B10B88240580F4DEAF417F5E +:108D3000DB057E4826A43CA404F0CAF25BE37FBDB9 +:108D4000A9653C85AFAE41EF01A1962161DCC9CC9C +:108D50004EE21B1CD57FFE53F4C467C4382636FF91 +:108D6000954D541E23D1317E3687E38F8CBF0AE99F +:108D70007736C7D3CF057F2A2005C09FE670BCDDBC +:108D800064A67A34F2C35683866F3C130F726ACBA3 +:108D900080FABBBA5CC357AAF9B82BB9DE7E2B099F +:108DA000A07E724AF2627A7A0BD3DB6B2C4750BFFB +:108DB000E97984E9EDB5C48FFA8FD6BE59B3539DD6 +:108DC000AF6B53E7EBDBD5F99E1C0F8ED3B3A5AE8B +:108DD00018EC8AD50FBF8B76EC6AC15FBC6AFE4285 +:108DE0001571C65F1EBA06ED51DF986F3C4D4F6F8F +:108DF000C5AAB8D0DF029CFAEC352FB2F81437615F +:108E000076821EEB88F9704E251A79A4E527799CA5 +:108E10009F08FB86E02F7984C9237A8E7DD7418213 +:108E20007C5CABD7F5C473BD979FD384FE9307FAE0 +:108E30000FD0D3350D48644139647FDB2487C89F48 +:108E4000798566C073BE99EE6780976CC971595475 +:108E5000F4F005CA9981CF7BEA720DBD88F3D62D57 +:108E60009C5E668127858EFF7BC981E7BAC3B732D6 +:108E70007A99635987F4FAD16A462FE2DC77E5E7FD +:108E80003C87FC4DCE797D741241F55E9A1E4917E0 +:108E9000E77CE68FAF97181DD4557DF818E8CF8290 +:108EA0002F1C6E24F1FA103ED134CD64063B4A9358 +:108EB000819D83AAA67F5CBC3484CF38224A1313D9 +:108EC0004059EE8847FB6C5DA47A9C66A9F3BB7F92 +:108ED00080F3D24F23D14ED4FB304195A477EB7071 +:108EE0008CDB3E6B607E52319F550777EEF3C37E7D +:108EF0005CFFEB083D959F3592F7C55A5AB6C4E41E +:108F0000CA86716A743E23B36376A25F578C3BB006 +:108F10005DD683F2D5F81A93C3016910C6E1D2EF8A +:108F2000D9A1FEB5D1898C4FDF11EB2A48880FCA31 +:108F30004B613FA45296A4C604FD26C1F8066637CD +:108F4000F90B715C32BE6163887D9EB60F1B8F5634 +:108F500096C0F8F5F729CE61DE07A31DE5309FD353 +:108F6000DC8F7B9AFBFD4E47313FE0CCBEFA2C757F +:108F7000F1F434F7139E8E51FB8744BDA509CC8EC6 +:108F800072B2D16CDEA807BF3A316F1C4649EC21A2 +:108F90005303C6932C6078EAD913BD6D5388FFA59F +:108FA0002EA1F4FB309F7FD89C3743BABCF5B83173 +:108FB000D40EDF23B1F3770FA7979E08968A71EB43 +:108FC000122ABF0F78EC99E7473CF6E5C78ABC1335 +:108FD000FBEF99C0F86B5FFE3B2C4FB8DD43D8F533 +:108FE00007F2F769FD7B54D0B0734004B3CF6BFD3B +:108FF000F30B053FE3FEF9059C1F2DEC607E8245D7 +:1090000066D29C4ACB177724B2736E94275BE59F98 +:10901000F7445E513C86A0CB9EF4CE3E7FF62321E2 +:10902000FEEC3AEECFAC13EBDBAD5EDF0309DFBA4B +:109030003FFB818430FE6C6DDCC38BA0470C0BE2E0 +:1090400061AD8DC1AD42AE2D077B6FEF728271E8CD +:109050006BDF5AD604F6E0B53F000B2AF231D4A7F5 +:10906000EB389C075A57BC534714959D7D105142CD +:10907000E69FEC8A51E551430F89034DAD4E51B542 +:109080004F6F18AAAA3F64FD35AAF24C4FBE2A9F23 +:10909000D572ADAAFE55AD65AAFCF087AF57D5CF06 +:1090A000234307A3FDEC900CB62172B5B74A553E99 +:1090B00072E72DAAF69F9186CDE369BDDD42FE7968 +:1090C0001C9DA38A8371CE396D4B55ED9BA4B6626E +:1090D0001FF0469FE49368BD151C5FCB3B99FF6270 +:1090E00074FB6A55FF67A3D83D18AD5F96762EA333 +:1090F0001ED62E9147A4FE7EDAEA8EFB9B21EEA8B7 +:10910000BFBF96F24DDA6E353DBF80FEA6D56F8E9D +:1091100026703F5D0A496174ADA50B0BEA7FBD5B0C +:1091200065B427E691EC87C623BC0CC4ABF4C75FDB +:109130002F6176AEDEA7AD7688FF59F5D632A4470B +:1091400053929A2E2214355D448E50D385D5AEA607 +:1091500083C1256A3AD0C23DDAA1A60BE2A7FF433C +:10916000E02DE02AE01E3B554D375A78E79300DAB0 +:10917000D9DD5EC9EE2361FCE2EDDB705D97D21FA5 +:10918000F5896AF8161C703459106E2CBE4CE861D3 +:1091900026AEFF68FD1342AF894BE47A15EF47F81E +:1091A000179A250FEA517DFEC2125F862F13F4A78E +:1091B00006C2EC44CEA4C4F07646FC3E909D51C05D +:1091C00075F620262F6B8803EDE12B880BF9DDC99E +:1091D000CA5BD13EB4CAF263F4BB9EAD627A52352B +:1091E000F1229FBFE2B802AA879210FBAB168E5203 +:1091F00087E4B302BFE1F22085740879E0C27813F6 +:109200004A86E662951F47ADE782DF30847F09BD5D +:10921000578C27E029F89A18CF441AE424D8171A53 +:109220003E474668FD486A3B8DB0F3E06021FE2270 +:10923000AD5D26440F6E91E938F290CC2642F1578D +:109240006073A0DDAF8874CE87EF25E6B626BDC279 +:10925000ED1357933EFBC480F2EA12FEE8591EC993 +:10926000FF68667F3FB4F06BD3E59FF8036D3C5E0B +:109270005210EF552F0F8F077AEA6FA7B41F7D8525 +:10928000F623EB02B1A1F6C3BEFB06921FD7731300 +:1092900071DC4D42F41037699B3C3F13ECC4544ED3 +:1092A0004641CAEC58A45DAB07EBD18EACA32B01B1 +:1092B000BAAF21217EDACC6039E6E5FE7911377448 +:1092C000297DE242A28DC73FB07827C2F9A0385F5E +:1092D0000E749E13711470CF16FC21224EA8399182 +:1092E0009F8373492EF44FF7DBA644B41FD0FD29AA +:1092F00085EEC7BEB8222CEFB71F35EB177114B23D +:10930000B510ED42CB42D77B19F0107ACB6FA83E57 +:1093100080F7341215A6D70D3AF681038A0B3B5518 +:10932000719EF5467A80017BC18B3C8EAF4DADAF0F +:109330003F9BC8E393F839E752F01A181F3CEE4EF2 +:10934000E0E332F530117727E0F8427FB8EF51C102 +:10935000B5EFBCD807F73DE1E02EE072AEA8F329E7 +:10936000C0976C3D9200F0EE8872EE83FAE947FDFB +:10937000A7245D705E157217C6CBF6B6CB783FCFCB +:109380003D81C55BB9F7C8C81ABA3B4CE837AD6E2A +:109390007F1DF5C2AE46CA68A91E76A6910EA9BF6A +:1093A00088BD4003EF81CE47623D1F68D62FE2752E +:1093B000E83A7F7F0938FC3E1C1C2AE45183E19E79 +:1093C000575F9C913E905115421FDA756CE6F4B0E0 +:1093D00056EF3C01FD1DEF4CDB0CFD55C81D07533E +:1093E000003EEB24BC7F35D1C4EECB26F3FB7425C5 +:1093F000FE063BDC374E4AB3E0FDA9E1DF919DE07C +:1094000017FE78DD6D31704F4CF43F5CD2E1FD4EBC +:10941000429EFBE48E42F0572EB06FA2B98526160D +:109420009791F9DD485F16E523AF1A8919F6A36114 +:109430006803DE6B0944CB68B78C93C924A03B3129 +:109440006F711F567C87FBFA70EF527C9FD81428EF +:10945000584BD30E4E0F62DD13CB03050D9620FC47 +:10946000455CA6163E5B383CDCF1C666D017BBCD2A +:10947000E2FCC95262D3239F596766FBE6D855E2E6 +:10948000FCEDB3C2B9D41DE1183C06F6DFFB32791E +:1094900092267FB1390647E3FA15D4C7D7D958BB0E +:1094A0006E1E07BFEEA3B244885F8E6F0A1F6FA6C1 +:1094B00024B1735C2DF7EF8BEFB57A1FC68DD542C3 +:1094C000BC7641F0FB95C66B8B78FC01E110AD27B3 +:1094D000FAD178EFDC79B17AAFFC4B0E7BBEBE3EA1 +:1094E0004927E20FD1EF4DCF5B61E30B4B93D8F9E6 +:1094F0002A1807E8C77BC37DF1857B4A13C945CE8F +:10950000FBEEF30E55DC9F8837779F9F84717EFDBD +:10951000FAA5FD2996605CE140F0DF92C8E6E58699 +:1095200078BF82D0EF0AFBDE374E1C8FDFF347C1D6 +:109530003EFD45BB8CF7EA7F714837757B9879D73C +:109540002731B85D13AFC77D33D2471CDBC28C2FE8 +:10955000EA89FB35E29EAA767EBBCBFC8B60FE10CF +:10956000471C6EBCA59C8EC4BC77C7307CB8F799ED +:10957000F09E05ED17E3BD77C7F857E2BEB0A9F13D +:109580007C3BB7D7ECBEDE9F81F7BCA6313BC34026 +:10959000F4E08D72FD04F5D89B69654A3FC5FA0673 +:1095A000C916B2FF2E450F41B8EB5478ED0F772363 +:1095B000E257F4FBF961BE4F89C302E7B7255CBEF1 +:1095C0002DD95183FAAF381F7DFEB08CF1179F1350 +:1095D000E627F9BC55C2F3CF521721EB291F5AF9E0 +:1095E00064413388B92549845C17C3BEDF09E94665 +:1095F000B59F7CF9BDFDEC872454AEAE200D2857F5 +:1096000056FE58DDAE9ADCFB67D09FB4FEFBE1DC72 +:109610002E27D6B139899E4740EF2926C5201FD66F +:109620003EF985314A19781F9CA67C77981EF8AFC1 +:1096300019D3AE461BA6BF48723C9644F1B727C962 +:10964000B50DD29EF759FFBDB5BD4C7E6C8D43B9AB +:10965000D564FD2EF2757908E3EBF7C03B09141EC3 +:109660002613D39712740D7214EA2D5EA487E3F1CA +:109670006BAA6662DE9E04741FF7CB295331CEEFCE +:1096800097910E80F7A652471ED8253655B27B9982 +:109690006613F3B37B7F31F63570830C6BBBBF0C65 +:1096A000CEC1B68EFD3EB0F7B4E8FE7C10E2575A4C +:1096B000AE63F18B093AFFFED490F1E223BD49E09D +:1096C000878F1F69C4388F38B934AF21245ECACD63 +:1096D00071D1DB9E8576C21E83B01BB645E0BDA866 +:1096E000DAA183818F5C43189E45DC1BCC2154DFBB +:1096F000EDA27084A04B91BFA64DF219A2F0FD120D +:10970000F4E3D4DEE54B980F72EAE77AF48389F943 +:10971000C5BD9A5C06FE2E219FE64B366647E3FAEE +:10972000FC3C22FE317FD95C4E27F3B81E3F3F92AE +:10973000C17B29B16740BB5BCC244A47B7D4FCF25C +:10974000B6225C678D211AF405E1F71958CF086F2E +:10975000FF723F6565F78DA54036747286C2E76279 +:10976000FB30C0F9B23B9BDDBB23C38803FC8CEE0E +:109770007DC3B7817DC23488F9AF297F3297E4A3D6 +:109780005E6D8673D4ADAF44F0F8222FBF4FECC8A6 +:1097900083F89CFAAAB47C8C13391AC07737BA0DB7 +:1097A000FE0CDCC794EF4854360EDAF2FD197AB895 +:1097B000AF9942F5359A2FD9722FCB0FF5AFD4D18F +:1097C000FC922D4FCDD0D3FDE1BEC67F0AF2355BB2 +:1097D00076B17CBE7FA54CF3CD5B5E65F5E160495B +:1097E00009ECC12D07677868FF67A2B9BCB7FBF128 +:1097F0009EB5FBE5E1BA503B6B6332E35B67B89D16 +:10980000F84C26595C05F01E11BEFEB2641D0F5ABD +:1098100069C554AC57B42749E1DB25F3716EE5F710 +:10982000A32746929608E6B7F344513C1CE8188EED +:109830007EC7AF9362989E6EF3E3FB38A21F014F81 +:10984000D19F187735C867E0CB9A78ACEC64863F37 +:109850003ACE461C679883DD2BAE4ACB03FC51BC45 +:10986000E939DEF4ECFCBB8DCD8FF61B9D8B72A02D +:1098700000ECF807BEA2F53383F3D6D24941329308 +:109880002FB736317F6B203A0BE96962247F67A5D9 +:1098900050BD8E660E87C6E4687E6F46C02B51C2EF +:1098A000719A381CD3FC78CFF24AD75DF11F5A77F2 +:1098B00008BE1CF05ECA81F6ABB7B3F5C4F07BCD31 +:1098C000FE8C18D4F7EE57F5776683A67D09C1B8EC +:1098D00036774C16B6BF278298F13BD9DED72E33A8 +:1098E00097E9ADA0CF8A772C88E73A12EA47EC7B5C +:1098F000AFA28DC56706D739A390AFD3C6D769632A +:10990000EBF4AAE8951C0964CCB6F6A7E33EF8F799 +:10991000F5372A9FF7A7DAE7E1FA837D3D105ED697 +:10992000733AF9D6F022E6A981671F9C35F313F04C +:1099300084FD8DED46A9E952CCB326599C9335FBA5 +:109940003BF31B8E57CADAD5DDCEE2B989A2A6EB6E +:10995000BADD993A882B10ED6AC127101FB4FF3D7C +:109960009ACCED8969246D80F8C4C7938BC2DA0D57 +:10997000F1BBF69CD813CDE2D5B5F68A9E787B274D +:10998000DCAFF49C63EF0A8CD3D86FC0CFF49C2576 +:10999000D82E285FD4F9739C3FF6B73F0532607E1E +:1099A00085A6B2E7153BD547B61C437E5D38B8ECBB +:1099B000B64C9A7F35F98FC8CF0B53CBBEC8A4FCE9 +:1099C0007C7FB29FE547967D3114F25BFCACFE4490 +:1099D000C7F3C0EF89C73F63527250AF782D59412A +:1099E000B8C9E53A027464022586AEC7F4AA09E351 +:1099F000F6045C074A0B4DBA8670F76FDFEEA307DB +:109A0000E65729813F15B0F3713B805FAFB203F495 +:109A100044B17BDF3D7BFF8EF75D3E487675021ECD +:109A2000EA23BB1665D2FC5D919FA01F4F72D03D0B +:109A300001F615C54616D0F94A5D9B9CA03F91D50D +:109A400076B31EE1CAED5E748D1728FC5ED9F7F37C +:109A5000EFA5B2619C308FB19C0FD4EFFBF26FE0A9 +:109A6000F7AD3F63B183F97A6CC796DB40FF1ADB31 +:109A7000F1F6974C0EB3FB3962DE63C1AE49BF9776 +:109A8000B49B70FE633BAE5E01F5C7FDB6230BE8E9 +:109A900064C2315F13B0859EBD2FA5AAEEE590CFBD +:109AA0002E1AD739A0DF4DC0E353AA540D4678F4DF +:109AB00032787C85F167DDF1879BFD68FC54DF7FA0 +:109AC000A2FA3AFA917BC9203BF833C47D7AADBD46 +:109AD000F468255D1FFD3E21406710A24F4F3C6F8B +:109AE000A68C24982F25D1AA7CB9395955BFC29686 +:109AF000A92A9F9274B5AA7C9A92A7CA4F1F315681 +:109B000055FF067BA92A7F63C93455FD4A47A52A1C +:109B10009FE76B53D52F38D4AE2E3F4264C043FE2F +:109B200051FBEB90169D74A0D9B5F874C3EB908EE1 +:109B3000FD0B0387D65E7CEDF9B6D7E1BBB0176BA2 +:109B4000EF3309FBF1CDB2C56B0C6F274ED2670521 +:109B5000DF1F9075EC3ED318ABEBEA94A2E07DA634 +:109B600089602FA648A8587CEE47E3004F0B983D2C +:109B7000ED282006E3BEAD68873C6A6878E60F2CC6 +:109B80000E201DF8DE84C05CD5BA279E77A9D65D6D +:109B90004A6ED5E0698D2A5F61BB5D557F4AD2066A +:109BA00055F934E5071A3CDDAFCADF60DFA2C1D347 +:109BB000360D9E7EAE2A17F4DDC1ED5AFBC01E4560 +:109BC000D3F1FECE72C0C375A703888F92CED67232 +:109BD000C0D3B547DB105F853E6739B0CBE2430D9C +:109BE000AF43EAA3E73168F75A6312A6071A15B420 +:109BF0006B1D6C1C81E9A1463B7EFF756309A6EFD6 +:109C0000343A307DAF712AA69D8D4E4CDB1ADBB005 +:109C1000FE738DEDCC2E16DBF7DE453AD807BA750C +:109C20007E377882173F927703F0CBEE41FE6EC805 +:109C3000DF45EC374CA2F925C044E8BEFC294F377C +:109C4000A43A028057371CCA8A82F1186D3A471E1F +:109C5000E8E177A44CF8A13E9D90BB3738936CD1D6 +:109C60002C6FA6794436C6B34DF8A18312D73320A2 +:109C70004AD0A933E106C8F744B07277CA841B40C2 +:109C80000FFFC6FE73473FFFF91D2961FCE7CF9C1C +:109C900056AC60D739FCD5702BC0E330B76F39486C +:109CA0009E61094D4BF5790690B34707B8B7F08030 +:109CB000AEB409E0D0A6B3CFC178EFEB0D04E8B79E +:109CC0004A62E75F51CF95CAE441CF0D263C4F1D54 +:109CD000D13956605C9914780CE0BC3DA512E1DEE8 +:109CE000630D6400FCBC294E968F0F3C26D943F2CD +:109CF00006069F07526EFCB6E1F35838F83C9162B5 +:109D000063FAB6CF910E7A80C81FA974D4C17E3E83 +:109D100052EAB80AEFCF384D6CFF3AADDEABD03E19 +:109D2000E4289A1362E719926A60F7D1E16222D8B7 +:109D30003B6F91719F6BE1392195E97B482770CE8C +:109D40009C1789E782233AF69E81B6FE020ED7B3AE +:109D500083C2DBE316A632BDA26C56DD332FD0FEE4 +:109D60007AD64560D73DCEE1A88FF53450E82A3445 +:109D70003DDD708E959BEC1C24E8BF9D0F7FD1F2DA +:109D8000673A6EFBEBEF68FD4FD645DA5186D8AEE9 +:109D900041F8DDC22B2F8C35A3FEB4B02ABD0CE4F4 +:109DA000E27CEE075C64D527A03B501F6D8427172B +:109DB000975BF29A2904C9CAB84A233C25559DB637 +:109DC000A619D2D5C3EE37C21329B5A37635831AA7 +:109DD0005B47B77011F23FFFBB8D745E8BD7CB0A28 +:109DE0003BCF89FBAE355714CF22E8F7088F3BA253 +:109DF00040C0F3EA220E6FD16E1187D78914AE3FAF +:109E0000E6909C0B6A3FD66740EF5D0BDFCD1EC02E +:109E1000CFA02EE7FAE3074636AEF6FD1231EEE2AA +:109E20005476FE3A62A49409FAE42D4C0EE4CEFD79 +:109E3000E2AE22BAFEDC0E9B0EE31516D7BD00780B +:109E4000E86DE778349076D84FB33C4B3EF91D224D +:109E5000264E758FF752F2D2DE692B0F9597857ECD +:109E60006779A8BC2C09B496835C14F251F84F7D35 +:109E70008DD59C2F37203F3DD0B81EF3071B3D9852 +:109E80001E6A6CE17CB915CBDF697C98F3652FE71E +:109E9000CB3BF17B47E35C4CF735BA583ECA19958A +:109EA0000AFBC4ECC2F8C437B69808F8E77A3B4C12 +:109EB000189F4177C4638FC641FC9109EF716AE333 +:109EC00090B47CBE8F1E76F77B372505C6E98B1FC5 +:109ED000027D71C8C0F474982856E04BF98FFEE4F7 +:109EE00006D0AF0F2B8A15F4E982D4CD2CEF50ACFD +:109EF000069A2F7C94E75D8AD504AC22F521E45BB9 +:109F0000873D8A3582E68B1F7D88957B093AF3C7AA +:109F10003DBAF5060FF059221D80FD516ECE9C44CE +:109F2000C50595D7A507605F4C495A3209F6C5CEDD +:109F30001405E9639AB2E100E4A78FD8A687ABFACB +:109F40000E4BDE4668571657A9877693D2D66C8497 +:109F5000769387DDAF0F6D3775D4AE8D909F61DF3F +:109F6000A607FD7427F0B1F8603F222FCA059F169F +:109F70007172A33B9C280F72DB9D280F045CCA669C +:109F800057DE0DF6CFFA76C926C13C664B7D410AF5 +:109F90001093E886F74929BFBE3EF597D60DB45D0C +:109FA0003DE4AFC5FC0F377CBBFCFBA6D430FCFB0B +:109FB00043BEDF41DE43DCFB8746F60ECC331C2E6E +:109FC000F51D4BACF88E2A715941CF7A9ECBF39791 +:109FD00020A5E59FF1B48B7F7F40E770C138AB527D +:109FE000B91FB23F7FA84965FB5F738F648072CE53 +:109FF0001FEA526DAAF73CEA08BBBF76A9383B6D51 +:10A000009CB836EE6435693BE8C8EC1F6F520BF71D +:10A01000DCB2FAC77F8B786A6D1C78DFB96A10E30F +:10A02000A77381D750BA6E491D904FDE7B0938DC8B +:10A030001B0E0EFDD643589C7BBF38241EEFAE5D31 +:10A040001771C5B3778D79FCBB767D822EFAAFAFE1 +:10A0500095C15FCFE04FF5BBC7607E158BAD04ECBB +:10A0600056A1FCE77717E13F5A7EF66DF1C99B17C1 +:10A07000D7E1BB6561F8D8F3E1F898B8CFAF4D856B +:10A080009E0AF7F3201E12DE3982737E65A26B1FD3 +:10A09000F4D35316F89B0ECEA171ECDDF083D1AE54 +:10A0A000FDF05D32B2B80611977C5AE7F915E86DFC +:10A0B000EF3DFA19F2B36E1016748FBC41F3A097FE +:10A0C000FDC3E67C13E04746F88DA1EF8F0F147FA8 +:10A0D000FB1B2EFFFAA76CDF8938D49E6D5F66A04C +:10A0E000FDEE12FB62207854C8E3FD703FA4B72454 +:10A0F00012E56797447CF0DE71576902EA2D5DE94D +:10A10000463DA4DFF6B9B82B3D1BFBD79E8FBB9213 +:10A110004BCC6CDCC953217D2FF95421C8BDDFF035 +:10A12000F8CB76A3A7E03DB00F8F8D40FFFE8D9258 +:10A13000BF10E0A03D5777BDB5A04CC9ED7FBEA6CE +:10A14000EB9B04EBAB3DAEBB1BBE5DE979BB76FD83 +:10A15000DF08C4B98F5BFF1581F7EFAEFCFCDD199A +:10A1600093AB805EE16A021219D345F5099ABF5498 +:10A17000FCD639899ED33343CEE5256FB3382E9E66 +:10A180006ACFE7FDDE095CED51C70D96FA8A305EB5 +:10A1900045F647E1BD601D7B6F43C473BDC9CFF376 +:10A1A000F4BC3E240DED709D19AAF3FA1D1F2DFA83 +:10A1B0001EF281088CEF78A6FD443CCCF58F9DF112 +:10A1C0003F794509D277BDED6F24F49DC0DAF5BD26 +:10A1D000AA7CD786E0FB56701FABF65F32CA252AF1 +:10A1E000C75A104FE435E3DA10F94ADAFEDC07EF1C +:10A1F000D194DF5502C050BE36CF74D07695FC3C6A +:10A200004448E48D0EDAAE929F1F8967252B8FE7B5 +:10A21000F53D9FB07CBA28FFE34CAC7F95E86F1CFE +:10A220002B4F1679DEDFD5229F782396678AF62595 +:10A230002C9F23C6AF64EDADACFEE4ADFF9C097A64 +:10A240008DE0F733D2B89CE0EF5251FEEF4C2BBAC1 +:10A2500068BC8EBA9CCB07F10E55C51DD322DF8595 +:10A260007DDC2661EC61ED9D06B4E79F8D69CB0D29 +:10A27000BD2F2FE27A9CE5568CF3AA7B71F8769974 +:10A28000C73B811EB39CFBE92B640BFA617AEF6537 +:10A290007C7E203D70E5FA9755F8EC57CEDFD3462B +:10A2A00047251DEFDC0F13F17E0219D689F102EE6E +:10A2B0003449C427E0BD6A11571797451C707E8E3C +:10A2C0007B2982BDA77AB213F9EFCA97987DBB6E3E +:10A2D000CBEB28EF96CA0ADA97BE1EEA5A07F0E9D6 +:10A2E000B6B2772F57AEDF87FBF431C5C6FD60816C +:10A2F00051A1F0BCB33FFC3D69F11785BFBAFC3FEB +:10A300000C7FAD5D5DDCD75F7D85F17FDD56E607B7 +:10A31000B6733CFD49A71473783D02F03AB7A233F7 +:10A320003B5A8620EE4E8C77AB90DF2982F3566F36 +:10A33000839500DEBBA5CEDC0FC3E05F7BAE389F0C +:10A34000415471693BFBC3F7E94BD0F7D3FF4DFA9A +:10A350004ED4FB8D76F01B1F65EFE51577FEC9180F +:10A360001A1FF44E1A3B070F6E677E311117172C18 +:10A37000B7323C71FF535DD53BE3C1FF24F6C3C444 +:10A3800048D206FE044AD7764ED776A06B41BF412D +:10A390003F146D1706BE41FA252C2E91C3E9B7FD77 +:10A3A000E1FAE125E0FAE17F13AEBBA93E8CFEDBCA +:10A3B0001722D04EA385F33F385C05BC23D32F0E64 +:10A3C000E7C8F4FF0C9C23D315959D43C07B20F96F +:10A3D000A4C58F9877987D5AF44DF6E923199C4FC0 +:10A3E000E9FD188FABC57B4C7A3FBC27A45F1CEFFF +:10A3F000EAF2FF30DEB570D3A6B5DC9FABFD5E9808 +:10A400003E20BFFB56E0F87FCD4FB0B061BFAA7CC5 +:10A41000F1FAB754E54B3CEF5F965F41D8FBFF5B29 +:10A42000FE05E15798F9FC2A1DF81FB5F24137C423 +:10A43000F923A0C71B5FFE7AD48730F9EA6C8CB78A +:10A44000BA8DAFE58BF17FFFE47B94BEBE6860F60A +:10A45000D663FB3F372839FDE965E1791D7184D06A +:10A46000D9C2F5EF1B40CF5A48D8FB54DAFA0FA6F1 +:10A47000337B30C64951BE30D74C0C71941FCC9DF4 +:10A48000CBEE4BCF0507630CA63E172D9FA9273EA9 +:10A49000788FBBD2A2F799D0EFA9BEFF6EE2EF751D +:10A4A00093B858D53D78D921639CDF9C12E62FBD27 +:10A4B000C5D286F787E71DBAEBDCF7602F6FF4147F +:10A4C000B1B87771FFF0F7BA2BF1833E087A2A9C76 +:10A4D000FB24EE5F5F6340FFBAB6DD2ABE9F66CA0B +:10A4E000128BA3D9C3E233C5FEA4EB3B64CA67F762 +:10A4F00060E0F7482A1B0CBEE1B9A067EF473DBBFF +:10A50000BE64432EE0AF7E9274DC941B3CEFD4AF6C +:10A51000FF0BB6D7F2676D7AB9F6D54F1A0F21BD8A +:10A520008873D1B1461FE6B5F6D60513FF17FD9324 +:10A5300063FFE26D8274DC578E0FC7D075FB1B3B47 +:10A54000FF2D7B82B02308BB82D64E21F88878BFCE +:10A55000D2976EE3EFB296A2DF83E8592AF8EDC1F5 +:10A56000FEFCF9D7E917D727D5E5FF61FE7CB9F4E2 +:10A570005F9BC4E4AA96EE8F56FD0CEDCF82BEB56C +:10A58000F4BF006252E8F80BEA25BC273E7755ABD2 +:10A59000619CF4CDE97DB5E56406839B462E5CB1F4 +:10A5A0003C50783C878CE70B93BCC60E760F8187B6 +:10A5B000AFD3D5EF0353BC48191797ABEAF2FFFAB4 +:10A5C00039E0E4A26F2617894A9F48CBE8B76EE5C9 +:10A5D00012EB56FE9BEB0EB9A7B448D605EFE3404D +:10A5E000FC35C481F678D9FDD4EACC56FCDD0352A3 +:10A5F0001288027E77EB5E99FD9E8EDEA14F0E796A +:10A600003FAD8BF83E007A5C359EBD3BA48D9B76BA +:10A61000F378EAD596DD78BF51FB0E9A88CB76F3B6 +:10A62000FEB4EFA189F6E29D03ED7B685332781CFE +:10A63000763EC967712917E7A3DD20CF43FC35DDDE +:10A640005F35A25DE1C6C74AEEF3A405F13227A348 +:10A650001FDF99977171BEA32EFF2FD3AF6CDD81E1 +:10A66000F7D8AE947E47643ADC407F822FF7F19BA7 +:10A67000574CC86FC43BF33D6B9EC1F7877ABE242D +:10A68000E897BDD43BE313BBD835C40927BD4D566D +:10A690008AD771C73C68AF1B7BC485F776C7BCE31C +:10A6A00080887F9277C029C3BC853E23F49B20FF1E +:10A6B000E2F7D9789CD5E5F2B92BF537FEA7FC8CEB +:10A6C000E25E5DB7C15704BFE7E0D91381BF03A1C4 +:10A6D0009DFF9319BA8BBE93DC11E57A12F0348B8F +:10A6E000CB09F15E7285CCDE49EFED94D15EB8EE18 +:10A6F0007F7EFBAB47954BDB15EA6DBD61CF6522D5 +:10A70000ADD7B17B2DF9E50AC649C2790DEC87C2F8 +:10A710009EA8AD7F4A297B2903ED5BE3F13DDADE9C +:10A7200087D97C06C257FDFA008E3F60391FBF7E75 +:10A730006F912DF49D95F3197DE743DB297310DFAD +:10A74000974B17FFD7CE2D3365E291A87CCD91BCF6 +:10A750004CEF254CFF5D403A315D440298BA08BB8E +:10A76000CFB094D8315D4E9C98AE555C5D191837CA +:10A770001448C0F8D317FF390AE8E6DC75E35A211C +:10A7800046F1DBF22369F5BE9E3C85BD97F4C23FDE +:10A790007F07F4D9F33F86CBE21B47A21C6448181D +:10A7A0003FD37BA532BBD754F25DDC17E2FD5D32AF +:10A7B00089F9E1962766E2FE09F2CDC46D826F82C7 +:10A7C0003F39E7B88EC5C3DC2AE17BC6ED7E1D6E3E +:10A7D000B19C15995EF8DDB9F6DDAC3CA72EDA2BFD +:10A7E000D17CCED80856BE26DA0BF74F16123FEEB4 +:10A7F000CBC570FB4486FB4B8C2F8ADF0BA02782D6 +:10A80000A1126DBFA2C3CCEE5110FF30E0FFB970B2 +:10A810007E0A174F3384F1F1D14319BF1F5DA6B6ED +:10A82000870CE5E5F72965DF0778B40C71640D81C5 +:10A83000FA319D9B1E2C043B908E809FE6B3B1B7EE +:10A84000A35F53B47B51291B01F59F9558BCBF678B +:10A850002FBF6F4C0209A1FEB1B54A792ED42B1A35 +:10A86000C2F8D3407085DF517486392F8AF8D1D170 +:10A87000706643BB3CC177D29E95587EF2E35B6F16 +:10A88000DC68415F8207F4E31715D744186FB49171 +:10A89000100BCCFFA7FC7E1B69C800BBE8AAC74C05 +:10A8A0003AD02F3EA2E218EEF7FC819EB721FD9828 +:10A8B0009E9B21FD233D37437A9C9E9B213D41CFAA +:10A8C000CD90AE386F87C7CCC989218EB9D0BFF083 +:10A8D000F769E75B3984F1D7BEF1F71A71FCFB1415 +:10A8E00017C2B70FDF7B08FEDEEDB3D18194988BE2 +:10A8F000D05BCFDEBFA39F7420B808FFA3B67C0A4D +:10A90000C76BEE6E3DCAFFDC767FD4CA907A2B8788 +:10A9100018B17DCE0B27A3A0FF6E5B1F7C1D125DBF +:10A92000F24C1DCBAF7CFCB91B378E82F93BBE0FBE +:10A930007441F7F96A4873DB7FFB00FC5E2AED1F68 +:10A94000E3247AA4C0663C2F68D6A1858358D7B388 +:10A95000D19D9BA0FDB32F0C859550BE43D8BE0161 +:10A960003A92C2AD7703AEE74653A010EE0BDD7806 +:10A97000410E1BA77D9F528A704E067A43FEDDCAA8 +:10A9800053465F026FDF747F6BFB23E2FD15E0A58A +:10A990000AC8A5AFA2402FACE4F104EDBB87FD06C9 +:10A9A000D6E9392413F8BDDAD131EAFDB78BE34992 +:10A9B000A4397B8D4EC0D7B37B4F0D83F789297E99 +:10A9C00086C17BC5DB865C45427FEF3167EC978FA4 +:10A9D0003C1887F5F1F769E7916D15103733DFBC47 +:10A9E000FF0D58D242DBF10A889B599C241D8474C8 +:10A9F00089923919E265C47D8365234A0FC2969A0C +:10AA000061AF447DAE14984C887C283747F247D814 +:10AA1000853C8A55E5A724A5AAEA4F53B254E5D34D +:10AA2000478C54958B7167D80B54F546C70486C282 +:10AA3000798EAE83BD03FFA48CF186392F1CB97EBD +:10AA400024CDCF7C6A0EBE43F92C2F9FF95CB91739 +:10AA5000F0D143E169A40AD5E9921F6C7E103AD384 +:10AA60009C176AF73E71D0A15CC679E112E7848138 +:10AA7000DE4F16EDB5E704CA371F00BE39FAC5D957 +:10AA800036F0DB3E3BF6CB148847FDCD10FEAE0C16 +:10AA90003F3F0C44377DFB435218DDBC259327C351 +:10AAA000D00D44F2323A64E9CCC3EC7EDE95F2B5C7 +:10AAB0004F81AFA1BDC043427F7F576BDF1B6DB499 +:10AAC000FFE636B047BD2BC30DA5BE7B932BE16FD0 +:10AAD0003948EF64F9B6BB93E3F0BB07F46137B7CD +:10AAE000F70D52B83E55BBFFEEE4C2603959775CB2 +:10AAF000559FDC2935ABF21B33D5F97B4B9B43DBF0 +:10AB00000FA48FAD7C7889D19503F76EA5B0BF37C0 +:10AB10002CE6F3FF010980D5200080000000000032 +:10AB20001F8B08000000000000FFB5190B5454658E +:10AB3000FABBF7CE0B1960782810427798440A8444 +:10AB4000895728B08DA01ED7DA1A4C8F545693E53A +:10AB500003794DE0B6F4D8E318AD8FB6076D5B69A5 +:10AB60006B355696E7E439B144462536AE5B49EB82 +:10AB7000D654A266E499D8424C70267A6D9D5AF755 +:10AB8000FBFEFF5E672E605B9DD64EE79FEFFFFFEB +:10AB9000FB7FEF279014CA70CE0008F6ACCC7099FA +:10ABA0000106F7D61AE41880D3F4EFE2F0DAB8F928 +:10ABB0007A8303CF5700383ACCE3CF01D601140390 +:10ABC0005C29817BA2F3145960E760FF65F1BD2F1A +:10ABD000010849009E178DDEED5684E35C06676E22 +:10ABE000F89E8DF04E0618D972FFEFBF2AC2F525E8 +:10ABF000B0E30E8CC4430DBD9BD7755C1471CD9F23 +:10AC000004D7D17779968098806B7055B407E200AD +:10AC10009A6A633C623E9E67860E992E04C8F1A62E +:10AC2000B59B52018E8A22C039440778A014EFE305 +:10AC30001B045F24A739EFA4DFB9C867CC2FC7E78F +:10AC40004532B035BF3294E9C67BD77E87E71CBF5B +:10AC500003A291CE3F804A8F034C5C2E04BBBD19EA +:10AC6000FE3F233F4DBD1218909F61F01DBA5A6000 +:10AC7000D7CCA925002BE9A74CFB1D0690D86F194E +:10AC8000707F95B2BFB27CE5A5108BF056FD4020D9 +:10AC90009BBD0FA7F1FFD57F6F3798F17CF553DA95 +:10ACA0007D420F53902FE5FB3AF0B377EB77E23D0F +:10ACB00053F85E23DCFD9984EF367669BF5F24C7C5 +:10ACC000240DE6E08F0228382DB16D91DE6B36F150 +:10ACD000F7E64ADFBD7B09EAB1E925C96EC4ADD10B +:10ACE000DDD3E200F98339A8E4D4F1F26BDA8C7A8F +:10ACF0002A0CC3A7764BF3BD745F17CAA89E315EBA +:10AD0000CE60C9E2F82C1C5F73C5D70B01F135F793 +:10AD1000E8D0D07E00CF4611E4083CCFED31AEF252 +:10AD20009AC3F4072D9CC7FC9E2F1366E7F2751D8E +:10AD3000D101ED1C2F70BF9821803E09F141B56013 +:10AD4000DF8E4B5F4F7225C9BF4F009F5CC09E587E +:10AD50006442FD5CC19FA37D3324E08F946C1DE1B0 +:10AD600059A8C8FD8AD27F7C23E0778B7B164F439E +:10AD70000AE050D7B23ED40C6C906D0CDF12F0E8B4 +:10AD8000492F7DF1CEF416A4F3324960F6DF171F88 +:10AD90001A16107F5F45B4D026B0F7EFA4F755BE62 +:10ADA000FAF4CE7437E36B8E6510F526382E904E8C +:10ADB000478F974758AE3A1854F52B7177217F9CEF +:10ADC0002BDD3EFB12F4DBD1A5603122BD974B6831 +:10ADD0003808C3ABDC8FAB49D63351AE823F81E834 +:10ADE0006C96176E91F1BBE4D67B41971821371D05 +:10ADF000F733552FAA1CC7D3A1E22DF73B90BFD143 +:10AE00001D02B39F46BBCCECB3B1FCE4834B107F77 +:10AE1000A35FB20B48CFB2EEBD47487E1D6B3B40EF +:10AE2000771E40E7DA6EB62E33997D521EE38BD93A +:10AE3000AD8846417CAD5660C6A7357C1EE67B0CCE +:10AE4000BC513F7C06CE043818EB7C9EF85BF3FBCC +:10AE5000CFFB9610B51BCAE3991F90AD9D1BA63F73 +:10AE6000DF006046FA43DBA3BD4F303C68AF25618D +:10AE70007B3DB127EB700B9E9F7853CFCC755FC5A0 +:10AE8000C3A76E4178CDF66826E71309E049A5F31C +:10AE900027A67B3D7861A518EA6F21B977C6D8B798 +:10AEA000E3F9F147A73FBB13E1DA67A7D9894CF271 +:10AEB0001F19E57D3C1D01DA7F3E957D07291CEFBA +:10AEC0000AC52FA56766DC574EE7CF24DA098FAA9B +:10AED000BFA147A31C80F2FA127C791634BD93827D +:10AEE0006750C487EBC49DC704B4CBDB0CAE83C4EE +:10AEF000F7EA47FE7AA80CF9A97AE6370FCF44FAA9 +:10AF00006ADF9B0CF44E58AFE3E2406C2097FCDF05 +:10AF1000C6FD5F914FDD8E28CBC71171A6A1235EC0 +:10AF2000033775A75A3E8E883775C0650CF5828E3B +:10AF3000F8A957FCAA5E741D25BA1A20C0E3228422 +:10AF40000C64570592E0A07810BAC7C8E43FD6CE8B +:10AF5000466591D1512F828BE27941229852C86F78 +:10AF60005D5C7EC17BA63F7117CA66923541F5FBD9 +:10AF7000AC853322EDB3BFF115B2CFCD46669FC38A +:10AF8000513C2F8DC5F31F399E7DBFC2F405F38759 +:10AF900033F9A4F5DF5A38171C14EF0ADAE4C29B20 +:10AFA000706D51F4722CC5295849EE1DF7EF3AC067 +:10AFB000E4B9F5E6A38477BF99E90F0E70B90705E8 +:10AFC0009E27D5F7569842A02B247AB7317AD5FD23 +:10AFD000C12D87F35CF8FEE00B397980F6BC4CF2AA +:10AFE0000FFE05E5732AC67FEC365C3BF7BF3B8559 +:10AFF000F2E0587AEB5B47D97B2A3C2CF038544F6F +:10B000007CE0FEF799CE64A213C3088B0F0377CDC3 +:10B0100060F29B2BE5C691FE8327B4F48DA5537D8A +:10B020005FA54F7D5FBD37CD2A32398E18FC7994EC +:10B03000F75FCC90357C8DC4FAF3E2CDB46FE17547 +:10B040004402C211F656433F51BF35268CDB485FA0 +:10B050004D8D606F03B6EFA1B889ABCF85E7F529B9 +:10B060002F2B7203A709ED78B162679094C8EC6E3C +:10B070001170BB5EACC4EDABA0430FE82F47C475A5 +:10B08000BF35A0FD0D773CA07745C65DCF51F1746B +:10B09000CE4F8FBB9E4AC8A6F83D6231B3BA669EBA +:10B0A00055D0B17BE9904EF7F0DCEE433BF0741ADB +:10B0B000ED6D48CFE3A2738115E5536FF0E5911F65 +:10B0C000A8DF3D2EBAD8FEB0706005E91B74BE3C07 +:10B0D00056EFC41B40C03A2338D9EE77505DF625B1 +:10B0E000B0B812D4434D27E22DAA12DD9DE6703C84 +:10B0F00054E367510EEEA35C2B685FF557B49BA237 +:10B100007CEDFD303F5AF8B895FB5D51A2E8EE9812 +:10B11000C05F6E57F4DC061D12F7679E47CB14B96B +:10B1200063DD2245D62D8D4A9C0FC69A3C12F25300 +:10B13000B61BF5827099CEB797568C02D08AFA9DCD +:10B14000053EFE5EB7369E530E59CAF2720ECBCB49 +:10B15000B31475AF17DC407A3551FEC2F52EC12FFE +:10B16000D1FA2B08B1D501161DADA806B6CE012720 +:10B170005BE7819BADF3A19DAD0BA083AD97829F53 +:10B18000AD7081AF0D583EB8DD3288F9187EBD52E2 +:10B19000A4BC5CB464E27AFC71455E67970746F92B +:10B1A000929F2F8F79E04A61749D4D2E53B399DDA4 +:10B1B000AB7231927DE27751E04DA1B50202EC9D78 +:10B1C0008BC990F19DD920EB08AE020783E7FE48BA +:10B1D0007994065C3A57EE0472A99AD84E7628768E +:10B1E000524C365D1CD6D787561E1754BD01D24926 +:10B1F000F960BC3E2183E82C8AAEFC5CC690F1DA93 +:10B20000B6F79D3A8CA34585952D36840F593FE5B9 +:10B210007059E5F399081FD976D2A99B49765E59F2 +:10B22000A8B76315BA6ED83907CF4D18FCA3504E96 +:10B23000924D82525C5D51B179807E6794ACEB7423 +:10B24000E857C6DB80C5195714809FD5B36865E4FD +:10B250002735BC7E5D63E17ADB6B70BD4A7EDA60C8 +:10B26000F2C5CAC8D39A757393295F6E30F0F73F61 +:10B270009A2CE7BC827232223E5341984F3CF744ED +:10B28000211C10E496566B18FF8FC0F7CF1FC277B2 +:10B290006B8AEB5D16CF4D5940FA4F53F2796767D1 +:10B2A000598A5D24FC16863F1093D5D28A470752EF +:10B2B0009C1FD27BC1186E771F5AB95ECEB69A32E8 +:10B2C0001D1F5827D80FAEFB7A978FE2D02748086A +:10B2D000BEF399D53540743489818C42D4D71DD1C1 +:10B2E000C70C6427AA1D0BA8BCA5C87F9B03BC067E +:10B2F000E61FE59633F5982DEC07C1E5F81ECAA5C3 +:10B30000C8E9ACD2E371498D7B1FADA5AEF62A3CEE +:10B31000213C41A2A7490AAD20BB3815FF9EE1138D +:10B32000E6A753B93D2AF1AB674FEF6D691C744234 +:10B33000841F36EDF9E6AB0F50DF4DA3663B5D0F82 +:10B34000FBDF9616EA0BB01AD4C417D52F67751B0E +:10B350007DD45F95ED3E7F39DDAB78AFDF4671FA86 +:10B36000E2FE401B95CBC19EC369DC2FD43AFE6B35 +:10B37000E1E7E493B9120575ACCB5E90BC46E4AB53 +:10B3800099EA0B05F6207CDC84761347F779BFA990 +:10B39000F6950DBDAF19A82FC1673CC46FAD42FF34 +:10B3A000AAAD375C4AF562AD57DB2FD6F57BD713D4 +:10B3B000DD753BB4FB6ABFD9A47C5F4FF59A8DEA7B +:10B3C0003EEDBD26EA37F3A8FED3EE67662AFDA65A +:10B3D00092FF40A933572A77883F33EBFF0C5E2357 +:10B3E000F2D6FC688BDD4270BAD9CEE26DFD0666FE +:10B3F000C7EA7DD89AC86C44F5DBDA8DC0EA675598 +:10B400008EF94F1B1DA48FFCA793595D8CF53CABA7 +:10B4100047309EF0FE1E6522A0DD3D171FCA1411A5 +:10B42000CF733DD976AAB75F5EEB807F9D17A64F9D +:10B43000ADF7E74A3BAB0CD447DD887D146E35F79A +:10B440003ED96642B87913D00D242D3B8EEAA6E290 +:10B45000FD1278E91DF03E508E6B971A4F52B0BE28 +:10B460008F9047943C09E409FA79A3A2B7E8EC0469 +:10B47000CD798CFD1CCDF771A599DAEF3D0E7F6E6D +:10B4800009C573FE7DBCE302CDFD36C16DF791CDDC +:10B4900004F03FBC57AE88B1C2BF82CD1D12E71782 +:10B4A00068EE6F889DB79FECBBFC0BDD183B704BC3 +:10B4B000647765018047502FB386B5E7C507DB2168 +:10B4C00016F1471DD48D99577880EA16A3ACDD5F3D +:10B4D000AEDAC55498AA99439C913BB7FBD1219110 +:10B4E000D945099CF7707911C9590F5E79BCDC46C2 +:10B4F00069A5FB6603F38B59BD2D768A47939D5A48 +:10B50000F927D768E59FEAD2CA3B6D9556DEE96E0A +:10B51000ADBCCF6DD5CAD7EAD1CACFB67196E6FE1B +:10B52000B4F64A0D3C7DF302CDFDF3BD0B3570CE74 +:10B530008EAB34F767742CD39CE777AFD69CAB7691 +:10B5400036D60E2EF4358FB13311C408FDAB7A56C2 +:10B55000EDA070FFAD1A3CFF6FFD6F1FA3FFA7C8E2 +:10B56000D731DEBD153B7437B9EB65D13CAE9D9943 +:10B570002794EB59BFF6B69C5815437795FCE654D3 +:10B58000F21B94FF91C3160EDBFDF67D14CF0A8EDD +:10B5900038AB88AEA2807B1F85F392A1F6AA38BA99 +:10B5A000EF00D932858F9CE8FEE5A502E8347E8560 +:10B5B000F094B03CAFF0AC93E2F072D977DE36167F +:10B5C0006EC9E94BC2F320A194E7856A4714E822CB +:10B5D000E452A1EC0325E92961F9ABF323EC07C0A0 +:10B5E00040FD8068F2B65927AA77EC9B25568FB9A3 +:10B5F000587DF686E06273A545267F06C5F7DF25F0 +:10B60000BBDECEC4B8764AB4CBAC9E13026DC45434 +:10B610009018A3A4E5A9AF76501F87ED2CCD2BFF82 +:10B6200074476DB52797916F0994F0B699FEF56749 +:10B63000BA8E64A2FC0704CBFA42FCF6AD5927335C +:10B64000287F1925944401CD4F1C47E9FCCCDC240C +:10B6500019F9C3781B10650F89C273ABC0FA9093B8 +:10B66000F4D8CC08FFDDA867790B94BEEC1A455ED0 +:10B670006A5FB654C13F804FACC2787E4DF71B4C19 +:10B680002E7529C3CA1CCA6DB7E0FB374C3517505D +:10B690005F0A8E423BEFE7D53E2D4DFA297955EDF5 +:10B6A0006BCF76BF2E6548D32FC3CEC409E7916315 +:10B6B000E75E61BEF9FB039BA2591E1AD894CEE641 +:10B6C0008BE1F74FB1F7AF71BFA3B193EB5ADFD75F +:10B6D000D8DFF59E8F34E781A4903E0DF90FEC4A38 +:10B6E0009D7735CA6FE4056309F5ABA8B7385B7180 +:10B6F000F8FDC03DD3E710BEFFCDE7A74CBEFD6B04 +:10B70000FD6CEEA6F2796CED110607D606D83A96D6 +:10B710004FB5BF5557C3DF209BEAE59030C93ED1F6 +:10B72000BCE6311BEF83FA674FA9A47CDC9F6ED087 +:10B73000F1358BC3A9A5260ECF9B4F6B506FDE480A +:10B74000FD6DBF000E01ED61A9E07CEC7AE4BB3A2F +:10B75000D9956BA37A7275284F87FED0941FB8567F +:10B76000407DBE1EEFCA27FE052C065313189D59B7 +:10B77000D4370C899E3C0163C14D4F765753FD3F32 +:10B7800034C9738A3276ADADAB9AFA832103F78F51 +:10B790005B9E7C84F9C3B716D74C7AE71341F2312C +:10B7A0007B7E49F06E67F616302C8CF8BB823AAF80 +:10B7B000A17E9BFA9B60145F67DBF8DF5F2AC7AC52 +:10B7C0004B6D3CAEDD426B31E9E5EE2CFA7BCAE80D +:10B7D0006623905F203E8748F87AF85C760AF2404C +:10B7E000750D566FAC5F2878D5E8A3F8A1CE751615 +:10B7F000DBACECBD241B9FD724DD67F4B6B1FCEEB7 +:10B80000CFA8463ADBF558EF50DF7010D81C6D8496 +:10B81000E661117A596CE3FD17DC08C0CF93B7D10C +:10B820007943EFC0318A27DF67BAAE24390C8872BA +:10B8300009C59386D8BDACDE6BB6C9EC3BA497F1C5 +:10B840008F71E14ED2CF2F380F5C45FA6D300578FD +:10B85000DDAACC03CF26B791E5FE8772D9FCCB9E3B +:10B8600041F4A9F422FDCDB688B99D4A7FF89D1F09 +:10B87000F60B75AEA5C2835B3664919FA15EF8BCE2 +:10B880005112AE5B38C1F70F2AFA3E96E2F410FE71 +:10B89000D56E3EF70BDB4DFBCD4749CFBD66162776 +:10B8A000CFF6FD583E1BF6F43279209FD7127F1158 +:10B8B0007CDE1BC9E748CFE18772E59FCF5F309DF3 +:10B8C000FF1D29B8ED9B0C19BF6FD8FDC611B2BB87 +:10B8D00006751EDFA59D33182761FF9A30D11C1D08 +:10B8E000B34F445D6654BF9FAAD37E8F0539CDA95F +:10B8F000BBC9DFA97E71F0BF8BA9F9B84BE96B8496 +:10B90000C0EB2C1F103EF287F58287E545758ED17E +:10B910002660DE23DDBA5A589E90CE35DBC99EBB29 +:10B92000D006FDE4073A47349B5F8FE9A3BF35B8E3 +:10B930007691FCD6BC53994C7D76E79B0B947E8D1B +:10B94000E7A962C52E8B093FD19F1BC7ECB548A163 +:10B95000AFC484F55026857C8FC4E715CAFC63D339 +:10B96000EB9A3EEFBF32596853001E000000000002 +:10B9700000000000000000001F8B08000000000015 +:10B9800000FFFB51CFC0F0038AC515191844D41924 +:10B99000184C341818566820C46989B5B829D39F43 +:10B9A000C9C2C0900DC4B9409C0FC47C4C0C0CFCA7 +:10B9B0004CC4EB171445B0F50419188480FC6F02D1 +:10B9C0000C0CD7851818BE8B30300803F92E40F1C7 +:10B9D0000420CE01626FA0580B905E04C4DD402CA1 +:10B9E000228ADF7C5102F26B8551F937D1F87B84D2 +:10B9F000F0EB5710C12FAF47401E1B16D1223F3E20 +:10BA00002229D03B10585F01955F26C7C0D0270F71 +:10BA10008C7FA8B80192FC4B20BB5C0EC2F69660EE +:10BA2000602806F20D15B09BEB03942F01CA7D85AB +:10BA3000CA0300CCCCBA8C680300000000000000F0 +:10BA40001F8B08000000000000FFE57D0B78144507 +:10BA5000B670F574F7CC2499994C12F2E03D490088 +:10BA600011030E2144C0709924C0A2460D021A147D +:10BA7000750292849097887EECAEFE330189A0A86F +:10BA8000F1B9AC17DD416137B2E8060C1835E0605A +:10BA900000B32EBAC145C0E72680BC362443F0B9B6 +:10BAA000CB5E6F9D53D533DD9D09C4C7DE7FEFFFAD +:10BAB0008F9F5FA5BAAAEB71DEE7D4E942328F27E8 +:10BAC000640A21DFC18F969F8B8490F850596F20B4 +:10BAD0002E924188D766F46D4CA6CF88237AE6680B +:10BAE0005A981DD1375843EFE9CBD59EA434691835 +:10BAF000210F791C5812E223844EB55A2005F51601 +:10BB0000A83B93E07D3A3E21FDE8F80F46E2F8308D +:10BB10002D99181A671031E07B53ADF989B01E4298 +:10BB20006A47E6C3FC163B21FD7B9F9F8E88EBA7EF +:10BB3000EF0DC1F724FA9EB5EFEF2965570EFD13FF +:10BB4000F6DF6DF66D1408F1EFFCC77158EF9986BA +:10BB5000390E135D6F76B7D93F05EABE6C9F89B683 +:10BB6000E76EFBC026D1FEE5DB4409DA0D3B23F08E +:10BB7000FDCE75820FEA95A6D647AEA4F5C03691E4 +:10BB80003C0FD3F82D069240C87133613F8715EB07 +:10BB90004511AC5ABE7ED76D305F49A38944D0F7BA +:10BBA0008F37882EA82FD928F8089DAFFCB5078CB1 +:10BBB00003E878C53EA13EC241EB1B1F333AE83E85 +:10BBC00097EFFCD8D646E17CDA63260E23EEA3A4D9 +:10BBD0003E8D9052DF96E903E8FBA59B052780BECA +:10BBE00074DDD94E585F69833C5CA4E32DAE8B2293 +:10BBF0008E916CEEEF08CCD77C14E7DB260F83F92F +:10BC00004ACEDF650424E56E93912ECAE93A60DFDF +:10BC1000CABCA73D6B713E059EE52FD2F968BF8A6D +:10BC20009705276CB1C240DCB08ECED7220A5EB039 +:10BC3000C0FEAA8D23ACEA7D146E877D94FAD61BD4 +:10BC4000A75B607DEB8D4569A1F116D7FDA7767DD9 +:10BC50006B5313DD69BDE3F3B487827444A85E4A75 +:10BC6000880BE94FF219818E95E7E78518C4F7E252 +:10BC70003A9138CCA1F1153AF07EC0E9748795F17C +:10BC800001C7DB123BE02C84B76E3BC7A314C8543A +:10BC90008FAF948F003EE87A6A3D762C1FF72461BF +:10BCA000F9A4C781707BDA3312CBB51E273E7FC65D +:10BCB0003301CB751E1796CF796660E9F3E463BF55 +:10BCC000E73D05586EF0B8F1F96F3D2558D679AAD1 +:10BCD000F0F926CF322C377BBCF8FC65CF2A2CEB51 +:10BCE0003DB5586E057CD1B2C1E3C37EDB3D7558CE +:10BCF000367AEAF1F9EB9E462CD77038DAB248B6BC +:10BD000044E16073113B453B89CD7365CBB41E9B09 +:10BD1000CFEA09F3BCD9465A4F70D33A85CB80326B +:10BD20007FB689D60754B1F621F7921C33AD0FF1D7 +:10BD3000B2F69435AE9C085A4FA965ED23D67973B7 +:10BD400022697D848FB58FDAECCF89A2F551F5ACED +:10BD50007D4C13C9B5D0FA183FABA7EF73E55A690C +:10BD60003DBD95D5333FF1E6DA683DB38DBD3FA9C2 +:10BD7000C3273A2C3DF1B055762C2014574DDEB92F +:10BD80002E89CA9BAD46C75DC449C87BDEF92E89A2 +:10BD9000CA8706D985ED6DDEC5AC6E74617BB77759 +:10BDA00029F6DF2EBBB15DAABE0FDBB71BDDD89E27 +:10BDB000505D83ED8DB217DB47563F8AED8D462FE0 +:10BDC000B64FAA5E8BF5D7651FB6E755AFC7FEAF76 +:10BDD0001B7DD8FEF8FD9B5C5369FD05C1BD1DE4CC +:10BDE000DE0AC15D4252819EEA9340EED570F9F9B8 +:10BDF0001C101D6DAFE96F443EDCFA6EE60BC0BF50 +:10BE0000F8EB07F5A2DF3E988CE3BC89E3C8741C0D +:10BE1000F1E2E3A4BF3741334EFA7B25CA382D380F +:10BE20004E44DFC6D9FADE24ED7ADE2B55C6D90F93 +:10BE3000FCB4C2DAB77DA5FF394BBB9E3F9729E31F +:10BE40007C84EB89E9DB7A1A3ED0C2A7E183207CAF +:10BE50008EE238F17D5B4FC6412D7C320E06E1D378 +:10BE600081E3F4EFDB380D07B5F069381884CF971C +:10BE7000089FC17DDB57C6212D7C320E05E1F35FA3 +:10BE8000B89EE4BE8DB3FD532D7CB67F1A848F49D6 +:10BE900080F50CEFDBBE323FD3C227F3B3207CEC3E +:10BEA00038CEA57D1B67FB675AF86CFF2C089FFEF8 +:10BEB00038CEE8BEED2BF3AF5AF864FE35089F1478 +:10BEC00001E033B66FEB69FC5C0B9FC6CF83F0B922 +:10BED0000CC719DFB7F54C38AE85CF84E341F86461 +:10BEE000E0BE26F66D9CC6E35AF8341E0FC26732D8 +:10BEF0008E33B96FFB9A70420B9F092782F0998E9F +:10BF0000E364BBEB985146C7B1F63ECEEB67B4F0A5 +:10BF100079FD4C103ED7E338D3E838A9171F675294 +:10BF2000A7163E933A83F029C071AEEADB38AF77AB +:10BF30006AE1F37A67103E8538CEB57DDBD7A42E53 +:10BF40002D7C267531F88C3B50956BA3ED54173A38 +:10BF500045FACA951D2E9740EBA29DD545BB93800F +:10BF60005D222AF606697589F47DCBE698F4078987 +:10BF7000DAEEC8B913E8C74AAD31B5DD113D21523B +:10BF800063E7C4B86235F5B8190334FDE3F35334FD +:10BF9000ED8905A334EDFDDDE99AFAC092499AFED8 +:10BFA00083AB7234F5A1CBAED6F44FF6DEA0A9A7D1 +:10BFB000AEBA59D37F78ED7C4DFB256B4B35ED97B1 +:10BFC000FA9668EA97D5FD42D37F74FD724DFBE582 +:10BFD0008D0F6ADAC7FA1FD7D4C7B53CA3E93FBEB5 +:10BFE000F5794DFB15873769DA27B66DD5D4AF3CA7 +:10BFF000F9BACECEB3D88F5FC6EB22D03D61767F43 +:10C000007FE6F7F8AD46AC1B0758D08EDF652D7282 +:10C010001CA3F835BEB5C0D18FE217700A7E45F675 +:10C0200080924BDAE8F37B26B92FB1D3E7F718DD1E +:10C0300097DBC3D8A7941E049204A5C300A5BEFD38 +:10C040000199D163CEC0F323DAE9FB9586C0881845 +:10C050005ACF12B31B817E770ACC2F8A144915F46C +:10C060008B3411F40B1E48CE7CC1ABA2D75583296B +:10C070001F0AA17157C9EE24B033DEAA6EF7821DE4 +:10C08000523398EE6B0021CD42BBDF4BFDB4070667 +:10C090001725B9E9782623B5D3D5F31BE9FC693810 +:10C0A0007F0BD0EB7B307F7CCFF94D291334F39B92 +:10C0B000879468E6371BE9FC7642DEAF3EC5E7A70A +:10C0C000489844C85F845338BF694809CEFF8091BF +:10C0D000FA2BEAF92383F31F86FD7FD6DBFE532676 +:10C0E00069F73FA454BB7F23DBFF91EAB37CFE4892 +:10C0F000DCFF51E12CDBFF9052B67F131B3738BFBA +:10C100002D08FF93307F672FF39B52B3B4FB1F5A68 +:10C11000A6DDBF89CDDF5DFD2D9FDF82F39F13BEBE +:10C1200065FB1F5A86F31B4D6E27D08F7160649597 +:10C130008FCE4F1D6107490472A1F340393216FDBD +:10C14000E49784145CC73D918CDEBE8AA4F486F229 +:10C15000C6CBFC581F956C99D4EFE2B4BE7873B689 +:10C1600011E412B6537F65215FEA1D8D22D2377923 +:10C17000D2E41B4ED7DBD9287AA17EC793937D20CA +:10C18000FF2A4DE4F67C784F227E78FEF953A39F78 +:10C1900057EF4B5F2EAC958FB7A9F82DE847E59088 +:10C1A00091551698D7AEA91FA17E10A1FEC527D420 +:10C1B000CF2094248FCA6CBECFA8BF04F536EA2FD7 +:10C1C000413B21D5B85FE2757D308CAE3F9F283F63 +:10C1D00017EEF32664293A9EC4F8F7C81AC107F887 +:10C1E000B87D5914057E683D85DE384D9DEE0FFB08 +:10C1F00007AE127CCF0B38861BE033938F4760BDB0 +:10C20000B45E6067EF1CA2E8EF4F51B060D5408A82 +:10C210008BD038B3884B4EA4EFCF595A2843E8A2AD +:10C220005510062F01FA5920539711E0E78D276921 +:10C230009C38E87A6FB6B3F167BAE4636DAAF51477 +:10C24000C866573E5D4F41A188EB9F3543DBFED169 +:10C25000CE2897610C2D573D81F3CCC9D7B6DF545A +:10C26000A0ADCF756BEB54EFC9A0F76E29D13FA7F6 +:10C2700060A1FB9C17842B5D285DE7AD1C0EB756B3 +:10C28000C95E0D5EC16D55DA21A0E026B82F7C5F36 +:10C29000ECD9FFF665DA7AA1575B5FB04A373EA763 +:10C2A0009BE31CFF47803E687902E883C2F318A72E +:10C2B0008F905CD5D2C78DC16D30FA50F6715C623B +:10C2C0002838BE8ED1C7C2DAA8F0F45018A4079758 +:10C2D0009ABE147AB88DD3C3A79C1E8AD76AE96A1E +:10C2E0002EF1AD4CA2EFDFB26617E2E9A050C8E82C +:10C2F000E1970A3DB469E8C1CDE9418FBFDB383D24 +:10C30000DCF673460F7A7CB6717A685B7B4E262921 +:10C310003DF14AF1A0A9533CE8F06E37023D507C54 +:10C3200084A587F9C17DD38DD3FA02DED6035F9C45 +:10C330001EB03D05C04E104EF87E6ACFFE544E68CA +:10C34000EAC56BC3E3BFB2313BEE986A5DE5F557D2 +:10C35000C51D53F55B5C3753535FE49BABE95FBC92 +:10C36000B650D3BEB07691A67DC1AA3B35F542EF5B +:10C37000CF35FD6F5F56AD69BFB56AB5A6FD969224 +:10C38000C734F5B9EE5F6BFADF54B05ED33E27FFDA +:10C39000454DFBAC195B34F599AED734FD0D3B2F01 +:10C3A000BD1EE831EBA048C0FE38E67120DD1FF766 +:10C3B0008CC4F2A4C7897C71DA3301CB7D8DCD4F5B +:10C3C0005C49BB7C192888264C7F16911842F62CB4 +:10C3D0007757AFCA027D4E50EFFE717951B5771095 +:10C3E00095530607C2396FAD91F8C711228052E20A +:10C3F000F307C4507B561B6D8FEBBD3D6FAD14B67C +:10C400003DAB4D0A3B6EE5E38543ED61E233217EB2 +:10C410002603C13EEAE2F6B9BEBD4C20F9EAE78444 +:10C420002C47FE8F3130FD5C666472A26C6BFF1C82 +:10C430006283BA7F44D585E6ABA7CC9508F491AA70 +:10C44000E1E3E2B59769E43C81E86D3CD0D938CDB1 +:10C45000F3C575576ADEEBD825E2BA2B4086507DCE +:10C460003D8CE4070CA097FDCD43668D8675BACE52 +:10C470001A405E35C6A3FDD8E19911774C023CE61F +:10C480006379D25380E5718F1BCB639E122C8F781A +:10C49000AAB06CF32CC3F2338F17CB4F3CABB0FC7C +:10C4A000C8538BE561CF5A2C0F7A7C581EF0D461AB +:10C4B000F9BEA71ECB564F23969D1E17960ABF297D +:10C4C000F0D0D3DD49AEA74F03FD5D80CEE2C407B7 +:10C4D000AA570D0AD159E28A87ABBD59A171F3D68B +:10C4E0009A389D2468E86108F864E3815E4C9C5E9C +:10C4F000C2B7E7AD952FD89ED526871DBFF2F97F2D +:10C500000DBDCDF991F416A2A7813A7A4ABD183D26 +:10C510004D12C787E8698EC1CEF41FA7A787601F99 +:10C5200061FC8F6230EAC6ABEC3A57148B67F37349 +:10C53000076AD1B278369F7B051DAE15ED3FDF4807 +:10C54000C073F7C8BF8F80787DF761AA28937BDF1F +:10C550009F9E5E7A87BB0BFDA0221F55A2E37AB691 +:10C56000474432B84618C80C924EC8EAE1BF75CEAF +:10C570004FC3BA4462E17D9F736698F32802674F08 +:10C58000891787EB0AEB576360BCE3CFFC2313CA20 +:10C59000398614E6DF348B68DF13FF0B4E806F5053 +:10C5A0001F999C4910070F0C37DAD13EF059B4F0AF +:10C5B000F3D27A66087EAB298C5A51DFD72621FC4C +:10C5C000867D35A27F1FE07731397F3178CEF70D38 +:10C5D000F897C0F362F2F1627291B81C2F37D2FD66 +:10C5E00077ED1C9DFEA003E4E085E1AD9C5FE9D7FB +:10C5F000F3BC287D2F3AEE4A50E8B87508A1F388BD +:10C60000A21DC7EF6EB884C92FC5EEDB66F2F50533 +:10C61000AF6792B5E33DC5F94F19AFBBE5051BF810 +:10C620005B4B920CF66361F0A094E5F5C9768BDA6A +:10C63000FE6CD4D6BB6B8519F568273AA2678F06C6 +:10C640003D61B71F1B06723B094B659C254946FBA4 +:10C65000312AF74ED7A546333FCFC7E4C1E6189439 +:10C6600017A73D66ECFF53AFA7B77194F510D24002 +:10C670008E9A411ED3B6D4DEFBF74ACFD217463C82 +:10C68000F76D92BF02FBD04CFFFF0EFC0D22615DE7 +:10C6900019B7B25EF49A2E87E79B35F3D1F71CCA1F +:10C6A00019EB772917E21B891C57E896EA8B635C24 +:10C6B0009F2CAE8BB06BEDCF184DBDB2B1BF5D639B +:10C6C0008FC21F54FE922A4102FA29E3E4D325596E +:10C6D0005609747D6F429010E85660FDCACD6D46D4 +:10C6E000B703CE9519DE7A5B1FC5DF4C89927C8932 +:10C6F000B916CF614BEA2F9D0A7AE64CC38A0488AB +:10C700001B2C16BBEFC90FF3BE2C3179BFC827070E +:10C71000B4F63DA70F42C7559E635C94588EABEAB2 +:10C720001D06168FD18F9B00E3C65F1C3E159BF73D +:10C730004F073B410FA78AC6B34637CA45FA5F6623 +:10C74000084E0AFCDE14F313243A7E695D3BC62DC5 +:10C750004ECADE11BFBC80BCECB93F4BD2F128D52C +:10C76000BEBCA415E6993F814F441C377D4CE5F8CB +:10C77000A93FC904E410394F7B65624886FB3B063C +:10C7800062C80CF93BF31B16E701BC4F81BF47E5BC +:10C79000E61D24DF867820B599E0DF9C218619000C +:10C7A000A733E47DDB38151E7225238733958294E9 +:10C7B0001E4CC1F1DDFDC1EF3215D4B48A63E0B97E +:10C7C000A4F83FC2771847720B98B750C09E7B8978 +:10C7D000B91AE897FA511A3F8DFA519A3AF5A334EB +:10C7E000F522724302E425143D29139F8070D2B4D0 +:10C7F0008F92EC88C762525503F6D1AF79FC6DBEBB +:10C800009D4803E93ECB5F7D36B390EEE76A89C56C +:10C81000FD9473F545B10C0EA5253EA3CBD2737FD5 +:10C82000471BC6DD48253F8CC7CECF6F36621E053D +:10C83000B44A99DCF449E97DFF890DA22BC206FDBB +:10C84000E87365BDC9DF7FFFFAFD12F238EEA3B4CD +:10C850006E2601FAEB9127C0F723D7092E5F187EC9 +:10C860002AE474AFE8A73B017EE343F1ACFB74F527 +:10C87000D51CBE4AFD295DFB0F962FFD8846BEBC28 +:10C8800029BAEF93C6337902F017A400F2D70F1E2E +:10C890003FA9C7F8AB811F7FB2F10769F99E8EFFF0 +:10C8A000D44FBAFE613DD6BF3EDCFACB5F7D69BB9B +:10C8B00097EA97D23F3C652394DF4E49B5094E8AEB +:10C8C000F7B28D2B6D2E903B92D7067C71CA27CE86 +:10C8D00008470F87B87CA506884580782BFC49C798 +:10C8E0003FBDE9A1EBC09EF86AA36CC7386A9DC939 +:10C8F0006FA2F45CD1B0288F8CC17A3BAB3F70162D +:10C90000E8BFB2513EA2A6D3D2DF3D95007935945F +:10C9100052061A92A0F4A37F52B1E1F3E9606F547A +:10C920009200F2ABFE3D98FF9B58D48785C6E89EE7 +:10C93000ED18984980F7D9AFB2E1A1B3A20DFE6A14 +:10C94000C33890BE7F09F7375A246B3F3C27B98222 +:10C950005C01F2548107F1317F63C58BBF1AD34E5E +:10C96000D7D3B1E14F36410527C54FEAAE5FF09B03 +:10C97000D71DBDCBEF4ECA876ABB56D14F8E46EE50 +:10C980002735B1B24CF6DBAEA4F2A46CBDECF4D208 +:10C99000C7652FBDF0DB67207EFDA1C9399C8EBF26 +:10C9A000F8A53D0727D1FAE22D72BF3CB60D8B905A +:10C9B00010C24B25FD7F597A080FA5AFEC313A46DE +:10C9C000B3E7F7C686F0B178CB2E2319DD131EB975 +:10C9D000F5BB8C6D963078A96F9F0E76DF8A17BFF6 +:10C9E0003682BC3BB5532089C961E0B97E0FDA8538 +:10C9F0000027C423C753106FBAFE95142FA05F14ED +:10CA00003CE9DB37717902E339D2909E5F7E9DCE9F +:10CA10005FF291C909FB2F79F92E1BECE38454C511 +:10CA2000E8FAD9950920DF4A646F821D4BF6BCE411 +:10CA3000B9BB91DE8AF7DF9DC0E292AEFE06D495C7 +:10CA4000DEFEB0BF85EBE6E0FE8A881BE9AEE45966 +:10CA500031DF47CB2F2532634B18BEB8566672F2D2 +:10CA6000C4F35423D0FD9D50F4C0FB22D70377625A +:10CA7000DCF36EBE176A3162FD4B33C3D330D9C0CD +:10CA8000E52CD32B417ADDF000EA8BD3835D8970EE +:10CA9000BE5619D20FA837C4FDD312197E989EC175 +:10CAA000F7A89EC985E7D0BF5576458CD1BC877A5B +:10CAB00045997F299F9FAE3B12ECB51309E1FD8F8D +:10CAC0009FCB0ADF53BB42455F2AFE66FCBE613541 +:10CAD000E36F85DF7D336740FB170718FFC07BA03E +:10CAE00067E9BAFC89D8BE6BB680F2C044FCE1F8B5 +:10CAF0007A83CCF95ADBAED0095DB72444ABE805A4 +:10CB0000C68F45F8A35E2F7A92BEA7929795309F65 +:10CB1000ADE7780ADF1673FE9F216BF99FAC8BEFB0 +:10CB2000533E6599ECFBED33C0AF943FBD0EE0572B +:10CB3000391FF6FDB7CDCD076FA67CFAB77A854FC2 +:10CB4000B5F253CFA7255BEF26409F7A3EFDDBA0D1 +:10CB50002A12964FE9F3B07C3AA8ED7F547E2AF072 +:10CB6000AB02F84585E0A7C8C3DEE0A8978756D991 +:10CB700011561ED2DF0192D993FE14BA53E8ADF4D8 +:10CB8000F7E54341EE04E952A1BB205D2A74A7DF1B +:10CB9000AF167EFAF64932C175E5BF26A3FF5CD613 +:10CBA000C4F242E97B7B0766209C5CA8C648EDDEA8 +:10CBB00081FDD4759FAE5EAFEBEFD2D5F375FDDD91 +:10CBC000BA7A95A67F5963B39120FEFD9A7EE2B2B0 +:10CBD00067C8D1B870F4EA637E59C359A317E8C295 +:10CBE00012C0F7E5E5C40B7986811D22C605BA2877 +:10CBF0008C6B207EB139D9E7A5726365048B3F74D5 +:10CC0000D903B6585AAE8C61F540BCB106E49EF229 +:10CC10003C10C1E28A5DF9015B8CCA9F6A6F1251B8 +:10CC20006EB7F9C88C707E16D528C8476DA4B77644 +:10CC300076EE354DB40C590671A55AD10936F81D5A +:10CC4000D537D9E0DCA9AB29F5FA02FA7CE11F451A +:10CC50004C7BE98AB48D817511AF4BEAAFF26F4E10 +:10CC600012EFD359747F0B9A989F73C71A9D3D4258 +:10CC7000D6203D1559961A419E527FE288F6BC8611 +:10CC8000F145291FAF649DB65D799FD201FAF3A5E6 +:10CC90001BB4ED6EEE0F7FA0F0C9583296FBA32CAB +:10CCA0000EC3E5F23431EDFA028A8FAE1691986820 +:10CCB000BDBB49447C746F167C104F23DE78E4B70B +:10CCC0000A124079A8C0A903F8C9D8BBBCEAD8F6B3 +:10CCD00069E62F816EB67F3CE63F69D9B1FDC3118D +:10CCE0006F40FDD543433E263DFBE7EE8CC073FF0E +:10CCF000AE9D56A4F7AE1DEF0EF925D45F33396112 +:10CD00009D5D3BBF1E03F4D3B5DC5402F2AE6B3025 +:10CD10008BC7AED8F1F59836D4AFF733FD6164FE1A +:10CD20006177D33F3E13FA4149770576C3CE28E4B5 +:10CD3000A7CAD72330DFBB6BC7D7996ECB4FB79F3E +:10CD40000A9EE7D16525055B617D312C8FA1F28DAF +:10CD5000892F54D3F9CB1B761917D0F6DC37FF395E +:10CD600006E468D756660F75CA6DCF411E4394F12D +:10CD7000DC7299E2AB13988A3ACDBF3366E402DFE6 +:10CD8000F484CB3F313ED65778A4FCAF8187E06274 +:10CD9000F2CEEA330BB0EF6F3FFB18E39A26A44BB9 +:10CDA00065BF7FABAF467BE562FBCEFE7F6EDF8269 +:10CDB000BF2FFB76FF9BEFFB38D7BB7A3EE849E7F6 +:10CDC0003BEEC1FA4B5627AEB78FF4EE85FDC7FF99 +:10CDD000FBEEFF7BE37D2BC5BBEDE2FBFECDFF5AF7 +:10CDE000BCFFF1368E773B7ED7F3E63F717DDF5790 +:10CDF000CEBDF96F8EF7DEF6AFD8F5AD862A7B068D +:10CE00005D5F01A9B582613137BEDB92E1806CD7ED +:10CE100073FD308F0ECE4BC3F84D0123F30B4D90B5 +:10CE200047077EFB1C41890BA21F751DB71FAE1B58 +:10CE3000548276C875AE8799DD2055B566D3FEADB0 +:10CE4000390B9C987349D20FBBA13E7B32AF6BFD6F +:10CE5000C9F704E212A81D7F5DCE352D60D75EEFC5 +:10CE600012D1EEA525DABB1F0C99CE9E4FD0FA3D0C +:10CE700073DDDAFA4D05DAFA1C3EDE8D84ADFFC6AD +:10CE80007CC107715553F613F11067352D948990C5 +:10CE90000CF942552BC1BF9893AF7D7F1FF8C1E3BA +:10CEA0007F3C1C534D0A1C97205C48B6E8DC48FACE +:10CEB0000047BEEED6D9637D90CF4C242783E38D07 +:10CEC000E54E8C83737F5BE6EFCB9655ADC0CFB25A +:10CED000CECF56FCE5DEE04DB8FF8DE3A484E02F15 +:10CEE000BB44F4BF659DFFADE0E5FBE243C1E38FCA +:10CEF000C5CB973ABC0CB2B808F0ABCCFD85A916EF +:10CF000027AB0FCA2778DEC8FD05A99F8B78D342CF +:10CF100079DF8BCCE66C385F338F1430DE71FD1A0D +:10CF200011F583394DC075E54F90318FF873437E0D +:10CF300026E03B6FDC1515BF60CB70023C1771B863 +:10CF400017912AB45FC9F9EFBECBCA84730682F683 +:10CF5000EF221721D752BFAD284BF0475278154B1F +:10CF6000C41B9D0E716F811CD1C4BDB575F8FD4702 +:10CF700042689C8BF5EF4DBEFCD4E55FA93C3B328B +:10CF80008CFA411E9EBB4958DC56F1AF6F6F627040 +:10CF9000AC2C137C2948777E395F75EEF81CE7834B +:10CFA000BFDE3B0EE564F6A3A3A3D1EF7739D06FC4 +:10CFB000A8E47E43B7D7110D71AEEEA6547E3E9B1A +:10CFC0006B53CB55A5DCCFFDEEBF407E212DBBA61C +:10CFD0000AB522F8712480F15CEFD408B2314CFE1E +:10CFE000EBFF311938FD54611C007E6226E091FD93 +:10CFF0008AE9ABD1B12ABCADB9F69434A6271EE0BC +:10D000007744750EF963E10B7E3EC0757F44DBF417 +:10D01000FC30FBAD35B13856DE5BDFE2779C373450 +:10D0200025CB00971BA68A9A73FB5526EE978D2376 +:10D03000E3605D796F5D659B087869119DF0DD6641 +:10D0400065D359A33BCC79B01E9E303EC4D58FCA60 +:10D05000CE2280E7D1872308F8D1EFF273C634F8E7 +:10D060006E220D433A2E882BFE9AC3B5D364C77245 +:10D07000565EB61C4FE74D6BB08F85A3D401BC7FC5 +:10D08000271821E3218987BDA7F41B50C6FAB51BD9 +:10D09000ED15E1F63F3C82EDBF9838EF9920FCFB9F +:10D0A000E12DFB51AB3F07EC83A93CAED283AE0927 +:10D0B000F247F70CC107FA1BFC61ACE7B1EF84DF64 +:10D0C00055BEB3BE81E95985EEF570DECBE1ACCC3F +:10D0D0007FDCC4E2AF7FE2FCA5C05981AF7EBD4AD0 +:10D0E0007F2AAFA6A8E351D7378E7D19EC9B8A26FD +:10D0F000C16EA04355486D46E0C3CAC6C764386FC9 +:10D1000099EB60E312297F8C3A9FA0D3C4F23B9A3B +:10D11000D3AFBC0DE8E4DC1A13E842E2BAE3AC0D8D +:10D12000E4F0BB06E79FE17B6AEF7B22D9780179C7 +:10D13000F5B1A7CE3555528F9B8CEB9C55962D4360 +:10D14000F8EC96B25D72A28A9E3A4DB1D8AE3C1F01 +:10D1500050E64887E7743E5C87F7111381EF42D2AF +:10D16000EA5BF1FBD45BAA62181D96D4EF32623DF4 +:10D1700019FB2BF329F3E8F969769E36EF78416EB7 +:10D18000DB20804B9EC9BFD419864E1F332BE78E00 +:10D19000DF534FB828DD8EF9FF484F2C55F4441B60 +:10D1A000E6B92BEFCF35333E57E989C4707A62492F +:10D1B000B52311F0B064476A2230C9923F4E4B0844 +:10D1C000A7273EF0B073E343FCBBEEAED9544F5CEF +:10D1D000AED213B323904EF4EFE59A95738D8BE89E +:10D1E00009056FFFC3F2E603D01361F8FB46B3569F +:10D1F0004FDCD854887AE2C6D9A2E6FBAA6BCD17D9 +:10D20000D313D90973B12E3BA3C2D0CF07DCBF39EA +:10D21000C4F3FB611ED0176BCC76849B5E6FF42643 +:10D22000D7C7F655AEFF5F82B322D797CC61F743DD +:10D23000F4A44382F4BC642E95EB02D02393EB4B11 +:10D240006EE5714E9D9CCD07399BA196B3ECFD0A0E +:10D2500037D30B958DC9BF9A47DB6FAE959D66DAC4 +:10D26000FFE690DCCD54CBDD356609E1DC43EE967C +:10D2700030B97BAE691CDA4FBDEDEF532E6FA93C80 +:10D280001BE60C431F05F3A234DFDF1D1DFB76DA1E +:10D290002BC02FEF8A787EFB39B703F68D7D3B03D9 +:10D2A000ECE9537C3DDBB8FCEBF4F85C53A91CC8FB +:10D2B000BD83D9D3E59B45845F4503E3FF8A619134 +:10D2C0003E07AD4F4FFF16CF6117EF60E7B0740711 +:10D2D00079D92AFC2F7EB7AD06CE0516AF17F01C04 +:10D2E00019BE5F0078167378163917E3394AF1DAF8 +:10D2F000F0E73FE5BCDFA2A6F5180F5FE4D3F62BFD +:10D300001F76F529F047F24C0C0F79AF08BEF5C92E +:10D3100090CFA0EBE75C8DE747E5F5DAE707F97E0C +:10D32000178AFEB457E8FBE4CFCCBFD3C3FBA01EE3 +:10D330002E253F122EFB295C32FEF570E90D0ED42E +:10D34000BEC7F3013D3C0E2B72259D64001F7E6E0F +:10D3500070A15CF1BE43E142E7BBE3B1E19AFB405F +:10D360008E73B8BC6B70D7F4877E1502F62B5EB750 +:10D37000654F02ADCFAB2763E178A178AD560F07BB +:10D38000F57E8303F5FABCAA2D02E4C72EE4DFFB89 +:10D3900095F81EC37B546E5D46F53CEDBF20DDE481 +:10D3A0008673F0FD1101949B0ADDC64730FB258E84 +:10D3B000CBA1A3030253513F350A76E4477F04D340 +:10D3C00057144F70BF4BF3C4AFA773BCB0B8522310 +:10D3D000C36325C51BF0F3F4265EAF6376E02D4AE8 +:10D3E000BD5EF0390490ABBB64765F8C40E2048E86 +:10D3F00004957E84F3D5EC04159E77B433FADF28C8 +:10D4000038F1818FFEF743F0DC2BDD333BA6AFF420 +:10D41000AEC0293E428BE7FD11AD79E3FAC1F99B1D +:10D42000E0C47B739A62F09CE8582DBBFF2595BF42 +:10D43000A7E70BF03BD4F7D1CC8485437EF38C086F +:10D44000CC0FC57953985DA6964FFA7B80BE6FFED0 +:10D45000512569457B2C94C7E87EDE04E3CD10346A +:10D46000F94E1009033AFF09C6BFD57C81F14992F4 +:10D470001DF396EFB22BCFEDECBB2C5E6F1E9C79AB +:10D48000681E85EFB955A2135CA89B0C8E835920AA +:10D490006F1E9409F0CBB97DB28BE98128D43B850E +:10D4A000EF1EC5EFD90A590E1A29BC8FE997A37C44 +:10D4B0003D1F51BDED82580AA91F0FF7E0CC76EE53 +:10D4C0009AE680784BC6FE9570CE392BD77EF02039 +:10D4D000E07335BB07E9C8AA5CF4D3EEBA53407ECB +:10D4E0003B4CF106EFCF999D7CF0209DF7D655F18E +:10D4F000786E39CF157F239C63CEDB273A1DB4DFCE +:10D5000082EBAD1638C7BC66A448DC2AF8DC4A5A60 +:10D5100031BE33AFEACE39B0EE12AA0FC56428F798 +:10D520004F4B84FA3A01DFAFF4BA8DF0BD66EBDA07 +:10D53000B3C60C3A7F11ED0760AF5CC7FA556E10A9 +:10D540009C90FA5DD4F418CACBA20D025E34D34A83 +:10D55000ED5F331BD767A6E3B6AEA3EFD37A31BC3A +:10D560000FE36E88B911CE272BE93AF1FD09D57882 +:10D570002E5D44DFA3CDA475C39D38DEA275028164 +:10D58000EF034B26243F3201C6DB273BA1FDD0AE83 +:10D590005F1B61DDB7D1F9FAD3F117886DD3A03FD6 +:10D5A000F9A560C7FB87EA4660DCAD0B360C2F544B +:10D5B0000DC73AE6133B100C923A1F654704FB4E29 +:10D5C000B86859750DECABCD1B9F6C40BA3A6B0433 +:10D5D0003D7E8CC2DB4D873C6A64792ECDDEA3C6CE +:10D5E00036951CFD282215DFBFA3311BF3261692AA +:10D5F0007CCC9B7057337BA47D65840FE26AEDB2CF +:10D600007D083C6F5E69C2E79D2F31FDD339B80DAF +:10D61000E3DB27D6C904BE5F5CB12EF569C0E389A0 +:10D62000CD32D29BF82CCB1B287E89C5C99AD7B1A5 +:10D63000714F2C35B27BB5A09DD68B5F54F20AB4E6 +:10D6400072ACC8518A724A2F97F4726BD193D54647 +:10D6500020D91EF26AE9749457A554EF00A1F59001 +:10D6600057836A306EAA975795C4A2C8A974885F79 +:10D6700016960FBE6D2DD0F1ADEC838156FF6B5F1A +:10D680003E057AB7CC4AE04985647F5A6074418090 +:10D690005FE6356DF912F8A0645E04DEC7751CF014 +:10D6A000007CB3260ECFAF8B7C85086F252FB77813 +:10D6B000AD96CE95F8E35CB7485C6AFD5512455CC3 +:10D6C000AA7E87EEA3F44AE7B9BD51F081A83C7465 +:10D6D0005FFBDEBB33B06EC7752DE3F6C11A2BD2EC +:10D6E000F3A19F9F5D09F47ADBBD02017B9D78DD8C +:10D6F00035A00F2BD60A0E880F17DFCBDE2FA6EF33 +:10D70000C3BA0FFD9AD115A56F07D07FC5BAC7F66A +:10D7100062FF0D8203C63FB4BE10ED8912AF48B060 +:10D720007D433BFA0F544F619E59B3574C00FAAFFB +:10D73000B8DF64075349A123852EDBF97D08C4ECCB +:10D740001C338BBEB70A1615DF931EC50221A84FE6 +:10D75000814E2ABD8CCEDA5F929D403617A74BF6DC +:10D760001DFC09AE5FC567E74C87EF748AA97E048C +:10D770003A6D5E976B043BE2844FC0FC8A9E74490D +:10D780002C6A3B4AA1CB670526AF7BD0A38E0E7BCC +:10D79000D01DA74B85FE2851A35F59B64F26F0FD3B +:10D7A000BD9E1EDD72FD8D90FF51F832DD0F5D6F65 +:10D7B0006ECDCFD15E57E048EB09502F9258DE8FE7 +:10D7C000C20FE512CB0FFBDEEBD3CDBF2982E7877B +:10D7D000013F882C7FC94FE77D7BF30B982F79663B +:10D7E00053FB7568DFBC41E900E0BFD94AFCE87F24 +:10D7F000F8500E953688986F4D247FE62C95DFAE55 +:10D80000E4BF2CFE8315E15DBAD5E4CBA3EF976EA0 +:10D810003F3A06F311960730BFC7BB4960E71FDEEA +:10D82000B631F0FD50A9C4F270F476C1F04816E7A5 +:10D83000EA782DAA00EC36A18EDDB3575A7F936C9F +:10D8400052C5750745CA382FED87E7635E8A67B80A +:10D850001F01D6A7BEDF4DC9BFE97891D15F69A38B +:10D860008CF65C69DD964EC8C32C3D6C423FB7B266 +:10D87000EEAC11FCD8DC3FBC84F7F355368A9A3CF9 +:10D88000BC1EF96F75A2DF04F95B0DE5787E43EBF2 +:10D89000ED58AF0F9F077AB13CADC57FD8B1DD4BD6 +:10D8A00041B8F895DFD9F0BEBED68D36FCEEA9EEB4 +:10D8B000C2F9A73DF2DDEA575F30DFED34FC4109E4 +:10D8C000EBBA485DBE601D936B747D99F961E2C44B +:10D8D000417BEBA52F9F837CEC8EAD7F7B0ED65BCF +:10D8E000F65FE79E83BC1AB233C20EF648E5A60F78 +:10D8F000309F5579AF2492D97F9D2FFE0EF3803B48 +:10D900003F343961B4CE1D278680BDD1B9E5DB0433 +:10D91000C8EF5DBA631AC673966ECB4D2461E205FB +:10D920004A0974EBEB431EB21E5FCD0DCD98FF7319 +:10D9300086E21BE443307FB1BE9CE5833A78DEE2A9 +:10D94000E6F0F9DE3DF2141B665D3F19E46203B3B5 +:10D950000B2E9AAF7880E2F1F23EE06FF36A2E4F21 +:10D96000C2E3EF0CFC41F15413A9CD57FCB261E1C5 +:10D970006F9E81B686B85EF315FD7D809B924F3E0B +:10D980002BD2F55824F0CDD6DF637E28E02DCF01D1 +:10D99000F2F9CB2110173E290730FE10D861C2EFF3 +:10D9A0002C4B771C42FEE9DCB61FF3B509CFEBEE3A +:10D9B00024C11FCBC3E5B19ECA0D5696E7C8E10F3F +:10D9C00079900E1B3EE7F98E8C8E953CC8DEF21FD7 +:10D9D0005B2253F87D2A2C4FB37CC3C73CAF308405 +:10D9E0002F6102E0A9FD8279A50A1CEC00872BD4E7 +:10D9F000F9BCE1F34C8379DF1C5F803F90D3C17C9D +:10DA00005D5A1F04F99B3EE11009230F3AD7B33C3E +:10DA1000E04E39FCF7CC4A7E6FB39E4F7D7DCBEB59 +:10DA2000BDD8FABF2F7C1A221D38AE1E4E1DE7C38B +:10DA3000CBF1E39CEF7FF0F7216582FEFB93CF8172 +:10DA40001ECB1BDA8D789F89E23FF1FD76F0785A84 +:10DA5000C72611F33E6BEA9B518EEBE545053F2748 +:10DA6000D1AFF71BBEDE8A46A6273AB65A7D163AD4 +:10DA70004EC75BAF213D576C6EC7BCD3BD75AF18A9 +:10DA8000DB54E7CBA0277CAAF577BCBC6B0CCA6D36 +:10DA90007EBF987E1E63149BA7B229FC3C959BCF4A +:10DAA0006AE659ECAD37DA2D179FEFB4E4BA09C630 +:10DAB0003BDDCAECA5D3F5E20C5F98F94F71BD4987 +:10DAC000482D3B0FA5FA12EF59B3B27BD5445B2426 +:10DAD000DA5F4BAD130E47F783D288792F2BAA79E3 +:10DAE0009ECC7DCE24C0F70AEBD504D6BB12E0ABAA +:10DAF000F2E365BB9B80DD2627E567A8CF5994F547 +:10DB00001BFB19884F85FFA5D61989E07F12C93BF9 +:10DB100008D6715DCAD712E8BF560F8BDF93F34763 +:10DB200087C1F356C9BE278E8EDB3A557042E8B5E1 +:10DB300027DDFB347186992EED7DB1F80D1CDD5F7C +:10DB4000B7D380F6A0D5E0B7D32EC41AD19A840EED +:10DB5000AC8338A404FC1402F3211EF49867C1FDC1 +:10DB6000C83642CD53E8E79434F79F444F9074F79A +:10DB7000A19003C328BD5A38BD2A71392BFB9B8E57 +:10DB8000DB86F7ACC4A4916A20DF355637DA0D4F37 +:10DB9000F0FB69E86F24E441C49248A7FAFE263AF4 +:10DBA000AFE6FB383AAFA61EE3D2D6E36648C7C25B +:10DBB000E99738BE8EE9A205E11033CDA0F86B7964 +:10DBC000C31342EB8E89274E3FB45F6BC1EF012830 +:10DBD0007B79D5FBB058B4EBA6EBD3C889E8B43653 +:10DBE000AF81AD53F3DC4E1C02EEDFA57D4ED7AB0B +:10DBF000A917467179271109E49DC5DC4A38FCBB99 +:10DC000035F0BE5FDA373801F043B85FED2590CFCD +:10DC100012CDF741E7D7F4B7437480CDAF1D870C21 +:10DC2000B2ABBF43BD9CEBBF5196FC2551949E32D5 +:10DC30008756616276561249C3EFA59BFAA17C4ACA +:10DC40005996837927422DA3AB616B08F2CDB000C2 +:10DC5000CF9BBA3F12ED5193997823D2E17B36E204 +:10DC600095D361161FCF43702C37D0A1A45594D6FD +:10DC7000E87B4D811CC3428A847A68A2E35746B987 +:10DC8000AAA3289FD6CC742719C6C2F6DE5EB93B7C +:10DC90000BB9F65288081AAAF7EE69198C2204EF1C +:10DCA000F120DEBD7B80C66B953A15ECF09D7F6D53 +:10DCB00064B0EE3253795F9BC2EA8F3EB47725DCC5 +:10DCC00037936ECF7F14F649CCF65178DEE58FD5C9 +:10DCD000DCF3DD9B7E51D63972833F17EE05BE3AE9 +:10DCE000C0EEF51D6E0D7E778F7A78A345A9FBD126 +:10DCF0008FC86FD88F72ADBC7E3FB61BA04ECBA134 +:10DD000071FEDC81749F2F471D9A9674291DAFA167 +:10DD100030093ED97F35EAD01EF8EE3004878F57A0 +:10DD2000EE1E148283B4FCC33D2D93D570F8700FA2 +:10DD3000D8217D85C3AB0F7D8870E8EBBE295D6C73 +:10DD400007BC5C936DC0FBD6AE386CC1F80AFD45CC +:10DD5000A03EE2E3ACEFE5BB6CC51FA1E3EC54D3FE +:10DD600097F29E4257BDD14D2AB18F62F76C6AE996 +:10DD7000A72BCAF536ACAB25CA758F351EF78FF7C2 +:10DD8000005CE3763BA78E0BD135B1B8C7C1FDEE81 +:10DD9000A32CF35BA354F2F29AEC25620AC4C98166 +:10DDA00017E243FB895FE68D1841F719EF3260DE19 +:10DDB000FC288BFB20CC632B08F82177EC0AE21EB1 +:10DDC000278821BE50E6ABD9C1FCF59A42836F3952 +:10DDD0003BEF1560BC107DB4E9E823C0E8A3B11D9A +:10DDE000E9A3A2A99DD14763754E64063B37033F63 +:10DDF000BF9604C602DE3BA2BE9A2651FA1F1A1530 +:10DE0000A801BA91BDE7A6E55D8A703D1D163F7C6D +:10DE10007DCABE7AC36F6D4BCA4369E04FEE33E0F3 +:10DE200079970237A55F8C85E5C5B658DD5F03FCA1 +:10DE30002A27B4ED85ED6F6D791FF3366CFB6ED834 +:10DE400005EFDB66530C3942F3D6EE5B8EF767D7EE +:10DE500006D87DD8D124E005BDDE3B3C18FF04E1A7 +:10DE600001764F1AC0A31DF96513FF5E2CAB5170EC +:10DE7000819E1F1AC5EE0D89B4B0F3EB211611D7A0 +:10DE800039C4C2CE59E2F7BD2582BF9575BF01FBEB +:10DE9000C74399A6DEFFFDBCBFA489AF2BF854E8A9 +:10DEA000894AD228B87FE44C8C3BD1A2A19FD8A844 +:10DEB00014D578CA7B8F7888F30EAA47AFD83DFF78 +:10DEC0002ED0AB947EBE00FC04FB8D9623006E4AE0 +:10DED0007FA0CF70F8A1EF0D87F9601EB017B6ECE8 +:10DEE0005E22E23D1A7DC46B26DC1B49FB6746912E +:10DEF000AAADF4FDCC685A423D8ED713797D202B14 +:10DF0000533F711A04FA7C3D8FBB4EB6F0FC31C909 +:10DF10003EEA86D15067765C565224EA05856FE169 +:10DF20000E0838B796F8F9754A20C5007853F858A6 +:10DF30000A18FC56AAB452248701F218DEF1D07DEB +:10DF40004BBDCB9DAB2F65DF71EA9FCFE4EBF9C1F1 +:10DF5000F6F5173DBEEF9E09F02D37B73D7203ADC4 +:10DF6000575C7A0ECF079747555C79A17B2FF4EB6E +:10DF70007FE7FCDB5140874DDF98C27E0F55C3E140 +:10DF8000D6E229C0F732F9BD2E2451C93356E5B186 +:10DF9000421BB7CB109529F81CEDACFF401108F8D7 +:10DFA000F44AB1F07E54329E1F4ED1E5ADFE879FFC +:10DFB000C5F932C130002571C92836CF37CC4E3271 +:10DFC000D3FFE09C691A3F177B4772AFB0D2F1DEF6 +:10DFD00021EC7C3533AEAA19EAC4C4C6CF26DAFBDD +:10DFE0000A32136BA7C6C2B8D1C918DFCA35EBDA3B +:10DFF00053BD12C869929A8C7989D388CA3E637AD4 +:10E0000003EDEE08BA2E90E3D78C2C744EE5EDE7C5 +:10E01000E8FF434DE4F6992A7FE32AC75CE7548D75 +:10E02000FD528BF701FDE99FE2EDE1F22C3EE3FCAE +:10E03000DFE2C977C2F9B31E9E390EE17EABA3279A +:10E04000DCF570D4C35D81AB1E8ED99F38A7C68620 +:10E0500081931E2ED348ED48D0630ADCF57079C752 +:10E06000CCE8E29D3413DEABF88EC4E0F80E352325 +:10E07000A11EA49B6811EF01CE8CE2F53747B0BA20 +:10E0800082EFA864C4B71EAE7A3866C6F1F7E358CB +:10E09000FFBD002F09E502E247A19BCCD4AADD31E8 +:10E0A0002A7A50ECEB691C2ED4BE46FB3937DE8A47 +:10E0B0007126B0AFA72584E0965BCED6953BDCF207 +:10E0C0003CF8A9F475BCBF720AE13FFF143C2FCAAB +:10E0D000E45505CE53BED1DAC9D39AA69F8238C380 +:10E0E0005093FB7EA0CF801083E77514EE477470C9 +:10E0F000D7BE67D7D6F570F803FC31B127BC143A08 +:10E10000FBC0C2E34E03C820B097C7BC96110DF206 +:10E110009B34C5868D4B5C71383F380EA757A4637E +:10E1200081B883CFEDA93F428EEDA35A5225C73661 +:10E130008BEED396F89E724CC1D3648E87C9C4BB54 +:10E140000BE24B9389F445D01F480EEDBF5BD9E736 +:10E15000403210F67983C5C1E43FDF6770DFD4BC7D +:10E1600084F9B3F8FC59660B7E5F4302524710CE28 +:10E170002978DF91D7181B5A8792BF4F86541166B2 +:10E18000CFCDC37BAE295CC87751A17598AC828492 +:10E19000F7FDF0759CA9337B218FAD5B7447819DA2 +:10E1A000D721EC1B83FB93FC2340FFE9DBCF35EE4B +:10E1B000AE8076DAAF08FBF1F52F1659FC21B0C31B +:10E1C000E47B3EB9773B95B235EA09857EB3E0FB47 +:10E1D000D4CB81DEFD0361DD5340D5D172E759F622 +:10E1E0001D437663BA04F3ECE96679FF39C42581EF +:10E1F0007DABA7DFEF4BA7A178456008F8298A5DC2 +:10E2000036D5EA1E69A5CF57F3EF669BCE8E18056B +:10E2100078F9C1F474404B4F0A1D51BA1A0FF0EC53 +:10E22000CAF8FC6930C7DFCD3897007A51B1DF43B7 +:10E23000768A6B02ACA7373B7E89D53DC57A013B18 +:10E240005EB1672EE68790DDD441A674741BC7CB00 +:10E250003C73ABCCEECD0F60FEFDEA48E55E3B477C +:10E2600024D891B7AD4ED95407E786D52CFE7E6BE6 +:10E2700095ACF183DD90DD86EFB3FB666F5FA66D35 +:10E28000FF4C60FE7EA157FB9C581234F7EDF69CC4 +:10E29000D7E035C0BCC323313F413FAF7E7FFA7921 +:10E2A000F5F3ADE67ED56A63ED48A7CA2E596065E1 +:10E2B000F650F7AAC7EBE0CABADEE0E7360F48939C +:10E2C00054F7ABB5AD8E2C08776F8C329E02EF7988 +:10E2D000C4CFE20055F2DFC3DD839BE566F181DE4A +:10E2E000E61D16988A76A0E149BF08F6FCB0004109 +:10E2F000FB3B2BE0322CD0F801CC4FEEE107C0BD48 +:10E3000026B45ED6B08BF901F5D5E84F94517F0263 +:10E31000F4CC7A389B1EC0179486FE41D0DF85FC72 +:10E32000A92CB8CF92FBC312A597D45AD67FA3F5D8 +:10E330005DE36A09FC5577924C2963E3C3EFD798F4 +:10E34000A95F55934C2208F5AB5E78F8FDE96BC0E8 +:10E350005F8E7509707F28ADD758FAF7DDBFDEF8FC +:10E36000F0FE1AB86F94FA65EBAC2A7FB737FE78E7 +:10E37000048C910BF047BA3D7F23F0A112AF688A5D +:10E38000E07C1F11A4BB6880974227572F9B8F7E8C +:10E3900045C425E787409E5816C7FF162B8FC346F6 +:10E3A000B1F79F12DD5B90BFDF3A3F02E2CBEF8C0B +:10E3B0003C8AFE5C9395C5E7F7794AD07E52F0B966 +:10E3C000CB2A703FC93F10F8EDDAF1CD71E09764C8 +:10E3D000C902DE43DA24FB9E4CCF007934DBBE82D7 +:10E3E0006E296BA211BF136B8AF00FBC5B65A7355A +:10E3F000F1FB4C9BCEEE1DA8CE631E66CDDD6545C0 +:10E40000FAF38B307E56C6EEC3A0EF7BD32F21FDEF +:10E41000E112407F90F3FB13F0FCA8618F0DE24204 +:10E420001DFC7E82330DCD09F36959BEE52F36F010 +:10E43000D7DEE7703823B5E23D4A65DB44BCFF8395 +:10E44000CE9B700BC4A71B1664B2EFF7D877678A10 +:10E45000FE4CFF67F3C07C1634C4EFC8147B72B265 +:10E46000D9EB83F535558B182F9EACBB376C0ABFA3 +:10E47000374C6F5F9EB42A71E904CC875A6A67F300 +:10E48000F4C64F59DFC4129F8ADFB224BF08EBCF16 +:10E49000FA2681C01597675A529EC8033F9EC8CE80 +:10E4A000E130AC4476A3FDCACF9FE86F37DC43BEB2 +:10E4B0009357DE6C3837EB4A2466FBFD970960778B +:10E4C000B9FBB1E022D3078A7D37E51B6D7C556F20 +:10E4D000E7E6348DBD7F204178B37FA722C0EE559B +:10E4E000EB61FF06A687B57B09790CE190BE2DF59F +:10E4F0001AB84729FD8F063BCCDB027C110FF83C94 +:10E5000087F7FC5410FF8DD05ED120DAFDB07E92EB +:10E510007119F09562372870693CDF6C1E43D79102 +:10E5200075D6605F4E877833F005FACFE3FEBC2FD7 +:10E530000EF4575340C27382ACB3BBA316A8E46079 +:10E54000D379033E7FF3FC5BDAE781D8CBE0BD2DC6 +:10E5500006E617EFDEFBF728904B6F9EEFC6F182C1 +:10E5600076434FBB18E1916B15837167B55D4CC461 +:10E57000AC0390B7352D9AAA31A177BB37FB137244 +:10E58000BF95F4B41F72C01E11C3D8111CCE743EC7 +:10E5900009F8486F575C6EE3F1E6C1241DEEA36CE9 +:10E5A0003C1FB718BF1F6E8AB22F477DCCECA5AEBB +:10E5B000DDA71FBF069EEF13D9FD11E745E4A7B7FE +:10E5C000762E1EDAA6E25B2A39114F5FF53FDBF9A2 +:10E5D00006EDFFD59E481647979C97A9BF7708F58B +:10E5E000F77178F907B0F338EF00B8D7E907DB2FF8 +:10E5F0001D3DFCFA3C1BDAC381E9A01E46AC6B371B +:10E6000002FE5BACF9D7D990DFEAA3002E5E92330D +:10E61000904C80F37A92037415A82676F027B6B54D +:10E62000180C80978C8DC998A7B3899F572EAAAFD5 +:10E630003526ABE862113FEF3A297B87C4AA9E1FBB +:10E64000B031F972724FE96F304FE34313191EC6B0 +:10E65000DE6CB0317DFB8AD17BCD66E877C480DF8C +:10E660000DEDDEFBFA5EB8CF78D161C75888FF3D6B +:10E67000627360BFC67D9B6A20CFB7F113D052543E +:10E68000AF6C28140D74DE378883C5EF0E18D01FC9 +:10E690000FC63D892B0EF6F9105FCF1B2D06CDF965 +:10E6A000D81BFCDEDD7B6D32B62FB18988C7AD2D5E +:10E6B0003971A0375AACEEBB6DA02F8EB5D5C01204 +:10E6C00094789F62AF4D3CB0F59AD1F4CF891D0686 +:10E6D0003BA0DB71E07911F6EB3849488C407AD8E1 +:10E6E0006F743C8F7ABC373AD878741D6F01BF2A9B +:10E6F000F0A79AFFA1345A7FA3558A85FC2E05FE08 +:10E70000CA3E94F91DF5C4B5DE82ACE4DA7A81B86C +:10E71000B3925F3ACE4E947F2F01E9D268733D6A7F +:10E7200063F60EDAD727F730BBE815AE474952E15A +:10E7300050809F82A77A1B8B332AEBE96DFEDFDBCB +:10E74000989E54CAEF4BD79B648717E9661BCB0F83 +:10E750007778FDE654C8236B4CC57FCF499567FB9E +:10E760007BA4E793DA7B051BDB0C06F80EAC628713 +:10E770001083E66D1FEDEB209D49F5487F8D8709DD +:10E78000F27169DD9D2CEE48E50DBF7F0DCFD18183 +:10E790007FF8797A7F8196139BD6AF1888F0F5DBE6 +:10E7A00080AF4270A27C036555AD11E875D1525619 +:10E7B00016F373E9456BDDC89F45EB587EE11E5BA0 +:10E7C00032AEE70CA75762881C00F9272E0E7F6532 +:10E7D000DD799C6E4F353CD10CF352FAFA13E0739D +:10E7E00052E3634FC372157A3DB541C6714A22B5F3 +:10E7F000E7F6AD7CBC6D0718BD4FDC20E7C0FD5FC0 +:10E8000013BDC40E71EC37366C14417EBF01F49C0D +:10E81000CCF81CF4EDC93D0F46FD02F45CBB814011 +:10E82000BCFC152329D9A2E28BDDEB5FD5F06F6923 +:10E830005DF53518976F8B1540CE2B7CABC0FD1561 +:10E84000A3F32AE4FFEB74FC3F95BD2F473BB0DFF9 +:10E85000139CFF9F9841F99F3E8AD91023C038AF7F +:10E8600018C3DF07F7F50FA4BFA05C6DEB2157BFFE +:10E870006672B5CD964AE7AFB8B61BE30CC1F57129 +:10E88000BA7962AA4237C902C0BF96627018C08BBB +:10E89000C215E899DACDB7DF90865CD922E1390F4D +:10E8A0003F47E2F91FCA77020ABF86E499C2B76EF2 +:10E8B0007334D8D553AB56805D1F97E745FA3C2596 +:10E8C000B887C6527D760AF8388C3C38C1E5C75700 +:10E8D000B2FB62F7EE0F007A2EA11E22EC87AC137A +:10E8E000EC8017A5DDB18EDDC33A3C5AD09CBF2B1E +:10E8F000F51F0CEF408FFB418747637C3A60843CF7 +:10E90000D5113EA6C7889083FC400C570F003E5B94 +:10E9100044F5D7CD2AFD754AAE453A55E0707934B5 +:10E92000935F5FC5B07DFF95D38515E285AA732FF0 +:10E93000EA904802E36751607C2EC2F8A7F64CBA11 +:10E940000AE9FDDAF0F46E07FF2A16FE3DA7F54846 +:10E950009F3133ECF81DCB1392332246631FF9B07D +:10E96000DCBDF157E8D701FD02BFF746FF2540FFA8 +:10E97000240CDDFB28DDABF0A7D001A58B6BA255E5 +:10E98000F2414F17CA79A302975774E7954F47335F +:10E9900079B080978E5EF26694FDFC603C9FEC81BE +:10E9A000E7F90CCF21BE027C2BF2E16717E1AF3D06 +:10E9B000D1766CAFF97401E6A9D4F273AB7A3E9FBD +:10E9C000B2EEA5D182E67C4B7FEE34CAE2BE2B5A72 +:10E9D000773EEA480BD1C7346ECF2ED968C273FF99 +:10E9E0002DD00278DBCDFEBD6CE53DBB440D4F0A5A +:10E9F000EA15D14C8E2BF4E1586624C3A8FFF255DA +:10EA000072E16EC8FFF959AB376F34DDC716A377D3 +:10EA1000F6B5E80738AF82F1AFCA33D8211F24C654 +:10EA2000651720DE81240A7CB88FCD332ED5791965 +:10EA3000FAC90EE73890070F737C29F855E0D09B90 +:10EA40009EEB0DAF7B387CE279BB5E8E1473FE9E2D +:10EA5000C2FB5D5C8E7845E0271B712F1761FD5965 +:10EA60004CFE05E54816C173C9977572E4E59F5ED3 +:10EA70008EBCAC912313DAC2CA11FA0BCBFFF11B87 +:10EA800016A21D4B0E87B7637746333D1C0FFA93D2 +:10EA9000F68BF7B2F3DE8739DD528AC4BCC9DA0DD2 +:10EAA00026CC1357E4906D36C9817FAFD906FA168C +:10EAB0007ACD761F9E0CE7C54946079C5F9F92035F +:10EAC00088F753D401AF45FAC8C7FBC7C3C82302B0 +:10EAD000F112EF4783D0EF9C2636219F2C994650A8 +:10EAE0007FEEDE7805D255495E8A00745B5A1723A3 +:10EAF000407BEC54BB01E494B28F2B9619C8B071E3 +:10EB0000C80707D472E40A6F15FEBBCD43E3DC49A6 +:10EB1000720C21471F3DFB3375BCA88DD6D5F12261 +:10EB20005A7FE0FBC48B8E46071E8078D13F6CAEC7 +:10EB30007698779425FF28EAB7C42A91A8E4D6C529 +:10EB4000ECB71F4A2F953C2E455AA9344ED0C481AC +:10EB50006FAB73601CF82B584FC580E34FC37078C0 +:10EB6000AF46587B9BADA31F970BE41382F8E89741 +:10EB70005F2542FC45913B067BACE22F0B9097A1B1 +:10EB8000F0DB7F031C7DB5D7008000000000000093 +:10EB90001F8B08000000000000FFCD7D097894D590 +:10EBA000D5F07DE79D2DCB2493C9427626ECBB039F +:10EBB00009ABB14E086090040710448D380990B03D +:10EBC000640391D2D6968120068A182BB554B10ED3 +:10EBD00014FA51451BB61ADBA013401A143456AD73 +:10EBE000D8AFA561911D8980FDD38AE53BE7DC7B29 +:10EBF00033F34E26026A9FE70F0FCFCD5DDE7BCF4A +:10EC00003DFB3D77492D63793B22199B90B350ED35 +:10EC100006A9C9CC3C161B831F2F6343793E7A0893 +:10EC2000E659986B20636BF27579DE018C5DC79FA6 +:10EC30003BFD69A2153E8E676CFED630EB4933B5BD +:10EC400067D7E17F795D8C265F599F643DD9C79F67 +:10EC50009F8FBF24C1FF334CCF12182B63E2A7E173 +:10EC6000CBDFFF7018B4C7DF55C6DE54DD89568090 +:10EC7000A7DCDC12D5DDCED833F9C713DC91D45232 +:10EC800087DF3D22C67871B9E3BDDE718C79DE5530 +:10EC9000D916C80F36193D4A34FCE264766B82E817 +:10ECA0000F7E9406C5671904F97F43552C6397FEC0 +:10ECB000ADA3F4C59FB8F232E0FB8A7A9D6339B404 +:10ECC000AB685018CB62CCD19579CD198CD58547DE +:10ECD0000D62D05FCEBE48A701CA2F2966AF298337 +:10ECE000D100088741C23FA2357D1BD4573798D841 +:10ECF0006AC85ECA61AC19E1D53BA2D9003F7E0764 +:10ED00001D7EA60FCC00CA6B1D2E0B639BC278FF25 +:10ED10009BC2647B7B3483B4DB92D1EC04C0A7D765 +:10ED200033160DF481C48369F6926E03F499301F93 +:10ED30003DF318804ED9AD3E15F1D2ADD5AE6391FD +:10ED4000FE71F4AD8CE6DB4D6FD73960FC3A81F78C +:10ED50009D4D3B543DE073D898DA6A15D2D228F71E +:10ED600058C4F3A8ECAA6A2C8FCDF7A86E689FA5AB +:10ED700054EDB3005ED878E6D802E5CC07838F84E3 +:10ED8000FA16D61805D998232DCE28281F75C6D96E +:10ED90003800E61DED620AF6C7D8321ABF5FA4CB71 +:10EDA00085FDB238A75200FD0CFB0723BCC87E7658 +:10EDB000368D56EC006F5CF318C51EC05F304DE217 +:10EDC000ABF5CCFE53ECD77348E740BADAEB987357 +:10EDD00023B4EFFA72BF312CCADFBED2AAD078B703 +:10EDE000BBDDB94646F379D80ADF8F9CEEDD6700BC +:10EDF0007886CFF1EC33DA03E63397517F292D1E65 +:10EE00009A47D211770EA68B2D31D4CFA833BEC628 +:10EE100001D0AE4B15CC07CAD39A3F5410AF6955F9 +:10EE2000CD0AD27167D35E8237B5793F4F8111EA3F +:10EE300020DD01725517308FC5161DCD63B145A178 +:10EE400074E5C599892EA87FC4EA5E6C19EA9FC74C +:10EE5000CA1C776215F4BFBEA95BFB7C7B02BCB702 +:10EE6000C1678827D9DF72AB91FA69B2B87F84F3A2 +:10EE7000AB9CDE7200796F47D39FA3482E1AE288BD +:10EE8000BE09878E133D129600CEA078FDA1850A9B +:10EE900083AAF5854033A5239E27B8DD8E31998856 +:10EEA0006F809FF8C71A3109F8F2628CBB06C791D0 +:10EEB000ED2714D922505FB4E7C577CF2E658E5960 +:10EEC0003D00CFFB8B77B26E4877F712A47B7BBBFC +:10EED000818F87213F318BB316FBBBA4B0E938CEBD +:10EEE0004B9842F94B069E97F8FAAB95E3EB11EB82 +:10EEF000A4C596788E272BF0F14B61BC5DB01E7ACD +:10EF0000D7CABFB30B7E61CD9C5F701EA8BF64BB28 +:10EF1000DDA2DFDB9DEE5C3DE793CD08E7C811DEA7 +:10EF20007DC8B7C3F33CFB90FFD398E0933CCE275A +:10EF3000C1FCBECF6AA37E469D696588F72C85B962 +:10EF400002E92ED3D710AEA1C8DFA3897F401EB639 +:10EF5000E378C352AA54038012C7AC135877C6DEB5 +:10EF6000B6DAA95DE608E73EE437ABD345F27C208C +:10EF7000C24AE52B33387FC0F77F40FC05CBD32E48 +:10EF800094A3017E398A437E8CECC88FBF13F0BCFA +:10EF90002DE4A563FFEE3F61FF71CD3AA7029D0C02 +:10EFA0003F12E965D074F8A22A15E18F63C0FF0013 +:10EFB000A06D8E3507E52CA5CCA1205D9B225C873A +:10EFC000ADD40F23BDB93247E7AD86EFE6463B89A6 +:10EFD0007EDFD83EEC676636CC6F1FC01EFC15E1A5 +:10EFE000037BB0B608F5F46FFF69443D6A97F2D72A +:10EFF0003424A238803FAE48BDE0A7F771D20B4160 +:10F00000F40ED673C1F4F6EB05AD9E037C5DE0F41F +:10F010007067229FC5352F52B97ED0EAB5CEE8D1B0 +:10F02000413F083A5C8A707E81F85C0C3288E37A52 +:10F0300046B33E58DE991D0E8B89A476FF453B1CD6 +:10F040001613DFD10EEBCCAD0715C04779836A5795 +:10F05000610AD58FD99C48FF17EB148709E5A441B5 +:10F06000257E78716538D94B09EF67BBA307B1DB03 +:10F070002015F2CFDCDDC98E56C688F1ED9087F100 +:10F080002F5979D6687527C504E893171BBE084326 +:10F090003CF74F64034EC6620BA7D60E830829F0D7 +:10F0A000BD097F5310AF836B5414AC69EE9D269558 +:10F0B000E8D61DFB1BCE5AFE9C0D70BDBC6DB4CEB8 +:10F0C0001DC837F55767EC05F82B23B85DBEB4F7BC +:10F0D0005A2FE433597FF79262D27B3F072B1913E3 +:10F0E000A01FDFEE7382EB6156683DD51F87762A3D +:10F0F000D723008551E63E7AF427D47087AAF527F6 +:10F100008839AA7B027E107F8DE184BFEA9E20773A +:10F110001904E748EC7FBFC5C892A0FC0AC823B613 +:10F1200093707F03784707E2D10F6FAAF55484E00C +:10F130000BD50F5F3B5D900ED0BF6AD1D33C2EB193 +:10F140007007D2B3CEE864487FCF51E11F08BA55AB +:10F15000089EBBD430F4881BE6F7E29154077E7F0B +:10F16000A9FE4A982E12FD46F7149C979AD61A8546 +:10F17000F6705FC395BE2D0348BF4DC5F22B874E79 +:10F18000D8DC03BED1FC6684A687767E95FAC89A41 +:10F1900040FF50617C7EC17CA43434FE4B1944F2A4 +:10F1A000C7501F7AD299B71AE6BD72A0E0A77B9923 +:10F1B0001DE53E98DE46ABAB2226406EFF15EDAA5C +:10F1C00042B8709C942134CF85981F747866A6410C +:10F1D00087F31BC3D06E4A7F0FFDEFB0217EFF4E39 +:10F1E000CEAF7DFE3DAF0D3AC468BE3FC67100F89C +:10F1F000E53A80AF128CC1EA8CC079FB881EE562CB +:10F200007EE5E6489F0AF361BB0C175AA41EE8D6B8 +:10F21000117EA04F0DC2E719ED38E246FAFE35D255 +:10F22000518DF8D1375BD15F85F9ACC67A36A2280B +:10F2300011E7DF2FD2B905F5FC4BCB18F1F3A55739 +:10F240009877134C76FB7E1DF1CB46D68FF8BE9F88 +:10F25000EEF20C5724C9F33A843BABB956877AB720 +:10F26000A7D7AE437DDAB7B94EA7233E70FF2286FB +:10F27000FCE49957F4005FFF6D55EA37E4076F68C7 +:10F280007EEF40AFCD81F49278CB167C908D7843A1 +:10F2900083D0AABFD062F6E30DE8C3526C1DFB63B6 +:10F2A000AC251DF1D4F8FAE95E2DD05FC51BA76728 +:10F2B000205E2AFE60222618F387BED1C8EF9FE5A4 +:10F2C00084F6672E2CAD72E8C19F7A25A61BD985DE +:10F2D00032D66C443FA1BC6E81431FA0CFA5FF7600 +:10F2E000C8D09C8FFD1F1AAAB26580E72B8EE15D06 +:10F2F00058083BD1EE2FA1BF06B02F47D811CFAF92 +:10F30000674573FFD146F620B8FDA1A5731C637A4B +:10F3100074DEDFA1C161D3BDF07D7E901F743486A1 +:10F32000DBB5B6186E8741213B11CE8BBFB7783D58 +:10F33000507471C847510CFDCC5D1F647A808F2ECC +:10F34000B2E647FE8872763592D671F9833FCA5C81 +:10F3500066F1CBE51D23F8DCEF78ED70941DDAE75C +:10F360006FDF17E709C0DF1D4C7FB59DAF33705CC1 +:10F3700046E3337D4B2FA407FBE3D9043BA4F9AF4D +:10F38000BF15C7F9204187745E24F4DBEFB028C0B5 +:10F39000DFCE5F52417C24F3E56D66E68D0DC8EB50 +:10F3A0009B8DB8042E6F8B645E68B737C612477AA0 +:10F3B000269925A39EE9145F3789CFE07289CF4350 +:10F3C00083CFA6A35FF15927FE706F1B6FD7CEF7CF +:10F3D0004BC14FD7FBF3EF7CA53EEC0AF15D848D6A +:10F3E000D3E98A636417F4F7F28DBE1ED610EDE4FC +:10F3F000FA32184F6F5F2B8DC07E7FDF66CA0B0518 +:10F4000097DEA6FB767ECA21802AC01FDCA6BA53EF +:10F410006DC21F9C0CF98ABE57C6D1BA5AF28BD066 +:10F420007B77304F23CA6F307F487AF7B001DDFA1F +:10F43000A372662948B78B3176CE37421EA47C046E +:10F44000E331389D6064EE50EB80AF62245EC39878 +:10F4500007F4E1231B0D64DF0F5FFBF8DE4CE0F7E0 +:10F46000D31B0CD6E530E49C17F6A53E03F57306D6 +:10F470009BAC0AE44FDB7D3D50EE4B5F505DC80F07 +:10F48000A7373C923013D2F320BF650047E946030B +:10F4900095CFD9F828959F15725DFA427C7FD49755 +:10F4A00087F7AF4E403ACEF9EA89694897ED466B47 +:10F4B000FFC190966D531C6302F03D6F739826BF99 +:10F4C0005DC7E6E03C245D99E26EAF47133FD5A6E9 +:10F4D000FB76711F9FD6DF04FF72AAA0E3C4293018 +:10F4E000EF8AA157C8AFDF77209CECC99B912AF91E +:10F4F0008FBEC1FFEF9DDB209FFB95DE41BE9DA02F +:10F50000F3584167B05CA4B74BCC3C9FFBBA9EFC60 +:10F51000CF5C8B4AF886F69163A1FE7BA2BD0FF407 +:10F520002CCA2153B3D78D847663A30D0CEDD0F78D +:10F530007CF3F219D8C93BDBF4C75B02E6339AD5FA +:10F54000F6417F38871982CA9D7A2CCF356BCBC79D +:10F55000F6B8FB2CFA0F63ADDA72C9778FD8B4FA1C +:10F5600062DF81733F9B00F32B39A492FF7C237DE4 +:10F57000FC2EC2AF473ABF5DB80DBE3B2CB072F84F +:10F58000DAE91549C857231486F1ACD3D742CBE347 +:10F590001FA45E6640DF3E7EFA1638E6B6E751DC11 +:10F5A000EF19B1A03D8FF0DFBC1EFB7A3D759B8D3E +:10F5B000C73382ED46B0DCFCB7EC46FEE0B7D23D87 +:10F5C000164A7F83E985ED5CEF06EB89603B21E11C +:10F5D0000A86B7BC4DA7B10F5FA11E191A68278C08 +:10F5E0006427BEC3F570836D68C7F530F831842F8A +:10F5F000CF303DADC3C1DF6AC4760322EDB139001F +:10F60000D20A6BB708B27F16F77E5B401CAAFFB622 +:10F610005A1DEA8DF6F88C411BA791EBD577849D96 +:10F62000A813FA1CD6ABB4CEDF18EE4ED4E3B8C99B +:10F6300046C7968C8EF8F948B4EFCCCF957EACBE19 +:10F6400086FBB18F585D9A3819EB93A889FBA25FAE +:10F650008EF2EDD91B4EF3FC54710D4239D433E7D1 +:10F66000DF6D01F4A93670F883E1898FE576923178 +:10F6700017F907B27CF6E8D07A5C89D553FB9C6712 +:10F68000EF4F47FFEDD3C607D251BF7E1A14E7ED07 +:10F690004C1E9E16F2FAA4B02331222EF014CA1189 +:10F6A000E441DA9DDBE1FB554B5D24573F5D3A9D1C +:10F6B000D267962EA1FA13B60C1ADF9AF367577722 +:10F6C000C0D3C9352AD989D94657AF18F8EEA459FD +:10F6D00047F18513559179BB22B19CD17A72F6B36B +:10F6E00013B67802E27E276C7AA24367F38C8FFD13 +:10F6F00066FABD9CB544A1BD6AE7D7231DECB52DC4 +:10F7000016E37FAC2501DB552ACDBDB6291DC7B751 +:10F7100032677C2CF29791F547B9A90BE7F628B828 +:10F720005D4A2CE7C3BFA11F0BFD7E8A762B849E0A +:10F73000B10B3A2FB438EDB1A4EF22C95F27B881DD +:10F740005FBE8C727647B8605DD613D3615D787CFE +:10F750006EB1C52AF8C3A9F0758EAB5F6C88F85BF3 +:10F7600067F19E6038DE11780D8E03C954C681861C +:10F77000C6F2F9BC6DB36AE24218FF0E15FFF979C3 +:10F780002CD7A31BC35B3C2ACAC3037C3DDE25DB0D +:10F79000A3607C2B25BF3607E35F77C5F2B8A52DA4 +:10F7A000CF9D88EBF6E444A303E336372B8F03EABF +:10F7B0009C7C5FC0AD2338D6377BC27A015C09CD13 +:10F7C000EE1C23A45371310DF8EDC2AA9621DDA0E1 +:10F7D0001D21236B7FB857918B6C689229F42840C8 +:10F7E0001A8672678C724F45BA0C9B55558D71FA0B +:10F7F0009432BEFF70567177B5019F9C7D2B3CA45F +:10F800003F5C22E8CF94D1C968FAB3361B08AEAC8E +:10F81000CD3F9F817C9FB5F92EBD12A08796C71A58 +:10F8200068FE67DF9AD795E2169F9858CF107AEA5C +:10F8300087825F1E1074D8690CCD7F8B45BB6FAC7F +:10F84000CF5B405569F5F9E2D880385B45F965D260 +:10F85000E79363ED34CEF3FABA03C980CFE767319B +:10F8600087078AE66DDD48F1D79DC6BAF1B8EFE4A7 +:10F87000A9D031A4FBFE037F38908C7EE42CFB6082 +:10F88000F423DABF3FF4D24A2C7F7E0E1B8CF84F54 +:10F89000F23EAD603CE69F61B584AF7F6E31B165ED +:10F8A00018B77DBF6EFC0F21BFBE4CC750BF04CF41 +:10F8B0001B4632E81231F519742338FD510F4ABA4C +:10F8C000030319911E926E88BFED90EEDFF21AC10C +:10F8D0002FE19A2AE2DEF3B66E1F8F7C925C6653AC +:10F8E000304E20E1BA913D7931F6DBD993EFD00E5D +:10F8F000BF121B222E1DC20EEF880D618783ED2FD4 +:10F90000B3387763BB1BD9E1E182FF36C606ED7FD2 +:10F91000E07E5908BA0D8DED100FDF1F1B62FFE36B +:10F9200046F1F0DEB172FF431B0F7FC9C8F56FAD22 +:10F930008D3D3C2984BC7413E3EBD6B51AD17EC649 +:10F94000352821F5D9628B51EE1F7E1C1BB05F124A +:10F95000AC8F43E0F728B6EFBBCDB7175B0D89E955 +:10F960001181EE5BBFEBB0DE0D31CE29813FFB2272 +:10F9700046FBA6F62A46FA0AF25E1E14F42914374C +:10F98000B0384F93DDBAC1BED59DD61CF283E43E9C +:10F99000D554ABD64F8C8B93ED9C9F239C699DD8FF +:10F9A000897F093CC1FCDB70DCB8454CB31F23F7F1 +:10F9B00061E2AA3C8A310BCD11A3F86AD758F7321D +:10F9C00003B46B1DC91C9B201F5D68CD417D6A9BE4 +:10F9D000E368C4FD9A9517793C7EE502E65D4EFD2D +:10F9E000F0F93277372FCA17D22D302E1011C7E118 +:10F9F0008888E3720676D21CC7E10A8F0BB0939217 +:10FA00001EBA753E95E8DA1ADA4E05D0D546DF778C +:10FA100042D7EF502EED7137E71FF78CBB05BE19AB +:10FA20001877737CF3144C4BECDF048F9789F30F3A +:10FA30001E0FF82C2BEE26F8ECEA2DEE8F1E8850C8 +:10FA4000BE5DDCA5235E27C485D0776BF2757D484B +:10FA50005FB3704728BB3A232EF2BF7D5E6486A059 +:10FA6000F72D9D1779F1272D46A4B3DCF790F0060A +:10FA70009F1391E5150D4A26AE3F73F65DA375C041 +:10FA8000A5C67FD33AA0E3790F3EEE42E403806738 +:10FA9000AC3AA0CE07F277799B9156EA2AB3FF22BF +:10FAA0001BE3F64D06E6B5537B33B6EFC778FB7E16 +:10FAB000DB563663DCAA1FD37BC47A54B9CEFDA8CB +:10FAC0006894E37E4D2A5B8DF9ADBCBE8A9997613F +:10FAD0005C3A7A848ED903F019E30C67F6007CC691 +:10FAE000E6D93479B94E9E2FC68D77256BBEEF329D +:10FAF000BD9BA67D92BB9FA63E65CE104D3EAD6AD6 +:10FB000094A67D57B0CF81F90CCFDD9AF6DD6B2638 +:10FB10006BF23D6B1FD0B43FCDAA9ECDC6797A9CC7 +:10FB2000CD3D00CE5902CEDEEB8B35DFF5D7D50DBE +:10FB3000F3A120F9141FEEFFCD166C324BC473FAFB +:10FB40007AE769FA3DFF6A5E9302F89D5D6B3819AA +:10FB5000189F217C007E4BEA15F61C8C5BBA5E5B1D +:10FB60003FA7E1E9952990CEF56ACBE7E1BE9C82FB +:10FB7000FCAD2DDFAD733D82EB9DED7122CE28E211 +:10FB80003DAC037F44D2B89737F07897EAE91DC4BB +:10FB90001F5A3AB16FC92F76C12FA6442DBF84D901 +:10FBA000B5FC527A70E7301FEB88FF883E417CE459 +:10FBB000817F017897F895F8B738B47CF55DE19DC1 +:10FBC00031AF91DB0D6DF93FE2B4F1B57E91EEE31B +:10FBD000A8B7AED42F5271BF8DE5F17DFB2BF55741 +:10FBE000071DB26BF6D73ADB4F3A1717185717FBBA +:10FBF0004997703FF1367613FB89FBFE85F800D9F3 +:10FC0000771B801FD80887B97DFF30CCBF7F14AC2D +:10FC100037650A76E3CB38B227FE7DD76AF87A5883 +:10FC2000F45F5C08AFDC8793E772E4F92116C9E75B +:10FC300029FB013CA8F143F1FC9F2D02D7ADDBF776 +:10FC40002FA4F5963C3FC4C4B9BF107E3FE9EF3AFC +:10FC5000FC3589FC81F0786ECF23316DF707C4F94C +:10FC60002E69CF3BEB47EEB775962A7B55DA3F6C92 +:10FC700055C21D9B42D8935EF1DF72FD75A6431CF1 +:10FC8000BA577CE0FAEBD12B07D0AE00DEFB62B9AD +:10FC9000C502F65AF1DBEB5F444411BFB61E54BDFA +:10FCA000BDA1E0B2D91E6D033C368469ED884CAB32 +:10FCB000CCC903F4B158AF3DE727F71183DB676385 +:10FCC000FB80FD27F84EE38FAC1CC2FDB5EC786ECF +:10FCD000DFBF88E4FEC11491AF0C5A1755D670BF30 +:10FCE0006C23F8E90D01FD4C89B750FBA511395380 +:10FCF000E2298EC0D7BB2B3314F227562A0AF921EA +:10FD000067A24753FDB5B89CC9C43F629C29E8BBB4 +:10FD1000C1FFDA6E1C1EBB388F23FB37C7F3F6E634 +:10FD2000F8D1944E89B78AB8B3B51FF2476584936A +:10FD3000FA35AAA1F7A5A6C7F379ADB530E9276AC8 +:10FD4000E2FEE384DEC438BF89FBA3F96313FC71D0 +:10FD50007EA6667F688C13F17D853E77A29EBA539E +:10FD6000D0BDB378BFB38F753F6E27758CF7FB128C +:10FD700043C6FB1DE328DE0F5FEA715EC1717FA4FD +:10FD80004384CD2F3F8FC4B7DB8354D44FF54677E0 +:10FD900035AEBB5A7783FF0EC57DBC2DB41F30F046 +:10FDA000507707AEAF5666B0BD16E4B7658CA17F3D +:10FDB0005FDFA25B1E06F56B3CCC8AF52337F0753E +:10FDC0005BE97ABB03A7698075B065885F1FAC8B60 +:10FDD0008F21BCD7B74C6EC4FD8135F7321B9AA179 +:10FDE0005A569B1B85FED0061672DDF89490B30917 +:10FDF000397B55D417F1E8DF87A0D353824EA00F8B +:10FE0000D6229D87B7BAAFF0FD38AE4F4825E2FA4B +:10FE100074BFCE1B6A3D3F373A771DF2C1406FE891 +:10FE2000F5C35A0BE7B77511AEE7A8DD2E7EEEB528 +:10FE300054EADF593AA607BA4F11749DB2819FDF89 +:10FE400060D7AE5F57A59FC8A87F867AA5F45E8B62 +:10FE500017E343A50D191E82CBA5387AA2BE687898 +:10FE6000DF85F9D2AC2C2BC6239C7F65CAA93EE462 +:10FE70006232AEBFF4EC94D42764C7E368DF69B2A2 +:10FE8000E0B7B5163B3F470D288E00FC976E58B67D +:10FE900017CFEF7CF46B46FB4B47D4D661D8D954CF +:10FEA00040CE922198EA5921C52BF8FED5BDA21F5C +:10FEB000CFBF615CB37FDCA90D07693E470CCC6303 +:10FEC000063EBAB4E73E3BFADB2BE3CD14C793FB07 +:10FED000B24755F7E36484F4AD1508DAFD0D115609 +:10FEE0008C7FFC43F05D46827B1FD2C7BD7C7C05C6 +:10FEF000DAC19665A674C4A37B79921A0770BAD743 +:10FF00002A34EFD1CB938C787E61E68AC1E3504FDF +:10FF10000D61CE9518DF7928968594D3F3F17C9DF9 +:10FF2000585C6560C6689A8411E32F176B148ABF0A +:10FF3000E0FE5B01D0678E985FF9AAF7A3883FECDB +:10FF4000F06F181ECBE53F73AA4A491EC1CE6BE481 +:10FF5000A78CD51993A09F796B6039DB8DECFDF1EF +:10FF60000EFE43C079EFF23A6D7D255BF3399D7F3C +:10FF700061E0EF5BD02E68EB3F95F2E8600EA4AB3A +:10FF80007BB1C58CE784460BBC14AD51ACA85F6651 +:10FF9000AE688CBF0FF2339B5407F2B4C40BEBE88E +:10FFA000EFD3398FCB4D3D693D70D96EEF82EDDCDB +:10FFB000515CFF2B7AF7702C7F28D63D1CD7F1AD12 +:10FFC0009F58189E9B39D606FE18C61ECD6C10C5CC +:10FFD0001FAC6CD0A4003B5A64B02660BCDFC316D3 +:10FFE0002632BEB7650E9C77A5790DF98195E80795 +:10FFF000F2F9911FF8502C67D5D6D7153A9FC3EA6E +:020000021000EC +:100000000DE4079A851F78D65E9B00AE17733D6E90 +:1000100020392DDE16437E68F18A5C23F26FF1AE43 +:1000200018D243E0077ED863989F8EC756641E4857 +:10003000847E8BEB321CAA967E5AFFB8E698A45BAE +:1000400047BF4F4BB793A1E806F4D294A72408FF0B +:100050004ED08B3D164B7E47E182B77A9A019ECBFC +:10006000556174EEA833FF83A5C6D1BE9E5C17E62A +:1000700025B7AFDF68DFFCCA9AA144B7607AE5FD17 +:1000800067E670B427ECAF16867AECA1EEECE1C916 +:1000900050FEB0C2E5EBA1EAF17928A759095C6FDF +:1000A000BEB714666864ECFDA566E6ECC5D8074BE0 +:1000B000AD94FF686922E53F5E6AA7F493A57D28A9 +:1000C0003D29E26852CE8001885F472570F91A9574 +:1000D00020E2DE6C5122AA8CBCFF7C305467C5A1A3 +:1000E000D2278C4D63EC1E272023C0DF997E6F043E +:1000F00012B93DDF62B08E4B44FF719542FABED813 +:1001000075BBA63DF825463CFFCDFA64FACBE99CC9 +:1001100098DD3819F8F0FEFC584DFB6935299AFC3A +:10012000E4043BCD7B525E774DF90385FD35F9A2A2 +:100130003640029E2F30DBF8FEAAD8B767CCC6D770 +:10014000EB56DEF66AD5F02EDF0778AF1E32507D13 +:10015000303D245D67ADD731378036733DCC0DFA25 +:100160003D593B93E4EAFC110BD9FD95DB32DF1DD1 +:1001700001F963DB0CB4BF7E6C45EC5ADC3F3EB644 +:100180002D3E8A41EA5EA9321FFAC17AAB9105E899 +:10019000B7DC15CBE8FC5691D7E440F92FDAEFF93C +:1001A00095CCDBD11F4420513E3E54BD3E85E8E74F +:1001B00024FCBE14E6DD02F933A0AFF1C8F8CC167A +:1001C0000ED71985ADC0FCD9B0BFF5FA3EC071B1EC +:1001D000A0B64487EB01F5503CE9CB1D2A43BE2D68 +:1001E0005C60A0FDBBB91FA91B31CF9421299CDE07 +:1001F0002A9D47642F99A87FD60A1C02ED16FDD6CA +:10020000B489D6774CE4770FF4AE16FC897C74265B +:10021000863963085885E03DF77EFC46ACF7E3D3AA +:100220003B08E7FDA5DEB53201F8EB5C897710E904 +:10023000B5C7E249AE82F17ED2C8F59607E540F136 +:10024000EB4BBF9C2D273E9D69702438485F652588 +:10025000A1BE3AB9C640E79899DE193589D63F3B29 +:10026000888FE53827F5F67108DFC99A0C86FB966A +:10027000C56B54F20790FF787B2FE7FFA755371B1C +:100280000EFDD6286ED6A523DF3CB260389D639A5A +:1002900021D641C17AE0339055772F7F7EDE1E7ED6 +:1002A000CE8665B5E8EF1D18388F157CBC44DEBFDF +:1002B0003C0750D6ED4F47D1E5BEDCD43D1AEDF0FA +:1002C000D90F55E2B3B3DD6A8725023D2FE8F60E5C +:1002D000FB3EE4CF17784EE921FF54B87B6702AEAE +:1002E00057746BD2956E783EF6C4DADBE1BB73AF20 +:1002F000181C24E64BE2497FCC7B696ED7C0F38E95 +:100300001DF5972F99EFBF389314C0E77C7BDD383C +:10031000EB005C77BB841DE2F8B1E3E62AE0C5BAE6 +:100320004EC143C3ECC450CB6A3C773D13C4243068 +:100330004E7842EC8F1F107A45FA09115D787EA63F +:100340008EF3377B5521BF0D7E34FABF529C4F94FC +:100350007A5FEAEB32564BFBC14712F839C6B98ACD +:1003600097DA55E0CE2EA8A8122B0F42976D35795B +:10037000BD19D49735D00F48EE62E7FB43C6579EB0 +:1003800045B62D65CD7C7E41EDCE19BC25CD191D20 +:10039000ED4D8975E30A1BF56F7060FCA454C869C4 +:1003A00079ADE2F5F17990DD94F18AD9C26E06DB80 +:1003B000A70EF628C80ECD0EB2B3AC566B5701DEB1 +:1003C000481C47C21B0CA72BC24278980770A1BDDE +:1003D0002D717B0F4C24B8150750B2033CA5CC35CA +:1003E0002606E701F53E7B47F882E7D5015E31CF6F +:1003F00060B84B1C9FFB70FF18CF8751BC29681E4B +:10040000921EC1FE9AA44B8987E3B7A441217A7E4C +:10041000DAEE07328A1B497E8105509DF67BD74470 +:10042000D467A5EB40FF66F8F947F2D33C56178531 +:10043000FC52C17C2B9350BE7C75D346A2DFBEE13B +:100440007D23CA49A1CDD7531783285CFBD3BCB405 +:1004500080F544109E6F44D76F8A379C955EC6BD69 +:10046000004FB337ABCEB0419A76E21C9187E4607F +:100470008EC763C4F8C61CB1EEBF119C957A7E6E20 +:10048000FC86F076E2277D5BB8F3BA68FD62BF9F19 +:10049000D5333A949E6AF7AF82ECFADF0C3C7E21AA +:1004A000F5F155BD93E225502EFCAE2A2B8F9B070C +:1004B000E9F1B42CD2E325C2AECB714EADDF49F1E8 +:1004C000B7D968F703CA3F5DB793E2FEC6576647E0 +:1004D000A1FF7D6AFDCCB578BEEBD4B69964E74B3D +:1004E0009F9376DE6D0CF41F72D717BDF863E4DFBF +:1004F000AD61149F2FD9EF16EB1ED0ABD0CEBE9EB0 +:10050000EB51B68EEBD552B48703C81EF6C6768B78 +:100510004BDCBD510E02CAC94E2E9EE9FEDD1EE81F +:1005200077F1CB110E0FA1C2EAD391DF6EF5A13D99 +:100530002C5FF8F1513CE70EF6FFA31F48FB0FD9E3 +:100540008D7AF7922E286FC2EE97AB1BD3ADE827BA +:10055000083BF15FC0BF3934FE8710FE8B11FF01ED +:10056000FB20C76B389E6706E1FFC41A4E9795DBE8 +:10057000BA47E1FAF1784D77F2B38E6FEB49F89F05 +:10058000B51AF0CFE35F5A3FAB06F08FEB08C43FDC +:10059000C05BBCDF2EF0EFE0F8AFE178676B783A34 +:1005A000AB039E3D748E61F1AF4D0EF41BCE84F90A +:1005B000C89F3AB35D65D5017E98F483BE60B5BF30 +:1005C000427F4DE27F6EAFE641A87F0A9FFE531443 +:1005D000D261EE761EA4EF807FE6EC82FEB87FFC4F +:1005E00076BFE9952EF1017ED34DD2A982B918D9F3 +:1005F000C5863F1DC17583E2844F6D788F46DCD779 +:10060000A8D7DED7C0331985368C2F38CC6684271F +:1006100035F81E8A9B611CF99F3D3F9FB190E4BC59 +:100620005573BE6D22F319BAA0FF58A7D0FDC6F2CC +:10063000453951390CE3D45504C7E92E8AE6FC78D4 +:10064000B9AA23FFB1CCC8FD48B93FF9AEF00FDE1F +:10065000EDC2D725EF75B1D27797C218D9814B1665 +:10066000A317EF23C07A2A11C7F7EC3111DD8E22D0 +:100670004C807FD528E2366002914F1F649C4F1F4B +:100680008C6CA23839AC545E40BBF8D0129383FC1A +:10069000DAB8688AD73E20F4DD83912B5D681F1E8F +:1006A0008A343A31857E3D7888CE301A8687F10DBE +:1006B000C946BAAF53686E790597BE0F279E78D4A6 +:1006C0000CA0DE06EE37C655E0D75DD7633BD2C53A +:1006D0004F1F6D9CA7323C74DCA355E04B713A2947 +:1006E0009E6382BEC3018E2B682FB1DC6EE5F19D47 +:1006F0000D40278B9FBEC1E5CCC3F703CAF05CE376 +:1007000028C6196404E15F932F33F2FAF0C4AF26D0 +:10071000ACCB66ECCFCC3E10E956863A04D7F74511 +:10072000D15E8C97DF83F1251BA67AE297C97AE622 +:10073000D1F1B42612CFCC8978D34481CFA92398A4 +:100740002F1AF0EE3BA88D77DDE7D3F97A037EEF21 +:10075000D1FB1A913F7566BBC10AE3B8F29421B888 +:100760002E295B7E73F0A6259AF3D7A5425EC7CFEC +:1007700085B5FE80C7211E046145BCCDD0B3FDEA1E +:1007800010CE0788974A9BDD43ED1628140F95710C +:100790003649FFC1D07D201D1F14F0413F3551F86F +:1007A000BD3134BDFA26CAF5731DADABE70BB99B5D +:1007B0002FE56D9B56DEC627DAA9BD827E30E0EDBF +:1007C0004191762617E344FFE312B95C64DDE278D9 +:1007D0002CB2359DCEB708792937F1FEE5F8F788B8 +:1007E000744CA28DFA95F000BF1EC77E74A00190D4 +:1007F0005F4FD656937F348705C4B533FCED245F35 +:1008000077CCB7EB11DD754C8DADB310F5CAF7C2DF +:100810001CA8471F34D6F5AC8AECD84EEEDB14B2D8 +:100820006603233D29E261C2FE8C5523E97C40A189 +:10083000C2EF0F5ECAB17874D118A73110690B638B +:10084000143A3FF137B17FF250F4E28928D785514D +:10085000463DA633582BF5FB776BB7E8FB18DE3324 +:100860005631760E038FC877C2B8D5A877787E8DBB +:10087000339BA24A227FC72127E0E1DE6B407FCA7B +:100880007F2FDF09FD5F7A4BD4B33BE9FB4B8F0B26 +:100890003EF6E4F2FCCF657D1ECFAF92F5F93CFF4A +:1008A000A4EC5FE49F0EAA5F1654FF4B9E5FBC3E14 +:1008B0003FDF837EEB68CED285A314D2537B84BE08 +:1008C000285CEE23FC16EAF6F27434F3E9B26EDC2F +:1008D0006E53A26B0FDA1FD572D282F6F7D564275A +:1008E000E59F4F702F4BC475D424C563447DFBA195 +:1008F00097ECC1C44ECE1FEDE9C2E3F89B92A0BFB6 +:10090000A17EFB05FDAC4E8CBFF57E1C491CAE8064 +:100910007E9EF926F0FCA7233C1BBE493FB392B54F +:10092000FD487F484975BE86F36327E334E745E613 +:10093000FFC4118DF12786E74500F5F397D7A5672A +:1009400042FFF35F7D3DBD04FD2561E72BDA74CCEA +:1009500089F734DB18A5E71B3F31E27DB38A5D8D53 +:10096000C671D0AE12D2DC00B8CA049C60E7F49322 +:1009700003EC7383D01B8C3DCDF7375F3DAB477ADB +:10098000CED7D59D7A0EEDF62825E43ECD66F1DD75 +:10099000D14ECE17EF157AE86A9AB311E7F96B8C4E +:1009A00021403EB7BA93FB60491C5F85C2EECD1C67 +:1009B0006631DB01CF433FE4FB54251B3286603CAC +:1009C000F8CD84D1EF247E6D3CB595C7531B783CA0 +:1009D000B5D0D6BC089437332695AD31DFC1D88465 +:1009E0005F48390391856FF34C325F9D3F269BC76B +:1009F000BB307F76FD636B506E9AC2B91FFBD0F09F +:100A000081E1A8175A3222745690E737E38B8C495C +:100A100043B1FC8E71589E63B2F42A22FC32E28B01 +:100A200037E35DC7905FB03DC641DC465FFC7D307B +:100A30000FF7DB2A9DA7750F8A7087DA77FA87C0D0 +:100A4000AB31C94A69139019FD1709871C1FFCF9BE +:100A500045CDD0DFC9E5498357DB719F25C7903469 +:100A6000D43F7E4682FB72E0F82775AC172E296EC4 +:100A7000168E4B020E03EE5D03BE5DD92A7306ACE3 +:100A8000F3268F89D0E4EFCD8F65CEC038EDBD2938 +:100A90009AFCF4C2EE9AF60FCCEAAFA92F30356774 +:100AA0005505F8B19DFB491E82A7D26209477FEE2A +:100AB000EF0D5FFCE541F4FF36AB0EF455E7EED9E0 +:100AC000F297DBA1D5653C4E45F1473BC5CBCEC97E +:100AD000F3287AA73E705FE8226BA6F33E9DED03F4 +:100AE000C975EE7CEB7E3A77F65DEF03F54A12EBC3 +:100AF000DD216C08DAC3CB551F51BCAE2292CFEF7B +:100B0000E2EBC78CB80F8AFB8AD781DFEFC20FD127 +:100B10003F6CF3503C3BB7FE18ED9B1D48E47ABA9E +:100B20002275811EEF1D55428A76681CE8AB68E08D +:100B300097E646367017EEBB6658B81FDE3699B199 +:100B400058E42B1EDF694A88A17BD7F36BF2A8BC5F +:100B5000A22D9CFA7F4F6D1E47E7095F5368FFA1E6 +:100B600020E5A1E5787EB829DC33E01118B7E077FD +:100B700077E521DE2A76F1F3B505EA9FB316405AF0 +:100B8000569B47DF17A8AC49017F61422EB7BF05CE +:100B900068F321AF0EB3AC46BBAB1A7DBD9E473D9B +:100BA00063B4909E896E7B80C6AF6C33D3F7F72415 +:100BB000717FD7D0C2E11ADBE6A272C90F5393BA94 +:100BC00069D60F86F8CD7A7C97C3D0C2A8FDDD6DBB +:100BD000FD2895F37DBBCFAFE93EAE21FEEAB81408 +:100BE00098F7DB718A95DC90203D7CA56A78340B00 +:100BF000A1A7DAC769E3E7F44C6DFCDC5E618A7398 +:100C00007E12C031F1B1163DEE07B148B315F13592 +:100C100071C4607B49807CA97BEF37227D0CEBDEC1 +:100C200037A29D36419A1B505F2ECE3304EBE90567 +:100C300049524F2FA354DA1D767506F9A933AC82B9 +:100C40000185FCCC10FA547EDF4C6B1AA0E36E1EBB +:100C5000C77F34C5BD02F545730E9BBE83F4667332 +:100C60003AEEC37C57F0039DCD0AF9892D741E75A9 +:100C7000E208BB0EE3FFAB045C528E6F348FC5A25B +:100C8000FD7B2A5B82FDBE77E79DCD4EE8AFF14745 +:100C90009999680FE4B8CF25F17B29CCDA7A0DD782 +:100CA00083956F44D851DE0B703186FB9D7B4CB42D +:100CB0004E8172DACFA87CC3B409EF895446C17A59 +:100CC00015C6CF7D33CC877CDCF866981EED46EFE9 +:100CD00074F77348CFDC377B8FC1F5A1B3C1A4672C +:100CE000E4F7389F273DDB09BC37D25BC17C26E5A2 +:100CF000D35DC3E5A548F069B1903FB790A32B55EC +:100D00005D480EAF3C0640E33EE963CAC05DE8279C +:100D1000D82DF47E9394CB025C0F417941FF183AB1 +:100D2000FF2BFD8D60392C6BB352BFE56D7621EF43 +:100D300036CA4BB92B167263127EC62CC1E7BB5361 +:100D4000DCEF205E0AAA41EEA3681F3F0BE5C9CF86 +:100D500037462BF217F04D624980FC5437DECFD076 +:100D60003F31C5B9886F66411AE89FCC6EF74FAC2A +:100D7000E31200FE892B327478DFA99D7FDBF9E650 +:100D8000E6F87F8F9097E2485F4FF4670D55610E4C +:100D90003C877E398EEFF72C5CC5F1B8D0E0CA45B0 +:100DA000FF62E12F158A97A1DF817A69D8912A63C2 +:100DB000601CE5FEB641CC0E7898D2D683D23713AC +:100DC000DC47110F456DD304BE067DA3FDC5A14EC2 +:100DD0001E4732784D8E8D19184772AB48E733693C +:100DE000CCFA4CE07EDE7A1DC5C3E4BEA38C2B9901 +:100DF000F0BC7C801DFD425F9B4EEF3704C79972AB +:100E0000B8DDBFB0D94076BFACF1CFC374507F2EF0 +:100E1000C3D905EDC9977A771BF2F5BCC9DE570D2A +:100E2000909FFFE4CEA891763F3EEBF4BE9E6847CC +:100E3000EB008F18EFAA5BA3E679B9BF13C1F7C91E +:100E4000387F4B7E0EE6F3796DDD889FAE5499C8EE +:100E50000E5D01BE65017648DA1DA9E7A5FD917C0E +:100E60005DAEE7FAAB3C32DAEBC908B43B935C39D0 +:100E7000C8777DF8791ABFDDD9B47614CAC1A53810 +:100E80003AB728ED46B01CBCB6141CD35E1DED8EDF +:100E9000D4EB52CF4BBB35FAE52F77FE15CD558AF3 +:100EA0007B4032E0EB6E3DB75F77EB2DC43F63E3F1 +:100EB00026E9916F6E5E8F1E137AF498468F5674F2 +:100EC00062070627DF9A1C7415EDF34CDC7F443D66 +:100ED0001FD8DFA329A3C7E03CC627733BFB5DC136 +:100EE000DD99FE1F9F7C6BFA7F58B288F7DD40FFCB +:100EF000172673FD1FACEF9995BFA773694F5F2F3E +:100F0000DA83A30CEC03DAC18608FB16610FC85E16 +:100F100084477BBFCE1E5C4D9B5988780A610F1EAB +:100F20004AFE16F640F2A1941B2927522E82E5486C +:100F3000CAC5849FC23A11E9F41EBF5750AEF76C80 +:100F4000A3FD467BC46094CF763F6E9742F2D6C134 +:100F50004E08F9F1CB8BD66E48B990F222E5A75C2A +:100F6000C8C5EC20B9D8A7D63D330AF7CB92DD6BC4 +:100F700093E3FD7252B623D83E74CA57185964B32E +:100F8000E3AA18F25539A4817C65EA441E9E49BE45 +:100F900035BF68D94DF2D36FFEFBFCF49B4EF8E9E8 +:100FA0007FBE0D3F75F4633FCEB2033C57B240DFC6 +:100FB00066F8F96DC23B8CFB0FDDF97A00D6970419 +:100FC0007793318DE23E13AEB32A8A2F0ABE947412 +:100FD00096FEC06C11773893E27A07E1C5F5C082BE +:100FE0009BD37B4467535CB311D727B3210DF40324 +:100FF0003AF37F9B6F51EFBD7193743E96FC9DFB5E +:101000008DC79243FB8DC7B1FC9BD2B5209789F861 +:10101000DE8F0B30DE38E1299167CB0A108FD34683 +:10102000C8FA9F3CE9EC81FA81C9B838C539DE536A +:1010300045DEB3F4F018683FE119E68F9B43FDD815 +:10104000ECE8F6B888C2FCED95E71F3BBC86E8519A +:10105000CBE5CCDDA2E7FB3F229F05794B407E44E8 +:10106000507E036F1FA56F6181E745909F94219C7F +:10107000CEAE00FF0186DF7F05ED85556118D7A84C +:101080008CDBF8D615D46BF50AED45B5E381D514A4 +:101090003853C5FBB9945F73D8093EC203BB78BE11 +:1010A0004F4AED931EBDE837E0DCBDA14E71D2B9C9 +:1010B00083118AB75B46477CF749D1DA27FCD16BAD +:1010C000BF67781EEF56BE6FBFCFD68DBEF7996E45 +:1010D00061FCFBB2439F7FFE5E0AE7EF3159D121ED +:1010E000EBC7A5A8BC1F1137A0F1A1684A5DE87B3A +:1010F000B013C5B8CDB85F42F8DCF624E2B7D92802 +:10110000F1FDF293C8776319D3C4CF607CCADF9F27 +:10111000F272418D9E4FD71984AFAF9BEF8014A917 +:10112000BFFDF8F204D1CBF435F87684C0B75DFB8F +:10113000BDEFEBE835ACC3F7826FE7483E766AF85F +:101140003D5AEF22FE8C8E53ACE84757B8C2D6E02A +:101150007AC12F9FBF27BE6C96FB031DE4EFB5023B +:1011600094BF0A8947CFEB4FA2FCBA74EDEDB93CAE +:10117000B6F33573F601BC52C80FBE7FE4F9FA2707 +:10118000312E097C41F594D707C01D2C8F7541F98C +:10119000EC20F915F247FA03ED01E0A927EAB7B808 +:1011A00063467B009FFC4CD0E9A2B827DA3C9AFB4F +:1011B00093CDDD78BA2385FB8FCF097C6E12ED9B32 +:1011C000C303F090AAE11F1FAE5B02E64D78BA3F61 +:1011D0004ECEFB93827CD063CD365EBF2DE5A32738 +:1011E0003DD9FE7C707FAFA67C528078F1F7FFF18D +:1011F00061F423EE1778DB9172E4B02752D039C145 +:10120000FF4E21F007BD63518EFCA174E48F1F7661 +:10121000E44F4FD0F7F44E7767DF7B3A7EEF0CFA5E +:101220009EE13DEA9BFF5ED02D3F88AE7941741D63 +:1012300013942F9479AF46FF4ABD5C5CFFF4E30939 +:101240007118DF54E838BF9F9F4F93BD996F95FC8D +:101250007BE630F2AB9F9FCF129E27D709BA79CE9B +:101260003D897A7812EAE151FEFC14D443943F5F41 +:1012700080FB617E7B7581EAEFAB91ED2F92FD7A69 +:101280006085ECEF33CA4B3A32CF25B277F70BBD0E +:10129000C33CADA4F7E735F0EF3F7DFEF3C35F2B12 +:1012A0000FB54178D91094F704B55F7703FBB622E8 +:1012B000E8FBC782EAD704E5D707E56BB4DF17CDB3 +:1012C00052480E8B46F0FDC960B90CE68F2F52DAFA +:1012D000E363EDF65C8924FF4E235713AA79FEFAE7 +:1012E000F3FF29A8890CC8A7B0891EB2EF305AC0F5 +:1012F000FD41D0B91E15F8C1D089DEBCD899DEEC0D +:10130000136CEF79FD3FF0D724DA2FD2F825FB5488 +:101310006DBE51957047BDBB2832605F955926E27E +:10132000BABAF3FD9B8889635203FC224FF84467E5 +:10133000C03C65FB715F5D5771BCF8D4F0899B714F +:101340007F68B4D8D7B4F114ECA58AF6BA52C46F4A +:10135000C6E1395D6C17EEEBB930D00F6275BD7028 +:101360009E8D3F52F9BB50D5401FC05311B3D37966 +:10137000D39978EABE3BD447472FF90D7CB7EF47A6 +:10138000EA12B4D34797C4D239A645A9DCEFDC17DB +:10139000DD356136E41B231E267DDBF8C4584AF791 +:1013A000AACE95AD56E83A357962645FAC8F263C9B +:1013B0003936C44F5C06FC9D996A2738DC366B428F +:1013C0003DFADBAB0DB45F082D7E45FCF3A469301C +:1013D000AEB78B96F5A7FDB0E29F4F1A87F7B08A9C +:1013E0001F37D03E498BCE4A7122F7EAB1742E6A7C +:1013F000D60A917AEEA2F4CDFFFCBA1AEF69B5BE17 +:10140000A0D0FB0E775CAD7B67109E9BACE94EF7DE +:101410002EDE8075009EFB3EBEBEB717CF219F0813 +:10142000ABA273A4D09EEE8B955EB3BF3B310BDBBA +:10143000ABD6E5D0FE1494A3FF7C6A95BA09EF41C0 +:10144000154559C2F1FCF6A9AF18C5754E3D6EA2FF +:1014500077228E47BA67AC8FA3FBB8E8E9B3538A0B +:101460003D4A013C4CDAD067626212969B047DFBD8 +:101470004415011E8A74EDFC43F6A42486E727A5D3 +:10148000F699B805E671EA97BDE97CD8C154E7E45E +:1014900054C0D72FD29C5352E3115E6EB7DEFC0FBF +:1014A000DF8FFCE385E204E4AF8752395FBFD1569A +:1014B0009C10F8BE77C9453DF1C19B46FB227A27B7 +:1014C000303C4DC17536F0412CC6CD6789750BF0A7 +:1014D000F3929D21FCABE1A92AD1ABF1A7F1D94848 +:1014E0005F3F5F0F7F17F519AD37205FB121732D77 +:1014F000DAB993A625EC440FD67EFE91ED0B233C82 +:1015000019B68579C332307EEA1C87FCCD12EB7A9E +:101510004DB604C8A168FF770F3FE7FB77688FEBF4 +:10152000BEBF7BFED712B89F21DB9746593CE85CD3 +:101530009CB658F4488FA3FAA5A7F03C5AC90B06ED +:10154000B203252FC43FD68AFA07F806E36BC1F32E +:10155000FA63AA81C7313A934BCF18AD5CB231130D +:1015600071BE9DC965CD86DC899B233B97CB522BF1 +:10157000D74FE35EE0EF51960EB5E8717F73F40B41 +:101580006F6DA17B740BC286E0BD89D2174C44AF4E +:10159000168BC563BD0DEF1358F431903E9BCAED19 +:1015A00069BD909F5C95E9CD4328A57B1272DFF061 +:1015B000EC92679EC5E397E79877DA70C0DF6527FE +:1015C000E7D3CBBB548A3F06EF23961FDC69CC617F +:1015D00037B18F7883FDC332D622DEDF0DFD7DF07B +:1015E000FEE1ABA9C1FB8706BA4F5E2AF60F73373F +:1015F000280477E9127ECF3F3796C78D4F2E05FA24 +:101600001B69DE1EEB103C0FCDED4E2953BC66F876 +:10161000F5AE0D0B288ED913F184716EF16EE2894F +:1016200030473AAEF34B5E0823FC96FE6AEE5F7ECF +:101630009985F7FA0AE202D7D5FB912F387E19DE99 +:101640001F94FD9C5EF6637AA731F745581FC37C53 +:101650004A63D8ABF76720BD92D2719F53B62B5D1A +:10166000FEA35EBC1DACAF611D5DB44AE5EFC7ECE7 +:1016700036911D04594F6401F72C67AD38683472F8 +:101680003BC6128709FFDAEEBF9F761CEAF1EA6ECD +:10169000A5B88726F127EF5115E9F8FB74853A853F +:1016A000EE578126A37B499753B95F7B3A959F6795 +:1016B000284A77D0FD9CF2B526C7F20CDE4FFB7DA1 +:1016C0004F58DF95EB9A4B683FF3F7268AAB54AE41 +:1016D00008738645F1F3173B06D0F96ABD11F05146 +:1016E00066E7FAE2B2986FA57DD25D749F41CF8E16 +:1016F000E8A1BEDCC2F563790CE03D92338A6E1836 +:10170000BE67C7E8DC24F69B3428607C4594433FE1 +:10171000F6287FBF4D3A5683711B6CDF7710E2319C +:1017200076DA7484EF1595E41990B47604FA7DAFF7 +:10173000A899B8DE2E5AB56F1CEADFF9DB07E38DF6 +:101740000956F4EA07643FE60BFAB7887367C59059 +:10175000C777B622D2B83CB9551E2F8A485334EF0A +:1017600010C9FAF255061EBF073D8F8AA57CD9C75E +:10177000D46FB9A53901F56FF96EC330D4D351696F +:101780005C2E8B97A5651F01BE2A3644D3BB8365AB +:101790009E0223E6CB6A15CAFBBF8B4F473E3DBF77 +:1017A000E2B528E49F1361BE9E68975A178439E812 +:1017B000DEA195C7EBCEAFE849F79566599B2DF8AA +:1017C0009EC1AC45DD6DA8BF8F5A7D46AC3F5A9790 +:1017D000A1C3BCD36ACDC6BC537F1BE5CF8BF32D11 +:1017E000F4837CA5703A976DDB67C4BF4F3244CC5D +:1017F000F7E22B1FF4C2F84F797A732FB42BC0078E +:10180000BD5210CF2F2964972BB6F1F3EE920F2A19 +:10181000900F40EEE6093EA8D8F5DAF7511E2A905F +:10182000FE433AF211F0F37E2ADFB1711CE3DFEFE1 +:10183000473E91760CF22B0C368CDFF17C661AA7B2 +:101840003F948FE1E59E01FC1C5DFB39048D1C7407 +:10185000465F571AB787C5CB4CA46F5D695C1E5AAB +:1018600056ED8E42FA5D7C65DF01DC6729DF0156AB +:10187000DA1E421E043E2A71FE51043FF9179538C4 +:10188000DF28FFFCDBF95EC86125E3F393F3ADD4F9 +:101890008BF9CB7AF1FD24C12F654CE06B576F2E8D +:1018A0007742CE508EE9BD0E313FB74DFB0EE5F7C6 +:1018B000C5FCDC2265D6BA28C40FD217F50F3E103E +:1018C0006994FA049A5CDCBE91CEF14B7A49F857E0 +:1018D000093840DF39636C7E3AB674F24E6495E0A5 +:1018E0009B638F7749AF07FC9DDF4ACF6C11BFEA3E +:1018F00003C6937C23C7CB7D79D2DD386FE8DF87C1 +:10190000FDCB718F7A22F4D8CF51C6E543C22FE5C3 +:1019100032B7FAA1BB074761BB8B96EE0370DE9C22 +:101920008EABD2ACF4BD13FD05F8DE59AF50DCFA36 +:101930009858E71F7BFCB5A8E2017E7E7F427C279A +:10194000F90C7F303E26E16DB2F1387030DC520F79 +:1019500049B8739FB8EF6E2C97F0E3BE51209F4AB1 +:101960003C4A7E95F7F582F996784EDA4FB573FECC +:10197000AE4C3D46E7773A9407F727FCA213E25CAA +:10198000796B3CE371FF1589FB35F78A188B0CB432 +:101990003FD28EC0CF1A7D80FD69BFA716E73C8B72 +:1019A00074BB90D68DFA3FC7EA8C39D06FD999E6CF +:1019B00071F8CE9DF443EFB8EA53A3315EB58B9F27 +:1019C0007793FC5276613FC941B9B8FF54B4EA83BA +:1019D00082E1C8EFBF35D0BE4ED1E3638DE8DFCFE3 +:1019E000DD327318A201EF41A05E3FBB796826BFCC +:1019F00059604D9886F721363F33ED01289F55AF4A +:101A0000D2BB0DD80FCA6FD1A399145F3D11D65226 +:101A1000300AFDF81FA856F4E36FDF32F4316C7F13 +:101A2000BBA56B0C3DB6B13996F24E7D34D907E9B2 +:101A3000F7CA7380D5E2DEC75F84DE3FDC9E2AE210 +:101A4000FC5F752FDC8F6FDD1846EFAC141AED7557 +:101A50003E1C6F4F175A67541AF1EA23DD5B25BF0E +:101A60006C8E9199938650B93909CA0F1A9A1F45FD +:101A70003B72F051CB607C3F92A9D78615737F9A59 +:101A8000EF3BC66ADF2D91707C24C60FEE4F7EDFE0 +:101A900084EB081BDD4FA4EFCFAEF8ED34B48367C1 +:101AA000B7F6B4E1BC4FEF09A3FB03A70DDA77CF7C +:101AB0006EF5DE57F07D29796FF5749AD68F93FC19 +:101AC0007EC37B377FD39E83BCD1B9A50B4B19DD79 +:101AD000FB7E398DD1F76322BEDA89E7084B6A4D68 +:101AE00056BC077312F91EF7B376ABFCFEA599CB73 +:101AF000C1C9DD9974BFB7E46F3C5F52A778F13E6E +:101B0000F2FEA79FA0F30AB3C1CFC4AB09EDFEF369 +:101B1000BAA7A7A1385C76B857E27DFECB5BF9F98E +:101B20008A0EEF321CDC7920C9DEB9DFFC5DFBCB0D +:101B3000320E119FAEBDCF2FF12CD74F6F023F8CCD +:101B400018E2C7DB674BE790BF7C61A99BD24BCA09 +:101B5000B1B5B7231F5BA2E9BEC01FEB9F51F1BD1A +:101B6000A8F25D83AFE13A78546434BD93F2D9D2E0 +:101B700025B48F7A616915A592DE320E77C7AE461D +:101B8000FAEEB3FACC06BC9FFB4664B4B003B69041 +:101B900074EDECDEB19CD7B91F70FA4AB8CF6D9DD9 +:101BA0001985F36A7C3EB66124D23522DA8A7E5FDB +:101BB000A93847726A3DF7ABCF98A37F930FF43DE6 +:101BC000B3614A02BE3737BBF1DE69585EB247B136 +:101BD000E27AC0B1675214AEDB3ED5B744E1FDA84E +:101BE0004FD7CB7B555EFA3B54A3F2D8146C3FCA57 +:101BF000A767F60CBE758D7C32F2829EEEBF9E8783 +:101C0000728A935C0BA73809FCC4E2B991D9AFF38F +:101C1000F84AFB3A57ACF36E17F37E34DD26F73102 +:101C2000A83C77042F3FBD61E744ECEFEC668315D9 +:101C3000E1FE6CB381FA9F07EB331DC07B662B5F1F +:101C4000F7601ED7CB67B7F2F5CDBC3ABEBE295FB1 +:101C50006070F2FBA25A7ECC0D6847EFFB74F25E17 +:101C6000C83C279FDF3CB09738DF60BE8D6175743C +:101C70008FEC9B9E170DE6DBF9925F857E68E7D7B8 +:101C8000CEF844E013E51DF955F2C3BCF57CDFDE68 +:101C900056373807F94EF247F03B59D546C6DF575D +:101CA000D485D37BB89322ED06B40F53E25AC620F5 +:101CB0005A3E4EE77E809AAB73E2BD37566D0AF905 +:101CC000CECE8A74EE57457465C4EFDE742B3FCFD9 +:101CD00029EE7FC914269286767B5284ED0B3B3425 +:101CE000793AFDAE7BF4C0CF936EB73DDADDC1D853 +:101CF0002FD30BEED1C37C2665DA767783FCF3BF56 +:101D00009AC0F3B7D9861A20BF4C9978CF18C8D794 +:101D1000A73B9F4A0F18E7EC962E69383F28FF191A +:101D200096D7C5BB7F8E69A5B80F7649691DB424C7 +:101D3000C3DFFEFD3D96A37FB4FBF32D0696EE18A0 +:101D40008079097FE8B425DDF9ABF4F88EE5C58C20 +:101D50003D4EE7F53CFC1E0EFCB8CC09784F8AF3EB +:101D60005BB1BC975313742FC7C1EF9FC9FB52F2ED +:101D70003E545FFF7DB20DB7729FEC9281FF1D2A2A +:101D8000C5A9BD0FA634FC89DEF9A9F6B09630A22C +:101D900083F69E4D39BE53771BDD0BA2FB874C6F3C +:101DA000277D3357FA3B68AC87F9DF296089FCFC53 +:101DB000C1A3821F4F2F653D7A80E89F7FB739CA44 +:101DC0000E705C98E8EB85FA2032DCFD27C4D7E979 +:101DD0000DD5A90BE3F01EAAC9910FEDCF78F97DBF +:101DE000CE32E1B7B2CDF1422FA8BE3BA15D534642 +:101DF000DF4D6887DE177C7521C397FE23D42B192E +:101E00007C9D04EDE83C5DDEF2BBE2B1DD85ED4F8B +:101E1000F4980D709B0006BCA7351EFA1C61A3F751 +:101E2000AA984AFBCF5EFE7E929E79A26CF8EED510 +:101E300033E9E23E11DD13947492F8EF4017181A5B +:101E4000FD599D991910EEBE6C03FDFD2F491FF938 +:101E5000CEE2C2DD3CFE427724451EE348A7CDE238 +:101E6000EF9F75B08B6F91BF0A62E9D1E89F0D3388 +:101E700043DBC9111B8DD8F5776D2FFF9D2EFC928A +:101E8000C16C70E03B92A5A2CD58B5D08EEF5B2D12 +:101E90008C37D37B250B5FE84EFCC196FC9005B6D2 +:101EA000631B62895F5666A884FFB9F58CDE1D2A24 +:101EB000A84FA6F394F9F5364AA3DA12A9FCEC6F01 +:101EC000DEC9E27A89D3A7E07FBA8CA6734BFFD331 +:101ED0009B52D6D97BA79166BACFBBF020B76B0BCC +:101EE000A7CABFC7C2EFAFBB0438AEC81A8A0BB9C6 +:101EF0003ADC53E7EF57BAF0BE007EE734507D6717 +:101F0000EF574AFC9A04DD82DFB39C7A303391DECE +:101F10007F14EF594E17ED9AC5BDB3CEDEB5BC4F59 +:101F2000B47B226A5C13F2DD746769C8772DF59E75 +:101F30003007FACF86D4487A47E13E37F8979AF5CA +:101F40004C8B1EF1302D9BBF733975BAB6DE90FDF8 +:101F500039E97343768777920CA88F4D2E6DFBEC91 +:101F6000AEC20EF5657DBFF65DD15423D94F3DBE9F +:101F70003B0BF969E25D51F40FD1FFBFECB410FFE8 +:101F80009BC43BB8CD2C2B11F5C2ADBE27FBFFDBAC +:101F9000FBB1C1EFC406BF03DB7FEB424D7E60DDCA +:101FA0000F35ED6FAB5FAEA91FEC5BADA9CF6CFA3F +:101FB00099263FB4F9394DFBE1473669EA47B6BC8B +:101FC000A4A9BFFDCC0E4DFE8ED63F68DADFD9B690 +:101FD0005793CF61EF68DAE79A3FD0E4C75AFF57CB +:101FE000D3FEAEC4139AFAF1F6F39AFA097DAE68FD +:101FF000F2058E2F35ED3F37BA577745BF22EA0CF1 +:10200000F1AD3A4361F844F9E5A62966D4076BBA05 +:102010000A7D24F86FB9B0D3AC07A37BAC63D56C51 +:102020001FF15F3DFFBBA0C1764F7FDEE5C4F81F07 +:102030007B8DDF6B8B067F521F307E8CD3CC02FFF3 +:10204000EE5D6C9E55938F77256ADA77996ED7D4BB +:1020500027B9FB68EA53E63834F9B4AA119AF65D59 +:10206000973835F90C4F9EA67DF71A9726DFB37681 +:10207000BAA67DEFF56E4D7D5FEF1C4D7DFFAD5532 +:102080009AFCC0BA259AF6B7D57B34F5837D359A8C +:10209000FACCA65A4D7E68F37A4DFBE147BC9AFA1A +:1020A000912D5B35F5B79FA9D3E4EF68ADD7B4BFE9 +:1020B000B3CDA7C9E7B0839AF6B9E6F735F9B1D63B +:1020C0004F34EDEF4A3CA6A91F6F3FABA9977ECED8 +:1020D000843E9F6BCB85DF53E0F897E6FBF6F76E07 +:1020E0007728741FEA5CD76EF27DC5963015FD2403 +:1020F00017C5996C781011F515DE27B7F1F33985FE +:1021000014AF8A237F884C941DCF0B81DF1085ABE1 +:10211000B68C0CF4AB23FCFE5BEAF5CC9BF7DFDA64 +:1021200084FFDCD5EEBE88F231AF6EFB387A9F9823 +:102130007956221CF2FDBF7783DE6D95E978F3199D +:10214000A60FF0170F86D5A60EF99A38C178F305B9 +:1021500086EFC1B6F72BE222F8C7BD1706F4BF160B +:10216000D617F8F7236B979AE96FC7FF6CA995F21A +:10217000EB962652FEFF003A29BF47008000000080 +:102180001F8B08000000000000FFED7D0B78544518 +:102190009670DDEEDB8F249DD07975779EDC3C490F +:1021A00048089DF0D8003E3A216040C0E635044919 +:1021B000A4C1A84143BA81F84F7475BB311002B273 +:1021C000B391D11095C1860164199D092EA3D1093F +:1021D0009AF09AE03A4C601CC5D91937A0A3E28E58 +:1021E000101EE3CFEE8FC37FCEA97B93BE9D0E382A +:1021F000FE3AFFF73FFAFBB4385575AB4E559D7369 +:10220000EA3CAA2AAD5E898922636DDE1C4A9FF3EF +:10221000DA9998C9D8366F31C1DBBD0E82FDDE7206 +:102220004A777A9D94BFCB5B41F01EAF8BD2BDDE67 +:102230001A4AF7793D54FE92B781E09F7A7D94B6B1 +:102240007B9B29FF156F0BC107BC6D04BFEAF553DB +:10225000DAE1DD4BE91BDE762AEFF47610FCA6B757 +:102260008BE02E6F0FC187BCBD041FF19E26F8982E +:10227000B78FD21EEF6794BEEDEDA7F277BC57097A +:10228000BE8EBFDB19FC2ACD9FE431263097E67A5B +:102290001EC2CCC92632F600FE4B82FFE24688CC35 +:1022A000C2D8FD8CFF3ED7B09A76139477FEF23FEA +:1022B0008502C674A58C8D1F0F6962F6CEC634C622 +:1022C00026B075E64F7218D34057D76307FB094E07 +:1022D000191319D6C3DF752DFEDFC7583CFCBF9418 +:1022E000E5784C836953091442FBBE55827F771A07 +:1022F00055D7203EAB8D1CBF695A1395573E2CF81D +:102300000D02635522F3E98B18FB7D5854011BC164 +:10231000D8258F2E47C47221DC0E8304F88F3A44EF +:102320000E7E5D2C8EB1A59D861D9BD206F1AA84E2 +:10233000EF35F0FD2B561A0CAB643D3AC403F21D89 +:10234000DA18C69EB7B8A64B90FF608AC6A787F674 +:1023500099C99FED8C64EC2D8B6B06E65FF2DC7700 +:102360000C1B7FC06CCFC67E661BBAE21741FFFD17 +:10237000C7B5F69DD2F0F3E16E29676CDC0DCADFBC +:102380003C97EC023CCAFFA275E1FC9FD04556F891 +:10239000F3012F49E0784A1A553ADBEA5A82F87C71 +:1023A00019E9B9470353F8E56DABF6AC812155AE99 +:1023B000CA1AE182EFEE822563198CCD65928E41B7 +:1023C000F97CE6389A064D2D642E8217311FA56FD1 +:1023D000C5BBAAB19DC5CC4FB06BB22135D4B88274 +:1023E000F172CB78B9657C94F471ABAB8EE3E520E8 +:1023F000BC4E4CBA231BC7A5E0F59655A27A73587C +:10240000FF76C4EFCB83173F113286D2C7774017D0 +:1024100026681EEB313DAC73A38ED1F78D8F087EFD +:10242000A46B852E2A9991B7FB18E40B817402F4F2 +:102430005184FCD29F3A3792E8E449091A7C7092A1 +:10244000D6A71F0BE3D4F8B3052DD1875E00FC1E81 +:102450008803FA481F9E0EEA9A210DE01FA0AF677D +:10246000B0BDF3AFFF5D0ECE97FBCD4912CE57A3A3 +:1024700006D601E8D8F7B6D6BE5B92991460ED9403 +:10248000317EA46B26DAED73C7E07AB1A54EA8DFE2 +:10249000AD650DFBF387F6FB2AAE17B47FC2A62B02 +:1024A000F753BB9CCF95F29FE2FAC563CAEBAD5ED2 +:1024B000F569AD16F03F71E89C5E1A13621C0D6F52 +:1024C000E76606E0EFEE3833DD6142E4FAF2E74515 +:1024D0000EE69F94E944A11FAD3ED2B5C314881700 +:1024E000EF17E8F9E74437D140CF1944CF9FF8E020 +:1024F000D3390669C42248FB606ABA2075BD60D62C +:1025000023DD2C67764AAB9993D20760F9917E9DC3 +:10251000BEA7F438EF0FB276CAAF2BBED782F47CD9 +:10252000BFC6958A702DEBA57C37EB2FB3C1FC2D70 +:102530006C5E7BD40658CF6F796A5A02CCEF3CFFB1 +:10254000B2A398CEDD257CE293883F7A10AF3EC1DE +:10255000B33E11FABFFBA592F549903F47CBD78513 +:10256000FD2B5F17457E048F1BF8A1978FCB41E3AE +:10257000D24695ABF8A1F209E610A09DFE8306FFB6 +:10258000CEB400FE287EE8DF93508E89FDF7E07A16 +:10259000BBDF34C4E07A3F08E21BC72938186B80E0 +:1025A000FE90D62A63882A88DE1F62E176ACF7B9EE +:1025B0004CDF9FA730A2EFCF05E66040BF1774A69F +:1025C0006601E55AAACB5604F8AC60BE2606E56E55 +:1025D000CD4B05384F2325D7A744D71FB53715A6B0 +:1025E000A1FCF7A70A28FFF719EC8D69AAFD845D05 +:1025F0008F4021E361389F3FC076C70EC54B283E10 +:10260000F69F421463063DF3198B88BFD944E4EB6F +:10261000443DF157234E6D06F6E3943CA6A1ED9F91 +:1026200090F1EDF94A4B74EF83F1EC1642F5C3F7E4 +:102630002B43F8603F243F2C8CFAD1A7713E56FA09 +:1026400063A6BE6427D0756A844B978682C116C77D +:10265000E58B99CB979EB44F33717DE64CDEA8C8CD +:10266000656A8FDDC6E5D1099DE443F844499A1DAA +:1026700024D7809CBDABF897A7118FBB8CA62E2DBD +:10268000A4EC16DD9FFA947D307D70FFBD4BD97FA1 +:102690006FE1FBEF1C99B5EF12BBBAF17BC6EC3AC8 +:1026A000C42F97FD5E998F6DB8DF2AF271C87E0B3B +:1026B00003EBC5F913252B8374B5C0C7BF3A25DCDE +:1026C0008F7CC436E7D2F8F4B2FC0CFEDE5AC15857 +:1026D000A651C613FE4B70195966CE209C54635602 +:1026E000C1291E9BAAFEC80649559EE6CB51956797 +:1026F00034DB5570564BB1AAFEA836870ACEF59743 +:10270000ABEAE7ED75AAE031ED15AAFA633B5CAAE6 +:10271000F2C2AE1A55F9B81E8F0A9ED0DBA0AAFFEE +:1027200077A77DAAF2497DCDAAF2299FB5A8E05BE3 +:10273000FBDB54F56FBFEA579597B07F56954F3541 +:10274000EE57C1D3CCAFABEABF80FB16F0CF1DB6BE +:102750006E55FE0CE9B8EABB3B734EAAE017E47570 +:10276000F62D0E27BE682DE7FBD16CFB07AA765825 +:10277000E768BEFE613C6F7BCF1F0B514E6ED7F4F6 +:10278000A721DD4A5A7322F27166F1DC4340662CC0 +:10279000DBB1AA14C55B4EF95387301DEDDC5F8AAF +:1027A0006C925F71F210A605AE8BA5D01CB3D74416 +:1027B0001FC6B4C85338D58AA834CC3D8CE944DF51 +:1027C000AAA928575F785C3F1AF9282A46A14F0723 +:1027D000D1677D8286F8B97EB1C98FF2C732C52430 +:1027E000329013961F5AD6B1024C8B9A316DF61A5D +:1027F000995F0FFA809751BAC96B66FE6C2067AF7C +:102800008DE0FA93F795A7433B23AB4433AA99E6AF +:10281000518F2548D0BEF5E5969C5D76C6D6EDB0C5 +:10282000CFD7E542FF199EC53BA2014E638E05300E +:102830007F1698233699B1253BDF76FAF287C29747 +:10284000339D4D2417C4F65CD4FF947637967E6E84 +:10285000D79821DFF74BE71198F7ADF1E1F41DC2EE +:1028600025995FA75D470BB60BF99EF6107CFC4CD3 +:102870001ADF7F97A4737D0A8784EB66E5CBC6AC2D +:10288000A0A78C80B9DC3AA9E10CEAF0A2D927A074 +:102890007C62D7E07B902B89582983E0DBC3014E13 +:1028A0004058626C7F96EBC7D8AFD5C5D8D900FA2F +:1028B00049A851C35B619ECF660EE2A35BAAF18972 +:1028C0003006DD8F9D763BF4B3AD0AC60BF0563D66 +:1028D000D737947AA3348CF6F72FD3F87ECEAECDCB +:1028E000B7A39EF4A53C9EE7BCFD8B3ECE447BEB9C +:1028F0002AA589351EC105F2CD5AE9B4FBA09EAECA +:1029000011E62384DEF28B3491BED71D7E4490A065 +:10291000DEA76912C189957E1A77520DB41B80BF5C +:102920004DF40966C8B73DE613103F9BD96967F0BF +:102930001D335A88FED7C83C616BF8CBA28F410F7C +:10294000D3799D76ACA7BB13E8331F27D46366B851 +:102950004EC9E347B010EBA3A4863E0D73DC409F45 +:102960008F4A7DD443FBC5DD26290BE8FB85C5A630 +:102970008A1D21DAFB549E9F0D31EAFE2D5A3E1F1F +:102980008ADCBE6CE6EBA8F0F19A68A692E36B5283 +:10299000C65B6F84AFB5CDC85C01F86E857ECCD0C8 +:1029A000BEE1AB55661C3FE8D04EEA4FE4F264C787 +:1029B0008F72C86E0A5EC721F408943FA208E9A38B +:1029C000CFDF087C68A8D2DB516FB2FE4393807BD7 +:1029D00073226B1150BE5853CA7A44DCD74457AEA9 +:1029E00033843E7933BA54D64FD99F83D74B773D42 +:1029F000E3FD129CEF7FD531D4C7561F8F8F710531 +:102A0000D0534C3AA7CB62D6A245FE98CCDA29BD6A +:102A100085F5527A1BEBA7D4C1CC22A6A5CC4E6972 +:102A20001973523A9D79282D672D94CE64ED94CE7A +:102A300062BD94823D43A99399C9EE9A07FB37A6DC +:102A40000B9893D2EF310FA599E99C7E2B580BC1BF +:102A500077B3764A3B80EF243DFA018C9476829CD2 +:102A6000C3F44D9073987679252665A31F2087D2ED +:102A7000235E3BA5C7BCC594F6781D54EF6D6F3936 +:102A8000A5EF789D949EF05650DAEB7551BD53DE5C +:102A90001A4ADFF57A287DCFDB40E969AF8FD2DFB4 +:102AA000799B291DA5077EC6F9CDE92B447D3EF50E +:102AB00023BD4302F9EC91E5D26187E699DCF1B8D8 +:102AC0006E1A66403A285B2320FD5973340E3FA4EA +:102AD0009B72560BF742BAE104D7DF0CD648D20FEF +:102AE000AD6DF58204ED76087DDA0858CBE9E9A9E9 +:102AF000738D209F4B3AD9BA083BC2194F1981EE0A +:102B000076E83CFD3BA0BC64A734D7087BD6E4C87C +:102B100053FFB18FC3543EE9086B34033C2B3DFB9C +:102B2000A93881E381C2EF7B3B73E6AECD443C25FF +:102B3000C2F3C534302C51BF7EC444FA7561DBD971 +:102B4000420DC0931A4C45681706D4EB42BA1FAE2B +:102B50005E70B9F2DDB65596469C870D9F805A0E81 +:102B600059A9197D85ABF3D5ED6ABE5EFF4C7B8319 +:102B7000FE03EB0937686F7F96A3327DC2FF7E3A72 +:102B80000FA66FDDF58FF66BC80F648EC1FD74570D +:102B9000349733FDA09FEE04BC77C5C8F0C64C1A2D +:102BA00017CA435CB70D9BD2FD3E80778539571F0E +:102BB000C7F27FD4D87742D1AE70D7A65C8233C932 +:102BC0003FB121C69313938FFA3CDF975A931F0DA1 +:102BD0009302F8BF399DCBAFADB75CE9DD81764498 +:102BE000B38665C1773B9B976FCC81767EBC19F429 +:102BF000078047DC5ABD310BCAD3376A266A65198C +:102C00008778FC7873F59E4DA85F258F8EC98676F0 +:102C1000336479991ADB57B806E8BC55AFB6A79567 +:102C2000F49F647EA98666CE826C4D95EDF41D3AC4 +:102C30005611B8DFFD4CC6EF57593CD5DDCEFD57D8 +:102C40008691E1FE2760FC2523B9BFC3B2CE48FEC2 +:102C50000E4BF27F9DBC03CA2DDB347654E9446BE6 +:102C6000ED5A1DEAFB8B593BF2E30E817FEF4BE1FE +:102C70007A21280AE97303ECF2ADDED38B3203FC30 +:102C800084B60A9F80F67BC9C85AA10FF79FE40754 +:102C900005B4FB2D152EC11589F68187CACF65B9FC +:102CA0007E920EF8D92AE1FB40FD92B912705DA127 +:102CB000DF8A76D2F35851607FA7B3F83CAC073B6C +:102CC00099F4D5757AC22B78BE4E65971EC0F695DD +:102CD000750C2EFF7E06B7AB773D015D201F4CE2E1 +:102CE00076F389DD89A43FCE690D77A0FD74E2A952 +:102CF000D165046F99EC403DF2C4EEC9D3319DB368 +:102D00006526D53B21B01EB487E76CB95BC4FCD403 +:102D10000CC00BDB3BA3277A9CB3E541F9FB47CB07 +:102D2000B0BC58E3FB09DA91C58DFB22D04E9E1C46 +:102D3000F94A12A627347DF5DDD0FF5D66F62BDC5F +:102D40009E9D1BE3FEB11CFE31F7A9741DEAD7BF9F +:102D50004B4FA7F59CCF1CC4075083ECBA5BF6F62B +:102D60001E064D8ADDD6DE3F15CC5CE6E8301FC17D +:102D7000B4B4CB5E86D357D6E33C82E9F45E4F19F8 +:102D8000AA2FE5A75B8E60BA24D7F53B9C9F17FF5F +:102D9000E17BAFBC08F0C8C7EBCDA807653ED137D3 +:102DA0006327F9EB740CF9216B92A7458B046C74C3 +:102DB000C6A07C78F6695183FBB921AD250C61C3AF +:102DC0007DE91AB40B7745B7D4D0B8B3C219CEE3B6 +:102DD000DBB00F215D64453B63909F802F691D3EF2 +:102DE00093E9D310ED3147637E18CF1FA817CEE1CA +:102DF000F303F55AC204EA274620FB13D406DCBFCE +:102E00006DF2FEDDC63C09381FD648CF0EF4EB64E8 +:102E10009570FE67919C2EB07AD344FA849CCD962F +:102E200016CF9DB80E5697E8EB0BA43BD80607F4D7 +:102E300091748219DAD75B050E839C21BCF0877EE2 +:102E40000C8BC9427A8D82BFB502DA0BD033701C6D +:102E5000F34C83DF2974179BC1C73542A6BFAC650D +:102E6000BC3D05DFB80C2E9F016F4983F868657C77 +:102E7000601C9A007C02EAD1F806F066761BD20547 +:102E8000487A81A74C1203C75FAD7184A15D647A53 +:102E9000F5FBE84F8942390278FE53F72423F269A3 +:102EA000F0387232D208DF46D087516F9FE9E2FCDA +:102EB000DB58E911C83E4218C79F2C3AD01F68352D +:102EC000AD167401E3B526F37D7A66A5A71BE5CAA6 +:102ED000CCE2083BD2F79DAC7D9D99F3F7914CC0B5 +:102EE0006F141BF899D8C441BDF0474FBF7B1297B0 +:102EF0003499B597E4E2FEF9F8FDB370FDB63E3AB9 +:102F0000B307F14FCC79AA3B061A745E94D77D19AA +:102F1000F7EBA46C133F0E1C479207E040BF448DB3 +:102F2000BA1CE841052B7465131AA271BFD144E4A1 +:102F3000CF9C817A4A9486E43BC829614148FD339D +:102F400088AEE4F957D6E7AE8C4C5A37AB89AF035D +:102F5000EBB71B1746CA8355D609FA6D04361F0115 +:102F600074DF58A6F50B68D762FD28ACCFE29D91BF +:102F700043D769874E9A3903E5F4C31AF36E367462 +:102F80005E81DC7E4B7AEDC371540EF9A291FC7D1B +:102F900001F86A43C1EAF5B859FD6DAC6BEE8CB42B +:102FA000A1F989C90B66E23E9B58CB68FD83CB47EC +:102FB0003DA65E57B237C7A3FF88F9BBBEC17ACE24 +:102FC0004CDE5586FA7CF0BA2A74971A1B7A5F1089 +:102FD00033395FA646D84F95935E21929EE04C11FF +:102FE000E303EDA20D197C1FBAFD3513ED43EC236D +:102FF000A31FB75C7B57EF93B9B00EA5573468AEEB +:10300000B0A3EF1CFAE14C48A7FDEADDD5FF0AF5B5 +:10301000A67D651A87F96FB0BE19E810F1F5809D9D +:1030200001F0DA2FF6B4A0A3A4B192D971DF55FA5A +:10303000D923F7F30B9DDF49F23557643B490E82E4 +:10304000651E402F0069897E78197356B690DD6839 +:10305000CDCC07598D6EBDF625B45FFE49CFD0EFBC +:1030600038AF42D295C0F8E7554ABA65E8C7175954 +:1030700039EA11F32BEC943FBFD2CEF38D3C7F4164 +:103080008583F217543A78BE09F2613E1656F87BF2 +:10309000BDD0EE42538CA4413F78A593975F355045 +:1030A000F93B600F6402C98787F949DEB77CA6E166 +:1030B000F1124FB85F005C0D91453D12CEDF7D1AD5 +:1030C0007B162486149199017EB6C2E9D742F9F3A2 +:1030D000CC9F8013F946F56A6736E4BF912C9A714C +:1030E0007C6F38C06EC6F9AB1569DEE907F01B3599 +:1030F000C914CFD821FBAD7D2B8CE467055D87FC1F +:10310000AC6C45A2ACC7F0F26DCBCD7ED4C7400EFF +:10311000D23AF6DF27921E00F2F0ED1CD48B5ECA85 +:10312000B4874948B76A7EB3542F2FA1F62A99195C +:10313000EDF25995BCBDC697347E0DEA55A679339C +:10314000910E1AF7323BDAAFCF569F2A8B45789B08 +:10315000DDCEE5875A2E34566F392EE1783C1A734E +:1031600016D5E77EAD464FE92EAD30C8CFB4DED2DE +:10317000A0FC182A6FEC3DD84E4255A97D13D4B35C +:10318000C038D18FBD4DCFF37DF7881467B0548B15 +:103190005DE68241FE4E91A7D0827C1845F245C57E +:1031A0005FA35F52C33F92F914F85DC471F97631A1 +:1031B0003BC9955DEA7A20273528AF52DAD4F96702 +:1031C000B204C52FA59A87E079B67AB8DC0B1EE762 +:1031D000E0B8BAC246D1B8347C5C28D7203FD77457 +:1031E00088F2732B45BB24A1BC6B3F85E31FF5928E +:1031F000C8BA009E555D3413E969D6660DB94366B9 +:10320000B35E920B371BB7E2DF081E67F0F8366437 +:103210006869DF1CD007D71B491F6C7DC4A4C1B8E7 +:1032200022E85BE1E8573897551A9E09F33022539C +:10323000D6D7AF6BB93C6934119DEAAC8FE504FA7F +:103240001F84D1A523B0BEEE7AECBC728A1BE9685C +:10325000DCC172AC58966393FA607C2AFF73389392 +:1032600002E6F7D6FE18157CFBD54455FD12102E4C +:1032700081E5538D79AAF269E6712AF80EDB1455BF +:10328000FD19D254157C67CE9DAAFAB3EDF355F023 +:103290005DC54B54F5E73AEE5595CF2F7F4855BEA7 +:1032A000D0B946052FAAF87B55FDC5AE4655F99213 +:1032B0009A2755E5C1F693929666723FCF569BE7E3 +:1032C000A483E48B4B70460EAD67A914FB03D73D76 +:1032D0002A82EB53C1F51AE5F57841E0FDB1FE48CD +:1032E0000DF29DE27F63ED912AFF5CD7E4C9C63EF3 +:1032F00013FA72ECEF23DDB213DC1FC5FCFC3BC5F7 +:103300007FD5FD04D483F65647A65B71BF43BFABA0 +:103310004B0FFDF935E4BFB736D70BB40F6EAEE7F0 +:103320007E95AB7AE68A0DC08385F37EE5788E8242 +:1033300027734470FF6018CFDF26FB959E43BF5272 +:1033400036633FB0287E7817B59B50ACF7A17F4617 +:10335000A8F6087A945B2E66364828079753FF979D +:103360002BEC2358887956D256AF8D39A07D5BBDA2 +:103370006FAD1EC656973969CBB3D0BCCDC3C81F3D +:10338000F368E6942D6B81E7FF2153A2754910F98C +:103390003C3F5FF7C6B93DD05F6B95A508E56A7005 +:1033A0007992BBF3E2B11B943FBFF2D50FEEBFD1D0 +:1033B000F7751D679A02CA87F58B56243247001DA0 +:1033C0004886D07EF91FC874E59EAC273FD6335A95 +:1033D000D793C8CF1726FFD7C4BDF0DD79E9CA3D22 +:1033E000A8A743FE0F301FEAD1BC9ECFBC44E729FB +:1033F00052F340BF47FD3B2C34DD1E94DB17AD95E7 +:10340000FDE8075A1DA997D0CE4F327E467EEA0EC0 +:103410001DB7AB83EDF7E707ECED76B2BFF7CBED69 +:10342000EC9653AD997FCF8C3E265AE4F84088F94C +:10343000D046B50928AF12ABC54F02F9A23B524F97 +:103440007E048B49F63B986A547E01C56FD01D7986 +:10345000BF80746FE95A417E7AF417607B07E57587 +:1034600009F6172419FFB4E8E3D81BB5CF06F223F9 +:103470008410FD04E1A1F82782FBF1A33E81FBCC7F +:10348000CA70D22782C77D39B3E450663CF248FF48 +:10349000C93B507E9FD2D17E381CBD8449E1CC1FF0 +:1034A000D07E6F26B7EF23726254F991F644E60F8F +:1034B000F45FB364F32711320C5BCC487DDFC65157 +:1034C000D8DFDBBCBF133ABB8DF441D8F6D0FE7B0E +:1034D0004FE6E7EE5C4669AB6C97B7011F63FA9C59 +:1034E000D74CFAD936E03F84B77B254AFDDE1C4A2B +:1034F000777AED54BECB5B4CF01EAF83E0BDDE723D +:103500004AF7799D94FF92B782E09F7A5D94B67BEB +:103510006B28FF15AF87E003DE06825F457D5044D0 +:103520003F7533A56F785BA8BCD3DB46F09B5E3F4D +:10353000A55DDEBD947FC8DB4EF0116F07C1C7BC2F +:103540005D04F7787B287DDBDB4BF9EF784F13DCEC +:103550002B8F93B1E65E2FFA2B5CA284FADDB3AE1B +:103560006A33EAD7B6651A338AF336976605FA39AD +:10357000B655F2789F6D9586FC40A087FA519FB3AF +:103580002D7BFAF8342A5F40E55BB149304AACAB99 +:10359000B8FECA56EAA99E150F02C177DB6A2BFD59 +:1035A0005A805BB2C3A9DCBA4A24BBED798D273AB5 +:1035B0009BEB5D24BFAD3AAE3F28741021FBE9229E +:1035C000B2444A976573FCA33242EF2319594AFC6F +:1035D000A4B907C767AB82F121BE55F5468C5F5A87 +:1035E000EF83F149A43FAE3A047824C378117FC039 +:1035F00087FCC26C19D797AD55EB08AFE465F3941F +:10360000786734DAE96D9EFAB9846FA5487ECD36C5 +:10361000D7A1E8FB504ECAE77CACF1E14E7FFE50EB +:103620007C3282F0DFC6B8DD900CFAD2FE10E300E7 +:103630008B47A9C7FD788F1943FAF126CB7A62B27E +:10364000C0F98F3D2C12FF6D67A0F7C177CF817E47 +:10365000E7433950BA6F15FAAB1ECD724DCC023C20 +:103660007E248D3F24021C53CEDB4FAF17F7A01EE4 +:103670000DEB7DAE09F2373EB8D989B671EC6669BB +:103680002DB25BDBB25713D0FF952CA8D74749CB9F +:10369000653CB63B787BCFD58BE44FB6AE3A90769F +:1036A00084F75B86FD268EFA7D18BA613216481AB9 +:1036B0001419C955E245EC2FECA1CDE5D85FFC66A5 +:1036C00087D25F21F6F775E769E4E365565708BCD2 +:1036D0008693273793238BB322E3488E24B1249417 +:1036E00023CFEBB8DCF29DE4FA241D869934B41F95 +:1036F000257EAEC4D383E3E835323D241942C76149 +:10370000570DE8FD3EAAB7DDB1C949E74B303E0B86 +:1037100045AB756C05AEF3EA9270F3DA10F4A0A431 +:103720005B508E01DFDF8B4623B5B3B99CB7A3E1B5 +:10373000EDDCCA56115C6232FB42C86B257D5A6EC5 +:10374000E7812C4EB7490FBEB4F118AEEFDB3A3A21 +:1037500013F49CC6BF11ED04DF092DC9D7446DFBDE +:103760008E3D017835CBE3794EEFCFB523FF407B1B +:10377000F92857915FF2C97FC16605CCBBF2DD5ACB +:10378000D98FFDA36B1BA229BE5CB52E0CF5A33609 +:1037900066247AB0EA3CD18501F46045BA0C411F39 +:1037A000FBB2F44A3CD5543211E3327C5F9E8A72FC +:1037B00009F03E581D45FBE1D465EFDE3916E05BAC +:1037C000AE8876D4CB9EABE5E71327FD5143E726C1 +:1037D000DE7C9CDB7DB7FDB7B21EF47B27C8E9B366 +:1037E00068E7417A4B33B377C1BADC526D22FFCD23 +:1037F000AD57C5B381761AB9A4C7A37DC1FD3553B2 +:10380000FAA13C80FE267DA6AE0F33AA453D23A13A +:103810004F9D6FAB3A70661AF4D356CB3F6EBBF632 +:10382000FE71847DF51AF29300F529F49340FE4D64 +:10383000D19780E716371A19C973EB32A319E541FE +:10384000B7259CE45FDB6213E9A11B325787A19E79 +:103850006CA8AA8FC674A4DEB7037DA7DDBBFF7D6D +:103860009E2D81E42D3F7F8184590CFAC0BD7AAE34 +:10387000E4F8FAB64CCB4479A9A1F2C3BBFF7D8B27 +:103880000F7D07AC85F090342C910F7E00BE9BE23B +:10389000D402DF2F40674E44F874AEAB07E54342D5 +:1038A0009CAF1B8BB69ACE56D2F9E2CA38E2335D92 +:1038B000B587E931BFB2C818C8E70A9FFCB5FCFF5D +:1038C000B41CE7BB991CB859BB37E3F79FA573BE7F +:1038D00019CE9E360C234F15FB18CF9A638A6C4B7A +:1038E000FBEA597D48FDEAF66CCE67C57A7E3E64F8 +:1038F0004EC5F4728AC3F8FA443CC79693CDF9A931 +:10390000CD124971E2B674D6857103DF720DF7F7F7 +:10391000C4F1FFDA2AD3C93FD42A78A27D19783EB0 +:10392000C29586EBD706731409FDB7A672B9CEFC13 +:103930001E33C6ABA19D9A40FCC1DEF3A9E9989164 +:103940003E4CFE0B2DF19EA40FF0B7A35F1CFD179C +:10395000C1DFDDDAAF866FBFAA864B984E054F35C3 +:10396000AAE16966356CC9E67AFA1D3675FE0C491E +:103970000D27A71C09D3F073EDA6017FB344F0BB5C +:1039800099017EA00D9A7601E725A5AF96FCB2AD10 +:10399000A9DCDF935CAFF67324B296B53102F96D02 +:1039A00054F9B6FC5502FA736CD5EA7C9807158C6D +:1039B000CB8AF4BF24D7959F8D71E9027EEE3A4BF6 +:1039C000EBE9CDC575688B233E4A93CF050DDD1F0E +:1039D000B7D0B89576900F7C01E345FA0F842FE6B7 +:1039E000BA2667C7733EF005EE97F97D3AE403A562 +:1039F000BFE1F841E1C762396EA29CABB922B7A51D +:103A00009CABA997CFC775049DC7B9925C46E78167 +:103A1000AEF4AE090FC577C867BE6CCE77986E94CA +:103A2000CFD720DFF9F49CEF30DFF0D52A6728FDEF +:103A3000F0BCBCAF3CB437CCFC71C0F856B647AB59 +:103A40006077478239F0BCD343F80F74BA37333A02 +:103A5000475A2B0FE78B33BFDBD308E95B5A970B31 +:103A6000D76765D6593D8F33F5EB51FE9E97F7DF4B +:103A70000D82DD385AC094DBA58D66BB11FDBDCC2F +:103A80009FA1F257287E87D52BD2AC3180FF8801C9 +:103A90003F82D34CE74DE333C98F1135D571372BB6 +:103AA000043CF7CC986F04A2DC854E5590C78F6517 +:103AB00097FDD0973C385E03FAAB02CE2319440F32 +:103AC00023B97335954901E7CA5B65FFC5001F9BA4 +:103AD0009697607F3FCC96783C8679D672FF9FDAC6 +:103AE0005F66B86A53B533D87EB2AADF56D92F7253 +:103AF000F3F6D5FE37C3D5F461DACF0E6ADF1CB218 +:103B0000FDC176D57EBCAF111F6F433E18CEFFB509 +:103B10005F96A71B6C9E5EF47FE918D89514070684 +:103B2000FA98886A23FF69C3F979535DB2DA0FA660 +:103B3000637E921FCF47D690FC48603E8ADF59983B +:103B400087F2D7474DE7F1BB60B9711379C1988708 +:103B5000A1DE00FDA9F2573FC2F7D346C1EE423CB9 +:103B600083C7F3FF8ADDAB891CDF4BFA734AB86465 +:103B7000B881DEDBEA7525E3F71BC23D3518EBFEA5 +:103B80003CBB2E763DE83D1B30C6087C7635BB71CC +:103B9000BECF84FB24A78FF5711AA227CBDD961D1B +:103BA000DA007AB2E85D69A8F75A34F2392FFCA13D +:103BB000BF6CBD65E7A610FD2BFA9B025B2B008F47 +:103BC00000BA6D95F5E681FE9624EED006B4633119 +:103BD000B80AA93FE55CA3D25FD337EB6FABECF734 +:103BE00052FAB3DEA31E9F55EFA1F159E5FD47E957 +:103BF0006F2B8E2F045FDDB43FD98E1EE86FA97A3C +:103C00007C568387C667D572FFE1407F4DDFACBF2E +:103C100036F91E934DE6D3E1CEFD370E9CAB761AF6 +:103C200051AEB429FE40797FBB14B4BFAD96F737CF +:103C3000E5FB4B71E9E4DFBDD433DF186A5FC3FDF8 +:103C40008CC97A2493F54826EB9108CF997AA63E41 +:103C50001EE8B0F0C5B6F922ECE3731E3A333E1508 +:103C6000E0192FF6CF17615F9AF3E2990349F0C983 +:103C7000CB2FBECCCB7F78E64A32949B7CEFCD2F06 +:103C800003382A96EFC70ADE4ABFB78DE27AA3BB94 +:103C9000E173EEBF04F98AFB5663AA87A17FF14264 +:103CA000727FD432A8EF4EE9B72C0F312F4AEA6E5B +:103CB000384F7E46147928FFE6E1BF40B4CF53EE7B +:103CC0006794ABEF6744456D22FD2F8CF9CD28EF4B +:103CD000228C0EBA4FF8D628BE1F2C64F60A6E3717 +:103CE0004859F2390DBACF31BF586ED77CCBCFB11E +:103CF0007CA1C6B11EEDD9DF4EAA8A47F558391707 +:103D00009737787F72D7F51B9C1F0EBE3F39E7238C +:103D100081EBC223B8BFA53B57E2F7B902FC86A8E6 +:103D2000F70E379FB5A3B87D3F389F0E3E9F310EEB +:103D30003E9FE6FEA8B5B0FEEEE87ECB13C49F5DC5 +:103D400021E76BC8BC06CD5FFD28A6D8795AA4B779 +:103D50009BCDB732AFCAF9C14641CAA2FDEA4F793D +:103D60002AFD8331BB142A8E83F419B8BFEA6D4E45 +:103D700086FE195D9C3D07CF9537FE451BF25CDE44 +:103D80006E793ED64685D3B9CEC6283DD9DBDD5106 +:103D90003319FA9745D3749A97B2A8723A6FA98DDE +:103DA00065ED688F069F23D78EB89BCE0169AD68FD +:103DB00041403A702ED961A4F889B9E886E7C8C5B0 +:103DC0009B9D238F99C9CF9147E9257459B445EA42 +:103DD000439E237F6C14DFF7BB713C71883F8C27B7 +:103DE0006D701CA299C7D1313F02F2F56617237F8F +:103DF000BA3CDEC7E47550EA1BCC1E86F240ABB776 +:103E00004BA8A768C3F93E61B069584E08BFC8F710 +:103E100047E9E8FB4F72CD34AF1A23D7CBE7FC5A02 +:103E200008E94F7A7594E24F0A4D67C3D1C93C0D3A +:103E30003F47A7F0E102939ECEF72D30D94AD10F2C +:103E4000B20008EFB39880FAB72DE2F78145BB0DB9 +:103E5000E9E737536EFFF96F18BAF9B97C3E35437D +:103E600047F7E34E09CC618F197A7ED5E98C9E869F +:103E70006E9ABB669D5987ECF7E2F2EF15617B867F +:103E8000E353751689EC9F7746A15CA84E5B1F0F24 +:103E9000F0A2CA421DDDDF94E344EE082EC79FD195 +:103EA000BA4E8EA278D1E751A54847627F2AE2A395 +:103EB000C48902EABD372A9EEACDE1D7C5A0DE1843 +:103EC00094D3677FEF62B41EB6507A12DA4F2C306B +:103ED0006E23CB07B4A302F3D17E6201EB272C2F14 +:103EE000B6F68590174A9A60DB92520D7C9E90D070 +:103EF00042A992FFAC435BEE0FB1AE57E575FDC62C +:103F0000764C1B603B71D08E01FBE52ACEDB17D5CA +:103F1000A72CE36148756517C98EB1E9153E9388F2 +:103F2000BF06611EAF04FB4575DEB0D5EB4BA1FBB0 +:103F3000FEF2386D2BD646A31D03551C489FDBBCF3 +:103F40006D29659983E3C8CE91E9138DB689A817C9 +:103F5000F35F725CCB0CF497249B34743E012653C0 +:103F6000752F616E59F4B4383445DDCC6E92D02E85 +:103F7000EF253D3FE1BA96F820E1F0628671ABA4EF +:103F8000B87601EF030DF423DF6FAE97E3B9575C0A +:103F900065348E04EBC0FECEC80E8DF3CD4579742A +:103FA000E5698E51C28FD5E5C971FCDCC2FDD5E152 +:103FB0007E09E83AA9B6574038010C38F4C5275CA9 +:103FC0006F4C6B4279F25A04F98BB56D99CC07F2BC +:103FD00027557445E5E03CFBA5FFA6C990070BDF1C +:103FE000AD7C209CF4B336A16506D925F769582825 +:103FF0003FCF981CEEC728C8E1FC9F606B4DA91EFF +:1040000087E9D344375F97CF6790B31DF4D9119FE9 +:104010002DFA581CD47B9A75A1E9739BDCEFC07E06 +:1040200021CF5F187319917FB582933B39F7EEDB8F +:10403000B7CF82CE1346E75536C97A8DD24E444E5D +:104040003B1546D81D0CCF450A6607DF07CC3E9BC3 +:104050000FD6ABF92B6D487BEBC11C791F496BB2B6 +:1040600061FDB24CBB0DFD94C1F7551AD326DA7031 +:104070007D1A670CD0A931705FE84ECB7E1FCF53FD +:10408000997A742CF01C5970AAC77321B1372897FC +:10409000CF97371DE2E7429B4C45BD780EA1C9146E +:1040A0005744C7FE4CFC9CA952DF643A46F2DE64DA +:1040B000E7F15613EE0F02A2C7E7A13BED18CD833F +:1040C000526F5A0E97AB267B17C3FB5BE1763FD549 +:1040D0000B139D3E0DE01F16C7E8FE4F9891F35558 +:1040E00004AC8F3180EF957E6FCBD1D1BC352517D5 +:1040F000F596107E22DE04674DB6221BEDDB38DF1D +:10410000D06F63B442DF9CAF1F97E75B69A7513E56 +:10411000FF7A4F43CEFCB258F41339D7E460BBA604 +:10412000E546B483B491E36FD8DE8661DB6B5E282D +:10413000B7F738F28536B2C88CEDE9505E84A0C37B +:1041400067E476FE57E3ED30B374DF97605A309F33 +:104150002D94DEA3A4468CA38F1BFADD3796BFEB0C +:10416000D47E2490BF7B71FC2B93CF1E2BA11CEE21 +:104170003FDA2EDB278A9D6191DBDE2EF07BE83E65 +:1041800021DC4EEF36C87687254C3D0F83F741F989 +:104190003A5CAEE0E7E62EC7318A6B04F3F3E577CD +:1041A0003E8A0EB44F50EF736473BB0453B44B1C80 +:1041B000B29F0D61F41BA09DA2F0FD805FB742FA93 +:1041C000A75B003F03C86F0DB42B247B88BE0DC9CD +:1041D0007D69C8E7A9F23B0543F6D75C2EA7854762 +:1041E0003F4B43FE2E8BEB4FC0EF82F9FC8547AE71 +:1041F00026E0785E983170CE86E243AB17A7F37B5A +:10420000D9C7FF1CED0AD1FECDEE7F459DDDB486FA +:10421000F4C0E55C0FFC5BDF07DBBE8CEB9D1D8211 +:10422000DAEFA4CDE57AE75FE47DCC7A55A4F72DEB +:10423000CE65B92E201FB60AE6E5287F531FE1E7B9 +:10424000E6563F5EFFD90321F84118EDFA734E8020 +:104250003D5CDCAC273F5AA3297DC48DE21CC3AF73 +:10426000B387CB71797D4B1E35F2F3242EAE175BED +:104270005CF7D33995E0F323C3D53B24CB3DA5BEF2 +:1042800001DB4779629A47FE804B6823A0BF4D96B9 +:104290007BC17876E264C8F36304B9127568451887 +:1042A000B6AB93EDB1ED8A3FA3A2C8E808F85EB7BC +:1042B000B8C8581A402F8D8C9FDF0D6EFFCEDC01E1 +:1042C0007D5AA5AFE8709F45DF509CF8A7013943A0 +:1042D0008A65B8CA8E51FA0F3E3F16705E2C8CF379 +:1042E00029B7675AF1DC18E8B76B2B968FC4F96DC4 +:1042F000155D2F58611EFA3F30D039E70F65BEECCF +:1043000093F972B8F5F3B143A08C31F6043B829770 +:10431000D6804EC68F40FE68CCD494FB438CB35CF1 +:104320001E6708FDFAD6DCAFA75F97E686D0AF51CF +:104330007F7604C51F0261D49B1D21F4EB1382EC30 +:104340000F90CFED9CD0491D7D300F276E1D616F02 +:1043500094E89E91C35E04F6C38B6732516F9F232E +:104360000CBCC723DB318C60B02316225E739967C7 +:10437000DF0302C5515AEE48A3EE045C8F9BADA744 +:1043800024FB1137C23A61DCA1F5DAB219A1E20CC3 +:10439000FF38402728BA02EF07C02A04C49586C414 +:1043A000CB82E263184E1938FFAB1D5AFFAE62751F +:1043B000FC6AE335EEBF30AC60FE27043C1FAA2E3A +:1043C0009F5FAE0B8ECFA9E25A0B9DBA607C7C88B2 +:1043D0006FB28C6FCAB607290E3E2D45E4FDAC6462 +:1043E00064CF07C7BD0C85BD0E2DEAC3158CF4F74D +:1043F000603F369E1725FF5E0563CF0974DE5A7D48 +:10440000DFE4E959E7F8FB1C2DE5D88F2D53C350A5 +:104410003F0EBEAFA0C49BF0984CE07D69E5DD2265 +:10442000CB620DE1C77CB753B9E29787FAA6124B6E +:10443000C0B9EE556CA03EDDA3F2851EF7D6D65965 +:1044400014EF4F1CEF29EC82A2243BA37948AA6603 +:104450006407C03CA8E2FA86945D34CE4B358CC527 +:10446000F238A0AA3C017670A44F18BF2ACE0FE301 +:1044700054C1C176E7CDEC4D434AE60DE5F9CDFCDC +:104480008D06395EF8466E641CE93B63D818D47714 +:104490002C8B9FA6F5B804EB817E59348442C5036A +:1044A0003743FB6807BA905FE2D1DFC454EFCA30EC +:1044B0008748F7C984628EB310EBE4F1E17C46FCD7 +:1044C0006D0807950BF859986C70E0BC1B0C00C385 +:1044D00090053D332640BE56F637AF1598883033E9 +:1044E000DB8DDC4FA8BC6BE3A7776D86EB0774FF11 +:1044F000BE30ECCFC7BF53FA19F28EDB0DBE27FBDF +:10450000CD1CFC7D19F91D95FE879BFFE1DE6DFB3F +:10451000C3D4772770BF6732D16BE520BD12BC4C86 +:10452000A647FC1EE5C2BD4AB1AD770CDE373CFBA9 +:1045300070841DFDE003E3F0DDA9E5EFD1FD75ED2D +:104540000DE0619348BE0F8C4B6EEFAF1D17FD025F +:10455000E4DA06BC3484E74F2A199D27B0B84ACF65 +:1045600089740E00C6A0921301EF13407B1B0EF15D +:1045700073AF5BF19D0B71B05FD42BD06EB0554221 +:104580007E083B4849AB19BF1FACE0D5A8073D1AD0 +:10459000E952C3F5E8D9A63E11CF35E9E2FA45E480 +:1045A0001FE7682EC707E8379ED1F90B6D927CCEC6 +:1045B00071A4C4DF4DCBE4FB9BD2CF84D11A59FE4A +:1045C000F7D2FB47B3234ED54B76C6F2F6C52F4440 +:1045D000FFFCEC11A7EAD3002ED867E170D2A92B1B +:1045E0006966C6ECFBAC0BD19F3F3BEFD495748062 +:1045F0008BF6D978F9144646CEF87D090BD19F3158 +:1046000061B459D5FE5B38D7F1DF3CD51A3421CFE0 +:1046100063DF365A394FC9E83EADB3F397A7312E61 +:10462000E954F647872E48DF81220BDE23937F7102 +:1046300051140F9D29D3D99DF8EE5214FA2DBB6861 +:104640007E470DFAE99FFE6BFCF482437997CACC52 +:104650002A81FF1B1B982B2C2380EE9943739D9F6F +:1046600003A6B881828FD2FF10BC6069C59840BC98 +:10467000B6513B0A5E170A0DA48705C7872E08FDB1 +:10468000DBF19C54C4CFD62FC275BA10D99F2A0033 +:104690001C9EB79ED6ED427CFF76C11E00EBF83A19 +:1046A00056EF2BA275FCA3D6513D7A02BEDBC5DFC7 +:1046B0006F6896E3504FC6BB7C689F01DDD1B9326D +:1046C0005F8A9EFC4865E30547A03FB06E34F7CB98 +:1046D0005C92D3698616CF49A04BF70181AD85FA6C +:1046E000EE6B97F5A89FCCEE3CA3473DBAEEC01900 +:1046F0003DDE4BAD4318DAA9DBA67784D2FFFE324C +:104700005AABF2972976D7D194ECF5E877ABAB1694 +:10471000E81EDEEAD7B91F6EF5321C256377DFB2DB +:104720009FFCB855CEEEF5982E657D47F1DD88C526 +:104730002EADEADCC0929A08553CBECA13AB8297F4 +:10474000B6C0EAC03EBBB42149F51DC35DCF82EFC0 +:10475000280EFED0FEAF90D771B16D732FFABB1645 +:10476000BBD47ACCECCEB5620CE2ED11EC1ACEFEE5 +:10477000127EB7848F10D200BD0AE67D5A07D7A3F8 +:10478000EA2A8C649F54220CF35A59ABF5E39373D5 +:104790004753F454EEEE10A8DC2D97BB6B046E5714 +:1047A000CBF275A98CE3928327A7D175529FA337CB +:1047B0003300DFA515E5E7881E657D43195785C4DD +:1047C000F58D0D29EFE9B0DDA5DF17586C1A8D4B7B +:1047D000A5472DA951C3551E5D909ED5A743F9BD90 +:1047E000B4419DFFF3D1F2BE9EC7F2909FDE182D1B +:1047F000889F1807E13FA5BC7702EF815DD23A0F91 +:10480000227DD6EABB0A70DFBBA47511AC94437E4F +:104810001DDFAFB8BEA201CEC3EF1B750E33DEA7FE +:10482000F5AD14886E97B000BD276DB03EC1DAA11A +:1048300070BF2277C39CF5E40F3D2898516F281371 +:104840001D22DE836F1CC68F7E51E68313AC2F1FA3 +:10485000F1CA46228575CA9E3F82F699ECB796F951 +:10486000308E943D4E20BFC49D80714311A622C955 +:104870009139B03784419AAD6DAF20F93E566FE65D +:10488000EF62DA58A0BC70FC331370BE1075B20B27 +:10489000937BE8FDBD396D9B2FA25CCCCC70143DA1 +:1048A00005F83D19C6FB7FF275C1BF16DAA9CB3FEB +:1048B00046F2D30AE481FDD6D96439DAA1F6CF5A9B +:1048C00051AE21C1CCCAA77E1394F832D015EDC3E6 +:1048D0005DA5A49F58E57E9F2D94B8DDFCA07C2E9D +:1048E0008DF9D6E2F9FABED18CF295F41BFBABCA76 +:1048F0000431285E50371AE679A5AD4F75DEE95BC5 +:104900006CBF01E92CB87D18BE2A5E394D7B2D8A1B +:10491000EE771DCCB0DEE8FE94D6A83EB7A4338770 +:1049200007DDBB53CB9FD9F6A4A07B771941F7EEE7 +:10493000F282EEDDA9EFF92D744E09BA77A7BEE732 +:1049400067B0CD54D50F93E6A9E0889CBB55F523FD +:10495000EDCBD5E7AE8EFFBC4248C777067D7D2EF6 +:10496000988766E08DE298C17D242F0A2A431A3E7B +:104970002ECC846973A1A10BE9A43991DBE786E30E +:104980000FDBBAA01DE388978CE86FFC89E02F4508 +:10499000FBC4289F5319FD1853ED33AF1570BE5259 +:1049A000D2DBF25CB3F3617DF2F74A49FC1DE0DE35 +:1049B000D1B83E467C6C03F9E6557EAF78AC6C47C7 +:1049C00028ED3C5F5832350FBECF7FCC3183E2EC0F +:1049D0001DFC7EF04E3D8FA7F85EE5E75BF33BFAEA +:1049E000348E00FE3E99C7F590679CA5141FA9EB75 +:1049F000845D16F9A9EDAC1EEF65D4757647E17EAE +:104A000056E03CAB47BFC960BEBCCF89FDE168AF93 +:104A1000FFAC3D743C6D6D9E9EF8E3982CD7AB1EA9 +:104A2000D672BB913966E1B971455E57EDE7E3ABEC +:104A30005AA8E7E760311A1D426E839C3EAB96C3CD +:104A40000EF57E708B7F3DCA0E90DFAA7A4B174C15 +:104A500027BBB712E436F231C87375797213C917E0 +:104A600090E7AA7C77DE803CCFBF0EDF9D766A425E +:104A70008EF3708148F378DA3595E6FF199847F49C +:104A8000A73D3364DEF87CDE6CBE5EC6B50F58B75A +:104A9000E07ABF2EE0EBF6F230F2FA7D795D770A2C +:104AA000BD45284CDDCE70A2DB254663099E7B38D0 +:104AB00096F26513C6E1AA7E2ED03DFD7FEB3E6ED9 +:104AC00041FD5FBFFFA805FD61EEF6A316B04D598D +:104AD000AD4E5A8B7A3CD0851DF59EBA8E2EC27F84 +:104AE00065FBB86ECC5FD921D0FB3DEE0317A7D391 +:104AF00038595F13C60B770E83D78FF2B8FEBE37D7 +:104B00004FE27E3017F489FBFD0183DF2F201D80EB +:104B10005C42BC5E17F0E535B673A3B122941EF576 +:104B20006FF27C1FD9A867E8AFAF85EF711CC75241 +:104B30008EE98D4847FB05B2B5DDED27174660FBD2 +:104B4000F53A86FA8582DF1729BD1FE2F83FA8D61D +:104B5000A1A78035566B69BE3FA8D7523BDAFB74DC +:104B6000042F5EC1CF551CAEFEA82909DAFDA05660 +:104B7000A07B0C53EFFBF3318417AFE0FA5A303DC2 +:104B80002BF41A4C9FC1F43B844E6BBE199D1EC979 +:104B900093EFD5E4B102DCE761DDA759917E1EE118 +:104BA000F7E32BAE1DD6A17F33BDC96C7F02E03188 +:104BB0005AFF7A0BCA89C3BCBCB07687C0E58D7436 +:104BC00037F26152B39EA1BDFB7E1E974BEFE37A95 +:104BD000C5E3D0FA058CAF31B1371DE5529A1C4FB1 +:104BE0007A45C72AF6535C90CB9B31AFD954EF96E8 +:104BF00037E571BD43918340E6AEFDE4976D4FC448 +:104C00007B142FCBE74153E5F6B232FAA7CF85F4F8 +:104C1000AA4C2F67643C14F8B24CFF6CDBCF681FC2 +:104C20009F2DC759663674D179CC3C83EB5394875A +:104C3000B352DFABC57DAE39FDED7C3A678D3725CC +:104C400026E2FBC9FC7778D2A7DBD660DC2F379C45 +:104C5000D631ECE053741E382C6BBC35549C434960 +:104C6000DD57257A8FB0EE6A3AA50A3CF7D0397D38 +:104C70001FD90117A7139F5CB5A9DE2DFC54C67B75 +:104C80008CF23E5D27F7F3809C168B8B06EB29F3A5 +:104C9000809E651C6F58D62E5AAF35AB5821A9752A +:104CA000EC29FECE66ED4901DFBD58A473E84C3017 +:104CB000DFEF8D60251F8BFC1D245736C64D8C748D +:104CC0002FFB84D74C70AFD746F029AF44E9AD61D4 +:104CD000CE887C6867E1114F16CEDBE1945627DE63 +:104CE00057BCF08E4EA66B33BF2F2ED3DAE54E2D78 +:104CF00033629CEB00E8E3C220FEF75C4DA4FBDDD1 +:104D0000BFC3FEA09F950DBF217967AFB9381DEDD8 +:104D1000A2C2DA334D08BB1BFE3C1DF5890F61FFB3 +:104D200020BD1EF47B9B8072E424BDD35D79358663 +:104D3000DA7959D33F1DF9CBF7A640F76F3EECB8AF +:104D4000A8B7F2FD89DC73782F1CFDF2B3F2A3B98A +:104D50001CE92CD4D0FA3A24D53BEBDDA3FF2B0A77 +:104D6000D7C3D820FD7A0A7EDFA365C8BF9B4AFB64 +:104D7000A3CC21E4EF69F4DF65F371B0ECA1E51594 +:104D80007A5F169E93AC90E938B8BC3C7FC03FA1D7 +:104D900073CAEFEB0801FEA12AC6DF3F05BBA72BB4 +:104DA0001CF8B8AA732AF967AA3CC20DFD33C3D117 +:104DB000E1D74DEB18F7CF2830DA8D817E4DB41B4B +:104DC00099AA7F1F7F072B25F386F774DC7D891452 +:104DD000CFAF6B6614EF5A797534A5E75FDF2021FA +:104DE000FF18C3FB5BE97E6BB686EC8C953EB5FE87 +:104DF00033A580CB8529057CDE5CF9602FE5B00109 +:104E00007B09ECA27BF3B95D147588A9ECA5E07C65 +:104E1000B2978CF23D1D1013AE5742E07D474169B9 +:104E20000D7E97CA5A88CED93BFCFE72F038D7E483 +:104E3000733E55F87A31F235D26F07E7EBE076E74B +:104E40001594AC413EDA384C7CAB5CE6FB956D8C3E +:104E5000E6CBDD1643F3F4056B7396025D7E0178B5 +:104E6000E03DD20B4E6744347C7FC1E58CC0F33DFE +:104E70008A1CA86B0BA7EF3666CE8BC573A3CD48F3 +:104E8000F7D0DEF98EA9469CE77BDA38FF29FD7D55 +:104E9000D8B53816F96982AE5F6F87F2E4CE335128 +:104EA000A8F74D787D7E2CF2E17078FEFD1819CFC1 +:104EB00086C4121E9787BD70A26C4F007EEE27BA83 +:104EC000E89DFA871A18D16FF7ABFF56877C7CBE36 +:104ED00033C28CFBE6170723E8BDCA0B6F1AE83D07 +:104EE0009A5AF97DD52F747D7348BF7C5D4BF722AC +:104EF000DD6FFE472BF2A3FB55039D3B7CA873C3DC +:104F000045DCF76A3B679CC377566B5FFADBF2C3FD +:104F1000CA8654D28B14F83FBC4627BEF37B5EE4AE +:104F200072E2A18E7F217DF7A16B970BF07CCA17EF +:104F300007FFC744946BEEB72E4F4479E6FEC5E5F4 +:104F40008958EE7E2DC2134A5FB95EC0FD3ECA7E0F +:104F500099F6AEA8F20FAD90E9236D5D0BBD073D4C +:104F6000E1E4027BE0BB0F13B2344EAC3FE1B76526 +:104F7000B1F7057CB7AE57A438E3F8936511D501B6 +:104F800074794F814EF12F7E23BF0E93DFC719F046 +:104F9000E3F4F2777F36F68AFC7DA31A81EEA183D3 +:104FA000FE32E45E1AADFF8A587ADF8889CE3BC7AD +:104FB0008C47388BDE05623EE3D1CC003D6971AF92 +:104FC000A6CB007454D169E822FDBE573C43B0AC77 +:104FD0003FDD73F1D3C83421847F26E7D43494E3D2 +:104FE000C17E1AF84522DE8ABE55E971A520FEC1B0 +:104FF000FE9BA51577907F28D87F93D62B6A668F66 +:10500000C7F7DFE93A2F8CF76923F28BA287E2FA20 +:105010001D08C1FF6BC67039A6F0D5BA5E1EFF5DD4 +:10502000D75B6ACC84B456E6AB03B09DFAA0FD759D +:105030009DF377A31F61DDB545116360BED6BD3B0F +:105040008F3D81FC6F2E3566E177D7EE302ECC1F79 +:10505000A497E0FEA68CE1F272404F1866DFCB9772 +:10506000F1FA5BED7F3963E4F36CFF87EF7F6087D4 +:105070008F1DC3EDF025DC4FC2EDF0E07D4391C7FD +:105080004ABB2E799D87CA63FE7748C05E2679ECBD +:105090001A2351BDE4CEB9B16447BFBB2056320DCF +:1050A0006D3F43B46B62F287B6AFE8716E9FE3A8C1 +:1050B00011ED1C8796FB491708F4BE99A2F7B99D1C +:1050C00002E9E3EE4A9D1FEB2978F52EE07ED585B7 +:1050D0000E9D3F4C18D40F15FD71A0DC2E50B9A2C7 +:1050E0004F2A7A63AF93FB71178CE7E5B786B91641 +:1050F000E17C7DD81546F91326F17CC69C479300C8 +:105100005EF43D8111FFCBFAA442A7C1FAE6A5CE19 +:105110008C1BBED7B34DA64F85CF5283F843D9BF62 +:105120009AF339DDD7E1FE1D8BFBF77FAAF4F2E09D +:105130007661FF7E08F16F461D12BE1FFF5BD1191D +:10514000CA3EFF4AD60BFE5E59BFDE232588AF72EA +:105150004E76B87DB54ED66F862B6FCEFF7AFCBCEF +:10516000471EDFDF8A9F778EF9BF439F1DD00BF567 +:10517000A1C7794741C94FC6C0BC866B3D749E73B9 +:10518000B8F7CD1E95F555B07355747C3445AF41D5 +:10519000BBC85DC3FD03CDD1D2AFC97E39AEA5F783 +:1051A000571E92EF733E78D54C692DEAC9902ED9DF +:1051B0007B92DED95D52A3C6BF197DB7F8FDAA3434 +:1051C0008AEB57B132F22B5575469BF1BC7F737C4D +:1051D000FB31E42BDF6EADB43BB0FEC6D1727D2354 +:1051E000F7B7D544D3DF8F61417A40952758DF5711 +:1051F000EB0553643FD170FAC12FBAC3B85CE9D153 +:10520000129FD739F9DF55D07772B9E06E0823BF06 +:1052100009DA6B88D7670D821FDF3D5F29D7FB4C0A +:10522000EC25FF13C5D3A0CAB9CEA72C0EB2DFD48C +:10523000F1A395BB7E4B7233388E1473408E0B0DE9 +:10524000C48D26D2799095604FE29FBC724BD25D9F +:1052500038FF801FF393DC71A8FC30977A3E22FB65 +:1052600073C9EB3CFE33247ED43C93C78FF0DD95AD +:10527000107EC8A5238F1DC5BFA374B3B8515DC7E9 +:1052800049BA473244FF08D23BAE8D51FB19478AD9 +:10529000DC8F3BB25330A37F6AA43C8F7FB7319C35 +:1052A000F4EAE97FA88E4579A0ACD3F9B97C5ECF4A +:1052B0007F70A504BF9BF807D11C06E3FAC507F56C +:1052C000BF49E2B06494F0BBFA08B463CEFF6175E5 +:1052D00004CEEB2F20C5BF2FF1DA6931A43FD22BCA +:1052E000CB2DD80FA30BC8BF2CFBA545D80F230788 +:1052F000FD39C1DF6D97BF6B063385FC98AFF3F8BE +:105300007E73826B26C1CFA633FE1EA683FCCEFF22 +:1053100002748DFEA23C182CC69F7F1ACED661BCAB +:10532000A839DEF536F1D1B31A09F908BEA73893CA +:105330006FBF44FB234E19C6730AF4FC5D46EA0CAA +:10534000D66BB4BC8E0960C7623C09B05980F1E6E7 +:105350003C39AE5310CE446CFF499D6B13BE97F998 +:1053600064B7685F4B4C608FC577BF83E34B828324 +:10537000C7C5953893121F1F2ECE24603F059CEEA3 +:10538000F8B91587807173259EC4BEE7A4205763C2 +:10539000B187CEF73F53C848AE7F8B719E25F92168 +:1053A000E24835C86324CFD571C54D39AF109DFE95 +:1053B000B5F1C43D63D8B71CFFE2F3138CF7F8E8EE +:1053C0004B16B2B7BEFAEF51B4CF765EA6FDF042EF +:1053D000BF41BE8FD0C7FDEC9D3AF22F5C00BB2DC4 +:1053E0003E609F3D9ACFDB3DD43995E8FF406F5931 +:1053F00004D63F2FE76F7C77C1FCD94897BD22BD0B +:10540000078BE7E3D00E3BD02B4E40BDE55B5C97AE +:10541000EF8F09B12EC6F0D0EF4CE4CB7C945FC087 +:10542000E963EA07DCFE72D7F3388A59960BEE720D +:105430003DC9C163291641F19F5B43C5595EEFA782 +:105440007DA36A8540F71CBE719CA5A35BDEB78275 +:10545000FCD3E5D3496E0EE7B70E889BABCAB715F0 +:105460000C9C8723FF75548199C61DE3292CC1B379 +:1054700087CAF8BFC575B8736C083AFB16DB5F695D +:10548000FF6EDB9F92F7DDB6BFE63B6E7F6DDE778A +:105490001BE7DEF11DE37FF53B6EFFCC773C3FAFB2 +:1054A000E5FFFF73000370709C3FF85C4070BCDF49 +:1054B00070FC3E1F966D1036F777416A8C7AB542C4 +:1054C00000512D46EFA27708664DE271B08D65461A +:1054D000FF0E61F07C80325F4B0BB91D61CEBFE8DF +:1054E0008B85794E75F496C5A29F6C127F87FD82DD +:1054F000FCCE2A13CDF4CE18D44CC0FBF1CD61A163 +:10550000E3AA61727BC3ED23CF1796DC31369EFE92 +:105510006C43C8FB1D2FC8FE47730723BF2413A588 +:105520008479D4AF9480FAD088233C3FAA8B397613 +:10553000105E52DA3CB207A534C46F8B1CEF8D9914 +:10554000999D86FEE818D00B311EF814C605298EE9 +:1055500065A67A4A7F1F8CE5FD6DD13181EE5BE552 +:10556000F2F34CACF9A02A9EF78EAEEBE36502C5D0 +:10557000F39623FEBFD274E5EF4C938918E637FF0C +:105580008099E28C2726BD487F775689EFAD31F3AD +:105590002A87D16E063CD61C1C47F4BBE4D0A4F786 +:1055A000F1E93377A6680F754F51F1179C96FD1DF1 +:1055B0008ABF40896BFD5EF6937C88FE17BA1F2276 +:1055C00051EA1DABF9B6F727EFD810FCBF45E0FE56 +:1055D00021DFAFB87F689CDE9E11786E72B33CAF5E +:1055E000CBBA78DC42F1F7EC93C733EE116D97013B +:1055F000F6D2714D63F4B8CF8F6B4A09C7B4C0E1DE +:10560000D7E07DF0C5D5FB35CAFA85A2A3D6B1B2E5 +:105610001FA3A79FE27AFF1214E7FF602C3FBF3061 +:10562000AF90E3F101D82408AFC9121B517D1C7162 +:105630008B591B2A9E54057631E2B9AC99E3ADCC67 +:105640007755973415FB3973B4BF09D3A29AB4A91F +:10565000E46FAFBDD884FA9BFBDAE563B793BF4C28 +:105660002FA13D714F9FDAEFB60AA3A5F18427FD64 +:105670009D5ADF0C91ECE3713344A29F98AA30B29B +:105680005F63744C6B42782ED78B8ACAE3A622CC18 +:105690001644933E58D42345DF973FE8078B995132 +:1056A0001F8FF374B3F8AAE24FBB35CCF11AAEE703 +:1056B0005F1B5F5DF9CEBB74AE541997322F4A9CC5 +:1056C00074B8F8AA72CEC15D7E45752EC32DF64F13 +:1056D00047FFE3B88367F4F2394B33FE1D6125FEC3 +:1056E0003AEEF58B147755E2AC6ECF45D2ABE13B89 +:1056F0003D7E3F0E963F2106DF17E2F1D757F19E20 +:10570000941EEFFF99E9BED41BF2FDC54E183FE68B +:10571000BFE9CDA1B4CB6BA7F490B7985277E7451A +:105720008AD77E38561DEF53E27997B4CE3363D5CE +:10573000E723090E8EF769C3B9BFC6DDA3A3BF97E0 +:10574000E17EC748F2BBA47319DDEBFAF2A46B2427 +:10575000E25D87F1B600BA38EFB087E13B61E79DC3 +:10576000F6308CB38DEB3EA7C7F32F7562AF1EFDED +:10577000618071121E4D741FB8C8CFF77696D0DFC6 +:10578000E3BA695CACE36F1317FB9FE541012100AD +:10579000800000001F8B08000000000000FFB5170C +:1057A0005D4C5367F47CB7B7E596DF0B2A3F227256 +:1057B000C16298A2DCC240A7311674AC135C8A4A5D +:1057C0000201B5662E92092DD9CCC2CBD23A8901FD +:1057D000DDC3B2B864F3A92683E8B687FA93AD6E49 +:1057E000550B0B84252EE2C39C71C9520D3333BA7D +:1057F0008162DCD85CD839DFBDB5BDD8BD2CDAA458 +:10580000393D3FDF39DFF9FF0A003007DAE756B9E3 +:1058100006E74CF8A5CFC6FF0F3DA44F8CE3DDBDD6 +:105820004BEB2617C4F1BB3EC9356903F85D9CCE2E +:10583000942B00F687CE5A1C041FCFAC7621FCEDCA +:10584000C2DFB54A3A80F7D24C2D20EEFD66A6960F +:10585000F8DEAFD27A02E94FDB7BD78E975E047019 +:1058600096416B10F9552EC17182E0B8C3FA4645D6 +:105870005C6EC02538E9FC80AD349BE8C75CA5D9D7 +:105880007B13F4F539456700E939AFDAAC89F409DF +:10589000BB19A006E90C5CC124F66B5581DBDF7FE8 +:1058A000D22A4F4A7A1CF1DB1DCC36E0DE50813C17 +:1058B000591EC7F7D38F02FC6E6622D40274E9B971 +:1058C000B86472D7AAA8AF3B3F6A8152A24C5B5C16 +:1058D000AB305EDF4BFDAC1260F8FCBEE268051732 +:1058E000952017A04D3F37E0DC5B9CB110C07F3D99 +:1058F00005CA98461391DF4A3F148E2A22DA69A717 +:105900005F78E5B6FCF7274CAB11BACDFE68C2BD97 +:10591000DA9D82C39AC9ED2E6DCE207931CE2F212A +:10592000A5D34BB7AD22CC5128E413F417C25A02C9 +:10593000D2A8AD366EEF06047EB0A17C9B5388A43E +:10594000A09DD6704A04506F955304DF8B087BCD21 +:105950008112467CF126E72B6F3611BF4FAE2A0429 +:10596000F4E3E7CB16794109BFDF6434218EAAF353 +:10597000D3FE523CAF763195DC6AEF34F2F19341BD +:105980007EEED6E3B23334FC7221F75F36019ECB54 +:105990001D03388E7677F618CFED6E75DE61743F95 +:1059A000F8A07F33CA814D900789DE6B94A33A3B00 +:1059B0008DF11F007026D64337D5410D41C6E1E772 +:1059C000E813D54515062A58113F37BF7E4674F9AE +:1059D000F9FA62F00CF117517D560DD828BF4D022F +:1059E0009401E1F5922D419F5F15B99E0F6501FC71 +:1059F00028D717DE3EC8307E7D8F5F915A506E4AA1 +:105A0000AE97CAD2E3B8F732D6531640F5F06C031E +:105A1000C5FB589881154D79F3F1BE28577DB16EBD +:105A20009CAD4EBCA7E6DF31CCF9443AD5819A0D46 +:105A30009A5F2061BCFC17586010ED55353D1C493C +:105A4000A3F8B9B2D53285ECD80EA523EE6D126B52 +:105A500018E12E3C40F80E1690F0E7F62B9D5B0007 +:105A6000ED54B7D8AF52DC5B3ACCAA1588DEDA40E9 +:105A7000F46B5950372912FFC47BA9C42F67AA556C +:105A800021BEB39EF88D5F4444AAE7AD14A56578A6 +:105A9000B7CB288D7DB3C1EA0E501F5537A311F443 +:105AA0006F47873540FEB5849BCD90CEEB41A0BEBD +:105AB0007B5BCFEDB7458F32A3489F095767915F56 +:105AC0000BCCD316156135EA2EC84178E1BE05B07E +:105AD0001FBCE2B44546B9733E4CAC05E04B9FC4D5 +:105AE00061C827836339C0D7BE7C0EC33E85D32FE0 +:105AF000FACA398CF8540E477C6B35A8CA3C9E957F +:105B0000E1FB02DD27A75970259B6F7EBD3E62F940 +:105B1000AA0BEF29A67B3EBAEA2E9693C8C7205A55 +:105B20002C14D66AFDC930675EE7C306B2E381E88C +:105B3000613AA760BE610D46218430EFBFEB6FAACA +:105B4000529B6FD902B893F167F4FA048722D03CD4 +:105B50007A4BD2FA7F78C55F3C9E5248B9B21EF3A9 +:105B6000E61937410AD28FD46B737FBE9EEB184F74 +:105B7000C0B8DDC078129CCF6FB5F8CB281FAD74CC +:105B80008F24E7A7F4FAC40A30BB32B49C32BC4F6E +:105B9000476C0E6020B2308F1D211649C53EDF19BB +:105BA000DE744724D8C3E096717E3CD77DD8E646A4 +:105BB000A589F3B6338D26F9135C4AD5E22C593406 +:105BC000D86FD5F65A935D8B730C6EB56B75719467 +:105BD0009A05EBFBE879163888FDE7A918BB4E73E8 +:105BE0002CCF01D08BC3C7939F1E31D13C0F99EFAF +:105BF0003D99E3D81F798A0C1D3994370C26F6415C +:105C0000817E0724C06D9463911C616E25CA2D1995 +:105C10009F257D9FD8156E2F77579001BA5004FEAF +:105C200083345F462D50771AED779D637090FA3B71 +:105C3000E00205F7FDE8F11B874F21DD738EC9B443 +:105C40008EBA8357F99EEF162778FF78C2772DBC5E +:105C50001E8337357A88390249F23A40FB1DED6ED2 +:105C6000467F686E741F300552D06EC339ADAFBD2C +:105C70000E4B40417CACE81D91F09DE719E4D11C2E +:105C8000532616A511FF80190225DCAFA6BA84FDA4 +:105C9000845F85FC8EEDCFD8FEF1C0F45821D56B22 +:105CA0002753230ADF3FB78CFB052F921BDF2FED15 +:105CB000A16133CD1BDC4306B9DD8E863B343F71D9 +:105CC000CF18E94B0EDFE7F98028AF53DC2F067EB3 +:105CD0008D3D63E16D2C095809157338CF3655CACF +:105CE0003CDFAD6EC6DC181F497075919F7091C97D +:105CF000346FE7C7ABD1AEF541A39F412FE677C81C +:105D0000A2D5C7D03A16F0A37C23A294F7A18B7B2F +:105D1000FC0CFD1CAA62AA40F120218CC7163D3E56 +:105D20002F801F6E4BFCA9706CAE1AE035AC612B56 +:105D3000D653A35E0F00016EA7F9E3D408BD238EEE +:105D40009A83F92A7F97F8F97D6755E0FCD414E827 +:105D500049D6AF6BEC75B36A0DC93DF3F7D32E7B13 +:105D600092F7D347F876223B7BED4C24BF30BE2B15 +:105D7000A9BFEF155DCB1C41F481C9B58FCE755914 +:105D800022ABA9BE1F98DC1C8FF191EEA1FD828B86 +:105D9000EF16F591008CCF8723E567CC949776A218 +:105DA000C7EE5B1297E3B8E969FCA10ACFDAEFA16D +:105DB000CA9AA7FD7E86FA17ABCF577F6EB2BC1D7D +:105DC000A2F997A47E7ED2E71FC01299F7CB933831 +:105DD00083B68764E0753CAAEFF57EA6FC487BC8D5 +:105DE000FF9D190695F85CEDCFD0F47FA6EB8BC133 +:105DF000511DF69B35B9F9F627F439FC8BC9718A28 +:105E0000EEBDF2A4004A82DFAB82A9A024F85D199E +:105E1000CA31E0F6C862837CF578A9815F33B1C2EC +:105E2000C05F73BDCA80BF145D67905FFF6BBD012B +:105E3000DF30BDC520BFF1CF6D063CD6BF7558B968 +:105E400089E73649AF1BE40A3B8D7E15F518FD2A1C +:105E5000EE35FA15D35BE237FAB7ACDFE85F4EF602 +:105E6000835C85DEA1FFFC9149FB60203CC3F334D9 +:105E7000359D02133447C4A8B61FC266BE17A6F0EC +:105E8000FFE2A2843C2CA7D73FDA19092FB3D2B97D +:105E90000F9D362BBDDB2E510D603EFE05D7762EB5 +:105EA00017E00E00000000000000000000000000ED +:105EB0001F8B08000000000000FFE3E36660F8515C +:105EC0000FC1D3B81818367221F84301B7334368AD +:105ED0003E16060601207EC7C8C0F09E91043338E6 +:105EE00010EC7E20BB0A88277150CF7D43112FE52F +:105EF000A19F5D5FA0763D1518787F83B083100366 +:105F0000839B300383B40884BF5F0455DE5108C10E +:105F10007E2E41995D9F81FA018DEBBB318003009C +:105F200000000000000000001F8B080000000000BF +:105F300000FFE57D0B7C54D5B5F73E731E33939976 +:105F40004C260F4242004F08202A842140088838FE +:105F50000990068D9A080888CA000142483211A9A2 +:105F6000975E6D672214D16A1B2D6DA397DA0141EC +:105F7000A3450D18E840031D4C41BC5A8D0A4A5BED +:105F8000B541313C0A4978E8C5D65BEF5E6BEF332B +:105F900099736642A2B6DFFDBEDF177FFE36FBECCB +:105FA00073F65E7BADFF5A7BEDB51F2359C613D345 +:105FB00015847C057FD71372482484F4EB4E3B0B89 +:105FC000683A8E107F8E39B0552024B4EFEFED245F +:105FD0008590B34DB355732621FBC79843D7D3F2B1 +:105FE000B381FC8099964FDD79C421D17CD54E5187 +:105FF0008272D33E2B7EDFB1510840DE6B6EFDF125 +:10600000B534DFB553249B69D5246437915442DA03 +:106010002D84FDA9F1985F6A65D9AA4DFBEF82F640 +:10602000CA836662A5DFB737896EC8AFDC2A040869 +:106030006DAF6AF783CA005ADFB280D06855697EB7 +:10604000EB638A1A4FC803FBFEEC68B31372DA677E +:1060500021AA82FD286F1C494845607BE100FA7D3A +:10606000C536C165A2F5576C3CD701F45534C9C398 +:10607000445ADF8A061B5147B0B6BF22D05ECB0719 +:10608000D8DE4E7928B457FEE53D0A11A19FB21B18 +:10609000BEABA27440BFB5764FFBEAB13D8D9F55B4 +:1060A000CFD1F6E87BD52F0A2EE862B58978808EAD +:1060B0008EDDD6B94FDBA17FB5CAF0F8C87E2CDCE7 +:1060C00005FDA8086C520AED40DF2665E9C8EEFA26 +:1060D0005634FC879EBEFAACFE9E8872637ADA471D +:1060E000593ABC3B5F4188BB91D64BA480523AAA37 +:1060F000FBF907422221E3A17E91A896EEFAA9E4DA +:106100001107FE23F49F940FFEBDF181AD99DD725E +:106110005BE9049975CBEDBC93CB51EACA8DAC5FBA +:106120004B7F0CF2A0F4D4F99C983EEE4BC37483E1 +:106130004F45BEFDDC3702D37A9F0B9F3FE9CBC3AF +:1061400074A3CF8DE953BE224C03BE127C6FB36F94 +:106150002EA65B7C1E7CFE8CAF1CD3065F0D3E7FA3 +:10616000DEB71AD36D3E3F3E7FD1B71ED3465F1DCB +:10617000A63B405E346DF205F0BD5DBE064C83BEAD +:10618000467CBEC717C4F411CE47C764922F513E58 +:1061900038DCC449C54E928ADDF932CD2795B07CF2 +:1061A000EA1DFE7C85E6533D344FF932A032946FF0 +:1061B000A6F90135AC7CF0FDA4C042F383FDAC7CB4 +:1061C000C823EE022BCD0FA963E5C337FA0BE268B3 +:1061D0007E7880955FBD2D5460A3F9AB1B5979760D +:1061E00033996AA7F9EC10CBE7BCE19E1A4FF3395B +:1061F000AD2C9FFB817FAA83E673DBD8F793CE0497 +:1062000044D51E2D871DB2BA9850596DF4CF704BEE +:1062100013695E51EF212ECA1FFFAD6E299DF24317 +:10622000766379C83F1FCB9B143796BFE32FC3FC1F +:106230002ED983E5C7FD552CAF78B0FC73FFBD9810 +:106240000FCA7E2CB7D4FA585EF163F980DAF5589C +:10625000FF1E3980E5236B1FC3F23D4A00CB1F5F51 +:10626000FBA47B1ACDAF113C3F073CD2B49C640128 +:106270009E1AD34A289ED609642EE0F707003A8A70 +:10628000CB75E90AEAE18E3FE43E0DFA8B7F299057 +:106290005FFACCC399F8FDAFB01E99D623F65E4FD6 +:1062A000CE9B79BA7A72DE2CD7EA6980F7D658FB92 +:1062B00056CF8E3727E9E979B342AB673BD213DF7C +:1062C000B77EE5BC35594FCF5B955A3D7B909EC458 +:1062D000BED1D37444CF9FA62361FEB4203DFDFA06 +:1062E00046CFB8F7F4FC19F75E983F6F603DE97D43 +:1062F000ABA7E93D3D7F9ADE0BF3E708F66B50DF75 +:10630000FA35EE7D3D7FC6BD1FE6CF47484F66DFBD +:10631000EAD9F5A19E3FBB3E0CF3E704D633AC6F40 +:10632000FDCAFD48CF9FDC8FC2FCE9C27AAEEA5BB2 +:106330003DBB3ED2F367D74761FE7C81F58CEA5BBB +:10634000BF72FFA2E74FEE5FC2FC310950CF98BE8B +:10635000D113FC54CF9FE0A761FED8B09EF17DA37E +:1063600027AF5DCF9FBCF6307F520490FBC4BED5F3 +:10637000136CD7F327D81EE6CF20ACE7BABEF52BB7 +:10638000EF849E3F7927C2FC198EFDCAA77A0FF4CD +:10639000105A4F7CCFF5EC39ABE7CF9EB361FE8C42 +:1063A000C67AA6D37AB27AAF6752879E3F933AC233 +:1063B000FCC9C37A66F4AD9E3D1D7AFEECE908F394 +:1063C000271FF97353DFFA35A953CF9F499D8C3F9F +:1063D000630FD74C75D0723A16BA44FAC9B567DC68 +:1063E0006E81E64527CB8B4E1701BF44D4FC0DD2FE +:1063F000EA16E9F7F66D89390F9348BFA3A014FA9E +:10640000154FBDB148BF23212F4EE7E724BA93743F +:10641000F9E4A201BAF7FB950CD195F79F7BB5AED5 +:106420003CDD93A3CB67944FD2BD3FA8A64097BF56 +:1064300062F50DBAF733FDB7EAF259EB6FD7BD3FFE +:10644000AC6E91AEFCCAFA0A5DF9558195BAFC357D +:106450000DFFAE7B7F54E303BAF2D1C18775E563CC +:10646000428FEBF2630F3DA97B7F7CEB665DF98485 +:10647000A3CFEBCA27B6EDD0E5AF3DB9C7E0E7D96A +:106480009DEDD7F0BC08B827CCEF4F57D0DF0BC538 +:106490002B985706D8D18FDF1FBF543D4EE5ABBCBC +:1064A000B2584DA1F20599123AAEE70F28BFB28D4E +:1064B0003EBF7792E74A277D7EAFE219ED8CE19FE0 +:1064C000523C08240D52D504A9B1FC4199E1B120F8 +:1064D000E3CBE1C7E8F75E53D7F0449AEF2FE6D756 +:1064E000035E9E124C88D33891D4C07B716682F3D0 +:1064F000820733739FF647E075FD20AA874277BD78 +:10650000EB654F1AF8199B6BDFF6831FB26E10ED27 +:10651000D700429E16DE0EF987D2EF072D4DF3D03D +:10652000FACC0AF5D323DB5768FB23B1FD0668FFDD +:10653000C51EDA370FC9D3B56F195CAE6BDFA2D0B9 +:10654000F69DD41FA8FD236F9F0A6112212F0B7F98 +:10655000C4F6CD83CBB1FD07153A5F896C3F2EDCC5 +:106560007E10F4771FB43F3E46FF874CD2F77F7012 +:1065700085BEFF0AEBFF2BB5C778FB71D8FF16E18C +:1065800018EBFFE00AD67F33AB37DCBE23CCFF43EA +:10659000D0FF377BEA7FD6647DFFAFA8D4F7DFCC8E +:1065A000DA7FA7F6146FDF8EEDBF2B9C62FDBFA2D2 +:1065B00012DB57CC1E17E047C988AB09D0F6C9409B +:1065C0006A98FA035C683B908E48A2A026E4516169 +:1065D00008D2716F1CC3DBE771146F686FFCF89C05 +:1065E00004A865CBA5F32E8EF515DBF215B04B583C +:1065F0004EE72B4B38A9654111F14D369803C3285E +:10660000BD1D41D10FF9B20DD705C0FE79CD644152 +:10661000097C2791103CFFF467A33647F6CB982EF0 +:10662000A993DBDB22F42D3C8F2A20236A287DD31B +:106630000104E3BBF31FD37910A1F38B0FE83C8374 +:1066400050487E22B3F63EA2F325C8B7D1F9129482 +:1066500013528BDFD1EA0EA751FA4B38FD1F4B4C7A +:106660005F3FBE4308F8A97E7EFEBD31384F5DB066 +:10667000DA4699DE4DC7427FB22E4FFBE5073975EA +:10668000ED3607360BC85F15F8558AAA49C8E2F5FA +:106690001994D7DDEFBF4FC59E4E597F1B71CBFDBF +:1066A000E9FB77AE12063969BBB3DDE61C364EB89E +:1066B000334CA8D724C39447C8AD4D63645A03290B +:1066C00075CB1FB745B43BB3489F9F5DA2CF77C83A +:1066D0006ED944E9EA2815C8265AEF9CB9FA72AD7A +:1066E0001DBB2989C999B75792CAE89B03690E3C1B +:1066F00076A29CE73AD9B71A3DDEC5329DC2823CEC +:10670000FDFD08C8D59F82EFDDEE64FD36D23B5714 +:10671000B6B84B683FE72E1403806F23FD7FDA671E +:10672000739BB269BAFEA7323145F7C748FF3C8F69 +:10673000B13F8D328CC3F3CB8DCF196EDAB9FC3FEC +:10674000067CD0F404E083D27F9CE3A3DBAE327CF2 +:1067500078CD9E9B010F5D4F8804E5CAF1721BC77F +:10676000CB923A3D2E08F1C820C76573859C8723DC +:10677000703087E36059BD1E377712BF9C1E432ED1 +:10678000F3366CFA619A1ADDBF0F396EE63FB21F1D +:10679000F913DD4F26A7BBB89CEEACD197DFC6E559 +:1067A0007A2797EBDCFAC70E50F3416E570332E8B5 +:1067B000BBF73E4D9E6D3A797AB83C8D74DEC5E5E7 +:1067C00079D7F7983C8DF4B67179B6D55F90C990BA +:1067D000687A8DF42D581DD51F05E4B9D01F5B9E36 +:1067E000DE607EF2F188E7558D33928F47E8D98AD3 +:1067F00086525D7E79609EEEFD65F50B75E54BEA90 +:1068000096EBCA17AFBF5B975FE8FF9EEEFD05AB47 +:106810006B75E577D63CA42B9F5FFE982E3FCFF398 +:1068200084EEFD397337E9CA67973CA72B9F59B4AB +:106830005D972F75EFD6BD6FDA77D52D80CF378E68 +:106840008804FC89CF5C27302EF8994B76C13BC772 +:106850007D2AE2BADD3702D3933E17E2FEB42F0F52 +:10686000D38E608B1DC6093A2E2E2589D4CC9B6E03 +:10687000AE5D3F10C66982E3E916D3AC5AFF6442AD +:106880007E6D5291DFC5F50A098D254480C186D3FE +:10689000D1254694B7F5525E4F0D7F727479715BC6 +:1068A000ECE7DEC7175EE18C1177E9D65392017EE3 +:1068B0004F27F7BB8DE5950229897C4EC803A8D7E1 +:1068C000E7F8B85BA930FDAFDC915E401C900F0D7E +:1068D000AFB95C7B8D14E4FD0127593A3D5E567FCC +:1068E0008DCEBE1388CAF603BC8DD53D5FD170AD89 +:1068F000EEBB33FB45A4BB1A6CC54418164B5E3780 +:10690000811D0EB50C9E390AE874BF6182712AD8C8 +:106910000FFDC233BEA2E4E312C8AF04D393BEB9E5 +:1069200098B6FB3C981EF79563FAB1AF06D336DFF5 +:106930006A4C3FF2F931FDC0B71ED33FF9EA303D52 +:10694000EAABC7F43D5F00D3C3BE064CDFF135624E +:10695000DAEA0B62DAE17363AAE95D6FB83BC9C793 +:10696000E1D380BF1838EB786055EDFAC9DD383BCC +:106970006FBAAFD63FB09BCFC5F5668E87541D1E4C +:10698000BE806033E2AC97F27A99E3B0A7EF6397E9 +:106990007B37FF6BF036DEC4FCCC6F8AB76E3C658C +:1069A00018F094D51B9EFA89E3BBF134DEE4647ED3 +:1069B0000FC7D38FA01F31E61505E084F48BF0D705 +:1069C000DC3616A7E6EB09D45365716ADEF61AFACF +:1069D0006E2BFA758111306E9C1FF1B7E110873F65 +:1069E0007FD44C277D3DF7CF88939EF9EEC6F9CD35 +:1069F000D2001DBCC646975BE3185FAD265244E843 +:106A0000B8F6D0B0675C8B46625E2249F07DC05517 +:106A10001A1FA35EEA2B037F7BE3EB9AF8CFB3A1A7 +:106A2000BEF627FF9E0BE97813F397E35A44F4DB95 +:106A300049E86917F0373C2E995D6910DFEE1AA618 +:106A400038D16F08D8F5FCF3D37C6E37FF1EA23C1B +:106A50006AC571B72E0DF937F4F3E1E97DE05F6F98 +:106A6000F6BD377E2E0A0CF897F0B337FBD89B5D46 +:106A7000246EF5C520ED7FE7BE51390FAB60078767 +:106A8000B0795A0FFCD6D6A58CF47CFF6BE2B833F4 +:106A900055C371EB6042DBF988EBCBF9A62B1340B1 +:106AA0002EB41E9C1F74EDE47E7E2F723D9BA9AF19 +:106AB000CF6BAC2F4121C268DA6EBCA29004426A4F +:106AC00044CFA322CE6F5C6D7E881BECB3B9D6A8F1 +:106AD000306F3CFD6648851AF5F185F3879E76C0D8 +:106AE0003C6C659AC9793C861CB5B4AA31D3698FD0 +:106AF0009CAF04F5F9F375425123CEE7D48459A332 +:106B0000609C713A8F0F05BB9F86A956CFCA34C5CA +:106B1000799CDADDD30D59096CFE1760F6645B22AF +:106B2000DA9BD33E0BBEFFCFA6A7A77A347A0869BB +:106B3000229F58C09ED3B2AC9EDFEF511FA48B0A98 +:106B4000C43749B3FC39CC37ADF4FFAF8640BD1232 +:106B5000E6B57ABD8DA2DF3C1A9E6FD3B547BF5311 +:106B6000B5B557F8AE67BD9348BB867B2ABF57F9CA +:106B7000FAF08A06AB53EFC726EAF2DE60BA53E7B3 +:106B8000D7C23FC071AF1124C05F25875FA7645F84 +:106B90000F78DA0CC14398BF08ECBD2A4B9BE25139 +:106BA000515D5A019F8BF234FCAB73FE4CEDD4A9BE +:106BB000D765027A46BEA454E5F2A920E2CD444C42 +:106BC00034BF98BFBDA86945318C5BA74C6CFE50A3 +:106BD000464A1C303F2E2775B9104F3D4B4C45A0FF +:106BE0009F67C93B8EB111FA784E54B0D2C5EBF510 +:106BF0007E3C9DDFEBF2CBEAF5F9A5E4D6545807CD +:106C00005FBA41260101EC86BEFC98E8C47A9791F0 +:106C10009A75306EFF9CC7BB1639899441E9ABFA6F +:106C2000CD2F7317523A2E896CFCD5D67197273128 +:106C3000FA2B660514377DFF93A6B1B7510B44BFFD +:106C40000FAC83756D7F29716D25D1F2FBBAF41BF2 +:106C5000E9D5FC81A8F5644E474A83E00EC4B063D1 +:106C60008A24303DE3F6EE6AC9A98B83E4423E22D2 +:106C70000EF28DF194427478DA2C7A064BE3197E89 +:106C8000000F82D4A578BE4DFD6951F55F2DF5FB4F +:106C900027D63F90D69FABAB3FF79F4AFFD028FA4D +:106CA0000B62D55FF59B1776F9A93DA978E9670EC8 +:106CB00042C7C953525DAA8BCAB572EB0F1D6E9ABB +:106CC0009E94FC0EC0EBA98058144BDEABC3F27649 +:106CD000DB0588BBC13F69FDA79FFF11C6233EDFCF +:106CE0002A3B319ED6600E99A93E56372D2F26D9C4 +:106CF000983FC6F20F9E13211FD4E3AFE2D99FA5A0 +:106D0000C2FE0A8A141E5F0AA13F5BBDE5D3421C86 +:106D10009F4817EA91F13B68FF5212DABF854A4259 +:106D20007439A513E3045ECE176FD38FCE890EF8A6 +:106D3000571BCEDF8DEF9773FF74B9149FD26EA3EC +:106D4000FF9E4026803DD4F84102CC3F5DF3DC2F0E +:106D5000B28F517ACE6C79DD2144F049D3A3F38D03 +:106D60008B7FB547EDD9DE76503D8BF483B4F14A85 +:106D70000D72BFBA99A59572C8712DD5FBCA4DB2D7 +:106D8000CB4F1F57BEF0F4334F421CF38F66D73002 +:106D90005AFF8A170EBC3789E6576C97538A5937C2 +:106DA000EC426AB75CBCF4FFD539DD72A878F98093 +:106DB000A28E62CFEF4FEA96C78AEDFB15322A9A70 +:106DC0001F531BF72B6DF61872693C56087EC29A4A +:106DD000E7FE4B81F8E2A97D02E99F19839F9B0E94 +:106DE000A01F007C4239723985E56678DF4BE502E9 +:106DF000F65A9393B1FC466E4FA03E7524E2F9C556 +:106E00003DB4FDF23F995DD0FFF217EF71403F4E68 +:106E100048350CD7BFFC612AD8AF72D99FEAC49419 +:106E20003D2F7FEABB88B7656F7F3715E349C49D67 +:106E30006EC2B1C79F0EFD5BB27136F66F29F120AD +:106E4000EECA7F29960468FA99448AB6C7D08B0E99 +:106E5000AE17273653478CF6EF04CC1FC15EBF2315 +:106E6000E2BE2A42EE26A0FFDFE57DA11E02E63F3C +:106E7000B330391D904C5CAFA8B71989D72D0FB628 +:106E8000827C4E0F72F78775162F91FC9C1FC2579C +:106E9000B45EF1EDE9FD997C882AE5F2EFE8383F30 +:106EA000159EC3FBADB2DB9AADFB8E7C95D9DDFEA2 +:106EB0002ADE3EA53B0EC6E713A9B1FDD501B2A659 +:106EC000F7749C8EC057847E337DDFF210D36F4DF4 +:106ED000DF03A545507EF130D31FF80EC63F4A5759 +:106EE000A83F96EF9F25A03DA0F3E6587ABD45E662 +:106EF0007AAD2FD77042E996848408BC40FD49C81A +:106F00007F5C5F59BA817E17612FBDD09E23BA3E48 +:106F10004D6F9771FD3F05FA7F4DB7FE938D4CEF96 +:106F20007BF69FFC2C6E23079E7912F495EAA75FEF +:106F3000057D954BA0DF7FDDD6F2DEED544FFFDA05 +:106F4000A8E9A9DE7E1AF5B47CC778124B4FFF6A18 +:106F50007791987A4A9FC7D4537B1BE2F8FF94FD40 +:106F6000D4F89728EBF9A7D9C39EF868B4872F4ABD +:106F70002AF2D3680FE9DF61921B8D3F0D771ADE8D +:106F80002A7E5D7505D89D302E35DC8571A9E12EF0 +:106F90002A7EABE39FB1FCCF106BA274CDB7D44F68 +:106FA000817984A58BE0BC2B7F9688EBA6968B0419 +:106FB000F5BE80C8B86FF07D53CD78F043A7FCFDD7 +:106FC000B6B3F7527AE713BFCCD6E5EB64F4EBBF68 +:106FD000FCEAABC9B43FB773FECEA7ECBE89CA6367 +:106FE000AE2484E2289DF324E24F4882F8AC403E70 +:106FF0008EA0637EB93E0F7F5352BBEBE9EDFDAF30 +:107000003B0FF9A6E9DB3EB676F52EA443B179290C +:10701000124FA52057CA3FEF38213004ED529B5440 +:107020001231AF7A9CDB9DB7A7CD1C0FFE4BFE9CA7 +:1070300051090CE783717EEBE5F6EBBC5F4D00BBBD +:107040007EBE390BE7AFE70F2D8E8FB56FB285E3AC +:10705000EC005F57E9B40B7522C57D27E942FFC5F7 +:107060006FB792AD31D6FDBE2F9BF8E483CB8DFE7A +:1070700089546E73390EE7D14F137222E436EBA6B2 +:107080005392235A0EF0F771C43CEBDBF217700DEC +:10709000FC6DB1B61596C488D7FD84F36FCA2B5F1B +:1070A000E0FED569CDF912F0719A5DD4C5391ED4D0 +:1070B000F475241909744D7965F9A3E3298EBD8708 +:1070C0004417EC57F5369F533C31E6BB467E42FDF4 +:1070D000E0471E909DC8AF2372C912E0EB91D956CC +:1070E00002EB96EF2AAEAA58744E37B378C83C52DA +:1070F000F2D938E1FF3EFEE6CF890F15507E9CB7EE +:10710000B3FDC0D1F8637A7FDE29046A05C0A1C847 +:10711000F2294200E26485C4F3E86401F5FDFA480F +:10712000FB951F2C7D01F6D554370B4E132DAF96D2 +:10713000DA14C0B137B85D02FFFC4695B831DE20E5 +:10714000D58C9A1511D73A204BC8AF96BFDD7E2754 +:10715000F0F7C22C3301BADC23CF3960DCBFD03C5E +:1071600016F5A0A77EFDC147A64C93A01E82F8305D +:10717000E2A130C5A6CBCF9E4A06BAA8DCA698DB12 +:10718000EE71C590DF3285E1ACCFF6CDF2FF997D8F +:107190009B4CED1BC3B51C69DF462B51F6AD7F2C14 +:1071A000FBB6B256ED0FB858B937AB3FC875E56BB3 +:1071B0004BFAC5B26FAFFAD8FCFD35BE0FBB7320DA +:1071C000B56FA323ECDB406ADF62C46DD315CDFF3E +:1071D000ECC5BE59FE77F4EF55B06F31FA3B52D192 +:1071E000DBB7A2E65AB46F450345DD7EA82C85CFF8 +:1071F000E77AB46F0B7F361BF3B2CB16033FC05751 +:10720000B06FAF713B07ED809D5BA438B1FDBEDA76 +:10721000B9D2BEDAB9FF253E6B766EE520769E23A5 +:107220001A87CCCEADCC64766EE55E66E7560E630B +:1072300076CE68DF0AA2EC1BFBBE7A04FD1EE78B4C +:1072400099BFB8839617CF955D16FA7EB1AA9D5F58 +:10725000A8191F69EF162912F239CADEB9CEE13931 +:1072600090DEECDD5B60EF86A21D1B0A7A64C4C76A +:107270000D436DBAFD7247BE68FFF54BA02F7F101E +:10728000719EFDBE89CD8BF67DD13E16F46E37A77B +:10729000E75185C9B3C3E7477B3A7524D3F7AA43BF +:1072A00071384E543709ACBFF70B0115C681BF5D6D +:1072B000C2F9F29D7BD97C798E99F183FC9BC8CE73 +:1072C0005D50162C8CC0C3DC4B1518D79C2B110BB2 +:1072D000F8AF0B0EDD700AFCD60597D6A3BFBB0036 +:1072E0009EC3BE89ED6DEB3268BB772E1770DEA1B1 +:1072F000EDEF9817B6977A3F767E73EC7D1A533888 +:107300003D53EE1302B02FA7B77D102F72FD9B23C4 +:10731000B621BFC85B62CCF8A4F65E984F2EC69724 +:10732000AA55CC6F0EF389F24D15A2F944255DBC28 +:1073300030B59B2F77EEA4FD4DE9B9BF1ADFA2F758 +:10734000E1B8713EB380BFD7131F343E47F59FF3BA +:107350009DFAA9B89FC7C88F46CDCE5C4346815ED3 +:10736000BE6FF23C3A1E70F49F942F94CEDBE60D74 +:10737000D39DE7D9C5F97293E7D8B45415F8486A94 +:107380000067B7976F3F904AFB778B3B330742E626 +:10739000B3FFA67820FED062ED423BA8E130CDCC11 +:1073A00070F8578EC323039CD370BC090A4ED4AF28 +:1073B00090C1CEF17D645ECA67D05F6F908F4F142D +:1073C0009FA09F85DA780572A1FFBCA999C9C55B0A +:1073D00023A05C6E265D0781EFD529822B44AB2A62 +:1073E0000C6EFF21ECB77AD54A9F839E970BAECDEA +:1073F0008C1DF6F4D498389662E1183709468C9BB8 +:107400000BE0BD24D8B768C6F6EFFC1EB347463F75 +:10741000658AB9F508D033E5DF64B2091E06E87F56 +:10742000113830FA31517AF035F7FDA472FBFD2A9C +:10743000C8C10EFCEE52C01FF286D8F8A3957B257A +:10744000751AF24D9343908E2FE3981C60A9DFC804 +:10745000E75BB43CE01FDE6F1664F87E06954F32A2 +:107460002D9A6AFAE2A08677B31ACD2F8827A4470F +:10747000D80DB06F91EB96D5C1B7914F37ACA2EE56 +:10748000991ACD274D3E60072FC7AF28FD09EE8F13 +:10749000B97FEA9BEA4F9A59AF3FFBAC5DAF8F864D +:1074A00038DA5E01ED0A694ED4C50FF2CC6C5ED6B7 +:1074B00062F520CEBB5E935D9BD568FB7315970B81 +:1074C000CC5722CFEF4D850EC1BAB1D34A3ED1FA87 +:1074D0003D84E12C723C78D5EA41F9F554FF045E15 +:1074E0007F4FFE9896FF0EB407FB16557D7BC6F1C5 +:1074F000488B27F5D6AF6966663FBE69BFB476BED6 +:10750000EEBA8397B462FC4D5B7FD82C7A7E2EC393 +:10751000FCB848D0AD7350CA71FDF29F50FF58E5DA +:1075200032F543FC2844F9FCEAB6A7315E7DF6F952 +:10753000633783FEACF8AD482C549F3AB6C5931020 +:10754000DB07A2809F50D124E27A169142B93323FF +:10755000FC0C42D6307EBC148F76A7628739504C23 +:10756000BFAFD8F54936C4DD3A1E60F6CFFF3CC741 +:10757000A3BF2D1BD6FB2B24B68E6F94CFBD1C9FB3 +:107580006776DBE682FD161AD879D78AC639B23912 +:1075900022CE506596595C7BB70DF759FB9F13704F +:1075A0009F32D01779CE52DBFF79E63966972B826E +:1075B0007200CECD56346CEF803878C55133FAAFB7 +:1075C000DE86730AF8A7535F7A01FD236F50D4C596 +:1075D00041A3E28F0D62C80CF1B3A62AB403347F35 +:1075E0000CF38DB1E3F0BDC5C956BCB477979FB21B +:1075F00070C5CBCF3AF0DC6CEB5607C6211B2E1FB3 +:10760000FF8F8A37363E74D978E3698E8F5F99F59C +:10761000EB35A42119E39094BEDC9218718B30EE07 +:107620005FF8EC29580F3BB3E3AF4F01BD95FFB8AE +:10763000F0D47DE08FEDB33A61BCF63E7F04D71302 +:10764000B4EF76733DEF78EE595C87E9F8A3D9057E +:10765000B575EC3D3118D6233AB67F910A71DB55EA +:107660007BA7E33C6DD5CEA9FD498C798096026E4F +:10767000037D580732CAABA5A96530D07996CA1BDD +:107680005CB670FCB8B18AC5E3551E37DE167BBD0B +:107690002D2A4EDC34F396EB60FC6E925D2AE943B2 +:1076A000BCF83095E3E83EC86FDB439ABD8F29BF35 +:1076B000B3F00F2AA7F70DF2FBAC69C9AF9E84B2F5 +:1076C000A6E41EE3C5A13EF04D5BCFDB62767F6C86 +:1076D00006BDD9F16B8CCF83DCE85C8374BCF0D938 +:1076E0006088B39C94BBEEC2FD337BCDB82FAA62F9 +:1076F000EFFBA83F1D3BDFC6F532C2D7D53A48F8AD +:107700008FAD83F0399C774B3C8B3373FE431C5A0F +:1077100075E0731E6F6638D6E2D03DC59FD32D6CE1 +:107720003F91B6CE58B5E5CF0A31C4F5853C90D32C +:10773000B1CBAE8B6A7C70021F2644AEA7C48EF319 +:1077400087D7DDB8BC407EE07F85D74B687E20C4FC +:10775000CF03C2FB24863DE8D8C4D6613AE4D8FB07 +:107760000FB5F595148B414F037D5B57E98DFEAF47 +:10777000CB1F19269BE3A3F974E6CBD8767C824510 +:10778000F876FB612A85A8F57F0BACCF371D5360D7 +:10779000FEA18D635A7FCFF079F299E7453CEFB1B6 +:1077A000AEB105EDB8D15E5413161F34D23B83D36E +:1077B0005B1D64E3C4991DF1013BADE7CC2BBB110C +:1077C000CFD5DB8E297E5ADFC1869795B688FD52CC +:1077D000304E0422E83FF3E2FE6CB67EC4E6E5C616 +:1077E00076E6F076BCCDB1DBF16E3BA76B6785BF6B +:1077F0005161E7772EDFDE69C93D07EA3BDD2A13D9 +:10780000D8BF7FBA512C0AC4687F9245D6E2F24CA9 +:107810006FE87889E71DE3D9F946314941FF7A5588 +:107820007CDED18414481515E2146B6AD9FED2357A +:10783000DF77A581BCD724DE86EB6D7506FE3A5353 +:107840009CF910BF704E2B19077035DA9B44B7496D +:1078500047FFAAF8A2FE701E7F2DF7C788E4C2F387 +:1078600097A2A3B008FA233A4D4E6B8CF505D95E6A +:10787000423C117C919DFAF392E4CBB12AD4A3ED62 +:10788000A3A9B4B41EC442A71BB70A4B79ECDDFC14 +:10789000594EEC77E7363E4F7013D599CAF683C13F +:1078A000B8D1B923219B8CC60F899BE2D1C69F0B0F +:1078B000DBF6EF077BB4D641DC8954CF285755312E +:1078C0000BCE8D8EB1085980D3736FFE96D66B6D3B +:1078D0001671FED069D7F685BA1341CF6CE411DC7E +:1078E000FF0750FE2AB99B4EE3BE4002AFA476DFED +:1078F0002B315DB4E3BCE7FC46160710C9D5BF9831 +:10790000CCE2702400F4F3F16405A7F33CA4F07E0C +:107910009982E73A96BDF6726E88303944F22BB9F7 +:10792000487FBEB4DEEAC8867579E277B7C2399976 +:10793000325E5FBF12FDB953AA7E7ED0D3255C4F65 +:10794000FFBAB4F010D8BF32CF52B4EBFDE7EACFA4 +:10795000A51AF75921BDB02F8CEADD9342F4BEABD6 +:10796000F2E6C7D6C17C397AFF151901FBC92A484E +:107970009C0BCEE7AC68D097EF03BB7915B093D8DA +:107980002F17EFEB95BF6DC37F3179DC65F9EB0AFB +:10799000C1FBDBE231AEB2ECB5C5689FCC697AFEC3 +:1079A0005A553D7F6D238C7CD4F339DEA5E79B3699 +:1079B000FFEC89CF0979FAF3BE463E4B84C71B0220 +:1079C0002C0E11B5BF2DB809E936F2D9C8D7760B00 +:1079D0005FF7E27CA57F25965466B281EE74298418 +:1079E0007A61D4A30C7B48807F0F4A09D4E257AE5A +:1079F00078B4EF69BC3F4219FBCE067A2402BD2E53 +:107A0000D42338D10776DE463E70B65B41589F904E +:107A1000AFAEE9599EF794FEFED822FAD546C0EFE4 +:107A200068D42B766E378904D664829EBA9C306EF9 +:107A300037FA2C6A9904F79F10B56C28DC7BE2C4F6 +:107A4000F4C77C1F4AE74882FB821B431753C13EA1 +:107A5000FD38A7EB66B07BDE25A404ECE0CD716CAD +:107A60009EB298A77FB72ADCAE4E7BED7AF8BE595E +:107A700056E15C7867F356CB30C80745BC7FC49BA2 +:107A8000587715B4DFD12C33BACA2C816110BFD816 +:107A90002B63BB1D6593F17C65D86F6B66FB403A29 +:107AA0009B3F712C8EB0E71DC19F5E05F1AC274C4A +:107AB000B1F79F0CB79AF8FD35DF70FC6D8CDA7F5B +:107AC00037DCCAF6C7FD7808ED4775E9793E0E3315 +:107AD0007DB896CBF9F74B6FC0FEEF6C1654184784 +:107AE0000AC53B6E1C45FB39F188C4E3302C2E39A6 +:107AF0008EBFBF9BB8D2801F13AF2302E8F3C43FF1 +:107B000012DCB735AE6629CEAB7EEBA038CF8675DA +:107B1000528A5BB07367ECE8BF8F6F9574B84C9C6A +:107B2000E6698179E684A304EDED84A3FAF23C12C0 +:107B300010B19D36FDF36B4FEAF305568E6F074982 +:107B4000057C6FF85244BA3ABB88EB015A6F67D98B +:107B500000BCEFA6F3229CDAA5E9976251AC717ED6 +:107B600026E081F2EB0985E0F8F2C4523BC6EF5FF4 +:107B7000595A71058CEB9F7FCF7345AC73E011763A +:107B80002981EDAF722750E229AED70A8CDF75E963 +:107B90002531F6EB6B38D670ADE1397D699C27D67F +:107BA000BEC40FADCC0F29583A4250605EB64F208C +:107BB000C0D78E073C973D37E3270F64003DDEE0DA +:107BC00005F4B32DCD823B969FB1CAEA60F3BE07A0 +:107BD000FCB5B01FEF5EAA94601F7BAE7703CEABFF +:107BE0006E87A02B7C67A95B88E7709758C866886A +:107BF000674B75E9B7C603EEA7CE5847E97DB2C417 +:107C000084727E427621FDFE2A4230BEC0E3B50377 +:107C10006F269B22CF23FFC09AFFB095D6FBB0D52D +:107C2000897249F6B804A0DFF5DFFFE500BDEEBCC0 +:107C30006446390EE0F31FEDBBAD9C4FA3E3DC6B54 +:107C400001FFA43C05F5C3E571A865C9702F01E5E6 +:107C50007B8C7554CD2F4DF250DB46E949B29BF039 +:107C60007E2EE276AB4E6DDF19E1EF45E8030909A0 +:107C700004F6A569F654681642F114FFE32CF610D9 +:107C8000CC3392CA69BF2909566261F5B54A67C209 +:107C9000E7AA719F3BC5652E1C6E22B8AF0D36D288 +:107CA00042FD9A9DD5ECF3DA4482F666ED635260AC +:107CB0000DAD67A3D46685F849A65B2D80AD444918 +:107CC000928AE7BD0795337DB465FD3231ECAF5044 +:107CD000651FF30F7141ACF5BA8FC3FCF2BC00FC19 +:107CE000CA3ED4F50AB8352E2B6BCF75C082FE790B +:107CF000D86E703FAC908FBB133F35B1FD02A1EB46 +:107D000071BF9DB68E66B41B540FDE1541AF3E9514 +:107D1000089ECF75D3FF72B52D7711F6838F93B977 +:107D2000C19A16F4DDC4912D80C76B5FC7BB38A222 +:107D3000ECC884373C6B80DE6F6A3F8C781813A2E6 +:107D4000FAC8E53352857B2A9CE13C94B75AF9FC8A +:107D50008EDB9B94D271FDD1AFE53833F257D36BF4 +:107D6000A3BEE7AC76B598B1D60032C1D80E11BA31 +:107D7000E950B3C01EBD21827FDF994FF142E9BABD +:107D800017F40EFCF38B8119809B0DCDDFB1827E41 +:107D90007CE3F1A3997E1DB1BFFA27A2A7C3CAF65F +:107DA000873B800FD5FB2FF2F12384720ECB95EA2F +:107DB00047643C44C3BD11E79A5EAC810B33B2F01B +:107DC0007C1C01F98842230AD64C363A81AF9A7F4F +:107DD000BD26ECCF26E2B99E554ED6DE1A59F3CB1E +:107DE0005D16E8EFAAF882FE975B17F55EA2F3979F +:107DF00088F3305EA90BE767DE4B0A09247F0B7E10 +:107E00000569EBB93A7EA5C4C5E05707E8D1F8FF8C +:107E100027FB936DECCF836A777FAE259EDFB6514B +:107E2000BB907B4F7D3AC305399C16890BBE5ED94A +:107E3000937EE751FD06D72D4A9F0D7A3CB199EA12 +:107E4000B1295A8F5D7209DE5BE7DA6B437B67D439 +:107E5000EB8BBC5F5E1BE37B8DE8991107F37153DD +:107E6000D760C05DB64A928B29B1D94191ADAFB60A +:107E700026EBC691E8F1DD8F7652F32F35BFD2F8AD +:107E80005ED8AFE4E38616CF148214FFB4DFF7C7E1 +:107E900079E6015FD738D9FC130E9A82BFFC03AB99 +:107EA000E70EA0CF46FB1007EB1A2342992C5E1277 +:107EB000D2E95B4FFA6533E84F6348C271CC4FC7D4 +:107EC000B16142CFF4F48B4B64F452AB027ECAC072 +:107ED0005CC21AAB26B8AF7B6036BB4766600EBB90 +:107EE000F7F1DFE3D87ACC7D716CDCD0D21F584B30 +:107EF000EE817EC912F19B73BE39DD402AC40FEFBB +:107F00008F73DF0DFCB014B9B11F194EE21228DED9 +:107F100032A44601F6372455AA028B1B1236EE40D6 +:107F20004AEBCB2856F361DCCAA0B616E22019CD85 +:107F3000B1CFF56C8893BF5DBCAB29EA3CCA8638EB +:107F4000E66F1F54687F938BD9799470DC86920F0B +:107F5000FCED88BF0D3BDBF1195B0FF527323E1BB3 +:107F6000E75F2030E897C4F33F5488644DC2F9912D +:107F7000DF04DF992C383FB2115723D8CF97E2584E +:107F80005C759DE05A0FF99F485D16B86F47C3FFB7 +:107F90008F27DFEA92E82B8EEBCE67C39C95EAC36E +:107FA000F320AF8EC9E787AFC51E740D6678738B5B +:107FB000BAFDEF9ADC82B24E6E56888744DAEB78CF +:107FC00005E7F71D429C0BE6431DCB0546A760E184 +:107FD000E703247D9C86DB436D1C78272E13E9B7CD +:107FE00011FF18BC1FCCE2B2003D1AFDE173A4865C +:107FF000739EC673A06959E1B84D3AEE932D51E0D6 +:108000008E2F72BED986FE97D7C1F4DF8887FE60B7 +:108010003C2E736E92F2AB15E4DB5FAE49047BDB62 +:10802000FFCEE30E90AF910F9D827FCC4158DFFAD7 +:10803000831C739F8896A6A50D28057F342D3D0DC2 +:1080400053ED79BD5D8A19073CCDF5EE1BE3B59E76 +:10805000580CF3C3D3D09FB39E77DE73A3BA776176 +:108060007CBC3E8EF1BB5ED1F8A826809E75E75D94 +:1080700009EC7E924476FF9093C97383CF522A49CC +:1080800091EFB9D11FE947DC33E68111D82093ADD8 +:10809000886B16BFD1CE655043C7E497C8E8FAB9DC +:1080A0006F4C29EC9F916DCC2E5DDC301DDB4B2598 +:1080B0000F588753BE2E2D31B920AE7376D19F1C39 +:1080C00070147C51466B2EE0FD88E8916DE331D44D +:1080D0008DF3B76573954088422AA59E1A2426978A +:1080E00019B8EEB8D01473FFB3DDC6E6DFCD714E1C +:1080F0004CD3D20697968D8DCC0F44396978A47AEB +:10810000985E36AEFB9C30C5470AB46FD4A74E9933 +:108110000461DD40B387299CFF9A3DD6F42105F424 +:108120000CD6014BA87DD4E43984BF9A8AF14AFC6D +:10813000139A5FFD02E6038EEB0AD0DE51FD5F8FDE +:10814000FA3282D96F2BD8D3883865E7DEF707C1BA +:10815000FADF87DFBF100FEB407F91BAE2C17E9E4E +:10816000BCFFDD783837F4E1FD2C5E7197611E3578 +:10817000C1C6ECFAA3B6926CE8D702DF7FE77A2299 +:10818000704956B3758DE501D1709E5C7F2F4F55B8 +:1081900063B2E19E1E3FD65BC5EFE732CAA192CB28 +:1081A00061F9B64D4A860AED7BDCB67E706E8FA013 +:1081B000BD3CD9148FF3118D9E45DBC6283077FA6C +:1081C0004BB399AF7FB7CA6C5C7017C37A9687F3CD +:1081D000CD48E7C17D36AC6FC9CFD8FE9485B4AD2C +:1081E000D5D4BE7A9AD9790B633F967CA816F6A7A8 +:1081F000C25BF29080F36278FF7E3A4E79563F88F8 +:10820000EB5EC67E1AEFCD319E5FD5E653CBB8FC50 +:10821000CB8807F52FEA5C6B335B9F36C6FFCE1F1A +:10822000CAB261FF6D3CFE914B26C079E81D87867E +:10823000245CEE3EE533FC1E26B8571AD2933E82EC +:1082400069B64D65F76434BF7D2FE0AA3AB81DEFDB +:1082500019FBBAF6A6AAF99403F6306B7687FA9161 +:10826000AB013FA44CD0F997D59B2E286CBECBF820 +:1082700070077F7E07F4371BF659AB3F9A4CE57CBD +:1082800047A57C31F21E32BF4D7FEEA6AFFDD5FA79 +:10829000A9F55B2BAFE2FBD18CDF69F8CFE6782C38 +:1082A000DB52BA6E0065D19ABD2706F3F368784EAB +:1082B00047C397113FCB484961BA108193E647B154 +:1082C0005F9A3CCBEA16F2FEFBD3F8BA5E1AC48F73 +:1082D0007AC38D111F1D72DB60D067233E3A7AB8D6 +:1082E0005FE42736E62794A9EE4288675137769DEA +:1082F00033C24F3929D51DBC0FF46C0BC379C4F8B8 +:10830000CB9CB9D7651CCF57C6ABFDE13E3D94DB96 +:1083100044D81760F6C37B5A3BED3EB76BA8047C8C +:108320002FC2F4B4AFC435746877F9D2272E38C0A1 +:108330008FEE1C41308ED311AFA7F7773611E9F9D4 +:108340001D9743A5D4FA8F3F838DDAD28AFB1DDABD +:10835000BFE471A02FCD45B1FAF927FE1DE1F786E4 +:10836000DDC5F54C9B972CE072BBAB99AD672FDA5E +:10837000588AF230EED77A43701666D0AA3C8D63E5 +:108380001490BF513E4B5CDFC17D605172228FF073 +:108390007D011EDCA753562F62DCC328BF7CBB9334 +:1083A0009DA3576B701EB7428ABD0E79A5DDF4B54B +:1083B000FA63ECC7C22601EDA491FE655B6AD70D96 +:1083C00020D07FD6BFE87E8406A25DE2FDD4FA55B8 +:1083D000465C78FF40D4FA50DBF524723FF5F2E6B4 +:1083E000C5B82FBF9AF69FB03812C68534FA357AD1 +:1083F0008DFD2814CFC81688E3AE165C609FA3EFEE +:108400002773EBEE3F5CD8B07F20C8AF5D62FB66A0 +:10841000DBFD02CE0B3B3F206C7D60BD80EB693DF8 +:10842000CAAF99ED07EA598E350ADCE757B651888D +:1084300029C765F5F9AEA111766A7960866BA88EB9 +:10844000DE46DC1FB2A2A154F77C809DC793B8FD25 +:10845000EE4DDF484D62CC3893A65F9ABE69FA971D +:108460006F57D93C470A1CCCC804BBFE18CE4BA89A +:108470005DBEDACED707E6D157AA9FB8A05B1F58DA +:1084800092C7E4B3442CC6E73DD957CA079D7D1E69 +:1084900067D7EF7FF8B6FDD1FAA1E985D63FA35E95 +:1084A00018F9AFC5D58C7230F21FE882F9C11B7B79 +:1084B0006D810704D07746A77FAF15E9EC482B7094 +:1084C000C139C83FC00794CEEAF4DB315F239694EC +:1084D000DA715EC7E74DE3FA163FC8E17ED64EABD0 +:1084E0007B2C3B4754920CB89852DB36D3E2A4F86D +:1084F0007C647421DC2B3AE5B1B69910FA5EF2C8BF +:108500009842B85F7ECAD6B6772D2EEAD7D58E2D83 +:1085100084FBE55780DD80F60796DB10573DE58943 +:10852000E7F27995BD3FCE5C329FDDCBCCCA2B29DB +:108530008F2D743CAB3C3CFCF7A09F95ADC545101E +:10854000B7A98488371DCFAADC8E902D9B8DE79329 +:10855000E87BDB6C9E5576F0EB2EADC5F1ADF2B04D +:1085600084FA440EB1B8A844FB6AA5DFAD8DA37EA2 +:108570002FE5EFDA248B0BE6AFF4B91FE6B56B936A +:10858000DCAA1AF15C931F7C0774AC35B175FBFD56 +:10859000AF0D4F68BBCC78BFDF4726C33CA4C5678F +:1085A000C1D4589EAF38F17C44BE89C5358CE5BF37 +:1085B000D2EC2C51330017D5871416AFA67FE04FAD +:1085C0005611A617D5849DEBAA3A4CF01C4BF5A189 +:1085D000423CC702FBFC3FD6E1F05F738EA51B5700 +:1085E0008C4F059230598AC0F534BB559717FB9BC9 +:1085F00046407F8818E78273186286A96607EDBF38 +:1086000078054D293F24A74B84FB5AEAA64E11E179 +:10861000BEA93532DF3F6262E7CCB5F69A387FB447 +:10862000F4B4BD6407C8FDEC5BADB936B67E81F32A +:1086300061ADBF6B04371160DE7580E0F9809C147A +:10864000D202FCB311771EE0ED3D7B12E7375B37BA +:10865000A67F1990BACCA697558AF7571F5984FA66 +:10866000E04A30DD9349F36FD997B17C86E9422621 +:1086700085F0DBF67296BFC6746108CDBF6B5FCE26 +:10868000F2B0C04907B623F68A42FF486887E37D07 +:108690009BFB1AC0B76462F117E91505D753B47D87 +:1086A000216BE9440BF0F81ED84D88A7D416FCDAEC +:1086B00006F1EA02B70AFB3D36F37B83BE69AAF1F5 +:1086C00055B49970FE0329F0FF43CE4F4D2EA4C937 +:1086D0007D0DEC8B258DEE6B601DEDB4DDD306F6C4 +:1086E00066EC1BAD53C07E37BDF3A75CBC9FFC0A94 +:1086F00056CFD837E89C90F6E7EC6F066D8A5C8F12 +:108700003E6DCFFF14BEA36240FF54509DE40EAAFD +:10871000876BDC4455B260BEAC9F2F3611669FB6A6 +:10872000D94ACE825CC9C0108E5B45F6924EC86BAA +:10873000F69CB426F5695F9B92BD5A847139292352 +:10874000787411D8FFDFB17B3D04B71BF773BE14FB +:10875000BED78CED0FB1C1FE10D07F1749F3A7F241 +:10876000F8178B2F9394DC887930EF07FD7E1AEC95 +:10877000379F6063FB0768BF44B0AB63888AE958E2 +:1087800088676581283D98DF431A8FDE47EB7FDCE1 +:10879000CAE2499606A28B0F66C7B338CB4C078B4B +:1087A0000FC6C98DB782FF10778E38C17FE8FCA550 +:1087B00022E1FE22C97923AE8F1D3411A0F7593969 +:1087C000E084F599AEAB247533E9AEAF93CB5BABE8 +:1087D000F77145BD0AE272731DCC3F7D369FE07E86 +:1087E000E8AE534A00D64D93322C3591F19F2BF9C8 +:1087F000770F390B32E321FEBC378E40FB13F6C5F1 +:1088000099400EBFDE9663053CBC043CA27C483216 +:108810003BEF86FA922E507A33F139DB272FA9638A +:1088200012287F27DD6057E1BEA967AD8D37E07E56 +:10883000D0174C78BFEE4B8AAB14F22F9D579D603A +:108840007F9FCD6C8CC3FEBC60C2FEBC14D775F597 +:108850004A4AF7C323587C4AB21109ECB2642A5041 +:10886000EFA6CF73E3D93C49B3D3CBE399FE3C2EBB +:10887000103C0F2099F2517FB4FD3A9D5D04F7EB57 +:10888000F49BD52A028EE34AB5B851488478CFE4E8 +:1088900012827EDB64BB8CE772607F309C1B9BC2C4 +:1088A000EDEF940F2A713D814AE030DC7FD962E719 +:1088B000F768F175C5EB394EAE236D22F891D75D9F +:1088C000222E88075D7F498AE9474EE7F53E23104F +:1088D0002981BE977F51950077F944EFE74DAF2F7F +:1088E0003C05E3E0548BE139F889488F1BCFF74F03 +:1088F000771AEE4F8EE7F3D6C16470E43E316D1DFA +:1089000068BA38F209F4538B1417F065BBDDFD3EED +:10891000AC7BFA5B6572B938E2333EB69F6FC4A593 +:10892000385CFFA1F8B4032EAEAEAFF35B69BFAF06 +:108930001ECAEA071C825DB9F29729C960E7CDF12A +:10894000CCDE68A9863BC0973381E1CB39BA5B3F67 +:1089500057C567E27B9ABE01EEA09E3D72607EAC79 +:1089600075658AD75580D7ED7682F3B31FA55BE690 +:10897000829E69EDEC8967F837A6EB6A57EE87753A +:108980001DFF676CBC9836E0921239DE7FE86438D0 +:10899000F3AA75336FA6FDF3DA655CBF49E5E78B93 +:1089A00022F1921E81170D771D7616EFD1F03375E7 +:1089B000F7BB223C9FFA1921CE4C129E8768F8998A +:1089C000E267389C72888D13BDE1C7DDE59C06E641 +:1089D000310A3787186E0A283EF0F7B77AC08F1130 +:1089E000374FF58A9B2FF13CFCAABD532FBB6E1865 +:1089F000F4E9F77D1AD389B6D8FB828F727EEF56E1 +:108A0000EA6ECC067B7193899D7F9348C6AD14E7CF +:108A1000BBE3B47BE56BB220BF5D62F6677BB31945 +:108A2000EDCF76BBC78371D7340B9ECB2692A70DB3 +:108A3000F6F5BB0658D4C8DFD1F82EC761A31C9A3F +:108A40007802FCEFD798FCF36ECA811BEC487A19C8 +:108A500093C3B893CA2611E2428EFCFD80AF4FE06B +:108A60004E2DC0C37105EF25AA3EAEA05DFCCDBE64 +:108A7000B70B21BEA9ED1F9EB0E7EDC28291F03E7B +:108A8000C3D96BDCAE6A793C4A0176D2702FFDC443 +:108A9000F07926FDBDF225809FECEE72E37DEB734D +:108AA000E084171D776E6D734D07B360BC6F7D4E0C +:108AB000889D1F9B7DD43D1D4C65D47DEB1C0FB75D +:108AC00091D65D7162F4FDDF747C3E160FF1FBD729 +:108AD000430AC4C11B959A6BD87CA2260BEC8FA6C7 +:108AE00077F847F9D6F8E108DD7DFFC3F8F8F38899 +:108AF0004B62F738B529B84EF82861DF35F271EBD3 +:108B00002BAEF739AB5E9C0FF6706CB91BD76D5767 +:108B100039457CFE1312B26481BC5C12AE7734CA54 +:108B2000EAD41342F77B442A1961A7E57BFAC58D85 +:108B300085F6EF70784C0EF02BA4AE43F0DD84493F +:108B40003963C16EDBC7AC4D86714CA39BD255B463 +:108B5000D5DE4D87465727C7C91D8E8526C778F6AF +:108B60001DD8A1E0B1760B7CAFE1A071EF3926FFF3 +:108B7000083C80FCBBF1202C80BCC6071B4FB5FC19 +:108B80003F1F0FA181209F1EF1007108C7B7C2438C +:108B900016F055C303F5D7AE02FE68FE5AA3C2F61F +:108BA0001D6A790D0745F67C7CCFA510DC3F44F6A5 +:108BB00059D9396D4F22AE57BCEC646D747ED83EE6 +:108BC00098BA9864B283F9EBDAEF898C0909E8570F +:108BD0008EA106E10EF4E306A23D74717E9176410A +:108BE000807B37716F7906F897A164D08B31E6E20C +:108BF00010E07F876D4A06F88739B6C95980AF5DA6 +:108C00002356BD0E43D6AE01E52F6F51BBFD27CDD8 +:108C1000EEB5F06AB5F66F7430FB74BD9B9D0F0224 +:108C2000BB1D498766FF412C4087109A63FACA86AC +:108C3000F6BAB90DEC39D041F9BA5F204DE01FE426 +:108C40009BDC2953C1CFEB179280CECEBD5F0C8643 +:108C5000386571F3AB4781DE626D3DD4A55F0F359A +:108C6000FAD19ABFA3CD2B347F489BCF82DF04E596 +:108C7000D9FCB9D3CCD6AD26872C786EF9F1F3EABE +:108C8000556EAEBF12ED4731EFC72DA415E9D2EEF8 +:108C90001DB999F3A3F8109D876643392137513EDA +:108CA000DCC4EF1DB9C9A5BF57E196BCD8F78E68E3 +:108CB000F5F4F6BE717CB8D6B06EF46DD3433E7653 +:108CC000CFC87FFAD83C77D210D12FC1809A97CEE7 +:108CD000EE6970323E1C52628F57FBB9FE4E32B5C0 +:108CE00065C3B9E5FD7BFE8EE3E32B7BFEFE1EF83C +:108CF00089134F4904F6B54E3A352E01D7E7F3D222 +:108D0000703D59ABD7FB69938DB0E7881FED77575E +:108D10000E527ADC0AD067C1F4B7671EFF29D477F8 +:108D2000F1B84422CF4D142A9EA110C72DE4BFBF35 +:108D3000735060FE92567E90FFEEC5F31CB7B021D3 +:108D400042BB8FC41C21E79BF83D199A5C6F3A59CE +:108D5000744ACA8E960FFCFD33E20B5A5CA199F35C +:108D60008FB4FC11CFB77CA7E96E09FCF3EFA4899F +:108D7000C41DD1EE0C95CEE023E21C2F3B0C7E4AA5 +:108D8000CB733FBD998E2BDE3744DC4AE86DDEFEA7 +:108D90007A36E45BC598F78F18F9FB9DE6BBF1FEC8 +:108DA0009121092AD2D35BFB93AEA638190D722705 +:108DB000CCCFCB65F77718E5FBCA9EFF486E1BD971 +:108DC00033BF7B92BF510EBF3D5380EB4EBDC9C335 +:108DD00088DB7DB49F7EDABF10EDA79FFA63AFF802 +:108DE0009C98FFBD2F0DF31A5EBD7B9F4E067F4EF4 +:108DF000C3E9F464869B89BB7F9A4CECDDF232F2C6 +:108E0000ED7307F36BE610D7EC9BE93F770AAE787A +:108E1000B4177ED20AFBB34A388D730E17A2FF41F6 +:108E2000F87910E33836471C89E7DE7BFDDD9BA12E +:108E3000F932985BE37805BFC702B8368E53456FA9 +:108E4000D449E0B2154AAB981DE37EBA469751CE9D +:108E5000474809F6A3273A8D3830D2ABF9E7DAEF65 +:108E6000C0507E4C4FA2F5DDAAE663FFA2C661CEDC +:108E7000979EC6DF9EFA959CC0E3DE1CFF174E4E00 +:108E80007B0BD8DB93BE19E5662CD7EC47213490D9 +:108E900083A91FFC912109A9A80F859714E2A6E3D5 +:108EA0000C19A83FFF4E8AAF40BCDDE364CF7AC205 +:108EB0005BF52513F12477E34E0E3E6603DCED9659 +:108EC000EA6C101FBDCE5EBA06546FDAA705B3F088 +:108ED0009E8736138190D9F4E6732D1047F01E2536 +:108EE000783EA0A079FF54C0E9EFA5569C47755E77 +:108EF00024E4B1083F33D8BCC6067E5830859D6F48 +:108F00003B984874FB90F72730BC068F9FBFD91D54 +:108F1000A3FC122F9F49DC29D9382EC763FCA3700C +:108F2000BD09FB3F4D701D4801BF659E80F385CE96 +:108F3000BD130EA4507A3BEE4C443B333DF8E0DDCC +:108F40004E2A88C6FF1E8BCFBB160A78CF40A1EAF7 +:108F5000C27C615926EEDF98F08FE499C5503E43FC +:108F6000C6F9CD74B1528278D4D9342107E68B7B0F +:108F700084B65AF81D5C7F296B8738FDC930FF7CA9 +:108F8000A738790CFE769CAAE587E1EF0312C33C73 +:108F90006DD5CE0BFBCDB47CD56C01F7EF4E77666B +:108FA000107F047E0AD753798EA5B86CEE5F00B8A7 +:108FB0009E59A43F3738BBC4460291EB168213EF8B +:108FC000213BC8F7697709FC5E7CAEE73770BCCF00 +:108FD000999BACFBAE94303FD3BB5364F771E4B3C1 +:108FE000DFA1D6F4EB46AE8737F0F9F13C4F868E21 +:108FF0008E6288D288403F5B47BEE5621B0ECFA5DC +:10900000E20787E7D3F66E1C6198D78A956B111734 +:10901000696C1D6F36EC8213C16EEADFBB254F9F72 +:109020008FA1C797B5139A3D98BD57C475C3D9F999 +:1090300094CF0289F2D3BFAEBD9860721D8078D004 +:10904000AD97DC788F4E94BDF8A0E81BD98BDF502C +:109050001DCCA37AFD64021F370791416037A68BB0 +:10906000DB7E0A38EAA4E3A639068EB471479BEF8B +:1090700017523D06DC90336C9D65FAA534DCEFA4F5 +:10908000CDF7C37684FA25AE18FED26F12B274F70C +:109090007A84ED4A845F22E77E7BBF643AF5479588 +:1090A0001CA06F20F18F457B8671C942D81805F14D +:1090B000C1B47318E7F14A74FE8AE3F3D3882FB082 +:1090C0007F4252B77E18FD152DCE3CD6A9F9537AB2 +:1090D0009C84E38DB3D87DA51A4E0A819FA0FFB36F +:1090E000448CEBF4861BADFDDEF012A2F6084C5664 +:1090F0008F78E1FAF775F1F2176D7C194A86F6055B +:10910000271A3E34BC18C79BFF34C4837A1A6FBA3F +:109110007A196F0E8C90D1AEF7E6D77CEAE4F3EAC9 +:109120000427A6375C351B7F97682CD811F037F9D8 +:10913000B8158E6BD5339C1C685B24C1FA9117EC73 +:109140004766B71CB478F0FF00C6C481D500800024 +:10915000000000001F8B08000000000000FFBD7C25 +:109160000B7C54D5B9EFB767EF7924334966924940 +:10917000323C841D082121090E21BC1137490811F8 +:10918000A20CA8888FD6011F6020094DADD5536F62 +:10919000332181526C3D58BDD67BF4F43758ED41F4 +:1091A0000D75080183277026A098F0D020F8C07AAA +:1091B000DA6829451B92185A0F6ACFF57CDFB7F69B +:1091C0004E662683A5F7DE73879F2ED65E6BAFF5BE +:1091D000ADEFF95FDF5A9B4AC09F0A50B315209844 +:1091E0000650F9E1864A4806E83B20011403D4966C +:1091F000C9411BFEB5B4FDB1C745DD0C5689DF5131 +:109200006126C0F5207E0B950EC5E60658E695BC96 +:10921000721680D62EDEBFE19225A862FD7AAFF9E4 +:10922000E31E9BE8FB35FF5F03C800B8517F7F1941 +:10923000FD0FFB2FD3A460185F5D363BBAFF8D97FF +:10924000CA3F91A6022CD7629EC34F3E93A7F2223B +:10925000CCBE24AC5744B78F7326B9CFD9F12FE3D6 +:1092600061FCD732C0C5F3656F51F7AFE977EDC840 +:10927000F2483D526601E8ACB77119DB5E6E017FC2 +:10928000C881254D50C4650052010A9DB8981958EF +:10929000BF64010DF9086313E0F7B93A1D1386DFC7 +:1092A0003F88E30770DC308E1FC8013854EFE4FAC2 +:1092B0006BF51EAE5F93822FA4E37F87BFB0A8B883 +:1092C0009EC5EDDF51FC38DFE24B0A8F3B9BD69306 +:1092D0004F0B8371B49E3FF716FDE30D30DCBFB634 +:1092E000FD338BBFF0F2EBF95BF3E7A7A83C3FCD72 +:1092F000AB150CCFBB44011883EB5C9A1BCD5F63AD +:109300009E58F9C6CA6FB9FE7EACFC56C4ACC79075 +:109310000FF4A2328D8AC3FF4B26D0A65F5E7E4338 +:10932000F2B1F8B3BD0523DB017EC9721A1E4F9757 +:1093300017742BBE42419719F5BA52B70BD4EF40C0 +:109340000ACAB9B213C28948D8F5E72B3E51A8F42E +:109350004AF071943E037C6CC85B1E1E7FD125E4ED +:109360006BDAF0BC8B146477113D1F0B8138EBA8CE +:10937000A17114EA1F60396CD9615A15C2755C631A +:10938000813B7D54268A32E094B87D93D3C4E3F6C2 +:10939000FFC56682AB015E3E985902489FD7EA3C02 +:1093A0000613014266E0F7BF4E52B9DFE6240824F7 +:1093B000E0FCA074DBC85E9412805CB43B65B4250D +:1093C000D88843362B611FD961BF578106B4DB2F84 +:1093D0008DF70E056E0714C9E68F734C8D59F47E18 +:1093E000B87B1EF69B55A4A8DBB08BCBAA7E87DA90 +:1093F000FB0E589DF45EFFFEEF7798699CBF8017C7 +:109400002984D70E5881DAE73BCC41F21F8BE4E385 +:10941000B209EBFD030056EC3F7F55B814506ED7F0 +:109420004077A313CBB924C738F27B8DD69BCEFEF1 +:10943000C3310AE5B44097D302DD6F951E90D98FF2 +:109440009426C941C81AF653D7EA325A806C253A95 +:1094500016B4E17AB1FDDA4B4A5CBFB4481F77E13C +:109460009F4121935C08D17ABBA84DF8A312D01478 +:10947000C0294B6D31EDE497909E45CEE8E773C966 +:1094800077A25EEF8EF14BF833D1BCF73BC5BC8BB6 +:10949000E4BF26F7E0FA5FB668EFCD437A074E9A4D +:1094A000E1597C0EE7B13267245FDAD0AE83399799 +:1094B000B78BFD07133515E97999F4C741F5D19AB2 +:1094C0003AF5F2FDA7F60C94607778B97985021326 +:1094D000581D4F7B3286F93D82AF3AFF63F9D9229E +:1094E00041931DF9BCB0DD5B46AE65041F3B918F17 +:1094F000F85EC980C6F35C291F0DFB78F95CA246B3 +:10950000FAFEF2B9D11ACDFF2AE96BFAB0FEEF3FAD +:109510003B9848FE13F9A82AA817032E9BF759D6A3 +:109520005FA1F7A15139C16D586FD1F5FCE5C48138 +:10953000A3F9C4EFEB4DDE67691A65E3C41585E452 +:1095400037B7969CC577240DA407D17E24D509771B +:10955000601940FB217D0BA402EB93194240F336C6 +:109560006AF034950BE6AB29C4EF411CB3DB41E351 +:10957000A929A4E7F0D78B337D8523F9DE528F0A22 +:1095800085F3B4D6DB34251B605FBD93EB6DF51E10 +:109590002E5FAD57B9DC742CF9C1208E53AB593412 +:1095A000256DF87D57AAB08F05E86788AE052005C0 +:1095B00003A8730B1ED6F55E91829B249213AE27EF +:1095C000829F2897C19EDC08FE36294D9366B235EE +:1095D000B0BC8BF24DFC3E06FFE0F35923FBA3DC4D +:1095E000A3EAAA4B627EE6BAB42417963F74F852F7 +:1095F000A86C916E397C01B8EE12F55BE50B38FE74 +:10960000F4F0427810E3C374140CF1157FB713FD26 +:10961000333A2C40F2C180CA7659A4D3A37D2E4997 +:10962000E7703E329DAFC7E07BD6CA30E9D13EE855 +:109630004923BE17DB7C76B428A443C855936EF645 +:109640004838DE9C748B5726D226FAA66F44FE75E6 +:10965000A4E384D8BFA32363AC8AF6A6296FBC4FCA +:1096600076ADD91C61812BCCBD3D11713C139E712F +:1096700052BC229FF635F2BDF377C901F66B8873B1 +:10968000C88F759E4AF686719E6B2ED9BC56D27FC6 +:109690007A11EDF56062F254F2CFD05DC6EBB8D628 +:1096A00026D6916FF617BBD89F850F9FC0F7FE6D2A +:1096B0001080FCE935DD1FCA80F4949AF2327B9069 +:1096C000CEC3D2E4142A9FFC5D720197A7927B89D6 +:1096D0003F074D7695E67DA75E2DCE467DD1DE72A5 +:1096E00098001DD682B71C0A9527EAA1381BF5E51C +:1096F000AD7A1B9727EB9D5C9EAAF7707918DB4922 +:109700009F5EC776D2B737B09DEA5DD84EE5311C73 +:1097100097CAA2DB9378BC96DB922CB48E83C9D017 +:109720006CCC4FFA144E0CB78217E03F1EFB6AABAD +:10973000ED2A8C97567FA1340DF9F4B3AF2A14ACFF +:109740001F5B3CEEA1BF60BBF967A61FDB90DE9BF1 +:109750004E395A8F63DD9EAAFCD841FA792C119DAF +:109760002399B5B94B433AA6936F1CCD6CD760369D +:10977000D6D3F47AC07C5DD97C8095A53DF9E042D2 +:10978000257159AFB3217F57DAFDDFA3BA25B0ABFE +:10979000A2EC2AAA6388247B97CC41B6F7B1927BCE +:1097A00005C6BB950EFF7F12BF0D7BD1A43FA491D0 +:1097B0007F98A949E072B3BC8393A4E1E746BF95C3 +:1097C0008E45FF49FABADE25B37DCD982F6941C792 +:1097D00048FB35FACD38AB9691FC669E2F6FA2728E +:1097E00059858BEBBE55B39AC8FECB1C977BBF94B3 +:1097F000DF7FD06566BD2D51B05F9C3868F49B8ECD +:109800004A46B87BA02B31F82CE9F5697F6312D664 +:109810001779B28A64DD3703D75D3BB6517BE5EB40 +:10982000AD6C57DE242FE1F299A89069D8BED02103 +:1098300079C3642AF33F6A4AA376A7E425B62DD4F8 +:10984000A69D28A6F66CD9BB90EAA7D5320A51A7E7 +:109850009485F32E60BFC5B9295E1BBE772AFCD064 +:1098600045D2DF85B949DE04F2F34AF0E91AAA7B52 +:10987000ADDE0695D6F15869328DA34A5E13D65BEC +:109880006E28FD1F4447892F052489DA5D0AE1D738 +:10989000277FF7C33227F66B192701D9CFA970DECE +:1098A0009F88FE859D896A02F9698BB38CDE6BB156 +:1098B00048CE4D5CF79552FF408E597D1EC73D7EC8 +:1098C0009B9DE341E55B058C838EDF3686E342E5B5 +:1098D0005BF34BA83C6E1278BDF2ADCA0A6E3741FD +:1098E000989C4AE5EDDFE2F7B697FEB0CC8DE31F1A +:1098F0001BEF62DF82722A5622FC24F60789DEBF44 +:10990000BD9AFB7748990F9DC5FE170B528AAC385C +:109910007FB93B21AA7FC55857547D49F6A86225D7 +:10992000C24F56166445D56F28968AB323FAFBE6D4 +:109930002744D55794B98AB323FADF54392AAABEEB +:10994000F2A6ACA8FA42D31CE13FEA617E99B0F3DB +:10995000F965D9208C89FCA953F47D03DBEF263B04 +:10996000EF12F8A9C885F809E552D655CC71B9D8D7 +:10997000AEFBAF00747B6692FF17BF2E1C8FDE8399 +:1099800020FE99497848FC1676231E207CA460DCD2 +:109990008EA0A7CC111DC72B40CD27FF5BD1B9846A +:1099A000F154B96779199A31F231FABD0AF9618136 +:1099B0004362E82EEA32C7A5B7626CF4FB06AEAB91 +:1099C000D0E96B31F99B52098B05B46EC235C67A6A +:1099D0000C3A2EB79E0AF98E3214FFDF5C572CFD2D +:1099E000001B797F114BD7A04BC78188A71807763A +:1099F000A6323EC49F3B1E3E30704F25FA3757A417 +:109A00007F7348EEE58597F76FC6B897C37BC6B8F6 +:109A1000C6FBD02CF3FCC6FB43CF5529FEF39DD8E3 +:109A20003F29CE73B714FFF973D1FD17286AA3033A +:109A3000EDF82848DE00F1FBB8AA10242B3DAD3527 +:109A400051B9E843BF427874F1D9401395F37A8352 +:109A5000C7ADB8FEEB726595F20D061E8A5DD78C18 +:109A600054B14F3A7A49B5ABD8DE1250EDB4BF6865 +:109A70007958B5D33EAA45830ADA2F6A134D1B697C +:109A8000BFA1E56389F59C54E1E7F352058E31CA25 +:109A900067657F5E2A96D5B69E47098BD47C316078 +:109AA00021307094705EC1489C7754093A68BEA317 +:109AB0000F071DBE083F7EA5386F14295B3AE9A742 +:109AC000A445FA91525B8216E93716395D51F5AF1C +:109AD0009CAAD8C77B4645BD779D9A15D50FF16BDB +:109AE0002EE1A0460BE42AE4474D895EC277B17CA3 +:109AF000FC177DFD5E8793E01398DDAAEC8F13972A +:109B0000BCA5827FB1CF57A48A7DEA6F683D586EAD +:109B10004F15F435C93E01E21037933EC4D6714F5C +:109B2000BA8AC6C3913DA4775EBBE922426FF84E64 +:109B3000EAD5D729A8CFDEE9A6EF4EC4FA23A98B30 +:109B4000447D9E69CF04ACFF34B55CD4AF364D374D +:109B50007B017E058BAF2BC37ABADBE74FC579FB60 +:109B6000CD8EAD12E219C52441917B78FFFB8805AB +:109B7000E3290A16954C7321AD76ABD82FD724A0D4 +:109B8000FFA3FE259A4AFCAA4930E4DC9341711DEB +:109B9000EECE3491BF30F66F760BBE87EFE7D8FC80 +:109BA000B5425FC2C92AFAA5FBF72FCA24BDD89EC9 +:109BB000EAE4F5E7EF99E7217F85747D97FAFD7F69 +:109BC000A46B533CBA9ACC629EDE96FC528ABBF9D7 +:109BD000E3511CD2B0BC70BBCFCF1342A82B8CCBAF +:109BE000358F84F54697C54B387DFB907CAFAC6CC8 +:109BF000D4F313B25DE88D9C62DAB81BCB9FEBFA0D +:109C0000F214CD3B83E61918B71CF5019C03E3560B +:109C1000148A3AE9832C170D10DE1EF8569297F736 +:109C2000C763077EFB03ACBF7747BE9770F4078915 +:109C3000823FAB82131A7BB03ECD1ABC2A8C743E95 +:109C400094E67F96F4E0366B7012EB9B6363128DA3 +:109C50002F69C0FB10637F87FB38D5327124EE1F5C +:109C6000392FD888CFB7CC117C36E6459EDA28EE5E +:109C7000BC375B3C37E8C0F95B88FF063D4374C0E6 +:109C80005827C7031079A445B243E461FF60E2BCE2 +:109C9000492D191FD6F79C35F1BEAECFD85780E6B7 +:109CA000583D939B789E392736C94C6C00FFCCD425 +:109CB0005948AFB6ADE77DFA8CEEE87DFAAC4E7F41 +:109CC000A903DF9BF57EFC7CC83C7DDCD910942980 +:109CD0005ECFE989EE374FDFA7CF3B1FFDFCCD54A8 +:109CE0003DBE8D86D191798E3A7DFF33787C420AD4 +:109CF000E929F93A19F96E5165989D3AEC375AEB12 +:109D0000B15F0EF9471B9785A79D7711FD6DF5A8EB +:109D1000D016F2931E2E0D7B2A3C0D77C2D4887983 +:109D200074BD37F838F8BEE0E3B49EDC9FCFC7BA05 +:109D3000B9D30C4175789D73753E0D82E0F3A0D3C5 +:109D4000C27C9ED9F5CBE9617C64F598408D585F63 +:109D5000829A086A843FB5E7A646D565433E3ACE67 +:109D600098AE8F9FE41D1D358E81370CF9BD9A5A30 +:109D7000DE493864BA631DE38E94D913A2C62D3E22 +:109D80001E2B27641CE17624F29F08D79F56A270F1 +:109D9000C62C77803800B33F546270C97699EC685E +:109DA000EED9E8E7E6B4CBC8ED72FC84A93F9FEF9B +:109DB000FEFBF9E9D2A2F9995611CDCF745F343F79 +:109DC000335745F36D943F9A2F63D64D896ABF6A26 +:109DD0006351547DFC8373A3FA6761008CAC4FDC44 +:109DE000BA24AAFFA4ED2BA2EA939FBA2DAA7F5E04 +:109DF000704D547BFECEAA2B927F61A82EAA1FB174 +:109E0000D7F40DF2BFBAED1FA2E6F9EF96FFA23428 +:109E10003D2FAFCB7F998E435C1AFAC7A2E138453C +:109E2000E915F293AEF637BEA0FC4BA044E5BC5357 +:109E30006009781BB1ED09D927915F1B83AC36A16E +:109E4000DF6832C13AF2F78F9A4C9C8734ECBC2A17 +:109E50004DE08BAA34E1F79F469BA6F866F0CFEC65 +:109E6000DE9E4478433699A09BE29AE265BF71C6B4 +:109E700001E16B713E7934705EAB3479F6B299A82A +:109E800087F29B32EF1FE5D17E50717D8DC71F3F5A +:109E900041F99F8B0E9B4AFA2AA7FA0314B7707DEB +:109EA000A1E761245E79AF3E3C89F649467D95671E +:109EB000E366EABFEA8E859368FF3AF4FC8E8E492A +:109EC000651172885CDF8A38F8E87B69223F67C4D5 +:109ED00087DBAC6A630FCA6B9A2CFC3FC685EFA583 +:109EE000E1FA3F901E360B9C1530D3BA314E72DE2C +:109EF000DF8580BA0ECB94E178A47E8D4AF5C184CB +:109F000068DCF9261144FB085B2AC7FF5B0D7FBBA9 +:109F10002E8FF936E888EE3F78F744C1CF6F23D70C +:109F200090DF672C621D06DDE7753FFCA9EE877B9D +:109F3000C9FF46E49BD7ED783C89F0F5995C81A791 +:109F40008DE7CFE8727D264DE0E9F53B139C9179D2 +:109F5000C7EA902BAA5EDB36CA7936420FD71BEBD5 +:109F6000F04B0AAD63836E3FD59D3DC9B701E3F168 +:109F7000A7D370DC9A1D17BFBD8FDE370D648838FC +:109F80001AE0F96E790F18D7DFF21544E1D297D2B3 +:109F9000447EE525A20BCB95583851DF56626C778D +:109FA00051F9C6FC72B23B7C1E96B0BEAC13CC8499 +:109FB000D396FBB3CCC4F453E07D672F2E6D5F9A2C +:109FC000CAF3DC043E33C5C577BF5D9D44FD86C63C +:109FD00033C61943B959D42B57C09C41F99A6B2405 +:109FE000C60D389F8D9EFBEE18B399E2AF31DFBBF3 +:109FF000E0BFF00EEAC50AF0F2B8C6F800A9517E3B +:10A00000F803CB901CED24BFBA2E5398F239756734 +:10A01000AC7CFED1DF30F0EB0790CEDF557DB15741 +:10A0200042BA7FBB7AE057FBF0F9AD4FA1DFC5B56F +:10A0300066DBFD87D322CEC3CEDC7D91ED0CF1C86B +:10A04000F34F92337AC9EA25FBF8A0EAA59C48BCF5 +:10A050007F226D6127BD07B3D3E29E47C4EE2BABD1 +:10A06000483FD96E55C699865EDEA7EB65DD0B933A +:10A07000F9795DD2D07A44FD7999F3577507ACBC74 +:10A08000BF7F47D787AA17BF9819999F6B41BD54C7 +:10A0900073A8747249E79C2AF266CFF1C1A9D46F04 +:10A0A000A3ECEF213D3978E9E364AAEF79F34B5E45 +:10A0B0000FDC7465F4F723F322F95C9B34F02EF97E +:10A0C00093EA7D5695F250A5FBF28EDD8EF59A4E01 +:10A0D000F43BB89E0BAE9E234FD37E6ABF04949789 +:10A0E000AA0927B073AF69958294C7AA6ADBBD65D8 +:10A0F0000CD6AB9A971793BAD6260B3F56D32205A8 +:10A10000693CF0A7317F8A74DB287D35EF1F0BB0E7 +:10A11000BDEFA818FF5C7D78EA59F44F7D2D9F9D17 +:10A12000233A36B459393F762E296C1983F35ED819 +:10A130002D8502EAB0DDF6B9C43E6A5DE8310BCD8B +:10A14000BBEEB9E5D9040FFBF69DB4907F5CD7FA5E +:10A1500058B9FEBC5884FB20DBC5FA9D1D9322F341 +:10A1600049F721FC83C8F881F40508F78290E309D8 +:10A170005D3EABDA273612BBD0AFED7D5A62BFE64B +:10A180007493DF3BB8EBDFFF95E6DDFF2F9398FF7D +:10A19000C557C67FF005184FD4E8F3C0F95316DA57 +:10A1A0001FD6B49ACFC53B17FABEDB77957BC6F0B6 +:10A1B000FE3616576FB18038B79900C1E7291E38AF +:10A1C000062CAB919E1F5107A447710E58D660DD37 +:10A1D00046764671C2E308C6DB17D7B9159E0FF75E +:10A1E000081BE39D57D6EAEDA56A8F85F270359E70 +:10A1F0005E0BE9754DF813715EDFF651B91667BF56 +:10A200005CED167ED3D003C3DEEBD2A7B05D98879A +:10A21000E260C8C6765FB86680E253DD7ED40EDAAF +:10A2200017B8FC034477606F824AEB2BDDF7C9CC8B +:10A230009E8879FEA4DB8751AF79F9A3A966E2E78E +:10A240009E8FA62A49C3CFFB321CEBE2E555AADD5F +:10A25000224E6F4EF69D8FB683046F18E7AD69B737 +:10A26000F3F907DAC1968EE2483BB875DD0ED2F3FA +:10A2700076D98B1601356DCBFD0DDC3FC94BE291D4 +:10A28000DB1606480F65A78FF513FE8AF3CDD4CFF2 +:10A290007D2652AEDB7F1BE991E2084F8ACC6BD45E +:10A2A000987A7ED121915CB76B269AAF08D86FC996 +:10A2B0000E5F0FEF9F8A3354DAC71E9E510EC4A75C +:10A2C0009F1E90385F6B4EF56FCD22F91E95B9BF7A +:10A2D000E5F00B013A97EE9B06C5449FB1DE9F4E19 +:10A2E0000B838CE36C2E042F4DBB79FF2D1ED2DF28 +:10A2F0009FA61F617C61F78680FC4A23E206CAE7BD +:10A30000D80B42611A2721D7572CE33C796E27F3EB +:10A31000CB62F57B291F944D755C874DF1AD23FA17 +:10A320006CEE44B19F1E7B6579BA3EB27F85CE1B31 +:10A33000FD9C2FE9330B3DEDBB0A185FF31D9D39E2 +:10A34000D4A409BEC1762E6BDB3AA646C6DB44F028 +:10A35000DBE879DFFE5BBC44BF3951D7F78C44B6EC +:10A360008BD8F9FF99F499E46E5AB3358BF84C7C8D +:10A370005347F67B5AEF67F003147F2ED92B92AA2E +:10A38000C5CB0F8D77973C4E72DD9CEACB7515F0EF +:10A39000F1AC00C39EC4B87687FDFF5764FF1FE988 +:10A3A000FCDCA2F86DC4DF4D7ADD6CF1A94EB67FFE +:10A3B0009F4AF30FAD6F74FCF5B5E9F6BA6582FFFD +:10A3C0001BD7B74F5F9F3915F58DC64B06EE674E0D +:10A3D0000E0648FF9A92A078133E3EEC2AF790DDD5 +:10A3E0006D39F4C538B2F7A624AF0728AF7560D62B +:10A3F0002AB2FB2DA36F63FDFFF485BC2239629E58 +:10A40000136925ADE4BF7E69ACCBE2CFA575FC42F4 +:10A41000D723635DE96EDFABEE88BC118C755F916D +:10A42000FE80BE9FF3EAF117F7739CFFEB87442F82 +:10A430009D27EED671B7023ED61B3B7855C6551AFE +:10A440001CA37B1F8D1D26D846CBA6E454C4395DC2 +:10A45000B26C32367D9A0DB7E6746C4CED6FBAEB88 +:10A46000963421BDFB21200B7C169DAF004DD2A45C +:10A47000C83CC56B55F1F314CFF81BC92EFF569E8F +:10A48000624ED8B4DA92F2F7E72BCEBAA3F73D9F2B +:10A49000BA55262A942BF431144E0C8ABC174CA7BB +:10A4A0007D5333F112FF7B06D7CAF62DF5E5DA5C52 +:10A4B000684FEEFBB76D1D8B76972DD64FF546FA9C +:10A4C0007BA7C03D43F98FD7A630EE463F27F3FE6A +:10A4D000DFA9D31223B762C46BC0F78852A3F22757 +:10A4E000E1235F26937EED4A55DF22B90C74C97CC7 +:10A4F0004F2441E9B1B8E2D8D93EC203E8F78BD383 +:10A50000C53EC4D626CE176DAAC67E31C1E99C26AB +:10A5100047D8C579B7C89F571FF9609C0531DC053E +:10A52000D3F1E4021C7FC3DE96644AC3AD3FF3F669 +:10A530004CBA9253A2F81DE9B8FE4FA51D3936C298 +:10A54000A95B8353893FA1F08414F293850A049494 +:10A55000A238F1F1A922DE14D73CC587FF50D83EBE +:10A560007D2DE1E5DAB0582FCD61C6A6BC36E07A84 +:10A570005F5B632A8D57FB6F074693BF7A295DE0C7 +:10A580009A172F4D11EF2BA050FFAC7497AEE741F7 +:10A5900013E50B5FD2F38C7D974CDCCF98BFB06D89 +:10A5A000A1EC443D28086F3FC479CD76AB4AF24D0B +:10A5B000780E043FDA131877D61E5C0C14E7FA5DA8 +:10A5C000E095B07D57E2C06F491F060E58553A77A7 +:10A5D0004D706E87541C7F977E4F2B0F15B2C5317F +:10A5E000FCDC982FA1FDE7941324BDE0F3DF0465A4 +:10A5F0003B5CE388E47712D35DA2EBD5AEC4B089AF +:10A60000CE450626E15E87E91AA613785E83CE3C26 +:10A61000F6FBBB2C03E77EE066BA9CA4077920E832 +:10A6200084F6C92AF9D104A7C6EB4870AADE8034A3 +:10A6300092AEDAA908FCD06E1E25E73577D8AE6B4E +:10A640001387EB36B4855D13403F8FFFD5363A8FC5 +:10A650001FAA9383993DFCFE2DE92F6C6B1ACBF951 +:10A66000BD808CA2B66399944AEB54797DE845B5D8 +:10A67000F422C107BAAF67B789F6A1FEA8E70EAA10 +:10A680003B443FAFD5695F92C5F64287D74378F028 +:10A690007E297CEE5AB4D7DEC77C2905B8AE5ED3DE +:10A6A000A1079AB1DF9F568772E83EE97356FF1AF9 +:10A6B000D2CF573E5CF34821F9DB5D666F25F99DEB +:10A6C0009EC0CF1887BF6856B745D81D8C1DC8E0FF +:10A6D000FB8031F3D49ED9F433C2D7FDFB2595CE50 +:10A6E000BDFBCD03E388EE9AF63F5AE8BE64EDFE6B +:10A6F0008F184F4B19FE1A9A6F765B03DF6B9B0323 +:10A70000DBF95E1BFA43BE9F18F2087F32783AE706 +:10A71000D98608393C912EEC0D06FCE3295EB5EB99 +:10A72000F67A90F6DD58EEEDB875228DBF57CF075B +:10A7300018EF35C0A131C4F74DF01A97C6F3FEA04B +:10A7400052417A96FFAEED4E2DA2FFA3E902BF3D26 +:10A750009A2E70667686BF89E85DDFF1B12599D6BD +:10A760007936348EF6B921454D71C6F12343F61B77 +:10A77000634FB5CA8085FAD79E07F62B28EFA6143B +:10A7800094DF4BEFB64D598DCFF7A24C5228AEE275 +:10A79000FE94E2EF5EB36F0CF56F78E7F3A9E4C7C0 +:10A7A0001E484FE7F57F7E60FD78E21BEA7F492275 +:10A7B000D9D96E60BF66D86901D929BE5F40FA5FFA +:10A7C0004CF53CF6CBBB2CDD4BD82EF79A80EC1227 +:10A7D000F59FED01F5DF49F8AEC089F6C0EF4F6691 +:10A7E0003BDFD56DD21827A35F9FC4F5921BA9BE8E +:10A7F000ABBBCCC9764EF7058AC85EC387789C1080 +:10A80000C024129D04BEA8FC883B99E936FCE5E70C +:10A810006ED0E3869AE2C575D86539CA3E22E2A4B5 +:10A82000A81B71F4C933DB9E407B81EED428DC0F7A +:10A83000EF0BBFFF5D3D56D5BD3E775933AEB3EE4E +:10A8400084CCED07F57D5E58D793437A7E86E28609 +:10A850003A5DDCEFA5E733B04EF75D676A1B4B0945 +:10A8600063CDAED87E98CAB9BE502941C8F9ABBAFB +:10A870000F9B8599E793FEB51EBA2E9FEECDF59FEF +:10A88000B1420292D8FAE5C06F5FC4B53D7010F9CD +:10A890001F274EE17258FF106F8D01CFC8F67EC999 +:10A8A000F023BD4B481FFB5AE5E13A1252838A4D13 +:10A8B000F577D23FDD16C0BA3F437B9F54E2C7997C +:10A8C000FEF7493FFB4F7E994166B9F7B4D8C7B749 +:10A8D0005AB47CD29FD609B8B58DA3A7AFA58B3C3F +:10A8E0004FB115E29E4B7EA5C7C19C003C22F1FEF4 +:10A8F0005C760651EE175A65CD82F8E73C0456CED9 +:10A90000237FA3E76FEF01FDA7E11F94CFBD7AF589 +:10A910001EC22B18B7EE7D62C4B9BF89F4696DBB46 +:10A9200004FF846B5FF74CFC7B09465EEBBEB61DF3 +:10A9300047C6A03CAB9E8BEEB761E89E7B88F7BD17 +:10A940001B9AA3EF1B7C95AEE396893091700BEABE +:10A9500013FB07B3029D56D4DF5732FD9F105E7E76 +:10A96000C924F8847E95EDF213B71E674A843F1A16 +:10A97000B8007C8F286F67E830DDD799DB9CE5A5B0 +:10A9800039E62AA27D6E5B16C719508232DD3798F0 +:10A99000ADF9CB195F07B4D3742F649DEE27C1893D +:10A9A0007F28BFA3AF6B9D8EE7EE0B46D33D07829A +:10A9B0008D34CFDA9DE2FED1FA9DF1BF13A8D5C741 +:10A9C000D9F0D4C923940EAC0E45F7ABD5F953DBBF +:10A9D00016FDBC057812189F117DCFFC4AEF43FC91 +:10A9E000C92CF0C5DBFA3846FBB519C27FD62079F1 +:10A9F00024DF0D4139487AB34E0A240B7C0B8ED5E7 +:10AA000048F75D86BEE8F765EFD6F97397AE2FBCC1 +:10AA10002E7CBFFA192948E78077FF249AFE7B42F3 +:10AA2000ABCB491F62F56A5DB399F16D156CB4103B +:10AA3000BE8DD5ABAA217DD96EA13816AB4F357E20 +:10AA4000E932740B5CFE7F4BF77A7398F34CEBFFA3 +:10AA5000A7E4A53CD4BDADDFB1505E74A47D08F978 +:10AA600056197AA2AFEBEF5DCFED867CA7C01496A6 +:10AA70006F45DA15EE83A2F1F46ECB509E92F37C13 +:10AA8000839D13383F6EE851EC38E53A2E5FFC1495 +:10AA90007079A1ADD44EF8A2FFB8C92BA99C7F4C08 +:10AAA0002E443E4C3F2003E18DFEF6898F0790FE39 +:10AAB000A213C53752BE7CFA098C3FD8BEA7B3F8A3 +:10AAC00057E45F11E1A4917D2FECCA4EFBBD83C713 +:10AAD000E1F8DD7FBCE8F14AF2C3C7CB8A695C09C3 +:10AAE000DBE97E78911E871A8E17D97B22E2D1FD91 +:10AAF0001922DFBEC5F3FB47695FB078B7D94BF9C0 +:10AB00008EC566FFA604A4AFE805C9DB80B31DE9C6 +:10AB10003EF4248D8BF6A452BE66F1EEEF1DA2F634 +:10AB2000DA5D12D3DFDFBE287F17C5C7A0ECA5B85A +:10AB3000D7DF7E57C1BD84730EDC537057C47C478A +:10AB400052855F597C9599E371EF68FB2F2B29CFD4 +:10AB5000A9ED60FFD0FBEA1E0B7F57B04B020FAE92 +:10AB6000F388E7F0AF890FBDFB4E5A08E497B69E15 +:10AB7000B4F4C4F1CF467901B77161CEBF6EB7F0BE +:10AB80003DCABD7FB0D07A6B9EFB88F369556D12CC +:10AB9000FBA7AA67E4A04A799E03AF58483F6B9A87 +:10ABA00025C8CC8A6C37733BF951AAFFB159F865B7 +:10ABB00043EFD7E87A6EE8BD61076B74FF75D7D6AF +:10ABC000683DBF17B42DA3F1FD7B9A57F33DA07BE1 +:10ABD000B6C7F75F861F5C4BFB528C2B6B9F8AEED0 +:10ABE00077DF907E07D8BFC7FAC95732F4F3D83C55 +:10ABF000C823FD1E0CAF19AFA03D7D7EB26A3CC4D8 +:10AC0000C93B1ED7F180118F07C3268E67B1FDFAAD +:10AC1000DA2E5A288ED676FE99F16B79FB672C874F +:10AC2000CAF60EBEAF7A3DF837101FAF6FB73B09BB +:10AC30004757F608BB5FD26E0D06256A0F35917C2B +:10AC4000FB0F8AEF3B02AF4A8CA340F77F6B757E08 +:10AC5000AED5F9B716F76763E8DE8ABEFFBE2F7779 +:10AC6000C711BAE251A33FDFD0753899F8B8048410 +:10AC70007F5A1212FEC99087115F46C6D1816F9329 +:10AC80003CD7B75BF9BEF852DD3F2D6D16DF93C59B +:10AC9000FA8BFE517691FFDD2BE88D8DA735ADD176 +:10ACA000FDBB32D2D9DF0FEA78F813C3DFE8F2A890 +:10ACB0001C003BE5E797A8B237C86F752B347FE7D8 +:10ACC0005489CF633BD58929F1EE4B19E59B3ACEE8 +:10ACD00037EACB284F86FD43CEED8EC87DFC8D999B +:10ACE00002AF54CD910324CF887DCFB2A2ACB8FB84 +:10ACF0001EC844BADF187BD74FA645EE7BB41D397A +:10AD0000A4673FF23C5E49F78C6A9B857FE89B8D88 +:10AD1000E3A6108E07C6C5B5CDD620ED4F6A514FBC +:10AD2000F87B30D20FB2BF766911E907EE1B1C9990 +:10AD300048CF723AAAC4F52F6FC3388EC32F2FFBAA +:10AD40008CF5AA2B5BAC1BF996196F1F61EC1F6A7F +:10AD50002E099C6A3CAF517A781F51D32EEE49B729 +:10AD60001EFA625C16D2DB7FE03FC6ADC67241A61A +:10AD700088BFAD25A18FE9BECFE7BB6C71F1E8902C +:10AD8000BF979AD80E6ACC3D198C57F6232E9C8516 +:10AD90007EF3ED4F79DFD17A28E14ECAC7F5ADF1E8 +:10ADA0008F777E839C1A6013E3DA4DD0C425E19E31 +:10ADB000481CB8D629EE0FDDABC749AA3F8C7A7D77 +:10ADC0002FF65D5014CFEE035BE64923EDDDF01B5B +:10ADD000D5BABEAF2FD8B1858EE063F151B56E47BD +:10ADE00088FC392EC6E2A21B33A3F5B4E1ED44C6BC +:10ADF000B9FD5DB29372C4C8D75F8C26DC87F87E3C +:10AE0000429C3CEBA7BA5EF6EAE7BE0DB365E69B53 +:10AE1000698E280D1C85FC637DE93FE908521CCB37 +:10AE20003FF8CA0492FFFA9DD1E745243F3FDFDF98 +:10AE30000AB2FCAA43763E4332DA5F3AF8CA14D229 +:10AE4000B386B7BFCC1172F922C7E2BE3C7D46295A +:10AE50004962FF6B92C4FE77AFD2934CFBAEDAFD32 +:10AE6000B22FF2FEBC21E7BB75FD0145ECF3D765BF +:10AE7000AA5C6F68177A613A204A9C7FA5C8F3984C +:10AE800079FE11ED25A82FDF10B780E842D9D79AB7 +:10AE90000758EF6A4F9A989EDA938319D911EF05F4 +:10AEA00068DC4CF27B0D1B80FD881DC8BF2EA5EF12 +:10AEB0000FB1BEF4FD04C65947263C5229CEAD64FD +:10AEC00020BFF5C0DB559323FDFF053DEE03F1C127 +:10AED0004328E70931BFCE874DB042CF13083DAEBE +:10AEE000D2712CEEAF9AC88E63F757578A931B0E18 +:10AEF0005881F2C7B51F58F93ED0E707D6F2FE1DBC +:10AF00002EF927939F01BFFF6A2A1F38B876323D7A +:10AF1000FFFCE07D5773DE53DA1495AF08107D1EF9 +:10AF2000C2517F79F776C2975D0AE390A2AED3EF64 +:10AF3000D2F9EA9E56337F9B59BD77C6E38124C27E +:10AF40004F454BE9BB9D3D9D0AEB1FE22A0347D9C4 +:10AF500019479D28661C85E3F8825C161FABA47117 +:10AF60004F9414533709DBC99F4D271CE518C6556C +:10AF7000063DFF9C29F8D9DF91C0F9130926083D49 +:10AF800083EC28BA37B4BECE3864439B1CF5BD862B +:10AF9000F1DEEE4C71AEB0D7D0B390A4B11EED1679 +:10AFA000E586B63D19B48EF5E610EB4943B359B4C6 +:10AFB000EF1225D0F9CD0CFED83840FC39468F5021 +:10AFC0002E4B2CC1B184DB770F9D07EAF73982E263 +:10AFD0005E5D63E744FE6E68B0738F3B5EFC394E86 +:10AFE000E73348DAD12CB1CF896DAFF3887CC6D175 +:10AFF00033C22F1E5DE89F1CCF3F06A044ECFB250B +:10B000005D7EADE68A78E7861B3D22DFB4736CE097 +:10B0100028E971EFEE043E37EC7589FC6C694B97BB +:10B0200042DF9FAC6F9566503C5A9FFB1E7F9F820C +:10B03000F562F683E1FD7C6E5ADDBCBB5C8B43C7D9 +:10B04000B51E111F97E8DF018FD057BDFD1478D3CF +:10B05000F57DDA23745E73AAD2EC14DF9989EF4A86 +:10B060006FD0FDF98DD79B19379D02D52CCE3FC4EB +:10B0700039C532DD2FDFA0FBF911DF3B3F039BE930 +:10B080009C22F67B67C3AFDFAC8FBF02341E37F65E +:10B09000BBF59B753C78B32FFAF9A54C1D07E6402C +:10B0A0000EF9F310C617BE1F9197C0717A69E1A41B +:10B0B000B83883BE0357F5EFC0A934E4DE90F71E1D +:10B0C000C7BFA31D677ECDDF139C49800971CEC524 +:10B0D00086E39FE13F6E12F2D6CF2DAA9D824643B2 +:10B0E000EE17700716991F33E43E46E7FFFFF13D68 +:10B0F000A05C5022F325CFCAFE311E3A9FB0F53234 +:10B10000FEC615701CC4758DD3D735CE1A11DF2E2F +:10B110008C5A1D577F87D7971A1071C4CD65479EEB +:10B120009571627548E2EFFBAAC3625F5B5D26F62C +:10B13000B539AD02A7AEBC490A6A12BBC3D3449F5E +:10B14000A13FCB6C020F187A32C42F5D7FA89DF00F +:10B15000C10D3A3E88D5A3C9D05D4EF9E65B34C92E +:10B160004BF72A477C3FBF6ADAEBE4EE2FA73FA8F4 +:10B170006FFCEF22C4EAD1F73DFE120FE5D3BA0708 +:10B180005716E2B847F3FE388EF4A6E63276F32D72 +:10B190008F88133B1D81A37CDFA4453FEF6FC96BF4 +:10B1A000EB217E7402E3C75E57F7963A81ABF9BC98 +:10B1B000BF3A9CC0DF4356B7DBF9BBB0EAD686C4C2 +:10B1C00029E47FDB65AF1DEB95AD27CB889F95C547 +:10B1D000E23E4AAD5DDC8BB3B9FDB7107DD77B3B5A +:10B1E000A2CFF92D3DBFA8FB063D8FF56B1B09A330 +:10B1F000A5FFF7F99B8D3A5FEABA2E664CC1A9FE0E +:10B2000090E6AF267DEC7FFD450B1DD7D54E79A589 +:10B210009CAE886DF4A8DCEFFAE68E264AF31AF4A9 +:10B2200077643AF9F95173702CE3D2822BBB0FD3B8 +:10B23000B0FF8DA914A7FA3ABAA65A22F4BBB70EEA +:10B24000FD731CF9358049B75B854B495AA1E3254D +:10B2500061C7B5070E67503EA297ECB780CA7792D8 +:10B26000B3B1ACDE7D2A7912E196BDA21CC219ED04 +:10B2700032F703A527E7E6A448FA36337D17426282 +:10B280001C809E9C1B0B23DB1BFF5FDBFFD3A427D3 +:10B29000D5B69E28FB37F884BB7CFE3E3770D0CAFB +:10B2A000F708E8BCC61521C757747F340B374B64C9 +:10B2B000A773E87C7A22413B05EEA0BA026125958E +:10B2C000CE8BC3B2B87F3796FDF74C7DFE594AB896 +:10B2D00083EEE9CED1CF37E74237F75B00035C6AF4 +:10B2E000E0E4EF8B4BC0CBE56C5B7829C1F1825079 +:10B2F00088BF9F096728AE7336FD3BE638F21EE62D +:10B300009B02E70C7EC8740E26EE1BC5AEA75BD76A +:10B31000C7599AF03B041DE87EEE6C08F1B9FB3585 +:10B32000D0A39FBFC75FC73CDCF7D1B9DB35683B13 +:10B3300089CC8F20F79F4FEB91E3ADA767298B193D +:10B34000CA9C449F14CE307D6DBFF275F4D36D4D11 +:10B35000CA57DF35D0F783E2E1734B6FFB1BEFD3A6 +:10B360007D6249D3F8BEB197BEC7A67D4E58E91D90 +:10B37000F2631300FEDDB3E637646FC6F71AE00729 +:10B38000BEE711FBBD062DF77CC6F03D35E3FEEDB3 +:10B39000CEE00A95EE6FAC72DBF8DFAD29B28D9B83 +:10B3A0004E79CA87D2FCBF21BDFA406A9EC4832869 +:10B3B000C1198C6375BDB283369BD62F69C6F7223F +:10B3C000C0FA32F4EF0164007FB763B78AEF691EF9 +:10B3D000413DB4A5B2F6AB740F1A1E2E55092F6F5E +:10B3E00071D9BCF45DAE95E8B50FD3DB6813F72FC8 +:10B3F0008CFB6BB17C6CB419794AAF8D7176CC77CC +:10B400003E77DAFCFF9BE8BF3FA924937060FECB38 +:10B41000F33D7C3F29C15877898DEBC3F71A193763 +:10B4200036D17D6AA4AB311DF81EE2E1A49C14BAAA +:10B430001FD5D825EE5337A607D87F9BFD12FBF307 +:10B44000C6CED24E8A07830E0BDFAB6E74F934AAD8 +:10B4500007D22144FE9FF83EDFE0BB6998EF21FD53 +:10B460005E5091EDD75751DE7F9A1B4AE9BD696165 +:10B470006D12F1C0F81E06E5E019954ECFA3EF7BE3 +:10B4800081E2E4FB17861C503158999DBA7C0DB9B6 +:10B49000388DEFF83525EA3B7E435E8F240AB99854 +:10B4A000E926CC447E57A57163E561F0FDBF008FAE +:10B4B00040AEB13049000000000000000000000074 +:10B4C0001F8B08000000000000FF3B24C3C0F0A356 +:10B4D0001E81EF4A313030F1A28AD112EFE364606D +:10B4E00010E062603005E2FB3C0C0C3380F44C2031 +:10B4F00016E566601003E21A20DE0DC47B80F819A1 +:10B5000050FC3910EF00E21B3C10FDBE4C0C0CFE51 +:10B51000401C08C4C140FC958181E11B03F1F67316 +:10B520000A33304C1547F02F03D99F24E9E7FFC1B8 +:10B5300086430CE96BDF71A07DF3AC107C46207B69 +:10B54000BE15AA9A0556F8CD588826BF088DBF1893 +:10B550008FFE720354FE5A4D34B3B581E90949CDCB +:10B560003A4DFC6E41C7AA40FFA9013100ADF15F21 +:10B57000CA68030000000000000000000000000096 +:10B580001F8B08000000000000FFE57D097894D5BE +:10B59000D5F07DE75D66269999BC816CAC4ED844A8 +:10B5A0000B7442421A10DB618B6811834B051798AC +:10B5B00008644F2620F5C7DAEFCF40005151438B86 +:10B5C000355AB40304051B34D88041020EE0822DA5 +:10B5D000D5D86A5DDAD2A0C81A93801BFE5DFCCE76 +:10B5E00039F7BEC9FB4E2682B5FFFFF5FBFEF8F822 +:10B5F0005CEE7BF7B3DD73CE3DF78EE218C7948B1C +:10B6000018FB12FFBEC798DDC6181BD79D32562304 +:10B61000D24A2DCFCD58D003FFCC62ACDCAD85979C +:10B62000A7333665871AF95E12E43748613BE46D4B +:10B630007B9D54DEBE9EE7236ECDCFA0FCA33AC80F +:10B640004BD0DEDEF2C06550DEB943661BB1DB9144 +:10B65000713696C2D83107E37F5990CF66ACC0C926 +:10B66000B3E51BF6CDC5F6454D76E684FECA7715E3 +:10B67000CEBC0CF28507558655CA372FD3FA43BE88 +:10B68000382C3560BE63329F5F68A71CDE0CF53B2B +:10B690003C2D2937B8183B55E5605E8DB16A774B74 +:10B6A000CAF5A3182B096FCFC57625F5920F973AE7 +:10B6B00065C7E697FBE1BAB64A3EBB97B1D22DF11A +:10B6C000CC3B92CFE14BF8FF58A31CF91E942F8678 +:10B6D0007532E8B790D5E43219C75FAB79DDDDF09C +:10B6E0003B55A5D33846BE7C2B8C03ED2A9E967C19 +:10B6F000B8C40A1B0B34C0F8EDBB9CB337B9707DDE +:10B70000CBB4116E5CD7DD1AD62B0CE7EF747A71CF +:10B710007E1BB45C282F59BF412B18D5DD5FE996FD +:10B72000BED679D50E4D0D98CAA3D353558C794703 +:10B7300074E74B18F33740BF4C096BB346777FFF74 +:10B74000802532968CFDCBCCEBE8EE1F2049DF4301 +:10B750006FC13F015EA13D6E82AB81B7C53AFCDB94 +:10B76000DB8DB7B3BAC0A3D2996DEEDF481F403C62 +:10B77000C07C6A104E90AE11F3F34C649314E8DF72 +:10B78000E367BAC47A5F8F91D6A82C9FC1580B4249 +:10B79000A3FDCA78C86B6C11F331F69315D9FEA9D5 +:10B7A00090BF9F05E6E2BC57488122C413630D6930 +:10B7B00048BFAB24361BD7FF039C3494AFEA07F491 +:10B7C0000970AF9996BD4996C4DC93305FF0C4BD53 +:10B7D000E9D44F21F5A3423F43CFDF8F9E9B63E91E +:10B7E00047CF2D32FAA9A47E9C17D64F4DEE04EB1D +:10B7F0007C724B8C7EEEA47EDC17B62EFD8A89D639 +:10B80000F95C5146FD244EF5B100D4970D7A602DB8 +:10B810007E19CA5DF58963EF6566BA98BC12F9DFD7 +:10B820000D5C62A68B849C380B1D26FAFB58F2D067 +:10B83000937EEC5B220F834412351A5FEBAF915C71 +:10B8400098D4DF41F93BFABB482EDC312170B10EB0 +:10B85000F3C0B1593FC86B816FEB31E81AE629B1EB +:10B86000344CBD364CA3CBEF56391C260FF8DB8881 +:10B8700023D03E68EB1C9108F9F5D2A45F205C361A +:10B88000331BC1274E6695582FCECE483EDD9D9E78 +:10B89000BD296482D3EA41807FA9BBDFD56A200D30 +:10B8A000E96B2BBB2184F4B66A10ACA73F634F85CC +:10B8B000AE8F8414683FA8200DE169D780BFCDE327 +:10B8C0006B30FE281AFF191C77078E3FAEE7F8F69B +:10B8D000213996F11D838B2CE33B34181FE87D172B +:10B8E000BB558C0FF09BC0D8F3A15B687CFBE022BA +:10B8F0001AFF6E8D1559C68FEB1AFF051CF7A5DED2 +:10B90000D63F648275FD834BACEBD7F8FA5F650BCD +:10B91000C5F871B4FE5F8716F0F50F2EE1EBB7F3B3 +:10B920007EBBC6F774C1FF751CF7ADDED63F74A2AF +:10B9300075FD179559D76FE7E3BFCBCAC5F82E1A27 +:10B94000FFBD50195FFF456534BE660FF8908EB499 +:10B9500001719561189F0D0486482519E5A7746447 +:10B960001FC6A0FD3A3684E070471CA7BBCFE2801B +:10B97000DE5CDDF28E8581A3409E55089A2FAD9F37 +:10B98000A4A19CA572907B0BC5541734C9B4DFB039 +:10B9900075F6F070986F7B931CC2FC827597876573 +:10B9A000DAEFD8BC3C6CA7B0087EFFF0A1D11BCD6C +:10B9B000EB8A4E17D6A8C75A2D7CC4E7139ACC46FB +:10B9C00056C2FCA621118CEBCE1F0339CA407EBEA5 +:10B9D0000F7214D3E32A8C07DF8F829C659A996FCC +:10B9E00096F17D3CC4DE1C99827282FF1D5338BCE7 +:10B9F0008F2D91C208FFCFD62ED2503E2DAC890795 +:10BA0000A077CF2328F0D4B9CB1EDE28113CBD0887 +:10BA10009F1B891519FB33A0B51F80B6B0B6AFA523 +:10BA2000DD2D2CBC320DEACF5F933F4887F5DF3C1C +:10BA3000DB3E56C6FD83F907D8888FD9005B0E63BD +:10BA4000B31BD7AA032073E36CF5FD5653FB3901F2 +:10BA50006BFEE6226BBE5D0DAB36D4378A25B60190 +:10BA6000FABDB5D25A6E8C9328F5E17815E3FD2026 +:10BA700085CFF7564CC7E2679DF03A57E76D8DF9D1 +:10BA800004EF525984F6CBD66446F84FA67A019D4E +:10BA9000AF3B7ABE7355873F0FE633F74E99E019F7 +:10BAA0003DFFD6BDF17EDB18486B3F569104A3D70E +:10BAB000133DFF794BA3D7A3931E961F8AFECEE9B1 +:10BAC000249A9E824D93FA1E35D52B6FB8B2EF5152 +:10BAD000137D956E9965C91787E758EA17D6E65B17 +:10BAE000CA17D6145BCAE7AF5E64C9E787EEB4D461 +:10BAF0009FB77499A5FCD6CA7B2CE53717ADB5E482 +:10BB0000E7041EB1D4BF71F6064BB96DEF25D720FF +:10BB10001F55BF2533DC373E751D7B00F5C14F5DDA +:10BB20008A0FF171A22A8DF8E0549597D2F6A64CAF +:10BB30004780CBC1025471162E6B08AD9E88729956 +:10BB400091FC2C5EB633141A08DAADE425F8C9B5B9 +:10BB50001A8B00094BAC4F171D77CAA6F2D6F39487 +:10BB6000D702A367F62C975B637F0F6ECCBF08E507 +:10BB70004E6FF200FE06E03ED721F6F7E8F232897A +:10BB8000E599BF33B69CF8FC9C90B3651A9707659E +:10BB9000CFF69BCC3C988F8CA8FCAAF11A00A82861 +:10BBA00027513B4F467A002EB0D0CB500B7FB7EDDC +:10BBB00093695E152813C6A3C8C95B23A19C891C81 +:10BBC000187CDD689C87FF7E09F9AE2999F6F5B6E9 +:10BBD000AAE97D8F2A889F3C4A4F54CDA6F4585538 +:10BBE00080D2A3554594BE5F5549696BD5524A0F23 +:10BBF000578528FD53D56A4ADFABAAA1F49DAA5AFE +:10BC00004AFF5015A6B4BDCA4FA9C10F5DF237490E +:10BC1000E8ABC2AE809D87F267C55A5640DD16E29A +:10BC2000735F1AF2F959D76723501F3FFB8E9DA10E +:10BC3000BEDF1BBCA2E9AD773CFA495F290803FED1 +:10BC4000337B963BE3389E9C36369D813CBA67F841 +:10BC500013BEDB46515E4192810DC937CB1DA3DF78 +:10BC6000618CF0753E3C317FE7986B011FC71EFD6C +:10BC70006B36F67B4EEC7F710764DA875964930F5D +:10BC8000F165821BED6B9D3B84BC3F0FFC3EEA825D +:10BC90005FCB6006E9044927FA3BDB68670AC2B15B +:10BCA000393E0CC4CFCE1EDCE4417E5C9C66D38F53 +:10BCB000C68083919637A4EB2EF3FED364CD9FAD5F +:10BCC00091A637903CF6265C3F1AE94AD78F0E437F +:10BCD000FCA7516AF4B3384DD38F02BF9EDA3234D9 +:10BCE00081EFDF61BE0FD62712BD825D48F5FFD51B +:10BCF000F3E9AD1F633E8C35B20F1C280FA06CE832 +:10BD0000F9ED9D1E78573ED1F2105FCDEA67A82F5E +:10BD1000C4C1FF5F0EC17E15CA1BFD061BE490FD6A +:10BD2000DBF8BDDE321EB4F31A3637B6EB9D6E1566 +:10BD300076CCA02B90571A1ACB64273A75EBBE929B +:10BD400068C9079BFAE9967D06FF01FC0F82524104 +:10BD5000BA291354D4A1B8564B30BF23283F012F22 +:10BD60004189D72B77B46A012F91630BEA19B7E5A4 +:10BD70001874E7BDF18F20EF4FFE4665F762F9DFDB +:10BD8000605650AE1AC520F76C909F2F72B735964B +:10BD9000CE40B977D2C6F7F9052CCF83464F11AB09 +:10BDA000C9463DE723669B8EF4FF11FB9D27D364B4 +:10BDB0006FF86C1AAD73FE6AEB3E0BFA99255F586B +:10BDC0006BCD17B06B5390DE0BD6A92C2C215F5A8C +:10BDD000CBBD369DFA2D6495ABC8DE417B05C6BD53 +:10BDE0004D67CA00985FF9738F65E743FE3B36AE37 +:10BDF000A71BF67B711F3EFF92A4B0E687F20F1AD5 +:10BE0000337F7019C3F6E15528A7426EE6DBCC7A82 +:10BE1000E2EFEBCE3F7ABEC67ED2C38F20E6216F23 +:10BE200091FCE11876DA349B24F4AD10A537E0BA22 +:10BE30004D7A6BBE8083912F8FCADF1995FFA7E9DA +:10BE40002D8959E8ED8814C8B72573FA427D41520F +:10BE50003AB5C037E93FAD47FFE5FFD2FE0742FFE5 +:10BE6000D996FEEFFC97F63FACC7FC57C6EABFFC7D +:10BE7000B96D3B43206F4A9E79C8C3601F3AA9D46D +:10BE8000A4F800EF659B577A900E4E28210FD2F34D +:10BE9000C9B03C3D163DEC467A203FA2DF25A15DAE +:10BEA00085FF84FE4F3D75DF4CDC673EDBACEA640A +:10BEB0002F6DB147ECC0AF158DC533D818CA1FE13F +:10BEC000F9BBCFC8986FB2D267C9930FA5A0FF0D79 +:10BED0002845D81311D2972AEA3ECCC57D28C83A06 +:10BEE00089CFA2DBE1F8E7FA907CCCD7127A96C32F +:10BEF0003C49CF0F0AB8041BEF3B23A3EF93B57265 +:10BF00003F6854FD22A1FFD4DBDC49C7C07462DF67 +:10BF100061DF417969C08385B9FE53BDF5E13147E1 +:10BF2000603E6D75BFF1482638197C76B661FE2FEC +:10BF30009EF7F62E8FDB859DD7DD2E4CEDBC4D4256 +:10BF40006F6BE669991AF1A05E5CB641F585E07306 +:10BF5000D9B64D4F3C8A76EABB76DF70E8BF74DB1A +:10BF60004B7F9800F9D2ED6AD20CBE0C9794D28D1B +:10BF70009720FCBF746C371E4A7EF592E61DCDBF3C +:10BF8000FFB84F373E4AB7EFD3D8E89EF098D2B00B +:10BF90004F6B75C5C04BC3915CD4AFAAB77EAEA141 +:10BFA0003D7972AFC452D363C073C34BA427209CA6 +:10BFB000088F024F5D788BAA1F04BCA03C37F01499 +:10BFC0005DFE80903FD89F7714D1F3D3CFA35FF964 +:10BFD0003DBB0FD75FF4F4ED1E5CC771A592D3F59E +:10BFE000632B53FC306E911A4AD129E5DF8B1EFF7B +:10BFF00021D15BE11B3F4CE1F6A0BF9F8DF6A6501F +:10C000003F5CDFC2F537D0FA0A5880E8AEE8313934 +:10C010002F0CE9A70A9BBE3D065F64C89C2F8E6F5C +:10C0200004850BD6771CED12F4B3FE4E0E6F267FFF +:10C03000C82286FCFF43C33FCE1653FE5307C79367 +:10C0400043B609BE026DCF4CAF7577B7207E4E0D5B +:10C05000F2A7A21F2DC894908087F425F42BBF313E +:10C060002D95E38779956CD10EF48029F81DEBB7F7 +:10C07000A87EE7184B3BF6657AF7F84BC4F830EF2B +:10C0800038DCBF8FA7B0A28618EBBB5536F81EF67A +:10C0900071137D99F89BF37BDD3D9CBF0D7E0FCF27 +:10C0A0009A8EE59FBCC9F907DBE1FE08F38AA4522A +:10C0B000F9BEEB259207761689C5D775AAE06B6B9A +:10C0C000B94127306F454A30D10BF6DF87E04FFE8C +:10C0D000B38275D0CE242F83389EA7677F06DF16E4 +:10C0E0000AFE1F255BF99FADE77CDFBB7E15A27DB5 +:10C0F000AE4C0D3FF128F22BF067C88BFCAAE6E1AD +:10C10000BA4FD71FF8C34DC0A7A71B0C3EB5CACF67 +:10C11000683E2D7A76B384F419CDA7A78B401B898E +:10C12000C5A7F03D269F16B5FE3F959F06FCAE8F36 +:10C13000829F210F7B8363B43C3C63F3123CA3E5F5 +:10C1400021FCBDC9B27BD29F417706BD95FCB2FCF4 +:10C1500022F217187469D05D175D1A74D7C3FF6295 +:10C16000815F74F960A405A093BC5D2AD95565CDA3 +:10C17000FC3C0CDABD3C208BE0E4A76D8CD5BC3CCC +:10C1800020C99C0F47E51BA2EAFBA3F27951F503F6 +:10C1900051F94A4BFDB2A6031A23FC472CF5EC4B90 +:10C1A0001F651FC4B0878CFD26D878460B215D0C17 +:10C1B000ECD450DEA9CB410545FFE01E99ECC50E3D +:10C1C00080F12A18A7A33E3D1C02B9B1D2C9EDF0F7 +:10C1D0000EBDD3D307D295893CDF99ACAD42B96788 +:10C1E0007CEF74723F47475EA727D1E4A738D22C73 +:10C1F00093DC6E0DB3E9B1FC20B0A310DE5B596F88 +:10C20000E5DCFF394D760D5E8AF6688DEC431377D9 +:10C21000C1B21B3DE82AE9681E7ACD6CF8BEF05524 +:10C22000998E553AE23C63705E2CE457FA99EC899A +:10C23000132CF4B389E8CF6CE676C5823551FA0841 +:10C240005B43F454E05AA2A13C053BE07DAB3F9731 +:10C25000F34589E8AF68BDB5DC688F275A68DF957C +:10C26000D459CB03C23EDA65F04906CB2039838628 +:10C270000FDAE7422E4F93475D331BF0D1715066C2 +:10C28000789E79B659267C9CADE7E7972C944CFCB8 +:10C2900056C13A491E1A706A437ED27A97576D3B4F +:10C2A000FE9C7D17D2CDCE3F8EF939A46D3BDF1DAC +:10C2B000B11BF3CFBD3DF88FAC67FD297B9DE43703 +:10C2C000EED8EB267AEFD8F3DBC177617E979DFC41 +:10C2D000751D7B3F1F83F4D7B1DC5E84F2AE631023 +:10C2E000B787AAF77C3EA695F6D71584B7A3B2C642 +:10C2F000F5A3E6BF1E9692308555A1DEB0379EF8B5 +:10C3000029F8BC93FC0B1D7B3ECF0EB8FE75EBA944 +:10C3100010E7391D6E36FB599C5F22F78307778F34 +:10C32000DFB40CCFA31BF769F3A17CCA0B7F1F837B +:10C3300072B4E359AE0FB5ABAD8FE3794587FCE13D +:10C340003215E0DC8E4CD59FB1FB94119343A36270 +:10C35000C1E5EFE437B95078680AB74FFFFDE12136 +:10C36000F9B9BC73871D12AEFB8BC37F44B9B0D73C +:10C370004E7469ACF774C332D257CEB7EEE1CA7FC0 +:10C38000173AB8D0754B910B59F7D47F737CFF5A8D +:10C39000F6D2FCA2F9A0279DEFB983F2DBDC3E9A2E +:10C3A000EF05D2FB82FF69787F16F0EE39FFBAAB5A +:10C3B000FFCDD7DD3BDE5F9D2BF0AEE3797FF085CF +:10C3C000BFD3FCBEAE9CDBF4DF94EE0DBDFE159B2F +:10C3D000F7CD0CA83F9DD5B850B1B8B27CFFAB19D2 +:10C3E00050FACAC0038938DFC951E73746FAA6C2F6 +:10C3F000EDA6C9928DEC419628097B90DB51038410 +:10C40000FE30604901E9210306DECFF506C5BB0E0B +:10C41000CF1F5F193CDF47B1146CEC3B01CCEB97AD +:10C420008BBCD59EFCB9C4FC78343A60F0F70FA2FF +:10C430005E3B70A04C7A2FA4A4EFBEE899CEBF97C4 +:10C440006916BBE74AAFD50ECA4DB2DA4B53457FEA +:10C45000D3189FFF3497140E031C260FFA6912FAA3 +:10C4600047270F579904F95C165881F6C55497B5BC +:10C47000BF063CC319F7CDE168570D380E599787B1 +:10C48000701C24939FF4BC70C47913DC32C2182F43 +:10C49000C3141F87639F721FF99D85BD4D474D9043 +:10C4A000575CAB5A909F15B497391CC8CE36ECE553 +:10C4B000DEE0CD84FDAD88210DF82B0365BFD3DA16 +:10C4C0001FD9DF065EBE2E3E0C3C7E53BCBC1B85D6 +:10C4D0009781AE450AF2EB74B417FA62FD0C9E1F09 +:10C4E0001852E8DC4DD80B57781729A4F70CCC501C +:10C4F000105F858EA6ABF01CC4E193681E17B7D9F8 +:10C50000687F70644904F791B50AE5DFB0E9E3108C +:10C51000DF332F7BEEF49D0CFDE67E8DC73DE5F10C +:10C52000F38FBF7DF9E5448C1714782C84FFAF4658 +:10C530003FFF7A168903382D545828A10FFABD25DC +:10C54000F6BEC5EF6DCDE3DF7753BAFB395FFDDE95 +:10C55000E4CABF3A7D0EE4D8FB00F35D980EA3E178 +:10C5600015B35DFD9D660EAFE021161EC2E32AE401 +:10C570003CD339E11D82FE9FFBD3B39968D74EEAC5 +:10C580001895C0E5EB30B21782C25E38CBBC093ECD +:10C5900017CAD7A10974FE795076C78A2BDC2AEC1A +:10C5A000ED5F627C09A41D75AC4646FB8D75921F3C +:10C5B0003754E7609B63C4B7E4AB869F4AE00DFE47 +:10C5C000E46C3C8FE1E32F84A60966BCB5CD38A9A5 +:10C5D0008CE98907FC7BDF741EF54DE18BF63DC2CB +:10C5E00077ABB335372F86FCB85DC06FE6FE2FC83A +:10C5F000FF7969F3061BD2EFA57536CBF96AA92A34 +:10C60000ECB1B16C2CCE6BE67EA73B0BF17250F611 +:10C61000613C67B0F98C1688712E180D4FEC1FFD28 +:10C62000E95B559DF86BB7DA301FE1BAFB2307438E +:10C630003B7A9756531A6B9E03EC7C9E0B59C3EDC5 +:10C6400063D2FFFDE03BA9C315998CF6671D137EED +:10C650008F68FA6344C767B7B030EEAF68AFA25CCB +:10C66000385BCF687F0790DC8F7637F0FBF7CC7EA6 +:10C670009C8B9BB6FF12F5828A6649C723860AA562 +:10C6800055433F6DB02951C67D38C36BC4BBEAA387 +:10C69000AF37F1C5565521F81E98B0FB661CF7E37D +:10C6A000368DA19EE27FB1D383FBF8C7CD99C40735 +:10C6B000BDADEB5755ECAAA948372A9787D1F4307E +:10C6C000AA3ECE92BF4C0EF447FE9A696F5DE28B94 +:10C6D00081BFEF6B923817BC40F916FEFF4CBEBD10 +:10C6E00069C8B7809C67E2A3BE5A0FF9961A4BBE81 +:10C6F0002D96BCA908F7C57B86A6225E17BFAA2681 +:10C70000C7926FDBAAF839E733224EB9A311E4DBF5 +:10C71000B74DF2AD11E45B8C7890BF5FA87C0BFF46 +:10C72000D7F0DF36946F31D6AB6B56F936A6F908E1 +:10C73000C9B7318D364B3CAF5D3B9F7C9392AF4781 +:10C74000FDF8A0EA8B8F413FDB843EFE8C884BC412 +:10C750007150CEE56A3A8D7FA172EEE20B9573FFC0 +:10C76000457036E4DCE21D8CE29C7BD22197738B12 +:10C7700077819C93901EB99C5BBC8771BF5C947C55 +:10C780001BD943BE31AA5F11E1ED834DE90FDF02F2 +:10C79000FD8DF5AB3E07D41FDB2DEFC699E55DAEF1 +:10C7A000A610DC7AC8BB831726EF76087907726C6F +:10C7B00008CAD768FAF0355BE3C1778F3F5EFF2B7D +:10C7C000E497DFCA74DEF8868D9F0FBD36FE7816BB +:10C7D000D2D763623E8B84DC6BAF0A51FF535EE4B9 +:10C7E000EB2B77F138F18A46AE1F56D44B612FFC04 +:10C7F0003377C2171ACEBF788FC452213FCBCEEB0E +:10C80000B3278DF3323623C3440F0B724AC9CFBF0F +:10C8100040610EF4E397BA724FA2FE5B9AC3FDFE2D +:10C82000A5E27BF1ABADABD0FF5DFC8844E7A5464C +:10C830007CAB11E7DB236EA27919F977A3E32766B6 +:10C840008AB8A999BF94C21B62C47F946EB1E67F77 +:10C8500022F86F96DC4AF062AFCB31E3388C7A5D18 +:10C86000703A28E05427D37EDA0527809B37BD270E +:10C870009C00D3333252BAE152FC5B586F56EFEB57 +:10C8800035E016BD6EC37F5D2AFAE90D0E069C7B6E +:10C89000AC5FC01DEC029293D1F058A775F9B53387 +:10C8A000314E09E886E44CE8D70017182F6FD27094 +:10C8B000CB7D974705FD64D64C9A82E10CB330AE30 +:10C8C0001CCA0B6A17BDDC0FE031EE1DEF58DC4EC1 +:10C8D0002F9B600FE039EC566727C941830EDB358B +:10C8E000AE071C14F0DDDDBF7232D9F94D928E7A9D +:10C8F0004830E224B80601AE78FF28A870FC068113 +:10C900001E91FF0E3CF21987E31EC98BFE9D5C63EE +:10C91000BF42BC40FDCC668E97605822BC64B14ECD +:10C920003A7FA9A8957C11845FD306829F219FE15D +:10C93000CF65C693897E9558F44B954CFB65A9A8A5 +:10C9400037D35EF307A4E7994FAA6C03811BFEFB64 +:10C950002A7A3E4F1C50349EDA04BCB6213C5D0856 +:10C96000B74EAE7745BEA0FB504679500959E03925 +:10C97000E5D1735F09AF7106BC908E51BE35E7CB30 +:10C98000982F689258DFF49EEBC5F35033BF17EF32 +:10C9900039C2FB7F4CF2B118EBBE60BAEE859E8BBC +:10C9A000806EF1BCA437BA8E86533BD2F3B7BAE996 +:10C9B000F93567E7A14CA4E73D12F74334275ACE77 +:10C9C000353D761EF7B5D509740FEBEE7C55F56D48 +:10C9D000F4C690CB82EED17E30DF37BB041782F1F4 +:10C9E000A25B1C14EF47F318C2F553B37CDEE66478 +:10C9F000C9D767F5DEBFDB2EC58C2737F423233F6D +:10CA00001AC7C3F8F926186F64F778D1FB83E12FB2 +:10CA100038DFBAFADBBFD9BA8C71BE6E3C5490B520 +:10CA2000105E8DB8A82352E0472AEA73D3254BFC49 +:10CA300015CC5CC8AD6FDC7FAA96DC7BFF2C4DA7C4 +:10CA4000FB74B7EBC6779DE8334F67E27C6FE2DBA0 +:10CA5000B8EF7FECE7E7985936F6D644DC3F26ABD3 +:10CA60000CE9EAE3432AF9A13F9ECAE36EAFF9ED70 +:10CA700001055D3ED7F0983876CD3889ECAC37B0FB +:10CA8000EBF1A8873B987F04C12F13EFED65D4D558 +:10CA90004CF1025F8FDD12AEC6D437A533E935C441 +:10CAA000DB249921DE5AFC7DA7B8207FFB872C036D +:10CAB0005DA0A01F50FBB1075932D69BE04F263333 +:10CAC000667CE3276F5E07F3187F48F679A1DEAC3A +:10CAD000032E17037D7AE47A1B0B98E0358185AB32 +:10CAE000D1DF34FEA8FF3A9C7711E83B784FA4A829 +:10CAF0007943B507F3EB256A1F0C05723DB09E6DB7 +:10CB0000B56772BF857201EA6137C1F5BC5EB04E90 +:10CB1000F261887241F35A8A2F2AA893E842E1B65B +:10CB2000B0C41CBCDFB003FADDB61EDA67E1FE0557 +:10CB3000EDB1DFBA336F5E877207E649EDEBF9B905 +:10CB40007C01B4F322BFD42DA2FE8AD74B0CEFB3E5 +:10CB500014D5F37DA9E890EAC3F2C67D8FD07E3B61 +:10CB600003C6EB978EFB50642ADD0BCA9474BA2F70 +:10CB7000191A4CF8EB601C7F6CFA20F20B52BCAB1C +:10CB800097C0A098E363FE641F42F2B3C0B74CEBBA +:10CB90000BFDBC96939C6E23BA3A43E7ED4701DE4A +:10CBA0000180F71B225EE540CE075AAB695FFCC2ED +:10CBB0003E949F9B344DA2388E852C8FE238668E32 +:10CBC000E7FAE6EB973BC3E8E77B5DED1C88DF0FF8 +:10CBD0005C6EA7EFEDDBB81C6E1FD44AFEF6E3EBEC +:10CBE0005586F758AAD7CB242F8ED7AB743F567EE5 +:10CBF0008CC731146EE3FAC781F5BCDFE3A8B7E157 +:10CC0000B9079643BE70AB11E7C0E5B4617F16E883 +:10CC10003CFEC290BBE562DD3DF6A175CB3424D964 +:10CC200068795B2EE471098B90BD1C2D77CBF11CCC +:10CC3000DD837C191D27E6EAB663900E225F105D46 +:10CC4000571C5219DA31D2076DB91497B647A2733F +:10CC50008BF1CD921FE31A8ADEB18749FF0EE7CF31 +:10CC6000FB11EE2FEFDA19862C1F433C809CCAB1D2 +:10CC700077FEE9A7F0FDE41B0E8C0802BAC927B8BD +:10CC80001B71BE599B793C4FD61BEB52F03E2F9B3C +:10CC9000DA97E44061ADCC0226397152F25F771326 +:10CCA000DF1F74D4770C7C66693505B8BF7ECBC1B5 +:10CCB000F755EF66156364D8EF843D04F6811FF5E0 +:10CCC0009BE25D6B5334131D14EF599B22C3F75540 +:10CCD000221EA61AF7576857ACF1718AF74AFA066E +:10CCE000D338463F46BFDA2EDE6EE81E9EF6D67F6C +:10CCF00031CE8FD6F9A986F222BA9F1EE3F7D24F22 +:10CD0000CEEFCFAD93605E39AFCB14AC9EF3C18C48 +:10CD1000A1E6731D2335FCCAD96FDA98DF04BF9CE6 +:10CD20003FC531BF09DF8DE380EF017F5737496190 +:10CD3000A784F9235A7916E575E4F30AE17FAE98E2 +:10CD4000CACFEB1A33DE58817C3F234B227A60A195 +:10CD500080D63789F4352FFAFD0BB378FB42688F04 +:10CD6000FCD8F808E74F90135E942315EBD7E652F2 +:10CD7000FD3AC98BFD376EC8277DA4284766545EEF +:10CD80007784F4A3A2A62349C8C7C0B7EB501FA855 +:10CD90009868D7518E1BFC68F0F7EBE23E2B73E8E6 +:10CDA000A3F17EC6FF46E68BC1D7F2212ED783F5CD +:10CDB0009C1F83399C5F5FDFA6E20A2F84BF899F97 +:10CDC0008F6FE1FC2A3F76432EDE872FDCCCEFC34A +:10CDD0001F583F45437DFA7858A2FDA6277F73BDB3 +:10CDE000359ABFAB25BEEF7D5DFDD2E06F838FE14D +:10CDF000EF6A1CAF0CF814EF4F46F3F54CB5E10F9A +:10CE0000B7C37CAF791AD603F39DF2DD3B3DAD2667 +:10CE10003909F914CC17283C9ECB902BE50A8FFBDF +:10CE2000FBDAF38B1A3F6CB7FA477E674FE4F1EBFE +:10CE3000752AD1FDF9F8B3079F5D207F5E285F9DBD +:10CE40008F3F8DF1E53DD67E7E27E82DBABF7680F7 +:10CE50006B04E0FA4AFD268AF3FDE8A92333113F6B +:10CE6000A5BB81CE91BEEADD2C82724E09D37E55E0 +:10CE7000D228D33D01A644B2AF739BF998C76D95F4 +:10CE80003EE3267A2A79D61E9E01ED4B767E3086C9 +:10CE9000E2689677525C5AE829A12F875AC7201F6B +:10CEA00094283C7E2C5A2E041CDC0FD7B62B7E36E1 +:10CEB000AE4FDAC2DF8F2869B851B59BCE256E74AC +:10CEC000A8463D3AD70D011DE3FD5D9C9FF9DD02AB +:10CED000236EAC6D2B9713254D2AD981255BB6B7F0 +:10CEE00063FC70C93B76F27705B79CA1FB10539E9B +:10CEF000D946FE9460936C397FEB11B7B9458ED853 +:10CF000031EEB0B19CCE1D217F84F20DB1E397CFFD +:10CF1000175F58FACC9E9D210061E9AF9EF4A07C7A +:10CF200039D5B2D98370877EBF326EBA479C66C34B +:10CF30003D5F19A7790AFF018C738F43D835469C52 +:10CF4000EB96BEA447C2FCB2F3629C7374E9E5DBC6 +:10CF50003E7D1CEF11B43D7BFA719C6FD93F3E7E44 +:10CF60001CE3C1D85E27ED77C1A7DEA2386CA3DD34 +:10CF700026B1DFB56F7D92E2D7DBDFB5FBB0B7F648 +:10CF80003DC707633C60FBF62F52D06FB964CF34C6 +:10CF9000F2EB2ED9312595C5D82F8C14E9367C01BA +:10CFA000F1F3D1F83AD07880E2D63E027CA3FCEBD4 +:10CFB0008ABB6D28E771CC5E116F5B1FFB9E428FB1 +:10CFC000F8DAC6EBAEB91CE57E23D71FCF1B67FB93 +:10CFD00026E0F1DB1780BF7AC32F101B7F1FE13FD4 +:10CFE000004FFBA2F0F769E3C25F3C8A658D7D7B51 +:10CFF0008DB38D5C00DC8C7B100F38FC871CC988DE +:10D00000E75F525C33E26D8617F79F4F07E3FD91B0 +:10D01000136AE75CBA5FB8C7AE63BC68C99EB789DC +:10D020007FDA77BC417E6826EE23B4B3AE3F1E3F65 +:10D030002E8975D6B9797CAE803FC6EF7A3DF45D16 +:10D04000C4E9723A36E2777B8BDB959D5CCF36EE96 +:10D050006794D7FD51C4C376E34BCA413C1DF9CA5E +:10D060007868030EBA90C3DD71E8B1E3A3BBEE2B81 +:10D07000087C21FE701FEA8A3387FCC0B1E4377A4E +:10D080009BC59007ED1B78FC7ABB1AFB5EB011972D +:10D09000FE8F683E0D5F583CFAF9E6FF75E1D381DB +:10D0A000CA4F724F38B5FD2DB61C4F774ADFEC9E44 +:10D0B0006199147D6FCAEB1C87713B4734B483BB05 +:10D0C000EC6CB1DE36E1576F7B4AA678E5550D076B +:10D0D000488E47CB8B0A7C2F25C67C33C57C2B9A88 +:10D0E000F83ED1F6AC3BEC827EDAF6EF227AAEA8BF +:10D0F0003F42F1D22F6FF995D66A8A8BC07D226CA0 +:10D100009A7FDBD3FBC690DC16EFB2448F33498C99 +:10D11000136C8E3D4EB0FE8C659CD25083A6BBCE68 +:10D120003FDE29C57F23F677AA85EB83A71AE4E9BA +:10D13000E118E30F73AAD677A160BFA4F767DCFC00 +:10D14000BD19D91347FAE51277CE3B0949986A14FD +:10D15000AF55BD4CC477FD872F0DF15DEDBE8AE163 +:10D160007C57227C4D7E1E550F30D44BD5B4BC2C41 +:10D17000F42B44CB1B2DC9C6C226FC2F714F4FF593 +:10D18000D279476420E2F370C67115FBFD4B949F82 +:10D19000EA2F0A5B950AF3FB4B48F22D837ED9DF19 +:10D1A0003E1894E7EED97F971EF163D9E257AAB0F3 +:10D1B000771E46BB84BDE0A4F80679AF93DEF9087C +:10D1C0003EEEA4F51ED8F1F913A45FFFC2CEF8B964 +:10D1D0000F582F20AF0A75DEC7F11D9F3FFE57D4B1 +:10D1E0009FB1318C5FF838D447BBA13E9EEC9C8E3A +:10D1F0006713C6A05FA4F085BB66A23C2B8CE7F446 +:10D2000058F84C6AB81AFA3B96CCF3C7B60DA27719 +:10D21000254A9F7553DCE8811DCF55E0BED4FE4CF6 +:10D220003CC37DA9FD05A1E7FF52BC5355AB7ACDA8 +:10D23000F1E3C54CF19AEFF39462DE12AFC4C82F4C +:10D24000417C84FEAAA604BA0704FAAFA59F8FD436 +:10D25000CE3B7C44C7A1FEFCFE53A43FCA83E87AC0 +:10D2600046F9BDCE21E25E39B47375D70F6A9D05CC +:10D270003C5FD39FCB9316AAFFB053F88F4579CF6D +:10D280007E79FD8784FCEEEE87B7AF10EFD044D3F4 +:10D29000EF46D16FE996BF5F1CEB9D9518F3A7EFA2 +:10D2A0003F9458C8867ACA7627BD7F85EF28E07DEF +:10D2B000859D1A3FD72AF344E89D9BDD421E97C502 +:10D2C00045E8DD9DFE621E581FF3CCD1FA34BD9FA8 +:10D2D000F69C93615C59F90B6E3FE2BB7CE7E7C7B4 +:10D2E0007E9E857189F114175FFEC2FF223A28B72E +:10D2F00047E6223F746EB7B38DC8E7DB5F1D8CFC39 +:10D30000DAA64606F7F98AF3BAF206BBF5FEBF586D +:10D31000C7A9AADACBF0BEBB71AFB6A41739F357D1 +:10D3200027D7A35F71FA5F7212BF5BDF733A55357F +:10D330003B13DF5930EA973862CBC577515E7C13D7 +:10D3400039EEEA713FF55D9CCF47AC2505FD3E15F2 +:10D35000A077A33C2FD9923E10FD04FB9DC63B0451 +:10D36000DE04DC8FF6AB5EB2A73135EF3327AA7C43 +:10D3700099CA30F4DF8CCC54601D1D1BCE14F467A9 +:10D380001847EA9C1D4BEE9D76C6D33A4A1CF69888 +:10D39000F79DCF09BA7A0F8DFE643E1EF28731EEFB +:10D3A0007E354C72F88E382FD52B01BB08BF976E97 +:10D3B000999369797F45A9A17AC0A704CF62B64E37 +:10D3C000CB32C96F63BCE2A559994A267E57FE4FFE +:10D3D00017BDCADD7866A124D20B150163B6AE9FD6 +:10D3E000E57E88A2E639107E1ACBD3151949A586A9 +:10D3F000F83D8E3550EA02758BBF5356C9504E9E8C +:10D4000010E7F6E8EFC2B41B5E7792DC0F0D626C9A +:10D41000783ABE07E14DD04DF053F1101EE6635748 +:10D420002A1997173374B493A550807D09F4545D7D +:10D43000353D13E911FEFC180749A607CCCFA3BF61 +:10D44000FC05EA4140A7FC3DBFEFB270358018C330 +:10D4500081C9AF3A99F177E856BFC3CCF6C6A5713A +:10D460009278E7681FC93117EBFEEB843C8A55942C +:10D47000B7D509FFC8C1734497CE22A817C6BB58B9 +:10D48000241E52D728E59499FF3D599037D1A93EE3 +:10D49000D15A1ECD1720D7A2C66D20F841BF9F4498 +:10D4A000F5FB4954BF9F7C55BF069C828E8D3E7C08 +:10D4B000A76265559E801B1FCF21E006F01989EFFA +:10D4C000E8315B9C4F9C87135CE3C46CEC581FF005 +:10D4D0005A1E974E78B92F616F27C641B3A45A865A +:10D4E00076EF0A89EFD3F097E732B563BA83F8F0A5 +:10D4F0001E314EB980F30AC33FD5A3BE93F4AF1ECD +:10D50000F59DBDD58F8B5DDFDDDB7CE263CF27B181 +:10D5100097FE6BE263F6FF75E552C50B6FBF86E7BA +:10D52000B65DF24907D05BF5CCF238D433138FFDEA +:10D53000A395BE703DD331D08AEF38A46FA0B7B8A1 +:10D5400061D6EFD174D21B7DE58B7540DED50FE03F +:10D550007093187F6A1D3FF7BE6509F7D38179E89C +:10D56000C7FA378BFA37390AC9DF70C4C6DFBFBACA +:10D57000A596EB91B7FC58A6F3E91EEF51E13F8069 +:10D58000DF6E5D2A8523E9B1DED76275783F6E9E36 +:10D59000183FFABDAA00F3E6AE9663BD57C5E9D2BF +:10D5A000B85717FD4EC5029627DE21B37E3FEBD458 +:10D5B000BBE467CDA8EE7D2CB416E81EF54FA07B2A +:10D5C0003C97C7EB621417E2D1785C48CB203A4F06 +:10D5D00033E4DFD991DE04DCAF997F30FFAEF3EFA7 +:10D5E0008BAFF4A69AEF1D2AE7E22CEFF554ABBE01 +:10D5F00034946FEA39D05FC154D6CE0D615E533991 +:10D60000E8ADC4FC18BE49722A4D09A35C54F43C31 +:10D6100056887AAF78EFC3A8AF255DD5A567BE0E53 +:10D62000FF6F8E4B26BE5CBCD64BF7B63F8BCFDB75 +:10D6300089F4247B727C01574F7A08EDE0EBAEC68B +:10D6400075A7F75C4FB5E6F391BE7D158080FC6F42 +:10D650003E07CE4FB67BDFF6E2FC7EA332F4BBF48E +:10D66000848FEF4418CACF8607507C889C306304AF +:10D670008EBF46BC6FBABA6A24A52BAA984879BC5B +:10D68000DC8A2AAF487344EA17E974AA776F551AFF +:10D69000E55755F92835E0EBF0D5D0FB938E617C4A +:10D6A0007C872EF0976413F00B90FEE548ABA473D3 +:10D6B00045A75E19C177DFD840D87770597A0DC178 +:10D6C00057D319F935A13EE5ED988754AD9D41F842 +:10D6D00052F44A5608E56FC5078E225C9DDE4B2D3D +:10D6E000EF5ADAD3C646BD7F1A056F83DEB671B82E +:10D6F000DF2F717A8B86FBFD6A8B17E322EEBFB2B8 +:10D70000EB5D29823B98431CEEBFE6E7B43DE1DECA +:10D71000327BBE09EEEEECE904F7FB049CEF1670D9 +:10D72000AD1678A816F0AC46B8537EA4C8FB443AB0 +:10D730009DD27BC4FBB72B111F90CA087780877DD1 +:10D740005488C9301EBA79F1CFEE1274ABDBC81F12 +:10D750002ABBF2FC08777B1287BBC3057820BA0688 +:10D76000B87BB13C44F0545D1CCE509FE341E415BE +:10D77000847B267EE7F800B8F78D1F87F27082055C +:10D78000CE5AD2E40B83FB237C7F4B127C1E0DBF51 +:10D79000248DBFAF6BF0776FFA71B588B7AE16EF17 +:10D7A00027221C51AF7908E0C3340E4FFE7DA4C878 +:10D7B000FB284D16F67F35E001CB1F16FA10C21973 +:10D7C000D31FC573FB3CC956B94F4538F5E1EFF29D +:10D7D000B0A4101B98CD78682FFEA5859817F3C6C6 +:10D7E000F9AFD74A3FB2AE44BD03E97D18E96DDD1C +:10D7F000ABAA0DCF3FE4A55759EE67CBB3FD895EC9 +:10D80000827F4042BDE63EC1876B915E687EDC1E32 +:10D810005E29E8E06EF1FEEE3D827EEE17FCFCA094 +:10D8200041373E7E3F64CD741EC798946113EF204C +:10D830004698394E30D1D7C0349817D9365E4AE968 +:10D840009D4BF68E9DF8367E14F3237D25BE7367BF +:10D8500098BF439BD70FF5A144E3DDD989DEC439D6 +:10D8600074313DA288F720656E4FB6C47CDFB5DA0F +:10D87000B7DF817E99DEE613EFF3A7AF84F1E26BA9 +:10D88000DD6447F50DE4CD590879572DD8550CCBFB +:10D89000B97C70C1BC0B4DF411DF8B5F47755D59CE +:10D8A00080F44AF638A43FA91DEA44F802ACBDE86A +:10D8B000BF7A48CDEB87FBC14389B1FD70B3E2B9B4 +:10D8C000BFC49375A9C59FB04EF5533B7DA255DEED +:10D8D000AC13FB439FA956FE30F683CB447F9FC514 +:10D8E000077E140F7496726E2AC9CFA46B63EF0F74 +:10D8F000D5AA16C2F739AA4773BE0EE56B5C6FEE68 +:10D900002177189D839C0D8CD888FE2F83BE96337B +:10D910002EE7428CEB93C6BA7E86F43E02F7019D59 +:10D92000E81EF701CCCBC334A29B945B6CE47F5818 +:10D9300025F8EC5EC15F6B045F3D807C3502DF81C2 +:10D94000F651FA13C14FEB90FF20DD129FCEF57810 +:10D95000F1BE9761C72C778CA5F71CAB5D36DA0F4B +:10D960009477ED6117DA05FBC6EBE8F791DD597A9C +:10D97000C08DE5590E3FC0434ACCD2915E3E732F15 +:10D98000B8E8ABE25B01FDF4AEB0A2727FA49E9456 +:10D99000C7DE1F45A753F49E80AA5FCBD03FFD7022 +:10D9A00052A513E1FC703C8FD3AACDCF26B8033E1D +:10D9B000B6C59BE2A552675FD5F51E1F76FF702F97 +:10D9C000EF12EC12F2820D0CB16126F9502BDE7BC6 +:10D9D00064DE101B699213CB87E732F4EBF5940FEA +:10D9E000BDC8CBCD5C5EAE9062CB4B437F37E46568 +:10D9F000B45C31D295174DB7DCA7545D3E46F26654 +:10DA0000646CFFC1EFE3EDFC1D6AE6F3E5A7F72CBC +:10DA10000778FDDE0C2FD4830C7FC5F762AC275A44 +:10DA20003E9EB8CAD85703F43ED002CDFBF0F8AF03 +:10DA3000DC57ADFB41E1B9D5A40F149CCBA1B4A830 +:10DA4000763AF111C3D318939D7C7CFD0F3D88DF9E +:10DA5000E3B5E27C7CBD1AC6B8A47D1BEF7A600EEC +:10DA6000C075C1E3329D8FE33D0DD914DFC2B2BC56 +:10DA7000A4A71BEF231E0FDFEE31C73114FCD4E93E +:10DA800047FDBF377A2C581FDB7F538DFF44BB8384 +:10DA9000F946A25D01FA5D6704F5BF9F38E9DD181C +:10DAA000231FDA18EF33C78F18E95BF1D3CE21DCDF +:10DAB000DF8AF73317D29DAB0F9DD7F4CE177CDCEE +:10DAC00063E833C773D247459C35C07D96C57FCA8E +:10DAD000CF498F097F1873F4521E27CABDBD947BAE +:10DAE000783C13D36397FFD37EA4513DECB421B8A7 +:10DAF000FEF2DAD3ABDEA52FD6F3806211C7BD608C +:10DB0000637C78790CBE5920EE072F10E75D067D07 +:10DB1000157FDFD0B3395D46D3ADF4D42544A71FBC +:10DB20001F54C95F5B01F4877A98F4D4787A8F69BF +:10DB3000D913973D780BC0F993433295979D731095 +:10DB40005DB6FF878FE2FC3B7FABD2EF267C727025 +:10DB50001AC5EBB78BF79EBBF8CEC5EDDA1B5C5C44 +:10DB6000AE149CBB97E8BB8BAEC2F335E4DB82738B +:10DB70000F905E5680EFBD4EC0758F78799222E887 +:10DB80007702B61F92BB1CEA15B6723E61134315AD +:10DB9000E48FDE10EFBB37063FDFE0F25AE2450BC1 +:10DBA0005BD750FF0CF4C324535CC802F1FB07851C +:10DBB00078B884E57A88A521DF08F9D64DFFD677B5 +:10DBC000B0DB9DD6751AE9C2AE754EB0D861DDEBFB +:10DBD000FC2EE773A16F14B6E6F07975ADE7E7E3C5 +:10DBE00063ADA77B1D13A97D7B62ECF1EF17E31FEB +:10DBF000AB2AC29B5BAC44BCB75B10BE5DC3F7D520 +:10DC00000AD627F6914CEB2AAC2DB5C42B15D4E6D9 +:10DC1000D3FB7A85EBF3B5DB4CFB53175E42FE97E3 +:10DC2000270DEBC6CBFD6B2E23BCA8AEBC3B917E73 +:10DC30008F3D557CC77B5EEC97E3E984161A534908 +:10DC4000F2EA764FACFB4DF747E3A956E009EC80CA +:10DC50002C139E0CFC44B73FB6B9FC8EF7F01CE2C7 +:10DC600011FE9A50EFF22B0A7FE9B1E1F7A4A0D799 +:10DC700063A00F042E087EDFB2C4CBF50A3F816F8C +:10DC8000033EC677D0E7C208B727913793B13F4E1E +:10DC90000FE7835BF7F8821E26C55ECF6B5DEB59FD +:10DCA000CA42A0C79CD4B83ED1FB7AEE6221C70518 +:10DCB000ACA78B4FF32D7CFADA9A5B389F0AFC9F56 +:10DCC000DC7F0FD1F5B170BC0FE3547A5BCF6B48AA +:10DCD00007E362D0C1B0101B95FD7F8F0E4E68FE2A +:10DCE000118FE03E02FB15EED3C54FDE3FC63CBFB1 +:10DCF000B7E227FD9EF6A59A0B3BA70E4DF61DF445 +:10DD0000D27E27FBAA6149435D813F63FB12CFA30B +:10DD10009FA19F6E45E2CFC6C4D28B5756052EC732 +:10DD2000F38BEAAAA2CBD18FAA0A3D97A19E9BCEE4 +:10DD30007F1723D67B7DCCCDF1BBB2AA92CE3F9884 +:10DD400023C4F494EE7700D8894CF2472B2EAB7E97 +:10DD5000A6A9011DFDDF9A78A7405502ABD3B3D029 +:10DD60005F94941132C1EF1F2E7EEEB2266DBF8EEE +:10DD7000E71A76E81FFD608E81CA598BFFEC456576 +:10DD8000415FC093F11C731C6BF04B12F913CF462B +:10DD9000F913CF5AE69104F3FE0A3B5B7178E81C55 +:10DDA0005261C28F2CE0015F681FBB5BE7EB5C1E1A +:10DDB000EF217D60D54536B2EBD609FFF4CFD02FE9 +:10DDC0004D7051E8BC01C3E0B0BE96C0D7E1C4734A +:10DDD0000C19EDAD08E5DDF862974C4F1F4A984FDE +:10DDE000645E09F37D596415DA0F1D935AEF203FE5 +:10DDF000A03390E606BC7ED6AFE5B084E712798109 +:10DE00008B11CEB57228C30BF57F21776660BDC13B +:10DE100050F44E1F9E5E84F71202A6F3CE21B48EFC +:10DE2000EEBCDC337FD15225EAFCEF6F179BCB5F52 +:10DE300071FA2FC679543BF9FB60491F4874BE57ED +:10DE4000DD75EE9447FBF26437C723D105D2D54187 +:10DE5000AE379D55BC097DC89F3D32F345CB3C7C18 +:10DE600096BC22ECD13AA0533CA732E86398E2B7C3 +:10DE7000211D0DAF81EF663CC6D077FBB8E879F085 +:10DE800098FAB9313F1897E8553E97CBF7E3287ACF +:10DE9000D82DF1F9878AEDDC6E642119F13AC7209B +:10DEA0003C6505CF2732E38FECB5778D7327B682BB +:10DEB000E7759E0BDEC6CFB9A3E733A7F9EE163C94 +:10DEC000EF99D3DC6F3E9E7BCE29BAF8434C77ABFB +:10DED0009DFBE3515EFC50227DF6A6B75E54E32124 +:10DEE000DDF1E6467A9F60AE9BEFBF7359A78AF8D3 +:10DEF0000F305DE3E756615ADF6DCC27F20D2AFA49 +:10DF00001D6E89846FB81A72B7BE18BE1AD5BDB916 +:10DF1000073B5F42B4051AF45C3A1B32DA35F95E0E +:10DF2000E679DEAE0B0E4EF1FB478A83D6D5BD6E89 +:10DF300007C1C15827D4247C74C149BCCF66C0A591 +:10DF40006BDDF1375F85FEF8DEE4DC1CC7E80F7996 +:10DF50009C3C9F57349C3EC12290930BDDFE1FB921 +:10DF6000A1FC7AB7FF2E4CCB1C9D839521C437555D +:10DF700098AF900317A5001C3E1A14B83819E1D1C8 +:10DF8000D2F782F4FEC34E2E0F0EA71B7A6DAB1B89 +:10DF9000E99BBDC8F55AE3F73256ED387EFF8D0098 +:10DFA0009F8F5EE5EFCD95CBDE6BEE22FFB2CC62AC +:10DFB000D921467A58F80D1E76DBC47BD17C9DF3BF +:10DFC000140EEF798DF174CF6EDE52D9F2BEFDBC26 +:10DFD000A53C7E95292D63AEB7D8092B045DF7ECDF +:10DFE00007FD1AD1FDCC5F3A99DE2DD9A9E993C876 +:10DFF000CFF138A7B3F953FD32C6FD4F582D911F0D +:10E0000069FC516F532BE4E787137DC8AEF3EF5CD7 +:10E010009C89EF9754B4703F67AABC28E33F207DEA +:10E02000683FDFEF31BF08E1E4F27B5DA6F39A368B +:10E03000B53243477ABED5E54779907FBDFF5DC4D1 +:10E04000A7E1E730F6DDE7400FC038CEFC5BBC3916 +:10E05000481FF90D4E3FA50EA6C4815CCB5798030F +:10E06000D3548D294E4CE39803D3ECE5427FAA9D0F +:10E0700045FA8327274FC3F7C4F39B9FFC14DB1794 +:10E080002A917D92899EF29B5FFD82EEC3F9F3286F +:10E090004EF75B5B348BDD39BAC19AFF7693359FBF +:10E0A00011B1E6330F5AF303706D267D73FF1E1E08 +:10E0B0009F527A9ADFEF7D1E60A0223CB6D9493E7E +:10E0C0004E296DCEC67887D34FBB6D58BEFBEFDCB3 +:10E0D000EEEEDCEAA47725F7BD17C7E292F01D6AE1 +:10E0E000E7462C3F1DD7908DFE45A84F714BB0BB26 +:10E0F0008E40BB71E7A506BD8629BE69E73FF8FDE6 +:10E1000094CEADF630C6519CDEF5E4D3489FA7B758 +:10E110000E207DEC792964C37E43F770FC4F88F3B1 +:10E1200058E454E916AB3D7E42E8011D27B579E875 +:10E1300017BAB8D6BAEE4BC2D67CA7A87F1B337DE0 +:10E140004FC7F810EFAA34DC6737C57EBFFD73C137 +:10E15000174F3DA519742B8BF71E9937A5FBBEE20F +:10E16000EEEE73DB2503808E4A111643BABF974645 +:10E170008DDB850FD17F92382FEBFCAD4CF03955FC +:10E18000556489EFE8D2FBAA7C69534DFB5141ED00 +:10E19000BE947CD257F7A5DC66DA67CAB61E48B9CA +:10E1A00019FA6BDBA2D0EFEB95CD79E2810949F842 +:10E1B0005D6EC0F96239FAE7DA1A5EF2603DD08B23 +:10E1C000C79AE3BD0A6BC7A54D35F1E9D7A54B83C7 +:10E1D0009FCA740E9FE7725A72F11E46692DFF1D89 +:10E1E000BED2861BAEBB1AE1BE9EDF4FCF56589EF5 +:10E1F0000CFC53B6FD86EF8F86EFC1C7C6F9703EA3 +:10E20000D9F8242DDEBBAD3F43F776EEB571FF4460 +:10E21000345C467B387EEFFD81AB08E512F4F7A253 +:10E220006D2CB53F68037DE4C4E4D06B374395D3D0 +:10E23000ACE10F57535C96959E803E25D4B73A3794 +:10E240004BBE8DF47579F6B5A85AFB97513C3A94BC +:10E25000C7B4378AC3D67EA2F17CA547327EF76861 +:10E26000A4995EA2EBF59D11A2DFB72A5B0A72CDDD +:10E27000A4EF971DADA178D8E871C819688A3BC191 +:10E28000FDD14B7CEC147A02931CD9225E7C28CF02 +:10E29000D3BBA748974010A597B2A95E84EBB56C95 +:10E2A0003AA6CF4B91076499CB03F2336D8B277954 +:10E2B000D0A6B73EF173A4A3FAD1741ED65FDCEFEB +:10E2C0006EF346E8BD58E37771DA749E2F69765293 +:10E2D0003CD5E98F349297CB308E13EB3FEDB4D918 +:10E2E000405F3BBDBDEF648C0B6E6BE0EF8A9F6AB5 +:10E2F000E83B59FB8AFD379AEF8D7DF108FE13DF6D +:10E300004FF5F88B3DB8DFACE071D3A97D2B332AF4 +:10E3100063E0C96897A45566A0BDD279ABCBB7912D +:10E32000EB53E90AF9DDD3C8AF922FFC49F7E9793D +:10E330007778A0BE1BEAFAE1FF3E07E58DE877FC9F +:10E3400040F6DDA10FED3E1F5F9015A0FBE3F40347 +:10E350003630FE7C854514A0B7F9B8AF8CA13CC916 +:10E36000CFF9EB258A235CB0C6BA1E7CE7DABC1F66 +:10E3700016E12F290EC5B8B0064A8BD65BCB8B7140 +:10E38000FFF050BC17C5CB94D459CB198B901FAD5F +:10E39000ACFE4B7B2CB87DCA8CF5F96B3C16B9A34F +:10E3A00092DCF950CEA3F595A23700D29BC4FE1C97 +:10E3B000BC33276D01A41D4B27A42DC8C47BEE7C64 +:10E3C0001F23D38EF898BF8F573A954506F1777182 +:10E3D00018EE8FA5CD526434E61D2CE419CBBFE3B3 +:10E3E000FB20B86EF33D3163DDB85EF377F626C7E8 +:10E3F000AB71CF10D76B2E2F137028ABB75BFC3AE5 +:10E4000013EAA590FBDB787FA995DA55347E69B7CE +:10E41000F42BF65FD8B79913F035A168838C8B790C +:10E42000A84B8E872F89750FE5B080DF433714F432 +:10E43000437E7D10F5CFFE02C039249F849F804526 +:10E440001C305E5C66579ECAB397F3FC3E4FE08A71 +:10E45000DA8160AFA9013A879A2FE7BD8CF71B4795 +:10E4600026065E42BCCCB7F9072BC4B7FE11E417F1 +:10E470005DCAE1F0F0D8CA4B2A63D9C502BF3F9309 +:10E480001AE85C3EB48BEFA3EEAC4ED5ECF7FE8BF6 +:10E49000904709FB5BE95E4FE70E89EE133F221DB3 +:10E4A000A1FBB68F5CE96568C7A7019E50EE3E22CE +:10E4B000B115F85E5E56E3AC452F219EB3E27C7841 +:10E4C000DE5FDE38492E77D1FAB9BE155FB901CFCC +:10E4D0008352E78D1C8B740EEB9E772D7CFFD0E36F +:10E4E000A5F1FAB938DED39687D2178FC2F1F316A9 +:10E4F000BD847C383A8EEEA1A702ACDC7D285D8D10 +:10E500007A541ACBD887FA60DA0CEF58F4B93FE4A2 +:10E51000E1E324DBE479B350CF1BCBF37D7E2CF910 +:10E52000371211AEA57152ED6C3ACE17BFA35EE85B +:10E53000403F82CB84EF299519387EEA509E2669A8 +:10E54000118A0F3C64E0BD99C7E92DD119C9E925AD +:10E550005F4C4A453BEE501B18D420BF0E0D34ECE7 +:10E56000CC888BF4F06123797D61F72DC9E0F75FEA +:10E5700092061BFA0FAFD7A1FA133251AEBEC1F506 +:10E58000F14F5C7EF2575FA6C58EBF4F48E0780A18 +:10E590009E8B636193FF3838FB33D21383E73C2CA7 +:10E5A0006CDA27F0BD4D731C7759D17EFA1D847249 +:10E5B000D642F701CA1BAC71E797C5C51ED7A0F3B9 +:10E5C000E0391B0BF525321E88F6D721A973D5C279 +:10E5D00024BA174BE73BC1731A0B99C60F9EEB6326 +:10E5E000CD77CD3385FAE9AEC7ACF59A3EA77A2C44 +:10E5F000A7D583E3B4EBADB48F04CF29D4CED86FC5 +:10E600003AC2B6900AFCDCEEE5E51DE23CCFA86F0D +:10E61000F4D73E5B13F7DEF8BBE86D552078002E8B +:10E620008F369F217F7459F33E828B410FDDF08935 +:10E630006721137C52AA5B2236E0ED690F6EB87B2E +:10E6400014D890C9FB051F8736DDED9F08E5F8BBA0 +:10E650000F26BE8ECFEAE27312330FD9642E174213 +:10E6600075774F9D68CA8BFA5DED439BAF980A346E +:10E6700095358AB7BFE6C1275E594E4E8B1A11DF1A +:10E68000DF3938CF6DCA3BA2F22EC88F36E5F5A828 +:10E69000F2A4A8F2B4A8FC405EBFCD1D192CFB402B +:10E6A000DE3FF8D415F8FB9E6DFD2273F1058F3522 +:10E6B000F2B62BF0F77CCBB3F8EFD356344B3EC910 +:10E6C000243F2BBACEF35BB5F9A3100E2D2FA31C5C +:10E6D000286B9274D4EB5D0DDB2394C7765E53BB3D +:10E6E000066E3F96351CA176BDF63FD2467C7CEF88 +:10E6F000C8F7A9DEF9CE9FD80CEBEF5BF5761E7557 +:10E70000440A2C4E48EE7E7FBD6DFBDBDDBF2F0A39 +:10E71000DFDBFBF90F901C8DBA071EC4F9B8BAF9FC +:10E72000C480E3BD23CFD27BB47F1CDDFC16AA03DB +:10E73000F14BCE2C53A0DD9FCB8F8F437D0BDFB4ED +:10E74000C57DE36752F812DC8F1E65814B70DC5B80 +:10E75000CB87EFC39F4C38ACB63E86EF956F78F011 +:10E76000E52B1498DF6177EB20FC09B74D096FF0BA +:10E770007C722B7F5145FF1DE1E7F0A0D64136C8E2 +:10E780003F99C0A6537E78EB63987F3DE104AF3F8D +:10E79000BA7590ACA30972F28AA990DFACC7E6F70C +:10E7A000DA04AE371BF39B36DCFF53840B2BE3FB01 +:10E7B0000D5E3376803C9D5B726ADB6680C7DC1F32 +:10E7C000C5939CDBDC76DD55790487501EC611A607 +:10E7D0000A78D37E48725D217DA21FEE817DBAF159 +:10E7E000E91EDCE2A5FDE2D2CAEDA837A4CE1D45A4 +:10E7F000FB45A1C72FE9C9DD69381952A82FE93AAD +:10E8000097EBB28DE22352EF72931EF5A0F83D0311 +:10E81000E03BA20F97C0CB36B19E6D09DCBFF680FE +:10E82000671AF5F39EE47FC42163CA424EF2A7C57E +:10E8300091BE72F306902B20D7D78979AF5B7B0905 +:10E84000F9296E463FF128FCEEEFD76754B7FEBFBB +:10E850002E03F2AE6EBB6EDD2C7F3FF3B9F6BA0D20 +:10E86000BCDC905BEBD2797B63BF4AADE6E3A43EB0 +:10E8700078C9465C47BCC2287E7BE1EC111B97D16E +:10E88000FE7F2DAD9FF9FDFDD00E3F5A3CC4867A28 +:10E89000A9819FC2E1FE5712603D3789DFEF35F055 +:10E8A000648C4FB7E2517F90417F403B353140EB64 +:10E8B000077D620C0F6EE0FA04D21633C19729ADC2 +:10E8C000E3F0FBFF2038B5FD2BE0F44F9F7747C9FD +:10E8D0002190370CFB2F5F7ADC72FFED3F01D123D3 +:10E8E0002A700080000000001F8B0800000000005C +:10E8F00000FFC57D0B7854D5B5F03E73CEBC929920 +:10E9000064264C9249C8E38440081071124344F0D5 +:10E9100031848851693B50D4D87A71203C022699C1 +:10E92000A8D5624BFF0C12790918342250C181021C +:10E93000C55BF506458C1A70448A7AAFF68EADB782 +:10E94000576C7FFF08888F4A32A2F5D297FDD75ABD +:10E950007BEF64CE24A9B4B6BDF93EDCEEB3CFD9CB +:10E960007BEDB5D76BAFB5F61EA6F54C0A5CC0D8EB +:10E9700066256ACEAE642C7C48F1ED61F007CF6766 +:10E980003B19FBF7B4A0D595C9D89FF1EF0AC6E6AD +:10E990007EBF29275806ED8D2318CB612CF5BBCF00 +:10E9A000D4DE00D5B94B3F7A7C0F7C3FF77BA98C36 +:10E9B000E903EF438F8CC1F7EFBC6D5BCF2E84D2A0 +:10E9C000D2193579A0BC86F956C07BEF98584327F9 +:10E9D000F4F70EBE7A096355DFBBE5353691B1DB3E +:10E9E0005D2A6393185BABF873988A250BDBE0BB59 +:10E9F000F02C4B644F11637D1153D80CFD75B82377 +:10EA00005B17C1B81DD795F9C2D05F1F637E86EF33 +:10EA10002D4BA5F73ADC3D4CC3F64B741740C20EA4 +:10EA20007EA1FA19D4E3375A22BB14785ECEC2769F +:10EA30006C5F323E1286FAF3300E7D7F634A640FBC +:10EA4000B6CF828FA0DE71A3371286FEEC2C624710 +:10EA5000783A76FA73321C8CE5AAAC05E1EF28828D +:10EA60003A94592BD9CD0107E2CF3F719673000F2D +:10EA70005F7799683EA9953D4FFF37F4C7D6DB7D98 +:10EA800063A0B0E1AB586FCF2678993B5885F86604 +:10EA90001AFC03B8EA1FC889ACC3E7CC5785EBB1B1 +:10EAA000DAE99F47F0FF205547F81FB6B335B60A9D +:10EAB0002815D666CB00FC0B7858FB43000C633757 +:10EAC000E3008097FFD770D6A9C3F32B5D0AAD078B +:10EAD000FCF96D558CCD67BC7DFEF2D477958958D5 +:10EAE000AA516B1A3C5B73A5BFC746EFB13F8FE2DB +:10EAF000A50DFA0B32F1B725EE44BA09E27769D8D1 +:10EB0000FFEF9DBA03EBF0FD445C76F8BE74E0FBCA +:10EB10003A17A3F9CF5539FCAC355547FC4AFCC828 +:10EB2000B24EC2D7FE903F713C394E72BFF7BAFC6D +:10EB30003722BE00EFD1740FE245A5754D86D7632D +:10EB4000896FB043FBDC56D57D37E033B8CC49F351 +:10EB500095F0DE9C1DBF8C150FEEFF746A739586D1 +:10EB6000F35FC6E99D2DB702E212F16219A8035DB9 +:10EB70002C64F163266588E75AF445847F5147C2C7 +:10EB8000F7F4DF2FAC89EF497E61BA9204BFA02B66 +:10EB90005DD170DD820A5F378B253E375036186EA7 +:10EBA00089CFD582EE245D24E37B35E27BD2607C85 +:10EBB0007B2C3DF9D86F709995F094DC3F6311FA86 +:10EBC000EE213BF00FD0DD1645217ADD72576A64E5 +:10EBD00025F2A73DBE17F1193A7C15AD77EF9214D7 +:10EBE0009DC12BDB2C30419433879D9C8F4B7A4AFF +:10EBF000909F7A61CE7E589FDED7D59D614502C138 +:10EC000058F3EBEA2EA4FFDE67AFE6FDAC48D5195A +:10EC1000D4438861183714FE432B03BC9E34C52CA3 +:10EC2000345E17E057C209FF7AE15F43C580BCE854 +:10EC3000C3061CBF8BCB0798E1121AE7DB296C1DBA +:10EC40008CDB6C52FC26686F5E3A3EB292C3614325 +:10EC50003E6A1420359B589B5231C0F7CDA6132530 +:10EC6000B795F1360DDEBB85F17581F78E2A005F11 +:10EC7000A36D7D4C45BA45FA87F6A5D85E3480FF72 +:10EC8000E6F5BFF913C2DF7CC048178D8F19E7B1D5 +:10EC900034919E8A06E824B592E389D5B0C81880DD +:10ECA000D729EAA9B5B1888A785A56CD4E02E966C5 +:10ECB0001EE99981F4E3ACEC64F3A10C7DC0FC1176 +:10ECC000807B4AF7CE9746C2FBEEDA583E4E37B409 +:10ECD000ECB68B4E5D34B0BE12CE4BBA37A9CC41E8 +:10ECE000E3D177008A7FBF83DE1B37FB82C4F26EDD +:10ECF000FA2ED3A412BDF6E023E41BCD9FA3C038A7 +:10ED00009B978C32E17AA6827C43B9BCB07DECAE95 +:10ED10001584677F09CAB707D380CE099FBE2A949E +:10ED20002FA5EEEA5FBBA0BFA7DCD5FF8D258E1314 +:10ED300070E2F44790BE48A6E764BD23DFCB2E6E99 +:10ED4000296F710CFF1EF017E12DBE359DCB0F4DC5 +:10ED5000A1FAA2FF30EF5C47F0694437B76D2F226C +:10ED600079DCC0DA89DE1A59C482F4BBC8C6C2692C +:10ED700040178BE0B57428176FB1323D61FD9644A2 +:10ED80008CF546210F6E6131FAFE967D49ED352CEA +:10ED9000EA84F6261B8BA662D9696C6F667141EF17 +:10EDA0007FB6263E671D7CBE378B7577D744D4204F +:10EDB000CC7BAB1D745706BED04EEB3365F94E5A73 +:10EDC000CFF40A7FD13DA84F5E35FB7601DDBE272B +:10EDD000D64BE2E75E57F5BB88F714D544F38FDFD7 +:10EDE0006325FC9C02BD8DEB7F9F9BDD3C1BCADE37 +:10EDF00056DD3B7A34A2C95530DB3918CFEB9EB3D0 +:10EE00003720DDB8DD26C2B77C7ECC65A67AD5DD9D +:10EE100002FF2B5223BB8A08DD13919EAA46497D2F +:10EE2000CA26CE82FABB6656D709F5E6EB1D41EC41 +:10EE3000AF07ED07A817B8B9DE28705B687EB22E61 +:10EE4000E72BE906C6A1FE522EE2A584638C5BC8BF +:10EE500041B6897F27F4EFE625293B49FFF6D3AF7A +:10EE60008911FD96052C88D7E7845C794ECA9536C2 +:10EE70002B972B9A6BEE32A83FF741996F1DE095C7 +:10EE80009582DE83EF1B3F4AD1919E5EF9E85FEFEA +:10EE9000FD19B49FFDC0A25BA17D01D218ACDB734C +:10EEA0000A9747607F30D48F8DC0F6386EE3C1B1CA +:10EEB000647F1CB408FB46C8CFC6B4E0D685D04FEB +:10EEC000E393993EA064F6BC39F2E85E6C3F64F7C8 +:10EED000ED817E1B53385E1B9F1B49DF3F610F4E48 +:10EEE00077C33C73AD919F3C8172E3052BD97B675F +:10EEF000597411C27FB6D3AEE07B27705EE95042F1 +:10EF00009B82F3EA76923D047C9AB310BE3BB936FD +:10EF10009BCF4BE0E9E48609C4179BCD7CBCF0B3E2 +:10EF20000ABD7FC21C989103F5134F97FB564053BF +:10EF30005FC012B5003D87EEE3765EBD49DF8178A4 +:10EF4000628753095EB91EA18D8B67627B68E9F207 +:10EF5000AFA37C1C8ECF51DEB304B9D9CBE205C878 +:10EF60004FDB1A467546519F748FF3915A655E5870 +:10EF70007CA01B177FF79499E3357EC84CF47CBEC8 +:10EF8000FDE37CB52AAE7F709C10C86526F98FE43E +:10EF900072425D1DAACEC8FE0C3D972DEC3A63FB74 +:10EFA000EBCEE01D6EA0BFE6FBFFE79D6584DF387A +:10EFB000C945D69E497C79CAEC9F8B74EBAE895AC1 +:10EFC000E627E8F30D82AFEAADC2FE63514B221F84 +:10EFD000CAF6AA6A23DDCB72BDA07F678CCBF7C1CE +:10EFE000ED26C11FDFB4A21E9BC2416685A8471C47 +:10EFF000D8BF4EFD4FF9206AA9877AE1F2A8659142 +:10F0000028914F00DF511BCCFBD45627E76F4003FC +:10F01000F6B36832237DB94805FBB5029FEB5D3D31 +:10F02000B02EA79F7673FAFA236005F03D8F89F71B +:10F03000AC60EF821C7BA64D89E27E60DE16EB2E73 +:10F040007B11F2B55F75E27A6E57488ECD6B9B5699 +:10F05000B215EA4B0F5C40EB9F3699D3E5D2889B03 +:10F06000F4E214211FEBAD110BD9DF3F5118F2016F +:10F07000F44F7674237C945331180F28D70DF41075 +:10F0800049A8835D34A593CB5506F29C25D84B52F5 +:10F09000DEA31C6749F69F913EC2521F71B9C7F4A7 +:10F0A0006C947B522EDFEB0A74B949AE8DCEC6F557 +:10F0B00085F5E47273BF42786D622DA44FA41EE8FB +:10F0C0001F57E891D36A98EB2BEB262A5F7717D16D +:10F0D000784B5927E913A95786A383D7BF840E7E9F +:10F0E000867400ED8D1FB0E865305EE372166D9A90 +:10F0F000C84BE744D28F5C4FDAB89EC432E53CF48B +:10F1000065B27E4CD687C97A30DBC2F59D5C6769F3 +:10F11000CF644FE776C094E51195C1FC36A6F93F60 +:10F12000CE9C3460D784DEB2D9F40BB11E60A3E06C +:10F13000BDC569D36ECA86F690C6FCC857A980972C +:10F140009DF07CBBB07B6BB339DD7B2D9C7ECD5AB3 +:10F1500080953B705D62B4CF8D673217D2A3C4E750 +:10F1600076277C5781DF71FDD4FFBD8DB5A5247C4A +:10F170005FFD9C9DE4EAE7CF3A2356B24782856E55 +:10F18000E82FEB5756B2537B9F73923EED15FAD0A2 +:10F1900083F628D1CB2AAE5F715D272135558F6468 +:10F1A00048FBCA352351044AFBACC9CDEDACC1F6CE +:10F1B00090682F8A5DCFE9CA4AFBCCCFDD3D7762EC +:10F1C0001DE061689FFF8F58E7D081E9E5DF87E7A1 +:10F1D000A180C3C7B11F2C477AB5AADFB9DE06F4F8 +:10F1E00035435D1EBF0BE6D194EF70A19EAB29FCA9 +:10F1F000F52F6F84FA8707CCCC8AEBBC677A1D1B8E +:10F2000035BCFC5D12319FE849E0975BF619EB4D88 +:10F210009DC67AA8CB582FC8707A4E4F20D9E1FBF3 +:10F2200033D0B5D5DAF2C14E80D7FABC95F4D1A768 +:10F23000EE607106CA5B53FC18E2D95AF8F144F447 +:10F240006F84BA3F51B0B402EDC4CA38FE91AF3FEB +:10F25000B7CF2B740D81B701FC319B89F00CD63AE6 +:10F260002F49CE85049F782CFE0F5F84F92F9A9D3D +:10F27000E2BA9B9EF8674EAA427B926064A12D572A +:10F280007F88FB2D786F09AEFFE959F01EC0D5B01D +:10F2900085EBC346164B43BE6D06BBD3064B7C477E +:10F2A000065F875BDAE25551F8DF8E8CDA7108A7CA +:10F2B000F6272D80F4B11AFB4DB093AFCDE07AE084 +:10F2C000967D76D729031EDD867AA82BC7752A91ED +:10F2D000FF84FC61798A96B81F7A57095E8BF86BB8 +:10F2E000B2F558A6C1F857FCE93392F78B97CDA732 +:10F2F0007DC4805D6D25F9B4F8AE203D7F692BDFBC +:10F30000179EDE6AD711EFA7B7F3FDE3E23C47C4CF +:10F3100006FF7B859BDBDB8BE13B45198CC764BC1F +:10F32000BDFFF0555EA4A3F7191F2FDCC9ED8FF7C1 +:10F330005D80AF62FE0EF6F77E17D8EF0AE2F9AAFB +:10F340000F512E2EDEAEFAD04E60879CE48F59BC52 +:10F35000FDCA710B1DD8DFA723A6A15F68C795E87A +:10F3600089C2F70211EED7895D01CFB51D17931D34 +:10F370007774BB95C3E9B6EDC5795CF12795F84A7A +:10F3800033B120DAC71D16FF38E467FDE13D337065 +:10F390005DDE9F956BA2F71F57980BF1E15E968596 +:10F3A000CF172B5A00F9B761CB929989F64E6A862E +:10F3B0004AEB35AD7079568F83F8E97AD4A34DDBEB +:10F3C000817F70FCD96FFFF2464F223FDD5EC54C56 +:10F3D00009F6CBC35F237AC2BF28E06BB1C0D75711 +:10F3E000E52B6BAAE48B961294A38BEF6E29710D1B +:10F3F0006157F4F3C5C39C0FEFCB50B8FF202FC368 +:10F40000B0CF186E5FE62835915EB1F9987F0F9402 +:10F41000D9B02DC6FDF7810C8DDA0F64707B5FFBD0 +:10F42000DD6DFB5E87794DCD086ECF807A21F39735 +:10F43000E3BAEB71573598B18862B2BBD8C3566E48 +:10F44000C76ADC8EDE9CC9F6AE4BD88F77627F9997 +:10F450002417F6623FBDC7FF780CF1DA5CF0F14487 +:10F46000B40F42E73EB3A01FCDD1AD903C77F80278 +:10F470000CE925D43D8B2D281B90C3211FD713C920 +:10F48000F3FA5306DFEF843C71EAE7FD119C7F3B02 +:10F49000DC9C3EB72D4B213FE4364FC48E40FFB578 +:10F4A0007C2AEDA525C2EF67DBFD945F45FA8E2827 +:10F4B000AE3158D7397FF435CC8DA830CE87BB8B91 +:10F4C000C9DFD977609A4F8536C7EE1FAD198578A9 +:10F4D000EA32FBF07D87AF270DE7F7E1EE9369385D +:10F4E000BF86DD2ACDBB21F249D6C2B201B9F033C5 +:10F4F00025F83ACA01E6521C38BE940F1FEEFE34BE +:10F500006B8183FB0B487F560E8D97A7DCD37E8ED5 +:10F51000DF5F71395F978F1EB74650EE7D6407FD40 +:10F5200096206F3F72727D772A43EEEF3A0B50DFE1 +:10F53000F4D76F2A35A19CF88E8BCFDF63E92C407E +:10F540007EFC8D62EC67E91A138B806C5FB206500B +:10F5500003F2E8A3479F294079FFE19E670AE62767 +:10F56000C097FC9D2C7BE578C26F26FDA81E4B340E +:10F570000FC79BEFB3727FE5307E54F93EDBC2FDCF +:10F58000A17D3EAB8E7428BFEB6B48F1A37DDBC73A +:10F590006C24FFE6770BBFACDF3FDA83FB18F97D05 +:10F5A00052FF151E4E4F4A9742FE83D4B238C9E32C +:10F5B000BF59DE7B603D13E43DACF3BF215F34D91E +:10F5C000E2C74632A20F0BE2CDD2ECD0503F65AD80 +:10F5D000E4F415BFC344FB2A4BAED781F2EC8A9208 +:10F5E00094361330A227256D22C601F2734BE9FD34 +:10F5F0007035A7FB7016237F5B0E6B51485EBBB85E +:10F60000DF3E6F3273AD83EAAC11DC9EF132DF1660 +:10F61000B598D65D41FF90C487D40B483F281F3F63 +:10F62000526C443F4AB74276A76AEA9C8BFD0E476C +:10F630004F1347C8FD3FA7A7FEFA3F899E268F18A4 +:10F640008E9E823AD193D736343D093FF179BFCFB0 +:10F65000C201DCBF660B7CDD27E44EFC0E9BF49BF5 +:10F660002B38DF99A2BF9936475445FDE1337F9C83 +:10F67000E8FF7D18EC5FDC27E5A0FD0EE5C895F3FB +:10F68000745A3716EB417F41EAC536D28FF79A623A +:10F690004568AF648F6FD98F74913DB7AC6225ED2B +:10F6A000FFF2DCA80F50B7921F745975E0D488049C +:10F6B0007BE110DFCF34DFE5A7E7D3BBB97D101ABC +:10F6C0006D217B38D4A584719D9B039608DA416B2C +:10F6D00015EE5F096FB0EB3CEEA3AFA0B8CF0F748F +:10F6E0001E178A48FF6FCF8EEF23BD3538C8EF91C4 +:10F6F0001C3F3AF885CAC71FC368FC8E721EAFEA6A +:10F70000B85AE7FE15B17E1DB3FC396EB407D618A2 +:10F71000F959C685FA9C8018186FFE7A3BAD43AE46 +:10F72000CAF1CCD26D5CFF0C960BE467CE9A2C1616 +:10F7300046C46FFAF91C2405D67345BB8C3739CB08 +:10F7400002456879BFBBE9B7AFA400BD66A19F8E33 +:10F750006FCAC268F7937F98D7C97DFCA00900C91A +:10F76000C5D6FF5C577369425DBC3FF0FDDC6B6B37 +:10F77000F248EFF6B723D8A08F65DD6FD7311E357D +:10F78000D0AE81BD6BEB52F8F761C7B5578E063C22 +:10F790002872FCFF5CEB477FA19D19C64B844F4B41 +:10F7A000EADF0CFD3B74F97EBCF64A78E1C10A59E8 +:10F7B000BF66AD1FE0BBCF6CEC8F502ABEC78A1C62 +:10F7C000EFD6AC6DEBD6E70DD8056027EC1A913972 +:10F7D000601FAC7E7B66FB853056AAEB530BEA5D5F +:10F7E000A9E7431E85EC8F647E3D20E4C3DF2C57E0 +:10F7F000F54176F4811124577B66204BC2FE83E4E9 +:10F8000076687980A13D07F64817C2DB7BFCE3D31D +:10F810002F427BEFECDF1F1BA9E37BB7CE45BB3745 +:10F82000744E23BA0DED53230AD0AD4DF00BE871A1 +:10F830008A0B487A5AEA1274EA0E338C73741C529B +:10F84000268589BE5A0AAE83B5CCF7F85F4238E404 +:10F85000BE3279DEBF1EC1F70FA1D2EAAD25D8FFB7 +:10F860006E85A19DB0AEF444D602DA37BD9BB530AB +:10F87000E1BB255D0F123E97EC330F89C75F8FE028 +:10F8800071DEE6679FF6A3DCF828A2904C68D022D0 +:10F890006BA740BDA1C1849620AB8CCCBB91E21C70 +:10F8A00075163606E67704ED268463DF37C353709A +:10F8B000DEF04F8147DB028B489F6EABB339284E99 +:10F8C000543AFF56C2832BC58F7858575A9D83E30D +:10F8D00034CF9AE1A2F808D871D8DE7CD7B7C82F08 +:10F8E00024E15AD765AE453BA70AECB9A700EEFC68 +:10F8F0008C6B6A7DC0C723D5FDE5B73B305E3EB457 +:10F900001CFF6E26A78B362510FE4625F94159A20D +:10F910005FB3B08BDB8D9F8DB018E22B9F8DE0F62F +:10F92000ECA5E1D874249FC35A4F2ADAD321E6FF0D +:10F9300004F7CF2CE0D0F7D03A7179E469D5C93F0C +:10F9400066F3F4DC7B21B65FAAD1FE85693D0FE04A +:10F95000B8BD6B3DBE754CF001D6EF2AA37D4FBDFF +:10F9600027A87832F9BC707D7B9FBDAA1CFD88D288 +:10F97000EE5AFBA89DF4E65AA77E7F2DCAD3DF6915 +:10F980003C1FC0168F4D877E96FE3E83C65D6B8FF3 +:10F99000ACC5F50FEF54A9BDD8117460BF4BBEB90B +:10F9A0006522D22B73444A508F9A3DED0CE918B66C +:10F9B0002BE42FB179020CE3C4D3C3F33405F5452E +:10F9C000923D331DFD55B45FF190BFB65AF0C71894 +:10F9D000A082D3366285B63F8F18B06F5EF9E31C04 +:10F9E0000D1F4ABBC764E3FEF39ABA1486F62D5B7B +:10F9F000153F66427FBD27C6D00E6EEA54689CA6AE +:10FA0000D2272DB86FB9A593F37748EC33007F0563 +:10FA100068578CF1A40A7BA08DFB3958ECD848C4F8 +:10FA2000F3637C3D1983F712FCAB8CADE0F240F43C +:10FA30006711718626E157024D48ED3E8FB45BEFAA +:10FA400016FDB7F3528CBB5989F955C46BB962F0F6 +:10FA500087CBF22AF17DFA91F80CE4DF38D017FA5F +:10FA600097B62AB36EFD29CC6FEBA4F13E34C1BC2E +:10FA7000404E6A053E075204BC57767D3203E98644 +:10FA8000D532E2D7E6AE696A9383C76FD05EC84EBF +:10FA90006DD989EDD93797927EC6F8C86C78FE3556 +:10FAA0000FE7B31C07F7D779EF0E1761BC33FD489A +:10FAB000E0D69FE2F817A490BF351BD6C69941E562 +:10FAC0001AF46F7959F98BA87FBD33F50A8447C6BC +:10FAD000F5302E38AB8CE438D5337C8A7F179437D9 +:10FAE00078DC340EECEF6A115E7C1E710CC419D107 +:10FAF0006F87E3621C0FCBDE9CA8467E7ED0E77B3F +:10FB0000904EBBAC2EC4D7CCAE97DF427D3BD3C664 +:10FB10003A29EE9A64B7C4D3BE19443AED3B737ADE +:10FB2000C73D08D775077D94CF92648F5C7139B754 +:10FB3000CB3FDA93AA233FEC12721BEC471E7F796E +:10FB40009CEF2393EDC8EFF6AF2FB723FBEB7F7746 +:10FB50003B92C317DEC3F328A47C0F897D5F5FC38C +:10FB6000D934D45F2B3DD2AE4DCAF7D82DF23DBA71 +:10FB700087CEF7D076F2F80F864149EEBA2D22AE45 +:10FB8000E5F7CE43FF87BB84E4C02B7B53C34837E4 +:10FB9000673BED6497696E4B14E16A7BDA1AC13CEE +:10FBA000883645E0EB90885759441C2CA344478382 +:10FBB000E2A02540723FFCA499C7ABD2228FEE850C +:10FBC0007AE3E11C11CF62D47FF8D954C277638AFB +:10FBD0009E8EFD37FEFB088671AA3E180FD7F909E5 +:10FBE0007B70BB87E25ABC7FF68255E7F1B3688928 +:10FBF0001BF0B033C2EDBF93A5A6A805E6BD93895F +:10FC00003C9FF532AEC5E7D9B761248FCBA03182D6 +:10FC1000FBB2B5DC5F542FE35587B91FAE5EC4A5B8 +:10FC20004ECE5EF408A658B4292DB5B84FFB7CDD46 +:10FC300034F29FDF79FF2C2AEBD718FDFD8BD03FE4 +:10FC40005F3C103F967EF7F9CC67E1F6F380FFD07A +:10FC500004F68CBE46AB46FD59C45C77A33ED0C3C8 +:10FC6000B07A1743D906251AF10A6019DED3D67A7D +:10FC70005270BD57B799486F85DB4C7E7C4FD2CB15 +:10FC8000AB1EAE67DFF570BD03A88EE038B26C33F3 +:10FC90008B7883E86F053345B13429BC5CEDD26ABB +:10FCA00087D2DFB2BF36738B6D1ADACDF926F277C1 +:10FCB0007F6EF1D791BF38A384D6A9CDD9B2A696CD +:10FCC000B7132F7D6E8F07A8FD328D1B964CCF404A +:10FCD00079FA8287C71792F1B6B0DD584F8EC32CE0 +:10FCE0008918EBF52C3836A798C70D129FBF20F462 +:10FCF000C4E7EB8A04BE7D1694BB72FE2BF238DE9D +:10FD00004CF9BC1C955F5D8774300AE3CA45587294 +:10FD1000BF2ACC84E01F75994721FA4882B7CDCD20 +:10FD2000E929BC96FB21FF5AF893E1FED09325F810 +:10FD3000D8EFC5B865BDCB4271E8F3F597A4641A56 +:10FD4000F7B7FDF5BFFFFE96EFE7D7AA22BFC6457E +:10FD50007269BE8BCFE5A4E2DB1BC5E70EB01F7056 +:10FD60001E6BD50A9423D3BFE9A079341F063982CC +:10FD700071ACE53D05A8D79BAB7B4A305E938C5FA9 +:10FD8000845693F20CDE9BEF81FD08DA0D6B8CF14B +:10FD9000B8C1F1557F616626EE7B4EEE7F19F5D72F +:10FDA0007E3BE92FF8BF17ADC8FFCF16915C8B38AB +:10FDB0008363312E144A89EEF87111DA31DC8E6AD0 +:10FDC000EAB6EE443B717E5B427C0FFFB3DE18EF78 +:10FDD000636B32C8EFCE3A8CCF1B1E4EFA6E50FCCE +:10FDE000AF9DD665B325380EF91DF410E51D9C595D +:10FDF0006262B8BEF5AA6F112AA93376A37D7EC6CA +:10FE0000C9D76B46A6D43F3EB2BFFAEB83D6D957CB +:10FE100082EB5C6F62C1C47E9A709D617D1BC53AA6 +:10FE20009F79FAE2125CE78FF75F5C82EBBCD9DC6A +:10FE3000EE47BE297507AF41FC9CBA3240F615E685 +:10FE4000EF201F9D2F3DDE94448F37FDE3E8B12E58 +:10FE5000311F32593F36F4E3CBA81F3D163D0FE565 +:10FE6000C17C9BF52FEA49FC1BD29F67B392FFE34D +:10FE7000F01F3FDD48F918DD2AD927B2BFC35AB0B9 +:10FE800018EDA3C36F797D6165F8FED385FDE5B5F7 +:10FE9000B130FA59E4BE40DA97C9F278B998CF0385 +:10FEA00099FEDF8CF81BE23CD27FDC20DEB1453EC0 +:10FEB000E576EF6EC5C7FDC79DE44F6E3E34CF8536 +:10FEC000FEE20F22DC7FDCFC7439F98F97445E8AF6 +:10FED000623E19EB565CB81F59B2FBDD34CC03907F +:10FEE000FB5ED8E7DE9F49F935C6FDEF07919369C0 +:10FEF00098370070BF8F70A77AE216A4FB66D8FF10 +:10FF000061DE60B3163F86FD367B18D905955DC668 +:10FF1000FDA08CEF6E0B5848EE6EEB562228AFB367 +:10FF20002CC1A23CD46B2CCF753A7580CF2299FEA0 +:10FF300017907E07E2EAFE5D5897FEA79EADE94462 +:10FF4000BF3D66E677A13CDBEA14F24C23F9F6DB11 +:10FF500087DD91750976C36F23DC4E5822F3C134D7 +:10FF600016D560BD16CDF11FC7F546791F4D92F726 +:10FF7000897519AFBF8545492F35B19EFEBCB0C408 +:10FF8000F792E3F9180737F4C35ACA75F493DDE41E +:10FF9000F0519CABEBCF56637B98EF9B811F96553E +:10FFA0000CD0AF5C0749BFCDC21F1D6A38B10AE94A +:10FFB00037D4A5B8707FDDE8E3F4DB08FB2FCC9BDA +:10FFC0004DE677D669CC131D8EFF7FDDCF779CFF82 +:10FFD0007F3DAC9CFAC7F85BDFEF973F9CEFE5FCF9 +:10FFE000A5FFBE7F9EDD0AE7CBA47925EF5B93FDDD +:10FFF000EE72DF79BEF2F08B247C7CF10FC6C77005 +:020000022000DC +:10000000F230256BE8FD42725CE3AF9687FFE0F8C3 +:10001000C623871E4A3381A8585214F672BBCE6F8E +:100020008817CF501D7E1E3755793E4572DC5D9F87 +:1000300021E2EE9C9F5F7A5AA5F56A12F1E1A64390 +:100040004E1FBEDAE0584CF1D9E4F8E952B67F060B +:100050002E51721CB511F9B8F8CBE3A91765393DDB +:10006000249F745684790AC9795A2F393E1D114C40 +:1000700058EFEA32D8080C41D7362DCC32129E4FB9 +:10008000CBE2F6F44B229FC86BE1E705EE73A6FACC +:10009000711FE335F17CA77C4F607AD62494EF0280 +:1000A0009FCFDEC04C809747CC9D244FC24D0E1F82 +:1000B000CA3FE9C791FDEF10718BF3A5F36F671984 +:1000C000E9BCBFFE4FE2FB8592BEFFDAB8DD16C089 +:1000D0008D811F18D1EF6B18672A1A4CB7C3F533FF +:1000E0001CFD2ECB0ADC9E4578F14FA4FCE6F39470 +:1000F0002FA995F193E82F6207AC3AFA376DE2FC2D +:100100000B5B9F23F6EBBEAA599497CDCF8FC87394 +:1001100036C3D98F1BFBF99FDB8FFDF5BF93FDC85D +:10012000DC81769CE7A9697ECAFB5FED04F8715F0C +:10013000F8A875C8F32CF2DCC597F95DF6F6C3CDC7 +:10014000E96AEFB070FF63E5E793FF34F9F9FB3438 +:10015000F4A30EDF4F58E47BC6FC229EC67625F83A +:10016000B743319EAFF79280573E7F44E8C5F46CA9 +:10017000FF515CA78F8FDB6C2C1D4C9E4A2E179B6A +:10018000030E8A2F3477F2BC97E6E58CE47733FAD6 +:100190004FCBD0AF388BA1BD373523F833FC7EF57C +:1001A000DB8EB09A8E7EF7D90CEDBBDEE3BCFEA9E8 +:1001B0003BF8736C0F2DEFA17846C7EC8F28EFAAA0 +:1001C000EACF9FAEAAAD2478C98FE0B11ACFAD7C3B +:1001D00091C5E30FB2FC43BF3CF1935FFFE3069E82 +:1001E0009F1DF2F85DE88F907EF1543D467EA6E6B5 +:1001F00003DC68AB52F97CD8F7F3889E9A0F4C2B3E +:1002000047FF29EBB497A39D5BF52B07EDF73EBEA7 +:100210002B97F224EA3DC10F513E3A2B2357A35DA1 +:100220005A08E3A0BDFBF1FEABCB116E29FF36A34C +:10023000FF1CC6DFEC34FAC7998DE7D92FDD9B4F41 +:10024000FBCB6247F053EC6FB39DC311DE23CEA30B +:1002500008BF7932FF4BBECF564D344EF6B76D1402 +:100260002F977261B399056DC503F2E478962EF26B +:100270004C445E63F72C9EA722EA0E8F31BFF381B8 +:10028000CC2B8F233CC7B3B4AF961FE618942F40F6 +:10029000FD627E18C505589CFC2DA9E7B81D3DCA16 +:1002A00065217A7202DF519C06E809EDF94BE3B152 +:1002B000E9789E6B7447F452C4F3E17326C2933617 +:1002C000EB358AD3A42B7CBCE2F53D6BC7A21FC6DD +:1002D000F5E665B8A47ABBAB1A513A3523909F4D29 +:1002E000FB8C96521CAFFABFCC3C9FF2502AF917F8 +:1002F0003A0A1A299FB2F76DABE13C4E7219667744 +:1003000053FEE4A8AE5F50BCC0794019322F76721C +:10031000B683F0D61C8ECDA01C9B4B3D2467B54305 +:10032000BFA238B5B6564309C4DACC7E139E430B40 +:10033000AF60E4EF1CD3E132E17A158AFC98BEC3CA +:100340007F9818A4FD8A8C0F44787E93B96715EEC8 +:10035000C3B4153D9787713D0EB84DCD65D85FBCD0 +:1003600099FC2D875219D24F6157F1DD53A15EB828 +:10037000C645F1B0BEE76E2924FF2ACC73CC10F33A +:100380002CCA36F3FE0FA59A509F699B980F47D54C +:10039000DC59D504F78350877E468A3C55193F4582 +:1003A0003F14EAA9F4ECE0D7303FB6FF1CD2B214F8 +:1003B0007E0E49E3FE12E7B2B71FC7F33D3B2CFCAC +:1003C0009CE791C3136693DF6FADA6E03A7CEEE63F +:1003D000F99437669B0CE74206F07F84F256471D7E +:1003E000FA05D76B3016F6AF9939BD686B3D3BD136 +:1003F000BFB8382D4879BA97B545558A9FB94E3D53 +:1004000050AB27EC73B6703DD3BC8FEFCB93F73571 +:100410005FA65F6ECB36DA2DFDF57F92DDF283FEAF +:10042000F1FFC6FD0A33EEF392ED97E47DDD203B4C +:100430003CA9BFE1EC18998F523D300EB7A79DD271 +:100440004E0A1BF275AA1DE27CA1CDD8FFE5235C04 +:10045000345F99BF93B5525F8179FAF11F30F2D7BB +:10046000C93CA27035CFF7099B6C74EED0CBDA296A +:100470007F68248B2A0AF9D37AE87C6D36E611C1AD +:1004800077EBB24751BFDB996F8D4AF25257106E2E +:100490003BE69F50BE6A64EB221CE73A078D63C7B8 +:1004A000FC938B3085C0BF15E5EBF4061E5FC805D5 +:1004B0007D8CF49B3B9AD3A1BD8EE7A1C83C1399D8 +:1004C0001722F1502DF09B3B765111CAC1B54AF06D +:1004D0005171AE99CBFF0D4E715E19EC6BCFC079A7 +:1004E000E43EC6FB0F3798F8796437AF778CD1F9C3 +:1004F00079A02FF839BB8E729E7732283F2509AF3D +:10050000323FE5C9B4E011E497E4F3CB924E12D642 +:100510008FCE476F3BC4EDFAEA060BCDA36FC9350A +:10052000E497EC5B6262A8FFABBBAD9CEE92C6DBCE +:1005300056676151EC578BD8517ECAF5FF32BB1616 +:10054000D6B514FDBE475A6B2F3A05383EDA1AA0CD +:10055000B2CFAE74AA17D2F9D2B928A99ED8F2F9AF +:10056000B55A0EE6DBC40B142099E7B77E3493EA44 +:1005700099F177B0FEEA16CFD73490C37D63E23BA2 +:100580001478FFFF797FC4DB911673197BF7A1877D +:1005900066861D5F41DFFD9125E7719C41BDD3C497 +:1005A0007A56C5C85F24F45D2597875E8785EC255C +:1005B000AFC83F6535221F15233B505F99534E71DD +:1005C0007B07D30FC4B03D8F9FCF8276A2FF956388 +:1005D000B87FDA26E882E549BF544F18E5DBCA2226 +:1005E000377DDF2F8F0F5823DC3FC6C77FE3E90B32 +:1005F00028BE25F36A1973E5CFB980F26C0CF5FBC0 +:10060000ECE21CA6E6CAC773EC2BCDC2EE15F5369C +:100610006730C58BF3443E047BEE8D2BBF5B867C3D +:1006200074E6E0F747A35CBBCA02FB8221E4D8EE84 +:100630001C2EC7FACC8E350A7C57E30C8EF0C2FA1A +:10064000BF953A77061E29A81B31CD82471758F867 +:100650005115F19A29E8C43D87C3E7AE0928987778 +:10066000BAD2CEC7CD0C6A7E3AF7109CA35C077055 +:10067000AF54B8BC868FD2C98E2AD5D3F11C61A3E2 +:1006800038D7AA0AB97149E72615EDF59FB7BE35E7 +:1006900055D306E0FB858887FFA2C8783EA2DCCB55 +:1006A000ED6259CE56F50B90FE56ADF0BC36F31206 +:1006B0007CCEE9F8CAB4659598A77D556A4B25FAB2 +:1006C00069073D4F87E76509752B7FAFD1162FC0AE +:1006D00073E60BEDC149888FCFE7BD7B27CA873B07 +:1006E00073DF7807F324DE300B3991AF88F5EE988D +:1006F0009E06EB79ACD82DF23C6C440FC7C6723F16 +:10070000647F1EDB3885F2FA66CEE1E749AF65B15A +:10071000B61EF89E9C15D03E637211D9913345DE0A +:10072000C58CB70269E8179871435C43393A9C5D00 +:100730007495D7ACF724F0C3D5BAB17E6DA9B1FEDC +:10074000359FB1FE8DC97F1A9B587FD9EE9F8DF4DE +:10075000F4BCC2F33EC3973017D1BD4709A3FD32A5 +:10076000E1995C710E97E727FEABD8773D3399513D +:100770007BD63EDB2E3C3720FDD7AA689FE065B6CE +:10078000C20C7EEF03EABBB822F21C3D14D3610712 +:100790006F75713F2EBC6B817E0ECED3893FAA460A +:1007A000DA52904EB21C267639F252A58DEC9A237D +:1007B00082EEE4B9EA2A8D0530CF02869C83E51BE0 +:1007C00066D78BE8A70E7FC818E7DB691AE55B8A56 +:1007D00031185B41F587045D1F91F2FF079A585766 +:1007E000E04018EFECFA5C1E872E65745EFE6C65C7 +:1007F00009D525DD4BFE01AE1E8DA14145F427E94B +:10080000F9A74E0BD1837ABF49F8BB34130259EADA +:10081000927080B8C9423DC9C8FE9571BA7C9B6C84 +:10082000D7FCF87E0E93757EDE2B4BD4A1296AAAE5 +:1008300040FDFCF2EF487F3B7C419C8725CD46E79D +:100840009386E3A35D827F7625F1914BBB9AF8E80E +:10085000A7CE923B08EE6B9C2ED4AFA53097BA0C76 +:100860002AFD232AF03BCE4F6A8A4F47BEF966ED38 +:10087000F1A95A829C86EF9BF8F7A9C6EFBDF07DDF +:1008800046C2F769F07DD9E0EF773B6D51D344EC78 +:10089000A74AEF217D18A5C95E23E6AD66F1EFAE4C +:1008A0001179B1A3D3E07DD45BA5C63C1336D967DB +:1008B000A3FCE4A4BC92AB94E539C85757DB9ABAC1 +:1008C0007BA0BF97C53A5E650A7EE682E72FCF2DF3 +:1008D000398AFC576B8B6898D7772D8BAEC2C5EDE4 +:1008E0009B167CC45D4CF2E159E4936635383603BF +:1008F000EA67CCEDA36F2D22FE79CE9B39185E49B5 +:1009000027125EA417A43F492FC970F7AFE7D73B62 +:1009100029116F3BD851584ABB8AB1169E77ADE773 +:100920000FCC0B886886AD6534DA352F2F0993DC40 +:10093000B8CAFD00E565BD9C1BFC4F946775177E2A +:1009400052A0E1CBDE796371DF00F0C6FE37E1959E +:10095000F6E3A0BCE30F2D86BCE3E1F84C8E1B420E +:10096000BB50C5FCE49D94471C9AE3F0E1799110DB +:10097000E6C15652FC8AECC2E7146E6F87159BB035 +:10098000E3CE373F99717BAFA9DFDE33E4D77794AD +:1009900073B83B6ED5E5FD35DC5E9CC7B83D394B81 +:1009A000B42F7451BBCCC3EFD8C9FD861D4F8FD572 +:1009B000B15FB003C97E60E9C2CE2C32DE9B837F7B +:1009C0004AD640DEF86633B75FB7997C5594E76244 +:1009D000E1F7E29C91FE8C317CFC64FF626E8E62DA +:1009E000884FF7D7FF4EFEC55277303F07FA5B5866 +:1009F000E62F504C0817F733027D3E1C6398FED655 +:100A0000321AEDFEAB59CB9BA662A2CFE21CA4CF5B +:100A100009409FC506FA1C9D93C9E524C225E9B388 +:100A20009F2E4B93F3CA8217603F1DEECE5F35A316 +:100A3000BDDC6DF5F1BC5A9E27982C0712E059A039 +:100A400071783CAA4AF04CC27193E1391F3E49A427 +:100A5000CF6CC6F961387EC9D658D85931C02F2F0E +:100A6000DB8335087F3FDFACE2FBA34170AB0EA216 +:100A7000AFEB6FE47194502AD747184FC981F167E3 +:100A800089F1AF5FCBE9F0FA7FB110DD02F8518454 +:100A90007FB6689FD5DD447954B36BCC2712ED0047 +:100AA00019B7A913EFCDF1949B9105E6CC34C64B51 +:100AB000EA6EE2F19AEB588B19E1BD7E8EB19F3A56 +:100AC000B6FE13CC0BABBBC9F83C98D31F67198B90 +:100AD0007196A3C28FD007FC82FCF4D3CCC50FDF84 +:100AE0000AF43BF6876515E877BA326BC9EE4D50CC +:100AF000FFF1B6F154FF69D6B7BFF306B6EF28A1F0 +:100B00007A0D26B9E13E08F911F54DD58DD714C1FE +:100B1000B847EDA2DF5BF939026F4AB06316BCE754 +:100B20009D388AF2216B84BCE95BC8DBAFBDD0C9BC +:100B3000535E6FD6C9DF5893C2EFF579ADFCBF2B7A +:100B4000303FB76694A8573C3F1EEB47954FE81ED1 +:100B500080DE268786F86FCEE57EDA09A54A741C0A +:100B6000E0A52643F4DFC4E735B3E2D15CE48F9A15 +:100B70006ADECF04DFB4B5C5F89EE92CD57B736D72 +:100B800069280F259FB5E770FD2CEDA980E0FB6774 +:100B9000FCEFB68D807E0336C587530C4C7E97DF05 +:100BA0005FE5E0E7CB02FE220DFDBCD3FD3C7FB349 +:100BB000DAB62207F7E75F0F5A2A715E2E5BF9510A +:100BC000B46FD2274F9B44F9BE3666463D0774DFAB +:100BD000417C78F1270569486C0E23DD4BBA9A25D4 +:100BE000E9BDC648D7C0AFDB7232BF5C5E1BE8DA36 +:100BF0003E40D7C3D9B900D78F09AEA946FDD53F2E +:100C00004E125F268F3B9CBCC0BF44793A005F27E1 +:100C1000F15F1E66C515237FB64BFEEC42382CA64D +:100C2000189DB329547CE3E960EA307686842F1F4F +:100C30007DAE1583E1C23F4DDA7FFCCF83FBF23CF2 +:100C4000D10EDFF959C6005C30FE2B240F577178A6 +:100C5000B62B2D5CBE087B5CEEE79BE57CBB8CF382 +:100C6000AD4AE1E7DEBDE87721DF7BF9F87EB8CF5A +:100C7000631DE47C42426FCFB1059C1698DB75EE94 +:100C80007AA29F1B58F869B48F963983FF17F174C5 +:100C9000C4143E84FB9C85CC4FF157A08F77721211 +:100CA000EC0D096F329E9A8791A7C9F349C6CFC050 +:100CB000BAC5C8BE93E7D8FAE77B9EF3947689C796 +:100CC00062F4776508FF5486F0472145A17E9EC9EE +:100CD000527CB82F98EE53C8BE98C96C249767D63B +:100CE000727D9EE1E0F687D4FBC3F1C7159733927E +:100CF00057331B993837C7E7954C87D9ACE70E2C8B +:100D000067DAF4AD0B90EFD14ED107E09FE9E07EBA +:100D1000ECEC5C213F58CF24D4F3FDF5417ABE675B +:100D200012CA9FE4FBC9669EE3FED28C738CCA99FB +:100D3000BE7727A19ECFA8ED998472CCE9F27B7390 +:100D4000270DDC1F988CC7D1B92619873B2FFA4C89 +:100D5000E61F193F6B7306C7E238D2CF714689553B +:100D6000E14B151E97E83F588474EC76154D43FF10 +:100D7000C51C1BE82318BACB15BC3017E9ED8F0052 +:100D80000F6E0EF155C0E37535C17B343E2CE1E1A9 +:100D90003681872B855E3DFBB04AF1891A7FE94396 +:100DA000184208BD626611E2573FE94579BFD8593C +:100DB00030A0A2F8FE634EB23316BF5A4FF195B180 +:100DC0005B4C4C4FD093E32229867B3226ECCB3010 +:100DD000D42FE8CC35BC7F61D728437B7974BCA184 +:100DE000FDA2572A0CF549B12986F72F7EABDA50C0 +:100DF000BFA4E71AC3FB533F986DA883C6D070DE2B +:100E00007B9F55D83698F765F16F19BEFFCDB6199F +:100E1000AF60BCF3A4D8F7B2B03F560A785820E9C7 +:100E2000F6DC7C637F5125AA5421DFF3BF05EB7903 +:100E3000BEF634C05C62BF0BDB8DF6C4E22DC67A11 +:100E400043F7A655281B07E779B454E35539C97908 +:100E50001E35AE7926A4CF502ED817E31011EC62C0 +:100E6000CC331B8ECFBF6CFD4BD8E82F5B7FFEFED3 +:100E7000160BD9F58B5F7DAA2A0A8FAC5EE3FADBED +:100E800075E3FAA7961AD7DFE933AE7FFA64E3FA7F +:100E9000BBFDC6F51F516B5CFFCC8071FDB3EB8CC5 +:100EA000EB9F1334AEFFC806E3FAE7B718D7BB7061 +:100EB00099713D8BC24B0DEDC9EB2FE565F19ADBC6 +:100EC0008CEF017A4D097420E96841A081F277C660 +:100ED000B47FCF304E323DC0BED144F7BFC13E6E6D +:100EE0009B72FEF401D28AFCBDC9F4F16FB9C2EE67 +:100EF000147401FAA813E50AD8174F61593756D868 +:100F0000FB81A1ED0B29BF12F579E2BE7838B93625 +:100F1000484F897DF2B07A0AF7C9F6817DF270F404 +:100F20007B1CB38FC88E5A4F7EA51B5D1C8E4FF164 +:100F3000D125E8CF7D82F4F271007032C07B1CE7CE +:100F400003E31F4F9940FE8D6FB328D9EDFF82193F +:100F50009630D8CD98A8ADE23D4F3A95F5426F2F27 +:100F600014FE8F85F6E05BB9DCEF519885E3E6C5AA +:100F7000E8BC147B6DC479DD237102E30820784F4F +:100F8000611C01CA5E3BA79BD352AEF899EE49C0E3 +:100F9000E7FCE94A29D9B56A0AE53DCDBF4121FD03 +:100FA00034FF7F781917FA2CB95CB94CE2B35DD8DD +:100FB00003DC2E48C7C39A1477624107E1CDE7C22C +:100FC0007586FEB81FFF47FC7CCDE30AD32667D0A9 +:100FD00031335A675C6F3C0FA5DA389C8F9B990DB3 +:100FE000F1398105C90EBC5703D1C6FB1BCFFB7B72 +:100FF0006314FAD354F5FF7CAD06E3CF382EFA9F85 +:101000001D3E86FE66D5EB63E8BF1AF4FCC014BA39 +:1010100024A3BFCEF87BF88778917EC23C412FBBDA +:101020009D8CFBBD92FC86235590C098BF63E6E77C +:10103000C3BDDA16BE9F3CE65B634D9837636637E7 +:101040009EE7FB327B08F36D4F27E4C7C3BA0C79E8 +:101050008FE9B43CAEEF57B6365C8671A25E1107DD +:10106000BBA7357819AEB7AAF9282F0EEF5772270C +:101070007C6FF1407B029F6A8E0643DDEC08105EB8 +:1010800056B5B610DD98C53D50ABF36E730513FC35 +:1010900012178E14F6862DCC5C594C98C6F0F7C109 +:1010A0007486F3555DDAE9C47DA8D50BFD25CA2BFE +:1010B000AD9025FAADD7B4B610DCAB9460103BB35D +:1010C0008E66513BE0DBAAE1595478BEF52A92675F +:1010D00016E76D3EBCF76738FC59BDDAE78972C880 +:1010E0003FD22887EE6FB55D8EF85AD9BA8CC69379 +:1010F000786B6F755D8EF58DAD5ED1BE82DA4DB5C4 +:10110000BA82F4711A6821867116ADC789713DB033 +:101110003319C603CD5E5B0499C8EAE1F0B2A305BA +:10112000441F735D1C06F48DE5037DBCB3CC4CFB02 +:10113000D3DBF31DF4FEEDAF8F79D10F7C60011E80 +:1011400051FF8AF9F48F23F06711728869C100F2A8 +:10115000952557237F74866B36ADE3DFDA9FC4BBDA +:10116000C5CE281FD492EF20BBEB7CE10C8D14F789 +:101170005009BC27E30FF04472F47681A7DBEFE25D +:101180007EBEDBEF6094C7CE96C15FD5005D8D1447 +:10119000F2259B05A86C6F05C15282EB6563410B7C +:1011A000E875D6492FDBD1BF83ED7ECD8DA1EA4D09 +:1011B000359E59586E9C7CAA1DD9F1BE4B3F8B6160 +:1011C00089BE74C497AB8145F0CC1FC58E3D781D98 +:1011D00035AFA789F6B43A5E4F17EDE9015ECFF758 +:1011E0003FA9D4206049F1977C47C6D5A351BE2DB5 +:1011F00060FC7CB2B8E7603B13F2C29131AB06DB16 +:101200006F6274BE40B6FF50B4E7384EAC29463921 +:101210003CC7F8FD5681876CC789F6E9149F31B643 +:10122000CBF84AA6E3EC2BF47D99B1FD41F1BDD397 +:101230007136361DDB471BC7DF20DA531D3CEF0834 +:10124000C4213F472FDAEF15ED766CC7F14B8DEDDA +:101250006BC5F82B9500AD433F9F89F8E48E569DF2 +:10126000EAC97CF6EAC80C7E8E59F0996B191BF21C +:10127000DCFCAB2379BE4C9ADEE3F70F210F657BD4 +:10128000864BA3B8AFEAB5101D591D428E083EEC3F +:1012900097234A8B8F1317F7977F193D03E17E8EB3 +:1012A000F2AC00FE909EF3BE6362C1047996DB98B7 +:1012B000C28209EF7B176418EA5937E51ADEF7CCCA +:1012C00019656877548E37B4B3583EF1C76D82AE56 +:1012D00052CA2A0CEDF2BE02A6733E9276B579F49C +:1012E00014C37B674BF574A4EDD357CBFBAB7C36B3 +:1012F000940BB7394765231FFEA475321ADF20EF20 +:101300006CA27489D24B47C956B6EAA25E4AF5C7A9 +:10131000DC3CAF7A65AB8FD78B189D6F5ED95A4B8B +:10132000F5C7812FB1FCD7563F957BA00E160EFB5B +:1013300011F4AF433F3BA17FAC3F02FD63B91DFAFF +:10134000C7F287D03FB66F857EB1FE10C085E583BA +:10135000D00F3E7F00FAC7FAA6D600D5EF6BADA33B +:10136000FA86D62095F7B636D0F3B5AD2D545FDDAD +:10137000BA8CCA7B5AC354AE6C5D43ED16A1371FBD +:1013800013E71F1F9BC6CF7D27AF7F469EF2D5EE8A +:10139000BBA804455E65C893C8C8C37D75A7312F37 +:1013A00010F14770D8391E93E1182BE018CF622B4B +:1013B00052B9DCA038EB982EDFDDA9C0A7235BF87B +:1013C000BA1775C5A93DA7818F3756CC9379C22C22 +:1013D000AF8A1FEFC5F77A9558752A8F37931F8309 +:1013E00079013F55E2DC339179C484706993417F80 +:1013F00027CCB31F5F6E0E27E26D28782BF2787C26 +:1014000043ADECE4F79BD4B64791CD52FC2D74BFAD +:1014100089AD2E10D5A0F40482744FC2F8733360E6 +:10142000930572EDDCE54C8732AFD1B8FFCA5D5051 +:1014300061D8E7A8E73632FD22E8B7CCB84F4A19A1 +:101440007D9BE13B5BDEF70CED16CFDD86F6F9B751 +:1014500014ADF2223E47328A3B59D7AF603900D7EC +:10146000C28E4D045750E0BD57D1F9FDEDFBC5EFDD +:101470004408FBFFC72E812FDB7ADAD78E75F36A1B +:10148000497AD884FAE7E3A7D2498EEE7DC444FEB8 +:10149000ED712C6242793301CC486CBF006F7256FB +:1014A000E9CA1C15EBE54C57B17E118BD3BE08EC95 +:1014B000FF3AA417B0FF1FB143FD4C7EF0C73CBFFD +:1014C0002B4A7ABA44AC6789DC076DD192FDC373AD +:1014D000F3C85F633C07D626F6012BDC55D918EF1D +:1014E000ED1D26FFCEE9FDD6D405B01ECE9C3A2ACE +:1014F000E5F30DBA69C873D1CBBE2ABF6C013D625A +:10150000E4976508FF99CA9F67A1BBAA79749CF804 +:10151000A6CD2CE5989E8E726CA0EE4B27BBA23B0D +:1015200087F0A389F5D9DB1AA4FC00394FED77D3F6 +:101530005C980F5622F24FF7B5DE3AB526211F66AA +:10154000B7A0DF5216AB453D5A5A66F245A827AF01 +:10155000C17F611FDDEEC773FA5A05F3A1181EC7DC +:10156000DAE9BCBAF6854A7940DA914B980E76B042 +:10157000C31165E1B2817E99F0837C47C8F5CF5CE9 +:1015800035340FAD40DA473ED4DDEC33873F867407 +:10159000F7598799B3E509637BA983919E5B546AE8 +:1015A00089E80AA623B4D33D8BDA0E85E515211C04 +:1015B000D3BDF3508F1F4C25BA4DDD524557C37B29 +:1015C0004CC1F57900C7991EFDA0491A57F05ED3AA +:1015D00004CB2EB41BC7225E709CD1A584C7856244 +:1015E000BEFB5A57109E9E15F368CBEFC73B87870B +:1015F000F9FC78CFE9A20EE9BF31CE734365F53728 +:10160000F0DEC6953155D874467CAE33C726CE532E +:1016100006E002389F453855849BFCBF7C7E4D8F89 +:1016200070BF19C8B15A8ABB4E32B1C4B8AB2CA333 +:1016300042FECDC87311BC4EEFDCA90B2E4AACDFC5 +:101640004474FDB8C2E71F766A3C2FCDEFD713FD77 +:10165000C4EBE47E599C7F4811F0F6DFE3369EE749 +:10166000613A586C0BE62D0DB71FFE252ECAA4C497 +:10167000FD30E81818579D64A33C9F75328F4B7F4F +:1016800043C77C332CF1FC8A4DD0E96AA731AFE423 +:101690005C1EB777CE89F5E8B371BEC6B8647956DB +:1016A000C2BD17DDF5E4FF9171CCBE6E9E0F2EFD1D +:1016B0006B4B0409F41DE578E87B58A5F8E592EE3C +:1016C0006BF97DA1871EA07B56A12F1DE9A15EBCF1 +:1016D0005FBFC6E8EF59B03BB02A451FEC575AC46C +:1016E000C2E4D748F62725FB917E9B27F6693E5634 +:1016F0008E71CA93EB8B8FA5E07EA688D1B9DB9162 +:10170000EA93748F3158FBED784F292BE3F7F424DB +:10171000AFFB250516C2F33EB9AE631CE467D837AC +:1017200089F3FFBE17CF7E7D0CF4F396AE18CE8101 +:10173000BCA59B098FE381AEB1EC64AC76A8FBA09D +:10174000B2F34D5FEDBCC0A5C6DFD768EAEA3996B3 +:10175000AA93BCCBCA0778FA8EFD3EAD8CF8274E13 +:10176000BF075157C4E141B8F1FCCB7ED3277313B7 +:10177000E9607CBEC6ED837CD35793BF3546B8CEB7 +:1017800094BD99750D876B1CC2D51B3D919568B7AB +:1017900048B8F60F73BFFAA55F154F938DFA200175 +:1017A0004F53FF129EF65B86866796C0CF4F8EF230 +:1017B000FB4206B77F45FDD56184F7CC63B1EB51A1 +:1017C0003C02BCB3087FDE5359143315F8EBAC145C +:1017D000F45929E48E8FCEA8B0D0DB17537E5EA7D4 +:1017E000C6DB43772E8AE07902DF8B0B0AD1DFE07C +:1017F0003C6EA57B9E42497922B25C2FE6B13F57F1 +:1018000019120FABF3B9BC78F1B5F9D4DFBD6F593C +:1018100019CA83ED22DFF55E57A70DEFEF9578C467 +:101820007A0594214B7C112ABA7B2B3FB3E98E2198 +:10183000C633F1F1EE4BE21B399E2C57E49772BB95 +:101840005439AAE23987FB2E7D93EED9BAAF5223E1 +:1018500099FB37E37F7D12FEA36F667D9DD3CB8A14 +:101860007CF4A32AEFA57D03EA2125FEB332C49FB1 +:101870002548F30FBD6D653B95C1786A14F42BE7DD +:1018800027E72FE1765EB680CE99E07A20E0ABC5FF +:10189000FB524FA40BBD87F3223D71A9C6CF894CE3 +:1018A000D2685DEF9B3C85CEF5EC17F914F14B2C1B +:1018B00043FE2EC333026FF79EFB450CEFA90D7755 +:1018C0009BE95E05A6F578BF0974147A5DA37B9A3F +:1018D000819E6AF1DEA8175F3B9B86FBE803F966F1 +:1018E00082FB403E97877DE7D45A3A6FF3DA672E42 +:1018F0003581FE9FCE57855D128BE1399A8D15FC9F +:10190000DC8043D8018ED74E3520FC8EC9DFB32A48 +:10191000097A764FBE95BEDB688967F9300E744848 +:101920006551EEDFA1FBEFFACF0BBA381E9A2B8F71 +:10193000929DE0E8E6F7E23D9DAF135C08F7417841 +:101940009E32EE33573DB657C278A306BE77BAF83B +:101950007AA64CE2F7D0DC77E9CF5D78EF5EBAC2C9 +:10196000E8FEE84B0ACC06395E5FC4D7A1B3321655 +:101970001B85FCE5D228AFB6337A9B0DED7AC917EB +:10198000A347A9F4DD6A9197BE7A7229F199A4E37D +:10199000B905C157916E36025F3C49764E2C309D99 +:1019A000F0E32AC7FCE3C795581DB73F2C2ED42F70 +:1019B000A5269381DF8A0B38DDC812EC52B277EE90 +:1019C00010B42CF57D5BC4C630BFFFB7E766A5A396 +:1019D0005DDA9627ED3CBF0DF1B55D09A417E1383E +:1019E000FFA5D2BEEFC5D74E34E0B86D302FE4DB93 +:1019F0007B7EEA588FF6499BCB4F7C2AC7D7DC26E3 +:101A0000B11EBC9FFD16FF2BE86F8CBBF97D4447D0 +:101A1000A65C6343FA87F74CD8CF7BADF80B1AD896 +:101A20004F0DF90716BA66CFC0EF16B1E02AB46BB6 +:101A30001775A8867B17EE11F262E1B914164DD81E +:101A40001F2C9CFC2D3A37B6F05C1A8B82BD758F2B +:101A500038177D8F3857C40A383D3B44E915E5DF18 +:101A6000CCF7BE24BD95F9CBBDF339DFB302E8B79F +:101A700049E9B114C1101BA7FC9ECEEBBCD7EA62AA +:101A8000D192047807CD73048B268CD3FFDE391BEB +:101A9000CD67607D39FD0ECCD7417878AFD54B78D6 +:101AA0001CBEFF91063C0EF43FCA80C7C1FD97D013 +:101AB000F8EFB5967E49FF1386E95F37C03FD0EF58 +:101AC000681AB7F7C8FC1FA702DF1D89DEBDEDF954 +:101AD0004AFC1D332BFD7E01EBEAACA673848F33E9 +:101AE0003A677AE7E1DFBD83F99A77EEB2F8708C56 +:101AF0003E737CAE6F083D339AB9C2789F972CC76E +:101B00001714D37C929FDBB4880BF3326DA59A0B2C +:101B10007F1FD1C66291BB71DF5269233927E3422F +:101B2000B2DF3FE5A9F23C3BC907796FCB12919731 +:101B300057EC085E81EBBED4D4DEFC13F8F683D2FA +:101B4000363A37CC989BF633326EA3E12FBF15A3FC +:101B50005F30C0F0FCCD137A70067EF74310271873 +:101B6000C7512FD81DC4BCB50D62DFB8C11EF3FA32 +:101B700012E4E60D05DA57B317DA93E876D22FF7B9 +:101B80004639DDDE50807E2235F6C4FC22CCB7ED2E +:101B900011F776E9168A77551EA3FBFEE6CB7DFF8B +:101BA0009AE4BC8E7C37DAD132CE94867977686B32 +:101BB0006CE4F7BED5A7F27AFD7F8CA07310B0FF5E +:101BC000492D43F9B25FE5FE2011DF3A2BE6D067DD +:101BD000DB5840F9F7221FE46CF74B74AFE4D935BA +:101BE0006368FDEB5FF83EDD0BB73F97EBB1BE439B +:101BF0004ED263F5565F15DE5BB83F97DBAB9D5A5F +:101C000034AD22C17E5D9D574DF2F9E335634C89B9 +:101C1000F18FEF0A79B051FA37B578159E67F9B8A8 +:101C200032FA33D2A307ECF43B51A683BFABA2FB3D +:101C30002D375AE97701AA0F8EDB5C87FBC3348D01 +:101C4000F2914D07ED04CF9975FC7E2DFC16E55DF4 +:101C5000D3C191F4FB56F5A971CA276C4AF195607E +:101C6000DCAFFEE054BAD7FFE486710528FF4E646E +:101C7000EA0574AFF1063CF409F54363F9F3B517CF +:101C8000D37955E7C6D4E0507E10A98F92EFEFDAF2 +:101C90009F5BDEDB85F81967F3A1FC7D4FF1F1B89E +:101CA000EF2BF1D93AC515F9F9D27AD769FA7DBC8B +:101CB000FA8E776F62F4DC43742BF773C9E3D50BAC +:101CC0007DB5DF129F8BBF4B56BF52E05DFC4E626D +:101CD000BDA99C7EAF4FE27D63D23DB74F08FD2486 +:101CE000CB93AF69745F20D81105E81F3A79D84AC1 +:101CF000747672E3043AAF2EC7AB079CB8802F4FBF +:101D000064E813715D9F16F2AA7E25DFA7CAE7304B +:101D10007E0C7FE7307E48A5BCAE3E573C0DE3927B +:101D2000F23D59EF9F4FB74ABF97B53FF7455A6FFE +:101D3000A02786F4647AC1497A3AF4827517AEE72F +:101D4000C7952C8CFECFF05BFCF7C78E1CB292FDC2 +:101D5000DC779CEF6F07DD9FE68817E0FDA1A117F8 +:101D600046921CEBCB8FEFE0F6B69DDFABF846F06A +:101D70006211FFCD11F711E6A09DF7F9217B14ED5B +:101D80003C28299E1066BBBDF4FC702A43FF0F94CB +:101D900014CF63CA012FFDEE0C6B17DFC7E8FB3BC6 +:101DA0000B8263512EDF590CFD3BF0FB53F4DEE751 +:101DB000A38217520C8AB15C315E2EF59B1F2CA4B6 +:101DC000E7CA675EFE7B2AEDA23D46ED216BF0621D +:101DD0009AC7AF9C6CE710F3FCAAF7EE1D2D1841D3 +:101DE000EB28E1063C93DD988C97B30526F17B3B0D +:101DF0001C1FC974D9BF9E5F021FFA5FE8BCF621A1 +:101E0000BE8EEBC659B81C593B81EC63D69662C8AE +:101E10009F5B7188DFC3D0BBC149EBDC67F63F84B1 +:101E2000FA28FE8699F17BEDC022403FC5E4A1F976 +:101E3000E523914FBF642DCFB3FBE8D1F70BE63913 +:101E4000F05CF2FB8673C9D25F089DA4A13FC6E196 +:101E5000D3D3E697717B5D25F8F8EF7A6D34EBF418 +:101E6000BB6BE10DE3C81F71D2A21FA4DF875B77B4 +:101E70008109E94A2D17F277139F9FBC2F4BDE7B18 +:101E8000958C9F8AC262927F4D2C7833DEA17E8230 +:101E9000E959C26146F7FF917BDF8469889A9FE226 +:101EA000B6AC85F4C2E07BF62C5FF2BB6CFFBBF5F1 +:101EB0002A5C2BF4EF9587D350AF7EE0E2FB463AE5 +:101EC0007D8F7A5DE5F36CC30F30AF8305A6144EAA +:101ED000A27692871F28BC5DCAB941F3477AC17EBA +:101EE000F03DE8EB9A42EE7F63AE0C71C82B6CC1FB +:101EF0003C4DA99F428A66C273F3A7DC7A1AD2E3EB +:101F0000A9B5C5192B300FC6AD6725DAD5A1A38CAD +:101F1000CE8BEB78DFF8C5F8FB32FE89E8F7DB9F64 +:101F200061F43B24C3F3E4B49EB989ED730AB99E0E +:101F30009B5F28F699854CE45726E38DAFFB62B191 +:101F4000EE6A79F072DA8726BDB7784BBAA087A41B +:101F5000E7EDCF7F97F2A01E36DE1349B15F18EF91 +:101F600083572C61E5422C5328AFBD611397730D45 +:101F7000AFCE2CB98BD7E95E85693BEFA1DFE35982 +:101F8000B0EBCA12C6E516AD83A4C70505FE12B4B0 +:101F9000E3E25B5517F245C31695E051CD3ED756A7 +:101FA000787E7A8B99ECBB0601CFE9BC601AAD9BB9 +:101FB000C6340BE0FDB4164C23FB75ABF8DDA1A4D1 +:101FC00079C07B6F6A1543E0C7C6D799F0533C04CC +:101FD0001DBC61A2755A80BF0B8970EC54C8BF79D3 +:101FE0003A3F7833D64FC1FE1FCFE9AB9B96D07DE9 +:101FF00036C9F83E6D0B127D2E16F391F84C1E4734 +:10200000E2B30FF189F6D22B5348EF851E5491624B +:10201000D98BDD9FD2BE7CDAA12BDF998ACF3781A5 +:10202000DDA2A39E1DF5B36FA39E5BA3528C7AFE27 +:10203000A1E22C96A4AF71FF39FFF53969A6043DE2 +:10204000A93EC8F1A43AE7A42DA4F7CF7E1DE9EB81 +:1020500084EECBAA4878EFF1C2FEB88361BDEA37BF +:10206000FD210DC769586FA679C975E9C379A07CB0 +:102070006B4F8D20FDF7E5C5A95FB94EFDF48DEBE3 +:1020800020E909DEFBAF429718274CF2E85451B023 +:10209000CA37049D2C7A00C6C5FEB638E9FED2F3D5 +:1020A0001D57E2A37FBD055F531DD7714711F9D1BD +:1020B0004D6F6874C8E044FB5505C8C7F5A02FD024 +:1020C0006F51AFC4DFA17B640F59E91EE6FA4DB72B +:1020D000DC8CE3D51FB79AB0FDD4E1AB26125C4986 +:1020E000EB0A782A188ADEFB8AE205BE04FC813DF1 +:1020F00041FC2DE7930037C101FB29BA8FA8AF0837 +:10210000D633410EBC59C8ED2E78DF6521FAE6F7CB +:1021100061F5CFD795345F57D27CDF6444DFCC17AD +:10212000A4F92C78DB6AC2E70BEEBFB604F73DA733 +:10213000D64DA7799DCAF04F44FE3A5500FD0F21B8 +:102140002F17DC0FF32CFB0BF36CB7D37A0D3BCFBF +:102150008CF80EF617E6F989A04339CFF7343D0D18 +:10216000F3F943CFAA0CFD2EA1FCC0C6A9BC4EBFFB +:10217000131732737A086D4AA57CDFDE6EFEFB040E +:10218000520EC078E7490F26A28753D5FAE6C9D088 +:10219000DFFF073F3717B700800000001F8B0800E4 +:1021A0000000000000FFCD7D0B7854D5B5FF3E73D5 +:1021B00066269364924C12088140983C09908449A9 +:1021C00002888A767804D1020D4F798993071042EC +:1021D0005EA0B5696BCD4002A2450D352A5AD401E7 +:1021E00081A2A20D0A0A15BC032A6245C5578BB607 +:1021F000E526405179C6A05EAEB5D7FFFAAD7D4E5B +:1022000072CE9054DBDEFB7DFF7C1FDF669FFD5AA4 +:102210007BEDB5D75EAFBDE7C23DAACBEF16E2E4DA +:10222000DD056FFFBC17A5F7AA2E81FC58DFCD0294 +:10223000F98FC32CFE144A938BA670FE659B6BA589 +:1022400022C489A6BFFD41A1FC857D36B7A0F20B53 +:102250002945F7CE467E8FEA5A41ED2F0C689F251F +:102260008673B9D844E5EA5D239A502E1E1EE6CA4D +:10227000A0F2F20D61426409FEFB56687F23E93B40 +:10228000520BA56B556F7834A54D2FFD44C9A56F32 +:1022900056378F57F3AB24F7DD347EB95558EDF937 +:1022A000A8DC9E392D4788F37B6D1303D9323F2379 +:1022B00087CB3FB052798D5DF85AF87BAD7D6A0EC1 +:1022C0008FE2B6D2388BA90F914AE9FA18EF60EA8B +:1022D0007F318D9342E37D8BBF1F5C0EDF0ECBE71A +:1022E0000B8AA89F7B6D62F673D95DF5F434DB4DE4 +:1022F0001DF6466D7B573B558825C63CE1A122243F +:10230000BF14794757BE32A4BC2AA47C47BFCFA7CD +:1023100014392F1F7F03C61FD185C7120D8F3B2C89 +:10232000F41DEB728F12D844FF2DB1BAEDCB09FE2C +:10233000E7C6889BD14FA95538AECD47BD0E9E5FED +:1023400089553486E5E3BB87EBE9F3A6FE1AC3E2C1 +:10235000281FD1CEE353BD8976439EDA9BE09AAB2A +:10236000C1A3A74BB785BB4EEAF3A07F552DB1A6FD +:102370007CCDEEBEAE93067C2FC57FFAD2BF49342A +:10238000FB91C08BFCABDADD7A3092E8A74DF1CD42 +:102390007553BF170E7E1D9DEDE6751F5944EB9BCF +:1023A000AFA63E7F98E6DBBE47F56C42BF6FD8FD17 +:1023B0004A0CFDE79B8B0F6EA7EFD52FA789BBDDDE +:1023C0005DF30FC5E385DD17A353E9FBF943F60879 +:1023D000318CE6B9377EAC9DE862475C7BB778AF5D +:1023E000D5D65DEFEFBCB5357AAAA1DE79D11A3D1D +:1023F000CD402F25BB2FD68B5CC69F5FCDEFC2EFA4 +:10240000897DBDC7AAF4BDF4F7FDC65A28BD5FC3D8 +:10241000DBBD36F7136B096EFF9E30CF1682FBFCD7 +:102420001BB32D687FFE8D722DBDCDCBE95F4F2490 +:1024300063FC688BA4777DBC356E0BF7536A697BB0 +:10244000EC1ADA8FA5BFEB93D290D2555E6AC9CF52 +:10245000C43A6FB7B52F00DCE715B14689EBEAE760 +:102460007EB79BDB9FDFF3C963E00F27EE1D904F24 +:10247000644DF941B93E2A3FFF5141A68BFA3D7F99 +:102480004F5F0FF8C2769BFB36A6B7BBA23CD8F7CE +:102490007A7F18A716FDEFB962A40FE947125ECA4A +:1024A000E7FAE4B87E25BFABDF688BFBBED1E0174F +:1024B000BFB779B650B2FCEF697D62313FECE76E91 +:1024C000D6A1744D98709BF8C94A86BB4478EC221B +:1024D0004D960B03BD958922FEBEB0C9FC7D11F15E +:1024E000097C5FBCDEFCBD5C34AD6EA5F92D09989E +:1024F000BF0BDA3FFE04EC6BFDAFC55E14057AFF3F +:1025000036CC544FF835FE401F095F25B41FC1C7B4 +:102510009E5102819558DFBB549E67E8BCDE75A7CB +:1025200070BB8722FF6741AB615D8F5B843591F0A3 +:102530007ADC2E1C89F9E8470885FAF5EF0B0B6C5D +:10254000A126770FFE2AB9047CAF31C22208BE5BF8 +:102550005DE07C42ACD8F74932FA295D53E86D352D +:10256000C077C1E67DE8E7D4BEFD5DE2D754EFF861 +:10257000D840D35882EBF8DDAAA7A11BB84EAFB163 +:10258000884001E1E32E2102F1947FF293E4625A44 +:1025900097CFB67C925C62A47F45CC36D2A39E12C4 +:1025A00024BC3EEF61EFD2FC8ED35C309FD07A5DCD +:1025B000EB6B8657C767B82A6ABBA387CF40F7542F +:1025C0009EF5775578B1EFF7D902A0CFC88D5F3C63 +:1025D000380FF4B9D7E64AA1B16BF6A95E95E62D9E +:1025E000F6A8810C9C637B4F4457E09CD953E05282 +:1025F0000DF3AED9A316E17C39BFFB62426936F711 +:1026000033C5ED44FB073CA0DF9EE0F89B5BFDF784 +:10261000F89FD7CCFFCE657F907003F8C0C6539962 +:10262000E0EFC407FFE6A6799ECFFCC68EBC10ADD6 +:1026300023417F045FB49BE0BC10F82A5A105C8EE3 +:10264000BDAA37D0CD3A44A5D8194FFF327C130923 +:10265000BE842EF8089EA894115D7056BBDBED3841 +:10266000672F38A273C14F694293F212B4F3C90DB8 +:10267000FE5A3A49107F1DBF67E1CA70C80B4D8AE8 +:10268000278CBE97ED55F9DC2ADB1B19C016183FC5 +:10269000C8C9F9D247D54018E527A8A3FF309BEA5F +:1026A0002FBE47F5D08E14FB37DEF6071BD6758399 +:1026B0004DA01C88035C4B34B896ECFDE1670A8D95 +:1026C000B378DF2D0730CEE207140F17A8F3EDE83B +:1026D00077C9438A88574067B6E3463A5BD864CEE9 +:1026E0002F12AD0B5415FCC1FC9DF09E5C41FD9674 +:1026F000EF0E73DD8DF102A1E542BC4AF0D468FF14 +:10270000CFCA583BF700D5CFDA68673C9C0F17E279 +:1027100008F6ABB53541200DB626631DCFEFF96B3A +:1027200032D6B1E677FF9529BA59BFCEFDB437AAA4 +:10273000D7A94821AE4E51C4B7A9A0FB8B538ABA82 +:10274000A96F1B20F7C5369BBF9F87CA0F6CFC8AF9 +:10275000F9C1853DBE81AE6EE8B76BBFFAC32D8966 +:102760004883E102E9F016D70DD827240F62BE3561 +:102770009B564FDB44F9F0976C38B9444D8693F77C +:102780000BF6C74243BFFA3ED906BE807484E40FFD +:10279000B601F21C3DAA9D7BDBF6774CC9E8069E8C +:1027A000A36E1BD7B30D105CEF5977D15CD05B845F +:1027B000C51F0DBE2DBC5E772FC2B3A2D157435D9E +:1027C000AD82EF89A289D3FEA285D34785F0395126 +:1027D0005F785CC0B3100362813FDEF38CCFBECC68 +:1027E000377FACAD217835E8C41F2B025BE8FFEAE8 +:1027F0004687506320EDB546A35154CEB4FB065234 +:10280000B9ED03D5A240DE1DA0AFA7C785FDF7A592 +:1028100073468C71FDF61F2E9988FEAA76A9228C2C +:10282000FA3BB7D326824ED4A7FD027C1CFEC29E83 +:1028300002BEB4571190976B288FEF35A3ADDE80A1 +:10284000012F77A4D8180FD52999F29CB67A0F4D8D +:10285000A27ECFBB4AEC90EB6D87CB26E2BCB125C4 +:1028600096D801D7FEC3631D2958B7582BEF9BD5C7 +:102870007BF5718FB8D07F54EC070C6F63B645447D +:1028800053BBC6A3610146A643F2A1300DAF8DC173 +:10289000F10E7737EBE317E393C4282ADFA94E0440 +:1028A0009CE75C252EACA32D96E8EE0A6A6FF34EEA +:1028B000BC9AFA0D8B8D8B077C6B52D2783DBF8A08 +:1028C000AD6538BF22F1C2CFFBB7B608F9C6FE65C9 +:1028D0002AE3BEE921DECF350E397ED43E95CF51B5 +:1028E00071A543E3DBEFBB4A699C05C9BE47410FB5 +:1028F0009DFC6DC4AB02FC39CB6261F9ACF135E7EC +:102900005AF021BDFC6C8AA4377D3D56F5B2BAC0A1 +:102910003F1ED5E87395ABC8916F98A7ADB745C377 +:1029200057910378DA612F3A84F3A59DBEE3DC3C2E +:102930009038CD013D85EA59D0CFA97ADA3176F4C5 +:102940003BC301FC2EEA553201ED168BDAD5D86F68 +:102950008BD7AB2268E0AB8D3639EEA24B11221833 +:10296000DF35EE225A3F6E7F295A04E9DC6D0C9761 +:10297000F51AA3E4FE792345EE9F0FB5F9B469F982 +:102980007F99AF7BCC7CFD5CEC1FB69648FEFE4683 +:102990000AF55BA5B44E48A1F9AD4EECB003BFA754 +:1029A000EA5D22986980F7B279C68BA061DCCE7AA5 +:1029B000971C3C9FAEF57033FC5DF375321E4ED50F +:1029C00027321E7BEE3FC984C7AEFE534D78BCBC98 +:1029D000FF4C1EFF547DD677F43FB487FEDD26F80A +:1029E000BBFA4DE771C56EDF40F0973B5DC40F98B1 +:1029F0006E885F50B95DF13D7E35E4DB8FC204E443 +:102A0000BEAFC27D835C06FEF00DCE65D6E782497F +:102A1000E0B77ED1CC69CDEE8B13D0DE4D7C01FBCF +:102A2000492FAF11ED0C27F885E88335B4BAB97C8E +:102A3000B76F10F4221D8E4E79E675A7DF42FB209A +:102A40006CDFDFA3B18F2F58DBA778286DD9AB4699 +:102A50001AF7757CAAA4A7B103BEC86DA5EFD56807 +:102A6000477CEFB697970E027EAAC3DA7301F7810F +:102A700097FF968B73E4AB7D4B07E2FB36AACFF250 +:102A800087BDBDDA63E82F5DB8FC96515DA933556B +:102A9000EEFFD0EFDBF635F4031CDB89BD09920BAA +:102AA000ABEB2A0A4EC6830D79EF07FF12C4B75865 +:102AB0001FDA3D5D1D03F9EE439279283F7C8F9428 +:102AC0001B860F10014B0AE4BE0F67834F548FB073 +:102AD000BBA00A47E41D61793B6284C3A550FDBFDA +:102AE000F797E3DB212FA4A17D613CE8F9CA64F1EB +:102AF000EFC96D1B42F64FF0BDEAED345E95DA3A50 +:102B0000659CC2FB283F157CFBAD2FDED6F4D704B5 +:102B1000ACCF019C6B04CFFB5A3F65A9BE2B50CFB5 +:102B2000E768BDE70AAA377356DF64E847C59A7EAF +:102B300026261152AE647E94033BC8E5E7B6D483E3 +:102B40005E527C3EE0C1DFD7E1C1F935344938FA45 +:102B5000125E456220751A8D3B21D5A2DB0F14C091 +:102B60003D449BE333FD5A96C7F2391988031DFD96 +:102B7000B3E34E4BF54E06FC7AFD0F67CDCBF175F6 +:102B8000736EE8F2BCDDDEB20C70B65739597FFCCB +:102B90000045D4EE89596141351A7A8A730DF4F9EA +:102BA000A3910B0EF6267C8C8FF2CD43FFB36FBC46 +:102BB0007E35F2CA8178F772D07371EB48D6EFC2D6 +:102BC0007D37A3BCD2E11B9840533C37C037280661 +:102BD000877C51BC5C27519453D42DFC129E6245D6 +:102BE0008EDF18E52B473FC596238F5D816FD62377 +:102BF0006C6F108DBDB99F737651DE9DFCAFE3E124 +:102C000098368FFD3671ED259ADFFE75319E06826E +:102C1000B7ECCE1B17D450BAD0529410544D70DF7D +:102C2000964A5D57FA8B07F62579EE9C4D83BB4E8D +:102C300083DBEACA34EEE750B81B7479E5170AEB78 +:102C400083FC47F917FDB181BB291F66B9F8C17430 +:102C50009C5B3916B6936C88A0BD457AE43B1A9C00 +:102C60008FD2BE73C4F1F735F89E1821DB273E687A +:102C700009C07E5034760FAFD313D54E8F4A6315FB +:102C80000BB71D7250A9F0B2FEFCD7317FDBD74ADB +:102C9000F36A4EF5DD07BCDD1C6F49FE80E1F00DE7 +:102CA0009D0A796BB49CC73F9037791ED384CBC6FD +:102CB0004299586B81FC31CD25A7B25091FB63BA84 +:102CC000F0DA30DE4CE1E37AEF9DB77BA14FBC0731 +:102CD0005D88E0BE51F8F9FB1C11E0749E0872FD9E +:102CE0009B442BE7757C137DDCDC4BD2C7277D54DE +:102CF000C6FF56C0FD6E64EE803A9AC7D48706655B +:102D0000B07ED5DC9BF1F35D704FD5E886F6EF6FB2 +:102D1000B18ED8BF33A89F693784ECDFF1BDF5F5DC +:102D2000CCF847FBE84847A7FEE4EC4B78B84E5B8D +:102D3000D2EBBC4B597F12C2C5F2D18FB47D5BA8D8 +:102D40003A452F5A9F236ED297089689639625623B +:102D5000BEAFAF106F15D03ABE3E46150D5CD3CB5B +:102D6000EDA668FD4DE93FE133D85B0F8B60AFE125 +:102D7000D4AEF092EFD518827B8ABABD3196CA27BD +:102D8000F627BDC6C0EFAEEFB5C30AFDEE8674F3FD +:102D9000F749D966FD67B2685231FE94E1E67AFBE5 +:102DA0008127A2B3F753A5FE22868821DFF27A0B92 +:102DB0008B713E1D932EDA2F101C1169BE8FB12E20 +:102DC000CB27FF7501C61556399FEAB755B6EB1DDF +:102DD00027798B28509CACA7932253CA25C87F4AD9 +:102DE000F203D2D3F56E4ECFD2798FF2F3F51ECE29 +:102DF00017A4159D40BF256B3EB7627DEE0C97F87A +:102E00002E6F699A00B02A76B71C445A162C9A8005 +:102E10006376D1A1DA8348EFECD4DB6A59BED3E103 +:102E2000BE45A3D35BA2A6FD3087D6E1963DAA8717 +:102E3000F303A64D9FDC0B791BE77BA2A3AA4B44AF +:102E400033245754ABDE2F0197776FDBC1789ADFBD +:102E500027F5A318EECFEABD0CF799FA899C4E4AE4 +:102E60002BFA1BE8CC2B3E67796CF2F6366B12D549 +:102E70002FF42A5EECDB6BBD2210A0FDB7DE26CF5F +:102E800081F5740E601F8FC999F6E8AD027CDA6790 +:102E90004BA37166DEB0A410E34C19556C45BD1B05 +:102EA000BF211920A58B4EBF8BEEF5F95769EB7644 +:102EB000EE6585F1D8B1332D0672C1F25D697D9062 +:102EC00012BFD4F5DD48E0ADE39285E1EC381AC1DC +:102ED000FA86DE6EF9AE48E63BCB07D803C260B790 +:102EE0003C43EB2C0CF2E699677EE2369E2B67E2C0 +:102EF0005ABEFA18FCED2F92BF916473EA11F0BF2D +:102F0000FEFD3CA093F39A9C4D7A4624CEBF6ACD39 +:102F1000AE08FE84FC990869CF1DF96CD258EC2FDD +:102F20008C471C4EE8FC2BF3D987527FEEEE1A6FCC +:102F30005BCBC28F1FA1FCB980C56FA3F3E99C686E +:102F400039FF3BF0DFCD4EB6EBDDA9103C387FB743 +:102F5000F4E37C96628DA8C3F92B02BCBFB314B70F +:102F6000B58EF855E5730FF703FDBD44381845E5F8 +:102F70002FAD8B647EF692CD73AC0EFD3D2AFBFB2C +:102F8000CDBD3F3DBE1BE93D55F93FC5F2A4C5315E +:102F9000FECB7EB56408DAD3F92EFA527F4FBFA874 +:102FA00004C3693FE734EF5FD997E01BB6A1CDD2E8 +:102FB0008FD2BCCD4A03D2A1036E3804BBF30D6996 +:102FC0006E6E5FB03D454DC236EC17F8F8077CEEEB +:102FD0009BE581ECE6CFC7F6135D72C110A5E5F461 +:102FE0004682352CF968BE8FF1D7C4F3D9B577FA8C +:102FF000FBF304E6411207E02EB67BF81C0AF83713 +:10300000623DCFF9B23CACD715F91F069D9DF32563 +:1030100078702EBD407AFC55A87FCCCAF37C71F342 +:10302000BBD1B0EBC4907E1C0E7F485EFB04D4AFD6 +:103030001AE0167E6A3FE0B1EB26023FD53B776D82 +:10304000E47E2A1D1EE8B9E5BB2E1E4C829C78BD8D +:10305000F064800E77CAFC2FC77B3D2A4DB57CE318 +:1030600097327FA488F345A4755A51BF54CA470FBD +:1030700069E79F68CD65FEC8A4EDEE5AAF5F523197 +:10308000CAD7A7F8FBC2AEAD9F9B74DE55A561AB56 +:10309000D865FB2363E725335EBEE77967D7CE2D7E +:1030A000BDBF87ECC21F4EFDC06C033BFA06BB3CA4 +:1030B000A7B7107F01BDE8E7348DFB0BEC5F6AEF2B +:1030C000053F4D52959C9D848FA487C258CEF8BE73 +:1030D000E3CF8E59CDE7B62E67D544483EC8670585 +:1030E000B55F18E5BB0BF35BA89DF3C2EACE861C67 +:1030F0003223CA7B37BE573ADA9331073A3FEF455E +:10310000BE5A25B92BCD207739E3BED7F95917E53B +:103110006DC67CBE6FFDB19104670C525DCF22ADD0 +:10312000A35B7E9CBABD05FCF88130C98FA30A98C9 +:103130001FE9F30BEDFF15DAF73EE233AFD179E289 +:1031400023DC8F738EB1F27ABE6AA93C48E770A186 +:103150001C01846C8D1DCE796F14E16FBC5315BEBC +:103160006EF4453DA5F57A1EF899D02BD254AFB038 +:1031700057AC1DFBF7FBCE5BD5D6478DD0F9A9BB6D +:10318000977076376F39CF5BC247F4015EC62ADF8E +:103190006FBE0E5BD141ACC338671E9F8BE39C535F +:1031A0008FF904C37F18DF43E7193A1FE1F87EF275 +:1031B000D28F15E1B760FF7D6E67FBDA5E5BEBD304 +:1031C000BF257CEE5D92ED819DE805F05EF0CF6855 +:1031D0003BCBB37BA3841F7C65EFD48400EC452FED +:1031E000414F04DFE82D6479B8ACBF770E95537F6B +:1031F000FDC2685FC05E342F42EB9F0646FB157D23 +:10320000B87D8352FB660EDAAF8864BE733420F952 +:1032100078736C709E4ADF9B3FCF14A8775404D616 +:10322000A4A2DEEDD25F43E54935D46FF3922112BB +:10323000CEFF51F9DC68CEF3F68D73321F67FB4C7D +:10324000F3546F5FF8AF7A69EBD5BC5196F7833DC5 +:1032500014E52994A7F4639BAC3F57ABF7914697CD +:10326000B4CF990FF8A6445A41E7FDD24BC2D29988 +:103270002979FBC2EFF3485906DB28E7565C9FC269 +:10328000F4A3D9CB666B7C5BEF0F0D1C23212FCBF6 +:10329000BF390BB784839E679687B741EE3B5ABE12 +:1032A000320A7AFB4C9F1A0C835C39A3D0DB29AF1E +:1032B000A5625CAF1CB74CD7FF82A5C0EBCBED0E6F +:1032C0007137CBF7C102A33EA5AF6F55CB9878A35A +:1032D000DE5C6127FE42F02CD1F66D9AD3D73B7DA0 +:1032E00004F4E9EBE38DFAF4A7650FE4F2FED2C62D +:1032F0003B5BEF8D3F990EB96D22A7FA789D7A0F4F +:10330000D64DE757A097DB25BD086BFB478B29DF20 +:10331000307B8807F6EA89D31C4C6F1D2DE12C1FEA +:1033200037CC8EF0C26ED7B02B8CED06376BFB839B +:10333000F428A61BFFBE28EEA7D22EF395CF65304A +:10334000DDBC600F3CB915E52F87B37FB6325A8ECE +:103350005BF9BB248D2EBD29AB7AB15F8EE9A53216 +:10336000C21DC3E5BF8F677A7A36DC57007C127DB9 +:10337000B25DBCD21ECC8C25FC1FD3E80F7A23FB98 +:10338000F56AA3986E8596F7FD3C9EF538927F7995 +:103390003CDF7D4339EFB37BFB2EC43E5A1EC9F0A0 +:1033A0001C73C9F26395B1BC0FE6DFB7F430FCC5FE +:1033B000C78AECBC5F8EED5559DEFA739D1A849F67 +:1033C0005BA7CF9A25C7DF86F9A8BAE1A3E4DDD4CD +:1033D000CFFC955593D06E7EC5ED5370DEF69AF610 +:1033E00029FB6943F7F3FC4AB37FD497EE9D8CF930 +:1033F000D56407761CA47E1E9C736A11D6D39FEEFB +:103400009B86F53E6F6F7DE14F0477EB8A3FB25E9E +:10341000747DB46F26BE5FD8F31BAE5FBDF2BF16DE +:1034200041CEAFB64A7AD1CFE31A8D7E45866F1E64 +:10343000EA57AE7C9DF581C8EC23927FDEFEFDF855 +:10344000CEE9BD5B5E50A8DDD288BDD59CAA815C6B +:103450009C6B679460B492067C4A3DEDAC2B188D52 +:1034600075F159A49CB8745B881F184B91A0D97F43 +:10347000A8DDD21619BF42F2821DF4195A7F297DA8 +:10348000E77ADFF37B856891DF6377DF7BB55CF7F5 +:10349000607038FCAE199BB0EEE776FD26D3E87776 +:1034A0000D4D2F8757CEFFACB65FCEEAFB65B6BD9C +:1034B000D35E00B9EBFC337D4C7476FEC9C19C3FF2 +:1034C000ADB42B114A977F57785A46727C8DB765F9 +:1034D00024E4E707B5EF4BE35B4682AFE97C4E3867 +:1034E0005A7259FFCF6AC985BEABF34751D492C90E +:1034F000DF032D9968FF8245DA53F88FE0A8783A08 +:1035000069E3DDD20FE1B70C477EE826E4F5711AD6 +:10351000C2251FE969BE8FA54B3BE6F939F69BBD75 +:10352000547FD07ABBA97C70C09CDF9A2EEDE70354 +:1035300043E26FFAA9EDFBC3708E3C21BAF5D73F89 +:10354000A38DF3D4539D713CAAA6CF0AB74E1F6E2C +:1035500029DFDB80EF8F3AF17D6B12F1E5A59863EF +:103560002ACF5F9E674F49FBCD0B79BE249C17E79E +:10357000811782FF8558CA6743BE9278D5F33A3ED9 +:1035800043E7BFF2A34549B0DF7E94AEDBF93C7D53 +:1035900040973ADE1A6CA4EF64433F2E2F386985BA +:1035A000DEEC492CB31AECDAEBF31CD8578B37E47A +:1035B000398C74D6B0ADE010491CE2EC36AB072074 +:1035C000375803F7427E6FD8A6B6F805973BBC5430 +:1035D000FFACF3C0DBA8B768436C3EE46DBDFDE211 +:1035E000F52312CB0C700EDD665E879C16737ED8B9 +:1035F0006E73FE04CE80DEFF7CBBBCA0395F70C85A +:103600009CFFE4835B67819CCB55FFBD2AF4893F17 +:103610004D3884F3F1D3175E8CC6FA2CFD4BD9419B +:10362000E849A17122B46E0AF408FF5685E9E3B2B5 +:1036300078911EF8811E0F819D61A4930AE13F6875 +:103640004DB9BCFE19D132CB4B745559B7BCE064AF +:103650004157BF57B6ACB343CE0B1DB7A7FD2F9C48 +:103660005E37EC6AC5A364D9557563C509F82DD6D4 +:10367000BE3B01F457FC4B85E58AE2E707BD0ABE75 +:10368000DFB663CE0D9CCE9AC8F8D0ED7D8BF72ABD +:10369000C128CABB4649BA5DB85E617DBDA4D11CD4 +:1036A0004757B63624DEA6D95CBE78F7FEFF869F64 +:1036B000BEDCF118C7335C1E271878057A5BC5A7F6 +:1036C00082ED3D159BBF0D3397CB792DD4E7E1BF3C +:1036D00096E3E1AE92553ACFB793C8D0F9F04B5785 +:1036E000516A06E1FDAAE68DAA949BBDC5EC9775CB +:1036F000DA39CEB0CA21829104CFA128BBD745DFE9 +:103700002FAE8F6279615118C99FF99C8A708E43E0 +:10371000F4C4A0DDA977549683AAE2251EAA1E57F9 +:1037200002B0C556C1488AFC1332BF04DE2655D20A +:103730008FD7003FD6CD98174D526FABB406F70325 +:103740002F9DE7C03673BD4A9AE7D138C859E6EFD6 +:10375000D5A29DEBD7ECFE36CCF8DD60DF657D525F +:10376000D76B55C83304A77A4704CBB3C49823401A +:1037700057AB14EFC30E15299DE3A0EF254E962FEE +:10378000E66E94E747338C839083D70D66B967AEB6 +:10379000E2CD04BEC4BA70D6A7A9DC1FDE8BE564F7 +:1037A0009643484E6639AA7D8E9DE3129BF35A825A +:1037B00090C79A1F48F1D00A327FE4F3E89E7096D2 +:1037C0007B9AA74AB9A7795D1F6EFF3140EB0B3991 +:1037D0005AE2B9F99E1C1EB79F2ADB893E520F2080 +:1037E000B93A137A02C1E541B92E4767C5FA4AB022 +:1037F000EEFAFC9B63DBA3E0C712E5F1DF4B6ED86A +:10380000A29D87EDEBC203F0539C548A0E5A0CF62E +:10381000A95B32E4F93172AC77AB568FFD1965962E +:10382000A977FF80E0297BD0E26E48E95A07E1F5ED +:103830006662FE27D785E783EE468E95F6A7637905 +:10384000929F470E171CBF73BBD6EFED1916539A04 +:103850001841F448FD9C2C94F6EDA8E1456C07A4B2 +:1038600035BAB9BB38903519F29C2AB317FDFE9AC8 +:103870006EE0E9A48BF152DE3DB94CD924E1F2723D +:10388000BCDFC85F85B3FDF0A476DEE8EB4174349D +:1038900082CF718D9FADD3E8665DCF7463A28BB983 +:1038A00090B7413773E4B9D84957DAFA12DDF07AA4 +:1038B000B7135D48BA11E26BB42F744B793B44DF08 +:1038C000EAD4B77BD0B7880E9EC8E86DA817420728 +:1038D000C21A18F18FFC2C25A362472AB40449565A +:1038E000E147DC2CCE46C6D75DD6C04A82A7BF557D +:1038F000AECB00ABA43B3A65FC11F95CDF8BF8D989 +:10390000E2FB170B2FD52F4E126CB74A27F926264C +:103910008EDB09A47007AAB0E7508AF6C531B2FF62 +:1039200062A26FC4B3517F5E4B9CC6DC46C27F2A45 +:10393000587E40FBE87C6EEFB7C8F65E2BA503D33C +:10394000E43E6A5F15C6F82BBE734026E864D25881 +:10395000339D24664A39414F1B33DDBADC90087E23 +:1039600050D23898CF9986F0A2AA5DD8A7CF487DCB +:10397000A378F54D934700BE67E33DD8C2A7A7ECF7 +:1039800060FF4A49E39C1F7F083D655B387FDF98F5 +:10399000E97B0F783FADB817ECA20F25335FB12755 +:1039A000527B5FCBD473BFA3748A7FC7DB9023A6FF +:1039B000CC50B9FE1421EDB9A2518E33D9FFB935DF +:1039C00091FA9B3C5AE1F094B67057F232F855B434 +:1039D000F53DA6D17743B898FD9C13700DC84CCD2A +:1039E000861F8224D46EE4E401995AFD31CA06C8C8 +:1039F0004303C7C9FDA7D7473FE8372D53EEB7CFDD +:103A0000B47DA7E709AF5CBF6C4D585B5A34525B7D +:103A10007010A5F3B2C69E039F99942A26AC07DEC8 +:103A20007FAA8A4D0C6F7B31F385A84C37F8828FC3 +:103A30001459A6FB6D8399EEDBC6B4B7DD49F9B620 +:103A40002D39D27EA7E9F30B5D82E582B63192EF84 +:103A5000B56F8964FE73CCD51A1527ED5DACDF9781 +:103A60006A24F1D7BA867BE1372E75DADB707E2CBB +:103A70007C603AFBFB4B9B49BF475CFD5AB37E4FD2 +:103A80007A78586637FA7AA85E0E9A011D95AD5578 +:103A9000980E073678EC7D99CF292ECCAFCC194CF7 +:103AA00007FF2FF384735CF0657AFB3784F791B0DE +:103AB0001F0B0EBA1A3AC8D70BE3163715B37E1A86 +:103AC00099ED63FE355025BC101DCFD4E86F12EC84 +:103AD000A0E04BD6D6BED897AF6568DFE35C994EC1 +:103AE000A6EB70BE6FD066736502BEB655E1169C3C +:103AF000B793564AFAA67DE7C0BD80BBAC2202FC54 +:103B0000E0B8D67EFE0A6BD146CAF777086B541C24 +:103B1000E82B8FE93B90E5FB0CEBF7E92FC428C8B5 +:103B20000DA56BD749B834FA10D623E3E3699C4F4F +:103B3000B7A4E4C3AEA0D353206B6C76E608035D54 +:103B4000CC50981E683E87609F9D9755928F72FA61 +:103B5000BE1FF432696C301D71D8856A25C7AB76FB +:103B6000240A0FE2873A443BCB231D248F803FEA8F +:103B70007C46E72744175E4742D77AEB7C656B3D6E +:103B8000814678DE56EFE0F4A97A97B0124FD85EFE +:103B90009FC8F967EBDD9CB6D467F1F7E7EA3D9C77 +:103BA000DF593F8AF32FD47B39BFBB7E22A7BFAB3F +:103BB0002FE2EF841FE64B3ADFD1F9934E5F3A9F35 +:103BC0000AA5AB058466DC33A0F6CC0F753E887978 +:103BD00058F2BBF893BECEA94A913F11FC50B4CE27 +:103BE00001FF2854CF3EF322E1B9A3DCC9F1A11DA6 +:103BF00042F2C10EA783CF8D64BBD80DFB40C33208 +:103C00006FDB9D8673785EB922AC06BABDA9365CBF +:103C1000580D747D735DAC293FBFEEFDD7FA50FFA0 +:103C20003F8BF12DC2FA1CBBE3D4A37FA4EF8FDF3F +:103C3000713A03EB4E706C7908E3DE1EA1C1D12A04 +:103C4000E1BADDCEF2D2C008A94FE1CF6188732D71 +:103C50004E897DFB3704E7316D1D06DA5DB346C141 +:103C60002EB34A75ADA42A1F63BDE8FB9FB5F52AA4 +:103C7000A90B637C96346AFBD418FF4CF83CDE57E2 +:103C8000B05CA77885801FE9F82FEC419211C471D0 +:103C9000C51150681C8594ADF9B017AE79FD28E4C4 +:103CA00074A5EE10CBD53E8793E32884DF76D6D873 +:103CB0009F527790EB89D6FEA638C8C8E15E3BF8E4 +:103CC00005681BEB56927540609F8B2685EFF1943B +:103CD00069DFCBD628A6F8E27B3355E68B8732AC7A +:103CE0009C0ECA149A13A589CF299D5E897F703CCA +:103CF0006359539E7D91812F9768DF4BB32CA67833 +:103D0000C74319322E6A109805A57767A5DA1732CE +:103D1000DF7373DCBD5EBF242B7F75EA70F483E82C +:103D2000A0AEF68F645AB9DDA10C9784C741E7595C +:103D300014C7E9747B2EE872CCA7F8EF950C3FEB23 +:103D40005915CF3EFD2CFC7B157F0AE3F3A9629841 +:103D500066DFC80E8C9CCEF28FD7A98C84FC2DD741 +:103D60007FFCD37F89467C54CD4E6957A5B40D693D +:103D7000F5EDE56C57ABF6D0FE88039F35FBCD5FC4 +:103D80007DF64FD1ADAC97F893B4F85B8EF7AADE11 +:103D90007982E3C0F4B8AFD07635CA37ACA7EA7100 +:103DA00001BA3FB6709F8DF74DCD1E85F5989A5D8F +:103DB0001713C0E76AF6AD4AE82E2E27B45F3D5EC2 +:103DC00040B7BFD588B59FC37F4884C3F80FADFF08 +:103DD000766654AF53430562D5AE603B8855701C80 +:103DE000C7722D8EB32390C17EE19EE4ED9AF5C497 +:103DF000F049BFEDB0BA6310AF7C418889DDAD53A7 +:103E0000FC20797E9FA37D04BFF085ED2ACB91171E +:103E1000B647F17EA8DE7EFF41C4DB556F56D88DD4 +:103E200057258E30DEAA77AAC261E00F35B00BC5E8 +:103E3000F70CE7D2A7A36A415F4B5A14EF16F8AD0F +:103E40001DEE98DE0678DA35FA5A1AD63292D74540 +:103E500083FF14F89A41CE5CB2F77E8E13A47AE702 +:103E600059AEF96D24C7B3510F6F03CE331B0AD877 +:103E70004FBDA4654735CB05DB235D10694EDBCC18 +:103E8000F729BED1C6FB4693D3CEC04F82F6CFAA48 +:103E90002C0F034EECCBD35A3CABDECE3248B6B33C +:103EA0006878FB0DF6E788AEFA4B5ADAA2D3A9FE82 +:103EB00027BBDFE7D43948EEE325CE23B938473FA7 +:103EC000D919C9F7ED3ED9F9EB092FD178E75AC6D0 +:103ED000F4520CFB6CE0201BD73FB741C601F32521 +:103EE00011D60F5A783E67B62729AC2703DF849F87 +:103EF000333B9F8FB6F03EF6FF7B71ABB3156BC8BB +:103F00007D84EBB24780FE5BB5FB11ED9AFDE57F4A +:103F1000A7FF6AED7B9B52A48D23EF3B083D0EC2A9 +:103F2000A5ED3BD5C9FB6E79949DEF2F2C18E6BE0D +:103F3000711EF8E89B328E51F4773F04FD6FC13B50 +:103F4000F16C6F596E73F741FE8BC336F6132C2854 +:103F5000F01CF5A17E8C9DED4A22B17504ECAD6D8F +:103F60002952BEA85C433B9350DC8FE8CD4FF8ACA0 +:103F70000C58848FF29307A5F2BA3E526EF1DAD94B +:103F8000FF13E4FB92C7ECC28F7B2FFEE7A47E5D9C +:103F9000992AFD0E8F607F515A1917CC8C87DD4E00 +:103FA000A39BCA69546EA09FCA4DC14CC84F67ED10 +:103FB000D21E8972E84D95F9B25E8346A7E807FDE7 +:103FC000B6A5B8CEB3BCBB2B4A40EFB0BC1825EDAC +:103FD00021BF09DF146638AF6F1A24E9B841F3072F +:103FE000FAB748F80017E4F825F6A64CC8B9FAB8AD +:103FF0004BA29B78BCB3DA784B229AA4FF448BC7C0 +:10400000437D1EDF26D8BFD3FE6418CBCBA7FB1E93 +:104010007901E39F7E7230C711B4A50416EDE6F274 +:10402000708EE3AE782A2C08783F7B328AED589F59 +:10403000D9A41CF6595402CB6187A21E5C80FE3ABB +:10404000368729E0A39F29C29E88F22DBD590EA86C +:10405000A8AF633F4905B117C8AF944E84DCF7D9C8 +:1040600096C16C27FAEC0D952F29D0F735F8EE1391 +:104070004D0B7EC6F2BFF43F9E7EEA6F83BBF3AF6B +:10408000546C36DBC3F4F5D7CBEF1824ED03770C73 +:10409000927AC9CA412EE97F8B6C793095E729F96C +:1040A00003AD03EB7FB41F13606F3FD6B22741719E +:1040B00002CFC1CC5F03EFDBA49E757ABB8DFD42BE +:1040C000152F4679D9FE74E7157CEFB042957278CA +:1040D0008545DEDBABD0EE99564467B27D8BF0CDE3 +:1040E0007A6DFB16551B478EFBD9D601D29F10D493 +:1040F000F22FE4F03DB84971E2E6692C5F6DC80526 +:104100005E2F6E8EE4F8791AC78BB8878A9FFD5CA4 +:10411000E2336611EB0774AE317FAED4F873D59DF0 +:1041200057C7E05E817847E5FB1217AD9E3EE0BFC2 +:10413000A1F87A4FE3634B5F7894F94125ED17C4FA +:10414000592DD5FCCB4B9F52589E5CBAFAEA879802 +:10415000EFBE6D13B85F70B6E5FE68E37AECD5F894 +:1041600067577B0FD75F4AF565FB37A3199EAD36BE +:104170000FE0095DC7EFDDFE29F55F6A5FD142F20E +:1041800045EEE5F3BF288EDCF627F095EDE16C6790 +:10419000A3F5E77B46676C2D8B30FF33CF8433BFAD +:1041A00039132BF7FD27749EFAED80E787F7B15D91 +:1041B000EDBDE902E7D0E280B95F1DAEFD1ADFAFC9 +:1041C0008AF7C4C04F5345EB81FE687D7EC4EDDFA6 +:1041D000B171FBD0F93C8E76230CFBF49948A69B79 +:1041E00033FDE4BA9C7976109F676DB192DE09DEEB +:1041F00064E84B6762658A1B3EA0870A97A48733F1 +:10420000635AD81E7046D9C1699B4DB6ABA8D3FC82 +:10421000DA447F89A01FD026ECA98EB54720C7803D +:10422000CF8FCCE73488FBCEA17673D029CEBFBE2A +:1042300059F2DC8478053ECF7E1BF6E3B4F03D7383 +:104240009F264F566EBFDC4F8875AADCAEB03FEBA1 +:104250009276FE02EA5EBADD9FE872A95FF1226EF5 +:104260006B69E3B225A0FBA5B5EBE681EEF5792CF1 +:10427000D5EE5FB7292AC3D3164EFB27FBF2F174A4 +:10428000FCAA598A1E9F275CFAF9457B382CCB2D56 +:10429000E988B24DD45F65A3B296C749D1F55B39C1 +:1042A0003F1D4FB8CD02FB5E9B76DFB9A7F9EB70DF +:1042B000F6044F5296E44F6D29F29E6FFB5BF2BEFF +:1042C000F6C56F0A62E2FE813CC891FA7A7F047FEC +:1042D000166810728FC6E796C2AE4E70666E30FBDF +:1042E00073B2369BF343B69BF3D93BCDF9DCBDE605 +:1042F000BCE75573DE85717B77E109FA36E203A1ED +:104300006F2385BEEDCE94FA36F2D0B79142DFC668 +:1043100077E8DBC843DF461EFA36F2D0B79142DFBA +:10432000C6F7391A9E2A357B29D681E3D4F684EB69 +:10433000F100BC5F2ECC49603E2AAC521FBDB024B8 +:104340009BE5C74E3BD35407DB99F438A7B7A27C53 +:10435000E3B27AC37F7B6475DF146EC7F6E79ADF3A +:1043600049FB73657EB813F68ED6559FAC86D8137D +:1043700088F24D44FD0BB6F6ADC06F55DD2BEC6FEA +:104380006F5DE17EE70772FDD8EEA2C72D15E3DC75 +:1043900003DF267D49C66F7B1C463B6AA85F48AC9D +:1043A00035E4213F359BF3A17E20F035AF695F35C1 +:1043B000311D3C6E6BEF0BBE7FE24907DFF33AA184 +:1043C000D9EDC46C17CB63BA3CDF298FDDA36CC277 +:1043D000F9BD242B8EDB771CCA30DDD30B4D4B2F60 +:1043E000E5B3BCDA995FAB58304ED98C15FB59AFA9 +:1043F0004E8CE673E9160DB64190FF0D700F0E441A +:1044000098E868E8B6B810BF653F53FD61BB5343F9 +:10441000FC96434CE5D3D71698EFB5175D6D2A1F70 +:1044200068EF8C877348FF96069F4BD6B9E8CCE7B8 +:10443000F986D64B563C7F84BF56BC25E5D3329ACD +:1044400087B7407B9F231FFE39EF14E0AFBCC51632 +:104450008BF3BE543B87449DF95C2EB70ABF2BAE4D +:104460008BEECA5DC21B4BEDBFB43625331DDD712B +:10447000345925142D19722437087DE58D2746827D +:10448000AEAAD48DC92E2ABF55096CC545ECD3718F +:104490003B12AEA4F2FFB4F81EC9A2754AB605EFEE +:1044A0009D0F3EBA234DE0BD91136B9F8FE6B83C44 +:1044B0008DFE926DAE08D0C1C62695F514D8CDD428 +:1044C000B82E3AD9D8141F01BDA67C8CE297727120 +:1044D000B449DF0BC547A19AFD8E9BE67BF1902A7C +:1044E000EF406AF35CEE92F545BA6CAFDFB3D7E705 +:1044F0007B52D3472B36BE96790B7D3F3B787F2E80 +:10450000AE8457D6EFE6792FB56CDFDA97D27B1DF4 +:10451000BE5D98D7F2B7C6455F49E37CB95DC687F3 +:10452000FFB5F989C7FCC44FEF6C7AC20EFB418519 +:104530003560871E5CFEE4463BE218AEDBB691BFF9 +:104540002FDA56CCF600FDBEDAA77A7CB3868FF25E +:10455000B1CA0617CDB3FF60C94FCA23641C4BA173 +:104560003AFA35DC13B8B84DC9C3BC6614EDB0E3F4 +:104570001EFF3B1ADF09DD371D87A717F686BDAB87 +:1045800045F120DFD33E9989CB72440FD32FB9393F +:104590009D716908EBD51F0AD2BE708E6487E8D77B +:1045A000875569CF433C12AD73B93DD86B3AE4856A +:1045B00097E5FB0F55740E8DCA87DE2EC4559416F1 +:1045C0008D564D745E333ED2B40F660BC3BEA2FE51 +:1045D00066897EA6FC8C4969A6FA37CE181AE2676E +:1045E000CEEF2A67FE7595E95D97AADBFD6E85E340 +:1045F0007BC69ABF537A3BD3D90DA6F655629AE98A +:104600005D97259BDF653C1395D9A18F956BF7418D +:1046100066FBDAB4EFADFC9D2662DAAF03D33C7FD4 +:1046200094E7A58DFD08BA1D7D36FE9FD6DD79196C +:10463000D1198F89F85BD83B7C6679E408EBA942F5 +:10464000AE4395668FAACA92F6A82AFF113BE29B59 +:1046500009FFD62442497593C2F646AAEF488A93C9 +:10466000F9DBF17DA7F95E07FABB84F2436A31F604 +:1046700057687935CD1BE74235EC47B083E9FD6BD0 +:10468000FDEAF4197ACF3EB41FDF6037EFE78A6D99 +:104690003B0EF623BC4C2F8ACD437C4965CB545B43 +:1046A00071F6E574A6F3FD8BE516B67F751C7E8565 +:1046B000E9ACA3DCEA91F1DDFF181FD55E696F0D4F +:1046C000A5BF45341FF89917ED543C0145D6035E4C +:1046D000FA812E43F092D40DBE743C75E22DA47C79 +:1046E00031FE331CF1114A007CF232BCE878D4FA76 +:1046F0005FE4132C67123C018627A43F312A74FF24 +:10470000DDC2EF20746C50844BF96E3C4CBB24ED41 +:104710003603D3E4BCDB77291EC8EBB32E59F97BF3 +:1047200027BD14C938F51993CCFBB3937E8AE47E78 +:1047300099792981DBFD6FD3D177D18FEE9F098DD8 +:10474000FFD6EF5D2D1AACDD4B1A21467CFB4FC422 +:10475000AFEB72404FE749E779E3D2F0EF4CEDF66B +:104760001C5E1E95CAF1DA3ECD8EA8F3639FD64E2D +:104770001FB798CADD05A0EFFE09B017AF6E4C4B0E +:1047800036BE17E35B65633B6FF28A784E8BC35D81 +:104790000938478A57C8774D8EDFD52701FE88E351 +:1047A000AB6CBD2651D7C77F3A3C59E4205FC8E9BE +:1047B000897561B38D76783D6D1A2CED35FA397EA9 +:1047C000CE72387A36F6DFAA5DD108055ABAEAFD0C +:1047D000912E3ACF57597C8F0F667FEF463ECF859B +:1047E0006B632EEC70BA3C51B1AAB00FCEFDCAFF7C +:1047F00079E5319CFBBE15B604C8A39F7DA00A8451 +:10480000CED079C672C4A7E192AE3FDD12C9F710CF +:104810003F558417FEA625EAFE5C97E95CDD3B0B5D +:10482000E3FFDE41E38EC0B881AD8918D7E3CFC482 +:10483000B8BE151931DDD957F4B466BD94F3B6EAA4 +:10484000F664CDEE0CF91E79C8F7706241BE471EC2 +:10485000F23D52C8F7F8BE4DF32F0C6C68CF837E43 +:10486000EA1F2BB26AF9BC7566417EBF4589F080AC +:10487000FFDCA278FA70BCC166F9DEC4F29075D58F +:10488000D36BDA490633D0ED0F2E3984316E6E8C3E +:104890008835E5C739FA9AEA17BA524CE5D7250E9A +:1048A00036955FEFCE33E57F9875A5A9FE64CF18E6 +:1048B00053FE47A3AE37D59FEA9D6ACA4F9F38C7BC +:1048C000547F6651B1A9FCC6D94B4CE5737CCB4CE7 +:1048D000F979E53F35D5BFA97685A9DC2B5C569CD7 +:1048E000777BA17711DE5F86DE45E92D6F65388D18 +:1048F000EB3A7A9CA5DB77794E697250BFA1DE3620 +:10490000D025EED7800E0768F767BEC0B9D21B7EF0 +:10491000C9A022F5DE237D4137A1F542CB47471ED2 +:10492000B8E8A6352C7A2A7AA695F8C4E82B0E1496 +:10493000A4517EF5538533ADC45F465F7DE0F954E5 +:10494000CA373DB54A960F3B7011E5514FDF20F352 +:10495000D3058B1A8F0CF97A869FE631FA07A96B7B +:104960003DD26ED26DBC69A73D88F080784DE001E4 +:104970006990E813E901A24FA4AF127D96A50B71CF +:1049800090E813E921D23FF1FDF7A47F223D4CFAD4 +:1049900027D2B749FF447A84F44FA4EFD5CFE6F489 +:1049A000837A1FB7FB437D39A747EB6BF9FBC7F54C +:1049B000759CFEB9DECFDF5D43743B4390ED31BAA9 +:1049C000FFAB1A7E47D8ED76DBCE1AFDC28A579E22 +:1049D000A7BABFB2A156B446629FB65A634F39BA5E +:1049E000FC903DF35BAB386590BF5E0FF7260DE1A1 +:1049F000F1FBBB986F6BDF8F89E903F2699D0A5267 +:104A00007D29289F995FBA2A86F8C70FBEA9B5816C +:104A10005E3EB4747F7FFB0B8D4EDA877833878CD4 +:104A2000E8F2BBEB7EEFCEF81A835F1EFE6C3D8E84 +:104A300047F7C7F39F213E47F793EBF141D76AEF62 +:104A400023E97E703DFE47EFB7F09260BE77CD1A46 +:104A50002BCB2D515611C4387A9CCF358E963CC441 +:104A60003B5C53E9E438B73EF41DEF23523D2FDEA3 +:104A700099DBFC25D5CFEDF2BBF7D1E641E53C8FC4 +:104A8000C24B3EB6D75EA3C51DA0BD4396F33B7592 +:104A9000881183FC4129DBE11E55A87D7E571C004F +:104AA000EA47CAFA41F497FE158D17DDB58F06C4A3 +:104AB000B5E4216E6C40B593E3C6368C09F2BDB9FE +:104AC000E9B1D7DED3AA224E38E6C7D8474FA7FAB6 +:104AD0006602CFEFEE730FF0507E5A5C5A6FA4530C +:104AE00043DEB5EB667DE6625D757CE978D7D74B32 +:104AF000C7B7219E8AF1FC5DEB17BA6EA1EBA5AF9B +:104B000053E1A52EFC037F97AF4FD7FAC13EFBFFC1 +:104B1000CBFA0CB7B6F07DCCB04A8707707DD77A58 +:104B2000DDDC2E26E03E78F125F741A44BD27C5FF8 +:104B3000807F968A31135CC0914BCD819D27B4DE76 +:104B4000F2EF59EFE1907A07E20AD67C9D7679BDC3 +:104B5000DD21F51A620BD67E2DED4C37E27C3DE46B +:104B6000B6B11FEDCD703D1EC3EBCCA3751CA7F1F4 +:104B7000A343A296CF0F12D7FC58DFF1DA528FCBA6 +:104B80005ECC72EE78A7596E9CF04D5123C69DD035 +:104B90002B448ED6FCE13768FD5E279AB8DFD07BC8 +:104BA000F23768F269E83DF9E78668F2658A4801FC +:104BB0009F1A2F3C122EEDBD83F12ED96F92462FF6 +:104BC000696E558C063D089F15CCF155BC77908BCE +:104BD00071FD9CBF5E0438FDA108723F938991224C +:104BE000FF23216CF29D03793FB35AF5FD27E42C96 +:104BF000FD5EE6C270DFABD877AF444E998FF728E1 +:104C0000C6158C4B47BB03E3DD2C9F1C70A4B1BCC5 +:104C1000847D658BEBDA7F6FD0F9926E95F7069104 +:104C2000E2DE603A6D96D7E9FC41FE86AC1502EDF6 +:104C300026B8CD71387AFB1FBAC60A6B41CFFCFD8E +:104C400087B97BFAC3AEF366ECA0F1B083BF197BE2 +:104C5000C578CCF7CDD83E169986D939CD7931BDF6 +:104C60003B794EA7E7AEF126086B7CCF78D6F11AD8 +:104C70008A4F1DCFFF025E2F7487D72F060B29376F +:104C8000474A3EA2E3B72AACF31E671F635C44A504 +:104C900043E2E933808C7BB87557F13C3EA917FDA0 +:104CA00081EF4575A3B83CD40E2536C7705E7FC72B +:104CB000ECCC83EF4627127CD7397CEA50C2CBD9A3 +:104CC000FC60264930E2930D0D7CEFFADCB3AA07B5 +:104CD000F27FA5EA5EEB014F7953653FA0F8E695B8 +:104CE00064F809C5E6EEE3A32B1D12AFBAFEB3329A +:104CF000AD88F7A7701524CAF7D5E43D725D1EE8AC +:104D00001F26E38BF5FBCC3DC9072323241FEB1F94 +:104D100026F9AEBE9ED48EF349D4CF48E25349F76C +:104D200045B03EB0DBE54D1A0A7FCA786192A7759F +:104D3000BDBFA3977C3FF05A91F9D068CA8F3F64FA +:104D400013012AEF182F4CF164856F94F2BB16FA09 +:104D5000FD98B044D2AF0CFC20DC1D617A6F343278 +:104D60002BCE948FF2F433D58F19956A2A8FF50ED6 +:104D70003195C74FCC37E57B175D65AADF67F658DD +:104D800053BEAFEF0653FDA4F269A6BCCE9792E4E2 +:104D90002731A076AEA9FDC0BA1253FD147F85F964 +:104DA000FD54BFF74856029E77947F696B9687BC87 +:104DB000AF6A1196915DEF90FC3A5ADE0799E85C74 +:104DC000C4EF916434FDCC0C8FFA8D8A732629468A +:104DD000E1F724AE739BF96061A2393FDE95F72AB3 +:104DE000966E9C2B34FE28A8809E926AADA6EFF3A7 +:104DF000866A7C3457E4B29EFE5DEBEF1B625AFF7D +:104E0000507C5D4E0FCFE705DDD29E6F9C17ECF90D +:104E100046BCC09E6FCCC39E6FAC0F7BBEB11CF670 +:104E20007C6379C121331D8C3862A6832B8E9AE96D +:104E300040A7CFD0F5BAB2D54C1FC2A7F8947FB027 +:104E40005E577F6AA69FD0F521098BD76F825311D9 +:104E50008FA4FCFBEBB52E64BD3AD787F00DF9F6B5 +:104E6000DAE050BE275B78481578B7E4516D9ED7DD +:104E70000DADE527C3B65B7DBFE67DAED155435F83 +:104E800049571D879E0F071F7D34A4FFD7FBF902EA +:104E9000A83F3BFE62B21DF4D12EDF456B031FEE2F +:104EA000DD15B7497ABABC77F23395E3188E599A73 +:104EB00014F0EB8218DF36F0CB9BB36B15F8671359 +:104EC00045D18E4588CBF98FB064E4170C94F77701 +:104ED00045762BDF7FD0F9E282241917D83254F3BC +:104EE000F37A64DCCEF343A5DD24CAE3E238E3E2DF +:104EF0006C79BF83D499E40539C0C7E1F041C0475C +:104F0000B385DF696CB5B9396EC4FF862AE0F783D3 +:104F10001C0BF9728026DF357CE47000FE41EB85C6 +:104F2000E99C1D1C7098E25B876E7399F2392D899C +:104F3000A6FAC376BB4DE579C12C5379C1218F29DF +:104F40003FE2C82853FD2B8E7A4DF92B5B279AEA56 +:104F50005FFD6991299F24DA1F067E072A528F3E42 +:104F6000333455E2C92D387E6FC19DB1F2DEA7A65C +:104F70005FEB72BA1EF7ECD3E83954DE1F68F771A5 +:104F80001C75435FE1E17B180E4D9F12663DC0A783 +:104F9000C52D77DEA3F09BE396F578E54E7D41D3F2 +:104FA0000F7439DD10AFEC35C62B2F08EBFE3DE05A +:104FB000FFD2D63D14FE817639DF869FDAF9DE888E +:104FC0000E57283C33B538DA2D8EEEEFF5D8B225E2 +:104FD0009D256514FD1DF4FE98CDD3CA6FDD5F36A7 +:104FE0009EA7D54FF4D5F00BBB67A5FBBBC75B30C5 +:104FF0004CCE67BEC572F3D46C8ECF32BD83DF3B1F +:105000005BEAFD51B94AB7F35B1023E3A7448CDD9B +:105010000DFAED793C89CF44BB68E4FB475A9CFF0D +:105020004D6B5BEE194445F3ED4DDA7B60011BE8F7 +:1050300061D25892C3F284D8B66557B393E4A2C73D +:10504000EAAC6C3FE9BFDD358B24B8CEFB1B0349CE +:10505000EF017D40B681BEB42147E571AEC19E1B14 +:1050600081FDF64D679C3DFB0584D0CE0BA94F75A5 +:10507000436F4C87FA3CFEAFE3ED43F1A4EBAD4246 +:105080008B334CD7E0D2F1D76977D0F0A7DF7F70B0 +:105090002FB3156D72F23D8A8988DBD2D7AF2547D1 +:1050A000D265AD860FD4033FEAA95EA19A1D03FB2A +:1050B000728770C7B8BAA1433DFDBFC28B8EFF9EF9 +:1050C000EE57F5C41F42F9C277DDB7EA894EFFD922 +:1050D0007B57063E21E368B47509A45BD83F7D6722 +:1050E00094793F6FCC96768D71DABEA2F3DD996725 +:1050F000E61702F6F18655AAC62FE4395E9C52C423 +:10510000EF118B3A17CB33E51A2FD6CFD7850FC8BF +:10511000F7E0AEF516255C45F992669BD848A015D8 +:10512000FBBB8FF366BF931B71FE9E44C0CD263739 +:105130001AB7B44909EC4FB9FCBDECC54EF97E5C19 +:10514000E8BBD98B35FD172F2A60DF86FA65EECFD5 +:10515000D6CE6B8FF07C2BE167BDA50B7E8DDE027A +:10516000F21D31E8C3AAB4F3709C968E3737FC2445 +:10517000F15D79C26F4416CEF3466BB771749DF83A +:10518000D5FD2A9D7EC2C31CAF1F1A1770D6FF4AD9 +:1051900074777E1ADD7FD3D33EE8F4DF7C875FA887 +:1051A000C369891E053E04FFBFDBE857F9F3488257 +:1051B00090FD2731F08FB46AFD898DB9DDDD4FF4A4 +:1051C000ADD8C5F110AB2CBEFF405CF219EA1FEF61 +:1051D000B0DEE53C9080FBF89334BBD3E5F3D6E436 +:1051E000B0D1F27E40875FE5F5EE9828EF73131F8C +:1051F00015D877BA1F7FAA08F642AAFB497C6B46EE +:1052000031FE753F49717014C339B361B10D4F4818 +:10521000B63E7C7B6184BBCB7FD23A40C6E7F4E4E8 +:1052200047997EC9C3FDCDB87415F7732C3B45CAA9 +:105230006B8DF72C039D0DD9266C9867ABADFBDF0A +:1052400019989223F7D152F8D27B1BE27E5628ACF4 +:10525000072C57841E07C47C5ECF5F6CD2F2853268 +:105260007FCB2A996FD5DEC5DAAAD93B304FA498F7 +:105270000FF4F0ED9A3D04F3408A79E03BF81AF21E +:10528000E06BC883AF210FBE86147C0DDF4B445109 +:10529000729E2AFD3DE30DFB03FE9EF106B909FE59 +:1052A0001E631EFE1E637DF87B8CE5F0F718CBE1D4 +:1052B000EF31E6E1EF31D687BFC79887BFC7581FE8 +:1052C000FE1E631EFE1E637DF87B8CE5F0F718CB97 +:1052D000E1EF31E6E1EF31D687BFC7587E739D62BB +:1052E000F207DDACBD3B50BA3E8EE9A339B52829A3 +:1052F00087D6F73F23FFE7C7B654ACF3DE25FC6E35 +:1053000060558447AE73D344B9EE1621D7B97D0EEC +:10531000AFF3ED76992F94F1C2A1F403BFCAF874EC +:10532000E957410ABF0A52F85590C2AF32DE2AFD52 +:105330002A48E157C177F85590C2AF82147E15A470 +:10534000F0AB20855F0529FC2A6807BF0A52F85593 +:10535000F01D7E15A4F0ABE0FB318203FE151D2E7F +:10536000C8F9E9263D94E8D0A487BA4C79C8F9C6B3 +:10537000FA90F38DE590F38DE590F38D79C8F9C639 +:10538000FA90F38DF91BF188716F29EF1BDB41DE79 +:1053900037E6739AFCAFC1863579C3F95791B646A3 +:1053A000298F292E92EB729E9A05FF586BB8921C9A +:1053B000EB213976C56F678DBF92F889166F972BF1 +:1053C000DA2D586FF67BD3BAF98282E38373FE3B02 +:1053D00091CB757F2BFFD1BAE7ED14AC376CCB9036 +:1053E00070E9ED3DC2A522D5EB77E5BBAF173ABE1C +:1053F0005E8FF9A5010E5228F310079177BB331F7A +:10540000F1ED5B2D8A8C0B5D29E37243E9AA49E338 +:105410004B5B2D3B0E4450BBF662C5837B07995610 +:1054200071C8960F3CD5E6439EA8CB89D5E2836B25 +:10543000AF423C900EB76E7F243EC1F7DD46B70BFE +:105440007B198D73CD17C28EDF5B986497F204DAF7 +:1054500041DF1CEA57BC9B0CF4BD32479E7B3EFFEC +:10546000B2ABCAE8FBD0EDB557E11EDDA408D9EE1A +:10547000378F47331EA7342A9BF0FEC9E8EDC28B55 +:10548000FBB1BFD4E01EBADD652FE3715D7CFF4E3A +:10549000EFB7784332DF172C16ADE313D927A1F00D +:1054A000FBE63ADE687EAF627EC4E20FC18EFC2F5F +:1054B000DFC32171F1FBDCC3B966786C21E2DBC488 +:1054C0005EF90EE4E4E1C5AB7A135CBE807C07F2C2 +:1054D0009A2F6A5FE3FC66F90E2493CF48868FCF3C +:1054E000C3417E85DFFF98E2DF68E9E5C6BDE015D0 +:1054F000B604D4DF2E3C500B060979AF559F57B642 +:1055000038620957402FE2957803FD11E798017A38 +:10551000C9F3D8F87D90A956970DFC4697738A5D1C +:1055200072EC4275740CDFF70B91132E36F6E6B869 +:105530008D7F3D8EA483EF932FDF15CE72858FF87C +:1055400007F8E6B93C197759B9ECC39196D4AE384F +:1055500092D32981AD78DFF374EA8EE8510ACB113A +:1055600087C05FDB1A9FE77B82C5AB5EE3FB10174A +:105570001B1F8896F7AAA47FA54CC39B6E6F5AA8E1 +:10558000AD4F99163F74BC5EBECF4BE730BFF7718D +:10559000B1D1C67246A8BC2884EB0F88732B6FB4B8 +:1055A000F1DDD3C56B8B57278AEE7E77C52BE3CF12 +:1055B000B5719734DA384EA85C7B472BF477589650 +:1055C0006A72E8D26DE6EF277242E44FFDFD44AD0A +:1055D0004EF15BAFCC6439A8D6C671EEF35748B92B +:1055E00048EC1001DC6798BF629C05EF58CCDFE502 +:1055F000F528DDD0D13B9A7C34098312DEA75E8A80 +:1056000060BE32ED523FCECFBA94C8E98D97B2E476 +:1056100077AC1DD14B6BA1BC5FFFBE2617CD441CE0 +:105620006501E4B23E4CD71D44D7182257E35743D7 +:10563000BCCA2B30C34FB2F956214E73D246C1F7C4 +:105640009126437EA282D990A70AB02F520AF93E32 +:10565000C64485EFB74C1EBE4CDB07B42F04F311D4 +:105660007EF7C3377E6A00F137B37D3B2C58777DD8 +:105670003FF8FC6DFC0EE664BF62C77B813E4DCFF8 +:10568000D6E93D745F2C88D4EC634E69FFEAB48F91 +:1056900001587E9C27F246C4B32E802DB39FB6B02E +:1056A00084AAA86C599E9C1B79632394AC7FD36E0B +:1056B00032DF6291F79F48FEE3787571A4B00FE581 +:1056C0008BD72AF98897D7E1FA7AD8D849C37A775D +:1056D000D14149E7FECCEE03BD60F95D1926FF4CD0 +:1056E000685A4AF8C63E5A10D3FA63FCD2D0845C9A +:1056F000E11D9F8877C8F5F98A20E202E76AF9DBA5 +:105700009EBDF28F6B9C8C27CE8FCDED7723E23F31 +:10571000FE65FE385FB11A7F37AA4DF17973E53D1A +:10572000C80958DFC8EC767EC76066A64B9E2F215D +:105730007696DB72DDF25D84107B4B69B63C6F843C +:10574000D59D3C8FFD3A6EB657EAF33E6E33DF339C +:10575000D5D3EA5C6937F8BFBA27F1A045DEFB7FF5 +:10576000C412D8F122D16BA0B76F01E6FB08E2BDED +:10577000197E1FCF4F7F47A3934F69EF65E8F474FD +:10578000ACEE22DF972871DADDAA819ECAD6287C8A +:105790001FB1A44EDE27F6AD51E4BDFC1EEC578FC1 +:1057A000CFF99ADF517AFC1711B250C3EF7CFB910D +:1057B000D71C295DF8FD53DDAF6C927F0633106F67 +:1057C0003FB7369CDF41FE7A58D18F017F64B687A0 +:1057D000D76912F134D49F1AE3FB29BE97882307B7 +:1057E000616F5CF0F3B7F87DE19ABD29FCEE61F1E1 +:1057F000EEBCD57847E5EB61BE3B72897E8B9D2E72 +:105800003BE490EAC6583E9717F4D1EEA98B76F6A2 +:10581000E7E9EBF360AE94078A3C729C0B9A3E4535 +:1058200008B34D35D593E77FE83ED4EDA2A1F695B8 +:10583000D0F72ABECB9E027B89DD6057D5ED31B60D +:10584000ACE373709ECFB777FFBB8DAFEB76474D60 +:105850009F5DD8A9CF664FE803B97F9DE2821DBD49 +:10586000CCE9BE11F1F565876C88F01493E2DCF2A7 +:10587000DD92BBE4BB2525B7E6313F9B8F35C9C719 +:10588000BD8751BC8FCB0294C6F7BCDFE7AD7B650B +:10589000C01ED053D0CBF7E0CB5C5E7B9C412E2A60 +:1058A0006D524CEF18E8F91773A51D723EA919C087 +:1058B000DF4DB7A6D8F186D07C128F1037F8BA46E4 +:1058C000277A3BAAC771259352C541F9AE14C19DF1 +:1058D00022C733FE4E514993F93D06AACF72DDFE31 +:1058E000DC28EEAFD845F34E41EA6238090F8CA7A9 +:1058F000F67BA83F378FC3EB511A0CD86037988FCF +:105900007816CACF75056C18A7A451BE8FE25B2B21 +:10591000C7F1AD89B5E7402EB0BAEC038CF260A3B5 +:105920007CCF78BEF6FB11042FCBCB658427DCF34C +:10593000D2EF7D86E2AB5883BFAC29D62C5F36AD63 +:10594000B3617DE6F4F05EC3971A1D97348EE1FBD8 +:10595000F565562FDF97F069F8FEEBB2F0BBE12753 +:1059600099D3FC902D05798D2F7D093CF7069E82F9 +:1059700019FC3ED2B2708E679EE36AE2F976E2FBD2 +:1059800001C20FE4155711E39BE8C48F38C0B2661B +:10599000F3FA76C11325DF656F2EE6FDB7C8EAB3CB +:1059A000BB8C70ACDF9F81FB5B7368DFE3FD27E19D +:1059B000F2F17DCC530FDCC8BFFB063881E7288F9E +:1059C0007B02DE3B22BA61BAD6E9674181DCCFFABD +:1059D0007851C3ACD20E3FECBBF6A9F720E4F30636 +:1059E0005A6FD8FF7BDAA7765C00A471ED65F2DD13 +:1059F000BAD07DABEF577D9FEAFB56DFCF8FD98AB8 +:105A000082894A17DFA1F3BDF6B96EF03449837776 +:105A1000AEB6AE84D75785C1AE376298DCDFF3539C +:105A2000CDFB1FFDA1DF54BD7C6C3003F73DF5FAC3 +:105A3000FAB8F3E3643BEC03D05BEA304B67FDE577 +:105A40005CDF62E21FA59DFC63FBAA04F08F1D0AC8 +:105A5000FBE196DF23E5BEE5CFC87BE16796BFF8A3 +:105A6000F62CAA77FAC18D0B8CF72FCA82925F2C85 +:105A700024790BFC6391260F6CCCF4E50D33ECE735 +:105A8000B2FB9FC9C4FE98DB92770A6FA8D1BCF91C +:105A9000BDA33F3FF3D28757B9BBCE5D7D1E256BBB +:105AA000DEB5153B8D7893F47E7756079F5BA5385E +:105AB000B7E853696331F36191487A8FD2B5EEA1AB +:105AC000F450DCA8B09C575A3732A0FE2FF2EBD22C +:105AD000B553F98D287DBDF4775FF47357877FA6A2 +:105AE000B64E73357A9E3D4CEEC3B9E529F645BCFA +:105AF000FF53ECF8BDCD395AF99C32F3F7CEF5726D +:105B000075F2FBD5D827B89F84F5EA586B93F6CB8E +:105B1000ED97AD5732E4021D8EC59A9D72A1666F56 +:105B20005CA4C9CBB45E8B8DEBB5F871B95EA5CF23 +:105B3000BEF517BC5346F3D3DEA393EF0A94B4EC3F +:105B4000E0759BB3669D2D85EAFD64588A29FEA801 +:105B5000B436CF053BFDDC351B6DE0073F1926F160 +:105B6000164AF7F3B5F8621DAF388F14833F47AF7D +:105B70000F3EB883C6B9755978B4F177ED021A3D76 +:105B800097D6C6C661BCD2DAE27BA17FE9E740E8DE +:105B9000FE3B112EF74509F587FD79628C87EF559D +:105BA000CFD77E372FB4FE431ADDFDDA26DFBF4C98 +:105BB0008A6C7992E33B6A223CE013E9E9AD018CFF +:105BC0000B7A06DC768B7C2F33BDB2F573C041A215 +:105BD0003CC7F520C57B5B10ED1328BFC922EF79C8 +:105BE000A5AA32DDA7E107A637948B5EADFC1E5F48 +:105BF000E7BB5121F46A179BD7E0DD1F7B2FC1EF74 +:105C0000A6E9F4A9F7A3D3A74EBF3DCD6FD7F79C64 +:105C1000DF8914CDCE92E54976D0B80BEE1BC4BF18 +:105C20006BF15DF3B46BEF3576CE374CFEDEC765B6 +:105C3000F34D97FA52CFF36D2E4CE866BEA1F3D424 +:105C4000F7891E43DFE94F6992FE94130A9D63D4DE +:105C5000EEC4B2708EABD3E7A5DBF5BFEFBD878F87 +:105C600086C569F6AAD628C897F3B5DF51114199C0 +:105C7000C7F7A986EFFAF9AFBF5FA7F3E993B5DAE3 +:105C8000F9285AEFC17E1675697C0FF558D389281B +:105C9000BC1373628C844F6F77AB4DDE73165176F5 +:105CA00037DECFBBE9D63CFEBD94858D7D589FBDC8 +:105CB000A92E8DF9C24D7E581745A71EB048E38323 +:105CC00091B716AFBE02F5D7A7F0EFC22D747A4E8A +:105CD000ADE7F6433D9013239BA7DA53591E96FA7E +:105CE00082EE17BB5511457C4F0D7C12FBCBB23FAA +:105CF0001DE7CFE2F5523F9864116BE03F1DD8508D +:105D000034A12FF8C4C38AFC3D9A0DE6F7BC860E79 +:105D10002AFA027C26F45DBC5B6D2D5EE8A782E466 +:105D20000ED8D1163A8B589EBF45E393C79ADBF83D +:105D3000BD7E1DAF8FE0BF78A72AC47E146A271AE4 +:105D4000A8D907FF1FAF8F7B3D0080000000000037 +:105D50001F8B08000000000000FFB57C0B5C546541 +:105D6000DAF87BCE992BCCC080C84512878B84850E +:105D700034C080D7DA518150BBA0BBB9BA218E653F +:105D8000CA650650DB5D77D7FE8CA1A6667DFA4515 +:105D9000A665ED80976AC376483428A8C90B99593F +:105DA0007F62376A2FB9635BE62D40BAFCEDBF6DA9 +:105DB0007DCFF3BCE7301751DBFDBE6FFCF97B797B +:105DC000DFF35E9FFBF3BCCF3963348C751B186324 +:105DD0002A8B8E413968488964998C8D09695F6185 +:105DE0004C89C3F625DB45C64640FB7C93C8621947 +:105DF0002BD731FA7D8FBF1F31761F3C37C3F3425B +:105E0000A934D607FDD737CCA072C9D6C26DAEF182 +:105E10008C250925B1936360C0E36AB6078A25CE55 +:105E20001977302BCCD3A48DD225C373B52B29C7BA +:105E3000E09F6F49E343490CC69D69D4CF77437B0C +:105E400081694E41148C5FBA332A5B32FBFB5D6F74 +:105E500011181BC958A573461C4B61CCF1DDE167D5 +:105E60004CA9B01F98D304F37FE50977BBA08BA39F +:105E7000AE2D4982233CAAB3A758A07F95D8316F95 +:105E800012CC734E70EF4DA0FEE63853C0FAA1E578 +:105E9000E93AC6CCE98C39FFCF8734CFE7E2893BBA +:105EA00016C07887737F04CE53F5F81FF201326C69 +:105EB0009D68CFB2E4E1BC8D7B4D121C747B6356B0 +:105EC000099CE3BEC7C746DA332F9FF7B668B6A86A +:105ED00004DACBDB18C157695FE88ED420DCED5EB5 +:105EE000A6316169629A6828CF486C9507CADB526F +:105EF000D8A2B9067FBB0DE100EB9E89DC9254026B +:105F0000ED157B9F48324379D6C8EBA57B7F7A9C01 +:105F10004540FFDD5A0DE2D5AE621A0B8CBBD7258A +:105F2000D8DC50B2F268C61210A36E7D9991B159B7 +:105F300096709AAF627B0E63B9FE7DC1736A3FAB08 +:105F400062C5B88F31F503D9CBA1FC8BCA7B1FE2A8 +:105F5000F32FB57A8B2B19F16226BCFC658B548428 +:105F6000EDAEFB053656C0FA7E631AAC5F16C96A01 +:105F7000717CA1F4579B04CF571C10B2B5307B78CD +:105F800066B7E61E039116D159B589D3D98A7675BD +:105F90005122E07F458B402D0E9557331CBE2A2F92 +:105FA0004D66E680FD56B6B668CCB08EA319CE0914 +:105FB000FD1D9E539AA5785EB685B17CC027FE89EB +:105FC000F86B3EA5B937003FD5AD1C2ECE56DEBED0 +:105FD0003803903B99B66213D2A0DE2650BD3E6BCB +:105FE000C2FC35AAC07AFEFC3569589A084E4C3579 +:105FF000905402F0DC94D1A341FC3BD7CAF3425D3C +:106000001DB05E0D12E548DE9E6AC0F1661AAF3C17 +:1060100077B646D178AF336C03BB0936516D50610A +:1060200059EF344460B9B356CC50597173611609B5 +:10603000E0DF111691C52261CAAA5E3D4012503BB5 +:10604000705884F6DC48FB83489F710CB802E83333 +:1060500091790506F4DFDFF9592ECE7FCB18DF17D3 +:106060000CB6AE5E337D7E01D0C3268B7C8E4C5F3A +:106070002ED2F1C84340AFB0BFA7D56C833E07CF47 +:1060800057C2E6423BCCC208CFDF84B9F7C0DFAFCE +:10609000316F22CECF74DE541CF79ACCA7255AC399 +:1060A0000601F6F59B14FB63B88F3B05F5F86C1100 +:1060B00071208DC57EFD6AFE9C6D79C2A603FC4FE2 +:1060C000E7E867A345E66240A29A51F106A463C1DE +:1060D0006663AB60FD07330FDDCB802E1E1ED03113 +:1060E0002D9CAF5ECFCF3D7D20EC9400FD468F2AE6 +:1060F000165916F437AB5829F43F94297A55D89F8E +:10610000E9DCD89FE90A6DBE0C599681FCD0887AEB +:106110001BF5EF78F31B01CA44E9E2E1483857E286 +:106120002F054B3DF4291B3CFDF4FF85B2F452537F +:10613000CBEFA1FC75A4BD19517772B0F8941D5036 +:10614000F6B0C9A3B364F2F902F7DFF1AB6F22A294 +:1061500045FFBEFA074EEF7BD98AA5CE22C0B8E92B +:106160001D92579B75F97EFAE361E3A9D48FE1395B +:10617000FB0DA25B10B0FFE10F717FD37506AF146A +:1061800081E3D4177C3AFF38661E1D75FA4646280F +:10619000F83E91B158DC3C8C1FB8687037C1B96FBC +:1061A00091F94FA1AF1E8B48F8E991F1A4C091E994 +:1061B000B222917EEBD58A5EF085B34C3F7FD6E864 +:1061C00038FF0C5E126D38FF60B9D6CD608AC18E83 +:1061D00054D2275792A77F0079CA40D7BC976AFB51 +:1061E00033C20FF94A07FC78970C2FC03FC3F9253B +:1061F00079FEBB64B8DD6510399C7E120227996E6A +:1062000014BA50F62F98635869B41F9FECD7DD4736 +:106210002393098FE3FF83E3EF13C2DF3727D60110 +:106220001BB151FF984578FC5FC09F57B4FE0BF837 +:10623000EB0EC59F577F3DE2EF71D1D284FC800801 +:10624000C8A1D226C2F9580623FE2F93C22C9BE088 +:106250007C76E4FF9B88EF8F22DF2BFC3EA6D837AD +:106260001EF5E449C69EC17DF9440FB5A766A71087 +:106270009F5FC7BA13B01DF09C3717F12ED876E890 +:10628000242C7DFB5E86F55D1506CB1E386FBF5B4B +:1062900074A961FE8628F78EA5B06EC35D991617A6 +:1062A000B63396D58672A03CCC827ABE218ACB8545 +:1062B0008605E9A4870F7E2725ADC2732C08B33469 +:1062C00041FF866CDF2313A0DE30D66C7141D757B7 +:1062D0000596BE1DC7CFD1D13A0D7338DD363C329D +:1062E000DA8D7A05F4CFF37AA83F591EC6F09C0DDB +:1062F0008DB68468A0CB9722ECA3B361FFA3244E94 +:10630000D70DC9D00EE536A164C17D38DF78BE6FE8 +:10631000DF82B017F7C22CFA341059D07E7295B1D3 +:1063200009E5A5429777A5737937C6756A07C2C98B +:10633000359D65D4C2FC7F93E94B81BB60636C558E +:10634000B41FFE0A9DC5C8701756737A734D97E542 +:10635000623573D70B085FE60B07F8966941414237 +:106360006934D9ADB8EFFAE5801709F7CFE17F526C +:1063700064E59E61F8E747282CF3884C04E48F32EB +:10638000C6F9A30CE908E96F15D05100FD31DF759E +:1063900051A7C3653A82F16B8D25D370BDCF853F80 +:1063A000E463E3897F4AF3875B67563697030BF410 +:1063B000F699D89FED8E14515FAE30F1F54E647FA3 +:1063C000361AF5C5C95FBD791D96C7234A6ECB86BF +:1063D000FEDB167C5D84E2FC6F093E359EE36F0BAD +:1063E000FEFF68B443CA56BF49F4FE43F759281963 +:1063F00032504EAF047DA615B0E474B0F23E467440 +:1064000090C86A896EE365FD050CA3473975F300F2 +:10641000D88ECABCF0FF4797746C89CE5F9FC6A226 +:1064200082EA33740941FD0B4DC941CF6F8D1F17AF +:10643000F47CA6393BA83E3B635250FFDB2DD38250 +:10644000EA774E9C19D47F8E6D4E50DDC64C241FCA +:106450003AEA8A733F01BBE1B5BA92DC4F5497E345 +:1064600063AAF6D07EB305E824DB3B5F3509EA91E9 +:10647000875626437D53CB115E4F3CF44532E06690 +:1064800073CBD1F92AD0DB536F3CF4450AD41F6D8E +:10649000E9E2CFA7C062A340ACB6BC39DF05F89AE9 +:1064A0009B62DF8AF89A77A9F6288AF9F7D7CCBDDC +:1064B0002F5942B930677406EC2737C5FE103EBF2E +:1064C0002BF69E759100FB1F7D5BAB463CBF985D34 +:1064D000B215E9A1FF22A7F353889791FF7E099691 +:1064E00003D9618A9CBD923C54F8AD03F4C61215E1 +:1064F000C24947A5B7CE44E5A1BA782A8FD499D925 +:10650000128063575D0695C7EA2CD47EBC6E229537 +:1065100027EA6C54BE5B574C65775D09950AFFB25C +:10652000BD960D6A2442972AEAB4CE4F8F57D263A4 +:106530002028D969059FD0F94DBDAD399BCE759DF9 +:1065400009E959693FDAF9815904FA9D6AD5113D83 +:106550004F35749B75565E47B9B8FB22F38A11BC60 +:106560009F2AB05F8C271BFD98A90E03F54B1B8457 +:106570007E59D8EFCD0494F7536B3516B4639E5013 +:1065800033971EF66F14DF90701DE320CA6CD80598 +:1065900018D53A905771A06BF139F4633A28770F08 +:1065A000F2F54647D72E47F934BACC60A9E7F29501 +:1065B000E44BE2086F02EE2F71A586DA8D628F1927 +:1065C000E5605F9D7716D269812CE70A345CEF3075 +:1065D00011E4BD807CFB6D5722DAF3EDDC9E2FD0F9 +:1065E00096EC44FAAE5671FE65317AF71E5C47D5DB +:1065F0005DF12CF4EB894DB46C4268C51F64696091 +:10660000B717D61467A2DCED615B88AFC15EFD13DE +:10661000D2DB8F3381DF459948609EF8E2F0A64DCA +:1066200002DAADD7E7215DCED59A0F30E0075FF6ED +:1066300000D1FBDC48731E7A0ABEECAF793DCE7CFC +:106640004080E7263630BF00EA55CFE94D9F04F081 +:10665000A9D3131554AF694B307D12C0A755F80765 +:10666000FA47B7092A94BB0E792BA704FB05C4B7D8 +:10667000B3F8730DDFDF8006EDD88BD966A26FB05B +:106680009749EF0FCC34BA9B60BF71236AB357A010 +:10669000FD9469CEC37E49EA8108F463FABF5515BB +:1066A000BBC9EF1988F8C9783F7D3DD321517B28BC +:1066B000DDB5E6707FAF26CDB019F1501DAFD351D7 +:1066C000D971B188919D56928676B94DC3FDCBD0D4 +:1066D000F17B73B81E495EAF21B940A208B66C0BBE +:1066E000634ADDC52632D6F88BB021BF07C0C93456 +:1066F00063653FC8356247415A507F1BF61F7A8E4B +:10670000F61CF38F4F7949BB63AD4A5E0FE96529EB +:1067100073A33F182AC7AB72A365B9C0F1FC748C90 +:10672000BE11F19C26017DE750C94C50268633B23C +:1067300037135FD7BB913E77EB39FDA789BCDC2DC2 +:10674000F2FE9A30E6427A57FC874DB9F629B979BC +:10675000348F97E6915AB291AE139887D657EC24AE +:10676000A51FD8437A1202AA8174C4D754491C16B3 +:106770009E2772A615E58C44FEB0B14F03E4775F07 +:1067800078C4AA40FC55E37843E0B8E9344E19EFE9 +:106790005C25B24F47905C243A72A689E42F564B91 +:1067A000EC8880FE16EBD6A09E53C6F5821CFC1426 +:1067B000F0F047908B587E08F210D7FF33C8432C77 +:1067C000FF0AF210DB4F823CC4D207F210DB3F0617 +:1067D0007988E5BCBB8D56E49F9AB669ECD3207EE0 +:1067E00050DB7D01F5DE69C3D39143A6A3DEE4E16E +:1067F0009FAFCBE17E45EF2D1C9FFDA0BFD1FF00D9 +:10680000BA5C6B8ABEB21EEF37B2F91E80D3B67C7B +:106810006E87F427F0FAD21C35D56D22DB8EE3B7F4 +:10682000E56BF8FA2962393EB745F3797BD345B277 +:106830009FA64E9EB624079EDB62A13DC75FEFBDBB +:10684000813FB78DE2ED437A567E3E25D7A4F8EF1F +:10685000E9DC2F65642701BDD3FC4AFFF726723EB1 +:106860000CEDEF4E138BDDC3C0E32D996F892FD054 +:106870009E463E480EE08B6A33F18542870AFD55FD +:10688000E57238A769653A07DD42F0431D83723A25 +:106890004E4FF625C0C5C6E03CBB05995F42F901E5 +:1068A0004AD4070A3F287CA0D07B22F09910ED3F04 +:1068B000C7CD21F4AA948FCAE7E88E35FE9CF0DAA2 +:1068C000A136A1DF7733CC87E313C5C177EF46FE4E +:1068D0008C359AD1F52C7CC8503B9C1CEBFAEFC24E +:1068E00043910B5780C76570D0F0F25F8503C939BB +:1068F00094E348BFC3C8ADFD39D1B25DCEE9F744DA +:106900008E6D1FD251BFA057A1DFD0AF67C3DAD9B8 +:10691000DBF2397F287454053A10EB8978CED4CB5A +:10692000E59E729EA1732E6324FFD2C2787B289EBF +:10693000957305C8BFC33901F11FC6B87D711DD855 +:1069400017E84F4DC935D33EFA477E56B695F9CF75 +:106950007F470E6F7F4A94881E14FD32D42E488BD9 +:10696000E66406E91D66423FAF534BFCEE057FE649 +:106970002518873E219BE43FBF20E37170FE58112C +:10698000EDBBBEAF0D2ED4637DA3064E0A30BE6FA5 +:106990003B18366497D86E1340EFDE073A06F5D4FD +:1069A00005907B2C9DB173721CA1CF73F124FA73F7 +:1069B000353B24A603504A3BBE9A87F4B4B4536DCA +:1069C000A2B8D0F6C78E213D9E6E15CC6897F4B55F +:1069D000C2F1A1BFB3C1E8D643FF22A863FF650699 +:1069E0008DDBCCD7A3F883435EEF537D750AC68554 +:1069F00066EC5013DC973E2FB9D13E3BBC7DA50A17 +:106A0000EBA7DD028B837145D2EAAE04A8573E2D79 +:106A100058B430CE61283A8BF182CAE799C50BF39E +:106A200057B618C9CF5DDAA0FED817605F94BBB720 +:106A30006AD0EE29DF19DC5EB93BB80EF822F9EF17 +:106A40006886F600F9FC6D8E3186ECCD712C1BED5D +:106A50004DD6C0E3B98A7CBFDC6E757139BA82CB82 +:106A60006DC6BE8C457F5FEAFC2AE96303AFCF9118 +:106A7000EBA7A0FEF9571C2F0A5CAAE5B53F4F60B3 +:106A8000560F9CB7BA536F42FFBFBAFDEF1118B74C +:106A9000AF09F3517C9FBD2299D0DEDBD826B91017 +:106AA000BECE0EFD2E11E0567DE03D8DD988705F83 +:106AB0004EF6CAADCCB51EE3DC5E5164DD4447DD65 +:106AC00014A766B681A5384F5FBBDE847640F52BF0 +:106AD0001F74DD8DF50302D3231E47FB884E96EE0F +:106AE0004086A52DDD26E4FBE94442BC229E3D9173 +:106AF00084AF658877C433E01DF12C213E71BC5111 +:106B0000E3E6742251FDF4731CBF0ADE8BA4CD1A98 +:106B10006CAF6CE4789EB163CFB630A2033593E9D5 +:106B200080F07E7A27C7BBA6739D6614D26F630878 +:106B30001DB46B87E800F777191D84E0BF02F08D64 +:106B40007220940E42F1DF93C3E506D8DFA79F427F +:106B5000FBDB087E01F3C7234656F51E8D81F5CA7F +:106B6000A2CF3B9743FBD8F89758DA088A7F15E401 +:106B700062FC6BE63BEB105D3DB35EC8467AA957FD +:106B8000FBF63C81718BA8708AE3F427CFD9F932E8 +:106B90009CBB20FA9BA416D87FCD6B5ABADE28C9BD +:106BA0001587EC358C9729F174C033C5C99C1D5AE3 +:106BB0001E176B2DB405FA73FD09FC5C859A81B232 +:106BC000E5E817C07CB88E60E37E5E55078F172816 +:106BD0007E59951237680E8E1B08A677A85F452E42 +:106BE0008F5FA5C6DD6C463BBC7E01B387A55E4DBD +:106BF0003FF078CCD3B2DF7445FBF10A7A42B11B87 +:106C0000992B386EA1C8A96513F91E8FFEE2B86AE8 +:106C100004C6FD760B848F8A0E904F70DE0AB7DAB9 +:106C20006D1602F849EEFF19D21BC0ED8CABF6A031 +:106C30002821DD1968BF0E993EAB918EE0BC95D638 +:106C40003722F09C0E59AE38DA8D147FAB645B8A24 +:106C500090EE2A613DEF30F454F95C0BF929D7A28C +:106C600027C5CEAC6E0DEEB7317748CE8CFF1EE057 +:106C7000BB016439D77B2E99FE3223F1DE6F9099E8 +:106C800023919F87F49FC0ED3745FE5CBF1D583CA4 +:106C900060DE716E1D5305AC7FE373A6A0FA784FDA +:106CA0007C50FF9BDACC41CFB3BD1941CF738F59D4 +:106CB00082EA79DD1383FA4FF8D016549FE42B0E45 +:106CC000EA3FE54C49507D3013CE7395FBC15BE341 +:106CD00085A0FE33CDFAA0F967674405D5070D32CC +:106CE0007C64BB52B1775FCEE5F66E68A9C0F776DB +:106CF0004BF03A8ABF7EE7C4E0F5E6D882D7FBA125 +:106D000078D90BFA54057EC273A05FB1FC1DF8134D +:106D10002AF0139AC19FC0FA8BE04F60E9017F020D +:106D2000DB5F027F02EBADE04F60FD20F83F586F64 +:106D3000AB2BA6F295BA126ABF16FCBAE4758FC9DE +:106D4000EB1E97D7FD77E174429EEF5D79BE6E9C96 +:106D50002FCDFFDC593C56BC04FC3C2DFAACC68759 +:106D60007EC30A5F11C62D06DE9218C6A599DD7D89 +:106D7000AC2E06F5D9088A33B39281B731AE527D75 +:106D800020D5B4C98CFAEC0FEFE2F3BE56C98C7C67 +:106D900079A8EDEF1138CF854B61745F4A7A10EF17 +:106DA0001BBF6154DF04CF310E3AB3050408E93745 +:106DB0000FE9B70B694ADD4DF7BD25CD2D1AC45338 +:106DC00015F2293C7FCBA30E7EFE5C63D07313F6D5 +:106DD00087B24AE5A638C2B936653E2FF577A4F1E9 +:106DE0007BCF73CF1D5E3F05F56FCBE211787F5EE1 +:106DF000D5FC5EECBD57C1C7E7075FC8A4FBCA76E8 +:106E000098CFE09FCFD9AE96EB7CFF8EB496A26868 +:106E1000541CCD021B0BC505B685EE5FAADAF63809 +:106E2000506E5565DCAD66009F7E8F24C737F8BD78 +:106E300091C3C4B81DE7F92202EF575FF71CBDC329 +:106E400086F8ED381C81EBF6B74A41FED3682BB7C4 +:106E50008F475B3584BF0BAD8723F05E77A3E730A8 +:106E600087BBCA4BE73F24D7FBA12478B74974FE00 +:106E70008A4B62D03D768655A27966B68D35E2B9E9 +:106E80007A3C7CBD1CAB99B7A72D5E82FB3F1EBF31 +:106E9000204F227B100435CAF11B66EF413BA4CA88 +:106EA00023D986F3EF0AE479BBD49C4EDF4ADBDFBB +:106EB00085F2F878F1886CD2118A9F69E5766F9136 +:106EC000C69E867AA4C76036229D3F589C6A44FCC1 +:106ED0001EC212DB8B7769EC06BCC7E6EBF598BAED +:106EE0002390EE7A5A7325B47794F9F2E57587E822 +:106EF0007B086F2EC253B9BBD180F3F8F1C7DB73A7 +:106F0000AC26EA7FDCFDDE3CB4AB7A32C2C92EE9A6 +:106F1000D230F2A7AB9AB95DDCD391D818784F92F2 +:106F20006395FDF20C91F0DAD7A696FBDDBD8705DF +:106F3000F553D3392FEC0EDE8FC97DEA51B4C71D4E +:106F40004F4B0CF5A2435D1B8BE7FF6C67F0FECA4D +:106F500065383BD4DED8D8007A75B40FF18D81E85E +:106F6000BC5DE11333E153C1634F06B7E77AE2F941 +:106F7000BDA4A3650FD1F5E5F1A4EE64F41F127F63 +:106F8000A9A378E7B5FC67C56E08F0AF18FA8BEADD +:106F9000E2D43C31C56F1FBC966BABB68E44BFAB21 +:106FA00084FCCA1E06F62CACE9447B3A92F21FB66A +:106FB000E1BA83AD6ABABF76EADA667D0276D9A015 +:106FC000051805F63DB8532DDF7BD90C68D72E95F3 +:106FD000EDDACFCCF67C09F4AF738D48E7736486A5 +:106FE000911FD327CBBDCF5B92EF24BBE1986442C6 +:106FF0007F688687DBC18E666ED7567B92FF632AD9 +:10700000DAEDCD6ACCD4608A1DE294ED90D3B2DD86 +:107010007B7ACD8086FC9B4E813D968C792A5BBB2A +:1070200012E1B9337316D9B34EA999EC8965DB83A4 +:10703000ED07B06F82EA55CF85DA17727CCB13DC8F +:10704000AEF887DBAC4376C638F4670AA5A971C8E9 +:107050000F2FC87855FC9B95E32D94B7B351659ECF +:10706000A5C421105E359DFB2B70DF6E479885FC13 +:107070008D55AF105CFBBFE47E4C7F3C2378F4332E +:107080000EDFFE364EE7356AC18DF9483540B6341D +:107090009F4E70AFC138B36B3082E41363C5C8171D +:1070A0002B16707FD586315F286B157E08D1ABB764 +:1070B000A87C5254809C68B3A650BF020DB3A33E77 +:1070C0005B69B4907E1BA3E3767AE16A4F36D2C344 +:1070D00018F0C7B501F1F831860101FBED7E80C7DC +:1070E000FF9578C21C95491D15A01F195B43FD959E +:1070F000F941A2F0F1D79ADF04F31BFCF303BC23A0 +:1071000011DE5F582DA4B793E628F7FFB5C497CAE0 +:10711000792E00BD611C1863348837C7CE37C89FED +:1071200073B2EEF538AE2882EFA308F783F5305E30 +:10713000FE5196E7B179BCBC4D2E15F9D590677B11 +:10714000DF0AF59579F63F5949AE99883E57CAB49A +:1071500002F64C9C6F18F9BBE21D89F0FA05F003AA +:10716000F2FBC25AC19C16642F713AAFE14DEC3C60 +:10717000F3F44E4538B86CDD1998D7C6387F2D5AD0 +:10718000A537A705DE0720BDA3FF5102FFF2D12FCF +:10719000E3BF7253C56D9457B52AD68CF71735C81F +:1071A0000F29D7A6FF50BA87DF4EA4B76AA6B5A0AD +:1071B0007EA9690B7D6E51A13DFE4D085F24C97407 +:1071C000DA6817E87EBDF15B158FA3950A1437BB0B +:1071D0000B1A914EE987FDCAA7B9717ECCB3A0FB0B +:1071E000AE861839EF2B86EEE17E229FFF2E95F7B3 +:1071F0000DE4EFA36A4F32C6718E3AF93DD502E62F +:10720000A17BDD52D64D656F78F5012F4DEE1A8DBD +:107210007EF807762DC5911AD7361951CE66B1B5CD +:1072200026BC1F033679EEFBDC2BDB1BA1F7689431 +:107230009F95E7C7F3CABC92F83CA0833380A3F8BC +:107240009CCBC757BD7F2002E17EFEFEFDF37ECAC8 +:10725000D00F02B905F354D6B664D0BD8C8B7567D8 +:10726000E4FBF1ABE053C11FB49983F00A67B90E98 +:10727000E0339F0DE4636ED3B5F0A9C039493DF00A +:10728000630425E8319243A17856E05ECD6AD53C8F +:10729000FE56FBEE02E8FFB3B5A219EDCACBF07EB5 +:1072A0000DFC78F5FC91D728903F7B257C29785AF6 +:1072B000C8BC54FF308A8FFB70A144F1C3FF697CC6 +:1072C00035E4D94BF2AEC2B7A17C7A25BE5CB42AB4 +:1072D000847F43F874882F2DF02F007FF65511C45A +:1072E0008F0A7E1D66F09351FF75182D6E76393E1C +:1072F000D1DFC5FD54B60AEC49E187F0AB8FFCE362 +:10730000507C01ADD8501F54E705F3A982C72BC9A3 +:107310002D45EE7DC4BC474D02DD67703EFE85966F +:10732000F2E994FB0CE5DEE2D13CAE6F42CB8FC0BC +:107330006EC17BA24D193D23D1DEEBD528F3F07B46 +:10734000D78FD6748FC67CCD8FA6F1B257C3F34CBE +:1073500094BA2D8CC7033F4AD0BA106E1F09E3A61A +:10736000A31DF091F0CB3B783D4E63C6FA82B8E99D +:1073700026A8F7AA95F8E183B2FC7653F9D18209E1 +:1073800005D44F6047101E668195D03A82105D0C7F +:10739000FBF9E8E76373F05E4039FF03793C8EF454 +:1073A0001BF91C43F1F65F09146F5F04AAC384F74D +:1073B00002D39F284E81F693BF4ECDA6FBCA15C1BE +:1073C000EBA3FE4DA638E5569AE7964B03EAC5991E +:1073D000FE7D0DE9CD828BBC7DC9D8A07C665BF4B7 +:1073E00038EE27BB5323518F297A6DF0D87E436046 +:1073F0001CF5AC1C771EAA8F7B2429502FBEB1F739 +:10740000E1749CA75CE3CAB218308FF9A924B41FB9 +:10741000CAF73E944E76EDDE8DE9E89F94373D9CA9 +:107420006EA37AB89DFC23153FF7F97D93766D0A1C +:10743000B0A36F9DC0EDFB52DD1B8568DFCEBAF1B6 +:10744000F37518B71FFB6B81E2700B59F73AD4B78D +:1074500065199CAF58838EE43FCC47F7A47BC6DD0B +:10746000BE1BE5FEF18CBFAB97A0FECD53D17C6572 +:10747000CCBD390EE36F1B048ABFF9FB8FA67BD707 +:10748000C56B054D7C0CEA519E77FDC7BC2882E395 +:107490003D1BB2BBB0BD6C356F9FA575B7F6E03C28 +:1074A0004F6828CF0A14654A49C03DF61FF3F83DDE +:1074B000DDA2CD72BEB1BCCED86DB18D81E7FCA38B +:1074C0008C7F56FE01C9833B65BCDCB6FABD23F157 +:1074D000306FA4DAFE67942BEF3E7E3A0DE55941FA +:1074E000F4D94CA4F3B11AFB931578EE262DC52BD5 +:1074F000AD5989521CF4CFB97FDA63582E5ABDF8C2 +:10750000C90A8CFB6ED7911FA6EC6F856016D15F00 +:107510003DDCF8D37B106E671EE779A42B1AAF8F82 +:10752000BB5AFEE2B3753C1FFCF93A1D952FD49966 +:1075300098198EB8AF2E9EEABFAF3353C9E673FADF +:1075400052F2A6AE345FEEA530CA5BB66ED0511EC5 +:107550007DAED6F6551EC06BEC0DCEA68DF2B9C62B +:10756000C2F86C57F20C848375E3F22E34614FE558 +:1075700071FFEAED9E0D496487AF3EF54C053CCFA7 +:10758000CC2FF90EC7EB765EA478C1E1F687CA105E +:10759000DEE54D5A7E3EF9DC671E4F8F7B12E3BC61 +:1075A0006FA9C97FAFD979EA998D50DEBB79B92629 +:1075B00090DE7FE879BF95F7732DBEBA121CFE7579 +:1075C000BE7A3889F8A709F82AF3DFE7AB9AD56BBA +:1075D000087E73F34BC6E6C3FECFA85D49C84F676C +:1075E000C6DD4C74EEEA1408FE8A1C57C6A7E6F303 +:1075F000FBE82AD1B399EC48598E7F059E23C2F748 +:107600008DF6CFD2D18EFEAA6DC155CF7DB00E3D85 +:10761000228C9BE9A80C7D9EAFB1A7625E71BEC8AB +:10762000EDE7D0E7B7E72B71781EB7C59F1090A79D +:10763000E2848D4546A3FE13BC6120979D6DB79EE5 +:1076400055A1FF067EE1C7C17628FB3840AF5F69D0 +:10765000BFD72AAB711E955FEE4EF85064DE003D39 +:107660003EC917C6BC01EB0EF92BD0A6A1FB9E04A8 +:10767000920B8837CC87EA6B1FD784F5B31A8EC775 +:10768000BE83E097F1B80C93F2FDE73CDB7E3E0B46 +:10769000E56CE879AB5F394FF4E1687BE8A240E73D +:1076A0009F79569575EDF3BFB1F77C16E2EFACDA32 +:1076B000978FFE579FC6978578A87E95CBF37F1549 +:1076C0000E4A7BC5060D8F130A26F2230BA50B1459 +:1076D00007E83BC6E300D5EDBB489E0E76F0784C3C +:1076E0008DD85D1487F18BDA535D28CF06E3B95F3F +:1076F00006F3DB28CF2155D683AA81A43920D71ED3 +:1077000019A207EE0F9E41FED5E03C1E07E561651C +:107710008533B42BCE213F437BD9AAE4F548E767F4 +:10772000DC2373503EBE9DF58F6A8ADFBD1E6E92CC +:10773000C88E9530C778084E43E7704B3CD18729F7 +:10774000767138B305F4ABD198EF24BFFA38BF9FF8 +:10775000ABB981F3137B85F39373ED1B9AF880F932 +:107760007E25F393624FCE7AFD1FC4970FE7DA9E12 +:1077700040BE0C475988F3C547521EB5F21E8772AA +:107780001F69E890FDF862899ED7B4490CEFE5586F +:10779000BC91F20A8AD916CAB79CC53C53795E8F50 +:1077A000EFD129F07CF6EB522EE6A1813D4DF7DBBF +:1077B0004561F634CCD3EA150519AE1EEB9C007D6D +:1077C000F67E3EF757A74A02E9B1818470B253664C +:1077D000CE7796E27E957E5A91EB339887EC2CE635 +:1077E0001EC8C27B55E61DC8C2FB56A5DFBCD7C369 +:1077F0006B492F328F755EC03AA7F379BCF30BBC8F +:107800001F07795223DFC3164ADF6E437F6B45277C +:10781000BF7FEC15933FC03C3317C019F17A1EF0BF +:107820006A43FD6367361BF2CFF8916EE49F9A7D41 +:1078300002C37CBDEA766D13C685AAD5BE58A4E7FF +:107840008D6DEF6B909E6BF05E763C8E6772BCDC4C +:107850004479BF3526C6EFF5DAAEFF00E376CE6396 +:107860005C8B3A55EF513C00E536AE57D5DA42FE17 +:10787000BF8379C9FF773407D3CD603C8FE787F2A8 +:10788000C9E97C73107FCCDCCEF9631EE6731B68FC +:1078900038C55F67C6C7915DE21FC7F16093CEAF81 +:1078A000433BA63F45A07CFCFE30D75AB48F5CE931 +:1078B000DCAEE97FED052BBDF7A3735B7F8CF93C54 +:1078C000B2DD3B73C3569514B09F991D3CDED81FA3 +:1078D000C6CA0F12DEEDD7213E7CB92567F231BE54 +:1078E000A31978770AC683441E1F0D3D875D8E6BF2 +:1078F0001C67FCFD2865DFB31313B93C636EA2A3BC +:107900002E39BF5BC9D751C6DF324150EED1B89F87 +:107910002458AEFA5E1ADED7609E2BDED760F93BA4 +:10792000391F16EF6BB0FEA29C0F8BF735D88EF780 +:1079300035586F95F361F1BE06EB785F83E52B72E6 +:107940003EEC71DC2AE5F16D7C0AE9A20B796D94BD +:10795000BFDE1B1D521F15DCBF375A08AE8F12A8A1 +:10796000BF69C2C6A730FF7893922FC5CC46B4C377 +:107970002AC2F9FB1AA9067BEC04F4F38B77ED45D8 +:107980007F1EF89BDE9F2B885E504AEF97C46819D4 +:10799000CAA3DB27D8474F80F1C78ECD48DB4A7298 +:1079A000524FF7ECBD3FBB3192E27A6F494C8225D2 +:1079B000A765E4AEB5427D9A4120FA85F96E2A5159 +:1079C000FC4C986746C762AB8ACB0713DACB85922B +:1079D0006309AEB322419F8B72F888D59E81FB511B +:1079E000E05D346A591ADA455D6AF307189F75BD80 +:1079F000A366E85729713CA5DF93D669F9B8BF990A +:107A000019A96B73707E60369477360D6BC6FDD9FD +:107A1000C470A19EE4975985F2207F02A79BE96676 +:107A20006E1F7B35665534FAF561D362F05EB74B55 +:107A3000C6F33119CFC7653CE33D57818ADF7361D7 +:107A400089F75C5886E6A32DCF2FB14D20780F24FF +:107A500005E6B3CD92DF97000AA1F7D49C721CF320 +:107A60004B59EE34E695DCCAC779689E2A398E7781 +:107A70005E1D7C6FA88CF38F6754CEBD89CB6B16CF +:107A8000A9E179BFD73117E615CF7D3981E2507D65 +:107A90006ED1A506BCCF055E4779C65EE6FE2E8B8D +:107AA000E77C33777F1CF5AB97E3A9CEE8EE747CD7 +:107AB000AFA34FE62FA57EF03B9E97E4CC81BA8121 +:107AC000DE23A1F339E776A74741BD4FD08B485F4E +:107AD000CE26FEBC47E63F678A3C9F7C1EA6F32469 +:107AE000213EFA3B5F4EC2F7103719BC4BB9FCF789 +:107AF000A693DC66DE74CC6F3A2F784E62BEF1AD91 +:107B00006D29A5986F7F5EED7906EBB3DBD2785DCA +:107B10006839690A7C3ED29384F9C8B7B6A59662E3 +:107B20003EF2F9912DCF445902EAEA974EE273CD25 +:107B30008369A5989F3C5BEB3E568774F37B4E5F51 +:107B4000FA7D074E237CAADAB9FD3E7DDF810B2F3B +:107B5000A17E3E60A4BC8275139209DFF5EDCF6E65 +:107B6000467AEB6B51133F6C6A7EFF99DF503F2DD5 +:107B70008559666B3D560CC994B41DBA1BF7353B4D +:107B8000DCF325D6174FBC89F6317B04E7EBA51350 +:107B9000734A914FFB0EECFB05EAB3D99160D8E232 +:107BA0007E5ED0137E2AF78F2BC0B8409FB1BB0CEE +:107BB000E7AFFE9D96E71FEC8F9B8E7182FF9CC006 +:107BC000F3312A6ED89284FA567CE5F9BDBFC1F82C +:107BD000E6EFF474DF5313CDEDBD4AA9317F39E1EF +:107BE0006FD75ECC5BE97B5E4FF7AF151893B3E2BE +:107BF0007BAC63293EFFEA3FFF5E8678289476EEF1 +:107C0000C5F62F77EB4584438FC6167933F2618F23 +:107C10009AFCCE0AB95ED13B82EF27DC5744F88B41 +:107C2000D99284FAB672C4AFEEC07DCF96B63C83CB +:107C30007E0F7B564B770E679F07B8C1B8B37BD4D6 +:107C4000984903FB30AA905ECE0B5BCA9EC4F9F73D +:107C5000F07EE7F55B089EAE3DD7335C0FFA31D47A +:107C6000C7E785AD41ED67F73C9B857EE9B9DFCD80 +:107C700026FF54A173855F2A776B83F422498258CB +:107C80008C5BCA3F938B1902E259E70EEEE87B92B8 +:107C9000F9C79F6B567B3500A30A2D5B8BF9CD0A84 +:107CA0003F5426DE5A8CE7AB141BD3D17EA9C8F50E +:107CB00095215F9CD5335D3CF47B5BD65B95AD6BCA +:107CC000E6A01D7CA5FDFC4596475FC97CF8559B49 +:107CD000DE1D78DF185AFEB58E994FA8FCF585B5E4 +:107CE0005AB2E595F9DED6781CE8AF554773F971BD +:107CF00012FA37831CFB93ACEF16AD0AEEFFEE04CD +:107D00009E4F59ADF1A5A3FE53E67F7B8289DB87A9 +:107D10002A5F3ACAABD071B32559DEBC2090BCA90A +:107D20006C154ED1FB2408D2583F3C2B752E37E6FC +:107D3000130D8787F87C190F12E6F170BEAA6CD676 +:107D4000DBF4304F55982F02ED2587D117817650FF +:107D5000DF2B126B92D117A3CC9FE25F4F89535652 +:107D600078D436FD70EBC171D04F5E867F03285604 +:107D70004FE47C53DE164EEB31932F1FE9B67C6740 +:107D8000F0383CA729801FFBDA76C506FAEB0CF722 +:107D90004DF751A7886FFAFFF931BD075E29B2B5DB +:107DA000784F794EE0EF83409DDE073927DF775625 +:107DB0007E6D0843FA39F79583F8B84FF0919C7BB4 +:107DC000B1CD4672AC4FED2339B76B6211AF47F9B5 +:107DD000CA506EBD38F1A7243FFA127C65F89ED2D6 +:107DE00066A58E2FCC811DD0D1B690E4C96C89E7F1 +:107DF00051B05D6A138F1371782F93E1C4D886DE7A +:107E00003AF243D466B4973A272AF7421AFFF92583 +:107E10003F3FF531F3BE56E4CF7203C57DC0BE6A65 +:107E20007E09EDC005B1168CA787C24DB95F8C895C +:107E3000FE6629E2E91DA37DECC43CBCCFF4919F12 +:107E400001D44EF67CF56B5AF237FBD5037B517E9D +:107E5000B98DF67113019E0E4DF77A547117D4BE89 +:107E60002E34ED6721BD911CE1F4D697B98BBF0785 +:107E700022DF4F4E92F100FA8C35227D081CCF870D +:107E8000DBF69F4079D3D79D4A723A949FCEB63D98 +:107E9000168172E343D0EFAE8078C0878B9FA57CBC +:107EA00080F9980702E53D6B83CF37F8ED8FC92F36 +:107EB000649B03DA911E1B82EBA17041BAF406F1B8 +:107EC000818BF67D3FF21BC0A76A7A7735C261A825 +:107ED0003E17EA5240FD50483DA43F2BE1F6C3FD5A +:107EE0001318CDEB18EDED253F7E1FCFEFAD07BD8D +:107EF00046F503E1743F2DEE03BD15C3F516EA8B7D +:107F0000AA886E8A5FF51DD0D2BDCA83ED9F25E198 +:107F1000F9811E294E53D5FE722CFAF7EB2698698B +:107F20007ED08FB1941773A03D16FD11A5DD217A87 +:107F3000D2E5F70CB2507E28ED4EC99B4E79E54252 +:107F400077163E5F27CB1987087509EB8CCEE110B9 +:107F500038DFB37689E47C28DE56C9F40AF2218B37 +:107F6000F2395EE1F103451E54C872E510B667723E +:107F7000FE3729F75278CF847C3F8C9CF85A8123B6 +:107F8000ABA5F8CEFD13CDBC2E8FA77979FC89E780 +:107F9000EDBD7A3E2B2513C79995F745FDF228D5FF +:107FA0002F5F500EC4931C78501D0BE7AA7C46B07F +:107FB000D4C3908AD23545D09D2D532D2FA2B81A07 +:107FC000E6E71A2EDF57281D454EE4F8AD14B91F19 +:107FD0005EB957A0FBA5736A7E6F07F286DE0F5865 +:107FE00056B0A608F9EFBE18A726D05FBED6FC4B48 +:107FF0001B82EBCB6AD714C50DC3E795ABB6768D64 +:108000006497CF57616F2C8A355FDEAEECFB9C5EC8 +:10801000D9E774F5C84078CC5F533412CA65BA7F8B +:10802000171EFCDCE7DAB55ECA572D5D43F7C4B70F +:108030005CAA0D8AB35E6BBE0AE6A67B902BED3F71 +:10804000B47408DE5E8C2B31E0AF3DC467C03701ED +:10805000EBC5CBF43A149F285F3C06FD53665F3CAA +:1080600026303E115AE29B3322E58AB8A8043E2C02 +:10807000B30C030FA5FFD1893CCE1A3F91D3F1A8D1 +:10808000D9553B5E6214D7E941F97BA5F74CFE2236 +:10809000EFEF07BF6732239CF7EBD49B30FED3DFB3 +:1080A000F90DC587FBD719E6F37B07034B80E75D26 +:1080B000F1E39B02E3C0AB26713B24DCCAED9D9A41 +:1080C0000CF5D5E34B99C6A1F812D91B99E174DFE1 +:1080D000D2D7F605E9B7FE8E3C13DE8BF475BB0DE7 +:1080E000C86F35FFFC7FB1A887FB3A3EA5BCB4BE84 +:1080F0006F3FA37CB58D72DEE0A13639DFABDB6C60 +:10810000C4F6FEE2BF1761BF4D72E98F2FF0F898F9 +:10811000522AF18300FFF93BD4537B4C1B1FC554FB +:1081200099CAB02D24BFC07F8E46BDE18F2B98E346 +:10813000868BC304C615D2543CAE8025C615D2D258 +:10814000785C01EB1857C012E30AD88E7105AC6356 +:108150005C01EB1857C03AC615B0C4B802B67F2907 +:10816000BFE7D10F828BC73D0D24F757627E33C026 +:108170006F6527BFBF5AB947A27B617CCF03F5DF8C +:1081800065793BAD72DE8E672BDD07D61C902C889F +:10819000227C1FC4958EF93B0347311E54D32258CD +:1081A000D698B17D3EED636347DE07A5D8BE476D27 +:1081B00011CD444F1C9F8D825B8F7CD5B187E257D8 +:1081C00005719D94EF5FD32C308CBBCED3723FD919 +:1081D00029416B0EDDAB921DEDD47693FF52F59CD9 +:1081E000600E7CEFBB66E2459213CA7DF552FE88B5 +:1081F000393D7AF392203D6BE37957F827ECC72994 +:10820000E777931D1260172DC57B6C6C97BEA5F7A1 +:108210004D9CE0E08E10AE9D7755D9D1B21EF3B5DE +:108220007E68FE55E124F9DE3A9BBF4752FCF89286 +:108230007D0760BDC12D5AB2536E9F60BF6D521E47 +:10824000E619D828EE72B4534F7ED6275BAF0F8A5B +:10825000BB144AD751DC63855A20FD7DC46A9F3B1D +:1082600009E87246F1BD146F99116F243E56E8F08B +:10827000496BC94F70DE15E3F977980AB5ECE7341E +:108280009F9CCFA5E0A9B05E70E3F72C16330BBD21 +:108290003FB008C0877151E5FB1F8B18CFAF50E886 +:1082A0006AC55681E88ABEBC10F0BD8445F83D1011 +:1082B000D07FF76AB9FD9B28F27BF2C44D3C8FE278 +:1082C0003E66A7FC9165487D12E9D7D77CD06E0F3A +:1082D000BF2E89DBF7E6389C7FF17135E50717C6BD +:1082E000DD9E6E273D5F40F91382F76EE9FB1BAF01 +:1082F000263F83F3278EAAB9DC0178929FD585F4B7 +:108300004AF11E3B95C7EBCAA99C22BF1F16FA5E15 +:10831000437FE7CB2D38BEB0C66041F85FF13DC06A +:10832000B0ABBFFFE694F3EB12C59E5C33C2E36BC8 +:108330008305E15118D749EF89A5CAF33F9C5BB289 +:1083400009F1698B602E5C1FEF69B6007C8BF040F1 +:1083500002C6D13D367CCF66A05330513EF56572E2 +:1083600074EB3ACC53A949134C18AF2D0ADB5218C1 +:108370000BF317A524D377766ADA781CB60F4A4E2A +:108380000753DC92C0C7AA62317ECFF1E8CBB53F7C +:108390003D29CFDF3E5BE6B3FE8E2F781EF1B5E3BD +:1083A000B4BBE9FB1C4C4FEFAFD30FF635FBC6D186 +:1083B00014AF55E868B039AE09E9A845D613A5A5AC +:1083C000EFA9D18E68CCB337231CCA965C5C174BDF +:1083D000E71C3E4EA6E4DF87C6C902E5EDFF46DE98 +:1083E000FD89BA5A2ADFAD5B4565779D8B9E07E80C +:1083F0008B2308BF1F106F7D7BD230F156A6334709 +:1084000092BE05BEE7F1ED90F82AF0BB18C0EF333D +:108410003AA2EED980F64883C682F7CD98FFBCD247 +:1084200040F2E1FD49C3C65915F819282E3BC8F49E +:10843000398887E919A92A119EFF6D921014E74423 +:10844000BEC17322DF60897CA352F9F9E6690DA3EE +:10845000EF94A17DE022FB404FF85DBF06E40AD413 +:10846000EF65A620B9722144AE8023F3337A5FAC66 +:1084700043CB3609FEFCCFE9505CCA1946CE78B82A +:108480009C191DE6799EBEB3501D46F9C5C0EF4448 +:10849000674737F2BCBD25AC84D61D46DED07B3E97 +:1084A000F78E1838F914F4BFF76103D939EB139636 +:1084B000E6FF77E4CD9F2771783C81DF73505DED57 +:1084C0007B0E9B05BC8F5DB1906523BE95EF39C4D3 +:1084D000C118F27BFFF5EF398C983C12BFE7E00A38 +:1084E000FA9E43DC15BEE7306AB27161E0F71C46C4 +:1084F0004D1EB130F87B0EC685F89DB2FFC1EF3935 +:10850000A44FCEBBFC7B0E374E36FFA0EF39803D2B +:108510009B89E34FE4D8C66399289F3BF4FDE5E3CC +:10852000F23D6497682FC5B228C2A5A276D16DC569 +:10853000F26DD1733FB6035F4C4478153D967D03D1 +:108540007E972551EBA1BCF227ADB64938FF6BB938 +:10855000B6C9F83C34DE5F2F9F0FF6730BF60BCDD8 +:108560001F53E8E2AEC95C0ECD93CBA9F5C3BFC7DC +:108570003F6F32BF4FBED6BE61BF77E07ACAFED929 +:1085800096C556DC0FECF74EDC27ECB7044B66883B +:108590000E7A0FF8727A75C9FB62742E908FB33F12 +:1085A000E1F62895E92A7714DA0DA31E7047E17EDB +:1085B00047350EE8F17D90DFBA06F4683FFC76F5AA +:1085C000801EDB7F6BE3F9DAA1F36F9FCCFD91F4A2 +:1085D000A903347E0CFCDD4DFEC14014DA6DE9E5E3 +:1085E0004734AE147A4F6DF62741769399F87B8C19 +:1085F000DC36E60191213D8CD9C1781E63410CE93E +:10860000B94A1DEF5AF9C0FD22D2D13837EC3B8070 +:10861000FEAEDFAE1A0C7EAFD74BE3AAE425C05EF8 +:108620000B7AEE643CBF74942C8FD05EC4EFD939C2 +:10863000CB8FD077A6C08E0B998FBE7930944F59CF +:10864000ADB3BFE63353BE6250BFA577FF663DFAB8 +:10865000B5E5A55B35E4172F69598FA5C3F19E26B3 +:108660008E917D19D41FECCBA0FA65FB0CD947F590 +:10867000FD17D7C70DB32ED0C156A413850E8EAAF1 +:108680003DE3D04F3DEA0CB3F0F71D3CF45D9A2674 +:10869000F9BDF45DFF39DDCAF365395DC0F81D3FF2 +:1086A0008C8EEAA9BFF21DAF6B958A1C1CFACE8D89 +:1086B00086B9285E39CB4872AE46F6FFAA9798C8AD +:1086C0001E51F8BA5AE539B51EFBC51879FE9B8ACA +:1086D000D1F7AB7AC45194CF4D3FACCF4AA5FBAC98 +:1086E000D87A8F17E71DB85DA0EFB9158473B95A12 +:1086F0002896389E85E74744FE5D81A7517E4898BD +:1087000047C1BF37302597BF3F10CFF877DB98CAF6 +:108710001CF29D36391E7AEDEFB4F1EF92CDE7F7FA +:10872000720D5125A5CBF1F9821BE8F9C1EF521F5B +:10873000B1E2FE2A94EFB4717BBF614E063D7F55D6 +:1087400030AF413DE17A805DE93B6D7AE4FB80EF3B +:10875000B3BD87F8BAD6F7D994EF0F1C5D70C32369 +:108760007B391CBD78EF5533CB18E4AFFF17313C94 +:108770009ED2C05600000000000000000000000073 +:088780000408350000000000B0 +:00000001FF diff --git a/firmware/bnx2x-e1h-4.8.53.0.fw.ihex b/firmware/bnx2x-e1h-4.8.53.0.fw.ihex new file mode 100644 index 0000000..48d7612 --- /dev/null +++ b/firmware/bnx2x-e1h-4.8.53.0.fw.ihex @@ -0,0 +1,12028 @@ +:10000000000039D8000000600000063000003A40CF +:100010000000191C000040780000009C0000599866 +:10002000000082E400005A38000000D40000DD2007 +:100030000000C7CC0000DDF8000000780001A5C872 +:10004000000056980001A648000000C00001FCE82E +:100050000000F1D40001FDB0000000040002EF88B0 +:10006000020400480000000F020400540000004594 +:1000700002040058000000840204005C0000000636 +:100080000204007000000004020400780000000078 +:100090000204007C121700000204008022170000F6 +:1000A00002040084321700000604008800000005E6 +:1000B0000204009C12150000020400A0221500009A +:1000C000020400A432150000060400A80000000489 +:1000D000020400B802100000020400BC001000007E +:1000E000020400C010100000020400C42010000030 +:1000F000020400C830100000020400CC40100000D0 +:10010000060400D000000003020400DC0010000020 +:10011000020400E012140000020400E422140000B3 +:10012000020400E832140000020400EC4214000053 +:10013000060400F000000003010401240000000098 +:1001400001040128000000000104012C000000004F +:100150000104013000000000020401D00000890603 +:1001600002040004000000FF02040008000000FF79 +:100170000204000C000000FF02040010000000FF59 +:1001800002040014000000FF02040018000000FF39 +:100190000204001C000000FF02040020000000FF19 +:1001A000020400240000003E0204002800000000B9 +:1001B0000204002C0000003F020400300000003F59 +:1001C000020400340000003F020400380000003F39 +:1001D0000204003C0000003F020400400000003F19 +:1001E000020400440000003F020404CC00000001AF +:1001F00002042008000002110204200C000002008A +:10020000020420100000020402042014000002195D +:100210000204201C0000FFFF020420200000FFFF5A +:10022000020420240000FFFF020420280000FFFF3A +:1002300002042038000000200204203C00000000DE +:100240000204204000000034020420440000003575 +:10025000060420480000001C020420B80000000131 +:10026000060420BC0000005F0204223807FFFFFFE5 +:100270000204223C0000003F0204224007FFFFFF6F +:10028000020422440000000F010422480000000084 +:100290000104224C00000000010422500000000074 +:1002A0000104225400000000010422580000000054 +:1002B0000104225C00000000010422600000000034 +:1002C0000104226400000000010422680000000014 +:1002D0000104226C000000000104227000000000F4 +:1002E00001042274000000000104227800000000D4 +:1002F0000104227C000000000C042000000003E840 +:100300000A042000000000010B0420000000000A85 +:1003100002050044000000200205004800000032F1 +:10032000020500900215002002050094021500202D +:1003300002050098000000300205009C0810000033 +:10034000020500A000000033020500A400000030F8 +:10035000020500A800000031020500AC0000000208 +:10036000020500B000000005020500B40000000610 +:10037000020500B800000002020500BC00000002F7 +:10038000020500C000000000020500C400000005D6 +:10039000020500C800000002020500CC00000002B7 +:1003A000020500D000000002020500D40000000198 +:1003B00002050114000000010205011C00000001FB +:1003C00002050120000000020205020400000001F5 +:1003D0000205020C0000004002050210000000406F +:1003E0000205021C0000002002050220000000138C +:1003F0000205022400000020060502400000000A59 +:1004000004050280002000000205005000000007E3 +:100410000205005400000007020500580000000813 +:100420000205005C000000080205006000000001F9 +:100430000605006400000003020500D80000000665 +:100440000205000400000001020500080000000190 +:100450000205000C00000001020500100000000170 +:100460000205001400000001020500180000000150 +:100470000205001C00000001020500200000000130 +:100480000205002400000001020500280000000110 +:100490000205002C000000010205003000000001F0 +:1004A00002050034000000010205003800000001D0 +:1004B0000205003C000000010205004000000001B0 +:1004C000020500E00000000D020500E80000000742 +:1004D000020500F000000007020500F80000000718 +:1004E000020500E40000002D020500EC00000027DA +:1004F000020500F400000027020500FC00000027B0 +:10050000020500E00000001D020500E800000017E1 +:10051000020500F000000017020500F800000017B7 +:10052000020500E40000003D020500EC0000003779 +:10053000020500F400000037020500FC000000374F +:10054000020500E00000004D020500E80000004741 +:10055000020500F000000047020500F80000004717 +:10056000020500E40000006D020500EC00000067D9 +:10057000020500F400000067020500FC00000067AF +:10058000020500E00000005D020500E800000057E1 +:10059000020500F000000057020500F800000057B7 +:1005A000020500E40000007D020500EC0000007779 +:1005B000020500F400000077020500FC000000774F +:1005C0000406100002000020020600DC000000010A +:1005D000010600D80000000004060200000302200B +:1005E000020600DC00000000010600B80000000068 +:1005F000010600C800000000010600BC0000000069 +:10060000010600CC0000000007180400009B000059 +:1006100008180798000D0223071C0000325E000036 +:10062000071C800035960C98071D00001AEA19FE79 +:10063000081D43D057860225011800000000000065 +:10064000011800040000000001180008000000006C +:100650000118000C0000000001180010000000004C +:100660000118001400000000021800200000000122 +:1006700002180024000000020218002800000003F5 +:100680000218002C000000000218003000000004D6 +:1006900002180034000000010218003800000000B9 +:1006A0000218003C00000001021800400000000495 +:1006B0000218004400000000021800480000000179 +:1006C0000218004C00000003021800500000000057 +:1006D0000218005400000001021800580000000435 +:1006E0000218005C00000000021800600000000119 +:1006F00002180064000000030218006800000000F7 +:100700000218006C000000010218007000000004D4 +:1007100002180074000000000218007800000004B5 +:100720000218007C00000003061800800000000290 +:10073000021800A400003FFF021800A8000003FFF9 +:100740000218022400000000021802340000000019 +:100750000218024C00000000021802E4000000FF32 +:100760000618100000000400021B8BC000000001EE +:10077000021B800000000034021B804000000018B3 +:10078000021B80800000000C021B80C000000020C3 +:100790000C1B83000007A1200A1B83000000013806 +:1007A0000B1B830000001388021B83C0000001F4B0 +:1007B000021B1480000000010A1B148000000000CE +:1007C000061A1000000002B3041A1ACC0001022716 +:1007D000061AA020000000C8061AA00000000002AF +:1007E000021A1AD000000000061A1AD800000004ED +:1007F000061A367800000006061A3670000000025D +:10080000061A500000000002061A500800000004FA +:10081000061A501800000004061A502800000004B0 +:10082000061A503800000004061A50480000000460 +:10083000061A505800000004061A50680000000410 +:10084000061A507800000002061A4000000000025C +:10085000061A400800000002041A62C000200228A4 +:10086000061A20000000016C061AB00000000028E3 +:10087000061AB1400000000C061A32C00000001237 +:10088000061A335000000064061A810800000002B6 +:10089000061A25B00000016C061AB0A0000000285E +:1008A000061AB1700000000C061A3308000000128E +:1008B000061A34E000000064061A811000000002ED +:1008C000021A2B6000000000061A3000000000022F +:1008D000041A300800050248061A301C0000000700 +:1008E000061A31C000000008061A5000000000027D +:1008F000061A508000000012061A40000000000294 +:10090000021A2B6400000000061A303800000002B2 +:10091000041A30400005024D061A3054000000074A +:10092000061A31E000000008061A5010000000020C +:10093000061A50C800000012061A40080000000203 +:10094000021A2B6800000000061A30700000000236 +:10095000041A307800050252061A308C0000000795 +:10096000061A320000000008061A5020000000029B +:10097000061A511000000012041A4010000202571B +:10098000021A2B6C00000000061A30A800000002BA +:10099000041A30B000050259061A30C400000007DE +:1009A000061A322000000008061A5030000000022B +:1009B000061A515800000012041A40180002025E84 +:1009C000021A2B7000000000061A30E0000000023E +:1009D000041A30E800050260061A30FC0000000727 +:1009E000061A324000000008061A504000000002BB +:1009F000061A51A000000012041A402000020265ED +:100A0000021A2B7400000000061A311800000002C0 +:100A1000041A312000050267061A3134000000076D +:100A2000061A326000000008061A5050000000024A +:100A3000061A51E800000012041A40280002026C55 +:100A4000021A2B7800000000061A31500000000244 +:100A5000041A31580005026E061A316C00000007B6 +:100A6000061A328000000008061A506000000002DA +:100A7000061A523000000012041A403000020273BD +:100A8000021A2B7C00000000061A318800000002C8 +:100A9000041A319000050275061A31A400000007FF +:100AA000061A32A000000008061A5070000000026A +:100AB000061A527800000012041A40380002027A26 +:100AC0000200A294071D29110200A2980000000054 +:100AD0000200A29C009C04240200A2A000000000CE +:100AE0000200A2A4000002090200A270000000009F +:100AF0000200A274000000000200A27000000000CA +:100B00000200A274000000000200A27000000000B9 +:100B10000200A274000000000200A27000000000A9 +:100B20000200A27400000000020100B400000001F5 +:100B3000020100B800000001020100DC0000000119 +:100B40000201010000000001020101040000000197 +:100B50000201007C00300000020100840000002837 +:100B60000201008C000000000201013000000004BE +:100B70000201025C000000010201032800000000E5 +:100B800002016080000000010201055400000030F5 +:100B9000020100C400000001020100CC00000001BD +:100BA000020100F800000001020100F00000000155 +:100BB00002010080003000000201008800000028CF +:100BC0000201009000000000020101340000000456 +:100BD000020102DC000000010201032C0000000001 +:100BE0000201608400000001020105640000003081 +:100BF000020100C800000001020100D00000000155 +:100C0000020100FC00000001020100F400000001EC +:100C1000020C100000000020020C2008000002114D +:100C2000020C200C00000200020C20100000020444 +:100C3000020C201C0000FFFF020C20200000FFFF20 +:100C4000020C20240000FFFF020C20280000FFFF00 +:100C5000020C2038000000C6020C203C00000000FE +:100C6000020C204000000034020C2044000000353B +:100C7000060C20480000001C020C20B800000001F7 +:100C8000060C20BC0000005F020C223807FFFFFFAB +:100C9000020C223C0000003F020C224007FFFFFF35 +:100CA000020C22440000000F010C2248000000004A +:100CB000010C224C00000000010C2250000000003A +:100CC000010C225400000000010C2258000000001A +:100CD000010C225C00000000010C226000000000FA +:100CE000010C226400000000010C226800000000DA +:100CF000010C226C00000000010C227000000000BA +:100D0000010C227400000000010C22780000000099 +:100D1000010C227C000000000C0C2000000003E805 +:100D20000A0C2000000000010B0C20000000000A4B +:100D3000020C400800000411020C400C00000400EA +:100D4000020C401000000404020C401400000421B6 +:100D5000020C401C0000FFFF020C40200000FFFFBF +:100D6000020C40240000FFFF020C40280000FFFF9F +:100D7000020C403800000046020C403C0000000518 +:100D8000020C404000000034020C404400000035DA +:100D9000020C404800000007060C404C0000005BBD +:100DA000020C41B800000001060C41BC0000000329 +:100DB000020C41C800000001060C41CC0000001BE1 +:100DC000020C423807FFFFFF020C423C0000003FCC +:100DD000020C424007FFFFFF020C42440000000FDC +:100DE000010C424800000000010C424C00000000D1 +:100DF000010C425000000000010C425400000000B1 +:100E0000010C425800000000010C425C0000000090 +:100E1000010C426000000000010C42640000000070 +:100E2000010C426800000000010C426C0000000050 +:100E3000010C427000000000010C42740000000030 +:100E4000010C427800000000010C427C0000000010 +:100E5000010C4280000000000C0C4000000003E880 +:100E60000A0C4000000000010B0C40000000000ACA +:100E7000020D004400000032020D008C021500201B +:100E8000020D009002150020020D009408100000D1 +:100E9000020D009800000033020D009C00000002CB +:100EA000020D00A000000000020D00A400000005DB +:100EB000020D00A800000005060D00AC00000002B5 +:100EC000020D00B400000002020D00B80000000393 +:100ED000020D00BC00000002020D00C00000000175 +:100EE000020D00C800000002020D00CC000000024C +:100EF000020D010800000001020D015C000000016C +:100F0000020D016400000001020D016800000002F2 +:100F1000020D020400000001020D020C000000207E +:100F2000020D021000000040020D021400000040FB +:100F3000020D022000000003020D02240000001830 +:100F4000060D028000000012040D03000024027C44 +:100F5000020D004C00000001020D005000000002D4 +:100F6000020D005400000008020D005800000008A7 +:100F7000060D005C00000004020D00C40000000427 +:100F8000020D000400000001020D00080000000135 +:100F9000020D000C00000001020D00100000000115 +:100FA000020D001400000001020D001800000001F5 +:100FB000020D001C00000001020D002000000001D5 +:100FC000020D002400000001020D002800000001B5 +:100FD000020D002C00000001020D00300000000195 +:100FE000020D003400000001020D00380000000175 +:100FF000020D003C00000001020D01140000000978 +:10100000020D011C0000000A020D0124000000076F +:10101000020D012C00000007020D01340000000C3D +:10102000020D013C0000000B020D0144000000070E +:10103000020D011800000029020D01200000002A05 +:10104000020D012800000027020D013000000027DA +:10105000020D01380000002C020D01400000002BA1 +:10106000020D014800000027020D011400000019C4 +:10107000020D011C0000001A020D012400000017DF +:10108000020D012C00000017020D01340000001CAD +:10109000020D013C0000001B020D0144000000177E +:1010A000020D011800000039020D01200000003A75 +:1010B000020D012800000037020D0130000000374A +:1010C000020D01380000003C020D01400000003B11 +:1010D000020D014800000037020D01140000004914 +:1010E000020D011C0000004A020D0124000000470F +:1010F000020D012C00000047020D01340000004CDD +:10110000020D013C0000004B020D014400000047AD +:10111000020D011800000069020D01200000006AA4 +:10112000020D012800000067020D01300000006779 +:10113000020D01380000006C020D01400000006B40 +:10114000020D014800000067020D01140000005963 +:10115000020D011C0000005A020D0124000000577E +:10116000020D012C00000057020D01340000005C4C +:10117000020D013C0000005B020D0144000000571D +:10118000020D011800000079020D01200000007A14 +:10119000020D012800000077020D013000000077E9 +:1011A000020D01380000007C020D01400000007BB0 +:1011B000020D014800000077020E004C00000032D2 +:1011C000020E009402150020020E00980215002065 +:1011D000020E009C00000030020E00A0081000006B +:1011E000020E00A400000033020E00A80000003030 +:1011F000020E00AC00000031020E00B00000000240 +:10120000020E00B400000004020E00B8000000004E +:10121000020E00BC00000002020E00C0000000022E +:10122000020E00C400000000020E00C80000000210 +:10123000020E00CC00000007020E00D000000002E9 +:10124000020E00D400000002020E00D800000001CF +:10125000020E00E400000001020E01440000000143 +:10126000020E014C00000001020E015000000002BD +:10127000020E020400000001020E020C00000040F9 +:10128000020E021000000040020E021C00000004CA +:10129000020E022000000020020E02240000000EB8 +:1012A000020E02280000001B060E030000000012C0 +:1012B000040E0280001B02A0020E00540000001069 +:1012C000020E005800000007020E005C0000000F34 +:1012D000020E006000000010020E00640000000B0F +:1012E000060E006800000003020E00DC0000000390 +:1012F000020E000400000001020E000800000001C0 +:10130000020E000C00000001020E0010000000019F +:10131000020E001400000001020E0018000000017F +:10132000020E001C00000001020E0020000000015F +:10133000020E002400000001020E0028000000013F +:10134000020E002C00000001020E0030000000011F +:10135000020E003400000001020E003800000001FF +:10136000020E003C00000001020E004000000001DF +:10137000020E004400000001020E01100000000FE8 +:10138000020E01180000000E020E012000000000F5 +:10139000020E012800000000020E01140000002FC0 +:1013A000020E011C0000002E020E012400000000AD +:1013B000020E012C00000000020E01100000001FB0 +:1013C000020E01180000001E020E012000000000A5 +:1013D000020E012800000000020E01140000003F70 +:1013E000020E011C0000003E020E0124000000005D +:1013F000020E012C00000000020E01100000004F40 +:10140000020E01180000004E020E01200000000034 +:10141000020E012800000000020E01140000006FFF +:10142000020E011C0000006E020E012400000000EC +:10143000020E012C00000000020E01100000005FEF +:10144000020E01180000005E020E012000000000E4 +:10145000020E012800000000020E01140000007FAF +:10146000020E011C0000007E020E0124000000009C +:10147000020E012C000000000730040000D2000022 +:10148000083007A8000B02BB0734000031B600008B +:101490000734800036500C6E0735000037591A03A8 +:1014A00007358000286127DA0835FF40401802BD63 +:1014B00001300000000000000130000400000000C6 +:1014C00001300008000000000130000C00000000A6 +:1014D0000130001000000000013000140000000086 +:1014E0000230002000000001023000240000000251 +:1014F00002300028000000030230002C0000000031 +:10150000023000300000000402300034000000010E +:1015100002300038000000000230003C00000001F2 +:1015200002300040000000040230004400000000CF +:1015300002300048000000010230004C00000003AF +:101540000230005000000000023000540000000192 +:1015500002300058000000040230005C000000006F +:10156000023000600000000102300064000000034F +:1015700002300068000000000230006C0000000132 +:10158000023000700000000402300074000000000F +:1015900002300078000000040230007C00000003EC +:1015A0000630008000000002023000A400003FFF6F +:1015B000023000A8000003FF0230022400000000F7 +:1015C00002300234000000000230024C0000000033 +:1015D000023002E40000FFFF063020000000080097 +:1015E00002338BC000000001023380000000001AAB +:1015F000023380400000004E023380800000001063 +:10160000023380C0000000200C3383000007A120BB +:101610000A338300000001380B3383000000138875 +:10162000023383C0000001F40C3383801DCD6500BC +:101630000A3383800004C4B40B338380004C4B40D6 +:101640000A331480000000000233148000000001FF +:10165000063220000000010206328980000000C826 +:1016600006328960000000020632322800000004C1 +:10167000063232000000000904323224000102BFA9 +:1016800006323180000000200632500000000400C5 +:10169000063240000000000204324008000102C08F +:1016A0000632400C0000000306326B6800000002A6 +:1016B00004326B70000202C106326B10000000029F +:1016C000043274C0000202C30233080001000000AB +:1016D00004330C00001002C50233080000000000B3 +:1016E00004330C40001002D506329000000000A028 +:1016F0000632950000000040063297000000003CD2 +:1017000006322450000000B406322AD00000000245 +:101710000632308000000020063280000000012CDC +:101720000232323800000000063250000000002073 +:101730000632510000000020063252000000002056 +:101740000632530000000020063254000000002042 +:10175000063255000000002006325600000000202E +:10176000063257000000002006325800000000201A +:10177000063259000000002006325A000000002006 +:1017800006325B000000002006325C0000000020F2 +:1017900006325D000000002006325E0000000020DE +:1017A00006325F000000002006326B780000005215 +:1017B00006326E080000000C06329280000000A085 +:1017C0000632960000000040063297F00000003C10 +:1017D00006322720000000B406322AD8000000029A +:1017E0000632310000000020063284B00000012CD7 +:1017F0000232323C0000000006325080000000201F +:101800000632518000000020063252800000002085 +:101810000632538000000020063254800000002071 +:10182000063255800000002006325680000000205D +:101830000632578000000020063258800000002049 +:10184000063259800000002006325A800000002035 +:1018500006325B800000002006325C800000002021 +:1018600006325D800000002006325E80000000200D +:1018700006325F800000002006326CC0000000527B +:1018800006326E380000000C02322A3000000000E0 +:10189000063230000000000406324018000000024A +:1018A00002322A340000000006323010000000042A +:1018B000063240280000000202322A3800000000F0 +:1018C00006323020000000040632403800000002DA +:1018D00002322A3C000000000632303000000004D2 +:1018E000063240480000000202322A400000000098 +:1018F000063230400000000406324058000000026A +:1019000002322A4400000000063230500000000479 +:10191000063240680000000202322A48000000003F +:1019200006323060000000040632407800000002F9 +:1019300002322A4C00000000063230700000000421 +:1019400006324088000000020720040000740000F6 +:1019500008200780001002E507240000322600005E +:1019600007248000246E0C8A0824CBB064F002E7C0 +:101970000120000000000000012000040000000021 +:1019800001200008000000000120000C0000000001 +:1019900001200010000000000120001400000000E1 +:1019A00002200020000000010220002400000002AC +:1019B00002200028000000030220002C000000008C +:1019C000022000300000000402200034000000016A +:1019D00002200038000000000220003C000000014E +:1019E000022000400000000402200044000000002B +:1019F00002200048000000010220004C000000030B +:101A000002200050000000000220005400000001ED +:101A100002200058000000040220005C00000000CA +:101A200002200060000000010220006400000003AA +:101A300002200068000000000220006C000000018D +:101A4000022000700000000402200074000000006A +:101A500002200078000000040220007C0000000347 +:101A60000620008000000002022000A400003FFFCA +:101A7000022000A8000003FF022002240000000052 +:101A800002200234000000000220024C000000008E +:101A9000022002E40000FFFF0620200000000800F2 +:101AA00002238BC000000001022380000000001010 +:101AB00002238040000000120223808000000030DA +:101AC000022380C00000000E022383C0000001F446 +:101AD00002231480000000010A231480000000008B +:101AE000062210000000004206227020000000C8FC +:101AF0000622700000000002022211E8000000002F +:101B000006223000000000C0062240700000008065 +:101B10000622528000000004062267000000010037 +:101B2000062290000000040004226B08002002E955 +:101B300002230800013FFFFF04230C0000100309EB +:101B4000022308000000000004230C4000100319C9 +:101B500006228000000000A0062285000000004050 +:101B6000062287000000003C0622404000000006DC +:101B700006228280000000A00622860000000040AD +:101B8000062287F00000003C0622405800000006B4 +:101B9000022211480000000006223300000000026B +:101BA00006226040000000300222114C00000000BC +:101BB0000622330800000002062261000000003007 +:101BC0000222115000000000062233100000000223 +:101BD000062261C000000030022211540000000003 +:101BE0000622331800000002062262800000003046 +:101BF00002221158000000000622332000000002DB +:101C000006226340000000300222115C0000000048 +:101C10000622332800000002062264000000003083 +:101C20000222116000000000062233300000000292 +:101C3000062264C00000003002221164000000008F +:101C400006223338000000020622658000000030C2 +:101C50000216100000000020021700080000000219 +:101C60000217002C000000030217003C00000004D3 +:101C7000021700440000000802170048000000029C +:101C80000217004C00000090021700500000009066 +:101C9000021700540080009002170058081400003A +:101CA000021700600000008A021700640000008034 +:101CB00002170068000000900217006C000000800E +:101CC000021700700000000602170078000007D01D +:101CD0000217007C0000076C02170038007C10041B +:101CE000021700040000000F061640240000000246 +:101CF000021640700000001C02164208000000019D +:101D000002164210000000010216422000000001ED +:101D100002164228000000010216423000000001B5 +:101D20000216423800000001021642600000000264 +:101D30000C16401C0003D0900A16401C0000009CAA +:101D40000B16401C000009C40216403000000008B9 +:101D5000021640340000000C02164038000000104B +:101D6000021640440000002002164000000000015E +:101D7000021640D8000000010216400800000001D1 +:101D80000216400C00000001021640100000000185 +:101D90000216424000000000021642480000000007 +:101DA00006164270000000020216425000000000B9 +:101DB0000216425800000000061642800000000291 +:101DC00002166008000004240216600C00000410D3 +:101DD00002166010000004140216601C0000FFFFD1 +:101DE000021660200000FFFF021660240000FFFFC3 +:101DF000021660280000FFFF021660380000002075 +:101E00000216603C00000020021660400000003412 +:101E100002166044000000350216604800000023EE +:101E20000216604C000000240216605000000025DD +:101E300002166054000000260216605800000027B9 +:101E40000216605C00000029021660600000002A93 +:101E5000021660640000002B021660680000002C6F +:101E60000216606C0000002D061660700000005223 +:101E7000021661B800000001061661BC0000001FD8 +:101E80000216623807FFFFFF0216623C0000003FA7 +:101E90000216624007FFFFFF021662440000000FB7 +:101EA00001166248000000000116624C00000000AC +:101EB000011662500000000001166254000000008C +:101EC00001166258000000000116625C000000006C +:101ED000011662600000000001166264000000004C +:101EE00001166268000000000116626C000000002C +:101EF000011662700000000001166274000000000C +:101F000001166278000000000116627C00000000EB +:101F10000C166000000003E80A16600000000001D3 +:101F20000B1660000000000A021680400000000648 +:101F30000216804400000005021680480000000AD6 +:101F40000216804C000000050216805400000002BA +:101F5000021680CC00000004021680D000000004AD +:101F6000021680D400000004021680D8000000048D +:101F7000021680DC00000004021680E0000000046D +:101F8000021680E400000004021680E8000000044D +:101F90000216880400000004021680300000007C55 +:101FA000021680340000003D021680380000003F19 +:101FB0000216803C0000009C021680F00000000722 +:101FC000061680F4000000050216880C01010101CC +:101FD00002168108000000000216810C00000004B7 +:101FE0000216811000000004021681140000000295 +:101FF000021688100801200402168118000000054E +:102000000216811C00000005021681200000000558 +:1020100002168124000000050216882C20081001F9 +:1020200002168128000000080216812C000000061C +:102030000216813000000007021681340000000003 +:1020400002168830010101200616813800000004C4 +:1020500002168834010101010216814800000000C7 +:102060000216814C0000000402168150000000049A +:10207000021681540000000202168838080120046C +:1020800002168158000000050216815C0000000560 +:102090000216816000000005021681640000000540 +:1020A0000216883C20081001021681680000000812 +:1020B0000216816C00000006021681700000000705 +:1020C00002168174000000010216884001010120FF +:1020D00002168178000000010216817C00000001D8 +:1020E00002168180000000010216818400000001B8 +:1020F00002168844010101010216818800000001D6 +:102100000216818C00000004021681900000000479 +:10211000021681940000000202168848080120047B +:1021200002168198000000050216819C000000053F +:10213000021681A000000005021681A4000000051F +:102140000216881420081001021681A80000000859 +:10215000021681AC00000006021681B000000007E4 +:10216000021681B400000001021688180101012046 +:10217000021681B800000001021681BC00000001B7 +:10218000021681C000000001021681C40000000197 +:102190000216881C01010101021681C8000000011D +:1021A000021681CC00000004021681D00000000459 +:1021B000021681D4000000020216882008012004C3 +:1021C000021681D800000005021681DC000000051F +:1021D000021681E000000005021681E400000005FF +:1021E0000216882420081001021681E80000000869 +:1021F000021681EC00000006021681F000000007C4 +:102200000216E40C000000000216882801010120DB +:102210000616E410000000040216E00001010101AE +:102220000216E420000000000216E424000000046E +:102230000216E428000000040216E42C000000024C +:102240000216E004080120040216E4300000000534 +:102250000216E434000000050216E4380000000510 +:102260000216E43C000000050216E00820081001F8 +:102270000216E440000000080216E44400000006D4 +:102280000216E448000000070216E44C00000000BB +:102290000216E00C010101200616E45000000004C3 +:1022A0000216E010010101010216E46000000000C6 +:1022B0000216E464000000040216E4680000000452 +:1022C0000216E46C000000020216E014080120046B +:1022D0000216E470000000050216E4740000000518 +:1022E0000216E478000000050216E47C00000005F8 +:1022F0000216E018200810010216E4800000000811 +:102300000216E484000000060216E48800000007BC +:102310000216E48C000000010216E01C01010120FD +:102320000216E490000000010216E494000000018F +:102330000216E498000000010216E49C000000016F +:102340000216E020010101010216E4A000000001D4 +:102350000216E4A4000000040216E4A80000000431 +:102360000216E4AC000000020216E024080120047A +:102370000216E4B0000000050216E4B400000005F7 +:102380000216E4B8000000050216E4BC00000005D7 +:102390000216E028200810010216E4C00000000820 +:1023A0000216E4C4000000060216E4C8000000079C +:1023B0000216E4CC000000010216E02C010101200D +:1023C0000216E4D0000000010216E4D4000000016F +:1023D0000216E4D8000000010216E4DC000000014F +:1023E0000216E030010101010216E4E000000001E4 +:1023F0000216E4E4000000040216E4E80000000411 +:102400000216E4EC000000020216E0340801200489 +:102410000216E4F0000000050216E4F400000005D6 +:102420000216E4F8000000050216E4FC00000005B6 +:102430000216E038200810010216E500000000082E +:102440000216E504000000060216E5080000000779 +:102450000216E03C0101012002168240003F003FCD +:1024600002168244000000000216E524003F003FEF +:102470000216E52800000000021682480000000055 +:102480000216824C003F003F0216E52C00000000BF +:102490000216E530003F003F0216825001000100A5 +:1024A00002168254010001000216E5340100010009 +:1024B0000216E538010001000616825800000002ED +:1024C0000216E53C000000000216E5400000000096 +:1024D0000216826000C000C00216826400C000C004 +:1024E0000216E54400C000C00216E54800C000C066 +:1024F000021682681E001E000216826C1E001E005C +:102500000216E54C1E001E000216E5501E001E00BD +:1025100002168270400040000216827440004000A3 +:102520000216E554400040000216E5584000400005 +:1025300002168278800080000216827C8000800073 +:102540000216E55C800080000216E56080008000D5 +:1025500002168280200020000216828420002000C3 +:102560000216E564200020000216E5682000200025 +:1025700006168288000000020216E56C00000000CA +:102580000216E570000000000216829000000000B4 +:1025900002168294000000000216E574000000009C +:1025A0000216E57800000000021682980000000084 +:1025B0000216829C000000000216E57C000000006C +:1025C0000216E58000000000021682A00000000054 +:1025D000021682A400000001061682A80000000A6C +:1025E000021681F400000C08021681F80000004079 +:1025F000021681FC0000010002168200000000208B +:1026000002168204000000170216820800000080F3 +:102610000216820C00000200021682100000000068 +:102620000216821801FF01FF0216821401FF01FF4A +:102630000216E51001FF01FF0216E50C01FF01FF84 +:102640000216823C00000013021680900000013F39 +:102650000216806000000140021680640000014004 +:10266000061680680000000202168070000000C09C +:1026700006168074000000070216809C00000048C7 +:10268000021680A000000048061680A40000000288 +:10269000021680AC00000048061680B0000000075B +:1026A000021682380000800002168234000025E401 +:1026B0000216809400007FFF0216822000070007A8 +:1026C0000216821C000700070216E5180007000723 +:1026D0000216E51400070007021682280000000019 +:1026E00002168224FFFFFFFF0216E5200000000013 +:1026F0000216E51CFFFFFFFF0216E6BC000000000B +:102700000216E6C0000000020216E6C40000000146 +:102710000216E6C8000000030216E6CC0000000422 +:102720000216E6D0000000060216E6D400000005FE +:102730000216E6D800000007021680EC000000FF39 +:1027400002140000000000010214000C000000014F +:1027500002140040000000010214004400007FFF4A +:102760000214000C00000000021400000000000031 +:102770000214006C000000000214000400000001BC +:1027800002140030000000010214000400000000E8 +:102790000214005C000000000214000800000001A8 +:1027A00002140034000000010214000800000000C0 +:1027B0000214006000000000020200580000003215 +:1027C000020200A003150020020200A4031500204D +:1027D000020200A801000030020200AC0810000054 +:1027E000020200B000000033020200B4000000301A +:1027F000020200B800000031020200BC0000000329 +:10280000020200C000000006020200C40000000333 +:10281000020200C800000003020200CC0000000217 +:10282000020200D000000000020200D400000002FA +:10283000020200DC00000000020200E000000006CE +:10284000020200E400000004020200E800000002AE +:10285000020200EC00000002020200F00000000191 +:10286000020200FC0000000602020120000000003D +:102870000202013400000002020201B00000000167 +:102880000202020C0000000102020214000000011A +:10289000020202180000000202020404000000010B +:1028A0000202040C0000004002020410000000407C +:1028B0000202041C000000040202042000000020A8 +:1028C000020204240000000202020428000000208A +:1028D000060205000000001204020480001F032904 +:1028E000020200600000000F020200640000000706 +:1028F000020200680000000B0202006C0000000EE3 +:10290000020200700000000E0602007400000003C6 +:10291000020200F4000000040202000400000001B2 +:1029200002020008000000010202000C0000000189 +:102930000202001000000001020200140000000169 +:1029400002020018000000010202001C0000000149 +:102950000202002000000001020200240000000129 +:1029600002020028000000010202002C0000000109 +:1029700002020030000000010202003400000001E9 +:1029800002020038000000010202003C00000001C9 +:1029900002020040000000010202004400000001A9 +:1029A00002020048000000010202004C0000000189 +:1029B000020200500000000102020108000000C8ED +:1029C0000202011800000002020201C4000000001F +:1029D000020201CC00000000020201D4000000024B +:1029E000020201DC00000002020201E4000000FF1C +:1029F000020201EC000000FF0202010000000000E2 +:102A00000202010C000000C80202011C00000002CA +:102A1000020201C800000000020201D00000000014 +:102A2000020201D800000002020201E000000002E0 +:102A3000020201E8000000FF020201F0000000FFB6 +:102A4000020201040000000002020108000000C8A8 +:102A50000202011800000002020201C4000000008E +:102A6000020201CC00000000020201D400000002BA +:102A7000020201DC00000002020201E4000000FF8B +:102A8000020201EC000000FF020201000000000051 +:102A90000202010C000000C80202011C000000023A +:102AA000020201C800000000020201D00000000084 +:102AB000020201D800000002020201E00000000250 +:102AC000020201E8000000FF020201F0000000FF26 +:102AD000020201040000000002020108000000C818 +:102AE0000202011800000002020201C400000000FE +:102AF000020201CC00000000020201D4000000022A +:102B0000020201DC00000002020201E4000000FFFA +:102B1000020201EC000000FF0202010000000000C0 +:102B20000202010C000000C80202011C00000002A9 +:102B3000020201C800000000020201D000000000F3 +:102B4000020201D800000002020201E000000002BF +:102B5000020201E8000000FF020201F0000000FF95 +:102B6000020201040000000002020108000000C887 +:102B70000202011800000002020201C4000000006D +:102B8000020201CC00000000020201D40000000299 +:102B9000020201DC00000002020201E4000000FF6A +:102BA000020201EC000000FF020201000000000030 +:102BB0000202010C000000C80202011C0000000219 +:102BC000020201C800000000020201D00000000063 +:102BD000020201D800000002020201E0000000022F +:102BE000020201E8000000FF020201F0000000FF05 +:102BF00002020104000000000728040000BD0000DC +:102C0000082807A8000B0348072C00003406000022 +:102C1000072C800037960D02072D00003BC31AE8F1 +:102C2000072D8000382629D9072E0000124537E3EA +:102C3000082E22203BBC034A0128000000000000AF +:102C40000128000400000000012800080000000026 +:102C50000128000C00000000012800100000000006 +:102C600001280014000000000228002000000001DC +:102C700002280024000000020228002800000003AF +:102C80000228002C00000000022800300000000490 +:102C90000228003400000001022800380000000073 +:102CA0000228003C0000000102280040000000044F +:102CB0000228004400000000022800480000000133 +:102CC0000228004C00000003022800500000000011 +:102CD00002280054000000010228005800000004EF +:102CE0000228005C000000000228006000000001D3 +:102CF00002280064000000030228006800000000B1 +:102D00000228006C0000000102280070000000048E +:102D1000022800740000000002280078000000046F +:102D20000228007C0000000306280080000000024A +:102D3000022800A400003FFF022800A8000003FFB3 +:102D400002280224000000000228023400000000D3 +:102D50000228024C00000000022802E40000FFFFED +:102D60000628200000000800022B8BC00000000194 +:102D7000022B800000000000022B804000000018A1 +:102D8000022B80800000000C022B80C00000006637 +:102D90000C2B83000007A1200A2B830000000138C0 +:102DA0000B2B830000001388022B83C0000001F46A +:102DB0000C2B8340000001F40A2B8340000000002C +:102DC0000B2B8340000000050A2B83800004C4B451 +:102DD0000C2B83801DCD65000A2B148000000000A1 +:102DE0000B2B8380004C4B40022B14800000000111 +:102DF000062A29C800000004042A29D80002034C2E +:102E0000062A208000000048062A9020000000C802 +:102E1000062A900000000002062A21A80000008671 +:102E2000062A200000000020022A23C8000000001B +:102E3000042A23D00002034E042A249800040350DD +:102E4000022A2C2000000000022A2C1000000000A2 +:102E5000042A2C0800020354022A3010000000014A +:102E6000062A404000000010042A400000100356CB +:102E7000062A6AC000000002062A6B000000000457 +:102E8000042A840800020366022B080000000000E8 +:102E9000042B0C0000100368022B08000100000046 +:102EA000042B0C4000080378022B080002000000ED +:102EB000042B0C6000080380062AC000000000FC00 +:102EC000062A24A800000014062A25480000002431 +:102ED000062A266800000024062A2788000000240D +:102EE000062A28A800000024062AA00000000028C6 +:102EF000062AA1400000000C042A29E000020388F1 +:102F0000022A300000000001062A502000000002C2 +:102F1000062A503000000002062A5000000000027D +:102F2000062A501000000002022A52080000000188 +:102F3000042A6AC80002038A062A6B1000000042B5 +:102F4000062A6D2000000004062AC3F0000000FCE1 +:102F5000062A24F800000014062A25D800000024C0 +:102F6000062A26F800000024062A2818000000245B +:102F7000062A293800000024062AA0A00000002804 +:102F8000062AA1700000000C042A29E80002038C24 +:102F9000022A300400000001062A50280000000226 +:102FA000062A503800000002062A500800000002DD +:102FB000062A501800000002022A520C00000001EC +:102FC000042A6AD00002038E062A6C180000004210 +:102FD000062A6D3000000004022AC7E0000000004D +:102FE000042A29F000100390062A50480000000E21 +:102FF000022AC7E400000000042A2A30001003A0BF +:10300000062A50800000000E022AC7E800000000D7 +:10301000042A2A70001003B0062A50B80000000EDF +:10302000022AC7EC00000000042A2AB0001003C0E6 +:10303000062A50F00000000E022AC7F0000000002F +:10304000042A2AF0001003D0062A51280000000E9E +:10305000022AC7F400000000042A2B30001003E00D +:10306000062A51600000000E022AC7F80000000086 +:10307000042A2B70001003F0062A51980000000E5D +:10308000022AC7FC00000000042A2BB00010040034 +:10309000062A51D00000000E0210100800000001A6 +:1030A0000210105000000001021010000003D000B8 +:1030B000021010040000003D091018000200041066 +:1030C0000910110000280610061011A000000018B9 +:1030D00006102400000000E00210201C0000000088 +:1030E0000210202000000001021020C00000000299 +:1030F000021020040000000102102008000000015E +:1031000009103C0000050638091038000005063D8E +:10311000091038200005064206104C00000001008E +:1031200002104028000000100210404400003FFF41 +:103130000210405800280000021040840084924A87 +:1031400002104058000000000210800000001080B3 +:10315000021080AC00000000021080380000001057 +:103160000210810000000000061081200000000213 +:1031700002108008000002B502108010000000005C +:10318000061082000000004A021081080001FFFFC3 +:1031900006108140000000020210800000001A802A +:1031A0000610900000000024061091200000004A44 +:1031B000061093700000004A061095C00000004AF7 +:1031C0000210800400001080021080B00000000196 +:1031D0000210803C0000001002108104000000007A +:1031E00006108128000000020210800C000002B5C9 +:1031F0000210801400000000061084000000004A45 +:103200000210810C0001FFFF06108148000000023F +:103210000210800400001A80061090900000002424 +:10322000061092480000004A061094980000004AD8 +:10323000061096E80000004A02108000000010808E +:10324000021080AC00000002021080380000001064 +:103250000210810000000000061081200000000222 +:1032600002108008000002B502108010000000006B +:10327000061082000000004A021081080001FFFFD2 +:1032800006108140000000020210800000001A8039 +:103290000610900000000024061091200000004A53 +:1032A000061093700000004A061095C00000004A06 +:1032B0000210800400001080021080B000000003A3 +:1032C0000210803C00000010021081040000000089 +:1032D00006108128000000020210800C000002B5D8 +:1032E0000210801400000000061084000000004A54 +:1032F0000210810C0001FFFF06108148000000024F +:103300000210800400001A80061090900000002433 +:10331000061092480000004A061094980000004AE7 +:10332000061096E80000004A02108000000010809D +:10333000021080AC00000004021080380000001071 +:103340000210810000000000061081200000000231 +:1033500002108008000002B502108010000000007A +:10336000061082000000004A021081080001FFFFE1 +:1033700006108140000000020210800000001A8048 +:103380000610900000000024061091200000004A62 +:10339000061093700000004A061095C00000004A15 +:1033A0000210800400001080021080B000000005B0 +:1033B0000210803C00000010021081040000000098 +:1033C00006108128000000020210800C000002B5E7 +:1033D0000210801400000000061084000000004A63 +:1033E0000210810C0001FFFF06108148000000025E +:1033F0000210800400001A80061090900000002443 +:10340000061092480000004A061094980000004AF6 +:10341000061096E80000004A0210800000001080AC +:10342000021080AC0000000602108038000000107E +:103430000210810000000000061081200000000240 +:1034400002108008000002B5021080100000000089 +:10345000061082000000004A021081080001FFFFF0 +:1034600006108140000000020210800000001A8057 +:103470000610900000000024061091200000004A71 +:10348000061093700000004A061095C00000004A24 +:103490000210800400001080021080B000000007BD +:1034A0000210803C000000100210810400000000A7 +:1034B00006108128000000020210800C000002B5F6 +:1034C0000210801400000000061084000000004A72 +:1034D0000210810C0001FFFF06108148000000026D +:1034E0000210800400001A80061090900000002452 +:1034F000061092480000004A061094980000004A06 +:10350000061096E80000004A021205B00000000113 +:103510000212049000E383400212051400003C10E4 +:103520000212066C0000000102120670000000008A +:1035300002120494FFFFFFFF02120498FFFFFFFF37 +:103540000212049CFFFFFFFF021204A0FFFFFFFF17 +:10355000021204A4FFFFFFFF021204A8FFFFFFFFF7 +:10356000021204ACFFFFFFFF021204B0FFFFFFFFD7 +:10357000021204BCFFFFFFFF021204C0FFFFFFFFA7 +:10358000021204C4FFFFFFFF021204C8FFFFFFFF87 +:10359000021204CCFFFFFFFF021204D0FFFFFFFF67 +:1035A000021204D8FFFFFFFF021204DCFFFFFFFF3F +:1035B000021204E0FFFFFFFF021204E4FFFFFFFF1F +:1035C000021204E8FFFFFFFF021204ECFFFFFFFFFF +:1035D000021204F0FFFFFFFF021204F4FFFFFFFFDF +:1035E000021204F8FFFFFFFF021204FCFFFFFFFFBF +:1035F00002120500FFFFFFFF02120504FFFFFFFF9D +:1036000002120508FFFFFFFF0212050CFFFFFFFF7C +:1036100002120510FFFFFFFF021204D4FF802000FA +:10362000021204B4F0005000021204B8F00080004E +:1036300002120390000000080212039C0000000820 +:10364000021203A000000008021203A400000002FE +:10365000021203BC00000004021203C000000005B7 +:10366000021203C400000004021203D00000000094 +:103670000212036C00000001021203680000003F08 +:10368000021201BC00000040021201C00000180834 +:10369000021201C400000803021201C8000008035E +:1036A000021201CC00000040021201D00000000311 +:1036B000021201D400000803021201D8000008031E +:1036C000021201DC00000803021201E00001000305 +:1036D000021201E400000803021201E800000803DE +:1036E000021201EC00000003021201F000000003CE +:1036F000021201F400000003021201F800000003AE +:10370000021201FC0000000302120200000000038C +:10371000021202040000000302120208000000036B +:103720000212020C0000000302120210000000034B +:10373000021202140000000302120218000000032B +:103740000212021C0000000302120220000000030B +:1037500002120224000000030212022800002403C7 +:103760000212022C0000002F021202300000000999 +:103770000212023400000019021202380000018413 +:103780000212023C00000183021202400000030604 +:103790000212024400000019021202480000000652 +:1037A0000212024C0000030602120250000003063F +:1037B00002120254000003060212025800000C8696 +:1037C0000212025C000003060212026000000306FF +:1037D00002120264000000060212026800000006E5 +:1037E0000212026C000000060212027000000006C5 +:1037F00002120274000000060212027800000006A5 +:103800000212027C00000006021202800000000684 +:103810000212028400000006021202880000000664 +:103820000212028C00000006021202900000000644 +:103830000212029400000006021202980000000624 +:103840000212029C00000006021202A00000030601 +:10385000021202A400000013021202A800000006D7 +:10386000021202B000001004021202B400001004A0 +:103870000212032400106440021203280010644066 +:10388000021205B400000001021201B000000001A4 +:103890000600A000000000160200A0EC5554000035 +:1038A0000200A0F0555555550200A0F400005555F2 +:1038B0000200A0F8F00000000200A0FC5554000037 +:1038C0000200A100555555550200A10400005555B0 +:1038D0000200A108F00000000200A18C5554000075 +:1038E0000200A190555555550200A1940000555570 +:1038F0000200A198F00000000200A19C000000005E +:103900000200A1A0000100000200A1A400005014C8 +:103910000200A1A8000000000200A45C00000C004E +:103920000200A61C000000030200A06CFF5C000067 +:103930000200A070FFF55FFF0200A0740000FFFF0F +:103940000200A078F00003E00200A07C000000006C +:103950000200A0800000A0000600A0840000000576 +:103960000200A0980FE000000600A09C00000007E5 +:103970000200A0B8000004000600A0BC0000000384 +:103980000200A0C8000010000600A0CC0000000348 +:103990000200A0D8000040000600A0DC00000003E8 +:1039A0000200A0E8000100000600A22C00000004B4 +:1039B0000200A10CFF5C00000200A110FFF55FFFF8 +:1039C0000200A1140000FFFF0200A118F00003E0B4 +:1039D0000200A11C000000000200A1200000A000C5 +:1039E0000600A124000000050200A1380FE000003D +:1039F0000600A13C000000070200A15800000800DA +:103A00000600A15C000000030200A1680000200085 +:103A10000600A16C000000030200A17800008000F5 +:103A20000600A17C000000030200A1880002000043 +:103A30000600A23C0000000400000000000000009E +:103A40000000003100000000000000000000000045 +:103A50000000000000000000000000000000000066 +:103A600000000000000000000000000000310032F3 +:103A70000000000000000000000000000000000046 +:103A80000000000000000000000000000000000036 +:103A9000000000000000000000320056000000009E +:103AA0000000000000000000000000000000000016 +:103AB0000000000000000000000000000000000006 +:103AC000000000000056008C000000000000000014 +:103AD000008C009000900094009400980098009C46 +:103AE000009C00A000A000A400A400A800A800ACB6 +:103AF00000AC00B100B100B300B300B5000000009D +:103B000000000000000000000000000000000000B5 +:103B100000000000000000000000000000B50100EF +:103B2000010001060106010C010C01140114011C25 +:103B3000011C01240124012C012C01340134013C1D +:103B4000013C01440144014C000000000000000061 +:103B50000000000000000000000000000000000065 +:103B60000000000000000000000000000000000055 +:103B70000000000000000000000000000000000045 +:103B80000000000000000000000000000000000035 +:103B90000000000000000000000000000000000025 +:103BA0000000000000000000000000000000000015 +:103BB0000000000000000000000000000000000005 +:103BC00000000000000000000000000000000000F5 +:103BD00000000000000000000000000000000000E5 +:103BE00000000000000000000000000000000000D5 +:103BF0000000000000000000014C01510000000026 +:103C000000000000015101520152015301530154BF +:103C100001540155015501560156015701570158EC +:103C200001580159000000000000000000000000E1 +:103C30000000000000000000000000000000000084 +:103C40000000000000000000000000000000000074 +:103C50000159015E015E016A016A017600000000FF +:103C60000000000000000000000000000000000054 +:103C70000000000000000000000000000000000044 +:103C80000000000000000000000000000000000034 +:103C90000000000000000000000000000000000024 +:103CA0000000000000000000017601770000000025 +:103CB0000000000000000000000000000000000004 +:103CC00000000000000000000000000000000000F4 +:103CD000000000000177019A0000000000000000D1 +:103CE00000000000000000000000000000000000D4 +:103CF00000000000000000000000000000000000C4 +:103D0000019A01C200000000000000000000000055 +:103D100000000000000000000000000000000000A3 +:103D200000000000000000000000000001C201F3DC +:103D3000000000000000000001F301FA01FA020196 +:103D4000020102080208020F020F02160216021DEB +:103D5000021D02240224022B022B02630000000039 +:103D600000000000026302670267026B026B026FD1 +:103D7000026F0273027302770277027B027B027F7B +:103D8000027F0283028302D102D102EB02EB030520 +:103D9000030503080308030B030B030E030E0311B3 +:103DA00003110314031403170317031A031A031D43 +:103DB000031D035E035E0362036203660366036919 +:103DC0000369036C036C036F036F03720372037563 +:103DD000037503780378037B037B037E037E037FF5 +:103DE00000000000000000000000000000000000D3 +:103DF00000000000000000000000000000000000C3 +:103E00000000000000000000037F0391000000009C +:103E100000000000000000000000000000000000A2 +:103E20000000000000000000000000000000000092 +:103E300000000000039103A603A603A903A903AC95 +:103E40000000000000000000000000000000000072 +:103E50000000000000000000000000000000000062 +:103E600003AC03D9000000000000000000000000C7 +:103E70000000000000000000000000000000000042 +:103E800000000000000000000000000003D904DC76 +:103E90000000000000000000000000000000000022 +:103EA0000000000000000000000000000000000012 +:103EB000000000000000000004DC04E304E304E769 +:103EC00004E704EB00000000000000000000000018 +:103ED00000000000000000000000000000000000E2 +:103EE0000000000004EB052B0000000000000000B3 +:103EF000052B05340534053D053D05460546054FB2 +:103F0000054F0558055805610561056A056A057381 +:103F1000057305CB05CB05DD05DD05EF05EF05F2E6 +:103F200005F205F505F505F805F805FB05FB05FEA9 +:103F300005FE060106010604060406070607060E2E +:103F40000000000000000000000000000000000071 +:103F50000000000000000000000000000000000061 +:103F60000000000000000000060E06140000000023 +:103F70000000000000000000000000000000000041 +:103F80000000000000000000000000000000000031 +:103F900000000000061406170000000000000000EA +:103FA0000000000000000000000000000000000011 +:103FB0000000000000000000000000000000000001 +:103FC0000617061D000000000000000000000000B1 +:103FD00000000000000000000000000000000000E1 +:103FE00000000000000000000000000000000000D1 +:103FF0000000000000000000061D062C062C063BF9 +:10400000063B064A064A06590659066806680677B8 +:1040100006770686068606950695070600000000C8 +:104020000000000000000000000000000000000090 +:104030000000000000000000000000000000000080 +:1040400000000000070607190719072A072A073B7F +:104050000000000000000000000000000000000060 +:104060000000000000000000000000000000000050 +:10407000000000000000000000010000000204C079 +:104080000003098000040E4000051300000617C05D +:1040900000071C800008214000092600000A2AC0F1 +:1040A000000B2F80000C3440000D3900000E3DC085 +:1040B000000F42800010474000114C00001250C019 +:1040C0000013558000145A4000155F00001663C0AD +:1040D0000017688000186D4000197200001A76C041 +:1040E000001B7B80001C8040001D8500001E89C0D5 +:1040F000001F8E8000209340000020000000400040 +:1041000000006000000080000000A0000000C0006F +:104110000000E0000001000000012000000140005C +:1041200000016000000180000001A0000001C0004B +:104130000001E00000020000000220000002400038 +:1041400000026000000280000002A0000002C00027 +:104150000002E00000030000000320000003400014 +:1041600000036000000380000003A0000003C00003 +:104170000003E000000400000004200000044000F0 +:1041800000046000000480000004A0000004C000DF +:104190000004E000000500000005200000054000CC +:1041A00000056000000580000005A0000005C000BB +:1041B0000005E000000600000006200000064000A8 +:1041C00000066000000680000006A0000006C00097 +:1041D0000006E00000070000000720000007400084 +:1041E00000076000000780000007A0000007C00073 +:1041F0000007E00000080000000820000008400060 +:1042000000086000000880000008A0000008C0004E +:104210000008E0000009000000092000000940003B +:1042200000096000000980000009A0000009C0002A +:104230000009E000000A0000000A2000000A400017 +:10424000000A6000000A8000000AA000000AC00006 +:10425000000AE000000B0000000B2000000B4000F3 +:10426000000B6000000B8000000BA000000BC000E2 +:10427000000BE000000C0000000C2000000C4000CF +:10428000000C6000000C8000000CA000000CC000BE +:10429000000CE000000D0000000D2000000D4000AB +:1042A000000D6000000D8000000DA000000DC0009A +:1042B000000DE000000E0000000E2000000E400087 +:1042C000000E6000000E8000000EA000000EC00076 +:1042D000000EE000000F0000000F2000000F400063 +:1042E000000F6000000F8000000FA000000FC00052 +:1042F000000FE0000010000000102000001040003F +:1043000000106000001080000010A0000010C0002D +:104310000010E0000011000000112000001140001A +:1043200000116000001180000011A0000011C00009 +:104330000011E000001200000012200000124000F6 +:1043400000126000001280000012A0000012C000E5 +:104350000012E000001300000013200000134000D2 +:1043600000136000001380000013A0000013C000C1 +:104370000013E000001400000014200000144000AE +:1043800000146000001480000014A0000014C0009D +:104390000014E0000015000000152000001540008A +:1043A00000156000001580000015A0000015C00079 +:1043B0000015E00000160000001620000016400066 +:1043C00000166000001680000016A0000016C00055 +:1043D0000016E00000170000001720000017400042 +:1043E00000176000001780000017A0000017C00031 +:1043F0000017E0000018000000182000001840001E +:1044000000186000001880000018A0000018C0000C +:104410000018E000001900000019200000194000F9 +:1044200000196000001980000019A0000019C000E8 +:104430000019E000001A0000001A2000001A4000D5 +:10444000001A6000001A8000001AA000001AC000C4 +:10445000001AE000001B0000001B2000001B4000B1 +:10446000001B6000001B8000001BA000001BC000A0 +:10447000001BE000001C0000001C2000001C40008D +:10448000001C6000001C8000001CA000001CC0007C +:10449000001CE000001D0000001D2000001D400069 +:1044A000001D6000001D8000001DA000001DC00058 +:1044B000001DE000001E0000001E2000001E400045 +:1044C000001E6000001E8000001EA000001EC00034 +:1044D000001EE000001F0000001F2000001F400021 +:1044E000001F6000001F8000001FA000001FC00010 +:1044F000001FE000002000000020200000204000FD +:1045000000206000002080000020A0000020C000EB +:104510000020E000002100000021200000214000D8 +:1045200000216000002180000021A0000021C000C7 +:104530000021E000002200000022200000224000B4 +:1045400000226000002280000022A0000022C000A3 +:104550000022E00000230000002320000023400090 +:1045600000236000002380000023A0000023C0007F +:104570000023E0000024000000242000002440006C +:1045800000246000002480000024A0000024C0005B +:104590000024E00000250000002520000025400048 +:1045A00000256000002580000025A0000025C00037 +:1045B0000025E00000260000002620000026400024 +:1045C00000266000002680000026A0000026C00013 +:1045D0000026E00000270000002720000027400000 +:1045E00000276000002780000027A0000027C000EF +:1045F0000027E000002800000028200000284000DC +:1046000000286000002880000028A0000028C000CA +:104610000028E000002900000029200000294000B7 +:1046200000296000002980000029A0000029C000A6 +:104630000029E000002A0000002A2000002A400093 +:10464000002A6000002A8000002AA000002AC00082 +:10465000002AE000002B0000002B2000002B40006F +:10466000002B6000002B8000002BA000002BC0005E +:10467000002BE000002C0000002C2000002C40004B +:10468000002C6000002C8000002CA000002CC0003A +:10469000002CE000002D0000002D2000002D400027 +:1046A000002D6000002D8000002DA000002DC00016 +:1046B000002DE000002E0000002E2000002E400003 +:1046C000002E6000002E8000002EA000002EC000F2 +:1046D000002EE000002F0000002F2000002F4000DF +:1046E000002F6000002F8000002FA000002FC000CE +:1046F000002FE000003000000030200000304000BB +:1047000000306000003080000030A0000030C000A9 +:104710000030E00000310000003120000031400096 +:1047200000316000003180000031A0000031C00085 +:104730000031E00000320000003220000032400072 +:1047400000326000003280000032A0000032C00061 +:104750000032E0000033000000332000003340004E +:1047600000336000003380000033A0000033C0003D +:104770000033E0000034000000342000003440002A +:1047800000346000003480000034A0000034C00019 +:104790000034E00000350000003520000035400006 +:1047A00000356000003580000035A0000035C000F5 +:1047B0000035E000003600000036200000364000E2 +:1047C00000366000003680000036A0000036C000D1 +:1047D0000036E000003700000037200000374000BE +:1047E00000376000003780000037A0000037C000AD +:1047F0000037E0000038000000382000003840009A +:1048000000386000003880000038A0000038C00088 +:104810000038E00000390000003920000039400075 +:1048200000396000003980000039A0000039C00064 +:104830000039E000003A0000003A2000003A400051 +:10484000003A6000003A8000003AA000003AC00040 +:10485000003AE000003B0000003B2000003B40002D +:10486000003B6000003B8000003BA000003BC0001C +:10487000003BE000003C0000003C2000003C400009 +:10488000003C6000003C8000003CA000003CC000F8 +:10489000003CE000003D0000003D2000003D4000E5 +:1048A000003D6000003D8000003DA000003DC000D4 +:1048B000003DE000003E0000003E2000003E4000C1 +:1048C000003E6000003E8000003EA000003EC000B0 +:1048D000003EE000003F0000003F2000003F40009D +:1048E000003F6000003F8000003FA000003FC0008C +:1048F000003FE000003FE00100000000000001FF79 +:104900000000020000007FF800007FF800000704AC +:104910000000350000000001FFFFFFFFFFFFFFFF69 +:10492000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:10493000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 +:10494000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:10495000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 +:10496000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:10497000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 +:10498000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:10499000FFFFFFFFFFFFFFFFFFFFFFFF0000000023 +:1049A000FFFFFFFF00000000FFFFFFFFFFFFFFFF13 +:1049B00000000000FFFFFFFF00000000FFFFFFFFFF +:1049C000FFFFFFFF00000000FFFFFFFF00000000EF +:1049D000FFFFFFFF0000000300BEBC20FFFFFFFF42 +:1049E00000000000FFFFFFFF00000000FFFFFFFFCF +:1049F0000000000300BEBC20FFFFFFFF000000001E +:104A0000FFFFFFFF00000000FFFFFFFF00000003AB +:104A100000BEBC20FFFFFFFF00000000FFFFFFFF04 +:104A200000000000FFFFFFFF0000000300BEBC20ED +:104A3000FFFFFFFF00000000FFFFFFFF000000007E +:104A4000FFFFFFFF0000000300BEBC20FFFFFFFFD1 +:104A500000000000FFFFFFFF00000000FFFFFFFF5E +:104A60000000000300BEBC2000002000000040C089 +:104A700000006180000082400000A3000000C3C06D +:104A80000000E4800001054000012600000146C04E +:104A900000016780000188400001A9000001C9C031 +:104AA0000001EA8000020B4000022C0000024CC012 +:104AB00000026D8000028E400002AF000002CFC0F5 +:104AC0000002F0800003114000033200000352C0D6 +:104AD00000037380000394400003B5000003D5C0B9 +:104AE0000003F6800004174000043800000458C09A +:104AF0000004798000049A400000800000010380D7 +:104B00000001870000020A8000028E00000311806D +:104B1000000395000004188000049C0000051F801D +:104B20000005A300000626800006AA0000072D80CD +:104B30000007B100000834800008B80000093B807D +:104B40000009BF00000A4280000AC600000B49802D +:104B5000000BCD00000C5080000CD400000D5780DD +:104B6000000DDB0000007FF800007FF800000487E4 +:104B700000001500000019000000002800100000CF +:104B80000000000000000000FFFFFFFF40000000E9 +:104B90004000000040000000400000004000000015 +:104BA0004000000040000000400000004000000005 +:104BB00040000000400000004000000040000000F5 +:104BC00040000000400000004000000040000000E5 +:104BD00040000000400000004000000040000000D5 +:104BE00040000000400000004000000040000000C5 +:104BF00040000000400000004000000040000000B5 +:104C000040000000400000004000000000007FF86D +:104C100000007FF8000003E000001500FFFFFFFF29 +:104C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 +:104C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +:104C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 +:104C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +:104C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 +:104C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +:104C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 +:104C9000FFFFFFFFFFFFFFFFFFFFFFFF40000000E0 +:104CA0004000000040000000400000004000000004 +:104CB00040000000400000004000000040000000F4 +:104CC00040000000400000004000000040000000E4 +:104CD00040000000400000004000000040000000D4 +:104CE00040000000400000004000000040000000C4 +:104CF00040000000400000004000000040000000B4 +:104D000040000000400000004000000040000000A3 +:104D100040000000400000004000000000001000C3 +:104D2000000020800000310000004180000052009F +:104D30000000628000007300000083800000940087 +:104D40000000A4800000B5000000C5800000D6006F +:104D50000000E6800000F700000107800001180055 +:104D600000012880000139000001498000015A003B +:104D700000016A8000017B0000018B8000019C0023 +:104D80000001AC800001BD000001CD800001DE000B +:104D90000001EE800001FF0000007FF800007FF8B6 +:104DA0000000023E0000350010000000000028ADA9 +:104DB000000000000001000100350804CCCCCCC587 +:104DC000FFFFFFFFFFFFFFFF7058103C00000000D7 +:104DD000CCCC0201CCCCCCCCCCCC0201CCCCCCCC3D +:104DE000CCCC0201CCCCCCCCCCCC0201CCCCCCCC2D +:104DF000CCCC0201CCCCCCCCCCCC0201CCCCCCCC1D +:104E0000CCCC0201CCCCCCCCCCCC0201CCCCCCCC0C +:104E100000000000FFFFFFFF400000004000000016 +:104E20004000000040000000400000004000000082 +:104E30004000000040000000400000004000000072 +:104E40004000000040000000400000004000000062 +:104E50004000000040000000400000004000000052 +:104E60004000000040000000400000004000000042 +:104E70004000000040000000400000004000000032 +:104E80004000000040000000400000004000000022 +:104E90004000000040000000000E0232011600D663 +:104EA000001000000000000000720236012300F331 +:104EB00000100000000000000000FFFF00000000E4 +:104EC0000000FFFF000000000000FFFF00000000E6 +:104ED0000000FFFF000000000000FFFF00000000D6 +:104EE0000000FFFF000000000000FFFF00000000C6 +:104EF0000000FFFF000000000000FFFF00000000B6 +:104F00000000FFFF000000000000FFFF00000000A5 +:104F10000000FFFF000000000000FFFF0000000095 +:104F20000000FFFF000000000000FFFF0000000085 +:104F30000000FFFF000000000000FFFF0000000075 +:104F40000000FFFF000000000000FFFF0000000065 +:104F50000000FFFF000000000000FFFF0000000055 +:104F60000000FFFF000000000000FFFF0000000045 +:104F70000000FFFF000000000000FFFF0000000035 +:104F80000000FFFF000000000000FFFF0000000025 +:104F90000000FFFF000000000000FFFF0000000015 +:104FA0000000FFFF000000000000FFFF0000000005 +:104FB0000000FFFF000000000000FFFF00000000F5 +:104FC0000000FFFF000000000000FFFF00000000E5 +:104FD0000000FFFF000000000000FFFF00000000D5 +:104FE0000000FFFF000000000000FFFF00000000C5 +:104FF0000000FFFF000000000000FFFF00000000B5 +:105000000000FFFF000000000000FFFF00000000A4 +:105010000000FFFF000000000000FFFF0000000094 +:105020000000FFFF000000000000FFFF0000000084 +:105030000000FFFF000000000000FFFF0000000074 +:105040000000FFFF000000000000FFFF0000000064 +:105050000000FFFF000000000000FFFF0000000054 +:105060000000FFFF000000000000FFFF0000000044 +:105070000000FFFF000000000000FFFF0000000034 +:105080000000FFFF000000000000FFFF0000000024 +:105090000000FFFF000000000000FFFF0000000014 +:1050A0000000FFFF000000000000FFFF0000000004 +:1050B0000000FFFF00000000FFFFFFF3320FFFFFC3 +:1050C0000C30C30CC30C30C3CF3CF300F3CF3CF324 +:1050D0000000CF3CCDCDCDCDFFFFFFF130EFFFFF86 +:1050E0000C30C30CC30C30C3CF3CF300F3CF3CF304 +:1050F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFF0 +:105100000C30C30CC30C30C3CF3CF300F3CF3CF3E3 +:105110000002CF3CCDCDCDCDFFFFF4061CBFFFFF7D +:105120000C30C305C30C30C3CF300014F3CF3CF3B5 +:105130000004CF3CCDCDCDCDFFFFFFF2304FFFFFC0 +:105140000C30C30CC30C30C3CF3CF300F3CF3CF3A3 +:105150000008CF3CCDCDCDCDFFFFFFFA302FFFFFB4 +:105160000C30C30CC30C30C3CF3CF300F3CF3CF383 +:105170000010CF3CCDCDCDCDFFFFFFF731EFFFFFCE +:105180000C30C30CC30C30C3CF3CF300F3CF3CF363 +:105190000020CF3CCDCDCDCDFFFFFFF5302FFFFF61 +:1051A0000C30C30CC30C30C3CF3CF300F3CF3CF343 +:1051B0000040CF3CCDCDCDCDFFFFFFF3310FFFFF42 +:1051C0000C30C30CC30C30C3CF3CF300F3CF3CF323 +:1051D0000000CF3CCDCDCDCDFFFFFFF1310FFFFF64 +:1051E0000C30C30CC30C30C3CF3CF300F3CF3CF303 +:1051F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFEF +:105200000C30C30CC30C30C3CF3CF300F3CF3CF3E2 +:105210000002CF3CCDCDCDCDFFFFF4061CBFFFFF7C +:105220000C30C305C30C30C3CF300014F3CF3CF3B4 +:105230000004CF3CCDCDCDCDFFFFFFF2304FFFFFBF +:105240000C30C30CC30C30C3CF3CF300F3CF3CF3A2 +:105250000008CF3CCDCDCDCDFFFFFFFA302FFFFFB3 +:105260000C30C30CC30C30C3CF3CF300F3CF3CF382 +:105270000010CF3CCDCDCDCDFFFFFFF730EFFFFFCE +:105280000C30C30CC30C30C3CF3CF300F3CF3CF362 +:105290000020CF3CCDCDCDCDFFFFFFF5304FFFFF40 +:1052A0000C30C30CC30C30C3CF3CF300F3CF3CF342 +:1052B0000040CF3CCDCDCDCDFFFFFFF331EFFFFF61 +:1052C0000C30C30CC30C30C3CF3CF300F3CF3CF322 +:1052D0000000CF3CCDCDCDCDFFFFFFF1310FFFFF63 +:1052E0000C30C30CC30C30C3CF3CF300F3CF3CF302 +:1052F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFEE +:105300000C30C30CC30C30C3CF3CF300F3CF3CF3E1 +:105310000002CF3CCDCDCDCDFFFFF4061CBFFFFF7B +:105320000C30C305C30C30C3CF300014F3CF3CF3B3 +:105330000004CF3CCDCDCDCDFFFFFFF2304FFFFFBE +:105340000C30C30CC30C30C3CF3CF300F3CF3CF3A1 +:105350000008CF3CCDCDCDCDFFFFFFFA302FFFFFB2 +:105360000C30C30CC30C30C3CF3CF300F3CF3CF381 +:105370000010CF3CCDCDCDCDFFFFFF97056FFFFFD8 +:105380000C30C30CC30C30C3CF3CC000F3CF3CF394 +:105390000020CF3CCDCDCDCDFFFFFFF5310FFFFF7E +:1053A0000C30C30CC30C30C3CF3CF300F3CF3CF341 +:1053B0000040CF3CCDCDCDCDFFFFFFF3320FFFFF3F +:1053C0000C30C30CC30C30C3CF3CF300F3CF3CF321 +:1053D0000000CF3CCDCDCDCDFFFFFFF1310FFFFF62 +:1053E0000C30C30CC30C30C3CF3CF300F3CF3CF301 +:1053F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFED +:105400000C30C30CC30C30C3CF3CF300F3CF3CF3E0 +:105410000002CF3CCDCDCDCDFFFFF4061CBFFFFF7A +:105420000C30C305C30C30C3CF300014F3CF3CF3B2 +:105430000004CF3CCDCDCDCDFFFFFFF2304FFFFFBD +:105440000C30C30CC30C30C3CF3CF300F3CF3CF3A0 +:105450000008CF3CCDCDCDCDFFFFFF8A042FFFFF4D +:105460000C30C30CC30C30C3CF3CC000F3CF3CF3B3 +:105470000010CF3CCDCDCDCDFFFFFF9705CFFFFF77 +:105480000C30C30CC30C30C3CF3CC000F3CF3CF393 +:105490000020CF3CCDCDCDCDFFFFFFF5310FFFFF7D +:1054A0000C30C30CC30C30C3CF3CF300F3CF3CF340 +:1054B0000040CF3CCDCDCDCDFFFFFFF3316FFFFFDF +:1054C0000C30C30CC30C30C3CF3CF300F3CF3CF320 +:1054D0000000CF3CCDCDCDCDFFFFFFF1302FFFFF42 +:1054E0000C30C30CC30C30C3CF3CF300F3CF3CF300 +:1054F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFEC +:105500000C30C30CC30C30C3CF3CF300F3CF3CF3DF +:105510000002CF3CCDCDCDCDFFFFFFF630BFFFFF6A +:105520000C30C30CC30C30C3CF3CF314F3CF3CF3AB +:105530000004CF3CCDCDCDCDFFFFFFF2304FFFFFBC +:105540000C30C30CC30C30C3CF3CF300F3CF3CF39F +:105550000008CF3CCDCDCDCDFFFFFFFA302FFFFFB0 +:105560000C30C30CC30C30C3CF3CF300F3CF3CF37F +:105570000010CF3CCDCDCDCDFFFFFFF731CFFFFFEA +:105580000C30C30CC30C30C3CF3CF300F3CF3CF35F +:105590000020CF3CCDCDCDCDFFFFFFF0307FFFFF12 +:1055A0000C30C30CC30C30C3CF3CF300F3CF3CF33F +:1055B0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF73 +:1055C0000C30C30CC30C30C3CF3CF3CCF3CF3CF353 +:1055D0000000CF3CCDCDCDCDFFFFFFFF30CFFFFF93 +:1055E0000C30C30CC30C30C3CF3CF3CCF3CF3CF333 +:1055F0000001CF3CCDCDCDCDFFFFFFFF30CFFFFF72 +:105600000C30C30CC30C30C3CF3CF3CCF3CF3CF312 +:105610000002CF3CCDCDCDCDFFFFFFFF30CFFFFF50 +:105620000C30C30CC30C30C3CF3CF3CCF3CF3CF3F2 +:105630000004CF3CCDCDCDCDFFFFFFFF30CFFFFF2E +:105640000C30C30CC30C30C3CF3CF3CCF3CF3CF3D2 +:105650000008CF3CCDCDCDCDFFFFFFFF30CFFFFF0A +:105660000C30C30CC30C30C3CF3CF3CCF3CF3CF3B2 +:105670000010CF3CCDCDCDCDFFFFFFFF30CFFFFFE2 +:105680000C30C30CC30C30C3CF3CF3CCF3CF3CF392 +:105690000020CF3CCDCDCDCDFFFFFFFF30CFFFFFB2 +:1056A0000C30C30CC30C30C3CF3CF3CCF3CF3CF372 +:1056B0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF72 +:1056C0000C30C30CC30C30C3CF3CF3CCF3CF3CF352 +:1056D0000000CF3CCDCDCDCDFFFFFFFF30CFFFFF92 +:1056E0000C30C30CC30C30C3CF3CF3CCF3CF3CF332 +:1056F0000001CF3CCDCDCDCDFFFFFFFF30CFFFFF71 +:105700000C30C30CC30C30C3CF3CF3CCF3CF3CF311 +:105710000002CF3CCDCDCDCDFFFFFFFF30CFFFFF4F +:105720000C30C30CC30C30C3CF3CF3CCF3CF3CF3F1 +:105730000004CF3CCDCDCDCDFFFFFFFF30CFFFFF2D +:105740000C30C30CC30C30C3CF3CF3CCF3CF3CF3D1 +:105750000008CF3CCDCDCDCDFFFFFFFF30CFFFFF09 +:105760000C30C30CC30C30C3CF3CF3CCF3CF3CF3B1 +:105770000010CF3CCDCDCDCDFFFFFFFF30CFFFFFE1 +:105780000C30C30CC30C30C3CF3CF3CCF3CF3CF391 +:105790000020CF3CCDCDCDCDFFFFFFFF30CFFFFFB1 +:1057A0000C30C30CC30C30C3CF3CF3CCF3CF3CF371 +:1057B0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF71 +:1057C0000C30C30CC30C30C3CF3CF3CCF3CF3CF351 +:1057D0000000CF3CCDCDCDCDFFFFFFFF30CFFFFF91 +:1057E0000C30C30CC30C30C3CF3CF3CCF3CF3CF331 +:1057F0000001CF3CCDCDCDCDFFFFFFFF30CFFFFF70 +:105800000C30C30CC30C30C3CF3CF3CCF3CF3CF310 +:105810000002CF3CCDCDCDCDFFFFFFFF30CFFFFF4E +:105820000C30C30CC30C30C3CF3CF3CCF3CF3CF3F0 +:105830000004CF3CCDCDCDCDFFFFFFFF30CFFFFF2C +:105840000C30C30CC30C30C3CF3CF3CCF3CF3CF3D0 +:105850000008CF3CCDCDCDCDFFFFFFFF30CFFFFF08 +:105860000C30C30CC30C30C3CF3CF3CCF3CF3CF3B0 +:105870000010CF3CCDCDCDCDFFFFFFFF30CFFFFFE0 +:105880000C30C30CC30C30C3CF3CF3CCF3CF3CF390 +:105890000020CF3CCDCDCDCDFFFFFFFF30CFFFFFB0 +:1058A0000C30C30CC30C30C3CF3CF3CCF3CF3CF370 +:1058B0000040CF3CCDCDCDCD001000000007010051 +:1058C00000028170000B81980002025000010270FA +:1058D000000F028000010370000800000008008033 +:1058E00000028100000B8128000201E0000102009B +:1058F0000007021000020280000F0000000800F004 +:1059000000028170000B81980002025000010270B9 +:10591000000B82800008033800100000000801001E +:1059200000028180000B81A80002026000018280D9 +:10593000000E829800080380000B0000000100B0F8 +:10594000000280C0000580E8000201400001016003 +:10595000000E017000038250CCCCCCCCCCCCCCCC93 +:10596000CCCCCCCCCCCCCCCC00002000CCCCCCCC87 +:10597000CCCCCCCCCCCCCCCCCCCCCCCC0000200077 +:10598000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC57 +:1059900004002000000000001F8B08000000000031 +:1059A00000FFFB51CFC0F0038A277033309CE345E2 +:1059B000F0E981831829D35FC6CEC05001C4554099 +:1059C000BC0B883FB132307C66255EFF352904DB95 +:1059D000488281211E88D7883130A84922C41DA45D +:1059E00019182603F9A150B147403A5F8A32770F60 +:1059F000169CA68029E62A8760A7639147C6196886 +:105A0000F24BE550F99904F40F34BEA28ECAFFA2FE +:105A10000AA113A0E257D1E4BF42E53BA0FEBAA61B +:105A20008EDDDC4E32FD5DC302A101FC99B04798CA +:105A300003000000000000001F8B080000000000B1 +:105A400000FFED7D0B7854D5B5F03E731E3393798E +:105A5000E424E43181104E1E2068080384888AB74C +:105A6000271030F6D27678D5582D0EAF10F2866B0F +:105A70002DBDB67F06084978A8C11F11ADD5E12913 +:105A8000F6821D3122B6880328D2ABBD37587C552B +:105A9000EB1FD10B8A90442A6AEFB5E5EEB5F63ECE +:105AA000C99C9309047BDBAFFFFFFD7C9FEEECC735 +:105AB000D97BEDF5DA6BADFD18C93181A40D23E476 +:105AC00022FCFB0621929D1032A1379DE32021D7B5 +:105AD000184292662FFDDD921442DCBAE2BF49A360 +:105AE000A9BBFEE41A9A5F5FECF0AFA44D5B1F4DBB +:105AF000786A092DBFEFA12FC34FD07CFAEC79ADA6 +:105B0000C5B47ECE24C90F5D1D1AAB1002EDE7D8D7 +:105B1000C276015281E5979030A17F92AFE8F845B7 +:105B200084B8E89F2497FE37891CB2A5603EE4D173 +:105B3000A09E029946483631FE55607E36FC09F536 +:105B4000447767D0EF759E77E513EC7F8E5F0ADBB5 +:105B5000E94773F20372C84DD3C6086D49C71DFBF0 +:105B60005D3908F9C00C99E46387B6D8FE6FCA0F97 +:105B70004C7514D2FE670B08FFF9D94936DA82CC8E +:105B8000A6EDE13B224E1F1ACC679FD9E8B8DFE0B3 +:105B9000DFDDDF40FFA7C05F4B09A1E5CB1C0C9EFA +:105BA000E4D9D9C530CE8919D71643BF73A61332AD +:105BB00088564D9D3DF69044F3EB1A89DF4EDBCDC0 +:105BC000290D1CCF81D9F8CBA79302E8978EEE6000 +:105BD0007D5FC4FFEB38EF643EDE3FCC1E2B10FA36 +:105BE00041F6978AA95D72A0F953D14B486A052DF9 +:105BF0001F1953EE9F769AD0F2E4E9E6F64013724D +:105C00001D2125C49372EA1AFA7716C9BA2842AD43 +:105C10006A0B8CEEE50F6B4AFFFDF922D001FA12F8 +:105C2000FBD61F6A9CE9E9A0F85A377B9687D0F427 +:105C3000F5C02C0FE0EFF5D9B3108FD6F673666779 +:105C400027025EFB1BEFFE063AD008FA3DC7B3B54C +:105C50007E9048EA23F4FB393AD1C331FDDF01934A +:105C60004D256409301B4DB325D5A6D2FA6C8DE8BD +:105C70009138E39502B1693B92499928E352F30FB9 +:105C800061BB3726D94AC371E67307EFC7551AB807 +:105C9000670EA56FD674127551BA1229AAC6E2759D +:105CA0005D8A541A8E03C7DD1C5E42687BCFC0E15B +:105CB0007165D802D09F32470CC4C2F50380674299 +:105CC0006F4AA24CEEE6F818FD72BFFB6C508F33A2 +:105CD0008FBB008E0990AAEC3B0E8F0C7C9301B217 +:105CE0009682FC43C26324E0FBCC1EB9240107E585 +:105CF0008FA1F01715AE2DA47BD41214B256EC4729 +:105D0000F4A42403BD5711DE0F29514F517E1542D3 +:105D1000AB848BD75C6A9E123965F035F0A93B19CC +:105D2000C7BF1C5E48A018E55231D48878C007E38D +:105D30002BF94DED02A5CBBAD1E57E946F8A219067 +:105D400033437EE1DF57F43B37FFCCBD9CD291CA91 +:105D5000916B39D38F8ADF2C67EB928EB50820C800 +:105D600064B9490F1012244077036FEBBEA278BCD0 +:105D700004BF5BFBDD6FC8E7603298C927933F051E +:105D8000FA07BD79D37E07F0F53ADF5E07CC6B5D8D +:105D9000FE5E827A8AD3C7E8D795AF5D52CED681B0 +:105DA0007C8D80EEC348A79EF2D1A7C6027E76A660 +:105DB0002AF78B747E3B9308EAD9756B48782BD011 +:105DC000B594E5B56F69E1B5748E3B9DBCBE98D6C0 +:105DD000D3BC06EDA9BEDB3A490B87687E6B8B8D81 +:105DE000B51FAB85459A1F319184148A4F6DC5C28A +:105DF000954E5ABE75A3EA17B55EFD34A225672DF0 +:105E0000B4DFB2DEA60AF0BD8FAD233BF3493844C0 +:105E1000C7DFB139F99B23693E14B2F987D34FF23A +:105E2000F8FA45D9A5442802B4313A9C21795CAEF0 +:105E30000402E5A9BC7CCB7EFFBF8EA4F03D365D9D +:105E4000F2AFA0453BD6CF4CD0289E766881043F68 +:105E50004D7FF0C07CCCEFCC0C2600DD766E9C9F95 +:105E6000004CF1C0E6991B46417B61D2611DE96C93 +:105E7000D6FF471F283AEC00384B999E4F6A0D7E9B +:105E800053A2F9BC4912B9894E21CFAD21DCDB1FE9 +:105E9000B211584FFBE86D8BBE4ED4CD7957EBB4A1 +:105EA0008F817F5D0F160920DA3B3586E7413792F7 +:105EB000F08AECBEE3EF5CC8EA13295D800E2EBFCA +:105EC000625967965AF856477970713CB95A751CF1 +:105ED0008F487A8990D68B57FA9F4662F0E97AF01C +:105EE0002881F5E98AE76381275DA07C0F83AB9C5D +:105EF000EFB91E1CF7CA5763E3F1B121EF1EA07F73 +:105F000022C577612404EB507A61240AFCE2C95768 +:105F100034B00B9A0931C9C5A1D1FB7C1D203713C0 +:105F2000223E58AFD78D7E83C98F5681F830E66FF9 +:105F3000B4F7E4B79358FBC1A88772F8CE537869D9 +:105F400039BB87CB594F7F84AD4724731CC2754F33 +:105F5000E161755E1C7D4CC80A94CB9749E07A815B +:105F6000A6DECDED51A7066CAEDF0079B7400291F9 +:105F700038DF4D13D87AD242745DA0E9A3442F16BE +:105F8000709D4B66FAD7B22EF5D19FBC5D16E9160F +:105F900040DF68D43E803487F831CD23014C4792EE +:105FA000564CAF26114CF3493BA605A41B5343AFF7 +:105FB000F8892A427EC4C4FAC920E7A4DA638BE5D3 +:105FC000BBD06432B23ECE3C9A2D787390F8EBF899 +:105FD0001D025FE748A68AFC43F87AF16EB018E824 +:105FE000C55428FCBBDBCCEFE224BE0E38EA3D6989 +:105FF000805733DD8D5454CD7C5A6DF0A944241C58 +:10600000C7321FC463CCB8D6FE5673FBC6989F9C9C +:10601000A2231F496E66CF5038F4BD71F0D1280815 +:106020007C9E41ABDC3AB229BF4B49B6C85A9A6B49 +:10603000744F76E8382F3F894767EB7CACF02ABE77 +:1060400081C1B3A9079E0ACB3AFA97C2F34FA6FEC5 +:10605000A44CB21DD60BA28670DE56BCF6F9DE4209 +:106060008FFEE4D29169D6574A8AD70287859F0668 +:10607000687F7CE34BEA7FE4C3FA1B21412AECA949 +:10608000F90101E67FAD401A13295EC868A2EDA0B0 +:1060900070CDF56ACC8E8B693719F491660BC97493 +:1060A000BECF92EE23D03EE427911DF4B367F36D8B +:1060B000A55B697DAA9FB663FD05401EAE1D6D0BF5 +:1060C00040B9D19F4E9E32F547FD2E11F0E136E8E2 +:1060D00063F1C3E4B136B41F957CA26F89235FC717 +:1060E000B97C151D71EAB09EB8CA94B0331BFA8F03 +:1060F00014433EB59AF8615D9FD4CDE651C6E130B8 +:10610000E69DFA5940007E6AF7313BC05548D03FC2 +:106110005432DA74F01FDDB40EF5427E541753503A +:106120003FA23FD81F9E3D5F3DED0BD07E7DD4B991 +:106130006A07BE92FCE9A09F578F56C860FABDF867 +:106140003B3BF6FFB9A762188999CF470DD1B10B38 +:10615000A9C170A6E118A6671BDA31ED6C780BD3E4 +:10616000FEE94A598EDACEEB7EE2D7C01E100F3F11 +:1061700047340FC01DD5755C171CA212B32E808248 +:1061800006FF6FD3D8BCF0DA6CC46B08E64DD56758 +:10619000787836E05B0A009E873822C2D27C867708 +:1061A000C03FD001CA8B8E3CB702F15C4DC6029E47 +:1061B00037C9A40CF43CE013D6897D82ED0E800330 +:1061C000F2F369FEFA8FFAC1FB5986F78C97299E84 +:1061D000004E494B64C6AD8EF2953B910B12D7270A +:1061E000BD7A92F9D9BDF6BDF6EF00CF964689ACDF +:1061F00085BCA6684A11B7F7414A8215D3C1DFDCD6 +:10620000563EFD28D80BB9E25787645A3EB45E3A31 +:10621000D911234F596574FDA476C2B0E5E6F2ECBE +:1062200090394F07407F34B7C55C3EC4C6F5AE8792 +:1062300078401EADF35AB6E85771FDD3550D24EAE8 +:106240009663F202C3A79117BC133B42747ECB4600 +:10625000118C034CB7B1F5B315BEA37C712F4FD78A +:106260005BFA315269A2DB46C6303D196F7DBADD5B +:10627000563CCE46FB6BB04D1E67A372E4922204DF +:10628000EC77975BD1E3F993D36D128E9F20B5EB3A +:106290002285ABFB3AE2DF4AF1BE4CEE8E827C2CCB +:1062A0002BD6FC215047FE30CA6312D56162F61529 +:1062B000C153027050784A6C384E04FBE9A6380787 +:1062C000FB7D99CCFA5D364A236837F603E75536ED +:1062D00019E10CD80409FD344E97551539F74DA333 +:1062E000D94E559F05FD67260567C17846B96F7E73 +:1062F00029FA6319C3CCF42B77D467017F540622A3 +:10630000D3807F4E7B5F6C92E9BCB73610BF44F1FF +:10631000FF9E2B701BF457737BFD08B07FDF065E7A +:1063200098002A3B807AACA564A55FA2E572891427 +:1063300095293FCA130FBF2517401A2A86388B9319 +:10634000D4337D47F54B2235BD1C23F58F217EA22A +:10635000803CD072556F25600F38A8DB703286EF15 +:10636000944C731E6CFAD87C7F7AE3722998E727E5 +:106370008703FE09DAE9DD49CC7F9226FA0B00DEBD +:106380007BAFFFA606F0FCC46633F967567F4D5A13 +:10639000FE6F69791068E2FEB6B4FCD5B4BCF1803A +:1063A00097569C9763CA32940B05F02432F907BFC5 +:1063B000BE671DE478F85BCFDB582F5737BC35F844 +:1063C000C3E120A71D833FA4C4592D0591FF423E80 +:1063D000F0B5281C92998F09784F1362526E1718E6 +:1063E000F69B9C5A887494DCD2A98E98F5DDC08FF8 +:1063F000B2FCDDC11F8E87F46D4CAD7855A4200131 +:106400003FD068D713B718E0FAEF34E2A979C41F78 +:10641000A53873A4B0786A7A5E280AF37252FD092F +:10642000EBD33D235F6BC5F081C50F3B94AD203F9F +:10643000B48CB6615CB36578E49002F90C6A40D123 +:106440007A67CA5D21886D4CCD637CE3F4B3F5D4E3 +:10645000353C8C7E98A1BFBD1C1F5EAD1CF5B3679B +:10646000A2D9DE31D601272BA2F436DB51CE94A679 +:106470004FC582BE7E9A539B761AE569A4B93F2325 +:10648000DED16EE3F18B6BC9B5683759E212FDE1DD +:10649000CD6BF87113D9BCDCD34918FCE6F48951F3 +:1064A000C49BD7CFF066D89B1E3EBF9B4A2304FCFB +:1064B000BE9EF8F3CD0C6FEBAF8BA27FB77EEC29BD +:1064C000B467BD851D263FCEF81ECAA1FEFCC4766A +:1064D000A8A1F618CB1B71238AA7E91969BDEB6146 +:1064E0002BB7DBAD7453279262D0634747A7158360 +:1064F000DEBEB784C24EAB3C7A589762F0ADF27EF6 +:10650000D47C86DF7BCBD87C697BF4D3EF9D9893DA +:1065100004E366F2F8B0117FEEF1CBEBCD784F28B3 +:10652000B4C4852D7EB7EA67F4524BCCE5AB395F36 +:106530002B22A7572A19CEE835303E4F32F8BC84BB +:10654000F17932DF37482FD10E011D924A99FF4D64 +:106550002C7EF34D291D8C5E378FC8003FFCFEA9B1 +:10656000DD3E669730BA26717EBCEFC61102C87157 +:10657000728926407D723EC35332C513AC77C9A5DC +:10658000CCEFF64ED4B05D5209A35B0B7C4CE15FBF +:1065900003748A891F3B4B5B75A07F6BF14E1D74A2 +:1065A0005932C5E1200ACFD4520A1BD89DB45F806E +:1065B000D75318C5B85A524970D8A5FC7A42A2825E +:1065C000CD87F8106C684BE93C25587E6862B22094 +:1065D000D07EEFA77CC0F180713C178FA3DF5F787E +:1065E00012F5DCFDF04D36C8A9F6EB1C9A27A5364E +:1065F0003FF807F797E608F1E2E7C6BCFB83CB2A32 +:10660000C712F83531FC7295C8E3DE16FE5D4722ED +:106610006A2EC857486FF7A5F5EA0F83FF7AE4653D +:1066200012E3CBFEF489A187DD2418B265F7D51FEC +:1066300092CEF8DE9E174079EB03EF24C6AF528A64 +:10664000B9FC3691DB7F865ED19207142727A10023 +:10665000AE7722D74F4FDA020BC554F0BBC3B84E0A +:10666000B8C874AE37199FCA9CFFA6E633BDE24A8C +:1066700089B076978DA73A90DFD634A8A81F5AC65E +:10668000DED59E43F1B06678931FBE738C6B19B94B +:106690008DF6DB3C7C79702B0CC0FD30D4BF22AC76 +:1066A000838C5F8D7D30030E9219D2619FCC097E61 +:1066B00011E06724DB5F902412B58FEB1DDF954757 +:1066C000E1CD6769289FC10DFEC9EBB6E02A9C6F3A +:1066D0007E6B94A29BCE9BC9CB6A21425C22CCEB01 +:1066E000727C1EB231BE8E9FF6F75D02ECD3C4E120 +:1066F000DFDD22DBA7592D478850087E1BED89F28C +:10670000C9EA6C6A97C781A391F36BD52E67F8C36A +:10671000187EAB892499F275FB33C21FC6FA117734 +:106720000AB84F51CDD158433AB200CFEF291AF6EB +:10673000576BEB48837C17E94E5B027810038F8B15 +:1067400074FD7752BEC4B8907B60EBD6E5F0A781AC +:106750000CD18540CBE4A90F79988E17DC07E3694B +:106760002A2BBFD271E3F0F50BB17C4DC457596AA7 +:10677000E56B7F14F9DA9D12C57AB79FF1B5C18F29 +:10678000899C1FAD7C688CBF9EC7AFD6723E5F33BD +:10679000A1498570DFDA519B309EE62CDA5C017CE2 +:1067A000DE32AA250C7CDE64F035DF17A1FE2EDB7D +:1067B0001FD35AA3B04E2672BE56D4EE06907BEB82 +:1067C0007C5D9338BC3405BE06B8395FBF07F893CB +:1067D000FDDD08AEC1D76B07CCD7BA456F9BD3FEA2 +:1067E000FC27D9C2D71E89F1E767C0D7004F0AB38B +:1067F00063DC3E96CA7EEADFC7E9E70689F9996B52 +:10680000B91CACE572B0B61F39F83F22F303FE9A0B +:1068100072308BC98143A2E58993AE8C1F25B0D31A +:10682000E3C87B9E24FCB5E1DE3443BC723CFE270A +:1068300030CD84BEF434D2CF44E7C0E43B8FC9737B +:106840007F72BE76687C38FE5364F4A7F82E9226D9 +:106850005C39BEFF5A7015727E36F04382C528B788 +:10686000317A663AC02BA9869E7904D3A979AD28DE +:10687000A786BE81580AFA2B6A2BC63B9C99AD6845 +:106880009F39F398BE31FC24EB7C8DB87813D73355 +:1068900049792102EB9F3D85703FAA9EF95199CC21 +:1068A0001F30E2D586FDA8187ED4D0BB709FA77993 +:1068B000783DDA97CD37D63BE2EDC336FBEE77F085 +:1068C0004D5FD33EEB1A5A0EFDAEC9BB9FC4B3C396 +:1068D0008C7918FB464E3E6E731EB5A8605CDF32A5 +:1068E000FCDE6AC73467B2FE7ABEE77A57EED1BBE8 +:1068F0002C8F76546E8C9F6FE9C7E00385E843A325 +:10690000103718E41E09E74C9A84043FD8C74D920B +:10691000209D72901E7BA95A891640FF2766BC9C59 +:1069200085F6B23DB806E4BCE9AB8003E2A9AB53FF +:106930005EF3C6969F9DF1E6B7C16CA5DFD5E27EFA +:106940008E8348B1FB6327DCDBD17E4BC837C7E9B8 +:106950009C14AE0902C413CCE50A8FBF2899E672D5 +:1069600099C75FA4144B39E70FB934BE5E7993EB36 +:1069700015DF02764EE7C41C16D73B712B4F6730EC +:10698000FE3EC7DB75F334C2F5EE5F531F25E5F617 +:10699000C2EF9BE2C7F822996547BB3E2B859D2B32 +:1069A00020B1E726E05F6BA24462FCCCA18197FF97 +:1069B00008F1D4610BBECA063C6B15EA615846DB90 +:1069C000A56C9CC76342F72818CFE63A8BFBF5020B +:1069D00045E3726A120BF4DBDB2185EFBDC0523A4E +:1069E0008F7B0591BFECC03722D0298CA98B44B195 +:1069F000DE433A309F081BE6B9E08751BF4BC433F2 +:106A00004C611BC68D7ECCF643D688786E83A80376 +:106A1000B4BFC9ED2AF89742887EE71AF877BE40DE +:106A20006B31C8C4E0B208C693ADED7C53D839A031 +:106A30003E7AFBAF4FDF375273818F542C37E81CFF +:106A400014F54E6942DFF25F8981F312C6AB58DC60 +:106A5000CD5A5F2AE91740DEACE5C20B7F3A057ECE +:106A6000F4AA6764F4A3A73C2347BF41F3355B0452 +:106A7000F4536D079DE80F773EC2F2518FA243FB9E +:106A800073DB058C07D5D9DBEFBD01E28ACF880423 +:106A9000FD8D7019EE8B9DE27326FB59BE9C07801D +:106AA0006AB61C9A0BDF57ECB713D877A8796EF14A +:106AB000B76FA0F9C5C764F4516A76AC50607F65C2 +:106AC00049588840BE6B32C1F143FBC4F00EDABEB8 +:106AD000CBDB9E36C70DFB2B0EA25D45E1F6B4A7BE +:106AE000CDA6F4A90C3F350DBEABDC2DF8C1FF9847 +:106AF000F2CC8EA319F4BB9A27043CA750B5CB4522 +:106B0000B418BA9C6A13A3DF80F8339D27F8C58BAD +:106B100049EB34C07BCD8E0D8A1613B73CD330922F +:106B200068F6DE7CCD13741CFA5DED93821FA658C7 +:106B30006B2341E08FCEE79C65DBDC30BF15CA08D4 +:106B40000FCCAB5981768BC3F3F6C17E7A65788B17 +:106B5000328DD6573EB245298FE1A7AA5DD7102DB9 +:106B6000863F4E6DCE4DBFD47A7B86AE5BB1F0547E +:106B700012A6B788145666C4EC7B76C8499C3F457C +:106B800053FF06DF875E2718C70A3DEF41BC1A7422 +:106B90005BA632BD60D0EDBCCAE9287517CD88B3BD +:106BA000AF7A2FD0C10EF12A15D3FB1B7C986E6CE7 +:106BB000D0903E9B007F57E1BE06967B279162886E +:106BC0008B7875A2C2529F3C5D2F96214E1260F9C0 +:106BD000B4DB83827689F91BE92639380F825CB7EA +:106BE000C94F4C96E8BABE49092E257E3ABEB47705 +:106BF00072C97560A705E7C8A9B09F1DAC60F1E830 +:106C0000880FE4A289EFCB7C4B66F2D694A1607C1E +:106C100064D3F78BB6A1ED41185E367DBF7C27ECBF +:106C2000ABD17EE6CA54AE1A65DA4FEEE5FB499B5E +:106C30003BD1D44FDADC0AA39FC5D88F7360FD6CBB +:106C40009A7BBD199EB995463FF5D88F6760F34A88 +:106C5000BB6392199E3BAAB19FF4DBFD681F8806B7 +:106C6000FF9076DC1775EF4E1AB796C4F2D1E41F89 +:106C7000C3781E2A55B17C943831C1244F497AB269 +:106C8000293FA874B0A97D6A20C7549F5E76B58558 +:106C90002FDDA8BF314F818A26B138AB325841BDB4 +:106CA000533CD881F9BB06BB51EFDC757DF02AB0AF +:106CB000F70056D0F37729C1316A1CBEA1F3120840 +:106CC000C6CF341BA47DEC32BEEF3979C85723DE22 +:106CD000A7DFD7D9BA4724D1FC434AF12330EFAD1F +:106CE00032B3E38D3843829DA0FE6BCE2EDA168A36 +:106CF000C16BCB50CA2F426FBF2D72D007FCB87347 +:106D0000F56F574A14BEA6A10A1E6E7A5CFEEDE12D +:106D100010B5999B8796FB00FF7685EA8FD8F11511 +:106D20003A7E3E8EBF1BC6DF2B333BD93ABE3D6752 +:106D3000A2697C475685697C8742C7A7F2B16FF587 +:106D40003B7C7C8ABFEB0979567E07C7B76755E065 +:106D5000F8CD0AA9308D9FD033FE01909FC3FDCDA1 +:106D60003FE77AF3FCB32ACDF357D8FC8FAEFE8011 +:106D70008F9F80F37F59FE80CD3FAB92CDDFCEFA5F +:106D8000ED19DFDB83FF5761FEAFF537FFDC49E626 +:106D9000F90FAB36CFDFCEC67F63F5277C7C378E0D +:106DA000FFA6FC099BFFB06A1C5FB107FDC047CA84 +:106DB00090847AF09FA961A461405DA3E3403A9278 +:106DC000C5A937C83908C75D098CEF3E4FA0FCE65E +:106DD000EED5A7244C2590EACB5ACED355BB8B15C4 +:106DE000E62F84D05F58C4415DB85FC4F58C6CB4A5 +:106DF000878753783BF78B21C82FDC78239E5BACC9 +:106E0000B313DC77A75630FA1FFFF1C0E8ADB1F33A +:106E1000B2A68B5A65CBFE1383C738EF5424ABA6BA +:106E2000FC2988A7503D7C12FC1F9A9E96E978B4F5 +:106E3000FC43F083AE8A951B762E8C7677229FCE0C +:106E4000EBBB1CFE5312C3F7A93B05DC47F87CC320 +:106E50005205F4D9A25697C96FA8E374EA7ECE8E84 +:106E6000FB8DC679BE5B501409F9FDC16F1D05BBD2 +:106E700071F1E641A6EF6E27E1D5701473C1FA797E +:106E800043553AFFDBCAECE3448C6BEB43581C9C44 +:106E90000C81B84959DB067908CDDC52269BECF908 +:106EA0005B83E6FC6D15E67CA71C966D60CF2C110C +:106EB000C816DAEFF7EB65CBB900368E5749E676A0 +:106EC000251BEFBB948619B4E8FB908E836215E90D +:106ED0003A5765DF1AF0D4DD2D9328AEC71DA9B847 +:106EE0000F144A45BF2DA8B2795BE19D2B3BF400FE +:106EF0008567EE8F44C4A715FE8E832EDD46EDF325 +:106F00008ECD7F90217E6C9D8F15FE3B965BE7A317 +:106F10002AB03ECC0B59CB199F58F9A96E7FF13698 +:106F2000B33D7BF3B658FBB56AD70C537E49F85690 +:106F300053FBC59BE799EA17B52E31D52F68596ADF +:106F4000CACF0BFDC8D4FE8EE52B4CF5DFAF5F63D7 +:106F5000AABFAD6283297F6BF02153FB5BCAB69851 +:106F6000EA6D07477D07E468D5EB229EFDBDE03E54 +:106F7000752FD89B17DC12EE737E44ED159083338A +:106F8000D45E81B473FF78F4A7A91E2C874DA2F9B3 +:106F9000CA98552D99A09709EACF7265C2AAD02444 +:106FA0008A17B0D7A97C889B15121D04CE4C720F8E +:106FB0001F778B31F51D97A9DF4C057D7CDF7AB1FA +:106FC000237E79DDD679C3D4387E6AAFDC9221B0D6 +:106FD000CE7559CE9F1869B5E53CA7B1BF7D81EB51 +:106FE000D96A85E983EABD1993617386FAE523E2DC +:106FF0009D9BECF93E22B00D48B0FE53811F869850 +:10700000F66BAA76E59AE4FBEC2111E1AA059D4016 +:10701000F5EA1752608D0272163D92356B34C0A1AD +:10702000AF5540EFEC4FC575FD6C43E936D8AF3F27 +:10703000D310C0F4A386324C4F350431FDB0A10209 +:10704000D3930DF59876342CC7F4BD8610A6EF3691 +:10705000B460FABB86564CDF6AD88CE91B0D614CD4 +:107060003B1B744C0D79E8D1BF016E0F1B1BD784FD +:10707000DBC37C2E8DA93DE7C270FFF7BCFBF3118B +:1070800060EF9F7FCB8EFB6CFDE1CBCA6FFDD351D0 +:10709000477BA53C3C089D636BBD3381D1C9692307 +:1070A000A5641CECFFECF4CFCFC7BCC42EF584FD67 +:1070B000333C71FA85785DFAE5E944F4EE829994FF +:1070C0001EA71EFEAF22E8F702AC7F60071C1171FD +:1070D0001D26D16D7EA0D795E24D78E1F759102F8E +:1070E0003BD783BFF62C888B5DABA8D8FFF9363B26 +:1070F00081F8D2F9032EBCCF75FED8362FC8E33203 +:107100009F188E3D47614D6B22D961B7C9EF36E7B5 +:10711000CFB70AA5781E9A6889B347035FA961387B +:107120000FD2D9E0C3D4E867994FC171CEECCA65DC +:1071300071337E5E83EC4E427EA57E27B6FF9F862E +:10714000A7BF7E0C780869231F38085E71BB98DBE7 +:107150007FFB7EF949FA4C81F82A39207F0EF682AE +:107160009DFE77111C652261DEE8B72E2286EC6356 +:10717000A07CB7693CFA9D66F8F417732EC5B7E694 +:10718000FB34220468BF469CA40AFE80F330F5025B +:10719000C6AB8C784997E46E11C6F4C64BEA78BC4E +:1071A000B8C6D1A10469D1B9B6DC4BEE9F9E69384F +:1071B000A6C239AF0A47AB02CE4F45645409E8B9BD +:1071C000736DABD2C01EAC12CFDF152F7E9B6767ED +:1071D00071BD2561B9DBBC8E72FE20B45FA39C1D1E +:1071E00072749F8AC99FB5313BDBDAEF04FBC0F6AE +:1071F0002D6A771F9F7683D6174FB5FB3F55303EDC +:107200002E11535CC9C0DF7B4A60829DE2A972D710 +:10721000FB688F7E248746DC7D09FDD4777E6E9FD8 +:10722000E97C7288B4C338F327F2818876CB3B744B +:107230003DFDF815999DDBE4E7807BF695F9BEFEF0 +:10724000029E9BDF5685E7843EDEF78F68FF2D2484 +:10725000012FD281B416811D798ED84A014FE7C81B +:107260006BDEF13174B8953A4A40EF052D663B86E6 +:10727000DABFA6FCE2CDE67C39999906FAA47CA394 +:107280004CC202CECF547FB35DC57E1793FA265809 +:107290005725EE8FCC57893484EAD59A677F5634C8 +:1072A0008FC211B4333FC888BF2C49667660654AE7 +:1072B00058817DC20FDAC67FF70620833DDC04715A +:1072C000289248FC3B485FFC5E29FC56788DF5BA55 +:1072D0004F1C88C321EE12E2EE03D6DA056ECF868C +:1072E000303DC0E76DF805C72CF915767EDE5224D7 +:1072F00022D0FD9CEA08D912B1DE1F8578DC5EBB86 +:107300007F950671FCC06A7B6A6FDCDF6897640F4B +:1073100062F959E1D5723CF720450BF0DE218FEF81 +:107320002B9C1FC4046F019C23F540DC1ECE753AD4 +:10733000BD5B21DFE4A9C0F31F7520EFB4BF7BBCA8 +:10734000D38E419CDA415AA33AE55FBBCFB21FA06E +:1073500099F32E904BD0675080E7A209C6B95C2301 +:10736000CDED3C7E73FE312E8F7481433EEE39DFCE +:10737000E67047E13C0999289DEDF1B772C0DF63E3 +:10738000F0C3FD56687FA7CADAD7F27DDD3BDF9EEA +:107390009C9E7C097D54F7A540C231EB489DD4AD3D +:1073A000001FD67D2961F9D7D69B1A5D5563F4E697 +:1073B0002B4AF059FB04A627013E818E13BBDF64E4 +:1073C000BD877002F861422F3F7C6D385288497F3B +:1073D000BFA7048FC583E36BF7EFEBD3FF09E0BBD7 +:1073E000FFB1FEF3FAF4DF110FFE9A67F7EC0BD151 +:1073F000F5B5F2170F78E110D3C7526B1A9CEFACBA +:10740000DEB1DA0B72F99114F2025D3F0E8B71EF6F +:10741000E7A63B0CBED3DD708FB096F3DD999FAF2E +:10742000FB36F82F9FEF90558C0FECB247ED942967 +:107430006BDB9630F9D8657F9FE59BF1BC53DD7E11 +:10744000B3BEA87CFC81340D0F5585B8FF1C45FFE9 +:10745000A076FB7F4C03BBAB8E74A3DEB37E07E349 +:107460007F998CF6C03C25B16FBD710EAB8EE3A544 +:10747000AE6D1DDE13AF6BBBF934139A0EF43BAD4A +:10748000DF5570BBDFE1309FDF34F042C2CCEE5FEE +:10749000F5C48305EF53B8CE6E7FC52BE4C7F22940 +:1074A000D37FE7230B1EFBA5D6BF5C7552FD186B7F +:1074B0005F1BEBB4B69FFB2B07585A2D47BDE00F5F +:1074C000566F91F1BC7BF59E6D3B1F86F8CCDB7649 +:1074D000FF70DA7FD59E97DEB89EE6AB9E9253A6EC +:1074E000B369B8E19EA2419F3AFADFF271BDF4A8F8 +:1074F0007CFA25451BCDCA7F9CDC4B97AAA70E2999 +:1075000064745F7C4C891C52D87EB6853E91F7A787 +:10751000815FB1EA892F14D05F1F1F14487A761C4F +:107520007C6E7909ED63C013D293D3AB877E96F658 +:1075300075942EA8172DF4B2B6FB98AF07D02FC4C0 +:10754000E3297F3FF94BD8B7F99DDD0F78A878F292 +:107550009FBC309FD3523DE3F39FAD4E83FB20157C +:1075600072284DC59495573CFA03E4BFC5C77F9078 +:10757000C6CEC5EA19FC5C5706CC73D12373709E46 +:10758000E524887C58F13376CFFC82444A9F8A23D5 +:1075900027F739D83A767AAB1D37114FC34202FB31 +:1075A00018AF89E11D180F64E70D7F60EC3F91650E +:1075B00098BFE060F45AE430EEF1D1A524967FB78D +:1075C00037B7039DCE0CD5D3218E5C47A410C78757 +:1075D0007091F62B1E9F9ACECF1D685211FF8EEA36 +:1075E000FF29500EEDDB65DD5960FA8E5CCCEE1D97 +:1075F000FF4E3E3E853B01ECD7D369D41E8C33BF92 +:10760000030E639DA676560C9FC5C83B93FFED6B9A +:1076100098BC1BF21F9E510AF59F9D607204DF818A +:10762000FD42E18AA663FDA1D902EA073B89C69320 +:10763000F3ED32977373BD955F28FC12ACC73D7CA8 +:1076400003E324231DD0BE2DDF48BF8FD5AB30AE62 +:10765000B76FBF861C2FE6FA60AD451F90475207F3 +:10766000B47F5B2D87773E0CF24BE535A481FCCAD5 +:10767000F85EC127BB8FBCF13D2AB79F440CB935DA +:10768000EB55ABDC56EC9D40E2C9ED276E3F892BF4 +:10769000B7B43CAEDCBA3B909FFFD67AD5C0E3D3FB +:1076A000163C1A7AB23F7C5AF5E4B71D5A5C3D4944 +:1076B000FF9D20457DF9D1E04383FF2AFFA506CF3A +:1076C0000BF5F0A9C1873D7C6AF0619F78A4098F12 +:1076D000D6FABBE16F3A85C07332C6CFAB0FB0FDAF +:1076E00067FADDD12185882F1D9739D27A74484AEF +:1076F0006C3E6CC9472CED754B3E60691FB4E4EBE2 +:107700004DEDABF71F51D8B99EA8A99DB8FCA7E4D1 +:107710008338F101631DAA6BFB5409017FB8BBF1EB +:107720007B79250979205EFEBC88F1F22E8AE3265A +:107730003A4ED7EE6C7C8F60B593C557BAD46E2F96 +:10774000D893AB9358BE3B5569023D6894773B593B +:10775000DCAF2BD0ED4D8AB1EFDE3F20A21EEF084B +:1077600093D2787E28DE40A1F8ED20FDD5B3FD80D0 +:107770002EB0D761BC84AC30F0E354D19DB51CE28F +:1077800035AD22DE6B5BB8E2162F9C23E93A90FB05 +:107790009D325ABEE8D722DBA60CE952468C1FF870 +:1077A00011096D9A24C0FEF57AE49F0507985FB829 +:1077B000707D7C79A8E4DF95BBEF5440EF527FEEFB +:1077C00064ECBE87D14FC52396F203FFC8E5A6152A +:1077D000E31F95DBCDF5411E3F18ECE4E7BEC792F1 +:1077E000B1DC7FB7C5DE0F9E2AE67FA78CD2A7EB60 +:1077F0009848E03CC1F90322D2E7FC6E767E00E3B4 +:10780000FCD701BF772BB1E7A9CE827C5DD5BF1E27 +:107810003BFBCCEF8BEE063EDAF74EC14F697A7632 +:10782000DFDB237E05F967DFCC7A87F46D3FE5A0C7 +:1078300013F755BA0E7A90FFBB9EFF4DD6DD907FB1 +:10784000CE8EF1ECAE835F14003F75ADB457801E51 +:10785000ECE2E7EF563DFF454107AEBF8D48C7A9B3 +:107860004EE64F9F3FF05FEFC1FD81F307E8ACC0EC +:10787000BE38E842F9AAFBA513E36F5DCF7F511430 +:10788000EB27FCA5F3A9E5FB9D5D1E52B617E04B67 +:1078900062FB4475BFBA6E1BBC2F51D3764859406A +:1078A000EBA7BCF0A702D0AF5D7B99DDD429773C74 +:1078B0000AFB7981350F34CA945E9D20648369FF89 +:1078C0006BDE280139EA8B973F615C71A0F858FCA8 +:1078D0007F0D3E049DE93F4F184C852907FFF8DED8 +:1078E0003BA0270EDA912F8DF97E125981F6CCE557 +:1078F000E6DDF4FFDCBC85E840E6BD03E63DE1EFF4 +:1079000077DED7C0A1A1D4BE72D097CF9FBF0BF3B3 +:107910007B3C7E847780FCFED2DFF9FCAF98EE7B67 +:1079200029DDBD979FF7877FE7F3EE9FEEBF9ECBE4 +:10793000E9AEC27998BA17FE84F05DA99E9312FE53 +:10794000BEE5BDBFF91BF6FE5A9BBF35271BCF9383 +:107950003AC0B0707B66B6407871EDC8992AD89D60 +:10796000623FEFD54C48607E9528B0F721C850168D +:107970000F24DCCF82630DF80E889BDD3B93DC4D3A +:10798000687713C9DFAE53BCACBD7ABE1FCF1A9166 +:10799000716F05219F39C98FF16E8BBFD928105D9A +:1079A000A0F6AE74F5378F81DF238FB445ED0598CF +:1079B000BE0F69338F63CAAA62F287DCF9E6BC5353 +:1079C00033E7EDBC3F0761F03B7C240CF16C71D4D4 +:1079D0006115CED3896325024FA538496B08FC0E8B +:1079E000BBCFFC7D5202E17EEF5F86C78A0416A7FB +:1079F000128571ED3AE071940DE3DC78481BF1E2F9 +:107A0000C7F7BA08F7AF7BF1DAD40EF894C03F6637 +:107A1000F617FAD584FBD312EF421A69D39DE676A6 +:107A2000DC8FBE2C9D185DB2AA399D9699E862D074 +:107A3000210E7D4C7431F07CA5F4B1D2C58AFFEBE8 +:107A400013185FF7472F832E996E1DEFD7C9DC7F80 +:107A500028013F13F2990182FBABDC7F905274BC8A +:107A6000A724AA7EBC97007E5C941AE02FEFDE86E6 +:107A7000F1A4733F7FFFDB004FD5AF44E2A0F8EBEA +:107A8000DCED2151F85E0A2BE09F56B689B84F40D5 +:107A9000A468D1AC987D62C30FA8FA8507E753B9F3 +:107AA000D71E9E4EBFAFDCF74101DA612BBBD1CFB1 +:107AB00009FD5C60740F7514C03E70A5C4FC112BE9 +:107AC000BFAC4960F196B3CFB9CA20AE23EC62E7F0 +:107AD0007F2B23B7C8F698734DA10499C59B9E735D +:107AE000A15E083D21E0F928802FF6DCA9E1879C02 +:107AF0007D4260F0ED97F19D98CA5D4F75427CAA7A +:107B0000F22DBB1FCCF8BA5D9FE27EC8945FECF10A +:107B100076A01F2E9AE2127DE201BB44E48FDAB612 +:107B20001AF443681EF9A236C2FDEF2BF457AB7E60 +:107B3000F1FC3EB87056F5F4E35E887F9D69DFE1A5 +:107B4000C5B8C0AE4BC7E7FAF8FF9135DCFFFFD6EA +:107B500069764F3BBEFF7F06FEA076F1D30996FB08 +:107B6000ABBB06B1F71449B4E852EF7155EDB9F06B +:107B700028C4AFCFEEFDE45180BBFACF7F7814FC70 +:107B80000A72D0A9C27D82BA9FBF8EF13EE3BBDFED +:107B9000703DD0F9C4E3182FED7C9BFA1FF45FE72A +:107BA000F3A7B3C0CFEC7CEA8F69104FB9F3F9A902 +:107BB000F86ECE9DCF4C492771F4899102FF86075C +:107BC00010AFB5D2ED48DB11F47FCE51BA83FFD9A7 +:107BD00013D789D4B07899C6E339BBE3C7C7FBC4D0 +:107BE0006FDA667DE7C6424865BF460610C7394171 +:107BF000E939660074DCCDE375916F5D328E730EEA +:107C0000FEA0F43A6BA1E385B6458F3D0C756D83FC +:107C1000FA8DE34407803F23FEBE3F41FF2201E48B +:107C200068EFBF60FC0CE8379D4EB873CF852CD849 +:107C3000BFF848EE9E8BEF853C6F57211E51F9FC33 +:107C40009B284F9DCF1CC7F836E171F04ED2F38FC1 +:107C5000C52BF999CCBAED1E16FFE17480F890E6B9 +:107C6000C5721E07627C6DC487FA8B0B8D71B17370 +:107C700027C6BE40CDF67778BCA5976EC244A0D784 +:107C8000FB97DCCF30F0A0021EAE8D8D7BC68FC37C +:107C9000F5C43D2D74037A42BCB327AE49D8137B9B +:107CA0007561E1CD7871F4CE2D2C5EDA29C73F8F56 +:107CB00065C441AF7659E29FE181C53F2F378F2BD5 +:107CC000C5D3609786FD5AF175F6ABF8FAFD5BAE49 +:107CD000819D5FE8777FADDA7C1FE63D2538DD05C5 +:107CE000FB6B6DEF2B04CFA774B3732B7CBE67F9CE +:107CF000F9D3B33F17312ED6143982FADDAA3F8C5F +:107D0000FD572BBC7770786BF7B3F5E3EC5E4FD87B +:107D10004DFB397BF839E4EBDADDEF635CEEE8AE7E +:107D2000A7958E98F516D68F70CC7CCE3E79A8801C +:107D3000C579E3DF1BAB71317BB3EE40FC71EA76B2 +:107D40007F6A1AA72A1451981D70E9F1CE48FA2DBE +:107D5000D0DF997619DF4D3A1311E3BE171C70C9B5 +:107D60007C1FA195C90F5D47F19EC071767FA7F07A +:107D7000B5043C577FE7F1D277E0FDB73BA95883C4 +:107D8000DDDFB682F169DB4FF42140EFB6E3DF13AC +:107D900061FDDA07F88DB1FF8B4ED44FF150FD50E5 +:107DA000F46EA010D8D5AA77AE7DCB66829F8E9355 +:107DB0000EEB4223ED07EE83C0B939BC57EE9D565A +:107DC0000AF088AA4D750A7DE721BBF97D55DEAF23 +:107DD000AC9AEF2190AFC66BD08F6F268B4B66CCE1 +:107DE0003252169F0C19F787CA13C2ABE87C7FAFDB +:107DF0000637BB285E7C9E8DD92F1178276AA20694 +:107E0000F6D3632E7EDEC14BBCECBC833B64A37A0D +:107E1000FD61FFF60D93089E67D8067CD9739E819D +:107E2000440B802F8D767DEA2DE71D32E1132A5A0F +:107E300022873317EE2550FDB26A86772BE41FF1B7 +:107E4000B0F7CDB248F72138DFB08DDBA3D960158C +:107E5000E7F67DE7ECEBBE6F9632A578E9303F851B +:107E6000D3F55F53E15C7CCA2DC54F0D5169852D5B +:107E7000631ADCA34979BC786C06CDCF5FFFF4347C +:107E8000ACFFF7E2B15934FF937B0EB2FA2A01CF6F +:107E9000C1BEB0AE761AF0EFD796FBD9143366B9EF +:107EA0007F05F0772EF0EE77176970AEA25BE1EFF9 +:107EB0006504A0DDD0890C7F99EE779F027F6598DD +:107EC000AD6305F0EB63CF7F9184F716F9FBA12A30 +:107ED0006954E1DC152D9A78F112E7F3FABCFBCC7A +:107EE000F5CB8D49C177813F9AE78DBC6F1A1DEFA5 +:107EF000E18A710E760ED0F24EA39A82745DC8E9C3 +:107F00004AF83DCB457C3E8BC590C202DFAD5C7F1D +:107F100019EF51578B57F41E3587ABDBD5EFFB6755 +:107F20007F00783393827F00FC59DF3F7BC515B813 +:107F300000F519E55FE27D5CE33D33EBBB6844EAA5 +:107F40008EFB3EFB56FE2E5A7FF0FE9B3B28BA6905 +:107F5000FF392F687B8F51391BB350F1C3D1CF311B +:107F6000CB0BFDD220C226047610A71F3CCF88F78A +:107F70001FEE22B85FDB651774F0AFBBFE49457D8D +:107F80009EB9703AFA5F5DAEEC089C33EABA5BC307 +:107F90007D3D8A0101E469E881C428F887541E3ECA +:107FA000B7C8C3E766FE378FDB7551DBDF81FDA9FC +:107FB000BC3F6AA0C5DC8BED12999EEE6AD0108E94 +:107FC000A1247408D6FD818E97E3E6EB37A7CF4650 +:107FD0009B9EEB9E80F81FEE8EC1FF2877BF74CC6E +:107FE00077333AE6BBE3D0D1FA6EDD7BAEE058687A +:107FF00077BAFC28BE5F677DAFCE4ADF3AA9F5218C +:10800000783B2BEDC0A7B8FE18F41BB37C2CD2290B +:10801000869E93008E31073EB501BC061D1FECE71E +:108020003C79A99BAD73D6F1D2CA3A0607E3B49F57 +:10803000E5D64CF70E0A1C457E89CA69BA8DC587FC +:10804000FAB6EFB7FF9C4B9DF32C5059BF14FF734A +:10805000004F06FE6F75F3FBEA7DF17F3BB4A3F89A +:10806000BF1DE63F00FCCFBB14FE0DFBBF8AEB87B4 +:108070002AD89FA27CF41FDACCB41C3AEE34D18DFE +:1080800072B06487C8F731D9FB5F863E59725DFDD7 +:1080900021B817B9E46702F2EB42FEFEE527FCFDCA +:1080A0004BEBB9C1F2B210EACBCB9F1F0CA33EAA97 +:1080B000DA652EFF6777CFBB975978DE172435AD89 +:1080C000F7BD4E2BFECFBBB9DE58E8B4C57B2FD72A +:1080D0004887D6DB4CE7CC33A6F4F483FEA0CFA6CA +:1080E000BD89F1B87F9509C4137429A510DE192044 +:1080F000854209F45BCCE5D7E86FD872F3FA9F1D8F +:1081000032DF43CC6D31DF431CDE6ABE8778D56633 +:10811000F33DC45161F33DC46B768D33E54747AE03 +:1081200037B51FB37FB2293F36FA4D53FBF1C7660F +:108130009AF213DABF676A7FED5BF34DF5D775549A +:108140009AEA6FF86899297F63F73F9BDA471731FE +:10815000FD78B8617911DC5B30F07278A96253A1C7 +:108160007CE9089B5A105B9EA66B059016E9E07FA0 +:10817000F5272F531C3F2A8A5DA78B896CD26F533A +:108180001CE67CD46DFE7D8F972C7235A47E52CB7D +:10819000089A1DBC240FCF6353F93AC6F5DBB10131 +:1081A000EAB7DFA07CD5469B206F952FE3BD019AEF +:1081B00086D88FADB0779F1F729AF9D4D78F5EF9AA +:1081C0009DDB3807D4CAFA53CBC64B263931CA3F98 +:1081D0002A8C2D17164FC77340FDF5ABF8165CB30C +:1081E0007D10BC3B3C0F53A3BCA9CC16F7DCDF676A +:1081F000EEBFD07FDADCC78EFA0CF07CCEF7DA2641 +:1082000038BF567B7B37FA511976335E7AF3EC5DD3 +:1082100063039E471A483EACF7C6FDB64534E1EB12 +:1082200036CE77D1DB33D3E09C41663FFE55A18744 +:10823000E9EB471B42D72C04C21187E95E7956B49B +:108240006E1AF839C3F879EB4DB6F8E7A0923C0CFA +:108250002FE9A048C15E50DD682F9C2B7FD70B4FC4 +:10826000C7DC680F2679E838F3C7B417B1FBD4BA76 +:108270007FE6E85EB80D7D94E50E6C02FD92E59315 +:108280008896DD179EF4DB832DF08E7863B2CDEFF8 +:10829000C67CB700E3D97F4CC8203A5EE39F458493 +:1082A000AFF1F075783EC8EEAEC7B8AB314FC2CF74 +:1082B000091871E60BBED98980CFC6AB7BEE07E10A +:1082C0007B9017DCC176E8F7C24619C76D9C2C98E5 +:1082D000EA8D794B9BBF8DF7BEB2DC6CDEE574DEB8 +:1082E00000B73D93C1D5F8A8403211AEFFBDF428C8 +:1082F000F835FB5CF8DE07C5C710C0C7393DFB7316 +:108300009B31793AAF9A41EEAD6BD19E89EFA74E82 +:1083100037E6A18F34D13BE32A33FCE24619FDC690 +:1083200045496E3CEF106E8872FA9AE7DFE49BF9DC +:108330009D5B295CAB4E88F8DEB6D6D1BAF428FD39 +:10834000AEBCCDE50F6B7DF17F4E63F052F8A77B9D +:1083500040DE364FC3F9E3796A80FF31813C9C0DE2 +:10836000FC172C453E186C23B06FD3C74EF0307904 +:108370009EED51D97B35BE722687BE85D76CA7FD91 +:108380009579FA5DF76FF3B075FF364F9C75FF7204 +:10839000EF075797B51F8554D445B43708A91F1167 +:1083A0006B47533D560EFD1B7931F1C705D06FFF6A +:1083B000769ABF6544F6E5ED34B0CF800F0DFBEC47 +:1083C0004E8FD9AE8CD1BB3FF430BDFB43CFC0F450 +:1083D000EE8FA1FDE9EF45E3DA35A94A7CBDF7B49C +:1083E00087DD1FAC531582E703FBD90FD8C9E5DA47 +:1083F0003AEFFED6A5CBF91F392E834FCDFAFEFCFE +:10840000312D11F454CA0742DC77B7862CBF6D3C7E +:10841000D06B9BAD7833CCF76716FE78684D9FF52F +:108420002BCCF1188E8BC76A8A479B098F3B3C97F0 +:10843000B00FBFB6BEAF30DFF3E9E4F8A67ABF09EC +:10844000C63B37EBBD22886BD4CEF91CF5FED71E98 +:10845000A7CCBCAE187E391D6705E0A173D69F7905 +:108460007CAE03E34AAB9EB92A11E25835930D7AEC +:1084700044F07DAAF3F939489773FBEC3AC0792EA2 +:10848000999D133DB7EFDAA310F7F8A4E158722CC9 +:108490007DCF3D79BC48A6FD9DDB7BBC48C2037700 +:1084A00061D33BD435177F5B1470F7DE4BE8E137BF +:1084B000075B8F363A597CE54138173786DABF6A51 +:1084C00012F2657A9AED5E28171DBF1DFC215C39FA +:1084D0003FE62FA659B24AD03316C17ED33C37EEC1 +:1084E00067F972C9C86CFA9D12AD87E3CCC4F96A0A +:1084F00098C0EF04B84E44F1F7023CEF7660F83EC6 +:10850000F143B2029EC2FFBD1A3C09784F3AAB0953 +:10851000891AC4778A6E1E4753690AD3BFDDB73AFA +:10852000F0F78C8405AFAA53A8FEDA3C93FD8EDDEC +:10853000F9630B92C01F695599DEF20DEBE163B44C +:108540008B07E76B371723E6757C574055191D924B +:10855000336C6B8A358CC7F9F398FE25521AFF3DB0 +:1085600029CAB71ECDA6431CD8F8CEC5BF2B52FCD6 +:10857000BFCE037846DBFCF04E8FFBAB6F38CA9260 +:1085800069FBCC28BE5F5E94C0E19DC3DE07EFFBB4 +:108590004EE345D37D18B5D4FC4EB727D0B414E2D2 +:1085A000FCD0EF6DC9F8CE8BB99EA2389196BB0B6B +:1085B000CDE5AE0A9A8FE147EB77D6F6865F92AEAD +:1085C0003238F63738100FBF6C50FD79948F0E3467 +:1085D000F8307FB041C334DA3012CB0F37F8312F87 +:1085E000DAF46C984FFAAF7F9014BBEEC2EF549D53 +:1085F0008CE1C37572E4ADF9808FDF8888AF15AF69 +:108600008E47FEDE349A8E3A86BD677332C6FEFE12 +:10861000E9F257D24A285F0DF9D1AFD34AC6C3EF6A +:1086200096B0F31770413AF61EEE7A25A0F993E062 +:108630007734C6343B86C2FBA4C15BC9589423FD82 +:10864000C589F0BB0B7B336CB47E9A94D7ECF807EA +:1086500080ABDE64E7AFE7E7331F9F6CD6AFE3BCC8 +:108660004CFF660AC5E3BC71F8097E5300FDAC39C6 +:10867000C6B907331E8954BFE1768AEBE6EFB3DF54 +:108680005F4854C7FBE1BDF7CD5EC3CEA9F7C5BEB9 +:10869000E7BE99FF0E44E2E1256817293EF63B103C +:1086A000290A7B0F8904934DEFEDCDE5FDCC06063D +:1086B0009AD0571FCFE6FD151D790EFB83DF9788F3 +:1086C000F5EF87F0DFC3D8CCF5D3743550EC4DED22 +:1086D0006D67D45BBFEB59776D21D10BF6430189F0 +:1086E00080BD04ED8A69BBD40F0302DCEF33CED723 +:1086F0003E0BF8CDEFFDDD937D02C3EB933C7D8A0D +:10870000FF4E49D4139807E3FB163C12DA0376CAEE +:108710003EBB06625274E48FF87E94F83BC501E7D5 +:10872000FC530FBCCFEEE5D93A1438BFB8D25B7C0E +:1087300013C45145A53E03F3F74E6F81FC839EFAA7 +:1087400087D8A3DDC537011FA4F3F706080400018D +:108750000E08AAE18F63FD43B34E65649FCCF22BF4 +:10876000BD37368732215F3F0FF808F28DB4BF7DE9 +:1087700049C121C0476EE186E6633742DE687F0368 +:10878000B6FF895765FE8F3B980DF64A4F5EA57977 +:108790004F4C5E6279E260A931BF9A237FC473D0E7 +:1087A000B507D83B5DA907660830CFD4FD3310FF6D +:1087B000E7D5B7BC2B348C878F60EB048B971BF409 +:1087C00030EEE1A6D983F77963F8619DD76CC7C411 +:1087D000DC27BC0FF0DDD31F8FAFCB36F69E4AF7F8 +:1087E0008FD8EFC60D037B5484B8B986692EDCA3FD +:1087F000A7FEC170125C3998D65FE3CD413A5EB5F1 +:108800003BFBCDA95A2F5FA7642977803E4EB5F870 +:1088100035D95C3F8F508B7F93482B370AC1B5F019 +:108820009E6C688FACE27D935D19284767B98E22F4 +:10883000F583315FCDEFBFCB2B836B47811E59C4CE +:10884000F46E5576A058A6DF573D978DBF0B67F0A5 +:108850005D5552246D9CBBF75CB791377E47E42190 +:10886000B5D509EFF218FB5AB5FB3764C13EFDC719 +:1088700087DE463B71496236C259D3765C81DF6937 +:10888000A96DA37C47BFFBD8D963C7A35FF287C894 +:10889000A06F02BEFED068C3CBDDFDD9552F52FDBF +:1088A000A6D385EA688303D39D7AFDD5E00A9CF0C0 +:1088B0002EB8C949F9E9F11C5D05FEEABCB71EF501 +:1088C000D8E38A3A0AF8AFD3FBC366E0E7AA24915B +:1088D000F3EB0F5FD6F3F87E3DCDEFB9B7EDA6BF52 +:1088E00068DF60A1D9FEA97BC48DFC41ED92DF0257 +:1088F0001FD56EB68560FDB339DAF1BE7327E81B6C +:10890000D45FE6FB991B05A60F4373581CFA72F758 +:10891000342BBE7491708CFDBD2491E9AB0A29847F +:10892000FB76155F7AB1FE2F1FC769BA0FDA771C85 +:1089300037D61BE354F78E837C52FDF661F4CF5F8C +:10894000BCDAB0AF75D4FF773EC5CF6138F574E8B7 +:10895000E741D9D027D4CFA47886E71E793E24F901 +:108960000879A947FFAC6D2EC904FAF6D613B37E79 +:10897000D2254AB79712783E747F73C9A438ED1395 +:108980002CED738CFC4FB17F2B3C0F3A7BF30EDA4E +:108990005EFA93BD270FF06DB059FA4B36C6DF86ED +:1089A000FD19FCB7C7BBFB6578EFE9A5A440F11042 +:1089B00066DF6820875B24157F87D1C0F31EBE3E2B +:1089C000557C798D09FFBD782F30959F6ED04CFB7B +:1089D000A18B172EC37B3F7BF83A564142EC3EDB1E +:1089E00023B9A67DD0FF0FC7D785A3B81F384AFE8D +:1089F000C6708C32E9815E38F24DE55F170E316941 +:108A0000766936EC53ADB1A19F90660B3972C06E9A +:108A1000FB5FECF71A203407E799A8616CDA57CEB0 +:108A200039609F07C6798E448E49E3409E746D0578 +:108A3000AC533F91D0AFA1E50E3919866ED5E1FD5B +:108A40002B2A95D85F4E75B08619F5E6776287AB0D +:108A5000A458A2E5E3D579B8EEE594DD5507F6FD17 +:108A60003677E1CF571393BCA27DB25A588AF6C726 +:108A70009AC4179B61DF383D81D9330279B1F95827 +:108A800046BC7A26AF2DF7BD7813C431B6AED4AE4E +:108A9000067F6EAB331C390CEBF93D6EFC3DAADC56 +:108AA00075E116F8BD0A71830DD74B3129BC6B2BCC +:108AB0009C177860841FEC8BAD60D740FB356E5CF3 +:108AC000FF5B1A42682FAFE2EBC0F6F5935438E72C +:108AD000DCE8969261BD6B91EB6F05B85EBAEF640E +:108AE000B3E33AD063FE96413CEFCB80754DCB713A +:108AF0008CE5F514195B576883C18534F2C3FF44D4 +:108B0000AD12D43327D10E6B742FAB043B8ED6BF7E +:108B1000ECA0787A3C99E385D7E7F4E8A593CDA05B +:108B200007C515BDF9123AEF1D3F637AEA09DA3F2E +:108B3000BC2B45E713827718BB4749E8872524C13A +:108B40006FC7D074740EFB9D5BAA17BDE8C7493888 +:108B50005F631F4919C57E0F1DDAC37A9390918315 +:108B6000FB98CA0CF65E83E271E3FD66E37756DD9F +:108B7000C4F8A7B37829DF677159DE4370AE5F8907 +:108B80009BE94E783721864F15CB7B0B1209CC071A +:108B90007B4B54CDE5BF49E4FB4A83D8EFAD0EB71C +:108BA00085D02EA35284E935248AF6D968D281F97A +:108BB00031E06DE6C2352C0D2F8E8D27BAC8E2BB91 +:108BC0000111ECC7B45B8D784CF0F544BADEBF966A +:108BD000C8E336FC778C536614E27E7D6612AB5F89 +:108BE00015C8BB0FECBC8D33A6619CC6B0EF8CF5ED +:108BF000D2B0DF16729857AB425C7BC1B0EB163A2D +:108C0000593E75B6FEE068886BB6530B341BEE2FE9 +:108C1000B3F86AF9E6E234B0CB161EBA15EDE44CAF +:108C200095D9658B36CE5082A3E1DEDA3CF4078A13 +:108C3000374C48847D84D54E7FE27585E867E2FB3A +:108C4000B903B5C7B6A65D3519E471AB8D1290CAEC +:108C5000FB4BB2EE1E0B7CB1210FEDCCAD09C1C6B2 +:108C600024DAEFD67FD6FCAB68FEA74EBDF0388C79 +:108C7000B33A81D5C3BB51C09B3DE712B6E1BBC936 +:108C8000FD8D6F3D97F052127B7FCAA8FF6F537E18 +:108C90007C7D0080000000001F8B080000000000A9 +:108CA00000FFBD7D0B7C94D595F8FD66BE796566A9 +:108CB00092C963F2220913C24B5E4E9E80224C126F +:108CC000C243B44C102A20E8F03490A7485DDCBAC7 +:108CD000FF0C043050B60657112BEA8462C5AABBBC +:108CE00041A31B35EA8080B8D66D44DAD216FD8FD9 +:108CF0004A1510488AB5D2FEDD65CF39F7DECC7C47 +:108D00009319F0B5FFB4FE3EEEF7DDE779DF73CEE1 +:108D1000BD73E912FC4D612C94A43056CAD8C151E0 +:108D20008CF58C618CA9DE2406CF4D066FD2E2341F +:108D3000C6FA7EA367BBE1F517666F92C3C6D82556 +:108D4000D12EFA79AA99B1A089B1B3CD6E161CC102 +:108D5000D8996633956B961F98C6A09F9A0E85B9D1 +:108D6000F2195BC5DA36633FAF3B9269DC55013DD2 +:108D70000B8E64F47709FE5BBDFC28D55FDDC9EB83 +:108D8000D7B20EAABF92314F073C6BF75A59D01C8D +:108D9000AE5FDF51AC691F4AD251BFD725FB063BFE +:108DA0009C8CDD5B3DFCBE2A789F565D62F6E1FA45 +:108DB000588EE313ABA8AF87F73AE6EB88B1AE77EE +:108DC000045CDE49828A4EACEDD0B132C6D63AE0C0 +:108DD0009F2EC61E50D87C6CB7F6F715192963C2B2 +:108DE000EDD62A9E0CC798F8706ABCA86781D48813 +:108DF000B2DA67C4F5355E34D2FBF30EB35F0763B6 +:108E00001EC9F43F702DAC7F26EB5319CC539F90B5 +:108E1000388E5DCD588B2571373E67BA0C7DA10821 +:108E200038303353717E33F82BF6EBC469479471B5 +:108E3000D83E40ED67D98EA90C4073C45E7303839E +:108E4000F737B090CA0A06CE0FFAFD28B2DF5923D1 +:108E5000B5E51BDDDAF2EC09DA32637E82D74F9A90 +:108E60009BCA4E1AC2FDFE04A6D611032EB70258A5 +:108E7000B17EED5E4BE064041EEB3B9235E5C6AE81 +:108E8000ACC0C988716AF11F59F05F135F779D58B4 +:108E9000F70746DFAD0EC05B3D0B1971DD40C146E3 +:108EA000EF58C6AC16E6457C1DD86FF1B012E8CF7E +:108EB000666EB7007C1BBBAB9525F0DE6A87EF3092 +:108EC0003F2796E16935F0FA8C05880EE08FDA3994 +:108ED000BD99ED5B15E413B7ABDAFECDE7DD00FF1E +:108EE000DD93024F953DAC2446ACA30ED6911E5E99 +:108EF000C739EB0765882F58CF6FECA5481746A6F2 +:108F00002485D7F3ADE1B55C0BAFC65D36A237184B +:108F1000E7BD4418A761A7CE6F84B2CEDC63447E60 +:108F2000B917E93C06DE721C4A4C3C6F433CC7E073 +:108F3000A7EDACFC3EE4C71CE41F18C7B6EE2765DE +:108F4000278B818FAA3717FAA0BE4D05FE86715474 +:108F5000F8BFA908C8D93B6D5532D0E9293BE7C312 +:108F60000D892E7AEE50BC0AE2355DE7C947FAD585 +:108F700027B843CCC1F1A366421960CBAEC162F9F8 +:108F8000BD1EE8EF21981BCB168409F078C8C2CB30 +:108F90002F39CAEFDD08E36E4AE6E50D3FBDB9D5CE +:108FA0003F09CA16599E43E5870C6D413DE0DDFF40 +:108FB00082C9F5443EB5F728585E3032F0044C4D76 +:108FC0003F8465235EA62642E720B7F42F9A769B5E +:108FD000A05ED0EEFB2784A75CFF39FBF13C362670 +:108FE000667F7E4D7F79DFAC3F18BF537775F8FB06 +:108FF000D4C49D413D6FE7C2762CA7E7033FF49FA1 +:10900000FEA2896D85E22306769B17DAD55D2C6377 +:10901000C10839D423F079B6D941725BBEAF43F9A8 +:109020003D06F9A987E4707D47AA46FE4AB95C7FF0 +:10903000F15A4D7F398E7CC257BDDA43F2ADFEE264 +:1090400064FA1E12F2F46C7326E989F8E30CD2C8B4 +:10905000F5F0381359B0F872E34CA2EF721CE6CB6E +:1090600022B9BD06E70C24A43782BC87712E0C758B +:1090700025255F469FD976029145AC679B1A3463DC +:10908000FFDBDC071CBE18FC20E544B8BD51DB1E2D +:10909000F4231B81F4ED6348B7FFAC7ACC91FAD48A +:1090A00066F038506FA8F68A232E37344D7E6486DA +:1090B0000A286951393D7FD9B681E8D16E701F41C8 +:1090C000FCDAED3A971FBEAFB7E93C48272D0E7387 +:1090D00000F1BD51B9C1817243F66B07318FF3B80E +:1090E000601B427A3DDE7AD58B89540F669219A9AE +:1090F0001FFFF7C683C5170F1C8FBD31F1880BFA10 +:10910000574B746E0BE00B91FA71041D44F763DF4B +:10911000A9C69C77743D09FFB8F836841211FEE7A2 +:109120006DBA198118F32E4D56BE9B9E5A1425DF39 +:10913000937F3B3C88ED95D00F0AF249FE9626A31B +:10914000FC2DBC9058E922399FEEB573B185E3B68A +:10915000D88E9A7DA48F98ED13D9BF3E3EFD49B8B5 +:1091600018DEAA64881F6004867AE34A70B02B4137 +:109170002FE29715AA0CE5D3403A6FA7F9F4D777F9 +:1091800043E711EB6F51DD0EA46BFD751E33CA99D9 +:10919000F58E39E6109437AAAED9F92087FADE02A7 +:1091A0007B12D6B729ADC81C8B8F5AC16EC4F92D5E +:1091B0004DD669D6239F661DE7DFE8F75B92B99E1F +:1091C00068DD3FB1C753129F7E40D279518F9BCB50 +:1091D00054C756589FDEC0E76B896307CA7EE3C158 +:1091E0006BCB7E0BC96975A83980F644F4789B5423 +:1091F000778F07BE6F82F9F8B19CC3C7DF54A23ADC +:109200007643D71657023347D437384B08FE176CCE +:10921000694C0FDF37213DC6989784D3BCE4EF68D3 +:109220003FF9A2E832F7B7C3D9100D5DB6C6A2CB9D +:1092300079A8374BF9FC993972FE4393BE8E7C8C2A +:10924000A69BB249CC837C9701CF76586FA7CA669C +:10925000EC437D80B6D64498DFCD36E600993E39A2 +:10926000B57C6732ACB7ACE78091213F743A691D99 +:1092700075A27DF4B8A6148E3F538A839E49C73DDC +:109280004F4F01F876F624B814F8D49902FA300654 +:109290007C8F08BC33D6C69F6A681CF28FAC5FB661 +:1092A000887976C3F350026B3583BDB24FC807C6C9 +:1092B000EEE74F151817C699FDCAE8DD642F8AF549 +:1092C0001F02B580F5D3D343E314FD77C0DB5E58AE +:1092D0007D04DEEACD21C2DBDB46DF6B089FC6E3FF +:1092E000A1742C771E3D9387F870B670FBB5EF25FF +:1092F0006B00E96E207ED6D3FCEA2E0E62FEE28180 +:1093000078AB5383A45FEB2EE6D17758B7DF9C127E +:10931000FE3E1B6C8609B02E66E67042F8C4C2475A +:10932000BBE06B890F50EBA3ED021F08A78FC43E73 +:10933000A71FEF4EE36606783F6BE6EF996724DFE1 +:1093400087097DFE51425E00F7331F0D07CE467A36 +:10935000505DE9917AA7CEE2B96F3EAC9BBDAB6799 +:109360004FC06359A5AD15EDAB65264F12DA5DCB45 +:10937000DED32BEBF30984C4072B043CCF32F75D1B +:10938000883FFF368BE309C29F76FF97BFA3BCF8E7 +:109390001D68BFA24BEF46937169A5CD8FFD96F571 +:1093A000543C6D87F72B5BAD2E06FD2E9BE2FE0431 +:1093B000EDBD65F7595C1BF271BF38A43C0BFA5D3B +:1093C000FB60BE03E581759D37D3EC0693E07EEB31 +:1093D0004C2BE06D93B264895208AC7D7FCA1615A0 +:1093E000F0ACFE57E56716285F757FC116F3758CE4 +:1093F000BD82B21CED59FFD09968DFFE12A746F678 +:109400002EB76F7F794427CAC55BA6820A18E5ECA0 +:10941000D4D960CE2B538AB79861FCF4144FA10EB7 +:10942000C65B93326126F6B7F4BEB17FDD09DF7704 +:10943000A4CC9AA9E613DE447BEFCCCAA1D06E92ED +:109440002CCFB354427F695616B6A72700BF0F0929 +:109450008F8FF67767BFFDBD60E6D41CC04B4553C8 +:10946000A50AFDBF9E72DB9631573136FE817287A9 +:1094700007C63F98B264A615F0DF6994F5976DF1C1 +:10948000C0589DCCF78601BEFFF1FEBA9966A89F31 +:1094900096EA2D74C0FA53CDF76F9991FB1DF865CC +:1094A000A412BD4F2C487112DF1C4690E6ADEB3381 +:1094B00072FD2AF83D87D3717F792494ED11E54C34 +:1094C0005EEEDC105B7E9C4EE572B93321F6778F41 +:1094D000904B00EFA00EE9B3CB1A18961F9627C049 +:1094E0004FE609C45FDBB93C01BE9A63273E8ED9C3 +:1094F000DF37E55F803BF5D3A97AACE8BF90720D0A +:109500006666C571BE4C7669E47559CF5292B7BF95 +:109510004A157CEBE2F071566AE50A33F70C47B85E +:10952000C8768BC53AF3474BFF52D088FCB9D6E2D8 +:10953000C9C0F9ACDD579EC12E6387D75D2CD7F823 +:109540004BC2EB984AEF07F40BFDB944FFEE315FD5 +:10955000075EC95780571A7DBFD23AC3FD69FD3BEC +:1095600003FBE37E9E017AC5187B9E1B53B85E41C8 +:10957000F8EB22E4DA4A215F416A913D7EFEC5ABF9 +:10958000766FCD8F1C7703F50FF87D7A0AEE2F41A9 +:10959000BEA21C2B533DB3B07E594F8A03ED79A078 +:1095A000B78D82DE54A43789E7CE94A6725AEF763F +:1095B000C5B13B861DF81339AF36C583F649C622BF +:1095C0009F7E49C4FCA4FC87FE3B45FF259C9E1F53 +:1095D000EDA7E7C5C83FC22FC4DC40DF6307CE5FFD +:1095E000C136CE08FDF5822580F39170FBB6F42FCD +:1095F000ED87BAB87A2A91DA651C0F26BAA09E21A7 +:10960000C5C5F9B9E3E3C46B515F75E999E2E2EBD3 +:1096100046B95126E5A4BFE748854A764C582EBB8B +:10962000C89E917233683687EBDFBFBD67C646942C +:10963000AB26BE2F4FD383142F0ACFE3E514AE2FF2 +:1096400027F89827961D7824D92EE508ADE3E17513 +:1096500095EC63589F5DE8D709213FF9B39E4C66AE +:10966000C23EE1F090FA7BB629F4AFDC4FA6A547E5 +:1096700059063BA5415710EE1FBFCF89A0FB63825F +:109680000EA2F1F35DE513C0C18F70484DE172C8C1 +:10969000096505ED0B15F417C0FF5CB5CDBD353F71 +:1096A00062DE362E8F9D7A1D976357E08BB454FE91 +:1096B000BDEF253BF173181EDC8EF92F01F7761DE7 +:1096C000ABC17DC1211DF009D2A28DAFF3FC8B5936 +:1096D000D4EFE7293AB9FEEF452EB71B613CCED750 +:1096E000643FD6BF3CA85D3B7FDEDFDC544E8F6518 +:1096F000C73D8568C70CF3DADCB85F28EB9973C007 +:1097000000E5E1DD8A036B4B3A1FDEC1F914A84B7B +:10971000C0E5AD6722FBB5A5723AFABED631FC387A +:10972000A757C4CBE2083ECD4DB57178C1FA4C08BD +:109730004F552B47E5F3FB9B87F78001D65B07F07E +:1097400040B12DE1D6D9B1648305F9F83873231FF0 +:109750009FEF58A21B8B78DDC9C8BEEB970F0FF0A7 +:1097600075487B14E8B203E9F2EAD45C1A6FD87149 +:109770008F750C7C1F867613FA953BEC01DC574CF9 +:109780004EF5CD4D4578CEEDAB64204A1AAC4DEB8D +:109790002D11EFFBEB77417DA2639F7E2CCEF3363C +:1097A000C6B6BAC2EB81A9FAD11F5A6F043E2DA0EA +:1097B0007210E1D669E4F5FB16338ACF34E8FB8CEE +:1097C000F81DF4F72CA2CFA3BA14C42FEE9BD06ED1 +:1097D000AED37B7314DCD76798DCA807601F42F414 +:1097E0007EC8C2540BF4FF263C514E57E9EFD88F88 +:1097F000F0AA2A50DC2D24AEDA85DC6041DC37CDBE +:109800009E62257A645FDD39B41AF5BF95E309FAE3 +:10981000318B7ECCE6A230FFFD3AEF2ADAFF48FD1D +:10982000764851A89F43D78DDEDD12B12FC2FE507E +:10983000FE1F52AA73EE40FA17FB3AB20FD3C27A58 +:1098400017ED95225B24DEFD627EA13CA4A3487B3C +:1098500014EDD37E7BD6DFB1653AC8D9F1333A82B5 +:109860003A0752D1F333FF01D65105F6AC05E0704B +:109870005B2A973387F2FDFA449CDF30583FBC3AAD +:109880009CE01BD3640B8F932EFC0FE946EE2F4810 +:109890004FE0CFBFA7723BE727695C1EFE218D9783 +:1098A000D31363FB2BBE10F55413971F5BCBB9FC8E +:1098B0008FAEB741F4FBADEDDE318A667F0F76EFF8 +:1098C00086546EF71AB95F88C713960AFA063B8763 +:1098D000F014B6AB783C50DAA15FF4CCA3F272F38B +:1098E0007BD9E8BFBFED9FE6DD87F4B6F2377AF2A9 +:1098F000579C14F18295C9BEF464DCBF27C4F6AB53 +:109900003C27D675BA99911FF8538C1B82EC3D8980 +:10991000714328AFDAF9E034E4BFD52C40FEE0E52E +:109920003B37515C707940612E05F7695EEE271672 +:10993000F858BD47AFF14BDFAE361993C784E977CE +:10994000459B366E58B3AB5853FEF6F669250B446B +:10995000C8A1B0FC9946EFA3FB95F41E6DA77ED479 +:10996000ECD2F8C397EE1C46EB97F5973137AD77FD +:10997000596B8166DEAC95F349BCF949BA45BBD455 +:109980001F739E46CDFB8F00FEFE08FFFFD25343A0 +:10999000691E2DA9BEFF40BA09CFC3CAFC1ABFDA9F +:1099A00024C727B05666E17E49A023FFE5EC81502D +:1099B0002AA7FF6F0FF7D171F605E3FEBFEE0BCAC2 +:1099C000267139CCDA14360C1EE3A76AEDB4BFA0B9 +:1099D000BE2BC5A795EB6B61472D5FA4AD7751D426 +:1099E000BB28EA5DC9BF12699F290528D7787F0D7A +:1099F000828FF3CF1C35BAA0DEF8346EC716393D1E +:109A00009750EF6CB3248E437FCA364B5E00F552FD +:109A1000FFFABA381D6D33483F8A3B03E1D6FE5F3B +:109A200077B6A888C77DB00F007958FEE841168A3E +:109A3000905337AE533CCB01DE7621EFEADC7C7DE0 +:109A400075EEA07128F4935DC7E795D3B15F5123FC +:109A5000DAE5D4087F5F9A41B3CFCCC1324E258D71 +:109A6000CBE39C9AA03214EA65EFDAA3A8D85F870B +:109A7000427A33BB0900134157D925DCBEB9B1A4E2 +:109A80005D5936260C87565DF51807E0A735DDEAE7 +:109A9000467D738FD337240DE7792218C4EDFCF887 +:109AA000133D2ADAEF3F757A0AD29C6138B8F48EFA +:109AB0006CD4A7D6137C9E6DFDFB63AE6728A24DC8 +:109AC000FEABDDDC9ED1B3238CDB87A4AFD2378C19 +:109AD00024BD27E7979E22F4453AF33D67A3FAADEC +:109AE0008CF0C9683DE91B86EFE6F62CC7775581F7 +:109AF000770FBEAFCAB8AAA805DE176C0BAA4BA198 +:109B0000DDCBBB62FB83CB853E81754CC2F5C9754D +:109B10005C492EC87A86387E0AC90FD619B1F71F5C +:109B200030227D2F7F346D21CEB76EA39199943072 +:109B3000FC7FEAF4CEC6F96477B42B081BE9DF9307 +:109B4000E34AFF1D7E47FEFCC828F996D35F5CFE02 +:109B50005FA7F72C8F94671B8D8427693F87E7C722 +:109B6000EDFDD5695CCFBEEAF42EC1F934746D27E2 +:109B70007FCFAA3D1F1A63F9ABA3F9E24A70546A7A +:109B8000F8BEA06EBE3980EB2F7F54253AA8DD6861 +:109B9000A43859DD33FBB89FE71EE6463951D7B1EB +:109BA0004F590EE3D63EB34F591101D74175010508 +:109BB000E733C22EF990CBAF68BA473F32DA2D8730 +:109BC0002D5C4E9C2DB7F91580EB5983AF0EEB9DA4 +:109BD000CDB2BAFDF9613CBCB96FFA11CC37B03FD8 +:109BE000670AE2B355B73BD30CF55A4719DD485F16 +:109BF0003F75FA36235C52546F27B64F4EB3BBD72E +:109C0000435B978915A1BCFBBA70181F4527E3EF8A +:109C1000E1FCD3857288DB9145C83F8134BBB4A792 +:109C200048AE1D36F0753CC7F87CFF9EEA7990E897 +:109C3000F8480A8D9B5D1754D09F9D7FE639926B43 +:109C4000B2FF309D791E89E4DF2BCFB3C388F45671 +:109C50002BE450F9A37B948F23E6FD4B30F4916EF7 +:109C6000B29F01BAB4D1F7FD33D3A83E33B9F0BDEA +:109C700042ED6AE1FB8A087923D71143EEECC3F584 +:109C8000D84EF41CE47227C8FD8D62BED1F87C1555 +:109C9000E51F7C9A06EA99DE1BFD23312E7A78486F +:109CA00002F527E54034DFBE2AE81CE5A5CE46FED6 +:109CB0005AB22BE5FC64BD2267C5FE3482430FC156 +:109CC000A17E974AEBA9327A87DE11C10FBF16FD3C +:109CD0001DB8F90323CAFD07FEFD5DA2C7FA36854C +:109CE000E2F1ACED5DE33CD447FEA7F46867CEE259 +:109CF0002601DBF1C2BB84A7599D5C2ED777EE53BA +:109D000097D9C2749A7FE6C0AD4867F51D2686FBD9 +:109D100022A0BFDF207CA2E954C247CADD78F8B494 +:109D2000CEE07294F98DE44785FD543EFA29A4DC17 +:109D3000FE7BAA4EF809F8FB0B69BC1CA61FDFA727 +:109D4000088FB0DCB5105FE49F293A60C67DB85B30 +:109D5000213F7F5A258767E4BCAAC7C6979BCE548C +:109D6000A137D450DE1C7B58BEF7CB7FD1FE0B81D0 +:109D70006F781FE4EFD910D4F372FED1F8CB77726D +:109D80007D1B83CEFE1BD711ADDFA43D20E9E6C9C4 +:109D90005DAA468FD89D46EACF0E1B739CC78E7274 +:109DA0001ECFD861E0FA6CC77A7300E5C99B0B78C7 +:109DB0005E997DA13188CF43BAA575F8FD50361F55 +:109DC000BF55A75B83E5D60D36D64278F5243A4BCE +:109DD000917E1219978F5C1E3EF03C9767757E5BF3 +:109DE00080C13FEB7C739753DC39CDE2C6B833F3C7 +:109DF0001D34CEB30FA42BD773FB8D2E783FAB83CE +:109E0000F39FC403C853A22FC90F12AE617872B872 +:109E10004B7E92F8F8BBF46703BD7CA7BCAA3DDA81 +:109E200078DCDB46DFD54EBECF3A6C70A19F86C78B +:109E300017E2D16FEDBAB7B34F821DB53AF32D7A61 +:109E40004ABE85FDAC86BF2709BC1738B9BEAF74C2 +:109E500072BAA92DE920BEAC3DD944FC6C9BC1E58A +:109E60009AED84561E33F6CF62BDDBA85D95B563CF +:109E70001AE677543DAE3870BF1F4F6EDEAEF0FC71 +:109E8000B84F77BD9188F972EC2BB0F2319E62E148 +:109E9000EB9DEBE472E2EC5E0038D17B93F172F65D +:109EA000FB95FA63C1630AC2B356C0FAEC3395134B +:109EB000FF847EECBD49EE61B0E4CF9EB9E9EE3F90 +:109EC000C1BCCFEE99E246F7655A8B97E8A7CF69F8 +:109ED00071E37E03C4F70CF417AEEF7823F15A68F0 +:109EE00077FAE9AB8B506ED78A799E795EBF0EE127 +:109EF000B2E1C97F9B8CDF6B034AAA09C7D9FBF883 +:109F00007F6763BEEA9E46F217B53CFDBA11F317B0 +:109F1000748176FE7E6F9203EB9DFEF9F6C908EF21 +:109F2000968E16FA7EE6E7ED543EF0E4BFBDF67776 +:109F3000F4E37813DD58EFCCF3FB092F753E95F26F +:109F4000DBE2D1F58E7DFBB9BC443D8F7C309FCBED +:109F50003149D7927E4F3F79DBC448BD21DFB70A34 +:109F60007F4E6B02D7239F09FEADADE0F1CECF9EB1 +:109F7000B5CCA7FD8131341CF7C57563385DDC2D88 +:109F8000E051D77187A1C146EDA99FDF02DFE373DE +:109F90002CD0E72723298564CF25CAD7F957AA0FE4 +:109FA000F526A0BFE7E6451F2A381FEB9826432D6C +:109FB000CDF369FE1D561DF9BD6C6D6C3FFBBF38BE +:109FC0006DC22EE07C90DD599DE3223960720F8BCB +:109FD000B087B36B7C2D1827BE7EADCFAD073CBEDE +:109FE0007CEAE8B441507E72A4524CF8D72B5CCF87 +:109FF000F96D344E3DFAC1818F760B3E497730F5CD +:10A000001A9203DC1F50A532D5467EAA3E9213F564 +:10A01000AD420FEE117E6E735FDE4D766A67BB2632 +:10A02000621F06ED6C362AF7E5FD10F34A67F8E784 +:10A0300093DE711969BE67A43C607EF27B4A7E8B19 +:10A04000F61BA1BCC1FCD1579DE55D281FE5333D42 +:10A050008EBFE4EFE2FBB8744F17CA15B63755A3AD +:10A060000FE2C99503379FE77AFB950F890E1B9086 +:10A070000E717CDF498DDE5E4EC215E8F0A50F89BA +:10A080000E977771F9DAD0556EC4FDD40EE1D76919 +:10A0900010F4847484FBE8BF3A93699C86C9A1E1FB +:10A0A00028A7CE0BBA3BFF12A7B7433A1DF9010E02 +:10A0B000ED1EDDDEA20CD48F4A8D97F0DD00F8E6B0 +:10A0C00076F3DAA36867D5D73037F26B43A7E0079A +:10A0D000B07B11BE0D5DD5CBB1BF416933C9DF0D7A +:10A0E00076C9B441506EA863A5C86FD9BB2A5E4239 +:10A0F000BA605D7C3F9E5D03F62CD24D5ABD5B9FDE +:10A100008F7A8FDBBDD78F2CA3F63B725D14E7F2FD +:10A1100057318AF3EF40FB19F55DD6686E3FFB3689 +:10A1200092DDC55C09E437653E750DD66FF02F6290 +:10A1300094D711CDC72F29B40F680858291F685626 +:10A1400017B77F1ABA381F9F93F0914F43CFADE4F2 +:10A150008F7FC1C4FC11FED0375F9ACEF5EC8B2601 +:10A16000D2B39F357BD8C7B0A0B785BC9770AC6D14 +:10A17000CBD721DD32769309E7B14CCCA3CDC0F526 +:10A1800046B2D00305DBF83CD474E1774CD789A7FD +:10A19000519BE7E2F0937FE19C188FC8225DE8397C +:10A1A00018BA7E7990F8A4EE19DE5F9AC9537867E1 +:10A1B00004BD4AFB289A1E0BC4B8D9BB0E2A284CF2 +:10A1C000B277CDD1F0F9F5352CD808EBBC7E972EBF +:10A1D00038651CD94D0B499EAF37B258F92A23D2A6 +:10A1E000B9FD5695EA2D44BF76D5CD3677A43FB953 +:10A1F0002AC1A3B3A01D5724FDD8DE128C1B9D4A93 +:10A20000B7BB116FE3D25DD20ED3D85B03F7DFDCAF +:10A210000EBCA1CD3F0EF71F81F509F329AE09DA77 +:10A220008DFCDC0E688FFBF7DDD7FE9CEFDF5BB8A3 +:10A23000FF020407C999546F09FA8F9D05DEB55CCA +:10A240003FD9DDB1D6F3AA93AFE7C0CDB716E23E52 +:10A25000B161AE8DF8E1815794A59CDE4011E2BE5C +:10A26000DAC7F983017F3CE1227A243BAAA1C91B0A +:10A27000884D8F9C5F1AC0AE423B1BE8710DB793AF +:10A280006D8CF313A74BB9BF47B91569CF4A3E8D03 +:10A29000E67B49BFFD7CFF35F9FDBC81F3E37980A6 +:10A2A00003D27B3F9DBFCCE97CEB7AE047F8BE153B +:10A2B000F8B12542FE47EF7F709EB81F90F2F61E60 +:10A2C000A777513ACAA1DD6F6DC650AB948F0D2FA1 +:10A2D0006F197E39BBCB8C95A15F33F06B24FD6089 +:10A2E0008CD65E444F3FEA09EBBAD8FE8FBBD26DE5 +:10A2F000DFCD3F3F302FE5AEF4D2817929E9A87355 +:10A30000106FBBAD01B48FA51F297A3E4B049F4946 +:10A310007CCAFD03C621B0FEFD82EF37897A8F88A3 +:10A3200067C4BE84F8C1A5F37D4879F671F4916CD9 +:10A33000F77DF9B5E438522F46D38D8CA3E07AAA85 +:10A34000C7C4AFD7B65FECCFA2E8F829C15F0B80D6 +:10A350003770DE6D86E017C48F77D819E513F8994A +:10A360002715E371AF8DE07C34B26F38B6B766FA6B +:10A37000BE44BA927E5D7C8F71AA5A11BFACDD6B70 +:10A3800008449E7FB93783D138BD76B35F0FFC9107 +:10A390009BE9DB87EDFD15CC1D443DF38F168A2B21 +:10A3A00081815B8AF2A691851211CEEF25FB5E209A +:10A3B000FAD5F70C47BFE33925340EDF9F10FEDADC +:10A3C00013C25FFB7ED77BCFBE02AD17BF726EF1AB +:10A3D0008F91CE5EB4E4217D9CB0F4E7BF25A1DD72 +:10A3E0007D81B9922E770E699159EF5523FC67272D +:10A3F000ECB1FD7F6F0B3C378A782B5319EDC3B757 +:10A400006770F9193EBFC4E3ADEFEBB4FE37F91C3A +:10A4100093C1E1DF19E71C506106DFD7740EE1FC40 +:10A42000D8D7AE50BCAF66DDFA3FEB412ED4ACB509 +:10A4300007E9099FD18EAB71F8833A289F3070B934 +:10A44000047F73CD6561FD07F5D449C8337E07C528 +:10A45000BF960AFDB5ACE9CDBFA15FA14665E6494F +:10A460004518C7F21E1E049F3EB52D4F44F1BFF2A2 +:10A470004777A6A37ECA58D426F2C1A63AD0FE5585 +:10A480003C37E82F592F676FA96427131D00DE1E84 +:10A49000CCF0F6221F2F4AE27EC145775A03FE0810 +:10A4A00079B857F06134FD7C10E7BCCD97191501E0 +:10A4B000EC6F61AAF76FD4EF9DE73472EDBC12FA2E +:10A4C000C523485F77D8DD4FF0EEF222F363D20563 +:10A4D000FC6B310E04A2B1B7B067F8BA7CA4E3BE3E +:10A4E000BCDFA15FABDBE4F0BBF0BB91BECB76F190 +:10A4F000E241F1E3402E23D247C34585E86169F785 +:10A500009BC751AE37A821A293A5661BE1B1E1A27A +:10A51000CAE9A9D5703624DB03EED7A47AD232601B +:10A520009EFE7B2725533C09F889C3172A459CE3E7 +:10A53000F832C3372803E0F79035F136DC7F5D3021 +:10A54000BB92308FADD108F4703575E73547D843ED +:10A550002CC7AEA583EEB7FE86F35A6EF61951AF3F +:10A56000AFF034D179B14549C152C79848BC4FD2F8 +:10A570005F1AFDF5F17E49C897F78D3C6F64209D09 +:10A58000733C6CCF10F5B239BFBC9FC76A9EC3E75E +:10A59000287842BBF787887291280F17F5D279790E +:10A5A0009AE097F7C7F17AD1E32C15E37C99E1990A +:10A5B0008C7082764123D2C76B163A67C44A40FE3C +:10A5C000A1BC5B934B762CC8B96908771827984CC7 +:10A5D000F54CA4675813C841C0676FA98BE0B3B5A9 +:10A5E0001CE805E341AF9A281E24F12BF11A8DCF08 +:10A5F0008519CA77CB4F1F18BF5E98513A307ECD70 +:10A60000D850C217D14B8CF31FF1F0F56B3BC70349 +:10A61000F0EBF20CD283C1B1917CB349C051CAB501 +:10A62000F713B478FD3C9DE3A15ED4BB84761FDABA +:10A63000D1EE3EE2BFF75378FDB402AE97A45DFEC3 +:10A640004F022E5FA66B9F52CF44FBD1BF14F2E2A4 +:10A65000CB74EE4707BCDE8DF395FA09E44C301954 +:10A66000F878D1EB2692336C631FE5D540BDFF83AC +:10A67000F05A64EABB3515F4CA0FC1DE311651BB7E +:10A680004B284706ECEFC748BAB033D4DBAD190E00 +:10A690006E1F94F4F1B8D748BEAEA50CE48772657E +:10A6A000FC630C210BE4F06B22BF42C1BCAE146210 +:10A6B0006717F60770FF978CD230DCA3C73B21E801 +:10A6C000E0D10C4525BC15B242C4DBADEF7E6E5F18 +:10A6D0000C5D9E13E765934DBE76ECE7ECDD6F9164 +:10A6E0009D7EC2181CDE668BF1DD187CEC2125FCFA +:10A6F000FDB6A7F47EE3D5987F7EF6C19B61DD4B66 +:10A700007BF46E1C72E93D5FBC331EEDEC1E03C58D +:10A710006B40DF6F5371DE4DDCAE3CA1D3D2C1671D +:10A720007769F73DAF0B7A90E772A5DC91FA7C155B +:10A730007373799390B81BCB1FDD713B9DCB5DCEBE +:10A74000BC873D00F7D36B66925D7C3BF3515ECFD7 +:10A75000B256ED39DB156DDAF2ED3B079CC32539B6 +:10A76000BC2A10FD5EF8A52B63EBFBF3822E3F3372 +:10A770008AF8FD7A53CCF8FDEF85FC09C7D9FBB404 +:10A78000F1FB572F1FBF6F8C8ADF87ED88E8F83DFC +:10A79000EFF713616F60BF9171FCCF2A62AFE3A343 +:10A7A0000C69B75835F9199F0CB05B12E97BE3458A +:10A7B0004B9CF9D8E8FD672B638FD3D73F8E365F6C +:10A7C00020DC9EE709C8FDB5A493C68B59A4676534 +:10A7D00059DAC7E17639F43DFABCBAF46F4BBEF8EA +:10A7E0005861E62CF2476D1776BC9BF2333F46BBAF +:10A7F00008F972BAEBB5104C71D98F270E578784C0 +:10A80000F9267A1D405F674211F2D898694F23FDFF +:10A81000EB666E3A9727E8FED6BBABE87CCFFFBD70 +:10A82000A73223326E2AF7530D46698FD934FA9630 +:10A8300045E9E3655D6F911D06F6D770143E7F7A9A +:10A84000F56ED2C32B99371DE9BDF7D511746EE5AE +:10A85000DBEA61399F9BFC4B0C3CBF358DEC8739A3 +:10A86000623E3775733B5067F618681C0F7339D218 +:10A87000698BCDE70B425485F275FDF347E71D6305 +:10A8800093C4FC156C0FF0BD4E3CD9525F26CEDB55 +:10A8900084E3EA310D269089CF96896E173EA7286A +:10A8A0005E95CF83E3791A6BCAC1FA3A7348CFD762 +:10A8B000093348C7F6FDF0A2B25D9437CEBD70EB08 +:10A8C0000A7C6FB3933C318A794CCF04B988FC6D14 +:10A8D00066665CB7C9163C4DF133F1F457B8888F02 +:10A8E000FD4318F9411258079D3FB5D9CEF971B112 +:10A8F0000EE650B06C715C08E27EE29CC3E6C7F3E2 +:10A90000C4202F6765A23F5FF9D54AC40BC867EE24 +:10A91000178AF75D0DF2F31142DEA588F9B50879C3 +:10A9200097C5DC8AB8C780E4DDFDF69537E07E2662 +:10A930008D79F7A3BC7B387106C5FD32988FE693FD +:10A940003A43D5C82DA7575BCE98AF46CB3B05E71A +:10A9500097E5D3BE37B3139497A404BD9997526972 +:10A960001F3612FD310621378E59783EC26631CF2F +:10A970003B3353886E8E59785EC2B7B65BDCDA7DA6 +:10A980007D430A3FBF7F3EDD6CC6F1C08EB913E147 +:10A990000776CC077E16CEDF2C9CD24179029B6FC6 +:10A9A00054DC1BE0FD66BB6BBD0AA4EB9FA9707F66 +:10A9B0008FEA28C77C9CF63C871BF3441B45BEF7F7 +:10A9C000668BA3F619F2639A783DD6B719E396ED34 +:10A9D0005B1D0EAC9756D937CD88FBAA15CCB19B21 +:10A9E000C5A0F7AF808F60BE3FC732E04911F46366 +:10A9F0003DE2BA85D620BEEFC17F17F0F29432DC7B +:10AA0000BFF2BF82EE423A77C93C7AD2978DDD859C +:10AA10006FD860BC82B985E4AFF756F2B82F1372D5 +:10AA200060BC1C57F0D9B561BAA7EF85A23CB45BF6 +:10AA3000F87FD34C3CAEEB8021CAC49143AC9FC697 +:10AA4000F9C1CDE41FE7D36B58F80FFBAB0CF74F00 +:10AA500072696AF87398EF60A822B3BBA50EEA8DFD +:10AA60005783FB91AFAF15CF42F13C547E23E9E50C +:10AA70001E9DCD65D4713E3717A0ABC3AB47B894CC +:10AA800039B6B4603FD729417AE6CDD8DE82D39F6C +:10AA900023FC4CC999C6009E376B99007826BFC825 +:10AAA0009F0FA3FF5AFF2FAC18F174CC20F59E27FF +:10AAB00089E7FFB9683DD50E3E5997CE337B2EC24C +:10AAC000F9283FCFC6D0748BF8FE97A9554997D780 +:10AAD000BB3C0F30254BCFE5E30C1E876D9C6FA66A +:10AAE000BCE546710F03537DF93F8CF0AFC8B8C584 +:10AAF000BB06367F5F8CFD464A16B707E6DCC0FD15 +:10AB0000C28D221F477E4FCCE27EB2BF644E7B37A0 +:10AB100093EC3D1E6FFD9D945F23D948945F11F225 +:10AB2000E58F245FCADF8E277FB4DF85FC99E72994 +:10AB300036D0BE40C82129EFBD22EF6801F31810BE +:10AB40004F3DE21E95A3E5AB480EDDCC7CF4FEF74D +:10AB5000153CFF0008D380FDDD34436B3FCDF36A25 +:10AB6000CB37CF8FB6AF383EE4B80B7CDAEF73A4A7 +:10AB70009D3C436B272FFA87AF9249CF67FCA2FE1B +:10AB8000D2E0703E5163543E5183C8276AEC2A3CA0 +:10AB90009416914FD4D8CDF3891ABAAE944FC4ED20 +:10ABA00029AF29B01FE324DE5AD294EC0D917F72B5 +:10ABB00010F34F8AC2746EAFB0F33C0CE6A1BCA296 +:10ABC0001C8795CE5DB4EA8AC88FDB9A68D7F8DD1A +:10ABD000B7AE7755613DE9BF95F9434837B1F6C344 +:10ABE000D9597C5FB343E17E74FF0233ED3B9D0591 +:10ABF0005E4D5CC1A967C7D1AFF86EA64BD6273FA3 +:10AC0000C90E832FAB189E0185D17989FEF67AB6DD +:10AC100091FC905172CA99EAA6388033692CF9F5F3 +:10AC2000E77517923F92D92CEE614AB8FF7973DB32 +:10AC300055CCEB69EC6E5797DBC27437364BEC435F +:10AC4000ACCC8AF4DAEFD77BCE447EBD6493B730C8 +:10AC50000BDAD71983E4BF8BA0577A1F4F5FDE2E24 +:10AC6000E8C550E15DB002E6D7FB8ED18DFB6B0AE3 +:10AC7000CC41FFCFBF944C7E49750E233DB5B19CAE +:10AC8000CB935EF493C13A3E4DE6F7FA6CAC66A402 +:10AC90005FCFA74C233A5EC502873DE847DB0574CA +:10ACA0001879CFD21E6DB98E7590FEA97B66003DD6 +:10ACB000937C94F2B89EB9F4068C1B746ADBB3A142 +:10ACC0005A395C28F447F1BCA92D98FF50ACE3F247 +:10ACD000912D770F9A43FBF5458E4F2C28727FA15B +:10ACE0005CCEAEEBB59FD273FEE77AA154F41FADF4 +:10ACF000BF4A853D3719E417EE6FA57D06F5A97C9F +:10AD000050D7ADCFD485E75922DA49BB50EA0B8939 +:10AD1000AFF2098CE179B5BBB2847C1AC28620BE41 +:10AD2000A17FE21305375829D4BF1FF785D78AF1D1 +:10AD3000801EFCA8BFFD3A7300E96BB3D244FAD27F +:10AD40008CF63F3CB72A3ED20BFF5EE3D7237D4C07 +:10AD5000644D37DD00F526997BAC28B7804EFE3177 +:10AD6000927E5A58306F9FA2A123FA7E36F9ED9851 +:10AD70007424F55AF0F7DC9E99C5BC74CF93E70FA5 +:10AD8000DCEE3AA8F07D26D89F07D1EE7A5B3793A8 +:10AD9000E864262C03EB5539B4F89F9EA92D47DFB4 +:10ADA0000FC5D05A284374487806549C4FF4BD51BF +:10ADB0001E29F79856EEE5B3AF78DEF896C33F420A +:10ADC000FF83751D1B89F60E58AAC48FD1F4B027D6 +:10ADD000EB7B8FB7ECC98A116FE9157EE56B58687C +:10ADE000E533CA407A3B7F689D3E33822E257FBC87 +:10ADF0006CE07913CAEB3CAE35C1CCC604112E25EC +:10AE0000DCFF28F9E31AA4D39430FD9589F787A4D1 +:10AE10007C19CC0623BD5DD76509EA013F85A2BF39 +:10AE20006B90FE8AC2F689DC77B44C184067F998BB +:10AE3000170EF64C01D295B44F8A958E163CE7FD5D +:10AE4000FC4BF7B6E07C23E8EA2D84C35905E88A79 +:10AE5000FC6A03F4ADF67B14DD49FC4B7BBA9C35F0 +:10AE6000D17E676E02D7B3C1EADB49CF82B824BA7C +:10AE70007B730EA7BB2AE621BA2B675A7AA9346BDB +:10AE8000CBD1740923EAB474E723BA8BA6D77874BC +:10AE90003718E94EEADBD42BD3DDE74877DFC58FDF +:10AEA0003990EE3ECF72C6A7BB687A93F26C9FC50D +:10AEB00051897675638D42FAA1F89DA12D581E51D6 +:10AEC0009F4F76F6BE6437D9DD8D4DFC7B498F47A9 +:10AED0008F7933056BC5F77C6F25961BD7C177E853 +:10AEE000BAF418CFAB197A0FFF5EB8A1E90DBCBF59 +:10AEF000A0D1CFDBBF7C7A339D870A6C16EDCBDB0C +:10AF00002AB1DCD8CADB7F8A71AEAB31BF2DD082CB +:10AF1000EFAFDA96EFE6DB6F6ED74F11EBDDA73CB4 +:10AF2000F706B56BE3ED6E3F6C4E60E427E0F6FA92 +:10AF300064B1CE29BBF83AD33EBE7E860BE86345AA +:10AF40009F9FECB94F74756524EFE2ECB3CB95B6D7 +:10AF50001C7C4E4739A647BCBB5BF543781C743755 +:10AF60000C717536F7D3C8F821E6295447D817571E +:10AF700067733B44D64B4F61747E8DFDCC4EFE72A1 +:10AF800019DF0C3EC414D407B8466197C48C774EC1 +:10AF90002F6822BB62FA6019E70CA94B61DCC24B37 +:10AFA0009F4F8BE5472ACBE6F6F329917721DFD730 +:10AFB00004F2754817FB9048E8FCF09077D09EDBD0 +:10AFC00097CC34E7DCF6E5F3F2D4ECBC7F6ECD0130 +:10AFD000F8EA9A54BCF78BE52994B7F2831E164C15 +:10AFE0004A1C38FFE92A0B1A290F8ACF7F658B513B +:10AFF000DC57C2E5DA3C813F366918D1EF5C81A7A6 +:10B00000EA6CA1178B5931CAA979026F3F343719FD +:10B01000B8BE6E3344C98F79D9283F1E8E6BCF6B73 +:10B02000BF47C9971A31EE4A61C7AF627DE43FFD61 +:10B0300044D8F1A71EE676FC6AD641FED3DE9F71A6 +:10B040003BBE1E9687F412ED07ADDDAB2DD77768BA +:10B05000CB0DA0DEB1FFC6AE28B93386FBA57B1FA2 +:10B06000AE2F433F64CDCE77C8FF5D23E54C402B28 +:10B0700067C040E772E6A151E4BFFAD6F2E319D8FF +:10B08000D59569F24BEFC97646F8775EE4792E0DD7 +:10B090008CFB117AED236FC17D2C8BD24FD172A521 +:10B0A00050C815E9FF90F25BCA9B42C6F514EC77D5 +:10B0B000DFF1609B283BEFE16CA1AFC4FE4DFA4D80 +:10B0C000A47D5488F611D2D7A82622BAB07E72BFCA +:10B0D0006DD247E8A5052566C47B9119F81BE1A64A +:10B0E000B78DF5D934F4F168F6E5F783DAEF51F46A +:10B0F00023F7630B05FDDC84911818FF0F721FB84E +:10B100008AD3CF5CE63D84F4F3FBD59C7EE4BEF0AD +:10B110009BEF033DFAC87DA0DC4F7EDDFD603FDD87 +:10B1200058C03E86E7B15CE917E0F1FD4685D3459E +:10B13000FD9CDF3D56C5C2F2E2683373AB8670B941 +:10B1400065A6C98C7E971603DF2FCD99F57ED9D2DF +:10B1500008F913B4971F40B8B16E27F977EBADDA51 +:10B1600071362B3D77FD11F7558F5AC9AF74E10841 +:10B170002393E5C2AE11940FFE9981C75BE57C6E07 +:10B180003FBCF7B510D45BB9EE9662CC2FA8550240 +:10B190002FD6C1B70FACBE7791BF6B7541712F67CA +:10B1A0000FC527E4B8F1FDBA7E92C7C6035C3FF72E +:10B1B000290994DF0BEF8747C6E9FE3888CBEFDC1F +:10B1C0004CDF07B81EA9475BFAF327F813B4301B0E +:10B1D0009412CEA708E74D707FCB5F98E78A79136A +:10B1E0001B23E204D03E66BEDB7921CF47617201AA +:10B1F000CC6765BAA717D77F4AC4854F8938E2A9BB +:10B20000441E57FC7B7F7DFEB40DE27AE894883BB8 +:10B210009E4AD1C69B64BD44F13CD96CF66E346045 +:10B22000BC9E793782FE703D646AA27C95451C5FA6 +:10B23000BD2F256BEE11C81A543E6A10B4FB99D38A +:10B24000AB1F04E32C6FD39E83EA15F7DBF60ABA33 +:10B25000E9B5F0A71C376B50F5286CD7BB80DFB37E +:10B26000DA5F9E28CB5EEABFF7BA10C9A3FEF28F61 +:10B2700042E29C3AF793C8F840BCF86174BC30FADB +:10B280009C6974BC7FB1E43711EF5F24E4D4E26EB3 +:10B290001E6FB8D5CC360F82EFB7756750FCB82655 +:10B2A000D13F5C13EFF75BBF519E87A4CFDEDC9EDE +:10B2B000FEF8F8CF22E2E3F5223E5A2FD7D7A95D58 +:10B2C000DF6401CFEF313E3E799073607C3C3A9F62 +:10B2D000E245B4330C613CAC7170B855E9EB2AD14E +:10B2E0004F7C6139A33CF7356F2D6B413FF29A2DAE +:10B2F000E296556177D70B38C75B97D3AB632E8D3A +:10B30000BF3E81B922D693E54BD194C9928FC83301 +:10B310001D5493AD699FDB3444537FF0BA519AEFCB +:10B32000F9FE224DB9A0F51A4DFD616D159AF2880E +:10B330009DD76BEA17B22149E46F3BA2475F12BB6E +:10B340002A3047F37DF4DE859AF69FB2A61D93A0BE +:10B350005EA7457B2F33F37B7AC69485F3A9C77626 +:10B360002CD5F4C3824A50290BDF33F699B8A7795C +:10B37000790F8F875CDDB55A334EADBE8EF0181D48 +:10B38000EF2D627DE4376E0828EE201B18FF5DD597 +:10B39000D54EEDAE64F7C878C8C64122DE97CDB26F +:10B3A000395D47D3858DECC30BBBF4E47F2C64C3BC +:10B3B0001F9A44F032B0806B20FE2E30EE17BBF0A7 +:10B3C0008CDD8D7945B7BFB58CE663CAD4D205DE76 +:10B3D0001F18B95EEB482D5DD8DD5A3A489AA0A5F2 +:10B3E000836878277BB474C142F0BFCBC03B7586BD +:10B3F000966EFEB7E0DC81F0B586E15B7CD0D3626F +:10B4000023B8F1BC35699F99843D141DD790764EC1 +:10B410007090B0BB453F322EB159F1935DD51F7787 +:10B420009C10CC0BE6A33DD5C4B85FC97B10E56F7B +:10B430000CBF24BD8FE79794709D9BC0F5672DF3DB +:10B4400092FC3E66E1FEA493D5ABC89FB4923591C1 +:10B45000DDFDD99CE9C2EFE8A77A57CA5318909F3F +:10B4600000F6298BF0D7AE068B1AEF1F8A86A7D27B +:10B47000AD04ED786E98754B7DE0A3FC150FDEED05 +:10B48000A989FF68ED5FE65122E597B487E5781258 +:10B490009E52AEC9714CAC499F897C1125E7D8C832 +:10B4A000E8F893D69F23FD41328E23E34CD1FE9BD7 +:10B4B00008BBB8558F71D2C1F92D78CEB7D8E1212C +:10B4C0003F6129EBB905DF4F3077B4A82EE1BFB853 +:10B4D0008AF5FB2FE2EAAB2BC4B56FF22BA147F242 +:10B4E00007C6B3657C1C96FFF11FA1F124C5958B9F +:10B4F000F398F3F20827D2D340BFA6FBF82BD08FE6 +:10B500005ED7978AF5AA30313D22DEFDA612A2F55C +:10B51000FC907936459EDB6F601DD36E217F32E84B +:10B5200049BC27A793FBBB5857B43DAC92BF590702 +:10B530002B41BAAF651171DEFCF0772AEB079665F7 +:10B540001ED295EC89A7F18272CAA3E0F9534CC8C8 +:10B5500041B9FF8CB7CF93F918F27E4F9977549485 +:10B5600023F8751C1B87FD03BF95E594A27F01F8A6 +:10B570005389E4C7FE3C25FA3E801FA3D62FF33142 +:10B58000F4F612F21B2D8B5CEFD78087B45B7E9CA8 +:10B59000C3E8E9C871D1B33EE1C46F3DF8B9A4472F +:10B5A000933FDA68840D0DFA135E1479811D5ABB3E +:10B5B000FD961C9D801BDFF75C095EF1F121F2F81E +:10B5C000043EBEAE1D26F3F8241C970C84FB0A0D26 +:10B5D0005CFBF78FFD705F110BEE122EE74A7B7E4E +:10B5E00081F8D2DB8FA523BC17A67A5763FDDCE375 +:10B5F000A14F145D785E55FAB394877BA14B4FE75A +:10B60000FF1AAEE372B0E1253D8986F3DD268AB3E9 +:10B61000D674BD4176E1D96610B406FCBD0C187233 +:10B62000D865FC0851F08EB74F92EBD99023F6E520 +:10B6300062FD32EF07D6B93927665E473F1CB4DF9B +:10B64000051CAAF46392F01C597FBE92DA97177911 +:10B650005F5FF43A2A7278FEDB29B3F73EECEFC362 +:10B660009E9C1DD85F95BEFB7036C267AD42E7BB9E +:10B67000A698F879DC2C715E6F42A8C98DE79933E2 +:10B6800073F87D66237EA4F7621CF9FDB577A6E00A +:10B690003934D9FF084547E747197BEE837F2CC132 +:10B6A000F8E62237DE6FBFD824EE2FBACB1A2C0073 +:10B6B00039F2BA91DF476518D244E766FA92F5E4A9 +:10B6C000D74CD3B3A9487772DEF2BCAD7C8FF701BB +:10B6D000605EB17C3FA5A5AF780DFA7B043DC875CF +:10B6E0004FA9EC2B6EB285E12FF33CA3E15325F873 +:10B6F00043EE431BF05E5BD0BFE7CDBC1C7DAF6D5E +:10B70000FFFE7458FF3D36F6C8B87E83C593341EDD +:10B71000F951DC6BFB17872789DF77A4BDA7F6BC3F +:10B72000C8B797BF5312EFDE9BFFCC51BE977B8209 +:10B73000E2E585CBBCFF7870694856997A359D73F0 +:10B74000F75EAEDE2BFFAD8FB9DFBE28BEF7DFD3CD +:10B75000F96AECBCC55EB1CE707E6188CE29F7E790 +:10B760002DBE547ED97B471AF03ED20838C8BCF6AD +:10B7700006BC8FB43846BFD09FCB76E57B87AAC482 +:10B78000BC1A308F3035F23DA7B7F03869222F3020 +:10B7900094887CFBCB2E3D9DE3FFE511DD8CDD31F4 +:10B7A000E69D9BCBE132CAA9121F8D0EF2FBB5E3D9 +:10B7B000D593E779E4B9D8E8F97556846EC5F9638D +:10B7C0009E72ACF11CB97C3F2BE7DD99C2F1D1F040 +:10B7D0009A89DF9BAAF27CF2CE94D04AE2138716B4 +:10B7E000CFC3041E3BAF0FE5D1B9B299DCEF108F88 +:10B7F0001E26A7FACA51BEC87BEECAD426C511C1FF +:10B800008F57A28730DCF51ABC0E84BB91BECB7E6D +:10B810004F1F157CCB3C36DCCF2D11FA6EC99E5ADA +:10B82000B287E57EE9F44E3DE56F9C663CAE72BAA8 +:10B830004DA1FDD0521F63EB402EAD7CA27833AA00 +:10B84000AE2599B09614FE1E7F1F66E9C6A8F8BA09 +:10B85000D85F49BD2AC75FBE4D6B17D7B06D7F4615 +:10B86000FBE9F4512E3F56B026D23F2B1FD0F6579E +:10B87000B367D6A738CFE8BC8011C28F372D57ECFD +:10B8800057CA5819EA8F354F7C6EC49F6089C71715 +:10B89000F8FB4F4387F1DF7DC227FE8E083E6FC95C +:10B8A000F5FC2017FD3EEFF2F9AECEF5CDC9457F90 +:10B8B000C9BB7C7E17EA2E703DB32B8DF45B8BFDEC +:10B8C0002E92FFFAC15CFEDF8BF735009C4C26718F +:10B8D0006FBAAE499F48F64D80E8EC43E71D737E92 +:10B8E00040657726F243DAD3D36760BFCEA7AD1E9B +:10B8F0005CDFD6724F21FA2FB656F3F3A166138F91 +:10B90000DF077E39F100865386766CAF40179DA322 +:10B910007B7F10FD42ADBA3F1FC6BC98D6C93C5FC5 +:10B92000325D17DA3F28623CA7359089F17DE768E0 +:10B930007E6F4E9ABEBC90CB7F6E2736085C5CE86B +:10B940002A207F62AF41FA173B2C742EAB8EFF2E5C +:10B95000C628C6F12FF3EA700E9176F1D966A6F9E2 +:10B960009D86511D4AD09048F7A8503CA86E4330A0 +:10B97000FD16D4674FA9144F93F34B7B3DAB02E305 +:10B9800066528FDDA238B8BF4DD8FD0B98FCE3712D +:10B99000B7F9829E16087BFF162B87F752E6CEC3B7 +:10B9A000760BCD2C5107AC764B654729ADB3D690BD +:10B9B0008C76858C1FC5B74762FBC91A7E61E7E7A5 +:10B9C0009E95BEE1D8C919F4415D863FDB853C698F +:10B9D00018CECFFFB1A1CC83F1CA86D746D0EF30C5 +:10B9E0009912783C1CE49619EF113A84FA1ED6BDE0 +:10B9F000EA158BC85B0A8873CDFCDED8C639394599 +:10BA0000741EF1781FDDFF71DE10CA23FE067984F3 +:10BA100037A6BE92FBBB1FE0BDEB0DD960D741F945 +:10BA200074EE9F7879486825DE1B9992778997474D +:10BA3000853EC1724E5EC26C2A178556EAA13C3E15 +:10BA40002F939771030A0436356FF06C3FDA2DC9D6 +:10BA5000C22E7087E8BC77C3CB237491FE58771E43 +:10BA6000976767843FF94C3EBB6D0EC27B64ECFA6E +:10BA70006979D2DE6EA3F5C9F5CAF62C3376BBFF21 +:10BA800010727E9538A73DC5CA5A2D3CFEE74F047B +:10BA90003C1CEC1E41F1CB7FCD4DE1FD3B42744F90 +:10BAA0008FEC27FA771CE4B8AB15FE7B59E7A3F2BD +:10BAB000BC7E97CBE52B8CB391C619EAE1E79BE7F7 +:10BAC000E41422FE006FAAC09BCAF7C9ED7C7ED0A9 +:10BAD0002FFEFE13E88762F4FB1FFC0AEAE787E704 +:10BAE0001D4D2727C538AB5A78DCB62FB980E869D9 +:10BAF0008A55DCF752A25DC7F83C6E9FBAF392C537 +:10BB0000791D09AF0C85C6691170CC090D9F33F6FC +:10BB10009BAFFBAFFF4BEB8EC09707EF6D39D8C5DE +:10BB2000EF371E9FC7F185F49C4276E0764D7F6724 +:10BB3000D647B59FC0285FAE21A580DADF2BEE6F18 +:10BB400095F7D961BBFC71DCBE45BB57DEA7C1FCD4 +:10BB50009359641CB2FFDE8C0E71BF70FF3A6F28E0 +:10BB600011EB7488753A22EF33ECE7CF637D79737C +:10BB7000ED03E9B81FFEFDFD8D2912FD69F83C5665 +:10BB80007FC8D7F1F072551E9727DF1B5EE43CA3F8 +:10BB9000E0D90FE7A8F94978227F53BB315ABA940C +:10BBA000F3CC11F43980BFF3BFE578E27ED9FABB5C +:10BBB00079BE387369E9BABE335F87F909B2DD0728 +:10BBC00078C0A034EC27BC214FEC2773584E9CBCA6 +:10BBD000476F9E33A67F91DE47EF277B93E5EFD932 +:10BBE00069FD1ABD4EFE7B39FE73FC7E836BA3FCA0 +:10BBF0003C188F7ACE166E17D62FDAF263027E03C8 +:10BC0000FD547D7938BF1253C5F3F83B5BABF34A63 +:10BC100067AB6077942455DC990FE5A6C7C693FC03 +:10BC20002E1954F1793EC8F3358F4DE0DF47577C2C +:10BC30003E04CB791379798AE77994F760B4CC9E86 +:10BC40009A15B62BEECC73D1B8FA4A1DDD6B67425C +:10BC50002306D6637ADD44F98012AEF19E25265D77 +:10BC600053ACF3BFF7F4D3038FBF4CC07FBAD01FE0 +:10BC700028FC052155E32FE84DE4E7CF7B5FFD92DB +:10BC8000CED7DC9BE75B9F07ED1BAD676FCD87F2DF +:10BC900006EB0714EF533C6087A01FC6E5608B607E +:10BCA000BECAD9AD5EB49FD86AB75925B80AFF1885 +:10BCB000DEA907F07BE5B5A77E3C880FE3C5794C8C +:10BCC0001472A0F1B5BFFD15E3C48D676C6E341B13 +:10BCD00027763F7C27DA5F13BBDFFE1BD7C3FC3C14 +:10BCE000909CF744F47FC2FB095D269AFFC4EEAB3B +:10BCF0005660FD6BDFEB2E403AB9EE44B005C5420D +:10BD0000EFABFF3E48730E887D7AD97CD1B8F1390C +:10BD1000098F3F01A093081E3FE7F0F88AF2D9CEC1 +:10BD20003B8F6E0E9193547BDE0AEC788A3B5F600A +:10BD3000096E8C7BC873FDD17ED5E3D5B03E787F8C +:10BD40005D1FCC20C29E9E72D10C82245C2E67C9DE +:10BD50009A72A5394B53BFCA91AFF93E3DF32ACD34 +:10BD6000F799AE424D79D6C8899AFA37BACB35E5FC +:10BD7000D913666AEA577BAA35E5C26087A67EF1C9 +:10BD8000912EEDF7634C8F78283AEE7E039FA5271E +:10BD90003DE49E2D3BD5F4063E27FE858323DAAF96 +:10BDA0007CCDC58E37F0BDF42B479F9F927EE69BDE +:10BDB000F5B68031B63F39532D08DF83A0D7F1F3B4 +:10BDC00053EF25FBFE807893E7A7A6A05F1990505C +:10BDD00075DBB99FE2EF325C58C4FD6EC711319438 +:10BDE0004F6E277FE57143D3B37FE47903B928F71A +:10BDF000AEEB9BAF59F7948B3ECDBACBD9AA283C7A +:10BE0000DDA1295739EED6D49F9EB95EF37DA66B8E +:10BE10004B149EB66BCA37BA1F8EC2537B149E9EBC +:10BE2000D27C97F4DD2DFC5FAFA1DF0A9E93423DEB +:10BE3000958887C9A7FA081F137ADA2A114FD71CE9 +:10BE4000EF207C9504BD95282ECB8E34BD81CF206C +:10BE5000ECCBB0DD81E64C7A1E6C7691FFEB70F393 +:10BE6000487A1E6976D3FBFF689E40CF5F357BE83A +:10BE7000F99FCD33E8D9D3ECA567477307D57FAEDB +:10BE8000B98BFBCF52FBEFDDC845BFC1795DA8017F +:10BE900023C68EC15B499E9E4F089DC7F2067FEB6D +:10BEA000ECA92034F0671D902F7F209E452E4FFB7C +:10BEB00060780E1ECCF8FD19227FA343E729443B8E +:10BEC0007CF4E30FDEA7E632B669BD37137F3A187C +:10BED000CB662813B2E9F7901EBCCF93C3D8B3A8A2 +:10BEE0004AE8BEF7076763B957FC9EE7E0C71F241F +:10BEF0003BFC5BC7D93D03E2ECA307C788B33F7B9C +:10BF0000CA65477FCFD1AF46D8111E4785DFCBC367 +:10BF10000A0DF83B1CE56AA101F5ECF138E7215464 +:10BF20005379C9E0525CB77B1EE5915F6FA0DFE1FA +:10BF30009BA3F0FDAFAC97ECE2FAA0F74613EDA798 +:10BF40008EE93C2B903F7A95BEC710CE373DFE144C +:10BF5000E9A95E7B5F1EC2AFFAF1BDBCECEC7B4C85 +:10BF60007147940D1C3E958F3F39DB6FFB5EE133CB +:10BF70001BD7110D9FB9831D7C5F11F4E4A21D2016 +:10BF8000CBC7AA3DF514572CF70CC3751CF59A388E +:10BF9000FF7AED8161E437F294CE8BF0FFF40C363A +:10BFA000D0FAE7A2DE443FE8427D20D6EF159E1F7F +:10BFB000CCED3DA213DC672EB0D2BEE0988EDFA39D +:10BFC000105DDFEEE2FBA3CFE2DC879C28BE57DCEE +:10BFD00054FFEC0BD05FEF5A0B75DDEB1D41F658AB +:10BFE0006F13401768BAF754D339FEDDE41620A169 +:10BFF00038EF2DF82FF8FE6CF79D5FFC06EA7FB056 +:10C00000D6EA261DE21845F05B282A2F4E3593FD0F +:10C01000B4784E6E05EAC55B44BCF056BB9A4E61DF +:10C020004335D9E8807E96DB0A370304D9CAB46A5F +:10C0300023FE64534DCE1D9BF1B97AE87623F25866 +:10C04000DD987D9BD18CAD07162E25F9177AA7199F +:10C05000E675DB3ABD8BEFE7E4F9DADA6F94F722A5 +:10C06000E9F798C84F0220D07E35C9A568F649493E +:10C07000824E1F182CE23163D9D84BDA78D74EE4C0 +:10C08000A3B38BDF191E271EA1FD2EECC7DF8A7B11 +:10C090009EA3EF4F91E33A5C7CFF75CC089489F640 +:10C0A000E442AE07C6CDFF7C4329AC7F5CB7434773 +:10C0B000790DB7D5BF8078B8D025F068605DC84FDE +:10C0C00037F9977CF01B424C9AE6DCF095F4A5BB5F +:10C0D000C75119A92F4B42DECA487D39A1AFAD1215 +:10C0E000F5A2D48FC1E61A218F9B488E1E6C5E4745 +:10C0F000E5C3CD7E7A1E696E15F2B88DBEFFAA79B2 +:10C10000A790C701218FF7D2FBEEE6F9F47CADD9F9 +:10C1100047CF85A9BED7116E328E3BD7ECA3BCDCCE +:10C12000430F9B18C6F12E749B288F0338E2B1474A +:10C13000D2304FC944E744A3F395A2E57C3F3D7458 +:10C140000EB8B7E56DE4F7FE3C23B41707C7A7A701 +:10C15000A3CC6547B9F4F1E0F324878EBA5C76B4DA +:10C16000A74F3E2ECA1E97DD00E53F0DEE25FD715F +:10C17000D4E7B29BA0FCC9E3BDFCBBDF65B740F9C7 +:10C18000D3C17DFC7B8051D0FFECE02F488E9533EE +:10C19000E520F247A5397F2AA80BD0D7E507912FD4 +:10C1A000A6672E998A7CB160B08BE872A66BFD41C0 +:10C1B0002CCF1AD9AEE215151E5BE1466C5791568D +:10C1C000AD62BBA939776CC476D3866E5723DBCDBD +:10C1D00018B36F23966F70B7AB689F2E4039561A0D +:10C1E000EE4796E57729A7653EDDD5DD5ED207E30C +:10C1F000BABCA40F245C2AE6566F42FF676397E23D +:10C20000C0DFA5A998ABF4273360EE6203DE930A82 +:10C21000F2FAFF3DAE77AC87753662F91A2AB7ADF0 +:10C22000FF06FAED7F00F6E231E800800000000032 +:10C230001F8B08000000000000FFD53C097854E582 +:10C24000B5E7CE9D2D64924C360842E2649924965F +:10C250002C43B6261064480CEE3001F944651910E1 +:10C26000C2164804EB17AB7E191A17E0698D6BD123 +:10C27000AA6FC4B5AFB6E461D458091DAA52D287DB +:10C280003A5510B47974A488F0999011DC78D2C72B +:10C290003BE7FCF766E6CE248014FDBE078693FFDD +:10C2A000FEFBD9CFF9FF5F008053F8B3027F603403 +:10C2B000FE38253D8C046804F167BFD16DB295034B +:10C2C000AC34078CA0A32F41A3AB1060AF0E9676C1 +:10C2D0001400A424C3FC7A0B968DB0740B96E75D12 +:10C2E0006803480568DABA206E8185DABBE36660C8 +:10C2F000FB4517E2AF38CE52056E54E0930AD49B4B +:10C300009C89344F9A4DD21FCAC76F8550784A0610 +:10C31000E8B79A3DBA048044937BAC0DC7ED9BFB14 +:10C320004E835887AF88D6316CBD1EEBE300326C6C +:10C33000561E1FCA8219545E09ED46C846B8F5CF8D +:10C34000FBA422DA97C52723844E435F205FECF9D4 +:10C350005416FE63063D54E07AE9036E6999D7707E +:10C36000206056EAF1673974EC706622DE5ED47E96 +:10C370006F04BF18BF43FB7D15E28DBE377569BFE3 +:10C3800003545B0F8D433002CBB8DFD912FE5E85BC +:10C39000FF0D8F874967C0C3A4A1F010B51FF01A25 +:10C3A000418EDED70ACB6EA673E4BEC09DCAFCD117 +:10C3B000088121F7A7F245F4FEDA05FEF502FF2514 +:10C3C00036E7745A5FDDFC389053008E6D35794D39 +:10C3D00099DCFFA93D2944179375832D9A3E5B5B39 +:10C3E0006783DE00B0ADD5CDD0D7BA14F476803FE8 +:10C3F000B53673F9ADD6162EEF68F530DCD9BA8EA6 +:10C40000E15F5ADBB97E57EB462EBFDBEA65E86F8A +:10C410007D91BF5F3B7F6586DB124DFFD5C9CE4561 +:10C42000C48F9E7BAA13993EB8F753C8AB9E1AC817 +:10C430006FB644C30183659D94C0658F11F7E1D940 +:10C4400016E36DC37DFD738CBB89C619A8097EAD4B +:10C45000437C434A80F1D030D2BD9ABE4B461C3A51 +:10C460008966F5E412FE0EEB3CBF0764D9569BD3F8 +:10C47000A5473E381A8F551700DC82650FCEF3783A +:10C48000AAAB85FA417EC048E39CA23F93717C0928 +:10C490006677F03A10A21C0EC408E8B1492C8FD17F +:10C4A00050C8DD40BA9FF960E0E91319B68233CB7A +:10C4B000C570F8A893AB039E32A46765ACC384D55E +:10C4C0007D12F8A412845346D6008ED3976ED413EF +:10C4D0009C14445650C7C39FC9DF226386F1CB1416 +:10C4E00048D4946BCDA335EDEBAC999AFABEF45CCD +:10C4F0001EFFD2B48B34EDFA46579AC5BC532F2396 +:10C50000D865746F5C80740956991C9BB0FEBD9809 +:10C51000F822280698161BBF89E07B31195E6A371E +:10C52000EDC0C914C07D4E937D238B105597DBC69B +:10C530006BC7ED995363C37657E65769D721C12579 +:10C54000B4DFAB1D5334DFA7575EAEE9EF32FB9388 +:10C5500008ADF5CE7ACDF7C696AF419F0C30B1E568 +:10C5600024E84B01C6FB3A34E394EEECD2B41FBF8F +:10C570001B6412EB927D8E3709961F74CAC42A156C +:10C58000879BDF2458F5A53F83F6014EB059519F94 +:10C590004B8ADC8347023D962729E5CAA0B72D8147 +:10C5A000E87012F2F548BF8930C2216363A9F2BF77 +:10C5B0004E101F4C5220003207F6AB164B80793AD2 +:10C5C0008BD798456A05E51BF5C106C991A6473882 +:10C5D000470E5450F928048A08CA3A979EF86B2AE5 +:10C5E000348FA5B209DC69043F4874BF4F7CDC2F4F +:10C5F00005DAC4E282C9C4CF753FFF68DE6DAC17AF +:10C60000621C265CDFEFBAFE914A6BFDBB3FF591E1 +:10C61000376C217E6FB27ECD7852CB8D2DC7197FBE +:10C620006AB96F2DCC77E192DB0D689F1036FEAFB3 +:10C63000CC760AEDDA3AA25323FCC9B8BA20D41E4C +:10C640003ABE18C47731EABF7A5AD304C2D7DF5D45 +:10C650004E6C576F1072089E45F54E1CA73E46293A +:10C66000834FD4A72AEDA1B29ECBE96A7D95686F6E +:10C6700057C77B58B41FAD9695F12E52CBCDA29CD7 +:10C68000A9CEF7A02817AAE5FF7071394EB43F6113 +:10C690009B55EF2908E9FF53AADD180FE3C96EA0E7 +:10C6A0003D9033C91E48BB1A981FA2ED85B65EB1F6 +:10C6B00017F37F237B8CC5448FCB63DF21B9EE90CA +:10C6C00080E4BAF17683D38BF37F9ED451B4C61243 +:10C6D000C2DFE7B7087CBB6AE39C32B65FF96ADE6B +:10C6E00026E223396EF7C885F8DD3A56C77AA74E99 +:10C6F000B63881E87BAFD0FB6AFF48D8D0F2868697 +:10C700009E51F5B2C4F3C16CFCC1F9FAEF1BF5F40C +:10C7100006C2598E3F9770939929F4DC48D4AD95A1 +:10C72000F8F336EA5933D23D251B9C3A6C9FF21A36 +:10C73000EA67A2F141BFD0C7AFC5F824149C958F1A +:10C74000BDC9F66FA18C528EF87B2DCF9D97897C49 +:10C750007A34CE9F4B7CDBD0B28DD7758DDDCAE3AA +:10C76000833558108ECFE2CC28FC979E01FFA53F61 +:10C7700026FE718203A4CF752874B4BEE596B778FF +:10C78000BFCB95EFAC5F3243EDB82C47978FC639DE +:10C7900032081F0E854E0774B60A055F5713BEFA9E +:10C7A00017FB7313B1ECF0F947BAD93EEC2A97881E +:10C7B000EECD7140743F2AF98BF60E41FF8ED60EF6 +:10C7C000B6CB5B5ABB18BE8473D0BA557CDD108DD6 +:10C7D000DFF967C0EFFC1F13BFA3F401A303FBAD98 +:10C7E000DA073C4E85FF8011C2F44C2BF125E2277D +:10C7F000A14BE2FA3AB92021A0A98F13FE528E7301 +:10C800003CF1E9CA19BBAA37482179981C0B1D31A4 +:10C8100049CCD70E85AF1DC4D72AFF223F96EA1117 +:10C82000CF6F9DC47E43E037C4BFC0F3A878BA3B46 +:10C830001AAF1B888EA7C1ABB6FE07C66B27FAC717 +:10C84000A43782AFC478376546E3F9770A5E557C32 +:10C850006F53E47F383C6F233CA79E7F3C6FCBB483 +:10C86000F1B891F81ECE3E45D2475DF710725A7E60 +:10C870002E723A2DDBAAF8DFE8771646D3FD6DA2BB +:10C88000BB5943F79E33C853CF8F294F91788B8480 +:10C890008D12B83A2CD1DF3FCB1C56DF9D173C4E92 +:10C8A0000ACED6F86793BF756BFCB329186169FD92 +:10C8B000D89B34E53AEBAD9AF697A6ADD5D45F6E2A +:10C8C0005BAFA9BF32FF014DF96AC763117EE6D3A2 +:10C8D0009AFA7AE76F34F5739BB76BEAE7B7F468B7 +:10C8E000EA1778FEAA29AB78DCDA0A1C2F6D6B35C3 +:10C8F0002BF1D3650CAB03FE5A12838B0F07D9DFE4 +:10C90000ACF4B7D7B24BB2AF83FDD1329FAB96C276 +:10C91000AA8A9DCD6F12F4B55A95782D8DE15BAD45 +:10C9200036D6EF3B5AF319EE6C7528F15A25C35DE4 +:10C93000AD4E254E73318CB40BAF66BBA764213D61 +:10C94000A6BDBC4407B880E97FF867C15E5ABC77D2 +:10C95000BC8EE2DC35CA5E8E577FB3FF36E4AFE3B0 +:10C96000CD2607957BB71F31D80AA3F965EEB732FC +:10C9700038C3F86C6ECB5F0DE467CD450FBA630822 +:10C98000399D9AA5637E20F703502FCC368321056D +:10C99000F5C1ECD992A30DF8BB079218FADC583F09 +:10C9A0004D0F3E1396EB2D7A9F299E97E632A33FBB +:10C9B0003D4B2C134C7AF0503DA424739C7E0D7D8E +:10C9C000B4A13C3865B818BFCF223F1CFB5D6FE9AE +:10C9D0003090DDBD6EE72FFA6FC37AB8D353CEF136 +:10C9E0003D5C6225FD2D793ED69D1A37BCBC2035B5 +:10C9F000E150185F4F25194EA5F8D1E17752DC7A46 +:10CA000093C1F19C2DBADF05CA7EA7C912FB6FC185 +:10CA1000D74DDE4D52483E717F3B4DB8CF26E201E7 +:10CA2000DA67B3C19757447EF676F6B39B2AD716DA +:10CA3000119D9A2E913E311585E29DA6962FD98F94 +:10CA40008FD4CF91F04CF190C36F65FEDBDFBA93CA +:10CA5000F9458D8B7A5B7D5C2E0BB86AC3E3A339F5 +:10CA600093FF4DA6B8A7EA4B11FF4C3CE9DCFB5302 +:10CA7000DC77A0D5FF2FE517D4BC829A6788CC5B02 +:10CA8000A87A64DEAD75096EDCEF9A2C5106F3943A +:10CA900074A6A35E4055DFDE9A156597EFC83ABDD0 +:10CAA0007ED6D6FFC0FAF96CF9BF314DD8D548BE55 +:10CAB000DF37E30503AD53E5EF48FE9F437D70FE8E +:10CAC000394D92D7837A7AF69276C344E9DCF97DC0 +:10CAD000B9E5A0888B23EDC2F7B60736A69B5C2B81 +:10CAE000737C61926F72501E44A5434734DD3ACF88 +:10CAF00040B7CE1F936ED176F1E0BC73B38BA0F13B +:10CB0000CFDFCB8AF2273EC83ABD1FA9ADFF81F720 +:10CB10006D1D6B63B87244EF3C5927EA457C620196 +:10CB20001DF2EF8057E6B87469667B3CC533501937 +:10CB30008C277DB7AC5B06F20F41EFD48F46FE5CCD +:10CB4000A2F0671FF83E247E5C05F77E4109982518 +:10CB5000D54BAE223DB7F40943084FFCAF93F32702 +:10CB6000AB947ECB2D9D46DAEFF267B5EDD4711A0A +:10CB70005F8AC81F575FFA19B0DDF073DE6F55A7E3 +:10CB8000B6DF77597129876259164B08EF67D2A72C +:10CB900047C9AE1BC2CA275B39BF203FF3E0039EE3 +:10CBA000B121FAC46447F1715CF6E9F9585BFF23DF +:10CBB000F3B11CF7AC91E8F97DF978BFDD9945EB4D +:10CBC00056F5F3A0DE79C3C47A67A0DC26F2A43759 +:10CBD000FDAE2D9EF8E40438881D162AF9D2856A28 +:10CBE000BE749D365F3AB9CFC779B94907BD6D713B +:10CBF00048F789BD1ECEDB55ED76B759B0FCD35D45 +:10CC00004E99FCA3F16FB9645AB7EADFA8FE4E480B +:10CC10008FE5B0BEE3BC6BF6D9EB3BD52EAAF63060 +:10CC2000D20E5606DB6BC9FE4DF8B6E34D82E72BFC +:10CC3000AF1E69F7DE8B137AE2A8C157BE97FC8C52 +:10CC4000D7631CCF41F4FAAFCB167EC64CCF02039C +:10CC5000CB1F091FCADB0C456EAE4F765F974DF5B3 +:10CC60008ABDD0999D06B2A37572DF23D7125FF9F2 +:10CC700065CE1BDE7CC707BFFFB5EDCCF98526EB83 +:10CC800071F63F868B339A74E0A6F8A2A4D6564A72 +:10CC90007E0CC56D944754F38A91ED9FB0D7ACC814 +:10CCA000E63C57B5DF49EBD928D6331CBD9A5ABEAE +:10CCB000D0E431879BBFA9BBDCBA304C3E5ECA16BC +:10CCC000F12ED2DB7AC81CA2F7D9F2C5FFB7F865FE +:10CCD0009A0C1E09ED6CA1E415FE2F083F780EF8A2 +:10CCE00019CE8320433758F97C6A2138182E021751 +:10CCF000C37CBBDB4B7C3360088E24BEEA7FF5BB74 +:10CD000002E29BFE8B27B657C1F93B5F8AF4FF0610 +:10CD1000C6DB78FE8157BEDB43FC397087E1ACF49B +:10CD2000C6EA646727F151E479CBBB53643ED7016F +:10CD3000FD7A968B7AABE80397A4721BEBD84CE68E +:10CD40008B90DE1CF5B4AA371760BFC24F74ACD706 +:10CD50006099E4B563D3AE808E45AC7071A657A6DA +:10CD600072A7A82F5C99E895B05C581523EA6F4A22 +:10CD7000F44226C5430196CBF900AC0F1780D08B47 +:10CD8000378293F78991419684FD176F3597703EEE +:10CD9000160239A4FF8B288E1A224EB7E608792F87 +:10CDA000CE12FABEB8469B17F9305BC91BDB6B4A43 +:10CDB000721056E738F7121D8B93FC1B1E2AA37CBA +:10CDC000900E36A17C7D56752B9F77AAFD1AED3506 +:10CDD000BD84BFCD1270BCE2E936799F13E78C2386 +:10CDE000C3CFCDF2EDB507A8DD115A7BF9F078C5B8 +:10CDF0007E1CF747CB9587D7574CB11BE7FBF14318 +:10CE000025CFCBE5FF79E6EBFA3B0BF84CC1437E2F +:10CE100072A3DD7D9CD76F04B0D0FA9F14711440CB +:10CE20007306E547973C65D2919FF1119A63C80359 +:10CE3000F81BC6DD04FF1BE367827FC7F899E02774 +:10CE4000183F13FC07C6CF04177F3B1E8322808D3B +:10CE5000394E4B4E79E81C3072BD861C81CFC1F92A +:10CE6000BB8D3C7F9DDDCDF81DA4F7EBE0A573994C +:10CE7000CD89C10B924EC36F03DDDFF0F9E9707805 +:10CE800051CF2523EBBF53E85AD4A967FB5FD415D4 +:10CE9000886F086B77418E91EB0B5F39184FE31F5A +:10CEA000B50EE2D729E196A7E944F982672D330848 +:10CEB000BF75766709ED1BE53C83F651D4F5C18358 +:10CEC00013CB787CAB64A375041FE5B821621F9176 +:10CED0007850F7B539D1BF81FA6F7E258B76827A8B +:10CEE0000784DC101F4943ED772DF3CF7453B0CC8A +:10CEF0008AEB9D7E4A6E1E0AFF75F6298CE77754F1 +:10CF00007E53CFC715FE52E976AEF21D391E906BE7 +:10CF1000847EE76AD2A536B24B27E3C92FAC57EE21 +:10CF2000197475E6BC47FBF4EC94C16E633ED6C839 +:10CF3000DF62855F5458D86D7411BD36771FCA59AA +:10CF40006461FAE42CC6F6B372EC9ABC6761D589C9 +:10CF5000C71F4AE1F6569AEA3A78BACE8AE3DF600A +:10CF6000DEFE366D69AEF593BA442CCF4F93761042 +:10CF70005C60CB9C9A64A3E57A79FD37E64FD94192 +:10CF8000227595A39EFDB929A464C2EC43AD3996E0 +:10CF90000E1F07CB75D6644DF9D2B4319AF697DBE4 +:10CFA000B235F557E68FD3D4ABF35EE528D5B42B75 +:10CFB0004E0A66515C87FB60B980E764AF5DA27D75 +:10CFC000EFBE621C96A73D3FCB416ECA66A57EDAD6 +:10CFD000965A2FD16300F1694487EA70E5FA471F3A +:10CFE000A2C122E286C6EE6776386DE710370C13D1 +:10CFF0002FAC00718E3F5CDC10192FA0FE7C90F4EA +:10D0000067F1ABD758DB70DCCD55272EB0E13EEF92 +:10D01000CCC13882EC8D12470CC73F837222D904F1 +:10D02000FFF4C8F0DC10FC03F00B851F059CF63EF6 +:10D03000FA3305DF5FBF7D4AFA8DF3071EC5EF5750 +:10D040006044BEAFD8E8786F0DE5A7DE9181CEF9D8 +:10D05000E124AE03EB1BE87739C4F7B0E8E9BB463F +:10D06000A7F0770FB9A6AB94FCDF1F7314BFAA71AA +:10D07000FB5DA3CB42F570F3279AF670BB74B7A69D +:10D080007C67A6B67CEF94BBC3FB0FE797356C5C5F +:10D090006074A39C363C2C39BD43E88BC1F5A428B1 +:10D0A000FAA17B09EBDB43DB97196D71D1ED57E1F9 +:10D0B0007894B76C18C6DEAA7AEA3A199A87AA7FDA +:10D0C000479DCF717EE7FB08714FF6CDF39AB0C351 +:10D0D0001F25B88DE17CB22F479C7BF43FF6C01D25 +:10D0E0005FD379EEEB22BEEA4F14F6A3A8F3339D8B +:10D0F0000E61F108C15F45D6808EECD2C0D2580FC8 +:10D10000A09C352D8BF3E88AC98F087E681E4F5E80 +:10D11000C72D0F9A91CE1FEB741ABB3C40C11696D7 +:10D12000FB9EFDD98C3BE9F702712FE97CEDB32F13 +:10D1300007847DAD117A631EF19F62B7005556D307 +:10D140005D3068C748CF105EA89C6BBFF5FD87C9EE +:10D15000CFEF117A83F20A37B05FE0B468F30D1DA8 +:10D160002CE7F8BB2DFC3ED759EB8FB7DA8D96F341 +:10D17000A84746D8B5798721F4C5FB57223D9B5E69 +:10D1800097F95ED0B1ADF60408D31F91786CDA2818 +:10D19000B39CABE5A35BE5CBBC6C0F8319F585D1E4 +:10D1A000F806A783E57FB555CCB77AD23733C84E9A +:10D1B000AFEED68B4B2FC3CDB34E065BD83C9BB79F +:10D1C0009996925D53D73F6055F449F75749530AF2 +:10D1D000045C3B847D45BFC090427E41BDC4F1EC00 +:10D1E0009EEE513584A73D12F86C253CC435665C33 +:10D1F000DF4C311C7DB7505E14D2F2F99EA51AD7D0 +:10D20000AAF1ECACEE5976F2633FEC5CB807290763 +:10D2100093ECD9CC4FD78287FDEE3D89AE74CA938B +:10D220004C53EE3FEC490CF691BFBD6752AC44F74E +:10D230001970FC3B697C755F7B0CAEF466DE9792DF +:10D240002F75FE443E157BF671A2AA67EBE4DBA7BF +:10D250005C49E7F773C04AF1EC7459F8D5F04721FF +:10D26000CFAA5E6D92FC496CAAED33A6DB114FA3E9 +:10D270005A7EA9E47DDB35F700CFD6AF1E8CA35FC5 +:10D2800094987F563944BCB1AAFAF347AEC5F95712 +:10D2900061BC4FFEDDC2AEEDFB087F91F1FD607C0D +:10D2A000F52FE67BA3E333D732DADFCD771CDF73CC +:10D2B0002D44C769837181EA5F3E17CBE7D6A85832 +:10D2C000857C28FC7A645BEEDE35587FE42F0666A9 +:10D2D000D73727FDEAE8AD58BEF9B958C6F391240F +:10D2E000F0901D39B229CFEBC1064B74C15EB26F0D +:10D2F000B0258ECF693E7B32EFB72F517EF2B776E5 +:10D30000F643487E6CE8C27C46F78FE8FBCBA3B9B6 +:10D310001FB8C5BC0D8A5CCA2F14DE5F4DF52F24E3 +:10D32000737E42A5DFE127639C14AC7D05BE222BF2 +:10D33000B2DEE792E710DD5B5CA17B69BF847CF91C +:10D34000D508F706DAF7F2C7FFF3C389B89FDA17F3 +:10D35000AEFE5515AE6FD907A940E384E83AB4DFB5 +:10D36000706C6BB6907F053F2B5E8CF11E0CD32743 +:10D370002B3B1235E5A6AED1DE83617A68F09E7252 +:10D38000A3C4E7048D8A5CED37BADBED94D7A5FB27 +:10D39000A94C3F711FB584CEAB08FFF79918FF91D8 +:10D3A0007CF6A25D396756F33CC9604E23B9750B14 +:10D3B000FC0DDC97B789E2319F3D49F13B82B933DF +:10D3C0000AC3F9B377D51B9CE731897B8F31439F23 +:10D3D000EB77DA13B97D83F94B4D9E6955CB094D37 +:10D3E000FE675501B01F50D2662BBD89CE8714BA97 +:10D3F000DC9FEE7A8DF1DEF1C0ABBB189F4FDCF203 +:10D4000031CDBBD3C2F4835D4A3C16116F3598BF52 +:10D4100050E4EF698D7F7EE8B1BD4594FF38F4CAD2 +:10D42000B822CAD32E94FD877E9DC9F79CF6DF866D +:10D4300070CBCEF7392F1EB9DEA87B0C92D0438D6E +:10D44000B48F64BAFFE37AC7CE722EF4C3810D8520 +:10D450008C3F351F3D7064E878505DA73ABEBA3EF8 +:10D46000757CB5DDDFEC225FD06FF41791FD5F4175 +:10D47000E73061FBEA8FF717255AE8BB55F81349E7 +:10D48000580EE3B77FF5BC2AF27C6AF05C56C947B8 +:10D49000EDD3ADFD9911F9AFAFE321833B5CEF7E96 +:10D4A000CF732A75BDEAFDDA7EAB85FD9B937625A9 +:10D4B0001F9F0EE9D40EEB1D3EF2BFB7981CE4C7C8 +:10D4C000279A5C908BF86934FAF8FE9ADA2FD1E447 +:10D4D000E6EF9179F9814423D0BDE58154E5FCF76D +:10D4E0002B60BD4271E8169CB7AC56D7BCC512D2B2 +:10D4F00087AAFE2C1B87DF0BE81EA93EE42720DF4E +:10D5000094156BDB87F6A32DFF7BAEA06359B26E3B +:10D51000C838B92457C8651B74C8429E851D9DA88C +:10D52000E01D0DBF1CEED7AC52F4FC40BCD9430744 +:10D53000BB13B78A7BAB13F5BEED04510B404B1206 +:10D540005D99F489F1BAB4FA9C6CC81CB6CBE3D8E7 +:10D550002E4F50C87DB7D4CCF75B43F75CFD32C18A +:10D560008B21C8D009563D412403C34BC0C5702A46 +:10D570003433BC0CDA195E011D0CAF023F43F8894D +:10D58000AF0DD81EDC6E65FFE9F2253AB2CB65D748 +:10D590000EED97CF52F0353C3E50CB579C3B3EA60C +:10D5A0002AF77287C5CBD87CE67B152F26E24FEC95 +:10D5B0001703DE34829320C0E34C2646CEA678DDE6 +:10D5C000C6F77E6BC1C9E5BAB3C44765C0AD77176E +:10D5D0000C8197DAA1F9649EC22703B9C0F851E91A +:10D5E000F548AE8DCB2ADD30504C237B104D4FC813 +:10D5F000A07596C5D61CA7A722B73F5F36538F7A72 +:10D60000B4ACB4660DA9905FE64E15E589352FD30D +:10D61000517DFBF3978A72714DA9C1815EE8DACB27 +:10D62000665E82FAD9ADDC2737A311A07B6372B6A0 +:10D630003817762BF7CA4D72E65ABA2F66BA0D58CC +:10D64000DFB86300FCECD722B791BCB8451C7BB3B4 +:10D6500055D0AF3AD67D4B2ED933B32FDE8674B872 +:10D66000796DDD28B29BF718C5F89FA4DAC6BD8195 +:10D67000F83299C4BD5675BF58EF89C17240B2AD3A +:10D6800069C90CAD4B5DC759CC7BD7E9E6CD4F7767 +:10D690006F203D023607C7156314FBBE65CBC4344B +:10D6A000F430701D565E47202E774D0B56DD91EEFF +:10D6B0007A84C61B88137CF808D1297578E8CB7565 +:10D6C0003E943BC4F781B5DFBCEA23BDF4292E04A8 +:10D6D000C7F94DAEFB715A47932E90518AF4FB4522 +:10D6E0002C7A000521BE96909873100F6D4EF01A9B +:10D6F000595E947736CAF9992A17038B713CC44F47 +:10D7000099CB558BEE2254CC6E7E9360A5BBBD1693 +:10D710006B689E17683D4D72B081F8E468E207C6F9 +:10D720004F596EC70AFE54F459F7B69EDBC688A25D +:10D730000BC2E4B269DB89AFFF86746F3A66715041 +:10D74000F3903C3EB6469CE75A34FA4695D3095DC1 +:10D75000263E389CB8F5A2C5D46ED207BDD9A4B771 +:10D7600027F706DAC87D1EE8DE3B46C889EAD77F80 +:10D77000239D8B7DF9CC8CFC914010F9235E9C831A +:10D7800073FCF48A38075FADE43DA9ECE17D8B784A +:10D79000548D3B57F6BC2DDE8579F06F05BD2B12FD +:10D7A0007F963E71E355C46F91EF8BD478B449698D +:10D7B000B7A2D77B37ED27F2BD5113C5A345C3BF31 +:10D7C000376A7AA296E3D1C8F746BDB94AFE4AB194 +:10D7D0008FA0F8A14B9436B43F0BC78746AF09F72B +:10D7E000B6FAC9350E2B95D32D0ED6C7573D0EE18F +:10D7F000EDE18964E619559E97AD93D8BF56F15A6D +:10D80000FCBCC949EB287E7E14FBCDE8EF8B7BE99D +:10D810004A3E91DE12D07B83CD89C12CBA67BAB95A +:10D820003BDF41FEF81F5A9DF00F43687D6A3C5074 +:10D8300027BF544BEF878E2DC2380B3FADEE79A634 +:10D84000CD8CE5D5EBE95510A584F313C8AF2ADFDD +:10D85000298397C601EF43D5083B153937A5E9C0A1 +:10D8600016868F18DB08B00D910F3029F48BCD4F41 +:10D87000D2D4C7392ED0F44FA8CCD2D4B7C588F7AC +:10D8800032E071FA0B2A42EF48129D3FD1F4830037 +:10D89000FEAD08BD17B9277EEA4E7E4FE26FE03C31 +:10D8A00045F265259AF62679AB4CFC5DFDA55E43F5 +:10D8B000CF9F52A61BF156B91BFD1C9C67429FB619 +:10D8C0003E26E001EA17B35BAFC94B986CDAF285EC +:10D8D000794A9E622C8CD5E42906F12EF8FED86197 +:10D8E0001DF34505E4FCAABA8CF06C00AF2D1A6F4D +:10D8F000C740F85DC7C65A1CF4966A42CFCB32C9FE +:10D9000041AA4B8BFF51B3B5F81FEDD6E27BCC5249 +:10D910002DBED39BB5F8BEB0458BD74C8F166FD9B3 +:10D92000EB2668DADBDB6B34E5BC8D5768DA5FE445 +:10D930009DA1298F7BF17A4DFBC28E859AFAE2AECA +:10D94000E59A7A95CF86E383F1BED511FCA603DD77 +:10D9500069F8A074E7CF35F3FD50F49F9FA7E80561 +:10D9600085FED72B76E5DDF8C3F792B84E8B157A96 +:10D970007030DF506DE078EE3D5B726D1CE905C5DF +:10D98000DEB9147B07394F89B255941D7E71BFA251 +:10D99000649FAB36DE46F72CC4FD8A8AC3EDB50919 +:10D9A000D43EE21DD6F44A4973DE1DF92E6BA667FC +:10D9B000AD9C20D1BD44713F31F21E84FA3EABDEF6 +:10D9C00019A339271FEEBD969A5FC278018C142FD8 +:10D9D000E8CCFC3E31DA1F726C94D95F73B3FFF66A +:10D9E00067C9CD79A76BCCFE0CE2EFECB1EEF5790F +:10D9F00088B7A33A878DFD3DE5FDD6006D8CDF2FFE +:10DA0000F5CCA43CE90086BB94D7D4DFB36326BD34 +:10DA10005BC4E55B031522ACA63F8FE6B91FA4717A +:10DA20000E48D6BB4BB1EFBB133ECF207B66A27333 +:10DA3000FE123EFF7E382FFCFC7B14EE0FF56D408E +:10DA400067F3F079EECF258E533EA7C1AAC2E477E3 +:10DA50009D41794F2AE2B6B90ABED4B86D8E32FF25 +:10DA6000011C6229EAF3B95D7F66BCAC48EB53E266 +:10DA7000BD668715C7BF71ACA584EF7B394B1D22EE +:10DA8000DE57E3B831F2F7B1B367BA87B522ED8854 +:10DA9000269E86979287CC5746E6C542FB16E31F23 +:10DAA000581FCB76E8C0FA74CE3F86C63FCAF985C8 +:10DAB000B9CDDAFBDDF35B3ED2F0DF02CF279AFA75 +:10DAC000404AD03006F71F7875F4D41B107FFDAFA5 +:10DAD000982A289E45BAF5E49587C60FDC97778982 +:10DAE000F01BCEB4CFCF791DBDCAFD5A759FFB5B2D +:10DAF000F77139D01A88B8EFE4D1C4BF2A34FE09CF +:10DB0000F2C98F0E4A231C43E57366E78B38A95789 +:10DB10007977DAABBC3BED55DE89F62AEF427B958F +:10DB200077A1EABBDD5E099C74BF648EE47A6A81EA +:10DB3000C4EF760FD13E9B96078BE85D635371600F +:10DB40009E24F3BBDD23F47D8877BB459295F46971 +:10DB5000EA35F46EF7F008CF51B2D8D9F989D75029 +:10DB6000BC70D828E4A3F4C56F66D27BBDC753DD73 +:10DB7000C789BF3F95641FF3F3EB129F2B8333607C +:10DB80009C7116EF7ABFCB13E73427F3C4B9890A27 +:10DB900047E60BBD564AB09CE8726F2EBFBBDA68F1 +:10DBA000E27757389F5317761F22F27D5CC91F4DCD +:10DBB0003ED21F6ADE27215F9C37D3BB395A67CA22 +:10DBC000FD26F16E2EE0CFA07776740FCA45F2BD28 +:10DBD0001B9CE21D5EDEA6F0F73009F9CA3DBD458B +:10DBE000A079A7B7B2E7C07ED227AFE5B993F353C8 +:10DBF00043EFC756C66F677FAF20DFC6F3E27A797F +:10DC0000FFA817EE24FA9CC77C61567E79F4FFD7F3 +:10DC10006038BCF52FF63F5A90197AF716F6DEAD4C +:10DC2000203F2CAFA7AE3F34CEE9E542CD7BA9E53E +:10DC3000438FDD934B72867411F948599A3F63887C +:10DC4000FED3F305FDEF4F774DA0F997378BBC60FE +:10DC5000886FDA6FF998E8DC6319F23EBFDA3F7239 +:10DC60009F2BB7F5303E709FF3687F61FBBC8CF053 +:10DC7000A5EEB3BF7BEFA305B673DFDFF77D776E4D +:10DC80001A81716DD2507976B43E617E9949ED3F2B +:10DC900056AFED8F0E39E5B1BB48DED16FE954E2E6 +:10DCA0001EB2CBC417AA5DEE54E22029B083ED0268 +:10DCB000CD4B7271B7E461FBA8E63BDA24B47F94E4 +:10DCC0005770AF617B215F6871105F7722EFF94970 +:10DCD0001EF4CE58CE7347C4D73F8B75DF4478BC53 +:10DCE000F9AF35A328FEDEF2972B94384ED8AB72ED +:10DCF000853FCB697EDA474102F36D99B2BE0A7364 +:10DD000033FBC955E091455E43C993ACDFC1F1DFF8 +:10DD1000FF011A14AFAAD043000000000000000069 +:10DD20001F8B08000000000000FFFB51CFC0F00374 +:10DD30008A739418187A351818366B32306868313F +:10DD400030883120E46885AF7153A69F9B9581810F +:10DD50001788F981581088D73331306C60225EFF04 +:10DD6000115104FB9E2003C351207F1990EE1466CD +:10DD7000605805641F03E22F40BE801003830C101F +:10DD8000FF1561603005D2C1406C03C4C745F19BEB +:10DD90007F82807CBC082ABF1B8D9F278C5FFF255C +:10DDA00011FCF20F08C863C33216E4C74722057A94 +:10DDB00007023729A2F28FCA33303C546060D05139 +:10DDC00082F09B91E4ED8062C7E421EC2992C0B817 +:10DDD00007CAB5286237772A50FE0450CE4B8934E3 +:10DDE000F7DCD341E5AF3484D000BC3E14E4A80393 +:10DDF00000000000000000001F8B08000000000071 +:10DE000000FFE57D0B7C54C5B9F89C3DE7EC6E92B4 +:10DE1000DDCD262121BCC22601440DB8400CA04115 +:10DE2000370F5294A8E1A1A2226C782421EF22F6A8 +:10DE3000621FBFDDF088C4521B1FC5D48B7651B062 +:10DE4000D18B3640D058175C9E458B6DE845A0D5E8 +:10DE50007A13405E06B240A5B645FDCFF7CD9CDDF6 +:10DE6000734E36266AEFFFF6FEFFDB9F1DE6CCCC35 +:10DE70003733DF7CF3BDE69B8964BE91D88713F20C +:10DE800025FC6E25E451891092184E9B3C93C69F49 +:10DE90009409B1ED7E24EA3B99840C9E6B7046D1C7 +:10DEA000A25F08644E4B0621C9658D7546FA3D791F +:10DEB000917DBCE808C319987CE4BABD09840C7252 +:10DEC000D3F66682BF2FE97F3FB737C69174C87912 +:10DED00085A231E1FA4A9ABC48FA7B87AABE9B1414 +:10DEE00075A6DD48FBFB51FD20B785901FC3784622 +:10DEF00042A9CB40B2E8B8785D6F2EFD3F3A0EAF35 +:10DF0000CDE85B2910221A1CB1442424262348A002 +:10DF10009DBE9F673CEDD74908A736AAC84AE74986 +:10DF2000C8B49608F57289807888CD76257BE97823 +:10DF3000577D2EE2BC570D22A49DD62792D34E6862 +:10DF40003A95C461BDC72D2306427ED5AE3F120768 +:10DF5000851B9B19245E15DC060F210E13C5AFC768 +:10DF60008CE92A8F9DA7C9C4710D21AB3D0E4C577A +:10DF7000794663FAD8D027DB7306D0F90C32D8E99A +:10DF800048488363A6DD91118627C72D30E73809FD +:10DF9000C92629AEC4545A2FD140C84D84DC42F35F +:10DFA0007523081949EC8450FC3D93BC2CCA9D0193 +:10DFB0007907E6450371C37C6332032E91E22DC6D7 +:10DFC00069CF951CE1EFF81B80DF5F782C15D6C177 +:10DFD0007D1BCCEF19E2ECF0029EDD46E7265A7F6E +:10DFE000A5EC4C5E4AE18A46DA2E83ADBB94101E46 +:10DFF000DF4CC01FED8FCCC9D5ACD730184722B449 +:10E0000073DC05EB6471B2755A097415611DE6F293 +:10E0100075586577D919FD384924FA11ED5AFAB1C6 +:10E020006468E98F7EB19FBA9EE769BF4D42ED3BC0 +:10E0300053E93CBD4B0CCE4DF4DB60A15100F80A16 +:10E04000BC25C480FD2AF9416552A063B41A9E170D +:10E05000CBE9F7F60E73CFEF2D06E252E872532AA2 +:10E060007C77C4CEA0E3266647EC4C6BCFF187E902 +:10E0700024D925C940EF0E4C1B0447AC00E37C4774 +:10E08000249B049C7F72A4F6FFD3ED08F1E17A375C +:10E09000F07554DA513C203D791F8B463C88503452 +:10E0A000390CE7171CCF17AD454F434A48E3685872 +:10E0B0005F9A5F87F463A6792BE69BB0DC1ECA3FAC +:10E0C0008BE5C9AC3E5D5EBA18BDE3555917DA6EF3 +:10E0D00003C29142705E44389650BF9B303F2094FB +:10E0E000FF25D61FCAEAF7B71F25EDCE0D9EC2F950 +:10E0F000BF2E3B009FC2DBD6C0AD942E0E6E107CAF +:10E10000269A0FEC8C41FE757EFD0C9F89E267D745 +:10E1100038930BEA9FDF9883F9BCEDEFDB245A5E5E +:10E12000B55D94206FD879D6D641F15B636A7FFCE8 +:10E1300066FA3DB85D242F6077D3719F9DE2B448A5 +:10E140003E63F9922896ADDAB06B1EC02D6B339109 +:10E15000280AA7EACDD23B6FA6F9D20332812A550D +:10E160009BEA8C83697E894F6881FC8A9D1F603F92 +:10E17000DDB9A40CF6F739E05B942F75DBDA93EE8A +:10E18000A6DFCB7D5B0AA07EF966C1094B5CBE7E33 +:10E19000D78700BFBC551E2152F815CD31C4A1DA76 +:10E1A0002F79DB17DF09E3AD7A472694ED91B2AB07 +:10E1B0000F199118A44623E0B56AD31346E09BE7F4 +:10E1C0003C07B01F059F552FD37E68BBEAD70427B5 +:10E1D0004CADDAC0F8CD8537A3E6BC688179D51996 +:10E1E0004741FB371F3542BD525FF1EB510E18DF3F +:10E1F0000663018C73FD0663898A6F5634FF5633BC +:10E20000AE534DE903DD19BDAFE739CEB7957C3983 +:10E21000154048DF92CF3843C5879E33C421FD5750 +:10E22000348BC411811F78DFE7FB608795F103BE53 +:10E230005E4BEDC01AC2EB75C9CED74F0A66CD88CA +:10E24000C0E71EE7F2A391CB8F27417ED0F4692E61 +:10E250003FD671F9D1E471E2F7673D93305DEF711C +:10E2600061FABC671AA63E4F11D67BC13307D38D26 +:10E270001E377E7FC9538669B3A716BFBFE2598E8A +:10E28000E9668F17BFBFE65983698BA711D3AD9E8F +:10E29000264C5B3D3EACF7BAA719D3364F0B7EFF39 +:10E2A000B5A70D53BF2780E94E585F9A063CED98FD +:10E2B000EEF61CC374AFA703DBEDF79CC1742DC74A +:10E2C000BB2D9BE448146F36174139185FE8CA919B +:10E2D000693EBE88E593E67A738C349FE4A6798A1A +:10E2E000C7C195811C13CD0FAE65E5293F24B966E2 +:10E2F0009A4FF1B2F2B4B5AEDC289A4F6B64E5A345 +:10E30000D67B73A3697E948F955FB739901B43F3D7 +:10E31000D7B5B0F2B17E9267A1F9B101961F7FD057 +:10E320009567A5F9F1ED2C9FF5A137CF46F3591D5F +:10E33000ACFD4D5D81BC589ABF29C8CA6FB94AF27D +:10E34000ED03402E0B98CFB5E4E4C7D17CAE9DE53C +:10E350000B86164B8E08F4B753EE5808227C86B015 +:10E36000D125517EB3D3D8F110157D64A1F0AA4B0D +:10E37000A2FC3320934550FEB0F03A96078C641906 +:10E38000943F2ABC8DE5BB650796FF5C38C0F2461A +:10E390000796FF877008F37B651796EF10FEC4F2AF +:10E3A000461796FF5E3881F9FDB21BCB3B852E9652 +:10E3B00037BAB1FC49E953573EED2FDFE09E2EDC22 +:10E3C0000872DB5D8672596A49067E59CFF9FF04EF +:10E3D00040062DAF1F644439B8F3F3AC174581D321 +:10E3E000F600C897BC04FA0585335B48047D82C2F9 +:10E3F00011FB8673CB179334706EF9A24C81F32016 +:10E40000C289EA1F9C9D5FDCA41DCF17E50A9C1200 +:10E410009C97B57FF3BAE5CB6CED78BEAC54E0D4F5 +:10E42000209CB8FE8D27204FD4C009C8A50A9CE5C2 +:10E430000827B17FE37119276BE0B88C4B1438754E +:10E44000086750FFE0048C376BC763AC50E03C8634 +:10E45000781ED6BF79B94C53B4E3315529709EC2AA +:10E46000F1A4F60FCE6EAB163FBBAD21FCAC473826 +:10E4700023FB37AF5C9B163FB9B6107E36219C6BF1 +:10E48000FB0767B74D8B9FDDB6107E5E43FC8CE9C2 +:10E49000DFBC7263B5F8C98D0DE1E70D1CCFB8FE86 +:10E4A0008D676FA2163F7B1343F809209C1BFB3737 +:10E4B0009EFC242D7EF29342F87907E14CEE1F9CDE +:10E4C000BD495AFCEC4D0AE1E70F08674AFFE695A3 +:10E4D0003F508B9FFC8121FC7C807072DCCD4CA96D +:10E4E000A470ACBDC3D93F4C8B9FFDC342F83989A2 +:10E4F00070A65238E97DC32948D1E2A72025849F20 +:10E50000F308E7B6FEC1D99FA2C5CFFE94107EAE38 +:10E51000209C3BFA37AF82E15AFC140C67F8B955DE +:10E520001A877286CA4E27D8E7DF199AE31232C1DA +:10E530004E6279D1EE24A0F7888A3E43DA5D22AD9F +:10E540006FD91C37FE31A2D66B728D064ACF56AA00 +:10E55000E5A9F59AD849D11A3D2ACE15AFC9274C5D +:10E560001BACA99F5894A6291F38E73A4DF920F70C +:10E57000784D7E48D94D9AFAC36A7335F9E1CB6F6D +:10E58000D7D44FF5CED4E4D3D7DCAFA93FB2718155 +:10E59000A6FC9AA6724DF9B5BEA59AFCF5CDDFD7BB +:10E5A000D41FD3B242537E43DB639AF27181273585 +:10E5B000F909079ED5D4BFB1FD054DF9C463AF6815 +:10E5C000CA27776CD5E46F3EF36B4DFD29C1DD9A08 +:10E5D000FCAD9FBDABA99F43FE53AB6F9B3FD0D417 +:10E5E0009F6A3FA129FF4EF2273A3D556B1FAFCCE2 +:10E5F00021CCAF3288D9AF01AB11F3C6C11666A7E3 +:10E60000584B1C2729FD18772F740CA0F4033403F2 +:10E610007651CEE0B26B3AE8F7EFDDE4BEC64EBF0E +:10E620007FCFE8BEC11E41BFA1F4269064481D06FD +:10E6300048F5E58FCA8CDE73875C1DD549DBD7189A +:10E6400082A3E268FE2331E73EA0C7F90603EE830A +:10E650006891D442BD681341BBE9D1D4AC17BDAABF +:10E66000FDB06618D5338430DC35B23B19F528C3CC +:10E67000F83AD09BEA87D1790D2664D18A71BBBC68 +:10E680002368FB6125C9E08F3019993F24D4BF91DD +:10E69000F69F81FD2F81FE6B7AE9DF943649D3BF67 +:10E6A00039A54CD3BFD948FBB713F290E126DEBFA2 +:10E6B00019FD36CB564CC6FE4D2965D8FFA3466AD8 +:10E6C00077A9FB8F0EF5FF8881F6EB3130BBB9C718 +:10E6D000FCD36ED2CE3FA55C3B7F239BFF4A432EEB +:10E6E000EF3F1AE7BF6A450E9B7F4A399BBF89C13E +:10E6F0000DF56F0BE1BF01FAFF692FFD9BD2B3B59A +:10E70000F31F5EA99DBF89F5FF94E176DEBF05FB8F +:10E710007F7AC56D6CFEC32BB17FA3C9ED04FA31BE +:10E720000E89AEF5D1FEC9506A250D0472A1FD40D7 +:10E730003A3A1EFD08771AD2701CDF8B66F47625F4 +:10E740009AD21BF2332FB3C37D947352BBAA9AD3D0 +:10E750007AC5E61C23F03D2C4F2264311FEAA23615 +:10E7600011E99B3C6DF28DA4E3BDD0267A21BFE870 +:10E77000E9293EE0AF352632BF08DA492400DF3F01 +:10E78000FED99817D4F3D2A78B1BE55391FC45DE35 +:10E790005C32BA968EEF0210812A7F9CDA71601883 +:10E7A0007F48ED1E42ED9F1332EBEF236AEF41BE2F +:10E7B00083DA7B6838933AE657F3BADE1F41C75FC6 +:10E7C00044949F0BE7792F6E290A4F62FBF7F85AA2 +:10E7D000C107EB317F790C457E783CC5DE044DBE28 +:10E7E000C6C4EA076F137C2F0808C30DF899C1E16E +:10E7F00011182FCDCFB1B3364777DEB15FB0D17DE1 +:10E80000B466085D8B309C59C4250FA4EDEF5E56AD +:10E810002C836BA75D1086819FB066A14C02683780 +:10E820007B134906270E3ADEFBED0CFE0C977C525B +:10E83000ED479B239B5D45743C738A451CFFAC6987 +:10E84000DAF23FED8C7119C6D274CD53D8CFDD45C5 +:10E85000DAF27BE768F3F7B9B5792A576590AB0F21 +:10E8600094E9BF53B42481DF31F41B00E37C90E3CF +:10E87000E1C15AD9AB59576A761B95727084B809B1 +:10E88000CE0BDB8B3DEBCF5FAECD177BB5F9856B48 +:10E8900074F039DD9CE2EB7F1CE883A6A7813E285B +:10E8A0003E4F72FA08F3552D7DDC139A06A30F65CF +:10E8B0001EA724B604A7D633FA58DC1813991E8A6B +:10E8C00043F4E052D397420FF3383DFC99D34369A8 +:10E8D0009396AEEE23BED5C9B4FD036B77E13A1D26 +:10E8E000118A193DFC40A1870E0D3DB8393DE8D78E +:10E8F0006F1EA787798F307AD0AF6707A7878EA65C +:10E90000CB3249EBB9AE741D3479BA0EBA75B7A3E0 +:10E910001F8AAE47447A58109A379D38CD2FE46548 +:10E920003DD68BD30396A701DA09E209DBA7F7AC42 +:10E930004FF984265FDA1479FD6BDA36AC3DA9FA1B +:10E940005ED5F2F25AB57FBBA2798B26BFC4F7A67B +:10E95000A67E69D32E4D7E71E33B9AFA0BD71CD26B +:10E96000E48BBD7FD4D49FBFBC5353FE60ED594DA3 +:10E97000F903651735F9FBDC7FD3D4BF778EF0132D +:10E9800075FEEEA2A89FA8EBCF9A16A7C9CF700D6F +:10E99000D2D437ECBCF62EA0C783EF8B04F48F4F94 +:10E9A0009DA7D1FFF9A95376429D931E07EE83538D +:10E9B0009ED1989EF138719F9CF34CC2F442DB1EAD +:10E9C0000BC8152A474BE0C8A674E596BA35D9207E +:10E9D000D709CADF8A956FD4798712B21494638AF3 +:10E9E000EFC22623094C204400E1C4C7151455E5A5 +:10E9F0001D7D9437514191D0B3BCB023F2F79A27D3 +:10EA00008B87DB239C7F84F73519027A52772FE7B7 +:10EA100024950229527F276405F281AD5C4FA93409 +:10EA2000327E51B975502EB1413E30AAF6ABFA6B29 +:10EA3000A19B6C20D049BA663F97365DAFE1F704E1 +:10EA4000BCCF89406F1334DF2B9A6FD6B4EBDA2535 +:10EA5000E2B8AB819750B9FD2A297A52043E15D805 +:10EA600093326B0C8CD3F514E6DB12518FECF2343D +:10EA7000AF85F3C7739E164CCF78DA303DE509AC0D +:10EA80008573C0939E03981EF7B463DAE13986E973 +:10EA9000479E0E4C3FF49CC1F44F9E20A6C73C9F5E +:10EAA000617AC4437E02700E7BCC98FEC163C7B40A +:10EAB000DD938CE9058F0FFB51F65D5F747786CB94 +:10EAC000ED73407F11E86CBB78AC6ECDD0309DBD4E +:10EAD000B9F223A43305CF854D264E0F491A7A0883 +:10EAE00080ED7723D04B1FE54D32A7C3DEDA472EEA +:10EAF000AF79E1BF87DEAE7C4B7A0BD3D3101D3DDF +:10EB0000A5F7454F1FAAE9E98AC1CEE420A7A71FB0 +:10EB1000F3736B7DBF51123BA70CE977AEDB0C8022 +:10EB2000AAA5FCDC84906998BFC4FB5E49C1B5A36B +:10EB30001EE81B0D72EBD2E8BF8F8273874BC7E8CC +:10EB4000E2A7F63E3F3D9DF48E7717DA43253EBAA5 +:10EB5000E80911C61BCDF01A6520D3C878421A46C1 +:10EB6000BEE45C90817989C4437B9F734684F33A09 +:10EB700042756BC06F5F785D69BD3216E09D7AF6B5 +:10EB80001F59905EE1FA75F41E11F57C1278D109D7 +:10EB9000F80DC925933319FCF3C191463BEA09648A +:10EBA000BA167FDEDB35F86B4855CECF1B93117F4D +:10EBB00023AE8C1AD40FFCF5C5DFFBC2E70298F731 +:10EBC0007F033EFBE28F7DF145E272BCD646E7DF74 +:10EBD000BD73CCF8C71CC007BF1ADFCA799C7E3C46 +:10EBE000F992F4B5E8B83B49A1E3F614885BD82460 +:10EBF000DA11FEA5D66B62615D4270FA584FE1ED05 +:10EC00003FA780BD7F3E550B2F4B07EFD281176D7D +:10EC100060772D4D5ED87032C23A2869554B5D83BE +:10EC200045AD87B669F3971A85692D382E47ECEC08 +:10EC30003120276A1B18DF5E8EA90267697209F608 +:10EC400073AE393D96D97B3EC60F36C721BF38E734 +:10EC500029C3FAFFECF1F40647190F21ADE484193A +:10EC6000F8312D4BEFBD7EAFF42CFDC588E7DD7E7E +:10EC7000F90AE88966FADF9760771009F30ADC9AE7 +:10EC800016D16BBA01BE6FD6F447DB399433E22F4D +:10EC9000D3BE6ADF48E49442B7545ED483BD80E7B4 +:10ECA0009B4B1AD47A5955CB7735F99AB6471AD473 +:10ECB0007A5C05FC83F25F522B484037959C8CBAF6 +:10ECC00025CB1A818EAF18824F808F08AC5E95B924 +:10ECD000C3E8A69FCEB7B275EB6D7CE73CE65488DF +:10ECE0003B283337E2397259CBB5F92067CEB7AE3E +:10ECF0004C02F95B215EFA5E5184F6BF94042E5FEC +:10ED0000E4A056CFE7F441285CD5BCE9CF12C21786 +:10ED1000CD7719985F460FB78DCB91BEF053BDF9F3 +:10ED200050C1CD8E9E78AA6EBB6874235FA4FFCBC2 +:10ED30000AE349C15FB154D426D171973777A2FF56 +:10ED4000E28CEC1DF583AFE0973DE767493E15A3E4 +:10ED50009A9797B4433F0B26F18E88E3DE0F281F66 +:10ED60003FFB5B99001F225769AD2C74CD70BBC768 +:10ED7000400C5961BB67416B4521E0FBECEBD3D103 +:10ED8000EE5B448A6CB80EA4310BEC9CF3C480712A +:10ED900055E7C91F6C1354EBF0B164E478A65C30FE +:10EDA00089BB3410BE7B10D85FA639F5EDE258F868 +:10EDB0002E297690F025CA15B780F11773D8772FD2 +:10EDC00031D701FD527B4A63AF517B4A93A7F6943A +:10EDD000265F426626413C45C9D332F10988274D5A +:10EDE000F941C98EE32B25B5F5A01FFD9CFBE1166B +:10EDF000D8893484CA87AA379ECB2AA6F3E9929889 +:10EE0000FF4B890F584265C5205A5E5EE633BA2C27 +:10EE10003DE777A275C23D94F3033C160770BFD15E +:10EE2000C7E26B8843CAE2AA4F5AEFF31FD82ABA47 +:10EE3000A26C508F7E57C69BFAF5E7AF9F2F214FEC +:10EE4000E23CCA9B67601C568F78073E1FB9597019 +:10EE5000F922EC27511634F12E0932C39FE2D71A5A +:10EE6000AECB5F0F7995DF6BA2AEFC1BF39701442D +:10EE7000C35F8A25F7703991F113C0BF2005717FF8 +:10EE80007D63F8C93DE05F2FDFF84F843F54BBEF4F +:10EE900029FC89FFD4F18FE831FEBC48F0ABDE7865 +:10EEA000F57588772CFFD5CF6C84EEB7B35263929B +:10EEB00093AE7BE5A6D53617F01DC96B837D71D661 +:10EEC000274E8B440FDF9779DC1F715904F0BBC2CA +:10EED0003F29FC73AFFCF84EB0A3AE6C92EDE84F47 +:10EEE0006D36054C949EAB5B971492B198EF64F924 +:10EEF000472F02FDD7B4C9C7D5745AFECB9F254111 +:10EF00007C10A5942186644803689F546FFCB80068 +:10EF1000F48D1A12C4FDAA6F07FD7F168FF2B0D8C8 +:10EF200018DBB31C1D3449D09EFD6A5A7F7C51B456 +:10EF3000417ADB69E06FD4B244BF90BE5D19B73B44 +:10EF40002A64EB00E4AB13C944E0AB0A5E888FD9B6 +:10EF50001D2B5F7E666C271D57D7C6DFDA0415BEF2 +:10EF6000147BE952CBC25FFCDAD13B1FBF40F7A351 +:10EF70005ABF55E494A38DDB4B7E9656CA011BC441 +:10EF800073556E909D5EFAB9F2D5175F7A16FCD96B +:10EF90007F34394752F815AFEE3B7213CD576C9161 +:10EFA0000714B2695884A4F0FAD4D0FF968F0FAF3B +:10EFB00047F9B67D46C718F6FD87F1E175A9D8B2C5 +:10EFC000CB48C6F4C4475ECB2E638725C2FAB4741F +:10EFD0001680FEB7F2E5BF1A81EF9DDD299081A969 +:10EFE00011F0B9611FEA8780275C4FBE5EA1F5D39F +:10EFF000D5AFA1EB027246BF5EFA7A859CBF005C7A +:10F0000088B3A1F4FDDAAF210EEE4F2627E0A1EC84 +:10F01000B5876C309FD3522DA3F3E7562701BF2B42 +:10F0200093BD49764CD9F7B2E71F46FA2B3DF470F1 +:10F0300012F357BA061950767A07C13C17AFBF1BB7 +:10F04000E75942DC488765CF89453E9A7E2A916917 +:10F050005B22EC934B7C9F9C7E812E2E9DE7694525 +:10F060002EFC41E472E1BBE80F7D98CF856A909851 +:10F07000FFD4CCD6EB806CD0C8D110FD6E7C14E5EB +:10F08000C7B961AE8170EE561396172847C4435333 +:10F0900007B275627207DB51B99307DFA17EBBEC43 +:10F0A0008A1AAB69877246E97F19EF9F8E3B1AF483 +:10F0B000B7D34991ED91E146850F503D434567AA8D +:10F0C000FDCEF6FFC606B6DF95FDEF9B310DCAFFFC +:10F0D0007298ED23680772978E2B3010CB77CD1680 +:10F0E000903F984820D23EDF28F37DAE2DD7D30B3A +:10F0F0001DBF24C4AAE806FA89C77540795FF234B7 +:10F100006DAFE2A335D0AFAD275C651F97727E70FF +:10F110001EF8C1F5617E40D627F62B5EB452F6BDCF +:10F12000F42CEC5FBA5FBD0ED8BF7211CCFF93CD4B +:10F130007B8EDC4FF7ED272DCABED5F255FDBE2DD7 +:10F14000DBFA30C69FEBF7ED27436B49C47D4BBF1D +:10F1500047DCB7433BFE47F8AA82C724A396AF2AF1 +:10F160007CB2377CEAF9E416D98178D5F349FA3BC9 +:10F170004CB27AD2A342870AFD95FF47D570E0478B +:10F18000213A55E83044A70A1DEAE7ADC5A3BEFC05 +:10F1900023F02D527A297A53C6F3954A3F8B03A662 +:10F1A000EDF60FC9447CB950CC91C6FD4306A8F3D7 +:10F1B0003E5DBE4557DFA5CB17E9EABB75F95A4D51 +:10F1C000FDCAB63D46827410D0D41397FF3B393147 +:10F1D0002112DDFA98BFA1F5A211EE39D45882D8D8 +:10F1E0005E5E41BC101F19DC21E2B95137C5713D8B +:10F1F000F83736A7FABC948FAC8E627E856E7BD0D2 +:10F20000164FD3D5712C1F4C34D6031F54BE07A301 +:10F2100098DFB1BB28688B53D95B9D7E11F9788745 +:10F220002FF2BD0D2A6970DD3B7AB9D7A19C8F758D +:10F2300047DBC6627FD1293EA0C7A9A2256539F860 +:10F24000A11A4527E8EC8BEAEEB5C17955B73FFD29 +:10F25000AE39F4FBE27744168EE37549835476D0D9 +:10F2600019E25D972D405CF05AA49F857E66172DAC +:10F270005A1B793F94F37625966546E0BBD40E3948 +:10F28000AE3EEF51E094ADD77DF74FE7FBA611ED11 +:10F29000FFF28DDA7237B79F7F64E4FC671C19C7F1 +:10F2A000ED57E6BFE17C7BAA9871D71CBA3EDD071B +:10F2B0004462A2F94B7E11D7E7D266C107FE37E25E +:10F2C0004DC4FD574D8246F57D882ED85FD7F4CECC +:10F2D000C7BAB6FF39EB074047AF7F30F6DF69DAD0 +:10F2E000F5FA1F47BD05F9378EA67C407AD6CFDBED +:10F2F0001985F102DD3BAD48FFDD3BDE4BF901E452 +:10F30000DF3439619CDD3BFF3A16E8A97B85A90C07 +:10F31000F860F730E6BF5DB9E3AF633B50FEAEC2C5 +:10F32000756C361A999FC9FF8F8FE0DEC2253F9D0D +:10F3300015E8173CAEBEE6D7513E82F0FF9AA5BE57 +:10F340000FF46DE753CDE343BAAD64CE56185F1C9E +:10F350008B7FA8796BF28B75B4FFAAD65DC685B496 +:10F360003CEFEDCFC7621CFD56A6375D903B9E87F4 +:10F37000F8876DC6EFAC94299E2FC026A346F65D94 +:10F38000A63579B08F7AE2E573F4A7F5171FEF1A67 +:10F39000997DFDAF8F0FC1C5F89FD5671660DE7FE1 +:10F3A000FBE803F4839A902E95F97ED25287FA4CAB +:10F3B0005FF33EFBBF860EFA3B6F21D09F799B4DDA +:10F3C000FFDAEBFDB8D181EBA2DF073DE97CC7F79F +:10F3D00030FFAAD589E3ED27BD8F36FD3FB6EE5B42 +:10F3E000E9BADBFA9EF777FEC5E7DDFBBABF338FDC +:10F3F000AFBB1DCE536BDEFE1CC7F775F95CE9FF92 +:10F4000052BA57F4FD7643AD3D938E6F0E69B482C8 +:10F4100062715FE2254BA603A2702F0FC0F83B3844 +:10F420005F8D6057359998BFCD241858BCDADD82BE +:10F43000E247443BEB4EAE5FDC39B40CF5903B5DEC +:10F440003F417D8248B5ED39B47E7BEE4227C66AE6 +:10F4500092F1C7DC909F3D85E7B5F6E6EF04E21236 +:10F46000A87E7F67EEF403A0E7DEE512510FA62920 +:10F47000EABFEFA714B0EF93B4F6D07D6E6DFEDE59 +:10F4800039DAFCDD1CDE3D848DFF9E22C1077E58EB +:10F4900053CE5389E097352D9689900A7146B5ABC6 +:10F4A000C1EEB8BB48DB7E1928672A7FE337C5E386 +:10F4B0006F43785C8A78213922DE03ED138F7CDC80 +:10F4C000EDB3C7F920CE9A484E86C77BAA9CE83791 +:10F4D000E7F6B8CCDBCB9635EDB09F659D1DAED879 +:10F4E000D3BDE19B70FB1CE1A485F12FBB44B4CFDD +:10F4F000659D7DAEACCBD75D0F651DBFEDBA3C07FA +:10F50000EB7263785D865A5C04F6ABCCED877C8B3E +:10F5100093E587161176AEE8C3FAD20017F1668438 +:10F52000E3D197988B2BE09CCC3C5A407FC85D6B15 +:10F5300045940FE60C01C7553449C6F8E38F0D45D5 +:10F5400059B0DE851326567F9F0DC309F85CC2F1C2 +:10F550005E426A517F2557BFFC323B0BCE2508EA3D +:10F56000BF4B5C84DC41EDB8926C21100DF16A1246 +:10F57000F1C68E073FB9408E6BFCE4DA3CFC6E4965 +:10F580000AC3E9AB7E6FFCE59F9DFE17E567C729BF +:10F590009174423A12BB97D476F77C3FC3634DA572 +:10F5A000E04B43BA0BC8EAFBD30566B60FFEEB8708 +:10F5B00013904FE6FC744C2CF30764E27DC41A6E82 +:10F5C000375CF23A62C10F76C99FCECF73F36C6A93 +:10F5D000BEAAA487B81DFE9F109748D3EE7CA15108 +:10F5E000043B8B04D1FFEBCD8FC27BC5FA76A3CC55 +:10F5F00006BEAF6BD12F003F11EEAFF27994D2A6C9 +:10F60000B1F1AA755B7BC759696CCF7580DF71D585 +:10F61000F9DDB7C52FD8FD80D743511D054511E64B +:10F620003B89E3AF70F7DFF0FEEA4C7FAA0C7899D4 +:10F63000992F6ACEF99D66EECF984026C0B80A771A +:10F64000DF669B0CEB724074C27DD51AFF45A33B6D +:10F65000C2F9B11E9F001FFCF027646709E0F3C4E4 +:10F660004FA208D8D5EFF173C90CB8CF9181AE1E67 +:10F6700017F81D73CCCC4FB8CE6CC77456618E9CF6 +:10F6800048FBCD68B58F8350B5C1BCFE3AB303CB00 +:10F6900087F0764ABDC195AC5EA7D15E1D69FEBFFD +:10F6A0008B12F87999F37B93847FBD75CBF9A935DB +:10F6B000900BFA41BEE267D1D335C1FD71699AE082 +:10F6C00003F90DF630E60B05D41FDE53EEAFCF6421 +:10F6D0007256A17B3D9EABCDDAF7021EE7787F889C +:10F6E000D387826705BFFAF12AF529BFBA55ED9F86 +:10F6F000BAAB6DDC6BA0DF54FB05BB8182AA963AE6 +:10F700008CB00F6BDA9E90E17CE63E07834BA4A29F +:10F71000B1EAF8837566160FB267FCCDF3804E2E02 +:10F72000AF35812C24AE45176DC087DF33387F0F8E +:10F73000716CDEDF8964D357F0AB0F3CF6F27C5975 +:10F740000D3715E733AB32470677DA0395BBE48113 +:10F750002A7A5A678EC772E5FBE04A07BE0F42FB62 +:10F76000C371781F3711B84F92D1D28EF76C1FA892 +:10F770008D637458D6B2CB88F954CD7B224A3FFAB8 +:10F78000FD34BB501BAFBC30AF6328E0A5D014588C +:10F79000E68C40A793A39473CAAF29275C946EC7E5 +:10F7A000FE7F2427962972A203E3E395F602DFE7A2 +:10F7B0002A393130929C585AE71808EBB07447FA4E +:10F7C00040D8244BDF999A14494EBCEF61E7CC47EF +:10F7D000F97DF6EED9544EDCA09213B3A3904EF40B +:10F7E000ED3E51F6495F724259B7FFCBFCE67D9082 +:10F7F0001311F6F7173A39718FBF18E5C43DB345B9 +:10F80000CDBDAC4FFB94133949F7615E76C644A079 +:10F810009FF7B97D7394DF0B807E405E6446D911FB +:10F820006F7AB9D11B5FFF537FF9FAFF109E15BEA7 +:10F83000BE94DA3FA6D4487448909E97DE47F9BA42 +:10F8400000F4C8F8FAD207B99F53C7678B80CF6618 +:10F85000AAF92C6B5FED6672A1A62DF599B9B4FCDF +:10F86000FE46D909A2F2FE30DFCD52F3DDCCA85E10 +:10F87000F86E19E3BB97FD13507FEA6D7E7FE6FCBF +:10F8800096F2B311CE08F431676E8CE6DEDE897134 +:10F89000BFC9D806FBE53D11CF793FE67AC0C171FB +:10F8A000BFC9047DFA493E9E797C3D2F7848793E58 +:10F8B000C55FDE22A64F576D16117FD5AD6CFF5781 +:10F8C000370B3E07CD178CFF1B9ED756EC60E7B574 +:10F8D00074068539AAF5AF78AFA31ECE092A36087B +:10F8E00078DE0CF71E009FA51C9F25CE0A3C5729E9 +:10F8F0006DD2FAC11BA26D2F901B101EFAC3AB78FC +:10F90000FD425310CF1D0A7F293837209FD4B6AB54 +:10F910001A71FB59B04F2A9A75DF9D0D78AE0437E6 +:10F92000D441AFAD6AD1967BF8BC178B818C6D1436 +:10F930003EF93DB3F3F478F7E8F153F62DF173880F +:10F94000E227F39F879F25FE5D785EF075F1A2C7E1 +:10F95000475D143F1F184F32613F7E6C70217FF16D +:10F96000BE2BE2BB4E8B9E18A9790FE5A71C2FEF8B +:10F9700019DCF583A05EB580F54AD76FD99744F3BB +:10F98000735BC8383866286DD2CAE390FC6F75A0E7 +:10F990007C9F5BBB4580B8DAC5FCBE6099EF097CF3 +:10F9A0003FE6C1E554DED3FA0BC79BDC705E7E28D0 +:10F9B0002A88FC53A1DF9D40BF946FFAF9384E0CA2 +:10F9C0000EE6A39C6A13ECB82F03514C6ED17582DE +:10F9D000776DF64CFE6B015F17E65F6A63EB584389 +:10F9E000D70DF675819FE75B983EF880FF223BE7D5 +:10F9F000F4EF92D9FB380249407EE744FB5C918FDB +:10FA000070EE9A93A45ADF1D9D8CFE37094EFCE0E0 +:10FA1000A3FFFB36EBDBCBBA2AFA4C7FD757C1D317 +:10FA20004EDD3A1F8A6A2F9C80E7728213DF0BF249 +:10FA3000C7E179D1C946F6FECD41AE1FE9F705D839 +:10FA40001FEAF77866C0C0212E7A5A14C69562BFA5 +:10FA5000694C3F53F329FD3B485F376EA986B4A339 +:10FA60005E168E7F74DF6E06B93F4DD0C449D11942 +:10FA7000E1BEFF27C097A3BE023E4936A37C79C8EA +:10FA8000CEBEEE196624F01EDAE53532D2D1BD06BF +:10FA9000C7916CE02F8FC904F6C7E583371E9D3BE5 +:10FAA00000CA45A48FE2F72654836BA598C5AA9196 +:10FAB000E247985C3AC1FBFF1395D7AE6B7897A0ED +:10FAC000077BE27C70BF74B673D75407F85B320FC4 +:10FAD000AD8673CF5979F62347601D1BD8BB4FC73E +:10FAE000D7E4A19DF6D07705DC67C7E87A019CBB17 +:10FAF00067A71E3942C7F7E09A443CB79CEB4ABC63 +:10FB000007CE31E71E149D0E5A6FE15D560B9C7FA8 +:10FB10004E1F2D12B70A2F0F9276F4EFCCADFDEEEB +:10FB2000DDB04FCAA83C84F79CCAFC87A60E84FCB3 +:10FB30007A01DBD778DD46B8E7D9DE74D19849FB86 +:10FB40002FA1F500DD35EB59BD9A8D02BE1758E2A5 +:10FB50007F02F964C946011FC469A7FAAF99C1F5CC +:10FB60008129D1BE9EB6A7F952680F7037C6DD0352 +:10FB7000E79335749CD87E521D9E5397D076B498E7 +:10FB8000B46FFC2EC25BB25E2070AFB06C52EAE381 +:10FB90009300DE41D909E54777FDDC08E39E47FB8A +:10FBA0001B44E12F143BA6427DF203C18EEF2E15BC +:10FBB0005E8BFBBA9BEF3B621FCDE21404A2DCEF2D +:10FBC00093D4F12A25D169B89F4A96D7D5C3BC3AB8 +:10FBD000BC89A906A4A78B4690E32729BEDD547FE4 +:10FBE0003D616471307BBC278C1D2AFEB9323A1D01 +:10FBF000DB2F6ACB413EB39814613C85BB8EE92371 +:10FC00009DABA37CE057EB94ED29F07DCF6A137E8A +:10FC1000BFF02A933B178675A07FFBF47A99C0BD8D +:10FC2000C795EBD3D7C13A9EDE2C3BE1DC407C8EFE +:10FC3000C51194BECAFC647BD633B8A79B197FCB91 +:10FC40007BEEEE02E0DBA5944F99707E5A3E56E2C1 +:10FC500028473EF55C14E34B7A7EA5E753658D1B80 +:10FC600022CBA1650591E5D0D07AEE378D2C9F6B24 +:10FC70008885E9BBE3C978F06316570D9BD704F478 +:10FC8000FC20BB70D01E78F3D39F81DCADB4E23B87 +:10FC900065D5927D9DC0E88300FF9FEBDFF229ECE4 +:10FCA00087B2B951F80ED929580FD8476B13F01CF9 +:10FCB000BBC4578C7857E2794B9BB4F4AEF821EF74 +:10FCC000738BC4A5965F6531C4A5AA77F447946E7B +:10FCD000693FF3DB041FB0CAA33FEADCFF7026E6EE +:10FCE000ED38AEE55C3F586B45BA3EFAC8C5D54025 +:10FCF000B7F37E2810D0DB89D75D0FF2B0BA497018 +:10FD0000809FB8F487AC7D296D0FE33EFA73465FA0 +:10FD100094CE1DB00FAAD73FB11FEB6F141C00FF8C +:10FD2000E88662D427CABC22C1F28D9D684750790B +:10FD300085F1687BBC6212EC83EA55263BB86215FC +:10FD40007A52E8B393BFA740CCCEB1B3683B67B457 +:10FD500003F9B29E2EC53942489E02FDD47819BDE2 +:10FD600075BE2A3B618BF44D9FEC1EBD427F22D0B5 +:10FD70005F6698FEF6ACCF33023D9EF60918679198 +:10FD800007F40BF4F9B2E29F2116B51ED5177DEAF0 +:10FD9000E9B007FDC1CB58E961FA54E8514F87C774 +:10FDA00025720F8CFBA1D551388FBCFA37EF59CE95 +:10FDB000F6199ECFE5D53F9204FBBA446271400A22 +:10FDC0005EAB241637D6635C4FD71907F5677CBA4C +:10FDD00071CC8A0EC9EDF120B7A93E4A02B49FDF6B +:10FDE0006C7E11E32BCFBFD27927EA376F513A00EF +:10FDF000FC6FB69200DA213EE447E5AD22C66913F6 +:10FE00002990354B65BF2B713115BFB222BECBB7E0 +:10FE10009A7C85B47DF9EB27C6625CC20AA67F7B1B +:10FE20005F11D83988B7632CDC3B2A97587C8E5EEB +:10FE30002FF85D34B3C3BBDE8C99037A9BD0CCDE44 +:10FE4000172C6FB95736A9FCBBFBA265A51E9E9364 +:10FE500079E93AC3FB0A303EF5FB764A5C4ED7CBD4 +:10FE60008CFECADB64D4E7CA9BB75C8078CDF263B2 +:10FE700026B4776B9A2F1AC19ECDFBD5ABEC1DC46F +:10FE8000365113A7D7233EAE590C9820AEABB50A16 +:10FE9000CF7168BE13F32D3C1EED6BC66F55FC6A27 +:10FEA000C7EB5E8AC28A6DBFB4E17B85ED9B6C783F +:10FEB0005FAAF9ABE3557BC4C3B534F078B83B4EC9 +:10FEC00013E48F91E3E1CEC13F28217D16AD8D87EC +:10FED00023CD8CBFD17166457A0F35A477BDFAE981 +:10FEE000F310CFDDB5F593E761DC955F5C7E1EE234 +:10FEF0006CA88268073DA5E695F731FE5569171F86 +:10FF0000C3EDA0977F89F1C317FE687202B40B3B63 +:10FF10004EA780FE7161CBDF92202E78D98EA9E8A2 +:10FF2000DF59B63D0FDFBDEDCD9E05FAF5F5237E19 +:10FF300059BF6E7B5AF7603CD079BAEEC027427148 +:10FF40008E2D552C7ED4C1E31B37478E17EF11CF72 +:10FF5000D83AEBAE29C01F5B999ED0675CE361BACB +:10FF60009E37F4631D37F3F8D5963BBE32AEF13CB5 +:10FF7000FC83AED7B8186D7CE8A7AD8B7FF12C94CD +:10FF8000B526F41AD718E807FE9478F4CFA35DD904 +:10FF90003189B0DEFF81F1A4B07E850EE0D79FA647 +:10FFA00080BFF88C1C44BF44708709EF6B96EF3814 +:10FFB0008AFBE9C2F64318EF4D785CF80512FAB1F6 +:10FFC000F85DEE03AAD96865F1907C1D205ED261D0 +:10FFD000C3EF3C2E92D1B5122FD95B9CE4B298347A +:10FFE000FE3E0B8BE7ACDAF8018F3F0CAF9B30097C +:10FFF000D6ABF32BE350153CD8010F13D571C0914C +:020000021000EC +:10000000E3524371C0BA7583F5043E1E8AF3A5F925 +:10001000A110EFE9138E468A2BBFB081C50F5F9008 +:1000200023DF8F56E2826B6274FBD6D7BF78E0BEC7 +:10003000E6F175F1343FC6A1A11B055F5D5723F3BF +:10004000F72763846F64B785EE9B540AFAFB2C4F45 +:10005000C4C07D99D64E23BE93A2D8557CBE5DDC2C +:10006000DFD6F58A8871A2F52D7B90BFEBF9473575 +:100070003F47D18F77231F6F751B931F5D5BAD3E8D +:100080000B85D3B5FB4DA4EBEACD9D18A7BABF797C +:100090009BB14375FE0CF2C3A71A7FD76BBBC62278 +:1000A0003FE7EFA2E9FBD9CAF9638D3F723F359B69 +:1000B0002F6AFAA9F0B618ED96BEFB3B27B9EE05FC +:1000C00078E7DA991E75AE459CE68BD0FFCF626467 +:1000D0006E5737323F3895A3F83E9C95BD0727DA17 +:1000E000A2512F5B669D740CDE215D6635625CCC8F +:1000F000CA3A1E47F3236732ACF74AEBED04C6BB9E +:100100001AF0ABB2EF65BB9B803E27271765AACFDD +:100110006194F11B0718884FBD8FADD306827D4ACD +:1001200024EF5018C79D697F95402EB67B987F9F1E +:100130005C3D3102BEB74BF67D09146E7BBEE00418 +:10014000D76C4FBA67F0437E0697F61D5DBC5347E8 +:10015000E777C969403DD16A08D86915628D6A4F51 +:100160004603D7411C52125EA5C07889C73CE611F0 +:10017000703FD446A8DA0AF59C92E65D95D849927C +:10018000EE9D15727804A5570BA757C55F6765FFED +:10019000A6703BF0FD96B80C5207E4BBD6EA467D4C +:1001A000E2299B0BEF3FD2DF6888938827D14EF579 +:1001B000BB50B45FCD7D3BDAAF261FE7D2E613A676 +:1001C000492723C99B043E8E02D18278889B6AE02E +:1001D000FAB2AB70645278DC7189C41980F23B2C9E +:1001E000788F806E2FAF7A1E168B76DC747C1A3E69 +:1001F000119BD1E135B0716ABEDB8903DF47A7E30C +:100200003DAE1BAF266FB5707E271109F89DC5DC8A +:100210004E38FE2F69F0BD4A2A8A4F224C64C238FC +:10022000E93021DE2596CF83F6AFA96F07EF01EB0A +:100230005F0B870CB5ABEFB5DEC0E5E0114B518A23 +:1002400085EE93ACE1B518B89D9D2CB84E4EA065D7 +:10025000FE01C89FD296E7615C8AD0C8E86AC45A9A +:1002600082FB664490C755AD8A463DD56426DEA81C +:10027000F1703F8E78E5F1D08B8F9F3F395618286B +:1002800028690DA535DACE1FCC352CA68BD00245BA +:1002900014FE108B6B0CF45F3FC39D6C1807D31BCF +:1002A00056BF7728EEDA6BC16368A81BBAFFC0148B +:1002B0006421F82E08F10EDD0F72B851C953C60E35 +:1002C000EF06344687F22E33E5F78D692C7FF3DA9B +:1002D000A1F5F07E4DA7BDE8660B8CC76CBF0ECFB5 +:1002E000C302F19AF7D57B932FCA38476F0CE4C14C +:1002F000FBC7B707D9FBC523ADA17BFC288F3759B6 +:10030000947C00ED8BA2D643C8D7AA5A0E61B901DE +:10031000F2341D9E10C81B42E779BF654C41F2B50F +:10032000145E6B71323CC1B1D03266BFA4C1C3B898 +:10033000FABDD9613C482B6ED0E1E186AF85878557 +:100340006B6FA887F755FA3B6F4A170B005FD373A3 +:100350000CF88EDBC46316F4BFD05F14CA230E679B +:10036000432FF7BC153B85C22957D397D24EA1AB7B +:10037000DEE8269DD8AF63EF836AE9E7DF2DAE871D +:1003800000DE328B2BDD9688F3C77705A6BB8B8BFF +:10039000F213C2744D2CEE09F0AEFE11CB821F5A3F +:1003A00054FEDAE9394BC5343ADE1F0123B8313C3B +:1003B0009FC4E5DEA851749E892E03C6D51FB1B82F +:1003C00057403BDB9C600062CB2612F704410CF7E0 +:1003D000A3EC8FFA1DCC8EAF2F36F856B0F360FC2D +:1003E000BB1D61FAE8D0D14790D1475B27D247B512 +:1003F000BF93D1475B5D6E343F57033BBA9104C74F +:10040000C1BA37590A0BA461946E6282F54037B2C3 +:10041000F7B682C228C4EB3A185F8FF5E1E352E6E3 +:10042000D5DBFA361E48FB7106D899070D781EA653 +:10043000E04DA9B7C3C2E246FFCDE67E11FAA99905 +:10044000D4B11F966FEB813F605C87EDE0CC5DD04F +:10045000DE369BAE9023DC6FE3C115F84E78237F28 +:10046000D73B9604BD20D77BC707DB3F217C80DECE +:100470009301F8E8C4FDF20ABF6796DD26B840CEC6 +:100480000F8F61EF90BC6E6176F5BB1691A74CAFF4 +:10049000493CB85B04FB2B7B9501EB27429AA19E5C +:1004A000FF2A5E5FD2F8DD957555E88972D218781B +:1004B000CFE4F978F71E2DFDC4C7A4A9E029ED1EED +:1004C000F790A245945026EE5DF010C8554A3F3E85 +:1004D0004DBB317214E02D443F943E23AD0F6D7738 +:1004E00088AD6B7C0CE80B5BF62E15F15D8E7EAE55 +:1004F0006B16BC4749EB67C590DAADB47D562C4D01 +:10050000219FC0F303797E084BD33F741A04FA7D10 +:1005100003F7CB9EE5782592FDBA996320CFF4B816 +:10052000ECE418940BCABE856754E05C5BE2E7DB41 +:1005300069C13403AC9BB28FA5A02160A5422B4DAD +:10054000721820CEE15D8FBB08CE0B7BE33BB75F1B +:10055000CBEE81EABF7FCEC7F38DF5EBBFF4B82FAA +:10056000FE39E0B7CADCF1F84C9AAFBEF632FA6950 +:1005700057C454DFFC55EF68E8C7FFEED5DFC40071 +:100580001DFA3F3345BC3F35CECAE8F180670EB651 +:10059000CBE2EF0492814A1CB22ACE15CAB85E861D +:1005A0004B9986DF51CFBA055920ACA7578A87F6F9 +:1005B00031A978AE78AB2EAE55392FBB25C0FC8063 +:1005C00059B1BE42ECEFFA74F6F7493E63FA9299DC +:1005D000FE0FCEA1A6F27333D731FB5E1087590907 +:1005E0008DF9083F3615FD5A3944FBFE41D640AF20 +:1005F0006480F2F454849767D695A713F45B916BEB +:10060000AEC3F94D252AFD0CE546A313F8F1F4D14C +:1006100094FEF9F7CBF4BFE126327F86CACEB8CD7F +:10062000715F51BE466F69C477857EFBB9383F5212 +:10063000FCC563213C1715413C801E8FB90E6195A6 +:10064000D5D113DF7AFCE9F1ADE0518FB79C0F9D56 +:10065000F9F18E9EF8D1E3237C7EE95B0BEB3075DC +:10066000B488F24BC17B4FFCB0F5FAEDB5B49E00F7 +:10067000F442F10DF84C1730BE272B86D34F6C3A5D +:10068000E2370B14C001480F98D7E3558FC7AC046D +:10069000DE3E81D5DF0FF81A89FC00ED2165DDB261 +:1006A000D26BF7C641DEC4E84CD1ABA772BC50BDDB +:1006B0001AF5E6BC442BFA9B40AF9E9A14C65B5ECB +:1006C000151B57DE48CB0B609FFE0AFCD1B1080614 +:1006D000DFC5BC95F05FE0563C5FCAE25905DFB765 +:1006E0007EA6D593A7FA0BCE82FE3DDCE45E6505BF +:1006F0007F8C1087E77914FFC775F8D7B6B36BF313 +:100700007A7CFC0AFE31B927DE147AABB372FD7C29 +:1007100030190AFAF2D8373363817F137F7C44BFE4 +:10072000C4C4634521389C6E919E05E20E7DB7A737 +:100730007F0B3E76904A49151FBB5372AFB3DED88C +:10074000938F29EB3585AFC714E2DD057EA62944DA +:10075000FA4BC81E480DCFFF792BF7B30D2143602C +:100760009E5F581C8CFFF37986E64DD54BE83F9B86 +:10077000F79F6DB6E0FD1B1294BA42784EC3F79313 +:10078000BCC6F8F0386465BD536A09D3E7E6E2FBFE +:10079000D9142FE4CB98F038B6590509DF0FE2E3FE +:1007A00038DF6CF6429CDBD392FB0D2BF83D848343 +:1007B00063717E526014C83F7DF9E5B6BDD5504ED9 +:1007C000EB95603D3EFE0A91F91F823B4CBE1752ED +:1007D0007BD753E9F64639A1D07136DC7BBD01E801 +:1007E0003E28C2B8FDFC5C65E74576CFC145ECAB61 +:1007F000AEA7F0F65D62F702F228DB817A7AFAEDB5 +:100800008B4EF349701EB4D3D3AB22CF1BF8FD5BE4 +:10081000453FBB6875BF0FEBDEC0EFE3FA2F8EBA22 +:100820000ED6E71BD3D5612D5D29F444E9EB38F4EE +:10083000D39DF9F13A50CBDFCBBC9C04F251D1E30C +:10084000C3FA8AEB63A8D79B3E3FDCE6EEB27E8517 +:100850003EAFE8357DD92364AF4446D371CEE3EB98 +:1008600033D7DC2EB38BC6418CD36F8856DECB7367 +:1008700044833E39AF21ED95663857AC637EF90766 +:100880006B658D3DEC86DBBED89EBD673B7FB9B600 +:10089000FC238AEF41F1F8CEADD68E86FD91147E11 +:1008A000CFB767BF062FC8C97923A3317E4EDFAF0C +:1008B0007E7EFA7EF5FD3570FBAAC1D838DAA9D262 +:1008C0004FEC3616477D69CD93CDF0145E6FF8730B +:1008D0009B87B8D47F6FAEA3217A4EA4F7681478B3 +:1008E0000ABEE7C2CB98E00FA895FF1EE99DDD6C1C +:1008F00037F313F4D6EF88603EEA8386A70322E835 +:10090000F5238204F5F0ECA0CBB050630F307BB937 +:10091000873D00EFA4D07C65EB2E660FB4D4A15DBB +:100920005149ED0A903B1BE01D90C17C401968279E +:1009300084EC5E88AFCA867732B95D0C4FA7A537C5 +:10094000B2FA331F4F37358C00BBD59D0C2F93CE99 +:10095000B45DFBA899DA57F5A9248A50FBAAC8769A +:10096000ED77D64EA2DC3BDE25C0BBA434FFA865E4 +:1009700072FFEDEC99B6D18F82BF81DA67B7D95497 +:10098000766F6FFBE3669B03F1D9DBFEE8B417CD0E +:1009900004388ADF82F221E407FE28BEFFA342F476 +:1009A000170B7853E8E5F6E50BD1CE88BAE66A0A6C +:1009B000C49365733A70DBB85F3686C1A9896170EC +:1009C000264A6E37F4D3BDFBEA28F03BBF3BFA045E +:1009D000DA797E2BF3DB1FF49415A9E3DB6B6D0250 +:1009E000A797C010D87F77DCB82701EC956C59C069 +:1009F000F74EFDB2EFE9F199C09F66DB57D2296649 +:100A00004F36E2FD327F5460C8C32A3DCECFDF4D62 +:100A1000F55FDC3F441DFFDC6ECDABB531F822C085 +:100A2000CFCEDC7B0CF480DEE44E58AEB804902BC5 +:100A3000E4EAA1243C5F6ADD67039F68177FE7E073 +:100A40007CEB9EA40534ADDAF29F36B0E3EA383E83 +:100A5000CE4BEDF85E53E57611DF13A1FD263D0088 +:100A60007EEBD68559ECDE1FBBAFA6C8D5F19FEF54 +:100A70001952C49C8978FF4CD137A798BD3E189F66 +:100A8000BF8EFD1DCC29BAF7C96EE5EF93E9F5CF0E +:100A9000676CB2E22FC3F8A96576D64F6FFB2BFBCC +:100AA000B304E253EDBF6C2920C2F8B33F4BC2EF51 +:100AB000E70FA43D5508F63D919D2301AC44F6A2F5 +:100AC0007ECBCFA7E86F2FBC7BBE9367DE6EBD3CAD +:100AD000EB66246E2AD704D0C7DC0398D391C907EC +:100AE00045FFBBF533ADDF55AF072B7232D73F6EF5 +:100AF000D510027877CCC2FB1307248CF7D2EBC950 +:100B0000538305BDE8C34F207D6D6D4D8F017BFE86 +:100B1000DF609F00DDB65EC6F783AA49E01E78C796 +:100B2000A9BA55B40760FC24F37AD8678A3EA1E0DD +:100B3000A5EDEA1EF358DA7FF645837D0505F176CB +:100B4000F02F68574FF8FDC1049067FEA084E707B7 +:100B5000D917F7C62C54F145FF55037E7FFBEA6E8B +:100B6000EDF760FCF5D06E8B81D9CB7BF7FF3D06AE +:100B7000F8D4DB572F21BC903ED1536F46FD3BCFBD +:100B80002A86FCD16ABD9988D98721DE6B6A2C152B +:100B90006B42EFFA70CE87649595F4D42B42782798 +:100BA0002E09F0D0431F56F0ACD3333EB2713D77DF +:100BB00018190FEF5EB65D4DA8C07BC7FE18FB0A83 +:100BC00094CF4C8FEADE7BEEC9E9F0FDA0C8DE9D34 +:100BD000B82AE27EDABDB36278876ADF524E8AEBCA +:100BE0007665D0C50B6FD1FA57F64533FFBAE4BC32 +:100BF0005E7D4F225CDFC7F11518CCCEE9BC83E1E6 +:100C0000BDA86FACCF74F5B0F7FF61433D39580014 +:100C1000E262D4FA4E23ACFFBFD98A3E67FCA52519 +:100C200006F88B97E40E21B4DFB268920B7415AC12 +:100C30002376B033B61F3018605D3237A5625CCFC3 +:100C40002BFC1C73494BA3315545174BF839D81968 +:100C5000D99B12AFFABE3296F19733FBCA7F8171EE +:100C60001D7F34919111F4D085B14CFE6E337AA77B +:100C70006F867AC70D78DF68EFFE5FEF877793970F +:100C80001C738C03BFE09458B60FDA0EBE520F717E +:100C9000C16D1F82D4A2726663B168A0FDBE451CFF +:100CA000CCAF7798FDBDD6903F94B812609E37C503 +:100CB00032BEFDD60183E6DCEC2DFEBEEFF5B18C35 +:100CC0000FA5C632BFDAD603B9090B70FFB947C406 +:100CD000821FF064473D6C45C50FA8E86F930F6F06 +:100CE0009D3E86FE737297C10ECBED38FC8208F3F1 +:100CF000759C21244E203DF4390A6FAC1ADE5B5DF1 +:100D00000C1E1DC76ED8AF0AFEA904FE7106CDBF2A +:100D1000D52EC5433C98827F651E4AFF8E16E2DAC7 +:100D200060C1ADE4DAFA15FE68E5EF314CB013E5C9 +:100D3000EF33205D6EB7B96E89C5726F0AE4CFECF0 +:100D4000637AD2362E4F4972F170C09FB24EF3795A +:100D5000AA8CA7B7FEEFE7E354D2AF4BD7AFC80ECC +:100D60002FD2CD76164FEEF006CCE91077D6968EC0 +:100D70007F9F4A15977B3F8EFF8CF6FDC2B60E8390 +:100D800001EE8F55EF10E250DDEDA7BE1DA233A995 +:100D900005E9AFED18C17D5CDEFC5DE68FA4729FB6 +:100DA000BFEB86E7EBB07FF839FB2081A693FD1BF4 +:100DB000560E41FC066CB0AFC278A2FB06D2DA46F2 +:100DC00023D0EB92652C2DE5E7D54B9ADCB83F4B51 +:100DD000D6B378C465B1A94C3E737A2586E8C1F8CC +:100DE000DEBA4D7B8FF01F5C7E9E6D7D6A0FF44BEB +:100DF000E9EBFB808F9BDA9E5807C355E8F5EC467C +:100E000019E194456BCFF33DB1CCCFB8FD30A3F7DA +:100E1000C91BE55C784F6CB297D8C1BFFDD6C64DF3 +:100E200022F0EFB7809E53D93E07797B66DF6331AE +:100E3000DF07F9D66920E047DF6624655B54FB6273 +:100E4000EF863734FBB7BCB96E3AFAEB3BE205E00C +:100E5000F3CABE55F0BECDE8BC0DF7FF9DBAFD9FAD +:100E6000CFDAB7C2BAD07A4FF1FDFFD434BAFFE976 +:100E7000A7B88D7102C0D9668CFCCEDC4BDF90FE2A +:100E8000427CB5A3075F7D2996F91F6CE9B4FFEAA0 +:100E90003B2EA1FF21343E4E374FE52B74932A00A1 +:100EA000FE1BE90A8E007C51BC023D533D7AFECC0C +:100EB0000CDC9507243CFFE1E74B3C2E0477946A59 +:100EC000BF86F999B26FDD6FC038B2F26B57829E60 +:100ED0009F50E845FA3C2BB887C753797616F671D0 +:100EE000047EB08EE3E38AECEEEB7DFFC140CF657C +:100EF000D46284F990F5821DD6452977AC67EFBDA1 +:100F00001EE6F094EF87BF2DBE833DDE213DCCF081 +:100F10001D34425CEB281F936344C8C5FD400CB7E9 +:100F20000F867DB684CAAFFB55F2EBACDC8874AAA1 +:100F3000E0E123CEB7AEC4B1793FCEC7E9071F5D6C +:100F4000A20AFF8224096C3F8B02DBE722C03FBB71 +:100F5000EFA6DB90DEEF884CEF76B0B7E2E1EF472B +:100F60006D40FA8C9B66C77B2F4F49CEA8388D7E8B +:100F7000E4C374EFA667D0CE03FA85FDDE1BFD97B0 +:100F800001FD930874EFA374AF5A3F850E285DFCF2 +:100F90001DF0A57CD7D385720EA9E0659BEE1C736E +:100FA000AA9DE1E9FF00528D6EB5008000000000AF +:100FB0001F8B08000000000000FFBD7D097C54D598 +:100FC000D5F87DF366C93233994C76B230490CA01E +:100FD0002C0E4980B0D84E08204A88C352D7A0931F +:100FE00000094B36109556948120068B18152DB6A6 +:100FF000208385EF431B6D10A858832610112D62A6 +:10100000DCB17FA54190454122A81FED87F53BE764 +:10101000DC7B33336F26026AFFE1C7EFE6DE77DF62 +:101020005DCE7ECF39F7C56ED3313684310763AEDE +:10103000E6018C7D8F3FBFF4978C2DA1E77337CFEE +:101040005E712482D1CFF7F0BFBA795E50BD76C70A +:10105000AF571CE9E7AFCFC55F52E0FF71A66789C4 +:101060008C55F147AC4CEF89B525C0FB119DD66C72 +:1010700098B466E2196384039F781983F66F631C42 +:10108000543EAA6FDED32B1FCA31CCE985A6399B0B +:1010900033158F99B105361BAD67F927D393DDB0B2 +:1010A000DE46C6C6E3BA9BC57C72DDD93685C699D5 +:1010B000E029738F898367664F9E7BA0FFF90766DF +:1010C0004F966D88BF3EA170BEEA18404B8CC47E1F +:1010D0006355980CE69FBFC9E4336532B6059FC4DB +:1010E000C32ADBA37C9B32FDEFD9F4CCA5B73396A2 +:1010F0006BCBA475C1EA5AB1EE58686497C1BCDFE6 +:101100006696B59BE1D1D51DDEE281B08F2D46EF0D +:10111000D489993898F31A1CFF9A629DED01586A98 +:10112000ACCBA63807D092695EB68FCF9397EDEC23 +:10113000CFB2A1EE70E6B92D8C8D12F862AD30C938 +:10114000703F1C42F1C6E1D9135E17207C86501710 +:101150007A7EE2D5A81B7D66FFF34401BF2F63783A +:10116000F9ADC1D3DB660E1D27603E554966CCCA7A +:101170003C4B555CFF2866DBE4F03F778C622E1C0D +:101180007F9A1857B6CBFA8FA6AFAE10FA9A867828 +:10119000AD8EE822BAEA53D06974C0BC4C19DD8B1D +:1011A000C1FA98EEDA5EAC80BAEA71BD0048552902 +:1011B000E0EBC7F6848D33D7239ED90113CBC90C3E +:1011C000DD67B5CDC0E1B6D130FA66E897E065B825 +:1011D00003C08B83E38535DE8AF86BDC686288D7D1 +:1011E0006F6339DCAC53D96803F4B7427F24F7C688 +:1011F000A99E035741BD31D9E850609E13862EC287 +:10120000FB89ABA08DE8C3AD20BE4FBC3AE29ADFAC +:1012100040BB77A28EE5C08B5B8DB005A4C3BFA792 +:10122000F9362948A72DC427F3C7B2C12678DEBEF8 +:101230006918D1D5ACE22C05E976CEE658059FDBDE +:10124000C7D8742AF3EF63D84295E813F8A0DE16E6 +:10125000808F61DE3A15E1D53BCE936C8865EC1149 +:10126000DB35E323D281CE3259241BCCD843505FE7 +:1012700009706BB4BB14164BF506730AF121632396 +:1012800008AEAD0CF0D418D55D774560FF2C5E7FBD +:10129000A4F1EA868634C69E897135229E3E30BB13 +:1012A0001FC1F98726D5A944E782AE7F80CE7E1282 +:1012B000BDD42E2C6287F3E0F70E660EA41B904778 +:1012C000B76E06F895E83D9B705D35BD8E3E8EC3CA +:1012D000D5B67C65F484A17BB98E782117D8C78CEC +:1012E000F011EFAE53CBCD7EB9B3C566174CED52BE +:1012F000265BFCFC8672EB7933973B59509A229817 +:10130000D762C77E3EA223ACC7E4FAE5D1CA62DD4C +:10131000785F183E7E0D89EB6794CFACE57FFFF2D6 +:101320009BA1D01F7F57899F5EE3FCC4E5F5A3C551 +:101330009F26223C9093F0BDDBC51CEB973ADFEA79 +:101340008B74B95F659BA03ED864F42A31B86DE612 +:10135000B0258AF1900D5B9456CB20A8FF4B612EEF +:10136000C0C3E97FA954AEBFD73D3E13DEAFD9A1BC +:10137000732E857E352D0AF183B337F345001D3773 +:101380004759073118AF70B7D96580F6D34A04C9F9 +:10139000659C00D76190EB2FE8CA6882E7F52DC005 +:1013A0007F503D5D08A8C6F5EA9D316C801FBE8365 +:1013B000DE7CB41FEC00DA1B9DC8674F45F2F19F3D +:1013C0008ACCF081108352BEE788014A6159826E4F +:1013D000F47AC662004F5078B11CB530DBA5073CEB +:1013E0002B7AE63500BE4675B5AA089FAC2E878ECF +:1013F00099FDF3E9BB18ED3B4BEFD03903F4D5D69B +:10140000BDCFAB7A80EBD0318DF52A9489319E6FB8 +:1014100010DE2346D5D5637B5CB157F540FF7CA534 +:101420006EB705E9EC1AE644B92AF924AE93B5C1C2 +:101430007259EC814E9715DA471C77B50D80FDC7C0 +:10144000B89982E349FD0D7CC662910EE35DCA4402 +:101450001867E83F18C1478EB375EF6805F93EBEBF +:10146000638CE218104AE76B98E3B738AE779FCEEB +:1014700089F8753433D70694137FBA620CC24BF6E1 +:10148000EF1DCBF5CA488FA7084415EE2706E71DC8 +:101490007EA36FB701D6336C9677B7D111B09FD9C1 +:1014A0008CC64BEDF4D23E520E780AB1CCB6C6D201 +:1014B00038238EB7B60D807E4975B01F684FEF7820 +:1014C0004F41B8A6D7752888CFAD7B77D17AD33A6C +:1014D000DA7929F8EB79611774DB03561DED23DB0C +:1014E000CAF5CDF2535C6F66C77AB2AD09FE7D2CAA +:1014F0002FF424D7C1F86BF66675EF17E5EE952843 +:10150000E403E4526EAC91C6B9CBEAE98FFBABBD04 +:10151000B1730FD2E0F37BDFB1127FB4C4137E133B +:10152000F77D4AF8485C48BA98ADD9375F4179B140 +:10153000A61470A684C259CA8D35B87EA21F5BF46A +:1015400024A0CF27ED9E82D8407BA5CC1E9D1520E0 +:1015500097E47B8F2F66EE19B09061EDE55B59162D +:10156000C9F77EB101F27DC2C0FB22919E9A2C2E5A +:1015700017B69F56D88D38CF335842FB33065E9747 +:10158000F07A40E0333B7652B6750887930DE8F861 +:101590009948DE4F2B8FEE8DD509BB83D30BEBE043 +:1015A000F482FB08B4BF66C6723C8C74798AF49CE2 +:1015B0004EA6E2FE8617F87623DD0E1BEFDD8DF4D6 +:1015C0009FCE049D8CE774A2A5F7DB63B97C1D71E7 +:1015D000BC8B21DCF315E60E67EF54C672BB29BE47 +:1015E0006334D10FF04319CE3734B54E35A0DC66E5 +:1015F000B609A87F7E13EBA07E7905AEDD486F3675 +:10160000979BF879BED9C6E92693D307BC3F271C20 +:101610003F6D433E1AE0E7A378A44773283DDE26DA +:10162000E0F41B01DFD0F13D77E1F8F11D3A9702BC +:10163000830C3B60F631E83A6C01E849E45306F468 +:101640000F0BB4CFB215229FA5563915C4EB02B3C8 +:10165000FB1EDCD772948DF948CF3A5F3DBC976C86 +:101660007311FE7EB49E6867116C68909DF5402CE6 +:10167000B7E35795A1BC7EFA5B23CA5387E4BFBD8D +:10168000B9D1E501F4F1C7507C3F120EDF5A39A7FA +:10169000C5B75F2E04CB3980D75A8E0F6EE7C77758 +:1016A0002C50B97C08966B3DE123443E083CFCC1BC +:1016B000ECDA84EBCCC64540E91DCDFA617B4FFAEC +:1016C000F8C558F34FB3672FAC8F5F8C4D08D5C763 +:1016D000BA88AED7158047758BEA50610BF58BEC55 +:1016E0002EC4FFFA66C58976E1EE1695E861FDF233 +:1016F00028D29B72BD5F6E8F19C4AE8452F03F6BCF +:101700008F257D5A1B2BE65F06BFC0FCA76DBCBAB8 +:10171000DDE6793D500EAD6FF92612E1DC3F5971DF +:101720001D41BB4AAB8F81851478DF84BF2908D760 +:10173000C10D2A32D6F59EAD2695F0F62E8E378C49 +:1017400075BE330AD6F5A7A6D1BA407BEBEC8EAFB7 +:101750006FDD05EBAF8DE6FAB9369AEBE7D3BBCE7A +:10176000F7417ABB76E174927BC3F49E8F03E5DC8C +:101770001BFD0E7339CC4A6D47FBE3D42EE5FB68A5 +:1017800000A135A29F1EED0A35CAA906DB15441C2F +:10179000F539001F845F5B14C1AF3E07F82E93D666 +:1017A0007902D7D96E31B214683F0BFC88FDE4BAD8 +:1017B0007FC47ACF845F6F9AED68B4A00BD5BFBEAB +:1017C0006EBC201E607CD5A2A77D9C66514EC4676E +:1017D000B3D1C510FFDE83C23E1078AB113477BAA7 +:1017E00065C8010FEC6FFD813427BE7F7AC7D948E9 +:1017F0009D19ED478F6A877DA9E95D56D487BB5B4C +:10180000CE5EDE3980E49BC10EEB3BBBEFB0DD3337 +:10181000E047EDCF6ABF88FDD5EACD0D817622AADB +:101820005952941A3A525ADAFEA90C22FE63280F32 +:10183000BD19CC570FFB5E3E50D0D354E640BED707 +:10184000E27BBBCD9D610FE0DBCD36B703D785F3DF +:10185000A4E6D23EB3B03EE8CDE979061DEE6F0CAA +:1018600043BD29ED3DB94FB4C72373FDFB93F65E2D +:10187000F7FE73CE0FDAC768DF83EC740E742CC5E5 +:10188000735A2D2885073203F7DF4A78A916FBAC77 +:101890008E30B7AAB02FB6CD70B253CA83ACD07D0C +:1018A000009E86F37D380F7810CF7F373BEB114ECB +:1018B000FA0E1BDAAFB0AF91B80F5650968C70F895 +:1018C000C0EC9A8CF2FE99258CE8FAF4B3CCF714AC +:1018D0006C7A4BBB8EE86603BB82E8FF0ADD995B3E +:1018E000DD66E2EBB1F87E7E47A30EE56F8ECFA1F9 +:1018F00043B97A7947B34E47F4E0192FE074560F95 +:10190000EBEBDF54A7FE48BA98149E2E42F0F6ABDC +:1019100040BC49B88D12F4300AE18632B94B7FB22F +:1019200033C20F37C00B4BB5878EC7586706C2A9A5 +:10193000EDC5637D3A61BC9A978FDD8A70A9F9ABDA +:10194000898861CC5F2F8F41BAFFB230BC5D737262 +:10195000719D5B0FC478AB3D8BE47B15EB30A2BD72 +:101960000072DDAD0F90EBD28EDB67E828C6F1F791 +:101970000D51D91280F359E7B02416465FC8723F63 +:10198000DA6D39007FF455E1F9E4C5FC186E47DAE9 +:1019900083FC5AB2DCB778967B8CA1E7F1F60D8E0A +:1019A000247F4EB1C61E7AC8CEED8DA7ED5CCF81E7 +:1019B0006076E13A4FFDC5E2F342D3A9DCF7AD0C06 +:1019C000E0746ADBBB795EA0A353ACE3F69790DFCB +:1019D000BE36D3B9AE78F0FB794B2C7EFEBC8AFBC9 +:1019E00052D8552FBC697540FFE22DBBE3BD01F015 +:1019F000BB8AE9BFEEA6EB4C9C97EF8FE93BFB203F +:101A00003ED84B27121D5016BFF86A3CA703383743 +:101A10000D45FF14E78F3F635380DD5DBCB0C63DCD +:101A2000262FC01F732E92F902EBFA0E231E89ABEC +:101A3000CF99A9FD76BB259EE44D2FD60BE54D8FA2 +:101A4000F0BA48786ADB253CF70D3E9181F6C597E0 +:101A50003DD8C507ECC17EAF37167BDC6372FCF561 +:101A6000BF7DA7DEE60EF35E8B18FFAC737812DA4B +:101A70007DC5C6D6CBC2F9E1E439530BA737CE57A3 +:101A800046E3B87F39671A1F6E5DDBEDBA9FE63F0C +:101A9000D807AB0AB00B4BF49E37EDDC5FB06A326F +:101AA000D46B2E3F3B8ECED9925E84DCBB8A79DB31 +:101AB000907FB5F421F1FDBEC45B2A4B45BC3D6966 +:101AC0007770BA11FC20F9430B476D39C1C83CE16E +:101AD000CE03CF75C3359279411EDEBEC1407AFE7A +:101AE000CDF31F4ECD037A3FB6D6605B0A53CE5A74 +:101AF000B73BED51F4A70D36D914A81F73B45E8619 +:101B00007C5FB94E75233D1C5B7B7BE27428BF0074 +:101B1000FEAD8275546E3050FBAC0D7750FB09C1A1 +:101B2000D795EB12FAA3BC7CB3FD8144C4E3ACEFC0 +:101B3000EEBF1EF1B2C568EB3F18CAAA26C53D2606 +:101B400000DE73364606D5B7E8D82CDC87C42B53A5 +:101B50003CDDCF1DB01E63DC4FC4636B881FD518FE +:101B6000C7EDCC9229B0EF9A2167C9BEDFBD278AA5 +:101B7000F4C92B6695ECC8D6C1FFF3B72BA15EF470 +:101B80009DDE49369EC0F358816786CE40A08F8A7D +:101B9000085E2F7A514F766891452578B7825C1D93 +:101BA000434ADE651E0BFD7E21DF5347AD1E0EFD51 +:101BB000C6C61818EAA15FB4CE2966A0277F794E61 +:101BC000FF6967C07E4633971EEDE24266086A5F92 +:101BD00011657D0AED5A184C8FFAB02822F8F9D811 +:101BE000CBAE3D81F6C4585B70BBA4BF9C38A0BF90 +:101BF000FE7EB9B17BCFE78F4C807D56EC53C99EFA +:101C0000BE905CDE8FFBCA417CBF51DA04EFBD2978 +:101C1000A0F3E6F963CB5290BE0A14867EAE63E76A +:101C2000C3F3E55C419F8C019EFBF9F13CD139BBCC +:101C3000BB8E6C7F5DC1BCEE3AAEFFE2E5D90FCB47 +:101C4000AB4E3BF76F68F587967FFE53FAA378F0AB +:101C5000AB195E0B95FF85E5C92D5CFE6AE58556DF +:101C60005FC87569D75B7D4E0DD213CF0979E2D776 +:101C700017467AFE339E8F6BE286849E8FC19E212B +:101C8000787987EAE95C0E76D7EDD86F80D911575D +:101C9000084B5A66CB8A46B9D664F1DC1917E0972F +:101CA000EADFD4A843F9D1EDAF3104FB6DE4F9F5D7 +:101CB0009E38BEFFF2385E87F32B9DFB3744799246 +:101CC000F5386F2FA333307E25CBFB85FC9076AFA4 +:101CD000B477A59D2BED597D03B767B363DD417ED6 +:101CE00033D6AF5F903F18ED74E473EFAE28DAE7B8 +:101CF000678A7B10F26915733D1417A007EB0D7C02 +:101D0000FDDAF5BC1627EC13E6263B41B6CF1C1DC9 +:101D10005E9E6F8DD353FFC2C76FCA403BEEB3B612 +:101D20009B3350CE7EA6F1FFF6C40F0F0B7E7D5085 +:101D3000E89358E1277808F908EAC0EDAE2DF0FEE7 +:101D40008AC56EE2ABDF2EBE91CA47172FA4E78F7C +:101D5000C565D2FCB6C277DCD900A7232B55D217B4 +:101D6000338DEE3EB1F0DE91081DF91B0ED799C7F9 +:101D70006F33633BA3F3E5CCC7276CF206F8011F72 +:101D8000C37D0CE9799FAF09BC5E2A9D56B34E2BEB +:101D9000EAAD6E7A3D10A2B7DB112FA7596722F684 +:101DA000AB553AFA3429A1F33FC85CAF61BF662353 +:101DB000EB8F7CD31CC5F592B6DF9B027FABD09E28 +:101DC00085F233D45F61E4CC3B825E7B5B5DEFC424 +:101DD00091BC3393DD4EEB56294EF43ECE07E7B46B +:101DE0000FF139C689D05F976DB575C755F879C7BA +:101DF000FD715C187F5C4FFE1FED3AEE89E770D5F0 +:101E0000FA856429FD42C7C47E16C5D982FC44E820 +:101E10000F0FE70FBA3ADE48FBDB10D5E9C5B8A8CB +:101E2000F7667E3E4F1AE555D0DF955ADC5888FE9E +:101E3000B07FC6713FA67DBC2719CFF1BD928D4EF4 +:101E4000F4E35C2C3F0E6876F138814747EB58D3BA +:101E5000E18DEC03EB4AECF0141AA134C426D2F85D +:101E600049AC6E09E20DFA1130F2DBA37C8A3C74B6 +:101E700043973C214761A591C877DBAD1E533CBC1D +:101E80003774465D3DFAED53AB783CE284E2E96D90 +:101E9000CF0E8D1BCB32395EF0AF88BBE66F34D0EE +:101EA000BAF2373E46F1D1FC8D57EB950039941FBD +:101EB0006FA0FE275E9DD39BFC181F858FBF0E88E9 +:101EC000E7F462461FE1108A8786A5BF7EF13F31A5 +:101ED000AEDC09F650B03CEF173F24206FA1FA0C9E +:101EE000C9737D3CD7237FC07C0558D31F66C87C4F +:101EF000850DE48FDD6A6CBE06E351DE1A1D43BC1E +:101F0000B7EFF92BC56B67CD7050BCB6FBFD7DCF2D +:101F10002CC7F63FCC628311FE29BE8715F4CF7C17 +:101F20001BC9E3C9DF6E32B125B0A5D96F37533C69 +:101F3000784D958EA17CD1EE1B6632E8785CDBA0F3 +:101F40002BE0F8473928F10E0464447C48BC21FC9E +:101F5000B698316EFC02AD5FAECB807EF004DCC77C +:101F6000966B904E7A55D915F417C8755D489F4CFD +:101F70008AFF69FAE467D4C3B7C55F9C1E9E81746B +:101F8000AED5C35AFDDB64715562BF0BE9E1134264 +:101F9000FE4D89D7C443307E16066FC7841C0CF0F3 +:101FA0008FDF19FF23FCE31FA11C09E31F7FC6C8B5 +:101FB000E56FA39DDD36290CBFBC27E6D7ADEE3219 +:101FC000A2FE8C6F51C2CAB36CAB51C61357E0FA74 +:101FD00064FC442B8FC3C0B711FB5FDED4BA0B7B0C +:101FE000E5C65E168DE6DB15DFC3B937CC3C6B0466 +:101FF0009F3B16308AA33AEA18C92BA8FBB893B0C6 +:1020000095F223001F4FE0B8178A639DB615921D05 +:1020100024E35686D8E0F3F89E78D9CFF547C46F0D +:102020007A0F7AE24F625DB0FF67B05FFC02161470 +:102030009F917199F83AAF62CC4775C4C8DFDA3B1B +:10204000CEB304F33FBA8633E753508F29B515A2B8 +:102050003CB5CF72B661FC66F929EE9F5F3E8FF901 +:10206000962A0179059E2CCA0342BC05FA07760A16 +:10207000F9B653AC1BF4E45FE3F9BA5AE203F4A4F3 +:10208000C4876E75AB4A78ED0AAFA702F0DAFE435B +:1020900078FD19F9F29D8BE4CB0F2F856EFE7191BF +:1020A00074F34B8C6F0C093BDF678857ED7C4067FE +:1020B0004783F8BE073ADB7889F1D2F9E69FA8A7F3 +:1020C00042E1FA5D7C42285C5716EBFA91BC6651FE +:1020D000CE707AD59660FE4FE791D812865C7A1E54 +:1020E000C9FA7B3B8D8867190791EBD5E68FC8F657 +:1020F0009A16250FCF9F85BBCFD339E074DBBFE89D +:102100001C109A07C2E79D0FE48DFC39561DD0DCE8 +:102110000AFC77A6C948277595397E370AFDF77BF3 +:102120000DCCE7A0FE11D8FF0AC6FB5FD1B4BC03FB +:10213000FD575730BD579C4795EFB91D15837C7CE3 +:10214000C55E95F2BFD866FEBC8E452C41FF744C2F +:10215000818E3902E019EB8A628E0078C68DB7074E +:10216000D5E53979AE9837C1DD2BE8FDA41BB382E4 +:10217000FAA778AE087A9E3A2B37A89E5E3722A837 +:102180007FEF85A383EA99DE6B83FA67374C0EAA4B +:10219000E734DE1CD4FF18AB7B7C14ECB33FFA5B56 +:1021A000003FCCEBEAB80CD63B43ACB7EF9AF2A0B9 +:1021B000F781FD5A311E385390C917CF8DDFAB0020 +:1021C0001C6708FFCEE5BE3941E3CF55AB887E677B +:1021D000361A8E04FA69F4AC6B4F2AC0B9C6A73818 +:1021E0005BA15EB926F8F9EC1D1BE8BDD9BEE0F68F +:1021F000B99B83EB83DE9CD29FE701B929BF72466E +:1022000042B0DF8785D08999E4F499B5DCFFA57ADF +:10221000FB6AE824185FEC27D28D43D08D293998CA +:102220006E221DC17453F9FAD6A108072DFCA3FB39 +:1022300069E8C90BFF7E00FE1667307D69E14EFB41 +:10224000837556EC50D8EF9550B8CF6A7978792AD3 +:102250000B853B633E23D71FC1ED8F68E0FD81D91D +:10226000F318CA89B33B16A8188763E3793CFFECDF +:102270008EAF07ED7384892FE584C497D62504F8C3 +:102280007F647CE934C619AF64171167DCFD4F84A5 +:1022900007C8008F01F3110B9C11DD71C5487F3C0D +:1022A000492B3F6509FAE3B904D22BFE786C3DBC9B +:1022B0003D34E60337AE53C6E564BE8ECC2B0A939D +:1022C0009FFC978404CC0FB447E3F9754BFB7C3A31 +:1022D00077C9BC2226F202C3D8FFA44F9AF1D714C3 +:1022E000B20B762670BDFE0A8ED76D1788BC2FA95B +:1022F000D77B1A47C6DF7A2A955D2AC513BB942877 +:10230000E75361F4CA47093F51BF85E68F7F14A8A0 +:10231000476AEE38BB07F50BC0FD636CB758406FDA +:102320002B7EBDFDBB682BD16BD7EBAAAF2F349CA6 +:102330008970C4D8018E2D22DFAF45E4FBC9F5D6E4 +:1023400045A4BAF479D81E9CFF27E38ADAFD8DC232 +:10235000FE71FE3ABC1764972CCFE576DB690187E6 +:102360000D166E271813B99D50AB391FD53670FB6B +:102370000CA4D7AC9680718C8916EADFDF5C684CC0 +:10238000C47184DF6579A64276C57245217BE47706 +:10239000B6D1F4FCCF09858644E8FF6F31AF1160F8 +:1023A000886563165F8F439317FE92E8FF52C268F9 +:1023B0002A8D8936E17FB65D81F4916A7619A95D2F +:1023C0000D1FA78A4EE4FB1A29F264B47180714292 +:1023D0006EA2DFDFC4EDD2E2B18941FEFEF78CF1DF +:1023E000C2DFAFD0EB2E9453BF1478EFC9FFEFEAF2 +:1023F000676B47F1ADF5FFAF8CE4FE7F191F08F165 +:10240000FF3BC785F5FF231EA2ED7EFEE993D82D85 +:102410009FD2503EED307AEAF1FCD5B51DEC7868DC +:10242000EEE7EBA4B8C0C07DD94E3C672DCF64BBAE +:102430002C486F4B18433B7F47A76E69243C5FE9EC +:1024400065367C3E7C2D3FBF55AE7138719B520E78 +:102450005C9DC8FD8706381F5B72F1BDC96D1827EA +:10246000583995D9510D35B2C6222BDA456B59D85A +:10247000F3E368414F130A7751FE764217CFB70F47 +:10248000EDA793767E21E2735897E72C8FCF717971 +:10249000422211CFA9ED3A5FB8737DB2ADE86AA4CC +:1024A000AF81BEF0E78891C24FE632BB27E2F80366 +:1024B000B7F17CD84A297F67E8981EF03E45E07561 +:1024C000CA5A9ED7C1CE7FFFBD2AED4546E333945D +:1024D0002B95532D3EF41355B6647A695D6EC599FC +:1024E00083F2A2E56D37D62BF3F36DE89770FD9D6F +:1024F0002947FB91A9C9B8FCD2B3A3529E901E8F65 +:10250000A738D464416F23F1B09C40727E6534C01B +:10251000BB72ED925D98D7F3FE1F19C59B0EA85DA7 +:102520004371B05F017016E662A967A5E4B748A6DB +:1025300071A68A71BCFF827923FCF3FEAAE575DAE5 +:10254000CF0103F346001D9DDE798303EDEEE5091F +:1025500011E4CF9371DA83AAE73E5242FAAE1A5CD5 +:10256000DA4D2DD136F4839CDEF9613AC64D3EB981 +:10257000E7AC05EDD87FE8BB2C982F7C7CD1BB164F +:1025800017C0F193452AE59DDD2AF48684FB7D89F9 +:102590001CEE1F27BA1721DC6F5BFCDDD0C03C2A84 +:1025A000B63081E879B64FA5905CB79CDD1C8D16DE +:1025B0004A77BDBA392EA82EF540B589D5853BBFDF +:1025C000BC24E86976D30663AA03E7F7AC42FA387D +:1025D000AEE774747C9BC5E7CDF4AFA7BC69B011BE +:1025E000ED837FB498582BEA337D8781E749BB8A16 +:1025F00015A00B8FC0BF769D7B5E8EA6F1663EC692 +:10260000E54719CCB510E0EB69994D7241BB8F9944 +:102610009F38C625015C67AE5018FAE3B0FF22C0B0 +:102620009F67E1FD5FA1FDA5DD679937580E48F969 +:102630005529F03CBD21F87965CB6F699C19CC43D5 +:1026400079206027699E5F730CF50AD84741ED67D2 +:10265000F6669B518F6F4914F1EDA16CD8F7F0FE2F +:10266000AE88EC184F187E92E5C9C53622D6CF1732 +:102670004750797C31A3725122A7E3AA96B7EF4461 +:102680007BA966C716238E73C9F1819613D69B99D1 +:102690005FEF96E83DAF211ED92C25284E50B3E1BF +:1026A000AC91EC32019F52D15E8AF0003CDCC21C3E +:1026B000ABF13C505A65F0C7E9E0FF5B72BFC36005 +:1026C000BF80DAD1913917B55FB94FB96FF9BC5AEC +:1026D000057A0CF3BEE48345421FCDD83869792FC3 +:1026E0000051FDCE63199DFCBC49F67891C06B5139 +:1026F000C4FD648F1785D8E3EC3DDCB7A4C74AE678 +:10270000243DA2A53B4907CC6CA0F72384BDDE4D38 +:102710006F2D0F125C243DCC5C5D68E4E69BC7C85E +:10272000ED4A6FB2F0D726A3BF16E830C83E06BA0E +:102730000BAA6BEDF12F0D9D19281FB476B8CCE7CD +:10274000D4C2E76022CF5F9AE1708DB30DC0738071 +:102750007B39F985F146CA10E4DBC63D7723DF6E8D +:10276000E47CF30F410FB3923C1149F0DCB3F49ACF +:102770001AC47FE7125306F2B367698A1A0FFD3D48 +:10278000AB1492C3A397A61811CED3970D1E877CC6 +:102790009DCB5C34FEB43816D66E189CC4E54779E0 +:1027A0009D811963082946F40B9F6A50C82F8C9AA3 +:1027B0006422E06B96C057F58AB7ADA4AF1CF06FEA +:1027C000285E1FE03FB3EA2A091F70EE08CBC7520C +:1027D000AF54B166630A8C3B67651BD1319C47825D +:1027E000FAD7B29584AFEA664D7BDDD5843FD8B980 +:1027F00011CF89B53B829FF74F127682933991BEF4 +:102800003D775A2230AF71B4804FD94AC586726B7A +:10281000FAB2B6841BA03E7DAFEA84ED74C387850F +:10282000FA23281FEDCCDE1CF2579C713892B09F22 +:10283000C7CAED5245EF1986EDD3E23CC3D0CFD8DD +:10284000F59185617EDFA1732A73E411950FA2FCD7 +:102850002A1B1B3429C0BE2F33D812311EE965F361 +:1028600093C53DB88840F8D446AC247EA8457E8800 +:10287000F0F3C3348C7BA1DDF3A24279846C473042 +:10288000BD9F703426C29190B9EF33909C2E6F8A11 +:10289000A5F371F9B22223EAD5F26DB1641FC1F933 +:1028A000F4BDCB86FAF1796859DE9E6418B7BC395D +:1028B000D3A906E331F4DC19B0CE390D8724FE8E9E +:1028C000F480BF23E1F007780B6A2F4F127249E0C2 +:1028D0008D2D8A23BD5A3AEFD59C0858D799BA480E +:1028E000CA93ECE97CC4668CA0FC03E9BF1ADFAB99 +:1028F000DBCF44793E67570E21FC69F136FEDFD30A +:1029000087A1BDCBFE6E6168674DCB66B74D86F67D +:10291000DB14CE6FD3EAAF198F76C4DD495C9EBD60 +:102920000572D0D597B1B7410EBA400EBE0BF21169 +:10293000EBEF2F4EA6FA878B1D547EB4B81F954738 +:1029400084BF5FF21D1002D1ED92242E179724C987 +:10295000F8FA82643469C6FFFBDD213A1BDE676C3E +:102960009B30369DB1EB5CC1FAF7C6A9C1FAB5D36D +:10297000601B978CE7DB150AD9A3E5EE9141FDE1D9 +:10298000DC64C47B2BAC5F9EBF9DF486C33819E822 +:10299000F1A6E2B8A0FED737A406D59F4872D0FAB8 +:1029A000268DCF0E6ABFB9B47F50BDEC9C9131A487 +:1029B000774701F1CF0291670407778E171BEFFB72 +:1029C00075DDB0A4BB60BD5FEF33D0732D3E245ED8 +:1029D00067AC519907C69BBE06E41F2CF148E3740F +:1029E000E2AF2F0E58E85CB2BC296F7F01D40F35DF +:1029F00019280FE8D0B2B85568AF1D6A4AB032281E +:102A00003DCB5561D7D88C2C40DE152D5B42F9A605 +:102A1000653E9393EC9776EF93B2EEC0F32A2E12B5 +:102A2000F9E43DD5D7AA10FE5C04DF6722E95EE138 +:102A300071B027F12AE1F44EBEAEE30A5B86F513CE +:102A4000911FF7B90BD6716A6263850EFD15EABE58 +:102A500004929FCFAB0CE9B6749E81F20C66BFAFB7 +:102A60006EC03A53725339BE55CAA366CF98687C7C +:102A7000D6051402FD163C6D7AEA01AEFF787DFBA7 +:102A800040DF03823E918E8EC732572C2D56A1F522 +:102A90007EFE76C2067CEE87A76F10EE7BBDC1FD81 +:102AA0006612E0EFF30ADF20926F8B1288AFB470EA +:102AB0003F62E4F2CB8B7CA0F8E5A69FCF96927E96 +:102AC000986E70263A496EE5A7A0DC3AB2D24076FD +:102AD00030D3BBAC93488F3E4F742CE739A2778C30 +:102AE000C3F51D69C864985F51BE52A5F30AD21F91 +:102AF000EFEFE3E7D487550FD824CCDBA07858520A +:102B000028DDDC3E6F18E55D6AED6D597E09BCEA93 +:102B100009B04BE6ECE479812CBF533F7560E03E91 +:102B200096F1F93C0541F94A5559AF1D34EBC82ED1 +:102B30008CC173C289F754A2B313598D4393019F7B +:102B40002775BB86DE05F52F267A8FEAA13E22DAAD +:102B5000F32F84EB5CDDCA0C250BF3FA0FAF1A09D7 +:102B6000EF7DFEACC1496C2EECFC39CFCCEEFD43C1 +:102B7000F615D81BBDB8DDE14AC1FBCF731DCD1AD8 +:102B80007B80C3C78149200017DB6A056D377678E3 +:102B900088E5013C574FD7314FE079E0B0C8E3B149 +:102BA00024F373A8B41BA6247339335DC7E99BBD16 +:102BB000AC707A03FB2A500F48B93D17F3AA55BFF2 +:102BC0001E9072BB8A3552FE8A2399DB2FB3151FE4 +:102BD000D9DD35988902FD2B6C3C6856B5D9E4F3F4 +:102BE00065D298B640FB607A329727738CCF3E8EC1 +:102BF000E45BC93AF83E35FD3E37F82A3A3243F5F0 +:102C00004F856DC3323B8D6F70A29FB752F06B75CD +:102C1000A3E26B253B85EB51E9579D29F4A8563F6C +:102C200085E8258D3E9AA9D1BBAC3158CFC27AE94F +:102C3000DEB25CAF769DEE680BC1610EAC0BF56F3A +:102C400085C7B7A784D6AD3801A321EBA964EE31BF +:102C5000B1B80F78DEEA085D9F765F21EB15FBD4F3 +:102C6000AEBBC2F9552BE6BB543529042FED3E24EB +:102C70003EB4769CC44B8597C3B7A245217C7ED6D3 +:102C80006D1F32F26F4BBA61CDF02FE07D4947B036 +:102C9000AF12946F95AB411E6786D2D31CD66C459C +:102CA000BAA961ADCB5390DF5A9BAF1F8E7E86B51C +:102CB0006FD3F9A9D4DE9AA38B05507A73578EBFD0 +:102CC000CA4FE7178A27FC5CF0C3DDE9A59F1EE029 +:102CD0003573A3EA8A1C14D44FE43F7A098EB3BC3F +:102CE0005E23FA6367093FE585D659ABE7F75F2EA8 +:102CF000B85E01CF9F7BDD0F27F76477853F17769E +:102D0000DB5B1A3DFFB181FB5BA57CFE5AEF22FF26 +:102D10002EB40B3BACCEC6E37D1AB99E9E4F72BD5E +:102D200042E87939CFD1355B295E3013ED8080F6EA +:102D3000CF566FA578A5F1D99956B4CB8FAE99BE71 +:102D40000AF3528F364D27BD5FF97BA9F73DC64088 +:102D50007BA2684DD9FA7B908E3747525CB1A2DDD9 +:102D600023CE452067A19F630D97AB6C3597B39534 +:102D7000A81F07907EEC8BFDEEACF0F4457E086852 +:102D800027BD79E774CF9F77C2B877FE29DAE925A6 +:102D900050D85A7564CFDB5A513F56CFFFF020DE32 +:102DA000D3017BE0FD5F4B7B00AA45064F5B32EA17 +:102DB00021610754AB1B326C683708BDF11F807F5F +:102DC0004478F8E712FCCB11FE01F1DB4F1B389C75 +:102DD000A76BE07F7825C7CBF2A66C2B9E2F3F6DAB +:102DE000C826BBEBD3A61C82FF8C0700FEDC5F1F4E +:102DF0006C773500FCF17C81F087F596B73B04FCDD +:102E00009D1CFE0D1CEE6C252F6784C0D94BF95715 +:102E100077FED1E4443BE278642BD957C7B7A8AC1E +:102E20003EC02E9376D137ACF149B4DF24FC67F76E +:102E3000E91884F2A7F4E1D7AC8887D95B785031E0 +:102E400004FECC9544F1C7EEF9BBEDA86F115FDD30 +:102E500076D445E2A986B919E9C796D70EE039427A +:102E60007171BF458DBC6FB623F8BE19E69295DA35 +:102E7000D1C5E28C88C0F5A469EFD37918C6BDBE70 +:102E8000CDF9EAD6F9C4E75D4179B925ACD580FE24 +:102E900036D6ACD03DEDEA0585D6428671B53A5AB4 +:102EA00087334509CACBAE5675644F5619457C44E5 +:102EB000E45524897E4929DC2F909C62A3F2742476 +:102EC000237D70DA62F4E17D2A385F25E3FCDE9D24 +:102ED00026C2DB415C13C05F350A3F33A842A4B76A +:102EE0005B18A7D35BCC7B29AE07279775A81FA7D4 +:102EF0002D3439C9CE8D8FA1F8D2CD42DEDD625E90 +:102F0000EE463D31CD6C746109E37A31F9D7301A60 +:102F1000A687F90DBD8C74EFB034A2F3593C12DFD3 +:102F2000967CF88E0858EA95608EA31F187EDDF611 +:102F30007D5C285EFCF809F64BD74685F78B0C17AD +:102F400070505C2EF23F9B60EC2858C7A814076FA6 +:102F500077D8B83F7A2DE0C9E2C7AFB69D7979FC42 +:102F6000B20AF3B1F9F758BC241F545D50BDCAC86A +:102F70009F4F796243F1EA34C6DE618E8188B72AB9 +:102F8000942178EE2F8BF1617CEF3AF487DBB1D49A +:102F900013BD4CD633AF8E970D663B0EC7FDE325B0 +:102FA000029EBF2A60AD3100F7D6D783FDF337B458 +:102FB000EA5AFB027CAFD3B7B6217DEA221C061B7E +:102FC000CCE31EAFE4E239A56AE9C5ADB7E289A654 +:102FD000E2D5A3A0AEE3F9AC5DBFE6FE895B805904 +:102FE000116EB7EA59BB9ACBE900E1526B7778A929 +:102FF000DF3C85E237322E20F13F18860FC4E32DE7 +:10300000627D304E8315DF3786C7D77C812FCC8C0D +:1030100046B8CF157C3757F25B5330BF3D827804FA +:103020003E55D02E06B8DD22CA9EF8E2A1146E47A6 +:103030003F94C2CFEFF75CE27CCCDC95417979829A +:103040005FAA4D7C7C39FF75A27C30C54EE3CBF581 +:1030500000BD7E8AE3E8400220BD1E69AC27FB6804 +:10306000160B88C365FAFB49BA0EAD77CB11DDF7B5 +:10307000581ABB6620E8955F443A518EDE626CCEEA +:10308000A93387F69371E652D661A0EF03493F99C1 +:10309000D03F635533E535952AFC1EF4E9428B5742 +:1030A0000776E2C722BE7B06EC469CA73456A1FCFD +:1030B000AF69317796205F975A8D7A2C3F16F1DFF2 +:1030C0005B59178DFF892D2BE60686DF4D5031E6C3 +:1030D000070BF8A4D805FBAD47F9C3EB2B5D69E4FA +:1030E0008D12F54FF7615C66EA79A003AA1F2E7670 +:1030F000C1BCA75F15CFD991627C7EFA3E41CFDE7D +:10310000E334DEE9C7E4F353FCF90AF9FC2B5E7FF4 +:10311000508E2FEA0F6B9E2FD13C7F82D75B9FF89A +:10312000AAD88BF6EB684EDAA523149257462137BE +:103130004A97B6129C4B75BB78399AB5EAF22FDCE8 +:10314000EF648ADB989280F7CE8F58500FFF33D50B +:10315000654C817E9F2679FE86E59C498AD78872D8 +:10316000F73D1FE985921EF2278D42AE9FEAE5A644 +:10317000F7A51E8371DEC3F12F759CBB43C7F9E42D +:10318000C78C734D6AC838477FCCBEFE9CCAE12409 +:10319000C791765171BA4BE985FC3A666490BF706D +:1031A000EEBDCE18F44B31CC7703D0CF5DDA9C91D5 +:1031B00007E3CF7DEEC58C0AB49B84BEAF39A7323E +:1031C00017C8A3DA730A955FB47D64C47BB335DB9B +:1031D000DA8CE3A05F2D944501EBAA12EB047DA7E6 +:1031E0009F1CA0A78DBD74426E3CCCF3329E3BA1C8 +:1031F000477CCED5351FFD3DEAEF114AD8F8F2974E +:10320000627F077BB81F61EEC5E551616F5734EEF1 +:10321000F314063960FCA2FAF0F902BF12EB28158C +:10322000FA6FFA504B8403E03CE43D1E5FAF589BBD +:10323000998BFE6263F2E804825B8F7ED62EEE6786 +:103240006DE17ED6527BC702FC4E99BB57EC83F8EA +:10325000DDB209BF937C062C0BEF8E37C97ABF898C +:103260006346713F18D6F37E9FF920F2CDDE286EBB +:10327000CF4E1B36300AE5436766B4CE06FCAC4F32 +:103280002A73F74AC0F6ABC6617BA1C9D2A78CE00E +:10329000CB882EF449EEFEB84EEC8FFE118FB1357F +:1032A000E106D887E70D95EE037806457BC2C5CBCE +:1032B0002FEFC5E5B9BB978DE0B15707EBCCF5AF64 +:1032C00043CE0F76FD820E18EFC8D294C10F38306E +:1032D0001E53785DAF04FFFCB3923CA302E73FA20C +:1032E000637DF06871B1EB182EF0711DC2064AF7CC +:1032F00028A0B780F3DEE431D141F5A9C571CC1522 +:10330000E8BF9D9A1A54BFB1343BA8FFCD33FA07EA +:103310003D9F68EAC8AF0BB0677BB697BC049F5A65 +:103320008B250AEDBA4F5ABEF9E016B40337AA4E00 +:10333000B45967EFDCF4C148E87506F01B477E49D5 +:1033400007F9D13E9779747A973E307E748A75502A +:10335000BEA23CD75E6CDC68AEAD9DF2097FAE7854 +:10336000D1BC5EE2FC9BCB72513F9EA97B9FFC7956 +:103370003566BECF532F1EE2DF2D44BD02747F356C +:10338000BE88F6E23910FCC0FF453B0E519CCD864D +:10339000C14DB4F7D3E6E9F1FE642D94A85FC68170 +:1033A000DC8A01BAE9686303B761DE48A685DBE51C +:1033B000E7A690BF7C6F14F7FBEC4D8CA5EF48CCD3 +:1033C0006DB886DA6BCE45D3F86FA91DE3282FFAC6 +:1033D0000585E2131353A72DC5FDEC8DF20EB81D24 +:1033E000E69DF8E7ABC723DC6AB6F17B0213D5771D +:1033F000F2E74159D5780DBD3F51657B15B01F628D +:10340000CEDD42E34E441B00EAEA50CB03A89755B9 +:10341000636B9F3FA0BC315A48DED49E8BA4F72635 +:103420001471FDFD7B214F0C9D7C5D63CF4DA2E7A8 +:10343000922E7CBDB282F2F70D091BF5F8BD214337 +:10344000A742FDAF3DD79F4AB9DF37FAFD91BE2FA6 +:103450006048F87A1CE68DBE11AFD8C82CD1C8E3FD +:10346000B375C362581879D53DCF399E6F6C3AC792 +:10347000F38FFF3BCDF517E4C392459D7A8C17314E +:1034800073840DE1555230D85111C067EAAE9B8C60 +:10349000881FC3EAB78DA8AF4D5016053CAF16F98B +:1034A000585A79DD22E483FC8E9BD43F2C7906D1D7 +:1034B000E7AD3641A0828F9E167C2CDFEFA0330E45 +:1034C000E0713BF7F3B7A679DE4239D151C86E7C83 +:1034D0009EE4674706C6697EAEF5039E2314B21BC1 +:1034E0003B29AFBEA4C0A1C3F8C07BDD7A87F3F34C +:1034F00085F6D126F6FD96CA16E2B86FFDF2971D45 +:103500002E18AFEDEEBC3CD40B72DECF7AF17B0B04 +:10351000CCD6751ECF87B52F473B90EF27E2E10C45 +:10352000E3A23B4D746E81768A77D4BE6C7A0AEF43 +:10353000BBD55AE1FC0AF317BD12D98A74DCF64AEE +:10354000A41EF5C71DBD3D9F217C8A5EE93B06CFC9 +:103550008BAE16939E91FDE33A4AF2B687F55E482C +:103560007E69E94CF2A7A781F34B99A0D372C17F82 +:103570001EC14767EB92880FCF2E8245633C759141 +:1035800032701BDA0B0E0B7D974EF2E5443C1F4167 +:10359000FBC4FEB1748FA1EA5C6C101F569FCB1464 +:1035A000FC1D47ED92DFCA059F98847D3143D0B55D +:1035B000B45B243FB2744F622AEC63623DF0BD9568 +:1035C000E2FEF9C84F7EBA31DA90BE806E922B02CD +:1035D000F8A7BEED2686768A29DE4D743303CA40ED +:1035E0003B6566B79D621B9708EB2F5996A9C37B75 +:1035F0009BF2796AEAA5D17F44AAC82730B7E6A032 +:103600005D6BA88B74E27D9A33F13C1E347F058795 +:10361000E37C83BB08ED8CF94F28E43F43FB03E5D3 +:10362000D2D00375C640BFCA4DE706513C7DCAB92A +:10363000CBA834267B2E4738949DBB5EE06BD08FA1 +:103640008A3F0E7171BF92C167726EC844BF9247C4 +:10365000453C1F4F67B64703E37D6B54F28FC9B8F3 +:10366000A4F43399F0DE4F803EFD46DF9841DFA39E +:10367000D1FA9D0AB9FE3FB9D140FABFAAED9DA18A +:103680003A78FE79A62B09F5C97A83A708F733673C +:10369000B2EF3903D4E73EB8D53ADCE18767B3BE71 +:1036A0003507F56933C011FD5FCD2BD5F13E6EF7BF +:1036B00044F3381AA76F49CF5A3A9F732E9BE07391 +:1036C000B6CE447AE82CD02D0BD04352EF48392F98 +:1036D000F58FA4EB6A3D975FD5E618CA23F3EB9DFF +:1036E00049EE42A4BB7E3C1FD0AF779E5A3502F90B +:1036F000E0743CE55D4BBD21F9E085C5C9944724E4 +:10370000F592E40329CFA57C97742FF5D6E83FFD09 +:10371000EFD6BFC3AF93D23C77A5027D5DABE7FA8E +:10372000EB5ABD85E8676CFC243DD2CDC5CBD143B7 +:10373000428E1E0A92A3353DE88145A9527E5E1C49 +:103740001FCC117C33DEC4ED4894F381E3B5A68D24 +:103750007E08F7B13A95EBD99F6BDD3DC9FFD5A93E +:103760009726FF97A45E9CFCFFEF54FE9D0AADBC1C +:10377000C70F71A3BC3FBDF3721FEA83830CF40330 +:10378000EAC19668C726A10F485F44C5F87E481F66 +:1037900014F69EFEDFA9E1F5C1666CFFB1FA40D2D6 +:1037A00097E41BC927922FB47C24F962C26FE1BC55 +:1037B00088787A8BDF8FAAD67B9B280EE9881E8CAF +:1037C000FCD96DC76D5388DF42F484E01F3FBF040E +:1037D000EB0DC91F925F24FF540BFE9829F843F2AA +:1037E000C56EB5F9D111980A90E6F908E588E49319 +:1037F000AAE7B5FAA147BA424F239B195FC790AE1B +:10380000AAA10CA42B530FFC70F012F5C2BE8BA41E +:10381000A7AFFEF3F4F4550FF474E6A7D053A81D38 +:10382000FB61BE03D673361FE46DA69FDE26FC8DBA +:1038300071FB219B9F07F646F17DEE35A693FF674E +:10384000C2F73CCF57DA033385BF41D2691ED80196 +:103850006943FCF8C7F3C0BC8B937B8467537C87B8 +:1038600011CF2733A10CB4037AB27F53D32E4DEE80 +:10387000458AFE17C2F380B49FDD6E1C90161EAF02 +:1038800003D37E025E2762A22AF92BB24B5CA3000F +:103890003F0F89BAB74F09C2F1FA02F9FCB2552EAF +:1038A0003DCA07D6FDDD75F477BCA5CA7ACEFE31D8 +:1038B000B09E098F32BF1F1D9E8F1D15D3ED1F5166 +:1038C00098BF7F715AD6FE95A4E71B45DE4AA79E96 +:1038D000C783443D1FEA96807A81A6BE96F7B7EA71 +:1038E0003B59603E09D28D92CBF1EC0EB01F60FACD +:1038F000F6B3A82F6C0A43FF466DFC8657CFA25C37 +:10390000DBA1506CAA1B0EDE810407FA3E38D507F6 +:10391000EF775DC6D8CDDB78FDF6B54356792F132A +:10392000E306DC1B32342B2ECA4728507C5999A160 +:10393000F0BE3D4DCA13B91E46F71402DE6798AFBC +:103940007729EF77E74D67D1FBADA64B98FF8651FE +:10395000E1EF6FAC10FDC6E4C7847DFE709ACAE14A +:103960002FFC06343F344D690E7F9FFF09C12F1D88 +:10397000183F21784E5A85FEED0EA384B77B15C201 +:103980007B2C63417E34989FEA1BD7BA4B1AF47C98 +:10399000BB2E0DBC7E68BF77A505DB03F49B065FDD +:1039A000A61F80F7DD61DE7704BFDFFA43F85A1205 +:1039B000F2BEA0DB59928E5D41F41EA377137DC643 +:1039C000C42B36B4A36BDC912BF1BCE0E7CFD21251 +:1039D000829B8C1384F0DFB4923103C84E12CF6FF8 +:1039E0005B85FCEBD675F7E7FC28E91AAF36015C7E +:1039F000C9F507EFBF9C76EB2AF44F025DD073AA9E +:103A0000EB03D6ADE5C7664D7D94867F05FF91FC3F +:103A1000407D0070CA41F9167FC8E808A0934F04A2 +:103A20009C4E897CF28ED1DC9EECC8E2E577693C45 +:103A30002EF599A0CB53929EA202E09016443FF43B +:103A4000F72102F64D70BA295EF2F3BD25C5C0BF5D +:103A50001D76FEFC7FD6FE669537CD5FD78EF7CFFD +:103A6000B5F796205CBAC7F72EDA8F76C44D026E92 +:103A7000DFADBD67BF7780C073A2FFBBAB401FF453 +:103A80003D9E6AA40F25943E5E0DA52FAFE67DFAFC +:103A90003B043DBDFFB75079E0D2BCCFF07B10179F +:103AA000FFBEC05BB106AFE335781DA3A997CABAC4 +:103AB0002F48FE4AB95CBEE3E1FB12E3D1AFA9D0C7 +:103AC00075243F3D3F48F43CD726E97715C1D54FD3 +:103AD000CF0FED47FA9DDC2CE9B591F4CF2494C3C8 +:103AE00023FCF5292887A8FE7009C6C5FCFAEA91CF +:103AF0005528B76F6890FD1FA5FE372F93E3ADA63D +:103B0000E7128F8C3D46FAEEA67CA9AF1E27B93F7F +:103B1000A785BFEF4CFFDDFE1FE487460D5CD66A2C +:103B2000EA5E4DFFD517D06FCB34EF2FD23C5FA9A3 +:103B3000A9AFD1D41B82DF2F9BA1101F9615F0389F +:103B4000A5962FB5F4E14AEFB673BAF5B96226FB34 +:103B50002E88AF26D4F3FAB5E91B4B1ACC01F575C4 +:103B60009B4A385FC06C01F79F41E67A55A0074336 +:103B70000F72B320BD07B9D94FABEFF9F37FE0AFB8 +:103B80002914370AB24B76ABC1F53655ACDBBB75A1 +:103B9000FF820181F1D5E74BF05CDD631CC7DB5C84 +:103BA0003226D02E62CD25AE807DCAFEE3BEFB5EFE +:103BB000C5F93CEBFE5CB2D18C714F11DFB4F3124E +:103BC000F4A58AFABA56F86FC6611E2FC693A25A98 +:103BD00073E60F08D8276BEE83FB6CBB5BE5DFB7A2 +:103BE000AB07FC009CCA9883F250A73317E5A5B633 +:103BF000C5C42CFC2F786FF7DDEA42D4D30717C673 +:103C0000515ED32BE9FC7CB13BA677E24CA8B745CB +:103C1000DF46F2B6EDFEB154EE525DCBBB6C8C2D9F +:103C20005EF74A89F9727C1E4370BA3BFDA5922566 +:103C300040EFF7A63BE87D8FDD96B803EDED070C6E +:103C40001437040E7892E8E741D3603C6F972DE972 +:103C50004F71B1F2C7268DC37BA4E5F719285ED258 +:103C6000A9B3919FC8F3C058CA939AB14C94DEABE4 +:103C7000A97CE5DF7FACC77BA65DEB14FA4ECD5582 +:103C80005F37FF6D10D42B1BB2E97EC6CBE774946F +:103C900017FEE99ABE3ECC533E1C5947F9A5D09F6A +:103CA000EEBB569E77EC2FC9C7FEAA0D53388E4245 +:103CB0003BDACF4757A84FE13DCE32AB250AF3BBE5 +:103CC0008F7EC7C8AF73F43E137DEFE653B3E7D6DC +:103CD00035F1748F092D7D765471581580C3DAF44F +:103CE000FD25C929D86E12F8DC6F2D033E2FD37540 +:103CF000D30FE9938A585E5FBBEECD924DB08FA390 +:103D00004FF4A57CB1840CD7BA7480D7E10CD7935B +:103D1000548AFBD9AFFC9BC7255F3A599E88F4B5FE +:103D200059D0F5CBE7CA1303FF6E41C5293DD1C178 +:103D30002B46C702FAEE6954BA82E76CA08338F4C6 +:103D40009BCF10E716A0E7855BC3D8574BD3B93D8F +:103D5000D6F6DB84518E20BAFE98E4299D37A0FE6A +:103D600062FA47A4E78E9816622E75773E24DB1D13 +:103D70004970323445FA2233D17FEA1AE7A2F34F71 +:103D8000739FC996003E14FD3FF1F2FCDF4FA03F48 +:103D90009EFB3EF1FE3F4B603C43F6AFB45ABC681D +:103DA0005C1CB358F4888F83FAC547313FAD629DE0 +:103DB00081F440C5BA84455D287F806ED0BFA6DD02 +:103DC0009729C3C0FD183DC6573F2F199316785E3B +:103DD0003941F2BB27BE7C37FD44C9C6013DF365BE +:103DE000A58DCBA771EBF8F7752B8758F474BF7BC3 +:103DF000DDAB9BE81EF0BCC85CBC5751B9CE44F8A3 +:103E0000EAB458BCB62BF1BE81451F0BE5A174AED8 +:103E10004FF5190EC24791CAF411B954D23D0A198F +:103E20003F3CB1F0D1C7311DF373E6BB7E18C0EF44 +:103E30008C8BD3E9996D2AF91FB5F1C4EAD7B71A6B +:103E40000BD98F8827F61047AC629DE2BBE2E1E315 +:103E500089DA38E2BFD2C5BDB3EE38A281BE875140 +:103E600029E288456B155A7FE542FEBD92A238EEE5 +:103E70003F3EB218E8A02FEDDF6BCBC53C69AE7FAB +:103E80002A99E28B805FAF5E3B8FFC9975E91C5EDF +:103E900065E23BB087239D1978DEAF58174970AEB5 +:103EA0007C72F6074FE4E37DC089F181E76B9BA04C +:103EB0000F189FE13D6839CEB125F7D077678BD6D3 +:103EC000C33919F3B463D973376522DE523230DE59 +:103ED00029FB552EBDBB0FEF07E76CD877D90A95A4 +:103EE0007F0F6BBB89F421F07C320BB82F3E63D976 +:103EF000EB4623D7672C79A8B0B31DFEFB6C9FC29D +:103F000073FC0441ADB8B726E127EF5B95E9F8F7FC +:103F1000364B750ADDC3028946F7977E91C1FDA332 +:103F20007919DCCE2DCB70D23D9EEA5526E7D24CD6 +:103F30003E4EF7BD7538E755EB3A2A28AEF9171310 +:103F4000F9576A9745BA22AD3C1FE3F9019477AD62 +:103F500037023CAA1C5C6EFC42D063AD63D2D594A0 +:103F60009FAE6707F0EF07565BB89CAC8E05B89B19 +:103F70003901E986E2F73919E553E2B8298302E607 +:103F800057443B8CE3B0FAC7DDAB630DE8A7C1FE35 +:103F9000970F4238C65D7F23AEEF5995F81A80B46B +:103FA000AA00EDBF67D53C3C7797ADD83D0EE5F054 +:103FB000DC2D83F146052B7BEE5DD2237305FE3BA2 +:103FC000453E5A39D4F1BB81376470B9E951B9DF44 +:103FD000E806012F4907F279F50A03F7E383BC47A6 +:103FE0000153BDE4431AB7DAD2918872B87ABB8123 +:103FF000EE87DF8CEB0638972F491F7500E8AADCA7 +:104000001043DF51ADF24E3462BDAA51A1BAFFBDDB +:10401000840CA4D32F96BD6045FA391CD99A83FA33 +:10402000A96B5EA493EE29DAB8DFEE8B653974AF25 +:104030006986ADC382DF6599B120DB8E72FCA0ADCD +:10404000D588CF0F3667EAB0EEB2D94661DDA5BF9D +:1040500092EA5F887C17FA41BA52389EAB9A761B77 +:10406000F1EF2FDD2BE8E2D4B3EFF6413F50754678 +:10407000471FD42F40077D5211CECF28A49F6B9AA3 +:10408000781EBCA4831AA403E0BB39820E6AB6BDB5 +:104090007017F2430DE23F37948E809EDBA9FDF945 +:1040A0000DE3187FBF1DE944EA33A82F33A03FCEAC +:1040B000C8EB8B05FEA17D0C6FF70EE0F975DDF9FD +:1040C00008417CD0137ED766E8043E4C2477D78A1B +:1040D000FD76AED86E45FC9D7A76F71E8CB7543FC0 +:1040E0000FDADA11861F043C6A71FF565A3FD9195C +:1040F000B5B85FAB7FFFDD742FF8B096F1FDC9FD59 +:10410000D6EAC5FEE573F1FE3AB1CF2A26E0B5AD99 +:104110002FE73BC167C8C7F4DD21B13F8F3DF8BB36 +:10412000BABBC5FE9A44C96CCD56840FE217E50FA1 +:10413000D08FCB28E5097439B56503E5F74B7CC909 +:10414000F5BFEFD72B2EFC9354128F9D3D7CF7B615 +:1041500045F0C9A1FB92327600FCBED84C9F0D24DD +:104160007AD507CC27E946CE57F4A749D7E2BE61F6 +:10417000FC561C5FCE7BD01BADC7710E32CE1F72BA +:10418000FD922F8BEAA75D3BD88AFD4E59B2D15ED6 +:1041900011787C3FC346EFBBD06E80F75D3B14F2D5 +:1041A0005F1F12E7FD43F7BD602D1FE0A7F777C53E +:1041B000BA259DE10FFAC9E47AF7DAB93F58BB6E28 +:1041C0002987E4BA8BEEBFE15A6C97EBC7F8512010 +:1041D0009D4A384A7A95F7FAB4744B3427F5AADA2F +:1041E000337DD7A61DA2FC9D9076ED78C23E3A2C79 +:1041F000F2CDBB9E56F97DE765C9ED41F78E1833C8 +:1042000007EA9F25F3AEB615623CB749A17B1E5263 +:10421000AFC0CF4A7D803E92F6C1F0DE3C7FA5362E +:10422000DE7502F15975BC631C7E9244DAA5577D98 +:10423000DDAAC6A0FF6A1BCF8393745375B29DF8A5 +:10424000A15ADC932A5BF1EEC46148F74F1B28CEDC +:104250005376DF5823DAFBB3374D1F8AE0C07B1259 +:1042600028DF4F6C1C9247E061B6C4EBF1BEC4C6B8 +:1042700047AFC7BF5F3A63874ADFA1C171908FCB59 +:10428000EEC8237FEBE1C8CE8923D0AEFFB56A43E9 +:10429000BB7EE4A6218BB0FF484BEF58FA78D0C61E +:1042A00038AABBF431A427A41D2CF303EBC5BD90A1 +:1042B000ECDE9CAF7A75978AC80BACEF83F1F9AE50 +:1042C0000D91F4DDA852A3A3B915E7DB9944E78E5D +:1042D0005A382625DBE99E2BD969B38C2C222597E9 +:1042E000DA233045F97543C71DA84F5EBFC33218A6 +:1042F000BF8BCBD4F343CBB97DCDE39071C1DF61EC +:1043000092EBC8EACDE9573B9E7C7F2F9E2BEC7445 +:104310009F91DE3FB1ECE9EB511F9ED89C63C77DB6 +:104320001FDB1949F70B8E1982BFE778A9F7C2B4D2 +:10433000F7A9E43DD7FCDEC1F69CA4FB0BDECBB9AC +:10434000ECD2F2984E2E66744FFC5C06E3FEE4E875 +:10435000EFB6627E6145A3C986F7648E20FD637C5B +:104360006BBB4ADF01A2BBDF80AF23DBF3E83E700B +:10437000C5C7BC5ED1ACF8F0FE72FBC3F753FEC2FA +:104380004CB037F16A79B73DBDFAE1EB910DCE380B +:104390003DCBF13B006736F37C8B90EF3ABCBE75AA +:1043A0004F8AE3FFBFFD2CFD13D37B07DF4793F05C +:1043B00096E7AA57802E0A72FDF0FB72F12CB29F8D +:1043C0004F2EF650795A39B46A24D2B32586EE15A9 +:1043D000BCB4E35115BF7353BD6DF0793C1F8F30F2 +:1043E000C7D0F79FBE5CBC90829A2717D7893F8AB7 +:1043F000B654F8157C545EB5AD8DDEFB72475E0B8E +:10440000DEEB7DD91CC3C59AAB20E83B9912BF3DBA +:10441000DD5796FBFAFCD71CCF72DD9F6F9E6EC5F1 +:104420007DB5FD21AE6538E2373AC6867660A5C80F +:104430002F39BA86DBD9C72362FEAB18F07C7CED3E +:104440009444FC0ED1CCB6A9D7637BC54EC586E794 +:1044500003E7CE49563CCF7DA6EFB4E23DAACFD6C6 +:10446000C8FB573EFABB7B23C6B329D87F44AB9E1B +:10447000393229844CF432FCA49EEECB7E01EDE46B +:104480003F391F45FE13F889C37C92992F72BF4BA9 +:10449000F7F9579CFF468A7DB7F7B6CBF806B517F4 +:1044A00015F0F6636BB796D0DF4FDE68B0E1BABFA8 +:1044B000DC68A0F1E7C0B94D07EB3DBE999F83B022 +:1044C0008EE7E8139BF979674E333FEF54CF33B84B +:1044D000F8FDD260BA2C0AE847DF2DEBE1BB23736D +:1044E0005C7C7F73407FE27E2F44BFB1AC99EE9F2E +:1044F0005D6A3EA9967EFFAA9117DD74DB13BD08A5 +:10450000B822FF23DD4ABA98B386C7F5EDCD830BF9 +:1045100091FE249D68BF03586F64FC3BB2BA28FA31 +:10452000EEF724B3C380FA624A7CE718044F5F07B2 +:1045300097AF6A91CE85F7E458BD29EC77C4DE15B4 +:10454000F2781ABC4BF7BB7ADBF8F7CFC47D315950 +:1045500082BE4A477D3E29DAFE8D03BA74AEFFF271 +:104560003A3DD0F5A491F63BB29D80D7F55FF37A42 +:104570009E7D7B16D43FEF7DF63A3DEC6FD295F6EB +:104580002106A82F59F2CD7563E0B9C9E13AD83BAD +:10459000609E139B92D2717FD07E08DBA7277A8E14 +:1045A00060592BEE8F9D56BA062DCCF4F77F7BA772 +:1045B000E5E04B0E7FBDD3C0E8BB3BA77BCBF587C7 +:1045C0002F9D0ED7A9DE09A1EDE58CDD47F97C5EB4 +:1045D0007E6F077EDC118978AF8AD35DB9BCC7D303 +:1045E000A0B9C7E3E4F7D5E4FD2A797FEA72FFFDBD +:1045F000B3B59772FFECFF0069F3B24F0080000083 +:10460000000000001F8B08000000000000FFE57D97 +:104610000B74545596E8B955B73E492A4925845438 +:1046200025A984AA7C2B90C0257C0C3148E5030485 +:104630008858286AD4A005A2808214011D74F455FC +:1046400061307C9AE98E9F1722462D10957178DD96 +:10465000D1B16D868F532032FC9A0EB463EB8CD3AC +:104660001DD0D168631B3138F40C366FEF7DCE4D11 +:10467000EA562A80BEE77B6FAD975EF6619F73EEC8 +:10468000F9ECB3FF67DF5B5F192CEBA564C6240F61 +:1046900063AB53A1745A596319947BFFE9CFD26875 +:1046A000C69A83AC3B2E8FC15FA3F5D35150CF7C0C +:1046B000BA4B502E4B481ACDC660991362D06F99F1 +:1046C00089B1AE12E8263B6DCCC2D81209FE9D011D +:1046D000FFF9CA194B676C9515FEED44B84287F097 +:1046E0008366467F9F05983FDFC0D81F4F742539EA +:1046F000F58C9D9D1D2E0CBB18FB65BCCFE69C0068 +:10470000ED1DCD8EA634C6BE7CC3A4D443FF9ED07F +:10471000DF27F960FCA57AE6EF84926D1FCED824DE +:10472000282FEAC353A0DF6157F1B68DF0BCCBA9A7 +:10473000630C9E3FEB0AE7FCF578C6822E93F232BB +:10474000A37E773280EB1E9F3E1CFB9D7D7D5DFE30 +:104750003DB06E93CC5812EC7B068C590E7830002D +:10476000AC2FC30742340EB40793A0BEC5F5740E38 +:10477000237C302F9BC8D80D8CEFEB0639BC1FF182 +:10478000C5946419F7379B6F0FDB83328CA33333E7 +:1047900003AEBB9875583F4D0098B18E4BC3607FF8 +:1047A00066C063329680C724C6A6EAA113ACAFE9FF +:1047B00097FA9009D6D784781470D085237A2CD7AD +:1047C000C3F88BC5BCCB8EBC6BC4C15810FE07EBC5 +:1047D0005922E65DDC71773D9ECB9290E14CB7C0EB +:1047E000F525FA7F0F9DC772D1EFFEF2AD469CE230 +:1047F000FE1DDA7ECBD9A6AFF5F0FC52D66DC4FD16 +:104800002EEB8C6AEFA8F90CD7BB7C97B6BEDE996D +:10481000988674C2C6B2B197F4544DE7BD48F49976 +:10482000AA6F74CAB89FE166C50413373D9F47F469 +:10483000C2DE0CB0C87EAC6318D14F8B4B4FE7B1D2 +:104840006497C49CE318BB7E5716734253FDAE6158 +:1048500054265DC8A0FACF5F3936DE5732705ED776 +:10486000BF6AABC6F55DFF6A1195EA3A9A041D4E20 +:10487000D5977486611DE72CB00E809B8EC0628137 +:104880007E9A6ED68718E19999B1BF572CC76B599C +:10489000DFA54F42580E8AFD4A97243A84643C1F94 +:1048A000EF613D437A621E03B53B9979CDA55CA0CB +:1048B0001BBB8E3963E0DF24CE2FCE19CF9CEE8157 +:1048C000763958FCB34A588761AE4109417B735C25 +:1048D000D236E43316F474E5C3730DE2B9AE384E44 +:1048E0003709EE54CDF32A1DDC2AFAAD4B9A76181F +:1048F000E9B2C1B388E82151C9D4ACC7A45F6A400A +:10490000FAB9D567F8A43B621CA25F58C70D5E29AF +:1049100084FC787383B6DD50F975AD4425D4478E99 +:10492000E7D5F6FB29D203D03B107E71243D0C9CC9 +:1049300083C5A3C373F02412BDCBCCB9B912E05B1D +:104940000E1B18EEDF14CFF7790E319786FD800F1E +:1049500060E2758817A84F2ED7E237C5A3C5E7B028 +:104960003A2D7E867BB5FBB735E46ADA337C233596 +:10497000ED598BCB3470B6BF42D37FC4EA6A0DECDD +:104980000ACED4F4CF5B7FA3062E68BD5DD3BFA84B +:104990007D81A6BD38749FA67DD48E260D5CDAF984 +:1049A00088A6FF985D8F6BDAC786376ADAC71D7EE7 +:1049B0004A034FE8DAA2E97FCD07DB34ED93BA5F13 +:1049C000D3B45FDBF386069EDCBB5BD37FCA850373 +:1049D0001AB88A1DD3F4AF31FF56034FB5FEABA60C +:1049E000FF74FBC79AF619CE3F6ADA67B9BFD1D216 +:1049F0006B3C9793D72BFFA579EE5993EFDF505F70 +:104A0000344B95DD4186F4EB243EBA354DA7840145 +:104A1000FE832A97041D9E1C612539C1F2598EB769 +:104A200014E9B0328C7C7C6E9744F2E0AB28BD2850 +:104A3000FFD1EB91A09DFD4A525E7622DD415DC41F +:104A4000FC291E339323D639ACCEAA81877BED9AFD +:104A5000FEB606A7A63DC3E7D6B4672D563470B69A +:104A6000BF5CD37FC46A8F067605EB34FDF3D67B3B +:104A70003570416B83A67F51BB4FD35E1C5AAC6926 +:104A80001FB5C3AF814B3B576BFA8FD915D4B48F89 +:104A90000DAFD7B48F3BDCAA812774B56BFA5FF3F7 +:104AA0004148D33EA97B87A6FDDA9E4E0D3CB977DF +:104AB00097A6FF940B610D5CC58E68FAD7984F6A74 +:104AC000E0A9D60F35FDA7DB4F6BDA67383FD7B4C7 +:104AD000AB76D02CF7D7DA7A61175DAFFC59F37C4F +:104AE000B0DAC3903E826F484AB313D6EB02E13F7F +:104AF0009CE47C779C1EED282F18148C0129AD4175 +:104B0000FD920C420CE90A488C35A6E22840AC2004 +:104B1000B74955C1F3C9684F0090AA73B9FCA01FEB +:104B200013D85AEBA766B21B1C9740DF5DC2BF29A2 +:104B3000834B94A09FAAEB85F966A14E023A6F724F +:104B4000F93C2E58CF7D9DAF4FCB626827045B7038 +:104B50001DA00793BB416F9E886377794B068F3703 +:104B6000C30C788998EF485CABA3CC32F4FC33CC0F +:104B700067A97FFFB8063EAE04FB6B8A18FFA7A0AB +:104B8000EE65B0FB5A03C037058C3D15B012FC4CE6 +:104B9000C04E705BC049657BC04DE5968042ED1DFF +:104BA0008172825F0878080E05EAA8DC16F052FDD3 +:104BB000F64003C1AF047C54EE082CA6F2B5809FEA +:104BC000DA77065613FCF34090CACEC07AAA7F2348 +:104BD000D04AF09B817682DF0A84A8DC15D841E5B3 +:104BE000EE4027B5EF0DEC22F8ED4098E070E03094 +:104BF000C107025D041F0C7C40F0A140379587037C +:104C00003D541E0DF452FBF1C0058207CE4B6B578D +:104C10003361572E1274C0D2B83D792F3F52F685BA +:104C20008E2D46BB7791A04343359887407786CC3D +:104C3000C26DCD2E3C6AA01337D1C971B42FAF9687 +:104C40004ED070407A0D563337D29B5AB654E9C9CC +:104C5000FE0CAE90422F73BB88EB6F3353F537B524 +:104C6000373E2885D09E9B0776B211F8E623619FD8 +:104C70007C14C7E5F539BFC18D765FA314AFC0665C +:104C800001FE77B23BE02F8CA47FD75ED356B49F52 +:104C9000D4F535C2383A18E7BFEC2E5A57233B6C8F +:104CA000C0F540BD470FFC72C6E6DBE202BABE2F7C +:104CB0005B17342213594285DE44C68C76DFF348F5 +:104CC000E7E7FCF71CC2C1175995429CE77A537875 +:104CD000F8AD307FEF11BDB2CD39345E96B7CE005E +:104CE000E17D99F6B73F77A01D5FF717BD0FCFE1C4 +:104CF0008421B1210474DDE99288CF3A5D3A4DD91F +:104D000066F7FD02D7F96DA2FF4E1DA0F2DBEB5650 +:104D1000BCB212B6D4B8A22019ED55F00F0C685FE2 +:104D2000CF614E03CA879B98E75D1CEA66E623F8CD +:104D30005616A452B6F976E1BE6E6321827D15A6A1 +:104D40009C58FB8A5ED73B38D8702C759AF290DD60 +:104D50007700C7FB36D143EB3A31697A21EE4B5DE0 +:104D60009739C349FD66B3DE17707DDFEEFBFA535A +:104D7000296F309DFC88F4618169B03F33C2793777 +:104D800003EFE038CD0F4B21A473953E1AC14CA719 +:104D9000F11F857A29925E804ED07F4BEBCD99939F +:104DA00048F4D24DF26F923E68047BFA842E542868 +:104DB000E9894E8C12AC73511AD049EED0F4F0C090 +:104DC0007A2823E420D0D91738DE9FFEE11A37E293 +:104DD0006DF9DB939C88B7661D9C07D073F0A89E85 +:104DE000EC042644BBFEDAD210F907B2A2CC29C5E6 +:104DF00073E37271BF9EAD7E3D86DC4DC8E5F474F1 +:104E0000C26EA80BD1B89CEFD5767D2E3F477D2E84 +:104E10003FDFA6159F2DD5C3FA4F1CF8DCE82C8D7B +:104E2000B18FD53F79283F82AE97EF3A3DCD837E53 +:104E300017EB2EB93171A0BE50CCABD291DE98E801 +:104E4000DB6A895C573F5DC7E7225DA7005DE7111C +:104E50005D7F8A76F96C9333F95628BB013561285A +:104E60007D2F5AC97F5CC0142A17322F958B800C76 +:104E7000908EBDC1278D88F7FB5827D53F507E7790 +:104E80003AD2F5BD3A1FF9D94B5917D52F67BDB5A1 +:104E900078B437AF5FF3AE1D567D53EB9353914417 +:104EA0006F0CCD7F17CB39DBA54F834EE293EC5CC3 +:104EB000C047B7E47F2213E6BF7D67D51359503F43 +:104EC0005BCFCF851DE3E7A2CA91E87D035F14E0C5 +:104ED000F3DFA678685FFAA43A0D5F343ECE3C1249 +:104EE0008CD3BBCF14DAE68AE093F2FBFF9085F215 +:104EF0004CEEBD13CF7BF9DBA6543CEFFB18D7FB80 +:104F000092478DAFA8FA9E11BDDFCFE215ECF78571 +:104F1000A0EF2FB219D1F71712388A65037628CB84 +:104F2000F1D9CBF206F4F672DDCED18827D0EB951D +:104F3000780EF77DDCD932D685FA2094837688E125 +:104F40003593D2ECD2E817762901858D9F213E7FDB +:104F50008AE38E19BC2EA9FCD09FD1EE301959D00E +:104F60005C467CCE26227F671A89BF9A11B57938B4 +:104F70008FD7E9B70C1EFF8458EFE1EFB83F1D84CF +:104F8000FDBC2CC59A87EB2F53FCC03C2447D2199B +:104F9000CD73472EE763753E66E976A09D7E34C1EA +:104FA000773B9E8F1A4752FDC8C3AECFF2F17C66A5 +:104FB000576C50E5338DC7AEE372E984C11944F8EC +:104FC00044954B0109D62F6F6F28FFA70F701D372F +:104FD000982D618C77B04AC3D97EFF3577401FDFAB +:104FE000A0EAE3CAA8F88E1AF7618A01D757CC3E27 +:104FF00052F141F11D554E0ED2BFB0B12EC49F8863 +:1050000097F5C779FEB93FCEA3C3798D428E32E6BC +:10501000777B23F8D4D600AE8BC67F30B37C8DFF70 +:1050200060D5C0D97EBBA6FF88D54E4DBB2BE8D638 +:10503000B4E7AD573470416BB9A67F51BB47031736 +:1050400087EA34FD47EDF06AE0D2CE064DFF31BB72 +:105050007C9AF6B1E1C59AF67187FD1A7842D76A53 +:105060004DFF6B3E086ADA2775AFD7B45FDBD3AA72 +:105070008127F7B66BFA4FB910D2B457B1BFD5B488 +:10508000D7985FD7C02FC6F178E754EB3F689E9B57 +:105090006EDFAF815F88E7F19A19CE23DAE7C5F9B1 +:1050A000066F8B277E98E53EA969DFFFC8C8CD8DC6 +:1050B000C02FA14774E47FB6D5713DC51AAA391D2A +:1050C000C4F1BED72B1F6AE6CBD1F7BA908E9D7A7A +:1050D0006B26F2757EF99C034076ACD0B3A21AC55C +:1050E0009DBBEEC903588EF4BE5E8D6C53D270F238 +:1050F0000096A37D5F570319336571CA3B5896F933 +:10510000C7D6D87089ABE7BC83E5C4E08A1A94B3EC +:1051100060267EB108D67D3E38926D84752565AADD +:10512000715E0FD1EDAA0C1DF1F9AADB2C14374BDF +:10513000BFD622A33EDF1CE81A7910ECDCF4A7D31B +:10514000D762DC693DD8F9A122B017C0EEC7F25989 +:10515000B0EB43E01C6D04BB1FCB4D60F763FD73E8 +:1051600060F7239CFE74D97A7C6ED5C97BEA7261A4 +:10517000FC110FCA563453D739752B0EC07AEC0F79 +:105180001AAD284B8CAE67E29CB08EEC65B08E0AEF +:10519000428B0751FDEC52301C32391C07FDEC2BC1 +:1051A000741AB81DFF45B02E588BCF973EE9DEAE7E +:1051B00030F6F9B6B337198A619F795DB76D4D0145 +:1051C000389779E602BED3F12C60FC93798FCD0934 +:1051D000960C8697147AFF487249EE2C463EB51617 +:1051E0007D9481EBDA50FD85A2B3E23C8FCC390887 +:1051F000EB7E7E78BC58E72373AAF2AF665CCF796A +:1052000094EF50EFEF8C2147FE53E8FF93795C2F2A +:10521000C39F15E5938D9308B3819D940CF276F3AB +:10522000A4D5A7D1A790AD4109E523BB08CF4F1462 +:1052300028C823784AFC441EB247795354E433E724 +:10524000C178361FD84E91F1B1C55A78339CE71911 +:10525000C3C07A0C77E98232ECC1F0925751609E5C +:105260008E79B05F80371BB5FE65918E917D719F01 +:10527000BAEE8B372968A7DD97C7F5F09680BBECAF +:105280001303FA7F4AD9274047998BFD920FE4AB6D +:10529000ADD1AB04A19FE1D2DFEF372261DFC53A88 +:1052A000519F63FD9A08BB27478C6BB8A427BC1994 +:1052B0009ABD4A6AC4FC06BDE4EF8C617795E6C9E5 +:1052C000FCB96646ED86771E969C305F666348BAE9 +:1052D00087C6F14B0AD4DBC2BC3EABB1535A08F0CF +:1052E0001D794E3A07759CACC5B0FE083CD9E5A0C7 +:1052F0006485E7ED8F0625C483DDEA555822E2DA9E +:105300004BFCBD52F0B47DF5C4B24F86E1BABD8A04 +:1053100017E79BA5F29BDFCA703D1F2BBFA942BDBB +:10532000F61B3DC3FB8C6F9C4A725A8C7DA8A5A9C5 +:105330005BCF3C97F16792721EF1939EBCDDE22C2D +:1053400000FE7DF1364BC3D6187476471EA7B375A1 +:1053500099AADEE2EB49D7733CA9FAEA1B2BA71FF7 +:10536000556EAD4CE1B03ACECAECF12437865A8F77 +:10537000AD3D8EF922D6BB19E6B1E2FDCC772BAC60 +:105380008837F021BC349FCCE5E9D6E7DDE4374629 +:10539000D3CF203E00D19B5C8674D91D6A06BA31FA +:1053A000CD332A682FDAFE5B8B84722493B54A28AA +:1053B000476DD9B58765D4E7B2AFD81BC38EBE128F +:1053C0003FA8E7A9DA2583CFCFF9BB2AB2430D0C5A +:1053D000E9B6C9E5B4E1F9A974DA746478AA2FE2F0 +:1053E0003CD70B3A2E67AD7AE4D30AD6496525EB54 +:1053F000A2F23AD64BA58759652CAB9942652DF39D +:1054000052398DF9A9AC63AD54CE649D54D6B32EF8 +:105410002AC1BFA3D2CBACE487DE08760C96739981 +:1054200097CA5B989FCA2D48DF13F0FEA195E0DB79 +:10543000592795BB80FF9D45181F3153B917E43993 +:10544000966F833CC7320CF2DC69C2F8889BCA8332 +:105450000185CA4381722A0F073CD4EF68A08ECA27 +:10546000E3012F9527020D5476057CD4EF5460316B +:1054700095EF05FC54BE1F584DE507812095FF129E +:10548000584F659111E40AE2DBDD3D16FD9A9C8FD1 +:105490008D1E27E8A34FF384FFEBD1FDF7E2F178EF +:1054A0008E3ABA83B1D5AE94901E6D6E9D2704E5F9 +:1054B000467793743794EB4E703BD6644B243BD9BC +:1054C000D6BE4A72C2B8BBA46E7D029CEDDEBC0F94 +:1054D000E798414F54ED656B1314847FFFA419E8DE +:1054E00070ABC1DFBB15DA7FF5D2BFCE3183CEAE54 +:1054F000483CF5C7D7384CED930EB2662BC007F287 +:105500004E3F9926F175A0103EFED2C773D6E4E354 +:105510003AB91C79D5058E36FA190F5BC8CF18DB5E +:105520007E66AC0EE049AB2D65E81F47F4A3B8F5E5 +:1055300050FDA2DBD5E73A56A437231ED67D0AEEEE +:105540008913E565F7588CCF458EABBBBAF999FE48 +:1055500032F347F6932E335E5191E754DEFF037426 +:105560001E4DDF864B1FBFAEA3F8983515F5FAF632 +:10557000142E777AB3E343DB60DDDB5305BC219F58 +:10558000F6B50E61D8D7BA8DB964C76F8FF3361DE3 +:10559000C1F6BFD129DBA0697BBC6F6331C1F914AF +:1055A000AF5997EA77A35ECA49E0FAB1CDF1489CBA +:1055B0003382FFFF22E4EEE6CABEAEADE84FADD7C0 +:1055C000B102786EDBFA051BDC30CE4B9BC02E029D +:1055D0003879F2C20D05D09EBB4137512F641EAE03 +:1055E000E3A54D0B5FD928E1B823530B61DC3C21C7 +:1055F0003F7386758F5D0974DE66D4C615FAF56350 +:105600003EE7978530CC19D0BF39225EB1D5C01A9C +:1056100022F566413E97B73545BC344CE1F13CD3A9 +:1056200088F8D0E3B0FFAA113CFE93BED64CF19FA0 +:1056300074C77F9E9C0EEDE91D3A054D5AD9B6748C +:105640008D01FD9EDB5827F2E356893F1FCCE6769D +:1056500032182CB97322FC1EB037CAF223E2A7F627 +:1056600086A084718CAA114B258C37A73BEE933012 +:10567000FE91DEE0937C89E827F9A9FDAE229F2BFD +:105680001FD6676F84E735F7B1BE0C3C5798B781DA +:10569000F20964561639DFEC228E872764203DB468 +:1056A000DFD71A695DD1F89AE5AE1E993F7CE01C00 +:1056B000A3DBBFCCE7E7B8FD719802F960128F1F3A +:1056C0009C783993ECE5D96DF11EF4234F3C39B247 +:1056D00096E0A72A3C68FF9E78B9621A96B39F9A13 +:1056E00049FD4E48EC30C605663F75BB8CF53979EF +:1056F000B02E1CEFB491E871F653F789E71FA9C5E6 +:10570000F6725DF0EFD09F2E6F7E2D01E3051589B7 +:105710006F64617942D7BD6A3FCC7F8395FD1AD50E +:10572000B57743DADFD4C13FE63C996BC0788C375C +:105730003F97CEF326E631F07C072FF9B7953BBAB9 +:10574000DE018B8E5DD7D95B83D7BA9E5DD6835839 +:1057500056871534A359ED61EF412CA775F96BD12C +:10576000BCA9FBA0F52096DD237D5EC4FFABFFED59 +:1057700096375E0578C463ABAC6887E63FDE3D6371 +:105780001BC52F0D0CF9A16092BF558F046CF6A6B6 +:10579000A27C78F6195987FADDE46A8D43D8744FF4 +:1057A000AE0EE34CDB535A17D3BE0BE219E2F128DD +:1057B000E821A48B82146F2AF213F0259DC39D82E9 +:1057C0003E4D297E6B0AD68B7B8EFE7EF11C5ED809 +:1057D000DFAF354EA27952A5A0C4CD08B423EC4268 +:1057E0009FB7337F06E2C396E8DF8AF1AD822ACE07 +:1057F000FF2C91D305766F99488F50103EBDD53F51 +:105800000BCFC1E6EBCF1BE074076AB0DF3EC925C2 +:1058100098EE7F364B1C063943EBC23F8CE7A45B06 +:10582000D2C9CE51D76F6B80F122EC0EDCC78D96BA +:1058300081E754BADB20F6F584280BE6F3F1D4F5C2 +:105840006ECCE77A1DD6EDD4E17AF4623DB00F5DFF +:10585000C47A22FAD1FEFAD7CD143BD205637E89F1 +:1058600097CC2947EE7FA1CE13371AD7FFD65F61B9 +:105870005C2909E508ACF367FB2799914FA3F7F181 +:1058800042BE88FB80BD8CFEC34C1FE7DFE646BFEF +:1058900084FE940D61DCBF43F6605CD46669920CB3 +:1058A00011FBB539B89E9ED9E8DF8F7265667982A3 +:1058B00082F43D8B75AEB572FE3E980FEB2B62FD08 +:1058C0007F163671C04E7CFE99F74EE2913A5867CA +:1058D0005531EACFC7EEA5BC89CD8FCC3C8CEBCF40 +:1058E000743FB93F1506F47E2DCE7D3E8F6F6577F0 +:1058F000C89ABC872CBFACC98BC858AC6D077AD08E +:10590000C02A5DD9A5D529A86F7409253367A09D44 +:1059100092A423F90E724A9A1BD31E8DA22B817F6B +:10592000F57CDECDCFA773B359F839B05EC57C7373 +:10593000A2D8AC7A4E306F33B07932D07D73AD3EA1 +:1059400024A11F8FFDF132B2970DF7260E3EA7ADB1 +:1059500006E7CC1928A71FD45929AF2A0AAFA06798 +:10596000FE99FC9407D3A81DEA6533C53D23D6AB49 +:105970008F056BCFE34AFD3B5878CE0CD7E0FA4C4D +:10598000C7DC99A8673397323AFFE8F6A247B5E734 +:105990004A7EEF788CA3B150F8079CE74CC7F65AC3 +:1059A000B4EFA3CF55A5BB9C61B1F5C223055C2F15 +:1059B000E42428A7EAC8AE90C94EF066CBC323FD05 +:1059C000A4EFF2B91F30E55716D243EC6373081FFA +:1059D00055C25D3F298673A8EED3A1FBC2DE3D7E92 +:1059E000E0E999504EFDF57B4DC7A0DFD4EF2CE3E5 +:1059F000B07E37EB9E8181A0E06103F98D6BBE7CA8 +:105A0000A5150344CD8D4C41BDABCEE328E0FA6E25 +:105A10008F21E425F95A2CB36D2407D9C54B11F415 +:105A200002909EE887B7316F632BF991B6FC12861E +:105A3000793CCDACF30ED297678D0CE3AF37363897 +:105A40000D55B0FF1B1B9D86F9789F21B33AB423F7 +:105A50006E6A50A8FEA64685D79B79FDDC060FD559 +:105A6000CF6DF4F07A0BD45B300F29D41580716FB1 +:105A7000B6A43A75781FD0E8E5ED174CD47E1CFC2F +:105A800001CC278C8F0B91BC6FEDD1F17B237F7CF8 +:105A90004882B59A12CB0E3B117FF7E8145017CC11 +:105AA000942D332BC0CF3678437A687F8E853210A1 +:105AB00091BB1736790BA17EB743B6E2FE76837BA6 +:105AC0008BF947C1A532E19DFE00DEBDD841F73A12 +:105AD0005B45FC3EB8C44CF166B07528DECC9664DC +:105AE0000A3B86B7772CB086D01E033948E7D87BAF +:105AF0008F4C7600C8C3A36EB48B76E62B189FCA72 +:105B00005CAAE5B7F4850BAA68BC4666453FBDBEF6 +:105B1000918FD7BC5317D2A15D65B97126D241F3DD +:105B20000EA6A03FFBECC253B5C310EE50142E3F9F +:105B3000B472A179E153479CB81FBFCE5A40FD799A +:105B40001CAFD95FBD5D2F0DF0339DB773407E0C48 +:105B50009637CA611C27635EB582F1C174D827C627 +:105B6000F33B8CBC3E78A74CF72DE90BE5B075F400 +:105B7000007F670B14A6231F26917CD1F0D7C89D08 +:105B80005AF879C1A7C0EF32EE2BB89D513E67D1CC +:105B9000766D3F90933A9457D9EDDAFA5B8BFAE33E +:105BA000021A3C44E3D9E6E7722F7A9F03FB0AC747 +:105BB00015D1BE747C5F28D7A0BED87280EA8B1B3B +:105BC00065C5E94479D7790AF75FB453666180EB1C +:105BD0001796CD447AAADFA4A3F0C8F5AC8BE4C233 +:105BE00095F6ADC63BA2F719BDBFEFF2F55C8EA8E6 +:105BF000F6E01366B207DB1EB6E8F09E15ECAD7852 +:105C00008C2BDC55541D2C407B40C81DC3253D9773 +:105C100027CD16A25383ED517764FCA16554F5138B +:105C200005D46FD88D753C6E41FB8E96633F17E3AC +:105C30004DEAD6E6E35DDB131F953FA6CDC79B7209 +:105C400021332A7F2C2F2A7F6C94A67DAA755C5461 +:105C5000FED8B551F963351A78967B96A6FFF5CA3A +:105C60004D1AF886F23B34FDE778EED6B4DF547770 +:105C7000BFA6FD66EF4A0D7C6BC35F6BFADFE66B78 +:105C8000D6B4DFB1F8279AF668FF492D771570F979 +:105C9000BED9EE3F49016CD0F791F73D6A99DE28F5 +:105CA000F7469E7B5202B7A7A2FBFDB980D3FB8BC0 +:105CB000129F8F05ED9A781CF3D835F1BA7045859F +:105CC000B91BC6711A95DF21DD62E20EBFBFB66B4C +:105CD000EED9F63F0EFD60BCA6C45C1BEA3B8CFF10 +:105CE000FA40B9378774745F615BBF4A223DB86977 +:105CF000158FAB5C30523CAF7F1DAC8EC6FB46DCD3 +:105D00006BA9EBEC1071A42D18474285E49941FD75 +:105D100056C6F17E3F4D57E38E3E1A37A3DC18A4DA +:105D2000FCBC857E09E3C0CD3E66C57B9374CB0287 +:105D30009AFF9B0625995D262EDA16B0330FCC67A5 +:105D40005F155C6384BD7D52D0F7D4B3F0BCDDCF6A +:105D5000281ED35BF0ED53188FE943E108749D21B1 +:105D6000733C3FF7C0EECF5F81F9DAE6A597A15CFF +:105D70008D6ECF5ABEF7EB4397697F6ED95B1FDEFE +:105D80007BB9E71FD875BA25A27DC838694326F3C9 +:105D900044D001E02CE6FD805CC8F5F9F20A23C589 +:105DA000B1AE01FC1502BEBFAAF8CF893BE0B93FF6 +:105DB00039FBEE443B1DEA65AC877E84D73FE59F07 +:105DC000A3FC929C5160DFA3FD1D179B6EC715724B +:105DD000BA956D8DBD18076A4A343AD1CFCF32BB20 +:105DE000CA3E1907746DE07E75B4FFFE5CBFBFDD6F +:105DF00049FE779118274B947A2B7F9E99834C4EBE +:105E000017F71431F0A14F6A97505E652E943F8DBD +:105E1000E48BFD89468A23A45B44DCC1B258131786 +:105E200050E306FB13EF9590EED3C34B289E8FF102 +:105E3000021C6F5CA193D6111D2FC832E7D3BA861E +:105E40001E9FF5D7274831E6895A871A9F889E27D3 +:105E500084F604EA9965F1644F44EF7B4961557912 +:105E6000E170E4D7DE93D3517E9F32903E1C8A5E70 +:105E700030CF3C1431FEB442EEDF63FE78643DE681 +:105E8000878722E3D9CC41EF2B100C2A6684B17BA3 +:105E90004311CE7794CF77C2A0D8C91E04B587FE30 +:105EA0005F7D21D703D330976D38F219F7CBDB81B3 +:105EB000AFB1DC12B0927DD601FC87F00B012795C3 +:105EC000A1809BCA6D0185DAB707CA097E25E0214A +:105ED0007847A08ECAD7025EAADF196820F8E701CA +:105EE0001F959D81C554FF46C04FF09B81D504BFCF +:105EF00085F66001C6A9D753B93BD04AED7B03EDC7 +:105F000004BF1D0851190EECA0FA03814E820F0642 +:105F100076117C281026F870E0309547035D547F99 +:105F20003CF001C137E33EC9AE58DF15C078854F5C +:105F300076A27DF7AC6FA115ED6BFB7C9D15C57945 +:105F4000BB4FB704E31C1D8DFC1E13EF23310E0461 +:105F5000766808ED39FBFC678E4CA5F6B9D4BE19FE +:105F60008704A7C4B682DBAF6C9991FAD930210AB5 +:105F70009EEB58DA18D203DC5A184FEDB61532F9F9 +:105F80006DCFE9FC2985DCEE22F96D3370FB41A56C +:105F90008335855CDEAE29E4F75C1F16F1734ACACF +:105FA0008BAD479E2D54EDA6F587717FF679B03FF6 +:105FB0005CEFBC5566BC97B5DDA3B3727B93DFCBBA +:105FC0003A60BFB87E580FC585D97C6E2FDBE6AD31 +:105FD000A57539E6DF48EDD6A24753D04F6FF7AF2E +:105FE0009A43EB6D9429AED9EE3B9082F76CCF8942 +:105FF0007C27DBF0786FA864F07A9E8D5A7F07E3E8 +:106000007E8303ECA5D763EC03D36E49CF3011C771 +:106010007BD41C338ED729E8D72171FE630FCAC405 +:106020007F2F30B0FBE0B92D60DF05510E54BFB6B5 +:1060300002E355BD85BE9D28379F778E3F20039C88 +:106040005AC7C7CF5D25BF8276349CF7E72D50BF76 +:10605000E1BE4D5E5CEAB04DCE35C86EEDF3DFCAF1 +:10606000C0F89743D29E8F5ABE2DF6F982878FB71C +:1060700065954CF164DB8A375D07F9BCBB91FF3352 +:106080008B3E8AC3304CDE5CA70E4586639EFC3592 +:10609000CE1777FFA63A42CD268F3ADF589CEF6A9B +:1060A000F134E2B15A9B2FC6BA869227579223BF8A +:1060B0002914EF8164B12C9423CF19B8DC0A9EE433 +:1060C000F62425054D1A3C8F9A2FA0E60F44E70BC6 +:1060D000FC5EE029CBC462DEE77ED64FBF413AD7F3 +:1060E000173C1BBD9467E3923149873519D8127A62 +:1060F000EFA72ADEBA26063DA8E55328C700C11F30 +:106100001632712E9BEAF8383A3ECE64B682E02A07 +:106110008B3518435EABE533629C7F2BE4749B7533 +:10612000DFCE0D87F07C8F1A28376A8B2EB401FDE5 +:1061300084E0093DC9D74C7DE7D65722D6F51741F3 +:106140009F5B8CA162BC876E87F14A50AE22BF94E0 +:1061500050FC82D547E05D7DEE3F841DF0FCC575A7 +:106160002974FF3C6F6D1CDA47EDCC4CF46033F8BA +:1061700053C646D0830DE932067D388B8C340EFC35 +:1061800059AA26E2BD0CD7CB35289760DDFB162631 +:10619000913EAC99FFDEAC310057F6C994CFB265A1 +:1061A00029CFD39CF4EF3ACA1379FB31EEF75DF7B0 +:1061B000502DBD9F9421CA67D1CF83B2723D53C287 +:1061C000702E950B2D14BF997C413E13E9A75148C1 +:1061D0007A3CFA173C5E736DAFAC790F6D528FB697 +:1061E0003F60548F764646B7B6DE3EEFCDD353615F +:1061F0009EF6A5FCE1F68BBF3B827070958EE22483 +:10620000EAFB64509341F14D399881F99B1BCC8C8A +:10621000E4B96DBED98AF2607F7A3CC9BFF6DB2C47 +:106220006487AECB6F8A433BD9346F550A96238C73 +:10623000C1AD183BBDE6D52D37D92791BC55F355D7 +:1062400082AC1CEC81BB8DDCC8093EF7F45419E527 +:1062500025CF6799F4EA96A783F9D8AD95D6E1D40E +:10626000B14CBEF97EF876BAB796B8BE701AA11DC9 +:10627000E079A37CD715417B465A703F366DB69CBA +:1062800069A47C6B4C3282F90D0BFDCC88F58D65D1 +:10629000E6483E57F9E4FBF27F3CC687875F590E1C +:1062A0005C69DC2BF17B413EE79BA1FC69D310F2DA +:1062B00054F58F1F29E0FC8B6C4B7AF58C31A67D51 +:1062C000F5AB22CE67E5469EA732BB615A1DDDC302 +:1062D00004BB65CCE77B51DC0BB5A727D23D717BB6 +:1062E0002E0BE3BD4170818EC77BD2F87FED8DB957 +:1062F000141F6A93FC29C13CCC97F0B9F0FCDA0179 +:106300004789307F5B0E97EB2CE4B7E27D358CB389 +:106310003872FDE0EF05B574CCC81EA6F8859E78EE +:10632000CF698C88B7635C1CE317D1CF4DEED5C223 +:10633000532E68E12A66D0C035662D3CD5AA853734 +:1063400015713B7DBA5D5B3FC3A9851DD907E37419 +:106350003CCFDFC222E249F0F75E7E441C68DD6874 +:10636000FE3E5F76F7528ACBB6E5F0788F639536BE +:10637000CE91C54212E22F7369543CD6BD663F866A +:1063800097ED0BA3E341FC5E02F0A1A947318A7CA3 +:10639000F0EA689E87DE3DD2B7BD08CEB3600C5FE1 +:1063A000C7AB1D4D743FC5DAD388AF5C225F69B0BF +:1063B000BE7C8AE8401D0FF92218B17FE48748F8B7 +:1063C000A151BE37701EE48B60A4FE2CE936D0FBD1 +:1063D000AB62BEA1F843E5CF72718FA2E6DDF4890E +:1063E000B1D4BC9B55225F705754BE4E9FA3361943 +:1063F000FDE7BEAE95F1B1F810F92E68E27C88E5B4 +:1064000006917F837C182CE27C88F5A6EF56786392 +:10641000D98B0B055DDCBF63C9864F22F6B7AC7321 +:1064200085065EBEEBE10D91F951F7E33F3008BF01 +:106430009E517EED52B19D2F4FFFCB2BCD0CCD4801 +:10644000DF0728CF96159C31F27BA75E239EEB4297 +:1064500061FF99CCB3F2D12FDB11E2F26C9D88374A +:10646000345B1533C681993B5513C750E3114D4B2F +:106470005CB654D847727F7CC16BA57CDCE1F91413 +:10648000DF48AAF1DCCEC632D653649C6B0662DDCF +:106490008EC156C0E9F957D93341C7C0BE4D17F870 +:1064A0007BC9FDB0EC67248F2EE468EADB449CA333 +:1064B0009FBF2D0BAA703E8BDB49FBB031FF1A1E2C +:1064C00017D4C6D14CE23DE7C1E33B34F56D227EE3 +:1064D00072E5F1B57139D385BC21C62F8C1ADF1A4C +:1064E00073FC8171B5F1BDABB8374F714F183A2EBF +:1064F00036D2CDE9699DDDDF85713183E07F6606A7 +:106500003A9988F280FFE9E3797EAEC1A18D8F19B7 +:1065100030AF0BFA3F97B898E48AFA3EB5FD99057B +:1065200012CACB27F0FDE8A4C1F2245A8ED844DE6B +:106530007CB41C81F93470D3C35CCF364B8A0FE531 +:1065400073F47EFE7FF1877589E3BBC8AECE8E778C +:106550009A2E630FB7058263F1B975F1FEC578070E +:106560007EF78E91694F94E37BEB8CF86CC58E2996 +:1065700073310FB64DF0EB13693AA2A7F4DBD3B732 +:10658000EA23E829DDE873A13D9CAE13F95FF887A3 +:1065900071B427D2B76D8C31BF6AD7A9B0AD01D61F +:1065A00011718E6DC29EEE9FEF8ECCADFA8871D2C6 +:1065B0004DBEB1345F7FFEA398AFE587CDB759C418 +:1065C000C3D4F96C776AF76733FA697F36A187D449 +:1065D000F936E3FE62F0D515E713FE75FF7C7769A7 +:1065E000F76733F9697F36F53B1BEA7C2D3F6C3E3C +:1065F000BBE0CF76F1DE973D9E7F3764A8F7239A04 +:10660000FBF3CCBD66942FED6ABC50E8BB7351FA26 +:10661000AE49E83BF5F97369B914FF3D77F8267385 +:106620002C3D87FA8D093B93093B93093B13E1D934 +:1066300035A7570D077AFCBB1D37CF9541AFCFBEAD +:10664000FFF4F81C80DFD9F18BB932E8A9D9AF9EED +:106650007E330B1E29FEDBFB38FCF4E93E07B45BFE +:1066600082CFCCAD05386918D7CFEABAD57977B9DA +:10667000B95DB97C751E8F6F829C453DD69CE367E2 +:10668000187FFCCAD19B341FFA2FCFEE4D5F100349 +:106690002F6AB97C75217F1EADC08998CFC648AFDF +:1066A000DDA8BEC752A77D8F25296923D987712C04 +:1066B0006445399660F6D0FB97D71673BD70335397 +:1066C0001AB85FE12C10791CF4DECB4DE5625C6BEF +:1066D000E52FB1FD669DE709F477FF79D2BCE1684B +:1066E0003EAB7973A306DE3BDDFE7DDE4F9EFDB142 +:1066F000C46DE5641E8F9936CAC9DF7B8B882BA2D7 +:106700005D3C143E3F7573FF7E009F1E8ECF540F7D +:10671000C7A7B537690D9CFFF294DEF4C7894FC354 +:1067200031F13508AF51F8FB939BA97EA01EED888F +:106730002BE15BC5AB9A5FD82C390BC85E67199A01 +:10674000FC60C61467AC7B1EA4CF483D6BB47B19BC +:10675000DAA38634C58DF9EFCD7FD1C7CCDB7315B5 +:106760008BF85E523CE57D362719C91FDF9F3493B5 +:1067700061FC59B64C23BCD426D5513EA67E18EBFD +:10678000447F353A0F5D9F7C3BE509E96DE8614048 +:10679000D99FC7EC31235FE93F56925D4800579976 +:1067A000872E5F290F3D7526CF434F323A315ED891 +:1067B0009E688C9987FEAD9BFB5DFB717F69B81F5E +:1067C00023FF6E88D8976CE5F7EE589F00F546AB2F +:1067D0008F51FC5DECFF5B6107A9FD4D563F43F90E +:1067E000A0372A4EB45FF4A95C7FE0775BDC31E22E +:1067F000285FBB0DF4FCFDA3AC5CCF99B9DD3EFB7B +:1068000037B1DF27282B9644BC2436DD0D453737BA +:10681000EA78DE9DCA97732D46CA079C6BB1D3F701 +:106820006CE60221F6A446F4BFEE56FE3EB5ACD8A7 +:10683000919E7E7BED945FFE96E1B50097DBA766A7 +:1068400018E8BDC25312F328A983F35DBDDE94A9F5 +:10685000B8CC1BEA4FAF45762C18C3C84E7A75C129 +:1068600043AD954EF28FEA8A919E7D73A6A20F7773 +:1068700063C3D877B1FFF2042ECFD5FBA5E509FCA1 +:106880007DDE6B64DF6CECFF55C51749D5485F7240 +:106890006F0EAE2BA23FDD3345F49F5B3C81FACFF8 +:1068A000E6AFDDF5D27739CEA59DF9C8C7E87CEC17 +:1068B000B1EC29F4B758E4BD86901FE87745D6A31C +:1068C000BFC522CE535A506EEB8E214FD432C33EF9 +:1068D0006EE442A0D78C8CB154AAF5CF7AF475A19E +:1068E00018E7FC9038E71FECF7B4C36A270EF83DB1 +:1068F000E0EF3C84F8F872E1A9F4F1B0A5076ABFB3 +:1069000026BFC76EECFFCE16F97103B0F6BEB32DED +:10691000D05B8CDF196088878911F98B62BFF625FF +:106920006B52D0EF81B3F420DD7604BC236B0D03F2 +:10693000CFBF2CE4080B16D2F306B12E475AEB0C4E +:106940008CBB382C3ACA7360CCAA9167736A53A681 +:10695000A6A10BBB9C291627FAF75DE41764E0FBA0 +:106960000D189F7CE73686F75F59699D12DA75FD31 +:10697000F388F7C657897BE13E5F2DED27C3D6EF3D +:106980009731F25FD38273506EF53DC35794F19205 +:10699000B6DD91C6F31FEE5D181F7202BD672DEDC7 +:1069A000C24F4FB00C70F830A69F71A9D9D5827232 +:1069B000E657091477D6B7E7B320C8FBB0ECFB1B4A +:1069C000C277C8F9902E4F6C169E5BB6289EECB924 +:1069D00076A97506F931F7E858AC78D1CE62EEA702 +:1069E000FC8F622BBFCFB54FE4F4631F3F72E1B859 +:1069F000ABE7FF77849EF949B293DE7F52EDA34D5A +:106A000043F8478E913A215F845E11F833339F1922 +:106A1000F9452F7979B074C76BAFBD96CEE8535B5B +:106A200048471B84FDA38E139F1FA2C678C543F25F +:106A300052B27AB8BEB0FAED4138AF75DFE963CE35 +:106A4000FF85A0FB35D90FD9B17FADD3E7C632FAA8 +:106A50003D98969C7BDD783E2D33FBE995ECBA960C +:106A600033CEDF613E56F028CF37D89F5D68C3EF45 +:106A700041590E1B64D365E2F146D027CECBD8191D +:106A80004691AFDE7280E799B658CABA30AFA1C559 +:106A90009256466AD8C2F356D5FE16CB21D20716B7 +:106AA00085DFDF5A507F48B84CC04709AEEB10E194 +:106AB00043ED7750C85D8B1266F85E5A9CD24AFD52 +:106AC000CCB2D78379CAE63446F744662BF017E296 +:106AD000355FC7CC31F4C9BE62AE4F5A4ACABAAAB2 +:106AE000697D327EB98EB5D8CBECA4E711EFF07C8E +:106AF000738696CFBF137857C76916F9B477AE4E31 +:106B000009D68EC33893F71BA4E716CB027310F592 +:106B10005AE2F8CB8E671A39D478FBD78AF1BE4394 +:106B200079AE4F2CB3E27806C6F7158DF7E1629C7B +:106B3000FFD5FB7BC02CBD474D301D58D81EEB7DCB +:106B4000ACFEF313F7F2D1CFFD6079BC561B870280 +:106B500079EC1E09FB5A5672E65035D5F0F8D30B86 +:106B6000C29F51FD927431F60B127FBF3F28C52B97 +:106B7000F45D0CE1A7A4C769F130F03E2D3F876FAB +:106B80001A781EDE37694C7C874ECBD7DF1CFF3866 +:106B900045939F057CEC31713FC623DEA7F588380D +:106BA0001DC2186FA0179D04FFF7C7891B9C3FC328 +:106BB000EFAC99408EEB605CC9E127FA3639BA5DDB +:106BC000C8EF39E2FB0FD178FEC9482EAFA5477A4E +:106BD0005C78AF519BD69B118BDF5F7CF84206EE51 +:106BE000E7C519FD793B74DFF4E269E7E602C4CB3F +:106BF00011EDFB6FEAF84D47CEA7F822FDA5C0E5E1 +:106C0000DF2F4B3AB37125D98D0BB8DDF87FFA7DB4 +:106C1000B317E6733B7597A495CF4F08B91C14FCC6 +:106C200060BB20D3F743EE2AF2AD403A6A93AC0B37 +:106C3000502EE73CCCF3F29A1E5BD5B328067FB406 +:106C40008CF2FDD5C808BFBA7CBD91E45EB3253790 +:106C5000F972F728439FBB9FE4947ADE558F9879A9 +:106C6000BE8A8FDBD1E9BE7B290F263A3F65A87E1D +:106C7000D5239D440F6A7F138E8FF2C57223C515ED +:106C8000CEA18F81713B2BB733A2D75989C898C049 +:106C9000F163067D997460491C8E6B10FEDC0B6AF3 +:106CA0005CA4A1CCEC8978DE705B99B93A824E9AEB +:106CB00019CF0F8E1EFF372355FB22ACB1630CA8F2 +:106CC0007F31C694269FED973B6478F2FCB4950320 +:106CD0007CCCE30E43E7A3C571BE2D237BAC0DF343 +:106CE000D2C00E5ED3B06004E2B74DF6BD68033C7F +:106CF000F47E68A23CEADF0B3EED167C3AD4F9053F +:106D0000D90130D2187B9C1DC497E2804EC6272340 +:106D10005F34E7EBEA4231F6795CECF332F67878EF +:106D2000E4F7B3C70F89FE1A7B1CED6D4FD4FD4607 +:106D3000248C76B627863D7E4212F105912774C2D7 +:106D4000E0DCD50D7839313999BE975690C0EF5DAA +:106D50004EA07F52067EC8ABA7F3D17E992DF57F5A +:106D60001749F8438C60F047FE05F9620EF3BFB691 +:106D700048223EE2F735781B9F7EE573DE3692D1DE +:106D8000BA36C0F9E1FD46DBC5F93362DD67A48E92 +:106D900052FD37506511EF13333C9D88FBAC41F732 +:106DA0007451F772786DD39F77AC1FDCFF8672ED5C +:106DB000BDD9868B3C2E625AC2428F4B9897AA6DE2 +:106DC000BFA9CE107D2FA8B94FBBD96B885E0F7DB0 +:106DD00017D421D69BDD711FDDBF4FCDE6F944A648 +:106DE000658CE204D1F76DA6B15D1E3DDACF0D8C46 +:106DF000ECFDE83839E6A952FCB081B12D12E579F5 +:106E00006BDF7379A6FE73FE7D94D63A9CC70E762F +:106E100010DAD3D1EF49A8F75AEAF751553CABDF66 +:106E20008F4ABF4D47EB63C129D4AEC6FDF17BB895 +:106E300055E911F9E42B587F7F7A7F2B187BDF9B74 +:106E4000DBEA29CF2073BC7F6C189AB2144678C84D +:106E50005AC8C86F003C68F2094CD9DB699FE71635 +:106E600033364C223C68DA3340D3D3FDC0426D7ECA +:106E700001EC530347FBAB57F2534DD9F99795F308 +:106E8000578A639AC4BDE49451E2FB97A5AC14ED14 +:106E9000A2F4DB9EA1F33807E781715F749C62DD89 +:106EA0003B6E82F1D18FFC77C12FCDE26E5BFDAEE0 +:106EB0000FF3C8F41E9B54CED72C0DF3F27BE912CE +:106EC000467C6E8A6766CC8F972A4C1EC4BBC90469 +:106ED000306C5932327306D4EB453C7B8DC46484EC +:106EE000995531F3F8A3FA5DA1107D5768A879D4BC +:106EF000EF2BB2207F4E9D67D077F52EF33CF97BC8 +:106F0000D6E8E76B299EA9CE3F14FE87FA8EDEBF36 +:106F1000D5BC3781C7531D44AF8D03F44AF07C4183 +:106F20008FF83CCA85BBD5667B5729FA0F671E4C84 +:106F300050364A11FB08CED2F3EF037EBFF1FAD7E9 +:106F4000617792BCEFDF9718EFFBEE8BFE22E4DA5D +:106F50003A7C5909F35E1A19E531A4FBAA3F972937 +:106F6000FF00F6A0911311DF4980F1D63DCEEF1F4F +:106F700036E3773EF0FEE7C040FEED13166CF7D126 +:106F80007736D4BC5CCCA35D5B32F03E72F47D837B +:106F9000BD11C689986FB2990513409FA4F43105BD +:106FA000BFF3ECB96854A6037E6C7DA05001BF937B +:106FB0009989EEA52AAD7E33FF0EE10A166967EFC7 +:106FC000976EA5EFBD86BF6494BF143ECF88EEC315 +:106FD0009FC3C4702EFFF8DDFB7AE4CBA97D5D7AF8 +:106FE000D4F393FBFCA47FF6D94F3DEDE2E7629921 +:106FF00011911F751D5B54CFE98A9F972CEA275F7B +:10700000306AF8FDDA5EA3461EC8175BBE46FD6512 +:10701000EA89AA67D33FE3E3F928DE2DDBB5ED5318 +:10702000443ED0DB2ADF5FC3AEA173BC981633CFDA +:107030006EE0DCD5736EE27174C6C7796E94F79F0B +:10704000464D40FFC04771E864C42FD8172995DD2D +:10705000CC8E7958E54C998E72BDB2F31DA487E4AD +:10706000B33C0F3C7AFCFD5FBE95857EC39EC99DF7 +:1070700059682FEDF9F2153D8E57D5D3CBB03E1997 +:107080004A1EA4584C78AA10B43350CFE34491F56B +:10709000B49E4AE765E5E4CF504E1A876EDF33D9D8 +:1070A000C2C2E4877526A03DC77C7CFE64B3CA5784 +:1070B000EC2F97705E84819FF654EA526A619F7B41 +:1070C0009E91156CDCD3F34602CEBFE7EC39CD7A46 +:1070D00098FE22F345ACFB5A71EE532B7BC9FE7E22 +:1070E0004AAC2BF96C2FC5A15395DE30EADBD4C333 +:1070F0007AFAFE37B3F0BCC8614CA1389ABA5EFC8C +:107100006E2A3ED78272DE88FBB3325628EC7E2888 +:10711000332A8355988F9ACC764A486B532B7D41FE +:10712000A4E7E4A59C9E93ADFEC318BF4F5EAFA33A +:107130003845F259DF06F4CB92CB6505C9E44AF82D +:10714000EC10F3B78AF9D4F9D5F58CA8F44BE87EA6 +:1071500024B3E362FEAE2A138EBF5ACCEF14EB5970 +:10716000C5E83B2CC967AD55E82F27839D41DF3328 +:10717000B8E2799A35F345B7274FD99945E7E0B199 +:107180001ED90AE3A5645B365441B9CEA123FF3270 +:10719000A987513C3DA9279DE47D524FA128278A0C +:1071A000FA69420F703993D4F3502DAF6FA1D2A476 +:1071B000CA17873F8CFB98DACBB87C717849BE98A8 +:1071C000D2B87C51E9B856952BCC5A321FEAF70F4A +:1071D000FFACB5069E7BF773FEFEE5BBD95CBEBC7B +:1071E000FB25F7FB4D69BFD3A35CAA42C305FA4D4B +:1071F000BBC0ED33951FABBA25361148639A83E7C0 +:10720000871FBAC89F3B84D9D500AF6312C929959F +:107210006E6B05DDAEB3EA8349D8FE8189DE773433 +:1072200039CEE598C11EFE83AEF7417CEFF8F73307 +:107230007AEF5D41F5827E434B492E9A846C39E4A6 +:107240005860413E847948AE1E7218E9BC0E083A77 +:107250003E67AFE908C33F5BCCDFFC693ED4FFC1AA +:107260009EEB40934C3D971E412F5F88F33B2BE8EC +:10727000A629DD7B53C904FCFE621ECD7BCEFE0D2C +:10728000BD7FB2DCF61F9FC6FA2EA73A8EFA7C4F5E +:1072900068A519CFF5D09B1F9F40B4ABE35F237B5C +:1072A000EFE4E37E339AF8D0123BCF7890FCF3AD55 +:1072B00088967F8B4A860FC8BF7A6691791E12E73F +:1072C000EB59421E4D55B8DD5E6FE5E7555FB25F85 +:1072D000A6FE8A8BF655AFD28DF2E45AE47F9BF27C +:1072E00024D14B7D3EA797BD829E0F0A7CCEEC63D6 +:1072F0009DE897ED2F986E190BF83EE2D213FF1C14 +:1073000019BBC65206CF1D2995F04B026C7AC9D61F +:10731000B5A900CF5224A2A7FA92AD1D4DD07F96F9 +:107320003541A903F8E8F9B31634AF0E05BC8497CC +:10733000E972F8E354179E1BC7D3CCCAB08CFE4F3A +:10734000BD63BF8CFAF66DC4AB11E32E1EC1677529 +:10735000041F576A2CB88F23A526212F3DE3515EC9 +:10736000CECA37D58FA1757C7D6C4C1ABE776F5015 +:10737000F8953CA7FFC9827EEACC276B53A0DFCCEF +:10738000926619D77BD42C91FC3CDAD744F993C789 +:107390003B39ACD22D3D077479BC6F5B7312B66F6D +:1073A00097483ED52B2F1DE2EA8FD3A73A7E0F0BCD +:1073B000B6E17730CF29AFB7603EF5B1BE05CFCC8F +:1073C000013C1C7F533FC4B84D1FADC071DF4C243E +:1073D0003A9E6D3569F4B18C4E69845EAD1E6FD3F3 +:1073E000C0F54A0DC5D3CF2992E50678DEF35DAD31 +:1073F0007B3991D152DA77BDE87B4CE17C79CCA125 +:1074000023BE3CD6F7B89C8AF05946FB919976DEAC +:10741000FA921AB2AFCE295BF54467820FD5F154C8 +:107420003A3E8A4F231EED9CFF8FF66DB320BD1DA3 +:1074300075BF23E3395D67891A57D0A1AADFF05DD4 +:1074400071A49FDA51FBF37E86EB5138FE6B94D723 +:107450008F237DD53B64A2A7A3CAFE9A1486BF27BB +:1074600062D2ECFFFE1DC99AF19775DA3470B45DF3 +:10747000B5CFFDDBA7CBC40E66A447D847F9C23E03 +:10748000D21F77E0FAAE681729EBE8F74906D9452D +:10749000F9DC2E8AB68754BE6ED689B8AC8EC76525 +:1074A000A3F9DF58FAC3EEF1D82A498EBCBF5BC6F8 +:1074B000BA7390BEE6A31286F11ED075A723FC1501 +:1074C000EB6D8B07397CADCC7669BFBFCABF373F48 +:1074D000BED4771EE59574364CDF6165AB18E507C1 +:1074E000E86B789E115E66AD88D48B25FDF12D8DFD +:1074F0005DA44BD89B8578AC386BE4F18F9EE8385F +:1075000097EA1F8525F22BAE522EEA93F9B87BE657 +:10751000F078677F79338F931509FCE5941A695DDC +:107520008A80F7DC16FB9EB5A454FA41F9A2DF0766 +:10753000DF2980EFAF90E6619E3D55B1D79152CAE9 +:10754000E3B5779778F24AA12C2AF11596225E3D91 +:10755000605FD377C53D649FA9E3BC33CAE316FDE2 +:107560004661C9BCDC0E8FEE07ED63689C86D8E3EC +:1075700040FB387A7E6EECF643B839FC7D23FB3055 +:10758000D243060C64A6F2522AE3E516FAAE468808 +:10759000FBE70D1ED2F34691AF88371091FCC7F47C +:1075A000F534BE1C9E41F7582DD82583FBF9917602 +:1075B00094AC846A22E3AD6AB9A894DF73CE28152F +:1075C000EFF34C6013C8AFA8BCFC3CEAF343CDC357 +:1075D000EC6557C87B5EF363D349FAC3E4275FA524 +:1075E0007D600E4A91DF391F6ABF894A941C8AC2A6 +:1075F000D350F35CED79DC22E8F66AD75D657ACC8E +:107600004EF9D12ECE076B057DF5DBD53F1E3FBE73 +:107610003F1F86FECAD9FBFE93F87E4A4268A53713 +:10762000C67E5E14FBF931E5C1D370CE1B8CA1FB85 +:10763000D1DE9907A76302D27BC7F2F1F005B09EB5 +:1076400037C5FC2D9695EB6F85475B1CBA98F91EE4 +:107650006FFE787AA20D3FD9FF95E3DCFB6D20A782 +:107660005B1E7DD0ACB08175306BD915CEF947E388 +:1076700013755D6D5B305E624DBDAAF7145A5CAF49 +:1076800024E07D69EDE74D76FC0E46B43DA0C6438F +:1076900054BDA5C64D54BBA4C2C1E31F33EDFC7B52 +:1076A0003D15F669A4DF0FB2AE1AF2AF303B6D2282 +:1076B000B10AFD19DD5AFBE43ABF57463B2ADA9E70 +:1076C000A84D3345D907BD7A94DF1517B5FD54FE93 +:1076D000F8AC54C45154791765479ACF9F4940BBC1 +:1076E000EBED0B67282E148D9FEB2E5CDE9FBDAE5D +:1076F0005D4FF783D171ADB72FE4D2FDA011AF1B61 +:10770000C1D4CACC3FC48C80974C7B6B9511EC18CC +:10771000A38329F8DD36FC5833C60D8D17789C7C81 +:10772000849DFBD7898BC12F85513395A07DC1786E +:107730007CCE48EFD3995DEF91BDBD09EA86219ECD +:10774000C79E19A68B110753CF638AC0EF6EE6B7A9 +:10775000E3EF814DB18BF7F72E46DB59FC3C2DA2B0 +:107760007FE2622D3E2DE23C27835B43DF79ECD341 +:107770003E6F11E76B591AFB1CECA3639F43A27A7F +:107780000E13B6C5E1396C59BC4D8A750E998B2F15 +:107790007F0E5B845FA9D2EFB4AC04B2AFF7A6E86A +:1077A000E8FB417B13C359CB31FEFDB299DECFAC70 +:1077B000107136B4A4109F6BB797BF8471DB71A3AF +:1077C000F5748E7B25D1FFBC8EFFFE60CF78EA1F5B +:1077D00027B383F8BB8007FBAAE9BB1BD1FCBBD353 +:1077E0007A00DD33B6CEB93D6B019C8325FB8099D1 +:1077F000FB9B83CF07EF3F4A05BE4B7BF8B954A6EE +:107800009DD4A3BD5EF266ECF351E38F7BA49D3A59 +:10781000202B36AAAF8BFC98913BA3ECE9B32D64E7 +:10782000675BC647D5F7C039D1BD8E9FEC16D9A18D +:107830003DAFEB8738A74A1187307F7D8AE265FB31 +:10784000FA4E717EE9D1C62527F75DFE9C5E13E7EF +:10785000B453C4A17E2EE2009DC27F7E23E0A4F239 +:10786000CD809BEADF0A2804EF0A940B61C1CF7731 +:10787000563ECB4717AFAA84FBED47CF73BF7D7F42 +:1078800062A883BEEF74DE42DF17A4BD4D14BFDBD8 +:10789000077C722CCE49BF1F7834DB4CF1B3A3A513 +:1078A000BFFB7B8ABB7C6BD1F1B80BC7B37A4EEBC5 +:1078B000704E186F5D858BEEA536E04714A1FFEE84 +:1078C0003289BEFF341B0E04EF45543A37F569F197 +:1078D000590FFF6595F1DF1DC8427F618C8BE8A4CD +:1078E00042EF73223E37BA4F915F1E57D8EE1B8787 +:1078F0007180F17A26BEFB143445AC3B0E6F42E03A +:1079000079538944DF731A0ABFD1E58654AE2FA399 +:10791000EBFF7534D7831BDDDBE83C773BBAB25015 +:10792000AFEF13F910B3642948BF5F2877DDB11CAE +:10793000F65B91651FBB11C02DA35368FDFB4A4F39 +:10794000531CF8D88557C621FD1DB3765A30CE7921 +:10795000CCC9DF53871395F97BB79DF22D31F2A483 +:10796000D5F258E922FAFD957FFC7CEFDAD17CDF75 +:107970004C52F50A8C5B81FB4D42F9DEB202F9C331 +:1079800098B983FCCCE873AA705FB388DEF364FC1B +:107990007B4FBFB6862C783F1CED67027D6C42FFA3 +:1079A00078F7043D7DAFAD5EE6E782E788E7A41F88 +:1079B000A3137E99767C66653E63FAC079601DDE0E +:1079C000D7D03AF13EAAEFADBF9262F8B583D6C9DF +:1079D000FC9E58F9B0D1CFCD76B2209A86B3151659 +:1079E00076A19F70309FC6996DE5E3CC12717C9BA8 +:1079F000A0FF59177594DF81F4D680CF95CC2779F5 +:107A000072CCF550571DACB71ECEC641FE469356FC +:107A10000E09395B5F5245F7BDC7DC07C6A3BEBF81 +:107A2000BE74E5E13227C29FD45441B729A52FD5B2 +:107A3000205D5A942E8A2F4C76CB745D787DB936B2 +:107A40004ED1AF17A3F44BB4BEA88F923B11F7549D +:107A50004E43C4F9CF729F4B88A483ABC7CB1C2F76 +:107A60007EAF7BD6051EA71D8C97F7E973A503781B +:107A7000893EEFD878893EA7013CADEAAACB1D8CA0 +:107A80005F156FBF2E79C91A99E71B8DB71F8AAF93 +:107A9000E6D15641AF5C9E5708BE7D3B3B4471B773 +:107AA000B74BF9EF4B1D73FF96E2BFB358A8630DB8 +:107AB000CA45E0CB3942F9E823E44C341E06F8F419 +:107AC0003F282EBFFBF3B7282EAACA2113F225EABE +:107AD00013C11FEAB999901F916F2FF0EF875E2DA8 +:107AE0007FA87C45EB213F38A48FCC1FFCDFC55F0E +:107AF0007B71CD18177616523CB8CAD1A5C77BAC9E +:107B0000C950D23D92887FD23A9C91F53C6E1C5967 +:107B10004F712FA1F7D4B8A6DABE3EBB2B41185542 +:107B2000A4474DC2DE51FDC47D8E53647FAAFA5432 +:107B300016F7FE57AB4FF7087D3A54FBDE73BB795F +:107B4000DCE7CB433D0F801C9F9C6FA4EFB84C0E2D +:107B50003FCCDFA3708449FE6F7437911F0CFB6923 +:107B600046A304E67544E6F3A9E5BEF36D0AD6EF35 +:107B700095BBF40AF507FF16E0038656FA9D860DBD +:107B80008F737D1357F451D6E5DE83BAB34F99E670 +:107B90004AC2EF616F5F83DF010B2A8CBEEB98B5A1 +:107BA000B48B45EEF7A531DCAF9D9CFFD61D076871 +:107BB000DD1FEA69DD6857039D4F969D0E05E7CFEF +:107BC000F6DB23FDEC7DD9F7DA9D00B77C696C0804 +:107BD000D17AC3A37E01F3EC33578D074B8DED7340 +:107BE0001F18F50BC0C74673D504CCA3ACB6DFDBBA +:107BF0003E1FE5DAD95B2660FC1BECBC56D4B7838C +:107C0000F6DFB7CD8CBF3B5DED789FD631A2AFAB31 +:107C100006BFBF5AEDE0F748BED1BE87C64C407BD9 +:107C200039ECC1734F349F0C22DD4C16EB65172FD6 +:107C300051FC41BD97D9739ED347FFF8400FB88FD1 +:107C40006BBF5C45F722B97DBAF926A0D5757D3C9E +:107C50007F0CDBF17BE058BF28861D00F35CE74B0F +:107C6000C6F3EBCABA3786DECDEDFB36E083E7F626 +:107C70006470BC44B76F1EC3ED82B8AFDECF7292A2 +:107C80003DC0F57FB0C012F33B55B7A9FAD21A3BFD +:107C90000F452D5579A5DA23805FB32102BF9BC61E +:107CA00070FFFD7CA9A703F1F77DE77F0A710BE563 +:107CB000F152CFF631C391AE045FAD9763C601EECA +:107CC0001CF3A3C52B6E4113EFABBE73E96FE986BE +:107CD000A6DB41746550E9F821A2E3FF8BF47BE257 +:107CE000FBD0EF207974FE14DDC347D3B14ABF0344 +:107CF00074C8E69B9206E87928BAC17E8B9206E8A2 +:107D00007AA87EFBCEBF1F93DE07C6E9BD2CDDAB94 +:107D1000F4B759D0917A0F5429CE79FDD78CECFE67 +:107D2000A33D46F577C6357E11E83FCAA3AEB072D3 +:107D3000B97FB43797FB193D66BA9F9AE95E29BEB1 +:107D4000BB0D5D23C6AD11F27EA6DB755939AFEAD6 +:107D50000B55DFFD4F7C774398008000000000004A +:107D60001F8B08000000000000FFED7D0B7454C75E +:107D70009560BDEED73FA9919E3E881692A085C022 +:107D8000164640EBFF053D7D10321FA7C1180B9032 +:107D90004C8BE0041B49DD60E2903D9EA131321224 +:107DA0009FCD621FCC7866BD390D038C9DB177C025 +:107DB000561C610BDCE237384BECC671189C4C3C0E +:107DC000C243086C6CD318C743B24ABCF7DE7A0FC3 +:107DD000F56B750BDB43EBCC6457E740A95EBDAA9E +:107DE000BA75EBFE6FD5D37A3363CCCED817F85380 +:107DF0003DBCAC081A19CB65F4F305FCDBE2F2EBF1 +:107E0000252B63DFB9EECBB443F9932CDF0A671E51 +:107E100063AF5F35CAAC88B1AEA9E3F6EAB387FABF +:107E20008F75088C15437B12748676EF54C17700EA +:107E30001E31D1272E9D1E7DDE9F4CFDAECD958738 +:107E4000B3FA329D63687AAF3E8DB159F89B0ECA82 +:107E500020932D33A0CCED5AC712A0CC2CF9369626 +:107E60004C622EB1843193F29EE9CA6BDF15F03972 +:107E7000931983FEEB95F556307F5D0DC031CFCC65 +:107E8000BCF189387AD3C9C9D05ECD970AE369D7E6 +:107E90001DDE9FFEA529F3E430362E57A0F5CDFB5D +:107EA0008CF94CF06B756EEB023603E78771CCD121 +:107EB000C7A9601E99E9011DE55EDB2AE83F6BAAB0 +:107EC000C9E1E5AF4BF8DE6CC6DF1B3ECE7AC64A91 +:107ED00086C6D9E209C8FA54C68E494CE92F5B6FB1 +:107EE000C167E7F8C37A85B23E536ECD55C4CBEB7C +:107EF00092C7E10778670F868D6F1DCB583A63559F +:107F00009F699F8B0E6D7D385C30FB58FAE54F5FA3 +:107F1000C07C4633C78F395D47F8795D32FA903EB1 +:107F20002AAED4EE6293184B96EC87FCF0DC2A99CB +:107F30001D3E053633F6537EAFB8020404ED9FC2F2 +:107F4000BF1480739B6EEF5A27D0DD166C4C1FA2B6 +:107F500097250B4C1A38962E49D4D49B9AC769EAB8 +:107F6000CB574FD4EC6F73DBDD9AFA431B666AEA9A +:107F7000AE274A35F5559DD59AF156EF9CAB69FF72 +:107F8000D6EE6F68EA6B9E7F50537F74FFCA11E98B +:107F9000221A5F88B691E98979053BD2BF884D3AAC +:107FA000FCCFC59CD3A3F7F7217FC27EBD6EAFB7D0 +:107FB000AD82FED5573F8DE7FDB4F4C5BC7200F924 +:107FC000A356D91798C72B407B8D52AD95BE45F46B +:107FD0005E633645E41B95EEB60A5611C7AF66DA06 +:107FE000FDAAB06DBDAE477E2E1AD0EB61BE5937EB +:107FF000B5FC572135FC06C767CCAFC7F584CBA5C8 +:10800000FFEE18937A399E60B57F01FCC4ACC98C31 +:108010009547C7A34AA7B75D37635F6FDDCAFCEA20 +:108020007A2B58A00EE93EDABA673BFC7A926B5184 +:10803000D61DBE5E15FEEF6F865F81EF5FFF23F3F7 +:10804000ED1310DBB288FCE6DF5DEBCFB52B400211 +:10805000BC27157AA8918227128B900E980365830E +:108060007190F9510ED433C16F8452961C04AF380D +:1080700068EF34302AEB717E711086A6D245EB355D +:108080000ECA8D286F452CA9EE9CC7EB8E065E8725 +:10809000F7A82ED5F2BAE73E5E8792EA5E27AF4395 +:1080A0003FAAEF5A8CF5CEB8C0894401EBBE2558E3 +:1080B000370E1E5ACA4BFF05814A99E49638E85D8F +:1080C000A7A77EEC22AF073771FAD0F283315EF6B4 +:1080D000F9B3195F3D3C3F81BF4DC2FD5CD76F00D6 +:1080E0003CD48A82C30EEFD50C32873F15F7D5E416 +:1080F00090D997E033A033316D88CF8C2C98B14A5A +:10810000203E790FF1ADCAEDE1E368E9AB1EF55A07 +:1081100001EC3BFCBE3119E530A7A7FAB2E0122C06 +:10812000F1F913D03E7B32FC4B1E4E1F2A5CA2326B +:108130005FA5B55F8FAAB6321826B75917D15985F2 +:10814000799D2CD987CB6D7150E52F2E2FC2E1562A +:10815000E5AD391FF86C1AFB3A7C96B90A6AB3AEE2 +:10816000BEABF0D9BA303E93ADF79684F019103219 +:10817000D3F0D9B7899E6E275F4E09837526184FB5 +:10818000F60CE823CA9954C04342243E9BFB1BB221 +:108190001FA2C89737F01758676E7E989C51F45C01 +:1081A000B5AAE7FEA8B3A2DDE2677A11CB707CC85E +:1081B0002C3B31D273B53CBE0906BA6BA80EF890C1 +:1081C0000F81BE631F15DC06CF9BC9CE62B85A80F3 +:1081D000C7AAE2318C6EAD712F9D90ECBC05F5EC19 +:1081E00018856E4E66A711DFC376BDC742E49DB504 +:1081F000E8CBF101CD3709C7736622BFD540DBC696 +:1082000082E1FD33B10FF09935C87C3E78CFEA08A2 +:108210000858AF46FD9E8DF4CFEA51FE575F09E83E +:1082200025EAA5E5975B7400BF3F01A4578B7C51FD +:10823000309C2E64E6D3E37E7CD5FDAFB61F349030 +:10824000BC0EDBFF9A41B0CF004E39D5E420FA1ABC +:108250006464CFC84EC1C748BEAC21BCA8F6E3AD2C +:10826000F6266817E8912E627BB340F6D0A76CB370 +:1082700081F305F3FA557A86E7CBAF303911ED3447 +:10828000CBF3D47E6C1323FAA8B6973C556747B856 +:108290000676CC44B824BD0A973F15C7BD60E2708E +:1082A000F9DA087FD50AFEE4411D3343BBBF4F69AD +:1082B0000FA35FFF20B7D3FC4FC42B70DDC8F04382 +:1082C000BF07D04E069368E5DD03FF4384F7DC6902 +:1082D000773FDF015DAE28F0FC6F856E3FDA2451F9 +:1082E000B93ECDF5FD7CA0C77F916E7CE266C80FDC +:1082F0003944F7D5F6CF27901E52F1D93786F410BE +:10830000C24DF8E8B34483DBAA107538BC0ABFE558 +:108310008CC8572A9C2A7C577C7AAB0BC67BB3E768 +:108320005F131CF621F84B45E77E84FBCDC14F67F8 +:10833000B888EF9235766634F96652FC88A44C967C +:108340002BA6A23E8873CC85758CCB74D1BA4C36E3 +:10835000A31DFD024B2793F360487382CF8CF0F787 +:10836000A737ECD243FBD6A92233C1FB5BB3BC36A3 +:108370005AA7FE0986EB9993E96103D6E8F377657E +:108380003E29119C835047BFC7C6F1A29F68F4F8ED +:10839000E0B95FC7D61C0AC1CBC102EE8F9DCDE705 +:1083A000E5DA171ED97629843FDA0FADD3D4DDBDC7 +:1083B000DFDB762954DE6E1044DC9736858EDBD900 +:1083C000C004F45F5A453BE1A143379086F56B2C1E +:1083D000787E0AAE0FE78F00FF3FE75B623DFFD27A +:1083E000A950F68FE1FE69FF241FF90DEAFC1F2B4F +:1083F000EBFF385F177338A6011EBAB3BFC5709F75 +:108400006A6C7C3F4D50727AE67243F577869E73B4 +:108410007951A53E0F3ADE73121DE91CA8764C99DE +:10842000F611E97D27D2BB71A8BEB548D7E88BF01D +:10843000FE730522C17BC016B93D5BA1979D135CFD +:10844000DDD9E8DF3FAB736C8625CECBDC3A1EE589 +:10845000FD56DB7AA253E6E2EB58C038BFCECBF430 +:108460007819E8D179FEB782422AD68DCCC286F837 +:1084700057F50BE7893ED101FDBBF2D79971DD5D60 +:10848000B6F5661CCF84D6826E383CEABA0FECE6AD +:10849000F3CECBF489E0E9B2B9B97BC501A83FA31B +:1084A000AC7B5EEE3A6AAF6AF49F14097FE06743E3 +:1084B000DDE868F5E23C2687BD46C23A736CC6B279 +:1084C0004F7889EC1355BF0DE94FAD9D72FABA9103 +:1084D000E463D7159DCF44F2535E3007DE9FAFBCF7 +:1084E0006D0D727BBE6BBFA35FC4F71C02F9E3F393 +:1084F00073BF4D769D35772EB7E7B3567991549873 +:108500004FF0A13F314FC55B9E565F191D17B7A0B5 +:10851000FA30DED4EAD1592CC090BE2AC2FCF370E6 +:108520007D3BBB40B1D7725931DA2B2D26DF63C8B2 +:108530000F960D423AC2A1E27545818EE820867CF5 +:10854000B06726945DD965B4AFFACCD31704985FB1 +:1085500017DF6643BED0DB8C7EC41BB38A1F0DA819 +:10856000F34DC2FF3325B2B7B08E842F7D3979FC2D +:108570006E96C786EBEC32B0A648F2A7B680F3FD44 +:1085800007597E920FD1DA8D1B04D27BAA7C376605 +:1085900032D937C278DB8C5CCE805FD22B40BF3EB5 +:1085A000A417A0FF175AB3F7E905A27B19E5F1ADAF +:1085B00052B1EF120BB91FFE668189CA93CA7E546D +:1085C0007F7136C33582FCAFAAF23084DF94CAC70C +:1085D0003365F2F14C222F7395713F2EE27CDC5C07 +:1085E000147BB95F9A337AFB1C4B7A8D87522890A3 +:1085F000E879DD9887492EC5126F39A38837A35DC6 +:10860000A13F07A713B5FD7345DEFFAA20E674B2AC +:10861000B47214E5412CE9A4E2CF83DECF97FF7951 +:10862000EC47DA68AEE3A399F2D442E093BF9C2E04 +:10863000DF83E596D723DBBBF3632F77D31E8072EE +:10864000F104DF3723E9B37985B197FB4BD1BE48FD +:10865000E1F645F8FCCB153D144B79D20465B31116 +:10866000D61F01FF8F8EC2FCCB7350EF727B81E56A +:108670009EB9A40FB1DFE167B22EC43E067B141C85 +:1086800041B443053992DDED8DFD7E2D7D483F647B +:10869000AFCC615C1FA8F32F2CE1F87A7A14E0B01C +:1086A00000DEEA256EAF9BC2E050CBBF2D8CBD7DB6 +:1086B0002AE943E04805BB1FCB0542447BAFA7D066 +:1086C00018737E1A0B78D9E2608D91E4C9C9D8EF8E +:1086D0004B9A0DCAAAE9CED328D7964B87E7605CA0 +:1086E000F9FBF81FE61BD279BE61A5C1E545FFAED7 +:1086F0004BB23BBC768C47ACA2FACA7CBB43AF52B0 +:108700003EB6DF947CDB056CD7517DE5EF241FDAA4 +:10871000C3DF17D69DC9C6F136EB1DFB18C69D9564 +:108720007C838DE71BAC369E9F106D3CEF60B529B6 +:1087300079071BCF3B586D4ADEC1C6F30E569B929C +:1087400077B0F1BC83D5A6E41D6C3CEF60B5297908 +:10875000071BCF3B586D6ADEC1D33815E391369EB7 +:1087600077B0DA78DEC16AE379079897E71D6C3C49 +:10877000EF0070F1BC832D72DEC13A947720FFF1D7 +:108780001896A467B85F7F54A9CF067BDD34637861 +:108790005EB56AE7FE2D1817AB0972FC5539785E95 +:1087A000D914B4770A307E4566B0DF04FE65451102 +:1087B000C3F0D5B0F9C3F313DDD9E7BD02FAA3B016 +:1087C0009729BC03E529EA187F3F7CFE6171573B7E +:1087D0008FE7D6657E8BF03BBB2C4878C3E71887C4 +:1087E000AD53F213B556ADFF2A7FE6B2F9715F992A +:1087F000D49908F890456DBB88F92F8CBB5EF1D7F2 +:1088000061DCB76A501B7715331BD4B83CCF4B845F +:10881000C139DFE11C5F046B6A017F2A01E6CFC129 +:10882000A415AE53127C5EA4B7DD1B88BEBC3B45CD +:10883000C71468AA0464609EA512206A86D254C632 +:10884000ACD24CF29B389DFED7D4BDF1D9280F0392 +:108850007A46046C233CA8F9850458BF3483FC2B6A +:10886000F2EF2A33FDBF473A50EB82CCF338825DFA +:1088700062CD802FF96E265C3693ABCE906FEB45C0 +:10888000E635C37341E9379B05294E2D3389F276CE +:10889000B5CC4165D174576911F0A3CEEC75E17A7E +:1088A000AAEC6609F9853DEE3CDB48F1E47AE93251 +:1088B000E04900F6F862DA48768AC82EABF81C4523 +:1088C000BB481F2F7822C9AD8AD8EB61B2832A0A30 +:1088D00019C9C72D2CB2FC7CAC84CBCF374B5DDFE4 +:1088E000443CD7FB16D58F872E8FBED04A799B6D1F +:1088F00061F1C25BFD8A626F4724E7903DB901E9EF +:108900007AF1048F0DE18816C7782AF6F0EC491B3E +:10891000C1AE7B7614EC5AD443B7EC2AFB9993FA98 +:10892000503BCAB10E4FBAD0EFBA929038AADDC30D +:108930003C14678D1CAF796914E22099A8BF13FE1F +:108940000B9D63EA3A02FB87E5FBBC54E1F88E42DB +:1089500087E34B63CF17D3A0D4273E610B8D1B77E2 +:1089600059040E9741D0C0F5B962FFFDA024F678F6 +:108970002A81727DA9FC2EF261D574F96758AA7C10 +:108980003BDFE1BA40FC292DAA4F02F9BC667F7695 +:1089900001EA8906DB5EE32A80F7D552F9FD223A27 +:1089A0006FF41F5B1E6EB11E8F47BCF7B922CBA3BD +:1089B000BB1109C5E44FDE28E2FEE467848728FE88 +:1089C000E4AF8B63BE2F7BEA7386FCC970FE1F5B2E +:1089D000CCE39D6347018E06285746F1EBA68CC277 +:1089E000FC8D5ABF6EBF3E44CE104185E6696CDCFB +:1089F000AF6311FC3D9735BABF377B14D6B110F386 +:108A000071B591F5DA7DC531F7AF967E03CA0733AC +:108A10005BFDA9D0C4BC306FDA50BEB2C9D5AF0F70 +:108A20008D733F38E1E037E508707EB338E672F2C7 +:108A30007C9C1EF975BD19E1E96A067E8DB05F2543 +:108A400025DCFF9B3BE111968876633A43F711E4FE +:108A500009CF3736297E6383A27F762A72D4532CBE +:108A600052E92CE5F5B951E8FAD7CAFB8D4A9CB614 +:108A70005162F22B91F47FECE9E6FC3828E7C671ED +:108A800038EF0DF3CFDF53F4C49ED8D3CF9E0CA0A4 +:108A900093B9B591F17530F674B17402CCBFD4F6C8 +:108AA000F41C90F8B02F9B0D945F9C2EBF580CEFD8 +:108AB0006D8BC2579F2B7869863E3AB0FB5BA03422 +:108AC00042F91090815440FAED55EC6F018E30144C +:108AD0002004DEF1E8E7F43AE41E7CCE5C6DE47F2E +:108AE00084C81BCA9F569939DF74A783FF88FE0E7E +:108AF00033D33993AE20CF9F7665F2FC68383C6A59 +:108B0000FEF46F458F19CF71776516C485F2DDEBE2 +:108B10009B98266FDC7585E785C14F8AD3FA49C9D2 +:108B2000E427858F9F90B9745EA87F24C8DC1F025C +:108B30007F26505C3CE417A9FECF987CF95CF17F5E +:108B400002FD1DCD9F1147490F8B30073EFFDD749D +:108B5000F9DF108F23D0D31FA3D0D39FB0DF7F3492 +:108B60007A62CC11B768CCF071BBB21EB7B58E700B +:108B70003F2021D31991CE54FA027A9B503276E8E5 +:108B80007D21F3B44A6F134B8ABF3EBD5DC0BEF07A +:108B9000EFACE1AFECD649D1FB9DB57ACC280FFA0A +:108BA00032D79BF19EC4D4992E07CE6B11996C00DD +:108BB00038BB5C3E339E7B003B2FBF6484BCC1CD81 +:108BC000222E3F7EADECFFDC099CFF2A960BBE7D7A +:108BD000C07F4D6C9701F74D7DFF5849ECFD887BB8 +:108BE0007248EE35968C20F75E56F8E273055F2BDF +:108BF000DAD629E7995844FB6755ECFD8C342B9461 +:108C00007352D745A4E35B7487E78522AC6714E20F +:108C1000E0E7C7E4E03C4CCD2B6D40FC3E56C4F190 +:108C200017CDFE7D6A14FCB38900D74AF69901FD81 +:108C30006959FFC7AC48E7118E15D9399C069003D6 +:108C400080DF9559BAB731FCD995A4B587D4F767B9 +:108C50002BFEAE6714E467520ECEC3F11A7E0E4CA3 +:108C60002DCFC53E1EB0B488FBB9FF80FC0EFC734F +:108C7000A8A458E3E7FEA864643FF7B57F8FDC1A29 +:108C800050E8A8CB11D99E7D21F6FB40E7E060DDDE +:108C9000EF7C15B9116E6FAAE59ED8DB7B69597A16 +:108CA0009C87C3D1C8B4E7246EF1DF28E02D5D8F27 +:108CB000F368E97725E3FA5F85C3581AF3738CE705 +:108CC00067E831FFC3F9797DA92BBE94EC368F1983 +:108CD000F537D80714675FB939251FCD2AD8676BD8 +:108CE000A996BE934A47A6EFE4D23B40DFAA9CFC7C +:108CF00017614C53A8BC99A8C89B69A5B1DFAF29DF +:108D000018AF488E2CAF2B631FE7DB73774E747957 +:108D1000AC9E37FB47411B4F6EBD258F634E4769A5 +:108D2000A9FA2179ACEA87703C8D865E480CD10B9C +:108D30000D51E4CC68C03136041FB59D02E5AF98F3 +:108D40008DF9A6C0AF9DD839E4DEC7965188134F80 +:108D50000F8D7FC860AF47A0E3DDA5B1CF7FA3BC77 +:108D6000E9377CDB36D2F947A3D5C5283F6273319A +:108D70003BEC9FB1B395F2F6C605AD9487669D02B4 +:108D8000E5FD98F42EF979AB6CDEA7307D365C9E5C +:108D90006C8D395E8B72D897F637C5287ECDEBF88F +:108DA0004A3AF937AFA33C1524EE47B30DCC4EF742 +:108DB000A4AF7CB9FB582F2012302F9AC4E83E761E +:108DC000A7E1C77ACC471B053EFE5CE6E7F94F9763 +:108DD00077FCA3F09EE5A0317F3B547F519A4DFB79 +:108DE000DE69E5CFBBF69BF39F84A59EB6159EC1B9 +:108DF000F3E153A727531CECC5038F6BECEC5ABC73 +:108E0000C7807EDF0B1E867EA229D33571243B9C52 +:108E1000317F92AE8C509AA8947A5EFA059D6DF8D7 +:108E2000FB3BF7F748E867BD78C04C727FEA819E4C +:108E3000F85521E32796713EB6063DFE1900AF3581 +:108E4000D3733209EF1D2BF9739179CED4C22B6302 +:108E5000A4009D0FDF91576B0EA5BB2EA9D64C79B0 +:108E6000E45C9D638A1DEBFC1C43FCF4DAFD82404C +:108E70007EDD2E1150EF9AE1BA867AEC0D89EBC3B4 +:108E8000A9536B49AB752AE71E76E42D3980EFC7ED +:108E90004FAFA7F13B59647BCC58C6E5F08B0699E0 +:108EA000E67DF18048E7C855BCDE697CD6CB300F43 +:108EB000E0A3DEA6A77BD8A78D4E11E5D0E93481CB +:108EC000ED822DDFE97885EE99EC8802EF2F4AB923 +:108ED0009FCA6CA9447FA7F7772E8F747E5FA5BFCA +:108EE000C93364A90CEDC0499E2694FFCCB6E43684 +:108EF0007CF124DFBF4387E6CF03FCCF7DC17F2217 +:108F00000EF7216BCF785CF707A5766ABF450F1F78 +:108F1000BD42F4B0C5C8EFE37875718E03B08E859D +:108F2000D60111CF4F18528394E76D2AE3F2748B68 +:108F3000CA0F63811FE03D7D06BF07C526DAA9CEB3 +:108F400026072784DEA39E55A6AC970532F1F9C209 +:108F5000F87737D81D8C15F6A6378BB0FE8589EFCC +:108F60006EC8867A49EF785ECF78F7B36C89B1B274 +:108F7000DE0C5E9FF6EE6793A05ED19BC9EB953049 +:108F8000D478B09B7AB39ABD7938BEA419BF150FB7 +:108F900072147FFD526FD2458C5F3528EB871F031B +:108FA000CEE3ECFB473AEFE2345BFD782E83C986D3 +:108FB000B0F8193485DC7760A90924FFD4FB0BF3E2 +:108FC000457F3FF6D799FD84DFBB5927D97380AD24 +:108FD000DD5F147E797B2E5CEE6DD9C85C784E8C9B +:108FE000B16609EF33084CD67DC1E3784E9C5F85AE +:108FF000479D7F185CB0B5C89F43703D4FE3A87094 +:109000005DCB377951DE7A6B59AE27044FD784E0B8 +:109010000F186C45DAAC1D0FE13E5D1B139C204020 +:109020003DB97C1BEDDBB5B1C11F088E90BA81EF55 +:10903000635B6F09ED639728B7219D9B8CD66E21EA +:1090400091B1EEB884190CE6D931D6E5C57B6E40F6 +:109050007774EFD89B65741C0038EB8BB4F9A1C70B +:10906000153AFB83220FE6987679CE015DBA7B0430 +:1090700086F770DC83378CA8FF16F65D3462BEA4D9 +:10908000A3E7A211E9BE03EB304EC7F3C688F96F20 +:1090900063B95EBD2F4AE791D64B1C4FA7B2EE7A5B +:1090A0002A15E0E9582DD0BDBCF54792E6607D7DDC +:1090B0002BAE92B1E55587E720B9B438FB9FC27259 +:1090C000251B38950A24B4CCA567F6103DB9624D2E +:1090D0003CB387E8C9164F8AA6BE7217ECCE0C289F +:1090E000376668FA31E5FEEA3236F483E7989A94F7 +:1090F0007D5C66DB19C0B8EE3297C13B1032DEC230 +:10910000BECD6232C2ED111C748DD2CBCF3FADE02B +:109110002B84521C7A1FCFF7F40AC4EF1D6D7ABA64 +:10912000C7D3DCCBEDAEE63582CF2E201EF8BD0DC9 +:1091300077AF40EDEEDEA7EB9311EF1B000F00477A +:10914000DAF8847D2C114793E9DCD54A055677DFA0 +:1091500039038EB3E23B02DD6755BF9BA0C2BFB2AD +:10916000A991CE91017C5EA44F759D4DF647E95CB7 +:10917000D5CA89970DA887617D970634F8D4D65B48 +:109180003CDAFACA8DDAFAD132E59EF234360DF9BC +:10919000E9789920E23924B5FE51D6F9B7F15EE7B6 +:1091A0006ED1790AE9B3CDE89F81FA7EB7E8A2BA19 +:1091B000DA0ECF3B18F19DF8E100F1B140FCB9C5E2 +:1091C000204B35F83D977681E87605B6ABF3670F0F +:1091D000BD4F75FDF0FA4D55EE5A9C1BE8BB30476C +:1091E0000509ED907A511693F3882F229E77F9BDE9 +:1091F000C2076FA3F603B8EE4222857DBAEBFE44A8 +:109200009F17E6BDEBCD563AE7765721D0811DF981 +:109210005E47E7D6E6E3792F28EF03796881F22EDF +:10922000FDA12692EF338D12C977E59C972A2FE492 +:1092300017B5E7B6E6679E213BEBBEE776D279B578 +:10924000C93972C1D3A80F2D7CFE1D4704DF6618F3 +:10925000A723EF34C9CF71323F2FD76153E4682F72 +:10926000C85175FDB0BFE350AE612269411ECD9B70 +:109270006E56A95D263928F86B75E8FF8E53E6DD3A +:109280005F6DA775A73D7A48C0756731EF6601E647 +:10929000BB823A7CEC50F955EDD7B5F80BE85D563A +:1092A000AFB5635B45D7E365305FBB6DC0C8CF2DFD +:1092B000068DA81FEEE0F8DE48E3C3F27574EE50A9 +:1092C000E2FB30473F988076CEFAA339E3D808F620 +:1092D0008DDEACD3C8118314A79137F373B5F26751 +:1092E000A1432B77BE5196A3695F244FD3B4DFDF30 +:1092F00058A8A93FE0ACD4BCFF60539DA66EB2CD88 +:10930000D3BC6FB12FD6D4E373976BDE1FE358A5A0 +:109310006937BDF5A32601ED71B377C00578E8067E +:10932000DE284B1ED223D312E06528E30A2D562CEB +:10933000BBF34D744EB67B3CE89744ECFF1D3A7787 +:10934000694E7CC95C03E5DF0BBE5AFC7E0EA0C9EA +:1093500085F6DB3D4F68E3F0C7AB385FA96543B9DD +:10936000EBC10A28F35EB067F07BE9817B707FCCAC +:10937000718CDB45AF99C92E9A89765388BF71B03D +:10938000BA667E39F67B42BE17F982F532690ABCAD +:10939000B7CF083B8B7AEE3523F5CBEB1DD085E6B6 +:1093A000F77F59CEE5C1B3CEDA7B71FC8E3ED0B2E9 +:1093B000C84FCF7D6844BFAEA3AF3F01F5D90CE7DE +:1093C0008746B4CF879E2B7A4E0CC6619CE31F0E56 +:1093D000E923DE63DD5E6EA4F14F2B72BDE53B7ABF +:1093E0003A4F8BF7376B4A86E473CBE1A01FEF63EC +:1093F000B7B4F37B9B788E36929C06F9FC61A8BCCF +:109400007D361DF4C14C1A4FA30F9697F9E9DE3E45 +:10941000C86FCDFB2B97345CC57C25C871EDF34C30 +:109420007E1E96B10103FA7320D735ED1BCB95FB59 +:109430009CD358DE1720072E3823DFDB7DBB8A9FA5 +:1094400033B8E0AAA37D7816F089E7479F1D863FD1 +:109450008ED7DBE1ED65A48190FD1B66FF5771FFA0 +:10946000EAE52872FBA2B2BFFB8440010A55B7337C +:109470008EE87785B975EDA542DC97CFB7A2BFDE40 +:10948000F22381EEC1FFB2FFAD343BACDF78F8547C +:109490001ADE97761F3A9586F789DB0CF6CD68CFF2 +:1094A000037DD03DE48E5E3FC1DF7EA8B01F9FB735 +:1094B000F70A0E14C9EE9EEB0DB44E36B015FDA39F +:1094C0007D51E03A58CEEDABC3E5762ADD2E9813F8 +:1094D000F57E8FC9E713901E403E215C47C00F8286 +:1094E000FABE6DE6A648F6D46505DF27B71919DE82 +:1094F000FB6D83FEB88ED359A78DF8BD8596C3B09A +:109500002E01D771EE81781C7F8381A19DA1C2F7C6 +:109510007156E0035CFFFBAB0D0CCF2D6F59AD27EF +:109520007CBFBF81DB27FA877FBD3503EACB802E66 +:10953000F13B0F2756DF389D01E3BEBF86DB69751F +:109540000F1B882F97AD136EDD4B0EA56B956EFF2D +:1095500046A1D370FA0DA7DB61F4BAE6EBD1EBDBE1 +:10956000E5B7EC9019A8F761FFE78C433AFA1E7350 +:109570001C407E1A3C611807704FDA2A39C0C36359 +:10958000D3F5BEA7D2506E9CE0EDF96D7B052E7F22 +:10959000ECCB717D19DD4686F7082E2AFB7651D972 +:1095A000373B0B0AF1C8CF626012CAA96C25CEF90D +:1095B0008A81351D46FF52E4F267FA8F6D7BB787CB +:1095C000D0EF7F2BE774ABCAC56946E63A6CC5F7A6 +:1095D0000F8D5F04E3BC6CE0E7352728E34DC90934 +:1095E000362C825257C1E5E46F1538D4FA9F143EE9 +:1095F00060277F43F85C68E6F89FB7D1DF8CEBF813 +:1096000099C975BD1CDE5F30E17C1BEABDEE493FA8 +:10961000C9E3DFB973901DEE56F07FA2FC37CF632C +:10962000EECF32358EF6D772F46909E9D932A568E2 +:10963000DC48F130F7CD6CE64A01BABA9943A55A35 +:109640005F74FCAA7180FC82EB0DC42F37D3E9B99B +:10965000DAEF5305EEE9468E07D6974A7A1BE4B651 +:109660005816926750F1A0FAE39629FB69BF1E5B7A +:10967000C728EECFD8D3848F156DE7845618E741FD +:10968000836CB002BECF2736ADBD3485B19F6C620E +:10969000CC050B3ABBC9CC5C77037D6C92A81ED875 +:1096A00064A3FABB9BEC545EB638C7A2FE79E0A473 +:1096B000670AE2ED44D61E672DCC73EDAC81F04114 +:1096C0003B06F4FD98426B37FAF4CC0CED377A94F4 +:1096D000EFAD28F03F743383B940BEFC02E7838EC0 +:1096E000ED1B7F4672CFB1E67A03FA49F96D17B7E1 +:1096F00062DDBDF1770D685F7C00FA04E90CEC7E59 +:109700006613509E9C33DA810E9A6FA6D0382FEBE9 +:10971000820DC877DE630243FAFCA0F7BA711CD74A +:1097200057742DE1F94D74E69F2DAD4822FCB8FB2E +:10973000F2757C7F8B74A1F729FAEFF94302EE876B +:1097400079A3FD9D4AEC7F46CF90AFB7D70613A40F +:109750000872F8028C8B97A3701D5886B73719BD15 +:1097600053F03C419342C7E1ED8B15FA044C1B9436 +:10977000EF2932218D9F23C19F1658526232F94141 +:10978000FE38E0E796BEBAAB22961E817DA8F5CFE3 +:10979000D88721767C343AFCB2257E43E6C3294340 +:1097A00075F42343EF7FA01F19E9FB82A6ACC9E340 +:1097B000468A77B907C0BE83FDEA00C3C99E82F41A +:1097C0003E8DCA4F8E74D9917FCC71C13DA82FD8E0 +:1097D0005D3AF23BDABD5A7BA841E18706C51E7AA5 +:1097E000B442EB3F819FD45EC1FDA484E34CE33FD0 +:1097F000853F27FFC98C7C05F34E83FD7925D2FE7A +:1098000054D5AEC77E13D82EA27306748EF415BE3F +:10981000CEBFA8E07A54E5EB65C8D748BFBD9CAF82 +:10982000C3C76DA9AAF90B1C775B947B10F757F19E +:10983000F1DA9F13085FEEE752084F1FB3E79CB5BC +:1098400040971F031CFB802EAF399DF149D0FF9A32 +:10985000CB199F6C1D92031DCFC553BF6D9317A7E6 +:10986000B442FD19A47B18EF93DE3A8A6F3EF41CD4 +:10987000E73F75BE0FFCCB52909F8A0D41A303DAE0 +:1098800033FB2E26A01D587CE4FE14E4C368706EE2 +:10989000AD54E0DCF8D8DA4B299C1EF01CEE5A459A +:1098A000BFB99FF41B11FF6B3732A2DFFED77ED901 +:1098B000817CFC495FBC84FAF0E3A3F15E94FFD79E +:1098C0008E997C3A81FC106F22C8B58F0D03F791F9 +:1098D000BD79442FA1FFE83EF6DB3DC88FEED74CA3 +:1098E00068F9B1B57D5DD751EFB5F5DD7B55C4F2B3 +:1098F000A5D1E587F68D8FD37AD5FA6F3799ED2804 +:10990000473F11B99C58DBFB2AD9BF6B076FCCC00E +:1099100038EAC747FF4F09CA35F79B374A509EB907 +:10992000DFB85182EDEE1FC77B22D92D71B3F484CD +:1099300057555F66BF276AE2451B14FAC8EEDCD5AF +:109940003809F0577C6E8903F3B66A7BF1149D13D6 +:10995000DF2FFE797DCAC321FD3A0322E58D8ACE31 +:10996000D5C7AF0EA1CB47AA0C9AEF947DD5380F7F +:10997000B6E2F72D6FC575023AFA0EECB680C8BF95 +:109980002FBB46F0A1BF01F64B783FB2A7AE3D9288 +:1099900042F71099E89C3FBD08EB531CDBED2856BD +:1099A000CCA72687D84BCB023ABF09E8A8A9CFE4B9 +:1099B000277B3F205EA4BA62473D74FD3763B285C2 +:1099C00008719ADC77E7A01C0F8FD7C0CF18845B93 +:1099D000B5AFCEA7F3F851A647D22D04B89A3B995C +:1099E00084781D16D7699A4BF1A2F0F88E3DB0DB52 +:1099F0008CFDEC937512C2ABDAA5B88F3D11E4C0B3 +:109A00005F567279A6F2576780E7F53A03B5E6C963 +:109A1000507E5769EF9174CC0B78E9ECBBFF00C620 +:109A2000173A071F8C9F0EF374BEB798619EE79A92 +:109A3000546B9E82FD06E79A1FC81BA29BF0F91A81 +:109A40002AB95D34642F44D67FA50A5F8F961E2CF9 +:109A5000ACFCF3D083E09F575472FF7C058F9F705E +:109A6000FF3C5C7FA872591D77AD82EFE172F92A45 +:109A7000D939E047935C5E5B69A7F732FB16A59086 +:109A80007FFDDE9214BB75F8F839A243979C377CB2 +:109A90007CD59E737BE55366F47B643DF1A77B899F +:109AA000E0C3FC976AFFB99D02D9E5EE66830FDF3C +:109AB00053E10A2CE1F1D8076483CF220CD989AA9B +:109AC0001D79ABDD2150BB6A57AAF663C0C9E3BB61 +:109AD0004B8A78FB658B6B55E5585CA7859E17977D +:109AE000F3E78C394FA15FF5E05281911C50EC4AAD +:109AF000954EC3EDCE4FFB7212478A433DAFD0A7C0 +:109B0000CA6713C2F843D563CF54707EEB403D5E05 +:109B1000887AFCF71AFB3C7C5CD0E38F57523F46B7 +:109B2000FD8B7E2E3A23F9EB6665FCADEAFE054E11 +:109B3000D620BC592CB019FDCC68FAF57B8A9D1350 +:109B4000ADFD19C57EBC1D3F1F56E4C868F1F3CBBF +:109B500095B7F270FFA9F9F9967D688C62BF57D569 +:109B6000BC86FB1FA7F7046A90FFFE9781E2EEE137 +:109B7000EF3DA5FA9F22D3ECCFA92CA30EFD23F72E +:109B80001A1E3FE84EB2BF437ECC5B7A86E3AC053B +:109B90007F10EDB8476F2651D986F632942B5E3888 +:109BA00047F988156BB4F077634C17FBAFCBA6F37E +:109BB000032DAC9EE24C2D7D49D216500ADD630F79 +:109BC0009D46BEF21ED0DB0F84BEFF88FABE99C749 +:109BD000E136A6FB28F71A660FB478C2ED7EAD7D9C +:109BE00050A9C48DA2D9096FF45BB85C39A3273E94 +:109BF000EFC078D34CC68C7D5C2EB837F23849471D +:109C0000DFE604FC086ABBD27E450C501C8AF26B6E +:109C1000F0EAD5BEA7D3E83E97ACCD27B5EFFF3924 +:109C2000C9CBF0BC52720F974BEE36BD92472AA1BA +:109C3000EF97B7833F390EED4BBBFD1B8877808BC9 +:109C4000F948DEC89AB8CB3E25AFF4E9997F253FA5 +:109C500074C5912879A4EE793C8FA47C2777781E6F +:109C6000E9F4A90CFBEDF3481DBDE7E81ECBEDF2CE +:109C700049A6AA5B711C8A3B4E14797C77629F20AF +:109C800061BC6A621F5F77E9B638B2AF1B7EB53A36 +:109C900005E581BA4F9F2CE2F8FDE4FDCF6AB05F85 +:109CA000C9AF44C902EB7AE3FD0D3FCBE075BBD9E8 +:109CB0008EFD36C4A33FF3C9AFD6C7237EDF801223 +:109CC000F7E7C717C4C8F1C9A178756615C59D9592 +:109CD00078B508FA70CC505C27BCDF8B555C6E748D +:109CE00083BB4271CD233CEFDF9DEE9A47F5BF9ECB +:109CF000C4F8DF2990291EFD2AD035C68DA6C16281 +:109D0000312FFD3FE35827E691BAC7BA7E427CF473 +:109D1000D73A3BF211F4A7FC93F7B09DF423866A7F +:109D200031CF33033F5B40F7315229DF738FB28F5E +:109D3000E9E0CFA25F09D02CC13CF43425DF332306 +:109D40008E8938FE0E836BFB54CC2FF58B8ECDC4E1 +:109D5000048E143C6F199E7712649E2F57F34F6A3E +:109D6000DE3C5AFE49C07994EF56F0F396B280F982 +:109D70007435CFC4963A29F9B5A5CC43F7427C8017 +:109D8000B3AF73DE6B84FCCFC31511F23FEB2B989E +:109D9000629F69F38DDB735F213AFDAA79C6C378B0 +:109DA000AEE28EE6C5ECDC0F0D83BB28E9D334F2BE +:109DB000BBFEF86F09A467FB6E903EBC1634B10081 +:109DC000C51F0778DCBDCF4071866BE0BF8D0DD11C +:109DD000B3EF54F0718FF7D511FDF704EAE3F1FD0D +:109DE000DF2BCFB7BDB7E47EB4F7BD01FE1D0BC6B8 +:109DF000B83FD613108BD16EB983FBF2646584F53E +:109E000099E3B87E0AE7A35285FF4AAB389EEBDEA2 +:109E1000E77E987B03CFAF488A5C707B785EFD74E9 +:109E2000569AA0C6D3C745CABF1C0992DE687944BA +:109E3000A0EFC97CD9FCCB33E991F3F12B7A2F4603 +:109E4000CEBF343690FC8C16CF0E8F63FF9D2AFF59 +:109E5000A6F338767A9544EB4EF6E4D78C6343EB61 +:109E6000BF83FBB07456847DB883E36F9C1DDBF128 +:109E7000EBCA633BFE13311E7F7B8CC7FF61796C9D +:109E8000F3EBBA8AD8C2FFDB18C3DF1F09FEFF5706 +:109E9000CF0784E7FFC3CF0B849F0330BDF5B01716 +:109EA000DBBA849D413FC3EF8DBFD624801C149341 +:109EB000F6D37DCE05E53C1FB6ADDEECDB2B0C9D6D +:109EC0001B50F1F56835F723A5BCEB5EFC5ED404AE +:109ED00039509F82F1B272FE7743AE59785E8C8919 +:109EE000523AE6C9E0CDF4C56097745B22E7595356 +:109EF00095F1A2E99183D5358B6715E31F3D8A7CE7 +:109F00000EFF874A1C52EAE5F7E999684F5F4CF368 +:109F1000DAD3D11E4A3CC99F27F899BC97E0B267B3 +:109F20002FE67FDC201BE17B46C9FF26CFBB2B1B26 +:109F3000E3D2C96017625EF069CC0F923F2BD17BF0 +:109F4000EA7C9766713FEA190313309FEB9DCACFF5 +:109F500039B19EDF91FDA6E6F5CE1AFC975A05CAE7 +:109F6000EBB523FC3FD5F9F3F6652B440CF8CDEBAC +:109F70009128DFF876F9DFE5BA681E9EE77B4CE2B0 +:109F8000AF9C40BF19E078EC6821D1EF8AE3E5FF90 +:109F9000D48CFEC76491F03CCCAF54E205179478A2 +:109FA000871A2F50F35BFFACC4493EC0F80B9403F3 +:109FB000180F8172FB2CDD9DD64FDB6745E0FF67F4 +:109FC000041E1FF2FE94C7870A8D8E9CD0F3947FE7 +:109FD000358BEF63AB9FE72FD478CF0F95F5147EC9 +:109FE0004FEFC7EFA1156E9D6E443D5FB8352B0E48 +:109FF000CB19B24F9706F85EB6FAB04EDDBF487483 +:10A00000B45759E7B63341CAEFBD1A96F7BF348B40 +:10A010009F6768A9E6FB7B09FFA018D41F9B226EEF +:10A0200041F331B14AD247CA2BB5805F8C70B67606 +:10A0300073B8557CB7F8ED7538CFC553C1AD581618 +:10A04000ACC9AEA3B87BDBF5AD68BFB9076F9CAEFA +:10A05000A67899D18EFEC44303DAB8DB13D53CFE53 +:10A06000FE2A1AE088B77B45F28F0BEF15897E92A6 +:10A070005B2CE4BF261B98DE8AF545DC2E2A684C53 +:10A08000ADC33A5B9244F660C1197BD2C379437188 +:10A09000B0E47B378C453CDD2ECFAAC6D32E5BE4E3 +:10A0A000E3B89F5F35CFDA7EF63D3A6FAAAE4BC577 +:10A0B0008B9A2F8D966755CF3DB81B3FD39CD3709D +:10A0C0008BC1068C3F161EBD6854CE5F4AB6ECA10C +:10A0D0003C6CE191EB947F55F3AD6ECF75B2ABA1C3 +:10A0E0009F11FBF76CE2F9D7D7000E2C7B61DDB234 +:10A0F00009EFA1DBA8EC8375E3F3639B72A9F46F0E +:10A100007250797C531995F899C9F464CCDB5EA739 +:10A11000BCEDD559C3CE4D525E6FB7E8FC08F115C2 +:10A1200092F7A37A78DE4F1FC7E335EE3306FABE07 +:10A13000A1FBAC99E4774D5FEB44F40F3E3FE79A07 +:10A1400088707760DE2D842E3E911D9624F4839DC9 +:10A150000E0BE6DB0AFBAF1AF13C4C871830623C71 +:10A160000C20CFC0238BEE9EEBFCDC6F5F8D05F1E6 +:10A170007BDBFC58EFFFCF8F7D95FC5877353F2771 +:10A18000ADCA9102A74EDE8BE519D9F270889CD832 +:10A19000E6E4F9946D9327111FEE764E4A5A1D326C +:10A1A0005E67238F5F24DF3BD912FAFC97D53C1FF3 +:10A1B000962C306724795633FBEBDDC71B416ED7F5 +:10A1C00044B2FB3FF929D0E54CA08B23DF9E3890A9 +:10A1D000C7193F341EB7AD71F5C431289F2E98D8EA +:10A1E000141EAFD3C4E358585E2E5A5C6E45A34E7E +:10A1F000B6D079A1E004D4DBE1F13326062770BDA7 +:10A200002E67E0BD1498318395B161F9B95F30DFF5 +:10A21000CF27C3FBCB1A75A42FD43C5D41A3C8360E +:10A22000017D166C34F8283FD7285EA476C56FEC04 +:10A23000940A3290CE3F386B9430AE161E1F7334A2 +:10A24000EEEF9E04FD1D6D02DD0BBA5D1E4F3D0756 +:10A25000DED2DB3F07E36DF96C57773DF4CF9FAC5F +:10A2600093F0FCF4F07C1E3FFF5DA0D839E171361D +:10A27000A433B44BC2E3F01B153AD8389BEBADD7EF +:10A28000147F531D47ED174E3F3F9DCDF56DB4B87C +:10A29000FE5165BCCEC6826D93717F17E818EA93B4 +:10A2A000CEC65AF3E490F176CCE6E7DB9EC1FC60C3 +:10A2B0006A687E90E701C3F382AA9C2BECFF7D03C2 +:10A2C000E27B37C86BD4636E1BCF1F141EAB398380 +:10A2D0007263084EAEB777C39E07C8BE732431BE03 +:10A2E0002EFA7B45DEA302C5E70A167C763C1EEA01 +:10A2F000CC9944F7B0DC67276FB1A23C5A2016E333 +:10A30000BD1EB753B89567C27CD2FDEFACA1EFBCC0 +:10A31000163E907F0EF7E58166039D0F54F5DEFD36 +:10A32000EF3435F0F6BD4FC6617BAEE0B0D8F179C1 +:10A33000237D3F76FE4B7EFABB580B113A90E781A6 +:10A34000B39744E49BCB16D7DF231F152E52F24C54 +:10A35000CD5C4F3FD0B7C8C0C8CED3EACD13599F0C +:10A36000533CE8465F21E58F52F0FC43DE90BE2966 +:10A370003C0A7A6CCC9DD3633F9D2D113E67821EB3 +:10A3800043789217F13C7DF8FEEF50F63F9A5E8AD3 +:10A39000268751FFF0FB63DE0CC1365C8FDB31EEAC +:10A3A000538AF63A94E3A2D3DF1F6671BA4E8A62EB +:10A3B000CFFD49A1DFA8E7A77A4727CFF487D97F48 +:10A3C0001E7963D5FF52F34DAABFF6A0620FAB65AD +:10A3D0009352FEBBEF37A0728D78BF2139F2FD8614 +:10A3E000870E0968A7A8F71B4E1959CDE1543C4FB9 +:10A3F000ABDC77F22D223BE9D4DFFC62EB8BA97852 +:10A40000DF4990501DB51F3A477ABE1DEC23B2A715 +:10A41000FA7ECBE3AD87F8F9F0F6DEC8DFDDDBAD21 +:10A42000D8DFF53223B9D1AE9CB76DE851F244B70D +:10A43000E2968F8BA1714BB73D30563DC7EB237F22 +:10A440004F1BC78C16B7EC60413AB7DBB14670A022 +:10A450007EB8DD39DC5DCA79DDA8714C79E473B969 +:10A46000E1714CB95A9BC7B96F96C4F7DB250868F0 +:10A47000EF9A75CE363AB77F4C90229DF35E5ACD57 +:10A48000E5F47C250F72D0C8E9E3608540F76FF0F2 +:10A490001E1EEEFBC163FC1ECEC1027E0F47CD7BAC +:10A4A000A8F76BA60EE53DE8FE9D7A2F47BD67C372 +:10A4B000988FE05AF45C1C7DC76B87E1908DDBBD03 +:10A4C0005E7E3F1A6510E6434DCC13895F6BAB6B24 +:10A4D000C46A7AEF8EDB4F8F5447F07B7D8A1FE989 +:10A4E000AE8EEA2FACAFD6FA0B540FF717EE54DE50 +:10A4F000E38BD9EC4EFBFB87631C8F9E323BB6F19E +:10A50000C4EC48FBB6C5A2FD1EAF5A5E56E4DFB0F0 +:10A51000EFC50DBB2FC9F57AB760FFA74ACAA71BC5 +:10A52000289FAECAD5EE317CFC1F29E3A9654029DE +:10A53000BBA37CD7F9974ABCAC4B947B10EE692F38 +:10A5400068E397D30F69E397337B9335F57CFF7806 +:10A55000CDFB85672669DA8B03F768DA4B2F146821 +:10A56000EAE503159AF72BAFD46AEAB382DAF86505 +:10A57000F5CDC561F7387DB4BE1AA0DCD07E75E696 +:10A580006F6ADECB58A35D579647BBAE891BB5EB10 +:10A5900052C7CDF66AD797D3AD5D5F32E6E3F2BE20 +:10A5A0007E3E2E7FB65DC9C7E558B0DF338D932D53 +:10A5B00068B7A9F7A9D5F7FE2F376658DF407F00A7 +:10A5C00000000000000000001F8B080000000000D9 +:10A5D00000FFB3E46660F8510FC17BB918186E72C2 +:10A5E00021F84301CF6786D06A2C0C0C1A40CCC6E8 +:10A5F000C4C0C0CE44BC7E714E047B1D0703C34C57 +:10A6000020DEC831F0FE1A487C9D877E76A9F34291 +:10A610006859C181F73708570A3130B40A3330C45A +:10A620008840F80CA2A8F2554208B6A924657639EC +:10A6300002F5030024CC7134800300000000000008 +:10A6400000000000000000001F8B08000000000058 +:10A6500000FFE57D0B7854D5B5F03E731E3393793A +:10A6600064F2200F02F18400A242180284870827B6 +:10A6700021C4A8018380BC54263C43483211A8BFA2 +:10A680006DBD77260411ADB551691BBCE81D1014D2 +:10A690001575A0D1061CE84014B1DADBA8F8A8D5DE +:10A6A0007650444048C2CB8B2DD57FAFB5CF49E61D +:10A6B0009C4C48D4F6BFFFFFFDF1F3DBECB3CFD9E0 +:10A6C0007BEDF5DA6BADBDF61EC1329A244E22E465 +:10A6D0005BF8A365842784F4E92CDB0ADA8F9164A4 +:10A6E00042FC2F8BF2368E10EE778EF0A45184BC94 +:10A6F000B5990B98693DBCCF4608AD9FDE343D60EF +:10A70000CE2264FF08B302EF9FDE9A8FF5C92FBDFA +:10A71000E714687BD54BBC0075D3BE13CE889D1063 +:10A72000AFB9E5A16BE9F3F69778B2850E45FC93D6 +:10A730004D2485906316C2FE2EB2FA522BAB566D95 +:10A74000DE7F07F45BDE642656DA4FD5EE65D3AEC6 +:10A75000A5F565874402AF546DAB95FAD2FAF200C5 +:10A760001784FA9A7D7FC671DA0A48797028212702 +:10A770007D16225F49EBCE969459F47945606711B6 +:10A78000BC5FB183739BE8FB159BF67F0CFD5734D0 +:10A790008A0379DAFF8AED36220F61637F4B601EF0 +:10A7A0004BA601BC556F88C44CEBE5975649047025 +:10A7B00024D44BA50E18FF614976C03887701C0D54 +:10A7C0009F55CFD071E877D52F706E985AB589789C +:10A7D000009ED6DDD6394FDA615EB5D260F87EF7DD +:10A7E0007D12BCB72C50F6B25506F8364B4500E743 +:10A7F000A6CDD2D2A19DFDADD8FEA60EAE630DD9D9 +:10A80000A99EA8766379D247886CEEAC5710A20453 +:10A81000ED0077409A3EACF3F9792E8190D1D03F8C +:10A820004F644B67FF9430C807FEF7E83F810FF68F +:10A830003A02DBB23AE9B5D245FF2D77D2EBAC4B09 +:10A84000A59FD09E17DDBF563E0474A0F0D4FB5CDC +:10A85000583EE24BC372834F46BCFDCA3704CB0659 +:10A860009F1B9F3FE61B8BE5269F82E513BE622C54 +:10A8700003BE527C6F8B6F0E965B7D1E7CFE94AF89 +:10A880001CCBEDBE1A7CFEACEF6E2C77F8FCF8FC0E +:10A8900005DF7A2C83BE7A2C77F91AB06CF405F0B8 +:10A8A000BD977DDBB16CF205F1F91E5F1396215F58 +:10A8B00018CB7D405F5A867D2D581EF07D88E5AB14 +:10A8C000BE087E77D0771CCB0755BC3B27907C8198 +:10A8D000E2CDA9101715179258A2E48BB49E58CA5E +:10A8E000EA29B7F9F3255A4FF1D03AC563DFCA70A8 +:10A8F000BE99D6FBD6B0F6CC7B488185D633FDAC6D +:10A900007DC0834A8195D607D4B3F6C19BFC0571FF +:10A91000B43E38C0DAAFDE112EB0D1FAD541D69EA2 +:10A92000132293EDB49E1366F5DCB794C90E5ACF8B +:10A930006D61F5BC8FFD939DB49E1761DF8F3F1550 +:10A940009E1C4FEBE3DB59FBC44BA4D045EB130932 +:10A9500087F5027B7E6102AD17B858BDA85F9920CC +:10A96000C7E0BF7D626411A1BCB0DD7FB322A4D378 +:10A97000BA145945DC149FFE39580F8B6431B4BFAB +:10A98000E52F538471B42E91D5D0FE177F05B61FE5 +:10A9900010656C6FF7AFC2F603928CEDA6DA7BB050 +:10A9A000FEAAA8607B72EDBDF8FEAB9282ED836BD0 +:10A9B0001FC2FA41D183ED636B7F8DEF1F943CD8AA +:10A9C000FEC8DA805248EBFFC179B6005FD7719EAE +:10A9D00072920DFC1A4C2BA5FCBA8E2373403E1EBE +:10A9E00000A6A6F2B02E5D5240BFEDFB47DE933CC1 +:10A9F000A7F27632D4973EF54016F6F31CF623D232 +:10AA00007EF89EFB99F8CD585D3F13BF29D7FA69B0 +:10AA100084F7EAACBDEB67DF37E3F5F07C53A1F5D3 +:10AA2000B317FB71F46E5E13BF9DA087E7DB4AADE1 +:10AA30009F83D84F42EFE0098B6374FD84C5655A4C +:10AA40003F7FC47EFAF40E1E451AA7EB4791966B22 +:10AA5000FD7C88FDA4F7AE9FB074AD1E1E6985D63F +:10AA6000CF11ECA77FEFE6A598AFD3C363AED2FAC0 +:10AA7000398974CFEA5D3F071C7AFC1C7074E0E7EB +:10AA80001CC233A877F32A70EAF153E0ECC0CF255B +:10AA9000ECE7AADEF573C0A9C7CF0167077E440EB5 +:10AAA000E635AC77F32A88D7E3A720BE033F4E0EE6 +:10AAB000E019D13B785EEDA3C7CFAB7D3AF0938A26 +:10AAC000F08CEE1D3C85297AFC14A674E04746788C +:10AAD000C6F5AE9F5753F4F87935A5033F57613F4C +:10AAE000D7F56E5E85A97AFC14A676E02717FBC918 +:10AAF000F76C477808EDC7D17D3F07FBEBF173B0EA +:10AB00007F077EAEC57EA6D07EB27BEEA728538F90 +:10AB10009FA2CC0EFC14229E6FE85D3F0733F5F830 +:10AB20003998D9819FA9D8CFD4DECDABE80A3D7E34 +:10AB30008AAE60F899248CC07586AE9D6E9E7E723A +:10AB40007DBF7C85A3EFF32E56E75D6E02760FAFD7 +:10AB5000D933A445E1E9FBF61D09B90F9068BBA6FE +:10AB6000E076C08F835A79D1764DFCD8389D1D95FB +:10AB7000A024EAEA49C57D75EFF7291DA06B4F9D1A +:10AB800073B5AE3DDD93ABAB67948FD7BDDFBFA68A +:10AB90004057BFE2EE1B75EF67F96FD1D5B3D7CF42 +:10ABA000D3BD3FA87EA1AEFDCA860A5DFB55819547 +:10ABB000BAFA35DB7FA27B7F58708DAE7D78D303E8 +:10ABC000BAF611E14774F591871ED3BD3FBA658B84 +:10ABD000AE7DCC87CFEADAC74576E9EAD71EDFA398 +:10ABE0007BFFBAF603BAFAA48BBFD7BD9F4FDED561 +:10ABF000DBDB963FEBDE9FE2FA4CD77E7DDA9706F1 +:10AC00003BD5EE3A768D5AE741AE08FA25FE740937 +:10AC1000EDD5B043C2BAD4D7CEFC14C752F928E55B +:10AC20001FE9C0223919F992FE51BB21BF6FF99576 +:10AC300011FAFCAEF19E2B5DF4F95D9267B82B869C +:10AC40007D43F98D236950CA26288DEDF7898CDF65 +:10AC50000B322E0D3E42BFF79ADA0727D0FA703E2C +:10AC60003F08F2F1326742BB3A8E2735F05E9C997D +:10AC7000A0DF745F56DE93FE287958DF9FDA195CF7 +:10AC800067BFEB454F1ADA51B59FF8C1CE59D79F30 +:10AC9000CEAB2F21AF709F84FD03E9F7FD97A67916 +:10ACA000687F6689FA19D1E34B74FCA1387E18E4F9 +:10ACB000E1208C3FBAEBF8E6016375E35B32CB75BC +:10ACC000E35B243ABE8B90DFD77EAE8E4F89309EF9 +:10ACD0009037B9CF717C7366398E7F9F44FDAEE8A3 +:10ACE000F1E33AC66F81F9BFDFDDFC078CD7CF3FB8 +:10ACF000B3423F7F89CDFFA3DAD3EAF87138FF3F33 +:10AD000073A7D9FC332BD8FCCDACDF8EF19D1DF899 +:10AD10008FC0F8C7BA19DF9C3D413FFF2B2AF5F3DE +:10AD200037B3F14FD65E50C7B7E3F85F7217D8FC60 +:10AD3000AFA8C4F125B3C70DFC2365C4D504E8F85A +:10AD4000A41F557CA9C02E741C28872452A12164FD +:10AD50001B3700E1B82B8EF1DB577194DF509FF960 +:10AD6000F1390950CD9947FD4695D757ECC8974022 +:10AD7000EF613BF5B796A8A02E6EE291BFC90673AE +:10AD8000601085B7B589F7437DF186EB02A05FBD02 +:10AD900066B2A014BE1348189E7FFECB615BA2E78B +:10ADA000652C97D48BC72251F2D6E1071690213536 +:10ADB00014BE29C004A33BEB9F523F0E1CE38FA996 +:10ADC000DF43A8FFF399C8C6FB0BF5F7A01EA1FE51 +:10ADD0001E3ACEA416BFA3DD1D4EA3F097AAF07FA6 +:10ADE0002A3079FDF4362EE0A7F2F9D58F47A07FFF +:10ADF000BDE06E1B457A271C65FE245D9DCECB0F02 +:10AE0000746ADF6D0E6CE110BF32E06B3A8A262166 +:10AE10008BD667505C77BEFFC1BEA907392721B723 +:10AE200012454CA5EFDFBE9AEBEFA2E3CE52CCB9B0 +:10AE30006C1D52324C28D724C33496905B1A478835 +:10AE4000B407325D113F8D448D3BA3585F9F55AAD7 +:10AE5000AFB78A8A68A270B54EE7C866DAEFEC39F8 +:10AE6000FA766D9C81A644466775BC528A9374FA43 +:10AE7000683694B9F0D885749EE362DF6AF078177B +:10AE800089248C7EBCBF0F01BAFA93F1BD792E36AE +:10AE90006F23BC73448B524AE739A78C0F007F1B8A +:10AEA000E1FF689F4D31E5D072FDA32231759D8F82 +:10AEB00011FEB91EE37C8222ACF3F3CB8DCF19DFF8 +:10AEC0001C53E9FF29F0072DBF00FEA0F01F55F924 +:10AED000A353AF32FEF09A3DD3801FDA37F204E974 +:10AEE000AAF2CBAD2ABF2CA9D7F305211E11E8B8D1 +:10AEF0006C0E97FB40141FCC56F96059839E6F6E01 +:10AF0000277E313D065DE66ED87C6F9ADC757E9FAC +:10AF1000A87C33FFC1FD889FAEF36474BA43A5D308 +:10AF2000ED35FAF65B55BADEAED2754EC3C3AF51FE +:10AF3000F541E6C90111E4DDFB538D9E111D3D3D38 +:10AF40002A3D8D70DEA1D2F38E1F337A1AE18DA8CF +:10AF5000F48C349C13C980AEF01AE15B707797F9DA +:10AF6000605CABCC1F9B9EDEA6FC5547A39E57059D +:10AF70006F5875344ACE566C9FAEAB2F0FCCD5BDF3 +:10AF8000BFACA14CD7BEA47EB9AE7DD1FA3B75F55E +:10AF900032FF8F75EF2FB8BB56D77E7BCDFDBAF64B +:10AFA000F9E50FEBEA733D1B75EFCF9EB359D73E22 +:10AFB000ABF4195DFB8CE29DBAFA7465B7EE7DD3F4 +:10AFC000BEAB6E06FE7CEB3D9E803D71C1FD05C6AD +:10AFD000332FB84537BC73D427235F1FF30DC1F25D +:10AFE000B8CF8D7C7FD23716CBD6A6663BAC137418 +:10AFF0005D5C4A12086932CDAB5DDF0FD66982EB2A +:10B0000069C8E4A9F5D37AB34946792869904878A4 +:10B0100024211C2C362A1CED7C547BA487F606AA1E +:10B02000F893BAB69744623FF73E527605F06577DB +:10B03000EB03FDCB00BBA74DB5EB8DED951C298D2A +:10B040007E4EC81A84C36A627647A5C4E4BF7257AD +:10B050007A0171423D3CB8E672E3052993A7029F4D +:10B0600064EBE47859C3353AFD4E209ADC07F86D5D +:10B07000A4EEF98AEDD7EABE3BB59F47B8AB41577E +:10B080008C8365B1F43313E8E17073E68C6100A73B +:10B090007214EB4D7DD02E3CE52B5E757410D0AF55 +:10B0A00014CBE3BE39581EF379B03CEA2BC7F253F8 +:10B0B0005F0D9611DFDD58FEC5E7C7F263DF7A2C1E +:10B0C0003FF2D563F9A1AF01CBF77D012C0FFBB6A1 +:10B0D00063F98E2F88658BAF09CB569F82A52677A3 +:10B0E0003DF1DD71751D3E09FC1783CFA43A7FED5C +:10B0F000FA099D7C16C7DF877CA6E1B9A4C1ACF232 +:10B10000438A8E1F12C097433EEBA1BD4154F9B054 +:10B11000BBEF63B77BB7FC6BF86DEA0FE4B74E7E0D +:10B12000CA30F053764FFC348C8FE2A7A92617B3B0 +:10B130007B547EFA19CC23865F310F8C903E51F6FA +:10B140009A926F82756CA5BA0F421F60FDAC3A7679 +:10B150001D7DB705EDBAC0105837CE0EF9DB60D8AB +:10B160004738FB21257E56F7F333F249F77857D05D +:10B17000BF591AA0444FEADA6E8D6378B59A483108 +:10B18000A1EBDAFD839E722F1C8A758124C2F70120 +:10B19000F774478C7EA9AD0CF8ED09AF758EAF72D0 +:10B1A000A0BF638FFD3D0FCAA926662FC735F36880 +:10B1B000B793F0936EC06FC7BA6476A741BCBD7DEC +:10B1C00090E442BB814CD6E3CF5FA0C3DFFD1447C0 +:10B1D0002DB8EED6A721FE067E3538BD17F8EB490F +:10B1E000BFF784CF8530EF7F013E7BD28F3DE945AD +:10B1F000A2C82F34D1F9B7ED1B96FB800CE35E1E7D +:10B20000DFDAFE9A119E5F7E473E6E4BD1F8B8257D +:10B2100093801FA4CACBD9C62BE3812E1DFDF44019 +:10B220004FEE779F6482FF7E3A4BDFDF7DC6FEE202 +:10B2300025C20DA7E33A2489C453BF92F76CE3D12A +:10B240009F7147FC1037D86773D7C9E0379EFCAFB2 +:10B25000B00C3DEBE30B670F3DE9043F6C651A5FF3 +:10B260007334061DB5B22A9855638FF6579AF4F5D4 +:10B27000B3F55C7110E725C7CF1C06EB8CABE6A8D5 +:10B28000087A3F0D4BAD9F9569128E73727B763CA9 +:10B29000F3FF024C9FEC48407D73D267C1F7FFD9A2 +:10B2A000F074D78F060F218DE4330BE873DA96DD47 +:10B2B000FDFBDDCA83705E82F82909895F81BF6961 +:10B2C000A5FF7F3B00FA15B0AEF5EB0DF27EF370F3 +:10B2D00078BE43371EFD4ED6F68CE1BBEEE54E2020 +:10B2E000C734BEA7F4FBABBABFBD62BBB5466FC7E0 +:10B2F00026E8EADEA6F41A9D5D0BFF00C3BD8613A7 +:10B300006009AB54D9B04DB0AF077EDA03C149F044 +:10B310005F38F65E9525227964149716E0D385632D +:10B3200035FE9767FF99EAA9136F8A04E48C5CA243 +:10B3300050E5A9AE20F29B8998687D91FAF6C2C6C5 +:10B340001525B06E9D78F926F44316935227F8C759 +:10B35000E5A43E0FE2B5A789A918E4F33479C7390B +:10B36000324A1EAD82849D2E5AAFB7E3A97FAFABA0 +:10B370002F6BD0D797925B5260DF7EE9069104383D +:10B38000D01BFAF6AF7917F6BB8CD4AC8375FB579C +:10B390006ABC6BA18B0819546F55FDF6F1BC320ADB +:10B3A000874B6071166D1F7A7922F37F2A66062417 +:10B3B00085BEFF59E3C85BA906A2DF07D6C17EBCE4 +:10B3C0007F3A716F235DE9F75DE137C2ABD9035D69 +:10B3D000F6C3553892B7734A20861ECB14382667B9 +:10B3E000AABE2B105CBAB8C73443FD7BF35332D1ED +:10B3F000F1D31EDE93278C66FC03FCC009ED92E7B7 +:10B4000087F49FD6A5FF827F6AFFFD68FF79BAFEA9 +:10B41000A7FD53FB1FD805FE79B1FAAFFAEDF32F64 +:10B42000FBA93EA978F1974E42D7C913427D8A9B6A +:10B43000D2B572DBBD4E8596C705BF13F8F54480C3 +:10B440002F8E45EF87054E1542C5CE41DC0DFE49D6 +:10B45000FB3FF9ECCF301EF1D536D185F1B4EDE6E6 +:10B46000B099CA6175E3F2129283F523AC7EDF19BD +:10B470001EEA4D7AFEAB78FA9729901F4239458D26 +:10B480002F85D19EADDEFA7911AC4F5ED28E7264FB +:10B49000FC0EC6BF9888FAAF4C8AEFDA4EE1C4388A +:10B4A0008157C58BB7F16767782794377C01FA829B +:10B4B0007A22E8C71BBF2B57EDD4358223F9988D2C +:10B4C000FE7B0C19037A51C30B09303BB5EE995F33 +:10B4D000E71CA1709DDAFAA6938BC297264F67836B +:10B4E0008BFE738FDCBDDE6DA5F2166D0F69EB96DA +:10B4F000DCA4DAD72156568A6127E4F3546E16DDB0 +:10B500007EFAB8F2F9279F7A0CE2997F32BB07D115 +:10B51000FE573CFFDAFBE3697DC54E31B9844DC36C +:10B52000CEA574D2C74BFFBF3BB7931E15BF794D55 +:10B530009287B1E7F72476D265C5CEFD1219D615EC +:10B540001F9383FBA5883D067D82478AC05EA87B4A +:10B55000E6BF2588339ED8C791D4AC18F8DCFC1A16 +:10B56000DA038027A4A74AAF0EFA19DEF752BA8091 +:10B57000DE36D2CBF8DE2255BF40BF906741F9FBE3 +:10B58000853D9007F591D90D78287F619513E6F3F5 +:10B590008550C3F8FCF17B53409F958BFE141796A2 +:10B5A000EC79F9133F42FE5BF6F68F5230BE4494BD +:10B5B0007413AE45FE7498E7924DB3709E4B8907A5 +:10B5C000F9B0FC71BE3440CB0B0229DE19434EACFE +:10B5D0002293932FB650E2D2797E01FE24E8EF77D2 +:10B5E000F8C036B4BBEF24A00F7EA4CE855A0C5809 +:10B5F000BF6061F4FAABBA2E10B03EA3F977EB7DD1 +:10B600002D40A793FD9554D877F112C1AFE283FB8B +:10B6100096F6CBBF3D2595D189C8429EFA1D5DF7B0 +:10B6200027C37378BF4554AC39BAEFC8B7599DE307 +:10B63000AF56C7A770C7C17AFD454A6CFB354FD4DA +:10B64000F4005DB7A3F82C4ADE99FC6FBD9FC9BB1F +:10B6500026FF81E9C5D07EFE309323F80ED6430A3B +:10B66000573815DBF7CFE4503F503F3A969C6F15A3 +:10B670005539D7B71BF985C22F70F1517C03E324EC +:10B68000221D70DF65E906FA7D941EF5C2B8CEAEC4 +:10B69000FD6A72BC4CF35B45BD3E209B981EE8DE04 +:10B6A000AEF2239E2AC5C0538F81FC5279F5CB2080 +:10B6B000BF6229CCFFCB1DCDEFCFA372FB655093AA +:10B6C0005BBD5E35CA6DF9AED12496DC7E69779399 +:10B6D00098724B9FC7945B7B04F9F9FFB45ED5F079 +:10B6E000380CF0784D271E353DD91D3E8D7AF290ED +:10B6F00020235E8D7A92FE1D26795DF951E3438DFC +:10B70000FF2A9EABBA02F451079F6A7CD8C1A71AE0 +:10B710001F7689EFEAF0686CBF00FB3414AEF9962F +:10B720008DD38E5257D2D24E70DF267F268FFBAA42 +:10B7300096F384E5811011F3433F30D58C063B75B9 +:10B74000E2DF6F3D7D1785773EF18B2C2FA05E44A5 +:10B75000BBFFD2B7DF4EA0F399A7E2793E45FB5479 +:10B760004A973902178EA370CE15883F3E11E2B773 +:10B770001CF9340A8EF9E5FA3AFC4D4CE9ECA7A71E +:10B78000F7BFAB9FF27DCBB7295D3F1D44C8BB50CF +:10B790008A38BC10CD57D381AE147FDE515C600077 +:10B7A000EAA988501AE577BD2032FBF3EDC219A350 +:10B7B000C1BEC99F3D2C9EF1FB60F47BBDAA3E3B00 +:10B7C000EB97E341CF9F0D65A37F7BF6D02247AC7B +:10B7D000BCD06695CF5E53F75DDAEC5C3D4FF9BFA8 +:10B7E0008DB4A37DE3B75BC9B618FB821B454D5FE3 +:10B7F000AB74A37F3C1D7F8ECA8773E9A7F1B95153 +:10B80000749B39F584E0EC4A07F8FB34CA0FFBA1BE +:10B81000F805BE06FC365B2345A531E279CFA9F8D1 +:10B820009B78E06BCCCF2D0CE50B80C7423BAF8BF8 +:10B83000833CA9C9EB503214E09A7860F9CF4753A2 +:10B840003EF61EE2DD908FEB0D9D913C31FC6123B5 +:10B850003EA17FB0338F882EC4D77B62E912C0EB44 +:10B860007BB3AC04F635DF95DC55B1E02C33B3F592 +:10B87000662E29BD308AFBBF0FBFF9B31DE1028AD6 +:10B880008FB37696F7DD95FF98DC9F7571815A0E20 +:10B89000F89067F5642E0071B422E2F9F9040EE520 +:10B8A0007D52B4FECA6F9AFE3CE4F55487389789FE +:10B8B000B6570B1109F8D8DBB45300FBFD269928C5 +:10B8C000188F106A86CD8C8A7B1D1105C457F3DF53 +:10B8D000E6DD0EF83D37D34C002E65E81927D80178 +:10B8E000E74223510EBA9BD71F7C645AA108FD1072 +:10B8F000E40F233F1425DB74F55993493F37A5DB4B +:10B90000447364953B06FDEA24C667BDD66F96FF77 +:10B91000CFF4DB04AADF185F8BD1FAED2689F17D25 +:10B92000947E4B8DA5DF56D6CAA9C0172BF766A704 +:10B93000025D57BEB1A44F2CFDF6BA8FF9F76FA880 +:10B9400079E66DFDA87E1B1EA5DFFA51FD1623AE1C +:10B950003B5AEAA57EB3FCCFC8DFEBA0DF62CCB7D1 +:10B9600058C59FA6DF8A43B5A8DF8AFBF1BA7CA938 +:10B9700049524FFAADEC97B3B02EBA6D31F807F0DB +:10B980000AFAED0D55CFC138A0E7FE5D727D273D67 +:10B9900057D55B3DF73F84674DCFADECCFA13DD38D +:10B9A000950F999E5B99C5F4DCCABD4CCFAD1CC404 +:10B9B000F49C51BF1574D16FECFBEA21F47BF423A6 +:10B9C000B37E7D1B6D2F9923BA2DF4FD12593B9F39 +:10B9D00051333A5ADFFDBBD48DBE739FC1732E3DE8 +:10B9E000E9BB3F82BE1B847A6C20C891913F6E1CDC +:10B9F00068D3E5D3BDF7F5B1E75E0479F9038FFEAF +:10BA0000F70726E627EDFBFAD84890BBF7001EAAF9 +:10BA1000EF9E51F9AFD5E7477D3A792893F7AA7B96 +:10BA200018FEAA1B3936DFD57C408675E06F17D12A +:10BA30008FBE7D2FF3A3679B5BFAD8C0CFFF5F2239 +:10BA4000CA25FD2B298BE28739172B30EEB92BCE77 +:10BA5000B905FCCC3902B1801DBBE0D08D27C07E7A +:10BA60005D70713DDABD0BE07922E9C8FB98DBA17E +:10BA700027F5F6EBBCA69DAF6590AEF91013CD8C03 +:10BA80002E13577181CD595DF323A85D86F92DC61C +:10BA90003C89DFABF39FCD47105FE48F7CCCF8E5AA +:10BAA000EF8D787233BC54ADE6F578AAE162E28995 +:10BAB00052BAA42CA5132FB7BF14599701EDCB3957 +:10BAC000F4B78CF3D6F0669CBF8647CDBF59A0BEB5 +:10BAD0003F3F7424669E8886E72EF9221ADE0DF811 +:10BAE000784BD333D7906120971F983C3F1F0D7C34 +:10BAF000F47B8A170AE7AD7307E9CE2BBDA3E26595 +:10BB0000AAE748618A0C782435C067F3CA77BE96E5 +:10BB100042E777B392950B21F5597F933C108F68DC +:10BB2000B6B6A31ED4F8709499C98559D52BEFF5F4 +:10BB30007515E27AD3C4B950BEC2063DA7E699791D +:10BB4000EF61F2D7CCFDF7BA8C518867582E489137 +:10BB5000B65E015DE83FA786185DBC4017FACF6965 +:10BB6000A4FD20E0BD3A997387E1FDA69DF7023F51 +:10BB7000BD6EA5CF41CECB39F716860E7B7ACA654E +:10BB8000F95888C5C718CCC8EB5C3F17C07B895DE6 +:10BB9000ED9389E696F7008E89546E36C3C300FD97 +:10BBA0002F8AFE46FBC5C8073DE50375C7EFB92AD6 +:10BBB0009E5F073AD801DFED12D843DE305B7FB4D9 +:10BBC00076AF201722DE343A34D1F56514A38329E9 +:10BBD000069E6FD6EA2A9EBD214E84EF6FA0FE6FAF +:10BBE0001207BB7E5F1FD4F8DD2C77C513C415D2B6 +:10BBF000A3F406E8B7E87DCDEAA6B7115F37AEA695 +:10BC0000E699DC155F1A7D400F5E0E6FDDCA4FD3DB +:10BC100091987961DF557E4699F5F2B3CFDAFEE669 +:10BC20007088ABEDE550AF9050822E7E30D3CCECD7 +:10BC30009666AB07F9BCFD0DD1BD45EEAA7FA6A85F +:10BC400074017F25FA7CE2649808E84D97957CA6FC +:10BC5000CD7B00E3B7E8F5E075AB07E9D75DFF33CF +:10BC6000CCCCFEEDCE1ED3EAD7C37890D728EBC755 +:10BC700033AE475A5CA9A77979D471BFEFBCB471D0 +:10BC8000BEEBBE8497B4603C4EDB9FD8C37B768905 +:10BC9000603F1673BA7D100A39EE6FFE13FABF5972 +:10BCA0001ADD7DFF103F0A533CBFBEE3498C639F02 +:10BCB0007EF6C834909F15AFF0C442E5AF75878318 +:10BCC00084599E8804764245238FFB5D4408E7CD66 +:10BCD00088B233A827C3F0F1A203F55EC52E73A086 +:10BCE000847E5FF1F26739107F6B5DC3F49FFF596B +:10BCF000951FFD911CC807A810D8FEBC913E8FA8C7 +:10BD0000FC796AB76D0EE86F6E3B3BC75B119C2DEB +:10BD10009AA3E20CF79B4516E7DE6DC33C6CFF333C +:10BD20001CE631037CD1E748B5FCD053CF30BD5C75 +:10BD3000D12406E03C70C5F69DAD1017AFF8D08C4D +:10BD4000F6AB77FB1909ECD3C92F3ECFCE1B37F1E9 +:10BD5000BA78689738E4763E6C86F8596315EA013C +:10BD60005A3F82F5A01AF7FB8E71B2152FEE7DD9DE +:10BD70004F51B8E2374F3BF15C70CB3627C623B743 +:10BD80005F7E5FA04BDC3178BF1A779CFA05C1F566 +:10BD90002176DCF1A4CA2721B33EEE48B627613CE8 +:10BDA00092C299571A237ED1C1FFCF5F7802F6CD98 +:10BDB0004EEDFAF20980BBF29B734FFC94E2932A9A +:10BDC0002017ACDBDE67DFC37D06EDBBF7557DD208 +:10BDD000FACCD3B84FD3FA27B31B7A6BDDFB4526D9 +:10BDE000EC53B4EEFC3A05E2B8ABF74E417F6DF58B +:10BDF0004B9353490C7F402B817F03BDD82732D210 +:10BE0000ADB9B13913E03C4DE90EEB77473C3958F9 +:10BE1000C5E2F4B21A47DE117B5FAE4BDCB871C6E7 +:10BE2000CDD7C13ADE28BA65D28BF8F1614ACFE1AD +:10BE3000BDA0E30E759F2038F5B2F1E3D3F00F4AB1 +:10BE4000AF0B667D1CFE42E392FF7C0CDA1A93BABC +:10BE50008D1F877B813F6DDF6FBF59211690A35DDA +:10BE6000CF61DC1EE8477D0FD2FAFC854C88BB1CF5 +:10BE700017DBEFC0FCEBBD66CCA3AAD8FB01CA530D +:10BE8000EB4B6FE3BE1A51F7DF5A49C71FDB27514F +:10BE90007D3AEF56078B3BAB7480B8B4ECC4E76ACD +:10BEA000FC99F1B51697EE2E1E3DD63280EDBFAB54 +:10BEB000FB91555BFF2C1143BC9F1B0BF43A72D9CD +:10BEC0007D540D0F2EC0C398E8FD96D8F1FF8EFD6E +:10BED0001603DD809E608F75ECA7D07A3F88AB0794 +:10BEE000B80F62EDDFB56E66FB34AD62ECBC456D3C +:10BEF000FF65A4C5B0EF12E8DDBE4B4FF3F8AE7896 +:10BF0000CA0627B44F577C9DBA145BBFDF6AE1D4E1 +:10BF10007B03BEE7BE7E2567CC1B98057C59D57890 +:10BF200044027B4A5BDFB4F99E52FDE753CFF278BF +:10BF30004E645DB019F5BB517F5413163734C25BA4 +:10BF40006E617AABBA89AD1FA776390276DACFA9CE +:10BF500003BB91AFAB771C91FCB4BF83DB7F234560 +:10BF6000A2F2AC60FD0844C17FEA85FD396C7F898F +:10BF7000F9EBC671EE52C7F186628FE3DD71463789 +:10BF8000CE0A7F5062E77E2E3FDE4941990DFD9D2E +:10BF90006C1109E4FD9F0CF2C58118E3CFB5885AF6 +:10BFA0003C8BC90F5D47F11CA6839DBBE41325B4F0 +:10BFB000BB573BC67E08E7FD573B2419E21775B512 +:10BFC0002C2FB5EEDFDC6940EFBA845B713FAEDE4B +:10BFD000805F57B22B1FE21AAEC2D251C0AE46BD2F +:10BFE00093A09874F0AF7614A7CA14CEB5AA9D4654 +:10BFF00004379E0BE59D45C5301FDE65725963EC25 +:10C000003B88F652E289C28BE8D29FE3249746CA66 +:10C01000D08F967F53696939888D2E05538C85B1F1 +:10C02000ECDDFC992E9C77DB0ED57F5088EC4A61C5 +:10C030007964B08EB4ED8ACF21C3F143A2507EB4AF +:10C04000A9CFB91DFBF7835E5AEB244A0295338AC8 +:10C050005599CF86F3AC232C5C36F0E999FF7A85AD +:10C06000F66B0DF1E857B4D9B57C522501E4CC4606 +:10C070001EC4BC4160E56F933AE134E613127825A3 +:10C08000EA3E8D29BC1DFDA1B39B587C802757FF3C +:10C090007A028BCF9100C0AFAE2F2B5438CF12E273 +:10C0A0000EC3FB3B1C180F58F6C622941FA0433446 +:10C0B000BE928AF5E75E1BACCE1CF067365A55BFC0 +:10C0C000C6AFB4C0399BC56ABF7D4AF5E762A918FF +:10C0D000FA415E97A8F2FAE5D2A243988FE6598A10 +:10C0E0007A3E758EFEDCAC314F4B20AA9F1C60FE61 +:10C0F0007397BCADA6CD08B7317F6BC5767D5DC3A8 +:10C10000E327A037AF027412FBE5E2803DE237324D +:10C11000F8D713467D77FC9AD3F4F8B5CA7AFCDADF +:10C120008618F1A7C7AFC3ADC797E6977687DFF844 +:10C13000B1FA73C8FF2AFC8A56D58E54F14AFF4AD9 +:10C140002D294C6503DCE94218E5C2284719F63071 +:10C1500007FFEE9F1CA8C5AFDC0ED4EF69EA7CB8E0 +:10C16000C5EC3B1BC8110FF0BA518EE02420E879D2 +:10C170001BF9D875CC0AC4FA8C7C7B4DF7F45C357E +:10C18000FDD5230BE9579B807F87233FB0F3BE8902 +:10C190002450970572EA76C1FA1DF459DC8B45B834 +:10C1A000F785B8170F82FB5E5C583EA4E6ABB40D72 +:10C1B00025786E30183E9F02FAE9A1DCF669A0F7F7 +:10C1C000BC4B4829E8C11FC5B1F3030FA865BF38B0 +:10C1D00049D5AB856F4C82EF43A20CE7D5DB42DB40 +:10C1E0002C83A0DEC4E33D2ADE84FAAB60FCD6904B +:10C1F000C8E05A6C090C8238C85E11C76D5D3C01FD +:10C20000CF6576D86F21962FD216FACCB9284A9FDF +:10C21000B7363D7A15C4B9369A62E7A94CB19A7E11 +:10C22000D8FA1BEC92B737C5CAF2EA1E1A40E7519A +:10C230003DFDACBA0E3379B856A5F3AB4B6FC4F9DC +:10C24000BF14E26458478AF8DB6E1A46E739EE3DC0 +:10C25000418DCFB078E528F5FD3AD02FA85FEBDF10 +:10C26000E5E9C3DD470502E7F446D52C457FEB152C +:10C2700027E573CA17794A7024F06D612801EFCD64 +:10C28000F17E4CD0AE1FDD22E8F8334F5D57F3222C +:10C29000545EC044F950DF3E2E2218ECA0000FFC83 +:10C2A00075ED71FDF38556D5EE729214E0F30D979E +:10C2B000780EF25EDBDA897B0D85BB6D715F84A33E +:10C2C000ED3C9CFAA5E525BE38D67ABFCACAF8620D +:10C2D000A344709DD9B8D48EF1C5034B2BAE80F525 +:10C2E000FDAB1F7BAE88758E3C4A3FC5B37C2C25C9 +:10C2F0009E8C05FE5ECB31BCD7A797C6C8F7D7F892 +:10C3000059E36F8DAFD397C67962E5357E63657665 +:10C310005AC1D2219C04FEDA3E0E8FE3B6AEF15C28 +:10C32000F6DC8D9FACC90078BC4DE7D0EEB6843802 +:10C330002596BDB1C1EAC4FE5BD7F86B218FEF2E05 +:10C340002A9CA027BBEF7703FA5B3F81A02C7C6778 +:10C35000A92FC373BC4B2C640BC4BB85FAF45B1CC4 +:10C36000C0FF936F5847E17DACD484EBEB46D18D91 +:10C37000F0FBAB08C1F8831ACFED378D6C8E3ECF42 +:10C38000FC8435FF592BA5C7B35617D225C9E3E660 +:10C39000007EF73FFEDB09F2DD76D18C74ECABFA60 +:10C3A00043DA77AF5999DD36334ED90ADF93F26419 +:10C3B0009413B7C7E95E3C12EE4DA0788F92A34E5E +:10C3C000FAF9F1BB440FD571149E44BB09F99228C8 +:10C3D0008AECD2C529FD28479A5C903047208F4DC2 +:10C3E000D3AB5C880B3BA81C8CB2D8C3E0772496F7 +:10C3F000D3795310ACC4C2FA6B114E759CCBC63CBA +:10C4000079CA977970388A6048141271A17F4DDF1C +:10C410006A7A7A6D02417959FBB010A8A3FD6C12BB +:10C42000225688AF64297201A41A250A329E17EF9A +:10C430005F4E30FFD296FD784287DD42857EC4375D +:10C44000FC8258FB797C9C862FCF1F406FE41C6ACE +:10C450003F00E68DDBCAC673BF66413BBD437FA884 +:10C46000F65891BAFE8EFBDCC4F209C29348F43E42 +:10C470009B517F68F6C9B8EB226B60BF68DC9F18E0 +:10C480009CB45B05BE1BADCEB7439FA8EBE69810EE +:10C49000D527F4FBDCD0C866B8072BF76326C75D49 +:10C4A000F4C9213F0FF8FBBE7AC4C81723C2542E2B +:10C4B000D5F6A132DCA7E1EAA843FB1983DE499E49 +:10C4C0003E2A15ED5C95DF8C78D6E4DB28F7B9774A +:10C4D000BB9BCD0C2EE6471AC6215C271C7236E8A2 +:10C4E000A5B778B0F7DBF2291E285CBF02F9A3F4E8 +:10C4F0004B381FB801E6BF2174BD15E4E47BAF27BC +:10C5000021FA75549EF6D3BC273EAE0FAE274EC01F +:10C5100043F5FEF3EA7A12467A77C8019593E878F4 +:10C5200089C6FF467ED7E4A30E2EDEC8C673760406 +:10C53000D6599E0BE2653066B2C90578D5ECED3A66 +:10C54000D5BE25FE74B4FF56BB88BA1E6506804F63 +:10C55000EA44CD5E775BA2E353AB1D05A997DB4FA1 +:10C56000F55EA4FE59D4391BAFD08EFE9BF7A28492 +:10C57000CFBF37FE9A2814793AFC8D891BDD157FD1 +:10C58000F17184B0FBC2FE9F9FDF0C237FDC277715 +:10C59000CEEF5AE2792542F547DEAAF57536193F06 +:10C5A000399C96D7552F68FB9FDDE901A3BC8FA965 +:10C5B000AC6FC6704B0FF2EEB5A9F8256406E8B370 +:10C5C000F1616AB7647595FFF3EAFCBC3686F7B68D +:10C5D0005BDB07833CADE73D3571682F464C26B0E9 +:10C5E0002B7613B47BDCFB8F3A51DE5B9274EB4FFE +:10C5F00057BBC08FF2A9D9A79A5D6A7CAFC32E55ED +:10C60000D71B2D3ECA355179A1F03C19E7F1031C27 +:10C61000752EE6BFC20157D0634F583D75C05F36D7 +:10C620003A9738D82F1912CE62F196B04E3EBB938E +:10C63000479B41DE82143FB0FEF9E9FA3788EB1ED2 +:10C640009EB171090C5EAA85C0BEE99747D860D536 +:10C6500004F3C7FBE5B0FB6BFAE5B2FB3237C73139 +:10C66000FB658BA17CC25AFA18CC4B1488DF9CFB6B +:10C67000FDE10650210EF9649CD200F8B0142B386D +:10C680008F0C17717394DE19429083BC89C44A9948 +:10C6900063F147D2B9FF48FBCB2891F3813F3206C3 +:10C6A000123C379A118A7D9EE89538F187D9EB8D37 +:10C6B0005DCEC1BCA2CACF4189CE37A9849D83E992 +:10C6C00088FB50F001BFAD8E5B71B2AD17D83EABA9 +:10C6D0003F81E1D9E8BF01C1605E825ABF57228223 +:10C6E0003511FD2B3FF0AFDF6441FFCA46DC41D07E +:10C6F000B71FC4B1F8EC3ACEBD1EEABF10DA2D70F8 +:10C70000CF8F26379A3C3C34E116B7405F755E7791 +:10C7100036077C5F2A17EF009E5B279C1DBC1667BF +:10C72000D29EC9F84EE175F9F61AFD9A441DFDAC8A +:10C73000105789D6F30E6908D8EDAD5C9C1BFCAA96 +:10C74000D6E51C8397B3A8E71104DD3CD36CCC1F5E +:10C750006953F5E7DFE3B2901FB5F584CE6F3DC6B0 +:10C760007F0DF3E838876A38776A3C979A96DD112F +:10C77000074AC77CDC5209EE3223674336B4E3BC78 +:10C78000CEF64C12E3BC646AC41AF35CB05652BCD9 +:10C790007D0D784B156B12401FA7DECEF488111F5C +:10C7A0006D9C7FC441D847FB8318331F452BD3D2E0 +:10C7B0006E4A584CDF4F4BBF014BED79835D8819B2 +:10C7C000574CB2713FECDC6403B118FCCD241BED77 +:10C7D000EFB4E79DF71514FF768CBB37C431BC3737 +:10C7E000C431BC37481A3EE57890BFCEBA5B97F7A4 +:10C7F000B4C1674910200FD19F8EF2B9C4C5E8DDDE +:10C80000F9BE82F64D1FA2DC301794C406916C432A +:10C81000BE67F121ED7CC8AF7CCF2440BE94DB968F +:10C82000A5FAFB1646DF0406F7F90D5370DC14B2C7 +:10C83000C63A98E27969A9C90D71A3D30B3F72C2B8 +:10C8400091E985192D79200FA7798F1BE6974A98D2 +:10C850005FB86C8E1408D32E931BA8C26274BA0101 +:10C86000F73BCB4C31F3AEC7D8D8FEE9D138179699 +:10C870006969D3904E9DF59204F04B8C7C4AE53566 +:10C880007DF1A8CE73CC946F145B0C796B134913B4 +:10C8900087EB5B18F195ACB1B3AAB7357949063986 +:10C8A000847DAB52AA47353A0F505F4DC1B828FE80 +:10C8B00071A1D7BF067FC3795D01EA454D8EC810CF +:10C8C000A6E7ADA077A3E2A16D7B3FE80FFB8E9FAB +:10C8D000FCDB3907EC3BFD556877809E3D7ECFBB86 +:10C8E0000E38C7F4C93D2C2E7287C14F5B6463FAC2 +:10C8F0007F8FAD741EE07781EF1F799E287E2577AC +:10C90000B3FD93E501DE70DE5D7F6F505530C97079 +:10C910008F901FF15AA5DE1F66A4C7461B8BB72C4C +:10C92000DFB159CA90617C4F258C7F5CF5438F370E +:10C930003AD0DFD1E059B8638404BED95F4366754D +:10C94000FFBD4564EB875202FB671E156F46380F2B +:10C95000AAF76A2FF925CB8F29A363DD4DF5B02700 +:10C96000C4CE7B18E7B1E413B92895126FC9FD1C3A +:10C97000FADDF0FE3D743DF3DC7D1FEEB319E7D91F +:10C98000F55E1F05FDB3652ABD8DE76D9785D83E21 +:10C99000F862E241F9EC72FE36C4CEC518E38D6749 +:10C9A0000F65DB000FBFB0A9F1C43C3206CE6DEFBE +:10C9B0003A3420FE72F7569F52EF8B827BBBA13C2C +:10C9C000EE2358CE032390E2BF32F4F65DC05FD56C +:10C9D0004D3BF13EB4EFAA8FAA42279C904BADE9A4 +:10C9E000256A876E03F9208B399D7D5ABDF99CC459 +:10C9F000FC6A869FDBD4E7B7013E7220DF5BFED97D +:10CA0000044AEFDB2AC5F3D1F7A53D6FD3EFC3F797 +:10CA100076BEDA3CB5796BED556A5E9CF13B4D0E06 +:10CA2000E6A97CB978EBF4757D298AEAF67E91A9AE +:10CA30009E93C3F3421A9F2D23A545E931F849A3DC +:10CA40006F07DF847E8EF3D3E8BAB8BE4CC5833F50 +:10CA50004DDD4F4C837895918F7A3AA7DD2A463287 +:10CA600041BE8D7CD2DACD7D28211BB32F16CB4A57 +:10CA700011C4CFA8F9BBCE1565DF1C17EA0FFE1451 +:10CA8000E46E2BE3FB0E3D084E31E8F737455CFFC3 +:10CA9000573AE454B8FF0FE9370EF213CC7E784FC3 +:10CAA0001BE7984F51068A80FF622C4FFA4A958106 +:10CAB000833ADB976E3CE704FBBB6D08C1B851AB12 +:10CAC000430FEF691B8F7AE3B44A8F4AA1E59B3F7E +:10CAD00083CEDADA827917C72EA971A74BE6E2581E +:10CAE000F3B4D839DDBD7877A872A8F9350B54FABC +:10CAF000DD1162FBE90B374D477A74C9BF54FDA1C4 +:10CB0000B2460EF58E913E4BDCD7633EDAA2403E34 +:10CB10007EDF855EE441A4BB916E77DA5DEC1E3763 +:10CB2000A146827BED8E6DE270FF7185107BFF73F5 +:10CB3000B6DDF49DE6639C4777F02FDB5ABBAE2F42 +:10CB400081F98F9080CF8DF06BF35F4214A6A7D44C +:10CB5000F976372F1299C4F234D4757F399C5B81F2 +:10CB6000FD93077996CFADC6A134F835788DF328BB +:10CB7000E22BF17C415B038F79D977F8D97D067779 +:10CB8000ACE570FDED8E4E9A5ED1F67BAA9BCA3065 +:10CB90006FCB43FB013BB6ED63C2F629D67378CF6A +:10CBA0005BB7F40CB17CA5EEE84908A3DB624A3719 +:10CBB000F03FBBDE9F90AF0C8CDE270ADCA00C8C14 +:10CBC000DEB72241CC5759B17DBAEEF98D76358E5C +:10CBD000A5EAF59EE48FD424C48C6F69F2A6C99FA0 +:10CBE000268F77DA65666F0A81831959809F87D10E +:10CBF000BFA1FA7A9E9DF93D0FCDA5AF546F3CA71A +:10CC0000DBA7583296D16B095F82CFBBD3BB140F21 +:10CC10003ABDBDD8AECFC3F8A1F3D1E6A1C98936DC +:10CC20003FA39C18BF37D2438BEF19E962A407C01A +:10CC3000097EC65B7B6D813514CEB73806B77FAFF2 +:10CC400015E16E4D9BACC0B9CDEAF4F958FE013E3A +:10CC50004C07FBB0B4CE8E76AEEA878DEA5D5C22DF +:10CC600057B5CB5EB22A23D9B9A7D224E09389B5B0 +:10CC700091191617218F3E585C04F7A44E7C383268 +:10CC80000342F1BF7EF04656DF1679D7E286FBFC01 +:10CC90004B8A0A69FD71D02FA02FFA95DBE0FB6E5D +:10CCA000EBC473F9BACCDE1F652E9DCFEEB166EDF5 +:10CCB00095D43EB3D0F5AEF2F0E057417E2B5B4AFF +:10CCC0008A212E54091178BADE5529CEB02D87ADB0 +:10CCD000FBE3E97B1FD93C4FD921EE76712DAE8B5A +:10CCE000958705942F7288C567053A572BFD6E6DA1 +:10CCF0001CB593297ED7265ADCE017D3E77EF09740 +:10CD0000D7262AB21CF55CA31F7C0770AC35B17C1A +:10CD100082FD6F0C8E8F5CC62ED8EF2325E0CF34BA +:10CD2000FB2C581ADBF325179EE7C837B17889B179 +:10CD3000FD6DBB76AE49CE00BEA83E24A1FCC31F4C +:10CD4000D89F5584C9493561E7D0AA0E133C775363 +:10CD50007DA808CFDDC0B9844F757AE05F73EEA679 +:10CD600093AF189E0A04AE44881AB7D06ED5D5F991 +:10CD700054D310980FE1E3DC706E84CF30D5ECA271 +:10CD8000F3E7AFA025C587E072F370FF4CFDE4899F +:10CD90003CDC9F5527AA792D26763EBE63DD57E5FC +:10CDA0004F2BFB394A8F02DD4FFFB125CFC6F6531B +:10CDB000D0AFD6E65BC72984037FED3582E71972D1 +:10CDC000934933E0CF4694B1C06F1647A2CA976C1F +:10CDD0003F9BFE6540E9369B7E23537EFFFAC19F51 +:10CDE00022FFBBE34DABB2689D73F8593DC3742E6F +:10CDF0008BB230EFA865F56B4CE706D0BAE858C3A4 +:10CE0000EAB0F14A173EB3A3AEC83F14C67131BAB7 +:10CE1000EE50AE01FE164C2CAE231C90707F47CB1B +:10CE200057594B7906F8D1E2607A745D6DC173365B +:10CE3000889B172832E44FEC51EF41FABEA5865784 +:10CE4000DE66427F094AC07FBC83E153A30B69546D +:10CE5000AE813C5E1254AE817DBD7E0E4FA2837EBC +:10CE60003FF2AD9689A0CF1BDFF9280FEF73BF8289 +:10CE7000F533F22DEA43D2F99CFE6DFFCDD1FBE4F0 +:10CE8000FD1CF9A9F01D2503DAAF9CEC22B751393E +:10CE9000AC53882C65839FADF72F1B09D34F1FD947 +:10CEA0004AAF70A03E09E33AF613BB6700D48D7E0B +:10CEB000336949EC55DE9D947337EE172566347D52 +:10CEC000B810D685DFB17B4A3845C1FCD3173BEE9D +:10CED0006B231897B2913837C48D899BA4F953D42A +:10CEE000F89A89F155725E94FFACCE877E5F08791F +:10CEF000F2636C2CBF81CE8F07FD3A82C8588E84B6 +:10CF0000385936A0D883F53D24F8E14F69FF8F5892 +:10CF1000597CCAB29DE8E28F650E16B779C0C9E2A6 +:10CF20008F7162F016B02BE2CE1017D8156D8F4BB3 +:10CF300002EECF0BAE9B70DFEEA009E3DC4F8B015E +:10CF400017EC17B55F25C85B48677F6D2ADDB57E96 +:10CF50001F91E4AB20EEF70B27AB3F9D4F308FBB0B +:10CF6000FD841480FDDCC40C4B4D743C699E83D958 +:10CF7000BBBF7315CC043A04F7C611187FCCBE387A +:10CF800013D0E3B91DB956E08B170147140F89661A +:10CF9000D79DD05FE2390A6F163E67F9FD823C22C9 +:10CFA0009EE277FC8D7619EED17ADA1ABC11F3562F +:10CFB0009F37E1BDC12F4AEEE9507FF1ACEC023D55 +:10CFC000FC7456300EE7F3BC09E7F3625CFBD52B2B +:10CFD00029DC0F0C61F12EC14604D0CF82A940BEDE +:10CFE000933E5FAEF2B1A6AF37811CD1FA231CC1CC +:10CFF000730C82291FE548CB276A6B27984FD467AB +:10D00000660B0FFC1C375D8B3B857988174D2825F7 +:10D0100068CF4DB08B78CE05F299E1BCDB44550F5B +:10D020004FFCB8B284E507BB0FC3BD9ECD76F57E3D +:10D0300030759F7392CA27D791086FA1EDD75D24F1 +:10D040006E88274DBAA8DF8F78CA605F4E51FB57B4 +:10D05000DA5D85F0389FE8EDBF290D4527603D2C4E +:10D06000208A00FC34D96268073BD209F7F0EB9FB5 +:10D070003FE050FDDC4C92199DC7A6ED434DE18782 +:10D080006E44FBB55872035E76DA950F203FC0DF21 +:10D090002292CBC5259FF2B17CC321176D04AE2C23 +:10D0A000A4FC6987F95CDD50EFB7D2795F3D90F55C +:10D0B0000F7C08FAE5CAC7939340DF8F57E9A5951F +:10D0C0001ADF017FB9E2197FB98677CAE7D38E2CC0 +:10D0D0007C4F9337E03BE8678F18981F6BBF9BF23C +:10D0E000EBD3C0AF3BED04FDB89FA55BE6809C6928 +:10D0F000E3B4AA7C6D2CD7D5AEDC0FBFFBE4BFC078 +:10D10000D68DC2BE17A5E875BF4F0283D72BD7CFE8 +:10D11000980679687611F3CC52D47351D1FC921EE3 +:10D12000C52F1ADFB5DA599C48E39FC9BBDFE5E19B +:10D13000F9E40B84B8B24887BFA2F1CF447F18F757 +:10D14000812712E69F18F9675737FC937F5E1640D8 +:10D150006F75E19F438C7FBAE31BDA0FDE6B61E4EE +:10D160009F771CAABDDD2DFF5CC2F3FCABF74EBE62 +:10D17000EC7E65934F9F9F6A2CC7D962E72FBB5403 +:10D18000BCEF96EA6FCA01BD31D5C4CEEF0924E3E6 +:10D19000160AEFEE38EDDEFC9A6CA8EF14981EDA52 +:10D1A0001932A31EDA69F778307E9B6661E757056E +:10D1B0004F04CE23B8FB5AE4E8DF21D9EE6076585D +:10D1C000500C8FFB02ECF137181F8C9D9ACB432A31 +:10D1D0005AFA62A617461D9736C3EFCF3DEACCBF79 +:10D1E000007C9606B8A3DF798F4A78CF52F55109B3 +:10D1F000F5E36FF7BD5D04F1512DCF79CC9EB78B70 +:10D200000A86C2FB8CDFFEA1EA65AD8E4740405F17 +:10D210001AEEDD1FD7711E4B7F6F7E29F0514E67CE +:10D22000BBF13EF9601CDB3F994D6411869871B4E7 +:10D23000F45EB8DECC78AFFCEC303BFF36F3B027C1 +:10D24000F6BDF22A7F18EF37A7F6778A13ECEFE7DF +:10D250005AF6416884C86CDD0E4A35D7303FA326A4 +:10D260001BF8499343FCA3F80B7E3244F7BB06B787 +:10D27000A9F37FD02DB0FBA92212EE4BFE9CB0EF9C +:10D2800082EA3A36CAC9F440EEEA17E6039C23CB99 +:10D290009566A0CBB32E16D7F905095BB2816E6EE9 +:10D2A00001F75382A23CF90BAEF33D22940EB1D3A9 +:10D2B000F63D7DE246C2F88F3A3D639C609F09EDE2 +:10D2C00087E0BB31E37347821EB78F589B04EB9A0C +:10D2D000063785AB789BBD130E0DAE814EC6978F7A +:10D2E0003ACBC6001EE03BD04B4D478E59E07B8DBC +:10D2F0001F827BCF303E88E20BE0834EBEE01640BB +:10D300005DC383A2AECFB7FD8BF8428B6BF4C81719 +:10D3100010B7707E2FBE980B7835F205B5E73CCE7E +:10D3200018F65C50627993C6E73FB1E7E3FB6E897C +:10D3300060DE13D96765BF6BE849C07D90DFB8D860 +:10D34000986D9F1CCBA4A62859E56476BDF63B2AB0 +:10D3500023C21CDA9F23A8A2B80DEDBC7EA827DD4E +:10D360002AFEC8318E83FB4631373E03ECD0701263 +:10D37000D86B23CC256190875DB68919603FE6DACA +:10D380002664C3FC5F1EB2FA4D58D25EEE5BFE9B74 +:10D39000AD72A77DA5E9C366B55B6DFC352A7F4CF0 +:10D3A00052D87927D0EBD17068EB039009E0E0C246 +:10D3B000B34DDFDA508F8722146F93000E8A87FDFA +:10D3C0001C6904FB21DFA4244F063BB04F580038F2 +:10D3D000DBF67E9D09F1CE92D0EB1F02BC25DA3E32 +:10D3E000AC5BBF0F6BB4B7357B48F33F347B49F37D +:10D3F0007BC1AE82F632D51F7199D9BED884B005F3 +:10D40000EF5378E4AC7C95A2CAB340E751A2CEE3D7 +:10D4100066D2827069F7A94C53F1517288FAAB3920 +:10D42000D04EC8548A87A9EA7D2A53DDFAFB226EC2 +:10D430001E1BFB3E15AD9F9EDE37AE1BD71AF6A313 +:10D440007E6879C8C7EE4FF9BD8FF9C3E307F07E58 +:10D4500001D6DFB159ECFE0917C3C32129F63A768C +:10D460005195EBF1A6480E9CC7DEBFE7EFB86E1EE4 +:10D47000D8F3F7F7C18E1C77422090973BFEC4A8E3 +:10D4800078CC0F182B235F69FD7A3F6FB411F69C9F +:10D4900044FFDECC410A8F7225C067C1F295538FDD +:10D4A0003C0AFD9D3F2A90E8731F45926720C4E522 +:10D4B0008BD4DF1D3AC8317B4A6B3FA8FEDEC71113 +:10D4C000956F212143BB67C51C45E7A9EAFD1F1ADB +:10D4D0005DA71E2F3E21E474A50FFCFD33E2105A18 +:10D4E000FCE19CAA0F49F39FF07CCEF58D770A6092 +:10D4F000BF5F9FC613256ADC1B64EAE947C5214E5E +:10D500003A0DF66FF3338F4E83BCE5B7784C81F458 +:10D510008676BE9903F5163EE6BD2A46FC5E1FBA26 +:10D5200013EF55991BCFE4A3A7F1C75F4DF96438FA +:10D53000D09D303B308FDD4B62A4EF813DFF9114D5 +:10D5400019DA3DBEBBA3BF910EAF9C2AC07DAC9E35 +:10D55000E861E4DB7D749EFE2BE177532DC48FBF21 +:10D560009BEAC2FAABBE34AC6BFCEADDFB6412D8BA +:10D57000791A9F4E49627C336EF7A349C4DE492F66 +:10D5800023DE86C533FE7FC9AAD925EE59D3E8A389 +:10D5900077E93A848CEA272D903756AAC23AFB7075 +:10D5A00011DA25443DCF625CDF66F3B74D0175DAD1 +:10D5B000D3EFFECC94CB7AF57B39C56FD50BB00E8B +:10D5C0001609AB991E53ED780D1E239DDF23A50888 +:10D5D0007F77F019F9C008E74B1DF9F60AAE07DAB4 +:10D5E000EFE0CC18982526C69887868F9984AEC719 +:10D5F000D9BD5F8F6F8CD7DBEFE78E17FE11D0DAC6 +:10D600009DBC19E9666CD7F447110C908BA51FECF3 +:10D6100093B9F12948DFA28B1251E83A43FAE9CFD6 +:10D62000F593922B91DF56B9D8B3EEF8ADFA224FAD +:10D630003C233BF94E6C7AD8067CB75BA8B7411CFB +:10D64000F53AFBF43A10BDC2CF0B66E2FD1511139B +:10D6500081D0DA94D099668833783F2478BEA120AF +:10D66000B47F32F0E9AB420BFA596DE7097938CA59 +:10D67000EE6C0AD5D9C02E6B4A66E7F30E26105D14 +:10D68000FEF4C578A66F9A8E9E9DA6C4681FEE62B2 +:10D69000FC3C8328C939F49F45EB297F801FDCC7F8 +:10D6A00081719242CEFD5A32D82D7339F423DAF6C5 +:10D6B0008E792D99C2DB7A7B02EA99294DF7DDE953 +:10D6C000A28408FE63243E6F2FE3F0FE8422D98DEE +:10D6D000F5A2C559E8F78DF926694609B4DF20A2FD +:10D6E000DF3385AF14205E753A8DC3AB3CF6709185 +:10D6F0005AF83D62FF74360E71F993C03F7DA7243E +:10D700006904FE669EACD507E1EF2E1283FFB6FAE0 +:10D71000A573FBCDB47DF52C0EF38DA7B832883FF1 +:10D720008A7F8AD64B38AF5B42A905C0D7338AF5CA +:10D73000E71EC3AA3D39ABD44602D1FBF99C0BE5E9 +:10D74000FAA0B5FD56FC1DF1BD2281F969727EA3D8 +:10D75000CAEFB3E724E9BE9B4E98DDA9C9D54DAA0F +:10D76000FCDDA8FACD733D19BAF14B09B387FE4031 +:10D77000DA0B8164F7B8D87EF4B4F696C3F3E125EA +:10D78000BEDF68D087370D31F8BD7CE55AE48B34B5 +:10D79000CE8DF7C8B8F5ED378FD5D78DF26BD40F96 +:10D7A000B3208B8FEFAA27347D306B2F2F423C683C +:10D7B000563EC533DAC57ABBBD277D3126AE1B7D0B +:10D7C0007149BE17CC902EFAE2E3E2EFA52F7E4B13 +:10D7D000DD96B154AEDF8E57D7CDFEA43FE88D293C +:10D7E000FC8E47818FDAE8BA698EC147DABAA3C5E1 +:10D7F000018AA81CA31E38C5F663A65C4C27FE91BF +:10D800009D71800E3D42ED12770C7BA9353E1BE5E4 +:10D81000AB43EF687A25CA2E11F37EB85D3285DA04 +:10D82000A3522EC0D70FE12B52EF252982842B88DB +:10D830001FA69DC1389057A0FE2CAECF4F227F81EE +:10D84000FEE3123BE5C368AF6871E80A97664FE9EB +:10D85000F9A5231E3993DDC3AAF14911E013E47F32 +:10D86000268FFB04FF1BD47F03B300800000000061 +:10D870001F8B08000000000000FFC57C097854558C +:10D8800096F079F55E2D495592AA6C148BF012B67C +:10D890008424588480EC165958A314A080CB688146 +:10D8A0000B6B129A719CEE69FFA642024343B78349 +:10D8B000D2DACEE8F457D83A831AB40801039DD0DF +:10D8C00015504C5834082EF8D91A6D1AD10E4984C7 +:10D8D000D646BBBFCFFF9C73EF4BAA2A854DFFFFF7 +:10D8E0003FDF9FB47DB9EFDE77EFB9673FE79E97E3 +:10D8F000DB9B55B3AD08E0F6998A071400D0F177A9 +:10D9000022C042E07FC3ACAD16F08EC7BED7FC6923 +:10D91000870DF8E73BFC2F9C90FC2CA450CF0B907C +:10D9200009B054CE5FFC577D333D5E3C277AFE52F2 +:10D9300098FDB9920C701BF8CD301CF7F3C58EFF23 +:10D94000EC4B15C7972E8B7E9EE94C4ABF9087FF04 +:10D95000180123BE5301CAD4BA9DB722BCDD275596 +:10D960008F554C33D1FE0F39C5FE0F35970C807C97 +:10D9700080DF7416A7F8B13DB611211C0DD0BAD1C5 +:10D98000C6ED71EC07F1C5EFE8E7663C9F05FC21A9 +:10D9900007B6B45221B701480518EDC4452760FF0A +:10D9A0002A9E3F0DC78624C0EF73245CD900AFE7E1 +:10D9B00098E704F1BDC3B85E00D70DE3FA015CF748 +:10D9C000C84627F75FDBE8E6FE0D2E446A06C0FA7C +:10D9D0001427AF372FF776871FDF5BE3CCE6E750DE +:10D9E0003EDA44F836E02F7B6A080410DFAF77ACEC +:10D9F000D09474802AB7E2B166F5D1014FE3588E16 +:10DA0000F3CB25BE2BB72A10C4E7E51FAE2B07C406 +:10DA10005F5733EE87F8A92A558336FC6749D363ED +:10DA20003B45DF0CD608FADE228E0233B516CD86D2 +:10DA3000FB2CF0281E15F7F13689F76FF52A411DEA +:10DA4000FF798B279A1E8763E8BE58AEB380FE0F1E +:10DA5000DF5B30470986719D0593A2DF5B7C75D63D +:10DA6000E7CAD8FE7CB498E83EB63FBFDC4E74B738 +:10DA7000E33F86C130A2FB958BA56F8D853EBAC56D +:10DA8000B6B1748E1DBF169DEF273A675C9BCEC65C +:10DA9000FB7F8BCE0F114E90BE70F41B8B9E04301B +:10DAA000BBE9071AD179F6558DD7AD32CE3314863E +:10DAB000D279FED459F86FB742DFFCAAA62F2DFE0B +:10DAC000826B9FE76FEDBF2245E7FD695F6F7EDFE9 +:10DAD000BEF33480C178CEF939D1F88DA56B2CBD59 +:10DAE00016CAF762E9B535E61C065DA013996860B1 +:10DAF0001CBC5F55198E6BD1AD972E16FF084F7E5B +:10DB0000FF71805FF3B9FAD693748276CD5720E027 +:10DB10003247C803F2752005E95BDE0AE14404ECF4 +:10DB2000968B733ED7A8F528F069C439E8E753838C +:10DB3000CE6ADFFA655707B2FC19FB966910B0147C +:10DB4000D2732197B1F055D23A23697E80F968CB20 +:10DB50002ED3B2109E63BA05EEF5519B28DA034E20 +:10DB6000A1071A9D265EB7FB2B9B096E0478E5F092 +:10DB7000806240F83C56E709D28B2133F0FB45C95F +:10DB80003ACFDF9C048104DC1FB4769B0FF9442B51 +:10DB900006C84139D306598235B8649D16F691DC22 +:10DBA000757B34A846B9BBD178EF48E02E40926C23 +:10DBB000FE7494A9268BDE0FB74FC57937156AFA24 +:10DBC000369CE2B2EA3FA0F1AE66AB93DEEB3EF8E4 +:10DBD000CF2D665AE72BF02084F05A3332158E4F42 +:10DBE000739883A437CAD493AA09FBDD3D00A48FA0 +:10DBF000A62D0B9700D26D3AB4D738B19D42748CE4 +:10DC000043BFBFD0793384DE1A88749A21E9344344 +:10DC1000EAAB926695F54649921A84AC3EFD74B320 +:10DC2000A4D18C407B490AEE3B43533C35D8BFF925 +:10DC3000AA16C58F2F933EBAB14F1F95C9F5BD3DAA +:10DC4000BA869601664234FF96350A3D54628B7956 +:10DC50002EED0FBEC97C55E68C1E9F42BA13F9FB10 +:10DC6000628C5E8218FB53A6FE35B903F1F08AC5BB +:10DC7000FBDE5484BBE7B4199EC5E770113B93FBF0 +:10DC8000E3A731C61EC5B6070F277A7584EB15E2E8 +:10DC90002307F50779F5B1D79E3FB6A3A7988EF174 +:10DCA0004ADD220DB2992DCFBA33FBF0DE0FBF92C1 +:10DCB0000EB178AD977ADEDBE87C8D8EDB0F8FAD11 +:10DCC000B3D89E97FC49D748F5FDBDF834E4E595F7 +:10DCD0000B895EE2FF572E0CF2B2FD4AD2593E0C80 +:10DCE000793878FE7222E951C4A7AE219FF4B86C4E +:10DCF0009E67999F851C84068E0A6EC3FE8524C18B +:10DD0000F7AF24F61CCF23BCDF62F23C4BDB68EBA1 +:10DD1000872F2A20FDB975D1793380E205E5872860 +:10DD20004F8AEE84BBB10DA03C11FF055221487211 +:10DD3000628610D0BE355E789ADA19D3F414C2FB2D +:10DD4000655CB3DD41EBE929C4F7F0D72B137D0502 +:10DD5000FDF15FBF117C1AEED3B0D1E6D3502F1C7A +:10DD6000D8E8E47EE34637B78736EADC6E3A91FCC2 +:10DD700043F21FAABC169F16A157E6A50AFD300361 +:10DD8000F50EC13503946000796FC623C0F2887226 +:10DD900010DCA410BDF03C397DF844FA5CEE88E854 +:10DDA00043AD563B2193A582E95E9867E2F7D1091E +:10DDB000083E9FD57F3ED23FAABF8CFC1684C3EF9E +:10DDC000F296B9B00D397CB35D88DF7A65E9D14B45 +:10DDD000C0FDB9F4BC5EB943BD84EB8F0FCF841F87 +:10DDE000A2BD188F8421BCE2CF5D04FF84160B1006 +:10DDF0007DD0B0B27C161AF2F9B5A25CC0FD4884A1 +:10DE0000BE1B8CEF59CBC3C44F07A0238DF05E64BB +:10DE1000F3D9497E97B9043F7895DBDD0AAE3739EF +:10DE2000C3E25109B4E1BEF1EB117F2D19B821CE47 +:10DE30006F69C91CA2E713B7BDF13EC9B7D7E608A1 +:10DE4000AB6C98CC9D1D11F67C003CE3247F927452 +:10DE5000DC7768475A3F4E0EB09EBB6A09925E6BF4 +:10DE60003D93EC09E33ED3AFDAD8BFACA717516EB0 +:10DE70000F27268F653D13420D43F26313E7986D1C +:10DE8000F6AF233CA0653E7A0ADFFBED6500D2AF1A +:10DE9000D3DB3F54C90F2D31E50EE840388F2AA35C +:10DEA00053A87DF2E3E47C6ECF2477127E0E9BECC8 +:10DEB0003AEDFBCE46BD7404F2CBA98D503A02F97F +:10DEC000E3AD8D366E4F6F74727B66A39BDBA33818 +:10DED0004EFCF33A8E137FBD81E3D46FC3716A4F5A +:10DEE000E03AD47ADF7298487E67BCE5D0A82DBCB2 +:10DEF0002B89DBFA3B932C748EC3C95067EC4FFC23 +:10DF0000144E0C378007E52ED5FD53DB0D683FAD71 +:10DF1000FE02651CC0D454F75C6D3AAE3B7BE88FC3 +:10DF2000BEC2F119A9C37E6A43786F3BE3683889A2 +:10DF3000FDD2C7F59F3A883F4F24A292243C64B794 +:10DF4000795136C793D218C468F7C224ECA719FDDB +:10DF5000ECB9A5C80A4B4A3AF2C005B0F3B1E17377 +:10DF60006D88DF2576FF3F51DF12689B533A9DFA9B +:10DF7000107092BC2BE620CBFB10257D11DABFADD3 +:10DF80000EFFC4D4087FC0ABFC218DF4C344AF02A4 +:10DF9000AE74A67770A4D2F7DC98B7D55136311598 +:10DFA000F9F7D72E95F969C234C51B74F4975F63EE +:10DFB000DE84F37A29D16FE2C559B5D42E98E3E215 +:10DFC000BE6FD94DB524FFA58E6BBD5FC2EF875CD8 +:10DFD00066D647C51ACE8B63178D79E391C9C8FF02 +:10DFE000EE694B0C3E4B7C7DD65F9384FD327756B9 +:10DFF000A12A753470DFB56B1B8D97BFDEC072E54B +:10E0000049F2E859C48AEDA569383ED3A178C22403 +:10E010002AD33EA94DA371A7E221B4CDF48E3B557E +:10E0200044E32354CF4CEA9FD54B9DD89ED1664EF6 +:10E03000BD84F366E7A4786CF8DE99F08FAE10FF2C +:10E04000CECC49F224E81417049FAEA4BEC7EAA9B7 +:10E05000D6E91C8F9524D33ABAE23161BFFED6923D +:10E06000FF457014FB52405168DCA5911FFBE4C7CB +:10E070003F2975E2BCFAA10A90FC9C09E7FE91E0F9 +:10E080009FD99AA8272040F5166729BD576F519C44 +:10E090009BB8EF2BA1F9815166FD795CF7E49D7681 +:10E0A000B607E56FE5B35F74F2CEC16C17CADF9AAD +:10E0B000564CED4993F0DBCBDF2A9FC3E326089350 +:10E0C0005229BFEB1FF8BD1D253F294DC7F54F0C49 +:10E0D00073B16E413A956A117A0DE78342EFDF55CD +:10E0E000C1F35B94013F3A8FF3AFE4A7145A71FF79 +:10E0F00059E90951F3E70C7145F5E78D1858AA4520 +:10E10000D8B1F2FCACA8FEAD454AE98888F9BE69F1 +:10E110000951FD45A5AED21111F36F2B1F18D55F24 +:10E12000725B56547FA669B2D01F1BA1BC54C87D38 +:10E130007929FB9BD9AC870A9D62EE1B387E3F8E06 +:10E1400017B6097FAAD085FE14D2A5B4AD88FD808C +:10E15000367C8FC68BEC528F05A0DD3D91EC80FCA8 +:10E1600009E22FF68B6577663BFA056389AE68B7DF +:10E1700023E02F7544DBF1FA44E127CC017FAD0B9E +:10E18000E939A7751EFB5765E9D54561207C46BF77 +:10E190001F0B372AD19D77131FB66AAC37E70C895E +:10E1A000D9AFADD4C17E8CF4EFE6C8B78C7D21E049 +:10E1B0006D27FFC63887B1FFB5CE33479DC67EE1D8 +:10E1C000DF3AD7AC9C85A5A971E15FCFFE4C2C9CB2 +:10E1D00079A9324F81FE15FB85ADA9EC2FE24F7A6C +:10E1E0003C3FC1F07FCA51CFB922F59C43495F58EB +:10E1F000706D3D67AC7B2DFFCF58D7781FEA54DE9A +:10E20000DF78BFF7B9AEC47FBE1BE727C5799EAEE6 +:10E21000C47FFE5CF4FC199A5EE340793E0E8A27C7 +:10E2200040783FA96BE49A959CF5D6525BF6A15FC6 +:10E2300023B770F6F9402DB5533B8327AD78FEB96F +:10E2400039AA4EF907C32FEA1767A50A7FE4F855E4 +:10E25000DDAEE3787D40B753DC51FF886EA7F8AAA6 +:10E26000DE0B73288EF40E37ADA738C49B872DF6CE +:10E27000EF4D15FA7E857CDF680FA9FE15047F85BA +:10E28000ADE351F2492ABFE9B1105F1C277F2FBFD0 +:10E29000BFBF775C0B3A68BFE38F041DBE087D7E6D +:10E2A000BDFEDE2262A60CE253C517A94F4A6C09D7 +:10E2B000BE48FD51E67445F5C793FF83EFCD760F59 +:10E2C0008C7A6FAE9E15350FFDD81CF2876A2C90A4 +:10E2D000A3913E35257AC8CF8BC5E3EFE5F93D0E16 +:10E2E00027B951604ED7557F1CFBE42911F88B7D6F +:10E2F000BE3D55C47383C89EE33A2752756E6B5575 +:10E300009F70E6D07F267E88ED63ACBA8CD6C3952D +:10E31000DDC4771EBBE90ABAE0F0D2E3F3E76A682E +:10E32000FF3DE34DFF381CFBC71E5F21FA534DFB39 +:10E33000B2B1DFFAF87DA27FA369BCD983EC19B82A +:10E340007F6E29F90BE9BE7F27FA759B1D5B15D4FB +:10E35000039509A8D7B0D54C0A14A6F7C5C7DB2D7D +:10E36000685F91C0C86C5E17D2C06E15F17465C24B +:10E37000D020D913ADD8AB13DE2A130C7A77649270 +:10E380009D87DA0951719DDD82EFE1FB6536FF0B58 +:10E39000826FC2C93AEAA5870E960D20FE3891EA2F +:10E3A000643CE4ED9BEA267D85F0ED21FBFEFF0158 +:10E3B000BEE678F0D59AC53E9DF57925648FF38643 +:10E3C0002179943EFA156A3A3F4F0821EFB0BFEE2B +:10E3D0007553FEB1C665F190FF7E42F2EFF5B6359A +:10E3E000328FA1DA051FA929A6F57BB17D5BF2CF9B +:10E3F00019B92F6ABEA10B913FC0D933745181E87E +:10E40000137FA86A610FF9E13DFF90E4A1F8F98359 +:10E4100044813F18D2F3D18FF1F97B77E779B6F1D8 +:10E420007381A765C1EC9A0EEC8FB3066FA0FCE375 +:10E43000A134FF4784873BADC191CC878EF549B4A9 +:10E440008FE2058E538CF80FE33CDD32BC7F5C70AD +:10E45000EDFDC1467665E9648177637FC4B18DE8DF +:10E46000F1DE24F1DC8007E1E8263E30E0EA8507B2 +:10E470008638398F0022FFD425E38B2E5A8FECA7E4 +:10E48000EA1079DC3F9838FF5245C28AFD7DE74D9E +:10E490001C0F1A79E02210FB4D3EB54965E003F8E8 +:10E4A0003B51A2965E695CCBF1FD84762D26FEF68B +:10E4B000B23D9D2ADFBFA9D55FE2A0F6FDE8795302 +:10E4C000651C3F09822AC559933B62C61BE77F46FC +:10E4D000EB4FBD18FD3C294DDAC3413028324FB215 +:10E4E00041C64D974F66A7101F6B182BA8480F8B7E +:10E4F000AEC2A4D43E3DD3B011E759499FDAB82D3E +:10E5000038EBBC8FF669DC880C3F9AF4AA9B5B431E +:10E51000EE0ACEC2BD3036621F2917061E2FBF2F4E +:10E52000F038AE23E797D3B06F6E354350EFC3C3D7 +:10E5300014892F0CDF38FEBB7CD1C1F66B62DB6225 +:10E5400095E4D9EA36811E71BE043D11F4087D6C54 +:10E55000CF498DEAAB929EB509D17ECA78B94F9268 +:10E560006750D47A86BF62D0F350EAAC56F263C6E5 +:10E570003B56B1DF9232293B6AFDA293D1F82E04BB +:10E580009F97E263CF87C071C0C4B35A947F32298A +:10E59000BC83F963D287D1CFA79C8FEE97A6C9FC25 +:10E5A000562CDDAE854F18FBCB69E97F3F3E5DDE23 +:10E5B000687CA6CD89C667862F1A9F039645E36BB4 +:10E5C000A03F1A1F83578D891ABF617D61547FD880 +:10E5D0000FA744CDCF428319D91FBE755ED4FC91DD +:10E5E0003B1645F5473F7567D4FCDCE08AA8F1BCD3 +:10E5F000DD6BFE2EFA17843644CD27349BBE87FE92 +:10E600003736FE4BD47EFF53F4AF8DA1FF56D2E7D1 +:10E6100013885EA8370BFBEC19B925A43F5D4D6F3D +:10E620007C43799B40B1CEF9AAC03CF0D4E0D82F0E +:10E63000549F427A6E30A2DA847AA3D604ABC81E05 +:10E640003C6A32711ED390F317D3843FF2629AC8AA +:10E650007B19787B1AED22D94155EA4373FA8E244F +:10E66000F253549309DAC9FE691ED61FE71C10BE87 +:10E6700019F7550701E7C54A92272D9888FCA8BECF +:10E68000A972FCA90EF2838EF6A4E6E4CE53849F11 +:10E690002B0E9B4E7CABA6FA0364DFF09CA1E7A196 +:10E6A000BF9FF3DE465849F196D15FE65EBF99E61B +:10E6B0002FBB7BE6488A7F7B9FDFADAC2C8DA043D0 +:10E6C000E43917C5F1AB0EA409FB67D813C37EDC90 +:10E6D00069D56B3AD03E8C53857D40BB71200DF1DE +:10E6E000F181F28859F86901339D1FED2ADF27B8BF +:10E6F000D021DF806D4A9FDDD2BF43E6FA203BDAAE +:10E700006F7D9300A33844F7F03DE31D86FE5D95D1 +:10E71000CBF8BBEC889E7FF9FEE102AFF720F690C4 +:10E720000EE72CE23C06FC17A55EFE42EAE54ED25F +:10E73000C711F9EB55BB7626917F7E2E47F8E3C6CD +:10E74000F3DF493AFF2E4DE5F3AFDD9DB0FE7C04CB +:10E75000DE2A42AEA87E55E3C0F591F9CDB5C639A3 +:10E76000FC8A46E75827E5A8A2B523F94E607FFE4C +:10E77000C3345CB772D7957B0ED0FBA69E4C616705 +:10E7800003BCDFD2F780E382A57F8128BFB633CDFB +:10E79000CC7075A689386109364EE4BB25E803B80C +:10E7A000A87D63DA2CE23F7C1E56B0BFA015CCA436 +:10E7B000BF16FAB3CC84F433E079673F1EEDCF691E +:10E7C0003AEF731BF8F87EFBDD7B2A92D80F34D624 +:10E7D00033D64181203FEF3D57C09C49799FE90ADC +:10E7E000FB17B89F8D9EFBEE1EBC99ECB0B1DFBB52 +:10E7F000E0BFF40EF2C522F0F0BAC6FA40D73411E9 +:10E800007AF9034B2F1DED44BF0D6DA630E585361B +:10E810009CB3F2BD4A7775CFCB0F239C1FAFF9662F +:10E82000BF82707FB4BCE7BF0EE0F33B9E5241470E +:10E83000BEF1D9FD5A7A44BC79EEFE2B2C6FE8AFBD +:10E840003CFF2429A597AC1E92930FD6BC342A32E4 +:10E850005E484E9F99904EF73B93D2E2DE6FC4C65E +:10E86000A56B883F597E75F64B0DBE5C2DF972C3C2 +:10E870000BA3F9F986A4DEF388FEF32AE7C1363448 +:10E880005B39AFF18EE487352F7E333132CF578F2E +:10E890007CA95BA975724BF7A63AFA09FB4E5E1E7E +:10E8A000CB71ABEACFA2731EBEFA6932F5F7BDF9A0 +:10E8B0002D9F076EBB3EF8BB11799178AE4AEA797D +:10E8C00097F44AC501AB4EF9AC9203B927EEC27E6C +:10E8D000652BEA1F3CCF2557C7B1A7291E3BA800CF +:10E8E000E5B72AC309ACE42B1B9420E5C3D634EE6C +:10E8F000DD3218FB6BEA161611BB56250B7D5659F7 +:10E90000AF0437B11F3E87E95C2865A3E450EEBF32 +:10E91000E5E378D771B1FE858DB0F63CC69D5DF517 +:10E920005F5E2038D6355A39CF7621296C198CFB99 +:10E930005EDAAB84027A9FDC76B9441CB62AF4987E +:10E9400085F65DF5DCC211E436761D386D213DB9E2 +:10E95000AAE1B159F2799130FF41968BB5BB9595FB +:10E960009179ACD5E80E42A4FD42F80213FBEA40CF +:10E970004E49FA2C6B1A5E43E842BDB6FF6985F535 +:10E98000DA42E2970F0EEFF9DD6F68DF83FF3D9209 +:10E99000F15F747DF8075F80FD8B4AB90F5C3C63C3 +:10E9A000A1F8B2B2C17C21DEFD5263BAEF1EDACF0C +:10E9B000888F63FDEE2D1610F73FD9107C9EEC82F8 +:10E9C000A3C7B21CE1F9579A80F068CE1ECB0AECBF +:10E9D000DB48CEC85EB81DC17871F5BE748DF18478 +:10E9E000B1C4FA78F7A021395EA27758289F57E979 +:10E9F000EEB4105F57863F17F7FF8D9FCCF2C689A4 +:10EA0000B75F4E57A4333F274ADE37648C61B93075 +:10EA1000F7DAC3908DE5BE60450FD9A90D07913B8C +:10EA200014A2B7BF87E00EEC4FD0E97C25073E9FCC +:10EA3000D811B1CF1FA57CF4E6595EF964AC99F00A +:10EA4000B9EF93B15A52DFF3AE4CC7AA78799997D0 +:10EA5000D385DDDE9CECBB182D07099E30EE5BD91B +:10EA600064E77B1494832D2D45917270C7AA5DC411 +:10EA7000E74DAA0725022A1B17FAAB797E9287C8B1 +:10EA8000A336CE0C101FAA4E1FF327FC15F79B28A8 +:10EA9000EF8F50FFCD4DF73F4D72AC396065641E6E +:10EAA000A4D2D4F1AB1685E8BAC36BA2FD0A81F5F6 +:10EAB00096EAF075703C5594A953DC7B74C22C2007 +:10EAC0003CFDBC59E1BCAF39D5BF358BE87B5CE57B +:10EAD000F996A32F04E8BEBB6B1C14117CC6797F8A +:10EAE0003E2E0C2AAEB3B9003CB4EDE6834BDDC438 +:10EAF000BF3FCF38C67E86DD1302D22B35E83F50AC +:10EB0000DEC79E1F0AD33A0939BE2215F75993EE84 +:10EB100064BEB458FD1ECA273D20FB36CDB78AE03F +:10EB2000B3A5278AF87BC8F5E5F9BA48FECD746F1E +:10EB3000E9E77C4B9759F069D70DC07122D7FC4C9F +:10EB4000A6212FE3CD063BB8AD6A54D646DAD744AA +:10EB5000F0DBE879D7C1A51E82DF9C2DF93D33910A +:10EB6000E52276FF8F889FA9CEC0B4626B16E1992B +:10EB7000F0A6F79FF7A1E47B031FA0F973485E118D +:10EB8000546FBCFC923FBDF82CD17573AA2FC7956A +:10EB9000CFD7BCC2297627C6953B9CFF01C9B731A8 +:10EBA000BF95F089EF6FD1FC36C2EF51895FB3C5D5 +:10EBB000A73B59FE7D3AEDDF7BBE41F1CFF78D3C9F +:10EBC000DF966CFFF79EEFCFF27CE654E4375A2FC6 +:10EBD00019789E39391820FEAB4D82A24DF8F8A85D +:10EBE0006B969BE46ECB916F8692BCD72679DC4006 +:10EBF00079B1E69B9691DC6F197427F3FF172FE428 +:10EC000016AA11FB24A7177F45E73B2FCFB1C5E21A +:10EC1000CFA1737C2CCF699C6B49BAEF2FE911F916 +:10EC20002618927E5DFCB3D7B8D794719E47DA61FF +:10EC30008CF3388FD80D895C7FB657FAE11AF898B3 +:10EC40007FECE0D1D9BFF2C209AA2BA96931C13644 +:10EC50003A3E25B522EEFD925593110C7A6D18B20D +:10EC6000D335348D3B9FD839AF16E13E080155F8B6 +:10EC700069D1F90CF02A5E25328FF1DA9AEBCB6379 +:10EC80003CE3AF21798DCD634C0E9B965B52AE2356 +:10EC90009FF1DABCB8F98CD119D171514186CEC03F +:10ECA0008572047F86C28941913783F194BFEA2639 +:10ECB0005B85E39FE39959DE95AE1C9B0BEDE0135A +:10ECC0004F6CDB3A0DE57084C003F56B88C9F5F134 +:10ECD000EC07F5E6475E1BC37E38EA3D95F3024E2E +:10ECE000094B0C1D8BD07F1341A5272ABF123EF67E +:10ECF0006D32F1DB9E54FD2DA24F4F9BCA75280942 +:10ED00005A87C51547EE0E907F8076E09F33843E8C +:10ED1000B7358A7B4B9BEE653D99E0748E5323E4B7 +:10ED2000242F43D8A58A631F0CB5A02C5D329D4CBF +:10ED3000CEC7F5D7EDAF4FA634DEDA736F4FA4D24E +:10ED40009F3B35FF820C3CFF17CAAE5136F25BB7D2 +:10ED500006C7127E42E16CAECF2CD020A015F687FC +:10ED6000A7EA293C14BA04954FA5715BD0347E25DF +:10ED7000F15F55589C97F630A38ACC6D54B8DFD517 +:10ED800058934AEB55FDB67910E9AF9732849FF35B +:10ED9000E2D53CF1BE061ACDBF3FC325992A68A231 +:10EDA0007CE34B324FD97555E579C6FE058D335559 +:10EDB00027F2417E78C711CE8B365975A26FC27388 +:10EDC00020F0D194C07E68D5E1D94076AFDB051E36 +:10EDD00005C7F724F67C44FCD0D36CD5E93E37C197 +:10EDE000B9035271FD3DB21E2C1719B6DED1F7DC06 +:10EDF000D82FA1E997944324BEE07BE5046D074C2E +:10EE00007744E23B49D859C9577B12C326BA67E910 +:10EE100041DFEF5986AB0F4EE07D0D3873D90EEC14 +:10EE2000B1F45CF8713AC3E5243EC8050127348D7E +:10EE3000D649AF2638BD7C8E04A7EE0928FDE1AA8D +:10EE40001A8B8E20CACFA3A4CCA6F4C97755625FD3 +:10EE5000DF86B2B0271BA4FCB76E2B9D16D9478561 +:10EE600033A9EFFDFF78E2F8B6DA219CFF0BA84842 +:10EE70007F3BB649A9744E21572812DE8C42810788 +:10EE8000AA0BB4DBC478EF7CE473472ADB7F9EE7F0 +:10EE9000B13AEDF3B2585EF87ED1F00F1F52C217AF +:10EEA0006E46D2763EE64BC9C773759A8E3C5C8738 +:10EEB000F3FEB83C342A8CFD16ABFF79E2CF573F06 +:10EEC0005CB1BD80F4EF1EB3A79CF44F47E071F630 +:10EED000CB5F34EBDB22E40E86F46472DD61CC3E62 +:10EEE00055E7363D4EFE76F74145A7FBF46E73CFEE +:10EEF0005082BBB2E9330BD563561DFC84FDEBB2E7 +:10EF00004CFF5EDA6F526335D7CF4D861D5C3F876D +:10EF10007A91EB20436EA14F2E9F1DF56C75041D59 +:10EF2000DE93F2063DFE6164BF9AA4BC1EA6381CA7 +:10EF3000DBFD2D770CA7F5F7CBFC80F15E351C19B6 +:10EF40004C78DF04AF716B3CEF0E6A5CBF9CF7AE90 +:10EF5000ED5E6FC4FCD352FE4FCBFD5667FADF2047 +:10EF600078D7B67C6AA1D2C2AAF3A1A114F78634DD +:10EF70003DC519478FF4CA6F8C3C55693D169A5FA1 +:10EF8000751158AF20BD6B53907E2FBDDB386639AD +:10EF90003EDF8F3449213B8BF12AD9E3FD66DF60E8 +:10EFA0009A5FFDCED763498F1D2420F07F5F37AF76 +:10EFB0001D467843FE2F4E2439DB0BACD70C39CDE0 +:10EFC0002739C5F7F389FF8BA89FCB7A798FA57D69 +:10EFD0001ECBE57E13905C22FFB33C20FF3BC9DFD4 +:10EFE000CB77A23CF0FBA359CEF7B49BBCEC37A384 +:10EFF0005E1FC9FDE2C5D4DFD35EEA6439A73A8457 +:10F000004292D7F0115E270440D7F2450AF822FD5C +:10F01000FFBC8C64712F24F1393943D883508E9E04 +:10F02000E2C173D855354A3E22ECA5E84B7B5A9A8B +:10F03000F9976DBF98465226ED8453DA49FF78D68A +:10F04000FBFF286DD586D7A72CA8C3736E38A5F211 +:10F05000F86119F785259F1C91F91AB21B7A9AA8B5 +:10F060001FA6E713B04FF5E513BDEB4BC81C4D9A37 +:10F07000B3E328B5537CA11272DBA62D6B3F6A1651 +:10F08000629E47FCD770646E1ED5E3759FB3420243 +:10F0900082D8F06DCF472F221E1E3E8CF88F63A7BB +:10F0A000F038CC7FE87F0D0677FFF16E45EA91409E +:10F0B000D27CE2C7AE06B5AF8F8054226353DFFD2A +:10F0C000A47D7B006DE77F677A0767223ECF0CF057 +:10F0D00073DB7DFADB4C12CBFD67455CDF60F1E64C +:10F0E00011FF346463A81B874FAD9922EF536485E9 +:10F0F000B8F79C37670A39181580ED0AC7EBAA33B1 +:10F100008874BFD4A07A2DE82F5D84C092A9A46F23 +:10F11000645EF701903F5EFC45FA3C28BB0F90DF30 +:10F120008276EBC15FC4D61178D96F31F25800EB0B +:10F130004DC45F2B9B14F80FC4C5AA67A2E7AF9319 +:10F1400075F2AB1B771D1B8C745DF35CCC38F92D0D +:10F150007CFF11E278785D5D743DC3CD99D27F1953 +:10F160000EC3C97F41BE623D61D6A0D58A7CAC602A +:10F17000144322F69249E00BF52BCB67BE616F8AF0 +:10F18000855EEAB9045CA794BB3B7494EA81A6D47B +:10F190006579688F299A189FD29825EEA7B4A04A5E +:10F1A000750C93BCFE59EC7707BC67A9DE6495D457 +:10F1B00097E0C45FCAFBC8D3AF92FEDDEA606C9DE6 +:10F1C000A8C053959C37198235B4EFCADDA2DE6919 +:10F1D000EDEEE8F955124FEB9E3A7D8CD28515A1E4 +:10F1E000987189A7AAC6983A16B138DC9F29EFAD65 +:10F1F000647DFBF5D65BFCD12CFC8DB7E53AC6F8F7 +:10F20000E64C91EFADC463107DD705D520F1D12A2E +:10F2100025902CFC5E702CC7F3DD67B081ACCFBDB0 +:10F220005FE2E93EC93F7C7E7CBFE219F17DC5FD0E +:10F230003F8B867F0DF82C83F1F9830D3FB050DEB4 +:10F240003196DF56D599D9FF5D23F113CB5F6B7AE9 +:10F25000F9678785EC5B2C7F55FA956BC02FFCF620 +:10F26000FF5BF80D3AAF91CBAC3587393FB5F60966 +:10F27000C543F9AB6B9DABF73CF27C7FEFB99E3594 +:10F28000E83D06C630BDE7A45D17BD63FDEDBD9644 +:10F29000DEBC26E7052FB766733EDDE0ABD87566AA +:10F2A00049BF7DF653C27FBDD4586227FFA3FBA49C +:10F2B000C9A3E89CAF4C2EC0F38F6F5681FC91EE32 +:10F2C000A6E13B03087FE1A9A2C5945F1F7F0AED79 +:10F2D00013DD07B716FD5702DF077BD248EE67B68E +:10F2E0008D48FBBD83D761FBDE7DB2706739E9E9EC +:10F2F00093A545B4AE82E3549F5E28ED54F5C94210 +:10F300007B4784BDFA4DA6C8CF6F71FFFE518A1BA3 +:10F3100066EF357B283F32DBECDF9480F015BEA032 +:10F3200078AA71B763ED479EA47551BE28CD8AF3C4 +:10F33000FEE9088D57ED5118FEEEA6B2BC3D643FC4 +:10F3400083AA87EC6277D37DF90F921FD4FC40FE2D +:10F350007D11FB1D4B15FA66F60D66B6D79D83EC45 +:10F36000BF2EA7BCA87717EB8DCE43FB2CFC7DC32B +:10F370001E05DC78CE63EEA32F131E3A0F9CB65009 +:10F380001050D270DAD211477F1BED250CF3C29CCE +:10F39000AFDD61E1FACDFD7FB0D0792B9FFB84F327 +:10F3A0006F6B287E203FEF1995BF773ADAFCAA856C +:10F3B000F8B4B24E81015991E3661E27FD4AFDCF94 +:10F3C000EA849E36F87F85E47783FF0D795821F52E +:10F3D000DA7D5BE3F3BBA1FF1E04EF9641B8DE03C9 +:10F3E00075CBB90EE9811DD1F35752FC7A23CD17A5 +:10F3F000FCBEF2A9E8F1D5BD7C1E60FD1FAB47BF86 +:10F4000033F47F2EE4129F5F0EAF18A6A13C7D7DE2 +:10F410007ACD308893AF3C29FD06C36E5F0E9BD832 +:10F42000EEC5CEEB6ABC62217B5BD5FA27F673672B +:10F43000357DC9F4286F6AE17AD95BC0BF8EF07957 +:10F440004B93DD49FE767987D003F39AACC1A04295 +:10F45000E3A15AA273F761F1BD49E090C2FE1648DC +:10F46000BDB852E275A5C4E34A8CE306537D8C8C8B +:10F47000E32B65BCBE3A67D7312A29A994E3EBDABE +:10F480008E26131EE781D05BF342426F19F431ECF4 +:10F4900050ACBE400B770FD1776D9395EBD6E74B11 +:10F4A000BD35BF0EF596D25F7F740FB48BFCF17E35 +:10F4B0000177ACDDAD6C889EEF1A20FCD8CBD27FF3 +:10F4C0002E1C104D97F21EB0537E7F9EAE7A82FCAA +:10F4D00056BB46FBB78E457EC3F55BF5E129F1EAE5 +:10F4E000B58CF64D191718FD059467C3F921E70E81 +:10F4F0004764DCFF9F03847FB366B21A20BA46C418 +:10F50000490B0AB3E2C6497309F43786DCF7B371D5 +:10F5100091719277D728E2B77F75EF2CA7BAA6AA88 +:10F520003AA12FBA26E1BA29E4F703FBD15575D6E3 +:10F5300020C53355C82FFC7D1AF109C96393524683 +:10F540007C8271C6EDB4FE42BAEAC4F32F6C44FB70 +:10F550008ECB2F2CFD92F9AB6D843837E26D40BC19 +:10F56000B8C388372AAF0ABFD6785EA97570DC5158 +:10F57000D924EAB51B8E7C33340BE1ED6EFEF3D05B +:10F58000E5544F3E40D8E786E2D0A75457F4F51E25 +:10F590005B5CFFB557FF2BB52C0F95E68E4CF66BD9 +:10F5A0000EA21F7913EAD1B7BFE038A5E148C2BD6A +:10F5B00094CFEB5AE11FE6FC1E3A55C326F683377B +:10F5C000412DB7E41F45FA8D2B9DA24EE941693FBD +:10F5D000A9FF08F2F583387746617FF937F449854A +:10F5E000E4EBD510D83255E9AF072AA4DCACCDDF67 +:10F5F000B585AEF663FDA70A294F1831B0BD8CF56D +:10F600009FFE33865FABDF4E64FFB8BB4D7552AED5 +:10F6100019F1FBAB41E427625C901D275FFB85E499 +:10F62000CF4E797F5C3D4965FC99268BD6F0B710AB +:10F630008FCC37DDA71D41B26F79875FCD263E584D +:10F64000BB3BFADE89E8E8E7BAB1A0C84785EC7CA5 +:10F6500017658CBF74F8D531C46FD56F7F3B4AD026 +:10F66000E79B5196F46BC367B48A22E2669322E269 +:10F67000E6FD5A4732C56B5507555F643DBF41EF04 +:10F6800097A53C8126F203F50374E6ABEA26C11F79 +:10F69000A666D1E2FE4B447EC8CCFBF71B2F46BECC +:10F6A000F91E7B060417F24095B987F9AFEAB489D1 +:10F6B000E1A93A7D397344C47B015A7700E9BFEA76 +:10F6C00075C0FAC40EA46FE7D3F791D89FFF7E02EE +:10F6D000FB61C7B2B7978BFB2F15487F3DFCF69AAD +:10F6E000D191F660E200712F0E840737793FBF1089 +:10F6F000FB4B3C6C824532BF20F879AF8C9B302E9F +:10F700007B73409CB8EC7AFDE9EA662B50FEB9EABF +:10F71000032BD7197DDDBC92E37EB8EA1F4DFA06B4 +:10F72000FCFE1BA97DF8F0CAD1F4FCEBC3AB6FE47F +:10F730007CA9B2292ACF1120F8DCE45F7DF5EE5DCB +:10F74000E47FB669EC9F14B69D7D97EE69F7359816 +:10F75000F9DBD18AFD13760692C8AF2A9C4FDF11E0 +:10F76000ED6BD598FFD0DF32FC2B3BFB57A78AD837 +:10F77000BFC2757C416E8B4E94D3BAA78A8B689AB0 +:10F7800082E3A4D7C6937FE5E8F3B70C783E93F8FD +:10F79000EC6E49E0BC8B02D982CF604414DCEB1ADA +:10F7A0005E67FF645DA31AF5FD88F1DE5F06887B66 +:10F7B00087EF0C3E0B295EE6A3BDA25DD7B82F9361 +:10F7C000CEB1D61C623EA9AE338BF13DA205BA077D +:10F7D0009AC01F4107083F27E811D2659E2538844B +:10F7E000FCFABDBDF78AB22E2428EAF56A5A87F3DF +:10F7F000774C975BF7A5C7B34327E99E071DBEE388 +:10F8000059221E8A1DFFAD5BE4418E9F13FAF1F869 +:10F810004CFFE8787A3200C5225FA048FA3588EFBD +:10F82000ED63E735D37A78FEDD4302C7898F3BF776 +:10F8300026F0FD63A74BE4754BEADB34FA1E666DD8 +:10F84000833281ECD2DA9CF7F87B19EC17919E5C3D +:10F850001B3EC8F7AF15757B6779E3C0B1DD2DECB2 +:10F86000C33CF99D72ECF87C397E063C19329EDB74 +:10F870004EF73E67CACD4EF1DD9BF8EEF556A9D79F +:10F8800017DF62663FEA0CE866717F22EE391648A0 +:10F89000BD7DABD4F7B1DF631BFAFD76B9CEC2678D +:10F8A0006033DD73C47E9F7DBBF40F178197D7EF64 +:10F8B000F75DBDF41363FFFE42895BEAF551308AC0 +:10F8C000F47A08ED0DD75BE426B0DD9E5F3032AEF2 +:10F8D000DF41DFA9EBF23B756A0DFA57E7BEC7F6C9 +:10F8E000F078CBB997F9FB867309901DE79EADCFF1 +:10F8F0001E1A7AE436417779EF51E114301AF4BFD9 +:10F9000084115A647ECDA0FF83920EFFC7754539DE +:10F91000A045E6630EA9FE07DD195447DDC9FE3890 +:10F920009E80ED219E6BA83CD7506B849DBB3470AC +:10F93000795C3EEE3B5F6A40D893746E5B72ADECCF +:10F9400037568414FEEEB0220CA27F9BC2F9CA5136 +:10F950000D2D5CBFB1A454F178855A3C4BF0197C55 +:10F96000B4C026FC03835F7AF125F988C6C95FB865 +:10F9700055FA0BB1FC341ADA67D1FA4BBD8A87EA23 +:10F9800036AFC947CBC6BD4EE1EEB5F808F9D24C4B +:10F990007A31969F5E73FB1F25FC75B75F5E5280C0 +:10F9A000EB1FCFFD6C28F14FE535E4E84549BFDD9D +:10F9B0008EC071AE63A9977504F5B98D1D849756F5 +:10F9C00060BFB2D3D5BE6583F0B7B98EA0229CC00C +:10F9D000F5A5154D76FE6EADA2A13A710CE9E326B0 +:10F9E000D563C77E79C3E952CA239417893A972A07 +:10F9F000BBA8BBABB28BBABBB9E9FEE7DC13F8EF2F +:10FA00000344D711583A7EB5E17BF83E56DF359373 +:10FA10000F37E17F4E0F354BFC6C68BB923986C4C3 +:10FA200034DD7F88E0EE7EFD450B7D8A5135E6D5DD +:10FA3000595482D6ECD679DE2D752DB5945636E024 +:10FA4000B7BB9D42EF9A8343D86FCDBFBE7A9BEA86 +:10FA5000836F8C25FBD5D5D236D612C1EF9D1B50B6 +:10FA60006FC7A1633598A41C6BDC2ACA22E9470939 +:10FA7000B9AE6A3E9A49F98B4E92E77C6ADF491E1D +:10FA8000816DC5DE33C923C99FD92F5A63BD4B4D44 +:10FA90002ACF03AD63D4ED4991F06D66F82E85C48D +:10FAA0003A001DA31617448ED7FCBFD60717853E14 +:10FAB000E888D207069E4216E0EF880387AD5CA770 +:10FAC00040F73FAE083A6A0305FD6EC2608AE476ED +:10FAD00032DD7B0F27974F83BBA9AF41584BA5FB66 +:10FAE000E9B02AEAFB86B0BE9F28F7BF490BB750A2 +:10FAF0003DF064795F3A05DA79DE0CE8E1D60B4E29 +:10FB0000FE0EBA183CDC4EB285E7535A2B3F14E286 +:10FB1000EF7BC2999AEB824D7E6F1D87DE7D78D395 +:10FB2000E082810F95EED5443D53EC796E1828FCA8 +:10FB3000BC9BBC420F914B41F5C09320C4F7F9D355 +:10FB4000A143DEEBC73FC7548C0BE91E6F3ABA31B5 +:10FB5000898C8F20CF9F46E751E39DA7633E931981 +:10FB60004A9D049F12CE347D67BFFE7374533528BF +:10FB7000E5BDEFEBE9FA7151DF3DA8A7E98DF7A9E3 +:10FB80007E59F17AB9BED943DF8D53FC13D63A7B47 +:10FB9000F55936C098812B72064EE8FB6E04FCC006 +:10FBA0007524B1DF8D447C27021723FE2E9251E786 +:10FBB000BB3BB848A73A9165E936FE7B3B85B6A1C9 +:10FBC000E329AF7928CD9F333083EA7DEB46F2629B +:10FBD0005A7002FBB992BFECE09D447850BCC6F766 +:10FBE0002BC07CD3FBF70B3281BF27B25BC5773EBE +:10FBF000DB911F6DA92C053AD55FC323253AF9D3B4 +:10FC00005B5C360F7D476C25B8ED7D70D7D8441D01 +:10FC1000488D4DD47918F572B178ADB119794E8F00 +:10FC20008DFDF198EF907E62F3DF42787A28A998F3 +:10FC3000FF0E53DE2BD3DC5C0F25BF7FAA4930F0CB +:10FC4000506CE3E77DF594EC67D6523D37C259938B +:10FC5000015CFF783469540AD565D5B4897AEE9A87 +:10FC60008C00EB77B35F617D5FD35AD24AF6E2B284 +:10FC7000C3C275DD352E51071FC880D0F37A343DDD +:10FC8000A619F4A0FB4B598F64D0655C3A94D07BE5 +:10FC9000E3C2DE91849342DBCB37D0FDC2B87074EF +:10FCA0007D19D26935D1A9F73B1ECDC9F51E067D58 +:10FCB000907198D99D92EE06BD9CC6DF23F06A51E3 +:10FCC0007F8FC0A0E3F644412F3355E00CE77775F2 +:10FCD0005A37964EFF1BE114C1BAB04B000000002A +:10FCE00000000000000000001F8B08000000000062 +:10FCF00000FFCB936560F8518FC0F9D20C0CDEBCCD +:10FD0000A862B4C40C5C0C0C41405C0EC41A407B6D +:10FD10006F01E9DB401CCECDC01001C4FB81F81F90 +:10FD200010FF07620D20D604E25F407945A81B5BF7 +:10FD3000981818DA80B80388BB805887918141975A +:10FD40009178FB93841918DE8923F87A120C0CCD74 +:10FD500052F4F3FF60C33156F4B5EF29D03E4E178D +:10FD6000043FC71998245C50D570BBE03783074D1A +:10FD70009E178DCF87477F9E212ABF5C0B953F4DF5 +:10FD80008781E123929A0A2DFC6E41C78A460C0CAA +:10FD90004A46C4ABDF608CCA0F3081D000F9ADB1E8 +:10FDA00009A803000000000000000000000000009F +:10FDB0001F8B08000000000000FFE57D097C54D582 +:10FDC000F5F07DF3969949662693900D0871028AA5 +:10FDD000A88013086940B4C322A2228E5BC50D26F9 +:10FDE00002D93710FDF0AFFD3210362DD6D0824645 +:10FDF0008B74C0A0C182040D1824E0002EF82FD50A +:10FE0000D8BF7B5B0C4AC31692801B7EB5E57FCEC4 +:10FE1000B9F725EF4D26806DBF5FFBFDBF69F1E6A9 +:10FE2000BC7BDF5DCE76CF3DF7DCFB14DB2896F89C +:10FE300063C6CEE00FD2AB2C8CB151DDE96CDBA0F8 +:10FE4000A187FA74E7FF5965D3EA87421EABD06EEB +:10FE50001ED6FD9CB185547E408C6B38BB1CD3F400 +:10FE6000101B0E8F6DC91696CCD87D6E46BF01094A +:10FE7000BE742991B1CE1556F7BA0C78AE7A5C08EB +:10FE8000DFF7C8207750C2F73CC95216E43FA2BA48 +:10FE9000D701CCBE3F23B36CC666DAE06F0FFCC35C +:10FEA0007AA0BE7CAC6C1063EA699905A07FEA7702 +:10FEB00012A5033436C3EF0078F92D6CDCD0EEFECA +:10FEC000B913FDEC7380B7E8F9897E5BC0907F09B8 +:10FED00093A8FFECFB4AAA5F6F6FF1F25B6C3E07E1 +:10FEE0003616948DCF3B967FE9C2E78B9B6EA17A45 +:10FEF00018532CD8CF72B7C84FFC5C6396EEFABB90 +:10FF0000F114A27674D8D304EDFE8831E9B5BFB6FA +:10FF100032C043D556D56305BC4CD8AA867F0C7039 +:10FF2000E95A2984B065979D31C04BFB6A0E879DC5 +:10FF30009A0FCB9FA80518AA28B736FFFC0AC4DB86 +:10FF40005699ADA366FC84F7561BC73B6BE4709EC5 +:10FF50009D83A56B774FC7F70B1AADCC0EF5956E49 +:10FF6000CF9F7A05C0F9FB5486454AD72FD0FA01B6 +:10FF70005C1892EA11EE18CFA8FDE03639B41ECA1B +:10FF800077B89A936F83F11FABB431CFC5D06F6749 +:10FF900073F2AD8087A2D09649F85ED146C98B2C0A +:10FFA0003461EBFA37FBC27BA51B24AF15F0525C22 +:10FFB00017CB3C43781FCEC0BFD60639FC63C89F21 +:10FFC0000BE3641948D7EA494CC6F657681E6737F1 +:10FFD0009E8E550E611E6B375CBA01DA81F7CA5EE0 +:10FFE00094BC38C4320B0B205FB66FB74F7BD68101 +:10FFF000E35BA00D76E2B8966A582E3F94BBCDEE37 +:020000022000DC +:10000000C1FEADD526417ED1EAB55A9E81FEC575A9 +:1000100097318FCDD0AF9A412946FE884C8F019BF6 +:1000200018FB53C498AF1EF94409693719E4A29F1D +:10003000144FF42EAE934DF50326194B82FF7E002C +:100040007F02BE823B9D84579D6E73051FE9743B02 +:1000500025E487299DD9C6FAF5F4E74807E84F75E6 +:10006000A59BD25F54A652BAB2D243F47902F107EB +:10007000E972D16FD758364E81765D3EE646314BF8 +:1000800098E21BA7029CE0E770F2DD01C97396F1CC +:10009000EBE9136A20176572159BE453FA02AC056D +:1000A000E6302FB4AFDCE89B389AB1D759E0711C29 +:1000B000FF222950807465AC3ED50F745922811EF1 +:1000C000017C2DC541021E96F4057E063A3D714F16 +:1000D000F6B3B224C69A8870DE738F66503D3554ED +:1000E0008F0AF50C3A773DC9D3734CF5244F2FD0C6 +:1000F000EB594BF5D8CFAF9E27A68F31F7677A9192 +:100100005ECF0B586E91F3FCC6953C63ACB93F33A0 +:100110004AA89E94BBBD2C00E5659D7F58B34F86D1 +:100120007CC7C6F8118F32231F8DDF86F53941AAAF +:100130008C7C1497136392A7785F8209EE33B99F82 +:10014000A97C927FA0293F65DAA5117CE970B75E92 +:100150002660E854385EA3FE6AFD34D23BE3FAD948 +:10016000087EA09F83F4CE03630217BBA1DFD8579C +:1001700006F47F400B5CEE8EC237302E89A562EA12 +:10018000B1601A99BF54E5781BDFFFFBC107E1FDA1 +:10019000724BE7E07880FF4B1AF7218EFB8FA84C5B +:1001A000816E3132ABC072315646FA6F6946F6B392 +:1001B00041035E970D007E91BAEB5DA60652911F3A +:1001C0005B821541E4CF253041B07E8C1D6415E182 +:1001D000E085F0FE80BC54C4BF5503FD616C5F83B5 +:1001E000F68752FBADD87E5B2FED5B07E698DAB75A +:1001F000A51798DAB769D03EC8476770BE681FF088 +:100200003786B1936C3EB56F4D2FA0F6976AACC0A0 +:10021000D47E4C57FBDF60BBDF63FB4951C63F70A8 +:100220008C79FCE945E6F16B7CFC6C4150B41F43D2 +:10023000E397A4201F7F7A111FBF95D7DBD5BEABF4 +:100240000BFF9A04ED3AA45EC63F68AC79FC1794A4 +:1002500098C76FE5EDBB172C13ED3BA8FD78691926 +:100260001FFF0525D4BE660D78918FB4FE31152190 +:100270009C4FD34080524807FA281D92C018E8933B +:10028000DFB2818487076238DF7D1303FCE6E8D69E +:10029000A72C041208F37099E0E9E28DE3343E3FA5 +:1002A00007695E9F2DBA3AAB51A6F98CADB4862E84 +:1002B00082FEB637CA418467ADBC3224D37C0A764D +:1002C00002BEA7B0303EFFF3AA61EB8CE38A4C6715 +:1002D00057ABAD2D06B9EAD2EFE3D9900AE85F0536 +:1002E00032C1A86EB815F434033DFC39E8634C0FF5 +:1002F000ABDC2E39047A9C5D6C949B05DC2E09B234 +:10030000F78740FF7F22FADFAA707CB7CE9342883E +:10031000FF6F56CCD1509FCDAE8E05A477F7A35C6E +:10032000D0A973BB3544F6144C07889FDB491419D8 +:10033000FBD3AE1BDE945C303FD6F431BD77370B78 +:100340002D4E85F23397E70E70C3F8EF9A661D21A4 +:10035000E3FCC47CFD2D24C7ACBF2587B1690D2B00 +:10036000D4FE00DC3E4DFDBCC5F0FE1D01337C57C4 +:1003700081196E5743AA05ED994289AD857AEFA997 +:1003800030E7EBED4C9612385D457B3F011CF48560 +:1003900047F7603A021FBB89AED3DDFC5DBD3FE588 +:1003A0000FA92C4CF3714B1223FA2751B9809B8F64 +:1003B0003BB2BFD3559BCF0FFD99FEA04CF88CEC00 +:1003C0007FCBAE589F05ECD9969A2F5564C1C8F1E2 +:1003D00044F67FC6FCC8F1B8359C1F728391CF39B3 +:1003E0009F44F25379E3B85F1E32F05369FDB5BF05 +:1003F0003C6478AFB8EE26135C18BAC3543EBF26EF +:10040000D7943FBBBAD0943F73D91C139C1B7CD0AC +:10041000547EC6FC05A6FC7B2A1E31E5DF55B0C222 +:1004200004DF1178CA54FEF6696B4DF9965D97DCCE +:10043000887254F581CC70DEF8DAD1FA73B437BF24 +:1004400076285EA4C711B057500E8E81BD82697B9D +:10045000E348B2AB410FE63130A1564BFB83CBC62C +:10046000A25E66A43F43D2EF83C134C69E973C840C +:100470003FB94663616061892574F171A76CC86FEB +:1004800039477E0D08FAC89EF9724BF4E7E5EB7226 +:100490002F40BDD39B3E805F7F9CE73A843D1099FF +:1004A0005F2231BFF1B9BE7EBA5CE27ABE44AC5382 +:1004B0004A5EEA3B9EB9100E0FAE385B7BF5805466 +:1004C000D49368FD27213F801418E8515C37C82475 +:1004D000DF6DBB65EA5719EA04D0AB99CCBF574230 +:1004E0003D13DE9B7ECB30EC87EF75D4FBAC3189BE +:1004F000E6F5B6CAC9BF3CA4227DFC941EA99C4661 +:10050000696B6580D2439505947E5E5941694BE5E0 +:100510007C4A0F540629FD63E5324A3FADACA6F490 +:10052000E3CA1A4A3FAC0C51DA5EE9A35497872E0E +:10053000FDEB17F6B058B7C0036E0F8BB12C82B22B +:10054000CD24E7DE5494F3538E6F06A3BD7FEA6398 +:1005500060A28CDEF115C96FBDD3D147F64A5E08A3 +:1005600098A74FCF7C7B0CA793DDC22633D0478F53 +:100570005CF49CF7DEA1042BC832C0A9DE9B9C5121 +:10058000EA85B90FE9752E3A315FE7705C67B73ECF +:10059000FD976CACF77269209F87F7CA340FB3F0F0 +:1005A000B35EA4D70FC59BF4DA9FD25BA0DC892E83 +:1005B000FC35A73348E7486EAAFF5483952988C7BE +:1005C000A6D8102E8D4FED7BD685F2383755AE3E2E +:1005D00034B2777C95D667543B0CE3296F34C3A7BC +:1005E000AAA5C9DC7FE089BB7518F295BBFAD04596 +:1005F00048FF544AF57AE6A66AD4CEB1BA41717C76 +:10060000FE0EF17970633CF12BAC3BA9FC3FBB3F84 +:10061000BDD5A3F787B106F6850DF501E40D3AF7D0 +:10062000FAA807DD95AF343FD2AB49FD06ED85183A +:10063000F8776620D6AB10ACD75B5E2F07AD97E39B +:10064000F38DA6F6E03D8FBEA6C7F77AE75B85B5CA +:10065000EAE3047D75A5F0E714D7D9ABCDF34ABC26 +:10066000092E6FEC5B6D9A67F00F907F562129C8B9 +:100670003F25829B3A14C73209FA976AF150BDE5CB +:10068000122F576A6BD1021E62C766B433EECDD10A +:10069000F9CF73FB1F40DF1FFDADCA1EC57CE1D73C +:1006A00051F56CB06F2DE8E711D0BD0DC55350EF7B +:1006B0001DDD763DD927B398DF858BA402569D8D2D +:1006C00076CE0966998CFC7F82FDDE35D2B0DEC81D +:1006D000B768D49F99CBCCF32CD8672638BFC60C0B +:1006E000E7B19B9391DFF356AA30B7A05C9AF36F02 +:1006F000B7B849BEF259C5125AEF083FD8BD6EA629 +:10070000F407B92F7DE599ECDCA1E887E0FA5BF707 +:100710000F1426703BA52831A4F920FF8B86913F4A +:10072000B982E1FBA125A8A7824EE65DCF7AD2EF80 +:1007300087F63FB2BFFA7CD2C34F21FA21D749BE18 +:10074000509475DAC31649D85B414A978B71EB76A2 +:100750006B4D045C1B01D747C07F37BF253213BFE9 +:10076000A55A02359624CE5F682F484AA716F84747 +:10077000EA4FED517FED3FB5FE34A83FDB547FFDDE +:100780003FB5FE0B7BF4BF295AFDA5AF6CDA16040A +:100790007D53B479958BC13C7454A94EF602DD4B60 +:1007A000D62F76211F1C51822EE4E7A321797234C3 +:1007B0007EF8D222FCA2CCE790705D857F42FDC717 +:1007C0005EF8D954B4E7BE59AFBA69BD54670D5B42 +:1007D000414ECB1A0AA7A0DF17E0831C5E7A52466F +:1007E000B8D1CC9F45CFAF4A46FF1E708A584F8480 +:1007F000C95E2AABFDF3249C87CA5927C959E47BFB +:10080000D8FEE904D28FB95A5CCF7CE827D9F9E544 +:10081000022FE50D3F3B29BB30BDF630EA13B04C4B +:10082000C80E8F7CAF40D841872CCEC4565842B1F9 +:100830001FB11FA1DED4F1C242DC0EAADAF0E4F04F +:1008400083D0AFB6DADFBA2403BE74793B553FF3E9 +:10085000D7AF7A7AD7CBED62BDD7FD5E88DEF334B1 +:100860000AFBAD89A7256AD885F671C95AD51B84BC +:10087000C7259B9E7DEE695CAF7E62F55E04F51731 +:100880006F7AE3C33100176F5113A7F06138A4E406 +:100890006EFA94C3BFF923BAE951F4F21B9A6718B0 +:1008A0007FFE7042375D8AB7ECD6D8B09EF898507C +:1008B000BF5B6B7144A14FFDC1496867556DF85628 +:1008C000C375E5D15D124BC98882CFB56F90BD80ED +:1008D00078227A0A7A75D12FA27C39D005F57A244C +:1008E000BD22CBBD81FA6514AF17FD93C0DF2FBECB +:1008F0008A7EEC4FAD5EC443C18BF7B9703C8795DF +:100900000ACEE7CF2C4E463F7D811A4C7653CA9FC4 +:1009100017ACB99FF82FFFBDFB93F9FAD0D7D74298 +:100920007355B02F8E73F6EADB689C792C407C58A7 +:10093000F08CEC0F41FAB5C2266F892227C5329799 +:1009400093C3EB80B830CEC3B84E41BFEEEFE5D0D5 +:100950007AF28FCC61A80FEED7FDF16C2EC15F8BC0 +:10096000FD8471B2455FE7DA4CFC5BBBB419E974F6 +:100970006C802F05FD6AE54C090A7C4867A05EF98A +:10098000BDAB53389D9847C916EF815D30019F6319 +:10099000F966D5671F6E7A8F9DC9E86E7F9E681FC6 +:1009A000FA1D83F3F9E16456501F657C35B2AE073A +:1009B000605E37F09941DEB9FCD73EC2E55D97FF36 +:1009C000D04D9331FFABF7B91CE17B385F42BFC21A +:1009D0002994BFFB5689F4839585A3C979AD2AE490 +:1009E000DC9C1FC92FD07F458A33F00DB69340742D +:1009F00020BF5ADE4A78DFA857B15D57CF7A7539E4 +:100A0000CE17FA204F067D7059B73E60ABB91EE88D +:100A1000DDEE0AF2F59B1A7AEE69945F90D7A00793 +:100A2000E557F5E3F88F6FDCFBE19D20B7C7EB7569 +:100A3000B935EBD548B92D7869BD847C1A29B7C77B +:100A40000BC04A8926B7F03CAADC16B4FC4BF4AACA +:100A50008EC7C765B35ED5F5646FF88CD49397CA1B +:100A60009EA87A127EEFB3EC9EFCA8F3A1CE7F4540 +:100A7000BF29BD80FC093A9FEA7CD8C5A73A1FF67A +:100A8000F0CF98F018997F3BF2040CC1BF5D257F31 +:100A9000624913DF8F83F7DEEC9F45F8F2D134C74C +:100AA000AADFEC9F68844311707D44795F04EC8F6A +:100AB000281F88802B4CE54B1AF76A8CF8206C2A8B +:100AC000679DFF2BF6459475AC3E0F95379CD482FD +:100AD000C81F699D1AEA3F752198A8E83FDC299351 +:100AE000FFB00370BC04DAE9D898110A821E596C71 +:100AF000E7EBCD0E77A72B01D2C5F11CEE4CD296B9 +:100B0000A01ED49F77DAB91FA4C3DFE98A37F83172 +:100B10000E36C9A4C75B426C72343F09CC3484DF03 +:100B200016D65B3EF78F76E0BE33B687FBCE40CF5E +:100B3000AB6547FA7C5CBF56CB5E6023366BC1ED7C +:100B40002E74A177340DBA711A3C9FFDB6CCB76DE7 +:100B5000823EA5AF61DD7184059F182BE17EDE72B8 +:100B6000E29F994D7C1D326B7974792812EFE5393B +:100B7000E669A87761FDF0B9D10FACD753B03AE27E +:100B800079D3F5426EAA693D58546BCE0F88F5D4DF +:100B900037BAFEC96499A47F70A184EB7AA1B7AF7C +:100BA0009687DE380DE8D3B14F66B8BF7AAA4926DA +:100BB000FA9CDAC8F753593089E4AF8C7592BED4E9 +:100BC000F1D686F27571EF7AAC6DEB9FB21F423EA3 +:100BD000DAF687E1BF82B46DDB27837720FCCA4752 +:100BE000E97F603DCB4FD865273F73C72E27F17F44 +:100BF000C7CEDFA53F84F0762BF9F73A767D3B1C14 +:100C0000F9B163A1B500F560C700BE7EAADAF9EDBF +:100C1000F0169A7F17111D33148DE87DAAE92F076E +:100C2000302EE054138C0AED8B5DB1245FE5AFDA12 +:100C3000C91FD1B1F3DBEC80E39F379E32B1FFD304 +:100C4000E164D35EC2FEC573BF79F98ED1CF2EC0E9 +:100C5000FDF186DDDA4CC89FF0DA5F87A37EED7880 +:100C600089DB4DED6ACB1ADCDF18BA485EA802BDFD +:100C7000DA51C8FA31B66FD1C4F128473DF1F257C5 +:100C8000F2B39C2F3E26287C3DFBEF8F0FC9C7F5A2 +:100C90009F33649370DCDF1DF803EA895D56E24BF5 +:100CA0007DBCC7EB17903D73AE71DFFB3F6EDC522E +:100CB000F87CC6BDE0DF9CFFAD8A87FA1729073DA7 +:100CC000F97CE703046F727AA9BFE7C9EF6BFFA74E +:100CD000D1FD25A0BBEBDCE30EFF3F4BF7B7A70B25 +:100CE000BABB313EA0FCB5BF52FF7EA89E6BF93760 +:100CF000A77B6FE3D7EDFDB72C9EF733A1FC6456BD +:100D0000ED40C3E2DAD23D6F6742EE5B697BE3B14F +:100D1000BFE323F67BF4345EE5FEB6F1B8EF03EDF6 +:100D2000B27849AC17F93AABBFB02FFACFCB233B1F +:100D3000A47FDA63644F30C5B312F72BDF4A9FE913 +:100D4000A5D80B36E2E300C2EE2B056C5E6FFE4ABF +:100D5000623EDC4AED9F7EFD3EB473D3D264B28323 +:100D60002125FBF775D764FEBC4433AD87AEF598FB +:100D7000D7479312CDEBA889A2BEAB19EFFFD50ED2 +:100D80002914023C8C1FF0CB44F4A78EBF48651297 +:100D9000C093586011AE3B263ACCF59DC07D6C8364 +:100DA000BFF1EFC5E3C42E3C0E5CE9473C0E90C991 +:100DB000AF7A4E3C62BF096F99218CC7618A97E375 +:100DC00031A1D44B7E6AB11EC76EA21DA3389634E2 +:100DD000A33C2BB89EE678A075B8BE9EEE0DDF4C06 +:100DE000ACCF15D1A48E7F254DF6D9CDF5D1FA5CC7 +:100DF000A7CB0FA5874EC77F942EC9AA992E698EBF +:100E0000390ACAEB645C3F8CC4F2991C4E0B2AB4BD +:100E1000DF24D60FD778E628418027A4652A48AF7B +:100E20007CDBF6228C1FB57925EAC7C56D169A1FA3 +:100E30006C5912E17D488D42F07B16F728A4F7D457 +:100E40002B5E39FE20433FBB4FE306BA9FEF977CF2 +:100E50007FE6CCD86CF4C7F01FC67FDE00EBB75935 +:100E6000AB593806F0345B61C1B804F4934BEC73B2 +:100E7000939FDC0CE3EFAAE4EE7ACE55BE37BDF2C9 +:100E8000CF4E5F013DF6F9458C6DC7946F8A28C639 +:100E9000F5F68F9A38BECAF7B3D0401E8721FB0DF6 +:100EA000FB8A2FABDC3FF3CA1F5F1A89EBDC711D95 +:100EB00043E3B87ECDE271A962BD708A79E2BC0ECF +:100EC000D4AF83E268BF749FEC8C16E7B841ACBF27 +:100ED0007F83F1289076D4B26A19D757AC93FCBEC1 +:100EE000C15A1B5B1F251E668D6A117E224137F891 +:100EF000C9D9B87FC3DB9F0DAFC619E9D636E5A8BF +:100F000032BC271DF0F7B961FFEA1FC52FAEF711FC +:100F1000BF1BEC2D93FC51F447BDC0DFD43DDF91E6 +:100F20009FF4D2A6B516E4DF4B6B2DA6FDD83A553B +:100F3000F83146B011D8AFA97BECCE2CA4CB3ED96A +:100F40008BF1A5E54D27B540947DC4487C62FDE852 +:100F50007F6F55DDD4EE0EB57E26E275C7091BC343 +:100F600075F576ADBA385A3FEFB4F27ECE66F5F736 +:100F70000DCFF8F7C3EFB80E47783CAE3F6B99F052 +:100F80008344F21F233E3E55C74238BFE27A15F52F +:100F9000C2A98D8CE67740C963B8FE0679FFB1D14E +:100FA000AF7371E396DFA05D50D624B9714BA24CAC +:100FB00069D1D08F5BDE182FE33C9CE9D1E36FDD74 +:100FC000C36E35C845ABAA10BEF68ED97117B6FBF5 +:100FD000659BC6D04EF1BDDEE9C279FCCBA691245B +:100FE00007BD8DEBE54A563411E31C843E8CE48743 +:100FF000A11B634CF01572A01FCAD7546BCB3C6F7A +:1010000014FA2DD324B18F789EFA2DF4FF997E7BAC +:101010005FD76F01D96F9023BFC09B41BFA544D359 +:101020006F73254F0AE27DEECE412948D7B96FABE9 +:1010300049D1F4DBA64ABE2FBA59C44D7734807E1D +:10104000BBDCA0DF1A40BF45891F19A3E97EFA73F4 +:10105000E8B7D0BF46FE36A17E8B32DE1B04FE749D +:10106000FD36BCE920E9B7E10D16533CF0444DF8DC +:101070009B7AD56F52D2AD681FEF53BDB151F8675F +:1010800093B0C7378B38466C07F55C95F6C3F45CB4 +:10109000DEF9EAB97F119E753D37772BA3B8E89E3C +:1010A0007CC8F5DCDCEDA0E724E447AEE7E6EE64BF +:1010B000DC2F17A1DF86F4D06F8CCA9785F9FBE58A +:1010C0008D194FDE0DF58DF0A95E1B941FD1ADEF8C +:1010D0004619F55D95D68BBEDB777EFA6EABD07781 +:1010E000A0C706A27E8DE40F6F9339DE7CC7E8C3EC +:1010F0001B5F4679F99D4CFB92EF59F8FED13BA35B +:101100000F67217F7D2AFAF3A2C6E9D95E19A4FAF6 +:1011100027BCCEC757BA91FBCBCB1AB87D58562BFC +:10112000873CF0E7A431DF69D8FFC29D124B01F87C +:10113000266BF5130EB4EB9F5799581F4DC934F029 +:10114000C3AC9C62F2FB57D95DEBF0FCD12C85D986 +:10115000D0BF5FEC987414EDE0E21CBE1F502C9ED3 +:10116000EB71B0B3BBF464443C48E39C37FBB39EE3 +:10117000711653AD9CAE539F954218B7DA33EE22E9 +:10118000447AA1B8CEFCFC5D217F37C92D842FF6AF +:10119000AE1C35EE432FD785A77D024F8017139ED7 +:1011A0004252543C01A5A7642677E3A5F0772D4B66 +:1011B000705FA0F02989F69123C7ADE32D72FC3A48 +:1011C0001E753F77B1A82FBF692D9D6B8AC48B8E8A +:1011D000E7487C74E13D021FEF695D7EED9118D711 +:1011E000047C437A26F89F801768C73FEE22D3F924 +:1011F0009B8F045E46568F9B80E10F37611C3AE45B +:10120000E7D5CC79B32FE063D4C79E11389D5E310A +:10121000C61AC07DDA0DF64ED2833A1F0EB3723E67 +:10122000D4845ED9D1AF623CADF31B2537DA21E51A +:10123000613BE1B51CF8D10E45F63EF5CD24815752 +:10124000379DAF6A14F313D0C182EB267DBE0AF13D +:10125000F358239B385DCAEB385DB25827EDC7942D +:10126000D548DE308CA7AC710EC5A1EBFA197E0E05 +:10127000239DA2F0AF128D7F193A9BB3BBE7CD62DD +:10128000516EAAB5FA43DCE7990AF2B196D810FE7E +:101290007716FE3E57FC5024BD2E1378DB847875FC +:1012A00020FE3AB9FD15FE8ECE69E9F9E54AD084F3 +:1012B000D7094F9FE6FCB753F2A05FAC0B6FC8CFC6 +:1012C000903F4AC71BF233D2A1295746380FF0DDB1 +:1012D00027A3E77871BFD428F7853B0FF2FA9F91D7 +:1012E000BC2CCAB87F307FFF40BEEE4DDE8759C5AB +:1012F0003A41F0F73BF6CEFD2391BF774ADC2FD180 +:10130000146FDAF7BCC1CAD74D1BEC2007B8DFF663 +:10131000B6EA5DE7E9A91FAEB27239C0F584C7E04D +:10132000F7BA040782F1A675368A17A47E0CE4F694 +:10133000AA515F6FB2B3A45BB37AAF7F8AA8BF37FD +:101340007B498787617BA8471BA1BD21DDED45CE89 +:1013500017BAFFE05CE3BA43F0CFDF3B2EBD9D1F21 +:101360001A4F55CE9A695F4C8FAB4AB5045E51D186 +:10137000BE9B2C99E2B7A0E782CEFF70FDB76AA3AF +:101380007AAF9FA5DAC88ED0CFCB5E2D3B5810F038 +:10139000F6A54F2579012BE383B1387F8C8779102F +:1013A000922FF78FFAE86ECA97699FEDC6DFF5298D +:1013B000C57DC81B790C1DBB315322FBE13DAC6CD4 +:1013C00034DAE136E6B38A26213FE747F1213CD7FC +:1013D00092595B3DC103723DA22E5485A9774267A5 +:1013E000E23B48AF7132437A35FBFA4CC0F9F7BEA5 +:1013F0003FB34CDC8A073B81EA19B18F2561B931D3 +:10140000BE245ACE8C6EF8EAFD5BA07FA3F7CB5EBC +:101410000F94BB69AFC381723664B585050C78192A +:10142000C34255E8771A7DC8770BEA8302B07BF098 +:101430007C4941D3DA2A17C2AB257ABF3C1898E41D +:1014400082FE6DAA3939E932D40B500EAB295FCD3B +:10145000CB95D74A5E0C71CE6B5A41F14879B512E3 +:101460001D60DC1492988DD71BB241BD9B56C3FB07 +:1014700059387FC1FB586FEDC9F76F41BD03FDA41B +:10148000F737F2FDFA3C78CF8372523B87EA2B5C48 +:101490002D313C0753B091CF4F05FB552FE637EC6C +:1014A0007E8AE6DD29D05EDF0C9C8FC213E93CD139 +:1014B00048C94DE7381FBE80F456070E185FF0A5E7 +:1014C000F3F80949C062FDA3DB7FFD6DFC5C539E10 +:1014D0007781D607EA79272729C342FC7492F6E17F +:1014E0000F01BE03569C37793CCBDE9C2FB416C34C +:1014F000FC98631B44EFCF6A1C47711EB3999FE2AF +:101500003CA68EE676E7BB57DA43E8EF7B57ED4C17 +:10151000C3E77BAFB4D2F3F64D5C0FB70F6821BFC2 +:10152000FBE1D52AC3F32F55AB65D2138737AA74D5 +:101530006E577E86C737E46FE276C8DED5BCDEC361 +:1015400075DC7E9BF0CC6D93701ECE5FCFCFF9EA39 +:101550007A5A5F87E6B90B4DF35BA49ED5F570A967 +:10156000C04741F55ADA4F8FD4BBA5FA7C18A16F5A +:101570004B719F9DF6D3C32447A5F591F1658E6EFF +:10158000BF0DF243F83BE2EFB2FD2AC3758DF4457F +:10159000DB248A67C3F91EF24737493E8C7B28F863 +:1015A000D81A227B3C943BE33F709EF9C4CAF0C832 +:1015B000482BD203F4548EB5F38FBF84E747DFB3D3 +:1015C00061E410F04F2EE15F8F13CE5ACFE37EB26D +:1015D000DE5B998CE78DD9C43EA407F26B641630AC +:1015E000E88DA392EF963BF9FCE046FB47A76B968C +:1015F000569D87F36C918DEB47CF7A95CE8BC70BB9 +:1016000018D60B3EB4770AB7AF48D60CFC50B87367 +:101610004532A80EB644C4CB548973E6851A6FA729 +:101620007097E45E6B6847AF47AF57DBCEDF1BB404 +:1016300093A7BDD55F88FDA3717EADA1DE88ACA761 +:1016400047FBBDD493F35FA757E2B9FF9C77650AC8 +:1016500076CFF962CA20E33E8F9EEA7EE6ECF72D54 +:10166000CC67C05FCE1F6398CF40EF865120FF400C +:10167000BF1B1AB93DD730EAA0569A45B01BE5BD4D +:101680004CF8A3CB26F2FDBB86CCF716A1FC4FC9C4 +:1016900092881F5830A0F54924FBCD83FB00F959EF +:1016A000FCFD7C781FE5B2E1292EA7A02F3CA84FB6 +:1016B000CA56AF9844E56B250FD6DFB03697EC924B +:1016C000821C99517EED41B2930A1A0F26A23C83E7 +:1016D000FCAE447BA06CACD58DEA58974B5DCEDF59 +:1016E00015E76199CD3D0CCF77E0765834F996F740 +:1016F0003361B772B92CCFE172FBEE261547783E05 +:10170000724E72ADCBB18C729CD52DC77B574FD02A +:1017100050AE0F87248AA399807A00E57C831EE768 +:10172000C4EDD8F395F373D999A520BF385FEA7259 +:10173000AECB75A43C372B2DB7623FEEBBD24EE348 +:101740009870D5F60FEFE3FA8AF65F275CF5603202 +:10175000EAC73C85C779E9782D55785C608F7EAD06 +:101760005CA0F53D9FFE45F4E333ABD95F126F8B70 +:10177000E7F1EFB52AF1FDB9E4B3879C9DA77C9E04 +:10178000AF5C9D4B3EF5F6E59DE67AE2916947F543 +:10179000ACAF1DF018063CBEB5F1598A0F3EF1C240 +:1017A000C1A94887E21DC0E7C85F1B9D2C8C7A4EFB +:1017B00009D1BC55D420D33903A684B36F711AE57F +:1017C00098C775156F76123F15BD640D4D81F78B67 +:1017D000B67D319CE26A167652DC5AF005612F071D +:1017E0005B86A31C14293CBE2C522FFCDAC6EDE705 +:1017F000B6EDB1D3707C521DBFDFA2A8FE76D56ACC +:10180000D8A778C2A652BB508EF67983C0C778FE9F +:1018100017FB67BC57418F2B6BDBC0F54451A31AF4 +:10182000C27B328AEAB6B463BC71D1C756F27F95E7 +:10183000D79DA4F31413366F22FF4A79A36CDA8F75 +:10184000EB11DF592787AD1897D8504AFB90001F3E +:1018500024B85EC453FEC0F8C3E2CD3BB705018592 +:10186000C52F3FEF42FD72AC79BD0BF10EF59E35F1 +:10187000DEBA473C67FD23229EF386C3746F4B2F6D +:10188000F19CC7F00F1094B76DE6784E56D787ECF1 +:101890004BE867B63FCAFE47977DBEE9EB35781E39 +:1018A000A1EDA5E36BB0DF257FFB720DC689B15DAD +:1018B000769AF7CA5FF880E2B7F5F7BEB0097FC83D +:1018C00086E729FEBDFD13AB176B6BDF79381DE38F +:1018D00006DBB77C978CFECC793BAF267FEFBCADA7 +:1018E0001352589479434F917F43E7117F1F49B7B3 +:1018F000BD0D7B299EED04D01DF560579C6E7D29A2 +:101900008F7FF688F8DC8DD1CF3BF488C76DB8E5C2 +:10191000C62B51FF37707BF29C71B9EF033D2F3F0F +:101920000F3A6E14F1D7F5379C352EF704FE01F40B +:10193000B2D8CD74FCBA61F6AF9FC6BC863EBDC6B8 +:10194000E586CF037FFA798A776C3EA71DE5E8A587 +:10195000DF503C34D26F8A07E7A3AFD3F13CCA1102 +:10196000B5733ACE3F9D3BAD74DF4FD1CE8F489ECD +:10197000DAB7BE477E6A26CE35B4B3AE1F8F3F9727 +:10198000C4786B9D3C9E57D001E37D3D2E7A2EE2BC +:101990007A395FEBF1BEBDC5F95E6D1F28EE0FE031 +:1019A000F1C8A5B57F10F1B3DD749372905E07CFD7 +:1019B0001A47ADE3C12DF472771C7BF4B8EAAE3858 +:1019C000F608BA213D719EEA8A5307386D04F94939 +:1019D0003E8A762EA27D2D8F7F6F57A39F37D6E349 +:1019E000DA7D11F4D6C7DB9BBCE8727BAE71FC508C +:1019F0003CD16642524F7CB57D1F5DBFCFB44B7F5B +:101A0000D7FABEEBBC548914791EEB5EE4CBD286C8 +:101A100083E4CFEC5A7F8BF1B609FF7BDB0B32C539 +:101A2000392FA9DF4BFA3D527F94E1BD2D51FA7B4E +:101A3000BF5DD8E78D7CFE687BC91972403D6D7B28 +:101A4000B6135F976D3C4871D66FD6BDACB518E242 +:101A50002770FE0819C6D3F6E2EEE1A4CFC5FD302B +:101A600091ED548976CA9BA2B753BEF1A4A99DE219 +:101A700060BDE6769CBBBD638AEF76ACEF5833B7AA +:101A8000138FD5CB9343D1F669ECAAD8EFAFE629F3 +:101A9000CCA3740F8E93DF7B23BB62C8EE9CE7CC94 +:101AA000F9382E11538DE2BAAA168838B09F7A53AE +:101AB00091DE55CEEB18F67731E2D7E0FF51DD012C +:101AC00086F6AA9AEACF42BF43A4DED1122D2C6437 +:101AD000A0F73CE7E4140FED8B84D3909E07320F00 +:101AE000AB58EF6711FEABCF14B62405FAF7595087 +:101AF000F22E807AD9F75F0CF03B7BD6AFC381879B +:101B00006593BFA9CCDA7900D72BEC353BED47C8FC +:101B1000BBEC747F48F91A3B8D77EFD66F9F23BBE0 +:101B2000FBD756C6F787605583F796B9791D87B7F7 +:101B30007EBBE62F6857E3CBD07EFE1A288FEB8959 +:101B40008DB1B4FEE978298EEE51CB7FEDA1A9A825 +:101B5000D7F263393FE66F4E0955417DAD491C6EA2 +:101B6000DD3480EEAB287EC949F1A57BB7BE528635 +:101B7000F354FBE6580C3360EDAF09FBFF37E27E10 +:101B8000AD1AD5638C332F648AC7782EA818615399 +:101B90005C13233F06C911FAB11AE3E83C11D8C51A +:101BA000A67A4EA89D0F78898F83FDF839AA703FD9 +:101BB000D40791E5F4FCFD767E8EBDDC0AEF39BAE0 +:101BC000CB976B9D791CAEEEC7F5493395FF44E783 +:101BD0007391DFB35E5EFE23BDDEAE7AF8FB65E295 +:101BE0007E9B48FE3DD4A557FE7A71B4FB5BA2F400 +:101BF0009F9EDF2FB1A005ED962D76BAB70BEF674C +:101C0000C0730EDB34BEFF55E20AD3FD393B843E80 +:101C10002E8909D37D3EFD443FB03CC2CCD6F22292 +:101C2000D2BDF4153BC3F8B3D2D79C3EA477E9B636 +:101C30006F5B7F9585F18BB1E4D72B7DED7F111F15 +:101C4000945AC3D3E9FEBC2D5686F7E7B56D793BB0 +:101C50001DE5B54D0DA7279C655FAFB4DE6ABE5785 +:101C6000408CE35865E842BC77413FAF5BD48B9E24 +:101C7000B93286DBD7F6189F3586E4DD7C4FD4B1C8 +:101C8000CAC641C6F3FB459EE87AB17F8CFA8F9DA8 +:101C90004377F438F7DA3F2609ED99E66474409605 +:101CA000813D8EFABCA8EEE430F41F7C16A3DF6FF2 +:101CB000E089C3F9E833AD7318EABFCFD23B871987 +:101CC000E7992395368FA2925F87D28EB527F3FAD4 +:101CD000318C37B54F8BA6F786C5C412FE8A1E8E8F +:101CE0008D7A8E7A4C0CE7AB34681F536C17E54342 +:101CF0006FF7332D447AB831C6C3EB490B69F8BC92 +:101D0000B86EFB20231E0A956A2A07724AF82C64D3 +:101D10002BB52C83FED6DB2B9CEFF028743F81F291 +:101D20007FBAF855EEA6333991318E51E014665CD6 +:101D3000F233EBE74814D56F43FC69CCEF5664648B +:101D4000956A92F718564FA903CC2E7E5F5A054329 +:101D50003D7944ECEFA31F0CD36E7C3D487A3F38AD +:101D600080B18B32F0BE094F9CDB80BF6B70B33EFD +:101D700009E3692B18D71753DC688F48C1003B0370 +:101D8000FC5455593788DF03C27C182F49262CF4A0 +:101D9000CFE57EF33BB483804FF93D8457B15015B6 +:101DA000A018C386C9EF3A9EF1FBF3967DCC8CEB6D +:101DB0008F12410716DC4D7ACCC1BA7F9D00A35A21 +:101DC000457D5B15F7B71CDC9F73B85918EDC358F8 +:101DD000070BC742EA18AA1C33CABF2B0B60035F6C +:101DE000BAC79AF323E502F45A44BBF5843FA8F737 +:101DF000AB887ABF8AA8F7ABB3D5ABE3A9DC3628AA +:101E000003EFA5585C592FF0C6DBB309BC017E86F1 +:101E1000E03D7FCC12E315FBE684D718D11B2B964F +:101E200007BA6E8EC9207EFA59DCAE4E8C97668951 +:101E3000350CD7C38B24FDBE4FE67718DE636E1BCF +:101E4000C9E123A29DCD02CF8B74BF558FF276B22C +:101E5000BF7A94B7F7563E267A79676FFD898DDE93 +:101E60009FF85EEAAF8E8D5AFF0FD54B65AF7DF4BC +:101E70000EEEEF76E92737A0DE6C676E46FD541A4A +:101E8000DFFAB7167AC2ED4C5B9A99DE31C8DFC033 +:101E90006F31179A9F47F24914FE72F48571DF295A +:101EA000DABBF3617E5E4DE7835C31BE89B57C9F12 +:101EB000FCEE79DC8F07CB461FE6DF25F2EFAEE1C3 +:101EC000F6E3DD0FCBB40F1B79BFD5C1FFCDEFE13A +:101ED000B8071F80BCDD335F0A8533A2DDDBC5DEBA +:101EE0008F877A6788FE44DE8315609E49CBE4685D +:101EF000F76071BED4CFE145DE7F318BF9C5FD6659 +:101F0000E6E759316EE2DB2225A4550FED9EC7822C +:101F10002B80EFD1FE04BEC7FD2F599CC7662E8DC6 +:101F2000C7D7DF9A60D27FA78678E270BE66AF8B94 +:101F3000E76EFE7CEEB59E14E37945E574ACE91ED0 +:101F4000A02AD59B8AFA4D3D7D3DF3801C6AA707E8 +:101F5000318F211FEC56127E0CF3243D95AA84503C +:101F60002F2A6E3FCB47BB379EF3B35E5E4BBCAEB2 +:101F7000CBCE7C17FE1D46E681FFCF5DE1A1F3DFEE +:101F80005739FCA771FE955D39DE80A3273F04B762 +:101F9000F27157E1B8337A8EA74AF37AC9DEBE0EE2 +:101FA000E645F2CB796DD83FD9EAF9C883FDFBADA0 +:101FB000CAD00FD3133FDE2321C83F15EA4F712447 +:101FC00072DC94C1D8FE72BC6F14F4FF3271BFE8AA +:101FD000A24A26521E57B708EF1FA53447A43E91C8 +:101FE0004EA6728F8A7B4A97547A29D5F16BF356A5 +:101FF000D33D98B60B79FB36B7A05FA245E02F40E2 +:10200000F6972DB582F61DEDEE8A30DE27C7D26039 +:10201000DEC161B9AB09BF9A9B91BF13CA136C456E +:102020001852B5660AD1497157B07CC84F7504067D +:10203000C7A27DE331DF87694D1D71D6FB31BBF847 +:102040006D13C7FB6312E7B748BC3FA6367B306E03 +:10205000E2B16BBBEEAB22BCC37288E3FD3FF97EFD +:102060006E4FBC374F9B69C0BB337B32E1FD6702CB +:10207000CF4B055EAB041DAA043EABC4BDAF55E219 +:10208000DEDC2A81DF2AC43BA48F887B7B17233DBB +:10209000209511EFC0BFD6A14126437B7C0F0F5284 +:1020A00087E05BB785FCA4B2C3EF43BC5B1339DEAA +:1020B0006D0EA003F135E0DD83F941C2A7EAE078B7 +:1020C00086F29C0E025610EF23F139A707E0FDB609 +:1020D000D824D487634C78D612C79F1FDE9FE2F3C3 +:1020E0005BA290F348FC256AFC5E605DBE7BB38F0B +:1020F000AB445C7695B89711F18876CD2AC00FBBBA +:1021000098E3933F1F22602FA54962FD5F0574C0CD +:10211000FC27853D8478C674672C5FB7245A2A76DD +:10212000AB88A7047EDF0F4B0CB2B46CC64380F1C2 +:10213000971A641E84F5FDE15A33FFC86E25E27ECE +:1021400049CF93C86F2BDF562DB87F2FCFBFDE74DA +:10215000AE5B9EE68BF710FE0312DA353F1372B8C2 +:1021600002F985FAC7D7C38B051F2C15F7063F2246 +:10217000F8E73121CF8FEB7CE3E5E748964FE6F1B6 +:102180008E89991671BF629819E309E3BDF54C83F6 +:102190007ED1DAC64329DD9FC93EB692DCC60E6504 +:1021A0003EE4AFF88F1F0CF1FB70FD7DD11E8AD786 +:1021B000EFBF1DEB89BF830EB4871571CFA4CCD7B9 +:1021C00093CD51EF8DADF2EEB1A15FA6B7FEECBE9F +:1021D000691BF173DEE5441ED627E0BF6336C08E6F +:1021E0001A5857C12FD61BC85E8C7AA5C649FCEB7E +:1021F00080FEE71BF824B617FFCE54C7B51B505F0F +:10220000BC80062430C12F6A06D911CF80730FFA23 +:10221000B156A9FEBE382FAC8A8FEE8FFB652CDF3E +:102220008770655D6AF22BAC547DF49E7BAC59EFF0 +:10223000AC14F344C244B39CE8F3C24F457D573914 +:10224000023BB15FC9A727923C27DE1C7D9EA852A6 +:10225000B520DEF751358CCB773057E3F6730FFDA1 +:10226000C3689FE45460F03AF483E97CB690717DD2 +:102270001764DCAED4C7F504F2BD15E70337F13FB0 +:10228000CE0708CB176AFCDEE3BB2DE4875822E4B7 +:10229000ED512167CB857CFD1CE5CB8AF7587B2966 +:1022A000FD8590AB952887901E8FCDE0F6BCB83F9A +:1022B0004C5FCF2CB48DA0FB22AB1C169A17944F09 +:1022C000AC2107AE0F768F76A3FF477666B9034E33 +:1022D000CCCFA2FBDCA5F82C37F2CD37CE59179C1A +:1022E0002D1E16C84FF7162B2AF74BEAF7C8578949 +:1022F000FB0854F7CD0CFDD54F2656D829DE359670 +:10230000C787D7E46613DE811E9DB186755ACAB4AD +:10231000EBBAEEFBC3EA9FECE55E83EF85DE606916 +:102320004176A1414FD488FB249927C88618F4C56B +:10233000C28B2631F4EFF5D413BDE8CDF55C6F2EDA +:1023400092A2EB4DDD8ED7F566A47ED1D3C5174C96 +:10235000369DBF541D5E467A6748743F42B2C3CA79 +:10236000F72F99D79B9BD1331FF095EC30E00BED05 +:1023700021DD6FF1E328E389D49347AED3E7D7009B +:10238000DD3B344BF33C39FAACF3AB795EC83FFD2F +:1023900008CD4F79A747535A50732DD9230C77692D +:1023A0000CF72E1C5E7DBF0BE97BB846EC9FAF5649 +:1023B0004318BF74B8667119C1D5760FD266DC2F89 +:1023C0001E74E13D4DB3D6C8B49F7E2426984EF1CD +:1023D0009FDF9F39231BE26316AC5D9A8EFC386B3E +:1023E000DD523A377B24C137D86F80599687EC7914 +:1023F000FDFEC6BC67AD3EB4C77BE3DBBCD5D1FDFB +:102400003D55F827AE53987708AE4376BBC6748621 +:10241000810F8EFCC24EEB822A2DD88E70D5BA5811 +:102420007C83552544BF0F28D571B50FE994EAF098 +:102430005D8B297324D07E4FEF72C4DB6F455F3B09 +:10244000EEBB3E2DEE45023ADD64F2BBF27DD7567F +:10245000E14763B65EF26344BEA7977C178F936231 +:10246000EEE8F97FB7FF69688FF55D318EBFB4E69E +:10247000F8924FE889791FA150C48BCF5A171B5A85 +:102480001845CE6689F3C7B3C47E99CE8F85D7EB46 +:10249000F639E7E3483E975EB884F8FACB7D2ACD5B +:1024A0006B65C0AFA8EFA51746D37D500B9EBBE26E +:1024B000718C0BFC6ABF4CF925A7EDC4C7ED3FF545 +:1024C000D23982CEDFA9F49D88AFF65D4DE701DAFF +:1024D000C5FDD33A9ED29C7C3DBCC6C1F550DEE919 +:1024E0009F913C74F15768A686729E77FAE75C5E0E +:1024F000F0FED93138ECEBDE1C77A1E06B80D72CF5 +:102500009F346921D49BDFC2E58A8D0D96911F7B94 +:102510006DACF7D128F2BFC6E131F9B5F25B96F3A5 +:10252000F7C0AE4C34C499CC12DF7BC83FCDEF6509 +:1025300065EE204B457912FAB05B0ECCF772B7DB33 +:10254000CDE3D4D317BBC6798569FDD63DCEABE8C4 +:10255000799EB053F25B4613DC3D9E5F8D8E369EB6 +:10256000EE718CA5F2EDF1D1DBFF50B4DF5A59C00A +:102570007CA04F8BC4FDBF79A1FB34D41F79ABE3A2 +:102580001324C3B8F26B8A4DF14F7935B974DF5F0C +:10259000FEEA5CED5E83BC76D185CD36D1E543475E +:1025A00080E832D5E1DFE340B97CA1F0814F3D58AE +:1025B0002FA7D3112D38BC82F4DB7DAE68E7A73E90 +:1025C0008CA4538DA013AC1FB20C74D2E913F97E06 +:1025D000EBFAD2073EC5FD8BA7F8ED45BDEBB10880 +:1025E000FA6544C75FA783F36B2BD80F81F3C2DF73 +:1025F00065A6F8BB5EF127E8ADE3477F0EF6DF5135 +:1026000094FB4E94CD51581FE78773E1ADBB7DC15C +:102610000FE3A28F27C5A9F3C37C1604013EAA715C +:10262000FBA3F7F13CC482B6F3184F979C2E36F10A +:10263000438A7301975341FFA37B1E21BE6E0DC5D4 +:102640007AED19BD8F27C5D90B1F5C186443B3FF02 +:10265000EFF1C111CD37F8299C4760DEC279BDF09A +:10266000F9C7861BFB97EA1897E6C479A9FAFCF626 +:10267000B783E3BDFB701D1E5C277BAB6048258ED6 +:10268000C0607CBFC8F5F437E8DF5B14FFC4F068B6 +:1026900076F4E2CA7D97A0DFB5AAB2995255D8C5A3 +:1026A0000CEDE20CFE5D8F68F7055E2BF4EBE2CAE1 +:1026B00066EEB7B50599DB70CF003B3292FCD88A45 +:1026C000C36CCF696AC08D7E734DDC83A02A81659F +:1026D0001959E8674ACC0C1AF0778D93EFD72C4F35 +:1026E000DDE3C6FD102BD48FFE335B9A72CAE4770C +:1026F0007B5D99E5043AE9D744C7B07A9F24911FDE +:10270000F254841FF294A91F89CDA67D8A48BC2863 +:1027100036FE1D288509FFB3C087FE9DA4A56E3E29 +:10272000CE95C28FFD04FAAF2F023B36D645F6C1D7 +:10273000920B2C7C7D6853E8BE2B6B3C2FAFC5F110 +:1027400071D871FF43C6F559986027DE1026D3D59E +:102750008B12C2F1CC2321DC878597E07AA3635CDE +:10276000CB03F8FC797B20D70978FFA66FF301092A +:10277000F733FC818B11CF357230D303E57F2D7792 +:102780006662B974C8FA3881A717E0398780619FFB +:1027900094DFD7DC0DCB3DE10BE62B11FB86DF5F31 +:1027A0006CCCB7C7F82AB01F91DFCB4AFC42A2FD20 +:1027B00041FC4C079FFFFD343F2F77F27505F10771 +:1027C000F2D73E6E3F9D523C71B8EF87D879DDB4A9 +:1027D000EF63F3BC6E684F11EBD85AE057C5B04FAA +:1027E00077A1E2B3203F5D540DCF8DFD8D62272789 +:1027F00038E8DAF2A876BDDE3F3CAF83F8944F4F5D +:10280000227B24922F7674ED27F0EF69DDA1339EB1 +:10281000B288C3F14CFFD1FAEE93AEFDAA451C7607 +:1028200073A8FC5EBE3FFE696E1CC599EAFDB8A3A5 +:10283000696933DAC57734F59D89F8BCA3E0E23FD6 +:1028400063BA43EDDC138BFAE27E89CE97DDF9C1E2 +:10285000EB6A2CA45BDF5F47F71F3C2FE4713AEB78 +:102860005491FE01E6D6F87E5788DF47C5BC02AE1C +:1028700057D15F71773874DB0D00DDF37AE80634E9 +:10288000F7A6EFEB7C03D543A0DE3D89F694F4F781 +:102890001ABD6F7298BFD7357EC546E3E91EAF8D6E +:1028A000C6AF8F0F7A4AF8EFC28FB8F74DC7C7F897 +:1028B000997CDC77C4DE751D3BCB3AE00EDBB03F84 +:1028C000F3783EDE9F48FC7C8559A01F5F74FAF6C2 +:1028D000203F3EE3F4ED45BD5762EB4C570692BCFA +:1028E000BC85CFCBE4C005C930FE130302172721F6 +:1028F0001E9AFB9C97BD7FC0CEF9FB809DF3F781AC +:102900000C9DAF5B9CC8D7EC74228D53FF7EC792A1 +:10291000AD871FBB1DF8FBC4DBFC3EBB52D973E384 +:1029200043E4979699312E3E323D20FC0C2D5D7C80 +:10293000C8C73B43E1F232A32196CEC1CC982F9B6E +:10294000EEDB9F319FC7C332A579F8ADA675C222D1 +:1029500011D7D2B31EF48344D63373FE04BA17657D +:102960009BE61E477E91359CCF664EF4C9788E60FB +:10297000CC3289F6F1471FF234B6003C3314EF45F0 +:10298000319DF9E07F0DC2FB51CA9AB97F34459E53 +:1029900093F9534857EDE1F33DC273104F0E9FC7B3 +:1029A00061D8CF69532B32DDC8CFF7387CA80772C6 +:1029B0006FF57D8274D5FD22FABCFB0AD801181789 +:1029C0009A7BB72707F924B7DEEEA3D4C69418D0B4 +:1029D0006BB90AB3619AA231C58E690CB3619ABD15 +:1029E00050D84F353791FDE0CAF16B78BF796ED37F +:1029F000F35FE3FBF94A78B764E0ABDCA6B7BFA3AB +:102A000073763E3FC5FD5E56A799D69FC3EACDF0CB +:102A1000E58D6638336C8647EE33C36538366867B4 +:102A20008CF81EE19E9D5686DF2B2BDE6CA538F4BC +:102A30005771AEA0785E3BE9C509C54DD91827711D +:102A4000FC45A705FD953BFEFA32C559746E8A65B3 +:102A50001867B8FBD318168371BC9BEDEB30BF1819 +:102A60006887FED9E2CDF6B5184FB3ED529D4F43BE +:102A7000140FB5ED6FFCBC4BE7066B08E32E8E6FB1 +:102A80007FFE45E4CBE31BFA931DF6AA14B4607DE8 +:102A9000C14738DDC708BD3E46E8F5E23AF37AFCA7 +:102AA0000A976EAFBA87E2FC372681E3BBB5B22F37 +:102AB00087C5772574FB6D8CB067DD40CFCF8776F7 +:102AC000D37988D0CF79A17B351FD16B410CEAB384 +:102AD0008EA3DA0CF44B5D5C63C6A3CEDF9784CC87 +:102AE000CF27BA24A1E70CCF33305EC5B32415E756 +:102AF000EF67A3DF537FBD8BDB192FBCA0E9F2206A +:102B00008B7B2A99C770AEB25BEFB379FD319E081B +:102B1000E935B0FB797144BB7AFDB12E2ECF5FDA77 +:102B2000F879824481876395FBC86EE8B2232B7DD8 +:102B3000BE890638AF6677722EE16F77F2BD86F9EF +:102B4000AA64C3DEE4BB304EAE4E418F362BB9E3F0 +:102B5000B99F8F49C4E7723DF613F3118F6DF56F7E +:102B6000B8B01CD8D9238C7167F93557FB261AE405 +:102B7000FE87F2B94EB71237C7CB2B39CD93F09CF5 +:102B800048710DFF8E6171FD6DB7DC80F85ECDCFB1 +:102B9000D3672BCC2F833C966CB9EDFA61F0BCFC6B +:102BA00099515EEC0F54712B3E2FDE7892CE153D7D +:102BB0006AE1FE8E48FA04059F3DFA134701EA399F +:102BC000A8EF75CB087A7F9F05EC9B23E383EFDCAE +:102BD00005458EB3FA0F6FA0F830339F02DF4B68C4 +:102BE000BF75AE97BCEBE8E9C2EC9BD154F72DA0C2 +:102BF0007879C88FBA7E290C99EB89A4EF6AC16FE6 +:102C0000F01B62E493C8727DA604E9DC74C97CD031 +:102C10009306FF43C9A16A8ACF8D6C07235898C1D8 +:102C20000EDA81E17528979B789C16FC245BB688A8 +:102C3000631FC461BAC715F91118A2F85236D183BF +:102C400078BD994DC654D7376D39F5C3B1FCAB5239 +:102C5000CB73BFA2FA9C24E76DEE30DD6FDB4F9C97 +:102C6000476FF37058FFEE8F9E5FD464A7B8AEE352 +:102C70002734D2BF0B309E14CBBF68B758C0683D15 +:102C8000BEA5CF788C536EABE7F7A51FABEF335ED5 +:102C90003BCBBC1EA94FF4F9F620FE391AFD7ABED3 +:102CA0002617CE838B781C774A9F8ACC8A2874D2C9 +:102CB000DF4BD42A3271FDD3798FC3BB8EF014CC95 +:102CC00050C8EF9F4A7E9A5CE19F3AE8F6BFED025A +:102CD000BA39A1AC0FFE25EC93D7A1DFF30BD9FBDA +:102CE000807B50F73EFDACAC009DDFA30FF440FBB2 +:102CF0003315165680DF66E23C359C609A4F67AE0E +:102D000096289E71D672F378F0BE6EE3FC5AC0AA84 +:102D1000A9DE22564F69C16A737E21CE472E3C2719 +:102D2000C7E3768A6ACDF9FAB9C0928D67ACD1F063 +:102D3000F635D3C7E7FB02C727DD6CA3FEDDB72A54 +:102D40008EEF7769CC87F36DE72A27E9FF6216A03B +:102D50007EDC29E6FDF207737DB320ED983FD33783 +:102D6000AB0F9ECBE7F3232D19499EF9BD7EC5130A +:102D7000597800BFCF87E1BC5BDC248587216C03D9 +:102D8000511DC19FE3BD26387EE379367DFC386E48 +:102D9000E373F63EA76F119E9B92F9B88DF9250259 +:102DA0001F251BAD267FD1988D52D079399EAF6AF1 +:102DB000A1F7CA1ACE584DF58A791DEC016607BAFB +:102DC0008D29582BE3605675E9F1D025D1CECB1C67 +:102DD00010785C755B5E5F94DBC7D1BEED27109DFC +:102DE000437A4AF8A358D806EDC58CEC82293F7B7C +:102DF000218793E21EBDA6268DBE2F4AFB61336557 +:102E0000FF9B780EB3323ED0370EDA9969F1A52BCD +:102E100024BFBEC1E46F9DCFF1F0E4888A4B2AA2A3 +:102E2000ACB7753A3F21D5539C40703B9FA79D5945 +:102E30009D6AC0201723E3B8BE8CDBD342E78F3AEC +:102E4000B74A74FEF929E9209D0F7EEA5A0F43FF25 +:102E5000402AD009F5EF53125B84F7FC6535DC346A +:102E6000E70DA473568C17E30F4A1BC6C9A50E1AAB +:102E70003FB7E3622BD6E2BE54CA8C212390DF61B8 +:102E8000DC336E86E7A3E33CD45E5F07A77BEAC230 +:102E900060C6DCA1D8BE7FCE1B288FC362E8BC7C95 +:102EA0000AE0CA9940E932B4CF5259E66EB43353BE +:102EB000A77846A04F7F958BB793649167DC84F623 +:102EC000E3080E273C2CF9D61113AEA07652ACFCC9 +:102ED000937AF81CED4D1BFA271C067A4FA8C8C43C +:102EE000F65306F134510BA7613DFBBBE81EA075FC +:102EF000C83C37237D3DEFBB7129B82EDCDF060BC4 +:102F000075D063FBD3F4FD97B083ECFB0B87F0F235 +:102F1000C24E9997C9CFE724A6EBF6152FD7A1FA91 +:102F2000E246A25E7D8FDBF95F397CE407BF42EBAE +:102F3000E53C80A053F9E9581632CC0BE5D3BE210D +:102F4000FBB3FCB4CBF41CEF0935C6959714ECA188 +:102F5000EF3B94B2663A9F505A6F8E83BF22267A17 +:102F6000BB3A9F979F9659306ABB9AF9F9E93E2C74 +:102F7000D8275AB964F3F3D392196EFC569453E8E8 +:102F800039CB6971E1FA710ACE47A8674296A07AF7 +:102F900079375DDADD2DA679A8DDC3E10EB1BFA8D2 +:102FA000E7EBF5B74FD3C4393D7ECF7B5B252820B7 +:102FB000C0CFD34D27C9DF5DD2B49BF0A3F3453713 +:102FC0009E6259D080A7E4AAE6B00564FCE9B8FD8A +:102FD0004B875E0224D9A3CBF33B4B7D63211FBFFC +:102FE0006B6190EFD8AC2E792775B3CA220BFDF038 +:102FF000EED289638D302FDFFD7EF3351381B7B2BA +:1030000086F2F76BE3DE7B6B21C606759D3BE84CD1 +:10301000F73B0DB02D0276003CCC00BB23F213230E +:10302000F25323E0345EBECD194E97BD8C6D8EFBFE +:10303000E01A05F45C5BDFF074BC796479D547D79E +:10304000E0F78E4BB3F8F77BCB9A24AF64D0A3653F +:103050005E1E87E4F0B6683387221E9ADF447D50F7 +:10306000D228B971FDE0A8DF122618DFF318DEAB15 +:10307000E7EBD392FA83F45EAFF50FB1903C3F3AA1 +:10308000E4732A77AEFD2D36C5FC3DAFDEF6BB52AC +:103090002D81B750DFEAF7C7B76DF9A8FB7BAA20EF +:1030A0007FED7D7D7B499F469C5B2FC7FE38BAE54F +:1030B00045C7E3A3434ED17DBA7F18D6F4019A07E2 +:1030C000B1F34E2EC0AB75FF547A7814DA5F7827CF +:1030D0002FCE1F4F48A14B705E7A9A052EC176EF16 +:1030E00029BD68377E6AEC80DAF20C5E09F34DDCAC +:1030F00049C2FF0167CB00FC64DDE9C7FFC2E1A460 +:1031000016BA09E6B6EAEFAFC1EFCD1E18D032C04D +:1031100002F0F78F5F3A99E08B5A9E41F8C2EA04B9 +:103120000E0F6B1920C3FB03837D2623FDD6BBA3A3 +:10313000CBFD09A16FF4FEC50EF61D8943FBAA84E1 +:10314000CF3B782CDA067A757AD1B14DEB011FD3DB +:10315000FF2396F4DDFAB65BAEF3131E827E8C6F0E +:103160004C11F8A67991F4BB42F6445F9C0B13BA5C +:10317000E9E94C6FF6D0BC7169C516B41F52A60FB1 +:10318000A579E35597EF27EE51DDE9E9249EFEC4CA +:10319000EDE6FA5BB650BC46CA434EB2AB1E17DF33 +:1031A0006700B923FE7008BA58DC7C3CFF0D197328 +:1031B000D11B0080000000001F8B080000000000F1 +:1031C00000FFDD7D0D7894C5B5F0BCBBEFFEEF26AA +:1031D000BB9B4DB209F979F343081071139318A9F9 +:1031E000D64D881831B50B22626B7149F84930C948 +:1031F00046AD162DBD5948548208D146040AB8E19F +:1032000002622BFD82458C1AE88288F62BBDDF72A4 +:10321000EBAD3FBDD71B7E8A884256B45CEA6DEBAE +:103220009D736626D977935CA87A7B9FE78B8FBEC8 +:10323000CE3BF3CE9C3973FEE69C33B31ABB86902B +:1032400064428E25DC30C74E9FDF31E6159D4C224F +:10325000A4BB33F49C494BC87B1221C44548F009F8 +:1032600053687B0E21DFEDD1047589B4DEE14D7327 +:1032700016D1B2447CBD45C3E5BD7FD5DEE5B3D2F2 +:1032800072312DD3E7AB12998BF533BD690E5AFE1F +:1032900002FEAEA7E51E569FAE25AD589FC3BE7F6A +:1032A000AA84DCE5A3CFD4763A6E297DAE9DB8B56D +:1032B0009D8E6B918917CA0BE7166C5D4E616A7320 +:1032C000CC427889D79B2651F84E36E66A56D1769D +:1032D000BFA7AFC835845C51E0CDB097D1F940FFAE +:1032E000741CD2442795363CFE1C9837ADAFD77A74 +:1032F000B3643ACFDB1DFE39D0BE5EE39D42B4D04D +:1033000089B7C07705B423889F39763BB627F2404A +:1033100019BCFFFF084F95B8EE5F114F77EF34757A +:103320009D2C24F8F705FDB7B9D7A12A07FAD2BA20 +:103330004E1A87CB77C3FFD07148AD2493143A2C33 +:10334000AB226E8DFF36E8BF79E9077AA28137514B +:103350003DF42FF0BE4E0AEB52E9FC82FB24CF76FF +:10336000C2DECFB2119295E8BF13E621E09EF7C30B +:10337000E6347FD1F07C2C3F78A9E6765A9CB7E4FE +:10338000CCAEEDF4FB790F59085186DBD31E719D4D +:10339000DF7FCFB89A5C499FFADEB086E2EBFD1979 +:1033A000C4B39CB67B5F431A00FFEF73BC953F74B8 +:1033B000F7113285905FD9B5F89D49D083E4DBBD24 +:1033C00088E2B753224123D0C34C3DD2C36088D298 +:1033D000C395B0FE747DE8FBEE07278782747D06F7 +:1033E000C90091613E15C4BE5D89A9BFA300EB2948 +:1033F0009D044DB43EDA680E6D95805E28A0A55000 +:103400003F09EB5F95D8FA07EF30E238DD33191D3D +:1034100076373A43C11C00B68B00DEC6A2A3947671 +:1034200082744864EF9499B6617C6CE372C1523A3D +:10343000F0E2DBB43FB2DAE4194F1FB0843294BB40 +:1034400052713C4A0FAB91BE640647FD8FD342AB2D +:10345000705C4F39ACCBA336EF7C781FFD914501F2 +:10346000F83799C84A63097D4AA4C3E8A4EBC0E1D0 +:10347000215D4F13A083BB60008A877F6F386F5335 +:10348000E8FB9FD825840308CD584E481D61F5758B +:10349000CB2CC7A429F0D4860D09F4DDCA1BBC03CC +:1034A00082BE72D9D348FBF373BA22EBA336C08332 +:1034B0001FBE4B80FE3FB7295628D3EFA7C0F2D3DB +:1034C000EF0B87BFFF39F07D19C0C7E0276D166588 +:1034D000BB348C1FF1FCB980AFEB696FEC78629C58 +:1034E000F87E8FD9BDFF07F045F11E4E74015EB422 +:1034F000B8AEF1F0BAF4D1C74DB47E5E9BD6B182BE +:10350000E2D3BFD486F315F0DE951ABD8EE48DECC0 +:10351000FF94A5A55C86F92F65744F961928E26281 +:10352000F1A21F2E53D25D48A28735D228EFE5F0D5 +:1035300001807F5177CCF7F8DFBF1A62DB09BE212B +:103540008A14073FA72B459261DDFC125B37BD3E15 +:103550003A0FE4563CDC029FFFC6E58DA08B787CD9 +:10356000FF1BE0BB6C24BE5DFA814CE8D7BFD48062 +:10357000788AEF9F90107EF7B489044D94EED64B75 +:1035800012D2EBFA072D21909B83A6E80EC067604C +:10359000FF8DB8DEE71ACD0AA14D36EA19BF05F74F +:1035A000DB181F170C1480DC3B47E7ECA5EB73EE30 +:1035B00037DA9EA0248020A4E537DAAD40FFE75E2D +:1035C000BE89F5B3DCA2105A0E0086E9B881E07F0F +:1035D000B6118A57699611C73FB1570A19A0BE8F15 +:1035E000E239465E9EA3FF36940CCB8D41A800388D +:1035F000FA2C08079D69238EF75D335945C76FD1B3 +:10360000485E0DAD6F593229D4CEE031C6CAD51609 +:103610000DE9904A86F9BF4573BCE0DE225627A724 +:103620007079AC60BB431285B3C9B83AA205FA05FC +:103630003EA0F54BA03E67781D5A567FF417984779 +:10364000CB1E357D343DAF9EC79258BACA19A61716 +:103650004B29C317A926A1F1145E1B2F5B6A2221F7 +:103660002DE063E93472E22ADAF4E0C074A0235B4F +:10367000692FA9A3CFC069E20D51B8A7F6F7BC36F0 +:103680008EB677D4443261BA81A5BFCD3B79D5F0EF +:103690003A0B38AFE97F424BAC381E7E4741F1EE22 +:1036A000B662BB89B3AE887DAEC0EF92354C2F0FAA +:1036B000C02BE01F99E9CD755C6F52FD8AF27A61EB +:1036C000D704D4AFA0FF40CE3D95C0F431C83D90A3 +:1036D000336D8EAAAB1C749E6667D51447191BC741 +:1036E0006783E927A1FE88A7EB783D24DAA5E6B534 +:1036F00016B75AC76E47F90CF116DD90C8E4882C4E +:103700006179D1AF753DAB103E19E9E6DECD3928C0 +:10371000971B48971EE8BC8984F440C78B8C24987B +:1037200040E962116D96489F8BD71B8812B37E8D3E +:103730002175B989CB85BB4904BFBF7B675C7D35EB +:1037400009DB687DB391842DF0EC55D7B7507D8EA1 +:103750007CD6F78521F63DE966F3BD8BAFBBA33A76 +:10376000A4F5D3796F3051DDEA84065DB83E5397F6 +:10377000F5E07A269678731E06BDF22B9D672BA581 +:10378000DB3FF0F512F83966AFAA00BC9BB51A9C76 +:103790007FF46103E2E724D5E3B0FE6B1DE4AE598C +:1037A000F479AE8D78F37580267BD62CDB483CAF60 +:1037B0007AC5D40074D3E0D0A8E82AD3A1C372F9A3 +:1037C0000A8EFFE596D0D61C44F714A0A7F25CA1A0 +:1037D00057C99499B47C4C47ED3B5A6E9963F543B5 +:1037E0007F03604FD0F2FD0E26CFEE77E8713D45A6 +:1037F00059CC57D00D1D07FB335FC59E028E654324 +:10380000ED9F6074C3F5F0BA46730FEAE121FAD573 +:1038100010A4DF229F1EF0FA0A972BF3C16EA1F8C5 +:103820007E851214C88F602FB35F293EE62DA5E573 +:10383000574E1779562940674CDEBCF21D3359416B +:10384000877CF3CC4F1FFB275A7FFEB45E31D0FA42 +:1038500005406B74FD5E918817C60BBE680881BE7B +:103860006CD2337BB469FF15CC9ED1FB372C8471AD +:103870005ED079C0DE694A083DB703EBD33C94A221 +:10388000C9AB3A86CFE0CB16F6BD39F4B39FBBA0E7 +:103890003ED513A4EDA326FF4658D7748392887AA9 +:1038A000F9D75AC2C6091738285E8F8798DD7D9CE4 +:1038B0005649304EBF0DFBA17C9AB690F673A233E9 +:1038C00015E743E52FDA5927D618B682FC5D373461 +:1038D000AE84ED8FEB7CD3D368F9F88BC59EE5B44D +:1038E0006AD0A70FEB293D07D632BBAF5EA36C01B0 +:1038F000FC90FD169C87588FC09AC5B5501F58B2D2 +:10390000EC16908F63F139C87B122337CF9168167C +:10391000F0D3C686DCDE30E895FE891E54AFC44D78 +:10392000179FD28D9DB53DA963F88DEED3213D5FE4 +:103930006EFF40177239D343304E80CA6522F80FAC +:10394000E5724C593B5A99AD63E095546EDFA9EB93 +:103950005312FC47605D5A9EFC8FF7972A305E1425 +:10396000E522E94A46BE3CA9F3CE03BA755487F571 +:1039700075317AFDA483D999F5066E0792B03E960B +:103980000F457D79959AEEC5F304A77F5B84C9F74F +:1039900091F51ACE1FB71A408F4D6520936CD02336 +:1039A00056E85FC1FEA79E0EEBEB69397B5958BF05 +:1039B000883F814F28BEC3463AEF931B6C8CBF29CA +:1039C0001AA09F451504F5E5222DB5634BE0BDD245 +:1039D0003740D7E5D48B0EA42FF2678A158AEFF90A +:1039E00084B73350BB97CAB1973AA430EC0BE6AF1B +:1039F000376C35E5005F7BB53658CFCD12CAB1F9CB +:103A00001D95051B6879C99E2B70FD132A185D2E24 +:103A10000939502F4EE5F2B1DE10D2A31DFE3389D5 +:103A2000C03E88F68FF67413FD28AD64241E40AEA8 +:103A3000ABE8211453A6F6D1D45E26570995E724A6 +:103A4000C66E12F21EE43889B303D5F41114FA8855 +:103A5000C93DA2A482DC1372F998DD97E8443B3E8D +:103A60003F15D697AE27939BBB25C46B3369457D25 +:103A700022F4C0D0B85C8F9CD20699BE323C81CF74 +:103A80007C670EAEEB12D28BFA44E895B1E820DFEA +:103A9000A9E1FB88D1E960BC53C1FE9A4E93F07551 +:103AA00074BCA66524DC3C853D6D53503F323D69B6 +:103AB000647A129EE6CBD097F1FA315E1FC6EBC155 +:103AC000543DD377629D853D933A8DD901539785B7 +:103AD000B4A408FC35DEEA94E461BB26F08ED1A8DC +:103AE0005C09651FC905F99E50F9622AAD0FC8C46B +:103AF0000B7C65A178E9A1EF3773FBB72795CDD78C +:103B0000AD67F4AB937DA4D80AEB12C17D6F3499F5 +:103B1000D8811E053E37DBE87725F01DE3B7A1EF1E +:103B20008DA4C31CF37DD52B26D43F175EB6850C20 +:103B3000688FF8B31DB4BF94DF1BD04E3DF78A0DDC +:103B4000F5E939AE0F5DC2EF401E617E16BEAE4193 +:103B500052358E00ED4B33C6810814F659B383D924 +:103B60005923ED215E9F1399C3E8CA80FBCD0B8ECC +:103B70008107A04CE121A07F6E71327E0FEC995637 +:103B8000FC43FA3EE0B37A18F6FDC540AF06EDF708 +:103B9000E718297D4DD72E8B3E48E7D19C69B58328 +:103BA0007EABCEFED7DFDD41CB1FEED11103ACF3F0 +:103BB000F6697349EED8F2B731A43B3E10C32F77B4 +:103BC000EF54979B7BD5E5409FBA7CBFD3E63A651F +:103BD00041D9E1F982D2B5C1D07ABA87C26B78D522 +:103BE00080FA6886D3FF9013E4AD267A18F06CC88B +:103BF000FE780AF83B02FD9F48F03450368A1431B3 +:103C0000FC035F5F30CDCFB68F82B761FC11A30696 +:103C1000F14CAD75F6443917E07CE2D27B3F3C4075 +:103C2000E7BF6896D9BE02DF786BCBCAC19E441845 +:103C30004960FD4D1FC2BE8BB66B84F53F3593B610 +:103C4000A37035AC67FAB0894412806F5BA8DD6958 +:103C5000A44BFC1BCE6F777744CBC3F47FBB9D3561 +:103C600013014EF92FB20FE8E351E837C64EDEEAF2 +:103C70006472FC4BFB993246F899B602FE9A8D03AA +:103C8000FA4A3AFEF57FF90CE5FDE2A5AFE13E8286 +:103C9000CE633EB3AB4D0AC8A7C50F1EC0F762DFA7 +:103CA000762AD38AFBB6D7361858D9A1C7F2A9CD40 +:103CB0006C5FB9B8570AC13CA55917932A412F6CBC +:103CC000D6D90D64245EE3F1F8C1A6B713C0EFF5B1 +:103CD00001221DF67B12B3C7ECAD09B87F505A1311 +:103CE000C0BE0CACBFF143908F8B376B3D602F9003 +:103CF0007D36F4CF2CDE7CC3C48556E8E7D3A44AD6 +:103D0000F0136DB9013C54D0CE17627E9EC8F5F415 +:103D1000BDBCE56A05F8F1D06606FF62877107D081 +:103D2000D1F57FD1227FC91AE2073BB95BEF9D082D +:103D30007CAD6CDA3E1DD6E78399E91A6CBF4B2245 +:103D400076C08B63690ABC5F2CC93EE0E386F58DC3 +:103D5000B5B1764F9D93F9C72AB397A50C5891AF8B +:103D6000E6803E6DDE4CF908C69FF5DEEFEE700D85 +:103D7000F395346BFD2D53A1FF67751EE0BB217BCE +:103D800066D3B790BEE02F4CF1B598E3EBABF29958 +:103D9000C122F8A4B500E4EAE215AD05F651EC8CB9 +:103DA000213ED944F9723221A79D12F902FC9319E0 +:103DB0004ED5BE63AC7D9AB550837AC6E821DEED60 +:103DC000F4994AB7C9B01FB725C9586F4BD2237DA4 +:103DD000CB7FBA77E76FE8BC9E74FA2F80BECC2603 +:103DE000DE62D06B4AD45E45CD5A4035DA61641349 +:103DF000B3AF89CCFC85EB92C98E5531FB7353125E +:103E0000DB4F5039F105F473EEDD3F1F06FCB6645D +:103E10007D3C05EC85C0C5CFF4E05FB3F64B28DFF1 +:103E2000AD1E1F01BA09F4CF240B8A86E572C0C308 +:103E3000F446FCBCE624E9981C7545B19F4A97827C +:103E4000E56E07417ADAB8D48CF6FE4657C80440CE +:103E5000FFAD7C2BECA746EE0F346EFB85570B7441 +:103E60001E92ECE3A1AC30FE186C9817D2D2713ED2 +:103E7000DC9617C4F29E4A8F96D659B7FDE3CA5C0A +:103E8000C0539FCE03EDAD9E810498DF87DB4E24A7 +:103E9000C0FC1AB66971DE0DA14F5216160DCB0982 +:103EA0009DC65F900476825DB2C2F8425E7CB8ED3A +:103EB000D3940556E63F407D5A3A3A5ECCCECAC905 +:103EC000F0FDF5DF64EB726697210472F08C89F9DE +:103ED000F745BB3336A6FFAE4B12FECDDE2CD03FEE +:103EE000436579A206E4C4F7ED6CFE2E7D6F16F0F3 +:103EF000E54792BA9F252BB52444E552E34A8984CD +:103F0000A8CC3FF3DC4B5920FF3FDCFE52565D0C42 +:103F10007CF1DF89E78D496A7F9AF0AFBAF4E10C52 +:103F200018AFCE63607ECC31FCABA23D59CFFCA470 +:103F300083946B810EC577830D662FD8BB83C4181D +:103F400002975B5D3FF7D77ABDF92ED8D788EFE3AC +:103F5000FA5F0DF444E192FA24F427588AA2289FCC +:103F6000BFB4FC77D1F58C91FF749D8DB04ECDC65A +:103F7000E8E17104E9430F78D3B75865D05729EDCC +:103F80008CBEA2F76B709FE532274C81B8803EDD76 +:103F90006D05F9767D81B9439308EFB342D03E3386 +:103FA000BD10BF0B5631FA0FA610F4C3A5915609E8 +:103FB000FDB476E6E7CFA820F655B4F8B32466E75B +:103FC000B88967BD360FD75FC23807C78BD00F409F +:103FD00047202FCF4846A423A95F427B54ABE99DDD +:103FE00007FD8E45572BC5BA72BA1A2AFF9DE8EA1B +:103FF0004941C723E8CAAF205DB98DA3D315F72384 +:104000005F767B12F4C1BE3695E36B2D973FD1FBF3 +:104010008DC2AF2EC17C6B797FB5466B580B7AC4CD +:10402000A3FB38D63FBC89DAC5B07F4A03BB9E3EAE +:10403000C7B5CF5770DD486400FC0896AB8DA82F3C +:104040001FD34472C08E499DD4BA1BE823755E51BC +:10405000493BEE0B331CA01740D7A27F74E9341FF5 +:10406000B323581C283A538FFB9C96072B7DCC8E8C +:10407000A8417E09AC3629A007A7F5E72C07FA0866 +:104080002C231E03D271CF8645E0CF9D6DF580AC09 +:1040900013F125B252CD779D128B53056F22180F65 +:1040A0001B8E330D6CF921E8FFC622F49B0CF98FAF +:1040B000F309EA8DCB8D43D6AD3621DE45FC68D0C1 +:1040C00046117425FA91B13F9268647A68A47C40E5 +:1040D000FF734A05117FEBA19C2ECA3CDE23F85FDB +:1040E000C4A36C45BE1CB0C82B9C39BF32439C0492 +:1040F000FC776CB31684FD00FA8D5919DDCA4F693F +:104100002820E950FB9FABAA3362CABCFDD0F7C19F +:104110005537575F8BFA77A81EC0A67A5994BD26EB +:1041200005E255C3F532B5838D7D12FFBEE2E61B75 +:10413000A8AA1E94C4F87FEEF4821FD14454E3C5AC +:10414000C227C7F5AFA3FD5B15DE3E38EE26E8EFCC +:10415000A912517EA0D34BE15BAB53F78728E5DF73 +:1041600043418CF77F530EAF5A9D316C1F507BE15A +:10417000CF4965C376C2A3EFD5765D49C7B2D83FB4 +:10418000D583FE15FA3EE092D00E89E7D70497F466 +:10419000D5EC6B65847D9DE062F6F5746049BA2FBD +:1041A00041F91D58E62360DF52BBC4E942BBE4E39A +:1041B000530768FDB9599F1F1EA740BB7BE6C1BED0 +:1041C0002A705146F91BD8A90D49946F8CFDCCAECD +:1041D000A6FA1CE305827E96D839FD388204FC9746 +:1041E000DDFBA432A077425AB36EA36BF903973775 +:1041F00013C7E1FBCDF87997BB985F205058B5A164 +:1042000000FADF2611B01756151E4F5980FBA9631F +:10421000290B63BE6BEC7B0AF1D9B853372A1ECB4E +:10422000A9E104786C79F9452FC88D3321096542DD +:10423000831CEA04BBB6A141031621290DCDBF039F +:10424000E31F73F5643C9D5F06D777819DB706A792 +:10425000C2BCE9BF127DB5D1B708E5C4C6B9462BCB +:10426000C6910AEBEE413CD8CD5EC0C3AAC2AA34C7 +:1042700018A765E6743BC64DA83D07F52D0F7E07D0 +:10428000FD4502AE557DBA1AB077CAA95DF70B0A93 +:1042900077A673468D87F2F538EDEEE2FBAC10574A +:1042A0001F5D8EFFBF6446171D922FF8ED52F48FED +:1042B00092587F67761FB31F6F71E955FEF15B5C03 +:1042C000CCAEBD36189906E4B25F1EB0805D1D20ED +:1042D000DE4F605F4D7C56653BAE13935FAE360597 +:1042E000FD6646D7C0635742FDB532EE67883CF0A5 +:1042F0006318F75CA7CBB38A703E80F283452190A8 +:10430000C7FB5CFEEFC2FA96737BF5DCCB371683F6 +:104310007F51D85F9DCF99506F76DA94276B404ECE +:10432000FE49667903C668641AED67C9E74E1CB793 +:10433000D314EA84F50FF668B1BEC9EA5F04F4DB72 +:1043400078EBFA299887600D15801ED5B9BA08D088 +:1043500031DDBEA01FC5E8F21188234F0BCE972593 +:10436000D0177176CD34F063E1BEC5857EDC2ACEF0 +:104370001FE329159C32222B747C91346CE7BCF925 +:10438000E7D932BC14F68FC6C8FCEED573CD04EC69 +:104390005CF248F4B006FCF8AE08017BB8B957C22D +:1043A000719A0B5FD0C3FEE5EE5EC6DF01BEDFA0F3 +:1043B000F8CBC27894CBC2ED810E46672472781C8C +:1043C000E0F979B69E84D076317E5742963379C033 +:1043D000FBD3F3F84333F737514D88F5AB5CC2CECE +:1043E00058A18E5BF071D74911AF16F05A2CA9FC79 +:1043F000E4E2D9C3BF4F3C189D0EFC1BA5F4057E1B +:10440000A70DD2CC7B5EA7F3DB5036C903A6989BE1 +:104410009293B604DE5352A4782FEDFB643AD00D8C +:10442000A921C8AF2D7D95DA662B8BEB605E8CA53C +:10443000B507EA53EF2A44FD0C719359F4FDB31C00 +:10444000AF6956E6C773AF08E6401C34F1A0EF9E93 +:10445000D761FC2BCCE8874DA56B6373E27325F81D +:10446000BDDCA4F800E86777AD5202F088781FC47D +:104470000B67160DE7E3383D92772B7DEE76399882 +:10448000DFCE406A005E781FB20EC71FC19F07E3F0 +:10449000427C0F9EE7D2C232FAFFC9C096EDB8EF58 +:1044A00037603E486DDF1BEF80FEAD35925E8CC7F6 +:1044B000C6D92DD589B7BE02F43F78F6D4968701C8 +:1044C000AEDBF67A30EF25CE1EB9FE9BCC3E3FB375 +:1044D000DDA2003F6CE5729BDA8FC827C15D6C3F9F +:1044E000196F471E75A9F72743E5AFDD8E64F00508 +:1044F000B7B33C0B21DF037CFF37D8703E01F4D704 +:10450000BF0DC113970FB28DE783F48F9E0FF2E6B4 +:104510000E4B10E8E17CAF09FD92328F7B9DB545D3 +:104520001F002475380ECF01791B5872E6E71ACAAE +:104530007F720F8B23C9128F33FD4A4B585CCC6BB3 +:1045400007FF8B805B764C777B8B403EB27937716F +:10455000BF5193B34061F12E9637D494102E007B57 +:10456000EA55AE879ACC2C5E35E8D087615DA326EC +:10457000FF1F5D18D762DF935F1A94D8B8564F8833 +:10458000D975270A35613D9D670FD807B06EAB59C5 +:104590007C6B289F60BFA1C7C0E290581EECCC4145 +:1045A00039592FE256FB993FAE9EC7A74ECC5AF41D +:1045B0000CA45C7448AD35B03FBBB0AA12FDE80F47 +:1045C0003C39139FF52BD57EFF45E0A7CF1B8E23EB +:1045D0000BFF7B1DF1E899BD3CEC47D450FB4559DE +:1045E000295781BECC21F61520FF95205DADABE9A2 +:1045F000B3833EC168973412D83972A7CB0CEBFB5A +:10460000688706F554B043E3857602CF39C9CC8F6D +:10461000744D32F36BD0A50AC138E2D9A1E371071A +:10462000DEDF72A209C35323B1E7A376B966347DF6 +:104630002DFAEBD0B51AC14F17CDD4A0DFFB82DE27 +:104640003B17FDC6CE020279541DB6D69535AC1E79 +:1046500079E78229EAC3FAEB64664812C509F233A6 +:104660003599E7CBC5E16D6197BA1C1F8F690CA91D +:10467000CBF5C43F212D8FC50F62DFA72633F97517 +:1046800061550EC7B707F3E3C4FC976730BC6932C6 +:10469000D93337B36A2ED0412EC49773E0C9FCAB2F +:1046A0007426087FEE752E09E9230EDE0E30DA80BF +:1046B000BE3A593CF46F853F1EEECAE414AE1FBCEF +:1046C0006E885FD6DBF5188FBE5C3F495DB25A0E2F +:1046D0000D95BFFEFD2CDB27756A799E8D1DE5507B +:1046E0009D9DCDE584E4D91186F7566A2FC03C3AEA +:1046F000B525603F4CBBD58AF368D96F423F70F354 +:10470000B2812CD0E32D55030510B789C72F402B5C +:104710000BF945DBD5B9E8FE03EC84D8763C5F4B5A +:104720001D67F5FE20B90CF6392776BF01FA6AB786 +:1047300009F515FDBF0306F0B3BC9C83F6CC8736A4 +:104740007F1BB40B98C35B9ECD01BB85D94DCDFDBE +:10475000861EB00BEB3A62E27CF09FD5EAB81F5997 +:10476000E944FF3BE956BF6FD814F7DD883860177E +:10477000AEF33ABD7F22F03BD53B987F70B65183B4 +:104780007903F55ACF2290B7674D6A7BFCAC8DADAB +:10479000D796A175F6A0BDB565CC75F614C03AD70D +:1047A0006B883FB69F665867BABE4D7C9DCFBE787A +:1047B0007501ACF3C7BBAF2E80755EA7EBF202DFCD +:1047C000B439FC5B9369BF276FF0A13D25F2582FE8 +:1047D000971EF724ABFD2B43E5FF21FFCA58FA30A3 +:1047E0003C04875A1FBAF44A06C8833AA3E1BFD5EE +:1047F0008BF037AA1FCF68407FC7FE3F7FBA66079E +:10480000C8817E2DDA23A2BFFDB23F0FECA1FDEFE0 +:10481000B83D4169ECFE1BB95FD86D2441F0AB880F +:104820007D80B027E3E5F15B7C3E1F257B6F00BBFD +:10483000E6CBFA8D1BF83B63E85366E76E933CCCFE +:104840006FDC8B7EE4967DF3EDE0273E1D627EE318 +:1048500096178BD16FDC187A2D0C7965A45FB2C3E3 +:10486000FEA371DBB104C80710FB5CBAAF3D938CAB +:10487000F4A8DEEF9E0E9D4880FC010A7725E871C2 +:104880008B2BAA07BA6FA1FB3DC8236C91A387A10C +:10489000DF1617C13C97D23EF5FE4FC47937FAF4C4 +:1048A000287737F64B2190D7297A7F4E06E8359244 +:1048B00061C77820E7B38BC9DED494B2D8F8BAF7D1 +:1048C000F3E4E4E17CB0810D8948BF033AE2B583AB +:1048D0003CDB60E3F24C46F9F6C74D8E10CB0F631C +:1048E000EDFF18627642A3C80B934958A6EBB56852 +:1048F000B6F75D586F90F7E138791F5B1671FBBB17 +:104900004918F552331918CA0F8B6D171FD78778BE +:10491000B8AA1FD25AAC801FEC4EAB07E081F8B8A2 +:10492000BA3EC8F6EB941F96960CD3AF580741BF1A +:104930002DDC0F1D6838FE08D06FA04FB2837DD7E5 +:10494000E461F4DB44F75B90471BCFEFA4579D373E +:104950003A16FF97A6A8F5D150F9EFE45FBD3E45A2 +:10496000CDF762FEC26F3F34CF7E89F165DCBCE2D9 +:10497000F7A9F1FE76B1CFBC5C793827452D0F87BA +:10498000CA7F67795837B42EF1F2501DCFF89BE5F6 +:10499000E1FF705CE3997D4F27C0BE03EC78D8A798 +:1049A000ACDCAE63F91314FDB1F1E2E95AAB97C583 +:1049B0004FB5A25E1D8757A6F3383CE3EBD75ED414 +:1049C000E2BA35F33871F33E9B079A365817639C69 +:1049D000363E7EBA84EC9E0E4B151F476D027ECE8E +:1049E000BB743C75750A8B8F525872206F213E6FD5 +:1049F000EB35EBA749FE9875AF2AA21B8251E8DB85 +:104A000028078933E6FDC6146657BFC6F38BDC7AE8 +:104A1000768E60ADCDE285FD8C5BC3F29F7EE0F2C9 +:104A20006D82BC18A3C2F1FAF2ED4443F1F28CAEF0 +:104A300017E54AB0D9EA013928FC37A2FF8B3C5E62 +:104A400071D9FA3F8EDEF7FC0FD37B3C7EF68BF1FB +:104A5000FED6B8DD7A8A1B155F10A4E323105FCA67 +:104A60001949BF63F533161D1F4DF11D496176FECF +:104A700014CC57B84C3963298D9E003F11D963502F +:104A8000C0AF097E12D48FABD3783EAAA77C26E6AE +:104A900069B37325E21CCE5876E40743EBC3ECC838 +:104AA0000FC65C9F2F6747DEEEF07D087476B2D2AA +:104AB0008BE7011EB551F8617FF89C61D4732EE23B +:104AC0003CC6A5FC2D5FC4D1D517FF4B72D4923ADA +:104AD000965DF975CBD1CF13C07F3A763F419EFFEB +:104AE0001941BC45F749646B8C5F3B1061F97B1938 +:104AF0001C5EF1FE3FF8BEA121D59B994ADF7FFCE9 +:104B0000AED14812A99E2E6572B1C567C5B8424B99 +:104B10002FCB7F695946508EB780DFB408FC8933AC +:104B200009D87D4F3AFD13208FEED1F7AC416D22AD +:104B3000F8DB6711B0F3CEBDCBCA339CFEC99867D2 +:104B4000B76C00E318DDB3CE601E56F9179F3E52D6 +:104B5000538AF0A23FC165509F67B93D95C933F1B3 +:104B60009C3D846F2FFAF33F6E60F9DA0197D70E00 +:104B70007E09E10FB728118C2BB4EC61C65BB996A6 +:104B8000CD87FC3003E9A9654F6531F84D49AFA9E0 +:104B900018ECDDF2DF5B71DFF7F183E99827B1CF25 +:104BA000E5AF027CD84A4337817D9A4DC701BBF7F8 +:104BB000E3DD371503DC42FEAD03BF391D7F9D4D9C +:104BC000ED1727469677BF644726EE339BACFE5A17 +:104BD00098FF3A138323B89D9F4FE1FEF278FE17AA +:104BE0007C9FAAD5E038A9DF35629C5CC885753A00 +:104BF000E237E60DCB93129E671870F13CC7FE9921 +:104C00002C4F8597AD2E75BEE747C93794003C25DC +:104C1000A9F2578B675947E40B94A4B27896EA5CE3 +:104C2000A2E522B3A773ED7AA427DB4AC2E254942B +:104C30009EC0AEBF361A9906E7BCF2BBC3D7029E30 +:104C4000F75FD4209EE49947303E9328B1F1F256A5 +:104C50000F744E007F8CFDADEB6049952E7B15A047 +:104C6000F449A7EF8154E4FFD64218AFEA5F742CF1 +:104C7000BF729F05FD0CDD594D985F79EE3D83EACB +:104C80007C4EFC334856603E656EDF6F314E60DB14 +:104C9000238D9A27FB44AA15F9A62518998E393633 +:104CA000D7BA50CECAFB7E1F04BB43EE944102919B +:104CB0000E9D5703E7D382CB09FAF5C777DB35B0F2 +:104CC0005ED93C3F6670FF7F4EF1E3BE45C40542AE +:104CD0002CBF4937F008ECC7E4E503DF0CC27AECDF +:104CE00071685AC07FAA8BB6A0DF659F05FDACD95D +:104CF0007D792BBE41CBD92BED18071B7CE5EE6CE3 +:104D0000CCE7A7F31C3FCA3C1F4A65F948F23E8B2B +:104D100006F499FC04F1C0A8B223A50AE17E8A96A4 +:104D2000693FDF077A4A1E8E9B823F0AF45443AAEA +:104D30007F07D0CDD0B9A4A566762E899FA7B52DC3 +:104D40007D6F179CF7D9C2FDB907F74F9E85FEBF4F +:104D50004E598275B8E060F9952FA4B278E248FC0C +:104D60001FC43CD6DC7DBF657A8DE202FA97758C54 +:104D70005EE44E570FF8195F49F063DEEE751D6172 +:104D80002DC6CDEC277F5CA3C4EC77D6333DD3B2E0 +:104D900093EDCFE3F73797D22FBF1E92334CBF0C62 +:104DA00095FF4E76CBEFE2F4CADFBC6F21EAFD5EE1 +:104DB000BCFD12BFBF1B618FC7F537961D23F25094 +:104DC000AA86C761F6B44DD84941559E4E95959F28 +:104DD0003B34AAFB5F9F64477A10793B29EDCA7286 +:104DE000C8DB8FFE88A0DF4EE415893CA26015CB9E +:104DF000F7096A8C782ED14DBA307F681C094B12A6 +:104E0000FAD706F0FC6D2AE411D1EF4FA4E662FF59 +:104E10009B8967A516E5A62201FC26C83F4902B872 +:104E2000431B16C178B759713C13E49F24E13E033C +:104E3000F939DDC7F256A735B0B8433AD5CF504E51 +:104E4000CF6774699AABC73C56915722F24F045E04 +:104E5000AA38BED3272CCA01B928F254D6993DE509 +:104E60006017C1396838BF1C6C34F3BC13D66F7738 +:104E7000632E9E4FFEB27929F17816F929FA447F04 +:104E8000A6BB6CE43967413731EB89706DDCC7EC48 +:104E9000FCAA063DCE63B07106FA2B071B3504EC65 +:104EA00081AA7E03A3C3B8F136CED59330F42B8705 +:104EB0004C204F053D5CCACEA5EB5B08FEE0836D40 +:104EC0003BF34E52DE3FD4D68BCF4193D4ABBD12D1 +:104ED000CFA1CE03C9F58DB4FC5AF91AC8B78966BB +:104EE0004994846AD3AFFA964CF5C46072F47D2875 +:104EF000DFBEE17BAC3C3EBA45A2ED9BD33E62ED0A +:104F00008136D3A9D85EFFEFB541EB57D07F7F261E +:104F1000F1F91C35EE64F4EB3C12413F12D77FA54A +:104F20004C3EBAAD7AB49FDC3C1F9554F3FC5488D8 +:104F3000F8D0727B5A31C6EFAD44D91381FA0C0315 +:104F4000B32708E387F6F1CC6F6DE4F4403284BFF9 +:104F50006A2008F2AE3DC781DF0FC9E73D8610F336 +:104F60009BB1F18FBE78059E4B1279B684D833671A +:104F70005F81F936AAF25A133FA729DB33E1BC7BE4 +:104F8000BB8EDBC1BC7CC4E65F88F304BEA4F6DD47 +:104F9000D11B7E5004FC7476EF0FF341CEDDA8A741 +:104FA000FB8451E45A593A936B833AEB4A897EB7B2 +:104FB000C6E66F013A7CC7326F3A1C319A9B54A9FE +:104FC0007700BCC1E7B480D7644E278ED90C3E472A +:104FD000B54F823CD476131B37D92F7BF15C847F8D +:104FE000B6741B85BB5D62F29B7E94887655A19258 +:104FF0000871C8267EEE55CBE58896CB917F6E1B57 +:10500000C897A9C1784DEF135AB0E77FCBE3E2BF51 +:10501000CD519F9FE87133B8C5739656B902E8CF5A +:10502000A5AB3A524BE940ABF78470FD326D1837AF +:105030003E602B770FD0EFA5EC1F95423E777BE6C5 +:105040008F4A21BEA7757ADCBE98728F9BD17F35BF +:10505000B403BC595A4BC1EFFBB5F59748FB2BFA8B +:10506000F2FD0DF56360703519A359706EFE59930A +:105070007F3BACFF85F9C7302EFC40FAD1F721AF5A +:10508000E3A88ED15D3093E7E393EE690994EE0EC9 +:10509000E739785E0A8BBF1E9EC0FCA8547EB1FC27 +:1050A000D18912E621D6CE66E7626F26918E01FA8B +:1050B0003D3A5968FDF48A1CB47F6B799EC8F47739 +:1050C0007C09B07ED36F8FCA20F7C7B2E76E74EB4E +:1050D0009481183EBE4951976F2E5497BFE5519762 +:1050E000BF5DF19709B16593D97B10E8F55589DF6C +:1050F00047710DB1237FBAA420D85D935F4AE7E7DB +:1051000089593EE54FF97EF1A50A82F5293B8D5B71 +:105110008D50CFFDEF5A5E3FD94D8CD94EC407EA72 +:10512000E9A8C4F3325D1893227BEFB1333F346DAD +:10513000ABA7FDEC9DAF201FA75835E49BC0EBA5A6 +:1051400046B4C3045FB49B287D533C968F339A8149 +:10515000DEDB759EF5D097D66C50402F572618B1E0 +:105160006FED3FC8A8D7969B0CC44ECB071F376383 +:10517000B95C263EC823A120CE86E7519D27D40ADC +:10518000F3A5ED60BEED0E1657D796EB51CFD37E4B +:10519000715D0F3EA109119C7FA58CF9A61C66C10B +:1051A0007774247CFF34E76BAD8684518EA5B37B86 +:1051B000390ED1FEA1DF83BFD2F6A0DFAE50B91306 +:1051C000EACF1B27E0B9A8C0D0792F5903C015DA60 +:1051D000B97CE867E7F2043F0BF942A55EBE2B8578 +:1051E000309014F80F053B05EC0482FB0011B7CC9E +:1051F000348A7AD90BFDA60DB567E7E05278995647 +:1052000085352560A7BCF127A0C3B1E445611A9399 +:1052100013E229E4C516C3C3476AAF196D3D0AEF0F +:10522000C7F20C9B9DADC7840CE04BAD794206E8FC +:10523000CD768747F1C5940BE9766AAE13F045DB6E +:10524000D1F2AD35C7F2E518FD5498C6E4006DE71C +:105250004DA2F01E342919C0BFA38CDBCCC6B57C8F +:10526000BDE3BAE9B8B4DD411B1D97B6DB663284F5 +:105270003509A38D5FA1C078971A97A21D913F832E +:10528000AF03A59320F8C10EDA3448AF3378BEF2ED +:10529000C164361E2954E7FFE49BE9F8985FA6CE67 +:1052A000F7B951DAD4017AFA6953C256A0CF373828 +:1052B000DD1CB6FC433ED8696FCC2B388472267156 +:1052C000790710D10CD28BF246C8C10B69C7CAA1AD +:1052D0004CE5E18D6974DE0FE41E9D079D1F723C55 +:1052E0009D8FF6A5D95B935636127E419F026EA024 +:1052F00053E08B213A8D835FD01BB9A51713253757 +:10530000533B179EC2EE25A495E5C52B99C3F3A385 +:10531000443EDDD8CAE6D11844B86F74FC18F3E6F1 +:10532000EE18E7FF1EC035F7CA4FF0BE22E29E3FDF +:1053300001F67714DE7969C9FF7BF0C6DBF997CAFD +:105340000F1F8BCFC5F8D2AC9D981F1E986DC57CE2 +:10535000F1693C3F36D0A0C1B800DD0FE23EA28526 +:1053600018432097A772BB5C9C5B784562FED6E031 +:105370008B06457D3F517CDEB88279E9C1652CBF43 +:105380007CC87E6F56D07E1FD273FC9C44773193CD +:10539000EDDDF728EAFB89E613F5FD440BED2171FD +:1053A0006F8A94329CBFDFDD4390FEBB6DB9589F7E +:1053B000AE65FA887C83E9A3EE1CA2BA1F699D3909 +:1053C0003411F394785EC146C83FF86FF20B7E9AB1 +:1053D00026A9FCC243E5AFC92FDCE6F0EF023A5B39 +:1053E00058E4CD92283DD6EB997F98D2EBA6088160 +:1053F00074C5D67CD8A7DD445ADFD2E421BDFE02B5 +:10540000E97532A5D73C15BDEE61FC1544212DE8A8 +:1054100075884E0BE3F300FDFB60DC6E47EFEF5B3E +:10542000605FD36FF0B03C6896D7192F1F62E059C8 +:105430002033785C5A2DC2F33AF4130FCFE5F04DC8 +:105440002C9DA612C61F63F14FAA4C82B69261FE34 +:105450003199FD6FC1B8437CF408DBCF8E805B6B64 +:10546000457A9A73078B7F052CCC2E8038581A1DED +:105470007F261F7F4EA7AFDA01ED664A0C0F61FA57 +:105480000F857F16AF9FD9DF8C7970B3AA75C7637C +:10549000ED20212F45DC6D2E6F7FAB7DA60EF2D265 +:1054A00067D7AAE35D73EF64F1B639B3D5FDCC25B8 +:1054B000AB3FC17C4DD2AA03FCCDBD535DFF49DAA1 +:1054C000509C6C02C4C90E713FD020E513E0A3D7F5 +:1054D00093176FBA87D2F9849F149580DFF0869472 +:1054E000C66D4FD0F2B31B2761F9F594EF7EFF280C +:1054F000D46F29C072355CE204FB56E043CA67856D +:10550000E577CCC849007DC2FBBD87E07BB7D9DF1A +:105510003D93B6734FC9C53CD66AEED7185CC8EA4E +:105520006FBED2C65295EF52D05F5C6D66F7351DE7 +:10553000297EBB04F2AAAB7379B9E4D549503E2465 +:105540007D82F73A9C6BB6CAB00E2DE9CCCF3EB93E +:10555000500A4FA478A976F2FE9BD9BC6A4B9E4BA9 +:10556000073EA9AE62FD4CF65476E6413BCD792C60 +:105570009F4B372600FE05BFE5F07D95B02B7D5C87 +:105580004EBCE43DD69144FBF519250F4CD1577123 +:105590008CDD4B6665E7037DDE1C19FCF4D3BC2C67 +:1055A000EFB6CAB83C0DE4E12D7E7D29CCCB6E2C44 +:1055B0003E0479118915956598A76D24B8BE94FEAF +:1055C000C7A7033F5EFD495602109D554DFF82BEA1 +:1055D000660ABAAF56D337E5DBC9E9659796DF2A85 +:1055E000FA360DD3F758F63E85AB02E1FA865AAF8C +:1055F0000D8D13C79FF1E38E2537E02F56FE0EC3A6 +:10560000D78B7C9801D98D79C0A75D824F6F023806 +:10561000F49A089E8FCA963C93F0807185C7887A69 +:105620002F8E5F057C99E0332F190917FCC9C26ED4 +:10563000657F2EF0A364F07AFA9D973887E1A2E3A4 +:10564000DF910E7AFC1106CF66A995C919BE2F11FC +:10565000FE971631DF3EF57CCBCDEC1E0337F8CB41 +:105660003076523C6908EECB5807319F00D7E7B33C +:105670008D3E9B9ECEED36473DD2CFED54A33A28CA +:105680005EC274FF0F701ED404F7C17E6F21F162F9 +:10569000FC9CD247203DC66E12F0C6E3A9650CB94A +:1056A0001A3F9F78FC0CAF5B240D9EE2FCE1D07C9E +:1056B0002F739EF1F68A4BAFF65B3AB97FD139EC86 +:1056C0004F2C84FA5A62F6A03FD123E17EAF96DADE +:1056D0001F20A76B6B08FA719C560DFA13851D32BB +:1056E000169F5CFF4D26B76A9B083FF7C8E6174F29 +:1056F0008FA964E07E78D61A950D0B80FF1BACAAAB +:105700007306B556168F784EC8113250067A7FA8A8 +:105710003C42EF0F94811C8ABF7FAEF622F37B3BA5 +:105720002F4AF8ACF51C2B03BDEFAC1928037956B2 +:1057300067F7FE14D655DC13198FCFBDE91A919780 +:105740007259741ACF47220E7AC4E67F393DC63F9C +:1057500075568AA09F75B5CBCEE7E7CF017A76D88C +:10576000732AC1EF34DBD8AA03BB38D1E13F90CE16 +:10577000E4E8175FC0E6179A523CDE56ED7F5866A4 +:10578000C3221EEEE578B881EBD9F39BB4B80FA91C +:10579000F6163E0DA1A0C09B3A1242BEF5A27E14A1 +:1057A000F7C69DA7065518DA3F6F437DBBF857F53E +:1057B00018279BB05E4394187D39316456DD7F32E3 +:1057C00079A75355BEA2375DD5FECABE5C557D7123 +:1057D0007892AAFEAA374B54E5B2C85455FBABDF0A +:1057E000A95295AF1998A16ABF03F43DC5E3374E9E +:1057F000CF52BDFF68E3F437213E7D5DF43BAAEF55 +:105800004F703F04097A238574FE0B04BD5EAC53D0 +:105810007D4FCD9AB0540E7CCFFE16AC6679F795CD +:105820001463B1FD2DEC52DB13379028E62BB684C0 +:10583000244F9840DE9DBABEB1AF07F17AA97B0F25 +:1058400026B8E66BC05497C6513B632220825C0D9C +:10585000798363F1FBA5D6BF80E47FA9F537B8D57E +:10586000EB6F52D4EB6F2954AFBFCDA35EFFC40AD8 +:10587000F5FA3BBCEAF54FAA51AF7FB24FBDFEA986 +:1058800073D5EB9FE657AFFFB806F5BA67B6AAD750 +:105890003B7BA97A5D73824B54F5F17420E849C8CB +:1058A000CFBC95F7AADB53A46862E842D0D9025F67 +:1058B00003E6638DEF7A48355E3C7D4C203C8FF4E7 +:1058C0002BD247E5386E7F72BAA07AA96A5C32DAC9 +:1058D0001937C073EE046EFFFB46B73384FC8AD5DC +:1058E000EBB1FBE6B1E4DA087DC5F7D163EA2BD86A +:1058F000479B86F7D163D1EFBB84EA591C7C35FA0C +:10590000CFEEB033380E9A993DFF29545D43DBD179 +:10591000361514DE77613E74FC77CD93D10FF21DFE +:10592000D2AB8371EF24117CCE23517CFA895D7553 +:10593000BE6501F1E9B95F6409E0A9C938500E7A82 +:10594000FFC2FCA3EF637CEE48D265DD07721CE268 +:105950003FE30939C5E5C9498803D1F23913F7276F +:105960007A89E28AC1E729EEF7AC9B26A19E255AE7 +:1059700033E6B1D5DD2EA19EAAFB0FF66C1FC7F44E +:10598000DA88E75281D72E6E1F303BA10F0EDD6201 +:10599000FC90F8AD688F7AECB0DEB43F1687F9471B +:1059A000767FB1DBC8E0DC2511B9C289C70671DD9D +:1059B00061FDE17C9BDBC8E0DBA52346C0EF64E230 +:1059C00047FBF031998A3CD6EF24D6EFD15CF01733 +:1059D0009ACD6F7EAB1AF2A9E5E072F4DF7F8FA853 +:1059E000FDF777B64AE8BFFF1E859B3EDD768F1B2D +:1059F000F4B228EF02B8211E00EDE8FB5477AB04A7 +:105A0000FEB1AFADBF3D0FB1765FB2BFA17E0883DF +:105A10000BFE603D857F3683D2B781D2CBB6EF11C6 +:105A2000F41FC6FB6BC769A90681FC311DBB97C07B +:105A30002DAF67FBE2C31EBBCACF44740E38477A52 +:105A4000297B0EF2BE4FC59CD3A07434EAFDBA1F69 +:105A500065B07CA4F6B6C844884B9EE371D787DB5B +:105A6000DEC4B256F6605E26DCF7E588F95EEFA28A +:105A7000F531724EB6D2EF63E48DCEEAC3CB6B1E26 +:105A8000698B60BC53C7EF257B34E35EBB3FC6BF69 +:105A9000F2CE386E271983C49E42B8694FFF4E4F2D +:105AA00023403F5ABB7C2A761F6D70D3FE62F5EE11 +:105AB000C564121B7F58D9F60EC2FD88E4F7436710 +:105AC000867C1236517C1B6438034DDF6FB811E5BC +:105AD000AFDE76AF07EEA11A0B7F06B77C21567EAC +:105AE0007E388EDFCFC5E5E7936DD1C9304E7BDBC5 +:105AF000800A6F5D6D17F1FD9A3652C4EA3FC47A91 +:105B00004D8D82F4738AD24204E27AF2800DFCC198 +:105B1000D43E26107FD6B98D186F30B818BCE4A2D9 +:105B20000BE9639E9DC1003EBF4C4A1FEF2FD5E19C +:105B3000FEFABE4C2BB6BFEF37E30F7829DFEA2918 +:105B40001AB47FC37C86C761F8D373F94964BF0F69 +:105B5000E4803E5DC63885D33E0BD7F1CBF627F007 +:105B6000AE3711CC47D6675AD15EB85C38DD196ABA +:105B7000BCC7E38FE209E5FF7D1C4FF73DC8FC93EE +:105B8000F7DD4FF03C05594AFFCA87E96A1C978741 +:105B9000A9C487CFAE362A080DB05E46E29F40ED1D +:105BA00011D28B8D4DE0A7827AAFEC80D48827AAE2 +:105BB0005D33E1B9A6E26417B0E3DA6B3F8BC01343 +:105BC0006211802F7B0309C155BC98AB40C777F8A1 +:105BD000593981D727CC65E5445E9FE863E54CEFF2 +:105BE0000B523500161747CBB43A6FCA0779BC8001 +:105BF000B073F1FC7E8DCD84CB0BAB736635D4DFF7 +:105C000049F09C8BA8FF09AF4FB31E5F99077A63D9 +:105C1000B6FAFB0D1C0FA9D6E35DD330DEA6AE1796 +:105C2000F1AC64EBF937F1FB2275FD53FC7B9BF57E +:105C30007C641AD4E7ABC77F9CD75BAC2CEF8DCAD2 +:105C40007E767F03AF7F8CD79BA01EC62F64F55A4C +:105C500071DF096FD7C9E118E2331E430C2633BF49 +:105C6000F2963623F2573CBFDD07F773950DF39B91 +:105C70007D2919F5DE86FB3298DC495006BCDE51E1 +:105C8000E4A2A877DA65CC37D0BAF5484F062B974F +:105C9000279C1F87E489D4EA6144C6E4F4A5E89A06 +:105CA00012F005906B59F40FE83AE3FB1AE28F917A +:105CB00073E94D66E28FE583054E5539E5CE74559F +:105CC0007BD7EC5C55BDB57492AA9ECC76229FDC46 +:105CD000CBE9CB5C54A2AA17F765906DBC9D9DB52E +:105CE000D3E54F55B53B5FA824028D9FBA49DCA38D +:105CF000E631827CB8D7969B0AFCF8B3B60A444ECC +:105D00003BE527F6B4F3A71B8C59FA5478B910CBAE +:105D1000CF3B587E7F7B9B879573089EAF6F6FABA1 +:105D2000C1F22ECA9FF0FC699B179FDB6959A1CF76 +:105D30007FA4FD2BB49F1EDA3F949FA1FDC3733354 +:105D4000ED1F9E3FA1FD43FD06DA2F949FA670C173 +:105D5000F329DA0FBCFF31ED1FCA4FB4F9B0BCB65E +:105D60006D2E961F6FF3E3F3B1B6067CDFD9D68AAA +:105D7000E547DB96E2F3E1B6203EDBDB56627D2FA2 +:105D8000A793E7F979DCE72BD9BD03F1EBDF9F217E +:105D900061BB2F9D9F534A157AB92A3FA73F03FC49 +:105DA00002BDEAFC54C01FC26162788C87E36806BA +:105DB000B30F2791C8720B931F18071FDFE75961B4 +:105DC000A1FC35AE95AD7B4E5F14EBD31AD8784766 +:105DD000B99D405C419251CE8E9B43BB7352A4CA85 +:105DE000C2F207D00F43DC143FE5EC5A7246E621BD +:105DF0000DC02557503D1E33AF217C39189C80B70C +:105E0000D1E0FD578E376D692FBB5FA7A62B0C6CB9 +:105E100066F6B6E2FD3AC6B9BEB04C9F2E9F1FEFA4 +:105E2000E99874713ADD2452F976F19B44A1CF8C44 +:105E300026F5FE317D41896A7FA6BDB8862857D1F7 +:105E40007E8BD4FB3C73FEBDAAEF8C190FA9EAF53B +:105E5000AE15AAFABABB731E71033EC7B1B89961F9 +:105E6000F5720221E485DD4F205CE64C368F73929B +:105E7000C27E5F6037FF3D13BE7F79D6CEF1655C91 +:105E80008DFBF2090E562C480C6A400F7DFC8B44AA +:105E9000947F3B9ED1A09F7E22096940DE4CA6E6FE +:105EA00024D45F01378C6BF1AA262D948B89A285AF +:105EB000F255248AFB3ABA7FD164D2F56BD1FA9FAE +:105EC00031D1F2D94CFFB32CBF308CFABA80AF6716 +:105ED00081D8C7AD97E3FDDCC64CF437A9CF257652 +:105EE000F0FD4B8789F90D973BCA53C10E3E3746EB +:105EF0003EA8CD7DE28D0514DFB6B463F814EF1F24 +:105F00005734A39ED7CFCB94BE5A5EF77AAA4FD40C +:105F10007C9307F3385BFACF29E0766BC98F22FFB9 +:105F200074E8843C5312419E0D973D8924661E3BC4 +:105F3000DADEC9935121FA116F325F37315FF94FC1 +:105F40009576C84B2CE079D13BDBD2F2ABC70F7F03 +:105F5000EFE37450482235A05F0B8B349E1074E041 +:105F6000B5ABFC31A6FC2E2F9C0B934B8807C4F2DB +:105F700044D285F729C87FD5623E9A7CF01AA25098 +:105F8000FBD86A0D9360D170BF84FB75BECFE5FC72 +:105F900067F66A9C8F9C25EC260FE874F299D51B56 +:105FA000013AFCAC5BC7D8F4B8BABED04A50EF2D6A +:105FB0002AD4871409EECBEBC27B40E52D12C9C869 +:105FC0000138A6B9E7837EDF6B413AB6AC2FC79F95 +:105FD00030B859E3AF40FC0E287B35C2E8A2ED9AF9 +:105FE00027EBB7823D3901F06205BCDC915F0D43C0 +:105FF000E717221E17F2792FE4F3E8C81CC23F838B +:106000008778BC701FEFA26EE18F52CFF3F1D2AA56 +:106010006FC3BDA2ED112DFF9922353E57E92253E2 +:10602000E64BC37051381766825C01B8AF820FD857 +:10603000FC9A9F91C8C61C946B35686F9469303F79 +:106040003D9E2E9B3299DC8F66D8D97DE4EE534875 +:10605000CFC3E5936F2C48C2FD33B35B6C32CB8F5B +:10606000F47A9558BFF72AE15FE4E772CC1CDEA111 +:106070007B0527B1BC602B89AC87BCB4B1F6F52B8E +:10608000327370DCE17D3DB55D203FA5CC88795C45 +:10609000AB443EA172549969634F385765E474FA72 +:1060A000A84D9DF7B39DCF6F3B5F8F41A3C87BF297 +:1060B000D616C79CF3A9EBAF473F9688D30E72FF65 +:1060C000E1A0591D576DE4A43078A8ABCA0CF1C10A +:1060D0002E16A76DECBF99DD6BBBEFC7782F30EDA7 +:1060E00053017AA8E7EDEB57AAFD580B77FA915FB9 +:1060F000E3FD64F17E318A393DEC1FE3FD625B33E1 +:10610000F97EC2438A210E7B6275DE6133EC7772C1 +:10611000089E0F1FA77D01EFDDA6BB812EB84F970C +:1061200014B1FBA3E2D7FF54961EF1B253ACEF7843 +:106130002BDAA53BCB981CD879E0FC2DE3693F2BEB +:106140007324D5F98095393A5CA7B7297DC3B397F5 +:10615000909AD1EE293B94A9F96A72EF5AF5EFC1F2 +:1061600034F70D1CB62828FF5E03BA1F3CFC7942A9 +:1061700011F251147FBFC408C23099C10DE7B37644 +:106180006B3E99174B0F6F67CA58FF36A78B2F0DC1 +:1061900057B51AAEB3456FA5CC6070FD0EE4C6B915 +:1061A000F0F194587B46C0B57B8CDF03F8F0ABE28E +:1061B000A942AD1F62F074FABFC3D36EFDE8F0FCD4 +:1061C00095C3F3B343EC5E9B91F55F519F75ABE1D3 +:1061D0003DFB7C640E88490AEF5F117FEE9329181E +:1061E00013E6F8EB2DE5F459CAE58F07CF5091C0BF +:1061F0007B57631E66AF4C926AA15CBE007FF72C92 +:1062000093EFC3021A3F9EBF21EF1946957FD764D3 +:1062100031BADE9D2E8D8A87D22C36CF0347EAB263 +:10622000C1BFF1D83B0602726133CFBF7ECCDE6BBB +:10623000847BA6051EA15C429F017D741128BCC70A +:106240004A3F332AD651C6D3B0F1D6C6F18D184F86 +:106250003CA76415327B553AA48573386BAF7D0B30 +:10626000EF7F5B5B2AA3ECFDD2F85F1D87FFF05B3D +:1062700029B7307A999245E16B91FE90F06D5A0EF4 +:1062800048D17F2A827C15BD1FE71FA078EC91467C +:10629000E2292D8BD18B989F98BF80DB76DD025C45 +:1062A00007DBBB06541AA5BCBDD017895CFFC1BC77 +:1062B000505F5C2BB3734C6532AEFBDA8AA978EE83 +:1062C0006C37CF17895EA31FF577441670BC3D76F7 +:1062D000F1B711B84739D8AFC3FB3F883CE0BE15D2 +:1062E000EE1FFF8D8CF789537AAA81FBCC0E1C39E7 +:1062F0009F00FBEBF9593A847B3E97878317B535AE +:10630000781EECC867766D0CFDD76569B97D12897A +:10631000C039AF3525EC3C8B95DB03D623271B001A +:106320007E6BC543062986DE66651910AE35FA68B0 +:106330008A87F617D8A72561E6FFC17B1987CEB3F8 +:10634000DA191E5A4A0FA1BD60ED67F735D66529E7 +:106350004CCE52B8F7D2F7E6899FD9EBA1BE948E06 +:10636000973BFCBDCDCED6D35CC6EE4B5A7BED3F02 +:10637000DBE13EC844F81D47D8EFF2790AB89272C3 +:1063800035BCDF482417F8CB2E63BE5A6FF85E2366 +:10639000D8FB822FDECAD562BB47F93989472B0A61 +:1063A0004370AE4CD0B135DBFF4016CC8FF2C50B3D +:1063B00068EF447CD3103FF662C833DF2545E632F0 +:1063C0003B446F073E2CD46854FC16E1EB269E54E8 +:1063D000FDA3DD733FA75DA1F73B424602E74DFEFB +:1063E00078716622D8A71D19C2DEF31A015F9B25BA +:1063F0005F620E8CF32F5ADC0F1E3872BC01C6EDA3 +:10640000A0F302BE7DF875EB6AB0533AEC5EE4533C +:1064100031BEECD0F0F560FDECD67BDF047F64D4B8 +:10642000C1EECD3A38758611E89FB6D3403F7FA0C4 +:10643000FBF7F004E8A71AFD060BEDB3A6C3778BB4 +:1064400088FF11B06F17756B55F7833CCCE5C5C25B +:106450008B16128ED92F2CACF80E9E6B5C78310106 +:10646000DF3FCCCFED3FCCCFBDEDE2F878993F5F79 +:10647000CFFA8AFB6F4F9CDE4AFEDD8E3AC6F7BB31 +:1064800060FD9AA5013DA8FA35533FC7F3647F68C4 +:10649000B393B02106DE11F34C22E1987187DA5DE7 +:1064A00034917052ECFA32FA1D9EAF15EBFFD0E634 +:1064B000463C8EDDFF38151E87FBCF53E17164FF2C +:1064C0000558FF87B6C24BF43F798CFE7354F00F2A +:1064D000F79B8FEFCF1DAC7BD642F9EE6078C5C637 +:1064E000574BE1F7F70CF87B1BA4AFB70ACFB9EE17 +:1064F00022780EFA81FD7F7A1FF2521FD8AAF7C0C8 +:106500001883BAE83CCF287A269FD88370EF9C780E +:10651000BE9D9587EB1CFFDE2887EC90676A2C9464 +:10652000EDA0E78C24125A01FB975223CA3911DFE0 +:1065300012FDFE3453AB92B3E27EA1469E7FD86833 +:1065400061F1AF26ABFF2CACFF124D57CBCF681FCC +:10655000A70B3BF07C3B210EDCD788F88E0CFBC5EB +:106560003C707DF9089C0B9B97E3FF0CBEFB091563 +:106570002B10EFD15EB1CD0FF9798FF37DE4E3A657 +:1065800088DB13233F75D9F257B31BBAE2E8B7ECA7 +:10659000773BC28C7E75D940BFDAC8CFEB72E07C06 +:1065A000E300BF674E41FBB9AEF430DE475927FC2C +:1065B000022BE3F356321D604F8B785402E41782AE +:1065C000DDB086DD53586F61E5FA5F27E1B917BA90 +:1065D0001FB214819CD9AD65FE221E073BCF611E00 +:1065E00034AEC902FC0EF27C97F3FDAFE1BDA7E724 +:1065F000578E473AA8FFE50FF11EC3DDE94C9F0D0A +:10660000EEB3A13EAB3778CAE15ECDDDE9CC6EEDED +:1066100095C309253176ECA3195528A73F5E395E4D +:10662000131B27199FCDE4C21AE1FF94A3E570CE96 +:10663000EAE3D2F03FA13EDD63C2DF1BD3ECFD53A2 +:1066400039DEBFBAC680BF6351B577E2BAB9B05F71 +:106650004C90311F5BB3D784F09C5DC5EE83836F94 +:1066600041EE35EF1D87BFCB566F8962DE64B3D92B +:106670005300F1C1FABDDFC0DF9F38F1F8C42C90A0 +:1066800083C793952CBC6FFB718A743AEFE3FB26AA +:10669000B0F79D57E3B96ADB1A8B7F34FF88D04B84 +:1066A000F1F7CDED4E2F3ED707F89968F4801C5EC8 +:1066B00038E45F67F707D6BF199DA524A0FF06F34E +:1066C00017EAEDA7F0F71DEBBB8FDD49303EE9423D +:1066D000FA15FBBCF871EBB9FEDAAD8FCE83DFD5CE +:1066E000AB6FE7F8E7BFF759AF29C6DF9B14F85F38 +:1066F00013771FF3F738DEC5F3C41119EFB9A47689 +:106700004516F88F4EEC3720BD9D583319EF5710C2 +:10671000E3D55358ED944F8F3B9529B0BE0BB2157E +:1067200036FF76B67F15EFE9F811F8BDCEE83E2DBD +:10673000E6AF0DDAA30910C714ED4479683EFD5A9F +:10674000FCBDB7DDE90770DD295D11A02BCD2F6DF4 +:10675000A8B703BF64BF1BF7712909829F34F88E65 +:1067600001F77B07F719D09E1E7C979DCF1F71EF15 +:106770009F359A05F7DC067E390EE5DA6066740B04 +:10678000B3BF4D78CFE4E051FFD53C5E9CC6EFD15E +:106790004C03BBEFC23E5318EC3EFAC4B843906CB6 +:1067A00073E3FBFD16BC2F883ED9F924698F1B7F4C +:1067B000378974F1EF23F8FD0359FE0920A71FC89C +:1067C000A3FD5BE1FB93D8EE42AEFF4A8C591192D8 +:1067D000CEC74BC77E33FDD9F85EFACCCD7E0FA86D +:1067E0008BD747B03E60F05F8DF3F8BD8DF48C32EF +:1067F000CFAF7A5FE47DD949B88E026E8A67B42341 +:10680000E3F1D293CDF69F021FF17439B49E9780C5 +:106810000FFC3278BFC03EB68EAB26EA993CE99CAD +:106820008CF632DE30149327B87CDF074897833A22 +:10683000EFD3A097A2477584DDC3482D03F05754CA +:10684000B076F516E6F710709CE1E7071A3B591E83 +:10685000E199E73EC89A6F85F3F31FA8CECF0BFFEF +:1068600021ED2401FC33568F925057C4EC762DC293 +:10687000C57E8F6E8D4EC1DF0B0C3E3E11FD122783 +:10688000F4CA5EBC0776D5151AA0276D3197BF4FA5 +:10689000B07989FBDDC43D6DF17819C866FAB2990B +:1068A000F8EF823BFE8F132585074BF1BE4A74FF3C +:1068B0006B20CD52F69A587E3BEA8591F742EA2F3B +:1068C000F17B82FFBBE553B05665809F6002E8D53F +:1068D000D376B67FC45B2240BF6BD93C3BE003B8A4 +:1068E000FF82F84E835EC45B25281E4E4BAC3E9E55 +:1068F000CE84BC1B810FA01BE817BEA37D7F9E9D8D +:10690000C3F63F76273F9417D4435EAAD057014978 +:10691000D6C07D0F271D4A02D0E5C9CE3CE772C81C +:10692000F7712829B1F676E010C17B0E1438FF7399 +:1069300035FC2E92770AF805773BD5FE8878785E8D +:10694000A81C40FDF35F98C6C553008000000000FE +:106950001F8B08000000000000FFB57D0B7854D5A8 +:10696000B5FF3E73662633794E1E8484409824E436 +:10697000018430090F4141074810156878092885BE +:10698000930710421E88B6175BDB0C24205AB441D3 +:1069900051D18B76404154B4414141037700A55811 +:1069A0005163D5566DCB0D88BC1F31A897FFADAD97 +:1069B000FFF55BFB9C64CE90A8B5B7F93ED8D967CC +:1069C000BFD75A7BEDF5DA3BDF7C433FD7096175D2 +:1069D0002B42F41022CE6D11629810A3DC82F34298 +:1069E000D885C811FCF38DCA89DB3A5C8885F88D9F +:1069F000AAAAF9DAB59EC82BEB2D5C1FE375467782 +:106A0000F1BDF1B5FF50F228B3214C0887FE3D5D82 +:106A1000880F311E8D7BEA90DDA70C461A2EAC093B +:106A20004254AC75FA451AA56F4ECCBA53E685426E +:106A300075C76C5C99D84AE3966F2ACA1291B21F47 +:106A400041F3AAD0E7559EEACD52870AD1F6A8EACB +:106A5000DA84F6EB559E8F6AF3B81EA5EF27D6DBD6 +:106A60005CCBA99F0A7D3E277A6BD1C5B994B70A42 +:106A7000ABBD80F2562DDA45FD2E78542DF677B158 +:106A80003EAAF781B5A00BF8604D893A7C32A81E6A +:106A9000D66994E3BFF7687257D1FCC2E977CC633B +:106AA000A3E2F7D1FC4EF4D1E6217FFC9330B18212 +:106AB000F2EADA45D1EEDC2BE17DC2A1457B720121 +:106AC0005FB91E039EA1E318F0BC0878C620BDBACA +:106AD000C54BF0AB7D48F5A0CEBEE64BD180DF982C +:106AE0003D4547AEC1F7B561228CDAEC3B9CFECE4A +:106AF000AD348F8BAB55413D8AD23D198982C6DBBF +:106B00006EF97C2EE073BF4DCC7A91D2D2B7A747F5 +:106B10005B28FD46A71FF5210927356A7AF47CAE6C +:106B2000DF3EB998F2C7DC9EC482A07A3FD6E92C3A +:106B3000145F656BFF168D712AD6D8785D065E2EC0 +:106B4000621D34BF8B8D11FEE504978BBDDBB85FF2 +:106B5000034F46BF15C083414F546FA5DBA58FE39C +:106B6000B31747115CD3B4E19E2EE864C183342E81 +:106B7000FA5B1FE575E67DFF710D7874E09B962545 +:106B80000CFC038F4FA46DBC97BE59DEB30AD193A2 +:106B9000E0D0787DAA42DFCBF6840985FA2B53DA60 +:106BA0008E28099C77FB14AC7FF13C8C57F67198CA +:106BB00005E5C7F75E9FC7F30AC12BC129B52B7A3C +:106BC000BF98D696EA0982DFC53E6D7379BE067D11 +:106BD00074CE9BE751BB374C605F5C4C237C4676A0 +:106BE000C2B101F819C6F55D76A66F6F1EE0D7B188 +:106BF0005E57C87A5D21EBFD40307D0B8FC6EB29D7 +:106C0000FF24CC82EFE50FDC94E5A6718EDF3B8E8E +:106C1000D7753CCE9B87FD753C95FACFBD729DE53F +:106C20000FD03A73BF659D8D4EC657B7EB8C6B7B0B +:106C3000427CCB3A37EA7468ACF333AB3BDA8AFA7E +:106C4000BB55B19C8A6AFB14DF7F8DCCBB56D0D07C +:106C5000B536490FB56B23FCC0D78566DB047F6E64 +:106C6000271FA0F1BE273D58981E8E8F753F3C020E +:106C7000F4759FEAF2B9019721EFFC9CF2C7EF5738 +:106C80005D02F9B1127EC40F2CE00FC7538B27733E +:106C90007EAFCDB582FAF9B4F16F7F04FD5CDC63A1 +:106CA000730B5E5FF1FDB390A7F982AF115C6EC606 +:106CB000B854CEEB57EF19D68872F1E86057A6BBEF +:106CC0000BBE1402E78A35AA691FD201C1E3D53E83 +:106CD00090E2C63A0C381387CD9A3AA8131EC84FD3 +:106CE0001FD409975ABBD09AF8FB12FB944141FC80 +:106CF0000CF04997E744FF3CC9C7D2A283F673C89A +:106D0000FC42F98F51CF48FFD2C157CCFC7851706B +:106D10009EE05019925F1CC237AA42CAAB43CAB761 +:106D2000F7FA9CF940E8F813D3E4BE31E058AAC35F +:106D300071BB45917CE43EC5BF897E2DB5BAED4B54 +:106D400069FE2F8E11F3D04F995538AEE57DD9CE1F +:106D5000EB2BB58A86B0027CF7703D63DDD45F43D0 +:106D6000581CE5C3251FA27A13EC417983DF1AF37F +:106D7000094F93F030D2C55B9D8DC783E059DD1478 +:106D80006BCAD7EE4A6E3CEEE8CC2FC62FC9F46F23 +:106D900022AD7E38E0227FAA77B51E8C20FA49B258 +:106DA00068E169D4EFC583FF1B9DEB66BC0F2F26FE +:106DB000FC16A8E92F1DA6F5B6ED563D9BD0EF9B1E +:106DC000F2FC115F5F7A781B7DAFD99B21EE75775E +:106DD000AE3F148E17775D8A4EA7EF170ED9C30505 +:106DE000C901A5CDF163EDD1BCBFBA84BB5B87BB44 +:106DF000D1DF056B6BF494A07A17446BF4D4207A3E +:106E000029DD75A94EE431FC7C6A101FFF744F8F99 +:106E1000B12A7D2FFB7DAFB1164AC7E9FDDE6F7346 +:106E20003FB986E6EDDB1DE6D94CF3BEF0E62C0B50 +:106E3000DA5F78B3424F7FEAE5F4B34F53317EB463 +:106E400045D2BB31DE8834294F95598E3E311AFC2C +:106E5000FFD59E69F5699DE56596822CE0799BAD2D +:106E60006D2EE67D4111AB95B8CE7EC6A5B9B9FDB4 +:106E700085DD279F007FF8F4FE3E05602B177667BF +:106E8000E769547EE1E321592EEAF7C27DC91EF07D +:106E9000856D36F74F99DEEE89F260DF1BFD619C50 +:106EA00025E87FF755C335A41FCBF9523E4F93E336 +:106EB000FA9482CE7EA32DEE5F8F02BFF8BDCDB3D4 +:106EC0009992A57FCFE8198BF5613F778187B2D57D +:106ED00061C26DE2272B78DEA5C263871C84721124 +:106EE000445FE5A298BFCF6F347F5F407C02DF171D +:106EF000AE377FAF108DAB5A697D8BFCE6EF82F623 +:106F00008F2F11FBDAF869E2F37EF1D66FC24CF5F0 +:106F1000844FE70F0EE6C7A5B41FC1C79E57FCFEFE +:106F200015C0EF3D2AAF33745DCBD3D2781D8F44AB +:106F3000FC636E6B105E8F59843589E07ACC2E1C11 +:106F40004905E847089CABBE3D61FECDD4E4DEFEBA +:106F50005FA59632DF4BB2E03CB8C305CE47FDEDEE +:106F600039998A7ECA5617795B83E677D1E67DE444 +:106F7000E79057DF237E4DF58E8DF5378EA5791D71 +:106F8000BB57F5D47731AF33249FF9E3091EF728B7 +:106F9000C23F84F2CF9C4C2D21BC9CDE7C32B534A8 +:106FA00098FE15312B981E8D9466C2EB82AC89F445 +:106FB00018AD05EB09ADD7895FF37C0D783A55B173 +:106FC000A42B7A7814744FE5397F5705E4CE9A3DA7 +:106FD000363FE83362E3170FDF0AFA6CB6B940DADE +:106FE000B57B542FE474B15BF567E21C6BFE34BAD9 +:106FF00012E7CCEE212E3568DD740E17E37CB9B0B4 +:10700000EB5262592EF73319F244ED9E873CA0DF14 +:10701000EEE6F15C9AFAAFF13FAF99FF9DCFFD200C +:10702000F146F0818D27B2C0DF890F3E9786FD992A +:10703000F5B51D79215A8783FE687E2CBF5FF47FEA +:10704000C5F2A5A359F5FABBC0C39E343BC3FF07E5 +:10705000CF6F02CD2FB1737E349F3DE0CBC63C6B2A +:10706000DC6D769CB3171DD179E0A7B4A089F989AE +:10707000FAF9E4067F2D9B2888BF16EE9EBFC20951 +:1070800079A151F1400F286F56F9DC2ADFA0FADD13 +:107090008497C2ECBBF63B219F3E44E5D474BC3AD6 +:1070A000EA8FB3A8FEC2FB54CEEFDBF8D33FDA8001 +:1070B000D70D3611063C86476FD2C7637968913E7B +:1070C000BF45CD379D56A0B7EC513D01B4DF1CE55F +:1070D000C1F7B2D5B663C1F4351FBF507FF3D72BCC +:1070E000FE401AF884B9FCC2309FCE2742BE6F5CC6 +:1070F00035757F02522BEB898BFCE672FCBC4EF39C +:10710000A9D57FDF9AB9A617F073C129440BF6AB56 +:10711000B595F51D11684D051E2FECFE2C1578ACAC +:107120007DF57FB24417F8EBD84FCD510927228463 +:10713000384BE7C63716D0FDA5C9C55DD47FB18FE2 +:10714000DC175B6DBE5E9063F76FFC8AF9C1C5DD2D +:107150005A5F5717F4DBB95F7D4E4B12D280532034 +:107160001DDAE4BA11FB84E4C17B411F9B564DDD5F +:107170004479E76B364842A2363392F70BF6C7FCE8 +:10718000A07E8D7DB2157C01E930C91F5EEC23E540 +:1071900084D5BABCB0755FFBE4CC2EE6B33ACD26FD +:1071A000CFDB3E926FCC4D2B0E4F879C61F1450398 +:1071B0001FC2EB7527107C159DBEEA972D51F03D3F +:1071C000493472DA5B3471FAB8105A24EA0B8F0B27 +:1071D0007016A24F2CE0C77B9ED7AB31DFFC898EA7 +:1071E0003BF06AD0832F56F837D3EFEA46875063D7 +:1071F00020EDB546A351D4A0A9BFEE4BE5B60F5480 +:10720000D69FD43E063E3D2EE0F7CBC8E931C1F80B +:10721000DB77B87402FAABDE497A2EF5777E874DBC +:1072200004A0575969BF503DDBE12FEC69E04BCD1D +:107230008A80BC5C4B797CAF1D65F5FA83E0929740 +:107240002EE1919A9EC570BB60F51E9A08FA73955F +:10725000DA21D7DB0E974FC079634B2AB5635EFB0B +:107260000E8F75A4016FB156DE37AB9A8D715B5CE2 +:10727000E83F2AF6039E6F43AE454453BB868FC258 +:10728000FC0C4C87E443613A5C1B02850E7717F8CF +:10729000F189C2143182CA77A81330CFF3AE5217E6 +:1072A000F0688B957687309B7702F49AB0D8B878DF +:1072B000CC6F447A06CFFFABD8253CCFAF48BC801B +:1072C000BE41F27A31F20DBDCB55867DE323BC8FF2 +:1072D0006B1D72FCA83D2A9FA362A443E7DBEFBBB2 +:1072E000CA689CC8BEDA24D083319FA861AF0BF076 +:1072F000E71C8B85E5B3863722D7802F18E51BD294 +:1073000025BD19F858996075817F3CAED3E74A577F +:10731000B1A320689DB61E161D5EC50EC069BBBD1B +:10732000F810CE9736FA8E73737FD25407F414AAEE +:1073300067413F27EA68C764A3DFE90EC07741428F +:10734000E978B45B2896ACC27E5BB85E1581203EBE +:10735000DB6093E32EB81C2102433AC75D40F8E39B +:10736000F697A3F97B8353D66B8892FBE7CE7429FB +:107370002FAED4D3B57AFA83F9BAC7CCD7CFC7FE2C +:10738000714BA9E4EF77A653BFD54AEB788826ABBB +:1073900092DAED80EF893A97088405CDF78A75C6B1 +:1073A0008B40D0381DF52E3B45203E181F6EC6473A +:1073B000E77A23B9FC445D12C3B1FBFE534C70EC79 +:1073C000EC3FC304C72BFBCFE2F2137539DFD1FFCB +:1073D000C06EFA4F33CDBFB3DF7EFC5DECD2FA82D4 +:1073E000BFDCED227EC074D3CA7626BBA2FD067632 +:1073F0002FF1719880DCF79553CB7605F1876DE915 +:10740000765D9F0BA480DFFAC43A4E6B775D1A8FCE +:10741000F66EE20B6CE7D0CB6B451BCF13FC02FA88 +:10742000BD48B6BAB97C97960DBDC89847873CF35E +:10743000BB489F85F641D89EBF47631F5FB4B64DDA +:10744000867DAAA9598D08DED707F4FD31B6CF177E +:1074500079B0D7D5A01DF1BD9FEE5D9C0DF8D48409 +:10746000B5E561DEFBF7FE2D0FE7C8577B16F7C5C4 +:10747000F7AD549FE50F7B5B8D27A8BF7EC2E5B3B8 +:107480008CE84C9BF5FD1FFA7DEB9EFA5E98C736A3 +:10749000D83D482EAC59F656C6F178B021EF83E0BE +:1074A0005F82F816EB43BBA6A96320DF7D48320F4D +:1074B000E587EE9672C3D03EC26F4983DCF7E12CBC +:1074C000F0899A61761754E1F0FC1696B7C38739B4 +:1074D0005C389F9FED93C1EBB3434EC840FBA2784D +:1074E000A6E754F1AFC96D1B42F64FE00F35DB68DC +:1074F000BC6AB575F23885F7D131F0A99AB7BF7873 +:1075000047D75F13819F5A8C4BF0785FEF27214359 +:107510003B897A9AA3F5BEABA8DE8C9B9353A11F3F +:1075200095E8FA9998484019C9FC6810EC20579ED4 +:10753000DB520F7A4DD134C0C197ECF0E0FC1A98C1 +:10754000221CC971D8D0FEF4A934EE57E916C32E17 +:10755000AA60DE03F4353DDFAB69692C9F93FE38EA +:10756000D0D13F3BAE25C3FB77F00BA3FE8737DFBF +:107570003A48EBE2DC30E479BBBDE936CCB3AD3A56 +:1075800092F54798F3D0EEC99BC3022AEC8AB6C89D +:10759000D5D0E73F8A987BB007C1E3FE282D228330 +:1075A000DACD9A79C32AE495FDF1EEA5A0E792D64B +:1075B000E1C0E7D34E2D2683C6AF72687D1369897B +:1075C000E7FB68D93138E48BE3259E44F1A0E22E35 +:1075D000E72FE753A2C8F10F476949E8A7C4D2F2E1 +:1075E000C455F8666D617B8368E8C1FD9CB78B8AE2 +:1075F000AEE47F030E47F475ECB3896B2FD3FAF634 +:10760000AD8DF1D4D37CCBEF9E39B796D2F996E20B +:10761000C4806A9A7716D655E52BE99B4CF2F3792C +:107620009B3EEF65FABCADAEACE0FD1C3AEF7A4391 +:107630005EF985C2FA20FF50FE155FACFF5ECA8777 +:10764000592E7D300DE7D6200BDB493684D3DE2260 +:107650003DF25D7D9E8FD3BE73C4F1F7D5F89E14C5 +:107660002EDB273D6CF1C37E503C7637E3E9C99AA7 +:10767000488F4A639508B71D725099F0B25CFCD9E7 +:1076800098BFED69A575156668D7016EF3E22DA95F +:107690001FF03CB48153206F8D92EBF8167993D78D +:1076A0003155B86C2C94893516C81F535D7229F377 +:1076B00015B93FA609AF0DE3CD101AD7FBC305BB23 +:1076C00017FAC41FA00BD1BC670A1F7F9F2DFC9C1B +:1076D000DE2A025CFFC7A295F306BC893EE6254878 +:1076E000FA38D95365F8DF8C79BF1791D76719AD90 +:1076F00063CA23D999AC5FADEBC1F0F9AE794FD134 +:10770000E986F6EF3CF483FD3B9DFA997A63C8FE67 +:107710002DEC61E033F3DBF6514B7B87FE14994C83 +:1077200070B85E47E9F5DEC5AC3F15A991C247F8D0 +:107730006919A5FA21771CF22E4F48A075DCFDB916 +:10774000D4837EB75CBC3D84CA7F374615F5DCD256 +:10775000CBF2D464BD9FC9BDC79F869DF5B00824F8 +:107760000CA5B9175DD65E8FA1F94E56B735C45238 +:10777000F984DEA4C704F1BD1B12B65BA1D7DDD826 +:10778000CFFC7D62AE59DF99241A55C079F250734F +:10779000BD7D800FD1D78A0CA9B788016280EEDF4A +:1077A00063B9FB477A1FED132FD9E10B793543BB42 +:1077B00007705C3AE9B3B9185758E57A6ADE51D9CF +:1077C0009E778CE42C2F9DDFC7EBE8840893F208AA +:1077D000F2A7486E407AA6CECDE9393AE7517EA1AC +:1077E000CE23EB67143F807D56BAFA732BF072B745 +:1077F00053C2F96E67AA1F76B58AA6C6F1985EE5F0 +:10780000AEA68348CB03C5E371CC2E38B4E420D2B6 +:10781000BB3BF4B6250EDD5FC0F3BF5DA7D3DBA392 +:10782000A6DE3488F6C9EDBBA5DFEBF63E53A74DC7 +:107830004A40DEC6F9EEE8A8FAB22234DA22CFA82E +:10784000DECD58B7B7F9E8C1785AE7C9BA113CFF9D +:10785000D3755E9EFFD9BA099CFE3DA3F839AE27C9 +:107860003E67796CD2B6A3D614AA5FE455BCD8B7EC +:10787000D77A85DF4F74B1DE26CF81F5740E601F95 +:107880008F1934F5F13B30E90C6D27DACFB871511F +:1078900011C6993CA2C48A7A33BF16223EAD934EDC +:1078A000BF8BEE8DF557EBF83BBF5761789EDF1B22 +:1078B000CBF06CDF911103F960E9CE8C9E48896FA3 +:1078C0001A7A6F04E0D77ED9C2F36DFF289CF58E3B +:1078D000D0F64B770EEC897A6709DF2248DE3CFB55 +:1078E000FC7FB883CF95B3714D5F7D02FEF657C91B +:1078F000DF48B239F118F85FEF5E1ED0CB055DCEE0 +:10790000263D2302E75F8D6E57047F42FE6CB8B4BC +:10791000E70E7F21652CF617C673139CC31C19B99B +:10792000C787707F477E46FDBDFC589207FAEFB9C6 +:10793000ED8FA463FCAD4DF33F798CFA3FEFB7F8C0 +:107940006C744E9D174D175E051F7E2A92ED7B7756 +:107950002B342F9CC39B7B713E47B1862FC3392CA0 +:10796000FCBCCF7314B77519F1ADAA171FED057ADA +:107970007C8D603082CA5F5B1BC17CED359BE7C8A4 +:1079800032F4F7B8ECEFE9FBEF3CB60BE97DD50537 +:107990007752FA65461CE3A1FC814503D09ECE795F +:1079A000914CFD3DF78A1280BF6AD0BA7D2B926957 +:1079B0007E83371CB5F4A234FF29A51EE9C03E37EB +:1079C0001E82FDF96F196E6E3F645B9A9A826DD9C3 +:1079D000CBFFC9757CFE9BE582DC759F8FED253A58 +:1079E000E583014AD3998D34D7B0D48F0A348663A6 +:1079F00023AF6767F3B4F76F155807491E98778967 +:107A0000DDC3E791DFB711783EAFE57858BF2BF6BD +:107A10003D0A7A3BAF257A703EBD4CFAFCD5A87F73 +:107A2000C4CAEB7CE5A9F7A261DF89213DD909BF72 +:107A3000487EDB78D4AFEEE316F087F579E2FA09F9 +:107A4000804FCD8E9D1BB99F2A8707FA6EC5CE4BFE +:107A50000753202FDE203C99A0C71D32FFAB42AF59 +:107A600047A5A5566CFC52E65B8A395F4CDA27FCC9 +:107A7000FEA24CCA498FE8E7A068CD637EC924EE18 +:107A8000EEC4D7AFA818E5EBD37CC9B06F1BE727CE +:107A90009D7BA9FDB065ECB27DCBD85B53192EDF81 +:107AA000F3DCB3EBE797D1DF2376E173523F30DFAE +:107AB000C09EBEC12ECFEBCDC467402FC6794DE32B +:107AC000E6F593EDBDE0AF29AA326807C123E59141 +:107AD000309637BEEFF8B36256F1F96DC85BB5E189 +:107AE000922FF2D941ED5F88D2AEEE370C76327923 +:107AF000DE0BAB3B17F2C8E351DE6BFAB1BCD59697 +:107B00008A35D0397A1DE653A392FC9511247F451E +:107B1000C67DAF733410E52D42FBEF5B7F6C04CD67 +:107B2000330629F1EF68A486DE455A4897FC397D73 +:107B30005B13F8F34361923F470D61BE64AC33744D +:107B40009C03C40734E23B6FD039A3113F181739A7 +:107B5000C6CA787DDD527590CEE522390208DA1A60 +:107B60003B94F3DE28826361A42AB42EF4472325D4 +:107B7000BCCDC73AC7274498EA1525C4DAB18FBFF0 +:107B8000EFFA551D4F6AB83CBFD47083BFBA137467 +:107B9000BF7DC8FAE57A6F770E63BE3A56F97EEB81 +:107BA0002EB215DF093C8F8BCCE773735CE4942312 +:107BB0009AE075D4E17BE87A43D7251CDF4F8EFA33 +:107BC00089227C16ECC7CFED6C776BB6B53EF75BC0 +:107BD000826BF3A25C0FEC472FD3BE70809F4EB533 +:107BE000B39CDB0CD992EA37F770715CCB6BBADFD0 +:107BF000DC375B6FEF147CBE34CFEEC57EF45E6184 +:107C00003410EC48F5D26FD26C5BF216CEEBE6E5A1 +:107C1000291E9A8150C1EF69CB7CE497FCBC5E09B8 +:107C2000DC0A7F81EF73BB40FD75B1FED5E9945F3F +:107C3000F78B0C9ECF47A48FD762BC8A70E65BEBB4 +:107C400062BDC971049F97FFA1F279B22E9FF29194 +:107C5000CCD7D96EB36E8A37197EAD041D6FEB3663 +:107C6000CAF25EB093A23C4DB6FFC426EBDFA2D7AA +:107C70004BD0F1FBB14EA7B4FF993F689323ACA062 +:107C8000FF77FB95BEC6FB467893E1177AAC3C9331 +:107C90006D98B754DE90C6F4A4DBD366E9FCDCE84B +:107CA000170D1CC3214FCB9FD9F3373B41DF332A3C +:107CB0009C47211F7E54B1220A7AFD0C4D0D842170 +:107CC000BE6A7A91B743AE4BC7B85E396EB9A11F91 +:107CD00006CA00DFBD6D0E712FCBFF8121C1FA9660 +:107CE00081E745FABEAD6E1AF360B07E5D6927FE8E +:107CF0003318E5723F57456ABF077DD5EEBAE1C13B +:107D000060BDFB54F94379BCEFF471CFD5791F3CCA +:107D10009E09396F02A7C6B81DFA11F049FDF6D5C4 +:107D2000CF73DAEF3E0BF0DAE494FA92B5EDE38527 +:107D300094AF9F3580CFF709531D5ED8F5DA77846D +:107D4000F961AFAD9F15EEC5BAEAF744F9615798EE +:107D5000A7EF1BD2BBF8BB6FBB8DE9ADCAEE7F6648 +:107D60000BB5ABDADB9FE989E895ED96BE57236446 +:107D700079B4376DE55094F764FA79CDE68EE1F287 +:107D80003755C1E5E181AC5882779B533B8575132C +:107D9000BDB2FDBCCA2EBF1FD1E912FA25FBFF966A +:107DA0004471BF42CF6B3F8F677D4F58BDC9F39180 +:107DB000BF7D20AF47B3CB7D216AA47E78C425E781 +:107DC00075A4399EF785418F478AB7DC939580EF7C +:107DD00024AFD2FCFEB24C0DC01F6ED09F32F5F224 +:107DE000DB5751BB4F5F55D96F33E7D78B0FE3FBA1 +:107DF0009C15D51339ADBC6B329FCBF51FA7EEA2F6 +:107E0000F284A9A7D8BF6BE07F4E95D99F9A98E9D5 +:107E1000553381DF5CFFF68354FFE1D9271600AFAD +:107E2000C333354726ECDBF6D697FF4CF36D5DFE8A +:107E300027D6A336446B11F87E71F7D35CBF66C5B5 +:107E4000FF2C807E50639574639CDBB53A3DBF91F7 +:107E5000A9C5A2FFAA15BF633D2222B745F2D7BB31 +:107E6000BE1F3F3AD3BCF96585DA2D0E6FAEE154E3 +:107E7000F5E7E1FC3BAB04A2950C862BEB75E75CC8 +:107E80008168E047B348B972F1D610BF315092A86B +:107E9000DB8BA8DDE226558F57F4DB41A7A1F51750 +:107EA000D377AEF73DBF578A26F93D76D7FDD73059 +:107EB000FE4500FEAE33CF646E023D9CDFF9745682 +:107EC000B09F3634BD72BE72FDE7F47D738EBED8AE +:107ED000406FDBC24CF6850BCF24EBF426E9E9C2F8 +:107EE00033D9ECE74ED4F7D905C5670947BB5F081E +:107EF0008E67109EA6E11C97E36D1A0EB9FB619D7B +:107F00002F2E8E6F1A0EBE67F041E168CA63BB4127 +:107F10004E531EF464837F8AE2A62CFEEE6FCA42A3 +:107F2000FB972DD20E63CCA7F2B9148E7BA2B5F0CD +:107F3000FEAE7C6EE026E48D71EA9D92EFD43B2587 +:107F40007F095DB79629EDE8A44FE61EA7B3A43ECE +:107F500096F4825CE49365DE29F30B3794D8E16FE5 +:107F6000AFB7C9BC6B7D89FD18E6F73569B5C44F5D +:107F70007374BFC5027FA9DD0BFBFEFAE5E11C3F70 +:107F800031DB3ECF4B69F67ABB695C030FFDFDE642 +:107F9000EF8BF4F9F40D890BEAA5B6ED0BC339F6B6 +:107FA000A4E8328E6049A6B4E33EFB6C477C91AAFC +:107FB000EBDBC26DD0A15BEA1B8CD78FED065EEFC9 +:107FC00048A1F92FD6E3A55EB648B8FA9E957CE3A2 +:107FD000E57C2D05E7D505C01DE75C2CE57321EF99 +:107FE00049BC1979035FA1F05DF1F18214D8959F26 +:107FF000C894F6C7507C2C8F1ADE13E5065CCFD4EC +:108000001DCA00DC8D759DA8F37AE968EBB4BFAF9B +:10801000CF77688C8F7C47307DD76F1D7288242086 +:10802000716EABD58325D45BFDF743BFA8DFAA36BD +:10803000F904973B80977391FBDF41BD051B620BF1 +:10804000A00F18ED17AE2FF29607CD7BE056335EEA +:10805000063599F3837799F35B71060DFBE7DBE552 +:1080600007CCF92187CCF9931FDC7133B64F85EA31 +:10807000BB5F85BEF3E7F187704E9F7AF99568E0A4 +:108080006BF15FCB0F428F0B8D67213C2AD0737C45 +:108090005B14A6972BE25ABAE14346DC06766230BF +:1080A000DD540ADF416BDA95F5CF8AA69BBD4467A4 +:1080B00055CBDECF907AB3EC7764D35A3BE4CED085 +:1080C00071BBE33B22D2EBC63E2A1921CBAE5E3612 +:1080D0004E7C8AFED6BC371EF458F22B85E59B9267 +:1080E00097B25F07DD1CDD3EFB464E6F9EC0F03051 +:1080F000EC920B9B954014E55D2344877F1FF18B29 +:10810000A50D21F19F6B42E282D699CB17EEDAF7EB +:10811000FF104750E17882E32EAE8C67F41F805E3B +:1081200059794AB07DAAF2A96FC2CCE5725DF3F528 +:108130007518E7ADF05DCBF17B57CBAAE238FEA313 +:1081400073E9A84B3B8573CB3877AF5EB75195F297 +:10815000BCB784FDC891768E8BAC76884004CDEB9D +:108160005094DDEBA2EF97D647B1BCB280E45CE857 +:108170008B940A27C74D7A62D0EEC4BB2ACB65D553 +:10818000F1121ED5BF51FCB01D57C3A88BFC933212 +:10819000BF4804D8BE0B3AF206AD03F80BCE8B46AF +:1081A000A95F565903FB009F8E7368ABB95E15AD8E +:1081B000F3A338C87BE6EF35A28DEBD7EEFA262C79 +:1081C000F87B903D9AF55E43FF5675F94AFD653898 +:1081D000CB4F74208483BE6CBADCBEEE1E92236843 +:1081E0007D2B0D7BF85A29DFDDB2519E63249F67FA +:1081F000014EEBD6927C86EFA46F20CE442C0AF77A +:108200004BF95EEA0BEB6667B15CF4F23F5E0A4045 +:108210001F697B4861BBD2BA7CD9EFBAFBFA7339CC +:10822000F8A7C2E384B11CB66E8A51DE87F5914F80 +:1082300030C564C8F9FAF71E6EFEDE4BF566C13E26 +:10824000221E74B27DC490FB0DB9BE2E56CBC91A46 +:10825000D6B9FE75B16D51F0BB898AF8EF25B76CC0 +:10826000D6CFE3365A3FFC2AC795E283F08F19F543 +:108270004666C97365F858EF16BD1EFB5FCA2D53DD +:10828000EEBD8EE655FEB0C50D7BA18107E1F5661A +:10829000010EC7D73A0B4077C3C74A7BD9917CC937 +:1082A000E723860A8E371AABF73B36CB624A93C276 +:1082B000891EA99FE345D21E1F35B498ED9624135D +:1082C000CCEB2A6E65B2DE4FB9BDF8F7A3BB984F71 +:1082D000075D144AF9FBF86DCA26392F2FC7270E00 +:1082E0007FC0C9F6CEE3FA3964E081E86818CB0FA5 +:1082F0003A5F8B0DA19BB5A0079C87A00725986EC0 +:10830000CC74718B22E12BEE93F2F7BA589937E8CF +:1083100082F43FF1BFA09B22C1F0EF4E0F34D6DBB9 +:108320009D1E4874B00874D0512F840E84D53FEC44 +:10833000DBFC42A52362872B848214ABF021CE178D +:108340006724C3EB1EAB1FB178BDAD122F7DAC927D +:10835000EEE8B4F18517707D2FE27D4B1E5C28BCE2 +:1083600054BF2445B07DAD1FC9553171DC4E204549 +:10837000588E0ABB13A5685F1223FB2FE92938FE2C +:108380008EFAF35AE274E6361CFE5EC17205DA47D5 +:1083900017707B9F45B6F75A29ED9B21F598B69546 +:1083A000611CBF5C72779F2CD0C9C4B1663A39A2F8 +:1083B000D39591DE94EDD68D759E24F083D286FE02 +:1083C0007CDED43B8BAB77029FCF47B0FC59B2EA3F +:1083D000C79386617E2FC47B80C23393B7B33FA817 +:1083E000B461F64F3E84BEB4D5C9DF2BB2B5F559A2 +:1083F00090FF15F7DC9DF4A174C6017B12B5D79AE6 +:10840000A69C7F95D2C9BEEDEF409E983C5DE5FAF3 +:108410009385B43F8B0639CE24DFE7D624EA6FD2AA +:108420002885C3698E3A5DA9B7C10FA4E3F7A92CCB +:1084300045977FE43D8192557DB2D273E13F21C9DA +:10844000B80B39FD53A3FE186503E4A5BEE3E4FEB3 +:1084500033EAA31FF47B3A4BCA55BFD5E162E40966 +:10846000AE5CBF7C75D8D18C68A4B64036A5E9FD5A +:10847000C7BE84754E4C17E3D703EE77AA6213CFBD +:10848000B7AD84F94254961BF4AB9142CDFAE3D6D2 +:10849000FECC278F8E693B7A37E58F6E1E24ED8CDC +:1084A000BA7D61BE4BB07C70748CE4776D9B239871 +:1084B000FE8FB85AA3E2A43D8EED0D653A497CB615 +:1084C000ACFE7EF8B9CB22ED47717ECC7F681AC72F +:1084D0002794AD530361B807B0C66C6FA88AD4DE89 +:1084E000C67E08B51B84DA074033A0A3F2350AD351 +:1084F00061DF7A8F3D99F99CE2C2FACA2303FD70CD +:108500000E947B9C1CC77C85FDE06B82FB70D8B908 +:10851000050789B5676B9F004E258D25ACEF46E4B6 +:108520006ACCBFFAAA0417EC179DFE26C25E0BBEEA +:10853000646D4DC6BEFC55969BF13031CE9515C984 +:1085400074EDE4FB11476DAE2CCCEFE84AA705E7CC +:10855000EDC41592BE69DF39708FE11EAB08073F8D +:10856000D89A25FB9DB3DC5ABC91F2BD1DC21A15E9 +:1085700007FACA67FA5ED85FFB2DE675EA17620450 +:10858000E489B2356BE5BC74FA10D696C2781AE766 +:10859000D4E6B402D8013AE4DBFE63DB01C70EBACD +:1085A00098AE303DD07A0EC18E9CDEBFF432CAE95F +:1085B000FB3ED0CBC4B1817E881B2F52AB38BEB6F8 +:1085C0003D4978E0776C176D2C8FB4933C02BE6701 +:1085D000F019839F105D781D899DF8DE5247532264 +:1085E0001EBEB5CEC1E9B3752E6125786FAB4BE2E7 +:1085F000FC0B756E4E9BEA72F8FB8B751ECEEFA8D6 +:108600001BC1F997EBBC9CDF553781D357EB8AF937 +:10861000BBC1AF083ECC970CBE63F02783BE0C3EB7 +:10862000154A577309CCB81741ED991F1A7C10EB06 +:10863000B01474F22703CFE94AB12F09FC50B4CE2D +:1086400006FF2852CF3DFF0AC1B9BD2292ED22EDAF +:1086500042F2C1F648079F07A976B10BF689FADB0B +:10866000BC47EF0E3A876FAD508435888E7FBCC40F +:1086700029AC41743C6F59AC293F67D9FB6FF4A416 +:10868000FEDF8DD172B3691E477E79E2F13FD1F7EB +:10869000DFFCF24C26F04EF3D8FC08C6BD2B5C9FE5 +:1086A00047AB9CD75D769697FA864B7DAB6FB8D477 +:1086B000B7F0E3088ACF3DA2E3A3242DF69DA7B12E +:1086C0006FECAE9B47C04EB452DE4BFA04F8A3F2F7 +:1086D000BFE8F82B5D16C6702D6DD0F76B70DC36D9 +:1086E000C1F558B260F94EF10A01BFD7B15FD803A6 +:1086F000242B88638AC3AF407622E56B0EEC98ABDF +:108700007FF711E47665D92196B3354724C77F08F2 +:108710009FED5C707FCAB2835C4FB4F636C56F467E +:108720000CF5DAC13740E3C05F69CE7E81FD2E1AB9 +:1087300015BE7F54AE7F2F5FAD98E2A26764ABF2A7 +:10874000DE459695D3F359423F471AF9BC32E89675 +:10875000F808C7619637E6DB1704F1E752FD7B594D +:108760008EC514A7797F969DFB398FCD49FDDE9B81 +:10877000936E9FCFFCCFCDF7058CFAA53905AB6082 +:108780004F2E5D83A8A6CEF625D9567D5E2EA97FF5 +:1087900039E85C8BE2F8A22ECF07439E39855F470C +:1087A000F2FC59EFAA7CE1B917E08FACFC73189F7B +:1087B00053958375FB4AAE7FF8349683BC91CA709B +:1087C000C8E112FF85CFFD351A715DB53BA4BD9799 +:1087D000D2A3486BEEAA60FB5E8D87F6491CF8AD0C +:1087E000D9EFFFFA0B7FE6FB9D84B0143D6E98E352 +:1087F000D46A767CCAF16BB0C7F986727F1C5F1DA4 +:10880000DABE56F99AF557422CC3A768CF97893C30 +:108810008F9D9712C1E76AF7AC4CEC2A8E28B41FE3 +:1088200023CEC1B0FFD58A359FC3CF597BD7849360 +:1088300092DE65FFA1ED1ECA8E4A38315020C6EE89 +:108840002AB6935805C79F2CD5ED38EDFE4CF6633C +:10885000772777D7AEA7462492B55BDD3188B3BEC4 +:1088600028C484AEF0F449B6946BCFD33E823FFB6C +:10887000E23695E5CA8BDBA2783FD46C7BF020E230 +:10888000046B9E52D8ED582D5A38CEAF66872A1CFD +:10889000C1E71DEC47F1DDCF73F173514B405F8BA6 +:1088A0009A14EF669A4FBBC31DD323683EAF80BEB8 +:1088B00088341787350D47FFC6FC9F077F0B92371B +:1088C00017353FC8F18D54EF02CB37BF8DE0383CF0 +:1088D0003AC9DEC13CCF6E18C2FEF5454DDB6B5880 +:1088E0003ED816E182E9E98CCD7C0FE4803EDE8142 +:1088F0006C298F9CD5EDD1675F50591FC23CB12FB9 +:10890000CFE871B846BB37F5766F664BF9A7265BA3 +:10891000EE4FA3FEA2A6A3D1FDA8FEC95DEF73FA98 +:10892000BEBE6F1645B6F03DCF933B22F89EE0C920 +:108930001DFF39FE351AEF7CD3980425689F9DC82A +:10894000B6C97DBA41C62FF32517D6139A783D676D +:10895000B7A528AC2F03DEA4B79FDDF112DF4336A5 +:10896000E4EB1F1C2F384BB186DCA3183D08728D39 +:10897000A355BFD7D1A6DB63FE6FFAAFD1BF27598E +:108980008AF571E43D0D61C46FB864BD2235B72727 +:10899000F6DDDCC1EE99B8972DDE927197A2B7FB98 +:1089A00011E87F73DF8D67BBCB529BBB27F25F1C47 +:1089B000268595E0337788CE57925A87C1BE7B349F +:1089C0004DCA15863FAD6AB522BC04BF5E44673E02 +:1089D000E4FDAAD06007C949677C3D5661F1DA71B0 +:1089E0003E46D9992EEAB73B37C1BE75C42E7CEC02 +:1089F0007F7BD129FD27E9D20FF218F617A5557113 +:108A000081AC78D8F174BAA99A4AE541F453B529F2 +:108A1000900539EA9C5DDA2B510EFDA9AA40D6AB30 +:108A2000D7E914FDA0DFA369AE0B2CF7EE8C12D0B2 +:108A30003F2CAF4449BBC8D3CE4D6141E776BF1C44 +:108A40008B1177C7FE4ADF66393FCC0BF2FC227BE5 +:108A50006316E45D63DC45D18D3CDE397DBC45E1C8 +:108A60008DD29FA3C711A23E8F6F13EC776A7B262E +:108A70008CE5E633C92D2F63FC33CFF4E7B887A329 +:108A800069FE05BBB8DCC9F1E795CF860530DFD3B9 +:108A9000CF44B15DEBB44DCA63A7A312591E3B147A +:108AA000F5F05CF6633D15A6C02E745A11F62494B9 +:108AB0006FEEC1F24065DD32F6D754127B811C4B5C +:108AC000E904C87FA737F7677BD1E93755BE5C411A +:108AD000DF57E3BB261AE7FE8CF58008B6239E79A4 +:108AE000F66FFD83FD3B465AF994D93E66D083511B +:108AF0005E9423F960518ED4536EC871715A1DD1A2 +:108B0000F4703AAF53F207C203EB81B41F1361EF65 +:108B10003FD2B43B5189049C0359FF09B86F95FAC1 +:108B2000D6996D36F65355BE12E5653BD4DD57F147 +:108B30007DC94A55CAE3951679DF50F9E556B6FF67 +:108B4000D43FE32C003C08DEACDFB66D56F571E493 +:108B5000B8A7B7F4917E8D809E7F7910FB3526C62D +:108B600089795359CEDA9007B85E7A2A82E3FE6992 +:108B70001C2FE2342A7FF67309CF9805AC27D0C1A9 +:108B8000CDFCB94AE7CFD5775F1383FB10E25D9543 +:108B9000EF795CB27A7A82FF86C2EBD11C9D3FBF2F +:108BA000FC38F3832ADA37880F5BACFB13173FAB33 +:108BB000B05CB978D5358F30DF7DC726702FE25C89 +:108BC000D383D1C1F8A8CF91FCB0B3BD87EB2FA65A +:108BD000FAB2FD5BD13C9F2D360FE6138AC7EFDD5D +:108BE000FE59F507B5AF6C22F922EFCAF55F122DD9 +:108BF0003FFD33F8CB3627FB5109FF7C3FEAACAD94 +:108C00006901D67FF67927F39DB3B172DF9FA4F394 +:108C1000D4978DF9DCF46BB6CBFC619AC039B4D033 +:108C20006FEED798D7EA1C9BA4B7784F0CFC44D5BD +:108C3000840FF447F8F911B77FD7C6ED43D7B34097 +:108C40006FD7B14F9F8F60BA39DB4BE2E5EC0BD9A0 +:108C50007C9E1D8D95F44EF34D85DE743656A6B878 +:108C600099047AA874497A383BA689ED026795ED94 +:108C70009C1EB5C97695CB747F3BD15F12E807B4D3 +:108C800009BBAA634D0BE419F0F9E1059C06704F8E +:108C90003BD48E0E3AC5F9D7AAEF33E31D05F6EBA8 +:108CA000B09FA789EFC76BBA3C59B5ED4A7F25F055 +:108CB00054B54D617FDA7F19FDD0AC130C3F00D164 +:108CC000E5629FC2EF222C6EB86D11FBD396ACBD4E +:108CD00015746FAC63B17E6FFCA8A2F27C8E3A690A +:108CE000FFE45E399E01DFDFE7281DEF75B88CF3E6 +:108CF0008BF6F03B396E4947946DA4FEAA1A943561 +:108D00003C4E9AA1E7CAF5197022B0D861E73BAA98 +:108D1000DFD3EE6EFDC63CBB9BCF319DCF1F4D9385 +:108D2000F793DBDE96F7CC2F7D3D2426EE5BE44106 +:108D3000BE6160F487B863D020F5F322F81CF635E5 +:108D4000ECEB34CFAC0D66FF4ECE53E6FC806DE607 +:108D50007CEE0E733EAFD99CF7BC6ECEFF09E30EDE +:108D6000EB8413F46FC43542FF460AFDDB1D26F584 +:108D70006FE4A17F2385FE8DEFD0BF9187FE8D3CF0 +:108D8000F46FE4A17F2385FE8DEFEEFE124E55BAFF +:108D9000BD1478E0B8BADD4E233E81F7CBC5D98942 +:108DA000CC478555EAA51717E5B2FCD8616F9AE262 +:108DB000607B93118F9518AD85F7471C80D2B22A3E +:108DC000398DDBB11DBAF6556987AE2A7046C2EE01 +:108DD000D1BAF2E42A883DA7A3B418D4BF686BDBEC +:108DE00002F8562F3BC07EFFD6E5EE77AF93F863CF +:108DF000FB8B115F5582730F7C9BF4251977EE7105 +:108E000004DB5343FD44624D501EF2D33A733ED40B +:108E10002F04BEE635EDAB46C6C76F6C6DC9E0FBEF +:108E20009F3EE3E0FB699FEAF63B31CBC1F298211C +:108E3000CF23CE1B70597A9FB209E795A77F1CC339 +:108E4000B9FD50A6E97E61685A767908CBF31DF921 +:108E5000358A05E3944F5FBE8FF56ACDCBE7D2ED3F +:108E6000FADCB2D75B4CF3EEEF0F37D1D1C0AD7166 +:108E7000217ECC5EA6FA8377A587F8310798CAA72A +:108E8000AD1962BE8F5F7C8DA9BCAFBD236ECFA133 +:108E9000FBB9E4FC5CB2CEA5C8025E6F68BD54C5E8 +:108EA000F327F86FC5DB524E2DA773C61BAFBF2B40 +:108EB00052007F9D7732E057D1648B859DAD4C3F4A +:108EC00087C432F3B95C61153E575C27DD55B88421 +:108ED0003796DA7F696D4C653AFAE547A92A8168C9 +:108EE000D180963CE8AF8BDE7C7238E8AA5ADD98D8 +:108EF000EAA2F23B14FF165C203F13B73D712495A4 +:108F000027A95A497FC273AA2D70FF1CF0D1ED1911 +:108F100002EFA47CBAE6A5688E1FD4E92FD5E60A35 +:108F2000071D6C6C54594F81FD4C8DEBA4938D8DB6 +:108F3000F1E1D06B2AC6283EC8C7065C0CFA08854A +:108F400007C9EFEFBA69BD970EC9F7948C752E75F6 +:108F5000C9FAA241B637DE0730D67B5CD7472B373C +:108F6000BE91753B7D3FD77F5F9E1B7EDCBA5DBCAB +:108F7000EEC5966D5B92297DC7A1DD85752D7D7B44 +:108F80005CF4481AE7CB6D32AEFDB3754F3EE1237A +:108F90007E7A77E39376E80F9556BF9DDFCD7966AD +:108FA000A31DF10ED76FDDC8DF176C2D617B8071BB +:108FB000CFEE941197ADC3A362ACB2C145EB3CDEDA +:108FC0005FCA8515E1329EA6481DF54602D6B55505 +:108FD000C9C7BAA6176FB7E3FD8187F57AA1FBA6CB +:108FE000FDF0B4A21EB07B35291CC7D4DD3E99111B +:108FF000E8CFFB64DAE5344EA75F1EC87ADE8782CD +:10900000B42F9C23B921FAF56155DAF59A55F94E3A +:10901000983D90300DF2C25EF96E45359D43230AAE +:10902000A0B70B7135A5C5A354139DD7164698F666 +:10903000C12C11B4AFA8BF9B452F537EFAC40C536B +:10904000FD99D30786F89D0B3ACB997F5D6D7A8F9A +:10905000A6FA2E9F5B61BBC758F3774AEF623ABB13 +:10906000D1D4BE5A4C35BD47B3E8A9F718CE4465F4 +:1090700076C4E154E8F758666947F5EFADFC9D16F4 +:1090800062DAAF7D333C7F92E7A58DFD09863D7D99 +:10909000167ECFE8EABC0CEF881745BC30EC1D9A71 +:1090A000591E69613D55483C54EBF6A8EA1C698F8E +:1090B000AAF6B5D8118F4DF0B7A610486A1A15B6A2 +:1090C00037527D474A9CCCDF85EF3BCCF752D0DF4F +:1090D00065941F524BB0BF42CB6B68DD38176A6096 +:1090E00047623BD884936C0733C6D1FB37E834F42E +:1090F0007D80D0FE060C7033FFAEDCBAFD602F829F +:10910000CFB4E2D87CC49D54354DB195E45E496F2F +:1091100006FFBF546161BF7EFBE1034C6FED155646 +:109120008F8C4BFF76B8D478A5DD35940E17D0BA66 +:10913000E07F5EB043F1F815590FF0E905FA0C81B4 +:109140004F4A177033E0D501BF90727E3F6E28E220 +:1091500026E47B0A57C025149EFA380B34C17227C7 +:10916000CDCBCFF30AE9578C08DD8FB7DBD9FFB041 +:1091700041112EE5BBE131F5B2B4E3F4CD90EB6FD4 +:10918000DBA97820BFDF7CD9CADF3BE8A758C6D966 +:109190004F9F68DEAF1DF4542CF7CF8CCB89DCEEEB +:1091A000DF4557DF454F86FF26347EDDB847E61999 +:1091B000A0DFB71A26867DF34FC4E11BF24177E7A3 +:1091C0004CC739E4D2F11099DEE5F9BC342A9DE3AD +:1091D000CC35DDBE68F0694D6F678C5B42E5EE789B +:1091E000D07B6F7E67715543466AF0FB37DA4A1BC6 +:1091F000DB815397C7735AE27425E27C29592EDF2D +:109200006939764FCF44F8298EADB4254CA4AE8F82 +:10921000DD3934550C42BE88D34FD786CD0AB6CF40 +:109220001BE92D03E4F9619CEFE72D87A367613FFC +:10923000AEDC198D90A1C52BDF1FEEA273BED9A2A3 +:109240002D1AC0FEE08D7CCE0BD7C63CD8E70C397A +:10925000A37265514FC80355FF38F004E4016DB99E +:109260002D1172EAE90F5481D01A3AE758BE38E559 +:1092700094F47D6A7304DFAB3CA5082FFC518BD4BA +:109280007D792ED379DB7C33C68F70D2B8C330AEF4 +:109290007F4B12C6F5F8B230AEB63C33A62BBB8B73 +:1092A00091D6AE97F2DF16C3CEACDBA321F7230F26 +:1092B000B95F644BB91F79C8FD4821F7E37B0DFC0A +:1092C0000EF01BD7B7E5436FF58D15394BF81C8EA3 +:1092D000CC815C7FBB12EE013FBA5DF1F4E478848F +:1092E0000F62E5F91B8257231DDD46B25910DD5E82 +:1092F00077D92182E3EBC68858537E9C23D954BF8B +:10930000C895662ABF3EA9BFA9FC0677BE297F5330 +:10931000CE4853FD499E31A6FC8F46DC60AA3FC56E +:109320003BC5949F3661B6A9FE8CE21253F9CC5925 +:109330008B4CE5B3B5DB4CF95B2BEE34D5FFF192EA +:10934000E5A672AF7059710E36431F23B8EF853E04 +:1093500046E9ED6F674606E375D4384B97EF0C3559 +:109360000D90FA5674AEF739D025EE09810EFBE860 +:10937000F780F6E29C1906BF654091FA704B32E81F +:1093800026B45E68F9A888FD97F09465FFE76E9FA4 +:1093900061253E31EAAAFD4332287FFBC0E619561B +:1093A000E22FA3AED9FF523AE57FF1DC37B27CF071 +:1093B000FE4B285772F7CBFC34C122C8AF06CE9BB8 +:1093C000E1A3758CBA2E7D8D47DA53BA8C53355292 +:1093D000C001719D8003D200D127D2FD449F485F18 +:1093E00027FA2CB7097190E813E921D24BF1FDF768 +:1093F000A497223D4C7A29D277482F45DA427A2920 +:10940000D23FD4CDE2F4833A8DDBFDB1AE82D38F6F +:10941000EA96F0F74FEA9671FA973A1F7FFF648059 +:10942000617F08B09DC6F08BD5C01F097BDE2EDBA7 +:10943000B960BFB1E295E7ABE1C7AC5F225A23B098 +:109440004F5BADB1271C9DFEC9EEF9AD559C08924E +:10945000CB9CE1DECF06F0F8BD5DCCB7F5EF47C49D +:10946000B43E0584A74FD3B5B3E007330ACA56C646 +:1094700010FFB8EEEB2536D0CB8796AEEFA3EFD535 +:10948000F9DBA703BD6DE8F75AFD5DA66B1D32AE93 +:10949000F05A6B6B3DDBDBBF146EC403ED33ECEFB6 +:1094A000F758F95EB1F285E0FCE804C1F9FA2F5BE8 +:1094B000380EF15A972789CF1D3D6FC40575F8FD09 +:1094C000F11314EF63F8E18D789FC22F5AC7413E24 +:1094D000181D69778785C40DC0DFBE2FEA8FC6BC13 +:1094E000F87D27C3BFFFD4972280F7F20C3FFEB56B +:1094F0008E9634D81546DFE1F004C73319FE7AE5BD +:109500008B1615E78911AF648C63CC3BCA4AFD15F5 +:1095100074C6235DEB6ACA475C467D7524F7D79312 +:10952000BEE3DD49AAE755B95D533EECC7A3AB22C4 +:109530003D42E98C13E8A9AF9BEAF13A0BBFD03862 +:109540004E62B41E27817E1CB29CDF011C9D104818 +:10955000C6FB9FA397D83DB0833E8EB8B382CEB8EA +:1095600005D48F08DAC79827FAEDF715CD17F2BCA6 +:10957000D7CBF09DE692F429DC7A5E3FAF85632C71 +:10958000DBBB543D5F1CE6FA6B04D1CFAD19DA901A +:1095900081D4DF1F948CCC7CD617327A60DF4F09E0 +:1095A0007947B00BFA1931F0FF847EBC12EFBD058C +:1095B000DBE142E9C8C08F414F06DEBBA32B830E1F +:1095C00082E2D018EF1D71657A7FA1F4D61D9D1936 +:1095D000F475AD43D201F08CF82083AE942F9AF845 +:1095E0001EEBE82A079F7F065D85D2C5957425E9A5 +:1095F000B4FE270EEEEF4ABAEAA407C0E587D355BA +:109600008B8AF3F89FA5A7796D623CEEFF975C7695 +:109610001F44DAAB9FB6177CA64C8C190F12132E81 +:109620007510EC62A1F532BAA9174A7FA1ED6EBCA4 +:10963000A25D466E70BB71FA5919DAAE12ED7A046A +:10964000B71BC271116FE9F708DE721A712D9E996E +:1096500090530EB96DF22D2FE18DCC27BA19A7F3D7 +:10966000F34362099FBF24EEFA404F853A698DCBE0 +:109670005DC8FA426164D7710537EAEDC77F5DDCEA +:1096800080F98C4F30CBE337EAF2FCF5A291FB0F67 +:109690007D47E1C6DCEB59CE0F7D4761F3403DFECF +:1096A000204DA481DF170A8F9C9FFE0E46A1BECFDE +:1096B0005374BAC970AB62541CEE9B6A561C32AF2D +:1096C000E31D8C3C8CEBE3FC0DC2CFE94D22C0FDC9 +:1096D0004CA20309F91F096193EF5FC8FBBA35AAD1 +:1096E000F6DF90578D7BBA4F3BB557B0CF0F444C48 +:1096F0009E83774AC60D19D70FEDF617BA59CEDB00 +:10970000EFC860B913FBD216D7C927DEA473BA5FBE +:10971000A6BC378A14F746FBD179FA3B3AC791BF0A +:109720003167B940BBF16E73BC93D1FE26D7386167 +:109730008DEFFE9CBC296F776FD8CDDE8ACD2E04CD +:109740007EDF8ABDAA10EB7D2BB6A745A661764EBB +:1097500007BDD2AF2BB9D8A0FBCEF1C6F378DDC1DF +:10976000D9806B283C0D38FF00B81EEB0AAE7B0792 +:10977000089637AA23245FAD8E907CD580737558E8 +:10978000C77DDE9EC1F127550E09AFF9CBAE11564C +:1097900012F5172C1BC9F99375C207B89FC69260C2 +:1097A000100FB1F709EB58CE1BEFDC9D7DF8BDE83B +:1097B000249AE72A87F63F98DFB98240164984E267 +:1097C000E4867ABE8F7FFE05D5037DAA4A75AFF188 +:1097D000C0CEFA962AEF717D7D2015FE58F154D740 +:1097E000F1E8550E095F439F1CD2AF98F7ADB15F0A +:1097F00085FEBE80215FF50E93F1DCC63DF7EEE4F9 +:10980000ADE1E192AFF50E93FCD8C0EB06BB7EEE66 +:10981000533FC3898FA6FC3A9CF5AB98586F4C2EEA +:10982000EC8385C2A49F187695F604F97ECAB5220A +:10983000EB9151942F3C64137E2A6F074340799239 +:10984000F4B3B61FBAA482EF174529FC3E86716FA8 +:10985000292CC922DC417CC2E90E37BD4B1B911378 +:1098600067CA47797A99EAC78C483795C77A0798C3 +:10987000CAE3271498F23D8AAF36D5EF396BAC298D +:109880009FACDD68AA9F5231D59437F8588AFC24E2 +:10989000FA2CB9C5D4BEEFB25253FD345FA5A95C12 +:1098A000C53B9B3140ABB7252711CF81CA9F8CD5D3 +:1098B0004B43DEE3B508CBF0CE776BFE335ADECBFD +:1098C0009910B980DFAFC96CFC99799EEA446B2C82 +:1098D000A5D7BBCD7CB128C99C1F17B94F81DF71BB +:1098E0009CCBCC9F5396584DF91FE5EAFC344FE4CE +:1098F000B1DDE3BBF0AF0D30E13F144E440FFC7E11 +:10990000683B9DEF3ECCEBCD327E0F077E93E0753A +:10991000C06F120C07F84D82F3F09B04D787DF2449 +:10992000B81C7E93E0F22187CCF81FD662C6FF55A3 +:109930001F99F16FD06577781AD96AA60FA1299A75 +:10994000F22D78BAE694997E42F1731D895BB109D4 +:10995000C087E209B87F38BE5686E08BF0C3F73780 +:10996000DB7B47317E1ED7D7756D6020DF972E3A9F +:10997000A40ABC6F63ACF371FDDC3F6DD51A73892B +:10998000CFFCCE5D90043E769D907EDBF155164F68 +:1099900080BA7F20649CD929DA43A83F2BFE52AAC3 +:1099A0001D74D226DFCF7B0E7C79D895F1B23E12A2 +:1099B0004FF8BEF6CF54BE2775C4D2A8808FAF8EA5 +:1099C000D19E009F9997BB84D79B248AB72F405C78 +:1099D000D47F85A5223FB7AFBCC72D725BF9FE8946 +:1099E000C127E7A6C8B8A92DB9BA7FDD23E3A79E92 +:1099F000C995727794C7C571DE25B9F27E0DA98B22 +:109A0000A97307013E879DD980CF3A0BBFEBD98A56 +:109A10007BE4099DF7C8210F43FEECA3CB7FF51F24 +:109A20003B1C5847F67A613A7FFBFB1DA6F8E281A2 +:109A30005B5DA6FCA0A62453FDC1BBDCA6F2FC40E6 +:109A40008EA97CC8218F293FAC6584A9FE551F795A +:109A50004DF991AD134CF5AF39556CCAA788B6478F +:109A600001DFBE8AB4531CCD4D97FAB95B70DCE4BC +:109A7000DCBB63E57D5FDD7E61C8FB46DCB9A6D358 +:109A800075A81ED1D72EE5E8FA6421F54687AE1FEA +:109A90000AB33EA1E971E31DF7587CE6B871235E75 +:109AA000BC43EFD0F58A8E7B349DF1E2DEE078F1A5 +:109AB000B9615DBF1F7D5EC77BE8FCFBDAE57AEB31 +:109AC000EFB4F3BD1D635EA1F349C99674BBD9D150 +:109AD000F5BDAABFE54AFB466B66F125D0FD1336FE +:109AE0004F2BFF6D842BC6F3B4225EB7FE1776CFE3 +:109AF0000AF7778F3777B05CCF1C8B65DE945C8E6E +:109B00008B33FDDD84884192BEAD8375FB4AC878F6 +:109B1000736364DC9A88B1BB41BFDD8F27E1996430 +:109B2000170D7CFF4BBF67F1E3354DF7A1688EBD84 +:109B3000517F3FCE6F033D4C1C4BF2593EC9135B26 +:109B40007A3D144972CA13CBAC6C9F8A7BFE57379F +:109B5000FBFA75DE9FE94BFA10E803B20EF4A80792 +:109B6000F25429B70C92EB2B52BFEEB8E7C07E1827 +:109B700021F4F34370BC4F17F4C67468ACE3DF758F +:109B8000EFC1A0DB503819FAAFD0E33BFB19F3D299 +:109B9000E167EC07037EC6FD13F76DB6E24D917CDD +:109BA0008F6502E2E50CFC6DC993F6C6053A3C50A0 +:109BB0000FFCA8BB7A456A6E0CECF7EDC21DE3EA18 +:109BC000820E3BEAFF9BE062C0BFBBFB6DDDF1870D +:109BD00050BEF05DF7DDBAA3D37FF6DE5B109F9039 +:109BE000F14B3A5EFCFD2C1C17707794793F3F32A5 +:109BF00048F2899183F4FDE423FDD6CC2F04FC0FB9 +:109C0000F52B559D5FC8F3BC24AD98DFAFC6F98A2C +:109C1000FB5BF3374AF94788E2C4AB87C28F6FE337 +:109C2000FBCBD77A05DB6D4A1B153FDEF92AF175B0 +:109C3000AD0FB39FCFCD7207BF3BC8264D6A5746C5 +:109C4000EDF6A55DF9CEFAC248F9EE60E8FBEA0B45 +:109C500075BD192F6A60DF86FABDEE19A4FBB13C11 +:109C6000C2C3F29C1ED750A1D7E9A037BF7C6F0EAC +:109C70007A32F631A51C1F67C0CD0D3FD490CE3C83 +:109C8000C1373C07E77983B5CBF8C50EF81A7EAB30 +:109C90000EBFEC61BE27111A8F71CE7720BA2B3F11 +:109CA00098E11FEB6E1F74F8C7BEC3EFD61E69891B +:109CB000C6DFF169DF26DF67E9F45BFD65B8CB221B +:109CC000FD5331F03FB5EAFD898D795DDD0FD59605 +:109CD000EFE43894668BB67310ADEF2CF58F777B7D +:109CE000EF89DC9F88771126EA76A92BD7ADCBCDFB +:109CF000A314E98FF6A98CEFF609F25E3DF15181CC +:109D00007D67C44F4C118104A4861F4A5B3D92E1DC +:109D10006FF8A14A0223799E33EA17DAF0E468EB80 +:109D2000A3771585BB3BFD53AD7D645C54777EAA5C +:109D30006997F3B9BFE997AFE17E3E189426E5B67F +:109D400086FB6E039D0DD82A6C5867ABADEBBF4BFD +:109D500051A8F3AB12E89A3D82E2AD962BBC2F9648 +:109D60002AC288BF623E6FE42F35EAF92299BF7D8F +:109D7000A5CCB7EAEFA76DD1ED20582752AC077AF2 +:109D8000F936DD4E827520C53AF01D7C0D79F0352F +:109D9000E4C1D790075F430ABE86EFA5A2381576C7 +:109DA0005BF8D30A83F607FC6985417213FC69C12D +:109DB00079F8D382EBC39F165C0E7F5A7039FC6929 +:109DC000C179F8D382EBC39F169C873F2DB83EFC28 +:109DD00069C179F8D382EBC39F165C0E7F5A703944 +:109DE000FC69C179F8D382EBC39F165C3E6F996220 +:109DF000F2B7CDD3DF7F285B1FCFF45198511C9B66 +:109E000047F8FDEF887FFCC4960E3C372F02DD2E0D +:109E1000AD0EF7483C374E9078B70889E7B6D98C35 +:109E2000E7BBEC325F24E3B443E9077EAB429BF42B +:109E30005B2185DF0A29FC5648E1B72ACC947E2BAA +:109E4000A4F05BE13BFC5648E1B7420ABF1552F86B +:109E5000AD90C26F85147E2BB483DF0A29FC56F8BF +:109E60000EBF1552F8ADF0FD08CD03FE2B635E90DA +:109E7000F3FB99F452A243935EEA32E521E707D758 +:109E8000879C1F5C0E393FB81C727E701E727E70FC +:109E90007DC8F9C1F94983DCBCBF20EF07B783BC9B +:109EA0001F9C1FD4E87B03B6AB491B2EBC8EB43578 +:109EB0004A7942710931352F7326FC8BAD4E253519 +:109EC000D623846DF980998594D7F438C73CD16640 +:109ED00001BE39AE80F0A60504C7650FFA7FC95CE4 +:109EE0006EF8B3F987F09EBF43B0DE50A3DFAF3505 +:109EF000DA7B844B456AD4EFCC775D2F747CA31E4C +:109F0000F3CBA0799062998F7893FCBB220B70AF52 +:109F1000608B4591F1B82B643C74285DADCA93E722 +:109F2000FB16CBF6FDE1885329513CB8EF9165153E +:109F3000876C0580D392027EF72A2F565FD792ABAB +:109F4000118765CCDBB04B129FE07B86A3DA84BD22 +:109F50009CC619FD85B0E3EF734CB44B7902EDA0BC +:109F60006F0EF429DE4D41F4BD2C4F9E7B9AEFB667 +:109F7000ABCBE9FBC06D4BAEC6FDC589E1B2DDD30D +:109F8000BF8966384E6E50F89ECEA86DC28BFBC955 +:109F9000CB757E3A709BCB5ECEE3BAF8DEA3D16F71 +:109FA000C98654BEA759225A0B710F450C55F83D6E +:109FB0007C036EB4BED7B1BE2CDA2AB02FFFE0FB13 +:109FC0004F242E7E9FFB4FA387C61621AE5034CB65 +:109FD000F742270D2D59D983E6A5F9E57BA1A3BF4B +:109FE00058F206E79F92EF8532F90CE7F9F179987C +:109FF000ED53F8FD95C9BE8D960437EE652FB72554 +:10A00000A2FE36E1815805F508F78A8D75E58A16B6 +:10A010008B5301BD8803F141F4479C633AE825DF87 +:10A0200063E3F759A6585D36F01B43CE2971C9B1D9 +:10A030008BD451317CCF32444EB8D4D083E3627E8E +:10A04000789C4E3BDFE75FBAD3C97285B65E61BECE +:10A05000793E5FC6BB56DDF6E1704B7A679CCE99C0 +:10A0600034FF16BC037B267D7BF40885E588BD792B +:10A0700004D7A30D2FF13DCD92956FF03D944B0D7C +:10A080000F45CBFB6CD2FF52AEC3CDB03BCDD7F169 +:10A0900053AEC7691DAB93EF3AD339CCEFAE5C6AD0 +:10A0A000B0B19C112A2F1AF2A7F11E9110AE3FC237 +:10A0B000CE53D160E33BC00BD794AC4A1257CA9140 +:10A0C0008B75397351838DE3B22AF4F7D442FF6E56 +:10A0D000CF623D1E6BF156F3F74FF242E450E37D41 +:10A0E0004DBD4EC9DB0766B03CB4C4C6FECD39CB0E +:10A0F000A57C24B60B3FEE93CC593ECE82F766E6A4 +:10A10000ECF47A942EE8E95D5D4E9AD8EA64F84F53 +:10A11000B91CC1FC65EAE514CEDF7C3999D3999767 +:10A1200065DC2AEE22816E5A8BE43B07EFEBF2D11D +:10A130000CC4B1C6433EEBC9F4DD4EF48D21F2747C +:10A14000BE35C0AB1C807838D1A6AD449CECC48D24 +:10A1500082EF834D821C45FDCF825C158FFD9156A9 +:10A16000C4F76126287CBF68D2D0DBF4FD40FB43F6 +:10A17000303FE1F757B4C2297EC439CDD2B65B80F7 +:10A180007F635F68BEA3FC5EEA249F62C73B929A2E +:10A19000AE6F1B741FBA3FE646E876B2486907EB1C +:10A1A000B09361B27824C9B76A26E4D3B9B06DF62A +:10A1B000D20981601F952BCB7BFC76D5CC069241D2 +:10A1C000FF55FBC91C8B45DE3F233990EF0B88966A +:10A1D000A29E942F59A314403F32E6F5B967EC389C +:10A1E000CFB04E3A28EDD8A7F21EE5D27B324D7E95 +:10A1F0009BD0B48CE08DFD3437A6F5270A6168F456 +:10A2000060E12D1C81F7EB85F1285400F198B7E847 +:10A21000F9EAC13BFFB43A97E1C4F991BF7D68A662 +:10A220002FF25FE09373146BF0DF1B4BB268570D96 +:10A23000EEC1F750C703BF11B96DFC9E444AB64B3F +:10A24000F2A9107B4BF56089C750BB4B59AE3C77E8 +:10A2500084D59D7A2BFB7BDC6CB734D67DCC66BE77 +:10A26000E76BA4F307EBE75EDDBFE79ECAC316F911 +:10A27000FEC26316FFF657885E2FF7D06660BD8F6B +:10A2800021DE9EE7AFF1FA8CF74C3AF895FE6E8925 +:10A29000414F47965DE2FB2AA59176B71A444FE5F8 +:10A2A000AB15BE0F5ABA4CDEE7D6562BF25D846E64 +:10A2B000EC58BF99FDBFFC9ED56F7E112E0B75F833 +:10A2C000CEB1B7BCE148EB84EF9F973D60937C34FF +:10A2D0009089FB0EB72C71F2BBD99F7B8AAB060F1E +:10A2E000039E3C8CA771D8E5547F4B8CB604DF4BA2 +:10A2F00045CB41D81DE7FEFC6D7E8FBAB6398DDFA8 +:10A30000BF2CD995BF0AEFD97CEED17E82F5974458 +:10A31000BAEC90476A1A62F97C9EDB53BFCF2BDA06 +:10A32000D8CF67E0E7BEC1D28E777DBE1CE7A2AE74 +:10A330005711C06C534CF5BAB6631AF6D1503B4B6B +:10A34000E8BB21DF655781DDC41E645F35EC32B6A2 +:10A350009C63B371AECFB177FDF73EF7EAF337F404 +:10A36000DAF91D7A6DEEF89E90FFD72A2ED8D3CB5E +:10A3700023DD3371BFA1FC900D91B462629C5BBE82 +:10A380001F738F7C3FA6F48E7CE66773809302DC9C +:10A390003B19C9FBB8DC4FE990EEF7FBAD6B0FF44E +:10A3A000D90D7A0A78F91D827297D71E17241F9546 +:10A3B000352AA677248CFC0B8355C99748DD00FC11 +:10A3C0007E7C479A1D6F39CD213109F1997B412758 +:10A3D000C33ADB513D8E3F99982E0ECAF7BD14FE4D +:10A3E000BBE4182FF8EF5B95369ADFC3A0FA2CDF99 +:10A3F000ED1A1CC5FD95B868DD69485D3C4F8203C8 +:10A40000C3A9ED3EEACFCDE3303ECA027E1BEC0786 +:10A410007310F742F95B5C7E1BC6296D90EFD46820 +:10A420006BE438DAEA58FB20C8075697BD4FB05C9A +:10A43000D820DFBD9EA3FFDD119A2FCBCDE50427E9 +:10A44000DCB333EEDD86C2AB449F7F7963AC59CE7B +:10A450006C5C6B037E6677F35EC639DD0E5DDA30C9 +:10A4600086DF3728B77AF9BE8AA6C3FBB3DB9CF731 +:10A47000C25F327BDD23B634CAFF65B0946BCFE98F +:10A48000FB71627A2093DFA9BACDC9F1E3B35D8D88 +:10A49000BCDE0E783F44F081DCE22A6678139DF83A +:10A4A000106F59BECE8CDFCEF944C977FCD795F03A +:10A4B000FE5B60D5ECAEE079ACDF9789F8A1D9B44A +:10A4C000EFF10E9770697C1FF6C44333F9EF056214 +:10A4D0009E1CCFE6718FC7BB5344374CD706FD187F +:10A4E000F7F38DF1AC1EABB4C77BBE6B9F7A0F4206 +:10A4F0004EAF277CC30FD0DD3EB5E302268D6B2F18 +:10A5000097EF075EC1EFF4FDFAFF016A916CD3008B +:10A51000800000001F8B08000000000000FFED7DA0 +:10A520007B5C5565BAF0BBD6DA57D8C0668BB051A4 +:10A53000C00D0262116D10101575A1805B736A6306 +:10A540003729C48DB7500191ACA89FF3B10D6FA905 +:10A5500095262A9675B6A68D957570B2461B9BD921 +:10A560006A9A5D0F3A8DD33953B6CD32BB09D234D6 +:10A570009F7DD399BEE779DEB560AF0DA475A6F9CE +:10A58000CEEFFC3EFCE3F57DD77B7DEECFF35E7630 +:10A5900022634CB23136789883B1818C1918934577 +:10A5A000C83FA177FBED02639571ACBE2D13D22895 +:10A5B00056FF6B0B63DFE3DFF89E74A253642C8FAE +:10A5C000B1DBA05D1B7CAF10D9ABCCD6F33DD3295A +:10A5D000D0F78A1436D31DD41EFBC37EE3D5EF1308 +:10A5E000FC698B337BEAABE356D878BBA9D07E9A63 +:10A5F00005EB8BDDF51BA83ECFB3E92691C53236BE +:10A60000DB04FF87A594487B56C4E632D6B057706A +:10A610001AA1A8E14189B118489F8BF0B164C6BE68 +:10A6200068F8CD3BB740BDCF376FAF64437BE635AD +:10A63000C73F8A39463036F75236730C606CDEA558 +:10A640003194560FF364380706D5DBF85CBA07C6B9 +:10A65000BFAD2DFBDC7F305AB79FE530F6FE73BFF0 +:10A66000FDE368E897319FDE7D4DCF3A66AD3EA1B0 +:10A67000AFB204C38DAF734D4657158379CEB6186C +:10A680001C1214CD5E5EC5649827B333671AE413B9 +:10A6900075CC2B42BF6CFD16D904EBF330FE57B5D9 +:10A6A0005C90A95D63BE4F82F50C867AC61C5EDFA6 +:10A6B0000CF0F7580C678448A8E82D910319BCCD1D +:10A6C000F7293DF81D0CA921A707EF890A1DCC5ECB +:10A6D00057066D7BF0050333960FEB651CAEEAFC65 +:10A6E000A72AF3BF6DBD20FBA0DE0D4E07CF572775 +:10A6F0001BE6C17AE7AC4F36CC86B45CF95E3E47C8 +:10A700005BDE8D2FAB8AAFCC9576584F571BC75762 +:10A71000D73A3DE1AB6B4F2F7C2531A9671E7700FF +:10A72000BED8008E2F3682E30B53C057A5332FA817 +:10A73000DEBF707CCD7EFEED0F5E76D0FAA8FFCE38 +:10A74000078DBE1DD0FFACB6BD84B7F2D51BF4C9D2 +:10A7500050AFCE994C7051DBCFAECFB63280E76DA3 +:10A76000ABB7EB1D16FCEEE893EE219559103F4177 +:10A770009E099067BA40BC3BA2A77E39A47B619C2E +:10A78000258BCD91ECDA9E71B628F43CBB3EDA867F +:10A79000E3CDAEAF7A886571FA7767F6E6BFB36648 +:10A7A000CE17B3A03FE4CFB345CE24E48B0A51D4F7 +:10A7B000F09B9A3E847883793D06E03523FEC3DB27 +:10A7C0009E46380C5E14E66C864FA9A9011F8E8B3D +:10A7D000F48CF33688CC6B827AA935818B388F5410 +:10A7E000A0286C8769848D52160BF91D30ED024844 +:10A7F00053249EEE73F2F5C3773F7E6731813C5C54 +:10A80000BF4ACFA1F46A603B57A700FE0D31CCD9F7 +:10A81000ECE8A14FB51F953E55FAED6F7D7BAE700C +:10A820007D6793393C598633C904E3563E3CCCB925 +:10A8300046B8FC3A0D61000F5BD07A81580B6C7DF5 +:10A84000AC3735905776CD0FADB7A524B68FF586CA +:10A85000AE53E5933926CEC3C02751019877D7FA76 +:10A86000A1510CF12D302FCA9DB38BCD22CE5B5D53 +:10A87000D7534D5019E6B6BBC944E9334DC068C340 +:10A88000003E4D76CA3FDFE4A0B4AD2983CADB9D0C +:10A89000369A3F6381886980A78A3085FFFD3C8FA7 +:10A8A000E56541E5536D9CEE4E5B0311B62039FD25 +:10A8B00071BD790D8B42FA0E3C88FCCC1A87B25DD3 +:10A8C00030D4E9F56723C44CA44F3E3FB5DD127D7B +:10A8D00027C93F166170EC02969BB124FB7423E0FC +:10A8E0006BEEF2382790129BD13894E4C20C6FB40F +:10A8F0009300B07E0B4378CC53E460F892AA952382 +:10A90000B17E6BB2558071E65A9CE75AA9FDD5CE4F +:10A91000FBF17B4B99212593AACA26906377287275 +:10A920006C89C0DCC88777A09C44FE120FA5A2FEEC +:10A93000B9A355F01B29CF560B00D721CDEED27805 +:10A9400094135B05E70E6CBB0DE4A9A9479E760D39 +:10A95000737F817A817D07F407FD5F252002715D99 +:10A960006D721CCAF14D827517C379B90D089F0528 +:10A970000A9D9C6E3913E1C8EC81EBA3F85F10656A +:10A98000CC238B286F1B143D86644079454E0E31D5 +:10A9900070F841CADA113F3AA709E9A0CB9212C573 +:10A9A000FA286F884889C3F239AD12C945959EAA25 +:10A9B000D535287C3317BEA3DE2B912A6291BE5673 +:10A9C000B64CA474CE8692CD5EA0E324C11D3B9A02 +:10A9D000D6A367B89E39B513AF47BC55EF30469B39 +:10A9E000006F497A6F524E103FCED9BE2A8941BBC3 +:10A9F000F3DBCDD351FE175BCB8AA3A1FDBC6DD198 +:10AA0000D952901E49CAE67A6441EDC43806F0ACCA +:10AA1000F9FB9127ACA08FE7429F56E8FF9BB670E9 +:10AA20009F17AAD434ED4F9280E7DE3179E2B3A1CB +:10AA3000FE42F1E02DA3501F08BEA7E2A9BE23CE1F +:10AA4000DA873C50D373C00F0EA0F7DAFFF51EF57E +:10AA5000F395F8D6F5E5D0BEA6F68548EC67E1A6F5 +:10AA60003FE45BA1FCA0E849C3FE3F17B63F654544 +:10AA7000026CDD9E857A7CEEA6B4284F1FF217F992 +:10AA800000F151BD5F20F8AAE5337C510684BBC7B5 +:10AA9000CF0C564CADCC80F47E5E628D680FA8F66C +:10AAA0008C5A3E329BCBADF351EB93904EE63FB5C3 +:10AAB0002509F5CC67113C5FF1D4AD6FA0DCF2EC59 +:10AAC000341A10AF1E1D3338519F7941BF221D55D6 +:10AAD00003FFC693DD61AE047A2ACA0E27B8CE6F93 +:10AAE0001D41FA519D177CA7F2CF74CC85F318D283 +:10AAF000DC998D74FF679D7F2EE2F3CFF566A71773 +:10AB0000F199CDF5DB9FD74BA558EE0586417BE447 +:10AB1000CFEB5F8848B5F4D86F25D2FBB28476D6E8 +:10AB20008B4236EAEDF0CC76C32CB21B18D1599D7E +:10AB300095D359C3017DE9E018B2C7A8A446E73709 +:10AB4000F485AF058ABDD59DDFB7D7807C52B3872A +:10AB5000DB11356D67C88E50ED925A859F17EE391F +:10AB6000437685DAAE6E1F874BED3E5E5E9501C87B +:10AB70001DCDE5800042BA0AF105F9FBFEF5D7D3F9 +:10AB80009769F27B297FDFB5562E0F759D49A8B7CF +:10AB9000D6649C3420FE6B972BFD425E1F34DEBCD6 +:10ABA000EC81042F2C1F6AC1F60E8DFD50BB2F9A2D +:10ABB000DAFB6BC356A3BE97EB2C3A4C9B6B2DA4D0 +:10ABC000FFB7D58B19BA5C9C5C9813EDB983619182 +:10ABD000592847072E3C650648026A3B8F8850BEBD +:10ABE0003ACA732FD2671C03AE90506FF805B45F5A +:10ABF0003B5EF97404F63F6E48E06B0653D70BBF1B +:10AC00009B5E0CF26419982D641F670646201D0F89 +:10AC10003CCCE5F4E37AB61AF51BD3B9D93428F75E +:10AC2000A3DC423C7F1BE6DB05FFFF1DF30FC6FEE6 +:10AC300099C93F14DBBDA4D0A7DB68592DC0BCAEB9 +:10AC40001EEA59834BBE41D05F932D220EA434AC33 +:10AC5000D7A1E7DF557B758222A713C18E40BBC801 +:10AC600030C86E413A6E36F3F509B2CC1A611EF760 +:10AC7000671E9E8D7A7A6DA78919619D133AC3C8A4 +:10AC80007E4D1CE422BDD66C4E22BD2D3874AC0224 +:10AC9000EA1FCE14FD3AACCF4C3EACCF4C2176AE81 +:10ACA0006896B19D70F0B56F51BE0F962E1E8982C9 +:10ACB000F50DBE477036439DCAAE738FFF1BA415BA +:10ACC0009776ECFD5748FF2DCAB313E17ABACB75DE +:10ACD000C603A85B6B6D3339B9DE60C1EB3878EF22 +:10ACE000B79136B1677E1D9DE79EFB4D2EA62627A8 +:10ACF000EA9F090725D21FA1F3E9B0C3C487523DDB +:10AD0000B23B3B2CA24F10B0FE91F7707E134C1655 +:10AD1000BF84F6BA49FF65B07E618EC4E87357936D +:10AD20004A61DF8391108B93477D74D14276EB3873 +:10AD3000850F553A7B2B9BDB8F6F297255853373BB +:10AD4000C82C58AFA8F06CD6ABFA2210CE327BF8E4 +:10AD5000769152AFEB9228931D5E6DF431E8B2EB21 +:10AD6000E050D233FDC9D93FA0DD01F6C4F254F959 +:10AD70005D842753F4EECD0AFC54FD2D29FDDFAC94 +:10AD8000C0F1668BC8E1765308DC147A0AA5971ED9 +:10AD90007A8841DBA31BCFECBEF6A351C984DF6BDD +:10ADA0001EE678FD90F0FAED5B2B80CDD8A0BF4D6C +:10ADB00021FCFE0C78F58BB93F02AFEDA178F59B35 +:10ADC00087215E37896467A01D8876A307E5C0B533 +:10ADD00094E7F66006233951298539D724E3778033 +:10ADE0004316C987A3281F54B930C415B806F5E91E +:10ADF0006970E5717E01B18D97E7A4105D24B0F60E +:10AE0000782C07BCE7A17D279986667E0C72B7E592 +:10AE100001DFDEDF403FCD826FEB3C988FF7668B22 +:10AE200013EDB70E9FE8D5C33C5AA259D67E18BF82 +:10AE300065FE554E2F9633456E4C37F8D07E83EF26 +:10AE4000498DF8BD9C7F7FE9EF671F44FBAC338DD4 +:10AE5000D1BA5AB2593ADA672D6519F4FDB7AADCAE +:10AE6000793082B72FE3F4DD32DFE6433DF4E8A327 +:10AE7000BEE1A8275AB6CBF136480D519EF81C9872 +:10AE8000FF2089D37D4B329443BA597097CFC57E4A +:10AE9000AEE1F30D94873DFF1474654E05D106E5D0 +:10AEA000A71B2376A05C55E974F0302EDF8778CF9E +:10AEB0006C45387927B08C7AE8FF4385DE54F80B6F +:10AEC000C0368D00F798103CA87417A3C05F58CA0D +:10AED000E9CF3B41594F1DF3A1BF910053090738FA +:10AEE000571AC1F0837496D5938DF36F5E0CF89169 +:10AEF000701D1C0FA74556DDD6075F15E628F10D1E +:10AF00001802F9A69271BEA944BA427A6C04BA0A30 +:10AF1000A2471648883E17AED015CA8308F7B81C5A +:10AF200058E757C21FF2B1F0ADFF94A6F735CEA493 +:10AF30001C2E2F1E337B4A7348EF4DD0D89D6F6572 +:10AF40007F9A88FAE5F4BDAF25609A14E59E8CEBF4 +:10AF5000D85CFED75214FF1FC607F4B88E0FCBFF84 +:10AF60004F22DA2D954B5F23FABFD2799699983705 +:10AF70001CE01E5D2C38FD00BF792D46E724F81635 +:10AF8000575C750CE159D66A74189156D8628D1CBD +:10AF90003B2B8F40378A1DDA6A24BA39F74B89F484 +:10AFA000C1B9928BAF0E800FE756084EAC57D63220 +:10AFB0006C2590372B2916A85E9957A07A65A91C95 +:10AFC0005F271A05A23740AF253B28DE31A7F58E53 +:10AFD000A988DF13C55F0FA4F8C17A1847E5632E6F +:10AFE000DE489E9529F5AB561B9147BBBF97B5AC84 +:10AFF000BA88FC3FD31B52DE3AE953ECB7AC515B45 +:10B00000EEC635821D77574E440CCA07E664CEEF74 +:10B010001148F240F20FFA93BB407144CF300FC297 +:10B02000C389BC617AA4EB990857A0DBE8A57CDD55 +:10B0300033A70ABE49B0CE9916CE671F9609BEFB4C +:10B04000053EFF0940EF65501E0B745D16C3E438E2 +:10B0500048DD26E60FC7792E1DF609CADBD338D4A2 +:10B0600028AAEF8FB4A15CF7E81189B7322FA5E5C4 +:10B07000CC47E9EDCC4FF398C13A937490AF93FC71 +:10B080002B318EF32BB36703D2D75F8B4E9C16E028 +:10B09000FBDD3942DE2894438D0368DD975B1F702A +:10B0A000A5807606AA41AC5F96E37E14FBB3CA4C3A +:10B0B0008F71AB74958E5A993715D617BBDEE29B0C +:10B0C00004EB8B6BF51CC2F5A64F373810EF8313DA +:10B0D000F83A1374DC9F3F546E60A3810E363F181C +:10B0E000E6433ADBBC3520DAA1FEE6038001CC97CB +:10B0F000AF14BCF0DDEA614E8CD359751E11EDFE24 +:10B10000A2568F1808E2A7E1B241443991BED32379 +:10B11000A29EB45AD7533D355FACD44F3779065908 +:10B12000C94E9E4EF4335CA11FB59FD456835F0475 +:10B13000B817C94A7D99B757FB618A9E56DB6139BA +:10B14000D2677AABA34F3F454D5B503F838FF808E2 +:10B15000C605D27BCA1F71FDDA84F01B78F3AB36CB +:10B160004C370321F8711C9DC74CE379F83CD3158B +:10B17000DA87BFBF7F8FE3631EF0BBB9F5FE22E421 +:10B18000A3CD001FC4F3E69DB3CCD4CFF4599A7974 +:10B1900031A986F22508074BEF753CA2CC2F3DD58F +:10B1A000235A69BDCE4368E7A5CB8CE2016A3F769E +:10B1B0001D7405F46A777A857ACCCB905A94B84797 +:10B1C0003A8EB34E40FF315DC157496BFD6133F696 +:10B1D000E366145F4CCF85FEA1FE268483A137FC75 +:10B1E00042E7995ECCE77342A9DF8EF194746CE775 +:10B1F00058114374C5E7D7D5EA14621C97B18FA0E4 +:10B20000FDC9907E9EC2B80CA4CF4E7E6D4A2EB46E +:10B210007FFED19776B4D0520E3EB30FE556ABF514 +:10B22000E69B709C83229FFF4D72E25D98DF6D204C +:10B230003D9ABE534EDB44799313FDEBAE56DF557A +:10B240002F42BD2C18C664EB3D8F130A9CDA153AC9 +:10B25000383979CB205CEF5345772C5802ED875F66 +:10B26000F7388D3B7CCAFC9416C80F9BF8CBAB30EB +:10B270007F5F8EC73C02E4FEB0D25FDEB60FE56AA8 +:10B28000E9FC1C8297C57645F2A939DAE3F502BFDD +:10B290003747DC528EFCB8D26670482477EB19FA37 +:10B2A00059CD1177DBB1BFE5D1F9264C0DD6BF36AC +:10B2B000A19C3C6EC931211E9A2D131896EBAC0A45 +:10B2C0009EBE1B4FFA40528872778473BA4C74E565 +:10B2D0006428270C0906ADBCD671792FD91D3EB460 +:10B2E0009FBAACF54881CC600954A07C935479692D +:10B2F000717A713CC9E2B4A3BFB44291372C86AFD6 +:10B30000D36039F79F38AF5EFD632E96504B7F8632 +:10B31000B0CC2841F93FDA9BC6103E575383C5BBDA +:10B3200018F544687F5D2070508EA34F4776337EBA +:10B3300048EEDD5EB21B347AA45B5E7AA2F521F2A0 +:10B34000521E817AA2582079E961EB0CB8FE120CEA +:10B35000B2005C3CDBB85E54F97B26CE05F0E549D3 +:10B3600065915C5EE9E473260EC6EFD1AE5C2A45BA +:10B37000221E025EC9E0E9C39FF778937F501E9DAD +:10B3800041FA87A90790FE21FD44E10F8F8A076FDC +:10B39000D9F5A3505FCB12D90395CB8536B4CFE254 +:10B3A000BCD14769BEC5DC2E6897BFA6F51C2A89AB +:10B3B0004B44797962D999C7EF41BDBE299CF4FF0E +:10B3C000A4A56756603C6EA657701A21EF591A7DE6 +:10B3D000F77B986F343A5D903FABF081FB974591D6 +:10B3E000684F08B8CE8C9E75561632839BE239F1B1 +:10B3F0003396403B4FA3E0343B7AE0A1C77A52EF4B +:10B40000F505BC3746FED0FA3FBCD7A8C859773EF1 +:10B41000CAD9A2C6E4870A705DEBF57C9E8DD1D7B0 +:10B4200053DE27393976B91C9EA9D83F9EA5B3575C +:10B43000C6C3F7C06A41F9CEF156A9C8E540E38812 +:10B4400063183F0D2C17483E79BC52A21FDACD5C21 +:10B450009E4D78EF280A905DD8E53DB4925A2B7244 +:10B46000DEA37436178C58946FA7DFE3FE9F47FE68 +:10B470006325B69BD3A2B5832602FD0C40B8BC67FA +:10B4800026FDE9F196D1BAEFF04569EA55AD8ED3C4 +:10B49000E43DAB8BAEC7B0E7AC7B27523CAF9239F3 +:10B4A0002291DE2A656E37C19F251BE633579D4FDB +:10B4B00031B7C72A8BC17EA2EF5A7BB0C7FE893352 +:10B4C00020DFA87854F1133AEF5E7619E376D0AC1A +:10B4D00075DA7ADD761030168ABACAE5DA76BF32C6 +:10B4E000BB9F45B9E8DE38E01BF2ABAE501E828050 +:10B4F000217F6E26E3711FA6E843D5CE2F597A51DE +:10B500008F726866E3453DC273E6D21FE6A75F38D7 +:10B51000B5F3BEA1204ABB3E394E93BFD13544534B +:10B52000FF66F730CDF75BA75FABF95EEE19A9C9EF +:10B53000DF5E3D5E537F46FD24AD1C7A379AD6A36D +:10B54000E2A7BF79BFA5E8A37742EC12359D3AE2A6 +:10B550003F1391BF3F2C67E4BF7C7833D3F8311D94 +:10B56000232482E7805C3DF931F7E5C8EF8F20BFE7 +:10B57000C94FF4A1C2F34373A1C928A27F62E47E3C +:10B5800079A85F729039505ECED4B1FD42548FFFDE +:10B59000670EF39CC7FEBAE30D4B0FF17843881F8B +:10B5A00073A578FF7006CCBF0F79794D2EF7C316BF +:10B5B000EE36AFFF38088EB56DD19AFCA2FDF1EBE7 +:10B5C0003F0ED63B4B041DAEB346E1935A16A07D09 +:10B5D00052BBE8A0FEEAC4402CE63B58676CB4F4CA +:10B5E0008F838B0A0F808F253728DEA9FAC33F1976 +:10B5F0003E450A9ECBB4701A93CBE3905F8F10291F +:10B60000DD9C23C7E7FE03F11CB49EF4DCBC7FDCA9 +:10B610007A2247C859089F9F1BAFDFE31E0F94177C +:10B620008E900B7F26B84CFE47C2A547CF472FD838 +:10B630000DFAA3729D81FBFDDE335CBF3772FDFE08 +:10B640007CB48FF6879BF344E70E07ED97D23EE973 +:10B65000A17B8D611918DF59A1237D797A99908199 +:10B66000FEC226218CFC360FAB4816C8BEB978C87E +:10B6700048FD31AA07EDFD3A90F351053E6B09E410 +:10B68000DFCCE571B1356E714A8A03F5F61FAC1E49 +:10B690008A8B7AE2111E9EFD30E16B69DF45EE2B4D +:10B6A0007E12D06BE5D112858F5FCCD5D13A1F2E9B +:10B6B00014B99D942ABA701F6315D8A968570696C5 +:10B6C000EB285F91C7E9596DF71F0A9DC794DD14F8 +:10B6D00086F388DA24BA7D7D8CFB512E8F0F3D795D +:10B6E0005718EDB3012A7468EFDBBDD6692E58AF49 +:10B6F000BDD0968DB6DFDADC68EA6F4D469715CF80 +:10B70000A1FC8C7478CA8EFEA0C0FA8C33CD55E6AD +:10B71000ABEE0F5894FE36E941BFA29D2298281E39 +:10B7200061F11AF9F91567B126DECA1C020B6EA782 +:10B73000D6F328F46AC7421BE197F6EFD578B15DDE +:10B74000A117A41BC4BB4ACFA1FD8389EC8DCCE912 +:10B7500089F3D915528E1AE5D98D748FFDEA901FA1 +:10B76000BC5CFE076EBEC4E32CDED7DEC37988E185 +:10B770005F529C0CEC4ACE5F4B43E2BE3F914F02BE +:10B78000660ECF4084561EDEABD0C9DA7F82DE481B +:10B79000BA02BC3E9CCBE58FABC0FD36CA3BC7B2FC +:10B7A000D430A2FB1F0B2796604538515EBA723821 +:10B7B00079F33D1F109E74CC6FB4717F0BF9E17269 +:10B7C0007CA4C23149649EBEF4F2883CE5FB1BCAEE +:10B7D0007EAEB76AC80FD9612877C502C6D22CCC15 +:10B7E00061BCB6FF7A0E9C8F85E86A39D2E5AE96C9 +:10B7F0009430E4CF6465BCCA9BD2A70C77A05F20CD +:10B8000018D00E04BFC3C0E33FDC4E57E57A4FB9F2 +:10B81000D67EC4724F668F1FA6DAF7EA773C97820E +:10B82000E3AAF359A5D861FDCD7755124B72A2DC7E +:10B830005A768F80F0DCB15AD4F87D715E612503B1 +:10B840003F3ECE7FAF13FD8E38B0AFCD28CF75F51C +:10B850008233085E817B810A381387F82BE04FE240 +:10B860003ABD67895E42C757D7B1AB858F1BE75D8D +:10B870002CC8909F54512FA0DFB756997F5C05A329 +:10B88000EF69993E01E3219E16568AE3555633032C +:10B89000C6F52A33995386F2CAC64374DEEDB9025F +:10B8A00039256F20C94F3A4FE32AF0A4E7011D4D17 +:10B8B0004D28437667B84B86F1897F161DA7B54C96 +:10B8C000F0A2EF59D4E23C84FE01D011C57D3C2D9D +:10B8D000011A5FE7E571725D8BC1E98075488D657E +:10B8E000B4FF21551B9C32D43BB629DF8FF1952D37 +:10B8F0008DDCDF0DF59374D6FAD7C3D15FAB109909 +:10B9000044010A792AFA5956852E5630773BEEF7CC +:10B910003319FE41BB48A5DC5A3D6F2A6622E5D0AB +:10B920007883DC139F409E6BDC40B2D394AA8D6772 +:10B93000482D2BC9AF33627DA8AC0F897748D5A5B8 +:10B94000141797ACDAF25BF32262088E593C1E9E04 +:10B9500073EF888DB7C27C727F79E31F303D8741DA +:10B9600033805BFEB23B074C87FF16ACD87823A62A +:10B970004FBCCEE89CC18FE057668CFAF1FCFAE828 +:10B9800095F2ABB2260FD0B9C2AF7DD2BF1A4F0924 +:10B99000E54F95FE43F94E4DD75E867FD7260512BB +:10B9A000910F4FDF3B3203DB5736DE73C8C7885F2A +:10B9B0000507D077A577711123BA605697D05B5EE3 +:10B9C00084370B49ECBF371F3F867C3BFEEFE71304 +:10B9D0007F08DF95098CCE6381FD49F69C9AAADF2A +:10B9E00023F2B93EBD906724BC4E46C10AAC3B056C +:10B9F000DAE0BEC778604E2BA47F2EF03C8BE34D7F +:10BA0000813C9EEF7BFD406B0CAE374BC7F58EA79C +:10BA1000DB8EE67648B7FFA8D80F59063605EDDC71 +:10BA2000C02611776E59E0C0E73BD6E2BE6BB9C9BC +:10BA30009906EBCABADF48F484048AF6519668A7DF +:10BA4000B8E5AEB68FCB699FB1D1C0D2286EE00EFB +:10BA5000C3736400CFB0AA4CB257C3AC68AF7A8549 +:10BA6000A4AA881E7B08F5220AB42CEFAD53AC3093 +:10BA7000FEAE42B047337BEC1CD5FE599C9F4CEB8D +:10BA800057ED2068C7B0DD8FE5A74A0B4B22BB19E5 +:10BA9000E683FBF7B64C2690ED1352FFF43223D920 +:10BAA000AF76AF7BCA70B45B97A7E6A0DD0AE39AD6 +:10BAB000246E7FFD3BCA67BB4EF95E28E6E0B949BC +:10BAC000751F800574D1188753EDAAFEE7A563E7BB +:10BAD00054B905957F9B2F9FC17EFF5972DD635539 +:10BAE000E84D4D63F879E0E90ABD8DCF37539A9E52 +:10BAF000FFB3DB73A7AE93FE79EBFE39D7E1FA9F74 +:10BB0000B18ED8FF21F8D83CF97FC63A6E99F24F32 +:10BB10005C87375F6EC8CF4379D646E788EC2E7EC8 +:10BB20002E1CE4DE3DBC9CCB398B930964C7FF74AB +:10BB300079D784FD9D411F1CCFA17877083A1867FB +:10BB400088A5A188ECCDA58CF681862CE5FB404329 +:10BB5000963A4D22DA03166E270E52ECCE414BB9BF +:10BB6000DD19A79C2B888B117D32D43FF6CB5BCAA5 +:10BB7000E7C6E0BE9091ECD5E636DDF516D4535E0F +:10BB800089CE8F86DA89D2D2954A9C5F6B9FAAF6BE +:10BB9000681AE379FDB2B3B44FA7DAA34394F2B4C1 +:10BBA000A57C3F60488BD61E8DABD6DA8FFA82100B +:10BBB0003B73A9BA7FD049EBD32DD7E9F1FC7FA81D +:10BBC000DD897BB0A81407AB7A06B4FE4DD730F6FA +:10BBD000747EF7F98C1CDC1F9AB95AD0E83955CF1E +:10BBE0000224287EA4E2E343D473883FF734B55F90 +:10BBF000D26F3EAF48704C2E4FD79C5362EC7E1EE6 +:10BC00002F71733AFAF5EA116BD1AEDDB7EEC63794 +:10BC1000317D69FD9DE1E504AFF5546F7FCBC6EB47 +:10BC200030FF5076BB3D12E6F5D0A853EF09D0EFB8 +:10BC30006A3CE385EBB378298FB6149E8BD0B37A38 +:10BC4000DADFDBA40F4C9F0DE52B12451C91BE23C0 +:10BC50001D9832189D9F3059787EF5358CEEE33073 +:10BC6000E55C9F1A87093DD7B7CAC3C75905F0C419 +:10BC7000733596187E1FA939E1FEE908EF668781C2 +:10BC8000E139398B72EE4F62D5AE2AA877DC7EBFE0 +:10BC90007D16EE0B6718887EA498CE26C493D99E95 +:10BCA00063AFC27142E235CD29E9372059BCB5FBFB +:10BCB000F09E67207D7BCFC92F319D2AB5EFC3F35E +:10BCC000255246889FD26BBF9811DC9B87335F4A11 +:10BCD00032963B6E10914E75EB6F9A86FE54C150B2 +:10BCE000E71A584F5802F31B601E61BDF689797B35 +:10BCF000A9209CCED54896F5150DD8DFA808BA7FA7 +:10BD0000C0BE03AECBA7F34DF457F680A8473A0E5A +:10BD100053F68FC3327BED1FD3FCC2304DE1593B4C +:10BD2000E4C3157A5F637BCA87FB776B13526E108F +:10BD30001D3DF5695F19D6BBF2BB1BAB685FFD26E5 +:10BD40009315CF9F8529FBCAA1E374A53A5B67438E +:10BD50006AB418647316F1550F5F72E0D85383E626 +:10BD600001F5FA9CA73A6E731EC783DA9FD1C264AD +:10BD7000B42343F7AD43FB817970BE56EAA9FD3188 +:10BD8000D646E70174888B517DB5ABA7B90DDFE9C5 +:10BD900024BB1FFF82E382CC1A43FC35AC55DBCEBB +:10BDA0009CCACF0DA8F4182A2FA5D0FDF7D47A6F1E +:10BDB00038E1819F2708AD1F0AD7D0F6F0B7335876 +:10BDC000DEDD60E1FB885DA99DB922AC7BA53D4726 +:10BDD000337F5ABFD0D37FEFFD3C6DBE4C36F6B9F2 +:10BDE0003E94077DCD77824EBB6F596CD1B62F8DB7 +:10BDF000D17E772568F39245E9DF916DA2F31A8E23 +:10BE00007C139EF753F9D818E2EFF78ADF2AFA2E4F +:10BE100091C9741E7593DE790EE5C4E33340D201F7 +:10BE20007D3C2CF8CC582E55B45B510FC6ADD39346 +:10BE30009C7AFCAE5BCEE0BDA016A06B84E571F7EA +:10BE4000479B6EC57CB148F10D9BFB7039D251CB3D +:10BE5000775FBF371BCF9F3A0D74CE5B3DB7B1758F +:10BE6000AC612B1E0B8ACB94CD69F0FDA12AE68430 +:10BE700099B02363632371FC2DD1A215F5DDF3D1B5 +:10BE8000F5FF8E7194E6198CF61942E15737D246C8 +:10BE900072366E75B680F75B1E1E9B5F8972310627 +:10BEA000FC6594AF90CA7DC517C715F0F8C0B6C53C +:10BEB0002FC523BE37580FDB699E15A213A7D85292 +:10BEC000C1E57F8B85D13E7BF3A852371E4DEC72C6 +:10BED000C90E3C8BD8E2DE41F35E592D72D9AC9C81 +:10BEE000970158C851399CBE0C364AFD986E34B340 +:10BEF000F839289792C2E87C507FF681B484CB57FA +:10BF00006C6FCCE9BFDE43118DF1C85CCB67E49F59 +:10BF10009F0BFD6D9DB199F2AA3C8D53E8BBBBDF31 +:10BF2000103DBA1BF04B72361AE42C9EC7638E8705 +:10BF300089B775F5C2B4203AD555807CCDE2E72E9D +:10BF4000307EBBBEA834E387FC4C9D9BCBE51855E7 +:10BF50001EBBEB9761DC05DAFB515F633F78CE0FC8 +:10BF60005219D7B751A83F447EF30C8303EF39E849 +:10BF70002A400E437B5D82564F1C18C9F135FBC128 +:10BF8000BBCC9EA0384D8C721E66A3BEDE9C06EB19 +:10BF9000D93843746E07786CA96810FA8AC7C455FB +:10BFA000707E990DF5D16FDE5291131BBC9E668C8D +:10BFB00073C0D036D70F9FDBD385C8BF5D2379BC54 +:10BFC000BD67DD1CBE71403FA8879A4797AEE66A01 +:10BFD000DA41725567E56D6DAE7A3A07D955C1CF32 +:10BFE0005DAD13F87E82A4C4CB9B8BF249BFF44BAA +:10BFF0002F152B499F84E2579D3FFDE507E91199D5 +:10C00000F1F119879BB4CE4CFAE107DA3B74F94A97 +:10C010007DD40B1E6D7FBA625136E3F8A85F10AF76 +:10C020003AE6C57B93A1FD952AFC163A1FC969E043 +:10C03000EDB19D8DF88BF4DB6901E0C8E982CEA1FA +:10C04000B3F7383CB7243A7C6BF8012ED28774AE34 +:10C050002BA5F7788F098E65B8EFE87D5DA2F3E731 +:10C06000A17A4FCDAB7030B136E79C3EEC4D9C0FC2 +:10C07000EA3569A7D789FA01D0978AED362A4B09A4 +:10C08000BBB3D45CE0E8ADD7BA5C6DABAF82729362 +:10C090008399F6033C4C53997F30C079ED33CF1C24 +:10C0A000BF8AF53D0EAE03F899E0BCE6F94733E6EA +:10C0B000407BF3EDAD26B4B943CFA1F56EEFA47686 +:10C0C000714BAB4CD319C5236554B986080BD9AF56 +:10C0D000CC7486E4B334C9C6EDA7103DB90EF85050 +:10C0E0008FF04A6404AFD03871E8F84905C9FCDE26 +:10C0F000E4E2521A774345A71EE3905DAE7AC54E3F +:10C10000F2F4A9EF42FBB17B3AA723FF77151AC8D7 +:10C110001E7EF8C1499311CFDE6512C5D17AD17B5D +:10C12000C8BA3D23F59CAE1C8BCD287FB7CCB9DBBC +:10C13000ECE8C3FED852318BCE2F5A96703B63A5E4 +:10C14000BD81E488A542B9E7A2D8CB71AABF13A2EA +:10C1500027B7543798F1DE9B7ADE9085D8DB97EDD0 +:10C16000BF1FBDBB61F98BF1A84FEE2A6988C77963 +:10C170006F89F04F7713DFD5939F02F2381EE5F1F8 +:10C18000A2910E922FDDF27FC6393B0E1E18695523 +:10C19000F88ADB435FE27F41BF668D92A714601C83 +:10C1A0002DB5448E7660BC74DFBBD300AE93BD7AF0 +:10C1B000F2638DFB81F4C12F322638495F9E1E68E1 +:10C1C000B0229DAC6AFC468FF76BCEE2E955E87F62 +:10C1D0005502B78756C51898DF42F3A1454F752E13 +:10C1E00066A8A7F509DC3701BFC58F79162310FDB6 +:10C1F0004C8EF1BAAD00872931BEBB30AD4AACD709 +:10C20000D9609C1247B480F09DA263C5061EAF9D05 +:10C2100085F35C11F311C55927A7C5D17D54A3C57A +:10C22000ADC3FBC97A67D5F6B58CCE8B51BC15B0C2 +:10C230004AF7E18C18C7BDB6278EABEE13A9F1DC27 +:10C24000750529042F21C1FF2DE223CB1A10F11E01 +:10C250007E983E40F6F8AA4613F941CD093BDA91A3 +:10C260003D3223F83EA47A3E17E063B1027C560CBF +:10C27000BC9BD6959414BB17E7A5FA91F120AF505B +:10C28000DE6525CC9B8AEB4B7AC3ED4A867AC60CD9 +:10C290005D366016E0EAB9A278AC1EC6213C58D8DB +:10C2A000384CFBABBF22D140F1D8D0F2270B785CE1 +:10C2B000320B0521AEEB5E13DDCF5D75E0BEF7AA54 +:10C2C000507E1E3039C967678114BCFFDE1D77665A +:10C2D0007CFFDDAE9CBFB5DB0D743FA63BBECCF84A +:10C2E000BEBC1AE7881AE5D98C78F231C721F4C7A9 +:10C2F000FEAB718F1B46CA4F607FAC6DC015C56326 +:10C30000C2C6EA689F2729857982F7055629EB5F1F +:10C31000D50D877A3BEAF575289407F60F878D3798 +:10C32000E7BB2622DD46EC8847FDDA47BC431317FE +:10C33000C17B2879B10462FA93AA799C2466EA3C0D +:10C340008A774853F93ED90A1660FCDCA0C0847C89 +:10C35000BAEA4BFD0D7087E8D7CC7A929391AE90F4 +:10C36000B8482F7F45E6766588DCDBA2F0F9F1025C +:10C3700025EE91CFF2BFE79325BB2852D9F7891854 +:10C38000954272E811570AD943C41C41F0BE9C9DE6 +:10C390007350B1877EA79C8FF72BE7830F2BE78322 +:10C3A0005FC5770BC0903F86EF16407ABCC949E560 +:10C3B0006F341528CA99E36F45EE9248B21F94F97D +:10C3C000E994F9ADB04E7325037E566DD3D37958F9 +:10C3D00063C284E968CF32AFDC9E11DB73EF8775EF +:10C3E000C2BFFC9E73A75D091E3A4F3AC7CAF73F0A +:10C3F000557C2D54EAAF12B619905FC7766AE136C4 +:10C40000FE52A4C6AE2C62DAF397134D4334F54BBB +:10C41000ACDAF39793ECD76ABE4F7668CF5F5E973E +:10C42000313E641F564B570B13806E804EAA337DEE +:10C4300034FF85D6528A7BCD0DB9C77447AB363FE2 +:10C44000DFA7CD2FDCADCDABE7C9C34629F43092D1 +:10C450008DFC31F14EE4F70C85EF0701BF6FB33A65 +:10C460009911DACF1678BFF81EC6001BED4BC976BE +:10C470008C23ACE3F79FB05CC7CBBDC395F67ABE07 +:10C480006FC58EDBE8BE1D4BCCE1ED06F0EF7EFC08 +:10C490008EA4F1720EAF87FE12D61BA2F453C3E531 +:10C4A000939C45FE829BEC33236BB3626A01FEC210 +:10C4B000349A39E99E750CAB27BF7590727F325163 +:10C4C000E8A4BC43B086613E4570A6F0F8858FE4D1 +:10C4D000C35049FE752AF1895B7447F4E6970DB99C +:10C4E000BA07F0AAF8860291E4E2235646EFF9D89B +:10C4F0005CF713BF6EC316B06E336B8F49157AF8B5 +:10C50000E7EDBC61C45F135C0EDA2FB515240B7820 +:10C510002EA588859CCB364569E8A3C41A17425FCF +:10C520004342E84B4B7F7F9DECD5453990CE42E8A6 +:10C53000F02FBEE5512C18AF4C8FFA058FD58976B8 +:10C540004A059ECA02964F75469B31EE678BD173A2 +:10C5500079A5D83FA54A9FABE459EBB2E1FB6B56F6 +:10C56000D149E6F6BA2D3DF12518DF9600F635EAF9 +:10C570006399915C7DB0D31F7635D47F04FCFF6551 +:10C580000CFD1BEB64BCEF65B5E4105F3F624979BD +:10C5900000F35ED0E8587F4331F7AFE5E86C82EFF7 +:10C5A00051A1BE05EFA53DC2F24CA9C1F52DBCFEBF +:10C5B0007A596451909F183182EABF9D6766F8CE20 +:10C5C0008177A0D98771EC63F2AC77DD41EB7F7B9B +:10C5D00014D707AF191CF1A80F1E997C77A687D234 +:10C5E000748D5F684B10E4BECE17858F3672BD9296 +:10C5F0005BE2C7787C74C234579903FD1DB70BE921 +:10C6000042E712F1E85B37FD442B7EA8E406C10F38 +:10C610004B9B745D0E43FFE3110B77351E299ED5AE +:10C620005286F90291EE03D95CE2EBD9B8AE027EF4 +:10C63000FEF04AE571A81E18329ADBBF9386443C8F +:10C640003014FADF50245AB1FF0D7A2BDDE7F14E9A +:10C6500066E45717BBEA97E0BC6D09110CCF6FDA9F +:10C660000A1A78BED8C0CC004F936BBD17F1694A47 +:10C67000F58CC0F647077E7A1CED195B82483A704C +:10C68000A2CBF9AE1BEB1728F19DE279EB703C9B36 +:10C6900045B49A590F1C54B9BE9EC9CBC9FFB20A02 +:10C6A000F4DECC0A6B430DCEE7918470B2F36DAE2D +:10C6B000060BE279C3403DD14149227F576A55C2FA +:10C6C000B40ACCFF62A09171BEF32F1F8AFE815382 +:10C6D000A075355B1A685EC72E8939C1EF96A8A987 +:10C6E000D9A185CFEF46F1F89009E3F1809FB7F526 +:10C6F000CC9C9A8BF4A3A778537F7C6B735DCE7E22 +:10C70000FB61FE2A94030B11BE8597C2984F40FA35 +:10C710003D2961FE777F015B80D6D960C1FE416E05 +:10C72000BBFAA2BF88D19C7E9B0B0E4BF84E82D7E2 +:10C7300021101F345B4E4E443E7828B58CE8E8A1AA +:10C74000828F9A892F86F3FCDB79F7EE413C7A13CE +:10C75000C3697FE7A1825931C1F4BE609448F432C5 +:10C76000EE6F614E3FE2639481F8FB9108C7568CEF +:10C770004F79F3CC64BF4B8275D96C98E7C46228BB +:10C7800087FEA25D623EF17E75058F0B2B307ED554 +:10C79000653B84F8904A66317EAE4939F71491EFD3 +:10C7A0005C4335B4FA6F952597DECFD892D07042AE +:10C7B000D9B620BB6A9022570694884528DF0659CF +:10C7C000B85D65EB940594BBA1FB47AABED729EDE4 +:10C7D0008C325BA6A3541B37D215707D1B6A7FE990 +:10C7E0002CDC5EC33FBC8FAECF353F89E738743158 +:10C7F000DA7A7F19A59C730AB1AF543ADF60E57A03 +:10C800006243AED18774BDA198DB592A1FABF247B2 +:10C8100085BF2A87D47B7EEF28F695514E5E3687FA +:10C82000E4EA99E5786F07D49E7317C37B8956FABB +:10C83000FEAE721FF194626FBDA7D85BFFA1D85BFB +:10C84000EFA3BD05F986518308BF37142E76DD08A6 +:10C85000F31A902011DF143A4E4CC4EDAF71192732 +:10C860002C7DD96111D1A20EE3058F34F27B4936BC +:10C8700097ED9815F159CF95F92C6B766934BBBCBF +:10C880007CF2E37AD2D13EE4EB7B55B94F794C99F7 +:10C89000FF7165FE6F28F357ED8F4943BE32A1BC8F +:10C8A000DF10AFEF477E29FC29A7D0B9A85079B592 +:10C8B00001C408E9EB2291FC9F2078E76AE4BD25DA +:10C8C00020F7F54E59C9681EBFDB6076572C467CB1 +:10C8D0004E6614A79DE8AA27B96503B94572B3F857 +:10C8E0005CEB6CCA473883E59E518163B1CB5A8EAD +:10C8F00072BE38464F1F5724A4D0BD5BD5FE0E1D17 +:10C90000F772F00C9567A682F55EE2F3FF47726C52 +:10C910002CE3E38EBD243AFD5CDE1C4F2679239187 +:10C920007C0AED5F95376F63CC6420BE4F64A1FB3A +:10C9300000770A614E84E79D287C303F97D17DFFC8 +:10C94000C18A3D6757DED1014EA1B8CED84EB0F5B1 +:10C9500083F87AFC2553F71B6CDC8E8FD6E4279A7C +:10C96000E235F54BACC99AEF93ECC335DF273BB208 +:10C9700035F9EB324669EAFFC259A4C9DF50305994 +:10C9800053BF4C2ED3E46566A577480E36ED1EFAEC +:10C99000B11EFDA7B6A11FA7F5864FA1F1F00B0EA2 +:10C9A00060E1B5A38B67E80046855187EF4C86FCB4 +:10C9B000C6D19367E880EF0A071FFE3A195868D37B +:10C9C000E8293C7FF5E1AF5320BF65F4753C3F8615 +:10C9D00091F0DC3A7AEA0C2FE0591CEA797434D0F1 +:10C9E000F12D97EA8FA23DF8C765D3E6264BF84EA6 +:10C9F00040596206CCE76C8AE761FC7E73ECAC15AB +:10CA0000781176FC77F5748FED37A379BB8E8BFCAC +:10CA10005D8D8E8BFC1D0DBBC8F1F65353F5BECB5F +:10CA2000040E9A7EDF5F11647EAF05FDCD3969DCAF +:10CA3000DFC414FD4D4CD1DFC414FDCD397AEE6F47 +:10CA4000628AFE2696A3BF89E95B4D32A5EF34B911 +:10CA5000286D6F7253DA7DBFE029E76A3D0A38EF2F +:10CA60004F8B5B98C3E417114EA1E74A3AF49D4FF0 +:10CA7000D07ECA45E6C0FB1287224E3970BFAC3962 +:10CA8000CF44742E74B63B4CF0BD3097E79B2FB665 +:10CA90003B507E611EED9E8EE8B66C94BFCDB51600 +:10CAA00027EEBB355FF4C7239F14D61BE8DE4C711D +:10CAB0006727C5E90A2DFCBD844311C78E28E39181 +:10CAC0005CDA7991F9457C27C7DCEEB02AE3603F58 +:10CAD000306E32EAB7C225302EF55BBF98FAA9B0A6 +:10CAE000748F2B848C6BFAE171270A41E3A67631AF +:10CAF0007A1701C77568C6F54B743FFCA25FC27810 +:10CB00006147B4D38E714D355F8CDF21BF45CFDFD8 +:10CB10005F2C74F825D493B8BD89EF5BC681D833F8 +:10CB2000D3790D1FC965A84771B99D5D7C9D179A82 +:10CB3000FC0B909F8A957760C08CA57B9B4C0C73F7 +:10CB4000A2BE2891BE3B363817DF39E3EFA0151B94 +:10CB5000DDDB901FEB745CDEB01833DF57D0B5CF50 +:10CB6000FF15D43B193B98EC9504FB4B2C7504B492 +:10CB70005FE4CA44BBE3245B4F72687594E77F8F20 +:10CB8000067ABE31B35E50F427F5637785EFC0FDBA +:10CB9000888E5786E5211F4D333A5E64C0BF7F1FE4 +:10CBA000DD44FC3C2DCA91872FACFD7DF40A9E8F9D +:10CBB00073BC883783ADAC694671FC8F3F2F45F15C +:10CBC0000D749AA70A3AB47FD4735376D1133606FC +:10CBD000E054EBFACAC0E7D769C07870D41807C12F +:10CBE0006FE06146E7983A2747F876E07EDF80FA03 +:10CBF0006C8C87B24C471ED64BD277D27DF28EEF2B +:10CC0000F8FD27A819795350FCFE898392ABAFF841 +:10CC1000E3C931DC4E5D946A598778A8B39B4C9484 +:10CC20001EBC48E78299CE9D8AF16BD9D0F77BA9CB +:10CC3000AF8EE1FA2179A54131024174C294E53009 +:10CC4000A6E6BD0CF4D0F6BBC3BADF8B037032434B +:10CC50009AC8F3DE1D8F17EB34F565ACDFFD1DE3DD +:10CC6000F4ACA7BDFCDBCD8F2F4F55C6437A99C7D7 +:10CC7000C87F0CD53B6B0B6DEA3B3F84E7C763CCA9 +:10CC8000DBE93D5249798714EA5A314E11CEE83D2D +:10CC9000AEC1BF37FB9A819E769A393DA78A3CDDAB +:10CCA00029F2FAEA3BA5EABB6BCF147A6E2BCCA330 +:10CCB0007EFCD48FB4371BDFCB88676D34BEFA6E31 +:10CCC000945A2F01F420092B5D673AE2AB5012FB16 +:10CCD00084E7E7638AE6201D5C68F2B24F82F4CDF8 +:10CCE00085F0C8C660FCD549DAF75A3F1F3381DAB0 +:10CCF000A9ED6B1B27B24F2878E9273AAA4D156991 +:10CD00001FBD4E62AFE23B9C20590DA897D576A778 +:10CD100040DEE278EF82FCC5F43D90BB9FE8D13E57 +:10CD20009D4EE9FB4D1E2A3FDD544D69A0A99ECAC8 +:10CD30003F6A6AA4F496DB2372917F16ED5FC63ECC +:10CD400009A2F7DA36BD2710943F55D4371DAD51EF +:10CD5000E8E85472DFDF9F1CC3EDBB53E3383E3B72 +:10CD6000C0DEC0F7DA802E975B6DFDDB1D1DCAFDAE +:10CD7000AEA3E3F9FE65473CCF2F1FC3FD6E596498 +:10CD8000ADD8FEE87803EF3F45ACC6EFB28DF77B38 +:10CD90002A5DA477A47E35B1E8FE31583F16CA73E8 +:10CDA0007AF2A7AEE2DFE541BC5C9DAFFAFDB64288 +:10CDB000ABFAEE613A7FCF8FDFF7027AA7FED5FAA2 +:10CDC0006326703E0CADEF4BE5E7C943E1F1A9C224 +:10CDD000B7C4176867231F2407F1459D83F842A550 +:10CDE0004395FED6167238A71A153A0FE7E7EE07F5 +:10CDF000A32E847683E3CCB48F20E3BBCBB09E9D7F +:10CE000082C22FA1FCA0BC63ACF283CA072ABD0F6B +:10CE1000063EE3EF34F3758C95FA795F5859477BFA +:10CE20006CC45D84D7837A2BEAADB1127F2F79B0C1 +:10CE3000D8F5CEEDC89FB1110E8C9196ACB2D4F757 +:10CE400025C73EFEAFC243950BFDC0A3171C0CCAFD +:10CE5000BBC33F120E24E7508E23FDF621B74E8C44 +:10CE6000B1297617A7DFCFC7C86F221D7508661DC9 +:10CE7000DE7BE830F77D5FF0E878BE0E958ED61643 +:10CE8000324A07E33A87F6967BEA7ABAD7790723DC +:10CE9000F9971AC6CB43F1ACAE2B48FE9DC179A9D8 +:10CEA000F0640CEC1FE827A1C642EFE8DD56E8E08D +:10CEB000FC36F0D3CA0DAC67FD358A3E7B4C94F846 +:10CEC0007BC88A7EE92E17A49965991ABD4347CF7E +:10CED0003A5FE1EF8AFB45568DEF72A36F1D1C1779 +:10CEE0001F52C8E543D7F43C11F7132FFCD542F786 +:10CEF0008B2F0CEA3C8DF6CE85563D53DE239B2AC4 +:10CF000080DE9D8B3E130CF9A5F29EF3E7E8F70E49 +:10CF1000837A6D174FA3BDB568ABC44C789E60EBA8 +:10CF200037B7203DCD7B454FE7999A5B371E477A4F +:10CF30003CB74FC0E76FD9857D02C5316B5B227C62 +:10CF400066A85F0A79AC7FC76EC9C7E38B32C53963 +:10CF50006A94F13E31D7A5A05D3E71EB5D3A84FB4A +:10CF6000BCED028B837E8FB4DE790CDF1D39B78D6B +:10CF7000DF2F6B3647EEC0F9974AEB0C83A07CC1DC +:10CF8000765E5E6329FD0CF743173CCD28FEB36047 +:10CF90006F04F98FF35AF41F0582EC8EEA6DDAFC08 +:10CFA0007CD666403A58B0535B5EB307F241F279E3 +:10CFB00050A1122F19CEB2295ED2C2E307AA7CEF8C +:10CFC0006D5F7BB91C6D50DEFF667F89A5F70F5F33 +:10CFD000F926E9230BCF9729F93390FFEA1B8E1727 +:10CFE000152E75CAD85FC5B3DC365867DD2B662BA6 +:10CFF000FAED7507CE46E279B04561017A1799BD21 +:10D000002C59D1DE7B60BFE445F8D61E343F89FB46 +:10D0100098752F9E30603CA174DF62B2572631EFC5 +:10D020004AF49BFDA2C8DA898EDAE97D5F2677CEC5 +:10D03000C37E2E1C305BD10EA87BF94FC76EC7FC98 +:10D040008B02DDA7BC9018203A99B755A27B430C00 +:10D050002DB4FC1E3A9110AF88E7B6287A8FE50E02 +:10D06000C43BE219F0EE48463AE171D0794F4BF4F7 +:10D07000BDB9B5D980F5CFF9387E55BC974A4B0973 +:10D08000CF0B1EE7F89CB875D7E630A483A7F564EC +:10D090008F1F817683783B0D1D185EE1FD5FD8C53B +:10D0A000CF9177D3C10163371DE03C2F4707C0A75D +:10D0B000A4F72F47079DE89792BFFFDDB9C7D00EB1 +:10D0C0008FE0E787D5771BD5771A072E3C7514DFDD +:10D0D000E74AB3BF407677A5ED8BDAC58CDE099DB4 +:10D0E0005388E74B26BFBD02D17772CAB3D9142F3C +:10D0F000D507766DC178437438C5C73A92CBB6E18F +:10D10000FB98C5B66F93F6C23A16FDCE48E711EB11 +:10D11000157EC63F3C07A2BE4B0C78A7F319B50796 +:10D120008DFC5CC63EEDFBE11DF19CCE4B0C9D954C +:10D130008BD14F80FE701C41E6FEE9C283FC1D4589 +:10D14000D59F5CA8BEA7B847FB6E83607D9BEA3D78 +:10D1500050984270181A37D68176797339F3840D56 +:10D16000FD217DC1DFA97C5CF18BFAB527FBD11BCA +:10D17000AA1DC9BC21F7DA15B97547019FE3D1BBD8 +:10D18000DFD0E17B8C1D3BF9EF3BCC3F08F22A0658 +:10D19000F719F51AB953A7D4FF14E90FE076DE5B4F +:10D1A000FF922805CB97F78BB19F9AA7793F7548D7 +:10D1B000571457F56F0E83FEBE6CD333E497054CBE +:10D1C0009137FB23286ED44BBEECDCBE12CDF7505A +:10D1D000BA5A0876262E2294BEEAF669EB3D5DA87F +:10D1E000EC7B0E67D7E0F9FFAF31E090D7235FBA51 +:10D1F000DFE9678E28E4EF6E7D2868EFEF0F6B059F +:10D20000960FEA77B8CFC463A44AFEEADD564DFE16 +:10D210009A36BBA6FEB5FB1D9AEFD9FE0CCDF711D1 +:10D22000C79D9A7C5E7B81A6FEC8F7644D7E54C084 +:10D23000A5A93FE6BC5B93EFCA84F5F461CFA8E9EA +:10D2400024BBA0A93FD961D6F47F5D46B426DF6533 +:10D2500051E0A3D899AAFDFBA7426EFF86A62A7CBF +:10D260007FE1D48EA3FAED371468C72B93B5E35D45 +:10D27000295EF01D419D9EFF7E02A6F8FB09BA348F +:10D28000FEFB0998C7DF4FC0147F3F01CB7FDDE471 +:10D29000A4FCBEA602CABF047E09E6F7839F82E90A +:10D2A000CBE09F60F9E5E0774C19F7B832EE1BCA86 +:10D2B000B83F154E6F29FDBDA3F487EF0DEAF43D8D +:10D2C000DF6B5D79E225E0E322DB67745F596E086E +:10D2D00094621CA3F37589E1F967E6F11D6F8A4139 +:10D2E000FD3680A19DC4DC9D6FE23E6EDD8B43ADBB +:10D2F00078AEEF81FD7F7807BF5FD82751BCE6F09D +:10D30000FEB391D8CF9797C2E9300AE945C8D77CD8 +:10D310002B507E0D7CC7736793F74ACABB676DA419 +:10D32000EFBE4C55F33EBA2FEDDEB3D780785AB836 +:10D330007B2F7D7F1DF85AF37DF776CD772BD6872F +:10D3400074A1CE477185CFF7ABFDF9A97E4D2A7F39 +:10D350003FFEF3DD47568E417DBCB76A00C6B51768 +:10D36000EE39113BFB07F0F1D54BCF66A21EA83D6D +:10D370002029E7D1787FB507F44A9ECFBF26756F85 +:10D38000299E37637B04BAB3F4255B4FE7C416EEDE +:10D39000DF5583727661C6ED7A8A7FB5494ABC83D0 +:10D3A000BFD3506365DCAE6BFB3A12DFA9FF7DDBB8 +:10D3B000D1EBF11E74C7C123F45E4CC73E49E34F65 +:10D3C0008D1DCBF13B762CF7FFBEDC772412CF0905 +:10D3D0003ED07684C35DE7A7F51F56F21D9012BCC0 +:10D3E000F74BB4FEF99724CDEF01B8C071A1FBCD86 +:10D3F000FBD322705D27DBF878D3407D50796AD566 +:10D400001C9CFF1BF6F23CE57D32FADDA18EABAE33 +:10D41000DB857276619BD4E779F739D82FCCEF980A +:10D420009ED3E9EBA92F1C1B04707FC335209B748E +:10D430008452AF622CD79BA5064F2AEA91931647D8 +:10D4400004D2F9FDAEA11188DFC39862B9EB49BAE5 +:10D4500007BE601F1FEFA4B53D12E9EEE4BE1152F6 +:10D46000F0FECB2DCA7ABAE9BB1B6F5EC253B56F13 +:10D47000BB05FBE9C11F2F9F36D64AF5DFF09DB8EB +:10D4800005EDAC9319FCDDC0630646FEF5C23DDC3C +:10D490004E3E7970F0F6E0FB59D3147C7464F07D55 +:10D4A000F50BFBF54ABDDB77314D3D3DC7D74EED62 +:10D4B0007CACBE330FA17D5EF3B844671D6AF4F502 +:10D4C000B1B8FE4FB769E757ADC0B946EF8F8D0DC4 +:10D4D000A2D79A03DD7C63213A3FA0F28983F0A9A9 +:10D4E000E2F16486C4E765E7EFF8D5ECDD4574DD6D +:10D4F0003BBEC4E3B783EF313929BE74197F5AB5F7 +:10D500001B82FC2DFABD23BD6B689E98D2631F9CC5 +:10D510002E941F1A9B877E989BFCCC930CEC5B1877 +:10D52000B316EDEB28FA1D89CD386ED73E3DBDFF11 +:10D530005F6B3AB000DF23EF7202A3C0BCBBB6E959 +:10D54000BBDF67463B779E62E77EEAF0E44BA07F55 +:10D550006B9789B4BE9A3D920FCF175C50E4DE57AB +:10D560007B936F407AAD392E59D13F9AD896FC7093 +:10D57000612EE977B257EBDAB89D5CB75B20BB58F8 +:10D58000B5436A153BE49C62079F5BD6C9EDE35740 +:10D5900004B611EAAD0D037B04E65D9B3985ECDA38 +:10D5A0005A69DDCAC10E3C47A5B51BE61F3C44E7DE +:10D5B000AEC0CED1942FDCADCDD7B669F3AABFF8FB +:10D5C000D2D86E3B6338FA372552611CF2C39B0AEE +:10D5D0005E557FE7CE6B9CF4FB270FE81C53D4B855 +:10D5E00004C26BD12B2FCCC779FB6AC29CE47F3479 +:10D5F000FE96E0DAF117EED774E0DE1BF233E3F0CB +:10D60000EDD8CFE97C915EF0E1EFBA2C425D81FD6F +:10D610009904DF328C3B7BBB22493E29E7081ACABA +:10D62000B9FF2A630C18A6B27E2CF7E743F5EA3857 +:10D630005D408A0E921381B12954AFD8C0CF57DE16 +:10D6400019E124FD36C4C4EDF521266EAF0FD17566 +:10D650002EA3DF851824F07D8EAC9769FF606D9D49 +:10D6600085F617047B950EE1B17650950EE97D881D +:10D67000B52D03FD3A355F8CDF337BEC83528B474E +:10D6800087E3EC8C17947D04AE4FCB74567D749079 +:10D690007E656C99667EEA3DCC9F7D7E56989FA5FF +:10D6A000677E80EF286CFF75AE93EC86A432F5F7A9 +:10D6B0001AEA492EA8F0FC12E8BD187045776C8173 +:10D6C0006E6AB61D22FFB296B5AFC476A5917C1DD9 +:10D6D000A506FEBE5169184F75E3B8FC2A51D2A5C4 +:10D6E000E3B4F6C39171B27E1CA43BC6B94DE3F21C +:10D6F000683F9579617D0D6FF377D643E53E9413CE +:10D700003D7D0D7C88F26F46BD604DD5D8699CBFCC +:10D7100016F1A26E3E5AF8F693C427EA39CC6AC6CF +:10D72000F97B66A3D99A1AC4178B90DFD0DE77C332 +:10D73000BF7C8C13F0BF6AEB7C3A97E9698CB5A289 +:10D740005FB748FA92F6257E2CDF2DDAAFCDFBCD00 +:10D750009CFEFD1102F94919E3BAE30DC48F490A91 +:10D760007F6CF708740E60FB773A1ECFAB10287EF3 +:10D7700077331436DA944962BDEA22BA4F7233E342 +:10D780004763594B8CF2BB3D31B46F7993B2EE9B3A +:10D7900075FE4328578EEADB92319E74B4D6E4C4FA +:10D7A000FECB591BBD6F5AC1DA293D155EF7A29F0A +:10D7B0003AF72622DDFDC963A478D6F6E53B225070 +:10D7C000BE67B1E556DC4F0450ECC6B701FBB3733E +:10D7D00042F71DD5FBC4602FC7217D02FE27211D06 +:10D7E0009C07DCD8737AB75FF8C71723117F5F2CCB +:10D7F00079E1965B19FA5F9DE4472DA85F46F75DD6 +:10D80000819CDA33F27BF0AAE25DC55B375E1DF0E6 +:10D810002F18AFB0A6048493F46519C9A57F91E8C9 +:10D820009CD6E5F0AAC27DBC829F3B0E70F9158A9A +:10D830006F150FB7E2BBF54349EF6E233C3123C9A7 +:10D84000CB507AB81CBE8030E93CD9C41823F9A16A +:10D8500083452E4F07CF13285E793BF3BC1280F42B +:10D8600096F0F7F5FCDE0AC75B8582B73F31DF2F04 +:10D870003292FF71783B32CEDD346E606FBE0DE5C3 +:10D88000D3FEF8B2C6E1FC37555FFA18F263083FE1 +:10D8900087F06B371E9DF02F088F9EC648E2CB6E37 +:10D8A0007C4B7BAE4C2FE27F308EB55FF0F993AFAF +:10D8B000805F0546BFBFF8F838ADDE54F1A6C2A5BB +:10D8C000BFB8E007CC7FD42AD0BE0AE7E3BB8D7493 +:10D8D000FF43DD5751F74F5E19C7F55C68FA01D871 +:10D8E0004BB85FB526E3E440B4334F19D47EF8FE5D +:10D8F000EF07CBDA13F1F7B63E28E2E92903FFDDA3 +:10D900000F352F87F1B8E407F1462FC2E90361F81C +:10D9100004D4331F08F75CCFF3710607E6CBE32688 +:10D92000E03D90537A358E79BF127FF0F179948F74 +:10D930002CA67A02FF5D4A07FEDE1DF62B0836177D +:10D94000CCE783BBD2E87D9DEE7D8D71DC0E7F46FA +:10D95000594777DCFF5E81E2FE335135E1FEC48436 +:10D960002D2E7C87F3F47D43B369DFB4413B3EEA5F +:10D97000FD648A976EE0E7FE2E75EAAB82F45BB732 +:10D98000BE2DBEC8CBE7E4D1EF8CA8BF4727DB860E +:10D9900073FFDCC77FDF50D5675DC75FB004C77317 +:10D9A0003F53E2DFDDF9E10F2605EBC3434FAD4DF9 +:10D9B000C77EAA0DDE2CA7057F87EEB124B45BAA33 +:10D9C0009F5A954EF6F4530FA4A35F54BD636DBAEE +:10D9D0004CF9700FF9653ABEEE2F9E1B45E7F3D464 +:10D9E000FEF6CADCAFA8301D2A41BD3DE5EAAF56C0 +:10D9F000E0FE41DA7D02C5FF66B0F615A8672B335D +:10DA0000385FB11613C97FE88FF66B770DFFC54EEF +:10DA100094076F649CD5CF817A123E203510DFD5F4 +:10DA2000F2ADA3DF095CCD7F27B0A77E22EDFF56C4 +:10DA30002D17E89DAB19F5FC77F3A4F1D104C75974 +:10DA4000ABB38FD1FB574B79F914A36FDF49EC6768 +:10DA50008B81DF3F64EE94E0FB7092B25F38739D80 +:10DA6000F27B71CA38699B63B707AF5352F61D59F1 +:10DA7000EA7724DF6E50F03275E98957EDD0EF5424 +:10DA8000BDC73C1EBEBFB3E95CAA9F611CF4333A1C +:10DA90005F9866F03C3A1FD7BDC34871D2DCACC179 +:10DAA000521CD4CF5952B411D3994BAB1E9D8F72D7 +:10DAB000B8D594CD8F35F2F935084E11E5F491EDD6 +:10DAC000B7CE42B89DDFC47FFFAB61FB30FADDC249 +:10DAD000FEE4DEAF9AF8EFF93DDD64A2F4D9262B1F +:10DAE000C3A3EBCF35D929FFAF4D0E4AD9F43CCDB6 +:10DAF000EFD8F4D7DF884BE1F4BB73B9ABCDF43B7F +:10DB0000880D4639753CC02BEDAADA1D0F28EBC2F3 +:10DB1000F7B8B2BDC913110EB90F2C3E86A6B37566 +:10DB20003CDF977DF3E4EA2414D6772C3DF3C47CE4 +:10DB3000F87EFB78F7350827D3B68B14A7387260C8 +:10DB40005525C2BB7A8791AF4F59F7F94DE9718FCF +:10DB5000627CF9753DC50D166D3BF3C4030C7F87E0 +:10DB600077B12198DEAF74BD578FE77EE6E5F8AA5E +:10DB70003F38FC78BE5A9B44FCB303F82AF3A7F362 +:10DB8000D5A2A5CB087ECBC6BB6F42B89DD77B93F1 +:10DB9000909FCE0F1F4B74EE7D4520F8AB72BCDB1F +:10DBA000AF56E0BF506C5B5798DC23C7BF61B90428 +:10DBB000DF43073E4D47FBF99BFDE53FB8EE97601D +:10DBC000DDFE6118AF33511AFA3DDFE019EA84F542 +:10DBD000E5F7F33EE8D2F16AFC9F9F53C03F213640 +:10DBE000F89D21E68D82F9D41C14FC6159A8CF263A +:10DBF0007DA643BF11FCCF8F34E78C19FB28489FCB +:10DC0000F737DFCBA575D84F5A8FDC1DF99EC8FCBE +:10DC1000417A7B54208CF983C6EDF673A0CC40FB8F +:10DC20004EF12417106F782EECC281E13B30FF9942 +:10DC300081E3F1C24B604FF1781093F27BD6F9D9B2 +:10DC4000812FB250CE86AEB7EEE52F883E6AF6AF92 +:10DC5000BA28D0FA277FA6CBBAFCFA0F3DF54516B5 +:10DC6000E2EF337D201FFDB60B864016E2A1EEB732 +:10DC70005C9EFF5838A8E5F3571BE8F73AEB04130E +:10DC8000D14989F425C51F2E1CE7F187BA034F92AD +:10DC90003CED3AC8E3408BC4F6D2388C9BD49F3914 +:10DCA00086F2ACCBCEFD31E89FDE712B1CAAE84199 +:10DCB0005D6712DEF73BD84D0FDC8F3C8FFC3B0CD1 +:10DCC000FB69A3F3BD2C2B9CA15DF139F2F3307CF1 +:10DCD000BF307925D2F979DFC01C948F6F66FDAD16 +:10DCE0008EE286BF0FA77BB2B56D92E69C79F73ABC +:10DCF0007C123F70C454FB299CC9C1E7B90C8E1B30 +:10DD0000C86E7E83EF132EBA8AF3137B99F353ED1B +:10DD1000F243067B507FBB157E52EDC829BFFF1B27 +:10DD2000F1E5B38532FD04D54FA5C7FF9FFEF74C43 +:10DD3000FF2F4133EC630080000000001F8B0800C0 +:10DD40000000000000FFA55A0D705455963EEFBD2F +:10DD5000FE4927DD4913421208840642881A6203ED +:10DD60008172D6C4E9FC6E2033BB016B2DC4088DD3 +:10DD700022249D7482E8EC6AB96E1A02AC6475368E +:10DD80008C59471D479B9F8028EC769440C0A00D7E +:10DD90000ACBA26B45AA263A555B54ABAC0EE0A663 +:10DDA00023823BD6E2B8E73BEFB5DD1DE24FEDA69F +:10DDB0008ABA7DEECFB9E79E7BCE77CE3D8FB45247 +:10DDC00022CA226ACFCD082A0AFFA66EA245446D58 +:10DDD00029247FF641451FAFD364BC7D40A3C958B9 +:10DDE00093EB08CE9E415447DD269A45B4844265A4 +:10DDF000A471BF29F2CB5B79BCFE0D6D4117936115 +:10DE00001BAD6AB013D5A67A0B3614130DABCAAA94 +:10DE10008662CC0B952E9D4BF40DFE7E4A749B873B +:10DE2000994F222AD3140FF61B9D9C16DCC95D8BDB +:10DE300097FB1B494D98A7EAF3984F53087C82A3A0 +:10DE4000254B1DD868B46499233EEF8E37D2D60790 +:10DE5000314EA1D23B12F6F94B8F856821D117CBF9 +:10DE600017AA0F65F279AEDA037433518D76ED2976 +:10DE700085F7DD70CC4C5605FC67BCAFF239026704 +:10DE800034EA65FA52470A79ACCCCE4B1E0FCF1B51 +:10DE9000993B29D8C5E76F3FA09089E7B51DB1EE42 +:10DEA0004CE1796DE648B69BF7DD36F03B8B87DBBE +:10DEB000F6FEF72CAEB958CF4736439E1415FA6DCF +:10DEC00077F24F17917F60CEFB77313FFF694DF4BA +:10DED000ED37BD6721D6D7059E8FFD5A0EF6D58248 +:10DEE0006EA5F05627DAFD3CAF48BF9B6FF8DFE523 +:10DEF0005C5786B3387EBEF8395DA2A718BDF869B5 +:10DF00003EF702D68B46EB437659EE21967B716E37 +:10DF1000CE8E2E25719DAE5F8F76694B0ECB159DF3 +:10DF2000A9B81566154D0D6C76421F858AB39717F3 +:10DF3000475F7FB9742DF49B122CBD9DCF17B59010 +:10DF4000DCC7E2C7B69BB40479160F6A1EDC433403 +:10DF5000959A0EC9BD7BA7E23EA8BC61A96712D6FF +:10DF60008DBE7B2B6F195579BDFDFA7304CA757987 +:10DF7000CEB0A9C97D1B72D7E7E5ED80FED900C4FC +:10DF80008E4EA9FAFE1E95C7E7C7D7BF689CA74665 +:10DF90002BCE89F0F806C59DE31C679F58BB87F51B +:10DFA000BE86EFE945BE6FB42F753869CD6CA2FD12 +:10DFB0001DB942FF73874BDA504791F4BFD2E11687 +:10DFC000FA60C72D421FEAF0083DD05127EDD18EEF +:10DFD00006E93F0351FF8C70A020ECE2147C6D4AEF +:10DFE0009C1ECE1C434F499E3F9CA924D353149999 +:10DFF000FF70B83C1860FAA532A79C938DCAD1C0B7 +:10E00000FA684E4B2FA10CB4F9414A67BBB17B03B0 +:10E010001EB6FB3FD4EDDA4333C5CF4B30AF3AF3F6 +:10E02000CE46F8DBE52C2B69ACCFC31EEFDF63DEF9 +:10E03000E9D35505DBD13F68735BF9FE8757DC9464 +:10E0400001BD47FF4D238DB7AE285AB0B994E90AF8 +:10E05000BB2276CCFC6E6EC866BBC64FE65335B8A5 +:10E06000BAD4A4E38473B602FDB7AEC13E1B26DB6F +:10E07000165879FC4AB9F757D827A6F7DA29EB0AD8 +:10E08000BCD08BD9F5BECAF302FF6EA65E9EF780A8 +:10E09000C39D64DF47CB2B82B09BC545B336CF070A +:10E0A0007F76BAD9BC3FBBF57EC8E751D3944EC149 +:10E0B000319709B810C4FDF33E952E45EC306C71D4 +:10E0C0009932997F38B5222BC0EB4E19F77DDAB81B +:10E0D000EF33C67DBFC3FDD5DCBECBFD6887B81F5F +:10E0E000ED8A989E4DA385D05FF0A70D2F7944EF60 +:10E0F000A3F9A0A3665A0E3B5C023FD3F127BF8170 +:10E10000E578A25C97E36E037F866E6BE8D3D785D4 +:10E11000844F8B85BCB0FF4B589F609FB175F1F564 +:10E1200024EDB29B2990C2E7A0C3B620F4445389E2 +:10E13000805FCB0EE7082E6929B38ACF4F647A013E +:10E14000099ED2AB567D5EAE6B21FC857524FB8C9F +:10E1500004D58099EDC49F395498C9F28E187E1663 +:10E16000A30FFD4913FCF6CF679ADBD714FD7CFEA5 +:10E1700065438513B05EB1A9B033FF4E7DFCACE1C1 +:10E1800087FE99063FE33C9412CAC77D448F1DCE9B +:10E19000BF87E92E7B78AD1E07C28582DF142E5C17 +:10E1A000069C5442E7C84DD477FC7DAFE927D047A1 +:10E1B000E879D0FDC77FAFD34ADF3967E2F8A450D2 +:10E1C000BEE204FD8141F73D3FC19D409B5F398721 +:10E1D00071CBA6DF7BAB27336E5883A73B6037FF3D +:10E1E000A2DB97ED40FF27D05BCB112BC12E2B0F6D +:10E1F000F47FF60A8FB7F43BDC80FBA86786E8BBA8 +:10E20000F3C8DEC7616F237D66F187AEFDBF7BFE7D +:10E2100011996725985BBD35544ABCCFD1E37FE3A4 +:10E2200035619FB4D015D06F579C1739EA27EAFEA5 +:10E230003D54F1A93700BDF51FF86BC4B5FA0C0ABF +:10E24000C06EE965BE4766E47BF5866A2AE171C760 +:10E25000D04AF06F7BC9EA869DFA5ECDA9841F5F24 +:10E26000F3CC14FB6BBEB13B1F71573DBA6FCF238C +:10E2700059986723C8DB9EC976C47AF5693B16DDD9 +:10E280002FF7B76BCF6F20F73E1BED643ECDCC036D +:10E29000FB35EF991D0CF0D15EFBFAE395B8871AB8 +:10E2A000EDB93DE8BFB2DBA6420F672D9E8C72F838 +:10E2B000E159B3BB17EB0CBA7978A22E4F5AA4568A +:10E2C000EE2FAB3B1F71D737F1E1BF80DCF55AF77A +:10E2D000F3CFE23C7BAD843871611FEB8DD75DE8F5 +:10E2E00035CFC72D8FEC7398602F9794EE95CF8222 +:10E2F0007FAF3EEF92AD5BF419E89D43D88FE711F5 +:10E30000E2F225657B52FF85DEBD255ED6DFC5972F +:10E31000EA8BBD09F61BF317DF6E6B527C14246089 +:10E320005CF219BFC919203BC7DF6683BC78E89946 +:10E33000916729BEFEE27E73D8C23A6AB6D2E694ED +:10E34000CCB83FF8F2FEBC0EE7F3A93B0A91C73404 +:10E350002F88AC845F5CB0514A2ECF7BDB885FBED8 +:10E36000831B972A25DF2D4F4D85EEC75773F53850 +:10E370007675C0160C28DF1D8FFEA3839CEFCC8E14 +:10E38000D377AF677E29717E6F5B42AD6EDEB72DAE +:10E3900053C78F733C7F3FE35895B1CFAA8792E76D +:10E3A000DF529129F6D3668914220EC6F82FAC8865 +:10E3B000E15AA4107835765D3DD213E0C8CB8AE0EF +:10E3C00088EFA0F2A1966EA8343BAE4F5F4A20A81A +:10E3D000958C7F0FB98B8C7B605EEF55E87EE5DB1B +:10E3E0006FF3D8984F4B6A241D7953AB23928E7CE0 +:10E3F00068E4A8463B8DEBCB8AF19F19DFAF494615 +:10E40000B83F64F6D8C6DB8F8F433C6F1D7EB32ABE +:10E410003EA9D0FDA669204DF623676411ECB6E94C +:10E42000B9E47538A733C11F470676657B13E28FC1 +:10E43000CF903BAA7C287E13FDFAA37CD8814FA500 +:10E44000CD0AABF622AFB1650A4D293A1DB0B1E550 +:10E45000FBBEB4A7C27E2E5E6D153F1E5122827395 +:10E46000B927AE0A3E8C982382738ECAFF11FC181E +:10E4700099105909DCCAADB4AF96F1C991952E1E19 +:10E48000FFB2C2A0A791E40385273257034FEAB534 +:10E49000D1B711376997D9093F89E97B9DA127A297 +:10E4A000C7863B78FC0F41B30BF1614EA562E40BCC +:10E4B00096F8F9B5B83F8D90EBC041F86793DDDD74 +:10E4C0002BA3C1FDAF201FBC33DBDDE5BA5E6F328D +:10E4D00087E5CACAFC6A2DEE293BDDFB8F15CCDF30 +:10E4E0005F1CC907CEB1B54B1C6A7BDDBA13FB4775 +:10E4F000CDA37B805F171CDE272B589FAD96A1AD67 +:10E50000A52CD267E6C829A4F84B606F8223BABD58 +:10E510008D14EFB2089F1E562AEB6797710F944B2C +:10E52000B403F6A1E8F7FCE6C0ABEF006F468666E1 +:10E53000094E8FF5A70B034FA603373EE0F81E9850 +:10E5400013EFFF60F55E0BFA97BFB8C312E1F69EBA +:10E55000CDC9E7BB7CEDF60CF80B3D9ED00F7BECF4 +:10E5600049A6C7EA0576194EF28380E8FD9CC729C3 +:10E57000F2B7540EB5410FDFD2CB98D612E8136331 +:10E58000E831F3A941CF1FCE7948F8B64E0B0F43BF +:10E590006F2307CC047CEFE4B826747F5A10EF1A7F +:10E5A000F500C7AD2C3D6E215EB4A40FADC4BD8C8B +:10E5B000F45B9D98BFE9C8A7F9383FDB633ECEDB2B +:10E5C00072E47036C1CE8DF704C7C76C8CB7F41FE8 +:10E5D000C9C6BB24D6DFAA860A211747B812E0476E +:10E5E000ACDFAF850B217F8B325482F128E496F9A2 +:10E5F0004C6BA049CED1AAE87E4F4734C1F9B1F7A0 +:10E60000F651856EAF8C0F25C807371DBD5412B16A +:10E61000C7F1A0D9C09513E82FD6FDDFB9C8C0094E +:10E620005EDA0CBF1F0727BC31DCA3F516C87DAE30 +:10E6300042973BB65EF8CA3B2320E36DAF5D2A9953 +:10E64000598C75C63C4AC0A359717C010EE40A0E70 +:10E650006C3267F3B97CCF2BEE4E5ED2DCB8B1964C +:10E66000A7D33AD3FDB5D06B1305E45D3756AEB1F1 +:10E6700076F470857EBF3E557F8FFBF628C14E969F +:10E68000EB22637DEE7CC19B30F0675DF5C65AF8E6 +:10E69000DF7D597E4BE2BBF987F8AFED49A6D7ADD8 +:10E6A000DF589B338E9FFB1EDA7E6A125DCFAFD997 +:10E6B000BBA336DB757D7F4CEE8BB6989C95E64907 +:10E6C00089FA58BEB17612B7EB52FEAFFAD0CF7DC1 +:10E6D000F188358CB8CBFAB5E0FCB7FD71BD2509E2 +:10E6E000B77F805F33056B9D33BE5BFEB16DAB12B0 +:10E6F0001E56804FEC5FBDE267EC3709FB6DAA1830 +:10E7000053A7685A3D1D793779574F4FAC538C6DDD +:10E710001928A7A8B788BD49CB7EB8D23D8E3E62E6 +:10E72000F36FAED4649F4D861D4FA96F79E6151E19 +:10E730007FB9CC5356C97E55AEA992BF8FDDA7A62F +:10E7400052CF0F86B21DBF803D4507CD4EF849B967 +:10E75000A6EB334FBDFC2EFC312FDBE1EA647E35A6 +:10E760005569FABC633627EA40D1635FE57BE0FF79 +:10E770005BECCBA5CE62B2D3641E3F953B57F03D18 +:10E78000B6CFC7C63E69A57ABED35E64FEFE3A53D5 +:10E79000B1E3DB3A93E41BC569C1D91287BF90F896 +:10E7A000161D5CE8D45CC0F7A01DFED6FEF57F67A1 +:10E7B000230E8F0CFE67BA0BB875EDD374D8CFB6A5 +:10E7C000818FD3810F27066639D09E1D7239D01FE5 +:10E7D000ADFBB816F3BA8C365E67308B9CB136F65B +:10E7E0007E8ED51312DED1CDD06BAF73DB2F4B6194 +:10E7F000EFA9DD8263FC8ECE44FC88D7195C39E337 +:10E80000D56512EB0C05B3F53A035AD4190ACC7A44 +:10E810009D0134EA0C685167403FEA0CA051670043 +:10E820008D3A0368D419D0A2CE80FE2BA86BB1BC60 +:10E83000514EDE50DFAAD1EC82FF0FF46A41E4F5BD +:10E840000F1CD3747A8712C47D7FC6FB230E46AF9C +:10E85000E875B028C75379E71F34CBFB201ADA5E7E +:10E860003713F7D6AFB97155171137D914DBCDA3CC +:10E8700027511F6AEF53DC1B5DE85F2E726C1B5C37 +:10E88000F87E23FA7BCD6ED585FBBA9A8DFA976F09 +:10E89000B057EA58D539C72C72CFFB15CAE1FDEF46 +:10E8A000B0EAEF64BFC6BD2CF7B045953CDA6F1DEA +:10E8B00092F74BCB8B8A734D421EDA7ECBE78213E5 +:10E8C0009DB6F49D90D71FB239D724C5578FE47DEC +:10E8D0007EFC74C18D3C43454CAFD5A790DF5E7B79 +:10E8E000013821F948427EB4D6D9FC33E467A45DEF +:10E8F00033E1FC7E7EE84E64F9D63D6DFE2892B091 +:10E900007F733099F60DF66DCD23C899DC8F4A03DD +:10E91000E2B23F94DC1FAA74647D92C63FE6D13C0C +:10E92000E45B75FFB4E6403FEF77B9DB2AF9CA61D3 +:10E930008FF77025FBF149B347EA2F278FD9E4BD44 +:10E94000757EFB9CA4FA4B8D3655EA1F1BCC8AC4FE +:10E95000F12BE5DE63B0CBAABA7BA5EE5295EB10A6 +:10E960007F8ED9E1D1F28637C077C35C97D4BF6A76 +:10E97000ACF40BE1C77E2FF73C68167FABE95482FD +:10E980002AD3ABC96D817FAD62758A3D99ED8F2920 +:10E99000EC0FAB78AFC604BBDAB05D91BC420A1095 +:10E9A000ACE795863E570DFEEB570AFBCBBD563DB7 +:10E9B0000FCE5355E19FD7C5718BE7DF475E0BFC48 +:10E9C000661DC755B41C675F8F70BF376D6ABE9EEA +:10E9D000E7BB72C07FF51933014F6A727E5EE8951E +:10E9E000785FEDFC84EF5B09DFA57D73D3F7E1A8C9 +:10E9F000893E49C86B4F9A75FC617DCA7BEB14EC6C +:10EA000055EA3E5E69CF743449BBA28CC4FF0B3417 +:10EA10003D6F2FE0BB72664ADDA20FEB6BDAED6E45 +:10EA2000E83F860BBB8DFCBE40E596E7ED4ED55B1F +:10EA30000BD329DC3F8D5BCA147E61E77CD4715C0B +:10EA4000C23F4F3DBBC0057D7C6977431F3539C749 +:10EA5000E6E1DD31CBE0FF7259C355DC97279D021B +:10EA6000D89F8F43DDACDF5A1C48415D3DE4D15057 +:10EA7000273FA638F1AEBF1E4FB76F71C2CF0A1441 +:10EA800027EAB7B5A9DD35D9CCBF76E60C37F09CBF +:10EA9000F155EA6123DCEA76706B5053F4B5A66C4D +:10EAA000D4F30DFF29F7A6544D8AF7D71B7E141D0A +:10EAB000FC221DF1F547D46D77837F806CEE5E8379 +:10EAC0003FECA0FEA66952BF8DD9D1E5FD393B616F +:10EAD0004753ABF4758D8DEF99914F0CDDE6CDC1A9 +:10EAE000FE2BD77CBE255BCE397EBD8C713703B83B +:10EAF0003BB65E16C3F13D46FD1D786B32EABA2681 +:10EB0000A3AE6B32EABA26A3AE6B32EABA26A3AE44 +:10EB10006B32EABA26A3AE6B32EABA26A913AE97D5 +:10EB2000F6DD8E87A41DEA08C87842BCB8B9EAC7EA +:10EB3000D55D17558D5377A5145786C45DF67BBDFB +:10EB4000DE3DA6CECAFEAE26F87BD5E0847B1E4312 +:10EB50005ED26371B338546BF1163C60177CF0548D +:10EB60008D5B6F8DE9CF2EF5D9CB649B8F7BA82C65 +:10EB70009A655251C734EE2356EF84DFE09CF01BB8 +:10EB8000B4F01BD3ECB8DFFCD6C2AE5DAAE7090136 +:10EB9000C9136C72BF5B3732AE307D2F399370E58D +:10EBA000B331B8C20F9A159063EDA095BA743F23A4 +:10EBB000F84F25377F9C3F0ECE84749C99961ADAC5 +:10EBC000877DA6B5A5BA9117B3BF8B9D9DDCA6889E +:10EBD000BFAFA106D9771CBC49479E7CEFC4D17357 +:10EBE000BFE1F9F7FE835DF29DAD93D72EFAFFE00A +:10EBF0004D4D95AE8F5F77847DE75996EA54B643C5 +:10EC00008E57D5162A92BAB89A2AFE50A33DAE580E +:10EC100080A377D33CDC77B5B5E139C899C3FE2E24 +:10EC2000EFDF2CA3BE6B1A6ADECBF4D9EC3C37BE07 +:10EC3000AB4DCD3D44050B804775C5B0ABB3D4ADEE +:10EC400060DD6319DEBF83BFDC5ECCA756E3FE96B2 +:10EC50005397B6B34BEE63CE42DCFB32ABAB1FF542 +:10EC6000862D6F9E907AC2B20CD742D41BB6BC7967 +:10EC70005AA7735CFD8A1BE5B213ABAB7F82F866C3 +:10EC8000EB3E9F1067FDA1094974FBC0E4EEF30958 +:10EC900071AE053FF89D4E3F534CB8AF5643945C60 +:10ECA000D5BB1DF2F9EBFE4B7FCFD3A8C4C9A7AAF1 +:10ECB000745C9C7482C2B0E7D1C50EF9FE973371C3 +:10ECC000FD3CD4DBA8D8B510F338AFFD35ECF8E245 +:10ECD000AD9EA7C127CF38770EF1793558C7900D73 +:10ECE000ED19E3BBE429D5DB88B6363D60927E356D +:10ECF000588AF66D35F420FAD92F76814FED93F3CB +:10ED00006E2C623ACF1A9AB7DE8E78E9D98DFE73EF +:10ED1000659E5EEC37B6EEDF699C8FE5D98779C3D7 +:10ED200085AAE4F9C337EA6DCC2EC2553A0E1D37D9 +:10ED3000FCA8AC93E4FBE758FB395EA51A78F9FD13 +:10ED400072B3BC47204F4C7EEA5E5D0A7958DEA361 +:10ED500086BCAF619CEC99528FF96E7B0DC87EC763 +:10ED60000D3B657C6C39AFE3A3B485A6E004E40DEC +:10ED7000531E0D4E80BC53768CDA5CDCBE1018B589 +:10ED8000217F78E16F476DE87FC14375E3E1BF56AE +:10ED9000AD09DFC2B251593F9DF71A9277C2E8041C +:10EDA000E46F854D6F59026CB7739EE67D93F2B7A1 +:10EDB000228963D30D5B9AFEA84AB087E9CF90E41D +:10EDC000AB549D25E3BE14DDFF7D8F3EA8C28E6E41 +:10EDD00008B2DC09F637E769D3E54812DFB0AC6B5F +:10EDE000317083F3B5A4713F3347BE3CC5C023E403 +:10EDF0008F8D8C37FEA6B7BE42BEC879DC187E8CDC +:10EE00004D311C26C45DEFEB1117FC2079DEDABB17 +:10EE10001ED98AF76D53E3768BBC8FD7F46D45DB33 +:10EE2000DAFA9E258724BF4C9ACFF965127D9D9C06 +:10EE300063E4687BF0F3AD39E3ECCB76702DD10E53 +:10EE40004E9A4337E0BD7AD29FEA0E481C09DD0F87 +:10EE50007CD9D96A7723AEECFA55A5D8D7B7F5A9EE +:10EE6000328FA9FA47D951A7CC0F545211FCE6872B +:10EE7000DA11E0E1EC243C0C48DD72894370AEDD30 +:10EE80007807B6AD714A3E12F3EB3653E8C3AD983E +:10EE900097E590EF110CB745A62C7C6F9AE2EE4AED +:10EEA000C82BCE2E9915049DDD190A83EFE8CF15E6 +:10EEB00037EAC8D5693AAED6A80DAD7B79FC2D35B9 +:10EEC0002CB8F15BE007F36FB7AC977645D94CB13E +:10EED000DB5C0A29FAFF67702DC47B3DF63DAD6708 +:10EEE0005BB0EF20DEFB4AF099B5A88FFE955DE49C +:10EEF0008906D58099CFD3338104B77BEE2C94B8A3 +:10EF000013A586C6FB91FF2C4F953A6ACF04D71301 +:10EF1000F86EDAD37CA3E4F587FEA4C7FBD1A5295C +:10EF20006EE4713DF35C1B71AE9E475D32FE9AA2AA +:10EF3000F30B3CA1EBA767A97ECE9EE64C799FC55B +:10EF4000EEA167876732BEBF5932BCE5D5A803186A +:10EF5000DF1F7B66703FB74F290D77DE073E737565 +:10EF6000795794B9E4DE4EDE79E3137B747D86F144 +:10EF70001DAC7D8923E9FDFEBFFE80CBB3202200BE +:10EF80000000000000000000040835000000000040 +:00000001FF -- cgit v0.10.2 From 94a78b79cb5f14c09a42522738d6694c6a1cdd20 Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Mon, 27 Apr 2009 03:27:43 -0700 Subject: bnx2x: Separated FW from the source. >From now on FW will be downloaded from the binary file using request_firmware. There will be different files for every supported chip. Currently 57710 (e1) and 57711 (e1h). File names have the following format: bnx2x--.fw. ihex versions of current FW files are submitted in the next patch. Each binary file has a header in the following format: struct bnx2x_fw_file_section { __be32 len; __be32 offset; } struct bnx2x_fw_file_hdr { struct bnx2x_fw_file_section init_ops; struct bnx2x_fw_file_section init_ops_offsets; struct bnx2x_fw_file_section init_data; struct bnx2x_fw_file_section tsem_int_table_data; struct bnx2x_fw_file_section tsem_pram_data; struct bnx2x_fw_file_section usem_int_table_data; struct bnx2x_fw_file_section usem_pram_data; struct bnx2x_fw_file_section csem_int_table_data; struct bnx2x_fw_file_section csem_pram_data; struct bnx2x_fw_file_section xsem_int_table_data; struct bnx2x_fw_file_section xsem_pram_data; struct bnx2x_fw_file_section fw_version; } Each bnx2x_fw_file_section contains the length and the offset of the appropriate section in the binary file. Values are stored in the big endian format. Data types of arrays: init_data __be32 init_ops_offsets __be16 XXsem_pram_data u8 XXsem_int_table_data u8 init_ops struct raw_op { u8 op; __be24 offset; __be32 data; } fw_version u8 >From now boundaries of a specific initialization stage are stored in init_ops_offsets array instead of being defined by separate macroes. The index in init_ops_offsets is calculated by BLOCK_OPS_IDX macro: #define BLOCK_OPS_IDX(block, stage, end) \ (2*(((block)*STAGE_IDX_MAX) + (stage)) + (end)) Security: In addition to sanity check of array boundaries bnx2x will check a FW version. Additional checks might be added in the future. Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3320e77..bc7eef1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2676,6 +2676,7 @@ config TEHUTI config BNX2X tristate "Broadcom NetXtremeII 10Gb support" depends on PCI + select FW_LOADER select ZLIB_INFLATE select LIBCRC32C help diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index a329bee..8678457 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -965,6 +965,21 @@ struct bnx2x { int gunzip_outlen; #define FW_BUF_SIZE 0x8000 + struct raw_op *init_ops; + /* Init blocks offsets inside init_ops */ + u16 *init_ops_offsets; + /* Data blob - has 32 bit granularity */ + u32 *init_data; + /* Zipped PRAM blobs - raw data */ + const u8 *tsem_int_table_data; + const u8 *tsem_pram_data; + const u8 *usem_int_table_data; + const u8 *usem_pram_data; + const u8 *xsem_int_table_data; + const u8 *xsem_pram_data; + const u8 *csem_int_table_data; + const u8 *csem_pram_data; + const struct firmware *firmware; }; diff --git a/drivers/net/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x_fw_file_hdr.h new file mode 100644 index 0000000..3f5ee5d7 --- /dev/null +++ b/drivers/net/bnx2x_fw_file_hdr.h @@ -0,0 +1,37 @@ +/* bnx2x_fw_file_hdr.h: FW binary file header structure. + * + * Copyright (c) 2007-2009 Broadcom Corporation + * + * 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. + * + * Maintained by: Eilon Greenstein + * Written by: Vladislav Zolotarov + * Based on the original idea of John Wright . + */ + +#ifndef BNX2X_INIT_FILE_HDR_H +#define BNX2X_INIT_FILE_HDR_H + +struct bnx2x_fw_file_section { + __be32 len; + __be32 offset; +}; + +struct bnx2x_fw_file_hdr { + struct bnx2x_fw_file_section init_ops; + struct bnx2x_fw_file_section init_ops_offsets; + struct bnx2x_fw_file_section init_data; + struct bnx2x_fw_file_section tsem_int_table_data; + struct bnx2x_fw_file_section tsem_pram_data; + struct bnx2x_fw_file_section usem_int_table_data; + struct bnx2x_fw_file_section usem_pram_data; + struct bnx2x_fw_file_section csem_int_table_data; + struct bnx2x_fw_file_section csem_pram_data; + struct bnx2x_fw_file_section xsem_int_table_data; + struct bnx2x_fw_file_section xsem_pram_data; + struct bnx2x_fw_file_section fw_version; +}; + +#endif /* BNX2X_INIT_FILE_HDR_H */ diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h index 39ba293..3ba4d88 100644 --- a/drivers/net/bnx2x_init.h +++ b/drivers/net/bnx2x_init.h @@ -1,4 +1,5 @@ /* bnx2x_init.h: Broadcom Everest network driver. + * Structures and macroes needed during the initialization. * * Copyright (c) 2007-2009 Broadcom Corporation * @@ -8,6 +9,7 @@ * * Maintained by: Eilon Greenstein * Written by: Eliezer Tamir + * Modified by: Vladislav Zolotarov */ #ifndef BNX2X_INIT_H @@ -45,33 +47,71 @@ #define OP_WR_64 0x8 /* write 64 bit pattern */ #define OP_WB 0x9 /* copy a string using DMAE */ -/* Operation specific for E1 */ -#define OP_RD_E1 0xa /* read single register */ -#define OP_WR_E1 0xb /* write single register */ -#define OP_IW_E1 0xc /* write single register using mailbox */ -#define OP_SW_E1 0xd /* copy a string to the device */ -#define OP_SI_E1 0xe /* copy a string using mailbox */ -#define OP_ZR_E1 0xf /* clear memory */ -#define OP_ZP_E1 0x10 /* unzip then copy with DMAE */ -#define OP_WR_64_E1 0x11 /* write 64 bit pattern on E1 */ -#define OP_WB_E1 0x12 /* copy a string using DMAE */ - -/* Operation specific for E1H */ -#define OP_RD_E1H 0x13 /* read single register */ -#define OP_WR_E1H 0x14 /* write single register */ -#define OP_IW_E1H 0x15 /* write single register using mailbox */ -#define OP_SW_E1H 0x16 /* copy a string to the device */ -#define OP_SI_E1H 0x17 /* copy a string using mailbox */ -#define OP_ZR_E1H 0x18 /* clear memory */ -#define OP_ZP_E1H 0x19 /* unzip then copy with DMAE */ -#define OP_WR_64_E1H 0x1a /* write 64 bit pattern on E1H */ -#define OP_WB_E1H 0x1b /* copy a string using DMAE */ - /* FPGA and EMUL specific operations */ -#define OP_WR_EMUL_E1H 0x1c /* write single register on E1H Emul */ -#define OP_WR_EMUL 0x1d /* write single register on Emulation */ -#define OP_WR_FPGA 0x1e /* write single register on FPGA */ -#define OP_WR_ASIC 0x1f /* write single register on ASIC */ +#define OP_WR_EMUL 0xa /* write single register on Emulation */ +#define OP_WR_FPGA 0xb /* write single register on FPGA */ +#define OP_WR_ASIC 0xc /* write single register on ASIC */ + +/* Init stages */ +#define COMMON_STAGE 0 +#define PORT0_STAGE 1 +#define PORT1_STAGE 2 +/* Never reorder FUNCx stages !!! */ +#define FUNC0_STAGE 3 +#define FUNC1_STAGE 4 +#define FUNC2_STAGE 5 +#define FUNC3_STAGE 6 +#define FUNC4_STAGE 7 +#define FUNC5_STAGE 8 +#define FUNC6_STAGE 9 +#define FUNC7_STAGE 10 +#define STAGE_IDX_MAX 11 + +#define STAGE_START 0 +#define STAGE_END 1 + + +/* Indices of blocks */ +#define PRS_BLOCK 0 +#define SRCH_BLOCK 1 +#define TSDM_BLOCK 2 +#define TCM_BLOCK 3 +#define BRB1_BLOCK 4 +#define TSEM_BLOCK 5 +#define PXPCS_BLOCK 6 +#define EMAC0_BLOCK 7 +#define EMAC1_BLOCK 8 +#define DBU_BLOCK 9 +#define MISC_BLOCK 10 +#define DBG_BLOCK 11 +#define NIG_BLOCK 12 +#define MCP_BLOCK 13 +#define UPB_BLOCK 14 +#define CSDM_BLOCK 15 +#define USDM_BLOCK 16 +#define CCM_BLOCK 17 +#define UCM_BLOCK 18 +#define USEM_BLOCK 19 +#define CSEM_BLOCK 20 +#define XPB_BLOCK 21 +#define DQ_BLOCK 22 +#define TIMERS_BLOCK 23 +#define XSDM_BLOCK 24 +#define QM_BLOCK 25 +#define PBF_BLOCK 26 +#define XCM_BLOCK 27 +#define XSEM_BLOCK 28 +#define CDU_BLOCK 29 +#define DMAE_BLOCK 30 +#define PXP_BLOCK 31 +#define CFC_BLOCK 32 +#define HC_BLOCK 33 +#define PXP2_BLOCK 34 +#define MISC_AEU_BLOCK 35 + +/* Returns the index of start or end of a specific block stage in ops array*/ +#define BLOCK_OPS_IDX(block, stage, end) \ + (2*(((block)*STAGE_IDX_MAX) + (stage)) + (end)) struct raw_op { @@ -118,292 +158,6 @@ union init_op { struct raw_op raw; }; -#include "bnx2x_init_values.h" - -static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); -static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len); - -static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, - u32 len) -{ - int i; - - for (i = 0; i < len; i++) { - REG_WR(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } -} - -static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, - u16 len) -{ - int i; - - for (i = 0; i < len; i++) { - REG_WR_IND(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } -} - -static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) -{ - int offset = 0; - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); -} - -static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) -{ - u32 buf_len = (((len * 4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len * 4)); - u32 buf_len32 = buf_len / 4; - int i; - - memset(bp->gunzip_buf, fill, buf_len); - - for (i = 0; i < len; i += buf_len32) { - u32 cur_len = min(buf_len32, len - i); - - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); - } -} - -static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, - u32 len64) -{ - u32 buf_len32 = FW_BUF_SIZE / 4; - u32 len = len64 * 2; - u64 data64 = 0; - int i; - - /* 64 bit value is in a blob: first low DWORD, then high DWORD */ - data64 = HILO_U64((*(data + 1)), (*data)); - len64 = min((u32)(FW_BUF_SIZE/8), len64); - for (i = 0; i < len64; i++) { - u64 *pdata = ((u64 *)(bp->gunzip_buf)) + i; - - *pdata = data64; - } - - for (i = 0; i < len; i += buf_len32) { - u32 cur_len = min(buf_len32, len - i); - - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); - } -} - -/********************************************************* - There are different blobs for each PRAM section. - In addition, each blob write operation is divided into a few operations - in order to decrease the amount of phys. contiguous buffer needed. - Thus, when we select a blob the address may be with some offset - from the beginning of PRAM section. - The same holds for the INT_TABLE sections. -**********************************************************/ -#define IF_IS_INT_TABLE_ADDR(base, addr) \ - if (((base) <= (addr)) && ((base) + 0x400 >= (addr))) - -#define IF_IS_PRAM_ADDR(base, addr) \ - if (((base) <= (addr)) && ((base) + 0x40000 >= (addr))) - -static const u32 *bnx2x_sel_blob(u32 addr, const u32 *data, int is_e1) -{ - IF_IS_INT_TABLE_ADDR(TSEM_REG_INT_TABLE, addr) - data = is_e1 ? tsem_int_table_data_e1 : - tsem_int_table_data_e1h; - else - IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) - data = is_e1 ? csem_int_table_data_e1 : - csem_int_table_data_e1h; - else - IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) - data = is_e1 ? usem_int_table_data_e1 : - usem_int_table_data_e1h; - else - IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) - data = is_e1 ? xsem_int_table_data_e1 : - xsem_int_table_data_e1h; - else - IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) - data = is_e1 ? tsem_pram_data_e1 : tsem_pram_data_e1h; - else - IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) - data = is_e1 ? csem_pram_data_e1 : csem_pram_data_e1h; - else - IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) - data = is_e1 ? usem_pram_data_e1 : usem_pram_data_e1h; - else - IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) - data = is_e1 ? xsem_pram_data_e1 : xsem_pram_data_e1h; - - return data; -} - -static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, - u32 len, int gunzip, int is_e1, u32 blob_off) -{ - int offset = 0; - - data = bnx2x_sel_blob(addr, data, is_e1) + blob_off; - - if (gunzip) { - int rc; -#ifdef __BIG_ENDIAN - int i, size; - u32 *temp; - - temp = kmalloc(len, GFP_KERNEL); - size = (len / 4) + ((len % 4) ? 1 : 0); - for (i = 0; i < size; i++) - temp[i] = swab32(data[i]); - data = temp; -#endif - rc = bnx2x_gunzip(bp, (u8 *)data, len); - if (rc) { - BNX2X_ERR("gunzip failed ! rc %d\n", rc); -#ifdef __BIG_ENDIAN - kfree(temp); -#endif - return; - } - len = bp->gunzip_outlen; -#ifdef __BIG_ENDIAN - kfree(temp); - for (i = 0; i < len; i++) - ((u32 *)bp->gunzip_buf)[i] = - swab32(((u32 *)bp->gunzip_buf)[i]); -#endif - } else { - if ((len * 4) > FW_BUF_SIZE) { - BNX2X_ERR("LARGE DMAE OPERATION ! " - "addr 0x%x len 0x%x\n", addr, len*4); - return; - } - memcpy(bp->gunzip_buf, data, len * 4); - } - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_ind_wr(bp, addr, bp->gunzip_buf, len); -} - -static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end) -{ - int is_e1 = CHIP_IS_E1(bp); - int is_e1h = CHIP_IS_E1H(bp); - int is_emul_e1h = (CHIP_REV_IS_EMUL(bp) && is_e1h); - int hw_wr, i; - union init_op *op; - u32 op_type, addr, len; - const u32 *data, *data_base; - - if (CHIP_REV_IS_FPGA(bp)) - hw_wr = OP_WR_FPGA; - else if (CHIP_REV_IS_EMUL(bp)) - hw_wr = OP_WR_EMUL; - else - hw_wr = OP_WR_ASIC; - - if (is_e1) - data_base = init_data_e1; - else /* CHIP_IS_E1H(bp) */ - data_base = init_data_e1h; - - for (i = op_start; i < op_end; i++) { - - op = (union init_op *)&(init_ops[i]); - - op_type = op->str_wr.op; - addr = op->str_wr.offset; - len = op->str_wr.data_len; - data = data_base + op->str_wr.data_off; - - /* careful! it must be in order */ - if (unlikely(op_type > OP_WB)) { - - /* If E1 only */ - if (op_type <= OP_WB_E1) { - if (is_e1) - op_type -= (OP_RD_E1 - OP_RD); - - /* If E1H only */ - } else if (op_type <= OP_WB_E1H) { - if (is_e1h) - op_type -= (OP_RD_E1H - OP_RD); - } - - /* HW/EMUL specific */ - if (op_type == hw_wr) - op_type = OP_WR; - - /* EMUL on E1H is special */ - if ((op_type == OP_WR_EMUL_E1H) && is_emul_e1h) - op_type = OP_WR; - } - - switch (op_type) { - case OP_RD: - REG_RD(bp, addr); - break; - case OP_WR: - REG_WR(bp, addr, op->write.val); - break; - case OP_SW: - bnx2x_init_str_wr(bp, addr, data, len); - break; - case OP_WB: - bnx2x_init_wr_wb(bp, addr, data, len, 0, is_e1, 0); - break; - case OP_SI: - bnx2x_init_ind_wr(bp, addr, data, len); - break; - case OP_ZR: - bnx2x_init_fill(bp, addr, 0, op->zero.len); - break; - case OP_ZP: - bnx2x_init_wr_wb(bp, addr, data, len, 1, is_e1, - op->str_wr.data_off); - break; - case OP_WR_64: - bnx2x_init_wr_64(bp, addr, data, len); - break; - default: - /* happens whenever an op is of a diff HW */ -#if 0 - DP(NETIF_MSG_HW, "skipping init operation " - "index %d[%d:%d]: type %d addr 0x%x " - "len %d(0x%x)\n", - i, op_start, op_end, op_type, addr, len, len); -#endif - break; - } - } -} - - /**************************************************************************** * PXP ****************************************************************************/ @@ -567,111 +321,6 @@ static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { PXP2_REG_RQ_BW_WR_UBOUND30} }; -static void bnx2x_init_pxp(struct bnx2x *bp) -{ - u16 devctl; - int r_order, w_order; - u32 val, i; - - pci_read_config_word(bp->pdev, - bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); - DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); - w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); - if (bp->mrrs == -1) - r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); - else { - DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); - r_order = bp->mrrs; - } - - if (r_order > MAX_RD_ORD) { - DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", - r_order, MAX_RD_ORD); - r_order = MAX_RD_ORD; - } - if (w_order > MAX_WR_ORD) { - DP(NETIF_MSG_HW, "write order of %d order adjusted to %d\n", - w_order, MAX_WR_ORD); - w_order = MAX_WR_ORD; - } - if (CHIP_REV_IS_FPGA(bp)) { - DP(NETIF_MSG_HW, "write order adjusted to 1 for FPGA\n"); - w_order = 0; - } - DP(NETIF_MSG_HW, "read order %d write order %d\n", r_order, w_order); - - for (i = 0; i < NUM_RD_Q-1; i++) { - REG_WR(bp, read_arb_addr[i].l, read_arb_data[i][r_order].l); - REG_WR(bp, read_arb_addr[i].add, - read_arb_data[i][r_order].add); - REG_WR(bp, read_arb_addr[i].ubound, - read_arb_data[i][r_order].ubound); - } - - for (i = 0; i < NUM_WR_Q-1; i++) { - if ((write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L29) || - (write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L30)) { - - REG_WR(bp, write_arb_addr[i].l, - write_arb_data[i][w_order].l); - - REG_WR(bp, write_arb_addr[i].add, - write_arb_data[i][w_order].add); - - REG_WR(bp, write_arb_addr[i].ubound, - write_arb_data[i][w_order].ubound); - } else { - - val = REG_RD(bp, write_arb_addr[i].l); - REG_WR(bp, write_arb_addr[i].l, - val | (write_arb_data[i][w_order].l << 10)); - - val = REG_RD(bp, write_arb_addr[i].add); - REG_WR(bp, write_arb_addr[i].add, - val | (write_arb_data[i][w_order].add << 10)); - - val = REG_RD(bp, write_arb_addr[i].ubound); - REG_WR(bp, write_arb_addr[i].ubound, - val | (write_arb_data[i][w_order].ubound << 7)); - } - } - - val = write_arb_data[NUM_WR_Q-1][w_order].add; - val += write_arb_data[NUM_WR_Q-1][w_order].ubound << 10; - val += write_arb_data[NUM_WR_Q-1][w_order].l << 17; - REG_WR(bp, PXP2_REG_PSWRQ_BW_RD, val); - - val = read_arb_data[NUM_RD_Q-1][r_order].add; - val += read_arb_data[NUM_RD_Q-1][r_order].ubound << 10; - val += read_arb_data[NUM_RD_Q-1][r_order].l << 17; - REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val); - - REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order); - REG_WR(bp, PXP2_REG_RQ_WR_MBS1, w_order); - REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order); - REG_WR(bp, PXP2_REG_RQ_RD_MBS1, r_order); - - if (r_order == MAX_RD_ORD) - REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00); - - REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); - - if (CHIP_IS_E1H(bp)) { - val = ((w_order == 0) ? 2 : 3); - REG_WR(bp, PXP2_REG_WR_HC_MPS, val); - REG_WR(bp, PXP2_REG_WR_USDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_CSDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_TSDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_XSDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_QM_MPS, val); - REG_WR(bp, PXP2_REG_WR_TM_MPS, val); - REG_WR(bp, PXP2_REG_WR_SRC_MPS, val); - REG_WR(bp, PXP2_REG_WR_DBG_MPS, val); - REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2); /* DMAE is special */ - REG_WR(bp, PXP2_REG_WR_CDU_MPS, val); - } -} - /**************************************************************************** * CDU @@ -695,128 +344,12 @@ static void bnx2x_init_pxp(struct bnx2x *bp) (0x80 | ((_type) & 0xf << 3) | (CDU_CRC8(_cid, _region, _type) & 0x7)) #define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val) ((_val) & ~0x80) -/***************************************************************************** - * Description: - * Calculates crc 8 on a word value: polynomial 0-1-2-8 - * Code was translated from Verilog. - ****************************************************************************/ -static u8 calc_crc8(u32 data, u8 crc) -{ - u8 D[32]; - u8 NewCRC[8]; - u8 C[8]; - u8 crc_res; - u8 i; - - /* split the data into 31 bits */ - for (i = 0; i < 32; i++) { - D[i] = data & 1; - data = data >> 1; - } - - /* split the crc into 8 bits */ - for (i = 0; i < 8; i++) { - C[i] = crc & 1; - crc = crc >> 1; - } - - NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ - D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ - C[6] ^ C[7]; - NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ - D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ - D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6]; - NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ - D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ - C[0] ^ C[1] ^ C[4] ^ C[5]; - NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ - D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ - C[1] ^ C[2] ^ C[5] ^ C[6]; - NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ - D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ - C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; - NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ - D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ - C[3] ^ C[4] ^ C[7]; - NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ - D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ - C[5]; - NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ - D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ - C[6]; - - crc_res = 0; - for (i = 0; i < 8; i++) - crc_res |= (NewCRC[i] << i); - - return crc_res; -} /* registers addresses are not in order so these arrays help simplify the code */ -static const int cm_start[E1H_FUNC_MAX][9] = { - {MISC_FUNC0_START, TCM_FUNC0_START, UCM_FUNC0_START, CCM_FUNC0_START, - XCM_FUNC0_START, TSEM_FUNC0_START, USEM_FUNC0_START, CSEM_FUNC0_START, - XSEM_FUNC0_START}, - {MISC_FUNC1_START, TCM_FUNC1_START, UCM_FUNC1_START, CCM_FUNC1_START, - XCM_FUNC1_START, TSEM_FUNC1_START, USEM_FUNC1_START, CSEM_FUNC1_START, - XSEM_FUNC1_START}, - {MISC_FUNC2_START, TCM_FUNC2_START, UCM_FUNC2_START, CCM_FUNC2_START, - XCM_FUNC2_START, TSEM_FUNC2_START, USEM_FUNC2_START, CSEM_FUNC2_START, - XSEM_FUNC2_START}, - {MISC_FUNC3_START, TCM_FUNC3_START, UCM_FUNC3_START, CCM_FUNC3_START, - XCM_FUNC3_START, TSEM_FUNC3_START, USEM_FUNC3_START, CSEM_FUNC3_START, - XSEM_FUNC3_START}, - {MISC_FUNC4_START, TCM_FUNC4_START, UCM_FUNC4_START, CCM_FUNC4_START, - XCM_FUNC4_START, TSEM_FUNC4_START, USEM_FUNC4_START, CSEM_FUNC4_START, - XSEM_FUNC4_START}, - {MISC_FUNC5_START, TCM_FUNC5_START, UCM_FUNC5_START, CCM_FUNC5_START, - XCM_FUNC5_START, TSEM_FUNC5_START, USEM_FUNC5_START, CSEM_FUNC5_START, - XSEM_FUNC5_START}, - {MISC_FUNC6_START, TCM_FUNC6_START, UCM_FUNC6_START, CCM_FUNC6_START, - XCM_FUNC6_START, TSEM_FUNC6_START, USEM_FUNC6_START, CSEM_FUNC6_START, - XSEM_FUNC6_START}, - {MISC_FUNC7_START, TCM_FUNC7_START, UCM_FUNC7_START, CCM_FUNC7_START, - XCM_FUNC7_START, TSEM_FUNC7_START, USEM_FUNC7_START, CSEM_FUNC7_START, - XSEM_FUNC7_START} -}; - -static const int cm_end[E1H_FUNC_MAX][9] = { - {MISC_FUNC0_END, TCM_FUNC0_END, UCM_FUNC0_END, CCM_FUNC0_END, - XCM_FUNC0_END, TSEM_FUNC0_END, USEM_FUNC0_END, CSEM_FUNC0_END, - XSEM_FUNC0_END}, - {MISC_FUNC1_END, TCM_FUNC1_END, UCM_FUNC1_END, CCM_FUNC1_END, - XCM_FUNC1_END, TSEM_FUNC1_END, USEM_FUNC1_END, CSEM_FUNC1_END, - XSEM_FUNC1_END}, - {MISC_FUNC2_END, TCM_FUNC2_END, UCM_FUNC2_END, CCM_FUNC2_END, - XCM_FUNC2_END, TSEM_FUNC2_END, USEM_FUNC2_END, CSEM_FUNC2_END, - XSEM_FUNC2_END}, - {MISC_FUNC3_END, TCM_FUNC3_END, UCM_FUNC3_END, CCM_FUNC3_END, - XCM_FUNC3_END, TSEM_FUNC3_END, USEM_FUNC3_END, CSEM_FUNC3_END, - XSEM_FUNC3_END}, - {MISC_FUNC4_END, TCM_FUNC4_END, UCM_FUNC4_END, CCM_FUNC4_END, - XCM_FUNC4_END, TSEM_FUNC4_END, USEM_FUNC4_END, CSEM_FUNC4_END, - XSEM_FUNC4_END}, - {MISC_FUNC5_END, TCM_FUNC5_END, UCM_FUNC5_END, CCM_FUNC5_END, - XCM_FUNC5_END, TSEM_FUNC5_END, USEM_FUNC5_END, CSEM_FUNC5_END, - XSEM_FUNC5_END}, - {MISC_FUNC6_END, TCM_FUNC6_END, UCM_FUNC6_END, CCM_FUNC6_END, - XCM_FUNC6_END, TSEM_FUNC6_END, USEM_FUNC6_END, CSEM_FUNC6_END, - XSEM_FUNC6_END}, - {MISC_FUNC7_END, TCM_FUNC7_END, UCM_FUNC7_END, CCM_FUNC7_END, - XCM_FUNC7_END, TSEM_FUNC7_END, USEM_FUNC7_END, CSEM_FUNC7_END, - XSEM_FUNC7_END}, -}; - -static const int hc_limits[E1H_FUNC_MAX][2] = { - {HC_FUNC0_START, HC_FUNC0_END}, - {HC_FUNC1_START, HC_FUNC1_END}, - {HC_FUNC2_START, HC_FUNC2_END}, - {HC_FUNC3_START, HC_FUNC3_END}, - {HC_FUNC4_START, HC_FUNC4_END}, - {HC_FUNC5_START, HC_FUNC5_END}, - {HC_FUNC6_START, HC_FUNC6_END}, - {HC_FUNC7_START, HC_FUNC7_END} +static const int cm_blocks[9] = { + MISC_BLOCK, TCM_BLOCK, UCM_BLOCK, CCM_BLOCK, XCM_BLOCK, + TSEM_BLOCK, USEM_BLOCK, CSEM_BLOCK, XSEM_BLOCK }; #endif /* BNX2X_INIT_H */ diff --git a/drivers/net/bnx2x_init_ops.h b/drivers/net/bnx2x_init_ops.h new file mode 100644 index 0000000..32552b9 --- /dev/null +++ b/drivers/net/bnx2x_init_ops.h @@ -0,0 +1,442 @@ +/* bnx2x_init_ops.h: Broadcom Everest network driver. + * Static functions needed during the initialization. + * This file is "included" in bnx2x_main.c. + * + * Copyright (c) 2007-2009 Broadcom Corporation + * + * 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. + * + * Maintained by: Eilon Greenstein + * Written by: Vladislav Zolotarov + */ +#ifndef BNX2X_INIT_OPS_H +#define BNX2X_INIT_OPS_H + +static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); +static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len); + +static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len) +{ + int i; + + for (i = 0; i < len; i++) { + REG_WR(bp, addr + i*4, data[i]); + if (!(i % 10000)) { + touch_softlockup_watchdog(); + cpu_relax(); + } + } +} + +static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, + u16 len) +{ + int i; + + for (i = 0; i < len; i++) { + REG_WR_IND(bp, addr + i*4, data[i]); + if (!(i % 10000)) { + touch_softlockup_watchdog(); + cpu_relax(); + } + } +} + +static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) +{ + int offset = 0; + + if (bp->dmae_ready) { + while (len > DMAE_LEN32_WR_MAX) { + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, DMAE_LEN32_WR_MAX); + offset += DMAE_LEN32_WR_MAX * 4; + len -= DMAE_LEN32_WR_MAX; + } + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, len); + } else + bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); +} + +static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) +{ + u32 buf_len = (((len * 4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len * 4)); + u32 buf_len32 = buf_len / 4; + int i; + + memset(bp->gunzip_buf, fill, buf_len); + + for (i = 0; i < len; i += buf_len32) { + u32 cur_len = min(buf_len32, len - i); + + bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + } +} + +static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len64) +{ + u32 buf_len32 = FW_BUF_SIZE / 4; + u32 len = len64 * 2; + u64 data64 = 0; + int i; + + /* 64 bit value is in a blob: first low DWORD, then high DWORD */ + data64 = HILO_U64((*(data + 1)), (*data)); + len64 = min((u32)(FW_BUF_SIZE/8), len64); + for (i = 0; i < len64; i++) { + u64 *pdata = ((u64 *)(bp->gunzip_buf)) + i; + + *pdata = data64; + } + + for (i = 0; i < len; i += buf_len32) { + u32 cur_len = min(buf_len32, len - i); + + bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + } +} + +/********************************************************* + There are different blobs for each PRAM section. + In addition, each blob write operation is divided into a few operations + in order to decrease the amount of phys. contiguous buffer needed. + Thus, when we select a blob the address may be with some offset + from the beginning of PRAM section. + The same holds for the INT_TABLE sections. +**********************************************************/ +#define IF_IS_INT_TABLE_ADDR(base, addr) \ + if (((base) <= (addr)) && ((base) + 0x400 >= (addr))) + +#define IF_IS_PRAM_ADDR(base, addr) \ + if (((base) <= (addr)) && ((base) + 0x40000 >= (addr))) + +static const u8 *bnx2x_sel_blob(struct bnx2x *bp, u32 addr, const u8 *data) +{ + IF_IS_INT_TABLE_ADDR(TSEM_REG_INT_TABLE, addr) + data = bp->tsem_int_table_data; + else IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) + data = bp->csem_int_table_data; + else IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) + data = bp->usem_int_table_data; + else IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) + data = bp->xsem_int_table_data; + else IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) + data = bp->tsem_pram_data; + else IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) + data = bp->csem_pram_data; + else IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) + data = bp->usem_pram_data; + else IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) + data = bp->xsem_pram_data; + + return data; +} + +static void bnx2x_write_big_buf_wb(struct bnx2x *bp, u32 addr, u32 len) +{ + int offset = 0; + + if (bp->dmae_ready) { + while (len > DMAE_LEN32_WR_MAX) { + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, DMAE_LEN32_WR_MAX); + offset += DMAE_LEN32_WR_MAX * 4; + len -= DMAE_LEN32_WR_MAX; + } + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, len); + } else + bnx2x_init_ind_wr(bp, addr, bp->gunzip_buf, len); +} + +static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len) +{ + /* This is needed for NO_ZIP mode, currently supported + in little endian mode only */ + data = (const u32*)bnx2x_sel_blob(bp, addr, (const u8*)data); + + if ((len * 4) > FW_BUF_SIZE) { + BNX2X_ERR("LARGE DMAE OPERATION ! " + "addr 0x%x len 0x%x\n", addr, len*4); + return; + } + memcpy(bp->gunzip_buf, data, len * 4); + + bnx2x_write_big_buf_wb(bp, addr, len); +} + +static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, + u32 len, u32 blob_off) +{ + int rc, i; + const u8 *data = NULL; + + data = bnx2x_sel_blob(bp, addr, data) + 4*blob_off; + + if (data == NULL) { + panic("Blob not found for addr 0x%x\n", addr); + return; + } + + rc = bnx2x_gunzip(bp, data, len); + if (rc) { + BNX2X_ERR("gunzip failed ! addr 0x%x rc %d\n", addr, rc); + BNX2X_ERR("blob_offset=0x%x\n", blob_off); + return; + } + + /* gunzip_outlen is in dwords */ + len = bp->gunzip_outlen; + for (i = 0; i < len; i++) + ((u32 *)bp->gunzip_buf)[i] = + cpu_to_le32(((u32 *)bp->gunzip_buf)[i]); + + bnx2x_write_big_buf_wb(bp, addr, len); +} + +static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) +{ + int hw_wr, i; + u16 op_start = + bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_START)]; + u16 op_end = + bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_END)]; + union init_op *op; + u32 op_type, addr, len; + const u32 *data, *data_base; + + /* If empty block */ + if (op_start == op_end) + return; + + if (CHIP_REV_IS_FPGA(bp)) + hw_wr = OP_WR_FPGA; + else if (CHIP_REV_IS_EMUL(bp)) + hw_wr = OP_WR_EMUL; + else + hw_wr = OP_WR_ASIC; + + data_base = bp->init_data; + + for (i = op_start; i < op_end; i++) { + + op = (union init_op *)&(bp->init_ops[i]); + + op_type = op->str_wr.op; + addr = op->str_wr.offset; + len = op->str_wr.data_len; + data = data_base + op->str_wr.data_off; + + /* HW/EMUL specific */ + if (unlikely((op_type > OP_WB) && (op_type == hw_wr))) + op_type = OP_WR; + + switch (op_type) { + case OP_RD: + REG_RD(bp, addr); + break; + case OP_WR: + REG_WR(bp, addr, op->write.val); + break; + case OP_SW: + bnx2x_init_str_wr(bp, addr, data, len); + break; + case OP_WB: + bnx2x_init_wr_wb(bp, addr, data, len); + break; + case OP_SI: + bnx2x_init_ind_wr(bp, addr, data, len); + break; + case OP_ZR: + bnx2x_init_fill(bp, addr, 0, op->zero.len); + break; + case OP_ZP: + bnx2x_init_wr_zp(bp, addr, len, + op->str_wr.data_off); + break; + case OP_WR_64: + bnx2x_init_wr_64(bp, addr, data, len); + break; + default: + /* happens whenever an op is of a diff HW */ +#if 0 + DP(NETIF_MSG_HW, "skipping init operation " + "index %d[%d:%d]: type %d addr 0x%x " + "len %d(0x%x)\n", + i, op_start, op_end, op_type, addr, len, len); +#endif + break; + } + } +} + +/* PXP */ +static void bnx2x_init_pxp(struct bnx2x *bp) +{ + u16 devctl; + int r_order, w_order; + u32 val, i; + + pci_read_config_word(bp->pdev, + bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); + DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); + w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + if (bp->mrrs == -1) + r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); + else { + DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); + r_order = bp->mrrs; + } + + if (r_order > MAX_RD_ORD) { + DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", + r_order, MAX_RD_ORD); + r_order = MAX_RD_ORD; + } + if (w_order > MAX_WR_ORD) { + DP(NETIF_MSG_HW, "write order of %d order adjusted to %d\n", + w_order, MAX_WR_ORD); + w_order = MAX_WR_ORD; + } + if (CHIP_REV_IS_FPGA(bp)) { + DP(NETIF_MSG_HW, "write order adjusted to 1 for FPGA\n"); + w_order = 0; + } + DP(NETIF_MSG_HW, "read order %d write order %d\n", r_order, w_order); + + for (i = 0; i < NUM_RD_Q-1; i++) { + REG_WR(bp, read_arb_addr[i].l, read_arb_data[i][r_order].l); + REG_WR(bp, read_arb_addr[i].add, + read_arb_data[i][r_order].add); + REG_WR(bp, read_arb_addr[i].ubound, + read_arb_data[i][r_order].ubound); + } + + for (i = 0; i < NUM_WR_Q-1; i++) { + if ((write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L29) || + (write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L30)) { + + REG_WR(bp, write_arb_addr[i].l, + write_arb_data[i][w_order].l); + + REG_WR(bp, write_arb_addr[i].add, + write_arb_data[i][w_order].add); + + REG_WR(bp, write_arb_addr[i].ubound, + write_arb_data[i][w_order].ubound); + } else { + + val = REG_RD(bp, write_arb_addr[i].l); + REG_WR(bp, write_arb_addr[i].l, + val | (write_arb_data[i][w_order].l << 10)); + + val = REG_RD(bp, write_arb_addr[i].add); + REG_WR(bp, write_arb_addr[i].add, + val | (write_arb_data[i][w_order].add << 10)); + + val = REG_RD(bp, write_arb_addr[i].ubound); + REG_WR(bp, write_arb_addr[i].ubound, + val | (write_arb_data[i][w_order].ubound << 7)); + } + } + + val = write_arb_data[NUM_WR_Q-1][w_order].add; + val += write_arb_data[NUM_WR_Q-1][w_order].ubound << 10; + val += write_arb_data[NUM_WR_Q-1][w_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_RD, val); + + val = read_arb_data[NUM_RD_Q-1][r_order].add; + val += read_arb_data[NUM_RD_Q-1][r_order].ubound << 10; + val += read_arb_data[NUM_RD_Q-1][r_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val); + + REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order); + REG_WR(bp, PXP2_REG_RQ_WR_MBS1, w_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS1, r_order); + + if (r_order == MAX_RD_ORD) + REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00); + + REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); + + if (CHIP_IS_E1H(bp)) { + val = ((w_order == 0) ? 2 : 3); + REG_WR(bp, PXP2_REG_WR_HC_MPS, val); + REG_WR(bp, PXP2_REG_WR_USDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_CSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_TSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_XSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_QM_MPS, val); + REG_WR(bp, PXP2_REG_WR_TM_MPS, val); + REG_WR(bp, PXP2_REG_WR_SRC_MPS, val); + REG_WR(bp, PXP2_REG_WR_DBG_MPS, val); + REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2); /* DMAE is special */ + REG_WR(bp, PXP2_REG_WR_CDU_MPS, val); + } +} + +/***************************************************************************** + * Description: + * Calculates crc 8 on a word value: polynomial 0-1-2-8 + * Code was translated from Verilog. + ****************************************************************************/ +static u8 calc_crc8(u32 data, u8 crc) +{ + u8 D[32]; + u8 NewCRC[8]; + u8 C[8]; + u8 crc_res; + u8 i; + + /* split the data into 31 bits */ + for (i = 0; i < 32; i++) { + D[i] = data & 1; + data = data >> 1; + } + + /* split the crc into 8 bits */ + for (i = 0; i < 8; i++) { + C[i] = crc & 1; + crc = crc >> 1; + } + + NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ + D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ + C[6] ^ C[7]; + NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ + D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ + D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6]; + NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ + D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ + C[0] ^ C[1] ^ C[4] ^ C[5]; + NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ + D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ + C[1] ^ C[2] ^ C[5] ^ C[6]; + NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ + D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ + C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; + NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ + D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ + C[3] ^ C[4] ^ C[7]; + NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ + D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ + C[5]; + NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ + D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ + C[6]; + + crc_res = 0; + for (i = 0; i < 8; i++) + crc_res |= (NewCRC[i] << i); + + return crc_res; +} + +#endif /* BNX2X_INIT_OPS_H */ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ad5ef25..cdc80e0 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -53,12 +53,19 @@ #include "bnx2x.h" #include "bnx2x_init.h" +#include "bnx2x_init_ops.h" #include "bnx2x_dump.h" #define DRV_MODULE_VERSION "1.48.105" #define DRV_MODULE_RELDATE "2009/03/02" #define BNX2X_BC_VER 0x040200 +#include +#include "bnx2x_fw_file_hdr.h" +/* FW files */ +#define FW_FILE_PREFIX_E1 "bnx2x-e1-" +#define FW_FILE_PREFIX_E1H "bnx2x-e1h-" + /* Time in jiffies before concluding the transmitter is hung */ #define TX_TIMEOUT (5*HZ) @@ -5232,13 +5239,15 @@ static void bnx2x_gunzip_end(struct bnx2x *bp) } } -static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) +static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len) { int n, rc; /* check gzip header */ - if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) + if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) { + BNX2X_ERR("Bad gzip header\n"); return -EINVAL; + } n = 10; @@ -5247,7 +5256,7 @@ static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) if (zbuf[3] & FNAME) while ((zbuf[n++] != 0) && (n < len)); - bp->strm->next_in = zbuf + n; + bp->strm->next_in = (typeof(bp->strm->next_in))zbuf + n; bp->strm->avail_in = len - n; bp->strm->next_out = bp->gunzip_buf; bp->strm->avail_out = FW_BUF_SIZE; @@ -5369,8 +5378,8 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) msleep(50); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); msleep(50); - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE); DP(NETIF_MSG_HW, "part2\n"); @@ -5434,8 +5443,8 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) msleep(50); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); msleep(50); - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE); #ifndef BCM_ISCSI /* set NIC mode */ REG_WR(bp, PRS_REG_NIC_MODE, 1); @@ -5510,7 +5519,7 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc); - bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END); + bnx2x_init_block(bp, MISC_BLOCK, COMMON_STAGE); if (CHIP_IS_E1H(bp)) REG_WR(bp, MISC_REG_E1HMF_MODE, IS_E1HMF(bp)); @@ -5518,14 +5527,14 @@ static int bnx2x_init_common(struct bnx2x *bp) msleep(30); REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0); - bnx2x_init_block(bp, PXP_COMMON_START, PXP_COMMON_END); + bnx2x_init_block(bp, PXP_BLOCK, COMMON_STAGE); if (CHIP_IS_E1(bp)) { /* enable HW interrupt from PXP on USDM overflow bit 16 on INT_MASK_0 */ REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); } - bnx2x_init_block(bp, PXP2_COMMON_START, PXP2_COMMON_END); + bnx2x_init_block(bp, PXP2_BLOCK, COMMON_STAGE); bnx2x_init_pxp(bp); #ifdef __BIG_ENDIAN @@ -5571,60 +5580,60 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0); REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0); - bnx2x_init_block(bp, DMAE_COMMON_START, DMAE_COMMON_END); + bnx2x_init_block(bp, DMAE_BLOCK, COMMON_STAGE); /* clean the DMAE memory */ bp->dmae_ready = 1; bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8); - bnx2x_init_block(bp, TCM_COMMON_START, TCM_COMMON_END); - bnx2x_init_block(bp, UCM_COMMON_START, UCM_COMMON_END); - bnx2x_init_block(bp, CCM_COMMON_START, CCM_COMMON_END); - bnx2x_init_block(bp, XCM_COMMON_START, XCM_COMMON_END); + bnx2x_init_block(bp, TCM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, UCM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, CCM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XCM_BLOCK, COMMON_STAGE); bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3); bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3); bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3); bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3); - bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END); + bnx2x_init_block(bp, QM_BLOCK, COMMON_STAGE); /* soft reset pulse */ REG_WR(bp, QM_REG_SOFT_RESET, 1); REG_WR(bp, QM_REG_SOFT_RESET, 0); #ifdef BCM_ISCSI - bnx2x_init_block(bp, TIMERS_COMMON_START, TIMERS_COMMON_END); + bnx2x_init_block(bp, TIMERS_BLOCK, COMMON_STAGE); #endif - bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END); + bnx2x_init_block(bp, DQ_BLOCK, COMMON_STAGE); REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_SHIFT); if (!CHIP_REV_IS_SLOW(bp)) { /* enable hw interrupt from doorbell Q */ REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); } - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE); REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); /* set NIC mode */ REG_WR(bp, PRS_REG_NIC_MODE, 1); if (CHIP_IS_E1H(bp)) REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp)); - bnx2x_init_block(bp, TSDM_COMMON_START, TSDM_COMMON_END); - bnx2x_init_block(bp, CSDM_COMMON_START, CSDM_COMMON_END); - bnx2x_init_block(bp, USDM_COMMON_START, USDM_COMMON_END); - bnx2x_init_block(bp, XSDM_COMMON_START, XSDM_COMMON_END); + bnx2x_init_block(bp, TSDM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, CSDM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, USDM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XSDM_BLOCK, COMMON_STAGE); bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_block(bp, TSEM_COMMON_START, TSEM_COMMON_END); - bnx2x_init_block(bp, USEM_COMMON_START, USEM_COMMON_END); - bnx2x_init_block(bp, CSEM_COMMON_START, CSEM_COMMON_END); - bnx2x_init_block(bp, XSEM_COMMON_START, XSEM_COMMON_END); + bnx2x_init_block(bp, TSEM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, USEM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, CSEM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XSEM_BLOCK, COMMON_STAGE); /* sync semi rtc */ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, @@ -5632,16 +5641,16 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x80000000); - bnx2x_init_block(bp, UPB_COMMON_START, UPB_COMMON_END); - bnx2x_init_block(bp, XPB_COMMON_START, XPB_COMMON_END); - bnx2x_init_block(bp, PBF_COMMON_START, PBF_COMMON_END); + bnx2x_init_block(bp, UPB_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XPB_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE); REG_WR(bp, SRC_REG_SOFT_RST, 1); for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) { REG_WR(bp, i, 0xc0cac01a); /* TODO: replace with something meaningful */ } - bnx2x_init_block(bp, SRCH_COMMON_START, SRCH_COMMON_END); + bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE); REG_WR(bp, SRC_REG_SOFT_RST, 0); if (sizeof(union cdu_context) != 1024) @@ -5649,7 +5658,7 @@ static int bnx2x_init_common(struct bnx2x *bp) printk(KERN_ALERT PFX "please adjust the size of" " cdu_context(%ld)\n", (long)sizeof(union cdu_context)); - bnx2x_init_block(bp, CDU_COMMON_START, CDU_COMMON_END); + bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE); val = (4 << 24) + (0 << 12) + 1024; REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); if (CHIP_IS_E1(bp)) { @@ -5658,7 +5667,7 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, CDU_REG_CDU_DEBUG, 0); } - bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END); + bnx2x_init_block(bp, CFC_BLOCK, COMMON_STAGE); REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); /* enable context validation interrupt from CFC */ REG_WR(bp, CFC_REG_CFC_INT_MASK, 0); @@ -5666,20 +5675,25 @@ static int bnx2x_init_common(struct bnx2x *bp) /* set the thresholds to prevent CFC/CDU race */ REG_WR(bp, CFC_REG_DEBUG0, 0x20020000); - bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END); - bnx2x_init_block(bp, MISC_AEU_COMMON_START, MISC_AEU_COMMON_END); + bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE); /* PXPCS COMMON comes here */ + bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE); /* Reset PCIE errors for debug */ REG_WR(bp, 0x2814, 0xffffffff); REG_WR(bp, 0x3820, 0xffffffff); /* EMAC0 COMMON comes here */ + bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE); /* EMAC1 COMMON comes here */ + bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE); /* DBU COMMON comes here */ + bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE); /* DBG COMMON comes here */ + bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE); - bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END); + bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE); if (CHIP_IS_E1H(bp)) { REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_E1HMF(bp)); REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_E1HMF(bp)); @@ -5763,6 +5777,7 @@ static int bnx2x_init_common(struct bnx2x *bp) static int bnx2x_init_port(struct bnx2x *bp) { int port = BP_PORT(bp); + int init_stage = port ? PORT1_STAGE : PORT0_STAGE; u32 low, high; u32 val; @@ -5771,7 +5786,9 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); /* Port PXP comes here */ + bnx2x_init_block(bp, PXP_BLOCK, init_stage); /* Port PXP2 comes here */ + bnx2x_init_block(bp, PXP2_BLOCK, init_stage); #ifdef BCM_ISCSI /* Port0 1 * Port1 385 */ @@ -5798,21 +5815,19 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); #endif /* Port CMs come here */ - bnx2x_init_block(bp, (port ? XCM_PORT1_START : XCM_PORT0_START), - (port ? XCM_PORT1_END : XCM_PORT0_END)); + bnx2x_init_block(bp, XCM_BLOCK, init_stage); /* Port QM comes here */ #ifdef BCM_ISCSI REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20); REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31); - bnx2x_init_block(bp, func ? TIMERS_PORT1_START : TIMERS_PORT0_START, - func ? TIMERS_PORT1_END : TIMERS_PORT0_END); + bnx2x_init_block(bp, TIMERS_BLOCK, init_stage); #endif /* Port DQ comes here */ + bnx2x_init_block(bp, DQ_BLOCK, init_stage); - bnx2x_init_block(bp, (port ? BRB1_PORT1_START : BRB1_PORT0_START), - (port ? BRB1_PORT1_END : BRB1_PORT0_END)); + bnx2x_init_block(bp, BRB1_BLOCK, init_stage); if (CHIP_REV_IS_SLOW(bp) && !CHIP_IS_E1H(bp)) { /* no pause for emulation and FPGA */ low = 0; @@ -5837,25 +5852,27 @@ static int bnx2x_init_port(struct bnx2x *bp) /* Port PRS comes here */ + bnx2x_init_block(bp, PRS_BLOCK, init_stage); /* Port TSDM comes here */ + bnx2x_init_block(bp, TSDM_BLOCK, init_stage); /* Port CSDM comes here */ + bnx2x_init_block(bp, CSDM_BLOCK, init_stage); /* Port USDM comes here */ + bnx2x_init_block(bp, USDM_BLOCK, init_stage); /* Port XSDM comes here */ + bnx2x_init_block(bp, XSDM_BLOCK, init_stage); - bnx2x_init_block(bp, port ? TSEM_PORT1_START : TSEM_PORT0_START, - port ? TSEM_PORT1_END : TSEM_PORT0_END); - bnx2x_init_block(bp, port ? USEM_PORT1_START : USEM_PORT0_START, - port ? USEM_PORT1_END : USEM_PORT0_END); - bnx2x_init_block(bp, port ? CSEM_PORT1_START : CSEM_PORT0_START, - port ? CSEM_PORT1_END : CSEM_PORT0_END); - bnx2x_init_block(bp, port ? XSEM_PORT1_START : XSEM_PORT0_START, - port ? XSEM_PORT1_END : XSEM_PORT0_END); + bnx2x_init_block(bp, TSEM_BLOCK, init_stage); + bnx2x_init_block(bp, USEM_BLOCK, init_stage); + bnx2x_init_block(bp, CSEM_BLOCK, init_stage); + bnx2x_init_block(bp, XSEM_BLOCK, init_stage); /* Port UPB comes here */ + bnx2x_init_block(bp, UPB_BLOCK, init_stage); /* Port XPB comes here */ + bnx2x_init_block(bp, XPB_BLOCK, init_stage); - bnx2x_init_block(bp, port ? PBF_PORT1_START : PBF_PORT0_START, - port ? PBF_PORT1_END : PBF_PORT0_END); + bnx2x_init_block(bp, PBF_BLOCK, init_stage); /* configure PBF to work without PAUSE mtu 9000 */ REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0); @@ -5885,18 +5902,17 @@ static int bnx2x_init_port(struct bnx2x *bp) /* Port SRCH comes here */ #endif /* Port CDU comes here */ + bnx2x_init_block(bp, CDU_BLOCK, init_stage); /* Port CFC comes here */ + bnx2x_init_block(bp, CFC_BLOCK, init_stage); if (CHIP_IS_E1(bp)) { REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); } - bnx2x_init_block(bp, port ? HC_PORT1_START : HC_PORT0_START, - port ? HC_PORT1_END : HC_PORT0_END); + bnx2x_init_block(bp, HC_BLOCK, init_stage); - bnx2x_init_block(bp, port ? MISC_AEU_PORT1_START : - MISC_AEU_PORT0_START, - port ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END); + bnx2x_init_block(bp, MISC_AEU_BLOCK, init_stage); /* init aeu_mask_attn_func_0/1: * - SF mode: bits 3-7 are masked. only bits 0-2 are in use * - MF mode: bit 3 is masked. bits 0-2 are in use as in SF @@ -5905,13 +5921,17 @@ static int bnx2x_init_port(struct bnx2x *bp) (IS_E1HMF(bp) ? 0xF7 : 0x7)); /* Port PXPCS comes here */ + bnx2x_init_block(bp, PXPCS_BLOCK, init_stage); /* Port EMAC0 comes here */ + bnx2x_init_block(bp, EMAC0_BLOCK, init_stage); /* Port EMAC1 comes here */ + bnx2x_init_block(bp, EMAC1_BLOCK, init_stage); /* Port DBU comes here */ + bnx2x_init_block(bp, DBU_BLOCK, init_stage); /* Port DBG comes here */ + bnx2x_init_block(bp, DBG_BLOCK, init_stage); - bnx2x_init_block(bp, port ? NIG_PORT1_START : NIG_PORT0_START, - port ? NIG_PORT1_END : NIG_PORT0_END); + bnx2x_init_block(bp, NIG_BLOCK, init_stage); REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); @@ -5931,7 +5951,9 @@ static int bnx2x_init_port(struct bnx2x *bp) } /* Port MCP comes here */ + bnx2x_init_block(bp, MCP_BLOCK, init_stage); /* Port DMAE comes here */ + bnx2x_init_block(bp, DMAE_BLOCK, init_stage); switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: @@ -6036,7 +6058,7 @@ static int bnx2x_init_func(struct bnx2x *bp) if (CHIP_IS_E1H(bp)) { for (i = 0; i < 9; i++) bnx2x_init_block(bp, - cm_start[func][i], cm_end[func][i]); + cm_blocks[i], FUNC0_STAGE + func); REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov); @@ -6049,7 +6071,7 @@ static int bnx2x_init_func(struct bnx2x *bp) REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); } - bnx2x_init_block(bp, hc_limits[func][0], hc_limits[func][1]); + bnx2x_init_block(bp, HC_BLOCK, FUNC0_STAGE + func); /* Reset PCIE errors for debug */ REG_WR(bp, 0x2114, 0xffffffff); @@ -11082,6 +11104,190 @@ static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp) val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; return val; } +static int __devinit bnx2x_check_firmware(struct bnx2x *bp) +{ + struct bnx2x_fw_file_hdr *fw_hdr; + struct bnx2x_fw_file_section *sections; + u16 *ops_offsets; + u32 offset, len, num_ops; + int i; + const struct firmware *firmware = bp->firmware; + const u8 * fw_ver; + + if (firmware->size < sizeof(struct bnx2x_fw_file_hdr)) + return -EINVAL; + + fw_hdr = (struct bnx2x_fw_file_hdr *)firmware->data; + sections = (struct bnx2x_fw_file_section *)fw_hdr; + + /* Make sure none of the offsets and sizes make us read beyond + * the end of the firmware data */ + for (i = 0; i < sizeof(*fw_hdr) / sizeof(*sections); i++) { + offset = be32_to_cpu(sections[i].offset); + len = be32_to_cpu(sections[i].len); + if (offset + len > firmware->size) { + printk(KERN_ERR PFX "Section %d length is out of bounds\n", i); + return -EINVAL; + } + } + + /* Likewise for the init_ops offsets */ + offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset); + ops_offsets = (u16 *)(firmware->data + offset); + num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op); + + for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) { + if (be16_to_cpu(ops_offsets[i]) > num_ops) { + printk(KERN_ERR PFX "Section offset %d is out of bounds\n", i); + return -EINVAL; + } + } + + /* Check FW version */ + offset = be32_to_cpu(fw_hdr->fw_version.offset); + fw_ver = firmware->data + offset; + if ((fw_ver[0] != BCM_5710_FW_MAJOR_VERSION) || + (fw_ver[1] != BCM_5710_FW_MINOR_VERSION) || + (fw_ver[2] != BCM_5710_FW_REVISION_VERSION) || + (fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) { + printk(KERN_ERR PFX "Bad FW version:%d.%d.%d.%d." + " Should be %d.%d.%d.%d\n", + fw_ver[0], fw_ver[1], fw_ver[2], + fw_ver[3], BCM_5710_FW_MAJOR_VERSION, + BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_ENGINEERING_VERSION); + return -EINVAL; + } + + return 0; +} + +static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +{ + u32 i; + const __be32 *source = (const __be32*)_source; + u32 *target = (u32*)_target; + + for (i = 0; i < n/4; i++) + target[i] = be32_to_cpu(source[i]); +} + +/* + Ops array is stored in the following format: + {op(8bit), offset(24bit, big endian), data(32bit, big endian)} + */ +static void inline bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n) +{ + u32 i, j, tmp; + const __be32 *source = (const __be32*)_source; + struct raw_op *target = (struct raw_op*)_target; + + for (i = 0, j = 0; i < n/8; i++, j+=2) { + tmp = be32_to_cpu(source[j]); + target[i].op = (tmp >> 24) & 0xff; + target[i].offset = tmp & 0xffffff; + target[i].raw_data = be32_to_cpu(source[j+1]); + } +} +static void inline be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +{ + u32 i; + u16 *target = (u16*)_target; + const __be16 *source = (const __be16*)_source; + + for (i = 0; i < n/2; i++) + target[i] = be16_to_cpu(source[i]); +} + +#define BNX2X_ALLOC_AND_SET(arr, lbl, func) \ + do { \ + u32 len = be32_to_cpu(fw_hdr->arr.len); \ + bp->arr = kmalloc(len, GFP_KERNEL); \ + if (!bp->arr) { \ + printk(KERN_ERR PFX "Failed to allocate %d bytes for "#arr"\n", len); \ + goto lbl; \ + } \ + func(bp->firmware->data + \ + be32_to_cpu(fw_hdr->arr.offset), \ + (u8*)bp->arr, len); \ + } while (0) + + +static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) +{ + char fw_file_name[40] = {0}; + int rc, offset; + struct bnx2x_fw_file_hdr *fw_hdr; + + /* Create a FW file name */ + if (CHIP_IS_E1(bp)) + offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1); + else + offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1H); + + sprintf(fw_file_name + offset, "%d.%d.%d.%d.fw", + BCM_5710_FW_MAJOR_VERSION, + BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_ENGINEERING_VERSION); + + printk(KERN_INFO PFX "Loading %s\n", fw_file_name); + + rc = request_firmware(&bp->firmware, fw_file_name, dev); + if (rc) { + printk(KERN_ERR PFX "Can't load firmware file %s\n", fw_file_name); + goto request_firmware_exit; + } + + rc = bnx2x_check_firmware(bp); + if (rc) { + printk(KERN_ERR PFX "Corrupt firmware file %s\n", fw_file_name); + goto request_firmware_exit; + } + + fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data; + + /* Initialize the pointers to the init arrays */ + /* Blob */ + BNX2X_ALLOC_AND_SET(init_data, request_firmware_exit, be32_to_cpu_n); + + /* Opcodes */ + BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops); + + /* Offsets */ + BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, be16_to_cpu_n); + + /* STORMs firmware */ + bp->tsem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_int_table_data.offset); + bp->tsem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_pram_data.offset); + bp->usem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_int_table_data.offset); + bp->usem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_pram_data.offset); + bp->xsem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_int_table_data.offset); + bp->xsem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_pram_data.offset); + bp->csem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_int_table_data.offset); + bp->csem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_pram_data.offset); + + return 0; +init_offsets_alloc_err: + kfree(bp->init_ops); +init_ops_alloc_err: + kfree(bp->init_data); +request_firmware_exit: + release_firmware(bp->firmware); + + return rc; +} + + static int __devinit bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -11116,6 +11322,13 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, if (rc) goto init_one_exit; + /* Set init arrays */ + rc = bnx2x_init_firmware(bp, &pdev->dev); + if (rc) { + printk(KERN_ERR PFX "Error loading firmware\n"); + goto init_one_exit; + } + rc = register_netdev(dev); if (rc) { dev_err(&pdev->dev, "Cannot register net device\n"); @@ -11163,6 +11376,11 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev) unregister_netdev(dev); + kfree(bp->init_ops_offsets); + kfree(bp->init_ops); + kfree(bp->init_data); + release_firmware(bp->firmware); + if (bp->regview) iounmap(bp->regview); @@ -11431,3 +11649,4 @@ static void __exit bnx2x_cleanup(void) module_init(bnx2x_init); module_exit(bnx2x_cleanup); + diff --git a/firmware/Makefile b/firmware/Makefile index 25200d1..1c670e0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -32,6 +32,7 @@ fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \ adaptec/starfire_tx.bin fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw +fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-4.8.53.0.fw bnx2x-e1h-4.8.53.0.fw fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-4.6.17.fw \ bnx2/bnx2-rv2p-09-4.6.15.fw \ bnx2/bnx2-mips-06-4.6.16.fw \ diff --git a/firmware/WHENCE b/firmware/WHENCE index 4c52984..c1e9c5a 100644 --- a/firmware/WHENCE +++ b/firmware/WHENCE @@ -618,6 +618,26 @@ Found in hex form in kernel source. -------------------------------------------------------------------------- +Driver: bnx2x: Broadcom Everest + +File: bnx2x-e1-4.8.53.0.fw.ihex +File: bnx2x-e1h-4.8.53.0.fw.ihex + +License: + Copyright (c) 2007-2009 Broadcom Corporation + + This file contains firmware data derived from proprietary unpublished + source code, Copyright (c) 2007-2009 Broadcom Corporation. + + Permission is hereby granted for the distribution of this firmware data + in hexadecimal or equivalent format, provided this copyright notice is + accompanying it. + + +Found in hex form in kernel source. + +-------------------------------------------------------------------------- + Driver: BNX2 - Broadcom NetXtremeII File: bnx2/bnx2-mips-06-4.6.16.fw -- cgit v0.10.2 From 29b35dd868e9442914a44ff8e8be739c3d65cc9d Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Mon, 27 Apr 2009 03:28:03 -0700 Subject: bnx2x: Removed blob file Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_init_values.h b/drivers/net/bnx2x_init_values.h deleted file mode 100644 index 1f22c9a..0000000 --- a/drivers/net/bnx2x_init_values.h +++ /dev/null @@ -1,16322 +0,0 @@ -#ifndef __BNX2X_INIT_VALUES_H__ -#define __BNX2X_INIT_VALUES_H__ - -/* bnx2x_init_values.h: Broadcom NX2 10G network driver. - * - * Copyright (c) 2007-2009 Broadcom Corporation - * - * 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, except as noted below. - * - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2007-2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - * - * - * This array contains the list of operations needed to initialize the chip. - * - * For each block in the chip there are three init stages: - * common - HW used by both ports, - * port1 and port2 - initialization for a specific Ethernet port. - * When a port is opened or closed, the management CPU tells the driver - * whether to init/disable common HW in addition to the port HW. - * This way the first port going up will first initializes the common HW, - * and the last port going down also resets the common HW - * - * For each init stage/block there is a list of actions needed in a format: - * {operation, register, data} - * where: - * OP_WR - write a value to the chip. - * OP_RD - read a register (usually a clear on read register). - * OP_SW - string write, write a section of consecutive addresses to the chip. - * OP_SI - copy a string using indirect writes. - * OP_ZR - clear a range of memory. - * OP_ZP - unzip and copy using DMAE. - * OP_WB - string copy using DMAE. - * - * The #defines mark the stages. - * - */ - -static const struct raw_op init_ops[] = { -#define PRS_COMMON_START 0 - {OP_WR, PRS_REG_INC_VALUE, 0xf}, - {OP_WR, PRS_REG_EVENT_ID_1, 0x45}, - {OP_WR, PRS_REG_EVENT_ID_2, 0x84}, - {OP_WR, PRS_REG_EVENT_ID_3, 0x6}, - {OP_WR, PRS_REG_NO_MATCH_EVENT_ID, 0x4}, - {OP_WR, PRS_REG_CM_HDR_TYPE_0, 0x0}, - {OP_WR, PRS_REG_CM_HDR_TYPE_1, 0x12170000}, - {OP_WR, PRS_REG_CM_HDR_TYPE_2, 0x22170000}, - {OP_WR, PRS_REG_CM_HDR_TYPE_3, 0x32170000}, - {OP_ZR, PRS_REG_CM_HDR_TYPE_4, 0x5}, - {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_1, 0x12150000}, - {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_2, 0x22150000}, - {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_3, 0x32150000}, - {OP_ZR, PRS_REG_CM_HDR_LOOPBACK_TYPE_4, 0x4}, - {OP_WR, PRS_REG_CM_NO_MATCH_HDR, 0x2100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_0, 0x100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_1, 0x10100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_2, 0x20100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_3, 0x30100000}, - {OP_ZR_E1, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4, 0x4}, - {OP_WR_E1H, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4, 0x40100000}, - {OP_ZR_E1H, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_5, 0x3}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_0, 0x100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_1, 0x12140000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_2, 0x22140000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_3, 0x32140000}, - {OP_ZR_E1, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4, 0x4}, - {OP_WR_E1H, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4, 0x42140000}, - {OP_ZR_E1H, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_5, 0x3}, - {OP_RD, PRS_REG_NUM_OF_PACKETS, 0x0}, - {OP_RD, PRS_REG_NUM_OF_CFC_FLUSH_MESSAGES, 0x0}, - {OP_RD, PRS_REG_NUM_OF_TRANSPARENT_FLUSH_MESSAGES, 0x0}, - {OP_RD, PRS_REG_NUM_OF_DEAD_CYCLES, 0x0}, - {OP_WR_E1H, PRS_REG_FCOE_TYPE, 0x8906}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_0, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_1, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_2, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_3, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_4, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_5, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_6, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_7, 0xff}, - {OP_WR, PRS_REG_PURE_REGIONS, 0x3e}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_0, 0x0}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_1, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_2, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_3, 0x3f}, - {OP_WR_E1, PRS_REG_PACKET_REGIONS_TYPE_4, 0x0}, - {OP_WR_E1H, PRS_REG_PACKET_REGIONS_TYPE_4, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_5, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_6, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_7, 0x3f}, -#define PRS_COMMON_END 52 -#define SRCH_COMMON_START 52 - {OP_WR_E1H, SRC_REG_E1HMF_ENABLE, 0x1}, -#define SRCH_COMMON_END 53 -#define TSDM_COMMON_START 53 - {OP_WR_E1, TSDM_REG_CFC_RSP_START_ADDR, 0x411}, - {OP_WR_E1H, TSDM_REG_CFC_RSP_START_ADDR, 0x211}, - {OP_WR_E1, TSDM_REG_CMP_COUNTER_START_ADDR, 0x400}, - {OP_WR_E1H, TSDM_REG_CMP_COUNTER_START_ADDR, 0x200}, - {OP_WR_E1, TSDM_REG_Q_COUNTER_START_ADDR, 0x404}, - {OP_WR_E1H, TSDM_REG_Q_COUNTER_START_ADDR, 0x204}, - {OP_WR_E1, TSDM_REG_PCK_END_MSG_START_ADDR, 0x419}, - {OP_WR_E1H, TSDM_REG_PCK_END_MSG_START_ADDR, 0x219}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_ZR_E1, TSDM_REG_AGG_INT_EVENT_0, 0x2}, - {OP_WR_E1H, TSDM_REG_AGG_INT_EVENT_0, 0x20}, - {OP_WR_E1H, TSDM_REG_AGG_INT_EVENT_1, 0x0}, - {OP_WR, TSDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, TSDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_ZR_E1, TSDM_REG_AGG_INT_EVENT_4, 0x7c}, - {OP_ZR_E1H, TSDM_REG_AGG_INT_EVENT_4, 0x1c}, - {OP_WR_E1H, TSDM_REG_AGG_INT_T_0, 0x1}, - {OP_ZR_E1H, TSDM_REG_AGG_INT_T_1, 0x5f}, - {OP_WR, TSDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, TSDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, TSDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, TSDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, TSDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, TSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, TSDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, TSDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, TSDM_REG_TIMER_TICK, 0xa}, -#define TSDM_COMMON_END 96 -#define TCM_COMMON_START 96 - {OP_WR, TCM_REG_XX_MAX_LL_SZ, 0x20}, - {OP_WR, TCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, TCM_REG_TQM_TCM_HDR_P, 0x2150020}, - {OP_WR, TCM_REG_TQM_TCM_HDR_S, 0x2150020}, - {OP_WR, TCM_REG_TM_TCM_HDR, 0x30}, - {OP_WR, TCM_REG_ERR_TCM_HDR, 0x8100000}, - {OP_WR, TCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, TCM_REG_EXPR_EVNT_ID, 0x30}, - {OP_WR, TCM_REG_STOP_EVNT_ID, 0x31}, - {OP_WR, TCM_REG_STORM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_PRS_WEIGHT, 0x5}, - {OP_WR, TCM_REG_PBF_WEIGHT, 0x6}, - {OP_WR, TCM_REG_USEM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_CSEM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_CP_WEIGHT, 0x0}, - {OP_WR, TCM_REG_TSDM_WEIGHT, 0x5}, - {OP_WR, TCM_REG_TQM_P_WEIGHT, 0x2}, - {OP_WR, TCM_REG_TQM_S_WEIGHT, 0x2}, - {OP_WR, TCM_REG_TM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_TCM_TQM_USE_Q, 0x1}, - {OP_WR, TCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, TCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, TCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, TCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, TCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, TCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, TCM_REG_TQM_INIT_CRD, 0x20}, - {OP_WR, TCM_REG_XX_INIT_CRD, 0x13}, - {OP_WR, TCM_REG_XX_MSG_NUM, 0x20}, - {OP_ZR, TCM_REG_XX_TABLE, 0xa}, - {OP_SW, TCM_REG_XX_DESCR_TABLE, 0x200000}, - {OP_WR, TCM_REG_N_SM_CTX_LD_0, 0x7}, - {OP_WR, TCM_REG_N_SM_CTX_LD_1, 0x7}, - {OP_WR, TCM_REG_N_SM_CTX_LD_2, 0x8}, - {OP_WR, TCM_REG_N_SM_CTX_LD_3, 0x8}, - {OP_ZR_E1, TCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR_E1H, TCM_REG_N_SM_CTX_LD_4, 0x1}, - {OP_ZR_E1H, TCM_REG_N_SM_CTX_LD_5, 0x3}, - {OP_WR, TCM_REG_TCM_REG0_SZ, 0x6}, - {OP_WR_E1, TCM_REG_PHYS_QNUM0_0, 0xd}, - {OP_WR_E1, TCM_REG_PHYS_QNUM0_1, 0x2d}, - {OP_WR_E1, TCM_REG_PHYS_QNUM1_0, 0x7}, - {OP_WR_E1, TCM_REG_PHYS_QNUM1_1, 0x27}, - {OP_WR_E1, TCM_REG_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1, TCM_REG_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1, TCM_REG_PHYS_QNUM3_0, 0x7}, - {OP_WR_E1, TCM_REG_PHYS_QNUM3_1, 0x27}, - {OP_WR, TCM_REG_TCM_STORM0_IFEN, 0x1}, - {OP_WR, TCM_REG_TCM_STORM1_IFEN, 0x1}, - {OP_WR, TCM_REG_TCM_TQM_IFEN, 0x1}, - {OP_WR, TCM_REG_STORM_TCM_IFEN, 0x1}, - {OP_WR, TCM_REG_TQM_TCM_IFEN, 0x1}, - {OP_WR, TCM_REG_TSDM_IFEN, 0x1}, - {OP_WR, TCM_REG_TM_TCM_IFEN, 0x1}, - {OP_WR, TCM_REG_PRS_IFEN, 0x1}, - {OP_WR, TCM_REG_PBF_IFEN, 0x1}, - {OP_WR, TCM_REG_USEM_IFEN, 0x1}, - {OP_WR, TCM_REG_CSEM_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, TCM_REG_TCM_CFC_IFEN, 0x1}, -#define TCM_COMMON_END 159 -#define TCM_FUNC0_START 159 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0xd}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x7}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x7}, -#define TCM_FUNC0_END 163 -#define TCM_FUNC1_START 163 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x2d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x27}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x27}, -#define TCM_FUNC1_END 167 -#define TCM_FUNC2_START 167 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0x1d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x17}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x17}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x17}, -#define TCM_FUNC2_END 171 -#define TCM_FUNC3_START 171 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x3d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x37}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x37}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x37}, -#define TCM_FUNC3_END 175 -#define TCM_FUNC4_START 175 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0x4d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x47}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x47}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x47}, -#define TCM_FUNC4_END 179 -#define TCM_FUNC5_START 179 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x6d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x67}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x67}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x67}, -#define TCM_FUNC5_END 183 -#define TCM_FUNC6_START 183 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0x5d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x57}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x57}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x57}, -#define TCM_FUNC6_END 187 -#define TCM_FUNC7_START 187 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x7d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x77}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x77}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x77}, -#define TCM_FUNC7_END 191 -#define BRB1_COMMON_START 191 - {OP_SW, BRB1_REG_LL_RAM, 0x2000020}, - {OP_WR, BRB1_REG_SOFT_RESET, 0x1}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_4, 0x0}, - {OP_SW, BRB1_REG_FREE_LIST_PRS_CRDT, 0x30220}, - {OP_WR, BRB1_REG_SOFT_RESET, 0x0}, -#define BRB1_COMMON_END 196 -#define BRB1_PORT0_START 196 - {OP_WR_E1, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0xb8}, - {OP_WR_E1, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 0x114}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_0, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_0, 0x0}, -#define BRB1_PORT0_END 200 -#define BRB1_PORT1_START 200 - {OP_WR_E1, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0xb8}, - {OP_WR_E1, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 0x114}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_1, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_1, 0x0}, -#define BRB1_PORT1_END 204 -#define TSEM_COMMON_START 204 - {OP_RD, TSEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, TSEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, TSEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, TSEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, TSEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, TSEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, TSEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, TSEM_REG_TS_0_AS, 0x0}, - {OP_WR, TSEM_REG_TS_1_AS, 0x1}, - {OP_WR, TSEM_REG_TS_2_AS, 0x4}, - {OP_WR, TSEM_REG_TS_3_AS, 0x0}, - {OP_WR, TSEM_REG_TS_4_AS, 0x1}, - {OP_WR, TSEM_REG_TS_5_AS, 0x3}, - {OP_WR, TSEM_REG_TS_6_AS, 0x0}, - {OP_WR, TSEM_REG_TS_7_AS, 0x1}, - {OP_WR, TSEM_REG_TS_8_AS, 0x4}, - {OP_WR, TSEM_REG_TS_9_AS, 0x0}, - {OP_WR, TSEM_REG_TS_10_AS, 0x1}, - {OP_WR, TSEM_REG_TS_11_AS, 0x3}, - {OP_WR, TSEM_REG_TS_12_AS, 0x0}, - {OP_WR, TSEM_REG_TS_13_AS, 0x1}, - {OP_WR, TSEM_REG_TS_14_AS, 0x4}, - {OP_WR, TSEM_REG_TS_15_AS, 0x0}, - {OP_WR, TSEM_REG_TS_16_AS, 0x4}, - {OP_WR, TSEM_REG_TS_17_AS, 0x3}, - {OP_ZR, TSEM_REG_TS_18_AS, 0x2}, - {OP_WR, TSEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, TSEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, TSEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, TSEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, TSEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, TSEM_REG_THREADS_LIST, 0xff}, - {OP_ZR, TSEM_REG_PASSIVE_BUFFER, 0x400}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18000, 0x34}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18040, 0x18}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18080, 0xc}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x180c0, 0x20}, - {OP_WR_ASIC, TSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, - {OP_WR_EMUL, TSEM_REG_FAST_MEMORY + 0x18300, 0x138}, - {OP_WR_FPGA, TSEM_REG_FAST_MEMORY + 0x18300, 0x1388}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2000, 0xb2}, - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x23c8, 0xc1}, - {OP_WR_EMUL_E1H, TSEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x23c8 + 0x304, 0x10223}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x1000, 0x2b3}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x1000 + 0xacc, 0x10223}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xa020, 0xc8}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1c18, 0x4}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xa000, 0x2}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1c10, 0x2}, - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x1ad0, 0x0}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x1ad8, 0x4}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3678, 0x6}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x810, 0x4}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3670, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1fb0, 0x40224}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5000, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x4cb0, 0x80228}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5008, 0x4}, - {OP_ZP_E1, TSEM_REG_INT_TABLE, 0x930000}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5018, 0x4}, - {OP_WR_64_E1, TSEM_REG_INT_TABLE + 0x360, 0x140230}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5028, 0x4}, - {OP_ZP_E1, TSEM_REG_PRAM, 0x324f0000}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5038, 0x4}, - {OP_ZP_E1, TSEM_REG_PRAM + 0x8000, 0x33250c94}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5048, 0x4}, - {OP_ZP_E1, TSEM_REG_PRAM + 0x10000, 0xe4d195e}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5058, 0x4}, - {OP_WR_64_E1, TSEM_REG_PRAM + 0x11e00, 0x5c400232}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5068, 0x4}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5078, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4000, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4008, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x62c0, 0x200224}, - {OP_ZP_E1H, TSEM_REG_INT_TABLE, 0x9b0000}, - {OP_WR_64_E1H, TSEM_REG_INT_TABLE + 0x398, 0xd0244}, - {OP_ZP_E1H, TSEM_REG_PRAM, 0x325e0000}, - {OP_ZP_E1H, TSEM_REG_PRAM + 0x8000, 0x35960c98}, - {OP_ZP_E1H, TSEM_REG_PRAM + 0x10000, 0x1aea19fe}, - {OP_WR_64_E1H, TSEM_REG_PRAM + 0x143d0, 0x57860246}, -#define TSEM_COMMON_END 297 -#define TSEM_PORT0_START 297 - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x22c8, 0x20}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x2000, 0x16c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x4000, 0x16c}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb000, 0x28}, - {OP_WR_E1, TSEM_REG_FAST_MEMORY + 0x4b60, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb140, 0xc}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1400, 0xa}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x32c0, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1450, 0x6}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3350, 0x64}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1500, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x8108, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1500 + 0x8, 0x50234}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1500 + 0x1c, 0x7}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1570, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x9c0, 0x4c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x820, 0xe}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1fb0, 0x20239}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2908, 0x2}, -#define TSEM_PORT0_END 317 -#define TSEM_PORT1_START 317 - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2348, 0x20}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x25b0, 0x16c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x45b0, 0x16c}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb0a0, 0x28}, - {OP_WR_E1, TSEM_REG_FAST_MEMORY + 0x4b64, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb170, 0xc}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1428, 0xa}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3308, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1468, 0x6}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x34e0, 0x64}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1538, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x8110, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1538 + 0x8, 0x5023b}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1538 + 0x1c, 0x7}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x15b8, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0xaf0, 0x4c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x858, 0xe}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1fb8, 0x20240}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2910, 0x2}, -#define TSEM_PORT1_END 337 -#define TSEM_FUNC0_START 337 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b60, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3000, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3000 + 0x8, 0x50248}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3000 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x31c0, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5000, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5080, 0x12}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4000, 0x2}, -#define TSEM_FUNC0_END 345 -#define TSEM_FUNC1_START 345 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b64, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3038, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3038 + 0x8, 0x5024d}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3038 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x31e0, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5010, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x50c8, 0x12}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4008, 0x2}, -#define TSEM_FUNC1_END 353 -#define TSEM_FUNC2_START 353 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b68, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3070, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3070 + 0x8, 0x50252}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3070 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3200, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5020, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5110, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4010, 0x20257}, -#define TSEM_FUNC2_END 361 -#define TSEM_FUNC3_START 361 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b6c, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30a8, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x30a8 + 0x8, 0x50259}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30a8 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3220, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5030, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5158, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4018, 0x2025e}, -#define TSEM_FUNC3_END 369 -#define TSEM_FUNC4_START 369 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b70, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30e0, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x30e0 + 0x8, 0x50260}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30e0 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3240, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5040, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x51a0, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4020, 0x20265}, -#define TSEM_FUNC4_END 377 -#define TSEM_FUNC5_START 377 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b74, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3118, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3118 + 0x8, 0x50267}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3118 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3260, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5050, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x51e8, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4028, 0x2026c}, -#define TSEM_FUNC5_END 385 -#define TSEM_FUNC6_START 385 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b78, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3150, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3150 + 0x8, 0x5026e}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3150 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3280, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5060, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5230, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4030, 0x20273}, -#define TSEM_FUNC6_END 393 -#define TSEM_FUNC7_START 393 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b7c, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3188, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3188 + 0x8, 0x50275}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3188 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x32a0, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5070, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5278, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4038, 0x2027a}, -#define TSEM_FUNC7_END 401 -#define MISC_COMMON_START 401 - {OP_WR_E1, MISC_REG_GRC_TIMEOUT_EN, 0x1}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_1, 0x71d2911}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_2, 0x0}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_3, 0x9c0424}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_4, 0x0}, - {OP_WR, MISC_REG_LCPLL_CTRL_1, 0x209}, - {OP_WR_E1, MISC_REG_SPIO, 0xff000000}, -#define MISC_COMMON_END 408 -#define MISC_FUNC0_START 408 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC0_END 409 -#define MISC_FUNC1_START 409 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC1_END 410 -#define MISC_FUNC2_START 410 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC2_END 411 -#define MISC_FUNC3_START 411 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC3_END 412 -#define MISC_FUNC4_START 412 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC4_END 413 -#define MISC_FUNC5_START 413 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC5_END 414 -#define MISC_FUNC6_START 414 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC6_END 415 -#define MISC_FUNC7_START 415 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC7_END 416 -#define NIG_COMMON_START 416 - {OP_WR, NIG_REG_PBF_LB_IN_EN, 0x1}, - {OP_WR, NIG_REG_PRS_REQ_IN_EN, 0x1}, - {OP_WR, NIG_REG_EGRESS_DEBUG_IN_EN, 0x1}, - {OP_WR, NIG_REG_BRB_LB_OUT_EN, 0x1}, - {OP_WR, NIG_REG_PRS_EOP_OUT_EN, 0x1}, -#define NIG_COMMON_END 421 -#define NIG_PORT0_START 421 - {OP_WR, NIG_REG_LLH0_CM_HEADER, 0x300000}, - {OP_WR, NIG_REG_LLH0_EVENT_ID, 0x28}, - {OP_WR, NIG_REG_LLH0_ERROR_MASK, 0x0}, - {OP_WR, NIG_REG_LLH0_XCM_MASK, 0x4}, - {OP_WR, NIG_REG_LLH0_BRB1_NOT_MCP, 0x1}, - {OP_WR, NIG_REG_STATUS_INTERRUPT_PORT0, 0x0}, - {OP_WR_E1H, NIG_REG_LLH0_CLS_TYPE, 0x1}, - {OP_WR, NIG_REG_LLH0_XCM_INIT_CREDIT, 0x30}, - {OP_WR, NIG_REG_BRB0_PAUSE_IN_EN, 0x1}, - {OP_WR, NIG_REG_EGRESS_PBF0_IN_EN, 0x1}, - {OP_WR, NIG_REG_BRB0_OUT_EN, 0x1}, - {OP_WR, NIG_REG_XCM0_OUT_EN, 0x1}, -#define NIG_PORT0_END 433 -#define NIG_PORT1_START 433 - {OP_WR, NIG_REG_LLH1_CM_HEADER, 0x300000}, - {OP_WR, NIG_REG_LLH1_EVENT_ID, 0x28}, - {OP_WR, NIG_REG_LLH1_ERROR_MASK, 0x0}, - {OP_WR, NIG_REG_LLH1_XCM_MASK, 0x4}, - {OP_WR, NIG_REG_LLH1_BRB1_NOT_MCP, 0x1}, - {OP_WR, NIG_REG_STATUS_INTERRUPT_PORT1, 0x0}, - {OP_WR_E1H, NIG_REG_LLH1_CLS_TYPE, 0x1}, - {OP_WR, NIG_REG_LLH1_XCM_INIT_CREDIT, 0x30}, - {OP_WR, NIG_REG_BRB1_PAUSE_IN_EN, 0x1}, - {OP_WR, NIG_REG_EGRESS_PBF1_IN_EN, 0x1}, - {OP_WR, NIG_REG_BRB1_OUT_EN, 0x1}, - {OP_WR, NIG_REG_XCM1_OUT_EN, 0x1}, -#define NIG_PORT1_END 445 -#define UPB_COMMON_START 445 - {OP_WR, GRCBASE_UPB + PB_REG_CONTROL, 0x20}, -#define UPB_COMMON_END 446 -#define CSDM_COMMON_START 446 - {OP_WR_E1, CSDM_REG_CFC_RSP_START_ADDR, 0xa11}, - {OP_WR_E1H, CSDM_REG_CFC_RSP_START_ADDR, 0x211}, - {OP_WR_E1, CSDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, - {OP_WR_E1H, CSDM_REG_CMP_COUNTER_START_ADDR, 0x200}, - {OP_WR_E1, CSDM_REG_Q_COUNTER_START_ADDR, 0xa04}, - {OP_WR_E1H, CSDM_REG_Q_COUNTER_START_ADDR, 0x204}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_0, 0xc6}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_1, 0x0}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_ZR, CSDM_REG_AGG_INT_EVENT_4, 0x1c}, - {OP_WR, CSDM_REG_AGG_INT_T_0, 0x1}, - {OP_ZR, CSDM_REG_AGG_INT_T_1, 0x5f}, - {OP_WR, CSDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, CSDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, CSDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, CSDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, CSDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, CSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, CSDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, CSDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, CSDM_REG_TIMER_TICK, 0xa}, -#define CSDM_COMMON_END 485 -#define USDM_COMMON_START 485 - {OP_WR_E1, USDM_REG_CFC_RSP_START_ADDR, 0xa11}, - {OP_WR_E1H, USDM_REG_CFC_RSP_START_ADDR, 0x411}, - {OP_WR_E1, USDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, - {OP_WR_E1H, USDM_REG_CMP_COUNTER_START_ADDR, 0x400}, - {OP_WR_E1, USDM_REG_Q_COUNTER_START_ADDR, 0xa04}, - {OP_WR_E1H, USDM_REG_Q_COUNTER_START_ADDR, 0x404}, - {OP_WR_E1, USDM_REG_PCK_END_MSG_START_ADDR, 0xa21}, - {OP_WR_E1H, USDM_REG_PCK_END_MSG_START_ADDR, 0x421}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_WR, USDM_REG_AGG_INT_EVENT_0, 0x46}, - {OP_WR, USDM_REG_AGG_INT_EVENT_1, 0x5}, - {OP_WR, USDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, USDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_ZR_E1, USDM_REG_AGG_INT_EVENT_4, 0x5c}, - {OP_WR_E1H, USDM_REG_AGG_INT_EVENT_4, 0x7}, - {OP_ZR_E1H, USDM_REG_AGG_INT_EVENT_5, 0x5b}, - {OP_WR, USDM_REG_AGG_INT_MODE_0, 0x1}, - {OP_ZR_E1, USDM_REG_AGG_INT_MODE_1, 0x1f}, - {OP_ZR_E1H, USDM_REG_AGG_INT_MODE_1, 0x3}, - {OP_WR_E1H, USDM_REG_AGG_INT_MODE_4, 0x1}, - {OP_ZR_E1H, USDM_REG_AGG_INT_MODE_5, 0x1b}, - {OP_WR, USDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, USDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, USDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, USDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, USDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q2_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, USDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, USDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, USDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, USDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, USDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, USDM_REG_TIMER_TICK, 0xa}, -#define USDM_COMMON_END 532 -#define CCM_COMMON_START 532 - {OP_WR, CCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, CCM_REG_CQM_CCM_HDR_P, 0x2150020}, - {OP_WR, CCM_REG_CQM_CCM_HDR_S, 0x2150020}, - {OP_WR, CCM_REG_ERR_CCM_HDR, 0x8100000}, - {OP_WR, CCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, CCM_REG_STORM_WEIGHT, 0x2}, - {OP_WR, CCM_REG_TSEM_WEIGHT, 0x0}, - {OP_WR, CCM_REG_XSEM_WEIGHT, 0x5}, - {OP_WR, CCM_REG_USEM_WEIGHT, 0x5}, - {OP_ZR, CCM_REG_PBF_WEIGHT, 0x2}, - {OP_WR, CCM_REG_CSDM_WEIGHT, 0x2}, - {OP_WR, CCM_REG_CQM_P_WEIGHT, 0x3}, - {OP_WR, CCM_REG_CQM_S_WEIGHT, 0x2}, - {OP_WR, CCM_REG_CCM_CQM_USE_Q, 0x1}, - {OP_WR, CCM_REG_CNT_AUX1_Q, 0x2}, - {OP_WR, CCM_REG_CNT_AUX2_Q, 0x2}, - {OP_WR, CCM_REG_INV_DONE_Q, 0x1}, - {OP_WR, CCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, CCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, CCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, CCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, CCM_REG_CQM_INIT_CRD, 0x20}, - {OP_WR, CCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, CCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, CCM_REG_XX_INIT_CRD, 0x3}, - {OP_WR, CCM_REG_XX_MSG_NUM, 0x18}, - {OP_ZR, CCM_REG_XX_TABLE, 0x12}, - {OP_SW_E1, CCM_REG_XX_DESCR_TABLE, 0x240242}, - {OP_SW_E1H, CCM_REG_XX_DESCR_TABLE, 0x24027c}, - {OP_WR, CCM_REG_N_SM_CTX_LD_0, 0x1}, - {OP_WR, CCM_REG_N_SM_CTX_LD_1, 0x2}, - {OP_WR, CCM_REG_N_SM_CTX_LD_2, 0x8}, - {OP_WR, CCM_REG_N_SM_CTX_LD_3, 0x8}, - {OP_ZR, CCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR, CCM_REG_CCM_REG0_SZ, 0x4}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM0_0, 0x9}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM0_1, 0x29}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM1_0, 0xa}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM1_1, 0x2a}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM3_0, 0x7}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM3_1, 0x27}, - {OP_WR_E1, CCM_REG_PHYS_QNUM1_0, 0xc}, - {OP_WR_E1, CCM_REG_PHYS_QNUM1_1, 0x2c}, - {OP_WR_E1, CCM_REG_PHYS_QNUM2_0, 0xc}, - {OP_WR_E1, CCM_REG_PHYS_QNUM2_1, 0x2c}, - {OP_WR_E1, CCM_REG_PHYS_QNUM3_0, 0xc}, - {OP_WR_E1, CCM_REG_PHYS_QNUM3_1, 0x2c}, - {OP_WR, CCM_REG_CCM_STORM0_IFEN, 0x1}, - {OP_WR, CCM_REG_CCM_STORM1_IFEN, 0x1}, - {OP_WR, CCM_REG_CCM_CQM_IFEN, 0x1}, - {OP_WR, CCM_REG_STORM_CCM_IFEN, 0x1}, - {OP_WR, CCM_REG_CQM_CCM_IFEN, 0x1}, - {OP_WR, CCM_REG_CSDM_IFEN, 0x1}, - {OP_WR, CCM_REG_TSEM_IFEN, 0x1}, - {OP_WR, CCM_REG_XSEM_IFEN, 0x1}, - {OP_WR, CCM_REG_USEM_IFEN, 0x1}, - {OP_WR, CCM_REG_PBF_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, CCM_REG_CCM_CFC_IFEN, 0x1}, -#define CCM_COMMON_END 596 -#define CCM_FUNC0_START 596 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x9}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0xa}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x7}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0xc}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0xb}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x7}, -#define CCM_FUNC0_END 603 -#define CCM_FUNC1_START 603 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x29}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x2a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x27}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x2c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x2b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x27}, -#define CCM_FUNC1_END 610 -#define CCM_FUNC2_START 610 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x19}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0x1a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x17}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x17}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0x1c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0x1b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x17}, -#define CCM_FUNC2_END 617 -#define CCM_FUNC3_START 617 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x39}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x3a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x37}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x37}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x3c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x3b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x37}, -#define CCM_FUNC3_END 624 -#define CCM_FUNC4_START 624 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x49}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0x4a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x47}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x47}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0x4c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0x4b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x47}, -#define CCM_FUNC4_END 631 -#define CCM_FUNC5_START 631 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x69}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x6a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x67}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x67}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x6c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x6b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x67}, -#define CCM_FUNC5_END 638 -#define CCM_FUNC6_START 638 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x59}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0x5a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x57}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x57}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0x5c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0x5b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x57}, -#define CCM_FUNC6_END 645 -#define CCM_FUNC7_START 645 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x79}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x7a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x77}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x77}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x7c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x7b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x77}, -#define CCM_FUNC7_END 652 -#define UCM_COMMON_START 652 - {OP_WR, UCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, UCM_REG_UQM_UCM_HDR_P, 0x2150020}, - {OP_WR, UCM_REG_UQM_UCM_HDR_S, 0x2150020}, - {OP_WR, UCM_REG_TM_UCM_HDR, 0x30}, - {OP_WR, UCM_REG_ERR_UCM_HDR, 0x8100000}, - {OP_WR, UCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, UCM_REG_EXPR_EVNT_ID, 0x30}, - {OP_WR, UCM_REG_STOP_EVNT_ID, 0x31}, - {OP_WR, UCM_REG_STORM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_TSEM_WEIGHT, 0x4}, - {OP_WR, UCM_REG_CSEM_WEIGHT, 0x0}, - {OP_WR, UCM_REG_XSEM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_DORQ_WEIGHT, 0x2}, - {OP_WR, UCM_REG_CP_WEIGHT, 0x0}, - {OP_WR, UCM_REG_USDM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_UQM_P_WEIGHT, 0x7}, - {OP_WR, UCM_REG_UQM_S_WEIGHT, 0x2}, - {OP_WR, UCM_REG_TM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_UCM_UQM_USE_Q, 0x1}, - {OP_WR, UCM_REG_INV_CFLG_Q, 0x1}, - {OP_WR, UCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, UCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, UCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, UCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, UCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, UCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, UCM_REG_TM_INIT_CRD, 0x4}, - {OP_WR, UCM_REG_UQM_INIT_CRD, 0x20}, - {OP_WR, UCM_REG_XX_INIT_CRD, 0xe}, - {OP_WR, UCM_REG_XX_MSG_NUM, 0x1b}, - {OP_ZR, UCM_REG_XX_TABLE, 0x12}, - {OP_SW_E1, UCM_REG_XX_DESCR_TABLE, 0x1b0266}, - {OP_SW_E1H, UCM_REG_XX_DESCR_TABLE, 0x1b02a0}, - {OP_WR, UCM_REG_N_SM_CTX_LD_0, 0x10}, - {OP_WR, UCM_REG_N_SM_CTX_LD_1, 0x7}, - {OP_WR, UCM_REG_N_SM_CTX_LD_2, 0xf}, - {OP_WR, UCM_REG_N_SM_CTX_LD_3, 0x10}, - {OP_ZR_E1, UCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR_E1H, UCM_REG_N_SM_CTX_LD_4, 0xb}, - {OP_ZR_E1H, UCM_REG_N_SM_CTX_LD_5, 0x3}, - {OP_WR, UCM_REG_UCM_REG0_SZ, 0x3}, - {OP_WR_E1, UCM_REG_PHYS_QNUM0_0, 0xf}, - {OP_WR_E1, UCM_REG_PHYS_QNUM0_1, 0x2f}, - {OP_WR_E1, UCM_REG_PHYS_QNUM1_0, 0xe}, - {OP_WR_E1, UCM_REG_PHYS_QNUM1_1, 0x2e}, - {OP_WR, UCM_REG_UCM_STORM0_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_STORM1_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_UQM_IFEN, 0x1}, - {OP_WR, UCM_REG_STORM_UCM_IFEN, 0x1}, - {OP_WR, UCM_REG_UQM_UCM_IFEN, 0x1}, - {OP_WR, UCM_REG_USDM_IFEN, 0x1}, - {OP_WR, UCM_REG_TM_UCM_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_TM_IFEN, 0x1}, - {OP_WR, UCM_REG_TSEM_IFEN, 0x1}, - {OP_WR, UCM_REG_CSEM_IFEN, 0x1}, - {OP_WR, UCM_REG_XSEM_IFEN, 0x1}, - {OP_WR, UCM_REG_DORQ_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_CFC_IFEN, 0x1}, -#define UCM_COMMON_END 714 -#define UCM_FUNC0_START 714 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0xf}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0xe}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC0_END 718 -#define UCM_FUNC1_START 718 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x2f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x2e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC1_END 722 -#define UCM_FUNC2_START 722 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0x1f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0x1e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC2_END 726 -#define UCM_FUNC3_START 726 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x3f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x3e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC3_END 730 -#define UCM_FUNC4_START 730 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0x4f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0x4e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC4_END 734 -#define UCM_FUNC5_START 734 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x6f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x6e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC5_END 738 -#define UCM_FUNC6_START 738 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0x5f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0x5e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC6_END 742 -#define UCM_FUNC7_START 742 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x7f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x7e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC7_END 746 -#define USEM_COMMON_START 746 - {OP_RD, USEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, USEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, USEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, USEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, USEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, USEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, USEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, USEM_REG_TS_0_AS, 0x0}, - {OP_WR, USEM_REG_TS_1_AS, 0x1}, - {OP_WR, USEM_REG_TS_2_AS, 0x4}, - {OP_WR, USEM_REG_TS_3_AS, 0x0}, - {OP_WR, USEM_REG_TS_4_AS, 0x1}, - {OP_WR, USEM_REG_TS_5_AS, 0x3}, - {OP_WR, USEM_REG_TS_6_AS, 0x0}, - {OP_WR, USEM_REG_TS_7_AS, 0x1}, - {OP_WR, USEM_REG_TS_8_AS, 0x4}, - {OP_WR, USEM_REG_TS_9_AS, 0x0}, - {OP_WR, USEM_REG_TS_10_AS, 0x1}, - {OP_WR, USEM_REG_TS_11_AS, 0x3}, - {OP_WR, USEM_REG_TS_12_AS, 0x0}, - {OP_WR, USEM_REG_TS_13_AS, 0x1}, - {OP_WR, USEM_REG_TS_14_AS, 0x4}, - {OP_WR, USEM_REG_TS_15_AS, 0x0}, - {OP_WR, USEM_REG_TS_16_AS, 0x4}, - {OP_WR, USEM_REG_TS_17_AS, 0x3}, - {OP_ZR, USEM_REG_TS_18_AS, 0x2}, - {OP_WR, USEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, USEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, USEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, USEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, USEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, USEM_REG_THREADS_LIST, 0xffff}, - {OP_ZR, USEM_REG_PASSIVE_BUFFER, 0x800}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18000, 0x1a}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18040, 0x4e}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18080, 0x10}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x180c0, 0x20}, - {OP_WR_ASIC, USEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, - {OP_WR_EMUL, USEM_REG_FAST_MEMORY + 0x18300, 0x138}, - {OP_WR_FPGA, USEM_REG_FAST_MEMORY + 0x18300, 0x1388}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_WR_ASIC, USEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, - {OP_WR_EMUL, USEM_REG_FAST_MEMORY + 0x18380, 0x4c4b4}, - {OP_WR_FPGA, USEM_REG_FAST_MEMORY + 0x18380, 0x4c4b40}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5000, 0xc2}, - {OP_WR_EMUL_E1H, USEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2000, 0x102}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4640, 0x40}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8980, 0xc8}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x57f0, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8960, 0x2}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x57d8, 0x5}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3228, 0x4}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x57d8 + 0x14, 0x10281}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3200, 0x9}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1c60, 0x20}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x3200 + 0x24, 0x102bb}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x2830, 0x20282}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3180, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5000, 0x400}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4000, 0x2}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x4000 + 0x8, 0x102bc}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4000 + 0xc, 0x3}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b68, 0x2}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x6b68 + 0x8, 0x202bd}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b10, 0x2}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x74c0, 0x202bf}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x10c00, 0x100284}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x10c00, 0x1002c1}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x10c40, 0x100294}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x10c40, 0x1002d1}, - {OP_ZP_E1, USEM_REG_INT_TABLE, 0xc30000}, - {OP_ZP_E1H, USEM_REG_INT_TABLE, 0xd20000}, - {OP_WR_64_E1, USEM_REG_INT_TABLE + 0x368, 0x1302a4}, - {OP_WR_64_E1H, USEM_REG_INT_TABLE + 0x3a8, 0xb02e1}, - {OP_ZP_E1, USEM_REG_PRAM, 0x314c0000}, - {OP_ZP_E1H, USEM_REG_PRAM, 0x31b60000}, - {OP_ZP_E1, USEM_REG_PRAM + 0x8000, 0x35ef0c53}, - {OP_ZP_E1H, USEM_REG_PRAM + 0x8000, 0x36500c6e}, - {OP_ZP_E1, USEM_REG_PRAM + 0x10000, 0x361319cf}, - {OP_ZP_E1H, USEM_REG_PRAM + 0x10000, 0x37591a02}, - {OP_ZP_E1, USEM_REG_PRAM + 0x18000, 0x7112754}, - {OP_ZP_E1H, USEM_REG_PRAM + 0x18000, 0x286127d9}, - {OP_WR_64_E1, USEM_REG_PRAM + 0x18ee0, 0x4e2402a6}, - {OP_WR_64_E1H, USEM_REG_PRAM + 0x1ff40, 0x401802e3}, -#define USEM_COMMON_END 842 -#define USEM_PORT0_START 842 - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1400, 0xa0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9000, 0xa0}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1900, 0x10}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9500, 0x40}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1980, 0x30}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9700, 0x3c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4740, 0xb4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2450, 0xb4}, - {OP_WR_E1, USEM_REG_FAST_MEMORY + 0x1d90, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2ad0, 0x2}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1b40, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3080, 0x20}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1b60, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8000, 0x12c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5318, 0x98}, - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x3238, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5000, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5100, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5200, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5300, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5400, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5500, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5600, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5700, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5800, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5900, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5a00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5b00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5c00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5d00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5e00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5f00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b78, 0x52}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6e08, 0xc}, -#define USEM_PORT0_END 876 -#define USEM_PORT1_START 876 - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1680, 0xa0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9280, 0xa0}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1940, 0x10}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9600, 0x40}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1a40, 0x30}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x97f0, 0x3c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4a10, 0xb4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2720, 0xb4}, - {OP_WR_E1, USEM_REG_FAST_MEMORY + 0x1d94, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2ad8, 0x2}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1b50, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3100, 0x20}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1be0, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x84b0, 0x12c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5578, 0x98}, - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x323c, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5080, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5180, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5280, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5380, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5480, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5580, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5680, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5780, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5880, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5980, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5a80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5b80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5c80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5d80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5e80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5f80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6cc0, 0x52}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6e38, 0xc}, -#define USEM_PORT1_END 910 -#define USEM_FUNC0_START 910 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a30, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3000, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4018, 0x2}, -#define USEM_FUNC0_END 913 -#define USEM_FUNC1_START 913 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a34, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3010, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4028, 0x2}, -#define USEM_FUNC1_END 916 -#define USEM_FUNC2_START 916 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a38, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3020, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4038, 0x2}, -#define USEM_FUNC2_END 919 -#define USEM_FUNC3_START 919 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a3c, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3030, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4048, 0x2}, -#define USEM_FUNC3_END 922 -#define USEM_FUNC4_START 922 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a40, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3040, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4058, 0x2}, -#define USEM_FUNC4_END 925 -#define USEM_FUNC5_START 925 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a44, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3050, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4068, 0x2}, -#define USEM_FUNC5_END 928 -#define USEM_FUNC6_START 928 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a48, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3060, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4078, 0x2}, -#define USEM_FUNC6_END 931 -#define USEM_FUNC7_START 931 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a4c, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3070, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4088, 0x2}, -#define USEM_FUNC7_END 934 -#define CSEM_COMMON_START 934 - {OP_RD, CSEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, CSEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, CSEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, CSEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, CSEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, CSEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, CSEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, CSEM_REG_TS_0_AS, 0x0}, - {OP_WR, CSEM_REG_TS_1_AS, 0x1}, - {OP_WR, CSEM_REG_TS_2_AS, 0x4}, - {OP_WR, CSEM_REG_TS_3_AS, 0x0}, - {OP_WR, CSEM_REG_TS_4_AS, 0x1}, - {OP_WR, CSEM_REG_TS_5_AS, 0x3}, - {OP_WR, CSEM_REG_TS_6_AS, 0x0}, - {OP_WR, CSEM_REG_TS_7_AS, 0x1}, - {OP_WR, CSEM_REG_TS_8_AS, 0x4}, - {OP_WR, CSEM_REG_TS_9_AS, 0x0}, - {OP_WR, CSEM_REG_TS_10_AS, 0x1}, - {OP_WR, CSEM_REG_TS_11_AS, 0x3}, - {OP_WR, CSEM_REG_TS_12_AS, 0x0}, - {OP_WR, CSEM_REG_TS_13_AS, 0x1}, - {OP_WR, CSEM_REG_TS_14_AS, 0x4}, - {OP_WR, CSEM_REG_TS_15_AS, 0x0}, - {OP_WR, CSEM_REG_TS_16_AS, 0x4}, - {OP_WR, CSEM_REG_TS_17_AS, 0x3}, - {OP_ZR, CSEM_REG_TS_18_AS, 0x2}, - {OP_WR, CSEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, CSEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, CSEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, CSEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, CSEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, CSEM_REG_THREADS_LIST, 0xffff}, - {OP_ZR, CSEM_REG_PASSIVE_BUFFER, 0x800}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18000, 0x10}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18040, 0x12}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18080, 0x30}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x180c0, 0xe}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x5000, 0x42}, - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_WR_EMUL_E1H, CSEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x1000, 0x42}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2000, 0xc0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x7020, 0xc8}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3070, 0x80}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x7000, 0x2}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x4280, 0x4}, - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x11e8, 0x0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x25c0, 0x240}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3000, 0xc0}, - {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x2ec8, 0x802a8}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x4070, 0x80}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x5280, 0x4}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6700, 0x100}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x9000, 0x400}, - {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x6b08, 0x2002e5}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x13fffff}, - {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x10c00, 0x1002b0}, - {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x10c00, 0x100305}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x10c40, 0x1002c0}, - {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x10c40, 0x100315}, - {OP_ZP_E1, CSEM_REG_INT_TABLE, 0x710000}, - {OP_ZP_E1H, CSEM_REG_INT_TABLE, 0x740000}, - {OP_WR_64_E1, CSEM_REG_INT_TABLE + 0x380, 0x1002d0}, - {OP_WR_64_E1H, CSEM_REG_INT_TABLE + 0x380, 0x100325}, - {OP_ZP_E1, CSEM_REG_PRAM, 0x32290000}, - {OP_ZP_E1H, CSEM_REG_PRAM, 0x32260000}, - {OP_ZP_E1, CSEM_REG_PRAM + 0x8000, 0x23630c8b}, - {OP_ZP_E1H, CSEM_REG_PRAM + 0x8000, 0x246e0c8a}, - {OP_WR_64_E1, CSEM_REG_PRAM + 0xc930, 0x654002d2}, - {OP_WR_64_E1H, CSEM_REG_PRAM + 0xcbb0, 0x64f00327}, -#define CSEM_COMMON_END 1014 -#define CSEM_PORT0_START 1014 - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1400, 0xa0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8000, 0xa0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1900, 0x10}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8500, 0x40}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1980, 0x30}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8700, 0x3c}, - {OP_WR_E1, CSEM_REG_FAST_MEMORY + 0x5118, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x4040, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2300, 0xe}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3040, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2410, 0x30}, -#define CSEM_PORT0_END 1025 -#define CSEM_PORT1_START 1025 - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1680, 0xa0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8280, 0xa0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1940, 0x10}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8600, 0x40}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1a40, 0x30}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x87f0, 0x3c}, - {OP_WR_E1, CSEM_REG_FAST_MEMORY + 0x511c, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x4058, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2338, 0xe}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3058, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x24d0, 0x30}, -#define CSEM_PORT1_END 1036 -#define CSEM_FUNC0_START 1036 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1148, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3300, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6040, 0x30}, -#define CSEM_FUNC0_END 1039 -#define CSEM_FUNC1_START 1039 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x114c, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3308, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6100, 0x30}, -#define CSEM_FUNC1_END 1042 -#define CSEM_FUNC2_START 1042 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1150, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3310, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x61c0, 0x30}, -#define CSEM_FUNC2_END 1045 -#define CSEM_FUNC3_START 1045 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1154, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3318, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6280, 0x30}, -#define CSEM_FUNC3_END 1048 -#define CSEM_FUNC4_START 1048 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1158, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3320, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6340, 0x30}, -#define CSEM_FUNC4_END 1051 -#define CSEM_FUNC5_START 1051 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x115c, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3328, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6400, 0x30}, -#define CSEM_FUNC5_END 1054 -#define CSEM_FUNC6_START 1054 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1160, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3330, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x64c0, 0x30}, -#define CSEM_FUNC6_END 1057 -#define CSEM_FUNC7_START 1057 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1164, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3338, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6580, 0x30}, -#define CSEM_FUNC7_END 1060 -#define XPB_COMMON_START 1060 - {OP_WR, GRCBASE_XPB + PB_REG_CONTROL, 0x20}, -#define XPB_COMMON_END 1061 -#define DQ_COMMON_START 1061 - {OP_WR, DORQ_REG_MODE_ACT, 0x2}, - {OP_WR, DORQ_REG_NORM_CID_OFST, 0x3}, - {OP_WR, DORQ_REG_OUTST_REQ, 0x4}, - {OP_WR, DORQ_REG_DPM_CID_ADDR, 0x8}, - {OP_WR, DORQ_REG_RSP_INIT_CRD, 0x2}, - {OP_WR, DORQ_REG_NORM_CMHEAD_TX, 0x90}, - {OP_WR, DORQ_REG_CMHEAD_RX, 0x90}, - {OP_WR, DORQ_REG_SHRT_CMHEAD, 0x800090}, - {OP_WR, DORQ_REG_ERR_CMHEAD, 0x8140000}, - {OP_WR, DORQ_REG_AGG_CMD0, 0x8a}, - {OP_WR, DORQ_REG_AGG_CMD1, 0x80}, - {OP_WR, DORQ_REG_AGG_CMD2, 0x90}, - {OP_WR, DORQ_REG_AGG_CMD3, 0x80}, - {OP_WR, DORQ_REG_SHRT_ACT_CNT, 0x6}, - {OP_WR, DORQ_REG_DQ_FIFO_FULL_TH, 0x7d0}, - {OP_WR, DORQ_REG_DQ_FIFO_AFULL_TH, 0x76c}, - {OP_WR, DORQ_REG_REGN, 0x7c1004}, - {OP_WR, DORQ_REG_IF_EN, 0xf}, -#define DQ_COMMON_END 1079 -#define TIMERS_COMMON_START 1079 - {OP_ZR, TM_REG_CLIN_PRIOR0_CLIENT, 0x2}, - {OP_WR, TM_REG_LIN_SETCLR_FIFO_ALFULL_THR, 0x1c}, - {OP_WR, TM_REG_CFC_AC_CRDCNT_VAL, 0x1}, - {OP_WR, TM_REG_CFC_CLD_CRDCNT_VAL, 0x1}, - {OP_WR, TM_REG_CLOUT_CRDCNT0_VAL, 0x1}, - {OP_WR, TM_REG_CLOUT_CRDCNT1_VAL, 0x1}, - {OP_WR, TM_REG_CLOUT_CRDCNT2_VAL, 0x1}, - {OP_WR, TM_REG_EXP_CRDCNT_VAL, 0x1}, - {OP_WR_E1, TM_REG_PCIARB_CRDCNT_VAL, 0x1}, - {OP_WR_E1H, TM_REG_PCIARB_CRDCNT_VAL, 0x2}, - {OP_WR_ASIC, TM_REG_TIMER_TICK_SIZE, 0x3d090}, - {OP_WR_EMUL, TM_REG_TIMER_TICK_SIZE, 0x9c}, - {OP_WR_FPGA, TM_REG_TIMER_TICK_SIZE, 0x9c4}, - {OP_WR, TM_REG_CL0_CONT_REGION, 0x8}, - {OP_WR, TM_REG_CL1_CONT_REGION, 0xc}, - {OP_WR, TM_REG_CL2_CONT_REGION, 0x10}, - {OP_WR, TM_REG_TM_CONTEXT_REGION, 0x20}, - {OP_WR, TM_REG_EN_TIMERS, 0x1}, - {OP_WR, TM_REG_EN_REAL_TIME_CNT, 0x1}, - {OP_WR, TM_REG_EN_CL0_INPUT, 0x1}, - {OP_WR, TM_REG_EN_CL1_INPUT, 0x1}, - {OP_WR, TM_REG_EN_CL2_INPUT, 0x1}, -#define TIMERS_COMMON_END 1101 -#define TIMERS_PORT0_START 1101 - {OP_WR, TM_REG_LIN0_LOGIC_ADDR, 0x0}, - {OP_WR, TM_REG_LIN0_PHY_ADDR_VALID, 0x0}, - {OP_ZR, TM_REG_LIN0_PHY_ADDR, 0x2}, -#define TIMERS_PORT0_END 1104 -#define TIMERS_PORT1_START 1104 - {OP_WR, TM_REG_LIN1_LOGIC_ADDR, 0x0}, - {OP_WR, TM_REG_LIN1_PHY_ADDR_VALID, 0x0}, - {OP_ZR, TM_REG_LIN1_PHY_ADDR, 0x2}, -#define TIMERS_PORT1_END 1107 -#define XSDM_COMMON_START 1107 - {OP_WR_E1, XSDM_REG_CFC_RSP_START_ADDR, 0x614}, - {OP_WR_E1H, XSDM_REG_CFC_RSP_START_ADDR, 0x424}, - {OP_WR_E1, XSDM_REG_CMP_COUNTER_START_ADDR, 0x600}, - {OP_WR_E1H, XSDM_REG_CMP_COUNTER_START_ADDR, 0x410}, - {OP_WR_E1, XSDM_REG_Q_COUNTER_START_ADDR, 0x604}, - {OP_WR_E1H, XSDM_REG_Q_COUNTER_START_ADDR, 0x414}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_0, 0x20}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_1, 0x20}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_4, 0x23}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_5, 0x24}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_6, 0x25}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_7, 0x26}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_8, 0x27}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_9, 0x29}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_10, 0x2a}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_11, 0x2b}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_12, 0x2c}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_13, 0x2d}, - {OP_ZR, XSDM_REG_AGG_INT_EVENT_14, 0x52}, - {OP_WR, XSDM_REG_AGG_INT_MODE_0, 0x1}, - {OP_ZR, XSDM_REG_AGG_INT_MODE_1, 0x1f}, - {OP_WR, XSDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, XSDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, XSDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, XSDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, XSDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, XSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, XSDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, XSDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, XSDM_REG_TIMER_TICK, 0xa}, -#define XSDM_COMMON_END 1156 -#define QM_COMMON_START 1156 - {OP_WR, QM_REG_ACTCTRINITVAL_0, 0x6}, - {OP_WR, QM_REG_ACTCTRINITVAL_1, 0x5}, - {OP_WR, QM_REG_ACTCTRINITVAL_2, 0xa}, - {OP_WR, QM_REG_ACTCTRINITVAL_3, 0x5}, - {OP_WR, QM_REG_PCIREQAT, 0x2}, - {OP_WR, QM_REG_CMINITCRD_0, 0x4}, - {OP_WR, QM_REG_CMINITCRD_1, 0x4}, - {OP_WR, QM_REG_CMINITCRD_2, 0x4}, - {OP_WR, QM_REG_CMINITCRD_3, 0x4}, - {OP_WR, QM_REG_CMINITCRD_4, 0x4}, - {OP_WR, QM_REG_CMINITCRD_5, 0x4}, - {OP_WR, QM_REG_CMINITCRD_6, 0x4}, - {OP_WR, QM_REG_CMINITCRD_7, 0x4}, - {OP_WR, QM_REG_OUTLDREQ, 0x4}, - {OP_WR, QM_REG_CTXREG_0, 0x7c}, - {OP_WR, QM_REG_CTXREG_1, 0x3d}, - {OP_WR, QM_REG_CTXREG_2, 0x3f}, - {OP_WR, QM_REG_CTXREG_3, 0x9c}, - {OP_WR, QM_REG_ENSEC, 0x7}, - {OP_ZR, QM_REG_QVOQIDX_0, 0x5}, - {OP_WR, QM_REG_WRRWEIGHTS_0, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_5, 0x0}, - {OP_WR, QM_REG_QVOQIDX_6, 0x4}, - {OP_WR, QM_REG_QVOQIDX_7, 0x4}, - {OP_WR, QM_REG_QVOQIDX_8, 0x2}, - {OP_WR, QM_REG_WRRWEIGHTS_1, 0x8012004}, - {OP_WR, QM_REG_QVOQIDX_9, 0x5}, - {OP_WR, QM_REG_QVOQIDX_10, 0x5}, - {OP_WR, QM_REG_QVOQIDX_11, 0x5}, - {OP_WR, QM_REG_QVOQIDX_12, 0x5}, - {OP_WR, QM_REG_WRRWEIGHTS_2, 0x20081001}, - {OP_WR, QM_REG_QVOQIDX_13, 0x8}, - {OP_WR, QM_REG_QVOQIDX_14, 0x6}, - {OP_WR, QM_REG_QVOQIDX_15, 0x7}, - {OP_WR, QM_REG_QVOQIDX_16, 0x0}, - {OP_WR, QM_REG_WRRWEIGHTS_3, 0x1010120}, - {OP_ZR, QM_REG_QVOQIDX_17, 0x4}, - {OP_WR, QM_REG_WRRWEIGHTS_4, 0x1010101}, - {OP_ZR_E1, QM_REG_QVOQIDX_21, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_21, 0x0}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_5, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_22, 0x4}, - {OP_ZR_E1, QM_REG_QVOQIDX_25, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_23, 0x4}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_6, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_24, 0x2}, - {OP_ZR_E1, QM_REG_QVOQIDX_29, 0x3}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_5, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_25, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_26, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_27, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_28, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_6, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_29, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_30, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_31, 0x7}, - {OP_WR, QM_REG_QVOQIDX_32, 0x1}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_7, 0x1010101}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_7, 0x1010120}, - {OP_WR, QM_REG_QVOQIDX_33, 0x1}, - {OP_WR, QM_REG_QVOQIDX_34, 0x1}, - {OP_WR, QM_REG_QVOQIDX_35, 0x1}, - {OP_WR, QM_REG_QVOQIDX_36, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_8, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_37, 0x1}, - {OP_WR, QM_REG_QVOQIDX_38, 0x4}, - {OP_WR, QM_REG_QVOQIDX_39, 0x4}, - {OP_WR, QM_REG_QVOQIDX_40, 0x2}, - {OP_WR, QM_REG_WRRWEIGHTS_9, 0x8012004}, - {OP_WR, QM_REG_QVOQIDX_41, 0x5}, - {OP_WR, QM_REG_QVOQIDX_42, 0x5}, - {OP_WR, QM_REG_QVOQIDX_43, 0x5}, - {OP_WR, QM_REG_QVOQIDX_44, 0x5}, - {OP_WR, QM_REG_WRRWEIGHTS_10, 0x20081001}, - {OP_WR, QM_REG_QVOQIDX_45, 0x8}, - {OP_WR, QM_REG_QVOQIDX_46, 0x6}, - {OP_WR, QM_REG_QVOQIDX_47, 0x7}, - {OP_WR, QM_REG_QVOQIDX_48, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_11, 0x1010120}, - {OP_WR, QM_REG_QVOQIDX_49, 0x1}, - {OP_WR, QM_REG_QVOQIDX_50, 0x1}, - {OP_WR, QM_REG_QVOQIDX_51, 0x1}, - {OP_WR, QM_REG_QVOQIDX_52, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_12, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_53, 0x1}, - {OP_WR_E1, QM_REG_QVOQIDX_54, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_54, 0x4}, - {OP_WR_E1, QM_REG_QVOQIDX_55, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_55, 0x4}, - {OP_WR_E1, QM_REG_QVOQIDX_56, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_56, 0x2}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_13, 0x1010101}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_13, 0x8012004}, - {OP_WR_E1, QM_REG_QVOQIDX_57, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_57, 0x5}, - {OP_WR_E1, QM_REG_QVOQIDX_58, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_58, 0x5}, - {OP_WR_E1, QM_REG_QVOQIDX_59, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_59, 0x5}, - {OP_WR_E1, QM_REG_QVOQIDX_60, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_60, 0x5}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_14, 0x1010101}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_14, 0x20081001}, - {OP_WR_E1, QM_REG_QVOQIDX_61, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_61, 0x8}, - {OP_WR_E1, QM_REG_QVOQIDX_62, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_62, 0x6}, - {OP_WR_E1, QM_REG_QVOQIDX_63, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_63, 0x7}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_15, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_64, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_0_LSB, 0xffff003f}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_15, 0x1010120}, - {OP_ZR_E1, QM_REG_VOQQMASK_0_MSB, 0x2}, - {OP_ZR_E1H, QM_REG_QVOQIDX_65, 0x4}, - {OP_WR_E1, QM_REG_VOQQMASK_1_MSB, 0xffff003f}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_16, 0x1010101}, - {OP_WR_E1, QM_REG_VOQQMASK_2_LSB, 0x100}, - {OP_WR_E1H, QM_REG_QVOQIDX_69, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_2_MSB, 0x100}, - {OP_WR_E1H, QM_REG_QVOQIDX_70, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_71, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_72, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_17, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_73, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_74, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_75, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_76, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_18, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_77, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_78, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_79, 0x7}, - {OP_WR_E1H, QM_REG_QVOQIDX_80, 0x0}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_19, 0x1010120}, - {OP_ZR_E1H, QM_REG_QVOQIDX_81, 0x4}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_20, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_85, 0x0}, - {OP_WR_E1H, QM_REG_QVOQIDX_86, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_87, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_88, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_21, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_89, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_90, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_91, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_92, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_22, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_93, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_94, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_95, 0x7}, - {OP_WR_E1H, QM_REG_QVOQIDX_96, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_23, 0x1010120}, - {OP_WR_E1H, QM_REG_QVOQIDX_97, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_98, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_99, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_100, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_24, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_101, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_102, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_103, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_104, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_25, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_105, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_106, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_107, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_108, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_26, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_109, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_110, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_111, 0x7}, - {OP_WR_E1H, QM_REG_QVOQIDX_112, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_27, 0x1010120}, - {OP_WR_E1H, QM_REG_QVOQIDX_113, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_114, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_115, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_116, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_28, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_117, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_118, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_119, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_120, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_29, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_121, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_122, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_123, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_124, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_30, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_125, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_126, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_127, 0x7}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_31, 0x1010120}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_LSB, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_MSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_LSB_EXT_A, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_LSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_MSB, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_MSB_EXT_A, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_LSB, 0x1000100}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_MSB, 0x1000100}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_LSB_EXT_A, 0x1000100}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_MSB_EXT_A, 0x1000100}, - {OP_ZR, QM_REG_VOQQMASK_3_LSB, 0x2}, - {OP_WR_E1, QM_REG_VOQQMASK_4_LSB, 0xc0}, - {OP_WR_E1H, QM_REG_VOQQMASK_3_LSB_EXT_A, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_4_MSB, 0xc0}, - {OP_WR_E1H, QM_REG_VOQQMASK_3_MSB_EXT_A, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_5_LSB, 0x1e00}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_LSB, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_5_MSB, 0x1e00}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_MSB, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_6_LSB, 0x4000}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_LSB_EXT_A, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_6_MSB, 0x4000}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_MSB_EXT_A, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_7_LSB, 0x8000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_LSB, 0x1e001e00}, - {OP_WR_E1, QM_REG_VOQQMASK_7_MSB, 0x8000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_MSB, 0x1e001e00}, - {OP_WR_E1, QM_REG_VOQQMASK_8_LSB, 0x2000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_LSB_EXT_A, 0x1e001e00}, - {OP_WR_E1, QM_REG_VOQQMASK_8_MSB, 0x2000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_MSB_EXT_A, 0x1e001e00}, - {OP_ZR_E1, QM_REG_VOQQMASK_9_LSB, 0x7}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_LSB, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_MSB, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_LSB_EXT_A, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_MSB_EXT_A, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_LSB, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_MSB, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_LSB_EXT_A, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_MSB_EXT_A, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_LSB, 0x20002000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_MSB, 0x20002000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_LSB_EXT_A, 0x20002000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_MSB_EXT_A, 0x20002000}, - {OP_ZR_E1H, QM_REG_VOQQMASK_9_LSB, 0x2}, - {OP_WR_E1H, QM_REG_VOQQMASK_9_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_9_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_LSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_MSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_LSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_MSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQPORT_0, 0x0}, - {OP_WR, QM_REG_VOQPORT_1, 0x1}, - {OP_ZR, QM_REG_VOQPORT_2, 0xa}, - {OP_WR, QM_REG_CMINTVOQMASK_0, 0xc08}, - {OP_WR, QM_REG_CMINTVOQMASK_1, 0x40}, - {OP_WR, QM_REG_CMINTVOQMASK_2, 0x100}, - {OP_WR, QM_REG_CMINTVOQMASK_3, 0x20}, - {OP_WR, QM_REG_CMINTVOQMASK_4, 0x17}, - {OP_WR, QM_REG_CMINTVOQMASK_5, 0x80}, - {OP_WR, QM_REG_CMINTVOQMASK_6, 0x200}, - {OP_WR, QM_REG_CMINTVOQMASK_7, 0x0}, - {OP_WR_E1, QM_REG_HWAEMPTYMASK_LSB, 0xffff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_LSB, 0x1ff01ff}, - {OP_WR_E1, QM_REG_HWAEMPTYMASK_MSB, 0xffff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_MSB, 0x1ff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_LSB_EXT_A, 0x1ff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_MSB_EXT_A, 0x1ff01ff}, - {OP_WR, QM_REG_ENBYPVOQMASK, 0x13}, - {OP_WR, QM_REG_VOQCREDITAFULLTHR, 0x13f}, - {OP_WR, QM_REG_VOQINITCREDIT_0, 0x140}, - {OP_WR, QM_REG_VOQINITCREDIT_1, 0x140}, - {OP_ZR, QM_REG_VOQINITCREDIT_2, 0x2}, - {OP_WR, QM_REG_VOQINITCREDIT_4, 0xc0}, - {OP_ZR, QM_REG_VOQINITCREDIT_5, 0x7}, - {OP_WR, QM_REG_TASKCRDCOST_0, 0x48}, - {OP_WR, QM_REG_TASKCRDCOST_1, 0x48}, - {OP_ZR, QM_REG_TASKCRDCOST_2, 0x2}, - {OP_WR, QM_REG_TASKCRDCOST_4, 0x48}, - {OP_ZR, QM_REG_TASKCRDCOST_5, 0x7}, - {OP_WR, QM_REG_BYTECRDINITVAL, 0x8000}, - {OP_WR, QM_REG_BYTECRDCOST, 0x25e4}, - {OP_WR, QM_REG_BYTECREDITAFULLTHR, 0x7fff}, - {OP_WR_E1, QM_REG_ENBYTECRD_LSB, 0x7}, - {OP_WR_E1H, QM_REG_ENBYTECRD_LSB, 0x70007}, - {OP_WR_E1, QM_REG_ENBYTECRD_MSB, 0x7}, - {OP_WR_E1H, QM_REG_ENBYTECRD_MSB, 0x70007}, - {OP_WR_E1H, QM_REG_ENBYTECRD_LSB_EXT_A, 0x70007}, - {OP_WR_E1H, QM_REG_ENBYTECRD_MSB_EXT_A, 0x70007}, - {OP_WR, QM_REG_BYTECRDPORT_LSB, 0x0}, - {OP_WR, QM_REG_BYTECRDPORT_MSB, 0xffffffff}, - {OP_WR_E1, QM_REG_FUNCNUMSEL_LSB, 0x0}, - {OP_WR_E1H, QM_REG_BYTECRDPORT_LSB_EXT_A, 0x0}, - {OP_WR_E1, QM_REG_FUNCNUMSEL_MSB, 0xffffffff}, - {OP_WR_E1H, QM_REG_BYTECRDPORT_MSB_EXT_A, 0xffffffff}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_0, 0x0}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_1, 0x2}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_2, 0x1}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_3, 0x3}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_4, 0x4}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_5, 0x6}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_6, 0x5}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_7, 0x7}, - {OP_WR, QM_REG_CMINTEN, 0xff}, -#define QM_COMMON_END 1456 -#define PBF_COMMON_START 1456 - {OP_WR, PBF_REG_INIT, 0x1}, - {OP_WR, PBF_REG_INIT_P4, 0x1}, - {OP_WR, PBF_REG_MAC_LB_ENABLE, 0x1}, - {OP_WR, PBF_REG_IF_ENABLE_REG, 0x7fff}, - {OP_WR, PBF_REG_INIT_P4, 0x0}, - {OP_WR, PBF_REG_INIT, 0x0}, - {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P4, 0x0}, -#define PBF_COMMON_END 1463 -#define PBF_PORT0_START 1463 - {OP_WR, PBF_REG_INIT_P0, 0x1}, - {OP_WR, PBF_REG_MAC_IF0_ENABLE, 0x1}, - {OP_WR, PBF_REG_INIT_P0, 0x0}, - {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P0, 0x0}, -#define PBF_PORT0_END 1467 -#define PBF_PORT1_START 1467 - {OP_WR, PBF_REG_INIT_P1, 0x1}, - {OP_WR, PBF_REG_MAC_IF1_ENABLE, 0x1}, - {OP_WR, PBF_REG_INIT_P1, 0x0}, - {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P1, 0x0}, -#define PBF_PORT1_END 1471 -#define XCM_COMMON_START 1471 - {OP_WR, XCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, XCM_REG_XQM_XCM_HDR_P, 0x3150020}, - {OP_WR, XCM_REG_XQM_XCM_HDR_S, 0x3150020}, - {OP_WR, XCM_REG_TM_XCM_HDR, 0x1000030}, - {OP_WR, XCM_REG_ERR_XCM_HDR, 0x8100000}, - {OP_WR, XCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, XCM_REG_EXPR_EVNT_ID, 0x30}, - {OP_WR, XCM_REG_STOP_EVNT_ID, 0x31}, - {OP_WR, XCM_REG_STORM_WEIGHT, 0x3}, - {OP_WR, XCM_REG_TSEM_WEIGHT, 0x6}, - {OP_WR, XCM_REG_CSEM_WEIGHT, 0x3}, - {OP_WR, XCM_REG_USEM_WEIGHT, 0x3}, - {OP_WR, XCM_REG_DORQ_WEIGHT, 0x2}, - {OP_WR, XCM_REG_PBF_WEIGHT, 0x0}, - {OP_WR, XCM_REG_NIG0_WEIGHT, 0x2}, - {OP_WR, XCM_REG_CP_WEIGHT, 0x0}, - {OP_WR, XCM_REG_XSDM_WEIGHT, 0x6}, - {OP_WR, XCM_REG_XQM_P_WEIGHT, 0x4}, - {OP_WR, XCM_REG_XQM_S_WEIGHT, 0x2}, - {OP_WR, XCM_REG_TM_WEIGHT, 0x2}, - {OP_WR, XCM_REG_XCM_XQM_USE_Q, 0x1}, - {OP_WR, XCM_REG_XQM_BYP_ACT_UPD, 0x6}, - {OP_WR, XCM_REG_UNA_GT_NXT_Q, 0x0}, - {OP_WR, XCM_REG_AUX1_Q, 0x2}, - {OP_WR, XCM_REG_AUX_CNT_FLG_Q_19, 0x1}, - {OP_WR, XCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, XCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, XCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, XCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, XCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, XCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, XCM_REG_TM_INIT_CRD, 0x4}, - {OP_WR, XCM_REG_XQM_INIT_CRD, 0x20}, - {OP_WR, XCM_REG_XX_INIT_CRD, 0x2}, - {OP_WR_E1, XCM_REG_XX_MSG_NUM, 0x1f}, - {OP_WR_E1H, XCM_REG_XX_MSG_NUM, 0x20}, - {OP_ZR, XCM_REG_XX_TABLE, 0x12}, - {OP_SW_E1, XCM_REG_XX_DESCR_TABLE, 0x1f02d4}, - {OP_SW_E1H, XCM_REG_XX_DESCR_TABLE, 0x1f0329}, - {OP_WR, XCM_REG_N_SM_CTX_LD_0, 0xf}, - {OP_WR, XCM_REG_N_SM_CTX_LD_1, 0x7}, - {OP_WR, XCM_REG_N_SM_CTX_LD_2, 0xb}, - {OP_WR, XCM_REG_N_SM_CTX_LD_3, 0xe}, - {OP_ZR_E1, XCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR_E1H, XCM_REG_N_SM_CTX_LD_4, 0xe}, - {OP_ZR_E1H, XCM_REG_N_SM_CTX_LD_5, 0x3}, - {OP_WR, XCM_REG_XCM_REG0_SZ, 0x4}, - {OP_WR, XCM_REG_XCM_STORM0_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_STORM1_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_XQM_IFEN, 0x1}, - {OP_WR, XCM_REG_STORM_XCM_IFEN, 0x1}, - {OP_WR, XCM_REG_XQM_XCM_IFEN, 0x1}, - {OP_WR, XCM_REG_XSDM_IFEN, 0x1}, - {OP_WR, XCM_REG_TM_XCM_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_TM_IFEN, 0x1}, - {OP_WR, XCM_REG_TSEM_IFEN, 0x1}, - {OP_WR, XCM_REG_CSEM_IFEN, 0x1}, - {OP_WR, XCM_REG_USEM_IFEN, 0x1}, - {OP_WR, XCM_REG_DORQ_IFEN, 0x1}, - {OP_WR, XCM_REG_PBF_IFEN, 0x1}, - {OP_WR, XCM_REG_NIG0_IFEN, 0x1}, - {OP_WR, XCM_REG_NIG1_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_CFC_IFEN, 0x1}, -#define XCM_COMMON_END 1538 -#define XCM_PORT0_START 1538 - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, -#define XCM_PORT0_END 1546 -#define XCM_PORT1_START 1546 - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, -#define XCM_PORT1_END 1554 -#define XCM_FUNC0_START 1554 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC0_END 1563 -#define XCM_FUNC1_START 1563 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC1_END 1572 -#define XCM_FUNC2_START 1572 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC2_END 1581 -#define XCM_FUNC3_START 1581 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC3_END 1590 -#define XCM_FUNC4_START 1590 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC4_END 1599 -#define XCM_FUNC5_START 1599 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC5_END 1608 -#define XCM_FUNC6_START 1608 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC6_END 1617 -#define XCM_FUNC7_START 1617 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC7_END 1626 -#define XSEM_COMMON_START 1626 - {OP_RD, XSEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, XSEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, XSEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, XSEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, XSEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, XSEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, XSEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, XSEM_REG_TS_0_AS, 0x0}, - {OP_WR, XSEM_REG_TS_1_AS, 0x1}, - {OP_WR, XSEM_REG_TS_2_AS, 0x4}, - {OP_WR, XSEM_REG_TS_3_AS, 0x0}, - {OP_WR, XSEM_REG_TS_4_AS, 0x1}, - {OP_WR, XSEM_REG_TS_5_AS, 0x3}, - {OP_WR, XSEM_REG_TS_6_AS, 0x0}, - {OP_WR, XSEM_REG_TS_7_AS, 0x1}, - {OP_WR, XSEM_REG_TS_8_AS, 0x4}, - {OP_WR, XSEM_REG_TS_9_AS, 0x0}, - {OP_WR, XSEM_REG_TS_10_AS, 0x1}, - {OP_WR, XSEM_REG_TS_11_AS, 0x3}, - {OP_WR, XSEM_REG_TS_12_AS, 0x0}, - {OP_WR, XSEM_REG_TS_13_AS, 0x1}, - {OP_WR, XSEM_REG_TS_14_AS, 0x4}, - {OP_WR, XSEM_REG_TS_15_AS, 0x0}, - {OP_WR, XSEM_REG_TS_16_AS, 0x4}, - {OP_WR, XSEM_REG_TS_17_AS, 0x3}, - {OP_ZR, XSEM_REG_TS_18_AS, 0x2}, - {OP_WR, XSEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, XSEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, XSEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, XSEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, XSEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, XSEM_REG_THREADS_LIST, 0xffff}, - {OP_ZR, XSEM_REG_PASSIVE_BUFFER, 0x800}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18000, 0x0}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18040, 0x18}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18080, 0xc}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x180c0, 0x66}, - {OP_WR_ASIC, XSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, - {OP_WR_EMUL, XSEM_REG_FAST_MEMORY + 0x18300, 0x138}, - {OP_WR_FPGA, XSEM_REG_FAST_MEMORY + 0x18300, 0x1388}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_WR_ASIC, XSEM_REG_FAST_MEMORY + 0x18340, 0x1f4}, - {OP_WR_EMUL, XSEM_REG_FAST_MEMORY + 0x18340, 0x0}, - {OP_WR_FPGA, XSEM_REG_FAST_MEMORY + 0x18340, 0x5}, - {OP_WR_EMUL, XSEM_REG_FAST_MEMORY + 0x18380, 0x4c4b4}, - {OP_WR_ASIC, XSEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, - {OP_WR_EMUL_E1H, XSEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_WR_FPGA, XSEM_REG_FAST_MEMORY + 0x18380, 0x4c4b40}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3d60, 0x4}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d60 + 0x10, 0x202f3}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x29c8, 0x4}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3000, 0x48}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29c8 + 0x10, 0x20348}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2080, 0x48}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x9020, 0xc8}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3128, 0x8e}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x9000, 0x2}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3368, 0x0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x21a8, 0x86}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3370, 0x202f5}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2000, 0x20}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3b90, 0x402f7}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x23c8, 0x0}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3e20, 0x202fb}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x23d0, 0x2034a}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1518, 0x1}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2498, 0x4034c}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1830, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x2c20, 0x0}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1838, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x2c10, 0x0}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x1820, 0x202fd}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2c08, 0x20350}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4ac0, 0x2}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x3010, 0x1}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4b00, 0x4}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x4040, 0x10}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x1f48, 0x202ff}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x4000, 0x100352}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6ac0, 0x2}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6b00, 0x4}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x8408, 0x20362}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c00, 0x100301}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c00, 0x100364}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c40, 0x80311}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c40, 0x80374}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x2000000}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c60, 0x80319}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c60, 0x8037c}, - {OP_ZP_E1, XSEM_REG_INT_TABLE, 0xb50000}, - {OP_ZP_E1H, XSEM_REG_INT_TABLE, 0xbd0000}, - {OP_WR_64_E1, XSEM_REG_INT_TABLE + 0x368, 0x130321}, - {OP_WR_64_E1H, XSEM_REG_INT_TABLE + 0x3a8, 0xb0384}, - {OP_ZP_E1, XSEM_REG_PRAM, 0x33660000}, - {OP_ZP_E1H, XSEM_REG_PRAM, 0x34060000}, - {OP_ZP_E1, XSEM_REG_PRAM + 0x8000, 0x38b30cda}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x8000, 0x37960d02}, - {OP_ZP_E1, XSEM_REG_PRAM + 0x10000, 0x3bb11b07}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x10000, 0x3bc31ae8}, - {OP_ZP_E1, XSEM_REG_PRAM + 0x18000, 0x2a2629f4}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x18000, 0x382629d9}, - {OP_WR_64_E1, XSEM_REG_PRAM + 0x1d6c0, 0x45280323}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x20000, 0x124537e3}, - {OP_WR_64_E1H, XSEM_REG_PRAM + 0x22220, 0x3bbc0386}, -#define XSEM_COMMON_END 1741 -#define XSEM_PORT0_START 1741 - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3ba0, 0x14}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xc000, 0xfc}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3c40, 0x24}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x24a8, 0x14}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1400, 0xa}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2548, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1450, 0x6}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2668, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3378, 0xfc}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2788, 0x24}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3b58, 0x0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x28a8, 0x24}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d78, 0x20325}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa000, 0x28}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d88, 0x100327}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa140, 0xc}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1500, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29e0, 0x20388}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1508, 0x1}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x3000, 0x1}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5020, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5030, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5000, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5010, 0x2}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x5040, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x5208, 0x1}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x5048, 0xe}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x6ac8, 0x2038a}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x50b8, 0x1}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6b10, 0x42}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x4ac8, 0x20337}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6d20, 0x4}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4b10, 0x42}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4d20, 0x4}, -#define XSEM_PORT0_END 1775 -#define XSEM_PORT1_START 1775 - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3bf0, 0x14}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xc3f0, 0xfc}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3cd0, 0x24}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x24f8, 0x14}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1428, 0xa}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x25d8, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1468, 0x6}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x26f8, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3768, 0xfc}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2818, 0x24}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3b5c, 0x0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2938, 0x24}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d80, 0x20339}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa0a0, 0x28}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3dc8, 0x10033b}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa170, 0xc}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1504, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29e8, 0x2038c}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x150c, 0x1}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x3004, 0x1}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5028, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5038, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5008, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5018, 0x2}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x5044, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x520c, 0x1}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x5080, 0xe}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x6ad0, 0x2038e}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x50bc, 0x1}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6c18, 0x42}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x4ad0, 0x2034b}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6d30, 0x4}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4c18, 0x42}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4d30, 0x4}, -#define XSEM_PORT1_END 1809 -#define XSEM_FUNC0_START 1809 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e0, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29f0, 0x100390}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5048, 0xe}, -#define XSEM_FUNC0_END 1812 -#define XSEM_FUNC1_START 1812 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e4, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2a30, 0x1003a0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5080, 0xe}, -#define XSEM_FUNC1_END 1815 -#define XSEM_FUNC2_START 1815 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e8, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2a70, 0x1003b0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x50b8, 0xe}, -#define XSEM_FUNC2_END 1818 -#define XSEM_FUNC3_START 1818 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7ec, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2ab0, 0x1003c0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x50f0, 0xe}, -#define XSEM_FUNC3_END 1821 -#define XSEM_FUNC4_START 1821 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f0, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2af0, 0x1003d0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5128, 0xe}, -#define XSEM_FUNC4_END 1824 -#define XSEM_FUNC5_START 1824 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f4, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2b30, 0x1003e0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5160, 0xe}, -#define XSEM_FUNC5_END 1827 -#define XSEM_FUNC6_START 1827 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f8, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2b70, 0x1003f0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5198, 0xe}, -#define XSEM_FUNC6_END 1830 -#define XSEM_FUNC7_START 1830 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7fc, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2bb0, 0x100400}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x51d0, 0xe}, -#define XSEM_FUNC7_END 1833 -#define CDU_COMMON_START 1833 - {OP_WR, CDU_REG_CDU_CONTROL0, 0x1}, - {OP_WR_E1H, CDU_REG_MF_MODE, 0x1}, - {OP_WR, CDU_REG_CDU_CHK_MASK0, 0x3d000}, - {OP_WR, CDU_REG_CDU_CHK_MASK1, 0x3d}, - {OP_WB_E1, CDU_REG_L1TT, 0x200034d}, - {OP_WB_E1H, CDU_REG_L1TT, 0x2000410}, - {OP_WB_E1, CDU_REG_MATT, 0x20054d}, - {OP_WB_E1H, CDU_REG_MATT, 0x280610}, - {OP_ZR_E1, CDU_REG_MATT + 0x80, 0x2}, - {OP_WB_E1, CDU_REG_MATT + 0x88, 0x6056d}, - {OP_ZR, CDU_REG_MATT + 0xa0, 0x18}, -#define CDU_COMMON_END 1844 -#define DMAE_COMMON_START 1844 - {OP_ZR, DMAE_REG_CMD_MEM, 0xe0}, - {OP_WR, DMAE_REG_CRC16C_INIT, 0x0}, - {OP_WR, DMAE_REG_CRC16T10_INIT, 0x1}, - {OP_WR_E1, DMAE_REG_PXP_REQ_INIT_CRD, 0x1}, - {OP_WR_E1H, DMAE_REG_PXP_REQ_INIT_CRD, 0x2}, - {OP_WR, DMAE_REG_PCI_IFEN, 0x1}, - {OP_WR, DMAE_REG_GRC_IFEN, 0x1}, -#define DMAE_COMMON_END 1851 -#define PXP_COMMON_START 1851 - {OP_WB_E1, PXP_REG_HST_INBOUND_INT + 0x400, 0x50573}, - {OP_WB_E1H, PXP_REG_HST_INBOUND_INT + 0x400, 0x50638}, - {OP_WB_E1, PXP_REG_HST_INBOUND_INT + 0x420, 0x50578}, - {OP_WB_E1H, PXP_REG_HST_INBOUND_INT, 0x5063d}, - {OP_WB_E1, PXP_REG_HST_INBOUND_INT, 0x5057d}, - {OP_WB_E1H, PXP_REG_HST_INBOUND_INT + 0x20, 0x50642}, -#define PXP_COMMON_END 1857 -#define CFC_COMMON_START 1857 - {OP_ZR_E1H, CFC_REG_LINK_LIST, 0x100}, - {OP_WR, CFC_REG_CONTROL0, 0x10}, - {OP_WR, CFC_REG_DISABLE_ON_ERROR, 0x3fff}, - {OP_WR, CFC_REG_INTERFACES, 0x280000}, - {OP_WR, CFC_REG_LCREQ_WEIGHTS, 0x84924a}, - {OP_WR, CFC_REG_INTERFACES, 0x0}, -#define CFC_COMMON_END 1863 -#define HC_COMMON_START 1863 - {OP_ZR_E1, HC_REG_USTORM_ADDR_FOR_COALESCE, 0x4}, -#define HC_COMMON_END 1864 -#define HC_PORT0_START 1864 - {OP_WR_E1, HC_REG_CONFIG_0, 0x1080}, - {OP_ZR_E1, HC_REG_UC_RAM_ADDR_0, 0x2}, - {OP_WR_E1, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1, HC_REG_LEADING_EDGE_0, 0xffff}, - {OP_WR_E1, HC_REG_TRAILING_EDGE_0, 0xffff}, - {OP_WR_E1, HC_REG_AGG_INT_0, 0x0}, - {OP_WR_E1, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_PORT0_END 1882 -#define HC_PORT1_START 1882 - {OP_WR_E1, HC_REG_CONFIG_1, 0x1080}, - {OP_ZR_E1, HC_REG_UC_RAM_ADDR_1, 0x2}, - {OP_WR_E1, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1, HC_REG_LEADING_EDGE_1, 0xffff}, - {OP_WR_E1, HC_REG_TRAILING_EDGE_1, 0xffff}, - {OP_WR_E1, HC_REG_AGG_INT_1, 0x0}, - {OP_WR_E1, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_PORT1_END 1900 -#define HC_FUNC0_START 1900 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x0}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC0_END 1915 -#define HC_FUNC1_START 1915 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x1}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC1_END 1930 -#define HC_FUNC2_START 1930 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x2}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC2_END 1945 -#define HC_FUNC3_START 1945 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x3}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC3_END 1960 -#define HC_FUNC4_START 1960 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x4}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC4_END 1975 -#define HC_FUNC5_START 1975 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x5}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC5_END 1990 -#define HC_FUNC6_START 1990 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x6}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC6_END 2005 -#define HC_FUNC7_START 2005 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x7}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC7_END 2020 -#define PXP2_COMMON_START 2020 - {OP_WR_E1H, PXP2_REG_RQ_DRAM_ALIGN, 0x1}, - {OP_WR, PXP2_REG_PGL_CONTROL0, 0xe38340}, - {OP_WR, PXP2_REG_PGL_CONTROL1, 0x3c10}, - {OP_WR_E1H, PXP2_REG_RQ_ELT_DISABLE, 0x1}, - {OP_WR_E1H, PXP2_REG_WR_REV_MODE, 0x0}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_0, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_7, 0xffffffff}, - {OP_WR_E1, PXP2_REG_PGL_INT_USDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_7, 0xffffffff}, - {OP_WR_E1H, PXP2_REG_PGL_INT_XSDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_7, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_0, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_7, 0xffffffff}, - {OP_WR_E1, PXP2_REG_PGL_INT_XSDM_0, 0xffff3330}, - {OP_WR_E1H, PXP2_REG_PGL_INT_XSDM_0, 0xff802000}, - {OP_WR_E1, PXP2_REG_PGL_INT_XSDM_1, 0xffff3340}, - {OP_WR_E1H, PXP2_REG_PGL_INT_USDM_0, 0xf0005000}, - {OP_WR_E1, PXP2_REG_PGL_INT_USDM_0, 0xf0003000}, - {OP_WR_E1H, PXP2_REG_PGL_INT_USDM_1, 0xf0008000}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ6, 0x8}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ9, 0x8}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ10, 0x8}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ11, 0x2}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ17, 0x4}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ18, 0x5}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ19, 0x4}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ22, 0x0}, - {OP_WR, PXP2_REG_RD_START_INIT, 0x1}, - {OP_WR, PXP2_REG_WR_DMAE_TH, 0x3f}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD0, 0x40}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD1, 0x1808}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD2, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD3, 0x803}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD4, 0x40}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD5, 0x3}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD6, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD7, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD8, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD9, 0x10003}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD10, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD11, 0x803}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD12, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD13, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD14, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD15, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD16, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD17, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD18, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD19, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD20, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD22, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD23, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD24, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD25, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD26, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD27, 0x3}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD28, 0x2403}, - {OP_WR, PXP2_REG_RQ_BW_WR_ADD29, 0x2f}, - {OP_WR, PXP2_REG_RQ_BW_WR_ADD30, 0x9}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND0, 0x19}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB1, 0x184}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB2, 0x183}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB3, 0x306}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND4, 0x19}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND5, 0x6}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB6, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB7, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB8, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB9, 0xc86}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB10, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB11, 0x306}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND12, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND13, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND14, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND15, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND16, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND17, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND18, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND19, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND20, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND22, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND23, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND24, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND25, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND26, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND27, 0x6}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB28, 0x306}, - {OP_WR, PXP2_REG_RQ_BW_WR_UBOUND29, 0x13}, - {OP_WR, PXP2_REG_RQ_BW_WR_UBOUND30, 0x6}, - {OP_WR, PXP2_REG_PSWRQ_BW_L1, 0x1004}, - {OP_WR, PXP2_REG_PSWRQ_BW_L2, 0x1004}, - {OP_WR, PXP2_REG_PSWRQ_BW_RD, 0x106440}, - {OP_WR, PXP2_REG_PSWRQ_BW_WR, 0x106440}, - {OP_WR_E1H, PXP2_REG_RQ_ILT_MODE, 0x1}, - {OP_WR, PXP2_REG_RQ_RBC_DONE, 0x1}, -#define PXP2_COMMON_END 2137 -#define MISC_AEU_COMMON_START 2137 - {OP_ZR, MISC_REG_AEU_GENERAL_ATTN_0, 0x16}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_NIG_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_NIG_0, 0x55555555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_NIG_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_NIG_0, 0xf0000000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_PXP_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_PXP_0, 0x55555555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_PXP_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_PXP_0, 0xf0000000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_NIG_1, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_NIG_1, 0x55555555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_NIG_1, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_NIG_1, 0xf0000000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_PXP_1, 0x0}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_PXP_1, 0x10000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_PXP_1, 0x5014}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_PXP_1, 0x0}, - {OP_WR_E1H, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0xc00}, - {OP_WR_E1H, MISC_REG_AEU_GENERAL_MASK, 0x3}, -#define MISC_AEU_COMMON_END 2156 -#define MISC_AEU_PORT0_START 2156 - {OP_WR_E1, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, 0xbf5c0000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, 0xff5c0000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0, 0xfff51fef}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0, 0xfff55fff}, - {OP_WR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_0, 0xffff}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, 0x500003e0}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, 0xf00003e0}, - {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1, 0x0}, - {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_1, 0xa000}, - {OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_1, 0x5}, - {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2, 0xfe00000}, - {OP_ZR_E1, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3, 0x14}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3, 0x7}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_NIG_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_4, 0x400}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_NIG_0, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_5, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_NIG_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_5, 0x1000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_NIG_0, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_6, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_PXP_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_6, 0x4000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_PXP_0, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_7, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_PXP_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_7, 0x10000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_PXP_0, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_INVERTER_1_FUNC_0, 0x4}, - {OP_WR_E1, MISC_REG_AEU_INVERTER_1_FUNC_0, 0x0}, - {OP_ZR_E1, MISC_REG_AEU_INVERTER_2_FUNC_0, 0x3}, - {OP_WR_E1, MISC_REG_AEU_MASK_ATTN_FUNC_0, 0x7}, -#define MISC_AEU_PORT0_END 2188 -#define MISC_AEU_PORT1_START 2188 - {OP_WR_E1, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0, 0xbf5c0000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0, 0xff5c0000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0, 0xfff51fef}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0, 0xfff55fff}, - {OP_WR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0, 0xffff}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, 0x500003e0}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, 0xf00003e0}, - {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1, 0x0}, - {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1, 0xa000}, - {OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1, 0x5}, - {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2, 0xfe00000}, - {OP_ZR_E1, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3, 0x14}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3, 0x7}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_NIG_1, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_4, 0x800}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_NIG_1, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_5, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_NIG_1, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_5, 0x2000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_NIG_1, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_6, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_PXP_1, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_6, 0x8000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_PXP_1, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_7, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_PXP_1, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_7, 0x20000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_PXP_1, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_INVERTER_1_FUNC_1, 0x4}, - {OP_WR_E1, MISC_REG_AEU_INVERTER_1_FUNC_1, 0x0}, - {OP_ZR_E1, MISC_REG_AEU_INVERTER_2_FUNC_1, 0x3}, - {OP_WR_E1, MISC_REG_AEU_MASK_ATTN_FUNC_1, 0x7}, -#define MISC_AEU_PORT1_END 2220 - -}; - -static const u32 init_data_e1[] = { - 0x00010000, 0x000204c0, 0x00030980, 0x00040e40, 0x00051300, 0x000617c0, - 0x00071c80, 0x00082140, 0x00092600, 0x000a2ac0, 0x000b2f80, 0x000c3440, - 0x000d3900, 0x000e3dc0, 0x000f4280, 0x00104740, 0x00114c00, 0x001250c0, - 0x00135580, 0x00145a40, 0x00155f00, 0x001663c0, 0x00176880, 0x00186d40, - 0x00197200, 0x001a76c0, 0x001b7b80, 0x001c8040, 0x001d8500, 0x001e89c0, - 0x001f8e80, 0x00209340, 0x00002000, 0x00004000, 0x00006000, 0x00008000, - 0x0000a000, 0x0000c000, 0x0000e000, 0x00010000, 0x00012000, 0x00014000, - 0x00016000, 0x00018000, 0x0001a000, 0x0001c000, 0x0001e000, 0x00020000, - 0x00022000, 0x00024000, 0x00026000, 0x00028000, 0x0002a000, 0x0002c000, - 0x0002e000, 0x00030000, 0x00032000, 0x00034000, 0x00036000, 0x00038000, - 0x0003a000, 0x0003c000, 0x0003e000, 0x00040000, 0x00042000, 0x00044000, - 0x00046000, 0x00048000, 0x0004a000, 0x0004c000, 0x0004e000, 0x00050000, - 0x00052000, 0x00054000, 0x00056000, 0x00058000, 0x0005a000, 0x0005c000, - 0x0005e000, 0x00060000, 0x00062000, 0x00064000, 0x00066000, 0x00068000, - 0x0006a000, 0x0006c000, 0x0006e000, 0x00070000, 0x00072000, 0x00074000, - 0x00076000, 0x00078000, 0x0007a000, 0x0007c000, 0x0007e000, 0x00080000, - 0x00082000, 0x00084000, 0x00086000, 0x00088000, 0x0008a000, 0x0008c000, - 0x0008e000, 0x00090000, 0x00092000, 0x00094000, 0x00096000, 0x00098000, - 0x0009a000, 0x0009c000, 0x0009e000, 0x000a0000, 0x000a2000, 0x000a4000, - 0x000a6000, 0x000a8000, 0x000aa000, 0x000ac000, 0x000ae000, 0x000b0000, - 0x000b2000, 0x000b4000, 0x000b6000, 0x000b8000, 0x000ba000, 0x000bc000, - 0x000be000, 0x000c0000, 0x000c2000, 0x000c4000, 0x000c6000, 0x000c8000, - 0x000ca000, 0x000cc000, 0x000ce000, 0x000d0000, 0x000d2000, 0x000d4000, - 0x000d6000, 0x000d8000, 0x000da000, 0x000dc000, 0x000de000, 0x000e0000, - 0x000e2000, 0x000e4000, 0x000e6000, 0x000e8000, 0x000ea000, 0x000ec000, - 0x000ee000, 0x000f0000, 0x000f2000, 0x000f4000, 0x000f6000, 0x000f8000, - 0x000fa000, 0x000fc000, 0x000fe000, 0x00100000, 0x00102000, 0x00104000, - 0x00106000, 0x00108000, 0x0010a000, 0x0010c000, 0x0010e000, 0x00110000, - 0x00112000, 0x00114000, 0x00116000, 0x00118000, 0x0011a000, 0x0011c000, - 0x0011e000, 0x00120000, 0x00122000, 0x00124000, 0x00126000, 0x00128000, - 0x0012a000, 0x0012c000, 0x0012e000, 0x00130000, 0x00132000, 0x00134000, - 0x00136000, 0x00138000, 0x0013a000, 0x0013c000, 0x0013e000, 0x00140000, - 0x00142000, 0x00144000, 0x00146000, 0x00148000, 0x0014a000, 0x0014c000, - 0x0014e000, 0x00150000, 0x00152000, 0x00154000, 0x00156000, 0x00158000, - 0x0015a000, 0x0015c000, 0x0015e000, 0x00160000, 0x00162000, 0x00164000, - 0x00166000, 0x00168000, 0x0016a000, 0x0016c000, 0x0016e000, 0x00170000, - 0x00172000, 0x00174000, 0x00176000, 0x00178000, 0x0017a000, 0x0017c000, - 0x0017e000, 0x00180000, 0x00182000, 0x00184000, 0x00186000, 0x00188000, - 0x0018a000, 0x0018c000, 0x0018e000, 0x00190000, 0x00192000, 0x00194000, - 0x00196000, 0x00198000, 0x0019a000, 0x0019c000, 0x0019e000, 0x001a0000, - 0x001a2000, 0x001a4000, 0x001a6000, 0x001a8000, 0x001aa000, 0x001ac000, - 0x001ae000, 0x001b0000, 0x001b2000, 0x001b4000, 0x001b6000, 0x001b8000, - 0x001ba000, 0x001bc000, 0x001be000, 0x001c0000, 0x001c2000, 0x001c4000, - 0x001c6000, 0x001c8000, 0x001ca000, 0x001cc000, 0x001ce000, 0x001d0000, - 0x001d2000, 0x001d4000, 0x001d6000, 0x001d8000, 0x001da000, 0x001dc000, - 0x001de000, 0x001e0000, 0x001e2000, 0x001e4000, 0x001e6000, 0x001e8000, - 0x001ea000, 0x001ec000, 0x001ee000, 0x001f0000, 0x001f2000, 0x001f4000, - 0x001f6000, 0x001f8000, 0x001fa000, 0x001fc000, 0x001fe000, 0x00200000, - 0x00202000, 0x00204000, 0x00206000, 0x00208000, 0x0020a000, 0x0020c000, - 0x0020e000, 0x00210000, 0x00212000, 0x00214000, 0x00216000, 0x00218000, - 0x0021a000, 0x0021c000, 0x0021e000, 0x00220000, 0x00222000, 0x00224000, - 0x00226000, 0x00228000, 0x0022a000, 0x0022c000, 0x0022e000, 0x00230000, - 0x00232000, 0x00234000, 0x00236000, 0x00238000, 0x0023a000, 0x0023c000, - 0x0023e000, 0x00240000, 0x00242000, 0x00244000, 0x00246000, 0x00248000, - 0x0024a000, 0x0024c000, 0x0024e000, 0x00250000, 0x00252000, 0x00254000, - 0x00256000, 0x00258000, 0x0025a000, 0x0025c000, 0x0025e000, 0x00260000, - 0x00262000, 0x00264000, 0x00266000, 0x00268000, 0x0026a000, 0x0026c000, - 0x0026e000, 0x00270000, 0x00272000, 0x00274000, 0x00276000, 0x00278000, - 0x0027a000, 0x0027c000, 0x0027e000, 0x00280000, 0x00282000, 0x00284000, - 0x00286000, 0x00288000, 0x0028a000, 0x0028c000, 0x0028e000, 0x00290000, - 0x00292000, 0x00294000, 0x00296000, 0x00298000, 0x0029a000, 0x0029c000, - 0x0029e000, 0x002a0000, 0x002a2000, 0x002a4000, 0x002a6000, 0x002a8000, - 0x002aa000, 0x002ac000, 0x002ae000, 0x002b0000, 0x002b2000, 0x002b4000, - 0x002b6000, 0x002b8000, 0x002ba000, 0x002bc000, 0x002be000, 0x002c0000, - 0x002c2000, 0x002c4000, 0x002c6000, 0x002c8000, 0x002ca000, 0x002cc000, - 0x002ce000, 0x002d0000, 0x002d2000, 0x002d4000, 0x002d6000, 0x002d8000, - 0x002da000, 0x002dc000, 0x002de000, 0x002e0000, 0x002e2000, 0x002e4000, - 0x002e6000, 0x002e8000, 0x002ea000, 0x002ec000, 0x002ee000, 0x002f0000, - 0x002f2000, 0x002f4000, 0x002f6000, 0x002f8000, 0x002fa000, 0x002fc000, - 0x002fe000, 0x00300000, 0x00302000, 0x00304000, 0x00306000, 0x00308000, - 0x0030a000, 0x0030c000, 0x0030e000, 0x00310000, 0x00312000, 0x00314000, - 0x00316000, 0x00318000, 0x0031a000, 0x0031c000, 0x0031e000, 0x00320000, - 0x00322000, 0x00324000, 0x00326000, 0x00328000, 0x0032a000, 0x0032c000, - 0x0032e000, 0x00330000, 0x00332000, 0x00334000, 0x00336000, 0x00338000, - 0x0033a000, 0x0033c000, 0x0033e000, 0x00340000, 0x00342000, 0x00344000, - 0x00346000, 0x00348000, 0x0034a000, 0x0034c000, 0x0034e000, 0x00350000, - 0x00352000, 0x00354000, 0x00356000, 0x00358000, 0x0035a000, 0x0035c000, - 0x0035e000, 0x00360000, 0x00362000, 0x00364000, 0x00366000, 0x00368000, - 0x0036a000, 0x0036c000, 0x0036e000, 0x00370000, 0x00372000, 0x00374000, - 0x00376000, 0x00378000, 0x0037a000, 0x0037c000, 0x0037e000, 0x00380000, - 0x00382000, 0x00384000, 0x00386000, 0x00388000, 0x0038a000, 0x0038c000, - 0x0038e000, 0x00390000, 0x00392000, 0x00394000, 0x00396000, 0x00398000, - 0x0039a000, 0x0039c000, 0x0039e000, 0x003a0000, 0x003a2000, 0x003a4000, - 0x003a6000, 0x003a8000, 0x003aa000, 0x003ac000, 0x003ae000, 0x003b0000, - 0x003b2000, 0x003b4000, 0x003b6000, 0x003b8000, 0x003ba000, 0x003bc000, - 0x003be000, 0x003c0000, 0x003c2000, 0x003c4000, 0x003c6000, 0x003c8000, - 0x003ca000, 0x003cc000, 0x003ce000, 0x003d0000, 0x003d2000, 0x003d4000, - 0x003d6000, 0x003d8000, 0x003da000, 0x003dc000, 0x003de000, 0x003e0000, - 0x003e2000, 0x003e4000, 0x003e6000, 0x003e8000, 0x003ea000, 0x003ec000, - 0x003ee000, 0x003f0000, 0x003f2000, 0x003f4000, 0x003f6000, 0x003f8000, - 0x003fa000, 0x003fc000, 0x003fe000, 0x003fe001, 0x00000000, 0x000001ff, - 0x00000200, 0x00000001, 0x00000003, 0x00bebc20, 0x00000003, 0x00bebc20, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00007ff8, 0x00000000, 0x00003500, - 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, - 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0x00000003, 0x00bebc20, 0x00002000, 0x000040c0, 0x00006180, 0x00008240, - 0x0000a300, 0x0000c3c0, 0x0000e480, 0x00010540, 0x00012600, 0x000146c0, - 0x00016780, 0x00018840, 0x0001a900, 0x0001c9c0, 0x0001ea80, 0x00020b40, - 0x00022c00, 0x00024cc0, 0x00026d80, 0x00028e40, 0x0002af00, 0x0002cfc0, - 0x0002f080, 0x00031140, 0x00033200, 0x000352c0, 0x00037380, 0x00039440, - 0x0003b500, 0x0003d5c0, 0x0003f680, 0x00041740, 0x00043800, 0x000458c0, - 0x00047980, 0x00049a40, 0x00008000, 0x00010380, 0x00018700, 0x00020a80, - 0x00028e00, 0x00031180, 0x00039500, 0x00041880, 0x00049c00, 0x00051f80, - 0x0005a300, 0x00062680, 0x0006aa00, 0x00072d80, 0x0007b100, 0x00083480, - 0x0008b800, 0x00093b80, 0x0009bf00, 0x000a4280, 0x000ac600, 0x000b4980, - 0x000bcd00, 0x000c5080, 0x000cd400, 0x000d5780, 0x000ddb00, 0x00001900, - 0x00000000, 0xffffffff, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x00000000, 0x00007ff8, - 0x00000000, 0x00001500, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x00000000, 0x00007ff8, 0x00000000, 0x00001500, 0x00001000, 0x00002080, - 0x00003100, 0x00004180, 0x00005200, 0x00006280, 0x00007300, 0x00008380, - 0x00009400, 0x0000a480, 0x0000b500, 0x0000c580, 0x0000d600, 0x0000e680, - 0x0000f700, 0x00010780, 0x00011800, 0x00012880, 0x00013900, 0x00014980, - 0x00015a00, 0x00016a80, 0x00017b00, 0x00018b80, 0x00019c00, 0x0001ac80, - 0x0001bd00, 0x0001cd80, 0x0001de00, 0x0001ee80, 0x0001ff00, 0x10000000, - 0x000028ad, 0x00000000, 0x00010001, 0x00350804, 0xccccccc1, 0xffffffff, - 0xffffffff, 0x7058103c, 0x00000000, 0xcccc0201, 0xcccccccc, 0x00000000, - 0xffffffff, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x00000000, 0x00007ff8, 0x00000000, - 0x00003500, 0x000e01b7, 0x011600d6, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x00100000, 0x00000000, 0x007201bb, 0x012300f3, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x00100000, 0x00000000, 0xfffffff3, - 0x320fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, - 0xcdcdcdcd, 0xfffffff1, 0x30efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, - 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, - 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, - 0x31efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, - 0xcdcdcdcd, 0xfffffff5, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x310fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, - 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, - 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, - 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, - 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, - 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x30efffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, - 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, - 0xcdcdcdcd, 0xfffffff3, 0x31efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, - 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, - 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, - 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, - 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, - 0xcdcdcdcd, 0xffffff97, 0x056fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, - 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x310fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, - 0x320fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, - 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, - 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, - 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffff8a, 0x042fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, - 0x05cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, - 0xcdcdcdcd, 0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x300fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, - 0x300fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, - 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, - 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, - 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, - 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x040fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, - 0x300fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, - 0xcdcdcdcd, 0x00100000, 0x00070100, 0x00028170, 0x000b8198, 0x00020250, - 0x00010270, 0x000f0280, 0x00010370, 0x00080000, 0x00080080, 0x00028100, - 0x000b8128, 0x000201e0, 0x00010200, 0x00070210, 0x00020280, 0x000f0000, - 0x000800f0, 0x00028170, 0x000b8198, 0x00020250, 0x00010270, 0x000b8280, - 0x00080338, 0x00100000, 0x00080100, 0x00028180, 0x000b81a8, 0x00020260, - 0x00018280, 0x000e8298, 0x00080380, 0x00028000, 0x000b8028, 0x000200e0, - 0x00010100, 0x00008110, 0x00000118, 0xcccccccc, 0xcccccccc, 0xcccccccc, - 0xcccccccc, 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, - 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000 -}; - -static const u32 init_data_e1h[] = { - 0x00010000, 0x000204c0, 0x00030980, 0x00040e40, 0x00051300, 0x000617c0, - 0x00071c80, 0x00082140, 0x00092600, 0x000a2ac0, 0x000b2f80, 0x000c3440, - 0x000d3900, 0x000e3dc0, 0x000f4280, 0x00104740, 0x00114c00, 0x001250c0, - 0x00135580, 0x00145a40, 0x00155f00, 0x001663c0, 0x00176880, 0x00186d40, - 0x00197200, 0x001a76c0, 0x001b7b80, 0x001c8040, 0x001d8500, 0x001e89c0, - 0x001f8e80, 0x00209340, 0x00002000, 0x00004000, 0x00006000, 0x00008000, - 0x0000a000, 0x0000c000, 0x0000e000, 0x00010000, 0x00012000, 0x00014000, - 0x00016000, 0x00018000, 0x0001a000, 0x0001c000, 0x0001e000, 0x00020000, - 0x00022000, 0x00024000, 0x00026000, 0x00028000, 0x0002a000, 0x0002c000, - 0x0002e000, 0x00030000, 0x00032000, 0x00034000, 0x00036000, 0x00038000, - 0x0003a000, 0x0003c000, 0x0003e000, 0x00040000, 0x00042000, 0x00044000, - 0x00046000, 0x00048000, 0x0004a000, 0x0004c000, 0x0004e000, 0x00050000, - 0x00052000, 0x00054000, 0x00056000, 0x00058000, 0x0005a000, 0x0005c000, - 0x0005e000, 0x00060000, 0x00062000, 0x00064000, 0x00066000, 0x00068000, - 0x0006a000, 0x0006c000, 0x0006e000, 0x00070000, 0x00072000, 0x00074000, - 0x00076000, 0x00078000, 0x0007a000, 0x0007c000, 0x0007e000, 0x00080000, - 0x00082000, 0x00084000, 0x00086000, 0x00088000, 0x0008a000, 0x0008c000, - 0x0008e000, 0x00090000, 0x00092000, 0x00094000, 0x00096000, 0x00098000, - 0x0009a000, 0x0009c000, 0x0009e000, 0x000a0000, 0x000a2000, 0x000a4000, - 0x000a6000, 0x000a8000, 0x000aa000, 0x000ac000, 0x000ae000, 0x000b0000, - 0x000b2000, 0x000b4000, 0x000b6000, 0x000b8000, 0x000ba000, 0x000bc000, - 0x000be000, 0x000c0000, 0x000c2000, 0x000c4000, 0x000c6000, 0x000c8000, - 0x000ca000, 0x000cc000, 0x000ce000, 0x000d0000, 0x000d2000, 0x000d4000, - 0x000d6000, 0x000d8000, 0x000da000, 0x000dc000, 0x000de000, 0x000e0000, - 0x000e2000, 0x000e4000, 0x000e6000, 0x000e8000, 0x000ea000, 0x000ec000, - 0x000ee000, 0x000f0000, 0x000f2000, 0x000f4000, 0x000f6000, 0x000f8000, - 0x000fa000, 0x000fc000, 0x000fe000, 0x00100000, 0x00102000, 0x00104000, - 0x00106000, 0x00108000, 0x0010a000, 0x0010c000, 0x0010e000, 0x00110000, - 0x00112000, 0x00114000, 0x00116000, 0x00118000, 0x0011a000, 0x0011c000, - 0x0011e000, 0x00120000, 0x00122000, 0x00124000, 0x00126000, 0x00128000, - 0x0012a000, 0x0012c000, 0x0012e000, 0x00130000, 0x00132000, 0x00134000, - 0x00136000, 0x00138000, 0x0013a000, 0x0013c000, 0x0013e000, 0x00140000, - 0x00142000, 0x00144000, 0x00146000, 0x00148000, 0x0014a000, 0x0014c000, - 0x0014e000, 0x00150000, 0x00152000, 0x00154000, 0x00156000, 0x00158000, - 0x0015a000, 0x0015c000, 0x0015e000, 0x00160000, 0x00162000, 0x00164000, - 0x00166000, 0x00168000, 0x0016a000, 0x0016c000, 0x0016e000, 0x00170000, - 0x00172000, 0x00174000, 0x00176000, 0x00178000, 0x0017a000, 0x0017c000, - 0x0017e000, 0x00180000, 0x00182000, 0x00184000, 0x00186000, 0x00188000, - 0x0018a000, 0x0018c000, 0x0018e000, 0x00190000, 0x00192000, 0x00194000, - 0x00196000, 0x00198000, 0x0019a000, 0x0019c000, 0x0019e000, 0x001a0000, - 0x001a2000, 0x001a4000, 0x001a6000, 0x001a8000, 0x001aa000, 0x001ac000, - 0x001ae000, 0x001b0000, 0x001b2000, 0x001b4000, 0x001b6000, 0x001b8000, - 0x001ba000, 0x001bc000, 0x001be000, 0x001c0000, 0x001c2000, 0x001c4000, - 0x001c6000, 0x001c8000, 0x001ca000, 0x001cc000, 0x001ce000, 0x001d0000, - 0x001d2000, 0x001d4000, 0x001d6000, 0x001d8000, 0x001da000, 0x001dc000, - 0x001de000, 0x001e0000, 0x001e2000, 0x001e4000, 0x001e6000, 0x001e8000, - 0x001ea000, 0x001ec000, 0x001ee000, 0x001f0000, 0x001f2000, 0x001f4000, - 0x001f6000, 0x001f8000, 0x001fa000, 0x001fc000, 0x001fe000, 0x00200000, - 0x00202000, 0x00204000, 0x00206000, 0x00208000, 0x0020a000, 0x0020c000, - 0x0020e000, 0x00210000, 0x00212000, 0x00214000, 0x00216000, 0x00218000, - 0x0021a000, 0x0021c000, 0x0021e000, 0x00220000, 0x00222000, 0x00224000, - 0x00226000, 0x00228000, 0x0022a000, 0x0022c000, 0x0022e000, 0x00230000, - 0x00232000, 0x00234000, 0x00236000, 0x00238000, 0x0023a000, 0x0023c000, - 0x0023e000, 0x00240000, 0x00242000, 0x00244000, 0x00246000, 0x00248000, - 0x0024a000, 0x0024c000, 0x0024e000, 0x00250000, 0x00252000, 0x00254000, - 0x00256000, 0x00258000, 0x0025a000, 0x0025c000, 0x0025e000, 0x00260000, - 0x00262000, 0x00264000, 0x00266000, 0x00268000, 0x0026a000, 0x0026c000, - 0x0026e000, 0x00270000, 0x00272000, 0x00274000, 0x00276000, 0x00278000, - 0x0027a000, 0x0027c000, 0x0027e000, 0x00280000, 0x00282000, 0x00284000, - 0x00286000, 0x00288000, 0x0028a000, 0x0028c000, 0x0028e000, 0x00290000, - 0x00292000, 0x00294000, 0x00296000, 0x00298000, 0x0029a000, 0x0029c000, - 0x0029e000, 0x002a0000, 0x002a2000, 0x002a4000, 0x002a6000, 0x002a8000, - 0x002aa000, 0x002ac000, 0x002ae000, 0x002b0000, 0x002b2000, 0x002b4000, - 0x002b6000, 0x002b8000, 0x002ba000, 0x002bc000, 0x002be000, 0x002c0000, - 0x002c2000, 0x002c4000, 0x002c6000, 0x002c8000, 0x002ca000, 0x002cc000, - 0x002ce000, 0x002d0000, 0x002d2000, 0x002d4000, 0x002d6000, 0x002d8000, - 0x002da000, 0x002dc000, 0x002de000, 0x002e0000, 0x002e2000, 0x002e4000, - 0x002e6000, 0x002e8000, 0x002ea000, 0x002ec000, 0x002ee000, 0x002f0000, - 0x002f2000, 0x002f4000, 0x002f6000, 0x002f8000, 0x002fa000, 0x002fc000, - 0x002fe000, 0x00300000, 0x00302000, 0x00304000, 0x00306000, 0x00308000, - 0x0030a000, 0x0030c000, 0x0030e000, 0x00310000, 0x00312000, 0x00314000, - 0x00316000, 0x00318000, 0x0031a000, 0x0031c000, 0x0031e000, 0x00320000, - 0x00322000, 0x00324000, 0x00326000, 0x00328000, 0x0032a000, 0x0032c000, - 0x0032e000, 0x00330000, 0x00332000, 0x00334000, 0x00336000, 0x00338000, - 0x0033a000, 0x0033c000, 0x0033e000, 0x00340000, 0x00342000, 0x00344000, - 0x00346000, 0x00348000, 0x0034a000, 0x0034c000, 0x0034e000, 0x00350000, - 0x00352000, 0x00354000, 0x00356000, 0x00358000, 0x0035a000, 0x0035c000, - 0x0035e000, 0x00360000, 0x00362000, 0x00364000, 0x00366000, 0x00368000, - 0x0036a000, 0x0036c000, 0x0036e000, 0x00370000, 0x00372000, 0x00374000, - 0x00376000, 0x00378000, 0x0037a000, 0x0037c000, 0x0037e000, 0x00380000, - 0x00382000, 0x00384000, 0x00386000, 0x00388000, 0x0038a000, 0x0038c000, - 0x0038e000, 0x00390000, 0x00392000, 0x00394000, 0x00396000, 0x00398000, - 0x0039a000, 0x0039c000, 0x0039e000, 0x003a0000, 0x003a2000, 0x003a4000, - 0x003a6000, 0x003a8000, 0x003aa000, 0x003ac000, 0x003ae000, 0x003b0000, - 0x003b2000, 0x003b4000, 0x003b6000, 0x003b8000, 0x003ba000, 0x003bc000, - 0x003be000, 0x003c0000, 0x003c2000, 0x003c4000, 0x003c6000, 0x003c8000, - 0x003ca000, 0x003cc000, 0x003ce000, 0x003d0000, 0x003d2000, 0x003d4000, - 0x003d6000, 0x003d8000, 0x003da000, 0x003dc000, 0x003de000, 0x003e0000, - 0x003e2000, 0x003e4000, 0x003e6000, 0x003e8000, 0x003ea000, 0x003ec000, - 0x003ee000, 0x003f0000, 0x003f2000, 0x003f4000, 0x003f6000, 0x003f8000, - 0x003fa000, 0x003fc000, 0x003fe000, 0x003fe001, 0x00000000, 0x000001ff, - 0x00000200, 0x00000001, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00007ff8, - 0x00000000, 0x00003500, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, - 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0x00000003, 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, - 0xffffffff, 0x00000003, 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, - 0x00000000, 0xffffffff, 0x00000003, 0x00bebc20, 0xffffffff, 0x00000000, - 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, 0x00bebc20, 0xffffffff, - 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, 0x00bebc20, - 0x00002000, 0x000040c0, 0x00006180, 0x00008240, 0x0000a300, 0x0000c3c0, - 0x0000e480, 0x00010540, 0x00012600, 0x000146c0, 0x00016780, 0x00018840, - 0x0001a900, 0x0001c9c0, 0x0001ea80, 0x00020b40, 0x00022c00, 0x00024cc0, - 0x00026d80, 0x00028e40, 0x0002af00, 0x0002cfc0, 0x0002f080, 0x00031140, - 0x00033200, 0x000352c0, 0x00037380, 0x00039440, 0x0003b500, 0x0003d5c0, - 0x0003f680, 0x00041740, 0x00043800, 0x000458c0, 0x00047980, 0x00049a40, - 0x00008000, 0x00010380, 0x00018700, 0x00020a80, 0x00028e00, 0x00031180, - 0x00039500, 0x00041880, 0x00049c00, 0x00051f80, 0x0005a300, 0x00062680, - 0x0006aa00, 0x00072d80, 0x0007b100, 0x00083480, 0x0008b800, 0x00093b80, - 0x0009bf00, 0x000a4280, 0x000ac600, 0x000b4980, 0x000bcd00, 0x000c5080, - 0x000cd400, 0x000d5780, 0x000ddb00, 0x00001900, 0x00000028, 0x00100000, - 0x00000000, 0x00000000, 0xffffffff, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x00000000, - 0x00007ff8, 0x00000000, 0x00001500, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x00000000, 0x00007ff8, 0x00000000, 0x00001500, 0x00001000, - 0x00002080, 0x00003100, 0x00004180, 0x00005200, 0x00006280, 0x00007300, - 0x00008380, 0x00009400, 0x0000a480, 0x0000b500, 0x0000c580, 0x0000d600, - 0x0000e680, 0x0000f700, 0x00010780, 0x00011800, 0x00012880, 0x00013900, - 0x00014980, 0x00015a00, 0x00016a80, 0x00017b00, 0x00018b80, 0x00019c00, - 0x0001ac80, 0x0001bd00, 0x0001cd80, 0x0001de00, 0x0001ee80, 0x0001ff00, - 0x10000000, 0x000028ad, 0x00000000, 0x00010001, 0x00350804, 0xccccccc5, - 0xffffffff, 0xffffffff, 0x7058103c, 0x00000000, 0xcccc0201, 0xcccccccc, - 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, - 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, - 0xcccc0201, 0xcccccccc, 0x00000000, 0xffffffff, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x00000000, 0x00007ff8, 0x00000000, 0x00003500, 0x000e0232, 0x011600d6, - 0x00100000, 0x00000000, 0x00720236, 0x012300f3, 0x00100000, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0xfffffff3, 0x320fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x30efffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, - 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, - 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, - 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x31efffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x302fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, - 0xfffffff3, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, - 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, - 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, - 0xfffffff7, 0x30efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x304fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x31efffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, - 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, - 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, - 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x056fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, - 0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x320fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, - 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, - 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, - 0xffffff8a, 0x042fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, - 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x05cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x310fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, - 0xfffffff3, 0x316fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x302fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, - 0xfffffff6, 0x30bfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf314, 0xf3cf3cf3, - 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, - 0xfffffff7, 0x31cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0020cf3c, 0xcdcdcdcd, 0xfffffff0, 0x307fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0x00100000, 0x00070100, - 0x00028170, 0x000b8198, 0x00020250, 0x00010270, 0x000f0280, 0x00010370, - 0x00080000, 0x00080080, 0x00028100, 0x000b8128, 0x000201e0, 0x00010200, - 0x00070210, 0x00020280, 0x000f0000, 0x000800f0, 0x00028170, 0x000b8198, - 0x00020250, 0x00010270, 0x000b8280, 0x00080338, 0x00100000, 0x00080100, - 0x00028180, 0x000b81a8, 0x00020260, 0x00018280, 0x000e8298, 0x00080380, - 0x000b0000, 0x000100b0, 0x000280c0, 0x000580e8, 0x00020140, 0x00010160, - 0x000e0170, 0x00038250, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, - 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000, - 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x04002000 -}; - -static const u32 tsem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x19d9458a, 0x1138fc18, - 0x5980a1fc, 0xd8181998, 0x88039880, 0x81b8803d, 0x91a18191, 0xdafd7891, - 0xbf760862, 0x6ec30330, 0x0211e620, 0x1082239a, 0xf354029f, 0x0f5fc806, - 0x6512b315, 0x3a263860, 0x06a77ef0, 0x298d2ade, 0xc1124536, 0x1e4586de, - 0x93476f19, 0xca8922ff, 0xff4041df, 0x65296340, 0x229dbe54, 0x04a65e84, - 0xe4d1a5a1, 0xd7f2a1ed, 0x5192fea1, 0x0dee6ec6, 0xf8003ca8, 0x6065495c, - 0x00606549 -}; - -static const u32 tsem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7dedff00, 0xd554780b, 0x733ef0b5, 0x49999cce, - 0x424e4cce, 0x4c22f212, 0x21a08812, 0x8a80af0c, 0x2201277f, 0x282039f5, - 0x4201d458, 0xd4837908, 0xcdedaf4b, 0x11102484, 0x0547f435, 0x5088768b, - 0x340da2d1, 0x0ec160d2, 0x6d7b1420, 0xc0faf06f, 0x480bf5ea, 0xb12f3141, - 0xcbc57e20, 0xe7dad6bf, 0x264ce664, 0xafdbd880, 0xb4fdffff, 0xece7d9b8, - 0xebdaf7b3, 0x7b5ad7b5, 0x75923ded, 0xc7bf9302, 0x03fc45d8, 0x8c4d4fe5, - 0xf2c109b1, 0x80f66667, 0xc9b18727, 0x473afebd, 0x6d55633c, 0x9da23b19, - 0x99ec258c, 0x50281421, 0x2c23d5fe, 0xbfdf8250, 0xf097c365, 0x4219b6ff, - 0xd0977c3e, 0xc3e611e9, 0x02d5e4fb, 0x933a876b, 0xea0c319c, 0x4b19b98c, - 0x126b2c64, 0x4b223fa3, 0xe0ff828d, 0x8f392573, 0x27fc34b1, 0x61467574, - 0xc678c0ae, 0x5c531e32, 0x38a9d0d4, 0x843f7815, 0xbcd2c67f, 0x0731b725, - 0xbc03cf63, 0xbcf071c9, 0x61de3a5a, 0xc22eefe5, 0x3af3a1df, 0xae58cd6a, - 0x32773e30, 0x416589a7, 0xf3e33ebf, 0x3d6346ac, 0x4fe3d99b, 0xec3fc346, - 0x8c517ecc, 0xb1138f30, 0xcb3c018c, 0x632f0e54, 0x5467b2bd, 0x6a9b1f10, - 0x2c32a258, 0x852f0f58, 0x56338765, 0xed975e03, 0xf8165c16, 0x2f6c39fe, - 0xbed7e631, 0x15ead66b, 0xa362593e, 0xb50404a1, 0x67eff4e4, 0x11bfcb11, - 0x2b30fef1, 0xea4ab2a0, 0xaf805595, 0xfb765aaa, 0x67edfe95, 0x54e88933, - 0x5bf6b929, 0x5adefc61, 0xf1866ae6, 0x02d59997, 0x91fb2fac, 0x7a83e5d3, - 0x21476366, 0x36d0fa83, 0xc1198981, 0x9e00afef, 0x007f91db, 0xa52b2a1e, - 0x740642de, 0xb02bddec, 0x871c0ce6, 0x776cbbf7, 0x0c65f306, 0x6658e70c, - 0x32e73826, 0x74893a41, 0xd2073071, 0xf324bcc1, 0xcea84289, 0xb0f3dc54, - 0x9de29f7f, 0xe7f4ed87, 0x38e60b49, 0xf25700bd, 0x57a06650, 0x9d3ab5b1, - 0xea563265, 0xbe442969, 0x8decb538, 0x9e025855, 0xf7c02413, 0x08a78b7c, - 0x5798a9fb, 0xa780cd9d, 0x8d1859e6, 0xff2db43f, 0x0cf80933, 0xc4c5f3ba, - 0x76313f21, 0xf04f843c, 0x5a11f1cf, 0xde981c5d, 0xb08b2b97, 0x05f1091f, - 0x1f011772, 0x26a0423f, 0x544d28e0, 0x29fc573a, 0xd0a0d86b, 0xc3595bfa, - 0xe50069c6, 0x3f0cbc11, 0x0843ac61, 0x1cbd4be5, 0xb0ff3bba, 0x3c303b94, - 0x04f3d3ff, 0xab7e1274, 0x1fc8b700, 0xbfd97615, 0xca61f812, 0xf7c0e6ab, - 0x362a3f80, 0xd40b7e0b, 0xe8dbaf4d, 0x5e26f77d, 0x3765d80f, 0x16d74ff2, - 0xbdf00ba8, 0x1bf1fda5, 0x155ebf91, 0x3b763359, 0xfa84ca22, 0x3b06a4e5, - 0xc0750f1b, 0x578db147, 0xbbef362b, 0x692fbf1f, 0xf41b30b3, 0xf17bb157, - 0x7d42371d, 0xc33361f1, 0x6b5b1526, 0x2fa814e5, 0x582d0bf1, 0xf0e029ef, - 0xfe8976f9, 0xc7bed0ad, 0x1b389ed1, 0xc6ba73e8, 0x63329cca, 0xc4f6f675, - 0xa567c059, 0xf8851dfe, 0xc176e95d, 0xf29f6885, 0xc943d6ea, 0xb917af38, - 0x8b6d977c, 0x7f1d4e66, 0xab64f7f0, 0xbc1ef818, 0x64f3065f, 0xd662efd0, - 0xb07a8854, 0xd93aeb62, 0xebe20f69, 0xe34a8d74, 0x8bdfc9f4, 0x577c0e30, - 0xc2e08af9, 0x989a5629, 0x7bb0e517, 0xf3ce6db7, 0x56afce0a, 0xbce3b6ce, - 0x6ed8cb56, 0x2efe7fb1, 0xfea5cd54, 0xbc2172cd, 0x59b4dd2f, 0xdb910e2e, - 0x8c836db2, 0x1ac86d70, 0xd7208dec, 0xd7807841, 0x52f583b2, 0x0fa803d4, - 0x233cbf25, 0x852acf84, 0xb2cbe258, 0x1a73226d, 0xddd388f8, 0x13fc2ef7, - 0x6bdbe5f0, 0x74eabc27, 0x1aa7d3eb, 0x1aa8cedd, 0xbcdea51d, 0xf8f81119, - 0xc003a471, 0x827884d3, 0x9f06ad72, 0x97cb3263, 0x9b877fa0, 0x3cbb02a9, - 0xd999365f, 0xf563067c, 0xd2dd07b0, 0xd99750f5, 0xf582e652, 0x7bb1fa50, - 0x0493d42a, 0x9f3867ef, 0xc25bc17a, 0x2496abd7, 0x9579e00f, 0xfce0e6c0, - 0x30d0218f, 0xc0c955af, 0xa6f7809f, 0x8bcf7969, 0x3c7b0682, 0xb17f8bd6, - 0x39fa8326, 0xa198fd43, 0xf7cbac9f, 0x324e16a3, 0x9616a3f4, 0x8dfcfde8, - 0x595db1fa, 0x37854d3f, 0x2c29e118, 0x0491fbd5, 0xbf6f5768, 0x37a979b2, - 0x73c2364f, 0x13f53973, 0xbcc5d53b, 0x1ae7ae0a, 0xb776b03f, 0xed95ef08, - 0xb0d763b1, 0x5028be50, 0x0edb8005, 0x17ca1252, 0x0ca29331, 0x8eeb187c, - 0x27a1d433, 0x4175e4f5, 0x958813fd, 0x45397c69, 0x9f90bd26, 0x43faa562, - 0x85e90a29, 0x5ef06e87, 0x8e20eb83, 0x2ea192cd, 0x11ab477b, 0x14e01af8, - 0x60961258, 0x7ff52417, 0xf1ccdabf, 0x217a9050, 0x5f7c18fb, 0x8ecdea65, - 0xa635fa85, 0x6f116bfc, 0xe5eb812e, 0x63559128, 0x230b28bb, 0x233ab4fd, - 0x085f79ef, 0x00871a9e, 0xbf6085fd, 0x126f668d, 0xdaf8d7f2, 0xc0127c67, - 0xcc086ab7, 0x12ba0527, 0x60f8099e, 0xa43d5a3d, 0x69f10938, 0x43be4191, - 0xfc6197c7, 0x06ff1a1c, 0xc71ba3c4, 0xbe3fe84f, 0x61927325, 0x897a6b7c, - 0x0cab7c61, 0x4fbf03e3, 0xc6d66dad, 0xc0ddfc07, 0x99a134d8, 0x97a4b7c6, - 0x65abf8d0, 0x3f186256, 0x5bfc6faa, 0x819efe70, 0x83799fe6, 0xa5e9fe71, - 0x7ccbf9c6, 0x5f6ab3fe, 0xa28fc6d2, 0x5e16cff9, 0x2f4ff3e2, 0xf0b7f3e5, - 0x77c6fb7e, 0x5effe1f4, 0x8077bf9c, 0x93592df1, 0x5a1ff38d, 0x85bf9c6e, - 0xbb545f8f, 0xa15f1b53, 0x3b0917f1, 0x9687fcf9, 0xc5b2f8d3, 0x923e42eb, - 0xfdaaa353, 0x81a44f68, 0x1d260c40, 0x0472a6e5, 0x1fa00518, 0x04990a86, - 0x9c5143c7, 0x0145ceef, 0x7d4129bf, 0x5120fcc7, 0x352acfa0, 0x9edb2f9e, - 0xa59ea32f, 0x376889f7, 0x6d453ff1, 0x6c37ad22, 0x1c3fc5bd, 0x136eede0, - 0x5a2f587d, 0xa45f937f, 0xe5db8ef5, 0xf005c660, 0x1c9e5ff9, 0xaf3a1cd5, - 0x935172f0, 0x418764f9, 0xbe3c388e, 0x1aa23602, 0x26476be0, 0x9fac1098, - 0xc60a3d04, 0x7a0e3b2f, 0x6653cb14, 0x009c8f6e, 0x50e4cb3d, 0xf6e5a9b9, - 0x93bd8f88, 0x5bbaf303, 0xc4a4ff83, 0xb9727df1, 0x9ffc47e0, 0x4654b75b, - 0x09a8b4fd, 0x7910e98c, 0xd4e8d2af, 0x6fe2dbbb, 0x4e9f0816, 0x243dcfc4, - 0x97fd8c8a, 0xde2fd766, 0xddf0c830, 0x486fe63c, 0xd70bf682, 0xc2a21fce, - 0xc7307ffc, 0x53ed1632, 0x13548490, 0x354b31c9, 0xa7316f81, 0x15399d75, - 0x31ccf72a, 0xb9faec1b, 0x07fd635e, 0xb77ac625, 0xa1366fd9, 0x6044b1bd, - 0xfbdfa19b, 0xf5ef8daa, 0x71093671, 0x78daae9c, 0x78722777, 0x2c72c3ef, - 0xae89563e, 0x5bfcabf7, 0x87aa9e1d, 0xeb402ccd, 0x43024765, 0xc812fa3a, - 0x7caaf35e, 0xdef0e1de, 0x3dbab66f, 0x3ffdcf00, 0xe19f0912, 0x1ebc77f0, - 0x1d8136ed, 0x4be1b1d7, 0xe1b7da33, 0xff8709f3, 0xf3e11581, 0xf7d46551, - 0xcfe17df3, 0xf3849f39, 0xfe5b5553, 0xed2113a0, 0x3fbe5a2a, 0x7f0844e8, - 0x619b6d95, 0xcff12fa8, 0xbc5fb435, 0xfde1be61, 0x8625a6a2, 0x971b0bf7, - 0x7df3ea1a, 0x7fb4323f, 0xe1ad4560, 0x8fd57dfd, 0xa0ffde18, 0x3ea19d64, - 0xd0d1bbd7, 0x9b399efe, 0xaf4def0d, 0xe513bc8f, 0x915deea8, 0x5671bae1, - 0xda38f939, 0xc9156783, 0xb4f8f485, 0xe0e48926, 0xca938d74, 0x5671b6ee, - 0xc583d72f, 0x5e9c4c0c, 0x71af9ce1, 0x4665ea32, 0xc2aff3fa, 0xea0f9f05, - 0x849c137f, 0xcc83713f, 0x02c2c002, 0xe3e3eb8b, 0x7de4315e, 0x6fde65c7, - 0xd71f4100, 0x11d8bdff, 0xf35579f9, 0x046aa1fc, 0xb72821ff, 0xb9d7152c, - 0x0f7d6d1e, 0x302e5f7f, 0xc673e84f, 0xd79c9256, 0xb94ceb69, 0xf941f5cc, - 0xf402e4ce, 0x40e5cbbf, 0xc6a5f576, 0xa2a4016b, 0x3ceb449e, 0xa401f901, - 0x592fc0c0, 0xdceef906, 0x955c1227, 0xaf4013a8, 0xc19e63ae, 0x8133d426, - 0x8d77e903, 0x49dc3842, 0xa04b6f54, 0x66b3bd75, 0x1213a0fa, 0xe543c7d2, - 0xa87335a7, 0xa5e3593c, 0x094d44f2, 0xaa6bc795, 0x59a8eca9, 0x35c7e541, - 0xaa3f2a3e, 0xcff2a469, 0x1e544d35, 0xe540d9ad, 0x2a7e357b, 0x54dc6bbb, - 0xba2bf9f6, 0xecd78dfe, 0x80afcd55, 0x67ea8795, 0x43d4b9b4, 0x739276db, - 0xf9ca1257, 0x365ce519, 0x8e67e3da, 0x31996382, 0xf9c2be30, 0xba3a606d, - 0xf6295ec9, 0xf5c7fd03, 0xe28b6f7f, 0xd899b274, 0xd9a67074, 0xe17fc323, - 0x7543905a, 0x16065909, 0x7b0cd724, 0xed617e84, 0x8e5d7a43, 0x9bddcc4e, - 0x71e8133b, 0xe5bf99f2, 0xda75bf61, 0x407517fa, 0x059875a4, 0xbd21779e, - 0xeb46f042, 0x9aabef5a, 0xfe0cbfbe, 0xd7f0faba, 0xfbfe8e9e, 0xfea54141, - 0x985ab4cf, 0x13dc7884, 0x67e607ed, 0xef3f0e67, 0x965c7940, 0x444f5264, - 0x565e83c0, 0x4aa864b4, 0x66d3fae8, 0x12699fac, 0x7ad0b7a6, 0x35998cec, - 0x554af90a, 0xfa430c4f, 0xf7a95127, 0x56492cb3, 0x9ebc804f, 0xc31596de, - 0x5f3f6fd7, 0x12c7b707, 0x485f82bf, 0xf0deffed, 0x0e8fd40c, 0xecad630f, - 0x03ea2b13, 0xedf59778, 0xfd2672fd, 0x6c57e295, 0xda1cf98f, 0x7bf8160b, - 0x1207e291, 0xab7ef5d5, 0x659f445a, 0x6edf3e34, 0x73be0f18, 0xc5f73eea, - 0xadf14bcc, 0xc4864ec4, 0xf169d611, 0x366db2c6, 0xc4aeb8d5, 0x6d55ea1a, - 0x9d61aac9, 0xfc807fc1, 0x42416ab3, 0xb8d729be, 0x1a5247a8, 0xdcaf8005, - 0xab7ea4e4, 0xc2aede04, 0xe17b21da, 0xa72b5751, 0x9df040db, 0x94ec39ae, - 0xac4bde40, 0x7c0201e0, 0xa7232d25, 0x6aeb9ea2, 0x7b444bad, 0xf33c4cb0, - 0xf7c22790, 0x8d024d3b, 0xee6fc4b7, 0x1aa3ae35, 0x57e8307f, 0x167e4e7f, - 0xd4864e53, 0xcedc4d3b, 0x80f7ef0e, 0xf0e5efd6, 0x48fdb953, 0xfece8de1, - 0xfb6caa78, 0x1c92f642, 0x82f2ffc1, 0x57f1d278, 0x401cf26e, 0xedba5a7d, - 0x9fa3d918, 0x0fd97d9a, 0xf53f425f, 0x44929f9f, 0x5e7d5271, 0x6129303e, - 0x7c5a059c, 0x9ef7f817, 0xfd3d610f, 0x6ccddfec, 0x2ec7c00d, 0x6f782b40, - 0x13335fd6, 0xa17d4133, 0x5ad05b56, 0xcfdd7146, 0x2a8edc4c, 0xd1071e62, - 0xa1e53581, 0x4cc5d91d, 0x5d4f11d3, 0xb8c76dec, 0x329c3a10, 0x1667a4c9, - 0x18ed1a36, 0xf50d7fb0, 0xf58c1bc5, 0x11333662, 0x7af149f5, 0x340bf333, - 0xf7fbc33f, 0x7fe12a4d, 0x855eab31, 0xf9a4aaeb, 0x26540b23, 0x157c02a5, - 0x6f3679bf, 0x4c5fc63e, 0xe3d10fdc, 0x38e24b23, 0x7ef1a5fc, 0x3fef0dd9, - 0xf7771d69, 0x8b06488d, 0x89c6157f, 0x6d730c58, 0xfbf1fd65, 0x870fe16d, - 0xfbaf5f57, 0x383469c5, 0xdb826dc4, 0x2f7f811f, 0xeba67c68, 0xd5445beb, - 0x8ddc17e0, 0x21bf10f5, 0xb2e2d446, 0xee911322, 0x67d5aa5d, 0x14f7a18a, - 0xb4edf7b7, 0xde80eab8, 0x0679373f, 0x4ec81389, 0xed2165c8, 0xd2f26e7e, - 0xade14ef3, 0x995bb462, 0x3b45c814, 0xe218d614, 0x07e35953, 0x8b91ca31, - 0x833b66f1, 0x6fe81475, 0x9fa0f841, 0xdb92f655, 0xbbc62e58, 0xbfa1de41, - 0x87851cc7, 0x94dba805, 0x59fd8656, 0x7cf18c92, 0xaf58d39b, 0x1d207fc2, - 0x3f8a3046, 0xc2908f45, 0xa86018f0, 0xe32eed0f, 0x84e851f3, 0x201fdd91, - 0x8b10763e, 0x02556943, 0x26cf8c22, 0xfe7d9d49, 0x7bfa2656, 0x2f8a7e1c, - 0x2ae5fb40, 0xc5a95f6f, 0x507f97cf, 0x12ee3830, 0x3ceaa8fa, 0x21419068, - 0x7fbe3d75, 0x71fe625e, 0x3a6f41df, 0xd10d5561, 0xde4d739b, 0xd40f4869, - 0x009f0893, 0x760d78e3, 0x2a1a9a60, 0xf8c20be7, 0x88e1aae3, 0x5dfd0667, - 0x2ddef26e, 0xe387f426, 0xea4ffbaa, 0x4882ffd7, 0xfeeabcf3, 0xbfebf587, - 0x15ff5232, 0x977979bf, 0xf4a9f80f, 0x803a4f57, 0x5267d999, 0xe80ba253, - 0xc1b5be5e, 0xa9f97281, 0x5d2073e4, 0xd38bf33f, 0x16e7c923, 0xb74f9751, - 0xff11e422, 0x7e9d1f10, 0xd03bd1e9, 0xd5b73aae, 0x607c52ac, 0x0160259b, - 0x5d6caca6, 0x9b63e5c2, 0xafaf18e5, 0xb3f902fe, 0x2fa8cdaa, 0x32785f4a, - 0x40cde311, 0x0e7fcd49, 0xb9507f90, 0x68852fe5, 0x5eb15577, 0xdfe17bd2, - 0xe3e7f8e1, 0x2f981ec8, 0xaf7ff4c7, 0x6955f3ef, 0x7d6aa978, 0x84910bf4, - 0xcdfc83a5, 0x9a25f6f0, 0x68a4ffbd, 0xdf38a78f, 0xf9113644, 0xf307c74c, - 0xeebf7b73, 0x8f73a7c5, 0x5b9d3c01, 0xe421ddfe, 0xd727f284, 0x165a677b, - 0xe735fcfe, 0x0dd4f2c0, 0xaed4317a, 0x6767d7d6, 0xeca7e69b, 0x39b965e1, - 0xb03f40e0, 0xe5d9b37c, 0xfcbeba43, 0xc19e2ffc, 0x1607ccb8, 0xbfe870d7, - 0xef83e5ec, 0xb2f500dd, 0xdbf8e61d, 0x211434f8, 0x2a974831, 0x6c62bbf8, - 0xbfa50e90, 0x473b283e, 0x8e3fe7f1, 0x6ca3d20b, 0x8d993ec7, 0x298f8fea, - 0x0ee4fb2d, 0x5a5d0225, 0x3fa2158e, 0x57e2f751, 0xcfafea32, 0xe0d8175e, - 0xdcf8088c, 0x62ec907c, 0x51d113c4, 0xdd1f53a3, 0x0157dac2, 0xeabf505d, - 0xff7f0a74, 0xc7fe9a2f, 0xc4399cfe, 0x86bcafcf, 0xb67f28fb, 0x25fe70b8, - 0xc0e83caf, 0xaa929c79, 0xdb3f5f39, 0x7186e890, 0x44becc4b, 0xbcfe4a95, - 0x121fb9e4, 0xf23e2dbf, 0x7f8a44c3, 0x89b27730, 0x325f056c, 0xa6d16fce, - 0x62bf34d9, 0x2bbe25e6, 0xe0f45679, 0x8959e0fe, 0x4111df4d, 0xae24522e, - 0x5b354f8f, 0xa7654d70, 0x7dc0e170, 0xff45b785, 0x2dff8a56, 0x0fcaf8a5, - 0xb620fdf5, 0xad67ea8c, 0x885f4e9c, 0xac1abefa, 0xbafca13c, 0xd23b7565, - 0xf710f4e7, 0x571b8c60, 0xe1a7c931, 0xfd08b843, 0x0da6478a, 0x4e61f4e6, - 0x0efb4f29, 0x7c14fdf4, 0xcddbed8e, 0xe1ae5b6e, 0x2331763b, 0x6d72fe38, - 0x0a3b807c, 0x8953d5ed, 0x9845ff60, 0xafa4a15f, 0x85576037, 0x7c8857f0, - 0xf2df7973, 0x5d6f9708, 0xa633fdde, 0xbebffbe3, 0xbf07e5c3, 0xe0057b43, - 0xf7a60c0a, 0xa40966fb, 0x102c2c0f, 0x98b7ae49, 0xbe36b935, 0xe004f9d7, - 0xeddd7096, 0x3fec17e3, 0x764ff08e, 0xf87af16c, 0x565f442e, 0xfe8e78e1, - 0xbb72e9fd, 0x04ff9358, 0x6cff28c9, 0x81fb9713, 0x8f1f09fd, 0xbffd984b, - 0x15e50678, 0xaff713e4, 0x7b365fcb, 0x6f9fde70, 0xbddef03f, 0xb79fa720, - 0xd46a72e8, 0x5a72e19f, 0x8b0273b2, 0x639fa724, 0x3924421a, 0xe511e785, - 0x3e20e954, 0x4fe947fe, 0x85377f1d, 0x87d74fe1, 0x5c31e103, 0x7459fe1f, - 0xf087d446, 0xd7961de7, 0xbe74ff9f, 0xf4adf9d3, 0x29431597, 0xa5f3a63e, - 0x7c7d77ce, 0xbf5df3a9, 0x7f01a378, 0x182defe1, 0x3cb80183, 0x4714cdbb, - 0xf7c3df28, 0x43bbe17f, 0x4f09e3a9, 0x58c65a6e, 0xf8d4a1d3, 0xac3fbad0, - 0xded612de, 0x84f7561d, 0xd586f7b5, 0xcbed0dab, 0x3cc80edb, 0x686025af, - 0x8678ae27, 0x1228327d, 0x5fb9fabf, 0xec85fada, 0x7a50be43, 0x4af37be9, - 0x3c63b3e6, 0xf148af7c, 0xf1c01e91, 0x67a7182a, 0xf31f867b, 0x3c6c1a24, - 0xf6a3d4ee, 0x6c5ed03a, 0xdef5e588, 0xea157904, 0xaf79fd3d, 0x7af5c78d, - 0xd88ebd3c, 0xd8edfb10, 0x76f4911e, 0x8f4d9f87, 0x8ac267e4, 0xc1d47242, - 0xe3cf7a06, 0x2544d3fd, 0x5fc6057d, 0x8617449a, 0xef6a8a74, 0x419e6071, - 0x3bac9ecf, 0x45f3c0e7, 0x8db48a6f, 0x7b7683d8, 0x2dc7920c, 0x77f88725, - 0x53df329f, 0xbf7e3193, 0x4579fb87, 0x11ecc36b, 0xa9f896b6, 0xa32e5958, - 0xecbf053e, 0x82ff71b8, 0xd6a945cb, 0xe326c95f, 0xdc7bfd7b, 0xbdfb45c1, - 0xbdf18b74, 0x34078b57, 0x863272eb, 0x71fcd18d, 0xf4d28f1e, 0xe73134f2, - 0x8f4039ce, 0xc322c39e, 0x7b33fbfd, 0x99c7a244, 0x9ebf7ced, 0x23d7f6e2, - 0x3e92f77f, 0x89d4f1d4, 0xac0f24f2, 0xfd5f3aaf, 0x9187bcaf, 0x987d766f, - 0x3b2833fb, 0xfd907d77, 0xe6ffac5b, 0x590ff4fd, 0x5e53f6ff, 0x493ed1b7, - 0xe276ebcf, 0x7fbd9ef7, 0xeb187f4c, 0x9f142dbb, 0xabfd79ee, 0x9e9fe45c, - 0xd4129695, 0x80433d77, 0xec1f68fe, 0x83b72afd, 0xa27ad7d6, 0x99251fdb, - 0xfe7b47db, 0x8f10b1f6, 0xed0acc25, 0x49a3d786, 0xb35eaa9e, 0x67ad3c51, - 0xa17957ef, 0x9d77ff76, 0x7fb6a54f, 0x736763d9, 0xb17c2276, 0xeaa7df7c, - 0x5f3fd7b7, 0xad17f98b, 0xf085e4fb, 0xbeefca7e, 0xda3d45c9, 0x43db93b3, - 0xe78ee6dd, 0x68ee7f70, 0x6695dcfd, 0x0a3773c0, 0x9bac0a55, 0xa014cf0d, - 0xcbc7f4dc, 0xbc271437, 0xfcf47c52, 0xc10f835f, 0xdd9df5cd, 0xde70156f, - 0x21fc7f5f, 0x2dd785ea, 0x7cfa97c4, 0x25a96f3f, 0xf372e57b, 0x9c799876, - 0x799dffe4, 0x992b810b, 0x3ff328f7, 0x2d7fbd37, 0xe12e8939, 0xcf9fd072, - 0xf5443ef7, 0x822eed97, 0xfdf90af7, 0xf9f27ff6, 0xefba6b7f, 0x2e3bba04, - 0x7ff2ef3f, 0x4c0f79f2, 0xd7ef37f7, 0x7e62aee8, 0xbeefd54b, 0xadbef821, - 0x4ffb5b9e, 0xcd03ef2e, 0xd7ebb75f, 0x994d5c98, 0xaf439f18, 0xc569d601, - 0xc311b33e, 0xcc466b85, 0x14ced154, 0xf52bf6c3, 0xfb99af72, 0x5bee224d, - 0x086f9c62, 0xcd31f38f, 0x3d2da28f, 0x8a525a18, 0x94958ec9, 0x96bedc55, - 0xc06eed5c, 0x176b9acb, 0x887728b8, 0xc5ea3d8d, 0x1764da7a, 0xfcc3afc5, - 0xb9817ac9, 0xa56fb005, 0x8c396f6b, 0x84798dfe, 0xa5c96029, 0xab9618f2, - 0x59a4b8b5, 0x8f7e0d95, 0xdbac6392, 0x45bac69c, 0x38cacfeb, 0xe624d6fc, - 0x38b4f8c7, 0x798abf72, 0x8918e26d, 0xb1b75009, 0x17fa1f26, 0xf7e32496, - 0x1ec0311b, 0x5abdcf12, 0xe1f6f63c, 0x1bbb6c71, 0x44d238f1, 0x2e4a6b71, - 0xfcb8bc25, 0x8d9e786b, 0x55d788d5, 0x094f88ed, 0x7f6e5ffd, 0x34ccdf91, - 0xbad2597f, 0xdc984690, 0xcd3b6336, 0x9d2cbe4f, 0xcbd25d38, 0x332d3a35, - 0x43a745d0, 0xe818fa04, 0xdbf9e3a2, 0x2e9c27d2, 0x6fdff8e1, 0x07fe1276, - 0x974e97a2, 0x50cdc534, 0xbf9acd5e, 0x49fd1530, 0x1879a7ac, 0xfe6b33ed, - 0x66ef1482, 0xea93a43e, 0xf42f4862, 0xb7e002db, 0xf3fb7efd, 0x7aea2714, - 0x081dd8e9, 0x456fd94f, 0x75fc0566, 0x00b3b76f, 0x65f92f7e, 0x5b4b43f4, - 0x33fb8a45, 0x57779029, 0x6eafbec8, 0xcafd97f7, 0xdd29f34e, 0x06dff169, - 0xfaee97df, 0xb0ec9724, 0xd7e4bd95, 0x38125ef8, 0xb91d7ddd, 0x2a5bafb8, - 0x9c23ff71, 0x9e65625f, 0x3bb9d027, 0x6dc60e7a, 0xdf3c6d84, 0x1ee5b4b6, - 0x7f90c5b3, 0x91dbd666, 0x28bdf05e, 0xc213be50, 0xa9e79a17, 0x2f9d1dfb, - 0x36be1c0a, 0x76f31fb3, 0xe8edb74b, 0xe953f8c6, 0xc30b8b51, 0xbedb55d2, - 0x298dfda0, 0xd1d97abf, 0x68b6fe41, 0xf3f43f88, 0xc489b7fb, 0x15ad951f, - 0x9d4087e4, 0x25b2a2f8, 0x72ebfc72, 0xafd969fe, 0x01f2eef6, 0xfd7ecb0a, - 0x5be30382, 0x3ab7dba7, 0x76dfffc8, 0x3f5bb8e9, 0x91e5bf3f, 0xa7f9fa4b, - 0xbfe01ff1, 0xc58720dc, 0x220db649, 0xcbe0047f, 0xadef948b, 0xcbd95bf3, - 0x38c39f67, 0xcfcee774, 0xcb78439f, 0xe7cbfbff, 0xaf609fd0, 0x88add4db, - 0xa5de9797, 0xddfe9e38, 0x9dc7992c, 0x817c5fbb, 0x1fdd9fe2, 0x7f01df80, - 0x4a9ef7ba, 0x7bb27f47, 0x1889d7c7, 0x77be592f, 0xef9c60da, 0x0ca757f2, - 0x88f41166, 0xfadf225e, 0x1afe20af, 0xad03af4e, 0xe9efc807, 0xdfa37a02, - 0x69b717d9, 0x3071e0a9, 0xd9af16a7, 0xddce391e, 0x7ad33e2f, 0x8d379dd7, - 0x72ecd2c7, 0xd3882bb2, 0x1c7403bc, 0xdbf4057d, 0x7fe688fe, 0x175fa646, - 0xb4e803fe, 0x677e8c2c, 0xfcfd175b, 0x3ad77c19, 0x4d38c068, 0xa6f00ae0, - 0x27bfd1c7, 0xa3227fbb, 0x25fced7c, 0x6e90c5c5, 0xbb44c1b7, 0x8e9b3e5f, - 0x9a9f0ffb, 0xe7e7ef7b, 0xc62a2c32, 0xbef74a1b, 0xfdd3f24f, 0x538a11ea, - 0xdd9e2d33, 0xf0fefacd, 0x5396a3f8, 0xcec5b559, 0xfe1a3be3, 0x74e3fe31, - 0xce2d73d0, 0x8f58f9c3, 0xf7140cff, 0xde799569, 0xafdf1e88, 0x16a1f2d8, - 0x4bd2094f, 0x3a748498, 0x08fdc976, 0xe22a0f1d, 0x1c686261, 0xad7c7233, - 0xd1adde2f, 0xf187e90b, 0x2538becb, 0x6e30d3d4, 0x67de17e5, 0xf741f411, - 0xecff1e66, 0xa3ce4736, 0xbf9ae3d2, 0xff53970a, 0x2f33c595, 0xc5b7ff07, - 0x52765f8f, 0xea78e1bf, 0x8f5910bc, 0x75f32dbf, 0xc5f7aaff, 0xbe4305ca, - 0x7bc9b941, 0xa2b1f904, 0xcfcc98f5, 0x52f3f0a5, 0xb53b7cfa, 0x97ced1bc, - 0xad778a44, 0x7a40396a, 0xe85f5c3c, 0xf0e1a6fb, 0xade0d09e, 0x44ebe36c, - 0x5fbb4ee7, 0xf73a7e81, 0xae7e26ef, 0xe28c7edc, 0xfdb6876d, 0x5908ee5a, - 0xf09d7157, 0xf9dfc087, 0x1e5cbeca, 0xec79e5b7, 0xd19ce3e1, 0x9ed561f4, - 0x6d54e3c8, 0x4e30c2ff, 0xe645af99, 0xc7a5fdeb, 0xefb92d3b, 0xb74efec1, - 0x79e6199b, 0xa7116e9e, 0xf5173a47, 0xea6eb6ae, 0xbd707ee7, 0x23fd7ca4, - 0xf8cc5cfc, 0x1f28a3b7, 0xe991f97e, 0x63c4c61f, 0xfe878409, 0x9f396b5a, - 0x9dc4feb6, 0x3d6ef48a, 0xeb88af72, 0x6fc42ed4, 0xf79f9d88, 0x3b14f54e, - 0x8fbc85e8, 0x5d91e33c, 0xc4cdf5c3, 0xfc0326a3, 0x5c60ce30, 0x1fa1ea07, - 0xf982a73c, 0xe88f086e, 0xf08e9c28, 0xb549aa88, 0x61e7fd09, 0x5e743c56, - 0xacd7ef40, 0xb003cf1a, 0xd89ce30b, 0x1e4cd24f, 0x8bbe4c47, 0x3cfd3e97, - 0xbf94714e, 0xa059e60e, 0xf02cd378, 0x7d7d927d, 0xe78641c6, 0xde5126bf, - 0x78c59676, 0x554bac6e, 0xdfd0267c, 0x596ce4cf, 0xf949d937, 0x4258d707, - 0x20580ff3, 0x6f51f917, 0x587defd7, 0x7e1a427e, 0x1a88fd02, 0x7e5a597c, - 0x21d610c2, 0xc9bd7da0, 0x0e27cfce, 0xf84de255, 0xbd9af3fd, 0xec3f9fa9, - 0xec315e77, 0xcee5e29c, 0xc94fc627, 0x05d43a5f, 0xcf7ab4fc, 0x8f5fcc14, - 0x477f27bf, 0x12798aaa, 0xe7829e7f, 0xc85fe257, 0xf50c931f, 0x9c1fab13, - 0xc8fff54a, 0xf50e931f, 0x8dff1a6f, 0xca04cbd7, 0x3d582d57, 0xebf22a7a, - 0x2cf9cb55, 0xce5188c0, 0x75bc40ef, 0x7bba3e79, 0x1ff31391, 0x5f8e657a, - 0x4376c1e6, 0xa5bc7126, 0x40ed1f29, 0x75350d3c, 0xfe7f22d4, 0xb157ef7c, - 0x4c9c17a8, 0xaca8fc25, 0xc1fa455e, 0x2f1749a3, 0x9e174791, 0x93eba64f, - 0x01f78acd, 0xf991e384, 0xe05ce823, 0xad332533, 0x98cf5f3c, 0x78d4c0c7, - 0x469167a2, 0x1ad3844f, 0x58bf8f92, 0x5cfcc9f4, 0xafa6934c, 0x9e38aaa6, - 0x2f172be0, 0xe1edf75e, 0x4be7507a, 0xc8695ced, 0x1087c679, 0x7de29f5e, - 0xffd092c8, 0x161de33c, 0x9f7c0acf, 0x1d3e7c5c, 0x9f3f5bf9, 0x91ce7e18, - 0x48a6bd49, 0x76b35ff6, 0x782071ce, 0x2aef563d, 0x77f3371c, 0x41879dce, - 0xc91746be, 0x1ccd4c2e, 0x827c62bd, 0x5215cfc4, 0x4695439e, 0x971324bf, - 0xa310f643, 0x8b1ed67d, 0xb9bf46e0, 0xf49541e7, 0x6dd15a77, 0x44f557e4, - 0x3e60b467, 0xfcc3cf50, 0x4c66295c, 0xd90d1ca3, 0xbf401313, 0x5ce0e40f, - 0x339c1c98, 0x71c673ae, 0xdb3a2e7b, 0x553fa83a, 0xb00c0feb, 0xe0b9e0c4, - 0xe5eb911e, 0xc1271a9e, 0xf6f98431, 0xa57efae1, 0x18b56de3, 0xde02fdcf, - 0xe8bc405f, 0xc0e5ff78, 0xa3457bf4, 0xe8912bdf, 0x74fe7e17, 0x6bfbc5be, - 0xf8aa7f6c, 0x15742ad0, 0x869dcfc3, 0x6a4ab5d3, 0x78ae88da, 0x682f9ee2, - 0x36e9d19d, 0x412b857a, 0xe3a0641a, 0xe8efd8eb, 0x10985f3d, 0x4f7e9d5e, - 0xfdef900f, 0xcf5f0b07, 0x9c4bc7c2, 0x8de291d3, 0x1060feb4, 0xcf58212e, - 0xf8d1e6b5, 0xde3c4d83, 0x10bdbfd3, 0x7fd03e71, 0x30f2a5e6, 0x2fde5573, - 0x50fdffe0, 0xf110ffbe, 0xfe22223f, 0x03bc463f, 0xf6c63ffe, 0x4fff8057, - 0xdd7f852e, 0xf4d32fae, 0x2bee1942, 0xc5fcff01, 0x13313339, 0x15142dc6, - 0x5b25ffe2, 0xd21f6d45, 0x62725b7d, 0xb92c8f50, 0x199f7abe, 0xb3c970f8, - 0x9169f102, 0x73fd5e76, 0x784b5ced, 0x1cf15f5e, 0xcbc9e91f, 0x49f9f7e7, - 0x336d950f, 0xe410bf3e, 0xc7ca74db, 0x93f3f1f5, 0xe11726a2, 0x68a33ff8, - 0xd628a2fa, 0x0e9c2ed0, 0x864daa43, 0x29e4f03c, 0x9f90fd7d, 0xbe726497, - 0x3fb5f14f, 0x07c61998, 0xf8fc52dc, 0xbc63e200, 0xcdfb1530, 0xef56e4d7, - 0xe30ae86f, 0x33e19f3a, 0x6acbfb9e, 0x1bfb9e34, 0x686294de, 0x4c86cd7f, - 0xfe91fbc3, 0xafef0d6b, 0x50d636db, 0x8372d51f, 0xb6e8fda1, 0x4c7d4302, - 0xfb4316e0, 0x1a678771, 0xefda13ea, 0x789fb435, 0xfde18174, 0x86a51df5, - 0xba7e37f7, 0xa9bf50cc, 0xed0d5ff7, 0x5eb88b03, 0x94935fdc, 0x740ae786, - 0x2a5fecbc, 0xbe7c549b, 0xe6a4db34, 0x744f3e86, 0xccb1733b, 0x357fa373, - 0xb14cbc90, 0xae85a726, 0x6cccf9cf, 0xac536bd0, 0x55817ac6, 0xe07497e3, - 0xcdfe2017, 0xa55ca356, 0x026bcf56, 0x2ca59bb3, 0xd2f94619, 0x58b75f20, - 0xc5bb7eb9, 0xedfa657a, 0xaa7f6c4e, 0xece74032, 0x444be5c3, 0xd2a2caf9, - 0xcca9fb47, 0x1b96f945, 0x4d3e466d, 0xccaf401a, 0xc3cf1ab3, 0x9b61ea8b, - 0xfd139064, 0xd0a8f9f9, 0xdbe2c2e7, 0xa0676f28, 0x05a4e57e, 0x7d016eb7, - 0xa97b2729, 0x9aaf9fd4, 0x97988a63, 0x3bf590f7, 0xfa1b49fa, 0x210f4fd9, - 0xde92bb7e, 0xccf30a7e, 0x92f5e72a, 0x316c94bf, 0x775825e2, 0x5479e60d, - 0x508e7e4e, 0x54dcffe5, 0xae2b78d3, 0x173cfaf7, 0x1133307d, 0x06d203f3, - 0xd55e9ff0, 0x4d5cf1e6, 0xc345adc9, 0x14d53fb0, 0x7a45bf7a, 0xfd10aaa0, - 0x1e5aa198, 0xc8a653f4, 0xd53f4af9, 0x0a8c19fa, 0x5503ed14, 0xaba0fb21, - 0x048723f8, 0x9377f8f3, 0x17c8a7f7, 0xe7b7460b, 0x6ecb73f1, 0xabb24cd7, - 0xd75f8254, 0xe78ae943, 0xe92bd429, 0x66731249, 0xf06787f4, 0x06636f3c, - 0x338fafbc, 0xf7aa14b9, 0xe59e380a, 0x820d8cc7, 0x5bffeaf1, 0xf7eaf824, - 0x3cf94f5f, 0xe29aa516, 0x993cfaa7, 0xc7afdfb6, 0xcd26cf8b, 0xd63c418a, - 0x6e77db5f, 0xacfd6187, 0x7ec76de2, 0xd337aecf, 0x8205f5b8, 0x6f3ebde1, - 0x741dc369, 0xe15d2b1e, 0x79862ef3, 0x3496dc23, 0x73fd570e, 0xb8234b02, - 0x43d2f7fe, 0x8aecbfe8, 0x0dbc6176, 0xe889b1f0, 0x6738ceed, 0xf30f27d2, - 0x34a418aa, 0x25fb21af, 0x96fa1fb2, 0x4cdbaf95, 0xf688959d, 0x4635f254, - 0x66f5c5b8, 0xc51707f2, 0xe0af942a, 0xd1a159af, 0x55ef38d5, 0x9cef3349, - 0xbdd4f00b, 0xfd4c3223, 0x2d347671, 0x15df043d, 0xfcbb46b7, 0xef78fece, - 0x01387272, 0x6e10b7ee, 0xcd214371, 0xdc21da9b, 0x33d8173f, 0xde77c819, - 0x14ff44e9, 0x977dc313, 0xd3fff870, 0xefc4e3ca, 0x879a5558, 0xeb7c549c, - 0x16584196, 0xb51ddc91, 0x7fceb80e, 0xfcebe568, 0xeb08d687, 0xfdeee5fc, - 0x7ed39f28, 0x6dd14b08, 0xeadaecd2, 0x197b50ec, 0xec49d6f4, 0x318baf57, - 0x7ec5ce3f, 0x3ccbb607, 0x9719d94d, 0x1ed0cbb7, 0xedd3fe43, 0x8d5abfb1, - 0x9e886476, 0xb3d34afd, 0x9ea15d5f, 0x4eed80bd, 0x68881bdd, 0x91c824c7, - 0x1b38dcf5, 0x2a957fc7, 0x1be3ca33, 0x6d9f9e20, 0x0e1f6c8b, 0xce5d0eb4, - 0xd68cc8cf, 0xefd754f9, 0xc560dfdc, 0x9c2fed32, 0x247fe0d9, 0xe329f71b, - 0xedde5187, 0xaea4fd40, 0xf10d83f8, 0x886de3ab, 0xc04f88cd, 0xf9c6d3a3, - 0x648b69c4, 0x1e03960f, 0x0e3c064d, 0xd903f6c7, 0xdfad5783, 0x6ee78c4b, - 0x837c35ba, 0xbc71979e, 0xce3ebbae, 0xe545b8c3, 0xe7a473ec, 0x399c7aaf, - 0xf74475c6, 0x011c61bf, 0xd77ddfe7, 0xb7716b7f, 0xd5178a0e, 0x0c4d7abd, - 0x0a2aa7c6, 0x9586f4fa, 0xa49985db, 0x5976bb07, 0x576708dc, 0xece7cf1c, - 0x10f135da, 0xaf3e39c6, 0x85299c39, 0xaf5d2dd8, 0x4333c91c, 0x8f3b5d7f, - 0x209449e4, 0xd17e27e7, 0xfc5c57df, 0x128f3ccf, 0xc7d0273c, 0x0ebe566f, - 0xf8f1b7ad, 0xc798d3c9, 0xf7b19a36, 0xfaf963a3, 0x1c7a6891, 0xe3bf479f, - 0x7f7ea1f3, 0xc7e57054, 0xdd262b00, 0xab664c55, 0x00a68de5, 0x6e0a8f96, - 0xbe55e311, 0x4d3cfc91, 0x911b1652, 0x4728fd01, 0x8e0803db, 0x8dd7a3a3, - 0xa7ea29db, 0x0b2c3eea, 0xc402ef14, 0x2baf5c7b, 0x37fc7d09, 0xa1b38d87, - 0xe14d215f, 0x7e77b77a, 0x29ef1f94, 0x8fb9344a, 0x6767aa80, 0xc58c2f0e, - 0xe68b7ff7, 0xd258f2f2, 0x8e5c2689, 0x38a03970, 0x5a669bd4, 0x710d96df, - 0xef822f27, 0xe7884d97, 0x9805e97e, 0x9639c87d, 0x0967e3c7, 0x00b90714, - 0x14e78178, 0xb53e02fa, 0x3317cc4b, 0x89b0f416, 0x0bf055b9, 0xee4293ec, - 0x68ffc1d9, 0x4d60fc76, 0x4d38f6ff, 0x45e0333e, 0xd5db1976, 0x5c0cee09, - 0xfc81774f, 0xb4fa030d, 0x7ca958d5, 0x184d46ad, 0xa7b8f206, 0xafea8926, - 0x0ca938d7, 0xe7a08cd4, 0x545c6bfb, 0xa7b5368f, 0x552c7ad3, 0xfe879baf, - 0x0b12fdf5, 0xbc23b7bd, 0x8e567bc4, 0x97f9c887, 0x0093e62e, 0x3d352fae, - 0x38d6fb52, 0xc6a7afe2, 0xfd31d400, 0x8ad9ffbf, 0x054d643f, 0xa3fa983d, - 0x415359c3, 0x78129f8e, 0x181e02fe, 0x552e748e, 0xb7329f2f, 0xf0a9a2c4, - 0x4df31b6b, 0xc8bcc24d, 0x8e153fde, 0xe8f6cc61, 0x1d4ea69f, 0xfdc7f309, - 0xf6c614fe, 0xc7abdeda, 0xfba9d873, 0x818bab3f, 0xfc6dc8f9, 0x82899f3e, - 0x7d4056a7, 0x0bf39b33, 0x98b53c93, 0x3773d9cf, 0xbefee273, 0x1b5ece3e, - 0xdb7613b7, 0x51399db8, 0xe6c1fce0, 0x411e5aca, 0xbae86e6f, 0xef3ede11, - 0x8f74d7c0, 0x2fb78c0f, 0x2f5e30d5, 0xfa0711c5, 0xd7ff752e, 0xe95c8eb4, - 0x491f3d77, 0xc4847cfc, 0xe6ba2bf3, 0xfda66e26, 0xba1f6878, 0x4723da8f, - 0xd2ded7b6, 0xed0681d6, 0x659fb7be, 0xa68372f0, 0xf5c62457, 0x05d16bff, - 0x61b947bf, 0x5fda38de, 0x09e2d3aa, 0xe57a3a93, 0x2f7e76f9, 0x13d43e5c, - 0x3c04784e, 0xd1a5d70f, 0x1e605533, 0x6048ffcc, 0x28028433, 0xdbcf36dd, - 0xc2d24fd8, 0xd197be4d, 0x7165d85e, 0xe3a3d9a2, 0xd903eeab, 0x6121fa8a, - 0x8fda31cf, 0x643a13aa, 0x8f97f7a4, 0xcb714d7c, 0x3275733a, 0x1b176dd5, - 0xbdb4feb0, 0x99d6237a, 0x6fa9ebef, 0xd60c3f00, 0x13e3e1ce, 0x90bb63d4, - 0x3b5829e8, 0x7e06ef57, 0xf5e665d8, 0x4b391f2f, 0x5ccbb1fc, 0xe18d9f3d, - 0xef987af5, 0xaa6f58ae, 0x52905409, 0xe1fd65fb, 0xb7aeb09b, 0x77da92ff, - 0x3f6e54db, 0xa40cde2a, 0x855d5f7f, 0x2ea43dba, 0xf2b33af1, 0xc55f9f52, - 0x7f29af81, 0xe70f72b8, 0xce1bc447, 0xc3cdef13, 0x7a8ce975, 0xa4eb51d4, - 0xd73673b8, 0x9f0301d7, 0xb753e7e9, 0x2a2cbc98, 0x085ecf44, 0xce42ff5b, - 0x84a8b1d9, 0x38b4fe90, 0xbb033a76, 0x6f182b34, 0x2a2e64cd, 0x950f3187, - 0xee96dbd9, 0xbb2db447, 0x7a89d5af, 0xfad73e2b, 0x68e89780, 0xd09e1ff4, - 0xe8fae2f4, 0x01a31bfc, 0x7782f59e, 0xf17a888d, 0xe74ab365, 0xb2243a2f, - 0x35b53b37, 0x5330ad8c, 0xf73b5cbd, 0x5de95e6d, 0xeef51233, 0x19ab9322, - 0x4f0cb3d7, 0x2fbe19be, 0xaae19ddb, 0xe7bcc165, 0xc496d8b2, 0xef304ab1, - 0xaa3faf59, 0xb546d9f1, 0xd2f786c9, 0x9543fbe8, 0x71d2eb6d, 0x7db3fb7f, - 0xbd3c901f, 0x7c41951f, 0x447ad15c, 0xbf69daf6, 0x29f3c64c, 0xd6fad99f, - 0xbef75a3f, 0x0b74196c, 0xeb2ff5ea, 0x79b8744d, 0x06f43d20, 0x38373fe8, - 0xac6a87c8, 0x5dc2fe54, 0xde9a2d7d, 0xd3295105, 0xbfb4606c, 0x9156e990, - 0xb9ade68f, 0x7c0ac1a6, 0x8eac82f4, 0x179b3e44, 0x5b7c4b95, 0xbe722b16, - 0xdd07b964, 0x0dcfb692, 0x6535d4f5, 0x3c53bed3, 0x6f68c8be, 0x88526d54, - 0xc80ec00f, 0xdca83e47, 0x7ee1f260, 0x4edac9a2, 0x45e77de7, 0x368fcd31, - 0xaf5c4f9e, 0x6cdf3be9, 0xdcbddf1e, 0xf392c539, 0x511e7451, 0xe51fbfaf, - 0x9128be24, 0x55ffb47c, 0xe741de72, 0x38fbbf18, 0xc879c356, 0x0428e3fe, - 0x794e3e87, 0x57d21c70, 0x27ec1fe5, 0x6b8df83f, 0x4dd67b75, 0x3be5ac71, - 0x9b05fcb4, 0xf3f6307b, 0x1827a6b4, 0x7780b1fa, 0xeeafa329, 0x1ccf4093, - 0xf933d3ec, 0x90d3530d, 0x6cf7c1be, 0xb90f4192, 0xc1d3a025, 0xfbeead28, - 0x51f6e47e, 0xf533ed61, 0xa986ccfa, 0xf3c3fb93, 0xb7582db4, 0x1be97b42, - 0xe11d5f4b, 0xa1f573a3, 0xe3e9c5fd, 0xe9fd4bdf, 0xb51a97fc, 0xf80fa0f0, - 0x27ac60ef, 0x7a7cf31f, 0xca273367, 0x8d4966e1, 0x21d08572, 0x37af8a35, - 0x35afe725, 0xf7883fe0, 0x4ffd035c, 0xfb0d38d5, 0x968b8b8a, 0x549879d1, - 0xc7cc5e9d, 0xca6d77cf, 0xfe27ec32, 0x16ae387f, 0x7000f70e, 0xc307fd4c, - 0x5e30c231, 0x031c8e10, 0x870b577c, 0x7a6b3b18, 0x8f6bda06, 0x280f2898, - 0x66b3e4d1, 0x6ff65da2, 0x0ca78a26, 0x880f3c67, 0xfb0de329, 0x2c7b99b4, - 0x9efe31f3, 0xd2c3b129, 0xb7279458, 0xa9d716b3, 0x5f64489f, 0x39ab73c1, - 0x726e870e, 0x204ffde3, 0x665fd495, 0x1f82b7b9, 0x82fbe6f2, 0x70d33efa, - 0xbde3e595, 0xe7a39ba0, 0xfb8d18df, 0xaa1e7366, 0xe7983cc2, 0x352ff195, - 0x92bc8330, 0x2c20d21d, 0xabe33b25, 0x701b87a8, 0x147076bf, 0xf6045bb7, - 0xe4e1c370, 0xbcb9ef48, 0xf0f35b9e, 0x341b8c34, 0x8b5e74af, 0xcdb353fe, - 0xf31fb2df, 0xe8531e76, 0x47acd6de, 0x50998dfd, 0x6899d717, 0xfd6314bd, - 0xdf719adb, 0x176cc9fd, 0x68cd11da, 0x47fb60bf, 0x566bf214, 0xf0d338d5, - 0x6d3a927e, 0x76b2d81d, 0xc1798ab2, 0x87148af5, 0x732addeb, 0x773c5cf5, - 0x8dd1ee31, 0x51ebd60d, 0x071ab98f, 0x949ebca9, 0x339aeb8c, 0x7b463ad3, - 0xae68c80f, 0xb1a8a675, 0x6ff0fac1, 0x3d20fac0, 0x9dc1b1b3, 0x2b2efd86, - 0x883bfad5, 0xe2178a71, 0xef68bc34, 0xd2f4fb33, 0xcbcc06c6, 0xf5836b12, - 0xaddf30a9, 0x353d72cf, 0xfb47fa18, 0xc3e3e60b, 0x877b057b, 0xca4e744b, - 0x603b6306, 0x9991b67e, 0x0cd7dfb4, 0x2bef117a, 0xdfc91dee, 0xf234fbeb, - 0xd3ed1370, 0x6f5c7b60, 0xbdbcc96c, 0x57df833c, 0x8a15db20, 0x307ac037, - 0x149ef315, 0xf371ffa6, 0x8fb6a4b8, 0x01f78511, 0x75a3f084, 0xf73a32ed, - 0xdc661d69, 0x8cd3979f, 0x16798975, 0xaa27bfa0, 0x4637e7c6, 0x8341f96b, - 0x6dda0a58, 0x133e4dc3, 0xfcc91bb6, 0x02c75e54, 0x628d8f64, 0x8d1f541d, - 0x1e16635e, 0x41d2725b, 0x2dcc71ab, 0x47aa38f2, 0x71313b44, 0xf2471eae, - 0x74be414e, 0x61766b47, 0x7e3fef0a, 0xf7ca2cc6, 0xcdef69f5, 0x313d8633, - 0x7eb5e60d, 0x50ceddc6, 0x2f5f4efb, 0x48adfb75, 0x68cbf983, 0xa0bda221, - 0x364575db, 0xe5984f5e, 0xc6147a7e, 0x26cddb11, 0x58ad9fbc, 0x6f16638b, - 0xbb444fc8, 0x5cdf68ac, 0x44d787b2, 0xd16cbb73, 0x77b219fa, 0x9af79e14, - 0xfe7f764f, 0x183109ba, 0xb9b06fa7, 0xfe47ae62, 0xdfbf23fd, 0xb1ed4af5, - 0x0a6bc4e6, 0xc19b1e50, 0x8ffbc6af, 0xcadd9a0e, 0x758be418, 0x6ccec8c3, - 0xc7d6f28e, 0xffcdbf42, 0x41d574ea, 0xf73667fd, 0x4e3823f8, 0x8f7f1443, - 0x6f2126f7, 0x3ff7edf6, 0x1e8c5c2f, 0xfdf0fc78, 0x91b183fe, 0x43bdf1ef, - 0xfed05fc3, 0xd9dd90f0, 0xdcc4f660, 0xcbbdf087, 0xead679e7, 0x112f5189, - 0x86b4fb67, 0xd67603e7, 0xe64058b8, 0xbd62d1f7, 0xdd3f68a4, 0x22d25caf, - 0x097cdc50, 0x3a3d226b, 0xeed5894c, 0xc5e631a7, 0x4dbd1696, 0x795b4bed, - 0x42d632fb, 0xe17a75ed, 0x8301b5bd, 0xf0ce3a1d, 0xdcd11dfd, 0x78acdd6f, - 0xfffb431f, 0xc4d91991, 0x1167c04f, 0x07e22df3, 0x31b977d8, 0x371faf9a, - 0xf6c8db62, 0xb863f128, 0xe05cb87d, 0xc207b3e7, 0x9379d553, 0xde0a3d61, - 0x7ad3219f, 0x49f9add4, 0xeb7c9387, 0x7ff9846f, 0x244af59f, 0x23bddaa7, - 0x425f8275, 0x33befaf9, 0x2d1bdeec, 0xa6ba680f, 0xcb43fe25, 0x6b3ef9ef, - 0xfd0dc379, 0xf402cedc, 0x9eed61dd, 0x48a41412, 0xafd01979, 0x3adc1f41, - 0xddbf58c2, 0x39dfac65, 0x7d3df229, 0xb4d46b6b, 0xd6aa7bd0, 0xf38e700e, - 0x575e8d2d, 0x0b12df7f, 0x0b7bebcf, 0xf9815ee9, 0xc17fb494, 0x1b14faf3, - 0xd91ea0f3, 0xfb46cfbf, 0xbc8a5521, 0x55164319, 0xbde2efe0, 0x9f9d8af0, - 0x17ff4037, 0x998a05e3, 0x97de0fb7, 0x1251f7c4, 0x3c5a493c, 0x633495c3, - 0x1b87b7d4, 0x0bca2afd, 0xdc46d896, 0x27e60d77, 0xe8edef1a, 0x0f38fe8a, - 0xcf9863fd, 0xe84f8c6c, 0x3e7d5a71, 0x2c7f28ff, 0x39cfbb5a, 0x346b6e9c, - 0xa30ba8f9, 0x39d23d73, 0xb973df07, 0x87bb52f9, 0x43c129ff, 0x26896879, - 0xb3ac171e, 0x9c528eb9, 0xea0ff344, 0xf306b8b4, 0x56ef5d7d, 0x1095ecc2, - 0xed7d22ff, 0x39f5f5d7, 0x38f377e4, 0x156a2d88, 0x360dc3ae, 0xfaa66ebd, - 0x00a6e6d3, 0x5aaffdf9, 0x831f189c, 0x6718ddef, 0x411dcdf3, 0x065d5d7e, - 0x0e7bc14b, 0xb4cbb0de, 0x6abdd6fe, 0xd8f5c669, 0xdb76f36d, 0xba49f242, - 0xf9d1efec, 0xf9fd08a6, 0xf90dfd0c, 0xf8c1fd76, 0xfd7788ad, 0xa7f61bfd, - 0xceff2202, 0x691bf949, 0xa17b1fed, 0x42cbb89e, 0xf7fd4f71, 0xe7cfca0f, - 0x7a8cfdd1, 0x4e14137f, 0xd51ace87, 0x8e5d8f90, 0xe507377a, 0x67f49da0, - 0x8320cb45, 0x69f5d4de, 0x681bf9c5, 0x57482cbf, 0xb5212e2d, 0x38aa5e93, - 0xbc68bfff, 0x349e903b, 0xf7e9124e, 0x3549c781, 0x38e0e3e8, 0xf7700c93, - 0xc132671f, 0xdac38fa1, 0x9fe70ca2, 0xae3ccceb, 0x33986672, 0x1e823626, - 0x83714bd1, 0x60ff70c9, 0x62b2e49d, 0x4eca75ff, 0x287f3435, 0xef005f7c, - 0xf02164c5, 0x867ac1d5, 0xf30b72c1, 0x3d405e52, 0x072213f6, 0x62a5d9a2, - 0xf8c262bf, 0xc62ef9e9, 0xbdb945fe, 0x33727d10, 0x8bd82df2, 0x7e3b583f, - 0x49ec0f95, 0x4769ecc9, 0x93764aba, 0x6b68f313, 0x45c51315, 0x64ac92eb, - 0xca12adff, 0xbd739455, 0x2243a95f, 0x8f7df438, 0x9f29e681, 0xc33cd077, - 0x9ffb3bef, 0x76a14f1b, 0x3b57eefd, 0x0f93d730, 0x93545bfd, 0x4e5d450b, - 0x2127d853, 0x47ef0ff4, 0xec4520da, 0x8e9dbc27, 0x6ce901ff, 0x3d2070ee, - 0x88a5e3ba, 0x951b1079, 0x310798ef, 0x271f4c2f, 0xe00ecd1c, 0x238742f7, - 0xe5f48323, 0xa5f50546, 0xdc9fccfd, 0xb4cbd24e, 0x7fafadef, 0x56a984e6, - 0xbc6c4f9e, 0xfe206f57, 0x7d62f1d3, 0xf3c641f3, 0x7f94bd53, 0x483c3972, - 0xfb43cb82, 0xe2297600, 0x425836be, 0x4938fc86, 0x354fe631, 0x63e21e48, - 0x56d54df3, 0x5b4927da, 0x927dc569, 0x063392d5, 0x37ded8fd, 0xf983fec1, - 0xbe793a35, 0x6bff786a, 0xb4661ef0, 0xc4531573, 0x06a379fb, 0x34baafb0, - 0x77d9acfa, 0xf501fe69, 0x3775c1e1, 0x71524e2a, 0x399b35dd, 0x4bad03bc, - 0xe103bf7a, 0xfc7dd1eb, 0x392c1bf7, 0xffae3f56, 0x4a35e3e1, 0xbc3e4f1e, - 0x7078046f, 0xcd31acdf, 0x546df84d, 0xd5fd1525, 0xcc5111e8, 0x656fea1a, - 0x67f7a2cc, 0xccf1e3e2, 0x8f8c6b22, 0xe3a3979c, 0x1df2b769, 0x186f1ded, - 0x8f7f0e5f, 0x7c21e8e2, 0xe84ca9d9, 0x91bb97cf, 0xfc381317, 0x5aa6f7a1, - 0xbc458633, 0x7f1fb27f, 0xde4df186, 0xf7e74664, 0x19b94306, 0xeed56efa, - 0xb5c0aa43, 0xf2f4fc0b, 0xc2a6147b, 0xe477e6fa, 0xc939405f, 0xcfcfdf6b, - 0xf026b4d1, 0xefb51e7b, 0x625dc7c3, 0x12c8fee7, 0xcc654abb, 0xf12ff751, - 0xdb5a37f7, 0x5e789ca3, 0xb22e35b1, 0xd763931f, 0xb49a68f3, 0xb41d0873, - 0xcfb7a14f, 0xcddcc79b, 0x1b3dc50a, 0x257fe0ad, 0xa9ffb5f4, 0x82023fb6, - 0xf9dce30b, 0xf99aebdb, 0x7f3e51f9, 0xfb62ab8c, 0x5c8ec4c4, 0x740efc41, - 0xf70cc6db, 0x3b5855db, 0xe7ce51b2, 0x7699bc9a, 0x68eaa718, 0x5bd62247, - 0x4e9d3edf, 0xb71d6f7e, 0x47777b37, 0x3fa0dc53, 0x79f96a7d, 0xcc29f3f2, - 0xdd3fa837, 0xad00a5ca, 0xd3e7e5ab, 0xcd1c6f99, 0x0b8d67db, 0xc2d3bfbe, - 0xc8b1a4d8, 0x884f1c00, 0x30f4489f, 0x7a064ddb, 0x675e3c80, 0x7881e8d7, - 0x76b7a3ea, 0x76a74bef, 0xcd71e0bf, 0xf72a615f, 0xa5fbf5d7, 0xe5f7678e, - 0x5b7dd05b, 0x13f736e5, 0x3b0b4f78, 0xe6be5222, 0xfefc29c2, 0x771685c4, - 0x0b57da0c, 0x6a1453ff, 0xf3937f69, 0x7f0d22fd, 0xf745cc9d, 0xdad6f80e, - 0x984ebef8, 0x54f1967f, 0xc23fb8fe, 0x44da8bf7, 0x305f1bca, 0xbf61f145, - 0xbf05ed79, 0xe2f9fdc4, 0x773a68c6, 0xae7bf0be, 0x2dd76893, 0xc4e6c27c, - 0xfe597bdf, 0x327e6641, 0xc9fcbbf4, 0xdf07d50c, 0x24f0af45, 0x27a05d59, - 0x8853db1f, 0x3083457e, 0x0630be7f, 0x0ec7cafc, 0x98b8c2ac, 0xcf94cdf4, - 0xf47f506d, 0x615677b1, 0x18b7e9bc, 0xf63b26e7, 0x63b442dd, 0xf4d0425f, - 0xc1c03ffd, 0x5a4d874b, 0xa9aac4fd, 0x4daff2a0, 0x2a293568, 0x562765fa, - 0xc4d939e1, 0x1318f738, 0xfd8ef78c, 0x6fec42b3, 0xcea313c1, 0xe7f7806d, - 0xbec817ed, 0xdf693a00, 0x014f370b, 0xb278bbbb, 0x582d975e, 0x86668f8f, - 0x3339be38, 0xd9da3e38, 0x8b7c7aad, 0x718cdd45, 0xd505e3f7, 0x3fe82453, - 0xceaea1c3, 0xc4d8c919, 0x1baaf9f5, 0xc476cfc6, 0x98f18cdd, 0x837dbed6, - 0x1f18d5f8, 0x03de656b, 0xd37f7866, 0xb66e43e3, 0x07e36202, 0x30a8c679, - 0x29d641ff, 0xf4dfa7ab, 0x4463e41d, 0x0d59f3bf, 0x939204f6, 0xf4d28843, - 0xc2defc15, 0xe34ef93e, 0x1f57db7c, 0xc3cfc1d1, 0x5e24f5e8, 0x59195d6f, - 0xc312dc5f, 0x2a35baf9, 0x4d66fbf2, 0x03be003f, 0x8b6d7f14, 0x08cf0ff6, - 0x1f900fea, 0xa79224eb, 0x807f5c75, 0x93b4cd1c, 0xefec46dc, 0xab6bcadb, - 0xab79af76, 0xf8c68ee4, 0x30c7ae82, 0xcce38682, 0xfa0d3bb5, 0x017daf39, - 0x3151d7e9, 0xc9c7872a, 0xc53093f1, 0xb59847a8, 0xdf743b3d, 0x3cda77fe, - 0xe3d3ae33, 0x7439013f, 0x8ef969df, 0x9f9e4bfc, 0x7f38c72d, 0x9c1dbd88, - 0x678a54c7, 0xfa17ebf4, 0xbbfd6a73, 0x5f04ae72, 0x15f065ea, 0xdcbaf84f, - 0x19fd833c, 0xfbfd2fe3, 0xc17db593, 0x223ae326, 0xa4f38647, 0x7f8027ce, - 0x2cfe8853, 0x9ea9f4d6, 0x6bbdd107, 0x064fe524, 0x31e7e5c7, 0xc4bfbe81, - 0x81f25ddf, 0x963d453e, 0xc56fb927, 0x71ed79f6, 0xc0efda2a, 0xbf1af56f, - 0x3a6fc849, 0xaae35b9d, 0xebbe69f3, 0xfa4bb204, 0x3ada41d9, 0xd024d79a, - 0x9e0d99ef, 0x87e715e7, 0x7beba7c0, 0xeb55bfe8, 0xe7e73c7f, 0xf9f8fb67, - 0xcd1f943e, 0x0eae679f, 0x1c3d5fba, 0x732885fe, 0xd5eb2109, 0xeb8a36ab, - 0x5abb78eb, 0x85edd7fe, 0x25d701f2, 0xf8377d07, 0x84e1c068, 0x1e518b76, - 0x7cb55f50, 0xb664f742, 0x7f0c89b6, 0x8de700b2, 0xd74f237a, 0x8795be93, - 0x5bb2240a, 0x49d97a82, 0x37ae8bf6, 0xb06b5603, 0x2bb5b9fd, 0xaf51eb0b, - 0xc7ecf76a, 0xc7c5a08b, 0x7348e106, 0x9277bb70, 0xddfc4597, 0x5dbb1cb8, - 0x8f3423d7, 0xe80a2b8d, 0x6d2a855e, 0xe1d49d3d, 0x345378a3, 0x104271e2, - 0x7d7afa1f, 0x15e3a5a7, 0x8197bced, 0xd83af51f, 0xaca69525, 0x7ef8ff60, - 0xe7df0866, 0x841f3839, 0xeabbe7d3, 0x0f83c027, 0x0d43f0f1, 0xc75009ef, - 0x04982d7b, 0xfde617eb, 0x6b5c50cc, 0x56e04232, 0x104e3eb8, 0x5d8f5c4d, - 0x07e22e46, 0x58f7ed31, 0x41cf24ec, 0xe5bb707c, 0xe7168701, 0x3f29eed5, - 0xa1390268, 0xcf3e367d, 0xd4c95dee, 0xddad6cef, 0x6f2f4bdf, 0x7496f2d6, - 0xb5e2b17b, 0xf846cdd4, 0x1cbb7f79, 0x47792f1c, 0x8ed063dd, 0x5c51ee19, - 0xb5e41fe8, 0xf98fdccf, 0xf07bd924, 0x7c820407, 0xe5c2dd9e, 0xc34bb814, - 0x43db9bcb, 0xd874adfb, 0xbbfb3975, 0x28fb23cc, 0xcba457e7, 0x5a72217d, - 0xbe3850e3, 0xc4167e60, 0xa3d464a7, 0x83f7f97a, 0xcf1fb3c3, 0x3e039525, - 0x78eb6d50, 0xbf996d6b, 0x7c7286d2, 0x8e50b994, 0x9be65bbb, 0x315d2146, - 0xa219cc11, 0x79f3d61f, 0xf02876e8, 0xe5f20b65, 0x1a10c73a, 0x7751f86f, - 0x1fbc0e74, 0xc613768e, 0x7eec5b7d, 0x0efc23f4, 0xe2072eef, 0x14ef5673, - 0x8cad4fdc, 0x85b5aeae, 0xdf6bef3c, 0x8f89ed06, 0x1fee22bd, 0xf8c03f95, - 0x7cdaf1bd, 0x02cfa9a0, 0x20c855e3, 0x0f5459a7, 0x655ade20, 0x3ef7bede, - 0x5611a5fa, 0xf97bf229, 0x95befd60, 0x536df3f8, 0xfd17d21c, 0xcb93b424, - 0xee1a4f45, 0x16c1b27b, 0xe003ae17, 0x1fbf1077, 0x06c931b4, 0x4a1efffd, - 0xc4d3d3d4, 0x6b8e74a5, 0xfb40965a, 0x8f7fba44, 0xa4fd0b7a, 0x4d17bf3b, - 0x3c2ec8fc, 0xd3e30c38, 0x4e9cd109, 0xeb558fd0, 0x1b1d6ac7, 0x48ffbf94, - 0x8efe491f, 0x141dbebe, 0xe0e7ea04, 0xd735d74d, 0xd841f885, 0x83ffea1f, - 0xa5b48cc2, 0x1f9affc8, 0x7c61f647, 0x7b45dd70, 0xce21ac65, 0xebe0d3e6, - 0x0a3e4748, 0x3ed147b5, 0x7d67b3ed, 0x0cdf57f3, 0xf4e2767a, 0x715e0096, - 0x6e8acb5f, 0x6fe817fe, 0x36b3d81a, 0x8d3ec3c0, 0xf8660e2f, 0x3d4fdc44, - 0xfba05c38, 0x79450fdc, 0xe095aa73, 0x5c5a8938, 0x33cb5120, 0xe5e28c4f, - 0x1eb8620f, 0xaf863cfc, 0xbca837d7, 0x1c88e89e, 0xbdad9847, 0xeb89a9ff, - 0x91f935f7, 0x684fd1f3, 0xedaaf5fa, 0xfc211cde, 0x8e13eebe, 0xdd7dda09, - 0xe3c76f94, 0xfe340bfd, 0xe8873b06, 0xf8abb414, 0x876e9d7e, 0x4d9f6d9e, - 0xf78213f5, 0x2c047bbd, 0x9f904f3d, 0xf148aef4, 0x6f58e2a1, 0x55a5e622, - 0xcb8e4544, 0xf4f0d20c, 0x38a30d59, 0xcfdc29ef, 0xb7bfe6cb, 0x1b25f585, - 0x1d7ba49e, 0xe29f994a, 0x1a1b45bd, 0xc8aebf68, 0x80a7302f, 0xc78799fe, - 0x943a3581, 0x710d116e, 0xb552c5e7, 0xe4139b1c, 0xae1dfc5b, 0x9b25f7d0, - 0x57ea19c6, 0x1816976f, 0x7a823bf2, 0xbfec90a7, 0x3e757ef0, 0x8f4fb70f, - 0xf10d38d7, 0x861b05ee, 0x78cdf217, 0x73217ede, 0x36177cd1, 0x11ef1966, - 0xb2b84c6e, 0x1ec1827b, 0x538445f5, 0x3fa8fd26, 0xf7f80e3f, 0x17f7c485, - 0xe08c3a7c, 0x7bc38bf8, 0x8e018c5d, 0xc433e668, 0xdff326cf, 0xf8f1b429, - 0xef8ff023, 0x7e407652, 0x07f577cc, 0x1fc01dae, 0xfa87fdc8, 0xb9937903, - 0x024d65fe, 0x9c4ce0e5, 0x66cfb46a, 0x6e75f0c7, 0xc1b44c76, 0x679a2b3e, - 0x6b57376c, 0x776b5737, 0xa84a38b9, 0xa164265d, 0xe9fde33e, 0x71951fbf, - 0xffca6dfa, 0xedc310dc, 0x6eaa9fd7, 0xbbf40c6f, 0xd0773b56, 0xefdade6f, - 0xf735ad4a, 0x5e5285e5, 0x1e6fe6e0, 0x09dfc3ac, 0xf601dde9, 0xfcc1e83f, - 0x7ba0df67, 0x6eeff4ba, 0xb432d15f, 0xa954f008, 0x8bb973c9, 0x15dcafcf, - 0x3f418790, 0xae1ce529, 0x827d96b4, 0x5a5df214, 0x22b76f09, 0x2ff06cc6, - 0xffd5a27f, 0x6549c635, 0x1840495a, 0x3652ed06, 0xec24116d, 0x0b577f0f, - 0x66a949e0, 0x93dfd0fe, 0xedcf194a, 0x6fc7db9a, 0x04e61616, 0x9a68d0f1, - 0x5c62a391, 0x85da3135, 0xaa47cceb, 0x50f10eb7, 0xce8051fe, 0xa8fc4c49, - 0xbdbb425d, 0x23d7755b, 0x7078eb7f, 0xae0a6a8a, 0x711fd1a3, 0xfcfa9b38, - 0x30bebe62, 0x4766a8f6, 0xe976eb37, 0x42edc661, 0x5712a75a, 0x3efc308e, - 0xb69c6261, 0xef32244e, 0x37da854e, 0xa327a232, 0xccae24f9, 0x2c76e66e, - 0x2cb4f7a7, 0x3e7c16cf, 0xb1c8f06d, 0xd647df78, 0xbf8480da, 0x26dafe3b, - 0x51fbc453, 0xc3fc359a, 0xf9c59e3c, 0x9cb8f3e9, 0x99dbd05e, 0xe84f8807, - 0x3d3d10f2, 0xd8c1dfb2, 0xff3ef4e3, 0xe97bf8d9, 0x997acafe, 0xc74e4f7e, - 0x69eab77f, 0xb4a6bc41, 0x3708166c, 0xdc7a78da, 0x5ca39f0e, 0xe78d971e, - 0xfb94073a, 0x16873b15, 0xbd7dca85, 0x1cd9f44c, 0xdbafe796, 0xe1887ff7, - 0x5890eaeb, 0x4bc43ecf, 0x8a3adb65, 0xc2d92cef, 0x4067f77f, 0xfe215cfc, - 0x07ee1284, 0xfbe1cf94, 0x4acff95e, 0x7ab2ff44, 0xe5acfbfe, 0xb8f077db, - 0x0b998fce, 0xcb7943f5, 0x0728a10e, 0x8773077f, 0x9f0428b0, 0xca7ee5a9, - 0xaec6bf83, 0x5bd71fcb, 0x718efce1, 0x0e53b462, 0xe87eb8d9, 0xb87c57cc, - 0xf669dc1f, 0xcebb6396, 0xe61768e4, 0xfff8e977, 0xe99b8efd, 0xa77db5dc, - 0xa3658025, 0x8ac939a9, 0xcad70efb, 0x6eabe42e, 0xe9127bd5, 0x5a792713, - 0x78d8fbf1, 0xbe16abbb, 0x58d85a75, 0x3c72b955, 0x8fe30c4c, 0x72e63f89, - 0xf43aa493, 0x24b186bc, 0xeb9daa37, 0x67d7132d, 0x1e7ccc87, 0xf787193b, - 0xb3ee3107, 0xe3878724, 0xf294dc68, 0xca1f9d00, 0x70d3bd38, 0x5fc830ce, - 0x1b7dbfee, 0x2c3fff7e, 0x00284ba1, 0x0000284b, 0x00088b1f, 0x00000000, - 0x7dd5ff00, 0xc5547c7b, 0xbddcf8f5, 0x0dd90afb, 0xdc3bf79b, 0x24280c10, - 0x01049e6c, 0x878424d9, 0x28026e20, 0x47796bc8, 0xd2026c92, 0x6dfad0fe, - 0xe5318316, 0x16d46b6b, 0x882ea945, 0x835ab696, 0xb80d06a2, 0x47d62228, - 0x2d8aa523, 0x2220a5da, 0xfb1b6484, 0x6fcb56c0, 0xec9999ce, 0x0f0d9bde, - 0x7cf9fb6b, 0xdcc98fe1, 0xe6739f79, 0x9ce7339c, 0xb5331d99, 0x228ca8cd, - 0x389aa6a4, 0xfd2d34bc, 0x84e90ee9, 0xf00b9085, 0x8321226f, 0xf121326c, - 0xbd3ca484, 0x582c524d, 0x1c5a7fbe, 0x052627d6, 0xaed84bbe, 0xa0af9686, - 0x84225ba9, 0xa0e4258c, 0x31cc7881, 0x2ae8b484, 0xfd68d947, 0x7b488496, - 0x663b2d13, 0x68db4573, 0x9d63967f, 0xeab4ac07, 0xa33e6398, 0xda4bf68b, - 0x4264c7e9, 0x121230de, 0x8c1ddb41, 0x6dd3ed60, 0x42229074, 0x07891b26, - 0x233d1bbf, 0xc1dfda14, 0xbfb083a1, 0xa6eab797, 0xc37b697a, 0x19d8b220, - 0x9b74ef32, 0x6ca5db0e, 0xe8e921dd, 0x5a48b8f7, 0x513f321e, 0x595b01ef, - 0xcc67cc26, 0x43844ed4, 0xae3d56dd, 0x1ce8c2a7, 0xb05466b6, 0x8fe868de, - 0xe6ed7bd6, 0xfa7e8c4f, 0xbd2fc7fd, 0xbf50246f, 0xc1b47255, 0x37df5bfc, - 0xa9a1c9ce, 0x4932e7e7, 0x613a6420, 0xf0bf36ff, 0xdfa151be, 0x70a6efa7, - 0x76eaf5a2, 0xa32fd2ef, 0xc5a95769, 0x24268d23, 0x8b6bccf3, 0xdefd2148, - 0x74112266, 0x5736dd6e, 0xfbce8d91, 0x0e535dcd, 0x58845149, 0x20f9339f, - 0xc421f015, 0x06b4e19f, 0x3a5225e7, 0x722fce30, 0x10b3fd2a, 0x55ef46b2, - 0x95ddf099, 0xb7eb4559, 0xccf830c6, 0x42e0cc1f, 0x157bec2c, 0x0b80975f, - 0x8c0a7f1d, 0xdce5915f, 0x2454fd01, 0x329bd846, 0xaff99e61, 0xebdc2999, - 0x823d92ec, 0x672b8d56, 0x579d0cf0, 0x79b84e65, 0xe2f1c06d, 0x44f8d963, - 0x7180cfef, 0xefb2f109, 0xf9216932, 0x3873f6c1, 0x1f77e9be, 0x3a864efb, - 0xd7f38273, 0x4d836fe2, 0xe861fac2, 0xa3ac116c, 0xc7cf98f6, 0x0f53ace8, - 0xe6799674, 0xd043e230, 0xeab6cfcd, 0xd5fd1531, 0x5fd88cd9, 0x708f4d9d, - 0x1a780cd9, 0x2c03534c, 0xcc1ba69a, 0xc7850f5e, 0x1f26f39b, 0x7e297292, - 0x20fa316e, 0xb4b7437d, 0x48dfca16, 0xe8b7e361, 0xdf216b74, 0x34859772, - 0x6e1d5e21, 0x376bcf98, 0x6a7e2147, 0x26bd1ae7, 0x9f8fcfda, 0x63de5897, - 0x67fa12f1, 0x72f66bad, 0x22e24768, 0xfe024fec, 0x738c075c, 0x4ae9fdac, - 0x51bf6e79, 0xb7a7dfa1, 0xf027fdb1, 0xe8c6db50, 0x0107ec4b, 0xbd3c20d7, - 0xf024fdaa, 0x8db07f31, 0x17a505d1, 0xcecd7780, 0x3349db08, 0x0102eb1b, - 0xe5568cfa, 0x6d93dbeb, 0xf3044727, 0xd007f035, 0x81620ec1, 0x79f2d679, - 0xeeb9d3ce, 0x6755fd83, 0x50341ff6, 0x0d1f16d4, 0x881f7ee0, 0xffd66b7e, - 0x0164fb3a, 0x0e93ab21, 0xadf62a61, 0x7f7aa861, 0x6f78e56f, 0x7bb69482, - 0x4d4dd382, 0xcbee1b61, 0xb80d939a, 0x19532d9f, 0x231cb35f, 0x133c508e, - 0xdebe43f2, 0x457db17b, 0x9964db64, 0x71e2bdc2, 0xfa44d6c9, 0xaba44fcf, - 0xa36ce224, 0xf5b67dfd, 0x0025a8f5, 0xc82eafdf, 0x37ae98a4, 0x3777ad82, - 0x3b5d3be7, 0xde91c029, 0xcc248c1b, 0x3fb72f7a, 0x01223be2, 0xec386b3c, - 0x1f2e9ebb, 0x17a529fb, 0xf6c1cecf, 0xcf92e8ab, 0xf6eb3d3e, 0xbbbce94f, - 0xcbb44c76, 0x4e4d3640, 0x7c409fa4, 0xa53b7d84, 0x4c99389f, 0x37de2895, - 0x351ebdb4, 0xfcfbb68e, 0x81f3a397, 0xf7cdbf6f, 0xe5e799fd, 0xbb9700f5, - 0x75ecf67e, 0x95e35e50, 0xce304d62, 0x95ffc7ce, 0xdea9fb42, 0x26100f51, - 0xd57cbf4d, 0x74f5a7e8, 0xfbec6dde, 0xa836c1ce, 0xf713f9f7, 0x6ef0075f, - 0xf2c26b6a, 0xc36c4f33, 0x7b3f6bfc, 0x683fdf76, 0x94675abd, 0x799dea1d, - 0xa5e23f7e, 0xc077a5d6, 0xeba2077a, 0x33f6bbcd, 0xe126d97e, 0x1973237e, - 0x2d74131f, 0x9ff3f7e8, 0x2a1b1e2d, 0x16f7c437, 0x833b9723, 0xcb391c98, - 0x994d6ff7, 0xb3d205a5, 0x85cc44cf, 0xfe8dbaf5, 0xcf9868ec, 0x1f174628, - 0xb6d47871, 0x2db831ad, 0xf9fb1ed8, 0x487bee80, 0x9e7d2873, 0x6b4ef4a2, - 0x0050b8ed, 0xeb0afde3, 0x11257ad3, 0x2f37be14, 0x7cc12e38, 0x18354722, - 0xbf9e706a, 0xd574e564, 0xebc5e5a1, 0xe96a3d18, 0x059b0be0, 0x907d8beb, - 0x4d32bbb2, 0xb2603e41, 0xd6ce3e33, 0x6aed5297, 0xd7efd2b2, 0x65d973af, - 0x4f97c78a, 0x4a9c9e1f, 0x211b3ff3, 0x65fe2015, 0x8f39c989, 0x5ba9c705, - 0xd04e465f, 0xd9a2eaf9, 0x11b0497e, 0x07c8b5fd, 0xd7ba31b6, 0xf205bd13, - 0x89f200fa, 0x072e16ba, 0x1279b077, 0x96632073, 0xae59db15, 0x83ce098d, - 0x3058b3b6, 0x29b8c81f, 0x678ee407, 0xc51dca2e, 0x233df388, 0xe4f101f8, - 0xee09cc2e, 0x711d04b7, 0x8c13fe01, 0x7e30b534, 0x4ffb4953, 0x8a4d2e8f, - 0x09a60a2e, 0x16b95883, 0xf2f0b74e, 0x923b451f, 0x3b5e01a2, 0x60f25563, - 0xdaf2be20, 0x6e4cddcd, 0xe91c72bf, 0x08740dd0, 0xaa4ebbe3, 0x6472f6e4, - 0xf70e94ae, 0x5c3a471c, 0xabf8cede, 0xb8d4bdbb, 0x259ba68c, 0xefe61732, - 0x7404f4e6, 0x9bf9a764, 0x7d71a3a2, 0xd9fcebee, 0x39baa7c0, 0x61ef75dd, - 0x4e86f6f4, 0xbcf801e7, 0x36e47db1, 0xf95a0790, 0x113b5528, 0x6f8a6edf, - 0xd67a0493, 0x67a0c3ba, 0x3b1355d5, 0x6ef757ec, 0x081a1fbe, 0x7b7707ee, - 0x2fe872e5, 0x5d9a6e35, 0x992f5096, 0xeef34a9c, 0xfb04525a, 0xd96b652d, - 0xd20ba01e, 0x20ab912e, 0x0ddced5f, 0xab8fafed, 0x2099cbb3, 0x9927b6f7, - 0x47ebfd69, 0xcdfb6314, 0xf4294ae9, 0xb620a9e7, 0x706f2127, 0x9cdb3ca1, - 0xf20ed23c, 0x88daedce, 0x0651177a, 0xb89ca1d9, 0xbea16bf4, 0x6c80b3db, - 0xe3ecc292, 0xcb03923d, 0x08de91bd, 0x3b7a7eda, 0xeddc7fd3, 0x139f1f6c, - 0xa1a911f0, 0xd78c1173, 0x788982fd, 0xbd9d20a4, 0x930a67b9, 0x509a2fb3, - 0x746d9ece, 0x34541390, 0x10568c8f, 0x358e02af, 0xa03a99ad, 0x9966425b, - 0xf8cb1e60, 0x4c0d5a3c, 0x3973446e, 0x9b2f7590, 0x1fbe72c7, 0x78eb4796, - 0xaffbe46a, 0x9b05c995, 0xe0e41727, 0x921e3e39, 0x73970245, 0xe5bae874, - 0xb527dc3e, 0xe2feb34f, 0xdbbc8e4c, 0xe855e842, 0x6c7a5a47, 0x6ca6e3e2, - 0x3301203d, 0xa55ad949, 0x57d7e7da, 0x5d3d5f13, 0x755bf5e7, 0xa8b989be, - 0xfc82dd37, 0x6c91837c, 0x77f7fa97, 0x5be3344f, 0x3cceb115, 0xcdd7e409, - 0xfa3fd416, 0x8720e9f6, 0xb8f4022e, 0x84dec97c, 0xea1670ab, 0x09d3bd68, - 0xede03b56, 0x5a8e1c47, 0xbdafab7d, 0xd19c0f46, 0x4325c9ea, 0x4186e969, - 0x549e0173, 0xa198b75f, 0xa7b68d9d, 0x8fb612f5, 0xf213627b, 0xf7ec26ab, - 0xeb1b68f6, 0xd859d627, 0xcb2e2c00, 0x27c98eb9, 0x7adc3dab, 0x9e85a3d2, - 0x074f28bd, 0x82db33f4, 0xafc7e1fb, 0xbd194b48, 0x01284151, 0x41fdb23d, - 0x5278fee8, 0x3d447a41, 0xf4e0ddca, 0xb647a786, 0xaf54dc5f, 0xd29b3d02, - 0x27a65ae3, 0x4fdb085b, 0xa7232e8c, 0x7c007932, 0x159f542b, 0xefbb54fb, - 0xedf6fd05, 0xefdccbfb, 0x1fb606dd, 0x801c29bb, 0xfce8fbde, 0x9be74665, - 0x48fdd036, 0xfdd137cb, 0xffc214d8, 0x981fe7b5, 0x04079c27, 0x73663dbf, - 0x745f0076, 0x19ab7f6f, 0x47f396c9, 0xc83fcbf7, 0x65de98be, 0x5fb4ca86, - 0xa1afdd33, 0xe0a663f4, 0xea63e6b6, 0xb9113901, 0x8947ad5e, 0x266883f4, - 0xdeb1bebf, 0xa3d24238, 0x55f1c3de, 0x007d73ab, 0x46f41e7c, 0x6324114a, - 0x131bd33d, 0xde00e640, 0x417a47b6, 0x20484e3f, 0xccc2e7ae, 0x67df3f67, - 0xfce29f02, 0xeac51090, 0xff7df2f7, 0x4ff7af29, 0x4b9c869e, 0x3a283f70, - 0x0f2271d7, 0x3b448f2c, 0x172c2f3a, 0xd73be9f3, 0x137cd998, 0xbedecaee, - 0xc18f0429, 0x3e75757d, 0x5eeb37e0, 0x25a97e9f, 0x8b908e38, 0xf981ba5a, - 0xf581fc83, 0xb81a8e54, 0x7e7eeb5e, 0x71d0d33e, 0x7b5fdf04, 0xb482b8a8, - 0x2bfbe0d5, 0x5635c7ee, 0x2522fa02, 0x9d2c4707, 0xe1befd57, 0x088d1f6c, - 0xeafb4364, 0x314dd758, 0x9331dfb4, 0xdfa0fef8, 0xa09ce0ab, 0x0c531e27, - 0xf5e0dde0, 0xd3f9e087, 0x8f7fd618, 0xe991ecd5, 0xd623b8fe, 0x3ded0d15, - 0x03eec465, 0xe5077339, 0x896fb027, 0x4df808af, 0x0147f13d, 0x5d58c79c, - 0xbf4031f1, 0xc9366772, 0xf257fca2, 0x63f7c2e7, 0x84b95111, 0xfb71f3f6, - 0x85799f6f, 0xcaf85ab6, 0x03df85b9, 0x22317afa, 0x18e2e803, 0x513b97d5, - 0x830656df, 0x944bddbe, 0xfc30b6c1, 0xcc0ba457, 0x20beb33a, 0x55663f98, - 0x7a442f9f, 0x6fc30c4d, 0xe214f9fd, 0x09fe8589, 0x627bbf9e, 0x1f5df614, - 0x56ea8230, 0x78833e7f, 0xeb1f7f68, 0x985b7548, 0x30c53771, 0xc84ddb7a, - 0xf7e570d4, 0x0f7671f1, 0xb030fb65, 0x7f02f24d, 0xe1bf5eac, 0x07e532cf, - 0x3eacebd5, 0xe831694c, 0x8f36d56f, 0xc7f3474f, 0xd11f8c0c, 0xc5cdb37f, - 0xeb47b941, 0x0e03c7e9, 0x4b20f43c, 0x2e52e0f9, 0xbc3596b7, 0x13d825f9, - 0x3cc4f5aa, 0xdcb3f69e, 0x4a983cec, 0x2cb33e8b, 0xbfb6028f, 0x25b73bf2, - 0x5c4a5c80, 0x32eccad0, 0xf40d9264, 0x4331c95e, 0x317910be, 0xfa8f4b3d, - 0xe29fe231, 0xe7188beb, 0x82f7c04c, 0x80f504c1, 0x7a45b705, 0xd07c213d, - 0xa5a1e1cc, 0x7eb84f9b, 0x767feda5, 0xfe81196c, 0x739ca23a, 0xdc163e81, - 0xcfc54e76, 0x53ff25ba, 0xad5d028f, 0x649fdab1, 0x433865dd, 0x623bfee8, - 0xc43af3bc, 0x675e4f53, 0xa04cfaf6, 0x87c640df, 0x30eacf60, 0x940a3cd9, - 0xa2cf111b, 0x291a9fdd, 0xe60ecbe3, 0x361e9e97, 0x196be819, 0xde0337b1, - 0x1244b597, 0x033f084f, 0xc3e81805, 0x3f609e7d, 0x3cde3b4b, 0xaddcfc0a, - 0x2c9d23f7, 0x8f105b35, 0x9c7af3ee, 0x74316907, 0x8a7b45f9, 0x8e5123fb, - 0x9e7d60db, 0x9f47c67b, 0x263f491a, 0x7eb8efd2, 0xfdf0edd7, 0xe228c8a1, - 0x4b78fa00, 0xf3a70ef6, 0x832b35ef, 0xeabc2863, 0x460e948d, 0x734e3763, - 0xd243fe88, 0x77fc6aac, 0xcc25f5bc, 0x65d9b967, 0xc2be3904, 0x32a7cf41, - 0x6457c9e0, 0xef8a151b, 0x9185f2f1, 0x45ef8f97, 0x6c7fbf7c, 0x661ff4a4, - 0xe1c7dd1f, 0xa5ea23df, 0x71f27db0, 0x0e7ea906, 0x4a686bd2, 0x943c7ddb, - 0x3e79f3e7, 0x604bd79b, 0x9f7c1df9, 0xeacb9c7c, 0xc5f1c769, 0x3b36fe30, - 0xe015b1d6, 0x8cf9db45, 0x22fb1740, 0x16b7a8bc, 0xfc077e52, 0xea3a6d6d, - 0xedaf94ad, 0xc4d97ac0, 0x4cf58d17, 0x03485728, 0xcfb07be5, 0xcf84148b, - 0x274a52a6, 0xd7b03cb4, 0x04aedb64, 0xa9f02af1, 0x8c7b63c5, 0xc3c9eff4, - 0xd43e9251, 0x61e5428e, 0xa3b30c7b, 0xd27f6118, 0x9e991899, 0x85f10c36, - 0x3e5f2274, 0x608c6ebe, 0xf4fba078, 0x7bd418b5, 0xfba1397d, 0x97c704e5, - 0x0f1f67e0, 0x8ab5e352, 0x5e6de1e3, 0x8d8c516f, 0x007b4fc9, 0x31c7ddf7, - 0x165c7eac, 0x0f424393, 0xcb8703ff, 0xc8549a4d, 0xd5533195, 0x1c4dc5fa, - 0x44c5379f, 0x087ebc09, 0x88f215f3, 0x345f17f2, 0x5e0b0fdd, 0x217f2135, - 0xb0d9031b, 0x63bd68ff, 0x2c0a6e58, 0xe472a58a, 0x18dfaa26, 0x22ddb1f3, - 0x3cefdf68, 0x85d04a3f, 0x3e9c8095, 0x1853d625, 0xe54f7e40, 0x296bae1d, - 0xba437ca1, 0xd037fe34, 0xd694c93a, 0xd8560c87, 0x03a64ef9, 0x208fed02, - 0xe147f40a, 0xb850e7fe, 0xc63bc76b, 0x319fe0e9, 0x96f11e92, 0x9f70f247, - 0x7585ffbd, 0x9cf2ed21, 0x51d1eccd, 0xceb8ffbe, 0xe9fa0175, 0xd42dfdba, - 0x7d198fcb, 0x3096add9, 0x63df46e5, 0xf2c1490f, 0x3d973fc5, 0x762fca46, - 0xe4fd7677, 0xa5eeba66, 0x861db29d, 0x5fe77a5c, 0x7a031ddf, 0x0ec1a775, - 0xdf2a46e7, 0xbcc3d5ef, 0x791e981b, 0x83a6a74c, 0x9f55dfb3, 0x1962d273, - 0x83dea8be, 0x3be09cfa, 0x4adf7e42, 0x5c81577c, 0x461c465f, 0x66b4ff48, - 0xe1420cd5, 0x0eb2c2b7, 0x6be7d1f9, 0xbc1ea1a7, 0x7cb07892, 0x4fe18b59, - 0x4561f2a1, 0xeabf3aab, 0x56fe7561, 0x67df3aaf, 0x2f0f2e7f, 0x32c7a7df, - 0xd94b3e3a, 0xb03fe03e, 0x3d05e4c1, 0x98af5b48, 0x3ca4cbd7, 0x24f813b1, - 0x4760fb95, 0x48e11758, 0x6ebebe04, 0xc5e2696f, 0xe7f57cec, 0x10de21af, - 0x37a8237d, 0x6c6f12e4, 0x63cb7eff, 0xf4238415, 0xe071f0ab, 0x2cb671bc, - 0xc6263afc, 0x10653d0a, 0x8bbe27f6, 0x45e3827e, 0xcfea3ce1, 0x8f98079b, - 0x5d9fdb05, 0x1b9c7e19, 0xa9b1c6fa, 0x7db064e4, 0xfc6b931c, 0xa3e82d1c, - 0x7e127cfe, 0x07a17917, 0x31a5db07, 0xd9a48afd, 0xf906454e, 0x8b63b094, - 0x224270fd, 0x3bb464e6, 0xebcfcfdd, 0x5fb05cf6, 0x083d009f, 0x6514e3f6, - 0x714e9f9f, 0x66c6f7d9, 0xf70687eb, 0x941d768b, 0x43f8ceae, 0x58b2eef8, - 0x6b8e1c6b, 0x57187627, 0xdba2fbd0, 0xe8bb062b, 0x6778ff7c, 0x546ba279, - 0x30f53f28, 0xe85189bf, 0x9c95165f, 0xbc391a25, 0xd42dfdac, 0x95bea8bb, - 0xd3e74c0d, 0xbd23b7bd, 0x04ce24af, 0xbd9ef3a0, 0xff5c33c3, 0xf315fc86, - 0x6259e599, 0x9ba79820, 0x2abfee98, 0x1d599f3e, 0x99d3ef4c, 0xc71c061d, - 0x025b1441, 0x7cd9a51e, 0xd3d4f329, 0xf9be84fc, 0x908e9183, 0x12fe7cf1, - 0x9df0a7b4, 0xd4b253c0, 0x36f30495, 0xbc74b8c1, 0x824de208, 0x5dac69b4, - 0xe4a27481, 0x3079b3d4, 0x0d264f3c, 0x675f5069, 0x9d6ccbf6, 0xd0090674, - 0x985e0fbe, 0xc6fcf2b7, 0x568bbdd9, 0x158b77c0, 0xcf9188f9, 0xe52c4763, - 0x2fe46687, 0xc9b75866, 0xfd1cfbe2, 0x94f53c64, 0x3d8fb829, 0x3bda0943, - 0x02369106, 0xe72c5ae3, 0x1b58b03c, 0x8f9049b1, 0xe0faf5b0, 0x66ce70fc, - 0x2346e8f1, 0x0b19dc9f, 0x677a527c, 0xf285e025, 0x19ff6665, 0xc3ef5ca8, - 0x73e0b773, 0x4d7e7c31, 0x1325cf9c, 0xe2588706, 0xb01ef1c0, 0x40419cae, - 0x49d65984, 0xd44b7ed0, 0x25eff454, 0x7969e000, 0x8abd54ec, 0xd53bc56f, - 0xeab9c4f9, 0x9d4bb27c, 0x3f93d337, 0xcf928be8, 0x16217499, 0xc02359cf, - 0xfce062de, 0xebcf99a2, 0x3d74a408, 0xfd3e71ef, 0xbb13f58d, 0x8eeebcfa, - 0xe3b41231, 0xd0cd9825, 0xde57d53f, 0xcafa658b, 0x97281e27, 0xf3cfc803, - 0xc0f9b626, 0x837cd3ae, 0x7e8bbf64, 0x1b2ab66f, 0x3d5494f4, 0xc76624d3, - 0xf54adbd1, 0x865b7cb4, 0xe689becd, 0x1d7ec1eb, 0xd5b7f30b, 0x49f68d3c, - 0x0247ab13, 0xdc8fe0cd, 0x8366c9b6, 0x81e5717a, 0x8bd046c9, 0x76db1057, - 0xbfbe8612, 0xce86fba2, 0x53c809f7, 0x5e9c48bc, 0xf3290f22, 0x7cbc0d71, - 0xc59dfc07, 0xe18b13f2, 0x65feca5c, 0x3a75e475, 0x90e0eec0, 0x77d62e51, - 0xa16ebde4, 0xcecd65e3, 0xb3bc3b43, 0x0973f99c, 0x3463f7df, 0x905c6afb, - 0x8f3cb1ce, 0x707587e7, 0x899c6ebb, 0x746d6bf9, 0x36666288, 0x8c71fac0, - 0xfc44edfe, 0x5af2fb63, 0xfd07fc12, 0x47fb0795, 0x5829343e, 0x7467dc1c, - 0xbdb37ca8, 0x1bd696a9, 0x87edf7a3, 0xa78e3c7d, 0xa37d3c79, 0xbf9406f4, - 0x628b3a9d, 0x6d7db1d4, 0x861302ce, 0x14b80653, 0x04d07edb, 0x7c904cfd, - 0xbd4c6698, 0x5fa609bf, 0xd147edc5, 0x06ef4649, 0x12a68eba, 0x77b4678a, - 0xd820f9fc, 0x4907e5a5, 0x88e9e001, 0x0739c841, 0x7a15d39e, 0x3a1afb1c, - 0xfd406c98, 0x2a932ffc, 0xd5013bf0, 0xd2bbce8c, 0xbe2116c6, 0x755f2c0f, - 0xe36a3f28, 0xb337e464, 0x6abf32a6, 0x57b35cfd, 0x10ce4092, 0xbbd277e6, - 0xb10a6f32, 0xc43f0897, 0x773206fb, 0x44f39857, 0x4fd31c6d, 0x3b3066ab, - 0xa346fd6f, 0x1d537fca, 0x335eecc7, 0x8c8f26e3, 0xfcc47943, 0x5c7179a7, - 0x46411b6f, 0xe10a9f00, 0xaf504523, 0x81edf4ab, 0x9cba8cf8, 0x8e3999f3, - 0xfdea0302, 0xbe08df9c, 0xf6c41cee, 0xd2423cf3, 0x9367ae81, 0x87ffe406, - 0x7e456f4b, 0x18f11373, 0x951f6f00, 0x310278b1, 0xd55359ef, 0xa71cd27a, - 0x5cf37f3a, 0xf0c51ead, 0xe79dc621, 0x09579752, 0x5aaa783d, 0xfff05e0f, - 0xb9468abe, 0xdd54f89a, 0xe7e02185, 0xc000f660, 0xe873f30b, 0x1bdc6e91, - 0xbebc3f99, 0x388def3d, 0x127767d8, 0x4976cfbe, 0xb2ffd1cb, 0x82115a4b, - 0xaf5ad4ff, 0xb8647204, 0x987dd855, 0x7934e4de, 0xc3df83f7, 0x91128359, - 0x49e3cebc, 0x493c400e, 0xadbe907e, 0x57165665, 0x30b51c41, 0xa45b349f, - 0x16fef41d, 0x65da3e5d, 0x2aaca25b, 0x0da6fa3b, 0x13d4054a, 0x44c558f6, - 0x6e9c6df2, 0xd7779dc2, 0xbafe31c5, 0x71766259, 0x9e333ccf, 0x9cb3e32b, - 0xbc413f2a, 0x9d828e4c, 0x229c6470, 0x63fda3ea, 0x5c95c1b3, 0x44af5340, - 0xd2171197, 0xd11b265e, 0x4fe1a8ae, 0xb476b1f1, 0xce0fc7eb, 0x9cfd3b41, - 0x2fb43c8e, 0xfd844b12, 0xffd8292a, 0xf4dbd99c, 0xdf53a710, 0xdcbf4db1, - 0x7bbba412, 0x8d5cb8e2, 0xaf409124, 0xe7ba767d, 0x7ba7684c, 0x5ffce75c, - 0xa35acba0, 0x2171ed0f, 0x07df8af4, 0x38ab8b92, 0x9cca18bd, 0xf9d056f3, - 0xb46bbcf5, 0x1d19f9c3, 0xe7ffb46d, 0x9da344f7, 0x50455f51, 0x652c6d3e, - 0xec07a47c, 0x9f1d745f, 0xf9e35745, 0x8ad4a360, 0x663ba3f2, 0x6af1d232, - 0x073c01cb, 0x74a56f57, 0x569f2218, 0x6be750ef, 0xdf9e2748, 0x47ee9f6b, - 0x0517c8cf, 0x56ef761f, 0xd4c323b7, 0xcb8f377c, 0x7da77c8b, 0x7d4c0556, - 0x9d8b3dae, 0x8641e9c3, 0x1de8a3ae, 0x2eefb723, 0x008a9db0, 0x7494fb56, - 0xc7adfd31, 0xfb665a7a, 0x2283c99f, 0x6e568e3e, 0xedbd7115, 0xe0bfca3a, - 0xb0f42afc, 0x07f2c222, 0x92721d74, 0x42df382e, 0x7fe84ede, 0x7c084e42, - 0x52109695, 0xa743f742, 0xc9434fe0, 0xed37c050, 0x0489f71f, 0xd8314391, - 0x7dce07bf, 0x9478f8e3, 0xb7203c1e, 0x17b33a3d, 0x6a59abe8, 0x06693940, - 0x9ba69f3d, 0x83ca1724, 0x323daa97, 0x692c7bc0, 0xd6833598, 0x8cee6f1b, - 0x3a513804, 0x3f4a1239, 0xb197c44d, 0x11d1524b, 0xbf457796, 0x848e961d, - 0xc47df33c, 0x74e998f4, 0x054fd0c5, 0x7a687e38, 0xc8e76240, 0xeb1f9629, - 0xbadbfda1, 0x53274869, 0xf30f5789, 0xf1a9b0ab, 0x9d49253f, 0xa3f4a69f, - 0x70c38c0f, 0x1f4e7870, 0x08772ea1, 0xfcd4477e, 0x857c932e, 0xc1f9187a, - 0x5d80efc1, 0x193d7221, 0xd50dfa01, 0x6a1f7144, 0xb8ebe0e9, 0xf26fdd6f, - 0xbf185c75, 0x13b70f49, 0x2bfc4b5f, 0xd3fa969f, 0xeb1bf759, 0x7a10a4e5, - 0x65e2fb14, 0x907f8b03, 0xa9fe655e, 0xe5193312, 0x642afa03, 0x3fb14576, - 0x8cfa05ae, 0x315dd209, 0xcf119eff, 0x19086ce9, 0xa1367402, 0x5327c23d, - 0xfef1e4bc, 0xcbba05ae, 0xe223ea0f, 0xd254d15c, 0xa532be8f, 0x705fd42c, - 0xa47d09df, 0xd26b6a40, 0xb91f0267, 0x1be609a7, 0xe3434f42, 0x512f808b, - 0xda7dc27a, 0xcbaace4f, 0xf026f435, 0x52e5f42e, 0x367480d2, 0xea60a75b, - 0xf2855cab, 0x5b32dcb5, 0xacdfed0f, 0x0936f462, 0xea0b31e8, 0xdca5e9ab, - 0xe96bceac, 0x0ba88e91, 0x9f4b571d, 0x10dbd103, 0x5f2137a0, 0x6f4d2f63, - 0x75bfe3d3, 0x7f1e9b7a, 0xd2d37a11, 0xbb5fe099, 0xa0e56c22, 0x4b57d73f, - 0xde0a0f28, 0xf904d61d, 0xa89975e1, 0xb68aef4f, 0xdf5d7ea3, 0x3b0bcac0, - 0xbdc4321d, 0xe5e3ad64, 0xc872ce99, 0xe5a7afd7, 0x23a2ebb4, 0xd8662e2c, - 0xef3cac9d, 0xadd786ae, 0x587867a0, 0x6f3f97fb, 0xb968a396, 0x2fb799b7, - 0x7c872d6d, 0xff6b0b7d, 0x46a9f819, 0xb79a7c43, 0x7d5fbe09, 0x1d9da66f, - 0x3efe99ab, 0x9777af91, 0xd8ebdcf4, 0x5bb595ae, 0x883cd075, 0xe99ff9e0, - 0x75f1d7e5, 0xd6cadc4e, 0xfae27719, 0x8ba50aa9, 0xea0f0115, 0xb574a76f, - 0x06dfc8c5, 0x4a973f38, 0x4e9069ad, 0x5217eca1, 0x22ded987, 0xcc7e650f, - 0x7b8874ed, 0x45fd99e2, 0xce20fff8, 0x9f4432a0, 0xd99e27b8, 0x84bd4563, - 0xa0018a18, 0xa8ac4787, 0xa4ff0b5f, 0x812221ef, 0x723587bc, 0xbfac243d, - 0x03564a72, 0x865311ea, 0x5fa53f08, 0x9b8e94bf, 0xc98be177, 0x3f43ece1, - 0xe69ee3e2, 0x7a7d1371, 0x075337b2, 0x880bb174, 0xf4800524, 0x7f41afde, - 0x487e05db, 0xa43ca426, 0xf2caf004, 0xbd7fe35b, 0x853c65a9, 0xef41aeaf, - 0x2196a101, 0xccc9dc61, 0x1c1be24e, 0x53fe7fd5, 0xc467c4f4, 0xff362638, - 0x1e544d95, 0x7e31d123, 0x8fe38736, 0xe90abf8c, 0xd3c73677, 0x2a7f05cf, - 0x9fc00520, 0xddbc70e6, 0x347aa664, 0x8356c3f2, 0x133c6f86, 0xcb6a720f, - 0xbabbfa80, 0xaa57c35c, 0xb92bb8f9, 0x092b7ede, 0x4a727ea0, 0x7a7a62f2, - 0x6bdbd30b, 0xbf50472c, 0xe98479e9, 0x8fc4b5ed, 0xbed68ffa, 0x9d53b359, - 0xe7536baf, 0xf9d5dbeb, 0x8e0f1c9e, 0xaea5b3d3, 0xd58aec18, 0x768bbf0f, - 0x5fc16aec, 0x42fe6abc, 0x5fc67115, 0xed06ba1e, 0x6f98df51, 0x6f4f4d3c, - 0xd0b8aac5, 0xfa9c02df, 0xb22f35ec, 0x613714f8, 0xeb1e8276, 0x4e70f988, - 0xa4791a25, 0x9c7927e5, 0x86fb089f, 0x84792fe0, 0x8e7a23c9, 0x8241d77d, - 0xd7ab5c7c, 0xbd73c4f5, 0x84d39f97, 0xfa0793fe, 0x35d3d00f, 0x4164480d, - 0xdb7f6439, 0x9fc88724, 0xc0668579, 0xee99be73, 0x6c978067, 0x545971c9, - 0xca05f0f4, 0x7bcf8199, 0xbd0d72ea, 0x2dd6f388, 0x81665e9c, 0xff8e8527, - 0xe781c97b, 0x32b7c3ba, 0x5963997a, 0xd1faf487, 0xe22f466a, 0xe7e577dc, - 0x4dfc873c, 0x747d79ce, 0x5ef54112, 0x17491e9a, 0x8fe67ce7, 0x1d1897af, - 0xf87d55d4, 0x82cfe818, 0x246e1c2f, 0x3e10faf1, 0x64cd34d1, 0x934a3b06, - 0xaa839d81, 0xbc5c7fa6, 0x38cf8434, 0x13134a22, 0x88ee5940, 0x5d6cfb47, - 0x669c7aa4, 0x7fbbf3a9, 0x4fd2f380, 0xd44ed123, 0x954130fb, 0x70eb77a4, - 0x6b3edb8c, 0x31527e60, 0x7707559f, 0x7ec3f3ee, 0x08ebff5c, 0x359f953d, - 0x5ac5f792, 0xe4c4b65a, 0x6a7186ca, 0xb3233e74, 0x5fa27663, 0xb03b8c57, - 0xf283d65d, 0x931af8d5, 0x106901c3, 0xefd2e1c6, 0xb5fea1d9, 0x4f8c89d1, - 0x2aeb11df, 0xca0f8848, 0xa43f614b, 0xc6a49652, 0xc126fd04, 0x376606f8, - 0x5c710bf9, 0x6361be32, 0xb69e7d88, 0x568f1b0f, 0xf5f8c096, 0x61ce29f7, - 0x1da307de, 0xd39f30e5, 0x9a7b8fdc, 0x474efdfb, 0xcce03f31, 0x752cfabe, - 0xf734f4f1, 0x518e9e13, 0xbd4487fb, 0x8ecc09a5, 0x6cd1b272, 0xbf07a8de, - 0x1c6f313a, 0x21ec4946, 0x93c60353, 0xea78602c, 0x6dbd13d9, 0xa5ff8853, - 0xfbf4a12e, 0xd87f9f30, 0xba43379c, 0x31b8f5bc, 0x23df0ed4, 0x0f77f3b1, - 0x089e97a7, 0xeb718a96, 0x0fbf2a12, 0xe799ec78, 0xe5f63c47, 0x13bc8ac7, - 0xc099effb, 0xfe5f6bf8, 0xb84f2c3b, 0xf5d843dd, 0x69f7f207, 0xd0547bfd, - 0x044073b0, 0xfd6bcfb3, 0x3f050bf3, 0x05f9fee3, 0xec2d1f9c, 0x45827e60, - 0x4a9cd266, 0x247717cb, 0x946e73b2, 0x9fe55b27, 0x515e44f7, 0xcba0863c, - 0x3ecef49e, 0x2123f67f, 0xee3aecfe, 0xeb13accf, 0xdf5eaddb, 0xbadf0903, - 0x8481fb3f, 0x6d6cfe30, 0xa08bc3dc, 0xe20b0c47, 0xc18dad61, 0x2dae42ad, - 0xef6f7b07, 0xe8718272, 0xd65adf6b, 0xb5e0f604, 0x2a0b003f, 0xa7d431f2, - 0x079c38eb, 0x53bc575a, 0x9d951447, 0x4251107d, 0x8aec9fe6, 0x4351e551, - 0x4d03890f, 0xb5514ead, 0xaa186f4f, 0xfd643faa, 0x4cf2aa35, 0x9f2abe4f, - 0xaaad72d5, 0x65ad55fe, 0x87f0fcaa, 0xcfd557af, 0xa3074323, 0x0c90ecfd, - 0xb57221b6, 0x3e554ab7, 0xaa2de772, 0x86919ff6, 0xbd69e3cd, 0x79fe42dd, - 0x8aa39d1c, 0x39ce7183, 0xed554b6d, 0x62b6a49b, 0x9f46f01f, 0xbd6893e4, - 0xcb5f1c15, 0x62ff993b, 0x556afb74, 0xd8a367ff, 0x5fad183d, 0xa32e7696, - 0x912ed61e, 0x7efea447, 0xfb8eeada, 0xa8ee219b, 0xf296bfbf, 0x356eda4d, - 0xfe80bf3d, 0x8e6fd5a6, 0x5d3f7026, 0x7461490a, 0x0b0ba5ad, 0x5bbd7fea, - 0xe627b465, 0xc687ec91, 0xc40cbc23, 0x5fc7f4ab, 0xae76612f, 0x76ada7de, - 0xf559ff88, 0x47a432d6, 0x2e9a9253, 0x5d351422, 0xd3508e44, 0xa6aed585, - 0x6a25c183, 0x3dc2d03a, 0x0ba6a1da, 0x43ffa7e2, 0x2ae02de0, 0x553b1ee0, - 0x785a374d, 0xda0093e7, 0xc95eddd9, 0xfc6123ee, 0x70dbede2, 0x1fd2975d, - 0xf86a89f5, 0x34701c16, 0x2c6e1059, 0x61e84cbe, 0x68ffae26, 0xaf4213fd, - 0x7ae44b89, 0xf847ef15, 0x0f259a17, 0xfe7d51ea, 0x865f12c2, 0xa7f4132f, - 0x44ecc206, 0xf0c4a4ce, 0x3efc4676, 0xc0519d90, 0x2620f675, 0x03886b2f, - 0x882be1ed, 0xc9ddf90b, 0x3ed15bca, 0x63f2cab4, 0xad9ebbf4, 0x35527a62, - 0xbf9f22f1, 0xaa02b8e2, 0xfb109287, 0x528e16ab, 0x02b3e487, 0x20f2e1bf, - 0x79087485, 0x1378c2e0, 0x62e6864a, 0xad471f95, 0x30df82e7, 0xbd097f84, - 0xe0278c57, 0x189af829, 0xe41a44cf, 0x1a17d824, 0x6846473e, 0x3b6a48fd, - 0xe0f3b08d, 0x22fe2160, 0x44265dad, 0xe9916e0f, 0xcc90f238, 0x57f14226, - 0xdda07360, 0xce7488af, 0xe625ef87, 0xc2bd26b6, 0x935713ed, 0x80c4fb3e, - 0xfe12eaf2, 0xc91e59e8, 0x7f6668ff, 0x6bf0b43f, 0xf89fe5d3, 0x5e3c6d03, - 0x55ef1052, 0x078f0f2f, 0xa76fea7a, 0x857d1fb4, 0x02eb23f6, 0xc3f6a1b1, - 0x9206fbbe, 0x1373d71f, 0x424ddc71, 0x693710f4, 0x133f3c9b, 0x4e54c4ec, - 0xecca4146, 0xab5da458, 0x8ed1eb07, 0x012ba3ac, 0x2121afba, 0x60ccda7e, - 0xfee5e639, 0x74371179, 0x42e27d29, 0x3fc78da2, 0xc22778b0, 0x5f38a0f9, - 0x139e740e, 0xcf701471, 0x2221fc16, 0x9139a84e, 0x4973839f, 0xf74ff42e, - 0xb444a6db, 0x29fdd01f, 0xbec7ee85, 0xef2c22b8, 0xeb351fb7, 0xb2147117, - 0x42ed10b5, 0x7bd742cb, 0x7a10f019, 0x3ea86fcb, 0x1234f780, 0x0dd7a615, - 0x0381f63a, 0x553b0b8a, 0x46f59e71, 0x7b01807a, 0x8e3c8bc1, 0xafad4daf, - 0xe3c89b3f, 0xe739f893, 0x181af052, 0x4eee3c1f, 0xf532e3e0, 0x27771130, - 0x7f42f8e0, 0xc151efb8, 0xd8bcefb5, 0xe13df707, 0x72e02ee0, 0x29f3a8ae, - 0x3d6c97c0, 0xeef00092, 0x83ee7288, 0xfd47e9fa, 0x705d24a7, 0x1772155e, - 0xb6f6cbc6, 0xcf3f78cb, 0x5bc5813d, 0xc8c8f7b9, 0x4c3bba1a, 0x6ead37e8, - 0xc2f51d7f, 0x68ca46ae, 0xa6761ea9, 0xbfa90e91, 0x0340bd88, 0x47ce81ef, - 0x681f3d62, 0x75e22fd6, 0x7f7f3ae8, 0x3efc3809, 0xe42a1c1c, 0x9ee18351, - 0x919c5f57, 0x1551903e, 0x75da1f42, 0xb0f4e66c, 0x013cef56, 0x4cef1dfd, - 0x55fd0cdb, 0x53071dc8, 0x24eb3e00, 0xd1357fbc, 0x26cbeec4, 0x2574fbf3, - 0xdc3b06fe, 0xb34a4e37, 0xe1a9fde0, 0xe09d91df, 0xdd78fe17, 0x4f70316d, - 0x5c3ff44c, 0x4efde1d2, 0xe4fb9e42, 0x57f0428e, 0xa26fb02e, 0x162685b9, - 0xddf99197, 0xe5165f48, 0x891aaf23, 0x61a3f619, 0x6bde0368, 0x68cb4409, - 0xc9938cb7, 0x313ba024, 0x561f716f, 0xfafb877c, 0x7c52ef70, 0x2814d89f, - 0x0ed34b58, 0xdd620f4e, 0x0503cb13, 0xfc20960d, 0x16a65c45, 0x3c385b3e, - 0x66c6f1dc, 0xcdbb17d0, 0x52c9fce2, 0x9f23d362, 0xfb666759, 0xe255d8e6, - 0xc2b3edfc, 0xe11dd4b9, 0xf6063c18, 0x7932fbdf, 0xb17f2692, 0xe3470639, - 0xc7d415fa, 0xbb58d9d7, 0xbf071e6e, 0x44b2a3ee, 0x6f8e5f88, 0xa66f1f0a, - 0x5c73b124, 0x8beff72d, 0x1f7ab5ef, 0x42d58dc6, 0xf04176bc, 0x6bc695fb, - 0x01fc788b, 0x27ad10e1, 0xef78d1fa, 0x7ab179dc, 0x0e4bfcaf, 0x3ebebe7b, - 0x0fe22749, 0xcf4defd1, 0x0be3615b, 0xf9d8934b, 0xe807182a, 0x7dc37bc7, - 0x4a7b85f1, 0xce45c913, 0x0ef3eefb, 0x889fdc55, 0x9f9f7737, 0xfd7e7184, - 0x29fda5fa, 0xe15c6096, 0x92dff040, 0x86e5e6c8, 0xd082bf78, 0xdefb0aef, - 0x8f1c4e37, 0xc147f3df, 0xbb45fd3e, 0x7feaf78c, 0x75374871, 0xd779987b, - 0x5db83127, 0x7dc7af13, 0x1c47d233, 0x2f8cc2db, 0x35fb89ea, 0x76aa9ee2, - 0xfccbbb7e, 0x10fe608b, 0xbc6e1c47, 0xc48e9ca5, 0x30c777bc, 0x99f7b87c, - 0xed059ef0, 0x77bde317, 0xe257f8c7, 0xf1a9b0be, 0xd7b73b7c, 0x9fdebeec, - 0xa6bcf781, 0x40c33b31, 0x728de0f4, 0xd8f504fd, 0x4a65699b, 0x06fac53f, - 0xffb216c9, 0x410f452e, 0x7854ebb8, 0x23770fed, 0xfbf457e2, 0x4fbe61f9, - 0xe702c389, 0xbe5c25b7, 0x8351d92d, 0x1f38affa, 0x8cb0fe7d, 0x139f17f1, - 0xbcf927e6, 0xcff3c255, 0xeb211752, 0xf95a1f29, 0x88334164, 0x844925b9, - 0xbec3175c, 0x46e909df, 0xf97c9fb5, 0x87ecfdbd, 0xaeae5424, 0x57280d20, - 0xdd58fe56, 0xfbdc9aae, 0xb49fd067, 0xdce1fbfe, 0xb1d6272e, 0x479e8939, - 0x2629ef40, 0xd61f20c5, 0x3185f93e, 0x1f78194a, 0x777ca69c, 0xaff81e98, - 0x46aed319, 0x48bfa61b, 0x44963c72, 0xc927b7f1, 0x9ed20db5, 0xbdff59f7, - 0x7e4cbdb5, 0xb9438d6c, 0x2efd64d5, 0x087975f2, 0xc0f7ebe3, 0x1e14093b, - 0x97d31326, 0x720d7412, 0x5e2dea14, 0xf1e387a4, 0x6266aa6b, 0x74049ede, - 0x29cbf71f, 0xefce3153, 0x800e9197, 0x4752a6f7, 0x3625d81e, 0x997bb255, - 0xb3f31366, 0xf6317f7b, 0x0c837035, 0x0cbfbb6b, 0x8eb6c1ce, 0xf7b03efd, - 0x7cfee8b4, 0x5a57e210, 0x8bf163ae, 0xfeff3a09, 0xe2f190d4, 0xe049bd23, - 0x691f8f87, 0x388f38c4, 0x21af34b9, 0xcdca5e24, 0x9edbd171, 0x1ec27685, - 0xb61bb083, 0xa8bde045, 0x8183a1da, 0x18435c8f, 0x1bdc459e, 0xdf5421cc, - 0x8470a2ed, 0xbf914ba0, 0x19f24da6, 0x12fdf0a2, 0xded4e3f4, 0x0f984be5, - 0x7ae7ea72, 0xf98983f4, 0x5c9abdc5, 0x212efe06, 0x364be69f, 0xfae34766, - 0xfe223cfc, 0x5cd97f31, 0xb8f3274e, 0x923f3f1e, 0xb1297bc1, 0x5bbb4067, - 0x474a24cc, 0xf2fcd4b7, 0x675c22b6, 0xf41a218d, 0x19f7e105, 0x6f08cf58, - 0x653f72ff, 0xa58df765, 0x72743640, 0x62e7c286, 0xf9c030fb, 0xdd9b3bb2, - 0x88c323bb, 0xee8cfc03, 0x81b7c37d, 0x8834c27d, 0x7f29aff9, 0xa3e49732, - 0x73866d5e, 0x44afadd4, 0x2f22f8f0, 0xc8ec4fbf, 0xfa9cf883, 0x8c7cb4aa, - 0xc01a3913, 0x0dba3777, 0xc7dc0cfe, 0x5448ef94, 0xf2da0e36, 0xb87a19fd, - 0xf54299af, 0xd92f9a35, 0x0fcb2f72, 0xd1d4aff5, 0x4f2d92fc, 0xfdd3d0cd, - 0x7fc6bee1, 0x5b35f20a, 0xbe7cb176, 0xf34ca57f, 0x655e5bcd, 0x4960e1f5, - 0x2dc1ec09, 0x68786707, 0xb9a267ff, 0xf1fbb7bc, 0xe5fbb59e, 0x3b50bae1, - 0xe332636b, 0x9db8675b, 0x59264cf8, 0x1ef0055c, 0xb2febe11, 0x5a0f1d64, - 0xac54c569, 0x4927b457, 0xf325dbe1, 0xf7e56e71, 0x924627a3, 0xb7e60896, - 0x3c5144f3, 0x8e18e81c, 0x93afc77e, 0x6e9e9862, 0x38fbe3f3, 0x4f011fa2, - 0x77189fd1, 0xe067c835, 0xac789acb, 0x3f8664ec, 0x1c46ce3a, 0xdd839867, - 0xcb4aae2b, 0xbc51fc03, 0xf4de39e9, 0x8dbbfcec, 0x1bf68fcd, 0xa0728b9d, - 0x07f8ec00, 0x33f5a2be, 0xd2d6f383, 0x93324149, 0x3136b72f, 0x3a206b7f, - 0x6269e90b, 0xa5677f24, 0x668ebd50, 0xe4c6870e, 0x466f7e68, 0xc2512bc0, - 0x1c389a71, 0xcf78fcd3, 0x5dd74af2, 0x775a1ff1, 0xf01cbe08, 0xf681ca5e, - 0xf5b3b7ab, 0xcd7bf0c4, 0xd4188cfe, 0xf557eef7, 0xa6836677, 0xb8c1097d, - 0x164c7736, 0x8227bfb6, 0xd93bf198, 0x332ed7de, 0xa0ade997, 0x2c778acf, - 0x123ae788, 0x7bec47ea, 0xc58da2af, 0x39d70667, 0xd3af90a3, 0x6369d7c6, - 0xe8aaf4eb, 0x64091c95, 0xa7f6b6cc, 0xf7f83ee3, 0x9f2a37f5, 0xe7daa7f7, - 0x7d83fae1, 0xd65e103d, 0xd6f93a73, 0xa9e622f0, 0x9c1f6781, 0xf013f335, - 0xed8dfd84, 0x52e9a946, 0x5926b3cc, 0xfb35939c, 0x8e1bf33b, 0xd5daca57, - 0xb9e2cedd, 0xeba6a289, 0x3a99ddba, 0xed102b88, 0x1027c16a, 0x3dffb41f, - 0x89edcc9a, 0x806d2469, 0x93c7c4f8, 0x0ddac28b, 0x9cf6bbf1, 0xe2cd13d8, - 0x8af6b5d5, 0x277b789e, 0x9cf4afdc, 0x8c0aef63, 0xc06fd8d3, 0x259cf4cf, - 0x5f282ed8, 0x9c73f9d4, 0x3fb7f63f, 0x7e603205, 0xe7b2a685, 0x47d53b15, - 0x7e431cb6, 0xecb8385d, 0x7f9a4cb6, 0xc88ff935, 0xcb530bcf, 0xfca4c8be, - 0x9fb27f7c, 0x7d9647e5, 0x5bf21431, 0x44feacfc, 0xefc0f3c7, 0x633fc789, - 0xaf507252, 0x41592d78, 0x3ae5c9b8, 0x02647402, 0xc7ae8625, 0xe309aaf4, - 0x075c04f6, 0xba4d0b4a, 0x6ff77086, 0x07a3eedf, 0x812957e6, 0xf3b0153f, - 0x5f803b71, 0xf403b2af, 0xdf7bb144, 0x8eff7b3d, 0x483e5df7, 0x1e027576, - 0x16bb23ea, 0x5dfcd265, 0x1fa09f91, 0x3dd0724f, 0xc515f601, 0xf9d01646, - 0x9c9b5d4a, 0xd5913fa0, 0xe11eb376, 0x745eedca, 0xfc28178d, 0xf3f7d95e, - 0x61b2a5ef, 0xb18f309c, 0xefd40f9c, 0xe06ff2fb, 0x633fadf7, 0x7af983b1, - 0xdb96c76c, 0xdb1aff40, 0x4c97f6f1, 0x39fbb30e, 0xc163de62, 0x97bf49ae, - 0xfe709bb4, 0x5eae3b63, 0xfdc7f501, 0xe80b23b6, 0x5f31c264, 0x9e85b013, - 0xaaa52fbd, 0xcf90e5ee, 0x39d71a2e, 0xc04ddfa0, 0x54aa53e3, 0xf478460d, - 0x857c7832, 0xf1dd67f1, 0x68fd9b87, 0x7fdf54fc, 0xfa3afaa2, 0x20c97b91, - 0xc433f83b, 0xbdad7a7d, 0x5d2568f4, 0x213efd1f, 0xa2106740, 0x6f3c4f4f, - 0x98248ca6, 0xaad1252f, 0x5939b97c, 0x96c2bf55, 0x929f2aa9, 0x7caab574, - 0xcaa7929a, 0x56311f4f, 0x7b06ff55, 0x637f2aa9, 0xfd5534c9, 0x2aa5474a, - 0x536be79f, 0xd4382fd5, 0x423f2eae, 0xfe43c064, 0x90ebfb51, 0xa0749d16, - 0x74f8b5d9, 0x8e90ebc3, 0x87030bfd, 0xed7c5ed6, 0xe1d7b6f9, 0x6b17b0bb, - 0xfb0933ef, 0xc5b2cdf1, 0x276f0c6b, 0x0567d24e, 0x75901fdf, 0x18d33eec, - 0x94eaebab, 0xa67de0a2, 0xa62f6089, 0x7c58a848, 0x00e347ee, 0x3d980b4f, - 0x062028ed, 0x68adbee3, 0x686a3c87, 0x2c0fe678, 0xf81d200e, 0x5cc084de, - 0x9e27bad5, 0x5dd6a977, 0xe0d56e4a, 0x5f2a8d69, 0x555dbb61, 0x06d24a7f, - 0xe534f955, 0xdd3c1a07, 0x60dfcaaf, 0xd3c1a2df, 0x7e9e0d36, 0xf4172aae, - 0x5aedc1dd, 0x451ec0fb, 0xcefef1d3, 0x75c3c072, 0x8f8803a7, 0x72d6ce92, - 0x47b5d3c0, 0x855f10db, 0xb039673e, 0x0d43e2cb, 0xa3ea43af, 0xf76831e7, - 0xa612635a, 0xb4151a07, 0x1c6c1d6b, 0x46a1e981, 0x75ff7e3b, 0xefa60963, - 0x7d303a34, 0xa62a71af, 0x4c4e8d9d, 0xb0db1adb, 0xed8d73fe, 0xdb162ecc, - 0x3a45def7, 0x75ba07d8, 0x8278377e, 0x77923f17, 0xeecbf003, 0xc86efe41, - 0x37ec45df, 0x25f9a24c, 0xbee844c0, 0x374f29fc, 0x80023aa4, 0xca1c3757, - 0x18f1828a, 0x1e473a6d, 0xa477e1e8, 0x3ea1f84c, 0x37bb909d, 0xd16c9338, - 0x79a66f2c, 0xb3c63644, 0x83a1f84d, 0x2033d712, 0x33a9d04a, 0xf7c806e1, - 0x7772b044, 0x401b84ca, 0xfec6ff0f, 0xff3f4773, 0x61291df9, 0x9ccfe7fc, - 0xd760ac56, 0x70d5fc39, 0x30e3c02b, 0x48396fb7, 0x4d09619e, 0x0679f54b, - 0x0747b390, 0x80f0b7b8, 0xe009b4ae, 0xcfb3a6d0, 0xebef78c1, 0xb7e8040d, - 0x5fe7624a, 0xca95cf51, 0x0dcf41e4, 0x1d4f3c26, 0x605639d1, 0x7814995c, - 0x3dbce00c, 0xdee112a5, 0x00640d63, 0x4e29bcfc, 0x3c0f8f96, 0xf243d926, - 0x079f0606, 0xb6fc6e52, 0x3858f3e1, 0x62913cf8, 0xcfb6fa63, 0x807a0e91, - 0x74a91fc8, 0x3e7ec1d4, 0x0ab8ea52, 0x4d38cfef, 0xad3aff6c, 0x3ed0abde, - 0x139a28e4, 0x9219e762, 0xd1f7606a, 0xd82262e1, 0x71916f3b, 0x39e16b9f, - 0x7be99521, 0xce702748, 0xe789179c, 0xf63a2382, 0xfeb6819e, 0xb3d70e02, - 0xe3dbc283, 0xbd32a616, 0xdd566ca2, 0xfed02f33, 0x6045d67a, 0xe1ce3dd7, - 0x34f58fa8, 0x342ae850, 0x8e70dd3d, 0x1cec9b95, 0x9dbfe824, 0xf2d17f0f, - 0xfb6e3a67, 0xfd68efeb, 0xda45d64f, 0xaed88651, 0xc2ddf841, 0x358c2f2b, - 0xb0b4fea3, 0xe40cbd2a, 0x07ee7ce2, 0x27d5645c, 0x1f503ba0, 0x1727846d, - 0x9af25b97, 0xcac90429, 0x3c234ab8, 0xb69d5525, 0xd5d219a6, 0xc237eec3, - 0xa3b52913, 0x1a833576, 0x70b7475b, 0xff3ff211, 0x5e748dbb, 0x0acbd78b, - 0xfb89cf3b, 0x145735ae, 0xf7e822cf, 0xa23b8f08, 0xeaf3c040, 0xd16f0e22, - 0xd787116e, 0x3fae1489, 0x0b9c90e6, 0x67d63f6a, 0x0b5def40, 0xc01ecddf, - 0xe72ea0cf, 0x4607e3fa, 0xfdf6ae36, 0xe2ee3112, 0x3afe7654, 0x0994a462, - 0x4c2de4fa, 0xfdcee40e, 0xba22aee2, 0x9b0edcfe, 0x1615e30e, 0x7800bdd7, - 0x78e76de8, 0xd8769034, 0x4b3cb34f, 0x221df93e, 0x8f754e26, 0xd2f252f7, - 0x0f2b69de, 0x7e859795, 0xbca87967, 0x96b4092c, 0xf2145c83, 0x7d4ff851, - 0x2f9cd58d, 0x3d3f2037, 0xf31eb8d0, 0x983d1b07, 0xe16c6a1e, 0xcb15b97c, - 0x987c69df, 0xe72f65f3, 0x7bf13bcb, 0x4c5ce347, 0x58ba35f7, 0x9519ca3e, - 0xecc4fb0a, 0x37c4f8c2, 0xf80898b6, 0x4c3b7ae7, 0x77419f18, 0xc68f63c4, - 0x0991fc41, 0xe36a71ef, 0xbe7cb490, 0xf7761e8f, 0x0525377b, 0x1f8be9c6, - 0xc8717d02, 0x9874f4c0, 0x4be05628, 0xe4fe8ff9, 0x0fafd006, 0xf4158a2b, - 0xcdd482e9, 0xac50ef2c, 0x7c2f9a06, 0x8a5de794, 0x22ac04d5, 0x5be421f5, - 0x358a3d87, 0x1f8be682, 0x7b95887d, 0xc7f33a09, 0x06f5ba3d, 0x2259f00f, - 0x51fd801d, 0x449cce6e, 0xd79505c5, 0x5f6007a5, 0x325a494c, 0xcec5f609, - 0x63e90514, 0x00e1b29a, 0xd88fa7e4, 0xfaab87a6, 0x46de4b0e, 0x57165768, - 0x937687a9, 0x846cd6d2, 0xdd879376, 0x376d0faf, 0x8daed475, 0xdf619f90, - 0x74fd07a6, 0xf8b1f027, 0x2f223f60, 0x169f05ca, 0x3ba37271, 0x720f289c, - 0x0f289ddb, 0x66ca5c04, 0xf60dde57, 0xc976facf, 0x663cc126, 0x0a417d4b, - 0x86e89310, 0xbf2949f7, 0x97f53ebe, 0x5db40dd6, 0xc5afe43d, 0x7c370ffc, - 0xa6fbfcbb, 0xfbfc30d4, 0x41dfbe43, 0xfbdc43de, 0x0ef64687, 0x2e1c33cc, - 0xac4b1df5, 0x712a8ef8, 0x7acf4159, 0x97f3cb9e, 0x9fe5a520, 0x7f8bb4f1, - 0x70e7407f, 0x52ab38c1, 0x3fb21fb9, 0x6549a87f, 0x8f735ffb, 0xce728064, - 0x6d52ea1f, 0xea3cf7aa, 0x76bfbb08, 0x6d3b38a9, 0xee36b89c, 0x3b693564, - 0x1fecc8e8, 0xf70b526f, 0xc7fab2dc, 0x6a788b7f, 0xdf781c6d, 0xe3106ab9, - 0xd78173a7, 0x496eba50, 0xde4f901d, 0xdc38097b, 0xfd0e0e1b, 0x9c5843d6, - 0x2438bf7b, 0x5daeef1e, 0xb3c57117, 0xfc798d77, 0x827d76bb, 0xafaffa2e, - 0xcf5fc195, 0xbbf54fe0, 0x157e60c7, 0xec04ad8b, 0xe7fca156, 0x3fe11777, - 0x6df67e5a, 0x179bc9f1, 0x65bbe1d7, 0xf3d8f861, 0xb898f8e1, 0x854dafcf, - 0xf3f70a9e, 0xde121e20, 0x7e738239, 0x1f6ba265, 0x1653d3f4, 0xce0e9bf8, - 0xddec71a1, 0xaed183f0, 0x325df0fd, 0x1106b8b2, 0xe75a7c97, 0x6de815f9, - 0x19fa3def, 0x106eb3f2, 0xbc8f7416, 0x97a0f341, 0x7ce6c3fd, 0x4647e013, - 0xefa18df8, 0x7f140f8f, 0xff2e1bfb, 0xdf6ca7fa, 0x9ed43889, 0xa0665f6d, - 0xfb12eefd, 0x54782062, 0x70fde3c8, 0x24b7a43f, 0x9767e512, 0xdef07c44, - 0x02695771, 0xe95d2dea, 0xdfa43d46, 0x2bb8b9f6, 0xd7fb1b3d, 0x92bb8f9e, - 0xdc6ccc4b, 0x7d2153c9, 0x2154f92f, 0xf0dfbdc8, 0xa376cbf8, 0xb03de0a7, - 0x408d8f0f, 0x928dfeff, 0xa0e010bf, 0xbd77573d, 0xc94ca0b5, 0xa6be7fed, - 0xeb049beb, 0xbbae3dab, 0xe95dbe1b, 0xfd76bb79, 0xb9c408df, 0x15ff5b8f, - 0xaeeff781, 0x19ddfcfc, 0x5e80ab93, 0x12026ae1, 0xf545d319, 0x54bf9a09, - 0x8939d6fc, 0x4333d39e, 0x6f25e5ce, 0x9e2e38b3, 0xfde7cf6a, 0xed5c09de, - 0x960dc751, 0x5e308afa, 0xe147f645, 0x7b1d60bd, 0x73c4436f, 0xf3cfc9bd, - 0x243ebcf4, 0x9d70ed0d, 0xfaf3aa19, 0xfa2d1f1d, 0x0881f21e, 0xa678ef8c, - 0xcc3c44fd, 0xf19d8ff5, 0x0945793f, 0xedbd77d2, 0x9df4246f, 0xbdf5dac0, - 0x86d77caa, 0x7056fbe0, 0x5ff6ab1f, 0x2a25ca32, 0x4f105ac7, 0xdae335e4, - 0xda4af910, 0xef07dcfe, 0x55df94d1, 0xbe50c002, 0xd074cf36, 0x3cfc9576, - 0x8de44844, 0x92aeda0e, 0x67891f9f, 0xe78f2b25, 0xb09f3df5, 0xff28ba7c, - 0x7fac4ce3, 0x1c6fe895, 0x79164f2b, 0x22d5dfde, 0x9623789f, 0x25f68a67, - 0xc6239f2c, 0xaded64af, 0xade4feac, 0x7a099cff, 0x33f7e08d, 0xe09cb8d2, - 0xfe5152ef, 0xba2b4cef, 0xba8ebc68, 0xf107cb9c, 0x1dc5550e, 0x85df22d3, - 0x6126dc7d, 0x9ded61ec, 0x9fe7b406, 0x0dcb698d, 0xe22f2fbd, 0x56e59c7a, - 0x7baaf38c, 0x9976f871, 0x1e813bc7, 0xe9fb9cb3, 0xfa0b642b, 0x65ef7a61, - 0x3d207e7c, 0x97fae570, 0x57ecf855, 0x46d3dfce, 0xef1d2547, 0xf1130fdc, - 0xd619027e, 0xee02f189, 0x27c44934, 0x116abde0, 0x45971757, 0x8e7e701c, - 0xbd82297b, 0x13b27aa7, 0x97caeff9, 0x6ebb7d98, 0xef28ebcb, 0xda0aca96, - 0xea1ebe97, 0xe9f0075a, 0x2f77b2b6, 0x87dfae57, 0xc531f4fb, 0x8160fdc6, - 0xbcf0a151, 0x3dfc3fb3, 0x8517f169, 0x3ffcbabf, 0x5dad7f0c, 0x5fd7dc5d, - 0x7ff1857d, 0x07e656dd, 0xfd3c73b6, 0x7314a749, 0xf0023d78, 0x33a2b73a, - 0x20865a3b, 0x778c4eee, 0x29df90ab, 0x6f56f382, 0xde009583, 0xdccea5bb, - 0x5fe0c30f, 0x9f38ae7b, 0x69715441, 0xf7c3fb3b, 0xf7d04be9, 0xfa4dffd3, - 0x8dfbd44e, 0x1f1bf076, 0x15e5ef65, 0x18c9fe77, 0x4ef41f1a, 0x0f073b1a, - 0x317e676e, 0x2c171711, 0x713c32b7, 0xd55d53ff, 0xffc1e33b, 0xc4c3f624, - 0xfe06d248, 0x76d74a04, 0xa076d74e, 0x41bf416b, 0x176d143f, 0xfa41be06, - 0x912e2c25, 0xfdb7e9c3, 0x25e1fae1, 0x7fe1fae0, 0xa9bbae13, 0xdbfe8c3e, - 0x4ed02217, 0x3ff385a3, 0xbc055c38, 0x0e2fd323, 0xfff4c8e7, 0xd3239c0c, - 0x439d9515, 0xf9207bc0, 0x988fc5a4, 0x5a7d9877, 0xe9f64df4, 0x4f9c1923, - 0x8f18fde9, 0x4c7bc5ab, 0x27bc3f7a, 0xef1c5fa4, 0x30fff2ea, 0xd370b5de, - 0x9fdcb5a6, 0x985efdab, 0xfbbf203e, 0x7ff8e056, 0xb0b04fcd, 0x7caabf61, - 0x54b7faf1, 0xef3c4be5, 0x415f965f, 0x5bfffbd8, 0x57e105fe, 0x2afcf998, - 0xb51ff81d, 0xc43741f2, 0xc7a023f9, 0x7afe5f1b, 0xf93087d4, 0xb78c6cea, - 0xe5af8dba, 0xff7ff18b, 0xbe947be4, 0xf66068be, 0x3ffb63d6, 0xfd392837, - 0x79e165e9, 0xd084711d, 0xeff5c2d9, 0x5acf401b, 0x54fbd848, 0xa60ffada, - 0xc6307b33, 0x30be5149, 0x710c4cd7, 0x9dcc1f94, 0xcf4beecb, 0x0c630705, - 0x2d173ea6, 0x3e27a99f, 0xd2bb8f78, 0xd099f7a2, 0xffbea9ef, 0x75efe26e, - 0xd558b893, 0x21d9783d, 0x9cdf9c63, 0xbd2fe612, 0xf786d2c5, 0xba1de787, - 0x60f7dceb, 0x14f46f2f, 0x7177b8b1, 0xbaf7f0ff, 0x3e83f12b, 0x9c2a7a08, - 0x5fee24fb, 0xff40635f, 0x2addb6ba, 0xca669fbe, 0xd9a38b12, 0xc533e2c3, - 0x3beba4fe, 0xf767ca64, 0x48f7e060, 0xbe0c1b2a, 0x67a0b9e1, 0xbb3d47ef, - 0x2e4364be, 0x927eafe0, 0x1b94dc74, 0xafd4ef3c, 0xd7b60bff, 0x7a6d67f2, - 0x4fd5f6b9, 0xbd210f1a, 0xb1d17388, 0xb5e61f46, 0x1305d6f6, 0x93fd17ff, - 0x6de2ff63, 0x57dc7482, 0xd0c70f8e, 0x3b1bfb75, 0x827b2dff, 0xbb0823b0, - 0x214ed682, 0xbf7888f8, 0xe36e97d2, 0xa296b2ef, 0x59e883df, 0xc1edf82a, - 0xd7f9fcfe, 0x27d717e9, 0x61ffe5d5, 0xf4b97cfe, 0xe4c49b5f, 0x8fee96aa, - 0xed0cfd56, 0xb5be82cf, 0x6200bff4, 0x0bf8e852, 0x27bc25ea, 0xab55773e, - 0xcdf49c61, 0xe5b57de9, 0x9b830664, 0xb15c2e46, 0x3c78503c, 0x0be78c87, - 0x0ec6bc93, 0x87810f76, 0xefd5d3af, 0x48bc5303, 0xab971719, 0xfafff2ea, - 0xa2e4e039, 0x8917266f, 0xcb489f4a, 0xe56eb7e8, 0xfe56eb12, 0xb90eeb9b, - 0xd648b4a7, 0x40e3ef05, 0x81c435fc, 0xfdd978f6, 0x56ccead4, 0x5203ddfc, - 0x7e028812, 0x995eeb77, 0xde8e9efd, 0x790e4fa1, 0xf88bad3f, 0x5c7a003e, - 0x3bbd9e35, 0x769b8da4, 0xd5ea78f3, 0xbf78dd96, 0x9a0efb51, 0xf376cb88, - 0xa1efb4fe, 0x9de2f689, 0x687bed03, 0x1c783253, 0x67c93e76, 0xe7172971, - 0xcf20dda3, 0xdd35fc43, 0x5da2355f, 0x4ac7c6e1, 0x05a4f3ee, 0xa32732f1, - 0x9799df1f, 0xa3be7171, 0xd32fff2e, 0x81dd6caf, 0x94aed8f7, 0x3a64477e, - 0x827f40dc, 0x9bf1f72f, 0x6fc84c57, 0x3df33bc4, 0xf7c19e6b, 0x24be7a87, - 0xd4bd97e8, 0xbb13e33b, 0x09c435d8, 0x564dbd27, 0xc771d78a, 0x1baf683c, - 0xf785c47b, 0xe3bcc776, 0x927f8880, 0xc329c077, 0x233e85bc, 0xff209bf4, - 0x78d9f7e2, 0xf2e5d59c, 0x37f52bb9, 0x8cfca7fe, 0xb75d5ee2, 0xbf0457c1, - 0x13d9e0e7, 0xa103bf81, 0x1993ff9d, 0x93be8bba, 0x7ae511dc, 0x8b34f012, - 0x5ef109cb, 0xdecc8572, 0x94edef49, 0xeeb85ed1, 0xabfb7e7f, 0xdb4b9547, - 0xbd6dea15, 0x2265cf61, 0x7bb1d7ad, 0x0ae5f92d, 0x79c249c6, 0xc287ec0d, - 0x7fada89e, 0x297b294a, 0xe35bed03, 0xdeda3df1, 0x067cd987, 0xfafd57c2, - 0x603f8e00, 0x7ebf1f39, 0xf42d916f, 0x19f3959d, 0xdb43e77d, 0xdf107329, - 0xff174b97, 0x332dced7, 0xa891e265, 0xbc91cd7c, 0x4c25ef4c, 0x3a405dff, - 0x02445d31, 0xbb08ba98, 0xd894b0cf, 0x9c4e5d31, 0x5c55ae98, 0x3718195d, - 0xf8c04814, 0x39ff17d3, 0xdce6e80a, 0x215ae375, 0xf2dbf146, 0xbef56923, - 0xbd853c9e, 0x3fc2f497, 0xd9f4077f, 0xcb863ff3, 0xa2471be2, 0x1848641c, - 0xa57bd33f, 0x54d7bb32, 0x17dc5df2, 0x325dfde2, 0x96e1f989, 0xfee26627, - 0xc4cdf209, 0x826f826d, 0xb8e7393f, 0xdcc3c58e, 0xc67be12a, 0x6e1d7eed, - 0x99159cb1, 0xb9ddf85e, 0x3cacddf6, 0x2bda2ea7, 0xd8ce7cd1, 0x26be5608, - 0x4ff70bda, 0xee3f1216, 0xfb70c5cb, 0x4bfb8644, 0xdf8a2f8c, 0x8227a00b, - 0xbf6d12a1, 0xeeccc3a2, 0x30ff1051, 0x70b9ffe0, 0x4f170a7e, 0xf1f18433, - 0xbf1943d1, 0xb6a65d1f, 0xe5e50c87, 0xdf6529f7, 0x0cb47807, 0x810d6471, - 0x9b9d31fa, 0x3b042c1e, 0x9f808e90, 0xb7b1b3e6, 0xb4535fa3, 0x1b29517b, - 0x959ff501, 0x67bfbc58, 0x4c6fbf2f, 0xfea10902, 0x794ab5b1, 0x1a2bd42e, - 0x40d3f8c2, 0x51df8570, 0x2f398674, 0xd1d1f88a, 0xbb436670, 0xd277c13c, - 0x7e58959e, 0x6f5be3f2, 0x5f4168dc, 0xe3f40782, 0x44d71517, 0x91b46f18, - 0xffcc0b10, 0x1b7efca7, 0xbb00c869, 0x4cc7aae8, 0x3e2fd03a, 0xee18e2a2, - 0x9e81fcf7, 0x98fd21b7, 0xfd219b9e, 0x43373d23, 0x9b9e9c7a, 0xcf413d21, - 0x38ae90cd, 0xccc7876f, 0x8e2189c9, 0xf0bfd0b9, 0x5be769f7, 0xd7f18439, - 0x1af7f1be, 0x14fbfc71, 0x0fb7c217, 0xfe087bdf, 0xd1b3edde, 0x8b989481, - 0xdecf5bd0, 0x749fa3bf, 0xff08b820, 0x0a7cb6a3, 0x6eee6bc7, 0xdcffca3d, - 0xcad47f76, 0x872b7a90, 0xce7db118, 0xa0a3270b, 0x1f5b6eff, 0x5d121d7c, - 0xcb1d4cf2, 0xb9fc7caf, 0x828e371b, 0x0fbe3bf9, 0xf9f74174, 0xdb73486a, - 0xfc00fb7f, 0x1fed2a5e, 0xa47a24e3, 0x2f3c66c0, 0x85a1d668, 0xb3d75883, - 0xa09b9dd1, 0x0c2fb3fd, 0xbe509585, 0x01bed843, 0xadc2923a, 0xe7ae0377, - 0x10a05346, 0x78dd0bee, 0xa71b0e41, 0x8a529f7d, 0x7a064e70, 0xcaddfe43, - 0x025f4653, 0x7f74df6f, 0xe223fb6b, 0xa5e015fd, 0xafa5c80a, 0xac2f40a2, - 0xed04f1e4, 0x06fd87bb, 0x2439e9d6, 0xdabdf813, 0xfdea31d1, 0x49e38bb7, - 0x8d7b39a4, 0xb3d7c04e, 0x830d4f7b, 0x7e2989f7, 0xc57bc186, 0x455c86db, - 0x31ef7f42, 0x8f97ec67, 0xf587183c, 0xe769f7f1, 0x10156d91, 0xbcdf3337, - 0xd2580dff, 0x0af1db42, 0x9c599b88, 0x74841d24, 0x19399289, 0x7dc465e2, - 0x4a236583, 0x9a96c20f, 0x7d44af61, 0x4c9814ae, 0x37287c88, 0xd847f247, - 0x558a3c85, 0xa524a7e5, 0x534feaaa, 0xd3e554b2, 0x95548c47, 0xd867718b, - 0x46f5540b, 0xc28604c7, 0x83ae8e79, 0xa4ff03bd, 0x3986f18c, 0x7eb91c2f, - 0x7ccfcd24, 0x43be0e6a, 0x9f2f2cf9, 0x17b95cf9, 0xe143d1f0, 0xd50aa469, - 0x6c1f92e9, 0xd33a107e, 0xf76a179c, 0xa1d0713e, 0xe179c65c, 0x8184e712, - 0xed164fde, 0xca04e7b5, 0xbe001f37, 0xd9c5fa39, 0x3edbf036, 0x14cbf63b, - 0xcdfd4788, 0x0caefe10, 0x440c3f3f, 0x43fb7d37, 0xbcdd1852, 0xc3279325, - 0xf2440dd0, 0xe9643a32, 0x7eecc3cc, 0xb5f295de, 0xa1af814f, 0x4243c0bd, - 0x6b577f7f, 0xb46d1bdf, 0xb036e6ff, 0xc32bbd47, 0x7bbea50d, 0x6fe12b93, - 0x64ef4839, 0x93bbb6f9, 0x07bbf0e3, 0xb73761f4, 0xb8520df7, 0xffbb553e, - 0x60c2e4ee, 0x5c775939, 0x29dc9f55, 0x1bf2ab35, 0x7bf9d533, 0xdb439b4b, - 0xad8fa40f, 0xd189787c, 0x6ef70395, 0x37bfb0a5, 0xfff3e62c, 0xd5800901, - 0x00800020, 0x00000000, 0x00088b1f, 0x00000000, 0x19b5ff00, 0x6554540b, - 0xcef7bbfa, 0x7860190b, 0x77421028, 0x840a4498, 0xb0285789, 0xd71ea08d, - 0x8f4c1ada, 0xe5935654, 0xe04d7903, 0xe3d8f4b6, 0xb68fad18, 0x695b6d07, - 0x9656356b, 0xb139e4e7, 0x36254644, 0xeb495bae, 0x66a254d6, 0x42d899e4, - 0x7a26704c, 0xf75a9d6d, 0x5efffefb, 0x5b602e67, 0xe74ed69d, 0xffffef9f, - 0x27ef7ffb, 0x70ca1490, 0xf60800ce, 0x9970ccac, 0xd6f70601, 0x8018e41a, - 0xe2eff4d3, 0xf9b8daf0, 0xcf03837a, 0x3a380057, 0x01cfe3cc, 0x031401d6, - 0x7b81295c, 0x5914f3a2, 0xff60e760, 0x2fbdf165, 0x00490801, 0xde8d179e, - 0xe38456ed, 0x6e67065c, 0xf08d9ef8, 0xd918064e, 0xbfefff72, 0x25f5c22a, - 0x8c0ee3b0, 0xbd0d43c4, 0x5c75d79b, 0x9fcd7114, 0x77d1d704, 0x98809679, - 0x55706b80, 0x00e207b4, 0x3c636a9a, 0x679e3e62, 0x2e990e86, 0xa6f1c804, - 0x01529bb5, 0xc0228a8e, 0x78074439, 0xe3ef14a0, 0x245f041b, 0xa4ef39a7, - 0x67c8b9df, 0xe7c72fcc, 0x35b03245, 0xe99432bf, 0x7ed77bc6, 0xbf1ce787, - 0xce91a203, 0x8f4a803f, 0x2e5c4c03, 0x19bdbb04, 0x3f233ffe, 0x1812bd4d, - 0xf0619f90, 0x605aba1d, 0x25a9ccd7, 0xa7e92b00, 0x061dfb4c, 0x196fd890, - 0xb2957f70, 0xe57cb2bf, 0xf08b10a5, 0x2040fd56, 0xa70fbd9b, 0x7fd5fff1, - 0xf198376f, 0xda53f57c, 0x530f427d, 0xfbe52f90, 0x77b3f03a, 0x3de277eb, - 0x235ef853, 0x8499fddc, 0x697636ef, 0xc7245fbf, 0xe0e60d24, 0x3828028f, - 0x916db12d, 0xf1366bde, 0xdf4ae6f7, 0xea097bbd, 0xc925e9b1, 0xd1adc46e, - 0x00e2d3dd, 0xa83983f9, 0xf2f1d4e4, 0x7a8cda6b, 0xa7c30c2a, 0xbdf34b76, - 0xca175f74, 0x5e319ea8, 0xe2c960ce, 0x5f1c2cf8, 0x0bd7c573, 0xf735f101, - 0x7ed0d0e8, 0x1146cf00, 0xcf3c08e4, 0xf2ae31ed, 0x07f4c39a, 0xfcc79c2d, - 0x66132f9e, 0x1d75f2e7, 0x1ced01d1, 0x98bf702f, 0x093e8021, 0x60b541f1, - 0x5f4b8edf, 0xc925724f, 0x9f004fbf, 0x589ec05c, 0x5cfd4264, 0x7da39fc1, - 0x8fe02433, 0xe11d6c94, 0xfdc8a859, 0x7c7fd28a, 0x8b77e023, 0x434f167b, - 0xd750e00a, 0x0cd43eb2, 0x0c6d906c, 0xe8f012df, 0xf17d2f49, 0xa416f4ce, - 0x604932f3, 0x1f17dff6, 0x7f10161a, 0xd0b4455f, 0xeff7b026, 0xbe55f7a4, - 0x74cef4fa, 0x8e6be337, 0x26f51065, 0x4e902e38, 0x47978f47, 0x183aae58, - 0x712bf554, 0x9c7f2177, 0xfb3edd2b, 0xd1dbf412, 0x223160a5, 0x684b97bd, - 0xabc30838, 0x49ab8fdc, 0xae5133d6, 0xe8813f82, 0x6e17966c, 0xe4bbf191, - 0x97417bd6, 0x1d372118, 0x2f5533f7, 0xd3c71caa, 0xf72de2a1, 0xd1bf903b, - 0x9fb3021d, 0xecccbb46, 0xe4fcb1b3, 0x7f104b83, 0x0bb25fa3, 0xeeb2cf48, - 0x7e4847bd, 0x403b6b1d, 0xe7401e77, 0x2eb66eda, 0x527d9933, 0xd98be31e, - 0x414688ad, 0x6056ad7c, 0x7c35a7c6, 0x0c7be61e, 0x7c3f51bc, 0x3804ce06, - 0x9e7ceb18, 0xfbf35bf8, 0x1096fbcf, 0xe3ca1bb5, 0xad901f99, 0x3fa61b9d, - 0x466000df, 0xa3db43fa, 0x3c304fbd, 0x6125af68, 0x27b13d7b, 0x9e0b70eb, - 0xcf53789f, 0xc55f75cc, 0x416ea7c3, 0x68f6cd78, 0x0913e726, 0xf3a549e0, - 0x3d7ba627, 0x18a56178, 0xb9216fea, 0xb7d8c677, 0x47f1f9e3, 0x13bb3fa7, - 0xa767dae1, 0xf24c89d9, 0x7de5191f, 0xda011d3c, 0x7d953e7f, 0xef1c2907, - 0xa52fc50a, 0x57dc6667, 0x24cfe74e, 0xaa8f09da, 0xa347a1bf, 0xfaf2801c, - 0x16797c12, 0x8293bd34, 0x87c45067, 0xc79dc4eb, 0xdbcbb404, 0xc483ae0c, - 0xfe47eaf7, 0xf90ca87a, 0x37e67aa9, 0xfa44cf0f, 0x0c9bdf6a, 0xaf584ef4, - 0x6c40e2e3, 0xdffc9720, 0x915ffdc6, 0x288edd4f, 0x7111c7cb, 0x5e23a1a6, - 0xa7753703, 0x888e3e5a, 0x65c07537, 0x8e82f50c, 0xfc57a9f8, 0x1d745eaa, - 0x201aba25, 0x8422e3c0, 0x0557640c, 0x78a0e092, 0xc8c7ba10, 0xced63fe4, - 0xd1916546, 0x8b822f51, 0x224179e2, 0x6fc85298, 0xc17e5c5d, 0x713fa67b, - 0x9266ca17, 0xfbf54135, 0x223385ac, 0xf1bfb3ed, 0xcdcfb215, 0xc39f6646, - 0x8d2f3c51, 0x391ff3c5, 0xc2bf7d9e, 0x87f305f4, 0xf5a4f933, 0x17385adf, - 0x0aef141c, 0x9bc2e4da, 0xf4516d70, 0x29c52c72, 0x1dee4958, 0xc03aeff7, - 0xe6f5b9e4, 0xbf7784a3, 0x0e0fe999, 0x0507b970, 0xf7d5279e, 0xa0429856, - 0xb77a242b, 0xfdd57a31, 0xf3872dc1, 0xe0fef85c, 0x8079390b, 0xf24cbcf6, - 0xe505fe0f, 0x7fc62a73, 0x3b5c36ec, 0x853bbff7, 0x7a58e0f2, 0xd9475beb, - 0x2c3c2a7b, 0x4f5438f0, 0xf7fee07c, 0xa264ce99, 0x8b08c313, 0xcd77030f, - 0x2b9bf260, 0xfe91c6e5, 0xf4b42783, 0x7d53a58d, 0x7d4fa55f, 0xcd37bd5f, - 0x8e39322a, 0x9479fc18, 0x90cc5ff7, 0xc48d7c35, 0xcde2f3fa, 0x75e16fb4, - 0x11c20244, 0x3f4356f6, 0x2635bf51, 0x5f48db8c, 0x6f608d4d, 0xa1efb603, - 0xcfab89b8, 0x29f5e785, 0x03722b2f, 0x78ed09a7, 0x906762b1, 0x6eecc894, - 0x5ebb7011, 0xabedc4ac, 0xe80f43a0, 0x75c4472f, 0xfda035bf, 0xa03c770d, - 0x5dc64577, 0x74f151cf, 0xbb8f4fce, 0xa6c84a9e, 0x31623df8, 0x9e66bab3, - 0x7bb1d055, 0xf74e90e9, 0x43eedcf0, 0x1a74f03b, 0xcf486ded, 0x8173a2e3, - 0x6f53e515, 0x1f91e5f0, 0x2e3ddfa8, 0xb0fed8ba, 0xe9056070, 0x3cbe741b, - 0x1bc4ef56, 0x233ac040, 0x77eed938, 0x25f65d50, 0xd412b8b0, 0xe2274d43, - 0xdd12aa2d, 0x3c70e69d, 0x5167e354, 0x5ca3ee0e, 0xf55f682b, 0xa29bb457, - 0x30fded7c, 0xb8f85a3f, 0x515dfb95, 0x98eee8a2, 0x576e5fc0, 0x1d06dcf4, - 0x9e67f712, 0xb914cb47, 0x4522dd63, 0x4a8d2dd6, 0x9ac60f9c, 0x53f2123c, - 0x82f51bb6, 0xb7ce9970, 0x028c5697, 0x9dfa8ad0, 0x5efe3e05, 0x539e36b7, - 0xf2ca590e, 0xcbcb0e72, 0xaf7514b3, 0x7a40dc17, 0xc2fe5135, 0x2fc12ef5, - 0x082bfad1, 0x1601d5b1, 0x06a8ad1d, 0x2701ceb6, 0x9b81e75b, 0x9da1f3ad, - 0x83a00bad, 0x9f8297ad, 0xaf8170ad, 0xb83e580d, 0xf98832dd, 0x52bd7e18, - 0xb45cbca4, 0xfc7ae264, 0x675e4571, 0xf9460797, 0x8f2f9f92, 0x614ae079, - 0x2e4d9d74, 0xdd99b353, 0x923172ab, 0x5177e27d, 0xb5a14de0, 0x9dec0202, - 0xf190c98b, 0xeb20d99d, 0x0702ae08, 0x48fee783, 0x5c069479, 0x04ee573a, - 0xd89aa972, 0x7628764e, 0x5d364c52, 0x87d7d61c, 0x54171e56, 0x49d201bd, - 0x3ebc60f9, 0x2ce88321, 0x5cfcae8a, 0xdaf190c6, 0x3a9df7b6, 0x8545a38c, - 0x84362d95, 0xe53f590f, 0xf3e55970, 0xd91f0899, 0x9ba9d276, 0x595e7649, - 0x1563b7a8, 0x39d86eba, 0x184dcf07, 0x4e50a3fc, 0x52824d92, 0xb1515d5c, - 0x677e8079, 0x74ebac94, 0xdbc657e8, 0x5719c580, 0xd59f8014, 0xe46568b3, - 0x7ebc3527, 0x7ae1635d, 0xbd706bdb, 0x60da7e4a, 0xc8cac5f2, 0x73759ad3, - 0x6e5f2993, 0x3ff7f030, 0xbce72c9a, 0x22327282, 0x9841533e, 0x44f73c4f, - 0xe4101c21, 0x186b5696, 0xf7c08fff, 0x77c21fcf, 0x5deb8a6b, 0x594dcf16, - 0x534ffa40, 0x676779f2, 0x245d8a59, 0x3f8616fc, 0xd2d59310, 0x5207478a, - 0x7bd21f9c, 0x776e18c1, 0x5eb95a1f, 0x329ab6ce, 0x27581f1d, 0xfbae0fd8, - 0xe28f977a, 0x084827d0, 0xd599f3be, 0x34744035, 0x428c8189, 0xd11dd7d4, - 0x27640cc7, 0xa80b1daa, 0x7fc8a5bc, 0x06bc039b, 0x96e51fe6, 0x2d98f533, - 0xe5c107ec, 0xa5ca1ef8, 0xd2ace9c8, 0x8d4971e3, 0xa5ad1f7b, 0x3c2af6ae, - 0xa2413c21, 0xad0a49a7, 0x1538bb20, 0x13e19eff, 0xb953a7e6, 0xabf12a3d, - 0x6def4f67, 0x42741c69, 0xed361f84, 0x0fabe6f9, 0xa34ddf50, 0x0f5d3b66, - 0x1696dffb, 0x1ab00bea, 0xd517c4d4, 0x1b75672f, 0x955fd47d, 0x397f3eed, - 0xaf78abdd, 0xfa7146df, 0x1b40fee2, 0x9ec1cb95, 0x2fdc69c3, 0x6bfe3ad4, - 0x93e4e7e1, 0x750512b9, 0x905ecbac, 0xabe446bc, 0x050bea99, 0xdc7c20f6, - 0x47137684, 0xa9bf79f7, 0xbd0d95f6, 0x2fa819af, 0xc43c67c1, 0xff42ad6f, - 0x5c37adaa, 0xad62f54a, 0xd62fdb57, 0x13d77bf5, 0xb43b75dd, 0xd9bf6afb, - 0x4f5f7ca4, 0xea8d9af5, 0x26bded3e, 0xa8f337ea, 0x67eed3fe, 0xa6fd2a66, - 0xa940ff92, 0x772a5733, 0xeb333f88, 0x235e0cff, 0x68fcd6f2, 0x7042dd8b, - 0xe2ced9ba, 0x6606fd6d, 0xd87deac7, 0x446cc89a, 0x8ddadbf5, 0x5567eac0, - 0x1b4ff98e, 0xfc8fa41d, 0x5d5993a7, 0xab3cf58c, 0xf09e3047, 0x22651efe, - 0x173ddda0, 0x1114ca1f, 0xd93d73cf, 0x5fb7aa76, 0x7f80eb5e, 0x4fa6179d, - 0x4ae7f7ad, 0xd40cab3b, 0x7d88dd47, 0xf7356e14, 0x4266d93e, 0xd01379b8, - 0x3b2d240d, 0xe2a6ea8e, 0xe97812fd, 0x503ef01d, 0x1a976b8e, 0xbeb0524f, - 0x9447908f, 0x09e4093c, 0xa2a379fa, 0x04ece8b7, 0xfd8c79cd, 0x71f7cd1c, - 0xefda99a5, 0x6e7f0e3d, 0xfe73c509, 0x02e3bc7d, 0xc136fdcd, 0xcd91f76d, - 0xbc3ff004, 0xb188ae57, 0xcd82bfc2, 0x17e7121d, 0x886fee68, 0xec9fb79d, - 0xdd0bfcbb, 0x4b703b18, 0x01657764, 0x2f504780, 0xe7b586b3, 0x21db07c5, - 0x1d47f116, 0x57998dd4, 0x16ea8078, 0x5fddaca3, 0x54c5daae, 0x4399aa98, - 0xb73b919c, 0x9121d1fb, 0x9c0945d9, 0x117970f7, 0x5e0f59c9, 0x46dcbc79, - 0x66fba569, 0x598bf303, 0x8a762dbd, 0x5a9d9347, 0x68d727f9, 0xd2ea9fe5, - 0x956d3bca, 0x6ee9de56, 0x6dcfbcad, 0xead7cad5, 0xb6cfcad1, 0xfee69671, - 0x0d4af6b4, 0x02f37d3c, 0xbdf3fdcd, 0xce70350b, 0xf734ab8e, 0xd32c7467, - 0xaf77e79c, 0x76ab9cd6, 0x2e0ed636, 0xb18f35f4, 0x08c41133, 0x567aabfd, - 0xff70a0ed, 0xff3c1aad, 0x1f6ffd6f, 0xc8a7ffa3, 0xbdde31d7, 0x37743b15, - 0xd165ebb9, 0x999dae3c, 0x59eb9427, 0x9cb6f6bf, 0x77431558, 0x54e6fc95, - 0xff941bf2, 0x0e16c391, 0x7df6fddb, 0x8e0acf14, 0xae88ab38, 0x1f7b80a2, - 0xa192f385, 0xba38aaf6, 0x32d900ef, 0xe89c8f85, 0x02a5e5fe, 0x857e34e8, - 0x3cb094f0, 0x93acf0af, 0xd972f0e2, 0x1636de77, 0x4be9c96e, 0xa120f3c2, - 0x6a85e794, 0x22e81447, 0xeca152e4, 0x29e92503, 0xf3abf961, 0xc007ec23, - 0x6880fd40, 0x2759b6f2, 0x9bec77aa, 0xb98f5625, 0x86f67d58, 0xa57362e0, - 0x067f2645, 0x25dff7c5, 0xc4cedebb, 0xb44a76b8, 0x139eaccb, 0x54c46d02, - 0xa4a31890, 0x76afa9e5, 0xed871f50, 0xff2bcd2c, 0xb56d4774, 0x6f919727, - 0xb6f09409, 0x67f5fe99, 0xa2648eba, 0xcb0407fc, 0xf6fc42fa, 0x332759ad, - 0x25197f28, 0xcd014494, 0xe9471c4f, 0x24dcccfc, 0x78c3f919, 0x0f65101b, - 0xab73c289, 0x9390fac0, 0x08ccd8f4, 0x67a8ddff, 0xbe940b79, 0x5e451aec, - 0x54b65f6a, 0x4f803fc1, 0x7e78c2ac, 0x4c1bf74d, 0xc329752e, 0x6dca1cca, - 0x37fbe0b7, 0x5017354c, 0x428e0a5f, 0xd5e7ef3b, 0xfa4d2d3e, 0xed557929, - 0xbf76cf6b, 0xd348652e, 0xc4cec32f, 0x6391e709, 0xbe615ee7, 0x9b03fbf9, - 0x1a1e59a2, 0xe6ce94d8, 0x4ff7e18b, 0x71aff7b1, 0x93b1a3bf, 0xd7df5aeb, - 0x9ef5dfd8, 0x81e7348f, 0x0d3e90a4, 0x4aec0ff9, 0xca35779d, 0x6305e46f, - 0xa8abf509, 0x715b38b7, 0x3dc0fdf8, 0xbe10e7d3, 0xa7e7cdff, 0x6bfdbe4c, - 0xa6ee6cfd, 0xed6c79f2, 0xd6070611, 0x963ad806, 0x55bfb54f, 0x20dfc357, - 0x90e5ea9b, 0xd13ec930, 0x1b31e6bc, 0x67fa83ef, 0x7ca4a94f, 0xd06e9fdc, - 0xc38b35f1, 0x0e26a5a9, 0x6b4f9bcf, 0x48de6f50, 0x00bf6dfd, 0x61ed010e, - 0xec7ce0a9, 0x3abbe47a, 0xa36b95d9, 0x2875727a, 0xd0fe874f, 0x56b81f94, - 0x1ebe7d40, 0xfe27caef, 0x53062c05, 0x599d1813, 0x890c37d4, 0x63013c9e, - 0x764f4dc1, 0x3ffd5357, 0x8a73c934, 0xadad7632, 0x83fa9aab, 0x8ff70321, - 0x847c9e5b, 0x16b7c3f9, 0xe77a4cd7, 0x31f24113, 0xf0497e7b, 0x16f6676e, - 0xf88c2c30, 0xaf3a82bb, 0xfa9b7ea1, 0x5f14609b, 0xdff8db67, 0xacc72a5f, - 0xae3c6d4b, 0x316b42dd, 0x2ceee5e9, 0xe8ca7bfa, 0x5f902366, 0x48873e20, - 0x5cf87af8, 0x40f20a76, 0x6f560d75, 0x78285fac, 0xf8a3e8d5, 0x1675cea1, - 0xbdecacdb, 0xd79f1b24, 0xf467dd24, 0xeefcb1b6, 0x3a46a8cf, 0xef58f5db, - 0x1070df50, 0x846d1cd8, 0x7a1161e6, 0xfde36c59, 0xc008dc17, 0xd1b793cf, - 0xc0ef4379, 0xdf278a31, 0x24aeba67, 0x72880c39, 0x8693c509, 0xdeacbdd8, - 0xecc9b66b, 0xf197a43b, 0x4ee1718f, 0x382fcfd2, 0xfa455c0f, 0x7805306d, - 0x03ccaadd, 0x91b726cf, 0x7287fee5, 0x9ecbfcd9, 0xf4a9f441, 0xb6cdfd22, - 0x4a9db988, 0x1f9df87f, 0xae750bf6, 0x5b83c2a5, 0x9f916436, 0xbcf85ea1, - 0x5bae1251, 0x0ff7c138, 0x963efa2a, 0xfe10f4e2, 0xf73e6ed5, 0xfb4ddb0b, - 0xcf4947cd, 0x271666bd, 0x58fdf6cf, 0xf4f61b3e, 0x9f207932, 0x117f12d7, - 0xc91bde7c, 0xe1cf48e7, 0x9fe57287, 0x9d305fcf, 0xb8291dff, 0x190c9bed, - 0xfdd86fbf, 0xbbb211c6, 0xdf1e7506, 0x18339da5, 0x9aff6127, 0x1d1cd130, - 0x5d444fb3, 0x9fbf5466, 0x8f7ed3aa, 0xa9cd3905, 0xa9dfc9bb, 0xbff0717e, - 0xb8f9a98b, 0x846be94b, 0x1f2cebc0, 0x87f23e10, 0xe58782f5, 0xd18e7545, - 0x23de6026, 0x585abadd, 0x35ce909e, 0xbb9ec9db, 0xe4fd06d0, 0x34473a07, - 0xe98f5f9b, 0xb835bfa3, 0xd6fc9176, 0x4c9953bc, 0x9be7767d, 0x8d7e940b, - 0xc562a9e7, 0x3f098b2e, 0xc71b9fd1, 0xa148b5ec, 0xf584c4af, 0x7c852650, - 0x15e7c48f, 0xd363fcca, 0xef3e9aeb, 0x685932bf, 0x001e0053, 0x00000000 -}; - -static const u32 usem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x1915c58a, 0x19d44418, - 0x18344c18, 0x20685618, 0xb58969c4, 0x9fd329b8, 0x90c0c2c9, 0x40b9c40d, - 0x7cc40f9c, 0xfc0c0c4c, 0x17ebc44c, 0xf5b04514, 0x84181904, 0x026ffc80, - 0x85d70c0c, 0x8bbe1818, 0x03083030, 0xf1402ef9, 0x01ce2004, 0x58a06f62, - 0x045e900b, 0x2c40ddc4, 0x7cdf8a22, 0x6bf20251, 0x37f95185, 0x847bf8d1, - 0x1057ebf0, 0x47af2fc1, 0x161b1e40, 0x3e3f22d1, 0x3bd02922, 0x015f5810, - 0xc7265f95, 0x0f27d0c0, 0xb8a87f8c, 0x4bfc9201, 0x0e5cbb20, 0x6096f6c2, - 0xf2062860, 0x9bb0150d, 0x2f9403eb, 0x857dca01, 0xcc0003ca, 0x688cbacc, - 0x00688cba -}; - -static const u32 usem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0x4514780b, 0x74f570b6, 0x9924ccf7, - 0xf2124c99, 0x00493de0, 0x210e0311, 0x9970c044, 0x46a2c024, 0x141a020d, - 0x84920275, 0x7e889790, 0x33feaeec, 0xa8a08901, 0x17acb9f1, 0x376141dd, - 0x0c06e8b2, 0x60e03518, 0xba2eb300, 0xe7c045c1, 0x36bc8026, 0xb9f04324, - 0x9d6f5ecb, 0xdd33d553, 0xc7c4099d, 0xffef7fde, 0xa55f9f8f, 0x71ebaaba, - 0xe9d4e7de, 0x278f3242, 0xdf210a64, 0x9f968fc1, 0xf890848b, 0x206f5950, - 0x8841922e, 0x6df466d7, 0x88cfa64c, 0x68e67a23, 0xd11d985a, 0xef435837, - 0x9ed5cbe9, 0x186934a4, 0x1c790f21, 0x23e21258, 0x5ab54e84, 0x16f50520, - 0xe0933ba8, 0x213e3a7d, 0x0ff8e8fd, 0x30f8e246, 0x1a18992d, 0xe0311067, - 0xf9ad537b, 0x421eb089, 0xc3e6476a, 0x213b16fc, 0x9f9f7bfd, 0xa7eb888e, - 0xf7c10def, 0xb59efa24, 0x6529efef, 0x13fd0e57, 0xf66ddff6, 0xf108146d, - 0x71c7fcef, 0x8699ef58, 0x5d130e39, 0xd9b7766f, 0xbeea053f, 0xb6899f6c, - 0xc0fb6ee7, 0xe5fed126, 0xda0944db, 0xf0233b0d, 0x8275cefd, 0xa695ea0f, - 0xa4ae47d6, 0x9136c0f5, 0xf8d30f3c, 0x4092062d, 0x613371c8, 0xeb15873f, - 0x5aac1145, 0x6dd77ebe, 0xa3495f30, 0xf7d04489, 0x2e88378f, 0x28d92fa8, - 0xaf9d08f8, 0x8c07b5fc, 0xc578e803, 0xc23ea13e, 0x1f1beb41, 0x3ee83a33, - 0xd8fcef97, 0x7ce146d6, 0x0e2663da, 0xa4a3ee23, 0x52908d3e, 0x03e996df, - 0x9ba5fbe8, 0xbe802705, 0x4ed9dd74, 0x83695f58, 0xe3a45c3c, 0x228bae2d, - 0xee6c918e, 0xd7cc08ef, 0xdbe7147c, 0xf9830f26, 0x65dfce4a, 0x6ee52404, - 0xca2e9193, 0xdf603ae9, 0x3da7bcca, 0x053e716b, 0xd22fe59e, 0x8abf68f9, - 0x6c270597, 0xdc40c2b1, 0xd7ce8eb0, 0xb05e0a22, 0x8daafec0, 0x7deaac23, - 0x7d876e14, 0x1bd6fa94, 0x7d605ba7, 0x69458deb, 0xd716f1a1, 0x7d76a7fd, - 0xdd13536b, 0xf3e3bd69, 0x748287b4, 0x4a5ea844, 0x4fe90b88, 0x8e8119f2, - 0x85e7e795, 0xe2f7c418, 0xcc38913a, 0x3a15f1a1, 0xe9c07ef0, 0xf1958774, - 0x12dbc701, 0x842ce03b, 0xc73b6eb7, 0x54c814a3, 0x8f94af8f, 0x7ae83e00, - 0x2c763d6a, 0x6124f71f, 0x81c7a4f9, 0x33da7b70, 0x1eb5cb12, 0xc67f3e27, - 0x75cb0133, 0xcf96171e, 0xe9606679, 0xbf63e4f3, 0x58053de7, 0xf1b8f06e, - 0x253d6ff9, 0xaa79d658, 0xcf26f9f0, 0x7b372c32, 0x65fcf8bc, 0xeb2c2acf, - 0x6e58b53d, 0xb2d17c05, 0x7ec3e3c1, 0x58753ddb, 0xf1ea7a36, 0x469eebf9, - 0x3870d72c, 0xb648b2da, 0x7360e144, 0x3b453b11, 0x6573cd89, 0x9b1eb4cb, - 0xf309eacf, 0x5a46d9bc, 0x3ad3704f, 0x3280cb85, 0xd689b67f, 0xf6b15407, - 0x1c92f721, 0xf10fad33, 0x3594f6b2, 0x5a089cae, 0xed65a94f, 0x7379d623, - 0x847d6922, 0xda8fb58f, 0xa289cfec, 0xacf551f5, 0xc9134c7d, 0x18fad0b5, - 0xefa7ab3f, 0x695ae573, 0xd595bd3d, 0xe6f13f33, 0xb33d68da, 0xa93fbd8d, - 0x2c3a27c3, 0x55b0f13d, 0x14202c76, 0xb9de4d57, 0x9bca892e, 0x5dc746ad, - 0x7bc849c4, 0x892ef9de, 0xd90687ca, 0xde6ded85, 0x746eacc5, 0x77b77b61, - 0x2edff629, 0xaa5db1bb, 0xb7db0fbe, 0x9ed8dd1b, 0xed835d50, 0xdb17b28d, - 0x8a3f5647, 0x2f468ded, 0x5eaa4fb6, 0x65d7f58b, 0x55e7b61f, 0xaffec7af, - 0xfed87d1b, 0x5c9bfdf8, 0x05fd6953, 0xe41dbdc1, 0x5dc10ade, 0x9e815242, - 0xee4093ea, 0xf9f970d5, 0x6d1d101c, 0x446fe9af, 0x6efadc3e, 0xbfc00be6, - 0xf507ebf8, 0x983edfa2, 0x89bce38c, 0x1c74c8e3, 0xa4e3e2f1, 0x334137bf, - 0x257bfa4e, 0x382d38ca, 0xc6df444e, 0x24defad9, 0x2bde7aed, 0x0fd9c655, - 0xdac2b4fc, 0xffa57db7, 0x9ebb4b39, 0xe329973f, 0x89eb847c, 0x1a7adbe9, - 0xa7c2d03e, 0x7c2083e1, 0xf138e28e, 0xc64f5b7d, 0x327c2d41, 0xd3e1060e, - 0xeff4e381, 0x070d38db, 0x3869f0b5, 0x97cf8418, 0x7dc19f08, 0x21c657db, - 0x0e327c2d, 0x5ff3e105, 0xbee49eb8, 0x53fdb38d, 0x7fb67c2d, 0x498f841a, - 0xef0cf580, 0x3f32bedb, 0xf327c2d3, 0xec7c20b3, 0x7da5ce38, 0x67fb671b, - 0xff6cf85a, 0xfe9f082c, 0xbee8ce38, 0xaff32bed, 0xfe64f85a, 0x149f0835, - 0xb633e001, 0xfc69eb6f, 0xc69f0b5c, 0xb9f083cf, 0xdf19c70c, 0x384cf5b7, - 0x84cf85ae, 0x64f841e3, 0xf626bee0, 0xe3c69c6d, 0x1e34f85a, 0x3267c20f, - 0x6fb9338e, 0x42709afb, 0x27099f0b, 0x8e99f082, 0xebbb64e3, 0xc7465198, - 0xce3ef6b1, 0xf0b467eb, 0x104cfd79, 0x38e3d73e, 0xa938e8d3, 0x52671f17, - 0x933e16a7, 0x29f0833a, 0xeaae71c0, 0x77af38db, 0x7af3e16a, 0x853e1067, - 0x7db5ce38, 0x2ea4d7db, 0x75267c2d, 0x3b8cf831, 0xa36b9550, 0x3a1754ed, - 0x95cafa45, 0x40972e1d, 0xd59da2eb, 0x8093bb45, 0xf62a225d, 0x89756906, - 0xe6cb7df4, 0x8907f498, 0xb9c8eeda, 0x4ac7e813, 0xddb531ad, 0x52213d11, - 0xb8c4e763, 0xb8f53562, 0xfd340319, 0x3453f3e3, 0xa30589ed, 0xddfded34, - 0xc0fa9ae9, 0xfe9a4992, 0x3472ab83, 0xaecba1f5, 0xf64ff4d6, 0xa7a9a0de, - 0xd359baae, 0x7ced787f, 0x6b25fb4d, 0x97ed354b, 0xea6896fa, 0x42fdd597, - 0xfd747fd3, 0xe5fb4d72, 0xda6a0f8d, 0xd71ffac7, 0x3cb5c7d4, 0xbe3fe9a3, - 0xfb4d79f5, 0x69378715, 0x6db627da, 0x3cafd4d5, 0xcecebaf9, 0x5f8fd8b3, - 0xd022ebc6, 0x7f76613d, 0xf8f7e67f, 0x1bac46ad, 0x8ed05807, 0x722d65df, - 0x35f8a31c, 0xd1c0b5be, 0x7017e28f, 0xf6457e0a, 0xda4b9280, 0x267bf3e8, - 0xd3b12fb9, 0xdd18f7e7, 0xd8c3db97, 0x041e94a7, 0xc3a50492, 0xfdbea500, - 0x63d19901, 0x23f3c0ce, 0x95fbe9da, 0x1888c086, 0xb312cf5a, 0x777e811b, - 0x8a2fcc0a, 0xf4154914, 0xf411348b, 0xce481e0b, 0xa2abc17c, 0x298355d7, - 0x71a10a1f, 0x24eec957, 0xaade33b0, 0x1d82f76e, 0xee983352, 0xcd21006b, - 0x4bdfbb42, 0x0607b4fd, 0xe9b92517, 0xb5232678, 0x1bf3d5d3, 0x3869fce9, - 0xebd00b7f, 0x7c7f307b, 0x294df9cf, 0x9bf33413, 0xe6689487, 0xfce91b37, - 0xafde4276, 0xa7e7c53e, 0xc8449848, 0x3853845f, 0x094869bf, 0x9180ffce, - 0xf9ea2bfa, 0x1ff38323, 0xd67ffd86, 0x2653fedb, 0xa43ff769, 0x237fbb54, - 0xea91ffdb, 0x48fe7cb3, 0xe151ffdc, 0x90ffdb2c, 0x137fb652, 0xbf38371b, - 0x93ff082d, 0x2f677f30, 0xb3529bf3, 0x5a1ffbb4, 0x89bfdda6, 0xfd5ddfcd, - 0x82df9f2d, 0xbe139ff3, 0x5a1ffb65, 0x4d1bf386, 0x8fd0276e, 0x95646071, - 0x1d4fce8f, 0x04490761, 0x40f3a172, 0xfd163239, 0x148497e4, 0x913dc75c, - 0x8abede8c, 0xf286f4a4, 0x58fccbc6, 0x996c951f, 0xb4e2efd4, 0xb67378be, - 0xb612e411, 0x21657f53, 0x8d1dea5f, 0x7937d222, 0x4e1be4d2, 0x28d9dbd7, - 0xc77ea17a, 0x207d9393, 0xe44d2aff, 0x4f787cf6, 0xfe787e22, 0x9fa353f9, - 0x5f4bef57, 0x8f95ac2e, 0x2df8a9b7, 0x90e547e8, 0x98165591, 0x1fa9aed7, - 0xa1107ea1, 0xd427c5fe, 0x249420cf, 0xbe6cca8f, 0x04bfa8cf, 0x2fea36f5, - 0xd5213b41, 0x75e25fb8, 0xae8c307d, 0x3f289f3f, 0x26f3ee17, 0x9e3a2964, - 0xc8f7f8c4, 0xf807c11a, 0x14597db8, 0x3d687e05, 0x4d38de85, 0xfb0fee9d, - 0x7c12ae07, 0x86380bcf, 0x9333e01b, 0xbd60478f, 0x67605eb4, 0xe8a21cef, - 0xb0514fef, 0x8a40d560, 0xb338d08b, 0xa44e4b88, 0x5a59cfef, 0xa2e84328, - 0x2f061055, 0x2059fa01, 0xe0119753, 0x69278de7, 0x7ae8389c, 0xf1b3b66f, - 0x63e4ba67, 0x14f5aa6d, 0x3e5766c8, 0xa1414f5d, 0x359feb88, 0xd1fedb43, - 0x619728ce, 0x3d572d0c, 0xc9ccf381, 0x54dfb6d7, 0x75cfada0, 0xef54eb6b, - 0x6ef7a0c9, 0xa73fd129, 0x9cfba160, 0x5d2b8417, 0xade75d28, 0x56b70e1c, - 0x5e0d5ec9, 0xda556dc1, 0x26e0a021, 0x5f7c2fb8, 0xf6ffd9ec, 0xa17ada65, - 0xb05f5b57, 0xa73e374a, 0xff1ce39b, 0x683e8047, 0x83e80279, 0xa718f3c2, - 0xd55c908f, 0xc18dc7d2, 0x50fa306d, 0x625c71f6, 0x8ebe3828, 0xdac2c7d1, - 0x50f4f0a8, 0x9707a418, 0x7a14be9a, 0xc3d38db8, 0x8a1e9ca7, 0x6ae96ad7, - 0x4cadf12e, 0xb2dfefa2, 0xe9e21766, 0xe8c850a0, 0x3d0a97e1, 0xc1e869b4, - 0x8f41e9cd, 0x3d38dbbf, 0x4673f6dc, 0xb67c7a0f, 0x5b687a71, 0x29264e7b, - 0xf14af13d, 0x3c53a9a0, 0x376ef0e8, 0x7c503d02, 0xf987a584, 0x8dd37dc1, - 0xde02fad3, 0x9c5f03d6, 0x053db01e, 0x4e104ec0, 0xcf6a7ef8, 0x684e54fe, - 0xc36bc5ea, 0x31b2bfe3, 0x6a98ee3b, 0x57f5e55d, 0xf5531dc5, 0x53375c5b, - 0x9be45f53, 0xbc5fe9ab, 0xbed350b6, 0xa69176b0, 0x3baac17d, 0xef42f535, - 0x6ffd35cf, 0x69ad565f, 0xb56ab5bf, 0x9296fda6, 0xb9f534c7, 0xfa6b5fee, - 0x5eb054df, 0xff273ed3, 0xacfb4d45, 0xf5345b19, 0x34d7ae99, 0x2f3b0dfd, - 0x31e81ebd, 0xc048a0eb, 0x71e638fe, 0xf71fdd20, 0xa4f2c48c, 0x717c89c7, - 0xcb0133da, 0x4fcd8d7d, 0x7cbb495c, 0x26882819, 0x91167f4c, 0x2cf64218, - 0xcaaf5777, 0x504e7d02, 0x7971feef, 0x1077b551, 0x07065395, 0xad6f39c2, - 0x11c7f891, 0xe2528022, 0x50c407f3, 0x6d1b567b, 0x3dbdeb8f, 0xb614ad6f, - 0x0a4dab3d, 0xe3e56e3b, 0x61ed4385, 0x7e2133e2, 0x3ec10326, 0xb9f6e2ea, - 0x204cbdbe, 0x84e7eaf9, 0x8ffe472c, 0x5cfd3031, 0xa2726466, 0x1cff6b6c, - 0x7fba8362, 0xe685d544, 0x95cca7ab, 0xaa91f408, 0xb5e2e3e1, 0x3ce46997, - 0x3c6de881, 0xcd38d9d0, 0x5775c5f3, 0xd8ebde6a, 0x2bbae225, 0x7d508640, - 0x07e48c3d, 0xfd97a00c, 0x8d6643cd, 0xceba7586, 0x355e401a, 0xd8fda3c6, - 0x771199e1, 0xe63c024c, 0x53d27963, 0x8f71e580, 0x9e63cb1b, 0x788f2c12, - 0xf36cb0aa, 0x33f2c32c, 0x4fcb178f, 0xfcb0ab3c, 0xe58b53c8, 0x2c5acf61, - 0x587c7a0f, 0x61d4f01e, 0x1ea7bef9, 0x234f56cb, 0x171e9d96, 0x29bf0a96, - 0xddd3d0f0, 0x4fa7ae49, 0x805dfd03, 0x07c4e2ce, 0x0a0d57aa, 0x8ae259d1, - 0x59bdab87, 0xd6f371a1, 0x249d389a, 0x0861e868, 0x81e364f8, 0x5e9c4c5e, - 0xade7b7c2, 0x9ed82f95, 0x1d8726d5, 0x7ff9f2bf, 0xf9cdbd0d, 0xa216f491, - 0x7a3a81a7, 0x3d18bd4a, 0x87c7124d, 0xc18e69e8, 0xa71ff4ce, 0x1f6087a7, - 0x628ffc61, 0xabc6ea30, 0x14573aec, 0x73f3678b, 0xb2d16a07, 0x7b9f3678, - 0x15ae1d05, 0x48df3fed, 0xc8f773c0, 0x78808fbf, 0xaa61f77d, 0xdf7b9328, - 0x7a5e9e9f, 0xfd0bbb87, 0x551f22a0, 0xb67ae3a2, 0xb8324447, 0x0cc81846, - 0xeac84e92, 0xce75bfe1, 0x44bac34f, 0x9f7de162, 0xf3986673, 0x4f670228, - 0xeb871789, 0x6357eb0a, 0xcfe3bc60, 0xca1323fc, 0xe6148639, 0x688b34df, - 0x0bff13df, 0x506f804e, 0x499c991f, 0x0c0f0710, 0x3ed1da37, 0xf0b459f0, - 0x667ad2f3, 0x29ab7e08, 0xdf515a8c, 0xfc2126d7, 0xa2357d86, 0x77e01f7f, - 0x317f3931, 0x0df7ce78, 0xf3c097f8, 0x62f1f262, 0x1cb89172, 0xfdd2372f, - 0x9d1ced77, 0xe403a0fe, 0xade185e0, 0xd7e95f9c, 0x7d28bcf3, 0x4aee3a2f, - 0x75b8e850, 0x88f3a108, 0xefc71da2, 0xc984b86e, 0xdbeec52f, 0x05f5f266, - 0xb59267af, 0xf9c53de3, 0xbbaf194f, 0xf81b05e5, 0x0c924b5b, 0xf06163f6, - 0xf5e594a0, 0xda8b76c9, 0xd6d46cfe, 0x19856bbb, 0x3a2768f5, 0x068f67a2, - 0x1fb7613d, 0x3b72061b, 0x9c654b09, 0xfb464925, 0x4ef72a31, 0x3346a5d7, - 0xe4c7cf3f, 0x9418e6c1, 0x663da717, 0xaf53ffec, 0x9471b7a7, 0x40d210f5, - 0x1e419a8e, 0xded4b6d3, 0xcf4af7fb, 0x3c4617d2, 0xbf926df7, 0x4cd0fb02, - 0xfc0effff, 0x5d61220d, 0x5eb2b719, 0x872e9af4, 0xf3359be7, 0xca1cf7d1, - 0x2977eb19, 0x891be217, 0x96e8571c, 0x5c638bea, 0x8bae2c9f, 0xcfed6bb0, - 0xb2bd4d18, 0x635dbfb1, 0x541fc28f, 0x412a92fe, 0xe329fa02, 0x5925d3e4, - 0x7d740956, 0x1090426f, 0xfd6056e8, 0x466dcdca, 0x95ce03b7, 0x5b7ade19, - 0x4cdfc51f, 0x897c9289, 0x61cf16b9, 0x9d2fea4b, 0x4ce67a0a, 0x88048ac3, - 0xbb162c1b, 0xf30fc9ef, 0x79312cbe, 0x0727c8bf, 0xa73df6b4, 0x55c7420f, - 0x945c639e, 0xeaab8e58, 0x8f16061d, 0x009b8fd1, 0x1c5fc6e3, 0xf79b153e, - 0x413b074f, 0xc68aa70f, 0xca3746b3, 0x665ffa45, 0xfc0a4e08, 0x13f314de, - 0x697e3a24, 0x2dc63b5d, 0x11deca4e, 0xbc80bcbf, 0x4b3fb9ec, 0xd528f1d2, - 0x15a4bcbe, 0x813f99e6, 0x371c444f, 0xf8e54c7d, 0x04c93fa9, 0x4f3910e4, - 0x4862657b, 0x063bfb86, 0xf90cc862, 0x161bf33b, 0x4fbc01e7, 0xe547bf81, - 0xdf241de6, 0xb5207886, 0x9cdfe099, 0x00198621, 0x7de433a7, 0x1e1538db, - 0x87232572, 0x94829533, 0xf1c14c1e, 0xefc1fddd, 0xb4d41532, 0xb9e0638a, - 0xc23ff8a4, 0x72471877, 0x50b7980b, 0x897b9ec0, 0x97e81ab9, 0x3f1a51fa, - 0x9a51fa8d, 0x34a3f53a, 0x437222f5, 0x1425e402, 0x9f13293d, 0xb4d27080, - 0x88ec928f, 0x555262c7, 0xafd1f603, 0xbe6dfc79, 0xe903489d, 0x7d5fcb3e, - 0xee90b336, 0xc5896ae7, 0xf57394fd, 0x0e0cb145, 0xa33e25a5, 0x7f73d2cb, - 0xddc61b47, 0x8c3f2548, 0x6fcfcec7, 0x051e6236, 0xdc994ab4, 0x7de949f4, - 0xa20d89ff, 0xfd06c22b, 0xbd6573e8, 0xff7fdfc9, 0xf212fdfa, 0xb4a3ee38, - 0xfa01266e, 0xc02791eb, 0x09d723f7, 0x7e185f2e, 0xaf74e42a, 0x013ba7e8, - 0xf143e37e, 0xf574fbac, 0x4abe1cd5, 0xfb5d29fd, 0xfd2f960f, 0xbcbe4688, - 0x93efba29, 0x027933c6, 0x00a417f0, 0x1e0fd7f2, 0xf8c7a93f, 0x7f1f81ab, - 0x6907f1b2, 0xff8e9ef9, 0xfeba4fd4, 0xbfd63d61, 0xcbfadc3e, 0xbb697d5f, - 0xd297ea97, 0x23653c3f, 0x494edf94, 0x8a4e09b5, 0x2b8db2f7, 0x3b902e6d, - 0x7c06d792, 0xce27ca71, 0x870f4708, 0x06a57cb8, 0x78804588, 0xc749fc2b, - 0xa1e9bd3f, 0xf89ec0eb, 0xc76ca36a, 0xc99d6a38, 0x5cf4a26f, 0x8f28b0d1, - 0x3b7ac18c, 0x16703fab, 0x51b2bfe8, 0xd3a6a23e, 0x953ddfd2, 0x94357900, - 0x921a0652, 0x7fa3f4a0, 0xf3e1b152, 0x546f60e9, 0xabf20092, 0xff983dfe, - 0x87d4589b, 0x9ee8c685, 0x499818ed, 0xafd9f780, 0xb3a1e1b2, 0x6afe0da2, - 0xbe9038c3, 0x37f7097f, 0x3f6b245a, 0x82b9273c, 0x54f2015c, 0x31f10781, - 0x8bc5637f, 0x4ed31abf, 0xe1b1d3d7, 0x0541364f, 0xea4fc527, 0x9bf05fae, - 0xcbbd1dd7, 0x87ca4eef, 0xd156bb6a, 0xee468e4f, 0xb2b13527, 0xaedbf64c, - 0x6ca4f2a4, 0xd2f4ecbd, 0xbd2f65c7, 0x2067dbf0, 0xc9a1fd7e, 0xbf8e9c39, - 0x073da5f8, 0xe2fad127, 0x3cbf722d, 0x908b0db6, 0x254bc210, 0x7a597ffd, - 0xafa50f08, 0x463a31ec, 0xc6f7e7b3, 0x78b1f086, 0x19232ecb, 0xb91e13dd, - 0x6d8cbbf5, 0xa9783096, 0x760e9f6f, 0xbf178adf, 0x3bbc8236, 0x892053b5, - 0xb9e061c9, 0x85da0f7e, 0x23c42700, 0x6f1053c7, 0x1495feba, 0x145fa02f, - 0x37dbe93c, 0xe3027971, 0x9e90d239, 0xce9d7e5f, 0xc991f25f, 0x792ffb09, - 0xec1b2ef9, 0xc55484e3, 0x95d9fae8, 0x4adf2009, 0x1d826f64, 0xe4bcf64b, - 0xde91bbb9, 0x9ddff78a, 0xae92e2c0, 0x95d406fe, 0xbfb0fede, 0xe0e6eb85, - 0x1b888afe, 0x59e4aee9, 0xcb47df31, 0x6332252f, 0xb8be184b, 0xf2726656, - 0x2354f3c4, 0x509dfdd0, 0x22fbc0f4, 0x627703d7, 0xbe6ef3dc, 0x62316a17, - 0xc3334bfd, 0xc0d930d3, 0x2bd32ce5, 0xf0dd7a41, 0xd38bea00, 0x70895d83, - 0xd21956be, 0xc437a80f, 0x1912d3fd, 0xc19e987e, 0xc99ea8f7, 0xbfd0e785, - 0x8c457655, 0x7a87bcd1, 0x297f9945, 0x3bae9f9f, 0x13b5ec12, 0x8ffde109, - 0xdf0acb9f, 0x4542bb53, 0x66fe2a5f, 0x3561befc, 0xdf856fe3, 0x4067337d, - 0x180717fb, 0xa07bc0ff, 0xfcbae967, 0x6bbed889, 0xc0f280b6, 0xf8e1fc44, - 0xf9cc837a, 0xd0aedb5a, 0x24b75d09, 0x05e8ab44, 0xf8458fc6, 0x7a2f5ea3, - 0x92a7be92, 0x9f309597, 0x0a78e7ad, 0xfe7316df, 0xf96b219f, 0xef8bac9f, - 0x99653e53, 0x33edfbec, 0x3f94afc0, 0x57e00ebd, 0xfdf61f39, 0x07cdcdb7, - 0xfa7ca66f, 0x4f857ab7, 0xcf53f2b5, 0xef5b25a7, 0x7a9f4026, 0xa0dbfd3e, - 0x4f96122a, 0x7cb0f3e9, 0x7feda83a, 0xf02a7e54, 0x45f802ab, 0xc8a7e085, - 0xa8e0dec3, 0xd9568797, 0xd21e5611, 0xd99201df, 0xba14fe93, 0xf4ade853, - 0x4143e5f7, 0x52e904ee, 0x5d20bba1, 0xdfa7742a, 0xfa7e16af, 0xc13249f6, - 0x26bfe575, 0xd65cffa3, 0xe942f2c4, 0x66077b7b, 0xa85c9c20, 0xdeed48c6, - 0x75d4fd81, 0xaf5eae9f, 0xd5d2efeb, 0xddfd75f3, 0xa6957aba, 0xb363597f, - 0xfdfe2091, 0xb2e27e9a, 0xb8d1c867, 0x63eaf470, 0x59c3597e, 0xc2e817a3, - 0xe5f7c012, 0x790bc4e5, 0x221d8186, 0x28ba05c6, 0x7e206b8c, 0xe7d939b1, - 0x656372a5, 0x743f8b04, 0x58b603d9, 0x618cae5a, 0xb1bc40f5, 0xf29ee406, - 0xe2c1103c, 0x01f95d8a, 0x9fca8c5b, 0x51126f6a, 0xc8f9b76e, 0x167e708c, - 0x47c828d5, 0x76b7a46d, 0x4d35ee76, 0x06590cb4, 0xd15aa571, 0x1df83609, - 0xe0d937d5, 0x29aba9dc, 0xfa02faf5, 0x451fe17c, 0x8ae97b4c, 0x75818db4, - 0xea4baf11, 0x4e6ff2af, 0x59d3ef12, 0x9a0b7f74, 0xc7739f98, 0x423d9d1a, - 0x153d20d6, 0x411a9659, 0xe27f529e, 0x86bcf688, 0x1f2945f1, 0xb69d64af, - 0xd29f795d, 0xa5f3fa01, 0x6eedb41b, 0xa07f0fee, 0x3258c9f0, 0x2ca3fb96, - 0xf2e5c30e, 0xfaed3134, 0xae8f8a02, 0x68989116, 0x4449bbbd, 0x166f747c, - 0x234f107c, 0xb7e478de, 0x7940120a, 0x03a9c0a8, 0xbbd8c9f8, 0xf6d8eabc, - 0x812fe669, 0x3c7fb66e, 0xd9693fe6, 0x11c3fdb1, 0xd5fd406f, 0x263e4343, - 0xeee7fb3d, 0xff73c08c, 0xa4569dae, 0xef1daef7, 0xd425f90e, 0x6139335f, - 0xbf3b5d9d, 0xd3f4031e, 0x0254dcb5, 0x306baef2, 0xd8aec78b, 0x3698f5f1, - 0x33f7afd4, 0xfe6461fd, 0x3fd37761, 0x41fa133e, 0x76057749, 0xe428cec3, - 0x23d7caa7, 0x6bbbdf30, 0x6e99d7c7, 0x9fb74fcb, 0xd1e79e0a, 0x5b052565, - 0x2c317d61, 0x8df2a18f, 0xd3542f89, 0x761bcbf9, 0xf6d01719, 0x39ff37dc, - 0xd768e406, 0x750f6656, 0x41cf6dca, 0xf194431e, 0xe29972dc, 0x8a9813ab, - 0x33bfcd3a, 0xdf02e466, 0x3fcb84f4, 0x57d63e31, 0xaffca478, 0x62e08781, - 0x33eacef2, 0x6fefb00b, 0xe318fb3f, 0x4ba4269a, 0xab7fbf65, 0xe57b46af, - 0xfecefb62, 0x82df6e7f, 0x76fb2fbf, 0xfbef9bff, 0x7abbd738, 0xe749e83e, - 0xfac1ee3b, 0xae27564b, 0xeef48fb7, 0xffc7fd85, 0x7bffeefb, 0xc52b7de3, - 0xfbe2edbb, 0x5affcdfe, 0x36f1ffbc, 0x7e3b778e, 0x3fe6f3d7, 0x57df7d71, - 0x6ff9bdce, 0xf6def78e, 0xadf5d8af, 0x067b2a86, 0xa9015f5d, 0x316182b5, - 0x92dbbe37, 0xd76c80e1, 0x8f30fd73, 0xc34bce0e, 0x23014df8, 0x904d0bf3, - 0xfb7e0747, 0x0b89411c, 0x1d751fa2, 0x1bae1fb7, 0xc8768254, 0x9987ae75, - 0xb55520dd, 0xadfed366, 0x989c0b39, 0x0fd24973, 0x7b3ea1bb, 0xfd6baf32, - 0xe204f7c9, 0x7f1da812, 0x2d35ce5d, 0xef5ed760, 0xa5eed112, 0x1fbbda25, - 0x9ece990c, 0x3dfad04f, 0xfadadd73, 0xfada054d, 0x8dde3e1c, 0xc6ffad84, - 0x7107c17c, 0x13f65355, 0x356710f1, 0x9089942d, 0x5542f90c, 0x98bfc12b, - 0x7f7daf93, 0xe3c1f81f, 0x531c3c7f, 0x971c0a4d, 0xb6485c20, 0xfa48dce8, - 0xeebe4700, 0x7d63d9d6, 0x244ccf90, 0x8de38327, 0x838c4ee5, 0xe65b7f73, - 0x5596cbef, 0xb2cfc0ad, 0xfc56cfce, 0x4de0dee5, 0xe38dffb8, 0x2fe084a4, - 0xbff444bb, 0xadff9d65, 0xe2fbe5e0, 0x8fe3c143, 0x3a97cbc5, 0xb8b20cbc, - 0xccabf008, 0x16a985fd, 0xca0fab27, 0xc8de7827, 0x9fa905fd, 0x42d3788b, - 0xcc8bdf79, 0x5f386ce6, 0x30148f33, 0x1afd71de, 0x3983f511, 0xe575c04d, - 0x8f31904f, 0x7e4373f8, 0x6f3be026, 0xbf1515dc, 0x0270cb60, 0xb871173c, - 0xb42a9117, 0xeff9c95f, 0x84cacbbe, 0xf6820673, 0x211722ef, 0xadbf52d7, - 0x47f04b28, 0x4b157852, 0x0e9d1bc4, 0x1c816f71, 0xb5bdc4d1, 0x47fdf875, - 0x8b9c6842, 0xbe4deff5, 0x5fe5d4fc, 0x323b3ca9, 0x1e41fa8c, 0x5849bb9e, - 0xaff156dc, 0x70626f6f, 0x7c132cac, 0x7e774829, 0xee755f39, 0x83e71cf8, - 0x0e3bdebf, 0xa3f664e5, 0xefd1a3a3, 0x6fd03977, 0x437ee4a8, 0x0d11d7b7, - 0xa6eeae71, 0x9b3e7e54, 0x55cb536b, 0xfdcfdca5, 0x7e40bfee, 0xa6bb2d21, - 0xf822b50a, 0xf1802471, 0x08d4ef5c, 0xfe4c31b2, 0x1931ffeb, 0x6154fd38, - 0x627e001c, 0xfd91e026, 0xd1abe98a, 0xadbc2ab1, 0x3494f6b9, 0xe01e27a6, - 0x0e754477, 0x0be163f9, 0x75c03e7e, 0xf4db447f, 0xadfb30fc, 0x5638b135, - 0xe2df5bde, 0x34379c77, 0x9700cb25, 0x9a8aa61b, 0x2655fb73, 0x238d97ee, - 0x795d60e3, 0x9b655d6f, 0x11697808, 0x66ddf09d, 0xa359d365, 0xb079cc3b, - 0x3e309e1e, 0xca8fd5c4, 0xe78022ce, 0x082387d1, 0xf2efd1f8, 0xf834c673, - 0x430d226e, 0x2b882e3a, 0xb5c39afe, 0x72c764d3, 0x1cb65e56, 0x6b4de74f, - 0xa3858fb0, 0x7fbc01d4, 0xe3211827, 0xbd878921, 0x501bf4a7, 0x1bb5fac6, - 0xf6e115ed, 0xed823c3f, 0xef3898bf, 0xfbfc2099, 0x51fb2de1, 0xec073fab, - 0xae3ca983, 0x09ae83d2, 0x0cf747f2, 0x1bfa07c1, 0xe7ac61fc, 0xdf84efb1, - 0xbeb3be55, 0x8559e981, 0xde70f5ee, 0xccace1cb, 0xe2c4dc7f, 0xfce27faf, - 0x8159c0a5, 0x4abd7eaf, 0xa6af2a7f, 0xd751e3a8, 0x197d8e37, 0x268a9bec, - 0x43a06ec1, 0x466d4855, 0xc6cac3e0, 0x6f3864c7, 0xe360eb99, 0x8c7f2912, - 0xd3a09f3a, 0x9a3bf2c4, 0x0dbcafd3, 0x1adce4e8, 0xe242e813, 0x0dace3ba, - 0x06bbf0e4, 0x7be19fe7, 0x227bef6a, 0x790178d9, 0xcea7b1f5, 0x8f525535, - 0x9ceb8c9b, 0x432d9655, 0xb296ecf8, 0x8aa2725d, 0xb14d3a9e, 0x1f3caed8, - 0x8748e650, 0x5c3e74e7, 0x1311f787, 0xd242ef81, 0xfbf15bea, 0x62aa5bd4, - 0xd4961d18, 0x3d6232ef, 0xf32bfb19, 0xf9e8f329, 0x369e7669, 0x6e4178ef, - 0x4b8020db, 0xd4bfc99e, 0x1f4e8619, 0x8ee72b33, 0xb84f53df, 0xf98edd28, - 0x2c4f48ff, 0x1b44f455, 0xef2bb9e6, 0x3e3335cf, 0xc489e957, 0x49627a70, - 0xf01123b5, 0x6a4764b0, 0x92c93022, 0x084b4e3f, 0xf03e27a7, 0x43e373b0, - 0xaeeebbfc, 0x5c4f54d9, 0xb313d2ae, 0xf44e9023, 0x959ae5ef, 0xe88b8d73, - 0xff6f0509, 0x03e6f2c3, 0xf86113d0, 0x56b346fb, 0x54d8dc4f, 0xc6e27a88, - 0xfbe6a2d9, 0x17cd6baa, 0x09d913d3, 0x3b2eb173, 0xcfd0c2a3, 0x39bfdc07, - 0x61fbf3c4, 0x6b17d01e, 0x9b8476cc, 0x26f46f5e, 0x55f6c7d7, 0x825fffae, - 0x97d722b3, 0x43f761cc, 0x8243a4f4, 0x2e64bcf4, 0xd002eb95, 0x4beb9323, - 0x4e71e56e, 0x07cd9c9d, 0x96a19b39, 0x0afdecb3, 0x950bd337, 0x9abfc98d, - 0xae6fdb47, 0xda669d95, 0xdc90e6ff, 0xddcb54cd, 0xe1096635, 0x96ee43dc, - 0xae7bb930, 0x4fda1c69, 0x53efedbd, 0x3ca96f2e, 0x430ce61b, 0xa2f3051f, - 0x1ddfdf34, 0xda76fb1d, 0xef2fc02b, 0xfb7e788a, 0xf603b739, 0x033b7d8d, - 0x7c53e9ec, 0xfcb8db3d, 0x5cf8f4eb, 0xc81ca953, 0xd3d983bd, 0x84459be5, - 0xe303455f, 0x91618aff, 0x4fad073e, 0xcf16ff4f, 0x60ef1761, 0x0774b0e7, - 0xfc2ad979, 0xadb77e2f, 0x1605ce06, 0x1cf017af, 0x005fbe19, 0x78731678, - 0xe3173916, 0xdaf14a39, 0xe53fe7f0, 0xa6a2dfbc, 0x5f0f18f5, 0x2bf6d3e4, - 0x29f5761f, 0x4cf247f0, 0xaf790f0c, 0xc9f5be08, 0xeba0cf90, 0xe78d5ce7, - 0xdaf5e547, 0x7ef907e7, 0xb4fe8a17, 0xe4fbe857, 0xd3bfcccf, 0x1ea0fbc3, - 0x123f252e, 0x5c29fb2e, 0x70f5fe32, 0xd40e0de9, 0x01f3c7be, 0x2b0e3c3d, - 0x649d2572, 0x6e7e1f00, 0xf15ca170, 0x42e143be, 0xb1e3bbe7, 0x40fb9ae1, - 0xbcb8738e, 0xf4d7706b, 0x02157e87, 0xb75e2bf6, 0xad024f65, 0x6327abcf, - 0x78a178e1, 0x070f56ad, 0x03837ef5, 0xaabcfaf5, 0xc7e4022d, 0xfbdfe42e, - 0xc31ef895, 0x5d6e547b, 0xed3cf546, 0xe4dd20bf, 0xfdf07386, 0x9b940111, - 0x47c6dd0a, 0x8e25fb30, 0x03a3a1cb, 0x3f515302, 0xe4760a35, 0xd3047f47, - 0x704f1457, 0xc4f34bbf, 0xbc73a7af, 0x2352b8b0, 0xc52563c3, 0xf4f3f01b, - 0x63af5e26, 0x4a2de076, 0x39f05ebd, 0xbbab9004, 0x8c5f7664, 0x8e04e240, - 0x847e9504, 0x04ecd5f3, 0xb4779e15, 0x28dffa33, 0x8f81f138, 0xf043f7fe, - 0x33dd2bdc, 0xf4afa63b, 0x3e29c0ae, 0xfde78b42, 0xe379ad11, 0x9bf9c1fa, - 0x737bc4e0, 0x9cf0629a, 0xbb2d58e8, 0xbf9525ff, 0xf00be7a7, 0xd1f7d43b, - 0x438584cc, 0x088cf37e, 0x79c50fcc, 0xa65d9853, 0x7bfa4f96, 0xfe6fbe80, - 0x45692551, 0xc7942c7b, 0x04de7ee8, 0x3410cde3, 0x09104ef9, 0x09ff3a03, - 0x7cd5bfc6, 0x9249f181, 0xef96f31d, 0xedcf2bb2, 0x5e2cbbec, 0x799c1e6f, - 0xef851e68, 0x13a255b9, 0x0c9ba85c, 0x2059838e, 0x09941e6f, 0x7db9cbf0, - 0x81e98bb2, 0x853bd428, 0xefc51eef, 0x0e590ad9, 0x8fbc291a, 0x7ca397e9, - 0xbd511f3d, 0x0a5882ed, 0xf70f1fa9, 0xee76cce0, 0x7880e69a, 0x95fec64b, - 0x2b39ce70, 0x20f07ed7, 0xbb3573e0, 0xaac8e907, 0xeed3f45c, 0x7e4053ba, - 0x06f14c3b, 0x9d99cfef, 0x9d20f07c, 0xf155d6f7, 0xcf396e78, 0x9c237f15, - 0x27dbce63, 0xdfb41d3a, 0x16adeb82, 0x66bcc738, 0x2adc48a4, 0x5a4adcf8, - 0xaf33be31, 0xb039ceea, 0x0faa12ee, 0xf72864c5, 0xfa844b4f, 0xafdf013a, - 0xf08dbaf4, 0xdaeb66bd, 0x3a0cc6b3, 0x07ed117f, 0xc75caf60, 0x106e55fa, - 0x5dfa909c, 0xca18f4d4, 0x020da2cb, 0x4ad3345e, 0x1b335fed, 0xe3a667d7, - 0xefa3aeb6, 0xbc317ad3, 0x886ee30f, 0x27ce11b9, 0xf13ae92b, 0x78d509fd, - 0xdf445d2e, 0x75a4cda3, 0xde389dc3, 0x810275a2, 0x264b03ef, 0x01323f24, - 0x3b27dbc6, 0xaed0fda1, 0xdd611b5f, 0xfaf9d1b7, 0x8817f1d3, 0x3fa0d36d, - 0xc760a5f9, 0x46ea87fb, 0x0baddc60, 0x542f0c36, 0xe63ac70d, 0x0c103b13, - 0x651f3a92, 0x4efb0447, 0x755968b8, 0xcdabec0d, 0x406c9f1b, 0x046b3aba, - 0xc28c7e3d, 0x3c874ddb, 0x2e79646a, 0xc6a3decd, 0xfd1c9536, 0xdf152228, - 0x1b31a3bf, 0x921626f3, 0x709bcc7c, 0xa47b3357, 0x0f84657d, 0xb2ed6ae2, - 0x6f3c087d, 0xe7c2695e, 0xfd312f9d, 0x0db839d3, 0xd627dbe3, 0x5fbe04c9, - 0xf52eb15c, 0x89e3c069, 0x9bd232cd, 0x1bcb2cf8, 0xc5897e28, 0xb1d79ac9, - 0x352c4f71, 0xa0b57bb2, 0x5f8bd69d, 0xb40af254, 0x51c8ac72, 0x2f4a728a, - 0x6b72f497, 0x46d593d1, 0xf21ed920, 0x9474e96a, 0xef54a557, 0x90f5a100, - 0x306a8357, 0x5797aa6e, 0xc8a2c495, 0x5f8874a9, 0xbe0f9616, 0xf1d02d6d, - 0x8183ecad, 0x5f6bff56, 0xb77a053e, 0x49e04acc, 0x5a7f6485, 0x80417460, - 0x6d35e65f, 0xa0f812f9, 0xde045e64, 0xf01c75c7, 0x26b37c00, 0x8bafcf0e, - 0x6f08857c, 0x78b72f25, 0x95ce96ad, 0xb75ce3f8, 0xfd6a5c48, 0x5c451255, - 0xee877eaa, 0xe74af4a3, 0xf051bdb9, 0x743ca881, 0xbbdefb5f, 0xc76eb033, - 0xf6e32d75, 0xd22b1ac1, 0x9f9fa1f3, 0x7af4095d, 0x0102bddb, 0xdd789d7b, - 0x2b0fa035, 0x880e0ad6, 0xcbdf170f, 0xefa62fde, 0xfd0fbac3, 0xa515d19a, - 0x7fd0076f, 0xf6c7bac5, 0x820dff62, 0xb43fc603, 0x89ed10be, 0xb048af12, - 0xfa3b437d, 0x614f540f, 0x57b3599e, 0xaffa004c, 0x0764dfb8, 0x23a14953, - 0xf9db2e85, 0xecc4087d, 0xbe8b331c, 0x15160ab7, 0xc51e93df, 0x4fa82102, - 0xbd2a4e81, 0x5fdace8c, 0x36409d92, 0xf64ba717, 0xae09fc1d, 0xe767c55f, - 0x74ef874c, 0x047ea98a, 0x975e6d3a, 0xe23b046b, 0xfcc04f84, 0x49749e8a, - 0x4a3b6a2c, 0x0567cba1, 0xd07baf26, 0x7b0e8ea3, 0x4ba71dd0, 0x5128fe85, - 0xb6595fa3, 0xfdf0264f, 0xdd1e9ebd, 0x908dfd72, 0x32f851ff, 0x6f5d0fdd, - 0xd1cfcd6e, 0x48e0575e, 0x2f5009eb, 0x8fde5892, 0x12e50fc2, 0xdefb0fcb, - 0xbfcdd3eb, 0x87e78229, 0x2c883f01, 0xe74fc97f, 0x0bf37b7d, 0x66792f98, - 0x6875fb53, 0xe941bcdf, 0xd9bfe000, 0x7fe8fc4a, 0x950e50f8, 0x6f988836, - 0xe67f244d, 0xaedf952c, 0xfe2cbfe4, 0x5de11583, 0xcbe4d5ba, 0x6e97efa3, - 0xf3063a3f, 0x30079611, 0x49bbc7bf, 0xde1fe760, 0xfdf031b6, 0xf2c4a950, - 0xc176f470, 0xe71648f0, 0xaa2d78ea, 0xa136ec00, 0x57b3dd8e, 0x6c937f5a, - 0x0775c552, 0x2f38ca45, 0x63e787ed, 0xb8678a5e, 0xa7d6011f, 0xc94ddfbe, - 0x9178e9bf, 0xa3695fd1, 0x695cf68c, 0xc84e96dd, 0x6c3d2cc3, 0xb2b73f42, - 0xfc11acee, 0xbc3fdcd8, 0x55f3f784, 0x3c9a8a36, 0x6ff91ebc, 0x04dfa275, - 0xe50d5bf9, 0xeb437e78, 0x0faf58ed, 0xb17a079f, 0x7fc5ad3c, 0x4bddb1d8, - 0x95f8b841, 0xbef0d9df, 0x368dd6be, 0xeea9eefc, 0x3da7f9c2, 0x57eaddf2, - 0xeddf305f, 0x0941fc34, 0x5d48baeb, 0x931d60be, 0x997d746b, 0xc4e261f9, - 0xa5eb7b41, 0x7c839f2f, 0x7fad8eec, 0x5bd60e7b, 0x9ee75ff6, 0xb21abc83, - 0xf60ec233, 0x0fa6e548, 0x79559f30, 0xd99224af, 0xfe2f9d7f, 0x3b80f30e, - 0x6139343f, 0x271dceb4, 0xd1bd8086, 0x04dbe5b9, 0xba5defc8, 0x73c61a63, - 0x4dcb6e96, 0x05e26124, 0xeb74094a, 0xb21e43eb, 0x0dcd5f1e, 0x73ff98cd, - 0xe41be286, 0xb17f3043, 0x83e59cbe, 0xe2de783a, 0xdef9f0e6, 0x1b14f23d, - 0x193f5d66, 0xb30362e4, 0xaf9a2e0b, 0xf1e28078, 0x6fe03ef2, 0x4f2e6af3, - 0x0cefe3c2, 0x54f141fc, 0x57cda913, 0xe161b2fc, 0xb6819e6f, 0xf35eb886, - 0x807dfd15, 0x3e4f929b, 0x58f5d22b, 0xd6cdf024, 0x287e63df, 0x01cf2de0, - 0x21cbf9f2, 0x293e1710, 0x10fe3007, 0xefc261d8, 0x1c774b2c, 0xdce9fe42, - 0xb5f31fb6, 0xeeebcf09, 0xcb1fc124, 0x9eb1e5c3, 0x96560dca, 0x0fe1c8e7, - 0x1b0e9079, 0x8ef9e73e, 0x3c958e8c, 0x1ff2dec8, 0xf853225b, 0x4f2c2a7d, - 0xc7c37cb3, 0x8430af3c, 0xe002612f, 0x7982fda9, 0xec1c0aa5, 0xd42b8700, - 0xf3e1bcf9, 0xdf79834c, 0x3f805f1c, 0x7cc1d390, 0x041f5a5d, 0xe13e9bf9, - 0x0f230910, 0x3cb3d73a, 0xfc394ee0, 0x7e4accf7, 0x4f9eb36f, 0xebcb7d7d, - 0xbffad8bd, 0x221a7c2f, 0x1eae381d, 0xc3e71d4e, 0x9ce3f1cb, 0xf7f07fef, - 0xfe826521, 0x81cf93fb, 0xda1bcb1e, 0x899f788d, 0xfdf13fe2, 0x5a78f076, - 0xf31126c7, 0x9bea6b3e, 0xe5eb8e51, 0x273f0545, 0x1bf7afd1, 0x468adebe, - 0xb63a27a6, 0x3a167d5a, 0xaf5bc74e, 0x6c573d21, 0xd3bcc76e, 0x18af75bd, - 0xcbe754db, 0xaa7c27a0, 0xbcbc77f5, 0x6dca0c6b, 0x7e98bf7e, 0x9b14631e, - 0xfc29b2a7, 0xcf9b953c, 0xec59e66a, 0x2dda37ad, 0xb4ef9f17, 0xc609bae4, - 0xeccadd3b, 0xe2f5d3a5, 0xf9985f0c, 0x49bd714f, 0x0f3b2d48, 0xef12faa5, - 0x7bb2b359, 0x245b44d5, 0xad4b5fda, 0xf7470e13, 0x7988d283, 0x79aa2b2f, - 0xce7dcc9e, 0x0af7c024, 0xd604d5eb, 0xabe012bb, 0xbb65e3f2, 0x26dd809b, - 0xa867e527, 0xf59459cf, 0x8819fb1b, 0xa5ff854f, 0xe08919d6, 0x3bc9127f, - 0x5d71d608, 0xe812d7ca, 0x8b0f56bf, 0x47f393df, 0x56f3c187, 0x8e27bec9, - 0x553adb8e, 0xb5e84270, 0x34fbdd27, 0x2e998671, 0xf8b17ded, 0x5fdd1c0d, - 0xf680d3b7, 0xb7e0d5a0, 0x1ac42ed3, 0x0e849ad1, 0xa43883ac, 0x0214fc04, - 0xf41e21f3, 0xfdc16798, 0xcd4236c8, 0x94e7e853, 0x449ff734, 0xf774904f, - 0xc30390a1, 0x385abd28, 0x39712abd, 0x8e9bfb2b, 0xacf786db, 0x6a91a4c4, - 0x5635df20, 0x4f0dda37, 0xe869fbf0, 0x41e4246f, 0xa74892c4, 0x3a26fefa, - 0x38fbe6af, 0x1ea6af3a, 0xe3d6d2e3, 0xc2c74866, 0xbe3897e9, 0x05a2e98e, - 0xcd3310e1, 0x796bf8a0, 0xeb4213c3, 0x4e27898e, 0x6b5fb43f, 0x2801efc1, - 0xfbd5797b, 0xebb458b0, 0xc8d3eba6, 0x36b4e889, 0x53ad81af, 0x1c4edcf3, - 0xa5dfee02, 0xabd74e7d, 0x714617a9, 0x09112779, 0xdcc59de4, 0xbbfc384a, - 0x5fbef035, 0x013837da, 0x5fb843f0, 0xcf9025ed, 0x41f7cd12, 0xb7f4d7e7, - 0xcd807443, 0x0c871daf, 0x43bfabb2, 0xbfeb9cbd, 0x25fc9651, 0x329e9451, - 0x62615687, 0x49125676, 0x9ba5efc3, 0x4a7ca1fa, 0x79839659, 0xa32d4227, - 0x086b61ab, 0x00b0cdf2, 0x3fba9bcf, 0x9351ed12, 0xd2237899, 0xe2367be1, - 0x1661d395, 0x7043cf1f, 0xa1d0372c, 0xd69455a4, 0x814d7be8, 0x8a42c31c, - 0xa2687a84, 0xb94657e3, 0x9f28a3aa, 0x2774ccd6, 0xf6c2c619, 0x3bb95ede, - 0x52f6b90b, 0xaa1a0888, 0x1969eef7, 0xef04228c, 0xbdde20f1, 0x6bc6807b, - 0xec153a95, 0x6d7f9df0, 0x32eeb064, 0x9b5f7953, 0x3e8feac2, 0xdc2577b4, - 0xcf6e9337, 0x49f6147f, 0x7851f6cc, 0xd58fe5de, 0x9bddf3dc, 0x39d6517e, - 0x173f8372, 0x3abe05ee, 0x1df5eec0, 0x777e0d6e, 0xa3787a8f, 0xd1fba945, - 0xd86fc88f, 0xbcad728f, 0x1bb63f7e, 0xa1cb4ea0, 0x81dcfe71, 0x472f9f74, - 0x74969a1d, 0xa1af1d29, 0xd93e0930, 0xd0ea357f, 0x30eef81e, 0x578f8704, - 0x82141eee, 0xc3fcb483, 0xd5932d3d, 0x0f70f870, 0x857d21d8, 0x7d0fabc3, - 0xebe87088, 0x6c5d29be, 0x935cbc07, 0xd6fbc06d, 0xc16c38ae, 0x45fd0af8, - 0xe3e23ea0, 0xbbe5efac, 0xa11fc56c, 0xd354ece3, 0x429ef297, 0x4dd1bd57, - 0x628fb12a, 0xe96a6cf7, 0xf5ca2ba7, 0x25abac36, 0x358f75ca, 0xf78ff71e, - 0x76e35c00, 0x0b8ea73b, 0xb8b135d1, 0xeefdc1c7, 0x5bf32ca3, 0xf2f254a3, - 0x6225ec9a, 0x81c9c40a, 0xfb43e217, 0x8de65f89, 0x19f74118, 0xde6032ef, - 0xfb8b28fc, 0x2b63cc20, 0x7721f808, 0x1ee20aec, 0xbe218827, 0xd9abe650, - 0x9af5fcc1, 0x396f8342, 0x6015ef3b, 0xb47d10bc, 0xc023e8e9, 0x1db1a3e8, - 0xa9a2a3e9, 0x6347d19d, 0x06644e75, 0x3f03373b, 0xc60496bf, 0xa23bde02, - 0x51269abe, 0x151a1ffa, 0x91ba01a8, 0xe5a6e7bd, 0x3d708a5d, 0x7c3f161d, - 0x7abeca7d, 0x4b6d6fc3, 0xe06943ca, 0xe033ee4f, 0x37029779, 0x858c5fa5, - 0x58b6c5e5, 0xfc035fdd, 0xedb4272a, 0x6d6fed85, 0x36f31f79, 0xd86efb6c, - 0x66dbef05, 0x42390c53, 0x5beed6f3, 0xd767f78e, 0xd87dd806, 0x05e024d1, - 0x3c3bdebd, 0xe104ff18, 0x1a4f7601, 0xf91da3c0, 0x5eff1365, 0x7051ab2c, - 0x1a1f9e81, 0x890deec5, 0xebf3b0b4, 0xd7111621, 0xcec2c439, 0xbdf7e259, - 0x95bf8225, 0xfb01bf75, 0xa69943c7, 0xbcfdffde, 0xaf89a4bf, 0xe854f82b, - 0x28d24a89, 0x4ce47fb8, 0xa2d13b8c, 0xa8d89fa1, 0xca78d514, 0x88788f7b, - 0x47aa0ef3, 0xff3dd8af, 0x94abd02e, 0xfc00be7e, 0x968dfb04, 0x4a6e0023, - 0x70cfa07f, 0x0defa1f8, 0x1e60f987, 0xecb617b0, 0x3de2225e, 0x6bc47d1a, - 0x491bdc26, 0x914667fb, 0xfdf4adaa, 0x425a68cc, 0x13d78e3d, 0x2b207d79, - 0x1a713f53, 0x3d7cfa04, 0xb64ebb8f, 0xc931fcf0, 0xd186ea3e, 0x5c766750, - 0xea245256, 0xe16f8505, 0xb738080e, 0x75f9f896, 0x00c5204a, 0x58f85378, - 0x56fc180a, 0x2452b4aa, 0x18f20187, 0x7dd0f1de, 0x9dcbbd4b, 0xdf652fab, - 0xcf9fea71, 0xc1f9ebe4, 0x3d17f5f6, 0x099eefbe, 0xb7372df0, 0xad03723d, - 0x0e7a5c57, 0x479707cf, 0xa1795c55, 0xebf42f7b, 0xdbfce77f, 0x4d874051, - 0x7ec298df, 0xe1c3550f, 0xc029e2d6, 0xbdf932f7, 0xc951242e, 0xb1e55633, - 0xcbb71b42, 0xf8299510, 0xffaced1c, 0xf8081140, 0xf0b14af4, 0x9e32547e, - 0xe5d14e1f, 0x9f87fead, 0xc132f9c5, 0x71250030, 0xcf3628c9, 0x324ecc37, - 0x9ce0ffd3, 0x173f1a69, 0xaf72477b, 0xdef1d2b0, 0x357cec21, 0x19aaae33, - 0xc6c4c4ea, 0xfbda26cf, 0x6b13320a, 0xb8c2c6a7, 0xdf18c9d1, 0xdaeb35ca, - 0xc812bd53, 0x8c9a9269, 0x88d38979, 0x7a633eca, 0x08eeed03, 0xe3902eba, - 0x742c8cd7, 0xe7ede54e, 0x4d43ffe8, 0x2a99f6e4, 0xc72ae37f, 0x8d54e75c, - 0xf78b52fd, 0x9fe9fd01, 0xf2e1ede2, 0xfce33e2c, 0x77c9e2df, 0x1eb3f9c2, - 0xe10e399e, 0x27a3ab7e, 0xd470f5dc, 0xab815dc3, 0x9fd98e1e, 0x86c6a738, - 0x2e1e9381, 0x48ed48d3, 0xdc0a63d0, 0xc77970f5, 0x9de2e8cc, 0xabde1334, - 0xe0c48ef8, 0x23350ef8, 0x9ba41ea1, 0x01ef1168, 0xf5e28cce, 0xbab04737, - 0x64a8ef82, 0xae1eb7c4, 0xc666387a, 0x58e3f7f1, 0x2f00bdff, 0xe202e509, - 0xcc9ba147, 0x31ddaad4, 0xec507a2a, 0x2e1c69eb, 0xfb46bed4, 0x8ade3739, - 0xafb02671, 0xe08425a7, 0xd6ce5b96, 0xf2dc3b95, 0xf4a9f83c, 0x72bfbc75, - 0xff3fe10a, 0xca2f3c14, 0xce0555e4, 0xdad1be53, 0xa69ad3c9, 0xc338829f, - 0x7efb9350, 0x1080cfa0, 0x1475e783, 0x707447ee, 0xd767bed7, 0xf870f5d6, - 0xb131fc03, 0x3a14bc27, 0xe3c2c0fb, 0x20c8034e, 0xbcc797b0, 0xf20d1196, - 0x86c5349b, 0x715c4b8d, 0x0e383f38, 0x63a457a7, 0xcf83b881, 0x423fa9ed, - 0x5aa3ed8e, 0x36c72552, 0x96d3ee8b, 0x4c729ef8, 0x8e64d3c1, 0xbbc4c987, - 0x934be20b, 0xd045f489, 0xed0e481f, 0xe7d95bbf, 0xf6103240, 0xc1c58379, - 0x67df3fe4, 0xbcd4df70, 0xf8b3f984, 0x0b6659fc, 0x02435f7e, 0xce104752, - 0x91df7829, 0x5a1b18d7, 0x4fbf9287, 0x66115486, 0x7bc3cdcf, 0xc85c29ae, - 0x75a15177, 0x8482ac98, 0x75f0fdf7, 0x7b33a99c, 0x5bad8f21, 0x9d814774, - 0x1bec21d7, 0xfc93fb83, 0xe9ff4023, 0xee35cfdb, 0xda7680ae, 0xf1fb08af, - 0x59162ff5, 0xc3b021fc, 0xb93e7be4, 0xb2953b77, 0x8509ea35, 0xfbe0b37e, - 0xde81cbd4, 0xdd6103fd, 0xd1d54053, 0xf659e772, 0x6376431d, 0xecf304ba, - 0xff7966e9, 0x8125c439, 0xdfa7ab7d, 0xa1a74bef, 0x08604578, 0x5d8a29f8, - 0x1eead536, 0x57cfa569, 0x9b66eff3, 0x05188ece, 0xf4c1f978, 0x4f4b4074, - 0xba511d0a, 0xecf00f1a, 0x69fcf8ca, 0xcddfc730, 0x7a009738, 0x43dfb151, - 0x026b8a76, 0x3b37a7ac, 0x3dd5897e, 0x3b017ac5, 0x2e67b15e, 0xdd9087e6, - 0x74a641d4, 0xcbc71b74, 0xccab733c, 0x600fcdee, 0x48eafdfe, 0x473b5ee5, - 0xb791d824, 0x54d94ead, 0xd586e707, 0x6b7efe2c, 0x83f1ac95, 0x86dd90dd, - 0x66fbb3ef, 0x6da65f6f, 0xfe604cff, 0xfb57a17e, 0x3412589c, 0x9cf6edf7, - 0xc035e0d7, 0x3123c3bc, 0xaf3f413f, 0x79fa7f7e, 0xe6adf3f5, 0x636ad57e, - 0xcaa748ed, 0x6560592e, 0xaaf750f6, 0xcae0ebc7, 0xe7e0deba, 0x93480f36, - 0xb5abf754, 0x082c8ead, 0x328c6f77, 0x79ef029e, 0x00e2cfc4, 0xc3dff255, - 0xe59b83dd, 0xde81f166, 0x98161de6, 0xe1a0768a, 0xf608bf49, 0x4100b0fc, - 0xe02b3bfb, 0xf8d02c32, 0xee4fcc01, 0xbdc007e1, 0xd65eb426, 0x01f98bb0, - 0x4fe8d5f5, 0x027f5194, 0x387accf4, 0x17c01e9b, 0x41fe8694, 0xfc85dfd0, - 0xcfb82ca9, 0x12c3fb92, 0x5ad497a5, 0xf5a37fd6, 0x096ae35d, 0x927755fc, - 0xe363294c, 0x98d7efc3, 0x93555fa9, 0xf508224c, 0xf8785eab, 0xc06be9fd, - 0x09758e5f, 0xad287f70, 0xf7fa58d7, 0xf8debfdd, 0xb81afef0, 0x65fa946f, - 0x7f2aaceb, 0x78fe37b7, 0x0b918c04, 0x3dba47f0, 0xa1f0237f, 0x8a68af12, - 0x111f7ce0, 0x8068bba4, 0x57274297, 0x7e8f9b2f, 0xe725c445, 0x589e4087, - 0x16ffc716, 0x46c38f2b, 0x129ff7b1, 0xbf905bdd, 0x023f3adf, 0x8cefcbe2, - 0x5cfe8a3c, 0xe7c59593, 0xd04a79f7, 0xb9f0527e, 0x3f702acb, 0xf8103fc9, - 0xcdf1daed, 0x6497e071, 0x43de02c9, 0x9efb24da, 0x7900cf4c, 0x82bedb34, - 0xa26b296e, 0x6b13bf11, 0xbc0ff08a, 0x35a7655b, 0x9b4cfbf1, 0xa81deece, - 0x661e63ce, 0x4565ddcd, 0x308bf3fa, 0xeec6567e, 0x7befa0c3, 0xfd212fd3, - 0x7f4012e1, 0x13fbf390, 0x61a8fcf0, 0x42e20d8f, 0x827efc1d, 0x09cd0d33, - 0xbe5969f3, 0xf0362fe5, 0x70e7ded7, 0xe2b52338, 0xdb654a3d, 0x83ffbc44, - 0x0b709bce, 0x161ba7c4, 0xf7efb264, 0x8a6777d8, 0x67ff4cfe, 0x167cc0f3, - 0xc8efc434, 0xb2727b14, 0xf583ebd9, 0x188b5535, 0xbbac9e2f, 0xbf0a6c37, - 0x5f6f4c37, 0x712ab49e, 0x87cc04e9, 0xf3676a5a, 0x594fc6f4, 0x9f12c4df, - 0x24b2df8a, 0xcfeb08bf, 0xc08126fa, 0x5a679715, 0x03c89e52, 0xcec89e3f, - 0x44ac30e1, 0xcafda376, 0x6fe89fcf, 0xbe43dc37, 0x6cde5793, 0x4aeb3738, - 0xfdfb6624, 0x77600997, 0xe0b1fbb9, 0x8a07d322, 0x1be5377d, 0x6f557c6d, - 0x8d34e6e7, 0x41207fbd, 0xa77fb378, 0x55eec022, 0x06ff61eb, 0x7bb587a6, - 0xe10c7909, 0xf52dbe90, 0x2947b81a, 0x3b068ffd, 0x7c02dbcc, 0x3cf80f11, - 0x54fcf787, 0xd08dff10, 0xda20d15e, 0x927eb0fd, 0x95f01971, 0x70283762, - 0x6cdf3c69, 0x91d7431e, 0x5f60d675, 0x3378874e, 0xcffa05f0, 0x2fbcfee3, - 0x5357f40e, 0x8273c240, 0xa3bbb3ac, 0x60e4a816, 0x3e0379d3, 0x5bfcf37f, - 0xd881e7da, 0x2dbde0cb, 0xef17e606, 0x28f7fbde, 0x9e6f4b90, 0x82f1c6ef, - 0xbb4f4376, 0x6b91e118, 0x67718315, 0xc44c5db5, 0xb79003ac, 0xaa9a2d35, - 0xbb77a131, 0x7213fb37, 0xb4f495bf, 0x1ec0721f, 0x11d8c311, 0x3e74ce1c, - 0x6f48f809, 0xe36e5c57, 0x24c1e6f1, 0x6ca3ee1d, 0x18b71f3c, 0x8a6e1fbf, - 0x7d472fb2, 0xaea5eccc, 0xbf1fa7dd, 0x13ef9e06, 0xe711fdd9, 0xb7a7e445, - 0xda1e2e76, 0x2a5be2a6, 0x5f4f1139, 0xf9db3ff5, 0xd5ffed06, 0x4716489e, - 0xa9979c97, 0xf50877bf, 0xf97871f7, 0x38f3b007, 0xd7b800ef, 0x2fdb07e9, - 0xfafc3d1d, 0xc3da1b3c, 0x1ea0e981, 0x376bac46, 0xac5bfe02, 0x90d9d7f9, - 0x00a3eadf, 0x33925e2e, 0xf3804c90, 0x7403927a, 0x7626a815, 0xb5b627f0, - 0x97800c18, 0x98c98d8c, 0x9f89b3a7, 0xafaa2e57, 0xe8ab2635, 0xef3f1162, - 0x877b293a, 0x1f9eaac4, 0x72f931b0, 0x6fe94f72, 0x43e34f30, 0xc61e1913, - 0x31b06cde, 0xd18afb7d, 0xe866cd7b, 0xdf80c477, 0xfbdeed0d, 0xcfb85efa, - 0xc761d178, 0x3dff8858, 0xbf607362, 0x6a9b7dc6, 0xf1b7cf20, 0x5452d013, - 0x14286caf, 0x37de740d, 0xefc58388, 0x1fd0180e, 0x893dc60f, 0xf9f60e2b, - 0x1bcf5f10, 0xf9cd062d, 0xdefc1bd8, 0x326d7bdd, 0x89b12fb6, 0x2dadc788, - 0x37a07139, 0xbbeeac5a, 0x8e2fa06d, 0x12c0d5b5, 0x629f7894, 0xb03c4daf, - 0xf4d19af5, 0x061d89cf, 0x71dba03b, 0xf61179e0, 0x484938eb, 0xd87a408c, - 0x8f3c746f, 0x3a37bc7a, 0x1d7478d8, 0x2abf016f, 0xff9aa7f0, 0x7f5a34a1, - 0x858a55a3, 0xfe052efc, 0xf9943eca, 0xb5c4f51d, 0xe4ac82de, 0xb8817ada, - 0x3a5f92b3, 0x7f944ece, 0xd2e9012f, 0x6a3d7368, 0xda0ef663, 0x30f727d7, - 0xae15e8bb, 0xe1524947, 0x829f8050, 0x8b1b7aa7, 0xe9eb2a33, 0xdbdffe6d, - 0xca549e98, 0x9bd74bef, 0xe9178764, 0x0fcb1b66, 0xe6fd7877, 0x6b23c854, - 0xcf7fc54c, 0xfb679549, 0x93e7a47b, 0x1b057bda, 0xf8060cdb, 0x8762ac0e, - 0x6de68310, 0x20ebed1f, 0x48f5499d, 0x09878d7f, 0xdd6971f2, 0x48ee2c9d, - 0x7fbf0de5, 0x81d1cf0d, 0x7a79f87f, 0x1396817f, 0x18afd69b, 0xdbf5f088, - 0x7042af80, 0x65037ca2, 0xe811ad55, 0x5652d175, 0xe973f316, 0xc8dd6b45, - 0x58eb459f, 0x5b1ee17e, 0x0ce7ae32, 0x886257a7, 0x27f9001c, 0x657f0e2e, - 0x6e9c79dd, 0xd13c354f, 0xfa52f30c, 0x73e013fa, 0x4f63e352, 0x7a1572c3, - 0xc641b53d, 0xb5224a71, 0x7cadf6e7, 0x18076dbc, 0x20dc4fbd, 0x5ffdc0e7, - 0x0ec4bd13, 0x3637ec71, 0x7e41146c, 0x9cf401bf, 0xf41cf8cc, 0x0f3dc9ed, - 0xf402fd46, 0x4081bb5c, 0x2315fcbc, 0xe2a2d929, 0x5febdd8b, 0x696ff0d5, - 0x1835f55d, 0x158b6f97, 0x7c2bce40, 0x15fdc0ab, 0xe42af3a3, 0xfc74ebff, - 0x2fbd953f, 0xdfb03b47, 0x9fff9c13, 0x9ff94198, 0x10d98a3e, 0xaf38c023, - 0x07dfc318, 0xa40ff5f7, 0x6d5ca0bf, 0xbf5721eb, 0xcdb57266, 0xafe74a96, - 0xe31bb6b8, 0x71f5c10c, 0xaa6279ba, 0x02c93742, 0x6296bfc0, 0x8bc01870, - 0x99e815c2, 0xdfb7cdda, 0xd95c8690, 0x0f39e122, 0xf9e2473f, 0x0277ca1f, - 0xe486bf0a, 0x6eb7c299, 0xd5d83473, 0x8056ab53, 0xe7971f5d, 0x253cfa45, - 0x52c687b8, 0xf80a767d, 0x383c8c38, 0x57c7e5c1, 0xf762fbb2, 0x7a000fee, - 0x221ea12e, 0x13ac87ec, 0xa51780ec, 0xdd8eb1dd, 0x5a3c3ac3, 0x2bbf9cd0, - 0xef0c1ff5, 0x41fb8f40, 0x7c634787, 0x3c84603a, 0xa63e11d5, 0x839088c7, - 0x570c40fc, 0x5b3e000f, 0xcdd7f544, 0x4a75fd2a, 0x553a45ae, 0x347970e0, - 0xc55f5f93, 0x95ff7db0, 0xe21585d3, 0x2f73aa85, 0x024890ea, 0x605167e3, - 0xf8c22e7c, 0xba4cf6a7, 0xdafde90a, 0x076ef4f0, 0xfe162aff, 0x48f5a73d, - 0xec33319f, 0x13cb1df8, 0x46223392, 0xb0f91f63, 0x57f1bddc, 0xfd01d7e8, - 0x46f7bf02, 0xff4025ff, 0xfbdd0c24, 0xf0abdd28, 0xa501d0a7, 0x55a26b8b, - 0x174f41f2, 0x02a379ca, 0xe7745797, 0x33474f95, 0x9780b079, 0x66f25e8e, - 0x60fcfd94, 0x81ec9f3c, 0xcf0cf9e7, 0x7c02be21, 0x67e1f22b, 0x3dafe117, - 0xaf6c76d1, 0xe60174f9, 0x73f2d4a9, 0x9f3e7aab, 0xd1a5eeb2, 0x4b7ce682, - 0xca34ee7f, 0x5a2bbee2, 0x48ea3e77, 0x34c7d10b, 0xd92ecf6e, 0xff73c268, - 0x7802d02d, 0xbdfecddb, 0xbb3de56c, 0x0a4f0d44, 0x4cd115ea, 0xe1f42b8e, - 0xc3246658, 0x55f2ffa8, 0xc86ee172, 0xab59f9ff, 0xdd346f37, 0x77a316c7, - 0x07e8b5f6, 0xf182af38, 0xd833caaf, 0xc6241f21, 0xde201765, 0x7c0a2481, - 0x33cd8fb8, 0x1979d52e, 0xe70ec9fa, 0x0f079038, 0xf8297c73, 0x9bd0e055, - 0xaf0deb9e, 0xe27c387b, 0x8e5ebb79, 0x9efe7314, 0x5c5dfbc2, 0xe045788e, - 0x2f711b27, 0x59fd6117, 0xe505fe4c, 0x73c11648, 0x727597c9, 0x5e9fe5e4, - 0x91acbc8e, 0xc2da1323, 0x0bfa11ca, 0x1bf1ffcb, 0x4b1da216, 0x63b7870e, - 0x3d334677, 0x93fa0f1c, 0xb2f78bf6, 0x3987def3, 0xc48a52dd, 0x0ddac9bc, - 0x5713cc26, 0x366d90e4, 0xaf7f81c9, 0x16fa06d9, 0x1f76cd7a, 0xc5e70c9e, - 0x9c074649, 0x03929f5f, 0xd453f788, 0xfa45af01, 0xc7fbc7c8, 0x0223c8c3, - 0x47ef12f1, 0x9cefd083, 0x9f213626, 0x5046992c, 0x78deee7f, 0x4955d205, - 0x74008a5e, 0x23175a5b, 0x54ec7b40, 0x94e401bb, 0x962b8fb2, 0x71b0c819, - 0xd40707c8, 0x6f0ae472, 0xcdbbfe15, 0x49dce343, 0x47210c72, 0x33fb3d1f, - 0x8da8bc75, 0x22f1d5d6, 0xfbe07f5a, 0x468e8bc4, 0x78801e07, 0xae6c3fd1, - 0x94779876, 0xea28ff25, 0x912ac4b7, 0xc5d6e4a8, 0x4a1fb7ec, 0x2e3c952f, - 0x34a95a45, 0x81c4d04e, 0x6073ab6f, 0x582bf81c, 0xe380c54f, 0x7870c34f, - 0x7b5846af, 0x1fa3ad9b, 0x13e40b97, 0x97e8f882, 0xfc42255f, 0x063b9145, - 0x2fe2ac7b, 0xa197900b, 0x037fdbf0, 0xd7b57d1c, 0x00008000, 0x00088b1f, - 0x00000000, 0x7dcdff00, 0xd5947809, 0xe77df0d5, 0x24cb2d9d, 0x7642c993, - 0x03bbec26, 0x4eb1ab09, 0x04906008, 0x8d441007, 0xb0900938, 0xd2910364, - 0x208196d6, 0x2b188a06, 0x0eb154b5, 0x4551fa14, 0xdb1ab61b, 0x1a4013a0, - 0xad563414, 0x61a5afd8, 0x80891d91, 0xe58ad3fd, 0x7bdce73b, 0x264ef333, - 0xe79f6a02, 0xcdcf0f0f, 0xcf7bde5d, 0x773dfb3d, 0x79632d49, 0x9b19223b, - 0xed50b390, 0xccc9a906, 0x831b163c, 0x43632f1f, 0x087a3e79, 0x6b9859e6, - 0xf26b6320, 0x01de7975, 0x9fc75d8c, 0xa269fd3b, 0x678e3e15, 0x30d6fe6c, - 0xb53349eb, 0x7fe1d767, 0x268c5d79, 0x649f595f, 0x9fc7d93d, 0x24bf8f9f, - 0x4c33ffc1, 0x2b1812cf, 0xe1a7e263, 0x70ffdfcb, 0xdfc7b418, 0x54dec655, - 0x805689dd, 0x12dcdca7, 0xd8ceddd5, 0x13c7f933, 0x52d491dc, 0x223ddf87, - 0xb97178c6, 0x71debde3, 0x55de798c, 0x0fc816d9, 0x4a3d1936, 0x64e2fc34, - 0xe8826b76, 0x06947e0f, 0x041967c5, 0x55437ff9, 0xfe97632c, 0xc5f4a3ad, - 0x32f2b89f, 0x7a8afbe0, 0xb439639d, 0x185068ab, 0xd1cc62cb, 0x19cd7995, - 0x4785d58c, 0x5fd0620d, 0xa748bece, 0x292fca01, 0x8329af66, 0x870800d1, - 0xa23fc241, 0xd41b7d35, 0xd8983757, 0xca5ec86a, 0xe119ac61, 0xd9a23bd5, - 0x077e3f00, 0x0fa67e1d, 0x6bca00cc, 0x630b2e1d, 0xff78c29b, 0x7b64c29b, - 0xb483347b, 0xecd192db, 0xd7a7c004, 0xf40d1633, 0x6983c481, 0x036e92f6, - 0x1f3099f4, 0x8018f33d, 0x3eadd94e, 0xadd2f115, 0x9163aed5, 0xadf471fe, - 0x4ddbe68c, 0x6039d76f, 0xf7813afc, 0x543b4d9d, 0xd873e03d, 0x156ada98, - 0xf728d2d2, 0xa8f3c458, 0x2c6aaaec, 0xa8f7cd8f, 0xa59f686e, 0x00b3ed54, - 0xe678d85e, 0xcce502d8, 0x848f8307, 0x18d616fa, 0x2398d905, 0x2828ce2d, - 0xd9c6751f, 0x1de60038, 0xf60a62ed, 0x1a32d8c7, 0xcba45fbf, 0x38b2fd85, - 0xfd0052a7, 0x2307fb0c, 0x767ec8bc, 0xec568d36, 0xf35c6f00, 0xc01ec518, - 0xe24d305f, 0xfeccf5ab, 0x73d7ec53, 0xba40e748, 0x7398ebda, 0xfaefb423, - 0x2c31bf72, 0xd2bedfca, 0xb778d0aa, 0x46b9ddbb, 0xd879f346, 0x9c8fdf0a, - 0x0067ddee, 0xf1cf8678, 0x03da33ec, 0x519733e6, 0x1e2d297f, 0x11d2479a, - 0x8ba60e77, 0xcfd4312d, 0xc6be33a8, 0x4baed001, 0xca07cc15, 0x543f9ad3, - 0x5569af10, 0x71d20acd, 0x825ed367, 0x3f79b537, 0xea11814f, 0x7201dd20, - 0x8f301755, 0xcd1d16c5, 0xa145b163, 0x99c5e574, 0x7fa82e89, 0x6c5eeac4, - 0xc79fea19, 0x62771cca, 0xbebff415, 0x7cfb5ba9, 0xb7bc027b, 0x278867c1, - 0xab72dfd9, 0xb269fa91, 0xf3847fb8, 0x72de9cab, 0x476f7900, 0x48a39fd3, - 0x88e21a2e, 0x8e8709be, 0x96123d13, 0x78a0ce00, 0x0a85a1fd, 0x85f5aa83, - 0x23a53340, 0xddb8279e, 0x8899318e, 0xf89f806f, 0x09311ac7, 0x8c62f2f8, - 0x91c706bb, 0xd91427ed, 0xb45f5022, 0xcf77c5e7, 0x598e652e, 0xfbcf003d, - 0x6eb2778b, 0x12f77748, 0xbb7b7ba4, 0x21878f81, 0xb38b313f, 0xa4bbfb16, - 0xce38e9b0, 0xf942984b, 0x979e064b, 0x95abfaf8, 0xeb11ebe3, 0x7896c5a4, - 0xf02b278e, 0xbc614bf1, 0x7a1eb05d, 0xb3bfcad7, 0xcd617e0b, 0x1e705f9c, - 0xbb64bfa8, 0xdbdfa2dd, 0x3d5cee9d, 0x08cd93e7, 0xde11c8e7, 0xc3b7c87d, - 0x90fb3cf3, 0xe098d3ff, 0x27ce3c93, 0xcfbefcc1, 0x467ea36a, 0x8865699d, - 0xb9852cf7, 0xd32ee902, 0xa1ae10d7, 0x89a3dfc8, 0xb61e407f, 0x52c378e3, - 0x800354aa, 0x13acc712, 0xdec67758, 0x5da9dab6, 0x3ee708e6, 0xd3ab37e4, - 0x207cf245, 0x2be54ac2, 0xc07f3833, 0xfc407ff7, 0x2ed3cb05, 0x7e01a394, - 0x7e438a39, 0x8fc8ec8c, 0xbcf013bf, 0x63a5e42d, 0x613feeff, 0x3acd71ff, - 0x0c9d02a7, 0x65e9123f, 0xa2f874d0, 0x8fe1152a, 0x00ffc063, 0x358e6da0, - 0xa52ce507, 0x5d20a1cc, 0x875c229b, 0x230fd4ad, 0x4732b9bd, 0xef86ade7, - 0x893b46e6, 0x3ed8df7e, 0x366667ec, 0xc01f6fcc, 0xe115fc1e, 0xb6b07b03, - 0x6ff4f508, 0x3d4469ff, 0xd7f2976a, 0x38a22434, 0x48ae3f80, 0xf7a7e0bd, - 0x410bd271, 0x73d60ef4, 0xebf6f4c1, 0x039ead05, 0xf4e05d7c, 0x9f226770, - 0x522f35c5, 0xead07eb9, 0xd1e8ceb5, 0x3a083f41, 0x7e708a5c, 0x0c5cf881, - 0x7ae38832, 0x583eb346, 0x0e1d99de, 0x76a4898b, 0x1c3b45ff, 0xd1df1316, - 0xadcceb0e, 0x47c01507, 0x576a8379, 0x8fd50a61, 0xff489cd9, 0x8714eb17, - 0x41a4e509, 0x71787e25, 0x4bd93865, 0xbb67ef09, 0xdbb107a3, 0xcff21520, - 0x8ec9dddc, 0xf188c656, 0xf18790ed, 0xd679592f, 0xc5277568, 0x1793e804, - 0x4308be1b, 0x644ff73c, 0x62c64e03, 0x0ed6a70b, 0xf0290883, 0x537f09bd, - 0x6b83af10, 0x69ac1454, 0x95269dee, 0xfb1dd6e8, 0xfe5ace1b, 0xbd700d9c, - 0xceb46dbc, 0xf537c81d, 0x05ec6757, 0xb8232bf8, 0xf7b4be5d, 0x33e42f5a, - 0x92f77f59, 0x3f7bd262, 0x13192b07, 0xeedf1fa0, 0x61eb8273, 0xd53d6856, - 0x2a76871f, 0x850023d7, 0x7a3ee651, 0x70d427f4, 0x27f5aa87, 0x7baa3988, - 0x7f107e02, 0xbf84e18d, 0x77209eea, 0x48e70419, 0xc5bf7fec, 0xfca092c8, - 0xb623c80a, 0x037f7093, 0xe2074778, 0xaa6f0fd1, 0xe08454f5, 0x5f0fd50b, - 0x0e905d3b, 0xd16abfd0, 0xb12e3cd3, 0xb3d20770, 0x4864e8ce, 0xe151cf7f, - 0x55ba081f, 0xd4bb9e08, 0x1b88f430, 0x91e2f7e6, 0x7f7e0754, 0x984afea9, - 0x46fd122e, 0x979c14f7, 0x851ad69a, 0xc35f70f6, 0x032dbe95, 0xc54dbf48, - 0x4e872bf2, 0xbe03dcd8, 0x8466fcd1, 0x7e7687a6, 0x9ac8fa95, 0x6150ff40, - 0x7cc17e7c, 0xfe3434a4, 0xf244194b, 0x7a1f50c7, 0x1ab799d2, 0xa072bde6, - 0x997ba7e0, 0x983ee51d, 0xabab46de, 0x6e402622, 0xaaed15ff, 0x9c70b842, - 0xcf342194, 0x741f9885, 0x41a66678, 0xc31bf387, 0x7f4a6ed0, 0xb0effd0f, - 0x4eff7e21, 0xfe7dafce, 0x3a0daf3d, 0x3fbe68c4, 0xf80071c6, 0xaf803ae5, - 0xeac18c12, 0xfb79c08c, 0x62e51e88, 0x48e6e57e, 0x61f30a9f, 0x5a170cbb, - 0xd6e81ea4, 0x4fa07e11, 0x19e7c20d, 0x46e238ed, 0xd235fefa, 0xd1f88d51, - 0x5fd15b37, 0xc6acf985, 0x28a2367a, 0x2fdfe711, 0xf505b9d2, 0x18cb4bfc, - 0x57a5f3f1, 0x4c137798, 0x1d7efb76, 0xd646cbf1, 0x9fbef88f, 0x570cf2ee, - 0x3af3c924, 0xb9ab3b84, 0xb77a8756, 0x43aed7a7, 0xb9b7da7d, 0x3e23a74e, - 0x8622ff70, 0x5799e4fc, 0xff5f00f4, 0x37ea556d, 0x686f07e4, 0xaf40ef7e, - 0x92f481cd, 0x7c16cb78, 0x43788d90, 0xbfaad083, 0xe3f662d0, 0x52c3e80d, - 0x63fb1d6c, 0xf11d25ac, 0xe9faf8d4, 0x5fd02d5e, 0x67a71bc5, 0xfe2a5e20, - 0x18262260, 0xd1be87f3, 0xe59fefc8, 0x2e67f684, 0xe872ad2c, 0x257a9fc1, - 0x85d91ba6, 0x446cd632, 0x6ebca13f, 0xa01f4381, 0x76ffa5cf, 0x8f9cd0c8, - 0xaa1a1ffd, 0xe78065b2, 0x5de18e2b, 0xd13b0858, 0xbfa12fee, 0x472fb006, - 0xafcf11d8, 0xff734567, 0x20f646d1, 0xa5a1fdb8, 0x7a631c73, 0xa1dfde74, - 0xbdd361c1, 0x907e7df0, 0x8634741f, 0x18b6b5db, 0x2141876e, 0x8bce113b, - 0x3d78b7bf, 0xc8717450, 0xfd0c5147, 0x641f5dcc, 0x2e8f807a, 0xfe47e6b2, - 0x35767288, 0xf971d692, 0x5cca3f83, 0xe5cbf166, 0xdcf8231d, 0x70ed78ef, - 0xe7da1d94, 0xe717df6f, 0x1ddfc009, 0x9db57f4c, 0x5c7033af, 0x7d33e346, - 0x07a42f4b, 0x04d9e3fb, 0xaff9a43b, 0xf9c715bf, 0x74874120, 0xdbf4245e, - 0xc028b0ef, 0x525fcedf, 0xf3247c41, 0xe6666de5, 0xebc80d8d, 0x04b88d9b, - 0x648b6f2e, 0x37b7685e, 0x7a4712c6, 0xa3259926, 0x5f14e99e, 0xe0cf8937, - 0x43cf8972, 0xa3a6cf83, 0x2759f15f, 0x1b6f70fe, 0xf7ced76f, 0xd74fc14b, - 0x7ceff3fb, 0x0aec3ea5, 0x8d845df1, 0x638ae9d3, 0xf7f41764, 0x1ebe8df2, - 0xe4ed10d6, 0x4f1832fa, 0x8d2b5f6f, 0xdf7f7ec0, 0x050bca66, 0xfba6de97, - 0x21ca7e76, 0x1fc02a80, 0x53baa6dc, 0x9c1fc26d, 0xbe8af90c, 0xbad1c657, - 0xd08bf25a, 0x4f30777b, 0x306fca23, 0xf77a487f, 0xfadd01b0, 0x296672a3, - 0x318bb748, 0x4237ce76, 0x047ca41e, 0x9d3831e3, 0x50ee6460, 0x62af80eb, - 0x98c35e24, 0x23e1f407, 0xdf640d1b, 0xf8fb5f0f, 0xf7e04cde, 0xd60c1bd3, - 0x9ce430e5, 0x3ea5f617, 0x0673f503, 0xe40aac9b, 0x3d7ddb4f, 0x5f4bee50, - 0x0fc85d50, 0x923c37a7, 0xf3d21330, 0x0065bf20, 0x0346e947, 0xf8d9cf95, - 0x159f9528, 0x42fa5d72, 0x97d47f7c, 0x4eaff787, 0xf9ce3a40, 0x486989ea, - 0x6b46ed97, 0x9690c1ff, 0x631c536d, 0x6f3df002, 0xbf269873, 0xe0e6c75d, - 0x995d243c, 0x47af6ee2, 0xa6d53f13, 0x1f7176fb, 0x04dfd69f, 0xa0aa72ff, - 0x3029c4e3, 0x57a18aef, 0x77dfafc8, 0xc9ec9c20, 0xf92a919b, 0xffc1be8f, - 0x20db9def, 0xde95fb9f, 0xa09dbe41, 0x674158f3, 0xb7a45cb0, 0x9f3ccc4b, - 0xfc9ebafb, 0x4a8b5ccf, 0x91f686f8, 0x7bfea163, 0xf40fbda2, 0x5321ca2c, - 0x848dd7b3, 0x0da36376, 0xf7d0ed0c, 0x19f2f37c, 0xdb3bc9d8, 0x025bc7f4, - 0xd59a33e6, 0x387f41f6, 0xca821987, 0xcf2c7a9d, 0xc7cb6b35, 0x2cfbb8f6, - 0xad630ffa, 0x77c972da, 0xfab4d88f, 0x7381df62, 0xf3009b3f, 0x92a4392b, - 0x7d237cff, 0xafc22efc, 0x5dbf3a47, 0x3bbe0db8, 0xf872b02c, 0x4915e9da, - 0x142357c8, 0xd3acf186, 0xe3cb42d7, 0x665ea41f, 0x7e3edf40, 0xe63816fa, - 0xdc51e7b6, 0xa0b119ef, 0xdff08f3d, 0x7afb1ebc, 0x8d9b753d, 0xed8233c7, - 0xfcdcb046, 0xfe46ecb7, 0x3dd2b7e0, 0x837f4a16, 0x5ced85e9, 0x89eb06ef, - 0xe1213b60, 0xbcb7860a, 0x0fb1a74d, 0x191ea15f, 0x8c27681a, 0xc3be2764, - 0x6d8370f5, 0x30f5c768, 0x2f8431f8, 0xad3d30cf, 0x6adfc1c3, 0x220376c4, - 0x0039b1ed, 0xb76b0ad2, 0x167fb208, 0x405b7ef7, 0xb6ffaa1c, 0x8dea1d5a, - 0x418cf8f6, 0xeb91a71b, 0x9d8477d5, 0x1cfa13a8, 0xceb4abd6, 0x4eee18df, - 0xc9b8e3d4, 0x8c96c746, 0x48f9f88e, 0xcfccefb4, 0xbeac7e95, 0x8fb1fb86, - 0x389a5d58, 0xa893eb19, 0x5fa2fb89, 0xd9edf28e, 0xfcf34e1b, 0x420d7154, - 0xe733d439, 0xf4016ddf, 0xf87036a9, 0x8f89e183, 0x319276e5, 0xb207f917, - 0xd0e8f67c, 0xd5895c7a, 0x679cfb53, 0xff474fef, 0x07c6d3ed, 0x7ebf51d2, - 0xede7141a, 0x169e1e4c, 0xb0a4faf2, 0x2e223123, 0x11ca14f0, 0x9dda41e4, - 0x55fbe1db, 0x57245d4b, 0x9d3a5d3f, 0x2e9667d2, 0xb613faa1, 0x9adf1a0c, - 0x775767f3, 0x35c9d3c0, 0xd989d92a, 0x18af5746, 0x59a4eef8, 0x1385f147, - 0xbb799155, 0xd19cb122, 0xb3f6727a, 0x0278b613, 0x6c277ee2, 0x6743a27a, - 0xfd8f8cf3, 0x9cbdfa66, 0xbda144b5, 0x23d7e76a, 0x2db5ec1d, 0xac7fe316, - 0x55db0125, 0xb6bdcd2a, 0xb7c71d29, 0x2c7c6732, 0xf59197f2, 0x0ba9b947, - 0xb828f6e7, 0xe72c4a5d, 0x1fa1bfc3, 0x8a7efd0b, 0x9e842b76, 0x2f3a0bb1, - 0xb1ed38b4, 0xc922efa4, 0x81b8275f, 0x728cbe5f, 0x60b84776, 0xd313d65d, - 0x7c785d61, 0x2ac5b16e, 0xf0a9c3f8, 0x5fab8e75, 0x5bf8886c, 0x609ef167, - 0x7811de38, 0xc9038e0d, 0x8681c654, 0xbcf9f2c6, 0xe26ab36d, 0x0eff1842, - 0x79f9ff15, 0x1ba3d72c, 0x2a3c5bc3, 0x7c03c3ca, 0xdb25de3d, 0x2b7c60a3, - 0x0736bf25, 0xc5775fe3, 0x2da5b8f2, 0xeb889dcf, 0xa344e4f6, 0x3736e303, - 0xea038f2b, 0xc05f7c9c, 0xd63823ad, 0x7ac27b37, 0xcd095c01, 0xa4231cee, - 0x0d317153, 0xaac2edf8, 0xa0dd2196, 0x6b23211d, 0x9157b87f, 0x92686c8b, - 0x4028f429, 0x6772861a, 0x454f728c, 0x559b0cba, 0xfa718d55, 0xffbe3294, - 0x77715670, 0x9c9f01b5, 0xa43c2b7d, 0xe8225c3f, 0xc9d194cf, 0x36b3fa68, - 0xacae081b, 0x819f3fcd, 0xf9b59f7c, 0xa012bd2e, 0x1ac79687, 0xdf67fe68, - 0xe295d79a, 0x58989f16, 0xea7a10cf, 0x1e5f8287, 0x69d87410, 0x8b7fcd0c, - 0xac6fbb45, 0x55405bcf, 0xe2f9f569, 0x5b3880d8, 0xd265f945, 0xed6393e7, - 0xfaf3ce34, 0x80c903ba, 0x3167e7cf, 0xe68a0787, 0xf148dd6d, 0xbac69dd7, - 0xe4efb8f1, 0xa431d0a9, 0x7f03fefb, 0x7e8c9038, 0x60fb2ce4, 0xbfda23f4, - 0x4ad2f43f, 0x0e7e7f2c, 0x4ff88c1b, 0x60ad3ef2, 0x619fe63c, 0x7faf84b5, - 0x65b1316e, 0xbf7db718, 0x210ffc6e, 0xc74cbebf, 0xcf04bf50, 0xe832461b, - 0x19f53112, 0xfd382374, 0xba4a0f51, 0x91190303, 0x886e921e, 0xee90edbf, - 0xc11af2df, 0x2a9ae12f, 0xb6f3dee2, 0x7c8f1f6e, 0x53665c92, 0xe1204e30, - 0x793d91ba, 0xd9dbf631, 0x0ed0ef93, 0x221b12bf, 0x0ec21d2e, 0x610d88ef, - 0x2fed8387, 0x637738b3, 0xe1d91bbb, 0x36ff82e1, 0x7fed06c6, 0x08597ee0, - 0xed8d0dba, 0x1fdf0f10, 0xe3ff621b, 0xdef0f146, 0x43ff72b1, 0xc97f0f1b, - 0xad6ff5c8, 0x293c3d8d, 0x1374bc84, 0xb5d6ebe3, 0xc67ed11a, 0xf5212835, - 0x518b62d9, 0x1c7e1fee, 0x125fb01b, 0xe0438fac, 0xefb628f7, 0x17b7cdbb, - 0xe9890d5b, 0x5bee8111, 0xdeb0ebbf, 0x29ce310d, 0x22fb3f81, 0xf6a6fb46, - 0x0afa462a, 0x141e5ef2, 0x371429f4, 0x934f38b0, 0xbec1badd, 0x1cd69dd5, - 0x3ee483f2, 0xd6ab54d5, 0x938b8c4f, 0x239f9ced, 0xd89d699c, 0x3c097f89, - 0x70dbfcc1, 0x4c45b8dc, 0xf7231fb3, 0x3caae261, 0xcd0b318a, 0x6af8a311, - 0x32f758d7, 0x1d6bb403, 0x209b1cc9, 0xcd685d1f, 0x9b6a7d41, 0xfdc468e3, - 0x7917959a, 0x02e57e3c, 0xfd4e5de6, 0x7732f9f0, 0x17ca2f37, 0x2e302dd2, - 0xe1c71110, 0x72e38888, 0x1cd27606, 0x8f0ae1c7, 0x9293b00b, 0x3e75ba1e, - 0x1adae895, 0xd0054eda, 0x77df46d5, 0x50efd742, 0x3771ed2e, 0x8cf71fe7, - 0x19be05bb, 0x7c737718, 0x4b4c14f3, 0x8f04dfec, 0x0ff38997, 0x2cf80f1e, - 0xf826ee2b, 0xee2deaec, 0x50881e8f, 0xa5dc5dbe, 0xc4275e23, 0x6b77d085, - 0x487d75f2, 0x4770b35f, 0x233abb28, 0x7dbff22e, 0xa086645e, 0x179d2df7, - 0x2d27f179, 0xdcb3a446, 0x06f090f7, 0xe591139f, 0x264a0d15, 0xf6733fae, - 0xc075a35d, 0xd37fc6a5, 0x79e3a03a, 0x42ee3e0f, 0x678003e4, 0xcea03aac, - 0x7977f207, 0xea56919b, 0x22ffb32a, 0x4df6e31b, 0x53b5e606, 0xefb6337b, - 0x7efb78c7, 0x633656db, 0xd31faadc, 0x547ac47b, 0xa8fdceb9, 0x7ee39468, - 0x8d5b2a4d, 0xbebcadf9, 0x6197998a, 0x847a3a5c, 0xf003d98e, 0x670ce319, - 0xc67c00f6, 0x7934d9e6, 0x2f9e4eb9, 0x25778dc6, 0x32efbe6b, 0x7da69bbd, - 0xa69fbb92, 0x10ce653e, 0x6aad3e4d, 0x577da694, 0xf981cfb0, 0x9addcf0c, - 0x266bddf6, 0x6b3df26b, 0x3fb4d01f, 0xcd9eaacd, 0x9c7a79c6, 0xce003dcd, - 0xdece0259, 0xdf358beb, 0x0dd5d7f5, 0xf920a1f3, 0xffee1f14, 0x326c16cd, - 0xfa73c44b, 0xfa69e77a, 0x5e6aff3d, 0x9df80293, 0x19386b5d, 0x7c219f18, - 0xea4b7e00, 0x8c1cf615, 0x5b5eba5b, 0xe9e1a73f, 0xce902995, 0xe7cb6af5, - 0x829cbee1, 0xdf2dadfc, 0x823d73ad, 0x71ed9deb, 0xe228ce22, 0x7f03ac3d, - 0x97b8d244, 0x9778f037, 0xc41de9ea, 0xb13a5a1f, 0x762fc96f, 0x44a62fc1, - 0xd984bf2d, 0x7a52fcb5, 0x1f30e770, 0x88ff88eb, 0xe47c413e, 0x78017f81, - 0xf895f897, 0x7cb438b7, 0x9de15df5, 0xdb91af31, 0x3ff96d0d, 0xb5f1b4e2, - 0xe3ee917e, 0xd4aeb7a8, 0xbf71522f, 0x7df1e58d, 0x57f52bfb, 0x6bb21d07, - 0xdb3ad7f6, 0x17173a4f, 0xfb175718, 0x3f709749, 0x137636f1, 0xfefb89fb, - 0xd900f885, 0x1f801b77, 0xb98708d8, 0xcc30ff7d, 0xac147fbf, 0x760a6537, - 0xb238cbe3, 0xd77dfe27, 0x587af86a, 0x085c5ff4, 0x9387dcaf, 0xf9e472e7, - 0xe7c91621, 0x3c01fb29, 0xf143f1a8, 0x022d9ffc, 0xf7dbadd7, 0x96f5a42f, - 0xc4c43f3c, 0x7e10bfb9, 0x3aefe93f, 0xfc8935fc, 0x6e78f081, 0x6d3123cf, - 0xf9c407f7, 0x3bcf692e, 0xb7ee47eb, 0x7b2a9675, 0x6c3fda55, 0x9b1dc255, - 0x5e93d842, 0xfd72dff1, 0x1c43a675, 0xe07c57ba, 0x2bd1ebfa, 0x00aed007, - 0xb962fbde, 0x5af602c5, 0x5febdbf1, 0xbf114444, 0xbd541eb6, 0xb2e0a1bd, - 0x036d1ed9, 0x6984363c, 0xab4c88ed, 0xf403c9cc, 0x3daf58b1, 0x11f727e7, - 0x6367db83, 0x27fd80fb, 0x8fe34ef8, 0xfdc21cac, 0x6e78ecb5, 0xe488bfdf, - 0x9114c1fe, 0x175a0caf, 0xbf70d655, 0xe9f8236c, 0x4cfd010d, 0xfb50b789, - 0x533911a5, 0xc08e29e2, 0x332bbbd7, 0x5627f214, 0x21f90a2a, 0x5347a267, - 0x9cb8b5fd, 0x623fc4c9, 0xbbe8299c, 0x6edaffc1, 0x38bb1e1c, 0x37fb238f, - 0xe6f6f3c7, 0x4e94d1f8, 0xb88ab789, 0xf21fb5b3, 0x93846547, 0xa1aa35fa, - 0xc7a6a5f7, 0xb5ad79f3, 0x6a27e930, 0x84e3fee2, 0xbf38c4de, 0xf9a3fb89, - 0x71fc1363, 0x7f66a67e, 0xf1138c68, 0x773e857d, 0x53ba9ea2, 0x78b3bdd0, - 0x758fb3bf, 0x75276e3f, 0x12fbf78c, 0x1dfbc643, 0x0fde28e3, 0x5e71ea5f, - 0xa47f71c1, 0x2fcd8443, 0xb7c48f3f, 0xd45483db, 0x7746f54f, 0x5abbae35, - 0x0eff8377, 0x2dbc7dc5, 0xf0301fb4, 0xae077750, 0xb06656af, 0xb7e416bd, - 0x7fa18c65, 0x5ba2df5f, 0x6bf5061e, 0xf58acc3c, 0x75f03723, 0xbb7ae95b, - 0x8069a703, 0x8865b075, 0x8bac1f5f, 0xd7bc218f, 0xc46e4cb7, 0xf73581fd, - 0xa19a1b32, 0x1b9b565a, 0x06d0fe85, 0xf8dd7216, 0x09b39094, 0xd4557b39, - 0xdfe8f117, 0x53d3a087, 0x0fa04e82, 0x879d22d6, 0xf0afbab7, 0x4fae38fd, - 0xfae22548, 0x1bcebf74, 0x373f3d6a, 0xf21d773a, 0xe86f40c1, 0x0b5ac3f5, - 0x1175b7e7, 0xdda8e7ae, 0xb5ee7e2e, 0x59dfea54, 0xba07a63a, 0x9d74114f, - 0xdf9f81b2, 0x5faed760, 0xc89fa557, 0x7a867fa8, 0x8b5ef4a5, 0xa543e317, - 0x821e190d, 0x7a38a5cb, 0x7868bea2, 0xd2f985df, 0xc62b2cac, 0x657f9c23, - 0xe43ea9ca, 0xbfae3262, 0xd494ecf4, 0xe3c76427, 0xb269df68, 0x16b5b7e0, - 0x0d473f3b, 0xfc008e28, 0xb6586e97, 0x7cefcf17, 0xfb466bf4, 0xd6d4474b, - 0x54d9d861, 0x2192ce40, 0x2159ea98, 0xfef82bc5, 0x1fa2bdd5, 0x5c61bfcf, - 0xa9dc7fb3, 0x3e69070d, 0x63cc0c47, 0xb4ba3e06, 0xfa3b3ee7, 0xcde32bdb, - 0xfb93c714, 0xf75547b2, 0xf48464e3, 0xda0815ad, 0x56110dfd, 0x43fc7f8c, - 0x82465df0, 0xc7d21f7b, 0x057c7cbd, 0x6596c1da, 0xa3c474a6, 0x1a92797b, - 0xd7ba7007, 0xd1ef342a, 0x788c93cb, 0x8ae6617e, 0x4f50e3c1, 0x95ce610d, - 0x2879df18, 0xd3948596, 0x9d7cf1f3, 0x60655c58, 0x849a68c6, 0x172fe311, - 0xbf8a146b, 0x015bfee0, 0x988e67d0, 0xf7aaf95f, 0xec3f88a3, 0x1e186ff0, - 0x733fe5cb, 0x1e494aaa, 0xe46bcec1, 0x19d58ca7, 0x799fa093, 0xdb39606b, - 0xf1fdec8d, 0xc043fe0e, 0x3af2ef79, 0x5b257d6d, 0x7f9d39f3, 0x5befe061, - 0xeb682ed0, 0xe8f2953f, 0xaba40e60, 0x8cc5b17b, 0x0b4684e7, 0x51ad14bc, - 0x665fa8ac, 0xbf8c68ae, 0x9b33f20f, 0xb4f20754, 0xe8eb0bc4, 0x8f39d3ef, - 0x693d4dcb, 0x6ed9703d, 0xdced82ef, 0x2bff5c51, 0x2c70f77a, 0x3dd6287f, - 0xadf1d71c, 0x9e18589f, 0x06d6399b, 0x1ec618fe, 0xc5106ccd, 0xd06cac1f, - 0x5a3b00a4, 0x6026b064, 0x16c3dfbc, 0xb7be3226, 0x779c0e65, 0xf90d79a5, - 0x07e89581, 0x1f91f9f2, 0x672c50f8, 0x15d7d6d5, 0xeac39f3a, 0x9a07e40d, - 0xd6781f85, 0xae009b5e, 0x6e3d7317, 0xde2d3920, 0x687e4316, 0x235c8af1, - 0xaef16ff2, 0xe043d218, 0x63d87e07, 0xc78e9f98, 0x481e6456, 0xeb8b7e84, - 0x96aa1c32, 0xb8ff5a7e, 0x5ba498e6, 0x4b4fbf47, 0xe8a193b7, 0x94d2f406, - 0xff0824a7, 0x3d8bd04e, 0x477e4b16, 0x7ab782e1, 0xcb9e019a, 0xee746155, - 0x83ff33a8, 0xbed1c6a5, 0xe6175c9e, 0xdfafb725, 0xcafcdf68, 0xb744a19a, - 0xfde57a60, 0xb470e667, 0x16afec27, 0xa1ec7a86, 0xc9e1ecee, 0xc2b0fe50, - 0xeaa1ebe5, 0xa72879f1, 0x6f5c0959, 0x6614b7be, 0xfdec6468, 0xece666a5, - 0x4b07d8c5, 0x68ff94ad, 0x3fe52269, 0xf4a76a5e, 0x287da593, 0x68e2293d, - 0x0180ce52, 0x25475f88, 0x951af970, 0x6cdee220, 0x8caa2251, 0x307cffbc, - 0xa1c56754, 0x4d8c27d2, 0x271eec63, 0xdfc02320, 0x046f7e99, 0xdf3db912, - 0x4b8eb062, 0x9571ff44, 0xd8befa42, 0x3da6bb75, 0x3c4625f8, 0x64facdff, - 0x9ce9cbfa, 0x1938dd98, 0xfcfef0f8, 0x69fb4d58, 0xfc9a2935, 0xcd3b04e4, - 0x775e527b, 0x8503f94d, 0xa2f935fd, 0x9e024036, 0xf8db302f, 0xb7d8aafe, - 0xd7c6cc67, 0xf6de56eb, 0x2ef0d56a, 0xaf7807df, 0x7d50321e, 0x5d243d30, - 0x31d7ad67, 0x73368037, 0xfa0dcc3d, 0x933b593d, 0x11fceae4, 0x95fdd90b, - 0x1ddf32db, 0xdb63f901, 0x7ebfb40c, 0x5aec456c, 0xb63e3fdc, 0x418a3e2d, - 0x32a95eea, 0x7ac1fa1f, 0xe80591ab, 0xcb15dcb7, 0x9156fce8, 0xf940e4d7, - 0xf9efda2f, 0xd1dbcc95, 0x5120441f, 0xbd543e3e, 0xe7e8853e, 0x14befc24, - 0xf902dde6, 0xf1afa033, 0x16ccf8c8, 0x8519d70e, 0xd9fcc0ad, 0xfaf5bfb0, - 0xb171c03e, 0x8744b6a0, 0x50f501eb, 0x1dcbe93c, 0x2dbe432a, 0xfda0605c, - 0xa91fb9bb, 0x94cf311b, 0xde9c2921, 0x64479d2a, 0x7fa8992f, 0x021c0ad6, - 0xd6fd16ed, 0x77d689b4, 0x0f77e44c, 0xfc16aef4, 0x26747c89, 0x08633986, - 0x3de08558, 0x46fc7ef7, 0xd3e3f7ac, 0xfde7083b, 0x32b5dea5, 0x5cebf801, - 0xe9107789, 0x49e2c7b5, 0x7ef182ae, 0x96f5c8d2, 0xf140e507, 0x9cbf4beb, - 0x9d3e272d, 0x38247069, 0x25655f48, 0xb93abea1, 0x98e740c6, 0x3519de99, - 0x3b3fd689, 0x38e58f88, 0x71f6f527, 0x9ac9df08, 0x96fb860c, 0xf2546bc5, - 0x78ff9007, 0xffe72f7b, 0x1b3755a7, 0x28d6fd0e, 0x23a5d66e, 0x60b23cdf, - 0x9a639d38, 0xc141d621, 0x9033e07a, 0x7f2f7755, 0x7e1ede7e, 0xb56586ce, - 0x181defe8, 0x7c158f38, 0xbfde44bc, 0xd650073c, 0xd1474fed, 0xd4dcbee5, - 0xf0ed1a3d, 0xe2550fd9, 0x6addb3b3, 0x3d022587, 0x0ef6e82f, 0xcfe43efb, - 0xe94e7817, 0xb854ff21, 0xae02677b, 0xd26b7457, 0x3e786e95, 0xdbdac4f6, - 0xaf73bbe1, 0xe6241c18, 0x7f49e24b, 0x6e697bcc, 0x8ef3c0d7, 0x2f97f51d, - 0x38bfef99, 0xe7c01493, 0x38dd7b7c, 0x775c00eb, 0xe21d84bb, 0xe6e3b1f8, - 0xbac5e02a, 0xc343c14e, 0xcb50c4ec, 0x3d773c6a, 0x3024c413, 0xec42784e, - 0x7a101f8f, 0x1109fa45, 0xa67e785d, 0x7b37f38e, 0x0dbf2155, 0xbffa347e, - 0x944f9c52, 0xebea5f7a, 0xfb4b5632, 0xf81247c1, 0x8ab9c639, 0xe055da97, - 0xa8a82ece, 0x420f2b12, 0x79356d97, 0x97d419bd, 0x480fd035, 0xfbe762ee, - 0x9e57c643, 0x652db645, 0x417e7ccd, 0xbc19ceed, 0x1d19cd25, 0x75894ded, - 0xf51b0ae3, 0xfc60706f, 0x69c854a4, 0xf5e2ad79, 0xdd9079f1, 0xd98af194, - 0xdb066ec2, 0x28f60ea7, 0x0ecd0ec8, 0x56acb3b2, 0xde01576b, 0xc2471c48, - 0x2ba70c1b, 0x987842c2, 0xbda17007, 0x0f7b712d, 0x15b8244c, 0x03b25007, - 0x35cca53c, 0x01e70626, 0x477b3ef5, 0xd5e782f8, 0xcf315e01, 0x1c4bb860, - 0xff70fb9f, 0x5187cf18, 0x1e6829bc, 0xfec11e92, 0x894ba49a, 0xa4b7e387, - 0x7e7a2141, 0x3207eeda, 0x7e491b8a, 0x9d500581, 0x44d77bf6, 0xeba567d4, - 0xf866ff40, 0xd3f247f9, 0x8517563c, 0x7cc152fc, 0xbe50932b, 0x46d3757c, - 0xe1bedfa2, 0x49ca237d, 0x53d7cda1, 0x5c288317, 0xb4bcd3fb, 0x1044f580, - 0xd7446f9e, 0x9c378a6f, 0xbdc65e95, 0x37b34f00, 0x41b0ceab, 0x1ce2769a, - 0x60e48791, 0xc463c78e, 0xb11cc6f8, 0x9c11bfee, 0x6e7e7a95, 0x76f086fc, - 0x5b7d27e2, 0x68baf3b8, 0x9fbf62fd, 0x943a33d5, 0xaff76a9e, 0xdffaec82, - 0x217e3c0c, 0xbd55f1f5, 0x5025e293, 0x2aaefc2e, 0x079b8f2b, 0x2cb4f1e9, - 0xc225e3d2, 0x4e71cbae, 0xf149dfad, 0xf768d9b7, 0x5d3fca03, 0xfee293b7, - 0x476657c6, 0x6a7dffa1, 0x78b5ccfd, 0xb6d4ebbe, 0x4be76499, 0xde76939f, - 0x1ff40c6d, 0xbd17d772, 0xdfe463f8, 0x9f1461ad, 0x16efd92f, 0xabd01eeb, - 0x9ebeced0, 0x8eb651eb, 0xb452d5eb, 0x1ec80387, 0x8b76c6f6, 0x51bddc4b, - 0xc9ca020e, 0xe99e2e4e, 0xe81eddfe, 0x11cbf177, 0xc2a10f0e, 0xdf91d3ea, - 0x3da1f56e, 0xf1f85f2c, 0x0ee73c51, 0x1fa3fff6, 0xd90ffb48, 0x92f77a8d, - 0xc26f282e, 0x1bab97ee, 0x27e8add3, 0x5ff13b08, 0x3439bfc0, 0xfe1087fe, - 0x01ff118b, 0x6bc720fb, 0x06679e38, 0x1ac4ffe1, 0xdb95974e, 0xfae147ba, - 0x774d78f1, 0x6f8eb3f2, 0x9ff849eb, 0xcff01ab5, 0x3f5a5fe3, 0x8ff006ab, - 0x3fc408eb, 0xdfbc5bc0, 0xe0eff02e, 0x78e1aff8, 0x3a786b67, 0x3d9e03ab, - 0xf1618e74, 0xf40e4daf, 0xf984ce1b, 0xb33a9fc8, 0x01d5655d, 0x83f4987e, - 0xbfb560be, 0xe24d7f42, 0xe6af6e7f, 0x0a7fa841, 0x1453fe9f, 0x76ee61d2, - 0x80efa41e, 0x82ece67f, 0xfc7fb8fe, 0x95e9bf76, 0x7e01f12e, 0xa9d24dd3, - 0xd918b982, 0x1d3f86c5, 0xe28375c1, 0x786d4f84, 0xd7dc468f, 0xd7ded7a8, - 0x851933c0, 0x382f8c36, 0x278466cc, 0x8a1ef835, 0xf91c619b, 0x9f3f3d9f, - 0xbce490b1, 0x6dbe7355, 0xba19f322, 0xa758ffa0, 0xf2c6fdd0, 0x39513945, - 0x55d4e30c, 0x2ee9c704, 0x78fce68a, 0xff23aab9, 0xfdc8ccb1, 0xf93fb948, - 0xde0ff0ae, 0x25d7c2ed, 0xd2b175ef, 0x18c29777, 0x164b81d9, 0x23ef17a3, - 0x112a7ac0, 0x31ecf7c7, 0x228edd11, 0xd57f804c, 0x6036e228, 0x1f4f9102, - 0x1f4f9c64, 0x38a26c8c, 0x5e54ac39, 0xd0f8bb40, 0xfc839312, 0x8a68b8da, - 0xf4203ed7, 0x2b9183dd, 0x1e1f685d, 0x313a348a, 0x783d7e85, 0x1a30ce88, - 0x0df18786, 0xafba46c9, 0x796e6853, 0x0fbe9705, 0xd4789e27, 0x06dea00c, - 0x55c637ee, 0xd75dd7e0, 0xc5d23b63, 0x9c6d1f4f, 0x743c32a7, 0xe055a3dc, - 0x293a714b, 0xbe82639e, 0x2b8e01c3, 0xdcb12f68, 0x9df1e56e, 0x8b27400d, - 0xe5c1be9f, 0x03f7c3cc, 0xe35cf0ca, 0x6419c628, 0x935fe104, 0xfaf2332f, - 0x26afc4f0, 0xec66cbac, 0x103ecccf, 0x3a8656e9, 0x45f7d704, 0x978c5ed1, - 0x25f183df, 0xe27aa61b, 0xe67ac997, 0x26b4f1d1, 0x89cccf12, 0x8144d378, - 0x9823a9cf, 0xeef01a2f, 0x778da83b, 0xf9d3e7dd, 0xef7e037a, 0x911afbd1, - 0xbb66753f, 0xb8e30ac1, 0xb82194f2, 0x7e5b292e, 0x25a6f073, 0xa5d7f39a, - 0xcfc75e42, 0x80feb585, 0x041e21c7, 0xcdbc4561, 0xeafdb3d0, 0x8807ce10, - 0xdd9b4a97, 0x2816ed43, 0x71950f14, 0xc1ff4936, 0x1d207dd0, 0x41f0141f, - 0xf851353f, 0xbd3431bd, 0xf5ca26fa, 0xabad1d73, 0x9bb90be7, 0x9b6de52f, - 0x27c6de56, 0x82bda9da, 0xede0307e, 0x26769141, 0xff44e317, 0x5cb912e3, - 0x78e2dd64, 0x9d35b22c, 0x7908b7ce, 0xfef13729, 0x88f7f8e5, 0x8da24c74, - 0x00f095fa, 0x7ec71ebf, 0x9001a074, 0x56d64f5f, 0x87347f93, 0x33b5c405, - 0x5f24edfc, 0xebb7cc77, 0x4c75dd11, 0x10b3ad8d, 0xc2f7caf5, 0x1f47a81c, - 0xacf5d634, 0x4ed8ec8a, 0xb214dbee, 0x3d230366, 0xc261e229, 0x23558cfe, - 0xa1407ce9, 0x5e0fefc2, 0x7478b1ca, 0x31a718d1, 0x630b6910, 0xf13f3a14, - 0xf27fb137, 0x89e2f450, 0x5185d728, 0x33a63d46, 0xfbf52b58, 0xe8b76b77, - 0x33de18fb, 0x0e763156, 0x77c88f03, 0xa8d5b8c2, 0x8d7e7877, 0x4aa29b33, - 0x21c77f22, 0xdee1e027, 0xca7f406b, 0x09df2f7f, 0x4b7a5ffd, 0xe93bb3d4, - 0x0b8f4bfb, 0xf2e4f63e, 0x7d65cffc, 0x92afcf1e, 0xff3cf9f5, 0xe45feca4, - 0x5faa0e9f, 0x4bff5416, 0x3ebc5f9e, 0x7e83df3f, 0xd2ce68eb, 0xd214a385, - 0xbe847b53, 0x23ee5c28, 0xf6ea16fc, 0xf33474f2, 0xdc6eb2e9, 0x6ba2536e, - 0xd51fda0f, 0xf682d272, 0x2764d5f7, 0x704f9fe5, 0x75c44b2f, 0x63c524d4, - 0xa1fb7d44, 0xc4c1ec97, 0xed1fce4e, 0xf8e3c2e9, 0xbfa0929b, 0x05fb7ea1, - 0x8c4eacfd, 0x1c7ef5bf, 0x80ae1c49, 0x26f99e7e, 0x23a7fcf0, 0x49be1b3c, - 0xb592b33f, 0x487f48fd, 0x86be7549, 0xe32763f3, 0xe645e734, 0x8d11c4ff, - 0xe78627f1, 0xf3f50045, 0x67a5d797, 0x5ff3ff42, 0x04bd3d7d, 0xe76125fd, - 0xcc74da2b, 0xdb34f789, 0x1be7a518, 0x7de2313f, 0x8d5d8ab3, 0xaed071c6, - 0x00dcd212, 0x9c04cab8, 0x93f4e760, 0x8373ec03, 0x3d8c1bd0, 0x5f37f7cd, - 0x7a47ab3d, 0x9dd5d7ce, 0xf6ed0e7a, 0x3ee42528, 0xddf166cd, 0x17ce4ed1, - 0xe87a15ef, 0x11b39a6a, 0x8c6bf9e7, 0xb73e4021, 0x60fb93ba, 0x855f1c49, - 0x1ccdeec2, 0x01db3166, 0xe43f43cf, 0x1b2554fb, 0x3c608632, 0xd184cdf8, - 0x6d7e24ef, 0xc795b53c, 0x3c781b53, 0xbcd6d0b5, 0x33379408, 0x31ad9526, - 0x84d8c1df, 0x0339485f, 0xf36f8591, 0x9d5f324c, 0xc79b263f, 0x767f30bb, - 0x506b63fd, 0xb9c29a6e, 0xf0d0fb1f, 0x17a8e181, 0x7422325a, 0x37e79056, - 0x498c8be3, 0x8efcb143, 0x639e5871, 0x222af4b2, 0x8be232fc, 0xc75de337, - 0x3db05f90, 0x46dc41c6, 0x307dfc5f, 0x2adbf70f, 0x0f75a79d, 0xda87708a, - 0xc087fa77, 0x4ac931ab, 0x19901369, 0x870917fd, 0xf9fc1f1c, 0xdfd0cd45, - 0x8349e5c9, 0x9f71db57, 0x3490c725, 0x467e3fd4, 0xe072fb82, 0xac7527f8, - 0x6e292e17, 0x024b8e16, 0x5dee030e, 0xd95dbe03, 0xac06732a, 0x898f26f3, - 0xcdefe4d0, 0xc0ce658f, 0x29bded38, 0xc2f4fc9a, 0x0ff69aee, 0xa9afeacc, - 0x6735302f, 0xb1f80555, 0x1e49fb9d, 0x62d2a782, 0xee7f4709, 0xfc5f0def, - 0xfff441e5, 0xf40eab36, 0xd9eee755, 0xa1db97f2, 0x4e3c65d5, 0x3b47f145, - 0xc9cecbc5, 0xa77a28f3, 0xe85f703e, 0xf3a66b22, 0x03ed9d3e, 0x7cee75c9, - 0x773a7eeb, 0x03ef5df6, 0xeb124af5, 0x086c21dd, 0x55cbc3da, 0xaebc511f, - 0xefcf9222, 0x8cc7ebe2, 0xfb8a0fb8, 0xdf81d78a, 0xd10fc2ef, 0x50f36c3f, - 0xfeb73b3c, 0x1d9bed18, 0xba7ae448, 0x1e817522, 0x42551def, 0x1c68768a, - 0xe068abe8, 0x3646e697, 0xbbee1770, 0x1fb85866, 0xb19936de, 0x1e2be458, - 0x884a69df, 0xf3d77ba1, 0xbca8f26b, 0xfa9c2da2, 0x1e6d4f7f, 0x5f09e747, - 0xa1ff6853, 0xe5a1e520, 0x29b87e78, 0x11e033dc, 0x77e0b718, 0xde21e577, - 0xf3f1762a, 0x9fea05b5, 0x5a4016b3, 0xdf479b56, 0x49aca817, 0x42617f01, - 0x05bfb72e, 0xaf21f368, 0x46acb30e, 0x7d1aabbb, 0x3d479ebd, 0x9e90b463, - 0x807b6e89, 0x336cafc6, 0x24f7f7d3, 0xd0d77f71, 0xdb1ae1c2, 0xc972a2e6, - 0xba93530f, 0x860fd669, 0x7c7acdf8, 0xc2d0c397, 0x6dddfda8, 0xf39528fd, - 0xafcfbb7d, 0x21ae3ee9, 0x14b8eafe, 0x71dbf798, 0x90dc958a, 0xa57c3d20, - 0x0b34786a, 0xc7daa7a1, 0xf4e7e369, 0xdcfc6d4c, 0x738a615e, 0x31c0127e, - 0x3d16b1f1, 0x48b107ee, 0x35f115b3, 0x7b60c471, 0xa97c8049, 0x2237ef7b, - 0xdeeb0c7d, 0x369da237, 0x501b9a41, 0x33ce2e5f, 0x05e9eb04, 0x2f4f5249, - 0x1dda54a3, 0xf9067576, 0x82ac33a9, 0xccfc8501, 0x7e54fa10, 0x1a6b4cdf, - 0x1e6ee3a0, 0xc5347fc7, 0x45f502bd, 0xbe9b0e73, 0x7366f483, 0x7cc3ee3a, - 0x9d03f057, 0x89f90acd, 0x751e742d, 0x0ebb08e2, 0x04abffe3, 0x6f8e525c, - 0xa2c58f34, 0x5b2a7bfd, 0x77befd82, 0x4ecd9de7, 0x47f1afe8, 0x0f689999, - 0x25cfb8e4, 0xcc297bf1, 0xd70d7ada, 0x446f9583, 0x0bde51d8, 0xfb863170, - 0xb44c7b9d, 0xda72814e, 0xc37ca8cf, 0x89ef09b4, 0x7ac14654, 0x7dcfc615, - 0x7c87cc33, 0x9866f8dc, 0xef46ed1e, 0x4873f774, 0x7b37dccf, 0xa1f5c18f, - 0x67a4c1b3, 0x9f38f7e4, 0x09db3d27, 0x5bd237bc, 0xe5267cc1, 0xe5c35dd3, - 0x69f048a5, 0xb73f90b1, 0x552ba390, 0xaf0e485d, 0xe340063c, 0xca63e93e, - 0x27e85dc0, 0x7ef42dd8, 0x02cb9493, 0x79410f5c, 0x3a18ff41, 0x8dfd2bff, - 0x6b2c3960, 0xe5bf52b3, 0xef21766d, 0xb94bca36, 0x6372162b, 0x2cc67e12, - 0x53bbe7c1, 0x5e20efdc, 0xee41aa0a, 0x3f1f68a3, 0xcfc9e50b, 0xf22b4637, - 0x624df017, 0x54fc8049, 0xd0cfde37, 0xb9c5313f, 0x41666f88, 0xcc9fe81a, - 0xac4ff76e, 0xfe0012e3, 0x74322b89, 0x9da9df78, 0xe6f9db7f, 0x8f7ff8e6, - 0x48e29790, 0x67f44f5f, 0x0e61550d, 0x397e873c, 0x2cf7ef8e, 0xb8f1c55c, - 0x45cae0d0, 0x2fe162ff, 0xa1978a15, 0x697a81df, 0x632a91d8, 0xfee51c60, - 0x0ecc41b6, 0xd6d29878, 0x1337d283, 0x0f1147dc, 0x04d36d45, 0xa37d06be, - 0x4ea1c5fd, 0x7832471e, 0x198d8e4d, 0xab724718, 0x6933e748, 0xe04cfacc, - 0x1d7ade7e, 0xbee4c3c5, 0x992b8ca3, 0x807cbcf0, 0x5f42fd1d, 0x37ef4e9b, - 0x7299c704, 0xb0bfddb8, 0xbf7640d9, 0xc3cff1ac, 0x2e7f5074, 0xed05d9c3, - 0x777a97c9, 0xbcf5f21b, 0x0d57dec9, 0xe4ff9f90, 0x7691a8ce, 0xf4eb3e3f, - 0x47689ebe, 0x188f00eb, 0xa35baaef, 0xbfb979e6, 0xc9f7c113, 0x7e4b7f38, - 0x79f3e60e, 0x9f88dd6d, 0xc89954ae, 0xbe015d0e, 0x48760165, 0xe7a91dda, - 0x7c91fda5, 0xfae7ae5d, 0xda323cab, 0xb408c9eb, 0x395c933b, 0xf87d77c8, - 0xddbf1a79, 0x1476b4d9, 0x38a5c1ca, 0xed28b73a, 0xbc1cb046, 0xd31c14b6, - 0x8eed1d5e, 0xcf52ebd4, 0xfa35bb4b, 0xfe772fe5, 0x8a55cd15, 0xe032407b, - 0xb73d6eeb, 0x2deb775f, 0xe3633fc4, 0x6f91e926, 0x1e8f5e6e, 0x98f47a13, - 0x74568f46, 0x27060762, 0x741c9adf, 0x4cf3ed15, 0x3d447fdc, 0xa3dfd81f, - 0xe0c7a329, 0x7327c63c, 0xc15dfb3b, 0x1ffe99dd, 0xfa6b7c9f, 0x88b2587f, - 0xff40ddf7, 0xfd732617, 0x99efac1f, 0x73a7bf95, 0x2f5f4f69, 0x0ca383da, - 0xc1da03ec, 0x16fb0886, 0x5ec80f61, 0xbf7b4784, 0x4d5c1ece, 0x7888599b, - 0x1e0f610a, 0xf616fe4a, 0x94a1f240, 0x5227291b, 0x48e5822e, 0x9f84c5ca, - 0xe9113ac2, 0x57bf1ef4, 0x6cf7ae50, 0x7b46fda3, 0xcf9460c4, 0x976e3f76, - 0xc1d6f242, 0xf1f9084e, 0x6ed68bcb, 0xf290b948, 0x5ca7e522, 0x20ecc5c8, - 0xd6a7d8b9, 0xf70a333d, 0x6bdd92cb, 0x72fde393, 0xd823b652, 0x57ca743e, - 0xb3645918, 0xf218aae3, 0x81a43955, 0x44ea657c, 0xbe499e1e, 0xd968bf35, - 0x6fd3f24d, 0xf4fcfbfe, 0xe9f84e9b, 0x3f0dbe7f, 0x3f63f475, 0x3c03b2ce, - 0xdf40b257, 0x6df9f866, 0xfb8c3bc2, 0x7af9dd0f, 0x0497d600, 0x8d319377, - 0xae133ee2, 0x2f8a2ab3, 0x7494be0a, 0x6cc0fe96, 0x93387711, 0xe1077ae2, - 0x82c0f5c5, 0x447bd39b, 0xb35c5367, 0xb327d711, 0x03f40d21, 0x9b7ff33a, - 0xbdef516f, 0x3e749371, 0xfb9dfc96, 0x4392c78d, 0xb1c78dfb, 0xb5d29bfc, - 0xf8899720, 0x300b8fde, 0x29e138de, 0x0acb6791, 0x46d38f10, 0x3c9ffac8, - 0xfa81ece9, 0x38b8c981, 0x53de39c5, 0xf4b3de45, 0x3f6818f0, 0x8fe619e1, - 0xd8fd439b, 0xb8f6e8ec, 0xedfcc288, 0x3b1fe795, 0x51e886bc, 0xddcce5cb, - 0x3ffbe7a2, 0x79059f22, 0x447e404b, 0x6f037e50, 0x616fa51f, 0x9045e781, - 0x9c21949f, 0xff00aece, 0x7fdf8601, 0x5585ed05, 0xa8d71861, 0xd6f8db8c, - 0xf56bd415, 0xb545ed0a, 0x14d581e3, 0xfbc55338, 0x735f94b9, 0xc23e09d8, - 0xbe78bb03, 0x93ed4a4f, 0x37e8bd1e, 0xa1bddce0, 0xb9d2714e, 0xb78a1183, - 0x7c47465b, 0xdad149f7, 0x6bd1fc27, 0x1e7867bf, 0x6fbe56ef, 0x8dd6cfbf, - 0x6e99f7be, 0xb2fbfc61, 0xfe7f9f43, 0xefe70a5e, 0x21d15931, 0xa8a5c7eb, - 0x37111fbc, 0x68a1f1a0, 0x7be85d4a, 0xb8c513b0, 0x425fb8cd, 0x24f6dcf8, - 0x28d9b7e2, 0x93f2fdf1, 0x196377c8, 0x60cfc4d3, 0x9fdfca7c, 0x8d4172f2, - 0x19d74f9e, 0x9bafaf84, 0xa91480ef, 0xf2f8fdbf, 0xf4cbd104, 0x8476f835, - 0xfb5db7c0, 0xe8ebefbd, 0xf7c3ac35, 0x48e76f82, 0xf86a763e, 0x22ef5a3d, - 0x538e8cfe, 0x5747e8ac, 0xe0d6c2b8, 0x9f2fc17a, 0x6cbe27bf, 0x1d03fb96, - 0x02b5efe4, 0x890abf94, 0x4febcf47, 0x74bafca2, 0x3cb9eded, 0x7335f3b6, - 0x52bc01f6, 0x7fbe0fc8, 0x27faf9e4, 0x7c092e31, 0xd794f541, 0x2c1dc007, - 0xf941758f, 0x15f920ec, 0x03fa47f2, 0xa9e001ed, 0xb8b7ea27, 0x007b4663, - 0xd04cfc9f, 0x27b8a2e9, 0xfb9a3cda, 0x78ddcd93, 0xfb8523ba, 0x7c09cf8f, - 0x9bed126e, 0x90f003c3, 0x1f1fe1aa, 0xe6025bae, 0x3fba784d, 0x93fbce4e, - 0x63d07c82, 0xbf5e36cd, 0x27a3e52d, 0x7cfed93d, 0xa6af7f70, 0x7880527c, - 0xf1fff7f1, 0xee23f461, 0x91db7817, 0x27b0e472, 0xc139d052, 0xf0214eff, - 0x5163bd07, 0x74a1fc8e, 0x761f8fe4, 0xd04f4fe4, 0x774ef4f7, 0x3a7bdf67, - 0xfa0cef7e, 0xea3de19e, 0xd05eff9b, 0xae883f2d, 0x1d744179, 0x942f9413, - 0xff46af79, 0x5c5cbd4a, 0x09e3f4ff, 0x54df1871, 0x9fbf38e8, 0xbd934f9f, - 0xfc956f99, 0xf230e67b, 0xcf9f9fab, 0xd7279e12, 0xce79ba09, 0x787a893d, - 0x51e1ea12, 0xd414fcfe, 0x5f3f9443, 0x7e61fb80, 0xea81757b, 0xed91abef, - 0x7afd922f, 0xefec8560, 0x3a4bca33, 0xb225cf32, 0xbd0bf777, 0xa4ad3cc3, - 0xf035e7f7, 0xfe7d3fef, 0x2b5fc3f3, 0x7841b50f, 0xf79410d9, 0x775fb504, - 0x22b6fb03, 0x82c7fbe8, 0xe504d7ea, 0x6be507d7, 0xcd17dfb4, 0x8b0e4852, - 0xc9fdf046, 0xe60cb960, 0xda522f8f, 0xf6ed63e3, 0xff24895c, 0x1357234e, - 0xfafe79aa, 0xa829fff3, 0xa7c80c89, 0xb21e89b0, 0xc05a30ef, 0xb9d041fd, - 0xc1f8151e, 0xbcde89d0, 0xecde99d8, 0x79ef6c13, 0xd7f03ffd, 0xd22fda24, - 0x54fb25f8, 0x9551be6d, 0xbbbd4770, 0x5f603228, 0xe2265995, 0xfdf3baba, - 0x6389889b, 0x22fc0352, 0x6744f84f, 0xfb653cc0, 0x575d5f71, 0xd4f8bc71, - 0x719b89f0, 0xd8b4687f, 0x14f1b4d7, 0xf68aa5ec, 0x6fc452ba, 0x5d39e1c6, - 0xebee176c, 0x0fd030b9, 0x70bd7562, 0x523f8d9e, 0xd550bbf9, 0x53c01f40, - 0x79d3b311, 0xea7899d3, 0x47d43bbe, 0x0df92f47, 0x47efb77c, 0xd3b412ea, - 0xd2c49747, 0xa945a639, 0x17dcefdc, 0x366135dd, 0x1e231be4, 0xf8db7d26, - 0xf74a58c4, 0xad95ceaa, 0x353ae856, 0x5f646279, 0x3c268fac, 0x4fc43639, - 0x9dfc065c, 0x38276a99, 0x426b36dc, 0xabdbfa3d, 0x085fb40d, 0xfc457e2d, - 0x3069a4f3, 0x968bb7ae, 0xb0fda7f5, 0x1a4f9fe2, 0x8ab0f787, 0x3ed0371f, - 0x4ace8b49, 0xeaf72271, 0x6a2e74b1, 0x7a910ad6, 0xcdf4a2ee, 0x1abafcff, - 0xbeb569ef, 0x0efbd0a0, 0x7bad5c77, 0x9b9e1067, 0xf74ee9ac, 0x7580de2e, - 0x3efb9e00, 0x17b7bebe, 0x089f21cf, 0xa473a2ab, 0x8bee9ed0, 0xbfb35e95, - 0xdb0b313b, 0xd0e5d6ab, 0xa39414fe, 0x956a7cff, 0x41ef09ba, 0xc2594515, - 0xa9f6fcf1, 0x75c518af, 0xa26e3d4e, 0x478e2277, 0x8fac67ba, 0xe8b8fba3, - 0x8a53b3e9, 0x3c014a3d, 0x67d0da4c, 0x96126262, 0xfb7d049b, 0x1e011544, - 0xfced748a, 0x24a4f643, 0xa527e786, 0x05b899f6, 0x97ea71e6, 0xd87ce9bd, - 0xe4e754c1, 0x2fd7c054, 0x52539cd2, 0x6e5e11e3, 0x0ffcdeb7, 0xe3fc8fdf, - 0xe404e285, 0x395287af, 0x56d1bf5f, 0xbef8109c, 0x3d45c977, 0x469bc1f1, - 0x277a22fb, 0xc14d3c30, 0x41f03675, 0x67cdc62c, 0xf00b7589, 0x219d92f3, - 0xa9e1abfc, 0xf1abd12a, 0x48d9f1a7, 0x0f5f3f5f, 0x19f5177f, 0x5f2037ad, - 0x2d7321b1, 0xa693b9da, 0x0f44ec25, 0x91fe7ed6, 0x3c230bed, 0x7985b619, - 0x7e3032c3, 0xfc871cea, 0x7aeb12cd, 0xc804b64d, 0x77ff68a1, 0xfbe73f0f, - 0xeb8f6877, 0xfe7bbfbe, 0x9fb812d7, 0x4697db21, 0x5ce83c59, 0xf458b69c, - 0xfaa38f48, 0x3cf0a7a5, 0x060bc95a, 0x2f2503b2, 0x8ad63fc4, 0x06f807fa, - 0xf3c16be3, 0x81aa63fa, 0x933a31c7, 0xad18cf4b, 0x1331b25c, 0xc99dbe71, - 0xdc86cd65, 0x3b239b89, 0x2b52cb97, 0x5ee34fd7, 0x9651efe0, 0x71e8b50e, - 0x0bf4737f, 0x7ba16d6f, 0x86c20b74, 0xd289bde0, 0xaf444c17, 0x63c58b16, - 0x13ef0dbd, 0x9031f458, 0xedca9b3e, 0x9f90bd69, 0xcde9955c, 0x7ba52843, - 0xf0df7212, 0x9e6792ec, 0xe797e3c5, 0x70da7798, 0x2765dfc0, 0xbbcbd3e7, - 0x063f8a54, 0x1f9623ef, 0x61cc69dc, 0x788fb137, 0x32c3fd83, 0xdfde22d6, - 0xf07dfd0d, 0xa9abe1fe, 0x0687fbc1, 0x2a5e4fba, 0x37730ff6, 0xe9770428, - 0x3fcf7e12, 0x8dc79637, 0xfa052e4f, 0x1ede691b, 0x0f3c10eb, 0x294eedcd, - 0xf866bc53, 0x0b0daef5, 0x13d98e28, 0x6e7184f1, 0x89e26ef1, 0xae3a4730, - 0x085e4bf3, 0xfe96fc23, 0x7e5fee6a, 0xfaf78599, 0xd702e20a, 0x2f91fbd5, - 0xde197e38, 0x9cfd941f, 0x7a63f65e, 0x45f731a7, 0x7cc31f58, 0xabd8634a, - 0xbd2067f7, 0x9f71d292, 0x5d2bb653, 0xbc5ea3fe, 0x61afac1d, 0x4ab45d1d, - 0xecc7efe5, 0x041d9136, 0x01644f59, 0xad672cf7, 0x72346838, 0x8712c63b, - 0xeedaff09, 0x1c769fbf, 0x6eeaf1ea, 0x2687b8a5, 0x51ef27f1, 0xfbf8e915, - 0x853a8574, 0x268157ee, 0x97497ba3, 0x7b5fb953, 0x679f953a, 0xd0774a28, - 0xb5f29cfd, 0x0cf2c726, 0x7dfb4fde, 0x95df584f, 0x684b9aeb, 0x26f7f33f, - 0xae54ab8a, 0x45867308, 0x3b17f3f1, 0x6af9d006, 0x51f011bd, 0xe2fae766, - 0xa56f98b2, 0x745dd27d, 0x8ecf419f, 0xdcbea1e8, 0x7963f5c2, 0x923de00c, - 0x186e8a33, 0xe8c767be, 0x9bf624dc, 0x7c602834, 0x3f439445, 0xbf7f28f6, - 0x83563a4d, 0xdf6c1b71, 0x31e21077, 0x8474da76, 0xe49515ef, 0x76b49019, - 0xaf7dfa04, 0xdeb899a8, 0x6fb55a2e, 0xf9dfea1c, 0x8de307db, 0xeaf45609, - 0xe63f6407, 0x88b7fa0b, 0x90c56773, 0x22b677c7, 0xb93cb8d2, 0x8a2f1e55, - 0xef345348, 0xf2fac910, 0xbf1e0655, 0x8a8f3d07, 0xc7d97ca5, 0xa5b96fd4, - 0x6ff50139, 0x30c36ef9, 0x6951d3d4, 0x978b2e5c, 0x011f65a5, 0x44362abe, - 0x6583bbd3, 0xe623029e, 0xca156acb, 0x4f8bbffb, 0xbf3d3e47, 0xe428b5e2, - 0xbe61139f, 0x5a97689e, 0xe8398417, 0xc795a1de, 0xe8afceeb, 0x6695f749, - 0xf82d9b59, 0x45acc19e, 0xbfa86ddd, 0x467d5a8f, 0x975a3fac, 0xd3bcc3a1, - 0xbcc6cd6a, 0xe51b7f53, 0x2df38bcf, 0xa57c83f4, 0x6d973a70, 0xbfc467db, - 0xcc44324f, 0x1f2be2f7, 0x4ff8c2f4, 0x2f737a79, 0x07c02bb4, 0xcf1052bd, - 0x9764292f, 0xf3f1b62b, 0x2a0f92ee, 0xee400f90, 0xa83e09e6, 0xf7daf5d8, - 0x902a1e51, 0xf23a43fe, 0x7ef3f011, 0x71b1df2a, 0xefdfe31c, 0x76913e47, - 0x0c2bf20c, 0xf1df8c36, 0xa71a667c, 0xe18f943f, 0xfc019ee5, 0x39fb5d1c, - 0x741c8d04, 0x1a575f46, 0xcbc587b7, 0x5d6fa44c, 0x5a1e5c69, 0x428eed56, - 0x657c5dfa, 0x67dc01df, 0x5601df29, 0x1e421eda, 0x712a3e04, 0x3f0451fe, - 0x389517f9, 0xfcff28df, 0xc85ef9db, 0xf3e32561, 0xd4adf393, 0x7acbf98b, - 0xc124fdf1, 0xe04c652f, 0x2e6f576b, 0x50ce4277, 0x0ebde98e, 0x4db73f31, - 0xf7e50efb, 0x22dcfcc5, 0x28bad665, 0x17d20fc4, 0x103e0ff5, 0x04fa9469, - 0xbedc5c9a, 0x4bf1ce91, 0x57f8497a, 0xdf403809, 0x7e6c6339, 0xf274b63a, - 0xe095644e, 0x778f639b, 0xfc07af49, 0xcf4adf9d, 0xeabf116c, 0x7c93c603, - 0x7dcbc723, 0x38ddd279, 0x87dfe86f, 0x8f71cbfd, 0xd8f4227a, 0xe5c651cf, - 0xe52fc243, 0xa1fab732, 0x614707bb, 0xee968bbb, 0x9cde7003, 0xacd2ab8e, - 0xfd13bdf4, 0x59def805, 0xfadc50af, 0x1fe75898, 0xa8b5fc7b, 0x7e7e01e2, - 0x277c427f, 0x307f0cf9, 0x6de1263e, 0x7038f1b2, 0x0f52dc30, 0x9f73b849, - 0x2c6eefb8, 0xbee3f097, 0x4a9f2051, 0x957e4a3c, 0xf982f5f7, 0xda4e7896, - 0xfe73b54f, 0x463d4cae, 0x943a77e7, 0xfc27f707, 0x5ce213a2, 0xe33c6b79, - 0x8915ff71, 0x8af735fb, 0xb40c8b18, 0xc08ed23f, 0x807d1acf, 0xa7bf69fd, - 0x8b3ce716, 0xd690bb74, 0xc73ffa8d, 0xd0398cea, 0xe699d96f, 0x9dcef871, - 0xb8ef43f4, 0x31a353ea, 0x9f8bb55e, 0x52fc9377, 0xc93f6176, 0xffb8b941, - 0x83eab454, 0xefc8e182, 0xbed035bf, 0x63e3d14e, 0xcfdfe88d, 0x187332dd, - 0x41ef01a2, 0xbb3f5ea0, 0xbf266879, 0x984d6059, 0x3621f786, 0x01ed333f, - 0xaf559f28, 0xd80dbbd2, 0xd16fca0f, 0x5f1499a3, 0x52d6113d, 0xf8fd0a30, - 0xf456a81f, 0x32df6fe3, 0x7f6c31f4, 0x0c6ba5bb, 0x39b1b63d, 0x7d4ef296, - 0xe907d934, 0x8073caf7, 0xc7dee2d5, 0x3fde845f, 0xe22a9edc, 0x2f755ffc, - 0xdd6f8fdc, 0xacef4618, 0x75ed1a14, 0x4f6f1c3e, 0x54675a17, 0x23eaf11a, - 0xbf255bdd, 0x99918e6c, 0xb9508693, 0x0fca0939, 0x451f9a1a, 0x51f0723b, - 0x3f7c60cb, 0x86d7a992, 0x9a7f7315, 0x6ac63bef, 0x70912ddf, 0x0fc6247c, - 0xdf7e4fee, 0x1b08eb84, 0xefa44fdd, 0xedf8aecf, 0x6783b434, 0xe1b4f6b7, - 0x09ef4fbc, 0xa703fba3, 0xcf77da0d, 0x57def56e, 0x79297df0, 0x9a74f56f, - 0xfc938fd6, 0x377bc37e, 0x839ed37f, 0xa5b9d1bc, 0xdd194b0b, 0x8d397efb, - 0x2263f7d1, 0xe789dabe, 0x4d6a4b08, 0x7307bc56, 0xf71ef912, 0xfcab76b3, - 0xcb99a5fe, 0x99ddc9c1, 0xe4b7bf74, 0x525f3c6f, 0x3ef178a7, 0x9fa7fef2, - 0xb30af3a0, 0xabc4cfc1, 0xf3feed09, 0xa1a7a7ba, 0xb8765c38, 0xfe7de257, - 0xf9f95bcb, 0x32ef0e8a, 0x2079dc1c, 0xdfb9dec9, 0xcbfb5dfc, 0x9f110e32, - 0x2fcfbdae, 0x4fd72cf1, 0x8c3f026f, 0xdbc7e218, 0x90e74b67, 0xa9617cbf, - 0xca4bd29b, 0x23b7b5b1, 0xe9a25b1f, 0xeb1fc0be, 0xbdf1519f, 0x835df2a8, - 0x783ae1af, 0xbd346454, 0xd2d9f293, 0x7a8fb425, 0xa5156961, 0x0e32de92, - 0x46aec777, 0xfab3eefa, 0x9fbc06cc, 0xb46446fb, 0x90b603b0, 0xdeeced74, - 0xb9d79cb1, 0x4afa701f, 0x9d6dcfb8, 0x6af38519, 0x61b63e7c, 0x2235d224, - 0x5f7e8ada, 0x724738a9, 0xabf73d6a, 0x7fa398cf, 0x3df40f93, 0x024a61b3, - 0xbb3737be, 0x5869def1, 0xb147b25e, 0xb1c07ae2, 0xae145267, 0xb7d53edb, - 0xa8fde144, 0x7bcbd74f, 0x3bfa5e55, 0xd8f2a354, 0xca3f6c14, 0x0cf667a7, - 0x7c8d75be, 0x9e82f232, 0x879ebfee, 0x5c938a72, 0x0938a70b, 0xb9e2c4fc, - 0xf3afd991, 0x3afb4af8, 0x6ef3ac57, 0x347ef317, 0x31f726dd, 0x04773ca8, - 0x61bd3f2f, 0xefec44e7, 0x158366ec, 0xb36cfee1, 0x079ffa81, 0xc01d33eb, - 0x5f2b667b, 0xd71e60f7, 0xf2b767cb, 0x3abccdf5, 0x5f29bebe, 0xfbf27060, - 0xcc7e5aa2, 0xef47680d, 0x5ef274fb, 0x9f273cc8, 0x97b03cdf, 0xbe60df38, - 0x7475618d, 0x9e9bec8f, 0xdbe60d17, 0x855f92f9, 0xd7e7687e, 0xe044f8ce, - 0xf91de513, 0xbcc3f255, 0xdedf7cf5, 0x07383756, 0x47f24ef9, 0xd5593bf0, - 0x57dfc646, 0x7bd385d4, 0xed2293b8, 0x530fb406, 0x20c65ae2, 0xe74e3e5a, - 0xab9a807e, 0x37bde273, 0xf90a6d56, 0x748acece, 0x744557ee, 0xdeefc465, - 0xcf3f2b74, 0xc97fee29, 0x86922614, 0x84527b76, 0x343b0bed, 0xaefd3a79, - 0xcfc0f47b, 0x3db76e93, 0xd8c1ddda, 0xee0bd32f, 0x267cc3d1, 0x7776da65, - 0xbff3fc83, 0xb7f3c09a, 0x201a86d9, 0x78994cbf, 0xd7c818cf, 0x4a9f3ba7, - 0xece7180f, 0x38692e96, 0x19ff283f, 0xbbc5d796, 0xa5698e7f, 0x49760fb8, - 0x24b41d69, 0xfdfedfc3, 0x7fa3963d, 0x2df3fbb4, 0x18ee9606, 0x7f097980, - 0xdd25b4e8, 0xf8f4abf9, 0x8cc5e58e, 0xf5e74e3d, 0x0e1efc3c, 0x09ccb8fc, - 0xf38a4f78, 0x97bcb15b, 0x2f741353, 0x9fefc1c7, 0xf252fbc9, 0xff5f543e, - 0xb70db27d, 0x92ec9f72, 0x2a1dff81, 0x0fbda9c5, 0x89fc34a6, 0xf6a9f9de, - 0xa23096b0, 0x4d9ef683, 0x7753be39, 0xa20bdd1b, 0x6f4c87fb, 0x57337d27, - 0xac683bfa, 0x29dff987, 0xfcfc8960, 0x1f82a3c1, 0x3d652f4f, 0x9fe8807a, - 0xca39b77f, 0x985c700e, 0xfa85ebe8, 0xfddc3220, 0xe9d7c427, 0x0ba9d50d, - 0xaa1ef0e3, 0xed0f91c9, 0x7df978cf, 0xb7e132ce, 0x42f1cdb2, 0x3bbea82f, - 0x46535da1, 0x87684ddf, 0x757c17de, 0xfe97c321, 0x192bd423, 0xed049d7c, - 0xde5d3ce8, 0xb1e2bbf2, 0x4fed85dd, 0x700d98f4, 0xbc06009b, 0xfa1e35a7, - 0xf7a3611c, 0xfb4a98aa, 0x7efe5ecf, 0xa2799e92, 0xd5eef86c, 0x3ee2e933, - 0x9413dd11, 0xeff89274, 0x1a181740, 0x999d59fd, 0xbeee1019, 0xfdfd036c, - 0xf91f492f, 0xddc2e2ce, 0x7742fe3c, 0xe31e4524, 0xe2cda748, 0xb0759fef, - 0xbf916f8b, 0xd1e9620a, 0x330d9fe8, 0x11c9db43, 0xf5d88d1b, 0xff2f6d77, - 0x92fc2e9d, 0xe0706cc1, 0xa2a5923b, 0xd0b558cd, 0x2d5bef8e, 0x7bd3378c, - 0xe85f0b25, 0x96c1fc4e, 0xb60590fc, 0x89621b63, 0xa866565f, 0xf5b9ff84, - 0x2a1dde8c, 0xf3a64fa8, 0x36f5f994, 0x12daa34a, 0x6fecfca9, 0x7ae2c9de, - 0xe0a7d389, 0xa68cba7f, 0xd3ff4b73, 0xd9d6529b, 0x6691a77b, 0xf0bbcfba, - 0x0b6bb720, 0xc7bfcaa7, 0xbbafefc2, 0xc8ae3804, 0xb90b8a1a, 0xe753dc3a, - 0xf0ba57ef, 0xe77e00be, 0x677d5034, 0xfc4a57ef, 0x82dd049a, 0x7a9cb3df, - 0xde913330, 0x59ef147f, 0x9aed174e, 0xceb3bdc5, 0x4fbcb5de, 0x6a227bb4, - 0xddf2135c, 0xc8696774, 0x9ef52d77, 0xcffa0730, 0x7a48d486, 0x373ee147, - 0xf59a97f8, 0xf11e8b4c, 0xbf9b2d30, 0xba753973, 0xfd90deb6, 0x4373e939, - 0x92778776, 0x4d8fa80c, 0xecfb6d2e, 0xf50ec2ae, 0xf6bf7d65, 0x2354d15d, - 0xbe3d4fd9, 0x69f90b3b, 0xf4515de2, 0xbfffd10f, 0xff10b4ec, 0xb83bc49b, - 0x112b2ccd, 0xbeadc2f5, 0xdbfffb27, 0xefc1b1fb, 0x03bf06c4, 0x42eb7fdb, - 0xdd607e4d, 0x6fed350f, 0xa9ae5fab, 0xad5bec1f, 0xfa6ccfa9, 0xb43f2699, - 0xfb4d39f9, 0x693647e1, 0xbcb647ea, 0xfdbfa9a4, 0xfe4d0ecc, 0x683fd68e, - 0xb6d9dfda, 0x61cf9357, 0xe7da68ef, 0xe4d03f9a, 0x57ff5ac7, 0xc4aefed3, - 0xf1fa9a13, 0xfa9af3f6, 0x68ae7d09, 0x2f8e05f2, 0x373fed35, 0x457757ba, - 0x0cea22bf, 0x433aadf1, 0xf944f861, 0x6629a6e5, 0xba6b07d4, 0xf8247d0a, - 0xd3b0b96f, 0x7ba307ac, 0x6cd563ac, 0x3d5ff11f, 0xc1a0bbff, 0xde7f4f76, - 0x1ff8c4e5, 0x6bdf8d7b, 0x527f068b, 0x8c7e301f, 0xff02ccd3, 0x9e6c5dee, - 0x778f9355, 0x77da6a25, 0xd4d76e99, 0x68fbb927, 0x38e653ea, 0xaab4f934, - 0x5df69a11, 0xf9353897, 0xa69e4f0c, 0x971af77d, 0x76b3df26, 0xef7da6ba, - 0x7d4d6ef5, 0x4d1cef5f, 0x55adff7d, 0xbac0fc9a, 0xb7f69a25, 0xf5347bd5, - 0x9a357d83, 0x5aa6ccfa, 0xf3687e4d, 0xe1fb4d7a, 0xfa9abc47, 0x355b2d91, - 0xa99fb7f5, 0x68efe4d3, 0xbfb4d7ad, 0xc9a7cdb3, 0x9a83b0e7, 0xf7e6b9f6, - 0xd6b1f935, 0xefed344f, 0xa9a63c4a, 0xab3f6f1f, 0xce7e97a9, 0x6b9f3e84, - 0x53df85cb, 0xe697f8e0, 0x6ef7f6fb, 0x1f742877, 0x6ed75cea, 0x96c57df2, - 0x24fd1530, 0x6c99c517, 0xf5111078, 0xb727de15, 0x8539f3f1, 0x238aaf14, - 0x944c887f, 0x810bcf1d, 0xab8510df, 0xf40c8cb6, 0xfefc23ab, 0xccf5ea5b, - 0xdadff79b, 0xd5dcff84, 0xf288beee, 0xfb6eaf31, 0x989f7a38, 0x1c225679, - 0x77bffdf2, 0x956dde83, 0x19f378e9, 0x17f00fa6, 0xa6d5860f, 0x389af90e, - 0x05f378c1, 0xb6c1ef86, 0x22e22bf7, 0x17bdc7f8, 0x16bff406, 0xf7f817d6, - 0x9a976b23, 0xffc76fe9, 0xf295a96c, 0x522696eb, 0x3a00fffe, 0x0047bf29, - 0x000047bf, 0x00088b1f, 0x00000000, 0x7dedff00, 0x4554780b, 0xeedd7096, - 0x9d248fdb, 0x777579d0, 0x493cdc9e, 0xf09d0848, 0x3a3e00d8, 0xc0406021, - 0x490435e6, 0x41a8c1a4, 0xf881ba43, 0xbb75744f, 0xb2021031, 0x10d191b3, - 0x0186c195, 0x099d1964, 0x09d1a32e, 0xe09af09a, 0x1c604c3a, 0x3719d9c5, - 0x8ee2a3a0, 0xcfe31e10, 0x7fc38fee, 0x937ba9ce, 0x380e9dbe, 0xf7ff3afe, - 0xb4fbfa3f, 0xab755538, 0x739d554e, 0x2aaa3cea, 0x89895ead, 0xde6d6322, - 0xf39f4a1c, 0xc99899da, 0x316f36d8, 0x0ebddbc1, 0x72defd82, 0x9d7a774a, - 0x5bcbbf94, 0xaf1ef041, 0xdebdd28b, 0x79f74a1a, 0x92fe543d, 0x9fe081b7, - 0xb6947d7a, 0xff299b7b, 0xc10b6f15, 0x046dbc07, 0x53f5eabf, 0x4bdde1da, - 0x76de1be9, 0x76f4ef2a, 0xb7a6fc10, 0x6f2ee08b, 0xbc87c10f, 0xf11f04bd, - 0x98f8269e, 0x1ed28fb7, 0xbe9467ef, 0xf2a7eded, 0x0957bc77, 0xdbbf8ebe, - 0xcd2afc19, 0x2631e49f, 0x7ae69730, 0xc9ccc21e, 0x00f63226, 0xff824bfe, - 0xcc8846e2, 0x8cfdd8c2, 0xb0d73eff, 0x9413769a, 0x3ff2fe77, 0x74c60285, - 0x1f8d8ca5, 0xf662690f, 0xc634c6ce, 0xe675b026, 0xd318724f, 0x63d75740, - 0x4e09fb07, 0xd6191319, 0x2d75dfc3, 0x58c7dffe, 0x94bffc3c, 0x834c78e5, - 0x14095369, 0x55befb42, 0x1a777f82, 0x3e20d755, 0xbf1c8dab, 0x95135a69, - 0xf82c3e57, 0x5563020d, 0x8be9f322, 0x587dfb18, 0xc11b0154, 0x2e8f25d8, - 0x2172c447, 0x04830edc, 0x443a8ff8, 0x2c5d7e0e, 0x9da5b18e, 0xd29b1d86, - 0x84aaf106, 0xfdf035ef, 0x0c1a562b, 0x3a3d64ab, 0x1df203c4, 0x9ec618da, - 0x4ba6b8b7, 0x8a60ff90, 0xf687a7c6, 0xed9fc999, 0x2dec648c, 0xe6066b8b, - 0x77dcf25f, 0xc07f1b0c, 0x7ec6cf6c, 0xe2ba1b66, 0xfdff4117, 0x9df6b5c7, - 0xe1f3f0d2, 0x6c67296e, 0xdfca0ddc, 0x02ec973c, 0xa2ffca3c, 0x9ffce175, - 0xf85645d0, 0x492f01f3, 0x1a4a78e0, 0xeadb3a55, 0x7cf8825a, 0x47b9e919, - 0xe5f85303, 0xacf6ab6d, 0xae552181, 0x82e11aca, 0x2582eeef, 0xcd8c1963, - 0x418e9265, 0x38e67cf9, 0x2d4d069a, 0x17822e64, 0x6fa51f31, 0xb1aabbc5, - 0x4fccc59d, 0x21b26bb0, 0x82b8d435, 0x78cb72f1, 0x947c65b9, 0xabab71f4, - 0x20e5e38e, 0xba4c4ebc, 0xa5c71b23, 0x5596f5e0, 0x58737aa2, 0xefc476ff, - 0x3f1783cb, 0xd2863211, 0x174077c7, 0xeb1e6826, 0x73ac3d31, 0xf7d18ea3, - 0x7e088f8d, 0x2e856ba4, 0xb791992a, 0x0be418fb, 0xf4027481, 0xd2fc8451, - 0x92373a9f, 0x0949e4e8, 0x92707c1a, 0x0b1fa7d6, 0xb3f8d4e3, 0x87d12d05, - 0x1efc005e, 0x48fa0388, 0xea0e9e1f, 0xe00d219a, 0x67afa01f, 0xaff3bdb0, - 0xce0e5dff, 0x49cdfb97, 0xa357ce12, 0xe801d606, 0xd6b6f7d8, 0x99925bbe, - 0x94ed6014, 0x6ba47e31, 0x73edda26, 0xb17ae0c7, 0xdfa84ea5, 0xfb0d65ad, - 0xfbf687f3, 0xb417ae2a, 0x2ba6c27f, 0x9cbb53f7, 0x9ff295cf, 0x63c5fae2, - 0x5eadebca, 0x16ad69f5, 0xe8713ff0, 0x131a5e9c, 0x6f0d1c62, 0xe00666e7, - 0x3338eeef, 0xe44261dd, 0x45e7f2fa, 0x949fe60e, 0x1fa144e9, 0xb5d23ead, - 0x178814c3, 0xf9e817ef, 0xd13744e7, 0x4419cf40, 0xe0f89fcf, 0x690639d3, - 0xfb4822c4, 0x20ba6a60, 0xd660bd75, 0x672cdd23, 0x99ab4a76, 0x6007d293, - 0x9d7e91f9, 0x38f4a7be, 0x76b20fef, 0xbe2bafca, 0x7cf482d7, 0x8a95c6bf, - 0xa5eb2d70, 0x2feb377c, 0x2dfcc1b3, 0xd47b5e6c, 0x6fcf5806, 0x025a6a79, - 0xff3cefcc, 0xce98a3b2, 0xe27c25dd, 0x7a3f8893, 0xc13eaf10, 0xfa113eb3, - 0x92a5fbbf, 0x3f9049f5, 0x85d7cb47, 0x175f2bfd, 0x8f047e45, 0x97a1f81b, - 0xe341cb8f, 0xab9546d2, 0x09f2a1f8, 0x9da010e6, 0xff0683fe, 0xfe00b4ce, - 0xdfe87e28, 0x898e5093, 0x7ae0f7fd, 0xc434dfbb, 0x083f7ae0, 0x29c71be2, - 0x806b1838, 0x2ad690fe, 0x882a8863, 0xe1621fde, 0xb9f7ac76, 0xa79fdf4c, - 0xcfefa230, 0x4060e605, 0xa67417bf, 0x5ae50166, 0x0456cbaa, 0xbe60acf8, - 0x6ee50626, 0x38054bcd, 0xd725234f, 0x1fd744a7, 0xa61537b5, 0xa7f7fca1, - 0xf7ff280a, 0x698dec19, 0x5d84fdaa, 0xe321408f, 0x3f9f3861, 0x0ec776c0, - 0x3e284bc5, 0x14429ff6, 0xf33d0663, 0xbf888b19, 0xebe444d9, 0x57f13d44, - 0x066d4e23, 0x3c94e3f6, 0x9feda1a6, 0xf9edf190, 0xef744b4a, 0x16ecf183, - 0xf7c3f542, 0x60f8432b, 0x2c3f243f, 0xa7d1fa8c, 0xfa563e71, 0x64bea663, - 0x6a75d027, 0x86974b84, 0xc716c182, 0xcb998be5, 0x4fb49e97, 0xe67d7133, - 0xc8a8de4c, 0xdd8f6a65, 0x09d1e5c6, 0xf843e49d, 0x1d9a4944, 0x9c80d724, - 0x97f8abbd, 0xbb8f11a7, 0x2d2ea68c, 0xdd16eca4, 0x7d94fa9f, 0xff707d30, - 0x7fd94bbd, 0xeffbe16f, 0xefb5991c, 0xf1babb12, 0x3aecc67b, 0xfd972fc4, - 0x6d8f995e, 0xf22adfb8, 0x0b7ec871, 0xf9c5eb03, 0x832b2513, 0xc7c0b574, - 0xdc253abf, 0x36c47c8f, 0xf4f8d2e7, 0xfe0cfcb2, 0x58c15ade, 0x13c651a6, - 0x19704bfe, 0x20ce6659, 0x5663549c, 0x9b1e29c1, 0x06c8feaa, 0xe69e5549, - 0x679551cb, 0x7055db34, 0xaab14b56, 0x8736a8fe, 0x97f5ce0a, 0xede7eaab, - 0x31e0aa75, 0xfaaa15ed, 0xaa5c3b63, 0x1aaec2f2, 0x1eb8f955, 0xd09e0a8f, - 0xffaaa0db, 0xaa7da777, 0xcd7d49f2, 0x9f29f2aa, 0x5be0a8b5, 0xf554dbfb, - 0x57eabf6f, 0x7fb09795, 0x354f9556, 0xd3c157ee, 0xeaabafcc, 0x16fb80bf, - 0xb61dcff0, 0x0cfe556e, 0xbbeab8e9, 0xaa4e733b, 0x75e417e0, 0x270e2df6, - 0xe72d68be, 0xfb6cd1fb, 0x5876aa07, 0xfebe68e7, 0x7b6f3c61, 0x510b1fcf, - 0xf4d76e4e, 0x4add21a7, 0xf222735a, 0xdcf16671, 0x2c664043, 0x14aab1db, - 0xf94e5bc5, 0x1d308753, 0x8a5fdced, 0x715f926c, 0x05a610f2, 0xd0a58bae, - 0x44d7b31c, 0xc8b4c61f, 0x8ad53853, 0x3dcc34a8, 0xdf44e98c, 0x5728a9aa, - 0x3f5c785f, 0x2a28f91a, 0x074fa146, 0x827d67d1, 0x7eb9f886, 0xf28fc9b1, - 0x24c532c7, 0x96139032, 0xb1d65a1f, 0x9a8b4c02, 0x1af66d31, 0xfa0f5f99, - 0xba519780, 0xfe666bc9, 0xaf67206c, 0x93fae08d, 0x43a795f7, 0x44ab233b, - 0xe699aa33, 0x48258f51, 0xe5f5bed0, 0x765d9c96, 0xb0edd6c6, 0x42e5d7cf, - 0xc59e19ff, 0x4e01a23b, 0x30058e63, 0x2398167f, 0x25b19936, 0xfa76df3b, - 0x97c287f2, 0x244d9d33, 0x5cf6c417, 0x7694ffd4, 0x6e7e9637, 0xdf2198d7, - 0x11e74bf7, 0xf1adf798, 0xc21df4e1, 0xa75f9925, 0xb60b475d, 0xf69ef90b, - 0x4cfc7c10, 0x977fdf1a, 0x0a7d73a4, 0x66eb8487, 0xacc6cbe5, 0x808ca7a0, - 0xa93adcb9, 0xf0ea0ce1, 0xa027d9a2, 0xe0d7627c, 0x892b907b, 0xe0832958, - 0x4e01c3db, 0x6c625840, 0xc7eb967f, 0xc5d5afd8, 0xfa00d9d8, 0xc351a849, - 0xcf9e615b, 0xa3e20e66, 0x89f1aa5b, 0x8fdd0630, 0xf43b769d, 0xc60aadb3, - 0x3d56f00b, 0x7a9437d7, 0xf68c34a3, 0xf8d32ff7, 0xcdaece7e, 0xf49ea3b7, - 0xe79e3ca5, 0x3e8bfdbc, 0xeb7b44ce, 0x3589a52a, 0xf205c11e, 0xb4e95acd, - 0xae9ea0fb, 0x8423e611, 0x348bf2de, 0x1dd7be91, 0xa090447e, 0x1269a7de, - 0x7e9589c1, 0x0d52771a, 0xbf801bb4, 0x6609f44d, 0xe63db7c8, 0x9b3f1013, - 0xf06769d9, 0x885a331d, 0x3cc8d7fe, 0xcbf86b61, 0x0f418fa2, 0x769d79d3, - 0x13bba7ac, 0x271f33e8, 0xb86663d4, 0x47e3c94e, 0xa3eb10b0, 0x0d3e86a4, - 0x9f40dc73, 0xd47d4a8f, 0xddc5fb43, 0xe80b2926, 0xa6c585fb, 0xda211d8a, - 0x9f9e54fb, 0xfeea310d, 0x1f3e5a2d, 0x6cbedc8a, 0xf0a8ebe6, 0xa6689af1, - 0x526be392, 0x846f5bc6, 0xc8cdb5af, 0x6ef8015c, 0xd0cc7e85, 0x55abe1be, - 0xe83f1c66, 0x4fea4ed0, 0xc764f2e4, 0x6ec8728f, 0x21c75e0a, 0x3f9408f4, - 0xa3e908a2, 0x7c08dfcf, 0xdbd2a868, 0xfeb26f51, 0x7b809343, 0x116b2273, - 0x5358be50, 0xdc447aca, 0xae5744d7, 0x793e8433, 0xd654ba33, 0x839fd94f, - 0x3d774bd7, 0x9c12fde3, 0x31d57fef, 0x1f56c7d4, 0x05718f8f, 0x3a4c53d0, - 0xd662cba7, 0x98fe45a2, 0xbd29dacc, 0x7a52f585, 0xd4a7eb1b, 0xa622ccc1, - 0x694ecca5, 0x3a527319, 0x2d28799d, 0xce942d67, 0xce94ed64, 0x8294bd62, - 0x93a9433d, 0x9aeec999, 0xa637fb07, 0xd293980b, 0xa50f31ef, 0x7e9ce999, - 0xc10b582b, 0x4a76b377, 0x24ef803b, 0x8c01fa3d, 0x9c827694, 0x904df4c3, - 0x79769873, 0xa3652625, 0xd287201f, 0xa53b5e23, 0x94c5bcc7, 0x541d78f6, - 0x396f6def, 0x9d78efa5, 0x56f09e94, 0x75ebda50, 0xde53bd51, 0xf5df4a1a, - 0xcf7d287a, 0x69e940db, 0xdfd28faf, 0x1d299b79, 0xc67e07a5, 0x2be9cdf9, - 0xf53e7d44, 0x0243bd23, 0xe591ecf9, 0xe68761d2, 0xb8f1dc99, 0x40661a6e, - 0x235b283a, 0x7359fd20, 0xa43f0e34, 0x0b56729b, 0xe1ba42f7, 0x0cdfd704, - 0x0fd248d6, 0x82f56dad, 0x0876ed04, 0x5808da7d, 0xa9e9e9cb, 0x9f208d73, - 0xbad93a4b, 0x19c23b08, 0xee81194f, 0xfd3ce876, 0x64bca03b, 0x08d734a7, - 0xc8e4d67b, 0x8fb1ff53, 0xe93e54c3, 0x03346b08, 0xfb3d2b3c, 0xe38138a9, - 0x7befc281, 0xaee6733b, 0x253c44cd, 0x34c5f3c2, 0xbf512c30, 0xfa44c47e, - 0xd9db6175, 0x93c00d42, 0x68454c1a, 0xebd40617, 0xae1fba42, 0xf2b9705e, - 0x9655b6dd, 0x0d879c46, 0x0e5a809f, 0x7d19a959, 0xd5f3ab85, 0x5ebe6aed, - 0x837b4cff, 0x09eb03fe, 0x7f6f6837, 0x7d32a396, 0x3a7effc2, 0xdd6fa60f, - 0x6bf68ff5, 0x8e640fc8, 0x5774fdc1, 0xfd339734, 0x04ee9fa0, 0xc8c577bc, - 0x1a4cc6f0, 0x5c43ca17, 0xd29b0db7, 0x77803efd, 0x1f573985, 0xd47ff2c7, - 0xd14277d8, 0xa6d770ae, 0xc933825c, 0xc621b13f, 0x8f931393, 0x97df3cfa, - 0x0d1f935a, 0xbff80293, 0xafcb9d39, 0xe95cb7ad, 0x447681dd, 0xc16586b3, - 0x979b3b77, 0x7681cc6f, 0xf419bc7e, 0xdc478007, 0x0b31bd5a, 0x6a37d3ca, - 0x19656a26, 0x78fc7887, 0x4d9ef573, 0x8f255fa8, 0x7686c98e, 0x99796433, - 0xb857db1a, 0x55bce806, 0x95a7b6af, 0x7e649ff4, 0xce6686a9, 0x954d6c82, - 0x3a1df4ed, 0xdfb81156, 0xefc64cfd, 0xd53c5957, 0x57fdcedd, 0xfee19186, - 0x25fc6027, 0xc3bfb923, 0xfe48ceb2, 0x7ff24b0e, 0xca03bc9d, 0x7634db2d, - 0x6b44e954, 0xea1d5aed, 0x3b598bfb, 0x810ee3f2, 0xe14bef7f, 0x0a28217a, - 0xec0373e9, 0xd3deadf2, 0xfc03328b, 0x9f0ab684, 0xc97bf680, 0x0fa15ac8, - 0x07e49ff7, 0x2dfbb405, 0x15c12e15, 0x8781f689, 0xb965cfca, 0xf80e927e, - 0xfbe12ad9, 0xb992fd40, 0xa15d7012, 0xd2768adf, 0x605158f3, 0xf8b3a77f, - 0x3b07ac3c, 0x75d5f499, 0x782bc27a, 0x97654ebe, 0x95f6c01e, 0xff2e0c75, - 0xabb7067e, 0x5d013d77, 0xe24c1f20, 0xdd89f376, 0xce3fa489, 0xa0770d69, - 0xa9e274fd, 0x6f0465d1, 0x3d40ec99, 0xc9eec4f2, 0xb39d31d3, 0x3bd52665, - 0xb41eb021, 0xb96ce787, 0xd4fcc45b, 0xdb0bc00c, 0x7a27a33b, 0x41e5b39c, - 0xcb47fbf9, 0xe358bcb0, 0x91da09fb, 0x22fb8dc5, 0x1c9e4ed0, 0xa6124af9, - 0xf57d3427, 0x5dffd0dd, 0xdc2bf666, 0xe31b9d9e, 0xfe1cb1fe, 0x74a9f731, - 0xbfd7ea1d, 0xf5a74f4b, 0xc41ccf9c, 0xec835007, 0xf6f65bba, 0x8a4d061e, - 0x3fded6dd, 0xe65ccc15, 0xc11f30e8, 0x5ecbb4b4, 0xd657d386, 0xe9823ce3, - 0x194f5ef4, 0xa7e52faa, 0xba608e5b, 0x3bf5d724, 0xff179f9c, 0xbcaf7be1, - 0xc7c8f008, 0x07a8cdeb, 0x37d13e65, 0xebf92763, 0x21f90c74, 0x45a7926b, - 0x746c048b, 0x787ca0c6, 0x835169f6, 0xad21b9fb, 0xc3610c25, 0xb41ae97d, - 0xb745770b, 0xb3b8d0d4, 0xe3ce19c2, 0x210fb0db, 0x3b45645d, 0x809f9063, - 0x3e1d692f, 0x10d3e993, 0x634731ed, 0x1fcf187e, 0xe1ce17a8, 0x5af503f3, - 0x27ea04c2, 0x13fb2046, 0xbfdc06d4, 0xddfef26d, 0x38093cc6, 0xcf48d61f, - 0x64ebf40e, 0x67fe7095, 0xb02e9c91, 0xfa44d37a, 0x96cd9c84, 0xb89dcf16, - 0xe897560e, 0x3ba40beb, 0xf40706d8, 0x19827491, 0x055bd7da, 0x219c830e, - 0x7e87f0bc, 0x42c98b0c, 0xbf828d7a, 0x0bda02b5, 0x1c7033d0, 0xdf834cf3, - 0x9b177429, 0x4235c7c1, 0x65acbfa6, 0xdf053dbc, 0x9f2e0cb8, 0x83496f01, - 0x7c6568f8, 0x009a1c60, 0xd1ea027c, 0x66f006f8, 0x05d21b76, 0xa7817a48, - 0xc703124c, 0x8471ad5f, 0x7a645da1, 0x4fe8fbf5, 0x02394289, 0xf753fe78, - 0x69f22324, 0x327238f0, 0x46df08d2, 0x6f5187d0, 0xfce2e99f, 0x11e958db, - 0x18423ec8, 0x3a2c9fc7, 0x35681fd0, 0x017416ad, 0xf326b5e3, 0xa5667a7d, - 0xcae51ba7, 0x3b08e2cc, 0xac9df7d2, 0xf3999d7d, 0xc04c91f7, 0xf81b146f, - 0x41c4d899, 0x4f47f0bd, 0x97127bbf, 0x97b59934, 0xf9fee2e4, 0x70b3fdf8, - 0x3a3eb6fd, 0x4ff107b3, 0x3baa79cc, 0x5e741a06, 0x197dd794, 0x6ca4ebf7, - 0x1c0e3f13, 0xe0079247, 0x8d44bf40, 0x41e81cba, 0x65742b05, 0x71a21a13, - 0xe444d1bf, 0x7a819ccf, 0xe486944a, 0x6129c83b, 0x33fd4841, 0xf9e4ae88, - 0xaee7d657, 0x375a4c8c, 0x03af89ab, 0x171bb7eb, 0x5583ca46, 0x6dfa09d6, - 0x011f3604, 0xa658df74, 0xd7680bf5, 0xac28fd62, 0x919de2cf, 0x8769d743, - 0x03399a4e, 0x1ac3f4e5, 0x74366ef3, 0x7edc815e, 0xc3ed7a4b, 0xf90e5471, - 0x7dfc91a2, 0x436af801, 0xb8f5eac1, 0xac6dfd59, 0xb48cee6b, 0xc989f9a1, - 0x3ee2660b, 0x68cb589b, 0x47cb83fd, 0x575ea63d, 0xa3c737b2, 0xbbf988ff, - 0xce7ac1be, 0x8655de4c, 0xbaf07cfa, 0x1a97742a, 0x105f7a1b, 0xa65f3933, - 0x954fd846, 0x92215e93, 0x114ce09e, 0xa2ed03e3, 0x1f7c190d, 0x1335fdba, - 0x23ec43ed, 0x5cb71fa3, 0x93ef577b, 0xa50eb0b9, 0xae683457, 0x1cefa3b0, - 0x484ce1fa, 0xddeafda7, 0xf50affd5, 0x1a657da6, 0xb06ff987, 0x10e819be, - 0x9d80f5f1, 0x2fdaf001, 0xa3a0b4f6, 0xd992b1a4, 0xfa55df71, 0xf3f723d9, - 0x49df9d0b, 0x645735f2, 0x820e493b, 0x2f401e65, 0x7e896900, 0x56731978, - 0x68dd90b6, 0x5907cccd, 0xf6bd6e8d, 0xfe5fb425, 0xefd0cf49, 0xd242af38, - 0xe7f8c095, 0x65ba4a55, 0x5917c7e8, 0xf311ea39, 0x3f94ec2b, 0xf3ced2bf, - 0x417f3c8d, 0x17f28385, 0xbe783a54, 0x3e61f209, 0x7bf85616, 0x42eed0bd, - 0x41a48c53, 0x93a5783f, 0x50355f97, 0x0f603bf9, 0x87c90264, 0xde49f987, - 0xe1a67cb7, 0xb84f12f1, 0x0d5c005f, 0x123d4591, 0x1a7ddfce, 0x8624167b, - 0x01999114, 0xe9c2b67e, 0xf3f942d7, 0x13809fcc, 0x6af546f9, 0xbfe43667, - 0x719a2c91, 0xc0386f7c, 0xabf9c66e, 0xe9de6915, 0x351bf007, 0xd8cf14c9, - 0x7dadfb21, 0x67e48c2b, 0xfc875d05, 0xa2456cac, 0xf2f0c7ac, 0x7ecdcb6d, - 0x0e40c7d4, 0xdff63ad2, 0x001e9227, 0x1cedf0f2, 0xca5e8bd4, 0x484987b4, - 0xb37e6ab7, 0xa12f2f54, 0x19992af6, 0x9559f2ed, 0x97c6bdbc, 0xea0d7e34, - 0x3379a655, 0xf71a0e91, 0xafda3b32, 0x2a9f56cf, 0x9b78458b, 0x87e5cedd, - 0x56342e5a, 0xe12e396f, 0x731a3c78, 0x7ee7d516, 0xe94f46ad, 0xc830ad2e, - 0xd2deb4cf, 0x2a18fca0, 0xd83dec6f, 0xa955424e, 0xb3d4137d, 0x8fd138c0, - 0xf3cf4dbd, 0x1488f77d, 0x8b54b067, 0x4182e65d, 0xa7914efe, 0x187c82d0, - 0xc545f245, 0x525fa35f, 0xf9923fc3, 0xc45df814, 0x3176f971, 0x5d95c93b, - 0x27207aea, 0x52af2835, 0x67f9d4da, 0x2fc504b2, 0xe0879aa5, 0xb87ab679, - 0xe71e0bdc, 0xc2bab8e0, 0x34b8d146, 0xd7285c7c, 0x74d73f20, 0x2b73f288, - 0xa124bb45, 0x853f6bbc, 0x92f51fe3, 0x9e00bac8, 0x13345d55, 0x66d669e9, - 0x6643b90d, 0x0b925eb3, 0xe2b71b37, 0x671e08df, 0x6436f8f0, 0x1cdf6968, - 0x1bd707d0, 0x7d6c1f49, 0xb8c1a4c4, 0xe15be822, 0x973857e8, 0x099e1a55, - 0x532230f3, 0x6bafd7d6, 0x34693cb9, 0xacea9d11, 0xfa04e58f, 0xa5d1841f, - 0xeebeb023, 0x72bcec7a, 0x68e91b8a, 0xac72c1dc, 0x93639658, 0x2a7c60fa, - 0x933873ff, 0xd6f7e602, 0x7c1518fe, 0x5544d5fb, 0x2e1012fd, 0x8d53e581, - 0x69f2aa79, 0xf82a71e6, 0x5514db0e, 0x54d219fd, 0xce677c15, 0xb3faaa9d, - 0xf055f3ed, 0x544bc55d, 0xee3ae7f5, 0x2fcf9555, 0xbe55487f, 0x0546b9d0, - 0x7bf8aa2f, 0xaec5fd55, 0x92f95546, 0xe555279a, 0x9293f6c1, 0x3f726696, - 0xe79b56cf, 0x8be483a4, 0x0e46704b, 0x14a967ad, 0x3dd703fb, 0x53eb822a, - 0xe51af5c1, 0xe04178f5, 0x48feb1fd, 0xe29df20d, 0x91ed637f, 0xd75cff2a, - 0x3ec6c9e4, 0xec72fa13, 0xb2dd23ef, 0xc51fdc13, 0xc53bfcfc, 0x04fdd57f, - 0x56f683d4, 0x715ba647, 0xabbf43bf, 0xf9fd0f4b, 0xb7bfe435, 0xb40bd736, - 0xe7ae6e0f, 0x7aab957e, 0xc00d8ae6, 0x7ef38583, 0x828e78e5, 0x70447327, - 0xcf1860ff, 0x95fb26df, 0x52bf439e, 0xb03f6336, 0x17787e28, 0xac509bb5, - 0x467fa1f7, 0x7a08f6a8, 0x662e5b94, 0x07284836, 0x97ff5397, 0x5823ec2b, - 0xd2567988, 0x398daf56, 0xbd5b7da0, 0xc61ead6f, 0x69399756, 0xbcd0b3cb, - 0x1fc8c3cd, 0x94e668f3, 0xe7816b2d, 0xa25321ff, 0xf9104975, 0xf75f3f3c, - 0xd03db9c6, 0xa5956b5f, 0x706ae508, 0xf3bb9279, 0x941bb1e2, 0xd5f2bf3f, - 0xd1bfee0f, 0x671d75f7, 0x87ca029a, 0x24568bf5, 0x1d004732, 0x7ed08648, - 0x74c81ff9, 0x27ac9ee5, 0x5a33d63f, 0xcfc893d7, 0xd7ff2617, 0xddf0bdc4, - 0x3dcae979, 0xfe43a7a8, 0xea1f300f, 0xcf9ebcd1, 0x29e744bc, 0xbf40f352, - 0x2c3bfd47, 0x941edd34, 0x95ad17db, 0x5a07e8fd, 0xd097a91d, 0x7e324fce, - 0x0eea7e46, 0x83abb71d, 0x07e7f7ed, 0xb276edec, 0xedcbf7bf, 0xad5396ec, - 0x8ccf7f99, 0xe45a263e, 0xf98840f8, 0x09b546d0, 0xab12af28, 0xf9024fc5, - 0x4f523ba2, 0x498b047e, 0x6a983bf6, 0xc5017e54, 0x791dd06f, 0x6f7480bf, - 0x7e415ae9, 0x6017f47a, 0x75e5077b, 0x2417f609, 0xe8b4ff19, 0xb51bd8e3, - 0x23f206cf, 0x04fd1084, 0x27f8a1e1, 0xa3f1fb82, 0xccfb813e, 0x27d270ca, - 0x397dc782, 0x6650e4b3, 0xff48f23c, 0x7e503bc9, 0x7ed1d29f, 0x84bd1c38, - 0x1fcce149, 0x266f7ed0, 0x7223efb7, 0x91f95462, 0x0fe644f6, 0x64b35ff4, - 0x321127f3, 0x48cc5b0c, 0x51c6df7d, 0xbcdbdfd8, 0xbb3a13bf, 0xd841f48d, - 0x7bfed0f6, 0xeee7e64f, 0xab69465c, 0x01b7976c, 0x9cfa631f, 0xd9fa4cd7, - 0x843fe036, 0x4a257bb7, 0x4a1cdefd, 0x54ed7a77, 0x4c5bcbbe, 0x83af1ef0, - 0x72debde0, 0x9d79f74a, 0xb792ff94, 0x7a9fe082, 0x7bb6945d, 0x15ff286b, - 0x03e087af, 0x5f8206de, 0x44507d45, 0xa533753f, 0xa85b786f, 0x46dbd3bc, - 0x3f5e9bf0, 0xbdde5da5, 0xdbc87f94, 0x6f11f04e, 0xbcc7c107, 0x78f7045d, - 0xdb7d287b, 0xeff94bdb, 0xdc134f78, 0xb1938f2b, 0xfa2f5ee6, 0x84a25c2b, - 0xaeb3ddfa, 0xd7ea336a, 0x331a65b6, 0x9736f38a, 0x39fa0566, 0x78f255b6, - 0x86956d9f, 0x87a040fc, 0xb39f51fa, 0xf8fa7b2d, 0x405f2a34, 0x49b15be5, - 0xabac4a30, 0x56cafeb8, 0x159ea9ea, 0x77c1020f, 0xfd2b6adb, 0xb25b805a, - 0xbadca9c3, 0xedbb244a, 0x3a278d79, 0x245deb9b, 0xae3aadbf, 0x1074283f, - 0x22e9fb21, 0x974a44b2, 0xa3fc7365, 0x23ef4232, 0xfc4a5919, 0xc707b9a4, - 0xf182ab67, 0xf555be21, 0x5a5f8c46, 0x49f183ef, 0x3aae3fa4, 0xc3247804, - 0xc07f1178, 0x6cc2fc87, 0xad97d719, 0xaf08eb55, 0x94f365e4, 0xda346778, - 0xfa9e6de9, 0xa56f84b9, 0x36cd7e48, 0xfbe8a1d7, 0xe7ca4e50, 0xe1f1ac7c, - 0x50fe7f4e, 0xf082327c, 0xddb8c6df, 0xd2fa0c90, 0x00e310fe, 0xc7a9478b, - 0x198f78fd, 0x26f1fa43, 0xb2627acb, 0x3d8ff9c0, 0x6dff122c, 0xc1f7a067, - 0x7e81cf77, 0x503943e7, 0xfa156fba, 0x72cd1eab, 0x3c02cc4d, 0x3f8d247e, - 0x531c0224, 0xaf4fdbce, 0x1ea0f717, 0xae7deb0d, 0x3e37f209, 0xb689d9b8, - 0x6966ec71, 0xdb5bb22d, 0xd01357b2, 0xa82c95ff, 0xcb4947d7, 0x3bb63c65, - 0xd5cf7b78, 0xb64fe48b, 0x76903aae, 0x865bf784, 0xfa8e26fd, 0x61ba187d, - 0x1a481632, 0x55c91914, 0x2fec45e2, 0xe5cda1ec, 0x66fc5fd8, 0x215fd287, - 0xe775f7f6, 0x65e3e469, 0xbc085756, 0x37279386, 0xb38b2393, 0x8e48e322, - 0x9424b124, 0xb8ebcf23, 0xe49df2dc, 0x861d24fa, 0x1fb43499, 0xc4ae7e25, - 0xe8e383d3, 0x243d3235, 0x61c74219, 0xfde80d57, 0xddb7aa3e, 0xe749c9b1, - 0x0b3e304b, 0x6c75ab45, 0xeaf3ae05, 0xdaf37092, 0xa4a0f410, 0x018e505b, - 0x468bdfdf, 0xb9b3b523, 0xe1a3b79c, 0x56cadced, 0x32625c11, 0x6bc842fb, - 0x6e5a7d25, 0x4e2c81e7, 0xbe0f49b7, 0xae18f1b4, 0x3a3adbef, 0xc69cf413, - 0x04ed11bf, 0xc92d09df, 0xfb6d44d7, 0x78013d8e, 0x79e3cb35, 0xb5cfef4e, - 0x7b40ff23, 0x915728f9, 0x7fc9f25f, 0xcc0566c1, 0x5addf2bb, 0xa3fd8fd9, - 0x29a21b6b, 0x2eb55cbe, 0x36a3f50c, 0xb07a2466, 0x85d13cea, 0x4560f401, - 0x1f410cba, 0x4af4b2fb, 0x3254d53c, 0x7c32e311, 0x728a9e5f, 0x583ef009, - 0xe1fb451d, 0xdeef65d4, 0x5be01639, 0xd47688ae, 0xe5ab9ecb, 0xfd2713e7, - 0x26e74351, 0xdb9c7cde, 0xb7fdb77d, 0x7bf41eb2, 0xb3e9c827, 0x7a41e768, - 0x77b3334b, 0x52dcbac1, 0xcdff226d, 0xb3c557ad, 0xb91a7681, 0x7da3c7a4, - 0x5335fdc1, 0x803ca1fa, 0xa67d26fe, 0xaa330fae, 0xa1233d45, 0xab6f9d4f, - 0x1a66703a, 0xcb56d3f4, 0xf6bb6e3f, 0x7d8471fe, 0x93f21af5, 0xf429f500, - 0x4dfe4093, 0xe78097d1, 0x191a3716, 0x32eb73c9, 0x41e519a3, 0xe49c25b7, - 0x1362db5f, 0x321ba1e9, 0x9ea18757, 0x8faaa86c, 0xdea474c6, 0xa77d03b7, - 0x7dffbbdd, 0xe4812d9e, 0x817f3f2d, 0xfa0c5984, 0xae7abdc0, 0xb6faf8e4, - 0x7944cb4c, 0xc3f2a1a9, 0x8b7dffbb, 0xac077d0f, 0x3490f085, 0x7e0f912c, - 0xe29bbe00, 0x2fdf02d4, 0x444e6740, 0xabae74f8, 0x4243e507, 0x8b1baf9c, - 0x56ce9ab6, 0xcae2f9d2, 0x5d33e238, 0x31e987b5, 0x18c8b2bf, 0x9f0ae7c8, - 0xfffcb5fc, 0xbbe71cb4, 0x59b81c99, 0xf7e337bb, 0xbe73a59f, 0x369ece19, - 0x154f230c, 0x9acf18fb, 0x4b6c8a63, 0x7d59eafb, 0xf6eafd48, 0xc567ce6c, - 0x643e7e7a, 0x72f4c54e, 0xfaf8c38a, 0x96c73c44, 0xa9f9cd93, 0x714912cd, - 0xd674b6e2, 0xdf037185, 0xf7f70d72, 0xdafff1c4, 0x3fc9d32a, 0xa2782ad4, - 0x3e78197d, 0xeb8695c2, 0x147306d7, 0xa6b7fd09, 0xfcceb972, 0xabc6331e, - 0x409a9da1, 0xf3dec1fc, 0x9198e9a9, 0x0bfe4c3e, 0xa49ef12d, 0xa3b7f00f, - 0x17fd1c5f, 0xdadddfc1, 0xbf6f86af, 0x984b86aa, 0x354f054e, 0x6669e1aa, - 0xe6c96c35, 0x361dfa7a, 0x490cfe75, 0x1ca7270d, 0x73f0d309, 0x7f01a6ed, - 0xbbf044b3, 0xa07e0199, 0x01769a0d, 0xafa525e7, 0xadb2fc96, 0x93dfdca9, - 0x73f6af5c, 0xb596b224, 0x6df90231, 0xfcb6f954, 0x73fa0255, 0x7cead56c, - 0x8c150798, 0xbff48acb, 0x9f95d724, 0x02e9718d, 0x4b3aee7e, 0xc5cde9eb, - 0x238b6875, 0xcf934a3e, 0x1fdd0d05, 0x95b8d0b7, 0x7c0f9076, 0xfa45e301, - 0xe62f840f, 0xc76726ba, 0x05f03e73, 0x7df997ee, 0xa503e43a, 0x41f8e1bf, - 0x3962c7e1, 0xab9ca26e, 0xa5b722b9, 0x97a9ab9c, 0x0475c7cf, 0x92b9c79d, - 0x81e7465c, 0x09aef4ae, 0xc877c50f, 0xce6cbe67, 0x946e9877, 0xdf20d7cf, - 0xef9cf4f9, 0xd5f0df30, 0xfd28672a, 0xafbcbcf0, 0xcc37b43c, 0xf8c071fc, - 0xab47b656, 0x82477760, 0xd3bcf039, 0x740ff843, 0x3a3337ba, 0x0f2b5a47, - 0xbf338be7, 0xe908d3db, 0x0b975a5b, 0xd66567d7, 0x338f3d59, 0xfe51ebf5, - 0xdff7979e, 0x38dd820d, 0xdb94c05a, 0xbb668da5, 0xccbdfd11, 0x57f2a19f, - 0xd5877e28, 0x31acd22b, 0x0188ff80, 0x4cd3823f, 0x33e34de7, 0x35118fc9, - 0x2b3771d5, 0xccf73c04, 0xa2046f98, 0x554e85dc, 0x658fc790, 0x97d0fd97, - 0x035e383c, 0xce02abfa, 0x0f441923, 0x3573b923, 0xe7014995, 0xff655bca, - 0x9b1f00c5, 0x7f609796, 0x7896cc3f, 0xd679863c, 0xda9fff72, 0x6ab8665f, - 0xd833b553, 0xdfaab27e, 0x722fd956, 0xfed5f6f3, 0xf4d5c337, 0x0ecfda61, - 0xb21cdf6a, 0xd576c1fd, 0x11afbc7e, 0x3e436f1f, 0xb5ffce18, 0x1ba7965f, - 0xf45e9e6c, 0xd818e97f, 0x06071495, 0x6a8898fa, 0xc369ff23, 0x5d5379f9, - 0xa60fdab2, 0x1f927e63, 0x90d647cf, 0x3e6048fc, 0x9859df8a, 0x47d7f287, - 0xbbf1e74d, 0x1371b960, 0x8798c179, 0xfd00dea1, 0x3f57f2a9, 0x46d3f7c2, - 0x3c42eec1, 0xfff3c783, 0x89abdd8a, 0xfa4bdf1c, 0x64b84a73, 0xdbde81b8, - 0xe32575ea, 0x3dc21bf7, 0xfeeb1835, 0x762ebb3c, 0x1b3de83d, 0x7c08c630, - 0x71bb3576, 0xfb84cfbe, 0xf58fa724, 0x27a21a71, 0x1d96ddcb, 0xb27a00da, - 0xa8695de8, 0xf2345af7, 0xa1fc2f39, 0x65bd6cbf, 0xfd10a6e7, 0x029bfa2b, - 0x8f002b5b, 0x956dba00, 0xfe81e6f5, 0xd0ee2496, 0x3163b406, 0x3fa90ab8, - 0xd2a35ce5, 0xeb37d35f, 0xf7ecab6f, 0xdeb3fa52, 0x559f1ea3, 0x59f1a1ef, - 0xe947fde5, 0x2f8e2b6f, 0xb4dd5f04, 0x1e8ed93f, 0x7aa96fe8, 0x8783567c, - 0x72d567c6, 0x7f40e1ff, 0xbfacdf4d, 0x931ef936, 0xe1d3e64d, 0x0e37fdce, - 0x1a76ab9c, 0x29b4ae51, 0x7f7940fe, 0xbfb414bb, 0x37f796ad, 0x714bfbe5, - 0xbddfe4e9, 0x18df33d4, 0xfdc35f6a, 0x247ac98c, 0x2648f593, 0xcf0891eb, - 0x3ea67a99, 0xf0b0e81e, 0x22f9b6c5, 0x1e73e3ec, 0x153e333a, 0xf62f19e0, - 0x5f6117cf, 0x99e2f39a, 0xc9f04903, 0xccbe2fcb, 0xe6787fcb, 0x9b94324a, - 0x2fcdef7c, 0x962a3803, 0xde0ac7ef, 0x8db7bf4a, 0xbba37ae2, 0xbfee73e1, - 0xfb8af904, 0x87aa6356, 0x42f17fa1, 0x32d47f72, 0xe94eefa8, 0x310f2cb7, - 0x6eea4a2f, 0x467e4f38, 0xff287914, 0x40bfe1e6, 0xee53cfb4, 0xefab9467, - 0x6d454467, 0x8c2ffd22, 0xef28cdf9, 0xba0e8c22, 0x28d6f84f, 0x642c1fbe, - 0x376e0af6, 0x39f25948, 0x31cfba0d, 0xd76e58bf, 0xb1cfcb7c, 0xb1c6a17c, - 0xdfd9ed1e, 0x478aaa4e, 0x173958f5, 0x7f783797, 0x1bf5d772, 0xbe0e1f9c, - 0x23e7393f, 0x23c2eb81, 0x3ba5bfb8, 0xb9f7e257, 0xa886fc02, 0x9f370ef7, - 0x7db8a3b5, 0x0e9f383f, 0x0e319f3e, 0xfee69f3e, 0xfeb0b5a8, 0xcb7ee8ee, - 0x5d9fc413, 0xc86be721, 0x5fcd06bc, 0xd8a628fd, 0xb7a45a79, 0x32b7cd9b, - 0xc1f9caaf, 0xa2ca4146, 0x794feafd, 0x3183fd2a, 0x8e2a14bb, 0xb819f483, - 0x4e6deabf, 0x5d19fe86, 0xcf073d9c, 0x45fe3795, 0xde5cf21b, 0xd63e796e, - 0xb9d38546, 0x3d28c6ce, 0x51dddbd9, 0x97fa1933, 0x9a74d345, 0x72a8b297, - 0x8da96f3a, 0x8f68ed65, 0xd7239f06, 0xce9bb88e, 0x68ad6901, 0x703a4041, - 0xa461d92e, 0xe8b989f8, 0xc5c8e786, 0x8f239d9b, 0x91cfc999, 0x7425e947, - 0xea45b459, 0x7f239e43, 0xf7df146c, 0x713c71bb, 0x278c3f88, 0xa21c706d, - 0x31d1c799, 0xf5f2023f, 0x7f231766, 0xc7de3cba, 0xea5075e4, 0x861ecc1b, - 0xb7ab40f2, 0x68a7a84b, 0x613ef9c3, 0x4e5869b0, 0xf7c8bf08, 0xfbe8e947, - 0x34cd724f, 0xd7231aaf, 0x5afce7cb, 0x7a4fe908, 0x4fe29475, 0xc3674d0a, - 0x0d3cc9d1, 0xf0a7473f, 0x9e9302e1, 0x302df7ce, 0x0fd14ad9, 0xef0800b2, - 0xfa8098b3, 0xf7e22db7, 0x0dbb4581, 0x5337e7e9, 0x6ff9ff6e, 0xb9f9ba18, - 0x43353e7c, 0x4ee3f747, 0x8f61cc09, 0xd57e7a19, 0x869e8ce9, 0x66bb9a6e, - 0xec87599d, 0xeff2e2f7, 0x867b6115, 0x167553e3, 0x779fec89, 0xa85ca146, - 0x0f1f5b4e, 0x42caa2f0, 0x94dfdd1d, 0x08ee44e3, 0xd19fc72e, 0xa28e4eba, - 0x51e7d178, 0x624748a5, 0xa3e22a7f, 0xea0289c4, 0x9e2a37bd, 0xd7e1cdea, - 0x18dea0c5, 0x7f67d394, 0x1eb462ef, 0x127a50b6, 0x302c4fda, 0x07cb236e, - 0xf302a3b4, 0x01627ed1, 0x2f2c27eb, 0x9085f6b6, 0x609a4a17, 0x0d5292db, - 0xd0909e7c, 0xff92a942, 0xee5b43ac, 0x57aeb10f, 0xc6fd75e5, 0x601b4c76, - 0x8ed0713b, 0x2ae5fb01, 0xd517dbce, 0x61e32ca7, 0x17657548, 0xe9b18ec9, - 0x88933e15, 0x1e6106bf, 0x45fb04af, 0xd5b0de75, 0xfba14beb, 0x6d38f2fe, - 0xa346d62b, 0x1c55031d, 0xbcdb9f48, 0x9965296d, 0xcec8e383, 0x8d13e991, - 0x17a889b6, 0x5c725ff3, 0x97f40ccb, 0x74349b24, 0x5326013e, 0x6e612f75, - 0x38b4f459, 0xccdd4534, 0x2ed0926e, 0x3f3d25ef, 0xf896bae1, 0x62f0e120, - 0xa4ab7186, 0xef0176b8, 0x23f40d03, 0x97ae6fdf, 0x5c57b9e3, 0x048e3465, - 0xcefec0eb, 0xf38d0ec8, 0x747945cd, 0x518e69e5, 0xe5d58fc2, 0xdcfc71c9, - 0xe1d5fdc2, 0x3ae8097e, 0x4057b6a9, 0x380c0138, 0x5c27c5f4, 0x426b4c6f, - 0x045af279, 0x6db58bf9, 0xf207cc99, 0x45745527, 0xfb3ce0e5, 0xc9a6ffa5, - 0xdf0b0790, 0x9c207cad, 0xa136b3f4, 0x25d90665, 0x285869f7, 0x1c98cf3f, - 0xc828c7ee, 0x609ffce1, 0x1ea94d6b, 0x44d3e987, 0xcf975f37, 0x1db39067, - 0x9f11d9f4, 0x1c58fa2d, 0x759a7bd4, 0x9b73e9a1, 0x7ec0efdc, 0x185fcf21, - 0x7f911973, 0x3b9382b5, 0xdbeef739, 0xce82cfb7, 0x55e74613, 0x8d7ac936, - 0x4e444ed2, 0xd846153b, 0x45cf0c1d, 0xdf07660a, 0x9b3ecc07, 0xf9abd60f, - 0x7b486d2b, 0x791cc1eb, 0xb26b491f, 0x4cb2fd61, 0x94fd0dbb, 0x1a55f7c1, - 0x70da26d3, 0x0c671a7d, 0x7031a9d0, 0xcb4ee85f, 0x53cf1f7e, 0x2c747a99, - 0x70591cf0, 0x2173c7aa, 0x972837b1, 0x1d3797cf, 0x9b42e7e2, 0x78bd454c, - 0x14c9a10e, 0xfec74457, 0xa99cfc4c, 0x3a64df52, 0x64def246, 0x1356f1e7, - 0xa2020fee, 0x3ba1e7c7, 0x83cd18ed, 0x0e5a6f52, 0x7b26ab97, 0x5bfbc317, - 0xd53f76e1, 0x3e9d130b, 0x161fe00d, 0x4ffee8c7, 0x55f39198, 0x318fac04, - 0x7e95ef80, 0xd1d1cb6f, 0x172535bc, 0x7e1096f5, 0x6704de22, 0x1b22b64d, - 0xdf38dbed, 0xb4636fd0, 0xaf9cdf42, 0x5be7971f, 0x3e51a769, 0x434f7aff, - 0x58b2fcce, 0xd73913f4, 0xa6bb60e4, 0x83b446e5, 0x6fe391b4, 0x6186ded8, - 0x285e6bdb, 0xf238f7b7, 0xc8b23685, 0x50e9ed8c, 0xc3a0845e, 0xfe76e467, - 0x30ede357, 0x97df74b3, 0x9f305a60, 0xa3de942d, 0xa38c46a4, 0xddfa1b8f, - 0xebbf9637, 0x90247ed4, 0xfc717bbf, 0x1ecf932b, 0xee1ca12b, 0xdb2eda3f, - 0x619d8a27, 0x2ededb91, 0x3ee87bf0, 0xef4edc21, 0x8776c836, 0x0f3d4c25, - 0xf941f783, 0xe0ae5c3a, 0xc72ee6e7, 0x046b8a31, 0x77e5f3f3, 0xb40e8a3e, - 0x73ef504f, 0x04bb7364, 0x1c4bb453, 0x610d9fb2, 0x9da01bf4, 0x80fdf0a2, - 0xfa42b75f, 0x3f005ba7, 0x0d6fc803, 0x7b242bb4, 0xc90dbe88, 0xe7c8697d, - 0x053bf2a9, 0x5cd7f643, 0x4785a72e, 0xfe434b3f, 0x4feb8b2e, 0xf982efc0, - 0xae4785fc, 0x5e78e026, 0xce703198, 0xab43e286, 0x7bf3a717, 0x1cffc7d9, - 0xfed10aed, 0x457feecd, 0x86b4dd9d, 0x5ce5c0f4, 0xdf5bfc0f, 0x8cbedb07, - 0x821d9deb, 0xcda4efda, 0x5fe77ae5, 0x7acc7de4, 0x2df7a455, 0x2eb965ce, - 0x0ab61f20, 0x7f28e5e6, 0xe7e11f53, 0x5e3f56e6, 0x2103d9ff, 0xed1841f8, - 0x804e73fa, 0xacdc5c3d, 0xa35a3f27, 0x8dc47d29, 0xafc31ce2, 0x71cb87b3, - 0x1e4b7d79, 0x24f3f235, 0x5b17ae2e, 0x39d3f75c, 0x23f3e095, 0x243bd5c3, - 0xbea53dcb, 0x7947db01, 0xfe479a62, 0x23684b80, 0x964dbfa0, 0x7678c17b, - 0xf3c864e2, 0x12b90463, 0x18456875, 0xed93abb6, 0x3f8aedb1, 0xe8c8a2a3, - 0xb75ef808, 0x1a58c8b8, 0x8c8d2f40, 0x6e0ddf9f, 0x01dcceff, 0xafa55a7d, - 0x459f70e8, 0xf89c50df, 0x433901a7, 0xcab8658a, 0x0ffa518e, 0x70163f3e, - 0xf38c2c5e, 0x5a67b729, 0xe818dcf1, 0x962b6bb7, 0x6df9c48f, 0x582f5d15, - 0x3ffa1e61, 0xe739d030, 0xecbe650f, 0xb872f993, 0x43b1f3f5, 0xf6318ca0, - 0x97823b04, 0xc64e80d6, 0x68fe408f, 0xfb94d4cc, 0x5cb38c43, 0xfd08671e, - 0xafdcd6fa, 0xe6975fa7, 0x51afd086, 0xc504767f, 0xd461021f, 0xf4211d9b, - 0xec8213eb, 0xedcf900f, 0x1d49d09c, 0x270f307d, 0x6f611d6e, 0x919ee894, - 0xf6045ec3, 0x32678bc3, 0x239f6f51, 0x23c7bc0c, 0x608c31db, 0x221623b0, - 0x6799735e, 0xc50203df, 0x48ee5a51, 0x5c04eea3, 0xa7ad9b8f, 0x3711fb24, - 0xdc613ac2, 0xb2daf5a1, 0x0ce2a119, 0x274038ff, 0xef02ba28, 0x042ac007, - 0xc48695c4, 0x63e282cb, 0x38194e18, 0x5a1dabff, 0x7562aeff, 0x35e36afc, - 0xac30bfee, 0x0427fe60, 0x2eaa1f3c, 0x0bae5f9f, 0xe2a9cf8e, 0xba9d0b5a, - 0x887c7c60, 0x6f8cb26f, 0x2907b6ca, 0x452d3e0e, 0x64acfde4, 0xc707cf64, - 0xbd850cbd, 0xc3ea2d0e, 0xf7f48c15, 0x9e363f60, 0x5eff2517, 0x09cf6305, - 0x7d5ade74, 0x59e9e4df, 0x1cfbf8e7, 0x8fd8e52d, 0x50c3532d, 0xafbe0e3f, - 0xf09bc4a0, 0x7de04c98, 0x22dde569, 0xe10d62cb, 0x53b77cc7, 0x8797e2b9, - 0x4b12a6fa, 0x55eeb9c0, 0xdd3ea06c, 0x1e85f2a3, 0x59d6d6f7, 0x1c4fef14, - 0x82ec29ef, 0xa33b24a2, 0x66aa4879, 0x3cc00764, 0x86fae2a8, 0xce345d94, - 0xc58c354b, 0xaaa038f2, 0x7076013c, 0xbf184fa4, 0xe30fce2a, 0x76c1c154, - 0x4deccde7, 0x0de64a43, 0xfccdf9e5, 0x5e39068d, 0x646e46f8, 0x633be91c, - 0x77d418d8, 0xa69f8b2c, 0xeb04b8f5, 0x34597e81, 0x03c54284, 0x68fb4337, - 0x5f90ba07, 0xc4dfd1e2, 0x30caef54, 0xc9f74887, 0xb38e6284, 0xf1e4eb10, - 0xfc467ce1, 0x9507086d, 0x9859f80b, 0xbce0706c, 0xc3000c1b, 0x333d0590, - 0x56be4026, 0x15af37f6, 0x33308898, 0x4fdc8ddb, 0xe36bbca8, 0x866d77a7, - 0xff7407eb, 0xcfec30be, 0xfa53bfc7, 0xdb8ef219, 0xfb27be0d, 0x7dfc1ccd, - 0x951df919, 0xff9b87fe, 0xfb6ddee1, 0x2777d4c3, 0x3267bf70, 0x20e56bd1, - 0x4cbc12bd, 0x1efc47a6, 0x4abdc2e5, 0x0c77adb1, 0xfb3c37de, 0xfd1d8470, - 0xf0e303e0, 0xefe5a9dd, 0xed75fdd1, 0x9361e00d, 0x8c0fbe48, 0xafef6e4b, - 0x02fd171d, 0xbc06dae4, 0x4fe78434, 0x279d192a, 0xcf4ab8b0, 0x000e7489, - 0x1392a0c6, 0x4013ef01, 0xf10e1b7b, 0xf15baf73, 0xb0710b9d, 0xd02bd45f, - 0x4255b06e, 0x483b087e, 0xbf19ab49, 0xd5e0ac1f, 0x1a3d07a8, 0xf5c352e9, - 0x3ea6d9e8, 0xe935cf11, 0xe445fae2, 0x2e68e71f, 0x37e807c7, 0x0bf9d19e, - 0xce7c926d, 0xdfc4a471, 0xfbe4cb4d, 0x84cfd29b, 0xfe591ad1, 0x47fbd2f7, - 0xd54e23b3, 0xf2c6764b, 0x442fc5f6, 0x11ecfcff, 0x00d3eaa7, 0xe167d82e, - 0x2ba9d270, 0xecc66669, 0xd10bacfb, 0xef3b3f9f, 0x807495d4, 0x78d9f68b, - 0x464614f9, 0x097df8ce, 0x319fd10b, 0xd559b461, 0xd7385bfe, 0xd53cdff1, - 0xcf21341a, 0x5a36df63, 0xe8c94f39, 0xf3b3ad3e, 0x2e31a797, 0x47f654e9, - 0xdf482e87, 0xde0b2281, 0x717f9323, 0x9d0f1451, 0x9dd9d329, 0x1452eef8, - 0x68bb2dfa, 0xfa0d477e, 0x6bfe9fe9, 0x4382f4fc, 0xccca9779, 0x1bff812a, - 0x2c2b981b, 0x99ee8023, 0x9f9d7343, 0x81b8a603, 0xffd28f82, 0x6960bc10, - 0xbc4098c5, 0x0a3b51b6, 0x0d0a175e, 0xc70587a4, 0xfd082e87, 0x549cf1db, - 0x2fd6cfc4, 0x10ba75c2, 0x002a9fd9, 0x9eb79e1c, 0x7c42edd6, 0x1ec176ff, - 0x3af8eb00, 0xa22bef56, 0xd6a3fc75, 0x027a3d51, 0xdfc5dbbe, 0xe396686f, - 0xbbc64f50, 0x019f687c, 0x32b9d1dd, 0xfc9e8a5f, 0x05e36548, 0xb03fa047, - 0xcbf7346e, 0x69d3925c, 0x49cf1686, 0x01f74ba0, 0xfa85ad81, 0xf5976bee, - 0xeecc9fa8, 0x3d47a33c, 0x19c0eeba, 0xad4bde3d, 0xa9da1843, 0x8477a6db, - 0x32feffd2, 0x97f2ab5a, 0xd1d77629, 0xe8f5ec94, 0x16abab77, 0xeade1ee8, - 0x6e1fb9d7, 0x251c32f5, 0xb2df7763, 0x55b8fc9f, 0x98f5eece, 0x477d652e, - 0xc588ddf1, 0xdceaad2e, 0x089a92c0, 0xcabe3c55, 0x9782ab13, 0xc0eac0b6, - 0x21b4bb3e, 0xc31df549, 0xef82cf5d, 0xd0fe0e28, 0xd790affe, 0x736db171, - 0x16bbfa2f, 0xcc7ad4bb, 0x62b5ceec, 0x11ede20c, 0xfece1aec, 0x84b77e12, - 0x00d2108f, 0x7de60abd, 0xa3d7075a, 0x648c2aea, 0x0c22549f, 0xab595af3, - 0x7393e3f5, 0x54f45347, 0xa810eeee, 0xbb972ddc, 0x576e046b, 0xa975f2cb, - 0x8392e38c, 0x75d1a727, 0x37a39f52, 0xa5df0033, 0x88e7e515, 0x437d651e, - 0xc4855719, 0x290d8df5, 0xddb0e9ef, 0x5817dfa5, 0x4b8d1a6c, 0xa92d47a5, - 0x1e55c351, 0xd59e905d, 0xbdf943a7, 0xff9d41b4, 0xbef2d1f3, 0x90f2c79e, - 0x2d18de9f, 0x07189f88, 0xbca53fe1, 0x81ef0277, 0x0f3ad25d, 0xead67d22, - 0xdf700abb, 0x1175a4bb, 0x7e4394ac, 0xb8afdf1d, 0xce01a2be, 0x751befc3, - 0xa7de330e, 0x8814adf5, 0x00b0976e, 0xb06d27bd, 0xa1dac13e, 0x7722bf70, - 0xe4f59cc3, 0x98283d0f, 0x13286f51, 0x83de221d, 0x8fc61c6f, 0x83e6517e, - 0x1f2fac13, 0x2246caf1, 0x9eca7585, 0x99f6823f, 0xf996b7ec, 0x3d948e30, - 0xc4bf204e, 0x4371809d, 0xc922a611, 0x37b03991, 0xad9a4184, 0xf920af6d, - 0xe66f563e, 0x58da62ef, 0xfc70bca0, 0xbe701333, 0x0bb27510, 0xfde87b93, - 0x9b6d39bd, 0xcc5ca22f, 0x3d1470cc, 0x193df805, 0xf27ffbc6, 0x16bfc175, - 0x3fcba9da, 0x0ad3f246, 0xd6fd81e4, 0xda3964d9, 0x5acff6a1, 0xc121ae51, - 0x7ea7cacc, 0x32f89413, 0xc3ed15d0, 0x9fa4a55d, 0x9f7ee558, 0xddb8942d, - 0x2e7ca0fc, 0xe2d6f98d, 0xd1befaf9, 0xf495f28c, 0xcaabfb1b, 0x5e283104, - 0xe61a3750, 0x4fada579, 0x5be9de75, 0xe901bf6c, 0x187db82c, 0x395e2abe, - 0x8a2d7b4d, 0xcc1d77ee, 0xfee8deb0, 0x3ea8d694, 0x8733a4b7, 0x53bbdd07, - 0xf6d99fcb, 0x777ba0a4, 0xeef74119, 0xddee82f2, 0x2df9efa9, 0xba094e74, - 0xe7bea777, 0x54cdb067, 0xe6930fd5, 0x9c88e0a9, 0x23f555bb, 0xe7d5cbed, - 0xbcff8eae, 0x77c74842, 0x2e7d7d06, 0xe0668798, 0xc198e28d, 0x0a2f247d, - 0x3e1a432a, 0x6984cc2e, 0x0ba1a173, 0x9139a4e9, 0xe386e7db, 0xa0badb0f, - 0x9788e31d, 0xfc6fe88c, 0x452fe089, 0x9f28c4fb, 0x18fd1953, 0xaf33ed53, - 0x52be7015, 0x5cf2dbd2, 0x7d61f3b3, 0x494af7f2, 0xdee01dfc, 0x463eb8d1, - 0xf9036c7c, 0xaf7e55e6, 0x476cac78, 0x5f3ced28, 0x0f353258, 0xcc7fcfbe, - 0xece28331, 0xf07efc1d, 0xa78f3d4e, 0xe7e55ef8, 0xfa3bf35b, 0xfe008e34, - 0xf5c7993e, 0xa59c6790, 0xeba91f14, 0xf9165d84, 0x1eaceda9, 0x75d465ef, - 0x7ee14776, 0xab3ce056, 0x60c9bf47, 0x89cfbcbe, 0xaf68e1fd, 0x743dacff, - 0x9e6d6d3c, 0x98e3f89e, 0x1eabd72c, 0x91bb72d6, 0xb9e16639, 0x575e4571, - 0xabe3e7ed, 0xe7e7a85a, 0x1d1a3160, 0x9c836e42, 0xc396ab3e, 0x707ef50e, - 0xca3d7f8b, 0xaadf900e, 0x4c174b7a, 0x12b7bb27, 0x31f236e4, 0x797573c8, - 0x17c91372, 0x7caae790, 0x3c80de77, 0xdf0ebfcf, 0x426a769d, 0x8170f38e, - 0xda78f348, 0xffe69535, 0xf4479819, 0x64333da7, 0xde7cf8de, 0xc65ebe6c, - 0xb7580fb5, 0x2ebf7ae0, 0xf2f6ebe0, 0x7dfaf230, 0x0a775d79, 0x4c2845bd, - 0xa270cedd, 0x634625db, 0x387b9e09, 0x1365f296, 0x7eaae1c6, 0xfd3dd02e, - 0x6e3eeb7f, 0xbf5ffd41, 0xfd05a8ff, 0xa3f6ee61, 0x594db016, 0x8b5a4ead, - 0x85d03c7a, 0xba9ef51d, 0x7fc22e8e, 0x6eb8fb65, 0x21d95fcc, 0xee3dfbd0, - 0xd3a71703, 0x135f5938, 0x0e770bc6, 0xf28fd783, 0x37befeb8, 0x307ee24f, - 0xfb89f417, 0xdf8301fd, 0x801d202f, 0x5ebc425c, 0x35e5f017, 0xb1a373b6, - 0xf51e9422, 0x1f7cf26f, 0xe867a8d9, 0xef85afaf, 0x52c71c71, 0x488de98e, - 0xb205fb47, 0x27edddb5, 0xfb604617, 0xfa863af5, 0x17df8285, 0xe21fbd29, - 0xd6a83ff8, 0x3580a7a1, 0xbe696b56, 0x52d7a83f, 0x74fbda3b, 0xc15e2f04, - 0xae1c55cf, 0x0929a8fe, 0x56a0fdda, 0x530c7ba0, 0x31f3fbef, 0xe0af1784, - 0x3d305afa, 0x4c1af42b, 0x3bf4c19f, 0xbe6b4e84, 0xc91e9d19, 0xe4d5ef93, - 0xe7dc02b1, 0x59a7dd61, 0xe11e7e91, 0xae2be3f7, 0x7fa1d61d, 0x6cc9bd33, - 0x31e0027f, 0x0b7aff5a, 0xbcc389ca, 0x8776b0bc, 0x748de5c0, 0x5261f237, - 0xbda19eb3, 0x971e7efb, 0x7ae3ef4b, 0xfad0e3c5, 0x31af8c05, 0xe51d37b1, - 0x4f1c9a52, 0x2ac7457a, 0x905c53f6, 0xaf319bcb, 0x96ef54d9, 0xbd71e537, - 0x40839143, 0xe4fdaee6, 0xc44f6d97, 0xcb2f147b, 0xe55341e7, 0xfa32b2f6, - 0xf485cfa7, 0x672f4caa, 0xf8143c64, 0x6cff4cb2, 0x1f68cfdb, 0x59c72d9f, - 0xd1743666, 0x833ccc79, 0x879453eb, 0xabdf52b3, 0x39ae7dc5, 0x3a7cedfd, - 0x25378d67, 0xc9fbe226, 0xd27877fc, 0x60d6dba7, 0x9c372fdc, 0xe0ec31d6, - 0x381e7453, 0x35bc6b2c, 0x49439c54, 0x7a2557dd, 0x6aeeb08f, 0x3c0aa53a, - 0x7d39d0f7, 0x1701d91f, 0x5c9f13a7, 0x2ddea9b5, 0x7bc654fc, 0x5d3ef28c, - 0x80f3f727, 0x8b8b169c, 0xf329eb06, 0x1c659e80, 0x2ed6586f, 0xab35af5a, - 0x75a92158, 0xcefe29ec, 0x0149ed66, 0xa458bddf, 0x304ce873, 0x608defdf, - 0xfc8b1f25, 0x3657241d, 0x748c4dc6, 0xd784fb2f, 0xd7af704c, 0xaf29f046, - 0x61ade944, 0x687c88ce, 0x4f11e167, 0xe1dbce16, 0xde275694, 0x8ef0bc57, - 0x336ba64e, 0xd32e2fbf, 0x2d4ee5da, 0xeb9c6233, 0xc2e3e800, 0x5cf7fe20, - 0xddfba44d, 0xa0fec3bf, 0xbf0d959f, 0xaf677921, 0xed1d38b9, 0x33dac2a2, - 0x1bbb084d, 0xf51d3cfe, 0xff610f89, 0xf41ebd20, 0x72809b7b, 0xd3bd24e4, - 0x8635795d, 0xd35979da, 0xcbf91d3f, 0xf740a6f7, 0xb8ec3e6f, 0xfdf2b7a8, - 0x7873dc89, 0xf2fd1c2f, 0xb9a3f2b3, 0xd42ce91c, 0x243afad0, 0xddeb3bd5, - 0x0a2bffa3, 0x20d8c3d7, 0x7e0a7afd, 0xc865a3df, 0xfb4a9bbf, 0xe421cca3, - 0xdff469ef, 0xb071f365, 0x15e5a1ec, 0x9e165f7a, 0xe990ac93, 0x3cbcb838, - 0xa13fc07f, 0xebefca73, 0xa1fe0108, 0x3fdfc62a, 0x2ba7bb05, 0xaab8f81c, - 0x67f92a73, 0x0dc23caa, 0xd1c333fd, 0xeb4dd7e1, 0x28cff718, 0x818dda30, - 0x1bb44d7e, 0x1f7faa99, 0x252b077f, 0x74f786f3, 0x14897ddc, 0x666bafcf, - 0x795aef14, 0xe7a53475, 0x2120df5f, 0xfbc318ff, 0x6b7ee95b, 0x8cec86b6, - 0xfeb53e95, 0xcb80a533, 0x7c052985, 0x60f95cde, 0x01b0e52f, 0xa2ec097b, - 0x5db9f37b, 0xa9887514, 0x7ce0a5ec, 0xf28c97b2, 0x13101d3d, 0xe04257ae, - 0x6941477d, 0xca977e0d, 0xd9ce885a, 0x72fefc3b, 0xe4d738f0, 0xf8553e73, - 0x35f2317a, 0xe7076fd2, 0xe776e0eb, 0x41ac9415, 0x4c38da3e, 0xe65cab7c, - 0x8c6d95fb, 0x16ddcbe6, 0x05f4f343, 0x0296736b, 0x78017e5d, 0x0bd23de0, - 0x3444674e, 0xe5c17f7c, 0x3df3c08c, 0x6ba81c8a, 0x36efa70b, 0xc58bce66, - 0x48cda373, 0xf9ded0f7, 0x9c46a98e, 0x38da7be7, 0x7dfd29ff, 0x1638b5d8, - 0xae8269f9, 0xf2876f5f, 0x5133cee4, 0x784df7a8, 0xf22c7e7d, 0xfe7870e1, - 0xcf1918fd, 0x1e12c486, 0x70bd8797, 0x004f6ca2, 0xba27ee7e, 0x87fa9de8, - 0x6fd1181a, 0x56ffabf7, 0xbe7c7c87, 0xfb8cc233, 0x230717e6, 0x0bcabde8, - 0x3de81a6f, 0x7df95a9a, 0x7d742fd5, 0x7cbf4873, 0x22f74b5d, 0x47fe6fdd, - 0xfba3f22b, 0x3b9d0355, 0xc373a87c, 0x6af7dc45, 0xc39c673b, 0x5f6b5677, - 0xc3f2dbfa, 0xd25486ca, 0x3ff8148b, 0xbe2746bc, 0xe45e7bf3, 0x8ea1e272, - 0xf77d217f, 0x0b976ba1, 0x17ca7cf0, 0x44c7ff07, 0xb7ee6b94, 0x79444f2e, - 0xe5c5fee6, 0x7eee5889, 0x4a13c22d, 0xc05eb95f, 0x7eca3efd, 0xa8aef699, - 0x90ad0ff2, 0x5d6d23e9, 0x3d07bd0b, 0x7b02e4e1, 0x130fbbe0, 0xac4e34b2, - 0x65b7e13f, 0x7c05f7b1, 0xa457aeb7, 0x93f8e338, 0x01d51165, 0x814f7974, - 0x7e2ff14e, 0x930ebf23, 0xf019c7df, 0x77f2f4e3, 0x8af6367f, 0x1aa37dfc, - 0x83a1ee81, 0x5ee432fe, 0x8affad1a, 0x88df7a58, 0xc73bce89, 0x8b38478c, - 0x3e6205de, 0x00ccd1e3, 0xaf71693d, 0x7400cba6, 0xe869d154, 0x57befd22, - 0xacb0433c, 0xf173dd3f, 0x2134c8d3, 0xe7267f84, 0xe39434d4, 0xf81a7ec1, - 0x8ade2245, 0x71e955be, 0xc1fe20a5, 0x15a59bfe, 0x287f9077, 0xd6937fd8, - 0x8f666a2b, 0xe9dff7c7, 0xf78c2f3a, 0x8bf22369, 0xfae287a2, 0xffc1081d, - 0x3970c66b, 0xbad5f0a6, 0x5dff1e5e, 0xcc6a5bd7, 0xe656b484, 0x9db003ab, - 0x75fda0fa, 0xa377f39d, 0xb5dd611f, 0x60631145, 0x3bbdd6be, 0xfc813d8f, - 0x66352e6f, 0xeed777e1, 0x1fcc2e30, 0xfee097a4, 0xf2e18ca6, 0x184f4072, - 0x97cbdf66, 0xed5bfaf1, 0xe463397f, 0x87ff6cf3, 0x87607fef, 0xedc31d8f, - 0x4fdc25f0, 0xe0f0edc2, 0xc791437d, 0x792ebb4a, 0x63ca879d, 0xc04877fe, - 0xec79265e, 0xbd51231a, 0xb1b9cee4, 0xbbbf4764, 0x0d325620, 0xb4433f6d, - 0x87f2626b, 0x71e8afb6, 0xa8e39f6e, 0x871ced11, 0x1749fb96, 0x99bef408, - 0x9db9f7a2, 0xeee3e902, 0xeb1f9d4a, 0x2ef57829, 0x85d57ee0, 0x4c3f9d0e, - 0x150fd418, 0xdca071fd, 0xa2b9502e, 0x637a2a4f, 0x71fb93af, 0xe5e78c17, - 0x16b986b7, 0xd87d7ce1, 0x13f94615, 0xc67cf126, 0x0093479c, 0x813df45e, - 0xfacbff11, 0xc1a742a4, 0xcea5e6fa, 0xd7be1b8c, 0x4fa64db3, 0x8352cf85, - 0xbfd943f8, 0xdd39f39a, 0x1dfee1d7, 0x7ff7fb8b, 0xe0f2f4aa, 0x7eff6176, - 0x466ff108, 0x1fbe121d, 0x19d15bff, 0x4aff3eca, 0x5efe0bd6, 0x23debf59, - 0x72af8825, 0x7db8764e, 0x6fd64eb5, 0xce6f2b86, 0xbcfc7aff, 0xdfdf1e47, - 0x8e779f8a, 0x9f43bff9, 0xf50bd01d, 0x4779c7a1, 0xc64fc941, 0x6b86bcc0, - 0x739e743d, 0x1ecdf7b8, 0xb055f595, 0x7c745573, 0x41af4534, 0xc35dc8bb, - 0xd1cd03fd, 0x7ec9afd2, 0xf7a5ae39, 0xef921e57, 0xd5783e73, 0xea2d694c, - 0xd92e90c9, 0xd9de927b, 0xc6a3525d, 0xb77d19bf, 0x34aafdf8, 0xb157eb8a, - 0x552bf232, 0xf19b4675, 0x7c737fbc, 0x2be431fb, 0xb4ad6edf, 0xc6feb03b, - 0x237d72d1, 0x44d5b7f7, 0x618fdfd3, 0x95407a41, 0x57df5827, 0x645305eb, - 0xfa70d13f, 0xc3ba2fc1, 0xd1e95cb8, 0x39d79f12, 0xd055dff9, 0xe0b97277, - 0xbf23086e, 0x886bda09, 0x820d67d7, 0x5f3ddf1f, 0x4cfbd729, 0x13ff25ec, - 0xcaa0d3c5, 0x2ca7ceb9, 0xd4dfb20e, 0xbb95a3f1, 0x33724b7e, 0x73148e38, - 0x0d0b8e40, 0xd2268dc4, 0x60959079, 0xbc9fe24f, 0x5dd24b72, 0x1f80ff38, - 0x71dc93f3, 0x9730fca8, 0xfb223e7a, 0x3cebc973, 0x7e2433fe, 0xc7933cd4, - 0x95ddf08f, 0xa5c87e10, 0xc51d8f23, 0xb374a3bf, 0xc75d51b8, 0x3247ba49, - 0xd208ff44, 0x518dae3b, 0x8a4719fb, 0xb23b8fdc, 0x7fa33053, 0x8f3ca46a, - 0x9c31b77f, 0x7fe9eaf4, 0x79458ea8, 0xf9d3aca0, 0xcf5e7cb9, 0x04a5707f, - 0x07f89bbf, 0xe3061cd1, 0xf507c5fa, 0xb0e249bf, 0xbbf09464, 0x63b408fa, - 0x7561ffce, 0x2febce04, 0x2fbfc520, 0x3169daf1, 0x2bd23fa4, 0x0fd82dcb, - 0xbfc80ba3, 0x45a5fb2c, 0x07230fd8, 0xdfc139fd, 0x6bbf976d, 0xfc853306, - 0xf8f3af98, 0x6b82737e, 0xa6cfc126, 0xa61efe33, 0xffcefc83, 0xfe8d7402, - 0x2c183ca2, 0x1a7f9fc6, 0xbc61d6ce, 0xf5de39a8, 0xb3d1f136, 0x08f9091a, - 0x9338a7be, 0xfb44bf6f, 0xc6194e23, 0xfcf40a73, 0x0cea465d, 0xbcb46bd6, - 0xc760098e, 0xb0093c62, 0xe6f18059, 0x53ae393c, 0x6c44ce10, 0x6b9d49ff, - 0xf997be13, 0x5f68b764, 0x8f604c4b, 0x83bf77c5, 0x83824be3, 0x3895c5c7, - 0x1f1f1293, 0x6024ce2e, 0xee9c053f, 0x8715b9f8, 0x25737180, 0xe7bec49e, - 0x635720a4, 0xf7ce87b1, 0x48c8533f, 0x718b7fae, 0x21f9259e, 0xc83548e2, - 0xd5cf2463, 0x394dc571, 0xfe9d10af, 0x3dc4f1b5, 0x1cb7d863, 0x13f3e2ff, - 0xe8f8f78c, 0xb7b2164b, 0x51effabe, 0x5e76cfb4, 0x42f0fda6, 0x8fbe41bf, - 0xecfdc7d0, 0x2ff23a9d, 0x2dbb005c, 0x3d9f603e, 0x3ddbcf9a, 0xe89539d4, - 0x596f40ff, 0x2f3fd604, 0x777c6fe7, 0x48d9fcc1, 0xbd22bd97, 0xe3e78b07, - 0xd03b0ed0, 0xbd404e2b, 0x975c5be5, 0xb1098fef, 0xd0f0c62e, 0xcbe44cef, - 0xc05f947c, 0x07ea63e9, 0xd772fedc, 0x598a38f3, 0x72ee0b96, 0x63c1c93d, - 0xf1411629, 0xc5435b9f, 0xa7ef5e59, 0x856aa37d, 0xbe1cf740, 0xa3a59c71, - 0x82b7de5b, 0xd3e5d3fc, 0xe70e6e49, 0x9b880eb7, 0x15b7caab, 0x23879c0c, - 0x815475ff, 0xe31dc699, 0xb3c12c29, 0xbff8ca87, 0x73b875c5, 0xfb3a086c, - 0x695fdb16, 0x9fdb6eff, 0xb6ddf792, 0x6e3be6bf, 0x77de6d7f, 0xf1dee71b, - 0xf57fe31d, 0xccff6e3b, 0xaf3f3c77, 0x73ffffe5, 0x70700300, 0x5cf83f9c, - 0xdfbc7040, 0x1f3efc70, 0x36106d96, 0x6a4177f7, 0x42b57a8c, 0x462d5100, - 0x0877a2ef, 0x71e24d66, 0x46658db0, 0xf0610eff, 0x5f32807c, 0x1db90b4b, - 0xe8bfce61, 0x4e79858b, 0xc596f475, 0x126c9fa2, 0x82fd877f, 0x132acefc, - 0x18cef4cd, 0xfbc04cd4, 0xa161cdf1, 0x7261aae3, 0x23edc37b, 0xdc9617cf, - 0xfe9e3631, 0xfbc8436c, 0xfec82f1d, 0x23077347, 0xa51324bf, 0xafd47984, - 0xd0fa8094, 0x3f3c2388, 0x76398baa, 0xda525e10, 0xa507b23c, 0x8b6fc434, - 0x998def1c, 0xfe869d99, 0x0bd018e8, 0x14f81e31, 0x8e2905c6, 0x4a7aa665, - 0xe58c1f7f, 0x31d16dfd, 0xe55bee81, 0xac4cf3f2, 0x9e2aa0f9, 0xebae8ef7, - 0xc50265e3, 0xfe2396f3, 0xe574d2bf, 0x89934cef, 0xff37e618, 0x8ce29980, - 0x48bd2627, 0x8956777f, 0xf331adef, 0x6ed1872a, 0x1cd63c06, 0xbbf4471c, - 0xf7a4d0e4, 0x7733e9f1, 0x750f68a6, 0x17f1514f, 0x1dfd969c, 0x8940bf8a, - 0xf65efd6b, 0xfe887c93, 0x221fba17, 0xab1dea51, 0x27f7b6f9, 0xfc10d8ef, - 0xfee045bf, 0xb8afdf21, 0xde9c687f, 0x6e78119e, 0xaf3cb372, 0xdc78bacb, - 0xecf7f142, 0xee33c793, 0x01976d11, 0x4d71d2f6, 0xcfb8f463, 0x094a6b8f, - 0xe1c0b4c7, 0xf07de0d7, 0x35fbd5c5, 0xa285faca, 0xb2b1d6a3, 0x9fa7a31f, - 0x12ff7ae2, 0x60ffe714, 0x30bf3f2c, 0xf1e390af, 0x0824d801, 0x1b12c9af, - 0x711c7d51, 0x2a1b598b, 0x7605549e, 0xacb9e231, 0xccade399, 0x34975577, - 0x7339fb15, 0xd309bfb4, 0xa9b49aa2, 0xbdaf6fe4, 0x9bfa84d8, 0x63e5dafb, - 0x4cbf93b7, 0x713da12f, 0xefda9f4f, 0xa5a30ab6, 0xfd2784f1, 0x0cdf5a9d, - 0x71e3ec91, 0x9fa24433, 0xb230aa98, 0x4c74635f, 0x2e78426b, 0xca8a8bd7, - 0xcc22a6e3, 0x3e934416, 0x4523d458, 0xe83f97df, 0x51998b07, 0x74f38f1f, - 0xe2aaf8b3, 0xcc35bb4f, 0xe7ae1af1, 0x5d5f1b5f, 0x74bbcef9, 0x971954ae, - 0x9c4a2f32, 0xaaf8b874, 0x5dc1ce72, 0x2e75457e, 0x4ff62dc3, 0xb8e3ff47, - 0xf2f46783, 0xfe334b39, 0xfe25611d, 0x8bf5ee3a, 0xe2557714, 0x45cf6eac, - 0x3be1abd2, 0x0e3f7e3d, 0x06213f96, 0xf1e217df, 0x9ef157d7, 0xffef1e94, - 0xd4bee999, 0xc5fdf21b, 0xe63f184e, 0xa1cde9bf, 0xa76bcbb4, 0x98b790f4, - 0x45e77752, 0x387ed78a, 0x53ef1d56, 0xb49779e2, 0xd56333ce, 0x0e0923e7, - 0xc369f78e, 0xddc6bfb9, 0x97bfa3a3, 0x48c77ee1, 0x73a4bbf2, 0xfaebdd19, - 0x246ba4f2, 0xf1875de2, 0x38ba00b6, 0xe187b0ef, 0x9de7613b, 0xb38c30f6, - 0xa73eeb8d, 0x752ff3c7, 0xfd1eaf62, 0x12718061, 0x1f744d1e, 0xf7cfc8b8, - 0xdfd09676, 0x5c69bae3, 0x136fe3ac, 0xe59ffb17, 0x00210141, 0x00002101, - 0x00088b1f, 0x00000000, 0x17b5ff00, 0x67534c5d, 0xb7b77cf4, 0x0bdf96e5, - 0x72223f2a, 0xa29862c1, 0xa740c2dc, 0xac741631, 0x4a8a5c13, 0x66b50102, - 0x2d09922e, 0xcbc2ccd9, 0x01893ad2, 0xb8b2c3dd, 0x26a9f364, 0x87b6e883, - 0x6ead93fa, 0x840b0b55, 0xc3e22e25, 0x52c9719c, 0xba33330d, 0xd8dc6281, - 0xdf39d85c, 0xd8bdb5bd, 0xa4da2cbd, 0xdf3f3d39, 0xfff9df39, 0x0730000a, - 0xb956e7da, 0xf84ce706, 0xffc6cfa5, 0x4fa43d0f, 0xbddde38c, 0x1726eb4b, - 0x3ebbf1c4, 0x036935c9, 0xce9c5df8, 0xf6002b94, 0x1c5ace87, 0xaccf1f04, - 0xedfc2176, 0x4ab5dfc2, 0xd2f7803a, 0xee202d4c, 0x96a666fd, 0xd2afdef8, - 0x4fe9027a, 0x8ed77bdb, 0x70045e97, 0x106b4196, 0xc12e55f9, 0xb8e08271, - 0x4546fac3, 0x25c06e5c, 0x80fce938, 0xe89b34ad, 0xd9a55cc7, 0xf5f4137b, - 0x00674539, 0xdaaf39e9, 0x09f489ac, 0x06a019bb, 0xc15c0ce9, 0x556bf624, - 0x7fdfdb81, 0x4a4f2ad2, 0xdbf11c7a, 0xe036cc1d, 0x3c8150de, 0xf7c71e59, - 0xfc028fd3, 0xd422666e, 0xb9e97402, 0xd77264b8, 0x3bafa8aa, 0x52816a3f, - 0x5c5b4ca2, 0xdf5e30ab, 0x12acfd4b, 0xbefcf860, 0x170568e2, 0xa0172095, - 0xe0373f4d, 0xb19c5bdc, 0x3d7fc010, 0x4698ca05, 0x4adf9113, 0x2a8e143f, - 0xa769da22, 0xb6e5785f, 0x4c27f7fc, 0xcdba11ab, 0xbdc268fe, 0xc3829dda, - 0x2eedc99a, 0x7920ce6d, 0x212fce31, 0xb74bd3a5, 0x51cc22ad, 0xf413e428, - 0x025ac217, 0x36ada8d2, 0x0406ef6e, 0x7ca1b07e, 0xa488539b, 0x70d69da0, - 0x6f50044a, 0xdf045395, 0xcd7b088b, 0x7c461281, 0x2be726f1, 0xbf11366f, - 0x042aae4f, 0xcbe7e3f4, 0x09417916, 0x3464dfbf, 0xf3aa8e21, 0x3c52fed3, - 0x953176af, 0x34ef6adc, 0x4193f1f2, 0xe3d6ee7e, 0xfc3433b2, 0x5ff72172, - 0xcb9e0136, 0x8e38031d, 0x18f67776, 0x756eedcf, 0x3f7461de, 0x337fa0f8, - 0x904d81ca, 0x6bde8907, 0x3b3aa394, 0x001ff18d, 0x43d62670, 0x0d41d537, - 0xe7e1c641, 0x45d513e8, 0x582a0615, 0xbf373f11, 0xf974467e, 0xf062faf9, - 0x5117f10c, 0xd80d567d, 0x024dbf28, 0xf5e10194, 0x9f412d92, 0x9eb9155f, - 0xfc01650f, 0xde17d728, 0x7e30c83e, 0x915f8f7d, 0x4a6e505a, 0xd2ca97ae, - 0x32f7b8e3, 0x401653d6, 0x036cf0f5, 0x9858fbc5, 0x794d1581, 0x28bef1f3, - 0x6eb17d57, 0xbc4ead9c, 0x31dfe6a7, 0x3a44f9cc, 0x0d9a81d5, 0x61205f9a, - 0x5817fcbc, 0x55ed1060, 0x491c3d35, 0xb2b9f8a3, 0xec8532d5, 0x23a50ed8, - 0x6b126dee, 0x3c2ee118, 0x160ef840, 0xf6e7f090, 0x005b9d2b, 0xd8b754ed, - 0x5bdc52af, 0x15aacc3a, 0x40dade88, 0x50596bf4, 0xff122937, 0xc4a97bc4, - 0x55aa672f, 0x9eb3be21, 0x445f8df8, 0xade7aa44, 0x7865a514, 0x8d28cbb7, - 0xeac1b37d, 0x551f500e, 0xf411a337, 0x3587476f, 0x84b5fe40, 0xce90cd9b, - 0xbea041eb, 0xedcf5b7b, 0x328f45b7, 0x099f48a3, 0x5f916757, 0x16d3cc0b, - 0xea356115, 0x7841c82e, 0xb005bee1, 0xb4e2bc1f, 0x73b94645, 0x05ac4c3e, - 0xc49f4be0, 0x8327c861, 0xd7c03963, 0xc30e7cbe, 0x2fd3853e, 0x8c39cafa, - 0x470e54f8, 0xa8356b7c, 0x959e3cca, 0xdd02fbe1, 0x7059a727, 0x7e6f9b25, - 0xf9623ebd, 0x29ef0baa, 0xba3e7ba6, 0x93962eea, 0x5a20c7c8, 0x6ad6142c, - 0x6730c9fd, 0x06c3e75e, 0xe881e3b2, 0x60a73a61, 0x460d61be, 0xef308421, - 0xaa6febbf, 0xd96f9b52, 0xf193b802, 0x04faf467, 0x3cd02287, 0xfad24b7a, - 0x5fc5787f, 0x48529e3c, 0xf31eb2b9, 0x413719e6, 0xd48fd20a, 0xbe7f736b, - 0x4f18eb9e, 0xc0ddb8c0, 0xcf9c1278, 0xcbf8b56f, 0x74ad1f28, 0xa7e7248f, - 0x0ac4faf4, 0xb432bb30, 0x4fbc329c, 0x600e6c47, 0x8f30b220, 0x4916211d, - 0x19df3ec5, 0x244774de, 0x96e0c3d8, 0xd73c7e71, 0x46e6d87d, 0xb6f389a5, - 0xf9268d33, 0xd54a5c13, 0x34592ce2, 0xf6d56fd8, 0x8b5d935a, 0xb56e0c73, - 0x9471756b, 0xfbeb059a, 0x381679e8, 0xa9e7fd88, 0x734ebb18, 0xd001cf2c, - 0x93c7c38b, 0xd1311e9f, 0xef990f3c, 0xd8e3993d, 0x0c8a791f, 0x3794391d, - 0x41f6260c, 0x24077e81, 0x63946dc0, 0x6e611c91, 0x192dca25, 0x9f7d259f, - 0x2f6e15d8, 0x01905777, 0xfe0450ba, 0x465f3483, 0x1a77502d, 0x639d77ed, - 0x3bfa9070, 0xf70502e0, 0x1bf1e8fd, 0xdd214f87, 0xb4c98e73, 0x5783ba8e, - 0x16ef9ef9, 0x78ff7827, 0xbc2d77c2, 0x3537831e, 0x0239887a, 0x403af249, - 0x6eed1dfb, 0x6e687f46, 0x05301f74, 0xc36ed052, 0xbdafad39, 0x41404b0e, - 0x1de8ac7c, 0xe79df091, 0x1cd1e419, 0xa5162653, 0x1980ff11, 0xafdc2502, - 0xfd84baa6, 0xfc855f84, 0xd8cfed8e, 0xf4c0f1fe, 0x6bd52158, 0x0a235327, - 0x8cb73fdf, 0x922f05fb, 0xed2fdf1b, 0xcd3361a1, 0x0643dc1b, 0x868eddb9, - 0x713f343b, 0x4be918cf, 0xf9e7df0e, 0x53af2880, 0x7e062fdc, 0xe1633d8d, - 0x58092c6d, 0x38731509, 0xca5536cf, 0x6eaddf3c, 0x1f18dcc6, 0x91757049, - 0xc991709f, 0xc7e76f34, 0xf5aed1ab, 0x419fa341, 0xc877e62f, 0xd0c7d5a2, - 0xa3f0163a, 0x94a2237c, 0x7b8ba1f7, 0x1cfd0cfc, 0x40aa62aa, 0x8c2120f1, - 0x3e3d16c7, 0x6e1f802f, 0x70a9fc4b, 0xe01aae6c, 0x2b61ac35, 0x5ea353d6, - 0x6e01000f, 0xd4e3f9a7, 0x8e23bd08, 0x2af9839a, 0xf9f8977f, 0xe055677d, - 0xe814d4fc, 0x6bafd649, 0x6ab375ec, 0xf33dc90d, 0x7b2ed3f7, 0x47d3f792, - 0x3b2276f8, 0x244ced7b, 0x2bbe30bf, 0x15efbfa9, 0x411ccb5d, 0xb5c981f4, - 0x5975ce8f, 0xbea9ab22, 0x1cdc981f, 0xee91f18f, 0x8b82fda1, 0x91f516ef, - 0x87cf8c00, 0xcc67e523, 0xa2769794, 0x125beec7, 0xe9b8e397, 0x0aa1fc69, - 0xa1efdacf, 0xfda79aca, 0x17fa867e, 0x7f57cfab, 0x1dbcb26e, 0xa497f9a2, - 0xe7d27e7e, 0x9912c01f, 0x3893cbf7, 0x6487b683, 0xaa3c75e0, 0xa67ef5ef, - 0xc87b48fc, 0x06199dff, 0xed5cf895, 0x7ff4d0cf, 0xc18beba6, 0x9bf61d51, - 0xf6f9b935, 0xfc39f427, 0x8a71c98b, 0xa4f2bdee, 0xdf824a00, 0xa0a982ab, - 0x195df824, 0xf6e031ca, 0x7c8362c8, 0x81a978f5, 0xc2b1335f, 0xbd735fc0, - 0x14bf80ca, 0x5f90675d, 0x01bd6bff, 0xc5bd30df, 0xcff1bf20, 0xd63c066d, - 0xb95875bf, 0x4936e789, 0x0ae41baf, 0x157e8d3b, 0x2afd18f5, 0x15fa35ee, - 0x37e25bd3, 0xdfacb7fa, 0xf64e5fe8, 0xde855c83, 0x91fcffa1, 0x2060fb49, - 0x34f3c33c, 0x13029d35, 0xa8c44734, 0x66c21fb6, 0xf0a617be, 0x84a2e2ff, - 0xd7a72c3c, 0x0919da3f, 0xb9d2b32f, 0x2b369d0f, 0x512edbbd, 0xfe3e600d, - 0x2e76d705, 0x000ee017, 0x00000000 -}; - -static const u32 csem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0xe3e3ff00, 0x51f86066, 0xb8d3c10f, 0x72361818, - 0x0143f821, 0x684333b7, 0x0606163e, 0xc77e2001, 0x9ef0c0c8, 0x38330491, - 0x207eec10, 0x27880abb, 0x7dcf5071, 0xe52f1143, 0x5f5d9fa1, 0x153d76a0, - 0x837f7818, 0x031083b0, 0x03309b83, 0x8408b483, 0x55045fbf, 0xc10851de, - 0x99412e7e, 0xfa819f5d, 0xbbeb8d01, 0x00038031, 0x00000000 -}; - -static const u32 csem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c0b, 0x733ef7b5, 0x9993331e, - 0x420f264c, 0x084f0042, 0x21842a20, 0x38880840, 0x8d069009, 0x8808089a, - 0x420100ca, 0xa9113248, 0x676d5e97, 0x6ad11422, 0xa36d2d1b, 0x4101da97, - 0x180d45a3, 0x1d0340e8, 0x5abc414c, 0x5b4a0a8d, 0x3c3141b5, 0xe878490a, - 0xef5bd6c5, 0x33ef6b5e, 0x42667399, 0xfddfb6a2, 0x7f17dfbe, 0xecfb36fe, - 0x7b5ef673, 0x7b5affad, 0x231fb5ed, 0xd313c659, 0x057c8415, 0x7213d77f, - 0xf4842448, 0x0b3b4eeb, 0x108e3a68, 0xb0398e7f, 0xb4242055, 0x24edefef, - 0x4db39085, 0x267355b3, 0x98c7fb21, 0xf2d3d743, 0x80fc81b3, 0xdd4f9699, - 0xd121c479, 0x514ed57c, 0x3ed37282, 0xb1df7e2b, 0xde400851, 0xf1fd6e6b, - 0xb5df34b5, 0x699b2453, 0x376424d5, 0xda425491, 0xa9fd842d, 0x6a5f98f1, - 0x4daad965, 0xf682effb, 0x626683ca, 0x37b7dfa5, 0xafc86e89, 0x08042adc, - 0xf76aaf6d, 0x5a00ca83, 0xd080b2df, 0x7e695568, 0x1a8a63eb, 0xfb03c84f, - 0xb368ecfe, 0x67da7213, 0xfd82aa21, 0x491c6f28, 0x7b604548, 0x7dfa00e1, - 0x65c136c5, 0x6c57f5a2, 0xf401d73c, 0xc3c93455, 0x8adf5a44, 0x47511b06, - 0x22bfb6b0, 0x07cb5ed0, 0x794eded8, 0xfe57b428, 0x110a3de5, 0x1bb29fa1, - 0x74a2abbe, 0x76b5bf40, 0xb1eafb4f, 0x559f8d3d, 0xe8f6d1cf, 0x0a2fd57b, - 0xb562e82e, 0x8e807889, 0xb9d6dd8e, 0x7fa1db4f, 0xf8f0cab5, 0xdc2c7ec8, - 0x08a8fd05, 0xed0a526c, 0x6526df40, 0xfaeec8e9, 0x87fc3456, 0xacfabe9e, - 0x72889efe, 0x47da7a63, 0x3bbc3a59, 0xbb88415f, 0xa44bd691, 0xaa3a5280, - 0x4207f9fb, 0xa1e32122, 0x96a8917e, 0xe4a9faee, 0x23fe0711, 0x0f949ff4, - 0x81f1bdfe, 0x72dd99ad, 0x9904e95b, 0xbcedcb75, 0xea51cb93, 0x5fac8dca, - 0xf20c7f4b, 0xf9d4f4a0, 0xee3e989c, 0x8374c34b, 0xfdbe454f, 0xd30237dc, - 0x9f0b9f7a, 0xc3cbe93f, 0x8dcfa374, 0x22be53e9, 0x12be034c, 0x6fb36f7c, - 0x7c5ba62e, 0x8cfe7c1e, 0x06d31caf, 0x7f3e0d5f, 0xd31ab7de, 0x3e3f3e6d, - 0x1eb7d17f, 0x1d5f46d3, 0x5e403ba6, 0x05f26d34, 0xbe5dbdf0, 0xbe834c06, - 0xc7be7c46, 0x11f4c417, 0x64c747ce, 0x3e512f92, 0x49c4dc38, 0x8a924ec5, - 0xcd32f9dd, 0x7cb09527, 0x7cfe1dea, 0x3d53e685, 0x32f94f34, 0x6f9432a0, - 0x3501f9a6, 0xfdf07cac, 0xf342c0a4, 0x7cacfd83, 0x02ee23c8, 0xa90fcd2b, - 0x37c3e563, 0x68e20bfa, 0x9580787e, 0x542dbd5f, 0xabf9a360, 0x7679591b, - 0xa76a9933, 0xcb10ecf9, 0x9ee1bce7, 0x39f34f1a, 0xfb9f2cad, 0x83aa7f81, - 0xd8db73e6, 0x04ce93f7, 0x2d1ed544, 0xbab21d87, 0x6d595098, 0x4b70cff4, - 0x515e6913, 0xca2e21ef, 0x6eadff1f, 0x43f29d29, 0xc8796376, 0x9bcb1f3f, - 0xbf963714, 0xfcc32fe3, 0xe583d92e, 0x2c55fdc7, 0xfcb078af, 0x98bdff73, - 0x2c7eca0f, 0x58fad4b7, 0xf963f15e, 0x58f5da80, 0x80391eff, 0x1f6b23e5, - 0x4a3df2c3, 0x5f1fcb00, 0x1a7ba4fb, 0x3c11afcd, 0xd23c073f, 0x01649cb4, - 0x4ad31a9e, 0x09d69e28, 0xf7e02e64, 0x8a3a0007, 0x0ae975cb, 0x3f8ee1ea, - 0xfa0d3ee4, 0x90297f8b, 0xc3ccfa5f, 0xaffdf899, 0xd6991eb0, 0x4f5ef623, - 0xba799bce, 0x2cde727a, 0x8069ead7, 0xfb58d6f7, 0x378ecf56, 0x79e9e927, - 0x67ab42b3, 0xdf13d23b, 0xbce57eb7, 0xcf4f5935, 0x3d5a955b, 0xc49e907b, - 0x74d3d1be, 0xa69fcf44, 0xb4fe6123, 0xfafd3d20, 0xf7b8cf46, 0xf719fcf4, - 0x6f3f985e, 0x7de93d60, 0x3de9a7ab, 0xde9a7f3d, 0x08e7f30b, 0xdf506bf6, - 0x7dee35fa, 0xbdc67f3d, 0x47cfe61f, 0xdf664f48, 0xa1f5d9ea, 0x3ebb3f9e, - 0x04e7f30c, 0x6fac33d6, 0x48fdcafd, 0x8fdc9fcf, 0xc2e9fcc2, 0x5beaae7a, - 0xd23ebb3d, 0x47d767f3, 0x817cfe61, 0x5bea8cf5, 0xa2ff72bf, 0x5fee4fe7, - 0x0931fcc2, 0xbe98cf50, 0x54fc13d1, 0xa7e09fcf, 0xb0d8fe61, 0xa37df19e, - 0xcf5daf27, 0x30f6bc9f, 0x9004527f, 0xd5bec4fb, 0xf3d76c13, 0xe61ed827, - 0xe7ac20cf, 0x2bf5beba, 0x3f9e84ef, 0xfcc22779, 0xcafd8e19, 0xf40f7aa7, - 0x7c4f5a10, 0x39ecf5cf, 0x9ecfe7ab, 0x8cfe61b3, 0xd3a67ac6, 0xaf7ab27a, - 0x9e875267, 0xc23a933f, 0x7ac3c9fc, 0x9eadf466, 0xfe7a1d3d, 0xf308e9ec, - 0x73f91f27, 0x35fadf53, 0x9fcf53a9, 0x3f8c9d49, 0x4cd70f63, 0x3a72d075, - 0xfa44ba16, 0xdc67b5c9, 0x45e6816e, 0x4e8bcb27, 0x44bf0117, 0xd20dfcd4, - 0xf7e916ea, 0x39896df6, 0xbf48930f, 0xfa14a0a3, 0xb1bd4f15, 0x2123bf48, - 0xe7e74e2f, 0x7493ba24, 0x01a2e4f9, 0x95fbf7ba, 0xf795d10c, 0xaeb57b9f, - 0xa393dd3c, 0x4f9467cb, 0xa83fbdd2, 0xbf9740a6, 0xba0df562, 0xb7fd33f7, - 0xeb59f2ea, 0x3fbdd76f, 0xae916eac, 0x0afacafc, 0x8155f95d, 0x35fcba95, - 0x7baeff0d, 0x03e3547f, 0xc1d1f2ba, 0x63e57587, 0xf2eb8f42, 0xa93d0f63, - 0xeb7c7f7b, 0x84f95d66, 0xcaebcfa3, 0xd0edb627, 0xb93dafe5, 0xd9e7e0c7, - 0xf0d7ed9d, 0x27b808bc, 0x574fefcc, 0xc50bdfd0, 0x0657982b, 0xdf8fd1d8, - 0x3d54bf1f, 0xbcabe54e, 0xa14d58b2, 0x129905f2, 0x0fe7ae3a, 0x8db2bf28, - 0x9277bf3e, 0x7d274ae7, 0x19e2af7e, 0x9fe18ced, 0x24083c52, 0x04d5520d, - 0x41fcb1a9, 0x20b1e199, 0xc7e1cbe3, 0x535ef7e8, 0x9a44f0d7, 0xd7e62fef, - 0x129e5e03, 0x38d3884c, 0x7bc0d491, 0xf3826671, 0x73330782, 0xe047f69f, - 0xaa20fd75, 0xbd774287, 0x1a4f65eb, 0x6b9b19f8, 0x1f83f6df, 0xed106eb2, - 0x9e4200d7, 0xf90ede16, 0x07efd287, 0xd0f34d2d, 0xf50accfa, 0x57db23d3, - 0xb123fb68, 0xff6806fd, 0x37da1ec5, 0xb5d3c90f, 0xae5c196f, 0xd0a2df6b, - 0x1fd49df6, 0x6f23fda8, 0x12610a9f, 0x7f0b2f21, 0x83cdf6c4, 0x07fdb1cb, - 0x895f3a15, 0xdc2e3f6c, 0x77f4107e, 0x3e3fb41f, 0x4c87ff46, 0x707ff7d2, - 0x0affbe85, 0xb52bffeb, 0x71fb78c7, 0xe116ffd8, 0xe0ffeb18, 0x337fd60a, - 0xbedc37ab, 0x43ffcc23, 0x7b37ffd0, 0x64d67fea, 0xa8afff7d, 0xccdff7d4, - 0xf6a77fda, 0x8edf6f14, 0x9c2bbfed, 0xa2bffd62, 0xcc57db12, 0x47e0171e, - 0x09ab88c9, 0x40c9f6d0, 0x03fa986a, 0x903b685c, 0xa0a2488e, 0x6151e426, - 0x6f71d208, 0xe7dbc31c, 0x686f1471, 0x9cf8fc6f, 0xcb65a804, 0x8e2ef3a5, - 0xf2db15f5, 0x584bb015, 0x4b2be74e, 0x4165a938, 0x364df111, 0x28c30398, - 0xd1411dbd, 0x0db2f90f, 0xfec005d7, 0x4164cd79, 0x91277c09, 0xf4ff3c10, - 0x4736a367, 0x2e98cbf6, 0xdbdb93a9, 0x3c2df422, 0x23202a8f, 0xd37d286a, - 0xbbe30401, 0x79d31ff3, 0x8bf3a110, 0x833ce80f, 0x227e4850, 0xa23ef6b3, - 0xb7c825f3, 0x9412f9d1, 0xdf8b5213, 0xa70eead1, 0x384bfa51, 0x4c4b1ffd, - 0x43be3f5f, 0x7ea9f808, 0x31bdfe7e, 0xb05d4f38, 0xde9946da, 0x7f42c74d, - 0xfb4f2eb2, 0x753907e5, 0x360736ed, 0x155fc80b, 0xaa8a55f8, 0xf5e2c849, - 0xddd79419, 0xc54fbfef, 0x7f594e9e, 0xfdcb711b, 0xae77fbe9, 0x69390612, - 0xe6ddb3bb, 0xb84e361c, 0xd7a84c33, 0x4794c324, 0x634dadc8, 0x29035a64, - 0xb71fcb75, 0xb33bb445, 0x5d9f9f48, 0xc877cfa2, 0xe944d96e, 0xc81528ea, - 0x9cef5a26, 0xad72fab9, 0x8929bb1d, 0x57b799c9, 0x9be8ca92, 0x3c0e6903, - 0xe79ca276, 0x1ab7d93a, 0x32c5de3d, 0x3c82c29d, 0xc808fdfd, 0xef829fd5, - 0xfd64eedd, 0x573bd236, 0x684bb8b6, 0x142ee73f, 0x236f8003, 0x67da7ffd, - 0x69b29b73, 0x32a7feba, 0xc7f74531, 0x8f3cff48, 0x328d3fb1, 0xcbf3c38c, - 0x6e19cf8d, 0x3ffcb9da, 0xf4d07c06, 0xd283e004, 0xa3e39c7f, 0x7c32aedb, - 0x9b9ecd78, 0x4f5d0f01, 0xcae50488, 0xc71b72f1, 0x3d3a92cb, 0xc8f1082e, - 0x7365c720, 0x23879c85, 0xe3873070, 0x1ebd5960, 0xbf127737, 0x2e431e9c, - 0xfa6c36f3, 0xdd1a9a61, 0x6e390fbf, 0x1fb23fe6, 0x4fdd13f9, 0xb8bba726, - 0xd1acee9c, 0xe5c6df97, 0xeb97277a, 0x0ec7fadc, 0x6e41f350, 0xe8320357, - 0x4d3ef7bb, 0x793a6d9e, 0x8d3cb87a, 0xe5c5de74, 0x98f7d779, 0xb6f48d3c, - 0xd5b67971, 0x90c9905f, 0xf48d7a68, 0xd51d582d, 0xb9e4051f, 0x9e5b1fd0, - 0xf27e60de, 0x55e788f1, 0x8f92338d, 0x8ad9e847, 0x7e5d5286, 0xee9e6079, - 0x0bf565fd, 0xea4be575, 0x17caeb96, 0x975bbfaf, 0x9effe85f, 0xab05fdee, - 0x77e5756b, 0x2ba43cd6, 0x98fe5f9f, 0xf3cf3f2e, 0x39fdee84, 0xcae93773, - 0xa73c9767, 0xb4599f2b, 0x752f975d, 0x6fbdd6ef, 0x2dd577da, 0x8e37cf80, - 0x89fc0488, 0x30275ccf, 0x4b99f82e, 0xc73bc176, 0xbae22a7d, 0xd30237dd, - 0xe2173e93, 0x0f2fb4fe, 0x8b608ed3, 0x3a09c61d, 0x89252e2e, 0x6e9bccd4, - 0x103f5dae, 0xe38269c6, 0xacd316e9, 0x4264ff5a, 0x91526d7e, 0x0af5c5df, - 0x44258d09, 0xd386c180, 0x944625d1, 0x5e52f5b7, 0x727f0d4f, 0x5b717974, - 0xc7dee7ec, 0x8ce15e17, 0xd6e97711, 0x7e019253, 0xbbf7274f, 0x0295e58d, - 0x4e7c8929, 0xd7a803c8, 0x5bb8f8e7, 0xaffd30a9, 0x405e91dc, 0x0d0f901c, - 0x7b5cb9af, 0xfde4148d, 0x3a592701, 0x7f565e3d, 0x13bece8d, 0x03f6ca88, - 0x3dd58dbc, 0xad70d15f, 0xfb33bbee, 0x1abba445, 0x1844c56c, 0x375e4b16, - 0xb50e1d81, 0x0a399e0c, 0x61bf74e8, 0xd82a7182, 0x33c2fd0f, 0xe3e4a2be, - 0x04afc812, 0xb9be93d3, 0x3cfbb698, 0x95f71e98, 0xafb1fa63, 0xdf36d306, - 0xf23f4c6a, 0xc0fd31f9, 0x3fd31eb7, 0x3d30eaf9, 0xf4c7abea, 0xd3005f3d, - 0x4c06bec3, 0x6235f1df, 0x620beada, 0x6373e1da, 0x6f5de9aa, 0xc7c93bb8, - 0xbf80d3e1, 0x78eb3818, 0xfaed5560, 0x3b38ddc9, 0xd6afba6f, 0xcf9bb03f, - 0x8e66f5c5, 0x1e1d5487, 0x336080be, 0xf297ace2, 0xb0e3997a, 0x9763efa7, - 0x6bff377b, 0xc4de36f0, 0x8a6fccfc, 0x653c6eb7, 0xd594f018, 0x89fa9e1b, - 0x34f1bbe3, 0x7e64e4de, 0x8fd3c70f, 0xe6311fa0, 0x84e00515, 0xd7f08bf4, - 0xa71636dc, 0xd409ebe6, 0x6a716553, 0xfa1af6de, 0x75fa2b6e, 0x6e301181, - 0xb7f11f9c, 0x3f8710e1, 0x274cd47f, 0xcff73d7d, 0xf99e9388, 0xcdf9c6ee, - 0xbc1d00d2, 0x5b9746c6, 0xad5f18e3, 0xe8445226, 0xb0d0f6b8, 0x468b5c67, - 0x49225e62, 0x55c07df0, 0x5ea31f1a, 0x7f032bea, 0x9aebe37b, 0xa1b3cff8, - 0xff27f6be, 0x78e90b9e, 0xe397f313, 0xdbf4445a, 0x1769e849, 0x2e3c37f0, - 0x10695d99, 0xa61aeedf, 0x086fd138, 0xf3fcf5d8, 0x376e7cd3, 0x3ca21eff, - 0xb771c56a, 0x37f90d2e, 0xe9e1f3f4, 0x6f5fe07d, 0x7e37bdf6, 0xf80c0a2e, - 0x37b3f097, 0x5d9bd8fb, 0xc5f56e24, 0xe77fed20, 0x0f3951be, 0x870760ab, - 0x0f5a79b0, 0xa5d6d6fc, 0xff7cf48c, 0x33b8e26b, 0xeb71c355, 0xf9db4260, - 0xf9cbeb88, 0x40132ba6, 0x9c1eb42e, 0xe4ed741f, 0x722f7e7e, 0xafa99b3d, - 0x2fac6bcf, 0x68c22141, 0xa2bc6eda, 0x6a420490, 0x22a3cf44, 0x6d5c6fce, - 0xec1b887e, 0xa8d6b9b3, 0xfd3c6f30, 0x1a854866, 0xf385f1f5, 0xc0769e87, - 0x9a656c3c, 0x863c79c9, 0xaab4b51c, 0x8f69d331, 0xf504af9c, 0x4275f3f9, - 0xe7ce2351, 0xa35984d4, 0x3a719c60, 0xbb050f8f, 0x56a9869f, 0xc534cacf, - 0xddda9c79, 0x09590dd3, 0x6017fe6c, 0x225b64f6, 0x3ed39bda, 0xcfffbe0b, - 0x7aa7a7a6, 0x69087a34, 0xc0589f22, 0xacb2d39e, 0x51efdf9e, 0x0a8ba41f, - 0xb34937c4, 0x37cc39fc, 0xaffff4ad, 0x12bd4086, 0xbd7ab5e6, 0x3cdfa28d, - 0xd36f9e1a, 0x53bf47b5, 0xf857b5b5, 0x93bd67ae, 0x7b86bb48, 0xf957bf2a, - 0x068af0fa, 0xc7ef53ab, 0xdef2ea26, 0xe753ba60, 0xc03fc2d7, 0x2411af71, - 0x87255fc0, 0x5f64a75f, 0x0cda780f, 0xbf9843c1, 0x2abdec08, 0x51e29b4b, - 0x015a5d51, 0x34f28b9f, 0xfe73abfc, 0xa9d4ed4c, 0x7a0265d7, 0x54a4be46, - 0x20a9f2e5, 0x4c44cde2, 0xbf98bf34, 0x4569a8bd, 0xa75b8c31, 0x50fe6c4c, - 0x301c4a46, 0x75272e3f, 0x3d4f10b9, 0xa0454c4b, 0x3bc9679f, 0xfa11b18e, - 0xb0544e78, 0xf5ebc5d2, 0xdf9d3c7e, 0xeacbf2eb, 0xe4a5f9f5, 0x075854d6, - 0x2641ba5f, 0x86ec0101, 0xe898fcbe, 0x91977ac4, 0x6e30759a, 0xbbc79cff, - 0x94893916, 0xfaabe941, 0x17732fcd, 0x892e3a52, 0xd6d5fc6c, 0x31279771, - 0x05662bfa, 0xff7d3714, 0xb7b1a693, 0xbf440b51, 0x7583ac0f, 0x71297f6d, - 0xf2d1256d, 0x1bf4bafb, 0x81fcd5e9, 0x4e64f5a8, 0xe0834a47, 0x63b0c40e, - 0x3d30248a, 0x6aeef6e3, 0x838ba9c9, 0x223e42e4, 0xf18df20e, 0x78744294, - 0x067a2cda, 0x7e19e34b, 0xd4820f00, 0x4dbe78a5, 0xf55169fd, 0xfbf52d5f, - 0x903fd627, 0xabab9fd6, 0x4a9ff73f, 0xfa28d0ff, 0x5fd5620b, 0x76179bf5, - 0xa93da9f9, 0x0e67e978, 0x53c9c742, 0x8baa5d52, 0xeb72b5ca, 0x9a6e1d0f, - 0x0efc949e, 0x80a9ebc0, 0xde4b1458, 0x76f2c3ab, 0xbb8805db, 0xfd693fc1, - 0x11ff9fa7, 0xdf3e23c6, 0x9e313b2a, 0x990e60d6, 0x37563ea9, 0xd9262f2d, - 0xf2c63f98, 0x21139e0f, 0xafe3d41f, 0xa59fd9e2, 0x8a0afec2, 0x0a5f1e14, - 0xbd5b3fa1, 0x1c42d3e5, 0xea17489f, 0x683bf191, 0xda1252ff, 0x424a85bf, - 0x13a53974, 0xce5e04e3, 0x8fd36f17, 0xf80e89ce, 0xdfce1b57, 0x7397ef8d, - 0x14b974ff, 0xa36ed29f, 0x26409eff, 0xf8d43d80, 0x3fcc0241, 0x2fdcf35d, - 0x7a518fb2, 0xdd796cce, 0x49f04421, 0x8df3a3d3, 0x47b57f8b, 0x76ded9ed, - 0xf48b3d50, 0x4af1b483, 0xbabf720d, 0x7295a599, 0xd52d71c8, 0xb24dcafb, - 0x571f4fcb, 0x33f4f0be, 0xf31c424f, 0x30d7668f, 0x178aff5a, 0x8937bc0e, - 0x976c57e6, 0x37598a53, 0xb76a42ec, 0xfff4bc5c, 0x72dd39d5, 0x80f978a8, - 0xcf628ea2, 0x96ea4fef, 0xfbed8ac7, 0x9a2a3215, 0xf71b531f, 0x18f66d2b, - 0x563c6972, 0x9ac27e08, 0x814bfee7, 0x7da9e2f8, 0x199fe902, 0x0e9b9f83, - 0x7c001fa0, 0x39723942, 0x7866e585, 0x02e54bdf, 0x93935af6, 0x6e46fcb1, - 0x753ea04f, 0xc5f9e224, 0xf2fdb43d, 0xd05d993f, 0xef17f2ff, 0x4e3f4071, - 0xd70c3548, 0x2a61fcbf, 0xd972afd8, 0x94c4ea9f, 0xea7f2f3d, 0x65b788bb, - 0x15377f6f, 0x9dc449e3, 0xc7b1c26e, 0x5bfd0e9f, 0xf63671b2, 0x20f1296f, - 0x297fcaee, 0xfa680496, 0xb68a4499, 0x0e8bd0c7, 0x362717ae, 0xf68c4753, - 0x1fcc04ef, 0x23bf5ec1, 0x422abee2, 0xffa026ee, 0xa17de5df, 0x3fe6021e, - 0x1d3930b3, 0xaf5c4c90, 0x8919b7a8, 0xb60f2dd7, 0x0f4e7c82, 0x7587f772, - 0xfc912f16, 0x57c21f9c, 0xedf15eb4, 0x7c99fde9, 0xf2e52a88, 0x3f38e8ef, - 0xfbc39e15, 0x9adbb2ad, 0x7c8efbad, 0xfeddd995, 0xa53ede2a, 0xe7c60e3b, - 0xfdb1a913, 0xa6b201d5, 0x8e9c74f7, 0x7e8457c0, 0xf2df7d33, 0x4d6fd310, - 0x45a503df, 0x30f17e50, 0x0ef81fd3, 0x574a3fc6, 0xef963fa8, 0x3da0259f, - 0x58e6f3a0, 0xe645bd7a, 0xd72fad7a, 0x96e94270, 0xbc088484, 0xc849fd40, - 0x595f5c7f, 0x177e81ba, 0xd0bd2f61, 0x3eba239e, 0x71976f4d, 0xfa053ffd, - 0xfeb74d7f, 0xef4c8d93, 0xfc9ff67b, 0x07236e2c, 0xf412799e, 0x5fa7ea95, - 0x4b957d05, 0xdd7fdfa0, 0xeddef2d6, 0xdaff4f54, 0xdea9e9a8, 0xb4f51a7e, - 0x1278c77c, 0x6aff4f4b, 0x7a989177, 0xd4c79f4a, 0xe21b7b53, 0xfd94fff8, - 0x2897f8d4, 0xd9a7f9eb, 0x68f89ec3, 0x4a2f87b4, 0x68d3f22a, 0x61dfe90f, - 0x3f8d1b92, 0xde1a770d, 0x755d7e2a, 0x309dd805, 0x85dc352e, 0x2ee1a971, - 0xe3ab7e2a, 0xcffcb19f, 0x74a26b10, 0x4fd4b7cd, 0xa5847981, 0x2bbce08b, - 0xeb88967f, 0x048b96a6, 0xc880bef5, 0x7df06fb8, 0xf078cd53, 0xfdfca743, - 0x52f7b3b6, 0xbf13e77a, 0xebe5d6cc, 0xbfebf464, 0xc9abeafc, 0x73b73fb4, - 0xeca7cefe, 0x63ca89be, 0xe28424ae, 0x24f39d28, 0x82484fe2, 0x3e40acf8, - 0x7e63a08e, 0x7f0f3eb9, 0xebbb5253, 0xaffdede9, 0xa6f90f3b, 0xb63edbe9, - 0xa42ef576, 0x2979b143, 0x20a54f12, 0xef3fca57, 0x04302138, 0x549b52ed, - 0x7aaf3112, 0xb79ddb9c, 0x0f1ccda7, 0x9cfe4bfe, 0xe70c0951, 0xeb7e7183, - 0xbcebf6e5, 0xbb004d5f, 0x0b39be7e, 0x0fe7afe7, 0xb58f8e2d, 0xe385b26f, - 0x575f00ec, 0x750bb4e9, 0x277dc522, 0xc5ff42e9, 0xad92b76f, 0xbefdd631, - 0xe4f89b2f, 0xfe8dcb83, 0x736e5489, 0xd1e70e39, 0x2272134f, 0xa6eb36e4, - 0x5a239253, 0x71f7f00e, 0xdbeb3cc4, 0x0d7017f2, 0xb6b16dfc, 0x88c49615, - 0xf384fdd7, 0x5f2bca6f, 0x69d5fee0, 0xf012f9cd, 0xd45d9a71, 0xd41e39c5, - 0x192475f4, 0x794d7409, 0xe3a3f965, 0x87bd8e29, 0x57ec1744, 0x539f36f5, - 0xbbe6313c, 0xfd427e46, 0x901e47e0, 0x23afc89d, 0xe012c972, 0x56d991eb, - 0xef96eb02, 0x58aaae2a, 0xb3374e74, 0x523cc878, 0xe138d9f2, 0xe6fe3eff, - 0x150f89cf, 0xb79c7e50, 0xd1c0fdb3, 0x7f7a63f8, 0x6a0429de, 0xc8a1c005, - 0x004229f2, 0xc48564e2, 0x0164e8f3, 0x48fafdf5, 0x2c1f95fb, 0xd5f6017d, - 0x4e0b3754, 0x96af2d13, 0xb1c014da, 0x025db837, 0x9546fcff, 0x20de31b8, - 0x159a8cd5, 0x203ad711, 0x96afc84b, 0x277eddbf, 0x2cc2f7f0, 0xdcba0133, - 0x6039cf23, 0x3cd0bfdc, 0xa7a0f516, 0x47c1fd7e, 0xa0934ca6, 0x30f8821e, - 0xc530a1e2, 0x9ecfcba6, 0xa8ba064a, 0xdb98a6dc, 0x90c571ee, 0xe18532df, - 0xcdf6cfac, 0x7d99fff2, 0x1bed4c9b, 0x691cb5c3, 0x512b46df, 0x2c7fadf6, - 0x56b2b6fb, 0x58b80fed, 0x3fab37b9, 0x6be575c8, 0xb2c5fa4b, 0xd8faaf6f, - 0xbe35fdfc, 0x2073bb0f, 0x23a36fb5, 0x6a40dbec, 0x6dc462df, 0xffcd15d3, - 0x59bec5ec, 0xeff477fe, 0x316fb055, 0xd1523bfa, 0xe6a2b7db, 0x456fb45a, - 0x7edd4503, 0xcf852ca8, 0x6fb47ae7, 0x1b367f0b, 0x16cbb2f3, 0x57c03f03, - 0x71af6fb0, 0x80ed073b, 0x38a45b9d, 0xdabefdb1, 0xdabed2b9, 0x3e25ffb9, - 0xe56e766b, 0x239e7620, 0xcecc871a, 0x7664ccad, 0x665ee56e, 0x630e56e7, - 0xdf68ce76, 0x1beca20a, 0x047abefb, 0x8be71efd, 0x83b8bf99, 0x95cf1796, - 0x7efa165d, 0x5f9daab1, 0x691f19a8, 0x122916ef, 0xdeca39f2, 0x39e1ceb9, - 0xddecde90, 0x86ef605b, 0x0a1b1da2, 0xc7c4647a, 0xba6d430d, 0xbe4772fd, - 0x4bf5ff68, 0x107f2fa0, 0xbefd9e71, 0xf68bcd89, 0x163ed17d, 0xa7376ef4, - 0xc98551e7, 0x47e7c3b3, 0x24753a7b, 0x43aaf7d3, 0x544e3871, 0xbfac0937, - 0x15010bf7, 0x5dbf81c6, 0x9df2f9c2, 0x797cd97b, 0x83f1998e, 0xcec89bfc, - 0x2c16505d, 0xdcc3c08c, 0xd718154b, 0x0b112b9c, 0x0e0baff8, 0xfc0a70dd, - 0xd69705d6, 0x00bbbfa3, 0x89bec39e, 0x32eb6ded, 0x2e77bb68, 0xa1de7017, - 0x1798efed, 0x3f7a97b6, 0xec737e76, 0x38531a7d, 0x13ee533d, 0xa72fb002, - 0x2f107db7, 0x239bfd72, 0xc8bf21b6, 0xf8cc625b, 0x985ef6a4, 0x97c62e4f, - 0x6fcc55aa, 0xf289f30e, 0xf9a2154d, 0xbc5d2544, 0x2f9bb530, 0xfda4ee77, - 0xbfb9e94d, 0xf7a2df1a, 0x3e71b8e1, 0xd7bf80b3, 0x3e341f13, 0xf39ff547, - 0xb8a9fa9d, 0x8fc8c79f, 0x5ccecd46, 0x5e814643, 0x3cf26fbe, 0xf4701e3a, - 0x942f949f, 0x0de6dbce, 0xd9e79dd3, 0x9372f9c5, 0x54b4d8e7, 0x6a48f815, - 0x97b76700, 0x4a903f6f, 0x3b8b77fb, 0xe6420733, 0x78a6ffb3, 0x62d0fe20, - 0xa83b42ed, 0xcccd30e1, 0x8e57f870, 0x9c0323c3, 0x09bc70d3, 0xafd44e0a, - 0xf1cec190, 0xca5e647d, 0x6f5fd067, 0x144f8f90, 0x859fa09f, 0x720578da, - 0xa9bcffa1, 0x5bc5c999, 0x6e5ca023, 0x81075d26, 0x8229d5ef, 0x2aab442b, - 0x21ff6e0c, 0xd57ab7ec, 0x9e839f4a, 0xcdae0b97, 0xf4f61d8c, 0x963898d4, - 0x3718e162, 0x9b8c4609, 0x24bde00b, 0xc668b7d8, 0x1efceff6, 0x3f4647b3, - 0xf5b98a65, 0xe533d008, 0x09b264df, 0x7fe8061e, 0xfa303811, 0xf07a5131, - 0xa4fdf735, 0x2afdfb72, 0xfc0ec1c8, 0x1fc052ee, 0xf8d886f2, 0x257b95a3, - 0x4df21a75, 0x8e904393, 0x1c98e32f, 0xc8dfa960, 0x3cb45be7, 0x6fde1fe0, - 0x7ef86416, 0x324f9506, 0xfa6a9a2d, 0x7786a0e2, 0x2fcd1ab3, 0x47a42788, - 0x6fb00dd8, 0xd596eb91, 0x4f91b7c1, 0xeea2ac37, 0x27cd1a99, 0x07603e4d, - 0x28afc72f, 0x8fee09fd, 0x9bea7fb9, 0x599a4fea, 0xacfb3faf, 0x868faf5d, - 0x015eda38, 0x4e690aed, 0xf20fc5d4, 0xd65e6ccc, 0xce20f562, 0x5d935ebb, - 0xfb68d59b, 0x0b971573, 0xcf2257cc, 0x0e854def, 0xd3b1bac1, 0xfad13e4a, - 0x2ce1843d, 0xd5783c72, 0xf5f941ea, 0x5e04ff54, 0x98fe4f7f, 0xb40eff96, - 0x5516fb07, 0xf1c67b7d, 0xf5278b48, 0x6669afd6, 0x69be3f66, 0xbe76b4bf, - 0x9783baee, 0x4dfc62b4, 0x2cd87f5b, 0xc32e7e7a, 0xd048b8fc, 0xca5073ad, - 0x9ff2fd71, 0xe558ff50, 0xfc43f532, 0xfcf94428, 0x31a7b6ea, 0xf9f67d5e, - 0xfe833763, 0x48adf8ac, 0x3a9f542c, 0x1093c5b6, 0x80a207db, 0x24d1509f, - 0x91167ae2, 0x2333b942, 0xd6420cfc, 0x14bc7e30, 0x62a7768f, 0x4c503987, - 0xf5d8afbf, 0xddc43649, 0xf6601e3a, 0xc73cffcf, 0x1b2dbfa3, 0x242bfbd6, - 0x946f8eb6, 0x9f1cbdcf, 0xe6db7667, 0x1a16fd82, 0x8ad779d8, 0x39b239c6, - 0x6550ce22, 0x7b5c5996, 0x59f70db7, 0x70139ffb, 0x17d0329f, 0xdb52ce79, - 0x39e679ff, 0x822b9766, 0xcdce0072, 0xef6c3456, 0xc5783880, 0xaffa3351, - 0x0a7386de, 0x5f53a7f8, 0x23fd017a, 0xc5d4506f, 0x8fe2a341, 0x0cc8620d, - 0x2aa6b3f1, 0x7f3403b4, 0xb18df30c, 0xc5bdf0e3, 0xb4bc56c9, 0xb29f9777, - 0xcfcbc570, 0x6cdcf03a, 0xc60756eb, 0x1f2e1b21, 0x378a8fff, 0xd9743e36, - 0x8e69e378, 0xf5995f8f, 0x21a435eb, 0x9490e319, 0x1892dcbe, 0xee308b71, - 0x29ecf85f, 0xb33b0f58, 0x014fafe3, 0xb8ff95bd, 0xe07dd4f0, 0x3ab3ed8f, - 0x3ef6bc61, 0x13d7047f, 0x7376efb4, 0xee78ef3d, 0xe9875c59, 0x05d9a3f8, - 0x3dec75b5, 0x23d61831, 0x917fb63a, 0x55db710a, 0x3ce3a77b, 0xa9ced56d, - 0x798c49fd, 0x6e029680, 0x07587d03, 0xa5abca32, 0xd03065a9, 0x1bca9679, - 0xfc70b65c, 0xc58ab1b8, 0x371e55e3, 0xbd7b16de, 0xdc4e2a2d, 0xeb96f334, - 0x926efc60, 0x43e92a5d, 0x9530f8bc, 0xc83ee8e3, 0x9a43db6f, 0xbf298fbd, - 0x2a0ff0b3, 0xf20df7a7, 0xc969acfb, 0xb2849eaf, 0xe31ee4a6, 0xf03ea1c5, - 0xdbcf5b4d, 0x6c7f7662, 0xf1d9bd06, 0x83cf8c6b, 0x835ce8dc, 0xd9f0bc74, - 0x9cb38860, 0xc2eebb94, 0xcd7b33fd, 0x62aa2fb8, 0x3fa8fbef, 0xc6df3b1d, - 0xd7c232f5, 0xf8483ad5, 0xf083ad8f, 0x4b779c39, 0x73338b3c, 0x5a1c43fe, - 0x1e73e075, 0xd638666f, 0xc53dd0e2, 0x6c2dd39f, 0xceb6913f, 0xcfe5b558, - 0xf5c4310a, 0xd3903c85, 0x8baecbb1, 0x02707c6a, 0xae44261f, 0xf38ec4a7, - 0xb8ddd787, 0xe07e40bc, 0x4bd7857f, 0xc4207e68, 0xfbc203cf, 0xe83d8624, - 0x61d6c4d8, 0xfbd8e43a, 0x95f5b50f, 0x4f418b14, 0x575b7d03, 0xaffe8de9, - 0x26191fcb, 0xf9a3e39b, 0xd8cbe674, 0x45827c76, 0x61fb76f8, 0xf5a8852a, - 0xcfac0b7f, 0x60531d37, 0x638da1fe, 0xf0cf7f5a, 0xe799f279, 0xb1ef3c45, - 0xed05b1ae, 0x545ed1b8, 0x341f1613, 0xd3833bd2, 0xe3641d5b, 0xf11d99c4, - 0xe7ad3b01, 0x11bb2bcc, 0x8edbd5cf, 0xdf5a7e29, 0x959786c1, 0x52fd88b6, - 0x22044e30, 0xe2f33fe8, 0x7eb66cfe, 0xc6e5e6c4, 0x76f0e676, 0xdbb1cdbc, - 0xa73b6ef1, 0xbf85676b, 0x77e76151, 0x69dedf2e, 0xea073dc9, 0x132add3b, - 0xba7fbfd8, 0xc40a2c51, 0x45927f68, 0x4cf2e2d6, 0x8978e86f, 0xd9e31de7, - 0x493146f9, 0x557aff41, 0x84d1de7c, 0x15154814, 0x6a6b14e2, 0x35d2fed9, - 0x81a577df, 0xde24d7bc, 0x756deb86, 0x533afe06, 0xbf10f99c, 0x192b4e70, - 0xda357007, 0x49b7449b, 0xf8aaff47, 0x1e70fea2, 0xc7f72d7f, 0xf3c2e488, - 0xb0a3a297, 0x3a23fa08, 0x8c6b4e4d, 0x5ed905f5, 0x7c113c42, 0xf3fa9d91, - 0xb1cbe492, 0xeda3d42a, 0xb4b4a9a3, 0xa742c41e, 0x4b0ab71b, 0xfcddec79, - 0x77ec4e59, 0x4f3e36e7, 0x99d51370, 0xc183f6ca, 0x23b9d1b8, 0xc68c9b21, - 0xe29b890f, 0x0b9fc6d1, 0x07eff6db, 0x41d6b47b, 0xcf5489dc, 0x31555728, - 0x8e8dce0b, 0x805908b1, 0xfe6f73d3, 0x6d6bd696, 0xd0fe7116, 0x85f6d769, - 0xcf4113ba, 0xdc11e46c, 0xfe5007ff, 0x4e9bb92a, 0x0240bee3, 0xdf76a4af, - 0xb45d312b, 0xfce7bce3, 0x10071646, 0x98bfd5c9, 0x2470e2cc, 0xf1f3f400, - 0xf3a70564, 0x7ef0a43c, 0x3ae78299, 0x72f6bd96, 0x3930886e, 0xb92bf244, - 0xb4be7f48, 0x86c8eade, 0x77e27975, 0x9939c2b7, 0xbf5f5e32, 0x53b9fd12, - 0xd07e7eaa, 0x4f5c25d3, 0xf0b4baff, 0x32bfd810, 0xebb452cf, 0xcfeae7fd, - 0x59f71aa5, 0x2fb0bd21, 0x93ddea8c, 0xabbef442, 0xd6c7e6f2, 0x7a397cc1, - 0x011915ff, 0x482ac9fb, 0xe7ce0b9c, 0x97d068ac, 0x79bb03ef, 0xd893b015, - 0xebef172f, 0xc36dbf95, 0xdc79317f, 0x0aebf965, 0xe2dbfbc1, 0xecb2ae31, - 0x9f68c5b5, 0xfe7a69cc, 0x7f3d555a, 0x7c8c236d, 0xde39f3d4, 0x369be7a5, - 0xcf89ecff, 0xf3fa7909, 0x4b3e46be, 0x021bc784, 0xb5110e2c, 0x09b82dbf, - 0xd9f236e9, 0x0b76d7c8, 0x7ce2f75f, 0x96257fa5, 0x81b26654, 0x842974ee, - 0xa3d4617a, 0x80487b0c, 0x094a0f7f, 0xae57e2d4, 0x69efb478, 0x19423fbc, - 0x7a06cefb, 0x2ebd0224, 0xd13823d4, 0x46de7607, 0x5bb6703e, 0x909f5841, - 0x59e9aeaf, 0xfe94f79e, 0xfa22d8fe, 0xefc046d5, 0x762bd468, 0x0489376e, - 0x9e8264d6, 0x6e309cba, 0x6a2cfa37, 0x9ff70499, 0x286cb510, 0xc4e27bdc, - 0x1f7cc7f4, 0x8248e74a, 0x431b82fb, 0x3ec15317, 0xeba738fd, 0xde7bb066, - 0xec04a425, 0x6c71cde0, 0xa798b29e, 0xdc2ab77f, 0xed7b4eae, 0x59bef87a, - 0x785ce156, 0xcb56f367, 0x4507c830, 0x9bc47fbc, 0xb4157758, 0x332cd1df, - 0x812ccaba, 0xd8bf1061, 0x1dbb632b, 0x7cf19365, 0x6b6fd865, 0x3a40fb66, - 0x2c713f9b, 0x1de7b08e, 0x055e9fc1, 0x4c27acf1, 0x0c9ff7b1, 0xfdf89ab7, - 0xfc70df35, 0x7fda8c6d, 0xf6cadc37, 0x0878fdc7, 0xe97547ed, 0x330e3e79, - 0xcb96b87d, 0x6f4bf7f9, 0x6ceffec0, 0x47185416, 0x6e3bc50a, 0x39fb451c, - 0xe3c488f1, 0x392e2c30, 0x9bbfbf8e, 0x1f80d2b8, 0x0223af13, 0x3fc4f3e8, - 0x35b7dc12, 0xce2966ae, 0xa0eb7eab, 0x7586cf38, 0xb05b8a52, 0xe8ec6773, - 0x956f8fbf, 0x9c4cb874, 0x798169e6, 0x04a384e6, 0xa384eded, 0x123cf2fa, - 0x369db110, 0x4f6bf3fd, 0x5605f3ea, 0x49076f8e, 0xf86f7c05, 0x3aba4452, - 0x01eb88bb, 0xd9676f5a, 0xa6efbc00, 0xda9c22f3, 0x6297e9a5, 0x7e71ac51, - 0xf281e026, 0xe08509eb, 0x52c4f2f8, 0x5fefc63b, 0x05715a59, 0x7f9feb8c, - 0xac4573cf, 0x7611e073, 0xafed8129, 0xe2502772, 0x0ad7ae29, 0xe975df8c, - 0xebf63125, 0x70d6386b, 0x7d39e1ad, 0xd6279c69, 0xad0fc4be, 0x58290fcc, - 0x6050423a, 0x204fb65e, 0x078ed7c0, 0x373d973c, 0x640f27e3, 0xe0de3d00, - 0x2db3f405, 0x963b82cd, 0xeacab19f, 0x07bef360, 0x1fb0b5fc, 0x94aa5eef, - 0xae7b1f60, 0xabce0377, 0x2ba0876e, 0x5ba9677c, 0x9770e788, 0x8866c858, - 0xe9754b67, 0xee03c6b7, 0x4758cea7, 0xc4b27de9, 0x427e7284, 0xfefd2176, - 0xbe30422a, 0x03b5e3c0, 0x229b266f, 0xc0ff23cf, 0x95b0ff9a, 0xd5b0fbd6, - 0xf6497289, 0xdfa004b8, 0xe5ffdff5, 0xbceebd00, 0x0e394664, 0xed1ff3e0, - 0x4f9cadbb, 0x6bdce3a3, 0x3ca4ff01, 0xe5c3f505, 0xc965a871, 0xe5012f70, - 0x54758c7b, 0xf24d2fcd, 0xe946db50, 0xf09bb249, 0x76e22e7e, 0xdf6d4eab, - 0x45efe119, 0x090903e8, 0x69a5f604, 0x166854f6, 0xff14f142, 0x10f62ce3, - 0xca9233cc, 0x0929bf69, 0xf5616256, 0xc2674ab5, 0x9f71aae7, 0x2e65c53b, - 0xb8226e1c, 0xd2360daf, 0x9d9afd42, 0xdaf3ecd5, 0x66f68244, 0x605263ed, - 0xa367ad0d, 0xf88566d4, 0x2d5ba649, 0x4944ad80, 0xbde78a92, 0x7d339507, - 0x32fd65b4, 0x50afec31, 0x0ff31f65, 0xf5ac4171, 0xfcc38fba, 0xfc00bcf2, - 0xf5d43eca, 0x2e35b80a, 0x75cf6b2b, 0x79fe82c0, 0x3f706ed8, 0xbb8f90ac, - 0xb1353f13, 0xeba102fd, 0xb69dbf71, 0x1bb4668e, 0x15de0f54, 0x953eaf41, - 0x75cf9e08, 0xb572ffd3, 0xf611772d, 0xb9938f83, 0xf4169ac1, 0x2d91c4dd, - 0x5f6bc780, 0xa238bbc7, 0x3784c8ec, 0xde806b3c, 0x8c3f6a6f, 0xa2131878, - 0x33e5c8fa, 0x2a7b8552, 0x943ce19c, 0xfcf95ab7, 0x949bdb8e, 0xd1fd71d2, - 0x3338e5af, 0x6bd357f2, 0xace7bea3, 0xb198b576, 0xc13200d6, 0xba110ed8, - 0xc0b350e9, 0x8221bd1e, 0x4f99df7f, 0xbae942f1, 0xfc0ef417, 0x19818bf3, - 0xcd0d9b80, 0x7e82b1df, 0xa3f1e37c, 0xb11d7e99, 0xa227fabf, 0xf6cac3a7, - 0x0f803b87, 0xf22ffbd5, 0x728423f1, 0xea95cb0e, 0x443c6447, 0xe711bdc3, - 0x81ac5e9a, 0xf0b2330b, 0xf9011c7c, 0x0a234288, 0x3a364cd6, 0x7f9aaf81, - 0xcfec26bd, 0x9eb9e226, 0xded64e55, 0xcbf3591a, 0xefe8165d, 0xfe82f8aa, - 0xf5175b97, 0x97f3a25e, 0x5e30f388, 0x67e70ba9, 0x090a4bde, 0x7e0b7f24, - 0xb9eb6905, 0xc4a57e3a, 0x0757e0c5, 0xfff8d1e8, 0x6d93fb27, 0x6a83cfec, - 0x25ae7f77, 0x51b6df9e, 0x4f7b90bb, 0x05c33a7d, 0x89169c39, 0xd95ebe0b, - 0x51e77e93, 0x2dd706fd, 0x7a0d9f4a, 0xea99b13c, 0x8f5a29b1, 0xde09725d, - 0x6bdae75b, 0xd4677b43, 0x5fbc8beb, 0x7be31b5e, 0x1199e88d, 0x5371f307, - 0x5dc060d7, 0x8b924ab6, 0x41d9b129, 0xb6afad91, 0x91c6eb26, 0x8fddf1e8, - 0x2ff35276, 0xf8d2bf35, 0xe4afd85e, 0xcf1686e3, 0xff148214, 0xc7f7dfb4, - 0x5f01e679, 0xfcd938d7, 0x829a0e13, 0xab03fcbf, 0xcfa00ee7, 0x0710fb46, - 0x42231aeb, 0x125e2c99, 0x4f5be9d2, 0xe83365fa, 0xc248634f, 0xc74fcc71, - 0xcf4261b1, 0x4b8bf4f4, 0xab52f464, 0xc0ca7e02, 0xab1ac25c, 0x7bafb826, - 0x47bb3660, 0xbb0e6066, 0xe3dff1f7, 0x7dcc7ad8, 0xd0dc6c71, 0x4b581fd2, - 0xc97e81ee, 0x739bf112, 0x40dd39be, 0xef0fc42a, 0x0ddf738f, 0xb914b0fc, - 0x4e191fb1, 0xde2812e2, 0x0146a432, 0x552437f6, 0x1b8b02aa, 0x40ee3612, - 0x28cbeb4a, 0xdc61f356, 0x16b6a0ca, 0xcd1920e2, 0x6cf5cfb1, 0x5dbf9388, - 0xea29abbc, 0x3886ca3c, 0x541f6fe6, 0x8b937f68, 0x709479d9, 0x0f9286dc, - 0xbf88edfc, 0xf1db3b0d, 0xf50f5b19, 0x1b3e3227, 0x30205fe7, 0xf3c497e8, - 0x6488543f, 0x91f9c24d, 0x99df04df, 0xb23f382c, 0xd8235711, 0x58e297cf, - 0xe09d755c, 0x9ff90f5a, 0xb8165d48, 0xffc3476f, 0xeadf278f, 0x8e2be892, - 0xc367ceeb, 0xc3ea959c, 0x8eaf20f3, 0xaf87e7c9, 0x0d741ec5, 0x8b737866, - 0x9aeffdba, 0x4eb282dc, 0x8788566e, 0x78ebda44, 0x1df7e705, 0xe60b9c42, - 0x05cb1d43, 0xe160a746, 0x7d2403e7, 0x43db869c, 0x27781c6d, 0xb7e9132e, - 0xbc18ff11, 0xb2e2cc1f, 0xfd1a3d00, 0x86a473e1, 0x73c69e73, 0xe15969a0, - 0xee3a4db8, 0xe0512d93, 0xbe722f8e, 0x97fe86d9, 0xdff4c1d7, 0x60fe8788, - 0x6e732e3c, 0x15abf292, 0xae5fdbe4, 0xdb7b0449, 0x0ee3ceff, 0x0f91af90, - 0xcc7f829d, 0xfadf5841, 0x9f731c83, 0xa5a69688, 0x7f05280d, 0x0d3d2d34, - 0xbd79ed53, 0x07198a5d, 0xeef5cd3c, 0x9eb5e31b, 0xc3f30c58, 0xb39fd0d3, - 0x73de779e, 0x6177baa3, 0x8e3ebc7c, 0xd15ebbf1, 0x8026a8f8, 0x5de7759e, - 0x927eec09, 0x90ff7644, 0x8373c993, 0x492a52cf, 0xd1b9ef91, 0xdc47e91f, - 0x1181e633, 0xad9320d8, 0xbf166b88, 0x5065ced1, 0x97e4c743, 0xb9fae8c8, - 0xec294c6f, 0xcc6d919f, 0x30dc5d2e, 0x254bdb1d, 0x5387580f, 0x312d2ebe, - 0x73ae20b9, 0x1c9fd176, 0x517c1470, 0xe02e6b46, 0x91e888fd, 0xd431e36d, - 0x65b7f38d, 0x88409573, 0x9ea52a42, 0x9726241a, 0xb8eeb819, 0xff7314d0, - 0xe6c6ddb3, 0x4e71cddf, 0x06d2d34c, 0x8d8d9697, 0x39440fcc, 0x7aa47869, - 0xae365e98, 0xc5309cfb, 0x6fb40a47, 0x994ea7d4, 0x40dd6104, 0x9c2987b3, - 0xd63d9aff, 0xf40521f4, 0x4b01d60c, 0xe4d47da8, 0x9abf8439, 0xfc4af18a, - 0xfd5f9a13, 0x8e03e602, 0xded00aeb, 0x8f5ffd51, 0xd98232fa, 0xd3d82b6f, - 0xe7653888, 0xc107f7de, 0xdf87dffa, 0xeb0f10bf, 0xba917f40, 0x9e7ec1e2, - 0x78ddffbc, 0xe1f43738, 0x715e2cfd, 0x351e6197, 0xfaecc6c1, 0x6c92b6a3, - 0xdf02d7e8, 0x227ae77f, 0xb3564970, 0x01e58d75, 0x5c9e70d1, 0x554f2f7f, - 0x9ee1b263, 0x5bd63f1e, 0x32e7efc5, 0xcb92a1ca, 0x4db6f961, 0xed0a864a, - 0x7eb6dc7b, 0xa08f6e70, 0x14d93cbd, 0x8d11f38f, 0xc6db459e, 0xfa773028, - 0xaf99b34b, 0x6ccab77f, 0xc317705c, 0xf387967a, 0xc1e748cd, 0x6fac367d, - 0xfed8cfc9, 0xadb48594, 0x7abed4d5, 0x0b79d99a, 0x7c963f63, 0xa7f616a8, - 0x90f25bc2, 0x7862f380, 0x4e3a7eff, 0x883f5679, 0x7ec65eeb, 0x31cdef1a, - 0xe6d55f9e, 0xfcb8cb53, 0xf50788cb, 0x6b5cea2f, 0x369f5b33, 0x1fceffc6, - 0xff61b2ca, 0x91fe3c6d, 0x79c0264b, 0x86871de8, 0x3eee5c24, 0x1efc33e5, - 0x1a57b826, 0x823e93d2, 0x654db669, 0xbf3464f7, 0xaae02f7d, 0xef1db83a, - 0xf6bafb19, 0x94f9aaa6, 0x6b30f603, 0x91fa8776, 0xa43f01ab, 0x97f9d04c, - 0x282e9bd5, 0xf8cbbe6c, 0x7e7f0770, 0x1b37f407, 0x3fab59f6, 0x7ce54c9a, - 0x317ca547, 0xbf321ef2, 0xa6ee7f4d, 0xfad5fdaf, 0x2b5bf5a9, 0xd1fbe2af, - 0xf869df8c, 0x2c78e6cf, 0x6eba52db, 0x9ad16500, 0xf30627bd, 0x4e7868f3, - 0x1197c347, 0x4948cb3f, 0x8110ba61, 0xb147e693, 0xcb3c9a5f, 0xfef216ea, - 0xbaf8d3fb, 0x8fc41a5e, 0x118dc37a, 0xdb721d1f, 0x2367d060, 0xb87a3a3e, - 0x3627e45f, 0xa99427e6, 0x678842ee, 0x9d763751, 0x394fc233, 0xbc1dd529, - 0x0b6cf40f, 0xf8c479c3, 0xd7b99ccb, 0x57cf1c65, 0xe1fdabc6, 0xdb943d3e, - 0x6017d844, 0x5a7bc3f6, 0xb73eed3b, 0x7c04a86b, 0xb4f4c22f, 0x7435c4af, - 0xd2f97768, 0xc0382e27, 0x411cee8f, 0x11d38e30, 0x77f7a7af, 0xf9e91136, - 0xa543971d, 0x3f8ffad4, 0xd2da8d83, 0xda1dfb8a, 0xa071e4bf, 0xb145cd2f, - 0xfe27f9fa, 0x86f7e11d, 0x4cf5c5dd, 0xe02c979b, 0x99abbb72, 0xda2f67ad, - 0x30f28a58, 0x437ad7ee, 0xd0661670, 0x638d3caa, 0x51bf9014, 0xdf5c4b3e, - 0x51607dc1, 0xf08f2272, 0xdc1e017d, 0x2f5653a7, 0x28c3dc62, 0x93bb7cbf, - 0x6b57a39d, 0x42b71e70, 0x790ebd8a, 0xb5f4dda5, 0xc7ec63fa, 0xed0126c2, - 0x65fe91a4, 0x0dd76a5b, 0xd67fd020, 0x847ee8bf, 0xe25da206, 0x55fad4fd, - 0xff785c46, 0x50fad440, 0x7224f5db, 0xe6f2f53f, 0xbf2fb8c5, 0xb09ff69a, - 0x85c61238, 0x7a35fa34, 0x1428fd8d, 0x8816c8cf, 0x5c16aee3, 0xefa39f60, - 0xeeeb7327, 0xb0d85c3f, 0xafc8207f, 0x66fb625d, 0xce02fddb, 0x203f3b0b, - 0xbd607d6c, 0x3d69eb80, 0xed99afca, 0x8e59ea07, 0xe7dc0a35, 0x8851b657, - 0xf565c729, 0x11a1aef9, 0x60796a76, 0x8ea86b86, 0x1fdc46de, 0x54a1a2b2, - 0x9d807cf7, 0xfdb893c7, 0x48df4dee, 0x38cc624d, 0x9a5fa693, 0x97fa69be, - 0x3cd9576f, 0xcc1c0a47, 0xfebb04c8, 0xa84bce18, 0xcedabe5d, 0xd1e607d7, - 0xb89faa57, 0x581f5ba0, 0xb3e4c792, 0xe7c62c44, 0xca57d93d, 0x1e7d9d07, - 0x7fefd767, 0xd1fdb6f8, 0x85e9a1fa, 0x5ea33fd6, 0xc5aff918, 0x30728cd5, - 0x82e81ff2, 0x7b1bc1f9, 0x0407816d, 0xa74677d0, 0xe915af7f, 0x702b48ec, - 0x3fc839c1, 0xce9407c0, 0x31dbf4ea, 0x9496235f, 0xc75e71da, 0xfae34de7, - 0xe1c83f16, 0xab4ed67e, 0x473b2c7b, 0xb80c9254, 0x36db5298, 0xf8a4e2d3, - 0x2174647c, 0xe53a2bdc, 0x1099b6b1, 0xc8f25efa, 0x5fb84298, 0xb6d6ca7e, - 0xea2e2d77, 0x2d8ed5d7, 0x57e5fb84, 0xf680dd80, 0x10db9607, 0x89e53d57, - 0x9579f2e7, 0x5cce3fbd, 0xcbdd9f32, 0x292bcacc, 0x3c742d8f, 0xfc3c3cab, - 0x959fa0f7, 0x1045c5ad, 0x8884a9b7, 0xaacf1d37, 0x2d908edc, 0x93e78d9b, - 0x6cdb7be8, 0xf076559e, 0xc5ad2eeb, 0xb0f2adf1, 0x0e44fa84, 0x44a8b8b1, - 0xdfa56afb, 0x7ea38dad, 0xdaefe52f, 0xe60b8b24, 0x1fb9f4af, 0x936bb5e6, - 0xf11aaadc, 0x7c1f935c, 0x35ac7407, 0xfdfb75b1, 0x684f0daf, 0xbf78ccbb, - 0xc32647df, 0x67c5a43c, 0x9e58d4c1, 0x7cf138af, 0xc589be44, 0xbfe58c35, - 0x512cecd2, 0xd5170033, 0xaf161487, 0x4fe07fa6, 0x17a61156, 0xeb9d84d5, - 0xf04c3aaa, 0xa1f54b1c, 0x02c73c42, 0xd63ffcfb, 0x735ff0e1, 0x571ba58e, - 0x92054f8c, 0xc08a5930, 0x55bb34f5, 0x9bfb1797, 0x887f4046, 0x7382e718, - 0xa9866218, 0xbfed0766, 0x294d0578, 0x4ba7243f, 0xea5afb84, 0xe1114ea6, - 0x3235a9be, 0x62623fdf, 0xf6b5cce7, 0xb47f389a, 0x64bdb4f4, 0xecfdc807, - 0x36b9ad5b, 0xf3817eb6, 0x6bbfad61, 0x60113704, 0xe08075de, 0x149c80f9, - 0xb3fc02d2, 0xe01e7711, 0x127b3ded, 0x375b37e7, 0x90197fa6, 0x97a6ccba, - 0x57f78a55, 0xfa84591f, 0xdd304ae0, 0x6ff34993, 0x7cb197d9, 0x2642e986, - 0xf6dbf085, 0xc6bf9672, 0xcd086174, 0xce5f6bbf, 0x49c0b0f2, 0xf623b607, - 0x48ff428a, 0x7de38768, 0xc01afb9b, 0xf16264b7, 0x0515e917, 0x7db453d7, - 0x44e96b21, 0x1ef8f00b, 0xa7884dd8, 0xdafc16d4, 0x02eaf106, 0x3dfb0ab7, - 0x837bf336, 0xf1aa69be, 0x7099b455, 0xf02903fe, 0x4fce43ff, 0xc9a42e4d, - 0x8bec0d7d, 0x6bee8d25, 0xb4ed1d60, 0xf606d3dd, 0xad1bec66, 0x377ec053, - 0x5ca7f3bd, 0x0afc9fbc, 0x37d8cf56, 0xf6909ce8, 0x066fece7, 0x8f5c8a6d, - 0xffcf6d3e, 0x62a3be14, 0x5054ff40, 0xaa0ee49d, 0x44dc6b87, 0xbe60b255, - 0x362f9fac, 0xb69f6611, 0x82ce4ad9, 0x10c0c95c, 0xf6455b8e, 0x6bc84e92, - 0x26b49cf6, 0x9b5f69f5, 0x845abd92, 0x23293971, 0xd8117478, 0x7bb1dfff, - 0x1bb7043d, 0x14be73f7, 0xed8cd7be, 0xfec1b10f, 0x177fd010, 0xf2a7f349, - 0x2f8b17f8, 0x88dc9493, 0x07ef3079, 0xec1a7efd, 0x63609f37, 0xbf6807fb, - 0x63abb044, 0x58e98a88, 0x81656788, 0xdf983d28, 0xde8f1a43, 0xdc7feb47, - 0x9649e2ca, 0x0f8ba206, 0x38b3c766, 0x8b074ccb, 0x8dc9c60f, 0x10ff82b7, - 0xc1388e77, 0xa5fce87f, 0x22fee122, 0xae2379c9, 0x11341d8f, 0x3959f7a0, - 0x99f584e0, 0x7524abae, 0xafaee933, 0xab5bcb93, 0xbd4571f7, 0x7372e20a, - 0x7d3fcc1d, 0x7ee09f36, 0x4a53aee8, 0x934dd600, 0x91352c32, 0xf92b9ff1, - 0x0b390f77, 0xfe21e332, 0x408e37bc, 0xc5f613fb, 0xbf0e4099, 0x056396de, - 0x3c04bc3c, 0x32487ca2, 0xfa86ef3b, 0x7a502e92, 0xdb39f133, 0x63a92f27, - 0x277f2812, 0xe15760dd, 0xad67a9be, 0x7ee0378d, 0x784c17d0, 0x8a4beebf, - 0x2ff214ab, 0x609d579d, 0x6ccd9f7f, 0xbcfec38c, 0xbcfec260, 0xf575d714, - 0xc3f74a4a, 0x4a7c5823, 0xec0911b2, 0x502a64b2, 0x73cfa6ef, 0x493cd9e3, - 0xe3cbd3b3, 0x2e3cfe99, 0x200f3c10, 0x7f51f299, 0x9d3afdb4, 0xebf7045d, - 0x2ad59bf4, 0x4ae38e02, 0x4851b8b5, 0xe4cf7884, 0xdb7e8212, 0xe78cbb64, - 0x307f6072, 0xc29b1b9c, 0x0f94efed, 0x813d712a, 0xdc30e04a, 0xe762d97f, - 0x75f168f7, 0x4e39ebc5, 0x226d23ae, 0x5dd791f8, 0x07882e22, 0x8a497f5d, - 0xe74e47e9, 0x10233ef5, 0x97be8129, 0x0095517f, 0xef44f977, 0x2faf4de7, - 0xe0e3053c, 0x39e18b54, 0x8f4889f8, 0x4ff7cf1b, 0x4fee1a77, 0xd6f3e78e, - 0xe47064c1, 0x1d6d313e, 0xf238ba68, 0x8b53f409, 0x65f01714, 0x3efdddbb, - 0x5bfa7bac, 0x38b97265, 0xb63e33e2, 0xa5c46f9f, 0xa1ff5c38, 0x2e03b4f8, - 0xf3afaeae, 0xafbf695b, 0x07eaca1e, 0xb95d821c, 0xc92997f2, 0xf1cde760, - 0xa968decc, 0x97c03b86, 0xcbe18133, 0x3f5bba39, 0xe267c557, 0x01be9a7b, - 0x3d9ea0ee, 0xac7e6072, 0xd78a6575, 0xedd78055, 0xb3f38276, 0xe65ba51f, - 0xed699e82, 0xf86789ec, 0x6aeba637, 0x7587ee57, 0x6c67ff1d, 0xe03698bc, - 0xde391292, 0x3864e87f, 0x3375aaf3, 0xf3fda66f, 0xbf5c65da, 0x8be7e549, - 0x1e92f122, 0x770d1781, 0xef16761d, 0x7533f0d1, 0x3c22bbf7, 0x2119fa9f, - 0x9e124cce, 0x99f86887, 0x9c3867e2, 0x138d8872, 0xddc7e1bd, 0xe6069ce5, - 0x87370a31, 0x280a6e18, 0xb7f7f03e, 0x118fc07a, 0x8af54f37, 0x3cf12f9b, - 0x53bdaafc, 0x186ebb2f, 0x7df7e9f4, 0xb689d31a, 0x8f82fbd8, 0x56ef7e72, - 0x06cc6eea, 0x8993717b, 0x48937f9d, 0xe714adc6, 0x7bb4e3bb, 0x20b26be5, - 0xf6625dbf, 0x19b37b67, 0xbb76cfed, 0xd77183c7, 0xcb9e0b34, 0x0da79226, - 0x06bbf5f6, 0xdfc8d458, 0xc72ef8d1, 0x9a1ca361, 0xeffc0278, 0xf3fc98d7, - 0x1b81ca6e, 0x197a48ec, 0x93b8c393, 0xe21126ca, 0xfdfc8e42, 0xe04faf80, - 0xc3c02d4e, 0x25ef0571, 0xa0ae3eaa, 0xbecdfc5d, 0xbe210bb7, 0x9e1feda9, - 0xc2ede7b0, 0x3ef09182, 0xdc6bd9c3, 0x3c796aae, 0xd276014a, 0xc4fd2f70, - 0xfd2679f0, 0x8025f2bd, 0x72eeec9f, 0x73eb7de3, 0x1d1784e0, 0x736d6e77, - 0x60b3074d, 0x4e7d6fbc, 0x9b1f9d88, 0x1d3dd47d, 0x7dd4654c, 0xb70f1ceb, - 0x715dd691, 0xdffdf462, 0x163e7c74, 0xd7fbf10f, 0xc1c40a43, 0x6b9a951b, - 0x26a27cd8, 0xa68fec0b, 0xf947f877, 0x08e1f8d6, 0xc3ff7ddd, 0x88f3f8f8, - 0x38f7624b, 0x4eb829b5, 0xdf6128f8, 0xeb71f235, 0x39f7ae2b, 0x0f9c5eab, - 0xb96c70f6, 0x576dd71b, 0xfe7c4539, 0x64b21213, 0x125cbc81, 0xca3477ae, - 0x4213d4ea, 0x2a447bf7, 0xe5a76119, 0x8dc5fa7b, 0x70eff685, 0xf00e4c78, - 0x43aea42b, 0x4984ddf0, 0x6ec16339, 0x4dacc7db, 0xa34c7186, 0xb455d29b, - 0x874dded5, 0xc7275746, 0x858e1dc9, 0xf678c726, 0xe0a1d81d, 0x7c0b76b1, - 0x71a0e1af, 0xff2639ef, 0xfc803c08, 0x2c20f1bb, 0x07c6bc80, 0xfcb54f1b, - 0xa10f1f3f, 0x1e9f2081, 0x087100f1, 0x43c2b7c7, 0xc355f016, 0xaed7f503, - 0xfe68fe02, 0xf6c2a35a, 0x0d796a1d, 0x7cf64507, 0x10a5cf7c, 0xf6443fdc, - 0x6d39d959, 0x57ae224f, 0x6d64ecbc, 0x3ed87e74, 0x6498ba98, 0xebf983b2, - 0x8c89efda, 0x57e80909, 0xe106a18e, 0x06e3f40e, 0x71743da2, 0x4176917e, - 0x71377b80, 0xf806796f, 0xd064a197, 0xe2e6318b, 0x877fe010, 0xf8064a6d, - 0xc9b63987, 0x5daf8059, 0x0ebd5623, 0x01aed643, 0x516f2fe5, 0xcd27fdbb, - 0x6af0b5ee, 0x746ff6b5, 0xbd74fb30, 0x020f9d9b, 0x87491dbb, 0x2c41ff66, - 0x9a108740, 0x86cafa63, 0x0db9baf6, 0x41d039ec, 0x205fbaf9, 0xe41fe04d, - 0x5329dc9b, 0x17ebcfc1, 0xcece8092, 0x860c5fbd, 0xf3716538, 0xde8147ab, - 0xd43d6d62, 0x350f5fa5, 0xbf9ad1fa, 0x342bcda3, 0xcf9b487f, 0xe504df82, - 0xd3b9fcd9, 0x26add6cc, 0x6e782c87, 0xeaf3f1f9, 0xbfae6e55, 0x3147ed12, - 0xa42dc7ef, 0xeed2e915, 0xf399b91d, 0x9d10f8a3, 0x39436687, 0x3e513721, - 0x1defc4dc, 0xbfa5c9b9, 0xbc96e157, 0x688ef7d8, 0xbef6f4f5, 0xd6b87c71, - 0x6df46eb0, 0x763e43d3, 0xfa7fc8cf, 0xd2773cd8, 0xc12fd110, 0xce979a80, - 0x327069ee, 0x62521c3e, 0xb9fb578f, 0xb5324efe, 0xe5b9c365, 0x8efe7bfd, - 0x7b2be3e3, 0xf81efefe, 0x494f1389, 0x4eb5f604, 0x012e353a, 0xd2f3e7d7, - 0xab593d70, 0x9369fbd7, 0x88e7b08d, 0x5777ed1f, 0xdc7a520e, 0xc167d00a, - 0x1e67b7f4, 0x77d429ff, 0x2244b8f1, 0x2a144dcf, 0xc710a19e, 0xbfbfe42d, - 0xfe605073, 0x907e5692, 0xf3c5eeff, 0x21b0b71c, 0xc48fbb42, 0x9be7211c, - 0x9a193df8, 0x593a6f5c, 0x8eca4a74, 0xfdfc0f96, 0x5a0be233, 0xf399a15c, - 0x11fcb48f, 0xa77cb7cf, 0xfc096ee9, 0x89a4eff3, 0xeed11dc4, 0xe0ce950c, - 0x2f1ce223, 0x4a7e0c3b, 0xbd3f73cb, 0xde2b8e99, 0x4adc4437, 0xfede6de8, - 0x5be4367a, 0x8ff798c5, 0x9dfbf918, 0xfef1bbe6, 0x2a092191, 0xfb5bd3d2, - 0x38a6ae93, 0x27720d19, 0x65cbcfcc, 0xe51877f7, 0xff9ecafb, 0xd91b6e48, - 0x927bbf33, 0xbf0e51bf, 0xeb80533d, 0xc3c9bd4e, 0xb47ddb88, 0xbfda7e9f, - 0x9fa7ed10, 0xf8af63fa, 0xbdff989c, 0x1af30d2f, 0x9f7bbd5e, 0x4e7f064e, - 0x64f4e9c3, 0xbb899b86, 0xec4c9a7f, 0xf232f2dd, 0xf30773ed, 0xd710e66b, - 0x3fe99bec, 0x78ae0a77, 0xd27e17b4, 0x4ab3fb0a, 0x0e738d38, 0x41ffa217, - 0xe31079f8, 0x1c473638, 0x7bdee789, 0xa19bddfd, 0x5b9832f9, 0xbf0578e3, - 0x36b802c7, 0x6f45538e, 0xb2e049d4, 0x98ab4a15, 0xba7ee31d, 0xce519746, - 0xf6094847, 0x8d3a27a3, 0xabd23038, 0xefdae7f9, 0x4c7e50c0, 0xddf5a24f, - 0xff63e6aa, 0xce61c6a2, 0xdfc69e97, 0x9c95fa9e, 0x1cdee3c0, 0x4e4e17ff, - 0xdbd80b7b, 0xe519be93, 0xecd72c66, 0x90342147, 0xfc1fa983, 0xa9092191, - 0x97850fa8, 0xe3a6e214, 0x3fa8190c, 0xaf8a4eff, 0xe3ddbc40, 0xc27acf64, - 0x1325f55b, 0xe37724f1, 0x663e0e4e, 0x96eddc03, 0x1f106cea, 0xba5ecebd, - 0xda6f5406, 0xf0b305a7, 0x1336879e, 0xf4d99081, 0x102d73e6, 0x251ef047, - 0xa0a03e78, 0xc054ff79, 0x56a5efe9, 0x5e75479c, 0x08b1e424, 0xbcd8333f, - 0x587e06c6, 0x6f9d8530, 0x7448983b, 0x27f790fb, 0x8f06bc30, 0x1dd9bf9f, - 0x2f12fca3, 0x29dc499f, 0xc72e38d9, 0x70a3fc63, 0x3ffb09bd, 0x481d704d, - 0x9e65bf01, 0xce85f380, 0xa40e13bd, 0xee3b7a50, 0x333b444c, 0xdde0f83d, - 0xc6882a4e, 0xcf8b1eff, 0x780a16bb, 0xeaa140cf, 0x59617cc2, 0x98dfee26, - 0x99e48ff0, 0x433e50c5, 0x74cdf9c6, 0x788252b1, 0x2134d9d4, 0x7b8be607, - 0xf85ab684, 0x297f5c1d, 0xfd38876b, 0x7cff30c9, 0x0c7938a7, 0xaa9c76fe, - 0xefe187e5, 0x3cc31203, 0x0bced56d, 0x7cb4cdfb, 0xf7016cd5, 0x66774eef, - 0x7e047f10, 0x7953d70a, 0x6cb8a58e, 0xb8005fee, 0x3fa4599e, 0xc4bb3837, - 0xeb910246, 0xef138216, 0xf7c83b21, 0xfc097769, 0xe7ae7c5e, 0xcfbc7037, - 0xfbac9b99, 0x3f3094ae, 0x6453bbd3, 0xb3e471f7, 0xf4d6a1df, 0x87ae46eb, - 0xf1f9f037, 0x8e864f3c, 0xd288628e, 0x5b3f4088, 0x62e5be47, 0xa5cf0e1b, - 0xe78707e2, 0x1c6ef6d3, 0x8ad79861, 0x17116b95, 0x6f1d6c69, 0x1382ec36, - 0xdfea6ec1, 0x9f4f25bb, 0x97c7a18f, 0x3d9a13b5, 0xc457bd98, 0xf9d9c375, - 0x8902cf94, 0xaebfd3f2, 0x726098bd, 0xd078801d, 0x78dc97ad, 0xbd944e8f, - 0x1be8a0f8, 0x50df8bd9, 0x7aa3cc1d, 0x1f0264fd, 0x41910737, 0x8ba63760, - 0x380a7edb, 0xa6e3a4ea, 0xb48e0639, 0xef9b4771, 0x063d5217, 0x6c3390dc, - 0xa5fa659d, 0xa4efdc34, 0x76c3f7cd, 0xae25fa84, 0x6fd2fe18, 0xf774b212, - 0x4aed847a, 0xe7225f84, 0x64bf7b7e, 0x9547f53a, 0x206fa01c, 0x7b458ff1, - 0x42c97186, 0xf10518d8, 0x1873b4c1, 0x744af1e7, 0xf3e38afe, 0xb02f88d3, - 0xb752427f, 0x15fd187e, 0xd63cce2d, 0x7a53f9a9, 0x8de3849c, 0xa57dd8b3, - 0x810a4e1a, 0xb3ffa09f, 0xf4eb8c44, 0xfdad1b86, 0xa212f0de, 0x564c08f6, - 0xfae1788f, 0xf2f175f7, 0x197c6d17, 0x05f6864a, 0x343e1a27, 0x9bc718bc, - 0x83c434ff, 0xba6f1a7a, 0x0e6f197a, 0xaed1908c, 0x7cd7e6f7, 0xeaf3e4ea, - 0x37a62704, 0x7f1b355c, 0xd82c6897, 0xf937f011, 0x6b8e15b8, 0x1c9c33d5, - 0xc1245b68, 0xec1791fa, 0x1cb76647, 0xfff078b4, 0x81c4c600, 0x008000d5, - 0x00000000, 0x00088b1f, 0x00000000, 0x7cbdff00, 0xd5547c0b, 0x67b7efb9, - 0x332479ef, 0x49926649, 0x1d843c32, 0x09212108, 0x11bc210e, 0x11084937, - 0x88a80ca2, 0x1f01d68f, 0x4d092060, 0x6f53d5ad, 0x52812133, 0xbd583d6c, - 0xf4f47bd6, 0x41ed5837, 0x0108750d, 0x26702783, 0xd0f098a0, 0x7ac0f820, - 0x452968da, 0x5a18921b, 0xf5cf6a0f, 0xf6b7df7c, 0x8326664e, 0x73def7a5, - 0xd62e9f87, 0xf5af6b5e, 0x5ff9efad, 0x4a9b5adf, 0x500a9fc0, 0x982015b3, - 0xe1f95006, 0x06484a86, 0x01203be8, 0x96d40314, 0xfe1b41c9, 0xb1fdb4b5, - 0x0cdd45c7, 0x51df8956, 0xf5c02661, 0x950b7e20, 0x06e6c50e, 0xbc95e658, - 0xd6801672, 0xe1bfde2e, 0x62a82592, 0xf9af7afd, 0xe89b1ee3, 0x5fff35fb, - 0xb800c803, 0x197f7f51, 0x2ffb0ffd, 0x1860a4d3, 0x3b365d5f, 0x978dffba, - 0xa6913fca, 0x62d72c02, 0x3e4fc39e, 0x22f2a793, 0xac24becc, 0x8fb74457, - 0xcfb92673, 0xe32ff1d9, 0x32d7fc61, 0x65f3c5c0, 0xaff7516f, 0xc8ed77e9, - 0x523d48f2, 0xace80166, 0xdb1971b7, 0x7f016e5e, 0x4d2581c8, 0x0065c450, - 0x9d0a0152, 0x581998b8, 0x0d0164bf, 0x136308f9, 0x3ab9f7e0, 0xdf86131d, - 0x07e3883f, 0x8e30dc70, 0x3801c81f, 0xfae4ef54, 0xae1ef56b, 0x2f82935f, - 0x877fe3a4, 0xb8a8b0bf, 0xdfedc59e, 0xdf38fc51, 0x8f0a4be2, 0x93d69b3b, - 0x71830b4f, 0xf73f9eb4, 0x0de3fd16, 0xb6bfdc30, 0xbf8b33fd, 0xf9ebf2f0, - 0xa7e7f35b, 0xcd3f3ca8, 0xcf0c15ab, 0x180144bb, 0x9a5ceb83, 0x635fcd1b, - 0xc6f9589e, 0xfeb96fca, 0x56fcac7e, 0x90c7acc4, 0x32a2f40f, 0xffc38a8d, - 0xa6d0264b, 0x437e5e5f, 0xb3f8b1f2, 0xdb2305bd, 0x72c97e01, 0x974f1e1a, - 0xbe2b7417, 0x19974142, 0xb752baf5, 0x40efd40b, 0xb2b9ca0a, 0x4889c213, - 0x2be7f5d8, 0xf4a8513e, 0x9471f04a, 0x6c7c033e, 0x1e1e5bc8, 0xe425d17f, - 0xbcf0da6b, 0x7764148b, 0x0b1f3d11, 0xa8eb3881, 0xea1471a1, 0x6c39601f, - 0x155a61d9, 0x635c75c2, 0x547d3b81, 0xe0328a26, 0x937db894, 0xf6e3c4d3, - 0x8266c5ff, 0x3e5e01ab, 0x48025998, 0x3cead79f, 0x42011306, 0xbff7e066, - 0xdfb9524e, 0x240824e6, 0x74a0fce0, 0x945ec8db, 0xb45c8012, 0x25b4653b, - 0x364388d8, 0xd91f612b, 0x8157bf61, 0x2fdbb406, 0x050ef78d, 0xc914076e, - 0x4c738fe6, 0x7ef4598d, 0xf61e7bb8, 0xa8a4559b, 0xcb8bb0db, 0xda877eaa, - 0x9d580efb, 0xfeff5ef4, 0x699877ef, 0x1780bf9c, 0x0ed78429, 0xe7da8158, - 0xf241cc3b, 0xe3e48b1f, 0xfdeb09b2, 0xec560003, 0xb8557f3f, 0xd76e5014, - 0x13a37740, 0xc724b9cb, 0x8d7bf238, 0xfece9bd6, 0xe50a31c3, 0xd39740b4, - 0x956fdd02, 0x8fd9901e, 0x41c92694, 0x53f61ac8, 0x5a32ead7, 0x3a256c80, - 0x7ae1b416, 0x4bdafdb1, 0xb4bf5c4a, 0xe1771f48, 0x9321419f, 0x7ad1085c, - 0xf84da8bb, 0x14d012a3, 0x6d4b29c0, 0x97e4ed31, 0xce459e90, 0xc973e7e8, - 0xef5ea277, 0xf84bf18e, 0xf7bcd133, 0x8bbcc53b, 0xf726bfe4, 0xb65ffae0, - 0x43cdef68, 0x9a4e077a, 0x0e7c59e1, 0x6732b1e7, 0xd0da5f24, 0x973983ae, - 0x07fd8bb7, 0xe9153513, 0xc7f49979, 0x9ad1f541, 0xfdf2f53a, 0x940cf6a7, - 0xb9787760, 0x13028579, 0x7b4f1d58, 0x3df98632, 0xff3aaf82, 0x22d9f963, - 0xf91d9341, 0x5bddb0bc, 0x0465ae46, 0x8f913b1f, 0x80c95ef8, 0x295cf3c6, - 0x78fb0d1f, 0x46a25cf9, 0xb9f2fefa, 0xffcd1ad1, 0xfa6be92a, 0x3feffeb0, - 0xfe48983b, 0x2aa8f913, 0x2e0317a8, 0xd659f79b, 0xa1f7a15f, 0x6dc13951, - 0xf5d16f58, 0x81c4e5fc, 0xefc4f9a3, 0x67de4deb, 0xe3651a69, 0xe48515c4, - 0x9c96b737, 0x0d2477c5, 0x7ed107a4, 0x7709d524, 0xfb401960, 0xa40b7d21, - 0x1993eb02, 0x36f34042, 0x9534f06a, 0x29abe60b, 0x1c41efc4, 0xe341dbb3, - 0xe7a429a9, 0x338bd7f0, 0xf923857d, 0x0a8f52de, 0xd6b4f385, 0x1b2534db, - 0x93bd5f60, 0x1ef56deb, 0x57ad5f2e, 0x2c74dcb9, 0x8e20c1f9, 0x3459ab53, - 0x7df86d25, 0x8fb0aa57, 0x8867e805, 0x052005ae, 0x0b73a803, 0x5ef5d61e, - 0x249b8291, 0x27ae1392, 0x97289f82, 0x08dc9ec1, 0x4d2936fe, 0x35b26693, - 0xf28bbcb0, 0x063efc4d, 0x59f3e0ff, 0xdca3fb23, 0x4baaeaa3, 0xbae67e62, - 0x961724b4, 0x52f8743f, 0x6e916ca8, 0xb8017c39, 0x5bf512ee, 0xfe380be5, - 0x7842f0f4, 0x74c3e310, 0x15f10c14, 0xfd13b77f, 0x402c3a33, 0xca80c1f2, - 0xd3a45976, 0x492e7da3, 0x323e70e7, 0xe0c7af9d, 0x30cad67b, 0xe83ed1e9, - 0x17be2349, 0xb4767cdb, 0xc843a428, 0xf66e9355, 0x9cde3848, 0x26578b74, - 0xa6fa26d2, 0x75fe446f, 0xd884e3a4, 0x6323a3bf, 0xa6f68aac, 0x4fbc6f29, - 0x1cd9ad76, 0xcc2b8161, 0x71113dbd, 0x719e133c, 0x9f22bc52, 0xbdf235f6, - 0x01c977f3, 0x73886bf6, 0x9e758fc8, 0x7186f64a, 0xd92e6b9e, 0x7fd256bc, - 0xf5ed117a, 0x54f26260, 0x5dd0cff2, 0xd6b8ebc6, 0x6f91d626, 0xd8bb17f6, - 0x9f0f859f, 0x6dfef7c0, 0xe9fc8010, 0xca1fdd35, 0x9a94f480, 0x907b32f2, - 0xe4d2c3ce, 0xfc9f2a14, 0x9701725d, 0x897b92a7, 0x764d073f, 0xa77de695, - 0x46ce2d5e, 0x72ded17d, 0xd61d0098, 0x0a1cb782, 0xa1ea2795, 0xe5f51b38, - 0x971b7aad, 0x5c9deb27, 0x70f7aa9e, 0x49db1879, 0x76c75e9f, 0xb037b7d2, - 0xd85dea9d, 0x1c31e54e, 0xdba2ca97, 0x96bc7893, 0xb42c92db, 0xd0c9838e, - 0xfa4fcc6c, 0xb70c4e14, 0x3fe01782, 0xab6afb1e, 0x978c2aed, 0x34a17f56, - 0xb3f4f90d, 0xac142aaf, 0xee3c5b1f, 0xbb60bfa1, 0x1fa667f9, 0x9bde90db, - 0x8f5a394e, 0xaa9edd63, 0xfa41d8fc, 0x9d112c79, 0xb9b59923, 0xa63a434b, - 0xcd1c6f93, 0x3660d76c, 0x7af4d3d6, 0xd95d7cc0, 0xa595807c, 0x42e0f93d, - 0xaf597125, 0x577f21b3, 0xa3dffdda, 0xabb025ba, 0xaa2aeca2, 0x7b248863, - 0xb641cc97, 0x7b92b1f7, 0x95bbc605, 0x127fff0e, 0xd17b0dbf, 0x91a43fa4, - 0x49a9987f, 0xbcb372e0, 0xe1a49383, 0x95bf46e7, 0x49ff458e, 0x25debafa, - 0x98cd7db3, 0xc741692f, 0xfa35fb48, 0x96ab38cd, 0x9e66fc91, 0x72a26f2f, - 0xeb8b8559, 0x9ab355be, 0x1ccbfec8, 0x94bf7b97, 0x65d07fdf, 0x512dbd66, - 0x389c5fb0, 0x8e9bf468, 0x7bb8464a, 0xf8312ba0, 0x69f5e92c, 0xd612637f, - 0x8ab27917, 0x0337dd64, 0xb63b5dd7, 0xebe57b51, 0xde576cad, 0xf2e12f24, - 0x6990a899, 0x21d0bed8, 0x2a64c379, 0x4a6a3ff3, 0xe4a776a3, 0xd42db625, - 0xa6289da6, 0xbbd96cf6, 0xd5a7ea90, 0xa7510a32, 0x2ef38594, 0xb9c5bf60, - 0xbe1b5e29, 0xd0fc2a77, 0x85dfd245, 0x04de49b9, 0xf04af3f2, 0x7baa1ae9, - 0x9506dead, 0x6958f1d6, 0x4aa38d32, 0x5bd6135e, 0x1ffd286e, 0x2f894744, - 0xda892405, 0xd7e10a5d, 0xc3f77f27, 0x6bf62732, 0xd9012719, 0xde70a9cf, - 0x85fe889f, 0x026a899d, 0xb38b69f9, 0xb16bde8c, 0x5c4dce48, 0xff5295f7, - 0x7d598e40, 0x7e3dc71e, 0x41e39d9b, 0x8c055be5, 0x36df8e83, 0xe542e386, - 0xa84bf35b, 0x78126e3c, 0xcaadf2bd, 0x41376e0a, 0xe54a9c98, 0xf7e2dfed, - 0xb0fe97b6, 0x1fe38dcc, 0xdf62ef1b, 0x562a7282, 0xf624fc22, 0xbfde8907, - 0x77fb9abd, 0x9d0f9948, 0x0b17fec5, 0x38ac8a52, 0x213bb97f, 0x58c57faa, - 0x497d5457, 0x2562a8f6, 0x16564fc2, 0x6fd54564, 0xb38a9628, 0xe6fbfa23, - 0x57d54427, 0xb38ab994, 0x54dffa23, 0xbeaa2a39, 0xa8aca6f2, 0x1cd342fa, - 0x61ea3fe1, 0xf3b0997e, 0x20d965f9, 0xa9fc898c, 0x037df453, 0x3b26efdb, - 0xa9f812ef, 0x09f885c8, 0x55d652e5, 0xd8b971cc, 0x00affbae, 0x92667b74, - 0x2ebf17ff, 0x83de8f1c, 0x4999fe20, 0x16fc4878, 0x201e2376, 0xdc60a47c, - 0xcca7a08e, 0x2bc71d11, 0xff27cd40, 0x84b9d15b, 0x67b954f1, 0x319a1979, - 0xbdfa31f2, 0x8161f90a, 0x2ee86243, 0xa5c732ea, 0xf46c62b7, 0xabae06fb, - 0x316be9d0, 0x09529bf9, 0x6eb4058b, 0x7ac635c2, 0xb72e3a0c, 0x8ef90a9e, - 0xdfff1432, 0xfd2c575c, 0x7f791b00, 0xa0d74b11, 0x8881c74b, 0x760718a7, - 0xc43e32a6, 0x3e1e3b9f, 0x254f7030, 0xa45737fa, 0xee48737f, 0xf79785e5, - 0x97b8c66f, 0xb8c67bc3, 0x2cd0fbc6, 0xfbc6fcf3, 0x2955cf43, 0xd89df3fe, - 0x73ce293f, 0xf9ff14b7, 0x17fdd173, 0x03a36a28, 0x4828f8ed, 0xfbf100de, - 0x2410aab8, 0x35ad3d2b, 0x43e8b951, 0x747842bf, 0x1340d9f1, 0x837af395, - 0xfeb8adc7, 0x956572eb, 0x1e060df2, 0x8cd75d8a, 0x3a4fb154, 0xabb5497a, - 0x5012ded8, 0x68bfb4ed, 0xd3b55879, 0x8345aa3e, 0x6a2fda0a, 0x691b4d13, - 0x63e5a1bf, 0x549cf589, 0x52f3e7e1, 0xca318e05, 0x5e7f6567, 0xb6d5962a, - 0x8b09479e, 0x60317cd4, 0x94703021, 0x48c15e70, 0x0954779c, 0xa3be683a, - 0xbe1d070f, 0xa57e3f08, 0x29146f38, 0xa7e93a5b, 0x91fa45a4, 0x16825b52, - 0x391637e9, 0xaff5515d, 0xc7d8aa9c, 0xbd45467b, 0x159a9d77, 0x6bf10fd5, - 0x46a0e12e, 0xe42ae40b, 0x5e894d47, 0x7cb177c2, 0xfd7d17fc, 0xe093875e, - 0xaadd9813, 0x97138fec, 0x7f82a5bc, 0xa457cfb1, 0x6fea7d8a, 0x6e583d68, - 0x35f4154f, 0xe2013ec9, 0x3e933710, 0x4f71d6c4, 0xc3c68aba, 0x77a43d91, - 0x22e9bb5e, 0x4ef86f42, 0x29d7d5ea, 0xe9decfa8, 0xc44eefa6, 0x8ba923fa, - 0x699e7d44, 0xffac04cf, 0xd45cb534, 0x374d36af, 0x057e017b, 0xc32baf8b, - 0xe7dbba7a, 0xfb79c54f, 0x12ad8ecd, 0x24c519e2, 0x787b9141, 0x0588fbff, - 0x160a29e3, 0x21734c95, 0xd8ab76ad, 0xa024d72f, 0x25fea3ff, 0xaafc4a9a, - 0xdce43049, 0x1d714193, 0x9134ceee, 0x6ff630bf, 0x87be0b76, 0xfcd8e7ef, - 0xc25f42b5, 0xa5fa2ac9, 0xca2ff7fb, 0x9ed8bd24, 0xe7f5e4ea, 0x21e799ef, - 0x7d74857f, 0x7ffdfa97, 0x3c536ba4, 0x62cc9aba, 0xfc96de9e, 0xf9bb8a52, - 0xd21c51e3, 0xbb70bcb0, 0x4213cfcf, 0xcb8c2ba8, 0xf5848f35, 0x4bc59746, - 0x90fb7d38, 0x6cacaf7c, 0xb213f3d4, 0x9c8de85d, 0x1bb8da62, 0xfaeb9fcb, - 0x3bcd14f2, 0x1819e683, 0x01f51cb7, 0x56e3039c, 0xe93a8a14, 0x0d172c83, - 0xf81ede10, 0xf7979256, 0x7e0763c7, 0xbfac03fb, 0x97be4777, 0x8907f470, - 0x82ab3f82, 0xb07b1a13, 0xbc1acd3e, 0x3e748c2a, 0x967fe694, 0x6b36e0f4, - 0x9beb1270, 0x8d126363, 0xfbc0692f, 0x877f6310, 0x32d538fb, 0x1fee2471, - 0x88d82f39, 0x11ccb7cf, 0x45e6367c, 0xee28da9e, 0x3c5b37bc, 0xf9c0e837, - 0x06ff885b, 0xc074433d, 0x03c72758, 0x45a47910, 0x61e443b2, 0xbce260ff, - 0x1f192d49, 0x359cf7d6, 0xcfaebef1, 0xe68057d8, 0x9b933d58, 0x27399e78, - 0x6c4cc936, 0xd4ccff00, 0xb6af4859, 0xfa7de7ad, 0x7de8ee8c, 0x7f4eacfa, - 0x9bdf03a9, 0x7cfc7ef5, 0xdc7d3cc8, 0x299410d9, 0x89e9cf5e, 0xdf4f37ee, - 0x1f3bcfa7, 0x54cdfcfd, 0x868dbe3d, 0x8e7991d1, 0x33ff7d3a, 0x0a427c78, - 0x3af929e9, 0x516ef919, 0x3a9d9865, 0xeb5a37ec, 0xf90e5fb1, 0x85971b47, - 0x11779da7, 0xa8f56dfd, 0x93f216d0, 0x7b0d2e1e, 0x770d3c2a, 0x7988d4c2, - 0xf837bd74, 0xe0bef838, 0xdc9eb4e3, 0xbac7cf9f, 0x410cd3b9, 0x739d7875, - 0x820d3e75, 0xd3a0f3e0, 0xd99e7cc2, 0x61e9cbf5, 0x98f5647c, 0x5f588d40, - 0x6a089a82, 0xe7b53f84, 0x65d546a6, 0xce3a3e43, 0x9f8fae98, 0x351d1de4, - 0x0c37818e, 0x5a9abdf9, 0x643849de, 0xe31d63ba, 0x13d9948e, 0x3e2dc6a2, - 0x64272b1e, 0x2476e11c, 0xd7089ff2, 0x70a2569f, 0x80772cc6, 0x3fb30038, - 0xc9706254, 0x68ec9976, 0xe7e8d9ee, 0xc8cbb4e6, 0x84fc72ed, 0xef9f3fa9, - 0xe9f9fbfe, 0x99f9a2d2, 0xcfcd1156, 0x3f345f74, 0xf3455733, 0x9a3f946d, - 0x4dd6632f, 0x6abf6a89, 0x7d545163, 0xa37383fc, 0x006167fa, 0xdc4fac8c, - 0xffaa24ba, 0xa22beda4, 0xba9f93ea, 0x5e7faa2d, 0x7b544d70, 0x2baacefe, - 0xa8617f92, 0xb11faa2e, 0xf20df4d7, 0x1fedbabf, 0xeff9e6a2, 0x34a2ff96, - 0xcbaf2f3d, 0x438e997f, 0xc7fa1a5c, 0x4538e1a2, 0x93f215e9, 0xbe37f6ae, - 0xa04bfca0, 0x53bce544, 0x1b780960, 0xd909edb1, 0x1b5f9127, 0xa136ac83, - 0xc13268df, 0x8ff7f23a, 0x879c4c9a, 0x2abcec34, 0xaa8be04d, 0x9ff7e134, - 0xf8a69b46, 0xeccff066, 0x78449ede, 0xa0993643, 0xe29ae29b, 0xc671bf65, - 0x716be101, 0x7034793e, 0x7934ab5e, 0xa899b2f6, 0x329bf287, 0xd1e51fef, - 0x7d71507e, 0x3f1fc78d, 0x8b9ff941, 0xfa4a9b0e, 0x03faa72a, 0x7d70b714, - 0x2461e7a1, 0x3eaf795e, 0x49f6893c, 0x67957d46, 0xbfea66e3, 0x93858eea, - 0xf43aff68, 0x498e8efc, 0x88721165, 0x388adf5c, 0x697be8f8, 0xc4673f22, - 0x6aacdb87, 0x6bca0f63, 0x3ffc2c9a, 0xa5ef85c6, 0x903ffae1, 0x9c0b361e, - 0xbad33015, 0xde724e31, 0xba8085df, 0xe194cb0e, 0x8d7ea478, 0x84c1f54a, - 0x26f9dc68, 0x08fb4411, 0xffc72a5b, 0xbb7f0d5b, 0x36f98f2e, 0x3fee88e8, - 0xc144f778, 0xd7236fcf, 0x2c67df90, 0xdd061d62, 0xfc3f75e7, 0x7b87eea9, - 0xe446ffc9, 0x78edd79b, 0xf5f0893c, 0xa7815c99, 0xe8cfe78d, 0x4d267d72, - 0x3bf5e9e0, 0x79919c13, 0x2b90eac7, 0x36db5eaa, 0x423679ca, 0xeb1bd70f, - 0xad0a4bf0, 0x3f6e8363, 0xc93d9dd5, 0xf1e301b7, 0xdc70d3a7, 0xbf171d9a, - 0x37de8fbd, 0x3888640d, 0x6ef9e01a, 0xd7180f79, 0x4415f2df, 0xd297d2e1, - 0x25e57e44, 0x95cb0ba2, 0xdf513858, 0x776c6256, 0xfcc6f951, 0x7c3bb272, - 0xbeb0961e, 0x84cc13ac, 0xb3fb96d3, 0x53f4c4cc, 0x2f677de0, 0x9a5f6d2e, - 0x04dcf3ca, 0xc5c5333e, 0x9d5dbf77, 0xc686fd44, 0x4319c633, 0x2bd459b9, - 0x419cc057, 0x246b9af9, 0x9f380dc6, 0xeefb9e8d, 0xe299b318, 0xbbdf31af, - 0x0ef0bfe0, 0xf00ac5ea, 0xf8c6b8f2, 0x7e51a900, 0x90cb03f8, 0xbf24ed1c, - 0x98532eba, 0x677539f2, 0xd1fe7cac, 0xebf030df, 0xdfce9007, 0x57b17d55, - 0xbb7fba42, 0xfb57e07a, 0x4fadf9f0, 0xb5c5dfa1, 0x87fddb66, 0xc3ce22d3, - 0x917ddcce, 0xc8f10ced, 0x33924ff3, 0x25eac97a, 0xeaa0f8fb, 0xbc489ca5, - 0x616d227f, 0xb307bd27, 0x479ee2d3, 0xab2beec4, 0x6ed93f48, 0x8699c655, - 0xeba7de5e, 0x930bdd65, 0xd25d79f9, 0xfd447ad0, 0x57f39979, 0xbcac0775, - 0xd7477fbf, 0xbf17aa87, 0x9f991998, 0x54bd416b, 0x7274a873, 0x2a9ce749, - 0xf1cf66f2, 0x6fd4a9c1, 0x21efeca3, 0xe978393d, 0xefaa64e3, 0x5e4bf379, - 0x6574dc0f, 0xf323f7f4, 0x9b5cf922, 0xf92ef034, 0x567dea93, 0xa550f295, - 0xdd8ef2fb, 0x4e9af58e, 0x9eb83bf4, 0x239eae0b, 0x6a7ed34f, 0x979404bf, - 0xb02709aa, 0x9569af73, 0xaac79482, 0x65bddb6a, 0x9aabd60c, 0xba931797, - 0x3f0b26d6, 0x0522d356, 0xa7f03c69, 0x748a7f31, 0x357d28db, 0xb00b1fef, - 0x18a8efbd, 0x787d5cff, 0x4ff459ea, 0x9d9f2d7d, 0xb4363a23, 0x763f3959, - 0x196c292e, 0xd85ef383, 0xea02852d, 0xb9f6ddb0, 0x5d6a3ec4, 0xcd0b31e8, - 0xe5b9eebb, 0xfb0f04d9, 0x90b49df6, 0xfad75c7f, 0xbcfeb958, 0x20fb8458, - 0x9dfac5db, 0xf322931d, 0xfc21f749, 0x81f8c883, 0xf70805f4, 0x09e39082, - 0xdaab3e5d, 0xbb123627, 0x7dedafd0, 0xe6bf625a, 0x3bdf9374, 0xffdfebb8, - 0xffdde695, 0xff98932f, 0x7fc657c5, 0x4f1805f0, 0xc0f3e8d4, 0xda1653f9, - 0x9ab4d61f, 0x173bc5cf, 0x77dbbefa, 0xf0c67b95, 0x571636fe, 0x3880b16f, - 0xc10099b7, 0x381e29e7, 0x91ab2c06, 0x07511f9e, 0x0e7147a4, 0xdd60d658, - 0x71467646, 0xc608e3c2, 0xb9d717db, 0xf70f9e15, 0x9de31b08, 0xedead657, - 0x858f6aa5, 0x9e3570f2, 0x75e90b5e, 0x7113f84d, 0x51f6df5e, 0xbf6716b9, - 0x7e16ed5c, 0xc303d0d3, 0xa7d2ebde, 0x87985db0, 0xc6c860e2, 0x66b85f76, - 0xdd53e280, 0xda0ed47e, 0x03fcb817, 0x6f607744, 0x2beb4a82, 0xccc9f7dd, - 0xfe79889e, 0x5187dba4, 0xa3f979af, 0xe7e266a9, 0x2aa68f9e, 0xfbcfc349, - 0xe2eb1c32, 0xddaa55e5, 0x4e6f4e22, 0xb68f9df6, 0x186f0483, 0xb769ade7, - 0xda07f9f3, 0xe28e96c1, 0x75b83b48, 0xf3d20edd, 0x168bd976, 0xcb6d3501, - 0x3fdc0dfd, 0x91e24bc9, 0x480616db, 0x8fa7650f, 0x8afe13f5, 0xcfd4cdf3, - 0xae52267d, 0xe91b7fdb, 0x4f08e291, 0xd46bcc8a, 0xd17e7a98, 0xb75c9121, - 0xaf9a266b, 0xc96fd808, 0xef0f5f0e, 0x54338a9f, 0x9e1ec7da, 0xa7c40e51, - 0x38901e9f, 0xf54e6b5f, 0xf922cd6f, 0xbfb9951e, 0x010bf0e5, 0x9bee973a, - 0x9f44c506, 0x4e9fdeb1, 0xe38c830b, 0x2f042e6c, 0xff79bb4d, 0xdfd21e2d, - 0x611fa69f, 0x86f7617c, 0x234afc80, 0xe7ca06e2, 0x61420bd8, 0xd721271a, - 0x3ce32c57, 0xf3276e79, 0x7bf562cb, 0x4d941f29, 0x4d875c75, 0xfa23adf1, - 0xb144ee6c, 0x657b1e9f, 0xb23eba79, 0x1bce857f, 0xe92f9cfd, 0xed3d0b33, - 0x5f180abb, 0x399d1df3, 0xbe09a4d4, 0x6b2e76c1, 0x46a63adb, 0xf044dbc6, - 0xdf79e8db, 0x44bc5bfe, 0xd75139bf, 0xb6448cf7, 0xfff9d88b, 0xe499f499, - 0x35b35a6e, 0x7c4cf88b, 0x7bf64753, 0xf067ef5a, 0x2e7f1403, 0xaa922bd9, - 0x8d0fcbc5, 0x4e3c9777, 0xea9cdd72, 0xf01575cb, 0xc300acf1, 0x76b8c49e, - 0x57fffd87, 0xe91fff64, 0xf8a2dcfc, 0x4ddfc46d, 0xf16cdd7a, 0x7fb64ea9, - 0x0ff34a9f, 0xfc746fad, 0xf6e9b5f5, 0xff8265ba, 0x4fb7d71b, 0x15399f5f, - 0x4bc68df5, 0x4e67ee06, 0xff48060e, 0x78a0929a, 0xec3e3e13, 0xdd90f72a, - 0xc5f4396d, 0xa6f7b238, 0x2807af24, 0xd66075af, 0x2dfbb22a, 0xfd636fa3, - 0xbc85f4ff, 0x9e623922, 0xad256913, 0x697ebfe4, 0xcfe2cbac, 0x42fc75a5, - 0x5d6323d7, 0xabdf6ee9, 0x11bc88ee, 0x915f758c, 0x9fbe80fe, 0x17f1eaf3, - 0xff9c73f7, 0x2f4487eb, 0xd6ee279d, 0x3e02b771, 0x783b1bd6, 0x1a55c655, - 0x1f7ba31c, 0xd8261d8d, 0xe4a6cb46, 0x5d39c454, 0x36326cb2, 0xb70d9a7d, - 0x4c6c74e6, 0xebba6fed, 0xbd213496, 0x0b2021fb, 0xaf9d167c, 0xa4d24d00, - 0x6bc53cc8, 0x14f3f155, 0xc91bf8cf, 0x9e56ff2e, 0xb4d84e62, 0xf7f292da, - 0xbace2be7, 0x9f3df7a3, 0x2a2655ba, 0x31f42b94, 0x8a0c4e14, 0xa74c17bc, - 0xf133537d, 0x067bff12, 0x2df6cad7, 0x5cdae5f5, 0xfbee4f68, 0x8b1d6db7, - 0xd62d9776, 0xfa46f54f, 0x3dc0a77b, 0xd78ff943, 0x46ee30a6, 0xfef3273f, - 0x12d3a9df, 0xc462b723, 0x88f7c06b, 0x27f2a352, 0x265f23e1, 0x4aed7e93, - 0xb922df55, 0x7cc9740c, 0xe941244f, 0xd8e2b8b1, 0x03c23ed9, 0xd38bf7e8, - 0xd6c43ec5, 0x6d17ce26, 0x317ec6aa, 0x269ce9c1, 0x79c5d847, 0x579fc8b7, - 0x9c60f91f, 0x05dc3105, 0x02e4f1d3, 0xdec37f1c, 0xc34a6496, 0xf6f33fad, - 0x5392ba4c, 0xe91df8a2, 0xa54ffeb8, 0xc236391d, 0x53835ba9, 0xf0a13f89, - 0x93f21484, 0x94040a85, 0xf1f138a2, 0x14de22a9, 0x87c53cd7, 0x3ed850ff, - 0xe5e12d7d, 0x2f58b0da, 0xa6c661cd, 0x7ae036bc, 0x2a635b5f, 0x6ffb578d, - 0xbf934607, 0xe05d297a, 0x4d2f179a, 0xa02bef11, 0x74acff50, 0x41e7ae97, - 0x5f0be513, 0x7d8cf3d2, 0xcfdc4c97, 0x6db0bf98, 0x3d44eca1, 0x3f6f0828, - 0x76cd79c4, 0x4df24aab, 0x3f040e78, 0x771813da, 0x0c5c1ed6, 0x5dfae714, - 0x7db095e0, 0x6fc0e257, 0x0e061f49, 0x773a5558, 0x876e704d, 0x977f1c54, - 0x0f2b4f7e, 0x31c5b215, 0x2f98dcfc, 0x94e7fda1, 0xe0bd2413, 0x6504dff3, - 0x88e35c3b, 0xd31277e4, 0xd5eba25d, 0x89b0c4ae, 0x260645ce, 0xe9875ee1, - 0x7813a61a, 0x3cce835e, 0x2cbbfbf6, 0xe07ee703, 0xa49cba66, 0xe8207907, - 0x2ac9f684, 0xa704d1f9, 0x7048ebc6, 0x3480deaa, 0xa9daae92, 0x6ed0fc08, - 0x35e7251e, 0x6baed877, 0x36eb8713, 0x135d85b4, 0xff8f3f40, 0x8f3a36d5, - 0x8393aa1f, 0xfefc3d99, 0x6c2fe92d, 0xf9cb1a6b, 0xa28c80bd, 0x949963b6, - 0x7954eb4a, 0xb545e87d, 0x07c122f4, 0xb767afba, 0xfea1f689, 0xaa0ee7a8, - 0xaf3f443b, 0x925f69d5, 0x8742f6c5, 0xf07843d7, 0xee7c297e, 0xded7b45a, - 0x05297cc7, 0xd35eaeb8, 0xb19a07a1, 0x87569fdf, 0xe93ee872, 0x1aff5673, - 0x3e57cfd2, 0x2148f35c, 0x665ddbf9, 0x9df9256f, 0x18cfc09e, 0x5668bf87, - 0x1dd845b7, 0xe0c81d8c, 0xf33180fb, 0xf4d99ed4, 0xfdd7c233, 0xce9525fb, - 0x03cdfbbd, 0x9aee88e3, 0xe85a3ff6, 0xfeed64be, 0x4b4f188f, 0x9a1afe19, - 0x035b766f, 0x039b6bdf, 0x1b5ef9db, 0x9fbe43fa, 0x7f08f218, 0xe73a7832, - 0x390886d9, 0xec2e913c, 0xe3fc060d, 0xebb55e29, 0xf6907af6, 0xedee58dd, - 0x8d2275b8, 0x07cf57bf, 0xc035ef18, 0xf7c431a1, 0x971af04d, 0xa0fef3c6, - 0x967a4152, 0x4eedaeff, 0xa3ffa22d, 0x3dbf02e9, 0x66702e9a, 0x89bf8676, - 0xf1df5de8, 0xd69925b1, 0x8e343679, 0x4521b9f6, 0xf1c6714d, 0x1bf64323, - 0xcab54f63, 0xd7fa8580, 0x2bf6079e, 0x14a6ef28, 0xef4bdf94, 0x8d594db6, - 0x4ca2f7cf, 0xe2ae2852, 0xefe294fe, 0x0c6fb35e, 0xe7786ff5, 0xc7e4a9f3, - 0xe74f481e, 0x607e7ff5, 0x1be278fd, 0x22497fea, 0x606ed9d9, 0x69d866bf, - 0xbe29d901, 0x5ffa405f, 0xf63cf54c, 0xdd2cbbcb, 0xf72ed84b, 0x12ec809a, - 0x01ed9ff5, 0xf849dff5, 0xf689c0ae, 0x664fefc0, 0x6dd5df3b, 0xa32718d2, - 0xf5c49f5f, 0xbea91b92, 0xc9ccbbab, 0x05f74e76, 0xc35ec88a, 0x109c7887, - 0x9d1224c0, 0xfca8be04, 0xe9993b88, 0xe7e5fc36, 0x86e3d06e, 0x75c5e29a, - 0xca3965d8, 0xa4e2223e, 0xf4711ba8, 0x9edb33c9, 0xee817b40, 0x0fdc28d4, - 0xffbf0bef, 0xd5563d5d, 0x59773ebd, 0xeeb3ae33, 0x07edcc84, 0x585e7df5, - 0x7a4393d7, 0x86e2867e, 0xefdc5d3a, 0xb033e7a5, 0x675df74e, 0x094b1b6a, - 0xd8aecd63, 0xb9ca987e, 0x412950be, 0xbaabf9c8, 0x99859b0f, 0xb5fe93e7, - 0x9f2eba1e, 0x9ff5cdee, 0x920242b1, 0xc0e5fad8, 0xb5c45f6f, 0xf910703d, - 0xe14e271f, 0x10ff5872, 0xcf018d6f, 0xc97ef6c8, 0x4bbd23f0, 0x5afb1f48, - 0x123ae1e5, 0x4d8a8352, 0x3fd277f5, 0xbac016dd, 0x9f7b433f, 0x99c7e254, - 0x3f49f7fe, 0x997e4ffb, 0xf7b96641, 0xb7c7d8b4, 0xd27cb45a, 0xb809d69f, - 0xa7a38db5, 0x3c8ba5af, 0xe215b14f, 0xa57e4b9e, 0x009cc1c7, 0xfef1223c, - 0x5106765c, 0x655a17ee, 0xe7f882cd, 0xce56043c, 0xe7a37f23, 0xfd01ef6f, - 0x941fe1a7, 0xf57abdcf, 0x182bc21e, 0x627deeb7, 0x89bfb9c4, 0xbb6d69f4, - 0x6b84ff04, 0xfc4cf75f, 0x5e46097b, 0x1db6beeb, 0x3ca0c647, 0xee8b9eab, - 0x9ee861b7, 0xbdf7887b, 0xefa39a1b, 0xae957c1b, 0x308996e3, 0xea0b7091, - 0xb307fb13, 0xd4569d02, 0xfd3257df, 0x7e5e109f, 0x84f824c9, 0xf2ed957e, - 0x671eb713, 0x1a3f844a, 0x8f7c00b8, 0xe8676f28, 0x99d7dd30, 0xa5e59cdb, - 0xa22ae639, 0x165b6e7d, 0x825019c7, 0x9837dd32, 0x19cbf9ad, 0xd3b4075f, - 0x9d642f74, 0x89c127ee, 0xa3bf287f, 0x8e9d6baf, 0x460beee7, 0x82073dd3, - 0xdacf348d, 0xd1fee29d, 0xbff19dfa, 0xc7d5a813, 0xc9d4f0d9, 0xac0e9423, - 0xabf7450e, 0xdb53f9d5, 0x05bcfd16, 0x9f181278, 0xfccf7d11, 0xfc43ef4a, - 0xc5f02cc9, 0x4638fadb, 0xc219b5fb, 0x7920d67f, 0x410ddf24, 0xb37a4839, - 0x0b240a4e, 0xd58e0b7c, 0x865df748, 0x65f7e8be, 0x73f9d6ef, 0xbc2fae97, - 0xfabf7c2e, 0xe7482919, 0x24ff7780, 0x427bfe9a, 0x1f49cbab, 0x5d6af562, - 0x6df199b3, 0x10b46c15, 0xabd58dbe, 0xd97d21aa, 0x1638a16e, 0x7e354fab, - 0x0b7432e9, 0x4b7ffe5c, 0x98737af7, 0xffeb4cf3, 0x3ca5e4a7, 0xdfadbdd4, - 0x745e50b1, 0xf9087da4, 0xa27a1956, 0x5defebaf, 0x7c86edcf, 0x9614c0a7, - 0x15da456f, 0xf1a283ee, 0x50cb6ef4, 0x7cf3929e, 0x38139d83, 0x51e86e3f, - 0x3ae538ec, 0x14fc5f2e, 0xada17970, 0xa2f84ed4, 0x2bc9b8ff, 0x4c7f9ca9, - 0x4c3e442e, 0xe103203f, 0x89f6fe8d, 0xfe90078f, 0x37c513a2, 0xfa7cbe52, - 0xd83f8c09, 0xf8b3a7be, 0x115fe457, 0x7d91a4e1, 0x4ecaec2f, 0xc783bdfb, - 0x7fddf8e1, 0x4af1e8bc, 0xcbc7c3f2, 0x095c698a, 0x787ee9db, 0x1a871e91, - 0x7bd9178e, 0xfdd1e222, 0xbedf2219, 0x47fbf3c5, 0x78b05f69, 0xf94bd9b7, - 0xff66c58e, 0xafa404a6, 0xdbc905e8, 0xe91db380, 0x8d24f43e, 0x52a4f68b, - 0xeef166be, 0xf6a21def, 0xd3125dda, 0x28bedfdf, 0xc7c5177f, 0xb8a5eca0, - 0x577edfd7, 0x7384bdc1, 0x7053dc0e, 0x477cc457, 0x595f8552, 0xe399957c, - 0xfb68ef71, 0xcf292b2f, 0xff60eda9, 0x1eeafbd0, 0xb0577f0b, 0xae0f024b, - 0xf0e788f3, 0xbd0f89af, 0x085a4efb, 0x9eb697e4, 0xf1c4f4b4, 0x017946cf, - 0xce6171b7, 0xf0b76ebf, 0x7fbdca3d, 0x6b7ad0b0, 0xf388fb9e, 0x126d5569, - 0x67aaa7fb, 0x794aa0e4, 0x58af039e, 0x9a6b3f48, 0x8accc825, 0x3b73376c, - 0xffaa51f9, 0x65f859b1, 0xe8d7ef43, 0xbde86e7a, 0x746b0761, 0xd6d775ff, - 0x17bf3d68, 0xf1a32db4, 0x579a7bfd, 0x7ba03df3, 0x5ff7c7b6, 0x4b5c1f86, - 0x2b8c52fb, 0xee8a9f6b, 0x7e90df77, 0xc7bfd807, 0x3257c9fa, 0x3cd8f3f4, - 0x1efd23c8, 0xaf19af0c, 0x7e7d3da0, 0xc43c6ab2, 0xd71e3bc9, 0x8f1180f1, - 0x8e26c307, 0xfafdb167, 0x285a2eda, 0xfe76d68e, 0x796bf199, 0x872c67fb, - 0xbe0ef6ca, 0xf83d7aaf, 0xaf1f1037, 0x093bb76f, 0x08f65747, 0x6ed25fbb, - 0x6a25060d, 0x7c91350f, 0xef8a0ffb, 0x4aaf023b, 0xf740a38c, 0x7e756b7f, - 0xb7f9d5ae, 0x6367f716, 0xbe8adee8, 0x772fbeff, 0xe2ba11c7, 0xdf3fa351, - 0x993875d0, 0x8404b8f8, 0x12125a7f, 0x8790c9fe, 0xc6465f11, 0x936f81d1, - 0x5bb7d73c, 0x52f8bef9, 0x6d2d3fdd, 0xc593df16, 0x51fe8bfa, 0xddff9176, - 0x8d8de82b, 0xd1ad35a7, 0xd232bbfd, 0xea0fdfd9, 0xc313f878, 0xa8f2e8df, - 0xe53b001c, 0xb2a897e7, 0x756fc837, 0xe77f342b, 0x63cf8954, 0x2989d53b, - 0x194beef1, 0xce3a9be5, 0x28cbea37, 0x43fd864f, 0xc88eedce, 0x998dfc7d, - 0xcd54af02, 0xcf240391, 0xb2cf7d88, 0xfbb8aca2, 0xba44c81e, 0xd77b18df, - 0xee45a64f, 0x391db47b, 0xf23f67a4, 0xf7495e3c, 0x859b6a8c, 0x8d9be87f, - 0x8e10a6e3, 0xb5c5c607, 0xed20d6cd, 0x4f516a4f, 0xd2307bf8, 0x76bfb20f, - 0x07e91169, 0x991c1bee, 0x3a72cf48, 0x2ff5c4aa, 0x8e38c36f, 0xfb2f2fc3, - 0x2baaf58c, 0xf91bac5b, 0x1f6f1996, 0x6a1fec61, 0x6a9c092e, 0x7a51af3c, - 0xd3511f78, 0xb749ee2e, 0x5c62fa1e, 0x7fdbd216, 0xadc63fe0, 0xa64172c6, - 0x25adbf88, 0xbee98fa1, 0x6cbbe7cf, 0x90e8f171, 0xd89a97bf, 0x3dcc6a0e, - 0xf6578c19, 0x859c2e23, 0x4fedf37e, 0x7ad1df79, 0xca4ee128, 0xf1adf5c7, - 0x837e778f, 0x13601a9c, 0xd04ddae3, 0x9ee125c4, 0xd6b81c48, 0xdd0fee29, - 0xaa49c7ab, 0x7d7a8c3f, 0x505df62f, 0x03eecf14, 0x2349e65b, 0x1bf0dded, - 0xafbebad5, 0x85b1d82f, 0xf163e08e, 0x476eb551, 0x2e39fc88, 0x1ba2e2c6, - 0xb4f5a333, 0xc644ede1, 0xb25dfdb9, 0xc8c47293, 0x268c5fd7, 0x7ef887dc, - 0xeb3c9c42, 0xf65ebaa7, 0x0dbee7ea, 0x9be665b3, 0x0d288e69, 0x63fc851c, - 0xe93fe97d, 0xcb1c5208, 0x04caf83f, 0x9dfaff92, 0x2445e7d1, 0xdfdf3f3f, - 0xaafcb20a, 0x433e7643, 0x3a5fda32, 0xd214caf8, 0xbfb786b3, 0xf97211cc, - 0xbee2c722, 0x29467d3c, 0x6bff6249, 0x77fec492, 0x4c93d2af, 0xfddaaefb, - 0xfef22fb2, 0xbbe721bc, 0x4501fd75, 0x65d7f3ec, 0x686f5caa, 0x3a617a17, - 0x7f9c4a20, 0x98f3c8a5, 0xed11fe79, 0xdf2fa825, 0xe880b710, 0x9ad7d942, - 0x6aef5807, 0x9e989a4f, 0x198393da, 0x05ef11d9, 0xf24cdc68, 0x801b0d7b, - 0xc81d88fd, 0xefa52ebf, 0xf4beb10f, 0x59c604fd, 0x523c2647, 0x64adce29, - 0xc0f5bf20, 0x239355db, 0x3d05fffd, 0xc1f103ee, 0x09e72843, 0x87cebf31, - 0xcf42b04d, 0xae3d0813, 0xee2c71d2, 0x8ec89aaf, 0x5757f763, 0x0e1b938a, - 0xc7f28158, 0xf9581fb5, 0x07e7d03e, 0x1dfef2d6, 0x9327f92e, 0xffbf019f, - 0x381f2a6a, 0x3d3276b8, 0x7de0fcff, 0x53de7357, 0xaf9514da, 0x1e7d1008, - 0x797f51c2, 0x97c276f7, 0x90e30a5d, 0xefd3aea2, 0x9eeaf9d2, 0x9b7f3356, - 0xc677bd59, 0xc22481e3, 0xe94b454f, 0x9d3d9dbb, 0xe21feb0a, 0xd947032a, - 0x289d4719, 0xe3851c66, 0x165c82f8, 0x71a4ab1f, 0x5314944f, 0xc9db0937, - 0x1c274d9f, 0x55c618e5, 0x9cff3d06, 0xdfd9f829, 0x13f9c091, 0x3d082609, - 0xba28ec83, 0xcebeb437, 0x9b436438, 0x86bdf51c, 0x4ceedef1, 0xd7b0ae71, - 0xa490b3d0, 0x16ed1eb1, 0x3db686e5, 0xf58eb419, 0x49eb10e6, 0xb459b343, - 0xd02512ef, 0xfe0ccdf9, 0xfc4038d8, 0x508f4639, 0xc12c4b2e, 0x77db84b1, - 0xea079d0f, 0xe28239f7, 0xe7635d5e, 0x686efe44, 0x3b8f73b0, 0x4e39fc5e, - 0xda4833e7, 0xcfb12cd1, 0xf3af6d89, 0xd1c67c88, 0x1e2fc233, 0x1c9fe85d, - 0xa0063fcf, 0x25fbec44, 0xe6ad7e5d, 0x86e7788a, 0xdf223d1b, 0xe06c73b4, - 0xef71e928, 0x373e04ee, 0xfc8975ec, 0x974b696c, 0xac9fdf42, 0x5066956f, - 0xfb9f5a3c, 0x829f7f1e, 0x83f662f5, 0x6e7cfde1, 0xbbbcdd5a, 0xc7438b5c, - 0x1f111eb5, 0x01dfe897, 0xbd57d08f, 0xd37814fd, 0x23da7df5, 0xaa735e74, - 0xdf14ecd2, 0x4aef8999, 0xf9fdd06f, 0x199bd78d, 0xd5029d37, 0xc43fce2c, - 0xdd32c539, 0xfba0df2f, 0x3bdf11f9, 0xe99b033f, 0x7bf6229c, 0xdfafc367, - 0x02bf8fac, 0xf6371e34, 0x759bf5bb, 0x2fb3783c, 0x4ca5f9fa, 0x40e6071d, - 0x10f3f90e, 0x1fbe17c6, 0x71c09791, 0xa4e1697a, 0xbe8338b8, 0xeff55703, - 0xe434a9c0, 0x1ef790de, 0x1da3bfc7, 0xdfcd7e67, 0x80499c13, 0xc5ce7109, - 0xe19fe386, 0xf2126e3f, 0xaa2dcfd6, 0x4346829d, 0x077017ee, 0x331f9916, - 0xe7463ee4, 0x3df1ffff, 0x22505ca0, 0xcacf25f3, 0x3a1e31fe, 0x32f5b09f, - 0x7015c6fe, 0x8d75c41c, 0xce35d7d3, 0x2edf111a, 0x571d5a8c, 0x97d7877f, - 0xc471101a, 0x9e4765cd, 0x75627195, 0xfbefe248, 0x5f62c3aa, 0xf6265d5b, - 0x02ad39b5, 0x49bcaea7, 0xbb126a0a, 0x9f44d3c3, 0x6ccb3fa1, 0x7a180f02, - 0x5d2fc432, 0xf09da87f, 0x3e3a0dc1, 0xc9a3d588, 0xf94e5dd0, 0xc9345be6, - 0x472af74b, 0x6abf3f7c, 0xeee4ebda, 0xa83fa72f, 0x22effc6f, 0xf7d1eac4, - 0x0f12fe3d, 0x07bad3e5, 0xb8e21657, 0x38fef347, 0xe6a6f48e, 0x2df37632, - 0x3b13888f, 0x7ca3811d, 0x3f45a4df, 0x6bc96fef, 0x747e21eb, 0x5ec7e302, - 0x3a96f757, 0xbcf9ab81, 0xc09c3abf, 0xb75643df, 0xb0bbf9db, 0xc486d6ea, - 0xdb7fe429, 0xeb1daf65, 0xcb27ad95, 0xc5959f88, 0xad4a3ee2, 0xb38bdc5d, - 0x10b7fdb9, 0x3b7bd77d, 0x2df9cfa2, 0xfba8bf3d, 0xf58f3d06, 0xa3091b6b, - 0xf9f7ffa5, 0x5f3a8d9b, 0x662ebaea, 0xfea9c14c, 0x26afe690, 0xfd7fec7d, - 0xd71d0b45, 0xa5794ed5, 0x6d88ae9c, 0xefdca8f4, 0x268ee6fa, 0xf41af34a, - 0xf93a6477, 0x707351f9, 0x82d2e32c, 0xd30fbb2b, 0xa98dffb0, 0x3afaa714, - 0x225aa6ba, 0x0eb7bbf4, 0xf91c73fd, 0xb7498035, 0x494b855b, 0x25e3a15a, - 0x07b5c761, 0x3e50670e, 0xb7ec97a2, 0x9277ca80, 0xdeacb1b3, 0x12792a7d, - 0xa2bd96e1, 0xed19c21c, 0xa503f732, 0xa4e6e727, 0x3336fa48, 0x6242177d, - 0x9c9e801c, 0xdb230b1b, 0xdb5fff1b, 0x27a4d3ff, 0x289eb6d5, 0x84f837fb, - 0x3efe7cbb, 0xcad07037, 0xbce808f7, 0xc72115c6, 0x347f7457, 0x644b370b, - 0x7ce873a7, 0x3b41227a, 0xbaa0ee05, 0x95256102, 0xb2c38bce, 0x96377fb8, - 0x7d4cf7fd, 0xb84a59fe, 0xcee9ee83, 0xe737cfd1, 0x5bf73742, 0x6a5c0300, - 0x8befe4e0, 0xe5cbc04b, 0x29785b6c, 0x5082f1c1, 0x099fbf88, 0x73ae2867, - 0xe63bfd36, 0xe61ef238, 0x0ce7029b, 0x0e74c87e, 0xc51bee26, 0xd75ba7ae, - 0xf09a59c7, 0xe81d043b, 0x086cee7e, 0x35fbb9f1, 0xbf9fa3d0, 0x3cc75fc7, - 0xb9d1f7dc, 0x3b6835db, 0x208fcc89, 0xeb4f9ff7, 0xa7ade391, 0x198b2967, - 0x9f449cca, 0x7d30ce14, 0x75f2bf6d, 0x4d6dd3f4, 0x35df57ca, 0xe283f7d0, - 0x6f4b73e1, 0xd3ef1bfb, 0xd349627d, 0x97b1bef8, 0x7da6c7be, 0x1de9584e, - 0x001363f2, 0xe6b3ddfe, 0xc66f6437, 0x07e01af7, 0xfb11e7be, 0xf72d06bd, - 0x3df0c67c, 0xedfee335, 0x950ae0ce, 0x72ac6fee, 0xaddff8db, 0x9b8db229, - 0x87ca794e, 0x21bffcd2, 0x6a40fabd, 0x2883c49e, 0x638c19c1, 0x83b2bd75, - 0x2fd69b36, 0x22f7c669, 0xf432fac0, 0x006401ef, 0xb763b77f, 0x1e69ef8a, - 0xa5b43d41, 0x74abf6b2, 0x2e1e1a0f, 0x6f2f0955, 0xf4bcd971, 0xe895ae5d, - 0xdbd30fb5, 0x2ff71368, 0xb16bfb8c, 0x19b46c7c, 0x8daf4a79, 0x77cc7671, - 0xfcda773e, 0xbfe89bff, 0x9324a93f, 0xcbfe6070, 0x3f7c3df3, 0x7758c129, - 0xc3eb8d89, 0x37191af7, 0x6a7dd136, 0x1d31aba4, 0xe1e21ef8, 0xba149ca4, - 0x25d8d51f, 0xa63753ee, 0x9b7fd807, 0xf3fb12fd, 0x4ed2cec6, 0x0e83078a, - 0x6eabdf0b, 0xaa34f974, 0x4421d207, 0x3ef89ffe, 0x69bbe0df, 0xfd21ef98, - 0xed91505e, 0xde5157d7, 0x4a1b9a7f, 0x6169bde9, 0xc0f1126d, 0xe5061ef8, - 0x4e9519e0, 0x7befa3cf, 0xfbe4e281, 0x501c8617, 0x9d995831, 0xb90d7cba, - 0xf8ef8d38, 0x3bea2535, 0x8f5e437e, 0x98b90a24, 0x44cc26e9, 0x71a5577e, - 0xf061e563, 0x8f00bffd, 0x30b1ae40, 0x0030b1ae -}; - -static const u32 xsem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0x243bff00, 0xa3f0c0c3, 0x4aef811e, 0xf1303031, - 0x12d18aa2, 0x6064e3ef, 0x6062e010, 0xfbe20530, 0x330c0c3c, 0x204cf480, - 0x6066e516, 0x1ae20310, 0xc40dde20, 0x19f8807b, 0x1039fc50, 0x1be200ef, - 0xbefd103c, 0xfe0c0c4c, 0xc4081c40, 0x95fc40c1, 0x1be18181, 0x73f6f103, - 0x4c30330a, 0x2ff04715, 0x249fd903, 0xc1ffe7e9, 0xe90c4386, 0xa071df6b, - 0x10acf37d, 0x7b20467c, 0x9aaa15be, 0xcdf85605, 0xbf268858, 0x18bf8d08, - 0x0372fe8f, 0x4d5afe54, 0x81b5b334, 0xcd4909e9, 0x6efc4d3a, 0x40aac741, - 0x3101a9ff, 0x5ff1ad00, 0x000368ca, 0x00000000 -}; - -static const u32 xsem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5947809, 0xe77df0d5, 0x9926665d, - 0x6c81bc99, 0x44d84eac, 0x4242740b, 0x61db101a, 0x8311688b, 0x9817054b, - 0x264f6408, 0xdac7f520, 0x0040cfef, 0x8b435151, 0x03b45a35, 0x341b0504, - 0x024180d8, 0x2d82e00e, 0x5d6ad8d5, 0xc8a0d2da, 0x1b80931a, 0xcefc5dfe, - 0xc9bef739, 0x82264efb, 0xf5ffffb5, 0xf8f8fefb, 0xf77bee5c, 0xce73ddb3, - 0xe28ef73d, 0x8b94c718, 0xff12fb18, 0xdd98c7be, 0xd71b18c6, 0x2356329d, - 0xcf2d4ad2, 0x03d058cd, 0xac62ccff, 0x9785addc, 0x653633a7, 0x5ef91a87, - 0x4837e412, 0x6de43b61, 0xde549d7b, 0x23e79ebe, 0xa0cfcd6e, 0xc83aa3fc, - 0xdeded04b, 0x5065c0f2, 0x6643b9de, 0x91dbb11b, 0xc2963671, 0xe30731d8, - 0xcf90597f, 0xc9c0ac66, 0xf61be5b3, 0x45f6c5cd, 0x84e6764d, 0x1577cafe, - 0xf20cbcce, 0x86550785, 0x2f37ca55, 0xbe43fad3, 0x60352c38, 0x9f3263be, - 0x1ca7685f, 0x3bf50cde, 0x37292d3c, 0x553b18b8, 0x8d5e60e5, 0x4b776ab1, - 0x18a3f5ca, 0xcf6f092b, 0xf52576c5, 0x3a970f92, 0x97e6c765, 0xb6bae1fb, - 0x97bb3e4a, 0xf12dd2b1, 0xcf923bcc, 0xfff84be1, 0xf91ca358, 0x862f941e, - 0xb7e83275, 0x32e4d590, 0xab5fc719, 0xf0dddd79, 0xd3a5553b, 0x7cbe4638, - 0xed038c2b, 0x7c969e2a, 0x1b0ac4b8, 0xf8c0340b, 0xb39cbbed, 0x7d70b937, - 0x6e11b4cb, 0x1addd75c, 0xe70c2bd6, 0x717a74ef, 0x5cb41b7e, 0xbf592f28, - 0xd5182b41, 0x96e95fdd, 0xd579d6be, 0x980d4d0e, 0x53d3a3ca, 0x47798c55, - 0x184be774, 0xbf4037f3, 0xb36b094c, 0xff7f7746, 0x96322580, 0xcccbfd8c, - 0x1feee8eb, 0x43df4920, 0x013fc16f, 0x6e3da15e, 0xb781ab82, 0xdbfc3ac5, - 0xb3b78ddb, 0xd2a3c0ba, 0xdfee6d99, 0x3c401f48, 0x106a7cc0, 0x11ae904e, - 0x644cf3f3, 0xdfe81493, 0xc4ba67e3, 0x918f5f7a, 0x9f2ca8d6, 0x420b58c1, - 0x78cafda3, 0x116c6bc8, 0x93f631f3, 0xa9fed915, 0x059fbf90, 0x57bce2e6, - 0xc4228148, 0x690d6313, 0x24abbf48, 0xffd71b36, 0x94349c03, 0xf407eaaf, - 0x99af7009, 0x9649bd96, 0x3093dcc4, 0xbdc4f05f, 0x214fd4e9, 0x3f42a3f5, - 0x8fdfcf43, 0xe9639b9e, 0x322dcf47, 0x7ea4a9fa, 0x4fd6179c, 0xeb04ee4d, - 0x8c4b727c, 0x7ea4ee7e, 0x2eb617dc, 0xd6898afd, 0x46515cf9, 0xf54e24fd, - 0x97d400b1, 0x2d607a0d, 0x5dca197e, 0xef6389f5, 0x98ba6665, 0xdff912bc, - 0xa6625c0d, 0x389c848b, 0xfa261d0b, 0xd0f258fb, 0x5bec7e93, 0x44830f22, - 0x5f1a3512, 0x5c91afeb, 0x41dfd498, 0xbbfa3bf9, 0x31dc2e48, 0x0eb17021, - 0x59b1c0f3, 0x816bc83f, 0xe831eb6f, 0xb129e61a, 0x36bd4c34, 0xefcba34c, - 0x261c3956, 0x88dbf80f, 0x683ed023, 0x08911ceb, 0xa4d2f5f9, 0x365c205f, - 0x27c11b33, 0x5895664e, 0x48cece2f, 0x9e9ddd3e, 0x826429bd, 0x8041ead3, - 0xdfbba97f, 0x0d206ad5, 0xbb2b6be9, 0xb6f48421, 0xa7ac106a, 0x854f633f, - 0x14848fae, 0x20a83f68, 0xd769e10d, 0xe3cdbf80, 0x28fe306b, 0x1c19ff1a, - 0x3f8e0777, 0xf6f8e7ae, 0xf1963921, 0x2c8b831d, 0x18343be3, 0x177de81f, - 0x0f8c55bb, 0xd8c09bf0, 0x685ba1f3, 0x22e0fb7c, 0x8d6eff1a, 0x8fc65915, - 0x05ff1aeb, 0xdea5f71c, 0x82643fd6, 0x4b83fd75, 0xf8d7ebac, 0x0b655ffa, - 0xb471f8c5, 0x16875ffe, 0x2e0ff5f0, 0xf3b7ebe1, 0xf7c6bb7e, 0x75ffc174, - 0xdeadf71c, 0xa2743fd6, 0x9517fd75, 0xe76fd759, 0xcacbbfe3, 0x1a2ef8c5, - 0x1950bdff, 0x6545ff5f, 0x0f66be34, 0xb48e90f8, 0x61957101, 0x040d9f18, - 0x19254886, 0x6474a7e5, 0xfda0c61f, 0xe084363a, 0xa71c4770, 0x80e2cfbb, - 0xf2dd5cde, 0xa381858e, 0x08559e40, 0x9fad2f9a, 0xa59ca1a4, 0x0b7b9072, - 0x341754c5, 0xb0dfb4c9, 0x70f0f675, 0x937b6f98, 0x82fcc21c, 0x65879775, - 0xbcd8efda, 0xb0a76c3c, 0xf0ff7e08, 0xcd1bd1a1, 0x174e8aeb, 0x5ac7a8d6, - 0xe7c47c2d, 0x46cc9a13, 0xa6fcc256, 0xeb8c1121, 0x39031fce, 0xbe7e40ca, - 0xd314720f, 0x078c2ae3, 0x9c828fdf, 0x6f999a65, 0x3c7df196, 0x991cdec4, - 0xff827282, 0xbc38531d, 0xc2912d8f, 0xd6cfff08, 0x3e50d22e, 0x0789ac2d, - 0x23cf77a0, 0xb9d4f028, 0x28de1ecb, 0x08bd3c11, 0x15891b9f, 0xa033fb19, - 0xb6801fb5, 0xa5afb6b0, 0xbc2c2ddd, 0xcfea0d32, 0x483f935f, 0x3cdff587, - 0xc6563edb, 0x07f983fd, 0xd98f88d8, 0x630e5b00, 0xaad71bb3, 0xe3732003, - 0x56fdf56c, 0x0139fb53, 0x22e6fe6b, 0x0d5dbe6b, 0x37d436ab, 0x01b6258a, - 0xd2b5bdfa, 0x938c6e5a, 0x78e1f528, 0x20fde315, 0x56f7cf85, 0x67e2c74c, - 0x573af09d, 0xf98d6de7, 0x5952ef04, 0xd6cbf684, 0x4ff84664, 0x9d017aa6, - 0xbe7a3baf, 0x3f875573, 0xf733e60f, 0x19e0994e, 0xbdd6ff3d, 0x18db7ef1, - 0x563f6b48, 0xd7a30491, 0x79ff3d13, 0xa3d7a34b, 0x1f961e93, 0xe9cefe8a, - 0x829e9a24, 0x1efa934d, 0x6f2bd535, 0x51efb2b8, 0x6e957d13, 0x17c96599, - 0xea58e787, 0x5be6d617, 0x14d617ca, 0xafe7ca5b, 0xe7c9645e, 0xd4b4ee87, - 0x9974b79f, 0xcad6fca5, 0x37e52c7b, 0xe4b5ad17, 0xb11e04e7, 0xf671bfd4, - 0x6db94b06, 0x20d725ef, 0x25bf551f, 0x3e37dc33, 0x007b1d75, 0x5d4fc1f5, - 0x71f10f8a, 0xf88d2aa2, 0x979554e0, 0x4ca6f6d2, 0xc1cb8047, 0x16715402, - 0xad086b2e, 0x9972889e, 0x5e2cfc91, 0x1a1433b6, 0xe4adda08, 0xb5c9f825, - 0x09008b1a, 0x174fac4b, 0xa6ca771d, 0x94f3d6f2, 0x67a302d7, 0x5b972cf6, - 0x6e0f7f63, 0xe508bfcc, 0x00f26f4e, 0x3ee006fe, 0xf7f621d7, 0x8932f2e8, - 0x33bf99e5, 0xfcf89cb6, 0x65b3909c, 0x6507971a, 0xcc9bf6cf, 0x8c8f983c, - 0xf1aafca8, 0x28a8001a, 0x4f3b5127, 0x2e007a46, 0x50cbd0b0, 0xedb77f0b, - 0x155e6993, 0xa3c61328, 0x235bc9c8, 0x1c899ca1, 0x68dd7c18, 0x7eff879c, - 0x29aef909, 0xb6f5f699, 0x8f7de9aa, 0x3c9f882a, 0xcd544f4a, 0x5558f4a6, - 0x55a3d280, 0x5fbe9445, 0x6b694955, 0x0f4a52d5, 0xfd288557, 0x4a6ad553, - 0xa1aaabdf, 0x5aaa9df4, 0x1550ff4a, 0xcabdb4a6, 0x0fc1a94f, 0x4937f25d, - 0xaec2abe8, 0xf2879d80, 0x565ac567, 0xe216dd40, 0xf21a5f73, 0x67d759f9, - 0x3f1f5023, 0xa19d8efb, 0xbc1bdfbe, 0x77ade9a2, 0x5f49fa3c, 0xfe030829, - 0x3b967b33, 0x9c9e38e3, 0x819d3636, 0xf867ba3c, 0x46dbbe13, 0x92415e51, - 0x37c90d81, 0xdfa31dcb, 0x75f08c61, 0x7f313c3e, 0x016b98e7, 0xfd1ec71f, - 0x7bf6366b, 0x717fec4e, 0x87da6407, 0x0f936459, 0x1b8265f1, 0x3b9d6bed, - 0x0f3fbc84, 0x82ea3efc, 0x0660cb5f, 0x274904e9, 0x68db3bfa, 0xb1c20a67, - 0xc40c3e39, 0xdc1ececf, 0x5c7e41e4, 0x8fd3669c, 0x918380c6, 0xeba43796, - 0xd3fef32e, 0xad9fcd64, 0x9037a691, 0x5c26f63c, 0x4ae91a3f, 0x430e8fd7, - 0x6a51a7fc, 0x4d38b3f4, 0xbf028fd3, 0x3432da9e, 0x61dfef81, 0x27d60fbe, - 0x5d82bd12, 0xd5fff548, 0x1fade9f3, 0x358c3e63, 0x281c0fb2, 0xe86ca00f, - 0x1e9dedf9, 0xd13e5778, 0xcd5f10f2, 0x2fa867ea, 0x5fffc1c4, 0x157ec10e, - 0x06fd1bca, 0xfd90e41b, 0xdebdf8db, 0xf3b41e32, 0xb637361a, 0x156e9deb, - 0x2ba0cc76, 0x1a1a5790, 0x3a2764cb, 0x92beeb75, 0x9b07c968, 0x7d96e9fa, - 0xfc01ff06, 0x4152820f, 0x541329ba, 0x56b8a1d4, 0x23bf304b, 0x2f013f28, - 0x2bd78941, 0x016ab477, 0x0b63912f, 0xe5b719ea, 0xbde77418, 0xef208ff1, - 0x6546fe4f, 0xdff962f7, 0xae505660, 0xf720c51a, 0x2f9f906c, 0x9635b772, - 0x77b940ce, 0xf9f7c6d2, 0x83cf2c05, 0xab114f46, 0xe73d46c9, 0x8e9b6623, - 0xfb11fff4, 0x64d3279d, 0x1a6cf86f, 0x6afe73ad, 0xfa0b3eeb, 0x585f2599, - 0xb017cd6b, 0xde90536b, 0x2ca9d60b, 0x5a5f212c, 0x9d36bdcb, 0x95642dfa, - 0x41dec8ab, 0xbdc6057b, 0x00ca674d, 0x73f95f98, 0x43e7658f, 0xae363bfe, - 0x7bf61ba7, 0xff3e1f71, 0xe6b0a492, 0x1a0ff287, 0x19707f33, 0x55e1f6c3, - 0x6e42a728, 0x7accdbe6, 0xceebefe2, 0xc6be7a3f, 0x8fc3d27e, 0x6f21e620, - 0x18e1fc91, 0x9b34da76, 0x10adf424, 0xbae037a5, 0xbe6b7a4d, 0x2f918380, - 0x19dfca8f, 0xe9a7ff95, 0xe859892d, 0xc81488ed, 0xfa7325b7, 0x52417d42, - 0x37c0b53a, 0x47ad3fe9, 0xd2ffe5ff, 0xff4207fe, 0xeffe96d9, 0x3ff697fc, - 0x57fcc7ac, 0xfcbfeac6, 0x433b6db9, 0x9e4a6f20, 0x60c3c879, 0xd4a93a1f, - 0xef00f8a4, 0x7a579b65, 0x284e0e90, 0xf3d20f21, 0x3d3cb0c9, 0x46ec3d16, - 0xa23f207a, 0x5da125df, 0xfe84ff85, 0xdf753d4f, 0x3e67dc4c, 0x64eaacdb, - 0x47b16d2f, 0x15afc0ec, 0xd833c58d, 0xe11fca18, 0xc8cfbbf9, 0xd2b26f98, - 0x0f93c967, 0x0dffa0a5, 0x13d84528, 0x2a97d211, 0xc5cc3eea, 0x3ac8287d, - 0xdba2cf89, 0xfae7f8e1, 0xd7cc7c90, 0xc3967a12, 0x0fcf493c, 0x1b04b80a, - 0xa3233bef, 0x72b593ef, 0xfd54683f, 0xd4ffa122, 0xc749dcdb, 0xdf6274c0, - 0x7941df61, 0x8583c069, 0xbd53feb9, 0x4731e1f5, 0x756d3e60, 0x2648f1bf, - 0x767c1938, 0x2ffe61b6, 0x2ef6f79e, 0x9d85db8f, 0x4c2eddd7, 0x424dbced, - 0x69e66b6f, 0xa0f11a99, 0x41b65c5e, 0x73e085f5, 0x4f4db6d9, 0xea768a3c, - 0x70df76bb, 0xdb74bfe8, 0x00987f4b, 0x6aedd2f9, 0x0cbe0cd2, 0x8dd29497, - 0xbffc2097, 0x1e376c74, 0x92f57e4a, 0xbfcd1de6, 0x374fb8ff, 0xefb74a3e, - 0x9ee8d8d3, 0xb0d298f0, 0xc5756b4f, 0x91c34bc0, 0xaaafd45c, 0xa1ae7eb7, - 0xaf72793d, 0x63d352c4, 0x4bc373c0, 0x9c2027a4, 0x4f028f08, 0xaa8b785d, - 0xa0bc041f, 0x14f0373c, 0x9080fe5d, 0x779fd83f, 0xd3f3d114, 0xf95fa3cf, - 0xd70fbb3d, 0xedf4f45f, 0x71c75c1e, 0xf5d392a5, 0xfc532b63, 0x1a916e30, - 0xe529d14a, 0xff1e8bdf, 0xe15bd121, 0xe14c3f1b, 0x9fbfa0f6, 0x50a6f68d, - 0xc2df5c3f, 0xfad037f5, 0xe880580a, 0x3931e8ae, 0xa7e90c2f, 0x3dbe9b0a, - 0xc8645f06, 0x6f8e2f9c, 0xd60b8504, 0x12ed1c77, 0x4efeb3f4, 0x7f266f0e, - 0xfc8622c8, 0x3fc343ff, 0xfe5316ce, 0x93c70753, 0xbe09b643, 0x4ccf6d02, - 0xb77775af, 0x0d4e7e20, 0x1fa2a7f2, 0x9094c82d, 0x25f48780, 0x31bf2bf4, - 0x87e3952d, 0xd16c9579, 0x2980f40e, 0xb7eb1df8, 0x18e77ea8, 0x65f63b4b, - 0x4bf8f77a, 0xef30f8c4, 0x8fbfdc38, 0x86a2b0a7, 0x55bbeb18, 0xf61ef836, - 0x997d1371, 0x7bf39bf8, 0xbf9c3ddd, 0xcf0f7e0d, 0x9fe58e9a, 0x07f9c9bc, - 0x08fee1db, 0x52a48af3, 0x25ebbef9, 0x16760792, 0x75d7c589, 0x6b6be0aa, - 0x302741b9, 0x304a456f, 0xdff60bd1, 0xfe4fe087, 0xd07582b3, 0x832f24ce, - 0x67a79e38, 0x16df067f, 0x251ffe0a, 0xad9ff95b, 0xbbdf7ce7, 0x7da2157e, - 0x3f0d4cae, 0x2bf228f1, 0x8bc867f0, 0xe1e6aafc, 0x1fd74fba, 0xc04dc3f8, - 0x0c1ba7a7, 0xcfcab53e, 0x7a2d3e68, 0xf484b376, 0xa7a7cd19, 0x891b408b, - 0x3df0a7c5, 0xb5169f26, 0x9f953ffe, 0x8faefc06, 0x0f219f82, 0xb463837b, - 0xf3633c3c, 0xe5a33c12, 0xc9bdfc21, 0x9fd27bb2, 0xbd067741, 0xfcb2fc95, - 0x1817f222, 0x5dd06974, 0x741a5d17, 0x62ffc3d7, 0xf9745f81, 0xa005a460, - 0x2a5dbc93, 0xcd6555d9, 0xda0c3cfc, 0x8b203cbd, 0x6da7e4e0, 0x3cbcd58c, - 0x0f9cc920, 0xa21be547, 0xf2a3fbea, 0x03f55179, 0x4b4af951, 0x03a6b2fd, - 0x47fc231a, 0x4becf52c, 0xc41f651f, 0xfd8c87b0, 0x4678d826, 0x0c5d210b, - 0xde50d4ec, 0x0541cba9, 0x1ee0ff45, 0x0ec5ec99, 0x182af180, 0x3d3ea3a7, - 0xb1b9021c, 0xf0edc9d2, 0xd3d3bd0e, 0x8995d207, 0xac99df3c, 0x67b942ad, - 0x7274ef7c, 0x5e47473f, 0xe4d127a7, 0x2cd238a7, 0x0d6edc93, 0xfcb1e9b3, - 0x10a3b020, 0x6f595bde, 0x39ffdce5, 0x5e0d764d, 0x8d68f68a, 0x771343ec, - 0x3d1bb2c1, 0x68e92ae8, 0x6ccd7a1e, 0x55f0bef8, 0x3a558e99, 0x70633ce2, - 0x57e42c5e, 0x89ec99fa, 0xb3f42c13, 0x6ccfe889, 0x82c576e6, 0x08fa5135, - 0x54f4435b, 0xa1a25ae0, 0xe03b053c, 0x973fab7d, 0xe88945f3, 0xb5bd68af, - 0x278f68dc, 0x95df685a, 0x03cb59d4, 0x65da3ec2, 0xcb0649f0, 0x86833920, - 0x42e7da0f, 0x47934f2e, 0xf01b335d, 0x665071d1, 0xb6799e78, 0x9c7c2659, - 0x97e7e7ad, 0xfc4c942c, 0x493ac156, 0x6a701a1e, 0x7ad27e43, 0x3b6d5797, - 0x177d9cfe, 0x3fcecdd2, 0xa439f98e, 0x1ddf3b6d, 0xcff31bb1, 0x8ff83dbd, - 0x29fd67ac, 0x37e49d7b, 0x26ebd8ee, 0xf3d8ef7a, 0x6177c1db, 0xfc9d977e, - 0x3f7b1d75, 0xd7f4831f, 0x845edcb1, 0x1063aef2, 0xf7aa87b7, 0x95a63e7c, - 0x8415d7f6, 0xc6b2a3b7, 0xbfe6a3f5, 0x3092961e, 0xdea15585, 0xf89e37b0, - 0x93bcf829, 0x7b1d0bfc, 0xb80ecf3e, 0xa9eb75fe, 0x1d39e710, 0x59fb366e, - 0xf7225f9c, 0x8f770783, 0xcf0cb4df, 0x69f71ba3, 0xca7ca1f3, 0x831f7f0b, - 0x59e3b472, 0xabb50fae, 0x79e38fad, 0xe1fc8745, 0xdce01532, 0x9fd54c8e, - 0x1194fbb1, 0x62a34393, 0xe4efe5c1, 0x7850b937, 0x4fb70a68, 0x21e1fdff, - 0x73bcb9f9, 0xae121d87, 0x7fc38bfb, 0xd7b0b944, 0xac69744e, 0x32c374f7, - 0xb7ce57d2, 0x7fcae1ee, 0xd0b83a17, 0x0b914b75, 0x7fd4f759, 0x5aff7c73, - 0xa2fcd2f6, 0x9d27a0f9, 0xf283b9ef, 0x9a3edcdb, 0xfbd205ef, 0x7869ff82, - 0xeef0167f, 0xabbaff39, 0xddd7cdff, 0x9d5fde3b, 0xe3aef02b, 0x85f07f79, - 0xbefcd3bf, 0xf4db9cae, 0x0dee94df, 0x9b15febd, 0xa80ccdf7, 0xb8d59d3f, - 0xb2b8b150, 0x19abff7c, 0xc0cafa50, 0xdf388903, 0x37e751c9, 0xc2a6fa46, - 0x92c9a6ed, 0x9641ec8d, 0x907b0928, 0x840351db, 0x496030fe, 0x0321e901, - 0xf5cfde06, 0x0ebbc506, 0x195f1fcf, 0xb147df3c, 0x3bec6c14, 0x97ebcc01, - 0x9ed5bc8b, 0xfcc4b9fc, 0x603a3478, 0xa20ff7f0, 0xa0703b5e, 0xa42f7a4c, - 0xe8beefa4, 0x97bfce99, 0xe7bb1669, 0x0ed5af4a, 0xdab24dca, 0x7f45534b, - 0xff9f18d3, 0x0e149734, 0x0f261c03, 0xfa1269fa, 0x570f2747, 0x5cf90499, - 0xf6815816, 0xb59754c5, 0xc33c06bf, 0xe1cdf719, 0x380d5768, 0x8797590e, - 0x93241c70, 0x70bcf49f, 0xdc1379c4, 0x2f18c232, 0x871f14c3, 0x1f729f63, - 0xbd859df9, 0x904d474d, 0x5aab5c57, 0xb4159f90, 0xc81c3997, 0xe5ec36ce, - 0x84cde0de, 0x2188adfd, 0x032bf80d, 0xdad3bf65, 0x06dfd91f, 0x3e2ebe5e, - 0x537e3c0c, 0x851bbcbc, 0x45ae8197, 0x74ebf20a, 0x62fa17b4, 0x1f9e0cfd, - 0xdce85218, 0x570bd84d, 0xa4291778, 0x50cc0cf7, 0x8e855f10, 0x1cf0aba6, - 0x6893e1c4, 0xd9b7171e, 0x64707f68, 0x91f70449, 0xdfe50ab5, 0x10e3e9b0, - 0x7b2f33df, 0x0c9df4ee, 0x8d7ee6fd, 0xf1e53dc7, 0x7dbf8ff3, 0x8c44e5f9, - 0x2c781417, 0x46afff84, 0x167aff3f, 0x2d380389, 0xa1285854, 0x25bdfa0f, - 0xefc5bef6, 0xdfe3cd6d, 0xfbba5377, 0xdefd5f39, 0x3abfcae4, 0xd8e40e7d, - 0x5df300fb, 0xe1a30e98, 0xfd5db315, 0xaf0e669d, 0x1e1621e0, 0xe42ae3c2, - 0xe139d33c, 0x9ffe821d, 0x99b3d3fb, 0xea4ed768, 0xe5c09518, 0x17b230eb, - 0x385ec282, 0x3e09bccb, 0xa1d7ca17, 0x79fe7409, 0x8ac77650, 0xec2adc2b, - 0x7c625fed, 0x751da409, 0xfb4646ac, 0x1f92758d, 0x60e75437, 0xb7c4639b, - 0x9f86abe4, 0xfe0de04a, 0x8f3c6ce4, 0x842fe3e1, 0xbc6609a6, 0xa938cdb5, - 0x0789e98c, 0x74df7bfc, 0xe14df51e, 0xc23df68b, 0x35b3ab77, 0xfc862f37, - 0x6fc05db8, 0xc82ffee6, 0xf36979ff, 0xefd21b06, 0xcb3675a5, 0x2aa96af9, - 0x6cb1b1ec, 0xe66bce2c, 0x0b3ba77e, 0xf65072f1, 0xb0673c61, 0x88168cf9, - 0x0d182e71, 0xfd1fec4f, 0x9d555be9, 0xdab76bf8, 0xbae11f30, 0x430723fb, - 0x56977a3b, 0x9e6b1a53, 0x9e7cec03, 0xedc3590b, 0xfdffd263, 0xc3a93be0, - 0xf68c9915, 0x7e131d67, 0x63fa688f, 0xb767c744, 0xafee30b0, 0x5ca2af68, - 0x68cf5b38, 0xdc90077f, 0xf037768f, 0x7eccf7fb, 0xb69b8b9c, 0x82f512ff, - 0xc749668a, 0xa50a8623, 0x6d3f4355, 0xc65129b0, 0x6bc3387d, 0xa3eabbc4, - 0xc5f137af, 0xf8215556, 0xfbb0981e, 0xe3f71c66, 0x9ea18d36, 0xd3b17fe2, - 0xc7f8fb83, 0x07c499cd, 0x57ebadbd, 0xa9aaec55, 0x972a3748, 0x30f4d187, - 0x92ce3eaa, 0xf40e4cbf, 0x699afe47, 0x8be25d6f, 0x6befbf81, 0xbc173892, - 0xfe16f940, 0xbdbe4cff, 0x80b7c869, 0xa3e2679c, 0xf90f5abe, 0xbe4b1a96, - 0xa9bc962d, 0x7bc5f708, 0x5e22a686, 0x26aabf17, 0xdb6f92c7, 0xe739f8aa, - 0xb94e2233, 0xdbe411a3, 0xadf24db7, 0x8c5be411, 0x5fbf9078, 0xff0b7ca8, - 0x36dff0d7, 0xd6316f94, 0xf9566bab, 0x08f9a636, 0x8d31b7c9, 0xaf3c4b36, - 0x7c9f3b5d, 0x47af9293, 0xeaa0f8fd, 0x3f418f8b, 0xfe3e84db, 0xc44b888c, - 0xe5ce5071, 0x7f8d3a6a, 0xe2ee72a1, 0xff73950b, 0xe4367045, 0x8c1de2dc, - 0xd27b9ce2, 0x8b739721, 0x939c8177, 0x9cb91e90, 0x7187bc5b, 0x7c945cbf, - 0xbe43d91b, 0x115faa31, 0x4d83ede1, 0x02df0fe9, 0xabf58dfd, 0x1fd4073e, - 0xc6ef2ddb, 0xae5de599, 0x7adc10a6, 0x1783bbc8, 0x0876ef26, 0x6c720779, - 0x68d7ca08, 0x5b35f0fa, 0x8f77c1e3, 0x2bff5e3f, 0xcadf97e4, 0x86f8de74, - 0xbd0f9f8d, 0x1678fe36, 0x6263d7d2, 0xdc848b3e, 0x510aaf6b, 0xe45e53ff, - 0xf1772beb, 0x468af138, 0xd4561fae, 0xfc2f614b, 0x17c27733, 0x78bfce1a, - 0x2152c48f, 0xebcecb3f, 0xf38d27b3, 0xc3233632, 0x720b0f44, 0xbfcfc94a, - 0xf40e6140, 0x72ba97e3, 0x5bfea24f, 0xfefdc39a, 0xf17be2a5, 0xd0abadab, - 0x88fc5dff, 0x46a5e744, 0xe711ab7c, 0xa26e23db, 0x77f91979, 0x6627e3a3, - 0x99a9b88a, 0x1bc294bf, 0x947fc462, 0x7fe6b16e, 0x966ff822, 0x62f04adc, - 0xe331cbaf, 0x5d7a8c38, 0xe0283a70, 0x7ed32754, 0x802705da, 0x27bd379b, - 0x33d3009c, 0xe1ba5232, 0x585bfc52, 0xebef566f, 0xbd16e035, 0x5d7fc36e, - 0x0de9fa2a, 0x7b9c060e, 0x1dc05fac, 0x939202ec, 0xa758f0d1, 0x33b5f975, - 0xe8094e31, 0xe84ce486, 0x181700d7, 0x70d26f2f, 0x47977dcb, 0xd664fd05, - 0xe1829a4c, 0xae30b30c, 0x6a0bca1c, 0x0fdcbd17, 0x1dee31e0, 0x4edc58ef, - 0x0f609b2f, 0x56ec39e0, 0x41c92767, 0x35db0e83, 0x141c07ae, 0xbfddddf0, - 0xf9d93272, 0x7a8e924d, 0x24e23048, 0xae0106b8, 0xa828ff78, 0x8106fc70, - 0x0eff911e, 0x8719f23c, 0x8bc91ee3, 0x635c9dfe, 0x40bc42bf, 0x8e66ccfd, - 0x22586097, 0x4eb164bc, 0xa8a97f3a, 0x84117c95, 0x8206d35f, 0xe19f219f, - 0x93c665cf, 0x58957e89, 0x4c954bf4, 0xa8a965fb, 0xf35ed337, 0x99e7a407, - 0x036caa4f, 0xfbfe1b81, 0x4f3e7a2a, 0x9e34501c, 0xb6bc04da, 0x085d3c21, - 0x77ae4eb7, 0xfba0be45, 0x50794650, 0x39e05909, 0x5f73d1e5, 0x0671af09, - 0x518e90bc, 0xcbe735be, 0x92682f98, 0x9ef4df58, 0x50f3c5eb, 0xef17bf33, - 0x7ffbc239, 0x18b1f24c, 0xba60beeb, 0x8b9e85ee, 0xbcf16e80, 0x8eba37a4, - 0xd23b5386, 0xe9bab7f3, 0xe76735f9, 0xe7a44ca1, 0x43f7123d, 0xce5a2734, - 0x1e763d35, 0x09d5b5f7, 0xeeeb0f74, 0x6df5557c, 0xcb90c6f4, 0x7ed1ee82, - 0xbb37df30, 0xf1821704, 0x141c5ba2, 0x18f347ef, 0xb353f5c2, 0x64e6de7c, - 0xf567d7c9, 0x2edbbfde, 0x37278cc5, 0x3f2323f4, 0xf8c3c71a, 0x6f1826f9, - 0xd178f764, 0x2fe183fb, 0xfabadf38, 0xbad9bfdb, 0x6ebe718c, 0xb590543c, - 0xb88d5e10, 0xe05223a8, 0x73ea2a47, 0xfc4b25d3, 0xc85ccc15, 0x7fdc6fad, - 0x7bdc96aa, 0xa74d2cff, 0xebb774fb, 0xe89d77c6, 0xe2674f33, 0xdbe26f7c, - 0xec7fefb8, 0x5998e7e7, 0x44d6f636, 0xab263fdc, 0xe3eae90c, 0xa1f92a43, - 0xe3ca9e3f, 0xedf9af6e, 0x3e5d0501, 0x3898f0d7, 0x8938cd76, 0xb037acec, - 0x87a8f1eb, 0x047f983b, 0xef132fc1, 0xd5d465ed, 0x5f02f14c, 0xae12dd8f, - 0xa537d4c6, 0xc435e933, 0x219924db, 0x7dfc5ade, 0x7f20b8a7, 0x032c87fb, - 0x1fa0a05d, 0x07b1fb50, 0x9bd63259, 0x33264fe0, 0x27e37c66, 0xf3075e6f, - 0xf6487f18, 0xacdea179, 0x03172e03, 0x7ae47a7d, 0xe0980b1b, 0xab858135, - 0xfe34dfd1, 0x9c3affa8, 0x3be81177, 0xa8a44f78, 0x07b54379, 0x6a25ebf3, - 0x72050c1f, 0x6d9eb03d, 0xbf7267b5, 0xea017285, 0xf5c13761, 0x4eb05ebc, - 0x728861f2, 0x8a5af341, 0x93a82a2f, 0xb6e142e8, 0xbc1cc4b0, 0xfa03b0df, - 0xda1eb6dd, 0x05fee167, 0xbadfb1ed, 0x875e6f33, 0x49e60772, 0xb9f9ebed, - 0xf3b4017c, 0x2dd4bf22, 0xd78afea2, 0xb3ef0c4b, 0x7df3d514, 0xea90e8a9, - 0x7dc6f2c3, 0x3b7ed08f, 0x97ebc603, 0x6450fb8e, 0xca0bdd2a, 0x2fba7494, - 0xf84c1a19, 0x7f1c60eb, 0xf220fa6c, 0xabbc520b, 0x98a0c097, 0x64fe63e3, - 0xb3f2421f, 0xeb4cb7c0, 0x96bcfd0b, 0x236e9c93, 0xe7433aba, 0xde0147ed, - 0x1bf78001, 0x40e55e22, 0xab5a07ce, 0xc2fc5f69, 0x9b9f943e, 0x38a24d34, - 0x8f2c858e, 0x8e6638e2, 0xebe6fae7, 0xe8c33b97, 0xed5d7be7, 0x0fdf881c, - 0xefa76e5c, 0x1cb8dbed, 0x4ad41f6e, 0xebe3f6fe, 0x58f78655, 0x24cbd7aa, - 0xabd78e2f, 0x7e563f74, 0x1431c78c, 0xc7fae36e, 0xdfbcf581, 0xe1b7a8e3, - 0x439607b9, 0x11ab70be, 0xb4e5c0e7, 0xe8167f61, 0x90c2fe3c, 0xdd62e5bb, - 0x75a1f63d, 0xd92434cb, 0x2e5b7968, 0x8b0971e4, 0x2d1cbd90, 0x1cf1cb77, - 0x197c83dd, 0xeae6271d, 0x0e9063b6, 0x5d105f22, 0x19521c57, 0x07d231da, - 0x9714b96d, 0x73a247b6, 0x92cdf18b, 0x8a1ae31f, 0x4987b1de, 0xcfe70eff, - 0x2fee11fb, 0x8619daef, 0x3c431f2c, 0xb1ca9c80, 0xa7e9fe77, 0x1be4fdf0, - 0x02088c0e, 0xb827c9ba, 0x59be711b, 0x4f3c799b, 0x52eb1bd6, 0x9b2f3ef0, - 0x40e497da, 0x02ccad61, 0x52713926, 0x13775ff2, 0xd4741fdf, 0x667c0c77, - 0xb8053569, 0xc1cb7ebf, 0x66ef55f7, 0xd8646315, 0x043d84ef, 0xf51f81f6, - 0x6b5de29b, 0x1d133453, 0x9b59ef14, 0x55f7c322, 0x1aa61e22, 0x576857f7, - 0x8a71f1ac, 0x06fa4af7, 0x3f4638d3, 0x2edabf46, 0x1ee86ede, 0x7fd6f69e, - 0xd68fce31, 0xf286a9f9, 0x1e9fba22, 0x4fd2f7e3, 0xadcfefce, 0x395e6093, - 0xac14cbaf, 0x8cc1f39e, 0x1d73e6a1, 0xcafc3523, 0x98da6fd9, 0x9cbf04df, - 0xbf31c53f, 0xe38ddf09, 0x7f01ef80, 0x61493757, 0x23f984a7, 0xe516795a, - 0x0af3e475, 0x98ae7fe1, 0x1aebcfca, 0x8158de33, 0x4b233f7c, 0xa1607a22, - 0x8937d680, 0xfa2f35f4, 0x78b30bfd, 0x8f6842fb, 0x08f8d8fc, 0x13904fe7, - 0x1523945e, 0x52e6d7eb, 0x8bc93afd, 0xc86e37fd, 0x28a47d27, 0x5e546647, - 0xa3f48477, 0x4923a6a2, 0xb7c0c7c8, 0xa81f50eb, 0x51d76898, 0x68fc1b8e, - 0xe2ebf7f0, 0xe8732b3e, 0xc67ef1a3, 0x8be646ff, 0x21f2d7c1, 0xf583d72e, - 0x39831f9c, 0xdf5f5f9c, 0x2f0ae2a6, 0x9f89bf84, 0xfce16f8f, 0x43763f2a, - 0x2f87de2e, 0xc3efccdc, 0x453f581f, 0x78fa7d43, 0xa6fda258, 0xbd737f27, - 0xabbf9a35, 0x7defbe25, 0xe0d2fd5d, 0xe18f836f, 0xaf1c6aef, 0xef14f80c, - 0xf5f3464f, 0x0fe1b54c, 0xaf7cc3b7, 0x03d61a79, 0xddf29df3, 0x26ad3d3b, - 0x14f90939, 0x3c2817cc, 0x2b90cb9e, 0xfb8f0ae5, 0x8bf3dafb, 0xb76c3f1a, - 0x677e47fa, 0xebf1e44f, 0xfdd12a75, 0x07b3f8f9, 0x7f205d9f, 0x9d5f285e, - 0xf18d3f8f, 0x7ed63de5, 0x2de8277e, 0x8076bfba, 0xfae0046b, 0x8a26fd4a, - 0xa9e8fdf3, 0x3f113323, 0xce81bba5, 0xddeabe91, 0x4e72822c, 0x557ed309, - 0x3dd328d2, 0xb244a601, 0xf99b73af, 0x956dc798, 0x7a26e33e, 0x1ed6792a, - 0x4bed019e, 0x86307e76, 0x779668e2, 0xe85a5c52, 0x872fa129, 0x1f20c75a, - 0x7e3c2894, 0x042e5a2c, 0xd70fdc1c, 0x367e2bb6, 0xc2da4fae, 0x69288fdf, - 0x9bb551b8, 0x746e25ce, 0x3a3d46a8, 0x1d010dd7, 0x9c5dfde3, 0x02ddf99f, - 0x6dac6e23, 0x2513972b, 0x81d92a4d, 0xb7b65b25, 0xc970fc63, 0x77f2763b, - 0xa19cb705, 0x9e5310fb, 0x94fe46d9, 0x396c9360, 0xb711eb7f, 0xd88e45b9, - 0xb1b0ee31, 0x211dce9c, 0x0df2847f, 0xcf97e3b1, 0xfa585f17, 0x219d9ecc, - 0xafe96100, 0x7ca0f49e, 0xd9b2d539, 0x7e877083, 0xba6e32bf, 0xc3669c47, - 0xa7195f3d, 0x01ff0a79, 0x438f738c, 0x9c4635d8, 0xa4be96eb, 0xb2fcc247, - 0x739c62f3, 0xdbe5e974, 0xef1c7d3e, 0x7b3db411, 0x6f9c71fa, 0x7e3e3fd9, - 0xd8c1e31c, 0x77ed275e, 0xa2dea7c1, 0xdda36c38, 0xb5dfb126, 0xe2927d6f, - 0xb5dfdbd7, 0xf6b7b0fb, 0x6307c73d, 0xf6fb603c, 0x6fd0522f, 0x34cf64b9, - 0xd92eebf2, 0xc5952531, 0x148c2fd8, 0x017c36e9, 0xf8d1f3f1, 0x8078d03a, - 0x023ed6e2, 0xebfca37c, 0x286dbb8a, 0x5ecc71e7, 0x1f5b6f11, 0x8f429efb, - 0xebc6daf8, 0xe51cb9ae, 0x1fd7237e, 0xfb671bcf, 0xdbf1e026, 0x7abf8017, - 0x1b102fc3, 0x3fe11f7f, 0xa2fb4f00, 0xe369f7f0, 0x8a3c5fc2, 0x7b7d8d65, - 0x5c8db38d, 0x7b8cdc00, 0xfc380f10, 0x88c91c87, 0x5c525fe7, 0x866de233, - 0x4f9ff717, 0x91fde307, 0x5ce76a13, 0xc7b85fba, 0x68bc63ae, 0x89b79ec9, - 0xbc77da7f, 0x26687e41, 0xb3b423ee, 0x3f1e3fae, 0xd675892e, 0xae7c79b9, - 0xefc63f80, 0x5df43d7a, 0x3a72e9c4, 0x7b77e236, 0x9d95db8b, 0xee36cf5c, - 0xfdd79467, 0x76c3c451, 0x41ca4be3, 0xcaf91d3c, 0x0e036878, 0xddc390ba, - 0xe3b1e871, 0x2beebba3, 0xfe217c08, 0x8aea1f70, 0xc0fc8733, 0x7a37e4b1, - 0x0790c59b, 0xfc781bed, 0xfb1abb7a, 0x9711b05e, 0x3e688ffe, 0x3c585f0d, - 0xffe6f9fa, 0x81d3e175, 0x4f724fca, 0x2dfdb538, 0x774f1cb6, 0x9eecdf4a, - 0x7d149961, 0x1cebca6f, 0x473b7187, 0xbb83b434, 0xdeb16cec, 0x6f57e136, - 0x78a64a7b, 0x070d55e5, 0xcb478e48, 0x2f7c0a8b, 0x337cc625, 0x9a2b7cc5, - 0xf6d13ef8, 0x82ec3bac, 0xeff6da7e, 0xa8ae7a22, 0xd2f1423f, 0x95f96f2f, - 0x8b8a6ad6, 0x6c227dc0, 0xd3db7f9a, 0xdc90c6fb, 0x44b2ef16, 0x8c49338f, - 0x3d8e6c13, 0x8cfeb04e, 0x50d29c65, 0xcebba683, 0xc529de3f, 0x77f6237f, - 0x83eb85aa, 0xe9e41aa7, 0x0fe318e1, 0x77d6aa73, 0xa4bf60a1, 0xfcdc67f7, - 0x13d919bd, 0x12e5fa47, 0x093bce77, 0x146a9849, 0x4cbd55af, 0x87fd77c4, - 0x5df10d2f, 0xe18abeed, 0x7c22577c, 0x551e7e4d, 0x4bd4300f, 0x2cbcb4d5, - 0xcb442bf4, 0xc6c92d1b, 0x2ffc26c2, 0xf54f4f71, 0x644779d2, 0x70f3e220, - 0xfb1571c6, 0x9f944bfd, 0x5b0a2fea, 0xfbf30a95, 0x2df2484b, 0xdfd97e83, - 0xe794183e, 0x977fd9ee, 0xd963f11e, 0xb0aa57e2, 0xbb461e77, 0xa4e0bd84, - 0xaf7906f8, 0x08f9de93, 0xf5a4ee3e, 0xf9f1d81e, 0xff5fa413, 0xb9f8cec2, - 0x202f580f, 0xde750aaf, 0x9f1df1c7, 0xd457fe3f, 0x8c31b19f, 0xd438f85f, - 0x3ea1bb47, 0x8e9cec9e, 0xa0c61367, 0x85f0a45f, 0x3ca266bb, 0xf4e78c2b, - 0x6a4cf858, 0x3bfa1ab8, 0xc7f3cc96, 0x77a20db6, 0x759f4a25, 0x81e8dc53, - 0xe055cf1d, 0x4cfed4be, 0xa97dc33c, 0xe7a105fd, 0x53bc52ff, 0xcd7aab55, - 0x4cc5e3f1, 0xf3ef9af1, 0x12de6294, 0x2fc8c4af, 0xfe847c41, 0xba04a6aa, - 0xaffa0407, 0xd48f9fa5, 0x447c3bce, 0xfcfea1c7, 0x3fa453fe, 0x7ae883ca, - 0xcebdf946, 0x395ee221, 0xd77573b4, 0x059d6a0f, 0x9fd35f3c, 0xaa1693cb, - 0xf853b0ff, 0xcf79458f, 0x87fd797e, 0xeeeefc84, 0x10afb787, 0xd344d0ef, - 0x6fd146ef, 0x5fbf96e9, 0x959deb1c, 0xefa7f318, 0xc858943f, 0x76ca7a86, - 0x857fbd27, 0x7de028ef, 0x3f1a9d85, 0x44f32ad7, 0xdd9b9de8, 0xc5971e42, - 0x9ddde845, 0x581e62fe, 0xd1ccf31f, 0x9fbd34fa, 0x61939cf6, 0x0bf9595c, - 0xbbe23f6e, 0xc7e7e77c, 0x71859e7e, 0x1714f189, 0xffc2fe5f, 0xb7283a22, - 0x3f22e647, 0xb3b76e74, 0xdbe7c88d, 0xfc8c1d5f, 0x0646a6da, 0xf38af9f7, - 0xbb06f2ba, 0x58bffef5, 0xdaaaa9c7, 0xbbbef0cb, 0xa4b6af71, 0x57f33917, - 0x5fa3d727, 0x725ffa71, 0xdf5bbf12, 0x35553a73, 0x59df133b, 0x3897ea30, - 0x77c5cb62, 0x137c5e51, 0x71eaee39, 0x9c5df53f, 0x25ac47cf, 0x153efd05, - 0x3ca377a0, 0x3e92d92f, 0xfb04fd10, 0x043bc69d, 0x8fdc04de, 0xb25eabf6, - 0xef3531a7, 0x7caa2733, 0xf430ca99, 0x54cc8cdf, 0x1b1d1d60, 0x67f414ce, - 0x9cea4718, 0x9dee4b1d, 0x3ad3c676, 0x98f61c4a, 0x09cf9df7, 0x8d0f7aba, - 0x1e3e64fe, 0xee3187f2, 0x724c357e, 0x2f388ef8, 0xbb012bd5, 0x6e97bf08, - 0x79699399, 0xa1a9457f, 0x04a7c07a, 0x4eb662cf, 0x6fc932cb, 0xa5e2bc63, - 0x264a9959, 0x4ffe577e, 0xddcabd17, 0x24a16678, 0x01150bd2, 0x9faeb663, - 0xa2887ee5, 0x7e1039e6, 0x15d3cb1a, 0x86a54919, 0x358e3df8, 0x7502ea50, - 0x5653bf8b, 0x9e4e50c9, 0xe8f6e710, 0x1bb4c2ef, 0xdc92775e, 0x6c620d0f, - 0x07be3a78, 0x4dd04de1, 0x10f153f0, 0x5763e61e, 0x1797192a, 0x93b47433, - 0x7d8050a5, 0x5d54f409, 0xe9133d35, 0x18fcfe11, 0x07a64907, 0xbfa3cfcc, - 0x41ea05fc, 0x3dfca740, 0x70b2efbf, 0xc3188035, 0x3aafc981, 0xe877f199, - 0xccc3bf56, 0x71a5c6f6, 0x68e77892, 0x1731c91f, 0x84ebfeeb, 0x94558a3c, - 0xff09d5b7, 0x4473c1c8, 0xa822ce97, 0x58bbc617, 0xd7521e24, 0x9994e528, - 0x90593dff, 0x3ea9d137, 0xcd1e5ad1, 0xa2d72017, 0xf8206dc6, 0x449fbf41, - 0x5449fbf5, 0x557c9fbf, 0x829c06bf, 0x7c3e8d8e, 0x556562a7, 0x1f1b809e, - 0x06e021cf, 0xef8919f0, 0x9c5b31e8, 0x13879c4f, 0x6cc4e35c, 0xf01f58ec, - 0x4e971e5a, 0x612fb978, 0x41c6276f, 0x865aa4b3, 0x890aef76, 0x97f0d3ef, - 0x63b532e7, 0xf0f883ba, 0xb94e311e, 0xc30af380, 0xbea3d53f, 0x1eaff493, - 0xd5bd9df5, 0xdf5d8b8f, 0xe27cdbdd, 0xb127cf63, 0xe26bfe97, 0x75fff663, - 0x0bc552e5, 0xe786bf6f, 0x49f25db6, 0xf55bd007, 0xd438f2cc, 0xfd8f1333, - 0x70be95a3, 0xd031d33d, 0xa438ef8a, 0xb8b7a06f, 0xd1efd661, 0x7d1bd274, - 0x40758be5, 0xe00fd5de, 0x7f189370, 0xf73f1d6a, 0xf70965be, 0xe87981d3, - 0x8b37fac7, 0x0a3937fa, 0xc470dfc9, 0xbabfdfc6, 0x91eb96a5, 0xa658fcb7, - 0xef1ee9f3, 0x803fe151, 0x2a5d6edf, 0xb1e92385, 0x7562d7de, 0x9e6e3f78, - 0xbdfa3f18, 0xe6f300aa, 0xbd6396ae, 0xd2e9c557, 0xfd1757b8, 0x9602c54e, - 0xb321de27, 0xd4eb3f7e, 0xcd67e4bb, 0x2c7deea8, 0x1ee816b4, 0x7ba04ff5, - 0xebc7973c, 0xe2171462, 0x485c78d1, 0x4f3a20cb, 0xd9dfe433, 0xdc04de91, - 0x307f99af, 0xeff3aeff, 0xa6f4af8b, 0x2a1def9a, 0xef2ce2e7, 0xbeab54f5, - 0xea6f9434, 0xc15fd039, 0x0dced654, 0x39535e61, 0xfcc4ade8, 0x7249be18, - 0xa3094d2a, 0x3cf4545c, 0xaf7a8856, 0xa8c3ef78, 0xd55d25af, 0x0ebe67a5, - 0x4b8e6fff, 0xbc5cbe26, 0xb6f74bd6, 0xdbcf8b3f, 0x7b24f489, 0x57017c72, - 0xed087a4f, 0xc6aeebe0, 0x5cf7a775, 0xf3e6b54f, 0x157dbe91, 0x6ffc8080, - 0x4fce073e, 0xf6df7bb6, 0xa37efce2, 0xf4bbf432, 0x44ef8f84, 0x86cfca18, - 0x887c5007, 0x0463309c, 0xbc46bf8e, 0x6ababa6f, 0xaa2ba524, 0xbc794898, - 0xaf2a8adc, 0xea447348, 0xaa74e917, 0x1a556f77, 0xf95557e5, 0xebe03528, - 0xfbd0d5f0, 0x7c618e93, 0xf02e877c, 0xf0136497, 0xe5fe900b, 0x73a4ab48, - 0x195ea745, 0xd8df77c1, 0x7077d840, 0xc10d7a59, 0xf919d357, 0xe53ea135, - 0x548798ed, 0xf8419dad, 0x564af452, 0xc56fe508, 0x5c228e07, 0x2d4bde9d, - 0xd3da5aef, 0x7fbd46c6, 0x836f051a, 0xb871b6de, 0x7a712fdf, 0xfdfb868b, - 0xe3178b6a, 0xb2bfee22, 0x82295deb, 0x1c43983b, 0xe7e6bfee, 0xdee13db4, - 0x09be7b32, 0xe9eceeee, 0x04fbf704, 0x7016ef9c, 0xa87816ad, 0x46acf016, - 0xa47e53b8, 0x3a44fbc8, 0xc47bd29d, 0x112bb7fb, 0x08ca901f, 0x7d878077, - 0x30c98854, 0xf179ba1e, 0x7412eecf, 0x1fc8dbab, 0xfcf2bb2a, 0x127b7708, - 0x05c3bb87, 0x06ba2078, 0x3cb17bb8, 0x5d54f044, 0x9f50ce1c, 0x15e441e3, - 0x7e267b84, 0xb800f8e7, 0x871f8df7, 0x058270f2, 0xe4d25ace, 0x23fb830b, - 0x124b7f7c, 0xbf0d1e7c, 0xafbf8d24, 0x6f77f06b, 0x88b571fa, 0xef16aeb7, - 0x511c2227, 0xe00879af, 0x4f0e34c3, 0xc8a47dfe, 0x164d28fb, 0xe0357ff6, - 0x161fcb01, 0x19c210fa, 0x73c51fd3, 0x56c93cfb, 0x38454fb9, 0xf2efe1f5, - 0x1b10a4b0, 0x6878cd98, 0x85a5fe2f, 0xc6f31798, 0x4ad7aff9, 0x44aeb23f, - 0x7de903bd, 0xdd6de918, 0xcf0daaab, 0x57a5e43f, 0xcb67ee59, 0x5e89fdb3, - 0x42407f82, 0xc13ee6bd, 0x5e916b87, 0x1edc7e68, 0xe0e8295e, 0xeefef16e, - 0xee7e823d, 0xa0fcfc17, 0x7e3e3741, 0x74cd643f, 0x9498c71e, 0x20ef1361, - 0x4e399846, 0xc0d7d130, 0xd9179834, 0xe94a5e36, 0x8ef64b9d, 0x7e36f89d, - 0x7d23f314, 0x6773be25, 0x9b43bf98, 0xa1f50fd7, 0xd9dde344, 0x39c4de89, - 0xa23d3174, 0x6520f788, 0xc4b64f6e, 0xdab5df7c, 0x7e81dfb7, 0x13e6de99, - 0xafa7f3ef, 0x6be2f184, 0xf54764dd, 0x59cde40d, 0x2d577908, 0xcb0c55d8, - 0xc1707cb9, 0xf44d0bbc, 0x5f8bdf11, 0x595d7547, 0xf64af480, 0xa93fa438, - 0xf844ea1d, 0xe8bdac02, 0xcd487abf, 0xc1fb87eb, 0xfdb18943, 0xb9e2b370, - 0x7593c4bf, 0xb09fc5a9, 0x3b53f54e, 0xde55a27d, 0x43fb13ac, 0xfe56a99f, - 0xcb83f630, 0xc59f7f44, 0x0f147e07, 0x6e729674, 0xa4cfc92a, 0x0fef636b, - 0xc216aad5, 0x47aa39f7, 0xe50ebe73, 0xee6f5c6b, 0x9d187721, 0x8c0d9c83, - 0x2ffe88d8, 0x3396be83, 0x8c42e72e, 0xbac693eb, 0x3ef4867e, 0x9d01f702, - 0x01f71ee8, 0x34c3cbcc, 0x5b949ba2, 0x587fe46c, 0x5eecf825, 0x046b5fc1, - 0x7c803d5f, 0x81df0235, 0x13fa51f6, 0x90eb4fc1, 0x12dd20ff, 0x78f5ce9f, - 0x6197bef1, 0x8c772cc7, 0xab1cf7a5, 0x0fda365d, 0x61ed7794, 0xfb05da17, - 0xf7e8ebc6, 0x7a59dd91, 0x59e58dc0, 0x43c03f0e, 0x91d2cc4a, 0x2f733e5e, - 0xe2abe8b8, 0xf4fd015b, 0x72a2b0ae, 0x949ea47f, 0x451fdec7, 0x9ef453a7, - 0xcb5faa80, 0x70fd3fd0, 0xe113a552, 0x8f3c70fc, 0xcfcdaad3, 0x3e03b826, - 0xe29bc5b6, 0x5f6752a5, 0x1f1ef5d5, 0x2f70ff76, 0x12ec12ef, 0x0c0d82f2, - 0xf92661b1, 0x7bde2b50, 0x1b10de64, 0xcb139269, 0xf432e787, 0x0f94f5eb, - 0xcdcbc8bd, 0x90ae5e5c, 0x434bcb62, 0x65e4377f, 0xd2315cb4, 0xb74d1795, - 0x5d54a7dc, 0x66f2463e, 0xc1ff6c64, 0xfcede3ef, 0xf3e66a1d, 0x2cf7a7e5, - 0xdefd7807, 0x83d42f0c, 0xf7c57f0c, 0x5a27ac62, 0xcab89e3e, 0xf40357d8, - 0xcd02d03e, 0xaff8f0fb, 0xfbad57dc, 0xd5b9e141, 0x9c140fa4, 0xa8b4a1cb, - 0x11f13a76, 0x9318d3c3, 0xfd7c7c9d, 0xdf883d0f, 0x7ce2b5e3, 0xc61abd7c, - 0x1b7da4b8, 0x0e607aef, 0xe3c175c0, 0xe38f9d32, 0x14d90d3d, 0xbcb2c2df, - 0xef1ba7a4, 0xdf0f1e23, 0x31c731ee, 0xe9d4fc14, 0x37bffd47, 0x1f582c7a, - 0x8d537fdb, 0x83bb44ff, 0x5da246f9, 0x675dfa01, 0x9fbff504, 0x18dde938, - 0x18da1f23, 0x8fc733ef, 0xf15be918, 0xdc21ced3, 0x33f78adf, 0xab9dd217, - 0xf4d79d0f, 0xdc7c17ce, 0xc733e863, 0x4547d273, 0x7dc0359c, 0xca7fc596, - 0x098f49cf, 0xf473187f, 0xca271e52, 0x7b94bdbd, 0xd3133c78, 0xd3ff9763, - 0x3d51a47e, 0xb821b4ec, 0xd3daf2fe, 0x2fa5deab, 0x6280f3d6, 0x60bdc711, - 0x79787c63, 0x2059be0c, 0x102f07ee, 0x7d065de7, 0xd0df7f15, 0x465d39b3, - 0xd4f4add3, 0x1fa74425, 0x5fc9541f, 0x87f4015b, 0xd4f4987a, 0x698f7a78, - 0x3d9713d9, 0xf9c00b78, 0x95324393, 0x10739d97, 0x87ffb65d, 0x3bfce28f, - 0xefd2ab7f, 0x70727c26, 0xb7ebc51a, 0xbb9ef78b, 0xedc5cef8, 0x5c5c1bda, - 0xbb9c14ae, 0x8bbbe897, 0x35f3c2ae, 0x7382dbe4, 0x565e900f, 0x4ebdef80, - 0x788f75c0, 0xe8229279, 0x1fb60277, 0xea1cbb92, 0x3e72b615, 0x15431361, - 0x10de8fe4, 0x0637bbef, 0xf2e0df3f, 0x0b45e25a, 0xff50d75b, 0x24c3f40c, - 0x02c85c53, 0x8507fbf1, 0xe584b878, 0x21a5887a, 0xd6f908df, 0x77d6ff4d, - 0xd69ddbb0, 0xc2e91a75, 0xb04e75ae, 0xebdd61d8, 0x73e72efc, 0xb6146fa1, - 0x7579f0e6, 0xe3e7e7ad, 0x7ba7ad63, 0x7da9131d, 0xf1ec627b, 0x1fe317ef, - 0x9bc22aab, 0xbc44ac5b, 0xbe105bb7, 0xd5f7c35d, 0xf627d60a, 0x2aeb4c91, - 0xc4b52dac, 0xe6d4152b, 0x857afbd3, 0xdbb5f3eb, 0x1753fb4c, 0x97fe425e, - 0xc6eb0d27, 0x2e6bfdcb, 0xaea8bc23, 0x7e913bbc, 0x7c553d8f, 0xec5e7bc7, - 0x84e9e397, 0x49531a16, 0x4f76eaf2, 0xf74dfbac, 0x56a9e347, 0x80ec09e0, - 0x0c9e132c, 0x3fb744fc, 0x8efcb9b6, 0xe21cf0f7, 0x509afe11, 0x0a2bf2ef, - 0xe1b1e97f, 0xd7a0a4f7, 0x040fa063, 0xdf7e082e, 0xf5cbc4b2, 0x6f813f0a, - 0x77c63e03, 0x08c2e7d0, 0x379127b7, 0x4e3fb193, 0x5b83e70f, 0x1e82f8f7, - 0xcf5ec526, 0x59eb5d6b, 0xc7a042ca, 0x3eb8d49c, 0xee7afbd1, 0x05c72162, - 0x4f8ba7ac, 0xfa7c2df3, 0x385b9ada, 0x9ffc0a9f, 0xd10f7fdc, 0xbc70b1f5, - 0x7a54e30f, 0x486bcf5b, 0xd062e307, 0x1b10b0c1, 0x8f7ffd95, 0xfe684e0e, - 0x3ee08f11, 0xee15fb02, 0xde4fc5d3, 0xbf3cc63f, 0xfd27e2b7, 0x9aa5f69e, - 0x0ea73b0b, 0xf41df64d, 0xfb277ed2, 0x434961aa, 0x633f815d, 0xa3cf12fb, - 0x6e9fa19f, 0xc6cfe245, 0x578bd2c4, 0xc72e0556, 0xaaea8bf3, 0x8fd1cba2, - 0x973d0aaa, 0xce9b9ea1, 0xd623177f, 0xcdcc7d7b, 0xaab2bbf1, 0x983fce92, - 0x94f4c423, 0xd80077ee, 0x47f24c89, 0x7eab2e2b, 0x1d01a9a6, 0x789adffd, - 0x025540a7, 0xd0b3d3ab, 0x1194945f, 0x1fefc132, 0xb2ee7e2e, 0x8ebf6d26, - 0xe8761ae7, 0x8e60fd1f, 0x8b59ca81, 0x6545ecff, 0x93c05f41, 0x1c731cf1, - 0x124bf06b, 0x46cf13f9, 0x5acf13f9, 0xf30491e6, 0x5b3b0afe, 0x1ce87871, - 0x8fc26152, 0x5f01e02c, 0x5bbb1f68, 0x1e5cebe7, 0x607d21ef, 0xb23645d5, - 0xff09d6eb, 0x2fd0cff4, 0xe851704d, 0xe0c301bc, 0xc096beb0, 0x73c4e1d7, - 0xaded190c, 0xf8dde508, 0x4f4c9762, 0x4f984a1f, 0xf3095e64, 0x1564597d, - 0x931d0fda, 0x3f20ef5a, 0xe69033a0, 0xd67ebc06, 0x84b0e5af, 0x817912e7, - 0xb5ce118b, 0x0bc32872, 0x77217ff5, 0xc1bd6066, 0x1f4ef450, 0xf7845e9e, - 0xf3a60212, 0x8eb421ce, 0x33dcbcee, 0x2552d17f, 0x6feffcea, 0x5fcb9b17, - 0xc62ffa71, 0xf93b5479, 0x1f4960fb, 0x57be7448, 0x94ee75dd, 0x64f2fb47, - 0xd123c737, 0x41d5d205, 0x559d37ae, 0xc87d09bc, 0xf3323d9f, 0x7c3ccb45, - 0xec22bc96, 0x53a03ad1, 0xe832a73c, 0xb7e29863, 0xaf0d1d21, 0x3c66ef81, - 0xfb77d0c6, 0xf079e8b8, 0x31b9fa98, 0xe897183f, 0xcb973e55, 0x7a28e3f7, - 0xf9f12dd8, 0xdced8a87, 0x1921646e, 0x20c73af1, 0xcf05653c, 0x8fe33227, - 0x8d77b5ec, 0x82b62773, 0x0b9e75e7, 0xb9cfc6de, 0xa733e7a3, 0x3c16eef9, - 0xdcd399ef, 0x7b9e3e6f, 0xf8ba29ce, 0xab774c43, 0x51e3fb9d, 0x2250fc5e, - 0xb7a6f67d, 0x21e3545e, 0x46e6f1dd, 0xae609f7a, 0x73bfef9b, 0xf88aa759, - 0xe35d300f, 0x5a6156e7, 0x27cc6ddf, 0xfa2a0df2, 0x84896e1d, 0x721ab86f, - 0xbe18beb7, 0xb9bdd51a, 0x425f3b07, 0xf41a05b4, 0x321b3a5c, 0x5ef935da, - 0xaede79e6, 0xf14e0e0b, 0x838a47fb, 0x6ebdd5d6, 0x58c1c107, 0x7c24d427, - 0xbc49c174, 0xa5c066cf, 0x37f1dd6b, 0xf8fe855f, 0x1cdce4de, 0x790fe8c7, - 0x579f3c9c, 0xc13e9c34, 0x0b939022, 0xb91ffedd, 0xb77afca1, 0xcb4c2eff, - 0x95839d1c, 0x5537c421, 0x0390af98, 0x1c00a517, 0xb8141a3e, 0xd1e11938, - 0xf482f7d2, 0x2e4ec3fe, 0x1ba70e0f, 0x1bab6d7a, 0xc8bd9be9, 0xf7e35af5, - 0x38ed5632, 0x008dff7e, 0xe55e8f9f, 0xcb95cdef, 0x22ee6bde, 0x62ccb2ff, - 0x7a4621d9, 0x1e0df858, 0x7bc4db76, 0xf39d7cd1, 0x79ef0e14, 0xcf74f18d, - 0xd952de6e, 0xbcfdbef2, 0x957e3ca5, 0xae632d29, 0x2b09d8b7, 0xecf75d04, - 0xd11afd07, 0x3a5fccfd, 0xd92dde99, 0xc893e9a9, 0xa738f1cf, 0xfd53f9b3, - 0x4ffdc632, 0x1f912d58, 0x6f51fc69, 0xe7e42b53, 0xc87d1387, 0x5ceff3ae, - 0x97ef899c, 0x3f70b454, 0x28bcaa67, 0x7d203fe3, 0xefdf3f68, 0xe108bf31, - 0x5d7bf2e4, 0x369af3a6, 0x474332b5, 0xe5d5be7a, 0x7f907947, 0xc45dffbd, - 0x30e7e1a7, 0x40e7ddf6, 0xce38c00f, 0x39bc5bfc, 0x0df91f48, 0x0ea53f4e, - 0x5c81c4a6, 0x039857cb, 0x298d54d3, 0x98e34c4e, 0xe5ecd303, 0x9daa7f42, - 0x2783fa45, 0xf7c34f27, 0x9f9bf3c4, 0x17db14fc, 0x927d912a, 0x9bf29e89, - 0xee82fd5f, 0x28f3f9c3, 0x5b5bf74e, 0x39dd8b34, 0xff9ac1ba, 0x9f359376, - 0x33e6b111, 0x03f35a0f, 0x7d266d70, 0x1e1eff73, 0x9a7a529f, 0x1e7defdf, - 0x3c22a060, 0x3e49d9b6, 0xce6d294e, 0xd38778c6, 0x586dbb4f, 0xdceffbbe, - 0xeadceeee, 0xf72577a4, 0xe2c717bd, 0x6a1df092, 0x3f2c46e7, 0x8d90d71d, - 0x4fa845fe, 0xbbb04b71, 0x71bb408e, 0xbd06a5e7, 0x69be2986, 0xfdf83fe7, - 0xf6adce94, 0x9c51c630, 0xd3e4f5de, 0xb7a79f48, 0xec7d200e, 0xc3642979, - 0x70f7437e, 0xf3884ffc, 0xe954e458, 0x7e3dab16, 0x1d01e842, 0xe879b527, - 0xd6b8ba17, 0xc24beeba, 0xa8a77cd6, 0x7d331b7f, 0x10f8c74f, 0xdc34aaef, - 0x7ec53767, 0xc173fdbf, 0xa53d4f17, 0x8b2b7419, 0x37991ef7, 0xe2befba5, - 0xdb73eeee, 0x8e800325, 0x4316114a, 0x4697bfba, 0x0f85db8d, 0x38927fd1, - 0xadfceb2f, 0x5539f04c, 0xef896455, 0xaafbd2e8, 0x4d53697c, 0xed4151fb, - 0xd27c94be, 0xdca5f757, 0xca67da66, 0xb9481eb6, 0xdb6bfa19, 0xebefd0a2, - 0xe279cd95, 0xf8490981, 0xf9c06e5d, 0xe7fa3962, 0xf25e1ada, 0x8bd03d60, - 0xbde39ac7, 0xa5c76b0a, 0xe9f1354d, 0x834ba5d7, 0x0e74ca9f, 0x5a72e79f, - 0x461ef172, 0x1dff2d69, 0x1b86d2be, 0xe11abbae, 0x4fdf9ebe, 0x9e5856cf, - 0xb653fc0c, 0x8fef86fd, 0xc7c1ef86, 0x3e70f9c6, 0x2d24f8d9, 0x3fadbbde, - 0xee76f743, 0x44ff71b5, 0x7b465c34, 0xfdef7e38, 0xe508ab81, 0xa2f7f412, - 0x3fb52c6d, 0xe47d0368, 0x6bd0e4c4, 0xd3954337, 0x570fe1ac, 0x95965c53, - 0x253e809e, 0x373ab7d4, 0xf48dbe4b, 0xb5f67975, 0x97fb5aa8, 0x943a3c51, - 0x8a37b4c7, 0xa27ed6c3, 0x47a57cf1, 0x68f77e32, 0xa25e99a4, 0x119df5eb, - 0x2ab7dfa2, 0xcd720a5b, 0x1d97efa4, 0xd878a1ad, 0x19c871e8, 0xc13b8a68, - 0x7c4bd1fd, 0x027a14ec, 0x22d91c93, 0xcf287c5e, 0x48a7bbd3, 0xa5104097, - 0x5ea9b297, 0x6cb5eb84, 0x4bcfa63a, 0x99640791, 0x33f203cb, 0x79278b6d, - 0x3eb7a6d0, 0xa3a473f1, 0x1e74d1fa, 0xefdc5fd6, 0xe846f36e, 0x77e358bd, - 0x9e74da71, 0x5276692f, 0x8fe9d53c, 0xcb979234, 0xeb138e30, 0xd9b4ed3f, - 0xbd3b5f40, 0x8c64efbd, 0xe06b6e0b, 0x6a9f8aef, 0xfb593be8, 0x9a37fd8a, - 0xf17d8def, 0xdf13fe08, 0x8bf8f54f, 0xacdfb83d, 0xa9d371e0, 0x2a332b7d, - 0x68c9e063, 0x6655a497, 0x79d2bda0, 0x91b7cbab, 0x0ae953eb, 0xc8d3ddf9, - 0xfc2f92af, 0x79e9f749, 0xbea07877, 0xe1faea1b, 0xe5073eff, 0xfc77e88d, - 0xa1ddf640, 0x1f3eed0f, 0xa015905f, 0x03f4e3fb, 0x7cfe3036, 0xa0144585, - 0xafb8f9b7, 0xc93ca18c, 0x25ebf9cf, 0xb05c238a, 0x7c1ebac6, 0x1fbcdae7, - 0x292fe116, 0xb0b8c50e, 0xd68b4a06, 0x718bcb5b, 0xbc50f0ff, 0x94cbc517, - 0x19cb59d4, 0xad1f908b, 0x7b4bfeac, 0xca7db82c, 0x6bf9f58c, 0xa3b9163c, - 0x50f9dc92, 0x95f5a3ce, 0xd20037a2, 0x1cfec49b, 0x6d2733bc, 0x4b1da401, - 0xc82da427, 0x7cee7bc4, 0x8ed3231f, 0x8fbf98f8, 0x45953a57, 0x7177f106, - 0xa58fee18, 0x346452cd, 0xe42c1de6, 0xe3bfcb19, 0x6eb820fb, 0x63313df3, - 0xf35eb8dd, 0xc726f677, 0x10cf71ab, 0x2f2e6bd7, 0xab287013, 0x3afc5bb7, - 0x90a5ea13, 0x7f78dbfb, 0x55da95a9, 0xb7697e34, 0x5ff62bf4, 0x1399b7d8, - 0x68a135f0, 0x798b8c83, 0x878e4ba8, 0x0f75892f, 0xdf80b0e5, 0xf4143743, - 0x107d7e43, 0x02fecff5, 0x9f2439c0, 0x45809f84, 0x5c5e301c, 0xca9e5766, - 0xfcf397b3, 0x8ae04f3e, 0xaf6081da, 0x873a01a9, 0xbde72f9a, 0x471bf78c, - 0x425e0626, 0xf9b7ccbc, 0xb7c42b07, 0x17e411fe, 0xf0e1ca5d, 0x4bcad8f0, - 0xc5d9632a, 0x933fbf02, 0x3e5ce81a, 0xa3ef8bb4, 0xd54eacee, 0x8bfef7ec, - 0xfb094790, 0x4f5ee95b, 0xee890ee7, 0x1d223f13, 0x8fb6fba1, 0x6865e95c, - 0x9e01a7c7, 0x223eee50, 0x5ef815b1, 0xace3565e, 0x9e212f45, 0x787ce2b3, - 0x38de5fde, 0xd1772e49, 0x15beb9fa, 0xcf01b95f, 0x8de75283, 0x0e748b1c, - 0x2d779eeb, 0xe3d0ff7c, 0xb9faf1a5, 0x96d3de38, 0x8f17d287, 0x16f3f1c2, - 0x387c84bd, 0xa1ee8e3a, 0xdcac02a7, 0x8d5d287d, 0xcb1a547a, 0x60fa87d8, - 0x58ef0cda, 0xe43fb9f4, 0xdb24e3e1, 0x50b379e4, 0xf3cb1bcf, 0xf92c7e7d, - 0xae111237, 0xed5271a5, 0x17ce3a6c, 0xe85ea3bf, 0xcb823f40, 0x9529ef84, - 0xea7e3819, 0x69269e50, 0x3c0f8a11, 0x99bde064, 0xd12de9c7, 0x25e9c919, - 0x454a4c5f, 0x1b50ee3b, 0xbf20d418, 0xec340d0e, 0xf48b88cc, 0x792361f0, - 0x2df7617d, 0x5ff7e0c9, 0xfa1b0692, 0xa1d7af0f, 0x513213fa, 0xf5c1beae, - 0x7e5c4ff1, 0xa65f57f2, 0x4fbf8ec5, 0x0a78e048, 0x61638b9e, 0x3838ff93, - 0x13d233fb, 0x2c3ce783, 0xf027da6c, 0x1c734dbd, 0x7ed15977, 0x72841dfa, - 0x01f742d6, 0x71ac1bca, 0xc5c597e7, 0xf3a0d71e, 0x0b1b39e0, 0x1e3225f5, - 0x21d7f688, 0xc2d573a9, 0x4b17ba24, 0x73c13be7, 0xc6990b1a, 0x63eb9e0f, - 0x33cd77cd, 0xaee9fa85, 0x9af5acc7, 0x2c7aa73e, 0xe383d5a7, 0xb4adebb4, - 0x29cf048f, 0x6fd8ced4, 0x90b6c23a, 0xeedcfc0a, 0xe21de5e5, 0x6fa8cf3c, - 0x5b3ed7f4, 0xf8def713, 0x556de8bb, 0x2e007820, 0x219f368f, 0xf359747f, - 0x418b823e, 0x89f0dd0f, 0x7c132167, 0x225baa52, 0x69ede036, 0x7bb86e0f, - 0xc990d814, 0x871f05fb, 0x9feddd36, 0xbbf8e508, 0x8ebe260f, 0x73e2eacf, - 0xd90f3312, 0x42172e64, 0x9d4f7775, 0xfa8bca68, 0x9b43ed5d, 0x340a98af, - 0xb78a3595, 0x27c1e6bf, 0x4e4e595e, 0xdf111a8b, 0xcf3839df, 0xa23bca6d, - 0x8fc82ef2, 0xa8f5e536, 0xf2a8a4f2, 0x40fca8b4, 0x1dcdbf5e, 0x40fb2c19, - 0xd4f83fde, 0x9efbf815, 0x7322fd6d, 0x358f05f1, 0xf02bb6f2, 0xb3cb7cf7, - 0x56d3eff8, 0xc93e4b34, 0xba2b3f24, 0xb55bf3ce, 0x0e10a3f9, 0x1ca32f2d, - 0x74926b28, 0x0d5debd4, 0xc79423db, 0xbb535e76, 0x963f6e06, 0x76a11c35, - 0xd23ff6bd, 0xef7c7c46, 0xdea9f7c8, 0xd89fcef9, 0x5befeb0c, 0x751e76f5, - 0x4e2c0a44, 0x7f7eee48, 0xdbfb6dbd, 0x0a2fbfdd, 0xf9fbdbdf, 0x8d1c900f, - 0xc41e07ba, 0xf9bab8f9, 0xbde380c4, 0x7bd2cf23, 0xdd1c7fb4, 0x03aa16fc, - 0x2cce4bf1, 0x9fdda053, 0x438f8fcb, 0xb4df0b7d, 0x67e37dc5, 0xdc12f852, - 0x81651e8f, 0x5bdc704b, 0xc3ef87cb, 0xac384c9f, 0xef863eb6, 0xf0786f95, - 0x98142be5, 0xeb7761df, 0xb709fc20, 0xf06f094d, 0x7f2b727c, 0x1dff4551, - 0xa0f0e7e1, 0xc83641d6, 0xa6c0993f, 0xeb787e53, 0x3d7f9863, 0x3faf04e1, - 0xac9075ba, 0xf27209a3, 0xdf90a98a, 0xf7e6c7ac, 0x37ae04da, 0x369bf31b, - 0x8453ffdc, 0xfbe32b0b, 0x76335e0d, 0x5b9d3c80, 0x66db6a72, 0x1fdcc780, - 0xdb9c93c5, 0x55dd76dc, 0x50870479, 0xa611c61e, 0x7ed3780a, 0x215d7248, - 0xee1fa27d, 0xf1ba7d81, 0xe2dc1ee9, 0xd2e2fda5, 0x37a8edca, 0x451dcea4, - 0xc7a145fb, 0xddc9e92f, 0x52193869, 0x3ae92fa8, 0x8db2eb97, 0xef5223e2, - 0xf51e9372, 0x033df8a0, 0x0fa23be0, 0x36cbc097, 0x096d9eb1, 0x80f6bfdc, - 0xf3f51a67, 0xc47fe49e, 0x42ca6321, 0xc5a7f24e, 0xf372be91, 0x202b9006, - 0x7989d7d7, 0x097b5baf, 0x466e29f9, 0xfc28f13f, 0x67d7efee, 0xbffeb754, - 0xaef2032e, 0xdd6ebb6e, 0xf33f7f2c, 0x0dbaf6b9, 0x5b90dcbc, 0x7b79d2eb, - 0xad4abf63, 0x3ea4e3e6, 0x5c46c978, 0x28c2bc47, 0xece17b7e, 0xd1971b11, - 0xad2d7ffe, 0xfdfdf99f, 0x5a3f0ed0, 0x7a86c43c, 0xc29f81a9, 0x1257fee1, - 0x89373d60, 0xf035efdf, 0xb74f8c64, 0x907f51e2, 0x3b407f41, 0xeb403135, - 0x0c627d07, 0xfae06e0f, 0x3316d204, 0xad2997c1, 0xfffbf0e3, 0xfdb53820, - 0x4ff4e02b, 0xc947779f, 0x0c379021, 0x7a5f2ffb, 0xedff72dc, 0x23d1013f, - 0x8000702a, 0x00008000, 0x00088b1f, 0x00000000, 0x7dc5ff00, 0xd554780b, - 0x733ef0b5, 0x9992bcce, 0x924c2664, 0x84e3c849, 0x71100840, 0xf0444312, - 0x51888431, 0xd4503b69, 0x20717ad8, 0x9926023c, 0x4b62d5a8, 0x79120cff, - 0x22341809, 0x0281c150, 0x06f55bc5, 0x701a8c45, 0xaf7a8a44, 0xb7ad8ef6, - 0xff7f6c57, 0x4a8f8808, 0xd2f5a232, 0x5ad7fd97, 0xce64ef7b, 0xb6b4a924, - 0xdc3ef9bd, 0xd9cfb3ee, 0xd7b5ed7b, 0xf6b5af6b, 0x4cf5a61e, 0xd8c05c0a, - 0xce6a2566, 0x7c2c64ae, 0x61edf148, 0x67cf07f0, 0xf7fb193b, 0x95d5a0b4, - 0xf19fd8c9, 0xe6c60aef, 0x2729bf7e, 0x8ded0658, 0x61cb1823, 0xcfbbf52c, - 0xd500ded4, 0x7a3f4bb9, 0x3f7c0f7c, 0x8ca97bf7, 0x43ef03e9, 0xf7c18c8f, - 0x5b6dbcef, 0xd2842ecf, 0x793519d2, 0xf986bca0, 0xef7bc056, 0x27435898, - 0xbe0ef7f4, 0x5563097a, 0x35e5bbdf, 0xdbb19136, 0x93632a5d, 0xf8ab5b18, - 0x258a9873, 0xbbe0db0b, 0x644b2cf0, 0x7d63114f, 0x0cd85311, 0x23b875fd, - 0xb8c1175b, 0xf995d71d, 0x1f5fd0c2, 0xef867e63, 0xf7a54b2d, 0x4c3ddc3a, - 0x744bf6c3, 0x0ec24017, 0x19faa17e, 0x5a37e3d4, 0x7814bb22, 0x76c2ce5e, - 0x3e325f6c, 0xf3fa8612, 0x7f7d0e30, 0x0f644a63, 0x8f82cfb6, 0xa371dea0, - 0xfe861237, 0x47622cec, 0xfa763a78, 0x8c1c3273, 0x05acaae5, 0x8228efe1, - 0x2b59943a, 0x0701cdd9, 0x713fcfe2, 0x0f007396, 0x6899775f, 0x3d95a93e, - 0xf437ff4f, 0x7ddbd6c7, 0xe1b0a063, 0xcf6f58ab, 0x3b997826, 0x66f88558, - 0xb803fc1a, 0x89c81fea, 0xcce7c3ac, 0xb1eb8557, 0x479fe9da, 0x5520fff0, - 0xb61ff847, 0x0ab635b3, 0x66d61528, 0x0bfc00cb, 0x43fb5878, 0x37630c00, - 0x978000e3, 0xd670d7ff, 0x2bf3c3a9, 0x07ad0a5d, 0x556df9fc, 0xbc67cd8c, - 0xd4f2fe7d, 0x58899577, 0x1a6b51aa, 0xa5735b3c, 0xef46c7bf, 0xe28f3fb1, - 0x0bfa0da5, 0x25b7f132, 0x09ba44ee, 0xd86977e2, 0xba9defff, 0xfdf0eb03, - 0xf8765c44, 0xfbe074be, 0xf9a3173a, 0xfc3955cf, 0x475535ac, 0xc8fc4afc, - 0xd7c24eb2, 0x713f90fe, 0x724e393c, 0xfcbaf7bf, 0x00be2237, 0x0f74d1ef, - 0x75a545e2, 0x63d7864d, 0x43b06f89, 0xd556dcfb, 0x33e0377d, 0xf349ccb8, - 0x9cdef095, 0x158cbf1d, 0x74ffee0f, 0x8695736a, 0xe9c65ff3, 0x02b72d9d, - 0x62f112e2, 0x5d03a819, 0x63f1642c, 0xe7886526, 0x8445f45a, 0xc247517f, - 0x2fdff4f7, 0x49ef89ac, 0x92ba617e, 0x2ba0bf04, 0xdd70d15d, 0x375f0a82, - 0x373e258b, 0x6e183650, 0x82d5cf89, 0x245d24ee, 0xe2357be3, 0x7c60d27b, - 0xf93d2c7b, 0x99706fd8, 0xdc94f095, 0xfa11633f, 0xf03b21ee, 0x16ddd00f, - 0xdd7a2145, 0x646a5772, 0x3da7f225, 0x19f117be, 0xad157c3a, 0x1492ef77, - 0xdb2bc19d, 0x9441302c, 0x9c9d8733, 0x4a7a4b8f, 0x617a9f90, 0x9f587ece, - 0x9dd5d7de, 0xc1024561, 0xeaebf358, 0xdeffa42e, 0xfde6af67, 0x19d548ac, - 0x618843d4, 0xfe143718, 0xbc032b43, 0x2cc5349e, 0xe0175e34, 0xff09c257, - 0x435fe17a, 0xe8bc80c5, 0xbf1c06c3, 0x9807cb8b, 0xe71a12e1, 0x1d6c29db, - 0x526cdb8c, 0x6f6826fc, 0xb23e3a5e, 0x4361c392, 0x20146a3e, 0x9b589b35, - 0xf7c03152, 0x2513a6cd, 0x36f195b7, 0x85bbde0d, 0xf78175f1, 0x5f002a8e, - 0x4c7d6da3, 0xfa45ba45, 0xd8a5f687, 0xff80345e, 0xf9bff5e6, 0x7cdfc213, - 0x8d1748c0, 0xb1e7198f, 0x8a9e9134, 0xb524e806, 0xd589e392, 0x8018c8b0, - 0xa9ea29d7, 0x8a88b1b5, 0xcd565a78, 0x66e9024e, 0x8199e91e, 0xecace3f4, - 0x0ca1f364, 0x11fcc07d, 0xf74a7b80, 0xc24697ce, 0x58daeefb, 0xb4374e3e, - 0x4e8bb6ec, 0xbeb0345d, 0xba4bce12, 0x41cca937, 0x0077d1e3, 0x83bf7f8a, - 0xfb371bde, 0x6ef2c482, 0xa4d32efa, 0xe0f6bd12, 0xcd1be423, 0x38c0a39f, - 0x328c979b, 0x82a67ae1, 0xbcb9437c, 0xaeec7db0, 0x7f678415, 0x07b7ca09, - 0x09ce80d3, 0x942abe9f, 0xeaeea52f, 0xbfa0bb5f, 0xffd5dca7, 0x138e258d, - 0x47f4e270, 0xa648be90, 0x23bd64e7, 0x6e2ecbdf, 0x0c716f29, 0x17f01eff, - 0x35be2de1, 0x4d0fcb9d, 0xffa2faa1, 0x475cef30, 0x374469f0, 0x222f6db7, - 0xdac0dc79, 0x591ade89, 0xbbf482c4, 0x69c2c6c8, 0xe08b1740, 0x172874b5, - 0x3d32b16f, 0x4496fd61, 0x2146f58c, 0x31616e0f, 0x7d96fefa, 0x2c35ed49, - 0x26f684ea, 0x62a68b1b, 0x6f6c69d9, 0xef417166, 0x3e26b67f, 0xbe7c1d67, - 0x77758b37, 0x20d444d7, 0x1dab7bcc, 0xbe065774, 0x33eb4ed0, 0x5a4ef965, - 0x7f0af4cf, 0x4fa83dd1, 0x76fb355e, 0x27bedd01, 0xe7e24bd6, 0xbbf5575e, - 0xd514f788, 0xdf8ff344, 0x9cfc2563, 0xeb8dbd02, 0xdd9b9f7f, 0xdeca1b3c, - 0x7a3bdd56, 0x55c9a234, 0x1839db30, 0xb39eebcf, 0xb8dd2037, 0xb7c226dd, - 0x65cc7e7c, 0xddd57aa6, 0x522bff02, 0x088abb23, 0x9e9113dd, 0x7d4946aa, - 0x82ce26ca, 0x5666bbfa, 0xe6f509d7, 0xec411deb, 0x07ed07af, 0xb9b817a8, - 0x5b7028de, 0x2eb27e68, 0x06e92be7, 0x52fea1c6, 0x84a5e22e, 0xc85b8c63, - 0x7f89b641, 0xe6eff427, 0x493b2925, 0xafd3f6ff, 0x96fd1189, 0xd7882c05, - 0x795c84e7, 0x3695ca4e, 0x9a2b972b, 0xa832ee6b, 0x9941f73f, 0x95e01d6f, - 0x83de8295, 0x4a3f1bef, 0x5e9e91d1, 0xef5fe8f9, 0x9fb419fd, 0x5ba2c0fd, - 0xd2017da1, 0x73dbac18, 0x6047970a, 0x8fd4307f, 0x38f6c08d, 0xb1c1e36e, - 0xb41c7f64, 0xc846fb08, 0xe0b4c6cf, 0x4fd085d6, 0x3e9993e3, 0xbcf664a0, - 0x5ee8f239, 0xf7643f6c, 0x1b7e81ed, 0x1b5e3853, 0xdf491b9f, 0x4e0f613f, - 0x733cc377, 0x3c9f91ad, 0x05e37281, 0x677bd92b, 0xc2117459, 0xaed3b67f, - 0x70277be0, 0x4250e95e, 0xeaf3829b, 0x043d9276, 0x10b39a7c, 0x36b93bbe, - 0xe04bcf9b, 0x0986e4e9, 0xcd9b17c4, 0xb3f0bc7c, 0xc27fbd0a, 0x0391981c, - 0x974f13f5, 0x534056fb, 0xb512c05f, 0xee873d00, 0xbd5e76e3, 0x7881df49, - 0x09538762, 0xa11eb95e, 0x62678b8d, 0xf2e9687b, 0x1c7ca3af, 0xde51cf8e, - 0xd9b904b3, 0xc805e2cb, 0x461adb4f, 0x9f514675, 0x91f38f74, 0x585e655a, - 0x171ba07c, 0x9994f77f, 0xc87e35e3, 0xbe7cf44c, 0xb57ce3fd, 0x707fae2a, - 0x65c8109c, 0xe48ff926, 0x1d5d4272, 0xfec8ceaa, 0x2d973d0c, 0xfb633aec, - 0x1de0ceeb, 0xe6bfa06e, 0x9de7fffb, 0x38df8465, 0x9ed645c9, 0xca797c49, - 0x748b9fec, 0x5a89aeeb, 0xf3e827e6, 0xeaaf820d, 0x63fec2ad, 0x1f224b51, - 0x6aaaf6ca, 0x72cbdd23, 0x677fa0bd, 0xc1f7cb8c, 0x1fc126ed, 0x1ea2b4df, - 0x6641c29b, 0x1c47a885, 0xfd4ebfd8, 0x6a20f94f, 0xe17a87a9, 0x9165a8f2, - 0x004f9128, 0xcc1b51df, 0x2756d4fb, 0x03406fe7, 0x3268b3f6, 0x48b97d23, - 0x02b5fb05, 0x3d5deb9f, 0x9fa72eb0, 0xfafa7376, 0xf0056023, 0xf7898f3d, - 0x82ef60ac, 0x4da67b1c, 0x607ee289, 0x2eeb16de, 0xb5f2117b, 0x7ae2755f, - 0x8e48576e, 0x569b6bcd, 0x4bea15b2, 0xeb405c0f, 0xd399369f, 0x9b88d2e5, - 0x2114e2f4, 0x11adeb1f, 0x3fdfd90b, 0x01f21851, 0x74764ff4, 0x53947c23, - 0x280f1831, 0x10f40dd7, 0x5d83a849, 0xcb93a534, 0x9cf20655, 0x524bd825, - 0x671ca3de, 0x919ff649, 0x1f52c23e, 0xf4c7b971, 0x527b946c, 0x0aebdf2e, - 0xae49b974, 0xf5c6ce8d, 0x72e4f585, 0x7842bf73, 0xa42d626d, 0xe81ea44f, - 0x91e8571f, 0xeb986ad3, 0x2a26eb2b, 0xd117775f, 0x27594b78, 0x57a913e9, - 0xd783a386, 0x7e0e84bf, 0xed007486, 0xe8b01f8d, 0xe35e3065, 0x9a6d1672, - 0x44e74bc8, 0x4f5c8fd2, 0xc49eb8da, 0xf43ce532, 0x4c7eb265, 0x7ac987d6, - 0xf5c2db30, 0x69675c9d, 0xe74f64cf, 0xe594c076, 0xfcc19511, 0x3ff9a636, - 0x60349cce, 0xb2de84d7, 0xb10bf4d9, 0xe0a3601e, 0xd369c5bd, 0xf686ca6e, - 0xc8fcc690, 0x9780a957, 0xbb7cf09d, 0xb36b7bb0, 0x2d7bdd39, 0x5acd7e9c, - 0x703b9580, 0xcfb4625d, 0x1732678d, 0xe7c4a3d2, 0x577c2776, 0xfd71df81, - 0x8dbdffd4, 0x7c24a5b5, 0x9d9cfd5f, 0xcfe7eae4, 0xb256233a, 0x6e858247, - 0x57eb2fe8, 0x7b53b256, 0x3e92739f, 0xd0fa15ed, 0xd128f683, 0x5fae2acb, - 0x21275d71, 0x648f5535, 0x35cafb48, 0x4a045123, 0xcdc9acfb, 0xf6c1aced, - 0x8a2f6890, 0xcae9cf5d, 0xcfccfb4a, 0x62773ddd, 0x6861e01d, 0x588fff9f, - 0xe981d0e7, 0xe787dfe5, 0xc7c380a1, 0x472c1fb1, 0xdfaab57a, 0xf406deb9, - 0x1e5d4335, 0xd1e60bbf, 0xa170ef94, 0xfc29ab9e, 0x846f2ff5, 0xcc0787fa, - 0xbceb8acc, 0x1b1d7a67, 0x5dfcbc35, 0xe89f3112, 0x5b97e049, 0x4deb19f6, - 0xa87ac69d, 0xc82f58cb, 0x4f4e7a70, 0xfbe1d920, 0xd5b5d033, 0x4ec1f2da, - 0xbcfad780, 0xa7d1f495, 0x067160ee, 0xfc535bca, 0x5ad9e218, 0xf444f1f8, - 0x3fba846f, 0x02b4b051, 0x38cac4ed, 0x3faf91fe, 0x742bcfb7, 0x01b7810d, - 0x899b31fc, 0x3ad60cf0, 0x85ce492f, 0x2c789f04, 0x845f0ffe, 0x9d9a2ff9, - 0x9e9bbae2, 0xaa4e67f8, 0x60927b42, 0x572da164, 0x2dfb887f, 0xae096f78, - 0xf059e9ff, 0xb0d5c01e, 0x46c3eb85, 0xbe434b16, 0xd3bb066d, 0x477c4b06, - 0x5b875f06, 0x5155e2da, 0x8c8edff8, 0xa70871da, 0x802d27f6, 0xfb1ab1f4, - 0xaf93b04d, 0xe07ae0cd, 0xd7767d96, 0xdd1e0329, 0x2ba87a86, 0x912a75c7, - 0x61fc84ff, 0xb8968a79, 0x09577a1f, 0x6bf88b5e, 0xa658f5b2, 0xfc57f8c1, - 0xf79233e9, 0xa7cd978b, 0x5d80c47d, 0xb4f9256d, 0x3d20aef8, 0xdf2b697f, - 0x6ade9e17, 0xa7ef11d7, 0xe3fdf3b7, 0xc4473ce2, 0x857bff06, 0x8bdbdb9b, - 0x19453be1, 0xbc64c78c, 0x55f0ffbd, 0xf7a3a45e, 0xdc2f1f19, 0xf78fedc9, - 0x62af805d, 0xf7f60efe, 0xefd8177e, 0xaaf9e20a, 0x2e2e510f, 0xd0faaede, - 0x9c87604e, 0xbc598fe4, 0x0b71cafd, 0xa7dfd81d, 0x5fa1a623, 0xe895c768, - 0x02f7c289, 0x89d7ee11, 0xb5cf015d, 0x1d93171d, 0x95bb7477, 0xedb6e9c3, - 0xf15c79c5, 0x4af89527, 0xda20b133, 0xff161dc7, 0xfd67e438, 0x70333de1, - 0x959fde5d, 0x1ff7a26b, 0xf10b9857, 0x85965ee1, 0x5a2b17cf, 0x61b7f900, - 0x899992cb, 0x866a4ef6, 0xad35eb4a, 0x8f567970, 0x7ae9f883, 0xdb4da3d4, - 0xfc707f81, 0xf2ff6fd9, 0x3f224f46, 0x4cc55edd, 0xc3cbf609, 0xc27a235f, - 0x6be028bf, 0x57d7c0b1, 0xaa6b2be5, 0x12968be4, 0xef8ba394, 0x0d71296e, - 0xf3f45761, 0x0f9cc3c5, 0xb850cbef, 0xc32f20ff, 0x6e18cfb0, 0x3528e65f, - 0xf9b15e91, 0x940f7f98, 0xc62db0d9, 0x0c81f7fd, 0x640fda8d, 0xfb5f7b70, - 0x5efb6ddd, 0xcd4d7987, 0x80cf6e08, 0x97f3217a, 0x71ebbae3, 0xb1983557, - 0xbbb26288, 0x6e56c3d8, 0x8edc6ac7, 0xf6c99cde, 0x8fd84bae, 0x997f6277, - 0x62f61724, 0xffc7bd3f, 0xdaf10c78, 0x44f1f05c, 0xe7420fb4, 0x1fa0b33e, - 0x90add1cd, 0x02f8773c, 0xd425e90c, 0x282d8b3d, 0x21c3901b, 0xc913d71f, - 0x0653faf3, 0x3c84efdf, 0xfde7ea71, 0x3b7f9c11, 0xb73e9cdc, 0x3f214b2d, - 0xc44f36e4, 0xb5ff408e, 0xa5ed2a7c, 0x67efc225, 0x5f94fddb, 0x288efa45, - 0xd75831ae, 0x35f47f39, 0x30a88dcc, 0x8bbb87ce, 0x77d9dfc9, 0x854f9a60, - 0x1feec736, 0x788519ad, 0xf0fb32ea, 0x27af877d, 0xe1f7e70d, 0x386993ee, - 0x2add86bf, 0xf221bbcd, 0xb2c2d649, 0x33f0b901, 0xca3af825, 0x1c52e601, - 0x0f94be38, 0x34feee1f, 0xfb83816b, 0x567f480b, 0xa7978d0e, 0x8e7ed3dc, - 0x39715fdf, 0x1e8f975f, 0xee5046b7, 0xfd07647d, 0x3f6f2096, 0x777d7272, - 0xefee432a, 0xdf500b3a, 0x2a6fd7f4, 0xf89ca135, 0xdfcf8b8e, 0x402ce963, - 0x628dfc7e, 0x1ae967ec, 0x6c808b13, 0x5006b25f, 0xa3e8f203, 0x40299f47, - 0x9ee1ff79, 0x27e60a67, 0x9dfc97c0, 0x78e57b2c, 0xfd266fc2, 0x344b1ea8, - 0xef9bc70f, 0xe57f72b3, 0xf9547e30, 0xfdc2db3e, 0xab3e7da1, 0xbf28748e, - 0xf1486beb, 0xc7db7da3, 0xe6ff246c, 0xacbf0b77, 0x83da3fdf, 0x7df918fb, - 0x1e15ff52, 0x974a4f4e, 0xd483fe42, 0xe3c938b2, 0x7bde59bf, 0xe4133d60, - 0xbff3ac3d, 0xd9345f21, 0x3246c7e2, 0xe20b0fa2, 0xd0ecd2cd, 0xad653f50, - 0xbf15f4e4, 0x2afb44c3, 0x81d7ae4b, 0x928aecf2, 0x30133694, 0x6d2527a2, - 0xf201c622, 0xfde94b73, 0xfba73570, 0x7f231670, 0x516b0e5b, 0xb8bb5e48, - 0x326f3edf, 0xea83ad73, 0x9edc11ac, 0x16df32f1, 0x5dd698b5, 0xc490ff41, - 0x480bd487, 0x3f1f283f, 0x3f446c52, 0x7642b74a, 0x9cea6aa7, 0x470efd8b, - 0xc847134f, 0xa7a73ffd, 0x893ffafe, 0x188f269e, 0x3a829e8e, 0x36d793d1, - 0x3f093d34, 0xcfbf79f1, 0xbfdc01c2, 0xdd7c0b66, 0xfc4ee427, 0x9bf49b0e, - 0x99df382b, 0x3699bfa2, 0xfd455447, 0x9c7f33e1, 0x187dffe8, 0x27dc5fec, - 0x0efda0e5, 0xf395c8e5, 0x16375a74, 0x417f41eb, 0xd236c5ea, 0x629af78f, - 0x64af6845, 0x8fd96f8f, 0xb73d9174, 0xed2562ac, 0xa8dcf2ff, 0x92b7500f, - 0x7559741f, 0x0488d4e0, 0xdf10e17b, 0xe5df34cf, 0xbbd3e7a7, 0x1a107db9, - 0x387b216d, 0x7184a5d4, 0x96039b9d, 0x6b41da08, 0x095fee15, 0x3cebb06f, - 0xa0afa3ee, 0x740fcfb8, 0x488a171e, 0x8ecf6fff, 0x35bd23ef, 0x91efc838, - 0xf83a3f1c, 0x1fc7ca85, 0x8efc68c3, 0xeaaf1e72, 0xfee75ab8, 0x1d7eb115, - 0x6e39fcb3, 0x18d607b4, 0x85c659f9, 0x18809cfa, 0x7afe6f18, 0xae43ad3b, - 0xd2ccf1ca, 0x0cff5c6d, 0x67e40b96, 0x162c9ace, 0xfa6fc446, 0x05241cf9, - 0xbb4573d6, 0xcb39378c, 0x79684502, 0xb7e9bbbf, 0xbd00a4af, 0x8e9fa166, - 0x68c2ca6f, 0x987f93f7, 0xfc7dc9d7, 0xc90009a0, 0x5cffd6c5, 0x42697357, - 0xf03fbc5d, 0x6b6bdcfd, 0xf6ef48f2, 0xa0d823b7, 0x6fdd658f, 0x351e31d7, - 0xbd81aed0, 0xf852eb6b, 0xb5c761f7, 0x3c068e57, 0xfffc7228, 0x7f47eb5c, - 0xc6199da1, 0x4b4f844b, 0xfd0cdfea, 0x7ef9743b, 0x784af6bc, 0x590ac1e1, - 0x1fad66bf, 0x6ccfbbe0, 0x2a508fec, 0x1c8ac7be, 0x6dacd6ef, 0x0de7d6eb, - 0x276005d8, 0x39911aec, 0x7eac1f60, 0x85fb667b, 0xebaa5630, 0x5dea0b53, - 0x1e43e7a9, 0x648fec85, 0xe4203d7e, 0x572cdfc3, 0xf47641f5, 0x57241181, - 0x4b20667b, 0xe483fec2, 0x80796876, 0xf6073da1, 0xdbc21748, 0xd3e3fc7b, - 0xef7b422f, 0x1b1fdfec, 0xb77be3a9, 0x37bb45ce, 0xba234e74, 0x2353ed0d, - 0x4dadd00a, 0x71e80bf0, 0x7a480b8a, 0x7412ea5a, 0x8c330eea, 0x521c7473, - 0xbe898526, 0x83ae0a5a, 0xf8f7ccb5, 0xe438425f, 0xde7932be, 0xf7c11ebf, - 0xead2a10f, 0xffd825ad, 0x9da1856e, 0x44f4aeb0, 0x37da02d6, 0x30b59bbd, - 0x5d25bbe1, 0x973e120f, 0x890f33ec, 0xe08f5fc7, 0x67e6de71, 0xdca3f69f, - 0x90a228f8, 0x22d0684c, 0xbd40a76b, 0x9684c1a1, 0xcc8cab20, 0x1ce291bb, - 0x06361675, 0xed0477e6, 0xdf638426, 0x7053c337, 0x814ff0de, 0x8b02db47, - 0xab6e9f48, 0x4e2839b3, 0x56ff3a54, 0xc52b83c2, 0x5758788f, 0xe3839d5a, - 0xe19acf34, 0xd808f8a2, 0x7cded871, 0x2fc8b7d7, 0xd75ae124, 0x3b45ae65, - 0xb9ec0aa7, 0xfcee00a7, 0x7d6a6b8c, 0xd523c7c0, 0x3bb7e5fd, 0xb43e5e30, - 0x266eff1c, 0x25368ba7, 0x2546fe10, 0xa25941f9, 0x8bb0b35f, 0x8d9f8ddb, - 0x2be218b0, 0xf6e08d9f, 0xd8e1a5ec, 0xc39f2474, 0xda2a4f5a, 0xffe621d3, - 0x2ccff704, 0xd0f7d0e0, 0xe479713a, 0x3fc9d569, 0xdcf4f366, 0x5fb6217b, - 0x85fed1aa, 0xe00f3d69, 0x3d6bbdb8, 0xf04c75be, 0x2aefd601, 0xbd4f7da3, - 0x3278a827, 0x7d70bcf9, 0xaabd9f7b, 0xd288fd1c, 0xa8fb5aee, 0x5ae6f49d, - 0x2d7f7ea7, 0x69dfd3ca, 0x16c01f3c, 0x7e874d8f, 0x833efe96, 0x8f6b5dc6, - 0x0ff5c5ac, 0xbda954ef, 0x607411d8, 0xb9be4bbf, 0x2bd22265, 0x504a4473, - 0xed3d9a8f, 0xb618e90c, 0xb12fe42b, 0xe30c0279, 0xf3c3d3c4, 0x45f50534, - 0x1d333d92, 0x5fb455fd, 0xb6bf90f1, 0x18c7f05a, 0x36d382a0, 0x3fb68562, - 0x6fb0188f, 0x1ce3f95e, 0xbb4a1f0d, 0xfee364c7, 0x14ba9af3, 0x5b2df686, - 0x42663f15, 0xc627bd7f, 0xea6e0ed0, 0xa69c6854, 0xb82d27d2, 0x93a5b96f, - 0xec4877f3, 0x057f0033, 0xf18c5768, 0xa07b0aa4, 0x5839fb8d, 0xc448d8ec, - 0x3d7c63f3, 0x12f78319, 0xad8cabfc, 0xf440f2e0, 0x86711167, 0x0257e126, - 0x3eed484d, 0xef5bb48f, 0xf3b7fd16, 0x59bb8c52, 0xc455f989, 0xf062b96b, - 0x2af2cb87, 0x91fa7df1, 0xdfe40cf8, 0xfa17d038, 0xb32ab697, 0xcc29fd6e, - 0xf1a4eb6f, 0xbcc1343e, 0x056a4e40, 0x0452073e, 0x7d7657bc, 0x86e90332, - 0xd7e232d5, 0x6a69aee6, 0x6fc78393, 0x4ec85ed0, 0xed89d96d, 0x929737d9, - 0xc8f8c67e, 0x35fe786c, 0x1cb3e70f, 0x79d7f707, 0x61170eef, 0x48fd33bc, - 0xe29fd6e0, 0x90a417f8, 0xd61b35bf, 0xe54199c6, 0x796ff41a, 0xa88bf959, - 0xf533bd7f, 0xc647840a, 0x382e30f5, 0x38e48cab, 0x8a7c33d5, 0x3794177f, - 0x0e34dc78, 0x116aefec, 0x711e7c5e, 0xd119c40c, 0x62e3876f, 0xdecb0f1c, - 0x7e46a89c, 0x7be7d07e, 0xacbb4e90, 0xccd7c42e, 0x42df97ae, 0xc6d33b7d, - 0x9aee293a, 0xd3c4b764, 0x3a4419be, 0x7a733bed, 0xd7083dc7, 0x947d0775, - 0x8f6492cf, 0xb739715c, 0x93da3fcb, 0xec3f23aa, 0xec1b7212, 0x797f1e47, - 0x9323ef9c, 0xf6efc8ed, 0x23b72faf, 0x777febfb, 0x17c3923b, 0x28f3c3de, - 0x890f7ca4, 0xc35f5f7d, 0x5fd434d9, 0xaed23d2b, 0xd8f7ca4d, 0xba3df22d, - 0xd0f7ce87, 0x0ff8f276, 0xee494186, 0xae222dba, 0x43cef7e5, 0x84bb87ff, - 0x7b2bc0e4, 0x3748c353, 0x64ed3b67, 0x4b6e6997, 0x7b6ae114, 0x3cc11ada, - 0xe0453688, 0x578890eb, 0x2c1c4459, 0x834744a3, 0x4025a0e2, 0xa4fc3f72, - 0xd2abc799, 0x85ee8f22, 0x1ce1e37a, 0xd462cf11, 0x54d9f87f, 0x8a6377c2, - 0x37fd8e9e, 0x8608fbfe, 0x183eaa71, 0x09f9d70f, 0x87bb707b, 0x7fbc5ae2, - 0xe75582f6, 0x8968b3f1, 0x33b0f01b, 0x93bfedc2, 0x05a8a6a5, 0x8993bde6, - 0x32f59f3c, 0xd9e7c5ae, 0x8f2461b7, 0x8231a0cb, 0xdcb5b2fb, 0xe32f545f, - 0x1fb98755, 0xa5c45eae, 0xf45ece4e, 0xb458a608, 0xb8b52d29, 0xdd7cfb4f, - 0xdf9ff234, 0x2a2cff79, 0xfd18d7eb, 0x3fd08bfd, 0x3f103c5f, 0xf9f77e96, - 0xf6e167cc, 0xd0ff80f3, 0xbe8cf604, 0xfd46ab46, 0x775cc459, 0xc3d03ea3, - 0x43177ab0, 0x1a2506d9, 0x19600af1, 0x7ad6d3de, 0x57bd7052, 0x6f4899b7, - 0x7e4cdb85, 0xcbd24f7c, 0x67ae1eab, 0xbd70f5df, 0xe08ea803, 0x336cb238, - 0xe883788b, 0x4533056f, 0xbc2934b1, 0x6ad2ed5c, 0xb2dfd287, 0x8b7336bf, - 0xcdda1a6d, 0x77f226f9, 0xd7f16e7f, 0xa338bf91, 0xcda9d684, 0x96a6b2d9, - 0x7d2f13b7, 0xa8078f6e, 0x1b8d32fd, 0x40cf4c96, 0x8782fa79, 0xf19217c7, - 0x58ddb0b6, 0x2cc38e4f, 0xf5eb1889, 0xa736382c, 0x120dc798, 0xf420bf9f, - 0x8aebe7c4, 0x167dbe04, 0xfe72bb94, 0xde38f22b, 0x1cbcf94c, 0x875d5f95, - 0xe30a3074, 0x725845ca, 0x84cc2abf, 0x99751fe0, 0x48fa2147, 0xcdcdb782, - 0x96bc29e9, 0x5aff21fb, 0xfee193f8, 0xf82593d0, 0xb8c5efd8, 0x42cbbd65, - 0xf5f3e871, 0x1a64a497, 0xf5fdb7f7, 0x96feffbf, 0xaad7e7ef, 0x45c6bf22, - 0x8bbe6972, 0xe2a4e5cf, 0xe7c51bdb, 0x701fb00e, 0x0ad56b1e, 0xbfd32394, - 0x3479a0e9, 0x8239061f, 0x3de5ac71, 0x9bd7a805, 0x304a7bab, 0x5f8c935e, - 0xf2935684, 0xef9bde0c, 0xda08fd81, 0xf18c6b0d, 0x55f1c1b8, 0x2666617f, - 0xee4e7bee, 0xd7f5197f, 0x2fe93b7e, 0xad17bff8, 0x16cfffc8, 0x388b5c91, - 0x2e316383, 0xee894a14, 0xda1171f8, 0x6a8edc31, 0x44eeb6ea, 0x5b7e713b, - 0xff0f7c42, 0xef18deb3, 0xc8326b63, 0x8c3aceef, 0x4e1e1bcf, 0xfc506efa, - 0x65d69daf, 0x0e3825b3, 0x10f41df9, 0x599c1de5, 0xbeb86262, 0x116faaf5, - 0x7633a92a, 0xc67e7da3, 0x466bd7c9, 0x3e3fd4a6, 0xebfabfb2, 0x57d9d683, - 0x6f5ceb82, 0x7ec4c162, 0x619d709a, 0x3ac51b7d, 0xe2fa799f, 0x8fe75c12, - 0x825c5ff7, 0xdcd9bceb, 0x29be47ee, 0x41af0775, 0x32ba9cfc, 0xe615f640, - 0x9d1f20ef, 0x94de3d2f, 0xfd378f44, 0x2eb1e8e3, 0x59321f31, 0xe3f4363f, - 0x3d1fa8cb, 0xe50f3d16, 0xf59b7cc1, 0xfc49ea2f, 0x679fd21b, 0xe3ff92b3, - 0xdd3f1ff0, 0xdd18f948, 0xb227d92a, 0xb05ac3bf, 0xc3a3ed18, 0x617d796f, - 0xd3fef865, 0xb5e5fd85, 0x59fa30b1, 0xda40bee4, 0x78f2c997, 0x03cf98b9, - 0x8cdffe99, 0x3ce21bf8, 0x20dc7fd2, 0x3e45b1de, 0x6eef76e5, 0xc7fdc7c5, - 0x6e4fe49d, 0x85cf343e, 0x220fe2fe, 0xfcdc7fdc, 0x8ff93974, 0x8a5e4497, - 0xeb193e62, 0x1fb85c56, 0xddfbb259, 0x9003cc34, 0xe7d85efb, 0xf9499fde, - 0xeffdc635, 0x69939107, 0x70003798, 0xa7708fbf, 0xa416e27a, 0xffd866fb, - 0xb360de61, 0xfd863f16, 0xd9187b36, 0xc65d9505, 0xef8ca0fd, 0x48580b6e, - 0x56eb6eee, 0xb3af2822, 0x3ca2c12c, 0xcf2c6bd4, 0x80753a75, 0xfe9922cf, - 0x077e9017, 0x5dfeeae2, 0xa7fe9758, 0x44e9ad9e, 0xe6663dbf, 0xdb3ca177, - 0x4cf214ea, 0xdbf6f923, 0x7591dd87, 0x6fc37609, 0x584edc23, 0x34c1f322, - 0xbd60d516, 0x1ff1cd16, 0x7946f5c7, 0xf7924d1f, 0xaf197589, 0x494585bf, - 0x9eb1352f, 0xc4b0bcfe, 0xf9e392f7, 0xf4370718, 0x75ca5ac3, 0xe4dd93f4, - 0xab9c51f0, 0x6356cfeb, 0x9bef987b, 0x55961f81, 0x5cafd00c, 0xcdbf4907, - 0x6a1d1fc2, 0xe90ab138, 0xb8a5d437, 0xe8dd7f70, 0x08dbf4e3, 0x9bcc2ffb, - 0xd677e64d, 0x1d13cc69, 0xdd7fff8e, 0xff9c77cf, 0x9cac3d7f, 0x5bf8c7fa, - 0x3f97efdf, 0xfce5ef9c, 0x7fbeffa5, 0xe70add9e, 0x2579a4cb, 0xfd935bef, - 0x79df72ee, 0x8bf0f2be, 0xf17c7c24, 0x70c7c60f, 0x6b2530f2, 0x7242fde8, - 0x96afe35c, 0xf8e0ff87, 0x1e8723c6, 0xa881334a, 0xf6145258, 0x6fcebb72, - 0x50cf1788, 0x371e7e1d, 0x453e7955, 0x9f5ddc72, 0x9ceee221, 0x5a7a5f9f, - 0x126af5a5, 0x43a6e1f1, 0xdabe1f4e, 0xf14c58e0, 0xe9f8e4d9, 0x067fb652, - 0x1c72512e, 0xb8f911b5, 0xa9e3cbf8, 0x3d396517, 0x56749f24, 0xc90a7984, - 0x392f5a79, 0x4c111d3e, 0x32eaef58, 0x410c08d8, 0xcc2d36d7, 0x4f9e1232, - 0xf4f6e2cb, 0xc89f224b, 0x05e7e16b, 0xfaa673ee, 0x35e31f71, 0x7ca77cf1, - 0xd67a604f, 0x02ef9424, 0xc0decf9f, 0x4797804c, 0x4f249dcc, 0x1f0e4dc2, - 0xc7e93fca, 0x10effd91, 0xa5f38b71, 0x19676ff3, 0xfebfbce9, 0x85fbe24f, - 0xdaffbe92, 0xc016ddb8, 0x181f818d, 0x186befd1, 0x4c1a2a67, 0x33f5c3b7, - 0xcb2efd1c, 0x459edc0a, 0xa44ff178, 0x94f3e6fc, 0xf195a92f, 0x622fe893, - 0xfa3aac07, 0xfce26d37, 0x239f5b0b, 0xaabeebf6, 0xcd979459, 0x73c88fcf, - 0x8fd9c336, 0x9ff9fb1b, 0xf5fd8fdb, 0xc8fd93bf, 0x9c7681dc, 0x7e69a9e7, - 0xed5ffbca, 0x5f71f804, 0xc875a8f8, 0xdcf22cf3, 0x5df997c5, 0xcdc3f6f6, - 0xb0ef6ae9, 0xe563ff70, 0x34ff93e7, 0x34fbf9f9, 0xdf0ea3f4, 0x7be4584f, - 0x9e22fcc6, 0xf82576c6, 0x9e3143b7, 0x8092f7af, 0x447f3e57, 0x6cf4c5e8, - 0xa75c51ff, 0x6cdb8f8f, 0x9e4c1d2c, 0x9b172e4a, 0x2f8a0e03, 0xbcf27734, - 0x8ce5e697, 0xfa3377e4, 0xafd0cb4f, 0xbda18b38, 0xf8233537, 0xf57efc33, - 0x9ab08edb, 0xd9f77e8e, 0xdebbed0c, 0xa9febce3, 0x6c73f83b, 0xa1ef2d0f, - 0xecc74678, 0xaaef288f, 0xae9fcfea, 0x7824adaa, 0xb1e08fc9, 0x7cadcf1a, - 0x0fe3c591, 0xbf43fcb2, 0x5f93f13c, 0x9e06e3ff, 0xf8f21d9f, 0x908fe85d, - 0x3d54f17e, 0xe6a67e46, 0xab68dc03, 0xd87cf952, 0x9e88f3f7, 0x2b4c0f9a, - 0xeb29ff47, 0x9da397b4, 0x072bf55b, 0xbe3ef7ed, 0x24f2972b, 0x0fc13dea, - 0x2b3a3e51, 0x5da35723, 0xa0e3085a, 0xfef1fbbd, 0x6e11cbab, 0xa336ff29, - 0xdfc61cff, 0xc7fa34ec, 0xd9e78d99, 0x4f9bdd2f, 0x4762cbfb, 0x6fec53f0, - 0x11c39db3, 0xa3ce23de, 0x3279bf08, 0xcfbe4bff, 0x4e344d56, 0x146db7f6, - 0x6172972f, 0x6d0599b3, 0xe4f203c5, 0xf22e9678, 0x635e444c, 0xa79e2cf7, - 0x8f0eea22, 0x81f3bf31, 0x238f2bcc, 0xb4b3c73c, 0xe61f96af, 0x402f9418, - 0x187e62fd, 0x9c5805c5, 0xe7a92dfc, 0xca3d1db8, 0x727a2165, 0x9c51df02, - 0xed09e806, 0xb1e34bf9, 0x6b9e78e9, 0x52f44774, 0x73e1f3c4, 0x3693c226, - 0xd38a35eb, 0xbc7c2ba4, 0x6b3df5e2, 0xc61fa2c7, 0xb865e6f5, 0xabbb7aa4, - 0x353a511a, 0x4d9f9023, 0x52968cfb, 0xbffaaf1c, 0xf29f3ccc, 0x17f92a50, - 0x291a0a3a, 0x6df7b29f, 0x4e3ce1ab, 0x77661972, 0xa8e4fe53, 0xbc505fae, - 0x194079c0, 0x72762f32, 0xd6f083b6, 0xa0cd8e1c, 0x3d4b9b1c, 0x43b56724, - 0xb538a2bf, 0x094356b6, 0x7eccdac4, 0x0b439e13, 0xefe460af, 0x32e1d31c, - 0x8a157ae1, 0xc3be98fc, 0xa418987f, 0x0f8c8afd, 0x937e7844, 0xee1567b9, - 0x3d15b4c3, 0x3d718797, 0xcd4db80e, 0xbc5fd865, 0x872dfc99, 0x4fd21952, - 0xddf15761, 0xb85ea153, 0xb0f145c6, 0x296ee7be, 0xcc2aff24, 0xf310cc73, - 0xf336ca2c, 0x9aa50ffe, 0x9b699f50, 0xd5470f98, 0x04d559dc, 0x875083f7, - 0x3c8a467e, 0x453f1955, 0xa9ea143f, 0xd7e0ecf4, 0xffb63f30, 0x14b2d21c, - 0xe3490e7e, 0xb2e712fe, 0xf3c71fb7, 0xfc2c3b3d, 0xc391e79c, 0xdf936613, - 0xe0a6ad6f, 0xe6ee7c3a, 0x663794f9, 0x42e70c9b, 0x847ff006, 0x1d4756f2, - 0x6bd705fa, 0xaff61630, 0x68bd3999, 0xd13b3d6b, 0x2d38b8bf, 0x97ba7948, - 0x8a5545b5, 0x3d4eb99f, 0xec27ab50, 0x3d70b673, 0xef8fbcd3, 0x35f793cb, - 0x6e5fa65f, 0x2dda36cb, 0x927ff5fd, 0xfe83f2dd, 0xfdc6fff1, 0xf3ee330a, - 0xe497ed92, 0x3b20dd7d, 0xe1bfa93c, 0x8f9918ec, 0x0e303d52, 0xd29da7b7, - 0xf21b0a4e, 0xe21daa75, 0xd8cda17c, 0x5c23e5ff, 0xbf995f34, 0x5f52b593, - 0xf1fa7981, 0xd7f2301f, 0x70a23cc9, 0x09f7cf35, 0xee746c9b, 0x29dacbd0, - 0x8b24687f, 0xd3f90a2a, 0x6d7ce87a, 0xc111e636, 0x47b2eb77, 0x99dbbf51, - 0xf24a8d6f, 0x6e105752, 0x509fe63b, 0xeb646abe, 0x3ae71c22, 0xc7638d07, - 0x308b93fc, 0x15bfc085, 0x06f4ebe5, 0x05c85f1e, 0x9bf48c7d, 0xa1d39a3b, - 0xa1e78ebd, 0x99133cc8, 0x50f12217, 0x3b9bf02d, 0xca115176, 0xf04ab5c1, - 0x99ae7151, 0x4e0dffcb, 0xec195e71, 0x79c0cf6b, 0xfbc63ee4, 0xf898370f, - 0xaf376479, 0xf9d18c77, 0xf82fa079, 0x728ebb39, 0x2832779e, 0xaf09253f, - 0xc9e53f32, 0xe411e0b4, 0xcbf3e497, 0xd6124e92, 0x6f47ce8f, 0xfaedc43b, - 0xcd0b06ea, 0x35c96fa3, 0x5bec97e4, 0xffa86262, 0x9cadbbab, 0xdbc692ee, - 0x51616756, 0xd88b57ec, 0xf5ca7e51, 0x16bb32ff, 0xfd14b5d6, 0x6b5a47be, - 0x38053a2f, 0xa01ada3e, 0x74aecfb2, 0xf9d217aa, 0xa928b9d2, 0xf9f2d89e, - 0xe60e5ab5, 0x140bc4db, 0xb7e79920, 0xea93347e, 0xb077f199, 0xcf16eafe, - 0xc39034d7, 0x3be2637d, 0xffff7814, 0xdbc47f79, 0x19731691, 0x87a1f77b, - 0x5f1d8666, 0x91fddf41, 0x9c71e725, 0xc4d3bd41, 0xc8c5567a, 0x5df4245f, - 0x5e879725, 0x25ec8587, 0x653fc8af, 0x151f2235, 0x5f503b23, 0x714e5399, - 0x0fd3077b, 0x8f3db0c4, 0x7682cf9f, 0x6395ffa2, 0x26da7fb8, 0x49e582e8, - 0x184f54bf, 0x22cadbe5, 0x2fdf7d37, 0x23580f8f, 0xc7c63fdc, 0x0be9e37f, - 0xf325be28, 0xe573196a, 0xf280b9cf, 0xfbf50c6c, 0xa61ce2ec, 0x73c7cae6, - 0xc2cd2bec, 0x36f515ee, 0x8bc53067, 0x043e44f3, 0x2b8dee7b, 0x7c865bbf, - 0xf7e0e674, 0xbb5ca347, 0x82fb02ca, 0xeed8e421, 0xfac72e1c, 0x0a358ecc, - 0x0ce3577c, 0xfac2f08e, 0x773a95bf, 0xa8291e06, 0x82cd311b, 0xf8581747, - 0x9af11551, 0x3dc4e829, 0xaee7c387, 0x77982809, 0xc7ced2ba, 0x7e6a0ccd, - 0x9c10f73a, 0x70075ca3, 0xbcb854af, 0xc9d28f86, 0xd3d52a8e, 0xa3611cf1, - 0x0aaad738, 0xe74971b9, 0xf5ed1526, 0x35beb79f, 0xe006d355, 0x878885fb, - 0x78c8a2ff, 0xcbdca23e, 0xce5962ed, 0x900bf556, 0xf0ad56fe, 0x12f336bc, - 0xf8e9ce7c, 0x9565b4ca, 0x557da798, 0xfa254b6a, 0x4f3d0769, 0x0965e787, - 0xaf7f2b75, 0xc02f16d1, 0xed0be673, 0x8f8849c1, 0x7bbde7cf, 0x3b87ca27, - 0x0778df73, 0x30de24f3, 0xaf91390b, 0x98eef588, 0x79eb069e, 0xf22dd8ac, - 0x0f446c3c, 0x3f72c6c7, 0xdb1e7f64, 0xfaf28538, 0xe7e1ce66, 0xb165af49, - 0x9ef81eb6, 0x3ed0159c, 0xd9117263, 0xde453391, 0x02b78cc5, 0x9817e869, - 0x435c4371, 0x5d9c3a39, 0xacd79574, 0xc3f024f7, 0x7eb1bad5, 0xfeb1a96d, - 0xfeb19f35, 0x1a7fc98d, 0xd97f589b, 0xf48d9fee, 0xf3c2bcf4, 0x3097c33e, - 0x47bdd117, 0x32fda309, 0x715c99e1, 0x27e7970e, 0x77d8abfe, 0x5199333d, - 0xdb3ed67b, 0x20373c2e, 0x68aad7fd, 0xb665e09f, 0xef7e0cc2, 0xb8bbea03, - 0x3d1cf222, 0x0761d314, 0x3f71756f, 0x816bbc2e, 0xd3ce0e7e, 0x46aa3f89, - 0x4e9052da, 0x76261cb2, 0xa552f239, 0x239aec8d, 0xb9e4ee82, 0x058d2aea, - 0x8602cf30, 0x1be5839c, 0xe88bd766, 0xc87f0ea7, 0x69dbe718, 0x8a5be51a, - 0x415b1831, 0x5d0487f5, 0xfff2911f, 0x57589a07, 0xef1840e0, 0x1e5cfaec, - 0x74652e87, 0x656cfe5e, 0xdd25d509, 0xae01fe4b, 0x41a18d1e, 0xe927f445, - 0x0b4ea7f9, 0xbf7a83d1, 0x34bbf849, 0xea590213, 0xb8807092, 0xc93d42c9, - 0x7195fec8, 0x6c9b7cba, 0x7ef8fcd7, 0x7e75930e, 0xd44b2bde, 0xaa6a29a1, - 0xf2fcfd40, 0x3b7f48ef, 0x879c417c, 0xe746cd25, 0xa3e38693, 0x767f825d, - 0x4b91f125, 0xe8f89abb, 0x3b92cea7, 0x9c6bee08, 0xa5afd42e, 0x0cba9730, - 0x2a23fd2a, 0x4fce3bf0, 0x474f8a6a, 0xed66f9be, 0x825aa9f1, 0x9bef869c, - 0xc6a9f7f8, 0x7df0bdef, 0x69f7c246, 0xe0d97df0, 0x6d3b77ef, 0xec44d351, - 0x21ef4aa7, 0xc9a5187d, 0xade6235e, 0xaeeff166, 0xa3b17911, 0xd47de0d3, - 0x3cc6a55b, 0x67d93613, 0xa4e4fca3, 0x94ab92bc, 0x57c839e5, 0xba9adb57, - 0x97bfa07b, 0x655e3ac5, 0x82e67e0a, 0x2dcf2fe7, 0x57fc8a39, 0x98688b6b, - 0x8b2d77d7, 0xedc5c2ae, 0xc47c169b, 0xe1f24c5d, 0x6693e459, 0x03363835, - 0xedcc67ea, 0x222d6fa3, 0x9bce79fe, 0x495e1839, 0xa45e1227, 0x493fa417, - 0xf770c92f, 0x3bd7e7af, 0x3b6f1129, 0x4a5851d8, 0x16b18abb, 0xe7ad779e, - 0x880bcc0f, 0x65ad8668, 0x2f35da34, 0xdc93092f, 0x00fdcab8, 0x9cbd65e5, - 0x944ffc1b, 0x7e177567, 0xcbe1a052, 0x716379de, 0xc6f000df, 0x95e137fe, - 0xbca0e3f6, 0x862d0fe3, 0xf8e1e3bc, 0x421b8e4c, 0xfcc550bb, 0x47949de4, - 0xf0e39a1c, 0x109179e1, 0x5256c1e6, 0xc2ec8afc, 0x6f6e14e7, 0xb09b1587, - 0x3f37cee3, 0xaf7b7199, 0x33dedfa9, 0x9477d7e4, 0x6e3bb873, 0x35fde5d5, - 0xc79c5edc, 0x4b393db8, 0x51742fb4, 0xefc3ccbb, 0x86fdc9d8, 0xd58f4f1d, - 0x03b05fb1, 0xe9607ec9, 0x322ccec2, 0x7f839bde, 0xde40d64a, 0xb73366f8, - 0x7c99b75f, 0x62e79455, 0x9ce2f7e1, 0x318cfe91, 0xff64fc7c, 0x628e6e62, - 0xd7f74f88, 0xc5fe4eff, 0x3f307752, 0x585bfa07, 0x4c502fe6, 0x33f71708, - 0x1c3e7d02, 0xd6fe9863, 0xfeed1a32, 0x9bcb59ab, 0xcfa262a6, 0xcfa41ce2, - 0xc59f4009, 0x9d1cfa06, 0x24e5c993, 0xb3e925c2, 0x934b2e9f, 0x1782caf3, - 0xee1d3f60, 0xa3355fce, 0xf56ddcbd, 0x9e5abcf1, 0x072c9827, 0xa059e012, - 0xaa3c7871, 0xc24cf04a, 0x39e19371, 0xa4493e1f, 0xf9c66ccf, 0xc97e3861, - 0x59d858d6, 0x2f2fc031, 0x083583db, 0xacdf3f7f, 0x41a3fbe2, 0xa20eab70, - 0xe46febaf, 0x2a509471, 0x4f1847d7, 0x67f181c9, 0x5faff189, 0xfaf0e9cb, - 0xdd10b17f, 0x8451f802, 0x9f68b67f, 0x7944ddd5, 0xcc6bb354, 0x00ed1227, - 0x13a9b719, 0x94f1cdef, 0xe605919b, 0x4bc634cc, 0xf1e26eea, 0x8b58eb9a, - 0x7ebde119, 0x3a9fb18e, 0xcc13feb6, 0xc9bbab0b, 0xd3983cf8, 0x8b19671f, - 0xc2a39671, 0xfc07d08f, 0xd3f4fc82, 0xdf0fc5cc, 0xf63bf40a, 0xe8156587, - 0x6b32ba77, 0x504deec9, 0xf1b6f1ff, 0xd669ff54, 0x06f3bfb7, 0xa128efb6, - 0xb9260d7a, 0xf9083ee1, 0xd54df511, 0xc114d78d, 0xa2ed47b8, 0x39f95bdf, - 0xb04a6f02, 0xe7bc1663, 0xf28a389d, 0xbc846b21, 0xdbc85be9, 0xc9d0bdaf, - 0xd66f5e53, 0x9358dfc9, 0x79f5efc2, 0x2bbffcad, 0x66b73f30, 0x3c57a894, - 0x47eb1e3f, 0x1ee84f95, 0x8726de80, 0xce6ff886, 0x09da7ee5, 0x1c744aa5, - 0x4326a5e0, 0xe7c4dff4, 0xd1e2b335, 0x9a8fe45c, 0x04cfde6a, 0xc5b5b4df, - 0x2ce99ef8, 0x6d737bd5, 0x250f2869, 0x70e7b59f, 0xa9ed2cfd, 0x67fbe080, - 0x8db6effc, 0x36037e80, 0x0c5387c5, 0xdf977e4c, 0xe7e0e55f, 0x22fe02cb, - 0xd3bcfd0d, 0xb37f3cfd, 0x0722b6da, 0x0f5fe7f7, 0x5e712a5a, 0x51f95b2e, - 0x27d26fb4, 0xf9449b4f, 0x466636be, 0xdf74073d, 0xf1787c41, 0x48690527, - 0xdd230e6c, 0x259aba4b, 0x48c6bde9, 0xdbafc0d7, 0x5cbf3272, 0xdae81b5e, - 0xc3d7403e, 0xd700b9d9, 0xa9ae098f, 0x3fd5fd46, 0x265f124e, 0xbc9c3b8f, - 0x7944bfc0, 0x275f003a, 0x661e5ff1, 0x7f2315c5, 0xecfe4bb6, 0xa62c3842, - 0x29b39d18, 0xe9e37c54, 0x7630ea60, 0x1f2f8486, 0x8315ae7d, 0x4d3fc2e1, - 0xcffc7fda, 0x3cf2fb83, 0xf9df0ed1, 0x5c00c659, 0x242bfe30, 0x7871570f, - 0x5c2d2bb6, 0x5c7b08be, 0xe59be7ee, 0xf38cbb7c, 0xe7e14aad, 0x77e8bdde, - 0xf97bdf21, 0xcfb87ef8, 0x7ce41d63, 0xcf6f4242, 0x169c05b1, 0xee75db98, - 0x1b9fa27a, 0xb469f858, 0x8339968f, 0x74f117ff, 0x843e14c4, 0xcc859cfb, - 0xa057f14f, 0x1272778f, 0x6f090dec, 0x879a9e32, 0xf3c9a791, 0xc0cfc649, - 0xbec8c5ba, 0xfad8e793, 0xf39e7be7, 0xc7897694, 0x6577f462, 0x8654ff08, - 0x452147f0, 0xc99e7ea1, 0x2fb87c52, 0xc853ee98, 0x6cc998be, 0xd6679724, - 0xe19e7d72, 0xd487f6e0, 0xc7f1c3fb, 0x92339715, 0x991b3357, 0xe7c73738, - 0xd9874c95, 0x2c0ee7ac, 0xadf4da67, 0xd1ef900b, 0xe007d14e, 0x7ee0e99f, - 0x215cecec, 0x24cf583f, 0xf5fdf3d4, 0x67be7a41, 0xe49fca12, 0x9e66c9fb, - 0x8cd2fee3, 0x99ca8c73, 0xa12777be, 0xeda8cf9e, 0xcc728499, 0x737bf2e9, - 0x1fdc0d27, 0xd1c78c98, 0x871926b9, 0x4cfa2f3b, 0x3f191fe6, 0xc706736b, - 0xcfd238e2, 0x55894671, 0x1e154be1, 0x583fe897, 0x76ec7484, 0xff434d15, - 0xe81b1cc5, 0xcbba1823, 0x1730bc15, 0x008fede9, 0xf10e6e0f, 0x75e3c055, - 0x347bc135, 0xe1e12c3e, 0x2b878136, 0xfb3d5e85, 0x89f14ab0, 0x43e97f1a, - 0xbd084218, 0xe2116662, 0x45e93f57, 0x59d8bf79, 0xf8a2a030, 0xb24e63fe, - 0x5abf1633, 0xb195f14f, 0x4f4c4c5b, 0x22e393d0, 0x327b8629, 0x30cbec26, - 0xcce82fd4, 0x617fbc35, 0x7b4328d7, 0xa1bc7479, 0x2a57a2fd, 0xb149f50c, - 0x2ff78629, 0x50daab7e, 0x1ae7a4bf, 0x3f53fbc3, 0x83a86d98, 0xde70d0c6, - 0xd8559f7b, 0x65f79836, 0xbe196ff1, 0x19b6cdff, 0xf3bc60af, 0xb2f7d8a4, - 0x0a563fb0, 0xe9205878, 0x637cdcf6, 0xaa25517f, 0xf3df2154, 0x79eb05bf, - 0xc034f6be, 0x0bbf625c, 0xc4f68ddb, 0x7ac62de2, 0x55a6f743, 0xe7071b28, - 0xe354b479, 0x79c93955, 0x79ae351e, 0x50cfa426, 0xe317d82e, 0x62ec1110, - 0x8e1b33cc, 0xfd6cbfcf, 0x2fe8d84b, 0xfefe7f5b, 0xf5d90b16, 0xaa7d5f8b, - 0xac8f0a2a, 0xdbfae35e, 0xa7fae375, 0xdfd71a96, 0x7fae33e9, 0xfae364fa, - 0xf5c6fdbb, 0x5c6b511f, 0x7180ccff, 0x8cebb3fd, 0x34139feb, 0x06c8ffae, - 0xb7e7fae3, 0x70bbd718, 0x8b3d7199, 0xed0d4bc2, 0xe52febc9, 0xdb9af165, - 0x7a01ef8c, 0x2074094d, 0xa04168e9, 0xc677f281, 0x30cf7fb4, 0xc03d324e, - 0xf744d1be, 0x6e3ec1bf, 0xf4fe729b, 0xfc8ad201, 0xf1f4c9bd, 0xeec2b96f, - 0xfa017414, 0x0ae513a8, 0x614f17d8, 0xd8563759, 0xeda181fb, 0x12bf290b, - 0xbee279f5, 0x36b93878, 0x7d894f48, 0x0a7ab0f2, 0x81f6c9f7, 0xf470f27d, - 0x8fb31c7b, 0x4f5a8ec8, 0x5d1ba57e, 0xf14f8e1c, 0xcfe825d1, 0xf2f4827d, - 0x32700071, 0xe71c7bc0, 0x4f1fe303, 0x8dfe4099, 0xd928b36f, 0x1982ffed, - 0xcdd83096, 0xe2ada898, 0x953a4f3d, 0x2f6f42f5, 0x858ffe14, 0xb95be0f6, - 0x9851efdc, 0xc5e6e385, 0x7b14bce8, 0xdd79c46d, 0xe3027123, 0x4f782008, - 0xca011c61, 0x9ba73b5e, 0xf8ae52d3, 0xc049ee99, 0x4ae9fce7, 0x6ab5d929, - 0xcd3de50a, 0xfd2141bf, 0x787fff34, 0x2cfa1719, 0x4cb95cb9, 0xd85db3e2, - 0x482edc03, 0x149ac3c7, 0x07416277, 0xc2e7cde1, 0xb8fe8675, 0xfc47ff1f, - 0x0ae3cd7c, 0xd06726d3, 0x675a3331, 0x0f3c6f5c, 0x9c38daa5, 0x0d999b8f, - 0x058139f1, 0x57bc0ec9, 0xfbc6d103, 0x7bfbcf1b, 0xd3fa1463, 0x7cfff554, - 0xcfe306ad, 0x9ffa2e38, 0xfe863e1d, 0x63ebd566, 0xf41abfe8, 0xba14c0fc, - 0xcebfa324, 0x87f87bf8, 0xc27e9178, 0xbb2f413c, 0xbdfb8c9d, 0x2386fc92, - 0x98c09055, 0xe7e663bf, 0x16dabdc3, 0xe63c9fbe, 0x984d635b, 0x37666337, - 0x32fbe79e, 0x6df3087b, 0xc7e4274f, 0x790cbac3, 0x3cb4e98f, 0xb657efae, - 0x71865c36, 0x07115ea2, 0x7835a7bb, 0xaab7ae19, 0x0e2f28f9, 0x277257ef, - 0x40f16f7c, 0x6a9f027b, 0xdd43068e, 0x5e1008ec, 0x10b6b556, 0x3dc598dd, - 0x6ef3ab50, 0xfc130573, 0x148e1712, 0xcc2d86f6, 0x984c595c, 0xc1f7f0c6, - 0x55f38674, 0xc4e9da5d, 0x0bd5a87d, 0x2bca25fd, 0xfa2590ad, 0xb6b4d7ad, - 0x94abdc10, 0xb33b1060, 0x3b51668e, 0xe1aadbe0, 0xbe785459, 0x67922af5, - 0x3e6de716, 0x3867f7bc, 0xdabd59fc, 0xc87289e7, 0x8728d23f, 0x5db56fee, - 0xd95af88e, 0x93c68cba, 0x756f6b78, 0x8df58e5d, 0xbed15ead, 0xb54dda82, - 0x71f482ba, 0x8621681a, 0xc7ad1671, 0xb03d7189, 0x03c61933, 0x045b5ecd, - 0xe1eac899, 0x05a3b2f0, 0x5d731f44, 0x8df4061c, 0xbc7d03e5, 0xfb4cccb3, - 0x1df3dbd3, 0xafedfef4, 0x0fd1798f, 0x1e01607c, 0xf98aff51, 0xf0238ff4, - 0x88721167, 0xf200c169, 0x23572595, 0x6b86747f, 0xdfe3ad36, 0xbbc49fda, - 0x1f28cec5, 0x20ef92d4, 0xe17cebbb, 0xf7148d0c, 0x27bc0950, 0x44f00fe3, - 0x8176f472, 0xe2efdba7, 0xefdbbe7e, 0xcec79460, 0xd55fc196, 0x148d5d00, - 0x059b25f2, 0x056f6ca8, 0xeb8252c1, 0x0b416365, 0x49d675e8, 0xbfd1db2f, - 0xcd7eed83, 0x4deaa18d, 0x58599e35, 0xaa7c9c6e, 0xbef1d91d, 0x618b3f4b, - 0xc474be89, 0x4581ab97, 0xc51fccf0, 0x1d783d8e, 0x89a7af35, 0x5e3ab4f6, - 0xe9ed174f, 0xf7cf5e01, 0x20d4a93f, 0x97f14960, 0xd5c6477c, 0x2dbe51a3, - 0xb27cfc60, 0x3b60e7b8, 0x91c2f213, 0xdb06ab31, 0xbe74626f, 0x50ffb640, - 0x4e38e7b4, 0x394629ac, 0xfdf8c73c, 0x6c878156, 0xe9f689c7, 0xb6319f14, - 0xa64af8cb, 0xf42bece3, 0xfdb1997d, 0xd3bdf141, 0x1d363671, 0xc71b47db, - 0x53da20df, 0x08ef3c1d, 0x473f21c4, 0x15efda2f, 0xc76c76ed, 0xed8d4bf1, - 0x2bf8c56b, 0x43ad0095, 0xf8899f3f, 0x9d568ee4, 0xf67cc9ea, 0x7e0cc8ea, - 0x99f0598e, 0xf21b196b, 0x23abfcdc, 0x9a4cbe79, 0x0ff7e3de, 0x7b650f21, - 0xb8a34b86, 0x10b5eaaf, 0x421d591d, 0xec3e088e, 0x8b4a2397, 0xf717138f, - 0x3d197f97, 0x8e7ee103, 0xfe00acf2, 0xbef39e90, 0x04c16263, 0x98db9679, - 0xef0982c2, 0x1864177b, 0xe53759ea, 0xccf7de1a, 0x77686519, 0xb4378e54, - 0xf13e58b3, 0xae826dc7, 0x0c2aca52, 0x02bef2ed, 0x923e73a6, 0xf479b576, - 0x677bc314, 0xa474f54b, 0xcb57d3ed, 0x367cabfb, 0x39b70b94, 0x1f236547, - 0x3275a4fe, 0xef20df1a, 0x8974a26c, 0xc9474bd2, 0xa2eab656, 0xc7f54a5e, - 0x7aaf3cdc, 0xd78fab65, 0x6f9d188b, 0x4b5ad95e, 0x2f81c7f5, 0x56d7fcb1, - 0xa07b953f, 0xfb0e160e, 0x43aff411, 0x7fa13b3f, 0xfd023fac, 0xfa1db963, - 0xd087f2c7, 0x856fb63f, 0x10feb17e, 0x83e585c0, 0x7f3e0fd0, 0xfac7fa00, - 0xd500d6a6, 0xa3ad6bef, 0x20d686fa, 0x36b6f795, 0xadb5f3d0, 0xdd5f542d, - 0x7bca8cba, 0xae54c35a, 0xed435d6c, 0x1f37a116, 0x1f1fe713, 0x7dcfc69b, - 0x467faf27, 0xeed5f29e, 0x4504a8bb, 0x93c8655e, 0x7dc3c8c8, 0x2f31a775, - 0x7047f110, 0x931e39d8, 0xe02b18e1, 0x2b62cf18, 0xa0dcb952, 0x2e98eb38, - 0xc0a9dddf, 0xf85b23a7, 0xc57517ba, 0x81a73da9, 0xcc56378f, 0x2cc27993, - 0xef1f8aaf, 0x957af7c5, 0x8f2a7558, 0x831f9337, 0x553f0179, 0x9133dce2, - 0x7084c479, 0x7f419369, 0x1fb3cc27, 0x270e6e5f, 0x78286de2, 0x7c78f22b, - 0xe4ecad43, 0xb6d49bf7, 0x52cd9147, 0xbf742dfc, 0x102ead89, 0x04f4a0d5, - 0xc24f7482, 0x603373f8, 0xed720593, 0x874ce5dc, 0xb8d1af32, 0x505dcaff, - 0xa8e7d861, 0xfd3236e7, 0xccb7e822, 0x194a4fb8, 0x3be19b7d, 0x0cf7de5b, - 0xddcf16ed, 0xb7f9f686, 0x22f2ad14, 0x8a32473e, 0xafd7593b, 0xd7003960, - 0x044d8ec2, 0xbde05057, 0xfdf9d157, 0xefc5fbed, 0xfffb0844, 0x2f812ec7, - 0xd7da7adb, 0x6af3758e, 0x84d87a49, 0xa7e3e7fa, 0xee8e49d2, 0xfe44c47d, - 0x622c71ed, 0x01337942, 0xbf6c48cc, 0x56726f00, 0x151ccae9, 0x574ce5eb, - 0x8b117eb1, 0xec08bed3, 0x17a43aff, 0xb11fffb0, 0x7e4cfd43, 0xbf3cc7f0, - 0xba7a4a2b, 0x8967ac44, 0xd16d07dc, 0x73c3fd92, 0x635fc8f3, 0x26d6073c, - 0xdc2b01f6, 0xef18d955, 0xff261ded, 0xd6fde9ce, 0x1eb005d4, 0x2a3a9cce, - 0xba0df3e5, 0xd173c869, 0xbf2abecb, 0x623d016c, 0x086597e4, 0x9fca99ff, - 0xaabba167, 0xf89c7479, 0xe52ccda6, 0x728e9e98, 0x4beea06c, 0x3ba2bb27, - 0x89a3f087, 0x1adbd9f5, 0x3900fca4, 0xd377ed4f, 0x560f985c, 0xf74ff222, - 0xb53adeb5, 0x661f2126, 0x52dfa0b7, 0x3d45ab16, 0xf2665a5a, 0xaf27a845, - 0x1f617fc1, 0x73c7eedd, 0xf3055afa, 0xc71e18a1, 0xbabce9da, 0x794a85f6, - 0x4b91da40, 0xb0760e98, 0xe16511c3, 0x997e81b2, 0x477c83f0, 0x5ccff5c8, - 0xad0f3435, 0x3e47da40, 0x33ecddd4, 0x74863f87, 0x998759f7, 0x6309e5b3, - 0x9183a97b, 0x6a545b9e, 0xa60ae889, 0x3dd3b423, 0x850eda8b, 0x1c2115e5, - 0x50f3bdd3, 0x254c1f8f, 0x52dd4dba, 0x7bc35745, 0x79f5c14c, 0x1e99c700, - 0x1a49a0fd, 0xd35ef057, 0xb42ecb04, 0x5e22c71b, 0xa5d19c70, 0x6285c784, - 0x575afbbe, 0x159e9e10, 0xefcb68f3, 0x87873bc7, 0xcf78fcf9, 0xe90ea2e9, - 0x73ce31bf, 0x37f56543, 0x95c6def0, 0x74d85531, 0x33ae7c46, 0x53ce26c7, - 0x3802e006, 0x5538459f, 0xbffc9b84, 0x8f4d7e7c, 0xc819bf70, 0xbb8a5ab1, - 0xc4b1324e, 0xa32cabb8, 0xc8cdfe42, 0x4ebc1173, 0x0ba9dcef, 0xdfac4a2e, - 0xb8fd7444, 0x761fe7c2, 0xcd2f3c6a, 0xfd13d7ef, 0x7ee4ebc4, 0x487f9c59, - 0xdff6f011, 0xe79e36e3, 0x6c583a61, 0x0d2de60b, 0x25fe1fb7, 0xc4a4ca2e, - 0x18e830fd, 0x649d5718, 0x759f3ca3, 0x7f4b8f32, 0x337cc743, 0x8afcf12c, - 0x6ae9d04d, 0xe4af31a7, 0x77b71e5c, 0xe8f589ce, 0xc6be71b3, 0x567964b8, - 0xdd17bdc2, 0x91ffe4f5, 0x6ebecc71, 0xfd2e0f9e, 0x09044b6b, 0x78e51df4, - 0xa5587be8, 0xee92e5f8, 0xa17df96b, 0x7ba01e87, 0x1d2fa156, 0xbc5ea1e9, - 0xe8c6bf5f, 0x3bb059ef, 0x1f452ab0, 0xc45a57ec, 0x48d7e4c2, 0xfb2527f6, - 0x279b7e91, 0x563e69f6, 0x93ca718e, 0xa58f8beb, 0x88a67ee0, 0x91dbb9d1, - 0x8f7493ea, 0xedfb5831, 0x2b294f78, 0x24f4f7e3, 0x0525fbaf, 0x3ef3c216, - 0x1c63aeb9, 0x37d867e4, 0xbefff389, 0x7d7ecf17, 0x96f3f40c, 0x81ce18ae, - 0x099ba5bc, 0xae81e38f, 0xac64ecb1, 0xa0fba876, 0x5f4df3b2, 0xa5c0bced, - 0x68d7dfc6, 0x9639eaea, 0xcbbc93aa, 0xfa7807ca, 0xad3efd8e, 0x4e27f88c, - 0x575107bf, 0xb841e1c4, 0x7ecbfcf1, 0x137327d3, 0xbe7c60e9, 0x7c83edc6, - 0xbf9357d3, 0xceb84635, 0x7599bd94, 0x1c6b870d, 0x3d1bd5c2, 0xb7689591, - 0x0ff6b848, 0xa5fabf73, 0x934f155f, 0x0120fa8d, 0x12ff534f, 0x865bf69e, - 0xc0966786, 0xf28e4fcf, 0xb70642fb, 0xd5fd457f, 0xccf78461, 0x51ebb163, - 0xb3bc023c, 0x53de7f08, 0x15331459, 0x14acebf8, 0xe42959f4, 0xa8ce8f8e, - 0x17dbd0b0, 0xa75e7e53, 0x7743dbc6, 0x79e08a2e, 0x0b8bdf02, 0xe0dfd10a, - 0x7ba56e3c, 0x7949429e, 0x2f5cb222, 0x573fb1e6, 0xab0f1219, 0x78bcb9f3, - 0xd4f9b5f1, 0x596fbddf, 0xed83ca19, 0x5ef5df22, 0xef0da757, 0xc47895ef, - 0x2194057a, 0x2a117c4b, 0x3f2b7bba, 0x218ee9b3, 0xf1f133c6, 0x1be24bee, - 0x572c9e39, 0xbb7297e4, 0xe2aa3954, 0x2efb8739, 0xd9ee937d, 0x2352afba, - 0xe337fb99, 0xfe127d7f, 0x7d666fa3, 0x8acbd39d, 0x2aa3f47c, 0x037da5ef, - 0xfe2521ea, 0x9fc432b3, 0x0ff34825, 0x3b656dbd, 0x6a78c195, 0xe72bf414, - 0xe12fe727, 0x80b65e76, 0x7ae099ce, 0xc5abe020, 0xa44f52fb, 0xf387bd0b, - 0xa9713d22, 0x4c89cfc6, 0xef5d68d2, 0xce853c9b, 0xf917ecf5, 0x2c4bf114, - 0xc32efe43, 0xf76f0233, 0x0c45fb9e, 0x770da9ef, 0x055ee99b, 0xbf78f5a6, - 0x7a147409, 0x9a7ba35d, 0xf16a9e81, 0x5f17a8de, 0xfb869b3b, 0x66f903e8, - 0x3e40fb82, 0xe77d8797, 0x6f3a5ad4, 0x2e67daf3, 0x9ffe8135, 0x5d8557ce, - 0x39e18b12, 0xfc158d9a, 0xd84380dc, 0x4ed78e01, 0x8efc2035, 0x2ab3dfc9, - 0x4f767a09, 0xdbbe95be, 0xf9678968, 0x48740e30, 0xdfee5165, 0xfaeffba1, - 0x38ba0bcf, 0x8f2b9a1e, 0xe8e09d92, 0x3de2f7e6, 0x5c13af9d, 0x7841f708, - 0x33ee329e, 0x57b63d57, 0x06a378c2, 0xf8ba77be, 0xe24ca67a, 0x77dcd0f7, - 0x785dcfe9, 0xc2ba5eef, 0x4be8fee8, 0x3906cc0a, 0xd7c45f5e, 0x1632b3a1, - 0xe5fc851b, 0xb6af28d2, 0x0d9b7a33, 0x17c97aed, 0xf4a947a3, 0x97916add, - 0x29727abe, 0xe3a499f1, 0x57c105b9, 0x02366e91, 0x76493c5f, 0x9d302c4e, - 0xc72ae3f0, 0x95c7e3fc, 0x3fb71d58, 0x2fd42e2c, 0x819326a5, 0x380b8adf, - 0xec12c8dd, 0xee77b252, 0xf52cb410, 0xc6c45b7d, 0xb7ffbf30, 0xa3a566e7, - 0x2796da5d, 0x0dbf3ced, 0x095db5f1, 0x38e117a4, 0xbed2a5ff, 0x4ed7c5ef, - 0x6db8e034, 0xdbe42f30, 0x58ea7e7b, 0x9b49f68f, 0x2a7c4fcb, 0x26dcd7c7, - 0x9fbc1eb1, 0x2bff16fd, 0xbb8c6fe8, 0x47447df9, 0x43635ca6, 0x4cf787fa, - 0xad7bcfd8, 0xd81a0bf8, 0x07f90d4f, 0xcf66ba16, 0xb116efc0, 0x6bb42ae0, - 0x86a87517, 0x11ee177b, 0xb9e162f2, 0xd84d1614, 0xfc9c2c1f, 0xb6373a2d, - 0x8b1a5cf0, 0x8f75bd82, 0x8f7d1738, 0x0ac45738, 0x443b3d38, 0xdfe515e9, - 0x24bef7cc, 0xcbf995bd, 0xdf39f3bd, 0xb7e802b3, 0x14b1e949, 0xa71b10c1, - 0xebce9efc, 0x62ead7bc, 0x780492d1, 0x0473cd07, 0xd38c268b, 0x1b39deff, - 0x7d6067cd, 0xcc0efd39, 0x787841d7, 0x784bd5af, 0x91ffbe1c, 0xf40e3c06, - 0xc780ca3f, 0xd097fdc1, 0x96b5eff8, 0x13ff497e, 0x375fe986, 0xefd03fc0, - 0xf7b71a68, 0xa71ffcc8, 0x891ddf02, 0xf9edbdde, 0x331dfc4a, 0x017efd2b, - 0xa6aceaeb, 0x338f8473, 0xe77a673a, 0x83bddfe1, 0xee779af9, 0x8c70f8b2, - 0xae7c733e, 0x333d086f, 0x78c2b99a, 0xc72c979f, 0x7cd31417, 0xb4db9f92, - 0x32f30b88, 0x0b9aa56d, 0xc6d11f7f, 0x71bb9162, 0x236952df, 0x42e32739, - 0xe53fdfb2, 0x3b3cf2a9, 0x6f7907c9, 0x979112cb, 0x5e08ec57, 0xd4beeb81, - 0x13fcded4, 0xd283f6f8, 0xcc373a36, 0x33f69b98, 0xe1a36e32, 0xa315bf2f, - 0xf0c0305f, 0x7a13cdfc, 0xf77e0670, 0x18271043, 0xd82f51c7, 0xb5bcc41d, - 0xb8df620d, 0xfaf31ec1, 0x0de6e412, 0xb357da05, 0xe893da17, 0xf72fd276, - 0xdedd3946, 0x227e8050, 0xfcc4f635, 0xedb7cc22, 0xe976f711, 0x55778a16, - 0xfefba31e, 0xff7dcbe6, 0x8ebce49a, 0xd1da377c, 0x8694ce32, 0x6b687779, - 0xbef7e46c, 0x7af2a7d5, 0xa08c7ffd, 0xffb01073, 0xf9432d49, 0xfee55fb2, - 0x3adf1120, 0x67d0e62b, 0xf94058db, 0xe41f22f7, 0x744bf76c, 0x35d9e4af, - 0xebfd6863, 0xdd3ef85f, 0x973fb70b, 0x43beb1eb, 0xf563d24e, 0xde155f56, - 0x973fb85b, 0x5a9dabdb, 0xc122ad34, 0x579d5d7e, 0xe3f9f24d, 0x894c6335, - 0x0aef8ff1, 0xfa51b079, 0x1578b537, 0xb8f9679e, 0xd233fa32, 0xf4ec07a3, - 0x83a6513b, 0xfba2abbf, 0xe95a372d, 0x0faa0177, 0x875cdb8e, 0x8d34c3fb, - 0x074d91f2, 0x99cf04ed, 0x2d7efc75, 0x5de516fc, 0xf491c1d3, 0xa9f556fb, - 0x6c27ca71, 0x6095f14a, 0xe0feafdc, 0xffd7ba54, 0x057186e4, 0x644eff28, - 0xaf7405ea, 0xf43c06f1, 0x6343f509, 0x17b5f3f9, 0xe75579d3, 0x50e0d4c6, - 0x8fa9107e, 0xdaefef92, 0xdbde5b9f, 0x6719f885, 0x7dfca1f3, 0xb8f1f14f, - 0xd9f12bef, 0xf915c53a, 0xd77ad2f9, 0xbc7dfa69, 0x6f778efa, 0x43dcf462, - 0x73f72b74, 0x0bd5e3c9, 0x12dfb57d, 0x4bbf8b9f, 0xe052bf56, 0x624efc5d, - 0x7e9ca9bd, 0x7de24faf, 0xb73dd263, 0x24fd084f, 0x69af93cb, 0xd8205f74, - 0x1fe80511, 0x4ad8793a, 0xe3727674, 0x2eaf3a04, 0x9c07abc7, 0x4f2f80b8, - 0x7113e864, 0xf2169f5d, 0xdf257eaa, 0x30e7caa7, 0xe77f0c7e, 0xa5487e30, - 0x573eaebc, 0x92e30d3c, 0xef593df2, 0x4ab74f9f, 0x3fb597bf, 0x6f5a45f7, - 0xf48627a0, 0x49c17a64, 0x82f43a7a, 0xe7ae1775, 0x8c2c95c7, 0x5bf0cffe, - 0x8ec7f7fc, 0xfd92b21c, 0xef9c77dc, 0x9fdd076f, 0xe01788e6, 0x17a1a1fd, - 0xeb1c9246, 0xe0ef8fcb, 0xdf9db6f6, 0xf046f8ab, 0xcdff1162, 0xe611f711, - 0xf9f79da0, 0xed147b21, 0x9e29283c, 0xbdbb6610, 0x2a70fcf4, 0x940fff43, - 0xca63cf14, 0xeefd2f01, 0xdf176b0c, 0x3bfbe8c7, 0x5163820b, 0x0c59df2e, - 0xfbf03bfd, 0xe7def453, 0x521782a3, 0x5cb18a0c, 0xf52e5e31, 0xa42c1f9b, - 0x5e67cae7, 0xed2a7bfe, 0xed463da2, 0x62f06b21, 0x9cafc79a, 0xf310e76c, - 0xeef7aafc, 0x41182d1d, 0x06e128eb, 0x98dd933c, 0x05b3978c, 0x3b7bf126, - 0x74c91f1c, 0x5f9ebfd9, 0x5ffa1f02, 0x21f6bce8, 0xc6eb8ebe, 0x591cb859, - 0x63ec813b, 0xc86296d6, 0x88715b9f, 0xbbd0c3df, 0xdceb49c1, 0x843ff667, - 0x86fe28fa, 0xed7bf199, 0x3f4022c0, 0xf9a1e4c5, 0x4f9123e5, 0xcf2d64bf, - 0xd1e8fbb3, 0x39e60bf7, 0xfbf25cf0, 0xd2c97386, 0xa49d085f, 0xe1c63fa1, - 0x97e6d3d3, 0x255d7b71, 0x7aeff8f8, 0xf4eb346d, 0x0de16bbb, 0x711fc8e3, - 0xa41fa2d2, 0x775b87df, 0x4ae90981, 0x77f2172d, 0xbc9f9f13, 0x7bde4b2f, - 0x8a9f8c95, 0x7f9262c2, 0x33782c4d, 0x827ea1de, 0x61c259e9, 0x91fff746, - 0x6984df7b, 0xe29f9a88, 0xf485acb6, 0xf67be0c2, 0xbbf25f2c, 0xf5bbff6c, - 0xf42b5c2a, 0xd38795ef, 0xe07eaf50, 0x3a46fbe2, 0x5d7a8f7d, 0xc36cf3e5, - 0x83af300f, 0x4e14a605, 0x879276a2, 0x5dbc281f, 0xf341b9ca, 0x7ec17a47, - 0xebe83df0, 0x7fee429a, 0x710cae63, 0xc16c2bc8, 0x9fa94d3c, 0xc2668a42, - 0xdca7f373, 0xe3d21a7a, 0x19c5b5a9, 0xc60f302b, 0xda2567ad, 0x8ca3a1d5, - 0x78eb8bce, 0xf8c5f8df, 0x89fe32fb, 0x9fdbf7e8, 0x243bf461, 0xb4e4f3c3, - 0xed89b99e, 0x9eb90a73, 0xf6285f9b, 0xe44c8599, 0x8de32657, 0xb162fbaf, - 0xf0796aee, 0x2687da72, 0x4b78b7bd, 0xa487a0ba, 0x7fcfede7, 0x1ea0f297, - 0x4913de36, 0xef185fb1, 0x612c5783, 0x532c42e5, 0x61bdaf28, 0x0d739713, - 0xb92cceaf, 0x5ee9d78b, 0xef3b6985, 0x59e3dfa1, 0x12caebb0, 0xad16e5c6, - 0x05c7a483, 0xb412fe05, 0x555be2e3, 0xc345f217, 0x51e09516, 0x56d73ecd, - 0x8b7a7e78, 0x06bbec99, 0xbce9cf01, 0x9bad1a60, 0xe00b34c6, 0x4c16b4fd, - 0xab75fb23, 0xa4a1ddf8, 0x6f7bc079, 0xe043156a, 0x99d7c6c7, 0x043c53f0, - 0xa261bc1d, 0xbf805a75, 0xec70890b, 0x79bfc854, 0x33783f3a, 0xfec14fd6, - 0xabe9cf1f, 0x7dd0969b, 0x3ef8c936, 0x7d120b6d, 0x91f3162e, 0x471e4cf8, - 0xf10fb3e2, 0x2bd2f689, 0x85ef4853, 0x6291541e, 0x9fdd8bd9, 0xda7cbed2, - 0x99df2ba1, 0x8137cf8a, 0x9ea3a2dd, 0x6fb3f51d, 0xa35b9ea3, 0xfe7a8c52, - 0x962ce2a1, 0xff71afa4, 0x39f5ff39, 0x3d04a669, 0xf1c83ea9, 0xa4e73aa4, - 0xcff7a42d, 0xebe91d7e, 0xaacbee84, 0xf1ef7848, 0x83b8fec2, 0x37eabd61, - 0xc70d21fd, 0xa66f5869, 0xe975c979, 0x7ca079c3, 0x208d4f6b, 0xc5e5f7fd, - 0x4eb95fa9, 0xeb8df4fd, 0xde09e920, 0x9742affb, 0xf24c2718, 0xb05154e8, - 0x9d0437ca, 0xc6007a2c, 0x38b6fec5, 0xf3d2fee9, 0xa3e2571d, 0x5f05bd7f, - 0x71d71d53, 0xd1f91147, 0x74686f4d, 0xfb44e0c8, 0xc7c80555, 0xd02fa0f5, - 0xc4af516f, 0x647ba1df, 0x1ee9590f, 0xb74dfae6, 0xd5e38cdc, 0xb09ab71f, - 0xabe1d4fd, 0x495c1226, 0x2a780aeb, 0xfbde8a18, 0xbe05e28a, 0x3d81fc04, - 0xe72dfc41, 0xc1370093, 0xba29fb01, 0x08afa88f, 0x0e4133d6, 0xedc859bc, - 0x65df782e, 0xf7e6fa21, 0xd7cff561, 0x575f3495, 0x64df7cd2, 0x17ccdf44, - 0x782cf9a4, 0xe7c26adb, 0xb6bfee0b, 0xa73df704, 0x79a74dd6, 0x4ff0ca9d, - 0x553afe44, 0x210ffd00, 0x0fdc172f, 0x0bfb2cf3, 0xd3b76cf3, 0xcf3b0d7a, - 0xf60ef88c, 0x89f9e617, 0xcf3943a0, 0x0d3d34f7, 0xcf43f9f3, 0x2efd0caa, - 0xc6c0fca1, 0xbf4ebca9, 0x73321713, 0x4a6d087a, 0xdedf7ca5, 0x04fbfe6e, - 0x78c00e52, 0x260f49e7, 0xd55387a2, 0xd0c9e6fa, 0x3f07ffdf, 0x00b71737, - 0x0000b717, 0x00088b1f, 0x00000000, 0x7dcdff00, 0xd554780b, 0x733effb5, - 0x64932666, 0x08124c92, 0x3c984081, 0x49849009, 0x768a8802, 0x02d10478, - 0x89794f0d, 0x42100793, 0x69b5a05e, 0x0240cd6b, 0x350d45a2, 0x01d45a2a, - 0x0da2a281, 0xbc150a0a, 0x45622a03, 0xb68b57c5, 0x514026e5, 0x5ea0c679, - 0xffd7b5ae, 0x4e7dadfa, 0x5490ce72, 0x7dfbdedb, 0xdf1f7cff, 0x5afd9f66, - 0xd7b5ed7b, 0xe7bdaf5e, 0xcbaa3dc2, 0xe4e216ef, 0xff6f05dd, 0xf7a517bc, - 0xfc812eaa, 0x02cddf58, 0x2cc38ff9, 0x934a14fe, 0xfe70a68b, 0xa56b9b65, - 0xa689c422, 0xa141fdbf, 0x367d85fc, 0x0bf2a0b7, 0xcef74529, 0xea8f7e46, - 0x2fed415a, 0x259f680c, 0xd8b97386, 0x5deae544, 0x2e509a23, 0xcae61e1e, - 0x0df2f2a0, 0x09644261, 0x6856fbfe, 0x3be9237f, 0x6ba50b52, 0x34786f55, - 0xfd2f4da5, 0x6fa5c944, 0x578f3756, 0xf724abf3, 0xb97e34dd, 0xf9ed5855, - 0x399edca8, 0xf388472d, 0x03136d7b, 0x233f32d9, 0xb03fcb87, 0x5d8d7952, - 0x7bf85af8, 0x0e6a7dad, 0xd2b6e28f, 0x0fa98b38, 0xfae94a91, 0xea60ef18, - 0x938d317f, 0x8b7de342, 0x0e5c1fbf, 0xe7cb0edf, 0x9fa88a0b, 0xf6626d7b, - 0xf55dd973, 0x4ddb34f4, 0x6d46f61d, 0x553b577b, 0x3cc62588, 0x2422a1e1, - 0x477914bf, 0xa432be57, 0x7ca42abc, 0xa7cfbf47, 0x1f2f3914, 0x1fc6037f, - 0x12c785d1, 0x2c3b8f0d, 0x72eb1df4, 0x44d8128f, 0xbab12dff, 0xfe09cbed, - 0x9b88c6e7, 0x55a94fd1, 0x47cdae38, 0x5f9e0ebd, 0x86345589, 0x87bbe3e5, - 0xa6f3e9eb, 0xe2c31afe, 0xced11f28, 0x89bd53e3, 0xda9e4376, 0xab9ae09b, - 0x4ba7a3c1, 0x4ebb85b7, 0x7fa0f3ea, 0xa6b12d55, 0xbeeecd7c, 0x7c0693ae, - 0xfa7fc52f, 0x3449bfd2, 0x8bc091fb, 0xdddaabfc, 0xe892307a, 0xcdf14da7, - 0x17bf5375, 0x9d1d7e0e, 0x1f75e6ed, 0x9beb4459, 0x7f3ea6af, 0xbedbe698, - 0x426cf547, 0xfdd86fbf, 0xe7fd0c4a, 0x6e0f8b9b, 0x2fd5efa7, 0xddbb89a7, - 0xc50ff35d, 0x17dd85e3, 0xfbe953a3, 0x08f643f9, 0xb9e68c31, 0x9dac7e37, - 0x5c4762e8, 0xaf78b77b, 0xef5dd6d5, 0x35b5bcef, 0xdea1aa7a, 0x3d1ad179, - 0x252f40cd, 0x8bd62fbb, 0x5f9fc65c, 0xefc2efcd, 0xc7bd7d89, 0xf4bdf4aa, - 0x5ac6fdf7, 0xc35fbd28, 0xf736bddb, 0x6e096b13, 0xcf309eff, 0xfcfb8216, - 0x682db31b, 0x728dfe7f, 0xcbcdbd2d, 0x244f5fe9, 0x8b68fc63, 0xbc7d77a4, - 0xf70b6e35, 0x7b696a53, 0x8fda1aec, 0x93ebbfa5, 0x55d290d2, 0xcfc96a5e, - 0xb76f3ac4, 0xdc002fb5, 0x46b115e7, 0xe7eaeb89, 0xdb9bb77e, 0xc9f3df9f, - 0x270fe063, 0x4f901dee, 0x41f94d64, 0x3f2a3eb9, 0xa64151ff, 0x7f3dfa8b, - 0xf80f5f4f, 0xfb9b76c2, 0xbbb7a636, 0xf7d83ca2, 0xa7187f7a, 0xb9effd16, - 0xe90fa462, 0xca5e1247, 0xb8e4fae7, 0xabbf257e, 0xfb8b68df, 0x17e0d1be, - 0xb679b7bf, 0xeffcb250, 0x31627d69, 0x6ee7ec3f, 0x4d74a1d6, 0xf89b7098, - 0xbb864ac9, 0x22ec7844, 0x030b964d, 0x228995bd, 0xc9b0befe, 0xf1117dfc, - 0xbc5f7c09, 0x5cbdfcde, 0xa56ead34, 0x98092df9, 0x3fda0bbf, 0x6bec04fe, - 0x5ec5affd, 0xff7a0514, 0x4f54cc36, 0x40fe35f8, 0x255f091f, 0xc7c11fb4, - 0x8102519e, 0xbbdf5895, 0xe8679e54, 0xa775debc, 0x2287bb70, 0xab4167ff, - 0x5b8f5d61, 0xf0913584, 0x1c2edc7a, 0x47e8f989, 0xf5fa8508, 0x6c0b0bef, - 0x0f7726a1, 0x04b92afe, 0xc231af7c, 0x5bbe0822, 0x427ce05d, 0x49f7d8ac, - 0x5d29fa32, 0x356de853, 0xe6c177c0, 0xd4e7e87d, 0xe25dfdbe, 0xf8ef54d7, - 0x58d340d8, 0xddf8eb82, 0x1ba1a7aa, 0xb1af4eb8, 0xe1014088, 0x02212ee3, - 0xf27f94f1, 0x5a62e493, 0x7cb6cf97, 0xa4625c92, 0x36cc457f, 0x129ea3d2, - 0xef3ebc24, 0xfcd2ef61, 0x305cd38e, 0x5d7ad09f, 0x57866beb, 0x2ab867c7, - 0x87a3bb6a, 0x54f740cf, 0x5577f59e, 0xf7efb178, 0xcfa002d9, 0x3c5f8dc8, - 0xb9f40f38, 0xa14ae6d7, 0xa9f66bb1, 0x2de6955e, 0x0c81a8f6, 0x4f7b639c, - 0x9ce05744, 0x52e053d9, 0xd9aef30d, 0x7ce116a3, 0x62fbbf39, 0xf7366942, - 0x44edc533, 0xa03c07fb, 0xf8e09edf, 0xf7fd5b9b, 0xccd79ff8, 0x7f65ceff, - 0xf8037090, 0x9953c6c0, 0x07c4efe0, 0x79a6e6ff, 0xc6fccf9e, 0xad10bc8e, - 0x047f4123, 0xe09bb45f, 0x2af810bc, 0x8e5c105a, 0xd037aabd, 0xa5443acd, - 0xff4f19d8, 0x09137c32, 0xf82e84be, 0x94a89e08, 0x56705d11, 0x38eddbbb, - 0xa2382f67, 0x694fc173, 0x12f29342, 0x0dc9f3b4, 0x493a5afe, 0xbf1d7f10, - 0x70cae167, 0x8a4d0bc8, 0x97be8c27, 0xdcf955ed, 0x191bdb2a, 0x3f1816c0, - 0xd2f9c9c8, 0x1840d547, 0xa3a827e5, 0xea9b30ff, 0xf547be2f, 0xfb148ed0, - 0x07f6de37, 0x8375d61b, 0x881ca04d, 0x344b5c03, 0xfdec96b8, 0x8d0a67e1, - 0x2ddf78b3, 0xe2ce3007, 0x170f1407, 0xe8edf3a8, 0x8a43c977, 0x67405788, - 0x3a46e3b6, 0xce64d85b, 0x0bad122f, 0xc1fc1554, 0x9ef09dfc, 0x96fd415c, - 0xdd730eef, 0xa102f18d, 0x4abc42e5, 0xff68d4f0, 0x3b58cacf, 0xcfd500f7, - 0x3c6768da, 0xe2170f9c, 0xb5abf608, 0x0d204135, 0x1d6326b6, 0x6bf9efcf, - 0xe6b1d632, 0x2995ff77, 0xcebf59ba, 0xaa37b4fd, 0x2148a9d7, 0xc4514eae, - 0xfba0a9b7, 0xba8a538b, 0x201b6fa9, 0x9b36c5f7, 0xca879fbf, 0x8afc6c0f, - 0x3d85c1f9, 0x6eae81be, 0xbf6bb7e8, 0x892dc3fa, 0x02e18348, 0xd716f0e9, - 0x2427d80d, 0x35be620f, 0xdb4f569b, 0x97f0f944, 0x44b9386c, 0xf793864d, - 0x42c7f60b, 0x3efabf43, 0x80be06d9, 0x0fe48474, 0x1cf201b6, 0x7b9daa3d, - 0x4c77f6db, 0x9e06e8c9, 0xd71b6ea3, 0x5c100db3, 0xd17759ef, 0x845bd05c, - 0xbe0d1fc5, 0x775ebc2d, 0xa2b3c22f, 0x5d4357d1, 0x89ef82ad, 0xfed389a2, - 0x47d385a2, 0x5139f085, 0xc05c785f, 0x620310b3, 0xf3de3f81, 0xccbecf8c, - 0xadac7f37, 0xe8357821, 0x022b1fc4, 0xeaffe85b, 0x63508746, 0x46b5ed20, - 0xce5451a3, 0x5206fbb4, 0xd503edb9, 0x1dde40a2, 0xc7a7afa0, 0xa5f7fd85, - 0x718c4673, 0x2e1ff6fd, 0xaafe8899, 0x8c22a976, 0xd3b73bfa, 0xd44e8226, - 0x7c02fda7, 0x9ec2fe1c, 0x57b4be02, 0x6b979011, 0x35ef8f28, 0x80deada3, - 0xa4772f01, 0xd50f18d8, 0x9cf29929, 0x4d0f7ab6, 0xbbcf7ea2, 0xeb90ec4a, - 0x26cb876d, 0x25b1bce2, 0xd701d896, 0x1d63c3fe, 0x58b75829, 0xd59bef2b, - 0x8f71f57b, 0x547fd0b8, 0x6f0c07ec, 0x4445b663, 0xa3c6bb53, 0xa6460161, - 0x30a1f243, 0xc18daf0d, 0x37770ef1, 0xe317e3eb, 0x2a28c493, 0x044ea9df, - 0x255ce79c, 0x2da3ac2e, 0x0aeee896, 0x4ef36f6a, 0x0dfa9abc, 0x078b8d8b, - 0xd2526b7c, 0x8abf3d78, 0xbf3865ad, 0xcfc2f122, 0x08b6b7fb, 0x65fec6f9, - 0xe9bee32a, 0x35cfde21, 0xd47e390e, 0x51cf953e, 0xe343a571, 0x4abbefdb, - 0xc9059c69, 0x0f4147be, 0xc46dfc9d, 0x39fc02ab, 0xf96162cb, 0xe735f1ac, - 0xbd21f05a, 0xa48a6cfc, 0x563d7d37, 0xc0bab2f5, 0xe8d51e3f, 0xc8ab9573, - 0xa7986f91, 0xc345b7ad, 0x78039157, 0x3a2f61da, 0x9da5f384, 0x3cdce3be, - 0x01cd3890, 0x59ea853d, 0x7aa9cfd0, 0xf47631da, 0xfc01c33b, 0x3255ea2e, - 0x8b16ed01, 0x6fd8d5da, 0x22abd78b, 0x8dabe068, 0xa2ee3936, 0x1822114b, - 0x22ee35df, 0x7f6e3f5a, 0xe9045a29, 0x970c6ddc, 0xe4a31af5, 0x452379fe, - 0xb50f9fee, 0xf969b4f9, 0x7baf997f, 0x5cfd7ccc, 0x96b61fec, 0x46fefe48, - 0xa55bf50a, 0xa1484eb4, 0xec4eadf9, 0xa7bf03b0, 0x98225dea, 0xb2f78069, - 0xa08bc679, 0x7acedc61, 0x9f3c1c97, 0x3370f5ae, 0x75f35dfc, 0xd54e1e32, - 0x7b1e3227, 0x84c93fee, 0x53feaec7, 0xbcbc784d, 0xff1e4cff, 0x77d67d54, - 0x87b43ff4, 0xf826ddfe, 0xe74dfabb, 0xdf6ec571, 0x3b97f040, 0x980fc45d, - 0x505f886e, 0x3df15db9, 0xdbe4357e, 0xe404c28f, 0x7dc2afbe, 0xfe065c83, - 0x65ce0df0, 0x4982e7d6, 0xd17eb7e0, 0xeecd69cc, 0xded0138b, 0xfb017c4d, - 0x11af2f49, 0xf8270ced, 0x3583e885, 0x7cb9bab4, 0xf4106fb7, 0x4e8e1d22, - 0xa775e679, 0x20fb42df, 0xa3dfdf6c, 0x582f8fb1, 0x2878a7db, 0x46abd96d, - 0x7c75f71a, 0xb1a7a4aa, 0x6dc8be03, 0x68d5efa5, 0xb6ef7c47, 0x020e9797, - 0xdac3aa7e, 0x81f70173, 0x8b96ff97, 0x7dabe473, 0xfbe2074b, 0xf2cfaa36, - 0xdabdbd87, 0x5d2fe863, 0x5196fcb8, 0x5533a95d, 0xefd0ffee, 0xf435f6db, - 0x89db1c03, 0x0b9209bd, 0x0a2aebab, 0x0d83c64e, 0xff07ef79, 0x58b7c412, - 0x5d3dda1f, 0xeef9031d, 0x28799243, 0x948f7c3f, 0x100f861b, 0xe40a4b01, - 0x83670fbe, 0xb08f544f, 0x470aa0bb, 0x79611de4, 0xc384623b, 0xbffd50a5, - 0xdbe397f7, 0xa1a42f21, 0xe83c617d, 0xf164caf9, 0x1b6dc9ef, 0xf04ff642, - 0x34edeabd, 0x3ada955e, 0xfbc29c65, 0x7c153f28, 0xde2fadfb, 0x04d7f4d6, - 0x9c01cfac, 0xfbcf046b, 0xa9653f5a, 0xcf502bbe, 0xe7bd68e7, 0x7337aa0a, - 0xe864df56, 0x7e9ac547, 0x52112626, 0x947e64ae, 0xe5c83b03, 0x83d4b6e7, - 0x3e7c525e, 0xd7dfc1e0, 0x35f9c1e1, 0xfa384934, 0x62455e12, 0x8d1a7520, - 0xa2d5213b, 0xc0140fdb, 0xe39b443d, 0x965afd33, 0x1939f2c7, 0xfd1d0388, - 0x4b4ee3b3, 0xfc064ef5, 0x670ffd7a, 0x75f1cbcd, 0xf2e86e73, 0xb2deddbc, - 0x57b6700c, 0xfc7f5939, 0xeed44500, 0x41615989, 0x8a7a1a35, 0xf9f40d73, - 0x0e0b91a3, 0x8c7c26f6, 0x43cdf28f, 0xbc6fb3ff, 0xcaf2357e, 0x72f77881, - 0xeb7173d0, 0xc2efd648, 0xbca3377d, 0x981be1d2, 0x373c5340, 0x062837c0, - 0xbc517c87, 0x9451275c, 0xfc2dd453, 0x45629e12, 0xe518df8e, 0xc53f472b, - 0x5d8f2396, 0x23d66f81, 0x8d106f6c, 0x739fb9bd, 0x9dde5176, 0xe1e3affc, - 0xfd8f3698, 0x25ed7136, 0x75fedf9a, 0x82069e31, 0x1bceecb7, 0xba50d417, - 0x109452d0, 0xdf704d54, 0x575d4a96, 0xf6078bfa, 0x9cee7925, 0x4ebb834d, - 0xcaeadb83, 0x50e7ee34, 0x79741bb8, 0xeb0a17e5, 0xf947fc83, 0x81b1fd17, - 0x661f29bb, 0x74c1f8b9, 0x16395b9c, 0x886c93b6, 0x7a45bda0, 0x9c1a3be4, - 0x73bed28f, 0x35f7f1c4, 0x21189ef8, 0x683e27db, 0x507ec009, 0xaf0f7634, - 0x4ed513d3, 0x15634a8f, 0x721db70b, 0xb2f0a950, 0x31d7fcfe, 0x4ad7db7f, - 0xf54e6af3, 0xddbc07dd, 0xfe496f1c, 0x0df0e180, 0x6b790a9d, 0x3fc79cb4, - 0x1e793790, 0xc6cb84d3, 0x6b589942, 0xcd31fc81, 0x50b2a725, 0xba63fb91, - 0xde30daf0, 0x7ae3e14c, 0x7bb79def, 0x07bc4fa1, 0xbee0885d, 0xfbf9f851, - 0x74e0111c, 0xfd72089e, 0xe72b449b, 0x7d137c75, 0xd24bdcdc, 0x547d27c7, - 0xc056ffc6, 0xee646efd, 0xc79a3a80, 0x650687d4, 0xdcd57eb0, 0x5df3f19b, - 0xe8d54f70, 0x6feff686, 0xbfd88eb1, 0x699fa833, 0xdfec8437, 0xf5f5bdf1, - 0xfb47f8cc, 0xa74748e8, 0x4bece4fe, 0x5b4eb878, 0x4bbcebd2, 0xc2127f59, - 0x8fd1f2c5, 0xa85b7db4, 0x5a2f453a, 0xd26e239f, 0x89960897, 0x62259663, - 0x10afafbe, 0x3ad0156f, 0x15463ebe, 0xcbd35c0d, 0xfd68a6ed, 0xe13fe94d, - 0x0f5bd833, 0xe1af608b, 0x92f0aed4, 0x8218d5ef, 0xbdba8a7b, 0x27ca9631, - 0xc6bd27f6, 0xefaeefc0, 0xfd0ac3b5, 0xf37486ee, 0x66d949f7, 0x68b267fd, - 0x94fe3152, 0xfb7ae6e1, 0xb3a22781, 0xfea553f7, 0x21888622, 0x0b7af2df, - 0x1d3e718b, 0x2fda2e93, 0x69111c10, 0x2eb18fbe, 0x75ff27cb, 0x5615c601, - 0xb7ea9f39, 0x1debb655, 0x288b7927, 0xa7ac9c50, 0xca532293, 0x4a7fc825, - 0xd3d203f2, 0xcf4e6ef5, 0xf28f79d2, 0xce1ef5f3, 0x9d15a417, 0x6b25bf40, - 0x7d62b73e, 0xf8970cee, 0x9a696f2e, 0x762ab000, 0x5a441cb7, 0x809a2c16, - 0xa1d17663, 0xef4883da, 0x6adbd4ec, 0xe1d3be59, 0xd3a345be, 0xfda6a25b, - 0xe1d68730, 0x87aa3d96, 0x4da603f3, 0x790bdc9f, 0xa27be71b, 0x444baaa3, - 0x54572433, 0x012fdeab, 0xdb6f7797, 0xdf9a78c1, 0x18a3f527, 0xbdeacfee, - 0xfa99f70c, 0x4a4e9c89, 0xe81bfa2b, 0x673e2bcc, 0xf6f26c79, 0xd5126b36, - 0x5e2af42f, 0xbd6bdbec, 0xfda01022, 0xcf26deb7, 0x0e74f581, 0xc98f1f60, - 0xade8f699, 0x67da7c02, 0x6671a34b, 0x10a4b0de, 0x55194ce3, 0x1bbd456c, - 0x201921bf, 0xbf4e8ba5, 0xf9f5ee8b, 0x76eb6957, 0xf18565ee, 0x2d33b1d8, - 0xf2c17206, 0x907d695d, 0xf5d4bf12, 0xade048dd, 0xe18592e3, 0xc11a38ec, - 0x6ede86fa, 0xe648aef9, 0xd807cb3b, 0xb760c203, 0x2ceb433c, 0x99e6f20c, - 0x36e27e67, 0xe2672b9e, 0x18fabe5a, 0x922fedfc, 0x736491bf, 0xbff011ea, - 0xa03cfdfe, 0x9c9af393, 0x24467a4d, 0xcd6abfce, 0x84fe08ae, 0x690899fc, - 0x6cf91dcf, 0x2fec58d2, 0x4e1c478c, 0xf32bfce8, 0x7f5287d9, 0x6f1aeeee, - 0x8fc2cb5b, 0xb9fca11f, 0xa36fc580, 0x689ce9f3, 0xf03bff39, 0xb64ecddf, - 0x10a9ddeb, 0xb77f383c, 0x967ce3f4, 0xc3a88d62, 0xbc022bf9, 0xb714b3bf, - 0x55f88eb5, 0xf70f73e5, 0x44bdfd03, 0xe5451838, 0x648bad2f, 0xcd92f67e, - 0xfd0eac73, 0xfbfb2a3d, 0x3d3fbdcd, 0x3de91bbe, 0xc53ff955, 0x31c5a4f2, - 0xb57ecbfe, 0xd3da0864, 0x52fa2ef9, 0xa8bf4f7f, 0x3f69c304, 0x5fef34e7, - 0x1be097d9, 0xd2cda1b6, 0xcdbcd28f, 0xa1d2034a, 0x04386e03, 0x690df3bb, - 0xb05f6e6e, 0xc24d453d, 0xf817ec36, 0xee7c07f8, 0xec81e59b, 0xf6c7cfe6, - 0xc1725d13, 0xf4e5a510, 0x2c358246, 0x8fbe68f9, 0xf3c4d7f1, 0xfa77b5d9, - 0xe604f3fb, 0xe0071241, 0xf87bb62e, 0x37f80a1c, 0xf9cf3d62, 0xd7ac3cb2, - 0x061ff915, 0x25f39d9d, 0xbd2e7078, 0x55fc7a40, 0xcacc7fa8, 0xf3717cf3, - 0xebb0d1bb, 0x1c7e90c4, 0x5e487f0e, 0xafd404fb, 0x7e16e01a, 0xb1e03f6a, - 0x3f0226eb, 0x6d773bd5, 0x1d2a7ee4, 0xe5b9e81e, 0x4c1e2ebb, 0xbd789c82, - 0x0e8064f0, 0x2ffcca77, 0x2a3d7bc7, 0xe37cb54d, 0xa47f3297, 0xa445f388, - 0xbf515a75, 0x0f47ca54, 0x689fe769, 0xc8fe65cd, 0x5aeeeda4, 0x31525faf, - 0xf8a7d7ca, 0xadaec2fb, 0xde749b9f, 0xab61a555, 0x23fb65d8, 0x3325e763, - 0x79e7be5e, 0x2dced767, 0xec87bfbd, 0xfd4e1fc2, 0x3b036cc0, 0x3cbb06fa, - 0x7f10b7a7, 0xe7e8bd01, 0x0bfb8d34, 0xef6a5fec, 0x524d3f05, 0x849d9c95, - 0xc287a48f, 0xbef8ce58, 0x598ecfe3, 0x2eb6e7cd, 0x4844d567, 0x0567c83e, - 0xe5185fb5, 0x5bf30bbb, 0xc2f39da8, 0x1c86ceea, 0x7bca2332, 0x3a57be37, - 0x073193da, 0x45ef3f3a, 0xb9255abe, 0x7720cd2b, 0xd7bee339, 0xe51759f9, - 0xbe7cc66d, 0x91b1fd6f, 0x520c6704, 0xad22cf5d, 0x9c7e5ba3, 0xfc05bdba, - 0xc93081f8, 0x980aa38f, 0x0bf3e91f, 0xda15ffed, 0x33e23ef7, 0xe279d1af, - 0x738fdc23, 0x7af2b18e, 0x3ca96abe, 0xa170e748, 0x6c84011c, 0x79ce1d8d, - 0x6fe1146f, 0xbe1553bc, 0x3d45f46e, 0x1e7af5a5, 0x2bd099f8, 0xb0af54d2, - 0xfb1dac57, 0x5bcefbf7, 0x8d47d6d5, 0xbba9f9d0, 0x37767097, 0x5bcf396f, - 0x01f447c2, 0xdf2ac65e, 0x5b0ebe6f, 0xc3ac41d1, 0x9f1e6738, 0x539ce38b, - 0xc304f98f, 0x43df187f, 0x1f3a19e7, 0xf27ef8e1, 0xe1158fd2, 0x7dff60b7, - 0xdafb676e, 0xd3eb5b5e, 0xee7c25bf, 0x81ed925d, 0xf005e89d, 0x68cff05e, - 0x7bb3cb3b, 0x7c1f84a3, 0x84d4ef65, 0x2f45ec00, 0xdf044f41, 0x79642de8, - 0x77bfacb8, 0x7f53950e, 0x5f68c2fd, 0x2f345ec0, 0x069feb42, 0x7d15fb46, - 0x52837db8, 0xda0e66fb, 0xbe6488af, 0xf9203473, 0x706c7378, 0x9bdf4a9e, - 0xa814cf3f, 0xd6045477, 0xeddea2a4, 0xe5435fd2, 0x6fd43549, 0x122192f3, - 0xf951ffce, 0xf3ce68dc, 0x32738df6, 0x4cfb671f, 0x5f6f54f3, 0x697aaff8, - 0x51bcd5eb, 0x3d83f796, 0x9429e514, 0x9b63f4a7, 0xab573fac, 0x974691f7, - 0x0f99cfb4, 0x5a44a6f8, 0xd2fde741, 0x99d2c24b, 0xc2fb7929, 0x5948f3ef, - 0xe728db06, 0xc29f5c56, 0xcbd9a3f4, 0x5b7c6b66, 0x1c0d0fef, 0xcb2f2123, - 0xb70b39bf, 0x679e8384, 0x41b78796, 0xbe5a3bee, 0xfb7a0a32, 0x0c1a9f4c, - 0xa3395c83, 0xaf29dbd0, 0xaf5c62a5, 0xd74cb71c, 0xc0a582ff, 0x0eedcbeb, - 0xf7cb3771, 0x3ea302c1, 0x556fafa5, 0xa37898cb, 0x27615cde, 0x2cf042fe, - 0x9a6df6d1, 0x7d3bd7d3, 0xebe9f404, 0xf4fa8de3, 0xe40f65a7, 0xc6d2fef2, - 0x8def5b3b, 0xb90e993f, 0xfaa7226d, 0x0f7a9d78, 0x57e74dd6, 0x25db97a0, - 0xfb6b08bd, 0xdf298b47, 0x07887b30, 0xd389eaf6, 0x1d6f4c1c, 0x1f2ce12d, - 0xf08ecc37, 0xb0d76ec2, 0x06ed8c2b, 0x83fb6b37, 0x1ba628f4, 0xee28beff, - 0xf32ed2a7, 0x3065cf95, 0x0f60bcdd, 0xe515b93c, 0x7fb3872f, 0x8e5a32b6, - 0x24bbf95b, 0x29bd2e8d, 0x5fb17aab, 0x32a5e98e, 0xe5c31dc2, 0x7a678fbf, - 0x57dc367a, 0x7d127c00, 0xd2bc5db2, 0x258ccc1e, 0xe8d31ffc, 0xfb237a0f, - 0x98a36af5, 0xf796856e, 0xf59e3cfd, 0x797f9238, 0x437ddf3c, 0x7bb3ef39, - 0x3ec42efb, 0xf0c91e5a, 0xf2c9731c, 0xbcb19563, 0xb7dfe60f, 0xc5fc30f4, - 0xbcec8ac7, 0x55ed8e5f, 0x73fade59, 0x9f841a9d, 0x9acfa75b, 0x86dfc725, - 0xe1baa8f9, 0xd4dde4a3, 0x5595fccf, 0x7e6ed093, 0x7053edc5, 0xf69af6de, - 0x4369fb29, 0x4afcf3f7, 0x97d47fb3, 0xf98c9dee, 0x760764d5, 0x1e7ea41c, - 0x116a739c, 0xee9fd3d6, 0x3ef5869b, 0xe17d6f6f, 0xeb77044f, 0x5eb23f8a, - 0x6fb47d74, 0xd85fbe26, 0x5fae1bf3, 0x16bff2bd, 0xb6afce41, 0xcfd17a4a, - 0x7e8d1ae3, 0x1e6f8645, 0x7cae57ea, 0xc881f59d, 0x7f9223ec, 0xf8fdfede, - 0x5bbde9ce, 0xdda8505e, 0xd5bd88d2, 0x5c81aa9c, 0x94676b9c, 0x0692b460, - 0xed3d4a7c, 0x8d182bac, 0xa459f175, 0x5b74b89c, 0x4b181f88, 0x7fd9a091, - 0x16d2dda8, 0xf242bf19, 0x19f41d82, 0x7d297f5a, 0xf3df7ae7, 0x9168857b, - 0xdf7763df, 0xf75cb57b, 0xfc387060, 0xb09b19ae, 0xfd76e7ee, 0x77e8d326, - 0x872f4d0d, 0xacffce57, 0xeace5fb6, 0xbdb665fb, 0xb9005ed3, 0x7d33fceb, - 0xfe76744c, 0x3f9cc1c9, 0x112bb4ad, 0x577f974a, 0x72465a78, 0x65b78d7c, - 0x07e7e424, 0xe34befb5, 0xaf82465b, 0x384e7ce9, 0xff59725a, 0x85c96acf, - 0x47f3abbe, 0xc992d451, 0x992d03df, 0x4582ff68, 0x8ff853da, 0x3a78a8e0, - 0xd2dde369, 0x0cb7e10f, 0x26e87e47, 0x1a71f5e4, 0xe91f25c2, 0xa58fbe69, - 0xf9e63b4b, 0xbd9bf639, 0x7ad07f54, 0x707ca9bb, 0x9adf9cc0, 0x03e7ed2e, - 0xfa6fe243, 0xc3fbeda9, 0x213c8e70, 0x3fd7f5ba, 0xd4f38da3, 0x3c719d53, - 0x0acfa6aa, 0x6e1f4eb7, 0x80dbdf29, 0xf13a8fef, 0xf1126b7d, 0x6398a5e5, - 0x9e5fcf2a, 0xfb494f67, 0xbe790bcd, 0xe7179c24, 0xff821781, 0x67ca5885, - 0x7892be43, 0x3e3af3d5, 0xf2bfe743, 0xb04945a3, 0xae947edf, 0x7d3cf9db, - 0xde3a9740, 0xefa46c1a, 0x2e3f4364, 0x8569382f, 0x2c49ecde, 0xdaec1ab3, - 0xd81cf3eb, 0xe4378b57, 0xd6748c39, 0x10e0adb0, 0xece21c49, 0x2007ab36, - 0xf7035837, 0xd86f7e42, 0x05f8b6a6, 0x54bc3b97, 0xc0f3acff, 0x68b7a8db, - 0xe43e6c43, 0xe2fdbd6d, 0xcb1223f5, 0xdd0e700c, 0x9c875e66, 0xd87e7316, - 0x04fe736e, 0xffde80ce, 0xa0bcbb7c, 0xc8705f39, 0x83e4ff9c, 0x9c81675b, - 0xbdff55cb, 0x3f89f42a, 0xf384384d, 0x5e17d3f1, 0x2cfac68c, 0x41d94bfd, - 0x71a149e8, 0x0a6eb422, 0x56ff08f4, 0xb2e3e985, 0xf81e9178, 0x810f1e81, - 0x93a4619d, 0x683fe10a, 0xfebcb94d, 0xcb32d119, 0x5955744b, 0x64e0bcb7, - 0x57bf5741, 0x43b3acb6, 0xb71d0bce, 0x9c2ffda7, 0x6aec375e, 0xd964a3c5, - 0xc5637555, 0xd62df809, 0xf4013bbe, 0x854bfc57, 0xe7e28ae5, 0xbe0abd07, - 0xce63b6df, 0x9ace9c0d, 0xedd0f8c8, 0x2af78b7d, 0xbbca28c1, 0x5dba4946, - 0x7d615eb8, 0x1cd1a4bd, 0x36b65747, 0xd9a6de24, 0xf778be5c, 0x9f86fffe, - 0x18f1dcbe, 0x1e5c33c7, 0x05781827, 0xa7c55b7a, 0x153ded82, 0x330dbf9b, - 0x2d79cb97, 0xbfe1e7d4, 0xaee1e396, 0xcf3a5592, 0xd0c893b7, 0x574bf0f9, - 0xe1066a51, 0x8de6aafd, 0xbd9b94aa, 0x7597ecc5, 0xb0ce39da, 0x918221ca, - 0x28a1cf04, 0xdf45d7bb, 0x628fae2f, 0x18516179, 0x9cf99fc9, 0x438e708a, - 0xdda0c4f4, 0x965477a9, 0x25e2aa83, 0x571eaa1e, 0x56c5b002, 0xfc8a48c1, - 0x04bf3213, 0xd25526de, 0x3f00d78f, 0x1798cdd6, 0xab6f524d, 0x03f706b4, - 0xc0e79d2f, 0x4abd7336, 0x38d1e79a, 0xefe659c8, 0xeb9da2d5, 0x36feecd7, - 0x60ddf8cc, 0x527d65df, 0xc8556bd7, 0x7aa70433, 0xb3cb0447, 0x402398c4, - 0xef14ab57, 0x29150ec3, 0xefa0e39d, 0x2f964e25, 0xe7946ee6, 0x838c3347, - 0x0dd78390, 0xae67b966, 0xbe04cde2, 0xd670bac4, 0x1fdca9a7, 0x64e58bde, - 0x4e484396, 0x7daa3966, 0x12e39d8e, 0x825af39b, 0x1f9ac790, 0x0ad0f148, - 0xf3e47f32, 0x96709ee8, 0x4aa79a7b, 0x5d79a7b9, 0x31ff6e1f, 0x390beb40, - 0xf9b9e25a, 0xb71e1c9e, 0x89db2a9f, 0x200f523e, 0x7a133ab9, 0x41e5c102, - 0x67472eb9, 0xb04afac5, 0x9bfcfaee, 0xe0a3db63, 0xf1e512c7, 0xd86e4bdf, - 0xed879da2, 0xf003c2eb, 0x8a549c53, 0xf60c5a0e, 0xe4325ba9, 0xac7231f9, - 0x8f56ab77, 0x966519fd, 0x80ff77a9, 0xd07b29e0, 0xe9486ee2, 0xf5e1075a, - 0x27fe6266, 0x83e785d7, 0x958e46ee, 0x7963a7f6, 0x0e479f92, 0x73bf1c17, - 0xedefd6bb, 0x9a531619, 0x48f44118, 0x942c9cfd, 0xe1a8edf6, 0xa4076c45, - 0xbbb9ba35, 0x19359038, 0xb32a9cf2, 0x9afefd17, 0xa4e9e06e, 0xde52f18b, - 0xd94cb93d, 0x72f2e124, 0x5fc8dfbc, 0xf0fdb385, 0xe8de76a4, 0x347441eb, - 0x8d71cf82, 0xe8d3ad9f, 0x74cf5d66, 0xb98ba263, 0x3741b790, 0xd8b9e473, - 0xfada5749, 0x7af0dd12, 0x485d13b7, 0x6be211ba, 0x4b742fb4, 0xdf443b79, - 0x7bb7d4ea, 0x0e88b7d0, 0x6de8c89e, 0x074217a8, 0xf1181ac2, 0x252cfc8f, - 0x2a4762a3, 0x564904b4, 0x2cdc47e1, 0xd7c646ce, 0x4ac0d65d, 0x55bfa782, - 0xab00cbae, 0x653a3ba4, 0x5cf911fc, 0xd9f88bdf, 0x0b17fbe2, 0x4e2fd52f, - 0x4ab76c12, 0x2626f927, 0xa409db8e, 0xb0aa0770, 0xf68a50e7, 0xffb231c5, - 0xc46fa262, 0x5e7f51b3, 0xdcc69c4b, 0x2a7fc246, 0xfb407e58, 0xef6e7ce8, - 0x5ef6c8b7, 0xd303a52b, 0x5f6a3ee4, 0x2bf8c615, 0x264073be, 0x58d264e8, - 0x66249d33, 0x4f41394a, 0xbadd331b, 0x7e0890dc, 0x9838d250, 0xf08699cf, - 0xd85daaa2, 0x7d48cfa7, 0x4df578a3, 0xbe004793, 0xd83de367, 0xeca7a7c2, - 0x494aff60, 0x7f1f9ce3, 0x5b653d08, 0x98df7f38, 0x780f7be9, 0x17b8ad3f, - 0x250fa2ec, 0x27b15f33, 0xcb5f7b52, 0xa3bf73d4, 0xc77f8a74, 0xa62390db, - 0xfeb950cc, 0xb9ed2114, 0x338e51a2, 0x35b9ffd9, 0x3c9bfa91, 0x94f0e15a, - 0xf25770b6, 0xb455f832, 0xd1a63df5, 0x98b84377, 0x70139cfd, 0xcd4cc80d, - 0x24821f86, 0xe4e46ed4, 0xfd5a9901, 0xc806ca31, 0xc9c70343, 0x47d7a7fd, - 0x2d37e83f, 0xcfb7ee53, 0xe7a77db4, 0xbf5caf09, 0x5b584d6c, 0x5b52345a, - 0xf3a51070, 0x039ec6b2, 0x2a94999f, 0xde07ac26, 0x4d8aaa7f, 0x317b6f0c, - 0x4ca885f3, 0x8f82f837, 0xfba65914, 0xee99836d, 0xb7b4c6db, 0xb6f949dd, - 0x7ed2392d, 0x0bf3e9a7, 0x82e5825d, 0xef9231b6, 0x64896fb5, 0xd5cc73fe, - 0xed27151a, 0x97dfac5d, 0xd7f1246a, 0xe17b86ba, 0xda752e37, 0x2c7e70db, - 0xfb3a607c, 0x499b4bfb, 0xfd5c47bf, 0x4f7eb35a, 0x6658787a, 0xa87afa37, - 0x019a0e5e, 0x55ad951d, 0x36070e98, 0x997dec78, 0xcc2e29cf, 0x4c19ccaf, - 0xf32fff07, 0xf05c7384, 0x37fb7a65, 0xb091f784, 0xba0e0b1f, 0xd7c83a1a, - 0x3716e30b, 0x1a7eb315, 0xfe63ed99, 0xbc255035, 0xd4cf1d10, 0xec126fe8, - 0xd64be0a0, 0x97d8bed6, 0xdf6865af, 0x4e995ce3, 0xbe70eba6, 0x7366d06f, - 0xb6be0265, 0x9c16e155, 0x4a5693b7, 0xe77da6fa, 0xbb80bdc0, 0xfc0222ac, - 0x7ed6b8e0, 0xd16b0afe, 0x77f7ca46, 0x1c546b08, 0xe98f2be8, 0xfbe5903b, - 0xe9f7eb0c, 0xc828c42f, 0xd76ba50d, 0xfa34b849, 0xe323d610, 0x4f9c69e3, - 0xc3e4a4b7, 0x53d3a0ae, 0x766c6b20, 0x5d0308e6, 0x1e9850cc, 0x60873e68, - 0x55979d9f, 0xfa728f92, 0x32f41fbe, 0x1d306c69, 0x6a85d871, 0x76abc725, - 0xe20f0a24, 0x3b443a87, 0x241d23cb, 0xea3f808f, 0x27e7467c, 0x475e1744, - 0xeb7ad742, 0x3d6b657c, 0xde784681, 0xf4e0ef56, 0xb0977aa9, 0x5ed84f12, - 0x67f9c89f, 0xb69cddeb, 0xf7f167d4, 0x9c3deae7, 0x8a3f59df, 0x7bd42ff3, - 0x7ebbbf39, 0xabbfa722, 0x84efe22f, 0x3a4be61f, 0x93f9d1df, 0x9f3a5f4e, - 0x05aba50a, 0x33dc6684, 0x0fccf6a0, 0x79883e75, 0xf8bbf258, 0xa9cebe93, - 0x113f914a, 0xceb450fc, 0x5428ff01, 0x22f33ecf, 0xdca3b9e1, 0x1da1f1c9, - 0x0ec1f242, 0x8dcf83a7, 0x0dd8bb64, 0x32c340fb, 0x869ddb6f, 0xb95e7873, - 0xba06ac22, 0x5c36a9bd, 0x7d740d58, 0x29ac5d73, 0xfdeebf3f, 0xff50fad7, - 0x2df18b3f, 0xbb1cfac2, 0x7fa3d4e3, 0xdf8fefa4, 0xeb033a71, 0x796c704e, - 0x1edee308, 0x2ad1c1a1, 0xceddbae1, 0x08c0d2f2, 0xcfe14fa9, 0x2d738861, - 0xfb7d894e, 0x31e70437, 0xda061d6d, 0xc146b35d, 0x754ab32e, 0x1f2aa4ad, - 0xfbe8bd63, 0x2af5b59f, 0x7c630ba9, 0xfb6a3496, 0x4cff18d4, 0x57de3cf8, - 0x78a75cb0, 0xe91f8085, 0x41ec2ff8, 0x71c41192, 0x685011c5, 0xad94851c, - 0xae17b0f9, 0xe428fd79, 0x10eea574, 0x873ed5cb, 0x8428e393, 0xd8d676df, - 0x9077529f, 0xfed689eb, 0xc8c838a6, 0xf83b5ee1, 0xeb1b6805, 0x40759256, - 0x268b9f60, 0x94f1ef85, 0xd6cbdf69, 0xe2f8a628, 0xe655337b, 0xac32878b, - 0x14ca0e9c, 0x89a5139a, 0x5e9d29cf, 0x3c707f89, 0x9e535963, 0x2f81917d, - 0x4bdf6897, 0x78a62cb3, 0x321943c7, 0x98106a2e, 0x6777a505, 0x3217daa5, - 0xdc7373df, 0x24bf5ebd, 0xea757f2b, 0xe883f470, 0x8ff6aea0, 0xddb95a64, - 0x84970ca1, 0x59e741c7, 0x74e9c714, 0x72e82e7b, 0xeff8a7cc, 0xeb3f0c95, - 0x3ecf1559, 0x7bfc2cfd, 0xe30a7f15, 0x9862a9f3, 0x0ec8df66, 0xf2ce9c8c, - 0x8ca9d78f, 0xd72dfc84, 0x7fd3fc7f, 0x547c4689, 0x57694ecd, 0x690db4a5, - 0x6ce5edf5, 0xd0f6ab57, 0x9f0388fe, 0x5fcdfb35, 0xd14ff67d, 0xf897acad, - 0x5bf8b493, 0xdeaaf78e, 0xc0e38279, 0xd0afb8f4, 0x37ca3576, 0x71eaa7ac, - 0xb63fba01, 0xf78d9f70, 0x851ecd4d, 0x5d9a98f5, 0xe7c01317, 0x4aadf66a, - 0x272e2ee8, 0x5e3d5fb4, 0xd5bfb740, 0xc39fb588, 0xc384487f, 0xffad0ff8, - 0xaf546676, 0x62054353, 0x3b60aed5, 0x1c705588, 0x8e2d72c7, 0xc19023b3, - 0xe49ee17e, 0xc4f59aed, 0xedbf49f0, 0x1063bab0, 0x88417caf, 0x53addd89, - 0x7e7920fc, 0x047da39f, 0xed85f0bf, 0x1791cb2a, 0x7ef147b6, 0xff7edea8, - 0x55dbc441, 0x8dd8566f, 0x308e2557, 0xaa77aade, 0x0fe061c2, 0xc50bb035, - 0xd2e70cf7, 0x416aa3a7, 0x145a4b5f, 0xadf816ef, 0xde98ee1d, 0x35da7806, - 0xd61a5afa, 0x45d79232, 0xf814ff83, 0x5cce419a, 0x8e7ef7b2, 0xe77aa413, - 0x6df9ae59, 0x51b3c724, 0xce036f0f, 0xd80a1b33, 0x65a4bd4f, 0x05cb3547, - 0x105d23db, 0xccdb4e69, 0xd1be29f7, 0x9346fbc6, 0x4fc0ced3, 0xaacff682, - 0x4e030f2c, 0x5ad3cbec, 0xcedeab3c, 0xb3b64832, 0x0dfb7868, 0xae88e7f6, - 0xda5a4bfa, 0xfea9d3a2, 0xe7dfbb27, 0xee4839d4, 0x23ce25e3, 0x3f4738b9, - 0xf7c919d9, 0xf9d93eed, 0xd12f09eb, 0xc65ae778, 0xfb0c52f4, 0x1b20e06c, - 0x41b73fd7, 0x25f301c6, 0x5a0fd611, 0xb6673e78, 0x27ac2927, 0x9f84df03, - 0x8f9f3b33, 0xf63ef0b6, 0xab717bff, 0xc86b15b3, 0xb2eb847d, 0x5bfe8047, - 0xed11fbb5, 0x7fe5fd9a, 0xed6affa7, 0xa4529b7b, 0x3bef238d, 0xc20e3d08, - 0xd53beda5, 0x796efbc9, 0x2fef9d94, 0xbee6182c, 0xe8f81e71, 0x518e329b, - 0x043f77f4, 0x3bc16ffd, 0x596f6cf1, 0x41f7736e, 0x36c38bfe, 0x282c13f6, - 0xa1f51cf0, 0xed9d8c7e, 0x75b1224a, 0x6dadec04, 0xa8be5229, 0x933b435c, - 0xe88fdc50, 0xacf84fcd, 0x8f84580c, 0xa50793f2, 0x523ebaf2, 0xd9daf16e, - 0xfbe413ff, 0xc2ecc792, 0xfe2f7b8f, 0x5d7ea4e7, 0x0efd2a99, 0x517f608f, - 0xcc17195a, 0x4edd878c, 0x69ca9ba3, 0x9fa06e54, 0x4cc14dca, 0xed674fc8, - 0x72891ed2, 0xf9954de8, 0x46835eb2, 0xfd07e8a7, 0xceb8a5b6, 0x2bbbbcb3, - 0xb0ef404a, 0xed2518bc, 0xdf09bf21, 0xaf386614, 0xe9241a6f, 0x07f341b8, - 0xf848b7fa, 0xf8e41700, 0x4ca6f625, 0xb8fab9c8, 0x789ba24b, 0x78dab3bc, - 0xa49a224b, 0xc78b44ff, 0xdf1e7d43, 0xd3bfd826, 0xcb1864fe, 0x1efba7cb, - 0x9fe30179, 0xc730727e, 0x04a5b411, 0xf2e6ed16, 0xaee38e70, 0x082c2a78, - 0x327b3f78, 0x9f58ed8a, 0xf61ca4d9, 0xcb025459, 0x1ea28761, 0x3afe805c, - 0xe0298736, 0xc2299fa3, 0x2df2889e, 0xa80e59bd, 0x3f63afa8, 0x17b10549, - 0x4e94afc8, 0xd9f7dc84, 0x276cc196, 0x950decfa, 0xf7d0292f, 0x13eef835, - 0xc67e0b4d, 0x3ff4bff2, 0x6fea7e9e, 0xaff3bb83, 0xdb366c54, 0xd7f5f4c3, - 0x2418efcb, 0x0c7703ed, 0xcac97a92, 0x7fe92e41, 0x30796c8b, 0xf929e795, - 0xeb03ad03, 0x131fb47f, 0xd63f6f60, 0x714127b2, 0xccc1cf02, 0xdbef035f, - 0x7a759ea4, 0x42fd8dbb, 0x79462f15, 0xe774fed9, 0xb0ef7c15, 0x78729542, - 0xdbde4585, 0x99eed0ab, 0xb2674456, 0xcdf08b7d, 0x16fb6d7a, 0x8e471b55, - 0x01d6d9fb, 0xd4109fd2, 0xf0e42ff2, 0x7149b83d, 0x2c69e6e2, 0x05c86d5f, - 0x8e6e2f5e, 0x1a79f8e4, 0x87b88bc7, 0x5cfd9f8a, 0x116633e2, 0xae7407eb, - 0xd4ae7f31, 0x9dd573f8, 0x5ee0c757, 0xe5477881, 0xad1712fb, 0xbfe03e9e, - 0x4f7af8a1, 0x5f4b63e3, 0x41f99478, 0xc417ed25, 0xfcd52d59, 0x529f4bcb, - 0xba5c9e58, 0x9887eafa, 0x136dbeef, 0xb6705fb8, 0xe368fee5, 0xf8d5ec7a, - 0x0f7b5767, 0xf54a5fd7, 0xa337fb65, 0x36ad9e19, 0x5d09e00f, 0xfeddefc7, - 0x6a5ff529, 0xf242d15f, 0xf3e5ee45, 0xdc8e28bf, 0x95f027f6, 0x676ce1ed, - 0x7be7f5a3, 0x2d6c6746, 0x33ff308b, 0xbf3384cf, 0xf72b1339, 0x9e7427fd, - 0xe780edfa, 0x5db1f787, 0x02e9bded, 0x80e2d0e7, 0xae1d5fb9, 0xafdf1afd, - 0xc0c4f78a, 0xeb45534f, 0x7d68fe81, 0xdfedc47e, 0xd0fb71b1, 0x768e3cf9, - 0xf4fb0c23, 0x9ba64899, 0xbae4fd33, 0x1076799c, 0xb16d679f, 0xde09de92, - 0x674be864, 0x1b8a6562, 0x0a87a03e, 0x3387a497, 0x1ed85a63, 0xc1d94670, - 0xb64d9b69, 0xfcd3a8ab, 0x897f44da, 0x26d01fa0, 0xb58ea9ec, 0x80c72047, - 0xe7cc8fcf, 0xcefb8834, 0xd07376a1, 0xbebfce29, 0x84dcf259, 0xcf3e0578, - 0xe3f61b7e, 0x733df0b4, 0x564f269f, 0x4fdcbf6e, 0xdcaa7588, 0xeb3fb0ae, - 0x02fe7692, 0xddba5eea, 0xa972e89f, 0x6e22f15f, 0xb2e3696b, 0xa5fba025, - 0x81e6ebb5, 0x2c79f5ee, 0xb75feed5, 0xd3c32a29, 0x27fb4e16, 0x74f1f2fb, - 0x8a59aafc, 0x5c279f1e, 0x7b45f9fa, 0x2dcb2c38, 0x4db288e9, 0xa3655fd4, - 0x49c796b2, 0x395bf5d1, 0xb84f1d3f, 0x5efb02cd, 0xb9df769b, 0x70ebf9a7, - 0x524f04f6, 0x6d4fe496, 0x6f9ef229, 0xbef25bfb, 0x0a6fc5f6, 0x81fee262, - 0xfa91c83c, 0x7f047f7a, 0x72106816, 0x96e7c68f, 0x704eaec2, 0xfb306e66, - 0x9b36b273, 0x9bb643f3, 0xcd3bd9f3, 0xe6bddcf9, 0x7355e7bc, 0x7b7185de, - 0xfa09e177, 0xa103e236, 0xbe85236f, 0xfa94ceed, 0xb7d0f236, 0xc6df4291, - 0xc8dbe877, 0x1e46df43, 0xd0f236fa, 0xdf4291b7, 0x1a39f7c6, 0x7b352a9e, - 0xe381d629, 0xeb84f6d4, 0x5fbc00f1, 0x6049cc2e, 0x52ac2a3e, 0x24b0bd1f, - 0x4ec7e59b, 0x0754d33b, 0x38f499db, 0x7ca2b7a7, 0xc37ab2e3, 0x75647b7f, - 0xc76e14df, 0xdf9ae7f6, 0x6573fb49, 0xf613b87e, 0x9f55d68e, 0x13d886ac, - 0x444df288, 0xf6b60bfd, 0x556fc0ad, 0x6fec2bdd, 0x7ee15d6f, 0xfd7207e7, - 0xc7a2eed8, 0xdce3152d, 0x7d26df03, 0x7b6fc649, 0x6a3b461c, 0xac485fa8, - 0x3f21e435, 0xa1f39b35, 0x35f0207e, 0x355f69af, 0x6e3c1d31, 0xbe0bef6b, - 0x0749e27f, 0xa13af3df, 0x6cc4edd9, 0xba63cb17, 0x8f29df3c, 0xc26ca3dd, - 0x2b24bdf9, 0x1c77db8e, 0xd3dd30ca, 0x2f4b4d0b, 0xdabcb3e5, 0x58ab5f99, - 0x8cd94e30, 0xaf59fb15, 0x73e68c4e, 0xb60d16e9, 0x0dff9041, 0x440e0f70, - 0xe868e898, 0xbf10b8b6, 0xfd533f65, 0x4353bb61, 0x4c4396fc, 0x16d7d3e5, - 0x17b5ef98, 0x1f2a6d5d, 0x878cef68, 0x96ff4873, 0xd64b9f06, 0xe7cce8b9, - 0x4bd686f9, 0x847f3c56, 0x25bc56bf, 0x9a32d3e5, 0x7b40b787, 0xfe1f239f, - 0xe014ef39, 0x16c5bcaf, 0x54bef38b, 0x9d44873b, 0xb72e5cf9, 0xae2bbf0a, - 0x5dcaee8b, 0xed4b1bc2, 0x2536b4bf, 0x71dd1d33, 0x14255934, 0x2472192d, - 0xe57d0837, 0x8246278d, 0x8dd4aaae, 0xbf2a2ec9, 0xc56c0955, 0x71d3ec45, - 0xa4ae123b, 0xf8b4fff2, 0x75a2c91e, 0xef05b64a, 0xba3e0f9d, 0xbde04d23, - 0x9f6b1391, 0x3cb8e68f, 0x6d92fe8d, 0xc1d008ae, 0xf59526c6, 0xd4cdd814, - 0xd93a2eb8, 0x011f14d8, 0x8c7ca6bd, 0x717297e2, 0x0bdf49b4, 0x9aa147c5, - 0xe69b8efd, 0x2a90f17b, 0xf36a40ef, 0xf592ee5c, 0xaf6cba45, 0xe7d7b3df, - 0x47d3527b, 0x96be362b, 0x3f7d0b79, 0x2e7f783b, 0xd65784ae, 0x2f79e6ef, - 0xdadf6cb5, 0x1d7bd297, 0xd7985dbe, 0x45c6b7f2, 0x7ce3495f, 0x87c65db9, - 0x89f9b5ff, 0x4fc4fcc7, 0xc27a6cef, 0x8541fb0e, 0x1e876035, 0x46e4fe5c, - 0xae18e23b, 0xbf91b6db, 0xcc56da2f, 0xbefd00f6, 0x7c7aa7da, 0xf28f86b3, - 0x1706cab1, 0x60ffb3cd, 0x23ca4fc9, 0xa14b1c64, 0xdc35fa3a, 0x4db8b813, - 0x66bcc3c9, 0xe3b0ed14, 0x1a3bff1e, 0x37dd09df, 0x17a7871d, 0xabbd86f6, - 0xdf20f145, 0x89993ed3, 0x0f4472cb, 0x39b92fd3, 0x0869719d, 0x0a1fd5eb, - 0x8e70bed2, 0xd7e88764, 0xcf695587, 0xad123c43, 0xd83db973, 0x85e43a6b, - 0x0ffbe597, 0x8d0e7455, 0x2ede87ca, 0x169455c4, 0x744d568d, 0xd23e335e, - 0x0b660fb4, 0xfea2bec3, 0xa67e8966, 0x69498cfc, 0xce37faa6, 0x67e21a18, - 0x672aefce, 0xe99575fe, 0xdbaa975d, 0xe3856efd, 0xbf9ac67b, 0xd33b7a53, - 0xf6a60dd9, 0xe99a6255, 0x9b25975d, 0x133c65df, 0x8fa1d995, 0x41f76b95, - 0xb4dafb66, 0x9dfcadef, 0xafda6226, 0x7f3cd303, 0x8da5e794, 0x1dba08fd, - 0x9ffe367d, 0x1979ddd6, 0x898f19d1, 0x3bd85bf8, 0xe479667c, 0x42a9eb08, - 0x669543ae, 0x92caaa8f, 0xff2aa8f6, 0x9be23b11, 0x24d6ff09, 0x93754942, - 0xaa46f6c2, 0x938a48ef, 0x7df1dbf9, 0x075ef9a7, 0xf284bbfa, 0xf6316a43, - 0x35796857, 0x42e71bcd, 0xb047ec35, 0x6bfde983, 0x19f4eafd, 0xb43ecf7a, - 0x3760df1f, 0x6d8ae7ef, 0x23f60e3b, 0x8a2f4cbc, 0x497c43cd, 0x5b54cb65, - 0x74e5f671, 0x8bfdf3a6, 0x7fb616e5, 0x857e1c75, 0xdca3ace9, 0xddf191ea, - 0xd51f18ff, 0x0d6f695e, 0x3445bfa5, 0x1799f81f, 0x013c54ed, 0x5e03d645, - 0x432e81fa, 0x0dd492f0, 0x753c74be, 0x7ca42de2, 0x1c33fe31, 0x004a11f1, - 0xbc32f27c, 0xfad478e8, 0x2c13e45f, 0x013c1267, 0x3fa42786, 0xff742a31, - 0x20efc2dd, 0x84506c74, 0x3c6ef94b, 0xed24bb4c, 0xe4d30336, 0x2977dbbc, - 0xb3ebc81e, 0x7bf9592e, 0xc914bd27, 0x9319f538, 0x93b3fbcc, 0x7ee48a7e, - 0x81297999, 0xd36ffddb, 0x8fd177d1, 0x8d099fee, 0x5defd6ff, 0xddac1a2d, - 0x46211a4b, 0xc44ffb7c, 0x4072ebaf, 0xe749e74f, 0xf0d2e379, 0xf6ed4cef, - 0x951e5e1c, 0x3edaf1ca, 0xf3a88ecd, 0x4ed69f63, 0xca98b71f, 0xefa005dd, - 0x17b009fe, 0x4b4c6eaf, 0xe317be36, 0x3b63655b, 0x788af26f, 0x5dc38b4e, - 0x8a473809, 0x4d77c857, 0x27d5df8e, 0xe388fe01, 0x26bd6cab, 0x7fc7d751, - 0xe4593c3a, 0xe9c85f20, 0xb3617589, 0x3d78768d, 0xed2c1a6d, 0x7e39fa35, - 0x7a3872ce, 0xaadff636, 0x0508d15d, 0xfdeaba5a, 0xcf3a2e91, 0x8f7c5957, - 0xef7f660f, 0x85cf3e46, 0xec2e636b, 0x513cba70, 0x0fb0aab1, 0xffcafdce, - 0x9c31e579, 0xb615befb, 0x9fa3c804, 0x840aa07d, 0xc679d0ce, 0xe1a7c472, - 0xdd3fae92, 0x10f7c912, 0x1784553f, 0xea25a6fe, 0xe9975cfe, 0x0b3bdd5c, - 0x41deffe3, 0xb8c08ee3, 0x1889ad81, 0xc4cfe3d7, 0x1915beb8, 0x57d9dd31, - 0xbd66b4f4, 0xeab6f394, 0xeecd64f6, 0x791ef90c, 0x6270f7c8, 0x1e47be41, - 0xc8523df2, 0x4dbef8f7, 0x6c0c2ff3, 0x7e83cf68, 0xb22b1fea, 0x75bcf96a, - 0xbf7e4166, 0x80f08945, 0x78a2dcff, 0xc1bc70fa, 0xc4def966, 0xd57590f2, - 0x49da6bd3, 0xedd03306, 0x84392e0f, 0x8c6e6e31, 0xc7e53588, 0xea9afa39, - 0x4c52ba17, 0x0e25d7e5, 0xef5f9536, 0x7fe533ce, 0xa9a57598, 0x18cf64fe, - 0xa347fe53, 0x9fd537ae, 0xca6a9dea, 0xc7389f4f, 0x51667f54, 0xc6fca9b1, - 0xe54c4bd9, 0x4ccb7c73, 0x3fe579f9, 0xa9bfd535, 0xdca98576, 0x9c565c2b, - 0x77a17b77, 0x865fde11, 0x2de945de, 0x8d38656f, 0x9c7a3aeb, 0x7977dba5, - 0x5072694e, 0x36dea1bf, 0xd7ee25d0, 0x68070e80, 0xc0be67f7, 0x7e1bd2b9, - 0xf522a0c9, 0x417d23de, 0x42f5a137, 0x1e4747cb, 0x35a6e8b8, 0x7a2a7a2c, - 0xc4f895a6, 0x140e2be8, 0xf57e51a4, 0xad338553, 0x5f465fc4, 0x54f9e07d, - 0xb53d37ca, 0x3b0f964a, 0x51e51170, 0xf320df4f, 0x1a8b05d3, 0x7af90c8f, - 0x31e69f86, 0x6ba907fa, 0xd26ed23d, 0xa769bc6d, 0x80f0883d, 0x01e04d78, - 0x13e89069, 0x4fa201e9, 0x7d12afa4, 0x710ba596, 0xe913e890, 0xf13fd221, - 0x7fa4f7fd, 0xfa4c3d22, 0x49b7d227, 0x847a44ff, 0xefa44ff4, 0xf4e6cfd5, - 0xb71f7a83, 0x397d43fb, 0x6beb47a7, 0xf5c7fbf9, 0xb9fe9c75, 0x5ddfcfde, - 0x433b7443, 0xba31ed90, 0x7e1aabff, 0x76edd847, 0xfd1acedb, 0x9e578ac2, - 0xb2bfbaa7, 0x46b456a1, 0x5ab69f62, 0xba394f63, 0xf33d90fc, 0x6538ab5b, - 0x0f5ebf90, 0xe10d26f7, 0x98bbfbf1, 0x8fdf6b6f, 0xf203e989, 0x520a9d69, - 0x9f28297d, 0x2aba5f99, 0x0fc7f886, 0x81b5a9be, 0x74b43e5e, 0x0bfb7f7f, - 0x87da4e8d, 0x8c873378, 0xebbbf2e8, 0xf8ceef7e, 0x1e5f831a, 0x8e3d6cfe, - 0xf3c7f747, 0x473e219f, 0xf1eb93f7, 0xef6ad741, 0x707ee923, 0xef47fe3d, - 0x6092f0b7, 0x1acd77be, 0x512dcb2b, 0x38c41156, 0x35cf9c7a, 0xc43c968e, - 0xe9535c3b, 0x3eb738e4, 0x23ef1df4, 0xde2f3d52, 0x25fcdb99, 0xf2edcfd5, - 0xe6d1f7bb, 0x8f3ce541, 0xb63e4bc2, 0xc5a35ed7, 0x43bda01d, 0x753bf396, - 0xfc831188, 0xe1db2941, 0x7da8551e, 0x001c577e, 0xfaca47ea, 0xfe97f441, - 0xdd178d15, 0xc4068fb5, 0x6e21e4b5, 0x93b5406c, 0x8c36c6e3, 0xb9bdf209, - 0xded7b1e9, 0x4e22aad3, 0xd8c7e638, 0xfaa74f47, 0xefcf0266, 0xf00f73ee, - 0x5c5a7e50, 0x53a46f5a, 0xebb5de43, 0x62e67d66, 0xe97c755d, 0x4bd7d778, - 0x9e21b7c7, 0x5dfcf18a, 0x6eba17eb, 0xafa5eba1, 0x2ea5e153, 0x977f03fc, - 0xfad74faf, 0xfffb3ec1, 0xb70cfacb, 0xcc7df0b6, 0x07874ab0, 0x7ad77d70, - 0x262edcdd, 0xf1783ee0, 0xa441f725, 0x5f7cd24b, 0x8a967f80, 0xc05c1331, - 0x81cd4b91, 0xdeb4279d, 0xef59eff2, 0x077a90e1, 0x7cd60ae2, 0xbd79769d, - 0x1af521dd, 0x7ed60b62, 0x374ced2d, 0xe43d7ce2, 0xed1fb1b6, 0x1e3d70cd, - 0xa3ccebc3, 0xf1a71c75, 0x96a243a3, 0xd7120fcf, 0xf1df58fc, 0xcb8f52da, - 0xee72cc5e, 0x6e59a778, 0x514df09c, 0xd09dc623, 0xd68e442b, 0x6837e1fc, - 0x9a275efd, 0x7bd0dfb8, 0xf26837f2, 0xf93de869, 0xf26886e7, 0x01488a65, - 0x3c2f1a9f, 0xbded2e12, 0xd92ef183, 0x2f46926f, 0x8c556e69, 0x9f083d06, - 0x55f1cc15, 0x8b9077bc, 0xbf9cfd71, 0xfd38045e, 0x3f7208a1, 0x22918993, - 0x6c2123ff, 0x79039df2, 0xf55ab33f, 0x2ce427fd, 0xc2e65efd, 0xd8abdf70, - 0x4e44af77, 0x28f78f99, 0x4b8c15c6, 0xe303bb47, 0x1c9f2cdd, 0xbcb1a470, - 0x8b657d84, 0x6f7fdaeb, 0x6e92f9d0, 0x9106f795, 0x3a60dee2, 0xe9d7966d, - 0x86fe41fc, 0xed0215ac, 0x71cdb826, 0x1ffb7a38, 0x6b0ac6ba, 0xfdfccf41, - 0xfa7bb987, 0x66f3aec3, 0xb0f1a0ec, 0x7b19bf83, 0xf7cc78c5, 0x163ed8cd, - 0x39d98699, 0xbd3179cd, 0xa74e793b, 0x26f1aee7, 0xcf7c6b08, 0x1af1d678, - 0xcf1d4f8a, 0x2f5e02ff, 0x2fd78774, 0x37290b06, 0xa23e4a47, 0xac2ab7e3, - 0x1f671ef3, 0xa5445c63, 0x33e9e243, 0xb87b8c80, 0x3cf15775, 0xfd17a93e, - 0x7545ef81, 0xd43cb8a3, 0xc736250e, 0xc77f5e70, 0xef83ccec, 0x7c122746, - 0xea7c39d7, 0xd9cbc250, 0x492660fc, 0x0d93e230, 0xfaef7c0d, 0x07aab3dc, - 0xeaa57ff2, 0x4f01eb5e, 0x3f655379, 0x95e6f8a0, 0xc509f864, 0xa3e3eee6, - 0xaf121d2b, 0x32b3feba, 0xa7f788ad, 0xca241570, 0x3de4d5f7, 0xe81e5d72, - 0x8be3261f, 0x3dccfbf5, 0x232307c9, 0x1feb1f24, 0xbeaef926, 0xf38ed49e, - 0x48cfd449, 0xf74953e2, 0xb03eb045, 0x1a4de5db, 0x78ca7f0a, 0x75a79261, - 0x97a3bfbd, 0x5af03f7c, 0x68d0f991, 0x643f8fca, 0xef2a0113, 0xf14c2f18, - 0x946f8564, 0xfa16bbf2, 0x44b098fd, 0xfc0cafd2, 0x611ddc20, 0x32346f7a, - 0x8f94ce2b, 0xd533f4f2, 0x6a95198f, 0x0ef58f2a, 0x4fc79531, 0x7be537cc, - 0xaa655d17, 0x58f667df, 0xefafbe53, 0xa4fd5306, 0xbca669f2, 0xe49297ce, - 0x76a03127, 0xc0fda9ae, 0xfd5312ba, 0xf9857f14, 0xf7bf54fd, 0x9e025648, - 0x697f9477, 0xbc87966b, 0x96116aaf, 0x90ef5d91, 0xde5a3afc, 0x5ce89907, - 0x6491efc4, 0x0cccfd34, 0x8a8dfa8f, 0x46292673, 0xae24f7e1, 0x60f99b73, - 0x3f39a261, 0x2af795de, 0x2b9c6e96, 0xa828fe34, 0x6a929e80, 0xf3efa6ad, - 0x347c6a86, 0x9eb2e457, 0xefeb5dfe, 0xff5a621b, 0x4e5d7c50, 0x05e7cf0f, - 0x6f9ed2dd, 0xf9ec179c, 0x9ec0bc46, 0x9ec3cc6f, 0x7b0fac6f, 0xf61cb1be, - 0xc179637c, 0x8c1d3321, 0x83a66238, 0xe99a8e2b, 0xd0cfa740, 0xd5b2baf5, - 0xa7c21f4c, 0xb07f94f8, 0x6a7f575e, 0xf5d09fa6, 0xd78b0921, 0x1153826f, - 0xfbfca48f, 0x642eb5eb, 0x87d73abd, 0xf6f90df0, 0xbe50e0da, 0x48785b27, - 0xe4b77815, 0xd79e6d51, 0x27e5ad0d, 0x7d5bb6c3, 0xae7de6bf, 0x5f4355d1, - 0x871d5749, 0x1f070f9e, 0xffa4347d, 0x02f9fbd7, 0xfe3b3fa8, 0xf41db262, - 0x45df2ed1, 0xee1f036b, 0x49b715dd, 0x77bcba7a, 0xe39533f2, 0x9a598e18, - 0x82ebf014, 0xf036df18, 0x6bb39bcb, 0x1367f815, 0x458ed145, 0x8ff9cb88, - 0x17e464b0, 0x77f7940c, 0xdf2b7645, 0xe2f9d07f, 0x17192482, 0xf35432d8, - 0xdc647af3, 0xa543f3ce, 0xe3ca24dd, 0xe2e338e2, 0x83bf796c, 0x05e499d4, - 0xe1c7c039, 0x47c041f0, 0x69df85b3, 0x39b9b56c, 0x86ffc46e, 0x83f7e02a, - 0x72f90b1c, 0x35df2680, 0x0070e47c, 0x85eb41fe, 0x1c1d9ce9, 0x5be29870, - 0x99736e87, 0x892d39f2, 0x76c3faa6, 0x79e54dbb, 0x79532cc1, 0x298f21c1, - 0x28c8e23f, 0x8e2bfd53, 0x2bf94d7a, 0xea9a275b, 0x9169fd5f, 0xda249f29, - 0x077e061f, 0x3e8f522a, 0xe2553433, 0x7e382dc9, 0xb19dc16f, 0xa6a7def2, - 0xba72eb5f, 0xd3ecf71e, 0xde5439e8, 0x71f7681f, 0x5f43751c, 0x187be1e1, - 0x129f4d0e, 0xa7c03d66, 0xde772dc5, 0xe39bf0a3, 0xe578f596, 0xd3417d4e, - 0xdd39740f, 0x35ecaf10, 0x082f2bc6, 0xe03dfeeb, 0x3dd6d2ff, 0x7681fe14, - 0x9f86df39, 0x88def9da, 0x3c28570e, 0xda38b533, 0xefee8e2d, 0x25b2d8f5, - 0x1465259d, 0xfef41dfd, 0xcad3cd98, 0x365fdd6f, 0x4fd5a79e, 0x0bf0d5f4, - 0xfba567bb, 0x305bc7bb, 0xbe67ce4c, 0xd4f372c5, 0x32cf8e6c, 0x3bdf83bd, - 0x51fdea5b, 0xf3b74ab9, 0xe323105b, 0xdd8c44a7, 0x79edfa0d, 0x44cf893c, - 0xfbe468bb, 0xff9c5a47, 0xee5b6b4d, 0xf3454419, 0x7bda4ded, 0xe81b0160, - 0x9258d261, 0xd884f2c3, 0xb35765b6, 0xc7a2e493, 0x3f6cacea, 0x35ddbfe9, - 0xceb8248b, 0x49031bfb, 0x407d01ef, 0xb4be81b6, 0x71e54721, 0x1b9ec1ae, - 0x4df6fd81, 0xfb3d9c67, 0xced08405, 0x754fa90b, 0x874c6f43, 0xaffe3cfa, - 0xf143ede3, 0x42adeba4, 0xd74c338b, 0xd7f1d2e0, 0xf0d07769, 0x707fdfa7, - 0x6d15b32f, 0x8a3df272, 0xd2db8889, 0x4725afd7, 0x86ad65d2, 0x3f03d40f, - 0xa15ea9ea, 0xfb031d9a, 0xc7708772, 0x43a1bab8, 0xc2bffd3d, 0x9eff8e8b, - 0xc4f557ee, 0xc2f9421f, 0xeab7dd77, 0xd9ff4e89, 0x3e06577b, 0xb468e321, - 0x5ba40975, 0x677d3fd8, 0x6f3f7994, 0x8d7696cc, 0xa2beda71, 0x6799ddf3, - 0xf60217e6, 0xaa5586f1, 0x39e42fc6, 0xc4529c5e, 0x3a8b11ef, 0xe533cb17, - 0xcfd62f1a, 0xc80f85d7, 0xf5aee0f7, 0x455c2516, 0x9b6692f9, 0x15a048d8, - 0xf38fbbfb, 0x1b93bf66, 0x449efe71, 0x3726cdc0, 0x49b4b71a, 0xb94fec09, - 0xc5ecbdfc, 0x5c7ef94e, 0x8bd9bbe8, 0x2f17fd35, 0x86df602a, 0xcfee65fa, - 0x8f6bced6, 0xe12b7cf0, 0x0ba5bd67, 0x02de8d7e, 0xe8311df2, 0xf3b4aac3, - 0x8e969c70, 0x24fc3737, 0xc2795df1, 0xce16446f, 0xb76b46f3, 0xf89d7471, - 0x9d2afdd5, 0x1cc3c27e, 0x171a1faf, 0x4affd670, 0x1a7e7774, 0xd3d37fdd, - 0xdff4e83e, 0xa85f877c, 0x1e8969c3, 0xff043e05, 0x57e8dbbf, 0x8248f3f9, - 0x3127fd90, 0x6ab48ff0, 0xb98d89fd, 0xf44fdddd, 0xf1c5d8ad, 0xbe2cab10, - 0xf25c40ff, 0xef1fea19, 0x3ce5deb0, 0xf8fb8090, 0xd3bb3493, 0xe4d6f3e5, - 0x7ef2d1b0, 0xe55f8740, 0x2898eef5, 0x1f1373ef, 0xba77d815, 0x08aa7f1f, - 0xfbaa42f6, 0x466b7c49, 0x3f75fe31, 0x14707149, 0x61b339c3, 0x484f0db1, - 0x7b7c3eb6, 0xcbbb8461, 0x403ad27f, 0xe4f4e7c6, 0xc97e9947, 0xb8cdfdc3, - 0x73f71574, 0xca453b2c, 0x2cf78d6b, 0xd90d9d03, 0x67986c26, 0xdffbadab, - 0x23929819, 0xf852d1f7, 0xe21b7bd2, 0xac28567e, 0x84572c07, 0x7cc4071e, - 0x6c5fcf5e, 0x3285f2d2, 0x992acb7f, 0xc5ded56f, 0x3bd9aada, 0x98a44f30, - 0xedf0f40f, 0xf3043d9a, 0xe0798a40, 0xf21af83b, 0x83c86be0, 0xbe0f21af, - 0x0d7c1486, 0x51444bdf, 0xfd2a9e72, 0xfb0de33d, 0xf19efe03, 0xfe09b906, - 0xfe1e631e, 0xf87d631e, 0xf0e58c7b, 0xe1cb18f7, 0xe1e631ef, 0x87d631ef, - 0x8798c7bf, 0x1f58c7bf, 0x1e631efe, 0x7d631efe, 0xe58c7bf8, 0xcb18f7f0, - 0xe631efe1, 0xd631efe1, 0x58c7bf87, 0x629d737e, 0xacdd07f2, 0xba503bbd, - 0xa3e98e3e, 0x2928b539, 0x3ff7d687, 0xc7e7ff23, 0xf3ac54b6, 0x6efc25de, - 0x47845560, 0x44d373ae, 0x2116eeb9, 0x0e7db9d7, 0x76edf3af, 0xf1942f99, - 0x03f4a1c2, 0x74f8cabf, 0x0a4157e9, 0xf8520abf, 0xafc29055, 0xfd2ade32, - 0x57e1482a, 0x55f877c1, 0x82afc290, 0xa4157e14, 0x8520abf0, 0xfc29055f, - 0xbf07682a, 0x55f8520a, 0x157e1df0, 0xe0abf0a4, 0x038231fb, 0x2e1d15fe, - 0x26e9f9c8, 0xd0e8943d, 0x4cba87a4, 0xc6f9c879, 0x8df390fa, 0x8df390e5, - 0x8df390e5, 0xc6f9c879, 0x8df390fa, 0x88f11bf9, 0xef296f71, 0xde41db1b, - 0x9a73e637, 0x86c1affc, 0xf9c37935, 0x46b69157, 0x2e298f29, 0x9e72eb92, - 0x58ff059a, 0x1c92b86b, 0x763921eb, 0x8d676fc5, 0x89f892bf, 0x2b976f16, - 0x6f582dda, 0xbad37bf6, 0xe38282f9, 0x3bfe7383, 0x7f75cb91, 0xbad1ff2b, - 0xac14ede7, 0x90cb6c37, 0x3dede970, 0xd522a5c2, 0xbbe577eb, 0xbe3a17af, - 0xa5f98f5e, 0x28520e01, 0x910710f3, 0x1f33bb77, 0x2d5bedf1, 0x5d0b8c8a, - 0x4372e329, 0xe349aae9, 0x3b2d5b4b, 0xbb50440e, 0x83c562f6, 0x5699077b, - 0x0f96c871, 0x43e6d53c, 0x89cba89e, 0x6b83e2d5, 0x903c42af, 0x7f6eb70e, - 0xf7c13e24, 0x0bb746dd, 0x738d197b, 0x8ec217cd, 0x64985bdf, 0xda04f297, - 0xea1cdf41, 0x0c9bbc57, 0x4732bdf4, 0xff3e7b9e, 0xe8caabb2, 0xb5edd0fb, - 0xdd1ee157, 0xeed908a4, 0x33478f37, 0x2a34a71e, 0xc9fef09b, 0x8bc2ede8, - 0xd4bfb1fb, 0xddba1ee0, 0x71e32f65, 0x4eff7c5d, 0x4378b7ef, 0x2c17df32, - 0x13e3ad16, 0xf0a127d9, 0xde3ae6fb, 0x62af7e68, 0x0fe2c47e, 0x2ffc8ec1, - 0x7121c3df, 0xc3dcfbf1, 0x6c7866b9, 0xc4dbe221, 0xe40ef95e, 0xabc5e1e4, - 0xbe5c137a, 0xf2077c80, 0x5f6a2f9a, 0xf966fce3, 0xcf93240e, 0xcf8f8648, - 0x857e41c3, 0xe298ffdf, 0xe5e968df, 0x15e0bdc6, 0xdfd404b6, 0x0b503c2e, - 0xaf790906, 0xb6579f55, 0x57096238, 0x95e22f40, 0x11fd0378, 0x7a0198e7, - 0xf8d8f3c9, 0x56a9907d, 0x46fc0d97, 0x5d8a7397, 0x7542ec72, 0xf7df0c74, - 0x2e13910b, 0xb8e6f636, 0x8e3d7f8d, 0x93ef83a4, 0xce15df2f, 0xf88f8572, - 0xb9e6f807, 0x5977193c, 0x91c3ecb9, 0x38aed496, 0x8129d392, 0xf3df78ad, - 0xe88eea74, 0x11cb0a51, 0xdb5fc087, 0x7be79f1a, 0x5eabc582, 0x1710fbe3, - 0x96881f1b, 0x7fa4aaf7, 0x9bc34ca5, 0xa85a6f6e, 0x16994fad, 0x5ebc743f, - 0xe74bcfbe, 0x71f7bf30, 0x72c6d1b1, 0x28bca846, 0x880feb84, 0xb46f2b73, - 0xc5d3ddf1, 0x27578b6b, 0x777eee8a, 0xcfe32bc5, 0x349771b5, 0xa84e38da, - 0x2b477b5c, 0x965877f4, 0xd2e8726a, 0x27efe66d, 0x4fe44272, 0xad44fdfd, - 0xaf5bf14e, 0xa83964cc, 0xee71c6d6, 0xb94857f3, 0x0110ec48, 0xbf9867dc, - 0xef059c62, 0xe5dfcc58, 0xd0dd28f5, 0x7c9a3bd1, 0x12830934, 0x8a5ea7de, - 0xed32be60, 0xcfce3f52, 0xe9c894ba, 0xe4b2978d, 0xd11dac77, 0xbca16b4b, - 0x26beff5f, 0x1c44cd17, 0xb2e40165, 0x1dd74c3e, 0x2218d744, 0x4357e357, - 0x302bcabc, 0xf9b24fc3, 0x734e2156, 0xf7c146d2, 0x7e432691, 0x90d982a2, - 0x2fb00aa7, 0x3ef90a52, 0xef8544c6, 0xbe1e4cb7, 0xb407db4c, 0x11f3042f, - 0x37c3f77e, 0xf1006a7e, 0x3b7db337, 0x7d77582c, 0x6dfcf83f, 0x64e60efc, - 0x7bc762bf, 0xcf4d3e81, 0x743de9d6, 0xd4882c5f, 0x694e63ec, 0x8fb4eaff, - 0x9c7e5801, 0xc446f227, 0x2d802eb3, 0xb0b69fb3, 0x6ca8aa84, 0x1b9c9e59, - 0x94236379, 0x6ed37fac, 0x9162df32, 0xfe489ff7, 0x717578e3, 0xe50fb0a4, - 0xf92ad78b, 0xe1d79788, 0xd8d87afa, 0x777ac349, 0xe74941d1, 0x03eeccfe, - 0x5df960bd, 0x4cff2619, 0xf84a5a68, 0x105a3ec6, 0xfc63fad3, 0x5c84d0d2, - 0x889f1de1, 0xf9f5c877, 0x02e2208a, 0xdbf96ae7, 0x8ff2bd9e, 0x278c9c6b, - 0xedcd8fce, 0x3fe22377, 0x38fe65fe, 0x7f1ab15f, 0xf14daa37, 0x3de57379, - 0xdf5809c8, 0x7e76ecc8, 0xa66660c7, 0x212f9e4b, 0x72db9676, 0x845df2dd, - 0x694b7b10, 0x846f3cb6, 0x8f3c9dd5, 0xb66e3afd, 0x3ef3ea57, 0x33df336e, - 0x5cead3d5, 0xbff83769, 0xa0f127ba, 0x7ffbde45, 0xf1d812c4, 0xa06bd122, - 0xe6016fb7, 0xbde208fb, 0xcf1f7e19, 0xa3477f4f, 0xef694f93, 0x74f4e865, - 0xdf22eeac, 0xda712897, 0x9e81aadd, 0x7c28d6ca, 0x4ea4b11f, 0xadf627de, - 0xfcbde451, 0x8f57ec1e, 0xdf9af9cf, 0x17fc7a51, 0xc350b211, 0x91fb7cef, - 0x5d291cd7, 0xdd53fdf8, 0x7f926caf, 0x6f103306, 0x9c36b73f, 0x7afe41df, - 0x018fd158, 0x87b6647f, 0xf11269d7, 0x1a9fd434, 0xbe29fbe3, 0x07238897, - 0xf05c6f61, 0x7df8b7f3, 0x29bd9ae1, 0xf161eefc, 0x78d5bcee, 0x61ebe547, - 0x89723bbe, 0x2e9d8b7e, 0xea90e43b, 0x973e58c6, 0xeed1f417, 0xf6768ba9, - 0xf3ebe9e7, 0x0794ae60, 0x9c723c8a, 0x453e9a0b, 0x354db308, 0x7fe793d5, - 0xedd43ee8, 0x95f6a1a2, 0xbe2af7d0, 0x7b029ecb, 0x5760dd89, 0xb631edd5, - 0x7073e3ac, 0x77b7cf9e, 0xaf8dbbff, 0x4d4776eb, 0xa9d85d9f, 0xe84f66cf, - 0x9d7fb903, 0xbd1d82e2, 0x11bee9cc, 0x8765f5f1, 0x14f0886c, 0xf2dce293, - 0xe4bb92dd, 0xb72525bb, 0x9b3f31e6, 0xc7c9358f, 0xbc5187bd, 0x9402cb8f, - 0xdfbcf7c6, 0x657bade7, 0x53d01ec0, 0xe0f7cbd0, 0x7b5e5ccb, 0x2a2e419c, - 0xef4c526d, 0x17f9e818, 0x721da573, 0xc019a93e, 0xa6b74ddf, 0xd086f1d8, - 0x108f127c, 0x46baf837, 0xaa3b7a27, 0x932571c7, 0xf941c552, 0x9dc114ae, - 0xfe33c722, 0x9349514e, 0xaa063df9, 0xfedd72cf, 0xafee28dc, 0x4ef345d8, - 0x3862ea41, 0xa78c0f09, 0x3fa87bf6, 0xebc38f37, 0xd80c1a51, 0x8f983760, - 0xcfca1678, 0x186c0575, 0xbe51a4a7, 0x2b5be28f, 0x89adf1c7, 0x2e40e7b5, - 0x03ecbab0, 0xa360f28c, 0xbe78cf7c, 0x0411fbf6, 0x65cbcb2f, 0xf3dc2784, - 0x867defd2, 0x8358abe2, 0xd629acbf, 0xad365f2c, 0xe67d61b3, 0xc35ef0f4, - 0x971d1a97, 0xfbe18e34, 0x2f5665f5, 0x69f097df, 0xb2ebfef8, 0x27e1bbf0, - 0x90fcd399, 0x8d79052d, 0x3c097d2f, 0x829e06f7, 0xd23efc19, 0x678e70b2, - 0xe26ae39e, 0xfbe276f9, 0xe40fc201, 0xe3115715, 0x8fc4e89b, 0x66b2c038, - 0xc176faf3, 0x65df2513, 0xfde62e6f, 0xb3eac8b7, 0xac708cbb, 0xfb819fdf, - 0xdf68735b, 0xe127fde3, 0xcc7df1f2, 0xc8dc0f53, 0x3806fbbf, 0x8f28e781, - 0x3bde027b, 0xba61ba22, 0x4167e9d6, 0xfacfdc81, 0xacc35178, 0xec3f0ed2, - 0xf7a9f6bb, 0x06f3e420, 0xffd86f5a, 0x76a7da7b, 0x71a4005c, 0xddf265ed, - 0xab7dd0ba, 0x9f7d57ef, 0xdf56fbea, 0x8ad98fcf, 0x174a8982, 0xbdf3a1df, - 0xf06eb9f6, 0x77834934, 0x84aeb6ae, 0xc18557d7, 0x986237ae, 0x53f3dfdc, - 0xfd1ffbcd, 0xbd54dfa1, 0x03306c7c, 0xfaf53df7, 0xe3f3b8fa, 0x03ec3b64, - 0x30ea5bd0, 0xe5fd674b, 0xe262df5c, 0xfc9da51f, 0x04aafb63, 0x0a1d8ff0, - 0xdf96e1fb, 0xe5bee523, 0xe17bc8cf, 0xf8bf9667, 0x77aa2cf6, 0x0b8dc1fa, - 0xca2ff78c, 0x2c5f9282, 0xfc0b7924, 0x0f269163, 0xe5f4cc6c, 0xe7ec330d, - 0xc99ffbb2, 0xdb98fec4, 0x6f0a7792, 0xf9bcd1a8, 0x3f3fa3bd, 0x5787d2f3, - 0x5dcebbb9, 0x6b251e7d, 0x3b15b5de, 0xf493788d, 0x0756777e, 0x38a55b9f, - 0x6953e8b7, 0x61f33163, 0x8f7a4891, 0xa1eeb5d2, 0xa8dc50f4, 0x5a579cb0, - 0xfea03237, 0xd2ebf22f, 0x8df953b5, 0xf4bd7d28, 0x73f45f77, 0xa67f8757, - 0x35734eb6, 0x4c3d9e7a, 0xe5b9c3ee, 0xbc45f629, 0xf8ec53ff, 0x5a39cdbd, - 0xf3329cf9, 0x72f5cef7, 0xd5fbf275, 0x9fb827d8, 0x58eaf584, 0xcbf6936b, - 0x57ad97ed, 0x1d02e432, 0x9d9ac58e, 0x6f66a172, 0xcbc9a45c, 0x8d8b5eb4, - 0x71f8b5eb, 0xcfa55eb9, 0xbc17f5be, 0xd3f34653, 0xef93a3de, 0xecb4940a, - 0xb39b75e0, 0x852d9d66, 0x5864fdea, 0xa8fe298a, 0x05cf36b4, 0x35dcfd3b, - 0x07e06d1b, 0xf126193f, 0xf3f74a16, 0x1d62f8b5, 0x148f38af, 0xaf473f83, - 0x83b83e0f, 0x5975b9c6, 0x77f1b478, 0x3d1a02ed, 0xc6c6d697, 0xdad2bc61, - 0x7fa17be2, 0xe840e7e9, 0x2e113bfe, 0xf50945f7, 0x6279fd87, 0x55ef878c, - 0x377ed7cf, 0x43feb42f, 0xdafddd1a, 0x4cbfdf26, 0x92796c8a, 0x226a3be3, - 0xe913e03c, 0x8c01ade9, 0xdc067a0b, 0x2f7c8b76, 0xf5b2bd33, 0xa241c073, - 0x20f5c73c, 0x105b7bc5, 0xbf2813ed, 0x79ef22c9, 0xdd32aaa5, 0xa607e1a7, - 0x5e8b9437, 0x5f1efcad, 0x2151bbe7, 0x9b176af4, 0x1fdde0d7, 0xefc12f7b, - 0xa9f4e9a6, 0xa7d3a3f7, 0xcd3dbf4e, 0x9cf7d76f, 0xcd1489df, 0x49e592ce, - 0x0bb8d076, 0xbfc41bee, 0xf35df16b, 0x35ef6bb4, 0x4c37ce76, 0x65c7defe, - 0xfa974df3, 0x6df3cf52, 0x66e84c2e, 0xd4f3a1be, 0x431e89f7, 0x694fe9df, - 0x1394fe92, 0xd4639d0a, 0x70b2c4ee, 0xe7d3ab8e, 0xbff5dba5, 0x8f87bdef, - 0xf669c586, 0xc828d6aa, 0xdfb5f397, 0x99411151, 0x86a9f7c7, 0xaff9faef, - 0xf3a75fbf, 0xdab593e9, 0xef5a28f9, 0x75167ec1, 0xf50f7c69, 0x2889d358, - 0x627313bc, 0x6f4f848c, 0xde4dab77, 0x76511673, 0xbbcfde37, 0xfe3cd6e9, - 0x8d8594bd, 0xbd9f587d, 0xf98d2ea9, 0x587e4dc2, 0x1ea74517, 0x83e348b0, - 0xaf16b791, 0xd7f502be, 0xc2eff0a7, 0x4e7a742d, 0x43f6e7ad, 0x2313903d, - 0x53daa79b, 0xfa961e59, 0xbb17ee82, 0x7c451155, 0x127c0d4f, 0x3fb2cbfb, - 0xe2cfe71d, 0x983f52f5, 0xe06b1164, 0x50d81d3f, 0xf82fa134, 0xfc8ac3c4, - 0xe60d9a3d, 0x0e86bcf7, 0x7c02fa2a, 0xbc5df426, 0x5e2d6d5b, 0xe482a7e8, - 0x16d1d80e, 0x9e588b3a, 0x93e345bf, 0xf8db9ac7, 0xaf1d7ebd, 0x78bfe08f, - 0x7ec42aa7, 0x1a276a14, 0xff07d9a8, 0x7b8faf1f, 0x0080003d, 0x00000000, - 0x00088b1f, 0x00000000, 0x7cb5ff00, 0x65545c0b, 0xce7bf8da, 0xc0cc2b99, - 0x1245c880, 0x85848b87, 0xd780c034, 0x508151da, 0xb9bba0bb, 0x658e21ba, - 0x500665ca, 0xd7775ddb, 0xa6a18cfe, 0x45fa7d66, 0x80ed65a6, 0x76c36a97, - 0xa8283448, 0x59990bc9, 0x6a37627f, 0x5b63b92f, 0xba402de6, 0x6dbfedfc, - 0xbcf3cf7d, 0x511730e7, 0x6fbefddb, 0x797bf9fc, 0x9f5ef3df, 0xcfbcf3fb, - 0x8c346339, 0x63181b75, 0x418e8b2a, 0x89486839, 0x8d8c9964, 0x615f6909, - 0xf6c3894c, 0xc645db25, 0x7cfb4046, 0x1962c893, 0xfa31d72b, 0x1fbf8f7d, - 0x3c1f7631, 0x42f3c337, 0x07d634a9, 0xcc37d7fd, 0xd6c972a0, 0xf1ae6dc2, - 0x2509258c, 0x606393b1, 0xb66ae3c0, 0xce258a07, 0x2b307719, 0x8da4d3cc, - 0x73c325d2, 0xc7292bb5, 0x496f9fe0, 0x0c4943e3, 0xd4699dc6, 0x7b4377cf, - 0x414e6981, 0xba5f8c14, 0x325b2a33, 0x6f5dfbfb, 0xc91b1811, 0x4673a558, - 0xcc614b1c, 0x67e1ddf1, 0x1fb0a94c, 0xf304d398, 0x7709e57f, 0xa38ba0bb, - 0x82492dae, 0xb3aa3c23, 0x7fa058a7, 0x6f31d895, 0x4e73cc12, 0xa04def70, - 0x5338e6fe, 0xe5a1fac0, 0xccc63ae9, 0xff398ce9, 0xcf3487cf, 0x3b89e2e7, - 0x8778c016, 0xce047f73, 0x1ff8f553, 0x6c3201f2, 0xb2cf689d, 0x8dbce1e4, - 0x1c124d7b, 0x56637b74, 0xbee39c09, 0xda46c7c7, 0xf79f2f33, 0xa8b668b6, - 0xdbcbda04, 0x6957c118, 0xd48ee85f, 0x5eeddc20, 0x696131a6, 0x28689a62, - 0x956c48cf, 0x52dbca07, 0x06b9a2d8, 0xe10dbb7f, 0x899eeb00, 0x025492dc, - 0x9f7b15ed, 0x79433248, 0xa5ebc8d6, 0x9c7a7f7b, 0xddff4045, 0xd5e20d5a, - 0x0b1a62ae, 0x25d7bb8c, 0xb250dcd8, 0x12c668f2, 0x7d6ea310, 0x59b19199, - 0xaf9a7096, 0x630e7b62, 0xc17dfeb9, 0xab3f6a73, 0x8fb8c562, 0xd903f531, - 0x8bfca1cb, 0xe21f7bca, 0x7ab52ff3, 0xf1192b8b, 0xfcbc2662, 0x84548b65, - 0x05fbaeed, 0xfac05636, 0xac1a637e, 0x6ac9165f, 0xf4a17c71, 0xcf049b57, - 0xb2101c57, 0x787b30b5, 0x1ee6b766, 0xd1169103, 0xd389b559, 0x75768ad9, - 0x7fe02251, 0x2d408b45, 0x3357950e, 0x2f2abe1c, 0x80e6664d, 0xb6b656fd, - 0x8eb0cc68, 0x09ce19a3, 0x539e1dfd, 0x5e78a59a, 0x7cb185b6, 0x89fe27c0, - 0xa53e6bf8, 0x3f0037b9, 0x2e1cadd5, 0xbede56ce, 0x3b900338, 0x1362b699, - 0x26dea0d2, 0x6b3ebd50, 0xaa35fcc2, 0xfcfe7ac0, 0x9a586935, 0x354c4e08, - 0xf0025490, 0xa3d194dc, 0xd73bfc41, 0x5d42f3ca, 0x0d5eb01d, 0xde48e512, - 0xf1c06a9e, 0x3caf1a66, 0xd146b677, 0x6c33af78, 0x3609bb03, 0x61506d51, - 0x4434ef59, 0x56b3b960, 0x715950cc, 0x09166173, 0x1611dfe0, 0x6122c591, - 0x3d5eaaca, 0x3b501240, 0xf6845870, 0x83fb48dc, 0x0c719f48, 0x33e802b8, - 0x06057991, 0xf9dfdff4, 0x7fce2e59, 0x17df18cb, 0x5eaeb60c, 0x017e7d33, - 0x8b26c3d0, 0x5f4c8e7c, 0xc8f1d22e, 0xb0af4043, 0x6cd5a7bf, 0xcf073e83, - 0x42e6c257, 0x08c2cc3b, 0xb984dfcf, 0xafdfc0f7, 0xce226f31, 0x54de74cf, - 0xcc9af71c, 0xc35a25a7, 0xf5f60106, 0x63fb149b, 0x053b8fb8, 0x116cf8f5, - 0xc58d2071, 0xfe6afd7e, 0xc2796d9c, 0x4ffc03a6, 0xa367e8e7, 0x4062e645, - 0xf1519aa2, 0xc163a406, 0x60ab6366, 0x0f3307fd, 0x2e80cbdd, 0x31d01e1e, - 0x5eaf9c2d, 0x7d3dcfcf, 0x0094ec20, 0x2a8f46fd, 0xf4165916, 0x2958ab37, - 0x29943ff4, 0x9fd8557a, 0x9fd8dce9, 0xbe6d0ae9, 0x8196590c, 0x7a88d0fc, - 0x78eff51b, 0xca011bf3, 0xe1e2e944, 0xe2573848, 0x3d4b052f, 0x3c1b29f4, - 0x85fff4fd, 0x5352f4b2, 0xfca1efcb, 0x19bda475, 0xb0727751, 0x501d94f8, - 0xa3c9b0f6, 0xf9f264b3, 0xf1dff702, 0xa2226fab, 0xfabeff45, 0x7bef4e07, - 0xcea58ad9, 0xe9b8c022, 0x9b57921d, 0xfa7ef975, 0xa9e361e3, 0x39e18fd4, - 0x5ba20dfb, 0xe1ffb010, 0xd37f710f, 0x14af0675, 0x17d4e381, 0x38ff3a7c, - 0x751d1e66, 0x284646fa, 0xb1913ef8, 0x8c3cdc58, 0x7068b81f, 0x6fb9c137, - 0xa14ff991, 0x488b1eaf, 0xf191e9f8, 0xe991c0a4, 0x7e9122b2, 0x5e8ad5eb, - 0x4cb385f0, 0xe8d67f3f, 0x5e0cff38, 0xff386d12, 0xcdd6b960, 0x8ec18a60, - 0x5727d254, 0x007fa792, 0xd740ca79, 0xfb6a97bc, 0xf90fc233, 0x78fc074a, - 0xc02f0c97, 0x25f9c33f, 0x64bbfe79, 0x1065ddb8, 0x127e9c39, 0x6e992702, - 0xf650ba14, 0x5863982f, 0x9f1fb469, 0x47ddd7ec, 0x8f099323, 0xe383ffe3, - 0xdfc213ef, 0x01d62737, 0xff51b11b, 0xfc784598, 0x579fc05f, 0xf80bfeb4, - 0x9fc50eeb, 0xe23d7f57, 0xd2d171ef, 0x0880fc84, 0x26d2a1c8, 0x0658f9c2, - 0x932ffe23, 0xe09b2cc2, 0xffe4767c, 0x8fef889b, 0xfc2bdf22, 0x37d8a63e, - 0x49e4f51e, 0x7dc19ec6, 0xb50f44f9, 0x10a766a7, 0xbac75f9f, 0xf01db013, - 0xf117379c, 0xe876d82e, 0xfb7d2c24, 0x5df5865e, 0x1ecb0615, 0x5bbf6f38, - 0xfe61a974, 0x8ef72886, 0xc36eb0a5, 0x1716995d, 0xd59633b6, 0x3ca07286, - 0xbe7a82cc, 0x85cb8a21, 0xa4e90586, 0x277e0f87, 0x73c2ad25, 0x34b3082c, - 0x6c86ff41, 0xa01323df, 0x6cd630de, 0x57d74171, 0x1dbe9605, 0xd1d1cfc7, - 0x38730d3a, 0x323c36dd, 0x057a8dda, 0x7af3cff4, 0x1e593fa8, 0x0d9cf0c6, - 0x6884b68d, 0x2297cba0, 0x61b3a3ec, 0x4e24a3ff, 0xd0c90dd7, 0xa136e50e, - 0x387dc164, 0x6fbe78df, 0x17b082df, 0xfa2cc2f7, 0xd0591034, 0xb195727e, - 0x42a5e509, 0x73a57797, 0x75c63779, 0xc9c2076a, 0xd4659d35, 0x937ffcc2, - 0xbb814be9, 0x556c6360, 0x0afe1fb4, 0x70c8c59d, 0x7a735617, 0xe5974d73, - 0xd7733562, 0xe65f080b, 0x96f8070b, 0x42414169, 0xadd93469, 0xe5faefb8, - 0xf7091780, 0x527fe1cf, 0x619ee564, 0x2847e7f8, 0x4c88f32c, 0x328fe404, - 0x0ca3f9c6, 0x6fe908e9, 0x0051d015, 0x75df31fd, 0x65c3a751, 0x6bf1823a, - 0x70d3258d, 0x3f85cfbd, 0x89e363e4, 0x87f34a7f, 0x3656675b, 0xf40b0397, - 0x9fd899f6, 0x51148eed, 0xf130ae5f, 0x7f644ef5, 0xc5f51a36, 0x79bd5fc9, - 0x23c7961d, 0x86cb6e4a, 0x7c16dbfe, 0xfce2845d, 0x353e096f, 0x0b6fe39e, - 0xb468fffe, 0xbf56ca43, 0x43fef449, 0x192859f7, 0xaf4e5032, 0x15a67d04, - 0xb074e4b0, 0x74463ef2, 0x896ac890, 0xfd65e36e, 0x47a30c05, 0x00f37539, - 0xbcca8ed8, 0x9747fff0, 0xce896c74, 0xa2c69f5f, 0x7433ea82, 0x0bfd4109, - 0xcf41c94d, 0x171f8d6f, 0x39a67cf4, 0x3b3ea83b, 0xff505263, 0x82d32ddb, - 0x9c4e77ea, 0x8e7fd419, 0xdd504e6d, 0x1f244cc6, 0x738aea3a, 0xe1bb013f, - 0xdc92bab5, 0xe397544f, 0xd0f6aa63, 0xe805b37e, 0x5f3bdb24, 0x91ea0935, - 0x43265687, 0x11cb537d, 0xf43c4f5e, 0x66e03245, 0xf9d1cb73, 0x53dbd02a, - 0x45f43c6f, 0x6d1fd40a, 0xa7cfe2e9, 0x40a362c0, 0x39bcb6ac, 0x9af805df, - 0x8adf629b, 0xa9779af8, 0xf98a28f6, 0xbdccd7f7, 0xb942592f, 0x06746730, - 0xc53727ec, 0xbf3e10fe, 0x759ef62b, 0x1ffb0091, 0x46ab5b7d, 0x5d98bf3c, - 0xa1e915b2, 0xf3a722ff, 0x91978853, 0x96097eff, 0x8a61d903, 0x3c92bd9c, - 0x03adf854, 0x1512c6f4, 0xa54749c2, 0xe544ceb7, 0x2a78baa1, 0xd999d48f, - 0x57638012, 0xc795065d, 0x7ed42cea, 0x95226ebc, 0x546cea27, 0x4c575bbe, - 0x095d7765, 0xb2ff0a95, 0x6a0d96bd, 0x2a974224, 0x4fceb4ea, 0x63d2578f, - 0x69d92820, 0xf9d09f05, 0x39adbd4d, 0x9d75ce9b, 0x6959e909, 0x81f9da3f, - 0x9dfa0459, 0x3d11d56a, 0x9b74354f, 0x475e5675, 0x22fbb8b9, 0xbc118af3, - 0x5fb02a9f, 0xfd1b278c, 0x030ea998, 0x841b4bf5, 0xefd8597e, 0xf79404cd, - 0x16356b53, 0x509e63b4, 0xf61e9733, 0x90df146f, 0x20e31d70, 0x05d86cca, - 0x903ad518, 0x6ba07157, 0x63f439f1, 0x0f77283a, 0x4746f5f2, 0xf9472ed7, - 0x60ccba34, 0x95f2e7a9, 0x08e24be4, 0x2fee026f, 0xda86a571, 0x198f628d, - 0x9d5f60e5, 0x69d21677, 0x0ae72c81, 0x30ef5c34, 0x80bde411, 0x576dfb7c, - 0xedf3da22, 0xd02f9edc, 0xfa44ec96, 0xfe7156ae, 0xf77a3165, 0xd5475c1e, - 0xf42cf15d, 0xb44d89eb, 0xc568426c, 0x6069641f, 0x14d617b7, 0xeddca267, - 0xaf885b61, 0x13fd5ec1, 0x338fdbd2, 0x9945df81, 0xf89e6048, 0x4da6f0e2, - 0xd7adda02, 0xce5d21e7, 0x300f9ad5, 0xf65f07e0, 0xdcfbd100, 0x7a1e7348, - 0xafecbe0a, 0x7cce3d79, 0x26e78040, 0x00bf3036, 0xe9cf55ea, 0xf0049f4d, - 0x1513d3a9, 0x4b69af54, 0xc0127d30, 0x07f855a7, 0x09b747fa, 0x0ebb942a, - 0x04a72b79, 0xb7c405fb, 0x0d73f8b3, 0x0680dfdf, 0xd98bd8ed, 0xb06fa266, - 0x0fef4997, 0x9bba34cc, 0x2371bf60, 0xa057b36a, 0xce6994fd, 0xea497ec3, - 0x63f40881, 0x1555bffa, 0x19efc9bb, 0x78c9f888, 0xd33d7d3f, 0x287b5121, - 0x70e6b5dd, 0xcd26af7f, 0x50f119b0, 0x51d3af1d, 0x88b171d9, 0x92569d91, - 0x4db97686, 0xd0cbfdc3, 0xb8737bf1, 0xaf5e491e, 0xa240b921, 0x0b6cb608, - 0xc5dd4a63, 0xf8d63226, 0xbf21b08b, 0x34c9c007, 0xc83f6563, 0x41476235, - 0x1b7f505a, 0x8e7a1ff6, 0x8ff31cf6, 0xbb49794f, 0x5e4aad63, 0x2965e90f, - 0x183fa373, 0x72abc72a, 0xc0b965a3, 0x8c74fcf1, 0x9cf111be, 0xe77d0126, - 0x504cc950, 0xb2338626, 0xd75f1337, 0x773e91bb, 0xa7fd39eb, 0x2ddcbc89, - 0x309afef2, 0x577a42e6, 0xb94d87fc, 0x79b929f6, 0xe6978f34, 0x91b25a91, - 0x879813ae, 0x24ec57d6, 0x43d81fa5, 0xaa02127a, 0xd7c47481, 0x161c4954, - 0xa672279e, 0x448ce515, 0x4fb1b0fe, 0x5f77e403, 0x40aac478, 0x78e355fc, - 0xe9b8e043, 0xef194e34, 0x4fb2255c, 0x245c9047, 0x89a6723a, 0x4b562fe4, - 0xfe8088ec, 0xa0d6eb16, 0xf5c6539e, 0x14fc1c82, 0x9047f0f0, 0x087e588b, - 0xffd710f2, 0x2c43c833, 0x10f20aff, 0x3c824fdb, 0xf207d2c4, 0x063fdb10, - 0xbce58879, 0xe4568dbb, 0x69b69a9f, 0x7e20d3ec, 0x017ddb50, 0xc369def5, - 0xa64391d3, 0xe1e4dea3, 0xe1cbaf9f, 0x2def457e, 0xa0fd9f1c, 0x00ffd1bf, - 0x8a6b5cba, 0xef1eb2be, 0x1ef9b237, 0x7cb6d380, 0x27f4876e, 0x1cd2faf0, - 0x226dd535, 0xb7e38edb, 0xfaf86be5, 0x3e396229, 0x79f345b7, 0xb245d37b, - 0x9e4ea69f, 0x9e0724b6, 0x3da162db, 0xbdef5fc7, 0x8db73f81, 0x7a43ede2, - 0x253e7e56, 0xeff8a4d7, 0x652fdce9, 0xbd012764, 0xff4afcd3, 0x3e7226f7, - 0x4eefed0c, 0xc3dd8b13, 0x992de3c0, 0xd02f896f, 0x483e469e, 0x6a8be00e, - 0x4285f133, 0x55fd0a87, 0xa73872e5, 0x073a6569, 0x43f042dd, 0x3a72831d, - 0x25f64f4e, 0xe0c6c5c0, 0x9905bb3c, 0x01f9425f, 0x0a07d44a, 0xa07c283f, - 0xf0227bd0, 0x3fed1099, 0xf421cdc7, 0xca8f94aa, 0x358ee8e7, 0xdaf09cfe, - 0xdfa136a1, 0x87cc3377, 0xc1c513e3, 0xfe46ef77, 0xd19a358c, 0xc87c2cf5, - 0x1c9c3b50, 0xc2effaeb, 0x570b9143, 0x7065c780, 0x5ff2f0d0, 0x39c90385, - 0xbf48e394, 0xfdadc8c3, 0x5db2d139, 0x44f7e9ce, 0xd21f6d8e, 0x57a0bf51, - 0xafd0dfa1, 0xd9dac367, 0x7f39f2db, 0x05547428, 0x89eb103a, 0xcbd4ce78, - 0x9e729ee5, 0x632e73a1, 0xc2d2ff24, 0x9e287b78, 0xc8057395, 0x0139c3bf, - 0xb8c61ff1, 0xd81d717d, 0x4d4fe817, 0x3ed335c9, 0x567e47fa, 0xcff995b6, - 0x6f0e477f, 0x88944a7f, 0x32fd141e, 0x8b482ed4, 0xe90664e6, 0x3f42661d, - 0xfc4b53af, 0xe67f05ee, 0x3e871825, 0x3fe49b21, 0x71e320bf, 0x1158fe70, - 0xafbebbed, 0x63d42e0d, 0x4e06a37d, 0x6fbe300a, 0x6436183b, 0x136ed897, - 0x07deef40, 0xd4f5063a, 0x2c7b9005, 0x7273b19d, 0x73cfa11c, 0x73fa24f1, - 0xa6243b35, 0x3b4a5003, 0xf4879abe, 0x6d53b4b4, 0xf6d0b8a2, 0x3d218ec7, - 0xcc156e9e, 0xb5f49768, 0xbfa1f1c2, 0xd6e8c1b3, 0xa822ff43, 0x0665ff63, - 0xd7ccdb8d, 0x4383f8a3, 0x7d53ef5e, 0x85c60a75, 0x1350ec66, 0x2f3e97dc, - 0x3b3ed1b9, 0x0aa57dbc, 0x02dda7eb, 0x4571838b, 0x04aeead2, 0x2d3e57a8, - 0xce30b458, 0x8b3a2861, 0xe7ca82f1, 0xf30bc599, 0xc918b657, 0xa0da5dcf, - 0x6017d8fe, 0xb7bb945f, 0x29eed06a, 0x5edc19df, 0x0eb83bb9, 0xeff922f8, - 0x00f68668, 0x8e6dfcf9, 0xcdec8631, 0xed1b2c71, 0xe3c0d64d, 0xbf7c8ab9, - 0x71756edc, 0xcb82ba39, 0x8cbec66d, 0xea5f7f45, 0x63e92afc, 0x91cfaf03, - 0xfea0a7eb, 0x2f1c57f9, 0xe5aa5c0a, 0x604f3fb5, 0xb79c0f56, 0x426f53ba, - 0xfdbabfff, 0xb71811ef, 0x51f309af, 0x22bd9f7c, 0xdbded099, 0x10b926d8, - 0xfd0ecebe, 0x56e0112e, 0x8d3de07d, 0x5f7088d9, 0xadcaf64e, 0xe31eb5cc, - 0x64515edc, 0xdd4744dd, 0xb666a714, 0x4f38a581, 0x84debb5f, 0x2bf54076, - 0x8ddd741f, 0xd30203f5, 0xfb471e23, 0xee964e88, 0x2da58640, 0xfbe426dd, - 0xbc4244e9, 0x913d9e22, 0x8865af84, 0xe033c477, 0x212cf11d, 0x51bc713e, - 0x2274e6e3, 0x73f4fd51, 0xde0abf1c, 0x1acda48b, 0xe46caf6c, 0x63b19e78, - 0xa230b6cf, 0xe9933503, 0x7a7ef080, 0xa6bbc727, 0x14669d73, 0x08636fd2, - 0x876bb41d, 0x77f700e8, 0xe0841d19, 0x8df002bf, 0x0e942072, 0x93dff142, - 0xd806e5c3, 0x429fa7df, 0x7e08dbfb, 0x23c7f301, 0x1ef55646, 0xcaf5818d, - 0x973bcfa2, 0xf8d8fb43, 0x08da5897, 0xe4157f8a, 0xe66bfc62, 0x5d10eb3b, - 0xc85eb33d, 0x57a97a46, 0x813cf6fb, 0x70a88b71, 0x27f4e38a, 0x32f9d9cf, - 0xfa20bb9c, 0xd816a49b, 0x5a6bcd7f, 0xc928deba, 0x35ec8715, 0xf129978c, - 0xc533c074, 0x5a1d9cc9, 0x2d6b171e, 0x73fa05b4, 0x5cfc09fd, 0xb2819a85, - 0xc017e8e5, 0x608eb87c, 0x555e7ee3, 0x28178f07, 0x1295597e, 0x8e0e6837, - 0x77a6081b, 0x2e455fa8, 0xc6a55f8f, 0x3b466cdd, 0xb3017ebc, 0x4d5ea587, - 0xcc78f03f, 0x74dfb2d3, 0x0af1fb45, 0x1bb1427a, 0x6e382b99, 0x65a9c8a1, - 0x8f1ef913, 0x6ab8e2fe, 0x76fdc604, 0x8a8f840b, 0x704f900e, 0xdab70ade, - 0xf802166d, 0x19ffee49, 0xedc01bd2, 0xa0f6ab8c, 0x19dd2128, 0x990ebf68, - 0x8e91ab3e, 0xd695bce0, 0x9cf02237, 0x38ae590e, 0x7f148dda, 0x8a5b64ab, - 0x612aee90, 0xf430ef3d, 0x0b5cf954, 0xa2d729f9, 0xaccec527, 0xb7ee0d6e, - 0xce487731, 0xe01eff8c, 0x396401bb, 0x992e7bd7, 0xf12332fe, 0x99906fde, - 0x879f9123, 0xedc09ff4, 0x5cfe4537, 0x3c581dbf, 0x6e71de60, 0xac05531d, - 0xa673e37f, 0x4f78faa0, 0x9bff507c, 0xcf41ccda, 0x4119bdb3, 0x598f73cf, - 0xdd79ea82, 0x4ffa8313, 0x5416d0f8, 0x0e2be49f, 0x4ce53fea, 0x307d5049, - 0x9573ce13, 0xe35bc1fb, 0x33fea085, 0xf9a0facd, 0x05446767, 0x320d07d5, - 0x52bb647c, 0xce5f77b1, 0x686ef6e5, 0x76f7c0a9, 0x8a3af04b, 0xc4e77ebf, - 0xd8e6f5e0, 0xa1fbd782, 0xfa0bd978, 0xc27e0554, 0xb15fa073, 0x13f81dfc, - 0x9a13f02a, 0xfac09fc1, 0x604fe08b, 0x027f01e9, 0x7f025fdb, 0xe0adeb02, - 0x20fd604f, 0x6f583ff8, 0xf2a62bab, 0x6a12ba95, 0xbafc16bf, 0xc98f75e4, - 0xd7971eeb, 0x74e177fd, 0x5def9e42, 0x9c6ebe79, 0xdcffcd2f, 0xbc563c59, - 0x2d3cfc04, 0x87c6acfa, 0x5f0ac37e, 0x062dc611, 0xc61892de, 0x7ddd99a5, - 0xf5062eac, 0x338a08d9, 0xb78192b3, 0x7d52ae31, 0xc9b4d520, 0x0fecfa8c, - 0xbef3e2ef, 0x7c8cc956, 0xefeda879, 0x85cf3811, 0x5f74614b, 0xef107a4a, - 0x5461bf1b, 0x31cf04df, 0x05b33a0e, 0x37e90804, 0x0bb7e90f, 0x4ddd4a69, - 0xcd25bdf7, 0x53c41a2d, 0x3c29f215, 0x0ea3cb7f, 0x635cfe7e, 0xf61373d0, - 0xe54ab287, 0xb9c238a6, 0x2f3e6536, 0xf1a477f5, 0xcf73cf7b, 0x053f5e1d, - 0xe2cb6ff5, 0x5e7f7811, 0xec5efcd5, 0xc7c157bd, 0xc85f07e7, 0x76cafba4, - 0x9fe0cf98, 0x96aed9cf, 0x8eff7ceb, 0x68a296b4, 0x02cd1c54, 0x05c50b1b, - 0x5fee85b6, 0x38f6daaa, 0x65556e50, 0x0066addc, 0x248f7e9f, 0xbdf837c7, - 0xb8c4c391, 0x22f9e71d, 0x5f57ef02, 0xc3bd1cf7, 0x38edf886, 0xf6eb811c, - 0xfe414ab7, 0xb72b68d3, 0x355b478f, 0xad0bbf84, 0x5ef02387, 0x30e7a377, - 0x4bcabb87, 0xd7243fe7, 0x7824a1fb, 0xfe7449b7, 0xd0624b8a, 0x5586763d, - 0xb66679a2, 0xb9e2358d, 0xbd7c3c7a, 0xb799ab1c, 0x825e2da7, 0xbf1e3ffb, - 0x7b224f20, 0xca350410, 0xef661bf1, 0xcaa43b41, 0xf386d923, 0x79e40aef, - 0x4e9cd4bb, 0xdfdb4adf, 0x78f8f285, 0xd26c88f1, 0x699f8a11, 0x916f76e5, - 0x7a869ec6, 0x3660c7a4, 0x583f9d22, 0xfc446a9c, 0xdb12c21e, 0xec69778b, - 0xe6c7bc06, 0xba98f5eb, 0x7aee9023, 0xb425735a, 0xf2f99477, 0xe88775e5, - 0x2e6f087b, 0xbbb953c2, 0xf8f380d1, 0x73dbc7f1, 0x7fea26ac, 0x3cdefddc, - 0x327aabb4, 0xe92ec9c2, 0xa7f230d2, 0x5db99aab, 0xd891d3dc, 0x924f7818, - 0xf2fd9563, 0xdaf0910c, 0xfb96a6d7, 0x0587bddd, 0x39d353f5, 0xde0eec2f, - 0xea7dc98f, 0x1dc7b451, 0xf50c4b4f, 0x1b5d43a2, 0x6cffe78b, 0xcafef067, - 0xd43b3865, 0x00d8d8de, 0x0fb4757a, 0xe8818df1, 0x13e15dbc, 0xc153e133, - 0xb7064f63, 0xf9e27ae7, 0x65a3a4bd, 0xe5f5d10f, 0x64eea4f1, 0x7f121ff4, - 0xe778a3a9, 0xc567fcb5, 0xaff0086e, 0xea8bfa18, 0x313cd4e2, 0xbc1f6fc5, - 0xb6ab6b96, 0xabbf448e, 0x1ecafc84, 0xac2cf606, 0x3a7b44e9, 0xb61ff292, - 0xad83bae1, 0x76bfba6a, 0x7d66daea, 0xa0d97602, 0xf6051805, 0x2d53b83d, - 0x0cd97bdf, 0x952ed768, 0xcccfdaed, 0xf4097cf6, 0x488d73af, 0x866473e7, - 0x27d31f91, 0x5bcfbdcb, 0xbb24ef92, 0x426498e1, 0x8786687f, 0x668ec1db, - 0x7b56d76e, 0x2a63ff92, 0x6acdedda, 0x8a60d4cc, 0xed94e21d, 0xddb2d390, - 0x80cd7a7b, 0x4e9bfc86, 0x8c963d81, 0xbb5b2a79, 0x33b9e112, 0xb3d91673, - 0xec99a94e, 0x83db6589, 0x6fb007ed, 0xcf55ea82, 0x7217da85, 0xdc13cb7c, - 0xdb87f8ae, 0xc67643ac, 0x0a67f438, 0xc871a9a5, 0x78c82f0f, 0x959bfc55, - 0xb7942de3, 0x9e6551b3, 0x1021c4a5, 0xfb9d355e, 0x6edf702b, 0xfc859847, - 0x10af558d, 0xe4bffb5c, 0x3c7f4c7e, 0x33f47823, 0x36fedf0e, 0x6a35e74e, - 0x48f98dc1, 0x34b64035, 0xaf704e9f, 0x6bb338c1, 0x13e48230, 0x17c8c563, - 0x7f70162b, 0x5f3186d5, 0x7e156b28, 0xb7abd108, 0x54527ca8, 0xb3689c80, - 0x02bf50a6, 0x3ea3b30d, 0x90b4695b, 0xe3a31b7e, 0x6ae17a76, 0xc3d2364f, - 0xb5c7f018, 0x31f8f101, 0xfb010186, 0xc7807eed, 0xc27895ff, 0x1d49951c, - 0x191fa015, 0x95fd435b, 0xf0a241f9, 0xdf9ad7f1, 0xfc1bf304, 0x23bc03f3, - 0x585fde11, 0x93b7a42d, 0xfff728e6, 0xca97c4b5, 0xbd002e79, 0x63181c61, - 0xc7378834, 0x9fc837ce, 0xf5eeb273, 0x8228ae38, 0xf708a3ef, 0x5e30f583, - 0xe79651fe, 0xbcbc79b1, 0xf9152e4d, 0x7b6790d5, 0x95f50adf, 0x593ff679, - 0x8899ae49, 0xb4ca573e, 0x9c4cf602, 0xbbf9186f, 0xf0891de2, 0x03f005fa, - 0x5ac2fbf2, 0x64169cc1, 0xaf3a712f, 0x3cec4de1, 0x454ef4f3, 0xdd6cb838, - 0xc6d79819, 0x5a2d7f38, 0x05a737a5, 0xbd2007de, 0x0251ffa3, 0x2fd1f2ff, - 0x5372bfe3, 0x57946dc5, 0x8cd62ab5, 0xc83517f7, 0xa6d7290f, 0x87ba50ff, - 0xb7a44edf, 0xa0b5a66a, 0x0b69a97e, 0xa1516e7d, 0x084dfe3d, 0x74c9245f, - 0xe81768da, 0x5bf1bd7e, 0x95a38f15, 0xbb37140a, 0x4e911a0b, 0xcafd87e9, - 0x7e71b9a7, 0xfba0b3cc, 0x391886ae, 0xee862bef, 0x9f227ee1, 0xf7952eff, - 0xa3efe40d, 0xc6324f6a, 0xf93a8e71, 0xe602d53d, 0x52dd7ba1, 0x6f654dd6, - 0x2f01f578, 0x8d1aee4d, 0x7607f87e, 0x1a91c52d, 0x511936d7, 0xb5b166ce, - 0x031fbc26, 0xfbee7936, 0x1bdb2bdc, 0x9468f7a1, 0xc7e7959f, 0x92bccaf3, - 0x83a03cf8, 0xf8a38033, 0x57c7cb9c, 0x02207fbd, 0xfefe7ee1, 0xca7ef3fd, - 0xb9020fd0, 0xd654f305, 0xbdd064b6, 0x67758b8c, 0xabf1fbe4, 0x1fc153e0, - 0xf08399b4, 0x0eb9670a, 0x0d9f33e0, 0xd36e63e4, 0xc0a9f0b5, 0xf03d4939, - 0xe8250463, 0xa1439231, 0x5ee05678, 0x3cd56acd, 0xeefb56fe, 0xb3ffe802, - 0xed19a2b5, 0x7ef0cbca, 0xf578fc0d, 0x28d791fc, 0x257b3f90, 0x5a78297c, - 0xff54bcc8, 0xfb8f8a30, 0xf144a170, 0x7c69ffc3, 0x4bd9e435, 0xb7c2aef2, - 0x257a7ca1, 0x2ab45cbe, 0xf8437f84, 0x2d2f8874, 0x7f002ff0, 0xc41155f6, - 0x1d7e0a8f, 0x5193f066, 0x2d1875ff, 0x3e39766e, 0xfdc5dfd1, 0xec0ab654, - 0xf087e149, 0xe3fc8fab, 0xad017c50, 0x541f50d8, 0xa9f305e7, 0xc92bc782, - 0x7dee452d, 0x4d47bcc4, 0x7067dd02, 0x9685fe3e, 0xfb94e9f2, 0xe2dee50c, - 0x6fae3cd1, 0xc08fcb42, 0xa27bc16e, 0x233d194d, 0xd5ebded1, 0x7bf0f328, - 0x74d68fd7, 0xcd7cc68f, 0xb2f1a68f, 0x4cf3c357, 0x8c2dba94, 0x4a3f03c7, - 0x6e10bad0, 0xa6e3091f, 0x91f01da3, 0x783bcbf0, 0xc6634e3d, 0xe9b882fa, - 0xaaf7a826, 0x83e1f895, 0x5376fcb2, 0x0982d1f9, 0x604fd405, 0x661e1047, - 0x3ad09581, 0x0c5d1082, 0xe7e8f9fb, 0x5ef07363, 0x03ff3940, 0xf48e3c79, - 0x431cf91b, 0x095ff6f1, 0x045f6f14, 0xf784c3aa, 0x289fd302, 0x93f6814e, - 0xa6cd4ebf, 0xc115cafb, 0x4dfea3eb, 0x56e538a6, 0x4b96e79a, 0x99c5ea03, - 0xe90d7dfe, 0xbc8b82cd, 0xa0d8c97d, 0xf45b667c, 0xbb27ee38, 0x8f512353, - 0xf06d7a29, 0x60437ed8, 0x1cacf51c, 0x8faa1e77, 0x5029247b, 0xf7b1be2f, - 0xa79c74e1, 0xb2cae35c, 0xf98f3018, 0x1fb424a9, 0x943ef7ca, 0xdeed764e, - 0x9fe8e98d, 0x9c3d3794, 0xb87aa36e, 0x1523fc9d, 0x7df9f73f, 0x0a6d7693, - 0x9d6fa3b0, 0x52fbedc0, 0x68851bdd, 0xf1bacedf, 0xb71875f3, 0x816bfb1f, - 0x590b70e2, 0xb7d43af7, 0xaf9c1965, 0xe48e8358, 0xf747cc3f, 0xddc67ba4, - 0xfee51bbe, 0xabbf8cf1, 0xcdfea097, 0x657cd153, 0x0e39bdcc, 0x041b6fe3, - 0xfbf9bf8a, 0xd77ba68f, 0x4d056bc5, 0x51ea0c7c, 0xc7fd779e, 0xe38228bc, - 0xbbb21b3d, 0x356cbdb0, 0x75a59f6f, 0x3ce0f6b7, 0xcf28684f, 0x4a65140a, - 0xf63dc049, 0x3df8f31f, 0x72cda2dd, 0xcebcb1be, 0x8db16dd8, 0xa3fce781, - 0xfe567f8c, 0x3b83c901, 0xb6dcbc65, 0xf123bdfa, 0xdaa46f30, 0x2b9467fe, - 0x3a7e3eef, 0x4159e50d, 0xa44cd9f4, 0xfb1ab1f3, 0xee781593, 0x2bc52d26, - 0x528959ad, 0xb9cff41c, 0x5863da7f, 0xf8bd5a2e, 0xfb8c0ac9, 0x1f91d76e, - 0x856feca6, 0x5fd11660, 0xd3f8dc3d, 0x676e107b, 0xa479e71e, 0x8faf1a2b, - 0xe2fe5abb, 0x1f3c75b3, 0x1d3af9fc, 0x99d42f95, 0xb88e1998, 0xea9e2eaf, - 0x5333afbf, 0xfa73e6c9, 0xaea6f252, 0xa5ee5f34, 0xb65bca30, 0x1e51d06e, - 0xf6d6ae7d, 0x6bc01e55, 0xa6ce0dec, 0xc6b9f28d, 0x576cf8c2, 0x83840cf2, - 0x2ef2e375, 0xe54f6134, 0xedeaff71, 0x64490d9e, 0xf53eaf87, 0xcf3c054c, - 0x0ef92fcc, 0x5e76ebc7, 0xe1c178a4, 0x10ca87f6, 0x5a4de5de, 0xdcf93e7e, - 0x8f4f1e67, 0xbce3127b, 0x7fc9a96f, 0xea79d9af, 0xde508d99, 0x26b979bb, - 0xe87fde90, 0xf795bf79, 0xbabe2d73, 0x75fe1c12, 0x89387abe, 0xf809a7f8, - 0xe7dff32a, 0x6bd59aab, 0xf3737e08, 0xc3e6c64b, 0x5da8cffe, 0x674fc849, - 0x744cddc6, 0x0814eaee, 0x571c8afe, 0xf3e6a7c6, 0xd12ae8fb, 0x48ec99b3, - 0x057f8e59, 0xf7c2239e, 0xd2cff68d, 0xaafe8ed1, 0xcf55c16d, 0x3d0eb07d, - 0xe99b8c22, 0x9e7d0ca8, 0x62a7b1af, 0xc8be715e, 0xe7d0e7ed, 0x712be7b7, - 0xc5b71e78, 0xa790109f, 0x458d84e2, 0x13fea346, 0x972061bc, 0x9eb76d9d, - 0x06ffa155, 0xc1c7e17e, 0x38fb2876, 0x695faf40, 0xab2ad7bf, 0x5f951e71, - 0x50f84eee, 0x3d00de64, 0xc617c93e, 0x0eeb01bc, 0xa6d02bf9, 0x049efba1, - 0x37880b92, 0x6bea87cc, 0xf584d71f, 0xc78e1ab3, 0x97e083be, 0x930cb8f1, - 0x3ce7fdf2, 0x0b3e7edb, 0x79e86ce5, 0x4f395fab, 0x7b68e1f4, 0xe740a2e8, - 0x9556799f, 0xbff3ed75, 0x167cf7b1, 0xdaacefe2, 0x57fe8f97, 0x8597c69f, - 0x957ea878, 0x157ff3cb, 0xc57b4a0e, 0x138f0d06, 0x23f2260a, 0x140ba50b, - 0xc63be807, 0xedd500e3, 0x0e9e48bb, 0x4c78f076, 0x145dd88d, 0xda8bf187, - 0xcf285d53, 0x5fb9e306, 0x28dbf306, 0xd65521cf, 0xa481aa83, 0x1ed72039, - 0xee07a219, 0xfe419e0f, 0x1e3ce0d5, 0x6561e507, 0x2bb43385, 0x433f21ce, - 0xe4aad97b, 0x67e748f5, 0x507323dc, 0xf59dbe3e, 0xdf8a6a8f, 0x926e1ebd, - 0x30958ec8, 0x4e0878c7, 0x4b70e743, 0x2987d13c, 0xb3387176, 0xd1abf405, - 0xbf24ef98, 0x9fbf38fa, 0xf381b9ab, 0xf3857b13, 0x1bed7393, 0xf980f89a, - 0x93f3257e, 0x7ace4f62, 0x97c41ffd, 0x9edae70f, 0x470cbe40, 0xc5f38859, - 0xb51e5247, 0x72871ef2, 0x90e8691f, 0x8962f8fd, 0x49b4d79e, 0x58e5ef0c, - 0x0af291bc, 0xca16d98a, 0x3cc59cb7, 0x8f5e7953, 0xf029d1ef, 0x52ebf67c, - 0x81a1e62e, 0xdbf74d3d, 0x34f66145, 0x15ead3cc, 0x1eae1905, 0x7d009ceb, - 0xf73e7ef6, 0x024aa757, 0x8481b1e9, 0x6653b270, 0xe29677ce, 0x5a7e957e, - 0x9833eb91, 0xe62cec87, 0x7bc2c81e, 0xc81de655, 0xa556fbc2, 0xc3d7bcdf, - 0x322f496b, 0xc05e758f, 0x79f3a73a, 0xbc0bf3bc, 0x5279071f, 0x16c3df23, - 0x436edf4a, 0x27456b7f, 0x15ec7fbf, 0x3cc03f93, 0x19c01733, 0xf01e7af1, - 0x63fd436a, 0xf21b3667, 0x6e91f8cf, 0x7d9a9fe4, 0xbd7cc302, 0x136d76ea, - 0xd5aa85c6, 0xe7a458be, 0x6bef6d8d, 0xf06b9e90, 0x8e3c765e, 0xdcbc7267, - 0x35bf7944, 0xf5efc626, 0x00ffaeda, 0x63ce76e3, 0x553a8b5c, 0x003c51ef, - 0x57ae36e5, 0xfe42dad5, 0xc97983bf, 0x073477ff, 0x3c60cdd3, 0xf287e78f, - 0x737ce9c9, 0xdccc7f10, 0x1e63f9ce, 0x681b73e6, 0x675fc538, 0x5d91c7c6, - 0xf1c71fe2, 0xafce9360, 0x3fa63b43, 0xfc7ca045, 0x5ad730fe, 0xe95c8fb4, - 0x7fe9aedc, 0xbd2b05ed, 0x5b73a3f7, 0x3cf98c7f, 0x733bddb2, 0x149556c3, - 0x1d999fb0, 0x1fd8de3c, 0x120fcac6, 0x21d7edde, 0x25b97c3e, 0xbe31f267, - 0x777819a3, 0x4483c60a, 0x3d0d1f1e, 0x6b8e5d87, 0xfdfc671c, 0xb3df6528, - 0x3cb91313, 0xa3a26e63, 0x5bbf392e, 0xc651d7c9, 0x504132df, 0x9fb8d1ee, - 0xfaae5824, 0xd7de1a5e, 0xde2b9e60, 0x3bf960d7, 0xef161f39, 0xa2feb06b, - 0xf78b0f9c, 0xf78ed835, 0x956f5835, 0xbef161f3, 0x5f78eb06, 0x722be583, - 0xdc71ec3e, 0x6df1e52a, 0xa2e90a7c, 0x946d790b, 0x1d1bdebf, 0xdc151f52, - 0x085a37bf, 0xa8128fae, 0xc6c269bf, 0x78ff30a7, 0xc52f9293, 0xc3b446cc, - 0xfbf9c22a, 0x7b06a91a, 0xf3f404ec, 0x45ed778b, 0x9bf81e7f, 0x882b9fde, - 0xef4a505e, 0x1968c497, 0x27dba3ca, 0x804f47d8, 0xcd8ec7f1, 0x724adb48, - 0xecf74f52, 0x31bb3fbd, 0x6f7ae292, 0x25824c49, 0xaee465a7, 0x9a7d42b5, - 0x85fa2041, 0x512a6ef9, 0x67984cfc, 0xab62c746, 0x1307cb8a, 0x9285cbda, - 0xb3ae0963, 0x8b9f4122, 0xd588f872, 0x51fb819e, 0x6a345de0, 0x45da1a59, - 0x07f36a5d, 0xbd759f18, 0x57e866a3, 0xa53c7129, 0x69d693df, 0x99bfb8f9, - 0x736ba919, 0x36607e70, 0x0d367794, 0xd9fdc66b, 0x9ea170c4, 0x855997e4, - 0x027f20f2, 0x66e99ba7, 0x357b1f6e, 0xfa345566, 0x62d361f5, 0x4bb75ef0, - 0x1931f3c6, 0x3c65c7cf, 0x81573de3, 0x6173df8a, 0x585cf789, 0x2da3e686, - 0x4db12fcf, 0x240f7820, 0xcdb3e605, 0x0097df92, 0xd4f7a10a, 0xf31c729c, - 0x34ee594b, 0xcadc95e6, 0x9e6879c7, 0x778e392a, 0x6f7c1d5e, 0x8ff38ca8, - 0xbdce5467, 0x166bcb89, 0xbf79e1a9, 0xe61731d7, 0x397dcf15, 0x7d50e281, - 0x06a5d16e, 0x5e05cfbc, 0x5ec67947, 0x8b2efee6, 0x77337ce7, 0xabf51c7f, - 0xcea9e397, 0x7c74eee8, 0xe64fa3af, 0xf07ea52f, 0xe4979e3b, 0x81ba81cc, - 0xf3a123de, 0xa776e739, 0x4fbd4147, 0x5f488bd0, 0xbcfe26ce, 0x673fe647, - 0x7c9f3c8a, 0x24f3a61e, 0x3bfa3e21, 0xf7c24e5f, 0xbc193710, 0xf7fcb94b, - 0x66dc93a6, 0x6fcc74de, 0x4e782f3a, 0xadf1be62, 0x98a5296d, 0xed5e7f6f, - 0xb3eb0679, 0x5d78d2db, 0x0a693968, 0x93d23e7c, 0xb7c8f984, 0x6296a5b6, - 0x91f9f23e, 0x5944cf2d, 0x97eaea02, 0xcd73e24e, 0x98a56983, 0xeb5b3c9f, - 0x7487563e, 0x5f4e7bf3, 0x4e077dfa, 0xdaaa7c23, 0x7d3efdb9, 0x2f0b81df, - 0x603e7ea1, 0x7582bca4, 0xdf099213, 0x6ecfedf5, 0x6beb7a46, 0x6c3f1351, - 0x99ff7e6a, 0x2d3f50df, 0x6b665985, 0xc90c563d, 0xba1db494, 0x3b35f71b, - 0xd625f3dc, 0x89bc4f17, 0x047b31f6, 0x13a5ebe7, 0x4f914a73, 0xfbec0efb, - 0xd9b3ea05, 0xe2d86091, 0x13d05e7e, 0x8ff72a7e, 0x40b8c02b, 0x0cbbb19f, - 0x9dfeafe7, 0xec1fe796, 0x718e9b8f, 0xc09cff82, 0x6e2a31f3, 0xfa8492d8, - 0xf9e57c56, 0xf8c1bfbd, 0x74f4efe6, 0xcd1353df, 0xa94abded, 0xe1397f31, - 0xcc5ed76f, 0x5e7be95b, 0x15aff74f, 0xe2b39318, 0x2963ac7b, 0x3feaff3e, - 0x78865eff, 0xee769428, 0x772ff6c5, 0x438445eb, 0x7916c68f, 0x8f61f233, - 0x0acefc9a, 0x3bd15eb9, 0xdc27ef82, 0x8bf84457, 0xfa8492d9, 0xafc472b6, - 0xcf7dc0ee, 0x833cb696, 0x567b0f7e, 0x670e774b, 0xc1b8079f, 0xd47bb3b8, - 0xfb034998, 0x5e90aa30, 0xca5b0bce, 0xf7f9c49e, 0xf5e77ef0, 0xae9e085b, - 0x5c33d73d, 0xd431fa0f, 0xad85e7c7, 0xf767ed41, 0x7e859b3c, 0xcddfb9e9, - 0xa154ff26, 0x2a5f8573, 0xf4836b77, 0x58824922, 0x3fca5b8c, 0x02198b93, - 0x0ee759e2, 0x927be8ee, 0x6b9fc7f9, 0x00357b56, 0x5b2d0aa3, 0x0acdf98b, - 0xde26543f, 0xabe78c5a, 0xd1d31b14, 0xf5c8a97e, 0x9c5f2195, 0x3c5d33d5, - 0xd65b7bf4, 0x6bad955b, 0x7c1da0e6, 0x45fcfda5, 0xc95f4796, 0x9b55f87c, - 0xdf781dde, 0xb5fe5a18, 0xa84f998e, 0xb585f5fc, 0x95e5b25a, 0x78d6def9, - 0x55afe81c, 0x71f97347, 0x8337fa12, 0xac93fb1c, 0x0aad16ef, 0x04eeffee, - 0xad594f9e, 0xfea3a5f1, 0x7b7fe653, 0x87db8982, 0xca3a5f2a, 0xb371d0ab, - 0xbcde5925, 0xa9bc9020, 0xd14e156c, 0xd20824fb, 0x2b3c3f58, 0xe6372e75, - 0x87870d13, 0x0f197cf8, 0x70f1e612, 0xd66caabe, 0x4f30f4db, 0x022f9855, - 0xd18725ed, 0x50768117, 0x6b122bdf, 0xa317d192, 0x5fe29fcc, 0x5653894f, - 0xfd36d478, 0x71c1eb70, 0x865e4fd0, 0x5628037f, 0x537ce44f, 0xeb4e16de, - 0x1f2f9331, 0x677cb6e9, 0xa73c38f0, 0xfb1f8029, 0x06c576da, 0xf70cebfa, - 0xa751f74d, 0xfffa6f88, 0x07bd31f9, 0xb5b2295e, 0x4e794f78, 0x4083efe0, - 0x3907de9d, 0x5677df27, 0x43086d7e, 0x95f739fa, 0x4fb8f883, 0x7b9c91f0, - 0x7246cdb1, 0x23ed4fac, 0x626bb739, 0xf947af11, 0xbd6e50ca, 0x24a7f138, - 0x7c12fa3f, 0xd29ef865, 0x2f8ea566, 0xd01d81cc, 0xe490b6d1, 0xe7896cc9, - 0x6a5db051, 0x71138f13, 0xe1932f78, 0xde86d8c4, 0xd443f23a, 0x3a97b466, - 0x42f72a27, 0x25f9ff1a, 0x31f53f3f, 0xe456bef3, 0xc50372cf, 0x6abec07d, - 0xc0ed097e, 0x8c16b105, 0x4dc287a7, 0x898c5fb9, 0xe22966fe, 0x7da31de9, - 0xbc3cc4ec, 0x9f91f4cf, 0xf64ed401, 0x5a6bf57c, 0xd5fb37f2, 0x7e517b03, - 0x71f68db9, 0x0e9e0113, 0x547af74d, 0xbed41771, 0x67ed342e, 0x1c91bd21, - 0x97d6f4e1, 0x07bf8bb9, 0x4e4fdf22, 0xfa00f192, 0x7d22358c, 0x87cf1c08, - 0x409ff6db, 0x9dd7d379, 0x943a724a, 0x3db6ce9f, 0xe3728116, 0xaeefd043, - 0x87c07880, 0x7ca59f8b, 0x0798f980, 0x6b3de502, 0xf837cf83, 0x2fc98fed, - 0xda039b64, 0x821b1e91, 0x4170a1eb, 0xf106f4ba, 0x7df68b81, 0xc01bf23f, - 0x777a6aa7, 0xa861c235, 0x52ea173e, 0x4850fd40, 0x2b3fa43d, 0xfdc3f6e1, - 0xebcd1813, 0x25eded18, 0xcf1f7e3f, 0xbd07adef, 0xe103f546, 0xee2d3f74, - 0xc315bd03, 0x8bea16f5, 0x8a6e88aa, 0xd01df55f, 0x83cabdd2, 0xe1259fed, - 0x291e81f9, 0xfed5534e, 0xf7fa2c72, 0x699826eb, 0xb18fd07e, 0xa0731794, - 0x11fd163d, 0x7a21dda5, 0x0cf7e5d2, 0x287e50b2, 0x9bc94eed, 0x42e5794e, - 0x5f3e1677, 0x8719cb27, 0xeb097508, 0x10e1ce8c, 0x76b3df38, 0x287ce489, - 0xf4c956de, 0x8b21f20a, 0xe15e39f2, 0x1e4503f1, 0xe572c854, 0x7267b610, - 0xf72937fe, 0x84cf7852, 0x9c8c3f7c, 0x23815af8, 0xcef8a5ab, 0xbccd13fd, - 0x79a78f2e, 0xe789fc79, 0x3e7abded, 0xc713252b, 0x45f79599, 0xd528f2fd, - 0x0e505f2f, 0x781c93c4, 0xe70b1d50, 0xb0467caa, 0x8a90c3d4, 0xd04535d2, - 0x2d532d9d, 0x1ab8a22f, 0x2e1ae7e6, 0x1d2857df, 0xf8e44e45, 0x1fb914ad, - 0xa057b95e, 0x6a73a5fb, 0xf2076f7e, 0x580fde86, 0x08a6b056, 0x18beeff9, - 0x5fd026a7, 0x4bfcd6be, 0xcbeb821b, 0xc514d76a, 0x95e7c30d, 0x8d76b6ab, - 0x57cf9764, 0x8a2c6f61, 0xaede5f35, 0x5e9cfbec, 0xf574e7d9, 0xcc7840c8, - 0x1234535f, 0x7fba65ca, 0xdcfc1e17, 0x5eb5dae7, 0x5d2d57ca, 0xb7c4f743, - 0x8a0daa5c, 0xbe6b5eb3, 0x7ba6e60a, 0x3fed2b90, 0xde0874b4, 0x312b8c5e, - 0xc43dafe0, 0x0137c067, 0xf4cbc5eb, 0x289f143a, 0xfd063c5f, 0x3c5f6653, - 0x113e3026, 0x339be25a, 0xb88ae522, 0x2c3e04a8, 0x0f030cb3, 0x89d1ffa5, - 0x3f1ace3c, 0xa8f1d391, 0x5e3b55d9, 0xe9d71462, 0xa57bf941, 0x22fe4cf7, - 0xbf07efef, 0x9c233267, 0x9bd4ebf7, 0xdfd3fe30, 0x87c50df9, 0xe619d7fb, - 0x03077bf3, 0x5de7804b, 0x029be3f1, 0x26abc0e3, 0xdc243b71, 0x9a9dedca, - 0xe3d5f50c, 0xa1c6994b, 0x1bd912f8, 0xdf74e199, 0x05f6d7d2, 0x8efeb7e9, - 0x8bde133c, 0x0dbb75f4, 0xff356fc8, 0xa8b17ffc, 0x3e3afb87, 0xbeb4bca5, - 0x7ca33f6f, 0xde728db5, 0x3936a1e0, 0x6cdbabdf, 0xe2fef6c4, 0xbf6117bf, - 0x8fe9724d, 0x98f8f02f, 0x83f12a52, 0x3bf9ff00, 0x4c7b53d4, 0x54c51f1b, - 0x2db0ca99, 0x7fc0bf24, 0xe1bd468e, 0xe3982b8f, 0x04c38b86, 0x54d215c6, - 0x2580ae3c, 0xd2d215c6, 0xeb015c78, 0x12c05718, 0x8ed80ae3, 0x63ac0571, - 0x18eb015c, 0xc63ac057, 0xb8c4b015, 0x297fb602, 0x0fd1e7bf, 0x3dc78b82, - 0x57f7240d, 0xc0337e62, 0xbf27656f, 0x47b95abf, 0x7c617ba2, 0xdff503cf, - 0xad3b7965, 0x678ede72, 0xd607dd2b, 0x882c901c, 0xc41f7c22, 0x3bf98e95, - 0x1e314703, 0x5822d354, 0x7db198d6, 0x6363ed3e, 0xa507de47, 0x6d47bed8, - 0x4f44cd11, 0x828d9f1c, 0xd57c8f5b, 0x57e287b1, 0x949d7105, 0x2cd35fef, - 0xcebb8c30, 0xd93f72d3, 0x0e6b4129, 0x1d92abdd, 0x9376d4ed, 0x9cf552ff, - 0xef7c0e60, 0x45e266bb, 0x7dca1392, 0x88fe52f5, 0xf37a3d39, 0x6b3d2092, - 0xf85779e3, 0x29c7ec27, 0x1d9377e7, 0x2d176012, 0x6c6c7bc5, 0xf7a5be97, - 0xe0e09c4d, 0x9dae108e, 0xd1d95577, 0xb5f31eb2, 0x55fe687e, 0xdef924e1, - 0x47bf9b3a, 0x92f8fc52, 0xbd60077d, 0xb25a2dc1, 0x609f6e53, 0x1e526dbf, - 0x28d819e6, 0x53b472ee, 0x27d67e4f, 0x8a0faf5b, 0xd74a14bb, 0x8563dc51, - 0x7dfd205a, 0x3b9f6ac4, 0x4672e809, 0x6f14bdf1, 0x246f1199, 0xf0e8563e, - 0x4fc96b49, 0xe315de70, 0x0a9877f9, 0x34e7ecb5, 0xa5cf9c9f, 0x5eb0a9e0, - 0x2cf7e370, 0xbd0b3316, 0xc008b03f, 0xe5517187, 0x188b1ffb, 0xe850afcf, - 0x8156c56a, 0xbcbe8ae8, 0x84bdf010, 0x103df845, 0x6af77fd0, 0x289bfdb9, - 0xc4f27bf2, 0xe28f3c4d, 0xfca7663e, 0x7d486591, 0xd7d7e912, 0x0f6ed07c, - 0xdb892ebf, 0x9c38e6f7, 0x3571f17f, 0xc61707e5, 0x276e9edd, 0xf9405f3d, - 0x6ef78213, 0xaf1bfbe9, 0xf3833f26, 0xb9aa8e27, 0x927801dc, 0xf485d59f, - 0x3b1ef14a, 0xcaebc795, 0xbf229ca9, 0x5efa161f, 0xcbe77f43, 0xb0be382d, - 0xf84160c6, 0xc03df15f, 0xffbfabb0, 0xebf394e6, 0x5c9ec512, 0x6be3c233, - 0x51e10583, 0xef49d718, 0xf3caa589, 0xb25b9c3f, 0x8b69f109, 0x1f5c2e60, - 0x00b669ef, 0x40f08b7c, 0x3dd1c602, 0x66cf7c36, 0x513053a0, 0x7265f53e, - 0xcc3aeb74, 0x1349a953, 0x2daf184c, 0x1852db0a, 0xa517f30b, 0x7677d324, - 0x1c78da6a, 0x4e4a0fb6, 0x92dc5307, 0x62aac7c0, 0xf1cf7e31, 0x3fb5cbe8, - 0xdfcf293d, 0xb3e65b3e, 0x782f8efe, 0xe3b5f11e, 0xfbe9bbb4, 0xef4f4c1c, - 0xf60fd3af, 0xd1c6fb35, 0xe855af14, 0xae39b068, 0x45a8e909, 0xa5a513d6, - 0x8ed1a9ef, 0x37b3cc68, 0x96ca1c23, 0x4b175c5c, 0x4e3e1ce7, 0x87dfe4a6, - 0xe502c9c6, 0xde46ffed, 0x5aba89fd, 0x5baddf2a, 0x9d776545, 0xe8079e8b, - 0xbf08238b, 0x7d6f101f, 0xf130d27b, 0x4733a656, 0xbe05be92, 0x90edf1e7, - 0xbbf02af8, 0x33efc018, 0xd9eea23a, 0x8348f680, 0xcdf782c6, 0xd2bcff98, - 0xfde1f240, 0x59c6c349, 0x2819f815, 0xf4c83b2e, 0xe9878839, 0x112aa919, - 0x926dff9e, 0x44e71410, 0x2273c1be, 0x7c8960df, 0xf9f952a3, 0xa30d69e6, - 0x7da194ef, 0x40fb22e0, 0xbf5df84f, 0xd40ae406, 0x20a665ef, 0x442172b9, - 0xf32380ae, 0xac5f7a33, 0x0936cb43, 0xe9cffcfe, 0x19ca5c50, 0xb878ce46, - 0xe61d199c, 0xb3be9e79, 0xf9461d50, 0x44efc0c5, 0xf2374767, 0xac25bdbc, - 0x461dd684, 0x3e7bd0de, 0x38188ef7, 0xbff414f9, 0xd90361f7, 0x9613eb39, - 0xe477ffe6, 0x71279fcd, 0xdf813c78, 0xed5d5073, 0x059b0e7b, 0xb15d8fbc, - 0xbe236590, 0xc439ef95, 0x7bf218c1, 0x39eff5ff, 0x123c988c, 0x0ae0e7bf, - 0xdc439efa, 0x30e7be15, 0x6171b26a, 0x461cf7e0, 0x30b11e4d, 0xc60e7bf8, - 0xb29df885, 0x39efc1ff, 0xbbce4fa4, 0x370e7bfc, 0xa0ff364e, 0x3d8039ef, - 0x4fe3899b, 0x63c6d8e4, 0x3b9f2899, 0xe3e5fdf4, 0x97643df2, 0xb2c52f68, - 0xa2a5c228, 0xc56dd176, 0x73d16df2, 0x5f03b63f, 0x1578444c, 0x037d963d, - 0x5125977e, 0xf2bca1eb, 0x49b6ad27, 0xb96bff38, 0x3cf8c9b6, 0x2f5fde34, - 0x73f60f9f, 0xcd0bf60b, 0xe2e8531f, 0x0e5cc9ae, 0xa9cb93cd, 0xc7bfc3f5, - 0xbf326f3f, 0xbed6be4f, 0xe077bf61, 0xd9feca7a, 0xdc56c596, 0x4ef7ec0f, - 0xb7ec27dc, 0x88664b04, 0xf80f7a0e, 0xc9757a72, 0x2e7462fb, 0x3fb38f90, - 0x9528f6e1, 0x14772ae9, 0x1ea30dda, 0x7ee14770, 0xe80e3547, 0xdf907df1, - 0x68f406ba, 0xf576fc3f, 0x7fdb1e80, 0xdaf9e36b, 0x9f6ff3a1, 0xf491fdcc, - 0x7e3403a9, 0x4dddfc0c, 0x1440c1fe, 0xe5e96dda, 0x14ae3447, 0xf66d4f7a, - 0x93764127, 0x8c7bf899, 0x01e636dc, 0x8c3d2191, 0x1e78c1d9, 0xe90c4163, - 0xef1d4ab9, 0xfdc0f95a, 0x38d1d222, 0x803bec37, 0xaedfaefe, 0xaf7e0c1a, - 0xaae34bd7, 0x5ec025e4, 0x64ee7a0b, 0x9474bf3c, 0x5ed08f2c, 0x39d9efc4, - 0x77d08fcb, 0x0b8ec0a6, 0x79be8f99, 0x594f9430, 0xe6bfb3ad, 0x62be5333, - 0x77a5bf50, 0xfa3d66ff, 0x5ba5e5b5, 0x2f17e435, 0xa58f5969, 0x269ef1c3, - 0x197d918e, 0xcbec1fd4, 0xfb65faa0, 0xf547d90c, 0xc7d717fd, 0xd02eb30d, - 0x13a456c1, 0xaa8e0e85, 0x4fd0e33d, 0xb30cea3d, 0x3c1df7f0, 0x269a5df4, - 0x5df4bdf9, 0xcadd39ff, 0x5d3965f3, 0x3f1df8c0, 0xa9ea8e8c, 0xaf1df2bf, - 0x1c8a956b, 0x8dcefa1c, 0x5e28b986, 0x7248cb39, 0xfff646ae, 0xc89897aa, - 0xbaf8511e, 0xb539e55a, 0x18c5fb1e, 0x8a9bfe79, 0x7aabf7d1, 0xcf9451c4, - 0xcfac3f4d, 0xacfba54a, 0x178f7ad8, 0x5db81de7, 0x15b9efa0, 0x5ab97384, - 0x9e389628, 0x4447e785, 0xa7815dfe, 0x98487e51, 0x37bfc147, 0xbf972530, - 0xf8cf103f, 0xca98db77, 0x369df21c, 0xed7a1e39, 0xeff1b4ef, 0xf7e7cd92, - 0x25510d72, 0xf9f1cba5, 0xf9e81b82, 0x1f52efc1, 0x2afee2b1, 0x71b4ef94, - 0x4e61bf7b, 0x557f3d06, 0x3d41af30, 0x5d807ae1, 0x7a6d3be9, 0xef80fbe4, - 0xf887bdb3, 0xd9f7d6ba, 0x1c0fef94, 0x23c3705d, 0xbd1c397b, 0x3355ef78, - 0xafe418cb, 0x3c3117ff, 0x56c0d29e, 0x000056c0 -}; - -static const u32 tsem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x3370278a, 0x45e39c30, - 0x8381e9f0, 0x5fd32918, 0x50c0cec6, 0x4055c401, 0x3f880bbc, 0x7c3032b1, - 0xff5e2566, 0xdb042935, 0x21818248, 0x88d7881e, 0x49a83031, 0xa41dc422, - 0x03261819, 0xb150a1f9, 0x5f3a4047, 0x0f77328a, 0x80a69c16, 0x872ae629, - 0x9163a760, 0x6819c647, 0x50e54bf2, 0xf40499f9, 0xa2be340f, 0xa2ffca8e, - 0xa013a10a, 0xe4d157e2, 0x3be542bf, 0xa6bafea0, 0x4edcdd8e, 0xc35dfd32, - 0xfc01a102, 0x9847b099, 0x009847b0 -}; - -static const u32 tsem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7dedff00, 0xd554780b, 0x733ef0b5, 0x7993331e, - 0x31e424e4, 0x1e4e1081, 0x03086820, 0xb78a8884, 0xf6301027, 0xd57876d2, - 0xaf0e2d58, 0x6b86f210, 0x7fb6bd2d, 0x78490806, 0x111fc1a8, 0x29e1d5ad, - 0x311d82f6, 0x0388b622, 0xbdabd228, 0x557c5837, 0x0bd11feb, 0x2a44908a, - 0xe5b5ef6a, 0x3ef6b5ee, 0x09939cc9, 0xafdb7b04, 0x7cfdffff, 0xc7ecee9f, - 0xf5ed7bd9, 0xfdad6bda, 0x8131c918, 0xe4230da4, 0x06fbfc22, 0x109d9221, - 0x9d37a132, 0xd72120e3, 0x66924218, 0x92ddfd2f, 0xbadc4214, 0xa349bfe2, - 0xe4febba9, 0x5f5f9a1a, 0xa4aff0ec, 0x4d1f5b4d, 0x2d096a78, 0x2fa1efbf, - 0x7cd04fc3, 0xad79ecfa, 0xce7eb4c5, 0x5d0fc924, 0x10ab1a1d, 0xd8e7ed02, - 0x520176c2, 0x9097e581, 0x927fa130, 0x45f8e8af, 0x9fe8b884, 0x37fe9724, - 0xa5b21c89, 0xd1e43e60, 0x99029ea0, 0x31364846, 0x7e6055fe, 0xf509fc36, - 0xd0677744, 0x779e75ef, 0x7fec13e5, 0xdb0a5f8e, 0xf27347e9, 0x4dc87203, - 0x6d08c6d3, 0xfb1dc749, 0xf908395d, 0xe4990cc0, 0xd8b68763, 0x0fca6ffe, - 0xd214754c, 0x080b67fe, 0x49d9f9ff, 0xcc82da36, 0x3be1eda6, 0x1a1f4e22, - 0xd99f67cc, 0xe0dfb8e8, 0x40dfdddf, 0x5fc0a7ff, 0xe5a1094b, 0x9e0c1ccb, - 0xc5d9d9e4, 0x1989ce30, 0xbf4316d7, 0x3213a673, 0x9d4d5688, 0x4490f63d, - 0x891aebf3, 0xcddb4edf, 0xcf1c0d29, 0xcbf8d981, 0xe80293a7, 0x60ee8e97, - 0xffc45f7d, 0x64ef38eb, 0xcc3fde3e, 0xfa102b1e, 0x8a97f641, 0xa0725da9, - 0x4bd153f9, 0x2d056a48, 0xee53191f, 0xd09a769f, 0xe6e9e4f2, 0x721340f6, - 0xc425211d, 0x1aea7293, 0xc91677fa, 0xad4228ba, 0xee8c0b6a, 0x4a6b0fe5, - 0x22f9fdff, 0x12fa01d0, 0x6a1fd6fb, 0xa0e9e99c, 0x7b375af8, 0xf4d08796, - 0x0f2cc0f5, 0xd9f5efe0, 0xd68f10b3, 0x676673f6, 0xfb5e0227, 0x06feef1b, - 0xfa08d03a, 0xb5b3c73d, 0xea48907e, 0x39fbf423, 0x31c3d13a, 0x9301dffd, - 0x0964254d, 0xb34d1b30, 0xd2a6d525, 0xe88d6cfa, 0x95e33891, 0x3b69b102, - 0x28994992, 0x0ff352e3, 0x2637bb61, 0x71c34ad9, 0xef0773e6, 0xb81a55c7, - 0x6fa50e67, 0x751274d6, 0x2912ba51, 0x75e2c6aa, 0x1a548a5d, 0xddc7038e, - 0x68425e1c, 0xe1c0cf7b, 0x02d86571, 0x47329fd0, 0xf5c2c40c, 0x42678003, - 0x4ca24a6f, 0x18f8e6ee, 0xfbbf72fd, 0x338f506c, 0x8e00bb8f, 0xecaa9009, - 0x0c8f0e3b, 0xb201937c, 0x43fc8296, 0xe02463c2, 0xb91eccfb, 0xe5070124, - 0x17f0a18f, 0xa42dae15, 0x1412d47b, 0x47ec56b2, 0x0324a4f4, 0xde1157bd, - 0x4f51290f, 0x42157e51, 0xd78b84ab, 0x129e6a5c, 0x35f06539, 0x193ba9f0, - 0x5e1cbfc7, 0xe518a048, 0x88d43152, 0xe307c078, 0xed4df92b, 0xbacba502, - 0x947ee5d1, 0x90218a6f, 0xe17e4333, 0x3bf457df, 0xbdccff37, 0xca91d29c, - 0xd3396b91, 0x2cdf8a8f, 0x8e92eb67, 0xc82008b5, 0x0f49b964, 0x40241210, - 0xeb6f0377, 0xbc78a2be, 0xfb5bbf04, 0xe7c86fdd, 0xc9983260, 0x053f9327, - 0x79bd07fa, 0xf0077ed3, 0x5edf3af5, 0x5d6bcc07, 0x7a825efe, 0xe8c7d38a, - 0x5daf95d7, 0x81d6ce52, 0xee808d7c, 0x9ea748c3, 0xc6a7d1f2, 0xa6767e02, - 0x748bf72a, 0x08933b7e, 0x6b75d9ea, 0xd02b7848, 0xb5e594b5, 0xb5e1696f, - 0x9d3b8e74, 0xd698bebc, 0xed06bcd3, 0x3adbbea9, 0x68870b49, 0x8d8b6b7e, - 0x85ab1fb5, 0x311f9a45, 0x8a148491, 0xc2c56d4f, 0xbe5a4e95, 0x17eaa375, - 0x34fd5eb5, 0x2d6725a2, 0xdeb2dfb4, 0xbdf00aa6, 0x3b23ad8f, 0x443849f3, - 0x39b1dfc7, 0x69239bf9, 0xf9b2143e, 0xf24fd387, 0xd945faf8, 0x022844a5, - 0x9c3a31b4, 0xae5c7921, 0xa9e50204, 0x7ecb7cbc, 0xa48ebfff, 0x5d363df0, - 0x45a0aff2, 0x4ccfd63b, 0x769e28d0, 0x3f048168, 0xc0f07f4d, 0xccefcc7c, - 0xdd00260c, 0x9f9c6e76, 0xc0f14c00, 0x461b99e6, 0xd2617b41, 0x6ce91d61, - 0x1f47ffd6, 0x00ec3a28, 0x9e994b38, 0x7e0d6a4f, 0xbcf9a253, 0x89b91249, - 0xadcf214e, 0x1fdbdc21, 0x4f5811b2, 0x8b6de8fb, 0xcdd44ebe, 0xb4eb5779, - 0x5d7f818f, 0x2009160f, 0x86353bda, 0x923741e7, 0xbeec8af0, 0xc85cefe3, - 0x5d2913ea, 0xbf2e0e80, 0x96675962, 0x4756f85a, 0x3c717079, 0x1c755ab9, - 0x897a488f, 0x578bd690, 0x62469ffa, 0xf07ae9f0, 0xe9f58128, 0x8163e78a, - 0x7ca05d27, 0x9cab830f, 0x1c1eb9ef, 0x6357caf7, 0x21b1f1e3, 0x7fa01eef, - 0x6177c522, 0x50eb0424, 0x0a24617a, 0x57c9e2fc, 0x9a0bb034, 0xc5c93109, - 0x7cfbd1a1, 0x1337201d, 0xaf583e22, 0x837e8dd7, 0x81568fc9, 0x6fe630f8, - 0xb7e4f7b4, 0xc1fb5893, 0xf87287a8, 0x697853ce, 0xcb87bb39, 0x847f4f59, - 0x732447ad, 0x4f75c21c, 0x5e7561e1, 0xc84c7d1c, 0x97cb940a, 0x817ae049, - 0xedcddea6, 0x6c06a751, 0x7900dfae, 0x910240b7, 0x134ddf38, 0x42d27ad8, - 0xe9a05d74, 0x162f44a3, 0x664b9d70, 0x2eb2d7fa, 0xbc9fd1f5, 0x16e9165d, - 0xd468df40, 0x8734803e, 0x23cd31f8, 0x92474c01, 0x26af4c56, 0x49f34c11, - 0xa405a63b, 0xaf43531b, 0x422a89f8, 0xfac4c47e, 0xa4e720c9, 0xe58b63da, - 0x3264d0bb, 0x3cce3eb2, 0x73782d9a, 0xf8ebf890, 0xe75f021d, 0xfc8aa648, - 0xf17af843, 0xe818b06e, 0xfc2854c5, 0xefccdbbb, 0x0ebe24e2, 0x693dea38, - 0xdd335780, 0xcd54548d, 0xf06d5a7c, 0x1c2444a9, 0xc41f32c7, 0xd6b8cc63, - 0xfb7356fe, 0x9c9f98c6, 0x491f23a2, 0x50cf666e, 0x71bdf438, 0x0828d1f0, - 0xab419e7c, 0x29b23adc, 0xb6494bbf, 0x6b9a5ac8, 0xe8764f74, 0x893f2f38, - 0x7ceb6747, 0xbe2af0ac, 0xa9b3c181, 0xcb0a9e07, 0xc297fa3a, 0xfea64ff3, - 0x1db24ca4, 0x86a20bd6, 0xbc56de70, 0x42def9f6, 0xd2e4fe8f, 0x57d66991, - 0x02d78a4a, 0x069f8587, 0xe37c7f68, 0xe47fea4b, 0x211bfac3, 0xa9ec2a41, - 0xe60101f9, 0x1a40ad7f, 0xc85e2913, 0xa0eda268, 0x6af5cd70, 0x698b8ecc, - 0x91f41937, 0x74c90b66, 0xee92cfbe, 0xe43ed023, 0xf41d9127, 0x6df367b3, - 0x7d695ba5, 0x63b69faa, 0x1e4005fd, 0x0b6d1dae, 0x9fd1b940, 0xf5329e4e, - 0x112efd47, 0xe836e1f0, 0xe4c3f163, 0x1fb436b1, 0x6fa27c95, 0xc75f2389, - 0x1d157cb9, 0x9eb0ea71, 0xb094cab8, 0x8ffa1b33, 0xb53e4314, 0x5d61f89a, - 0xe6cdd49f, 0x30e1c651, 0x59fa9de6, 0x6a7e0040, 0xc03b31f7, 0x3fd04855, - 0x74da3254, 0xb4dd1ff0, 0x7e42f50e, 0x50531754, 0xd83fa23f, 0x5f3d9e1f, - 0xd00bed3d, 0xb9d47d7e, 0x92be076a, 0x9fa0e9fc, 0xc8568f57, 0xf8bdfa60, - 0xfff63b3b, 0x1862a7b9, 0x47cf9989, 0x0bb1d10d, 0xa670c1a9, 0x67a618e1, - 0xed31da1b, 0xd30b786c, 0x594ae9fe, 0xebceda8e, 0xc0d7e27e, 0x3f0f101e, - 0xc00f3447, 0x5c75d51d, 0x12a21c17, 0x82802eb3, 0xd36fff06, 0xdaf0bcd8, - 0x086bc46c, 0x67d54de6, 0xe0367878, 0x9e000a5b, 0xc2223887, 0x77867cd2, - 0x01d03fc0, 0x3c8e8bca, 0x5cf102b7, 0x9e02c64d, 0x0ca4c937, 0x13e03cf4, - 0x827d89d6, 0x03800eed, 0xfe69f3f2, 0xc1fa8ffa, 0xf78659fb, 0x9e29978c, - 0x4b494e00, 0x8eadc664, 0x913b95f2, 0x27d7120b, 0xf9927abd, 0xbdf6bdd9, - 0xcf00eff6, 0xac894696, 0x68a6bc85, 0xf7b7114a, 0x15824a41, 0xdcdfc1d3, - 0x28fd3e56, 0xe2b90bd8, 0x5a648757, 0x3a5eb43e, 0x4f2311d9, 0xfd746559, - 0xb0c276a4, 0xecf2e6e5, 0x074f3990, 0xb7347f40, 0xc43e5cc5, 0x87aef5c6, - 0xad1e4078, 0xe8b65af3, 0xd3fd7157, 0xea240d55, 0x02f26396, 0x1791a7c3, - 0x423b13bc, 0x46cb7e74, 0x4c038c11, 0xb3f5b1b7, 0x7ca3be15, 0xd74f2f71, - 0x5231fa5b, 0x46dba269, 0x193d30c6, 0xddba7d6f, 0x46ce3c56, 0x4db06bfb, - 0x72a3671e, 0x042292e4, 0x5b9777ec, 0x93f9e3d1, 0x8e126dd3, 0xebb5209f, - 0xfbab8522, 0x4adfe23a, 0xee4cbef1, 0x2c7c828e, 0x21fcd62b, 0x30fe4750, - 0xd51263ca, 0x15f66261, 0x700253c1, 0x6c4a7850, 0xfb044e38, 0x0738a6e9, - 0xcc997dfb, 0x4a365dfa, 0xf6376823, 0x3655e703, 0xd80ce119, 0x34fd0904, - 0x1555974e, 0xa34df739, 0x9f554ed9, 0x2667fd05, 0x78c16705, 0x7e6fb946, - 0x1963fa29, 0x2bf4ccc3, 0x0167d477, 0x2206547f, 0x4e7f80d3, 0x926c5f7b, - 0x36b7bce9, 0xf144bf10, 0x702b9eff, 0x7357f41b, 0xb008fd7b, 0x5e06df7f, - 0x3b2a0098, 0xa5ac7a80, 0xa25fa564, 0x148972e5, 0xca3f2995, 0x25bf0f13, - 0x2a1a4017, 0x938b3886, 0x477d33d4, 0x35224bf5, 0xf5231cbd, 0xa27e218f, - 0x72d03c80, 0x60256f55, 0xdba8380f, 0xef863270, 0x1e734c94, 0x7cd8fa6c, - 0x72e37a7f, 0x27e79829, 0x09fe0387, 0x49dde9da, 0x26927fcc, 0xde000bfa, - 0xa6ffaf7b, 0xc4fcf006, 0x67f93366, 0x5a4d7f56, 0x79696ffe, 0xfee26810, - 0xd5fcb4b6, 0x80f1bcb4, 0x979c5697, 0x9432ca63, 0x24f0050b, 0xbf07f932, - 0xe41d67be, 0xcf5bf878, 0x572f58db, 0xf835bc37, 0xa720e1c3, 0xa43f831d, - 0x052d59c4, 0x3e42ff91, 0x1c28b5f0, 0x098f9992, 0x62134f78, 0x18176e52, - 0x5a9c9bf6, 0xdc947488, 0x988ea9d2, 0x8fc0ddf5, 0xc1ddfcb2, 0xf4878e1f, - 0x78ad4c6d, 0x0120a455, 0xd768d03f, 0xe018b713, 0xe234effa, 0x1fc479a9, - 0xa47338a5, 0x7a6a78b0, 0xf30a285e, 0x09fd5272, 0x233dd3eb, 0xf0c56b5f, - 0x3b0fc581, 0x3f20ad94, 0x61b68cb4, 0x7865b35c, 0xf90290e4, 0xd1406a0c, - 0x5dca677a, 0x4c6d8821, 0xe37c63cd, 0xd4f5b3f4, 0x7e8c3c35, 0xbdbfa198, - 0xad5e1f1c, 0x67b3f51c, 0x31ded9a2, 0x2b2701d6, 0xdb36f4a2, 0xa694ce51, - 0xbe82c54f, 0x9b539a7e, 0x69e51a76, 0x233fb9a4, 0xe36ed1de, 0xc96b8bf1, - 0x593768b5, 0xe1fd12e2, 0x71f86bcd, 0xdcbcd913, 0xfc1849d3, 0x5189f4e6, - 0xcfd79bc4, 0x9bd866f0, 0x9bbf3e1e, 0xfc04234a, 0xf3f89ebe, 0xeb6f0ccd, - 0x7fa28baf, 0x29ec7eb7, 0x85bd67b4, 0xce3f261d, 0xa1ca1ef8, 0x76c4fcfe, - 0x18f6a1a8, 0x23711bcb, 0x19e9a78a, 0x61ebbd69, 0xaddbb72b, 0x92275374, - 0x4763d062, 0x8315a747, 0x84b7bede, 0x3cab4ec2, 0x6297587a, 0x7ef2adf0, - 0xdf867cd4, 0x7cd8cb7b, 0xd3f47b69, 0x93989def, 0xf266e304, 0x7f11b0f8, - 0xebcbf1ee, 0x284f78cd, 0x2d85c4b4, 0x67eab77e, 0xcc4b52f4, 0x5f39abe5, - 0x57a7222b, 0xe8ce192a, 0x4f3e3035, 0x84bcf832, 0xdf3279f1, 0xd12f4837, - 0x921d010e, 0x4dff994a, 0x4df37e2c, 0x5e8c1d29, 0x00c88f37, 0xa9fefc3f, - 0x97663edd, 0x7126ba30, 0xc6efbc7e, 0x71c80211, 0x40268972, 0xc33e727d, - 0x13c53253, 0xa5c977ac, 0x4ef6efcc, 0x525db0d4, 0x0b5ba309, 0x5fe14c7c, - 0x898a7403, 0x5b4b3b1f, 0x6b7fa075, 0x741d4ef1, 0xe1c53259, 0xd4cf0a20, - 0xd81b0a52, 0x805fb49d, 0xc51853d7, 0x49525ab8, 0xfca5d870, 0x82a2427a, - 0x10f887cd, 0xe94b686c, 0x7e58253c, 0x20b26268, 0xa7ef7ed0, 0x80f1c07c, - 0x8f173c71, 0x785fdfa3, 0xfddcf512, 0xc8364df0, 0x1cebf6a9, 0x36a5279a, - 0xf707f83f, 0xf108e697, 0xbcc6e7e2, 0x2acb83fb, 0x35f812c7, 0x9572fc31, - 0x16dee3c8, 0x22475dfe, 0x57c82e6a, 0xa5f76f48, 0x830feaf5, 0x65e47aff, - 0xfecbe312, 0x87a189f4, 0xb21824dd, 0x1fd5f765, 0xdef8ce92, 0x7940179e, - 0x24ef03eb, 0x8a52afc6, 0x9136fcb9, 0x5e867fdb, 0x140792d1, 0x00a12727, - 0xd72277ae, 0x02da4f4f, 0xf054c50b, 0x4eb8c3bb, 0xae74c8b8, 0xca9f1937, - 0xe6a6ff9c, 0x4ae2bd33, 0x9776b089, 0x903aa78d, 0xa834d6df, 0xc65a1fa8, - 0x439ed5de, 0x7866b0f1, 0x73be1f93, 0xb9196b8c, 0x3cdbf68d, 0x2b70797c, - 0x30fdc00c, 0xac22bfd4, 0x8d5f8c83, 0x0e03307d, 0x61d21992, 0x7e09cc9f, - 0x2467e011, 0x24905fdb, 0xeb8fb512, 0x4795df1d, 0x6967cde1, 0x0dc19f28, - 0xb6ebc9fe, 0x6f9c2ae0, 0xa2946b7e, 0xc99bce9b, 0x42216acb, 0xebcc225c, - 0xb21e7c72, 0x9f8ebe31, 0x025df7f6, 0xe1c4d3ec, 0xdb22dddf, 0x472d59a7, - 0x7e085088, 0xf289ed1b, 0x6a6ceac9, 0xa381c797, 0xd56bf391, 0xc3f8672e, - 0x89ab7e18, 0x75f29924, 0x1fc233fb, 0x7711fac6, 0x514fb80a, 0x4358d1cd, - 0xcf00b23a, 0xf61a29ef, 0x48eb6b57, 0xe9177c83, 0x78025b4e, 0x8b8f0310, - 0x5277fd74, 0x90b8c4be, 0xd6eb607b, 0x81a7f0e5, 0x4085d10c, 0x0fa9e4cb, - 0x178e9879, 0x69e307dc, 0xd2bf2b2a, 0xf5f0e371, 0x4d7cb10b, 0x6a5957c4, - 0x147f6be5, 0x129ddaf9, 0x9fb77ac5, 0x8fc1b5f1, 0xad1f9c89, 0xbf8c687c, - 0xd6afc79e, 0x335f3e72, 0x708549a1, 0x9b51dadf, 0x2ce69e30, 0x7c015cda, - 0x25aa32de, 0x64de7c0c, 0x17df35f0, 0xdb2efea1, 0xa35ad31f, 0x72264eb0, - 0xeed456be, 0xeb7b9006, 0x38935d7c, 0xbe0534bc, 0x5f39b806, 0x93f807bf, - 0xae08ddfd, 0x076bd7c1, 0x45bad7cc, 0xfed39b6f, 0xc2d927fc, 0xf1891ed7, - 0xd7c067e7, 0xb30a4f00, 0x963edc63, 0xdfea7eca, 0x06e7e9c7, 0x6b99f989, - 0xe5ac1cb9, 0x1fb6b072, 0x223ff839, 0x9afe03f3, 0xc98b3072, 0xe5a24381, - 0x8cae9389, 0xd3b0251f, 0x9e7bc8e3, 0xe1b5fc24, 0xbc4334de, 0x27fe3c72, - 0xbe84cd30, 0xcfd234f4, 0xe4c0e744, 0x73c98f3b, 0x76be727f, 0xfe387c68, - 0xa7f46453, 0x26922ef8, 0xffbe395c, 0x7215705a, 0x43f0367e, 0xb728c582, - 0x3a667a31, 0x86a92bc0, 0xd304799e, 0x28ad79a9, 0x81be86a7, 0x2bfa0a58, - 0x3bc62b6a, 0x68ad999c, 0x98f3399f, 0x24fc31be, 0xb88d7ceb, 0x33d71378, - 0x02217949, 0x853d9feb, 0x9eaa3f70, 0xcc9951f9, 0xd5e2301f, 0x18a8fd86, - 0xbbd0d47e, 0x79a79f70, 0x97da3d78, 0x3bd637cd, 0x36c3ede2, 0xf077eefb, - 0x3ed35f4d, 0x0e5a1aeb, 0xbbc9aefd, 0xc3b3c49f, 0xfb18798c, 0x6e3e4e46, - 0xa8b51e73, 0x32df5c60, 0xc76adefc, 0xfeb26734, 0x7ae7be7a, 0xbbd1ee57, - 0x54768f2c, 0x6f9f8c6e, 0x03e0c7e9, 0xa343e885, 0xe4183710, 0x4ce7091e, - 0x3f04849a, 0x924dc7d8, 0x90729d20, 0x5aa97b1e, 0xff401689, 0x9cbc6627, - 0x3db2f685, 0xbce406b8, 0x0380abe9, 0x53aba9e2, 0x96c6f35e, 0xe6f19d9f, - 0xa56cc1b7, 0x7ee2d5df, 0xb148838e, 0xdc2763fb, 0x4b7ed1db, 0xe9c737c8, - 0x09ae149c, 0xcc13c402, 0xbf8f0ae5, 0x72e69928, 0xa45fc799, 0xe7394b14, - 0xbe34b90f, 0xeb93795e, 0x7602df15, 0x1cc4e74e, 0x713bd716, 0x30674f2b, - 0xdbc73efe, 0xc234f375, 0x535feef5, 0xf6e5251f, 0xe29befc2, 0x9922f8c7, - 0x3ebb4765, 0x2b9d852b, 0x26e7b120, 0xa26b5fe0, 0xccfc6244, 0xff9781a1, - 0x61d4f108, 0x06cabe0b, 0xea156b3c, 0xdb465861, 0xc79c6ca5, 0x28f74263, - 0x3ae6cf18, 0x02f5fb8b, 0x6a72e345, 0xdbf40b12, 0xef8521db, 0x3a52c0bd, - 0x91057b8f, 0x37c0ecbf, 0x8c29d022, 0xb1448ba9, 0x303a43de, 0xe61b089f, - 0x5187e0b9, 0x33c44bbf, 0xc61b614c, 0xf6cc7e8d, 0x7888d643, 0x03a8836e, - 0xedc9bfb4, 0x4297f82a, 0x1ae77e88, 0x40be77f8, 0xc4c8316b, 0xc608b2e0, - 0x7cedad93, 0xa039d853, 0xaffb7a3e, 0x5237df4f, 0x548f8173, 0x1ce8372c, - 0x694ef514, 0x5ff2df42, 0x12f38189, 0xdc58abc6, 0x2a5f5acd, 0xde4017e9, - 0x0bc2e5ac, 0x7e053a7f, 0x6467aaf4, 0x3ca7a3f4, 0x41bf4723, 0x045b35f3, - 0x076d53f4, 0x770fe89d, 0x51f2c23e, 0xfb43a28f, 0x8c05db73, 0xdbd9d507, - 0xe201bdef, 0x0488cf8a, 0x19708dfd, 0xe29d8bee, 0x59fb2673, 0x80079cbe, - 0x9a1cb66a, 0xec57df0b, 0x77d813b7, 0xf16e79a8, 0xf9a06fb7, 0xf464c7c5, - 0xac766a51, 0x657f6050, 0x40885849, 0xc1326bbe, 0xc4fb43f1, 0xbeda0ef0, - 0x369edbcb, 0x2bfb0dc7, 0x455da20e, 0xa7b4f6e1, 0xa9f4a6cd, 0x0d353f0c, - 0x2ddcabbe, 0x98ffc1f8, 0xa38eccf2, 0x9abbf419, 0xa73c0427, 0x45cbb550, - 0x9cba18b4, 0xdfa3136a, 0x9d33f880, 0x8bc5f827, 0xc034eb49, 0x0d8ecd7b, - 0xb713168a, 0x9230d33c, 0x7cdef668, 0x1c7413cd, 0x93ed5dfa, 0x58a61f82, - 0xe041236b, 0x9ce7ce8f, 0x30dcdb65, 0x08ca15bf, 0x59abcc0f, 0xc38b7681, - 0x7ec1f6f3, 0x8b78657a, 0x57d68d32, 0x2945b23e, 0xaaa7e18f, 0x2d10d75d, - 0x6d4e3f86, 0xd4bf4dce, 0xae867b7a, 0x54f0b15b, 0x88b7a612, 0xc4665614, - 0xc8767bec, 0x453f9c49, 0xdf06ff53, 0x18275e87, 0xef3d0ac7, 0x741abc41, - 0xbd32a65b, 0xbcedd060, 0x7528e9ca, 0xb388cd17, 0xd02f7aaf, 0x2af10ec1, - 0x1bfbd315, 0x6c6e987c, 0x9b3e90d0, 0xe1577f00, 0x7b9606be, 0x88629127, - 0xa275788b, 0x3c9f52c2, 0x21962f5d, 0xf960124e, 0x8283dbb4, 0x1bf98976, - 0x383926e9, 0xb75c820f, 0x964c4fc9, 0x49bebae8, 0x7e252e09, 0x77b4be3a, - 0x6075c972, 0xc8e705a7, 0x1d9fb0a9, 0xe8f160ac, 0xa2e40f88, 0x7ccbef89, - 0xd6f2664b, 0x7c60a194, 0x8bf7d364, 0x41eda1b6, 0x7d365e18, 0xec277cbf, - 0xe67ed1ab, 0x1aae54ca, 0xee4fda65, 0x9b49fbe5, 0x4fd4d13b, 0xa30adcda, - 0x8fd8c59f, 0x6cfd6073, 0x19bd7b9a, 0x4695b99e, 0x8fd8f53f, 0x4af36067, - 0x199263bb, 0xb1aa3b9e, 0xfddbf49f, 0x06881f68, 0xdc7690ff, 0x4eef7517, - 0xc496b71a, 0x1fe4d1f2, 0x2a1e78c3, 0x947cb155, 0x24c13138, 0xb27a494f, - 0x74a83f29, 0x6a7da9b0, 0x9f54c720, 0x85b5765e, 0xbfa8dd2f, 0x8a814f31, - 0xab38b126, 0xbd415832, 0x81d83c53, 0xbb06bbf9, 0x75dcef51, 0xb02af07d, - 0xd05600f7, 0xc12977f3, 0xbe1c6a31, 0x0812f3a1, 0x1b34cfc6, 0x32ec7da4, - 0x7939efbe, 0xde2357c8, 0xd9d7dfa7, 0xd12447ba, 0xf14a43fc, 0xadef3023, - 0x8de3b332, 0x9d824338, 0xce6bfea0, 0x8a16da2e, 0x50cb6bc1, 0x6f422fca, - 0xd0722dbf, 0x73b8fc07, 0x4a576ff5, 0xa1a6be14, 0x7a6e1e0a, 0xe1edfe5c, - 0x9b99b510, 0x00fb9687, 0xea8576ff, 0x15f1d88f, 0x8e3e7e3a, 0xdfc61bbf, - 0xd93b332b, 0x673dbe3a, 0x477c69a2, 0x7c698556, 0xa7c74287, 0xf56fb1f2, - 0x8a7c7c3b, 0x7909ebbf, 0xc7077e56, 0xe05567b7, 0xa90acdf8, 0xd09f8d30, - 0x9001fe33, 0xcdfdc39f, 0xf37ae73f, 0xcd2ab3fc, 0xfcd857f3, 0x80feae8f, - 0xf3809f8f, 0x80fe597f, 0x92ab3fcd, 0xfacedfcd, 0xdbdf19ed, 0x6157ff83, - 0x37f5affe, 0xe649dcff, 0x36ab0ff9, 0xc6cedfcf, 0x27f5637f, 0x8e377c7c, - 0x09fca6ff, 0x6ab0ff9b, 0x07b15f1c, 0xca47c0fd, 0xf07a8490, 0xa461a99f, - 0xa35d4061, 0x923a40e3, 0xc837a9c5, 0x5dc70839, 0x3eef8c09, 0xe6fca04f, - 0x24a7d5ee, 0xea90254c, 0xd3ce5acb, 0x158bbb55, 0xd0842fe6, 0x41c4585f, - 0xc45fb85d, 0xb46c8cf5, 0x78538787, 0x218bf73b, 0x78dc2fc8, 0xac5b9e23, - 0x77dc13b3, 0xfa3056a7, 0xc0f1ff1f, 0xf3b1ade8, 0x5a8ba6b2, 0x13fecb65, - 0xef38c783, 0xa6ab2454, 0xa78829fc, 0x127c3d50, 0x9e9a1ffc, 0xb478e996, - 0x83f043fc, 0x1b958aae, 0x768c2e76, 0xce9f2277, 0xfe1cbbeb, 0xf7c31253, - 0xdc053ba9, 0xc37cf847, 0xd9f40552, 0xc99756a2, 0x74e3a86f, 0x8ece7eea, - 0x79c68dfb, 0x14505bbe, 0xc1fdf909, 0xbb051d6f, 0x41e6f171, 0x276eefa6, - 0x1470d5e1, 0x79fac173, 0xff3a5543, 0xe3eccadb, 0xeb6b8c44, 0x9c1c5843, - 0x49b8810c, 0x7906db59, 0x52dccd08, 0xf9ec9b26, 0xfce6835b, 0x7ce6156d, - 0x6d961ca7, 0x112ccf60, 0xefda16c8, 0xcb65ebf7, 0x8e3600b9, 0x76e64957, - 0xbbef1b25, 0xb4198694, 0x8e90fbe8, 0xe9156283, 0xdf65573a, 0xddd4f01a, - 0xae28932d, 0xb8a91dc7, 0x454a140f, 0xb2a82dbf, 0x9de15b79, 0x00f43b2b, - 0x8fee6785, 0x15a7c444, 0x2e838efe, 0xf3ed46dd, 0x907fcd8e, 0x9d6c7e21, - 0x3bfe158f, 0xa3e75b96, 0xcc3eb02a, 0x19cb590b, 0xa9f9589f, 0x36f17f6e, - 0xf37b3db3, 0xb5fb58b6, 0x530cd76a, 0x56f8497e, 0x9bc5fb53, 0x17ea99e7, - 0xd5312eb5, 0x6a59682f, 0xfd0bcfca, 0x8efed4c8, 0xf54c2be5, 0x635fafdf, - 0x62adbfaa, 0x6b7f2983, 0xfb5321f0, 0x98b6ca5b, 0x47076dea, 0x68e4077d, - 0x9e22ebd5, 0x3ee0bdfd, 0x9bd82f75, 0xee12dc17, 0xed447e73, 0x33839015, - 0xb4815ed4, 0xf478ff73, 0x2c1ea9a7, 0xf9a24d87, 0x2d5598ca, 0x0997a099, - 0x6572cfea, 0x24d0aac2, 0xd7b0178a, 0x9b887ca9, 0x041d1215, 0x0f724cce, - 0x318b771f, 0xa9971df5, 0x7d054cdf, 0xb17adf7c, 0xdd797e23, 0xd4c379d6, - 0xaf6a7e38, 0xb02192dc, 0xce5975ce, 0xb569189f, 0xb1a73ce5, 0xeb817dbf, - 0xe9856ad9, 0x19bdea83, 0x86736193, 0xe223e5fa, 0xf9ec9b9d, 0x0db0223e, - 0x53feb048, 0x98861f81, 0x76aa6bf6, 0xfbe49ae5, 0xe11121ec, 0x409d05aa, - 0x5217eaf5, 0x72028d60, 0x35923d16, 0xa1c0346b, 0xef4055af, 0x75c54fec, - 0xe9436cfd, 0x3fafd836, 0xf4c010d3, 0x4c3286a3, 0x3104354f, 0x02a1b0fd, - 0xf50d93d3, 0x2c347698, 0x86bdf4c7, 0x36efa610, 0xbbfa60b4, 0xdf4c5686, - 0xe98cd86a, 0x4c610d1b, 0x4c741b3b, 0xd1e8790d, 0x0f6e01bf, 0x84d71b1b, - 0x2e7cc3db, 0xe73da98d, 0xf7ff70c2, 0x11f3fbbc, 0x7f9fef60, 0x6cfb8ecb, - 0xcacbe1fd, 0x51d3fd6f, 0x3ca57b47, 0x639d083c, 0x8133bd6b, 0x2369c9d1, - 0xec1c64a5, 0xcff4ecff, 0xc4bcc7cf, 0xfd84f52e, 0xfa713c33, 0xfa5d7885, - 0xf444e9e5, 0x949982ee, 0xfe1ea71e, 0xf7e822af, 0x607fac02, 0x71111c07, - 0x6dd1261d, 0x95d7a07e, 0xe1784de2, 0x2f1059f7, 0xbf83d73b, 0x8b882cf6, - 0xd8a8ab5d, 0x3b36f9ff, 0xf9d2f881, 0xcfbc2e03, 0x36d8fe75, 0x32e3c82f, - 0x3d8e189f, 0x6b4d6147, 0xb761d922, 0xe736efc9, 0xa50ab7cf, 0x689a1e78, - 0x0347b389, 0x3861a95f, 0xe0d9d20f, 0x67e8d4c3, 0x71c14f99, 0x65caecce, - 0x5e7e3371, 0x424eec83, 0x277ea57e, 0x869fffb6, 0x0c7ebfa7, 0x23690878, - 0x5e08381f, 0xdb98bb71, 0xf97efb7f, 0x814cfa49, 0x20392af8, 0x82f60e7f, - 0x1177fe9d, 0x6122651c, 0x2eb7e8de, 0x63ec8622, 0x69b77ca0, 0x669dfa3c, - 0x7317f4f8, 0xe6b7c52e, 0x042234fb, 0x9c46bf68, 0x80fe0aa4, 0x02f530f3, - 0x788cabc6, 0x6ee49749, 0xc6f4c611, 0xbc78ea4b, 0xa1d1c6b8, 0xb9d16904, - 0xee4bdcb6, 0x38699e9f, 0xaf39c2a6, 0x02ab470a, 0x64454fce, 0xb9e80954, - 0xd2ab6d73, 0x12ac1ec0, 0x2f15dfcf, 0x67679b7e, 0x6125bd71, 0x8ebcdbb9, - 0xb420fe72, 0x1d9ca35f, 0x8a9f7472, 0x31b59fc9, 0xefdadb3b, 0xf6c0fb04, - 0x1f776a2d, 0xd683769f, 0xfbb54f17, 0x3e30553f, 0x5c53112e, 0x7bdfc0c9, - 0x9d82604a, 0xd772a9e2, 0x7e8f68fb, 0xdc468724, 0xd4fd097d, 0x9f6e7e77, - 0x88727ce9, 0xf338c3b4, 0x8881f227, 0x743bcb76, 0x15f8fd3d, 0xe4db9d99, - 0xf67b80e7, 0xfebef995, 0xdf9b9e02, 0x84e78556, 0x8ff7de3e, 0x242dff68, - 0x81d22f01, 0x1d8116b4, 0x4ad88e79, 0xc8e74f01, 0x31f1de6b, 0x3a95b874, - 0x05ef404a, 0x863b662d, 0xfca6bfda, 0x7ce6cde2, 0x06999939, 0xa37ca4fa, - 0xce02c24c, 0xb37f54cf, 0x177ec55d, 0x5826fa93, 0x8fee2557, 0x348957cc, - 0x9ad5ea84, 0x34567f67, 0xb411c28f, 0x88c83f33, 0x66492cbf, 0x4a656076, - 0xc27d8158, 0x7fc6da0f, 0x832006f7, 0x7104dc3d, 0xfc489228, 0xfc5f483b, - 0x56fc295e, 0xbaf58d78, 0xc3881c4f, 0xe212ee21, 0xdad603ee, 0x86cf6e05, - 0xe7c03d30, 0xc705f86d, 0x7615f92c, 0x2452de7e, 0x9cfdd022, 0x12d908ea, - 0x851fdeb1, 0xbb5edc78, 0x7106957f, 0x7b6ac0fc, 0xdfdc6f6a, 0x0f649768, - 0xe159f962, 0xf73c72d5, 0xf00b4520, 0xef8f21de, 0xc41f9c2b, 0x9c016f04, - 0xdc40f523, 0x3a75ce1e, 0xdf215bbd, 0xf3c0a9e4, 0xef20751f, 0xbc7bbfb4, - 0x9c418ed3, 0xa35a41da, 0xbb5fe53a, 0xa01fb2cf, 0x902ef399, 0x5067d04b, - 0x09a2e780, 0x235cb9c6, 0x7e3cedcd, 0x2e31fe73, 0x4381748f, 0xdf39ee3e, - 0xe14770e6, 0x2899093c, 0xb7f1ed9d, 0x63dfc072, 0x56fdc3f0, 0xcaa77f68, - 0x7df2d7da, 0x9edf3bdd, 0x097c9e9c, 0xa5f7547d, 0xeb31c240, 0xadd49d48, - 0x7dd61f00, 0xd7f96129, 0x5d1a9bd6, 0xe6f46355, 0x59f04a2b, 0x27a604fb, - 0x8e813e01, 0x64dfbb13, 0x027087bd, 0x2f4261f8, 0x386d7c3f, 0x7f498852, - 0x8f04a7bf, 0x6be383c5, 0xd3ebeff7, 0xbbe009ff, 0xf3feb1ff, 0x11dff4fa, - 0x679afe0f, 0xd10becf7, 0x17f2b5f5, 0x10e1780f, 0x6b52c7d3, 0xacef9c1a, - 0x0bdab1de, 0x1491f972, 0x3f5d02f2, 0xef718b0e, 0x0c3ba6e7, 0x70ddd3be, - 0xf396b08f, 0xaf9f99dd, 0x2ff836fb, 0x5590ef9f, 0xb2ec0f8c, 0x2994ed47, - 0x3096db6b, 0x7f65d8f9, 0xf19be59f, 0x7edd53bc, 0x7ca8beb3, 0x0d3481fc, - 0xb885550f, 0xff451cff, 0x7ffb76a0, 0xabbb034c, 0xdea3748e, 0xe3077eb3, - 0xf68c997f, 0xb1253cc0, 0x0e71bd6f, 0xa5e38eab, 0xde1d6dae, 0xbb6baf13, - 0x9a1334f9, 0xad3bf40e, 0xbb7055df, 0x9f30e1df, 0x42f034df, 0x5feeccc2, - 0x0583c4f5, 0xceb853ef, 0x2bc57f6e, 0x29f2c7e4, 0x23e77fd3, 0xa5fb1e0b, - 0x755cbfd6, 0x6b18fd52, 0xb4eb1b5f, 0x2bfb9fb6, 0x2d5a5807, 0x0fe0bd47, - 0xf1916f56, 0x9ef57bbc, 0x861f3b6d, 0x76dbccf8, 0x7fda70ff, 0xde979ed5, - 0xabe69eb8, 0xa653929e, 0xe1b869b3, 0x9f41a29e, 0xf2dffa3a, 0xa8f4bd71, - 0x4525fa7c, 0x7fcacd1b, 0x974bdc9c, 0x290ea7aa, 0x7c5f7464, 0x521c894c, - 0x85b67ed8, 0xa7f7913e, 0xeab15f81, 0xd0142f89, 0x141f1f5f, 0x1c767a48, - 0x09796e7c, 0x13c063ed, 0xabd393d2, 0xf6967e87, 0xa82e9475, 0xb2f42d17, - 0xaf98fbb6, 0xc42fd007, 0x3f7f29e3, 0xb7d84bf9, 0x0fdd9df9, 0xf278a878, - 0x9f30bc9f, 0xe33d52d3, 0x4ead9ff3, 0x1520fb83, 0xc54d2872, 0x3c579594, - 0xbfe403fa, 0x907fc7c5, 0xeac5cec6, 0x575cfc19, 0xd173cc06, 0x9e707323, - 0x7c8824e5, 0x7633f158, 0x4482fccf, 0x238a9f4a, 0xd839f727, 0xab7a763a, - 0x4f11371d, 0xfb0242c3, 0xe189af18, 0x640f181d, 0x607f0de7, 0x65913fec, - 0x60e0bf98, 0x30e45af4, 0xa5d1f1ee, 0xb77f9624, 0x9d03b737, 0xd3d50cce, - 0x475c8e21, 0x87c710a4, 0x2bf69170, 0xce9a9f1e, 0x52681dcf, 0xea8eff11, - 0x0e5029ff, 0xdd65dbed, 0x8efa6059, 0x1deecc5c, 0x3e3e4eff, 0xec013b85, - 0xd469d3d7, 0xbf338c1e, 0x9d630e03, 0x0c5676a6, 0x3bc8c59f, 0x6bedff93, - 0xf21bbc98, 0x0a519e1f, 0x609d9ff5, 0x81df0472, 0x8ae142fd, 0xa1fd63a6, - 0x07ea02d9, 0x93c6893b, 0x9732edf3, 0x95bd7373, 0x12fc285f, 0x7c3dc7ac, - 0x2324e303, 0x2dbed01d, 0x8fbf48df, 0xae30abd5, 0x86bf6fb7, 0xfae62f1c, - 0x1f45ad60, 0x07524790, 0x2d5b7fb4, 0x0c3e7787, 0x35e54bf2, 0xcafc81a4, - 0x27c15ef8, 0xf1bc8fbb, 0x9fb72a3d, 0x35b90c44, 0xdcab55eb, 0x409dec56, - 0x27edc9e2, 0x2b893f6e, 0xae3cb4b7, 0x903bbadc, 0x7ad6ff9f, 0xd3e3c0d5, - 0x7a1a3c16, 0x5a7c3fb2, 0x1db7e4f5, 0x493d5c5a, 0x45209dff, 0xe0d1f97d, - 0x2aff8343, 0xcf06a5ff, 0xa9f0f50b, 0x7c3d87c1, 0x9f61f06a, 0x8f09a478, - 0xe1bbfad6, 0xc0853a6f, 0xcfc63273, 0xfdb00fab, 0xd1ddfa67, 0x2f888521, - 0xd239971d, 0x4a48747a, 0xc96c3e6c, 0x75ed2c47, 0x69603e4b, 0xebe4b41f, - 0xf7abed4d, 0xb9d8511f, 0x9da9a89e, 0xe4a7fcb8, 0x01f13883, 0x6baa1d63, - 0x010954fb, 0xf1bbb87f, 0x0925797b, 0xfe5e2079, 0xf2f188bc, 0x26e38a2e, - 0xeed74e3a, 0x608f7c6c, 0x57c593b5, 0x2f6ed4ba, 0x93ab93d8, 0x553bbe58, - 0x683d0269, 0x593b7794, 0xd02bafdc, 0xb18a4ded, 0x203fdeef, 0x08ef1ea2, - 0x7e78d293, 0xa140de28, 0xfd20edf8, 0x80fdb3d5, 0x61d7b02e, 0x30ac84bc, - 0xd154e3f0, 0xe21cb59d, 0xde22ad35, 0xe2b85b6b, 0x239c2f16, 0xfb903ae9, - 0xbe5a329d, 0xdb22d7e8, 0x52e90ca6, 0xf81f8c46, 0x9a6d0911, 0xf5fec024, - 0x059fe47a, 0xb85f9807, 0x797c7d70, 0x95dfe4a8, 0x4054efbb, 0xee7f52ef, - 0x87beec64, 0x23c54fd1, 0xff03f296, 0x15a6e5c8, 0xdb951fe3, 0x1e41f5cd, - 0xe4ec183f, 0x92c7bee7, 0xb77fdcb1, 0x9e0fdec5, 0xa77fe62a, 0xeba7d28c, - 0x3ce04898, 0x2203f9c1, 0x6efce7d2, 0xe3007e76, 0xbf01d7fc, 0xe7b12b77, - 0x7c82cea9, 0x1ebfd55d, 0xefccfb3b, 0x3e06ee8b, 0xc14ef7da, 0x767a694f, - 0x7e23dbdf, 0xdf67f905, 0xf4877acc, 0xa0e53f6d, 0xba55f713, 0xff907a0e, - 0x4dff9ebb, 0x7f90ddd6, 0xecf18ece, 0x145f83ae, 0xad753f00, 0x1e8057b4, - 0xefe7e2ec, 0x45ff3d56, 0xbfae0741, 0xa9c7488d, 0x9f4fe64e, 0xef5ff03f, - 0xf381fdc1, 0xc0ace807, 0x42e838be, 0xa5fbaaf9, 0x5d6fe313, 0x14517fcf, - 0xa5fc27eb, 0xfbe5a9f3, 0x521e5d9d, 0x4be017b6, 0x7544fb62, 0x1b6ebabf, - 0xd3512fbc, 0x40594876, 0xf0bca7eb, 0xafd002a7, 0xdd997b5d, 0x3c7729d4, - 0x8179fb0a, 0xca340f35, 0x209d5e94, 0xff698364, 0x0128de6b, 0x978bea39, - 0x715c613f, 0xfc58f8a0, 0x043e0d7f, 0x4f3fe99d, 0x29854c18, 0xdef8ff07, - 0x0e27a03b, 0x8d2f91da, 0x59127ef9, 0xe5ccf681, 0xfff4dde6, 0xe885bcdc, - 0x03bde640, 0xefe13de6, 0xc0d7de77, 0xbed4a1a1, 0xcf97d072, 0xf30bbf9f, - 0x847e3c7b, 0xfefc8077, 0xfcf9dfd2, 0x7bee98af, 0x97bddd29, 0x7f87f79f, - 0x9feef3e7, 0xcb9ebfee, 0x79c2aee9, 0xfe17ba98, 0xa95df084, 0xfe12939e, - 0xbfbde5be, 0xfef61bf9, 0x35bf9b5a, 0x93cf1b27, 0x70b0c03a, 0x40b6667b, - 0xc8ed7178, 0x9dd82a99, 0xd5ef3f62, 0x7e60484c, 0xf7b02895, 0x1650c821, - 0xcfdc240f, 0xf80d6382, 0xdd9b880e, 0x4ddc933b, 0xc9137768, 0xbc53aedf, - 0xbe7abdac, 0x911acf1f, 0x21056f71, 0x8fc9399f, 0xbf8b6ef1, 0x5d1028d9, - 0x74aef6a0, 0x818f37f5, 0xb48f23df, 0x9805ed45, 0x33690fbe, 0xaaca638f, - 0xdc87f262, 0x53bce6f9, 0xbcede733, 0xf061073f, 0x0c247c3b, 0xd4716cf1, - 0xd3ce1561, 0x02256389, 0x4938a54f, 0x0efc086b, 0x7dfccfbb, 0x7ee10252, - 0xc7865fef, 0xa716048a, 0xed718512, 0x9471e03a, 0x78dce30d, 0xe2f11b48, - 0x08baf7c7, 0xf17baff7, 0xf80ed4da, 0x663fc094, 0xd5fa17f6, 0x12d3fb84, - 0x691a42ef, 0x76e69dd3, 0x2cbe8fdc, 0xb25d189d, 0x969d39aa, 0xd062e899, - 0x4c7d0e21, 0x7cf03174, 0xd2b1f4a5, 0xebff8ac5, 0xf75f1813, 0x2e832f47, - 0xef1d6e99, 0x7fdcc9d7, 0x133f0128, 0x820199f2, 0x7fdcabfb, 0xbc745290, - 0x7eaa24a7, 0x7e0097bc, 0xe01a945c, 0x86deef2f, 0x3f73a4f1, 0x00dbff7f, - 0x44afd54f, 0xebf8a0e2, 0x5121eddc, 0x2b0a5ef8, 0xb6569fe0, 0x404fb889, - 0xacd168a4, 0xc3627d98, 0x85faa80f, 0xb953e707, 0x4e9e1ed7, 0xf7dcafbf, - 0x61da0141, 0xcfd1bb2b, 0x605cfd09, 0x14750f74, 0xa5703ec0, 0x2b11fcc4, - 0x6049acbf, 0xcfb396f1, 0xae20cab9, 0xe762ec23, 0xb7232b7f, 0x7398f6c8, - 0x9904a14d, 0x739e9bc5, 0x3d085ea1, 0x28f9e021, 0xdcf62f80, 0x9c87e1a9, - 0xf060427d, 0x9df197ed, 0x4f5dca98, 0xaa7c4275, 0x1fbb2df2, 0x5dbaf8cc, - 0xc87ee29f, 0xf1ec5f94, 0x2e1fa076, 0x7d12e29a, 0x44bb01e2, 0xb6da8fe4, - 0x6843f41a, 0x36a2f91e, 0x2beffdc2, 0x7eab57f4, 0xb83efcf1, 0xf4f55670, - 0x7f885ee3, 0xe1df699d, 0xaec0b8c5, 0xfae7c74b, 0x3591fff8, 0xd6ffffdc, - 0x3b4f7669, 0x067fffbe, 0xf176a0fe, 0xfb9609d3, 0xb106bbab, 0xb44914f7, - 0x71ef52e8, 0xf0b9ed55, 0xcfafc428, 0x51e4fdee, 0xcffabb80, 0xfc14787f, - 0xa9d0720a, 0xba827dc2, 0xf18ebf9f, 0xdfbbe33e, 0xf9d03d70, 0x2f18e3c4, - 0xfa9b7ced, 0xe75ff41f, 0xc0b3a7f3, 0xea7ceccf, 0x4f10698f, 0xa9f9f3b9, - 0x9dce6ef8, 0x27494ccf, 0x9189f471, 0x0786ff02, 0xd2b5af10, 0x11db48ed, - 0x51ce7ff4, 0xd9ff83ba, 0xd489d713, 0xc69978b0, 0xe3bb39e3, 0xc4fbc7c7, - 0x7d66da6f, 0x4842c6e7, 0x0646bf65, 0x4139c710, 0x006639e9, 0xe3cddc74, - 0x5d6f9175, 0x0e738e32, 0x3af4a0fe, 0x85e3a16b, 0x3d8f45b6, 0x836d750c, - 0x44e38dfa, 0x233f8007, 0x413fbefe, 0xe40122ff, 0x60bfef68, 0x37e80cfc, - 0x73b84e9d, 0xd82c85cf, 0xee48f8bf, 0x85ef8b9e, 0x21576f3c, 0xfcf9511e, - 0x9d4f289b, 0xf8c71ccf, 0xf071e136, 0x8ff3d24e, 0x99f92bc5, 0x1eedbacc, - 0x74e1ff16, 0xe690f880, 0x071e72c5, 0xc46d7c62, 0x0b8bfa87, 0x73b1718d, - 0x40bec627, 0x7877f6cd, 0x6e97a5bc, 0xd7a044c2, 0xcfdc97fb, 0x02a0f030, - 0x8d8dae1e, 0xc38fc67b, 0x2d3dc4f5, 0x427a0374, 0xae27b3bc, 0x7b13d849, - 0xcde16175, 0xcef47178, 0xda5e2c2d, 0x8f3fc729, 0xaf41c465, 0x9fe25976, - 0x3fc581e1, 0x2b8f372f, 0x9760d3c5, 0xf15afd86, 0xf8abf675, 0xae5bfdfa, - 0xe85f9d81, 0xdaad7f77, 0x3de61f7c, 0x05dd3825, 0xef6d6bfb, 0xa7cf042b, - 0x2b73b374, 0xf967be7c, 0x3fb3d3f9, 0xd62e3117, 0xfa823914, 0x8c3faadd, - 0xbc2b57fd, 0x6b787077, 0xe3f5b3f7, 0xd84f5eec, 0x7b39fb4d, 0xebe439f8, - 0x63efddda, 0xaee8ee5c, 0x988e95a7, 0x8fd616f5, 0xce7ccc70, 0x80a8793e, - 0xdfe379c5, 0x3171ab1b, 0x40eeb37b, 0x76ea71fc, 0xa71a6a7f, 0x9851142a, - 0xf1e9701d, 0x2dfa48ce, 0x7699dfd0, 0x3a4ddf19, 0xbee31113, 0xc9701c17, - 0x95a11f7c, 0x475d0fc9, 0x71c09ef1, 0xf0a77f76, 0x573c04b5, 0xd2f1e77f, - 0xb7fde077, 0x8358a93b, 0x82b6dfdd, 0x4fdb69f1, 0xef4021f4, 0x13dfe3b6, - 0x07dafd61, 0xffb18df8, 0x4fd44e8b, 0x50fd50f1, 0x10a06ef4, 0x77aad5d8, - 0x66cb7dae, 0x938e9f82, 0x2342eb0e, 0x83ee07ed, 0xbc39b9c0, 0x569dee57, - 0xaa88f00a, 0x7d0a754d, 0xf9bb21e7, 0xafde557d, 0x21ef9aac, 0x6bc6af90, - 0x266f8fd0, 0xcc664b8b, 0x9f165232, 0x87f7190c, 0xabc213ca, 0xaf7f7ce8, - 0x28bb3706, 0x8d9e7c5e, 0x78112fd9, 0x06a26a27, 0x2e63d3f6, 0x4bc1de7e, - 0x83bcecbc, 0x7aa3643b, 0xf6ff61fd, 0x9e08930d, 0x7c06d867, 0x819e73d9, - 0x2f800b44, 0xea7d768d, 0x321de72d, 0x5a2a13e1, 0x17338722, 0xfd5025ee, - 0x77866ab2, 0xf11fe42b, 0xb2cdf7b0, 0x3821f748, 0xdb8db0df, 0x1560d9a3, - 0xe77df6e7, 0x6fbeebec, 0x78a53296, 0x853f30e9, 0x535ff5d3, 0xca7c5ce1, - 0x0d4fc52d, 0x2d856951, 0xa3dc1a63, 0x78bc7949, 0xcfcd066c, 0x34f4ff5f, - 0xe2f7ffac, 0xff3459b1, 0xb20e7b93, 0xcf012afa, 0xaeb0bec1, 0xeff01a76, - 0xd9fb96d7, 0xb9663314, 0x77f0057f, 0x77eef02e, 0xae706917, 0xefe15ba2, - 0xdda00465, 0x7f0c89d0, 0x9f77ee99, 0x98657f02, 0xf00563ad, 0x7fcf63eb, - 0x16f78491, 0x2aa1fbf9, 0xdce15469, 0x789a2d15, 0xf3e712f1, 0xccfbbcfa, - 0x498dcbf5, 0x3f8177c1, 0xbc8de79a, 0xef1d1a6f, 0x0e718ae1, 0xf2d00e76, - 0x829aa34e, 0xe9c85d74, 0xcb3df84a, 0x8b3e7c45, 0x02c290c5, 0x7f5caddf, - 0x5751ef19, 0x1ef4578b, 0xdbab8735, 0x67fbefd5, 0x3378007f, 0x007f8293, - 0x3fdf59fc, 0xb815c57b, 0xe519f500, 0x5c7de25f, 0xeb333de3, 0xea4468bb, - 0xfb3efb8e, 0x5a2efe56, 0x9bfef07f, 0x69ba283b, 0x682f39ff, 0x39518f7b, - 0xf150b31b, 0x31cfd1c3, 0xd2fd0bcb, 0x0426c220, 0x1fa71076, 0xf788cf3c, - 0xb822ee1f, 0x1765db5f, 0xbbaff074, 0x7d4549fe, 0x3a70b99e, 0xae5d5ffa, - 0x339c08ec, 0xc35bbaea, 0x018a3d7d, 0xe869e401, 0xf828c481, 0x3e1e5487, - 0xe7c3c8b7, 0x8f37fe66, 0xdb5175db, 0xa9fd81df, 0xa06a3fbc, 0xed8bdcc5, - 0xee9e9912, 0x8e10d06a, 0x087424a1, 0x8e81fdd6, 0xebe6e397, 0x46cfa737, - 0x9eeb9e9b, 0xee1ff880, 0x28ffc18e, 0xcc74bf77, 0xe63a3377, 0xd1d0e3bb, - 0x7bdd6efa, 0x6858e0ae, 0x28fcba77, 0x7d675fbe, 0xdf4aceaf, 0x21f5a93a, - 0xed2b3b78, 0xfeb8a7c0, 0xb31bf418, 0x29d22c7c, 0x00939e86, 0x3e07318e, - 0x06bc01b5, 0xe7ec1f1d, 0x9ba9793c, 0xf1d673ad, 0x063acad2, 0x9fb4e307, - 0xf74cd6e5, 0x451c0a0e, 0x69ca897e, 0x87c58dba, 0xb7efb6fa, 0x9d4b9cff, - 0x59502cf3, 0x73ff14bf, 0xfe064f00, 0xfbf3756f, 0x7ff17dea, 0xf8a3b43b, - 0x3fe61dbf, 0xbbcffc00, 0xfb0dfe14, 0x87eb8abf, 0xa29fd82a, 0xda1ff47c, - 0x3a1cb4cc, 0x8dd134ee, 0x8764b072, 0xd931f7c8, 0x3e865ffb, 0xfd5d7259, - 0xb917b821, 0xf20267e4, 0xfefe42eb, 0xfdfc27e5, 0xc1b9eb4b, 0xea10b2f2, - 0x1f9fcbcb, 0xaa3ea30c, 0xff2e65da, 0xbbcf7767, 0xde785997, 0xad352417, - 0x2b4ebdf7, 0xb9bbcffe, 0xb4e858de, 0xd72f7bc5, 0xdbd68748, 0x33cce74c, - 0x83f4f4a6, 0xa6cfa0fe, 0xb8f189bd, 0xc409957f, 0xa5297413, 0x2019de10, - 0xf4094285, 0xd7e5cc5b, 0x72d86fe8, 0x1d9ffaf3, 0xcc43df32, 0x43df316d, - 0xbe6ade1c, 0x66d57887, 0x51c43df3, 0xc43df361, 0x338d766b, 0xae4747e5, - 0xb31fb537, 0x3f29b27f, 0x534dfa36, 0x66c7f1fb, 0xda13f29a, 0x7f6a67bf, - 0x4df35bed, 0x5475d7f5, 0xf86fea9a, 0x7f299968, 0x9b3ff763, 0x311747da, - 0x61b878fd, 0x5bdc1179, 0x7872f030, 0xa15362a9, 0x9b08e97c, 0x9e5b105a, - 0x90056ba6, 0x7fe0e916, 0x532f27f5, 0x8a2a3f1c, 0x898ba75d, 0x536fd26c, - 0xd47ce61c, 0x8f7dfe6d, 0x35722c97, 0xcb527ea4, 0xbc1d9a08, 0x63cf0f24, - 0xc63af953, 0x01b1dbf5, 0xa0dfb7ea, 0x9b46d57c, 0x2f956f20, 0x9a01bde3, - 0xad8fd886, 0x1f9f77b0, 0xd4f99a72, 0xf95e8fd7, 0x0738db9d, 0x53facad4, - 0x264bc6cb, 0x3fca3139, 0x172d8c2a, 0x73c74f16, 0xabf5fd40, 0xb35c16f8, - 0x3bbc107d, 0xa3530f3c, 0x16cca9bc, 0x67dfdcf7, 0x7fd0bfee, 0x8ec7dcda, - 0x7cf00cfa, 0x26daf7ce, 0x7b56bf38, 0x51fa377b, 0x5e337619, 0x5decf37a, - 0x479e0363, 0xac3e481a, 0xb6fdc6f7, 0xebe13445, 0xd177ce36, 0xe0d333db, - 0x3f66419c, 0x87a155fe, 0x1b47ebe9, 0x042cd742, 0xe98711c2, 0xb456795e, - 0x39f81a6e, 0xeb79f8c3, 0xe7f8b64d, 0x0c3c92a0, 0x48a0e92f, 0xdd505ec1, - 0x2b9c2f68, 0x4f0bd77f, 0x0f68dcc7, 0x38e87926, 0x17b4c7f3, 0xbad4fbb1, - 0x5ee8e67f, 0x947d0db8, 0x026c0ee5, 0x93e592fd, 0x17dd9688, 0x83dbf49e, - 0x788ef02d, 0xefcdb263, 0x00b77cc6, 0x4c7fd9e3, 0x5e3a20c8, 0x84459fe3, - 0x75f0f1af, 0xeec83e78, 0xabb8c7ae, 0xcfc24f31, 0xe6711809, 0x89d9be0b, - 0xabc6cf80, 0xe107ee7b, 0xdc17907b, 0xf7e876c1, 0xc71946c2, 0x982c9c6d, - 0x4b798dea, 0xf78dbf9b, 0x6cdcb2be, 0xde74e5de, 0x933db700, 0xa8f8d5c1, - 0xae113240, 0x28f4bdff, 0x5cfb35f8, 0xc507def8, 0xc7c010c7, 0x73fb3d39, - 0x3a79319b, 0xee419aaf, 0x9ed16bad, 0x4ea7ef89, 0x8fa1e637, 0xe33bd134, - 0xe2fc332a, 0xc6fd1946, 0x3c6e4945, 0x886e10ef, 0xe79afa72, 0xf99be4df, - 0x5c295b9d, 0xf8884eab, 0xd1d6b6de, 0xfd28f4ba, 0xe5cdbcae, 0xf17d6b0f, - 0xf0634e7f, 0x7ba7f852, 0x4f36de40, 0x79e3f9c3, 0x31ff806a, 0x0d9c3c81, - 0x452c17fc, 0x236c183e, 0xc7d36fb0, 0x7930f04e, 0xd951ed9e, 0x72be357b, - 0x85be8726, 0xfda76cd7, 0x5dfa7995, 0xb0f36ff7, 0x4f36ff75, 0x72ff759c, - 0x975707ef, 0x54851fb5, 0x37b445d4, 0x111fa908, 0x3d53476b, 0x1bfd0e56, - 0xc7f13179, 0xff6fd005, 0x65bf9a76, 0xede5f644, 0x80cfb034, 0xecfb0d0f, - 0xaed98f4e, 0x3fbbd18c, 0xfbbd30f4, 0xf4c0cf43, 0xfda18fee, 0xe345efe9, - 0x4aa935da, 0xb4f7bd7c, 0xac1fdd87, 0xe7821553, 0x0fd9fb03, 0xdae5c9d8, - 0xd6feef3a, 0x1ff9cba5, 0x4f832e39, 0xfcfefacd, 0xf4112d31, 0x4207ca54, - 0x86b777dc, 0x3c6dbf2c, 0xad9b6bd0, 0xf7cc3378, 0x78fe1667, 0xf59f4d68, - 0x18f1cc2b, 0x6ac78b8e, 0x099b478a, 0x973c3b8f, 0xb6bf0fb0, 0xdf30afbe, - 0xf8e4e9f3, 0x09bf7aa6, 0xeb373bc6, 0x6b8822bd, 0x1cf9ced4, 0x1ed7fef5, - 0xaebccca7, 0x1d397e18, 0xa1e00567, 0x799fd673, 0xe303ae7c, 0xb99eab4a, - 0x58e2112a, 0x7a0d9335, 0xaa7df044, 0x4839f9f3, 0xecfb7397, 0x2e79c03a, - 0x3d139d99, 0xa3daefb7, 0xa4f8f710, 0x2c7258e1, 0x793dcf7d, 0xfda648bc, - 0xbc7bdb9d, 0x7703c248, 0xd43bd361, 0x5b7f1735, 0xdef77014, 0x37e1e84b, - 0x368f5b07, 0xe57c593a, 0x37173841, 0x6abfda86, 0x7a65f212, 0x285eed9a, - 0x1dbf1d17, 0x395c21fc, 0xa62fe63f, 0xd04ab259, 0x7ec11633, 0xee373cd3, - 0xc972f967, 0x9dfa6cc8, 0xe387ad12, 0x6af9c4cc, 0x04efc098, 0xf1444eb8, - 0xef3c02f7, 0x3ef86076, 0x02b243f1, 0xbdffc29e, 0x78093c1a, 0x09ab3a4f, - 0x77c41a89, 0x471e6e8a, 0xd30a6953, 0x3ab7ddbf, 0x848cf7f0, 0x53aaaf05, - 0x3cdafea8, 0xdd8efd93, 0x920b63f9, 0x55691fc0, 0x0df2de99, 0xb463e1eb, - 0x6be7078b, 0xe6231737, 0x40577c75, 0x921d1955, 0x8a6b6c33, 0xf9c78c35, - 0x25fe98f3, 0x3dff1a52, 0x1eb7ca29, 0x1c43a6cd, 0xc5cef8d8, 0xfc522bbf, - 0x7803cebf, 0xf0fcdb46, 0xabfb8f4e, 0x92ca386f, 0x28ccfb69, 0x945e5fbe, - 0xc39de1c0, 0xfbef07de, 0xd345e34e, 0xd4b5187d, 0x27b74efc, 0xe214b4d0, - 0x6defd0fc, 0x8bcef8c9, 0x38a29eb9, 0x0bbb9691, 0x0aaee5cd, 0x47e18f9a, - 0xf6d677eb, 0xae925f86, 0x37f63832, 0xbf0f1038, 0x79fd506c, 0x340e8f94, - 0xb07f30f8, 0xda34c341, 0x0fcb1230, 0x2f31f837, 0x986cf4da, 0x7faffa4f, - 0xeebb1490, 0x9d54efc2, 0x75c3e18c, 0xf9ade472, 0x88df8f80, 0xaf15af88, - 0xdefe478e, 0x3a8e9a34, 0x7367bd86, 0xfefec632, 0xd257f2e9, 0x0d5f284a, - 0xd3afd1f9, 0xefc3c64a, 0x17f3b096, 0xf63a4170, 0x257aee1e, 0xe093f9a0, - 0x34c63477, 0xfbc2863b, 0xc95bc1a4, 0xfd239458, 0xbbf089c5, 0x6c337b0b, - 0x949a7eb4, 0x07f8ecd7, 0x64deab80, 0xe7e7afe7, 0x6c9f1f33, 0xbce3afd6, - 0x0a66ff4c, 0x71bce3c5, 0x537e09f8, 0x39acfd00, 0x3307b9c6, 0xbf54891e, - 0xeb8a76e1, 0xdfb3efe6, 0xc754485f, 0xf7bde1fb, 0xcec35ecd, 0xbec5f7a9, - 0xff99bee7, 0xe1e2440e, 0x29176825, 0x103bf63e, 0x0f7b0a29, 0x4d930489, - 0xe5cdedef, 0x0606ccfd, 0x1f57d09a, 0x15fde6cf, 0xfb0e791d, 0x8897df83, - 0xf087eff5, 0xccd8c3df, 0x3574d3f5, 0xed4dec50, 0x5bd4676d, 0x7759ebbf, - 0x0bd1216d, 0x890143f6, 0xed04bd80, 0xd4bb698a, 0xdc02030f, 0xd7ce33ef, - 0xcdf80b3e, 0x93ddfdef, 0xebc3027d, 0x8a7d3c93, 0xd4494eff, 0xe3079813, - 0x123c16fb, 0xca7603da, 0x6206bb3e, 0x8fe47452, 0xf8947ef8, 0xe701c53b, - 0xbc0f53fc, 0xd9e5eecf, 0xbf38143a, 0x7c5bd2b8, 0x4551c413, 0xf3033ea5, - 0x816f4ef7, 0xfa9e83fc, 0xdda3d887, 0x1f0137c5, 0x06f7f3a4, 0x01000408, - 0xe1aa080e, 0x43fd638f, 0x64654eb3, 0x2bf2cc9f, 0x873637bd, 0x3f5f2132, - 0xf208f80f, 0x7dbfb48d, 0xc021c149, 0x86e16e47, 0x423763e6, 0x037f68de, - 0x5789ffb6, 0x3b8ffe65, 0x4af60d98, 0x79a55e4f, 0x625e4c4f, 0xa960e279, - 0x239abf31, 0xd073c47f, 0x3bd807b5, 0x6607a95d, 0xd4cf3008, 0xff1033fd, - 0xbcb7d5e7, 0x878c342b, 0x04eb608f, 0xf41b978b, 0xa6e1ee30, 0x79f783d9, - 0x9d61f863, 0xc4c76cd7, 0x0fbc27dc, 0x1fd3ddf0, 0x36cbaf8f, 0xf74a9ef6, - 0xc6efd88f, 0x547b030d, 0x86b9b884, 0xa3dc2e69, 0x70c1fea7, 0x98395c12, - 0xcde35fd6, 0xb55e3a41, 0xa9cdfb3b, 0xa75f2f5a, 0x80772964, 0xf8b54e3e, - 0x3f5cd935, 0x7f8b508f, 0x372b4893, 0xf0b5c10a, 0x8f686c9e, 0x937de2ac, - 0x4728195d, 0x228eb967, 0x5f3183f5, 0xcbbfefcd, 0x476b832b, 0xc4591e81, - 0x76556ef4, 0xdfa658a0, 0x8d973d57, 0xf0670bbf, 0x2452555d, 0xf7bb9c6d, - 0x3791b75c, 0x21e4477e, 0xef09d5b5, 0x5afb18f2, 0x6437fbb5, 0xc7fd3ec1, - 0x3b46de87, 0x36624971, 0x76d359c2, 0x69df815c, 0x7ca36da9, 0xd8fbbf47, - 0xa3c763d9, 0xc887f25f, 0xbe026fa0, 0xc368d0fe, 0xd9fdddcb, 0xfd522f55, - 0xea85d3a6, 0xd3038368, 0xd5fd7a9d, 0xf09c0ae0, 0x49c9b82e, 0x1cf1e9f9, - 0xeafe055d, 0xf51eb7bc, 0x3a8ae3d8, 0xd3aff80a, 0xe066c3fb, 0x9124aae7, - 0x5f0febf3, 0x7ef8f3d6, 0xb9efcd3d, 0xbfa6edb7, 0xa160df68, 0x7ba9fed9, - 0x41fc8dc4, 0x02df92ed, 0xb66ed51f, 0xb3fd6085, 0xbef1da39, 0x1be82773, - 0xfbe65fd4, 0xa6051b99, 0x5873430f, 0xf772fa1c, 0x74be2b34, 0xfd8c7091, - 0xe99124bd, 0x84290aab, 0x5f1576fb, 0x2ffeb17a, 0xba69c71f, 0x1c77da0f, - 0xe31bd637, 0x838ef754, 0xf6fd527c, 0x5fcff461, 0xafb0dabc, 0x77ffd475, - 0x61cfc53e, 0xe874f538, 0xd0d941e7, 0xa4cfd427, 0x1ee78678, 0xf9243e79, - 0x47a97908, 0x2e6dacff, 0xf6fa04c9, 0x7eb313d6, 0xb74a25d2, 0x3e781297, - 0xc9737f74, 0x13ed38a4, 0x8c73ed2c, 0x7fb14ffc, 0x3a0f3c2b, 0xda0ef37b, - 0xbd93fa5e, 0x6df00f27, 0x4bfa59b0, 0x86dfc636, 0xb7fc19fd, 0x65fbbbc7, - 0xa5e9ef78, 0x10f140a4, 0x2068df66, 0x15245b87, 0xc0d1877f, 0x3ebe1ef3, - 0x8d797c55, 0x78bdff09, 0x9f95302f, 0xfb4cd06e, 0x2e178ba1, 0x7b3f7bc3, - 0x41563af8, 0xdb3eec42, 0x7da6b923, 0xc70fffd0, 0xb8a385d7, 0xfe4a381f, - 0x328c70c6, 0x385e81e9, 0x5fe54df2, 0x69310e17, 0xec366976, 0xa1b1ad53, - 0x0b66909f, 0x6ec07239, 0xf7ec5ffb, 0x0734201a, 0x61a899e7, 0xce57da6c, - 0x079f6039, 0x448e79c6, 0x40e3498e, 0x056d749e, 0x913f53ac, 0xe5a1afd0, - 0x8619390e, 0xfde1d56e, 0xd8952a2b, 0xb0754e5f, 0xe6f51986, 0xab876277, - 0xe5a258a4, 0xb879d5e3, 0xdd94e5ee, 0xfdf60755, 0xcfe17736, 0xbc931357, - 0x5ab27da2, 0xc7f68a58, 0x9b17c49a, 0x3d38df61, 0x0233d981, 0x58f9b179, - 0x267abc46, 0xbdf72daf, 0x31c41378, 0xaed4aeb6, 0xab6e7f06, 0x0c391c33, - 0x6e3df9eb, 0xdcaa3dfc, 0xf816e175, 0x83710abd, 0x314bd70d, 0x2b6bbc29, - 0x6078179c, 0x8bec1f84, 0x40d760ad, 0x5c6e35fb, 0x421a5bff, 0xe2af2f68, - 0xf5f6c0eb, 0xe7385493, 0x9296e8dc, 0x916bbd61, 0xb8056feb, 0x64efba5e, - 0xd03ae3b3, 0x4196fe63, 0x80cbef3c, 0x71cb4d75, 0x14f5e58c, 0x68575b19, - 0x3485c183, 0x44ffc3f2, 0x33d412ad, 0x6b0ed127, 0x04ab2f74, 0xbfd68e3b, - 0x7a78a0ec, 0x85e3993c, 0xe8f4e7d7, 0xa0cd93a5, 0xbd15c507, 0xef3a12f9, - 0x7a633f1d, 0x3fda09ea, 0xe7452bbc, 0x18778213, 0xe84947bb, 0xc1242587, - 0x74d0c76f, 0x9dfb0e74, 0xbd17aa5b, 0x3849c7e8, 0x491f635f, 0x0f7ec519, - 0x7ac3da1d, 0x83919093, 0x0cca98fb, 0xe2835ef6, 0x66fde371, 0xdd5677e3, - 0xb3a7f8c4, 0x67df2978, 0x43de5971, 0x895fae70, 0x784ee99b, 0x4f862137, - 0x0b7bcb15, 0x07cc0912, 0xcd544b7b, 0xe449bfe5, 0xd8834afb, 0xb70eadef, - 0xa32ed085, 0x35e98452, 0xd9f68a24, 0xf981d268, 0xe66de031, 0x0d2c35c2, - 0x278d8e2f, 0xbbe2c8ba, 0xc7ec1101, 0x788d5bb4, 0x44f5f04c, 0x96bfdeba, - 0xfc36e3c8, 0x66538c77, 0x7d7ee214, 0x5fab1266, 0x0fbbc815, 0x338dbcec, - 0xc69c61a6, 0xf58cefb0, 0x16dfb0d2, 0xab579872, 0xc17b5c42, 0x3a16ebb0, - 0xb6753e59, 0x8868e0fe, 0x0b53b66b, 0x2fee1b34, 0xf96af8b3, 0xb034e2e6, - 0xba1e16cb, 0x4ce4ed15, 0x8b65d995, 0x8250ce36, 0xdadee1a3, 0x8a07f43c, - 0x84484c37, 0x4ed5847d, 0x8575e27f, 0xfbe267e8, 0xc7b503b9, 0x355da6b6, - 0xab71e419, 0xca90128d, 0xeeb24bfb, 0xb17c0b1e, 0xcced0f21, 0xc6c109ad, - 0xd6efda24, 0xabfcd67f, 0x4ea7fe68, 0x8c38f0bd, 0xd5813ab3, 0xc051bbc3, - 0x12e73d9b, 0xc9bbe1b6, 0x3d6f8dfd, 0x1252f097, 0xa8ca7f7b, 0x7e536fff, - 0x80007d7c, 0x00008000, 0x00088b1f, 0x00000000, 0x7dbdff00, 0xd5947c0b, - 0x66fdf895, 0x666579be, 0xf263c992, 0xc2130922, 0x9e4e5e4b, 0x124c2280, - 0x4cb443c2, 0xe8202a10, 0xa79034f0, 0xbadc5d48, 0x30040cff, 0x5706b650, - 0x84ea2b11, 0xbbaac562, 0x351ba341, 0xb88080ea, 0xda446dd6, 0x8ffd16d2, - 0x4810154a, 0xfed2b58a, 0x39cf65dd, 0x7cccdef7, 0xb5f01993, 0x3efeb4ff, - 0xe7ddf7ee, 0xce73df79, 0x12e973bd, 0x2c614dfc, 0x5630a494, 0x51c1d8ca, - 0x618cf58c, 0x24dea98c, 0x064dcf06, 0x34e2d26f, 0xa37efac6, 0xf5e1bb67, - 0x926f6617, 0x25d8c6c3, 0x79fa2ed1, 0xa0b199aa, 0xcdb3b189, 0xc11c166e, - 0x336699d8, 0x1f966b95, 0x9fa0c698, 0xb9850e9a, 0xc55b19f2, 0x3f6336da, - 0x69923baf, 0x3d0155dc, 0xf4648e0b, 0x5bfe0977, 0xd528fcbd, 0xebc9dd5f, - 0xaa0eb2d7, 0x4f3192bf, 0xf76b3c07, 0x1cd0595a, 0x51df5fae, 0x4a1f69ac, - 0xd7bf51d2, 0x3b06fb25, 0x5bdd8c9c, 0x2abefc3d, 0x5d569f78, 0xfae1f662, - 0x13e38e58, 0x87afa8ab, 0xebe63af7, 0x77aeb188, 0x49de5c04, 0xac4e8a82, - 0x32b1d0ed, 0xe03ad6c6, 0x1ec62e9f, 0x6c7cd850, 0x15f7f6b7, 0xc2632919, - 0x9e2ad6ed, 0xf898c70c, 0xa8bc6a70, 0x88d48167, 0xc467dab2, 0x345e35f5, - 0x0ef3fbd2, 0x63075fb3, 0x3ff4c91e, 0x7fac2d70, 0x1953eb26, 0x909f53cc, - 0xcd5d8e38, 0x71258b58, 0xba673e37, 0x08a17d0c, 0x53333038, 0xf8337e71, - 0xc4ebf62b, 0x71944769, 0xed403ed8, 0xa98ed967, 0xc473400c, 0x8303735e, - 0x90b037f7, 0xce060aca, 0x28fdfa0f, 0x2359dfb2, 0xdd1be5b5, 0x09ecf2da, - 0x7e6332da, 0x9a4fd782, 0x1a4eca9b, 0x04fefdc2, 0x0311d6a6, 0x5802b72e, - 0x5eed7eb1, 0x0464e04b, 0x923beb1e, 0xaec6e535, 0x88c9c0ac, 0x1ff16a71, - 0x135ff059, 0x589d775f, 0xdf4607f7, 0x5bc00ead, 0x71190b3d, 0x46c140dd, - 0xacc658ef, 0x7c45e616, 0xf16fd81d, 0xcfe812b0, 0x00b76e66, 0xabbb1b7c, - 0xdef02595, 0x30ef876a, 0xe196273f, 0xfaf03569, 0x0e88058c, 0x39da8fe0, - 0x5bed99bd, 0xb713e415, 0xcdfedaab, 0xff00dde7, 0x4f0293dd, 0x24ac3d95, - 0x0ea3ac46, 0x5e1e91d6, 0x07eb39c7, 0x582f8865, 0xa5ec6fcf, 0xa6461748, - 0xf3d78524, 0x5cb5e1ad, 0x5dc6af0b, 0x1837a236, 0x1844bde7, 0xcea761a7, - 0xceb2846f, 0x7e4463dc, 0x3ce917b9, 0x1c72de06, 0x6f3c4c4a, 0xe0c73c43, - 0xfcaceda7, 0x1cc7e43e, 0xc7181fe4, 0x6527eeb6, 0x8f818b27, 0xfa1737aa, - 0x054dbea0, 0x547186fe, 0x08a9bff8, 0x6d3bd9c8, 0xe9d03255, 0xc3e73b29, - 0x7a2e890d, 0x0abc50ee, 0xe75d35e2, 0xd5fa47c9, 0xcc43b827, 0x66a3f1c1, - 0xcb601942, 0xf962c1ae, 0xefe81ebd, 0xcb1b9821, 0xf0098416, 0xcbc2c878, - 0xefca392f, 0x6ee308dd, 0x0de5e64a, 0xd5b9bd3f, 0x16ca093f, 0xe5439e59, - 0x416d0c87, 0xffdde03d, 0x44f5c982, 0x28f7b53e, 0x32305e58, 0x4d4c04f0, - 0x2365843f, 0x4226a65e, 0xf4b720e7, 0x9b769a2f, 0xeed05ea0, 0xa78427fb, - 0xfb39ff5c, 0x26363cf1, 0x4d7e7f66, 0xacdf797f, 0x53bf183f, 0xfbf87577, - 0x419dc4d4, 0xc2e76f3d, 0xe7a72c76, 0x9ff43f03, 0x6d89a2fe, 0x0623e285, - 0xda179b76, 0x632c5dd5, 0xd43908c1, 0xb679f023, 0x5b7241d9, 0xf943afbe, - 0xa9f9063d, 0x7d70e487, 0xfe46aa47, 0x7f5cb94a, 0x7f4d5af1, 0xc27c8e39, - 0x43dabd57, 0xe2feadf2, 0x121efa64, 0x736cf4f2, 0xf889e926, 0xc8d20ce3, - 0x1338f0f5, 0x72f8b059, 0xefa24ce3, 0xcbe61c72, 0x06bdb922, 0xa4240ce7, - 0x87bc8237, 0x750c2e71, 0x465f2525, 0x0276d99f, 0x67ac4591, 0x63341a9b, - 0x07dcdbff, 0xfc18be1c, 0xb844e520, 0x1edb51bd, 0x811b23f4, 0x4863edf4, - 0x7aacffb7, 0xd4fa91cc, 0x5038f066, 0x8af6a86f, 0x34372e23, 0x86647e4d, - 0x5169280a, 0xd97f3d39, 0xd1e881b6, 0x411f706e, 0x3aeddafc, 0xafbe1f97, - 0x483ce9b7, 0x730e2d27, 0x51bdf100, 0x7281c1b9, 0x076bf643, 0xb8f38f31, - 0x7a421b60, 0xd57ade3d, 0x0f54898b, 0xa9199266, 0xc6f7ff1f, 0x0f17c583, - 0x31bd8f1c, 0xfa0b88f1, 0x6e744b57, 0x910be00b, 0x1d0471fa, 0xdf63f744, - 0x779cc6a9, 0xff093d74, 0x8436f8b8, 0xe7fe1112, 0x8119ba6d, 0x4d2ef318, - 0x9e9bbe56, 0xdf25145a, 0x3c3b7f93, 0xd095ed88, 0x49f20a0f, 0xa32696fe, - 0x90bc2dfc, 0x3922e958, 0x73b5ee9f, 0xb6e385b1, 0x7d9a8ed8, 0xed988fa4, - 0x3ebfd913, 0xb849fd3e, 0x64aade18, 0x04601f88, 0x4ae37a86, 0x412bb070, - 0x1597e22f, 0xd3e50caa, 0xa76f3a40, 0x77d7f4f9, 0xeb11e743, 0x0edd516f, - 0x75fd6ba4, 0x99ca331e, 0xe6398ef5, 0xaa379410, 0x20f9d9ae, 0x02defa87, - 0xb7d6127b, 0x1cc8ad29, 0xc15a8f8b, 0x2df9c46e, 0xd669d64d, 0x1d669f23, - 0xf7e8dfe7, 0x9eb9925b, 0xb13fdd68, 0x9f1253c7, 0x79d2407e, 0xcb9b8f51, - 0x5856c754, 0xe7c0de9f, 0x0763896b, 0xc1e37eca, 0x0b7ecb6b, 0xa87569c9, - 0x44f68039, 0x549b78f4, 0xbe078f77, 0xf8f9826f, 0xc7c39cb1, 0x3aa254df, - 0x16d74376, 0x47330257, 0x4b3837d4, 0x6c17fe08, 0xdf0f4c69, 0xc63d2137, - 0xd3849798, 0x68efe4bc, 0xe8a2f93f, 0xc3b7f732, 0x5d0d10d9, 0xcba2c6b6, - 0x4b37a879, 0x3999fcf9, 0x9343fe72, 0x8c7c8ebe, 0x49b29ba6, 0x977c83cc, - 0x5876cf01, 0x66caa76f, 0x807d43ec, 0x9844d6b6, 0xe636cddf, 0x393e9900, - 0x32677cb5, 0xe7acb7ac, 0x3f219180, 0x1d693a74, 0xf47da275, 0x8e14a6b8, - 0x838a533f, 0x3dc7499e, 0xf8014f4f, 0xb824f676, 0x99d4f814, 0x0630fa02, - 0xbc088f7c, 0x9fc6d633, 0xf21c686a, 0xb65fac8f, 0xc3767988, 0x6b0250f3, - 0xb2bd8335, 0xc607c84f, 0x154fe7ee, 0x99c61718, 0xdde8cafd, 0xf58a2f64, - 0x80b5021f, 0x43d3d3f5, 0x77fd14e3, 0x585edbc0, 0xeade047d, 0xdbc221cd, - 0x6bdf46db, 0xe3c69f08, 0x772c74a1, 0x87933d1e, 0x70b670f8, 0x25efb5fb, - 0x6ee9006b, 0xd3d67e20, 0x0e2eeafc, 0x81e2fe62, 0x8353ab78, 0x2eeb5fa4, - 0x5877d1e6, 0x129cdfb7, 0x6c1b3efe, 0x2eb00986, 0x4270e666, 0x47c2c4f8, - 0x896be0bb, 0xa3eb500f, 0x081f02ed, 0x3ec48fa7, 0x4eef1fa7, 0x780666e3, - 0xefe66b3f, 0xdf246799, 0xfe7d0987, 0x005e4251, 0x0d1f33f7, 0x7a46ce07, - 0x91e95d50, 0xe2cea77a, 0xac3e6fb9, 0x67abbd9b, 0x5963c04f, 0xed15ada5, - 0x4f2665ab, 0xcb5dda12, 0xeb2bd3de, 0xc48409f3, 0x3c042b07, 0x5df732cf, - 0x36ff3f88, 0xc209e38b, 0x97ff769f, 0xf8bca3bf, 0xa2bf681d, 0x9346ef4b, - 0xcda56971, 0xf596fd8f, 0x876d3c54, 0xad5b2bf7, 0x2efd062e, 0x04fee29b, - 0xf765bded, 0xf21b5c59, 0xa438bf71, 0x5dfa0b3c, 0x03be60fb, 0x9d7581e5, - 0x06ecd337, 0xeb7ee093, 0x6de02b4c, 0x8964b293, 0x7dac0852, 0x1516ca7f, - 0x57feacf0, 0x281667e5, 0xc17f755f, 0x8c75f316, 0x1cb282bd, 0xd0ff59ed, - 0xfedf6899, 0xf646a712, 0x7f6fb72e, 0xca274479, 0x82a65bc5, 0xece5180a, - 0xce60d9d4, 0xb78a532b, 0xf4fc6198, 0x0ea14f14, 0x32935bc6, 0xb7f62661, - 0x7fb1bef4, 0x77df09dd, 0xa99acca4, 0x44de13e6, 0xcaccef7b, 0x926ed0a1, - 0x54b3cf2c, 0x56697f42, 0x27a7b616, 0x090fbf00, 0x77f68f8f, 0xbdfdbf67, - 0x1cd4e660, 0x53454bc0, 0xbffd0aa5, 0x96db729e, 0x36315731, 0x877281fe, - 0x983fc607, 0x15a664b2, 0x9469dff0, 0xf16d97f5, 0xcc9d58c0, 0xbe0186f7, - 0xbafef1ff, 0x9fa86699, 0x742dea96, 0xcd53fac0, 0x91996ff7, 0x65f81dfb, - 0x4fbd12a4, 0x1271482c, 0x90461cdf, 0x33ebade6, 0xf82afd72, 0x71d3873d, - 0x9424797f, 0x4ce511ed, 0x10dcee5e, 0x4e9c7e5b, 0x33b972e5, 0x8f77f621, - 0xef004b90, 0xb3e90ea0, 0x96181acb, 0xc027961f, 0xc409e64f, 0x3cb9db5f, - 0x639abe01, 0xd98e3e27, 0x5fe537df, 0xd3f53b80, 0xe8ac7aa9, 0x0d7290bf, - 0x71c56666, 0x69764cbe, 0xcf5975e4, 0xbfb79252, 0xeb7c154a, 0x5671f0e2, - 0x330ae56a, 0xb8470cf7, 0xc58b76c8, 0x4b47f33a, 0x88d052ff, 0xe2d6b9fc, - 0xacf9c0c9, 0xc19e57dd, 0xd787632e, 0xf8d72c5d, 0x98ebc24b, 0xf407ef4a, - 0x44b9fd0b, 0x5f31eeff, 0x57c95e07, 0x7d1a5780, 0xc33ad2bf, 0x3bfd69fd, - 0x7ee3fb03, 0xc57a019e, 0x1b9e7b18, 0x415eb853, 0xe422ebf8, 0x5f214ada, - 0x3d916a41, 0xabc5fe7e, 0x8fcd6f76, 0xf503771c, 0x7a7df80f, 0x412fee0a, - 0x2b1ca2be, 0xb0b33d53, 0x8a4f597e, 0xa079ed03, 0xde828db7, 0x8937a454, - 0xa694cee7, 0x76ef5a72, 0x863bb1c5, 0x3913f81d, 0x83c536af, 0x22c649f6, - 0xc4497e9f, 0x87fca4fc, 0xff453bfe, 0x1f9e9c25, 0xc5e7a7ed, 0x2fc23fc8, - 0xdf40dcc4, 0x5fce0763, 0x08ce36c1, 0x2582f5fd, 0x7091f380, 0x2ff4b6fb, - 0xb8ba87ed, 0xda912a7a, 0x260f1c65, 0x219ea0ba, 0xb9f9c5c5, 0x6bc4e3e3, - 0xe9755f51, 0xebe2e299, 0x2651b946, 0xe7bfa4e5, 0x764a8548, 0xbb2e584c, - 0x72919ec8, 0x87366833, 0xbdbfdfeb, 0x9446c667, 0x2fbe26ab, 0x1483d34f, - 0xe3cf0a2f, 0x2fae14e5, 0x2798f827, 0x24781d96, 0x08e52ed9, 0x75e1e3ad, - 0x5863ec95, 0xd7e85d9f, 0xf93f2109, 0x664c9eb3, 0xf0e13ec2, 0xb67bfa90, - 0xdcaff429, 0x47a5a64f, 0xa53b0659, 0xee105741, 0x89cfbf1f, 0x8263fba0, - 0xf3f1a20e, 0xc013e55d, 0x48708fc1, 0xc872e14d, 0xed056509, 0x17f4150b, - 0xb55cffc0, 0x3f35bdcd, 0x2e36de62, 0x1d7a9d8f, 0xe0576397, 0xfe54b48b, - 0x3b25efbd, 0x1e1873f1, 0x2ff98edc, 0x1d76f701, 0xc17dc1ab, 0x09f01d21, - 0xaf8da2d2, 0x598bfcf3, 0x29e7efd4, 0xeffeb93a, 0x1bb72e45, 0xd7ce3c61, - 0xbfd63f64, 0x3b5da83c, 0xdcdfde7f, 0x658f4e54, 0x68853dc7, 0xdaf30cc7, - 0x285fb8dc, 0xc07399eb, 0xdde1e500, 0x4b6b038a, 0xc1de1f3a, 0x4ba814f9, - 0x67ade5c0, 0xa5b5fb22, 0xbefa3a72, 0x38fc31d6, 0xcbc457a7, 0xcd3e08e2, - 0x7871b54d, 0x084cfac1, 0x472b554f, 0x9bfbf3e5, 0x0180f787, 0xf0075bd6, - 0xe12db140, 0x64b1d9d6, 0xf8f90583, 0x1f237338, 0xa258ef9f, 0xdd788b1b, - 0xebbec8c9, 0xf00f0f97, 0x147b4875, 0xe903b2e8, 0x5cd4eaf2, 0x71d86f1a, - 0x7c0c758f, 0x1376861f, 0xec3b95fa, 0x4c57dc01, 0x4dcdf54e, 0xedce7845, - 0x4a2064ab, 0xeb4dac1a, 0xfbef112d, 0x7d4177eb, 0x7e9f63a2, 0x36f3ce2c, - 0xc2bab6c6, 0xfaa981eb, 0x6f5a1fd1, 0xa02d3e04, 0xd6e11072, 0xfbf5e469, - 0xcf8a3316, 0x8cfbe834, 0xf7f41df8, 0xa3cfa22c, 0x2fc414ba, 0x6ed09bee, - 0x737bd3ae, 0x67d7dc14, 0x07a8dc98, 0xf4421f60, 0x54c2c87e, 0x26fff40b, - 0x574e513c, 0x8fd8efe9, 0x502aaaf0, 0xae242ddc, 0x60dc85da, 0xcd37dc41, - 0x7a25629e, 0x39dd5f64, 0xbff51ab4, 0xfa09e395, 0xcc7e8b31, 0xff30a2e6, - 0x2aef3afd, 0xfd48ffda, 0xa8514876, 0x8dd7439f, 0xb112ddde, 0x50fec22f, - 0xaa521ffe, 0xfa40ee73, 0xb23afb17, 0x7ac2d30f, 0x2295ed17, 0xfdde245b, - 0x3ca17e62, 0x7b48a3a4, 0x7ed3ed14, 0xb1dfd67b, 0xd9c83a65, 0x823a33f1, - 0xd152073a, 0x01ff33f3, 0xf60551d6, 0x70e005ac, 0x33972a5b, 0xfafdf287, - 0x30df9c44, 0x3abc3f58, 0xd31be09c, 0x938f0b64, 0xe90ffc2e, 0x482fee46, - 0xbfcfe04f, 0xe73b72a7, 0x1e5c6927, 0x978d21fe, 0xfb6313d3, 0xf510be2b, - 0x1f971354, 0xfcb9cb5b, 0x41b7ae8f, 0xedadfbf4, 0x668a31de, 0xef760f7f, - 0xf76e5486, 0x885fb91a, 0x0a9613c7, 0x873b06fa, 0xabb614f0, 0xda503c78, - 0xccf45fa1, 0xf372f2a3, 0xbfe8d97b, 0xe69fedbf, 0xb6f487dd, 0xf27a37f2, - 0xf1149c57, 0xbec99582, 0xbfdc64f4, 0xabf6c427, 0x75d6273c, 0x1f9199ba, - 0x1b8c53f8, 0x893dec82, 0xaf284371, 0x34e0f9da, 0x2cd5bfe4, 0xe5e0fe40, - 0x5c51373b, 0x61407970, 0x69f7052e, 0x1627ee5e, 0x47bd58f8, 0xdf4bf1af, - 0x931936ae, 0x77e984c7, 0x6e369b45, 0x58abb358, 0xf6f6fe53, 0x440b2569, - 0xfcb0a1c8, 0xa3ef4699, 0x1ef495fb, 0xd47ea76d, 0xc3f8d2ec, 0x461cee97, - 0x97f597eb, 0x77ad3731, 0x66816b59, 0xf395acde, 0x49f9bc49, 0xd4bb45ba, - 0x469e731f, 0x008ffbcd, 0xff08fefe, 0x4353d2ff, 0xa92d1e69, 0xba40ffbe, - 0xcac3cf09, 0xdabf1afc, 0xb027c724, 0x7ee16656, 0xff23a049, 0x5081ece5, - 0x6fffa72a, 0x71d1f70f, 0xfee305f6, 0xca0beebf, 0xcc397126, 0x0c3614da, - 0x6aa7e31e, 0xa0bfb4ed, 0xa7c52bbe, 0x616beb95, 0xa45f2d47, 0xd45177ad, - 0x5dea28bb, 0x6912bfc9, 0x2805299f, 0x0d7f78d7, 0xcff38f82, 0xa0ba351c, - 0x6e34f8de, 0x3d3916c7, 0x6cef5097, 0x438e24b3, 0x4b36ca7f, 0x52f5005e, - 0x38bafaff, 0x48336d1d, 0x033b8a3f, 0x5ffed6e1, 0x88a8b677, 0x0fb07dc7, - 0xfe587900, 0x8a1641e8, 0xae375390, 0x01cb3c53, 0xef2176de, 0x7d7cdcea, - 0x71a0ee75, 0x5d93f428, 0xd395e7c7, 0x23515fb1, 0x08d4e5da, 0x419a5f7f, - 0xc1cccfb3, 0x8d254e32, 0x9a9ce3cb, 0xea1432a0, 0xa3daef65, 0x875fd8a8, - 0xbb337a42, 0x41130009, 0xdc25d957, 0xa4b1b9be, 0x2636595d, 0x5d56870c, - 0xe00718f5, 0xeadd35a7, 0x8f737d46, 0x0d2437d3, 0x182279e7, 0xf8fcedc4, - 0xda2a3d13, 0x7a753fef, 0x619cd20a, 0x8ef4b838, 0xd6a7d46c, 0x6d9e7c13, - 0xae63fbfd, 0x4da22867, 0xdcddabfe, 0x23b3d19e, 0xa487db8c, 0x8c37d2af, - 0xe727bd24, 0xf4229e97, 0x3df33a45, 0xadfaa367, 0x68c9f08c, 0x861be93d, - 0x2cf6e6ef, 0x815577c7, 0xafbe0f77, 0xa8aab8ca, 0x6c17de05, 0xa14baa0b, - 0x62bbcbdd, 0x85cb83fb, 0x4c75813e, 0x75c9f5c2, 0xc82e495c, 0x7e38867a, - 0xd60fc90a, 0x1ff7b119, 0x2f7d2230, 0x216d347f, 0xa36eb7ce, 0x30949991, - 0xf4ea7ffc, 0x64f9c6ce, 0x082bb477, 0x93dfe91b, 0x1dff4ae3, 0xfcfe477e, - 0x96f928c8, 0xfe5c5fd3, 0x2cf7a75f, 0x1b67948f, 0x6927848d, 0xc7e7873f, - 0x69d5fded, 0xeabecf5c, 0xf9c12ef4, 0x276d7434, 0x3daacf7f, 0xf9631a1f, - 0xe2f9a3ab, 0x6a54704a, 0x6ea0bef8, 0xeb8039be, 0x25547f2f, 0x68dda83a, - 0xdd5938a4, 0x9fb8fb33, 0x46e61ee7, 0xb1d75139, 0xe30e594f, 0x4fb33ed6, - 0xd7011159, 0x05017541, 0x2ec233e7, 0xafcb90f9, 0x3f47ba68, 0x872dda32, - 0x9c4e5c2d, 0x15f9b72d, 0x8359eb80, 0x9deb0eaf, 0xfdbab2cd, 0xbc3c61f9, - 0x11fa6fb9, 0x3fb037cc, 0xb3e20a67, 0xd33bb755, 0x475af50c, 0x5f48dd19, - 0x36fa753f, 0x54525c23, 0x4fb6276f, 0xd7bbb34e, 0x89975b43, 0xfbbca115, - 0x1f1870ba, 0xefe32745, 0x85d3fce1, 0x91db8872, 0x813fc845, 0xa7b4bb34, - 0x361dae48, 0xc73c75f0, 0x9eff7cf8, 0xe89079ea, 0x8d0a48f8, 0x54175d9b, - 0x7f9d9fd0, 0x6b9239e6, 0x9d30ffb2, 0xe4891e79, 0xb3cf2bdf, 0x56f488c3, - 0xf950e42b, 0x8f947ba3, 0x4bfde623, 0x6e91f430, 0xba019fb2, 0xfdf7d1b4, - 0x3ea8d333, 0xbdf0b933, 0xe16aed42, 0x79088afb, 0x4311d723, 0xf5c3ecee, - 0x1cf44ed8, 0xc82772e4, 0xbe628dfd, 0x157cf8d1, 0x9a7c1fe5, 0xde99ea06, - 0x3123fd1b, 0x48787a2e, 0xe527f502, 0xbedf3440, 0xe51ce82a, 0xfe46cea5, - 0xe52bb25a, 0x22bd64fc, 0x34fec567, 0xc10f4382, 0x4a977ea1, 0x7a32a9eb, - 0xc111de87, 0xfd16bf0f, 0x03f9b81d, 0x07fdca23, 0xa25dfdfe, 0x8536fac7, - 0xedacf1e2, 0xd43ce35d, 0xf4a7fe47, 0xe2ce6768, 0xf1db0126, 0xa784bbc2, - 0x2e5c9d59, 0x53ee77d7, 0x74c2d997, 0xc0e67f9a, 0xf56748ad, 0xfb86261d, - 0xdfbfa022, 0xe9a27c20, 0xca47c254, 0xb4f878dd, 0x9472e0ce, 0x47e48df9, - 0x3e54fd85, 0xdca429fa, 0x4eaa7bfe, 0xfbf809f8, 0x1cbc690b, 0xa7df1fa6, - 0xdcb08f08, 0xe45f10b5, 0x603a299f, 0x5bb87dc6, 0x5a7f3f21, 0xe4678725, - 0xc6c7aabc, 0x54ce9b97, 0x50d437a1, 0x587b1cde, 0x7fcbf7be, 0x810bfed1, - 0xe41f786f, 0xd410d9ef, 0xd1fe72f3, 0x7277cbf8, 0xce831b7d, 0x11d71bfe, - 0x3da4dfad, 0xc9e6e920, 0x8f46aa5d, 0xea469dd8, 0x731b0ecf, 0x728ec79c, - 0x61d8cf1e, 0xc76cfae0, 0xe500737a, 0x780b9bc9, 0xa17d995e, 0x43cf8831, - 0xf875a5ba, 0x1f3650fd, 0x5ba755bf, 0x0dd6e583, 0x7842d636, 0x4b3a24f5, - 0x19127e91, 0x1e5c8f97, 0x973cf03e, 0x5b7e7567, 0xeb3fc180, 0x5397737c, - 0xe2cd39dc, 0xf333b8c6, 0xb3ce341d, 0xd72ba40f, 0x2e8dfb73, 0x83ab3f78, - 0x03c49ff3, 0x2fa253c8, 0xae120fc9, 0xb8727861, 0xf8927e4b, 0x67f4bbf8, - 0xa77cbd03, 0xda3daabc, 0x46dbdc78, 0xbe4ed5df, 0x706c3acf, 0xc7869fa1, - 0x6fd1e217, 0xb3b7baed, 0xb51d824f, 0x7a2df33a, 0xfd85be4a, 0x27bf86ac, - 0x3817bc09, 0x74afbeb9, 0x2da9ba72, 0xacbe20e9, 0xfc44d93d, 0xe5c19b6c, - 0x5684ed9a, 0xcff6331e, 0xa8dbbd62, 0x63b5955d, 0x5477e61a, 0x7038ae3d, - 0x6e4f1fbf, 0xfcf0aede, 0xbd774fb8, 0x72f98891, 0xf2b02bec, 0xe1629e31, - 0xe4eb9deb, 0x5eece272, 0x7bd13800, 0xf672f193, 0x63fa95fb, 0xc20a63c1, - 0xfac056b3, 0x139533ec, 0xec7e84ff, 0x61ee49bd, 0x9ecfe4b0, 0x3feee9b9, - 0xeecfbcc1, 0xf746e299, 0x978b5a65, 0x69cfa7e8, 0x037ee371, 0xf40cf7c4, - 0x78efae17, 0x685af123, 0xabe9fa77, 0xd76e508b, 0x799e798a, 0xe10ebf5e, - 0x7fc9e1b2, 0x6bdf8c9b, 0x09aa4a03, 0xf8fbd9c7, 0xbe63677f, 0xf2469eea, - 0xfd3cb517, 0x17f311ba, 0xfe768174, 0x03926f7e, 0xf9fe9deb, 0xef08c9f6, - 0xfa168e96, 0xede7e67e, 0xe4f03e54, 0x77f6bdbf, 0x1378e3f4, 0xccef58dd, - 0x2f09fbf3, 0xf2953e75, 0xf5d1e2db, 0xb9fb7d8e, 0x8f3d44bc, 0xcb9f307c, - 0x92d74931, 0x793f4f7e, 0xbd48c4db, 0x0ab7df21, 0x026b4e7f, 0x099f23d7, - 0xe0adadfe, 0x9ecfcef1, 0xfda7ccb5, 0x1c343181, 0x6375c5f7, 0x2ddc5d38, - 0x71d751e0, 0x46c1a187, 0xdf9fa9ed, 0x73e3df02, 0x27e7d02c, 0x64852923, - 0xd7ca25cf, 0x0faa57f9, 0xbfa026f5, 0x1f45e6e7, 0xeb1f382a, 0x2d432698, - 0xfe69f3cd, 0xf91d561d, 0x6c6d6cbd, 0x38bffb3f, 0xe02ec26d, 0x59dd907c, - 0x3922e39d, 0x8b0f7260, 0x6bb387b0, 0x27182d7c, 0xcfad7ebe, 0xbe3c07ad, - 0xb4e8ea7c, 0x727e5041, 0xf84c52a4, 0xcf5c2bd7, 0x4e346df9, 0x81c1fa3d, - 0x3e0b768f, 0xf5307749, 0xdc03921a, 0x32a5501f, 0xaa7e46d5, 0xf513923e, - 0xee0f42ad, 0x736e7e11, 0x764dde5f, 0x26bb676a, 0xed061f62, 0xf72a366c, - 0xf310fde5, 0xe7f8674a, 0x1971de93, 0xa467be69, 0xf27e603c, 0x8b7e4a7b, - 0xbca11bf6, 0x57d1fcc1, 0x285de59d, 0x3d33e51f, 0xefe4bf8e, 0x74b8fbe2, - 0x15ca174f, 0xa35537b6, 0x95c9e20f, 0xe79f3703, 0x0f95fb7a, 0x901b0e89, - 0xdf7c710e, 0x5ede8d49, 0xe815c24e, 0x890fa5f0, 0x7177970e, 0x55d0daf9, - 0xd4fdc46e, 0x69d7e10e, 0x7484f410, 0xbfe8fb84, 0x9c69933a, 0xe1a1c986, - 0x0bcea728, 0x12ff3bba, 0x3a43b7a7, 0x0e01f91d, 0xdedd1eed, 0x8fd40ca2, - 0xf0978d4a, 0xe6f800dd, 0xa3daf376, 0xd7d56768, 0x6bf23730, 0x07e0a743, - 0xbe117bb0, 0xcbd55d0d, 0x6941bfb1, 0x0ddfc933, 0x41b4c976, 0x63a86e50, - 0xd96fc8a5, 0x425e2abb, 0x7c5d60ba, 0x035d9e3f, 0x4dd22cf6, 0x9f5bbd5a, - 0xdb8f7a8f, 0x2c8fd7bd, 0x723bf6a3, 0xf2e7145d, 0xf38a3157, 0x19fb40ef, - 0x68d65df5, 0x36fb3f6e, 0x5cc5dd92, 0x6537e409, 0xd60d753e, 0x622ff06f, - 0xcd11d794, 0xb4292fc7, 0x5808680f, 0x56681f29, 0x1a7fb717, 0x9f1f38ba, - 0x4f91f093, 0xe4adcf43, 0xc4c17f8f, 0xd0fe11fc, 0xce9a5f37, 0x268becf5, - 0x359fb3d2, 0xb0c7d87b, 0xbc85b7a0, 0x6dac7097, 0xdd21d7cb, 0x09937632, - 0xcc4cb1e7, 0xf5c0cda3, 0x03d0b246, 0x3cf8db05, 0x77e174d4, 0xa789d74c, - 0xe2e79b51, 0xe17f93f0, 0xc88f189c, 0x39e85d22, 0x797eba18, 0xeea4f890, - 0x9a5fde19, 0x677853c9, 0xfb4abd04, 0x0b1e9a28, 0xbbd9b8c4, 0x4c282a0e, - 0xd1cd77b2, 0x35f5f9f0, 0xeb08d82c, 0x2e977ebc, 0xd91c6538, 0x9e490b4d, - 0x58b237af, 0xd2232af9, 0x9556fdb9, 0xbf442dea, 0x36cdd576, 0xb93fa477, - 0xb3a3c12a, 0x24571da0, 0x12ded8fd, 0x4a9d1b8c, 0x6f11bbb7, 0xd25dd2e3, - 0x5bd8d30e, 0xdcdff703, 0xcda1bc0e, 0x1ff70e3f, 0xf309f581, 0xda09ae29, - 0x0edcfc8d, 0xf7fb8f68, 0x9cfed7dd, 0xb85bdfef, 0x070402ff, 0x6f5499c9, - 0x9d8ffa09, 0x5cb5de05, 0xb1ddd93f, 0x93aaf3d6, 0xcdc0e7af, 0x3ee216b7, - 0x8dae61b1, 0x5781e1f8, 0xde9ca594, 0xbee21140, 0x83f9c7da, 0xe13c7f01, - 0x3b247a22, 0x1bc9a1aa, 0x9c8f4d88, 0xaec01a5f, 0xe81b3b42, 0x93b70d71, - 0x13f38c6d, 0xbfb94ba7, 0x6915b947, 0x8d3e4acf, 0xbf497be6, 0x35ff7cfd, - 0x81bcfdf9, 0x8079e3f3, 0x3f7bd203, 0xe9ccbf9d, 0xe07aeb7c, 0x15bef847, - 0x4225b1f8, 0x7fef47fe, 0x1fb89e70, 0x1ef6f290, 0x3a5177a7, 0x6fdda1ca, - 0xab50c66d, 0x2f0d8f94, 0x397e196f, 0x958ccbbb, 0xf0335fa1, 0x60fd246b, - 0x445ed68c, 0x09ea3f4f, 0xfed8baeb, 0x6dd2bb8f, 0x3f3fcddf, 0xaee52f30, - 0x7981d2f4, 0x73a8e929, 0xadbb6f10, 0xa58fb401, 0x3e7a291f, 0x499f044b, - 0x03fdca7c, 0xfeb021c6, 0x37ef82fd, 0x888f7a89, 0x84bec467, 0xf3a5c1f8, - 0xf679487d, 0x6c91f471, 0xb5f97df7, 0x2f5238e4, 0x8c8dd346, 0xaa7ae0a3, - 0xd7afc4c7, 0xcfec5fb6, 0x29f8e8a2, 0x800b5fc1, 0x6dde7037, 0xc417e086, - 0x19d8778f, 0x99f813e5, 0x71e31527, 0x7ce08daf, 0x386fb234, 0xfa66b7b6, - 0x92ba44be, 0x8f7c5d7e, 0x115aaa71, 0x6bddacbf, 0x7f9e4408, 0xd18337b9, - 0xb376bd38, 0x91fc0f5f, 0x87dbe99b, 0xcc15fded, 0xf33d441d, 0x2b8a168f, - 0x8a5b8181, 0x8591a6f2, 0xefce1112, 0x205efb25, 0x0cf7d5fa, 0x39e3bf47, - 0xdf0e3425, 0xdafe109f, 0xfb5fc213, 0xcf7bd77e, 0x17ad02be, 0xf16e72bf, - 0x5ece918f, 0x7d21e4b4, 0xe7f4b09c, 0xdda125bf, 0x92b9817d, 0x690e772e, - 0x55ef5991, 0x2767fc23, 0x7ffdb1ec, 0x373c0b6f, 0x532b788a, 0xb7c3ed19, - 0x19f97067, 0xe3c4bf3e, 0xb4ebefad, 0x1cf937fe, 0xdfe1c193, 0x501ce719, - 0xd7df0661, 0xfce10e74, 0x50aed7d8, 0xdd66afbc, 0x41eb3ffa, 0xb5acd42e, - 0x9f09e907, 0x71ab8ed1, 0x283a83f8, 0xb970309f, 0xcd737f04, 0x07fd6165, - 0xc849d4f5, 0xc5077e33, 0xfd0a96bf, 0xcde9acb5, 0xa15fa1bf, 0x49e66546, - 0xf2c71845, 0x9f041e1e, 0x4f2db53e, 0xf2bff144, 0xa3a67747, 0xd458ca7e, - 0xa6c1f226, 0x55fed03a, 0x2fe8373c, 0x6f672f59, 0x132764a9, 0x1ede001d, - 0x22f6f0cc, 0xe24a2f1f, 0x7745c17e, 0x08fe035a, 0xf057b879, 0x7cfd3461, - 0xcdbce710, 0x01151997, 0xaa616fec, 0xefd46ff7, 0x7234e79d, 0xfa12bced, - 0x5f4823c5, 0x4fddd877, 0x22f2eef0, 0x05d263f3, 0x0e316bfc, 0xb7b1a204, - 0xbaf867b0, 0xbee3a47c, 0x5fa1dfbc, 0xf0e4dbab, 0x91bbf0bb, 0xf176cbbe, - 0xe3f141e2, 0xd2232e40, 0x8545c347, 0xf76961e8, 0xae51c79b, 0xa221a837, - 0x1b66a593, 0xa2e1b1e1, 0xd5a9e9ca, 0xdb243670, 0xa4d7ee03, 0x6032d27a, - 0x277bfe9e, 0x093c5325, 0x17c389f8, 0xe39c452a, 0x37c332f8, 0xf7e00328, - 0x36f13590, 0x305d7fdc, 0x8f3092bb, 0xf408d1ad, 0xe7753570, 0x43d84735, - 0xa5aec72c, 0xfeb7ee83, 0x6e5af386, 0xaf5119f6, 0xd134f0af, 0x4945b179, - 0x98c752c1, 0xd24fbc48, 0xf5fd1a5f, 0xc8497ef1, 0x3c8df797, 0x9d20646f, - 0xcf6c3c73, 0x39b2f510, 0xc79fbcbf, 0xe7c39e6a, 0xbb427828, 0x728887f7, - 0x170f2891, 0x7979d2f5, 0xf797e09a, 0xd17af1c7, 0xe3152ce3, 0x99e1997c, - 0x7682708c, 0xc7d22341, 0x673a166b, 0xfe404ac4, 0x935bbca1, 0xc82c764b, - 0x770869b9, 0x4c982718, 0x67a44cf5, 0x41c81358, 0xa96f67c0, 0xb5b3e08b, - 0xe305e81c, 0x289aaf41, 0x2bf1241e, 0xcf8d1af1, 0x77ca1985, 0x181f4fcb, - 0x51985ebf, 0xcd7e303a, 0x17c250d8, 0xf38c4bd1, 0xf5f0f11f, 0x03c73b6b, - 0x0cf2ebf0, 0xb1c183d2, 0x49b37c91, 0xb5ca51c0, 0x78b413f7, 0xe39d3cfd, - 0xbbd45ea1, 0xda1f7684, 0xe23eeed1, 0x7853f7bf, 0xae02b4fd, 0xfe5da497, - 0x5f2e024f, 0x529f6ba6, 0xd1fb44cf, 0xe2f214bf, 0x47ee74cb, 0x8ddebc07, - 0x09fa95f3, 0x19304ce4, 0xebd178f8, 0x6c339226, 0xd5e51f63, 0x83ffbd40, - 0xea645af0, 0xf41535bb, 0xdec10fca, 0xbb511631, 0x0647284b, 0x48c7efec, - 0xd433b0ba, 0x0e19addb, 0xf4941f6e, 0x48d7b8f1, 0x0ca5aebe, 0x657287e4, - 0x210c63fc, 0x6bf0e40b, 0xc142bf22, 0x6214aebc, 0x07f61767, 0x8c97ff70, - 0xa3dc30d2, 0xe8213bc7, 0x450cd1e0, 0xb215bc25, 0xaddbc442, 0x5f6e7eef, - 0x139e5d0c, 0x4d9365e7, 0xe7ec76be, 0x916fddec, 0x18c27e9d, 0x8b66de1c, - 0x7c18ddf1, 0xfc2521ec, 0xf4a7b6fd, 0x98d5e37e, 0xc1f67e7f, 0x4bdd619b, - 0x1c6ef47b, 0x5f3de972, 0xed1e33bc, 0xc5031eec, 0x6fdf406b, 0x4dde7153, - 0xa13caedc, 0x67c1d2d3, 0x3df76977, 0x907a0baf, 0xdca572e7, 0x157cfa91, - 0x93797373, 0xcb1bb890, 0x3b71dd1f, 0xce5dcb9d, 0x003d87bc, 0x666bd3f7, - 0x3b7c5d92, 0xcf5e51f3, 0x39ed56b2, 0xda6d15db, 0x073bedf2, 0x3925c39c, - 0xfd102abc, 0x2ba5f85e, 0xf3fbeb63, 0x333f2e82, 0x7afdf88a, 0xfdf8cc53, - 0x09fc85ef, 0xb4fbd9c7, 0x2f57fbf1, 0x8c6fbf1f, 0xed87df8a, 0x3df8e888, - 0x6113f7ef, 0x91bf606f, 0x2acffc71, 0xa3e3af62, 0x58b7690c, 0x9f19f935, - 0x125bb00c, 0x45e37be9, 0xd8f99c4b, 0x2b67fde8, 0xd7d38f63, 0x5f368e3f, - 0xe79edc20, 0xb5fdc809, 0x8bc693a4, 0x6567a459, 0xe1c7da59, 0x3df43976, - 0xf4babcfa, 0xf8be4b6f, 0x2ce66158, 0x176d47f2, 0xf29bbc76, 0xbb463f33, - 0xba72f908, 0x4c10b5eb, 0x278fd971, 0x8487570e, 0x1d7a26f9, 0x42675f40, - 0x98d8f211, 0xfd234f69, 0x3a6e66eb, 0xfee82797, 0xe8abbbd6, 0xbdffcf7c, - 0x322332a7, 0x53f72a6e, 0x8f69460d, 0x96fa34d9, 0x65e3e945, 0x1d916f5d, - 0x70d7f606, 0x7a7f3e14, 0xc3d26ef5, 0x1d37992b, 0xd5f7bde9, 0xe56e7411, - 0x3961eadb, 0x4bfc9b9f, 0x35bf3c0c, 0x3987ec8d, 0x75373e62, 0x67503b73, - 0x1c6818f6, 0xd239730f, 0xe7cd8b69, 0x8554420b, 0xf3fd75f2, 0x631de747, - 0x15fcc493, 0xbdf00f6c, 0x52d93c4e, 0xdbce265f, 0x31eae384, 0x8990260d, - 0x6e8996cf, 0x28a73e17, 0x83cf955e, 0x6b1a79e3, 0x3afac1ca, 0xd7cf4873, - 0xc7483309, 0xa2f0fdf6, 0x37945db2, 0xeb70bdce, 0xb36f7c0a, 0x8a313c93, - 0x04cf4c79, 0x6dfc88b9, 0xb75c6666, 0x4d3c16c9, 0xf4f133f1, 0x8f88b857, - 0xf91843fd, 0x07581241, 0xd9b53f9d, 0xb171f9ce, 0xb050e60e, 0x085c716c, - 0x9ce27ee2, 0xf3c7e6c3, 0x672f20c4, 0x5f3fa265, 0xc44ad5f9, 0xee67c80b, - 0x5df78a17, 0x11f3f20d, 0x88a5de42, 0x7908b5f9, 0x8adcc597, 0xe480c7b8, - 0x95f6fddd, 0x267ee037, 0xa3f7798d, 0x71387bbc, 0x32fdc506, 0x93e68f98, - 0xc8d5433a, 0x5b57a72d, 0x46af98ce, 0xe7053bcb, 0xbed3e597, 0x9413b337, - 0xbd04a497, 0x69529799, 0xfd12361f, 0x37210631, 0x3e78598e, 0xcf3166c2, - 0x8853333b, 0x78598e6e, 0xb6b7c25e, 0x7ddadc5b, 0x3f0a437d, 0xdd3e7fbf, - 0xc0f1c66c, 0xe113b98e, 0x07cc7607, 0xdfce167e, 0x41d29c2c, 0x6f9b0279, - 0xe01bdc54, 0x6bbb66fd, 0xeba40abd, 0x7f70a99f, 0xc728ea8f, 0x3cf69c7c, - 0x44f31b87, 0xf7be451b, 0xf6a38b66, 0x9a63f219, 0xb7d63d78, 0xed96e319, - 0xac0e1d5b, 0x37d95697, 0xaafb88cd, 0x9bb1cc15, 0xaff7a0c5, 0xbe608f80, - 0xe032c73f, 0x63f41149, 0x85bae23d, 0xefbe20d6, 0xf0177fc1, 0xdc3294f2, - 0x82bff2bf, 0x773a42ee, 0xd27a3cc9, 0x85dd8d97, 0xbc60d86f, 0xe485b982, - 0xf256f7af, 0x72132fb8, 0x571cbc60, 0x61b5d9f0, 0x85efa7ba, 0x5bb43ca2, - 0x4cd37ff8, 0x80ebae3c, 0x91c4ca21, 0xc69fac43, 0xe4cdc1f9, 0x6bd3e71f, - 0xfb0ff858, 0x4ff70cab, 0xf86a6972, 0x60ef9873, 0xbbb322a8, 0x8dea0ea5, - 0x91fb8357, 0xcf15afaf, 0x543cf142, 0xe5e9237e, 0x65cd9d1e, 0x373e71d4, - 0xc3aba017, 0x94b847ab, 0x60b4b639, 0x4129d73f, 0xd8cde67a, 0x9fd382de, - 0xc94cfc23, 0x9e00c699, 0x00996b37, 0xc8bf2678, 0xffa30f9f, 0xac2fff5a, - 0xcc74f118, 0x279ef520, 0xb9ffe789, 0x0ed53d68, 0xce97593e, 0xc22e7b33, - 0xcf3f28f9, 0x8b74d0c6, 0xa997fef8, 0xd7974955, 0x300f3cbb, 0xe5cf4b25, - 0x871e0ce3, 0xa66f9c6d, 0x7146e5bc, 0x7d53030f, 0xf08c3ff9, 0xc5b8c8af, - 0x7f3606bb, 0x46fd8c5f, 0x07b7164a, 0xfdc0dce6, 0x1f228dc2, 0xcc4f7e47, - 0xbfb27ee2, 0x377b4e64, 0x1e3dec93, 0x949dfd6f, 0x48d9235f, 0xf2115f94, - 0x5f248fe5, 0x278edfca, 0x85dfb47f, 0x29e799fc, 0x40bed036, 0xef2921c8, - 0x68ef22bd, 0x1018f301, 0x1ee23d4f, 0xabe5a395, 0xccdd0e48, 0xf7fef47c, - 0x00ff3c15, 0xfd80d308, 0x6b4334dd, 0x6af3cd3f, 0x8fcf37cb, 0x3e38afb6, - 0x7c0bb8e4, 0xa473efda, 0x6b433c9d, 0x87fa2f27, 0xcf4992af, 0xfea2fc67, - 0x3e70e0d2, 0x3e546351, 0x27c88351, 0x3c2aec6a, 0x4f911694, 0xf3cdd8d4, - 0xaeba1a89, 0xedc44f94, 0xb029af29, 0xde24e31f, 0xec94d25a, 0x727f910d, - 0x8a4ff310, 0xaf6e74c2, 0x0c3cf3b0, 0xa2bca1e6, 0xce95871c, 0x8aeab45d, - 0x9adb8fc8, 0xddf8d768, 0x5577aeb7, 0xbfe93d61, 0x4843f995, 0xc3f6b137, - 0x5f7c59d9, 0x7ee143b3, 0x3302ff74, 0x059d3bed, 0xc15c4d5e, 0xd1c767a9, - 0xa66ef8af, 0x3f27d64b, 0x2f830ec9, 0x019e18ab, 0x8979d185, 0xb67af6fe, - 0x5190fc91, 0xea99ca72, 0x338038a6, 0xf5f92c69, 0x921775e7, 0x2cd9923f, - 0xb84a61ee, 0xdb7379ff, 0x69ebcc55, 0x97576eec, 0x3774c2db, 0x43ec4b36, - 0xf48accac, 0x7bd7efda, 0xbd7e44ce, 0x30b79364, 0x19d7da0b, 0x8bbfe483, - 0x1f7a57a0, 0x2ede5f4f, 0xe150c5e8, 0xe602b05d, 0xd18efbd7, 0x0a6bfb8d, - 0xcfff41cc, 0x7e4c94bf, 0x230e7549, 0x9cb1b53d, 0xf45e93cb, 0x3e3ac193, - 0xfaf7e64d, 0xa466ac6c, 0x4ca7cf5f, 0xc55e3a23, 0xe83d8702, 0x7405db47, - 0xd2cf7918, 0x8eb96d1e, 0xa9fe9075, 0x3d00667b, 0xf2947c93, 0xf4b99eb8, - 0x741b8c06, 0xa1b3db6a, 0x285c395a, 0xbcf147f4, 0xff982da9, 0xf2e3ac50, - 0x0f772d91, 0xf5fb439a, 0x2c4f8e45, 0xa17f7228, 0xebaece5c, 0x73d29fb5, - 0xa17ae7fe, 0xad1ff454, 0x3d854abf, 0x17e41937, 0x7da56fee, 0x7ca9f506, - 0xcfadd750, 0x59e785d4, 0xbb49da22, 0x890bea50, 0x8c09f2af, 0xbbb579e1, - 0x1a7c84b2, 0xbe2086c2, 0x13e27fa1, 0x29583705, 0xf71fbfd4, 0xf18ad785, - 0xa8fc1e80, 0x733afdbf, 0xb36be900, 0xd2fa44d2, 0x3c3ff68c, 0xd23e2ab7, - 0xe35eff0b, 0x4c7d23d7, 0xdd374d64, 0x9926f500, 0xb728ac7b, 0x31fe4e80, - 0x585a7e92, 0xa29f6f30, 0x7efa23a1, 0x98edf936, 0x5af52474, 0x9edcf7f0, - 0x74bcc599, 0x0fe793cf, 0xa83aeedc, 0xd8267df0, 0xeed1079f, 0x93375b7a, - 0x2c2664e8, 0x3955eb03, 0x9e9ff8b4, 0xdf472da9, 0x5ad0c50f, 0x48744328, - 0x9c540678, 0x51bdf44f, 0x98f7291e, 0xb3e5ee56, 0xf8de78af, 0x423fc396, - 0x1d7583ff, 0x0ef6891b, 0x8fc4aa58, 0x27b0f4d1, 0xb78f7beb, 0x118ac9ec, - 0x7e15e96f, 0x68586be5, 0x40ca33e5, 0x687f3b7a, 0x82333e9d, 0xbc7f252e, - 0x1379e06c, 0xae3cebca, 0xc6ccc135, 0x252e1104, 0xf928ffdc, 0xd3a41ae3, - 0x95fd3094, 0xa487f789, 0x06cc197c, 0xd75dbd23, 0x01ea0965, 0xbfa2853f, - 0x8afe906b, 0xdc89f6c2, 0x184cb477, 0x98f96740, 0x4cf60e17, 0xb495d201, - 0x8e958a4f, 0xfde73c16, 0xb6f74bfc, 0xe8237ce0, 0xc3842dea, 0x8ae80559, - 0xf4036afc, 0x147bf6ad, 0x4bfc49dd, 0x359cba7b, 0x6e677ed1, 0xc1b3d702, - 0xcf49dbea, 0xba24b882, 0xa70e737b, 0x21e62abb, 0x5a672bba, 0x6b34a97a, - 0x0974d1cb, 0x74b4ea23, 0x8bba23e7, 0x7478d7a6, 0x4ee91837, 0x2bd4dbea, - 0x48e7ddd3, 0x8fc5df77, 0x3eee9039, 0xa7c672cf, 0x937a68bb, 0xc59f6cf2, - 0x75768951, 0xfa428d63, 0xa19df8a1, 0x511e582d, 0xf6764f9f, 0xd93764be, - 0xfc4d8ddd, 0x478f497b, 0x0533798f, 0x7cf7c56b, 0x1b96256f, 0xe877c1d7, - 0xcf18f4ba, 0x0f7a19ab, 0xa1b85eff, 0xbfbc0de9, 0xdbcfd1a0, 0x337a7cbf, - 0x6c0a879d, 0xdbcbed16, 0xd8dcb12a, 0x8a7fdbca, 0x31abae71, 0x82d02dbf, - 0x96daafef, 0x6fdbe6ef, 0x114fd76e, 0x3ca7ddeb, 0x6bb506f7, 0x3f6eede3, - 0xe4604e6c, 0xfaf6e027, 0x29ceb164, 0xd33af8bb, 0x867ebe3e, 0x4563e80b, - 0xb9ec9f9f, 0x6575744f, 0xece2ef24, 0xb695cbb3, 0x474e7c1c, 0xbc47a639, - 0x43f55bbb, 0x37741c78, 0x3675710c, 0xf8c8d3f7, 0x5429e621, 0x5717d847, - 0x443b7367, 0x614f4bd6, 0xfd8d7e74, 0x72fe4ecc, 0x3e0cdf19, 0x07d414c4, - 0x976146b8, 0x4e778cc4, 0xbb22682f, 0x1960fa62, 0x4ba90ce7, 0x4bc2dc61, - 0xe58b4f9f, 0xe6cb2a47, 0x9129f3f6, 0xd7df2177, 0x4875f204, 0x4890fb17, - 0x90f0fce8, 0xdb9ed077, 0xe734cc97, 0xf3e5f6dc, 0xbcecd4f2, 0x01cd6e7f, - 0x549aeaf8, 0xe58bf7bc, 0xf2b79429, 0x4c161e83, 0xff381c4a, 0x1a0b2ae9, - 0xcf8a0f29, 0x518b657f, 0xe5c257dc, 0x3f813cda, 0xd1186936, 0xa7815cef, - 0x17a16cea, 0xca31598b, 0x6f0279a9, 0x1937343f, 0x336ebeb8, 0x798fc944, - 0x1e3f28d9, 0x6bcf6b8e, 0x97c947bf, 0x4aee311a, 0x62afc761, 0xfd3fe47d, - 0xa7f1d844, 0xfc76e61e, 0xfe41d66a, 0x719fded3, 0x961ebe3b, 0xed12f487, - 0xabddad07, 0x6877d72d, 0xdea00dcb, 0xaec6ffb1, 0x8633b928, 0x1f7ba5fb, - 0x3f432fae, 0x77cecd64, 0x235dffc8, 0x2b404ce5, 0xe740c067, 0x51a1e672, - 0xd6fabfe4, 0xd819e3f2, 0xf26995d5, 0x76c9ef4b, 0x5e77f846, 0x0d2e79e4, - 0x7a11fb8c, 0xc16f23ed, 0xd28b2c7d, 0xa572d14f, 0xe915c850, 0x5bf290ff, - 0xc6429bca, 0x77ec14f5, 0x9b60f1df, 0xe1ef3b28, 0xc4afa16c, 0x4dfa4dfe, - 0x88547da4, 0xd7d211f6, 0xba2226a8, 0xbf727eb0, 0xe847d26d, 0x662505a5, - 0x19917bc4, 0xa6e11bf8, 0xd9f58db7, 0x68f1f434, 0x83f7e5f6, 0xf451efda, - 0x0b63f723, 0x84dcfd05, 0xff181891, 0xb81f720f, 0x5ccfd38a, 0xf4843de6, - 0x9cd5fbf3, 0xf0bee47e, 0x3d03ef9b, 0xa07dc8fa, 0xdd7e4fdc, 0xdd3f60fd, - 0x863ec058, 0xe95cb1e7, 0xfdf1e017, 0x45d38546, 0x3ddf9cfd, 0xf2c2c556, - 0x733368e2, 0xb97086ab, 0x8cc9a665, 0x0316977e, 0x99cd2fdf, 0xd2d97ef5, - 0xb413f908, 0xb8401f97, 0xf9276eb1, 0xdaadeb77, 0x3d2b3671, 0xf711fd77, - 0xc95a8f55, 0x08e174af, 0xc2e59323, 0x0f9411ae, 0xc78199fe, 0x6e7ce55b, - 0xb5f7bc3f, 0xb95bd410, 0xcc6296ee, 0x0255a82f, 0xb7c1d62f, 0x77beac0f, - 0x756bbf91, 0x672f7141, 0xe427c50f, 0xbafdf1b8, 0xc6c7927e, 0xf73f5c03, - 0xdf940929, 0x4787ef0b, 0x38fee9c6, 0xdcefcb88, 0xb807df4c, 0x5b47a91e, - 0xf827f3fa, 0x1b30b413, 0xa7ce1294, 0x704de708, 0x985fcb7f, 0x13798ae7, - 0x04e2231b, 0xbe663ed0, 0xcf2179db, 0x01726147, 0xba6567cc, 0x7fd717a7, - 0x4f85c44a, 0xa9e23889, 0xfc571e44, 0xfe7d7f7b, 0x7ae20db4, 0x3b8894e8, - 0xc6d14a9e, 0x44bd649b, 0x6cd93cf1, 0x60346ef6, 0x37799ebc, 0x3d70fe82, - 0x7ca26a64, 0x5f1c4595, 0x6b252fbd, 0x1ac811ee, 0x106a3e54, 0xd399fbb4, - 0xe3041fab, 0x9ed36f2c, 0xf715ea83, 0xba0af6db, 0xa7f0b5e9, 0x506b371c, - 0xd76c28f5, 0xb3df80bb, 0x289e5fda, 0xbfea5ecb, 0xc910baf7, 0x8ff2fea3, - 0x3a9ce242, 0xf8c893f7, 0x61f8bc40, 0xfa30bc74, 0xbc74699c, 0x37e4b17f, - 0x245fef11, 0x6ee2d4e4, 0xd5b86f1e, 0x820f36cc, 0x6775b7ef, 0x26b8fc50, - 0x135c3fd1, 0xbf5bf7ef, 0xa4879e51, 0x9edcdecf, 0xcff8f8fe, 0xf5e3e222, - 0x2f5a3e22, 0x5da9d7d7, 0xcf0164df, 0x3e3e31ef, 0x60739079, 0x9f3a3c7c, - 0x33b445e2, 0xac3c610c, 0x55b87071, 0xd12aebe9, 0x39617c4f, 0x35f73ca3, - 0x416b2d6f, 0x2d9af23f, 0x615596e2, 0x380bd777, 0xd3975bc7, 0x8d2e63ab, - 0xb9813ebf, 0xe593d622, 0xc994d14b, 0x33c88f92, 0xad93541d, 0x34db9f69, - 0xf07f5344, 0xef9a51ba, 0x4d22fef9, 0x1af5a0b9, 0x6d61fd4d, 0x88f29a15, - 0xea6bd79d, 0x4921b217, 0xa23b6fe4, 0xbb125f47, 0xf347302a, 0x85def47d, - 0xb29ff69a, 0xa0931da6, 0x7b45a75e, 0x7bf3332f, 0x8594c67a, 0x76c7a9f3, - 0xc3f4d52c, 0x29504a82, 0xf633df0b, 0x79a7b899, 0x878f0f79, 0x5ab5dd5c, - 0xbead4e33, 0x1d18f08e, 0x7d622def, 0x086e37e4, 0x1b20ee28, 0xd55dff18, - 0xaeed4ed5, 0x78c8f764, 0x2241c6c8, 0xb2cd97de, 0xd3475d39, 0xc3ec8d85, - 0xe4f4bb0b, 0xc3642c7f, 0xf0449a1f, 0x6b80b032, 0x302efe20, 0xf0bb17ee, - 0x798ddd8c, 0xb5bfb745, 0xca63e68c, 0xde05d2d4, 0x5eb9181f, 0x5d2d48eb, - 0x3a5addd8, 0xa5a09a48, 0x27786883, 0xc174b47b, 0xcbbff042, 0x86753bc0, - 0xb7fe6e96, 0xf081dce0, 0x5be186b5, 0x62d3d07c, 0xbcf1b823, 0x999f6935, - 0x1d143d84, 0x4e7690d7, 0xbbb09070, 0x2e323f45, 0x93f159b1, 0x771fd55d, - 0x0bcc109c, 0xd53da3e6, 0xc95fb8c4, 0x6fe5107b, 0xbd24bf0c, 0x9497e78f, - 0xc09b9d70, 0xf32d67f5, 0x663efc92, 0x93a4fee1, 0x9fc8abd5, 0x913592b4, - 0x9cd9fddd, 0xe8efc2e9, 0xca577aa7, 0x9f901853, 0x8b29f600, 0x06aed7f0, - 0x1fef1a8b, 0xd2a7868a, 0x78ed04ad, 0x4b75986e, 0xfca3e07d, 0xedde0f15, - 0x68ff89a9, 0x51e65fed, 0xb497e522, 0x1278e587, 0xc9ae529e, 0x49ac4c71, - 0x117c899f, 0xc8d8e725, 0xd693f8e8, 0x41fd239f, 0xe3238e32, 0x9bfed14c, - 0x55b8bb08, 0xc1d2718f, 0xce782df9, 0x21e1d8b7, 0xeb29613f, 0x4fdf05b9, - 0xa8b47730, 0xb8bfe12e, 0x2ffbf58a, 0x2babeae2, 0xf26fb5c4, 0xf247a12b, - 0x65b3c607, 0xff961c7c, 0xf1a11ff1, 0x8b95c524, 0xf2f398f3, 0xd3d22708, - 0xfba6bf40, 0x8fd02bf8, 0x8a97d75e, 0x3130aaf5, 0xfdde223d, 0xf5a212a6, - 0x367990fc, 0x6fdb9e45, 0x6ed31d60, 0xe8327f21, 0xa727bc49, 0x58bbfb93, - 0xac3db457, 0x0759bf92, 0xafba412b, 0xde711165, 0x2a77f0fc, 0x659607eb, - 0xec95d21e, 0x82f1a789, 0xe0a3ca72, 0xc84c53f9, 0x8cffb941, 0xf993cfb7, - 0x4f7ef218, 0x94547799, 0x1c75f823, 0x03fd871b, 0x94e595bf, 0xf8017fa2, - 0xc7e48953, 0xfa253cfe, 0xa31f803e, 0x31f32fd6, 0xf212f6f4, 0x5c8b2d1b, - 0x8780d7ef, 0x9c7e5bb4, 0xc8e9e8c3, 0x3eb3d171, 0x3d6fc4e1, 0x47a4b9f8, - 0x68da3f93, 0xfa0d0d84, 0x79145e13, 0xbb5a1d81, 0x9d1c96fd, 0xf7df1b80, - 0xf15e095c, 0xf8f221f1, 0xaebe3e04, 0xf8f3261d, 0x0c971c24, 0x0d0afb84, - 0x8ff7fb5c, 0x115f70fd, 0x2e12ee0b, 0x7e7b4ae7, 0xdbd2f881, 0xbc23a58f, - 0x577aa617, 0xe3dcfd63, 0x5d144fa1, 0xfa555e78, 0x7b8794b3, 0xe74f4ba1, - 0xe3ae1aff, 0x25e1b072, 0xf386893d, 0xb38a26dd, 0x41bd74d6, 0x66d9e176, - 0xfc06b410, 0x72180cbd, 0x08fc65d8, 0xb78ef051, 0xd9eb924f, 0xe5f62390, - 0xef32fd62, 0x39b9d607, 0x475e6627, 0xdfb41c3f, 0xf4aa1c05, 0x1cf09263, - 0x92be7f59, 0x791797da, 0x3af45f5f, 0xfe78722a, 0xf7b329db, 0xc3efec3e, - 0xd81d9c9e, 0xfbbe955f, 0x67c23670, 0xbbe742ad, 0x79f898a6, 0x5e712cdc, - 0xc9a8426f, 0x3399e78d, 0x667df873, 0xf7a47e23, 0xfdf91c62, 0xe0a677b5, - 0xffd93439, 0xe7474508, 0xee7b1947, 0xc12c7f83, 0x3722e6f8, 0xd8bf6fde, - 0xba2fee24, 0x002c1acb, 0x91baf239, 0x186547df, 0x66e744d2, 0xe4f592fa, - 0xb3d34cd7, 0x727748a9, 0xadbcf2de, 0x01f78f7c, 0x7cb15e60, 0xafa5a53f, - 0x7bfa0d78, 0x75c83d04, 0x2beca94f, 0xe185b26e, 0xa33cf32f, 0xf82553e1, - 0x1b43ee43, 0xd05b5ef0, 0xbccde7bf, 0x6daf7d1c, 0x5874feff, 0xf6363dff, - 0x837eb8c8, 0x1e3493c5, 0x6bdc51f9, 0x278717fb, 0xa477df89, 0xbcf6a7bd, - 0xbf97b7c8, 0xdeef1253, 0x51ccff9b, 0x827b97be, 0xcb85e5e2, 0x7078ffbc, - 0x99564869, 0x739d357a, 0xdeae5ef7, 0x8fadff2b, 0x28bedfb9, 0xd3dff7be, - 0xbcec6af9, 0xceb15ec5, 0x88617e70, 0xe7f729ce, 0x7e54be2d, 0x1a477bd9, - 0x08d23ef0, 0xf6bcc838, 0xb48fbc06, 0xd0bf4638, 0xe576cb9f, 0xc4aa877b, - 0x8f301abc, 0x3df23530, 0x38f0b7a7, 0x302f2269, 0xfb7c8894, 0x9d3d2ecb, - 0x11e5ffe3, 0x31dd8cdd, 0xcb9b9de6, 0xa9ca32e1, 0x0e8d1f12, 0xe3b5fbf2, - 0x79e793d5, 0xe8d8b9e4, 0x845675f9, 0x63f9c56e, 0xf1ac729e, 0x3f7cb91c, - 0x99dde72b, 0xf0d1f1c2, 0x9bdf899a, 0xf27cf2aa, 0x4ad094ce, 0x168713e2, - 0x1e04c3cf, 0xe50faf3b, 0x99b2b9d1, 0x8f10efdc, 0xfaa7261e, 0xc8be51ca, - 0xd4caee7b, 0xc111c526, 0x87a2578f, 0x1af5dc30, 0xbb840ebc, 0x7ecbbe91, - 0x7c151f4f, 0xdc363ccb, 0xfa112dcf, 0x5a9ec96e, 0x7ee587b2, 0x3d4ef4e9, - 0x669c6fe5, 0xba72ae3c, 0xd0fda14d, 0xeb631f52, 0x7cad2e40, 0xaa3378a2, - 0xb09925ae, 0x1efe1496, 0xe9661f7f, 0xbaf8a8c6, 0xbd495fd8, 0xbe5fc72a, - 0xd7176b4d, 0x467f6db0, 0x51f4e9fb, 0xb0563f2e, 0x2b3fd226, 0x57f6d01f, - 0xa7d667b3, 0xbce8cf38, 0x8fc21180, 0xec572d37, 0x1958ca57, 0x4f358fea, - 0x9fc46e7c, 0x17c78960, 0x434ffbf8, 0x7ddff187, 0x8efe27c2, 0xc96f3e08, - 0x1720fcf5, 0xf2ef3efd, 0xf5ceaef9, 0x7f45c9cd, 0x7e7cbbc9, 0x702eea17, - 0x8d2bb33d, 0xfd8b5bf4, 0xfaff922e, 0xdffe5cc1, 0x0035f78b, 0x71264c9c, - 0x49aeba6f, 0x4df6489f, 0x43ece880, 0x7e731de7, 0x26776540, 0xd3da43f2, - 0xbf6067d3, 0x1eada7ce, 0x72d6df5c, 0x2ffa214f, 0xf3f356b6, 0x8f1366a1, - 0x397e07df, 0x538600f1, 0xaf6c7686, 0xa39d1740, 0xfd107f7b, 0x3fbaad42, - 0x98bcc61f, 0x5f3cc9d6, 0xda175d32, 0x3c62283f, 0x899035a7, 0x68e77df1, - 0x9a4e6f7e, 0xcb90bcbe, 0x36276e7f, 0xe85c5c08, 0x627f202a, 0x17fa41af, - 0x2e742c3b, 0x2eff8eab, 0xf1c628c6, 0x70eaf32f, 0xf176910e, 0xf9a666d9, - 0x1d51869d, 0x4890d04a, 0x3c50a8f7, 0x30436ea8, 0x67d416fd, 0x4f14a94f, - 0x7b4bf393, 0xe302ab3d, 0xdd8f5266, 0xbfb838a2, 0x0bfdd84d, 0x71e3fc98, - 0x9e82f9b7, 0xff7b0816, 0xf7872b16, 0xc3cee652, 0x2ccd0b76, 0x76ac0751, - 0x2947654b, 0x90d6b3ad, 0x8c85768c, 0x47b7c51f, 0x1ac9fb62, 0xe7e7617e, - 0xe1be959e, 0xf419c9d8, 0x3f865d41, 0x693c85db, 0xffcfce18, 0x83cca1b1, - 0xd786caf1, 0x30efd046, 0x3c781299, 0x1996e41c, 0x843a11ef, 0xbdd61efa, - 0xc88b15ea, 0x73880a5b, 0xd8defccd, 0x453939c6, 0x78f11e74, 0x71ffdd1f, - 0x23ca10de, 0x847906fe, 0x92bea637, 0xe01fbbfb, 0xd90debbd, 0xf941d760, - 0x789fee74, 0x25684879, 0x92991bde, 0x47978977, 0x72c13e85, 0x6cc25e4e, - 0x5685172a, 0x3e3ca1ea, 0x7197932f, 0x36040a03, 0x6cf06f35, 0xc92dda3f, - 0x87702ec2, 0xc377bce8, 0x917423cb, 0x1e7758fe, 0x84676797, 0x3e4cf93f, - 0xc20e6dbb, 0xfaec647b, 0xded27969, 0xc9f5a36e, 0x2cf6caf5, 0xffbb7633, - 0x957e7210, 0xc53da738, 0x3c2d5aca, 0x044fe7fe, 0x1eec1c3c, 0x7fcbf141, - 0xfde14dcd, 0x4f74423b, 0xfa27ec8f, 0xb8e41c77, 0x7bfe15ab, 0xf2a3e759, - 0xcb977ebc, 0xb38c2be5, 0xea19c691, 0xe79be7e1, 0xfe2214e4, 0xc0aa6f00, - 0xc9f7ca9b, 0xd07e7ced, 0x13fefe2f, 0xf46287e8, 0x0afc1ffb, 0xe787e7ea, - 0x27274d1d, 0x5aab38c5, 0x2fb6dc78, 0x69e880b9, 0xf7dc558a, 0xc75da252, - 0x9f6e3cf8, 0xc592f3ba, 0xaf091d79, 0x69c6850c, 0x09cc7011, 0xf6339f0d, - 0xaffbaf9b, 0x8eeb4bff, 0xef0797c0, 0xc5d8396d, 0x9f1e37ef, 0xf485f1c7, - 0xe076429c, 0x677f4d76, 0x9fb547d6, 0xae5f28c0, 0xda80a521, 0x6fee2bdf, - 0x61d9f795, 0xdc71fcbb, 0x57bb45be, 0xfcc1a7de, 0x1c645993, 0x8cdeffb2, - 0x70bf710e, 0x286f3aff, 0x8874eb11, 0xef223a75, 0xcfe7ec33, 0x73797d63, - 0xb8e903ed, 0xfdfdfe1f, 0xfd12298d, 0x563cf869, 0xf1d7c87f, 0x1e5572f0, - 0x1bdf2797, 0xa33ce45e, 0xe70fd9e0, 0x7849f9a8, 0xbb537f22, 0x94ba5a31, - 0xf411ccf3, 0xf3bf8039, 0xe278e5bf, 0xbbfad97e, 0x7338be79, 0xbebae969, - 0xf9875f33, 0x07ddb209, 0x34a0c078, 0x21bc27ec, 0x7327ec4f, 0xbc9c4e58, - 0x339e6f47, 0xde917fa6, 0x7b27ef47, 0xd9efe593, 0xbd1afd69, 0x397bfe4e, - 0x7efc73fe, 0xfca36b83, 0x7a8f183c, 0x176e16ce, 0xf2da2fd6, 0x037e0263, - 0x797d54fd, 0x5312bf38, 0x3bf8f3c5, 0x4af3ab5b, 0x7760ab67, 0xdc552494, - 0xa6e50f99, 0xfc93c6c7, 0xf154192e, 0xf3c83e79, 0xe04d8f35, 0x7c5747df, - 0x79cb043e, 0x8a797913, 0xf79479e7, 0x9eccb460, 0x2bb6159a, 0xd173ccee, - 0x1d4afab8, 0x42676bdd, 0x63d60623, 0xf944dd7a, 0xf1ae1280, 0x5d26259e, - 0xbff3ac53, 0x03d3f4f7, 0xc04cbf8f, 0x1fd0ba7f, 0x2105fc28, 0xe82fe355, - 0xcfe7e44d, 0x92fd5f7b, 0x9bdcd7ce, 0x079f5be7, 0x67ad1bed, 0xf287cd6f, - 0x1407eb06, 0x603c53ef, 0xc61fa087, 0x608b60e5, 0xadd9cabe, 0xd89fb45e, - 0x2559b76a, 0x18ff0ab8, 0xf007a9de, 0xa7b5e57b, 0x0f883c7e, 0x4c79c5e3, - 0xf1a07214, 0x15fdbfb5, 0x678dc4e3, 0x1b346e6c, 0x7c3f7627, 0x135fda27, - 0x1bfedfbb, 0x3cfcc3d7, 0x44f79c90, 0xfbc27ff4, 0x9a265d09, 0xabeec4ff, - 0x6bfd6056, 0x402eebdf, 0x44eeb93a, 0x42c505b0, 0x3effabef, 0x880e7348, - 0x7cd97a7d, 0x39f1b8d1, 0x013f8f09, 0x1e0893a0, 0xf8f0e73f, 0xced9f28a, - 0x0e6e8f3b, 0x7b549391, 0x78ec0ade, 0x605f3b8a, 0x7b8c6e09, 0xd1fd73c8, - 0xd5e3d57e, 0x7f783eb0, 0x20cc1f5d, 0x729e9ec2, 0x24820cd1, 0xc9672e5c, - 0x39a5729a, 0xcabf534b, 0x3ef9af91, 0xcd2af33d, 0x42ae99f7, 0xc8d6794d, - 0x37fa9a89, 0xe535cbba, 0x6a6613d9, 0xaa7b57ea, 0x60c2e535, 0xf17ea687, - 0xf7ed2e91, 0x788f4c63, 0x7eee3a28, 0x27a59f03, 0x2d9ee43d, 0x06f4d53b, - 0x85fe273e, 0xafda2383, 0x8ec5cd7c, 0xf4bdf037, 0x9f9f472b, 0x9be67e92, - 0x3180b6f5, 0x53393fb6, 0x83df082d, 0xf3f1d7a0, 0xfb25ef53, 0x937880fe, - 0xa0a6a7e7, 0x5090195f, 0x9fb9db75, 0x5c32efe2, 0x6efdc458, 0x943111c7, - 0x7f276e4f, 0xd34371e5, 0x79e47fb3, 0xf728b903, 0xaf9bebae, 0x8b94f759, - 0xcbbacd3e, 0x3c28aad9, 0x5729a1dd, 0xd4d6ee39, 0x5eb99e9f, 0x6ba67df3, - 0xb69e144b, 0xba37ca6b, 0x53c28e1f, 0x9e9e147b, 0xf4977cd2, 0x5ffc2ddd, - 0x0adfa1af, 0x3d42939e, 0xc9878895, 0x1f08faa7, 0x2ada7a13, 0x1cd74f11, - 0x957c20ef, 0x2895bd04, 0x348ecb2e, 0x20cf81bd, 0xddb0cbec, 0x7a4ce681, - 0x91766c1e, 0xf370ebff, 0x691e7a48, 0xfffbd376, 0xcf409e68, 0xe87b355f, - 0x33cd9ff9, 0xecd3d9e8, 0x734767a5, 0xae7fd507, 0xcffb8bb9, 0xddeffb52, - 0xc1bf45c8, 0x01a85d79, 0xc18ec623, 0x9e9e495b, 0xc79d084f, 0xeb7f06f2, - 0x3420a9ec, 0x901d67f0, 0x9e207f2f, 0xfb4f2e45, 0x1e0e7860, 0x19fdf8cc, - 0x43a37f22, 0x3b4429e7, 0x0fe3f47c, 0x32e6a7de, 0x37bd69b6, 0x183a7f13, - 0x132866cb, 0x90f7e9b2, 0x93cfbc1e, 0xa8b3d8c3, 0xf7bee84a, 0xb9636707, - 0xe79efc57, 0x241fc7e0, 0xc75bfc3b, 0xe2033dd9, 0xc707a3ec, 0x7b3fb388, - 0x7f4765ca, 0x46afd1cf, 0x471e11d8, 0xc3cbdf85, 0x3bf80d0a, 0xa16ae51c, - 0xf1ecf501, 0x5421e738, 0xe0c97953, 0x7bb75c52, 0x5f91e51e, 0xe1dfa06f, - 0xfdf0a39b, 0xec97acaf, 0xf7a0fae2, 0xa7ed1346, 0x2b3ce98e, 0x957a3f90, - 0xce10c7be, 0x14fe3d37, 0x7b5ea9e9, 0xafc21e5f, 0xbcbdf1fa, 0x4c7becec, - 0x0d944771, 0x8f953e1c, 0x6fdb393f, 0x33e15efb, 0x0d11d71b, 0x1d83b99f, - 0xf4115f7c, 0x201da2e4, 0x3daac7cb, 0x2c5714f5, 0x75c30cf7, 0x389af51c, - 0x81ed7aff, 0xf237e461, 0xf08bce94, 0x360cf4ff, 0xa2e7fad0, 0xe83f44de, - 0xd6207d42, 0x1f9e15ef, 0xa23dedcc, 0x2e67dc13, 0xe0bed2b0, 0xa3df8e98, - 0xeedf5d10, 0xcfa3fbe2, 0x9c87dce2, 0xdc57be28, 0x0becff54, 0x5aef5fd0, - 0xebdd750b, 0x58f6411d, 0x1740136f, 0x54f7ba68, 0xddfe39d3, 0xa12016e4, - 0xf82def38, 0x6cfef82f, 0xfc5f9df7, 0xb07fea06, 0x1d26ead6, 0xf04518e2, - 0x2f2a285b, 0xfd93354e, 0x6e4e78b4, 0x5bc5ea05, 0x56f0bc44, 0x614e9abb, - 0xe8d93543, 0xdb967e80, 0x0403370a, 0x6ab4cad9, 0x5364fe23, 0x9b1dce4d, - 0xe87ab9f1, 0x58f22376, 0x9b7d98dd, 0x07ad8cd1, 0xf9252e16, 0x19a77a17, - 0x3adb75e6, 0xe7ef8bbd, 0xdadaf9e4, 0x22f7946f, 0xc898f7e9, 0xd020024f, - 0xa5c9357e, 0x4949f668, 0x181f4e82, 0x6331e22c, 0xda4bd8d9, 0xe44ed778, - 0xdf8bb3a3, 0x1e271e19, 0xec2efda1, 0x7b8adfc7, 0x4fefa39e, 0x5c3ae391, - 0xcc75ff7c, 0xf6899408, 0x07ae42e4, 0x7cffcdc6, 0x7fac2943, 0x4743b75c, - 0xd5b70d79, 0xb87880bf, 0x68f025d0, 0x4fc85d60, 0x7c97f937, 0x4c421bf0, - 0xf0dce69a, 0xbba5f495, 0xa91951c7, 0xde424b2f, 0x397d48ca, 0x12adafa1, - 0x8fd4a2f5, 0x211ae6c1, 0x8e489b8f, 0x475e6c1e, 0x7ecdc3e5, 0x6e691e7a, - 0x8db8f215, 0x79aaffbe, 0x01c790a7, 0xd2f78f21, 0xf9e6eefb, 0xd9ad7cf4, - 0xa985cf47, 0x6e11d7be, 0xd73b8e32, 0xdcbca3ec, 0x189b0f43, 0x742ef1c6, - 0x038f289b, 0x47b1e238, 0xc94f30d2, 0xa344e744, 0xe5a295f3, 0x743d3f7c, - 0xe5b7b80e, 0xfef7e46d, 0x17b4233c, 0xa7a7c707, 0x4765cca3, 0xe0f1f4b9, - 0x8e8724f3, 0xb4765cba, 0x2e3e4fa7, 0xdd971eca, 0x0d3fe500, 0x71fd25ee, - 0x9bb2e7d4, 0xe3c9fca0, 0xdfbbfcbd, 0xf940b765, 0xfc7dc1d3, 0xd051807b, - 0x2fe0ecff, 0x33958e48, 0x47f220e5, 0x2a7f39a5, 0xd7d00ba8, 0x2f9107e5, - 0x992e67a6, 0x60b17c8a, 0x72e88bb0, 0x41fd6ba6, 0xd91acf2c, 0x1515e2ae, - 0x46e15b1e, 0x5691576c, 0xa9bb62ad, 0xc46c7739, 0x6e86d376, 0xcddb2357, - 0x236fb318, 0xb7706f96, 0x2e9f68ab, 0x1a563940, 0xe59647ee, 0x65a72977, - 0xddd5dd3e, 0xe307d25e, 0x0fa4bcba, 0xe62a5c24, 0xff426f56, 0xe2976367, - 0xa9a5dfc0, 0x27f4ab98, 0x62ee6033, 0x0a93de03, 0x3dfffaf2, 0x87ac77ae, - 0xf9623675, 0xadb72a1a, 0xedfa06ff, 0xe2f6007f, 0x8000e831, 0x00008000, - 0x00088b1f, 0x00000000, 0x3cd5ff00, 0xe5547809, 0x9dcee7b5, 0x4c92642d, - 0xe2420836, 0x96249964, 0x26b6432c, 0x0c486410, 0xf90130ee, 0x10196544, - 0x044816c2, 0x7eab17eb, 0xe0171a19, 0xd16b8d69, 0xb5c46faa, 0x61e4b6af, - 0x1d0958d4, 0x87d252aa, 0xb410553a, 0x88a47479, 0x119099f0, 0xc7d278dc, - 0xf7fce73b, 0x24cee666, 0xbefd1480, 0xff938607, 0xcfd9fbfe, 0x005ffff9, - 0xb3f85380, 0x34607f02, 0x3d2538fe, 0x0468048c, 0xd1bf67f1, 0x0395b26d, - 0x8c0734ac, 0x412fa3a0, 0x6010aba3, 0x76960eaf, 0x24a40014, 0x0b7afcc3, - 0x74b08d96, 0x5de7960b, 0x05480368, 0x20bada68, 0xda85816e, 0x6066e3bb, - 0xe21745fb, 0x52ce38af, 0xe0546e05, 0x9bd40a93, 0x4f34899c, 0x1fd24d9a, - 0x856fc7ca, 0x064a7850, 0x3d9ab7e8, 0x448004ba, 0x0dac7b93, 0xfb9bedc7, - 0x8758834e, 0x31d688af, 0xeb1ebd6c, 0x6c3200e3, 0xca1f1e56, 0x5e541982, - 0xc846ed09, 0xcff5b846, 0xda22a4fb, 0x2327c597, 0x5f434e84, 0xf9ec5f20, - 0x63fe1654, 0xe0543d06, 0x6e03e97a, 0x70d79969, 0xea566020, 0x743967f1, - 0x226670ec, 0x7ed45ede, 0x18bf046f, 0x7dfb43bf, 0xbe8de215, 0xbf697537, - 0x0f5b5403, 0x0230438d, 0xd9dfb8cb, 0x855efe12, 0x878f0dff, 0xc3c06749, - 0x10f0a1a4, 0x1af01fb5, 0xd7de8e41, 0xa66ecb0a, 0xc0bee473, 0xd1fcca9d, - 0xf7218108, 0xf445f2a7, 0xfe05dafe, 0x25ff02f5, 0x5a74e736, 0x38fcdd5f, - 0x8e005390, 0x4d79356d, 0xa9ffdc99, 0x1744293d, 0x2d837593, 0x5b5b3e9a, - 0x00de8367, 0xcdd5adb0, 0x14bad7d0, 0x3f8076f4, 0xf97336b5, 0x2e16d6ad, - 0x30f568ef, 0x8ebad9dc, 0xdb5a5fe1, 0xeb577eb9, 0xdbbf2e46, 0x6fe865ea, - 0x5fbf917d, 0x86657f3b, 0xff4d12db, 0x45cec9d5, 0x7b9e8fc4, 0x3e9913aa, - 0xc853f7b8, 0xc81a9eab, 0xc344b66f, 0x9d658301, 0x8f65c094, 0xd9e1f711, - 0xc36de316, 0x8c73fd7d, 0x19c689bb, 0xad7e09a8, 0x4a437c43, 0x30d0f180, - 0xbe9abdd2, 0x3a1c464b, 0xe4f56689, 0xeb0efe12, 0x6407bf3c, 0xd39b56d9, - 0x383e47a5, 0x17558f1a, 0x6582dc00, 0x78f3ce0f, 0xfa85abaa, 0x48c07e41, - 0x3fa29ce3, 0x097c7193, 0x3af07766, 0x0e1ca210, 0xb1e808c4, 0xd18f2c49, - 0x40ddc850, 0x60f99fba, 0x1913e9e0, 0xcb3382b6, 0xa8f870c5, 0x9e03ab93, - 0x6567a432, 0xd584c3ac, 0xa4f8127d, 0x46538412, 0xd38e00d6, 0x13d46e97, - 0x5644149c, 0x9fc3c750, 0x6322dfc9, 0x14cbf186, 0x6b94d448, 0xed35a3cd, - 0x9a99aceb, 0x5cf4befa, 0xb4d2ff1e, 0xfaed348b, 0xc59a5746, 0x232f53bc, - 0x6f7465d8, 0x0974805c, 0x9b1c9956, 0x98bdfeb0, 0x062822f8, 0xbf1b1698, - 0x317be089, 0x376a5e19, 0x14c9c0ed, 0x934e7dc0, 0x108b237d, 0xc6db9755, - 0x99edc76b, 0x76c36353, 0x6957e657, 0x25c121d7, 0x1dabdfb4, 0xa7df3453, - 0xe9ae5e57, 0x93fb32ef, 0xcef5ad08, 0xc6f7cd7a, 0x9f41af96, 0xe5b1300c, - 0x014be824, 0x343afbc6, 0xecee94e3, 0xbf1fb4d2, 0xeb12641b, 0x378e7d92, - 0x741f9609, 0x152ac4ca, 0x24df9b87, 0x3fa5f558, 0x4e01f683, 0x9f5159b0, - 0x83dc8a4b, 0x963d0247, 0xcae52927, 0x812db7a0, 0xf21270e8, 0x89bf48f5, - 0x6321c230, 0xbff2a963, 0x4c1f104e, 0x32002052, 0x16abf607, 0x3a79804b, - 0x4598d78b, 0x1be5056a, 0xc906c1f5, 0x3847a691, 0x50540e47, 0x8a0428f9, - 0x973aca08, 0x2a6bf89e, 0xb2a58f34, 0x0469dc09, 0xbf74483f, 0x2fdc7c4f, - 0xe2c4da05, 0xcfc4c982, 0x68ff3f75, 0x17ac6dde, 0x5c261c62, 0xfebaefdf, - 0xfd6b4a91, 0x91f53fbb, 0x7e216c37, 0xcd7eb26f, 0x8dcb5278, 0x7f19c72d, - 0x2d6fb96a, 0x92e177cc, 0x9f680ddb, 0xaffe3610, 0xed0a76cc, 0x53a23ada, - 0xb8c9fc23, 0x1ed420ba, 0xc418be3a, 0xbfea3177, 0x04d35a7a, 0x5ddfd7c2, - 0x6f576c4e, 0x9e087210, 0x1c4ef545, 0x29463ea7, 0xa7d44f83, 0xb2a1ed2a, - 0x6ae9cb9e, 0x6f68957d, 0x587bc757, 0x96ad1fb4, 0x522ef195, 0x9ca2cdcb, - 0xa0f7cea9, 0xe5aa1728, 0x397170ff, 0x613fb44e, 0x29ef559b, 0x53ffe908, - 0x0f18ddaa, 0xa06ec9e3, 0xc933903d, 0x1abb481e, 0xeda21f98, 0xb15eb685, - 0x237ff317, 0x44c58c7b, 0xdf63cb8f, 0x90eeb921, 0xf1bae480, 0x8bd38376, - 0xd49e7ff3, 0x12c6b451, 0xb7e7dfc2, 0x6abb7c08, 0xb6329ce3, 0xde6af95f, - 0x3923e226, 0x85c8f76e, 0x563addf8, 0x4ea77ac7, 0xe88138b6, 0xfbd0af7b, - 0xd848ff6a, 0x8686f2d0, 0xb2f5519e, 0x6cc1f3c4, 0xfaf9c1fc, 0xf4f51bef, - 0x8e59c206, 0x9370973f, 0xdcf42999, 0x95add448, 0xea36f3f8, 0x3dd23359, - 0x3a9c1b25, 0x1af29f6c, 0xf1a267ea, 0xc7d0bf41, 0x24f8c5af, 0x8f959c14, - 0x6ff6c9bd, 0x8e528ca1, 0xcf2d7bf8, 0x7c89979d, 0x9fce347a, 0xd0db7c4b, - 0x75d78db2, 0xe3cadd8d, 0x10583583, 0xcce2cf8e, 0x9e97fc28, 0x3fa5ff01, - 0x8271fe26, 0x75cfa403, 0xbeb47428, 0x78b796e5, 0xef95cbbf, 0x43325fac, - 0x472cb8ed, 0x39c68f97, 0x0e1f0832, 0x74074e85, 0x5f050ab6, 0xfabe1357, - 0x1373fb17, 0xf9f0ecb1, 0x3ed9ba47, 0x88972aec, 0x4071cdee, 0xf92a3f74, - 0x410ef68b, 0x0ed68eff, 0x5a5bcbb6, 0x84be18bb, 0x55bad073, 0x8d10dd7c, - 0xc067f9df, 0x131ffcef, 0x01f4a3bf, 0xadfb03a3, 0x4e3c07da, 0x1180ff85, - 0x2b4cf4c2, 0x27e225f1, 0xfae24ba1, 0x2120b93a, 0x138fa9a0, 0x738e52fe, - 0xcae9f13c, 0x37aabb19, 0x98792148, 0x311d0b1c, 0x0ed7cc49, 0xc41daf85, - 0x22ff2ad7, 0x11ea963f, 0xc49d6fcf, 0x37e0437e, 0xf3c0bfc4, 0x3bba78a8, - 0x881baf1a, 0xabc1a78e, 0xc607feb6, 0xc7fa276b, 0xaf8237a4, 0x653778c4, - 0x77f9e346, 0x7c555e0a, 0x7fe4536f, 0x236f3c38, 0x7f9ea73c, 0xb4cb6f3c, - 0xf891b8f1, 0x453ece1e, 0xf75d47d2, 0x7e5a7210, 0x2d3a722e, 0xdff8aadb, - 0x461677e8, 0xa26dfdd3, 0xf74359bb, 0x53c8339e, 0x4f298fcf, 0x848b7891, - 0x3ab8128d, 0x3fdfd12c, 0xdf561ccb, 0x4e3c179d, 0xf8d6ce0a, 0x75bf9367, - 0x29b3fc6b, 0xfd696118, 0xe5349bd8, 0x9aadeb3a, 0xada697f6, 0x6e5fd4d5, - 0xbfa9af5b, 0x4d01ff32, 0x63c76af9, 0xd3e67e11, 0xe77afa9a, 0x73f5346f, - 0xea6bb79b, 0x68f4b7e7, 0xfe7817ea, 0x78ab29aa, 0x1c0adadc, 0x356b6d2f, - 0x65d3f12b, 0xfe03ab0c, 0x8b83125a, 0xdfd9070f, 0xd7b7f4ac, 0xafb24bb2, - 0x32d1fd83, 0xc296ab9f, 0xcd9d8aaa, 0xb5f4126f, 0x2d78955a, 0xad5be18d, - 0x3befd636, 0xee19f35a, 0xf128756c, 0x5dc3255a, 0x4e254ead, 0xb48c3173, - 0xbb66af0b, 0x3d2164a7, 0x44bcbda6, 0xe980b807, 0xc167f87f, 0x77bc5a5e, - 0xdce28ebc, 0x8e5eca35, 0xffb37f57, 0xe3afe436, 0x950726cd, 0x311fb77b, - 0xf9a30ad8, 0x32b7ee65, 0x6cf8c338, 0x0d5fcb6e, 0x45cd67e4, 0x0863ba0f, - 0xa59a9d39, 0xf7207e63, 0xcc2f5003, 0x05218336, 0xd9ecc1f5, 0xf80da392, - 0x189207bb, 0x3f58dcfa, 0x133e0f4d, 0x7a2deb96, 0x979e299f, 0x3fa332e6, - 0x132c4b3d, 0x50f07a4c, 0x7324a43d, 0x7d0d7e9c, 0x383ca1b4, 0xbf18b865, - 0x1c3f22cf, 0xe96f5dfb, 0xbddd9030, 0xfa2fe76e, 0xb87ac36f, 0xf1ce53d3, - 0x25625c3d, 0x3e792dfd, 0x371a9dd6, 0x3520bcbc, 0x5f1850e1, 0x4e19254f, - 0xe1d1f8a5, 0x7adc5277, 0x9cf1c193, 0x05dfba2d, 0xc9a77eca, 0xc16ffb12, - 0x4dde4dd7, 0x713e4852, 0xb84d3b7f, 0x01e226cf, 0xc1b367da, 0x7e445797, - 0xb3f676f6, 0x16d72a9b, 0x2e9a9d11, 0x15313e91, 0xa69de285, 0x8fd92f96, - 0x91cfd48f, 0x90f14cf0, 0xfe656fc3, 0x93badfdb, 0x8b8d45f9, 0x5c7d5b7a, - 0x6ab80b2e, 0x39a3e3c3, 0xa64dff93, 0x4beaa7b8, 0x3c4cff11, 0x53fbdce9, - 0xd5a077dc, 0x17e52fff, 0x9a82bcd4, 0x5bcc8867, 0xde647aa8, 0x6e0975ad, - 0x2c9aefdc, 0x94f30651, 0x5ea3a674, 0xdedf5540, 0x9765159a, 0xbd3ac8ef, - 0xffd6d67e, 0x6cf9fac0, 0x4d31bff9, 0xbe48d5d8, 0x05e337df, 0xe553ad03, - 0x9ffe48ef, 0xfe707d43, 0xd7924d39, 0xf67a7a83, 0x44c37692, 0x7df9dce9, - 0x88a0e5b9, 0xc2ed238b, 0x3607b6f7, 0x2b5c9ba6, 0x92617c73, 0x1e50726f, - 0x4743a544, 0xcf3add34, 0x1fceb740, 0x76d16e93, 0x73bce0f1, 0xf1a08bb3, - 0x8acbdfcf, 0xc83e27f2, 0xa91fbd3a, 0xf781ffad, 0x636b1d6d, 0xef4472b8, - 0xea27593c, 0x01627c45, 0x80eff21d, 0x74b8e657, 0x3c7b6669, 0x195033c5, - 0xb77d278c, 0xf2065bac, 0xd4ef410f, 0x5cfe468f, 0x1f67f0a2, 0x7e243ef8, - 0x7ef7055c, 0x25980941, 0x22ae4bd5, 0x09f4b73d, 0xfc4f0843, 0x27f393af, - 0xcb7e94ab, 0xda469d2d, 0xb567f2ef, 0x1a71d4ed, 0x1fc88a5f, 0x19fa5f57, - 0x73f0ddb0, 0xa7556fde, 0x5977dfb6, 0x62872971, 0x084b1659, 0xa7d267ef, - 0x1baec947, 0x5b27cac2, 0x3f20bf39, 0x9e03e0f3, 0xc4fa21b1, 0x71f14764, - 0xf9e9f65c, 0x23ff5b58, 0xf71cb1f3, 0xf9e891ac, 0xbf78f97d, 0xeb4599dd, - 0xa0f3f556, 0xc4c379de, 0xdca0677a, 0x37a4f226, 0x9e2daefd, 0x3804e4f8, - 0x2a161d88, 0x6a85d2f9, 0x369d74be, 0xcfb93a5f, 0x49b979c7, 0x716dbd07, - 0xbd89f748, 0x55dbce1e, 0x59b776ed, 0x5dd3fcb0, 0xa3fc994e, 0x64b96ff1, - 0xdfeab75a, 0x484efea8, 0xbeb0e58f, 0xf66bbce3, 0xd53bebd9, 0x30f6aa2e, - 0x06560ed2, 0xfec96bdb, 0xe3b6f84d, 0x2be7824d, 0xf7691eaf, 0x7a138bde, - 0x57c1a8e2, 0x8cfc97be, 0xcf1c63d7, 0xaffaf441, 0xc67e16cb, 0x0302cf4c, - 0x1f091fcb, 0x450cdbca, 0x764fae6e, 0xf54d975f, 0x99d0bd8a, 0xa3b2069d, - 0x23df7275, 0xf95f12d7, 0xde1bce65, 0xbf07c77c, 0xccedb5ff, 0xeb2685f9, - 0x863ff671, 0x749a338b, 0xa2f8a6e0, 0x4a56d6a4, 0x6dc50c7e, 0xf3544794, - 0x9fed918a, 0xc8acd7b0, 0xb5573ce6, 0xd9eb49df, 0x1c33d628, 0xbe5a9abd, - 0x8731e4d0, 0xbba9bf9b, 0x4c30badc, 0x16ca5e3e, 0xdbd22ef1, 0xa21cc87a, - 0xc5f2d9f7, 0x65f8b7ff, 0x091e0c9a, 0xe4a16ced, 0x082ffe15, 0xf80e783f, - 0x2083ce19, 0xf9583743, 0x38216a7c, 0x17022e18, 0xdbbb7cc3, 0x60337c4b, - 0xbe248e08, 0xbbf57fea, 0xfe9be202, 0x57b6278b, 0x5f3bf9c1, 0x06fff48a, - 0xfe78dbc6, 0xdbbe5781, 0x7039fc43, 0xf4ace187, 0x6764eac6, 0xe451f127, - 0x53bbcb79, 0x01d73e64, 0x8b967afd, 0x03e8ab7a, 0x1b72a497, 0xe64cd8eb, - 0x1cde908b, 0x37aab4f5, 0xc2bf6017, 0xd7ac744f, 0xb5e49960, 0x80aed363, - 0x70ac458e, 0xa657a671, 0x2fa8a772, 0x95e8995c, 0x15585cb0, 0x4a6fea23, - 0xc52642f4, 0xcb960143, 0x0fac00f9, 0x8bd08017, 0xf7938237, 0x96419189, - 0x6f17fd84, 0x3e709735, 0xa4390216, 0x8e288bff, 0xb74e221a, 0x2f7908e6, - 0xbefa12ce, 0x179b46b8, 0xc95b30f9, 0x4a6bdb1b, 0xe7561072, 0x1d12f738, - 0x1bfc938b, 0x7ca32a1e, 0xa1360e90, 0x75567d7c, 0xaa779f2b, 0x35ed1afd, - 0xcdbf84bd, 0xe2bc7012, 0x9f7936e9, 0x238ce713, 0xf2cdcfc3, 0xa807b5ed, - 0x7b5a11dd, 0xc578f0f9, 0x47f71c7e, 0xd78795cb, 0x1bb14c57, 0x43f1fbe7, - 0xe5cbcf25, 0xebe679ff, 0xf80b3bfa, 0x7e43c14c, 0x7ddda372, 0x046fd79c, - 0x9ffad0b0, 0x40147114, 0x47e50673, 0xd2653c97, 0x11f19f91, 0x03c8639a, - 0xddc61bf8, 0xe31bff04, 0xc77f8267, 0x27e099f8, 0xfc133f18, 0x04cfc607, - 0x1e3b7f17, 0x8d802283, 0x4e4b4e39, 0x301ce879, 0x1c86bd72, 0xf9c1cf81, - 0x7f3c8dbb, 0xf8cddd9d, 0xebf7a41d, 0x9973a5e0, 0x0bc189cd, 0x6fc34e92, - 0xf0dfdd03, 0x7870e9f9, 0x2325cf51, 0xe853bfeb, 0x67a9d45a, 0x15d45ffb, - 0x6b086f88, 0x918e4177, 0x395f0beb, 0x1fe34f18, 0xd7e20eb5, 0xa796e129, - 0x82f944e9, 0x08332d67, 0x677675bf, 0xe51bed09, 0x51f6833c, 0x83c1f5d4, - 0x7c78cb13, 0x75a364ab, 0xb8e51f04, 0x911f6221, 0xb5f75078, 0x81bfd139, - 0x257e6ffa, 0x7a82768b, 0x10dc8407, 0xed43491f, 0xcff32d77, 0xccb05374, - 0x7e9deb8a, 0x0a1e6e4a, 0x29f675ff, 0x5477e78c, 0xc7cf537e, 0xe952fe15, - 0x1df2ae76, 0x6b901e39, 0x6ae77e84, 0xb236a5d2, 0xc9e3274b, 0xee57ac2f, - 0xe6757419, 0xf4fb47bc, 0x6ec194ec, 0xc8d63e63, 0x5f8562df, 0x6dd85854, - 0x36bd1174, 0x59ca1f77, 0xe4fa6164, 0xb3f6c62c, 0xbc9aec72, 0x89d56167, - 0xe14a1fc7, 0xea9a56f6, 0xceba783a, 0x60dfe38a, 0x6d36fede, 0x93f5ae69, - 0xcf2c44ba, 0x1076934f, 0x9ccb605c, 0xe5a3649a, 0x37fd797a, 0x41d94fe6, - 0xa3957522, 0x29b9fd9e, 0xecc264a4, 0x9639ad43, 0xcb071f0e, 0x4d64d675, - 0x31b4d2f9, 0xdb97f69a, 0x57f535b2, 0xd4d38fe6, 0xe55ef3ab, 0x2bb4d528, - 0x51660a4e, 0x60fb875c, 0x64e780b9, 0x7da25daf, 0x1c62beef, 0x3f3da796, - 0xca6e41cb, 0xda7ea566, 0xd12f5a96, 0x69f10063, 0x70ea8744, 0x1f47fae5, - 0xe222c1a2, 0x67eec686, 0xe76d3876, 0x130c3710, 0x7100ac2f, 0xdc5c3f8e, - 0xa02f1910, 0xf4907cfe, 0xd7abf167, 0xdc70db58, 0x2e2755cd, 0xef3ee1b0, - 0x8238c1cc, 0x47128dec, 0x833fc70c, 0x04d92272, 0xf0c8f4ff, 0x03fc10dc, - 0x1f850bf0, 0x3ef69c05, 0xdf0533fa, 0x4a7dbf5f, 0x07f38dfa, 0x57efc51e, - 0xafbe4460, 0x6f78e8d8, 0xdea7e50d, 0xf9ce8191, 0x03ae24e1, 0x77e81beb, - 0xb0f7c439, 0x46bbe9e8, 0x0f77f0a7, 0x94aba6b9, 0x731fdffc, 0x71aabf14, - 0xcba35dfb, 0xf370f542, 0x70f69a27, 0xa6b774bb, 0xb6a6677c, 0xbb94ef7c, - 0xe70ffbc3, 0x5c6c3597, 0x9ca37460, 0x392c3c36, 0x8be843bd, 0x28a4f5c1, - 0x097ba1fa, 0xdb43dbeb, 0x716d1997, 0xe157edd1, 0x6cb79478, 0xaadec618, - 0x193aea7a, 0x7faa879a, 0x71cf9d47, 0x08fbe77e, 0xcdf64f71, 0xc3b09af3, - 0x8db8251f, 0x2fb27ce1, 0xf47b9c47, 0x1dc0f63f, 0xee79d35f, 0xeabe22eb, - 0xa3f6144f, 0x9d33f3a8, 0x08f1610e, 0xd6455fc1, 0xd2ec8e80, 0x0f58d2c0, - 0x2d359ca0, 0x8ae8f38b, 0x7e088fc9, 0x5e4f1e68, 0x9a0f2dc7, 0xeb1fce91, - 0x3cbb1a74, 0x9616c140, 0xd9fd9efb, 0xf7e93b8c, 0xe92f7102, 0x2fb3ed7c, - 0xad7d8407, 0x1e637a11, 0xb7629ff1, 0xd3565500, 0xc768305d, 0x5e10cf48, - 0xbf6b9ca8, 0xc987fdf5, 0x7a11efcf, 0x370af283, 0xb4e05fb0, 0x1d0df368, - 0xbbf8e72c, 0xd73efc2d, 0xb78feb59, 0xf3968dda, 0xd84647a8, 0x218779b5, - 0x57fbc5f4, 0x5e9b3d22, 0xd05ef997, 0x04f6adb1, 0x911fd308, 0x28da6c78, - 0xe5ab9cb3, 0xcbe55ba3, 0x830f6cbc, 0xd185f519, 0x83a706f8, 0x55b57fe5, - 0xd27ab7cc, 0x4ec83337, 0x8bd6eeaf, 0xcdc32f4b, 0x5b064eb3, 0xb79b3cd8, - 0x5d929699, 0x603fd753, 0xf749f455, 0x0a534957, 0x843b5c04, 0xc0bf457d, - 0x417e4290, 0xecf1c4bd, 0x3551ee9e, 0x123da784, 0x3c256cf8, 0x5c6635c4, - 0x1c314cdf, 0x5e50b77d, 0xf9f2d214, 0xd71aa59e, 0xacecf1aa, 0xf27659ee, - 0x5cec3f63, 0x072907b8, 0xccd9ec93, 0x8782d74f, 0x893deefd, 0x93ca74ae, - 0x3fee534c, 0xf60c49ec, 0x67bdbf91, 0xf744ac52, 0x3bfc7019, 0x5f757c69, - 0xf4ae0c7b, 0x9297de66, 0x44fe752f, 0xf67b153e, 0x67aaa271, 0xa7dbe4eb, - 0xf7e7495c, 0xf14ac073, 0xf85974ec, 0x2147f0d5, 0x6d5eaacf, 0x6c49fc92, - 0xa633edaa, 0xa34f11db, 0xe4a97e5a, 0xf735db7d, 0xafd6cf00, 0x5fa38c1e, - 0x567f9894, 0xb1bc4439, 0x47f3faaa, 0x57f9c5ae, 0xfe4fbc61, 0xedaec2dd, - 0x917f08fb, 0x7c60fdf1, 0x7be62ff5, 0xd733e3a3, 0xcddfda32, 0x73df1c77, - 0x69c7442d, 0xea817183, 0xcb173e5f, 0x58a8d6e7, 0xfc287c85, 0xee5b647a, - 0x7f5835de, 0x66062fe4, 0xfd2737d7, 0x58ade8ea, 0x58b9f9be, 0x2491f3c6, - 0x391d90f0, 0xebcf29b2, 0x744b06c1, 0x6fb25ec1, 0xcf8e25b0, 0x327b3e69, - 0x512fb7ef, 0x76b7f27e, 0x7e4843f6, 0x7cc2e86c, 0xe88ff746, 0xb9a3cbfb, - 0xbcc5b81f, 0xca5c8a0d, 0x5fde142f, 0x242ff54d, 0xa5427e73, 0x6327e1df, - 0x7dac149c, 0x2b22be05, 0x92e7deb2, 0x5bdd10e7, 0x697ba15c, 0xf97c84bf, - 0x06f708d5, 0xc7f2f7da, 0x89c3f3ff, 0x17da9fb8, 0x1555feae, 0x07d96fae, - 0x84e340a9, 0xdfb43ae8, 0xb66b6c70, 0x3f057f90, 0xf18c5e2b, 0x27d30c1e, - 0x35123b2b, 0xd1aea6e5, 0x7a6183de, 0x729ef068, 0x04e7c4a3, 0xed5c8a8d, - 0xeddbba37, 0xfba5d794, 0x713f4ca9, 0xce84b51f, 0xf7ff08ab, 0x91ff1899, - 0x5da2f67c, 0xf3566739, 0x4e60c93c, 0x0b75b923, 0x97dc0dfc, 0x31e289b7, - 0xf1493d9f, 0x33b9823b, 0xb3f9c30a, 0x9c1bd577, 0x7b8931e7, 0x9f43318f, - 0x13da77eb, 0xf9837db9, 0x699e4d4b, 0x4d09cb55, 0x015567fe, 0xd2501fb0, - 0x89bd2b66, 0xba1487ce, 0x7aee9fdc, 0xf1def18d, 0x18bbabc0, 0xf2dc4f9f, - 0xd3bbcd31, 0x5d83f4c2, 0x11163c4a, 0xbf98356f, 0x69efe450, 0xe87e7f8d, - 0x9445bdb1, 0xcaf438ff, 0xd3ca22b8, 0x87fd942e, 0xf7c99d7e, 0x86dff69c, - 0xf7cecb70, 0xb91e2f39, 0x0c7ba8de, 0x8d43d092, 0xba648fb4, 0xc77ae3ff, - 0xf42e72ce, 0x850d81c3, 0x1f353f8c, 0xe864703d, 0xa75d5078, 0x3ebabe3a, - 0xddb57c75, 0x5f22ecdf, 0x17f46fd0, 0x415ffd91, 0xfb6130e7, 0x17f78fea, - 0xbbe85a25, 0x4913f855, 0xb7e30e58, 0x2abcf57f, 0xf06a7cf2, 0x47c9565c, - 0xfdadd3ed, 0xaff91199, 0x8321e3af, 0x7eef5c3b, 0x752a73cf, 0xdafdeabd, - 0xfd85ab7e, 0x2576939b, 0xe90e9f1f, 0x1deb0ed4, 0xb7bff23e, 0xc7e41c98, - 0x905c9a27, 0x3469f88b, 0x9afef8fa, 0xe4d12fda, 0x7991efe6, 0x234481f9, - 0x81e5bdd0, 0xf7fce554, 0x42bd602b, 0x9c16e871, 0xd756acb7, 0xd212c5bc, - 0x2cfeaa87, 0x0bdf871b, 0x3ea91ee8, 0xdf2027e4, 0xdb6b1594, 0x2da3f687, - 0xa0ae7bff, 0x6eb25963, 0x24b938c8, 0x1b65c857, 0x9e42c874, 0xa89d1d85, - 0xbf0d1de0, 0xacd7ee1c, 0x40fcf452, 0x0743d9bc, 0x8ab713bb, 0xf513ab7b, - 0x5104edbe, 0x124b400b, 0x89f4995d, 0xfab4baf1, 0x1cc86c9c, 0xd8e3cbb6, - 0xc8504f2e, 0xccd4b77d, 0xf7435bf7, 0xc132fd5c, 0xd0c8218b, 0x413d5609, - 0x4bc30324, 0x2a70c5c0, 0x0cbc3334, 0x015e19da, 0x02af0c1d, 0x89f8433f, - 0x1ed80daf, 0xff656edc, 0x3a25f2e9, 0xd765cbb2, 0xcf97ed0e, 0x3c35f052, - 0x57cb503e, 0xa63e3b9c, 0x8772f72a, 0x7cd8cbc5, 0x2f157be6, 0xec4fe226, - 0x34de0317, 0xc0209382, 0x46264ce3, 0xdd78a6ce, 0x6b7ef7c6, 0xbae5c9c1, - 0x6547c4b3, 0x1777adc0, 0xda97810c, 0x9e64f9a1, 0xb90327c2, 0xe951f8c0, - 0x8dae48f5, 0x30dd2acb, 0x7b234c50, 0xc84f4d10, 0xc59675a0, 0xa7a71cd6, - 0x5f3fb722, 0x7a8f5336, 0x66b4acb4, 0x5f90a90d, 0xe5154ee6, 0xd32f3589, - 0xf3fb7d51, 0x71728a97, 0x81c1a94d, 0xcbdae85e, 0xfa825e66, 0x27dcadd9, - 0xa011a337, 0xb672637b, 0x2b761738, 0x724dcaf7, 0x2fba5ae6, 0x580dba66, - 0x0063b8df, 0x22d7ecfc, 0xb8bc91b7, 0xb37b1c45, 0x3aafd055, 0x2e4b7dd6, - 0x2fb333d9, 0xb87486de, 0x28dd6d79, 0x18f79bb2, 0xa49ff8c5, 0x81bdc6da, - 0xc49932f8, 0xbf7556bd, 0xc189ef58, 0xadb24072, 0xad0cc969, 0x59c75d4b, - 0xe9d77bcc, 0x774fcde6, 0x023d206f, 0x15c70736, 0xbefb1463, 0x34c4cb65, - 0x1d7030f4, 0x20475e56, 0x0b4d772e, 0xee91dd56, 0x1bc6847a, 0xf87c1388, - 0x7529d108, 0x75cbe878, 0xc43b943e, 0xdfb581f7, 0xbd23eabc, 0x042e29f4, - 0xae4df9c7, 0x475a71fb, 0x51902e93, 0x45fbf48a, 0x05007a2c, 0x9096be21, - 0x0f107398, 0x1af04e6d, 0x77945e59, 0x99f9ca36, 0x8b03172a, 0x4fc43c71, - 0x8b55cb99, 0xcc5422ee, 0x60937e6e, 0x16bdbba5, 0x179e686b, 0x724d3d68, - 0xe4f881b0, 0xc607e268, 0xc76e594f, 0xf454fe0a, 0x9eb6f759, 0xa288c6db, - 0xb2e4c20b, 0xaf89db69, 0x6f7486ff, 0x5071663a, 0x3e3c90f3, 0xe79c46b6, - 0x46fa345a, 0x5d09d395, 0x9c383e26, 0xc5a2f5b8, 0x07d26ed4, 0xb7a4d9bd, - 0xda06f727, 0xe81e7dc8, 0xc8463bde, 0x7fd7ea89, 0x7d8b9d23, 0xfc8cccf9, - 0xf9104091, 0x839c5e23, 0x8af4fc73, 0xad5f0738, 0xeca93de4, 0x788b7de1, - 0x573b8d54, 0xde2dbcf6, 0x6ff07985, 0x122bbd05, 0x713e967f, 0x6fc455e3, - 0xd48bef91, 0x6949b478, 0x7bd7a2b7, 0xf227ed37, 0xc51351bd, 0xbfc345a3, - 0xa27a6a37, 0xc8d1e396, 0xb9bd46f7, 0xb14afe4a, 0xa1f8a08f, 0xb436944b, - 0x87c70b3f, 0xf709af46, 0x35c9fab6, 0xd3952b0e, 0xc7d60e2d, 0xe10e3d57, - 0x6489e1ed, 0x9e5519e6, 0xd893ad97, 0x5af156bf, 0x49c9bcfc, 0x7e7e28eb, - 0xe8cdfb14, 0xe97b8bef, 0xde913e4a, 0x837bd012, 0x2cc189cd, 0xb9ba67ba, - 0xfe41df3b, 0x9d5a1ff8, 0x68430ff0, 0x503c6a7d, 0x4b54bf27, 0x2d8e87ef, - 0x3f0b38c2, 0xa679eead, 0xd5e58ccd, 0x1055e9eb, 0x13f384a5, 0xdf2aafc8, - 0xc6978329, 0xd543ef01, 0x39153b08, 0xc0e9a537, 0x188f8616, 0x0db008db, - 0x29300f91, 0x4fcd8bf4, 0x39c7d4d2, 0x4ff4d02e, 0xd4d2cca8, 0xf788c5b7, - 0xfa71e032, 0xef422a0b, 0x3f9d1248, 0x0083f4d1, 0xbd08adfe, 0x7e27b917, - 0x4f7e4eea, 0x3ce06fe2, 0x2565f245, 0x7926f69a, 0x5dfc4cab, 0x435ea5fd, - 0xa6529fcf, 0xb956f11b, 0x9c1cfd1b, 0xb69f4267, 0x01e0263e, 0x5bb317ea, - 0x984bc9af, 0x85f2da6c, 0x629e4a79, 0xe4d58c2c, 0x2ef10629, 0x61d8fef8, - 0x0545f31d, 0xbaaafce4, 0x006cf08c, 0x6f1a2daf, 0x5df840c7, 0x1c5ac6c7, - 0x426a96f4, 0xc932cbcf, 0x8b4baa41, 0xb5b351ff, 0xd6ed1ff8, 0x52cc7be2, - 0x9bd3be2d, 0xb0bef8b5, 0x4cd78b45, 0xd96f168f, 0xda6826eb, 0x346bdbdb, - 0x578dbce5, 0xe45fda68, 0x8f29a19d, 0x4d7af17b, 0x858ec2fb, 0xaee2fa9a, - 0x957a9ae5, 0x83e386cf, 0x11d5bef1, 0xdd03a6fc, 0x74a0f869, 0xf335cfe7, - 0x9ff450fd, 0x05e8a79f, 0x2bd7fe85, 0xf8dde576, 0xb892f7c3, 0x7a158b4e, - 0x50df3070, 0xee78e06d, 0x6d725b3d, 0xc505e91c, 0x7b14b9de, 0x894f3907, - 0x1d9455b2, 0xa2bf717e, 0x36ab9f64, 0x2cf746de, 0x8a8afdc4, 0x09b5edc3, - 0x1de23ed4, 0x494af4d6, 0xf91dde73, 0x67a66b2e, 0xd1209cad, 0x3f7144bd, - 0x841ef231, 0xdeab3efa, 0x2739a319, 0x96bdee1f, 0x78c25f9a, 0x2f148c01, - 0x3efccce8, 0x721fda31, 0x5fd9946c, 0xf6ffb373, 0x79cdc967, 0xfecc6ba7, - 0xecefe20c, 0x79f5eeb1, 0x3aa3b788, 0x3dfd8d87, 0x00d6fde5, 0x2fdf8c6d, - 0x3ca4ccf5, 0xbb8600e9, 0xdfd4d794, 0xbd2663b3, 0x5be5c45b, 0xac221503, - 0xe68f3fa6, 0x71a41fb9, 0xbbd6480e, 0xbbefb14b, 0x20cf3e13, 0x73a2667b, - 0xff3e12fe, 0xfc2f387e, 0xee147bfc, 0x406df50f, 0x79f0f367, 0x8e25cfee, - 0xc1a73e53, 0x77e4c2aa, 0x4f79419d, 0xb9b6e22a, 0xb8d4be0a, 0xff328e6d, - 0x29621c01, 0x5db9f3ea, 0xacbc667f, 0xe253eb48, 0x158766bd, 0xac71bfc7, - 0x7bef84a5, 0x221d4b39, 0xb8e357de, 0xb1f7f231, 0x87ba67b3, 0x88ed22b5, - 0x97869e26, 0x57cc8792, 0x42c5e646, 0x1fe316fb, 0x76cb1f58, 0x74fac0e8, - 0xc6863fce, 0x85f9ca3f, 0xfbdacdb9, 0x3e5bf3dd, 0x02dff0d2, 0xfa9a27cf, - 0x30d04a40, 0x781ff706, 0x1bd4f475, 0xaffd7f10, 0x9e282a98, 0xe4f5ba45, - 0x0fc68795, 0x897797dc, 0xb4ce1bf0, 0x1d79cfcf, 0x5afdcabd, 0x5bfb9f75, - 0xd03971f7, 0xefb8881a, 0xbfc4d1e4, 0x09fe342a, 0x0e8fc9f2, 0x431c234a, - 0xe76673e5, 0x57a9388b, 0xabda7779, 0x55ed3bbc, 0x2af689de, 0x957b42ef, - 0xbbeaa177, 0x9c095edd, 0x8e64bf74, 0x816a7ae4, 0x0f76efc4, 0x969b3ed1, - 0x5de88b07, 0x60715363, 0xbbf3249e, 0x7df423dd, 0x45bb7788, 0x69f49592, - 0x6ef435ea, 0xcf08f0f7, 0xd9d8b251, 0x50d789f9, 0x28d870bc, 0xc5f4a3e4, - 0x7bd2666f, 0xdd53c7bd, 0x3fbf89c7, 0xf31f6495, 0x9f12ebf3, 0x6033832b, - 0xef16719c, 0x13cbbf7a, 0xf32734e7, 0x0a89b9c4, 0xbd0be647, 0x9cb04a56, - 0x2e6f72e8, 0x68dabbbf, 0x385777e2, 0x7617539f, 0x7df2221f, 0x4d1fc95c, - 0x6a1fd23e, 0x5f2127de, 0xbbd3379c, 0xca675a39, 0x6ef126fd, 0xa0cfe02e, - 0x0f747677, 0xbdf245ca, 0x1de29c1b, 0xf0a6de5e, 0xf90930f7, 0x45bd3dca, - 0xb7a779a0, 0x7ec0e7b2, 0xe5af27d2, 0x53f393b9, 0x56c7ef43, 0x7f676fc6, - 0xc6df20af, 0x797ae2f3, 0xee17a8ff, 0xc79cfa24, 0x7e56617c, 0xd7fff479, - 0xf5bc3860, 0x5a3ff62f, 0xf77a1990, 0xaddef616, 0xaf2c3f20, 0x343faea7, - 0x42e5e9ce, 0xe5a97bcd, 0x93dd8f43, 0x7486724b, 0x5948f911, 0x88633f9a, - 0x05f3d3fe, 0x774feffd, 0x97f9a04d, 0x60bc8b37, 0x6fda6f88, 0xdce898f9, - 0x3ef21963, 0x723fdabf, 0xf5b72b9f, 0x9f703e30, 0x617f68f3, 0xf08cbcfb, - 0xbfb3eea5, 0x05a3ef7b, 0xdfdf73b6, 0x6e777df7, 0x6d71811a, 0x767950d2, - 0x7e613eb4, 0x3fed4999, 0x8fedaf56, 0xb1e5390e, 0xd1de48bb, 0xe254e96f, - 0xc4cbb21e, 0xee5daa17, 0x2920e254, 0x02ed83b0, 0x71724bcd, 0xfb61e4b7, - 0xda3be6a8, 0x947fb424, 0x61af7057, 0x685f217b, 0x775f1071, 0x49f9ef22, - 0x58cef41e, 0xc44773ce, 0x758b3fd7, 0xbc7844df, 0xa335aff9, 0xf2defe28, - 0x38942b97, 0x72abd84e, 0x69cb3f85, 0x4147da7e, 0x996df302, 0x730abeb2, - 0x55c9fb33, 0x5e4591e0, 0xac93c943, 0xdff1c1df, 0x141a01ff, 0x43d0aaaf, - 0x000043d0 -}; - -static const u32 usem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x1894738a, 0x18357a18, - 0x326b3618, 0x31686830, 0x20318830, 0xaf8568e4, 0x9fa65371, 0x8181959b, - 0x81f98817, 0xd7881058, 0x6c303133, 0xff5e2260, 0xfb045111, 0xc303209e, - 0x197f2051, 0x6614ee90, 0x64055860, 0x2fe2031f, 0x1080be40, 0x100c8303, - 0x606115ff, 0xc1d20530, 0xc4036c40, 0x9bf145c7, 0x7c80827f, 0xbf2a08bc, - 0x279f8d1b, 0x25ff5f8c, 0x0ff2fc11, 0xc363c808, 0xc7e41632, 0x7a052247, - 0x29370207, 0xca8ff2a2, 0x543c3033, 0x51d06060, 0x919bf082, 0x6280ede4, - 0xec21e4c7, 0xb8c09229, 0x28b5ca07, 0x2a773762, 0x5004fe50, 0x34894bce, - 0x41d3dcf7, 0x8434afe5, 0x3ebc00d0, 0x03a8e414, 0x000003a8 -}; - -static const u32 usem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xc5547c0b, 0x3d9cf8b9, 0x926eece7, - 0x2126cddd, 0x26c2bc21, 0xb80d4401, 0x41a00c40, 0x94520f37, 0xa2a1e1a8, - 0x24786c22, 0xf622ef21, 0xddbf1f62, 0x52c488f0, 0xd4c51f1b, 0xb051768b, - 0x40368bd1, 0x5c1758d0, 0x6d8b459e, 0xd5a045e8, 0x5e40137a, 0xa540b206, - 0xcffd45b6, 0xdd9ccdf7, 0x26364e73, 0xf6ffef6a, 0x9fdbfffe, 0xcccce61d, - 0x7cdf3337, 0x9be6bdf3, 0x91be6489, 0xf21387d8, 0x256efc25, 0x108951e4, - 0x9b4e1892, 0x9fc6933c, 0xedb10994, 0x3bea247e, 0x9e0c8499, 0xd146706b, - 0x64085fa2, 0x21064b4e, 0x758d65c9, 0x793dfa46, 0xe8bc7d91, 0x9819c308, - 0xbdbae47c, 0x720c8409, 0x8266f6d3, 0x7fe92fbf, 0xc637b73f, 0x79c87491, - 0xe131a285, 0xbc9a4afa, 0x877bfa48, 0x149bbeaa, 0x48dda675, 0xfd51fbfb, - 0x9085b720, 0x4678c31f, 0x40cba942, 0x78b8e8b2, 0xfd2e6f5d, 0xaf0e3a3f, - 0x295be8cd, 0x1c1a2210, 0x242444b1, 0xa0482326, 0x679fbe9d, 0x49d7ed3c, - 0xaa36a708, 0x49e74ac8, 0x0896b4c8, 0x808972f5, 0x76cd8878, 0x78e97b25, - 0xe22e7d57, 0x220d57bc, 0x27d69da4, 0x684ed392, 0x61c4953a, 0x232dc7bd, - 0xd57e4206, 0x07123fae, 0x199b1b85, 0xdc155e24, 0x0e210f06, 0xc7afc513, - 0x8f2ae98c, 0xc4c9a79d, 0xab210d71, 0x574c0e3d, 0xfa634679, 0xdb27d0d8, - 0xf9d00673, 0xe9d8320c, 0x63834848, 0x1191dda6, 0x2dc72786, 0x0938e730, - 0xae2926c9, 0x2f5a54c4, 0x4dc840d1, 0xf342dc84, 0x19082375, 0x5084ec49, - 0xbc933dfc, 0x019dca2c, 0x45e60779, 0x7cc37103, 0x2e033263, 0xc62de291, - 0x1c95cf69, 0x1bf8efe1, 0x785fdf80, 0xc1d6152c, 0xefcc1b7d, 0xf0ece219, - 0x46dd9e02, 0x7f5a26e7, 0x5e4ceca5, 0x468ae14a, 0xad832eda, 0x1e1094bb, - 0x1fc04cdf, 0xc9cc8fed, 0x30d7acd5, 0xb4224718, 0xeb05dc73, 0x75b27164, - 0x1574095a, 0xf2e61d61, 0x77655875, 0x38fd19d9, 0x11fa2449, 0xb1fa5aed, - 0x8fe96864, 0xba9fb17e, 0xbf69e79e, 0x3bed424d, 0xbd3ce953, 0x4dce0c4b, - 0xa160dbf4, 0x0af80051, 0x80c425bc, 0x41f92afd, 0x63a05265, 0x179e1ab4, - 0xf6f7e9cb, 0xefcf730e, 0x52e2062d, 0x2a5372e8, 0xcec4777c, 0x6626e3a0, - 0x6b4cec47, 0xe987f1cf, 0xc925d924, 0x4c0eef40, 0xac47041b, 0x477ce300, - 0x9c049b24, 0xf6a4727f, 0x08edd3ff, 0x377ae1f1, 0xda5475f0, 0x3d203c51, - 0x468b1f79, 0x3450883c, 0x17e70c39, 0xad17cf1c, 0x4a434f45, 0x5868e348, - 0x875f9a5f, 0x79a663f4, 0xb09be62b, 0x3fca1edc, 0xacc9e58b, 0xba5e5d3e, - 0x55e3bd18, 0x6eda1759, 0x4291c203, 0x38445e70, 0x9bbf5096, 0x94203f30, - 0x1fd625ff, 0xb7f7eaca, 0xceed251f, 0xf9c29e0d, 0x003b2ebf, 0xd6dbc29f, - 0x2e94adc0, 0x7c106e0e, 0xec0f9a26, 0x75fe418c, 0x9f0cfd7e, 0xd767e289, - 0xea0b9338, 0x8398df9f, 0xefedbcf9, 0x5e5a24db, 0x20945db5, 0xd679d86f, - 0x5bf141d6, 0xfc7f6a63, 0xb83dfa66, 0x602f245d, 0x9f71d377, 0x48b4e29d, - 0x92f9633e, 0xdaad9628, 0xc01e6bb0, 0x91336b2d, 0xeaa70a28, 0x6f3bd2cd, - 0x03d2f9a6, 0x552a8132, 0x838cea9b, 0x4f897e69, 0x8afc8168, 0x3f601f9d, - 0x0ca4b9dd, 0xe039f7f6, 0x752f945b, 0xee93dadb, 0x7dcbdfa6, 0x7ea00a5b, - 0x09c166f9, 0x7ebe5c4b, 0xbf0087d7, 0x211e55bc, 0xcd15f852, 0xdaa1c431, - 0x17db792f, 0xade309df, 0x9426477a, 0xabb291ed, 0x1891190f, 0xe02346a4, - 0x13d36ab5, 0xe79be046, 0x1fb0073c, 0x2f559f05, 0xbb687ed3, 0x2704d7ea, - 0xc0daad4c, 0x3785cdf8, 0x68bce6a3, 0x19d57981, 0x37fb4147, 0xbd42351f, - 0xebf15f52, 0xdf180e51, 0x8c016306, 0x6306fd73, 0x566f8a89, 0x3356ff34, - 0xe94d53ae, 0xbd19dd03, 0xce39e7af, 0x397c95b7, 0xdf484015, 0x4338cf92, - 0x339e87c5, 0x57fd21c4, 0x11c48b34, 0xdf781f81, 0x8760fbe7, 0xbe03f195, - 0xc0ed4b5e, 0x75ebc21a, 0x4fd7cec9, 0x88cd660a, 0xe71ee7c0, 0xcb91a3f2, - 0x7e41278f, 0x2e69f4d0, 0xf971d63f, 0xe271e4d1, 0x933d67f7, 0x71ef5d30, - 0x67bcfa61, 0x4f3ea61a, 0xc17bd611, 0x8dd30733, 0x7f7e371e, 0x698653c9, - 0xbf16a7b3, 0x8e59e2bf, 0x178f66e9, 0x59e6bfbf, 0xa78b6983, 0x9eadd311, - 0x3d5b4c26, 0xbaf7ac3e, 0x36d319a7, 0xff7e0b4f, 0x530da7b5, 0xe98027bf, - 0x9a5f584e, 0x98ed3c06, 0xc31cf6ee, 0x03a7af74, 0x9cf7eddb, 0xc72d74c1, - 0xe49b2dbb, 0x366f1448, 0x18394117, 0x91cae85f, 0x88be3e69, 0x7ae693e5, - 0x9f348c73, 0x8a79a6e4, 0x8195c1c7, 0x0fcd131c, 0x29e565ae, 0x66b9243f, - 0xb2f14f9a, 0xaeb5b4f2, 0x4f9a28dc, 0xa3e5646b, 0xa3737bd6, 0x8f947e69, - 0x39b75f95, 0xf3431b90, 0xf2b0b5d7, 0x67927eb1, 0x01b1f9a1, 0xd07f1f96, - 0xf9a56795, 0x9f2cedf1, 0xcf37a1f5, 0x1d59f346, 0x5d4dfdac, 0x9a58bc81, - 0xcac829bf, 0xf24ab96f, 0x2e4003ed, 0xb5cf980b, 0xd1c7e4e4, 0xe59dae7c, - 0x4b16860b, 0xb7f4088e, 0x0858ee53, 0xb0867c22, 0x7e5125d1, 0xf1d8d3b3, - 0x647d1510, 0x4baaf0a1, 0x2033fca2, 0xfe504593, 0x963af0b0, 0x19648c07, - 0xbc2a3f94, 0x65bbe58d, 0x5cff9607, 0x46f2c038, 0x87ff9607, 0x7bf30870, - 0xef961765, 0xf2c4fe10, 0xff961746, 0xf981385e, 0xcb1bb2fd, 0x962e853b, - 0xfcb1ba37, 0x5753e949, 0xdf2fed3e, 0xdc2e9ee0, 0x5ddb7208, 0x6a597286, - 0x597e0649, 0x04fff9cf, 0xaf2d0640, 0x3944641f, 0xacf3f3b8, 0xd3814517, - 0x97c800f6, 0x05fa04bc, 0x485b3385, 0xc2827d04, 0x7386fb11, 0x349317cb, - 0xa2f96e70, 0x20f3814c, 0x1fea89c2, 0xdc5f9d9c, 0x17cf1da4, 0x129c0ae5, - 0x7fb5979c, 0xcbe5baf3, 0xbe78ed6c, 0xd4e054ac, 0xfeb89c20, 0x4f20278d, - 0xc809c0d4, 0xe59c0aa5, 0x7fb12708, 0x271971e3, 0x8cb8e06b, 0x7538144b, - 0xff506708, 0x378c04e0, 0xac63c76b, 0x863ce050, 0xbfd61e78, 0x534cb979, - 0x5531e3b4, 0xc29e7029, 0x0ff6a4f1, 0x16ab6ece, 0x21adbb3f, 0x3847acfc, - 0xaf37fb23, 0x3f169b5c, 0x7e10b6b9, 0x6b9c2136, 0xb76707fb, 0xdd9f8b4d, - 0x5e7e10b6, 0xe98cfc43, 0x6372bcdf, 0x8dc9f8b5, 0x0de7e10d, 0xfeb8cf1c, - 0xa26f678d, 0x137b3f16, 0x2009f843, 0x37fb1b9c, 0x2d24fc9e, 0x4293f27e, - 0xe10779f8, 0x9c1fee4c, 0xfc5a49bd, 0xe10a4dec, 0x67080fe7, 0x95e6ff4a, - 0x9f8b503f, 0xfc2181fc, 0x7270807c, 0xa94ccddc, 0xbdac70a4, 0x4c3fd9c3, - 0xc3fd9f8b, 0x8939f842, 0x3852a670, 0x29c37de9, 0xa7e2d148, 0x9f842520, - 0xb6e708f3, 0x9fd9c1fe, 0xfecfc5a2, 0xae7e1094, 0xfa3b9c20, 0xe182af37, - 0x0c14fc5a, 0x55b9f867, 0x8672871a, 0xd8274eca, 0x9a19dfe7, 0xc13212e3, - 0xd179624e, 0xf7a024ee, 0x433e8a88, 0xad225dda, 0x371cd96f, 0xd6a231fe, - 0x068d726b, 0xaa56cf4a, 0x9af5a9e5, 0x1ad149d8, 0x15ce2a3d, 0x4c27c9af, - 0x9fa9ac1b, 0x29a69458, 0x3ae7381f, 0xf720f94d, 0x487e4d78, 0xfa9a4dd9, - 0x35736ac3, 0x6fcbe1f9, 0xf54fd4d7, 0xd3e4d4ce, 0xa9afdcd7, 0x8171b23f, - 0xa69afca6, 0xb5f94d72, 0xfc9aa5be, 0xd7dfcdf5, 0xb2d31fd4, 0x437e5342, - 0xf29a63db, 0x35278171, 0x9e0709f9, 0xb1bfd4d5, 0xf94d05fd, 0x68af63c4, - 0x6c7727ca, 0x3e6fe4d5, 0xfd4d6bf3, 0x9addc129, 0xbd9fadfc, 0x439fa9ab, - 0x6fab53fe, 0xd4d03f9b, 0xa13f6a9f, 0xf24eff29, 0x553d3a27, 0xccaf1f6b, - 0x32afcc21, 0x01afd988, 0xc6f311ab, 0xa76616c1, 0x271c4b58, 0x7718fd29, - 0xa00c742f, 0x033403f4, 0xe0ce5176, 0xe83a6bb2, 0xe4ddeff7, 0xbf4ec6be, - 0xbee8cf7f, 0xbf411ec1, 0x9026f4a1, 0x061d4864, 0x8fe5f548, 0x73de8cca, - 0xd51d5c87, 0x18d7db49, 0x68e2a382, 0xe73123fe, 0xf9c7a03e, 0x83ee0306, - 0x42d49168, 0x411368bd, 0xd4d1e9bb, 0xaabd17ac, 0x1866b0fd, 0x308433d5, - 0x3bb235dc, 0xc328f519, 0x9bd03af8, 0x79d187ea, 0xd164260d, 0xbcbb718a, - 0x61fb6823, 0x8fe0c925, 0x3f991930, 0x91bfd424, 0xfd819ff6, 0x6bfe812f, - 0x94dfe97a, 0xbfd34936, 0xd34ca539, 0xfb48d9bf, 0x90f213b7, 0xbfde26e1, - 0xcb36fd19, 0xfec64c56, 0xd865294d, 0x6a46a3ff, 0x8ffba977, 0x88fff50e, - 0x31ebf681, 0xc7b9bb30, 0xd26ed3fc, 0x5ca53fce, 0x9b237f3b, 0x2e434aff, - 0xe71a3fef, 0x0e456abf, 0x394a7f9b, 0xc189bf9b, 0x0b6ff50d, 0xfa01bfe1, - 0xfd2f69ff, 0xb5b3d29b, 0xa95e1ff3, 0xf589bf9d, 0x76e194ff, 0xfb05bfde, - 0x6dc57a7f, 0x2bc3fe6c, 0xc9a37fb1, 0x31fa04ed, 0xf5ae890e, 0x50c9fed1, - 0x040d256a, 0x40fda172, 0xfd1e3a3a, 0xd21a7708, 0x8bdf1c70, 0x2576f466, - 0xf21bd29a, 0xc3b32f33, 0x5273947d, 0xd39aaabb, 0x1ce6c57a, 0x2c3df023, - 0x3164224f, 0x36a2ea1f, 0x3c9be911, 0xa48df26d, 0x26d0bde3, 0xe8bf217a, - 0xe03e29e9, 0x322635af, 0x49da08bf, 0x3fdf0024, 0x1798d9fe, 0xa7d2f3d4, - 0x53e51b8b, 0xde45fc91, 0x96ba325c, 0x1002ef8e, 0x9c7f2a81, 0x186071da, - 0x1eed487f, 0x139fed42, 0x23efeb32, 0xbe41ef6a, 0x687bda83, 0xe63a9338, - 0xdebaf357, 0x5fc7411f, 0x0b9f9444, 0x6e2f79e7, 0x624f0a29, 0x5af8f7fb, - 0x31eb07c1, 0x450c797f, 0xc53c787e, 0xbe4d04de, 0x07eac4c6, 0x2f7c136f, - 0x0dc30808, 0xe1c199f8, 0xcd2f1811, 0x36b3b1cf, 0xb1de7747, 0x7dd1b05f, - 0x5d0866b4, 0x599c308b, 0xa40f25c4, 0x565eefed, 0xa76b832c, 0x8186105d, - 0xa166b09f, 0x3768024c, 0x0649137b, 0xde3a0e27, 0xfe0cedfb, 0x527c970c, - 0x239b47ed, 0x74455d9b, 0x458a733c, 0x69acff1c, 0xed3ff2da, 0xc619718c, - 0x53cd74d2, 0x45ddcfd8, 0xe77bf2da, 0xb9f7f368, 0x572a79b5, 0x0fab9065, - 0x53bfe994, 0xdf8124b4, 0x001bf431, 0xe3907ce3, 0xd95ac1e1, 0x6a5759ab, - 0x72951b76, 0x09b88470, 0x8bdb0bce, 0x5fcfeb3d, 0x7b17cdae, 0x6b85f9b5, - 0xdd39f074, 0x7febe29c, 0xa683e81c, 0x283e81a7, 0xfa724f3e, 0x2d55f308, - 0x9a13dc7d, 0x650fa306, 0xb624a71e, 0x33d6a704, 0x18dc58fa, 0x8a1e9913, - 0x52e0f443, 0x0f4297d3, 0xfc3d38f3, 0x6943d399, 0xeeae9693, 0xc9d5be23, - 0x6b03fdb4, 0x1d3ae177, 0x3d198a11, 0x87a140fc, 0xb83d0d0e, 0xd7e83d39, - 0x87a71e6f, 0x7a308f79, 0x0767afd0, 0xa68e87a7, 0xeb4932cb, 0x1d74aeb9, - 0x0eba7934, 0xa3b775ba, 0x47ae8a1f, 0x10587a44, 0x389d379a, 0x65e42fcd, - 0xd38bd63d, 0x01a79603, 0x09e209da, 0xacf7a7db, 0x2684f94f, 0x7914da5f, - 0x36da6bfd, 0xfaa93dac, 0xf2f2d55e, 0xbb7fb55a, 0x268b79a2, 0xa6f7c4bf, - 0xd3697ea6, 0x717e4d2e, 0xfa9a3be3, 0xd21cd70b, 0x7fbd8be4, 0xbf9fd4d4, - 0xfe5353bc, 0x4d59ed60, 0x176503f9, 0xdcfbf935, 0xbfd4d37f, 0x13f08e77, - 0xa2eefe75, 0xeba89fa8, 0xa7169acf, 0x0d70cfc9, 0xec37d4d2, 0xa02ef6bc, - 0x8bef83c7, 0x4f8ff404, 0xffd1a79d, 0x7653a9f9, 0x1e939d42, 0x5383ee07, - 0x9e98d19e, 0x9f7138f1, 0xc24cf39c, 0x1edb42f4, 0x2a15c80b, 0xc8e04b47, - 0x96e574a6, 0x20d935ba, 0xdfca09d7, 0xd46f958a, 0xb2128779, 0x8a639414, - 0x2326c2ef, 0x44204c09, 0xc7c4e100, 0xe5551415, 0x37947d1d, 0xd0914151, - 0x23b0bcb3, 0x279af7f2, 0x23db878b, 0xf7847f9c, 0x7a021935, 0xe72f7752, - 0x29029524, 0x64277f52, 0xad81f205, 0x34a94f5c, 0xb9517e32, 0xb12e5075, - 0xaa303e41, 0x6bfaabf6, 0x206c9ba1, 0x66ba49d0, 0x5d36973f, 0x04f7e1af, - 0x4089cfbc, 0xdf34136f, 0xd66f9a2b, 0x25daebb4, 0x81abb8e2, 0xfdb95097, - 0x527a292a, 0xd8153e04, 0x0c6b3293, 0x14f5d38c, 0x5112dbe6, 0x34f2ec8f, - 0xc7f385af, 0x4c169e73, 0x30da78cf, 0xac09e53d, 0x93c07385, 0x1e98039e, - 0xda63b4f7, 0xe98639e1, 0x4c0e9e47, 0xc19cf43f, 0x209e4ff4, 0x9f3cc7a6, - 0x43c47a61, 0x0e70027e, 0xfe98cc7b, 0xb4c763c1, 0xe98c93dd, 0xfb0f8f05, - 0x5f5df651, 0xcb867774, 0x7f4073ed, 0xbb6ce811, 0xcd6eac78, 0xbd9d30d0, - 0xa423f2b9, 0x85cf0533, 0x0f4e264d, 0x087a1a49, 0x2377ed80, 0xe51f4bd0, - 0xc3a7324d, 0x2e47dade, 0xbfe179af, 0x7caede87, 0xd30b7a4b, 0x3d1d10d3, - 0x4f45f7a5, 0xe9e9aa1f, 0xe4cec18a, 0x1fa7a720, 0x7d6b73f3, 0x3b1251bf, - 0x77e90ca7, 0x800cdbae, 0xdcfca5aa, 0x98699084, 0x5efbc4bf, 0xa3b5c149, - 0x0d1be81e, 0xe8d2eb72, 0x73828fbf, 0xe8c74b87, 0x3ef6a7e2, 0xf49d3d3f, - 0xda17778e, 0xba3e2543, 0xc61109e8, 0x1af0cd1b, 0xc8d32065, 0x461a4278, - 0x905ce4be, 0xc4897981, 0x739f7b43, 0x3af38446, 0xc06b7542, 0x5d785f6f, - 0x1632bd69, 0xf67a9de0, 0x5e90591f, 0xf475fae1, 0x7cf5111e, 0x09d17812, - 0x25c90df8, 0xfc193393, 0x4691c1f3, 0x6409ea3b, 0xde7f16ba, 0x6bf835db, - 0xcfce5548, 0x7f11931b, 0x1a8cae23, 0xf5fc0fd4, 0xc2fbdfc5, 0xf79802e7, - 0xfb3e037f, 0xf17d8fe2, 0xbc72e245, 0xdfe746d6, 0xf8cc73bd, 0x07c01cc7, - 0xcadf1abf, 0x3c7e9c79, 0xb5f492f9, 0x493bb8e8, 0x14f6e3a1, 0x24d85b88, - 0xa5fe11da, 0x61626bd6, 0xfa70425d, 0xede14f58, 0xbd80a73f, 0x0b553e7f, - 0xef074b2f, 0x6d1781d2, 0x4d2d7760, 0x3270d85e, 0x69283ac2, 0x835d4b55, - 0xb687ad45, 0x1a97f369, 0x382d6985, 0xecec472e, 0x6a272031, 0x5edf181b, - 0x6702a98e, 0xf6097269, 0x3d39ae73, 0x3e7bd996, 0xc7360fc6, 0xe738bf21, - 0xfffac329, 0x06f4f1ec, 0x210f1947, 0x1984e4ad, 0x4b2d31f8, 0xaf7ebdef, - 0xc5fd2cf4, 0x7edde788, 0x89e80af9, 0x97dffa66, 0x09107760, 0x9adc0af3, - 0xba6bd116, 0xd66fbe01, 0x39db47f4, 0x2fe23394, 0xdf6abed3, 0x4294e448, - 0xd45e54b7, 0xe780bd83, 0xd41a4b9b, 0xcb55597a, 0x9af93577, 0xd41a47b6, - 0xfc055c7a, 0x525ff283, 0x3740482b, 0xba8c9c95, 0x811acb25, 0x8218af8e, - 0x088f804f, 0xb9955eac, 0x9fa6e8c3, 0x75b2b7ce, 0xe77c6deb, 0x8854e63c, - 0x3733283b, 0x597239e2, 0x20f9b5cb, 0xaeb7ce67, 0x5bf9024c, 0x5efa5e21, - 0xbff68451, 0x5f2e0494, 0xcf56a0e4, 0x2841f4e7, 0xe9bcd55c, 0x17c212cf, - 0x981977cd, 0xb70f465f, 0xbe91cb8d, 0xf9bd53f0, 0x8ecdc150, 0x6eaa789e, - 0x237468bb, 0xcbffa45f, 0xc149e30a, 0xd454b15f, 0x9771d126, 0xffa27737, - 0x1dec8ce2, 0xe0af83f5, 0x67e73d97, 0xa3153e49, 0xb497979a, 0x260b3f43, - 0xe3888ef1, 0x1f280fde, 0x995bfb3f, 0x57221f00, 0x742cad69, 0xc7bb70cd, - 0x61590c40, 0x6b4167bb, 0xfbe02145, 0xd1d3ebec, 0x8a445bee, 0xa40eb86c, - 0x9cec0b31, 0x7180c4f3, 0x1fc9e755, 0xeb54136c, 0xe464b1f0, 0x305ca678, - 0x1034bb89, 0xd8107bbe, 0xf539a65f, 0xf858e2ed, 0x9076292e, 0x15ca25f0, - 0x17f180b7, 0x2f77d873, 0xfd01d731, 0x634a7b52, 0x4a7b51af, 0x94f6a793, - 0x66425f26, 0x453c4126, 0xf132d3c9, 0x4d278809, 0x8ec941f9, 0xb5252be3, - 0xfd1fa0f5, 0x16e1fb9c, 0x843489d8, 0x37aa87ca, 0xa62acb9e, 0x9892e9f3, - 0x0f894bff, 0xc5654258, 0x5e5e5a20, 0x2cba33e6, 0xa277e73d, 0x943dc275, - 0x163c03f3, 0xd1bf7007, 0x886be2c7, 0xaae2ca43, 0xf3ef5a4f, 0xba2ad81f, - 0x8f506ca2, 0x9bc6577e, 0xafe7f5fa, 0x4f212f9f, 0x9bca3ce2, 0x561c6067, - 0x3e07788f, 0x7059b91f, 0x27ec22f9, 0xf1341651, 0xc332092e, 0x1ad7e29f, - 0x0f5fcbae, 0x6bdf9579, 0x1bfcaea2, 0x440197f3, 0x258a5fc3, 0x913970f7, - 0xbfc013f1, 0x7f710520, 0xc9f8637d, 0x2f5fe03d, 0x844ff8df, 0xefbb543f, - 0xff89fc29, 0xe88ff1d4, 0x48bcfe31, 0x78deabf0, 0x778875f5, 0xcfd5ff2c, - 0xb7ee846c, 0x926352b3, 0xe57bae93, 0x1736d5a6, 0x6bc91df0, 0xd6717d83, - 0x448b4e27, 0x7997df0f, 0x59711fdc, 0xc2bbf004, 0x73fc293f, 0x4ef8fcaf, - 0x6caea3b0, 0x4fe8ed92, 0x4c05366d, 0x5bab9e94, 0xb1921497, 0xf964ef98, - 0xfd022f47, 0xc7c9b4d7, 0xfe5a74d5, 0x41259fcb, 0x94a5107c, 0x48648621, - 0x549f6803, 0x00b8fc6f, 0x121a8df4, 0x6faafdc4, 0x167ffd07, 0xd8b0f28f, - 0x1cb3db18, 0xd049341d, 0x5a6afd9e, 0xb4517c7f, 0x69db7a41, 0xb2d46fe0, - 0xbe90bf44, 0x3bb7195d, 0x00eb642a, 0xc913abe4, 0x0aabe044, 0xd98f885e, - 0x7e5f2b1d, 0x1d276c66, 0xdfc6d757, 0xbe1504da, 0x52e97b14, 0xfc5fc2cb, - 0x1f3bd1da, 0xa3f740bf, 0xe455bf5a, 0xdb8da394, 0x56967e4b, 0xc41b01ca, - 0x906e5573, 0xb9fa5e9d, 0x5f17d5f2, 0xd9fc167a, 0x4739347f, 0xaf15f852, - 0x13723bee, 0x916c57cd, 0x69b21407, 0xf0a48458, 0xffd0d4fa, 0xaf0f8f96, - 0x7db6f947, 0xf618c746, 0xe1f187fd, 0xb2d8a975, 0xf4c648cb, 0xcb5e47c4, - 0x2587632e, 0x74b4fac2, 0xb7fe8016, 0x1abfe5f2, 0xdd9def81, 0xa9819029, - 0x61b9f011, 0x8087ea1f, 0xbe4f5c27, 0xd3f5a15e, 0xeba1afd5, 0xbf467202, - 0x857afa5e, 0x5c00bf9c, 0xf4a1b388, 0x21afdafd, 0x264fee0e, 0xeca1e027, - 0x306c87b5, 0x2d52d39f, 0x56e7f3a3, 0x2bbf0127, 0x7649bd93, 0xb2f7d94c, - 0xfa461fe7, 0x70f43d2b, 0xba57f312, 0x76501906, 0x3cc1077a, 0x1bbfaf17, - 0xdc4259e7, 0xcf658748, 0x9a3e4589, 0x69912a7e, 0x93ec225b, 0x9c9f7c4b, - 0x2e2e817e, 0x4569e79d, 0xe441fc2e, 0xe8bbe172, 0xcf987d0f, 0x98906a85, - 0xd6ccd4ff, 0xd06c80eb, 0xfd10d1c8, 0xe5147c6e, 0xae61b9c7, 0x56ee7081, - 0x28179613, 0x5343c447, 0x6275b207, 0x51db0772, 0xdf0793b9, 0xecbb7ea1, - 0x69ab1a8a, 0xe9467287, 0x9fef197f, 0xf41a3b8e, 0x9149d3b7, 0x46e191ed, - 0x3d500f85, 0xaa674543, 0xfff6cefd, 0xdfb606c6, 0x9beffd95, 0xffca0d31, - 0x23ed9872, 0x97720768, 0x10302b8e, 0x16cd77cb, 0x48983f90, 0xdf3ed220, - 0xae7df328, 0x0bd3d72d, 0xc424bf1d, 0xfa06e8aa, 0x4075c789, 0x34f25f79, - 0xa3e2af6d, 0xadafd035, 0x1f655c27, 0x707e7297, 0xf5c1f81e, 0xd6407e61, - 0x5e2bf627, 0xbdf652b4, 0x5fec2cf4, 0x0ebd5fba, 0x1172bfd8, 0xcd93ffcc, - 0x4fdc8e7b, 0x2d27edf7, 0xf2d5beca, 0x2dbefd55, 0xc630fadb, 0xedf7eb9f, - 0x496b4327, 0xbf4b7dc4, 0x43b7dc47, 0xf847fe3b, 0x24c782aa, 0x2aaf96a3, - 0x7c37b27c, 0x16e4f9ea, 0xd57881d9, 0x3bfa49f3, 0xd27ab24c, 0x0a8742a3, - 0x47ff95fd, 0x47e070d5, 0xe8553a21, 0x0aa74430, 0xade7ea1d, 0xfcbea3c5, - 0x522df023, 0x537a297a, 0x4a95f3c6, 0xa6038b3f, 0xc90ff6ed, 0x50b97c44, - 0xfdc691cc, 0xf3a80643, 0x45be5d3e, 0xcba5df57, 0xbbeae917, 0x4d5af975, - 0x3db6cafd, 0x10748246, 0x9713d4d0, 0x31393bff, 0xfadd1221, 0xf5a1bf98, - 0x39ee11a2, 0xd88258d4, 0xbc415e5e, 0xdc191f10, 0x51b9e221, 0x3d71c537, - 0xa73637f8, 0x8f94bcfa, 0x7e628eac, 0xd07b6e85, 0xd5d34f16, 0x4c1f2c71, - 0x1f03d634, 0xa307be54, 0xbbb1df98, 0x538b6828, 0x7e9d5bd9, 0x8778f911, - 0x0dbdf22f, 0xdd70692a, 0xd7b97a3b, 0x758f9ca1, 0x62c6db47, 0x3e29d17f, - 0xa2a9c7a0, 0xf8396525, 0x27451aa1, 0xea8bece8, 0x79c1b5ee, 0xfd3fb755, - 0xfbf439ae, 0x164477e2, 0x4975e38e, 0xd0765483, 0x975de219, 0xf05c402d, - 0x859fa45a, 0x2d17667e, 0x3f791b5a, 0x2576f394, 0xe0466596, 0x390ed4bb, - 0x51ef3eae, 0xd7ad94e0, 0xe74ff77d, 0xed11a6fb, 0xda8df2ff, 0x9fb73772, - 0xfce4647f, 0xc7191c67, 0xbfe657ed, 0xaa7b7ce1, 0x1cd77198, 0x07dd3eba, - 0xf9a26244, 0xd7117e4b, 0xc166d2e7, 0xe237fe07, 0x57fdc44d, 0xf546824d, - 0xd82e887d, 0xcef4d75f, 0xffb6bac7, 0x4007eb39, 0x307faf47, 0xda69dff6, - 0x471ffaf5, 0x37f905bd, 0x407ca68e, 0xdbcfd67a, 0x02f18519, 0x48ad3bdd, - 0xde3bddff, 0xe401f94b, 0x613934df, 0xff3bdd9c, 0xa9e8163a, 0x0ca9857b, - 0x30f760f8, 0xb95dbfe6, 0x3b63afe3, 0xc2aefe50, 0x1a366c75, 0xffc99f99, - 0xdee08f8f, 0x9d3f25c2, 0x3c17e815, 0xd7e6beae, 0xf0823e51, 0xbea59aff, - 0xe76df40f, 0x43e3cd53, 0xce64adba, 0x1c5f1856, 0x79a87f8b, 0x758bf26b, - 0xd6aaffb4, 0xb485c65d, 0xcfedef3c, 0xfd1c62c7, 0x5d37a656, 0x879e3b90, - 0xc66d87f8, 0x2994acef, 0x26c02f9e, 0x5df646a3, 0xb07935a6, 0xe5e27a8f, - 0xf5a7f473, 0x1aef1f17, 0xaffd7d99, 0xc5c10f8f, 0x67d59ff8, 0x7fde6016, - 0xf403e8fb, 0x2e909a83, 0xd27ef995, 0x4cfa8752, 0xfb3ef35f, 0xfa0e86bf, - 0xd0216f3b, 0x4d9b799f, 0xfdebdaff, 0xeb81d1b8, 0x3d07dfa2, 0xf7c77ce9, - 0xd5aaff30, 0x27ede389, 0xfd368fbd, 0x5beeb63f, 0xfadbbae9, 0xfe77f79e, - 0xfbdde7c5, 0x8f33bfba, 0xce1dbbaf, 0xfede6b53, 0x75f7c71c, 0xffe95cf9, - 0xf457ba52, 0xad4376fd, 0x6f8e933d, 0x82b4690e, 0xe25f7162, 0x03a64b25, - 0x0f2f70a2, 0x383bf8c0, 0x57608d5f, 0xbf989935, 0x581824cd, 0x82dddabc, - 0x3b4447e2, 0x5fae4eeb, 0x0cb439dc, 0x5d3b90f5, 0x827d413f, 0x39edb548, - 0xee7b7eb4, 0x6ac62742, 0xdcc7f192, 0x853d9f90, 0xe6f6b5e7, 0x12e204ef, - 0x677f7ea8, 0xa003f4ee, 0x12e5dee7, 0x29a60f51, 0xa7efbfea, 0x93efb014, - 0x7dd0f6b4, 0xdefe6d6e, 0xddfcda39, 0x843dde1c, 0x229eff8d, 0x587e07c1, - 0x8953ce53, 0x2d3597e0, 0x0a908996, 0xabb54671, 0xbbb8eec1, 0x197edb48, - 0x7f2a6728, 0xe3c537e3, 0x5c78436f, 0x3921788a, 0xed03de22, 0xdc7c8f13, - 0xf9c7b3ed, 0x489ace20, 0x7bc7864e, 0x37e89caa, 0xccb8f6e7, 0x3596cbdb, - 0x659fb0ed, 0xd8ae1d9d, 0x9be1bdd3, 0xe11cfb70, 0x2ff185a4, 0xcfb444bb, - 0xae7d9d65, 0x5dd7cbac, 0xbf1d650f, 0x073cbaed, 0x786372eb, 0x5c5a865d, - 0xccabf604, 0x8b7c87ed, 0x1687e593, 0xe8ae7611, 0x00d2fac3, 0x8466f117, - 0x9897d1e3, 0x9ce02b8b, 0x405a3ccc, 0x6b5dc87f, 0xe60f9445, 0x55c7010c, - 0xf8c64934, 0x450d8fe3, 0x85deb059, 0x7f562613, 0x09c30d9f, 0xf1c25cf8, - 0x516a425e, 0xbf57257f, 0x0b3b32fc, 0xea0825ce, 0x845c4bbf, 0xb8ed41dc, - 0x10216c92, 0x126af10d, 0x078ec6f1, 0x8e40b93f, 0xdae4fc6b, 0x496efc3c, - 0xabe9c30a, 0xe5fc6f7e, 0x17fe9d9f, 0x29c767e5, 0x3a427491, 0xd497bb12, - 0x3f7cf776, 0xa54d63c3, 0xba434be0, 0xfbeac80b, 0xb66605d3, 0x87ebfe0f, - 0xe64f9013, 0x2c4c74fc, 0xe26407f3, 0x6e1ac47d, 0x3af25c37, 0x760fc162, - 0xcfce9fc9, 0x6a6cf373, 0x87a4aabe, 0x9ffe1db8, 0xd3489710, 0x51a17cee, - 0x048b3b04, 0xcdebffd1, 0xc57bc28f, 0xcca376fa, 0x6bafbe06, 0x3f002fd1, - 0xf2afee11, 0xa6d29479, 0x75aaf1b1, 0x59c77b5b, 0x75cf6c69, 0xd571df80, - 0xc5b7ddf9, 0x80fdd82f, 0x1d5143d7, 0xe6114505, 0xafe3893b, 0xf0dff770, - 0x7f4ceafe, 0x99780caa, 0xce6a2f99, 0xee669df9, 0x264098cf, 0x770ab8c0, - 0x0c9b66df, 0x744072eb, 0x1ad57dc2, 0x3ba345ff, 0x1eb1f9c2, 0xfc1f009f, - 0x676427f0, 0xc4f3e009, 0xd808a24f, 0x73f1efd5, 0xcfb80cc9, 0x1eae8191, - 0x731df817, 0xb84fcccc, 0x74c76cce, 0x9c8e6156, 0x68cdfb48, 0x50838fb5, - 0xfebcc1b5, 0xcb03b33a, 0x4a76f087, 0xac95c1bd, 0x5ed1a75e, 0xbffe691d, - 0x79f8128b, 0x937bf399, 0x75bd7f84, 0x35a9f9cb, 0x41fa0b90, 0xd167e2be, - 0xfdc135d3, 0xe09a6971, 0xf60df903, 0x050be630, 0x53de1fd4, 0x64cfafee, - 0x7ba15672, 0xcdab9e3d, 0x1e02f7da, 0x887f78e7, 0x678287d3, 0xf1fabf05, - 0xbf29f52a, 0x9fed55ba, 0xdc6dabba, 0x54dfa06b, 0x81bb05fb, 0x3a96aa82, - 0x6b0fb08c, 0xe1909eda, 0x073ee67c, 0xa2a44b83, 0x83f8eab1, 0x0f166675, - 0xcdfc67b2, 0x2e4e80f3, 0x2c8135af, 0x1745ae24, 0xdf87c06d, 0x0f7f3833, - 0xdfde6c71, 0x57d36489, 0x3c0fabf0, 0x597cf2f6, 0xe715370d, 0x4732ab33, - 0x03da7706, 0x81e4bb95, 0x675a7a2a, 0xe572c78e, 0x074ae0fb, 0xfb420fbe, - 0x1f7871c3, 0x4fb81137, 0x8ed2d192, 0xa81f6cf7, 0x5874638d, 0x88cbb2d6, - 0x7bcd54f9, 0xfa3f4a22, 0x50bb34fd, 0x30bcaf1b, 0xe02863af, 0x5814d0a5, - 0xa7408ce6, 0x7394a393, 0x2729afca, 0xc76e945c, 0x27247ffe, 0xa2722996, - 0x95e3e303, 0xe7df02f6, 0x3031392a, 0x5a589c92, 0xeb0818e7, 0xfa4774b0, - 0x4b24d840, 0x149a99df, 0xefbc4e49, 0x47cce761, 0xeef67df9, 0xdc4e54d9, - 0xb31392a0, 0xf44e90a3, 0xf6513eed, 0x42725f49, 0xcbffb759, 0x907de6fc, - 0xf7f61113, 0x71393a17, 0xe518bf8f, 0x45b33dc4, 0x4facbdcd, 0x391394fb, - 0x5e61f749, 0xa044c676, 0x7db9f79f, 0x0bdf9473, 0x5e407e80, 0x11d94664, - 0xd1b97a6f, 0x53ff5f1b, 0xfffaf97f, 0xbe159e10, 0x3fda94be, 0x7448d4a6, - 0x979e9048, 0xbaf947de, 0xf8c8f400, 0xb907d2fa, 0x67c7539f, 0x66cf808b, - 0x6b2cf9aa, 0x7266ed5f, 0xf52da6a1, 0xfcb4b999, 0x09d946fe, 0x30fef2a2, - 0xf352cddf, 0x5ea8ccdd, 0xe3196ef8, 0x13fd97bb, 0x6dea7f50, 0xfce67f7e, - 0x11b3f296, 0x31f408ce, 0xe68c6e67, 0x7189dede, 0x06d8c9bf, 0x113de5fb, - 0xe63f79cf, 0x71c1c07a, 0x7d04c9bf, 0x9e3e49fa, 0x2f3d7c79, 0x3e794878, - 0x22de5fc5, 0x6d574fa6, 0xd57f1116, 0x57ff6cad, 0x073e0b37, 0xff8c17cd, - 0x56d79e1b, 0xb5e760ec, 0x39850674, 0x78aff5aa, 0xce1ea3af, 0x08362a09, - 0xf70cde78, 0xa59f001e, 0xce259f1c, 0x29573c0a, 0xc1fad26d, 0x2f6da21b, - 0x1e101b90, 0x78abc3fa, 0x105342fd, 0x7f0a1dcf, 0x20373829, 0xabb6d49f, - 0x59fb711a, 0x9a2a4fb0, 0x0d9ddf75, 0x3704ae78, 0xadaf41d4, 0x7b96d16a, - 0x8b17bcf8, 0x146d8c81, 0xb33df93e, 0xf778f4f3, 0xf653f1e8, 0x8873f12d, - 0x9ff327e2, 0xfe259f87, 0xf05e785d, 0xc7a2f175, 0x3f145d47, 0x324f181f, - 0x6c7e3f61, 0xf17f2170, 0xbbe22bbe, 0x189e8b4e, 0xe50f79a9, 0xef2f1ca7, - 0x83f5dc19, 0x80b55ea0, 0x6fd74af5, 0xf34497d9, 0x38c85b73, 0x6d286638, - 0x90e3cad2, 0xa0756ffc, 0xbb5b9f7c, 0xdab88045, 0x60befcc5, 0x7c09ef99, - 0xe5c1e63f, 0xfad3de54, 0xdc9bc70b, 0x287e5e70, 0x53fc882a, 0x409ddfa1, - 0xfa6f94bf, 0x0c4e38f9, 0x9ca3e60e, 0xb8ec136a, 0x4c51032f, 0x8275d16e, - 0x4cf66d77, 0x5f016bfe, 0x6a5fe617, 0x4358eb63, 0x75f60dd7, 0x5be79f81, - 0x80f83e98, 0xe73b22ff, 0xd992eff4, 0x490238fb, 0x44e77e40, 0x8f915cfb, - 0x939aee70, 0x1ddf5aa4, 0x37fe8c9d, 0xe0fc4e09, 0x36fbffa3, 0xbacbdbeb, - 0x7f4cfa2a, 0xd3c157d7, 0x1f3add4e, 0x9c2f6a8a, 0x8272e780, 0xf20bdf13, - 0xd179e1c7, 0xfef646c9, 0x1fae41cd, 0xd805f7e9, 0x78f7ea1f, 0x21c0c066, - 0x145a7a2e, 0xbf6295c6, 0x533f4c69, 0x3bfd29f3, 0x6e375f48, 0xa3b486a9, - 0x7f8e165e, 0x066edf74, 0xd04d3fb9, 0x19d149c4, 0x27ffbee1, 0xbea397c0, - 0x36493e02, 0xc8797ca3, 0x19eebece, 0x1ef02466, 0x3235e5da, 0x06bdd1d2, - 0xe06c91c7, 0x04c98f2f, 0x83e5c7f6, 0x3b9d1e37, 0xa445ca00, 0x26f7e28f, - 0xa56b8354, 0x91aac598, 0x5c9847e2, 0xfffbc13a, 0xaed79513, 0xa097786b, - 0x7ce27b07, 0xb674bf70, 0x0754d773, 0x0f325bf8, 0xcf7386ad, 0x23f67959, - 0x1b1d6047, 0xc74fbbd8, 0x9da1e4d7, 0x0577d0f6, 0xe8c767dc, 0xbb9c017a, - 0x391ea767, 0xe0f7c742, 0xb73c449a, 0xbc4aeb9c, 0xe731ce07, 0x0e9d141e, - 0x5de16f5a, 0x7f9c0b56, 0x122d1f4e, 0x0f2f0ab7, 0xeff47692, 0xeefdadcc, - 0xca4fb0dd, 0xf7843ca8, 0x87fcca9c, 0xfc840ea6, 0xd7db017a, 0xb846dd78, - 0x74ded9e7, 0xfb4998d1, 0x00f5a12f, 0x59eb35dd, 0x028d9abd, 0xe25817be, - 0x64f9027f, 0x1f0146c9, 0xfaa769c4, 0xf5c199af, 0xbed12981, 0xf9a7b69e, - 0x700f6852, 0x03ddc637, 0x743593e7, 0x527ed89c, 0x97539e1d, 0x98b476d0, - 0x2efc6fb4, 0x5eb25bc2, 0xb0af7020, 0xe3ea526c, 0x41de0093, 0x47e509d9, - 0x08dcfd77, 0xfb479ee3, 0x2fe1441b, 0x42a63b14, 0xc103f27d, 0x152eef8e, - 0xbafb8b5e, 0x623bef9b, 0x14e2cd1f, 0xefdca204, 0x2af1d493, 0xb869d125, - 0xd7964a9f, 0x3abcc3d5, 0x06a989bc, 0x468ba7a4, 0x2927e390, 0x7f54ddbe, - 0x7164613d, 0x27bc7b30, 0xfe2a1d8c, 0x1d3a32b9, 0xcb6a2fdb, 0x98b33e41, - 0x853c6114, 0x23e98ebb, 0x7ca3ab9d, 0x94eb57e0, 0x7df029ed, 0x7e136acf, - 0x932af0bf, 0x7586173b, 0xf4fb7fa0, 0xbdc0997a, 0xd3eb95c7, 0x9e3ac1d7, - 0xe13b2cde, 0x8e7c40dc, 0xbe9411c5, 0x7b64fcca, 0xa7b833d6, 0xcb7f199b, - 0x02eeee7b, 0x94a5dbe0, 0x7e70994f, 0xe2563e5a, 0xf53e4728, 0x4be3145c, - 0xe7a57e7a, 0x1b8d6553, 0x65a1cb22, 0xd0e59105, 0x37ee7ad0, 0x6b9f2c8d, - 0xbbe98588, 0xf078c9e3, 0x0d571663, 0xf404d79b, 0x70bb20fc, 0xf3781ed0, - 0xdc819fd3, 0x3be2b4ad, 0x7d92d565, 0x83e8c09d, 0xeb9fff00, 0xec29f2df, - 0x51b9b287, 0x29d90ef8, 0x47d80f58, 0x1cf0136b, 0x8c57c4bb, 0x79e25778, - 0xf4b49b4b, 0xef21f8ae, 0xa5c48b73, 0x31655f96, 0x77aaa5c4, 0x6e9447f4, - 0xdbf33f69, 0xcab01f04, 0xdcea3fa3, 0xe62670ff, 0xe5ae38ed, 0x6b583f5c, - 0xfa3eba45, 0x40d5c5c8, 0x287ef3b7, 0x89dbd010, 0xf20f5dd7, 0x7049bab0, - 0xf4b89f80, 0x297dac87, 0x3ee30f6d, 0x5f4673fa, 0xb01dce94, 0x3fd7aa0f, - 0x6feb1fb1, 0xff001c14, 0xd46286e8, 0x22bcca27, 0x9d8df2c1, 0x79504768, - 0x7b68f185, 0xec1262bc, 0x2655ea83, 0x1562b83b, 0xb3e8527a, 0x40a7bf93, - 0xb3b1cecc, 0xb4673b68, 0x9eb2f903, 0x4239c52e, 0xfd029e48, 0xbd1978d4, - 0x3b2abe75, 0x4df48b61, 0xbd1eec9f, 0xd0227f42, 0xfe98665f, 0x33cfacf6, - 0xf69e3d02, 0x91671809, 0xf40bf407, 0x9fe2b2f9, 0x1eb51621, 0xea7d17d5, - 0xfd07b0e9, 0xe958cbc1, 0xe854fa61, 0xc7874f51, 0x8c0f7225, 0x51d5a1fb, - 0xfabc8f38, 0xce59ef37, 0xcf9e19f6, 0x923fd5e5, 0x44bafb04, 0x0a407162, - 0x1624ab5e, 0x5c63d637, 0x0719d74f, 0xba7c67f5, 0x0e8acc71, 0x20f1edc9, - 0x4a3ea9b7, 0xdf9fb402, 0xe3117e6c, 0xd2bfcf2b, 0x37ea2779, 0x003a516f, - 0x92b66ffc, 0x3e21da00, 0xade547e4, 0x1369c622, 0x4b359029, 0x712bbf65, - 0xb2bf1531, 0xb7cbbe22, 0xb4857c9a, 0x27ebf97d, 0xc25c62c6, 0x7b7fa60a, - 0x39d8115f, 0x2c63b788, 0x972a3bdc, 0x5e8e7c58, 0x345df82f, 0xdebbc3b3, - 0x7a03998c, 0xdeccd09b, 0xb96f2c17, 0xfca93657, 0x65a2fbbb, 0x939e1ea5, - 0xc33ae979, 0x3e300afb, 0x4a76fbf5, 0xcbd74e5c, 0xdbcafe8c, 0xcae7d464, - 0x805cb79b, 0x63f2cd78, 0x6b77b426, 0xc11a2f9a, 0xd5fbcd9e, 0xc41decab, - 0xa7135136, 0xae3e23d7, 0x20980c59, 0x0ab5abae, 0xbe6871cf, 0x3c2df313, - 0xc66bed1e, 0x6afc556f, 0x8a5eebc7, 0xbf6d8ac2, 0x857be1b4, 0x786c9bed, - 0xabf9aa5f, 0xc47b55e3, 0xf034b5c3, 0x4e3bb878, 0x918fe413, 0xc1cee1e3, - 0x7d21283f, 0x878dad16, 0xbf8ccd23, 0x456671d1, 0xa4350f7a, 0xe9fabd77, - 0xddcf10f3, 0xe793f5b5, 0x5f95dc61, 0xe21e7e5c, 0x6882a86c, 0xe6a53d07, - 0xfe31f795, 0x1f176955, 0x97a0edc3, 0xc3f1897f, 0x7268fe17, 0x3b0bb402, - 0xfe80a74e, 0xdfcb6171, 0x782e2092, 0xe8a98ed9, 0x3db659df, 0xedbddf0f, - 0xfa059ecd, 0x7e23f5f5, 0x7b6ebf59, 0x3c60f75a, 0xeeba79d0, 0x714227c0, - 0x2c552d8e, 0xe3c1d47e, 0x8e47371b, 0xcf11ef17, 0xaeeb3ad8, 0x5b1fc029, - 0x67d09e99, 0xba61e35c, 0x63f4379e, 0xf8f3371d, 0xbe3b96d5, 0x3cf1ae32, - 0xd7ae83fc, 0x7c6d18b8, 0x8bada7e8, 0x942cf17f, 0x1af426b5, 0x07e818d7, - 0xf47894fe, 0xd95da3cf, 0xdeb08931, 0xa4f181ff, 0x0e857eb0, 0xa69fd7e0, - 0x8cf8bf80, 0x44bf441c, 0xef098770, 0x38ef966b, 0xc2e9fb8a, 0xef1843f6, - 0xf85c784d, 0xb1fa1205, 0x03ee5df8, 0x6568d9aa, 0x1d7c90f1, 0x61d25e20, - 0x2e3cefc3, 0x12b5d192, 0x9c5bd92f, 0x3498b2e4, 0x8b0b3efe, 0xf8daace7, - 0x0c3f8f01, 0x09309baf, 0x2bf3abd6, 0x3c1550e3, 0x130f01d8, 0x91c071d5, - 0x714352e3, 0x8375bac0, 0x1e3e04f5, 0xf9a5f38a, 0xe9ef10a1, 0x8a468e13, - 0x81b0bf2b, 0x905f0fc5, 0x568fdf23, 0x626b82e2, 0xd7d6fb74, 0xbee078bf, - 0xf175f1e6, 0xa1c63f34, 0x5f051ba1, 0xf323575d, 0x846327f7, 0x85b7646f, - 0x0a549bee, 0x4f2cfbfa, 0x997dc0c4, 0xbe234ed6, 0x55d8a293, 0xdc5dbe7c, - 0x8af5d6df, 0xf5a27188, 0xbf907b2d, 0x3547f9eb, 0x8fd1473f, 0x6f1f2377, - 0x1f931b75, 0x3ead5b5d, 0xb5d3850b, 0xeba44dfb, 0x189dcdea, 0x79bfbaa7, - 0x7543b19b, 0xc3f20cfe, 0xd77f1aa7, 0x22c6bb6b, 0xa2efe73f, 0xcad9fbe9, - 0x3f8d63f9, 0x9b353f72, 0xa9fa6a2f, 0xed18b6f0, 0x3bfbbe96, 0x05eeb927, - 0x99dae778, 0x45ae751e, 0xd08be69c, 0x6462cfff, 0x3237576e, 0xa395383f, - 0x959c3ef8, 0xda2707bd, 0x5b2f51a2, 0x0c749d66, 0x665d21de, 0xcc5c6235, - 0x471e3aca, 0x326723f3, 0xeb4af7ac, 0xbbc604ed, 0xb2abf01a, 0x9bbb65ef, - 0x27273e80, 0xcfaa6517, 0x1bf19461, 0x4f881807, 0xd3ad8fbd, 0x4a7d8206, - 0x1850ef24, 0x7f699dc7, 0xb62e4095, 0x9f7f987b, 0x02313d5c, 0xf64bb7be, - 0x6e14097d, 0x04e0be7b, 0xba4f6cd7, 0x7e43f067, 0x1df69706, 0x4753bc5d, - 0x69c977e7, 0x6ad13d40, 0x1569d808, 0x4f6a8d62, 0x41d70346, 0x5e12521c, - 0x8978c0a5, 0x11e63cc7, 0x46d43f70, 0xf50adaa8, 0x5de6929c, 0x9249d895, - 0x72159dee, 0x57a50478, 0xc557a70b, 0xff65675f, 0xf03b70a6, 0x0cb896fd, - 0xbbe40752, 0x7d46ead6, 0x0b9b29e2, 0xdfd23fef, 0x88938868, 0xf54ed127, - 0x5fb450bb, 0xda3b7dcd, 0xe71f26af, 0xa613e6d2, 0xc9232749, 0x8e3e049b, - 0x7882d102, 0xe06a9b88, 0x70abb2fa, 0xdc785264, 0x19c48971, 0x2c3bf280, - 0x6e808f78, 0x1e7aaf2f, 0xdc768b16, 0x3e1a7c74, 0xe1d19b11, 0x6a71b035, - 0x0389dbbe, 0xe3a747df, 0xaf1bae3d, 0x70b56f26, 0x0911277e, 0xdcc59df8, - 0x2ffe384e, 0x4abdf069, 0x224f8a2a, 0x38c2644c, 0xde2130e9, 0x83cf9625, - 0x6fa9aff6, 0xeb01ef07, 0x0c870b5f, 0xb5efabb5, 0xe0e5c0de, 0x8a514b11, - 0xac93ee85, 0xb818b5e1, 0xb82c9d9d, 0x65a04e4e, 0x9fc801fe, 0x61e796d2, - 0xc8d08a5c, 0x5ac46ae8, 0x4466fb82, 0xad55c790, 0xd53d468a, 0xa8de2664, - 0x8e3f70f1, 0xd0f1e578, 0x3f9f8f8b, 0x28185639, 0xa50d6928, 0x1fceda35, - 0xa62c35cc, 0x4502d08b, 0x8b10fe14, 0x5ff40c6b, 0x6c9dc33f, 0x1bd30718, - 0x2877bf56, 0xc16bdaee, 0x1ba86863, 0x14c0ffba, 0x2ef82164, 0xdd0ef108, - 0x51b8720f, 0x0ec653c9, 0x463406ef, 0x332ef287, 0x698df7e5, 0xdaf37f2c, - 0x7ef0f5a1, 0xe8bda74d, 0xc78c0b66, 0xcf0ebf6c, 0x9af102c3, 0x937bd5f7, - 0x4738ca2f, 0xc1e40c6f, 0x07b7c7fb, 0x23c5fbd9, 0xfc7ba1ad, 0x59378f28, - 0xed007c94, 0x43d6a28b, 0x5aaad7c8, 0x01b9610e, 0x9e1d34f2, 0x421bc810, - 0x65bf79e7, 0xb5f2414c, 0x716b5e14, 0xb1c13c32, 0xbf6632d0, 0xb8c3c1a4, - 0x61d9bdfa, 0x6e2b483c, 0x86e1e1d0, 0x858785af, 0x87a86f6b, 0x3bfa55f7, - 0x0b174a6f, 0x73d35f00, 0xdb8ef80c, 0xf41663c4, 0x145fd0bf, 0x670e23ca, - 0xbcf72f43, 0xc2853b15, 0x97d35729, 0xaba14ed2, 0x9d26e8de, 0xef63afd8, - 0xe7e96a83, 0x87ae2ddf, 0x8b32de00, 0x8896dd2b, 0x0577c7f3, 0x8b8bbba6, - 0x74c213f2, 0x09ee2c4d, 0x11feaef0, 0x5a1f82cb, 0xe9dafe54, 0x34c54b39, - 0x011fde3a, 0x3c31b823, 0xdee5c49f, 0x9e7451a8, 0xc6032e89, 0xb8b11fd5, - 0xdb3b4057, 0x6200609c, 0xf71226cb, 0xf70c4104, 0xfa8feca3, 0xaf8ecc1d, - 0x56f8362f, 0xfc60f3b0, 0xfa611dbb, 0x47d1d0e8, 0x5b47d190, 0xb547d227, - 0x47d193bf, 0x346e5d5b, 0x3b03573f, 0xc70491ba, 0x5937bac1, 0x61a40b0a, - 0x82626e94, 0xb23740f5, 0xc282b6f7, 0x3aebc428, 0xf58f5f18, 0xe652e3e1, - 0x36fadbd5, 0x71fb481e, 0x0799d806, 0xa61e780d, 0xb7a94de0, 0x46e2c2c3, - 0x7ee6cdff, 0x99a9fa11, 0x961fb1d4, 0x3f81eb6f, 0xed875c60, 0xd05dcce0, - 0xae9b36de, 0x6fdc2390, 0xf815c1e3, 0x7f23784e, 0x04963bd7, 0x7bd720bd, - 0x3fdb07c7, 0xde807c21, 0xe8f80193, 0x0af2fdc4, 0xdd9667bf, 0xce40b826, - 0xef618f0f, 0x616ebc90, 0x16bbf576, 0xaf4ca791, 0x5bb83c49, 0x7b2bfb04, - 0x27eb0195, 0x9ea19a42, 0x5f5e2aff, 0x95ddf8d2, 0x89e85575, 0x7818d272, - 0x78f9e4cf, 0xfd2d1ef7, 0xa9a4c7c4, 0x1eed29e0, 0x45a290f7, 0xee265094, - 0xc810f05d, 0x3e3f4a55, 0x7231bb4d, 0x442de014, 0x233e943f, 0x776d0fad, - 0x7c6bad88, 0x5b0be80c, 0xf1152ef6, 0xae7e8e5d, 0x47bc166b, 0xc567eb49, - 0xb4adda90, 0x4d2c567d, 0xf3c09f21, 0x087e7903, 0x743fd34b, 0x7dfa041a, - 0x9ecbf703, 0x922578e5, 0x6399bafd, 0xb8f4cf20, 0x9418e4ec, 0x85beca0b, - 0x5ce05467, 0xdbe7e25b, 0x0334c169, 0x8fb29bac, 0x6021a0a5, 0x4d2b42a5, - 0xce201872, 0xbb8f5de1, 0x7b0bce08, 0x5fb73be3, 0xea81eecb, 0xc7ce7fbf, - 0xebf58df3, 0x2fb8f4bf, 0xb7e039fe, 0xf8f1dcca, 0xbeaf9a4c, 0x69fa32f6, - 0xdf54c457, 0x68ef55fc, 0xeeffc7e8, 0x00c4dfd5, 0x333ffa1d, 0x353fbc45, - 0xf1e8cace, 0xb60e6780, 0x04efe2cb, 0x1c4a8192, 0x15ce2ab2, 0x865eb8ca, - 0xdf86994b, 0x05bacf51, 0xa7ac2059, 0xf6878a57, 0xae78a931, 0xae2eab78, - 0xbb2f3955, 0x80fcc025, 0x42beb159, 0x74faefec, 0x3e49f7f6, 0x9992fa63, - 0xa1ce0ffe, 0x3373f2a6, 0x5efb31d7, 0x09598710, 0x3f08f98d, 0x5afd1536, - 0xfefb4439, 0xaf40d641, 0xf4f28064, 0x67978454, 0x13a795d6, 0x6b915bf4, - 0x4df9c3ae, 0x0cfd2a25, 0x13a346e5, 0xd1f4f1f8, 0xf7f9fe94, 0xe1bff4cb, - 0x867f3226, 0xcdb8ceca, 0xbe515f71, 0xc4696f46, 0xfb7e8577, 0x523f38b9, - 0x2163c5fc, 0x4115173c, 0x8f1e803c, 0x95610eb9, 0xdf13d1d5, 0xf1e9fc7a, - 0x8f51e0ad, 0x9d0f9cb7, 0x9e8ef1f9, 0x23e3d1f8, 0x5be97e7c, 0x7530eb0b, - 0x4bf288b4, 0xfc4f7bc1, 0xedfaf5b0, 0x009eb4b5, 0x0df142f4, 0x30174cf8, - 0x862b27be, 0x3a6c4fd3, 0x140b37e2, 0x0f4801c0, 0x55e3d798, 0x04acc78f, - 0xd5813ede, 0x1af80fdf, 0xed00fc89, 0xb2dd6521, 0xc6f76bd2, 0xe8c4de41, - 0xa7abd14c, 0xbd50bc72, 0xbce6f51a, 0x9bfa2b44, 0x9a9eaf40, 0x5e5bc614, - 0xde571b15, 0x600bcb48, 0xfc0afe9f, 0x0608b1d1, 0x95bcc5df, 0x56e05ff0, - 0xe2ca5f3c, 0xb7df0559, 0x93d5a67e, 0xce0bfaa7, 0xdc3dfe82, 0x05655ee4, - 0x87108c7f, 0xff1479e7, 0xd7f875c7, 0xf36bb3b6, 0x0afc7c7a, 0x27b931fe, - 0xab7a14de, 0x7cfd72b3, 0xfa0a1930, 0x3337d8f2, 0x137f8163, 0xbf447c7f, - 0x4563c4c4, 0x6e9c3821, 0xe2059e91, 0xa7b77d0e, 0x763e0b7f, 0x15494a90, - 0x7253bb1f, 0xd8deb3af, 0xeb298f93, 0xc7af8535, 0x05dde214, 0x4429a67e, - 0x1ec84bfa, 0xffcf0d48, 0xb3f72b79, 0x6043210d, 0x1c585f9e, 0x79f3ff8c, - 0xd54de686, 0x9b3fe84b, 0xb66d9ff7, 0x121bfde0, 0x7842ba94, 0x93f7c34e, - 0xf0f8c6bc, 0xbd656438, 0xd3096a53, 0xfbe2e6e7, 0xe42f14d9, 0x38f098cb, - 0x090559b6, 0xe3e20fdf, 0xf66cdf38, 0xd3db9c42, 0x2b0dfb92, 0x83843df8, - 0x527e7163, 0x3fc81460, 0xb6e5f97d, 0x4e50d5bd, 0x3d6095eb, 0x910afe3e, - 0x3b821ff9, 0x5217be4c, 0xe953d77b, 0xa13946f6, 0xdc3671d0, 0xe801bd7b, - 0xb8c2283e, 0x655cfcfd, 0xcf7645e7, 0xabec45c1, 0xf6f0a7ae, 0x02f7625d, - 0x81db28f2, 0xedfa7a7a, 0x49f34e8b, 0xd3b41e70, 0xcf22abd3, 0x5bfdf81b, - 0x68bb3f45, 0xeb0fbf75, 0xe3efc0de, 0xba8e2ffa, 0x1be7d60e, 0x2d61d5d3, - 0x44f4295d, 0xf438ebe9, 0xf1f99dd3, 0xdfcb503a, 0x049cbccb, 0xe3d151f2, - 0xeb8afac3, 0x9bd7a863, 0xe6dc3f3e, 0x857eb2ee, 0x35e8af3e, 0x6423d97d, - 0xd34644af, 0xebe3ce71, 0x2edcd733, 0x41c68bb3, 0x886fd38c, 0x73cbde56, - 0x393e8344, 0x95ed21af, 0xac573866, 0x07f97e63, 0x3d8d656b, 0xbedb86ec, - 0x67bd9ed8, 0xb6b97f3b, 0xef8a23fc, 0xcef8f141, 0x868ed6ad, 0x7e1491fd, - 0xbf67b7cf, 0xc9c82f06, 0x31a32379, 0xafdf4e7e, 0x7efa7e7e, 0x7035fdf5, - 0xd8c1aafb, 0xd2a9da38, 0x1636ec4f, 0xcd697d47, 0x14f0cd93, 0x73f86f5e, - 0xd4b8879b, 0xa3ae6f7f, 0xa44e7a21, 0x781468f7, 0xc2e7be0a, 0x0fe098cb, - 0x1eff95a8, 0x6cdd9de9, 0xf413f337, 0x6088efd6, 0x8683ea3e, 0xe82203a7, - 0x048223f5, 0xa0ecf0f5, 0x6350b0cb, 0xb97b300f, 0xef003d87, 0x657cd0a4, - 0x0f662eeb, 0x5da1d4b4, 0x0aed4951, 0xe01b3b90, 0x7cc1901d, 0x27681940, - 0x885eec84, 0x7786caaf, 0x0c5db932, 0x37a5a74f, 0x1f33fab2, 0x8c35374f, - 0x9dd5bb00, 0xce932f0c, 0xa8fb5db4, 0xf557da99, 0x508a24a9, 0x76c8aafb, - 0x4ed677ed, 0xde3bdca2, 0xa4bbc025, 0x65a8ff34, 0xecedff72, 0x8fd1b699, - 0xda81bf82, 0x54d9b767, 0xfb6f6f76, 0x039b66e3, 0xfedbd9f1, 0xcd17b4e8, - 0xdf8a3804, 0xe421f282, 0xbe28fe07, 0xf442a3ff, 0x53780b17, 0xe5f6e5e8, - 0x88ced10b, 0x0a6ae6ba, 0x736593c4, 0xb8db703a, 0xc186365f, 0x706189a9, - 0x376e4a26, 0xfbbdd3f4, 0x3bf028ea, 0x04fa3bbf, 0x2b7e79da, 0xf41fdbf3, - 0xe3a91594, 0x026d6bdb, 0x10c097a7, 0xdc777fd8, 0xec0127b8, 0xc0596c95, - 0xb2fd4ef7, 0x99f1e9ef, 0xdb669fc0, 0x6629d257, 0xfde2364f, 0x60547f32, - 0x3d2ac3c8, 0x4ddfcfce, 0x3fdc5ff5, 0xdcff1d44, 0xb5abcd6e, 0xc022f831, - 0x7bdccecf, 0xde80f40c, 0xae584ee4, 0x2b9004b8, 0x24a1eae4, 0xdd6a5f3c, - 0x689f0367, 0xe0e77f17, 0xa49eeb7c, 0xdaad3405, 0xb0369ff2, 0x3e38eae3, - 0xf8ed4bce, 0x76e5535e, 0xa113df11, 0x003d26fd, 0x85d6eb7e, 0x1fdeec59, - 0xc8a6afbb, 0xef9ff1d5, 0x9cc45219, 0x4cff7889, 0x98a737d1, 0x9f183ebd, - 0x1dfd8ebf, 0xf7ba29cc, 0xefe56ec9, 0xcff5e993, 0xe2b26c67, 0xa9f8c32f, - 0x4fd67665, 0xfb2bfb6f, 0x53e204b3, 0x296cbfed, 0xb3f8c220, 0xefc24b3f, - 0x3da40fe7, 0x3df60855, 0x01239d91, 0xa2f644ac, 0xa7cfcb7e, 0xbc2f6fe8, - 0x6793be7b, 0x3cbd6ede, 0x6e2466eb, 0xd004d72a, 0x9803dcc7, 0x07c991d3, - 0xf5bbff45, 0x55dfad33, 0x722b07af, 0x6e3fd732, 0x780210d5, 0xfbc2cc77, - 0x8c240713, 0xc9ebd2f7, 0xbd058353, 0x204fc3e8, 0x4d6d6d7d, 0xfe7b018f, - 0x009f60df, 0xc65eb6dd, 0x49aa83f7, 0xc7781ee0, 0xb455baa9, 0x24fc6007, - 0x67d87af3, 0xe0a13e8a, 0x1eeaeda5, 0x7fda58f3, 0x7d8345f6, 0x76f10505, - 0x57682ff0, 0xc1fdf84f, 0xfe679004, 0x07e784a0, 0xc6f717d9, 0x45f1542c, - 0x7e0355ff, 0x6eeafb7f, 0xfc60f7ed, 0x8b6ed0f5, 0x7bcbd981, 0x063dfff7, - 0x57dbd4f8, 0x90bc212f, 0x6f53d13e, 0xcf3bfd46, 0xd1fc862a, 0x8899bd6a, - 0xde2187d9, 0x152c6a6b, 0xfaef426b, 0x6487ce70, 0xd4f49595, 0x2778422b, - 0xd0f0092e, 0xf0561f43, 0x3e33d3ac, 0x773d71b2, 0xef0f1918, 0x4d5db65e, - 0xc77bc0a8, 0x0afb18fe, 0x8f4ccf94, 0xee7bdeea, 0xfdf0e9c9, 0x9ddec8a0, - 0x7ee22ab8, 0x62b3bdda, 0xdf6a8778, 0xeb8a4e52, 0xc5d06576, 0xfad16f0b, - 0x3345f657, 0xbce4baff, 0x224f7d5e, 0xf1c7df5c, 0xcecc1815, 0xe183bce9, - 0xac6fa8bd, 0xb0f574cf, 0x4361fff7, 0x0058393d, 0xfad462e2, 0xffac234e, - 0x3e8ad9bf, 0x25a5fc67, 0x978bf806, 0xb4210ee4, 0x9268b2df, 0xac15740b, - 0x33b07623, 0x18301fb6, 0x37325d60, 0xcf5c62a5, 0x731cfc2b, 0x31a34b49, - 0x4b174555, 0x19d839f8, 0xaf129bd9, 0x9632befa, 0xfb3397f1, 0x71817fca, - 0x91347f1d, 0xd0f41191, 0xfe4cb185, 0xa77a336e, 0xc77a866f, 0x68df780d, - 0xef5ffeef, 0x97937787, 0x038c731c, 0x5894e0bf, 0x0eda0fb6, 0x710f52be, - 0x821f6dc1, 0x6672a2d4, 0xa068b163, 0x1c45befd, 0x9877afcc, 0x90d6bdfd, - 0x12b8943f, 0xc5379e60, 0xd6fdbe32, 0xdce68301, 0xbefe2dec, 0x8cb1f5ef, - 0x32c6a50f, 0x03d6dabf, 0x700b09b9, 0xc447b9ff, 0x64f01f82, 0x456c3d47, - 0xe8a80fc5, 0x6f0f936f, 0xfe863e9d, 0xc1977273, 0x38edcb0e, 0xf30882fc, - 0x24219c75, 0xf43d204e, 0xac6f0a39, 0x5d5bde1a, 0xc71d1e0c, 0x0aafd86e, - 0xfe04a9fe, 0xbfcd0671, 0x43c52ed5, 0x7f82983c, 0xff4a1e65, 0xdae2168e, - 0xe4adc160, 0xfe15fada, 0x31efe568, 0xe513b04c, 0x5d2033ef, 0x6eb9b76e, - 0x6f72c589, 0xeccfe40a, 0x36d27a63, 0x72494f2e, 0x9fc070f1, 0x79f34eb2, - 0xb7a78caa, 0xe3e7effe, 0x4bafd254, 0x0ec8afd7, 0x76cdd22f, 0xf0ee4f16, - 0x10e9cc06, 0x8e96d677, 0x154a9f7f, 0x8e3f7b97, 0xfdf68cff, 0x830eb6c2, - 0x558fee01, 0x50e210ef, 0xbea7eddd, 0xa933a21d, 0xedafe905, 0x5c7dc118, - 0xe65dfcde, 0x9f72a48f, 0xe786ebbf, 0xf87fb0eb, 0x8120fb39, 0x1bfd93a6, - 0xfc410e56, 0xafb06c06, 0xfba278c2, 0x46dad206, 0x92ebd023, 0xe52d2c65, - 0x9a4bd5e7, 0x4b3fb8dc, 0xc478b3d6, 0x4ca9b165, 0x257a733e, 0xf8c1e886, - 0x7b4dbade, 0x5c1ff08f, 0x7d6d9e7e, 0x4bf40f6a, 0x80fbebe9, 0x9eda9b8f, - 0x55c30758, 0x46ecf5e8, 0x4594e119, 0x3df3cf6b, 0xb8cfccb1, 0xf7a330fd, - 0x5ce51bc9, 0xb26c4f78, 0xbfc1d897, 0x4dc6d6fd, 0xb7eff022, 0xd9539e80, - 0x7b79073e, 0x3163df66, 0xd6f907df, 0x47e02069, 0x652466df, 0x62fb545b, - 0x343786ef, 0xb9bcb7fb, 0xebfa3a6e, 0xe005e23b, 0x55becaf3, 0xe8cdbef0, - 0xfff70dbc, 0x9ffdba9d, 0xc2b7dacf, 0x4f7ad0ba, 0xd4fffdf1, 0xe9ffba34, - 0x718db8a7, 0x66d9c002, 0xdccefc8c, 0xfe90df4b, 0xa3b57c42, 0x297d5f07, - 0x6c1ff996, 0xeaffb4e9, 0xffa12e3b, 0x4e3e3421, 0x2be54f37, 0x002a9374, - 0x0ae91bfe, 0x517c008e, 0x533d02bc, 0xccfe7a3d, 0x0795dc0c, 0xe1ff3c24, - 0x2e3c4be7, 0x6a947704, 0x99f986bf, 0x6fdd6fb2, 0xf2b238c0, 0x9e82576b, - 0x45e8509f, 0xb82b3cfa, 0x7953c787, 0x71f61676, 0x8eb07e04, 0xec8ae3e3, - 0xff7debee, 0x65cf40c1, 0xf98462d4, 0x1d82f590, 0x772945d6, 0xbdef67ac, - 0x94f0e61e, 0x2dbf87ef, 0xde3d83be, 0xf0cc3d21, 0x5c42341d, 0x931f28eb, - 0xc5c84463, 0xb70c40fd, 0xb67d860f, 0xfbafca84, 0xacebf255, 0xaa7488dc, - 0xce23e1e0, 0xb1c4aeb7, 0xc7ce3f79, 0x5d1f07e9, 0x82ff0aa2, 0x3f6c0924, - 0xe7db028b, 0xbb3fc022, 0x90dba6ef, 0x4c88efde, 0xb7b076ef, 0x47efe1e2, - 0x8cfa406d, 0x7bc7669b, 0xce494f2f, 0x7e8d38a8, 0xef74c3e4, 0xced067a6, - 0xfd85fa03, 0x97fd1bde, 0x0893fd01, 0x74a3ef74, 0x853f5aaf, 0xfc5d280e, - 0x7ca5f01d, 0x7285d3d7, 0x65e0a90e, 0x731cee9b, 0xe9e19daa, 0x8d5200ff, - 0x8000b56e, 0x00008000, 0x00088b1f, 0x00000000, 0x7dbdff00, 0xd5547c09, - 0xf37df8d5, 0x3332c966, 0xb2764c99, 0xa00c4930, 0x80490e2c, 0x084ed8b0, - 0xc3884a20, 0x93a0d752, 0x364b0900, 0x94569510, 0x8b062081, 0xb62d1518, - 0xef858320, 0x106d1b43, 0x268358a8, 0x622d1110, 0xa57fb1dc, 0x41459041, - 0xed1fa822, 0xe73bf587, 0x33337bdc, 0x6a02266f, 0xefc7e1ff, 0xdf77dee6, - 0xcf7ece5d, 0x6ec5f739, 0x843631d3, 0xae630731, 0x7d8c01e6, 0xf4bf3f8f, - 0xa12d8c97, 0xcf3773e7, 0x8224715e, 0xf0f7cfd1, 0x5e79babf, 0xc776bd50, - 0xe91c57af, 0xc5cfafe7, 0xffe0525f, 0x8967a671, 0x47f1558c, 0x89ef4cac, - 0xfbc025b5, 0x6cd69d11, 0xe266b498, 0x03846319, 0x8319789f, 0x1c636ff6, - 0x6faa3e54, 0x1f2bd3de, 0xe9cc31ca, 0x9b39a685, 0x998f1533, 0x1b3605b1, - 0x27f967ad, 0xb0dd93d3, 0xc6c646de, 0xc59bbae3, 0xd9dd727c, 0x99c68536, - 0x8f7329e0, 0x66678389, 0xa07b9e4f, 0x6607f9ff, 0x886d964f, 0x70a13ebf, - 0x4018eabe, 0x7ec48c4b, 0x0c985563, 0xc9bf9fe6, 0x326533e4, 0xc49f05b6, - 0xa3db2ac3, 0xfd329b7c, 0xccf4d9ef, 0x9633b7a5, 0x75a4cb6b, 0xb15aeac1, - 0x646858ee, 0xdfbcc197, 0x9bb59666, 0x1dd5d1e1, 0xb081e2de, 0xef462d8f, - 0x389989d4, 0x1c1af398, 0x9d629aff, 0x6a5801ed, 0x38a6cbac, 0x6992d007, - 0xcf8fb65e, 0xeced9793, 0xeea1b2cf, 0x2db9e670, 0xf8128d8c, 0xc930ad62, - 0x421c3f70, 0xd9e1c6f1, 0x20175e13, 0x1750867c, 0xd5e27e7a, 0x667d1ba8, - 0x0144f3ff, 0x78632fbf, 0xd3c1adf9, 0x1d0e66db, 0x553e6027, 0xcacc6649, - 0x5c554b3c, 0xdb6628ff, 0x773ff0e4, 0x1c2e628c, 0x57189a7f, 0x8ffacbb6, - 0x10aeafa6, 0x78869afa, 0x22e88ead, 0xd053eaba, 0xbcc07469, 0x8bdd194c, - 0xee98fac1, 0x80ac5eda, 0xbd71eaba, 0x29554800, 0xf6c7ebe0, 0xd7338d84, - 0x01d99e23, 0x0cc9cb13, 0xcdb567dd, 0xd1b6e1c0, 0xe866fa30, 0xb865e097, - 0x838bc003, 0xde3585e3, 0xdc6bf88a, 0xd7886268, 0xdc39636f, 0x68d953ac, - 0x42b7f403, 0xc6f7247f, 0x57039ea9, 0xd931bd41, 0x9e6050e8, 0xc22e8613, - 0xa0ab89fb, 0xadc3e88d, 0xbc4fbe20, 0xdf9ae23a, 0xa277bb40, 0x8bc0e58e, - 0x05b08d5b, 0xa7bfc3a4, 0x482936f9, 0x27c42da7, 0xc1b2c7f3, 0xbede7826, - 0xd5d11869, 0x052ce2ac, 0xe6ce76e9, 0xdb9f0558, 0x2a74d8c7, 0xd863eff3, - 0x13e89542, 0x16dea0f8, 0xde618f80, 0xd5e1153a, 0x6c93ce3b, 0x11ec6588, - 0x23e335db, 0x32ce81d2, 0xcc1b2459, 0x5f5043d8, 0xb46b7009, 0x4b1614bb, - 0x0a7306f5, 0x236321f1, 0x0cadae08, 0xd518d4f0, 0x6045775d, 0x7f5e2cff, - 0x86eaf1a4, 0x9ec63486, 0x22357189, 0xbb303e9e, 0x87f9c11f, 0x44a9d526, - 0x7fae82e7, 0x127ece80, 0x2c2ed4bd, 0xe0f38762, 0x0e660ef7, 0x47901ba4, - 0xf8066eb7, 0x9b3de895, 0xbd355d70, 0xc38e3e8e, 0x657cb6d5, 0x7ba184f4, - 0x21788eb9, 0x8cc7d817, 0xaeef11f0, 0x7ecdcb53, 0x66c5b3b9, 0x52ed4c17, - 0xfcfc5b26, 0x79eb7286, 0x593b9733, 0x98229a50, 0x7ec762d7, 0xac23a23e, - 0xe5fae4c7, 0xdd62cad1, 0x3e185f78, 0xeb890d7e, 0xaccf9467, 0xf2ff7fe5, - 0x1fd0a19b, 0x9f89577f, 0xc4fce35e, 0xc5a3f5e5, 0x3c22269f, 0xbdf09390, - 0xeb1cc5db, 0xeadf3a97, 0x5fb9748b, 0x3ea09b65, 0x2af464d8, 0xe66db831, - 0xf18a25b0, 0x945b0d90, 0xa820cb56, 0x2e614bff, 0x7fe9c3c0, 0xbfae54a9, - 0x133e3dd7, 0xa1d9afde, 0x7e852e73, 0xf10a2d35, 0xf337b383, 0x371d0045, - 0x31075947, 0xb770af18, 0xf68065d9, 0xc9044ad3, 0xd7009c65, 0x2feb9061, - 0x8268cae8, 0xc02df5e7, 0x5d3d507f, 0xf5c6a808, 0x6c319dea, 0x83be1f80, - 0x1fb47cde, 0x1bda00ec, 0x4f67c89d, 0x9ff1f245, 0x81f0cc8a, 0xbe528310, - 0x4a0188e7, 0x6e825961, 0x62c67af4, 0x78504f00, 0x30b51cb1, 0x3c07a5db, - 0x35e67a2b, 0x7546be00, 0x9f08aab5, 0x8e872eac, 0xe9f3fd99, 0x3bed18bb, - 0x39d0ef4b, 0xd6d5f403, 0x7aabcfbd, 0x31d0eb80, 0x942af58d, 0x6f9e3189, - 0x4623de10, 0x7b63d5d5, 0xf557b15c, 0xa57cff40, 0xe905b76e, 0x44e61aec, - 0x24f92ab9, 0xc1b593ae, 0x81ec5972, 0xda15974e, 0xb5771c47, 0xc7fd800d, - 0xe38299b8, 0x7c0dfd49, 0x0e9162c6, 0x44ca5de3, 0x3fe86718, 0x8e47c118, - 0x68ef75b3, 0xbe3ef905, 0x18e28c63, 0x6be74a10, 0x38b7e398, 0xce9f77ae, - 0x3475f889, 0x9406d733, 0x62ba7f13, 0xf64bc20c, 0xf5cb1def, 0xa78f48ca, - 0xee154408, 0x1de70627, 0xb76fa37e, 0x6c33d601, 0xd1b77796, 0xd99fb011, - 0xed4bc68c, 0x523ed2f4, 0xb10a780e, 0xd2c6b6cc, 0xb78e2338, 0x7e800db6, - 0x1fb07549, 0x78ef4f68, 0xa6b8414f, 0x882875d7, 0x777badcf, 0x3ad37ad1, - 0xf82979da, 0x176179eb, 0x5603db74, 0xdb23ed1d, 0xf2cdf5ca, 0x666f5c53, - 0xadb27ac7, 0x2c7dfe09, 0xd724f42f, 0xf66bf8c1, 0x17ef7566, 0x2895eee5, - 0x52e403e4, 0xc691ac6e, 0xe9eacbb9, 0xbdabfb8f, 0xd20f73b1, 0xdf7bf3e0, - 0xb47f12b1, 0x137e13c4, 0xf84a7df7, 0xba485c48, 0x37d9ad98, 0xb179415f, - 0xa67014a6, 0xca59c284, 0x7eb8358d, 0xf45b1fa2, 0x27cfa024, 0xd8829eed, - 0xcca57b40, 0x20159d1e, 0x8f7be497, 0x19ee662f, 0xed6190b0, 0x16595be5, - 0xb17ef7c9, 0xc27df201, 0x9122fbc0, 0x2e2c9a9e, 0x569fb617, 0xcf388dd8, - 0xfb425833, 0x975e0633, 0xe0407af0, 0x52763b33, 0x870875b6, 0xf8e80d93, - 0x4fde4899, 0x8dee8f2b, 0x83bb09d5, 0xe0eb0bd3, 0x08fb82f4, 0xc666bfb4, - 0x748c3c72, 0x9cf48a79, 0xfee2a64e, 0x76f81786, 0x1b0edd23, 0xf48dddef, - 0x9d04ce9f, 0xa274e78c, 0x63dbf7a5, 0x711d7cb9, 0xdc218bbc, 0x0ee615f3, - 0xc654ef67, 0xbe29bb72, 0x0fd13463, 0xce1943f0, 0x4eb53437, 0x66dca035, - 0x7fa809b6, 0xa0eb137e, 0xae05797e, 0x366f48dd, 0x79f89b97, 0xe9c6d9be, - 0x07d39326, 0x1c273fbc, 0x3e436d3f, 0xa3e7e01a, 0x7347a478, 0x26de3d28, - 0x011bf4e0, 0x3df1d0df, 0xf1f8e177, 0x02973a1d, 0x603b0c83, 0x3ae831f6, - 0x49e8016c, 0xf40653e4, 0xcfb40b0f, 0x9f2215b2, 0x153956a5, 0xb302ebc4, - 0xd7dc1efb, 0xf98d9472, 0x5f3acf48, 0x6c97bc3d, 0x7efe1173, 0x67689eb4, - 0x90686c11, 0x2c40f59d, 0x9557e3b7, 0xfa7ebca1, 0x53ca235b, 0xbdbfe487, - 0x01e5d1b9, 0x50c7f1f4, 0x0e123f7c, 0xa7395adf, 0x2e5fb7c5, 0x8039cb04, - 0x0f8e5ad7, 0x77c7e76e, 0x7cb9502c, 0x3d6b9608, 0x3e4423e1, 0xc1fc3c08, - 0xeb84daec, 0x4045c6cc, 0xfacd1de9, 0xfa4f7b61, 0xf358c5f8, 0x2f67b34f, - 0x8c5f8fac, 0xc7d5084d, 0xd7ae88ba, 0x75478015, 0x6150ea8b, 0xec8bf50b, - 0xfaffc42e, 0x7689c566, 0x9516eee1, 0xf2fd61e8, 0x729bd228, 0x8f6e5fbd, - 0x84aec419, 0x6b3ff052, 0x5a7d258f, 0x5fe62b1b, 0xfcc0bf06, 0xbabc6da7, - 0x3d79e6dd, 0x6fad0e50, 0xe11226f9, 0x71593fdc, 0x4abb411d, 0x85818fab, - 0x84df7814, 0xd70829bf, 0x322a0dc1, 0xad9ef5d6, 0xf6f09526, 0x8c378e2e, - 0x0a33be75, 0xa6a7f5d6, 0x7b40bad1, 0xaf8eeceb, 0xeb05dd6f, 0xfae68daf, - 0xeb9a36b9, 0xcebbd3e7, 0xbb7a41f7, 0x9274e176, 0x9ef4c37b, 0xdce5038f, - 0x730efd1b, 0x6d4acc39, 0xd4e3fb47, 0x68fbe52e, 0xa235a100, 0x0aed1e9f, - 0x06a9ca35, 0x1c4415db, 0x1f0039f5, 0x145b5f84, 0x073eafc1, 0xd6932ef8, - 0xd9d70279, 0x14b2316e, 0xfc0b3f68, 0xbae4fd88, 0xcf7ac47f, 0x9a6f5f84, - 0xa0b468ed, 0xbebfd50b, 0x1e20bc6e, 0xa2d57c60, 0x669c7da7, 0x67c44e51, - 0x10c5d1b3, 0xc283deff, 0xab78103e, 0xba773411, 0x0f01c865, 0x81fd6fec, - 0x7fbe2734, 0x48d9c77a, 0x47ed199d, 0x7d876a8f, 0x565de9a9, 0x5bbb87d4, - 0x39de5ece, 0xc19be480, 0xbb3beb0e, 0x33ddb0ef, 0xcfed47e0, 0xfd88bf6a, - 0x0dcdead5, 0xaa227681, 0x1a945259, 0xda5a523a, 0x220ca9fe, 0x0f2863fe, - 0x57cc19bd, 0x3e5efb0f, 0x54d3d050, 0xd7be40e6, 0xcdbb7be2, 0xe00f619d, - 0xb736cddb, 0xf385d703, 0x3ed2e6a4, 0xe83eb0b3, 0x0679e9cd, 0x0c6fee1d, - 0xed29bd43, 0xb44fb93d, 0xfd7323c7, 0x5ef693fb, 0xce73fef7, 0x68c7da0f, - 0x74ec83df, 0xc52c740e, 0x282d5a73, 0x03320785, 0x784adff7, 0xacfb16a9, - 0xaab7308e, 0xcdb62fb0, 0xca53b270, 0x7dd0ac83, 0xf3869e00, 0x780f387d, - 0x377fcf10, 0x4e11eb3b, 0xda1b0efa, 0x91afb0af, 0x50560fb8, 0xf8708c96, - 0x8c9aecc0, 0x2599fef2, 0xf4fae88c, 0x14f7ccb3, 0xbb4b7a6c, 0x0366e88e, - 0xffe882bb, 0x5b99dd0a, 0xebe266dd, 0x7e7ef8b1, 0xe50ea347, 0xa1cf8e6f, - 0x797ab943, 0x474eb347, 0x2f19e0f4, 0x0f5674e0, 0x54dfebeb, 0xba48fea7, - 0x2e9e1498, 0xabf6f042, 0xb849bc40, 0x30f4128d, 0x3286e10a, 0xb27f4bb9, - 0x370fc233, 0xb54b0bc0, 0x58c78e87, 0xa9c20667, 0x7d63c5ed, 0x9abc613a, - 0x8add8f97, 0xabf9a970, 0xcc618889, 0x418f2f5f, 0x30b2ffba, 0x72735dbc, - 0x0f5b9d71, 0x3dab78c4, 0x157be48b, 0xbda230eb, 0xaddd7200, 0xd2eb900f, - 0xe867db8e, 0xf7f1c628, 0x12d9510d, 0xe759f380, 0x461624b0, 0x3f72c85f, - 0x00396dda, 0xe155f47f, 0xfcc5e4f9, 0xda476e18, 0xb25afc83, 0x9678b7dc, - 0xe7a18c7b, 0x8e0df6f1, 0xb14e7f24, 0xc87a1ec6, 0xa78dedce, 0x81cf5ced, - 0x3ae17660, 0xe2c5fd4f, 0xa9d342f3, 0x0cadf7dc, 0xdb6a74e0, 0xa05e79bb, - 0xe3ac53a3, 0xdf9097f6, 0xb9d336be, 0xfbf078ae, 0x7e2c4b79, 0xfb8abcfe, - 0x2f55d852, 0x407569bc, 0xbb2de2ff, 0xf001bde3, 0xbfe98abb, 0x4ceba6ee, - 0x8fef979c, 0x20fb3be9, 0x274bd83e, 0x16501d12, 0x3c6af8bf, 0x373803a7, - 0x14ff450d, 0x633f8fe7, 0x5ddd8053, 0x3dc6b0bc, 0x1fc02f26, 0xf9922e73, - 0x0efaeb02, 0xab891e23, 0xfda999cf, 0x9e25bb76, 0xd62f4de4, 0x8f4de50b, - 0x7848baf0, 0x3c25db6a, 0x913e0df7, 0x97c5f681, 0x07c5d83d, 0xaf7ec1ec, - 0xdc7b1637, 0xf5fc7263, 0xdea77dbf, 0x5ef30ee6, 0xacff188b, 0xda127873, - 0xd6c6c57d, 0xe1f9c2cb, 0x0b5339e4, 0x57ce37a7, 0x7fb8e346, 0x1f1a6739, - 0xeddb5d6e, 0x3fe69fba, 0x0aab07d8, 0xf44b0bb0, 0xdced379e, 0x326ab05f, - 0x3f2e6bd4, 0xd9ce8e3b, 0xdc845e92, 0xdb798abb, 0xf4b57f90, 0xbefdf121, - 0x4b2a5bc4, 0x693dbc45, 0x11ba7077, 0x43f920fc, 0x396d470b, 0xe13cc8c1, - 0x75cf03ce, 0x799235c3, 0xbede1e41, 0xfe7a40c1, 0x4e1ff3cd, 0x3f7a03cd, - 0x5b60d6b6, 0x5ace530a, 0x51ed3bb7, 0x360da7f4, 0x1fa814d9, 0x865eb473, - 0x4eb95f7c, 0x1c3d2375, 0xe27b7b5b, 0x00bf2874, 0x7582adfe, 0x50306e54, - 0x770dacfb, 0xc109fb50, 0x12eb95d7, 0x7cbca3fa, 0x4481fdb3, 0xeface3c4, - 0xf11ebfee, 0xeb68c5b2, 0xaaca183f, 0x263dc526, 0x3673de00, 0xb7d50646, - 0xdc2cd8e8, 0x532bc487, 0x1dcfdd3c, 0xdc631eb0, 0x6b63c44f, 0x18d51f88, - 0x92ccedc7, 0x9aefb029, 0xbec96721, 0x8a27bddf, 0x662bc9f4, 0xd6c8ec95, - 0xb7f3ffc1, 0xf45ea12b, 0x3649de9d, 0x58f3c09e, 0xce866781, 0x8a8fa040, - 0x7a2f5e08, 0x68764f51, 0x78254591, 0x1d5c82b7, 0x65de4a43, 0x7efd0b1e, - 0x4753df21, 0xfd0e1ead, 0x1818c6c6, 0xb45fa1ea, 0xa06629ce, 0x4e797f27, - 0xc06769ff, 0x9733467e, 0x42e2ed1e, 0x5f6a0866, 0x0a7d6511, 0x4c185aed, - 0x28b0fa8f, 0xd8f9f822, 0x813daecb, 0x5b58c4f6, 0xbfa4bb70, 0xbfa0389c, - 0xb1b97efe, 0x8fe7cf7b, 0x567d804c, 0x9ec953ec, 0xde5c90be, 0x41cafb8f, - 0xda51bf7c, 0x29bdef04, 0xf9e6f3a0, 0x9052cb63, 0x86140abe, 0xe763ae7e, - 0x5ce5f3c3, 0x018c9f41, 0xf1f9fb9e, 0xbb39d13c, 0x7f6c8ebb, 0xeebcc15d, - 0xe2ffae3a, 0xcb0fd9e5, 0xf73b4eab, 0x87f5686f, 0x53fe7f96, 0xf078a3fa, - 0x0b5e19ab, 0xe585ff95, 0xfe5c2dc9, 0x5685e56a, 0x6975c85f, 0x4e7d5bd7, - 0xcf13d20d, 0xd7e27909, 0xfe7a4617, 0x6b8f9e33, 0x9e8486e2, 0x219ec18f, - 0xea877978, 0x760e5ce9, 0x6fd8edd7, 0x5711d980, 0x665a4b08, 0xb9468acb, - 0xdcf164d6, 0x97e01719, 0xa8d4dfea, 0xedd1f943, 0xfb0431af, 0xf5f9e46d, - 0xffbe389e, 0x875e38f2, 0xfb9d2bf3, 0x92794437, 0x2f6f38f5, 0x7e3033a3, - 0x85fbcb25, 0xaf7690fc, 0x9da577b4, 0x7d59ed2b, 0xb367b703, 0x7e41dd63, - 0x5fafd633, 0xed183f90, 0xef73e474, 0xe7da28ae, 0x107b8a67, 0x731569f2, - 0xa017143d, 0x7c0deb07, 0xbcf5dafd, 0x13ec2716, 0x413b26e6, 0x1d1ccfb6, - 0x8d6f9e5e, 0xc2ff53d3, 0x40ca6fc7, 0xb6b3ee3b, 0xce50339b, 0xfff1a67e, - 0x0f0fc4f6, 0x507d7e0b, 0xe15893e8, 0xf9087827, 0xedc0ea08, 0xfef02dae, - 0xe26ec58a, 0xbe2edfab, 0x1747ca91, 0x8fe7a42f, 0xfcd265c5, 0xdc77c2b6, - 0x23a700d9, 0x17d2552b, 0x3eee8d33, 0x91def0b1, 0x1bf91d08, 0xc799d70e, - 0x3b63336f, 0xcce5f3a3, 0xf26c27c7, 0x1f01f806, 0xe90c7dc3, 0x09af9f79, - 0x9d2a5ebc, 0x2b4eb356, 0x7a6eadea, 0xb7a2103d, 0xa72f11db, 0xf6226759, - 0xfa3a55ab, 0xf3a12934, 0xaf5cc83f, 0x2366bf61, 0xd37c8feb, 0x92f5c51c, - 0x029bdfb6, 0x9ed0ab7f, 0xd433f285, 0xcce4615f, 0x7b5e823b, 0xc4ef5d5b, - 0x9333bc91, 0x56eb4edd, 0x3ef44e29, 0xb4e707ce, 0xc639f10f, 0x975fd089, - 0xc775b56d, 0xc779f855, 0x185c71fd, 0xfe4f5c7f, 0xee3aed1f, 0xd570e789, - 0x296485fa, 0xc4c742fd, 0xd9c5167e, 0xe844fc82, 0x0fe70f0f, 0x48de3aba, - 0xd510dbfb, 0xa8b8c5e9, 0x3e7e66f7, 0x55e51a4f, 0x5a95dfd0, 0xfe8858dc, - 0x71c67fb0, 0xbc7da63f, 0xf1cf1927, 0x4e8d92bd, 0x2c5ce3f4, 0x76680e3f, - 0x478138f1, 0xd358eb47, 0x03ec8de1, 0xf0ec4aeb, 0x34a11a14, 0xf8d226c4, - 0x096eac49, 0x11fa0de2, 0xa3dbf230, 0x743c8a7c, 0x213c9743, 0x91a56147, - 0xaddb77c8, 0xbc3c531e, 0x5d467437, 0x53edfa3d, 0xe23c78ab, 0x6de9e284, - 0x1b8d0ecf, 0x5e3932cb, 0xbb88aff0, 0xd0346fe6, 0x3e37f2ba, 0xfcd1f146, - 0x95eb578d, 0x1f943900, 0x27fea06f, 0x9bd39d5e, 0x851f18fc, 0x880ebf8f, - 0x4662f4e7, 0x8a10e11f, 0xbfa58687, 0x313ff17e, 0xf609dcae, 0xef3cb050, - 0x20243f17, 0x0cfaa16f, 0x3c7d73c9, 0xc07f23d7, 0xd358057c, 0x7cc8661f, - 0x8fe40d85, 0xbe6c6add, 0xde51e306, 0xbc431d1a, 0x2bf9efb7, 0xcd676bc5, - 0xb6bc5070, 0xcf7dfdfb, 0x3ff6c72c, 0x118362cc, 0x87be29fe, 0x7ccff415, - 0xc9e3c91b, 0xb1326edf, 0xd9a5b025, 0x3c53376f, 0x8e954d78, 0xeed17ca1, - 0xe832661b, 0xa0db5c78, 0x47f8e02b, 0x0ef12839, 0x7c446404, 0xfc21bc48, - 0x6e3198b6, 0x5fad02fc, 0x7e80cbae, 0xc7dc04f0, 0x4e906b96, 0x15d9557a, - 0x75c817f4, 0x4c9f485d, 0xfa69ff8a, 0xc3d467e4, 0x9c5fc5b7, 0x74819e1e, - 0x5ac3d5ae, 0x7164dbfd, 0x0bbf6255, 0x4213e1e9, 0xd7894dfe, 0x7e3043c4, - 0xc76f0616, 0xf00c1c84, 0xff19df8f, 0x1fe3fc23, 0xe3091ca1, 0xc8c67f1f, - 0x9da36fe5, 0x0c2936dd, 0xe627bcbf, 0x32eeadd7, 0x6f8cfea2, 0xb3cac251, - 0xc651ab6c, 0xfae05713, 0x2b44fc64, 0xb7c0c38f, 0xde5ffb11, 0x7b0bbad4, - 0x165ec6e5, 0x15dbe68d, 0x37b9c3df, 0x046b3ccc, 0x30163b9f, 0xea3aa38a, - 0xa82bc918, 0xb093b8fb, 0x0023f295, 0xb8e04f1f, 0x9d638a17, 0x1d9215b6, - 0x8656e324, 0xf8f3e0d8, 0xcfd9789e, 0x6fc447f5, 0xe27a0f7a, 0xb05d624f, - 0x5fb067ff, 0x141602fc, 0x9971919f, 0x62af3af8, 0xc47547cc, 0x3bdadfc8, - 0xf304b3ce, 0x3386ba3f, 0x8f5053e7, 0xa215b529, 0x72cfb53c, 0x66fc61b6, - 0x9fee29f9, 0xf98f3e5f, 0x79012a96, 0xca2c9e05, 0x05bc4203, 0x0a7607fa, - 0xac53b6f9, 0x5fe4f41b, 0x5abaf9e3, 0xa4f403e2, 0x756e87c4, 0xed784aab, - 0x02a7af0a, 0x43fedaf0, 0xf919fd78, 0xe48b9df2, 0x852f0fcb, 0x9171fe6e, - 0x8c4bf374, 0x3b090c6f, 0x578867df, 0x67407ced, 0xbef88347, 0x78db3a07, - 0xf9d2f189, 0xa7a89fe6, 0x5dfae142, 0x5c28427c, 0xfaeb1657, 0x5166bc91, - 0xd57a70ce, 0x4ffe6096, 0x12d891e7, 0x1e7a5c86, 0x3b7bfac9, 0x1967888d, - 0xd5eb9107, 0xf6c88fe6, 0x0f25169a, 0xbb859fcf, 0xe039d3cf, 0xe8bfdb74, - 0x079a101c, 0x0f9de7c2, 0x39fc8de4, 0xdcd01d56, 0xa677fc0a, 0x752748c9, - 0x377e3995, 0x7bf7fd0a, 0xa0e7cc0d, 0xffd811fe, 0x5ffbc60a, 0x03bcb4d1, - 0x305757fd, 0x479c57bd, 0x1db9ef95, 0x7c7c8315, 0xf2955ec5, 0xfe66d8bf, - 0x2c458ebc, 0x4c74ff41, 0x02398e81, 0x8aeb19e0, 0x78008e62, 0x07b78dc6, - 0x7939e5d5, 0xc13798ae, 0xfde82bdd, 0x82b31ba4, 0xae78a7fa, 0x3a9e7a08, - 0x9ea8372b, 0xa822375e, 0xa385ef7f, 0xde99ea83, 0x67fa836b, 0xaa0e4c37, - 0x1cde34e7, 0xab18ffd4, 0xec147c7b, 0x5bfa3fb3, 0xebcc3f00, 0xd60cb8ea, - 0xb7ac433b, 0xa0f29aef, 0x5afd81f7, 0x53381e31, 0xcf17c990, 0x00abdf8d, - 0xff08671c, 0x39bee5ce, 0x55cfe341, 0x677e88ab, 0x048e1a36, 0xacf469fa, - 0xc02a4f6b, 0x38a7c6b9, 0xb95ea15b, 0xecf9f826, 0xbde81b1d, 0xf6e0bed9, - 0xeb839bb9, 0xd29cde83, 0xb901e79f, 0x4672bf29, 0x87dfb042, 0x9989d085, - 0xb599f4e4, 0x7aa5ffdc, 0x24e86afb, 0x27ec5f18, 0xd0438dd2, 0x9839298d, - 0xc11d226e, 0xfaf95374, 0x0708a1d6, 0xfba3fc2d, 0x0bc9e869, 0xfe007eff, - 0x7d306716, 0xfb4ee169, 0xec567583, 0x95efd850, 0x6acfb850, 0x2a797879, - 0x633b850b, 0x1fd7233e, 0x688fedc1, 0xd981fde0, 0x89ca18f3, 0xa8163bb3, - 0xe3638718, 0xecff3c79, 0xed07af8e, 0x2f898473, 0x97c484e5, 0xf80425d6, - 0xe97c647f, 0xaf19c634, 0x67111764, 0x844ffddc, 0x8f00c807, 0x0b11f301, - 0x71dd119c, 0x3c7f48c5, 0x653f2b49, 0xb9e3fa09, 0xfe2bd204, 0xbc3d6c78, - 0x03e6343d, 0xc653ae37, 0x8ebe64e5, 0x930a2bcc, 0x8497fc9f, 0xb40fcc04, - 0x75f9e347, 0x3a7cfb4b, 0x22bcc977, 0xc302f226, 0x4fa4ffd8, 0x14d7f19a, - 0x26760bb2, 0x0afebd70, 0x176dd78e, 0xa92fbc88, 0x471a7bd7, 0x2a7adfc6, - 0xc52a5d95, 0x2894bb13, 0xf46153e7, 0x3f0947ca, 0xe685bf51, 0xa8147f8f, - 0x38ee6a47, 0x0bf507bb, 0x6c63fdc0, 0x6f4058b7, 0xfdbd7e2b, 0xd12b68bb, - 0xaaebd76b, 0x9c342faf, 0xd8c47089, 0x222d8e01, 0xe445afdf, 0xd6f5c9fb, - 0xf4baa445, 0x9c1ed879, 0x8ae327ff, 0xc28dfdda, 0x3afe71fe, 0x976417bc, - 0x76e5cf2c, 0x870169db, 0x276e160d, 0x9db91318, 0x1f39ab50, 0xfb7036d5, - 0xacd7a40c, 0x8c718096, 0xdfea1689, 0x4c685cdf, 0xdf8471c4, 0x42a67965, - 0x4572c576, 0x77e47b21, 0xfcf4d1b6, 0x868509cf, 0x6fffe844, 0x6011af31, - 0x16636588, 0x93438f5f, 0xe892fe17, 0x68c252ff, 0x36898d2a, 0x5db67fe1, - 0x6a91f481, 0x5da91976, 0x8aa71f0d, 0x1afbe44e, 0xb464f229, 0x42718071, - 0xdfdfa26e, 0xe2d2edc4, 0xfe4189b1, 0xf18cf7fe, 0xd0afdfc2, 0x53942eeb, - 0xef7814bf, 0xeaefffc9, 0xf1476b67, 0xaffff5ad, 0x7ffee48c, 0xf1081f19, - 0x85c73bff, 0x1e23fff5, 0xfe7eeda2, 0x2dd893e9, 0x3e50d29f, 0xea7a30ed, - 0xb5d5fcf1, 0x6878ec1d, 0xa4ebe7ee, 0x7dc0c0b8, 0x673c4ed9, 0xbb64cf2d, - 0x4b6f482c, 0x7f3b4318, 0x696ea747, 0xe95f3c24, 0x3e7c3665, 0xbf3f2d7c, - 0x3871ae55, 0x0e529b71, 0xfdc89d5c, 0x1f380687, 0xbdf1725b, 0x27186dc9, - 0xd9953958, 0xb2350d51, 0xda2b22c6, 0xd8596b45, 0x4168e3f3, 0x770a134f, - 0x4276fe51, 0x0fb7cf17, 0x7693a7ed, 0x73e2217e, 0x2ce79758, 0x7971cf8f, - 0xcf112242, 0x5f3aeda9, 0xb27d73b8, 0xa46ae8ad, 0xf0be81af, 0xc29188e7, - 0xbb32e64f, 0x03f8e227, 0xd87cf1b7, 0x677f294a, 0xf01e98e8, 0x75e0453e, - 0xd79e5aca, 0xff7fcec1, 0x45ed2abd, 0x9433e346, 0x2d53952b, 0x5513f43e, - 0x697a64b6, 0x99c56e5d, 0xe5a2f283, 0x2bd6376d, 0xe86df3f3, 0x9dfd7097, - 0x91fb4729, 0xfcb8c9a9, 0x52a3b3d2, 0x8f1e909e, 0x64d438a7, 0xf1236f41, - 0x72409cb0, 0xc034657e, 0x92ed72bb, 0xf3d7985d, 0xc5191ffe, 0x5da80e9b, - 0x5fb07143, 0xe6167001, 0xa567a962, 0xa648b7e4, 0x718aa671, 0x7982ffbc, - 0xfef3fc23, 0xda75e5aa, 0xf30301cf, 0x9d1d0046, 0x038379de, 0x09e5eeed, - 0x93cfe411, 0xaa83da71, 0x42523ee7, 0x5c1aaefa, 0xd12d4dda, 0x9c83f436, - 0x3a61f9de, 0xb93e4dc6, 0xed05ace7, 0xbbe87fd8, 0x7c2f982c, 0x16bbd17c, - 0x93f1c017, 0x9de52a45, 0x86f42add, 0x897dfb84, 0x271fee1c, 0xdc2117ba, - 0xddfc5b6f, 0x2a3cc0d0, 0xe88130b6, 0xa54fb679, 0x9cb75c90, 0x168d1cdd, - 0xbabd774a, 0x2ea82e39, 0x89b540f5, 0xbf3b85d5, 0x69e824bc, 0x6306d376, - 0xf7e703aa, 0x38fa42ac, 0x7474e7ae, 0xe7c59b7c, 0xa7aff4cd, 0x11b069bc, - 0xb47f83ed, 0xea2b5898, 0x81877d33, 0x8abb49e7, 0x8f0ba015, 0x9d76bfc0, - 0xa68e5e7b, 0xc63e66f1, 0xcc1947e5, 0xebe010b5, 0x724d9969, 0x998fbb41, - 0x25c6389f, 0xae675c01, 0xe3fa1850, 0xc022ffb0, 0xfde1679f, 0xa5fda15f, - 0x379967dd, 0xf9480e58, 0x3cf02955, 0x79f821bd, 0x696fcb65, 0x43cc199c, - 0x27602079, 0x735f9e69, 0xd80af50c, 0x67ed4147, 0x519b66f6, 0x14496f8f, - 0x6ca1edf1, 0xfef0f7d8, 0x18ec88ae, 0x927e184f, 0x36c5c9e5, 0x17cfd622, - 0x7c795047, 0x5172a331, 0xaae3a722, 0x44efb796, 0xc766a97b, 0x738e2316, - 0x9681f1c9, 0x999bd613, 0xe896ef5f, 0x1e21af3d, 0x28252cd9, 0xe1b3504e, - 0x32ec91ac, 0xd1529f01, 0x00f08a5e, 0x1cc2dc3c, 0x503cf1ab, 0xc7f0655a, - 0x5bffe0e9, 0x60c3bf72, 0xd1da80bf, 0xb5173991, 0xb94fb95f, 0x5abcf96f, - 0xf30c7a05, 0x4583e4be, 0xd8cd1f42, 0x2f796938, 0xcefd5100, 0xfc9d1963, - 0x78f649bc, 0x516bc091, 0x8f64fdc4, 0xe3d88517, 0xb7dc3dec, 0xe64ac7a4, - 0xa5a23d24, 0xcc07493b, 0x23f7a06c, 0x4ddebd84, 0x120f2d6f, 0xcc3d245c, - 0xe4685d5c, 0xc8c79be6, 0xb26f4aed, 0xa326d7f0, 0x30e816bf, 0xba063ec8, - 0xed6baa0b, 0x9d0d2ff1, 0xb41f2819, 0xe7ccb876, 0x60e7c2d4, 0x9a5fcf22, - 0xb38d70e1, 0x8073c00d, 0x85f9397b, 0x10ca46f1, 0x3dc6dbe4, 0x6edf2377, - 0x0ff37ce4, 0x92b30f41, 0xf049113c, 0x9af4b3dc, 0xe77fc41a, 0xf2065312, - 0x8a6967b3, 0x3dfd0f1a, 0xc39214ab, 0x18a697a3, 0x97d3ce11, 0x7c871e0d, - 0x345ccb9d, 0x1638b4fe, 0x9c186ed6, 0x7947e5c4, 0x6319819d, 0xf4462908, - 0x506a9f0b, 0x9a8c2fc8, 0x6be02264, 0xf557c096, 0xa4adb78a, 0x6ff01caf, - 0xe01f5e28, 0x2aeab33f, 0xee701f09, 0x52c7cb08, 0x66b154af, 0x3b8c0a63, - 0xd11b6567, 0x82479c31, 0x95b2d7fa, 0x66eaaf84, 0xd5dd7b4d, 0xb9d83f84, - 0xb589cf11, 0xf79f823b, 0x8276124f, 0xbe913993, 0x225a773d, 0xb471af30, - 0x4ad94f80, 0x6b7286c5, 0x84b6b2fa, 0x7d3ea01b, 0xed84eaaf, 0x8587c374, - 0x1f2823fa, 0x1cdecced, 0x719c57f2, 0x9fb09238, 0x52edcac7, 0x8619ef45, - 0x3ce2d3ed, 0xd8cfd0c3, 0x618591f5, 0x73a1df7e, 0x11e4732a, 0xfca20f95, - 0x341b1b2a, 0x2fbec029, 0x3112d833, 0xf365e91e, 0xb83dc593, 0xd4f84088, - 0x7e24ac46, 0x887e45a8, 0x34c3f3f0, 0xdda17b8c, 0x7942a2f3, 0x30476c84, - 0x34709fbd, 0x9091c226, 0x9033efb9, 0x8a6f2e9c, 0xf971f3a5, 0xea2322b2, - 0xb16df2d5, 0xf9c11f64, 0x86cbbdf4, 0x6879f1fa, 0x649ede59, 0x39bcb718, - 0xe306a9d3, 0x19dcf431, 0x0d39ceb0, 0x8efe2487, 0x23bf80f4, 0x7807f0e1, - 0x4f2f6a0b, 0xe0497212, 0x238a2d8d, 0xef3a5abd, 0x58089cd5, 0x48ba99d7, - 0xe9ec93ca, 0x8c66c47c, 0xe903fca0, 0xabdf1abf, 0x7944cfdb, 0x0e57673e, - 0xf169fc21, 0xd3dffe36, 0xcbbda187, 0x68616efe, 0x66cb4d67, 0xf6864db7, - 0x6fce14db, 0x19afead3, 0xddc4768f, 0xbd9e5c49, 0xd5d07205, 0x41b7b197, - 0x0e40ba0e, 0x11f20bbe, 0x4e2fefeb, 0x8b87faa6, 0xb47e541d, 0x47951fb8, - 0xf25fbf84, 0xd102101d, 0x2e2492ed, 0xc9249717, 0x6482faf8, 0xffc66934, - 0x3a21ddfb, 0x6c67de1b, 0x9d36309b, 0xc15cebb1, 0xa9c6f7fa, 0xd3b5fac1, - 0x8c971b60, 0x0a15dbe7, 0xeee5a3d9, 0xe1fd4191, 0x7bc464dc, 0x9e5fac2b, - 0x86f49dbf, 0xe81938c3, 0xb8e2a6f1, 0x37d7fea0, 0x9fd506a4, 0xfad07248, - 0x0ecf8d26, 0xb4b9bf6a, 0xecbd507f, 0xa431919c, 0xf1014777, 0x679102cf, - 0x8e770704, 0xfbef1b17, 0xa4b0dd75, 0x5fbd60bb, 0x73d033ef, 0x5e243e2d, - 0x9951ac67, 0xbe9bc607, 0x2c1fe406, 0x74e348f1, 0x0e2fafe2, 0xb25ce858, - 0x7f6f29bc, 0x350fd401, 0xe80f2819, 0x55b8b2d0, 0x6a1daf68, 0x2832b04a, - 0x6155cb3d, 0x2c8cd8d7, 0x2d15de40, 0xa6f9425b, 0x93933e65, 0xef7697ec, - 0xc0eeb293, 0x122e2af3, 0xd53de4f9, 0xfe10aad7, 0x67df045c, 0xe15ee922, - 0xf127b071, 0x4ef4e12a, 0x0ae3aebe, 0x13f5865b, 0xb9f71f91, 0x6a71d60b, - 0x0e856362, 0xbeea15fd, 0xcf9f9204, 0xb6e90cab, 0xf2819e74, 0xafbf660c, - 0x533ac06e, 0xbe395372, 0x66a3ca55, 0x7c6898cf, 0x021405d6, 0x6d3c16fd, - 0xae01ea7a, 0xfb7d78ff, 0x8203df40, 0x8e8e913e, 0x2c5732c7, 0xf5a1562d, - 0xc276fe7e, 0x87ee7c06, 0xee106fa7, 0xfdc1bd7b, 0xefe01266, 0x20df0af3, - 0x128b6f92, 0x70b4af88, 0xf2e4623f, 0xa07c8bcb, 0x9fa6e5f8, 0x7e9296cf, - 0x26706e98, 0xe56e493a, 0x3adca0a7, 0x7640d2b2, 0xacbbd330, 0x3e8f4893, - 0xe72c744f, 0x8c77a239, 0x691df5c3, 0x5f9864c8, 0xa552be51, 0x1fd20af3, - 0xe7e3efef, 0x0f5587d4, 0xdbcc24d8, 0x525878a0, 0x3edcdd28, 0x5de5186f, - 0x596ded6a, 0xeabc097e, 0xe64bb009, 0x8179e4ec, 0x3f53bf2c, 0x3ee06075, - 0x3cf9f196, 0x4af94105, 0x1daf5955, 0x2ec8eb34, 0xc273c18c, 0xa254f789, - 0x8d5913b3, 0x9f019343, 0x86bb7527, 0x2ff505de, 0xea8f7a26, 0xda223ea1, - 0xeb842ff3, 0x0ccadd5c, 0xfaf30b25, 0x091aaf0f, 0xacfe7def, 0x2e6c49c1, - 0xcf39fcec, 0x43fdeecc, 0x1bd815f6, 0xe1ddb8bd, 0xcffbc14a, 0x1acd1d73, - 0xc7c3807b, 0x00204981, 0x056adb17, 0x7876376d, 0x3c01e588, 0x31d74f57, - 0xe079e04f, 0xb1e3c8b0, 0xa873f324, 0x24a61bb4, 0x5d333973, 0xbd9be9c7, - 0x037a70ac, 0x0f502afb, 0x173db948, 0xbf55aaf3, 0xbb72901e, 0xfe52358a, - 0xdb99238a, 0x1f15b32f, 0x9835ddd9, 0x2bfd0289, 0x56683c6c, 0xf3e4d9b5, - 0xb698d265, 0x7a60fb40, 0x73279732, 0x8e3ecf8c, 0x3ac95be4, 0xfd353ef8, - 0x2af8373e, 0xf543323a, 0xc36d854f, 0x6f8d3b32, 0xb79fa270, 0x756bf052, - 0x256be2a3, 0x51eb853b, 0x299d57e9, 0x3f56a8f4, 0x8d25e885, 0xd1a99a3e, - 0x5831acbb, 0xe97ac2cf, 0xaf5cb2de, 0x68ee9d76, 0x0e61c10b, 0x6ff50bac, - 0xa7b7c785, 0x38add684, 0xeb21a301, 0x31ee64a9, 0x780fb8b1, 0x5d08eade, - 0x215f769f, 0xd4fb15eb, 0xf9c2bbae, 0xbbe62b55, 0x04293554, 0x243eed2f, - 0x9c76b43e, 0x97854bc4, 0x45a2b7c3, 0xd67e7c21, 0xf2321f6d, 0x61ba4b6f, - 0xe02ff0cd, 0xb047497d, 0x6f9412af, 0x1e41ab95, 0xd3d28667, 0x456cd61c, - 0xad61a9ba, 0xdf9053cb, 0x1faf9b5a, 0xb5867e8e, 0xa9f9d36f, 0xa39aded4, - 0x7a50058b, 0xbf8e5773, 0x17e74fca, 0x5cfc278a, 0xe9ddc3f0, 0xe01e9fa5, - 0xeaa37335, 0xd4141c8a, 0x7a3fe44f, 0xbcb38e09, 0x63fa235e, 0xe53f0967, - 0xab59d685, 0x2e5ff7e7, 0xcf015eb8, 0x0fdd7b9f, 0x7764f727, 0x76173f85, - 0x3d1a5bdb, 0xfb81b1ff, 0xfe7ca55b, 0xff22ef5a, 0x3b0bb42e, 0xe3c6ceac, - 0x9eb91a7d, 0xbd724f9e, 0x3979e842, 0x5b35d1cf, 0x13305e29, 0xf68080ed, - 0xa56f56cf, 0xd9f1a578, 0xcbb45699, 0xbe99ae8f, 0x8f52f30a, 0xbd274d36, - 0xa97bf95f, 0x40c63df7, 0x4d68a27b, 0x907bfad9, 0x5247378e, 0xdda2b15c, - 0x2045ce23, 0x639fa167, 0x6cab970d, 0x95b39735, 0x90071fa8, 0xfd8bec7e, - 0xf4f0acee, 0x68087e45, 0xe779bd27, 0x779fcf74, 0xfe77b8c2, 0x25e9da29, - 0x755ad850, 0x5adbcf64, 0xcf563f51, 0xde20f0ff, 0xe07b01d3, 0x7b4b5ffd, - 0x0645aa00, 0xea325b4f, 0x54076121, 0x6c321bab, 0xbd083768, 0x7f801ff1, - 0xe7f87844, 0x11cbfc12, 0xdbf101fe, 0x9c381b4f, 0x7fe06ba7, 0xcbc72578, - 0x2b6ca6f2, 0x6d3f2f9e, 0xebbb26c8, 0x821ca6d3, 0x00078cff, 0x1f5fdcfe, - 0x0035776c, 0x817cf1fc, 0x96f587f0, 0xfc043bb7, 0x0dfe1c9d, 0x256cee1c, - 0xc084672f, 0x57f94bd9, 0xe4d1fe77, 0x78e23b44, 0x57d92b64, 0xaca8b7c7, - 0x932ec03e, 0xac37d176, 0xdfb449f1, 0xf767fc24, 0xf28418e9, 0xd7e1f4a7, - 0xd98788ac, 0x3150785b, 0x95ccfe04, 0xeec7f144, 0xa8edbbf9, 0xdd5f116f, - 0xe245d476, 0x19b986a9, 0xd796c7e9, 0x4239e00e, 0x45bf7171, 0xb66fbc8d, - 0x19bef823, 0xda9592e6, 0x8ce2c5d1, 0xa4f5c088, 0x79d3ef69, 0xbebdc618, - 0xd6eaf9cd, 0x5de7c4f9, 0x25b97941, 0xfe80d5ac, 0xd0acd636, 0x05eaed3d, - 0x8642d685, 0x5a3ab571, 0x09453387, 0x56aecbca, 0x564f6475, 0x447c4519, - 0x892455e4, 0xdc29497e, 0x629c902f, 0x2474f2a3, 0xda707d23, 0x7de1f462, - 0x255f382a, 0x9ddefce3, 0x41dbc226, 0x5fc0135c, 0x333f0a35, 0xb7a442a8, - 0xd3a7185b, 0x297bcc5b, 0x972707ae, 0xa71fa875, 0xc939342d, 0xa18f8dce, - 0x42cdd2f8, 0x5e62ddde, 0x313d46ee, 0x61746ccd, 0x317ae309, 0x1a30d7f9, - 0x0df987a6, 0xef748cbd, 0xf3a234b0, 0xdf123c59, 0x8ef87c96, 0x95ea5808, - 0x1fa38e60, 0xf6dd7e18, 0x5e285c7d, 0xf609f8fc, 0x8546d74b, 0x170c8bf7, - 0x2e5c5070, 0x609b3ff2, 0xc75828ec, 0x6f0714a8, 0x3fb8d877, 0xc9e02d7a, - 0xb6afc7e2, 0xfc79799d, 0xb1f30ab2, 0xbc58f7f9, 0x5d541f24, 0xc8cabd50, - 0x62794f9f, 0x34eaf143, 0x8e61dec6, 0x2ab78881, 0xee782194, 0x61f18b2f, - 0xf43aef7c, 0xd4b1db87, 0xd64cbd13, 0x978eaf33, 0x0e3b660d, 0x25e3fdc7, - 0x2abf9e02, 0x0031ad60, 0x83d7d6f7, 0xb437f3fd, 0x02fb5aea, 0xb7d3af7c, - 0xea7d21b6, 0x1b061c22, 0xaf1ee3cc, 0xa539e2e4, 0xadc5e96a, 0xa689e2b7, - 0xa0a3d5e2, 0xacf9e3ae, 0xfee6bf5d, 0x59805b89, 0xeab76e11, 0xcb9abb59, - 0x52e100e9, 0xa978776b, 0xe2853cdf, 0x202e3237, 0x86183ff1, 0x2de3c40f, - 0x4e307d62, 0x37df1583, 0x7cd7c786, 0x8ccc2f81, 0x15cfb846, 0xf257377c, - 0xbf30535b, 0x0478823d, 0x2ed0553e, 0x22ddb806, 0xe2f89eca, 0x476e14a1, - 0xcfc2943f, 0xe25cf7ef, 0x95dccc7c, 0x82797941, 0x7c4daa5f, 0x75ff397c, - 0xc5307ca2, 0xf5cbe34e, 0x8a7ebd00, 0x0240e8e3, 0x691ebd20, 0x68fb27ac, - 0xc3880b16, 0x49fbfa65, 0x77ad0eba, 0xf7dd11cb, 0x66bb1a58, 0x5f95e820, - 0x8e513a44, 0xce6c62de, 0xf68733a9, 0x52e67193, 0xefa061d6, 0x993f4903, - 0x55633fd0, 0x9535e533, 0xf41efc2a, 0x578b42e9, 0xc7e27607, 0x067bbe22, - 0xa79c46ec, 0xfca15634, 0x773169af, 0x975f2096, 0x2c7a8d5a, 0xdff1163f, - 0x8d17595b, 0x2b2d89ff, 0xdf8606e6, 0xe631504d, 0xa4f80b07, 0xadfb05d8, - 0xebc3f947, 0xe4695d2b, 0x4ff5128d, 0x665c61f7, 0x03a079ea, 0x762e1faa, - 0x5fa7bcc1, 0x91d9cf15, 0xfa7e7c62, 0xdecf413e, 0xe9de34e3, 0x53f3e4c7, - 0xf90af9fc, 0x7f5e2bfc, 0xea2f8e50, 0x2f9e6b0f, 0x827f3cd1, 0xf89f5bd7, - 0xf68bd8aa, 0xda4e68eb, 0x921423a5, 0x37214657, 0x12b6974a, 0xbb754b9c, - 0xb59a3978, 0xdc2ff2ea, 0xdb8a64ef, 0xf7809298, 0x50588fce, 0xd533ff0f, - 0x7e814c65, 0xfe79269f, 0x499ce586, 0x7288d78a, 0xe91f3df7, 0xf21e9285, - 0xae428d27, 0xa6e5ea9f, 0x831ea5f7, 0xf1c3de71, 0xbb9c752f, 0xe4f9c743, - 0x4d738cc7, 0x4738c86a, 0xfebecc7f, 0x24e1ca9c, 0x517691c7, 0xe94bba71, - 0x663afc85, 0x70bf9064, 0x18cebdee, 0xcc314bf4, 0xcfd00377, 0x919cda5d, - 0x7dcfe307, 0x0a8cc5ee, 0xbe849bb4, 0x32a739af, 0xdaa3c817, 0x5f950a73, - 0xc4647db4, 0xdb35b37b, 0xa0e38cda, 0x45942d5f, 0x12aaeb01, 0xa77d04eb, - 0xa7a01c9f, 0x4274bd8d, 0xf3cc3c6e, 0xa13b9e32, 0xd5ce7c47, 0x3dfd1f35, - 0x4a11efea, 0x97f2f8d8, 0x7b077f62, 0xee611fb8, 0x6151e5c5, 0xee34576f, - 0x390614f3, 0xfaa2fc60, 0xbf02f9f0, 0x1528eb12, 0x50fa6ffa, 0xe003844b, - 0x1e3de43c, 0x9b58af5f, 0x62fe8b99, 0x04e8f263, 0x7e8f5b82, 0x67ee2ed6, - 0xd67ee16d, 0x02c77b52, 0xbb994efc, 0xf883ec57, 0xbf09b2dd, 0x2c067c93, - 0x378eef0b, 0x89bf7ac9, 0x3f714663, 0x7ef3d618, 0xf220f99f, 0x6e28decd, - 0x361b4ecf, 0x43e50a30, 0xceb46667, 0x4facfc06, 0x4af7732a, 0xc6abf6c0, - 0xc9a17b61, 0xe08ca7d2, 0xf42e88cb, 0xb8feee49, 0xfe8fec4e, 0x35b18f11, - 0x87d806e1, 0xee950de7, 0x45067803, 0xcbc5c27b, 0xe5c5ef2f, 0x8d97bbb9, - 0x0757b1e0, 0xaff5cceb, 0x760fce43, 0x180e82fd, 0x94d2c8ef, 0x30380fc1, - 0x5d78531e, 0xfcff04af, 0xa33c92b3, 0xa23fe702, 0x68f07d63, 0x18ebb171, - 0x1d71f02e, 0xf74a06c2, 0x80b7a028, 0x31e4def3, 0xa9f541d1, 0x15cc71c5, - 0x9a9dbfe8, 0xb1bf541a, 0xffa83b34, 0x07fa33cd, 0xea689f3d, 0xb00bafc8, - 0x97b67b67, 0x5a9f04bc, 0xed0a258b, 0xbe5a4fba, 0xb416e0f9, 0x4eaa3703, - 0xef6759b4, 0x48c1f4dc, 0xf00675e8, 0x497e471b, 0x3ed1f907, 0x7a747997, - 0x7e303e97, 0x50758a74, 0xd73ca2be, 0x68dc6c5e, 0xf29dadae, 0x78ae7f09, - 0xe25ebcd1, 0x72cb9bfc, 0xa99e3f51, 0x79fc9f7b, 0xcfbe6635, 0xe21e2f53, - 0xbd442ddf, 0x357f7402, 0xe2f688be, 0xc0fc1039, 0x0e3b45ff, 0x86cd9c51, - 0xf7b44dc1, 0xf1e9e6d3, 0x942d64fe, 0x81c65fa8, 0xba018adc, 0x036368e9, - 0x48de61b7, 0xe5db85a6, 0xbf90a6e7, 0xf7146f7c, 0x8c4decfb, 0xcc48efa5, - 0xda86b86d, 0xd345ce6b, 0x1da96ff8, 0xfa2f28e3, 0x13e28505, 0x2da75313, - 0x8decfdc5, 0x1db80ef2, 0xe7f89de6, 0xdc23c7ab, 0x7bf1b66a, 0x77d51302, - 0x5941e7f2, 0xbd0d78d5, 0x7b65513f, 0x621fb015, 0xe342ddce, 0x001b444e, - 0xcb50eaea, 0x5597a803, 0x3f9f6b63, 0x5a31bca0, 0x9ed4de48, 0x26f7a48b, - 0xfdfd7114, 0x0c4f217b, 0x635d7c9d, 0xe7a24dcf, 0xbd7c2e92, 0xf7f282b2, - 0xf51b090d, 0x4321bdf8, 0xaffd42a7, 0x4a9fd73d, 0xfa37dfb9, 0x2fbe91fd, - 0x7af84860, 0xbe8de61c, 0xc8d8af11, 0xe3c8d12c, 0x62c375b3, 0xd5791858, - 0x9e39cf3d, 0xc73a6c6f, 0x3bff8ff3, 0xe417f5cd, 0x9d4592c3, 0x31178c7a, - 0xe10d8473, 0xd8305255, 0x67c01151, 0x8c9baeea, 0xeac31f88, 0xafa88db7, - 0x0516504d, 0xf916af3c, 0xdd795a58, 0xfc83e422, 0x3fd49b8e, 0xd106792c, - 0x4136ade7, 0x9e8f82a0, 0xdf2c7c16, 0x0e33a0ef, 0xf73b71e0, 0x79a6b7f3, - 0xd13942de, 0x7c6ec851, 0x4767e49e, 0x7e69c606, 0x9e03f5ae, 0x1bb21423, - 0xbeaf293b, 0xc3a1c0a4, 0xdd7bc0f8, 0xf3f3877a, 0x26d1f685, 0xca96fdf6, - 0x6fb8e216, 0x1d97f2fd, 0xedaf182e, 0xd43cbcee, 0xcfde720b, 0x0b7bf17a, - 0x1e75d6cc, 0x2fb587cf, 0xef903b47, 0x0ce1e227, 0x4d3ba2e3, 0x76816e74, - 0xbed4778a, 0xef0a7a6c, 0xe15ad5bb, 0x17f30afc, 0x8ad912bd, 0x4af6dc74, - 0xc7f51ea4, 0x9f3dbd1d, 0x5e8a7c21, 0xcf063be9, 0x9316ae8b, 0xe3fd919e, - 0xb6f24a3a, 0x485ef587, 0x4ce9697e, 0x81a7a7f2, 0xa0994bf3, 0x7fc172d3, - 0x6747c11e, 0x0f8892eb, 0x45822ecf, 0x91753c63, 0xda1b7032, 0x7d0b0e0b, - 0xe5f24e97, 0x411f3c44, 0xb1fec4fb, 0xeaa18f74, 0x1f106c5c, 0x14cb9f56, - 0xed471dfc, 0x05cadf92, 0x7d84989f, 0xb5d04331, 0x3f245bb4, 0x624f74b2, - 0x6263ec2a, 0x95bdf03d, 0xc8f9fee2, 0x31ba7e4f, 0x80be90da, 0x022b926e, - 0xedbea7f8, 0x8a768626, 0x744dde29, 0x40ca0333, 0xb766653b, 0x971b629d, - 0x592feb08, 0x7bc3a996, 0x6a79f29b, 0x7fd1a5ea, 0x27c8aa44, 0xa0e6b730, - 0x8ba86b5d, 0x9a7de274, 0x1e3cf133, 0x87057f34, 0xbb837ce3, 0xf98ced08, - 0x3fe4284f, 0xe503fb43, 0x7503d0d2, 0xcabf40c6, 0x5106e74d, 0xb9ca7d3c, - 0x2634a8cb, 0x38472e7b, 0x5ebb9d94, 0x8fd06be0, 0x710e3f8a, 0xc192bf71, - 0xc86e7267, 0x4792bf44, 0x4f1f3c45, 0x0347b667, 0x546b7de3, 0xb8c98ff2, - 0x9933f4a4, 0x804fdef0, 0xdf46fd3e, 0xa3df4198, 0x0a9dfad1, 0xb93ffeb9, - 0xbffa40d1, 0xa19dedaa, 0x79fe783a, 0xf5092ba6, 0xa7837ac9, 0x6733f708, - 0x0339efb2, 0xb83ee7d4, 0xe1dc3ad5, 0xbeb36787, 0x69f50735, 0xfd11c033, - 0xd52bcd5f, 0xf76e3ef1, 0x1a38f344, 0xcf496fa7, 0x739f3a5a, 0x73e09b2e, - 0x7a44ceb6, 0x2dd02ce8, 0x5243d00b, 0x2f3948ef, 0xeba48ff5, 0x5f973d6a, - 0xca18e6d5, 0x9debf323, 0xa442ee49, 0x1f3c7ebb, 0x9e77afd0, 0xf902355a, - 0xe53c74e0, 0x21bd4b5d, 0xc585e0f9, 0x244794c9, 0x03e492f5, 0x7ca5cf29, - 0xf52f7497, 0xfd3fe8d6, 0xc3bfd6ef, 0x3cd293af, 0x7d02a577, 0xfae7ab5d, - 0x85bd5aeb, 0xfc6c67e8, 0xcdd23d24, 0x43d1cbc5, 0x0a1e8e42, 0x3d35a392, - 0xa94581e8, 0x1c5e7e52, 0x7c11cc1f, 0xedc4de33, 0x81f39448, 0x8da6b5e3, - 0xb1f7087e, 0xd9eb953a, 0x3ddd6b9f, 0xa9d5ffc9, 0x97ff2697, 0xfc9c5ea4, - 0xfe54efff, 0xbcad0a9d, 0xa3710fc7, 0xf3bd3fbc, 0x83ea1f72, 0x03f40c83, - 0x6896c1ea, 0x0fa126c7, 0xc5445f48, 0x1f487ef8, 0xfe9ef614, 0xf5e1a9df, - 0xff6c66c1, 0xd240fab1, 0xc91be497, 0xb42f9227, 0x62f9247c, 0xbce16fc2, - 0x8b7a7888, 0xd6aa8fdf, 0x0e289b7b, 0x8c1e88e9, 0xc76dd9fc, 0xdf88536d, - 0xe084f442, 0x04bf3f1f, 0x1fc90deb, 0xff245f92, 0x98fe0b54, 0xf243f829, - 0xf9b56ec5, 0x0a9811d1, 0x08f9e690, 0x93e488e5, 0xfab5e7aa, 0x42ba47a1, - 0x199b234f, 0xae90c75f, 0xa40ca1aa, 0xfc0f532b, 0xf512f070, 0xa48bbec2, - 0xf3feafa7, 0x0f55f4f4, 0xa7e674f4, 0x1da853d0, 0x03be61fb, 0x1f3673d6, - 0x9fa66de4, 0x8dfc26de, 0x9b21fb71, 0x46f6079f, 0x35ee7df1, 0x67ff93a6, - 0xcf3cf7c2, 0x3303da57, 0xd241bf85, 0x01d81e69, 0xf8fc4369, 0xbcc0f3c7, - 0x847b938b, 0x877c5367, 0x3327cf11, 0x03b40ca1, 0x537fb27a, 0xee4d2ed3, - 0x17fe8a45, 0xb480f3c2, 0x1c6edd9f, 0xaf1e1690, 0x027ed303, 0xa262275e, - 0xb22bf92a, 0x00a35c4b, 0xba890f3f, 0xc2094fb7, 0xf902faf1, 0x2e55b2fc, - 0xd607ca3d, 0xf475ddfd, 0xcaa5bc77, 0x31fece7a, 0x8f099eb0, 0x1d1fbf32, - 0x151d8f9e, 0x511fedd3, 0x717fbf98, 0x95fed65a, 0x451be7a4, 0x9ea74ade, - 0x3d4483c7, 0x8096ea1f, 0xbea6817a, 0xeab7f796, 0x3e60593b, 0x928dd209, - 0x0eecf1cb, 0xfa601fb0, 0x2fa8b3f6, 0xff430a6c, 0x86fc6d46, 0x5ca2cf57, - 0x6c50a1db, 0xde0e1baa, 0xfa070481, 0x07d5383e, 0xc65d77ef, 0x78dbcdd8, - 0x43b5f6fd, 0x132f7956, 0x1bdc06e3, 0x2e2b3432, 0x502847ca, 0xa199597c, - 0x4d3dbef0, 0x1eb913ca, 0x0214f746, 0xaf9867de, 0x77ef2977, 0xd1674de7, - 0x4ba6adfb, 0x5186ff98, 0xac6fefe1, 0xe4c6fd10, 0xfe7d84c7, 0xe1ca9a70, - 0x3406fc2f, 0x694d343f, 0xff9f7f0e, 0x1d2fc109, 0x78213f18, 0xfe855a4e, - 0x84a30eed, 0xc2157bb7, 0x41632c7b, 0x9f98347e, 0xbad71bea, 0x7cf41a4b, - 0xbc0d2ebb, 0x77bf687e, 0x03db05a5, 0x5f069bf4, 0xf7801fa6, 0x77de61dd, - 0xfadfbf04, 0x125af843, 0xdba0bef2, 0x5d8e9259, 0xa31ef441, 0xc67d1377, - 0xb4362bc4, 0x91dc6ba3, 0xe0bcf12b, 0x12d2cfe7, 0x138c9b82, 0xb4dff084, - 0xc8033192, 0x6fcf124e, 0xebfc855b, 0xe7f775d6, 0x1ae928fc, 0x5c0136af, - 0xef07f5c9, 0xeb769cbf, 0x024ff42a, 0xaa73d05d, 0xadd603eb, 0x4d66c7e5, - 0x7f86947d, 0xfc91ff05, 0x70007d40, 0x16f941ca, 0x08e8c87f, 0x044f93a0, - 0x7c894e9c, 0xdcd18ef2, 0xe2c8ec9e, 0x3c6977e5, 0xa099f52e, 0x9e9253cb, - 0x90e002a2, 0xf43f4416, 0xf60221f7, 0x29ba704d, 0xbdf3f25e, 0xbfc0c525, - 0xfcfe761d, 0x66fed67f, 0x5fcd3795, 0xcff78ed7, 0x2096f7b5, 0xf7c7ba5c, - 0x768fda2e, 0x6e024dc4, 0x67bdaddf, 0xc08077bf, 0xbbffa273, 0xf41f40ab, - 0xa46a9e3d, 0x3e94250f, 0x2fa50d5e, 0xfa7de6af, 0xbd3d043b, 0x7950b7ff, - 0xcfbcd2e0, 0x17107bf0, 0x5bc0beff, 0xe3af06b1, 0xa31d7835, 0xbaca97a9, - 0x4afe482f, 0xe3be5cb9, 0xe312fbe1, 0xd0a9afd1, 0x3d3f2475, 0x3cf4483f, - 0x77e926d7, 0x4fd5c115, 0x47ed0fcf, 0x2cdc9dfa, 0xf491b5e9, 0xc39424cf, - 0x29f5fc23, 0xfea88728, 0xc5c60970, 0x91eafafc, 0x6fb72855, 0x1ffd9068, - 0x2f37fea5, 0xa6ade393, 0x8c8f12e7, 0xeefa463d, 0xafa97ca6, 0x3fb9271e, - 0xefbf85a7, 0xfeddff4c, 0x4687e41f, 0x6ad65c0d, 0xff4d5eea, 0x6fd017d5, - 0x2fef34cb, 0xa95f3cd2, 0xd4d1afa9, 0x2fdf821b, 0x1f10a19b, 0x38f01596, - 0xb52f96a5, 0xef4ae1f4, 0xf5ba73b6, 0xfb2662b9, 0x26af882e, 0xb5faf3d4, - 0x1a4b1be9, 0x75f501cc, 0x5f384a9b, 0xf7016cc0, 0x7ae6419f, 0x4307a055, - 0x20b3720f, 0xd9b907bd, 0xf9efab4f, 0xafe07ff3, 0x0a371429, 0xab764bb2, - 0x5536f5c1, 0x75bbdbac, 0x810182ff, 0x4be7d5f1, 0x63dd5cf0, 0x5cdbc71c, - 0x2ed02632, 0xae25cd62, 0xfeca7d80, 0x5efbbee3, 0xeb3cf9c5, 0xd1b25cfe, - 0x114f718c, 0x12f3b4df, 0xfa8aa5f4, 0x6ff856ba, 0x2f1e61c6, 0x5aa293c6, - 0x080fe673, 0xee6b27d8, 0xbb6cfb83, 0xb7dfe55b, 0x00fc07ab, 0x8398ca9c, - 0x33a750f2, 0xb6a5e517, 0xfc2cc4c5, 0xf76f782f, 0xd442eadd, 0xc61707d3, - 0x2bd35e51, 0xb17cfce9, 0xe277a63b, 0x45b7a84c, 0xb6f246df, 0x54b1feed, - 0xcb5d52ee, 0x2d8c6cbb, 0x894af75e, 0x1e7c72f9, 0x3bba7043, 0x2592a5fd, - 0xa6f7ef40, 0x8f7de83b, 0x03b896dd, 0x0c07eded, 0x0e043714, 0xe7e89278, - 0x3c60d341, 0xe92d976f, 0xf2b1714f, 0xc38d26c7, 0xf7e5a47b, 0xd25e2819, - 0x9f91b3a9, 0x58c0f3c8, 0xb19a93ca, 0xabde944c, 0xdfe57ca9, 0x7bc7ac7f, - 0x14eb5da6, 0x55cd4efa, 0x6dff375f, 0x1b2bd410, 0xc67ee9b2, 0x9474e7cb, - 0x9ae9fe17, 0x53cc3ebe, 0x47591c3e, 0x9fd0a5f9, 0x9e56bbee, 0xc92fec77, - 0x0daafec7, 0x428e3853, 0x47cfda3b, 0xe14fa857, 0xab32ce3d, 0xbbf30a25, - 0xc8c77e8f, 0x3ef473af, 0xe6ef7d13, 0xd6e7b353, 0x8f74f135, 0x767d2d09, - 0x15587154, 0xf4dac380, 0x29c925fd, 0xf8126ed8, 0x032d6fdc, 0x75d32f3e, - 0x93e90fd3, 0x5f5e588a, 0x92cdeebb, 0xa38fb04d, 0x7ca5f44f, 0xd70c84b1, - 0xd78074ba, 0x93d70ce1, 0xd9fb8a54, 0xc79bfcaf, 0x593a5f25, 0xb5f4889e, - 0xcbf5d059, 0x0313cae7, 0xc5416eff, 0xc1d13d29, 0x02c7462b, 0x5469eefa, - 0x6ce782ba, 0xf43883a0, 0xe710cf9b, 0x85e7a016, 0x57d8c35b, 0x3db9d34b, - 0x84dbf6d6, 0xba208e51, 0x29e498fe, 0xfea0379d, 0xa447fa62, 0x16988ee7, - 0x77752e62, 0x1ddb243e, 0x34327049, 0x3322fa45, 0x1aea7fd1, 0x4ff3a2e7, - 0x96c99f73, 0xfd143e00, 0xfcf2f13f, 0x3fa04fdf, 0xf13efb9e, 0x604b3ffe, - 0xaff6433c, 0x68bc5ab4, 0x58b31c5c, 0x838f88f4, 0x3147c5fa, 0x9d62ad3f, - 0xc540f481, 0x5d4584ba, 0x6e807f28, 0xdda6bfd0, 0xc0c32997, 0xc63d18fd, - 0x192f3f57, 0x5e781693, 0xbbf24139, 0x377cbe27, 0xc6c944fd, 0x65f33d01, - 0xa7cb8da5, 0xf7f8eb71, 0x58872b75, 0x7bbf74f4, 0xe89babdd, 0xc8bcf01e, - 0x5157bc5c, 0xf844ceb9, 0xbc58b4ea, 0xbef12bb6, 0x0b1f4581, 0xae74a1e5, - 0x0e19f54f, 0xca9147c2, 0x54b911f4, 0x190a3dd2, 0xf0b13c3f, 0x1d31c7d1, - 0xbbe673f3, 0xefc0187e, 0xe9d38b8c, 0xf92a6d99, 0xc4f1b51f, 0x1ab7d7ea, - 0x888fd90b, 0x4710f627, 0xe29d62ac, 0xe3e1e2bb, 0xe238da89, 0xbdc5d2bf, - 0xa238eeb3, 0x5187be81, 0x4588e229, 0x7f5a156b, 0xbdfe42e5, 0xee38a292, - 0x18b23e3f, 0xed2fa0e8, 0xc5cb6bdf, 0x7fae693c, 0x8be2992a, 0x5eaf5f80, - 0x99fc8f3b, 0x5e1ce975, 0xb03be265, 0x199d2387, 0x58afde78, 0xae704917, - 0x07f6727c, 0x7de3e44f, 0x81f189c0, 0xa09b6be7, 0xe19f180f, 0xce39683d, - 0xd0f725b1, 0xd68b6777, 0xf31939c3, 0x73d963b4, 0xde226537, 0xde303252, - 0x2e55fb29, 0xef0fbbbd, 0xd86ce707, 0x950ad977, 0xbb6b0f7f, 0xf021f489, - 0xb80b327c, 0xd9633e2f, 0xd72346eb, 0xa8792c67, 0xfe1db3b0, 0xc29f6cfb, - 0x4104fc73, 0x26b7b8ad, 0x5bef27e1, 0xf7f8e995, 0x0a754b36, 0x8902c3dd, - 0x7e97f746, 0xa3fdc191, 0xcedc1979, 0xd270cb2d, 0x55ea9e3d, 0x4cd2e726, - 0xbdf74e3e, 0x55e73875, 0x282a3aeb, 0x1317f9ae, 0x976a57f9, 0xad22ba45, - 0xf9e31f3c, 0xad779401, 0xaa3c0237, 0xfc6e5c1c, 0xad63d042, 0x94d5d263, - 0x0767ae9f, 0x5607eff0, 0xac9cb85b, 0x9bb8058e, 0x86e90139, 0x1939f7e2, - 0xb8e253e5, 0xe6028329, 0x8c3b4457, 0xc7fab0e3, 0x0d63abdd, 0xfec1a7e8, - 0x38420f97, 0x237f5dc6, 0x9559efae, 0xb4801af8, 0xbfed00aa, 0x3c3cd567, - 0xd8ad9777, 0xf0e50e3d, 0xf1832ddc, 0x7b2b0546, 0x23d25dee, 0x3bfe0573, - 0x395a3e45, 0x81bbf1d4, 0xb9706437, 0xdfb951e9, 0x2f0106e8, 0x79f20749, - 0xf7030af5, 0x47bc83e3, 0xe4bd5301, 0xdab71a43, 0x728891d2, 0x81bb7ab8, - 0x8cdf87ee, 0x973806eb, 0x751f492f, 0xdcaae800, 0x51df4310, 0x344ef2ad, - 0x51aabd62, 0xbdffbaa1, 0xd3a40c84, 0x60bd962f, 0x1c39fa45, 0xfa839ad9, - 0xa45e6ba9, 0xda29ee93, 0x8beedfb8, 0xaf743965, 0xc3ad8669, 0x9965df82, - 0x8edb20b1, 0xada0fc72, 0x0fcf88d5, 0xb0ea6736, 0x46d9b2ee, 0xbfa5dd61, - 0x885fea92, 0x41fa177c, 0x9e3852ba, 0x1b769aab, 0xdd2feff1, 0xd4e2e82b, - 0x41f6efb3, 0x4675503f, 0x2fd41f47, 0x527d0740, 0x28cfce11, 0x9a6b9fa4, - 0xa4bc1e78, 0x03a41a83, 0x8239bbe0, 0xbdb66a0e, 0x43f21770, 0x373fe20d, - 0x9e808e94, 0xf9fda9db, 0x7f18e30d, 0x44e91dbf, 0x2fa833ea, 0xce3fa033, - 0x058bebc8, 0x0c7da1fe, 0xe00ef76f, 0xf9dd75f9, 0xd07c4108, 0x66d77e13, - 0x4c3e04e8, 0x8ad77724, 0xd8ae76fd, 0x9dfc456e, 0x1ef7767a, 0x3f54b78c, - 0x11dada0f, 0x3c041f86, 0x56ff716a, 0x19d93f5a, 0xab5fb8b5, 0x74ddff7f, - 0x96b0f82f, 0xfdc9fdf1, 0xfec5ead6, 0xfef173e5, 0x2acfb13a, 0xadb5e026, - 0xc13be72f, 0xf4c7c867, 0x3fb121dd, 0xbbf83d8f, 0xfec5bbba, 0x6cc9449a, - 0x0f8456cd, 0x0fe517e2, 0x28cb8fd0, 0x397409e5, 0xe50365b5, 0xc97c4bf7, - 0xd7efbff5, 0x93fc2e2b, 0x9d8f1254, 0xb6f77c3d, 0xa1c9f045, 0x763292fb, - 0xd8befc00, 0x240d9f4c, 0xcc07d57a, 0xce46e927, 0x49a7f457, 0x61bee2d7, - 0x5f1c56fc, 0x1bd07bce, 0x0e71c7ad, 0x721fce32, 0x8b2f92fd, 0x3b5da7ea, - 0x4efd8ad8, 0x5ed1b259, 0x3f7c7811, 0xbbef46c3, 0xf7806ed0, 0xf2143b5d, - 0xe7121f5f, 0xbdf743fd, 0xe01f2d60, 0xc577f7a7, 0xe19d25ba, 0xe4c9fa0f, - 0xb9daf77a, 0x6ebb583f, 0xbae48729, 0xe1bfee8b, 0xeb976c5a, 0x2051f8c7, - 0x4a384a9d, 0xfaf7957a, 0x344b74b4, 0xdaaaf527, 0xa6d77d33, 0x9dfca21d, - 0x78ed7690, 0x2c3a3ec2, 0x9ebbcdf2, 0xe77df956, 0x41edc965, 0x33188ef7, - 0x259fea07, 0x15b6aef3, 0x49b73c62, 0x521e7ba1, 0x4acfc0af, 0x923e807d, - 0xdef0c1f6, 0x36a57f3c, 0xf10275de, 0x63bc7559, 0x44927e1c, 0x7d57a5da, - 0xa0c6aadd, 0xcf1b6aff, 0x53749383, 0xf89db275, 0x93dc5aa1, 0xeef15b2a, - 0xf74861c4, 0xce281b4f, 0x58df7653, 0xb3fbda23, 0x8a1f4d37, 0x127bc0e0, - 0x6c4fdf28, 0xe047921c, 0xebc4b661, 0xc6c4bef1, 0xbfc7af47, 0x87633a5f, - 0xc1a1df4a, 0xcb8f9071, 0x7f23c8ee, 0xcec8e1eb, 0xaed02389, 0x436ab5ff, - 0xa6e47ebb, 0xffb08b21, 0x58ef4b48, 0xc6d078fa, 0xf4bbaa38, 0xa427a431, - 0x03f32c1d, 0x90bdc5eb, 0xaf9cdeec, 0x8a97757a, 0xefac0bc8, 0xaef9f183, - 0xddf4910d, 0xa3a352a8, 0xdbe715b9, 0x8ee74499, 0x2526385a, 0x2b9ee9db, - 0x8cb369d9, 0x9725222c, 0x453023da, 0xc74375f9, 0x5e4fa81d, 0x1832c3bf, - 0xd4cb8bbf, 0xb9cb43f3, 0x90e3cd7d, 0x61dfc171, 0xeac8eb92, 0x3b57e9cd, - 0x2f7f7c9e, 0x74ec2b9e, 0x3fde919f, 0xebe9ecb1, 0xd89e1f51, 0x7dc7639c, - 0x4919db1f, 0x198e0bf7, 0x78e7bf82, 0xb4c2f7a9, 0x3de4a9f7, 0xc1defcd7, - 0xfba49cf6, 0xb9cbde0b, 0x98f2d2ec, 0x74662e4e, 0x065cfc4f, 0xe8e4fee3, - 0x7e62b6ef, 0xc9a34561, 0x8e64f786, 0x7c63fd20, 0xdf4abb6b, 0xdfbba201, - 0xdb23af80, 0x703ee8f3, 0x5ebcc7c5, 0xf0f8acd1, 0xc3fb72fe, 0xc2fe53f7, - 0xf137b04c, 0x3db7796a, 0xebe1fabd, 0x38ce0d91, 0x3bf1cb3d, 0xf3366700, - 0xef908b7c, 0x75bebc3a, 0xffe38a4f, 0xfd2cfdbf, 0x077bd313, 0xf09347df, - 0x57aae796, 0x720a2e80, 0x72fbf0fd, 0x9fb22cf1, 0x50f62e4f, 0xb4395a79, - 0xb3d2246a, 0x15ee8625, 0x51e3b4bc, 0x5373bf15, 0x79f06dbd, 0x308f1f3c, - 0x9ff7d0c7, 0x90bc5cbe, 0x17279a82, 0x8a3f89d7, 0x15f854b6, 0xb55e547c, - 0xfbde8dad, 0x0b5e4772, 0xd97debde, 0x9ac5c31c, 0x3be820ab, 0x3dbf1299, - 0xfb9657dd, 0x1cd7fcfa, 0x9fdd72cf, 0xc56e9e6f, 0x21fdb57d, 0xe23865ae, - 0x86c63a37, 0xc8a56076, 0x86ba392f, 0x23c7d9db, 0x18abfe62, 0xed7c7cf0, - 0x0efc4494, 0xa9b6ccd1, 0xc57b63d7, 0xe786c54e, 0x49cee703, 0x7dcf3c56, - 0xe2b4efa6, 0xd6cfaa3d, 0x3e57fbc8, 0x237bbbfa, 0xd829b3c6, 0x9eab447f, - 0x84293239, 0xfc32f44c, 0xcbee9ea4, 0xe4ed017e, 0x451f393f, 0x89f813fe, - 0x99927cc3, 0x4bbf722f, 0x9c57f9f7, 0x7d8a46ff, 0xcbb6f7b7, 0x17b506f8, - 0x63f6f015, 0xd096b76b, 0x68de4fdf, 0xbfbae1b0, 0xf1a068dc, 0x4db9c0e7, - 0xbe3deb07, 0xb0839f99, 0x13e8e78e, 0x6779f99b, 0xef3f334e, 0xb833cf54, - 0x60d2fdf8, 0xe80a2cba, 0xeb2ddf47, 0x7323bbe1, 0x737f7c5c, 0x7ee27f40, - 0xb1bf442f, 0x9fee99ac, 0xa93e6a5d, 0xaaff7e96, 0x74dd1791, 0x08bd13db, - 0x23ff22b8, 0x98ba4add, 0xf5c786b3, 0x0b83cded, 0x9d24fe91, 0x5803bf68, - 0x3bfc646f, 0xfa28bab2, 0xb324f7ee, 0x62fa80c3, 0x18e77c4a, 0x075f4f04, - 0x916aaf97, 0xe4f785ce, 0xec29bd58, 0x15dec477, 0xbc1a78f2, 0x7abbf74b, - 0xcff7f8db, 0x59317dc4, 0x474abe82, 0xda293e7d, 0xba038dfe, 0xf2ffae74, - 0xf5d03d3a, 0x3bf691a4, 0xd7809db2, 0x7af35ff5, 0x167b7d9e, 0x7def3fd4, - 0xec3d3af6, 0xf695d26f, 0x2fa80621, 0x75cdf259, 0xc9b9e063, 0x3bd83ae1, - 0x9b139e60, 0x7f71d292, 0xdb087ed0, 0x8e7a27a7, 0xee2b5960, 0xba569d8f, - 0xf4cc2d06, 0xa77b7ff7, 0x0e4be0e5, 0xc0d3bd7f, 0xa73bbbe8, 0x87f5cb7b, - 0xd70e9d2f, 0xa109dea9, 0xdd8ce5ed, 0x5e7cf947, 0x7e076f7e, 0x788911dc, - 0x5dd38aaf, 0xd3c7bcb9, 0xe3c7b9a0, 0xe4d5f7e4, 0x7f792afd, 0xfdff72ea, - 0x7297b5b3, 0x00ffecff, 0x4fb2f369, 0x00008000, 0x00088b1f, 0x00000000, - 0x7de5ff00, 0x5554740b, 0x55b9e896, 0x2a493eb7, 0x54842549, 0xaa84a925, - 0xc0902b7c, 0x310c7c25, 0x0403e548, 0x6a285888, 0xa205a0d4, 0x01148280, - 0x55f4741d, 0x9a7c3061, 0x179f8ee9, 0x102d4622, 0xdd787195, 0x866db1d1, - 0x3220538f, 0xb40e9afc, 0xd38ceb63, 0x68d1d01d, 0x38311b63, 0x6f360cf4, - 0x4dce7def, 0x802a56ea, 0x6f7be7be, 0xf65e97ad, 0xee739f61, 0xffb3ecf9, - 0x5f5bdf67, 0xa5eb2c19, 0x0f24c664, 0xa153ab63, 0x63595a74, 0xff7b9419, - 0x68d2cfe9, 0xac839ac6, 0xc18f2e3b, 0xd3f5a35f, 0x7ccf5051, 0x2e504bba, - 0xcd1a484b, 0x139960c6, 0x996fd062, 0x12aeb189, 0x6d3b26e8, 0x12d8c2cc, - 0x019dfe09, 0x19caf9ff, 0x956c674b, 0x44edfe15, 0xf08742b8, 0x7f466683, - 0x3f98059f, 0x1fd8c0df, 0x3925744f, 0x9d9d8cf5, 0xbb0c2e1d, 0xbc65fb18, - 0x009ce6cf, 0x8ecd1ded, 0xbec634a6, 0xd4a4c37c, 0xd09eff43, 0x60f927df, - 0xe67aa5fc, 0x6d9284ef, 0x24d8ce1f, 0xc3ea2f28, 0x61dfa053, 0x8db6f157, - 0xa9cbbcf0, 0x3f9e0c63, 0xfce70aeb, 0x82c678f5, 0x32f2932e, 0x32777ea3, - 0x9f1eeb80, 0x9dfb1c3e, 0xfe5d7d7d, 0x936eb03d, 0xec1258cc, 0x598c067b, - 0x0030780e, 0x07c32fac, 0xb40e3442, 0xbea09307, 0x0e74f5c5, 0x2f307c23, - 0x0dd8c89b, 0x06ebef8c, 0xf11fbc39, 0x196494c5, 0x6f9b37f7, 0x3283db0f, - 0x3333a38c, 0x98bbae03, 0x4d3f5875, 0x8eb19800, 0x7f60c34b, 0x3263c066, - 0x24c78096, 0xa1eaa6c6, 0xe9afac13, 0x0990fa97, 0x7884d7d6, 0x85d07014, - 0xd72c7a23, 0xc58bf8c3, 0xbc8ecbbc, 0x58c1c46b, 0xeb07fe10, 0x5de62259, - 0x3d7771dc, 0x9092cb9e, 0xc0b74ce1, 0x7ffa25f5, 0x72c79d0f, 0xf2feefd1, - 0xe29c46ad, 0x7eda1dfe, 0xafa6d9cb, 0x52fcf0f5, 0xfdc46dd6, 0x6a8ceb2e, - 0x0cf9a8ef, 0x977cbbd7, 0x99debeb6, 0xc2748698, 0x97b1b2c6, 0xe74d54f4, - 0x99f448bd, 0xca746faa, 0x66e19fb8, 0x371304c5, 0xf4479f3d, 0xb00cdec2, - 0x63ac7ec8, 0x8b4fd118, 0xb1e74f4b, 0x9cc49764, 0x7ebb18e3, 0x42731657, - 0x61aefd53, 0xc85d2654, 0x5fcffaa0, 0x57de3639, 0xd75e7032, 0xc6ab6abf, - 0x6aff5df5, 0x3aea9511, 0x4e1d049a, 0x867497d5, 0x2ce71d61, 0x9b800eb0, - 0x8162c08e, 0xd66e9a7e, 0x99e11887, 0x57bfb199, 0x596bc72c, 0x424fa5df, - 0xfd8a0e58, 0x3a24974a, 0x1f3c6484, 0x433d61ef, 0x031e627a, 0x79993bb5, - 0xa05ca5cd, 0x398ebb1b, 0x24dfe063, 0x19ce2fce, 0x81ee9ccf, 0xfc583976, - 0x87584ab3, 0x0941ae61, 0x5c737b41, 0x33e436d2, 0xe574f416, 0xe20d73c3, - 0x4e38aeb9, 0x54ee0937, 0x1d2af3cd, 0xadfa2adc, 0x18769a4b, 0xb3c1b2e9, - 0x5121e888, 0xc7acd4c9, 0x406a5fa4, 0x67d5b9fa, 0x623ba4f8, 0x585fa21c, - 0x295e0dc7, 0x7378fc84, 0x50ddb683, 0x44ad75f9, 0x8e47d425, 0xfbf6d5e7, - 0xd003d229, 0x717e103b, 0x9c0c3d24, 0xc3a3c583, 0x1224f073, 0xb9cccbbd, - 0x5be012b9, 0xee181b0e, 0xf7cf14df, 0x97310e79, 0x0f80fd86, 0x8875e260, - 0x2e4fa817, 0xc537e2d7, 0xb0e7c5a3, 0x867e2d3a, 0xb7fbb57b, 0xda6ae435, - 0x35237c33, 0xcb8b59ed, 0xbfb67034, 0xc47fd342, 0xec0d6aea, 0xf4d4ce0a, - 0xa37f5bcf, 0xbd682e06, 0xa8bfd35d, 0xbda6817d, 0xa69f7438, 0x268ed47d, - 0xf9da5c0d, 0x98ffa688, 0xda6b8f5d, 0x6a3786c7, 0x7e1dc7da, 0xe84f034a, - 0x7fe9a2da, 0x34db07cd, 0x5fba93ed, 0xdb5fb4d3, 0x9e0686f3, 0xd35bbbdc, - 0x0385ca7f, 0x1d8ab81a, 0x31aff4d3, 0x4f0356ff, 0xa6abfeb5, 0xc7fb74ff, - 0xce19f69a, 0x67da6a3f, 0xd2d1bfb9, 0x93973c6b, 0xa5ff2bd7, 0x9359ee79, - 0x5f50dfef, 0xdd954b34, 0xebf48641, 0x35ba3e24, 0x0184a74d, 0x972a83fe, - 0x1c9e1d04, 0xc1392561, 0xb78e59f2, 0x32b0e914, 0x6e7c7c8c, 0xe0f24497, - 0x28bd28ab, 0x91ebd1ff, 0x4afd9da0, 0x22765e52, 0xc45d41dd, 0x331e29fc, - 0x39d62393, 0x81aaceac, 0x9aed7b87, 0xa706b6fe, 0xe7c33da6, 0x2d67b4d6, - 0xb6703456, 0x7fd35cbf, 0x068f6ac4, 0x34eb0576, 0x7bd6f3fd, 0x6b417035, - 0x517fa683, 0x5ed34fbb, 0x69ac5a1c, 0xafc3b51f, 0x573b4b81, 0xd98ffa6b, - 0x8fb4d415, 0xb4d7af0d, 0xaadc3b8f, 0xb5742781, 0xf35ffa6b, 0x3ed34841, - 0xa6877ba9, 0x4e9edafd, 0x77b93c0d, 0x94ffa697, 0x5c0d610b, 0xfa688ec5, - 0x6a4f98d7, 0x0fd6a9e0, 0xdba7fd35, 0x67da6b4f, 0xb4d73f38, 0x2cd076ab, - 0x7adad7f7, 0xaf5d1761, 0x7cf359fc, 0x90c3dab0, 0x486f823e, 0xd613b34a, - 0x3fe102eb, 0x777ce49c, 0x28ed1e9c, 0x8c14182f, 0x41ad2901, 0x420c92fd, - 0x480ae90c, 0xe2a6358c, 0x20ac4028, 0xc15549b7, 0x4f68c9f3, 0x73aa9000, - 0x1fa0fcb9, 0xeb5ad813, 0x1bb266a7, 0xdf40971c, 0x29bfc25d, 0xa0944b83, - 0x85ebaa9f, 0x4ea166f9, 0x726f3a02, 0x582e3cf9, 0xaf9d7dcf, 0x6862cb4f, - 0x705b0427, 0x9307a01d, 0x9e6f41bb, 0x79776388, 0x378f064b, 0x89780cc3, - 0x5c48ef98, 0x32cca3ab, 0xcc33fcf4, 0xff7fa967, 0xae3e06b8, 0x8a6bfb04, - 0xa0a7ff18, 0xfbb065ee, 0x37c0035a, 0x153d8c05, 0x4cfc12b0, 0x5b704ec0, - 0x7b6549c0, 0x96e54dc0, 0x1ded4280, 0x5f827281, 0x0e087808, 0xdca8ea05, - 0xfd52f016, 0xc10340f6, 0x547c04af, 0xa62c08ee, 0x9f80b5f2, 0x560677da, - 0x40f3fc13, 0xc0ceca90, 0x237faa7a, 0x9bf04ad0, 0xdf827681, 0xdca8840a, - 0xe541d815, 0xb52740ee, 0x22ec0def, 0x9840edf8, 0x30e070e0, 0x5d0207c1, - 0x7c0c1f04, 0x40a1f040, 0x03879537, 0x0d1e543d, 0xf1fb52f4, 0x078205c0, - 0x576b4bce, 0x2e576133, 0xd2c07412, 0x2f793db8, 0x85f6523f, 0xbb462d8e, - 0x43a09177, 0x87983543, 0xcc867740, 0x2ecd6dc2, 0x13a06a3c, 0x71c9d137, - 0x96af2fb4, 0x4070d04e, 0x33560d7a, 0x5a9bd237, 0xc9e954b6, 0x90ae0cfe, - 0xbb732f42, 0x336feb88, 0xb537f553, 0x85283e37, 0x079b9ed0, 0xf811b276, - 0x9f6123e6, 0xe5c7147c, 0xc1bf39f5, 0xa35f768d, 0x66c0af14, 0xb277fe01, - 0x8c2fe03b, 0x5ed77fa4, 0x9fb456d3, 0xc235f5d4, 0xe7183a38, 0x5a2eecbf, - 0x6c3b2357, 0xbd40f5c0, 0x72fc0f47, 0xe2dbe6c6, 0x2fbeba02, 0x2234175b, - 0x85425913, 0x8cc644de, 0x48f3df76, 0xf7fce7e7, 0x17c1c21c, 0x9c429559, - 0x78537ae7, 0x7f30adf8, 0xb2bd11ef, 0x5e3439cd, 0x00ceb796, 0xf6997de1, - 0xa0773fb7, 0x17f75f1d, 0xe1cf0fbd, 0x21b12184, 0xe9dd7404, 0x3acf8892, - 0xd94d3a5d, 0x02fdf766, 0xa26df9d7, 0xa01d4eff, 0x56ebdbf2, 0xb612b2bc, - 0x20a2b8d4, 0xf055ed19, 0x5f680c0f, 0x034e61cf, 0x989b87ca, 0xea1c5de7, - 0xf823e666, 0x52a41656, 0xe176f9b6, 0x21636ebe, 0xa6157d82, 0x8afb589c, - 0x383bd75e, 0x752c70d8, 0xdd90f29a, 0xfbc70077, 0xeb43d136, 0x7a69313a, - 0x5d4bee21, 0x49c33997, 0xdeb366fd, 0xdf7d7017, 0x53fafbee, 0x9d306f29, - 0x61f488fc, 0x3fb06981, 0x3779c233, 0x38e0ef03, 0x214b0fcd, 0x3e9573a4, - 0xa74cc11a, 0x7a851ff1, 0x805e9229, 0x4b7fd04e, 0x9399cdeb, 0x4dd2f448, - 0x3e926ff2, 0xfa7b0468, 0x28542e84, 0x8c4e89e9, 0x5173ac12, 0xee49d01a, - 0xc0f0f4d0, 0xe423287a, 0x17d9d020, 0xfe9fde38, 0xe2371ae1, 0x93dbf96d, - 0x66b7889c, 0xd0079c1d, 0x9ea8f073, 0x442604ec, 0xd2dafebb, 0xb207f910, - 0xc529cca2, 0x7172e373, 0x7ead9ebf, 0x4ddc863d, 0x74f4e5c8, 0x0ba86ec2, - 0xef9cb8d1, 0x2e7d76d5, 0x2e7d473f, 0x15a6df3f, 0xc3d52d9f, 0xf81c4ffa, - 0x8d2ce8dc, 0x3fd58fb1, 0x823f2879, 0x3aef97ae, 0x7e83cd3d, 0xb92eeb17, - 0xbea07131, 0xd2abcc50, 0xe898de91, 0x5c896adb, 0xc75d3f57, 0xa75d22e7, - 0x11e75d00, 0x768a7f5d, 0x33936cf9, 0xbb2856f9, 0x28613501, 0xc95a2f7d, - 0x14c05c7f, 0x2f32172a, 0x0c808b95, 0xc1bd8e90, 0xf7888d27, 0xd52758fb, - 0x777e503f, 0xbdf5d23a, 0xd9f91f3a, 0xd517594b, 0xb5bd672f, 0xaf37b478, - 0x1daef35f, 0xeb537d56, 0x44915393, 0x7fcd0c6f, 0xdb39cb17, 0x4e834fa5, - 0x5cec93e2, 0xe4b747c0, 0xe613227f, 0xd5677dbf, 0x3f505913, 0x85cfcf5b, - 0xa2e7e31d, 0x7de891ca, 0xe0145f03, 0x78a6dff3, 0xa4fa5f68, 0x345f0d3a, - 0x123cce3e, 0xcfbbd38c, 0x8ae6da14, 0xfbf293e0, 0xf28590ff, 0x13bdee4c, - 0xdbf97bcf, 0xef3c54a6, 0xfbd718fb, 0xaf8d4792, 0x119efaa8, 0xe2cfdfbd, - 0x85f7ec15, 0xb22fefa0, 0x17f7d119, 0x658a3812, 0xcb287603, 0xf2cbd9f1, - 0x72f6f406, 0x88d1cedd, 0x95ebd027, 0x7df70e78, 0xd632d9dc, 0x9420fa85, - 0xe1887683, 0xecd29335, 0x7617e8d2, 0x8d850129, 0x7f3e219f, 0x198ee38a, - 0xfca92ebc, 0xeed19fd0, 0xd0591930, 0xce7c465c, 0x677f2226, 0x9abf891a, - 0x3879b511, 0xb7e9d78f, 0x84ff1e0c, 0xefe1ef58, 0x841d3fb8, 0xc52cbcfd, - 0x2feb879a, 0x3cc0fc53, 0x19d24724, 0x2e4773cd, 0x3e7563e7, 0xa076e966, - 0xc1347e9d, 0x8f9e3b77, 0xfd52471a, 0xcfaec3c8, 0x667cf1f2, 0xe5506c57, - 0xaec78d33, 0x84e972e3, 0xf84419c1, 0x014b9544, 0x6f2fd609, 0xa7ff286f, - 0x371d700f, 0x8c612d98, 0xc34ab077, 0x35ff7ed9, 0xdf1f4077, 0xcae3eaa0, - 0x1a8ef8a8, 0x018a61f7, 0x3ecc57d7, 0xf141f152, 0x0e4e551d, 0xb1b0bfd2, - 0x889fc42e, 0x79c7f597, 0xce3fb9fe, 0x8d79c3a3, 0xe6328e42, 0xf8237b77, - 0xae00d6d4, 0x307fc68b, 0xff8d7cb3, 0xd9c0d560, 0xffa6bb7e, 0x4d4ed588, - 0xd6e82bbb, 0x57ade7b4, 0x6b417034, 0x517fa6b9, 0x170347bb, 0xfd34ea87, - 0x6af0ed47, 0x06ced2e0, 0xbb31ff4d, 0xb1f69a7c, 0xf69ac5e1, 0x1afd8771, - 0x6ad74278, 0x3e6bff4d, 0x27da6a08, 0xb4d7af75, 0xaad3db5f, 0xb6f72781, - 0xb94ffa6b, 0x57b4d210, 0xb4d5bfb1, 0xd75f98d7, 0xf1c62fc0, 0xeb54e778, - 0x9b9e683f, 0x81afdf6e, 0xf1e7885f, 0x23ce199a, 0xf9c5e7da, 0x278b6f06, - 0x3ee5987e, 0xffdf69a9, 0x8dcdc8c8, 0x47a12fc0, 0xb67fe474, 0xc53d71d5, - 0x1d39aa1a, 0xd7bef1c4, 0xe66a1f2b, 0xbaf7d1cb, 0x7a9d8e90, 0x75f2266b, - 0x039cf97e, 0xd0ac7640, 0xc51aa2b3, 0xc9eebb9d, 0xf48e5803, 0x6c8d5ebe, - 0xf270d253, 0x7da39600, 0x1903575f, 0xca716533, 0xf996583b, 0x70d8d6c7, - 0xbce7ab89, 0xe0c4e583, 0xb3941a8a, 0xb17e2660, 0x3e7dd608, 0x846d9238, - 0xaa652575, 0xd10f5e71, 0x1d0caaed, 0xdbaaf9f1, 0x4b37142c, 0xa322d6bf, - 0xe81cdf3e, 0xec10791a, 0xd3a7f4dc, 0x69dc62d7, 0xa1f9d83d, 0xc017b022, - 0x59f2c7ee, 0xe043ebb0, 0xbb046d1c, 0x604dcb1f, 0x73fd63f7, 0x9c23f760, - 0x7ad974fe, 0xc9d56e7c, 0x6172ea7b, 0xca0f11fc, 0xd7533456, 0x0e2b7539, - 0x0fec7ac0, 0x4b28ad1a, 0xe267ae8c, 0xec8eb09c, 0x0a8eb065, 0x51078b42, - 0x3052ecfd, 0x1c39321c, 0x2becfd07, 0x1db81a74, 0x2eb045ff, 0x97cf8b58, - 0xaedee93e, 0xb6f9f630, 0x8a1937b3, 0x5d799f61, 0x014d6db7, 0xe6799738, - 0xf1d3be02, 0x93fc602c, 0x09cd8f79, 0x97860c96, 0x48ff7a14, 0x2cee4972, - 0x16b53e46, 0xeb81947d, 0x85fd50da, 0x3ce2b3a2, 0x0839cc8f, 0x787e7eeb, - 0x23e758bc, 0xaff2aa73, 0x79cf5c66, 0xef50ef94, 0x47218cef, 0xffe853fe, - 0x2f5c7993, 0xe5159fc3, 0x08938d93, 0x949d81b3, 0xf376f20c, 0xd1a7d5a4, - 0x41ad90a7, 0xbb23e509, 0x144fcf08, 0x7823c828, 0x1e44fc4a, 0x537947b2, - 0xe733e454, 0x1f3678c1, 0xf1914ed8, 0x785ac5b1, 0x19e79c33, 0x0c7ac0c3, - 0x3282e977, 0x92f0c1ec, 0x9e605157, 0x5fb0798e, 0xb51b3780, 0x8e9165fe, - 0x9f717d91, 0x378beeba, 0xdda76829, 0xf0f5c797, 0xecbb8096, 0x7ffa0313, - 0x4027d94a, 0xfd8b9947, 0xabe40f92, 0x04abd1ad, 0xd2e19fa1, 0x2237efdf, - 0x3ac5df61, 0xfd639f51, 0x27bb089a, 0xb86b8c47, 0x19bc27a4, 0x6a4abd9a, - 0xbd06fcc4, 0x618cefe4, 0xc9e69577, 0x4666b9fc, 0x1e7786ed, 0x5f309c96, - 0xba486366, 0x4bf1c687, 0xc2dbd40a, 0xb1ab3ebc, 0xf0085a53, 0x3a4e791d, - 0xac9c7507, 0x08feb0c5, 0xa0e5d93c, 0xede78564, 0xc425068f, 0x55eadd83, - 0xdae22258, 0x52bdfc4b, 0xf57db4f0, 0x864fb2c4, 0x8abdbae1, 0xa59be717, - 0xcadf9bf2, 0x2b1f3d70, 0xbd42a9bf, 0xc33d1bf6, 0x9c6f8cfb, 0x8c5a724a, - 0xa9a5a87d, 0x973ccf5b, 0x729267f1, 0x9e93f11e, 0x2ce2ddbc, 0xf17dfe00, - 0xd6c34b36, 0x47767418, 0x75b3a71e, 0xe2deaa99, 0x73d749eb, 0xeafaa93c, - 0x1fa72b1b, 0x4cad6e55, 0xce3ab0e1, 0x24f1ecca, 0x8f5a8637, 0xf98e3dad, - 0x19bbd622, 0xfde2b1e6, 0xac2b77cc, 0x21f03788, 0xcc9f34bc, 0xe7d6e9e5, - 0x4637e4dd, 0x3e20cfd3, 0x5c9bd100, 0x1dd97486, 0x31ba066a, 0x682a33cd, - 0x5bfeda2f, 0x2472848b, 0x284ab593, 0xb5d96d47, 0xe7d46587, 0x1bd8afb2, - 0x12be8ec3, 0xa9e7a83f, 0xcf8325da, 0x2abbf9cf, 0x0c0d43b2, 0xe5c9b6e9, - 0xa9f9e1b4, 0x6474da74, 0xe22faa78, 0x3a0bd73c, 0x7aad672e, 0xd60ad3e4, - 0xeb256549, 0xd63af2a2, 0x5987a54b, 0x99ab2c65, 0xf32d6542, 0xf98d3952, - 0xad63aca9, 0x9d64ce54, 0x2eb3d654, 0xa3bfc12a, 0xe4accbd2, 0x7608de87, - 0x9973960c, 0x985bca97, 0x482dca9f, 0xfef013df, 0xdbe095a1, 0xbb952759, - 0x459dff80, 0x53311f18, 0x39e417b9, 0x3c836f96, 0xf20c32c7, 0xf8c269dc, - 0x83ca9b88, 0x43ca8501, 0x0f2a7281, 0xefd43c07, 0xca8ea068, 0x952f01e3, - 0x540d0227, 0xd47c0576, 0x316054ef, 0xfc05ef95, 0x581fbe54, 0x8107e54d, - 0x12ff9520, 0x91654f58, 0xe20ae411, 0x163ddddb, 0x8f9c9afd, 0xe8271e8d, - 0x84f34fa3, 0xfdd1ebff, 0x78f1e2f7, 0x83ba3a8e, 0x94aed5b1, 0x6e6d1e90, - 0xe504279d, 0x74937746, 0x4eeb9437, 0x64d63b70, 0xd93b244b, 0x724abed6, - 0xa4bbb8c2, 0x9c027d6e, 0x0fbcdeed, 0x4f4198e7, 0x6b65ed54, 0x7f841413, - 0xe819a4ff, 0xdfc1ab70, 0x7fda15bb, 0xcebfd2f5, 0xaece8331, 0xc7f53c48, - 0xed4c38d7, 0x66b20e93, 0xf207c02b, 0x26993f4e, 0x10a075f1, 0xc7d2fe3e, - 0xe3e4d673, 0x791cb93a, 0x368e05d5, 0x5b0f19fa, 0xdb18cfc8, 0x0eac667e, - 0x2dab49e0, 0x471fe865, 0xf5b8a3f4, 0xdba2fd50, 0x563ae7d5, 0x1e2337a4, - 0xee0a7dd6, 0x65e51389, 0xcf8c58f7, 0xbbab8e45, 0xfe99f9ba, 0xf647f332, - 0x5e332e93, 0x54e79151, 0x7403ffde, 0x86df4d1e, 0xaebf1f4b, 0x3598f8a3, - 0xf6faf515, 0x7a772e14, 0xdb43e3b3, 0x53dbdd60, 0x9f21bc05, 0x610eb5f6, - 0x8dbad7d8, 0x6fc764b9, 0x1d36f38f, 0xd1bff6c1, 0x69a0db29, 0x636fbc7b, - 0x14f9c131, 0xea9759af, 0xca5ea377, 0xb1fae049, 0x9c48f1cd, 0xffff8233, - 0xe6eee422, 0xadaebeca, 0xd7ad4fe8, 0x6e7802b1, 0x1b05fadb, 0x4bce30dc, - 0x022ec09b, 0xc2f27938, 0x9ed0050d, 0x513741bb, 0xae1e642f, 0x0b4da5e3, - 0xe128d95f, 0x0b5323b8, 0x213cdc61, 0x7586733f, 0x74095d8f, 0xc6d466de, - 0x63f5fa15, 0x8597e73e, 0xd019cc30, 0x5e2239bf, 0x1ac0d5b1, 0x4166f522, - 0x35b7973e, 0x4c34bc45, 0xd33cf1e1, 0xe3d0f888, 0x11aaffb0, 0xbe93fe3c, - 0x9ff14cd6, 0x9e7fc774, 0xe9ed0e9c, 0x4d053a1d, 0x74b6d95a, 0x9efd018d, - 0xf22758db, 0x3f8956e3, 0x76e6cc1f, 0xb92c1832, 0x1efc2273, 0xf2ca37b0, - 0xf6a7e223, 0x7184a086, 0x4b11aa8c, 0xa7378c25, 0x3093ee3b, 0xe0de91fe, - 0xe8897c93, 0xfda9f927, 0x2b9f22ae, 0x6f67d61f, 0xf735e784, 0x3c0cbeb1, - 0x81b79857, 0x566409f2, 0xecdf3916, 0x27878e22, 0xb43d2064, 0x691ad7df, - 0x9af8d15d, 0x991eaee5, 0x1ce07c3f, 0xccbfdba3, 0xfdb8e7e7, 0xf9029871, - 0x1f8f1260, 0x9339789c, 0x6dd9e5ec, 0x23f41ef1, 0xb2393c4f, 0x2aa7e096, - 0x9eff683c, 0x1a62b978, 0x9a9fb396, 0x484efd49, 0x05c630ec, 0xbb753f66, - 0x7939f58c, 0xef1c2eb0, 0x71e891b4, 0x89f753f6, 0xc5a91fe7, 0xf05d72f6, - 0x2e9fd0ef, 0x012d7e6f, 0x891505e3, 0x7961646f, 0x6abdd742, 0x837fcc3f, - 0xd51afd95, 0xda4377b5, 0x3fc1d4df, 0x6b993ce6, 0x378c78c0, 0xf3ce973f, - 0xf031e626, 0xf92f077c, 0xba3b95b7, 0x8e8b01de, 0x5bd9d75d, 0x9ebad783, - 0x5883d65d, 0x34158756, 0x61ed59a3, 0xa72c41ef, 0xd16bf975, 0xa0fba9bc, - 0xdd9620f5, 0xc45e7d23, 0xedffabff, 0x055e3796, 0xab63c478, 0xe68768ac, - 0x633dde3f, 0x0d2fc51b, 0x60a1f90c, 0x8f55bf92, 0xa6f66c04, 0xf6787ca2, - 0xfa875919, 0x8d6ae4dd, 0x4f74d843, 0x4ce30eae, 0x175a53db, 0xe20bbed3, - 0x28f1e219, 0x8ba421e8, 0x2a6f1482, 0x25f013f2, 0x829dc39d, 0x7e294d3e, - 0x8bd60a6b, 0x7efe8e7b, 0xd85e1cf1, 0x4e35afdf, 0xa55279a2, 0x08cdc4a0, - 0x42ec23b4, 0x7f33b79f, 0x96c3e206, 0xf18adfe8, 0xce2a82ad, 0xd3912cff, - 0x996f7605, 0x10508f48, 0x3fd5bd3e, 0xe6c1cf0b, 0xe01bcfeb, 0xb06a0774, - 0x25c93edf, 0x367fee98, 0x39061c4b, 0x3fc2eb43, 0x5ba4e78c, 0x51cec9d2, - 0x806b6fd7, 0x0eec22f1, 0x968dc7dc, 0xba54e781, 0xf5f620db, 0xe60b2884, - 0xf5d4f1f3, 0x7ae7cc6e, 0xd4edd61d, 0x62f47ae1, 0x5d0fb03d, 0xfa227ac4, - 0xd7fafed1, 0xd23b14cd, 0x897e6305, 0x4729cc97, 0xcea17fee, 0xd71a3713, - 0x615fd6ff, 0xe509295c, 0x67f3ac08, 0x919927fb, 0xf1f7a34f, 0xfb88be42, - 0xfe8cbd80, 0xe71f4cc3, 0xbf46e6df, 0x0d94fe84, 0x43bfdc61, 0xd45c60f6, - 0x0c926966, 0x39b5fb11, 0xd99e9eb8, 0x728fdfe8, 0x82796665, 0x8b3df482, - 0x72b5ae75, 0x0f983efe, 0xfd622beb, 0x7136167f, 0xfe7c4ec0, 0xe24ef799, - 0x67583a91, 0xcfea3155, 0xbca5eec7, 0xcc8fcd89, 0xcfeb8c3c, 0x3fb93f74, - 0x7ef40615, 0x3e7dce2d, 0x77656f8f, 0x87bc9ac8, 0xc9acbf2c, 0xac58c88b, - 0xd07a076d, 0xd95d2ac0, 0xa829d5a5, 0x2509746f, 0x9da06733, 0xf923a492, - 0x9a4a720e, 0x8d1ed31b, 0x7f812ba2, 0xcdde7cf5, 0xb373a7cf, 0xb039f859, - 0x737cc55e, 0x7aacd8a2, 0x336f304e, 0xd03279b0, 0x3ead737d, 0x8f1fa124, - 0xb232f1fd, 0x26f70d97, 0xada73e0e, 0x19cce706, 0xd41fa728, 0x2aaf2959, - 0x67a0af0a, 0x94fc99fe, 0x1da8d307, 0xc53365ea, 0xabd6233d, 0xcf6b058f, - 0x3bfd4ae3, 0x0cce7858, 0x4cfae0d7, 0xa899dcc7, 0x32973367, 0xf6e8ff3a, - 0xe7b547a2, 0x78ef7e4a, 0x50b1a38c, 0xe79c07f8, 0x5af6c74c, 0xcfa3efb4, - 0x9cbba555, 0xc2f5b161, 0x2f5c0523, 0xa72824e4, 0x90aec8ea, 0x66f04ec9, - 0xfd23c3cb, 0xb9f2efa4, 0x57e5301f, 0xec43d216, 0x1f087363, 0x3f5dc255, - 0xa8738629, 0xfba1d3ee, 0x7e3ddec2, 0x5099e9e0, 0x7bf5fd4e, 0xdfa0c74d, - 0xe32cefd4, 0xeb377eb0, 0xa081819e, 0xf90361e0, 0x7cbe6b8d, 0x440315a5, - 0x414c8dcd, 0xe3ceabbd, 0x6efae028, 0x25e4218f, 0xb32c5af9, 0xd907246d, - 0xf4114bc5, 0xe89e9002, 0x6f31b787, 0x91f92b63, 0x8612fcb6, 0xaccd3c79, - 0x97d20ef3, 0xe30c8d67, 0x383637af, 0xffb0550d, 0x869d1b1b, 0x219f78f9, - 0x23b43ab3, 0xa8506a6e, 0x8546a6fe, 0xfd799bd7, 0xd50f06dc, 0xf0f46dcf, - 0x5bd40b7a, 0xd4290f30, 0x6f718015, 0x753aa4b6, 0xe8d01f78, 0x4c17ede5, - 0xfc1c7ed4, 0x8c27cc01, 0xbc910b8f, 0xf1d1ed6f, 0x7c7f237b, 0x9ab58248, - 0x3b0ecb12, 0xe8f77f11, 0xcc175014, 0x2b332d94, 0x7836cfc0, 0x7f687a43, - 0x1032858e, 0x3617bb91, 0x7ea10b79, 0xe2b643b7, 0x7b8376fe, 0xc147f98b, - 0x9de132a5, 0xbdde00fe, 0x3af741d8, 0x3efc455b, 0xf14cc4b8, 0x2875b066, - 0x6496ccde, 0xb7863b0a, 0x86b02c77, 0x39031ed0, 0x7bd8e748, 0x00764c8f, - 0x6ea3c3c8, 0xe6768bb4, 0xca9f182b, 0xb7e5aa5c, 0xaa0b85f4, 0x6646bc68, - 0xbebd3f45, 0xbcd78f91, 0xa1d21753, 0x71b9655d, 0xf341d226, 0x3fa0a60e, - 0x53c2ecfb, 0xee10c3b5, 0x3f2e1450, 0x79a172b4, 0x9c4753e1, 0xcebf1fb8, - 0x79fd405a, 0x5fd9af1c, 0x0d2f5dbd, 0xb79d33f0, 0x0c7e4073, 0x61ca3796, - 0x5e63271c, 0xc1f182b5, 0xc627d874, 0xbc8c3bf3, 0x4ca7783e, 0x0be92df7, - 0xf475b0e5, 0x0b677f00, 0x1f23a614, 0xd17c9126, 0x9dc8d7f0, 0xc179f85a, - 0x32efc0a7, 0x9db82bee, 0xd1673e51, 0x903f6d76, 0x57943a93, 0xfadaedd9, - 0xe3fa8b5b, 0x443c1a02, 0xe7e6d9e3, 0x9f7a2f72, 0xc70afb03, 0x74bed115, - 0xd7285f7c, 0x72d8bea0, 0x1b8bea80, 0x44e9c565, 0x0a79d779, 0x53b45ff7, - 0xeb806166, 0x44cd9617, 0xa4dfaa7a, 0xf5c8f0a3, 0xc2e48bac, 0xc6adf695, - 0x19f7a23b, 0xf2efbfbd, 0xa88e5cf5, 0x6613e0f6, 0x1edb07b2, 0x9ef0e8b6, - 0x78adec15, 0x55dc2b8c, 0x402c1d54, 0x1dc8407b, 0x973d25c3, 0xa216cd27, - 0x51ed8353, 0xa1fc6477, 0x13f55465, 0xd86fd405, 0x6e3c758d, 0x968efb41, - 0xe3173f63, 0xe6d6ea4d, 0x13db5de3, 0xa63f951f, 0x729bc7cd, 0x7f2a3321, - 0x7f2a2f2c, 0x7da6946c, 0x545c75aa, 0x51b5d8fe, 0x1a3563f9, 0x967b9678, - 0xcaf5ffa6, 0x86f81a4d, 0xfd343bf2, 0xd6ee78e7, 0x7754dfb4, 0x66fda6bf, - 0x7c0d4aef, 0x6b5fc36b, 0x6be6dffa, 0xb1dfb4d6, 0xf69a27f8, 0x2d49ff68, - 0xf9701577, 0x3feed9be, 0xd06c0149, 0x3df791f7, 0x28de996a, 0x7b9e46f7, - 0xa7b70252, 0xb9fdfba2, 0x8bfbd380, 0x058f9f12, 0x1c789aed, 0xf135d8f3, - 0x854570ba, 0x71c61bb9, 0x21df951a, 0x0ee262dd, 0x6bb6bfbf, 0x3ff6d9ee, - 0xbc60fd0e, 0x1b5cc4a6, 0xff8c3bea, 0x37b940fa, 0x5f747487, 0x4abf5b61, - 0x69b83d22, 0x5cab8f15, 0xaf3c5230, 0x8eac1d7f, 0xdc46fbc6, 0xeceba96b, - 0x2da47110, 0x85424718, 0xfd4199e4, 0x7ef1c656, 0xe3574d3f, 0x371a3e8e, - 0xa418dca3, 0x7e85bcfc, 0xcdc0e309, 0x7bc5663e, 0x02cb7493, 0x069bff9a, - 0x265d9925, 0xb016da2e, 0x67cc0f33, 0x635c155f, 0x527dbd84, 0xb3d4f7d0, - 0xcfddbcf0, 0x5bd31e28, 0x1853edf0, 0xe143e98f, 0x219d7408, 0xf73f3c73, - 0x5fcfeec0, 0xe6daf981, 0x5ca197a5, 0x5acf6e8d, 0x43ebf7be, 0x6e7f6997, - 0xde1f5bd9, 0x1fe7b97b, 0x25ba75d8, 0x38c87da2, 0xf3264369, 0xe001d044, - 0x80fde62c, 0xf9f5c85c, 0xc5230af2, 0xfc01aeb1, 0xbfbe0215, 0x89cff8aa, - 0x3fb9e03b, 0x44eefb39, 0x65ea1d3b, 0x847e87ac, 0x9fe53fd7, 0x9c92fca3, - 0xa3df6051, 0x9b171dfd, 0x7215c76e, 0x8d6d95ba, 0x6a0718bd, 0xd13a344a, - 0xbb32cfcf, 0x07193eca, 0x7ee06d74, 0xfeffb475, 0xddbfbf5c, 0x9177fe49, - 0x944b2718, 0x9e7f2b7a, 0x4e4c8399, 0x3114f717, 0x6a4fa1f0, 0x655e5097, - 0x8d3f942e, 0x89fd8be4, 0xa4238a46, 0xc1dc445b, 0x171358b2, 0xfb06e350, - 0x9095ef13, 0x4bc3d3ee, 0xf18f9e28, 0x5c6f1c02, 0x11d693a1, 0x32c82f1d, - 0x86bad3e7, 0xd7f59f1e, 0xe6314827, 0x1a875a89, 0x279e889f, 0xea04f684, - 0x64f16599, 0x7bef444f, 0x79556149, 0xd7e470e1, 0x51d393de, 0x90329f7e, - 0x5e8a1c3e, 0x143ccf30, 0x42b4fe31, 0xfe63dfee, 0xe63d6478, 0xe3228787, - 0xef41ccd9, 0x2a0c102b, 0x7bb18466, 0x77ce1143, 0xc277cf94, 0x1ec9d8a0, - 0xfe87b504, 0xd7217d5f, 0x9730d303, 0x19f2386d, 0x81dbcbf7, 0x12dcb1af, - 0xd67d92b0, 0xf087fc01, 0x9527010b, 0xca9b80a1, 0xda85016d, 0x09ca07b7, - 0x21e0257e, 0x8ea04778, 0x5e02d7ca, 0x6819dfaa, 0x01e7f820, 0x819d951f, - 0x46ff54c5, 0x9bf04fc0, 0xbf04d581, 0x0160f685, 0x53d7a9c6, 0x4ad03bb9, - 0xed037bed, 0x081dbf04, 0xec0e1951, 0x8103faa0, 0x060f824e, 0x287c1176, - 0x70f82610, 0x479530e0, 0x7f545d03, 0xc101f03c, 0xc93ee337, 0x15df58ae, - 0x4f8578c0, 0xf77da276, 0x15a16fac, 0x7cfb6bed, 0x79c5159d, 0x04b74fbb, - 0x8d1d1ce3, 0xef131efc, 0x040e3123, 0xed086876, 0x67fcfb39, 0xf6a54c8e, - 0x19bed4b9, 0xc4a70487, 0xafdb82b6, 0xfa91996c, 0x0a2130d9, 0xda58eb9e, - 0xdc03d218, 0xed4f185a, 0xf93215b6, 0xfce9cf6d, 0xeedc8529, 0x336df922, - 0xa541fb70, 0x5c853583, 0xe429aede, 0x161f5cf7, 0xca4a73f1, 0x9e47ad8b, - 0xa6ed542d, 0x7f7187f5, 0x3fb079f6, 0x55bcef5c, 0xb597bc66, 0x72b3a3dd, - 0xcbdf937b, 0xb8bf603a, 0xc50f587e, 0x6e7cd985, 0xade6db2f, 0xe63975a5, - 0xd6ed48df, 0xd05347a2, 0xaff76f4f, 0x6deb439a, 0xd9ae2994, 0x82903bee, - 0x89cf6cf7, 0xf0db277c, 0x64a86f78, 0x8d9e7af0, 0xe3077f5a, 0xec03837e, - 0xec63d7a5, 0x496ed303, 0xc71130cf, 0x331cd47b, 0xe829d78e, 0xfe7121d7, - 0xc4ca0f63, 0xb0302f7f, 0x2db9e0fb, 0x5105df60, 0xb6bf540e, 0xbd55e302, - 0x289dbe85, 0x8e779f37, 0x9c03203f, 0xcfc7c75a, 0x82bf255d, 0xf79c3476, - 0xbf502de7, 0x5e4dbee1, 0x4db0ea5c, 0x6ec835ce, 0xcadff3ed, 0x4397f8c0, - 0x5a8f9ed2, 0xf9f62dbe, 0xb78f8782, 0xf14c9565, 0x378adb64, 0xbcf9075d, - 0x33ff91bb, 0xc38a3e8b, 0x5cde4c30, 0x86450ea7, 0x35fc9e63, 0xff7717ce, - 0xcd423aa6, 0xdf3a8f26, 0x6aef9c58, 0xb1e234f1, 0xc62f9b5a, 0x279286ba, - 0xbf239257, 0x81ef1429, 0x942cb164, 0xb819cf23, 0xe49e0adc, 0x052524f6, - 0x8f3c1a4d, 0xe6a02f9a, 0x0be7440f, 0x29e05efc, 0xde62c4cb, 0x4fd67ee7, - 0xd73a41bf, 0xbd1b3c17, 0x92e36794, 0x35874931, 0x7a12d819, 0xde2aa7ef, - 0x3d0626ba, 0x2853e5a8, 0x1fc100c7, 0x2e713216, 0x38f8ea9b, 0x64ce3e3a, - 0x2ae082b6, 0x4318358b, 0x33e5ab5e, 0x2b7f9c62, 0x759b74e4, 0x870dcedf, - 0x1a8f7cf0, 0x8b6a3728, 0xfd01b42e, 0x3d09e084, 0x7d4cd7c9, 0x2257d6e7, - 0x4117f5d6, 0xa18c5b9f, 0x6e87bc62, 0x504af187, 0x94bf22ae, 0xd582fc50, - 0x7d5de047, 0x1d843fee, 0x75c5fcf0, 0x3cff7429, 0xda1c6d6f, 0x4ccced47, - 0xf83360f4, 0xd046c653, 0x32e90d83, 0x8b387d06, 0xfc0e348c, 0xe226aa59, - 0xcbd70cbd, 0x60972835, 0x2616fbdd, 0x99ac3e91, 0x31acdeff, 0xc9f65700, - 0x65b2cf94, 0x9cd3cf29, 0xca3aeff4, 0x31fb7913, 0xf75df7ee, 0x9fbd2d50, - 0x67ca2194, 0xb283cfd1, 0xc2533d72, 0x0b952e70, 0x99bf142d, 0x133e417c, - 0x4851a7e9, 0x17fa3c7a, 0x6d735e3c, 0x0f79acaf, 0xb68f526d, 0x8f54603f, - 0xb7464676, 0xef3edeb6, 0x6153d3cd, 0xfca5f69e, 0xbf8bf6e1, 0x7070823b, - 0x24e28e95, 0x5064fbea, 0x4df14193, 0xf9819839, 0x8ccc1b9b, 0xbe6db9e4, - 0x60f28ad9, 0xc93c7a7f, 0x2cdbf6bf, 0xcbae8764, 0x3b438a6f, 0x556f34d9, - 0x8c23960a, 0x3b18adc1, 0x2dd5e6bd, 0x9127d937, 0x55f355bc, 0xec1cac82, - 0xdc8dbb81, 0xf73e09c8, 0xe51954f4, 0x9967cf25, 0xa796eaf4, 0xadd8f983, - 0xd4e1d695, 0xf9be4cb1, 0xba76f87e, 0xbeb896b7, 0x1da11a70, 0x7ca379e0, - 0x7b4115d7, 0x3f705a46, 0x9cb66d36, 0x6b7ca469, 0xf982324c, 0xccfd0b0d, - 0x658df588, 0x573e48e6, 0xf2fbe4f9, 0x87c63c7f, 0x0e595f87, 0x2bdc695c, - 0x3e417bf1, 0xfca19be7, 0xf210d369, 0x1f8ff554, 0x8bfce029, 0xf57a4b6c, - 0x7da6318c, 0xce22abf5, 0x9e46e567, 0x61bb32a7, 0xc3dd1d5a, 0xcc65bb04, - 0xdc517be7, 0x27a7b50b, 0x7b713dd2, 0xbde30b2e, 0x8e817041, 0xf8d27bc7, - 0xb98ded7f, 0x936a1f14, 0x3cc129fc, 0xb9f097cc, 0x01dafcf0, 0x7f308947, - 0xeb970e5b, 0xe2b7e42c, 0xb38c357d, 0xe0fd7238, 0x74b505ef, 0xa61ec8cc, - 0x789e85f8, 0x888c69cf, 0x1c5c63b7, 0xcfd117e3, 0xc2d5ee4d, 0xe1682e53, - 0xc0d0662a, 0x3c2d6635, 0x3785aad5, 0x7d3b7115, 0x3f5b5dba, 0x1d85a9c3, - 0x74e307d9, 0xc2dfcf3c, 0xf049e222, 0x447e5ef7, 0x68dd681c, 0x765f3efe, - 0xcb8a52f7, 0x78f0e5b6, 0x3695638f, 0x42c591ce, 0x732fe212, 0xd63c5469, - 0x863f66bd, 0xa30bed97, 0x5efc41e3, 0xa9a1f002, 0x7c8a3147, 0x9e68eaf0, - 0xd23dde87, 0xce08bdb7, 0x5f0c60b3, 0x4d1dabc7, 0xdac53f74, 0x5caf88d3, - 0xb0695f22, 0xe88a7cbe, 0xf90f1d40, 0x7fb11822, 0xf84887e4, 0x37be51a1, - 0x8be41e70, 0x2cfea460, 0xfbd036e9, 0xa1be62ab, 0xcfe543f8, 0xa28f7172, - 0x89f4dde6, 0x9bbcd4b1, 0x705f2255, 0x4ebe5457, 0x1936a39f, 0xaebee7fd, - 0xf8b1f195, 0x682ef910, 0xe5887ce2, 0x837f9106, 0xe22c187c, 0xa6f5887c, - 0x637856ef, 0x050b8bd9, 0x63bfdc5d, 0x224f86c9, 0x73acb7f6, 0xbe5e0685, - 0x910de1eb, 0xe3f751f9, 0xbf08303f, 0xed7e519e, 0x2f9db152, 0x2bcbff4f, - 0x48cd0ccd, 0xcf2807df, 0x319c1596, 0x5ea77bf2, 0x42eb9e23, 0xcc99ff61, - 0x2fd1f2b3, 0xf2e211db, 0x37889d6c, 0x33155b34, 0x3b9981c6, 0x50c71355, - 0x4b4d11e3, 0xd854b65c, 0x7c7f7247, 0x7ca56bc1, 0x14f9e1dc, 0xf1aa48df, - 0x32c6cedc, 0x9c6453d6, 0xdd62066b, 0xc056c18e, 0xd957f9e9, 0xc0c74133, - 0xf8174dbe, 0xb0fdc97b, 0x8f2467ec, 0xea68e42e, 0xa39c44db, 0x0b2dbf9f, - 0x8b3e70aa, 0xb0fb49db, 0x1e1aff31, 0xd1c6d417, 0xe73de24c, 0x343be3c1, - 0x7e226df5, 0xb5f1e572, 0x85d33971, 0x2fc621bc, 0x1adf1a8c, 0x7181fc73, - 0xabbdf1b5, 0x714f37b8, 0x2e3a184f, 0xe9cdd236, 0xdfdd9d69, 0x83317185, - 0x06667fe0, 0xf288993a, 0xe3e9ff80, 0xc1ae7e79, 0x198f8da1, 0xfa0baf30, - 0x98b8973f, 0x3efa8ae4, 0x0599fdb5, 0x27cbca12, 0xa4e8fdf0, 0x5a24f2c1, - 0xde44d88e, 0x811cb47c, 0xd37034f9, 0x36cf5cc3, 0xe50f8a4b, 0xfe7ef473, - 0x7587f17f, 0xc8bbe389, 0x778eceae, 0x0f632e9a, 0x638205b7, 0xf175b9f1, - 0x0778c5fe, 0x918ef77e, 0xe3944f69, 0xf88ceb7b, 0x298ec56c, 0xb60f3173, - 0x13ebf04d, 0xa7a23a69, 0xb7d3dbf4, 0x29e823ea, 0xa173e8dd, 0x13ae9c3d, - 0x87f85ff9, 0xd227b471, 0x318c6db7, 0xa9d76abf, 0xd601adb0, 0x6d8e7111, - 0x9fee9ec2, 0xadcc8eef, 0xd27188fa, 0x34b1be4d, 0xa3fe7f5f, 0x87e5af98, - 0xc459b7cd, 0x6cf9d4c3, 0x67f76a77, 0x7f69fa33, 0xd487a136, 0xfee336f9, - 0x15d5f062, 0x75fe13e7, 0x69777cff, 0xf93367f7, 0xf5367f69, 0x7cea1b3b, - 0x3e6c3f2d, 0x76cfe0bb, 0x3d97def1, 0x64377f9e, 0x9a23f7a8, 0xbdccf3fb, - 0xed2f9466, 0xe850bc6a, 0xfa5173bb, 0x3be849ae, 0x6973f9f5, 0x3dff14b9, - 0x7326f877, 0xfa873d2c, 0x933b098d, 0x09933b09, 0xd9e1133b, 0x0d57a735, - 0xbbfc7a07, 0x95cf371d, 0xbecfaf41, 0x1cf8f4ff, 0xf1d9df80, 0xe832b98b, - 0x9eafd9a9, 0x1e0b337e, 0xfbdbfe29, 0xe9f4fc38, 0x5bb4073e, 0xadcccf82, - 0x18693805, 0xbaeacfd7, 0xb97779d5, 0x7cb95db9, 0x6f8f1e75, 0x3d459c82, - 0x67e39cd6, 0xcafc7f18, 0x1f349bd1, 0xeecf2ffa, 0x03105f4d, 0x7cb96a2f, - 0x1e7f2175, 0x9889c0ad, 0xaf48c6cf, 0xc7bea8dd, 0x8f7da752, 0x23692925, - 0x2c7187d9, 0x96394564, 0xfbd0f660, 0x7316d797, 0x533370bd, 0xe15fb81a, - 0x1c79102c, 0x4dcbdef4, 0x6b5c62e5, 0xfdb12fe5, 0x09e79d66, 0x79ff77f4, - 0x68e1bcd2, 0x7379ab3e, 0x3bde06a3, 0xde7dfedd, 0xb1fd9e4f, 0x64e56dc4, - 0x36998f1e, 0x7bdfc9ca, 0xa22b888b, 0x3e143c5d, 0xff73753f, 0x1e9f007e, - 0x0f54cf8e, 0x37b5a7c7, 0xff9c0d69, 0xf4de94f2, 0xc34f89c7, 0x0835f131, - 0xfbf851af, 0x7ea99b93, 0x88ed1ea0, 0xc55be12b, 0xd85f9aab, 0xc80b392c, - 0x9a19675e, 0x14c660fc, 0x1e7bac67, 0x3d48cfa4, 0x197bb46b, 0x3486a3da, - 0xeff98dc5, 0xc7d17fcd, 0x1573dbcc, 0x525ef88b, 0x367de53c, 0x1fc91927, - 0x93349fdf, 0xb659fc61, 0xd4bc234c, 0x3e51d526, 0xeb187ea6, 0x3a357f44, - 0x7c9f5d0f, 0xe909e53b, 0x4061e86d, 0xecc79fd9, 0xe95f2331, 0x5d92563f, - 0x99570048, 0x295f2e87, 0x26753d0f, 0x324f43cf, 0xd85e313a, 0x998c689e, - 0x9badfe87, 0x71fb5dfb, 0x1fb8697f, 0x886eff23, 0xe56c97d8, 0x9f58eef7, - 0xab46f500, 0x5dfc518f, 0x615bffec, 0x4dfda907, 0xf9433f56, 0x4e2a37a0, - 0xa9f45fb4, 0x77e07f5c, 0xe231dc5b, 0x0dbb5f28, 0xa3fdfcf4, 0x99cf5cac, - 0xfb3eddb9, 0x27dfb137, 0x44962b28, 0xdd3624bc, 0x3737450d, 0x9dde78ea, - 0x2d7397ca, 0x9c07ca46, 0xf7d3b16b, 0x2102e66c, 0xf446a4f6, 0xfe56eebf, - 0xd8acb53e, 0x7b7e9e91, 0xfe5f94ed, 0x00b5e196, 0x66a7db97, 0xc2bde818, - 0x28f31253, 0x5df383a9, 0xa994debd, 0xea1bccb8, 0x7645af4f, 0xc8c3182c, - 0xc1757a4e, 0x4e95ad43, 0x8aea8ff2, 0x737d9e91, 0x770fa2a6, 0x77d8c363, - 0x04f2ffb1, 0xfbd5cf2e, 0xfc09e5a5, 0x646bde7d, 0xffec6cdf, 0x4917c555, - 0x725f48d5, 0x2bae0e6f, 0x33dd3fa2, 0x5b9ff445, 0xcffa813c, 0xf5ddafe6, - 0xce3977d2, 0xc8f99da5, 0xec7ce8c7, 0xf429ecb1, 0xbde458b7, 0xe81f9086, - 0xa3d64577, 0xce22c5bf, 0x6e505a53, 0x4f218eeb, 0x3ec332d4, 0xa042e46e, - 0xb18c8cd7, 0xcff5aa54, 0xa175f47a, 0x90fce718, 0xec1fe738, 0x6ac3b4f7, - 0x3df80e27, 0x843cefe0, 0xe172f8f8, 0xb0f1f4a9, 0xbf6a07a5, 0x6ec7bf26, - 0x16ceffec, 0xb00371f9, 0x2db3bef6, 0xdf8c5bd0, 0x87886019, 0x8bf91189, - 0x25f6bf62, 0xefd0526b, 0x20f4b381, 0xbc0476dd, 0x030d6b23, 0xe42cbfcf, - 0xd2160b08, 0x2eb106f3, 0x0ceb5a47, 0x2c38bb8c, 0x6073ca3a, 0x6791aacc, - 0xa6536a73, 0xbb0ba1a6, 0x2716299c, 0xe45df7fa, 0xfbe06417, 0x7c9f180d, - 0xf78636e7, 0x9d69595f, 0xfd75da12, 0xc6f788f3, 0xe17b8957, 0xed2d5f3e, - 0xefd6c327, 0x5ff23197, 0x507382d3, 0xc33df56e, 0x92f19457, 0xc691ddb6, - 0x5dee1ff3, 0x02721f18, 0xed2d67bd, 0xb04f4fc2, 0x30f8700c, 0xa9719fa6, - 0x7282d5d9, 0x140957e6, 0xe7b7d677, 0xfbc820b3, 0x1bfbecb0, 0xf9c877c2, - 0x6c4f2e90, 0xb65b9e16, 0xb9ec9e28, 0x0675a976, 0xe8f731f9, 0xd178ac58, - 0xa7ee62ce, 0x2b628ffc, 0x4fb5cfbf, 0x1f63f4e4, 0xb8e1723f, 0x77ffe7ab, - 0x49f99e84, 0x7fde93b2, 0x4da3ed52, 0x8e47f843, 0x5f213a91, 0xf8115e84, - 0x199f3333, 0x792f45f9, 0xc774b079, 0x96bdaf6b, 0x5b53e8ce, 0x841b4748, - 0x138ea3fd, 0xc6a21f9f, 0xf243c578, 0xb87ab252, 0xedfab0be, 0x75af3841, - 0xce63e9df, 0xfba085ff, 0xd90fd935, 0xd3ad7fb1, 0xfa32c6e7, 0x9c96983d, - 0x3e78dd7b, 0xe9fb332d, 0x96baec95, 0x61dfce33, 0x28f0563e, 0x9fd837cf, - 0xefc3685d, 0x1b0e5941, 0xe265d364, 0x27d046f1, 0x19d8cbce, 0xdeaf9146, - 0x99e78072, 0xbaca58b6, 0xc5a1af30, 0x6a465692, 0x56f3c2d8, 0xcb16fed5, - 0x1607d221, 0x5adfdf85, 0xb8487f50, 0x0947c04c, 0xe110ebae, 0x5077ed43, - 0x128b5dc8, 0x5a5ef866, 0xfd4ad29c, 0x83d7b2cc, 0x34e6ca79, 0x6644f746, - 0xe217f02b, 0xccc75f35, 0xbec9f431, 0x5a4fae62, 0xaabaca4a, 0x7e327d69, - 0xd8b58eb9, 0xe7a4eccb, 0x7cf0ef11, 0xcf968673, 0x577813bf, 0xf91669c7, - 0x4eae77b4, 0xc38ed609, 0x1bf79338, 0xcb16e7a4, 0xf5107302, 0xcbf8e25a, - 0x391a678e, 0xd7fb78d4, 0x43bef18a, 0x2c4fae79, 0x0678e2b3, 0x8d15f7c6, - 0x9c62e1f7, 0x7bfbd5ff, 0x47bd2cc0, 0x581d304d, 0x7deb1ed8, 0x13f3feac, - 0xcfd1f2f7, 0xbc7960fd, 0x02871b56, 0x091eec79, 0x72565afb, 0xd53550e6, - 0x0bd3f8f0, 0xfd519fc2, 0xf6317492, 0xbf7f120b, 0x2bc5283f, 0xe10c5df4, - 0x69c7a4a7, 0x3ef030f1, 0x6f873f2d, 0xde1e781a, 0x7c4c6937, 0xd7cb4e87, - 0x38ff1cdf, 0x059f9345, 0x7131ec7c, 0xde23c63f, 0x3888f5a7, 0x6f18c21d, - 0x049d17a0, 0x89c7f7ff, 0xc33f9c1b, 0x4099acef, 0x5c60eb8e, 0xfa27e1c9, - 0x5dba3936, 0xe239efc8, 0x78d10ffb, 0x2e48c9fe, 0x7a47a5af, 0x51af785c, - 0x119bd69b, 0x7c5fdf8b, 0xee0642f8, 0xfd19c5e7, 0xdf743b79, 0xe769e2f4, - 0xcbc402e6, 0x6ffbed11, 0x474df8ea, 0x22f8a7ce, 0xe5c0a5fd, 0x3a4b2fdf, - 0xd92571b3, 0xddb80b8d, 0x7dfa7ff8, 0x73e617b3, 0xa497753b, 0x084fcf95, - 0xfc141cb9, 0xd320bb60, 0x2aee43f7, 0x3a40adf2, 0x0bac936a, 0x3ce72e50, - 0x9af2f3cc, 0xb3d55b1e, 0xb47f0628, 0xd5fdf28c, 0xbabf08c8, 0xe491bd7c, - 0x3725b35e, 0x28f772f9, 0x9fbb9f43, 0xde7a94e4, 0x79988f55, 0xdb8f8abe, - 0x7bbee9d1, 0x3a260f29, 0x7ea8653f, 0x449d23d5, 0x137f6a0f, 0xc5f28f8e, - 0x15c52372, 0x818fa1ce, 0xb72b3b71, 0x59d7a233, 0xc098c889, 0x7d0663f1, - 0x49607499, 0x106b8e1c, 0x6a0bdcfe, 0xcca1a45c, 0xde7889ec, 0xb9995b70, - 0x9a4e823a, 0x8e0fcf19, 0x2337ff1e, 0xac22fb55, 0xa80c63b1, 0x94c6317f, - 0x97ed9f26, 0xf278643b, 0x0395b4fc, 0x0ee3cc7c, 0xc5a3e743, 0x232dbe71, - 0xf30dac7b, 0x5e0ec0d2, 0x0460b0d3, 0xf64db7e2, 0x3c0368bd, 0xa2687ef4, - 0x0bdfea3c, 0x7c16ed3e, 0x05f9d43a, 0xd23001d9, 0x1d9c7b18, 0x80e297c4, - 0x2327c64e, 0xebe7345f, 0xf63142ea, 0xf3ec5c79, 0x7878f632, 0xc7b3f7e4, - 0x1afe890f, 0x6ded1c7b, 0x46fdd44f, 0xb6768c24, 0x7e3d8627, 0x05f11242, - 0xc2742791, 0x0dd5dce0, 0x39313978, 0x5697be99, 0x5defc090, 0x527fa04e, - 0xabc87e06, 0x7ed1f3a7, 0x7ff52d99, 0x43f84917, 0x47f0608c, 0x62f905fe, - 0xb6bff30e, 0xe23e2248, 0x1b7835f7, 0x73e57e9f, 0xd19236de, 0xf9c036ba, - 0xdb46fde1, 0x6233f9c5, 0x8ea467dd, 0x5037fd52, 0x13ef1165, 0x889d3c33, - 0xf741acfb, 0x72f75174, 0x9fd36d78, 0xdc1fac77, 0xed7286ff, 0x8b86d9bd, - 0x5a622e3c, 0x4b8f42c2, 0x6daa9798, 0x10cea9bf, 0xb9a82f7d, 0x6bd9bb4f, - 0x7d0f5e88, 0xd621d417, 0x1f71dd9b, 0xcd4fbfdd, 0xa644f9e6, 0x04e28c65, - 0xa66df7d1, 0x3d1e5db1, 0x8c0dcfda, 0x38e8fdec, 0x52a9e639, 0xb181b0fc, - 0x79e5122d, 0x7973df6b, 0xfe73fea6, 0x3ad6947d, 0x760ec79c, 0xd1d3da10, - 0xf7a849ef, 0x51f7ea5a, 0xdfab3c55, 0x4dbf4a8f, 0xc163eb47, 0xc6aed429, - 0xb87bf1fd, 0xf911e955, 0x7f582be4, 0x2b7f7a7f, 0x9bdf7b18, 0xcf29eadb, - 0x7fbc7320, 0xb29a186c, 0xc8784614, 0x6fc8c85a, 0xf2683c00, 0xdbd94c09, - 0x16e79f69, 0x224c3633, 0x33da683c, 0xfdd3d340, 0x7e6d42c0, 0x0353ec01, - 0x57abfb47, 0xd94d53f2, 0xf39597f9, 0x9a638a57, 0x94e4bdc4, 0x97fbe251, - 0xed14aca5, 0x9edbf4a2, 0x0738f3a1, 0x5f7181e7, 0xdd629c74, 0xf1826e3b, - 0x77fc8fd1, 0xe2cd2fc1, 0xaefd5b6e, 0xf4c8f30f, 0xce549b1e, 0xf30d2cd7, - 0x12e97bf2, 0x8a6e7c46, 0x8fcc6667, 0x1e4c2a97, 0x04c9bbc4, 0x32596c30, - 0xd4067332, 0x7b3c45eb, 0x8464c48d, 0xf3315599, 0x5dfaa3f8, 0x577d10a1, - 0xd479a868, 0x20b22bef, 0x679d4e7f, 0x2ef577d0, 0x7bf93cf3, 0x6be7e8d6, - 0xcea99e29, 0x87fe143f, 0xbfde8efa, 0x8137bcd5, 0x441d53c7, 0xf4038daf, - 0x417cf04a, 0xca3cf88f, 0x66d5bb85, 0xfa29577b, 0x4c1e670f, 0x114a3650, - 0xd2ce08fb, 0x7e03eff3, 0xd7faf1bf, 0xbc927761, 0x1897dfef, 0x8beefbef, - 0xdae422fe, 0x09597c3a, 0x191a5ef3, 0xfba431e5, 0x29973faa, 0xa0f600ff, - 0xdf111391, 0xd6f18049, 0x1fefce3d, 0x3e77e336, 0xc0e7fef0, 0x13edfe40, - 0xd1f76c16, 0xbcd43677, 0x5da3cc5c, 0x3ef0325b, 0x837df472, 0x89c611bd, - 0x99b26f98, 0x9f401305, 0x0531f4a4, 0xb9ecf3bf, 0x03a65468, 0xa07d6c7e, - 0x93bf0150, 0xa5ee8999, 0x337ead2a, 0x0ae10eff, 0xef676916, 0xefa56e97, - 0x64bf86bd, 0x3e14bf94, 0xc3ee88cf, 0x70c4c39f, 0xddf8ff2e, 0xcbe47afb, - 0x7a5d7da9, 0xfb93f3d4, 0xf67fa4fc, 0xed3d4fd9, 0x9962e7e2, 0x751f9111, - 0xcf545b1d, 0x979f8ae9, 0x5f27ea2c, 0xfdf86a30, 0x46a35eda, 0x5b17c81e, - 0x65fd46be, 0x67aa89ea, 0xe3e33fd3, 0x2dde28f9, 0x53edb5db, 0xdbd03e44, - 0xc35fdf2a, 0xbc73a1ae, 0xcf331698, 0xd5dce06e, 0x71e26e73, 0x79c7c674, - 0x9ff7946e, 0xff404d46, 0xe87147c0, 0xd82fc464, 0xdd952917, 0x58798ecc, - 0x8e994ce5, 0xf3b2bd72, 0xe487a41d, 0x3c0f3cb3, 0x5ffdfc7a, 0x7e8595be, - 0x9dc99ec3, 0xed2f6859, 0x3d15f2f9, 0xd3d5578e, 0x193eb0cb, 0x58a41e4a, - 0x10aa784c, 0xcf5033b4, 0xf59144e3, 0xe74a9eb4, 0xcfe4e565, 0x871a4e50, - 0xd933df6e, 0x87e4c2c2, 0x3da02675, 0xfe7c7cc7, 0x57cab364, 0x70972fec, - 0x9f81845e, 0x52ea54f6, 0x7b9f616a, 0x6c15919e, 0x46f3d3dc, 0xe7bfce02, - 0x7acd39ec, 0xf322fe98, 0x5afbac45, 0x2b53ee71, 0x7efec97b, 0xf92bac4a, - 0xa1c52f6c, 0x30de9553, 0xc3d4dbea, 0x37fefa7a, 0xc8bcf0b3, 0x38a14c61, - 0xfc5eba9a, 0xd73e2a6e, 0x88de7282, 0x5632b3fb, 0x287eec28, 0x55832a33, - 0xcc9a8f98, 0x6b484a76, 0x417d2b53, 0xa5e4e7a4, 0xad939e9c, 0xbf18c3fe, - 0xa3af5e4f, 0x59f24538, 0xcbf406df, 0x0565cb92, 0xf84ae4c9, 0xb7f310ec, - 0xf9d4f98a, 0xa88cf5d5, 0x7ee84bf4, 0x62e3b324, 0x132aaefe, 0xcc5abf8e, - 0x59eb14ef, 0x2c3be8c5, 0x55ad67c9, 0x83272fe8, 0x33df419d, 0x9a79e2b8, - 0xb745f335, 0x99d94f27, 0xb1e0e745, 0xe30ad91e, 0x365b64a5, 0xceb94154, - 0x32ff23a1, 0x3c5187a9, 0x9d27a93d, 0x4f527de4, 0x8a2728a1, 0x0f4269fa, - 0xd4933970, 0xaf2d50f3, 0xa4d2a16f, 0x3f8717ca, 0xda98fb8c, 0x717cb8cb, - 0x98be4978, 0x517cb8d2, 0x9556b8e9, 0x325acc2b, 0x0ff7ea1f, 0x06b5acff, - 0x73f77b9e, 0xbbe5fefe, 0xbcbe5cd9, 0xfbf725fb, 0xd3bf694d, 0x42aa5ca3, - 0x4dfa05c3, 0x33edc0bb, 0xbaab1f95, 0x48113625, 0xe7839a63, 0xc8ba1f87, - 0xd9843b9f, 0x63af00d5, 0x9529c912, 0xdd056b6e, 0x83eab3ae, 0x81fed849, - 0x3477de89, 0x98e5ce39, 0x83fe1ec1, 0x7c41f7ae, 0x33f7f8ef, 0x415def7a, - 0x437e82f5, 0x9a2e494b, 0xe4396c84, 0x3e416058, 0xae487984, 0xe918721e, - 0x3a080ebc, 0xe9af673e, 0x5b3fc308, 0x69fcdfcc, 0xc1ffd43e, 0x9340eb9e, - 0x1e973d4c, 0x885f2f41, 0xe82b3bf3, 0x7bdd29a6, 0xfc04c953, 0xcd1e62fe, - 0x0dfece7b, 0xdcb27fbd, 0xc69f1ff6, 0x3aa72efa, 0x4f7cfa8e, 0xcf19a568, - 0x1f9bd0f5, 0xabb4409f, 0x7b235fe3, 0x7ee3e4ef, 0xd0f89a33, 0x78cf3b12, - 0xadf3fc90, 0x8b7f9688, 0xc80f864a, 0x91667abf, 0xe7121e79, 0x1e4259eb, - 0xddb8554d, 0xe7e56f5e, 0x5fb25f55, 0x8b8afea6, 0xd2af55f6, 0x5ae4f28d, - 0xf29b7fe4, 0x7d4bd124, 0xbd97a73e, 0x0a0f9e82, 0x63ecce7c, 0xed97e89d, - 0x196e982f, 0xe23ef80b, 0x1cff13d2, 0x52c6bb19, 0x291dcf06, 0x024bf095, - 0xd6c97a6c, 0xcf00a9b5, 0xa7a22452, 0x1dad92fa, 0x967fd04d, 0x03a94135, - 0xb3f9e8f8, 0x0eaf3416, 0x9784bc05, 0xe3f872e9, 0x1b9e1754, 0xcaccd3c7, - 0x4ffe8cb0, 0x8cbf63bd, 0xc46df6fa, 0x2ee311ab, 0x7567c11e, 0x6a571f04, - 0x238fb82c, 0x2f2126a5, 0x5e51e33d, 0xd537cace, 0x7c75a18f, 0x1a4c6c7d, - 0x506f77be, 0xa73c95f8, 0x7e82c9ff, 0x6b27ccea, 0xccdfa053, 0xd7196692, - 0x912cd47b, 0xd7da3cfc, 0xc793f944, 0xd2ac393b, 0x74073d2d, 0x5b6fbc79, - 0x6fb61273, 0xd53e4897, 0xe21d2f2b, 0xa7d38fea, 0x0b0f7e3a, 0x3077e1b6, - 0xb7af29cf, 0xb1f53e60, 0xcccf05be, 0x7f1c3c01, 0xb8c43f53, 0xc0ad1f4d, - 0x244cdf71, 0x356d9e3a, 0x8cb1f469, 0x5e84694e, 0xd36f1ead, 0x0d4af5c0, - 0x29cfd3c5, 0x7806e592, 0xad5df3de, 0xd191397b, 0xbd77da52, 0xe14c7be8, - 0xa1cc797c, 0xd63cbe23, 0x8a9cb8f7, 0xfb4659f0, 0xde769991, 0xb21a92fa, - 0x5b29ceaf, 0x826744f5, 0x54f1d50f, 0x4f8a3e3a, 0x9ced1e23, 0x6df68fff, - 0x1dbd20b3, 0xe323bf75, 0x89675d39, 0xa1d0571a, 0x5df0dfaa, 0xda9fa471, - 0x7ef3fb51, 0x3851eb86, 0xd7946bfe, 0xd57d238f, 0xa7a2643b, 0x9afecaa3, - 0x27bf8614, 0xffecd262, 0x9ac91dfe, 0xda7597f1, 0x5db47034, 0xdbfdcfb5, - 0x0ec4cba7, 0xd847a466, 0x3ec2f947, 0xe0771fd2, 0x1768aefa, 0xf7e8eb29, - 0x45d90649, 0x8a2edcf9, 0xbe5487b6, 0xb889d66e, 0x65c78eac, 0x58dff9a3, - 0xf1eec3fa, 0x8e492ad8, 0xc65bbfbc, 0xbe9073ba, 0x8612a3e6, 0x75d01ef1, - 0x15fc23a7, 0x078b6deb, 0xccad7c39, 0xbfbf6976, 0x3f37bfca, 0x1e77d4be, - 0x367495e5, 0x6561df4c, 0x07e518ab, 0x9e786be8, 0xad665e11, 0x258bd488, - 0x8d2df1fd, 0xd84ba45d, 0xac78859b, 0xf1e46b38, 0x38e89e8f, 0x851fea97, - 0xae2bf225, 0x93ea2e52, 0xe67bb8f9, 0x7f6778f0, 0x938f3379, 0xe5fc0915, - 0x5d691a94, 0xdcf7808a, 0xb59efb16, 0x41fa54a4, 0x07dfa2f9, 0xef8029df, - 0x61e690af, 0xb1553d9e, 0xca5291d7, 0x9777b5e3, 0xa14af278, 0x15f12a2c, - 0x3d5e2296, 0x77d35f60, 0x9f643dc5, 0x33bce3a9, 0xfd16e3ca, 0xbcc96146, - 0xee8f0edc, 0x6863ed07, 0xe3d8869c, 0x7a38fb40, 0xf6ec6e7e, 0xfc39b843, - 0x30fb237d, 0x0c0643d2, 0x52f2a664, 0x16e5e32a, 0x8846aefa, 0x1e0de7fb, - 0x9146f3d2, 0x103788af, 0xf4c7fc91, 0x1cbe34f5, 0x58f7419e, 0x8325d82d, - 0x7691f9fb, 0x6a84ac94, 0x6aade322, 0xdf94a8b9, 0x1528ce73, 0x604cf3ef, - 0xa8afc813, 0xea3cfcbc, 0xc3cd43f3, 0xc85765ec, 0x63f35e7b, 0xc3fa49d3, - 0xa55f27e4, 0x4a0e607d, 0x1f39df91, 0x4a89bf6a, 0xc28a1c94, 0x5cf350d3, - 0x22dc79ed, 0xd76af6e8, 0xcc7a655d, 0x2ed1f94e, 0x056b07ce, 0xd5dbf57d, - 0xbe3f1e3f, 0xfe861f3f, 0xfefbd9ca, 0x4a7ef893, 0x37a56842, 0x145e7ec6, - 0xe531f9fb, 0xce70d3c1, 0xfba18c1b, 0x0799ded1, 0xd20263a7, 0xf1f2c77b, - 0x9eb005f0, 0x2dfcc537, 0x6feb9596, 0x1c5b4785, 0x1ef998ba, 0x7a78fe6f, - 0xd93f0da2, 0xdce395ff, 0xa7206dfb, 0xd07d1e5b, 0x7581b0ac, 0x15d96b30, - 0xe347f9ce, 0x6d5d7513, 0x625e305b, 0xf7aabd4d, 0xaf5c5a14, 0x697de024, - 0x764de7ed, 0xb4460efc, 0x43c6a03d, 0xc6a5bd54, 0xa4bb544d, 0x1fe3c1c2, - 0x7bfced33, 0x69f6153d, 0xb20fdfa4, 0xaff21aae, 0x226d3b30, 0x19fd0ab1, - 0xe4fb5add, 0x4657bf3a, 0x9eda2a3b, 0x45334da8, 0x7abd07d9, 0x1715df94, - 0xfe54fdb5, 0xc454acf8, 0x17795451, 0xcf9a4765, 0xbb40499f, 0x670bedeb, - 0x8d142e28, 0x5c2eeb9f, 0xaebd9fde, 0x83f74f5d, 0xb7ad71d1, 0xfdd2e42f, - 0x1baf11a0, 0xcccad4c1, 0x808cc43f, 0x6b7b4c97, 0x18ec1195, 0xf82983a3, - 0x58fc36dd, 0x8d0dc633, 0x7c9c7817, 0xd7fb9d84, 0x2fc18b89, 0x95335185, - 0x78c17da0, 0xef48ce7c, 0xef5d99d3, 0x09bdbd91, 0x9e2186ea, 0xa6199ec7, - 0x5307118b, 0xc08a63cf, 0xb7e66eef, 0x4d81efe3, 0xf7f78bb1, 0x59db462e, - 0xa22d3cfc, 0x2d62e27f, 0x3ce22d3e, 0x435b8327, 0xd3ec79df, 0xe7116f3e, - 0xfb1a596b, 0x63a3ec1c, 0x7aa2439f, 0xc5b6130e, 0x596c39e1, 0x758a4dbc, - 0x2f8b990e, 0x845b0e7f, 0xefd2a95f, 0xb204acb4, 0xe8a6f7af, 0x7b41fbe8, - 0xcb59c313, 0xb2fdfe31, 0xaccfde99, 0xb4367110, 0x6b9f10a4, 0x84bf97b7, - 0xa371db71, 0x7b8e74f5, 0xbcffd125, 0x60feff8e, 0x1fea78cf, 0xf883b327, - 0xfb0780bb, 0x1bbbe9aa, 0xd3bbfcd1, 0x33dd007a, 0x3db9ceb6, 0x839c016b, - 0x9980fb25, 0xcf839bfb, 0x4a3fef07, 0x7b4bbe05, 0xa654b9f8, 0xbda3d49d, - 0xec66f25e, 0x8fe351f3, 0x3a9da47b, 0xaa362b20, 0x98fc8baf, 0xeca33b91, - 0x642db3e9, 0x47c65b67, 0x39c0f7d5, 0x9f8ebdd1, 0xa1d916ec, 0x87ebaf3d, - 0x114aa738, 0x7d7f3087, 0xfb65e28a, 0x7e714efa, 0x25c6d1e9, 0xfe5df727, - 0xe7135e9c, 0xa1c453b4, 0x00e22e7e, 0x7e7fc29d, 0xf2a4e023, 0xea9b80cd, - 0x04280adf, 0x0b940aef, 0x77cfc161, 0x47cb3e56, 0x84aaaf17, 0xcf47edfb, - 0x7f7dbf73, 0xbe83a862, 0x42de74ef, 0xbda417df, 0xdbbf144d, 0x2c727c07, - 0x1fbf49ce, 0x4cdb3478, 0xa5a3b3f1, 0x8a7bfbbf, 0xd16b7cbb, 0xc70bb8f1, - 0xeb4e7ab3, 0x6f184e70, 0xee8b855d, 0x47e036a5, 0xeeffa114, 0xffbe8932, - 0x040e1b34, 0x3a5445ef, 0xf169f537, 0x65ff0f59, 0x1ddff195, 0x617f42c8, - 0xa4e88b8c, 0x2273ef42, 0x4fba373e, 0x571e5f91, 0x871beed8, 0x7af18071, - 0x14fbbe26, 0x3bac4534, 0xe0426f0e, 0x44895379, 0x0a1a73df, 0x86e5d1bf, - 0xa32fae54, 0x3475ffeb, 0xdd1b83d7, 0x773ce8db, 0x50b2ba3b, 0xf913efaf, - 0x2964b310, 0x285fbf48, 0x1cb1dd77, 0x65915bf6, 0xc011bb1f, 0x6853a32d, - 0x4f4afbfd, 0xd8f81c53, 0x21c65785, 0x76b31dfd, 0x79ce305a, 0x53dfc9cc, - 0xf9951387, 0xf29db77b, 0xa4f2312d, 0xe958f2d5, 0x95fdfa22, 0xef7cfc7f, - 0xdf7cd1da, 0x0af5524c, 0xfb815b8c, 0xdef9424d, 0xc3f902b2, 0xfc83b998, - 0xaa73e8cc, 0x88b35f70, 0xfc64f3de, 0xb6bf4f7b, 0x3f782c86, 0x0267ed1c, - 0xff426c7d, 0x3d04f778, 0x5eadaf7d, 0xe782e7e6, 0x1fa4e788, 0x997e13a3, - 0x65667c76, 0xc0fa633e, 0xde1d6079, 0xf13ad0d7, 0xadefaa3e, 0xf86292bf, - 0xc9d683b5, 0xf9589efc, 0xcdcfd1b0, 0x9a20b276, 0x1615b386, 0x709fa176, - 0x99c69f30, 0xcce3e56d, 0x9b7c7112, 0x1759ffa0, 0x81df9475, 0xcf80d6f4, - 0x7927cc95, 0x50f5cc72, 0xb7ac1d57, 0x41c6ce1e, 0x569346fe, 0x5b39090e, - 0xf745525f, 0x07dcc7bd, 0xbfbea3c6, 0xe1e574be, 0x9fc22732, 0xb74154d4, - 0xd52fa529, 0x945a5d20, 0x4c2f8a2e, 0x5d74cb76, 0x36b97d78, 0x17afd14e, - 0xb44bf4a3, 0x928fa8be, 0x54f7113b, 0xf9c4434e, 0x4b9f72cf, 0xab83a488, - 0x2f1ccbc7, 0xd67baf7e, 0x1da71e05, 0xe9f7978c, 0x7803a573, 0xd8ef3e89, - 0xa73e8978, 0xeaad3c01, 0x8c1dcbaa, 0xbf6f155f, 0x1ac9792e, 0x8d1be799, - 0xaf8a1fb7, 0x4156d1e6, 0x579e5caf, 0x3b7dbe08, 0xb771443b, 0xeff94bb7, - 0xff731d4b, 0xb3bfe296, 0x0d63a858, 0xcbe045ca, 0xe8f94239, 0x344ce423, - 0xf4f8061e, 0xbf2e283f, 0x28b7f3fb, 0x21caaa2e, 0xea25f213, 0xea1fc113, - 0x1f9099b9, 0xf02f6f91, 0x2d5e87ef, 0x457ca87f, 0x383f21eb, 0x1fcc8fa4, - 0x5fc5dffc, 0x18cd717b, 0x52167617, 0xd1cab83c, 0xac7bc7a5, 0x3dd250c9, - 0xd27f8892, 0xf5919c3a, 0x591c6e3c, 0xa12f714f, 0xa6b8d4f7, 0xbb3ebeda, - 0x5518412b, 0xc24d47a4, 0xc4fd51de, 0x64538e7d, 0x54faaa7f, 0x57fef716, - 0x08f74fab, 0xfb543a7d, 0x79bb73de, 0x43cbe7dc, 0x1c800f3d, 0xa46f9c9f, - 0x0e4cb8ef, 0xa3dfcc3f, 0xfe498470, 0x9137746f, 0x69fb0c1f, 0xe604a346, - 0xf3e64475, 0xf3bee5a9, 0xefd60a6d, 0x0af4bb95, 0x16ff07f5, 0x568603e0, - 0x0d869dfa, 0x137d738f, 0xd651f457, 0xba83dee5, 0xe6994fb3, 0x61efc24a, - 0xdf835f6f, 0x8c2a0b01, 0xb598ebbe, 0xee458bb4, 0xdc31a5f7, 0xff9c9daf, - 0x68071dd6, 0x69ea1fdd, 0x035768dd, 0x9d964f9d, 0xcfe7050e, 0xfd23dbf6, - 0xf7d97dec, 0xb7009dda, 0x086c697c, 0xa3c37ad1, 0xecf3017e, 0x078d5733, - 0x73ed8d4b, 0x0bf5181f, 0x7346c7c0, 0xa3cc04d5, 0xdbdfb6ac, 0xdae51f3e, - 0x60265bd9, 0xbcec1bfc, 0x83b7d456, 0xcdb7dff6, 0x5d3bbf8c, 0xd69f78ed, - 0xabafa231, 0x5abfbf06, 0x48f7e0ed, 0x87bed1be, 0x7b404cc6, 0x73c1ec39, - 0x0c9f344f, 0x164cdd22, 0x2f1765eb, 0xbd41fc51, 0x9e73d997, 0xf8ff47d3, - 0x8fb80f40, 0x455cbf6b, 0x7db922f7, 0xa026f9ba, 0x3c7d75d5, 0xf1db0c7f, - 0xbf58e07b, 0x001d8628, 0x4be75cf3, 0xcaebf3c6, 0xde8637ba, 0x36fbedcd, - 0xf6e783e0, 0x44bc7064, 0xc31e6fb7, 0xafb882ed, 0x9272cfde, 0x7ff5c03d, - 0xf312c0b0, 0xa9b7553b, 0x3b1ad2fa, 0x552d450f, 0x23daa579, 0x21b35f80, - 0xc69bbf02, 0x7cfdff70, 0xf103a7a9, 0x7fe77df7, 0xe50b710a, 0xf6cf52f1, - 0xae91c331, 0x97ad5f04, 0xee01c663, 0xc5a3f31c, 0x13416e2b, 0x73beabef, - 0x86e96fe9, 0x7441dba6, 0xf8e95065, 0xffe3a221, 0xe27bf48b, 0x20efd0fb, - 0x14fe7479, 0xd347c3dd, 0x03bf4ab1, 0x9be6c874, 0x79e80692, 0x7ec1ba28, - 0xe806928b, 0xfb7ea87a, 0x931fbfce, 0xe9c607de, 0xabdd2cbd, 0xd059b7f4, - 0x540f7a91, 0xfd79ce29, 0xfeec8cd7, 0xf5463da3, 0x7e35c677, 0xca3fe811, - 0x72b0aea3, 0x37b47fb9, 0x3d19fb97, 0x9a9fba66, 0xbe295ee9, 0x235d0dbb, - 0xf211adc6, 0x75dba67e, 0xeaaf3959, 0xfddf550b, 0x43777c4f, 0x00800098, - 0x00000000, 0x00088b1f, 0x00000000, 0x7dedff00, 0xc754740b, 0xeebd6095, - 0x91a93fd7, 0x16883e9e, 0xc085a092, 0xeb404616, 0x7d3d05ff, 0xa71f3210, - 0x900b18c1, 0x04e08b4c, 0x60dd491b, 0x9e3d90e2, 0x123231a1, 0x1f62cd9f, - 0xbd6678cc, 0x8c030d39, 0xc077b19d, 0x0b611c56, 0x3837e2dc, 0x71c6ec4b, - 0x3c4c9c18, 0x6c0843c2, 0xc718d36c, 0xbc4ab243, 0x0f7adef7, 0x0b756bf5, - 0xcceb43db, 0x40e75764, 0xaabd5ea9, 0xfeeb75ba, 0x7ad3d56f, 0xcecc6333, - 0x53f817d8, 0x08acbc3d, 0x65cb191a, 0xfc05f3f4, 0xebf2e2db, 0xdf632b25, - 0xb4cbeeb9, 0x2c93f943, 0x1e670adf, 0x355faf63, 0xb188acca, 0xf6e3a9ae, - 0xfa87b3ea, 0x8c08758f, 0x127b4315, 0xef768674, 0x0077c154, 0x27d1311e, - 0x7d1e9d2e, 0xfd4c9fde, 0x8795cdae, 0x9d32fab3, 0xaf7a6863, 0x59b18d3e, - 0xca0e9bf8, 0x332d9320, 0x5aedcca0, 0xcca012c7, 0x9636f92c, 0xb12e624c, - 0xf2933184, 0x6bcae99e, 0x39f015df, 0xfe831993, 0x56f595eb, 0x0d5d7f30, - 0xcccf31c0, 0x3889f1bc, 0xc9c9d37a, 0x97cd5ed0, 0xd769e30a, 0xfe9fde1d, - 0xe4f329a5, 0x572e3630, 0xfbcdf5a0, 0xf04cf98c, 0xeb6e756b, 0xe7033602, - 0xd1cc7187, 0x1e60a9c7, 0x1d01e999, 0x2adb5ee5, 0xaa6b3fe8, 0xafe5e1c9, - 0x6cdef84b, 0x3e1bdfc6, 0x4ac67ace, 0xe2d9c686, 0x54fac809, 0x4c498ec6, - 0x6f5b2fe9, 0xf8e767c1, 0xb2857ac3, 0xcd6e533e, 0xebcbc455, 0x07e1c792, - 0x860f6778, 0xcb1d6f8d, 0x55633a58, 0x8b9f699f, 0x387d6d0e, 0x58fb305c, - 0x5f4fe5fa, 0x33467cc0, 0x5d398fc7, 0x5d79f847, 0x3e90fa32, 0xeed4ae2a, - 0x4b189362, 0xfc87ec96, 0x992adcf0, 0x36053e1d, 0x7e53f633, 0x0402b8af, - 0xc29fed04, 0x738014bf, 0x5aef6e9b, 0x16ddd027, 0xa21f4c6c, 0x4c0b2597, - 0x2e96381a, 0x9bd4d449, 0xea69c79a, 0xd44f57cb, 0xdb736fec, 0x43fa9add, - 0xea6a661b, 0x354a27ae, 0xd59d55f5, 0xef56f19a, 0xff69ab9c, 0x686feed6, - 0x7f9e6bea, 0x747f5350, 0xe911caff, 0x885f1a22, 0x89e991b6, 0xd23b0579, - 0x3a4d88bf, 0x9cc5cffc, 0xf7f7a3d3, 0x7ec27f21, 0xb7af6ebd, 0xd5fe82ad, - 0xe78d3f57, 0xc5f4b4fd, 0xf90072bc, 0x17d956a3, 0x402bc798, 0xad528d7b, - 0xf445be95, 0x4536635e, 0xee951be4, 0x11560ab6, 0xda66afc7, 0x6db0aafd, - 0x7e47aebd, 0xebd01a2e, 0x3759be61, 0x2157fcb5, 0xc706fc35, 0xc7afcc67, - 0xa5cb84f5, 0x9318eeff, 0x609e397a, 0xfc017fb5, 0x8cc9acc4, 0xa3c74795, - 0x5db7a74a, 0x6f5f6337, 0xeafccadd, 0xa0582b7a, 0xda3ee90e, 0xfc3b67ba, - 0x516b927a, 0x5ebe1dd6, 0x6feffe15, 0xef815f86, 0xf323ff5f, 0xdb1013ed, - 0xe6fc88b2, 0xcfeb5ddf, 0x02402bb5, 0x7a1527bc, 0x278291a8, 0x0e908b12, - 0x83650398, 0x51f99071, 0xc133d40e, 0x9652846f, 0x38af041c, 0x3034ef68, - 0x7e71eb2a, 0xa6861071, 0x35eb45d2, 0x288dca0e, 0xa92c456f, 0xebc79cee, - 0x875e068e, 0xd52ea8f7, 0x3ee7baf2, 0xea92875e, 0x43af275e, 0x5aefaa3f, - 0xb8cef58c, 0x014489c0, 0x5825beeb, 0x5a1e0e37, 0x05ff4bca, 0xe4994a81, - 0x5de83896, 0xec7ea7a7, 0x3707af22, 0xf2d0fa71, 0xf65e3183, 0x5f19b3f9, - 0x813f3c3d, 0xfdc24dbf, 0x006fd75c, 0x828ad43c, 0xd5ef0ec3, 0x3f87320c, - 0xe4d5f715, 0xe097d990, 0x3133a033, 0x8ccf886d, 0x4ab1982c, 0x0f793e20, - 0xedcaadf1, 0xe968e3e1, 0x5af51eab, 0xfc3bec01, 0xe51931be, 0xfaa7a730, - 0x2c12e0b2, 0xd013f9f1, 0xfc327b3e, 0x1f4e1e4b, 0x32a25c2a, 0x5fb5a55f, - 0x32b6aa8f, 0x59b72618, 0x8559d117, 0xd92c9d79, 0x716dcb87, 0x2e2fe550, - 0x56e1c22f, 0x1f39ade5, 0xfb1a6cf8, 0xb9967c3a, 0xaeb36a0a, 0xd9f0abbe, - 0x933e30ba, 0x8496f7ad, 0x321019f0, 0xb7d9f0d3, 0x276e9e89, 0x83094e5f, - 0x4f182675, 0x23e80cf6, 0xc05499ca, 0x3e244243, 0xb21bfb9b, 0x97c8a21f, - 0x5817f037, 0x987e6e67, 0x5cf4519c, 0xfee7aab5, 0xdda2b3a8, 0x117a67e2, - 0xc87c70cb, 0xd2313b2c, 0xbe3cb573, 0x6bba0609, 0x90f80ea8, 0x63be810f, - 0x06dc151f, 0xcec99bcf, 0x805ab862, 0x31e2aac7, 0x71ad6e8c, 0xec909d2f, - 0xecf505bc, 0x4e6e8518, 0xdf11a766, 0xc7bd76c3, 0xb59de442, 0x01f1cbe8, - 0xc70937cd, 0xbf226673, 0xc6db40d5, 0x33fde182, 0x99f00fb1, 0x3e7cc835, - 0x08eacf78, 0x46af5808, 0xf48d9efd, 0xfe51eacf, 0xe8095f57, 0xe5a5ea25, - 0x00745b97, 0xa4013fbf, 0x517c8b57, 0x642e9c30, 0x7ee3d3e6, 0xaffdd57c, - 0x90341fb6, 0xffdb0ebc, 0xcfb0419a, 0xd5394e00, 0x1afa20e4, 0xc8cf6464, - 0x48c7c14e, 0xbc21acbe, 0xade3f6a8, 0x176826f6, 0x622e91e8, 0xf640b37b, - 0xb36ca7d0, 0xf305f381, 0x867a55fa, 0x30afcbe7, 0x34ed1139, 0x7ed4f3cb, - 0xfa23136c, 0x3c97b6a8, 0xb8476755, 0x44cc7606, 0x0abd24b8, 0xc7153f97, - 0x70e260bd, 0x7f08daf9, 0xe4fe0ad5, 0x43331d41, 0x694fbfbb, 0xff5fa30f, - 0xfcd3b720, 0x702bc44f, 0x43f0c8dd, 0x4ed007bf, 0xe5689306, 0x43ff03dd, - 0x69dcf784, 0x01df3f77, 0xf028ae5d, 0x6e856ffc, 0x5124da3f, 0xf5cd3eb9, - 0xc7a07cfd, 0x7c6e917f, 0x0fc866e2, 0xd5f74439, 0x9027cff6, 0xd9f1521e, - 0x10f48637, 0xe8f84dc2, 0xdb8344b3, 0x387510aa, 0xe5bf0abc, 0x2a57c88c, - 0x577c2a9c, 0x0bab7a7c, 0xe7b37bc6, 0xf61c135f, 0x454bf821, 0xfb847ee7, - 0x674fc1cd, 0x92ef88b8, 0x34667635, 0xfc5266f9, 0x964ca488, 0x3ea2a62b, - 0x85cc7388, 0x74cb8c75, 0x364cbad1, 0x02fd1da3, 0xf393274b, 0x82734860, - 0xf7f08ccf, 0xd2ec37a7, 0xa9d6fb43, 0xfbc13322, 0x36bcb35b, 0x09fea75a, - 0x9399eb86, 0xd60361e9, 0x6577f3e8, 0x9c11293e, 0xbf475083, 0xa2f1c6c7, - 0xf8f4689f, 0xc75fb9e0, 0xc10a1cd6, 0xee02c1cb, 0xe7cd9d8f, 0x1e17dae5, - 0x842976d9, 0xad0fda3f, 0xbdddd4d3, 0x2976dbdf, 0x106ede54, 0x3697dc44, - 0xd9db8e85, 0x5ff404c0, 0xe13b455a, 0x903743a1, 0x2c6bf586, 0xae0a7e78, - 0x008fe70f, 0x5be73fff, 0xd2ff3d62, 0x8ff650a9, 0xff69fee1, 0x0df91f24, - 0x2b1ffcea, 0x5f38ffeb, 0xa6387317, 0xb3ba1e01, 0x9f70c5bf, 0x3f7c6c6a, - 0x7a72504d, 0xf54372e6, 0x739e8677, 0x3ea55179, 0x73de3a0f, 0x1ce91d12, - 0x994c76a8, 0x7de911f6, 0x71bbd227, 0x48b5bea8, 0xf08be8d7, 0x220573fe, - 0x16c07bc1, 0xa15b3db9, 0x5c139d97, 0xdfe8d9dd, 0x6c73ab3f, 0xcbce2586, - 0xe51e3adc, 0x7adb56fd, 0xe2e653a2, 0x38c058eb, 0xf4cbcebf, 0xd1e81978, - 0x82b7fe79, 0x8dd62a42, 0xf886c2cc, 0xe70bf557, 0x01d13e89, 0xd7f2bbfd, - 0x5ddd7199, 0x1c66f5b6, 0x82d684cf, 0xea3c386e, 0xe6ec0fba, 0xf4cbcef3, - 0xb2e9e089, 0xc57bb9b9, 0xa33fa801, 0xee5e7bac, 0x6aaf6a3a, 0x09149ff4, - 0x4367e07f, 0xf568e8dd, 0x87263ce2, 0x3ac246bd, 0xb2c66c73, 0xec89784f, - 0x0dbf5513, 0x9dad4fe9, 0x91bafa72, 0x15d763e4, 0xf244cf9d, 0x07305e53, - 0xbcaf9fde, 0x7b720d6d, 0xa3bf6bbe, 0x1cf7c45f, 0xf3e3f902, 0x764dbf73, - 0x2e77359d, 0x56b3e7b7, 0x98549179, 0x3fa1f04f, 0x5bc54f31, 0x195f569e, - 0xa0b7171d, 0xd4de30fa, 0x2c59d1ea, 0x2abe90c0, 0x70f3fcc2, 0x40bb3b7d, - 0x5972d7b1, 0x2d2bda31, 0xc863df26, 0x420d960f, 0xe2a1c23a, 0x8e814575, - 0x7c8620e8, 0x942667b0, 0xb465d95d, 0xd3ccfaaf, 0x5f980417, 0x4366df17, - 0x8cdbd0be, 0xb31bc47e, 0xa80d1f8a, 0xffc24df3, 0xb7b22533, 0x2f848eb0, - 0xfc79397d, 0x86c7966e, 0xb032eceb, 0xa7f248a6, 0xfdf380b6, 0x927e5907, - 0x8ddad10f, 0x7bd2041b, 0x66377caa, 0xc237d932, 0x5c8cdb78, 0xd25f80ce, - 0x3ebf402b, 0xffa017a4, 0xf7b35a17, 0x7ba205e9, 0xadf1e519, 0x12efb152, - 0xfe1fb90b, 0xca898166, 0x547eca93, 0xc336717f, 0xaffc8235, 0x8430f2aa, - 0xc7ca94df, 0xf1f26533, 0x732f224c, 0x2e3f7195, 0x5cdc7ce2, 0x5fb97b14, - 0xfb7a339a, 0x8d7a4b1c, 0x90285287, 0x98dd79e8, 0xc52e4987, 0xa3396f12, - 0x5da33788, 0xa7073fa1, 0x73fdb513, 0xaaffde45, 0xb274e620, 0xe51472b4, - 0xa4e92c41, 0xde83cfe2, 0x79ff97cf, 0x68da47ec, 0x99a3e3ae, 0xe042d4f2, - 0x2e9cbf93, 0x96e583df, 0xbbdb23d7, 0x772f63f3, 0x72801ed3, 0x37df04f1, - 0x79b3e923, 0xfb97b185, 0x48bed14b, 0xf845f6e1, 0x3d15cbfc, 0xd2794b14, - 0x11b36504, 0xff011fd6, 0xfcc28e8f, 0xef5073cb, 0xe5817b72, 0x0fa4b99e, - 0x67e1dfb1, 0x3ec42eb2, 0x1c147b06, 0x0543b441, 0xeddd9239, 0x2d7efd8d, - 0x643f487d, 0x5c61ccaf, 0x2ff3a81f, 0x7af8e12c, 0xb0e0147a, 0x25eade00, - 0xc29baf6e, 0xbfcb50e0, 0x7dbd8c2d, 0xe043e92a, 0x1fbb0548, 0x444205cb, - 0xd0a7af7b, 0x1a7e7318, 0xe2d9780b, 0xe4918d60, 0xefd8c9c9, 0xca0d9a4b, - 0xd3cee9aa, 0x4b96d728, 0x5c60e787, 0x1ff8fbf9, 0x79d21be6, 0xc1a561be, - 0xaeff45e5, 0xbc3bb24b, 0xac478c76, 0x7ccafaa2, 0x52af43bb, 0x94dfb63e, - 0x6c05db7c, 0xe57d51d7, 0xda1f24ef, 0xd617dfc3, 0xf1c6c99d, 0xfb1deb36, - 0x959dc618, 0xe78d837c, 0x9e36ac1b, 0x3c6d109f, 0x29b560ef, 0xcf1b0779, - 0x4a6d583b, 0xf3c6c1de, 0x929b560e, 0xbcf1b077, 0xe4a6d583, 0xef3c6c1d, - 0x7929b560, 0x3bcf1b07, 0xde6a6d58, 0x1538d3c1, 0x9e3691e3, 0x78dab077, - 0xe36ac1de, 0x97980779, 0x3c6c1de7, 0xf17000ef, 0x722d83bc, 0x943ac1de, - 0xf1ff2077, 0x67a49618, 0x547f5fb8, 0x7b06cfa9, 0x786334dd, 0xe76ab55e, - 0x17182dfe, 0xfc7209ab, 0x5e783955, 0x77b414d9, 0x457e300a, 0x04dfb066, - 0x114565fe, 0xb0d5f0c3, 0x13f3c3f9, 0xbde7d9dd, 0xb0a3fa02, 0x03bc2997, - 0x18ea29e5, 0xfe7c3f7f, 0x3b577161, 0x65d6e78f, 0x3bf08b7e, 0x78482cbb, - 0x8718e7c3, 0x13f253ad, 0xffad56b5, 0xb2e67f2a, 0x995f71f9, 0xf80899d4, - 0xbb6d4590, 0x8c2ff988, 0xd7f15ebb, 0x6ab7dc61, 0x15771b50, 0xb8d41b33, - 0x844bcf3c, 0xe1df39c1, 0x6b045f1c, 0x2a7f016a, 0xc1cfe601, 0x53ae15a4, - 0xa45e7c12, 0x881bddb7, 0x453bbcbe, 0xaa6814c7, 0x9e606404, 0x6a2012a5, - 0xc654d286, 0xf24cd2ac, 0xfe9d389b, 0xf1bdd4d7, 0x030f28d9, 0x6c04467a, - 0xf9a83c23, 0xbf580485, 0x2bfc8334, 0x332aeff2, 0x3a47bffd, 0xcc82eb50, - 0x5d8238f3, 0x2f80cd62, 0x5c266ef9, 0xceab9336, 0x45eb6f90, 0x73c335e6, - 0x9b37e941, 0x2d4e2905, 0x76f28933, 0x6541ccb5, 0x695774d1, 0xcea3f011, - 0x7ae175ec, 0x0966ecaa, 0xee3d85f9, 0xf148db3c, 0x32e97ae4, 0xf60049e0, - 0x48da62f8, 0x2ec88a76, 0x451cf8ab, 0x2f1f48bb, 0xadc92278, 0x61ebd88a, - 0x0a2a83b2, 0x2dc7c919, 0x7cfcb22c, 0xcfcb84ac, 0xdf5d4b37, 0xfbd73c44, - 0x878fd516, 0xd0be8f2e, 0x6d9b794a, 0x5bc2f161, 0x6f628afd, 0x90e72447, - 0xe901b93d, 0x8f04f17a, 0x1688e10d, 0xf62a78c7, 0x1b49ecf0, 0x767baec1, - 0xd45aec14, 0x2aecb743, 0xfa9399fb, 0xb1ca3b50, 0xd0ba4f0e, 0x9092baef, - 0xc3ddaa38, 0x8d67143c, 0x6979af1c, 0x9920e214, 0xfe13bfa8, 0xea639d0b, - 0x87fb023a, 0x54bcfbe5, 0x428ef8e1, 0x634be387, 0xa0d317cf, 0x613e27d4, - 0x771b8d0b, 0x970e0459, 0xf5c0d041, 0xfdff62b9, 0x78f624a0, 0x7d72812a, - 0xf22efca9, 0xf974d561, 0x7caa5867, 0xbae1df3b, 0x2d29fc40, 0xf9024faa, - 0x767f66bc, 0x0689ea01, 0x2ae35edb, 0x52d5f780, 0x3a22fdf9, 0x5b1ff46f, - 0x1eb16e1e, 0xf7bc478f, 0xa3cb22b9, 0xc50911bb, 0x28de4fe4, 0x67e4fee2, - 0xfe288784, 0x638bafe4, 0xea7b2fbe, 0xc9fc8673, 0x5b1ffe70, 0x639de3cc, - 0x068e0147, 0xf1465728, 0xc28ca6eb, 0xbf5a8dfc, 0x443ebf6e, 0x854110ce, - 0xdc6c69e6, 0xfc1163af, 0xba35973d, 0x147b37bf, 0xf310b1d6, 0xf591b571, - 0x31c57dda, 0x7e96aff7, 0x3307ca03, 0xd0a9fd5b, 0x6f30bcc4, 0xb2be50da, - 0x0fafd5c9, 0x383f738d, 0xe537e0e1, 0xb37e7008, 0xf272e638, 0xf91e9c7c, - 0xe119bd75, 0x7e066ae9, 0x255fb08d, 0x9bffdc25, 0x9611e13b, 0x3a637688, - 0xe411f743, 0x3637cf09, 0x83637e29, 0x2a767fa2, 0x2c53d472, 0xe52ce952, - 0xe851b9f5, 0xfbcad7fa, 0xb69c4a8d, 0x2bf26251, 0xec7ff491, 0x38fce6e9, - 0x71c6e728, 0xf30def38, 0xf453dfcf, 0xd3d89ec4, 0xa00c9ecf, 0x91b5b993, - 0xf63075f1, 0x0274b174, 0xf6d4bfcc, 0xf8901cf4, 0x0d9b2fb0, 0x2e9c5f94, - 0xef0c58bf, 0x57c28b6d, 0x69782b9f, 0xb03a3e86, 0x34a05bfb, 0x9010f942, - 0xfa405481, 0x6fec55ed, 0x14308e01, 0xf1de0420, 0x3af4e7e8, 0xce7c1ee4, - 0x7fe46d5c, 0xca1bc884, 0x3999569f, 0x83a774df, 0x0efe88ff, 0x9339d333, - 0x9fcf20ae, 0xfcf26576, 0x6a3c3868, 0x456ff4fe, 0x71cf198f, 0xc4166577, - 0xebddf285, 0x6f26989b, 0xe78575dc, 0x8a4fc185, 0xc949fad3, 0x8f8527e4, - 0x74b9909f, 0x247fa85e, 0x021fdcc8, 0x5c50267f, 0xa917e43c, 0x7c98cffe, - 0x7ff15cf9, 0xcd1dfd02, 0x4947119f, 0x07308b0f, 0x74ddff3e, 0x8f10dff9, - 0x1fd3d023, 0x9fd3d0a3, 0x347fdfb0, 0x11cc627a, 0xf0cc68b7, 0x1eb2bb71, - 0x708eb5b7, 0xd321203f, 0x54ce9119, 0x9b7a02fa, 0xe8763250, 0xb4f3217d, - 0x4b136f4a, 0xbd3ebf8a, 0xf0bec05d, 0xafe1acef, 0xd149d6ec, 0x7ab59dfb, - 0xfa0f28cc, 0xf19bd732, 0x99d4c49e, 0x6bce072e, 0x006c9911, 0x3e5cbb38, - 0x007b9e33, 0x64bf2f3b, 0xcdc1bc84, 0x7e3f2e22, 0xdcffecad, 0x2aff9c09, - 0x7dbe0b96, 0x6c4d7fc0, 0x4df70197, 0x4958ff7d, 0x7b88fdec, 0x35ee4872, - 0xf7208c96, 0xe2f8565e, 0x2b5f0573, 0xe729d6da, 0xfb445899, 0xfdec5567, - 0x942b348c, 0x45d75273, 0x745be3a4, 0x2285e787, 0xe21467ac, 0xe4c7e7e0, - 0xcd4c3ce0, 0xfc406d2b, 0xf1c4563e, 0x7dfecd17, 0xb3fc146a, 0x4ad70089, - 0xfd0199f6, 0xc7ff5969, 0x11e748ac, 0x39d9158e, 0x0390069c, 0x5995df80, - 0xfc31b7ba, 0xb5a495d9, 0x67f7d487, 0x67aefe2b, 0x5267e414, 0xf1c3ce0e, - 0x4c0e7e1a, 0x3ec5cf2d, 0x88b4b01e, 0x80ffb9fb, 0x73fc0efc, 0xe358a4a8, - 0x64a8fee7, 0xb5f73f64, 0x1adc8f7f, 0xcba8e850, 0x7d9ed911, 0x40fbf621, - 0xdd60e0e7, 0xb9157cef, 0xaa6f6e11, 0xdbd89ee5, 0x7a59697b, 0xd1c3879c, - 0x24e7b4c8, 0x28dff16e, 0x8f5d2de0, 0x77e968f3, 0x5ffae325, 0x1a58c385, - 0xe78c73f3, 0xff31e867, 0x7d79f9c3, 0x94be2ba9, 0x198f36ec, 0x07d837f5, - 0xb95f6714, 0xcd1f2539, 0x6b67d82a, 0x93be96a9, 0xefa6474a, 0x403bd2e4, - 0xfc9caadf, 0x534c6117, 0xa899bca8, 0xa5699bc8, 0x29afdfb1, 0x8e48af18, - 0x632baf2c, 0x73dbe71f, 0x79744e77, 0xfb379eac, 0x4f1b4147, 0x8f25bd6e, - 0x69474e63, 0x7921faa9, 0x7087eaac, 0x5e868d3c, 0x0bd10c48, 0xcce4510d, - 0x3631c068, 0x9db51f04, 0x98afe502, 0xc0a6f98d, 0x39d89daf, 0x96c7dee4, - 0x4f138851, 0xc87f8d0f, 0xa047af60, 0xb1a5dde3, 0xbca37fcf, 0xdb7c37e9, - 0x47f9d236, 0x28c5d5a3, 0x3173623f, 0xb19fec3b, 0xf6f295b3, 0x94ad05c6, - 0x029d6687, 0xf498fde5, 0xab79f92e, 0x30a7de6c, 0x9e5c367d, 0x5e398d6c, - 0x97d8728b, 0x28c537f6, 0xf8ebcd7e, 0x37f93a4a, 0x153ca3af, 0xb347ee24, - 0xf74ecc0d, 0xb97cafa4, 0x202f58fb, 0x9a2f3012, 0x763ee8c4, 0x7ac7e1a7, - 0x051b47cc, 0xe65cfe3e, 0x974ff9e7, 0xf0a3fc77, 0x31a0e59e, 0x7f543b7f, - 0xfb4d9a51, 0xcfe569de, 0xf39bf6bb, 0x9ea5849f, 0xc19e15b6, 0xa753e1f3, - 0xec1c5327, 0x6b8f03c5, 0xbc5aecec, 0xdf7e80c7, 0x7e861e0b, 0x35d329a2, - 0x9c3b2471, 0xae927f31, 0xa89a508c, 0xfa5e7a94, 0xf86d9d05, 0xf7f73bfb, - 0xbd67e848, 0x724cc078, 0x9e81ea7f, 0xe32155f8, 0x3e719627, 0xfe3d06b6, - 0x35af0019, 0x093273d3, 0xf92b1def, 0xce799173, 0x632bc2d4, 0x0f9d00a4, - 0x6b5791df, 0x2ebba50e, 0x794cd6a9, 0x639d5ce4, 0xfceb1d8a, 0xf4fc431c, - 0x4082fdda, 0x112edd7e, 0xe19aef50, 0xec7a86ba, 0xc3eb890d, 0x496b53a9, - 0xe72a75ab, 0x2de4761e, 0xc7ef8039, 0xf1a7af4f, 0x7b64593b, 0xe5c658cc, - 0x99068bf0, 0x80f17de6, 0x55c8e748, 0x7c69debc, 0x0f30cbd6, 0xa6dea3e0, - 0xa7d87ba7, 0xe5114e8d, 0x8134e9d0, 0xdf2d82ed, 0xee8578e9, 0x0288ec99, - 0xb94a2fef, 0xa96cca9f, 0xf7a77f44, 0x748f2e77, 0xbfa55f7e, 0xa96433c9, - 0x49c0ed0c, 0xff94269e, 0x36e4b6cc, 0xdf24f17c, 0xe68743bf, 0xcffc03cf, - 0x227fc17d, 0x6b21f70e, 0xf75c78cf, 0x6a76a507, 0x1f0f45bf, 0xb0f442bd, - 0xe3efc8c5, 0x8e717578, 0x858eb003, 0xcf1101d6, 0x8352184f, 0x2a6de794, - 0x8b74f2e3, 0x81630fca, 0x7d3de01f, 0xc507bf06, 0xcea9da26, 0x84270726, - 0x559ea3de, 0x0597aca6, 0xc2f9f132, 0xd83777f8, 0xf6158c1d, 0xb08b37a6, - 0xef8985fe, 0x7a86c86e, 0x5e78ef49, 0xb3f778cf, 0xb2b1896c, 0x9f5e0cde, - 0x9367eef6, 0x9bd15ea0, 0x3095ebc9, 0x9bb078d4, 0xbd9ab37a, 0xa4be3879, - 0x0f15bf19, 0xfd7f1472, 0x45d26f52, 0x28355f8c, 0x031f87eb, 0xfbece3ce, - 0xe2ef3a47, 0x78fd5b34, 0x86c9832e, 0x3419f8b0, 0x6077dc85, 0xff2409a9, - 0xf30bfbd4, 0xf63f7f45, 0x84fd99d7, 0x2759bbdf, 0xad8073d9, 0x7e145fdd, - 0x5c2e7b79, 0xc8d96dee, 0x8c4e785c, 0xef0966b1, 0xd64c0833, 0x78e3c17d, - 0x855f9c4e, 0x187f9d47, 0xc8b5b05c, 0x3d70439f, 0x70a8e34f, 0x7937cb5d, - 0x6b7ade51, 0x0427ae59, 0xe084d74f, 0x456c180f, 0x0f1dacda, 0x1b5d3ee1, - 0x40209c13, 0x1b7cb93d, 0xb1b5dbed, 0x8e081fc1, 0xef81ba90, 0x096f5b63, - 0x289763ed, 0x9b9d21b7, 0x216ed68c, 0xb8eeb191, 0xe60c1984, 0xe5d631d9, - 0x406e7bc5, 0xd8ef7477, 0x1c74659b, 0x8beb3800, 0xc7a1f9b4, 0x83fb3a15, - 0x98e60f22, 0x01ce7976, 0x047bba5d, 0xdc70f786, 0xa88c3783, 0x5df616ff, - 0xa4be6234, 0x11a2e7a3, 0xeb03bee9, 0xf3c74e30, 0x6ff988c6, 0xbd5eb963, - 0x91e74a2f, 0x4f1c4bd6, 0x7aeeb2a7, 0xe9e0152a, 0xbdd02d58, 0x9247f5bc, - 0x7d7d60e6, 0xb192ae2b, 0xe78755e5, 0x38b4b920, 0x72c29ffb, 0x95381b25, - 0xccb4240a, 0x10f667a5, 0x4d62b93d, 0xe887b33c, 0x8a4f16c9, 0x1772bea6, - 0x280cceec, 0xfa686637, 0xeafee531, 0x83f43632, 0x949a98e7, 0xdb665c7d, - 0xeeb8c019, 0x3bc19732, 0xc2de3210, 0x3262cdbe, 0x1c11edc2, 0xcbd28d74, - 0xe0ad3fcf, 0x1c52842b, 0xf7cf1f7a, 0xefc40af4, 0xba7a6d1d, 0xcbdcd3c7, - 0x35e6aeed, 0x202ecf82, 0x0dbdf81e, 0xed40af77, 0xeba7deee, 0x1bef1193, - 0x47000f00, 0x7d84f8da, 0x9347112c, 0x4ad5dce9, 0xdf775605, 0xb38e0339, - 0xdd023be2, 0x9bbf5567, 0xb2bfc2a0, 0x91ce91a9, 0xa45e7c01, 0x4d9d754f, - 0x5ce947f6, 0x9789cad5, 0x6187a80d, 0x3406977d, 0x5bd6d4f8, 0xcafada3c, - 0xd1fada8d, 0xf29ee532, 0xf90d3634, 0x209978e9, 0xb52439e2, 0xf9d651fe, - 0xe75ef1b7, 0x0a79d16e, 0xe8cdb3e9, 0x7efa819f, 0xbaa2e8b7, 0x3bcf0eda, - 0xf89df118, 0xb1f100e1, 0xc5b9fc40, 0xf8354b20, 0x8176973d, 0xb60576e8, - 0x0f67f3ab, 0xfd754fbd, 0x554dfaf0, 0x1b9c5aee, 0x4730bbe8, 0x90ed0905, - 0x9316517a, 0x222f88f3, 0xbdf9779e, 0xa36f07c2, 0xeeb803f6, 0x7d852242, - 0x44feebba, 0xbde6179f, 0x3a56cdeb, 0x215776e7, 0xf91d81d0, 0xd6e7475e, - 0x2f79e3e6, 0x7903ef28, 0x2ef28168, 0x9226a1fd, 0x128d33ef, 0x9ce577c9, - 0xe42f2a97, 0xb6e7b517, 0x219e67e6, 0xe7beeb3b, 0xb579d276, 0xc17239c9, - 0x2d0fa8d3, 0x471dfe7c, 0x1866df04, 0x34ef23a7, 0x3271cfc9, 0x61d72f3f, - 0x2f68e453, 0xfd7551c8, 0x50e3bfb0, 0x692261ae, 0x9bcd1e41, 0x5da9566e, - 0xf8283926, 0xffe8756b, 0xdde6538e, 0x75a76d5f, 0x487a3da7, 0x316775c0, - 0xe60166ef, 0x7c3a82bb, 0x55f950ec, 0xf8b5d7ed, 0x565de80b, 0x5b63b5af, - 0x65e3d745, 0x6dbb5f30, 0x2dcfc8c0, 0x1fa88d06, 0xdef8e0ee, 0xf2c3e348, - 0x50ee7475, 0x4730fbe2, 0x7680983f, 0x39a3face, 0xf608d8e3, 0xd3acde8d, - 0x148311c8, 0xf33791a7, 0x67f2b573, 0x772b43a1, 0xa39651be, 0x4f245f69, - 0xdfdfb4d3, 0x3fa9a858, 0xbcd4ace0, 0x9d5360ff, 0xcdb26ea6, 0xb16fbcd3, - 0xe3d4d62f, 0xde6b9773, 0xa558e31f, 0xf5bd3769, 0xed0126a3, 0xc077b371, - 0x06e87805, 0x1e4b28de, 0x12d323d2, 0xe32865e0, 0x2c562d0a, 0x744df3bb, - 0x3c7bb64e, 0xec4497e8, 0x773a1dff, 0xc97c4e69, 0xdfe5035c, 0xfc5abe0b, - 0xc9a00e7e, 0x3ddbf685, 0xf0e3684f, 0x5f38abc7, 0xb94365a9, 0x280ac1eb, - 0x67b05ef3, 0x81e97bf0, 0xcc7f707b, 0x45db8c71, 0x2ec999af, 0x5376899a, - 0xb071bf88, 0x397e66ba, 0xbe427bf6, 0xf582f917, 0xbc0a6932, 0x3b08cfb7, - 0x35ee7a8b, 0xebcbf523, 0xe685d01d, 0xce597ff7, 0xceb3c1e5, 0xfc717bda, - 0xb2d03e8e, 0x7dcf4fc8, 0xaebf4468, 0x013fafa3, 0xe70cd9f5, 0xcfb44687, - 0x7a2b9e87, 0x61c60c4e, 0x0e1fe39c, 0x63de23e9, 0xa46e5edd, 0x722b4ff1, - 0x7a3be5bd, 0xf78b4f3a, 0x864a6b37, 0xe1cb73e4, 0x63ef1fa0, 0x7bf3b4b7, - 0x368e789b, 0xf9069c92, 0xbca861fc, 0xf41d367d, 0x4f1a4cc1, 0x97960fa3, - 0x3edee9f9, 0xfbcd6fc8, 0x5c34972b, 0xc8257cc5, 0x4cf3ed71, 0xb1961e7e, - 0x73fa0301, 0xed35d720, 0xfb95cb1b, 0xde58d39c, 0x2e072017, 0xdbdf2338, - 0x9f8abb7d, 0xaae0b833, 0x16787da3, 0x47e789f0, 0x3f861d9f, 0xe1dbd78e, - 0x81a465ed, 0x661bfd90, 0xff7157ff, 0x7228e5ea, 0xbfb2a2fb, 0x014084fb, - 0x33b7550a, 0x8577e88e, 0xa5ed75b9, 0xcf97dc42, 0xdebfa2b7, 0xee8123f2, - 0xffb2ffc1, 0xac3b34ad, 0x54f878df, 0x7697de1a, 0x86953a1f, 0x0cdb89f7, - 0xcf68cdf6, 0x3dd07d03, 0x3f5e8ee4, 0xa87edfc1, 0xb79f1fb0, 0x140e0af7, - 0xeb9eeec9, 0x364eb40d, 0xa3fd15b0, 0x3ae0517d, 0xabedce58, 0x2a76e5c3, - 0x13982edd, 0xc98f7ef5, 0x1e9013e7, 0x5c213e40, 0x820fc047, 0xe66dbefa, - 0xd4f648a6, 0x27df0565, 0xde1919b7, 0xfe836dfb, 0x59d38eb8, 0xbdf88da7, - 0xb0c39685, 0x71d7012e, 0x1c7881ee, 0xa181837f, 0xf7c2a19d, 0x03e05671, - 0xabfbff5c, 0x2dcf0c0d, 0x27ad596f, 0x81bfbf7c, 0x87fa27db, 0x0335bd7f, - 0x2e80cbea, 0x270f3bf1, 0x9d38df56, 0xbfbee301, 0x7569db86, 0x2f881b0f, - 0x6e13ad97, 0xa50e4bdd, 0xff6e956b, 0x70d3a146, 0xdba70dfa, 0xe6baf461, - 0xdbebd1eb, 0x90ecb7e5, 0x61f7a819, 0x438ce7ff, 0x731efa3a, 0x1a7e401c, - 0x0718613c, 0x2ada4f70, 0x63c3c039, 0xa7bef5d3, 0x9c6e50d2, 0x6df9ede0, - 0x7f2e057b, 0x7d71cbec, 0x8646dd19, 0x2a2e08f7, 0xd95176fb, 0x0a0b3b37, - 0x62cfc8f1, 0xa9ca1260, 0xf9ce256c, 0x1d35818a, 0xe452ff46, 0x8ffa67f2, - 0x87b77b6d, 0x2b7fefd0, 0xcaab74e7, 0xe64669c5, 0xf7c56c3a, 0x045f8d0f, - 0xe06cbce3, 0x282735e7, 0x09c94de3, 0x52822c36, 0xe4e5c157, 0xd438156f, - 0x3e149ffa, 0x437f2760, 0xe6685cf8, 0xd1b79ff8, 0xf8eb8cdf, 0xbd75c999, - 0x305fde1c, 0xea1b7ce1, 0x3f49eebd, 0xb9dfe3c9, 0xee1d9073, 0xa27ff056, - 0x63cf37fc, 0x3532cfee, 0x72d7f68e, 0xe90969f4, 0x68a532d9, 0x30f148dc, - 0xe66ccdf7, 0xbaba014a, 0x5aa54399, 0xaafc745f, 0x82fc8071, 0x2fc40deb, - 0xb9e9d337, 0x0553efda, 0x8e46e9ee, 0x4a97d607, 0xb6e41b7a, 0x67921658, - 0xfaa0f150, 0xfb2996e3, 0x5b1ebf69, 0xcfee28c7, 0x8f84d3d8, 0x84e76d15, - 0x41e71856, 0x02b06c83, 0x3627cfbe, 0x8534bdad, 0x626c9fb1, 0x3a0b05cc, - 0x5cccc9bb, 0x6c7d0377, 0xd81ea892, 0xbbfaa364, 0x5e54ec9b, 0xa2c738b6, - 0xa4e079fe, 0xede20a67, 0x671ed644, 0xed73cc2d, 0x41f081ac, 0xfdf4063b, - 0x376b4298, 0x0cccf4fa, 0x947a37ed, 0xf028adef, 0x8333743f, 0xfcbe40b9, - 0x8e83e702, 0x467f1bed, 0xe6b1cf72, 0x49fa037a, 0xb7176df9, 0xf1bddd62, - 0x5f680d77, 0x04fa007c, 0x7eec0ce9, 0x9e501366, 0x81da339c, 0xa66f9a0e, - 0xeb2f38d0, 0x77c80d82, 0x430263de, 0xf7a0fcfa, 0xd71c71ba, 0xe12d7457, - 0xe6744df9, 0x48ad2d9f, 0xfbb8fc22, 0x7f7c75f2, 0xf7a1748b, 0xf9effa29, - 0x87ee0243, 0x9dfda379, 0x467fec4a, 0xb7af90cf, 0xa41306d7, 0x02f87208, - 0xa3978b8c, 0x86581d70, 0xbd1937b7, 0x413cf053, 0xe1c74293, 0xfa158bed, - 0x941b4c04, 0x213229ef, 0xc1239f8d, 0x5258169f, 0x41f93262, 0xe7e038fe, - 0xabbabe96, 0x811e9622, 0xcff5a87d, 0x762187d8, 0xfc3a347c, 0x437e25b2, - 0x4329c3e6, 0x4323f475, 0x1fa07fef, 0x82fbe919, 0xe3c9aca6, 0xb9778a46, - 0x83bec007, 0xc300eafd, 0xf4829ec9, 0x4fca8d3e, 0x91d9748e, 0xc171cc7f, - 0xd82fa83d, 0x3bf23a5d, 0x7b5abdda, 0x87e141a8, 0x7a1ec506, 0x3feb42b4, - 0x5ed49f81, 0x84a4fdc1, 0x3fe34ce3, 0xff273f85, 0x057c8cc9, 0xfd834ef3, - 0xfed22579, 0xc7aed554, 0x2ed8137e, 0x740673a2, 0xbe15f48e, 0xe0a8bfce, - 0xebe5547a, 0x48d7c865, 0xaf9cbdbf, 0xa96dc7c3, 0x1c0bf9aa, 0x7b945b77, - 0xf157f710, 0x139fdaf1, 0xe7ee5f08, 0x1f4f0852, 0xb59ce7b3, 0x031f9740, - 0x2e80fb1c, 0xf19d39af, 0x9affd049, 0x6c9f19cb, 0x1d03921d, 0xbf53c5cf, - 0xa717936d, 0x19fd42b4, 0xef187ba4, 0x8a3ade93, 0x1cf43e6f, 0xbe753fe7, - 0x52cbfc0f, 0x0d8a9f90, 0xda03a341, 0x262efb33, 0x7c581da0, 0xe414fee4, - 0x6e7068c3, 0xdce054ad, 0x4bdad8f8, 0xf01e9c29, 0x455aee1c, 0xf49fb9bf, - 0x6bff111b, 0xdfa23237, 0xd97ed7fe, 0x49fc7c81, 0xfa84bc5f, 0xf1a3e3f0, - 0xd7ff945e, 0x3a7c998e, 0x6f10fc81, 0x8fb5c822, 0x91f7030d, 0x2f4479bd, - 0x3ee8ffa1, 0xc83ddbf6, 0x4cd7ee8f, 0xb5b1f968, 0x51d75d7d, 0xddf5b5ef, - 0xf2c4557b, 0x87e5d1a5, 0xd38f8df6, 0x6ffad57a, 0x28ed9937, 0xb9113f47, - 0xfbdb589c, 0x6bbfd92a, 0xc0cc6f07, 0x47c7ea38, 0xca094fff, 0x379bf735, - 0xb99e504a, 0x8251b8df, 0xc71feeed, 0x2dd9227b, 0x84f4b371, 0x665f5557, - 0xe26a27bf, 0xfa141b45, 0xd5dceec8, 0x57f00938, 0x03896e7c, 0x7b6ab6f3, - 0x139d14f1, 0x79fe2fdf, 0x21c3ca7d, 0x22033afd, 0xce8a8de5, 0x0eafc7d5, - 0xaa47cba1, 0x94ef9a0c, 0x0f38d57d, 0x2df7e2b6, 0x0275c56f, 0xec0efa3a, - 0xbfc880b6, 0xf046bb2f, 0xf601bfa1, 0xb23f784b, 0x923daea7, 0x9910f742, - 0xbd3f9ce8, 0x1c53eb08, 0x5628eddb, 0x8726a7cc, 0x02cb4bd8, 0xe809bf3a, - 0xe4cfa9a8, 0x203f7b27, 0x62baa45e, 0xfd743d47, 0x85b26337, 0xdc9a7108, - 0x1ca0e777, 0xc0d78f0f, 0x5b8418cf, 0xa7ceafb5, 0xa651f8f3, 0x042dd247, - 0x993b9ab8, 0x161d7884, 0x4b9a69d7, 0xf8f0a2f1, 0xdbb03d8e, 0x93ecfd8c, - 0xabc21275, 0x8fb8a5da, 0xc0e4113d, 0x7972565f, 0x6757f2a6, 0x3af5e780, - 0xc9e6b503, 0x69577e50, 0xcc7491ef, 0xece9780b, 0xc600ffbb, 0x1f073a17, - 0xf30e9f8c, 0x98b7be74, 0x9ae79e61, 0x829e6b54, 0x9ae706fd, 0xa21bc81f, - 0x1af9f09b, 0x345db92a, 0xd6442f64, 0x5f0aa57f, 0x2c1e968f, 0xd0f3fcac, - 0x579fe083, 0x7cff7254, 0x709f8f05, 0x7f5c3cff, 0x1d5972a8, 0xef82ad77, - 0x2af972e1, 0x47e039d9, 0x5b5e5c93, 0x32f7a769, 0x90a516fb, 0x92defd7f, - 0xf875bb14, 0x43a239f8, 0x7c379c97, 0x739ed57c, 0x6653e57b, 0x3d647bf4, - 0x897ba7f1, 0x97fcc3e0, 0x9db9ff6a, 0xeee5d902, 0xdf0f8366, 0x2c0ae153, - 0x07d8f1e1, 0x22cf8364, 0xaa89d90c, 0xddab791d, 0x6abb5021, 0x63f6aa57, - 0xbbe3c9c0, 0xfb788a4b, 0x556b8b65, 0xa75c58e5, 0x97179e85, 0x398ce7f3, - 0xf55fa14f, 0x918152e0, 0x4aec501c, 0xedc34e95, 0x72fb4fce, 0x438a4712, - 0xa7d0af3d, 0xc21367ca, 0x63d543f8, 0x7e7054cf, 0x5e3d40eb, 0xf7fc7a88, - 0x7c3cfb1a, 0x8fe3d05c, 0x463f5257, 0x2e7e8bfd, 0xebf9233a, 0xadfc6566, - 0x4e05feea, 0x59bc20d6, 0xfd19b02c, 0xf5fa68cc, 0x139d8a7b, 0xc519fdad, - 0x3f1dbc7e, 0xc8e4561f, 0xcbf3f168, 0x70f2b795, 0xf9f9a9ff, 0x8c687d96, - 0xd557bf62, 0x1ffb86bc, 0x6a04f7a7, 0x97feff90, 0xe1eee281, 0xfaa53def, - 0xecd3229f, 0xa32ca9cf, 0xf723fd0e, 0xe83f1e1a, 0x43bfb24e, 0x7a5bcc7e, - 0x05ace386, 0xb8ed107f, 0x51266f47, 0x32f686d9, 0x385e2b94, 0x1588f947, - 0x77f0b46b, 0xfb174c63, 0xf3a6cbaf, 0x9eac2d03, 0x7d2d4ce2, 0x5016d249, - 0x0f63dd0a, 0xf2be469d, 0x0fdbd01e, 0x88ffbe84, 0xc799befa, 0xfba636e1, - 0x661af728, 0xc278b40f, 0x7dad7eed, 0x8dc4a950, 0x6f09d9a2, 0x5cb85bf4, - 0x3e27a339, 0xd378c0ef, 0x7d8cc64c, 0x37b82e5c, 0x474938f2, 0xfc04e6df, - 0xd2bb6a08, 0x500c457e, 0x6bf28a1c, 0xbed5eaf0, 0x3ee8d3a7, 0x27cdac97, - 0x39ffefb5, 0xbcf0cbc9, 0x970f7252, 0xbd36ee4b, 0xa12a4792, 0x83b797ef, - 0xed0e393f, 0x1bfdbb4b, 0x8b807788, 0xc8de48f9, 0x3ecbb89a, 0xe9f4af25, - 0x3f257f99, 0x2891c574, 0x79eea479, 0x7ca48f3c, 0x1e787727, 0x0ca9f4e9, - 0x48f3edfb, 0xe8e7bd1d, 0xf2edcb1e, 0x5baaa649, 0x3b8a1c71, 0x7c79144e, - 0x209f6277, 0x626abc61, 0xe9775f1f, 0xafb238b6, 0x3ab57e1b, 0xba81e505, - 0xe22c9f4f, 0xfde4fdf8, 0x5fb06acf, 0xc944afc9, 0xe37aeb02, 0xcb3f0dfd, - 0xd9bb75e0, 0xc436fd8e, 0xc9f33fa3, 0x23c7d6af, 0x1280df7e, 0x17c7e7f7, - 0xc9f1c8c4, 0x667578a1, 0x959dc515, 0xfa08b578, 0x5c50cc70, 0x8bdfbc27, - 0x746e5c55, 0x7142bb83, 0xef3c23cd, 0x9aee9ddf, 0x9ebff547, 0x29dff8c4, - 0xfd1e2990, 0xc635d02a, 0x62c1a68d, 0x3ffd2f31, 0xe62758e3, 0xbac7ba91, - 0xf47c427e, 0xf23b3ad7, 0xfca7f411, 0x9db0f793, 0x6a8623f4, 0x0333cf31, - 0xf7405b3f, 0xdf295231, 0x8fb28f73, 0xa2cfe0e9, 0x2cd0095f, 0x34f43cc1, - 0x2333df25, 0xfe38898e, 0xfb6b830e, 0xf52fcc54, 0xc4cd8e8b, 0x3c148e04, - 0x779e196f, 0x2f9e6412, 0x6a4ff357, 0xfe5a3cde, 0x9479c049, 0xf3f056ef, - 0xf980b296, 0xc4cf3574, 0xf9293a96, 0x43cca5b5, 0x807c42f7, 0xde73afb3, - 0xcffc846b, 0xf21115c3, 0x982beb3f, 0xf3699f62, 0x5f73db8d, 0xaafd3a21, - 0x78c3c679, 0xe68ee2ae, 0x0fdcecc5, 0x28bb830d, 0xf234d3e9, 0x6ff8febb, - 0xfb67a409, 0xbc3e906e, 0x00b13416, 0x78071fc5, 0x40cfbddc, 0xe06b8671, - 0xd10d8dbf, 0xf054efb3, 0xd5f78f71, 0x04f7fd11, 0xfdf1e3ea, 0xb7cf2bdf, - 0x7ee4b7bd, 0x01bdf7b4, 0xc60b1dfe, 0x13d63fb8, 0x6ed18b10, 0xf2fb83b9, - 0xf5846564, 0x7eb8e399, 0x52a3e70a, 0xab4aff85, 0xdeeb9e38, 0x7b987ee7, - 0x48afcf03, 0x7b705c8a, 0x74fd5e78, 0xc6a09a56, 0xca45c7d3, 0x92091cbf, - 0x447968de, 0x7cc9efa0, 0x33cbfcd9, 0xf1f391e9, 0x462f7a2b, 0x3634bfce, - 0x168cfc90, 0x638f0ecf, 0xff2a9dff, 0x7638f3a6, 0xeb44957a, 0xd7e4f64e, - 0xeb43638c, 0xb0fb83bf, 0x7d845674, 0x6fe383b8, 0xf1db1d9c, 0x3b63caeb, - 0x1e3113fe, 0xc78c7b7f, 0x6c7961ff, 0x8abaebf3, 0xdbffc2d8, 0x1fdfc318, - 0x57fffe09, 0xe78407cf, 0x0bcfc3ff, 0x30039f84, 0x17b0f5bd, 0x9d84badb, - 0xefc33f41, 0x24d6bf8d, 0x93141c80, 0xce7dd3f6, 0x1f3ce505, 0xecdeadb6, - 0x9d0c2bdb, 0xf5f1501b, 0x23f73568, 0x5eebbca5, 0x04d45efc, 0x829f5039, - 0xfe72b2f1, 0x59ae4377, 0x898c5e78, 0xc9e63a52, 0xc5f4cde0, 0x5b749760, - 0x5359e722, 0xe9a2f195, 0x35d58391, 0xe315678b, 0x7c8a3d1f, 0x4a87ff0e, - 0xe5ea521c, 0x6899e9f7, 0xf34c5f4f, 0x1ed1d3da, 0x9fc93c4a, 0xbc99f827, - 0x67b2e097, 0xdc7fe62f, 0x7be11b20, 0x26ffc946, 0x1b2bbbcf, 0x60c9d2e3, - 0xf05e6217, 0x920fcc69, 0x7bd12b3f, 0x66977cea, 0x19ea3f71, 0x9f301303, - 0xcfca9deb, 0xdf9eb139, 0xe6a6fd91, 0xfc1acef5, 0xca055a97, 0xfc23b5eb, - 0xf3f9d53f, 0x442b65f6, 0xebcdf80c, 0xf8df2891, 0xe5dff976, 0x9e1e68ba, - 0xe24c7be7, 0xbf409caf, 0xec78e019, 0xefd12168, 0xffe5e38a, 0xc7fe8cd4, - 0x3cf09164, 0xe254afcc, 0x78941705, 0x502f1a87, 0xacff5bf3, 0xc03e49c4, - 0x03940bf8, 0x72810f18, 0x9ddd2cfb, 0x67db4fd6, 0x67ffe045, 0xf21f1e04, - 0x87c794fe, 0x9c8e8d0a, 0x7f94f3d0, 0x63ef8b35, 0x2fe79fab, 0x0fcf78d4, - 0x7e14f595, 0xefc7ef4f, 0x9d6e15a1, 0x5f3d446e, 0x0e2b35b8, 0x4fb219cb, - 0x5ef80697, 0x4eb0fab6, 0x7448bfdd, 0xe75957b4, 0xca4133b6, 0x961abdef, - 0x8b34bff7, 0xa968679f, 0x097bfbe6, 0xd418a0ff, 0x6e229b1f, 0xb131f341, - 0xca47d24a, 0x5f80b52b, 0x76b6708c, 0x7c55b873, 0x75edf8b7, 0x53c5cf38, - 0x1658adc1, 0xa3aec9ac, 0xf5db7bb8, 0xb9bf68ad, 0xae9c6f07, 0xd19978a6, - 0x43c4fe8e, 0xdbb8da03, 0xfe3cd513, 0xe01a2afe, 0x457bb788, 0xef0b8ff2, - 0x927e8915, 0xbfe42c5b, 0xde981b26, 0xdc45f58a, 0x4c682a2e, 0x5b3ac3ad, - 0x60f64492, 0xd27b19c1, 0x714379c3, 0x377be4b0, 0xdd3c458c, 0xc6aacf2e, - 0xe45b2ed3, 0x5f9fb8e3, 0x7edacf35, 0x6f3a3df6, 0xc54baeaa, 0x8d2f9a8b, - 0xcf556796, 0x3f1bb83d, 0x70d39cd3, 0x8c06c18b, 0xbd1e163f, 0x5fce5468, - 0xa1ecb64a, 0x91e16c3c, 0x557f94eb, 0xcf6eadf3, 0xa1abb275, 0xf7fb119f, - 0xd7f9e26c, 0x2c0e00d7, 0xb2dd617b, 0xdba1ef09, 0x7583eca8, 0x9b63f3e3, - 0x6ff4a972, 0x7c795072, 0xf8951953, 0x64f4c999, 0xa75edbcc, 0x59d5edbc, - 0x524dcec3, 0xe8b76f5e, 0x15f108fc, 0x7aa3f792, 0x1f4fde78, 0xee35e3c7, - 0xbefa0633, 0x99acfba1, 0x5f4d77e4, 0x0ff444eb, 0x9ae73f3e, 0x60777088, - 0x2e842dde, 0x961d913e, 0x9d83f424, 0xdbe60b0e, 0x1aaffb0a, 0x874c3cf1, - 0x3c623018, 0xc0cf200c, 0x9eee8b23, 0x6fdcfceb, 0xf1058d5f, 0x58fcdb7b, - 0x8fcfffef, 0x58fc957d, 0x273f3577, 0x0291caad, 0x8bde4ea7, 0xf2d919e5, - 0xd89c8870, 0x94f9e4e6, 0x1127936d, 0x4e76ee1f, 0x321d5a4a, 0x8f23675e, - 0x3bdf245f, 0xfcfa12d9, 0x1f3cd597, 0x67302c96, 0x33567924, 0xc7ddebfb, - 0xd76e411b, 0x3ffbb244, 0xe5d029f9, 0x238ba04c, 0x90389edf, 0x343f19c7, - 0x71adb71e, 0x2831c4f5, 0xd8982e9f, 0xd3af1e14, 0x5858e3c4, 0x5c5a2e5e, - 0x4ea3456e, 0xa179d0b6, 0xdbd404e0, 0x2633f1e1, 0xbd702706, 0xbde0672e, - 0x83319814, 0xf961b195, 0xdf305fb9, 0xfbc327cf, 0xa4751acb, 0x5d3cd42f, - 0x36c8a341, 0x6c167d01, 0x3f28f834, 0xa45e28d7, 0xec6fc576, 0x90320a94, - 0x6b383fce, 0x16ae3094, 0x34731f1e, 0x049eefee, 0x026d1dfd, 0x5dba0bdd, - 0x073d4f1e, 0x3fdbd2de, 0xf96de307, 0x3d77576c, 0xac9fcff4, 0xf4fcf093, - 0x3f1e7cf0, 0xd8a05dff, 0x3671e139, 0x4bb433a4, 0x1bf0e3c2, 0x38d83a15, - 0xd7adeb9b, 0x1d537f14, 0x4e17ed47, 0xcd9d3f3f, 0xb8b46df5, 0xbc6551fe, - 0x6d82c6ce, 0x177f7193, 0x93ea18e8, 0xf35ac6ce, 0x76f190e4, 0xdbe7e6cc, - 0x60fcc19e, 0x907e686a, 0xf3c301e7, 0x2b9caa82, 0x037dffec, 0xc8377be2, - 0x6e63d46b, 0x141fcf1b, 0x8339ab1e, 0x4e086372, 0xc377b7ae, 0xbec8079e, - 0xbe312473, 0x457bfa2e, 0xc502a3de, 0x7c160ae7, 0xea1e3c76, 0xf74499cc, - 0x2767dcb0, 0x3ca2b16f, 0xe316205a, 0x53b71ebd, 0xc26795b8, 0xeffdd27c, - 0xbcefa1ac, 0x7f903e16, 0x81e5f70e, 0x0f9d0366, 0xfddef554, 0xf03534ef, - 0xc64fbdf6, 0xe0ae7b61, 0x79f1d8b0, 0x763f7d23, 0xfa7e4bfe, 0x110b58bb, - 0x81e7903a, 0xe44497b3, 0xd716cb9b, 0x151f23df, 0x4cf2522e, 0x3f4f5ccd, - 0xc0c8b7d0, 0xead3cec8, 0x9f5913cd, 0x46e83c53, 0x8fe5215f, 0x43fcf052, - 0x29be90de, 0x6c7a0a3c, 0x63d39dcc, 0x112d9d3f, 0x1e82673e, 0x17927843, - 0xf87d3cf1, 0xf650effe, 0x8a5e9a3f, 0xff518726, 0xde63fbf0, 0x5c36c10c, - 0xee31db8f, 0x3af68a53, 0xd3a2e394, 0x71661fdf, 0x628a4eba, 0xa149fdcf, - 0xa7e7a8df, 0xcf27477a, 0x7fd987f4, 0xd563791e, 0x4df352ff, 0xa0f6bfaa, - 0x65ab0f62, 0xbbfe5293, 0x72a037ef, 0x21bf788d, 0x86fdf239, 0x68090e87, - 0x1bf7a8a7, 0xcd59194e, 0x4f3c54e1, 0xf277dcab, 0xe93b222d, 0x62fcdfd4, - 0x78a98beb, 0x509049df, 0x3a1fb51d, 0x1dbe7a47, 0xa7b223ec, 0xe3cb7efa, - 0xf9f887ad, 0xc8def6f0, 0xaddbdddf, 0x32f5dfd8, 0xaed1b923, 0xe86db79c, - 0xb744f251, 0x8b8f96e2, 0xb74b71a1, 0x3d56303d, 0x7f23ebc7, 0x8cc71b4f, - 0x60ecb716, 0xdbb73a41, 0xa07046b1, 0x39ddb87e, 0x79ca5ddc, 0x4c71a8dd, - 0xb973e479, 0xb94c71e1, 0xb9c79b5a, 0xf7c4966f, 0x680825db, 0xce759aef, - 0x7fb73a36, 0x9d22904c, 0xcd5a5ef3, 0x257cf4e5, 0xc8d0720f, 0x8560e3e9, - 0xf06ff740, 0xfbee1e1e, 0x1efc63c1, 0x7e02c1ce, 0x7bcd470f, 0xa66bf7a8, - 0xe83de50e, 0x2f7a9dfe, 0xc367bd47, 0x5ae08f98, 0x7d1c5cf4, 0xe1876bc7, - 0xbddb8d90, 0x1a3f7e5e, 0x43e61065, 0x8913cc4d, 0x6bab6b5f, 0xef7a6ac4, - 0x8f4fdb8e, 0x7bf04754, 0xe91f8a7d, 0x2fea8eae, 0xfad6afac, 0xf70f540b, - 0xde54ee17, 0xecd98be3, 0x87fbfb4e, 0x9e8f1c63, 0xf1b63b32, 0xfb48ecc4, - 0xfda2c5b6, 0x5e5aaf1e, 0xb0dfe456, 0xbb0dc5ef, 0x7af5c92f, 0xa7ff60b7, - 0x1ba7ca4a, 0xcaae9f28, 0x7c31eed5, 0xe3291ffc, 0x294065a9, 0xd77ca3bb, - 0xbc4a97f9, 0x7b944bac, 0x2f69ee10, 0xd397e368, 0x97e3690f, 0x35937b33, - 0x78ff7cf5, 0x6785fbcd, 0x8bda6926, 0xda68f703, 0x68142f4b, 0x1503e5ea, - 0xaf2bf79a, 0xb3ea6ad4, 0x65f8da82, 0x61c5cdf5, 0xb47d38f7, 0xdca01abe, - 0xe6757ed0, 0xcbde6a6f, 0x575da358, 0xaebb4796, 0xebb51b89, 0xf6cdc752, - 0xd397d76a, 0x325f5dad, 0xbef2e3e6, 0x7f2e3e7e, 0xc7c95db6, 0xdfb058e5, - 0x2d938d33, 0xf7a9b768, 0xfef7d5a9, 0x5866372f, 0x007f40df, 0x00000000 -}; - -static const u32 csem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0xe4b3ff00, 0x51f86066, 0xb97bc10f, 0x726e1818, - 0x0143f821, 0xd08667cf, 0x0c0c2c6a, 0xc6cc401a, 0xcec0c0c4, 0x717ebc44, - 0x1d7b044e, 0x4cc30307, 0x31c8de20, 0x481afef0, 0x7e879d7c, 0x42f3a976, - 0x81c15968, 0x570837f7, 0xb430310a, 0xc430330a, 0x0cf84088, 0x55f2a8a2, - 0xa9b60842, 0x39766524, 0x0003f502, 0x3471cc24, 0x00000380 -}; - -static const u32 csem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd554780b, 0x733ef0b5, 0x7993331e, - 0x0f20f264, 0x0084f102, 0x021842a2, 0x27088784, 0x01a8c421, 0x54bc8083, - 0x48433c26, 0xbfa81132, 0x2677bd6d, 0xb5ad1104, 0xbc1b6951, 0x14101de8, - 0xd1a07515, 0x40e81c06, 0xdbdab114, 0xd5a8f8a8, 0x40445076, 0x8bcbc248, - 0xaf7fd52d, 0xe649cfb5, 0xd4484c9c, 0xffffbff6, 0xdbf3f1fd, 0xd9cfb3ec, - 0xdaf5ed7b, 0xf6bdad6b, 0x9a32c11e, 0xe4224e24, 0x65a3f85b, 0xf4842784, - 0x0adb2ce9, 0x64918fda, 0x8b2ffc42, 0x108e36f2, 0xf08e77ee, 0xbc8451a4, - 0x980b99b5, 0xcfbc3d69, 0x9fad0846, 0x603d34de, 0xff6422ce, 0xef02b308, - 0x8f9ade9f, 0xbd2fc9f5, 0x7b6814e7, 0x00bc4bd5, 0x13bed375, 0x109d88ce, - 0xa1e5b9af, 0xf6f3e96b, 0x85b27897, 0x93fc450e, 0x9085244d, 0xfec21663, - 0x52fab22e, 0x6d56ab2b, 0xf4077fde, 0x2664de5b, 0xd54fda56, 0xaed365ee, - 0x8765f5a5, 0x54af0244, 0xfa95ab6d, 0x00f2fad2, 0x9afa8417, 0x71c67f7d, - 0x79480ada, 0x27212870, 0x5f22167d, 0x96ceeb49, 0x79f45994, 0x11676045, - 0x83b15fbc, 0xfbe89b73, 0x7ff69b15, 0x3457fd0c, 0xda79038a, 0x36ed8aff, - 0x63610f22, 0x1e604b7f, 0xbc01a64b, 0xc4886f55, 0x97e5eb4c, 0x70044956, - 0xa54bd424, 0x61ff180e, 0x38c07649, 0x0d1c7087, 0xd0cf559f, 0xd577e871, - 0x986e702f, 0x7889b55a, 0xddd69e00, 0xda4f39d6, 0xd2b55e61, 0xf77ef860, - 0xb7bc127d, 0xb2f6502c, 0x36f80655, 0xe700454b, 0xd2d2cda6, 0xadfd9da1, - 0x0ea6fed8, 0xd90d63ae, 0x76a89ea9, 0x47d27963, 0xacee6c88, 0x04a21057, - 0x407700ed, 0xf3ac3e9a, 0x812e79f9, 0x3fd0d190, 0x674b644f, 0xc83094ff, - 0xe8f7fe07, 0xf60f813f, 0xb2db023a, 0xd2b5e93a, 0x772dff45, 0x4bacebd2, - 0x9ed09fa5, 0x56bfdd17, 0xa074043e, 0x5cfbd4f0, 0x4be23e58, 0x4f8372c3, - 0xcafdbc46, 0x06cb0437, 0x3f9f1b9f, 0xe58b1be6, 0xe5829f26, 0x2c62be13, - 0x7c52be03, 0x0e6f8b6f, 0x1e7d5b96, 0xaf94fe7c, 0xbeedcb1c, 0xacfe7c1a, - 0x772c6eef, 0xfcf8fcf8, 0x2c7adf05, 0x2c7abe83, 0xb01af977, 0xf005f46c, - 0xdb7d97bd, 0x05f26cb1, 0x5f1ef9f1, 0x5f219613, 0x407dcb18, 0x7d865a5f, - 0xf01e582d, 0xabe5887d, 0x777e08be, 0xcb1c77d0, 0x3bbc5507, 0x817c9027, - 0x10a9cde2, 0x92171517, 0x8be4a258, 0xca589eb4, 0xf9b729ea, 0x4f5a25f3, - 0xc53ad0f1, 0x70cadf63, 0xfbd699be, 0xccf6b0d6, 0x8581487b, 0xacfd33d6, - 0x4a83c07d, 0x07d69581, 0xc1f6b3d4, 0x7105fc9b, 0xc0383eb4, 0x11deafda, - 0xfad1b02e, 0x9ed641d5, 0xed932213, 0x66139eb4, 0x94b7dcf5, 0xcf5a0ec9, - 0xbcf5616d, 0x9d93fd8f, 0x61179eb4, 0x153f8fdf, 0xeb4f1c9e, 0xfb59dbe3, - 0xd0a44bc4, 0x0913eb45, 0x7b02f587, 0xad02617e, 0xbd58b817, 0x20995fa8, - 0x7dbfe0c7, 0xa1116462, 0x7fddb0bc, 0xd3a422b3, 0x455914ba, 0xfe9f14dc, - 0x8b0f5839, 0xbfb43164, 0x84532fe5, 0x912eb471, 0x17fed0d5, 0x1fb6057f, - 0x6f6c6510, 0xf6c2aff7, 0xed8c9203, 0xb07bdaa6, 0x60a8aafe, 0xbded727b, - 0x92abfef8, 0x6b83ed82, 0x41fac21f, 0x63ed83d1, 0xef8d7f6b, 0xd83c941f, - 0x80dac8fe, 0xffeb4852, 0x00b679c1, 0x9e71d75f, 0xfc0d9272, 0xa52b4c1a, - 0x238ebafc, 0x1e3e4073, 0xf2a6a600, 0x525d2eb0, 0xfbedbf40, 0x3c93de47, - 0x3276f2a7, 0xf53e97d4, 0xf3f61640, 0xd223f61c, 0xfb9ef87e, 0x58cdf899, - 0xbf133f5d, 0x69fad729, 0xaceaf784, 0xdf67ebbd, 0xf0f5e337, 0xf5a1537c, - 0x71fb17b3, 0x135e6ef4, 0x87a09dbf, 0xad4adbe7, 0x4fd8839f, 0x09e0ef42, - 0xfd74638b, 0x5a65c584, 0x7ec47f3f, 0x1e0ef4fa, 0xeba71a45, 0x6b969147, - 0xfd887cfd, 0x9faef7a4, 0x1ead74b0, 0xd685691e, 0xa7ec11cf, 0xa5e6ef7f, - 0xc3d3af98, 0xfad2ae63, 0xcf748939, 0x073f5dea, 0x1cfc7a1c, 0xe7e07470, - 0xa833c21c, 0x702af377, 0xe053f1ea, 0x25cfc0ec, 0xdeaae7ec, 0xa9c073f5, - 0x6701cfc7, 0x0e447e07, 0x77ac35e6, 0xd7882af3, 0xbe20a7e3, 0x0e4e3f03, - 0x3bd119e0, 0xa3ed5e78, 0x7dabcfc7, 0x8a93f03a, 0x1dee8cf0, 0x7a29853c, - 0x74a614fc, 0x784647e0, 0x9faef5c6, 0xf8f45357, 0x03a53579, 0x3f61573f, - 0x5e6ef5d7, 0xfc7aa985, 0xe076a614, 0xc9fb1727, 0x78476cf7, 0xd1c7ed08, - 0xfb073f7d, 0xb073f1eb, 0xae7e077f, 0xd0a67ec5, 0xee7bb27e, 0x8f5328a7, - 0x0ecca29f, 0x9e2214fc, 0x3f5de86f, 0xf8f53307, 0x81d99839, 0xcfd8a99f, - 0xabcdded4, 0x7e3d0ae8, 0xf860ae8a, 0xc08c2499, 0x9dae8675, 0x727e9e6e, - 0x857cbf7d, 0x2ef3efa3, 0x6e5de756, 0xaf0f7602, 0x45a433d9, 0xf6fbe9e1, - 0x0fb9091d, 0xa6bb6890, 0x8fc076e0, 0xd1795a83, 0xd8fc4d76, 0x951d9d38, - 0xeaea24a0, 0x757dc549, 0x1d29f7ef, 0x9d4f6ba0, 0x3daeb573, 0xabab93dd, - 0xd78f9467, 0xa6bfdfbd, 0xe2bf5740, 0xef751bee, 0xd16ff967, 0xcfd7b3d5, - 0xa83fbdd3, 0xfdaea17e, 0x5d0a86ca, 0x958155fb, 0xdb35faba, 0x7f7ba27f, - 0xae8d7058, 0x03d3787d, 0xe111f6ba, 0x91f57447, 0xbdd31e87, 0x8b65ba3f, - 0x87cc7dae, 0xc7daeacf, 0xeae97645, 0xa3df1ed7, 0xf6baff7b, 0xa4faba03, - 0xbdd7bf8b, 0xd5de4f9f, 0x3f96dbdb, 0xe29fdeeb, 0x7ed74cfa, 0x0697da7d, - 0x3aeed53b, 0xe75a8d76, 0xfa08ae41, 0x0974fe25, 0x43b0d5ed, 0xd7d4bac2, - 0xc714fcce, 0xe528f952, 0x22c0e91f, 0x92f91939, 0x21bb51fe, 0x95f96fbf, - 0xaefcfa11, 0x5d2b9ef1, 0x925df9f4, 0x862bb867, 0x8df9437d, 0xca506923, - 0xed8d2826, 0xdf8c89f7, 0x0d2e320b, 0xf7bf423e, 0x2707da9a, 0x3e70fad0, - 0xf1f2083f, 0xbb426732, 0x35278e3a, 0x999c5ef0, 0x5f74dfa0, 0xfe93de56, - 0xdf587928, 0x5c19da9f, 0x45ebbf67, 0x51da1a4f, 0xc1f89fb5, 0x9fd759ce, - 0x212fabce, 0x849f70af, 0xf7e903fd, 0x79a697fd, 0x89667f68, 0xe3d119fa, - 0xa1fc744b, 0xe4187e38, 0x3f8c20e1, 0xe6f8ebba, 0xe3756301, 0x75cb325b, - 0x3a245be3, 0xdf908bbe, 0x8eae7ed7, 0x9e30894f, 0xcfb93790, 0x66737c71, - 0x9f7f8e39, 0xe8aefd44, 0xc63ae3f1, 0xbff9816f, 0x07fcdddf, 0x3fcfd78c, - 0x7f3f42b3, 0xa3ffcd89, 0xf8ead3da, 0x3fff3871, 0xfcd9a773, 0xfcd82b33, - 0x8edfaccd, 0xf81d9df1, 0xc7f8c08f, 0x9cdf19ba, 0xff3f413d, 0xf3f52a2b, - 0x4ff1b337, 0xc7505ed6, 0x5ff8e3b7, 0xfcd81772, 0xf1c4a8af, 0x0dc7b325, - 0xc46523fc, 0xf8e804d5, 0x7c551fa4, 0x742ec0a9, 0x2487281c, 0x6421a152, - 0xe100371b, 0xf18e2bb8, 0x947157db, 0xf99f50df, 0x500939f1, 0xfd4799cd, - 0x57d79546, 0x4097c8ec, 0xf53b61ef, 0xa0a896b7, 0x91e26e2e, 0x7306c9bf, - 0xb7851060, 0x43f789b5, 0xeb86f17d, 0xbd5fa002, 0x14a0b266, 0x184813be, - 0xcbfe7f9e, 0xe7a25b61, 0xd4972c65, 0x5122c78b, 0x07e1d6f2, 0x35219016, - 0xc029be14, 0xeb3ba304, 0x0e3f529f, 0xa98fe31c, 0xffa843df, 0xc6c899f3, - 0xf7f50bfb, 0xfea11ea0, 0xa4ce3a1e, 0xdda3bf16, 0xf0a34e1d, 0x7ff0aa97, - 0xfd79302a, 0xe02e36f4, 0xd5f9f2a7, 0x7fa0478f, 0x1b6ee0bd, 0x1c277a45, - 0x5d24fe65, 0x0fcbce9d, 0x6ddf6a74, 0x10e16c0e, 0x6be032bf, 0x21268a3a, - 0x5067d68b, 0xffbe775c, 0x07a9bec1, 0xb7212739, 0xa54c4512, 0x9abedfef, - 0xe3a2efeb, 0xb9cc52ce, 0x32521d6c, 0x24d7284c, 0x909634c3, 0x88471a5b, - 0x5d3207b4, 0x448d3f11, 0x58a33b8d, 0xaa559f5f, 0x8a8ab7af, 0xb570a268, - 0x66c8e74e, 0x39ecefda, 0x9c6d76fa, 0x4644a681, 0x52bc7567, 0xfa74938a, - 0xb9943668, 0x7485d8f0, 0xdf62e39e, 0x1778f06a, 0x7e8c2489, 0x010fbfbc, - 0xf193faba, 0x362e79bd, 0x73bc236f, 0x4a528b44, 0x8ca739e7, 0x1b7f000f, - 0x9f68ffe1, 0xd0e5314d, 0x22a3fd72, 0x8f9d7531, 0x1eb9fe11, 0x22827ce3, - 0xcbf3f3ac, 0xdf19cf8d, 0xffe9531c, 0x2d07f029, 0xa0fe00bf, 0xf9551ff0, - 0x32af53a3, 0x3d9af0fe, 0xda1f80d3, 0xe904f237, 0xadcbf2aa, 0xa92cbf2a, - 0x2105f3d7, 0xb8e8111e, 0xfb970e6c, 0xcc1f1440, 0x5960f956, 0x6e6f9e83, - 0x3d317e27, 0x6ee65d06, 0x9a6f7cd8, 0x9f7e75dc, 0xff337ca8, 0x9f88fdc1, - 0x7464f3ae, 0xd3a543ba, 0xf6fa35ed, 0xdeba555b, 0x4e75d2ae, 0x51afc3c3, - 0xc9e641f5, 0xdde41101, 0x9e8d53fb, 0x3d3d1d11, 0x708d3d2a, 0xf3d2a1de, - 0x7a331f8e, 0xa88de11a, 0x9c348cf4, 0xae80c913, 0x5be11af0, 0xf9977770, - 0xccab5c60, 0xde9e9b1f, 0x4755fca6, 0x05579ea3, 0x3475586f, 0x6c56ce4a, - 0x2fabae9f, 0xbdd5cc0f, 0x4ca1acbf, 0x7ea4bed7, 0xd17daeb9, 0xf5753bfa, - 0x758fff32, 0xbbb82fef, 0x7b7ed756, 0xf6bafdcd, 0xeb0fe5f9, 0x1b3d73ea, - 0x9ecfef75, 0x3ed759b3, 0x5d19f4ab, 0x9de28cfb, 0x6574faba, 0xd37deeb7, - 0x066eabbe, 0x3deb7cfe, 0x713d809e, 0xc605fdc1, 0x45b82f33, 0xd473bc37, - 0x1f5f2327, 0xf2c10df3, 0x7c8dcfb8, 0x1637d27f, 0x66a6d6cb, 0x7413ac3b, - 0x124a5c5d, 0xcd326908, 0x0fdf5dab, 0xeb8269d6, 0xa9e4c869, 0xb37ad3f5, - 0x28794649, 0x78489069, 0x2c1c2124, 0xed1c2a36, 0xa47b547c, 0xaa06f687, - 0xb6ba93f8, 0x3f624497, 0x76523ef7, 0x7765f005, 0xcbfd03eb, 0x4da7bb00, - 0xed8debb5, 0x8d291c95, 0x1ac84e7e, 0x626ac384, 0xc4a54776, 0x5772bfe4, - 0x4271017a, 0xe6b83c3d, 0x2905e372, 0x9f02a793, 0x78e4eb64, 0x3a35c359, - 0x9a204efd, 0x6df807dc, 0x8af9eea4, 0xbeead7ed, 0x479fb53b, 0x5741abb8, - 0xb165838c, 0xe81333f4, 0xe67370e1, 0xa700618c, 0x4deb1472, 0x3c2ed07d, - 0x755e2be5, 0xafd01074, 0xbee3cb14, 0xf31e5839, 0xea3cb079, 0x53f2c72b, - 0x11960d5f, 0xfe58dddf, 0xf2c7e7c5, 0x2c7adf63, 0x63d5f23f, 0x01afa1f9, - 0x017df7cb, 0xb6fb0f2c, 0x2f8ef963, 0xaf8b6588, 0x9f56cb09, 0x7726a582, - 0x71ddf13d, 0x093e1d75, 0xcf8317fc, 0xed7f3aa4, 0x7c9d09fa, 0x87dfc716, - 0xb9e1a67c, 0xf2acc1a4, 0x1f8e8a43, 0x4397c012, 0xbda1eb3e, 0xb0f95441, - 0xb763efbb, 0x6bfcb77b, 0x0fea6df8, 0x7e4eb7e4, 0x53f030ca, 0x34fc4f76, - 0xa7e28f8c, 0xb31726a9, 0xfa7e547b, 0x8623cc19, 0x8c0f315f, 0xf6513e90, - 0x826f929a, 0xbaa56c75, 0x601f420f, 0x763aacfd, 0x05b77d1d, 0x10c0baed, - 0x0ece3758, 0xd860dbf9, 0x21fb3847, 0xf7567e25, 0x49f233f3, 0xd05778f7, - 0xa01a59bf, 0xdaea4f44, 0x78638d6e, 0x31489ab5, 0xfddaeba1, 0x2f729e83, - 0x81758a1c, 0x01f7c224, 0x8c4774f7, 0x0cada97e, 0xaf09edf8, 0x72af8e75, - 0x8f63bfa0, 0xca0f3dfd, 0x2f6626a9, 0x68f335c7, 0x93f093b7, 0xc76fc06e, - 0xa77664ba, 0x7dbdbc41, 0xbb42e490, 0xe3d64c81, 0xc3a05fcf, 0x4714fddf, - 0xd6eeb82d, 0x06fe21a7, 0xbd38357e, 0x49ebf817, 0xcf84f7bf, 0x7fef3085, - 0xd27b3e01, 0x45e93d8f, 0x342fc8a2, 0xedb7f9d1, 0x80fb961b, 0x1e5ee30c, - 0x9afedadf, 0x7e5f9e11, 0x4b6e3e47, 0x25b8f8d1, 0xa41f8093, 0xc6d9cbca, - 0x2e81e32b, 0x40f4fd1d, 0x9f77ee4f, 0x7eff8264, 0xdfdf4b3a, 0xe2fec67d, - 0xa70dc225, 0x89243ae3, 0x92bf53c4, 0xd1e36cf7, 0xfc47719f, 0x67d83710, - 0xe0c9d773, 0xaffc9e37, 0xeb3d0cb0, 0x0f670be3, 0x3f04e93d, 0x5f1a656c, - 0x1d063473, 0x982ab2b5, 0xf68f6355, 0xf5f49a57, 0x715cf5b3, 0xc725e710, - 0xeb061ccf, 0xa8e6ab8c, 0x0d3f7a08, 0x959fad4b, 0x738e1269, 0x3c767b72, - 0x4c02fff3, 0x4048ec9f, 0x67d2737d, 0xd9fff7c1, 0x8fd774f0, 0x8d210f06, - 0xe80b33e4, 0xdd96da73, 0xcaddfbfd, 0x825e7083, 0x890929f8, 0x69bf815f, - 0x3b7fffa5, 0xb015fa00, 0x0debf5ae, 0x70f37ef2, 0x3743be78, 0xd64efd1e, - 0xbbe18cf6, 0x204ee5ee, 0xa7be34c7, 0xbaabfbf4, 0xbb62bdbf, 0xc76f46b5, - 0xdeeae826, 0x9d1af4a6, 0x00ff0b5d, 0x1386bdc3, 0x54ab0960, 0xb04db0d9, - 0xda7e07af, 0xf049c103, 0x5ef6385f, 0x79222595, 0x16971464, 0x6385d3e0, - 0x6797fe35, 0xa9ea99ff, 0x048a6f13, 0xa25c8ce4, 0xaea9e550, 0x899bf220, - 0x917d6898, 0xc6c2f6fa, 0x6eb02515, 0x26f9789d, 0x931643f4, 0xc7f82752, - 0x0f3ea4e5, 0x89a7b5e2, 0xf3e418a9, 0x39c77934, 0xad1e4a32, 0x2e9d8482, - 0xe3b7af5a, 0xabaf7fa9, 0xd7d06b2f, 0x525b9297, 0xe97edf60, 0x38049106, - 0xf6fa1bd0, 0xf61779af, 0xacd48cbb, 0x57fb7583, 0xa16bbc6a, 0x5419088b, - 0xf6fd556f, 0x0a32bcf1, 0x71604b87, 0x7a1f6d16, 0x7ff32279, 0x2406662a, - 0x59ffbe85, 0xa95bc8e3, 0x07dfa206, 0xbc7ec1d6, 0x6f713a7f, 0xf7e95d23, - 0xc237e15d, 0x5d03d9ab, 0x3855c3f6, 0x4a73b792, 0xcb1e8620, 0x67263814, - 0x102bbeaa, 0xc7b8ba5c, 0x7bfd4334, 0xd13253f3, 0xde1ed3f1, 0x668c2793, - 0xc0fc03fc, 0xe792ed09, 0xd69ff487, 0x7f82ffa5, 0x68fdff6a, 0xfeba79ff, - 0xfb53fda7, 0xfe05d81f, 0xaffab179, 0x2ff3edfa, 0xa93ea9fb, 0x4e97f178, - 0x13c9d742, 0x9b8a7d42, 0xdb72b5d2, 0x96854ebd, 0x13bf05c7, 0x8044f5f8, - 0xef458e2f, 0x154e0587, 0x41cec542, 0x49fe0ddc, 0xecf93ffb, 0xf11e30cf, - 0x85d136d5, 0xe6edb4f1, 0x61ca99b0, 0x12f2e375, 0x23f58392, 0x19df7eac, - 0x7a4dea1e, 0xfa78abfe, 0x1f902997, 0x8d453942, 0x9ed1852f, 0x79fadead, - 0x5e4fac11, 0x64728ed2, 0xbfc60efc, 0xaffa8898, 0xdaef8a4c, 0x38c4e14e, - 0x8bc55781, 0x6767f1b7, 0x37942778, 0x82fa017c, 0xc7e8227a, 0x572bbf1b, - 0x8235d4ed, 0x8d98f923, 0x190c7bfe, 0xc3517a03, 0x3b30090b, 0x5f99eeb5, - 0x70a11ce7, 0xa6fada9d, 0x97c28b93, 0x83674f26, 0x8f73fe8b, 0x6ddebddc, - 0x6d16f2a5, 0x96eb690f, 0xd7daa4dc, 0x8a565621, 0xf3e42761, 0xdd166e54, - 0xf2b8fa7e, 0x7a9f27f9, 0x7f99e20c, 0xd107bb32, 0xff3c57fe, 0x69e3fbda, - 0x314ec57d, 0xc34d84b9, 0xd274a5ce, 0xbfff4bc7, 0x1e93b73b, 0x4d79bf15, - 0xe7b18792, 0xd27624f7, 0xfdcec565, 0x15d61912, 0xfb83931f, 0x063d88a5, - 0x8a47827d, 0x7ba85ec0, 0x8825bfe6, 0xc7d89e33, 0x18acd491, 0x1afcdcf8, - 0x278003da, 0xaf4aa7a4, 0xde19fa0e, 0x80ba52f7, 0xcbd236de, 0x5522def8, - 0x90bf40bf, 0xfbf94167, 0x07903d85, 0x0dd991f5, 0x617f2878, 0xf3e61395, - 0xf8c35085, 0x537bf1fc, 0x8b959f40, 0x961714fe, 0x13f979ec, 0x5bfe423f, - 0x528ff6f6, 0x9444be30, 0x45ae1374, 0xe79874fe, 0x70b34d92, 0x07894b9e, - 0x71fcb0f9, 0xcb4034be, 0xde29020b, 0xac4e4319, 0x2f939322, 0xd2e250b6, - 0xfe017e79, 0x77efe824, 0xb436c0f8, 0xa024efbb, 0xcea47e0f, 0x580c5a85, - 0xf46160bf, 0x2ebaabfa, 0xa33eb010, 0x7deb77f9, 0x93a7402d, 0xd85495fd, - 0xc112f177, 0xfb83e2af, 0xbfcbf696, 0xd195253d, 0x9e42c889, 0xf75d1dfa, - 0x7873c327, 0xac5445bf, 0xc8efba39, 0xe39d59b7, 0xa7c756af, 0x7ac1c770, - 0x6c4a45fd, 0xd44f35fb, 0xb75d00f4, 0x4a2cf8a3, 0x6ffc99de, 0xbbc99fbd, - 0xe981ff26, 0xfe7ed0c5, 0xf8239330, 0x0a43d60e, 0xdb153857, 0x50e4cff7, - 0x3a3f503f, 0x156f9c96, 0xb7d73955, 0xc285f91b, 0x51f1702f, 0x24e3037c, - 0xdf701d22, 0xfa06e965, 0xf51e947d, 0xaeceb8c2, 0xbc726afd, 0x455bf34c, - 0x9b203ebd, 0xdee81e98, 0x9e23f2ae, 0x53c0c52a, 0x52fc818f, 0x20cbf579, - 0xcc2962bf, 0xcd1dcbff, 0x72a3cfef, 0x935065fb, 0x355ebd5b, 0xaef96dca, - 0xdc9624d1, 0x9377697e, 0x9f4b7298, 0x7b5b94c7, 0xfff9f904, 0xf0d55eb4, - 0x78f00c38, 0x351e274d, 0x3e1dd93d, 0x90f27a8d, 0x8d5e2320, 0x1dfe927a, - 0xf95d7926, 0x8d43e351, 0xab9e2aff, 0x51f402ba, 0x7c6a9f07, 0x1aa7c1d8, - 0xef89761f, 0x6c68f0ea, 0x34fb00bf, 0x96f9ae14, 0x528ed38d, 0x4ed2d257, - 0x7f26df70, 0xaafb8f26, 0xe584f396, 0xf3111081, 0xd5303f43, 0x753b068c, - 0x3d6fdfe2, 0x7785177d, 0x2c8bf13e, 0x445ea02f, 0xb7d2ffbb, 0xf3a04edf, - 0x79e2a799, 0x54fb453e, 0x0239974a, 0x70a38e17, 0x3f8815ce, 0xb7e2113e, - 0x0a34f91c, 0xfae5f98e, 0x4c4dfc3a, 0xa7a7ece9, 0x9fabbff7, 0xb7cb7df2, - 0x1d3f5d29, 0x50bbc844, 0x10bc388a, 0x81d357cd, 0xde7f14ae, 0x00605c51, - 0x5088a9ea, 0xbd77e51a, 0xf3fb3220, 0xa319c2ed, 0x9fc9bec1, 0xf19e2c3d, - 0x7bf460fb, 0x3b3eaabd, 0x41e397eb, 0x650d9fcf, 0xf67b7fa3, 0xac4722d0, - 0x9566d0bc, 0xf7535ecf, 0x5cecda5d, 0xbff94f3d, 0x7da3b48d, 0xc95bb7e3, - 0x82fb18b6, 0x5f4d451b, 0x7fa374ab, 0x8e7f1d3c, 0xe97387ca, 0x51b9f1a7, - 0xf5399b74, 0x4aece084, 0x34fbf807, 0xa1fb0fca, 0x06be05f8, 0x235b36fc, - 0xe231a545, 0xf8a9cf79, 0x6be0789b, 0x0c2dcfcc, 0xc7800be5, 0x8baf3b42, - 0xc9a93c83, 0x143250eb, 0x60789ae0, 0x5347cff9, 0xe21ef63e, 0xeb8f90dd, - 0x3c919d0d, 0x2361fc31, 0xb07fa13e, 0x2e888f33, 0x627bd7c4, 0xebc012e9, - 0x04acb37b, 0x95df35f6, 0xe0b155dc, 0xf5b3332c, 0xbd292e66, 0xbffb8a30, - 0xb3f9bf0f, 0x8a02e11d, 0x9676b38f, 0xff95ddf7, 0x759fdc98, 0x0e5a8171, - 0xf56790f8, 0x71002e64, 0xf9e222b4, 0xe50e04f9, 0xfeb4527d, 0xfe9a6fca, - 0x54f5e43c, 0x89973887, 0x110b57b6, 0xdbd8f809, 0xfb0053b4, 0x289926fd, - 0x6a108f18, 0x8a8ccd86, 0x05111d7b, 0xdff357c4, 0xf80edde6, 0x4cd3373d, - 0xe8652e00, 0x01d82719, 0x512342e7, 0xd79bba0e, 0x5a647c1f, 0x10fd08a1, - 0x3f230fe4, 0x74db2514, 0x499359f5, 0xdba5373f, 0x95647344, 0xeafd063b, - 0xbd67c624, 0xff966fd6, 0x04dbf4cf, 0x5f18dfaa, 0xedfad18b, 0x7df18926, - 0x8d4b7e94, 0xd656dfa5, 0x17c0a9ca, 0xa766f72b, 0xbe575d02, 0x2c4fa4b1, - 0x8fbaf6fd, 0xa86ff7f9, 0xfd6de679, 0x1e1b7ea8, 0x51fadfa5, 0xae2316fd, - 0xa5ea5a3b, 0xcffcb37e, 0xa0ebdfc8, 0xb7cc62df, 0xa69fc558, 0xb5438adf, - 0xfb8adfa8, 0xa97cbaf1, 0xfa4f5249, 0xb397ecad, 0x6dba2eb0, 0xf007f831, - 0x0dedfa0a, 0x38c1cf55, 0x5dfee7a0, 0x3d277d72, 0x3d5bd557, 0x67843ff7, - 0xecadcf4d, 0xd33da1cf, 0x9e990f95, 0xf4c5995b, 0x4cbdcadc, 0xc41cadcf, - 0xbf519cf4, 0x6fd17415, 0x21eafbec, 0x23f47bf4, 0x1b7d7eb3, 0x23992f6d, - 0xfdf42dba, 0x9f3b5912, 0x5a3a3351, 0xd4bbfddf, 0x9f73be8d, 0x3d2e73c1, - 0x823fbbe9, 0x7a841bbe, 0x91c8206c, 0x1c6e3f91, 0xd3e5d368, 0xb1f5f7bd, - 0x79045ee7, 0xfe8f03f9, 0xe62607f7, 0xfafbed27, 0xbb9048d8, 0xaa1e00f7, - 0xf9519eef, 0x47e7d5af, 0x28793a7d, 0x7baaf793, 0x1baafe18, 0xd5df3639, - 0x7586407c, 0xd1176fe0, 0x2f7dbe8f, 0x9b67a3f3, 0xc0d8fa5b, 0x225fffcf, - 0x2bfd25ca, 0x87e28b29, 0x302b1739, 0xce2bb9ee, 0xccfc05b9, 0x80b10239, - 0xd0e0bb1d, 0x7ec0278d, 0x3d71705d, 0xe00bbdda, 0xc8e92279, 0xa1db98fb, - 0xebf6f527, 0xaf9da6bc, 0xf9ae9065, 0x8ccd1310, 0x7157132e, 0x5d59cd81, - 0x5da823f3, 0xc62df986, 0xabdf893c, 0x47cd9ff3, 0x8fe45f10, 0xe5f8cc7c, - 0x72788def, 0xad54bc33, 0xaa78f5e6, 0x89e262e1, 0x2ca4ba52, 0xb72f13a5, - 0x975914bf, 0x39cbed01, 0xf38cb7f4, 0x9c66f0d6, 0xcd4786bf, 0xbea059bf, - 0x24743f3f, 0x86889e66, 0x22f92ee7, 0xf80dde1a, 0x33d34b78, 0x206190d7, - 0x3c981f97, 0x7c0d1f3f, 0x178a7bf4, 0x73ade70a, 0x2bcee907, 0x65e2a3bd, - 0x6148e7aa, 0x24780c8a, 0xf367c035, 0x96be77ca, 0xb377e742, 0x210b9592, - 0x937f59f5, 0x688f103c, 0x1ea3b6b6, 0x9470f8d4, 0x5985c999, 0xf5ef2bd5, - 0x7ae21575, 0x50b9c4d3, 0x3d06c2be, 0x7999e6a7, 0xd7f261ef, 0xbaf7fdcc, - 0x6788518c, 0x91482e58, 0x5d015eb6, 0x86a73fe8, 0x40bc5d18, 0x69cffa17, - 0xe020fda4, 0x73993abd, 0xa6fde187, 0x3f02f79d, 0xcfa56ebd, 0x39cbce41, - 0x0e8616f7, 0x65ca7a7b, 0xc58858f9, 0xc8cc18c7, 0x173f5ceb, 0x5d897bc0, - 0xe68993ed, 0x8e00f796, 0x366e5489, 0xfd00c3c3, 0x46fe8a2f, 0x07c8c5fb, - 0x7503e53d, 0x2ab9efc7, 0x3a075f9e, 0xeddf01d8, 0xde43d812, 0xb47f5b30, - 0x1720af76, 0x3a34de22, 0x65f5d134, 0x2983a314, 0xd66f9e06, 0xbd9e2aea, - 0xef844e21, 0x6ffea06f, 0x7ebb0712, 0xf8d41f5f, 0xc5772cdd, 0xd215c413, - 0xe806f4a3, 0xcd7de8b7, 0x11b7a6ea, 0xa6ae375f, 0x15dc99e6, 0x407d1a5f, - 0x6f0e5e0f, 0xd34fcadd, 0x61799891, 0x467e55df, 0xb3f2f599, 0xe6fedacf, - 0xedab8870, 0x90af50e5, 0x7e2e8250, 0xecccd330, 0x07ab6696, 0x0dfdbcf9, - 0xee45bdd1, 0xa8a67faa, 0x257f0174, 0x64e27cfa, 0x4de80898, 0xa67c9597, - 0xe3007bcd, 0xe0f5e8b7, 0xe907ab75, 0x33ff5dd7, 0xedfecccc, 0xead31ece, - 0x9078c3d7, 0xc7eb28d7, 0x5a47ae33, 0x79a7a95c, 0xbf71d479, 0x71b4bcef, - 0x84beebbe, 0x3c60b497, 0xd89fdb4e, 0x89767bc3, 0x73163f60, 0x0a107dba, - 0xfe6fee39, 0x59bffa13, 0xff7ddd1a, 0x530a3f10, 0xe3bebf3c, 0x9f638c49, - 0x34c8f67e, 0xaf159f90, 0xe542c4f0, 0x838775af, 0x889e5984, 0x45427604, - 0x5dfb8f23, 0xcde70844, 0xa833b288, 0xf1f0c327, 0x5ef503a2, 0xa0732ec5, - 0xf15f7e84, 0x103967f2, 0xc35d6b7f, 0x59ff9ff4, 0x91fd1f95, 0xa807c81c, - 0xbcfed810, 0xa88f3e91, 0xb76a79fc, 0x6fe80e6d, 0xc73b3b6e, 0x2d9c115b, - 0x0ce2a39a, 0x16459bf7, 0xc36ddee7, 0x33ff6c3c, 0x0331e61c, 0x48e7d17c, - 0x53d0fcb5, 0x5cbd30cf, 0xe00624d1, 0xf6c5703c, 0x1710ad9d, 0x8cd0f8af, - 0xfb77abf6, 0xd3ec0919, 0xcf3e2fc9, 0xf1371bce, 0x976878ba, 0x3e76e438, - 0x59f8866c, 0x01ea1563, 0xf5823f5a, 0xfbf71aa0, 0x15b2718e, 0xd97dee2f, - 0xe2b8514f, 0xf13b4f37, 0x36cb705c, 0xb723c627, 0xa05f7e5f, 0x7831dc4b, - 0x9c771abf, 0xf5c105fa, 0xf1dc7621, 0x2127caa4, 0x48ee3eb3, 0x3c6127b6, - 0x5799c292, 0xd17e231a, 0x5fcfffc1, 0xcdf60278, 0xf2faed4e, 0xf2bb8009, - 0xfc4f739b, 0x2a93e294, 0xdbac1720, 0xc3df67de, 0xbbed067d, 0xd27d55f7, - 0xb8d3ccfa, 0x27fad34f, 0x6b7a1bb3, 0x2645fbdd, 0xeeb453ec, 0xe2053afc, - 0x4ef7abb8, 0xf56d7f41, 0x4953934b, 0x2b407f0c, 0xbd037f81, 0xd23227d8, - 0x39b1b9ad, 0x4d3ce013, 0x77eb0ee9, 0x58393c47, 0xb2f4e2c5, 0x11de471a, - 0x4bae5f7b, 0xc671b8dc, 0x3ac1d7cd, 0x65ba28de, 0xf1f88bd2, 0xe1cf4a61, - 0x0ee3a0bd, 0x38209f75, 0xe3f1b2f5, 0x4a0ff0d3, 0x7d660baf, 0xe342fe1c, - 0x0c7cff92, 0xba931ada, 0x7b871f8d, 0xdf6d3f81, 0x2159bf6f, 0x5da39016, - 0x1edc61cf, 0x0f7d47e8, 0x85fcfad2, 0x1cbb884c, 0xc0efdb17, 0x66bdebfc, - 0xd8aaa3cc, 0x53ca01fb, 0xe36f4beb, 0xf7511abe, 0xc7495adf, 0x5127db1f, - 0x56ef3a7d, 0xab3b8b07, 0xb4b88074, 0x6ae7c4ec, 0xb5f199fc, 0x2eee9716, - 0x32d63d1e, 0xabbfed80, 0x5b5591fb, 0x43112cff, 0x0b1b9fbc, 0xd9723af4, - 0x0f0d547d, 0x98c3c02e, 0xd896fde8, 0xfd8efff1, 0x80dd0316, 0x758f609e, - 0x7ad0a7ec, 0x07ab883f, 0xed620fb8, 0x666eb5df, 0x62ad34fb, 0x6d45bcec, - 0xc5a465ff, 0xe812efb0, 0x4f4bbedd, 0x78aef8f3, 0xb42706ca, 0x9d7c574f, - 0xbf5b14ba, 0xd4e16adf, 0xe7be037b, 0x67257ebe, 0x05981bcc, 0x78d5597c, - 0x4a7b0244, 0xf9b4df5b, 0xe7fd529e, 0x78f2cf53, 0xb05d644e, 0x51bbf519, - 0x1613547f, 0x5bc23437, 0xab7a616e, 0x1fad89ba, 0x023976a7, 0xa9cfda76, - 0xaf91bb03, 0x911c77ab, 0x83bfb4fc, 0x45237fdb, 0x60acf2a2, 0xc14408fd, - 0xfd85ea7f, 0x897f6c39, 0x71c6ebf9, 0xf1c752ee, 0xe38f6286, 0x374671dd, - 0x507f0ace, 0x2e7ee762, 0x4149de3f, 0x9dfd0d99, 0xe409116c, 0xf20c9ffd, - 0xe31881c5, 0x5a88b5cf, 0x0fc98b3c, 0x1cf1475d, 0xbb9d83a6, 0xb42513e4, - 0xc63b57bb, 0xfde7087e, 0x19243b57, 0xb57517e2, 0xeeb52f2c, 0x4069dcdf, - 0x5b84baef, 0xdeae3f71, 0xb2575f80, 0x1ae21f2b, 0x51d2c2ae, 0xbd46aec0, - 0x7498a093, 0x1476aff0, 0xce14caa7, 0x469daab5, 0x0b9e3704, 0xc5459de5, - 0x65de1f30, 0xec635972, 0x52f6883b, 0x8bc289e2, 0xe39fd2e8, 0xca469724, - 0x7f968fd0, 0x39696953, 0x052e8d88, 0xb1858c53, 0x99fcddec, 0xdb779c2e, - 0x507fd50e, 0x614aec88, 0x8eb06479, 0xcf8aedb4, 0x43f1c321, 0xb47e50a2, - 0x1db9cfa9, 0x5e83f7fb, 0x4a24eb5a, 0x8a339502, 0x86cf9955, 0x2c23acf3, - 0xe9f0365c, 0x857aff99, 0xf10d6bf6, 0xd9b457e8, 0x25527cb5, 0x46cce401, - 0x41bcc41e, 0x936fe560, 0xe634e13a, 0x25781213, 0x298d3eea, 0xa1fd1dbc, - 0x7c589bb3, 0xff572780, 0xcf8b027a, 0xafc00091, 0x542b2fae, 0xe212cf38, - 0x3bfbc30e, 0x580f181c, 0x9422c6f6, 0x3443a01f, 0xf58a92be, 0xac1b5ee7, - 0x67f01cce, 0xbf555a36, 0xc0b4afc6, 0x6ac59b39, 0xf54a7dbf, 0x18a962e7, - 0x975e41fa, 0xe5faf2a8, 0x9843a2d2, 0x8a59e68f, 0x8e753e7a, 0x31acdcfe, - 0xaa204b4f, 0xfe601c9f, 0xadbc9773, 0xb708cda6, 0xc56b7f31, 0xc35d7d76, - 0x37a027e3, 0x127402af, 0x80e2e5fb, 0x3237e23d, 0x4613d7f8, 0x9afc777d, - 0xb5f8f4d3, 0xdafc7aca, 0xa7f11886, 0xadc3afc7, 0x97e697c7, 0xf8df8776, - 0xc873fab1, 0x8afc2aff, 0x548ed556, 0x4aff4af1, 0x654c292d, 0x42e9dc03, - 0x28c2e518, 0x30f61947, 0x9feeff07, 0xafc5a81c, 0xefd40edc, 0xb87cea69, - 0x1b3becc5, 0xf00f11c8, 0xe08e51ba, 0x79e82024, 0x75d8f91b, 0xfac40acc, - 0x4d7b7c8c, 0x355cf4f7, 0x0b23d5fd, 0x809b57e9, 0x3f23877f, 0x89bef3b0, - 0x05975024, 0xc176ea72, 0x59f41dfa, 0xb8458bdc, 0x17b885f7, 0x5efb820f, - 0xa43e585c, 0x0db4abe6, 0x306e7825, 0x029f3e18, 0xdca1e9fa, 0xf7a069f6, - 0x29484bbc, 0xc51fc1e8, 0x0f03f3b1, 0x38bf65a8, 0x85abd549, 0xef824c6f, - 0xe70ca243, 0xdb42dbd5, 0xdea0832c, 0x2a3de3c4, 0xabfa84de, 0x90d6fc60, - 0x6c5ae0c8, 0x38820c09, 0xc7115ec8, 0x013c5d6d, 0xd87665cf, 0x2f96216f, - 0xccfa16d2, 0x9f4a28b9, 0x7a3d36b7, 0x36b9c415, 0xa9e7629a, 0x7e9ab14c, - 0xec1bfad8, 0xc537b792, 0x1eeaf2ca, 0x51e7401a, 0xbaacfd3d, 0xb879330e, - 0xabf3a556, 0xf9c46f4b, 0x64e214bf, 0xf88a4758, 0x461a6edb, 0x3dee39e7, - 0xb0cf8d41, 0xf528e578, 0x2fd03afd, 0xdfeb5fa8, 0xddc3e9e5, 0xe7020547, - 0x2cd546f4, 0x15eb7f45, 0xca73e527, 0x704a7917, 0x616df024, 0xcdef0128, - 0xd04c7ef1, 0x22dd1fae, 0x4f33f8e8, 0x22f3575d, 0x44c05e54, 0x3edf50f9, - 0xec18222e, 0xfc0f00a0, 0xfd71ed75, 0xd55685f3, 0x149272ee, 0x970df3e0, - 0x5ef20e78, 0x7b89dadb, 0x6dbb850d, 0xa3845f71, 0xfa9c3ced, 0xbe25e5a5, - 0xbf7ad638, 0x62f8caca, 0x9d7044a3, 0x8ed4b8d9, 0x4b03c5f1, 0xf580ae2b, - 0x7b1fabfd, 0x8e7588ae, 0xc53f4a3c, 0x252c7cb3, 0xfe058c9e, 0xbc31cb5e, - 0xc697a7d7, 0xf8d7f7c8, 0x8d6fe359, 0xc697d3af, 0x35e56279, 0x7665637e, - 0x21d2c15a, 0xdafe049c, 0xe38f0e3e, 0x5cf1aeb6, 0x9f8ddcf6, 0x7800c9ac, - 0xd0e74dbc, 0x3884b6ee, 0xb1bd9625, 0xfec4eac1, 0x6bf8d75b, 0x2eef8f21, - 0x27a09c2a, 0x0377efbb, 0x813f5bfa, 0x677c2ca0, 0x73c32fa9, 0x642c4bbc, - 0x85bbc40b, 0x1c5bf4fa, 0x6f93ffc0, 0x7de14758, 0xeb84d4ac, 0x8dd146eb, - 0x08abfbf0, 0x1a83f8c1, 0x8d37edcf, 0xcf3e8e6c, 0xff3584fc, 0xc7a52b59, - 0xd21756b3, 0xe6e3c925, 0x3ff77e00, 0xf209dbfe, 0x8cd176dd, 0xfaabec74, - 0xaf77da43, 0x36dd9959, 0x0ad94e33, 0x64f293df, 0xc7b71394, 0x123c5ee9, - 0x78a04dee, 0x4ea3928f, 0xbbf1f9fa, 0x71d50f44, 0xbb449e14, 0x2892f909, - 0xc5d2ec8a, 0x4728fd29, 0x30905c9a, 0x4d8f2047, 0x885cabd3, 0x1ca83b0b, - 0xc3d8b28c, 0x962477e0, 0x105379d3, 0xfac2c4ac, 0x754e116b, 0x3cc6cb9c, - 0x7997ca79, 0x608a3870, 0x71121448, 0xdf4d7fa1, 0x6d7a7a6a, 0x59794102, - 0xa810b0fb, 0x126cfda3, 0xaf885622, 0x01722964, 0x0a251aa4, 0xef179e32, - 0xff304e5f, 0x78fd96d2, 0x42dd8742, 0x37c47e85, 0xfb5882fc, 0x869c7c79, - 0x401fcf2f, 0x6a1ce46f, 0x8de6003f, 0x73c6cadb, 0x3b4166bf, 0xa87f43bd, - 0xba9158f6, 0xdcfb8efe, 0xc209f2c4, 0x3ef44893, 0x687f519b, 0xebb8c9f6, - 0xbf606b22, 0x189fdc68, 0x055bb49c, 0xcead1bbe, 0xa89f43b7, 0x1098e6eb, - 0xfbf427d5, 0x66c8d0dc, 0xf72b07b8, 0x5dc72663, 0x3f21c9f4, 0xbefbf80f, - 0x17c8c47a, 0x2e54c223, 0x32a1f6d5, 0xeae1a7dc, 0x19fb43a8, 0x9e49de83, - 0xed152a3e, 0x8cdf955c, 0xdbe4d678, 0x77b9f728, 0x0ccd9bbb, 0x1a47e62e, - 0x275c21c6, 0xe836721c, 0xb078b7a5, 0x29f2dbf7, 0xbf5c281e, 0xf4a3f902, - 0xb81f384b, 0x21bfe601, 0xe415bd74, 0x27af7be4, 0x5475fa21, 0xbcd3f69e, - 0x0fae3e27, 0xc04e27ae, 0xf3fef543, 0x46127aea, 0x01c8777a, 0x78e89395, - 0x46ffc689, 0xa3e4d77e, 0xc8de2e0e, 0x047673c6, 0x0b9e59d6, 0x663065e2, - 0x7805c9b2, 0x3aedecd5, 0xfe25bed5, 0x56ffb474, 0x1eba88bb, 0x4f800665, - 0x5ecd44ea, 0xe3a25b77, 0x051dab53, 0x4fdb97a9, 0xfea45ef5, 0x1b39d459, - 0xfe8ed0af, 0x84a2f79b, 0xfe37bfcf, 0x7914289a, 0x898dfc3a, 0x7f15dd1b, - 0xb08471f1, 0x9ffec2fb, 0x230cdf9f, 0x7727dc7f, 0xe25aefce, 0xf5422579, - 0xf5aade47, 0x3f193675, 0xd7969c39, 0xfb682f55, 0x01e9dd9f, 0xa98fbca3, - 0x70c66fac, 0xeef20f4b, 0x25f8a9b5, 0xb3e80664, 0xb76a61f1, 0xff957564, - 0xbcfceaf3, 0xb6f78636, 0x8307db5b, 0x3de7ad3c, 0x2f687135, 0xb0264c46, - 0xb413762b, 0x8ffbdc7b, 0x5bde513a, 0x4feb7492, 0x8fc0bb57, 0xa7d9a9f2, - 0x7c6a5d9a, 0x552ec3af, 0x3e2d1bd7, 0x795135ca, 0x193cf0a1, 0x1c03f1e7, - 0xbfe62e75, 0xd05701c2, 0x3d584f63, 0x365fc075, 0xd838973a, 0xce12192f, - 0xb096f162, 0x93bb3e4e, 0xde419b47, 0xb03f1482, 0xfae9f9fe, 0x1eeb8837, - 0x0971b19e, 0x85aa5e0c, 0x97e9bec0, 0xd560d847, 0xfbc7f304, 0x6bfbb0e5, - 0xfbb2e5fa, 0x31c73732, 0xa18b65fb, 0xfa5ac27c, 0x144bcc18, 0xfb9cdf88, - 0x5006e1fd, 0x64f90e21, 0xf800d29c, 0x382b14b0, 0x71170c8f, 0x19de9473, - 0xbc839042, 0x994ac489, 0xd247f163, 0xfb48ffb9, 0xf39128cb, 0x06323f81, - 0x9a373c12, 0x9e7d8a11, 0xf13895e8, 0x8debd987, 0xbcc1ce5d, 0x41cfcaa2, - 0xa937ce89, 0xe9839d84, 0xf050fb88, 0x8eadbf01, 0xadb2715b, 0xab3ed817, - 0xd9e1813f, 0xc101bfe8, 0x5a825e60, 0x822257bf, 0x2bfd1135, 0xdfaff03f, - 0xcaff4164, 0xd041dc46, 0xb1c41fb7, 0xce3aecf8, 0xbfea1ebd, 0x702dda10, - 0x37268fcf, 0x343c3c9a, 0x40b716e1, 0x775e755f, 0x5f7c0736, 0x00ef172a, - 0x9c275b9e, 0x6716bc1d, 0xf8c99ed2, 0xf975e14e, 0x9afd1af6, 0xacfd1d44, - 0xd6895710, 0x08690ef3, 0x5cadedd8, 0xaafc1b9c, 0x831ce5d6, 0xe7a8b397, - 0x3cdd0411, 0x1fcc6cd3, 0xe7f55369, 0x90b2e3df, 0x84f5b51f, 0xc63d6fce, - 0xe8f30d7f, 0x386a8738, 0x973c6a77, 0x11dd969a, 0x7cc74a07, 0xee0952dc, - 0x43672332, 0xbce3b436, 0x124cf6ce, 0x6a64bce3, 0x5cf31ac4, 0xbc5256b0, - 0x4b780d7d, 0x40126b15, 0xcedea71f, 0x1f1188f4, 0xc47f9c6d, 0xfb47d841, - 0x1f331883, 0xd2d32b45, 0x4c584a6e, 0xbf4b4fdf, 0x79ed4b01, 0x19885d83, - 0x71b24c57, 0x64dcec3f, 0xfc18b103, 0xed1b24cd, 0x9de7b4ef, 0xff1415f7, - 0x37bb8c76, 0x37bc31c4, 0x37bc31c4, 0xe53e1a48, 0xcebf9078, 0xf7975bba, - 0x4967c1b4, 0xd10f2010, 0xb9f28e9f, 0xdde8c5c4, 0xf682bef9, 0xdca21f4d, - 0xc4941730, 0x436c9106, 0x21f167be, 0xafc87ced, 0x4024cf7c, 0x96db94be, - 0x16fbfaa5, 0x0604df46, 0x530df9f7, 0xb214dc70, 0xe2983ac6, 0xc9a96979, - 0xd3a3710d, 0xc2723f0b, 0x1985e991, 0x0f20792d, 0x1b8f79a7, 0x984a97e6, - 0x8e6cb85f, 0x2ed30814, 0xc2a81b93, 0x01ba7462, 0x4ccb3bf7, 0xc7aef331, - 0xe9fed8d8, 0x961738d1, 0x90d36969, 0x92f59d4e, 0x8c4bf004, 0x35e54a7c, - 0xcea8f17d, 0x6f94cc73, 0x790c5b14, 0x1349136b, 0x185beb87, 0xb1ac95f1, - 0x35b7aab3, 0x39064979, 0x52ab7d84, 0x3a3547aa, 0x4d5f500f, 0xfe28b8c1, - 0xbfd7a171, 0x79c37f06, 0x45ea015d, 0x10c88e4d, 0xa0ade7a6, 0xa1e2a377, - 0xe83f7b6d, 0x9f8efb0f, 0x0739dbfc, 0x55fd3bec, 0x9e807768, 0xbbcf7e3d, - 0xf4c7380e, 0x2e2c3dc9, 0x4fc18772, 0xfa63645b, 0x74ad8f7f, 0x8177e01e, - 0x9e791fef, 0x77257e28, 0xe593fdb3, 0xde70de01, 0x506f7f5d, 0x70c93055, - 0xf11f908f, 0x1fdea55a, 0x46c7a466, 0x2cb78b1b, 0xca59b1df, 0x4f7c6190, - 0x5c7f8c25, 0x378f43f5, 0xd1dfd03a, 0x63b859e0, 0xd9be0484, 0x7566435f, - 0x6445bdff, 0x025287eb, 0x151e67fb, 0x0f38466f, 0x2f6af7aa, 0x8fcb25f9, - 0xdd63a329, 0x27b0f54d, 0x187bcec4, 0x13e4b1e7, 0x129528b9, 0x1cfdc96f, - 0xfef0ddfa, 0xf33d743d, 0xee1f7ddc, 0xd9e719b3, 0x051f5ef5, 0x2a65b3fd, - 0x6de78dbd, 0x3ed88597, 0x41e262f8, 0xfe72ecf9, 0xc5cec436, 0x678de318, - 0x00db650f, 0xa9b0bf0f, 0x323cc4f1, 0xef6dce06, 0xfe20343a, 0x9f56f772, - 0x828bef52, 0x3ca1bb7b, 0xce5823ee, 0xe2902303, 0xf6f432bf, 0xd55fc05d, - 0x3ef13b4d, 0x8faaefb4, 0x9c2742aa, 0xe9ad4b90, 0x6e876a25, 0x8b20f903, - 0x5a7d9d39, 0xc49cf9bd, 0x9f866afc, 0xb7e7d4db, 0x20723e01, 0xd9fe5bdf, - 0xdbef4a04, 0xd1f3c52a, 0x6f3da5f7, 0xf7c3efd3, 0x3cdabe76, 0xed6b79b5, - 0x9c5e6a55, 0x0e4d3bf1, 0xb97ca9e6, 0x75f4eb78, 0xea8a297d, 0xa9917ef6, - 0xf3c3939e, 0x2d9f1a42, 0xe945a523, 0xa349f831, 0x84df076f, 0xd3f38e7e, - 0xbeb8bae8, 0x3f83c54c, 0x4c4fdd4d, 0x91957883, 0xa73a7a8f, 0x32462add, - 0x7c8dbe41, 0x7dcddad2, 0xb31b2128, 0x4acb162f, 0xa8cfc411, 0x15cebbf9, - 0x171cdf65, 0x14fe0fea, 0xe32b6ee4, 0x083d0efb, 0xf7e8314e, 0xff5c4537, - 0x54e43a57, 0xe90fffb8, 0x13f20e37, 0x4f787ecc, 0x4f98e71b, 0x808a0651, - 0x4f2c62ff, 0x81954afa, 0x97db3a83, 0x04e73c6e, 0x086dbbfb, 0xab51b8c1, - 0x69ef0f43, 0xe37a8f1b, 0x4a8f4ab4, 0x3f9be5a1, 0xdadace83, 0xc7177982, - 0xa771a92e, 0x58e2e64b, 0x39d8b4f3, 0x7778bddd, 0xf9a872a8, 0xfa540b35, - 0xfb6211dd, 0x4d370be9, 0xc9747a47, 0xa1fd54bf, 0xf50e46b2, 0x4b3e918e, - 0x3e63d7dc, 0x3e40a2da, 0x5e85df7e, 0xbba441e4, 0xda776e91, 0x371eec5d, - 0x7b8246a1, 0xe26d8eed, 0x8571ff70, 0x73ff7b10, 0x9df4ddb6, 0x479c63e6, - 0xdb2ff077, 0x2faebb5a, 0x908ff981, 0xf08dcf80, 0x425ff36b, 0xd4a7a614, - 0x2f3776f9, 0xf2c49912, 0x7f75d434, 0x815b9c39, 0x790793fd, 0xc6adcf96, - 0x35f834a1, 0x28f38d78, 0x7cf12be2, 0x8f035b41, 0xf877d979, 0x77067dd9, - 0xfd70e5ac, 0x9a4e8eed, 0x7bf6d15e, 0x30ca9baa, 0xfb43cb6f, 0xedb63b01, - 0x29f6c263, 0xcf7873d6, 0x0cf4b75b, 0xeea57cb1, 0xa30849e8, 0x374a62db, - 0xdebb3ff0, 0x0caf909f, 0x0a27de8c, 0x8c0ca0dc, 0x4122b7de, 0xb15957cc, - 0xf9eeba7d, 0x8e35768d, 0x9ef5eaa5, 0x24d48fe4, 0x696f8cc4, 0x9fc9a6f2, - 0xda778f26, 0x0a6f6665, 0x59198381, 0xd1879f80, 0x7afaa1bf, 0x3df99d9e, - 0xafa5cd0f, 0xa73c6f54, 0x3258a7db, 0x096bd196, 0xbbcf825f, 0x0f14bbd3, - 0xd8bdbd3a, 0xf8c3cfae, 0xe6d1f3a1, 0x3689c9a1, 0x189ca33f, 0x43d237bf, - 0xe919ef8b, 0xc007a462, 0x5bc67e09, 0x35816d7b, 0x38b7ce14, 0xaf7fb706, - 0x4d6ee115, 0xb9c0ac9b, 0xf9f4eacd, 0x3e01fe58, 0xb0fb074c, 0x768eceb4, - 0x8d87eaae, 0x225c5dea, 0x5ecbb557, 0xd9232ab2, 0x24d2a7b9, 0xb58993e0, - 0x17161991, 0x583e8f21, 0xa4f7045c, 0x32387c4e, 0xbff14203, 0x5646f07e, - 0xd77916df, 0xfcfb86e2, 0x690a8a4b, 0x2fd071fd, 0x95fa2fa0, 0x6efbe0db, - 0xf973c4eb, 0x1fdeccba, 0xcf9d2e65, 0xed66b1ee, 0xb33ed495, 0xf2aef5d0, - 0x4157e0f0, 0x4a5b2b7e, 0x542e218a, 0xba781109, 0xce2955de, 0xad872db0, - 0x7be9e3fb, 0x4f3cd91f, 0x76ee21d9, 0x8bae2d71, 0x94058795, 0xc588722f, - 0x573a0567, 0x6d6efd2b, 0x2993b51c, 0x5a26d77e, 0xd317e0dc, 0x97f07ee7, - 0xb22a26d7, 0xa35cf51c, 0x70077c1f, 0x7cb135ac, 0x0c6ffd82, 0xc65c8f8e, - 0x23efd82e, 0x34cfe025, 0x1a582cfb, 0x1725f3db, 0x37c8e79e, 0xb18978b1, - 0x76bb6dfd, 0x00ce49ae, 0x243ea8be, 0x1fc3fca1, 0x84559fd8, 0x613549c9, - 0x0eaad0e7, 0x53773c13, 0xcf08a87d, 0x84b9c0dd, 0xe07a754f, 0xa6ee735f, - 0x9e18af93, 0x44ae040a, 0xd0b71a88, 0xf9d5d56e, 0x9810d354, 0xdce3e10f, - 0xcf846e70, 0xa2ecd530, 0xa0afe7f3, 0xe087c525, 0xff70f372, 0x89e4fd4c, - 0x559fdc3c, 0x2d79aa27, 0xbe3e7626, 0xe557dd63, 0x39fb2b4f, 0xdd028f4a, - 0x25b1ff4f, 0x53f6c6cf, 0xe6d6afd0, 0x8429c75b, 0x35ed7f03, 0x7219e782, - 0xe0334993, 0xb19446cf, 0x47166fc0, 0x6c97caa2, 0x65fe9b3f, 0x9b36e940, - 0x7e53237e, 0x9fc1faff, 0xe3bbff22, 0x68b2ab4d, 0x59f8739d, 0x2e74c33d, - 0xef30b28b, 0x6bf565a8, 0xd006e74c, 0xc358e8ba, 0x4af1b0ea, 0xa3b33e17, - 0x143fc8ae, 0xba3171c6, 0x01ae50ee, 0x2c4c16fe, 0x901c23ae, 0xcb477f70, - 0x794b5957, 0xe2d1f806, 0x5d747a60, 0x3673c16d, 0x28179b88, 0xec4fe432, - 0xfa41ef51, 0x5786a5be, 0x7f4266de, 0x7fc04a09, 0x53e183bc, 0x54690ba3, - 0x5e3c81ae, 0x81ae5412, 0x0e7ebd7d, 0x7e83a24f, 0x96adf23f, 0x1bcfa089, - 0x0f28f9df, 0x82bf73ef, 0x2df233f5, 0xf9d243ea, 0xff6dfe9c, 0xe4fbd1cd, - 0xa9f91cfd, 0x03251df0, 0xec9cafda, 0x3951b722, 0x2c8853ac, 0xad9f8365, - 0x091b2ff7, 0xd91f4fd3, 0xa070af4a, 0x3ae3093e, 0x67bb13f6, 0x7e8dd400, - 0xec496933, 0x949dde55, 0x17ee3773, 0x7d346625, 0x85d610b8, 0x4a7bb1df, - 0xfcc14538, 0xee3b17d3, 0x9718236b, 0x373891b2, 0x9b898dc4, 0xd453f9a4, - 0xf1899af8, 0x945e7255, 0x87ceacff, 0x79085f7e, 0x2c6c63f2, 0x8fce81bf, - 0x823afd07, 0x848e58c8, 0xa0365938, 0x3df583d8, 0x4fe1f824, 0x588fff69, - 0xb2ca7c59, 0x8fe2e89d, 0xb7160e65, 0xe2c9c079, 0xf062718f, 0xe22bb016, - 0xd81710ce, 0x4b8f6d15, 0x0bcfee02, 0xdf709bae, 0xe309a0ee, 0x018b4fdc, - 0xb517ec17, 0x5bc8255f, 0x6d7f6748, 0x7eb5dd2a, 0xabe4911f, 0x0bf7ee20, - 0x9d3fab27, 0xbb8f304f, 0x801484fd, 0x0cc4dcfd, 0x3c744d4b, 0xd9839e69, - 0x1573bfbb, 0x043a04cc, 0x1811c6f7, 0x38becc7f, 0xb9e3d013, 0xe056b91d, - 0x4701178b, 0x66890f14, 0x5fd09dd7, 0x6f0a39e2, 0xf9673e16, 0x223c82fd, - 0xfc77e29e, 0xee19768d, 0x1ada7ad1, 0x56f311bc, 0xbde1379f, 0xee4a2fc1, - 0xf17f50e9, 0x3d02ecac, 0x305674fc, 0xbcf3e70e, 0x62f3e709, 0x2bd5fb5c, - 0x0c0fdc29, 0xc12ef161, 0xcfd00446, 0xbe40a982, 0xae5f3e93, 0xafa6b1f2, - 0xd11c8137, 0xc11c23fa, 0x29820c73, 0xcb48e51f, 0x276b6a27, 0x67d44f98, - 0xfc0f0b66, 0x8b5d371c, 0x8879853b, 0x25284d17, 0xb04dcf68, 0x05ce788b, - 0xbce199f2, 0x0f5544db, 0xb2b8fc4f, 0xbb07e584, 0x9ebdc30f, 0x7ef576cd, - 0x739f7530, 0xd727ca92, 0xa16f0891, 0x245dd7ed, 0x4d27886e, 0x8fdfa8ba, - 0x5f60ca78, 0x57fb514e, 0xf0855dda, 0xede89f38, 0x450d29bf, 0x2c3d6027, - 0xfc008a20, 0x6862d934, 0x09d23b07, 0x9febf0f7, 0xfd50e03f, 0x19924cdc, - 0xeda6c79d, 0x87e14d43, 0xb5fb446e, 0x5e037258, 0x0f95da76, 0xdfc03f20, - 0xc5cb9222, 0xb1f29f25, 0x1721c37c, 0x2cae046d, 0x8769fca4, 0x50dd5cf9, - 0x79d2b7ef, 0xf5903d5f, 0xfa087c0f, 0x93c7cae5, 0x8fdf4093, 0x95a5e957, - 0x7f01df1a, 0x7f19e2b9, 0xca7786b9, 0x2c8ed3e7, 0x37934f7c, 0x67e83be0, - 0x1f98188f, 0xf29bbf6b, 0xafc0d3eb, 0xfd04ed3b, 0x5ba59fb8, 0x699c80e6, - 0x7caab4e3, 0xd5d72c6d, 0xbf0fdcae, 0xc0bfe4fb, 0xbec28dd6, 0x75e8a517, - 0x83024fbf, 0xcfd72bd7, 0x68790698, 0xccf31176, 0x5173d452, 0x1e92fcd1, - 0xdf1a2fc5, 0x9c59dab5, 0xc99fe348, 0xe1e5dfbb, 0x840be4f9, 0x8748b2b8, - 0xcff1a2bf, 0xf7187f44, 0xe6122781, 0x67f9189f, 0x93fc3757, 0x40165e7f, - 0x9fe1756f, 0xba7f8c43, 0x0fda1be3, 0xe4616bde, 0xaa1c779f, 0xff2dddbd, - 0xfcf3c25c, 0xbe4ef7ab, 0x93657eec, 0x6a9f9f4f, 0x62d9c72c, 0x54bb2fe7, - 0xea96efbc, 0xbd01ca6f, 0xcec4d531, 0xe32409ef, 0xeeef0a16, 0xfcdeed38, - 0xefa86c9a, 0xda1e9814, 0x1ea33219, 0x78f769da, 0x669b7e30, 0x0557e761, - 0x23ce044f, 0xe45afbb8, 0xd921dfe8, 0x587660ee, 0xfb8f0c50, 0x37f1ec02, - 0x9d8c1f18, 0x2a43cb9a, 0xa662fa5a, 0x971d4617, 0xcfefc336, 0xbfccea3d, - 0x06967c00, 0x79dfa3b8, 0xcf784a8f, 0x0951f552, 0xf76fe3f5, 0xf1045dbd, - 0x79cf2d51, 0x8bb79ecc, 0xfbc2860a, 0xa1fedf8c, 0x8ead65ea, 0x5f404047, - 0x1fddee1a, 0x4b1e71d7, 0x297e6f7f, 0x674e51f0, 0xf93ef1bb, 0x3fdb1c60, - 0x11644d99, 0xb4719886, 0xdeb85ef4, 0xfcaf78cc, 0xff3b30ec, 0x27b0f336, - 0x2af2bdf6, 0x37ef187f, 0x8a77f6a7, 0xe7efec13, 0x6841f65a, 0xdd6cc884, - 0xd7354a0e, 0x26a33f30, 0x9349f81b, 0xf8a3fc43, 0x44327e0b, 0xb706bbf7, - 0xd07ff3a9, 0xa9fbb02d, 0x4bee1222, 0xefb09cfe, 0x363aea82, 0x40f4c9ca, - 0xe617eaee, 0xcb239c03, 0xcba06695, 0xd7162eb3, 0x5b0905f9, 0x6e6e81b2, - 0x8253f701, 0x0bf93ca2, 0x223df3ae, 0xd3b10e94, 0xe27d3df6, 0x8ff8c246, - 0x9c633d3a, 0xed099f60, 0x31bbe087, 0x824773e3, 0x588fb71e, 0x9aeb049b, - 0xab853706, 0x13bd9b78, 0x81ae0d0e, 0x8f97c64e, 0x00c6cb3a, 0xd03be01e, - 0x8e474d4b, 0x8d7be059, 0xcf7b821f, 0xe2883e30, 0x4e83e00b, 0x4016e0be, - 0xa283c35d, 0xfdb7cfae, 0x8b42f88b, 0x17c8f46b, 0x7e70b710, 0x0b98be2f, - 0x05f23578, 0xce3ce7b5, 0x505cf618, 0xc6937962, 0xe7b13fe7, 0x896efbe3, - 0xd913de60, 0x6bbf6567, 0x7dc049e8, 0xd8b8df90, 0x1c9f6d98, 0x28a6a4cb, - 0x7664e559, 0x2a3bf6bd, 0xda1cc223, 0xa2a8239f, 0xbced0db8, 0xdd27a87e, - 0x31c8fe2a, 0x46fb838e, 0x033e3731, 0x1270d0ec, 0xcc236bd8, 0x87906125, - 0x1989b65d, 0xdae63f60, 0xfcc36426, 0xfab21e5f, 0x5ed2584d, 0x9bfe5bee, - 0x7da772ad, 0x66c3e9a5, 0xfc6d5bb5, 0x4c7f2a35, 0x2779d852, 0x70d1ebd0, - 0x9003eb68, 0xc2e0e009, 0xdadf4db3, 0x22878f50, 0x00936f14, 0xfd878a0e, - 0xfb04691c, 0x24a4df21, 0xb03b064f, 0x3800584f, 0x9d7ef6db, 0x92cef109, - 0x021febd0, 0x3eda25bc, 0x0fbf5bac, 0x35b7b46b, 0x3ff3487b, 0xf3497b34, - 0x82aec17b, 0x1fd532f6, 0xbed99971, 0x05b084d8, 0xe47853ef, 0xa2957cac, - 0xe740b3ca, 0xe3cea251, 0x7082d266, 0x4ca9f769, 0x7251f153, 0x39abfa88, - 0x54c84ed0, 0xeaa9878a, 0xdd532a7d, 0x6e22fbfa, 0x3efb1b1e, 0x9e9fad15, - 0x1bae37de, 0xa3f61ad7, 0xc879687e, 0xf94feec7, 0xc3f98fbd, 0x7ef007e3, - 0xb1dfd601, 0x09feec59, 0x21c3c317, 0x763af629, 0xf1eb9551, 0x9c0e48a6, - 0xe7bfdec7, 0x1e6eb8ef, 0xf7f7f3d8, 0x771c8ec1, 0x97902042, 0xa8c4fe3b, - 0x180fcc78, 0x695f232b, 0x6f3f7afd, 0x9cf611b4, 0xccdeff44, 0x728f0a41, - 0xc167c025, 0x8f5395f2, 0x9dfd0a3c, 0xe8902a3f, 0x92451f73, 0xe5c42067, - 0x1ddfd48b, 0x7b31c83a, 0xa83f6b4a, 0x11c7defe, 0x21216f95, 0xc567bb43, - 0xa9e7451c, 0x1a1ffdea, 0x2f1ea75d, 0x74e4213e, 0xfdfc0fa5, 0x5a10e233, - 0xaa9ce1fc, 0x9ff3490f, 0xf5ce7cf0, 0x600a778d, 0xc69f5fbf, 0xdc6a2513, - 0xe9ea641b, 0x4e21c547, 0x6ff60d3a, 0x4e8f33f3, 0xb7e5bc83, 0xf4814c78, - 0x99be7686, 0x3e16f503, 0x462abde6, 0xba1f5efc, 0x9955ef13, 0xa3e4cf1b, - 0x5fc7f1a7, 0x3864f94d, 0x3b309dd0, 0x4bdd8f30, 0x81efa462, 0x1491ff3d, - 0xbe3dda19, 0x91bfa3bb, 0x2a9caf0e, 0x9eac7dc0, 0xdbe461e8, 0xfe9e747d, - 0x5377e12b, 0xbf8fc42d, 0xfac2ea9b, 0xac34beab, 0xddeafc6b, 0xd81264fb, - 0x4e9f1a79, 0x337c6249, 0x49a3f76e, 0x2f49dec4, 0xc586de23, 0xc97ffe33, - 0xee25d9aa, 0xa3e8d359, 0x843ae977, 0x2d27ea8c, 0xaa563790, 0x70fb3ac2, - 0x4425da11, 0x5c62cf3d, 0xb7f366df, 0xda75014d, 0xccfeefd3, 0xf57acb94, - 0x6fc5397b, 0x0eb00bd5, 0x99ab0916, 0x78ed531e, 0x9d231e0d, 0x08a523df, - 0x19f0777f, 0xe708c0f9, 0xf6f91d4b, 0xda07ae0a, 0x18cce0ef, 0xc6262598, - 0x8f868798, 0xc7ae8499, 0x8f5fbdd9, 0xdbd78c6f, 0x178ee7ef, 0xdad011fe, - 0xe919bc9d, 0xf4d76c66, 0x900c1147, 0xec1fa58b, 0x29f1b993, 0x8ba2df48, - 0x3ae85112, 0xcfe9fa43, 0x2b9293f5, 0xb956df91, 0xf8eeb3d8, 0x4f22faad, - 0xf93b233c, 0xd87a6c4e, 0x5bb77c06, 0x1c41b7a8, 0xf4fb3af5, 0xc2bd103a, - 0xe2660bcf, 0x131115fd, 0x94dad081, 0x886699d0, 0x243f7833, 0x20a1be78, - 0xf0327fb4, 0x0b42abe9, 0xe76d59fa, 0xca387909, 0xd50a6cee, 0x6b2ec0d9, - 0xf3e7664a, 0x5d10260e, 0x78c5f4fe, 0x8e9a6fa6, 0xc4a69d9e, 0x62ee1f68, - 0x28833cfc, 0x9ff439c9, 0x7f29eb45, 0xc7dc1f80, 0x42927181, 0x325afdce, - 0x39732dd8, 0xf6da23f4, 0x992d798e, 0x7b7adbc2, 0x2999ea02, 0xe9ddf74d, - 0xfe0884a2, 0x6f3e2463, 0xfef0e32f, 0x8dd92284, 0x59c5a2f5, 0xf98df7e8, - 0x09466926, 0xa220dfb4, 0xaf8533df, 0x755e2014, 0xabc38d3a, 0x9170f63c, - 0x623df85a, 0x0e3674ff, 0xc093f971, 0x24a77d3f, 0x66fe0469, 0x07d5ac9e, - 0x122eefe1, 0xfab6ff83, 0xcdfb73a5, 0x2cf57db4, 0xa78df30e, 0x3f8832b8, - 0xd68a7f8a, 0x5baf384b, 0xc005a942, 0xf58a33d7, 0xaac31ee7, 0xd4ab393d, - 0xfbd10246, 0xe50b9cf9, 0xfdb5a0fa, 0xf11dfc56, 0xf98122bd, 0xa37e7269, - 0xe7b3efca, 0x9bbee924, 0xa9dd984e, 0xaa4dd5c9, 0xfaa8ddfc, 0x193d73cd, - 0x094bf1ba, 0x40fe87b3, 0x64810bda, 0x7ed8b8f7, 0x96f6b4f4, 0x25e1f3c3, - 0xd068dfbe, 0x310d3787, 0xe57cbdf8, 0x348be45a, 0xc8f78dce, 0x37edf5b8, - 0x8dd7d58f, 0x0fd46bf2, 0x8f8b20b3, 0x3427aaef, 0x2f6b307d, 0x683c422f, - 0x33c53e56, 0xbb7ac5da, 0x317d27bd, 0x7d1bae26, 0x17be4971, 0xfa2e90cc, - 0xefe2e3e2, 0x4b7e2fa5, 0x54b196dd, 0x578edfae, 0xa4fecdd7, 0x298de83f, - 0x81478efc, 0xbae8da8f, 0x47c18e69, 0xc5a3bada, 0x1ca88a01, 0xc5381ea3, - 0x5ca663f6, 0x91fe274c, 0x0e80719d, 0x12ed423d, 0xa97b0c77, 0xe51b3e35, - 0x68ef43ab, 0x2eca257a, 0xb87ef311, 0xda85325d, 0xc02e52a3, 0x2be10fd7, - 0x2925ef52, 0x882b8482, 0xc19da61f, 0xa0579038, 0xcfae2cfe, 0x817f224f, - 0x3b12e3fe, 0xaf68c3e5, 0x0ae87168, 0xe94f6697, 0x1e23a5f9, 0xc3dd9339, - 0x1149f1aa, 0x7fe413e0, 0x04fb8f26, 0x7fd41bff, 0x8000b303, 0x00008000, - 0x00088b1f, 0x00000000, 0x7cc5ff00, 0x55547809, 0xf579f096, 0x55492d5e, - 0x146caa92, 0xb612f08b, 0x84582484, 0x5916ec80, 0xa014a358, 0x8168cb80, - 0x9a126b0b, 0x69ee9c71, 0x0242a6ff, 0x83b74343, 0xe8cedad2, 0x3ad857f4, - 0x08b41a83, 0xd09d0301, 0x584c5015, 0xf82e0834, 0x1a6d1ad9, 0x84490ed1, - 0xbfbb46d6, 0x739cffcf, 0x2aaa4bef, 0xffff4d85, 0xb49fdf3f, 0xdeefb97d, - 0x67b9ef77, 0x979ee73f, 0xb3559bdb, 0xf6e008ad, 0x14078a99, 0x77f1d000, - 0xe042c022, 0xadacc37f, 0xc78ef016, 0x69fcd7be, 0xe7f80d87, 0x9c2ffc3b, - 0xa42cfc90, 0x900bcf50, 0xce54b009, 0x7d57fc5f, 0x3c5e3d33, 0x52fe7a27, - 0x92b9fd98, 0xf81b700c, 0xf71c30cd, 0xff8ec5f3, 0xc7154bec, 0x7e8b2e97, - 0x4a4ce99e, 0xff8790bf, 0xbe230118, 0xd4ca0153, 0x22b79dba, 0x5527ddbc, - 0x334c558f, 0x390ffed1, 0x350ffec5, 0x7c800c97, 0x1674df80, 0x3db1f8a7, - 0x1c2111b6, 0xd1bad00d, 0xec71edc6, 0xefc5f107, 0x3c66e7e8, 0x21fc059f, - 0x52b4b607, 0x4801b721, 0xc4ed1805, 0xff602745, 0x0d3f9e2a, 0xc02486c7, - 0x5c2473ef, 0xe7af00d9, 0xf104e798, 0x5eb8c3bd, 0xe30dd700, 0xf75c01fa, - 0xf72746c8, 0xe6e8db5f, 0x442e0dfe, 0xfac0066a, 0x37af2714, 0x8776f72f, - 0xe35bdf1f, 0x50e7e6cc, 0xf844da3e, 0x7b2fe036, 0x1004086a, 0xac77afdf, - 0x807494d0, 0xb1e2b72a, 0x01d1f566, 0x8e58e34f, 0xbe25cbf3, 0x102ab72b, - 0x1fe5e7c4, 0xc4072bae, 0xee33575f, 0x2aa9f887, 0xfc368355, 0x63d34967, - 0x0cdf453b, 0xdefa08d6, 0x33028e22, 0x86cd16b5, 0x28f02cfb, 0xf1f7151e, - 0x6ff78936, 0x1d412af5, 0x278b79ff, 0x63871e9a, 0xae58bee8, 0x0ffe80b3, - 0x47305bdf, 0x9d718609, 0xdfa29305, 0xd6757c5b, 0xfed8cae7, 0xe898b47c, - 0xbf3fb63e, 0xb7744edc, 0xc1863fe3, 0x95fba230, 0x8d6fa58b, 0xc5ba3e85, - 0x8e74b1b6, 0x9d16bf1d, 0x673a27ef, 0xc6ce9b5c, 0xce8b7ffb, 0x904e110f, - 0x1bf470be, 0x30049e8b, 0x1a07e9bb, 0x55f679d1, 0x32add78d, 0x861433ce, - 0xd4fe79d2, 0xb76ff859, 0xaafcdf42, 0xfe2d2fa6, 0xe79f6b82, 0x22bfed6f, - 0x69fde745, 0xdf7e6f5f, 0x8034f3be, 0xf9ce78c1, 0x8df8d139, 0xbd2c6ba5, - 0x62f7ca16, 0xe635b5e9, 0xa05d061c, 0x60689913, 0x555fbc1c, 0xd16b8e19, - 0x162e97ad, 0x7e4f08ff, 0x5f8071ff, 0xd6fab9f3, 0x76827493, 0xe02057cd, - 0x03c84732, 0x052075f2, 0x0ade5be9, 0xec0444e1, 0x3e738b96, 0x28f5a8d7, - 0x39c469f0, 0x8353e7e8, 0xfadf6ace, 0xb2075765, 0x96fb19fc, 0x14b01069, - 0x972173d2, 0xd255f0b1, 0x7e69233a, 0xcb68f980, 0x10b2d32e, 0x05ba639e, - 0x9b51f5ee, 0x4e03da28, 0x9d1a07a1, 0xfbb75e26, 0x6e099b2b, 0xf0e57804, - 0xf8406280, 0x09e7563c, 0x33218bd2, 0xc945fbf0, 0x9cdfcf3a, 0xdc048104, - 0x9b76b41f, 0x2b44f90f, 0x3941c806, 0x825906d3, 0x9d64b835, 0xdc91f616, - 0xa8347b75, 0xd1bbb946, 0xe048ef78, 0x6c92402e, 0xa99474fe, 0x0fde8b26, - 0x79c54fb7, 0xfa6a1537, 0xb2e29c36, 0xf1a03fea, 0x93ab66ae, 0xf83eebde, - 0x5a662dcf, 0x20f02be7, 0x335af084, 0x4f8e1532, 0xa4839873, 0x93d4ca37, - 0xddfb09aa, 0x8fa4003d, 0x970b2da6, 0x3a6dd200, 0xb138d7b4, 0x8c74429d, - 0xd0bfbf43, 0xde843379, 0x9a74881a, 0x4334e921, 0x6692abea, 0x4946f595, - 0xac841a92, 0xb374fd3e, 0x408cd1a4, 0xee0a497b, 0x3c53433b, 0xf9bfd835, - 0x8fc516aa, 0xba3e932f, 0x951f4fb1, 0x3dbdf5c9, 0x019686ba, 0xff344266, - 0x3d0a3596, 0x798b6254, 0xbe0fed2e, 0xe6557cc9, 0x429f1e8c, 0xfbf913ba, - 0x825e8c62, 0xa653fb18, 0x03b935fe, 0xc58af0f1, 0x8454defb, 0x19b4e7bb, - 0x70e7c59e, 0xfb933b11, 0xc631a7e3, 0x07b6c51e, 0x757a270f, 0xe215eb84, - 0x07f50723, 0xd7b1f579, 0xa3b63f9e, 0xf18e98a7, 0x0d22dd4a, 0xcf2d99b2, - 0xf0fb33ba, 0x92bf0fde, 0xad78b10e, 0xdbde7a97, 0x8e8d7ce8, 0xad8f0fdb, - 0x979ed8b3, 0x48d749fc, 0xf8bdfdf5, 0x95e5e434, 0xe25e890b, 0x0c2e57ff, - 0x4afdb2f2, 0x0c3e59d2, 0xfe783879, 0x51e92272, 0x21aea7c4, 0x6cb8f49f, - 0x9f99679e, 0x06841c85, 0xc36e0a8e, 0xc12485fe, 0xf624aff7, 0xbc23cf1c, - 0x3cf262df, 0xeb68db4b, 0x202a2f87, 0xd175b9fd, 0xe2803379, 0x2887e505, - 0x84ee8a4f, 0xa00db1bb, 0x05ff113c, 0x72482152, 0xd0108662, 0x785e35be, - 0xd319da9a, 0xfbc214f4, 0xddb35c65, 0x29e9eb41, 0xd7f0f7c4, 0x057d132b, - 0xbf5ff1fd, 0xee1a7c11, 0xe6d1b0d3, 0x1c2f50d3, 0x7ee4e8d8, 0xb73746e3, - 0xdcea3687, 0xfc913a6e, 0xaa1ff243, 0x169f16bc, 0xa5e657a1, 0x0330fd0a, - 0x35c10ef5, 0x00609403, 0x23c66f79, 0x7288f2c0, 0x10a4dc10, 0x393cf0bd, - 0xfa44f87d, 0xe888ee5c, 0x3b56ad43, 0x82a59321, 0x67985ee9, 0x09d1f7e2, - 0xd59f3e08, 0x3fd23e7f, 0xfc8cbfaa, 0xefc38416, 0xb0b996f2, 0xb37c390d, - 0x7adf885d, 0x4bd1e965, 0xf4b9fdc0, 0x43b95ebc, 0x8feb84bd, 0x1f84cf0f, - 0x8f18bda2, 0xe2bc2184, 0xff045dcf, 0x100b1684, 0xb2b0d07d, 0xf21a167c, - 0x5ca2b5f9, 0x8448fdc0, 0xef8c1bbe, 0xc4c3cb59, 0x23a0074f, 0x645ef08d, - 0x7e49d9f3, 0x3f04b997, 0xdddb9578, 0x3937ae0a, 0x0951e2c3, 0xf1bee1b4, - 0x2d7f11eb, 0xce21b819, 0x1cc9696f, 0xb713e7a2, 0xc93ef1bd, 0x08e6d7b7, - 0xcc986cab, 0xf6111d9d, 0xe33c007c, 0x74927f24, 0x476877dc, 0x0e4e3f5a, - 0x6abb9eb0, 0x6b5e9209, 0x09ec933d, 0xafd33ee3, 0xacbfd8da, 0x6e5117a7, - 0x8f26270f, 0x42133d65, 0x63f2430d, 0x6d98e713, 0x3c23aff6, 0x7a3e65a0, - 0xedfbdf0a, 0xafd20065, 0x543fdbd3, 0x312d0fc9, 0x40e80ee5, 0xa32a8f38, - 0xf27da853, 0x6e7ce4e3, 0x127724cf, 0xec9b0e7e, 0xcefbed3a, 0x0474bd46, - 0x8da9cbf2, 0xf9023a50, 0x368dade3, 0x746f4f6e, 0xa3667b72, 0x38a3db9b, - 0x3af3fc4e, 0xbd7f138e, 0x6fd4e381, 0x4f6a71c3, 0x7ad43ae0, 0x489872df, - 0xe5bc677e, 0xbc2da8d0, 0xfadb892b, 0x742c933b, 0x50c9c38e, 0xfc4fec67, - 0x370c4e14, 0x2ee50780, 0xdb53fdd5, 0xad3f680d, 0x1c6502fe, 0xf754d4c0, - 0xae3a6d5c, 0x8fe87b3b, 0x19f1c2be, 0x6a7ec3a9, 0x3b6f7843, 0x893868e3, - 0xf5c7d2fd, 0x3f883a9f, 0x92a2244f, 0xb7643c24, 0xc7365179, 0xc418d293, - 0x24c2f768, 0xfd19a7ec, 0xc8a5b9ec, 0x3a4a4b0a, 0xb005c0f2, 0x73e1b1f3, - 0x25df886d, 0x513fff76, 0x9b6812df, 0xfa9d3a53, 0xbc927010, 0xcb20e62b, - 0x7d2510fb, 0xadbfda11, 0xd4c4ff0e, 0xabc07f08, 0xf48d21fc, 0x02af44c3, - 0x77a674ae, 0xf7d2a470, 0xd5b798dc, 0x15313651, 0x2ed7f7f9, 0xc269f995, - 0x741bc534, 0x635f97f4, 0x7af384de, 0xe26fd129, 0xd4b559c5, 0xe2e3982e, - 0x4dd96fbe, 0xa5ff24b5, 0x5fbd6b8e, 0x5c87efc2, 0xc547d666, 0x638bce1a, - 0xe3798d17, 0xffc8c991, 0x0c4b69ee, 0x7d7c4b3e, 0x84935fd6, 0x567732fd, - 0x34752aa1, 0x6bb5df70, 0xbf978d1b, 0xe572c0de, 0x59e8f249, 0xa5ed8ac4, - 0xd33e3869, 0x24c278a1, 0xa93ed32a, 0xa771a34d, 0xcdb421e2, 0x553b8ef4, - 0x5423e344, 0x9fea4ccf, 0xd89d4bd5, 0x4e66d19e, 0x66f384bd, 0x6c78a4e7, - 0xf099def8, 0xff10ae8f, 0xf249ccce, 0x1714e824, 0xa4ae9f04, 0xa9eac7be, - 0x8f1ce9d6, 0x3ad32495, 0x6131e2ba, 0x92d6febf, 0x147045ff, 0x514052fb, - 0x91a5dc68, 0xc7e4fb1f, 0xe275293f, 0x0aa1fabc, 0x099cfc90, 0xe091fee7, - 0xa89ad99f, 0xf5402027, 0xbd296716, 0x9c516f57, 0x2befb89b, 0x5181f9a1, - 0x5c79fd66, 0x769de4f7, 0x6fe507b6, 0x745fb3e5, 0x6cc1cef2, 0x9adfca17, - 0x49ed4c56, 0xcbdbf093, 0xc39f2adf, 0x930826e3, 0xebbf2952, 0x1dbdf81f, - 0x4d293f25, 0x0c4ff5c7, 0x416eb173, 0x116a953a, 0x83e70d7a, 0x55dfef42, - 0x945bf3c1, 0x8f3a3f01, 0xa7e4aff3, 0xff715a14, 0x5109e959, 0x710ce7f3, - 0x8de7f545, 0x45aa5818, 0xfcf2b1d8, 0xadfea8ac, 0x88e94a45, 0x69bef988, - 0x45fd5109, 0x11d2aea5, 0x2b6ff311, 0x5fd5181f, 0x54565b72, 0xb269a67f, - 0xa11b1fd0, 0x7dc854bc, 0x9bfb2979, 0x0a87acd9, 0x1bee629d, 0x8e3f7e38, - 0x7f09b617, 0xfe85d0aa, 0xb4a5d214, 0x80fd88ad, 0xc68f7c36, 0x8f52ec8b, - 0x3ddda005, 0xfc80ec91, 0xf62fe209, 0x6677658b, 0x6305fa3b, 0xb768ae89, - 0x752fe023, 0xfaf1db44, 0xcc27e144, 0x0bad7f01, 0x75a739e9, 0x6557fb1e, - 0x6145d5e9, 0xbf467c20, 0x2a370b1f, 0x13779dd1, 0xac6ab61f, 0x890ce737, - 0xd4adafd9, 0xf48c7ec1, 0xb7c8e6ef, 0xe0217d8c, 0xc6ff276d, 0xffb18738, - 0x4733ceb5, 0xe17ec69d, 0xacd73adf, 0xa9a5859c, 0xcf5fe171, 0x9c2c4cfe, - 0x4f32a979, 0xfb15fe81, 0xeca9ad85, 0x7a4fe22f, 0xf0c13f3c, 0xcf51ca7f, - 0x9cf522b9, 0x585f4943, 0x673d6d70, 0xff2d7bac, 0x78d758cf, 0xde54ea1f, - 0xf7bf78df, 0x7fc4aeb9, 0x27e71bbe, 0xae9e79c5, 0x5cfe7fc4, 0x9a19fcf4, - 0x7940e35e, 0x278a0e3e, 0xa93f7840, 0x959ae46b, 0x52d6f59c, 0x5fa1f65b, - 0xf670b723, 0xb52d40f9, 0x27833b53, 0xb9fe78ad, 0xf94eaa39, 0xea2fc307, - 0x0aa56717, 0x55f8e47f, 0x78e3aedd, 0x53b7407d, 0x88ff51dc, 0xaaf8a76e, - 0x28730bde, 0x370ef48e, 0xc438a7ad, 0xf62d879b, 0xfa154def, 0xdf7c857e, - 0xfea90f68, 0x857f0415, 0xf251e3ad, 0xe9bf2a49, 0x1c5f10b1, 0xbf2f7f27, - 0x5c77bfbf, 0xbf683a0b, 0x1d048fe3, 0x7e7d08be, 0x22defebd, 0xe20ca662, - 0xa917c553, 0x096c4a4f, 0x51fd48be, 0xf54574e6, 0x83ff93c7, 0x0f76cdef, - 0xae6f7a8c, 0x0f35159e, 0xf21cd8fd, 0x902c6a87, 0x353e91a3, 0xcfc87a25, - 0xefe3c58b, 0x0e3df9e5, 0x6051b927, 0x7f55d74e, 0x29e4fb1c, 0x7d8bf811, - 0xc4553dbe, 0x9ec88373, 0x52273ae3, 0x556b6e75, 0xd0e6709f, 0x887e267f, - 0xbaac63ed, 0x95c3d68c, 0x1e77c4dd, 0xba0ae9bb, 0xe3d2f0e0, 0x686ae7f3, - 0x4de33dff, 0xfb1c38ff, 0x215f1ec7, 0xfb4d53fa, 0xfadfb1b2, 0x7fa27df8, - 0xd9bc69a3, 0xb819ec83, 0xf9296e7f, 0x7fbee90b, 0x9b75fa27, 0xd4155b1d, - 0xa8099503, 0x4cd5b0d7, 0xf7a6140a, 0x2ddbc7c5, 0xc0915f68, 0x175e6cc8, - 0x156ec0d2, 0xc26574f1, 0x13d920d0, 0x13abd8ad, 0x0c132ade, 0x9264777a, - 0x09da879d, 0xdd9d7151, 0xfbe1ef82, 0x0bff3665, 0xc9c26f82, 0x87a5ea3a, - 0x200d960e, 0xea9138fe, 0xede43c64, 0x7d26ea9b, 0x21edf085, 0x01fffefb, - 0xf078e6be, 0x3ec59ad5, 0x2579f59d, 0x86f38f64, 0x3e947921, 0x3a6a15fa, - 0x21084f3f, 0xeebfb0ef, 0xb1fe5375, 0x90f165c6, 0xf2427eff, 0x35b6f5ef, - 0xdaa18f32, 0x29a91f05, 0xb17bf5a6, 0xcff25b7d, 0x6a2fb919, 0x910ba1be, - 0x33d9c03f, 0xe8815174, 0x6aa87f13, 0xe1f90f61, 0xe490ff3d, 0x83f9f8a1, - 0x183f8144, 0x8fd1f3d2, 0x777bf9f1, 0xf1b679e7, 0x65a78173, 0x0e9aecc1, - 0x06b38fec, 0xe3fca06f, 0x47ff34a1, 0xad3b8784, 0x87cc91c1, 0xb449f58e, - 0x8e05e28f, 0x0ff88c53, 0x32dd3ce3, 0x705c7fbc, 0x46c1fded, 0x64e96576, - 0x7f637781, 0xe88db1c4, 0xf124def1, 0xe10780dc, 0x303e26e8, 0x0785eae0, - 0x8f393886, 0xd4ff2200, 0x2e8be325, 0xa7ec8f5a, 0xdc7910ea, 0xff38983f, - 0x8ac24552, 0x4de77dfd, 0x791a0f1c, 0xfb1022e0, 0x49b53e4d, 0xf803e065, - 0x96a2513b, 0xcb5c695e, 0x7684fdf1, 0xf6fe262d, 0x2a9d3db2, 0xd5a9bfdf, - 0xf6a0e25f, 0x5379e8fd, 0x093f1c65, 0x59c52a82, 0xc6623b93, 0x467fe71b, - 0x18bd4feb, 0x4d293cfd, 0x3041c3da, 0xb24f3228, 0x974dc641, 0x10a7664f, - 0x2b186b1f, 0x8b0f48a8, 0xd4a4c2ae, 0xb0d33d3e, 0x4959e711, 0x2db8da9f, - 0x8fbceb38, 0x88dc69f6, 0xf49a3f0c, 0x435b9baa, 0xc2ce0aee, 0x623630bd, - 0x0617291f, 0x2fbf2f1e, 0x23ae38f0, 0xb0d397e7, 0x43356e6f, 0xc3c3ef50, - 0x0c2f8914, 0xbbfe38df, 0xf6c1d17c, 0x62db626b, 0xead9e495, 0x711e8136, - 0x113d04be, 0x6c7d08f4, 0xea8d49cf, 0xb59e92ab, 0xca7ed109, 0x924fb978, - 0x7ad45067, 0xd062bf86, 0xacea50f3, 0xc663f256, 0xdfb1563b, 0x3b293292, - 0x93a2fd6a, 0x042ef8d1, 0x63e2979f, 0x71c087cf, 0x5ab3c4c0, 0x29327f94, - 0x63f983bc, 0xcfd187d2, 0xee8f9ca7, 0xfcc9a697, 0xaedd2c56, 0xfb184f85, - 0x7fe969cb, 0xde5d3e3f, 0xcda67c68, 0x8667c689, 0x039f1a2f, 0x6be34596, - 0x1f1a3fa0, 0x898d5783, 0x7d61bf1a, 0xd87f5461, 0xcd44a70f, 0x198342cf, - 0x75be1fd9, 0x91fcd45e, 0xf545163b, 0x67753f47, 0xe0dcfcd4, 0xbcf1a88a, - 0x2efe6bdd, 0x368417fa, 0x3427cd44, 0xfe87be9b, 0x4bfe3637, 0x53ff7ed4, - 0xa18daff4, 0xe7d256ff, 0xa85e8813, 0xecfb0b37, 0xa425b919, 0x6f4d5d3f, - 0x9b79437c, 0xf9ceb140, 0xf03cc0aa, 0x2fd8e0d4, 0x7a429f54, 0xdaa2306e, - 0xd6a37a84, 0x1ec8ab04, 0x71326a3c, 0xf390d31e, 0x3f84d317, 0xc89a62f2, - 0x7b78197b, 0xd922ed1a, 0x43ea5541, 0x248efa73, 0x935453f2, 0xfec9da09, - 0x1fd61e69, 0xbe101ce7, 0x0755f719, 0x4ac5e701, 0x982d2792, 0xbea8fc88, - 0xa9fc72a9, 0x8e83f20e, 0xe4e6a4f6, 0x9f8453ce, 0x4e9b0e2b, 0xfaa6ab7c, - 0xf0df6403, 0xa1e7a19c, 0xdef39fbf, 0xf1495846, 0xe65fd196, 0xe699bf5e, - 0xe67bbb2f, 0x7b7f8a48, 0xacaddf9f, 0x43a08d2c, 0xc51739e4, 0xa40eabf1, - 0xd867fb09, 0xdc7ec313, 0x3a6bd569, 0x538c3ed0, 0xbb407d85, 0xf10d2071, - 0x88f281f1, 0x0169f859, 0xed1f9d33, 0xb827df2a, 0x80df21d0, 0xdd9f4a6d, - 0xe643bfd2, 0xda3b20fa, 0x00937d6f, 0xf74438a3, 0x1de33df0, 0x955dfe86, - 0xecbbf8cb, 0xf97f9e88, 0xaf02e1fe, 0x90f620f7, 0xe22ce70e, 0x17fc063c, - 0x42fe5ea5, 0xd24ee5ea, 0xebf911c7, 0x2676bb55, 0x2e7e7f91, 0xc6e3f847, - 0x3a49dff3, 0xe54d2eff, 0x9dddaff3, 0x047cfeb0, 0xae422ade, 0xe3557ea8, - 0xf991f5c0, 0x39c6b5cd, 0xe7468afc, 0xa8e52758, 0xf923b5a2, 0xfe7f604e, - 0xb75c34c3, 0x7b95d772, 0xa6fbd00e, 0x67614c9e, 0xd2dfbc03, 0x82e380f7, - 0x28817fa5, 0xcd33b6bf, 0xa67570cc, 0x09613889, 0xbbe44e36, 0xb803e825, - 0xda637da8, 0x7c3fe22c, 0xbfb0561e, 0xa4cc15a0, 0xb3fa16bf, 0x33f484cc, - 0x3f6779e0, 0x69cfed1e, 0x1b73ef3a, 0xfb7ef8f8, 0x922a7bdd, 0xd6340fd8, - 0x8141d633, 0x3def3f20, 0x499cc057, 0x0ae99f79, 0x9fb817fb, 0xeefb9e8d, - 0xec99bc1e, 0xbbdfb1b0, 0x0ef4bfe0, 0xf022c5f2, 0xfac6baf0, 0x1134d740, - 0x4b03f97a, 0x44ed1d2f, 0xa66d0dbf, 0x3685e530, 0xbdf2b39c, 0xcf75774a, - 0x9c230fcb, 0x66f9af1f, 0x7f7082bf, 0xbfe7bcb4, 0x3bf3e00e, 0x4741529e, - 0xfdd9f1be, 0xbc447a5a, 0x2bfeee79, 0xafe86f2c, 0x2924ff3c, 0x1eac97a5, - 0xd60f9392, 0x322a34bc, 0x9f4e485e, 0xf74e9099, 0xe2d2933b, 0xc6c46fde, - 0x3f886ba5, 0xf6757e59, 0x5cbe0d4b, 0xc372f92d, 0xf9f9a30b, 0xf3dea486, - 0x2af3fe88, 0x3436c1e7, 0xf1af395b, 0x3587e48e, 0x31337e2f, 0x8f57cf32, - 0xa95ba97c, 0xf74b7275, 0x09fa3aa6, 0x1e5e4efb, 0xeaab71cb, 0x1e73a2cf, - 0x3269fabe, 0xf9bdf7f5, 0x6e079f2d, 0xbbf83ebb, 0x78917911, 0x79ea4aae, - 0xc54af497, 0xf94eab01, 0xb90392ac, 0x7ec2ee27, 0x1fea2b65, 0x5725cf3c, - 0x29a7b1c7, 0x00a83b1e, 0xc32ab7e5, 0x2be4ac09, 0xe520941b, 0xee34d6c3, - 0xfb1832dd, 0x1616ea6b, 0x2556bb11, 0x59567d0b, 0xb13704af, 0xe9873e1f, - 0xa365285c, 0xbfee50e4, 0xd778e3e5, 0x85feb171, 0x3cf6b08d, 0xf55d9dc6, - 0x38205e5f, 0x395a35d6, 0x292176cf, 0xfb8c196c, 0x84abda5e, 0xdc9f7a02, - 0x1c44b976, 0x98f42ab6, 0xf55df685, 0xe411c2dc, 0x381d7636, 0xb93d216d, - 0x59b1e1aa, 0x309179f2, 0x8b9641ff, 0x9595bbb5, 0xd5ac7991, 0xa4420ee8, - 0x02f842fd, 0x40eafb13, 0x2cfa494e, 0x435e1a6b, 0xb6bd42e8, 0xf58569ff, - 0x97e242da, 0xf9ef0e0f, 0xdf686fdd, 0x923dff83, 0x7d745ff1, 0x805f07f8, - 0xb94a8bfd, 0x633c5c0f, 0xb2b2f8a1, 0xde217cc1, 0xba6352fd, 0xcfda1eef, - 0xfd638f88, 0x10162dee, 0x10d93ff7, 0x82ec9e7c, 0x1cb2c7a3, 0x9a57f9e1, - 0xce68f080, 0xec0acb1e, 0xc8ce48db, 0xc11db85e, 0xbef57178, 0x84f18d74, - 0x78fac4b1, 0x3921a0f7, 0x5877a25e, 0xe9579f28, 0x5f10b4ee, 0x173f8657, - 0x9f8dfff7, 0x89c6f2cc, 0x574e5fb7, 0x273f33a4, 0x6437de4a, 0x30b9618c, - 0x90c3daf7, 0x60bee58d, 0xa9d90f45, 0x3b91070d, 0xbfb7a214, 0xec0ee087, - 0x7ce9d04f, 0x9f3e0725, 0xcfb111d8, 0xf47ca51f, 0xf95e59e6, 0xf099ac64, - 0xb193efb9, 0xf3df525a, 0xaac74cae, 0x97997978, 0xdedd85d3, 0x18bbec9c, - 0x9e09072d, 0xd95bee30, 0x147be764, 0x2d2d8394, 0x70729145, 0xc45daac7, - 0x07aa4de7, 0x1b2a0225, 0x79abfa17, 0xc887927e, 0x0cce36a3, 0x4eaa1f10, - 0xfc27f31f, 0x289bf715, 0xff508fef, 0x3ff74dcd, 0x39ac724d, 0x1e646560, - 0xf1d4d2a4, 0xe88516ab, 0xa26bc3ba, 0xf5810afd, 0x75f0ea96, 0x94553c70, - 0x7bdc53a9, 0x202cc274, 0x59bcfd3c, 0x39afbce1, 0x8b35bfd5, 0xe55c7be8, - 0x2fa396f9, 0xbbbee804, 0x11141c6b, 0x7f79c67c, 0x2a0c2e3e, 0x00b9b3ae, - 0xe6edb43c, 0xc4dd4b83, 0x38cf3fbf, 0xdd867ec6, 0x2bd20213, 0x503fe835, - 0x1f9ec7de, 0x093ad30a, 0x1522be39, 0xee9359f7, 0x58b4be64, 0x27ca1efd, - 0x36fb203d, 0xe08ab7cd, 0x8a27a5b3, 0xf5c87bf8, 0x48baf9e5, 0x6f74cdfe, - 0x4b7ce7e9, 0x69f05997, 0x71c00dd7, 0x4cfcd722, 0xe32f21a6, 0xb83b06cd, - 0xd6546aad, 0x44d7da46, 0x79e8dbf0, 0x1ea5c1d7, 0x2d9cdf82, 0x91333df9, - 0xff7622e5, 0xa99f888f, 0x62b4c0ce, 0x99e1166b, 0x9ff7a6f0, 0x7be4a1f7, - 0xf9a01f03, 0x115e4873, 0xfcbc6f54, 0xf8bd3f92, 0x7375d12c, 0x95c72faa, - 0xc2bcd7cf, 0xc6277629, 0xff9c3b95, 0x31b7c901, 0x89f095bf, 0xfcd16fef, - 0x51efc236, 0xc5b35f89, 0xfe593ba7, 0xdfed3a7d, 0xf141be7b, 0x3c8df7cf, - 0xff6c96df, 0xcfef9ef7, 0x54e67cf2, 0x2f5a37e4, 0x399e7819, 0xfe201839, - 0xa2824dab, 0xa8f8f84d, 0xe49b966b, 0x6f91cb6e, 0xd7bc9286, 0x40dc7926, - 0x9be6b179, 0x6fdc9196, 0xf3277419, 0xe42f17ff, 0xfb11aa16, 0x7f17a724, - 0x2f3be745, 0xe2c5b1cf, 0x7c73a1cf, 0x9c69cf2c, 0xefba496b, 0xf911e92f, - 0x7e921826, 0xd7b3fc5d, 0x7194d7b8, 0x61da479e, 0x8f38f38c, 0x5c890dd8, - 0xfa57b67f, 0x98f81ae1, 0xd1e0ec7f, 0xc2f2bfd9, 0xa92baa09, 0x36c13169, - 0xb5253e3a, 0x92fdee22, 0x0c119355, 0xb2186d7a, 0x8d3435d3, 0x39d89f3b, - 0x3ee116af, 0xf8550108, 0x0cf9d169, 0x255e2af0, 0xdaf18f32, 0x63cbeb9a, - 0x21afe33c, 0x63cd8d79, 0x969b0e4c, 0x23ae525b, 0xbcdaf19f, 0xd18cf9b8, - 0x5171d119, 0xc0ce8641, 0x7f047285, 0x4189c286, 0xf1833791, 0x26eabf94, - 0x9fe3855b, 0xde5999e3, 0x9b1cae95, 0x13e0ed0b, 0x3adb6c4f, 0x8470e50d, - 0x6bf503c0, 0xf1f5c988, 0xe6f507ec, 0xc31b5e47, 0x3dea387e, 0x4e02f395, - 0x1d0c4b09, 0x137fd08b, 0x2a27a541, 0xf63e12bf, 0xdbf1326d, 0x2dfd549e, - 0x9b4f4fa2, 0x092875ca, 0x15c5875a, 0x900eee47, 0xe076807f, 0x3e84339f, - 0x7b8a35b7, 0x65ee9b4b, 0x74e0993d, 0xe423538e, 0xd8432f24, 0x1f638aa5, - 0x2ca0b50c, 0x4c9d325d, 0xd7f5c7ce, 0xa64fafed, 0x73dade34, 0xd2a44f6f, - 0xff353b9f, 0xff3c0c82, 0x51aeca17, 0xb75bf236, 0x7e12c706, 0xae6ce142, - 0x20d02ccf, 0x87f615a0, 0x3c29eaa7, 0x9504ba14, 0x5b71a54f, 0x257e34d0, - 0x58555ff1, 0x30f6979c, 0x6dcc8aa3, 0xd5dfb854, 0xeb4a9358, 0x79b6fd55, - 0x97afe910, 0xf39f8432, 0xf13cd5e2, 0xcd1a06be, 0x25c33fbf, 0xa2682a99, - 0x324be37c, 0x5575d94f, 0xfec679e5, 0x55338d05, 0x7e41f227, 0xce11c778, - 0x7559368b, 0x73c26fa2, 0x94d1f020, 0xd5687ec0, 0x7640d9e1, 0x1e05dbaf, - 0x24f7c705, 0xfc447cf6, 0xd56cd3d0, 0xc1373ee9, 0x715203b9, 0x1eb23dfd, - 0xb619172c, 0xdcf7d1de, 0xe9a12fd8, 0x24439497, 0xe57be0be, 0x4c076d04, - 0x3be24477, 0xc959d849, 0xc3127b57, 0xe967ba26, 0x59efdf41, 0x4e0fab86, - 0x380d7de0, 0xec0ed973, 0xf85cf4b1, 0xe5c33a71, 0x05c83e24, 0x8d342701, - 0x26af49d6, 0x8e7cbd38, 0x09eea704, 0xaae1fd28, 0x208e8b1a, 0xa4a3cfca, - 0xc9f4a6cc, 0x5f625577, 0xb0b286df, 0xfca41b27, 0x9d2b6eb7, 0x8547d916, - 0xfdefa933, 0xf8e278ff, 0x9c21dab6, 0x48a80bff, 0x49b63b7f, 0x214e74a9, - 0xde122857, 0x0781428c, 0xdbb40baa, 0x7cef78c4, 0x2a4773e4, 0xe79e7fdb, - 0xf3ed3ab1, 0xf85e58b2, 0x0ff0d17e, 0x17c2521f, 0x76d2466e, 0xc94be63e, - 0x9a7573c7, 0x875c3c8e, 0x3cb8fef3, 0xfd8c2a34, 0x79ffab16, 0x3f57cfe2, - 0x80bdb15c, 0xb31eeff4, 0x4ff49ca7, 0xf671e047, 0xeb345fcb, 0x0ee422db, - 0x7264f486, 0x3ecc61dd, 0x3d36e755, 0xf776fe4e, 0xfba74541, 0xcf736ef4, - 0xb2bb8250, 0xd50b33e9, 0xfc1d5663, 0xb2ebfd84, 0xda5eff4c, 0x3563526f, - 0x864dcfd7, 0x873f5c1d, 0x20eb917a, 0x4fa16e43, 0xf51d9f2e, 0x1d04756c, - 0x06f293de, 0x6461fe3d, 0xbca49abf, 0x1c38a61e, 0x772dfddb, 0xf7f5a70c, - 0xf180fccb, 0x191c355e, 0x04df784c, 0x3c6b71af, 0x5c6a0eef, 0xaef79cbf, - 0xc46f5eed, 0xfe52d3fc, 0x56fdcb4f, 0x20dffa67, 0x7cb6d778, 0xc2d2a16a, - 0xa1a1f3aa, 0x3486f714, 0x4719c53d, 0x6fcaf48f, 0x69553c8c, 0x5f9a163d, - 0xaf581175, 0x536bbd20, 0xbd2f7e90, 0x396638db, 0x348fdf3e, 0x8b3b2149, - 0xe3d92af1, 0x60df66fd, 0xcefd5f9a, 0x8f4963d7, 0xf020241d, 0xaf375f7f, - 0x4378461d, 0x244e2ffe, 0xac0bdb39, 0xcd390cd7, 0xf7c53927, 0x8bff89f3, - 0x7acb9fa8, 0x7da58f79, 0x7ee5cb1e, 0x225c9013, 0x203cb3ff, 0xdfc93bff, - 0x3ca277cb, 0x59a3fbf0, 0x9bb4f7ce, 0xa337ecbc, 0xfdc91f5e, 0xdfd4c5e2, - 0x64ea5ed3, 0x843aa739, 0xf0d79242, 0x04275e11, 0x45f2d740, 0xfd22f80a, - 0x648cbcff, 0xf1242f71, 0xd8433939, 0x9e8e5083, 0xd873c1e2, 0x3e4a3555, - 0xe8a5ec22, 0x9a5a7b4b, 0xbf6d97f9, 0x26524698, 0xda5384ed, 0xd678ff49, - 0x6d28fffb, 0xa7d786d5, 0x73c3a82c, 0xf2a5386e, 0xf71961f8, 0x1c9f2585, - 0xb21af991, 0xa89a7a1b, 0x13e7a61f, 0xe5f54fb0, 0x4bebbd13, 0x9a4d1cc8, - 0xb528e3b3, 0x12a17c53, 0x2da6db72, 0x166a3f6b, 0xfc479e62, 0x6e6470d7, - 0x75e3d51e, 0x0242b39f, 0x6df0d882, 0x222f47cf, 0x8c3e1e1e, 0xa7638ff8, - 0x7fcc38f0, 0x060d7fe8, 0x6ef1ff77, 0x4091ea45, 0xc7e27cd2, 0xafb506ae, - 0x2254808f, 0xfddf5363, 0x007b7da4, 0x677fe76d, 0x2267077a, 0xf00ccf3e, - 0xfa7ddb73, 0xcb124cdb, 0x5c4567fd, 0xe6f160df, 0x6434ff11, 0x871ba863, - 0x2299ad4f, 0x856453ef, 0x379cf7b8, 0x18390a67, 0x0aed8015, 0x33aaebc7, - 0xd4bf7488, 0xe82d7aa0, 0xc0845d2f, 0x6fa4a992, 0x01f75e64, 0xfc5e3f90, - 0x283cfa45, 0xdf900fbb, 0xc1eb7682, 0x11d6c45f, 0x316fd978, 0xeb0058f2, - 0x2b5fc44d, 0x0ff8149b, 0x67aac5c4, 0x93afe7a2, 0x1babf275, 0x8c1b1d77, - 0x5cf35d74, 0x2df938cc, 0xe211ff7c, 0x5d5d7878, 0xcdc33d74, 0x197fd299, - 0x7fc9c30e, 0x3d62be41, 0xd5a0d661, 0x60ac7c8a, 0xf6224314, 0x0be04992, - 0x67cb2bf5, 0x8a6f61be, 0xb9ea5e85, 0x94a75c04, 0x94743bbb, 0xd4a681ea, - 0x8f687965, 0x9f189a29, 0xee2598d2, 0x4aa0b4a7, 0xbc930c75, 0x77ec59fe, - 0xa967bc07, 0xd49564de, 0x5fc4e097, 0xd3c8fbca, 0xddfe92af, 0x9d6c60ea, - 0x9553c0a8, 0x8219379c, 0xcaefb435, 0x69dea2dd, 0xf9e8eeed, 0xeb4f1255, - 0x8c7d3a9e, 0xa11585d2, 0xa7897198, 0x3a98c6aa, 0xdc38b116, 0xadef299f, - 0xf5fb7d64, 0xd1fc5bd6, 0xb78dfc2c, 0xf8c63ae5, 0xef914ce6, 0x1063c4ad, - 0xd505d77d, 0x2ad1f120, 0xfc2c9025, 0xc72c705e, 0xb067ddf3, 0xbdcfac81, - 0x3ee9e25f, 0x7e7c3fc9, 0x19e2bf7c, 0xfdc57df1, 0x7f868b3f, 0x832cf80d, - 0x0d83f9f1, 0xde50b03f, 0x56df9631, 0xffd999d5, 0x13f1235d, 0x7a6b5fcb, - 0x858767f9, 0x7f2c5bec, 0x6b95fa55, 0xf6fc2fc0, 0x0df85bff, 0xcb91af3a, - 0x398735ac, 0x09f6b53f, 0xabf943c5, 0xf7ab9d6b, 0x7f7cf23c, 0x359eb9ef, - 0xc6063de8, 0xa4e7bd30, 0x63bd175d, 0x96bdedfd, 0xe726bcde, 0x66b72f05, - 0xe0dd3e73, 0x6675d8ab, 0xf67dbf49, 0xbd7fc253, 0x276258d4, 0xa4fba3ff, - 0x9ce8a3c9, 0xc02e4caf, 0x566f8ff3, 0xee91fc81, 0x033be1a6, 0xa9e17f08, - 0x5f94c5a2, 0xed0a7f1f, 0xb707dd13, 0x0257fd16, 0xd27b07df, 0xb667ee48, - 0xbdfb488d, 0xfb61d783, 0x70b27dde, 0xe9e93967, 0xb445a593, 0x54e382ae, - 0xed285e9f, 0x42c9f554, 0xbd84477b, 0xc8a64dfa, 0xff716fcf, 0x1b8a51fe, - 0x7b35ef66, 0xdb323f28, 0x8094dfec, 0xa0be15f0, 0xb771aa78, 0x9e47ed63, - 0xbe5175a4, 0xf38acd28, 0x8d08e9fe, 0x1851ed57, 0xb2a6eefe, 0x3f643dbc, - 0xec87aa83, 0x7dd37762, 0x1f920ff9, 0xfe40fcd4, 0x1dfb117d, 0x66fa154b, - 0xb6660df6, 0xec839dd7, 0xbca72ebf, 0xeb1777a8, 0xfb43ce8d, 0xc37dfc2c, - 0x78dc051e, 0xa3ee63ce, 0x3a1e132f, 0x50b69c0f, 0x70d25010, 0x4711d2da, - 0x25ed1b7f, 0x9cc2f30c, 0xe161ddaf, 0x7ffdcdfa, 0x2b79d0b0, 0xf384fb9f, - 0x7e286b6f, 0x19ef3f20, 0x3a77bf95, 0x85aafcda, 0x4eb2b4f8, 0x91590181, - 0x271e66e3, 0xcffd4afd, 0x369e84ea, 0xe4857ff8, 0x0dff8377, 0xf5215879, - 0xe35b7dda, 0xffa1bbf3, 0x96ef041e, 0x03deb841, 0x0eb9cb75, 0xd11d81e9, - 0xfc5257f3, 0x17cd237a, 0xa9f2befc, 0xbdd5f1e8, 0xfd601e7c, 0xbf47ab1f, - 0x2e7ff433, 0x5f9f12e4, 0xa618af0e, 0x7d7d3ca1, 0x8830cd7a, 0x293caf93, - 0x6ec306fd, 0xd89b0e5f, 0xebcec5ee, 0x2162bc6a, 0xfad55b7b, 0x6773f627, - 0xf4c97d35, 0xe16a6f28, 0xc05bd97a, 0x79f08ebf, 0x49dd934b, 0x877976fe, - 0x9af303d0, 0x42a0c1ac, 0xa25aa1e3, 0xf161f773, 0x90e049bd, 0x4816fec2, - 0xe252b8bd, 0xe3c4a575, 0x06e38c4a, 0x8c8c7d53, 0xbc652be3, 0xd7673abe, - 0xa9292a31, 0xdaebe394, 0x1e13268e, 0x5bd081e7, 0x6f4242f3, 0xec31f419, - 0x40beac50, 0xd10f770b, 0x95936d77, 0x4be7d6eb, 0x0ebf35bd, 0x5fd296f5, - 0xb40f747f, 0x7ef1fc8b, 0xddac7701, 0x9e886cad, 0xfc201aef, 0x7fd2cbd8, - 0x4d101c2e, 0xb01ef297, 0x9e7f7e53, 0xfc827aae, 0xfb46bb56, 0x7e458eb7, - 0xf55bf5c3, 0xeaf129e1, 0x4df68cb5, 0xfd181719, 0xc3679405, 0x0ee721f9, - 0xffdc6447, 0x7f84039f, 0x1ab266b3, 0xc446ba20, 0xb30a0b49, 0x7349c6e2, - 0x8637f409, 0x71b3f7dc, 0x77927191, 0xb7e228d7, 0x2cef757f, 0xaaa6baa7, - 0xba2fa13a, 0x29bae126, 0xfb03f7e4, 0xd67555d1, 0x5533c520, 0x7dfc2fc8, - 0xc909f11a, 0x46529363, 0xc671827c, 0x42feb4ed, 0xf3c4eaba, 0xfb446c2f, - 0x2c2fcb8e, 0xabf992fd, 0x3738846d, 0xbc406de2, 0x3788c3b8, 0xbf0aaf2a, - 0xa95e78d6, 0x51dc7075, 0xb5ea24d9, 0x337c8e1b, 0xede10b34, 0xd0f3fe6e, - 0x3e4f54e5, 0x86e7d840, 0x54a7d0e2, 0x1ef5f457, 0xb5ff5c5b, 0xb52bff57, - 0xe6950f2c, 0x6bf64c8e, 0x791fa20e, 0xb7d1ea13, 0xa538e0bf, 0xbdc248e1, - 0x5aebcf94, 0xfce61fe1, 0xc3553a1e, 0x3783f626, 0xe4b72d41, 0x8dfa451f, - 0x4ea29d2b, 0x3f6941e9, 0xf208ffa9, 0x773883f5, 0xf97f6146, 0x8549f437, - 0x10d5ebe4, 0xe95532d8, 0xa42a07af, 0xdfcdacdc, 0xf6ae85b5, 0x0aa7fd63, - 0x31184f29, 0xf58cbdb0, 0x8633fe9f, 0x4edfab5f, 0xbbb8ff64, 0xae52754d, - 0xabfbf119, 0x6227e441, 0x271d905c, 0xe485fb5f, 0x7f794ecf, 0x65493d5c, - 0x8b2699fc, 0x10b7f0d6, 0xdd37cc8f, 0xb2411da7, 0x5f87796f, 0x583e26cd, - 0xdefa3bbb, 0xe7e8e889, 0xc8a0b1ba, 0x7cec8547, 0xbf8c6517, 0x31d5f874, - 0x6fd56fc4, 0xd04a3b7f, 0x96519be7, 0x67c36bf4, 0xe2228ab4, 0xe2229366, - 0x475afde6, 0x556bc532, 0x645f5507, 0xef41bf3d, 0x813ca597, 0xf503f226, - 0xabe67403, 0x1fc126ea, 0xe2d166a6, 0x7e444bfe, 0xf7fbccc8, 0xbe462f1b, - 0x067b1ef9, 0x40f21704, 0xf987b995, 0x89b4eaaf, 0x7d3aa9e1, 0xc4447339, - 0x775a017b, 0xeabfe900, 0xc4fac075, 0xe76fa40e, 0xd891f7d3, 0x027eff9f, - 0xb2c761fb, 0xfb8b97b7, 0x7f48152f, 0x9af6fc3d, 0x60f691d1, 0x2f7100e2, - 0x3707840e, 0x10bf3f79, 0x6c3c4bfb, 0xbf324582, 0xaf79f820, 0x2e309b8c, - 0x9c40737b, 0xfd7aecb8, 0x2b66eae9, 0xeab9fe50, 0x19d72b03, 0x92bcdd7d, - 0xeab87ee3, 0x06fa4d1f, 0xa91bfefc, 0xcaf0f87d, 0xebfcf4d1, 0xe46fabc3, - 0x29b2a97c, 0x2011cf2a, 0x5fe4dcf8, 0x5deef57d, 0x69b67fe4, 0xb6149fec, - 0xee977d9d, 0x9835f769, 0x8ad1dbf9, 0x067613fd, 0x2aafc892, 0x11df4f9c, - 0x98d56bed, 0x32dfd0ff, 0xfb3b2bfc, 0xd88aa757, 0x7c75c2bf, 0x4e8b6e41, - 0xa7bad394, 0x9a688b8a, 0xd7a4e382, 0xe57f93c6, 0x0cb7f3e8, 0xf8933e78, - 0xe0496eec, 0xd9028bbc, 0x4460cf82, 0x1aebdc14, 0x64ff675e, 0xf51aa35d, - 0xdef188fd, 0x7b88065f, 0x3e0cef87, 0xe65e290b, 0x5da2bda3, 0x932fb8d7, - 0x1cd6b1ce, 0xaea93e62, 0x3df18b33, 0x07ba05a2, 0x411fc09a, 0x273f0807, - 0x65d211e8, 0x8438259e, 0xbdbdfafc, 0x2eb28af7, 0xf5ea2824, 0xf3875a6a, - 0x5b974c77, 0xb3c7a5f7, 0x9ee92743, 0xe3be1d07, 0x8a1e2259, 0x5badff1d, - 0x9f8e41e4, 0xf8f1fa13, 0x78e8ff4c, 0xc500327a, 0x48a05f22, 0xef8835fa, - 0x35e763ed, 0xfe787ad3, 0xc70243dd, 0xf73b8f89, 0x63fdf026, 0x75e44ba7, - 0x34dbea4b, 0x6d661efa, 0xec813283, 0xf79cdad2, 0xec197bf8, 0x5c9e9117, - 0xf7c83e1b, 0x7b7515af, 0xc0e37967, 0xec2dddb1, 0x9df93cc3, 0x7cf8ec72, - 0x3c067e39, 0xdb9e3219, 0x673ef74e, 0xf14ecdca, 0xeef89bdd, 0xd7a956f5, - 0x6662df17, 0xe80cea3f, 0x227f7166, 0x481639ee, 0xd4ab7dbd, 0x63dfb1f7, - 0x76fdfa1b, 0x67c2ceb9, 0x73dd3360, 0x7d9f7ec4, 0x170ff4bb, 0xefd79781, - 0xf4bd5df7, 0xfeff6313, 0xea5b8942, 0x8a3051f5, 0xed087af4, 0xe45bd70d, - 0x9eddb026, 0xae32305f, 0xa9df41df, 0x753bf2eb, 0x57fa0d6a, 0xf6c7bee7, - 0xb9cb78f0, 0x86fbf997, 0x1d900973, 0xcfad9ee7, 0xe47a1a1e, 0x79774136, - 0x14e151ef, 0xbff41a30, 0x645a1184, 0xffa0cd7e, 0xff0e9283, 0x394575c7, - 0x63e645a0, 0x07fea90e, 0x475419dd, 0x38fec9dd, 0x21ed809e, 0x3ca86b9e, - 0x846b50d7, 0x7034bb9d, 0xee3e5c79, 0x406a5f3b, 0x6e7493d8, 0xecad725b, - 0x14845637, 0x22b0eefe, 0x9b7fa20c, 0x51caf9c2, 0xbf5c2d0d, 0xf154a4b1, - 0x3c5a8578, 0x7c19f04b, 0xfc26c0b4, 0x7a5f8303, 0x88f925f1, 0xb85fc9c6, - 0xb10bfa55, 0xda1a34fc, 0x4bfad167, 0xea878abd, 0x47c9af36, 0x4ebdc6cb, - 0xf8b5eee1, 0x4cd2f908, 0x9f96317a, 0x1ffb735e, 0xb775fc25, 0x80525e5f, - 0xfdcf1feb, 0x4ff1286c, 0xe8e435e5, 0xddbf4945, 0xae71c08e, 0x7597a963, - 0x8db9f504, 0x5697841d, 0xd3b2bf60, 0x8365bed5, 0x8eb9b7f0, 0xc09c22a0, - 0x4d15a5f5, 0xad6efe76, 0x713aa1a2, 0x26e3e90c, 0x7ec763d5, 0x52e9c379, - 0x179423ca, 0x2a973a89, 0xabbba8bb, 0xbbba8bb2, 0xe7fee9b9, 0xeff813dc, - 0x11d74403, 0xb57e3a58, 0x3ef87be1, 0x9335df56, 0x7fe1370f, 0x4b350f4e, - 0xbb686cfc, 0xc4863992, 0x887fdd34, 0xfd7eeee0, 0x8a7d0b45, 0xd5e63551, - 0xd6825459, 0xde79d6ec, 0xb52d752d, 0xe0365694, 0x429dbbb7, 0x43839aef, - 0xbfcd6fd8, 0xea9b7abe, 0x258c6f83, 0xd2d5d5fb, 0xc112d636, 0x501b9def, - 0x63a1c76f, 0x1ca49835, 0xca2adc6b, 0x0947e922, 0x3e6aaeb9, 0x8bf9499a, - 0x7ce7924e, 0x1e49df6a, 0xdec56d81, 0xc923c933, 0x5a2fd99f, 0x4d4bbd63, - 0xad03cf2a, 0x49edd463, 0x666df091, 0xc4852ef8, 0xa31d003a, 0x8e441716, - 0xd6bffcd7, 0x3e851707, 0x07d288e8, 0x16429e06, 0x0388efe0, 0xa75cad87, - 0xae3ff740, 0x036a3a08, 0xc26efd05, 0x76e48a60, 0x0f7bdd32, 0x834f9727, - 0x41afa9bb, 0xfba54b58, 0xea2ab0e9, 0xbeb086fb, 0xbff7289f, 0x50b70b49, - 0x7964f03d, 0xda053a5f, 0xe80cde79, 0x4e0bd6e1, 0x18ba0efe, 0xb24edc3c, - 0x5a53e785, 0xe2143f2b, 0x99c27bef, 0x4d82eb9a, 0x871d6f7e, 0xd3787dde, - 0x0f8182e0, 0x44d5ee95, 0x79ec533d, 0xfc28186e, 0x42bc9bbc, 0x414b910f, - 0x2093c0f5, 0xd3f9f7c4, 0xebde43a1, 0x54c73fc7, 0x1ee90b8c, 0x31ba3a6f, - 0x208f8c89, 0xe7469fcf, 0xa79de351, 0x19933e63, 0x9f049d4a, 0x7d34ce12, - 0x73febf67, 0x28355374, 0xebefbde5, 0x5171fae9, 0xa7a83ddf, 0xa9f78de9, - 0x7af1597e, 0x43d9beb9, 0xfc538ddf, 0x7b3ad613, 0xc03659f5, 0x722b8198, - 0xfbe84e06, 0xc0fc046e, 0xdfb12475, 0x277c448d, 0xfe231702, 0xe751922e, - 0x48b83bbb, 0x65913aa7, 0x7bfe36e9, 0xa1b6853b, 0x79af29e3, 0x339fcd28, - 0x7dea8330, 0x62f246eb, 0xfb02705a, 0xecbf92b9, 0x78449de0, 0xf7c6bc50, - 0xd37cc02b, 0x320bf7fb, 0xb227bf81, 0x3e77c55b, 0x6d1f91db, 0x3a052ca9, - 0x23c35fd5, 0xd3f93a25, 0x0f365c5b, 0x256c477d, 0x707dedb8, 0x1d44d8d7, - 0xd44d8d48, 0x72f51879, 0xb1ad78b1, 0x8f4e7919, 0x98f1fd8d, 0x627e90ef, - 0x7842dff3, 0x98a9287a, 0xde530eff, 0x5cdcd32b, 0x7fbf250f, 0xf03049aa, - 0xe7e36c50, 0xec94f57d, 0x3d52d667, 0x9359c237, 0x78ff5c01, 0x0a546934, - 0xb4d565d5, 0x9aee7a89, 0x77eb008c, 0x7d615fb3, 0xd25ad35f, 0xb2e2f64a, - 0xdd75c2c3, 0x07512e35, 0xd080c81f, 0x3d347af3, 0xa0f419a6, 0x8f594bfb, - 0x5c65d064, 0x7bd0943a, 0x91dec2e3, 0xdb429384, 0xfdd037cb, 0x7470b8c2, - 0x69d2197d, 0xf7a9d135, 0xc9cd1e3b, 0x7d061ef5, 0xd9987190, 0x06ee929d, - 0xdfc69cbd, 0x516af023, 0xa0c08f7f, 0x4144f6e3, 0xe055332f, 0x7577e70c, - 0x4e96375a, 0x14e11bff, 0x4bb0bac1, 0x00004bb0 -}; - -static const u32 xsem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x93cbff00, 0x51f86065, 0xd2f9c08f, 0xbcde0c0c, - 0xc4b462a8, 0x0c0c5c0c, 0x0e5c4041, 0x7b401ac4, 0xdbe9016f, 0xcdce1c40, - 0xc40110c0, 0x1ff881fb, 0x6207ff10, 0x04d6200d, 0x79405fe2, 0x5b1ba845, - 0xda181898, 0x8803b880, 0x875880bb, 0x97418191, 0x93fb7891, 0xde181984, - 0x7af82389, 0xcd0c0c12, 0xfff3f452, 0x5631c360, 0x29efb5f4, 0x174e3ed0, - 0x19c73f04, 0x505c2498, 0xe0bb70d5, 0x4d078337, 0xcf8d179e, 0x9e7f4787, - 0x5cbf2a21, 0x4d3f950b, 0x23e18187, 0x2d0a9a92, 0xc7416efc, 0x0c0c468a, - 0xabc4464a, 0xca8c60df, 0xd081300f, 0xb1adf900, 0x0003a809, 0x00000000 -}; - -static const u32 xsem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c09, 0xf37df0f5, 0x66499996, - 0x0d909326, 0x8a027108, 0x081380a8, 0xc3b44069, 0x8e22a222, 0x260dc55b, - 0x1037d902, 0xfdaff0fd, 0x2d361032, 0x4682d0d6, 0xa0c0748b, 0x0d0482c1, - 0x00e02418, 0xd52ff82e, 0x5b7bbfd8, 0x16c34a0c, 0x7e1b8092, 0xce7fe5b5, - 0xef25f7b9, 0x6d80264d, 0xfdfb5fbf, 0xe6f169bf, 0x5ddf7bbc, 0x3dcf76ce, - 0x14fbdcf7, 0xf89628db, 0xe0cec663, 0x2cabd20f, 0xdd51b18c, 0xa0db6ce9, - 0x74fa87a1, 0x6559ffe7, 0x4287ead3, 0x6ed0ab1e, 0x9cfdd61e, 0x7e5485b1, - 0x386b8c40, 0xf4d31cbb, 0x8f0e1b10, 0x9616c96d, 0x6e7dd8cc, 0x0901bf46, - 0x912974be, 0x5615ceb1, 0x780cbaf7, 0x085c7aae, 0x20c8f7df, 0xf7c25077, - 0x1652c93c, 0xbaa23fe4, 0xbecc01d7, 0x6cb3233f, 0xe0da66c6, 0xc3fc0f6f, - 0x7cbea07a, 0x63106cac, 0x059969ea, 0x77ea7fa0, 0x3403a512, 0x00efc336, - 0x6c2df978, 0xfeeed0dc, 0xecfd13b9, 0xe8b78073, 0x5b7e89f9, 0x097f90c0, - 0xecffa893, 0x5faa4afb, 0xf2f16f6f, 0x073e6c5b, 0x8d941636, 0x7f963bcf, - 0x8be7c2e9, 0x7aa16e9b, 0xd82c5318, 0xc8b772cf, 0x635cfc4f, 0xbbfaee96, - 0x76a214f1, 0x04d3d874, 0x3188feed, 0xb6bfb5e9, 0xd543c032, 0x0563d556, - 0xaad84cbc, 0x700c7f86, 0x84295ae9, 0x9d9765b0, 0xfb4bc031, 0x9d870e6a, - 0x9fcb0f9a, 0xaa1805a8, 0xff36b728, 0xdbc40afc, 0xa3ad9956, 0xf784fc66, - 0x3bc71b56, 0x9e70e46b, 0x6ba5839d, 0xf7c74f77, 0xccad1a0b, 0x6e95f50e, - 0x057a9fcf, 0x54fbf9c0, 0xd74a4586, 0x01fad02f, 0xea92185c, 0xcf18ee11, - 0x36e0fda8, 0xca1eb439, 0x939ab877, 0x1ff1836f, 0xcf31b4ab, 0x676fd0c5, - 0x80adf273, 0x96d0a287, 0xd15ef849, 0x2c8bc946, 0xfaeb6134, 0x7bc2fb37, - 0xaf241ba5, 0x5c52f015, 0x433ccb17, 0xc0ce1f78, 0x3906d6bf, 0x9fc863fc, - 0x1964e30b, 0x49ead748, 0x57f6c64c, 0x37671e68, 0x0e558e9e, 0x376b1e61, - 0xda01ba5c, 0x5ecaf781, 0xc438bc94, 0x200b0b32, 0xb76fb65f, 0x81d67b4f, - 0x0da05be3, 0x96b8e276, 0x3f2e586a, 0xeecdbb94, 0xd5adfec1, 0xd17e4126, - 0x9e5ab5ea, 0x75c5fe81, 0xcd8f3197, 0x419aafd0, 0x88fe4629, 0x9b018f4c, - 0xc453fb18, 0xf91eaf98, 0x37690944, 0x9fa2e419, 0x2ef44f14, 0xf54d93ae, - 0x4b192603, 0x007eff82, 0x82be027f, 0x57849d3b, 0x05736e9d, 0x3b74e91f, - 0x2987e425, 0xfac6d99d, 0x48e7f4f5, 0x754fe807, 0x5fd29ba5, 0xba52a654, - 0xf443d2b2, 0x07f10279, 0x6fd172e9, 0x4e3658d7, 0x3e5d7681, 0x4b3146e6, - 0xa71be298, 0xe7e09c02, 0x01ddf270, 0xf19673c9, 0x6a13e9eb, 0x72651720, - 0x53e49b15, 0x05ac02fa, 0xb42f30e6, 0x9be8dcaf, 0xd7b19a38, 0x1c71e059, - 0x502922ff, 0xac657480, 0x740fd53e, 0x1e812259, 0xc52d7c01, 0x961e0241, - 0x067e05f4, 0x4f713d3a, 0x24b2b3f6, 0x70889ac6, 0x668f73de, 0x54353d50, - 0x0cf50a8f, 0xc93d773a, 0xf54c73d3, 0xd02f4f24, 0xf54b59eb, 0x9eafcfd8, - 0x318fa627, 0x917a67f7, 0x580bcf5e, 0xfcf3916e, 0x633c95c6, 0x333fb9ac, - 0x949ea84a, 0x002cbdbb, 0x7f9d65e5, 0x864fb358, 0xf8c6c77c, 0x23328f11, - 0x86df8d1f, 0xaa4139f5, 0x97147c8c, 0xa7926313, 0x09825f78, 0x9fb933ee, - 0x7f927ca9, 0x653f29a0, 0x7c11a5da, 0x5eb770e9, 0x54e86026, 0xfea35e38, - 0xd234fd6a, 0xd9fae33b, 0x9fa07e08, 0x03cef483, 0xbb170263, 0x57d8dfa1, - 0x407ff406, 0x8eee5c0b, 0x2e3037c2, 0xea62a589, 0x991a60b1, 0x78e554bf, - 0xfbffdf1b, 0xfde107c1, 0xe0e74b72, 0x4bff8078, 0x8e21f71a, 0x4ca88ffb, - 0x32316e81, 0x3172c0ab, 0x6ffa4656, 0xb3f64669, 0x975e0341, 0x917e000d, - 0xa65debba, 0x1f915206, 0x4115825b, 0x3025cfe4, 0x8c7eb041, 0xe115641d, - 0xfef085e0, 0xc454bc80, 0xfd0355bf, 0x835f6c61, 0xfb5287f6, 0x5b7ed8ad, - 0x075bed2f, 0xb7da98e6, 0xda9817a5, 0x3ed069b7, 0x706747c8, 0xf01f68be, - 0x93b18637, 0x6fb53e6c, 0xf6a02f4d, 0xc0ac6a97, 0x574c7ed4, 0xbb60dffb, - 0x49fb63df, 0x703fc651, 0xe9fc798c, 0x6bf1e645, 0x416cfc7c, 0x431fb450, - 0x20a497e3, 0x117a7f1f, 0xd795bf1f, 0xabbed5db, 0x049aff0b, 0x5ea43aed, - 0xac683fc6, 0x9417fc79, 0xe56fc798, 0x2c17bbed, 0xa83bed13, 0x196978fd, - 0x2505ff1f, 0x0d66bed4, 0xb48f9178, 0x211531fe, 0x40d34f9c, 0x07485280, - 0x921d28fa, 0x93e818c0, 0x8481b2df, 0x38620787, 0x03137ddf, 0xd6e8e6fc, - 0x12042ca7, 0x9970f308, 0x8de2e9e0, 0x3f3e34e3, 0x9f5e6907, 0xab3aba2d, - 0x8cf9a651, 0x2e86b4ad, 0x37b6fe82, 0x678441ca, 0x2432bcad, 0x760a7cd3, - 0xb0a7be02, 0xf3ff3e30, 0x8ceb61aa, 0x674c8ae3, 0x2dadab57, 0xd2eab906, - 0x90d9e3ef, 0x055fe80a, 0x6ea8c132, 0x34f415b8, 0x39fc3d03, 0x0f4c63e8, - 0x392edcab, 0x5d9c7a04, 0x059b946c, 0xb2092edc, 0xff4087f7, 0xdffa227f, - 0xb77c70aa, 0x884293ce, 0xcc566fff, 0xcd9f50d1, 0xa4058eae, 0x5ca3f777, - 0xbb73a9d0, 0x14f64435, 0x9f88074c, 0x191449db, 0x1baed3fb, 0x305c94de, - 0x31f4d63f, 0x0b3777bd, 0xf2854e2d, 0x0ee79733, 0xeff8c370, 0x211d669a, - 0x7cc4fce3, 0xc7242dfd, 0x8725bfac, 0x2b0d69b1, 0xdc00fed4, 0xbcfd4d3e, - 0x1dfef0c5, 0x577c3301, 0x576e1981, 0xed05aa43, 0xad894299, 0xa9ef7a85, - 0xedebe730, 0x3812964c, 0x3f7b455d, 0x85f41c01, 0x3a60f747, 0x89bb1f02, - 0xfcddd3ae, 0xe53fbd5d, 0x4c2ca90f, 0x124b71f3, 0x5127fa23, 0x8f9b80b9, - 0xd3bfb23b, 0x0fcf9b55, 0xa0fe99fd, 0xec8cf84c, 0x58aecb7f, 0xd9ec059f, - 0x552f9a96, 0xf1c8c164, 0xc67ff644, 0xb8f1c8fc, 0x721f9c35, 0x39cf9183, - 0x53f2449f, 0x5fb8e379, 0x53f0321e, 0xbfb5fd69, 0xaf78643c, 0x1326eeb8, - 0xc3ba185c, 0x26bf3e54, 0xbb3f94d7, 0x3f94d0ba, 0x131cd973, 0xd07c1b9c, - 0xfcc67e54, 0x7bfca605, 0xe5311e2a, 0xc2b055df, 0x7811df04, 0xf6fe54ca, - 0xf94d6b69, 0xdc975d96, 0xf5547288, 0xde70cc81, 0xfad1daf8, 0xbf37b473, - 0xa45e2876, 0x57b011c7, 0x818e0e50, 0x7b6982bd, 0xabb248e3, 0x31e60f41, - 0x4b56a130, 0xc6cb83fb, 0xa4665ea2, 0xefd2433f, 0xc634c183, 0x843c979e, - 0x6346b93f, 0x89616061, 0x71f17425, 0x6fc86ca7, 0x0d7e4739, 0x9ec8fa08, - 0xf44b72f9, 0x72ebe5e7, 0xd3bd402f, 0x5f803e9b, 0x3ae79c7f, 0x99103d84, - 0xbf31225f, 0x7ebeb9f1, 0x7ae25cba, 0x53ac44be, 0x3bea5e4a, 0x0e10b99e, - 0x5b38ae0f, 0x5480f57b, 0xfd6893d4, 0x803f2127, 0x51e81814, 0x24c8375c, - 0x65bb6ddf, 0xea1957ea, 0x99abd004, 0x4257bfcc, 0x9bde133d, 0xec30cb7e, - 0xd475ef87, 0x8931acfb, 0xcab6f5e6, 0xa43cbfc9, 0x94fc7d22, 0x469ca91e, - 0x80656b69, 0x059543d2, 0x595e7e94, 0xe54b6941, 0x540f4a7c, 0x63fd2906, - 0x3f4a32e5, 0xf4a6acad, 0x4a1acae3, 0x510cac3f, 0xa3e95eda, 0x2e879754, - 0xf617ebfd, 0xc0b758b0, 0x8b0f6e03, 0xb2822cb1, 0xdee724cd, 0x53f39454, - 0xa3066f8e, 0x63ea7fbd, 0xde8ca260, 0x6fc915f1, 0x47d1d3bd, 0x085e4af6, - 0xcf4fa798, 0xa70c7b7c, 0x26c2dd93, 0x8f47d033, 0xf79cf45c, 0x2b04a1de, - 0xa9c032c8, 0x519c9bde, 0x0fb985ea, 0x3a2e75e9, 0x70e75f31, 0x3eb7675c, - 0xac6c97fd, 0x206972f7, 0xcaf7879f, 0xf0b30f34, 0xd7a45eb3, 0xf49bc50f, - 0x5bd29fda, 0x2e89dca0, 0x33a735fc, 0x6e48e748, 0x8354ffaa, 0xc7882995, - 0x2e10d8a6, 0x7bed4f8d, 0x38f285d6, 0x3eae5537, 0x7c77b234, 0x5467d695, - 0x29e30c3b, 0xa7c3346f, 0xdcc9a5aa, 0xbb89e07f, 0x95f21875, 0x45d0fabb, - 0x4a54ff48, 0xa6e67af5, 0xb1ced46a, 0x7c7141ba, 0x79f10efe, 0xf13c6370, - 0xa93bac2b, 0x3fbb3ffc, 0xf7a3d5bd, 0xf606b187, 0x01f50d85, 0xf73a0de4, - 0xdd07a8fa, 0x3f34af95, 0xfd49abd2, 0x1885ed06, 0x206677f8, 0xac10abd6, - 0x2f5e5bd7, 0xe397ad07, 0xf6a68df3, 0xbe8f3de0, 0x7af7c7a6, 0xb5855be7, - 0x7d04e3ea, 0xe7f0a575, 0xabd9d714, 0xbc4af3cd, 0xec6f2e09, 0x679a6d5b, - 0x7f900ff0, 0xc8292156, 0x9b82253f, 0x32c7143a, 0x6a97fa09, 0xe5bd50f1, - 0x6a572f12, 0x1e02d16b, 0xb466c762, 0xd1cdee33, 0xfb73cff9, 0x1fdf401f, - 0x1ecaadfd, 0xd7e17cc5, 0xb06cf551, 0xe7e82d6f, 0x0dbdd011, 0xef5053c5, - 0x3d76dd1d, 0x98b327d9, 0xa48b85df, 0x8d9d5602, 0x6609ce76, 0x7ffc8c99, - 0x35defd82, 0xc8deb0d2, 0x9fd468b7, 0xf3cccb99, 0x2667d82c, 0x0cc6bf38, - 0x939bb1e7, 0x56f3df91, 0xa0b730aa, 0x6ff39a5c, 0xbe49b8b7, 0x12c559f2, - 0x3f08ef5a, 0xa66ebdd8, 0x2fb907f4, 0xec99e57d, 0x87e8a1dc, 0xf75bfae0, - 0x7026140f, 0x3128a53b, 0xff20f9a4, 0x3f91868b, 0xfbe182b9, 0xa7a825a1, - 0x5de64e82, 0xefd27acf, 0xb23ff687, 0xd27cfabf, 0xfa214fc3, 0xbe49d721, - 0xda759450, 0xd84916c3, 0x974a415b, 0x76eb718b, 0x5c044d6b, 0x47d7011b, - 0xbf377fc0, 0xbf133225, 0x35025aa5, 0x5fce2496, 0x4a482f68, 0x47f816a7, - 0x51ed4fea, 0xb53fed7f, 0x3fa834fe, 0xfd7f54db, 0x0bfeb53f, 0x29bff47b, - 0xafa5fd5a, 0x0416da6c, 0x79b4537d, 0x3cc18b95, 0x4ea95474, 0x4bdd02f6, - 0x21762fd6, 0x82511c1f, 0xa3e7e42e, 0x34727921, 0x22d2f87e, 0xe7cca2fc, - 0x855d7090, 0xc7fd427f, 0x54d9f85e, 0x59bee7b4, 0xbd69baaf, 0x5b0d6754, - 0x1acb4e41, 0xdfa0a70a, 0x1c83e017, 0x46527a5e, 0x9fccd1b8, 0x4aafcf45, - 0x701eff46, 0x844f588a, 0xab2a5ec9, 0x9c24f3fd, 0x2759ca87, 0x7be459c9, - 0x04e9fed8, 0x5ab98fd2, 0xe87ccf5c, 0xe5f9d927, 0x0de52f02, 0xbb293b3f, - 0x30f6bd30, 0x4cb013ea, 0x7c8f0ec8, 0x41d840af, 0xc4ce2c87, 0xb1425856, - 0xa11fb11f, 0xc2f1d4de, 0xaa0edc42, 0xf0e4f0da, 0xb6afd083, 0x24badfda, - 0x7974be03, 0xf33f553b, 0x7a7aafd7, 0x62edcbd7, 0x5efdd7bd, 0x34f3de88, - 0x89adfb0a, 0xd86a25a7, 0xc971f685, 0x841bd55a, 0x9e9b25c7, 0x5c69ee7d, - 0xf5627eaf, 0x17f5045e, 0xc3e37a6f, 0x6f170031, 0xf0a71351, 0xe4a43861, - 0xc394fa6e, 0xba23f9bf, 0xf2f451e9, 0x18679a1b, 0x4270fe7f, 0xb78a5d37, - 0xb0d8d6ec, 0x5098f89e, 0x716b5bbf, 0xfd4fa144, 0x676849c1, 0x56f86d55, - 0xd1e575c3, 0xc94b125d, 0xb5cf8288, 0x80bd906f, 0x0a7a2278, 0x2fd1757a, - 0xd0397ca2, 0x247af505, 0xbdcb22bd, 0x1465fa81, 0x93fd17af, 0xbe2fdfc0, - 0x4fec7e8a, 0x43c45ead, 0xb9f78bc1, 0x95873c70, 0xcfe7ce0a, 0x3f464e2c, - 0x4c1a817d, 0x9fca5376, 0x9fb9ac17, 0xbdff2ff8, 0xfaf993fb, 0x42d7d7d0, - 0x2fb05573, 0xeaf6738e, 0x799c68db, 0x587c402c, 0x0fec8cf0, 0xc2b5fa41, - 0x22896f26, 0x9732c527, 0x80ebc393, 0xc3ce30b8, 0xbf414eb8, 0xd0e5efee, - 0xcc8ff27a, 0xee0fa861, 0x6cf1fdd7, 0x8b5fc12e, 0xb27184fd, 0xdae75f45, - 0xbb5bfc4c, 0x74e919b4, 0x052f806c, 0x4ce56afd, 0x487c0a09, 0xf95ea067, - 0x3853abbd, 0xc947989d, 0x5d81ef16, 0x639f0130, 0x67d566f9, 0x8f7a6e1f, - 0x6ee8c99d, 0x1f689e7f, 0xf3831dfa, 0x5664e1f9, 0x7c651f50, 0x07aeb235, - 0xf0375e60, 0xb9de4199, 0xc23ed7fc, 0xff975de5, 0x31934dd0, 0xb9f7abff, - 0x387be11c, 0xc2bf425f, 0xfbbf9429, 0x83f48956, 0xc9a38595, 0xe42aad79, - 0xc91f9cdc, 0x457fd02f, 0x0df0338a, 0x744093b6, 0xde5abf20, 0xa8df784a, - 0x575db157, 0x39757acf, 0x20fa17ce, 0x707d064f, 0x603eb759, 0xe81eb9ab, - 0xf20aeedd, 0x7a1a9bf5, 0x5f9469ee, 0x07a0d790, 0xe3f557e5, 0xdc6f8ff8, - 0x209de1fb, 0x75ebc7b7, 0xd5eb35b9, 0x782db948, 0x7c84bd69, 0xc7b7291a, - 0x894ac00b, 0x3cf0b726, 0xb416dcaa, 0xaaf44bfc, 0x65c7c78e, 0xf5d55eb3, - 0x8cf86f64, 0xca9793d4, 0x127aa89e, 0xecb3ef7e, 0xf3a8fc9e, 0x457fcea1, - 0x80bd29bf, 0x9f3a09fc, 0xc5d87cea, 0xf61f3aa7, 0xf098cff0, 0x3b7f9918, - 0xc10c04f2, 0x7f255dbf, 0xdf134962, 0xdef7838f, 0xf8459fec, 0xc734d1f2, - 0x9fecdfaa, 0x11438468, 0x79447d70, 0x8fec045f, 0x80881f28, 0x4be54c2b, - 0x8c6af71a, 0x2a6c20f8, 0x2bff9d67, 0x759445f6, 0x950f3eac, 0x82d49c37, - 0x9d691fc8, 0x753fea1a, 0xe8a89821, 0x9329dc3f, 0x7003b0ff, 0xe9da04bc, - 0x0a1198d8, 0x6c591e82, 0x0ecdebe7, 0x012ba777, 0x1cf1c5d2, 0x96d24cee, - 0x9fd41ea0, 0x1fb9da77, 0xe9dfc3a4, 0x31f8378a, 0xa4c9360e, 0x6c425bc7, - 0x093f3472, 0xdf8434cc, 0x3e5bd616, 0xe0768ff7, 0x87b633be, 0xcf40cefb, - 0xfa4765ab, 0x56bf5c7c, 0x23605ecb, 0xedc16b36, 0x77a1742e, 0x71ba0d34, - 0xfd9f3c1a, 0x6db7ccb6, 0xafa53e82, 0x8471dd61, 0x2b189f05, 0x72de7ee1, - 0x4d999fe2, 0x6b321d7c, 0x28797479, 0x39e5ef12, 0x77a869e6, 0xb9f0fd61, - 0xd7ac0fd1, 0xe23ab053, 0x42f5d379, 0x3d69aa6e, 0xce6b5458, 0xd4f5880f, - 0xc9feba37, 0x7fa49964, 0xeb84a170, 0xafb7a17a, 0x38de8796, 0xb1d3e80d, - 0xbfb8664f, 0x2649aa7a, 0xc8da9cfa, 0x305953f7, 0x8cafe489, 0xd4be9275, - 0xf286d6f1, 0x7aef7175, 0x9feb6dac, 0x3e421fb2, 0xe187f6da, 0x6db482bf, - 0x778327db, 0x47cafc20, 0x3d607fe9, 0x65d84fcb, 0xc7733f27, 0x7ff1272e, - 0xa5dfcec7, 0x76f0843f, 0x3af7f92b, 0x1c3b7d76, 0xa163b1f9, 0x60f500b5, - 0x7ebe00c7, 0xedf9daaa, 0x7f9a16f0, 0x331d1117, 0x7de88d14, 0x072fe9aa, - 0x54e02e30, 0xed0a8c13, 0x24b15d8b, 0xdaafe55f, 0xb1d11fc9, 0x80ecdbf3, - 0x9e379fe3, 0xd3ffb132, 0x5ed364e1, 0x73c5fec2, 0x8ef979bf, 0xc02ecfd1, - 0xdd86f1fd, 0x9fc84cda, 0x875fdaf0, 0x78ed7ea3, 0xed4ddb89, 0xdc1acb6a, - 0x48ba18df, 0xbd02a85e, 0xfac851da, 0xd16fb631, 0x4728f1c4, 0x57f2f13d, - 0x2f9cb3f2, 0x7c28263e, 0x8feffb3d, 0xf5c7c90f, 0x9364339f, 0x1ddfdc70, - 0x89ea03f8, 0x4be2565d, 0xebc7bc7d, 0x733d9017, 0xfbdf71ae, 0x52dc6e3f, - 0xbdc67cf8, 0xff9cdfe0, 0xfa878aad, 0x3d072917, 0x03e77cf9, 0x7a726f04, - 0xc9e7bfa9, 0xa7ff6bef, 0xa025fdd1, 0xe3dcebbb, 0x4b3fff0e, 0x0ba7b7f7, - 0x3e31bbba, 0xbfb5fca0, 0xa87eff52, 0x37f96b9e, 0xe36f7ba7, 0xb7fdedd7, - 0x33f79e2c, 0x5664fca1, 0xe2c340ed, 0x6f3dd2da, 0x5bee4267, 0xb1e37b69, - 0xf623e3bf, 0x5e34f47b, 0xf1b6fee5, 0xed03efb8, 0xac4978b2, 0xab3af917, - 0xfa2fb0bf, 0x3b23cbcf, 0x63da7fa4, 0xc5304f64, 0x2bf712b3, 0xe99f4adf, - 0x360bd8a5, 0xc200e3e2, 0x6c052bee, 0x4afe6f5e, 0x4adc3e62, 0xfd7e9fed, - 0xd373b43e, 0x83b264d2, 0xf7fb2521, 0xfe64d775, 0xad3344bc, 0x98f5ae87, - 0x129347d7, 0x89a8ebcd, 0x19abbea2, 0x0ed5ffef, 0x3c021429, 0xcbf01f8c, - 0x8ea7f444, 0x126548bf, 0x605893c0, 0x263bae11, 0x9df5cc3a, 0x836c7dc0, - 0xc5eff1bf, 0x3c2ec4e3, 0x47e95c0e, 0xc9900e3c, 0x3c4e7aaf, 0x6f09bf62, - 0xc78c2199, 0xe3978a61, 0x4bd4a131, 0x1eb16a7e, 0x1da26ec7, 0x349638a3, - 0xb82b3ca3, 0xa078e69e, 0x9ebeb875, 0x4cdf0dee, 0xd115cfac, 0x257f8ea4, - 0xcdd9f64d, 0x5cfad1f5, 0xa50fcba7, 0x7fc74e87, 0xaac92e94, 0x8e692e99, - 0xebca0a39, 0x8c3f5c64, 0x1c99f2c4, 0xb42a0b4e, 0x0fd624df, 0x28e678d7, - 0xa4278041, 0xaf482a65, 0x22f6db7c, 0x79b51f8c, 0xc5c7ea25, 0x1f9a166d, - 0xe112596c, 0x428d487d, 0xf7167bf0, 0xd4f7a428, 0xfe395e2b, 0xbb3f4320, - 0xba06e34f, 0x7c97ef9f, 0xd8cce67f, 0xf0c7f46c, 0xde7fc61f, 0x59b7eb00, - 0x063859ab, 0x615b34f0, 0xf404b8c1, 0x73ec4b93, 0x0cdc9f93, 0xe4aaefe3, - 0x55ce7aee, 0xf2bd37be, 0x015f4ecf, 0x45f9f63d, 0x94c76d8c, 0xc6288a6f, - 0x9a8ff6f5, 0xf7cabe38, 0x1e40d0b3, 0x0dfb2187, 0xab2f8afb, 0xcaf33fdc, - 0x891a5f1f, 0x1d71dceb, 0x7eb8e343, 0xa971e2cd, 0x8a70bd62, 0x0ebce279, - 0xe283afd4, 0x9f74bf68, 0xe7168cec, 0xbfac41b8, 0x28f1837f, 0xb2d47690, - 0x57d7196a, 0xbefc93ac, 0x5b1b5ac1, 0x661e251f, 0x7e116a8d, 0xf8374122, - 0x7fb8d9c9, 0x0d9fdbc3, 0xe919c6af, 0xa8e536d6, 0x1d27bc32, 0x61b9f7f0, - 0xc51feaff, 0x11f7ae2f, 0x2dec1bbf, 0xf451fc93, 0xdfc0bd47, 0x91df3dd4, - 0xa6d2f49f, 0xdfe416b5, 0xa62d6b4b, 0x553ad8fd, 0xb04631f8, 0xa9afd811, - 0x2cceec7b, 0xd93ecba4, 0xe5a5f18b, 0x40b5274d, 0x48c47d94, 0xe8fd627c, - 0xdd556f7f, 0xb50eeed4, 0x75e2267e, 0xc31b09c7, 0xad76f575, 0x3f5a38ba, - 0x7ef2b4ef, 0xf7f566ce, 0xf7f8cf0d, 0x0eb8efc3, 0xae3c7847, 0xf0996b3f, - 0x1ff24483, 0x553e3e23, 0xbf3842c7, 0xf5157ae2, 0x8c8da9c2, 0xc94077e6, - 0x06feb863, 0xd1b1ff79, 0xe37173af, 0x5da0df96, 0xb924d650, 0x4ca24b71, - 0x8fd0d169, 0x2f18de5b, 0xe99c3ce3, 0xdd6fe3d1, 0xc8356ec3, 0x10aaab45, - 0xd98ef6be, 0xfbb61771, 0xd0c69b65, 0xdebdf14e, 0xfc79c2e9, 0x2491a6cb, - 0xeb8dbd07, 0x34564ae5, 0x841ce311, 0x87e48c3e, 0x4c631ba1, 0xa07215f0, - 0x54d7ca1f, 0x6f3ccb6b, 0xd32dfa14, 0x788fb124, 0xf42dfa9e, 0x7b7e99ff, - 0x016fd75f, 0x23906fd9, 0x419bc0bf, 0xd344a5bf, 0x4f25736f, 0xee7de20a, - 0x482941ce, 0xab6fb9d7, 0xdbf4d149, 0x2fbe4aa6, 0x4dc459ba, 0x7e803477, - 0xdfa0dcbb, 0x45bf401a, 0xa3191f89, 0x73fa7ee9, 0xbfd0b7e8, 0xa136fe46, - 0xde328b7e, 0x74fe041b, 0xe9bc36fd, 0xe1b7e920, 0x3c53160d, 0xf84d44f0, - 0x6fd57a9b, 0x68add252, 0xbd53ef1f, 0x67f851b1, 0x37c7b093, 0x6c46388b, - 0x955cf507, 0x5cf4c3f6, 0xb9eaf9de, 0x759e117f, 0x2b77373d, 0x9ee8b8a3, - 0xdcf5c87c, 0xe7a0eddc, 0xae47e424, 0x64eee6e7, 0xa1172fdc, 0xd0f486df, - 0x97ca8c6f, 0xe5fbf985, 0xde4f198d, 0xf08df50d, 0x941b5ea9, 0xefadd11f, - 0x5df51946, 0xbe8bd695, 0xfa7e77db, 0x77d0ab6e, 0xa206c7a0, 0x0fe48d7e, - 0xde39936f, 0xc3e8c77c, 0x79465f1b, 0xfb4c9df9, 0xf859ef92, 0xa33bd1fe, - 0x7f21670f, 0xf3fa2a7d, 0xd9e9c6a2, 0xfaa4195e, 0xc7cebc27, 0xfb91ba57, - 0xb81acbcb, 0x2b56587d, 0xe7f03c87, 0x69df31a4, 0x9dc2ffd8, 0xf8014b12, - 0x13f56b26, 0x9febb40e, 0x1f589957, 0xf034c94d, 0x629cacc3, 0xd957fbf2, - 0xfcf0eb5d, 0xd9852cd1, 0xec5fbfd0, 0xed147498, 0xbe1ce2e0, 0x9e2c501f, - 0xb3b071eb, 0x4464f4bb, 0x9ce3483c, 0x9eb3fb37, 0xad531671, 0x9f53ae9c, - 0xb7184295, 0x22ee33da, 0xb8a17a44, 0x5dfcfcce, 0xc9377f21, 0xf62f842d, - 0xee351cae, 0x85d72f43, 0x4f027da7, 0x9e131780, 0x3c545242, 0x64a7a501, - 0xa5e37726, 0x4b2d77f0, 0xf0a05f70, 0x91f68929, 0xe3adc723, 0x3afc722d, - 0x773f751e, 0xbf2fa8b1, 0x6b9d2d69, 0x8e8bc48a, 0x747c48e7, 0x1f023de1, - 0x7e5d69ef, 0xd71891ed, 0x7a437c04, 0x809ff826, 0x3fc76817, 0xf9d322ee, - 0x5e048f9b, 0x9b8f5646, 0x370fe180, 0xe43a1c61, 0x79ccd5e7, 0x63e02fb3, - 0x119ec7d4, 0x315e9d38, 0x7dc01ac6, 0x4ef60dda, 0x1f3a83d2, 0x3e72b30e, - 0xd95e84d4, 0x3c62afd1, 0x251bf3ad, 0xe521da37, 0xb5e13b61, 0x0ed1f81c, - 0xf53ef645, 0x578124cd, 0x6aaf9d37, 0xd013f314, 0x26eb82c1, 0xf10abe7d, - 0x9b2358f3, 0xebca5d38, 0x58b25d38, 0x94c7ed27, 0x30de48d5, 0x71aca78c, - 0xeba1c50e, 0x0e7e19fa, 0xf0a29d23, 0x7f8d12af, 0xb39b3a19, 0x62cde7bb, - 0xb5aa6e51, 0xe7dc43fa, 0xb1f20a99, 0xfe10d896, 0x3efe1677, 0x2450fc57, - 0x78132ebd, 0x757884db, 0xb93afe20, 0x8efe15fd, 0xf9e969ce, 0x84d04ae5, - 0x9f4f09d7, 0x53b7fce6, 0xac5fa0f2, 0xcfc86f0b, 0xc74a3f90, 0xd233f21b, - 0x465729a1, 0xddf00f38, 0x78e7a327, 0x28d4bf71, 0x0f3b85f7, 0x919ffaf2, - 0xb8ca2cbc, 0xff7f307f, 0x4deebe40, 0xc55987de, 0xf7f0413a, 0xfdcef63b, - 0x77bf9123, 0xd12fdc4a, 0xf7da6f14, 0xd7cac1bc, 0x20ec1b4d, 0xf6dfb807, - 0xe75deab6, 0xae1fa9e9, 0xc03972b2, 0xe0c784f5, 0x0704baf7, 0x75a6f182, - 0xa4178a36, 0xf6e40c7e, 0x6f5f51aa, 0x5ba4b3b2, 0x7faf7ab3, 0x37bfa88a, - 0x8787497b, 0x47a87b61, 0x21bda11b, 0xce45eddd, 0xe0ffba17, 0x43bae35c, - 0x3bdfcff0, 0x1f9dbd2e, 0xce554f1a, 0x4c5f699a, 0xb54aab8f, 0xd1515e04, - 0x992c9bbe, 0xe7a0b7e2, 0x70ffce82, 0xa36ab7fd, 0xa59faf7a, 0xd08ec8da, - 0x2d5ecbcf, 0xf010583b, 0x254fa5f6, 0xe32b0179, 0x7f38b183, 0x1079878c, - 0x8ff72f92, 0xca6ee8fa, 0xed9f6997, 0x29f5dfc6, 0x1bc87dc5, 0xbb1d0c79, - 0xfb225331, 0x6cac3de1, 0x36e1da34, 0x268ab3e6, 0x47e73f21, 0xd73c21f1, - 0x3d5b5992, 0x3d7203c1, 0x85542ea2, 0x674277a9, 0xaf483be2, 0x7a433271, - 0x4cfafb35, 0xbef7f9c0, 0xdc4cb33f, 0x813b078a, 0x8fb119ea, 0x31b96125, - 0xce5a24be, 0xeaf86e8c, 0x7fa05bfd, 0x5ecbf7a3, 0x69bb940f, 0x7281c3af, - 0x85b56436, 0x19780c05, 0xe85542c3, 0xc87d1a77, 0x83ea0b77, 0xf07bb002, - 0xd341497c, 0xc2172ada, 0xbf7a25ab, 0xe498183c, 0xaa6dfe82, 0x32e93939, - 0x0e500bd4, 0xcd5f29ab, 0x4ad795cb, 0xce710c5e, 0xf1415a6b, 0x12b57948, - 0x14dc601d, 0xd78d9892, 0xbd41b21b, 0xfbc3569b, 0xc17f3859, 0xed6f58fb, - 0x416ff7c9, 0xa4fd03bd, 0xfdf237f7, 0xcf783cfa, 0x3b527283, 0x5c2bea87, - 0x073c312d, 0xcf91b053, 0x55fb054f, 0xec37e62f, 0xdde68a7e, 0xdf5ed029, - 0xc28f9c0c, 0xd13ce913, 0xe74dc948, 0x80be1f38, 0x0e0756f4, 0xa5f05f18, - 0x4909f8f3, 0xa3fd62c0, 0x6dfd7fdb, 0x9e535cfc, 0x07d68177, 0x272779ea, - 0xfc42c329, 0xe1f69274, 0x03be010f, 0x79379c56, 0x9cdecb3c, 0xc316b42f, - 0x1b6398fc, 0x6acfef44, 0x1e71471c, 0xe29f99b3, 0xe68ea63c, 0x57bbe776, - 0xefe843da, 0x4ced577b, 0xaf7be7c3, 0xf6f3d2b4, 0xb70f5c4d, 0xbf21680f, - 0x2ad5e1fb, 0x552ff3c3, 0x13d265ab, 0x74aa3787, 0x867e576e, 0x6fe437c7, - 0xdec876e2, 0xc3debcd5, 0x9b7edc75, 0x936dccf0, 0x5fce1e70, 0xeaf9cfcf, - 0x875f5a7a, 0x4d0bb9e6, 0x9ea45bf3, 0xa970f5d5, 0xf54147c0, 0x8f4fda5a, - 0xfaa5bbd4, 0x6fa1187c, 0x9d9f714b, 0x24c3d3f6, 0x91f5a547, 0x6e8e65f1, - 0x43f20dbf, 0xefe23bf8, 0xc32afdb2, 0x45f48d75, 0x678a24db, 0xf21ef9c3, - 0x3e493747, 0xf8287b8c, 0x7b221ad8, 0xe33b943c, 0xf99e703f, 0xc8f0cac4, - 0x03d22b48, 0xb58e54f4, 0x84bf8ff3, 0xb3df47e7, 0xf010e461, 0x5fe12e4f, - 0x5ace138f, 0xb27ee3cf, 0x8c995bde, 0xc4d98de7, 0xf207a43e, 0x3016646b, - 0x92a38de8, 0xf93b96ef, 0xfb46e0fc, 0x966ba747, 0xf3879d56, 0xeb8d916c, - 0x957acf47, 0x0bc78bce, 0x3e0bd618, 0xb70a77b4, 0x0cd648af, 0x73b850fc, - 0x0ea83245, 0xcbc444b6, 0xe6738954, 0xa76f1a85, 0x5ee49770, 0xaf47686b, - 0xdb57af47, 0xb41bdfce, 0xd5bda793, 0xa3fd885f, 0xa1ad7e71, 0xa7ac88de, - 0xd4bdfb47, 0xa75ff393, 0xffb9e257, 0x0a65779c, 0x62f9cf76, 0x3ee320ca, - 0x7eea9e8f, 0x2df7ece6, 0x5fc067cc, 0x98631fce, 0x86ef40cf, 0x40ff2051, - 0xb91a1bbf, 0xea30d73d, 0x459a56a0, 0xbde51bb0, 0xcba3f84c, 0xbbfdf226, - 0x16f7cc86, 0xc94ffca1, 0x581f8892, 0x49f5a030, 0x83cdfb24, 0x59f900fb, - 0x787cfdfc, 0xe1b2e51f, 0xa0a72e29, 0x4fa83c2f, 0x98af56ca, 0x256be544, - 0xb0dfd60f, 0x92ec9736, 0x51991c82, 0xb241ed7e, 0x0f1a0a93, 0x833ca226, - 0x7b44aefc, 0xd5ac6ca0, 0x9758ea8d, 0xdfce5d4b, 0x9961e715, 0xcf0c3dcd, - 0x5876e077, 0xf796f934, 0x72b76133, 0xe1cf2cb9, 0x26eefb72, 0x3e784715, - 0xad724e72, 0x728cb1cb, 0xc72dd59c, 0xd04f577b, 0x870fae50, 0x99a38a24, - 0xe5007a80, 0xe71e837c, 0xf3d8edc4, 0xd973f395, 0xbf20a599, 0x72ea5f38, - 0xa475cbae, 0x2d2b373c, 0xee3f62b7, 0xe34ed2bb, 0xf6d57098, 0xfae3ef0f, - 0x275ff68a, 0x3260f55c, 0x853cc7ea, 0x78e979c7, 0x5c78552d, 0xad7e8f60, - 0x3df5a05c, 0xf445fe9f, 0xd9ab33e3, 0x8b6f125f, 0xb5eff1e7, 0xb9fdf12a, - 0x9c87b3e4, 0x9e7ca79d, 0x4b9d5caf, 0xe5f6f53e, 0xe27ae69d, 0xf5476991, - 0xf01dafac, 0xbe3c0618, 0x8a59f1b5, 0xc2f13e0f, 0x8748a9c1, 0xe7c01de2, - 0x9d1b5fc8, 0x4e7a8c2c, 0x55bcd109, 0x39d320d4, 0xb384a603, 0xe51a716f, - 0x1575c798, 0x3f12766f, 0x0d64bd15, 0x8bf7814d, 0x9c317db6, 0x76166ae2, - 0xf05adc52, 0x072f6105, 0x1ca3865b, 0xbe3c2914, 0xfc2f522c, 0xe7edc6da, - 0xd3b1edb6, 0x1d527c70, 0xa8a2dfbf, 0x6ad576fe, 0xc278a7d8, 0x50bb52a6, - 0x8379f68e, 0xfe78c7c0, 0xbc67fb17, 0x2b8f4157, 0xf5c0db6b, 0x1aa35144, - 0x8a327bc2, 0x63b4b6ea, 0xc7d171bc, 0x957ff256, 0xf3a49dd7, 0x6f361314, - 0x794aff22, 0x8fda6ca3, 0x59df11eb, 0x18ad8727, 0x4a50d897, 0x1f0090fb, - 0xc45eb824, 0xf8c0fe53, 0x3bcde2c3, 0x850105b7, 0xef3f2fc5, 0xac72fd42, - 0xf10bbd79, 0x359ef50e, 0x3c47bade, 0x2223fd67, 0xc386f39e, 0x2f4b6f74, - 0xf0c79cf1, 0xb794100f, 0x4e78e66d, 0xec87d756, 0xb667e84b, 0x47feca3f, - 0xe9be7d97, 0x1e7835eb, 0xe3a5eda1, 0x25dfb06b, 0x0d72fb7f, 0x5db189c6, - 0xcaf79a76, 0xe280f85f, 0xbef7f5b7, 0xc87f09b0, 0xfe29e786, 0xab13fdbd, - 0xdf6b6b17, 0xe31d3879, 0x7cb7db06, 0xccfe8c97, 0x26af3b79, 0xadbcef7f, - 0x94585213, 0x914f4379, 0x11e7437f, 0xb7491f7f, 0x297b0dbd, 0xd004ed9e, - 0x5760f51d, 0x297d6e9c, 0x88f67f8f, 0xd18ddcf8, 0x88f43bcf, 0xe5b86dc7, - 0xff512bc6, 0xf27b7037, 0xefb9719c, 0x3f2f3d03, 0x146e3a0f, 0x37f5d7f1, - 0xf72e359c, 0xf401fe04, 0x74cdd8b2, 0xf661bafc, 0xbcc69faf, 0xc6bd3e86, - 0x03cf86e5, 0x8a79fa7f, 0xa73e6c77, 0xa5e8e51d, 0x343c50df, 0x078a6fd2, - 0xd3afa3e7, 0x11ca3cf1, 0xce3a73b5, 0xad3b9d3f, 0xd14fdf74, 0x9e488fce, - 0x47beb7da, 0xce266a7e, 0xaeb3b435, 0x973f8f1f, 0x9d6b78c4, 0xd0579e3c, - 0x3d7de301, 0xe22e7a2e, 0xeb5f397a, 0xc5bdbef1, 0x1f6d5ef9, 0xe00fee28, - 0xb5a5c8f1, 0xb3f1107f, 0x729374dd, 0xcf075e90, 0xe3ad471a, 0x72f42dc1, - 0xf47b1c77, 0x38aeeab8, 0x21ba08f6, 0xea9e713d, 0x3807538a, 0x49f9046d, - 0x2e768a3e, 0x8f2d7da2, 0xa3576f7f, 0xe3d6379f, 0xf4117dda, 0x9bdbc7d6, - 0x7b72e8bc, 0x50fc71ae, 0x4266d13c, 0xb57c4f52, 0xbf5d1f7d, 0x7f4bb4cf, - 0xebbefad7, 0x148954bc, 0x5eeb1e79, 0x86d2cbe4, 0xeccfe483, 0xf18b7f5a, - 0x7bff09b6, 0xc5320bdb, 0xdfa92f39, 0x523dfa4b, 0xbde1947f, 0x7bfa512d, - 0xe7d85dbf, 0x68fe7c8d, 0x7219c97b, 0x7b6d3d40, 0x975f13b6, 0x71483c6d, - 0xbdd66fd6, 0xe218b5ac, 0x08fe7027, 0xf6d3c619, 0xa4e1eee2, 0x30fdc5cf, - 0x8954ed91, 0xa29bca76, 0xf1be53b7, 0xe29da9a4, 0x76e6bd60, 0x63bdbb9c, - 0xac76ef8a, 0xb73358ef, 0xcbd58f13, 0xf6d14393, 0xd8aaec69, 0x29e6afef, - 0x0f74a3cc, 0x7bdf938e, 0xc862bb23, 0xcce79cee, 0x112e38f9, 0xbae28d53, - 0x388816aa, 0x537a9fb0, 0xce55de91, 0x77f618eb, 0xe0d7e231, 0x01dd51ff, - 0x9aaaf686, 0xbf42cfea, 0xd1dea443, 0x642c2d12, 0xe73cf7a0, 0xed0f14e4, - 0x90d3848b, 0x0f32079e, 0x67ef58ab, 0xcfabfe11, 0x0524b614, 0x5059f7fa, - 0x7a802ef2, 0x0c5ff7d9, 0xd67b3bf0, 0x8781c3af, 0xa9bf9365, 0x0079dacc, - 0x35ec2bd7, 0xc847ed3b, 0x7f74ecbb, 0x3b1af948, 0xd6ef778d, 0xbb239f6f, - 0xc656d7fb, 0x556087f7, 0xb996f783, 0xb7871d79, 0x2fe6bb7e, 0xcbe35768, - 0x1afe7ed0, 0x89eb8f28, 0xfeb4b18d, 0x8e2978e9, 0x7fcb51ee, 0xa8a9a1ed, - 0x3963f2d7, 0x4e6fe63f, 0x7d415509, 0x6e1c49ad, 0xee8034dd, 0xc97e28ab, - 0x7ba5f149, 0x8652beb7, 0xe6fb54f3, 0x60330c58, 0xfb09afed, 0x7ee237ff, - 0x63d51aad, 0x642f338c, 0x2e78c78a, 0x536118a8, 0x3f23135c, 0xfa11c906, - 0xe8e31ab1, 0xc5d8113c, 0xa84e7aa6, 0x89780f9d, 0xf8fd838f, 0x3f70aa39, - 0xe59107d4, 0x76fdfcf4, 0xdcbd8e7e, 0xba39ef0a, 0x9d6b97cb, 0xeeae1c79, - 0x3349f5c7, 0xe744ff95, 0xb3df9173, 0x23fe5e5e, 0x7aaedebd, 0xe265fbf8, - 0xfe489b7e, 0x57a5d43d, 0xb4717afe, 0xf4a25bfb, 0x2fdf9e9f, 0xed05a0b1, - 0xba762d96, 0x67ef0bb7, 0xdb0e73c0, 0x55ffbe34, 0xfdd30ae2, 0x3e843b39, - 0xd309892e, 0x44fd3e7d, 0xc23cb03f, 0x22f2d6cc, 0x15f4bdd2, 0xb3f8c33b, - 0x3e9cd7d2, 0xb6e977a4, 0x957f5b6f, 0xb18bf185, 0x7d2bd7e4, 0x1f117fed, - 0xd3c35a94, 0x2dbcfee9, 0xe7f78656, 0x3b796db5, 0x4db5e51d, 0x9c27a70d, - 0xb4af5f65, 0x57be6ade, 0x58e38c40, 0xbc42e865, 0xaf3f4177, 0x9e8bd45b, - 0xdb8632b9, 0x9f18f6d7, 0xdde48635, 0xb1d44f7c, 0xc641c6ca, 0x9e45fbf3, - 0x7fb17ae8, 0x9d8ffa8c, 0x38f47743, 0x263fdaf7, 0xe699ed09, 0x96407464, - 0xfa8e3d81, 0xe4eea8bc, 0x7c1ff430, 0x6fdfa316, 0xf9c389e0, 0x73ad33e8, - 0xcfbfea18, 0x19873bd2, 0x952399e7, 0x92a28f36, 0x8ed2875f, 0xfaf327b5, - 0xb5378c31, 0xf7a68b4f, 0x12c4c586, 0x8e1e8afe, 0x7a8e7a8d, 0xabe70c4c, - 0x531f6834, 0x43e5176c, 0x2d33f76f, 0x31b87a44, 0x49ebc3c6, 0xbcf8690b, - 0x20fb6eb8, 0x950a1e23, 0x72072a6a, 0x642cf84a, 0x832cb52b, 0x2bdbd6fe, - 0x28f0ef9c, 0xf2813f74, 0x55f8ba7f, 0x3933a6ee, 0x518e3191, 0x5c6614e0, - 0xe7eb33f2, 0x6fd51448, 0xcc69fc43, 0x646456ef, 0xf7926a95, 0xa94f5618, - 0x7e2ecc03, 0x43055a5f, 0xec44793d, 0x0c1fa3ef, 0x3d7c6ed3, 0x383f7a48, - 0x328bb180, 0x4f09bef0, 0xbf80db9c, 0x3eb3706b, 0x2b69e309, 0x5317d718, - 0x488f68dc, 0x033b00c1, 0x595554fc, 0x03df8837, 0x2f187cc2, 0xf42c2649, - 0xf37ee5cf, 0x8083b43b, 0x843df94f, 0x1550b157, 0x86c318a0, 0x9e3aefc9, - 0x96f3fbf1, 0xeb8ccc7d, 0x0741128f, 0x7a4ddc16, 0x7fbac1cc, 0x5aa3009d, - 0x155b7d45, 0xdc1cb7f7, 0x59b8739f, 0x58c3ed18, 0x42c70b07, 0x1caa18ea, - 0x2bbfca33, 0x5f03600b, 0xf39ac7ba, 0xf402e523, 0xf5bb445a, 0xf7a83f84, - 0xbf7a88ab, 0xabf7a88a, 0xe3abd5b3, 0x2836dca9, 0x58a5ef03, 0xf02f595c, - 0x09b3dbc6, 0x867e01bc, 0xcc7f3de0, 0xfb15e312, 0x18d784e6, 0x962b1bd1, - 0x8e6eba07, 0xfa7e20c9, 0x4eaedc59, 0x8966978c, 0xc3d70c35, 0xbefd248b, - 0x1877e64f, 0x1b6e63de, 0xa223e1c9, 0xcf02cd9d, 0x55bf748b, 0xb276f28f, - 0xb7947abf, 0x263e56f7, 0x6f67797a, 0xde8d89fd, 0xea5ef89f, 0x5a8d8eaf, - 0x4bd50fff, 0xf47daf65, 0x76efee0e, 0xa03727e9, 0x6e676cde, 0x1a54fd46, - 0x16b7fadf, 0x4cedc27a, 0xde999a5b, 0xc0dfc831, 0x9a17316f, 0x49f2479f, - 0xf472fe14, 0x29df7185, 0x61f3bbda, 0xe74d5e7e, 0xbe315c83, 0x9f7cb589, - 0xdc79eefc, 0x46cb078f, 0x25dfe61f, 0xe1aeeff2, 0x0fdde3f6, 0x1b0fb4cb, - 0xc1d5bf79, 0xe1efcdff, 0x801f07b8, 0x5f33ddbc, 0xa233850a, 0xdec5dbdd, - 0x677a878f, 0xde44fe88, 0x9e601583, 0x68e4cb49, 0xbe7160f7, 0x45e1cfd4, - 0x8b317fde, 0x66fdc5f9, 0x3159e7e6, 0x22dbe26e, 0x0f55a425, 0x82c79eed, - 0xd1ef802b, 0xc7be04fe, 0x9c592ffd, 0x8d2e66c7, 0x9adfd7c7, 0xa77fd260, - 0x70e27886, 0x8baf66be, 0x7cfe6ee7, 0x149eb5ee, 0xe54579e3, 0x1ee9ac74, - 0x9bd52aa0, 0x3d4dfa8a, 0x80f33d7d, 0x07a76a1c, 0x1f218f31, 0x7e1256ec, - 0x3d24f30c, 0x5084aa95, 0x3f6e2a2f, 0x37bb47cb, 0x5eb3f39e, 0xaebc4b5e, - 0x177ccecb, 0xe6461dfe, 0x5dcfff81, 0xdff3a1e1, 0xa7fc3957, 0x5d95fe71, - 0xa380de39, 0xb7043f27, 0xe15771f2, 0x8e7a33b8, 0x7af34aa7, 0x0ebedec9, - 0xcbf245e6, 0x3fd86d79, 0xc8f9ead9, 0xadfbfd83, 0xd30fd0ca, 0x23de3f13, - 0x153fc821, 0x24714fea, 0xc194dc72, 0xbc72fed8, 0xfff4146f, 0xe8bf7132, - 0x52264aa2, 0x08b7571e, 0x34a51fef, 0x913ea447, 0x8f72a64e, 0x974a7b8a, - 0xd5297a54, 0x56f36bf1, 0xb6983dd3, 0x36fb790b, 0xa25fa0b7, 0x402fe045, - 0xb52d97f6, 0xed1df682, 0xde308aee, 0x60d2c727, 0xb961c1de, 0x9abf09ab, - 0x13bf919b, 0x456c13ca, 0x66b55218, 0x7149d10a, 0xc87cb057, 0x0604754f, - 0xe37da2c7, 0x6987df31, 0xd6711d4d, 0xf8bb31fb, 0xfbc7136d, 0xb7e71263, - 0xa63fbc48, 0x6e307b36, 0xbb6bb1e2, 0xbc22abee, 0xe38872c3, 0x7ef93ffd, - 0x37bc4f6e, 0xc0699b4f, 0x327b33bb, 0x0267fde1, 0x5e054bcf, 0xaa1d04ab, - 0xc4ab3e04, 0xe255afbd, 0x812adcde, 0x3bc42adf, 0x7b888fa4, 0x3d23177b, - 0xef119520, 0xa1d6bfc0, 0x7b432641, 0x520f0f7c, 0xb75be087, 0xb2a4fc85, - 0xbc43efc3, 0xde39135b, 0x03a00e6d, 0xdde035f1, 0xc241f983, 0x78e0eaa7, - 0x0e9cf286, 0xef105602, 0xa739f123, 0xb6fde007, 0x87d424d8, 0xd6784c63, - 0x1f9fc712, 0xf3e29fde, 0xf390a25b, 0x6a25fc48, 0x5d605efc, 0x8fb37bbe, - 0x765c44ab, 0x1197b895, 0xcd7688f1, 0xbb0fc02a, 0x3f93e398, 0x2f60221f, - 0xfd6249a5, 0xc074055f, 0x3d8527fc, 0x74c67884, 0xb75f2c67, 0x762a5a24, - 0x04a788ab, 0x4b0fdf7e, 0x6cb4b20c, 0xf18043c6, 0x1e641a97, 0xe1fdf584, - 0xc8ff335a, 0x7ee2256e, 0xc893cf49, 0x56df2b6f, 0x2f7fb82d, 0x74debfcf, - 0xe69e5bae, 0xfe10f78b, 0x35da1203, 0xb872133f, 0xfa85f902, 0x8bc3d7c7, - 0x152c1f05, 0x223f06f7, 0x2131e7f8, 0x7ceb8fcf, 0x48e7e5e3, 0xf1e64f96, - 0x1699898e, 0x9862bf71, 0xe309e319, 0x834cf5bd, 0xc6dad17e, 0x9fdd2943, - 0x92b63ec9, 0x650ec6dc, 0xf8afe43e, 0xf10c1f8f, 0x7dfd70fb, 0xd78a1ed1, - 0xeb1dbfef, 0x0e83bf89, 0x711587b4, 0xd7cca4cf, 0xef51cd93, 0xeef2ad8d, - 0xa65fa1b1, 0xbeecfeb7, 0x73f11b69, 0x1e44e5de, 0xbfe027d6, 0x8ec03663, - 0xc157581a, 0xc81bd62f, 0xa57a8c5e, 0xebfc49c6, 0x1be7fe80, 0x17b624f8, - 0xc754ceff, 0x5f501bb5, 0x240680bc, 0x6a2fc130, 0xcf11d906, 0xfa0f7380, - 0xfea956b1, 0xac2f38be, 0x8fee8f8a, 0xdf2c65fb, 0x5d657087, 0xac2bf26a, - 0x9ef47d54, 0xef59ac7b, 0x44f314ac, 0x9cb344c2, 0x4fc2f3e8, 0x39577d45, - 0x5fb13b02, 0x9227a7c9, 0x1cde273c, 0x52a89e7d, 0xf7de20b5, 0xcb8c3551, - 0xe3573077, 0xfd0f73f6, 0xe49f68c3, 0x3af06054, 0x7ce983f4, 0x7d7190b6, - 0xaedc6417, 0x04f5c7d4, 0xe715bdf2, 0x3ff13703, 0xcb0807ce, 0xdefc6a17, - 0xe42dbbe3, 0xe4225887, 0x672151ed, 0xfd7c85cb, 0x8acbe51c, 0x297b58f7, - 0xab9085fd, 0x90872895, 0xe0cd8f1e, 0x3fb8bcf6, 0x2ccf5f4c, 0xfba08db4, - 0x161cab22, 0x4f94179a, 0xae0721ac, 0x768f760f, 0x7647ffa3, 0x4e03b966, - 0xfba2cfcc, 0x2cf8a5dc, 0x37cdf237, 0x9c1759ce, 0xc8161e2d, 0x2b16f74f, - 0xea4bf72a, 0x8957c8f7, 0xf75408fb, 0xd5fd0ccd, 0xd856264f, 0x9635de29, - 0xe4d787c7, 0x81de1366, 0x86b19d1e, 0xb4ca5a75, 0xfbeebaeb, 0xec9feac3, - 0xef835ee5, 0x6960de85, 0x41a17641, 0xfb88d44f, 0xc8279924, 0xc5f41886, - 0x31268bc2, 0xd4f5eff4, 0xcde8bd13, 0x2e6f5cf5, 0x4deba292, 0xf5d78edd, - 0xd17ea466, 0x4c17c5d3, 0x54bf9d36, 0x7a465e1d, 0x3f744867, 0xcac3b242, - 0xd7992ff7, 0x33d19b9b, 0xec95f01f, 0xed0be030, 0xf16fdd21, 0x89e328e3, - 0xae4793d4, 0x00d7e7d3, 0x4b343bdd, 0xfa393cf3, 0x79abf3ac, 0xfd3fc85e, - 0x794fcd08, 0x5a5347a7, 0xd92d7350, 0x69770c23, 0x1c2ef70c, 0x0bbf7d5e, - 0x46b87be9, 0x56af9fec, 0x74bf1843, 0x197166b8, 0x0f76d5c1, 0x2fdc66d2, - 0x3de1741e, 0xc8d6b34d, 0x247e9fb4, 0xf14e9826, 0x399fdf9f, 0x63e21b23, - 0x9a5dac16, 0x6b38fc8e, 0x373a52dd, 0x37c1247b, 0x59806fd8, 0x79ec8796, - 0xbcc6fefd, 0xb43ead67, 0xdbe37bc7, 0xfdd1d5bc, 0x27f8553d, 0x779853ae, - 0x7643ae08, 0x8674c6bb, 0xfc8e0f81, 0x82eb4ec2, 0x8ed82d2a, 0x58bad570, - 0x2555837c, 0x280fbf44, 0x0fb571d5, 0xf0ea94e9, 0x73298b5d, 0x4f7ed024, - 0xdbc472ef, 0x3b5f456f, 0x2d3ebbee, 0x3a0245ee, 0xbbf264dd, 0x56d77df2, - 0xb66347e1, 0x4463f25e, 0x7c97a7be, 0x62938f17, 0x7ff9e8ee, 0x6869ffb7, - 0x315df58f, 0xe6b4bf8e, 0xe84f92f8, 0xa11f7989, 0xcf8bc450, 0x5a1b175a, - 0x66ce4518, 0xb3c7f389, 0xce997ec4, 0xebd7858f, 0xe3e739f6, 0x5e973e48, - 0xfaf884b8, 0xcd2a7dcb, 0xafc0656b, 0x17a5efa8, 0x507dd346, 0xe2bb9e0b, - 0xfc0b8c71, 0xf94cbf6a, 0xc4eda725, 0xf53fedc7, 0xce8239d2, 0x9df4a9df, - 0x5df6af88, 0xda01e74d, 0x3ad3fdc5, 0x7c9cd29e, 0xc1c6bc3d, 0xe9de50f5, - 0x743c919f, 0xa66857f1, 0x779e7286, 0x5e5ce7fa, 0x31d9fef0, 0xdeebec38, - 0xe0a1771c, 0x2cd7806b, 0x2169349f, 0xc2df9bd4, 0x0d8d8ae5, 0x7b1f9196, - 0xd1f7ac6d, 0xc6bff228, 0xb5f931e1, 0xf3965bf2, 0x4caec0f7, 0xcc99c434, - 0xc87bdf12, 0x65efcd3f, 0x4b20ee65, 0xfa127945, 0xcc0e5bb0, 0xdbb772f7, - 0xd3d4e3cd, 0x79c6bb17, 0xd6fd6985, 0xe8abce3d, 0x53b09e79, 0x13465bf2, - 0x5f9e3ddc, 0x9e368e8d, 0xa58c71ee, 0xd1f1edf2, 0xb450ffdb, 0xc0595adf, - 0x8b4fa07c, 0x79bffdc4, 0xd434fba1, 0xe3ab791f, 0xb8c32413, 0x4d8a6bf2, - 0x35794ff1, 0x5fdf74b9, 0xed5ceafe, 0x76bc835e, 0x36cd85d1, 0x4743e5d1, - 0xd532e880, 0x40e3dfe1, 0xf0a17cb9, 0x583d4f81, 0x11d3a72f, 0x82bc382d, - 0xae7ddbf4, 0x3ea7e768, 0x8d53a48c, 0x1fac13a0, 0xd2740cb2, 0x7ef913e9, - 0x07d2faeb, 0x8bfdc53e, 0x45edf8a7, 0x08b1ebbd, 0xc74465fa, 0xf383a75f, - 0x0fd82b6b, 0xdfc2f381, 0xbbf8a665, 0xe827f15e, 0x7f47e3ad, 0x51dff60e, - 0x944efb94, 0x1f5851cd, 0xe17387e7, 0xc17dbbad, 0x8fa2e30f, 0xf3a9c527, - 0x04167cc3, 0x71aa3e01, 0xf1f7a3fb, 0xb682c43c, 0x974f18f3, 0xf1362e9c, - 0x01738a43, 0xff415397, 0x211e7ba3, 0xc50d6ebe, 0xbd19ed7a, 0xd9c5278f, - 0x185c1f0b, 0xffb34364, 0x11c1f1ef, 0x29f837cd, 0xde60479c, 0xf0bd79c2, - 0x1b86c7f9, 0x18ea97fb, 0x79c4e697, 0xf6fcfaa9, 0xbde383b7, 0x1e1d70fb, - 0xab7b275c, 0x8e254860, 0xbf7c60c0, 0x37f4f5c8, 0x145bdfe8, 0x68f0c4ff, - 0xcae2f476, 0xdfa0977d, 0x99b2aab5, 0xc5d85552, 0x0ce2ed0c, 0x688f5dfe, - 0x2b5e05f7, 0xcae2ebf4, 0xb5b7ee66, 0x70db9905, 0x323b00cf, 0x8ad8fc92, - 0x69cf6cc3, 0x7e8dc06a, 0x83dc4d73, 0x65812aa0, 0x67e85919, 0x1a0ccc4a, - 0x938d77f0, 0x4f2cd7ef, 0xfdc6e3dd, 0x8fd42b10, 0x9a5b33fe, 0x77e4ca72, - 0xe5995d7b, 0xd7e93a04, 0x7ab0c744, 0x1f91249f, 0x1f8454f2, 0x1fa994f2, - 0x7da6cd89, 0x28bc488a, 0x281dfe36, 0xb3ff0985, 0x9dfe87c0, 0x3e6ea5a4, - 0x8fc295ce, 0xaffa04fd, 0x363b022f, 0xc1f645d6, 0x7c2c0b92, 0xe853687d, - 0x3c6b2bbe, 0xf1c5af2f, 0xff71d871, 0x59f5c643, 0xde276098, 0xd5d32610, - 0xf1c2128b, 0xdc2123cc, 0xe0978587, 0x5c63a37a, 0xfcf803cb, 0xd7207b79, - 0xa6ff7809, 0x0901f36f, 0x81fc33f7, 0x35cf118b, 0x03d33072, 0x772d7fe5, - 0x74b96266, 0x8138fac8, 0x39e017a7, 0x9f618087, 0xdcd7df94, 0xe13dcb0d, - 0x112be60b, 0x5fdf86fb, 0xc7b7cc6c, 0x1fb02af8, 0x4acbdf91, 0xfda242fc, - 0x074cfc41, 0x34fdff9f, 0xf2772f3f, 0x07f10575, 0x6e3ed7f2, 0x3c529d3f, - 0x87efb871, 0xb4dd79d8, 0xbcf363ef, 0x114f686e, 0xe05ad8eb, 0x4fb0c557, - 0xb3e2a177, 0x545d3f20, 0xfd8dcf0d, 0x2727628d, 0xf2dae838, 0xdebd76a8, - 0x83af3c3f, 0x4f4f94f8, 0x92247b22, 0xed74762f, 0x69eff027, 0x9e33a1dd, - 0xf1c388b2, 0xfad1ff4c, 0xfdae93ee, 0x761c45aa, 0x5efca873, 0x69fe3fbe, - 0x99c51c6e, 0xa3b8fdea, 0xda336969, 0xf53477c5, 0xbcf8899d, 0x3fe2e0a3, - 0xed43ba63, 0xfa8b13dc, 0xce897ee2, 0xc1f9dd97, 0xa42c6aeb, 0x475fdf5b, - 0x2f3c1ff7, 0xeb3a71e4, 0x01fe9154, 0x7ef8d6e6, 0x47df8857, 0xae02bcc5, - 0x715fd157, 0xdb743877, 0xf3dd000d, 0x3406e87a, 0xebefa6f7, 0x43d5037c, - 0x893ddea0, 0xf7f494f6, 0x726fbd1a, 0x35d7bf98, 0xe346c57e, 0x8daf1ee9, - 0x0f8fafc6, 0xeff84a7a, 0xf7b88fc2, 0xf8c7c74d, 0x77dc7c99, 0x1d75dec4, - 0xe03acb3b, 0x3fb0db0e, 0xde3e78f3, 0x7cfc489f, 0x1fa05985, 0xf6fa745f, - 0xe33e3f20, 0xbd45edf4, 0x4ceb6257, 0xbc920657, 0xcbcf85bc, 0xc905c0e4, - 0x0313fe30, 0x21271702, 0x9cfb9a1e, 0xc07fbd97, 0x80fbf9ce, 0x81f7f39d, - 0x5baf9d0c, 0xecd7c89c, 0x538d2274, 0x92c77eff, 0xbb1f87ad, 0xc4fbf81d, - 0xbb3efcdb, 0xe373d952, 0x9697e443, 0x3e2e3199, 0xfc203d32, 0x7c5d2d0c, - 0x433bc7c8, 0xa332f2e1, 0xc1ce9621, 0x9b2f98cc, 0x319fdbee, 0x32c3c79f, - 0xadf879a5, 0x22c275a6, 0xb3d2d711, 0x4483f41e, 0xfe7333d6, 0x6517ba04, - 0x471ee69b, 0x9c35917e, 0xf44e66cf, 0x608e78c9, 0xf68932cc, 0xf21f47f1, - 0x3c00b634, 0x45ef1433, 0xe0f99d31, 0xfbc20d7f, 0xb99aca51, 0x9e45347f, - 0x4853f993, 0xf3e1ed57, 0x1073c23d, 0xc79f0e4f, 0x69cfd861, 0xdd322b53, - 0x38f7cfc8, 0x7207a87c, 0x827df56f, 0x22fdd574, 0x0afbbcfa, 0x171801d8, - 0x27b77b9a, 0xb724f907, 0xd4a3eede, 0xd01894c6, 0xb30ab96b, 0x31a29a61, - 0x0c698ec5, 0xbd9a61b3, 0x354fd850, 0xe0fd9137, 0x786bf1ca, 0xd36e79bf, - 0xfbe35ff3, 0xb7784af9, 0xdcabe064, 0xa3bfb7a6, 0x3f3e7673, 0x565efdc5, - 0x9fd699a7, 0xf0cdeac3, 0x38668de5, 0x47866c33, 0x65c333ee, 0x67683638, - 0xe11ef88c, 0x86569d9e, 0xde2b2bdf, 0xf438a56c, 0xa0ae7157, 0xe93b5e78, - 0x4dc509c5, 0x712718d9, 0x05a745fc, 0xfe3b95fd, 0x59c532fa, 0x658a6e74, - 0xfbb86718, 0x831618d3, 0xed9bbc71, 0x18bf30eb, 0xd9fe8768, 0xb5f6cde2, - 0xedb34f18, 0x434f9d52, 0xedb50f14, 0x4bbcfc6f, 0x086b06e7, 0x6f8e2ee3, - 0xe445fe7f, 0xfa1be3cb, 0xaaf61d93, 0x7d60b414, 0xdd3847c1, 0x3ebd08c7, - 0xe2f5e846, 0xfc7af33a, 0xaf6e970a, 0xfce287ba, 0xe3812637, 0x2fb2b5bb, - 0x2577c587, 0x8c6dfb74, 0x40dd67b0, 0x7687cfcf, 0xd08879d3, 0x7ba179cf, - 0x6bd11f35, 0xb3ea0c41, 0x0cdaa38e, 0x5c5d4bf4, 0xcea3c663, 0xcc8497df, - 0x24ba27cf, 0xcf0ce7a1, 0xc55e3033, 0xe71524b3, 0xdfa367ef, 0x8bbd7f53, - 0xbc2f19db, 0x20f2e9a0, 0x992a7b8b, 0xb2ae70c7, 0x79b3ef5b, 0x089e31fd, - 0xfbb035e9, 0xbb447179, 0x2eb1fd7a, 0xda5fcf2e, 0x448279f8, 0x95638781, - 0xe86ec8fb, 0x7d2b23b2, 0x380689be, 0x727766af, 0x776fe12e, 0xf986bdf2, - 0xdec364aa, 0x4e30bbe4, 0x8f414eae, 0xe3b92b36, 0x498f9fb9, 0x3d72e7c4, - 0x11f313f6, 0x6ff56d8f, 0xd81cb0b8, 0x718c23d9, 0x5735f967, 0xe41a26fb, - 0xb9f287fe, 0x3712b74e, 0x392bcbc7, 0x9cf093cd, 0xff0d7148, 0xfd71618e, - 0x80dcb76d, 0xcfcd5ef8, 0xcc2b67d3, 0x963c832f, 0xfaedb96c, 0xfcbcf061, - 0xec5e5199, 0x2b71540f, 0x78de2f3e, 0x3d15ce92, 0x8efee16a, 0x0504fa48, - 0x13fa3d9f, 0x39ea0147, 0xcb75efa8, 0x9f7f7a08, 0x239bec05, 0xdcef83e3, - 0xb38e4505, 0xa06f0ffa, 0x9f3330f8, 0x684bdf02, 0x97ae75bf, 0xe9e8ebbc, - 0xd19becc2, 0xa02df754, 0x8fc87978, 0x0c297eba, 0xa489eb99, 0x6fc16aef, - 0xe4621bf0, 0x7d72c893, 0xdce904a6, 0xd07cc974, 0x43ff0693, 0x8a6aa1c9, - 0x076c8dcf, 0xc1985823, 0xe181da0e, 0x9b972875, 0xfc169c78, 0x88b65b24, - 0x61c41f63, 0xf915c7ba, 0xf8a21811, 0x83d13652, 0x4d99bd78, 0x37d754c6, - 0xc3f5396d, 0x52abfcb1, 0xa2bf73cb, 0xe7249cfa, 0xdd30ee6d, 0x9c4fdb6f, - 0x70f36f47, 0x8feeff58, 0x64d45f9e, 0xe3aeb8a7, 0xbfd23427, 0x149e300b, - 0xb768bfcb, 0x3d68c058, 0x78cfa5be, 0xab6e538c, 0x1fa5f7e7, 0x5e33efab, - 0x1ebccb3b, 0xf9f44fa9, 0x39fe20f6, 0xbe7afd1a, 0x83ce1726, 0x771c788b, - 0xcc8a9f4a, 0xd274288a, 0x2ad44bdf, 0xd3fd7132, 0xbbc38f79, 0xcc14f08e, - 0x9fefc850, 0x5c9a7e4a, 0xe83a9fe1, 0x02edbff6, 0xaca139ba, 0xec25fe0f, - 0xdfa1d793, 0xfbd90bf3, 0xf7507b80, 0xacacfd3e, 0xa3df9d00, 0xfb40f40f, - 0x56161533, 0xe266df80, 0x609c353c, 0xae674f9a, 0x719e2896, 0x78f372d6, - 0xe36ebef0, 0xaac05afc, 0x5622dea9, 0x6ac1694f, 0xce217e73, 0x273c2e47, - 0x8a76e3c7, 0xfaf9cd6a, 0x8d92c0b9, 0xf0d1ac67, 0xc7d335f6, 0xc702fbe7, - 0xa36cdd27, 0x2ab7ddfe, 0x6977ef8e, 0x6df387cc, 0xe9272ae7, 0xa01662ff, - 0xe629dc7e, 0x7307f2fd, 0xed20b37d, 0x37d33f98, 0xcb9e0fab, 0x2d23f3e7, - 0xf99e4919, 0x13c57ebd, 0xbf007859, 0xbce187cf, 0x8524dc5b, 0x036c2187, - 0x9fc11d51, 0x3826bde3, 0x3679e37e, 0x6e38fc7d, 0x3ef673e3, 0x9e116fa7, - 0xb8f9929b, 0x0225f98d, 0xad1b251f, 0x98d17f26, 0x79d0528d, 0x6aaf9e39, - 0x1acaf7a1, 0xf54d58ce, 0xec1d798a, 0xba076601, 0x2b58298d, 0x755660e3, - 0x25d0f1e9, 0x1ccbced1, 0x755c7810, 0x945f5e5b, 0xbed1c7db, 0x9d1027ed, - 0xf84a7a43, 0x06d858a3, 0xec8cc5ed, 0x7b3f2982, 0xe2938721, 0x26a6bd1e, - 0x4a2fbe8d, 0x653361fb, 0x0e789bff, 0xd03e32b3, 0x99da0e37, 0x2ba5f169, - 0xc1bebf24, 0xcf9d6fe4, 0x88e4f0f1, 0xa22a4b8a, 0x3a75b7ac, 0x53d5213f, - 0x3b70409c, 0x599da79f, 0x20c06a9d, 0xb8e32317, 0xd3db8cbe, 0x3a8fe742, - 0xfe744ab7, 0x20e929f9, 0xea7e0f9d, 0xff430f5a, 0x09d02a40, 0x1253eff5, - 0xfcf7845b, 0x34dc3565, 0x73a40de7, 0xe3178c56, 0xc61b4a0f, 0x1a0ea5c9, - 0x62e3b73f, 0xbee2d62b, 0x218cca54, 0x61df9023, 0x866e33dc, 0x3ce3a3e7, - 0x075f5ed4, 0xc2ea7ba7, 0xa1dcc660, 0xce7fbed8, 0xc38f281b, 0x7cbce862, - 0x99cae00a, 0xb432e940, 0xe65952cf, 0x5333b46e, 0xa04678a7, 0x8b957f4f, - 0x916493b7, 0xf684dc67, 0x270e08e3, 0xd6f92c3c, 0xa0ae1311, 0xfcac5276, - 0x1cf87a93, 0xfa1b4ded, 0x7a061c27, 0xc4c8a84f, 0xf10653f6, 0xa70b5134, - 0xbbfb3d61, 0x75a01ee8, 0x23373cc8, 0xbbef3d7d, 0x2eb82971, 0x0b06dfdc, - 0xfb63d075, 0x97fdf4d3, 0xfbec83b0, 0xf2f0870b, 0x97994ec2, 0x24e7cfc9, - 0x15f6eba6, 0xfaa1d72f, 0x5ea246e2, 0xf9db8f7d, 0xe47c395f, 0xeb42bf07, - 0xa0803ce5, 0x58e9f953, 0x0bcc3216, 0x21bed3e5, 0xb4fcb3fb, 0xef1cf4cb, - 0x95c63509, 0xa1ec1497, 0xb2943bef, 0x509f3a66, 0x838e6f5a, 0x7a2622bf, - 0x979f3abb, 0x3059969f, 0xf99abb6a, 0x2c3ee9f9, 0xb95a27d8, 0xd3f3f364, - 0xfc6e1992, 0xe8539456, 0x7169cb39, 0x0a71fae1, 0x67a847ce, 0x7aa09642, - 0xda5d3779, 0x79a62ddd, 0xe1c3dda8, 0xa8bfb10e, 0xb7f5ebe7, 0x39c4d34f, - 0x7bcf7e3d, 0x2028255b, 0x4dd3cfc0, 0x5ddfc927, 0xf09bb4d2, 0x3745f3a3, - 0xd059629e, 0xaae4a780, 0x6405b0e6, 0xfdb8e9fc, 0x025e874b, 0xcba3d924, - 0x7d4b3bf3, 0xbf1f2163, 0xef90616b, 0x792eacd8, 0xcab37527, 0xf0fd0b22, - 0x6389d2ee, 0xdf2f308d, 0x35f37efd, 0xb2b78113, 0x6bf7f286, 0x6b7bdee3, - 0x7506c621, 0x4ce83b9d, 0xb00d3bf7, 0x0076022d, 0xbb00cc3c, 0x2313f223, - 0xe02353f2, 0xcdbe5e34, 0xbd974e19, 0xfb8e6d8c, 0xf4051ae0, 0xf0df5b5c, - 0x6479bc74, 0xd747d579, 0x4b8ef7e0, 0x7bf7f8b3, 0xaf249acb, 0x65a3d064, - 0xe4871e5e, 0x3368b6f0, 0x9a1e2287, 0x507d44df, 0x71b928d2, 0xdfa8e0fd, - 0xdf182612, 0xabde18f3, 0x92d3ebe7, 0x5ef483fa, 0xb10ff5af, 0x3a3f3c90, - 0x772a73e4, 0x362dfdae, 0xaf3dfcc5, 0x52bbf6de, 0x50b7812d, 0xc7f7eadf, - 0xa8f96db7, 0x20aa7bfb, 0x7d7ded7f, 0x469f497b, 0xc72f5b9c, 0xe5ba38fe, - 0xa3e3c745, 0x7dd14e43, 0xd6187fba, 0x079a01f4, 0x2e4ef3b1, 0xff75abc0, - 0x14787a54, 0x27785fda, 0x4f1fce2f, 0x704ba148, 0x059a7a5e, 0xef76c12e, - 0x3768bd29, 0x80ec6a7e, 0x5e0cf2da, 0xdc4df309, 0x01ffc249, 0xfc00cb67, - 0xc7e9dd64, 0xa4e1c2ff, 0xe609ba16, 0xafefeab6, 0x1ecdefc1, 0xc032d018, - 0x8ff7f002, 0xe0993a5f, 0x419e5a8b, 0x04eac2f8, 0x196b0f0e, 0x03fbc320, - 0x23267d83, 0xa3bbd6fd, 0xa109fdcb, 0xc5fef46f, 0x891df60e, 0x84aafb43, - 0x2c783bcf, 0x757a06da, 0x4db1d17a, 0xd31f01eb, 0xf49623ff, 0x5bb6fadd, - 0x1e13f3ae, 0x6f8c7e82, 0xa6f8114c, 0xbbf49179, 0x5f44f642, 0xba130b9c, - 0x6f4ce9e9, 0x71bcd0f6, 0xb416c569, 0x0fa6521f, 0x55e379a5, 0xee27ef97, - 0xe9e9dd51, 0xc4fe9e24, 0x5bfae6ed, 0x46bc50b6, 0xb24e43ca, 0xdf171eab, - 0x23b90067, 0xba0870fe, 0x3c7cdc58, 0x73190dff, 0x80001bd1, 0x00008000, - 0x00088b1f, 0x00000000, 0x7dddff00, 0xc594780d, 0xbbbcf0b5, 0x26effeef, - 0xb24d9bbb, 0xf379f909, 0x71100843, 0xa9189313, 0x18884dd6, 0x220bb531, - 0x49716b62, 0xc93049f8, 0x2d16ad46, 0x544859bd, 0x46d10882, 0xe1b80a04, - 0xfd2b6202, 0x1a8c4582, 0xf68882e8, 0x72dfbd2b, 0xbd3fadeb, 0x8a7e1bd7, - 0xb4564288, 0xeb6dea5c, 0x2666739d, 0x5c9377d9, 0x9f7b7aa8, 0xbe8f8be7, - 0xcef33bce, 0xfe73399c, 0xb3339ce6, 0x9086bb1a, 0x258e4264, 0x4ec730dc, - 0xe631df9f, 0x224c9d15, 0xf433bba4, 0xc84b499c, 0xc421127b, 0x09f04845, - 0x0e7b6853, 0xd1eddf21, 0xb4897504, 0x734de1de, 0x44b2d116, 0xc345bd7c, - 0xd57fbde5, 0xd2b3e5de, 0xd32d3172, 0x9912abe7, 0xbd33f58b, 0xfe5a0e69, - 0xa7aefe02, 0x9f561ee5, 0x58ad25ae, 0x7fbec39f, 0xe5dc84aa, 0x76d4cfa3, - 0x7d296e3a, 0xb5b89dae, 0x916b8e9d, 0x0bca1789, 0x5d6c16e7, 0x736a614e, - 0x897842cc, 0x51269bd7, 0xe6364ef8, 0x76d1566a, 0xc8afa7bf, 0x515c8435, - 0x97b0cde0, 0xff40f9d1, 0x44d21c74, 0x3c369527, 0x37981cfe, 0x7ad7afad, - 0xcf3a64b3, 0x39fe1ddb, 0xe35ebed0, 0xd0b4429d, 0x77c0b789, 0x8823b405, - 0x3b76399f, 0x40f227b6, 0xffffbc19, 0xb8954f08, 0x4f115fee, 0x7534ef77, - 0xf8242c9d, 0xb7fd05f7, 0x2aa1d7b9, 0xbad2fa07, 0xcb871a4e, 0xd0ffc377, - 0x24ad4871, 0x2c3a1493, 0x8d6e22ab, 0xbfe836ff, 0x7a07e979, 0x513781a2, - 0xf02ff43d, 0xeb0a4ebe, 0x82fce952, 0x76cf24fb, 0xb2cfdec2, 0xe8959211, - 0x21e613bf, 0xc3f79ee0, 0xd17f34e6, 0x3f2c7cf0, 0x76e6a978, 0xe4b79c5a, - 0xf4edaecc, 0x590f79fb, 0xdb865108, 0x9d711ed3, 0xb8cf7fdf, 0x9f495c9a, - 0x86b0defa, 0x19fdebe2, 0xb69cb3c4, 0x1a435f7b, 0x73efff00, 0x743f95bc, - 0x853211f7, 0xb5d95f90, 0xd0499df8, 0xbddbe483, 0x53b7e288, 0xd0234122, - 0xd23d4cc3, 0xd28860c3, 0xfeb095c3, 0xfbe87d74, 0x872707ee, 0x067d7482, - 0x619100c9, 0xbec4153e, 0xbfa9895d, 0x29eb00a3, 0xb44d049d, 0x0e68da3e, - 0x5e80956d, 0x50a5a028, 0x5feb093f, 0x07fad895, 0x38e230ef, 0x1d1933dd, - 0x433a3776, 0xb6001cc1, 0xc6de008b, 0x7694a3a2, 0x64487482, 0xb69994ef, - 0xe36c7c61, 0x3a52c172, 0xb4dbe2f0, 0xe4dab23f, 0xb01f4f19, 0xbb943284, - 0x4a3c7152, 0xbe91ab0f, 0xfd470664, 0xab42d38f, 0x394f5c70, 0x36a3cbac, - 0x1f787cef, 0x014591fd, 0xc89937f8, 0x7d09634a, 0xe8c3a44a, 0xe1c0eba4, - 0x134f5d21, 0x60bb83a0, 0x7f878a00, 0x536f386f, 0xd89ffbe8, 0x08038425, - 0x484e58cd, 0x75f5611d, 0xa4c72ccb, 0x86d4f029, 0xddf4090d, 0x03bc1bca, - 0xd972be82, 0xf3fb48d3, 0xeb22ba73, 0x83c036a3, 0x804bbe1f, 0x29b73ffe, - 0xefd32856, 0xd3f2c0a7, 0xbf870bef, 0x7df039ff, 0xe0c7c019, 0x65166d27, - 0x1f8c34bb, 0x80b9fcf1, 0x6f69ebaf, 0x9c6278ec, 0xd98f7ef8, 0xf007ffbd, - 0x4e1ef145, 0xb45e0174, 0xf0f1aeb8, 0xc7d1f4ba, 0x5e7eb44d, 0x82b1d69b, - 0xd4bfd3e2, 0xf015f386, 0xbd1a95de, 0xec8de48e, 0xa5a594ff, 0x2ff9865c, - 0x964f7465, 0x62e22819, 0x2e1fa2f1, 0x485dd253, 0xd23587a2, 0xf0e5ef28, - 0x517f8001, 0xf8f7cc77, 0x621abfdf, 0x21be09db, 0x3f07148a, 0x92452ba7, - 0x12fcdd61, 0x3ebd375b, 0x56e40f3a, 0x9f02dc3c, 0x8de5c6ff, 0x7c788ba0, - 0xbbe01bff, 0x5dbe246c, 0xe84c81fa, 0x80d4bfd7, 0x9fef8a78, 0xf77e1090, - 0x4d0489b4, 0x4bd6ee94, 0xfaebd212, 0x90212d07, 0xe8a6839b, 0x6067c00e, - 0xdeb88dff, 0x0acd1ae7, 0xea364da1, 0xf705bf19, 0x171f18db, 0xdc80140c, - 0xece7473b, 0xee73eba5, 0xa09eda37, 0xa4208024, 0xadda37e5, 0x5ee7ff40, - 0xb3f589be, 0x5a10a2dc, 0xe986000e, 0x7fe081b8, 0x578a11b6, 0xc7119669, - 0x0a57b13f, 0x8fbea019, 0x5e4639e2, 0x36ffa39e, 0x8dcb0c94, 0x3800a841, - 0x07082cfa, 0x8e23699d, 0x59335df7, 0xd16fc745, 0xad0d5e48, 0x2932596f, - 0x31e0ced4, 0x16d5cac6, 0x4a90e90d, 0x45bff986, 0xdee0bc73, 0xa7275622, - 0x60ac7970, 0x851243bb, 0x3ab8c9b3, 0x05fa05a2, 0x4bf5a03e, 0x78673ea0, - 0x7f565a1d, 0x479817f4, 0x7d351ecb, 0x9eaf3d34, 0xba5892c7, 0x17a619ca, - 0x17c3294b, 0xf1a126a9, 0x2f1b5e14, 0x21226a5b, 0xe963e02d, 0x2ae27234, - 0xc0e0f4da, 0x5b23a074, 0xa3a92f69, 0xe269c0cf, 0xa7b8510d, 0x36bcf7f6, - 0xd477b68e, 0xba613244, 0xcdbfa581, 0xf0d5793b, 0xaf380b3a, 0x4b427fe9, - 0x7e1e38ac, 0xeef14147, 0x89bb62b6, 0x7d88aeb3, 0x92efc0ae, 0x0f2f4c35, - 0x1fe02bc0, 0x75cde999, 0xfd526f5c, 0x617af28a, 0xafd404d7, 0xce40ffa0, - 0xf4c0953d, 0x903dc831, 0xaa8e6d33, 0x9e741cab, 0x14d56766, 0xc71b1947, - 0x27e98367, 0xa788fea1, 0x243d78eb, 0xb5e6a5da, 0xc75ab716, 0x0cf9476e, - 0x90dd16f1, 0x2c88e4c8, 0xafd17961, 0x10ab3d75, 0xe6e9193e, 0x2839cdde, - 0x97481b97, 0x89bce81e, 0xc740f484, 0x98248c8b, 0x1162e940, 0x9f48966d, - 0x881bd78b, 0x8d7eb312, 0x89b97521, 0x49bb85cb, 0x7bbfbf04, 0x357d5c67, - 0x7d68db09, 0x2d8491b3, 0xd755ecf0, 0x8e7d50b7, 0x85f7d67c, 0xe93df621, - 0x8bbdf366, 0x3aa3bbaf, 0x79d3f5a4, 0xdd51306f, 0x5d0684ea, 0x97533eb8, - 0x267ae0f5, 0x1e737896, 0x2bf2bd06, 0xa52b679d, 0xf5f03fdb, 0x6639f812, - 0xbc00aaaf, 0x9c1ab59b, 0x0361f47f, 0xd524e7e2, 0x6bfeb0e3, 0x59aee41d, - 0x8dae79f4, 0x8075f378, 0x2cd67b26, 0xaf3c48db, 0x00d4c57a, 0xd0e0d374, - 0xd32ae8a8, 0xf972c3a1, 0xe5ff8e0a, 0x1cd6d096, 0xa014f744, 0xa15cf2a7, - 0x9994c957, 0x474c7cb4, 0x6e5a3bed, 0x43f56399, 0x4f60037f, 0x0efdf2d0, - 0x77eecf26, 0x453d71e8, 0xd057cc59, 0xfb071d0d, 0x9ec55f33, 0x43658e02, - 0x74609fed, 0xbaf0f5c3, 0xea0f7346, 0xd5fa21e1, 0x22dfa410, 0xfaf01e9f, - 0xf32b970a, 0xf8a16ec1, 0x1412857e, 0x2f608fc8, 0x3e295fb3, 0xe5a52de6, - 0x79174e57, 0x67402956, 0xf2bcde4c, 0x4159331d, 0xccf37c87, 0x27fb1f4f, - 0xb4fe7f5a, 0xfad0315e, 0x746b4005, 0x88915efd, 0xbe0bc617, 0xbe810868, - 0x7b33d26c, 0x15ff69b4, 0xfbd19ecc, 0x71842c37, 0xc079d05e, 0x084a69de, - 0xeb03b73d, 0xa2943cd3, 0x863aabc9, 0x16cbe0cf, 0xf439bdf6, 0xa0bb9fb3, - 0xa413d53e, 0xff26a3ed, 0x74d75846, 0x7a889283, 0xc25ad7f9, 0x381709c6, - 0x878f5e28, 0x9c7ddd98, 0x4e304956, 0xa1fb0dbf, 0x90b69a7c, 0x33a273f6, - 0xe543e715, 0x2759da2f, 0x82b618d6, 0x34375dfc, 0x8fed84ae, 0xd3d37ceb, - 0x8bf8f968, 0xb4e59ec5, 0x0fa7d06a, 0x073d29eb, 0xafbb32d6, 0x016ca35e, - 0x16fd90fc, 0x8f58879c, 0xb5c59ac0, 0xb2581f50, 0x8f9016ec, 0xc839f163, - 0x3723127b, 0x166891cf, 0x86c6d3f0, 0xe830dedc, 0x1e89fe95, 0x4dc4af54, - 0x8dd29f17, 0xa93db59d, 0xee8df863, 0x5f3d21d3, 0x1740ff6e, 0x43d33972, - 0xca804e30, 0x0ff82265, 0x594c72e5, 0xad995a3b, 0x5495e063, 0xeba9df6e, - 0x47fc1253, 0x9e5a5d60, 0x97f78ffc, 0x145e302a, 0x4ae922e5, 0xa93cbe46, - 0xba03cef3, 0xf5875475, 0xfd7a3175, 0x99d983a4, 0x076e06f5, 0x963eb092, - 0x797d450f, 0xc5ee9a95, 0x7fa704f3, 0xf7c9845b, 0xce1af591, 0x401ab71f, - 0x20654d8f, 0x23d06c93, 0xc15fe856, 0x0e9ea7fe, 0x3969ebeb, 0xbf58597b, - 0x4f813f88, 0x46c3be28, 0x1b93ef3a, 0x29bf8c6c, 0x459fa01a, 0xe5f50415, - 0x63b52d22, 0xd2bde04b, 0xe5d74037, 0xa40e8bd4, 0x8a67f22f, 0xf9ef8a15, - 0x5033b784, 0xb1ca97bb, 0x30a43a97, 0xafe60bec, 0xe5356c37, 0xb57b5f00, - 0xcdcf5836, 0xf9b1ca12, 0x1b05951d, 0x9ec97968, 0x13fd702b, 0x2e5d182a, - 0x2f503909, 0xb1f2e54e, 0xa3d210de, 0x8933fe1d, 0xf6883ec0, 0x1374f68f, - 0x64ad28fd, 0xae401e24, 0x1421e8ab, 0xd1f6a653, 0x57265ed4, 0x24e79509, - 0xf2126ec6, 0x8938e41e, 0xf4d503b3, 0x88fa1411, 0xa4a23dc9, 0x7213dc82, - 0x97dd98f9, 0x3e3b44e8, 0x97d6153f, 0x9b9327ae, 0x6bc425bb, 0x7d456933, - 0xd0c0f422, 0x9c8f5cb8, 0xbe9906d2, 0xcf813c32, 0xae0e677c, 0x8bd212eb, - 0x95e844fa, 0xdf20e8b1, 0x88fbe1a9, 0xbc60e9d1, 0x9afec153, 0x75f0934e, - 0x65a6bc74, 0x853cdc24, 0x50536d3d, 0x693d323f, 0x9e127a64, 0x97d0cbe6, - 0x5e31faf1, 0xc1ebc61f, 0x77d33d54, 0x3d859d62, 0xd98d3a93, 0x85975301, - 0xfc08a4b4, 0x94eade35, 0x26bb61e4, 0xa8d18ef0, 0x1f65095c, 0x9ef905c9, - 0x2a62f950, 0xc4c80fad, 0xa1657c0b, 0xefa1e978, 0xb7fb7337, 0xd7cd9527, - 0xabf467ad, 0xd8a47d93, 0xc112eb0a, 0x99346f7d, 0x051e81d8, 0xe8db373e, - 0x1df02577, 0xefa1b7e3, 0x1cc3a48d, 0x2bd57df3, 0x173fd426, 0x0c85b65e, - 0xb3f88f68, 0x94bfb41d, 0x4ed01bdf, 0x0d8af73d, 0xae39e9f5, 0xefc25d0f, - 0x7e611e40, 0x41aebe16, 0x008e3552, 0xc6334bed, 0xf6140881, 0xd983b359, - 0x21ed2359, 0x99139f5e, 0x80cae8c3, 0x8e0bcdfb, 0x4ca00781, 0x7fa021e1, - 0x7e32716e, 0x5699ec0f, 0x3efa43fc, 0x187ab3e0, 0x40c5fdf6, 0xf7ed06af, - 0x7d2918e7, 0x8b2ed74d, 0xd1e7483e, 0x83b5699c, 0xfeceab7e, 0x41dddfd7, - 0xd1ee1fcb, 0xf3ac0311, 0x497369f6, 0xb7f2d8ee, 0x3e3ba431, 0x772fc310, - 0x9b9754ef, 0x40e5d57b, 0xbf7cba9f, 0x653ae6d3, 0xf9e1d941, 0xc1b5d282, - 0x87ba7ad0, 0xd5786bc2, 0x8668fa80, 0x1390ffd3, 0x7a26ade4, 0xc86cf018, - 0xf80a78fe, 0x9ffd023b, 0x5034f048, 0x31148a36, 0x5f5f03fc, 0xb6cfcd30, - 0x61b7828f, 0x06a311fc, 0x75ad4cf1, 0x173944f6, 0xd2e27ce0, 0x403c3f7b, - 0x9668bfe7, 0xdf02bed9, 0xcacb6b78, 0x18449ec1, 0x4dfd6049, 0x8bbec21f, - 0xf5846bb6, 0xb693353f, 0xac3570a3, 0x89b0fa67, 0x6f801244, 0x69dda85b, - 0x1bfc4ba4, 0x77776fce, 0xf4c3cb44, 0x359dbb7f, 0xf94e0113, 0xe80fb22f, - 0x37e851e3, 0xeade4ec6, 0x4bfc7264, 0x463299fb, 0x02b699f8, 0x038d9afe, - 0xfe3a4afa, 0x0cf97ff5, 0xa5e2fde5, 0x823ee1af, 0xb33e63ce, 0xc80a4dab, - 0x1e0fc5a7, 0xdf62f7c0, 0x8ad32a76, 0x36d7b6fb, 0xa1d95818, 0xcda9f2c7, - 0xb8b95f6c, 0x3cc10a57, 0x931759a5, 0x6c2f412a, 0x640dd9d6, 0xf1e35e24, - 0xb7a6c1f8, 0xf5efc013, 0xf61d2201, 0xc7b3127b, 0xb809adec, 0x135a507f, - 0xac0cbec0, 0x9043f1bf, 0x6b378b8f, 0x902f603d, 0xcff4367d, 0xc37cde2c, - 0xe85685c4, 0x4aa4d3e7, 0xb96d13f0, 0xd0543c01, 0x7e6217ce, 0xf4f5c89e, - 0x6ae5bcbd, 0xd0f1f805, 0x62ff0666, 0xd0077187, 0xd17ff5d1, 0x1ac97f22, - 0xb93b07e2, 0x089def5b, 0xda6cad7c, 0xe7d61d3e, 0x1ae99983, 0x224bbf6c, - 0x638bc076, 0x5fbc0a69, 0xe03ec92c, 0x8df586e3, 0x4f76b1b5, 0xc7f9939d, - 0xa597b32a, 0xaf91580c, 0x6d3e80e6, 0x08f94cde, 0xdef59fc6, 0x0d70eeef, - 0x6b3495f3, 0xa1532dfd, 0x1e7567ff, 0x7b21bbe0, 0x90b7d366, 0x4c2fe0be, - 0xe398b5f1, 0x99f2abeb, 0xa4f822c1, 0xeae400b5, 0x05ad15e2, 0x8cec51f6, - 0x44d93e21, 0x213272f9, 0xf9129da7, 0x1993fc02, 0x63bed54e, 0xb59a7dac, - 0xc67a8350, 0xedde21e8, 0xb74a99f4, 0xb71fb0c9, 0x6f58c925, 0x7d23d24b, - 0x77ba7fcb, 0xbce86fe7, 0x2ffa749e, 0x26ccbe80, 0x6bd062de, 0x455ed44a, - 0x35405acd, 0x136461da, 0xcc89afb3, 0x92eb85fc, 0x31558ec9, 0x125373fb, - 0x39504fdb, 0x73f405f1, 0x1f3fddee, 0x64b6fc06, 0xec053c7d, 0xcfc5c085, - 0xb35fe0f4, 0xdf284bf6, 0x011f1ead, 0xcff409ba, 0x868a0b24, 0xc3c072e5, - 0xbcfc46f4, 0x98e924e6, 0xb145751c, 0x82974a9f, 0x41076ee5, 0xd4b8da7a, - 0x46fef68c, 0x4004c857, 0x2b7cadff, 0xee46a7ec, 0xfb6e340f, 0x740b5785, - 0xe3ec921e, 0xfe30aca1, 0x17986c18, 0x3e71d2d2, 0xc41796dc, 0x8f4a9ef2, - 0xb759d696, 0x5ccae3fd, 0xce9f53c0, 0x9eaded03, 0xdf980481, 0x244edb87, - 0xb61afcc0, 0x0dde7169, 0x16524fa1, 0x09cb0d16, 0x905fc69d, 0x5d827604, - 0x42f8c2b2, 0xedb87c5e, 0x560594d3, 0x7d403fe6, 0x5e3a3a5a, 0xc9cacecc, - 0xdff5fdf0, 0x6672eb64, 0x72042197, 0xf9898cf0, 0x33bb45f7, 0xaeffa636, - 0xcdfe124b, 0x3fd02cde, 0xa2796543, 0xf7c4e406, 0x2efe6ced, 0xf0166f7d, - 0xba9247e5, 0xb52b259f, 0x52e54424, 0x84894ae3, 0xf33fcca8, 0x20594bdc, - 0xfedc3fff, 0x0c5d5652, 0x89dff17c, 0x6a498de7, 0xaff09a7f, 0x0ce1f4ba, - 0x63ceaf18, 0x31cc7e60, 0x3da2abfc, 0xa4fccf59, 0x816b9483, 0x8377c50e, - 0xd82f660d, 0x18c483bb, 0x5d5b9702, 0x7ad7f73f, 0xd82ef9bd, 0xe3ef88d7, - 0xf40d5ffa, 0xfa92e144, 0x5827f424, 0x9f28a28a, 0x77fcb4bf, 0x918cf5d1, - 0x8d9d74ff, 0xc6cd4eb0, 0x0471e1e8, 0x780f43e9, 0x6558b7d3, 0xed2957d0, - 0xf7a2be8c, 0xe59f706b, 0x814c2732, 0xdd3e80b8, 0x76f9056d, 0x43b9817d, - 0xb3ef0893, 0x333ed042, 0x0bbf10bd, 0x0ffa3156, 0xc3f410a6, 0x095691a5, - 0xe676b4fd, 0x20a8cfe7, 0xf8b455f6, 0xe76624b3, 0xbd6789b8, 0x5fd70f36, - 0xc70738c2, 0x400fd08b, 0xcf2f2047, 0x23a44648, 0x7b425fa9, 0x9de9ab54, - 0x458efd07, 0xbac52b57, 0x2a1aba72, 0xeae89dff, 0x23c74149, 0x20afcae8, - 0xa38db95d, 0x23f715d3, 0x127b765f, 0x36bec1f4, 0x2d6be395, 0xfbd13f97, - 0x2eafc28d, 0x796b7cc1, 0x6b46b57f, 0xc47a0b58, 0xd638fba3, 0xda89bc3f, - 0x4a7fb0c5, 0x3e9ebb03, 0x57cfb5c7, 0x6448dd70, 0x9608fc00, 0x2fa88dab, - 0x7244d31f, 0x9d498ec0, 0xe81bbad4, 0x515e7523, 0x0bee3b49, 0x17a01c33, - 0x7fa2d740, 0x1f34e974, 0x1c5823b3, 0x8f533a28, 0x07969cfb, 0x8ecc7d2b, - 0x097e41a8, 0xa02936ac, 0xe7f5a707, 0x08fa072c, 0x031e232c, 0x86cf71d2, - 0x9dcfe045, 0xac80f56d, 0xb225f113, 0x9d77cd52, 0x05538b12, 0x0f18226f, - 0x0d338e1b, 0xe821f96c, 0xf422c6ff, 0x8ff90c9b, 0x8dea09f3, 0xd6438dcb, - 0xde2136ad, 0xd068fc45, 0x25741146, 0x3fb191fa, 0x7a646892, 0x407ca468, - 0x054a73ff, 0xa1eb7f11, 0x3cca2e9c, 0x5ff823de, 0x456ca3c4, 0xc8b01cbe, - 0xbf399c2b, 0x049c4332, 0xb36c77fc, 0x00fd8416, 0x19598dfa, 0x694fcadd, - 0x50e92028, 0xaaab9ffb, 0xbcca6233, 0xc1f7d0fd, 0x5f573755, 0xa877fa8b, - 0x7aa6c01e, 0x26bd9459, 0xc355e205, 0x83b532f5, 0xff127d8d, 0x1be6e2be, - 0x941eaaa8, 0xee7ff8c4, 0xd11f82f4, 0xc5e35444, 0xf5c727c2, 0x5bfda3af, - 0x383ede15, 0xefe826ee, 0x7e5112a9, 0xe14bd3a0, 0xf753ab5b, 0xdfe52887, - 0xf78c4143, 0xaf0e537f, 0x6c319d5a, 0xe17b501f, 0xc36549cf, 0xefa3c276, - 0x495d76d5, 0x3fd8b2c7, 0x15fe83d5, 0x92e03efa, 0xe7890ed0, 0xf49704d7, - 0x656becd5, 0xe09d7d84, 0x74f5f662, 0x2fba4960, 0x581df941, 0xdf6023e6, - 0xe9c4bb52, 0xe3e4bb42, 0xfd680753, 0x1f9f59b9, 0xbb40a71e, 0xbec1e67b, - 0x4651702a, 0xa9d81bf9, 0x6f94490d, 0xaeccfd8c, 0xe31cfaa6, 0x967e8205, - 0x38fd39d8, 0x97fc0482, 0x32a4fbdd, 0x5a4277a0, 0x6ba36eb3, 0x379703f9, - 0xfbe1c713, 0x9779f8cd, 0x205f98bb, 0xa1b55850, 0x26dffa00, 0x5617b011, - 0x594f1e15, 0x63a9fb80, 0xbe630b29, 0x0a7bec6b, 0x53b8d9f1, 0xcb1e2a37, - 0x7804e1a9, 0x45f9796c, 0x338dc82f, 0x42650921, 0x04ea1c83, 0x41a1b6bb, - 0x29211603, 0x03bfcd0d, 0xf5731fe3, 0x5f9d3c64, 0x8177d706, 0xa706b79d, - 0xbfe9bcc2, 0xd1b57d12, 0xc4e508b7, 0x2b46b9c6, 0xeb0a91c6, 0xd83c41ee, - 0xc3c05ecd, 0x34aac2aa, 0xe665a718, 0x4dc63b74, 0xf5073da8, 0x077e0f2d, - 0xae0245fd, 0x1aba7d55, 0xa9ca77b0, 0x0a0bf75d, 0x4673a677, 0xf5f2878d, - 0xe2eeed38, 0x5710acfb, 0xff8e5d1f, 0x174664bf, 0xf82f921d, 0x8ff452ed, - 0x677f5892, 0x1fb31f76, 0x55e9716f, 0x5c5bf1fe, 0x36bdaecc, 0xe4069918, - 0xb01e5fb2, 0x201d5d80, 0x5f604fde, 0x65567c4d, 0x9313ae3b, 0x0536ae5f, - 0xd74666fd, 0x425763c0, 0xee32b5fd, 0xf03c8867, 0x5cf71863, 0x8ab3cba7, - 0xf2803e70, 0x90214583, 0xfe5cfbc7, 0x96fac2ef, 0xdcf57b73, 0x831637cb, - 0x5fd8517f, 0x5099cf9d, 0x94da766f, 0x4e406b27, 0x796649fe, 0x6468c603, - 0xc967ed1a, 0xb71c4ee7, 0x84ea14d3, 0x68f60ff5, 0xeac9beb1, 0xdbf4045f, - 0x29faeb78, 0x0d608798, 0xd51e8015, 0xd008bab9, 0xa0bedd31, 0xf2e8c51f, - 0x4f238811, 0x2597ce0b, 0x767117d0, 0x63f034cd, 0x85c5bee1, 0xce2adc7e, - 0x1529e31f, 0x2b22329c, 0x34917c74, 0xf9bce76c, 0xbc32d9e7, 0xc68ff614, - 0xd5eefcc8, 0xec04cd73, 0xf448f25c, 0xf8fc06b0, 0x7b0108ae, 0xc257b9b8, - 0x5f0b9a71, 0xe5fec3d0, 0xdfc65eee, 0xa0dfbe01, 0x78c2cbf8, 0xedc2cb94, - 0x67460e81, 0x1c787224, 0xb679f9e0, 0x76d0849e, 0x42577e31, 0xc0793396, - 0xf8f3d3fb, 0x37f73343, 0xf5884d51, 0xcec25cab, 0x5b8ea158, 0x49d771f0, - 0xf016af11, 0xfca92c5a, 0xc3d9e2e4, 0x183c4fbf, 0x1bfc0e9d, 0x7e05f4a5, - 0xccd20da7, 0xf3a75e7b, 0xc93650db, 0x9b98a603, 0x04b69392, 0xa45253de, - 0xfbed2f78, 0x0dd03a64, 0xafc821a9, 0xda957d2d, 0xeb8b2b66, 0xa58c5e60, - 0x53ea07b5, 0xfd442aef, 0x5993710c, 0x1cb3fdf4, 0xe65669af, 0x08af73c7, - 0x341c40e6, 0x9eefa0f1, 0x2bfc61d7, 0x4d87e8cc, 0x73636ba5, 0xf82573e2, - 0xf8a4dcbd, 0x7767e800, 0xf00252ad, 0xc41f7888, 0x0d16670b, 0x3d38e3e7, - 0x7d2b7792, 0x983976ee, 0x6a40cedf, 0x1f785e00, 0x1fc70eb2, 0xe3079fc1, - 0x9e0f7c42, 0x32c2d2e7, 0xc0c9fffa, 0xefb8ed96, 0x483e6037, 0xef1bdf6d, - 0x35adfe80, 0xc78c5e92, 0xd52dd9c6, 0x02beb789, 0xf6783ff4, 0x018796d4, - 0x7af6dbae, 0xce25ef30, 0x9bfeb91e, 0xb33f3ecc, 0x3f00a2dd, 0x9b72e56c, - 0x27c88fda, 0x3f6c5dc1, 0x1e476f19, 0x27f7a975, 0xddafe543, 0x05f0648e, - 0x0b3cb3b7, 0x7c03df21, 0x70d837ff, 0xd7f4013e, 0x13c10dbf, 0x8db20f97, - 0x8ff483e7, 0xe6f20f9e, 0xe8104b0e, 0x09af7ce1, 0x8f3292fd, 0x45b59d7b, - 0x7524001f, 0x01cf0e38, 0x72581b79, 0xca1ae7e6, 0x8b0f727f, 0x8f12c923, - 0x4b4afd33, 0x6bcc5c58, 0x808bff07, 0x774c765b, 0x3e408b7b, 0x713779b2, - 0xb39351bf, 0x2ef16140, 0x94d43796, 0x7b002e10, 0x87ae55ea, 0x5e2ccc9a, - 0x87d0e835, 0x26a35d61, 0x185d1fff, 0x93df62d7, 0xd8941a5f, 0x884f56b8, - 0x0a2775d9, 0x9d3d6135, 0x07d80f67, 0x59ab6eb0, 0x9f286b7c, 0xc7a1bf60, - 0x5890e2c0, 0x41ccec1e, 0xe22f5939, 0x3f99fb56, 0xa7c79eae, 0xf45acc4e, - 0x745ca40c, 0xb035ad48, 0xaab0bb3f, 0x0fe8fd12, 0x9f13393c, 0x7ed52bf5, - 0xa7e045ff, 0x238e1bcf, 0x1d7bff0b, 0xbd99e8f1, 0xd447ec3c, 0x5945fb50, - 0xbe815729, 0x15f621cc, 0x2095ff20, 0xe9abad5d, 0xc13e83b3, 0x12349768, - 0xa77239d8, 0xfbeb0ccb, 0xf5068768, 0xe343b054, 0xcf027685, 0x8fccc939, - 0xf3324d74, 0x0aa5d06b, 0xd9e238c1, 0x0771e3a1, 0xa272dfde, 0x2353c309, - 0x76a3e7b1, 0x7d3466b9, 0xd0ebfa2d, 0x4fc11ab5, 0xa0d4cd17, 0xde82fbdf, - 0xc6fd173b, 0x790202ce, 0xd6b61d54, 0x1eac3595, 0x2982e779, 0xebfac3ea, - 0x12486664, 0x33f209c5, 0xcbe79935, 0x616de1c5, 0x1f1cba97, 0xa90c698f, - 0x3fc4f5cb, 0xc58f2d21, 0xa7df620f, 0x75f93326, 0xc70e5561, 0xe3f307b7, - 0x6797fcc4, 0x3269bc30, 0xb33733d9, 0x41d02e6a, 0x7397c42e, 0xabfcc9e0, - 0x7f082674, 0x092e75ee, 0xde0e23e9, 0x80da300e, 0x3c593abe, 0x3f856ff4, - 0xe4caee1e, 0xbc1fae14, 0xd65f886e, 0x8f18f5db, 0x493f5cbe, 0x0e5ab25d, - 0xfebf950d, 0x27db2cfd, 0x9e796a75, 0x50e51d8d, 0xe5cd9d9d, 0x11d9e484, - 0x6a56f786, 0x3a3cc02f, 0x3f6025b5, 0x8ad5bb4c, 0x6fd968f3, 0xf3703f42, - 0xd02c81b2, 0x03552de3, 0x89b71005, 0x2b402fc7, 0xdb45f90b, 0xfee8b9d5, - 0xd884ec03, 0x4b5f3c76, 0xfef5671d, 0xf60cb920, 0xbf762739, 0xb76afa01, - 0xfd15f509, 0xf00603bf, 0x839cbcb3, 0x3687ccf6, 0x0bb41b7f, 0x9e5bc398, - 0x85bb01cd, 0xfdcd4dd9, 0x0bb01e86, 0xe2623aeb, 0xd59ff07c, 0x591fb8ea, - 0x3bff44e9, 0x6fbf56e9, 0xddf714d8, 0x17603888, 0xbd3af3ae, 0x3bf0227f, - 0x7f983bd5, 0x8351b670, 0x5af50379, 0xb79022cf, 0x7b6a4d67, 0xad8dacfc, - 0x75a196d7, 0xb5bda0f6, 0xf675cc65, 0xd73ac014, 0xb63f886b, 0x6758669f, - 0x7c4dbeba, 0x78becf9d, 0xf3ac0175, 0x2eafbbc7, 0xa75e7580, 0xdf02f2eb, - 0x5bfc39b4, 0x27bf6993, 0x3da1f06f, 0x2f58f225, 0x24f71e97, 0x432bfdab, - 0xff21ffe5, 0x30fa58ca, 0x5a87043c, 0x4af4ba1f, 0x3a83c806, 0xd5bfe1a3, - 0xaa37f08b, 0x4068cf1f, 0x3ffec77f, 0x0766ba7f, 0x2d7e81c8, 0xbfa223da, - 0x0f3fb2fd, 0xeffda1ec, 0x69413db8, 0xb91bfeec, 0x246dd85f, 0x88abf041, - 0x27b0807d, 0x5bf1e5e3, 0x251f3e7c, 0xbb006f7b, 0x8dfacbe6, 0x633bf81b, - 0xe76653e8, 0xcc3c936e, 0x7e8bdc6f, 0xf37d96e4, 0x3e27e0ed, 0xe37e621d, - 0xd18b1796, 0x7a18dc6f, 0x65790c2d, 0xc3b25fa4, 0xdb71a3fe, 0x07c804b1, - 0xba5cfb10, 0x8c933daf, 0xefdea8f4, 0x489d0e9e, 0x0a01fc80, 0x71e82577, - 0x07aa2b8b, 0xfba16fba, 0x6c23c83d, 0xa187a391, 0xc11716df, 0x3ed2973c, - 0xc44ffef5, 0xf4fa3779, 0xf6377728, 0xd790214b, 0x4e7f7a29, 0x9235e806, - 0x2078c761, 0xc98bb3e7, 0xb294d4de, 0xf7baf8d8, 0xe1e4e4f3, 0x0d81b07c, - 0x03bf4889, 0x83b5e23a, 0xe360db3c, 0xf9464cf2, 0x8e4dc7f6, 0x630fcb10, - 0x6218ffed, 0xc8a34276, 0x5849930b, 0x68b5eba6, 0x585df7b6, 0xe1f7906f, - 0x5b1f7938, 0xbbfb7116, 0x52f51849, 0xca181933, 0x176d8b0f, 0x7887d71f, - 0xd21faab8, 0x1f80ac5a, 0x07ab4eec, 0xb8f881e0, 0xf6c83eba, 0x961f94eb, - 0xafd30c96, 0xbf410758, 0x1d0fdc2d, 0x08fe3868, 0x4fa06fd0, 0xd77d83b2, - 0xdbf461e4, 0x905bf744, 0xefcf1b47, 0x379d57a4, 0x97ff163a, 0xd1f5a8a6, - 0xe4eff950, 0x453ebd5f, 0xfe62f7cd, 0x343f6fc2, 0xf1897ecf, 0xe2bcdc65, - 0xfef1a9f7, 0xbccfb176, 0x2738795c, 0x870f2d45, 0x79677fca, 0x2eb43758, - 0x1d50f2f1, 0xe59bf8cf, 0x5c70ffe1, 0x4f7d99e3, 0x03bec027, 0xa7d878ec, - 0x63aedcac, 0xfd1413f9, 0xe9e2f1b1, 0xc597ab5a, 0x5ea2b54f, 0xa657871d, - 0xe33c38f3, 0xd45ed7eb, 0xf335bae2, 0x3ef37138, 0x369a079b, 0x9c631758, - 0xba7e3e36, 0x0e9eec84, 0x471f154b, 0xce7e026d, 0x753c74bb, 0x8f8b0a75, - 0x20725852, 0x6f3e216f, 0xa7eb35eb, 0x7598fe49, 0x1ba22aaf, 0xdbe85182, - 0x33890728, 0x14c6fde6, 0xc6bf5766, 0x7adc8bf3, 0xad608e76, 0xfd85e2cd, - 0xf2c35b8c, 0xf2e07e9f, 0x18bc826d, 0xfaf1c2a3, 0x4344edf2, 0xae8cf2f1, - 0xb04ae517, 0x3901ead9, 0xa237fc28, 0x5e3c8bff, 0x3ffad971, 0xfcf7de8e, - 0x3c7bd30f, 0xf18bf67e, 0xddb8d6fe, 0x151b8a7a, 0xe3a4105f, 0xca5f1023, - 0x63bf4919, 0x1d1633f5, 0x1df14d1f, 0xfe766149, 0xb857cc14, 0x2963394c, - 0x3f009e8d, 0x5063d911, 0x7e09afc0, 0xab8fd412, 0xaa3e78d3, 0xe6267ca7, - 0x2573b369, 0x58ce1ce2, 0x4307e476, 0xc8ecc3eb, 0x9f5cc60f, 0xde47672f, - 0x087df0ee, 0xd2b27674, 0x1e01e78b, 0x61f851b5, 0x619cf87f, 0xe22e73d4, - 0xfca5c63c, 0xd1c45f2d, 0x4bff17d5, 0x3a92d472, 0x75f95d96, 0x13cfd1cb, - 0x763a7fc0, 0xff9e413f, 0x45bc4119, 0x6b6449f7, 0x103b5f8c, 0x197bf961, - 0xfef15e1c, 0xa1bef83f, 0x999bd521, 0xfc7fdf4a, 0x1248d1ae, 0x652e9ea9, - 0x67c5b172, 0x4b42b8c5, 0x697fcb2f, 0x8e504659, 0xb4df80b7, 0x3389fc08, - 0x4f7dd809, 0x2013fd3a, 0xf7d1ee8f, 0x226d41ac, 0x1167dbf8, 0xbdcef3b0, - 0x9c33cacb, 0x6798c9fe, 0xe3006cb7, 0xceb3dd18, 0xf9561e60, 0x523e9f17, - 0xa2f08a53, 0x5065c13f, 0x3db9679f, 0xf133c995, 0x6f843d9c, 0x3ff3fa2f, - 0xdaf9606e, 0x0ed79701, 0x0fe1097e, 0x8c1128b7, 0x61ecb42b, 0x96b95bc6, - 0x30fc87cd, 0x65a9e903, 0xf831654f, 0xa9af494d, 0xf2ddec18, 0xdf715bdf, - 0xe983f1f7, 0xcfb12798, 0x7c02afe5, 0x37434ad8, 0x4d9a7d81, 0xf7bb01c7, - 0x1537dde3, 0xfe42dc03, 0x39bf03ad, 0x4d9d7f1d, 0x462717ed, 0x64bf7796, - 0x33ee2647, 0x5afeac9b, 0x133aff98, 0x9db82383, 0xfee14f9f, 0x17fe78f2, - 0xd5aa9f7c, 0xdfa938e0, 0x5c9c6235, 0x3a7585c8, 0x0de637e2, 0x9e1293cb, - 0xf1701867, 0x99fec73c, 0x97854f2c, 0xbe752ead, 0x37c947e7, 0x253c0094, - 0x8b57f2a9, 0xe4475967, 0xb2a4940b, 0x5cea9678, 0xb322e5a2, 0x7aed73a7, - 0x4adb27a4, 0x9454e2c2, 0xbfaec09e, 0x06991a36, 0xbbf2bce7, 0x9e02d7c3, - 0x20d45ff7, 0x4799e49e, 0x28933e30, 0x56f2f1b1, 0x004e740f, 0xadfd8c7f, - 0x954960eb, 0xa0157b2e, 0xefa749f4, 0xffe45481, 0xaf1842d6, 0x2c745fea, - 0x059f72bf, 0x59dd0cfd, 0x795f984d, 0xea833dee, 0x33fc4e7c, 0x3e605648, - 0x6fdf6e65, 0xdb604e31, 0x279a8d23, 0x15aa44fb, 0x1825a6f9, 0x36398e99, - 0xce50bad7, 0x1f7efbca, 0xee43bb04, 0x91024194, 0x03579d0e, 0xcb82d3e7, - 0xc7f5fa09, 0xb035db77, 0x3f3cd95e, 0x7fff7066, 0xbee3f14e, 0x4205c445, - 0x3749bf2c, 0xc7ec08f0, 0xdf03e5e4, 0xec7ac20c, 0xc05a6871, 0xb68baa7f, - 0x9f65dfa0, 0xd9acfd05, 0xbe2b797d, 0x2bd9cb41, 0x1b0718ed, 0x6ceee57c, - 0xf3a7e7cc, 0x3cca3f1c, 0xf9654a1f, 0x8b3ef248, 0xfc99f406, 0xa8c0f104, - 0x0aa523b2, 0x968a7ee1, 0x07df3f69, 0x8e1e4a7a, 0x0a3f829b, 0xaa4354f4, - 0xcdd0077f, 0xa5a4b9d0, 0x892e7666, 0x2db5a79f, 0x9c176f7d, 0xfdc2d9f7, - 0x4ff707b9, 0xbffe859e, 0x7582594e, 0xf960e0b8, 0xb2a42f95, 0xfc48e278, - 0xd63cc41f, 0x65bf7ddc, 0x02e28d7a, 0x8c7597fa, 0x574ee45e, 0x5f19f80f, - 0xde63f049, 0x611d75ee, 0xeccdc62d, 0xa35c7f27, 0xd677ecc4, 0xb2d33d33, - 0xe3cfed93, 0xd29737f7, 0x921ebf2f, 0x0cbf4c33, 0x764eff95, 0xf4e2efcb, - 0x6fbcdfca, 0x5efdea21, 0xbf12fdbc, 0x8f611bbf, 0x9637f5c7, 0x50f2231d, - 0x61c786aa, 0xd84db4f6, 0x9e554149, 0x9f95954e, 0xfbaa343b, 0x47649f5f, - 0x3b79107a, 0x72caed29, 0xfe8fdbc8, 0x4edfa088, 0x3c8915e4, 0xcb1560a2, - 0x8c6a09f7, 0x4dd12e78, 0x687f30ba, 0x124b091c, 0xf006d7fa, 0xe42a6dfc, - 0x4fefd111, 0xff62e6a4, 0xa567899b, 0x22a6e516, 0xc826fc01, 0xb802493f, - 0xc1161b43, 0x7159b778, 0x9fe4133c, 0x033ee124, 0xc7dd39f9, 0x35a756f2, - 0x3a43b8b0, 0x4e50cfd5, 0x697467cf, 0x3cc7ab9a, 0x22579156, 0x5e044ff2, - 0xd3be38aa, 0x01ca2c27, 0x54f228b9, 0xe53d99d6, 0x39c11760, 0x1cbf3868, - 0xbcf3346c, 0x776fd613, 0x4f9e2e63, 0x2979b2fe, 0xf91678f1, 0x7f44fa29, - 0xe46cbba6, 0x37416739, 0x7089eb31, 0xecc7dc6d, 0x3d06aafc, 0x71b063ce, - 0x072bfa06, 0xec04351b, 0x037eaa81, 0xf1b8c3a3, 0x93d5ce36, 0x872bf430, - 0x054f204c, 0xceca5c3d, 0x085beba5, 0x6d83e0fe, 0x524ef33b, 0xd6d43fde, - 0x9341cf8b, 0x12bdabd4, 0x03cea1cf, 0xb48df5c9, 0x1af95afc, 0x6689b7c8, - 0x6a849449, 0x96faafd3, 0x60c4f54c, 0x287df472, 0x7be1bedf, 0xba3e3cac, - 0x9beda245, 0xed623ed3, 0xa9d33681, 0xefff5ed8, 0x57eb41b5, 0x267f7fd0, - 0x351cf9f1, 0xebf464ee, 0x3f41123c, 0xa57fd712, 0xadba3e4c, 0xdc9fb47a, - 0x54951f3c, 0x8854fcf3, 0x7b72d0f8, 0xefc6315a, 0x13d944ad, 0x030cfa81, - 0xe30827b3, 0xccf1f687, 0xf4e46d6f, 0xbf843240, 0xf208206a, 0x81c73dae, - 0xe7c90fdf, 0xf310863d, 0x8ff1b19b, 0x9e0578be, 0xb679124b, 0x6733d884, - 0x36f9815f, 0x135af2aa, 0xdb29a73f, 0x7bbce133, 0xc1db8ebb, 0xe6c47cbc, - 0x04f3885f, 0xddf6a4be, 0x507e1bd1, 0x7674fc04, 0x41f30fef, 0xa7a8ddce, - 0xe45184fb, 0x933a595a, 0xeb3a836b, 0xb77e894a, 0x016fe6c6, 0x32c77c3a, - 0x311c3a6f, 0xa9549b9a, 0xc1bc0077, 0xd780b4e7, 0x8e274e64, 0x473e0cd9, - 0x3c824fb5, 0x1b1376d4, 0x7b2fd937, 0x7f845cf1, 0x851b74b6, 0xf2625dbb, - 0x88947e9b, 0x92a15576, 0x26c87108, 0xcb55ee7e, 0xcb9688e5, 0x1b6e7f91, - 0xc1a997c8, 0x13ef4d78, 0x7fe7b05a, 0xbfe2e3cb, 0x9f9f51cd, 0xb83371e8, - 0x569673c5, 0xcfe802b9, 0x523aaba5, 0xab40e94b, 0xfd7084f7, 0x37186d32, - 0x772b603e, 0xa5efd00f, 0x42951fec, 0xe67b773e, 0xbe214a8f, 0xdc7a75a7, - 0x8f7298be, 0x357fd19b, 0x59bc03b4, 0xefc14b5a, 0x97f5b5fb, 0xfa2bfb48, - 0xf50dfdf2, 0x35706063, 0x7059a319, 0x9359fe6e, 0xffac3b7f, 0x30c7f985, - 0xfa40fc2e, 0xaf21f7d1, 0xd18ea8e3, 0xe793305d, 0x69ee93e3, 0x0eee9409, - 0x5e7839e7, 0x1ebf8b0a, 0xa8fcc09e, 0xfcb17e54, 0xe61289d1, 0x66ced621, - 0x266f62e7, 0xfa018e91, 0x68593a3d, 0x1c8af4fd, 0x796b7fb4, 0x77f4c89e, - 0x7eb0097c, 0xca8f6fd3, 0xb2c7f720, 0xeb746ee7, 0x3e188194, 0x975149be, - 0x97542e6f, 0x9751e5bf, 0x97f15dbf, 0x9365b109, 0xe8107bd9, 0xdf8955f5, - 0xb10d7147, 0xa4ba7f23, 0x935dd820, 0xe7e74a5f, 0xe53e5989, 0xf17ef94f, - 0xf5820aa5, 0x5b8d3b29, 0xfdcf508d, 0x3f5e5aef, 0xd98c4dd9, 0xea07c44e, - 0xf3c4a8e9, 0x93185d32, 0xb1ef7b22, 0x6d343f33, 0xecfda7ab, 0x1f20af9d, - 0xe43558a7, 0xa5ebc09b, 0x04c3b446, 0x289bb45f, 0x963c537d, 0x819a338f, - 0x9e75dbde, 0xd697d0f5, 0x2f40506c, 0xb1182657, 0xc83fed6f, 0x9b96d7a8, - 0xcb4ec40c, 0x63371f07, 0x3e265cb9, 0x20a123c8, 0x51e786ce, 0x0ad4279d, - 0x60eda5f3, 0x160eedbe, 0xeb96d757, 0x7ed3cf51, 0x3e0f5d71, 0x9c1109a1, - 0xf98ca57f, 0xc1661ca6, 0x7c247477, 0x6be734ff, 0x518486ad, 0x7bb3a58e, - 0xfed10e39, 0xbf83dfa1, 0xdfa0f6d2, 0x13b950ae, 0x271bcfea, 0xc0a8b9e0, - 0x592f79d0, 0xda15c003, 0x67e87cb9, 0x3f04f2e7, 0xa542f90b, 0x852bbe5e, - 0xf8149030, 0x053b050f, 0xfb8204ec, 0xccb71100, 0xd97a8a34, 0x0da6fd0b, - 0xe0e767b5, 0x56997852, 0x60253585, 0x27f1bca7, 0xe4b1c3a0, 0x931a6145, - 0xe429e213, 0xc3c316c5, 0x19af6a47, 0xef0a3d6d, 0x9b0cf2c7, 0x84c7ad9d, - 0xad4be00c, 0xe8064279, 0x478776cd, 0x0b94c5f1, 0xae6a76e9, 0xdb45f013, - 0x35adf2d1, 0x18e5f2c7, 0xc69854fd, 0xe76d00e4, 0x1ef0a24d, 0xc0192934, - 0xdb8ca3bf, 0x7cb5c6cc, 0xe9bae3bd, 0x41ddb4b8, 0xb6971d1b, 0x843266db, - 0x8da30935, 0x78c0a15f, 0xa2971a97, 0x833f911d, 0x93a503af, 0x0ec1f820, - 0xaf4834da, 0xf2be7833, 0x1e3664c1, 0xffe75429, 0xf8e99be4, 0xcea65f98, - 0xda51b9f7, 0xfa7a01d4, 0x56c25369, 0x3837cfa0, 0xfcb61cdd, 0x69d83e43, - 0x382bcc6f, 0x71267284, 0xd1100779, 0xf28bd20c, 0x0bc1c846, 0xa1cac769, - 0x8de1e54c, 0x0fde7469, 0x079d1ee4, 0x3c721f9d, 0xa5f68f9d, 0x56935bd9, - 0x417e1236, 0xa06e029f, 0x218be053, 0x5f838d3a, 0xa5b91bd0, 0x37251317, - 0x9e173b53, 0xa425eec2, 0x2bc5e595, 0xa3f3c399, 0xd8dd3e44, 0x18d1e6ca, - 0x746fb844, 0xe6f318fc, 0xffe718ee, 0xf735c01e, 0xbef04fca, 0x3f9ee222, - 0x1477f601, 0xc96979de, 0xc6f07bff, 0xca97f9db, 0xcf8b1f0f, 0xacd2f8c5, - 0x1e1f989d, 0x7cc56d98, 0x3f3c69f1, 0xc1a0d036, 0x0fdd00b8, 0x85a23ee2, - 0x97204318, 0x5cbb72a7, 0x45785b9c, 0xe0d6fe62, 0x7d45068b, 0xde7c513f, - 0xe97982b8, 0xbf2c65c1, 0x6f7ec87c, 0x1f7ed056, 0x9cfc73d2, 0x93317744, - 0x28f7dded, 0xe689fbea, 0x44fdf513, 0x7121ed0b, 0x32948a6f, 0xdddfbf9c, - 0xbbfe9043, 0x9f58b96d, 0x88fa65ae, 0xa3e9837c, 0xbaa21cee, 0x399d691f, - 0x94f31134, 0x46c15e78, 0x6ff83fc8, 0x9a7e0bf2, 0xc2fca926, 0xc9afe543, - 0xf0e6dc2f, 0x5b3a02ef, 0x92cde458, 0xebd63d28, 0xd2987f99, 0x8108a6eb, - 0x7cd6c574, 0x44dda7d8, 0xe4d2df5a, 0x02febd21, 0xa53275e9, 0xbd153cd7, - 0x15fc61ee, 0xe82d2144, 0x0b4e8875, 0xfd00f3e3, 0x6edc60fb, 0x5befef47, - 0x6fd35f60, 0x683cb0f0, 0x2f19d796, 0x59e0621f, 0x5c783320, 0xf3c22d5a, - 0x0f13f43a, 0x4df0e5cf, 0x12a69d2c, 0xf1631fc6, 0x824caa4f, 0xfe6192b6, - 0x6ffd9931, 0x7c43b8c1, 0xcfdb08f4, 0x6b5b808e, 0x739a7a45, 0x057f8b07, - 0x802ecc2c, 0x1d1a5838, 0x7f1f267f, 0xdaafa74e, 0x4a66ed01, 0xfa610f0c, - 0x167f850f, 0xdfd99faf, 0xb370798c, 0x63c775aa, 0x2f2120ed, 0x2e6ddc45, - 0x7dab7f6f, 0xd2f20ea6, 0xe3aad767, 0x64ef735d, 0xb339b6f1, 0x25ccfdd5, - 0x7cc13fab, 0x03aad24d, 0x53bdcdfc, 0xda49ff5d, 0x026c9c50, 0x710ec9c4, - 0xe520d03f, 0xd7a3e013, 0xba6f1793, 0x84f9d287, 0x8095149f, 0x9486f0df, - 0xd04f6dc6, 0x271bb3f2, 0x94f5f961, 0x28ff7eef, 0xc0296fd4, 0xe25c3572, - 0xe056fb04, 0x8567ca43, 0xc8cc77e5, 0xc27d0049, 0xe087bdfb, 0xdfd9b77b, - 0x73b6933d, 0x3cc5c94f, 0xd7ee6ad6, 0xeac85c18, 0xc6d2be6f, 0x52ef9552, - 0x6d5c5fd0, 0x1d35f766, 0x04bb7e29, 0x73abaaf2, 0xd5e4b979, 0x243e5049, - 0x3af7827d, 0xcab66b9c, 0xe92d0eb0, 0xb93ecfcc, 0xa44f0a50, 0xf276a978, - 0xbcd99bfe, 0x4b9e4b6a, 0xaea93e07, 0xf64cfd62, 0x41e67654, 0x2c79cd3b, - 0x26374b9f, 0xbf05fe00, 0x957df0e5, 0x5c7d2bb0, 0x3de4bc4e, 0xfb4491d6, - 0x0f2519f5, 0x7157d14c, 0x664bdd8c, 0x7d03e765, 0xfc191cde, 0x2cbcd3f4, - 0xb8cab6ef, 0xe1e40d3c, 0x297d7e2d, 0x2c6ecbcc, 0x1179043e, 0x65951589, - 0x246da798, 0xfe94beb8, 0x3f03a7c7, 0x5649fd5e, 0x559d1002, 0xbe82ff4d, - 0xafba0a66, 0xe537d356, 0x65e9c9db, 0x2adf9697, 0xd30d36fa, 0x3ef658f7, - 0xe102ab85, 0xaf5a86fa, 0xc7138d0d, 0x8ee3f19f, 0x2fe03725, 0xc30efe56, - 0x987c8bd7, 0x798dd901, 0x825da7c0, 0x38026f4f, 0x9e089af4, 0x3c96ca8f, - 0x7180f093, 0x7a88c785, 0x055f8e2f, 0x33e0997c, 0x1709192f, 0x6ec2c9fc, - 0xf02e7f65, 0x7af064a3, 0x38979dfa, 0xe3a2e187, 0x7a0e91df, 0xcf0611fc, - 0xc995a966, 0x112fbe19, 0x311697fe, 0x7cf53edf, 0x1eeccdcb, 0xcbf83703, - 0x3c527630, 0xcbee0869, 0x9f310758, 0xb3e7d700, 0x9e9b3e8d, 0x4736edce, - 0xedcfd23d, 0x283aa354, 0xff74c25e, 0xd41e700f, 0x7ec1f704, 0x62f1216f, - 0x47d29cfc, 0x6ec63d20, 0xe3c6f012, 0xb90c65a9, 0x789f3f1a, 0x5baf0cfc, - 0xe29e0d24, 0x7cd0e1fc, 0xf19e732f, 0xaf4b8af6, 0xb93a5bf6, 0xec39d17f, - 0xfa842c4f, 0xa0f6625a, 0xe123d13f, 0xda96af7e, 0x6ba7201f, 0x71fa086b, - 0xfa0d569c, 0x321d8513, 0xff5c9f16, 0x6ab7264d, 0xf73f089b, 0x4f17e6c8, - 0xe064a98f, 0x1ad6787e, 0x800b0d95, 0xaaac1bff, 0x56b50673, 0x4e788f16, - 0x503211c8, 0xa87f7a06, 0x0fef423c, 0x8a1c8194, 0xf6ae7fbf, 0x3b7bf322, - 0xacf84a2f, 0x032b1cf5, 0x19acefbd, 0x56790328, 0x14fef767, 0x13dc55d6, - 0xbdcf8f19, 0x97911ae9, 0x1a745972, 0x0e2247cf, 0x7fe6c47a, 0x3fc63d39, - 0xa08a5675, 0xcbb5759f, 0xcfe7e7ce, 0xd8767a01, 0xefc12a73, 0xaad8db34, - 0xd138bb03, 0xce903fe1, 0x5f17e8e4, 0x9a17e6c0, 0x56de3c52, 0x66587fed, - 0xee1e22c3, 0x81b878e5, 0x9bf3d9eb, 0xa90fb8b4, 0x0d3e16f6, 0x9bc0a0a1, - 0xbe42123a, 0x147ea2f5, 0xa79dc6f7, 0xda185506, 0x7d436f3f, 0xf557f8bb, - 0xb09b2718, 0x1894435e, 0x6431397d, 0x327fdd56, 0x5553a779, 0x5d37a2be, - 0xbecafed5, 0x717d555c, 0xfeaa9278, 0x544b37aa, 0x54c8b2e5, 0xdfabfb55, - 0xaf9552a9, 0x6aa19819, 0x3df403bf, 0x4e37e3c5, 0xffbd52cf, 0x37f4e368, - 0x5d7d3e21, 0xefaa3bf4, 0x043f704f, 0x85237a09, 0x040bfe74, 0x53ac5ebd, - 0x9acd4f7d, 0x7c0e54b0, 0xac16fecf, 0x95f77966, 0xfdb16314, 0xdb52ec2d, - 0x28903713, 0x84b62be6, 0x40984f24, 0xbeba9dde, 0xf107afb1, 0x0f7ba97a, - 0x6be6b826, 0xc69754c0, 0x22633b51, 0x0d5c8220, 0xf1638379, 0xbfd6a5fb, - 0xa97fe480, 0xd5b837f5, 0xd4526feb, 0x54296feb, 0xa3cdbfaf, 0x0ac4ff5e, - 0xbc3bfaf5, 0xaa4ff5ea, 0xb27faf51, 0xa9febd4f, 0x9febd573, 0xffaf57e6, - 0xbaf506b8, 0xd7aab667, 0x7aa97b3b, 0x4b82735d, 0x74f1f554, 0xc849e820, - 0xf795bccf, 0xa453dbaa, 0x42e86268, 0x5f02d9d0, 0x8d63e603, 0x35487aef, - 0x4c7d3c5e, 0xf48f3c20, 0xe547d22b, 0x727f6e38, 0xa97aa0ba, 0xda325c6a, - 0x73c03719, 0xff6e04ee, 0x33b746fb, 0xd58afc84, 0xe6fbb1eb, 0x08dae4b1, - 0xd1f7c57d, 0xd82bea63, 0xf7869b47, 0xefd163d1, 0x59ea84bb, 0xfa357c1c, - 0x33b0eecf, 0x999a0e38, 0x5429ff3d, 0xd1db435d, 0xde141536, 0x743e6177, - 0x93cd77fc, 0x1df20fd1, 0x7183abd2, 0x7c1124ef, 0x7c5123ce, 0x755d89fa, - 0xf10165be, 0x645fb9e9, 0xc9a9e009, 0x7a0e5038, 0xa3fcc2ff, 0xee7c63ef, - 0xdd65d248, 0xe21c7207, 0x3909e33f, 0x49c9e5c5, 0xf2d10388, 0x27f71339, - 0x8ae2897a, 0xee29e7c1, 0x269bacf7, 0x5a259ea1, 0xd5b1e633, 0x9ea12edd, - 0xf60ffbaa, 0xf4c71f6c, 0x52e788da, 0x6e2ed781, 0xa13b301f, 0x62dd0e0f, - 0xadf890fc, 0xec7a8f68, 0x3fb4deb0, 0x47f98716, 0xdbb17f76, 0x25dce0c8, - 0x89c2b911, 0xdd7106c7, 0x7ce1fd61, 0xe0c8db9b, 0x4623a5db, 0xe264efc0, - 0x31f0fb47, 0xd63c8a99, 0xefd624ef, 0x17f05cd1, 0x7e6fcd9a, 0xa9f21aab, - 0xf472e0e5, 0xa88f7fdf, 0xb677f7fd, 0xffbfe84a, 0x3e9b851e, 0x1b8f76dd, - 0xef28b2f4, 0x1e21b802, 0xfbe8ed00, 0x04ab7754, 0xadafb1fe, 0xb10f3dbf, - 0xbfb25f76, 0x83087ea1, 0x3d60fe0b, 0x83367f85, 0xd281b7d2, 0x11efb6cb, - 0xfbc61ff4, 0xa969c76b, 0x31fc8106, 0xc097bb1d, 0xfb67af2d, 0xbb1ec3e2, - 0x7444cfca, 0x7a47380e, 0xf20e7b29, 0x9cc54fbe, 0x3474a0d3, 0x1fbafdea, - 0xa47cb065, 0x44c8b6f6, 0xe39e4b88, 0xdb87d771, 0x56b2c4de, 0x265e60f6, - 0x88e5f7dc, 0xa2ef5ef9, 0x4e7231f5, 0x63efd2b6, 0xeace8de4, 0x1e6bcbc3, - 0xbc608b69, 0x25efc753, 0x5ee3347b, 0xbfc63fbb, 0x6e38cef2, 0xc4831927, - 0x69b8429e, 0x4f4eff4f, 0x5a3f4023, 0x762a7cbb, 0xd3706d1f, 0xeef562fe, - 0x1b1264c5, 0xf6d9587f, 0x88fdc20e, 0x6743f7e4, 0x36127c86, 0x641b7c51, - 0xdf4d0338, 0xe511b86f, 0xaf76deaf, 0x1aa1ee07, 0xb7067f0b, 0x7e56217c, - 0xdf8e387e, 0xe7e5c5cf, 0xc9d16d93, 0xdb7b4e30, 0x5d6f0a80, 0xfdf1176d, - 0xc452369a, 0x7ac43fea, 0xf4828d4d, 0x42d28a73, 0xf27ae204, 0xc1fc0d80, - 0x10263ed4, 0x8db9d67f, 0xb8306f18, 0xa2e4bc18, 0x9e63e90b, 0x3e00c19d, - 0x1f4a4cbf, 0xe1d52fef, 0x4cbefafe, 0xefbfb62b, 0x780fe337, 0x29eadf29, - 0xc37fb41a, 0x61c7867c, 0xf973d3f8, 0x0fbf6449, 0x5d3e80e4, 0xd38538c6, - 0xf1d70b3e, 0xf027f6cb, 0xcc1137ae, 0x5a67d647, 0x5cb85ed1, 0x6a19dd38, - 0x8fe3c7bc, 0xffe509e2, 0xf74f1c7d, 0x93fcc83d, 0xf04fddf7, 0x4a59053c, - 0xe987caff, 0x87971c6a, 0xcf87c4a9, 0x082a36ae, 0x465eb00d, 0xed409fe2, - 0x8d8bd211, 0x82a7e04d, 0x80ecaf7a, 0xaa2788d4, 0xb9e1335d, 0x1764e2a6, - 0x6bdae3b0, 0x13c08b3f, 0x2f801162, 0xc109037b, 0xab98bc55, 0xf877c740, - 0xd7813959, 0xe565cc27, 0xe89f5e44, 0xef4ce563, 0x0035520b, 0xcb471716, - 0xca6f3ab4, 0x80bc7907, 0xfcf173b0, 0x84cd8d7e, 0x73ab0bcb, 0xdfd43566, - 0x8b9cf049, 0xaf09ffa8, 0x5f1eb34f, 0x637a0799, 0x0dfbfab6, 0xd6a90f1c, - 0x30d35de3, 0x17aea6de, 0xeb64acf1, 0xfbf137f9, 0x53fd7522, 0xf59b7bfc, - 0xd41a647c, 0x7fc7abe7, 0xac5bd79c, 0xca8def2c, 0x037f767e, 0xd78c7faf, - 0xc61ea09b, 0x5af5642f, 0x6f09df71, 0x18e1c9d7, 0x431e33e2, 0xbf33260c, - 0x233696f2, 0xbf3c57f2, 0x73f707dd, 0x9bf30d95, 0xf519297d, 0x32fb86de, - 0x5049dc98, 0x51debc06, 0x77a8a2e4, 0x37cc65da, 0x48f5bad0, 0x972b064f, - 0x871f9c27, 0xead489e4, 0xe4c64461, 0x9ae8a5f4, 0x9005f012, 0x0ff4596b, - 0xfbe33ae8, 0x918fe21a, 0x664de973, 0x83e58fe2, 0x39554e05, 0x5574cee5, - 0x5cecd77b, 0x74b5bd55, 0xcc9eaa92, 0xdc9f2276, 0x5ccbe9cb, 0x17aaa254, - 0x6d9065f7, 0xb59d9dbc, 0x554fe5d3, 0xa85f3bb5, 0x9f8d0224, 0xa3dc49ba, - 0x7c8231e6, 0x9b96d7b8, 0xb3f8fc0a, 0x4e440ab6, 0xf627e53b, 0x1ba7f3b4, - 0x54fa598c, 0xcb10b978, 0x7e583bcf, 0x879b7b7f, 0x9e087395, 0xab6f6faf, - 0xca2ef2c1, 0x69fcf09f, 0xdb9f179b, 0xcfa15969, 0x2bfda47f, 0xda1e9fb4, - 0xa19f943f, 0x3373c3fd, 0x3f9e1fed, 0xfd43fda1, 0x942fda06, 0xc170a69f, - 0x0fda29f3, 0xed31ffbc, 0xb44fca1f, 0xb6bcb0f9, 0x1f962e6d, 0xf3e3f36f, - 0x7c06b6b1, 0x8ad6d9df, 0x96db47e5, 0xb6e1f3e2, 0xdbdb3e20, 0x2f7d6256, - 0xf9e793a7, 0x2be7dc79, 0xf103bdd9, 0x219fdfeb, 0x9d2fbb61, 0x154a539f, - 0x3f2ab97a, 0xfc033fa7, 0xfceabd02, 0xc21fc054, 0x8c786261, 0x0668e387, - 0x91270fb3, 0x930b72c8, 0x1f07181f, 0x6159e7df, 0xae35fca1, 0x4e7bad95, - 0xd3eb145f, 0x4778d81a, 0x5c409db9, 0xce519241, 0xbb439b8e, 0xcaa45273, - 0xd007f2c2, 0x14dc430f, 0x5aece53f, 0x21e64672, 0x5725c00d, 0x331e3d50, - 0x397c21af, 0xb7809c18, 0x57fde0d1, 0x696d378e, 0xa75fbb2f, 0x6c0c2ba6, - 0xe2b6f666, 0xb9c63afd, 0x9f4cb0be, 0xef1f9f2e, 0x717498e9, 0x5224dd3a, - 0x9bf176f9, 0x8ccfa144, 0x31fef526, 0x6a89417d, 0xb8bda67f, 0xd1572886, - 0xfbd48b7e, 0xbdfe733c, 0x198cefaa, 0xf5eaa90f, 0xfaaa15ae, 0x1e73bbba, - 0xc73e0371, 0x6199b8b1, 0x210272f5, 0x4fdd85e4, 0x4ce65c20, 0x92738f36, - 0x605f7ec2, 0x133dff37, 0xd6797fbe, 0x5c65f1ce, 0x09f2fb8d, 0x482c560e, - 0x0f406a0c, 0x448bfc7d, 0x9e3b7f94, 0x7e9fa0d1, 0x40690922, 0xe6a64cde, - 0x015fd424, 0xf16b8c37, 0x942d26aa, 0x85a2898b, 0x8a2455f2, 0x7fba3afb, - 0xf5d264d1, 0x9ffad16b, 0xd9f2d131, 0x2cb3ff4c, 0xfa8c30bf, 0x67af80ba, - 0xadc7d881, 0xdcfde397, 0x37f44cc6, 0x7625cfa9, 0x874bfdf0, 0x970df989, - 0xc153ca3b, 0x46373e0e, 0x7dcda83e, 0x14058de2, 0x63b4b6df, 0x1fef14f8, - 0x9ea33457, 0x94cbcfd7, 0xf75e5abe, 0xd44faa7a, 0xf307937c, 0xcffa5b38, - 0x6b76e029, 0xff228fc9, 0x3c84e874, 0x9e411253, 0x893d970d, 0x3b1e6624, - 0x93c9deda, 0x11fa2151, 0x375f326f, 0x4ff95f31, 0x4bc87695, 0xd179e02c, - 0xf2d2db3b, 0x7f0fc7ab, 0x5074e3ef, 0xa0352248, 0x348b0b5f, 0xe074109e, - 0x31fcabb5, 0x2f2efca6, 0x4b930b9c, 0xf2c40788, 0xf785d244, 0xd57fc829, - 0x7c9a3e62, 0x50a21af0, 0x0d6ad8fb, 0x70d16093, 0x75fb84bf, 0xfce5cfbe, - 0x9c6af667, 0xec259c8f, 0x74e80f26, 0x1bd599f2, 0xacfc3a01, 0xf4d8c75b, - 0xd0bebab8, 0x2def504a, 0x1487d42a, 0xebcbee09, 0xe5407bc2, 0xc8c9122d, - 0xb9a63801, 0xdf7e83e7, 0xb63a416b, 0x9fc72fac, 0xe359b830, 0x0efc40af, - 0xc2357b28, 0x9aeda2e8, 0x82b7eb27, 0xf001393d, 0xdcbc0562, 0x430d5f91, - 0x1e2217e7, 0x2f79f217, 0xc8e8f3e4, 0x833fc21c, 0x70bc7887, 0x6ea2ef1f, - 0xcf528fe1, 0xaad2f1f3, 0xa2bdc36f, 0xff2d11ed, 0x3e352299, 0x5322e957, - 0x70c34be6, 0x66173851, 0xb8015c82, 0xd80f82af, 0x919f9afc, 0x941cc6c8, - 0x6f68356b, 0x3f306994, 0x9b2e9e3d, 0x8fdc9932, 0x7dd9d866, 0x4853eee4, - 0x93e5c3cf, 0xc2482c6f, 0x5bb333fd, 0x8fcb326c, 0x58957af4, 0xe12af7bf, - 0x72e7e45f, 0xa1de1ccc, 0xb127057b, 0x892b60bc, 0xb4bc87ac, 0x2bf5f6b1, - 0xdc707332, 0xb53d7de1, 0xa53f205d, 0x5c7988cc, 0xa13e44ab, 0x69995472, - 0x57384f63, 0xfa74e465, 0xf79d4da8, 0x6fcf9db3, 0x418f5f3b, 0xf27bc8a3, - 0x9cc716d6, 0xafeba9f3, 0x88963f47, 0xff720ed3, 0x1d59a0e1, 0xa4e46d57, - 0xaba87830, 0xc1f10cca, 0x6da7162e, 0xdd99bfec, 0xc7efbb6b, 0xed302f78, - 0xa87a0153, 0x57ebede7, 0x0b58fdaa, 0x5f91fa77, 0xf164fde3, 0x398a317e, - 0xe31fec3d, 0x335b62fd, 0x43c27ef9, 0x7b0e218a, 0x61de7562, 0x7277ec33, - 0x1f0f9e08, 0xef017da7, 0x81bba6dd, 0x974fb82e, 0xa3fbb114, 0x54ffd7e2, - 0xb2f11e96, 0x78efac53, 0x3ba5da2b, 0xd81c98cb, 0x2dfce079, 0x2b3f69e3, - 0xf9d52473, 0x3a399580, 0x29b7a75c, 0x97b3c37d, 0xeed19a90, 0xa9943b29, - 0xef726af9, 0xc1eff55a, 0x1c0df734, 0xff2828b6, 0x1fba035e, 0x4279fc3c, - 0x1451f211, 0x08c4bf7f, 0xc19930c2, 0x76b3e70d, 0x17993e6b, 0x676f0f4b, - 0x36ff58ca, 0x0d2f8ba7, 0xae1ab557, 0xa56f45b3, 0xfd7060cc, 0xb9c6e40e, - 0x5894f1f0, 0xb5c0467b, 0x03df8c7b, 0xe2abf0f8, 0x1fad42a9, 0xfa74f062, - 0x6ed3c3bf, 0xfcf0e8fd, 0xb3f3c395, 0x9b5eec43, 0x515ff591, 0xe1ab759f, - 0x647cfb3d, 0x0a49880e, 0x7f115fef, 0x182993ee, 0xebf8e613, 0x59f4e52d, - 0x078fe5ca, 0xc09150cf, 0x1e63577b, 0x924caf66, 0xbe5ca16a, 0x2cf77f00, - 0x02c3ef93, 0xbf9e3f1a, 0x4619ef21, 0x64d77f95, 0x9ddeba31, 0x878a8d2e, - 0xcf362cd2, 0xb2ea4703, 0xd8f1bfc1, 0x7202063b, 0xbfcf3361, 0x6bdecc7e, - 0x05a67b84, 0x425ca11e, 0x747d019f, 0xc7bc2811, 0x2a333f4a, 0xd3c651d6, - 0xc6d6f1b0, 0x4f188df1, 0x1564a73c, 0x3a557b32, 0x387385a4, 0x0b7daf6b, - 0x5b5b7fef, 0xfdeca32a, 0x1d5ff8d2, 0x5bf0ff87, 0x7a30b729, 0xe1459299, - 0x90fe916b, 0x0e5a6df0, 0x2a7fd148, 0xbd157c82, 0xa01fe71f, 0x4691ec78, - 0x8b2d29e2, 0x9f988bd1, 0xdb80bf98, 0x5c02dd76, 0x06bbdb07, 0xbca51a54, - 0x8917d0bd, 0xbcc1ff5c, 0x2b5c5f50, 0x654c73b3, 0xdafbae32, 0xee78a98a, - 0x17cf376c, 0x1fa35e89, 0x164477f5, 0x763dbc70, 0xb811b7f1, 0xafd83947, - 0x883ffbc3, 0x15bee03c, 0x8dff1fee, 0x5389f78c, 0xfb81aa7a, 0x391c0ecc, - 0xebfb009f, 0x843a59f9, 0x87973e7b, 0x35b51783, 0xc8ec1e78, 0x0c6d7667, - 0x6965d7fd, 0x89127db9, 0x35af39c0, 0x8b3cec25, 0xd603db95, 0x001b2723, - 0x43c56b7e, 0xde862906, 0x10196566, 0x68fa35ae, 0x17f6878a, 0x6125a7d8, - 0x7bc1ffe6, 0xb3ce8719, 0x5a1e19da, 0xbda10f4a, 0xf767ed60, 0x2965d635, - 0xb852ce4c, 0xe6f7d2f7, 0xebd99f89, 0x8e94bea1, 0xbdfc3b97, 0xd3d6cecd, - 0x4beec65c, 0x3fed7b5a, 0xc83ee1db, 0x471df844, 0x79f2efd8, 0x7292b80a, - 0x48dfbc35, 0xcbf81724, 0x5abe632e, 0x235ef86f, 0x2f82fbd8, 0x62d5cade, - 0x39f947bb, 0x0a2b4789, 0x4cae7043, 0xdb35b1d0, 0xcc1640ff, 0x0bc5f28f, - 0x7c44ef68, 0xf63f10d3, 0xdf33c862, 0x32e64525, 0x076f443b, 0x68d42c3e, - 0xe116fc54, 0x549e26eb, 0x73dda3fd, 0xa15da73f, 0x46423bf7, 0xfe4de702, - 0x22667178, 0x191da7d8, 0x1af3dec2, 0x259b5f01, 0x8c0e625f, 0xdc5a2ff3, - 0x72381e0f, 0xedc601bc, 0xbe02f3a0, 0xeb75f87d, 0x3a53b06a, 0x53e45eec, - 0xd0ecbe31, 0xfd60f5f0, 0xdf7bd6ec, 0xd4647f04, 0x3acdeec1, 0x11867538, - 0xd3b69fe8, 0xa07f3f40, 0x04f0f7fb, 0xfd1aa7e8, 0xb3ed0b06, 0x8b77c3a6, - 0xb011ff88, 0x6b75176f, 0x3c83f755, 0xc2c5e5cc, 0x8e12168b, 0xac2c2fd9, - 0x6b9e0ef8, 0x0131785c, 0xcfcc3fdf, 0xcfcc3fed, 0xf8e2edbd, 0x5f3f9978, - 0xfb8afacf, 0xde9c4f6f, 0x8eddfe4a, 0xbbf7c63a, 0xa59afd60, 0xfaa83d01, - 0xc73f5335, 0x687f64f3, 0x21b093b3, 0xf311de06, 0x98e1224c, 0x5dda8771, - 0x52709134, 0xfa32faec, 0x15af9e1d, 0xe6d0ffeb, 0xdd8e3c46, 0x1e1538ff, - 0x53cffb87, 0xff6471e1, 0x87ff5805, 0xf44bc2b6, 0xfe8c793f, 0x0ff05473, - 0xef8f9bf7, 0x7bac1dcf, 0xeef942d6, 0xc6c57860, 0xf7e14b57, 0x7bf80cf7, - 0xb7afa41b, 0xeeb9cf0a, 0xfa0e7822, 0x7a7ffd81, 0x1f52f21f, 0xc0f7aad8, - 0xe8ba8318, 0x7a28cf3c, 0x83d89f26, 0x789cef70, 0x87959dbe, 0xdeff1ceb, - 0x90ec8728, 0x942c6a67, 0x8ce7a0ed, 0x015a1224, 0x235297fb, 0xdf1139ca, - 0x34fefd12, 0xb392ab53, 0x46a17ee2, 0x68d87f9e, 0x26aff161, 0xac2cffab, - 0x574d12ff, 0x1f68cfcb, 0xf03b0ba7, 0x0e213b7c, 0xf888d7dc, 0xc5fb0c8e, - 0xf97d703c, 0x9b0b9c08, 0x0cffe397, 0x1509fbbe, 0xd1ef102b, 0x0fcdb15e, - 0xf38f79f9, 0xa6e3e47d, 0x2313db88, 0xf2d9753f, 0xba1bb357, 0xecb7e8e2, - 0x8cc23b77, 0x40d9757e, 0xcfc8dabf, 0x7ce072eb, 0x67bf00e3, 0xb9fb414e, - 0xde30f4ae, 0xfc275947, 0xf3e32b02, 0x601d3256, 0x54788b4f, 0x8217e402, - 0xdd86b0dd, 0x616f5853, 0x275ffae5, 0xba17b9e1, 0x8114b21f, 0x65add99c, - 0x071e22fe, 0x1e61cf3b, 0x02c9ae34, 0x7cf20efc, 0xaffdf397, 0xe7a7bde1, - 0x3a478e57, 0x0fe5ffa8, 0xddc31ef1, 0x0d9f4ce9, 0x3ea1b3ee, 0xca7837ab, - 0xddcd5ee1, 0xed6ecce9, 0x2509c395, 0xa3ec7631, 0xa7285519, 0x5e395e3f, - 0x19271b13, 0xc2e4cd9f, 0x94ffe11a, 0xce70e5a3, 0xf0d2e3ea, 0xdd3ea13f, - 0x1bdfc263, 0x53fdecd3, 0xbabfde39, 0x63bf80c6, 0xe277b551, 0x5fb0b9ba, - 0x1f31904c, 0x84d7b35b, 0xc55d9cf0, 0x6f8383ee, 0xef35ee41, 0xcbbf871d, - 0x62896f56, 0xd9b364de, 0xc1f10053, 0xc0dfbdfa, 0xf1389fdf, 0x902cc4f8, - 0x9593c783, 0xfb6fbc2c, 0x3a748a71, 0x26fbe3ef, 0x579df7b0, 0xdb6ab9e3, - 0x347f8b1a, 0x4bd088ff, 0xedcdf7f1, 0xd73e2f4e, 0x6899f807, 0x5e1c80f4, - 0x675fe438, 0xbfd607f7, 0x24a59d19, 0xf306ffa0, 0xa7edea17, 0xeb1df7f0, - 0x49dd8fbb, 0x42e93e30, 0xbcfb15fa, 0xb9eb71f8, 0x8faddafe, 0xd5df83ce, - 0xf8e76fab, 0x59f7bfe7, 0xdfc629af, 0x5ff8149b, 0xf31f7713, 0xc5de38f7, - 0x1911c4f3, 0x76a4b9ef, 0x8ff81645, 0x2037ec4e, 0x33589dbd, 0x1057ef19, - 0x5853d5e3, 0x8f4f94ed, 0xb029953b, 0x15b20bbe, 0xb676ff36, 0xe9ef157f, - 0xbdf811f8, 0x2d3ee8ce, 0xda0dafe6, 0xc71009a3, 0x7944ed14, 0x5afd3e68, - 0xddb7bdfc, 0xdd7007e9, 0xa0115d29, 0x6d2fcd2b, 0xbf03b7a8, 0xf71bbf64, - 0x82092971, 0x8ef8349f, 0x077bf701, 0x9ed019f7, 0x9d977c1e, 0xef711fcf, - 0x059a359f, 0x7e06dcf7, 0xdae50e39, 0x0b746660, 0x784dbfb3, 0x51e0e4cf, - 0x5e3cd5ff, 0xd1efc69c, 0xefbb034c, 0x18533ec2, 0xc4fa3eec, 0x6c9043b8, - 0xfdfbe373, 0x882fbc16, 0x24f9d93e, 0x7f1b8f69, 0xf1748937, 0xfdf823ef, - 0x09fe5903, 0xc81fa720, 0xe15bfda3, 0xeed893fb, 0x4affae42, 0x9211598c, - 0xc74bc7ce, 0xd9fd337e, 0xccfa5ef8, 0xa80f7ecd, 0xb047d78b, 0x5ff0603e, - 0xbdf8f38d, 0x328cf48d, 0x5f7aafcf, 0x49d97de4, 0x6e028eb8, 0x23b4678a, - 0x93d2f1e3, 0x029ff6cd, 0x3974f11f, 0x80979eb4, 0x7832fc0f, 0xb63ec0bf, - 0xea26ab8e, 0x9ce93c99, 0xde32f68c, 0x27931430, 0x07df7cb8, 0x3a839748, - 0x97a0d3ef, 0x847547a2, 0x2d48c3dd, 0x5457f003, 0x16f576b0, 0x7010f7e6, - 0x07e7e19c, 0x1e593b1a, 0x3ee799e1, 0x856f9ac8, 0xa81ff3f3, 0xff0bcfce, - 0x0124ed21, 0x8f5633fc, 0xc4575092, 0xc22d76ec, 0x6e8f7ec5, 0xdfc14e8d, - 0x3e3e0c0b, 0x2712fd11, 0xbc5ecaf4, 0x15d57607, 0x6d27a01a, 0x4fbf9731, - 0xfb8979b0, 0x6d3dc4dd, 0xc81978f1, 0x99b2fa66, 0x3b82eff8, 0x25138ffe, - 0xf14b0785, 0xff744abe, 0x52cd206b, 0x7e589af6, 0x9185ea3b, 0x2fea42f7, - 0xff827bf1, 0xb053e5bb, 0x9f806556, 0xd5e80260, 0x7fb676d3, 0x40225bc4, - 0x3cd96bbf, 0xb803e03b, 0x4ef882ff, 0x5bc45e83, 0x4e1e2825, 0x9e3eac4b, - 0x1bbc84ce, 0x1ba00f81, 0xa3be17e8, 0x9d9e7f7d, 0x763ff6c3, 0x17943f27, - 0xaa5e43d4, 0x490157d0, 0x0f7dc0d6, 0x024a1d27, 0xcec9e5d0, 0xc872e73c, - 0x292871f7, 0xe076f6b1, 0x0e7bc110, 0x73ff3814, 0x922efc35, 0x05f80a77, - 0xfed53b77, 0x5e787888, 0xfd401ca8, 0xc6985ff3, 0x800053c5, 0x00008000, - 0x00088b1f, 0x00000000, 0x7db5ff00, 0xd554780b, 0x733effb5, 0x79332666, - 0x84841e4e, 0xe4249840, 0x09308401, 0x0741410f, 0x68151048, 0x85280978, - 0x42100793, 0x17b6881e, 0x240cdb5b, 0x41b45a20, 0x768bd151, 0xb4544140, - 0x03414141, 0x58a50077, 0x56d56351, 0x880dcb6d, 0xa8311fbc, 0xadadff97, - 0xfb5bf5ff, 0x90ce649c, 0xf9b7b5a8, 0x67d9d83e, 0x7b5ad7bf, 0x3bdaf5ed, - 0x3f437cdf, 0x756109d7, 0x10f4422b, 0x116dce22, 0xa3109862, 0x42f382dc, - 0x11c885d8, 0xca8df3fc, 0x5c3adb89, 0x8df88588, 0xdaf9aaaa, 0x2bc89eb5, - 0x1f5c2deb, 0x774675e3, 0xb5f1bdf1, 0x28f250ff, 0x084c21b3, 0x5d3dfe87, - 0x1e310f88, 0x90ea7b8d, 0x460ca7dd, 0x09ac2e1a, 0x75ac5442, 0xa51a45fa, - 0xbacc4e6f, 0x4285e653, 0x5c6cc775, 0xe34ad899, 0xca2a6f96, 0x1fb29112, - 0xd0aaf341, 0xea9e55e7, 0x0a8752cd, 0xeaa8f6d1, 0xebf684da, 0x6a8f9e55, - 0xa51eb8f3, 0xdbd627ef, 0x9fa9cb5c, 0x273e7d0a, 0xc5d16b7a, 0x0ab794b9, - 0xf280bdab, 0x45da2d56, 0x54782efd, 0xb177f62d, 0x81f7aa3e, 0xf80ba0b5, - 0x3a894d60, 0x1ea8327c, 0xe39469d6, 0x7268f7bf, 0xc2fcd157, 0x63cc77e9, - 0xd1f7e2a3, 0xd1f44efc, 0xfc7f21e6, 0x82b13093, 0x45daeaf2, 0x2bdceed1, - 0xa1c27de1, 0x01727b45, 0x031eb95f, 0x18e3a19e, 0x7808bcf0, 0xbabd20c6, - 0xabf04bc5, 0xa0f5487d, 0x4be6bece, 0x98df80d1, 0xae47453d, 0x61b5f7c1, - 0xecda8c22, 0xcefe9c3b, 0x8b8f34ad, 0x3d4155ab, 0x193dd28a, 0xdbc68289, - 0x2e7cf96e, 0x4dbf73e0, 0xd2917acc, 0x47a7b7d2, 0x46fd285b, 0x21f51fa7, - 0x6a352709, 0xae7cf47a, 0x98b93edf, 0x9edcc7f2, 0x7aa082c4, 0x2ce9d63f, - 0x6b655f14, 0x718d16ff, 0x78d8d62a, 0x2e5e065d, 0xbf341d62, 0xfe118d8b, - 0x8b9704e5, 0x5fb8dbbd, 0xbf464f03, 0x4183c015, 0xa56f544f, 0xe38fa5db, - 0x114717b3, 0xe1b4d35c, 0x64e82e9e, 0x2e3483c1, 0xe51f5bfa, 0xff7de675, - 0x74780d71, 0x25969be0, 0x8f03fc0c, 0xbc6da44f, 0xde59be97, 0x93d10ab3, - 0x7d78d0e0, 0xcbdf42aa, 0x850984f6, 0xda532bfa, 0x9c09288e, 0xac14fb77, - 0x8c3cf17f, 0x9871f657, 0xf7c7e505, 0xf3c79f5e, 0xc12bc10a, 0x7a2bb529, - 0x96d698bf, 0xdf8209ea, 0x736d3ec5, 0x7d06be79, 0xe79bce74, 0x4c37bb51, - 0x4c5c5f60, 0x76467c23, 0xf801b1c2, 0x5df5c619, 0x6f6fa676, 0xb1d7e01e, - 0x7ac8575e, 0xfdeb215d, 0x0b7d3040, 0x29ebc68f, 0x82cc24ff, 0xdc0fe5ef, - 0x71a6e594, 0x8e3bdf8e, 0xce3c75d7, 0x75fd879b, 0xcffa953c, 0xe59d72bd, - 0x733ad00f, 0x8d9d65bf, 0xb757c64e, 0x7b6b8ceb, 0x3acb7c42, 0x6874ea37, - 0xab33f3ac, 0xfa8ada3b, 0x9cb155bb, 0x14fb6a8a, 0xcc8d7fdf, 0xd0d056bb, - 0x0f4936b5, 0xfc236bb5, 0x6685d7c0, 0x6e7f04db, 0xf1a01f27, 0x583d27be, - 0x8f8e1e98, 0x023c3f75, 0xea9f75f4, 0x9701b9f2, 0x9cfcef21, 0x57efc7f2, - 0xb1f9025d, 0x0fc47e12, 0xc70fe02c, 0x73278b53, 0xb5cdaf7e, 0xb4f9fa82, - 0x047f6ff1, 0x63dc5cfd, 0x5f5e0b73, 0x90b3fdf1, 0xaf82f9a7, 0xc66e5c11, - 0xebce54b8, 0xd619ef57, 0xe8f17288, 0xbba65760, 0x0214be0b, 0xaa358ae7, - 0x01d21f69, 0x3ed5e3c1, 0x3ac6e290, 0x8713380c, 0xa83a9acd, 0x4fc81e13, - 0x9709d41f, 0x9ad0bb5a, 0xfb12fbf8, 0xfc414194, 0x9749f00c, 0x3cff44e7, - 0xa2d2c7c9, 0xc873f683, 0x8ff942fc, 0xff48cf51, 0xcc57c1d2, 0x705178fc, - 0x1950e09e, 0xc21c5f92, 0xca42aa37, 0xb7ca43ab, 0xf99cfaf7, 0x13f8e840, - 0x31bee4d3, 0xc3aa58e0, 0x9145bb71, 0xc53ee47c, 0x2d7e89bf, 0x4bedbab5, - 0x8e2ffe69, 0x4fd0f311, 0xae385599, 0xced97de5, 0x8ab52beb, 0x7c02b086, - 0x633d70f7, 0x435fd4dd, 0xc3e51c58, 0x7aa21f25, 0x7941ec13, 0xf31adf83, - 0xf0934f09, 0x5bc5d230, 0x83c78d9d, 0x14dd59e0, 0xeed7ca6b, 0xee3c6e4a, - 0xc62fcce8, 0x6ff4c92f, 0x387ead22, 0xaa7f22e0, 0x8c1eb577, 0xb249fa20, - 0xd469e168, 0xff83c5ef, 0x66eb9d1b, 0x262f0fbc, 0xe9a816fc, 0xf5a61d2f, - 0x3d56edb6, 0x9befd09b, 0x5f11fcf2, 0x1b787a5f, 0x9bd9af7d, 0x7775ee21, - 0x8e143fae, 0x8a5d7717, 0x17efa74e, 0x05c3d90e, 0xcda501c9, 0xd1ed63f1, - 0x84babfbc, 0xbb875bbb, 0x6b05dfd1, 0xa094f46b, 0x6b44177a, 0x7a20d4f4, - 0xa975dd29, 0xfc31e44e, 0x1f106a7c, 0x8f4f74ff, 0x2f7d2ab1, 0xb1af7dfb, - 0xe9c74a16, 0x736fdefd, 0xe686b93f, 0xe61ddbed, 0xbef34cd9, 0x0b2ce6f0, - 0xb3785fda, 0xea7f4f42, 0x4fb3f4e5, 0xb47e3153, 0x31bbd245, 0x293488de, - 0x8e59954f, 0xfc1a313e, 0x699ed5ff, 0xe59d69f5, 0x2c829665, 0xad9b79e0, - 0x7de62e6d, 0x95ab1141, 0xc67eceb8, 0xfdb9b9a5, 0x9f27dd85, 0xf4f87f00, - 0x60053efe, 0x6776172b, 0x7e5469e7, 0x5921e3e1, 0xc2f7ea2e, 0xf01ec97d, - 0xf7366d85, 0xeede994f, 0xdf60f289, 0x9c61fd1b, 0xf77fe825, 0xa435c355, - 0x52f9cb1f, 0xe3934f3e, 0xce8294fa, 0xee2da37e, 0xbf028f5f, 0xb3cdbdf8, - 0x7fa59299, 0x8b19e8cf, 0x773f61f5, 0xd5b28781, 0xe26dc261, 0xde782b27, - 0x8763c2a5, 0x1172841c, 0xa2e55f44, 0x6fcfbf98, 0x405f7f34, 0x17df027c, - 0xaf7f37ae, 0x5aab8d10, 0xfc8b7d69, 0xf682efe6, 0xfb112f8f, 0xe269f8da, - 0xd6f17ef3, 0xf54cc26f, 0x0fe74f84, 0xa5c7e60e, 0xc7c11fb4, 0xfefc579e, - 0x3defc015, 0x7433af2a, 0xd2d3cb5d, 0x448f1d78, 0x6b6e63fc, 0x598f5e10, - 0xe0893584, 0x1c2ecc7a, 0x47e80549, 0xbeab9c08, 0xcdfe613d, 0xfedee4d4, - 0x3296a55f, 0xe0b24bdf, 0x05c3b83c, 0xedfd47ce, 0x7e8a9939, 0x791756ca, - 0x77e6835b, 0xe47de6d1, 0xdf5790e7, 0xf54d7e23, 0x37f58d8e, 0x1d79a58e, - 0xd4f557bb, 0x33af3177, 0xe3f99f24, 0x28f71e09, 0xf2843fc2, 0x2d4c9ccf, - 0xde9cbc21, 0x34b5327c, 0x3115fe98, 0x8d1e982b, 0xebc26694, 0xf489ac82, - 0xeb05ad18, 0x89d7ad09, 0x0d7cf35f, 0xb1553a78, 0x787a2ba4, 0xe54f7414, - 0x05577f39, 0x3d9acee4, 0x33e83f36, 0x0f17e362, 0x6cfa0adf, 0xda40b9b6, - 0x2f547bb5, 0x5bb174e4, 0x1ce267f5, 0xba34fe6b, 0xeecce712, 0x68352e21, - 0x170e74dd, 0xb0b97ce3, 0x596252eb, 0x1933f72e, 0x9eed44f2, 0xdfa03c87, - 0x5cf1e6ee, 0xf1affa9a, 0xff99af3f, 0x20fdcf9d, 0x81f046f1, 0xc0b2278d, - 0x3e0f89df, 0x99fd8697, 0x791db5f5, 0x83875a21, 0x2c7e68fe, 0x7ff45fbf, - 0xa3a5f2c5, 0xbbfaf559, 0x349ec3c0, 0x07ffc33b, 0xcd026fcf, 0x7e73b12f, - 0xe03d9f34, 0x6b3cc6cb, 0x9c766ddc, 0xd11d17b3, 0xb4a7e079, 0x89f989a0, - 0x06e4f9fa, 0x289b2d7f, 0xee16bf88, 0x09c2bf9e, 0xf151a179, 0x6f280f40, - 0x2adcf956, 0xddfaa0df, 0xecc29784, 0x213bf6bb, 0xe5443e9f, 0x3abc74d4, - 0xa8b38fea, 0x54fbc2fe, 0xf8dbefce, 0x80da3fd3, 0x11360dd7, 0x47863c06, - 0x63c7d26f, 0x3e916879, 0x37cd45bf, 0xb7a0569d, 0x013d51ec, 0xe51cdfb4, - 0xd5b2f7c1, 0xf4c163b6, 0x50bf1f35, 0x2bd7f37f, 0xf81a40fe, 0xc2fcb984, - 0x27ce9f30, 0x5c6fbe42, 0x027f7535, 0x89eb2b52, 0x72e6fc8b, 0xf34ebcfc, - 0xdf7fd5a9, 0x17a6b99a, 0x29c173f0, 0xabf60b44, 0x1df595b5, 0x054d6811, - 0xfeec2f1e, 0xac78152c, 0xb27ff57d, 0xebf81744, 0x51cd4fd8, 0x84222709, - 0xc6e74b38, 0xfdd01637, 0x5dc5c9a5, 0x8fb17fd4, 0x6d5b17dc, 0x63905ebe, - 0x8afc6ff7, 0xddc5c1f9, 0x17575f5a, 0x5fb9dbf4, 0x124b4e7d, 0x205380d2, - 0xbae4da1d, 0xe484fb11, 0x1f417bc1, 0xdd4d569b, 0x6be77944, 0xa2424836, - 0xf7923336, 0xfcc7f60b, 0x7d8d7ea0, 0x017c15b2, 0x1fc930e9, 0xe523ec5e, - 0xbcbad584, 0xfb5f75b0, 0xe62ecce4, 0x26cd3ab3, 0x923edbcf, 0x2b4dcc6f, - 0x9c874f0e, 0x0345f161, 0x75ebc21f, 0x157c1027, 0x97eabe9d, 0x3df0512d, - 0xda723449, 0xfa71345b, 0x245a10b8, 0x0b8f0bea, 0x4fa21670, 0x7bc7e02c, - 0x31abd79e, 0x8e89fcdf, 0xd06af03b, 0xf8562f83, 0xeaefd337, 0x63508746, - 0x46b5ed20, 0xa0d451a3, 0x4beebfa9, 0x540fb6e5, 0x3ed49fd6, 0x2e3d3e06, - 0xc8cbf7e0, 0xf8c131e9, 0x74b877db, 0xdeabfa02, 0xf52e7a49, 0x4d877e77, - 0x5957a004, 0x3d50bf69, 0xec2fe1db, 0xcd4be069, 0x5cbc808a, 0xaf7c794b, - 0xfaf5651d, 0x9792e083, 0x9a91e12e, 0xbb70c59e, 0x9a1ef560, 0x9573fa08, - 0xdbd721da, 0xc04f970e, 0x2a4b6379, 0xfb5e63b5, 0xa4758f0e, 0x56b16f01, - 0x9aab37de, 0x5c5b718d, 0xf62a3fe8, 0x436f9e03, 0x534445ae, 0xc28f86bb, - 0x874c0cfc, 0x3a6143e4, 0x85021b5c, 0xf817770e, 0x14c289f1, 0x77ca8231, - 0xcf3013a8, 0x1752aef3, 0x958b68f0, 0x9b308776, 0x9af40277, 0x78b8d8b0, - 0x7a446fcc, 0xabffcf06, 0xcf3c25d8, 0x80bc48af, 0x7af241be, 0xbd0df231, - 0x7d8655cb, 0x8fbc23e3, 0xfc721d6b, 0x9f2a3da8, 0x43a462a3, 0xbbefdbe7, - 0xc89c68ca, 0xd024dabe, 0xa89f3183, 0xf00baf61, 0x858b1ce7, 0x3786b3e5, - 0x2f80d722, 0xd21be518, 0xf819bd25, 0x75609958, 0xae3c7f81, 0x574ae7d3, - 0x6820a3b1, 0x161eb69d, 0x0ec55e1d, 0xbdbb69c0, 0x97ce10f8, 0x738efa36, - 0x54d27f73, 0xaa14f407, 0x273f4167, 0x64c768ea, 0x0ee9dfa3, 0x424177c0, - 0x5bb478e9, 0xc2ac9628, 0x5eb85b7e, 0x3e208115, 0xe39360db, 0x211cb82e, - 0xc73a4302, 0xe3f8405d, 0xf9a397f6, 0xd653837b, 0xfb92886b, 0x2974cee7, - 0xd3d4ae2f, 0x83fa7ab5, 0xccc7baf9, 0xfec7cfd7, 0xe4a94b71, 0x53a677ef, - 0xeb4ad5bf, 0xab268878, 0x80edda92, 0x973a89ef, 0xcd058408, 0xc6758af7, - 0x38d0408b, 0x3b2ef51d, 0x183e2045, 0x47c66e1f, 0xb9237ae7, 0x125d44fc, - 0xfefbb1c3, 0xec704c53, 0x04c33fec, 0xcffb2bc7, 0x7513f2e2, 0xffd1df39, - 0x4ffa6ec0, 0xb3bfcd33, 0x5dfc7edf, 0x82fad2ec, 0x22eddcbf, 0xd374c07e, - 0xbb2676ca, 0x7606fda2, 0x9871f12f, 0x95f7dc80, 0x0576cb53, 0xe96d87f1, - 0x0b9f5d76, 0xfadf80a4, 0x6b4e3ac4, 0x8f1a5d77, 0x0be26ef6, 0xcbd0e76c, - 0xcf1b456b, 0xfa02fc13, 0xbab648bd, 0x96977cb9, 0x98c8bd0d, 0xf33c8747, - 0x859f48bb, 0x9ed841f6, 0x1f6347bf, 0x4db6b45f, 0xa9aa7d86, 0xde088d59, - 0xfdf407d7, 0x17cfb631, 0xd5d7b079, 0xbdf11da0, 0x9c5dee9f, 0x84d4f80d, - 0xde61e5b5, 0x2dfef7fb, 0x57c8e70f, 0xc5f7167b, 0x9f54adf7, 0x5b7b0fe5, - 0xbfa8278d, 0xb3e5c27e, 0x9b4ce88c, 0xfa1ffdf5, 0xfa9eeb7d, 0x36c7985e, - 0x2e483dd8, 0x56f659ac, 0xb078f1c6, 0xe083ef21, 0x16f8825f, 0xa6bb43eb, - 0xdf2063a9, 0x0f32487d, 0x96ee87e5, 0x3ed0c372, 0x83496fc2, 0x2ce1f7dc, - 0x619a89f0, 0xe1541776, 0x9616fcf0, 0x3987c3b7, 0x9f9f385c, 0xebc193ed, - 0xc84e43b3, 0x78a2fb40, 0xf154e7a6, 0x1b6dc9af, 0xe04ff642, 0x68db350f, - 0x75b56abc, 0xf78538f2, 0xa9f031d1, 0x78bfb79a, 0x135fd747, 0x8c5a9f81, - 0x5f78f04b, 0x432127ef, 0x9a7a893b, 0xabbef5a3, 0x9b8cdea8, 0x1fa15393, - 0x99fae895, 0x19404898, 0x1068fcc9, 0x9e5720ec, 0x7a0f52db, 0xc034d14d, - 0xf0ec97c1, 0x981afce0, 0x71c91c22, 0xf4fed0d8, 0x57ee34a9, 0x2ec316e9, - 0x03de60aa, 0xdf3d35f4, 0x2c6969ab, 0x38fe939f, 0x3b3fd1d0, 0xfbc325ae, - 0xa30bf077, 0xdf3787fe, 0xe2eb483a, 0x79e430dc, 0x36e9bdbb, 0x3aadb3cc, - 0x9847f592, 0xc9eed0f3, 0x2a02c39b, 0xc8b68aec, 0x3fe7d0d5, 0xb07b988a, - 0xfee3c107, 0x83222d28, 0x799acdda, 0x95e42ac3, 0xa5eef1fd, 0xd692e7a0, - 0xd3e7c0e1, 0x83262d4e, 0x6872afc6, 0x8969137d, 0xd968fbe7, 0x8be43831, - 0x449e25e3, 0x2ee2a0f1, 0x53e72fe7, 0x0ff1c8a2, 0xe8496947, 0xf2d2c4a7, - 0x66f855c4, 0x837b616d, 0xfdc1e868, 0x8a8bb79c, 0x037fe4ae, 0x75f4470e, - 0x6b89b3ec, 0xf6fad32f, 0xd4f18dad, 0xefcb7cd3, 0x96b7399e, 0xe296f9d2, - 0x9a6a80c4, 0x55d61677, 0x9be92be5, 0x79f3f24c, 0x65ef3e9b, 0xaeadbcfa, - 0x1cfde0ac, 0x437aef3a, 0xc285f95e, 0x50ff20fa, 0xac5f15fe, 0x87ca5eff, - 0x307d2e59, 0x20d6e70d, 0x3649db0b, 0x22ded384, 0x7d5df23d, 0xbed38f9e, - 0xf7f1c473, 0x149ef8d5, 0x3d27db2e, 0x7ec3f16c, 0x37763c50, 0x9ac9e9e3, - 0x634a8f48, 0x1db70895, 0xf0995072, 0xd9fc5cb2, 0x69edbf98, 0x661575a5, - 0x6e01d768, 0xa92de2f3, 0xb43cf01f, 0x6f205381, 0xf8eb928d, 0xd7937916, - 0x6cb85531, 0x3589942c, 0x531fc816, 0xf329725d, 0xa63fb915, 0xe30daf09, - 0xd71a10cd, 0xbb05c3fb, 0x1fc4fa17, 0xbcd10ba0, 0x7f1f0a67, 0x9cfc2d9f, - 0x5c022ade, 0x95a2c7ff, 0x89bc06f3, 0x4825e63e, 0x53d938fa, 0x8cdff865, - 0x9117bf79, 0xad1967d7, 0xd923ca63, 0xad5fac99, 0xf9f0c1eb, 0xd14f79ae, - 0xeff686e9, 0xfd83f43c, 0x99fa9d3b, 0xfec8637a, 0xe061ec2d, 0xf6dbf333, - 0x877b4b51, 0x4c9914fe, 0x475eb870, 0xc5def5e9, 0xa9153fac, 0xf847c291, - 0xfaa51969, 0xf21c7721, 0xa0484f2e, 0xb9fddc75, 0xb77e83d4, 0x843dbc5c, - 0x46377fca, 0xd2dcf515, 0x64d4f2cb, 0xbdc99fbd, 0x9d869fc7, 0x2408b0f5, - 0x17b9a50c, 0x8f5ed65d, 0x564ef9a1, 0x52c435b7, 0xa4de84f9, 0xbdf104c7, - 0x5bb6121b, 0xd8ddd7a1, 0x627dfccf, 0x99df59ae, 0xc0551a24, 0x7350f279, - 0x0f807dbd, 0x0c8ad7d1, 0x0188b7a9, 0xdfee8062, 0x47fbb963, 0x13ed1f7a, - 0x0be1d92f, 0xbb433579, 0x3a5c7007, 0x18b9b3e9, 0x7ae55857, 0xd951de6a, - 0xe48c779e, 0xdf9d2f2c, 0x84e8ebc7, 0x08f29308, 0x6e48a7f2, 0xcea67a40, - 0x3a39e9cd, 0xa17e51e7, 0x67eb23ce, 0x7d803f14, 0x73faba56, 0xb772f02b, - 0x6ef9c253, 0x761faa67, 0xc6a68ab5, 0xe55e98f1, 0x4883a6ae, 0xe3c503cb, - 0x382ecc71, 0xd220e4b4, 0xb6f43bbb, 0x5fdd0e25, 0x5dbff3c0, 0xa3dbd3a7, - 0x8834dea6, 0xbbedc9f6, 0xf6ebdfa5, 0x4da7533e, 0xc6de404a, 0xa8e8eef9, - 0x3422b2fa, 0xa8cf22da, 0xb758cdde, 0xc1e8f9b7, 0xc9e75a78, 0xff3c11ba, - 0x9e5e75d3, 0x09bad9ff, 0xa33dfe9c, 0x27ae39f8, 0x6c79673e, 0xd6a3b6d2, - 0xe45faa14, 0xb7d8bc55, 0xdf857ad7, 0xdeb1744f, 0xf581cf26, 0x1f600e74, - 0xf534198f, 0xe9303bf1, 0xda276d0c, 0x5171b8cf, 0x3c99c611, 0x7a8ac4a2, - 0x2216bf33, 0x4e93ad3e, 0x8dee8bbf, 0xf8eb57f5, 0x6157bf3b, 0x1bdf9e78, - 0xdf6cf0cb, 0xf9031191, 0x8ccee960, 0x6f89489e, 0x046f7a1a, 0xd97ed7e0, - 0xff6df3c2, 0x8ef59c28, 0x774bf6d0, 0x7a89ec0e, 0x22df0967, 0xfb3cde48, - 0x83b87ffc, 0x71b395cf, 0x027d5f4d, 0xc957f6fe, 0x39b248df, 0x5ff818f1, - 0xd01e5eef, 0xce5d05cb, 0x02233d26, 0x6e8d5fe7, 0x427f0457, 0xb4b86cfe, - 0x217f0ee7, 0x17f62c65, 0x9c1373c6, 0xb9191cc3, 0x7f7087c7, 0xfd467e47, - 0x9258fcbd, 0xb9effa07, 0x63a48fed, 0xf34dadfc, 0xfa8c793f, 0xf8b7ef3f, - 0x9d4e746c, 0x5e174d17, 0x2a7e1f05, 0x777bed92, 0x9c2f342b, 0x717b9bc3, - 0x86b1473e, 0x2c39c32f, 0x73cfbcfc, 0x1975b714, 0x17aaadf1, 0x7a05ed1f, - 0x30608d7c, 0x5b5fca82, 0xed7cc11b, 0xc8e79b35, 0xb8f7f432, 0xfbe9efec, - 0x0bb63cef, 0x05d57de9, 0x65fa5277, 0xa1e31c46, 0x034581fc, 0x79ce9ed0, - 0x3dfd4c91, 0x80128af7, 0xbad06abf, 0x69922b7d, 0x1c37837e, 0x34a2f4b5, - 0x1ea529ff, 0x373ec0e9, 0xf9fd821e, 0x6e6e196f, 0x9a5b643f, 0xd96d829a, - 0x75c9ffcb, 0xe59bfe7c, 0x9f75dc82, 0x3a25ed8f, 0x4a0183e5, 0x348d99d3, - 0x8fd4b0d7, 0x6386340a, 0x6767af23, 0x6ff7b4f3, 0x49075815, 0x8977981e, - 0x91e7c3dd, 0x7811b7df, 0x78e5af3e, 0xf62bbf58, 0x3b7a0a3d, 0x707a25af, - 0xfa4cbd3e, 0x7fa8d5fc, 0x7cebcac4, 0xa2f7a9e5, 0x2189df61, 0xbf09d93d, - 0x78db7e48, 0xe3eeafd4, 0xf587f016, 0x09fae279, 0x8ecd4f80, 0x9fb91b9d, - 0xfa07872a, 0x4bcec56e, 0x2f205307, 0x993c20de, 0x321dc7a0, 0xaf42abff, - 0x56a5a547, 0xe652fc6c, 0x5f398a5b, 0xfc27da4c, 0xca4ca2fe, 0xe7e88f49, - 0x63cd68a0, 0xee24c97e, 0xafd7c4ee, 0xebe518a8, 0xb0c97cd3, 0x27e71b6f, - 0xfda97b9d, 0xb2ec65b0, 0x5bd8cb7d, 0xdf2e1953, 0xebb3dcf3, 0xdfd197e7, - 0x73e17623, 0xdf303f52, 0xc1be9ec0, 0xcdebcf2e, 0x2f4067c4, 0xe34d79c6, - 0xed93f5e6, 0x29afe0bd, 0x076832aa, 0x91e523c1, 0xbe379630, 0x62b3f8ef, - 0x6df9f156, 0xe1b55bc8, 0xd9f22f92, 0x885fed41, 0x37eeaed2, 0x7932760c, - 0x3bab0bde, 0xe3c8f217, 0xfa6bde51, 0x96d5bcb1, 0x39d0358a, 0x53e61d7a, - 0x95fc92a3, 0x457f2411, 0x73af7dc6, 0x2de51034, 0x5beffb42, 0xcd046c7f, - 0xf1290633, 0x86a468ef, 0x485a45de, 0x7d39fc97, 0xf3f8135b, 0x3f926143, - 0xbe610d47, 0x7433ac64, 0x07c4039c, 0x6f3be234, 0x11a339d0, 0x3917183f, - 0x7d78cac6, 0x907552dd, 0x3922e5ce, 0x1ada0802, 0xdef3943b, 0x61638228, - 0x2eb42aa4, 0x252347f4, 0x3ac7cdbc, 0x984427c7, 0xc42515ea, 0xbf8fb1da, - 0x1d55faef, 0x3cb86a4f, 0x8370d4bf, 0x7413babf, 0xfac87dbf, 0x776f7ae5, - 0x3abe630e, 0xeb7ef956, 0xdf15b22e, 0x8b8f3c09, 0x7373e7cc, 0x2394e45c, - 0xd475e09a, 0x7ae87be1, 0x1c25d743, 0xfa8e4fdf, 0x167c2289, 0xedcfc7ec, - 0xb66b776c, 0x5bf73eb5, 0xa2f36b82, 0x47ec0f5c, 0x70bed32f, 0xb54e9f80, - 0x0cdb9cb3, 0x37ea92d9, 0x5c7170f7, 0xdfba6bcb, 0x6f5b37dc, 0xbe7c14ef, - 0xc5eecf34, 0x615ef47e, 0x48ec1034, 0xd26fd2f5, 0x16f25b6c, 0xe5e6ebce, - 0x819a1e29, 0x69efc150, 0x97e47ccb, 0x095ebcfc, 0x817f0adc, 0x40bb73ef, - 0xfeb175fd, 0x5f94e9d5, 0x9e0c8bf7, 0x8fa447cf, 0x8abc62d7, 0xeb5be670, - 0x71c9bd62, 0xff979f04, 0xb279f2a1, 0x91f29f2e, 0x6ed9d7cc, 0x378a6eb3, - 0x04ad7e19, 0x36eb6f1d, 0xb05ef2ca, 0x4d3ca293, 0x26c4ffb6, 0xd7a2dfeb, - 0xfbf1d04b, 0xb4a74eb1, 0x683f99ff, 0xa0ac2393, 0x95fb77ff, 0x46fbc6be, - 0x17e19378, 0x933cac7a, 0x54b7986d, 0xf4c690de, 0x66d3dba4, 0xe8dcfce9, - 0xc31c0d17, 0x9fcb4f21, 0x3b37f3d9, 0x2a33df41, 0x1f21479c, 0x22b1547e, - 0x0cfd7a0a, 0x21840d4d, 0x917a6abe, 0x4bae43b7, 0x395eb8c7, 0x1fa1b96e, - 0xdf00ca06, 0x710e6dbd, 0x81ffcb2f, 0x96fac121, 0xfa45e781, 0x1a6eadbe, - 0x7eb060f3, 0xfe27695d, 0x72e51833, 0x6a45573f, 0xd57d07bf, 0xc1e1baee, - 0x54fbbd60, 0xbc7943f9, 0xcf71f4ef, 0x3c1f79d5, 0x6f39099e, 0xb8c6a702, - 0xf011fa1d, 0xd5f6fd49, 0xefda73cf, 0xdaf00b3e, 0x92fa94e4, 0x85e3edb5, - 0x359faf94, 0x09f7cf80, 0xd85e1d53, 0x8477daf5, 0xadaf61f9, 0xc5ee159f, - 0x44f7eaba, 0x985761f9, 0xd21befa7, 0x6fbbf8bb, 0xade98dbb, 0x667feeca, - 0xdaabb50b, 0x89e99fdb, 0x96ed95e8, 0x642357be, 0x6d37b479, 0xf79450e5, - 0xcd79fa64, 0xf2e18ee6, 0xe5c15537, 0x58ac81e1, 0x539b7782, 0x1375853b, - 0xbcfdb2bd, 0x1fbf2eca, 0xfa12e9d1, 0x96fffb25, 0x42bf7144, 0x8f3f6bcf, - 0x584f7d67, 0x91f3c9bd, 0xaf207dbf, 0x7dcbb347, 0x7ea46a21, 0xe725c478, - 0x9e39a475, 0x8f4185f7, 0xdcb78a47, 0xef809593, 0xfcd2af24, 0x0d4cb2fe, - 0xd06e1fc0, 0xf2f5329f, 0xbb5157db, 0xd9555f4f, 0xd7e7336f, 0xfbe30f8b, - 0x13d5159c, 0x6bbcad39, 0xf5cb9f32, 0xa2eea71f, 0xa7a984f2, 0xe06bbfd8, - 0xd9954e7f, 0xe9989a9f, 0xdf813355, 0x83f6ff5c, 0xd9e1ff54, 0xaf001627, - 0x473533c3, 0xf6dbec26, 0x4cff97d6, 0xfe5d6df3, 0x36a3d627, 0xf8116b44, - 0xd3f7717e, 0xc566bf5c, 0x7e802cff, 0x74956350, 0xb5db9c63, 0x91bf3d3a, - 0xffa2c5a9, 0x63bf15aa, 0xb722223d, 0xbbd7f245, 0x3a3f1fbe, 0x65f9bcd3, - 0x0e2dda85, 0x54e1ae6f, 0xfce1e7f5, 0xa204ab3b, 0x2b860c95, 0x5ce775eb, - 0x47e06881, 0x72b948b3, 0xbf10d6f1, 0xa8925031, 0xdda88bdb, 0x8f5526e2, - 0x41dbf457, 0x17f5a1a7, 0xf7ae77d3, 0x8a57bf3d, 0x763df926, 0x30d7fdd7, - 0xfe0045fe, 0x64cf33ae, 0x9c3d026e, 0x5674f9df, 0x34369fb0, 0x72be72bd, - 0x7df4e7fd, 0xd8be8e73, 0xc2db6f40, 0x0b85f64c, 0xf4eb24cf, 0xc2e9e926, - 0xe7ecd933, 0xd9f7d44e, 0x0967c505, 0x085fbb47, 0x9e10678e, 0x971ce1a6, - 0x0e1a6de3, 0x9d61fbb9, 0x6f8e2e2f, 0x67be0e1a, 0x68e141f0, 0x41bb63ca, - 0xf41e534e, 0x8a7f8364, 0xfe2ca6e2, 0x42ca6fee, 0xd22d97fb, 0xa7cc630e, - 0x8e14b9f2, 0xf0b5a27b, 0x6e7caefe, 0x8de426e0, 0x929dea71, 0x253bd4ef, - 0xb75d097f, 0xe8ed2996, 0x1ee64fa4, 0x3ea4b3a7, 0x5c82f496, 0xde6593e4, - 0x370bf329, 0x6fe1d894, 0xbcc9b7af, 0xfd897d6b, 0x35f7e618, 0x4fc4b569, - 0xc5bf7473, 0xdda97f02, 0xfafefb0b, 0x3f1ce1e5, 0xcf3edb31, 0x7af6694b, - 0x035c69bb, 0xe6fdfd0f, 0xf9f48bef, 0x0b890df4, 0xedb6a5ea, 0xf639c30b, - 0x8e32e8a4, 0xb4a64960, 0x6cfb3ee3, 0xaa917c47, 0x6dc2dbeb, 0xea5ba1d0, - 0x8fd78c1b, 0xef5e06ed, 0x2ff9a148, 0x5ea5e3d6, 0xfab848b6, 0xe37c959e, - 0x052d7ce5, 0xc005d5e7, 0x2c5ce71d, 0xef2173e5, 0x7919bc49, 0xf0a15f03, - 0x82f1f15d, 0x9f95d814, 0xc7f694c8, 0x8f2c7c50, 0xe513de1a, 0xd4cf5c06, - 0xdc00ca1d, 0xa89d758d, 0x68e97af3, 0xafbfb4eb, 0x8c6877cf, 0x30477c8f, - 0x1d6fd77d, 0x20248872, 0xd5ab6e71, 0x5bd42583, 0xbf43f7fd, 0x36aadfa8, - 0x3b9704f9, 0x91739780, 0xbd41dffb, 0x0b621b05, 0xed180fa0, 0xf22fae17, - 0x7bcd0796, 0x5e3356e0, 0xf3993506, 0xf3997783, 0x0d06715b, 0xe5dbe7fb, - 0x21f9cc07, 0x93f9cc87, 0x3371dc1f, 0xea854fb6, 0xbe855fbb, 0x87f1e7f3, - 0x7a9f4e70, 0xe06895f9, 0xcb5ff16b, 0x0b8f420f, 0x3c21678d, 0x7c73d02a, - 0x97a6145b, 0xba5ae22b, 0xdc4643e1, 0x30627606, 0xdf0a54dd, 0x95da6b41, - 0xa68acff5, 0x6744bd9b, 0xcfdecb55, 0xecb37a90, 0x5ad36477, 0xd0cee43b, - 0x3be3bb71, 0xc6ebd222, 0x21192a3e, 0x365eaecb, 0xfe8a7c4e, 0x1e37bcd6, - 0x2bf258f4, 0x929be585, 0x075fb297, 0x3edd1cdd, 0x6f4e46fb, 0x30f0c09e, - 0x9b0b92ec, 0xe5144095, 0x8744235d, 0x8bf11f7f, 0xf1210da5, 0xe2426b9f, - 0xcb99d682, 0xf7daee17, 0x504710ff, 0xe38278e1, 0x678cae2e, 0x5e801ff4, - 0xb04a7959, 0xa9f2aa7d, 0xe5ccc26f, 0xf5f35d72, 0xade71875, 0xf1cb5df0, - 0xaacb577b, 0xa3fe38e2, 0x4ba8e973, 0xcb73853b, 0x5eaf7738, 0xf29551b7, - 0xfd84b7bc, 0x8e7691c8, 0x8876ac8b, 0xebcd0440, 0xebdd9450, 0xd697efa2, - 0xb2bcb147, 0xe85ce480, 0x270a948b, 0x627a4dc7, 0xbbc4eed0, 0xd565cb2a, - 0xd51e12f1, 0xb0fc51bf, 0xa8c3571d, 0x3293fc8b, 0xd80448bf, 0xf23a0bbe, - 0xf803ad06, 0x468bce0b, 0x59565fa9, 0x9f00fb03, 0xab68738e, 0xad155eb9, - 0xc838a3f3, 0x35efe67b, 0xd7eb8da2, 0x2c26faee, 0x3d907bf8, 0x435ef59a, - 0xf97556ff, 0x3865fd4a, 0x20744fcb, 0x6cbe8384, 0xeebedcba, 0x6823921e, - 0x7b0d2b7d, 0xdf295af8, 0x9e51b2dd, 0x679f2463, 0xd6eb4e01, 0xef867c92, - 0xce206fa4, 0xf70a2c44, 0xea5ef94b, 0x6766eb0b, 0xf2f45cb1, 0x400a5e3f, - 0x487b691f, 0xbad2bb61, 0xbaefd97c, 0x3973fafb, 0xe3c2a7f8, 0xb61cb184, - 0xde518a6e, 0x4f91f587, 0xc864c530, 0x1ef7faf9, 0x4bdefe6e, 0x3ec166f5, - 0xb2741e22, 0xfb90c47d, 0x2ebeb90d, 0x1ac9cb56, 0x75feb9d6, 0xf0516db1, - 0xf88a89bb, 0x6cb725ef, 0x36e3cfd6, 0x2afc3f5a, 0x83e295c7, 0xf5198ff0, - 0x73c96646, 0xef58f865, 0xfb1ebd16, 0x532dca5f, 0xe68ebdee, 0xc5b0fe55, - 0x81a17b0d, 0x66f5e107, 0xd7c70e01, 0x77400b3a, 0x7b4ac7c3, 0xc97c91d9, - 0x0a8623e7, 0xab1a378e, 0xcb363bf7, 0xc2934a62, 0x9fa91e89, 0x1ed245e3, - 0x98b4351f, 0x132496ed, 0x6e2aebcc, 0x4fdeb265, 0xf7f8bdb9, 0x4f98bba3, - 0x4a145d07, 0x6df8fbf9, 0x2f3926ca, 0x0e27c72f, 0xf6c9c07f, 0x39fae3ce, - 0xe881e064, 0x0fcb1868, 0x0d8b5f3a, 0xa0b59ba1, 0xa0879c07, 0x6e982507, - 0x8b7174cc, 0xee2be122, 0xbaf7f293, 0xe8379958, 0xf13ff482, 0x229ba0bf, - 0x4eeff0c1, 0xdbd6340f, 0x74481e9d, 0xd07408b0, 0x0e842f51, 0xec3fd584, - 0xa542fcdb, 0x2b876223, 0xab148284, 0x17ce21f0, 0xebc32467, 0xb11fab1e, - 0x12adbd78, 0x92ac7d2f, 0xf1b4e8ee, 0x7d701785, 0x4b7de22f, 0xbc285c1e, - 0x4524bf54, 0x1fad7db0, 0x713155c9, 0x45204edc, 0xbb0a8e58, 0x5f68a513, - 0x2ffb2312, 0xfe3829e9, 0x5af3fa8e, 0x36e674e2, 0xc15efe1c, 0x47da0572, - 0x9f7b7017, 0x5af7b645, 0x219bed29, 0x95b698f5, 0x5cbf1c61, 0x2c9f7772, - 0xb1c4c9d0, 0xa2393a66, 0xde9195d3, 0x8dd6ed94, 0xf0249e75, 0xfe86d283, - 0x3bd4de7c, 0x0277ab8b, 0xb047cf9f, 0xeab259fc, 0x618693c7, 0x7bc42f7e, - 0x9333c280, 0xa83fb3b7, 0x4ff661b4, 0xb4be843e, 0x2bdfc9d5, 0x59f5b5b2, - 0xf715ff90, 0xa1f49ddc, 0x7b01c674, 0x9ad7b512, 0x957f9ca6, 0xedbec9d2, - 0x989e40ef, 0xfae55d3c, 0x3fb48593, 0xce39068b, 0xd6e7df24, 0xd26fea24, - 0x69c38528, 0xa95d3a8e, 0xa40fc1b7, 0x2ca9f7e3, 0xe47f9745, 0x5592813d, - 0x73d2b27d, 0xc9213fe1, 0xfd390bb8, 0x18fea353, 0xa5e40365, 0xfee4e3be, - 0x1fa3ea33, 0x4b3a7bf4, 0xd5bf55ca, 0x09e462e1, 0x7cbf5cae, 0x8cd1d875, - 0x40b6a468, 0xfde9a536, 0x7584bec7, 0xe3174c4e, 0x77ee03d7, 0xcf1362aa, - 0xf984adb7, 0x1b965442, 0x4291abf4, 0xd6e3facd, 0x8f27ccfe, 0x7a3b698e, - 0x6e8fe537, 0x8ced241e, 0xbe617dba, 0x707cb04b, 0x77e48c74, 0x98239b6d, - 0x5ab88ffe, 0x3da4e2a3, 0x650ded8e, 0xb67c493a, 0xf87efeac, 0xed22cbb9, - 0xcc7e7147, 0xc71a687f, 0x53ad9427, 0x07b86103, 0x6f6cc6b0, 0xded48aa8, - 0xb5087ec6, 0x07da841b, 0xa3a03340, 0xd30a35f2, 0x8f7adf61, 0x9cf9993d, - 0xcafac2e2, 0x70fd0323, 0x9c7b940e, 0x857cc71c, 0x826be0fd, 0xb9d870fb, - 0xb5890705, 0x009f6b67, 0x258d254e, 0xe446efac, 0xfabfcc6a, 0xec1704aa, - 0x26fe9d17, 0xbe0b5ec2, 0xc64d6d64, 0x9655fcbe, 0x3130f19b, 0xc91595ce, - 0xfbe4ed74, 0xae6d4711, 0xe8efcc2c, 0xe705a74a, 0x9215c4ed, 0x39df69be, - 0x1ee18f70, 0x3f0708ab, 0xfb259ad8, 0x5adcb39d, 0xbdf291bc, 0x151ac21d, - 0x67cafa07, 0x5fd85efa, 0x75e62dfb, 0x046217ea, 0x35b289e4, 0x74bce56b, - 0x96d610fa, 0xe71a78c2, 0x02b4e6d4, 0xe43a01d8, 0xdb63fedb, 0xba0ec701, - 0x3d30ae98, 0xc10e7ad0, 0xbfde9c8e, 0xe9ca32f4, 0xcbd03efb, 0x7e81b1c4, - 0x522f1b88, 0xb6be38ab, 0xe078493d, 0x6d176c77, 0x93b48f2c, 0x67be023c, - 0x9f8319f0, 0x1d785d10, 0xdef89d89, 0x22534752, 0xceb5be1e, 0x75b3e9c1, - 0x7825612e, 0xe24bab6f, 0x6e750bfc, 0x72ea9b4e, 0x758bfbf8, 0xa8efce1e, - 0x97f9c11b, 0xdf9cbceb, 0xd3813755, 0xf98aeb57, 0x08afc1bb, 0x0c97cc3e, - 0x27f063be, 0x3e0cbe83, 0x73574a15, 0x17b8cc09, 0x1f99ed41, 0xeb107c1a, - 0xf27414b0, 0xe9cf0327, 0x092fb14a, 0xceb450fc, 0x5228ff06, 0x0aff3dcf, - 0x22bdb9c1, 0xed22ed92, 0xf6c1f242, 0x079f0748, 0x0bb176a9, 0xdbfa89f6, - 0x0eef47bc, 0xad6f873a, 0x88358450, 0xc4bc7f8e, 0x7441ac29, 0xac596f3c, - 0xd9673f29, 0xa4f46ffb, 0xd18ddffe, 0x1e69b372, 0xe2797e47, 0xf7d13ff1, - 0x4cf2fcdf, 0xf34ef026, 0xc608fcd8, 0x9f5c2bbd, 0xd79cab47, 0x9796765d, - 0x7d4b86fa, 0xd4b86fab, 0x08e3f0b7, 0xa23dcf8a, 0x2d24a3e3, 0xb1a79df6, - 0x9baeec6f, 0xb44ec047, 0xfa4bde52, 0xf2a3f804, 0x2bf8e8bf, 0x70c6165d, - 0xf7d06d2d, 0x36dc706b, 0xb258f5c1, 0xf14ef960, 0xd7bf010a, 0x03d85fb1, - 0x63882b24, 0x40afc38a, 0x6be52276, 0xab98ec0e, 0xe411f77f, 0x21d96576, - 0x4735b396, 0x087fc724, 0x705ced9f, 0x83b2ca7f, 0xf6b44f5c, 0x466fc536, - 0xc1daf50c, 0xc0e34037, 0x7ece695f, 0x1a2efd81, 0x547fbe15, 0x5f2f7fae, - 0xa2e298ad, 0xf2ab6467, 0x959645de, 0x4259f3d3, 0xf91a473f, 0x96e832bc, - 0x61c708f8, 0xdbe63796, 0xe7f10417, 0x597bfd52, 0xa714c58e, 0x9d967f79, - 0xcd8f39fb, 0x9bdefd49, 0xcf9f6e93, 0xf7cdcffc, 0xa5fa8c05, 0x60ab0539, - 0x835d2e4f, 0xf6cea6a8, 0x7d56d925, 0x7fa92e5e, 0x8b5ce839, 0x2ea2f8e2, - 0x9e4307cf, 0x475f8539, 0xef59fcf2, 0xb9e17caa, 0xac8fe017, 0x9f1873fc, - 0x75839553, 0x7fae4afb, 0x839634f8, 0x70ca91bc, 0xff12e1c8, 0x35fdcf85, - 0xb55d711a, 0x97bda43b, 0x6b48a3d2, 0xfb60aaee, 0xf6878d5e, 0xadf81c49, - 0xfaffefd9, 0xfbe67f0b, 0x14b0849d, 0xe3986e3d, 0x7c766ad4, 0xb06bf1ca, - 0x7286f9c7, 0x1d5f1c7f, 0xf956beda, 0x4257f59a, 0x68a7c32c, 0x3c8997cf, - 0x12979d8f, 0xf76ae7c1, 0x2aec4cac, 0x1fb4288e, 0xb0c1ce23, 0x358ad5ff, - 0x59cfc39f, 0x9384d77b, 0xff65de92, 0xca1eeda1, 0x31384a8e, 0xeec62050, - 0x5893b62a, 0x2c9fc705, 0xed38edd5, 0x63f64cfe, 0xd7772777, 0x2446a7ae, - 0xdd5bb592, 0xbeb38831, 0xae84c428, 0xb649f4f0, 0xd3cf6b94, 0xfb3f823e, - 0xe59536e2, 0xa2db8bca, 0x6cd43f78, 0xe220f07b, 0x529e6b04, 0x2d58edd8, - 0xafce385a, 0x1c2a8766, 0xec1de7c1, 0xcfddf147, 0x5173f173, 0x8b5f404b, - 0x66ef149a, 0xc3bb4f9a, 0x6823d31d, 0xbe80af3e, 0x87173488, 0xff470d35, - 0x079ffcc6, 0x37920b7f, 0xc83f3517, 0xef548df1, 0xbf37cb02, 0x3c38e08d, - 0xc1dec93a, 0x186ecf3c, 0x45f5fec2, 0x586bdb4d, 0xe116d83e, 0x8ce9e982, - 0xe40f7ccd, 0x81de3e80, 0x9c8f296c, 0x67d1edd5, 0x1f59505f, 0x2fb13cc2, - 0xb871e8cf, 0xf537bb46, 0x4b666f76, 0x5b26a7f9, 0xfea34fee, 0xd1a3a6a2, - 0xc9fea8fd, 0xfa73ef5d, 0x166fbebe, 0x3df0b645, 0x223b93cf, 0xc9e09ef8, - 0xfe39ff1d, 0x7cef1a35, 0x250498d3, 0xc89d9f68, 0xba7dc9b6, 0xf32fc641, - 0x13d61725, 0x673d789a, 0xac28a5b7, 0xa4de032f, 0xf1dd9fb7, 0x3643df12, - 0x1c1febe4, 0xb14b382f, 0x18a3dc86, 0x8d72083d, 0xd7bf55a3, 0x63dba6d1, - 0xaffa6ffe, 0x5927bfd1, 0xe471f58a, 0xc4610d3d, 0xbd64b86f, 0x27b73522, - 0xc1dcddf6, 0x97b899ee, 0x7192de2d, 0xfbb7a297, 0x737fe811, 0xbb678ddf, - 0xbb9b52cb, 0x1c5ff227, 0xe0958526, 0xce887733, 0x875a9257, 0x347bbec1, - 0x8615ca4d, 0xb56aad3f, 0xbf04bc22, 0x3e67445e, 0xd0aafde4, 0x49c90760, - 0x563d7c67, 0x71daf161, 0x99d9463e, 0x3bb7ea2e, 0x75bec137, 0xec7c2ec4, - 0x29d17b7f, 0xd2e927fd, 0xf618f20f, 0x7155a517, 0xd878ac81, 0xa9ba74f1, - 0x41e54a9a, 0x29b553f4, 0xea390590, 0x2bda5d9c, 0xa9fd0e51, 0xabd640aa, - 0xfd14e9d7, 0x69a3dfa0, 0xf72c0bae, 0xd0128cee, 0x44af2c3f, 0xd3c8bb49, - 0x41614dce, 0x1cbf76e7, 0xc777118b, 0x66df4afe, 0x0bcc3f39, 0x7b22fcf2, - 0x5de41663, 0xd145dc63, 0x39de3c8d, 0xe145bc7d, 0xa39fd28d, 0x3ea211c7, - 0xec136f8f, 0x267b6a77, 0x33e6e58c, 0x632f2dc9, 0xf4cf33fc, 0xa387b8e7, - 0xbb05fe69, 0xf1c9dcb8, 0x86cf95e7, 0xd3df3005, 0x5db144cf, 0xca4db4eb, - 0x12a3a763, 0x143b1e59, 0xf65cf0f5, 0xa6153d63, 0x5a742ec0, 0x9424f611, - 0xf2c1ee6f, 0x32dd6540, 0x1254d7f6, 0x4b1c817b, 0x7fc804e9, 0x67f737a7, - 0x37e9d17b, 0x415cbe55, 0xbbe357df, 0xfee71a26, 0x0880f58c, 0x799e23b6, - 0x83fd6ff6, 0x5a463bfd, 0x3ed994f9, 0x5183d066, 0xf923945e, 0xd48e5160, - 0x71c86e53, 0xd11d5a71, 0xaf3a70f4, 0xc207f253, 0xb481eb03, 0xef61131f, - 0x3bb4d23f, 0x9c048951, 0x09ff5903, 0xfa956fb8, 0x366d99d6, 0xbe5553f6, - 0x3b65e512, 0xf157ddd4, 0x554ac97d, 0x1695e3ca, 0xf950df79, 0xffb656e5, - 0x2ce33fd4, 0xde083c00, 0x6db6dfac, 0xe471f556, 0xf4b7a7b8, 0x808d7e91, - 0x10797f9e, 0xc62635fb, 0x59537989, 0x0790dace, 0x2a7a5eb8, 0x69fee382, - 0x34e22f1c, 0x73f67f2a, 0x0598cf09, 0xc1d027ac, 0x4ab9fccd, 0x77d5cfe7, - 0xfb83135f, 0x955de210, 0xb25c79ef, 0xff827a7a, 0xd1ebc286, 0xbf3f9d1c, - 0x83f338fc, 0x8837da2a, 0xfbac5b0f, 0xab3f1713, 0x78b95cb0, 0x308f35d5, - 0x26c77ddf, 0x5ce22f70, 0xc1d183d3, 0x91cfa8f8, 0xbdb3b0fc, 0xa62feb87, - 0x5bfdb2fa, 0x2d9f3cd1, 0x13e60f36, 0xddefc78a, 0x07f559fe, 0x226cafb5, - 0xcaef22f9, 0x2d125ff5, 0xf833fd3f, 0xfb2736cb, 0x7cff0951, 0xadacea3f, - 0x7fd60169, 0xf32779f6, 0x72b1b39d, 0xf3a49fdf, 0xf98d97d4, 0xb66bf4dc, - 0x9a61fccb, 0xd0b439c0, 0x98d7ee6f, 0x9b1cead7, 0x4f78b7a4, 0xd544fc0c, - 0x47f40f84, 0xb711f9f8, 0xedc6d77f, 0x40b3d743, 0x4fb1d76f, 0xba608f9f, - 0xe24bdb39, 0xd90bece5, 0x8d1d9e7c, 0xf34ef495, 0x74de854d, 0xb8a65636, - 0xa87a0499, 0x387a4974, 0xed89a63b, 0xed956702, 0xc9b51e9c, 0x74cb9576, - 0x5fd13b7f, 0xb407e812, 0x63aabb09, 0x19e40b4d, 0x05e1f9f0, 0x4f70069c, - 0x0e8ed43b, 0xd7f9c53a, 0xe333efaa, 0xebf6051d, 0x89a79fb0, 0xba6bc7ef, - 0xedb5593c, 0xf0257f4a, 0x614db554, 0x197fda7f, 0x13acd0fd, 0xd1003f0c, - 0xc29f62e5, 0x6e2c22ef, 0xfb116db8, 0xbdac96d3, 0xac6f7415, 0x6f7eb163, - 0xf2a2a8fc, 0x693a8e7c, 0x395ee4ff, 0xdfdf019e, 0xef1d28e7, 0xf38cb875, - 0x3bf0f68b, 0x47496e39, 0xfea46d94, 0x35941aaa, 0xa19a4e3c, 0x19f5cae7, - 0xd8b02270, 0xaa3be761, 0x6eeed3df, 0xbb3cc6fd, 0x9d31cf9b, 0x934d1fcf, - 0xdedb93f7, 0x2fccf796, 0x26243d7d, 0x41e45bee, 0xf46061be, 0xd063b887, - 0x22f3f520, 0x35f61cf8, 0xcf34ebec, 0xff660dac, 0xe653ce4e, 0xe66d80fc, - 0x730eee7c, 0x9cd9af3e, 0xce6ebcf7, 0x0ee309ff, 0xf41384eb, 0x4235c46f, - 0xfd0a46ff, 0xf5261ddb, 0x7fa1e46f, 0x8dfe8523, 0x91bfd0ef, 0x3c8dfe87, - 0xa1e46ff4, 0xfe85237f, 0xfeeeef8d, 0xba554e12, 0xe07814bd, 0x4eddbab8, - 0xf7813e23, 0x89d9c5cb, 0x558547cc, 0x1717a5ea, 0xd8fcb2e5, 0xe29a6f61, - 0x11937b60, 0xad18958f, 0x1c47f785, 0x2ab2d280, 0xb1db8d39, 0x55f6ba1d, - 0x2aae8769, 0xeec24670, 0xe4f2bad1, 0xa73d882a, 0xd418b4a3, 0xdb6b68bf, - 0x2f56f802, 0xff7ec03b, 0x77eee5d6, 0x63f893af, 0x5f118bfb, 0x0f738255, - 0x25f49b7c, 0x71ee7719, 0x4353db04, 0x4d6244fd, 0xd3f21e50, 0xd43e733a, - 0xe6be042f, 0x46abed35, 0x6c6fc7c6, 0xfbe0c96d, 0xe0e33e9f, 0xea9f69fb, - 0xcb313bf6, 0x2198f2c1, 0x1bce23cf, 0x9f7a5970, 0x95e709b2, 0xc31c7fa7, - 0xa650fdb9, 0x68617ee9, 0x0879765a, 0xf91df3cb, 0xe3058a35, 0xbe5f4f94, - 0xcd6af58f, 0xedd2e7cb, 0xd7b2dcfa, 0xeef34c5b, 0xd1370fef, 0x71adc0d1, - 0x5ecc7e21, 0x7783faa6, 0x31f887a5, 0xa7ca9807, 0xbe6219ad, 0x8d7c5f8f, - 0xbdafbca9, 0xa1cf6e23, 0xfce4b9fb, 0xa5ceb25c, 0x6f5e02c8, 0xc554bd68, - 0x6ff827f3, 0x4e52dbc5, 0xc673a72d, 0x2bbfaf1b, 0x9d7f0052, 0x57e03277, - 0x858b64d1, 0x3f4cad9d, 0xf332c487, 0x15615cb9, 0x275c573e, 0x84b855dd, - 0x7fda9637, 0x654c6d69, 0x47e5fa3a, 0x68812aa9, 0x3c9680d1, 0xde8bafe8, - 0xe838727c, 0x98dd5aaa, 0x3bf2a2ea, 0x5c16ff14, 0xb7133f20, 0x9524713d, - 0x495aa927, 0xaa73c27f, 0x1cff702d, 0x19edd1f0, 0x7ca4ef02, 0x68a5e6ba, - 0xe9d41f8e, 0x0ae6d52f, 0x6c6c1d07, 0x814f5954, 0xeb8d4cfd, 0x8d8d93a4, - 0x6bd0e1f1, 0x3e28c62a, 0x5c06c7c8, 0x8508fa0c, 0xefefc907, 0x97bd69ba, - 0x94f7c90e, 0x752e758c, 0x41a2fac9, 0x07de37b6, 0x5c7bd630, 0x372b47d7, - 0x3b7591be, 0x7fd73f7d, 0x7e1b9e5f, 0xbc5dbadc, 0x6d96c5ee, 0x7d29925b, - 0x85dda1c7, 0x7b7d2d75, 0x1a48f45c, 0x326dcbe7, 0x75b3fdae, 0x23e13e4f, - 0xe3777a7e, 0x0fe87693, 0x9dbf5695, 0x6679cddf, 0x0ef11da3, 0xc8dd6fd7, - 0x2d6c17df, 0x71807b61, 0x1194eecf, 0xa3c3ad97, 0xc1b2ac62, 0xde3ceb45, - 0x1585ca5f, 0xa69e32e1, 0x46f51d48, 0x55b5d602, 0xa6bac7c9, 0xe3b76f17, - 0xf58781fd, 0xa6fba17a, 0xa2b4f0fd, 0x357bb01e, 0xd4c71c29, 0x11993edd, - 0x64fbcfe8, 0x4e34e5da, 0xc81e5fa7, 0x8287de7a, 0x239c2fb4, 0xf5fa21b9, - 0xf5da5561, 0x4ef9559a, 0x30903d98, 0x5ec2f20d, 0x35456ef9, 0x0a23439d, - 0x710bb7a0, 0xa3c5a535, 0xd79d1354, 0xf6984616, 0xb4112cc1, 0x9bbfa8af, - 0x7e532f45, 0x530cc4fa, 0x07d399fd, 0x0b9df886, 0x7f99cb3a, 0x8f7a6d5d, - 0x9f2efaa6, 0xc7bb615b, 0x4a77f358, 0xbb3a62ef, 0x5abed4d1, 0x47bd354c, - 0xf7a9e8b3, 0x6544ce18, 0x54e1c476, 0x6658f7e8, 0xeff54769, 0x169dfcad, - 0x7dafda62, 0x927f3c33, 0xfd8da5e7, 0x7d3d8609, 0xe8cf7e16, 0xef0cbcea, - 0xbc451788, 0x9a1dec30, 0x61691e59, 0x3c48553d, 0xa8f6eb54, 0x8f691cea, - 0xd8b5f6aa, 0xf04d8f11, 0x4810a6b7, 0xb6151a6a, 0x477d5237, 0xdfcc9c4a, - 0xcc3bef85, 0xdfd052f7, 0x521f9465, 0x42bfb04b, 0xdd686bcb, 0x606a1738, - 0xd83b6247, 0x076c9384, 0xfbd1c633, 0xf434e837, 0xfed0807d, 0x33700c06, - 0xbadcaeff, 0x822f60fd, 0xd8e2b4cf, 0x549dc47c, 0x95b14d35, 0x6f495ee4, - 0x54bfff06, 0x7ebf6161, 0x4c03e1fb, 0x5615ed6f, 0xff4b8c8f, 0x78d4b876, - 0x9435dda5, 0xbad0170e, 0xb05e7fe0, 0x15f8f143, 0xe9f00f59, 0x810cfa05, - 0x70174a4f, 0x01d5e033, 0x7e7290bf, 0xe2286e3f, 0x0a7be426, 0x1425c057, - 0x0b38fa9e, 0x2772c134, 0xf3cfcbcd, 0x8c57e90a, 0xb78fdd08, 0xb0ffd9db, - 0xe52e1141, 0xf531e1bb, 0xf4e3b4b2, 0x6feb90cd, 0x2078a9db, 0xd97cdfbf, - 0xe83bdfca, 0xd9c658a7, 0xde689f4f, 0x54f41daf, 0x8ccff72c, 0xeedc89cb, - 0xdf5745df, 0xff864f45, 0xdd7e3426, 0x19e647b8, 0x1ab7dfa0, 0xf37d8626, - 0x1be1c44f, 0xe77741f2, 0xe439c74c, 0x9910f1d2, 0xbcf9e5de, 0xe39d2a34, - 0xbedd35cc, 0x4d69f068, 0x5b8c676f, 0x78eee542, 0x7e6f7bd0, 0x43557167, - 0xfbf06a46, 0x1b4ada37, 0x975381db, 0xe25a73c7, 0x7ce22574, 0xdf2e5929, - 0x4f763969, 0x29f844cf, 0x25b4ad8e, 0x8faea44c, 0x553439dd, 0x88be420c, - 0x86d74fd3, 0xcfb60acd, 0x032de91b, 0x9c61f9e4, 0x872de7ef, 0x3f6167a3, - 0x8d19dcae, 0x2bc5a190, 0xa2ee1fdf, 0xa2d9be73, 0xfec01a2d, 0xce7c8de0, - 0x3cc6d70b, 0x390ce7d8, 0x516572a3, 0x5503c84f, 0x04f038ff, 0xb96d01e4, - 0xea72112d, 0x81540fe9, 0xe73a1ad0, 0xe538be58, 0x6a7df494, 0xabdf0473, - 0x2f08a53c, 0xd48b51fc, 0xd32e797d, 0x337cdb79, 0xd2708fc6, 0xae30c3b8, - 0xc6124b7f, 0x30b2f8f5, 0x333cb6ae, 0x8bbb2ba6, 0x97aed691, 0xc316dff2, - 0xa3dbacce, 0x0f23f721, 0x4b645fb9, 0xc8791fb9, 0xf72148fd, 0xfc0d7be3, - 0xd71bf00e, 0x6f43e5b7, 0x39158df5, 0x8e1cf84b, 0x7f5c81cc, 0x01ee12bb, - 0xf15dba3f, 0x8478e4f4, 0xf9e5620f, 0x2357821b, 0xb246dd1d, 0x5edd1059, - 0x8221d977, 0x88c6ebe3, 0x9c7e5358, 0xbf54d923, 0x2a6695c8, 0xbfa93ebf, - 0x7706fca9, 0x537f29be, 0xfd5348ce, 0xa6319e49, 0xdc468ffc, 0xc53faa60, - 0x9f94c53b, 0xa9b66136, 0x12e28cfe, 0x59ccf953, 0xb3e54c8b, 0xf94cdbb5, - 0x34ee2b5b, 0x92f1ffd5, 0xaf72a6e5, 0x0e715970, 0x231f4336, 0x3e85efb8, - 0x6fede946, 0xe3064667, 0x4b38d475, 0x350cef97, 0x56fa900d, 0x39f7ae74, - 0x09ee25d0, 0xe8fb0e81, 0xe2f680f7, 0xbf06199c, 0xfa914065, 0xe8324b70, - 0x685eb426, 0xfd88a8f9, 0x6594f097, 0x9f6ee7ff, 0x313e2561, 0x43fdaaea, - 0xfb7f2832, 0x5619e6c0, 0xaea32fe2, 0x3a52ffd9, 0xdcf17fe5, 0xf07cb237, - 0x57284bfe, 0xfccbf772, 0xc822c134, 0x9bce06af, 0x8c75a3e1, 0x8d7d2eba, - 0xba53da47, 0x5235538c, 0x9d7101c0, 0x00d20380, 0xfdd227d1, 0x5f489f44, - 0xb72cfa27, 0xe8907109, 0xd221e913, 0xf7fdf14b, 0x3d2297a4, 0xd2297a4c, - 0x452f4877, 0x297a42da, 0xcdd43fd2, 0x3a83f4e2, 0xb1fddb8d, 0x8fd382ae, - 0xf7f096ea, 0x7196ea4f, 0x1f3a97fa, 0x8064ff7f, 0xb0087f61, 0x8bf0c69d, - 0x091fc0d5, 0xdb2ede7b, 0xb1bf60b9, 0xabe795e2, 0x5facc7e1, 0xb0235a22, - 0xb1ad5b4f, 0xfe9d1c27, 0xadf9eec9, 0x92089c55, 0xdee19ccb, 0xf8f006cf, - 0xb7cc5dbd, 0xc447eff5, 0x84053eb4, 0xb5d34fa7, 0x3307e0b3, 0xc656ca0a, - 0xeeb8ff10, 0xd03625eb, 0xae9687cb, 0xd5efa3ef, 0x03a7dbf9, 0xf7e86dbd, - 0xa65dfd5a, 0xae321d6b, 0x6b6b5af0, 0xbfdbdb3d, 0x03c46e14, 0xefec33ed, - 0x5ef958f7, 0xe085f2b1, 0xc104e8fc, 0x5b2ffaf9, 0x5af10e38, 0xcf892797, - 0xc46f3d1d, 0xfdf87505, 0xef1413f1, 0x8de1f863, 0x2fc29f78, 0x3e41c75a, - 0x77691d18, 0x0dc48587, 0x2fbedfc0, 0xbcc68fea, 0xc3277df8, 0x97d4ffbf, - 0xf2f78022, 0xb5fe3f0c, 0xd834968e, 0xe1df4615, 0x33c704f0, 0xe57afe19, - 0xe715168b, 0x64af1189, 0x3bcc638c, 0x15fd4aca, 0x5d23c674, 0x47ca6aeb, - 0x757d465c, 0x93d7f724, 0x49dde3be, 0xb955e7aa, 0xec3e535d, 0x22aba3c7, - 0x8ce9423d, 0xafa9e813, 0x3af1ea9b, 0x38d0bf0b, 0x1eb4624e, 0x1c7e8127, - 0x01df9cb2, 0x48109d1c, 0xa39ffbc6, 0xb03dd897, 0xb88e3e83, 0xb8ce82b3, - 0x088fd405, 0x2798c7da, 0x15f7edfa, 0xbcf217cd, 0x9df0cbd7, 0x29f492e6, - 0x3f5e7adc, 0x2c6385af, 0x3d54bbdb, 0xfae61c5f, 0xcfd1046b, 0x90da19ad, - 0x1fdfd481, 0x7ccc8c94, 0x7a3217d6, 0x094fdf60, 0x0bb04779, 0xf03119fa, - 0xbc7e84ff, 0x05bdef12, 0xe942e1db, 0x418fc0c8, 0xbbde064f, 0x0e832ba3, - 0x18d0e282, 0x65711def, 0xf4a17f7a, 0x199d1dd6, 0x43ad75f4, 0x8cf001d2, - 0xae8320f8, 0xf89a2f94, 0x2ae8eb1e, 0x067f9f07, 0xc5d2855d, 0xe9257495, - 0x0e27feb4, 0xba4aefee, 0xc007a4ea, 0x55d387e5, 0xf8f38a8b, 0x79a7a59f, - 0xee3c626d, 0x765c97ff, 0xabda441f, 0x7c17b69f, 0x198c4ca6, 0x2e13120f, - 0x62ec1075, 0xba32f5a1, 0x7f4a17a9, 0xbc6eeda1, 0x6e465da2, 0xfa71bb70, - 0xaeda1959, 0x047aed12, 0x71c21bb7, 0xf7e96f11, 0x1a72de08, 0x999e2d71, - 0xb90e5390, 0x2f2df26d, 0x27cc8de1, 0xf3a719ba, 0x096243f3, 0xee24bf9f, - 0x854f40fa, 0xcb8d693a, 0x42fac85d, 0x71d76461, 0xedea3705, 0xdc5d7fc7, - 0x4f8cf980, 0x37e3cb30, 0xf5fcf2ea, 0x0ffb91a2, 0xc6e1477d, 0xce59ebdc, - 0x61477d0f, 0xfe3d40f3, 0x81a44d20, 0x8f0a17df, 0x0efe9f9c, 0xcfbea146, - 0xc9ba7453, 0x5462ab70, 0x6a9bee1c, 0xaf321c56, 0x3c8c1de3, 0xfce3eb8c, - 0xe9cfc20d, 0xfdc0224d, 0x0903a24c, 0x61091ff9, 0xc85fef93, 0xaa35bafb, - 0x5790dff6, 0x4fba7b8d, 0xb057b53b, 0x4c440fcf, 0x4a77839e, 0xd7190dc6, - 0x17f6ed0f, 0xdbce59ba, 0xb960c8ef, 0x16d2fb13, 0xde27c9d7, 0x5fba73a4, - 0x8a37bca6, 0xfb46f714, 0x3bfa79d1, 0xbf91c73a, 0x40b96731, 0x736ef1bb, - 0xfed193bc, 0x6138d726, 0x9cfeef8d, 0x776f29bc, 0xdecdd86f, 0x042ecd8a, - 0xbd8adf7e, 0x7deb10aa, 0x45a7b62b, 0x4e7661a6, 0xafd2bd07, 0xa0d8b92b, - 0xc6f1cefb, 0xc1dd78f3, 0x286b80d9, 0xff380d3c, 0xeb1eb800, 0x077bae0a, - 0xaa379608, 0xad5f2423, 0xd57c908e, 0x58757380, 0x9ede7dc7, 0x5527f1c1, - 0xf9af090e, 0x5611aecb, 0x2c17f512, 0x93f9c91b, 0xb807c275, 0x6092c69f, - 0xf7b10f10, 0xce58eb09, 0x9ddcef1b, 0xe8bdf87d, 0x2ae79a24, 0x983ff687, - 0x4082b9df, 0xe2844916, 0xbe7a86e4, 0x05fe7f8f, 0xaa7d03d5, 0xf1af754a, - 0x96facec0, 0x7d71ef2a, 0xfe15207d, 0xd754f158, 0x0e55e8f1, 0x9f435f09, - 0x98afd21c, 0x5fb1adf7, 0x80befe85, 0x0ef55f21, 0xc6dcf193, 0xe4eef73d, - 0x92e1e1ad, 0x930ef5af, 0xebc0d8fc, 0xee7ebb06, 0x89c33f53, 0x3afca68f, - 0x98abf59c, 0x2e4c6f58, 0xc28583ec, 0x76189fa4, 0xf904f695, 0x22b5ca7e, - 0x945191eb, 0x13643c2f, 0x076f2a7e, 0x92794043, 0x1fb6b3f4, 0xef82a4ba, - 0xfc294517, 0x6f71863e, 0x22c92c29, 0xc27c41dc, 0xbd370ee9, 0x13911b4b, - 0x7947ca67, 0xc7ea997a, 0x9537488c, 0x98077ac7, 0x1427e3ca, 0x8a3df298, - 0xefd536af, 0x29ac6b39, 0x68ddac9f, 0x31529faa, 0xf83794d5, 0x24fc8a58, - 0xc5b92cfa, 0xb2efbed4, 0x34fd5352, 0x5ca9a55f, 0x319b3bc5, 0x25b7ab40, - 0x81cf1127, 0xd58c9fca, 0xe3de434b, 0xf0cb08b5, 0xfe6b77ce, 0xcbde5a33, - 0x80b91099, 0x6cc9afdf, 0x9e7999fc, 0x2c6b44ea, 0xcdbbd7a5, 0xc928b17c, - 0xb9171f9c, 0x71df814f, 0x9fcccb9c, 0x4d589653, 0xeae51ff9, 0xe44f34fc, - 0xbbe3ddb1, 0x300daff0, 0x4e143fe1, 0x7efc0f44, 0xef9d3b68, 0xcdebcc3e, - 0x070f7e32, 0x75e0937e, 0x0c126fc0, 0x824df807, 0x049bf0f3, 0x24df87d7, - 0x937e1cb8, 0x8721f2e0, 0xd61ff8cc, 0x55ffc662, 0x6ff1991f, 0x787765d0, - 0xa66ad91a, 0x9a29a10f, 0xba782df2, 0x7e9994e6, 0x1d73f142, 0x09b15b89, - 0x09e287c0, 0xbe387fb8, 0x8be08656, 0x37f7c3f0, 0x31477bdb, 0xd7d71e7e, - 0x20606d75, 0x3a2e97df, 0x6fbc0aa4, 0x71f3ac63, 0x6d3fdcfd, 0x89731ad5, - 0x5dcefccf, 0x763e0490, 0xdb7e909d, 0x4f1655f1, 0x207fba80, 0x29d99c64, - 0x3fa843da, 0xaa52fe2b, 0x26d2741d, 0x0e7bcfdf, 0x95d8797c, 0x123eb2f1, - 0xf6bef84f, 0x27be54cf, 0xa8d2c475, 0x8eaf8f80, 0x9f009ed1, 0x84bb9799, - 0x8a249bd7, 0x5c402fb7, 0xa5857fd4, 0xafb73f22, 0x722dc7bc, 0x89fef95b, - 0xa6e727c1, 0x2da9b8c8, 0xdd7fbab9, 0x9ea7e323, 0x777295c9, 0x71c5c794, - 0xf2b925de, 0x8ba90d7e, 0x010773a9, 0xd99d873e, 0x0b3acf80, 0x8ad9ebbf, - 0x9d09e47b, 0x0f21c8f7, 0xa3ecfe43, 0x1ff57fcb, 0x47581c3b, 0x3a617af6, - 0x1dfbfb7f, 0x81e2f8a6, 0xfca65d5b, 0x5324a6a0, 0xdcbbc1fd, 0x40fcf2a6, - 0xc87ca98e, 0x3f298f21, 0xa98465ac, 0x791f55fe, 0xad91f94d, 0xaff54c13, - 0xca6c5539, 0x47b688a7, 0x8abedf01, 0xcd1c53b4, 0xb9fa974d, 0xe4dc705b, - 0xe563bbdc, 0x7edd5f7d, 0x46fbc861, 0xd3a6b9dc, 0xd11ea875, 0xe8e52ed7, - 0xf52164fa, 0x1fae8746, 0xa13eb30a, 0x1de371e9, 0xe67c58f7, 0x5e2371b8, - 0xd0ef43bc, 0x7b8e8af5, 0xe2f19d34, 0xf178e0de, 0xbf5d61b9, 0xc75e7d1f, - 0xfbfce87b, 0xeb7ae5da, 0xbdf3b4ef, 0xa15e631d, 0x96c949f3, 0xd1d9bb74, - 0xbfaabdf5, 0x46fb4ae5, 0x25f1666b, 0x3613fdd0, 0x6dff2b4f, 0xf3c62b84, - 0xb75e22b4, 0xcf7617fe, 0x8f77f70a, 0x5cb07737, 0x658b1ccf, 0x8e5c94de, - 0xddfd338b, 0x92418884, 0x7583adbe, 0x78c84afb, 0xdc646373, 0xbbb1889a, - 0x8fddbf41, 0x6499e127, 0xff7c0d17, 0xf167bf4b, 0xf74d35e3, 0xbd8e68a1, - 0xce3f7f51, 0x4c3d036f, 0x59f24b1c, 0x5b13c93e, 0x49143d7a, 0xcb13ca72, - 0x8a9f6cac, 0x3757fe7b, 0xde75fafb, 0xfa4be99f, 0xb203e810, 0x07a8f40e, - 0xb72954f2, 0x2beb920c, 0xb8eebf52, 0x187ec0e7, 0x43f3f421, 0x174fbc70, - 0x6874c6f4, 0x75dfe3ac, 0xdba0c1ef, 0xfa193850, 0x3be3d0af, 0xd2f319fb, - 0x07ec67e1, 0xfdc67e03, 0xb66df713, 0x7c914de2, 0xe202658f, 0x6dfc0ce5, - 0xc6f693c9, 0x503c3a05, 0xbba8fc0f, 0x6e6a457a, 0xedf7ec0c, 0xeae31dc2, - 0xea3b0e82, 0x62e09bff, 0xfbbbbfc0, 0x87f1dd6d, 0x5df0be50, 0xa3baddf7, - 0xdef67fd3, 0x909f105b, 0x5e3a4bf1, 0x1c2cfdfc, 0x94777017, 0x323f3f79, - 0x9189f248, 0xe4fdf483, 0xccd6fd23, 0x0ffc042f, 0x9d552bf5, 0xbcf3c85f, - 0xdf98ad24, 0x8af9c6af, 0x37f35bfb, 0x8847f94a, 0x87abc4e2, 0xe36f8fc2, - 0x7ad7cbfb, 0x4a6ddb05, 0xde3f151b, 0x75f12af9, 0x9fb30fad, 0x0772cdcf, - 0x26c83bbf, 0x46576a4d, 0x5da5f6ed, 0xc2facef9, 0x60eef948, 0x0beafbe8, - 0x2f19bd75, 0x86df606a, 0x19eebdfa, 0x3cb1fba4, 0x9cf2c3c2, 0xa150d71e, - 0x37a0e9d7, 0x0e6f7cbf, 0x31f6327a, 0x671f1ca5, 0x3f0dcdc0, 0x3cce90d4, - 0x073c37c1, 0xb58379e7, 0x0ec5f8cb, 0xab7e1af8, 0x61ecbf0e, 0x1a1127be, - 0x77ce718f, 0x3f2bba20, 0xeb1fe198, 0xf8741f6e, 0xefc3bec7, 0x89691ed6, - 0x69f1dfc6, 0x67df26df, 0xfd5bf4e9, 0x22cbb865, 0xf03153fd, 0xfdeab53f, - 0x5d798d89, 0x96d50fdd, 0x9438e4ef, 0x73b68b66, 0x2cefad10, 0x7b778ff5, - 0x9fdc89ef, 0x26117788, 0x2ba976ea, 0xcdcbadd7, 0x8fe914a3, 0xef8ca9f6, - 0x5ef209f6, 0x8151f13d, 0x4fc4677d, 0x0481114c, 0x4a1f86a4, 0xe1923d5b, - 0x4aa1f86f, 0x9e792302, 0xda17ea33, 0xeb68e4f0, 0x851577a3, 0x53fd3bbb, - 0x5c647dad, 0xaa7e7754, 0xb9f39769, 0xaf97e9bf, 0x183e7ee1, 0xb6e52694, - 0x036efb86, 0x2ad80d9d, 0xab67586c, 0x4bbfebad, 0xabf3a851, 0x3d9ae812, - 0x96ade282, 0x962fbc2b, 0xbf88c22a, 0xe46f3e62, 0xf9ea352f, 0x7dbf9922, - 0xeab7cca5, 0xd16da7ef, 0x275820ed, 0x7a07ac52, 0x4edd36f9, 0xc5207582, - 0x7c1df03a, 0x35f0790d, 0x90d7c1e4, 0x0a435f07, 0xa5ef86be, 0x761538a2, - 0x0ad3f85b, 0xfc07f683, 0x72418569, 0xc169fc13, 0x82d3f879, 0x169fc3eb, - 0x5a7f0e5c, 0x69fc3970, 0xd3f879c1, 0x9fc3eb82, 0x3f879c16, 0xfc3eb82d, - 0xf879c169, 0xc3eb82d3, 0x0e5c169f, 0x39705a7f, 0x79c169fc, 0xeb82d3f8, - 0x5c169fc3, 0x62996f3e, 0xd3cdb7f2, 0x5b287fdf, 0x51f4cf1f, 0x9b1c5198, - 0xeffdf847, 0xc4fc7f88, 0x373c0e96, 0x2edd022f, 0x48f70ead, 0x904e373c, - 0x8908b778, 0x8cd9b6e7, 0x32ecbbe7, 0xb4e3245f, 0x7e07e943, 0xf49b42ab, - 0xdf85215b, 0x56fc290a, 0x2ab7e148, 0x2b7e94cc, 0xe15bf0a4, 0x4856fc3b, - 0x0a42b7e1, 0xf85215bf, 0x6fc290ad, 0x2b7e1485, 0x0adf83b4, 0xf856fc29, - 0x5215bf0e, 0xfdf0adf8, 0xfe03cd08, 0x905e632b, 0xf499fbf3, 0x9343a252, - 0xe532ea5e, 0xd707e721, 0x5c1f9c87, 0xb83f390e, 0x707e721c, 0x707e721e, - 0xc1f9c87d, 0xdc8349f9, 0xef20bfbc, 0xbc83b707, 0xd41f9c1f, 0xb6037be8, - 0x2e1b49ab, 0x35b48ebc, 0x7142794a, 0x2f353109, 0x8bfc2673, 0x35254ead, - 0x6d8423d6, 0x859980f9, 0x38f4d794, 0x66d13cc7, 0xae39be01, 0x05a6f080, - 0x0f65c704, 0x5cc97ffa, 0xf9b3f86e, 0xbf9ef087, 0x50deb043, 0x35afdfa3, - 0x4b847bda, 0xefd46a45, 0x2f5d77cc, 0x1ea37c74, 0x79a0cbf3, 0x8f996290, - 0xbbfc9378, 0xaf700b22, 0x91458b60, 0x642bb8f1, 0x5d28743c, 0xe793caad, - 0xf6cb16fb, 0x5388e1fd, 0xb83c5129, 0x156591ef, 0x80056c87, 0x7e0292d3, - 0x562f2af7, 0xab92d75f, 0xcc658711, 0x124bb0db, 0x867be09f, 0xbd84daa3, - 0xfd19c69c, 0xefe3b085, 0x4bb44c73, 0xa0ed0279, 0x29f40e6f, 0xf4414dde, - 0x9e4f2cbd, 0xb6ef9a7b, 0xfbe9cbab, 0xae4b6dc0, 0x89c5fdc6, 0xd3ddb2e1, - 0x386689bf, 0xf8506e4e, 0x6da8ce9e, 0xc9fb8bc2, 0x3a7e75cb, 0x5ecb9b70, - 0xf8bae3ce, 0x6fd1a3de, 0xbe5486c9, 0x5a2259a7, 0x450f710b, 0x3df8550c, - 0xb46e037c, 0xbeb1d7be, 0xb02ada2c, 0xfbe0ff2f, 0x7e2e244f, 0xa34ffb9f, - 0x2116c687, 0xcb3450ae, 0x0d2742f7, 0x83d9592d, 0xe5f9a5e6, 0xbfa3a17b, - 0xe706f258, 0x85ef929f, 0xe70cf932, 0x9879f1f9, 0xfdf853ed, 0x8dbec995, - 0xee370496, 0x25b72f65, 0xe136fea2, 0xf5055881, 0x8d8af708, 0x168ae575, - 0xbd01538b, 0x41f10388, 0x639c47f4, 0xdf25e83a, 0x59f7e363, 0x365d58a6, - 0xce431bf0, 0xb1c97129, 0x3151d48b, 0x4432cf7c, 0xd0d4b84e, 0x7e62e383, - 0x3b4e9c78, 0xba5fe7df, 0x8572c9d3, 0xbe615eb6, 0xc65f3e79, 0xf6dd56bb, - 0x7a4b70e1, 0x99ce9c67, 0xbc16ff34, 0x7d267b03, 0x8508f47b, 0x79bd88e5, - 0x0da3d704, 0xcd3df12f, 0xf06f9592, 0x0d4b943d, 0xfbcb450f, 0x52ffd26c, - 0xb0cdc3ae, 0xf1d7cd3b, 0x69c7ae53, 0xef93ab1d, 0xcc39d33a, 0x6a5caeef, - 0x119cb1b0, 0xf21a2f2a, 0x911ef1a7, 0xc23fae10, 0x60d153ce, 0x0bc03be3, - 0x4aac94d7, 0x91ca5712, 0x7339758b, 0xe38d8351, 0xf7f42ab2, 0x6eff42d4, - 0x1e3d62cf, 0xf356f16b, 0x42f24ff7, 0x7de350e4, 0xc94ebd4d, 0xb06607db, - 0xc6c4b43c, 0xcb39cdfe, 0xb6247ca5, 0x93ee3f0b, 0xce3e59cc, 0xe666f782, - 0x947af4ec, 0x5de9e82e, 0xd89a4e5d, 0x4ff864ea, 0xfcc11cb9, 0x14e5ea65, - 0x397cdfce, 0x9799d399, 0xee2adc65, 0x5a6e8122, 0x073be48b, 0xd1f2ebef, - 0xc6b1c40c, 0xc9eb3e43, 0xf44eddf4, 0x74f2218d, 0xabc035be, 0x3878801c, - 0x44ada6d1, 0x8dc4ec9c, 0x4d83ef82, 0xfd451c82, 0x155c82cf, 0x5691fd8f, - 0x2661f7c4, 0x68bf7c28, 0xf4dbd0d2, 0x43fb40fd, 0xf7e13f30, 0x29c2b457, - 0xcd39c47e, 0x805bb6d2, 0x685f637f, 0x5efca3be, 0x629f24ea, 0x9a923bc7, - 0x741b6fae, 0xe63fba1f, 0xb276e846, 0xeb076948, 0xb26193b0, 0xb7c92478, - 0xd3e4266a, 0xf66db0b9, 0x608109d2, 0xcb2b951f, 0xd576fc7b, 0x419206cc, - 0xc9fb55ff, 0xde458b1c, 0x9039233f, 0x96880bef, 0x2f949ea2, 0x4014a359, - 0xf5e6323f, 0x38ec67b9, 0x3a4eb0cf, 0xa7d8ed28, 0xd2e51ef2, 0x7e4d327b, - 0x8cb4d09b, 0x34fd8de0, 0x27f5a637, 0xf468610a, 0x1c2de160, 0x85ebf781, - 0x005428f1, 0xe8b798f1, 0x3bc1eaf9, 0x973ab4ff, 0x91f9c4e1, 0xa6687dbf, - 0xe05ff22f, 0x6b147393, 0x4b1bdff0, 0x0d5768b2, 0x50f7c1ee, 0x11bf03c7, - 0x9efc6db9, 0x4bb64a44, 0x7b10a9f2, 0x8960f54b, 0x4bbb50c7, 0x773cae59, - 0x7a9dd584, 0xdc7bfb2b, 0xd634b76c, 0xbe66cc7d, 0xf3a46be7, 0x5ee7eb07, - 0x9ee7bfdd, 0xf916c3ca, 0x1663c2fe, 0x8857f6ff, 0xd0f72f5e, 0x8fbd6066, - 0xe79ede21, 0x8cfaf1af, 0xf83a4cf7, 0x896efe95, 0x96474f41, 0x2afbe25d, - 0xb77691a5, 0xe54f441a, 0x0fbe15ab, 0xde4cba5a, 0x2b56d6e7, 0x6e845df2, - 0x99bf58ec, 0x9efcbffd, 0x117e6fd5, 0xf8750b2e, 0xbcb7b1ce, 0x84eb48e1, - 0x3d979fef, 0x347c9360, 0x0efb8990, 0xf2712cb7, 0x7b9fd9bb, 0x0f06ab8a, - 0x8c3c9e03, 0xe5d871a7, 0x8c4b7f54, 0x4bdf04b6, 0xd841cb45, 0xfcfee71d, - 0xba8f7e6d, 0xdf8d39b6, 0x95d92cbf, 0xd9ef0abf, 0x7ed1ee7c, 0x4497f582, - 0x4790ecba, 0xf9621a6a, 0x53db9e7c, 0xda2bcfbf, 0xe067cfd8, 0xd2c1bee7, - 0xbe7d778e, 0xaea2e71c, 0x6cc01157, 0xbaf54c53, 0xf61a63b6, 0x4b3b50d1, - 0xdf21bbe8, 0xdd815765, 0x5f641ec4, 0xb632ec35, 0x71b3639c, 0x77b1cfae, - 0xf73ef7fd, 0xf437f3ea, 0x7a1df9da, 0x9ef8ee6d, 0x2ad7ff90, 0xcbd3d82e, - 0x7133dd23, 0x90fca1bf, 0x62b4910d, 0xbe5b9c62, 0x7c8f731f, 0x8ef4a63f, - 0x7367e67c, 0xdc029380, 0xfbc9193b, 0xe94fdcb8, 0xfbf7ee90, 0xf40f6bad, - 0x0a7a0dd9, 0x821df978, 0x1ed79772, 0x951f2417, 0x77a62a35, 0x0bfc8c24, - 0x97c95583, 0xfc00dd48, 0x9a477c7e, 0xcd396f1d, 0xf1093121, 0x27417b99, - 0x51db3ac3, 0x993f8e3d, 0xca0e2e98, 0xfe14bdf7, 0x2f18e4bb, 0x955beff8, - 0xc3df9a36, 0xdf2cfaa0, 0xc51c1aed, 0x68b895fd, 0x5d4869dd, 0x03824f3c, - 0x3eeda9c3, 0xe3cdcfea, 0x02ca3e30, 0x07ec1b7e, 0x42f71073, 0x7e5c5bf9, - 0x6d29c61b, 0x68d4ef90, 0xda38e46b, 0x20fb58ea, 0x975607c8, 0x5cb04fbd, - 0xbddf20d8, 0xddffa39e, 0xcb2f9a11, 0x2704e5cd, 0xee33b3dc, 0xabc286dd, - 0x797f9f44, 0xce59ac63, 0x036b5c6c, 0xf377667e, 0xdd39c65e, 0x30da5d0e, - 0x2837df86, 0xbef97ab7, 0xfbc3a68a, 0xf79cdbb3, 0x7b325fc2, 0x34b623dd, - 0xb065ffca, 0xe9cf6b94, 0x7a6271fb, 0xa9df9320, 0xf1c9cdba, 0x8d5db3e3, - 0x780edebc, 0x81f0443f, 0x662ae2dc, 0xf89d1378, 0xbe596f10, 0xcedf8cce, - 0x77c944f9, 0xf095d7fc, 0xd5605bfe, 0x79e0aeec, 0x8997dfac, 0xb4d9a1f8, - 0x970ef1ef, 0x1f7c6970, 0x3343c4f6, 0x6205eff9, 0xe6cf1c9e, 0xbbc78f71, - 0x4c374453, 0x18fd06d7, 0xf18df3f7, 0xb4ab1eac, 0x6bbe7bc7, 0x420f7a9f, - 0x7c27af4e, 0xddd00fc3, 0x02e3b53e, 0x2f6b8d26, 0x5e07ef97, 0xfdf4efc1, - 0x6a01fffa, 0x00d36c91, 0x0000d36c, 0x00088b1f, 0x00000000, 0x7dedff00, - 0x65555c7b, 0xd6bbf0ba, 0xc0d857da, 0x51b08b66, 0x62020dc0, 0x10106d11, - 0x80a17515, 0x636a735b, 0x8dc42937, 0x910150b7, 0xf39fa8ac, 0xa96f0db1, - 0x962a2695, 0x8da6b675, 0xb2707595, 0xd99b1b46, 0x0f5d9a6a, 0x39d38d3a, - 0x32cdb653, 0x34d209bb, 0x99d37d9f, 0xde79e7be, 0x0daf60b5, 0xf9a675a4, - 0x3efcefce, 0x7df5e3fc, 0xee7d7bd7, 0x765ef3cf, 0xb24c6322, 0x98783631, - 0x8c81b183, 0x45931819, 0x77a13fc8, 0x6302edfb, 0xbeac7195, 0x28d2132d, - 0x0b6bff56, 0xdfe3df63, 0xa2749ef8, 0x8f2c6453, 0x5da0dbb1, 0x10af7c1b, - 0xd6ccabd9, 0x29d33df3, 0x148af7d0, 0xd41dd336, 0x7ec3fb1e, 0x13efd5e3, - 0x338b69fc, 0xe3abea7b, 0xbb78d856, 0x9a7ed0a9, 0xdd8beb05, 0x3ea81bf5, - 0x26e9b3cf, 0x3632c591, 0x87ff04db, 0x7b4894a5, 0x32e6c456, 0x7057b0d6, - 0xe1a8a11a, 0x18b18941, 0xf08b9f48, 0xbec664b1, 0x3bcdf868, 0xcfbd40b7, - 0x64af6f37, 0x35e67b43, 0x398a3fc7, 0xf7363046, 0x0c733652, 0xa5de6c60, - 0x0f569431, 0x073864f3, 0xf8dbd506, 0xc607ba5c, 0xfb2dadbf, 0x5a307fdc, - 0x30e59fb7, 0xbf73fef6, 0xe868e3fd, 0xde9f3197, 0x3acf4d7d, 0xa13ead66, - 0xc304b2af, 0x4d73af8d, 0x83155746, 0x18b6ce79, 0xcd14121c, 0x64c55e5e, - 0x33b32798, 0x13e41a67, 0x422bcc75, 0x16fd6cbf, 0xf3eb04d9, 0xb557fe30, - 0x5da9905c, 0x824fbe63, 0x7a860cf5, 0xdf5e1cc6, 0x58f7f00c, 0x4884670c, - 0x912de8a8, 0xcdbc1903, 0xf83d29f7, 0x21a90c1d, 0x89ef07a7, 0x5ecc1d0a, - 0x7b6d0657, 0x330305f0, 0x65eb0f96, 0xfceaae1c, 0xbff32aa7, 0xfb20bd6d, - 0x4e0ddea0, 0x2757cf07, 0x7ac1e61b, 0x364face7, 0x5cb486cc, 0x473e5ef9, - 0x2f8dde5b, 0xccaf8aab, 0x4f587695, 0x57c71b57, 0xe13d3ad7, 0x2f4f6bab, - 0xa931257c, 0x00771e67, 0x8e00d8be, 0xe382362f, 0x57c0530b, 0xa82f33a5, - 0x7c70bfde, 0xedfe7ecd, 0xd0765e0f, 0xceffa8fa, 0x1dbe8d07, 0xb6acffd0, - 0xf2b784bd, 0xc9f41bd5, 0x99ceaf50, 0xdb51704c, 0xb6cfaecf, 0x6de78032, - 0x1debb7ab, 0xe8eefc16, 0x9521ee93, 0x413f1059, 0x6790099e, 0x3bbc40ba, - 0x397ea7a2, 0x9c617ba4, 0x91cd8b25, 0x719edaec, 0x3cf428b6, 0x86da3ebb, - 0xafaecde3, 0x7165887a, 0xf66777fa, 0x66b3bfe6, 0xa0b317ce, 0xb3cfe43f, - 0xe424ce45, 0xd4510a8b, 0x3e9a9bf0, 0x79837884, 0x35e0063d, 0xdbc3fe23, - 0x0c38469e, 0x6ce6145e, 0xa9a94f86, 0x8b8e1f01, 0x36f38cf4, 0x826bcc88, - 0x8135a97a, 0x548f388b, 0x876c28a0, 0x528d8469, 0x1df90b16, 0x4802ed30, - 0xee9e2453, 0xc3f5f273, 0x677e3f77, 0x5c3c8131, 0xa1cf4abf, 0x3b606af4, - 0xfe00a757, 0xd9cc310d, 0x4fa1e8ec, 0x3e951fb5, 0x6fedfa55, 0x70ae7b7d, - 0x3993677d, 0x3386593c, 0x56e304c9, 0xb9cc3c3e, 0x3afcb846, 0x0f00610d, - 0x817ad05b, 0x7d6c0b58, 0x903537ac, 0x0fcd7657, 0x24a5b7ad, 0x86f58fb6, - 0x93e553ae, 0xc3ce2639, 0x015127c0, 0xfad77798, 0xf10c51a1, 0xca2f302d, - 0xcd8bb39d, 0x5d5bce22, 0x504d53d7, 0xbbb6e619, 0x33e944c9, 0xc368c04d, - 0x764d3e00, 0xe4df3fca, 0x29adb4a0, 0x9ddbca83, 0x633f9a36, 0x80698881, - 0x85308aa7, 0x8f3cfdff, 0xe54165e5, 0xee9c6d53, 0x11035b4e, 0xfd3920b6, - 0x0d79bd71, 0x0efa428b, 0xccfc883c, 0x5db2871a, 0xf5e9d430, 0x4cc42367, - 0x3f3e4fa4, 0x7d12ddb5, 0x163fc927, 0x02ec7061, 0x24b19b96, 0xe02374fb, - 0x38f2ee6b, 0x9b129027, 0xe49438d1, 0xb46f0cc2, 0x7eb00093, 0xcc78430b, - 0xf860e453, 0x2395aa92, 0xb26b7eb1, 0xe6718055, 0x5ae79c5a, 0xced5fda9, - 0x4b7bf1fb, 0x93252199, 0x9026caaa, 0x72287763, 0xdcc0896c, 0xa07787c8, - 0x12fe449c, 0xfea2a50f, 0xf055a3b9, 0x56cf291b, 0x21d7000b, 0x78d2eecd, - 0x055b1394, 0xbb6c0ee7, 0xa9a9e40d, 0x0d769e47, 0x7a817f73, 0xf4077d81, - 0x255ffd07, 0x5d710220, 0xca1c726d, 0x75824df1, 0xb979c317, 0x059f080d, - 0x6e9c9d0a, 0xc8e11339, 0xa3eb81ec, 0x65105ff8, 0x288b23cc, 0x3d141b6f, - 0x79406486, 0x310e4e45, 0xca41f870, 0x3a3f11da, 0xa0e909a7, 0xc51292cb, - 0x886f28fa, 0xf2c38948, 0xc912ad39, 0xaa9e9545, 0x7c2835d5, 0xa3be1733, - 0x2a912bde, 0x56be9162, 0x74a44cb6, 0xcd9286ce, 0x24e3a05e, 0x9a3b1dc1, - 0xb867a3d6, 0x13b5399e, 0x55bc47af, 0x9b4630ef, 0x7a496f00, 0x104e526f, - 0xbed9ce3f, 0xbb41892a, 0xd3cddbf3, 0x5b17fe51, 0xa1a38acb, 0xd16dbcfd, - 0x1e9052d9, 0x7ae6ca49, 0xc4ed4164, 0xacf00638, 0x2791fbf9, 0xe78fa0ac, - 0xe8569f42, 0x70b69bff, 0xd4aa179f, 0x924fed34, 0x31dee780, 0xa1b3e279, - 0xe0f142fe, 0x1f50a32d, 0xe2a7be08, 0xce23bea9, 0x503c87da, 0x0fc073d3, - 0xdaf7a00e, 0xf51ef5ff, 0xd6f895f3, 0xbed0e5f5, 0x4885f6a6, 0xa6e167ec, - 0xa15be43f, 0x49e8a0fc, 0x173ffec3, 0x45653fb6, 0x9edd6c02, 0xee7c7a85, - 0x4f28b4a6, 0xf917f21f, 0xbd51f100, 0xaaf8205f, 0x517c33e5, 0xc7bb8406, - 0x4c560ccf, 0xf480ccad, 0x8d625e7e, 0xf6a80f68, 0x323e5a8c, 0xf3adcb9b, - 0x9093eb51, 0xb53fe64e, 0xccf50925, 0x5f3c1167, 0x6fadd4f1, 0xecf2dca0, - 0xaf101a34, 0x38331d1e, 0x41799f51, 0x551d22bf, 0x93c6ff03, 0x04ae61dd, - 0x0eca2a7a, 0x6fceb827, 0x51fa411d, 0xa77c179d, 0xcc74cff2, 0xd218f385, - 0x748d99dc, 0x7f9d67ff, 0xcff3e22e, 0x17a766f5, 0xf5cd99f1, 0x4bd79fdb, - 0x05ee58a5, 0xe47b4186, 0x885febcf, 0xd8f4b548, 0xfbd2256f, 0xd67684b2, - 0xea36428b, 0x76ccf0ed, 0x1bb22cc3, 0x9d59d118, 0xc359d395, 0xe0e97d01, - 0xa8c7b218, 0x37e746a4, 0x05af85f4, 0x9dd5bd8a, 0x80d7b7df, 0x87b3527c, - 0x6d3511db, 0x508ec867, 0x855a92ed, 0x39ee179f, 0xda857643, 0x871f6eae, - 0x5e3eed4b, 0xc801955e, 0x80e5cd1d, 0x0aba4200, 0xfbf905f1, 0xd3d7f5fe, - 0x7bf26997, 0xb5df7f29, 0x750f2e56, 0xb7a8499d, 0x349c64d6, 0x976bfe20, - 0x5e42fd2b, 0xbcde341f, 0x2f0481ec, 0xc16a1f2c, 0xfd8d0ef6, 0x9a2fbb50, - 0xc36bfbda, 0x97bea356, 0x4c3a2ceb, 0xa42d6b9b, 0x8bd5b7ff, 0x9c5cba19, - 0xed13985c, 0x916183b9, 0x07472859, 0x06653c2e, 0x3b6a0248, 0xbe50888f, - 0x2f73ca3a, 0x031c67d2, 0x6f5090ae, 0x5fb405f8, 0x74f95e3b, 0x6e3ff604, - 0x066be048, 0xbf0bd753, 0xf20c5e9b, 0x2d981964, 0x06671f64, 0x0f1d2046, - 0xf4e5cc3c, 0x1ab67ae3, 0xb9d31bf5, 0xf72834d9, 0x3c42dca3, 0xdbe61b7f, - 0x1dffff05, 0xfec60ff3, 0x143fc999, 0xd0a4bddb, 0x5968dba7, 0xaebcc02d, - 0x8359ea1e, 0xd041be4b, 0x222d935f, 0xac34a40e, 0xdfe7a1d7, 0x82757b55, - 0xc113a722, 0xc8bb408e, 0x416ec830, 0xf3366e3a, 0xccb209f5, 0xf71e611a, - 0x8d9e1e67, 0xa76d7a7a, 0x9d611989, 0xc8c33a13, 0xe41c4d7e, 0x6cd6bd22, - 0x2dbd224e, 0x02ac7438, 0x14ce1fea, 0xcfac3afd, 0xcfac3e4c, 0xae76214c, - 0x9db19668, 0x6fb5f070, 0x960fbe51, 0x82891e2e, 0x47be0df5, 0x9d433670, - 0x8f73aeca, 0x15a41bff, 0xfdec7697, 0x2dff4857, 0xe113b3ca, 0x75cbba7a, - 0x5ba803c6, 0x39336d6b, 0xc160deb9, 0xef7838eb, 0xb13691b7, 0x9d1d7e67, - 0x4dfb9ee7, 0x2726a62e, 0x07099fea, 0xa11fd225, 0xc3b0e9f3, 0x3d5287c4, - 0x2c3b3bb2, 0xb0104fa2, 0x70f791fe, 0x164c137e, 0xbaf684bf, 0xb065ff49, - 0xc48e617e, 0x935773e8, 0x83df614a, 0x938b1091, 0xd1747d47, 0x38eb7642, - 0x3a550f85, 0xdb9b2b7b, 0x72296f8f, 0x73338555, 0xaf582cc8, 0xd66cf0a8, - 0x1022faab, 0xf87b32ce, 0xaf529176, 0x932892eb, 0xf46d5e1d, 0xebb2e831, - 0x33d250e0, 0x3fd9c9fd, 0xf601dda0, 0xf954f2c4, 0x5327845d, 0x0acdeef4, - 0x2dfd54fc, 0xacdffd29, 0x8b66f1c0, 0x5376e1c8, 0x7a14dc08, 0x1e97a50a, - 0xdb41887a, 0xeccf1ba3, 0x51a3f6be, 0x6bdf84c9, 0xfd78e61e, 0xedfaf090, - 0xcd802b5b, 0x4dbfa0d8, 0x0cfefc21, 0xb98bf578, 0xedaf023f, 0x9bf578a1, - 0x375e2187, 0xa0676489, 0xa376881d, 0xb5c0e507, 0x60f6e794, 0x51392306, - 0xd7398529, 0x8077e324, 0x87c91643, 0x541f28a3, 0x15c430b9, 0xe9f506b8, - 0x71e57069, 0x8db1017e, 0x10a4e797, 0xf6b0245d, 0xbc072c78, 0x277da1e7, - 0x7e668699, 0xe5b7720c, 0xdfdedf01, 0x82cd3f40, 0x983ceb6f, 0x8b66f78f, - 0x0eb7ed13, 0xc3d5e89f, 0x59a25a3c, 0xbf187ed6, 0x4e55fe65, 0x4533962f, - 0xf8374c6e, 0xef837ed0, 0xbdf88d49, 0xe97f7f9c, 0x441f67ef, 0x8d33acfb, - 0xb25abad1, 0x67da3a59, 0xf419652d, 0xdcaab7fd, 0xb7823079, 0xddf4e32f, - 0x43e6df32, 0xa3e8f43d, 0x27a8e1be, 0xf1cbb65a, 0x510d4836, 0x981cf89e, - 0xd38920ff, 0x94324b7d, 0x7059ba43, 0x7ec5cf97, 0x0df3e1ae, 0xff3d8794, - 0x4e657414, 0xe506d105, 0x76231ba7, 0xe9555ca0, 0x2e30f074, 0xcf7887df, - 0x7938456c, 0x7a8cb027, 0x8543ffe8, 0x0bf854de, 0x008d36c0, 0x3c1098f7, - 0xa31774a8, 0xca585fc0, 0x413bcfe9, 0xf31d4f59, 0x0091bfa1, 0x38070953, - 0xf0c11a57, 0xd5967483, 0x6ff38d93, 0x91f80c5e, 0x0f1c1d70, 0xdd5645a7, - 0x155f07d6, 0x0df128e6, 0xa6f90218, 0xa9be7192, 0x7a42ba44, 0x0aba046c, - 0x481647a2, 0xae173e88, 0x83ca15d0, 0x1cb8f708, 0xc257e758, 0xf0b1f21f, - 0xa694ffad, 0xa4ce35f7, 0x1e2f2e1c, 0x734a7b33, 0xd04def48, 0x656f9dd8, - 0xfa889a7f, 0xafbdf4e5, 0x149a6025, 0xeb8c9ee5, 0xd7fe5cd8, 0x1fff1452, - 0xb8f407c6, 0xffcb0f8e, 0x2dda224f, 0x235f4b95, 0x79d2bffa, 0x37989996, - 0x5d1ee01c, 0x00fd382c, 0x462d79bf, 0x16f824e7, 0x0c755c57, 0x6ad659e1, - 0x56911874, 0x1c8d62d8, 0x408f2b3b, 0xda1d8a37, 0x39ba246a, 0xf4894bf7, - 0x8b92b9c1, 0x0f800eaf, 0x4e0856e7, 0x32d657ac, 0x3790256c, 0xa816292b, - 0xa057995e, 0x1ca9657a, 0x051a275f, 0xaf4037a2, 0xde283b25, 0x8ef5a731, - 0x13df88a9, 0xa40f5fc5, 0x187ac1f8, 0x2e63e547, 0x959e48de, 0x56abf529, - 0xbb47911b, 0xacb597bf, 0x3ffc88ba, 0xde521bd3, 0xec53e93a, 0x5b51acb7, - 0x8235c6ee, 0x4e57771d, 0x07ca0c44, 0xefce64e6, 0x40f24811, 0x93fa0ff2, - 0x447140bb, 0xc20f30cf, 0x61bc89c3, 0x99eba47a, 0xdba05708, 0xdd7ca5e8, - 0xbe0aa733, 0x99ceb049, 0x1f67ce16, 0xfbbe0996, 0x09ff3e05, 0x5065ef40, - 0x5d740b1e, 0x38e4c316, 0xe626dd48, 0x2e79c70f, 0xca09f61d, 0xd438d3db, - 0x8fefaa28, 0xf75ca1b4, 0xb78911e8, 0xe5a52f32, 0xede947cc, 0x98f34fcc, - 0x74933ac1, 0xfc93af90, 0xf38e312b, 0x0367b32b, 0x8b5fd7d2, 0xe0169c4e, - 0x4239ddfb, 0x439428de, 0xdd68038d, 0x701f5b97, 0x067680a5, 0x5fac41aa, - 0x147ee396, 0x4ccab3fb, 0x74ab718f, 0x995a8e95, 0x17d61537, 0x9be2debb, - 0x6b8beb04, 0xf5c21cf5, 0x38374fa6, 0x1383ef10, 0x74133af8, 0x543f9fdc, - 0x81a3606e, 0x183f360e, 0xdb3a43e6, 0xda2035bc, 0x03e6fea1, 0x97cc0180, - 0xf0bc14af, 0x4e61eadd, 0x7559d38c, 0xfeed111e, 0x188f56a2, 0xe1a7e208, - 0x394441b2, 0x23d3be91, 0x5ab49ea2, 0x353d53d7, 0x4fd4ac5f, 0x59067937, - 0x4e9e4ec9, 0xa15c33f4, 0xd49fb51f, 0x045f8356, 0x4ac917b8, 0x57b7997d, - 0x9e8a61fb, 0x3961db56, 0xab7a67d2, 0x453f4fa3, 0x3f505b4d, 0x08f88f83, - 0x7bd205c6, 0xfd711fca, 0x1bf084da, 0x36abf378, 0x2103374c, 0x9d1c71f8, - 0x79e34cc7, 0x15d33cf8, 0xbfbf87da, 0x63e38f7f, 0xb9bbf01e, 0xe422fef5, - 0x1f00cda3, 0x9de6f3c4, 0xcfd4ccb3, 0x799a59f4, 0xf286a931, 0x4b070825, - 0xa23c75ef, 0xd53d2fcc, 0xbd695a23, 0xe76843ce, 0xe28ccba5, 0x763f6a01, - 0xf405741d, 0x857a776a, 0x90cbcc7a, 0x47b8945a, 0x4eb38e3a, 0x5d31ff40, - 0x6b4957c1, 0xf63361fd, 0x5f1466e3, 0xfe85cf4c, 0x8426fea1, 0xfc37a183, - 0x5e99e742, 0x4273e7cc, 0xf18edfa9, 0xe76c7494, 0x74431158, 0xd5d7e7c5, - 0x1c6214ea, 0xa08fb197, 0x7e90c9fd, 0x0cb8c29e, 0x7e4ecfa4, 0xb42e4a6d, - 0x97d1fe7f, 0x52d0b476, 0x0fb33e0e, 0xf5ab56e5, 0x9c709be6, 0xff9f2283, - 0x5de2724d, 0x206ddf98, 0x53be9a3d, 0x7944db4e, 0xebfd1393, 0x55df56ae, - 0x2cbd422f, 0xeb64c618, 0x0a138f3d, 0x3a15da9c, 0xcb793938, 0x53ef5c20, - 0x582c7745, 0x5f87ed02, 0x3b8d38f7, 0x94fcca7c, 0x9b0fc816, 0x30abcbf8, - 0xc78e5f7f, 0xfee4023c, 0xde5fd2b0, 0x6ae50fb6, 0x821cfce9, 0x4576c597, - 0xda39a9f2, 0xbf02f5e3, 0x52dc4737, 0xd2b8fc8e, 0x24487066, 0xfa19eb77, - 0x7711cd59, 0xe5bfb1db, 0x4c26f9d1, 0x36bfd60d, 0x6e3c9ca1, 0x1e2131c9, - 0x18132d9a, 0x0aaceb96, 0x4f1bbe9e, 0x885240fa, 0x73847772, 0xe5744cba, - 0x0c272864, 0xbcad0609, 0x2f7971d6, 0xb43e1dd9, 0xf5acba9f, 0x60cc8148, - 0x7ca05409, 0x69795493, 0x3c717a71, 0xa3b4e2c9, 0x9142b4bf, 0xaf862c37, - 0xf73960d3, 0x5eaf389f, 0x962e63fd, 0x867f4b50, 0x4128ccb0, 0x9bda3ff9, - 0x573e10c6, 0xbbc58353, 0x6844f518, 0x70205d7f, 0x4fa38e50, 0x7e337647, - 0x5eddee48, 0x7a341bb2, 0x7a5e5ba4, 0xf221f5a2, 0x7a811e52, 0x792058a2, - 0x0ceb61e9, 0x0c12feb8, 0x3c5c00b2, 0x545eb8db, 0xce267bf9, 0x49e5f005, - 0x5e5c9165, 0x2673e4e9, 0xd1efc60e, 0x452a5cae, 0x5e021e22, 0xc3e9e0c9, - 0x9378f79f, 0x9d1e507f, 0xa987fa41, 0x21fe9007, 0x0fe144fd, 0x6f078a8f, - 0x50a3f5d9, 0xd912cb5f, 0x85cb9503, 0xe2cfb436, 0x6947d1bc, 0x2edcc5be, - 0xa6bf9768, 0x892a1cf5, 0x7979444b, 0xc799d962, 0xbebd41ef, 0xfff49c29, - 0x5667a5a4, 0xa66e3c60, 0x211a7057, 0x7d1a59ef, 0x6f987bf7, 0x905d3a34, - 0x81f0ab3f, 0x914597fb, 0xb8084f68, 0x759e8cce, 0x83321656, 0xf139e29b, - 0x3b409633, 0x34e0a34f, 0xa1e07a3b, 0xef527ac7, 0x37bc05f5, 0xfad0fe46, - 0xa8d7bc3f, 0x3e7759c8, 0xc6a2d9ca, 0x700a87e4, 0x7cf5eb5d, 0xd7d18d9e, - 0x3927de53, 0x1cb97639, 0x3fd8a99e, 0x57b3a59e, 0xc0f7c3c6, 0xcef9416a, - 0xc8a956f1, 0x88e340e5, 0x0d3f1863, 0x3e48172c, 0xa252bc79, 0x5ccdda1f, - 0xef784d9e, 0x5d900a28, 0xb43de5d8, 0x722b5a92, 0x3674a3de, 0x94588c17, - 0xe3dfa76f, 0xfe479ffe, 0x9bb62563, 0x83b5a2d3, 0x0cfd0226, 0x67bcb840, - 0xf1e9fd26, 0xefbad196, 0xea6945f0, 0xd38ead55, 0x8bab3de4, 0xe7b0c7ae, - 0x52277bac, 0x3992af3c, 0x2ade9122, 0xc1376e65, 0xe61b259f, 0x4f9d5733, - 0x2ac7b731, 0xa27ec18b, 0xb07b5aef, 0x3389fec7, 0x78a8df20, 0x3a13f154, - 0x19765eef, 0xacd076e3, 0xdd7ada75, 0x16301076, 0xe5caba8a, 0x32bf76da, - 0xb9459fbb, 0xe038dee8, 0xaeabf21b, 0x80821e50, 0x266e7f21, 0xa61f71e3, - 0xced543e8, 0x517a592f, 0x6668728f, 0xc23d45e3, 0x1fd2e673, 0x385fa7e6, - 0xa1bef3b5, 0x3ebb4a20, 0xbf934e39, 0x534435d1, 0x30f766ff, 0xa75bf7cd, - 0x5ef9ab5f, 0xc9a919ee, 0x5e3d5edf, 0xfd467f53, 0x7a1cad24, 0xa3d69a37, - 0x79bfa7e2, 0xa3e8a5bf, 0x12ec4277, 0xe23a9d35, 0xbf91133f, 0xe4672c3f, - 0x33787cbf, 0x1d31f8d3, 0xe7822423, 0xf93d5c80, 0xc8e5f731, 0xbf208fef, - 0xa1f44fc9, 0x7343f3c2, 0xa228c9a1, 0x7ee4627f, 0x725fa879, 0x5e503990, - 0xfdb1d4ce, 0xff8f5442, 0x9cf30e67, 0xe3bafec7, 0xf10f4b0d, 0x1f884378, - 0xff78a573, 0xbfcc0670, 0x4d79790f, 0x16c3f72e, 0xffaf36ee, 0xb58e0838, - 0xfc9ad16d, 0xebf1fda2, 0x3bd60e3f, 0xae1d044b, 0x93e146b3, 0x7da0165a, - 0xa0e8bb52, 0x40c4eafe, 0x583be62c, 0xf4b46c67, 0x0a8b838f, 0x258f800f, - 0xa9de2837, 0x193fc3fa, 0x9e0a453e, 0x1a70b4cb, 0x90e3cb93, 0x29108f5f, - 0xc7239cdd, 0xf103fee7, 0xf49eb41c, 0xdc7fbcdc, 0xc847227a, 0x9f9f0859, - 0xe3dfaf1b, 0x17940f1e, 0x7f0b908e, 0xfe4cb826, 0x47a5c247, 0xd82f47cf, - 0x72a3fa0d, 0xfdfb819d, 0xbf5c33de, 0xfefd7237, 0xf68fb47c, 0x44f39b87, - 0xed070ee7, 0xe93ed297, 0x618d7ba1, 0x59df1819, 0x797d23a1, 0x8190997a, - 0x2126c2fe, 0x0f36fc8c, 0xc81648ab, 0xc878b9be, 0xaa31fd48, 0x3afded07, - 0x0551f390, 0xe4096b3e, 0x71e5ccdf, 0x716e35b1, 0xf5038a4a, 0x1eac1ff6, - 0xe27a8b8a, 0xfd9e1e11, 0x696be130, 0x2bee45df, 0x6bd0127e, 0x8512d1e5, - 0xd5cc5f8f, 0x2e1f3ad1, 0x949db914, 0x1f70ba2a, 0xa9d81563, 0x96065768, - 0x915f28eb, 0x6d59e9c7, 0x9d0a1ff7, 0x14dd94c7, 0xda88f386, 0x7d7dba24, - 0x2e51fb8c, 0x793d0f8f, 0xb3ed1857, 0x68742a01, 0xd6bddbef, 0xaf582e69, - 0x8d96d0bd, 0xdcdadfb6, 0x4d6fea68, 0xcf159746, 0x748cfca1, 0xfe8eca78, - 0x8cfac0a0, 0xe655cd33, 0x580feeab, 0xe936fe94, 0x9da2bf41, 0x1e289822, - 0xf91af161, 0xb16715f9, 0x1ccade26, 0xa76e0b02, 0xf428f3d6, 0x1b42c76a, - 0xeff697e1, 0x5db178d5, 0x1ba417a1, 0xcf4abbc4, 0x8983fda1, 0xe9cc8dec, - 0x15d9f389, 0xe51a8e52, 0x8f748dd9, 0x1f90eafd, 0x07fe5cbc, 0xe3c4be6e, - 0xded7de2c, 0xe18879c3, 0x0c9c525f, 0x5fce4aec, 0xbee2434b, 0x024f913f, - 0x40cf0e66, 0xde1e5684, 0xdac9d0ab, 0x48de827f, 0x3ebc02ba, 0x8fe5cb9c, - 0x36fdc0ab, 0xb2c73bca, 0xfba230d4, 0x96270b1f, 0x51384560, 0x3872ba5e, - 0x1f3df379, 0xcc749e10, 0x7f71b46f, 0x72e1f90b, 0x31c2a47c, 0xbe9e6449, - 0x3c88f2f4, 0xca1bfbe5, 0x6ab7ae7e, 0x61d90fc8, 0x02c57728, 0xcc2cd2c6, - 0xffb6bc61, 0x8f9c0e7a, 0x396ae885, 0x96aee5d2, 0xcfe43094, 0xcabc6564, - 0x0ca7d29b, 0x205fa077, 0x040ed018, 0xe3c0c3bf, 0x574edc3f, 0xb94f7ae5, - 0x72c47ed6, 0x1f8f664f, 0xeaf7daa6, 0x82973c77, 0x59f3aae3, 0xfd61d8a5, - 0x125577cd, 0xdca2724b, 0x808f765a, 0x5ab1dcf0, 0x717df8d4, 0x0325615e, - 0x7fce3e3f, 0x8efd13af, 0xcdafb038, 0xf575cf28, 0x5e083382, 0x0a817b81, - 0xf8871338, 0xe24fe02b, 0x8967bd3a, 0x57c7425e, 0x85abb1d7, 0x5de71b8f, - 0x9f90c82c, 0xa02f5154, 0x9956b7df, 0xa3055c7f, 0x3e9969ef, 0x9e21e301, - 0xe38a5616, 0x03335655, 0x332af5c6, 0xf2865399, 0x7443c6ca, 0x02b9edde, - 0x206f2539, 0x4f3a4fc9, 0xa4f02ae3, 0x4d1d01e7, 0x7643284d, 0x864bb867, - 0x167f89f1, 0x4cb5a71d, 0x59efa2f0, 0x843ce2d4, 0x11d001fe, 0x2d3c7dc5, - 0xe75f1a01, 0x5d7271e5, 0x80e9c18b, 0x658d4875, 0x5521ffb4, 0xd4329c1b, - 0xdf29b63b, 0x2d95f18f, 0x0ddfdc8d, 0xd67493f5, 0xd1c3d7fa, 0x9910ab5f, - 0x790a0144, 0x5659fa2a, 0x30562e85, 0xf7ee3b77, 0x41fe1933, 0xdca548bb, - 0x2a6f3d5a, 0xd0e52266, 0x13dc8378, 0x6b9e409f, 0xd3b240dc, 0x678daa94, - 0xc92b2d48, 0x7d6233af, 0x890faca8, 0xa5d54877, 0xac971714, 0xf35bf2da, - 0x8e086222, 0x9e1e3c59, 0x8d88ef73, 0x727cc2b7, 0x1fe3797f, 0x41873d30, - 0xfe5b8033, 0x4c073bb2, 0xac16ff87, 0xa62378d8, 0xe8cebc4f, 0xe08fc19c, - 0xfa8c6657, 0xe8fafcf1, 0xb2abf295, 0xb9d00f26, 0xd27dafc2, 0x094f1abf, - 0xfe954fe5, 0x4d4ef943, 0x7f865ed7, 0x120526d7, 0xdf4f0f91, 0xdb03323b, - 0x73de3657, 0x5f88c7c8, 0x77d00705, 0x117177a5, 0x5660ba23, 0x5e5bd097, - 0x490b3784, 0x1f37bfec, 0x3b7c863f, 0x13e7effe, 0x95df087f, 0x63ce8c09, - 0xf649fd81, 0xdfaa9a9c, 0x3eb9f223, 0x246790bd, 0xc1464ebc, 0x053bac0a, - 0xc7bee0da, 0x2b4e6078, 0xf02e7fa4, 0x4de38b3c, 0xef9e3c81, 0x6b40fd7b, - 0x4b37ae0c, 0xa78ef5c7, 0x76e68edb, 0xa8ffb748, 0x06590fd8, 0xdced0536, - 0x771126c0, 0xc0e0596e, 0xe2d63be7, 0xc9b96bbe, 0xcaeb0699, 0xf448dfba, - 0xf68a0484, 0xa7689651, 0xb6aee5b8, 0x9f69cb8f, 0xd2c0d1b1, 0x0ee06e28, - 0x006473c3, 0x4caab0cf, 0xacc357b2, 0x857aaf68, 0x1e88aaa4, 0x22f5087b, - 0xef2cb40a, 0x30ac53ad, 0xb042aefe, 0xec7b3347, 0x59fed51c, 0xeb4c9f9c, - 0x6820ed57, 0x8fddb0c7, 0x0b4aa7e5, 0x19bb224b, 0xf7fb83e6, 0x90264cb6, - 0xff5213ed, 0xd92332f4, 0x7baf76af, 0x5bb470ca, 0xa0e6a797, 0x9ae30add, - 0xfd7f6e24, 0xbb67ca3b, 0x285ef94e, 0x49b9e0e6, 0x05801f75, 0x8718d174, - 0xfeaaed53, 0xe763a5e7, 0x9505b954, 0x9f2f9b7f, 0x59ff7ec1, 0x5563dd72, - 0x634d4de8, 0xe9e079f8, 0xcf8dbd0a, 0x9e9a5337, 0x73dbb3ff, 0xfe93aea7, - 0x39feeb79, 0x9ffae1d7, 0xffd88eb1, 0x3cd8f821, 0x3ac67ff9, 0x4ff2996e, - 0x5f37875c, 0x43cfc86e, 0xe746d679, 0x7e2eec88, 0xdee41c2e, 0xcb9cbc3d, - 0x09938b39, 0x74ffc764, 0xfd84d779, 0x1c1f419d, 0x7778a1cf, 0x67183a08, - 0x88a1a588, 0x8ca5cdec, 0x2c8681f6, 0x4340fbe5, 0x224d3a96, 0x6e1603da, - 0xec520e27, 0xb94b41ce, 0x9ca719dd, 0x118b882b, 0x3fd4327d, 0xca5bcbf6, - 0xbee0c6e7, 0xd5ec9190, 0xf5dd36e6, 0x5e53d416, 0x868fce89, 0xd2d289da, - 0x5f9c4a95, 0xf6aa9f6b, 0x79e31a68, 0xb4b3b2fd, 0xa3daa74f, 0xb4f29443, - 0x603f7ca5, 0x1ed68b48, 0xdad6ab8d, 0x1082fa8f, 0xbaa9733b, 0xeb49d07f, - 0xe9d72dd3, 0xa87ffcf1, 0xb07b89dd, 0xab0714a8, 0xfeb4067a, 0xf630d74d, - 0xf9f77e74, 0x1fdc1c8c, 0xd05ab99a, 0xcf5539e8, 0x7e282402, 0x43e3e2a4, - 0x3f8873d4, 0x5fb534f7, 0xaf3e6fd2, 0x2e4c7048, 0x539cd74f, 0x1e7eec62, - 0x3a73712f, 0x11eaf5fa, 0xddaed16b, 0x37c6eeb7, 0xfd697d31, 0x04e5e19d, - 0x6f54f5af, 0xebc6cb7f, 0x7650ff30, 0xe6123dbb, 0x53a8d0f5, 0xefd009ef, - 0x85e33c6a, 0x2978b3eb, 0x9e14b68f, 0x7ab3d08b, 0xa4dbdfda, 0x0d9f4c0f, - 0x45122be5, 0x23be911c, 0x1832981d, 0x59309f9d, 0x35f57e78, 0x30e3ee8c, - 0x1a9f5ce5, 0xd73d0987, 0xc7c3cab7, 0xc4f00559, 0x18963573, 0x39a91f7e, - 0x08e9fee1, 0x818766ef, 0x8b3939e1, 0x624fee72, 0xa82aaed5, 0xbf7edc77, - 0x0bee167d, 0x7e881867, 0x26ce98a4, 0x9ed993c4, 0x71c2af63, 0xcd35e242, - 0x2037e929, 0xfbb5bc59, 0x20679ef0, 0xc9cf7b7d, 0x2a9d312f, 0xf3c3efb5, - 0x88465225, 0xbf6bd29f, 0x9bdc1198, 0x4a5f3387, 0x6e3b9632, 0x754e9110, - 0x869a6feb, 0x50c154fe, 0x4f581ae7, 0x1bf30258, 0xbd611e60, 0x7b7989f6, - 0xce9c20a9, 0xf59648d5, 0xdfd80d15, 0x7fba08a8, 0xae03bec0, 0x4df3a7cb, - 0x80f657f4, 0x0e3a47a8, 0xc38ff653, 0x1fed7b32, 0x30c2fcd3, 0x3b59e14d, - 0x7a15c3e4, 0xca7b635f, 0x6b77fb87, 0x106e5213, 0x69f53d1d, 0xbbd6195f, - 0xab1bbbf2, 0x26fd5f68, 0x9fcf1593, 0xcafb2985, 0xa574e3a1, 0x43675b3a, - 0x6418b46a, 0x55f11673, 0xe0725f0f, 0xe68353d8, 0x9cfaf501, 0x736e3aa7, - 0xda83c71e, 0x64c2d19f, 0xf74323b4, 0x81fb43ad, 0x56be7079, 0x31fda9ea, - 0x01e746d6, 0x518b8874, 0xa7abb57d, 0xe9df0db9, 0xff1fbb24, 0xcc82e382, - 0x35fc431a, 0xcedb55ac, 0x0dcfca9c, 0x2a18f4a8, 0xfdd0a52f, 0x6f7ad4f7, - 0x9f81e138, 0x1fad0827, 0xf6d0d70a, 0x5833b7f0, 0xe160ddde, 0xa95d88fb, - 0xac22b99d, 0x473da57b, 0xbf5a7f33, 0xef7fd3d0, 0xbe6d3cfd, 0xb9f6364c, - 0x7d07943e, 0x4e8277cd, 0x6c596fbb, 0x8d2fb6d1, 0x25777ed1, 0x4592f368, - 0x6d91dfe9, 0x8e1af3a2, 0xf79e137c, 0x18d8f953, 0x8af7efe2, 0x2efa2adf, - 0x1e74c991, 0x79de9375, 0xe3c4e50e, 0x01d24033, 0xf82c3c7d, 0x552e58cc, - 0x0f515bb4, 0x93d3adc6, 0xaefc7a9c, 0xbde0ce5b, 0x6ba016a0, 0xf771e584, - 0xc56e9b47, 0xf148b17c, 0x70fb9b0d, 0xcb51d239, 0x37bf5f77, 0x3a9fcf1b, - 0x5bce740d, 0x75b1b73d, 0x1e2b61ac, 0x94cb8a0b, 0xfdf069cd, 0x84e62aa1, - 0x6323b099, 0xfc712363, 0x15a2d12d, 0xd1f3ddf5, 0x718efff5, 0x8c19e694, - 0xe14219f6, 0x46d23757, 0x756e3672, 0x5bf780b6, 0x5f9b1e1e, 0x06317289, - 0xaf9465fc, 0xc57dca90, 0xf015c717, 0xc5b6c0f8, 0xbe23c52f, 0xdb0f5837, - 0xa2159e69, 0x52d8a713, 0x8b7fe5c1, 0x7b3ed185, 0x3752a8f3, 0x72ec4d1e, - 0x8b3c0ec9, 0x41dee2d8, 0x2d595ef3, 0x9cacd972, 0xc8580197, 0xbe9c3951, - 0xfd4a360c, 0xb3346e98, 0x972839f8, 0x7ce8c292, 0x81f67f50, 0x57cb84b4, - 0xe9cc6f6c, 0x1143debf, 0x5cc8f18d, 0x9fe467cb, 0x6dfd0b9f, 0xf299b19d, - 0x538d3caa, 0xdfbbbbe8, 0x1bba3d10, 0x36724bf0, 0x9e2ce41a, 0x878e63c7, - 0xf575b789, 0x3a20b4c2, 0x7c8055d5, 0x2ee7e2cd, 0xbebb7e30, 0x87e334a8, - 0x9b9d4cfc, 0x5518e5cb, 0x97ebbb1e, 0xda05dc61, 0x635f51fb, 0x0fce783f, - 0xb7d71952, 0x443fa851, 0x830cf37e, 0xe839ef03, 0x430e402a, 0x56825d7b, - 0xc9181c4f, 0xc1fb35f1, 0xa09eccbb, 0x728c4d38, 0xbea3661e, 0xeb069cde, - 0x744338d9, 0x6c78076e, 0xfa1068a9, 0x55c4c78a, 0x0d997e70, 0xde6fd1f5, - 0x1b139152, 0x8c669ebc, 0x36d0c073, 0xdb9f0fd7, 0xbfc885d3, 0xbc79235d, - 0x1cdd67bd, 0x3f4071be, 0x479a87a8, 0x6ae6ae97, 0x557241da, 0x6d6de567, - 0x073a7aae, 0xcfc155d9, 0xf813ad5d, 0xc4a4827e, 0xf28b9bcb, 0x4bf4bf49, - 0x492b152f, 0x57e2849f, 0xe5fd3f9d, 0x9911e907, 0x8719f1f1, 0x4cceb49b, - 0xda07e1fa, 0x4af9743b, 0x1e0bd47d, 0x62ba7f6d, 0xf8e33651, 0xaf105fa8, - 0x7bc5e63a, 0x95fda193, 0x3a16fc2a, 0xe069c91f, 0x8d9db1ed, 0xdbf48bf8, - 0xc8e00169, 0xa1ce82e9, 0x3c38f7b3, 0x7c3a24b7, 0x2e01f86b, 0xae7487d2, - 0x78f7a52b, 0x658e098f, 0x7de8efb8, 0xe7f3a25d, 0xcd4f7aa1, 0xb13070ab, - 0x3e9ce736, 0x0f9c4dec, 0xa76935ea, 0x01fa89d7, 0xed8a97d0, 0x094b2a36, - 0x5cd4b3bb, 0xd7ade8e0, 0xab6d5cba, 0x937282af, 0x03f69983, 0x99534c3c, - 0x79c0307f, 0x1ccf33ed, 0x3df58abf, 0xf803ae0e, 0xe6bce099, 0xe63347f9, - 0xedf37b40, 0xb9b426ad, 0xf5a1cf43, 0x76a4ef6e, 0x4cab4b71, 0x23c519d3, - 0x86b95465, 0xafd90b08, 0xe48674cc, 0xc6c934b3, 0x3d10a7ed, 0x50f80eb9, - 0x644af08f, 0x38d0af04, 0x49f8e871, 0xdefcc905, 0x1a52e2e4, 0xa7454377, - 0x5d90e31e, 0x4ec57aae, 0xefa9f4f2, 0x7bb1fb42, 0xff23a73a, 0xc81a1577, - 0xc1f87e1e, 0xcf119349, 0xc51265de, 0x7bd17ad1, 0x233dbac8, 0x1cae9cf5, - 0x7f28cd8b, 0xdbb9ccb7, 0xfec3e8ec, 0x8b3152d8, 0x965a2fce, 0xa5633b70, - 0x88e481bd, 0xe7b942a5, 0x71cbd8a2, 0xa213bfaa, 0x3754b727, 0x9bdef198, - 0x8590de7a, 0xed97dbd8, 0xbbbd1fbf, 0xf18bf961, 0x2aee4fa8, 0x79c78869, - 0x4ff0896f, 0xd5df1377, 0xf2029f93, 0xf1e51e38, 0x920e91a2, 0x7ff2dd2f, - 0x0e3b39c6, 0x5569181e, 0x43db8af8, 0x417fe25f, 0x928d66bf, 0x1c6014a7, - 0x8e44b52d, 0x74bc6076, 0x00d3bbdf, 0x7abd93ae, 0xfb8d63f2, 0x2fc1f481, - 0x49382632, 0x681e9e5f, 0xac9d22b0, 0x8f46fc6a, 0xe2ce6bf7, 0x7fe855e9, - 0x87b70255, 0x9818c556, 0xa1f342df, 0x2e754f45, 0xf5a7a866, 0x0137dc09, - 0x798fc5bf, 0xfd102316, 0xbaf18e4c, 0x298700ad, 0x30bbbe31, 0xd7ac4aad, - 0x129c60d9, 0xf080b447, 0xc563a29d, 0x9daf1e06, 0x115cf385, 0x59c511f3, - 0xd1c5a727, 0xc5a3547d, 0xc9fbc3ad, 0xf6d5677a, 0x8bce8cb5, 0xb015bc51, - 0x8ce1f74a, 0xb6bdc718, 0xeeab8e27, 0xdcf1a913, 0x04290575, 0xffc1212f, - 0xcb23e22d, 0x1ef1101a, 0x403e987e, 0x46aaf8f6, 0xcd41f913, 0x91da3b09, - 0xf823323d, 0x3e7aa43e, 0xb163e017, 0x0c567c02, 0x95d69bbc, 0x17bb1494, - 0x91faa5e7, 0x50af20f1, 0xcc2565de, 0x4beb8a9b, 0x4aedc37a, 0x0cc67a86, - 0x1660365d, 0xa2b9eae0, 0xc61eac78, 0xd8583c21, 0xabfb4c38, 0x40d122bf, - 0xf2d0d8f1, 0x5c780b27, 0x21050b32, 0x135eebae, 0x755dcfdd, 0xaaf7bee0, - 0x301e7e50, 0x6767c939, 0xffbc1481, 0x66771dde, 0xaeddff7c, 0xdbb5bf9c, - 0xa63f740d, 0xf8ccbe3b, 0xe71abcbe, 0xd9e51a88, 0x31f2788c, 0xc7f421c7, - 0x8f71abfe, 0x4fca461b, 0x6dac7f60, 0x63c515c0, 0x68eac6c2, 0x8529279f, - 0x05f78279, 0x5feb2956, 0x7a870dd5, 0x75f5ea3b, 0xf6079428, 0x378d870f, - 0x2226bbe7, 0x88ec46dd, 0x47dafd47, 0x171343bc, 0x79287bc1, 0xfa6204b1, - 0x9c79aa93, 0x3cea6624, 0x5348778a, 0x0ad93ef9, 0xdcfc6016, 0x7c84c0a0, - 0xfd4beaba, 0xe887700d, 0x927accd7, 0x90ae9193, 0x7f2f48b8, 0x6576e645, - 0xa2dbdc88, 0x02f1f9f0, 0xcf91ee25, 0x93e7bff2, 0x5228bb25, 0x1889f7d9, - 0xe8724295, 0xd90a5711, 0x411cc443, 0x9d9cbef0, 0x87b15073, 0x8f9ca77e, - 0x83e72bf7, 0x83e72b0f, 0x0b77c55f, 0x863f90c0, 0x7a4016ef, 0xe549c9bc, - 0x2815346f, 0x6fe399ca, 0x4892ee45, 0xf9941fb2, 0xadf994e9, 0x25734eb0, - 0x6d567e03, 0x5879d3d3, 0xe984c263, 0xaf32cf68, 0xdb119edc, 0x7587ef73, - 0x9efcbfc2, 0x095da773, 0x3a4f3a1e, 0x3ff7cac7, 0x542d7c55, 0xb612afea, - 0xc75f9019, 0x36e16a76, 0xc6a452fe, 0xda622cae, 0x4d1397f3, 0x4bf53443, - 0x97f3daac, 0x6ad7ec93, 0x68764fbe, 0x975e5fcf, 0x1f643e31, 0x0b574b56, - 0x806e8013, 0x7d33aa4e, 0xd685ff34, 0xcd7b8a52, 0x74c7b90d, 0x3f36ab47, - 0x2fcda7df, 0xabcdaddc, 0x46c3c9e7, 0x9230f429, 0xf131fc8d, 0x0cf7e44e, - 0x0107ef85, 0x3ab36fbf, 0xcfda1199, 0xf8bf7816, 0x1b00c61e, 0x76c94bed, - 0xe3ac238c, 0x5cb09ff7, 0xc3bdcbc7, 0xbe7af695, 0xdb8ec56f, 0x4b1dbee8, - 0x06ede1cc, 0xfc7eeff0, 0x72f1a48e, 0xfe87af0e, 0xa21bd612, 0xe5c353f4, - 0xfe459c93, 0x33ec9b82, 0x62b36b23, 0xc2fe016a, 0xe9399a34, 0xab0c759e, - 0x9075bf27, 0x51327f72, 0x43bca4e8, 0x3e6186b0, 0xf0a67045, 0xe48f85f8, - 0xfe4950c3, 0x89f12a75, 0xf447745b, 0xb90d97e6, 0xaaf007ba, 0x910286f8, - 0x5623e2e4, 0xd8f9ef46, 0xbf13f75c, 0xb016c36e, 0x8f6b336e, 0xf87a1549, - 0x61bcede7, 0x5c135fc4, 0xb52fda0e, 0x780b2415, 0x8588a52e, 0x4536cb9c, - 0xc4a3e869, 0x5f42171a, 0x4be84243, 0x9d7f7f4b, 0x3945d5ec, 0xe842ce90, - 0xe5be2ff0, 0xaf182c51, 0x05fa8f4c, 0x7689d58f, 0xca9e054a, 0x754f9602, - 0xee319b46, 0x73d18b67, 0x3fd8a579, 0xab9f4aa5, 0xb2eb59e4, 0x566bfbe1, - 0xf6e649d1, 0xf13d2dba, 0x96df1825, 0xea35f600, 0x5c919963, 0x1fd3b07d, - 0x7fd43576, 0x65fffc04, 0xeb1bfd0c, 0x65efbc64, 0x5f10e4b5, 0x7949623f, - 0xd05ef300, 0x437f58e8, 0xe5aff731, 0xef826ce8, 0x05bea151, 0xc23da5ef, - 0xc1a94cf2, 0xfebc2df5, 0x5164597a, 0x31189f90, 0x9dbfea82, 0xcef86667, - 0xd9a07781, 0x63ec7187, 0xdd77acf2, 0x7b7feb41, 0xaf07d714, 0xa8f11c19, - 0x7c991e0f, 0xd287a677, 0x685f8d74, 0xbee4104b, 0x8f8517ce, 0x92bd7236, - 0x78c7e25b, 0x34c2747c, 0xfd039957, 0xe90bb71d, 0xf112e742, 0xfd375be8, - 0xa87e2b44, 0x0fc106e4, 0x5d749b4b, 0xe3ff430e, 0x35770b11, 0xd59e291e, - 0x02f98652, 0xd903ee91, 0xd9ebe25c, 0x7e02aeb8, 0xe54af0fe, 0x181ea871, - 0xbfdb9a32, 0x3c448693, 0xdffa1430, 0xb15a2450, 0x2b7a0dff, 0x4ef1e7dd, - 0x1757e466, 0xe097eabb, 0x11096dbc, 0xda6fcf0c, 0xbe781a0a, 0x00ccc0d8, - 0xbd6b934f, 0x4a69f117, 0xf6c08cf5, 0x7a7e0747, 0x5b19ed1c, 0x703a4882, - 0xaef9cba2, 0x2817eb1b, 0x79e29df1, 0x9b3c70eb, 0x599ab445, 0xb9541c0f, - 0xcbc99ebe, 0x0ab2ffc9, 0x0accdef4, 0xce0d436b, 0x708491e7, 0xae6df3b2, - 0x79e20b06, 0xd13d40c3, 0x7f224941, 0xc2556a57, 0xffcc0ab4, 0x7191a062, - 0x1f2ff3be, 0x5381fe8a, 0x5b3575a0, 0xc75e681a, 0xc139892e, 0xa9a896ef, - 0xcf85a1d9, 0xf8f146ef, 0xf1e30990, 0xf5b79f80, 0x8b9a9ccc, 0x78a7a3f4, - 0x6b7c7f53, 0x7ece5d73, 0x2afe61fb, 0x110b0394, 0xc29785be, 0xfa404f98, - 0xfe61293d, 0x5b017f77, 0x60d9d680, 0x6e41fec1, 0xbfa2fabb, 0x7e9cd188, - 0x4b0e0b9b, 0xd7824ef8, 0x341f1021, 0x444e4e5b, 0xb528783e, 0xa1e8e88c, - 0x899a8f82, 0xfcf3862f, 0xeef779db, 0x137a3c41, 0xe77f69c3, 0x315982a1, - 0x60bef4c1, 0x32f44894, 0x4e616fee, 0x9463e23f, 0x91fbf881, 0x8c56c708, - 0xccf3794f, 0x824bbf64, 0x986cd975, 0x2862c4e7, 0x5da2fe87, 0x7ef13e62, - 0x0b8f0575, 0xd57e302b, 0xf8843b65, 0x31664a90, 0x3949ae7e, 0xef9114f7, - 0xb435435c, 0x25956ffa, 0xd8cfde97, 0x4270d092, 0xbb20b6d9, 0x5722906a, - 0x45889406, 0x5906df28, 0xeb655db8, 0xbb940594, 0xaa47fba1, 0xed29d7be, - 0xa65b328c, 0x371b54a3, 0x7d7015d2, 0xe97f6a1b, 0xc35edc2c, 0xae8fbc3f, - 0x893f35cf, 0x317438e7, 0x197f7ada, 0x0a739ca5, 0x3a54afb1, 0x7ae560df, - 0xd1ae4362, 0xa1bd7487, 0x2a59db98, 0x47f2ab1f, 0x872abf85, 0xef7e7bd4, - 0x5195f628, 0x87365e4e, 0xe599eae4, 0xd4076f78, 0xc317739e, 0xfa56897b, - 0x1f72aefe, 0x6f6294f1, 0x5bd8a7bd, 0x5bd8a1ff, 0x05bda3ef, 0x835186f9, - 0x1437bf08, 0x08dd762e, 0x20901af3, 0x3a14df11, 0xedc44c4e, 0x271971af, - 0x61d97d2c, 0x0ea2d111, 0x348f05e3, 0x36497bf2, 0x1598ed97, 0x95cf59f1, - 0x766b2cf9, 0xbcbb3469, 0x7ae3f27c, 0xe43ed1d2, 0xb9557beb, 0x994c794f, - 0xfe6571ff, 0x57f3286f, 0x43498fed, 0xbca132be, 0xefaf10df, 0xfc297e47, - 0xb9d0a729, 0xb57950a8, 0xe908c401, 0xfc9122eb, 0xe778209f, 0x25bde46a, - 0x4ef5f720, 0x1e68c959, 0x7660dbbf, 0x7c462c57, 0xa714664e, 0x27aae89d, - 0xb90365b9, 0xf8b37245, 0xca6ceb5c, 0xe5833847, 0x6381519e, 0x8e5acbb1, - 0x4638be72, 0x24571f4f, 0x5bbdd0a4, 0x1d0efed5, 0x0cf072f7, 0x82a66795, - 0xf3e25ef5, 0x6c7247ff, 0x8ee3e32c, 0xfd3a24bd, 0x4f1cde5c, 0x91237926, - 0x5fed0a7c, 0x636f3795, 0xbe2064cc, 0xfba1644f, 0x610a7700, 0x9de7844e, - 0x3f307c28, 0xff7dd197, 0x673d8ac1, 0x01d1de57, 0xceb8a14e, 0xf5b04ed8, - 0xfc7af883, 0x1bf75325, 0x8f8edc6c, 0x9a27e4d6, 0x4bf535e2, 0xef9ac9ac, - 0x35c3ec93, 0xb23b27df, 0x32ebf935, 0xffea6946, 0xc9a459c2, 0x593050df, - 0x2e4cbf53, 0x6665e4d3, 0x0e4877a5, 0xfa1eed36, 0xa7fd1eb1, 0xa71fa1b6, - 0xa14f86f5, 0x0e0bf0f1, 0xa3b5e160, 0x00e8678b, 0x87518546, 0xfc864cef, - 0x6793d1c6, 0x0aef80e8, 0x3afe1f07, 0xd3685819, 0x7f3c29e8, 0x53afe1f5, - 0xf465bf20, 0x863f3c75, 0x3adcf091, 0x2f0cea7a, 0xea1c59e0, 0xd0347479, - 0xea972df1, 0xf83da28f, 0xe6d365c7, 0x4ef84b26, 0x06625940, 0x8a6ce7cc, - 0x7efc61e7, 0x15acec73, 0xfc761178, 0x8f74f577, 0x79a337ed, 0xfc8b8ebb, - 0x8b8e8d5d, 0xbb0d1dfc, 0x53f6f1c8, 0xcbbef553, 0x7e9a0e04, 0x64115fdf, - 0xfd05af7e, 0xdc6939cd, 0xfd14c4df, 0xdfd14c4d, 0xcdfd14c4, 0x6fee7a39, - 0x26fe8a62, 0x89bfa396, 0x324d5be9, 0xb934efa5, 0x726f6d28, 0xbf7dda53, - 0x6ae729e0, 0xef380a3d, 0x985b8b4f, 0x1117e4c3, 0x4ae7a14e, 0x4f9df43a, - 0x45ca7ed0, 0x12fbc0e6, 0x394e2287, 0x39acbf70, 0x2e7444cf, 0x4c3bb674, - 0x9730bdf0, 0xb62f9be7, 0x617e503b, 0x8e9eed1e, 0x946cb6e8, 0x16b5cdbf, - 0x35bbee27, 0x23c7f45f, 0x1bd6149f, 0x714cdee8, 0xe9c52767, 0xbdfc2d0a, - 0xc7114384, 0x91e3288e, 0x9179da5c, 0x277c45f9, 0xb0eedcc7, 0x3f60e32a, - 0xea326e30, 0x3025c2b7, 0xbf5bf52e, 0xb0a9fa98, 0x842b8f74, 0xe1fa6b8c, - 0x410a2771, 0x3176a6e3, 0xc701177a, 0xf5c66875, 0xfc3f744b, 0x78c25fa2, - 0xd3b44761, 0x354d718e, 0x21df8c5f, 0xdfcf45bf, 0xf8742c5f, 0xb893d425, - 0x5bef89bd, 0x33d881c6, 0x1f0d79d3, 0x47a865c9, 0x5d9db971, 0x9a179d7c, - 0x9f900bfc, 0x6077958a, 0x7ba58cc0, 0x730c4c9b, 0x9128bea2, 0x38363bbe, - 0xe339df17, 0x1b15a0ef, 0x1f90dbdd, 0xde5c74eb, 0xdf3318b0, 0xcfb5d057, - 0x3bd415ff, 0xec983b19, 0x4bfb0495, 0xb404752c, 0x44cae45f, 0x5b24e3bb, - 0x7568724f, 0x8f7fe794, 0x31be7a06, 0xf4505eb3, 0x7763f527, 0xfdc0ef85, - 0x86578e88, 0x4d1f21e5, 0x645e3a33, 0x1f7fbfc0, 0x3cfc44dd, 0x8791ca2d, - 0x7dfdac2f, 0x8f9e0af4, 0x3788bc73, 0x69acad83, 0x8ffc7146, 0xf1452f3f, - 0xa79a740d, 0x7fb43a0a, 0x765373d4, 0x063613d1, 0xfaeb54e0, 0xd7e7c0ca, - 0x7078c069, 0xc10718d4, 0x4661e06f, 0x273a98e7, 0xe076f847, 0xfa80df7e, - 0xb2878c6c, 0xd61e474c, 0xd277d24b, 0xef8ef27d, 0xa827fdf8, 0x50537919, - 0x8389fefc, 0xf8afab92, 0xdc31c9e3, 0x6a945d4e, 0xa8788759, 0x944c9bb3, - 0xe748bc1e, 0x9dce9982, 0xd96bf18a, 0xa97bf7d0, 0xfae18eaf, 0x41a57921, - 0x74410231, 0x30e594c2, 0x0cbde6a6, 0xbbf6d0f4, 0x8bdfbac3, 0x43327003, - 0xdef3c89a, 0xeb178f1d, 0xac65f534, 0xe31dfddf, 0xbda7acf4, 0x8fcddbfc, - 0xc6554f2f, 0xc7997a43, 0xd50c7fc8, 0x6d0b6b3b, 0x843f3bea, 0xcc63c7e7, - 0x523de9db, 0x14877949, 0x4e315aea, 0x3de8ce11, 0x37bfc1ae, 0x9e819afb, - 0x3d399a76, 0xdd3c8aa7, 0xeafaf229, 0xbbeaa53b, 0x7a14cf6b, 0xa3cc2b6e, - 0x8fd4fc7e, 0xdf1b37b4, 0x6d6788cb, 0x6efabe34, 0x012f5a94, 0x2b0920f4, - 0xe23a675d, 0xfb1250ab, 0x63e7e784, 0x1d20e68a, 0xb2f2685c, 0xcdf4824f, - 0xc6c8f085, 0x49d5fc60, 0x3f5af7da, 0xda81331f, 0x1b6beda9, 0x284fb227, - 0x3a27e978, 0x69154daa, 0x624ebd1f, 0x9c3be2af, 0xa80d5920, 0xa776d597, - 0x78e2de40, 0xc5fc82ef, 0xbb903df4, 0x3ed1e89f, 0xfbe94e9d, 0x3f2a1e4d, - 0x694d54dd, 0xca9ea9a0, 0xa46a6a3f, 0x23db96f4, 0x167f9172, 0x3ec65fed, - 0xdaf7a209, 0x1027bd36, 0xd4553f94, 0x51ad1d37, 0x7254e8e8, 0x1c9fdfdf, - 0x53bbedc3, 0x3b3e38e3, 0xf7c0dec0, 0x972e80da, 0xdbfd6d5b, 0xfdca1d1d, - 0xf9e3a3ae, 0x3c4765fe, 0xc31f2fcf, 0x64596efd, 0xe8fed8ad, 0x3fef0378, - 0xefc6ac45, 0x7bf78db2, 0x77a45d2a, 0xb1357ea4, 0x5831fee8, 0x73ca163f, - 0xaea7f27a, 0x41e5dfe2, 0xaf9d5cbc, 0x42b6fdfa, 0x61eefaab, 0x8fcf7f3a, - 0x7a02f7df, 0xfad5fea7, 0x3e702663, 0x4befad0c, 0x43c9e7e5, 0xc2a9f1e1, - 0x6817c4b7, 0x241f2367, 0x9d45f107, 0xa542f883, 0xd6fe9543, 0xa7387216, - 0x0f3a151a, 0x07eee7e7, 0x76842ea3, 0xb4cce383, 0xbbe3208f, 0x9d9eb0cb, - 0xa12fc282, 0x63bca0fc, 0xca83f2ac, 0x0fbd2a07, 0xefe33e06, 0x8c75f334, - 0x5f79fa95, 0x7b475958, 0x845dc46c, 0x2b7a83d7, 0x12b1adea, 0xb0792f7f, - 0xedcef5d8, 0x11b19fc8, 0x96918c0e, 0xf7d4b2ac, 0xfe3ec725, 0x9543c2af, - 0xa3c0fd0b, 0xca0c1c17, 0x123fc3bb, 0x50e7240e, 0xf6fd238e, 0x8c4eb721, - 0x177629b1, 0xc7cfdfa7, 0x1d226fc8, 0x1d660875, 0x30e87bde, 0xf05f7df7, - 0x0ebe78e8, 0x16d68e95, 0xe3074a32, 0x96f6873a, 0xba7aea7b, 0x230779d7, - 0xc61a97f9, 0xacf143cb, 0xfe482bae, 0xa979c19d, 0xec0c64f0, 0xa127e81f, - 0xe8ef42c6, 0xe0e856dd, 0xd3f036fc, 0x67ac0dca, 0x3e8a35fd, 0xf8944c7b, - 0x7e8ac87b, 0xa4172ee9, 0x1a996599, 0xcf4743bd, 0xefe15f3a, 0x5645fb8a, - 0xa372ef8d, 0x171c1d6f, 0xe5c8521f, 0x3cf4d743, 0x2f13f711, 0xf742d5fc, - 0xea0c2f8b, 0xcef68d3c, 0x533d5685, 0x2a9b23de, 0x8b9dde80, 0xf90c133e, - 0xf39ef2a5, 0x0ef7e8e7, 0x176d7a83, 0xb5bda34f, 0x4cc4ab68, 0xeb609e78, - 0x3d20b737, 0x4f457bcd, 0x5b9a99e7, 0x7a471e37, 0xc04fb73c, 0x85d96fe7, - 0x31c5027d, 0x7c225b6b, 0x0a5fa866, 0xc77fac79, 0xe3c7c96e, 0x39c5328b, - 0x3ef1946a, 0xa0a5d731, 0xeb713e5d, 0xfb843a5d, 0x8b02edbc, 0xb48f7e83, - 0xdf0c79de, 0x8db7391d, 0x366b2fdf, 0xf9c0ee47, 0x0ceb4a97, 0xc17ca083, - 0x635e5e76, 0xf70cfd29, 0xcd3c1743, 0x60b3fe28, 0x8ff9046f, 0x1ff45af3, - 0x8eec8205, 0xfcda6dea, 0x4066d67c, 0x53b0583a, 0x07b35e5b, 0x79f241f2, - 0x2f12a150, 0x29b2ce19, 0xe3c2d25e, 0xef7caa07, 0xb97b5f6d, 0xde506d1c, - 0x897f66ff, 0x5f0ff7a5, 0x23e926f9, 0x2997cf0b, 0xff9033f9, 0x178e1bea, - 0xca752e15, 0xb3c55fd8, 0x675836dc, 0x2b662bdd, 0x0775edfa, 0x79e246ce, - 0x016145b0, 0xbd99177a, 0xded1592c, 0xe4bf607b, 0x1ed6f845, 0xfb893f34, - 0x9e2f7598, 0xa13c6030, 0xb262df74, 0xef312657, 0xfd9bf44a, 0x89dac8a2, - 0x7de9da8e, 0xce77265f, 0x1c2e7ec3, 0x0ed15b30, 0x4ff97ba8, 0xfcc76ec7, - 0xa7dd028b, 0x201890bc, 0x55b7993a, 0x0c437ba2, 0x1efcb42d, 0xaf10913a, - 0x28b6e788, 0x0ee58f7a, 0x19e23bc4, 0x4648eef0, 0xd071e13a, 0xf44b4f79, - 0xd9b5b9bd, 0xf9cff580, 0xbc557e38, 0x094b4a97, 0xe71e0bcf, 0x75b89cf8, - 0xa430e6d7, 0x64f5a783, 0x76811f8f, 0x0d3b7883, 0xe15e181d, 0xc5d85ffd, - 0xd37791cf, 0x376301c1, 0x2f3ce01d, 0xa7c00747, 0x472ff7a4, 0x97e89d07, - 0xddffbf92, 0x0ed0c7b9, 0x87e7e08f, 0xd51b77d5, 0x2e071a77, 0xdf14753c, - 0xbfb34ae7, 0xa5777640, 0xc5da8bed, 0x9d09de8c, 0x4be78853, 0x02bdbf26, - 0xca7277d1, 0x2f14d9b3, 0x6d7607d5, 0x744378c1, 0x3ac7c538, 0xe1b6cb92, - 0xb6c598fb, 0xc2f6936f, 0xcefd163a, 0xeb11e748, 0x3fc67e15, 0xbea2073c, - 0xa7780c4b, 0x07b519f3, 0xc65cfc8d, 0xe1fbed3e, 0xce9cf11d, 0x959d0c4b, - 0x804fd18b, 0x411c70fe, 0xc2e9fee6, 0x451dfc83, 0xa85c9fd5, 0x47b8a7be, - 0x60836efb, 0x3dea9b7d, 0x70429850, 0xd6371a18, 0x73797681, 0x0d84f339, - 0xc17d21fd, 0x5c7ca9df, 0xb5fa8bf1, 0x1bd1fb27, 0xbcc91daa, 0x15daf721, - 0x014775b9, 0xbbd1e39f, 0x7be1d0df, 0xf93b1d8c, 0x3fcc3bef, 0x062af208, - 0x1af519f7, 0xd4a753b9, 0x0fe914ff, 0x5bde76e0, 0x052892ff, 0x8bf797cb, - 0xa79a9fb1, 0x48753f79, 0xf5571457, 0xfe830e6f, 0x33d36cbe, 0x4c0597e4, - 0x23fb3791, 0x4bd46e28, 0xbedcecbe, 0x50f7cd12, 0x76085aba, 0x94222e26, - 0x69f6eabe, 0xa85d3deb, 0x670e7bec, 0xfff9e0d7, 0x90e031af, 0xba5f23d7, - 0x8e67e9df, 0x6eefe428, 0xef68287d, 0x056b0fef, 0x77ea0f96, 0x63c4cfb8, - 0xeafe4aa4, 0xfe4d56dd, 0xa6bb369a, 0x1dfbb5fe, 0xfed9ef9a, 0x11f7cd0c, - 0x7c9a9dc7, 0xa6817b5e, 0x64f7c8fe, 0xc0547e4d, 0xe63fa9a5, 0xef935bbc, - 0xf4f584ca, 0xe9a8cf61, 0xa9a0bb24, 0xd661d93f, 0x465d7ff4, 0x65df26b4, - 0xd8a3e051, 0xfbfdaa99, 0xff6e42a7, 0x7c2aa686, 0x8ed4e17f, 0x37edfaa3, - 0x2bc76814, 0x5de3b593, 0x1df05e29, 0xff9e9d41, 0xf8a6027e, 0x34ba09fb, - 0x9809fbfe, 0xc04fdfc7, 0x013f7f14, 0xe4dd7fcb, 0xa6befca4, 0x04bfca02, - 0xf7e6097e, 0xe9829f83, 0x609fe0cb, 0x77e0e5f9, 0xb8f7194c, 0xca1bee32, - 0x4e153fb8, 0xbdfd296f, 0xef87f4a3, 0x3df4ea0d, 0x795d6bdf, 0xe3e025e2, - 0x7467db22, 0x086e595f, 0xa31c6294, 0xe18975f3, 0xf1e667f9, 0x418a6f1d, - 0xa18036fd, 0x9ddcc49d, 0x6e3ee26f, 0xad438bdd, 0x81efae78, 0x07787ffd, - 0x27d85fbf, 0xf0e6bc51, 0xd891b3fe, 0xc29797cf, 0xe90a30e9, 0x7cd7c845, - 0x0d7e502b, 0x6773c77c, 0xca4af793, 0xa46d67bb, 0x554cbeef, 0x2fba3ef3, - 0xd7b3deed, 0xb85a7880, 0x7f7d2f7b, 0xf35af81d, 0xcd76f77d, 0x87d62b77, - 0x47cea174, 0xf7cf8571, 0xa9f9fdab, 0x7f2a4d7e, 0xddf3fe3f, 0x418e5647, - 0x6ab7bc7d, 0x17b5c600, 0x3b1139ee, 0xf1f007fb, 0x66cf4bd5, 0x3da81ea2, - 0xd1e72920, 0x07b57f78, 0xcf9e4af4, 0x6f7526bf, 0x63379e29, 0xb3ba047b, - 0x4f5b25f4, 0xee16c4e7, 0x728355df, 0xedc66176, 0xb57f8a7a, 0x83bc4a49, - 0x6350d3bf, 0x6baedc65, 0xdf123afb, 0xdb7dffa9, 0x1ef1ebd1, 0x23c1c774, - 0xc74c5ef4, 0x4fe3493e, 0xf1cb1d8d, 0xf72c763b, 0x77dcbeff, 0x09cf1224, - 0x8476d03e, 0xa7e75dc3, 0xf2561ff5, 0xbc12901d, 0xfeb44bf7, 0xcd2497f9, - 0xc0b801ef, 0xcdfba171, 0x7022d3fb, 0xf8db275d, 0x7d40d378, 0xd56a7950, - 0x1bff9c1c, 0xe53cf2f6, 0xddfa327d, 0xaeab8ea1, 0x767285db, 0xe7d49b61, - 0xd839f779, 0x98efcc2f, 0xebe9d39e, 0x1b1c2fa9, 0xc37f7004, 0x749b2035, - 0x62af5284, 0xa59bd72c, 0xea2a4f06, 0x47169391, 0xfdf9d204, 0x8811a1ae, - 0x6298c3df, 0xba49ebb9, 0x1f60be07, 0xb5a4ef1f, 0xeee9123d, 0x5211bee4, - 0x2dcbfef0, 0xe9ba7aca, 0x5e6f1bbb, 0x6fb553c2, 0xe9fb05bb, 0x9f2f1fc1, - 0xf54ad636, 0xb89df0df, 0x93aced05, 0xc0ddfc19, 0xfe460663, 0xdc3dc2f5, - 0x70793e4e, 0xfbe0f6f0, 0x7c14d359, 0x7df06474, 0xf5fb0bf5, 0x77dbbd4a, - 0x3d3d4d31, 0xed4ed7c7, 0x33beac7c, 0x5e7da10f, 0x6744b8f3, 0xf5f46a1d, - 0x4ffeb8b1, 0x57e769b7, 0x46b9c0ad, 0x0d8d8fef, 0x039ad7a2, 0x21637cdd, - 0xf2a03f3a, 0xa9f08389, 0x8664f1e2, 0xe765e7c4, 0xecd5f8ef, 0xdd7445dd, - 0xe3c4be3b, 0x31ef83b7, 0x74be2939, 0xb55a7f19, 0x2dfc821b, 0xbd23bdfa, - 0x989e686b, 0x9c1f63d2, 0x1a1f942e, 0x987e879b, 0x93ccfc9b, 0x185bec0c, - 0xebed16b3, 0x891dfa28, 0xd76e38cd, 0xffbd3d3e, 0xb03a6b5f, 0xef23df00, - 0xc0a30272, 0xe9b6bbbc, 0x4667dfbb, 0x629e773b, 0xf0ea7ee7, 0x7fa04be4, - 0xb489976b, 0x923d9abe, 0x5c17cf0f, 0x57dee450, 0x406f937b, 0x2e39ad7a, - 0x9a3fd159, 0x70fc96d8, 0x77e92e61, 0xdaeb57b2, 0xb75c9db8, 0x58bb205b, - 0x156a43b5, 0x629ce43b, 0xd65b9f07, 0x57e3edc9, 0xea11b604, 0x7b030dad, - 0x9b5de604, 0xdaec8539, 0xcadd695a, 0x473c0ec1, 0xe61bb5a5, 0xe7443c1f, - 0xd1cec0ae, 0xaddc2f94, 0x69b6d7cd, 0xf8bfaaf3, 0x3b6ed8d2, 0x37fa3863, - 0x1c615225, 0x0a9bc3f2, 0xe77f555e, 0xf49c6bce, 0xe80f27fb, 0xb8d4531c, - 0xd16bc204, 0xc7cc2f2b, 0xc26afb79, 0x347fe49c, 0xdae096fe, 0xd7ee17f1, - 0x1bdee074, 0xf0e333f2, 0xe9cfd8ed, 0xf05e917c, 0x2cbaefe1, 0xfd815d42, - 0x32df0499, 0xbb7b3b8c, 0x293e4922, 0xca1a08e7, 0x632affb9, 0xb2a6180c, - 0xe7f72c7e, 0x38eaf543, 0x0e8a405d, 0xb1811392, 0xd8af5429, 0xde57cfc0, - 0xfd24e119, 0xedc4c436, 0x6e2621f5, 0x75d10faf, 0x85dfa32e, 0x7df02418, - 0x6997ac8e, 0x9d6d60ff, 0x0417f685, 0xe10e957b, 0x955076b1, 0x887de90e, - 0xfd032db5, 0x8c5f353a, 0xec7b33df, 0x478b5283, 0x8cece387, 0x047d9417, - 0x74cb4fae, 0x90747d56, 0x996c657e, 0x3dea7e66, 0x7e7d9fcc, 0xa59f9856, - 0xef807e67, 0x75ff6c28, 0x86ec93ae, 0xf7f532a4, 0x2e49ea1a, 0x12fcf0a8, - 0x7018bde8, 0x816c7745, 0x1db66a6e, 0x96b2ff22, 0x76c4afb5, 0x1d7c91a5, - 0xbefe06a5, 0x4f186951, 0xfcb8e375, 0xa5d2512a, 0xc3f6b4e3, 0x7eb27191, - 0xc63ba41c, 0xf2e34db9, 0x79953f68, 0x6f0d7d61, 0x43d677f3, 0x13943ee5, - 0x7c0d7d3d, 0x466ff288, 0xd54d60bd, 0xbf9c69d8, 0x6ea2f116, 0xf6f85a3e, - 0xea27c493, 0xc66acc39, 0xa3667bf9, 0xc41a9ad9, 0xdf908b17, 0xc377ded0, - 0x138c7cbf, 0xeb6abff0, 0xe9973a7c, 0xa2b58c69, 0xfa48b75f, 0x7e25f692, - 0xda2ddf2c, 0xcdfbcdaf, 0x11fdfe9c, 0x1949f902, 0x0de3bae3, 0x0a498fc4, - 0x08f76c7f, 0xfb600e74, 0xcf1e3a77, 0x7e2810ab, 0x36143377, 0x624994da, - 0xba22eabd, 0xe333724f, 0x4b596347, 0x3dbbf28c, 0x796fb431, 0x9beeb293, - 0x2843fe75, 0xdbea8e57, 0x749e3192, 0xc4e4d6b4, 0x1b59cbfe, 0xc15a6fbd, - 0x153d29da, 0x9fa2f75e, 0x2226f73a, 0x63c9fddd, 0xf6d678a4, 0x50223be5, - 0xe5b167be, 0x044fdc56, 0xb7c6ec50, 0x73b3fb01, 0xd51df742, 0x2f60c4fb, - 0x027d21c7, 0x1d2127fe, 0xd8dc079c, 0x5fb77a73, 0x2317c7f8, 0x2c5f7f11, - 0x5b96e179, 0x9d5ffa19, 0xa82d47e4, 0x5df7465f, 0x33da9c81, 0xaaf07bf2, - 0x5bc55de2, 0xf01d5e37, 0xb0af182f, 0x938404a6, 0xc91965f4, 0xe8917fa5, - 0xf0e5d69c, 0xbc7dc2aa, 0x0e3b9f82, 0x8a15f970, 0xb70f156f, 0x43f5bbe2, - 0x236eef49, 0xc923313c, 0xb87a50cb, 0x3080be1c, 0xc4d93ce9, 0xa1f92318, - 0x4f2e4583, 0x2813cf07, 0xf33b795e, 0xf48012bc, 0xf5f7f096, 0xc70adefc, - 0xb782855b, 0x2fdf313f, 0x71ff9232, 0xce323b78, 0x606e34dd, 0xe50dbe6f, - 0xb2f8fed3, 0x37fce1c6, 0x18fa5f55, 0x3f0863f2, 0x376bf087, 0x2ff09d1e, - 0xc69e8f08, 0x6ecbe248, 0xae7b4b7c, 0x7fe22f4c, 0x5fb58e30, 0xaf93f9f0, - 0x46055f80, 0xf8f8bfbf, 0x54dead38, 0xa5c2a6f1, 0x07e0b8bf, 0x2ad47fcc, - 0xe70abed0, 0x748dbbe3, 0x57dd43ff, 0x5e4ff751, 0x5cf5c719, 0xd801fa68, - 0xb55fb84b, 0x40e4e326, 0x194f33b4, 0xfef87ed4, 0xdacb07ef, 0xb6f7f113, - 0xe9e2283e, 0xddff0329, 0x872f350f, 0x07e4b8f1, 0xc22f46f1, 0xf86103e9, - 0x1f33d404, 0xcf5cf708, 0x070671f3, 0x26e3cbe6, 0x53903de0, 0x798e357a, - 0xf07f12bf, 0x8f9479f1, 0x027aa62c, 0x074a5dff, 0xf61ddefe, 0x1736082b, - 0xbb83e7cc, 0x9d7de8d2, 0x718d7dee, 0x467f0edc, 0xdc774759, 0xe2815eff, - 0x355133fe, 0x84c4fee1, 0x877c2e2d, 0x437df4f3, 0xb4df69b3, 0xea3e3b41, - 0x978a64fd, 0xfee7e06e, 0xabea752e, 0xb75bf482, 0xc8be2dbe, 0xd1e4e7cb, - 0xbfa88cef, 0x86db2747, 0xc7dcff73, 0xd550df7f, 0x5fc75d67, 0x73c704b0, - 0xdfe2533f, 0x0fe1f9dd, 0xc3eb0526, 0x4dad4f43, 0x0daa7ec7, 0x05a72cde, - 0xb1ee877f, 0xaa5bb424, 0x4e955a9f, 0x0f53f4f6, 0x545fa3a4, 0xba6d63bd, - 0x0f70f94c, 0xbe3a65f9, 0x1b9e2fee, 0xd4f3e745, 0xdccaf6fe, 0x1d30a8af, - 0x3dbd412a, 0x56afeae5, 0xda41fee0, 0xffc5027d, 0x15f6b066, 0x332b67a8, - 0x16b15f38, 0xe87fc913, 0x776bf68f, 0x4ec5ff0d, 0x646f0794, 0x81cfd59c, - 0x203e127a, 0xd5df1035, 0xdfa3adf2, 0x7fcd5c09, 0x7ea7b027, 0x56ffed22, - 0x9de8172d, 0xfcf519ab, 0xf1a4f377, 0x59c704d1, 0xd18fb3ab, 0x794b57fb, - 0x6fa314f9, 0x67ec49df, 0x3fdf818b, 0xe094ee64, 0xb29270fb, 0x9d73385f, - 0xca717bf2, 0x639b6938, 0x53af07b7, 0x591df652, 0xdf2477ea, 0x32f0506e, - 0x5789e975, 0x54efd0ed, 0x1e3cc7bd, 0xe9b3bfbe, 0x619faa5c, 0x3a33f41c, - 0xf066985f, 0xd71f3a3c, 0x7148c3bd, 0xc1acdcd2, 0xcfd41c52, 0x11b45259, - 0xab4b99d3, 0x728f9d1e, 0xcd94d5b8, 0xf9f2358f, 0x114e0835, 0xed91f4e5, - 0xb842ceb7, 0x7fc4df9d, 0xfb61abff, 0xc2ddfa30, 0xafdee4fe, 0xf9eff89a, - 0xa264dd3d, 0x2b26d9f4, 0xcfeba3c3, 0xff29d935, 0x4a0e4daf, 0xcd3cf4d9, - 0xd7f4d8ef, 0xe14b88df, 0xb973bbf4, 0x3bf4cdab, 0x39460d88, 0x2bc03c75, - 0x1ddaaaed, 0xc2eb280f, 0xbdb2b8f7, 0x0e1113c9, 0x3e2c0fb9, 0x75b3a686, - 0x7d97df3c, 0x24eae4f3, 0x2c77d614, 0x7cc4f33d, 0x78fb7ef8, 0x270835f7, - 0x148bb6d3, 0x607238a7, 0xbbc22555, 0xaf91877a, 0xf9f7594f, 0x8f71e94d, - 0x75f97c62, 0x160dc53d, 0xc4f33b6d, 0x877f0c03, 0x9821b177, 0xbd74afde, - 0x7ee78f57, 0xaaf8e5e6, 0x78fc383f, 0x449b5abe, 0xf803b3fc, 0xf3a7f32a, - 0xcba5a2d5, 0xc6cb7e08, 0xb8426fbb, 0x937bd79d, 0x0fce9f90, 0xee744b1f, - 0xf820457d, 0xdbbc72ab, 0xbfe056af, 0x575b6c50, 0xc723dc98, 0x04b961bf, - 0x3e0743df, 0xf9fb474d, 0x3fe5fd9b, 0x6097eeb8, 0x1861fedd, 0x1a5133af, - 0xe0df3dfa, 0xf584ea19, 0x3ef3f7e5, 0x6af1d2e8, 0x539f9ffc, 0x36213fc0, - 0xe6219df8, 0xd4f9828d, 0x61fc141c, 0x26cfa859, 0xbf43a67d, 0x8fcffc11, - 0x198ce734, 0x9f4828fb, 0xcbdf37f7, 0x4fd875a5, 0x1ddc8f5a, 0xfcc89ef9, - 0x547b7a41, 0x83f98c20, 0x73f6edc6, 0xfb40cca0, 0x1724f14e, 0x2e786f10, - 0xe181c2ec, 0x99ff303b, 0xc2f1e381, 0xf14f604b, 0xf2931078, 0xd9f9d67b, - 0x50b22f81, 0xb7ae86ce, 0x882fe5ee, 0xaff66a3e, 0xfad028ba, 0xcba67f27, - 0x0ffafcba, 0x1645f53d, 0x7d33efe2, 0xb6fd1f20, 0x1640860b, 0xb7eea1e2, - 0x58ff9e5c, 0xf3e5a838, 0xf7e81b57, 0x1304eb3a, 0xf48949d1, 0x2e1fc525, - 0x87f1e71c, 0x924f03ba, 0xc83aed3c, 0xc48b40e3, 0x8c38d2f6, 0x399fd49b, - 0xcbacf286, 0xe831fdce, 0x2b71de9f, 0x41e8aa1c, 0xde12675d, 0x4dd83bf7, - 0x3c8fdc0f, 0x0c3bfc8f, 0xf3a369fb, 0x9c2b2cbd, 0x39f15da1, 0x7c30f3f2, - 0x257930bf, 0xdf79f9d2, 0x8f941cc0, 0xadfd666f, 0xbf86e28e, 0xb27ba70f, - 0xe6926db5, 0x3af7799c, 0x703f127c, 0x29fb54c4, 0xe7c1c99c, 0x1b8e0cb9, - 0x837e6ec8, 0xba2e13ef, 0x7b13f38a, 0xed53f399, 0x7b0643f2, 0x15bb7f50, - 0xc8ed527e, 0x1bffbf29, 0x85b3e5f1, 0xd504fd32, 0xffc7a54f, 0x4cf7fe9f, - 0x33412fff, 0x800063ec, 0x00008000, 0x00088b1f, 0x00000000, 0x5aa5ff00, - 0x5554700d, 0xbdef3e96, 0xdd2749fe, 0x12421349, 0x42068408, 0x03621a88, - 0xc4d67281, 0x206efce9, 0x6b01bb33, 0x8d08c42d, 0x749d2422, 0x6aece882, - 0x021a6eb9, 0x367564ac, 0x1d47598c, 0x809f9b47, 0x9476ec28, 0x0da0c040, - 0x6ba2cb0a, 0x3a26aa45, 0xab545b55, 0xa6e00eac, 0xd63b8223, 0x3be7b8e2, - 0x1dddb5ef, 0xa6ed4fe2, 0xee7dba8a, 0x9ee7b9cf, 0xce77ce7b, 0x52b48f3d, - 0x6a22ca22, 0x2a08cdcf, 0x6ea6ff0a, 0x6d4445a2, 0xf67f2429, 0xaf1f4541, - 0x7dbc64d3, 0x58c9a340, 0xce08eb93, 0x4754419e, 0x459a26dd, 0x654284b4, - 0x29bf71a4, 0x795bcbf2, 0x6d0dfebc, 0x61931741, 0xb06aad1b, 0x7aa6d513, - 0x1314360b, 0xaacaab0d, 0x0bcc6286, 0x4b9d2e95, 0x7efe0df4, 0x879b744a, - 0x2a224f99, 0xf60f14d3, 0x169c9d1b, 0x8b5dc9dc, 0x491bfb97, 0xeaa7984d, - 0x534f98f3, 0xa3827c08, 0xd81d4b25, 0x9964b468, 0x8eef3e23, 0x07d6d237, - 0xd2a14e31, 0xf9f6123b, 0x68858f4b, 0xcb17d121, 0x650faa17, 0xdaae79f2, - 0x51337403, 0x29ed768d, 0x70ddf785, 0x05564ccc, 0xafbc67fc, 0x670239f2, - 0xfa65ea34, 0x790a4752, 0x4bceccac, 0x1bcf0f1e, 0xd8293b99, 0x3f6fe7c5, - 0xe78990a0, 0xeeb11db5, 0x6d79e14c, 0x9bb648e6, 0xf036ddf7, 0xdb878b3b, - 0x2cf7fef6, 0xcf58b9ae, 0x9e433647, 0x6dfa1514, 0x174ff277, 0xce607f91, - 0x3f3177fb, 0xf44d69ff, 0x67bd37ed, 0x05d7d621, 0x5afd8f9e, 0x82d5f60e, - 0x56f0a56e, 0x3cfdda27, 0x9bbf48af, 0xe5dff86f, 0xb386575c, 0xf8be7e38, - 0xa7a25d39, 0x69f8bd18, 0xd602f73e, 0x43eb468b, 0x21ee5976, 0x6e717b96, - 0x252e8ece, 0x5fae9d71, 0x4b69768f, 0x9d15cb0e, 0x6615b8a9, 0x6c0d4d15, - 0x851f4276, 0x1797b38a, 0xb97f5f47, 0x9bf42d74, 0x9dbd2c12, 0x90b517cf, - 0xc7e2c7dc, 0x04b49bb6, 0x6a0f1679, 0x3443dc1e, 0xc90e9a95, 0xe2a77bbd, - 0x61bca83e, 0xd61267a9, 0x2b7bbe8d, 0x7955196f, 0x73fafdbd, 0x7975ca04, - 0xc9a9b0ce, 0xd7721b7d, 0x80ede5e7, 0xc400d9fe, 0xfaa94e8e, 0xc7951efe, - 0xbfd7c7e7, 0x46a79c68, 0xf089ce2b, 0x9dc506f8, 0x9f671ce3, 0xf587bb58, - 0xe9ef86be, 0xb46fbe45, 0x6938752f, 0xfda26ccd, 0xff42b91d, 0xda4b8773, - 0xf4914750, 0x16e1d2bf, 0x2dc760fa, 0xf0ea1f42, 0x51d03d08, 0x8ed1ed27, - 0x033fe906, 0x708cff51, 0xe2ec20a0, 0x4a6d7c14, 0x1cce1e9c, 0x9e494f43, - 0x24a99c3f, 0x991453d3, 0x3cb870ff, 0xa5fa6018, 0x939ca732, 0xc0d1ca8d, - 0x4b4e68fa, 0xb40ca12f, 0x674a41f9, 0x037bb1bb, 0x3ffbb61e, 0x43daedd4, - 0x4bcfc533, 0xf33aaf30, 0xdbf846ce, 0x692b2ce5, 0x1ec3cfac, 0xde63dfef, - 0x0555d3e9, 0x683fd1db, 0xfef95b73, 0x94dc5787, 0xff47bd01, 0xb78d234d, - 0xb05a28ae, 0x0ae994b9, 0xcc7622bb, 0xc86e6efc, 0x4fc6bb66, 0xb83553e6, - 0xe3a4d4ba, 0x02b67384, 0xc1aeb7fd, 0xdb261b3e, 0xfc795816, 0x57f7b94a, - 0xf7a627d8, 0x0aeb29da, 0xd98bd0bc, 0xf3cabef5, 0xa66eff02, 0x80f79e5e, - 0xdf649dc3, 0x822bcb47, 0x45c59bb0, 0x07cf36b3, 0xd9ba767f, 0xf5bb3fbc, - 0x51e7c87e, 0xc14e94d3, 0xb8099731, 0xf3fdc410, 0x452e953e, 0x716c30ec, - 0x7f993299, 0x2b22b538, 0x194eebc0, 0xb8da7df7, 0x7dc633ef, 0xd5fdc3bf, - 0xfdcbbedc, 0x1fb88768, 0x9e988aed, 0xd085a34d, 0x0da7f05f, 0xef44792f, - 0xa3a0f9a3, 0x3b0e5a66, 0xd33f025c, 0x81bf27f1, 0x5ca278e5, 0x036ee397, - 0x6b6e867f, 0x85d7d3e8, 0x858b4f84, 0x4bffb0bc, 0x9f609f58, 0xf5f175b1, - 0x9bb2ed24, 0xe7c29029, 0x20b6c3a0, 0x895344f4, 0x0ecb5f80, 0x692e08e7, - 0xcf8ab329, 0x017a644f, 0xabd29e09, 0xae5e7d56, 0x85fc216b, 0x8cfb2475, - 0x9980d504, 0x399fc4ed, 0xf2c99854, 0x167e188e, 0x49fd0fa3, 0xcff6fc13, - 0xd7db9a67, 0xfe7cfd14, 0x13854365, 0xa9b15eb0, 0x4eff33b0, 0xe1acfc7d, - 0x0699fe87, 0x943ce33f, 0x7dc7ca12, 0xce1d8f44, 0x2ee987bf, 0x1ead787b, - 0x8285c207, 0x5c2e14df, 0x42549c06, 0xd44dc8e7, 0xaf7dfc77, 0x47d027e9, - 0xfdd079e8, 0xd3af7fc7, 0x6739df4a, 0x50a4f8e2, 0xfd04e2be, 0x3df74181, - 0x409dc13f, 0x87395f9b, 0xdfa6cb71, 0x3327ab7b, 0xa783586e, 0xff37603b, - 0xed97dba2, 0xd027ff40, 0x2b11cb5b, 0x0f2b2ec1, 0x0af67ff4, 0x3bf4b78f, - 0xa8fb80dc, 0xbbe88667, 0xc7dec8f3, 0x7d236f61, 0xae87f166, 0xfe7bbffd, - 0x25679911, 0x35bd5b98, 0xcfbc4a54, 0xe37fe3d1, 0xb49f6135, 0x6fd015d0, - 0x39179c57, 0xfeea27ea, 0xa9f1543d, 0xf5bd0037, 0xc46bf81f, 0x0a0cfab5, - 0x65e96ec0, 0xe46647be, 0x6a86f57b, 0xc771e12a, 0x6ff04ad0, 0x86eac97b, - 0xcd5efa9d, 0x5f1f84a9, 0xfb14ccf3, 0x3bb1be6b, 0x3d57711f, 0x23cf6fba, - 0x23679859, 0xc99edbc8, 0xf57ac476, 0xdd163b69, 0x6bb7f72f, 0xf7206fcf, - 0x64ed1b3e, 0x03cccd3e, 0x99ef35fb, 0xd1f00c1d, 0xe3fafb5e, 0x1a87b895, - 0xe83db9ed, 0xa6dbb2bf, 0x2d670f42, 0xf8728c9e, 0xbbb359e1, 0xba0ceb17, - 0x2ea27879, 0x56a45a4f, 0x3bab2fee, 0x37d7711f, 0x80bfe1f1, 0xf75af5dc, - 0x3ce2cff3, 0x3884ad7b, 0xeb1f6171, 0xe85dd78d, 0x2dc7cf35, 0x9873ec8f, - 0x94972f60, 0x82cf95ee, 0xef3eaf7f, 0xf45bad92, 0x439de819, 0x11e78fd8, - 0x6525f2e2, 0x85ff527b, 0x5e25bdde, 0x97c5dfd6, 0x09bd8bea, 0x17f31bf6, - 0x526b6edf, 0x6024147c, 0xbf19f25c, 0x3b2019c9, 0x8366dfc7, 0x99e878bc, - 0xbe296791, 0x737ee2fe, 0x6a3ac2d8, 0x94e6d2b6, 0xf83fb8cc, 0x0ebcfef2, - 0x3ba9f3e7, 0x34c7910a, 0x84ac882f, 0x51b05c5f, 0x7bcf2e4a, 0xbe5f88db, - 0x2a971b83, 0x4f2ddf25, 0xc7ee854d, 0x38f57357, 0x16c07576, 0x1ddf280c, - 0x83a3fe8f, 0x8eccef9c, 0x67af77d3, 0x7e71297e, 0xad425b6f, 0x2db7de6e, - 0x738fc753, 0xe33f7f3c, 0xcfb19558, 0xe79287aa, 0x299152df, 0x8966d3f6, - 0xc60e2214, 0x88ac2ff8, 0x10a45ae1, 0x5d763578, 0xe013d23d, 0xe08acbc8, - 0xf2a0ef88, 0xa86e96a1, 0x4fae3b34, 0xa8204a5f, 0x0f7f8c95, 0x7b8c8bb9, - 0x55ef5e60, 0xdbe57ee8, 0x98d8f36f, 0x246a4b4f, 0xab53791d, 0x7c8e9223, - 0x46a8e468, 0xcbeb8d3b, 0x199ff18a, 0x4649afdf, 0xf6643fb8, 0x8fdbc6d8, - 0x6f3c438f, 0x2ab37e1d, 0xfdd0a93e, 0x4d2069a6, 0x646723f6, 0xe9b6ec11, - 0x3875e4b9, 0x1fc133a7, 0x65760647, 0x8fe2137b, 0xaa3b90cf, 0x137e287c, - 0x7ca3fafd, 0xa54f81d8, 0xf6ab0acd, 0x65b1af22, 0x3a294d0a, 0xe5b1b01d, - 0xa7b4befb, 0x5e2e7ec2, 0x1e3f156d, 0x73822251, 0x0aae27b9, 0x23988c3e, - 0xca8e7382, 0x18fc11ff, 0x09591099, 0xb4adcadc, 0xc9f196af, 0x1e2e9591, - 0xa0c2b2ff, 0x03e491a7, 0x57322785, 0xb5ea4f03, 0x3711b7d1, 0x09d99769, - 0x7be9893f, 0xa227a19d, 0x783b86c7, 0xb3410ffc, 0x4e61f10b, 0x0be462a5, - 0xb5f9f896, 0x908d3fb8, 0xf841c0eb, 0xdddd9367, 0xfdc1a32b, 0xbc1f20af, - 0xe5dddb33, 0x326f5eba, 0xcacae587, 0xee2d6afc, 0xfbdd3b29, 0xdfcc158f, - 0x07c91c5f, 0x4bb5b1ce, 0xdd7b6a1c, 0x47fb13ba, 0x807ba3cd, 0xde1c175f, - 0x9f582b27, 0xada196ad, 0x67d22ca5, 0xa429c8e6, 0x6f604bf8, 0xbdba2382, - 0xb2ef148d, 0x561e9f08, 0x9767eb2a, 0x4b940f71, 0xa1f603b4, 0xe6fcf7e8, - 0x00efabc0, 0x6686466f, 0xf58f4e09, 0x4f030ba7, 0x3e3703a6, 0x981ef8e0, - 0x60ffef13, 0xfa0b5ef5, 0xc3b8bf97, 0x9ef6e112, 0xbbe7c9cd, 0x0cf6ed7c, - 0x9e3d0bf8, 0xec7b0fd0, 0xeac7a649, 0x4e197605, 0xe88083f2, 0x29c79cfd, - 0x0e54b7f2, 0xdf0f41b5, 0xd698cbd2, 0x6313e812, 0xa9f331e8, 0xce1fcf41, - 0xb6f84879, 0x430f0b4e, 0xcc07236f, 0xe4ef7c04, 0x7f7426b8, 0x1aef105a, - 0xadc700f5, 0x216e3d2c, 0x0fa4b45e, 0x8cbdc4ad, 0x989d5bf4, 0xa7c8e9bf, - 0xdb3f38f9, 0xdbce3e63, 0x3670e472, 0xf78dcec1, 0x6cc7c704, 0x1ff4b78c, - 0x24bbc6c9, 0x86aadfd6, 0x4717210a, 0x47e012b8, 0x85afdfac, 0x8b7f210b, - 0xf1825432, 0xf996e428, 0x49a06b4c, 0xe8aad1ce, 0x34474f7e, 0xf7b1f9c1, - 0x6e8551f6, 0x250f8caf, 0x1d3707c8, 0xb11254bd, 0xd9a0f1c7, 0xe81395c0, - 0xdffdd62f, 0x09c0c8b9, 0xbf0cda5e, 0xbc27071f, 0xf5a3dc31, 0xae7dc816, - 0xb63b9742, 0x3bcaf85e, 0x6de32023, 0x992a5daf, 0xc6758c59, 0xa3c04a3c, - 0x017c7159, 0x0e0ae40e, 0xf367326c, 0x2bcf7cb9, 0xd25e4eee, 0x96b1b8dc, - 0xd33ad3a7, 0x6bd0b5fd, 0x5de40513, 0xb1ae5637, 0x8570f476, 0x553ebf7e, - 0xf6fb8f7f, 0x964ec128, 0x7d6322eb, 0x9bc17cee, 0x5d67f030, 0xf85ac6f5, - 0x7e597ddf, 0xf9bbe24b, 0xedaff887, 0xadd7a649, 0x339b58df, 0x1efb9f8e, - 0x126a7eda, 0xd9afcf5d, 0xdb36a3bb, 0x4c7f7d75, 0x98b68bee, 0x49e6959c, - 0xbe58fa89, 0xb71276b1, 0xaffe52eb, 0x7dcfd0fa, 0x8c3588f1, 0xb5facbb8, - 0xfdb7fce0, 0x0925bd71, 0x5f807fb7, 0x9d6b0533, 0xfe5bbe33, 0x12ab6db1, - 0x4f80561e, 0xe2bd5fec, 0x0937ec67, 0x18aa6dfb, 0x5a68a753, 0x37791d3d, - 0x4f4f5779, 0x6d8c53ac, 0xa8a72819, 0x49bd88b7, 0xd2b87ecb, 0x623e8e3d, - 0xd4ae6ff3, 0x864d9f64, 0x6fa94f1d, 0x1e15e679, 0x53ccb97f, 0x557ec956, - 0xbf92a9ae, 0xa6a7dd8f, 0x860fcf52, 0x80bf1db2, 0xcd07453d, 0xb949f84e, - 0x4f33eba6, 0xfc2efcbd, 0xe1db2f31, 0x357e64ea, 0xbcfa6955, 0xea273663, - 0x5f63d140, 0xffe07be5, 0xa5cbec5b, 0xd3b262ce, 0x953f1e64, 0x3df0573b, - 0xc6c7cfb6, 0x7aa5693e, 0x645ed3be, 0x533afefe, 0x3adbe3b1, 0xc51be493, - 0x12d9c169, 0xf890bf87, 0xe85c1d16, 0xf7c05cd4, 0xd6fe1da0, 0x677ff5fe, - 0x0c8f0e23, 0x0bba67fe, 0xd3ed75b8, 0xb6cfd874, 0x81d38f81, 0x6606270f, - 0x1d9ed039, 0x1fd03972, 0x16b8fbad, 0x368cbaf3, 0x8b30675e, 0xf636b19c, - 0x13d58e7e, 0xcdd1de12, 0x73af6bd0, 0x614b2fdb, 0x82dda9ef, 0xce8efc63, - 0xd788fc44, 0xe3395c19, 0xeb1265d5, 0xf5b3050c, 0xd45a033a, 0x7acc0a19, - 0xea34019d, 0x6751680c, 0x0cea3f40, 0x006751a0, 0x68033a8d, 0xa2d019d4, - 0x2bfe80ce, 0xbcb16ba8, 0x50de4e51, 0xecd1aadf, 0xf40fff82, 0xf5e4416a, - 0x74d31c0f, 0xc412877a, 0xfbc67f7d, 0xaf460e23, 0x28b075e8, 0xe77953c7, - 0xfbcb341f, 0x5eda1a20, 0xd6f71337, 0x5571b9af, 0xd9371117, 0xa3cddb14, - 0x6a1f5127, 0x1bdc53ef, 0x2e5fe85d, 0x5c1b6c72, 0xfa237ef8, 0xd56ecd7b, - 0x9abafb85, 0x6f97fa8d, 0x58ea57b0, 0x2cc739d5, 0x15fbcf72, 0xeffde1ca, - 0x64efeab0, 0x2cbdc6bf, 0x9545b0f7, 0x1d6fda3c, 0xcb4bf792, 0x4d738a8b, - 0x7eda1e42, 0x1382e7cb, 0x9df4b69d, 0xb21fd790, 0xc524d739, 0x7de48f57, - 0xc174fc7e, 0x45433c8d, 0xa7d5af4c, 0x7b5edf90, 0xf9213801, 0xb47e4248, - 0x33fcd9d6, 0x5da467e4, 0x7efce133, 0x644ee87e, 0x6d3dd6f9, 0xb09228fe, - 0x9930737f, 0x6df60df6, 0x99c823cd, 0x034a8fdc, 0x943fb2e2, 0x74aa1fdc, - 0xc6927d64, 0x3cd1e63f, 0xff755be4, 0x3f40e6b4, 0xdbb977ef, 0x61caf92a, - 0x2570f78f, 0xb349f1fb, 0x272fea47, 0xbde4d98f, 0x9cfb7e75, 0x8d4bfaa4, - 0x1fea5536, 0xc48acc1b, 0xdee52bf1, 0xaacbb063, 0xeea57bba, 0x10eb9552, - 0xe1d98e7f, 0x3786f2d1, 0x5cc377c0, 0x6abfd497, 0xe10bf4ac, 0xf72f7ec7, - 0x7f16683c, 0x8254e9ab, 0xc9abd32a, 0xad7f816d, 0x3d8a7562, 0x298fed99, - 0x78ab0fec, 0xbb04c6af, 0x915db0da, 0x100a42bc, 0x8695e7ac, 0xfe0d573e, - 0xfb0a57eb, 0x3d56bdcb, 0x5553ce0f, 0xc5d79fe1, 0xdfe78b71, 0xfc0b5e47, - 0x55c71d66, 0x5f671cb4, 0x37bf708f, 0x9ebe6a6d, 0xc072bbe7, 0x3319f57f, - 0x726a4f01, 0x95e85e7e, 0xfced5f78, 0x095bef84, 0x737da5df, 0xa8e1f7d3, - 0xc8493e89, 0x759a4f6b, 0xca7d61fc, 0xec14eb7b, 0x5e3eea55, 0x3474cf69, - 0x8ca2bb49, 0x340bffc4, 0xe02f6f3d, 0x4a6672bb, 0xeb0fa2dd, 0x6eedda6b, - 0x0b863fe8, 0xbefc8dbb, 0xe796e540, 0x5bd54eed, 0xdc29d30b, 0xca5b8d3f, - 0xe7617e14, 0x5c71d47c, 0x3d4f3fc2, 0x7d05c0bb, 0x4377697c, 0xc739351f, - 0x31dde1e6, 0x72ffe0cb, 0xdc55c359, 0x029d2797, 0x438f9fd8, 0x5adfacdd, - 0x5d41481c, 0x50d1e43d, 0x38a63f27, 0x1ebfaef1, 0x716fb74f, 0x140acfc2, - 0xb5b7ea27, 0xd935dda9, 0xe676bfcc, 0x9cf0370c, 0x61ea55f1, 0x76eadc23, - 0x53506b70, 0x6ca6b5f4, 0xff0df3d4, 0x54a6f729, 0xd7f78a4d, 0x1d147e1b, - 0xf11d22fc, 0x6dd447f5, 0x807f8377, 0x835eee6c, 0xfea0ec3f, 0xbf5269a6, - 0xe5d1d98d, 0x613b39fd, 0xf4ab5347, 0xef8d8d75, 0x0c4f9199, 0xc1cde6dd, - 0x7cd72bfe, 0xce5b25be, 0x8cbd7e39, 0xb8033771, 0x165eb63b, 0x463df1c3, - 0x6b781dfd, 0x26baea32, 0x326baea3, 0xa326baea, 0xea326bae, 0xaea326ba, - 0xbaea326b, 0x6baea326, 0x26baea32, 0x97ae13a9, 0x878eddf6, 0x08ea1da4, - 0xbc4278c8, 0xc7eab9b8, 0x55175dd5, 0xa577538d, 0xc4865714, 0xbd7bf65d, - 0xcea63dde, 0x26aefeca, 0xe0d57bf8, 0x431e7b84, 0x7163d25e, 0x6b5438b3, - 0x603c16f1, 0x54f07c17, 0x8d6f5b8d, 0xf52ecfe9, 0x9b64cbd9, 0x2ca87b8f, - 0x5152659a, 0x23ee34c7, 0xdf84ef56, 0x1bf09ce0, 0xd31bf0b4, 0xfcdfb8ec, - 0x5daec2d6, 0x0109e7aa, 0x726c13c9, 0x32375bbf, 0x2f7d30ae, 0xe5709339, - 0xc2b831b3, 0x90159a0f, 0x95a0ed63, 0x233f74ba, 0x37254ff8, 0x0e3f9c7f, - 0x9c7484ce, 0xda1a9699, 0xb5a67d87, 0x1791baa5, 0x9d8bbfb3, 0x88a6dc9d, - 0x06a1afbf, 0xbc1c77d9, 0x7c9e4749, 0x73d1c4ef, 0xf7f9e1bf, 0xf25d83fe, - 0xd793ad9d, 0xe0fffa2e, 0xae954d4d, 0x84775f8f, 0x9659e77d, 0x43b654ea, - 0x16d5578e, 0xb8ba922a, 0x50fe2a9a, 0x58ae3da3, 0xd377a380, 0xb577dc3c, - 0xc839e1b5, 0x2efec399, 0xa32cdfef, 0x6a1a6bbe, 0xd9f4cbde, 0xbe373cec, - 0x3dcd4dab, 0x800b0544, 0xb0c57547, 0xadd4b3ab, 0x1963dd60, 0xbf83bfde, - 0xa7cc5edc, 0x96fee356, 0xb3b69753, 0xce63ee4b, 0x32fbdc42, 0xf51fabab, - 0x9e6f2d86, 0xb2c27a90, 0xd442d70c, 0x79bcb61b, 0x5c73a75a, 0xe51b8afd, - 0xabab13b2, 0x66f8827f, 0x109f3eeb, 0x09a1fd67, 0xc0fb7449, 0x09f3eee4, - 0x3f05ae71, 0x3f4e9df8, 0xafb84c53, 0x5c944356, 0xf21dbbd5, 0x4bfeebf9, - 0xa8d3cf7f, 0xaaa7c9c4, 0x749c5c74, 0xe7b0c282, 0xf90ec5d1, 0x713397fe, - 0xdbd43cfd, 0x10b5d8a8, 0xfdaf38f3, 0xe2f8ec35, 0xc1a79ead, 0x7738cf27, - 0x3579f10e, 0x0d90c758, 0xbbe319ed, 0xdbd529e4, 0x3d36b688, 0x357e9260, - 0x6df68a58, 0xfa20f435, 0x81762fd9, 0xf393ed4f, 0x3a622c6e, 0xb79a1acf, - 0xe9788ede, 0x73fe8dd9, 0xec5e9e65, 0xdfeeb637, 0xe58f9c69, 0xc37987d9, - 0xf9e4aa85, 0x6dea37c3, 0x55c22ecc, 0x371d0e3a, 0x93aca8fc, 0x58e7fbe4, - 0xa55e39fb, 0xfdf9781a, 0x47bcb372, 0x7e4c4f20, 0x0a5d5eea, 0xa3de5879, - 0x61afbc86, 0x5299ec9c, 0x7b6ef98f, 0xc77ec80d, 0x7c653b0d, 0xe3af396c, - 0xa685b4a3, 0x0de404e0, 0x4e0d1e53, 0x7653bc80, 0xdc5cda8c, 0xb51810be, - 0xe1787f21, 0xe86d476f, 0x7543c17f, 0x56bfe1e3, 0xc2df09ad, 0x3f5951b2, - 0x921af79d, 0x04e8c277, 0x4d856fe4, 0x6c02596f, 0xe69e73b7, 0xb7f2937d, - 0xd3638922, 0xfe9a5b0d, 0x87b04aa8, 0xe490cfe9, 0x259d54ab, 0xdd14bee3, - 0x3e8f7dff, 0x6e8ec2a8, 0x09dcb208, 0x69e737f6, 0x1248e5d3, 0x6bacb0df, - 0xf3837031, 0x3f71a4b5, 0x3cbe4733, 0xe423c0c5, 0x378c8d8f, 0xbeb7a6fe, - 0x79c8be42, 0x8c7e18dc, 0x261c314d, 0xebef5dc4, 0x20fc1711, 0xbbdade79, - 0xf78ad91e, 0x76e3536d, 0xd78fbc8b, 0xdb456df4, 0x259efada, 0x4cbf2487, - 0x65f9cf9a, 0x9c9d7d12, 0x7b68e463, 0x39adf3f0, 0x76cbece3, 0x0ed12d70, - 0x37439a4e, 0xd27abde0, 0x480eea9f, 0x0fdd091c, 0x6ad9d97c, 0xecae2377, - 0xd8a555fa, 0xa9f5b7d7, 0xfaa98f32, 0xa751d947, 0x52540fcc, 0x87e6fc11, - 0xe1e011da, 0x0c3c24ec, 0x8972dd48, 0xddae7043, 0xadb60778, 0x123e4a71, - 0x5336ebf3, 0x98adc3e8, 0xef90e597, 0x45b70c11, 0x6f7c2ca6, 0x4aeee29a, - 0x2ece2bc8, 0x9d041599, 0x830a19dd, 0x15cfe8ef, 0xd5c8ea37, 0xd6ae3a69, - 0x7bad0da8, 0x352dfc79, 0x5bf1b82c, 0x6ff307e0, 0x7697acb7, 0xb14cd945, - 0x290a5cdb, 0x7067fffa, 0x3d7bc42d, 0x67ad3df6, 0x20efb05b, 0xf04afbde, - 0x8fa8b599, 0xe45d95fe, 0x80d50689, 0x33d3cf99, 0x7bb70481, 0xb8942cee, - 0xc686a513, 0x2cff91fb, 0x6a3a954f, 0x13d704cf, 0xd3da6ef8, 0xf5e4a37c, - 0xc7a4fe87, 0x29a5d1fb, 0x3d71e46e, 0x711b5cf3, 0x5d479eae, 0xa29afe32, - 0xa13c0bf3, 0xa967a7eb, 0xe69ece7e, 0xc59f794c, 0x8767a1ee, 0xbfbe3267, - 0xe5bc3259, 0x1803a8d5, 0x667b1fdf, 0x4fb73f70, 0xde770d29, 0x75733e07, - 0xb9945779, 0xde4edee4, 0x7b13e379, 0xf1867d74, 0x897dac1d, 0xfefde923, - 0xcb80febf, 0x002220b3, 0x00000000 -}; - -#endif /*__BNX2X_INIT_VALUES_H__*/ -- cgit v0.10.2 From 56ed4351c2604c221a82276f51e5dfd467921bf3 Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Mon, 27 Apr 2009 03:28:25 -0700 Subject: bnx2x: driver version 1.48.105-1 Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index cdc80e0..a669bb7 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.105" -#define DRV_MODULE_RELDATE "2009/03/02" +#define DRV_MODULE_VERSION "1.48.105-1" +#define DRV_MODULE_RELDATE "2009/04/22" #define BNX2X_BC_VER 0x040200 #include -- cgit v0.10.2 From edbd9e30306067c3a45c035eb95a6f49daaa2337 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 27 Apr 2009 05:44:29 -0700 Subject: gro: Fix handling of headers that extend over the tail The skb_gro_* code fails to handle the case where a header starts in the linear area but ends in the frags area. Since the goal of skb_gro_* is to optimise the case of completely non-linear packets, we can simply bail out if we have anything in the linear area. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3116745..c9ef419 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1137,7 +1137,7 @@ static inline void skb_gro_reset_offset(struct sk_buff *skb) static inline void *skb_gro_mac_header(struct sk_buff *skb) { - return skb_mac_header(skb) < skb->data ? skb_mac_header(skb) : + return skb_headlen(skb) ? skb_mac_header(skb) : page_address(skb_shinfo(skb)->frags[0].page) + skb_shinfo(skb)->frags[0].page_offset; } diff --git a/net/core/dev.c b/net/core/dev.c index e48c08a..6785b06 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2378,18 +2378,13 @@ void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) unsigned int offset = skb_gro_offset(skb); hlen += offset; - if (hlen <= skb_headlen(skb)) - return skb->data + offset; - - if (unlikely(!skb_shinfo(skb)->nr_frags || - skb_shinfo(skb)->frags[0].size <= - hlen - skb_headlen(skb) || + if (unlikely(skb_headlen(skb) || + skb_shinfo(skb)->frags[0].size < hlen || PageHighMem(skb_shinfo(skb)->frags[0].page))) return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; return page_address(skb_shinfo(skb)->frags[0].page) + - skb_shinfo(skb)->frags[0].page_offset + - offset - skb_headlen(skb); + skb_shinfo(skb)->frags[0].page_offset + offset; } EXPORT_SYMBOL(skb_gro_header); -- cgit v0.10.2 From 36e7b1b8dac1a785abca3a121b6b0b79f1a8d7df Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 27 Apr 2009 05:44:45 -0700 Subject: gro: Fix COMPLETE checksum handling On a brand new GRO skb, we cannot call ip_hdr since the header may lie in the non-linear area. This patch adds the helper skb_gro_network_header to handle this. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c9ef419..fe20d17 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1142,6 +1142,13 @@ static inline void *skb_gro_mac_header(struct sk_buff *skb) skb_shinfo(skb)->frags[0].page_offset; } +static inline void *skb_gro_network_header(struct sk_buff *skb) +{ + return skb_headlen(skb) ? skb_network_header(skb) : + page_address(skb_shinfo(skb)->frags[0].page) + + skb_shinfo(skb)->frags[0].page_offset + skb_network_offset(skb); +} + static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5d427f8..bda74e8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2343,7 +2343,7 @@ void tcp4_proc_exit(void) struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); + struct iphdr *iph = skb_gro_network_header(skb); switch (skb->ip_summed) { case CHECKSUM_COMPLETE: diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4b5aa18..d9dd94b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -943,7 +943,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct ipv6hdr *iph = ipv6_hdr(skb); + struct ipv6hdr *iph = skb_gro_network_header(skb); switch (skb->ip_summed) { case CHECKSUM_COMPLETE: -- cgit v0.10.2 From 52fbc1007eb071c40a367462476eee695b412578 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Mon, 27 Apr 2009 19:42:03 +0000 Subject: atl1c: disable L1/L0s when link detected Disable L1/L0s when link detected. We enable L1/L0s when link connected before, but there is some hareware error on some platform. So just diable this feature when link connected. This feature is about power saving. Signed-off-by: Jie Yang Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index deb7b53..8b17278 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -220,11 +220,11 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) /* link down */ if (netif_carrier_ok(netdev)) { hw->hibernate = true; - atl1c_set_aspm(hw, false); if (atl1c_stop_mac(hw) != 0) if (netif_msg_hw(adapter)) dev_warn(&pdev->dev, "stop mac failed\n"); + atl1c_set_aspm(hw, false); } netif_carrier_off(netdev); } else { @@ -240,10 +240,10 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) adapter->link_duplex != duplex) { adapter->link_speed = speed; adapter->link_duplex = duplex; + atl1c_set_aspm(hw, true); atl1c_enable_tx_ctrl(hw); atl1c_enable_rx_ctrl(hw); atl1c_setup_mac_ctrl(adapter); - atl1c_set_aspm(hw, true); if (netif_msg_link(adapter)) dev_info(&pdev->dev, "%s: %s NIC Link is Up<%d Mbps %s>\n", @@ -1242,9 +1242,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup) AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data); - pm_ctrl_data &= PM_CTRL_SERDES_PD_EX_L1; - pm_ctrl_data |= ~PM_CTRL_SERDES_BUDS_RX_L1_EN; - pm_ctrl_data |= ~PM_CTRL_SERDES_L1_EN; + pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1; pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK << PM_CTRL_L1_ENTRY_TIMER_SHIFT); @@ -1254,19 +1252,11 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup) pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN; pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1; - if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) { - pm_ctrl_data |= AT_ASPM_L1_TIMER << - PM_CTRL_L1_ENTRY_TIMER_SHIFT; - pm_ctrl_data |= PM_CTRL_ASPM_L1_EN; - } else - pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; - - if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) - pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN; - else - pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; - + pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN; + pm_ctrl_data |= PM_CTRL_SERDES_L1_EN; } else { + pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN; + pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN; pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN; -- cgit v0.10.2 From 833cc67c7722e35863c6aaee9df56b442ef957ae Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 27 Apr 2009 21:32:16 +0000 Subject: smsc911x: add fifo byteswap support V2 This is V2 of the smsc911x fifo byteswap patch. The smsc911x hardware supports both big and little and endian hardware configurations, and the linux smsc911x driver currently detects word order. For correct operation on big endian platforms lacking swapped byte lanes the following patch is needed. Only fifo data is swapped, register data does not require any swapping. Signed-off-by: Magnus Damm Acked-by: Steve Glendinning Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index eb7db03..5113b26 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include "smsc911x.h" @@ -175,6 +176,12 @@ static inline void smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, unsigned int wordcount) { + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + smsc911x_reg_write(pdata, TX_DATA_FIFO, swab32(*buf++)); + return; + } + if (pdata->config.flags & SMSC911X_USE_32BIT) { writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); return; @@ -194,6 +201,12 @@ static inline void smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, unsigned int wordcount) { + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + *buf++ = swab32(smsc911x_reg_read(pdata, RX_DATA_FIFO)); + return; + } + if (pdata->config.flags & SMSC911X_USE_32BIT) { readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); return; diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h index b327250..5241e4f 100644 --- a/include/linux/smsc911x.h +++ b/include/linux/smsc911x.h @@ -47,4 +47,14 @@ struct smsc911x_platform_config { #define SMSC911X_FORCE_EXTERNAL_PHY (BIT(3)) #define SMSC911X_SAVE_MAC_ADDRESS (BIT(4)) +/* + * SMSC911X_SWAP_FIFO: + * Enables software byte swap for fifo data. Should only be used as a + * "last resort" in the case of big endian mode on boards with incorrectly + * routed data bus to older devices such as LAN9118. Newer devices such as + * LAN9221 can handle this in hardware, there are registers to control + * this swapping but the driver doesn't currently use them. + */ +#define SMSC911X_SWAP_FIFO (BIT(5)) + #endif /* __LINUX_SMSC911X_H__ */ -- cgit v0.10.2 From 3935358ebcb8320965478c0e8ee070e1d65851c8 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 27 Apr 2009 22:34:54 +0000 Subject: igb: reconfigure mailbox timeout logic This change updates the timeout logic so that it is not possible to have a sucessful check for message and still return an error if countdown = 0. Signed-off-by: Alexander Duyck Reported-by: Juha Leppanen Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c index 840782f..ed9058e 100644 --- a/drivers/net/igb/e1000_mbx.c +++ b/drivers/net/igb/e1000_mbx.c @@ -140,13 +140,13 @@ static s32 igb_poll_for_msg(struct e1000_hw *hw, u16 mbx_id) struct e1000_mbx_info *mbx = &hw->mbx; int countdown = mbx->timeout; - if (!mbx->ops.check_for_msg) + if (!countdown || !mbx->ops.check_for_msg) goto out; while (mbx->ops.check_for_msg(hw, mbx_id)) { + countdown--; if (!countdown) break; - countdown--; udelay(mbx->usec_delay); } out: @@ -165,13 +165,13 @@ static s32 igb_poll_for_ack(struct e1000_hw *hw, u16 mbx_id) struct e1000_mbx_info *mbx = &hw->mbx; int countdown = mbx->timeout; - if (!mbx->ops.check_for_ack) + if (!countdown || !mbx->ops.check_for_ack) goto out; while (mbx->ops.check_for_ack(hw, mbx_id)) { + countdown--; if (!countdown) break; - countdown--; udelay(mbx->usec_delay); } out: -- cgit v0.10.2 From 2844f7975837d47fe7f20aa96c1df3bcecf91935 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 27 Apr 2009 22:35:14 +0000 Subject: igb: make rxcsum configuration seperate from multiqueue The igb driver was being incorrectly setup to only allow disabling receive checksum if multiqueue was disabled. This change corrects that so that RXCSUM is configured regardless of queue configuration. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index ad2d319..65acbbac 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -289,8 +289,8 @@ #define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 /* Receive Checksum Control */ +#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ #define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ -#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ /* Header split receive */ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index ab846ec6..4ecf4df 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2236,29 +2236,21 @@ static void igb_configure_rx(struct igb_adapter *adapter) mrqc |= (E1000_MRQC_RSS_FIELD_IPV6_UDP_EX | E1000_MRQC_RSS_FIELD_IPV6_TCP_EX); - wr32(E1000_MRQC, mrqc); - - /* Multiqueue and raw packet checksumming are mutually - * exclusive. Note that this not the same as TCP/IP - * checksumming, which works fine. */ - rxcsum = rd32(E1000_RXCSUM); - rxcsum |= E1000_RXCSUM_PCSD; - wr32(E1000_RXCSUM, rxcsum); - } else { + } else if (adapter->vfs_allocated_count) { /* Enable multi-queue for sr-iov */ - if (adapter->vfs_allocated_count) - wr32(E1000_MRQC, E1000_MRQC_ENABLE_VMDQ); - /* Enable Receive Checksum Offload for TCP and UDP */ - rxcsum = rd32(E1000_RXCSUM); - if (adapter->rx_csum) - rxcsum |= E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE; - else - rxcsum &= ~(E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE); - - wr32(E1000_RXCSUM, rxcsum); + wr32(E1000_MRQC, E1000_MRQC_ENABLE_VMDQ); } + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = rd32(E1000_RXCSUM); + /* Disable raw packet checksumming */ + rxcsum |= E1000_RXCSUM_PCSD; + /* Don't need to set TUOFL or IPOFL, they default to 1 */ + if (!adapter->rx_csum) + rxcsum &= ~(E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPOFL); + wr32(E1000_RXCSUM, rxcsum); + /* Set the default pool for the PF's first queue */ igb_configure_vt_default_pool(adapter); -- cgit v0.10.2 From 182ff8dfdb63e66ca81e4d3a4c746f8d578e5687 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 27 Apr 2009 22:35:33 +0000 Subject: igb/ixgbe: remove unecessary checks for CHECKSUM_UNNECESSARY Both of these drivers do a check to verify ip_summed is set to CHECKSUM_UNNECESSARY prior to passing the packet to GRO. GRO itself already does such a check so it is redundant and can be removed as this will likely cause out of order issues when receiving a packet that didn't pass checksum validation. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 4ecf4df..f7f8612 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4430,20 +4430,12 @@ static void igb_receive_skb(struct igb_ring *ring, u8 status, bool vlan_extracted = (adapter->vlgrp && (status & E1000_RXD_STAT_VP)); skb_record_rx_queue(skb, ring->queue_index); - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - if (vlan_extracted) - vlan_gro_receive(&ring->napi, adapter->vlgrp, - le16_to_cpu(rx_desc->wb.upper.vlan), - skb); - else - napi_gro_receive(&ring->napi, skb); - } else { - if (vlan_extracted) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->wb.upper.vlan)); - else - netif_receive_skb(skb); - } + if (vlan_extracted) + vlan_gro_receive(&ring->napi, adapter->vlgrp, + le16_to_cpu(rx_desc->wb.upper.vlan), + skb); + else + napi_gro_receive(&ring->napi, skb); } static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index c45e4e7..42b803d 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -459,23 +459,16 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); skb_record_rx_queue(skb, q_vector - &adapter->q_vector[0]); - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_gro_receive(napi, adapter->vlgrp, tag, skb); else napi_gro_receive(napi, skb); } else { - if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { - if (adapter->vlgrp && is_vlan && (tag != 0)) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); - else - netif_receive_skb(skb); - } else { - if (adapter->vlgrp && is_vlan && (tag != 0)) - vlan_hwaccel_rx(skb, adapter->vlgrp, tag); - else - netif_rx(skb); - } + if (adapter->vlgrp && is_vlan && (tag != 0)) + vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + else + netif_rx(skb); } } -- cgit v0.10.2 From 8dc92f7e2ecfd93f5c57da78594a7a5482e2c15e Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 27 Apr 2009 22:35:52 +0000 Subject: sctp: add feature bit for SCTP offload in hardware this is the sctp code to enable hardware crc32c offload for adapters that support it. Originally by: Vlad Yasevich modified by Jesse Brandeburg Signed-off-by: Jesse Brandeburg Signed-off-by: Vlad Yasevich Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fe20d17..f8c3619 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -670,7 +670,9 @@ struct net_device #define NETIF_F_GRO 16384 /* Generic receive offload */ #define NETIF_F_LRO 32768 /* large receive offload */ +/* the GSO_MASK reserves bits 16 through 23 */ #define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */ +#define NETIF_F_SCTP_CSUM (1 << 25) /* SCTP checksum offload */ /* Segmentation offload features */ #define NETIF_F_GSO_SHIFT 16 diff --git a/net/sctp/output.c b/net/sctp/output.c index 7d08f52..f0c91df 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -412,6 +412,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) /* Build the SCTP header. */ sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); + skb_reset_transport_header(nskb); sh->source = htons(packet->source_port); sh->dest = htons(packet->destination_port); @@ -527,15 +528,25 @@ int sctp_packet_transmit(struct sctp_packet *packet) * Note: Adler-32 is no longer applicable, as has been replaced * by CRC32-C as described in . */ - if (!sctp_checksum_disable && !(dst->dev->features & NETIF_F_NO_CSUM)) { + if (!sctp_checksum_disable && + !(dst->dev->features & (NETIF_F_NO_CSUM | NETIF_F_SCTP_CSUM))) { __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); /* 3) Put the resultant value into the checksum field in the * common header, and leave the rest of the bits unchanged. */ sh->checksum = sctp_end_cksum(crc32); - } else - nskb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + if (dst->dev->features & NETIF_F_SCTP_CSUM) { + /* no need to seed psuedo checksum for SCTP */ + nskb->ip_summed = CHECKSUM_PARTIAL; + nskb->csum_start = (skb_transport_header(nskb) - + nskb->head); + nskb->csum_offset = offsetof(struct sctphdr, checksum); + } else { + nskb->ip_summed = CHECKSUM_UNNECESSARY; + } + } /* IP layer ECN support * From RFC 2481 -- cgit v0.10.2 From b9473560c6d882e0fbd3a8817e906c847b11c722 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 27 Apr 2009 22:36:13 +0000 Subject: igb: Enable SCTP checksum offloading Originally from: Vlad Yasevich This patch, both the driver portion and the sctp code was modified by Jesse Brandeburg and is Copyright(c) 2009 Intel Corporation. Thanks go to Vlad for starting this work. Intel 82576 chipset supports SCTP checksum offloading. This patch enables this functionality in the driver. A new NETIF feature is introduced for SCTP checksum offload. If the driver supports CRC32c checksum, it can set this feature flag. The hardware can offload both transmit and receive. Signed-off-by: Jesse Brandeburg Signed-off-by: Vlad Yasevich Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index eaf9770..0f16aba 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -130,6 +130,7 @@ struct e1000_adv_tx_context_desc { #define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ #define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ #define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */ /* IPSec Encrypt Enable for ESP */ #define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ #define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index 65acbbac..3bda3db 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -291,6 +291,7 @@ /* Receive Checksum Control */ #define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ #define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ /* Header split receive */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 27eae49..b1367ce 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -293,10 +293,16 @@ static u32 igb_get_tx_csum(struct net_device *netdev) static int igb_set_tx_csum(struct net_device *netdev, u32 data) { - if (data) + struct igb_adapter *adapter = netdev_priv(netdev); + + if (data) { netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - else - netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + if (adapter->hw.mac.type == e1000_82576) + netdev->features |= NETIF_F_SCTP_CSUM; + } else { + netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_SCTP_CSUM); + } return 0; } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index f7f8612..bca7e9f 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1345,6 +1345,9 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; + if (adapter->hw.mac.type == e1000_82576) + netdev->features |= NETIF_F_SCTP_CSUM; + adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw); /* before reading the NVM, reset the controller to put the device in a @@ -2249,6 +2252,10 @@ static void igb_configure_rx(struct igb_adapter *adapter) /* Don't need to set TUOFL or IPOFL, they default to 1 */ if (!adapter->rx_csum) rxcsum &= ~(E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPOFL); + else if (adapter->hw.mac.type == e1000_82576) + /* Enable Receive Checksum Offload for SCTP */ + rxcsum |= E1000_RXCSUM_CRCOFL; + wr32(E1000_RXCSUM, rxcsum); /* Set the default pool for the PF's first queue */ @@ -3064,11 +3071,15 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, tu_cmd |= E1000_ADVTXD_TUCMD_IPV4; if (ip_hdr(skb)->protocol == IPPROTO_TCP) tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + else if (ip_hdr(skb)->protocol == IPPROTO_SCTP) + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_SCTP; break; case cpu_to_be16(ETH_P_IPV6): /* XXX what about other V6 headers?? */ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + else if (ipv6_hdr(skb)->nexthdr == IPPROTO_SCTP) + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_SCTP; break; default: if (unlikely(net_ratelimit())) @@ -4449,14 +4460,22 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, /* TCP/UDP checksum error bit is set */ if (status_err & (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) { + /* + * work around errata with sctp packets where the TCPE aka + * L4E bit is set incorrectly on 64 byte (60 byte w/o crc) + * packets, (aka let the stack check the crc32c) + */ + if (!((adapter->hw.mac.type == e1000_82576) && + (skb->len == 60))) + adapter->hw_csum_err++; /* let the stack verify checksum errors */ - adapter->hw_csum_err++; return; } /* It must be a TCP or UDP packet with a valid checksum */ if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)) skb->ip_summed = CHECKSUM_UNNECESSARY; + dev_dbg(&adapter->pdev->dev, "cksum success: bits %08X\n", status_err); adapter->hw_csum_good++; } -- cgit v0.10.2 From 45a5ead0220cc7cc70f6961879decffbd0a54cc0 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 27 Apr 2009 22:36:35 +0000 Subject: ixgbe: enable hardware offload for sctp Inspired by: Vlad Yasevich This is the code to enable ixgbe for hardware offload support of CRC32c on both transmit and receive of SCTP traffic. only 82599 supports this offload, not 82598. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index f0a20fa..a499b6b 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -311,10 +311,17 @@ static u32 ixgbe_get_tx_csum(struct net_device *netdev) static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data) { - if (data) + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (data) { netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - else + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + netdev->features |= NETIF_F_SCTP_CSUM; + } else { netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + netdev->features &= ~NETIF_F_SCTP_CSUM; + } return 0; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 42b803d..c3dff8f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4189,12 +4189,18 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, if (ip_hdr(skb)->protocol == IPPROTO_TCP) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + else if (ip_hdr(skb)->protocol == IPPROTO_SCTP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_SCTP; break; case cpu_to_be16(ETH_P_IPV6): /* XXX what about other V6 headers?? */ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + else if (ipv6_hdr(skb)->nexthdr == IPPROTO_SCTP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_SCTP; break; default: if (unlikely(net_ratelimit())) { @@ -4718,6 +4724,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_GRO; + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + netdev->features |= NETIF_F_SCTP_CSUM; + netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_IP_CSUM; -- cgit v0.10.2 From f8212f979f777af2a8e3a9deb0c11a9fcf35e305 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 27 Apr 2009 22:42:37 +0000 Subject: ixgbe: enable HW RSC for 82599 This patch enables hardware receive side coalescing for 82599 hardware. 82599 can merge multiple frames from the same TCP/IP flow into a single structure that can span one ore more descriptors. The accumulated data is arranged similar to how jumbo frames are arranged with the exception that other packets can be interlaced inbetween. To overcome this issue a next pointer is included in the written back descriptor which indicates the next descriptor in the writeback sequence. This feature sets the NETIF_F_LRO flag and clearing it via the ethtool set flags operation will also disable hardware RSC. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index c26433d1..4b44a8e 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -147,6 +147,7 @@ struct ixgbe_ring { u16 work_limit; /* max work per interrupt */ u16 rx_buf_len; + u64 rsc_count; /* stat for coalesced packets */ }; enum ixgbe_ring_f_enum { @@ -294,6 +295,8 @@ struct ixgbe_adapter { #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) #define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24) #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) +#define IXGBE_FLAG_RSC_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_RSC_ENABLED (u32)(1 << 27) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -325,6 +328,7 @@ struct ixgbe_adapter { struct timer_list sfp_timer; struct work_struct multispeed_fiber_task; struct work_struct sfp_config_module_task; + u64 rsc_count; u32 wol; u16 eeprom_version; }; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index a499b6b..d822c92 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -67,6 +67,7 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)}, {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)}, {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)}, + {"hw_rsc_count", IXGBE_STAT(rsc_count)}, {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)}, {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)}, {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)}, @@ -1127,6 +1128,27 @@ static int ixgbe_set_coalesce(struct net_device *netdev, return 0; } +static int ixgbe_set_flags(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + ethtool_op_set_flags(netdev, data); + + if (!(adapter->flags & IXGBE_FLAG_RSC_CAPABLE)) + return 0; + + /* if state changes we need to update adapter->flags and reset */ + if ((!!(data & ETH_FLAG_LRO)) != + (!!(adapter->flags & IXGBE_FLAG_RSC_ENABLED))) { + adapter->flags ^= IXGBE_FLAG_RSC_ENABLED; + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); + else + ixgbe_reset(adapter); + } + return 0; + +} static const struct ethtool_ops ixgbe_ethtool_ops = { .get_settings = ixgbe_get_settings, @@ -1161,7 +1183,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .get_coalesce = ixgbe_get_coalesce, .set_coalesce = ixgbe_set_coalesce, .get_flags = ethtool_op_get_flags, - .set_flags = ethtool_op_set_flags, + .set_flags = ixgbe_set_flags, }; void ixgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index c3dff8f..419ce47 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -615,6 +615,40 @@ 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 inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc) +{ + return (le32_to_cpu(rx_desc->wb.lower.lo_dword.data) & + IXGBE_RXDADV_RSCCNT_MASK) >> + IXGBE_RXDADV_RSCCNT_SHIFT; +} + +/** + * ixgbe_transform_rsc_queue - change rsc queue into a full packet + * @skb: pointer to the last skb in the rsc queue + * + * This function changes a queue full of hw rsc buffers into a completed + * packet. It uses the ->prev pointers to find the first packet and then + * turns it into the frag list owner. + **/ +static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb) +{ + unsigned int frag_list_size = 0; + + while (skb->prev) { + struct sk_buff *prev = skb->prev; + frag_list_size += skb->len; + skb->prev = NULL; + skb = prev; + } + + skb_shinfo(skb)->frag_list = skb->next; + skb->next = NULL; + skb->len += frag_list_size; + skb->data_len += frag_list_size; + skb->truesize += frag_list_size; + return skb; +} + static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, struct ixgbe_ring *rx_ring, int *work_done, int work_to_do) @@ -624,7 +658,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, 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; + unsigned int i, rsc_count = 0; u32 len, staterr; u16 hdr_info; bool cleaned = false; @@ -690,20 +724,38 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, i++; if (i == rx_ring->count) i = 0; - next_buffer = &rx_ring->rx_buffer_info[i]; next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i); prefetch(next_rxd); - cleaned_count++; + + if (adapter->flags & IXGBE_FLAG_RSC_CAPABLE) + rsc_count = ixgbe_get_rsc_count(rx_desc); + + if (rsc_count) { + u32 nextp = (staterr & IXGBE_RXDADV_NEXTP_MASK) >> + IXGBE_RXDADV_NEXTP_SHIFT; + next_buffer = &rx_ring->rx_buffer_info[nextp]; + rx_ring->rsc_count += (rsc_count - 1); + } else { + next_buffer = &rx_ring->rx_buffer_info[i]; + } + if (staterr & IXGBE_RXD_STAT_EOP) { + if (skb->prev) + skb = ixgbe_transform_rsc_queue(skb); rx_ring->stats.packets++; rx_ring->stats.bytes += skb->len; } else { - rx_buffer_info->skb = next_buffer->skb; - rx_buffer_info->dma = next_buffer->dma; - next_buffer->skb = skb; - next_buffer->dma = 0; + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + rx_buffer_info->skb = next_buffer->skb; + rx_buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; + next_buffer->dma = 0; + } else { + skb->next = next_buffer->skb; + skb->next->prev = skb; + } adapter->non_eop_descs++; goto next_desc; } @@ -733,7 +785,7 @@ next_desc: /* use prefetched values */ rx_desc = next_rxd; - rx_buffer_info = next_buffer; + rx_buffer_info = &rx_ring->rx_buffer_info[i]; staterr = le32_to_cpu(rx_desc->wb.upper.status_error); } @@ -1729,6 +1781,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) u32 fctrl, hlreg0; u32 reta = 0, mrqc = 0; u32 rdrxctl; + u32 rscctrl; int rx_buf_len; /* Decide whether to use packet split mode or not */ @@ -1746,7 +1799,8 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); } } else { - if (netdev->mtu <= ETH_DATA_LEN) + if (!(adapter->flags & IXGBE_FLAG_RSC_ENABLED) && + (netdev->mtu <= ETH_DATA_LEN)) rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; else rx_buf_len = ALIGN(max_frame, 1024); @@ -1868,8 +1922,38 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) if (hw->mac.type == ixgbe_mac_82599EB) { rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP; + rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); } + + if (adapter->flags & IXGBE_FLAG_RSC_ENABLED) { + /* Enable 82599 HW-RSC */ + for (i = 0; i < adapter->num_rx_queues; i++) { + j = adapter->rx_ring[i].reg_idx; + rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(j)); + rscctrl |= IXGBE_RSCCTL_RSCEN; + /* + * if packet split is enabled we can only support up + * to max frags + 1 descriptors. + */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) +#if (MAX_SKB_FRAGS < 3) + rscctrl |= IXGBE_RSCCTL_MAXDESC_1; +#elif (MAX_SKB_FRAGS < 7) + rscctrl |= IXGBE_RSCCTL_MAXDESC_4; +#elif (MAX_SKB_FRAGS < 15) + rscctrl |= IXGBE_RSCCTL_MAXDESC_8; +#else + rscctrl |= IXGBE_RSCCTL_MAXDESC_16; +#endif + else + rscctrl |= IXGBE_RSCCTL_MAXDESC_16; + IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(j), rscctrl); + } + /* Disable RSC for ACK packets */ + IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, + (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU))); + } } static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) @@ -2438,8 +2522,13 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, rx_buffer_info->dma = 0; } if (rx_buffer_info->skb) { - dev_kfree_skb(rx_buffer_info->skb); + struct sk_buff *skb = rx_buffer_info->skb; rx_buffer_info->skb = NULL; + do { + struct sk_buff *this = skb; + skb = skb->prev; + dev_kfree_skb(this); + } while (skb); } if (!rx_buffer_info->page) continue; @@ -3180,8 +3269,11 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; if (hw->mac.type == ixgbe_mac_82598EB) adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598; - else if (hw->mac.type == ixgbe_mac_82599EB) + else if (hw->mac.type == ixgbe_mac_82599EB) { adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; + adapter->flags |= IXGBE_FLAG_RSC_CAPABLE; + adapter->flags |= IXGBE_FLAG_RSC_ENABLED; + } #ifdef CONFIG_IXGBE_DCB /* Configure DCB traffic classes */ @@ -3765,9 +3857,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot; if (hw->mac.type == ixgbe_mac_82599EB) { + u64 rsc_count = 0; for (i = 0; i < 16; i++) adapter->hw_rx_no_dma_resources += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); + for (i = 0; i < adapter->num_rx_queues; i++) + rsc_count += adapter->rx_ring[i].rsc_count; + adapter->rsc_count = rsc_count; } adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); @@ -4742,6 +4838,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; + if (adapter->flags & IXGBE_FLAG_RSC_ENABLED) + netdev->features |= NETIF_F_LRO; + /* make sure the EEPROM is good */ if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) { dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 375f0d4..bdfdf3b 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -443,6 +443,21 @@ #define IXGBE_SECTXCTRL_STORE_FORWARD_ENABLE 0x4 +/* HW RSC registers */ +#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \ + (0x0D02C + ((_i - 64) * 0x40))) +#define IXGBE_RSCDBU 0x03028 +#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 +#define IXGBE_RXDADV_RSCCNT_SHIFT 17 +#define IXGBE_GPIE_RSC_DELAY_SHIFT 11 +#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 +#define IXGBE_RSCDBU_RSCACKDIS 0x00000080 +#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 + /* DCB registers */ #define IXGBE_RTRPCS 0x02430 #define IXGBE_RTTDCS 0x04900 -- cgit v0.10.2 From 835462fc5d69adc948e8afb2073264888aaa0e2f Mon Sep 17 00:00:00 2001 From: "Nelson, Shannon" Date: Mon, 27 Apr 2009 22:42:54 +0000 Subject: ixgbe: Interrupt management update for 82599 Update the interrupt management to correctly handle greater than 16 queue vectors. Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 419ce47..6c90b68 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -326,8 +326,18 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, } /* re-arm the interrupt */ - if (count >= tx_ring->work_limit) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx); + if (count >= tx_ring->work_limit) { + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, + tx_ring->v_idx); + else if (tx_ring->v_idx & 0xFFFFFFFF) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), + tx_ring->v_idx); + else + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), + (tx_ring->v_idx >> 32)); + } + tx_ring->total_bytes += total_bytes; tx_ring->total_packets += total_packets; @@ -1166,7 +1176,13 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) 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, rx_ring->v_idx); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); + else if (rx_ring->v_idx & 0xFFFFFFFF) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), rx_ring->v_idx); + else + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), + (rx_ring->v_idx >> 32)); napi_schedule(&q_vector->napi); return IRQ_HANDLED; @@ -1180,6 +1196,23 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) return IRQ_HANDLED; } +static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask); + } + /* skip the flush */ +} + /** * ixgbe_clean_rxonly - msix (aka one shot) rx clean routine * @napi: napi struct with our devices info in it @@ -1212,7 +1245,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rx_ring->v_idx); + ixgbe_irq_enable_queues(adapter, rx_ring->v_idx); } return work_done; @@ -1234,7 +1267,7 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) struct ixgbe_ring *rx_ring = NULL; int work_done = 0, i; long r_idx; - u16 enable_mask = 0; + u64 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 */ @@ -1261,7 +1294,7 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, enable_mask); + ixgbe_irq_enable_queues(adapter, enable_mask); return 0; } @@ -1481,7 +1514,8 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter) static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) { u32 mask; - mask = IXGBE_EIMS_ENABLE_MASK; + + mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) mask |= IXGBE_EIMS_GPI_SDP1; if (adapter->hw.mac.type == ixgbe_mac_82599EB) { @@ -1491,14 +1525,7 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) } IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); - if (adapter->hw.mac.type == ixgbe_mac_82599EB) { - /* enable the rest of the queue vectors */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), - (IXGBE_EIMS_RTX_QUEUE << 16)); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2), - ((IXGBE_EIMS_RTX_QUEUE << 16) | - IXGBE_EIMS_RTX_QUEUE)); - } + ixgbe_irq_enable_queues(adapter, ~0); IXGBE_WRITE_FLUSH(&adapter->hw); } @@ -1622,10 +1649,12 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter) **/ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); - if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); + } else { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(2), ~0); } IXGBE_WRITE_FLUSH(&adapter->hw); if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { @@ -1637,18 +1666,6 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) } } -static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter) -{ - u32 mask = IXGBE_EIMS_RTX_QUEUE; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); - if (adapter->hw.mac.type == ixgbe_mac_82599EB) { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask << 16); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2), - (mask << 16 | mask)); - } - /* skip the flush */ -} - /** * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts * @@ -2714,7 +2731,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr(adapter); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - ixgbe_irq_enable_queues(adapter); + ixgbe_irq_enable_queues(adapter, IXGBE_EIMS_RTX_QUEUE); } return work_done; } @@ -4005,16 +4022,9 @@ static void ixgbe_watchdog(unsigned long data) break; case ixgbe_mac_82599EB: if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - /* - * EICS(0..15) first 0-15 q vectors - * EICS[1] (16..31) q vectors 16-31 - * EICS[2] (0..31) q vectors 32-63 - */ - IXGBE_WRITE_REG(hw, IXGBE_EICS, - (u32)(eics & 0xFFFF)); + IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(0), + (u32)(eics & 0xFFFFFFFF)); IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(1), - (u32)(eics & 0xFFFF0000)); - IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(2), (u32)(eics >> 32)); } else { /* -- cgit v0.10.2 From bc59fcda671ee15362986a902bbd90e218fe84c4 Mon Sep 17 00:00:00 2001 From: "Nelson, Shannon" Date: Mon, 27 Apr 2009 22:43:12 +0000 Subject: ixgbe: Clear out stray tx work on link down Ayyappan at VMware noticed that we're missing this check from ixgbe which is in our other drivers. The difference with this implementation from our other drivers is that this checks all the tx queues rather than just tx[0]. Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 6c90b68..5020f11 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4110,6 +4110,9 @@ static void ixgbe_watchdog_task(struct work_struct *work) struct ixgbe_hw *hw = &adapter->hw; u32 link_speed = adapter->link_speed; bool link_up = adapter->link_up; + int i; + struct ixgbe_ring *tx_ring; + int some_tx_pending = 0; adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; @@ -4167,6 +4170,25 @@ static void ixgbe_watchdog_task(struct work_struct *work) } } + if (!netif_carrier_ok(netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) { + tx_ring = &adapter->tx_ring[i]; + if (tx_ring->next_to_use != tx_ring->next_to_clean) { + some_tx_pending = 1; + break; + } + } + + if (some_tx_pending) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). + */ + schedule_work(&adapter->reset_task); + } + } + ixgbe_update_stats(adapter); adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; } -- cgit v0.10.2 From 1d58ea30b141c95bd21fb39021d4b602f48b30be Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 28 Apr 2009 02:05:21 -0700 Subject: fs_enet: Remove dead code CONFIG_DUET doesn't exist anymore, remove all the code that exists to support it. [ Simplify fs_init() even further -DaveM ] Signed-off-by: Kumar Gala Signed-off-by: David S. Miller diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 9604aae..b892c3a 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -941,30 +941,6 @@ extern void fs_mii_disconnect(struct net_device *dev); /**************************************************************************************/ -/* handy pointer to the immap */ -void __iomem *fs_enet_immap = NULL; - -static int setup_immap(void) -{ -#ifdef CONFIG_CPM1 - fs_enet_immap = ioremap(IMAP_ADDR, 0x4000); - WARN_ON(!fs_enet_immap); -#elif defined(CONFIG_CPM2) - fs_enet_immap = cpm2_immr; -#endif - - return 0; -} - -static void cleanup_immap(void) -{ -#if defined(CONFIG_CPM1) - iounmap(fs_enet_immap); -#endif -} - -/**************************************************************************************/ - #ifdef CONFIG_FS_ENET_HAS_FEC #define IS_FEC(match) ((match)->data == &fs_fec_ops) #else @@ -1144,25 +1120,12 @@ static struct of_platform_driver fs_enet_driver = { static int __init fs_init(void) { - int r = setup_immap(); - if (r != 0) - return r; - - r = of_register_platform_driver(&fs_enet_driver); - if (r != 0) - goto out; - - return 0; - -out: - cleanup_immap(); - return r; + return of_register_platform_driver(&fs_enet_driver); } static void __exit fs_cleanup(void) { of_unregister_platform_driver(&fs_enet_driver); - cleanup_immap(); } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 85a4bab..ef01e09 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -194,9 +194,4 @@ extern const struct fs_ops fs_scc_ops; /*******************************************************************/ -/* handy pointer to the immap */ -extern void __iomem *fs_enet_immap; - -/*******************************************************************/ - #endif diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 14e5753..ca7bcb8 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -245,10 +245,6 @@ static void set_multicast_list(struct net_device *dev) static void restart(struct net_device *dev) { -#ifdef CONFIG_DUET - immap_t *immap = fs_enet_immap; - u32 cptr; -#endif struct fs_enet_private *fep = netdev_priv(dev); fec_t __iomem *fecp = fep->fec.fecp; const struct fs_platform_info *fpi = fep->fpi; @@ -315,36 +311,6 @@ static void restart(struct net_device *dev) FW(fecp, ievent, 0xffc0); FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29); - /* - * adjust to speed (only for DUET & RMII) - */ -#ifdef CONFIG_DUET - if (fpi->use_rmii) { - cptr = in_be32(&immap->im_cpm.cp_cptr); - switch (fs_get_fec_index(fpi->fs_no)) { - case 0: - cptr |= 0x100; - if (fep->speed == 10) - cptr |= 0x0000010; - else if (fep->speed == 100) - cptr &= ~0x0000010; - break; - case 1: - cptr |= 0x80; - if (fep->speed == 10) - cptr |= 0x0000008; - else if (fep->speed == 100) - cptr &= ~0x0000008; - break; - default: - BUG(); /* should never happen */ - break; - } - out_be32(&immap->im_cpm.cp_cptr, cptr); - } -#endif - - FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ /* * adjust to duplex mode -- cgit v0.10.2 From 8555a5948467e941acc34e8b1c30df4c1f2f5862 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 28 Apr 2009 02:11:53 -0700 Subject: net: Fix ucc_geth.c handling of fixed-link w/o phy-connection-type property. Previous rework to ucc_geth.c to add of_mdio support (net: Rework ucc_geth driver to use of_mdio infrastructure) added a block of code which broke older openfirmware device trees which this case. This patch removes the offending blurb. Signed-off-by: Grant Likely Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index a536284..f18017d 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3631,9 +3631,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma prop = of_get_property(np, "phy-connection-type", NULL); if (!prop) { /* handle interface property present in old trees */ - if (!phy) - return -ENODEV; - prop = of_get_property(phy, "interface", NULL); if (prop != NULL) { phy_interface = enet_to_phy_interface[*prop]; -- cgit v0.10.2 From 6a321cb370ad3db4ba6e405e638b3a42c41089b0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 28 Apr 2009 04:43:42 -0700 Subject: net: netif_tx_queue_stopped too expensive netif_tx_queue_stopped(txq) is most of the time false. Yet its cost is very expensive on SMP. static inline int netif_tx_queue_stopped(const struct netdev_queue *dev_queue) { return test_bit(__QUEUE_STATE_XOFF, &dev_queue->state); } I saw this on oprofile hunting and bnx2 driver bnx2_tx_int(). We probably should split "struct netdev_queue" in two parts, one being read mostly. __netif_tx_lock() touches _xmit_lock & xmit_lock_owner, these deserve a separate cache line. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f8c3619..505a3c6 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -447,12 +447,18 @@ enum netdev_queue_state_t }; struct netdev_queue { +/* + * read mostly part + */ struct net_device *dev; struct Qdisc *qdisc; unsigned long state; - spinlock_t _xmit_lock; - int xmit_lock_owner; struct Qdisc *qdisc_sleeping; +/* + * write mostly part + */ + spinlock_t _xmit_lock ____cacheline_aligned_in_smp; + int xmit_lock_owner; } ____cacheline_aligned_in_smp; -- cgit v0.10.2 From ac5978e7f83a6cbd9a70282d6e39bd936a31b2bc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 28 Apr 2009 08:03:26 -0700 Subject: inet_diag: Remove dup assignments These are later assigned to other values without being used meanwhile. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 588a779..b0b2735 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -198,8 +198,6 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw, tmo = 0; r->idiag_family = tw->tw_family; - r->idiag_state = tw->tw_state; - r->idiag_timer = 0; r->idiag_retrans = 0; r->id.idiag_if = tw->tw_bound_dev_if; r->id.idiag_cookie[0] = (u32)(unsigned long)tw; -- cgit v0.10.2 From 6c31d55f755ff2bc1f7dc3b45c500032fe90aff8 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 28 Apr 2009 08:04:10 -0700 Subject: gianfar: Use memset instead of cacheable_memzero cacheable_memzero() is completely overkill for the clearing out the FCB block which is only 8-bytes. The compiler should easily optimize this with memset. Additionally, cacheable_memzero() only exists on ppc32 and thus breaks builds of gianfar on ppc64. Signed-off-by: Kumar Gala Signed-off-by: David S. Miller diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index dae1437..2bb038b 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -1207,7 +1207,8 @@ static int gfar_enet_open(struct net_device *dev) static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb) { struct txfcb *fcb = (struct txfcb *)skb_push(skb, GMAC_FCB_LEN); - cacheable_memzero(fcb, GMAC_FCB_LEN); + + memset(fcb, 0, GMAC_FCB_LEN); return fcb; } -- cgit v0.10.2 From 5103c9f7874506cb40fc3c8d3f22486d3c4d91aa Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 28 Apr 2009 15:29:09 +0000 Subject: netxen: fix link event handling Firmware starting 4.0.402 started supporting link events, disable it for older firmwares. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index a452b2f..e16ea46 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -247,6 +247,7 @@ skip: case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN: case LINKEVENT_MODULE_TWINAX: ecmd->port = PORT_TP; + break; default: ecmd->port = -1; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index e877eef..8331580 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -797,7 +797,7 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->max_sds_rings > 1) netxen_config_rss(adapter, 1); - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) netxen_linkevent_request(adapter, 1); return 0; diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 845dcf4..b73a62c 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -126,6 +126,7 @@ #define CRB_SW_INT_MASK_2 NETXEN_NIC_REG(0x1e4) #define CRB_SW_INT_MASK_3 NETXEN_NIC_REG(0x1e8) +#define CRB_FW_CAPABILITIES_1 NETXEN_CAM_RAM(0x128) #define CRB_MAC_BLOCK_START NETXEN_CAM_RAM(0x1c0) /* @@ -136,7 +137,6 @@ #define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) #define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) #define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) -#define CRB_FW_CAPABILITIES_1 NETXEN_NIC_REG(0x128) #define INTR_SCHEME_PERPORT 0x1 #define MSI_MODE_MULTIFUNC 0x1 -- cgit v0.10.2 From 4ea528a151549df795c984649d75860ea40390bd Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 28 Apr 2009 15:29:10 +0000 Subject: netxen: refactor netxen_recv_context struct o move related fields into netxen_recv_context struct. o allocate rx buffer and descriptor rings dynamically. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index ebd6c2e..16f5e22 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -775,8 +775,11 @@ struct netxen_recv_context { u16 context_id; u16 virt_port; - struct nx_host_rds_ring rds_rings[NUM_RCV_DESC_RINGS]; + struct nx_host_rds_ring *rds_rings; struct nx_host_sds_ring *sds_rings; + + struct netxen_ring_ctx *hwctx; + dma_addr_t phys_addr; }; /* New HW context creation */ @@ -1258,11 +1261,8 @@ struct netxen_adapter { struct netxen_adapter_stats stats; struct netxen_recv_context recv_ctx; - struct nx_host_tx_ring tx_ring; + struct nx_host_tx_ring *tx_ring; - /* Context interface shared between card and host */ - struct netxen_ring_ctx *ctx_desc; - dma_addr_t ctx_desc_phys_addr; int (*enable_phy_interrupts) (struct netxen_adapter *); int (*disable_phy_interrupts) (struct netxen_adapter *); int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index fd82adf..4754f5c 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -323,7 +323,8 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) int err = 0; u64 offset, phys_addr; dma_addr_t rq_phys_addr, rsp_phys_addr; - struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; + struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; rq_size = SIZEOF_HOSTRQ_TX(nx_hostrq_tx_ctx_t); rq_addr = pci_alloc_consistent(adapter->pdev, @@ -358,7 +359,7 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) prq->dummy_dma_addr = cpu_to_le64(adapter->dummy_dma.phys_addr); - offset = adapter->ctx_desc_phys_addr+sizeof(struct netxen_ring_ctx); + offset = recv_ctx->phys_addr + sizeof(struct netxen_ring_ctx); prq->cmd_cons_dma_addr = cpu_to_le64(offset); prq_cds = &prq->cds_ring; @@ -541,14 +542,16 @@ netxen_init_old_ctx(struct netxen_adapter *adapter) struct nx_host_tx_ring *tx_ring; int ring; int port = adapter->portnum; - struct netxen_ring_ctx *hwctx = adapter->ctx_desc; + struct netxen_ring_ctx *hwctx; u32 signature; - tx_ring = &adapter->tx_ring; + tx_ring = adapter->tx_ring; + recv_ctx = &adapter->recv_ctx; + hwctx = recv_ctx->hwctx; + hwctx->cmd_ring_addr = cpu_to_le64(tx_ring->phys_addr); hwctx->cmd_ring_size = cpu_to_le32(tx_ring->num_desc); - recv_ctx = &adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; @@ -576,9 +579,9 @@ netxen_init_old_ctx(struct netxen_adapter *adapter) NETXEN_CTX_SIGNATURE_V2 : NETXEN_CTX_SIGNATURE; NXWR32(adapter, CRB_CTX_ADDR_REG_LO(port), - lower32(adapter->ctx_desc_phys_addr)); + lower32(recv_ctx->phys_addr)); NXWR32(adapter, CRB_CTX_ADDR_REG_HI(port), - upper32(adapter->ctx_desc_phys_addr)); + upper32(recv_ctx->phys_addr)); NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port), signature | port); return 0; @@ -592,25 +595,28 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; - struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; + struct nx_host_tx_ring *tx_ring; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; int port = adapter->portnum; + recv_ctx = &adapter->recv_ctx; + tx_ring = adapter->tx_ring; + addr = pci_alloc_consistent(pdev, sizeof(struct netxen_ring_ctx) + sizeof(uint32_t), - &adapter->ctx_desc_phys_addr); - + &recv_ctx->phys_addr); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate hw context\n"); return -ENOMEM; } + memset(addr, 0, sizeof(struct netxen_ring_ctx)); - adapter->ctx_desc = (struct netxen_ring_ctx *)addr; - adapter->ctx_desc->ctx_id = cpu_to_le32(port); - adapter->ctx_desc->cmd_consumer_offset = - cpu_to_le64(adapter->ctx_desc_phys_addr + + recv_ctx->hwctx = (struct netxen_ring_ctx *)addr; + recv_ctx->hwctx->ctx_id = cpu_to_le32(port); + recv_ctx->hwctx->cmd_consumer_offset = + cpu_to_le64(recv_ctx->phys_addr + sizeof(struct netxen_ring_ctx)); tx_ring->hw_consumer = (__le32 *)(((char *)addr) + sizeof(struct netxen_ring_ctx)); @@ -627,8 +633,6 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) tx_ring->desc_head = (struct cmd_desc_type0 *)addr; - recv_ctx = &adapter->recv_ctx; - for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; addr = pci_alloc_consistent(adapter->pdev, @@ -713,16 +717,18 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) netxen_api_unlock(adapter); } - if (adapter->ctx_desc != NULL) { + recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->hwctx != NULL) { pci_free_consistent(adapter->pdev, sizeof(struct netxen_ring_ctx) + sizeof(uint32_t), - adapter->ctx_desc, - adapter->ctx_desc_phys_addr); - adapter->ctx_desc = NULL; + recv_ctx->hwctx, + recv_ctx->phys_addr); + recv_ctx->hwctx = NULL; } - tx_ring = &adapter->tx_ring; + tx_ring = adapter->tx_ring; if (tx_ring->desc_head != NULL) { pci_free_consistent(adapter->pdev, TX_DESC_RINGSIZE(tx_ring), @@ -730,7 +736,6 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) tx_ring->desc_head = NULL; } - recv_ctx = &adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 3bb2b8c..db53d9c 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -521,7 +521,7 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, i = 0; - tx_ring = &adapter->tx_ring; + tx_ring = adapter->tx_ring; netif_tx_lock_bh(adapter->netdev); producer = tx_ring->producer; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 8893a97..363ef70 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -137,7 +137,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) struct netxen_cmd_buffer *cmd_buf; struct netxen_skb_frag *buffrag; int i, j; - struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; cmd_buf = tx_ring->cmd_buf_arr; for (i = 0; i < tx_ring->num_desc; i++) { @@ -172,6 +172,10 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) int ring; recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->rds_rings == NULL) + goto skip_rds; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; if (rds_ring->rx_buf_arr) { @@ -179,11 +183,15 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) rds_ring->rx_buf_arr = NULL; } } + kfree(recv_ctx->rds_rings); + +skip_rds: + if (adapter->tx_ring == NULL) + return; - tx_ring = &adapter->tx_ring; + tx_ring = adapter->tx_ring; if (tx_ring->cmd_buf_arr) vfree(tx_ring->cmd_buf_arr); - return; } int netxen_alloc_sw_resources(struct netxen_adapter *adapter) @@ -191,17 +199,26 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; - struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; + struct nx_host_tx_ring *tx_ring; struct netxen_rx_buffer *rx_buf; - int ring, i, num_rx_bufs; + int ring, i, size; struct netxen_cmd_buffer *cmd_buf_arr; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; + size = sizeof(struct nx_host_tx_ring); + tx_ring = kzalloc(size, GFP_KERNEL); + if (tx_ring == NULL) { + dev_err(&pdev->dev, "%s: failed to allocate tx ring struct\n", + netdev->name); + return -ENOMEM; + } + adapter->tx_ring = tx_ring; + tx_ring->num_desc = adapter->num_txd; - cmd_buf_arr = - (struct netxen_cmd_buffer *)vmalloc(TX_BUFF_RINGSIZE(tx_ring)); + + cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring)); if (cmd_buf_arr == NULL) { dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n", netdev->name); @@ -211,6 +228,16 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) tx_ring->cmd_buf_arr = cmd_buf_arr; recv_ctx = &adapter->recv_ctx; + + size = adapter->max_rds_rings * sizeof (struct nx_host_rds_ring); + rds_ring = kzalloc(size, GFP_KERNEL); + if (rds_ring == NULL) { + dev_err(&pdev->dev, "%s: failed to allocate rds ring struct\n", + netdev->name); + return -ENOMEM; + } + recv_ctx->rds_rings = rds_ring; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; switch (ring) { @@ -262,9 +289,8 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) * Now go through all of them, set reference handles * and put them in the queues. */ - num_rx_bufs = rds_ring->num_desc; rx_buf = rds_ring->rx_buf_arr; - for (i = 0; i < num_rx_bufs; i++) { + for (i = 0; i < rds_ring->num_desc; i++) { list_add_tail(&rx_buf->list, &rds_ring->free_list); rx_buf->ref_handle = i; @@ -1064,7 +1090,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) struct net_device *netdev = adapter->netdev; struct netxen_skb_frag *frag; int done = 0; - struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; if (!spin_trylock(&adapter->tx_clean_lock)) return 1; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 8331580..07959fe 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -857,7 +857,7 @@ netxen_nic_attach(struct netxen_adapter *adapter) } if (adapter->fw_major < 4) { - tx_ring = &adapter->tx_ring; + tx_ring = adapter->tx_ring; tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum]; tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum]; @@ -1315,7 +1315,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); - struct nx_host_tx_ring *tx_ring = &adapter->tx_ring; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; unsigned int first_seg_len = skb->len - skb->data_len; struct netxen_cmd_buffer *pbuf; struct netxen_skb_frag *buffrag; -- cgit v0.10.2 From f7185c71234434d48b96f9a0387737df1759a4af Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 28 Apr 2009 15:29:11 +0000 Subject: netxen: fix firmware download o hold the firmware in memory across suspend, since filesystem may not be up after resuming. o reset the chip after requesting firmware, to minimize downtime for NC-SI. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 16f5e22..8dacfbb 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -1255,8 +1256,6 @@ struct netxen_adapter { u32 flags; u32 irq; u32 temp; - u32 fw_major; - u32 fw_version; struct netxen_adapter_stats stats; @@ -1295,6 +1294,10 @@ struct netxen_adapter { struct net_device_stats net_stats; nx_nic_intr_coalesce_t coal; + + u32 fw_major; + u32 fw_version; + const struct firmware *fw; }; /* @@ -1376,6 +1379,8 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter); int netxen_initialize_adapter_offload(struct netxen_adapter *adapter); int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); int netxen_load_firmware(struct netxen_adapter *adapter); +void netxen_request_firmware(struct netxen_adapter *adapter); +void netxen_release_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index db53d9c..9f5ced3 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -32,7 +32,6 @@ #include "netxen_nic_hw.h" #include "netxen_nic_phan_reg.h" -#include #include #define MASK(n) ((1ULL<<(n))-1) @@ -1016,200 +1015,6 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off) (ulong)adapter->ahw.pci_base0; } -static int -netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname, - const struct firmware *fw) -{ - u64 *ptr64; - u32 i, flashaddr, size; - struct pci_dev *pdev = adapter->pdev; - - if (fw) - dev_info(&pdev->dev, "loading firmware from file %s\n", fwname); - else - dev_info(&pdev->dev, "loading firmware from flash\n"); - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1); - - if (fw) { - __le64 data; - - size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8; - - ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START]; - flashaddr = NETXEN_BOOTLD_START; - - for (i = 0; i < size; i++) { - data = cpu_to_le64(ptr64[i]); - adapter->pci_mem_write(adapter, flashaddr, &data, 8); - flashaddr += 8; - } - - size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET]; - size = (__force u32)cpu_to_le32(size) / 8; - - ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START]; - flashaddr = NETXEN_IMAGE_START; - - for (i = 0; i < size; i++) { - data = cpu_to_le64(ptr64[i]); - - if (adapter->pci_mem_write(adapter, - flashaddr, &data, 8)) - return -EIO; - - flashaddr += 8; - } - } else { - u32 data; - - size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4; - flashaddr = NETXEN_BOOTLD_START; - - for (i = 0; i < size; i++) { - if (netxen_rom_fast_read(adapter, - flashaddr, (int *)&data) != 0) - return -EIO; - - if (adapter->pci_mem_write(adapter, - flashaddr, &data, 4)) - return -EIO; - - flashaddr += 4; - } - } - msleep(1); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d); - else { - NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff); - NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0); - } - - return 0; -} - -static int -netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname, - const struct firmware *fw) -{ - __le32 val; - u32 major, minor, build, ver, min_ver, bios; - struct pci_dev *pdev = adapter->pdev; - - if (fw->size < NX_FW_MIN_SIZE) - return -EINVAL; - - val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); - if ((__force u32)val != NETXEN_BDINFO_MAGIC) - return -EINVAL; - - val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]); - major = (__force u32)val & 0xff; - minor = ((__force u32)val >> 8) & 0xff; - build = (__force u32)val >> 16; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - min_ver = NETXEN_VERSION_CODE(4, 0, 216); - else - min_ver = NETXEN_VERSION_CODE(3, 4, 216); - - ver = NETXEN_VERSION_CODE(major, minor, build); - - if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) { - dev_err(&pdev->dev, - "%s: firmware version %d.%d.%d unsupported\n", - fwname, major, minor, build); - return -EINVAL; - } - - val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); - netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios); - if ((__force u32)val != bios) { - dev_err(&pdev->dev, "%s: firmware bios is incompatible\n", - fwname); - return -EINVAL; - } - - /* check if flashed firmware is newer */ - if (netxen_rom_fast_read(adapter, - NX_FW_VERSION_OFFSET, (int *)&val)) - return -EIO; - major = (__force u32)val & 0xff; - minor = ((__force u32)val >> 8) & 0xff; - build = (__force u32)val >> 16; - if (NETXEN_VERSION_CODE(major, minor, build) > ver) - return -EINVAL; - - NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); - return 0; -} - -static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" }; - -int netxen_load_firmware(struct netxen_adapter *adapter) -{ - u32 capability, flashed_ver; - const struct firmware *fw; - int fw_type; - struct pci_dev *pdev = adapter->pdev; - int rc = 0; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - fw_type = NX_P2_MN_ROMIMAGE; - goto request_fw; - } else { - fw_type = NX_P3_CT_ROMIMAGE; - goto request_fw; - } - -request_mn: - capability = 0; - - netxen_rom_fast_read(adapter, - NX_FW_VERSION_OFFSET, (int *)&flashed_ver); - if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { - capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); - if (capability & NX_PEG_TUNE_MN_PRESENT) { - fw_type = NX_P3_MN_ROMIMAGE; - goto request_fw; - } - } - -request_fw: - rc = request_firmware(&fw, fw_name[fw_type], &pdev->dev); - if (rc != 0) { - if (fw_type == NX_P3_CT_ROMIMAGE) { - msleep(1); - goto request_mn; - } - - fw = NULL; - goto load_fw; - } - - rc = netxen_validate_firmware(adapter, fw_name[fw_type], fw); - if (rc != 0) { - release_firmware(fw); - - if (fw_type == NX_P3_CT_ROMIMAGE) { - msleep(1); - goto request_mn; - } - - fw = NULL; - } - -load_fw: - rc = netxen_do_load_firmware(adapter, fw_name[fw_type], fw); - - if (fw) - release_firmware(fw); - return rc; -} - int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data) { diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 363ef70..d182167 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -683,6 +683,202 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) return 0; } +int +netxen_load_firmware(struct netxen_adapter *adapter) +{ + u64 *ptr64; + u32 i, flashaddr, size; + const struct firmware *fw = adapter->fw; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1); + + if (fw) { + __le64 data; + + size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8; + + ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START]; + flashaddr = NETXEN_BOOTLD_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + adapter->pci_mem_write(adapter, flashaddr, &data, 8); + flashaddr += 8; + } + + size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET]; + size = (__force u32)cpu_to_le32(size) / 8; + + ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START]; + flashaddr = NETXEN_IMAGE_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + + if (adapter->pci_mem_write(adapter, + flashaddr, &data, 8)) + return -EIO; + + flashaddr += 8; + } + } else { + u32 data; + + size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4; + flashaddr = NETXEN_BOOTLD_START; + + for (i = 0; i < size; i++) { + if (netxen_rom_fast_read(adapter, + flashaddr, (int *)&data) != 0) + return -EIO; + + if (adapter->pci_mem_write(adapter, + flashaddr, &data, 4)) + return -EIO; + + flashaddr += 4; + } + } + msleep(1); + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d); + else { + NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff); + NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0); + } + + return 0; +} + +static int +netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) +{ + __le32 val; + u32 major, minor, build, ver, min_ver, bios; + struct pci_dev *pdev = adapter->pdev; + const struct firmware *fw = adapter->fw; + + if (fw->size < NX_FW_MIN_SIZE) + return -EINVAL; + + val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); + if ((__force u32)val != NETXEN_BDINFO_MAGIC) + return -EINVAL; + + val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]); + major = (__force u32)val & 0xff; + minor = ((__force u32)val >> 8) & 0xff; + build = (__force u32)val >> 16; + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + min_ver = NETXEN_VERSION_CODE(4, 0, 216); + else + min_ver = NETXEN_VERSION_CODE(3, 4, 216); + + ver = NETXEN_VERSION_CODE(major, minor, build); + + if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) { + dev_err(&pdev->dev, + "%s: firmware version %d.%d.%d unsupported\n", + fwname, major, minor, build); + return -EINVAL; + } + + val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); + netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios); + if ((__force u32)val != bios) { + dev_err(&pdev->dev, "%s: firmware bios is incompatible\n", + fwname); + return -EINVAL; + } + + /* check if flashed firmware is newer */ + if (netxen_rom_fast_read(adapter, + NX_FW_VERSION_OFFSET, (int *)&val)) + return -EIO; + major = (__force u32)val & 0xff; + minor = ((__force u32)val >> 8) & 0xff; + build = (__force u32)val >> 16; + if (NETXEN_VERSION_CODE(major, minor, build) > ver) + return -EINVAL; + + NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); + return 0; +} + +static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" }; + +void netxen_request_firmware(struct netxen_adapter *adapter) +{ + u32 capability, flashed_ver; + int fw_type; + struct pci_dev *pdev = adapter->pdev; + int rc = 0; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + fw_type = NX_P2_MN_ROMIMAGE; + goto request_fw; + } else { + fw_type = NX_P3_CT_ROMIMAGE; + goto request_fw; + } + +request_mn: + capability = 0; + + netxen_rom_fast_read(adapter, + NX_FW_VERSION_OFFSET, (int *)&flashed_ver); + if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { + capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); + if (capability & NX_PEG_TUNE_MN_PRESENT) { + fw_type = NX_P3_MN_ROMIMAGE; + goto request_fw; + } + } + +request_fw: + rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev); + if (rc != 0) { + if (fw_type == NX_P3_CT_ROMIMAGE) { + msleep(1); + goto request_mn; + } + + adapter->fw = NULL; + goto done; + } + + rc = netxen_validate_firmware(adapter, fw_name[fw_type]); + if (rc != 0) { + release_firmware(adapter->fw); + + if (fw_type == NX_P3_CT_ROMIMAGE) { + msleep(1); + goto request_mn; + } + + adapter->fw = NULL; + goto done; + } + +done: + if (adapter->fw) + dev_info(&pdev->dev, "loading firmware from file %s\n", + fw_name[fw_type]); + else + dev_info(&pdev->dev, "loading firmware from flash\n"); +} + + +void +netxen_release_firmware(struct netxen_adapter *adapter) +{ + if (adapter->fw) + release_firmware(adapter->fw); +} + int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) { uint64_t addr; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 07959fe..5d79c19 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -654,19 +654,17 @@ err_out: } static int -netxen_start_firmware(struct netxen_adapter *adapter) +netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) { int val, err, first_boot; struct pci_dev *pdev = adapter->pdev; int first_driver = 0; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - if (adapter->ahw.pci_func == 0) - first_driver = 1; - } else { - if (adapter->portnum == 0) - first_driver = 1; - } + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + first_driver = (adapter->portnum == 0); + else + first_driver = (adapter->ahw.pci_func == 0); if (!first_driver) return 0; @@ -679,6 +677,9 @@ netxen_start_firmware(struct netxen_adapter *adapter) return err; } + if (request_fw) + netxen_request_firmware(adapter); + if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); netxen_pinit_from_rom(adapter, 0); @@ -1014,7 +1015,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } - err = netxen_start_firmware(adapter); + err = netxen_start_firmware(adapter, 1); if (err) goto err_out_iounmap; @@ -1125,6 +1126,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netxen_cleanup_pci_map(adapter); + netxen_release_firmware(adapter); + pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -1176,7 +1179,7 @@ netxen_nic_resume(struct pci_dev *pdev) adapter->curr_window = 255; - err = netxen_start_firmware(adapter); + err = netxen_start_firmware(adapter, 0); if (err) { dev_err(&pdev->dev, "failed to start firmware\n"); return err; -- cgit v0.10.2 From dd4d8ca6446538a904127838cb6c9a4cffe690f7 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 29 Apr 2009 00:22:31 -0700 Subject: ixgbe: Use pci_wake_from_d3() instead of multiple pci_enable_wake() We were calling pci_enable_wake() twice in a row for both D3_hot and D3_cold. This replaces those calls with a call to pci_wake_from_d3() to avoid issues with PCI PM vs ordering constraints. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 5020f11..01a8826 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3738,8 +3738,7 @@ static int ixgbe_resume(struct pci_dev *pdev) } pci_set_master(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_wake_from_d3(pdev, false); err = ixgbe_init_interrupt_scheme(adapter); if (err) { @@ -3813,13 +3812,10 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); } - if (wufc && hw->mac.type == ixgbe_mac_82599EB) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } else { - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - } + if (wufc && hw->mac.type == ixgbe_mac_82599EB) + pci_wake_from_d3(pdev, true); + else + pci_wake_from_d3(pdev, false); *enable_wake = !!wufc; @@ -5101,8 +5097,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_wake_from_d3(pdev, false); ixgbe_reset(adapter); IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0); -- cgit v0.10.2 From ce105a082371570effb71541f299b1dc2771ee03 Mon Sep 17 00:00:00 2001 From: John Dykstra Date: Wed, 29 Apr 2009 17:22:30 -0700 Subject: pcnet32: Remove pointless memory barriers These two memory barriers in performance-critical paths are not needed on x86. Even if some other architecture does buffer PCI I/O space writes, the existing memory-mapped I/O barriers are unlikely to be what is needed. Signed-off-by: John Dykstra Acked-by: Don Fry Signed-off-by: David S. Miller diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index e5e8c59..1c35e1d 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1405,7 +1405,7 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) /* Set interrupt enable. */ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN); - mmiowb(); + spin_unlock_irqrestore(&lp->lock, flags); } return work_done; @@ -2597,7 +2597,7 @@ pcnet32_interrupt(int irq, void *dev_id) val = lp->a.read_csr(ioaddr, CSR3); val |= 0x5f00; lp->a.write_csr(ioaddr, CSR3, val); - mmiowb(); + __napi_schedule(&lp->napi); break; } -- cgit v0.10.2 From 0821c71751ef88f4251d7206e76ce497ee267a2d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:02:59 +0000 Subject: ethtool: Add port type PORT_OTHER Add a PORT_OTHER to represent all other physical port types. Current NICs generally do not allow switching between multiple port types in software so specific types should not be needed. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 131b127..5ccb6bd 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -605,6 +605,7 @@ struct ethtool_ops { #define PORT_MII 0x02 #define PORT_FIBRE 0x03 #define PORT_BNC 0x04 +#define PORT_OTHER 0xff /* Which transceiver to use. */ #define XCVR_INTERNAL 0x00 -- cgit v0.10.2 From 52c94dfae11d9ffd70b7bd003a36a4e210f2866a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:04:14 +0000 Subject: mdio: Add register definitions for MDIO (clause 45) IEEE 802.3 clause 45 specifies the MDIO interface and registers for use in 10G and other PHYs, similar to the MII management interface. PHYs may have up to 32 MMDs corresponding to different sub-layers and functions, each with up to 65536 registers. These are addressed by PRTAD (similar to the MII PHY address) and DEVAD. Define a mapping for specifying PRTAD and DEVAD through the existing MII ioctls. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/mdio.h b/include/linux/mdio.h new file mode 100644 index 0000000..d57ddb0 --- /dev/null +++ b/include/linux/mdio.h @@ -0,0 +1,237 @@ +/* + * linux/mdio.h: definitions for MDIO (clause 45) transceivers + * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef __LINUX_MDIO_H__ +#define __LINUX_MDIO_H__ + +#include + +/* MDIO Manageable Devices (MMDs). */ +#define MDIO_MMD_PMAPMD 1 /* Physical Medium Attachment/ + * Physical Medium Dependent */ +#define MDIO_MMD_WIS 2 /* WAN Interface Sublayer */ +#define MDIO_MMD_PCS 3 /* Physical Coding Sublayer */ +#define MDIO_MMD_PHYXS 4 /* PHY Extender Sublayer */ +#define MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */ +#define MDIO_MMD_TC 6 /* Transmission Convergence */ +#define MDIO_MMD_AN 7 /* Auto-Negotiation */ +#define MDIO_MMD_C22EXT 29 /* Clause 22 extension */ +#define MDIO_MMD_VEND1 30 /* Vendor specific 1 */ +#define MDIO_MMD_VEND2 31 /* Vendor specific 2 */ + +/* Generic MDIO registers. */ +#define MDIO_CTRL1 MII_BMCR +#define MDIO_STAT1 MII_BMSR +#define MDIO_DEVID1 MII_PHYSID1 +#define MDIO_DEVID2 MII_PHYSID2 +#define MDIO_SPEED 4 /* Speed ability */ +#define MDIO_DEVS1 5 /* Devices in package */ +#define MDIO_DEVS2 6 +#define MDIO_CTRL2 7 /* 10G control 2 */ +#define MDIO_STAT2 8 /* 10G status 2 */ +#define MDIO_PMA_TXDIS 9 /* 10G PMA/PMD transmit disable */ +#define MDIO_PMA_RXDET 10 /* 10G PMA/PMD receive signal detect */ +#define MDIO_PMA_EXTABLE 11 /* 10G PMA/PMD extended ability */ +#define MDIO_PKGID1 14 /* Package identifier */ +#define MDIO_PKGID2 15 +#define MDIO_AN_ADVERTISE 16 /* AN advertising (base page) */ +#define MDIO_AN_LPA 19 /* AN LP abilities (base page) */ +#define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */ + +/* Media-dependent registers. */ +#define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ +#define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */ +#define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */ +#define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */ +#define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */ +#define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */ + +/* Control register 1. */ +/* Enable extended speed selection */ +#define MDIO_CTRL1_SPEEDSELEXT (BMCR_SPEED1000 | BMCR_SPEED100) +/* All speed selection bits */ +#define MDIO_CTRL1_SPEEDSEL (MDIO_CTRL1_SPEEDSELEXT | 0x003c) +#define MDIO_CTRL1_FULLDPLX BMCR_FULLDPLX +#define MDIO_CTRL1_LPOWER BMCR_PDOWN +#define MDIO_CTRL1_RESET BMCR_RESET +#define MDIO_PMA_CTRL1_LOOPBACK 0x0001 +#define MDIO_PMA_CTRL1_SPEED1000 BMCR_SPEED1000 +#define MDIO_PMA_CTRL1_SPEED100 BMCR_SPEED100 +#define MDIO_PCS_CTRL1_LOOPBACK BMCR_LOOPBACK +#define MDIO_PHYXS_CTRL1_LOOPBACK BMCR_LOOPBACK +#define MDIO_AN_CTRL1_RESTART BMCR_ANRESTART +#define MDIO_AN_CTRL1_ENABLE BMCR_ANENABLE +#define MDIO_AN_CTRL1_XNP 0x2000 /* Enable extended next page */ + +/* 10 Gb/s */ +#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) +/* 10PASS-TS/2BASE-TL */ +#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04) + +/* Status register 1. */ +#define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */ +#define MDIO_STAT1_LSTATUS BMSR_LSTATUS +#define MDIO_STAT1_FAULT 0x0080 /* Fault */ +#define MDIO_AN_STAT1_LPABLE 0x0001 /* Link partner AN ability */ +#define MDIO_AN_STAT1_ABLE BMSR_ANEGCAPABLE +#define MDIO_AN_STAT1_RFAULT BMSR_RFAULT +#define MDIO_AN_STAT1_COMPLETE BMSR_ANEGCOMPLETE +#define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */ +#define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */ + +/* Speed register. */ +#define MDIO_SPEED_10G 0x0001 /* 10G capable */ +#define MDIO_PMA_SPEED_2B 0x0002 /* 2BASE-TL capable */ +#define MDIO_PMA_SPEED_10P 0x0004 /* 10PASS-TS capable */ +#define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */ +#define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */ +#define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */ +#define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */ + +/* Device present registers. */ +#define MDIO_DEVS_PRESENT(devad) (1 << (devad)) +#define MDIO_DEVS_PMAPMD MDIO_DEVS_PRESENT(MDIO_MMD_PMAPMD) +#define MDIO_DEVS_WIS MDIO_DEVS_PRESENT(MDIO_MMD_WIS) +#define MDIO_DEVS_PCS MDIO_DEVS_PRESENT(MDIO_MMD_PCS) +#define MDIO_DEVS_PHYXS MDIO_DEVS_PRESENT(MDIO_MMD_PHYXS) +#define MDIO_DEVS_DTEXS MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS) +#define MDIO_DEVS_TC MDIO_DEVS_PRESENT(MDIO_MMD_TC) +#define MDIO_DEVS_AN MDIO_DEVS_PRESENT(MDIO_MMD_AN) +#define MDIO_DEVS_C22EXT MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT) + +/* Control register 2. */ +#define MDIO_PMA_CTRL2_TYPE 0x000f /* PMA/PMD type selection */ +#define MDIO_PMA_CTRL2_10GBCX4 0x0000 /* 10GBASE-CX4 type */ +#define MDIO_PMA_CTRL2_10GBEW 0x0001 /* 10GBASE-EW type */ +#define MDIO_PMA_CTRL2_10GBLW 0x0002 /* 10GBASE-LW type */ +#define MDIO_PMA_CTRL2_10GBSW 0x0003 /* 10GBASE-SW type */ +#define MDIO_PMA_CTRL2_10GBLX4 0x0004 /* 10GBASE-LX4 type */ +#define MDIO_PMA_CTRL2_10GBER 0x0005 /* 10GBASE-ER type */ +#define MDIO_PMA_CTRL2_10GBLR 0x0006 /* 10GBASE-LR type */ +#define MDIO_PMA_CTRL2_10GBSR 0x0007 /* 10GBASE-SR type */ +#define MDIO_PMA_CTRL2_10GBLRM 0x0008 /* 10GBASE-LRM type */ +#define MDIO_PMA_CTRL2_10GBT 0x0009 /* 10GBASE-T type */ +#define MDIO_PMA_CTRL2_10GBKX4 0x000a /* 10GBASE-KX4 type */ +#define MDIO_PMA_CTRL2_10GBKR 0x000b /* 10GBASE-KR type */ +#define MDIO_PMA_CTRL2_1000BT 0x000c /* 1000BASE-T type */ +#define MDIO_PMA_CTRL2_1000BKX 0x000d /* 1000BASE-KX type */ +#define MDIO_PMA_CTRL2_100BTX 0x000e /* 100BASE-TX type */ +#define MDIO_PMA_CTRL2_10BT 0x000f /* 10BASE-T type */ +#define MDIO_PCS_CTRL2_TYPE 0x0003 /* PCS type selection */ +#define MDIO_PCS_CTRL2_10GBR 0x0000 /* 10GBASE-R type */ +#define MDIO_PCS_CTRL2_10GBX 0x0001 /* 10GBASE-X type */ +#define MDIO_PCS_CTRL2_10GBW 0x0002 /* 10GBASE-W type */ +#define MDIO_PCS_CTRL2_10GBT 0x0003 /* 10GBASE-T type */ + +/* Status register 2. */ +#define MDIO_STAT2_RXFAULT 0x0400 /* Receive fault */ +#define MDIO_STAT2_TXFAULT 0x0800 /* Transmit fault */ +#define MDIO_STAT2_DEVPRST 0xc000 /* Device present */ +#define MDIO_STAT2_DEVPRST_VAL 0x8000 /* Device present value */ +#define MDIO_PMA_STAT2_LBABLE 0x0001 /* PMA loopback ability */ +#define MDIO_PMA_STAT2_10GBEW 0x0002 /* 10GBASE-EW ability */ +#define MDIO_PMA_STAT2_10GBLW 0x0004 /* 10GBASE-LW ability */ +#define MDIO_PMA_STAT2_10GBSW 0x0008 /* 10GBASE-SW ability */ +#define MDIO_PMA_STAT2_10GBLX4 0x0010 /* 10GBASE-LX4 ability */ +#define MDIO_PMA_STAT2_10GBER 0x0020 /* 10GBASE-ER ability */ +#define MDIO_PMA_STAT2_10GBLR 0x0040 /* 10GBASE-LR ability */ +#define MDIO_PMA_STAT2_10GBSR 0x0080 /* 10GBASE-SR ability */ +#define MDIO_PMD_STAT2_TXDISAB 0x0100 /* PMD TX disable ability */ +#define MDIO_PMA_STAT2_EXTABLE 0x0200 /* Extended abilities */ +#define MDIO_PMA_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */ +#define MDIO_PMA_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */ +#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R capable */ +#define MDIO_PCS_STAT2_10GBX 0x0002 /* 10GBASE-X capable */ +#define MDIO_PCS_STAT2_10GBW 0x0004 /* 10GBASE-W capable */ +#define MDIO_PCS_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */ +#define MDIO_PCS_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */ + +/* Transmit disable register. */ +#define MDIO_PMD_TXDIS_GLOBAL 0x0001 /* Global PMD TX disable */ +#define MDIO_PMD_TXDIS_0 0x0002 /* PMD TX disable 0 */ +#define MDIO_PMD_TXDIS_1 0x0004 /* PMD TX disable 1 */ +#define MDIO_PMD_TXDIS_2 0x0008 /* PMD TX disable 2 */ +#define MDIO_PMD_TXDIS_3 0x0010 /* PMD TX disable 3 */ + +/* Receive signal detect register. */ +#define MDIO_PMD_RXDET_GLOBAL 0x0001 /* Global PMD RX signal detect */ +#define MDIO_PMD_RXDET_0 0x0002 /* PMD RX signal detect 0 */ +#define MDIO_PMD_RXDET_1 0x0004 /* PMD RX signal detect 1 */ +#define MDIO_PMD_RXDET_2 0x0008 /* PMD RX signal detect 2 */ +#define MDIO_PMD_RXDET_3 0x0010 /* PMD RX signal detect 3 */ + +/* Extended abilities register. */ +#define MDIO_PMA_EXTABLE_10GCX4 0x0001 /* 10GBASE-CX4 ability */ +#define MDIO_PMA_EXTABLE_10GBLRM 0x0002 /* 10GBASE-LRM ability */ +#define MDIO_PMA_EXTABLE_10GBT 0x0004 /* 10GBASE-T ability */ +#define MDIO_PMA_EXTABLE_10GBKX4 0x0008 /* 10GBASE-KX4 ability */ +#define MDIO_PMA_EXTABLE_10GBKR 0x0010 /* 10GBASE-KR ability */ +#define MDIO_PMA_EXTABLE_1000BT 0x0020 /* 1000BASE-T ability */ +#define MDIO_PMA_EXTABLE_1000BKX 0x0040 /* 1000BASE-KX ability */ +#define MDIO_PMA_EXTABLE_100BTX 0x0080 /* 100BASE-TX ability */ +#define MDIO_PMA_EXTABLE_10BT 0x0100 /* 10BASE-T ability */ + +/* PHY XGXS lane state register. */ +#define MDIO_PHYXS_LNSTAT_SYNC0 0x0001 +#define MDIO_PHYXS_LNSTAT_SYNC1 0x0002 +#define MDIO_PHYXS_LNSTAT_SYNC2 0x0004 +#define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 +#define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 + +/* PMA 10GBASE-T TX power register. */ +#define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */ + +/* PCS 10GBASE-R/-T status register 1. */ +#define MDIO_PCS_10GBRT_STAT1_BLKLK 0x0001 /* Block lock attained */ + +/* PCS 10GBASE-R/-T status register 2. */ +#define MDIO_PCS_10GBRT_STAT2_ERR 0x00ff +#define MDIO_PCS_10GBRT_STAT2_BER 0x3f00 + +/* AN 10GBASE-T control register. */ +#define MDIO_AN_10GBT_CTRL_ADV10G 0x1000 /* Advertise 10GBASE-T */ + +/* AN 10GBASE-T status register. */ +#define MDIO_AN_10GBT_STAT_LPTRR 0x0200 /* LP training reset req. */ +#define MDIO_AN_10GBT_STAT_LPLTABLE 0x0400 /* LP loop timing ability */ +#define MDIO_AN_10GBT_STAT_LP10G 0x0800 /* LP is 10GBT capable */ +#define MDIO_AN_10GBT_STAT_REMOK 0x1000 /* Remote OK */ +#define MDIO_AN_10GBT_STAT_LOCOK 0x2000 /* Local OK */ +#define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */ +#define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */ + +/* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */ + +#define MDIO_PHY_ID_C45 0x8000 +#define MDIO_PHY_ID_PRTAD 0x03e0 +#define MDIO_PHY_ID_DEVAD 0x001f +#define MDIO_PHY_ID_C45_MASK \ + (MDIO_PHY_ID_C45 | MDIO_PHY_ID_PRTAD | MDIO_PHY_ID_DEVAD) + +static inline __u16 mdio_phy_id_c45(int prtad, int devad) +{ + return MDIO_PHY_ID_C45 | (prtad << 5) | devad; +} + +static inline bool mdio_phy_id_is_c45(int phy_id) +{ + return (phy_id & MDIO_PHY_ID_C45) && !(phy_id & ~MDIO_PHY_ID_C45_MASK); +} + +static inline __u16 mdio_phy_id_prtad(int phy_id) +{ + return (phy_id & MDIO_PHY_ID_PRTAD) >> 5; +} + +static inline __u16 mdio_phy_id_devad(int phy_id) +{ + return phy_id & MDIO_PHY_ID_DEVAD; +} + +#endif /* __LINUX_MDIO_H__ */ -- cgit v0.10.2 From 1b1c2e95103ce391c2ea39a9460968fcb73deb30 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:04:46 +0000 Subject: mdio: Add generic MDIO (clause 45) support functions These roughly mirror many of the MII library functions and are based on code from the sfc driver. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bc7eef1..2f81db5 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2443,6 +2443,9 @@ menuconfig NETDEV_10000 if NETDEV_10000 +config MDIO + tristate + config CHELSIO_T1 tristate "Chelsio 10Gb Ethernet support" depends on PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 80420f6..dcd5f15 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_SH_ETH) += sh_eth.o # obj-$(CONFIG_MII) += mii.o +obj-$(CONFIG_MDIO) += mdio.o obj-$(CONFIG_PHYLIB) += phy/ obj-$(CONFIG_SUNDANCE) += sundance.o diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c new file mode 100644 index 0000000..0604a25 --- /dev/null +++ b/drivers/net/mdio.c @@ -0,0 +1,359 @@ +/* + * mdio.c: Generic support for MDIO-compatible transceivers + * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include +#include +#include +#include +#include +#include + +/** + * mdio45_probe - probe for an MDIO (clause 45) device + * @mdio: MDIO interface + * @prtad: Expected PHY address + * + * This sets @prtad and @mmds in the MDIO interface if successful. + * Returns 0 on success, negative on error. + */ +int mdio45_probe(struct mdio_if_info *mdio, int prtad) +{ + int mmd, stat2, devs1, devs2; + + /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY + * XS or DTE XS; give up if none is present. */ + for (mmd = 1; mmd <= 5; mmd++) { + /* Is this MMD present? */ + stat2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_STAT2); + if (stat2 < 0 || + (stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) + continue; + + /* It should tell us about all the other MMDs */ + devs1 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS1); + devs2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS2); + if (devs1 < 0 || devs2 < 0) + continue; + + mdio->prtad = prtad; + mdio->mmds = devs1 | (devs2 << 16); + return 0; + } + + return -ENODEV; +} +EXPORT_SYMBOL(mdio45_probe); + +/** + * mdio_set_flag - set or clear flag in an MDIO register + * @mdio: MDIO interface + * @prtad: PHY address + * @devad: MMD address + * @addr: Register address + * @mask: Mask for flag (single bit set) + * @sense: New value of flag + * + * This debounces changes: it does not write the register if the flag + * already has the proper value. Returns 0 on success, negative on error. + */ +int mdio_set_flag(const struct mdio_if_info *mdio, + int prtad, int devad, u16 addr, int mask, + bool sense) +{ + int old_val = mdio->mdio_read(mdio->dev, prtad, devad, addr); + int new_val; + + if (old_val < 0) + return old_val; + if (sense) + new_val = old_val | mask; + else + new_val = old_val & ~mask; + if (old_val == new_val) + return 0; + return mdio->mdio_write(mdio->dev, prtad, devad, addr, new_val); +} +EXPORT_SYMBOL(mdio_set_flag); + +/** + * mdio_link_ok - is link status up/OK + * @mdio: MDIO interface + * @mmd_mask: Mask for MMDs to check + * + * Returns 1 if the PHY reports link status up/OK, 0 otherwise. + * @mmd_mask is normally @mdio->mmds, but if loopback is enabled + * the MMDs being bypassed should be excluded from the mask. + */ +int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmd_mask) +{ + int devad, reg; + + if (!mmd_mask) { + /* Use absence of XGMII faults in lieu of link state */ + reg = mdio->mdio_read(mdio->dev, mdio->prtad, + MDIO_MMD_PHYXS, MDIO_STAT2); + return reg >= 0 && !(reg & MDIO_STAT2_RXFAULT); + } + + for (devad = 0; mmd_mask; devad++) { + if (mmd_mask & (1 << devad)) { + mmd_mask &= ~(1 << devad); + + /* Read twice because link state is latched and a + * read moves the current state into the register */ + mdio->mdio_read(mdio->dev, mdio->prtad, + devad, MDIO_STAT1); + reg = mdio->mdio_read(mdio->dev, mdio->prtad, + devad, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + return false; + } + } + + return true; +} +EXPORT_SYMBOL(mdio45_links_ok); + +/** + * mdio45_nway_restart - restart auto-negotiation for this interface + * @mdio: MDIO interface + * + * Returns 0 on success, negative on error. + */ +int mdio45_nway_restart(const struct mdio_if_info *mdio) +{ + if (!(mdio->mmds & MDIO_DEVS_AN)) + return -EOPNOTSUPP; + + mdio_set_flag(mdio, mdio->prtad, MDIO_MMD_AN, MDIO_CTRL1, + MDIO_AN_CTRL1_RESTART, true); + return 0; +} +EXPORT_SYMBOL(mdio45_nway_restart); + +static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr) +{ + u32 result = 0; + int reg; + + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, addr); + if (reg & ADVERTISE_10HALF) + result |= ADVERTISED_10baseT_Half; + if (reg & ADVERTISE_10FULL) + result |= ADVERTISED_10baseT_Full; + if (reg & ADVERTISE_100HALF) + result |= ADVERTISED_100baseT_Half; + if (reg & ADVERTISE_100FULL) + result |= ADVERTISED_100baseT_Full; + return result; +} + +/** + * mdio45_ethtool_gset_npage - get settings for ETHTOOL_GSET + * @mdio: MDIO interface + * @ecmd: Ethtool request structure + * @npage_adv: Modes currently advertised on next pages + * @npage_lpa: Modes advertised by link partner on next pages + * + * Since the CSRs for auto-negotiation using next pages are not fully + * standardised, this function does not attempt to decode them. The + * caller must pass them in. + */ +void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, + struct ethtool_cmd *ecmd, + u32 npage_adv, u32 npage_lpa) +{ + int reg; + + ecmd->transceiver = XCVR_INTERNAL; + ecmd->phy_address = mdio->prtad; + + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL2); + switch (reg & MDIO_PMA_CTRL2_TYPE) { + case MDIO_PMA_CTRL2_10GBT: + case MDIO_PMA_CTRL2_1000BT: + case MDIO_PMA_CTRL2_100BTX: + case MDIO_PMA_CTRL2_10BT: + ecmd->port = PORT_TP; + ecmd->supported = SUPPORTED_TP; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_SPEED); + if (reg & MDIO_SPEED_10G) + ecmd->supported |= SUPPORTED_10000baseT_Full; + if (reg & MDIO_PMA_SPEED_1000) + ecmd->supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_1000baseT_Half); + if (reg & MDIO_PMA_SPEED_100) + ecmd->supported |= (SUPPORTED_100baseT_Full | + SUPPORTED_100baseT_Half); + if (reg & MDIO_PMA_SPEED_10) + ecmd->supported |= (SUPPORTED_10baseT_Full | + SUPPORTED_10baseT_Half); + ecmd->advertising = ADVERTISED_TP; + break; + + case MDIO_PMA_CTRL2_10GBCX4: + case MDIO_PMA_CTRL2_10GBKX4: + case MDIO_PMA_CTRL2_10GBKR: + case MDIO_PMA_CTRL2_1000BKX: + ecmd->port = PORT_OTHER; + ecmd->supported = 0; + ecmd->advertising = 0; + break; + + /* All the other defined modes are flavours of optical */ + default: + ecmd->port = PORT_FIBRE; + ecmd->supported = SUPPORTED_FIBRE; + ecmd->advertising = ADVERTISED_FIBRE; + break; + } + + if (mdio->mmds & MDIO_DEVS_AN) { + ecmd->supported |= SUPPORTED_Autoneg; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_CTRL1); + if (reg & MDIO_AN_CTRL1_ENABLE) { + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->advertising |= + ADVERTISED_Autoneg | + mdio45_get_an(mdio, MDIO_AN_ADVERTISE) | + npage_adv; + } else { + ecmd->autoneg = AUTONEG_DISABLE; + } + } else { + ecmd->autoneg = AUTONEG_DISABLE; + } + + if (ecmd->autoneg) { + u32 modes = 0; + + /* If AN is complete and successful, report best common + * mode, otherwise report best advertised mode. */ + if (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_STAT1) & + MDIO_AN_STAT1_COMPLETE) + modes = (ecmd->advertising & + (mdio45_get_an(mdio, MDIO_AN_LPA) | + npage_lpa)); + if (modes == 0) + modes = ecmd->advertising; + + if (modes & ADVERTISED_10000baseT_Full) { + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + } else if (modes & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half)) { + ecmd->speed = SPEED_1000; + ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full); + } else if (modes & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { + ecmd->speed = SPEED_100; + ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); + } else { + ecmd->speed = SPEED_10; + ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); + } + } else { + /* Report forced settings */ + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL1); + ecmd->speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) * + ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); + ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || + ecmd->speed == SPEED_10000); + } +} +EXPORT_SYMBOL(mdio45_ethtool_gset_npage); + +/** + * mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs + * @mdio: MDIO interface + * @mii_data: MII ioctl data structure + * @cmd: MII ioctl command + * + * Returns 0 on success, negative on error. + */ +int mdio_mii_ioctl(const struct mdio_if_info *mdio, + struct mii_ioctl_data *mii_data, int cmd) +{ + int prtad, devad; + u16 addr = mii_data->reg_num; + + /* Validate/convert cmd to one of SIOC{G,S}MIIREG */ + switch (cmd) { + case SIOCGMIIPHY: + if (mdio->prtad == MDIO_PRTAD_NONE) + return -EOPNOTSUPP; + mii_data->phy_id = mdio->prtad; + cmd = SIOCGMIIREG; + break; + case SIOCGMIIREG: + break; + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + break; + default: + return -EOPNOTSUPP; + } + + /* Validate/convert phy_id */ + if ((mdio->mode_support & MDIO_SUPPORTS_C45) && + mdio_phy_id_is_c45(mii_data->phy_id)) { + prtad = mdio_phy_id_prtad(mii_data->phy_id); + devad = mdio_phy_id_devad(mii_data->phy_id); + } else if ((mdio->mode_support & MDIO_SUPPORTS_C22) && + mii_data->phy_id < 0x20) { + prtad = mii_data->phy_id; + devad = MDIO_DEVAD_NONE; + addr &= 0x1f; + } else if ((mdio->mode_support & MDIO_EMULATE_C22) && + mdio->prtad != MDIO_PRTAD_NONE && + mii_data->phy_id == mdio->prtad) { + /* Remap commonly-used MII registers. */ + prtad = mdio->prtad; + switch (addr) { + case MII_BMCR: + case MII_BMSR: + case MII_PHYSID1: + case MII_PHYSID2: + devad = __ffs(mdio->mmds); + break; + case MII_ADVERTISE: + case MII_LPA: + if (!(mdio->mmds & MDIO_DEVS_AN)) + return -EINVAL; + devad = MDIO_MMD_AN; + if (addr == MII_ADVERTISE) + addr = MDIO_AN_ADVERTISE; + else + addr = MDIO_AN_LPA; + break; + default: + return -EINVAL; + } + } else { + return -EINVAL; + } + + if (cmd == SIOCGMIIREG) { + int rc = mdio->mdio_read(mdio->dev, prtad, devad, addr); + if (rc < 0) + return rc; + mii_data->val_out = rc; + return 0; + } else { + return mdio->mdio_write(mdio->dev, prtad, devad, addr, + mii_data->val_in); + } +} +EXPORT_SYMBOL(mdio_mii_ioctl); diff --git a/include/linux/mdio.h b/include/linux/mdio.h index d57ddb0..ba41537 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -234,4 +234,70 @@ static inline __u16 mdio_phy_id_devad(int phy_id) return phy_id & MDIO_PHY_ID_DEVAD; } +#ifdef __KERNEL__ + +/** + * struct mdio_if_info - Ethernet controller MDIO interface + * @prtad: PRTAD of the PHY (%MDIO_PRTAD_NONE if not present/unknown) + * @mmds: Mask of MMDs expected to be present in the PHY. This must be + * non-zero unless @prtad = %MDIO_PRTAD_NONE. + * @mode_support: MDIO modes supported. If %MDIO_SUPPORTS_C22 is set then + * MII register access will be passed through with @devad = + * %MDIO_DEVAD_NONE. If %MDIO_EMULATE_C22 is set then access to + * commonly used clause 22 registers will be translated into + * clause 45 registers. + * @dev: Net device structure + * @mdio_read: Register read function; returns value or negative error code + * @mdio_write: Register write function; returns 0 or negative error code + */ +struct mdio_if_info { + int prtad; + u32 __bitwise mmds; + unsigned mode_support; + + struct net_device *dev; + int (*mdio_read)(struct net_device *dev, int prtad, int devad, + u16 addr); + int (*mdio_write)(struct net_device *dev, int prtad, int devad, + u16 addr, u16 val); +}; + +#define MDIO_PRTAD_NONE (-1) +#define MDIO_DEVAD_NONE (-1) +#define MDIO_SUPPORTS_C22 1 +#define MDIO_SUPPORTS_C45 2 +#define MDIO_EMULATE_C22 4 + +struct ethtool_cmd; +struct ethtool_pauseparam; +extern int mdio45_probe(struct mdio_if_info *mdio, int prtad); +extern int mdio_set_flag(const struct mdio_if_info *mdio, + int prtad, int devad, u16 addr, int mask, + bool sense); +extern int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmds); +extern int mdio45_nway_restart(const struct mdio_if_info *mdio); +extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, + struct ethtool_cmd *ecmd, + u32 npage_adv, u32 npage_lpa); + +/** + * mdio45_ethtool_gset - get settings for ETHTOOL_GSET + * @mdio: MDIO interface + * @ecmd: Ethtool request structure + * + * Since the CSRs for auto-negotiation using next pages are not fully + * standardised, this function does not attempt to decode them. Use + * mdio45_ethtool_gset_npage() to specify advertisement bits from next + * pages. + */ +static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio, + struct ethtool_cmd *ecmd) +{ + mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0); +} + +extern int mdio_mii_ioctl(const struct mdio_if_info *mdio, + struct mii_ioctl_data *mii_data, int cmd); + +#endif /* __KERNEL__ */ #endif /* __LINUX_MDIO_H__ */ -- cgit v0.10.2 From 68e7f45e118f98b77cfa007aa2d97b5dac69fe6b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:05:08 +0000 Subject: sfc: Use generic MDIO functions and definitions Make use of the newly-added generic MDIO clause 45 support and remove redundant definitions. Add an 'efx_' prefix to the remaining driver-specific MDIO functions and remove arguments which are redundant with efx->mdio.prtad. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index 12a8296..260aafa 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -1,7 +1,7 @@ config SFC tristate "Solarflare Solarstorm SFC4000 support" depends on PCI && INET - select MII + select MDIO select CRC32 select I2C select I2C_ALGOBIT diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 7269a42..d3e240b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1300,10 +1300,16 @@ out_requeue: static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) { struct efx_nic *efx = netdev_priv(net_dev); + struct mii_ioctl_data *data = if_mii(ifr); EFX_ASSERT_RESET_SERIALISED(efx); - return generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL); + /* Convert phy_id from older PRTAD/DEVAD format */ + if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && + (data->phy_id & 0xfc00) == 0x0400) + data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400; + + return mdio_mii_ioctl(&efx->mdio, data, cmd); } /************************************************************************** @@ -1945,7 +1951,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, mutex_init(&efx->mac_lock); efx->mac_op = &efx_dummy_mac_operations; efx->phy_op = &efx_dummy_phy_operations; - efx->mii.dev = net_dev; + efx->mdio.dev = net_dev; INIT_WORK(&efx->phy_work, efx_phy_work); INIT_WORK(&efx->mac_work, efx_mac_work); atomic_set(&efx->netif_stop_count, 1); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 64309f4..1c7b684 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "net_driver.h" #include "workarounds.h" @@ -345,8 +346,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, unsigned int n = 0, i; enum efx_loopback_mode mode; - efx_fill_test(n++, strings, data, &tests->mii, - "core", 0, "mii", NULL); + efx_fill_test(n++, strings, data, &tests->mdio, + "core", 0, "mdio", NULL); efx_fill_test(n++, strings, data, &tests->nvram, "core", 0, "nvram", NULL); efx_fill_test(n++, strings, data, &tests->interrupt, @@ -529,14 +530,7 @@ static int efx_ethtool_nway_reset(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, - __ffs(BMCR_ANRESTART), true); - return 0; - } - - return -EOPNOTSUPP; + return mdio45_nway_restart(&efx->mdio); } static u32 efx_ethtool_get_link(struct net_device *net_dev) @@ -689,7 +683,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, return -EINVAL; } - if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) && + if (!(efx->phy_op->mmds & MDIO_DEVS_AN) && (wanted_fc & EFX_FC_AUTO)) { EFX_LOG(efx, "PHY does not support flow control " "autonegotiation\n"); @@ -717,7 +711,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, mutex_lock(&efx->mac_lock); efx->wanted_fc = wanted_fc; - mdio_clause45_set_pause(efx); + efx_mdio_set_pause(efx); __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 466a8ab..c049364 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -2063,26 +2063,6 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) ************************************************************************** */ -/* Use the top bit of the MII PHY id to indicate the PHY type - * (1G/10G), with the remaining bits as the actual PHY id. - * - * This allows us to avoid leaking information from the mii_if_info - * structure into other data structures. - */ -#define FALCON_PHY_ID_ID_WIDTH EFX_WIDTH(MD_PRT_DEV_ADR) -#define FALCON_PHY_ID_ID_MASK ((1 << FALCON_PHY_ID_ID_WIDTH) - 1) -#define FALCON_PHY_ID_WIDTH (FALCON_PHY_ID_ID_WIDTH + 1) -#define FALCON_PHY_ID_MASK ((1 << FALCON_PHY_ID_WIDTH) - 1) -#define FALCON_PHY_ID_10G (1 << (FALCON_PHY_ID_WIDTH - 1)) - - -/* Packing the clause 45 port and device fields into a single value */ -#define MD_PRT_ADR_COMP_LBN (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN) -#define MD_PRT_ADR_COMP_WIDTH MD_PRT_ADR_WIDTH -#define MD_DEV_ADR_COMP_LBN 0 -#define MD_DEV_ADR_COMP_WIDTH MD_DEV_ADR_WIDTH - - /* Wait for GMII access to complete */ static int falcon_gmii_wait(struct efx_nic *efx) { @@ -2108,49 +2088,29 @@ static int falcon_gmii_wait(struct efx_nic *efx) return -ETIMEDOUT; } -/* Writes a GMII register of a PHY connected to Falcon using MDIO. */ -static void falcon_mdio_write(struct net_device *net_dev, int phy_id, - int addr, int value) +/* Write an MDIO register of a PHY connected to Falcon. */ +static int falcon_mdio_write(struct net_device *net_dev, + int prtad, int devad, u16 addr, u16 value) { struct efx_nic *efx = netdev_priv(net_dev); - unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK; efx_oword_t reg; + int rc; - /* The 'generic' prt/dev packing in mdio_10g.h is conveniently - * chosen so that the only current user, Falcon, can take the - * packed value and use them directly. - * Fail to build if this assumption is broken. - */ - BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G); - BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH); - BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN); - BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN); - - if (phy_id2 == PHY_ADDR_INVALID) - return; - - /* See falcon_mdio_read for an explanation. */ - if (!(phy_id & FALCON_PHY_ID_10G)) { - int mmd = ffs(efx->phy_op->mmds) - 1; - EFX_TRACE(efx, "Fixing erroneous clause22 write\n"); - phy_id2 = mdio_clause45_pack(phy_id2, mmd) - & FALCON_PHY_ID_ID_MASK; - } - - EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id, - addr, value); + EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n", + prtad, devad, addr, value); spin_lock_bh(&efx->phy_lock); - /* Check MII not currently being accessed */ - if (falcon_gmii_wait(efx) != 0) + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); + if (rc) goto out; /* Write the address/ID register */ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); falcon_write(efx, ®, MD_PHY_ADR_REG_KER); - EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2); + EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); falcon_write(efx, ®, MD_ID_REG_KER); /* Write data */ @@ -2163,7 +2123,8 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id, falcon_write(efx, ®, MD_CS_REG_KER); /* Wait for data to be written */ - if (falcon_gmii_wait(efx) != 0) { + rc = falcon_gmii_wait(efx); + if (rc) { /* Abort the write operation */ EFX_POPULATE_OWORD_2(reg, MD_WRC, 0, @@ -2174,45 +2135,28 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id, out: spin_unlock_bh(&efx->phy_lock); + return rc; } -/* Reads a GMII register from a PHY connected to Falcon. If no value - * could be read, -1 will be returned. */ -static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr) +/* Read an MDIO register of a PHY connected to Falcon. */ +static int falcon_mdio_read(struct net_device *net_dev, + int prtad, int devad, u16 addr) { 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; - - if (phy_addr == PHY_ADDR_INVALID) - return -1; - - /* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G) - * but the generic Linux code does not make any distinction or have - * any state for this. - * We spot the case where someone tried to talk 22 to a 45 PHY and - * redirect the request to the lowest numbered MMD as a clause45 - * request. This is enough to allow simple queries like id and link - * state to succeed. TODO: We may need to do more in future. - */ - if (!(phy_id & FALCON_PHY_ID_10G)) { - int mmd = ffs(efx->phy_op->mmds) - 1; - EFX_TRACE(efx, "Fixing erroneous clause22 read\n"); - phy_addr = mdio_clause45_pack(phy_addr, mmd) - & FALCON_PHY_ID_ID_MASK; - } + int rc; spin_lock_bh(&efx->phy_lock); - /* Check MII not currently being accessed */ - if (falcon_gmii_wait(efx) != 0) + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); + if (rc) goto out; EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); falcon_write(efx, ®, MD_PHY_ADR_REG_KER); - EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr); + EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); falcon_write(efx, ®, MD_ID_REG_KER); /* Request data to be read */ @@ -2220,12 +2164,12 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr) falcon_write(efx, ®, MD_CS_REG_KER); /* Wait for data to become available */ - value = falcon_gmii_wait(efx); - if (value == 0) { + rc = falcon_gmii_wait(efx); + if (rc == 0) { falcon_read(efx, ®, MD_RXD_REG_KER); - value = EFX_OWORD_FIELD(reg, MD_RXD); - EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n", - phy_id, addr, value); + rc = EFX_OWORD_FIELD(reg, MD_RXD); + EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n", + prtad, devad, addr, rc); } else { /* Abort the read operation */ EFX_POPULATE_OWORD_2(reg, @@ -2233,22 +2177,13 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr) MD_GC, 1); falcon_write(efx, ®, MD_CS_REG_KER); - EFX_LOG(efx, "read from GMII 0x%x register %02x, got " - "error %d\n", phy_id, addr, value); + EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n", + prtad, devad, addr, rc); } out: spin_unlock_bh(&efx->phy_lock); - - return value; -} - -static void falcon_init_mdio(struct mii_if_info *gmii) -{ - gmii->mdio_read = falcon_mdio_read; - gmii->mdio_write = falcon_mdio_write; - gmii->phy_id_mask = FALCON_PHY_ID_MASK; - gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_PHY_ADR)) - 1); + return rc; } static int falcon_probe_phy(struct efx_nic *efx) @@ -2342,9 +2277,11 @@ int falcon_probe_port(struct efx_nic *efx) if (rc) return rc; - /* Set up GMII structure for PHY */ - efx->mii.supports_gmii = true; - falcon_init_mdio(&efx->mii); + /* Set up MDIO structure for PHY */ + efx->mdio.mmds = efx->phy_op->mmds; + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + efx->mdio.mdio_read = falcon_mdio_read; + efx->mdio.mdio_write = falcon_mdio_write; /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ if (falcon_rev(efx) >= FALCON_REV_B0) @@ -2761,7 +2698,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) 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; + efx->mdio.prtad = MDIO_PRTAD_NONE; board_rev = 0; rc = 0; } else if (rc) { @@ -2771,7 +2708,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3; efx->phy_type = v2->port0_phy_type; - efx->mii.phy_id = v2->port0_phy_addr; + efx->mdio.prtad = v2->port0_phy_addr; board_rev = le16_to_cpu(v2->board_revision); if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { @@ -2793,7 +2730,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) /* 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_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); efx_set_board_info(efx, board_rev); diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index bda8d5b..375e2a5 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -456,9 +456,6 @@ #define MD_PRT_ADR_WIDTH 5 #define MD_DEV_ADR_LBN 6 #define MD_DEV_ADR_WIDTH 5 -/* Used for writing both at once */ -#define MD_PRT_DEV_ADR_LBN 6 -#define MD_PRT_DEV_ADR_WIDTH 10 /* PHY management status & mask register (DWORD read only) */ #define MD_STAT_REG_KER 0xc50 diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 5a03713..2b3269c 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -133,7 +133,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) /* If the link is up, then check the phy side of the xaui link */ if (efx->link_up && link_ok) if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) - link_ok = mdio_clause45_phyxgxs_lane_sync(efx); + link_ok = efx_mdio_phyxgxs_lane_sync(efx); return link_ok; } diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 9f5ec3e..11c231a1 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -17,7 +17,7 @@ #include "boards.h" #include "workarounds.h" -unsigned mdio_id_oui(u32 id) +unsigned efx_mdio_id_oui(u32 id) { unsigned oui = 0; int i; @@ -32,52 +32,45 @@ unsigned mdio_id_oui(u32 id) return oui; } -int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, +int efx_mdio_reset_mmd(struct efx_nic *port, int mmd, int spins, int spintime) { u32 ctrl; - int phy_id = port->mii.phy_id; /* Catch callers passing values in the wrong units (or just silly) */ EFX_BUG_ON_PARANOID(spins * spintime >= 5000); - mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1, - (1 << MDIO_MMDREG_CTRL1_RESET_LBN)); + efx_mdio_write(port, mmd, MDIO_CTRL1, MDIO_CTRL1_RESET); /* Wait for the reset bit to clear. */ do { msleep(spintime); - ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1); + ctrl = efx_mdio_read(port, mmd, MDIO_CTRL1); spins--; - } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))); + } while (spins && (ctrl & MDIO_CTRL1_RESET)); return spins ? spins : -ETIMEDOUT; } -static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, - int fault_fatal) +static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal) { int status; - int phy_id = efx->mii.phy_id; if (LOOPBACK_INTERNAL(efx)) return 0; if (mmd != MDIO_MMD_AN) { /* Read MMD STATUS2 to check it is responding. */ - status = mdio_clause45_read(efx, phy_id, mmd, - MDIO_MMDREG_STAT2); - if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & - ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != - MDIO_MMDREG_STAT2_PRESENT_VAL) { + status = efx_mdio_read(efx, mmd, MDIO_STAT2); + if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) { EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); return -EIO; } } /* Read MMD STATUS 1 to check for fault. */ - status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1); - if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) { + status = efx_mdio_read(efx, mmd, MDIO_STAT1); + if (status & MDIO_STAT1_FAULT) { if (fault_fatal) { EFX_ERR(efx, "PHY MMD %d reporting fatal" " fault: status %x\n", mmd, status); @@ -94,8 +87,7 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, #define MDIO45_RESET_TIME 1000 /* ms */ #define MDIO45_RESET_ITERS 100 -int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, - unsigned int mmd_mask) +int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask) { const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS; int tries = MDIO45_RESET_ITERS; @@ -109,16 +101,13 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, in_reset = 0; while (mask) { if (mask & 1) { - stat = mdio_clause45_read(efx, - efx->mii.phy_id, - mmd, - MDIO_MMDREG_CTRL1); + stat = efx_mdio_read(efx, mmd, MDIO_CTRL1); if (stat < 0) { EFX_ERR(efx, "failed to read status of" " MMD %d\n", mmd); return -EIO; } - if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)) + if (stat & MDIO_CTRL1_RESET) in_reset |= (1 << mmd); } mask = mask >> 1; @@ -137,28 +126,26 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, return rc; } -int mdio_clause45_check_mmds(struct efx_nic *efx, - unsigned int mmd_mask, unsigned int fatal_mask) +int efx_mdio_check_mmds(struct efx_nic *efx, + unsigned int mmd_mask, unsigned int fatal_mask) { - int mmd = 0, probe_mmd, devs0, devs1; + int mmd = 0, probe_mmd, devs1, devs2; u32 devices; /* Historically we have probed the PHYXS to find out what devices are * present,but that doesn't work so well if the PHYXS isn't expected * to exist, if so just find the first item in the list supplied. */ - probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS : + probe_mmd = (mmd_mask & MDIO_DEVS_PHYXS) ? MDIO_MMD_PHYXS : __ffs(mmd_mask); /* Check all the expected MMDs are present */ - devs0 = mdio_clause45_read(efx, efx->mii.phy_id, - probe_mmd, MDIO_MMDREG_DEVS0); - devs1 = mdio_clause45_read(efx, efx->mii.phy_id, - probe_mmd, MDIO_MMDREG_DEVS1); - if (devs0 < 0 || devs1 < 0) { + devs1 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS1); + devs2 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS2); + if (devs1 < 0 || devs2 < 0) { EFX_ERR(efx, "failed to read devices present\n"); return -EIO; } - devices = devs0 | (devs1 << 16); + devices = devs1 | (devs2 << 16); if ((devices & mmd_mask) != mmd_mask) { EFX_ERR(efx, "required MMDs not present: got %x, " "wanted %x\n", devices, mmd_mask); @@ -170,7 +157,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, while (mmd_mask) { if (mmd_mask & 1) { int fault_fatal = fatal_mask & 1; - if (mdio_clause45_check_mmd(efx, mmd, fault_fatal)) + if (efx_mdio_check_mmd(efx, mmd, fault_fatal)) return -EIO; } mmd_mask = mmd_mask >> 1; @@ -181,13 +168,8 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, return 0; } -bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) +bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask) { - int phy_id = efx->mii.phy_id; - u32 reg; - bool ok = true; - int mmd = 0; - /* If the port is in loopback, then we should only consider a subset * of mmd's */ if (LOOPBACK_INTERNAL(efx)) @@ -197,241 +179,75 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) else if (efx_phy_mode_disabled(efx->phy_mode)) return false; else if (efx->loopback_mode == LOOPBACK_PHYXS) - mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | - MDIO_MMDREG_DEVS_PCS | - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_AN); + mmd_mask &= ~(MDIO_DEVS_PHYXS | + MDIO_DEVS_PCS | + MDIO_DEVS_PMAPMD | + MDIO_DEVS_AN); else if (efx->loopback_mode == LOOPBACK_PCS) - mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_AN); + mmd_mask &= ~(MDIO_DEVS_PCS | + MDIO_DEVS_PMAPMD | + MDIO_DEVS_AN); else if (efx->loopback_mode == LOOPBACK_PMAPMD) - mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_AN); - - if (!mmd_mask) { - /* Use presence of XGMII faults in leui of link state */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_PHYXS_STATUS2); - return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); - } + mmd_mask &= ~(MDIO_DEVS_PMAPMD | + MDIO_DEVS_AN); - while (mmd_mask) { - if (mmd_mask & 1) { - /* Double reads because link state is latched, and a - * read moves the current state into the register */ - reg = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - reg = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - ok = ok && (reg & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); - } - mmd_mask = (mmd_mask >> 1); - mmd++; - } - return ok; + return mdio45_links_ok(&efx->mdio, mmd_mask); } -void mdio_clause45_transmit_disable(struct efx_nic *efx) +void efx_mdio_transmit_disable(struct efx_nic *efx) { - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN, - efx->phy_mode & PHY_MODE_TX_DISABLED); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, + MDIO_PMA_TXDIS, MDIO_PMD_TXDIS_GLOBAL, + efx->phy_mode & PHY_MODE_TX_DISABLED); } -void mdio_clause45_phy_reconfigure(struct efx_nic *efx) +void efx_mdio_phy_reconfigure(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN, - efx->loopback_mode == LOOPBACK_PMAPMD); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS, - MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, - efx->loopback_mode == LOOPBACK_PCS); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, - efx->loopback_mode == LOOPBACK_NETWORK); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, + MDIO_CTRL1, MDIO_PMA_CTRL1_LOOPBACK, + efx->loopback_mode == LOOPBACK_PMAPMD); + efx_mdio_set_flag(efx, MDIO_MMD_PCS, + MDIO_CTRL1, MDIO_PCS_CTRL1_LOOPBACK, + efx->loopback_mode == LOOPBACK_PCS); + efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, + MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, + efx->loopback_mode == LOOPBACK_NETWORK); } -static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx, - int lpower, int mmd) +static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, + int lpower, int mmd) { - int phy = efx->mii.phy_id; - int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1); + int stat = efx_mdio_read(efx, mmd, MDIO_STAT1); EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n", mmd, lpower); - if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) { - mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1, - MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower); + if (stat & MDIO_STAT1_LPOWERABLE) { + efx_mdio_set_flag(efx, mmd, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, lpower); } } -void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, - int low_power, unsigned int mmd_mask) +void efx_mdio_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask) { int mmd = 0; - mmd_mask &= ~MDIO_MMDREG_DEVS_AN; + mmd_mask &= ~MDIO_DEVS_AN; while (mmd_mask) { if (mmd_mask & 1) - mdio_clause45_set_mmd_lpower(efx, low_power, mmd); + efx_mdio_set_mmd_lpower(efx, low_power, mmd); mmd_mask = (mmd_mask >> 1); mmd++; } } -static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr) -{ - int phy_id = efx->mii.phy_id; - u32 result = 0; - int reg; - - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr); - if (reg & ADVERTISE_10HALF) - result |= ADVERTISED_10baseT_Half; - if (reg & ADVERTISE_10FULL) - result |= ADVERTISED_10baseT_Full; - if (reg & ADVERTISE_100HALF) - result |= ADVERTISED_100baseT_Half; - if (reg & ADVERTISE_100FULL) - result |= ADVERTISED_100baseT_Full; - return result; -} - -/** - * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. - * @efx: Efx NIC - * @ecmd: Buffer for settings - * - * On return the 'port', 'speed', 'supported' and 'advertising' fields of - * ecmd have been filled out. - */ -void mdio_clause45_get_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd) -{ - mdio_clause45_get_settings_ext(efx, ecmd, 0, 0); -} - /** - * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. - * @efx: Efx NIC - * @ecmd: Buffer for settings - * @xnp: Advertised Extended Next Page state - * @xnp_lpa: Link Partner's advertised XNP state - * - * On return the 'port', 'speed', 'supported' and 'advertising' fields of - * ecmd have been filled out. - */ -void mdio_clause45_get_settings_ext(struct efx_nic *efx, - struct ethtool_cmd *ecmd, - u32 npage_adv, u32 npage_lpa) -{ - int phy_id = efx->mii.phy_id; - int reg; - - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = phy_id; - - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL2); - switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) { - case MDIO_PMAPMD_CTRL2_10G_BT: - case MDIO_PMAPMD_CTRL2_1G_BT: - case MDIO_PMAPMD_CTRL2_100_BT: - case MDIO_PMAPMD_CTRL2_10_BT: - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_SPEED); - if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN)) - ecmd->supported |= SUPPORTED_10000baseT_Full; - if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN)) - ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_1000baseT_Half); - if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN)) - ecmd->supported |= (SUPPORTED_100baseT_Full | - SUPPORTED_100baseT_Half); - if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN)) - ecmd->supported |= (SUPPORTED_10baseT_Full | - SUPPORTED_10baseT_Half); - ecmd->advertising = ADVERTISED_TP; - break; - - /* We represent CX4 as fibre in the absence of anything better */ - case MDIO_PMAPMD_CTRL2_10G_CX4: - /* All the other defined modes are flavours of optical */ - default: - ecmd->port = PORT_FIBRE; - ecmd->supported = SUPPORTED_FIBRE; - ecmd->advertising = ADVERTISED_FIBRE; - break; - } - - if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { - ecmd->supported |= SUPPORTED_Autoneg; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1); - if (reg & BMCR_ANENABLE) { - ecmd->autoneg = AUTONEG_ENABLE; - ecmd->advertising |= - ADVERTISED_Autoneg | - mdio_clause45_get_an(efx, MDIO_AN_ADVERTISE) | - npage_adv; - } else - ecmd->autoneg = AUTONEG_DISABLE; - } else - ecmd->autoneg = AUTONEG_DISABLE; - - if (ecmd->autoneg) { - /* If AN is complete, report best common mode, - * otherwise report best advertised mode. */ - u32 modes = 0; - if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_STAT1) & - (1 << MDIO_AN_STATUS_AN_DONE_LBN)) - modes = (ecmd->advertising & - (mdio_clause45_get_an(efx, MDIO_AN_LPA) | - npage_lpa)); - if (modes == 0) - modes = ecmd->advertising; - - if (modes & ADVERTISED_10000baseT_Full) { - ecmd->speed = SPEED_10000; - ecmd->duplex = DUPLEX_FULL; - } else if (modes & (ADVERTISED_1000baseT_Full | - ADVERTISED_1000baseT_Half)) { - ecmd->speed = SPEED_1000; - ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full); - } else if (modes & (ADVERTISED_100baseT_Full | - ADVERTISED_100baseT_Half)) { - ecmd->speed = SPEED_100; - ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); - } else { - ecmd->speed = SPEED_10; - ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); - } - } else { - /* Report forced settings */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1); - ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) * - ((reg & BMCR_SPEED100) ? 100 : 10)); - ecmd->duplex = (reg & BMCR_FULLDPLX || - ecmd->speed == SPEED_10000); - } -} - -/** - * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. + * efx_mdio_set_settings - Set (some of) the PHY settings over MDIO. * @efx: Efx NIC * @ecmd: New settings */ -int mdio_clause45_set_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd) +int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; struct ethtool_cmd prev; u32 required; int reg; @@ -489,94 +305,67 @@ int mdio_clause45_set_settings(struct efx_nic *efx, ADVERTISED_1000baseT_Full)) reg |= ADVERTISE_NPAGE; reg |= efx_fc_advertise(efx->wanted_fc); - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_ADVERTISE, reg); + efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); /* Set up the (extended) next page if necessary */ if (efx->phy_op->set_npage_adv) efx->phy_op->set_npage_adv(efx, ecmd->advertising); /* Enable and restart AN */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1); - reg |= BMCR_ANENABLE; + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); + reg |= MDIO_AN_CTRL1_ENABLE; if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) - reg |= BMCR_ANRESTART; + reg |= MDIO_AN_CTRL1_RESTART; if (xnp) - reg |= 1 << MDIO_AN_CTRL_XNP_LBN; + reg |= MDIO_AN_CTRL1_XNP; else - reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, reg); + reg &= ~MDIO_AN_CTRL1_XNP; + efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); } else { /* Disable AN */ - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, - __ffs(BMCR_ANENABLE), false); + efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1, + MDIO_AN_CTRL1_ENABLE, false); /* Set the basic control bits */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1); - reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | - 0x003c); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1); + reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX); if (ecmd->speed == SPEED_100) - reg |= BMCR_SPEED100; + reg |= MDIO_PMA_CTRL1_SPEED100; if (ecmd->duplex) - reg |= BMCR_FULLDPLX; - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1, reg); + reg |= MDIO_CTRL1_FULLDPLX; + efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg); } return 0; } -void mdio_clause45_set_pause(struct efx_nic *efx) +void efx_mdio_set_pause(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; int reg; - if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { + if (efx->phy_op->mmds & MDIO_DEVS_AN) { /* Set pause capability advertising */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_ADVERTISE); + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE); reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); reg |= efx_fc_advertise(efx->wanted_fc); - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_ADVERTISE, reg); + efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); /* Restart auto-negotiation */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1); - if (reg & BMCR_ANENABLE) { - reg |= BMCR_ANRESTART; - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, reg); + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); + if (reg & MDIO_AN_CTRL1_ENABLE) { + reg |= MDIO_AN_CTRL1_RESTART; + efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); } } } -enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) +enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; int lpa; - if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) + if (!(efx->phy_op->mmds & MDIO_DEVS_AN)) return efx->wanted_fc; - lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); + lpa = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA); return efx_fc_resolve(efx->wanted_fc, lpa); } - -void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, - u16 addr, int bit, bool sense) -{ - int old_val = mdio_clause45_read(efx, prt, dev, addr); - int new_val; - - if (sense) - new_val = old_val | (1 << bit); - else - new_val = old_val & ~(1 << bit); - if (old_val != new_val) - mdio_clause45_write(efx, prt, dev, addr, new_val); -} diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 7014d22..ea4587d 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -10,247 +10,53 @@ #ifndef EFX_MDIO_10G_H #define EFX_MDIO_10G_H +#include + /* - * Definitions needed for doing 10G MDIO as specified in clause 45 - * MDIO, which do not appear in Linux yet. Also some helper functions. + * Helper functions for doing 10G MDIO as specified in IEEE 802.3 clause 45. */ #include "efx.h" #include "boards.h" -/* Numbering of the MDIO Manageable Devices (MMDs) */ -/* Physical Medium Attachment/ Physical Medium Dependent sublayer */ -#define MDIO_MMD_PMAPMD (1) -/* WAN Interface Sublayer */ -#define MDIO_MMD_WIS (2) -/* Physical Coding Sublayer */ -#define MDIO_MMD_PCS (3) -/* PHY Extender Sublayer */ -#define MDIO_MMD_PHYXS (4) -/* Extender Sublayer */ -#define MDIO_MMD_DTEXS (5) -/* Transmission convergence */ -#define MDIO_MMD_TC (6) -/* Auto negotiation */ -#define MDIO_MMD_AN (7) -/* Clause 22 extension */ -#define MDIO_MMD_C22EXT 29 - -/* Generic register locations */ -#define MDIO_MMDREG_CTRL1 (0) -#define MDIO_MMDREG_STAT1 (1) -#define MDIO_MMDREG_IDHI (2) -#define MDIO_MMDREG_IDLOW (3) -#define MDIO_MMDREG_SPEED (4) -#define MDIO_MMDREG_DEVS0 (5) -#define MDIO_MMDREG_DEVS1 (6) -#define MDIO_MMDREG_CTRL2 (7) -#define MDIO_MMDREG_STAT2 (8) -#define MDIO_MMDREG_TXDIS (9) - -/* Bits in MMDREG_CTRL1 */ -/* Reset */ -#define MDIO_MMDREG_CTRL1_RESET_LBN (15) -#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1) -/* Loopback */ -/* Loopback bit for WIS, PCS, PHYSX and DTEXS */ -#define MDIO_MMDREG_CTRL1_LBACK_LBN (14) -#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1) -/* Low power */ -#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11) -#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1) - -/* Bits in MMDREG_STAT1 */ -#define MDIO_MMDREG_STAT1_FAULT_LBN (7) -#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1) -/* Link state */ -#define MDIO_MMDREG_STAT1_LINK_LBN (2) -#define MDIO_MMDREG_STAT1_LINK_WIDTH (1) -/* Low power ability */ -#define MDIO_MMDREG_STAT1_LPABLE_LBN (1) -#define MDIO_MMDREG_STAT1_LPABLE_WIDTH (1) - -/* Bits in combined ID regs */ -static inline unsigned mdio_id_rev(u32 id) { return id & 0xf; } -static inline unsigned mdio_id_model(u32 id) { return (id >> 4) & 0x3f; } -extern unsigned mdio_id_oui(u32 id); - -/* Bits in MMDREG_DEVS0/1. Someone thoughtfully layed things out - * so the 'bit present' bit number of an MMD is the number of - * that MMD */ -#define DEV_PRESENT_BIT(_b) (1 << _b) - -#define MDIO_MMDREG_DEVS_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) -#define MDIO_MMDREG_DEVS_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) -#define MDIO_MMDREG_DEVS_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) -#define MDIO_MMDREG_DEVS_AN DEV_PRESENT_BIT(MDIO_MMD_AN) -#define MDIO_MMDREG_DEVS_C22EXT DEV_PRESENT_BIT(MDIO_MMD_C22EXT) - -/* Bits in MMDREG_SPEED */ -#define MDIO_MMDREG_SPEED_10G_LBN 0 -#define MDIO_MMDREG_SPEED_10G_WIDTH 1 -#define MDIO_MMDREG_SPEED_1000M_LBN 4 -#define MDIO_MMDREG_SPEED_1000M_WIDTH 1 -#define MDIO_MMDREG_SPEED_100M_LBN 5 -#define MDIO_MMDREG_SPEED_100M_WIDTH 1 -#define MDIO_MMDREG_SPEED_10M_LBN 6 -#define MDIO_MMDREG_SPEED_10M_WIDTH 1 - -/* Bits in MMDREG_STAT2 */ -#define MDIO_MMDREG_STAT2_PRESENT_VAL (2) -#define MDIO_MMDREG_STAT2_PRESENT_LBN (14) -#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2) - -/* Bits in MMDREG_TXDIS */ -#define MDIO_MMDREG_TXDIS_GLOBAL_LBN (0) -#define MDIO_MMDREG_TXDIS_GLOBAL_WIDTH (1) - -/* MMD-specific bits, ordered by MMD, then register */ -#define MDIO_PMAPMD_CTRL1_LBACK_LBN (0) -#define MDIO_PMAPMD_CTRL1_LBACK_WIDTH (1) - -/* PMA type (4 bits) */ -#define MDIO_PMAPMD_CTRL2_10G_CX4 (0x0) -#define MDIO_PMAPMD_CTRL2_10G_EW (0x1) -#define MDIO_PMAPMD_CTRL2_10G_LW (0x2) -#define MDIO_PMAPMD_CTRL2_10G_SW (0x3) -#define MDIO_PMAPMD_CTRL2_10G_LX4 (0x4) -#define MDIO_PMAPMD_CTRL2_10G_ER (0x5) -#define MDIO_PMAPMD_CTRL2_10G_LR (0x6) -#define MDIO_PMAPMD_CTRL2_10G_SR (0x7) -/* Reserved */ -#define MDIO_PMAPMD_CTRL2_10G_BT (0x9) -/* Reserved */ -/* Reserved */ -#define MDIO_PMAPMD_CTRL2_1G_BT (0xc) -/* Reserved */ -#define MDIO_PMAPMD_CTRL2_100_BT (0xe) -#define MDIO_PMAPMD_CTRL2_10_BT (0xf) -#define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf) - -/* PMA 10GBT registers */ -#define MDIO_PMAPMD_10GBT_TXPWR (131) -#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN (0) -#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_WIDTH (1) - -/* PHY XGXS Status 2 */ -#define MDIO_PHYXS_STATUS2 (8) -#define MDIO_PHYXS_STATUS2_RX_FAULT_LBN 10 - -/* PHY XGXS lane state */ -#define MDIO_PHYXS_LANE_STATE (0x18) -#define MDIO_PHYXS_LANE_ALIGNED_LBN (12) - -/* AN registers */ -#define MDIO_AN_CTRL_XNP_LBN 13 -#define MDIO_AN_STATUS (1) -#define MDIO_AN_STATUS_XNP_LBN (7) -#define MDIO_AN_STATUS_PAGE_LBN (6) -#define MDIO_AN_STATUS_AN_DONE_LBN (5) -#define MDIO_AN_STATUS_LP_AN_CAP_LBN (0) - -#define MDIO_AN_ADVERTISE 16 -#define MDIO_AN_ADVERTISE_XNP_LBN 12 -#define MDIO_AN_LPA 19 -#define MDIO_AN_XNP 22 -#define MDIO_AN_LPA_XNP 25 - -#define MDIO_AN_10GBT_CTRL 32 -#define MDIO_AN_10GBT_CTRL_ADV_10G_LBN 12 -#define MDIO_AN_10GBT_STATUS (33) -#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */ -#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */ -#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */ -#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */ -#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */ -#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */ -#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9) /* LP Training Reset Request */ +static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; } +static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; } +extern unsigned efx_mdio_id_oui(u32 id); - -/* Packing of the prt and dev arguments of clause 45 style MDIO into a - * single int so they can be passed into the mdio_read/write functions - * that currently exist. Note that as Falcon is the only current user, - * the packed form is chosen to match what Falcon needs to write into - * a register. This is checked at compile-time so do not change it. If - * your target chip needs things layed out differently you will need - * to unpack the arguments in your chip-specific mdio functions. - */ - /* These are defined by the standard. */ -#define MDIO45_PRT_ID_WIDTH (5) -#define MDIO45_DEV_ID_WIDTH (5) - -/* The prt ID is just packed in immediately to the left of the dev ID */ -#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH) - -#define MDIO45_PRT_ID_MASK ((1 << MDIO45_PRT_DEV_WIDTH) - 1) -/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */ -#define MDIO45_XPRT_ID_WIDTH (MDIO45_PRT_DEV_WIDTH + 1) -#define MDIO45_XPRT_ID_MASK ((1 << MDIO45_XPRT_ID_WIDTH) - 1) -#define MDIO45_XPRT_ID_IS10G (1 << (MDIO45_XPRT_ID_WIDTH - 1)) - - -#define MDIO45_PRT_ID_COMP_LBN MDIO45_DEV_ID_WIDTH -#define MDIO45_PRT_ID_COMP_WIDTH MDIO45_PRT_ID_WIDTH -#define MDIO45_DEV_ID_COMP_LBN 0 -#define MDIO45_DEV_ID_COMP_WIDTH MDIO45_DEV_ID_WIDTH - -/* Compose port and device into a phy_id */ -static inline int mdio_clause45_pack(u8 prt, u8 dev) -{ - efx_dword_t phy_id; - EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt, - MDIO45_DEV_ID_COMP, dev); - return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id); -} - -static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev) +static inline int efx_mdio_read(struct efx_nic *efx, int devad, int addr) { - efx_dword_t phy_id; - EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val); - *prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP); - *dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP); + return efx->mdio.mdio_read(efx->net_dev, efx->mdio.prtad, devad, addr); } -static inline int mdio_clause45_read(struct efx_nic *efx, - u8 prt, u8 dev, u16 addr) +static inline void +efx_mdio_write(struct efx_nic *efx, int devad, int addr, int value) { - return efx->mii.mdio_read(efx->net_dev, - mdio_clause45_pack(prt, dev), addr); + efx->mdio.mdio_write(efx->net_dev, efx->mdio.prtad, devad, addr, value); } -static inline void mdio_clause45_write(struct efx_nic *efx, - u8 prt, u8 dev, u16 addr, int value) -{ - efx->mii.mdio_write(efx->net_dev, - mdio_clause45_pack(prt, dev), addr, value); -} - - -static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd) +static inline u32 efx_mdio_read_id(struct efx_nic *efx, int mmd) { - int phy_id = efx->mii.phy_id; - u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW); - u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI); + u16 id_low = efx_mdio_read(efx, mmd, MDIO_DEVID2); + u16 id_hi = efx_mdio_read(efx, mmd, MDIO_DEVID1); return (id_hi << 16) | (id_low); } -static inline bool mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx) +static inline bool efx_mdio_phyxgxs_lane_sync(struct efx_nic *efx) { 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); + lane_status = efx_mdio_read(efx, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT); - sync = !!(lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)); + sync = !!(lane_status & MDIO_PHYXS_LNSTAT_ALIGN); if (!sync) EFX_LOG(efx, "XGXS lane status: %x\n", lane_status); return sync; } -extern const char *mdio_clause45_mmd_name(int mmd); +extern const char *efx_mdio_mmd_name(int mmd); /* * Reset a specific MMD and wait for reset to clear. @@ -258,54 +64,47 @@ extern const char *mdio_clause45_mmd_name(int mmd); * * This function will sleep */ -extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd, - int spins, int spintime); +extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd, + int spins, int spintime); -/* As mdio_clause45_check_mmd but for multiple MMDs */ -int mdio_clause45_check_mmds(struct efx_nic *efx, - unsigned int mmd_mask, unsigned int fatal_mask); +/* As efx_mdio_check_mmd but for multiple MMDs */ +int efx_mdio_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 bool mdio_clause45_links_ok(struct efx_nic *efx, - unsigned int mmd_mask); +extern bool efx_mdio_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); +extern void efx_mdio_transmit_disable(struct efx_nic *efx); /* Generic part of reconfigure: set/clear loopback bits */ -extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); +extern void efx_mdio_phy_reconfigure(struct efx_nic *efx); /* Set the power state of the specified MMDs */ -extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, - int low_power, unsigned int mmd_mask); - -/* Read (some of) the PHY settings over MDIO */ -extern void mdio_clause45_get_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); - -/* Read (some of) the PHY settings over MDIO */ -extern void -mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd, - u32 xnp, u32 xnp_lpa); +extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask); /* Set (some of) the PHY settings over MDIO */ -extern int mdio_clause45_set_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); +extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); /* Set pause parameters to be advertised through AN (if available) */ -extern void mdio_clause45_set_pause(struct efx_nic *efx); +extern void efx_mdio_set_pause(struct efx_nic *efx); /* Get pause parameters from AN if available (otherwise return * requested pause parameters) */ -enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx); +enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx); /* Wait for specified MMDs to exit reset within a timeout */ -extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, - unsigned int mmd_mask); +extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx, + unsigned int mmd_mask); /* Set or clear flag, debouncing */ -extern void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, - u16 addr, int bit, bool sense); +static inline void +efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr, + int mask, bool state) +{ + mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state); +} #endif /* EFX_MDIO_10G_H */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index e169e5d..457e2f1 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -458,8 +458,6 @@ enum phy_type { PHY_TYPE_MAX /* Insert any new items before this */ }; -#define PHY_ADDR_INVALID 0xff - #define EFX_IS10G(efx) ((efx)->link_speed == 10000) enum nic_state { @@ -758,7 +756,7 @@ union efx_multicast_hash { * @phy_lock: PHY access lock * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) - * @mii: PHY interface + * @mdio: PHY MDIO interface * @phy_mode: PHY operating mode. Serialised by @mac_lock. * @mac_up: MAC link state * @link_up: Link status @@ -845,7 +843,7 @@ struct efx_nic { struct work_struct phy_work; struct efx_phy_operations *phy_op; void *phy_data; - struct mii_if_info mii; + struct mdio_if_info mdio; enum efx_phy_mode phy_mode; bool mac_up; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 0a59808..04379571 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -80,39 +80,38 @@ struct efx_loopback_state { * **************************************************************************/ -static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) +static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) { int rc = 0; + int devad = __ffs(efx->mdio.mmds); 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; + tests->mdio = -1; - physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); - physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); + physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1); + physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2); if ((physid1 == 0x0000) || (physid1 == 0xffff) || (physid2 == 0x0000) || (physid2 == 0xffff)) { - EFX_ERR(efx, "no MII PHY present with ID %d\n", - mii->phy_id); + EFX_ERR(efx, "no MDIO PHY present with ID %d\n", + efx->mdio.prtad); rc = -EINVAL; goto out; } if (EFX_IS10G(efx)) { - rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); + rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0); if (rc) goto out; } out: mutex_unlock(&efx->mac_lock); - tests->mii = rc ? -1 : 1; + tests->mdio = rc ? -1 : 1; return rc; } @@ -673,7 +672,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, /* Online (i.e. non-disruptive) testing * This checks interrupt generation, event delivery and PHY presence. */ - rc = efx_test_mii(efx, tests); + rc = efx_test_mdio(efx, tests); if (rc && !rc_test) rc_test = rc; diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index 39451cf..f6feee0 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -32,7 +32,7 @@ struct efx_loopback_self_tests { */ struct efx_self_tests { /* online tests */ - int mii; + int mdio; int nvram; int interrupt; int eventq_dma[EFX_MAX_CHANNELS]; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index e61dc4d..403f7d70 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -23,10 +23,10 @@ * clause 22 extension MMD, but since it doesn't have all the generic * MMD registers it is pointless to include it here. */ -#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \ - MDIO_MMDREG_DEVS_PCS | \ - MDIO_MMDREG_DEVS_PHYXS | \ - MDIO_MMDREG_DEVS_AN) +#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \ + MDIO_DEVS_PCS | \ + MDIO_DEVS_PHYXS | \ + MDIO_DEVS_AN) #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ (1 << LOOPBACK_PCS) | \ @@ -153,10 +153,6 @@ #define LOOPBACK_NEAR_LBN (8) #define LOOPBACK_NEAR_WIDTH (1) -#define PCS_10GBASET_STAT1 32 -#define PCS_10GBASET_BLKLK_LBN 0 -#define PCS_10GBASET_BLKLK_WIDTH 1 - /* Boot status register */ #define PCS_BOOT_STATUS_REG 53248 #define PCS_BOOT_FATAL_ERROR_LBN 0 @@ -206,10 +202,8 @@ static ssize_t show_phy_short_reach(struct device *dev, struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); int reg; - reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_PMAPMD_10GBT_TXPWR); - return sprintf(buf, "%d\n", - !!(reg & (1 << MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN))); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR); + return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT)); } static ssize_t set_phy_short_reach(struct device *dev, @@ -219,10 +213,9 @@ static ssize_t set_phy_short_reach(struct device *dev, struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); rtnl_lock(); - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_PMAPMD_10GBT_TXPWR, - MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN, - count != 0 && *buf != '0'); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, + MDIO_PMA_10GBT_TXPWR_SHORT, + count != 0 && *buf != '0'); efx_reconfigure_port(efx); rtnl_unlock(); @@ -238,9 +231,8 @@ int sft9001_wait_boot(struct efx_nic *efx) int boot_stat; for (;;) { - boot_stat = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PCS, - PCS_BOOT_STATUS_REG); + boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS, + PCS_BOOT_STATUS_REG); if (boot_stat >= 0) { EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat); switch (boot_stat & @@ -286,38 +278,32 @@ int sft9001_wait_boot(struct efx_nic *efx) static int tenxpress_init(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; int reg; if (efx->phy_type == PHY_TYPE_SFX7101) { /* Enable 312.5 MHz clock */ - mdio_clause45_write(efx, phy_id, - MDIO_MMD_PCS, PCS_TEST_SELECT_REG, - 1 << CLK312_EN_LBN); + efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, + 1 << CLK312_EN_LBN); } else { /* Enable 312.5 MHz clock and GMII */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | (1 << PMA_PMD_EXT_CLK_OUT_LBN) | (1 << PMA_PMD_EXT_CLK312_LBN) | (1 << PMA_PMD_EXT_ROBUST_LBN)); - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG, GPHY_ISOLATE_LBN, - false); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); + efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN, + false); } /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ if (efx->phy_type == PHY_TYPE_SFX7101) { - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_CTRL_REG, - PMA_PMA_LED_ACTIVITY_LBN, - true); - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG, + 1 << PMA_PMA_LED_ACTIVITY_LBN, true); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, + PMA_PMD_LED_DEFAULT); } return 0; @@ -337,22 +323,19 @@ static int tenxpress_phy_init(struct efx_nic *efx) if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { if (efx->phy_type == PHY_TYPE_SFT9001A) { int reg; - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); mdelay(200); } - rc = mdio_clause45_wait_reset_mmds(efx, - TENXPRESS_REQUIRED_DEVS); + rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) goto fail; - rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); + rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); if (rc < 0) goto fail; } @@ -360,7 +343,7 @@ static int tenxpress_phy_init(struct efx_nic *efx) rc = tenxpress_init(efx); if (rc < 0) goto fail; - mdio_clause45_set_pause(efx); + efx_mdio_set_pause(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, @@ -395,17 +378,14 @@ static int tenxpress_special_reset(struct efx_nic *efx) efx_stats_disable(efx); /* Initiate reset */ - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); mdelay(200); /* Wait for the blocks to come out of reset */ - rc = mdio_clause45_wait_reset_mmds(efx, - TENXPRESS_REQUIRED_DEVS); + rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) goto out; @@ -424,7 +404,6 @@ out: static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) { struct tenxpress_phy_data *pd = efx->phy_data; - int phy_id = efx->mii.phy_id; bool bad_lp; int reg; @@ -432,11 +411,10 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) bad_lp = false; } else { /* Check that AN has started but not completed. */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_STATUS); - if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN))) + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1); + if (!(reg & MDIO_AN_STAT1_LPABLE)) return; /* LP status is unknown */ - bad_lp = !(reg & (1 << MDIO_AN_STATUS_AN_DONE_LBN)); + bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE); if (bad_lp) pd->bad_lp_tries++; } @@ -448,8 +426,8 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) /* Use the RX (red) LED as an error indicator once we've seen AN * failure several times in a row, and also log a message. */ if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG); reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); if (!bad_lp) { reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; @@ -460,23 +438,22 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) " supports 10GBASE-T ONLY, so no link can" " be established\n"); } - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG, reg); pd->bad_lp_tries = bad_lp; } } static bool sfx7101_link_ok(struct efx_nic *efx) { - return mdio_clause45_links_ok(efx, - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_PCS | - MDIO_MMDREG_DEVS_PHYXS); + return efx_mdio_links_ok(efx, + MDIO_DEVS_PMAPMD | + MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS); } static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; u32 reg; if (efx_phy_mode_disabled(efx->phy_mode)) @@ -484,50 +461,43 @@ static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) else if (efx->loopback_mode == LOOPBACK_GPHY) return true; else if (efx->loopback_mode) - return mdio_clause45_links_ok(efx, - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_PHYXS); + return efx_mdio_links_ok(efx, + MDIO_DEVS_PMAPMD | + MDIO_DEVS_PHYXS); /* We must use the same definition of link state as LASI, * otherwise we can miss a link state transition */ if (ecmd->speed == 10000) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - PCS_10GBASET_STAT1); - return reg & (1 << PCS_10GBASET_BLKLK_LBN); + reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1); + return reg & MDIO_PCS_10GBRT_STAT1_BLKLK; } else { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_STATUS_REG); + reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG); return reg & (1 << C22EXT_STATUS_LINK_LBN); } } static void tenxpress_ext_loopback(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, - PHYXS_TEST1, LOOPBACK_NEAR_LBN, - efx->loopback_mode == LOOPBACK_PHYXS); + efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1, + 1 << LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_PHYXS); if (efx->phy_type != PHY_TYPE_SFX7101) - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG, - GPHY_LOOPBACK_NEAR_LBN, - efx->loopback_mode == LOOPBACK_GPHY); + efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG, + 1 << GPHY_LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_GPHY); } static void tenxpress_low_power(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - if (efx->phy_type == PHY_TYPE_SFX7101) - mdio_clause45_set_mmds_lpower( + efx_mdio_set_mmds_lpower( efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER), TENXPRESS_REQUIRED_DEVS); else - mdio_clause45_set_flag( - efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, PMA_PMD_EXT_LPOWER_LBN, + efx_mdio_set_flag( + efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, + 1 << PMA_PMD_EXT_LPOWER_LBN, !!(efx->phy_mode & PHY_MODE_LOW_POWER)); } @@ -568,8 +538,8 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) WARN_ON(rc); } - mdio_clause45_transmit_disable(efx); - mdio_clause45_phy_reconfigure(efx); + efx_mdio_transmit_disable(efx); + efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); phy_data->loopback_mode = efx->loopback_mode; @@ -585,7 +555,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) efx->link_fd = ecmd.duplex == DUPLEX_FULL; efx->link_up = sft9001_link_ok(efx, &ecmd); } - efx->link_fc = mdio_clause45_get_pause(efx); + efx->link_fc = efx_mdio_get_pause(efx); } /* Poll PHY for interrupt */ @@ -599,7 +569,7 @@ static void tenxpress_phy_poll(struct efx_nic *efx) if (link_ok != efx->link_up) { change = true; } else { - unsigned int link_fc = mdio_clause45_get_pause(efx); + unsigned int link_fc = efx_mdio_get_pause(efx); if (link_fc != efx->link_fc) change = true; } @@ -609,9 +579,8 @@ static void tenxpress_phy_poll(struct efx_nic *efx) if (link_ok != efx->link_up) change = true; } else { - u32 status = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_LASI_STATUS); + int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_LASI_STATUS); if (status & (1 << PMA_PMD_LS_ALARM_LBN)) change = true; } @@ -634,8 +603,7 @@ static void tenxpress_phy_fini(struct efx_nic *efx) if (efx->phy_type == PHY_TYPE_SFX7101) { /* Power down the LNPGA */ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); /* Waiting here ensures that the board fini, which can turn * off the power to the PHY, won't get run until the LNPGA @@ -661,8 +629,7 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink) else reg = PMA_PMD_LED_DEFAULT; - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg); } static const char *const sfx7101_test_names[] = { @@ -698,7 +665,6 @@ static const char *const sft9001_test_names[] = { static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) { struct ethtool_cmd ecmd; - int phy_id = efx->mii.phy_id; int rc = 0, rc2, i, ctrl_reg, res_reg; if (flags & ETH_TEST_FL_OFFLINE) @@ -717,11 +683,10 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) * must reset the PHY to resume normal service. */ ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN); } - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_CTRL_REG, ctrl_reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG, + ctrl_reg); i = 0; - while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_CTRL_REG) & + while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) & (1 << CDIAG_CTRL_IN_PROG_LBN)) { if (++i == 50) { rc = -ETIMEDOUT; @@ -729,15 +694,13 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) } msleep(100); } - res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_RES_REG); + res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG); for (i = 0; i < 4; i++) { int pair_res = (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) & ((1 << CDIAG_RES_WIDTH) - 1); - int len_reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_LEN_REG + i); + int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_LEN_REG + i); if (pair_res == CDIAG_RES_OK) results[1 + i] = 1; else if (pair_res == CDIAG_RES_INVALID) @@ -769,32 +732,27 @@ out: static void tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; u32 adv = 0, lpa = 0; int reg; if (efx->phy_type != PHY_TYPE_SFX7101) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_CTRL); + reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL); if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN)) adv |= ADVERTISED_1000baseT_Full; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_STATUS); + reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS); if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN)) lpa |= ADVERTISED_1000baseT_Half; if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN)) lpa |= ADVERTISED_1000baseT_Full; } - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_CTRL); - if (reg & (1 << MDIO_AN_10GBT_CTRL_ADV_10G_LBN)) + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL); + if (reg & MDIO_AN_10GBT_CTRL_ADV10G) adv |= ADVERTISED_10000baseT_Full; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_STATUS); - if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)) + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); + if (reg & MDIO_AN_10GBT_STAT_LP10G) lpa |= ADVERTISED_10000baseT_Full; - mdio_clause45_get_settings_ext(efx, ecmd, adv, lpa); + mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); if (efx->phy_type != PHY_TYPE_SFX7101) ecmd->supported |= (SUPPORTED_100baseT_Full | @@ -813,29 +771,24 @@ static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) if (!ecmd->autoneg) return -EINVAL; - return mdio_clause45_set_settings(efx, ecmd); + return efx_mdio_set_settings(efx, ecmd); } static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) { - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV_10G_LBN, - advertising & ADVERTISED_10000baseT_Full); + efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV10G, + advertising & ADVERTISED_10000baseT_Full); } static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) { - int phy_id = efx->mii.phy_id; - - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_CTRL, - C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, - advertising & ADVERTISED_1000baseT_Full); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV_10G_LBN, - advertising & ADVERTISED_10000baseT_Full); + efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL, + 1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, + advertising & ADVERTISED_1000baseT_Full); + efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV10G, + advertising & ADVERTISED_10000baseT_Full); } struct efx_phy_operations falcon_sfx7101_phy_ops = { diff --git a/drivers/net/sfc/xenpack.h b/drivers/net/sfc/xenpack.h index b0d1f22..4e52286 100644 --- a/drivers/net/sfc/xenpack.h +++ b/drivers/net/sfc/xenpack.h @@ -34,29 +34,24 @@ /* Enable LASI interrupts for PHY */ static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx) { - int reg; - int phy_id = efx->mii.phy_id; /* Read to clear LASI status register */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_XP_LASI_STAT); + efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT); - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL, + XP_LASI_LS_ALARM); } /* Read the LASI interrupt status to clear the interrupt. */ static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx) { /* Read to clear link status alarm */ - return mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT); + return efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT); } /* Turn off LASI interrupts */ static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx) { - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_XP_LASI_CTRL, 0); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL, 0); } #endif /* EFX_XENPACK_H */ diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index bb1ef77..aad2dca 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -19,9 +19,9 @@ #include "phy.h" #include "falcon.h" -#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PCS | \ - MDIO_MMDREG_DEVS_PMAPMD | \ - MDIO_MMDREG_DEVS_PHYXS) +#define XFP_REQUIRED_DEVS (MDIO_DEVS_PCS | \ + MDIO_DEVS_PMAPMD | \ + MDIO_DEVS_PHYXS) #define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ @@ -49,8 +49,7 @@ void xfp_set_led(struct efx_nic *p, int led, int mode) { int addr = MDIO_QUAKE_LED0_REG + led; - mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr, - mode); + efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode); } struct xfp_phy_data { @@ -63,14 +62,12 @@ struct xfp_phy_data { static int qt2025c_wait_reset(struct efx_nic *efx) { unsigned long timeout = jiffies + 10 * HZ; - int phy_id = efx->mii.phy_id; int reg, old_counter = 0; /* Wait for firmware heartbeat to start */ for (;;) { int counter; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - PCS_FW_HEARTBEAT_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG); if (reg < 0) return reg; counter = ((reg >> PCS_FW_HEARTB_LBN) & @@ -86,8 +83,7 @@ static int qt2025c_wait_reset(struct efx_nic *efx) /* Wait for firmware status to look good */ for (;;) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - PCS_UC8051_STATUS_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); if (reg < 0) return reg; if ((reg & @@ -109,9 +105,9 @@ static int xfp_reset_phy(struct efx_nic *efx) { int rc; - rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS, - XFP_MAX_RESET_TIME / XFP_RESET_WAIT, - XFP_RESET_WAIT); + rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, + XFP_MAX_RESET_TIME / XFP_RESET_WAIT, + XFP_RESET_WAIT); if (rc < 0) goto fail; @@ -126,8 +122,7 @@ static int xfp_reset_phy(struct efx_nic *efx) /* Check that all the MMDs we expect are present and responding. We * expect faults on some if the link is down, but not on the PHY XS */ - rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS, - MDIO_MMDREG_DEVS_PHYXS); + rc = efx_mdio_check_mmds(efx, XFP_REQUIRED_DEVS, MDIO_DEVS_PHYXS); if (rc < 0) goto fail; @@ -143,7 +138,7 @@ static int xfp_reset_phy(struct efx_nic *efx) static int xfp_phy_init(struct efx_nic *efx) { struct xfp_phy_data *phy_data; - u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS); + u32 devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); int rc; phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL); @@ -152,8 +147,8 @@ static int xfp_phy_init(struct efx_nic *efx) efx->phy_data = phy_data; EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", - devid, mdio_id_oui(devid), mdio_id_model(devid), - mdio_id_rev(devid)); + devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), + efx_mdio_id_rev(devid)); phy_data->phy_mode = efx->phy_mode; @@ -179,7 +174,7 @@ static void xfp_phy_clear_interrupt(struct efx_nic *efx) static int xfp_link_ok(struct efx_nic *efx) { - return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS); + return efx_mdio_links_ok(efx, XFP_REQUIRED_DEVS); } static void xfp_phy_poll(struct efx_nic *efx) @@ -200,9 +195,9 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) * or optical transceivers, varying somewhat between * firmware versions. Only 'static mode' appears to * cover everything. */ - mdio_clause45_set_flag( - efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_FTX_CTRL2_REG, PMA_PMD_FTX_STATIC_LBN, + mdio_set_flag( + &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD, + PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN, efx->phy_mode & PHY_MODE_TX_DISABLED || efx->phy_mode & PHY_MODE_LOW_POWER || efx->loopback_mode == LOOPBACK_PCS || @@ -213,10 +208,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) xfp_reset_phy(efx); - mdio_clause45_transmit_disable(efx); + efx_mdio_transmit_disable(efx); } - mdio_clause45_phy_reconfigure(efx); + efx_mdio_phy_reconfigure(efx); phy_data->phy_mode = efx->phy_mode; efx->link_up = xfp_link_ok(efx); @@ -225,6 +220,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) efx->link_fc = efx->wanted_fc; } +static void xfp_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + mdio45_ethtool_gset(&efx->mdio, ecmd); +} static void xfp_phy_fini(struct efx_nic *efx) { @@ -243,8 +242,8 @@ struct efx_phy_operations falcon_xfp_phy_ops = { .poll = xfp_phy_poll, .fini = xfp_phy_fini, .clear_interrupt = xfp_phy_clear_interrupt, - .get_settings = mdio_clause45_get_settings, - .set_settings = mdio_clause45_set_settings, + .get_settings = xfp_phy_get_settings, + .set_settings = efx_mdio_set_settings, .mmds = XFP_REQUIRED_DEVS, .loopbacks = XFP_LOOPBACKS, }; -- cgit v0.10.2 From 23c3320cb039debfb94b27e8e9bfe26dd47692c3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:06:34 +0000 Subject: chelsio: Use generic MDIO definitions and mdio_mii_ioctl() Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2f81db5..1ccd547 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2450,6 +2450,7 @@ config CHELSIO_T1 tristate "Chelsio 10Gb Ethernet support" depends on PCI select CRC32 + select MDIO help This driver supports Chelsio gigabit and 10-gigabit Ethernet cards. More information about adapter features and diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 4bd2455..699d22c 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h index 79d855e..8b5165a 100644 --- a/drivers/net/chelsio/cphy.h +++ b/drivers/net/chelsio/cphy.h @@ -43,10 +43,11 @@ struct mdio_ops { void (*init)(adapter_t *adapter, const struct board_info *bi); - int (*read)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *val); - int (*write)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr); + int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val); + unsigned mode_support; }; /* PHY interrupt types */ @@ -83,11 +84,12 @@ struct cphy_ops { int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, int *duplex, int *fc); + + u32 mmds; }; /* A PHY instance */ struct cphy { - int addr; /* PHY address */ int state; /* Link status state machine */ adapter_t *adapter; /* associated adapter */ @@ -101,36 +103,37 @@ struct cphy { u32 elmer_gpo; const struct cphy_ops *ops; /* PHY operations */ - int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *val); - int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + struct mdio_if_info mdio; struct cphy_instance *instance; }; /* Convenience MDIO read/write wrappers */ -static inline int mdio_read(struct cphy *cphy, int mmd, int reg, - unsigned int *valp) +static inline int cphy_mdio_read(struct cphy *cphy, int mmd, int reg, + unsigned int *valp) { - return cphy->mdio_read(cphy->adapter, cphy->addr, mmd, reg, valp); + int rc = cphy->mdio.mdio_read(cphy->mdio.dev, cphy->mdio.prtad, mmd, + reg); + *valp = (rc >= 0) ? rc : -1; + return (rc >= 0) ? 0 : rc; } -static inline int mdio_write(struct cphy *cphy, int mmd, int reg, - unsigned int val) +static inline int cphy_mdio_write(struct cphy *cphy, int mmd, int reg, + unsigned int val) { - return cphy->mdio_write(cphy->adapter, cphy->addr, mmd, reg, val); + return cphy->mdio.mdio_write(cphy->mdio.dev, cphy->mdio.prtad, mmd, + reg, val); } static inline int simple_mdio_read(struct cphy *cphy, int reg, unsigned int *valp) { - return mdio_read(cphy, 0, reg, valp); + return cphy_mdio_read(cphy, MDIO_DEVAD_NONE, reg, valp); } static inline int simple_mdio_write(struct cphy *cphy, int reg, unsigned int val) { - return mdio_write(cphy, 0, reg, val); + return cphy_mdio_write(cphy, MDIO_DEVAD_NONE, reg, val); } /* Convenience initializer */ @@ -139,11 +142,13 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, const struct mdio_ops *mdio_ops) { phy->adapter = adapter; - phy->addr = phy_addr; phy->ops = phy_ops; if (mdio_ops) { - phy->mdio_read = mdio_ops->read; - phy->mdio_write = mdio_ops->write; + phy->mdio.prtad = phy_addr; + phy->mdio.mmds = phy_ops->mmds; + phy->mdio.mode_support = mdio_ops->mode_support; + phy->mdio.mdio_read = mdio_ops->read; + phy->mdio.mdio_write = mdio_ops->write; } } diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index fa06994..082cdb2 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -589,7 +589,7 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy->addr; + cmd->phy_address = p->phy->mdio.prtad; cmd->transceiver = XCVR_EXTERNAL; cmd->autoneg = p->link_config.autoneg; cmd->maxtxpkt = 0; @@ -849,39 +849,9 @@ static const struct ethtool_ops t1_ethtool_ops = { static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct adapter *adapter = dev->ml_priv; - struct mii_ioctl_data *data = if_mii(req); - - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = adapter->port[dev->if_port].phy->addr; - /* FALLTHRU */ - case SIOCGMIIREG: { - struct cphy *phy = adapter->port[dev->if_port].phy; - u32 val; - - if (!phy->mdio_read) - return -EOPNOTSUPP; - phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f, - &val); - data->val_out = val; - break; - } - case SIOCSMIIREG: { - struct cphy *phy = adapter->port[dev->if_port].phy; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (!phy->mdio_write) - return -EOPNOTSUPP; - phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f, - data->val_in); - break; - } + struct mdio_if_info *mdio = &adapter->port[dev->if_port].phy->mdio; - default: - return -EOPNOTSUPP; - } - return 0; + return mdio_mii_ioctl(mdio, if_mii(req), cmd); } static int t1_change_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c index cd85604..29e0cba 100644 --- a/drivers/net/chelsio/mv88x201x.c +++ b/drivers/net/chelsio/mv88x201x.c @@ -53,7 +53,7 @@ static int led_init(struct cphy *cphy) * Writing these bits maps control to another * register. mmd(0x1) addr(0x7) */ - mdio_write(cphy, 0x3, 0x8304, 0xdddd); + cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8304, 0xdddd); return 0; } @@ -62,14 +62,14 @@ static int led_link(struct cphy *cphy, u32 do_enable) u32 led = 0; #define LINK_ENABLE_BIT 0x1 - mdio_read(cphy, 0x1, 0x7, &led); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, &led); if (do_enable & LINK_ENABLE_BIT) { led |= LINK_ENABLE_BIT; - mdio_write(cphy, 0x1, 0x7, led); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); } else { led &= ~LINK_ENABLE_BIT; - mdio_write(cphy, 0x1, 0x7, led); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); } return 0; } @@ -86,7 +86,7 @@ static int mv88x201x_reset(struct cphy *cphy, int wait) static int mv88x201x_interrupt_enable(struct cphy *cphy) { /* Enable PHY LASI interrupts. */ - mdio_write(cphy, 0x1, 0x9002, 0x1); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, 0x9002, 0x1); /* Enable Marvell interrupts through Elmer0. */ if (t1_is_asic(cphy->adapter)) { @@ -102,7 +102,7 @@ static int mv88x201x_interrupt_enable(struct cphy *cphy) static int mv88x201x_interrupt_disable(struct cphy *cphy) { /* Disable PHY LASI interrupts. */ - mdio_write(cphy, 0x1, 0x9002, 0x0); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, 0x9002, 0x0); /* Disable Marvell interrupts through Elmer0. */ if (t1_is_asic(cphy->adapter)) { @@ -122,25 +122,25 @@ static int mv88x201x_interrupt_clear(struct cphy *cphy) #ifdef MV88x2010_LINK_STATUS_BUGS /* Required to read twice before clear takes affect. */ - mdio_read(cphy, 0x1, 0x9003, &val); - mdio_read(cphy, 0x1, 0x9004, &val); - mdio_read(cphy, 0x1, 0x9005, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9003, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9004, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9005, &val); /* Read this register after the others above it else * the register doesn't clear correctly. */ - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); #endif /* Clear link status. */ - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); /* Clear PHY LASI interrupts. */ - mdio_read(cphy, 0x1, 0x9005, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9005, &val); #ifdef MV88x2010_LINK_STATUS_BUGS /* Do it again. */ - mdio_read(cphy, 0x1, 0x9003, &val); - mdio_read(cphy, 0x1, 0x9004, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9003, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9004, &val); #endif /* Clear Marvell interrupts through Elmer0. */ @@ -172,13 +172,12 @@ static int mv88x201x_get_link_status(struct cphy *cphy, int *link_ok, int *speed, int *duplex, int *fc) { u32 val = 0; -#define LINK_STATUS_BIT 0x4 if (link_ok) { /* Read link status. */ - mdio_read(cphy, 0x1, 0x1, &val); - val &= LINK_STATUS_BIT; - *link_ok = (val == LINK_STATUS_BIT); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); + val &= MDIO_STAT1_LSTATUS; + *link_ok = (val == MDIO_STAT1_LSTATUS); /* Turn on/off Link LED */ led_link(cphy, *link_ok); } @@ -205,6 +204,8 @@ static struct cphy_ops mv88x201x_ops = { .interrupt_handler = mv88x201x_interrupt_handler, .get_link_status = mv88x201x_get_link_status, .set_loopback = mv88x201x_set_loopback, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS | MDIO_DEVS_WIS), }; static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, @@ -219,12 +220,12 @@ static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, cphy_init(cphy, adapter, phy_addr, &mv88x201x_ops, mdio_ops); /* Commands the PHY to enable XFP's clock. */ - mdio_read(cphy, 0x3, 0x8300, &val); - mdio_write(cphy, 0x3, 0x8300, val | 1); + cphy_mdio_read(cphy, MDIO_MMD_PCS, 0x8300, &val); + cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8300, val | 1); /* Clear link status. Required because of a bug in the PHY. */ - mdio_read(cphy, 0x1, 0x8, &val); - mdio_read(cphy, 0x3, 0x8, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT2, &val); + cphy_mdio_read(cphy, MDIO_MMD_PCS, MDIO_STAT2, &val); /* Allows for Link,Ack LED turn on/off */ led_init(cphy); diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 040acd2..977c7e0 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -43,11 +43,11 @@ static int my3126_interrupt_handler(struct cphy *cphy) adapter = cphy->adapter; if (cphy->count == 50) { - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); val16 = (u16) val; status = cphy->bmsr ^ val16; - if (status & BMSR_LSTATUS) + if (status & MDIO_STAT1_LSTATUS) t1_link_changed(adapter, 0); cphy->bmsr = val16; @@ -114,14 +114,14 @@ static int my3126_get_link_status(struct cphy *cphy, adapter_t *adapter; adapter = cphy->adapter; - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); val16 = (u16) val; /* Populate elmer_gpo with the register value */ t1_tpi_read(adapter, A_ELMER0_GPO, &val); cphy->elmer_gpo = val; - *link_ok = (val16 & BMSR_LSTATUS); + *link_ok = (val16 & MDIO_STAT1_LSTATUS); if (*link_ok) { /* Turn on the LED. */ @@ -163,6 +163,8 @@ static struct cphy_ops my3126_ops = { .interrupt_handler = my3126_interrupt_handler, .get_link_status = my3126_get_link_status, .set_loopback = my3126_set_loopback, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS), }; static struct cphy *my3126_phy_create(adapter_t *adapter, diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 7adf302..2564312 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -284,32 +284,29 @@ static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi) /* * Elmer MI1 MDIO read/write operations. */ -static int mi1_mdio_read(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int mi1_mdio_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); - - if (mmd_addr) - return -EINVAL; + unsigned int val; spin_lock(&adapter->tpi_lock); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_READ); mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp); + __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); spin_unlock(&adapter->tpi_lock); - return 0; + return val; } -static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); - if (mmd_addr) - return -EINVAL; - spin_lock(&adapter->tpi_lock); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val); @@ -324,16 +321,19 @@ static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr, static const struct mdio_ops mi1_mdio_ops = { .init = mi1_mdio_init, .read = mi1_mdio_read, - .write = mi1_mdio_write + .write = mi1_mdio_write, + .mode_support = MDIO_SUPPORTS_C22 }; #endif #endif -static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int mi1_mdio_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); + unsigned int val; spin_lock(&adapter->tpi_lock); @@ -350,14 +350,15 @@ static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); /* Read the data. */ - __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp); + __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); spin_unlock(&adapter->tpi_lock); - return 0; + return val; } -static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int mi1_mdio_ext_write(struct net_device *dev, int phy_addr, + int mmd_addr, u16 reg_addr, u16 val) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); spin_lock(&adapter->tpi_lock); @@ -380,7 +381,8 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, static const struct mdio_ops mi1_mdio_ext_ops = { .init = mi1_mdio_init, .read = mi1_mdio_ext_read, - .write = mi1_mdio_ext_write + .write = mi1_mdio_ext_write, + .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 }; enum { @@ -1140,6 +1142,7 @@ int __devinit t1_init_sw_modules(adapter_t *adapter, adapter->name, i); goto error; } + adapter->port[i].phy->mdio.dev = adapter->port[i].dev; adapter->port[i].mac = mac = bi->gmac->create(adapter, i); if (!mac) { -- cgit v0.10.2 From 0f07c4ee8c800923ae7918c231532a9256233eed Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:07:20 +0000 Subject: cxgb3: Use generic MDIO definitions and mdio_mii_ioctl() Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1ccd547..435bbc9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2483,6 +2483,7 @@ config CHELSIO_T3 tristate "Chelsio Communications T3 10Gb Ethernet support" depends on CHELSIO_T3_DEPENDS select FW_LOADER + select MDIO help This driver supports Chelsio T3-based gigabit and 10Gb Ethernet adapters. diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index e1b2249..bebc00d 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -33,14 +33,6 @@ #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, @@ -74,8 +66,8 @@ static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) 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); + err = t3_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, @@ -86,7 +78,8 @@ static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) static void ael100x_txon(struct cphy *phy) { - int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; + int tx_on_gpio = + phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; msleep(100); t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); @@ -97,10 +90,11 @@ static int ael1002_power_down(struct cphy *phy, int enable) { int err; - err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable); + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable); if (!err) - err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, - BMCR_PDOWN, enable ? BMCR_PDOWN : 0); + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, enable); return err; } @@ -109,11 +103,11 @@ static int ael1002_reset(struct cphy *phy, int wait) int err; if ((err = ael1002_power_down(phy, 0)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) || - (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) || + (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN, 0, 1 << 5))) return err; return 0; @@ -132,12 +126,15 @@ static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed, { if (link_ok) { unsigned int stat0, stat1, stat2; - int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, + MDIO_PMA_RXDET, &stat0); if (!err) - err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_R, &stat1); + err = t3_mdio_read(phy, MDIO_MMD_PCS, + MDIO_PCS_10GBRT_STAT1, &stat1); if (!err) - err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); + err = t3_mdio_read(phy, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT, &stat2); if (err) return err; *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; @@ -157,6 +154,7 @@ static struct cphy_ops ael1002_ops = { .intr_handler = ael1002_intr_noop, .get_link_status = get_link_status_r, .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -171,13 +169,13 @@ int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, static int ael1006_reset(struct cphy *phy, int wait) { - return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); + return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait); } static int ael1006_power_down(struct cphy *phy, int enable) { - return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, - BMCR_PDOWN, enable ? BMCR_PDOWN : 0); + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable); } static struct cphy_ops ael1006_ops = { @@ -188,6 +186,7 @@ static struct cphy_ops ael1006_ops = { .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_r, .power_down = ael1006_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -203,9 +202,9 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, static int ael2005_setup_sr_edc(struct cphy *phy) { 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 }, + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 }, + { MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a }, + { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 }, { 0, 0, 0, 0 } }; static u16 sr_edc[] = { @@ -490,8 +489,8 @@ static int ael2005_setup_sr_edc(struct cphy *phy) 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]); + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i], + sr_edc[i + 1]); if (!err) phy->priv = edc_sr; return err; @@ -500,12 +499,12 @@ static int ael2005_setup_sr_edc(struct cphy *phy) static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) { static struct reg_val regs[] = { - { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5a00 }, + { MDIO_MMD_PMAPMD, 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 }, + { MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 }, + { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 }, { 0, 0, 0, 0 } }; static u16 twinax_edc[] = { @@ -887,8 +886,8 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) 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]); + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], + twinax_edc[i + 1]); if (!err) phy->priv = edc_twinax; return err; @@ -899,26 +898,26 @@ static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) 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); + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, 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); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); if (err) return err; if ((stat & 3) == 1) { - err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_DATA, - &data); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, 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); + phy->mdio.prtad, word_addr); return -ETIMEDOUT; } @@ -927,7 +926,7 @@ 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); + v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat); if (v) return v; @@ -971,48 +970,48 @@ unknown: static int ael2005_intr_enable(struct cphy *phy) { - int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200); + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, 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); + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, 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); + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, 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 }, + { MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 }, + { MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 }, + { MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_MMD_PMAPMD, 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 }, + { MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 }, + { MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 }, { 0, 0, 0, 0 } }; int err; unsigned int lasi_ctrl; - err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, LASI_CTRL, &lasi_ctrl); if (err) return err; - err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 0); + err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0); if (err) return err; @@ -1051,13 +1050,13 @@ 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); + ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, 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); + ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, + 0xd00); if (ret) return ret; @@ -1098,6 +1097,7 @@ static struct cphy_ops ael2005_ops = { .intr_handler = ael2005_intr_handler, .get_link_status = get_link_status_r, .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -1107,7 +1107,7 @@ int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, 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, + return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0, 1 << 5); } @@ -1119,12 +1119,15 @@ static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, { if (link_ok) { unsigned int stat0, stat1, stat2; - int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, + MDIO_PMA_RXDET, &stat0); if (!err) - err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_X, &stat1); + err = t3_mdio_read(phy, MDIO_MMD_PCS, + MDIO_PCS_10GBX_STAT1, &stat1); if (!err) - err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); + err = t3_mdio_read(phy, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT, &stat2); if (err) return err; *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1; @@ -1144,6 +1147,7 @@ static struct cphy_ops qt2045_ops = { .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_x, .power_down = ael1006_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -1159,9 +1163,10 @@ int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, * Some cards where the PHY is supposed to be at address 0 actually * have it at 1. */ - if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && + if (!phy_addr && + !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) && stat == 0xffff) - phy->addr = 1; + phy->mdio.prtad = 1; return 0; } @@ -1175,15 +1180,16 @@ static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, { if (link_ok) { unsigned int status; + int prtad = phy->mdio.prtad; status = t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) | + XGM_REG(A_XGM_SERDES_STAT0, prtad)) | t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) | + XGM_REG(A_XGM_SERDES_STAT1, prtad)) | t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) | + XGM_REG(A_XGM_SERDES_STAT2, prtad)) | t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT3, phy->addr)); + XGM_REG(A_XGM_SERDES_STAT3, prtad)); *link_ok = !(status & F_LOWSIG0); } if (speed) @@ -1211,7 +1217,7 @@ static struct cphy_ops xaui_direct_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, MDIO_PRTAD_NONE, &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 e508dc3..3147789 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include "version.h" #define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__) @@ -184,10 +184,11 @@ struct cphy; struct adapter; struct mdio_ops { - int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *val); - int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr); + int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val); + unsigned mode_support; }; struct adapter_info { @@ -520,17 +521,6 @@ enum { MAC_RXFIFO_SIZE = 32768 }; -/* 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_ANEG = 7, - MDIO_DEV_VEND1 = 30, - MDIO_DEV_VEND2 = 31 -}; - /* LASI control and status registers */ enum { RX_ALARM_CTRL = 0x9000, @@ -583,11 +573,12 @@ struct cphy_ops { int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, int *duplex, int *fc); int (*power_down)(struct cphy *phy, int enable); + + u32 mmds; }; /* A PHY instance */ struct cphy { - u8 addr; /* PHY address */ u8 modtype; /* PHY module type */ short priv; /* scratch pad */ unsigned int caps; /* PHY capabilities */ @@ -595,23 +586,23 @@ struct cphy { 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, - int reg_addr, unsigned int *val); - int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + struct mdio_if_info mdio; }; /* Convenience MDIO read/write wrappers */ -static inline int mdio_read(struct cphy *phy, int mmd, int reg, - unsigned int *valp) +static inline int t3_mdio_read(struct cphy *phy, int mmd, int reg, + unsigned int *valp) { - return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp); + int rc = phy->mdio.mdio_read(phy->mdio.dev, phy->mdio.prtad, mmd, reg); + *valp = (rc >= 0) ? rc : -1; + return (rc >= 0) ? 0 : rc; } -static inline int mdio_write(struct cphy *phy, int mmd, int reg, - unsigned int val) +static inline int t3_mdio_write(struct cphy *phy, int mmd, int reg, + unsigned int val) { - return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val); + return phy->mdio.mdio_write(phy->mdio.dev, phy->mdio.prtad, mmd, + reg, val); } /* Convenience initializer */ @@ -620,14 +611,16 @@ static inline void cphy_init(struct cphy *phy, struct adapter *adapter, const struct mdio_ops *mdio_ops, unsigned int caps, const char *desc) { - 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; - phy->mdio_write = mdio_ops->write; + phy->mdio.prtad = phy_addr; + phy->mdio.mmds = phy_ops->mmds; + phy->mdio.mode_support = mdio_ops->mode_support; + phy->mdio.mdio_read = mdio_ops->read; + phy->mdio.mdio_write = mdio_ops->write; } } diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 7ea4841..0b87fee 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -1593,7 +1593,7 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy.addr; + cmd->phy_address = p->phy.mdio.prtad; cmd->transceiver = XCVR_EXTERNAL; cmd->autoneg = p->link_config.autoneg; cmd->maxtxpkt = 0; @@ -2308,70 +2308,25 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) struct mii_ioctl_data *data = if_mii(req); struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - int ret, mmd; switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = pi->phy.addr; + case SIOCGMIIREG: + case SIOCSMIIREG: + /* Convert phy_id from older PRTAD/DEVAD format */ + if (is_10G(adapter) && + !mdio_phy_id_is_c45(data->phy_id) && + (data->phy_id & 0x1f00) && + !(data->phy_id & 0xe0e0)) + data->phy_id = mdio_phy_id_c45(data->phy_id >> 8, + data->phy_id & 0x1f); /* FALLTHRU */ - case SIOCGMIIREG:{ - u32 val; - struct cphy *phy = &pi->phy; - - if (!phy->mdio_read) - return -EOPNOTSUPP; - if (is_10G(adapter)) { - mmd = data->phy_id >> 8; - if (!mmd) - mmd = MDIO_DEV_PCS; - else if (mmd > MDIO_DEV_VEND2) - return -EINVAL; - - ret = - phy->mdio_read(adapter, data->phy_id & 0x1f, - mmd, data->reg_num, &val); - } else - ret = - phy->mdio_read(adapter, data->phy_id & 0x1f, - 0, data->reg_num & 0x1f, - &val); - if (!ret) - data->val_out = val; - break; - } - case SIOCSMIIREG:{ - struct cphy *phy = &pi->phy; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (!phy->mdio_write) - return -EOPNOTSUPP; - if (is_10G(adapter)) { - mmd = data->phy_id >> 8; - if (!mmd) - mmd = MDIO_DEV_PCS; - else if (mmd > MDIO_DEV_VEND2) - return -EINVAL; - - ret = - phy->mdio_write(adapter, - data->phy_id & 0x1f, mmd, - data->reg_num, - data->val_in); - } else - ret = - phy->mdio_write(adapter, - data->phy_id & 0x1f, 0, - data->reg_num & 0x1f, - data->val_in); - break; - } + case SIOCGMIIPHY: + return mdio_mii_ioctl(&pi->phy.mdio, data, cmd); case SIOCCHIOCTL: return cxgb_extension_ioctl(dev, req->ifr_data); default: return -EOPNOTSUPP; } - return ret; } static int cxgb_change_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index e1bd690..1dd1637 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -204,35 +204,33 @@ static void mi1_init(struct adapter *adap, const struct adapter_info *ai) /* * MI1 read/write operations for clause 22 PHYs. */ -static int t3_mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int t3_mi1_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); - if (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, 10); if (!ret) - *valp = t3_read_reg(adapter, A_MI1_DATA); + ret = t3_read_reg(adapter, A_MI1_DATA); mutex_unlock(&adapter->mdio_lock); return ret; } -static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int t3_mi1_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); - if (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); @@ -244,8 +242,9 @@ static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, } static const struct mdio_ops mi1_mdio_ops = { - t3_mi1_read, - t3_mi1_write + .read = t3_mi1_read, + .write = t3_mi1_write, + .mode_support = MDIO_SUPPORTS_C22 }; /* @@ -268,9 +267,11 @@ static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr, /* * 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) +static int mi1_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; mutex_lock(&adapter->mdio_lock); @@ -280,15 +281,17 @@ static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr, 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); + ret = t3_read_reg(adapter, A_MI1_DATA); } mutex_unlock(&adapter->mdio_lock); return ret; } -static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int mi1_ext_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; mutex_lock(&adapter->mdio_lock); @@ -304,8 +307,9 @@ static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr, } static const struct mdio_ops mi1_mdio_ext_ops = { - mi1_ext_read, - mi1_ext_write + .read = mi1_ext_read, + .write = mi1_ext_write, + .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 }; /** @@ -325,10 +329,10 @@ int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, int ret; unsigned int val; - ret = mdio_read(phy, mmd, reg, &val); + ret = t3_mdio_read(phy, mmd, reg, &val); if (!ret) { val &= ~clear; - ret = mdio_write(phy, mmd, reg, val | set); + ret = t3_mdio_write(phy, mmd, reg, val | set); } return ret; } @@ -348,15 +352,16 @@ int t3_phy_reset(struct cphy *phy, int mmd, int wait) int err; unsigned int ctl; - err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET); + err = t3_mdio_change_bits(phy, mmd, MDIO_CTRL1, MDIO_CTRL1_LPOWER, + MDIO_CTRL1_RESET); if (err || !wait) return err; do { - err = mdio_read(phy, mmd, MII_BMCR, &ctl); + err = t3_mdio_read(phy, mmd, MDIO_CTRL1, &ctl); if (err) return err; - ctl &= BMCR_RESET; + ctl &= MDIO_CTRL1_RESET; if (ctl) msleep(1); } while (ctl && --wait); @@ -377,7 +382,7 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert) int err; unsigned int val = 0; - err = mdio_read(phy, 0, MII_CTRL1000, &val); + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_CTRL1000, &val); if (err) return err; @@ -387,7 +392,7 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert) if (advert & ADVERTISED_1000baseT_Full) val |= ADVERTISE_1000FULL; - err = mdio_write(phy, 0, MII_CTRL1000, val); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_CTRL1000, val); if (err) return err; @@ -404,7 +409,7 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert) val |= ADVERTISE_PAUSE_CAP; if (advert & ADVERTISED_Asym_Pause) val |= ADVERTISE_PAUSE_ASYM; - return mdio_write(phy, 0, MII_ADVERTISE, val); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); } /** @@ -427,7 +432,7 @@ int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) val |= ADVERTISE_1000XPAUSE; if (advert & ADVERTISED_Asym_Pause) val |= ADVERTISE_1000XPSE_ASYM; - return mdio_write(phy, 0, MII_ADVERTISE, val); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); } /** @@ -444,7 +449,7 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) int err; unsigned int ctl; - err = mdio_read(phy, 0, MII_BMCR, &ctl); + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_BMCR, &ctl); if (err) return err; @@ -462,30 +467,30 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) } if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ ctl |= BMCR_ANENABLE; - return mdio_write(phy, 0, MII_BMCR, ctl); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_BMCR, ctl); } int t3_phy_lasi_intr_enable(struct cphy *phy) { - return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, LASI_CTRL, 1); } int t3_phy_lasi_intr_disable(struct cphy *phy) { - return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, 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); + return t3_mdio_read(phy, MDIO_MMD_PMAPMD, 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); + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, LASI_STAT, &status); if (err) return err; @@ -3863,6 +3868,7 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, ai->mdio_ops); if (ret) return ret; + p->phy.mdio.dev = adapter->port[i]; mac_prep(&p->mac, adapter, j); /* @@ -3918,7 +3924,7 @@ int t3_replay_prep_adapter(struct adapter *adapter) ; pti = &port_types[adapter->params.vpd.port_type[j]]; - ret = pti->phy_prep(&p->phy, adapter, p->phy.addr, NULL); + ret = pti->phy_prep(&p->phy, adapter, p->phy.mdio.prtad, NULL); if (ret) return ret; p->phy.ops->power_down(&p->phy, 1); diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c index d071309..4f9a1c2 100644 --- a/drivers/net/cxgb3/vsc8211.c +++ b/drivers/net/cxgb3/vsc8211.c @@ -91,17 +91,18 @@ enum { */ static int vsc8211_reset(struct cphy *cphy, int wait) { - return t3_phy_reset(cphy, 0, 0); + return t3_phy_reset(cphy, MDIO_DEVAD_NONE, 0); } static int vsc8211_intr_enable(struct cphy *cphy) { - return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK); + return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, + INTR_MASK); } static int vsc8211_intr_disable(struct cphy *cphy) { - return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0); + return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 0); } static int vsc8211_intr_clear(struct cphy *cphy) @@ -109,18 +110,20 @@ static int vsc8211_intr_clear(struct cphy *cphy) u32 val; /* Clear PHY interrupts by reading the register. */ - return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val); + return t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &val); } static int vsc8211_autoneg_enable(struct cphy *cphy) { - return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_PDOWN | BMCR_ISOLATE, BMCR_ANENABLE | BMCR_ANRESTART); } static int vsc8211_autoneg_restart(struct cphy *cphy) { - return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_PDOWN | BMCR_ISOLATE, BMCR_ANRESTART); } @@ -130,9 +133,9 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, unsigned int bmcr, status, lpa, adv; int err, sp = -1, dplx = -1, pause = 0; - err = mdio_read(cphy, 0, MII_BMCR, &bmcr); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); if (!err) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); if (err) return err; @@ -142,7 +145,8 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, * once more to get the current link state. */ if (!(status & BMSR_LSTATUS)) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, + &status); if (err) return err; *link_ok = (status & BMSR_LSTATUS) != 0; @@ -156,7 +160,8 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, else sp = SPEED_10; } else if (status & BMSR_ANEGCOMPLETE) { - err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_AUX_CTRL_STAT, + &status); if (err) return err; @@ -170,9 +175,11 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, sp = SPEED_1000; if (fc && dplx == DUPLEX_FULL) { - err = mdio_read(cphy, 0, MII_LPA, &lpa); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, + &lpa); if (!err) - err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, + MII_ADVERTISE, &adv); if (err) return err; @@ -202,9 +209,9 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, unsigned int bmcr, status, lpa, adv; int err, sp = -1, dplx = -1, pause = 0; - err = mdio_read(cphy, 0, MII_BMCR, &bmcr); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); if (!err) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); if (err) return err; @@ -214,7 +221,8 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, * once more to get the current link state. */ if (!(status & BMSR_LSTATUS)) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, + &status); if (err) return err; *link_ok = (status & BMSR_LSTATUS) != 0; @@ -228,9 +236,10 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, else sp = SPEED_10; } else if (status & BMSR_ANEGCOMPLETE) { - err = mdio_read(cphy, 0, MII_LPA, &lpa); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, &lpa); if (!err) - err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_ADVERTISE, + &adv); if (err) return err; @@ -270,23 +279,23 @@ static int vsc8211_set_automdi(struct cphy *phy, int enable) { int err; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0x52b5); if (err) return err; - err = mdio_write(phy, 0, 18, 0x12); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 18, 0x12); if (err) return err; - err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 17, enable ? 0x2803 : 0x3003); if (err) return err; - err = mdio_write(phy, 0, 16, 0x87fa); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 16, 0x87fa); if (err) return err; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); if (err) return err; @@ -315,7 +324,7 @@ static int vsc8211_intr_handler(struct cphy *cphy) unsigned int cause; int err, cphy_cause = 0; - err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &cause); if (err) return err; @@ -367,12 +376,13 @@ int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, 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); + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, 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); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_LED_CTRL, + 0x100); } phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | @@ -380,20 +390,20 @@ int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, phy->desc = "1000BASE-X"; phy->ops = &vsc8211_fiber_ops; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 1); if (err) return err; - err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_SIGDET_CTRL, 1); if (err) return err; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); if (err) return err; - err = mdio_write(phy, 0, VSC8211_EXT_CTRL, - val | VSC_CTRL_CLAUSE37_VIEW); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, + val | VSC_CTRL_CLAUSE37_VIEW); if (err) return err; -- cgit v0.10.2 From 6b73e10d2d89f9ce773f9b47d61b195936d059ba Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:08:58 +0000 Subject: ixgbe: Use generic MDIO definitions and functions Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 435bbc9..b8727d5 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2519,6 +2519,7 @@ config ENIC config IXGBE tristate "Intel(R) 10GbE PCI Express adapters support" depends on PCI && INET + select MDIO ---help--- This driver supports Intel(R) 10GbE PCI Express family of adapters. For more information on how to identify your adapter, go diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 03eb54f..e051964 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -229,14 +229,13 @@ static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, *speed = 0; *autoneg = true; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, &speed_ability); if (status == 0) { - if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) + if (speed_ability & MDIO_SPEED_10G) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) + if (speed_ability & MDIO_PMA_SPEED_1000) *speed |= IXGBE_LINK_SPEED_1GB_FULL; } @@ -526,9 +525,9 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, * clear indicates active; set indicates inactive. */ if (hw->phy.type == ixgbe_phy_nl) { - hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); - hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); - hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV, + hw->phy.ops.read_reg(hw, 0xC79F, MDIO_MMD_PMAPMD, &link_reg); + hw->phy.ops.read_reg(hw, 0xC79F, MDIO_MMD_PMAPMD, &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, MDIO_MMD_PMAPMD, &adapt_comp_reg); if (link_up_wait_to_complete) { for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { @@ -541,10 +540,10 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, } msleep(100); hw->phy.ops.read_reg(hw, 0xC79F, - IXGBE_TWINAX_DEV, + MDIO_MMD_PMAPMD, &link_reg); hw->phy.ops.read_reg(hw, 0xC00C, - IXGBE_TWINAX_DEV, + MDIO_MMD_PMAPMD, &adapt_comp_reg); } } else { @@ -990,14 +989,14 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK); hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + MDIO_MMD_PMAPMD, sfp_addr); /* Poll status */ for (i = 0; i < 100; i++) { hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + MDIO_MMD_PMAPMD, &sfp_stat); sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) @@ -1013,7 +1012,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, /* Read data */ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); + MDIO_MMD_PMAPMD, &sfp_data); *eeprom_data = (u8)(sfp_data >> 8); } else { @@ -1045,13 +1044,13 @@ static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) * physical layer because 10GBase-T PHYs use LMS = KX4/KX */ if (hw->phy.type == ixgbe_phy_tn || hw->phy.type == ixgbe_phy_cu_unknown) { - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability); - if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY) + hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD, + &ext_ability); + if (ext_ability & MDIO_PMA_EXTABLE_10GBT) physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; - if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY) + if (ext_ability & MDIO_PMA_EXTABLE_1000BT) physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; - if (ext_ability & IXGBE_MDIO_PHY_100BASETX_ABILITY) + if (ext_ability & MDIO_PMA_EXTABLE_100BTX) physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; goto out; } diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 9e824b4..6038ed1 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -314,14 +314,13 @@ static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, *speed = 0; *autoneg = true; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, &speed_ability); if (status == 0) { - if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) + if (speed_ability & MDIO_SPEED_10G) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) + if (speed_ability & MDIO_PMA_SPEED_1000) *speed |= IXGBE_LINK_SPEED_1GB_FULL; } @@ -1153,13 +1152,13 @@ u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) if (hw->phy.type == ixgbe_phy_tn || hw->phy.type == ixgbe_phy_cu_unknown) { - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability); - if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY) + hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD, + &ext_ability); + if (ext_ability & MDIO_PMA_EXTABLE_10GBT) physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; - if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY) + if (ext_ability & MDIO_PMA_EXTABLE_1000BT) physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; - if (ext_ability & IXGBE_MDIO_PHY_100BASETX_ABILITY) + if (ext_ability & MDIO_PMA_EXTABLE_100BTX) physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; goto out; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 01a8826..661bed6 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4642,6 +4642,40 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p) return 0; } +static int +ixgbe_mdio_read(struct net_device *netdev, int prtad, int devad, u16 addr) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u16 value; + int rc; + + if (prtad != hw->phy.mdio.prtad) + return -EINVAL; + rc = hw->phy.ops.read_reg(hw, addr, devad, &value); + if (!rc) + rc = value; + return rc; +} + +static int ixgbe_mdio_write(struct net_device *netdev, int prtad, int devad, + u16 addr, u16 value) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + if (prtad != hw->phy.mdio.prtad) + return -EINVAL; + return hw->phy.ops.write_reg(hw, addr, devad, value); +} + +static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd); +} + #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs @@ -4675,6 +4709,7 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_vlan_rx_register = ixgbe_vlan_rx_register, .ndo_vlan_rx_add_vid = ixgbe_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid, + .ndo_do_ioctl = ixgbe_ioctl, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ixgbe_netpoll, #endif @@ -4789,6 +4824,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* PHY */ memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); hw->phy.sfp_type = ixgbe_sfp_type_unknown; + /* ixgbe_identify_phy_generic will set prtad and mmds properly */ + hw->phy.mdio.prtad = MDIO_PRTAD_NONE; + hw->phy.mdio.mmds = 0; + hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + hw->phy.mdio.dev = netdev; + hw->phy.mdio.mdio_read = ixgbe_mdio_read; + hw->phy.mdio.mdio_write = ixgbe_mdio_write; /* set up this timer and work struct before calling get_invariants * which might start the timer diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 2543c32..6d385ea 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -44,7 +44,6 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); static bool ixgbe_get_i2c_data(u32 *i2cctl); static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw); -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); @@ -61,8 +60,7 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) 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; + if (mdio45_probe(&hw->phy.mdio, phy_addr) == 0) { ixgbe_get_phy_id(hw); hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); @@ -78,26 +76,6 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) } /** - * ixgbe_validate_phy_addr - Determines phy address is valid - * @hw: pointer to hardware structure - * - **/ -static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr) -{ - u16 phy_id = 0; - bool valid = false; - - hw->phy.addr = phy_addr; - 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; - - return valid; -} - -/** * ixgbe_get_phy_id - Get the phy type * @hw: pointer to hardware structure * @@ -108,14 +86,12 @@ static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) u16 phy_id_high = 0; u16 phy_id_low = 0; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_DEVID1, MDIO_MMD_PMAPMD, &phy_id_high); if (status == 0) { hw->phy.id = (u32)(phy_id_high << 16); - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_DEVID2, MDIO_MMD_PMAPMD, &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); @@ -160,9 +136,8 @@ 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 hw->phy.ops.write_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, MDIO_CTRL1, MDIO_MMD_PHYXS, + MDIO_CTRL1_RESET); } /** @@ -192,7 +167,7 @@ s32 ixgbe_read_phy_reg_generic(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) | + (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -223,7 +198,8 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (hw->phy.mdio.prtad << + IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -292,7 +268,7 @@ s32 ixgbe_write_phy_reg_generic(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) | + (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -323,7 +299,8 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (hw->phy.mdio.prtad << + IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -365,7 +342,7 @@ 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_reg = IXGBE_MII_AUTONEG_REG; + u16 autoneg_reg; /* * Set advertisement settings in PHY based on autoneg_advertised @@ -373,36 +350,31 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) * tnx devices cannot be "forced" to a autoneg 10G and fail. But can * for a 1G. */ - hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); + hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, &autoneg_reg); if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL) - autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */ + autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G; else - autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */ + autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G; - hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, autoneg_reg); /* Restart PHY autonegotiation and wait for completion */ - hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); + hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, &autoneg_reg); - autoneg_reg |= IXGBE_MII_RESTART; + autoneg_reg |= MDIO_AN_CTRL1_RESTART; - hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, 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 = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_STAT1, MDIO_MMD_AN, &autoneg_reg); - autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; - if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) { + autoneg_reg &= MDIO_AN_STAT1_COMPLETE; + if (autoneg_reg == MDIO_AN_STAT1_COMPLETE) { status = 0; break; } @@ -457,23 +429,21 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) s32 ret_val = 0; u32 i; - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data); /* reset the PHY and poll for completion */ - hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, - (phy_data | IXGBE_MDIO_PHY_XS_RESET)); + hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, + (phy_data | MDIO_CTRL1_RESET)); for (i = 0; i < 100; i++) { - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); - if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) + hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, + &phy_data); + if ((phy_data & MDIO_CTRL1_RESET) == 0) break; msleep(10); } - if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { + if ((phy_data & MDIO_CTRL1_RESET) != 0) { hw_dbg(hw, "PHY reset did not complete.\n"); ret_val = IXGBE_ERR_PHY; goto out; @@ -509,7 +479,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) for (i = 0; i < edata; i++) { hw->eeprom.ops.read(hw, data_offset, &eword); hw->phy.ops.write_reg(hw, phy_offset, - IXGBE_TWINAX_DEV, eword); + MDIO_MMD_PMAPMD, eword); hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, phy_offset); data_offset++; @@ -1302,7 +1272,7 @@ s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, udelay(10); status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, - IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + MDIO_MMD_VEND1, &phy_data); phy_link = phy_data & IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; @@ -1330,8 +1300,7 @@ s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, { s32 status = 0; - status = hw->phy.ops.read_reg(hw, TNX_FW_REV, - IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, TNX_FW_REV, MDIO_MMD_VEND1, firmware_version); return status; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index bdfdf3b..e49e8af 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -29,6 +29,7 @@ #define _IXGBE_TYPE_H_ #include +#include /* Vendor ID */ #define IXGBE_INTEL_VENDOR_ID 0x8086 @@ -848,13 +849,7 @@ /* Omer bit masks */ #define IXGBE_CORECTL_WRITE_CMD 0x00010000 -/* Device Type definitions for new protocol MDIO commands */ -#define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 -#define IXGBE_MDIO_PCS_DEV_TYPE 0x3 -#define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 -#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 -#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ -#define IXGBE_TWINAX_DEV 1 +/* MDIO definitions */ #define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ @@ -865,32 +860,10 @@ #define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED 0x0018 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED 0x0010 -#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */ -#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */ -#define IXGBE_MDIO_PHY_XS_CONTROL 0x0 /* PHY_XS Control Reg */ -#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 Ability Reg */ -#define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */ -#define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */ -#define IXGBE_MDIO_PHY_EXT_ABILITY 0xB /* Ext Ability Reg */ -#define IXGBE_MDIO_PHY_10GBASET_ABILITY 0x0004 /* 10GBaseT capable */ -#define IXGBE_MDIO_PHY_1000BASET_ABILITY 0x0020 /* 1000BaseT capable */ -#define IXGBE_MDIO_PHY_100BASETX_ABILITY 0x0080 /* 100BaseTX capable */ - #define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Addr 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 @@ -2214,8 +2187,8 @@ struct ixgbe_mac_info { struct ixgbe_phy_info { struct ixgbe_phy_operations ops; + struct mdio_if_info mdio; enum ixgbe_phy_type type; - u32 addr; u32 id; enum ixgbe_sfp_type sfp_type; bool sfp_setup_needed; -- cgit v0.10.2 From cdbf0eb478dd4c76aa665c80976837dc58367f52 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:11:05 +0000 Subject: ixgb: Use generic MDIO definitions Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 11dcda0..ff67a84 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -192,7 +192,7 @@ ixgb_identify_xpak_vendor(struct ixgb_hw *hw) vendor_name[i] = ixgb_read_phy_reg(hw, MDIO_PMA_PMD_XPAK_VENDOR_NAME + i, IXGB_PHY_ADDRESS, - MDIO_PMA_PMD_DID); + MDIO_MMD_PMAPMD); } /* Determine the actual vendor */ @@ -1225,15 +1225,15 @@ ixgb_optics_reset(struct ixgb_hw *hw) u16 mdio_reg; ixgb_write_phy_reg(hw, - MDIO_PMA_PMD_CR1, - IXGB_PHY_ADDRESS, - MDIO_PMA_PMD_DID, - MDIO_PMA_PMD_CR1_RESET); - - mdio_reg = ixgb_read_phy_reg( hw, - MDIO_PMA_PMD_CR1, - IXGB_PHY_ADDRESS, - MDIO_PMA_PMD_DID); + MDIO_CTRL1, + IXGB_PHY_ADDRESS, + MDIO_MMD_PMAPMD, + MDIO_CTRL1_RESET); + + mdio_reg = ixgb_read_phy_reg(hw, + MDIO_CTRL1, + IXGB_PHY_ADDRESS, + MDIO_MMD_PMAPMD); } return; diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 831fe0c..af6ca3a 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -29,6 +29,8 @@ #ifndef _IXGB_HW_H_ #define _IXGB_HW_H_ +#include + #include "ixgb_osdep.h" /* Enums */ @@ -507,18 +509,6 @@ typedef enum { /* Definitions for the optics devices on the MDIO bus. */ #define IXGB_PHY_ADDRESS 0x0 /* Single PHY, multiple "Devices" */ -/* Standard five-bit Device IDs. See IEEE 802.3ae, clause 45 */ -#define MDIO_PMA_PMD_DID 0x01 -#define MDIO_WIS_DID 0x02 -#define MDIO_PCS_DID 0x03 -#define MDIO_XGXS_DID 0x04 - -/* Standard PMA/PMD registers and bit definitions. */ -/* Note: This is a very limited set of definitions, */ -/* only implemented features are defined. */ -#define MDIO_PMA_PMD_CR1 0x0000 -#define MDIO_PMA_PMD_CR1_RESET 0x8000 - #define MDIO_PMA_PMD_XPAK_VENDOR_NAME 0x803A /* XPAK/XENPAK devices only */ /* Vendor-specific MDIO registers */ -- cgit v0.10.2 From 4023939667a906f0c02022ce7ec06d6512470211 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:13:29 +0000 Subject: s2io: Use generic MDIO definitions Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index f8274f8..416669f 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -271,11 +271,6 @@ struct XENA_dev_config { u64 mdio_control; #define MDIO_MMD_INDX_ADDR(val) vBIT(val, 0, 16) #define MDIO_MMD_DEV_ADDR(val) vBIT(val, 19, 5) -#define MDIO_MMD_PMA_DEV_ADDR 0x1 -#define MDIO_MMD_PMD_DEV_ADDR 0x1 -#define MDIO_MMD_WIS_DEV_ADDR 0x2 -#define MDIO_MMD_PCS_DEV_ADDR 0x3 -#define MDIO_MMD_PHYXS_DEV_ADDR 0x4 #define MDIO_MMS_PRT_ADDR(val) vBIT(val, 27, 5) #define MDIO_CTRL_START_TRANS(val) vBIT(val, 56, 4) #define MDIO_OP(val) vBIT(val, 60, 2) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 1a4979f..80562ea 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -3328,9 +3329,9 @@ static void s2io_updt_xpak_counter(struct net_device *dev) struct stat_block *stat_info = sp->mac_control.stats_info; /* Check the communication with the MDIO slave */ - addr = 0x0000; + addr = MDIO_CTRL1; val64 = 0x0; - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if((val64 == 0xFFFF) || (val64 == 0x0000)) { DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - " @@ -3338,24 +3339,24 @@ static void s2io_updt_xpak_counter(struct net_device *dev) return; } - /* Check for the expecte value of 2040 at PMA address 0x0000 */ - if(val64 != 0x2040) + /* Check for the expected value of control reg 1 */ + if(val64 != MDIO_CTRL1_SPEED10G) { DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - "); - DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x%x\n", + (unsigned long long)val64, MDIO_CTRL1_SPEED10G); return; } /* Loading the DOM register to MDIO register */ addr = 0xA100; - s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev); - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + s2io_mdio_write(MDIO_MMD_PMAPMD, addr, val16, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); /* Reading the Alarm flags */ addr = 0xA070; val64 = 0x0; - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); flag = CHECKBIT(val64, 0x7); type = 1; @@ -3387,7 +3388,7 @@ static void s2io_updt_xpak_counter(struct net_device *dev) /* Reading the Warning flags */ addr = 0xA074; val64 = 0x0; - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if(CHECKBIT(val64, 0x7)) stat_info->xpak_stat.warn_transceiver_temp_high++; -- cgit v0.10.2 From 44c22ee91b56d7cad3b48c439dd96aad2e910fbc Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:15:05 +0000 Subject: mii: Simplify mii_resolve_flowctrl_fdx() This is a shorter and more comprehensible formulation of the conditions for each flow control mode. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/mii.h b/include/linux/mii.h index ad74858..14ecb2e 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -250,18 +250,12 @@ static inline u8 mii_resolve_flowctrl_fdx(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)) + if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) { + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; + } else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) { + if (lcladv & ADVERTISE_PAUSE_CAP) + cap = FLOW_CTRL_RX; + else if (rmtadv & ADVERTISE_PAUSE_CAP) cap = FLOW_CTRL_TX; } -- cgit v0.10.2 From a8c30832b5b12e5d4e9d1c20cdac3cc2880e08b8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:19:03 +0000 Subject: mii: Add mii_advertise_flowctrl() This converts flow control capabilites to an advertising mask and can be useful in combination with mii_resolve_flowctrl_fdx(). Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/mii.h b/include/linux/mii.h index 14ecb2e..359fba8 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -240,6 +240,22 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock, } /** + * mii_advertise_flowctrl - get flow control advertisement flags + * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both) + */ +static inline u16 mii_advertise_flowctrl(int cap) +{ + u16 adv = 0; + + if (cap & FLOW_CTRL_RX) + adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + if (cap & FLOW_CTRL_TX) + adv ^= ADVERTISE_PAUSE_ASYM; + + return adv; +} + +/** * mii_resolve_flowctrl_fdx * @lcladv: value of MII ADVERTISE register * @rmtadv: value of MII LPA register -- cgit v0.10.2 From af2a3eac2fe6a6d8e9fdf6927284b34466a7d808 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:19:36 +0000 Subject: mdio: Add mdio45_ethtool_spauseparam_an() This implements the ETHTOOL_SPAUSEPARAM operation for MDIO (clause 45) PHYs with auto-negotiation MMDs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 0604a25..2fb0d16 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -275,6 +275,36 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, EXPORT_SYMBOL(mdio45_ethtool_gset_npage); /** + * mdio45_ethtool_spauseparam_an - set auto-negotiated pause parameters + * @mdio: MDIO interface + * @ecmd: Ethtool request structure + * + * This function assumes that the PHY has an auto-negotiation MMD. It + * will enable and disable advertising of flow control as appropriate. + */ +void mdio45_ethtool_spauseparam_an(const struct mdio_if_info *mdio, + const struct ethtool_pauseparam *ecmd) +{ + int adv, old_adv; + + WARN_ON(!(mdio->mmds & MDIO_DEVS_AN)); + + old_adv = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_AN_ADVERTISE); + adv = old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + if (ecmd->autoneg) + adv |= mii_advertise_flowctrl( + (ecmd->rx_pause ? FLOW_CTRL_RX : 0) | + (ecmd->tx_pause ? FLOW_CTRL_TX : 0)); + if (adv != old_adv) { + mdio->mdio_write(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_AN_ADVERTISE, adv); + mdio45_nway_restart(mdio); + } +} +EXPORT_SYMBOL(mdio45_ethtool_spauseparam_an); + +/** * mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs * @mdio: MDIO interface * @mii_data: MII ioctl data structure diff --git a/include/linux/mdio.h b/include/linux/mdio.h index ba41537..5645c0f 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -279,6 +279,9 @@ extern int mdio45_nway_restart(const struct mdio_if_info *mdio); extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, struct ethtool_cmd *ecmd, u32 npage_adv, u32 npage_lpa); +extern void +mdio45_ethtool_spauseparam_an(const struct mdio_if_info *mdio, + const struct ethtool_pauseparam *ecmd); /** * mdio45_ethtool_gset - get settings for ETHTOOL_GSET -- cgit v0.10.2 From 3f926da82f128c68c479247b1771729b9487502a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:20:37 +0000 Subject: sfc: Use generic MDIO flow control auto-negotiation functions Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 1c7b684..997ea2a 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -711,7 +711,8 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, mutex_lock(&efx->mac_lock); efx->wanted_fc = wanted_fc; - efx_mdio_set_pause(efx); + if (efx->phy_op->mmds & MDIO_DEVS_AN) + mdio45_ethtool_spauseparam_an(&efx->mdio, pause); __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 11c231a1..6c33459 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -304,7 +304,7 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) reg |= ADVERTISE_NPAGE; - reg |= efx_fc_advertise(efx->wanted_fc); + reg |= mii_advertise_flowctrl(efx->wanted_fc); efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); /* Set up the (extended) next page if necessary */ @@ -340,26 +340,6 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) return 0; } -void efx_mdio_set_pause(struct efx_nic *efx) -{ - int reg; - - if (efx->phy_op->mmds & MDIO_DEVS_AN) { - /* Set pause capability advertising */ - reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - reg |= efx_fc_advertise(efx->wanted_fc); - efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); - - /* Restart auto-negotiation */ - reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); - if (reg & MDIO_AN_CTRL1_ENABLE) { - reg |= MDIO_AN_CTRL1_RESTART; - efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); - } - } -} - enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) { int lpa; diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index ea4587d..6b14421 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -87,9 +87,6 @@ extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, /* Set (some of) the PHY settings over MDIO */ extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); -/* Set pause parameters to be advertised through AN (if available) */ -extern void efx_mdio_set_pause(struct efx_nic *efx); - /* Get pause parameters from AN if available (otherwise return * requested pause parameters) */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 457e2f1..5eabede 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -495,8 +495,8 @@ struct efx_nic; /* Pseudo bit-mask flow control field */ enum efx_fc_type { - EFX_FC_RX = 1, - EFX_FC_TX = 2, + EFX_FC_RX = FLOW_CTRL_RX, + EFX_FC_TX = FLOW_CTRL_TX, EFX_FC_AUTO = 4, }; @@ -506,33 +506,15 @@ enum efx_mac_type { EFX_XMAC = 2, }; -static inline unsigned int efx_fc_advertise(enum efx_fc_type wanted_fc) -{ - unsigned int adv = 0; - if (wanted_fc & EFX_FC_RX) - adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - if (wanted_fc & EFX_FC_TX) - adv ^= ADVERTISE_PAUSE_ASYM; - return adv; -} - static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc, unsigned int lpa) { - unsigned int adv = efx_fc_advertise(wanted_fc); + BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); if (!(wanted_fc & EFX_FC_AUTO)) return wanted_fc; - if (adv & lpa & ADVERTISE_PAUSE_CAP) - return EFX_FC_RX | EFX_FC_TX; - if (adv & lpa & ADVERTISE_PAUSE_ASYM) { - if (adv & ADVERTISE_PAUSE_CAP) - return EFX_FC_RX; - if (lpa & ADVERTISE_PAUSE_CAP) - return EFX_FC_TX; - } - return 0; + return mii_resolve_flowctrl_fdx(mii_advertise_flowctrl(wanted_fc), lpa); } /** diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 403f7d70..0421190 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -343,7 +343,6 @@ static int tenxpress_phy_init(struct efx_nic *efx) rc = tenxpress_init(efx); if (rc < 0) goto fail; - efx_mdio_set_pause(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, -- cgit v0.10.2 From 0c09c1a49cc7b819b33566a49d9901f7cfdd6889 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:21:53 +0000 Subject: ethtool/mdio: Report MDIO mode support and link partner advertising Add mdio_support and lp_advertising fields to ethtool_cmd. Set these in mdio45_ethtool_gset{,_npage}(). Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 2fb0d16..ee383c2 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -173,6 +173,8 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, ecmd->transceiver = XCVR_INTERNAL; ecmd->phy_address = mdio->prtad; + ecmd->mdio_support = + mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22); reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_CTRL2); @@ -235,16 +237,19 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, if (ecmd->autoneg) { u32 modes = 0; + int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad, + MDIO_MMD_AN, MDIO_STAT1); /* If AN is complete and successful, report best common * mode, otherwise report best advertised mode. */ - if (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, - MDIO_STAT1) & - MDIO_AN_STAT1_COMPLETE) - modes = (ecmd->advertising & - (mdio45_get_an(mdio, MDIO_AN_LPA) | - npage_lpa)); - if (modes == 0) + if (an_stat & MDIO_AN_STAT1_COMPLETE) { + ecmd->lp_advertising = + mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa; + if (an_stat & MDIO_AN_STAT1_LPABLE) + ecmd->lp_advertising |= ADVERTISED_Autoneg; + modes = ecmd->advertising & ecmd->lp_advertising; + } + if ((modes & ~ADVERTISED_Autoneg) == 0) modes = ecmd->advertising; if (modes & ADVERTISED_10000baseT_Full) { diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 5ccb6bd..14e6bc8 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -26,11 +26,13 @@ struct ethtool_cmd { __u8 phy_address; __u8 transceiver; /* Which transceiver to use */ __u8 autoneg; /* Enable or disable autonegotiation */ + __u8 mdio_support; __u32 maxtxpkt; /* Tx pkts before generating tx int */ __u32 maxrxpkt; /* Rx pkts before generating rx int */ __u16 speed_hi; __u16 reserved2; - __u32 reserved[3]; + __u32 lp_advertising; /* Features the link partner advertises */ + __u32 reserved[2]; }; static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep, diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 5645c0f..1bff2f2 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -234,6 +234,9 @@ static inline __u16 mdio_phy_id_devad(int phy_id) return phy_id & MDIO_PHY_ID_DEVAD; } +#define MDIO_SUPPORTS_C22 1 +#define MDIO_SUPPORTS_C45 2 + #ifdef __KERNEL__ /** @@ -264,8 +267,6 @@ struct mdio_if_info { #define MDIO_PRTAD_NONE (-1) #define MDIO_DEVAD_NONE (-1) -#define MDIO_SUPPORTS_C22 1 -#define MDIO_SUPPORTS_C45 2 #define MDIO_EMULATE_C22 4 struct ethtool_cmd; -- cgit v0.10.2 From 894b19a6b343ce3589237167a56e6df0fe72ef0d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:25:57 +0000 Subject: ethtool/mdio: Support backplane mode negotiation Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index ee383c2..6648303 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -202,12 +202,29 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, break; case MDIO_PMA_CTRL2_10GBCX4: + ecmd->port = PORT_OTHER; + ecmd->supported = 0; + ecmd->advertising = 0; + break; + case MDIO_PMA_CTRL2_10GBKX4: case MDIO_PMA_CTRL2_10GBKR: case MDIO_PMA_CTRL2_1000BKX: ecmd->port = PORT_OTHER; - ecmd->supported = 0; - ecmd->advertising = 0; + ecmd->supported = SUPPORTED_Backplane; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_EXTABLE); + if (reg & MDIO_PMA_EXTABLE_10GBKX4) + ecmd->supported |= SUPPORTED_10000baseKX4_Full; + if (reg & MDIO_PMA_EXTABLE_10GBKR) + ecmd->supported |= SUPPORTED_10000baseKR_Full; + if (reg & MDIO_PMA_EXTABLE_1000BKX) + ecmd->supported |= SUPPORTED_1000baseKX_Full; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBR_FECABLE); + if (reg & MDIO_PMA_10GBR_FECABLE_ABLE) + ecmd->supported |= SUPPORTED_10000baseR_FEC; + ecmd->advertising = ADVERTISED_Backplane; break; /* All the other defined modes are flavours of optical */ @@ -252,13 +269,16 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, if ((modes & ~ADVERTISED_Autoneg) == 0) modes = ecmd->advertising; - if (modes & ADVERTISED_10000baseT_Full) { + if (modes & (ADVERTISED_10000baseT_Full | + ADVERTISED_10000baseKX4_Full | + ADVERTISED_10000baseKR_Full)) { ecmd->speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; } else if (modes & (ADVERTISED_1000baseT_Full | - ADVERTISED_1000baseT_Half)) { + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseKX_Full)) { ecmd->speed = SPEED_1000; - ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full); + ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half); } else if (modes & (ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half)) { ecmd->speed = SPEED_100; diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 14e6bc8..380b042 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -565,6 +565,11 @@ struct ethtool_ops { #define SUPPORTED_Pause (1 << 13) #define SUPPORTED_Asym_Pause (1 << 14) #define SUPPORTED_2500baseX_Full (1 << 15) +#define SUPPORTED_Backplane (1 << 16) +#define SUPPORTED_1000baseKX_Full (1 << 17) +#define SUPPORTED_10000baseKX4_Full (1 << 18) +#define SUPPORTED_10000baseKR_Full (1 << 19) +#define SUPPORTED_10000baseR_FEC (1 << 20) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1 << 0) @@ -583,6 +588,11 @@ struct ethtool_ops { #define ADVERTISED_Pause (1 << 13) #define ADVERTISED_Asym_Pause (1 << 14) #define ADVERTISED_2500baseX_Full (1 << 15) +#define ADVERTISED_Backplane (1 << 16) +#define ADVERTISED_1000baseKX_Full (1 << 17) +#define ADVERTISED_10000baseKX4_Full (1 << 18) +#define ADVERTISED_10000baseKR_Full (1 << 19) +#define ADVERTISED_10000baseR_FEC (1 << 20) /* The following are all involved in forcing a particular link * mode for the device for setting things. When getting the diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 1bff2f2..26b4eb3 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -46,6 +46,7 @@ /* Media-dependent registers. */ #define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ +#define MDIO_PMA_10GBR_FECABLE 170 /* 10GBASE-R FEC ability */ #define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */ #define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */ #define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */ @@ -187,6 +188,10 @@ /* PMA 10GBASE-T TX power register. */ #define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */ +/* PMA 10GBASE-R FEC ability register. */ +#define MDIO_PMA_10GBR_FECABLE_ABLE 0x0001 /* FEC ability */ +#define MDIO_PMA_10GBR_FECABLE_ERRABLE 0x0002 /* FEC error indic. ability */ + /* PCS 10GBASE-R/-T status register 1. */ #define MDIO_PCS_10GBRT_STAT1_BLKLK 0x0001 /* Block lock attained */ -- cgit v0.10.2 From 5974700c288aa160fd02b1cb9294173664bcc172 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 29 Apr 2009 08:34:44 +0000 Subject: mii: Rewrite mii_ethtool_gset() to report mdio_support and lp_advertising Ignore link partner advertising flags while AN is not complete. Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 9205605..d81a5d2 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -31,7 +31,27 @@ #include #include #include -#include +#include + +static u32 mii_get_an(struct mii_if_info *mii, u16 addr) +{ + u32 result = 0; + int advert; + + advert = mii->mdio_read(mii->dev, mii->phy_id, addr); + if (advert & LPA_LPACK) + result |= ADVERTISED_Autoneg; + if (advert & ADVERTISE_10HALF) + result |= ADVERTISED_10baseT_Half; + if (advert & ADVERTISE_10FULL) + result |= ADVERTISED_10baseT_Full; + if (advert & ADVERTISE_100HALF) + result |= ADVERTISED_100baseT_Half; + if (advert & ADVERTISE_100FULL) + result |= ADVERTISED_100baseT_Full; + + return result; +} /** * mii_ethtool_gset - get settings that are specified in @ecmd @@ -43,8 +63,8 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; - u32 advert, bmcr, lpa, nego; - u32 advert2 = 0, bmcr2 = 0, lpa2 = 0; + u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; + u32 nego; ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -62,50 +82,51 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) /* this isn't fully supported at higher layers */ ecmd->phy_address = mii->phy_id; + ecmd->mdio_support = MDIO_SUPPORTS_C22; ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; - advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); - if (mii->supports_gmii) - advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); - - if (advert & ADVERTISE_10HALF) - ecmd->advertising |= ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - ecmd->advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - ecmd->advertising |= ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - ecmd->advertising |= ADVERTISED_100baseT_Full; - if (advert2 & ADVERTISE_1000HALF) - ecmd->advertising |= ADVERTISED_1000baseT_Half; - if (advert2 & ADVERTISE_1000FULL) - ecmd->advertising |= ADVERTISED_1000baseT_Full; bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); - lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA); + bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR); if (mii->supports_gmii) { - bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); - lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); + ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); + stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); } if (bmcr & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; - nego = mii_nway_result(advert & lpa); - if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) & - (lpa2 >> 2)) + ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE); + if (ctrl1000 & ADVERTISE_1000HALF) + ecmd->advertising |= ADVERTISED_1000baseT_Half; + if (ctrl1000 & ADVERTISE_1000FULL) + ecmd->advertising |= ADVERTISED_1000baseT_Full; + + if (bmsr & BMSR_ANEGCOMPLETE) { + ecmd->lp_advertising = mii_get_an(mii, MII_LPA); + if (stat1000 & LPA_1000HALF) + ecmd->lp_advertising |= + ADVERTISED_1000baseT_Half; + if (stat1000 & LPA_1000FULL) + ecmd->lp_advertising |= + ADVERTISED_1000baseT_Full; + } else { + ecmd->lp_advertising = 0; + } + + nego = ecmd->advertising & ecmd->lp_advertising; + + if (nego & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half)) { ecmd->speed = SPEED_1000; - else if (nego == LPA_100FULL || nego == LPA_100HALF) + ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full); + } else if (nego & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { ecmd->speed = SPEED_100; - else - ecmd->speed = SPEED_10; - if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL || - nego == LPA_10FULL) { - ecmd->duplex = DUPLEX_FULL; - mii->full_duplex = 1; + ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full); } else { - ecmd->duplex = DUPLEX_HALF; - mii->full_duplex = 0; + ecmd->speed = SPEED_10; + ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full); } } else { ecmd->autoneg = AUTONEG_DISABLE; @@ -116,6 +137,8 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } + mii->full_duplex = ecmd->duplex; + /* ignore maxtxpkt, maxrxpkt for now */ return 0; -- cgit v0.10.2 From a4fe91ee711f4e955ea85ab05b092cfe384b073e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 29 Apr 2009 17:53:20 -0700 Subject: Revert "vxge: use max() instead of VXGE_HW_SET_LEVEL" This reverts commit 011983048a120e520147361be1067dd82343038e. Causes warnings in the build as reported by Stephen Rothwell. So this change is worse than what it's curing. Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index cf4ebb5..506625b 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -505,7 +505,7 @@ enum vxge_hw_status vxge_hw_device_begin_irq(struct __vxge_hw_device *hldev, ret = __vxge_hw_vpath_alarm_process( &hldev->virtual_paths[i], skip_alarms); - error_level = max(ret, error_level); + error_level = VXGE_HW_SET_LEVEL(ret, error_level); if (unlikely((ret == VXGE_HW_ERR_CRITICAL) || (ret == VXGE_HW_ERR_SLOT_FREEZE))) @@ -1921,7 +1921,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( struct vxge_hw_vpath_reg __iomem *vp_reg; if (vpath == NULL) { - alarm_event = max(VXGE_HW_EVENT_UNKNOWN, + alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, alarm_event); goto out2; } @@ -1931,7 +1931,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( alarm_status = readq(&vp_reg->vpath_general_int_status); if (alarm_status == VXGE_HW_ALL_FOXES) { - alarm_event = max(VXGE_HW_EVENT_SLOT_FREEZE, + alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_SLOT_FREEZE, alarm_event); goto out; } @@ -1945,7 +1945,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) { sw_stats->error_stats.unknown_alarms++; - alarm_event = max(VXGE_HW_EVENT_UNKNOWN, + alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, alarm_event); goto out; } @@ -1975,8 +1975,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( &vp_reg->asic_ntwk_vp_err_mask); __vxge_hw_device_handle_link_down_ind(hldev); - alarm_event = max(VXGE_HW_EVENT_LINK_DOWN, - alarm_event); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_LINK_DOWN, alarm_event); } if (((val64 & @@ -1996,15 +1996,15 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( &vp_reg->asic_ntwk_vp_err_mask); __vxge_hw_device_handle_link_up_ind(hldev); - alarm_event = max(VXGE_HW_EVENT_LINK_UP, - alarm_event); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_LINK_UP, alarm_event); } writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->asic_ntwk_vp_err_reg); - alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, - alarm_event); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); if (skip_alarms) return VXGE_HW_OK; @@ -2026,8 +2026,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.ini_serr_det++; - alarm_event = max(VXGE_HW_EVENT_SERR, - alarm_event); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_SERR, alarm_event); } if ((val64 & @@ -2035,8 +2035,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.dblgen_fifo0_overflow++; - alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, - alarm_event); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, alarm_event); } if ((val64 & @@ -2057,7 +2057,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( if (!skip_alarms) { writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->general_errors_reg); - alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); } } @@ -2073,7 +2074,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.kdfcctl_fifo0_overwrite++; - alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, alarm_event); } @@ -2082,7 +2084,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.kdfcctl_fifo0_poison++; - alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, alarm_event); } @@ -2091,14 +2094,16 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.kdfcctl_fifo0_dma_error++; - alarm_event = max(VXGE_HW_EVENT_FIFO_ERR, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, alarm_event); } if (!skip_alarms) { writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_reg); - alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); } } @@ -2122,7 +2127,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( ~mask64) { sw_stats->error_stats.prc_rxdcm_sc_err++; - alarm_event = max(VXGE_HW_EVENT_VPATH_ERR, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_VPATH_ERR, alarm_event); } @@ -2130,7 +2136,8 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( & ~mask64) { sw_stats->error_stats.prc_rxdcm_sc_abort++; - alarm_event = max(VXGE_HW_EVENT_VPATH_ERR, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_VPATH_ERR, alarm_event); } @@ -2138,14 +2145,16 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( & ~mask64) { sw_stats->error_stats.prc_quanta_size_err++; - alarm_event = max(VXGE_HW_EVENT_VPATH_ERR, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_VPATH_ERR, alarm_event); } if (!skip_alarms) { writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->prc_alarm_reg); - alarm_event = max(VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); } } diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index d03f3d3..7567a11 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -110,6 +110,8 @@ enum vxge_hw_event { VXGE_HW_EVENT_SLOT_FREEZE = VXGE_HW_EVENT_BASE + 14, }; +#define VXGE_HW_SET_LEVEL(a, b) (((a) > (b)) ? (a) : (b)) + /* * struct vxge_hw_mempool_dma - Represents DMA objects passed to the caller. -- cgit v0.10.2 From 1aec5bdfed91b50aedbcad43393bcb05033c7ef3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Apr 2009 12:19:31 +0000 Subject: net: remove driver_data direct access of struct device In the near future, the driver core is going to not allow direct access to the driver_data pointer in struct device. Instead, the functions dev_get_drvdata() and dev_set_drvdata() should be used. These functions have been around since the beginning, so are backwards compatible with all older kernel versions. Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index fbb3719..393e4e7 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -653,11 +653,11 @@ static int __init el3_mca_probe(struct device *device) netdev_boot_setup_check(dev); el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_MCA); - device->driver_data = dev; + dev_set_drvdata(device, dev); err = el3_common_init(dev); if (err) { - device->driver_data = NULL; + dev_set_drvdata(device, NULL); free_netdev(dev); return -ENOMEM; } @@ -721,12 +721,12 @@ static int __init el3_eisa_probe (struct device *device) /* This remove works for all device types. * - * The net dev must be stored in the driver_data field */ + * The net dev must be stored in the driver data field */ static int __devexit el3_device_remove (struct device *device) { struct net_device *dev; - dev = device->driver_data; + dev = dev_get_drvdata(device); el3_common_remove (dev); return 0; @@ -1451,7 +1451,7 @@ el3_suspend(struct device *pdev, pm_message_t state) struct el3_private *lp; int ioaddr; - dev = pdev->driver_data; + dev = dev_get_drvdata(pdev); lp = netdev_priv(dev); ioaddr = dev->base_addr; @@ -1475,7 +1475,7 @@ el3_resume(struct device *pdev) struct el3_private *lp; int ioaddr; - dev = pdev->driver_data; + dev = dev_get_drvdata(pdev); lp = netdev_priv(dev); ioaddr = dev->base_addr; diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 357f565..9301eb2 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -810,7 +810,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) dev->mem_start = 0; - device->driver_data = dev; + dev_set_drvdata(device, dev); SET_NETDEV_DEV (dev, device); status = register_netdev(dev); @@ -1614,7 +1614,7 @@ static int __devexit depca_device_remove (struct device *device) struct depca_private *lp; int bus; - dev = device->driver_data; + dev = dev_get_drvdata(device); lp = netdev_priv(dev); unregister_netdev (dev); diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index de3f49f..8feda9f 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2864,7 +2864,7 @@ static int __init hp100_eisa_probe (struct device *gendev) printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, dev->base_addr); #endif - gendev->driver_data = dev; + dev_set_drvdata(gendev, dev); return 0; out1: free_netdev(dev); @@ -2873,7 +2873,7 @@ static int __init hp100_eisa_probe (struct device *gendev) static int __devexit hp100_eisa_remove (struct device *gendev) { - struct net_device *dev = gendev->driver_data; + struct net_device *dev = dev_get_drvdata(gendev); cleanup_dev(dev); return 0; } diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 6a843f7..a00bbfb 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -104,7 +104,7 @@ static int __init ne3210_eisa_probe (struct device *device) } SET_NETDEV_DEV(dev, device); - device->driver_data = dev; + dev_set_drvdata(device, dev); ioaddr = edev->base_addr; if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) { @@ -225,7 +225,7 @@ static int __init ne3210_eisa_probe (struct device *device) static int __devexit ne3210_eisa_remove (struct device *device) { - struct net_device *dev = device->driver_data; + struct net_device *dev = dev_get_drvdata(device); unsigned long ioaddr = to_eisa_device (device)->base_addr; unregister_netdev (dev); diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 8d36d40..c791ef7 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -370,7 +370,7 @@ static int __init ultramca_probe(struct device *gen_dev) outb(reg4, ioaddr + 4); - gen_dev->driver_data = dev; + dev_set_drvdata(gen_dev, dev); /* The 8390 isn't at the base address, so fake the offset */ @@ -531,7 +531,7 @@ static int ultramca_close_card(struct net_device *dev) static int ultramca_remove(struct device *gen_dev) { struct mca_device *mca_dev = to_mca_device(gen_dev); - struct net_device *dev = (struct net_device *)gen_dev->driver_data; + struct net_device *dev = dev_get_drvdata(gen_dev); if (dev) { /* NB: ultra_close_card() does free_irq */ diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index f9491bd..3225617 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1099,7 +1099,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) struct pci_dev *pdev = NULL; int i, status=0; - gendev->driver_data = dev; + dev_set_drvdata(gendev, dev); /* Ensure we're not sleeping */ if (lp->bus == EISA) { @@ -2094,7 +2094,7 @@ static int __devexit de4x5_eisa_remove (struct device *device) struct net_device *dev; u_long iobase; - dev = device->driver_data; + dev = dev_get_drvdata(device); iobase = dev->base_addr; unregister_netdev (dev); @@ -2338,7 +2338,7 @@ static void __devexit de4x5_pci_remove (struct pci_dev *pdev) struct net_device *dev; u_long iobase; - dev = pdev->dev.driver_data; + dev = dev_get_drvdata(&pdev->dev); iobase = dev->base_addr; unregister_netdev (dev); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index d696e5f..837135f 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -482,7 +482,7 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev, struct device_attribute *attr, char *buf) { - struct hso_device *hso_dev = dev->driver_data; + struct hso_device *hso_dev = dev_get_drvdata(dev); char *port_name; if (!hso_dev) @@ -2313,7 +2313,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, serial->parent->dev = tty_register_device(tty_drv, minor, &serial->parent->interface->dev); dev = serial->parent->dev; - dev->driver_data = serial->parent; + dev_set_drvdata(dev, serial->parent); i = device_create_file(dev, &dev_attr_hsotype); /* fill in specific data for later use */ -- cgit v0.10.2 From 88d7d8b00cdc3117150faab4c4ace6d464b71c22 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Fri, 1 May 2009 01:41:50 +0000 Subject: forcedeth: add clock gating feature This patch adds new logic to support a clock gating feature found on the latest set of chipsets. The clock gating is performed on the tx/rx engines when the link is disconnected. Clock gating helps in reducing power consumption. * modified based on comments from netdev Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index f9a846b..d0b1d9f 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -343,6 +343,7 @@ enum { #define NVREG_POWERSTATE2_POWERUP_MASK 0x0F15 #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 #define NVREG_POWERSTATE2_PHY_RESET 0x0004 +#define NVREG_POWERSTATE2_GATE_CLOCKS 0x0F00 }; /* Big endian: should work, but is untested */ @@ -1017,6 +1018,23 @@ static int using_multi_irqs(struct net_device *dev) return 1; } +static void nv_txrx_gate(struct net_device *dev, bool gate) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 powerstate; + + if (!np->mac_in_use && + (np->driver_data & DEV_HAS_POWER_CNTRL)) { + powerstate = readl(base + NvRegPowerState2); + if (gate) + powerstate |= NVREG_POWERSTATE2_GATE_CLOCKS; + else + powerstate &= ~NVREG_POWERSTATE2_GATE_CLOCKS; + writel(powerstate, base + NvRegPowerState2); + } +} + static void nv_enable_irq(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); @@ -3394,12 +3412,14 @@ static void nv_linkchange(struct net_device *dev) if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); printk(KERN_INFO "%s: link up.\n", dev->name); + nv_txrx_gate(dev, false); nv_start_rx(dev); } } else { if (netif_carrier_ok(dev)) { netif_carrier_off(dev); printk(KERN_INFO "%s: link down.\n", dev->name); + nv_txrx_gate(dev, true); nv_stop_rx(dev); } } @@ -5327,6 +5347,7 @@ static int nv_open(struct net_device *dev) mii_rw(dev, np->phyaddr, MII_BMCR, mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN); + nv_txrx_gate(dev, false); /* erase previous misconfiguration */ if (np->driver_data & DEV_HAS_POWER_CNTRL) nv_mac_reset(dev); @@ -5514,12 +5535,14 @@ static int nv_close(struct net_device *dev) nv_drain_rxtx(dev); if (np->wolenabled) { + nv_txrx_gate(dev, false); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); nv_start_rx(dev); } else { /* power down phy */ mii_rw(dev, np->phyaddr, MII_BMCR, mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ)|BMCR_PDOWN); + nv_txrx_gate(dev, true); } /* FIXME: power down nic */ -- cgit v0.10.2 From f0a3a1538d57dfb51c73d012cbb72f985cd419aa Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Fri, 1 May 2009 19:21:26 -0700 Subject: 3c589_cs: add cis(firmware) of 3Com multifunction pcmcia card 3c589_cs,3c574_cs,serial_cs: (1)add cis(firmware) of 3Com lan&modem mulitifunction pcmcia card. (2)load correct configuration register for 3Com card Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 8f3872b..f35c609 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1195,7 +1195,7 @@ static int el3_close(struct net_device *dev) static struct pcmcia_device_id tc574_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "3CCFEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, tc574_ids); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index cdf661a..ec7cf5a 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -967,8 +967,8 @@ static struct pcmcia_device_id tc589_ids[] = { PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77), PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589), PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "3CXEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, tc589_ids); diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 7546aa8..79c9c5f 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -681,7 +681,7 @@ static int serial_config(struct pcmcia_device * link) u_char *buf; cisparse_t *parse; cistpl_cftable_entry_t *cf; - int i; + int i, last_ret, last_fn; DEBUG(0, "serial_config(0x%p)\n", link); @@ -699,6 +699,16 @@ static int serial_config(struct pcmcia_device * link) tuple->TupleDataMax = 255; tuple->Attributes = 0; + /* Get configuration register information */ + tuple->DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(link, tuple, parse); + if (last_ret != 0) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse->config.base; + link->conf.Present = parse->config.rmask[0]; + /* Is this a compliant multifunction card? */ tuple->DesiredTuple = CISTPL_LONGLINK_MFC; tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; @@ -761,7 +771,9 @@ static int serial_config(struct pcmcia_device * link) kfree(cfg_mem); return 0; - failed: +cs_failed: + cs_error(link, last_fn, last_ret); +failed: serial_remove(link); kfree(cfg_mem); return -ENODEV; @@ -863,10 +875,10 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ diff --git a/firmware/Makefile b/firmware/Makefile index 1c670e0..96c3dd8 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -48,6 +48,8 @@ fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \ e100/d102e_ucode.bin fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis +fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis +fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ advansys/3550.bin advansys/38C0800.bin diff --git a/firmware/WHENCE b/firmware/WHENCE index c1e9c5a..bb8fda8 100644 --- a/firmware/WHENCE +++ b/firmware/WHENCE @@ -586,6 +586,26 @@ Originally developed by the pcmcia-cs project -------------------------------------------------------------------------- +Driver: PCMCIA_3C589 - 3Com PCMCIA adapter + +File: cis/3CXEM556.cis + +Licence: GPL + +Originally developed by the pcmcia-cs project + +-------------------------------------------------------------------------- + +Driver: PCMCIA_3C574 - 3Com PCMCIA adapter + +File: cis/3CCFEM556.cis + +Licence: GPL + +Originally developed by the pcmcia-cs project + +-------------------------------------------------------------------------- + Driver: PCMCIA_SMC91C92 - SMC 91Cxx PCMCIA File: ositech/Xilinx7OD.bin diff --git a/firmware/cis/3CCFEM556.cis.ihex b/firmware/cis/3CCFEM556.cis.ihex new file mode 100644 index 0000000..e4d92b1 --- /dev/null +++ b/firmware/cis/3CCFEM556.cis.ihex @@ -0,0 +1,13 @@ +:1000000001030000FF152D050033436F6D004D65A2 +:100010006761686572747A2033434346454D3535D0 +:1000200036004C414E202B2035366B204D6F6465D9 +:100030006D0000FF20040101560521020000060B9F +:1000400002004D000000006B000000FF001303439E +:100050004953210206001A060507001067021B0912 +:1000600087011901556430FFFFFF00130343495313 +:10007000210202001A060527001177021B09A701B9 +:090080001901552330FFFFFF00B8 +:00000001FF +# +# This card is MFC-compliant, but identifies itself as single function +# diff --git a/firmware/cis/3CXEM556.cis.ihex b/firmware/cis/3CXEM556.cis.ihex new file mode 100644 index 0000000..895010b --- /dev/null +++ b/firmware/cis/3CXEM556.cis.ihex @@ -0,0 +1,13 @@ +:1000000001030000FF152C050033436F6D004D65A3 +:100010006761686572747A20334358454D353536CB +:10002000004C414E202B2035366B204D6F64656DA2 +:100030000000FF20040101350021020000060B0230 +:10004000004C0000000069000000FF00130343495A +:1000500053210206001A0501070008631B098701E6 +:100060001901556430FFFFFF001303434953210278 +:1000700002001A0501270009631B09A70119015590 +:060080002330FFFFFF002A +:00000001FF +# +# This card is MFC-compliant, but identifies itself as single function +# -- cgit v0.10.2 From a52f5c5620673c292cb159205bf0e1eb5af1985b Mon Sep 17 00:00:00 2001 From: Dmitri Vorobiev Date: Fri, 1 May 2009 13:10:21 -0700 Subject: clockevents: tick_broadcast_device can become static The variable tick_broadcast_device is not used outside of the file where it is defined, so let's make it static. Signed-off-by: Dmitri Vorobiev Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 118a3b3..877dbed 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -27,7 +27,7 @@ * timer stops in C3 state. */ -struct tick_device tick_broadcast_device; +static struct tick_device tick_broadcast_device; /* FIXME: Use cpumask_var_t. */ static DECLARE_BITMAP(tick_broadcast_mask, NR_CPUS); static DECLARE_BITMAP(tmpmask, NR_CPUS); -- cgit v0.10.2 From a04198887658e1d8ae25f5420035c057cb170e67 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 1 May 2009 13:10:23 -0700 Subject: timers: allow deferrable timers for intervals tv2-tv5 to be deferred In the current kernel implementation only kernel timers for time interval tv1 are being deferred. This patch allows any timer that is configured as deferrable to be defer regardless of time interval. This patch was previously discussed in http://marc.info/?l=linux-kernel&m=123196343531966&w=2 and was acked by Venki Pallipadi, the author of the original deferrable timer patch. Signed-off-by: Jon Hunter Acked-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner diff --git a/kernel/timer.c b/kernel/timer.c index cffffad..5c1e84b 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1015,6 +1015,9 @@ cascade: index = slot = timer_jiffies & TVN_MASK; do { list_for_each_entry(nte, varp->vec + slot, entry) { + if (tbase_get_deferrable(nte->base)) + continue; + found = 1; if (time_before(nte->expires, expires)) expires = nte->expires; -- cgit v0.10.2 From c81fc2c331b8514ad112054cd2d87e6ec132286b Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 1 May 2009 14:52:47 +0900 Subject: clockevent: export register_device and delta2ns Export the following symbols using EXPORT_SYMBOL_GPL: - clockevent_delta2ns - clockevents_register_device This allows us to build SuperH clockevent and clocksource drivers as modules, see drivers/clocksource/sh_*.c [ Impact: allow modular build of clockevent drivers ] Signed-off-by: Magnus Damm LKML-Reference: <20090501055247.8286.64067.sendpatchset@rx1.opensource.se> Signed-off-by: Thomas Gleixner diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index d13be21..3948fa6 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -54,6 +54,7 @@ unsigned long clockevent_delta2ns(unsigned long latch, return (unsigned long) clc; } +EXPORT_SYMBOL_GPL(clockevent_delta2ns); /** * clockevents_set_mode - set the operating mode of a clock event device @@ -187,6 +188,7 @@ void clockevents_register_device(struct clock_event_device *dev) spin_unlock(&clockevents_lock); } +EXPORT_SYMBOL_GPL(clockevents_register_device); /* * Noop handler when we shut down an event device -- cgit v0.10.2 From eb457f36929da6d78c1f03cbb9038ef62646d79d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 2 May 2009 23:55:06 +0000 Subject: ne2k-pci: use dev->addr_len instead of "6" Spotted a tiny ugliness in a recently posted patch. This patch cuts it out. Jirka Signed-off-by: Jiri Pirko drivers/net/ne2k-pci.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) Signed-off-by: David S. Miller diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 7d83896..3fcebb7 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -374,7 +374,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, dev->ethtool_ops = &ne2k_pci_ethtool_ops; NS8390_init(dev, 0); - memcpy(dev->dev_addr, SA_prom, 6); + memcpy(dev->dev_addr, SA_prom, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); i = register_netdev(dev); -- cgit v0.10.2 From accc5b4f902b0ba83b2c6c48f2d9e7c204cef4a8 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Sun, 3 May 2009 08:58:48 +0000 Subject: ipv4: remove unused macro (FIB_RES_RESET) from ip_fib.h. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 34855ee..ef91fe9 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -124,14 +124,12 @@ struct fib_result_nl { #ifdef CONFIG_IP_ROUTE_MULTIPATH #define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel]) -#define FIB_RES_RESET(res) ((res).nh_sel = 0) #define FIB_TABLE_HASHSZ 2 #else /* CONFIG_IP_ROUTE_MULTIPATH */ #define FIB_RES_NH(res) ((res).fi->fib_nh[0]) -#define FIB_RES_RESET(res) #define FIB_TABLE_HASHSZ 256 -- cgit v0.10.2 From 513de11bba246b7a67df4c314d9fc936b6a75d0e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 3 May 2009 14:43:10 -0700 Subject: net: Avoid modulus in skb_tx_hash() for forwarding case. Based almost entirely upon a patch by Eric Dumazet. The common case is to have num-tx-queues <= num_rx_queues and even if num_tx_queues is larger it will not be significantly larger. Therefore, a subtraction loop is always going to be faster than modulus. Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 81442957..3c8073f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1735,8 +1735,12 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb) { u32 hash; - if (skb_rx_queue_recorded(skb)) - return skb_get_rx_queue(skb) % dev->real_num_tx_queues; + if (skb_rx_queue_recorded(skb)) { + hash = skb_get_rx_queue(skb); + while (unlikely (hash >= dev->real_num_tx_queues)) + hash -= dev->real_num_tx_queues; + return hash; + } if (skb->sk && skb->sk->sk_hash) hash = skb->sk->sk_hash; -- cgit v0.10.2 From 255cac91c3c9ce7dca7713b93ab03c75b7902e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 4 May 2009 11:07:36 -0700 Subject: tcp: extend ECN sysctl to allow server-side only ECN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should be very safe compared with full enabled, so I see no reason why it shouldn't be done right away. As ECN can only be negotiated if the SYN sending party is also supporting it, somebody in the loop probably knows what he/she is doing. If SYN does not ask for ECN, the server side SYN-ACK is identical to what it is without ECN. Thus it's quite safe. The chosen value is safe w.r.t to existing configs which choose to currently set manually either 0 or 1 but silently upgrades those who have not explicitly requested ECN off. Whether to just enable both sides comes up time to time but unless that gets done now we can at least make the servers aware of ECN already. As there are some known problems to occur if ECN is enabled, it's currently questionable whether there's any real gain from enabling clients as servers mostly won't support it anyway (so we'd hit just the negative sides). After enabling the servers and getting that deployed, the client end enable really has some potential gain too. Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index ec5de02..7f98aa3 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -168,7 +168,16 @@ tcp_dsack - BOOLEAN Allows TCP to send "duplicate" SACKs. tcp_ecn - BOOLEAN - Enable Explicit Congestion Notification in TCP. + Enable Explicit Congestion Notification (ECN) in TCP. ECN is only + used when both ends of the TCP flow support it. It is useful to + avoid losses due to congestion (when the bottleneck router supports + ECN). + Possible values are: + 0 disable ECN + 1 ECN enabled + 2 Only server-side ECN enabled. If the other end does + not support ECN, behavior is like with ECN disabled. + Default: 2 tcp_fack - BOOLEAN Enable FACK congestion avoidance and fast retransmission. diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c96a6bb..56dcf97 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -77,7 +77,7 @@ int sysctl_tcp_window_scaling __read_mostly = 1; int sysctl_tcp_sack __read_mostly = 1; int sysctl_tcp_fack __read_mostly = 1; int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH; -int sysctl_tcp_ecn __read_mostly; +int sysctl_tcp_ecn __read_mostly = 2; int sysctl_tcp_dsack __read_mostly = 1; int sysctl_tcp_app_win __read_mostly = 31; int sysctl_tcp_adv_win_scale __read_mostly = 2; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 59aec60..79c39dc 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -288,7 +288,7 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb) struct tcp_sock *tp = tcp_sk(sk); tp->ecn_flags = 0; - if (sysctl_tcp_ecn) { + if (sysctl_tcp_ecn == 1) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE | TCPCB_FLAG_CWR; tp->ecn_flags = TCP_ECN_OK; } -- cgit v0.10.2 From 6e8cf5c069c6cb7b316e9b1715eac38873dd5cab Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 4 May 2009 11:08:41 -0700 Subject: macb: Add support of the netpoll API With this patch in place, I'm successfully able to use the netconsole mechanism with the Calao USB-A9263 board, which uses the AT91SAM9263 CPU, which in terms of Ethernet controller is supported by the macb driver. Signed-off-by: Thomas Petazzoni [haavard.skinnemoen@atmel.com: disable_irq() -> local_irq_save()] [haavard.skinnemoen@atmel.com: convert to net_device_ops] Signed-off-by: Haavard Skinnemoen Signed-off-by: David S. Miller diff --git a/drivers/net/macb.c b/drivers/net/macb.c index e82aee4..7222659 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -599,6 +599,21 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void macb_poll_controller(struct net_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + macb_interrupt(dev->irq, dev); + local_irq_restore(flags); +} +#endif + static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct macb *bp = netdev_priv(dev); @@ -1094,6 +1109,9 @@ static const struct net_device_ops macb_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = macb_poll_controller, +#endif }; static int __init macb_probe(struct platform_device *pdev) -- cgit v0.10.2 From 4a84822c60afa2b0e2d3370041f69f9526a34757 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 4 May 2009 11:11:38 -0700 Subject: netns 1/2: don't get/put old netns on CLONE_NEWNET copy_net_ns() doesn't copy anything, it creates fresh netns, so get/put of old netns isn't needed. Signed-off-by: Alexey Dobriyan Acked-by: Serge Hallyn Signed-off-by: David S. Miller diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index e3bebd3..4488010 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -120,10 +120,8 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) struct net *new_net = NULL; int err; - get_net(old_net); - if (!(flags & CLONE_NEWNET)) - return old_net; + return get_net(old_net); err = -ENOMEM; new_net = net_alloc(); @@ -142,7 +140,6 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) if (err) goto out_free; out: - put_net(old_net); return new_net; out_free: -- cgit v0.10.2 From 088eb2d905de9518dad913995bb8aef493d4a7c5 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 4 May 2009 11:12:14 -0700 Subject: netns 2/2: extract net_create() net_create() will be used by C/R to create fresh netns on restart. Signed-off-by: Alexey Dobriyan Acked-by: Serge Hallyn Signed-off-by: David S. Miller diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 4488010..6b3edc9 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -115,38 +115,34 @@ static void net_free(struct net *net) kmem_cache_free(net_cachep, net); } -struct net *copy_net_ns(unsigned long flags, struct net *old_net) +static struct net *net_create(void) { - struct net *new_net = NULL; - int err; - - if (!(flags & CLONE_NEWNET)) - return get_net(old_net); - - err = -ENOMEM; - new_net = net_alloc(); - if (!new_net) - goto out_err; + struct net *net; + int rv; + net = net_alloc(); + if (!net) + return ERR_PTR(-ENOMEM); mutex_lock(&net_mutex); - err = setup_net(new_net); - if (!err) { + rv = setup_net(net); + if (rv == 0) { rtnl_lock(); - list_add_tail(&new_net->list, &net_namespace_list); + list_add_tail(&net->list, &net_namespace_list); rtnl_unlock(); } mutex_unlock(&net_mutex); + if (rv < 0) { + net_free(net); + return ERR_PTR(rv); + } + return net; +} - if (err) - goto out_free; -out: - return new_net; - -out_free: - net_free(new_net); -out_err: - new_net = ERR_PTR(err); - goto out; +struct net *copy_net_ns(unsigned long flags, struct net *old_net) +{ + if (!(flags & CLONE_NEWNET)) + return get_net(old_net); + return net_create(); } static void cleanup_net(struct work_struct *work) -- cgit v0.10.2 From c7ae011dc8306d982c25fb4f679752e790a08dc4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 4 May 2009 21:33:19 -0700 Subject: net: remove driver_data direct access of struct device from more drivers In the near future, the driver core is going to not allow direct access to the driver_data pointer in struct device. Instead, the functions dev_get_drvdata() and dev_set_drvdata() should be used. These functions have been around since the beginning, so are backwards compatible with all older kernel versions. Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 604c844..37a190d 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3256,7 +3256,7 @@ static ssize_t ehea_probe_port(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct ehea_adapter *adapter = dev->driver_data; + struct ehea_adapter *adapter = dev_get_drvdata(dev); struct ehea_port *port; struct device_node *eth_dn = NULL; int i; @@ -3311,7 +3311,7 @@ static ssize_t ehea_remove_port(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct ehea_adapter *adapter = dev->driver_data; + struct ehea_adapter *adapter = dev_get_drvdata(dev); struct ehea_port *port; int i; u32 logical_port_id; @@ -3399,7 +3399,7 @@ static int __devinit ehea_probe_adapter(struct of_device *dev, adapter->pd = EHEA_PD_ID; - dev->dev.driver_data = adapter; + dev_set_drvdata(&dev->dev, adapter); /* initialize adapter and ports */ @@ -3463,7 +3463,7 @@ out: static int __devexit ehea_remove(struct of_device *dev) { - struct ehea_adapter *adapter = dev->dev.driver_data; + struct ehea_adapter *adapter = dev_get_drvdata(&dev->dev); int i; for (i = 0; i < EHEA_MAX_PORTS; i++) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0a51b0b..7902e5e 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1255,7 +1255,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ return -ENOMEM; adapter = netdev_priv(netdev); - dev->dev.driver_data = netdev; + dev_set_drvdata(&dev->dev, netdev); adapter->vdev = dev; adapter->netdev = netdev; @@ -1341,7 +1341,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ static int __devexit ibmveth_remove(struct vio_dev *dev) { - struct net_device *netdev = dev->dev.driver_data; + struct net_device *netdev = dev_get_drvdata(&dev->dev); struct ibmveth_adapter *adapter = netdev_priv(netdev); int i; @@ -1474,8 +1474,8 @@ const char * buf, size_t count) struct ibmveth_buff_pool *pool = container_of(kobj, struct ibmveth_buff_pool, kobj); - struct net_device *netdev = - container_of(kobj->parent, struct device, kobj)->driver_data; + struct net_device *netdev = dev_get_drvdata( + container_of(kobj->parent, struct device, kobj)); struct ibmveth_adapter *adapter = netdev_priv(netdev); long value = simple_strtol(buf, NULL, 10); long rc; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index aaeebf5..7a4b9fb 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2300,7 +2300,7 @@ static const struct net_device_ops sbmac_netdev_ops = { static int sbmac_init(struct platform_device *pldev, long long base) { - struct net_device *dev = pldev->dev.driver_data; + struct net_device *dev = dev_get_drvdata(&pldev->dev); int idx = pldev->id; struct sbmac_softc *sc = netdev_priv(dev); unsigned char *eaddr; @@ -2731,7 +2731,7 @@ static int __init sbmac_probe(struct platform_device *pldev) goto out_unmap; } - pldev->dev.driver_data = dev; + dev_set_drvdata(&pldev->dev, dev); SET_NETDEV_DEV(dev, &pldev->dev); sc = netdev_priv(dev); @@ -2756,7 +2756,7 @@ out_out: static int __exit sbmac_remove(struct platform_device *pldev) { - struct net_device *dev = pldev->dev.driver_data; + struct net_device *dev = dev_get_drvdata(&pldev->dev); struct sbmac_softc *sc = netdev_priv(dev); unregister_netdev(dev); -- cgit v0.10.2 From b6907b0c705b6db221f937b4d343e2a6b280c8c5 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 5 May 2009 12:22:53 -0700 Subject: net: smsc911x: add power management functions This adds a power management implementation for smsc911x.c which assumes the chips remains powered during suspend. The device is put in its D1 power saving mode. Signed-off-by: Daniel Mack Acked-by: Steve Glendinning Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 5113b26..9a8528c 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -2109,12 +2109,58 @@ out_0: return retval; } +#ifdef CONFIG_PM +/* This implementation assumes the devices remains powered on its VDDVARIO + * pins during suspend. */ + +static int smsc911x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct smsc911x_data *pdata = netdev_priv(dev); + + /* enable wake on LAN, energy detection and the external PME + * signal. */ + smsc911x_reg_write(pdata, PMT_CTRL, + PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ | + PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_); + + return 0; +} + +static int smsc911x_resume(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int to = 100; + + /* Note 3.11 from the datasheet: + * "When the LAN9220 is in a power saving state, a write of any + * data to the BYTE_TEST register will wake-up the device." + */ + smsc911x_reg_write(pdata, BYTE_TEST, 0); + + /* poll the READY bit in PMT_CTRL. Any other access to the device is + * forbidden while this bit isn't set. Try for 100ms and return -EIO + * if it failed. */ + while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) + udelay(1000); + + return (to == 0) ? -EIO : 0; +} + +#else +#define smsc911x_suspend NULL +#define smsc911x_resume NULL +#endif + static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, .remove = smsc911x_drv_remove, .driver = { .name = SMSC_CHIPNAME, }, + .suspend = smsc911x_suspend, + .resume = smsc911x_resume, }; /* Entry point for loading the module */ -- cgit v0.10.2 From f001fde5eadd915f4858d22ed70d7040f48767cf Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 5 May 2009 02:48:28 +0000 Subject: net: introduce a list of device addresses dev_addr_list (v6) v5 -> v6 (current): -removed so far unused static functions -corrected dev_addr_del_multiple to call del instead of add v4 -> v5: -added device address type (suggested by davem) -removed refcounting (better to have simplier code then safe potentially few bytes) v3 -> v4: -changed kzalloc to kmalloc in __hw_addr_add_ii() -ASSERT_RTNL() avoided in dev_addr_flush() and dev_addr_init() v2 -> v3: -removed unnecessary rcu read locking -moved dev_addr_flush() calling to ensure no null dereference of dev_addr v1 -> v2: -added forgotten ASSERT_RTNL to dev_addr_init and dev_addr_flush -removed unnecessary rcu_read locking in dev_addr_init -use compare_ether_addr_64bits instead of compare_ether_addr -use L1_CACHE_BYTES as size for allocating struct netdev_hw_addr -use call_rcu instead of rcu_synchronize -moved is_etherdev_addr into __KERNEL__ ifdef This patch introduces a new list in struct net_device and brings a set of functions to handle the work with device address list. The list is a replacement for the original dev_addr field and because in some situations there is need to carry several device addresses with the net device. To be backward compatible, dev_addr is made to point to the first member of the list so original drivers sees no difference. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index a1f17ab..3d7a668 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -182,6 +182,33 @@ static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2], return compare_ether_addr(addr1, addr2); #endif } + +/** + * is_etherdev_addr - Tell if given Ethernet address belongs to the device. + * @dev: Pointer to a device structure + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Compare passed address with all addresses of the device. Return true if the + * address if one of the device addresses. + * + * Note that this function calls compare_ether_addr_64bits() so take care of + * the right padding. + */ +static inline bool is_etherdev_addr(const struct net_device *dev, + const u8 addr[6 + 2]) +{ + struct netdev_hw_addr *ha; + int res = 1; + + rcu_read_lock(); + for_each_dev_addr(dev, ha) { + res = compare_ether_addr_64bits(addr, ha->addr); + if (!res) + break; + } + rcu_read_unlock(); + return !res; +} #endif /* __KERNEL__ */ /** diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ff42aba..02882e2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -210,6 +210,16 @@ struct dev_addr_list #define dmi_users da_users #define dmi_gusers da_gusers +struct netdev_hw_addr { + struct list_head list; + unsigned char addr[MAX_ADDR_LEN]; + unsigned char type; +#define NETDEV_HW_ADDR_T_LAN 1 +#define NETDEV_HW_ADDR_T_SAN 2 +#define NETDEV_HW_ADDR_T_SLAVE 3 + struct rcu_head rcu_head; +}; + struct hh_cache { struct hh_cache *hh_next; /* Next entry */ @@ -784,8 +794,11 @@ struct net_device */ unsigned long last_rx; /* Time of last Rx */ /* Interface address info used in eth_type_trans() */ - unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast - because most packets are unicast) */ + unsigned char *dev_addr; /* hw address, (before bcast + because most packets are + unicast) */ + + struct list_head dev_addr_list; /* list of device hw addresses */ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ @@ -1791,6 +1804,13 @@ static inline void netif_addr_unlock_bh(struct net_device *dev) spin_unlock_bh(&dev->addr_list_lock); } +/* + * dev_addr_list walker. Should be used only for read access. Call with + * rcu_read_lock held. + */ +#define for_each_dev_addr(dev, ha) \ + list_for_each_entry_rcu(ha, &dev->dev_addr_list, list) + /* These functions live elsewhere (drivers/net/net_init.c, but related) */ extern void ether_setup(struct net_device *dev); @@ -1803,6 +1823,19 @@ extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, alloc_netdev_mq(sizeof_priv, name, setup, 1) extern int register_netdev(struct net_device *dev); extern void unregister_netdev(struct net_device *dev); + +/* Functions used for device addresses handling */ +extern int dev_addr_add(struct net_device *dev, unsigned char *addr, + unsigned char addr_type); +extern int dev_addr_del(struct net_device *dev, unsigned char *addr, + unsigned char addr_type); +extern int dev_addr_add_multiple(struct net_device *to_dev, + struct net_device *from_dev, + unsigned char addr_type); +extern int dev_addr_del_multiple(struct net_device *to_dev, + struct net_device *from_dev, + unsigned char addr_type); + /* Functions used for secondary unicast and multicast support */ extern void dev_set_rx_mode(struct net_device *dev); extern void __dev_set_rx_mode(struct net_device *dev); diff --git a/net/core/dev.c b/net/core/dev.c index 3c8073f..637ea71 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3434,6 +3434,252 @@ void dev_set_rx_mode(struct net_device *dev) netif_addr_unlock_bh(dev); } +/* hw addresses list handling functions */ + +static int __hw_addr_add(struct list_head *list, unsigned char *addr, + int addr_len, unsigned char addr_type) +{ + struct netdev_hw_addr *ha; + int alloc_size; + + if (addr_len > MAX_ADDR_LEN) + return -EINVAL; + + alloc_size = sizeof(*ha); + if (alloc_size < L1_CACHE_BYTES) + alloc_size = L1_CACHE_BYTES; + ha = kmalloc(alloc_size, GFP_ATOMIC); + if (!ha) + return -ENOMEM; + memcpy(ha->addr, addr, addr_len); + ha->type = addr_type; + list_add_tail_rcu(&ha->list, list); + return 0; +} + +static void ha_rcu_free(struct rcu_head *head) +{ + struct netdev_hw_addr *ha; + + ha = container_of(head, struct netdev_hw_addr, rcu_head); + kfree(ha); +} + +static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr, + int addr_len, unsigned char addr_type, + int ignore_index) +{ + struct netdev_hw_addr *ha; + int i = 0; + + list_for_each_entry(ha, list, list) { + if (i++ != ignore_index && + !memcmp(ha->addr, addr, addr_len) && + (ha->type == addr_type || !addr_type)) { + list_del_rcu(&ha->list); + call_rcu(&ha->rcu_head, ha_rcu_free); + return 0; + } + } + return -ENOENT; +} + +static int __hw_addr_add_multiple_ii(struct list_head *to_list, + struct list_head *from_list, + int addr_len, unsigned char addr_type, + int ignore_index) +{ + int err; + struct netdev_hw_addr *ha, *ha2; + unsigned char type; + + list_for_each_entry(ha, from_list, list) { + type = addr_type ? addr_type : ha->type; + err = __hw_addr_add(to_list, ha->addr, addr_len, type); + if (err) + goto unroll; + } + return 0; + +unroll: + list_for_each_entry(ha2, from_list, list) { + if (ha2 == ha) + break; + type = addr_type ? addr_type : ha2->type; + __hw_addr_del_ii(to_list, ha2->addr, addr_len, type, + ignore_index); + } + return err; +} + +static void __hw_addr_del_multiple_ii(struct list_head *to_list, + struct list_head *from_list, + int addr_len, unsigned char addr_type, + int ignore_index) +{ + struct netdev_hw_addr *ha; + unsigned char type; + + list_for_each_entry(ha, from_list, list) { + type = addr_type ? addr_type : ha->type; + __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type, + ignore_index); + } +} + +static void __hw_addr_flush(struct list_head *list) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, list, list) { + list_del_rcu(&ha->list); + call_rcu(&ha->rcu_head, ha_rcu_free); + } +} + +/* Device addresses handling functions */ + +static void dev_addr_flush(struct net_device *dev) +{ + /* rtnl_mutex must be held here */ + + __hw_addr_flush(&dev->dev_addr_list); + dev->dev_addr = NULL; +} + +static int dev_addr_init(struct net_device *dev) +{ + unsigned char addr[MAX_ADDR_LEN]; + struct netdev_hw_addr *ha; + int err; + + /* rtnl_mutex must be held here */ + + INIT_LIST_HEAD(&dev->dev_addr_list); + memset(addr, 0, sizeof(*addr)); + err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr), + NETDEV_HW_ADDR_T_LAN); + if (!err) { + /* + * Get the first (previously created) address from the list + * and set dev_addr pointer to this location. + */ + ha = list_first_entry(&dev->dev_addr_list, + struct netdev_hw_addr, list); + dev->dev_addr = ha->addr; + } + return err; +} + +/** + * dev_addr_add - Add a device address + * @dev: device + * @addr: address to add + * @addr_type: address type + * + * Add a device address to the device or increase the reference count if + * it already exists. + * + * The caller must hold the rtnl_mutex. + */ +int dev_addr_add(struct net_device *dev, unsigned char *addr, + unsigned char addr_type) +{ + int err; + + ASSERT_RTNL(); + + err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len, + addr_type); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + return err; +} +EXPORT_SYMBOL(dev_addr_add); + +/** + * dev_addr_del - Release a device address. + * @dev: device + * @addr: address to delete + * @addr_type: address type + * + * Release reference to a device address and remove it from the device + * if the reference count drops to zero. + * + * The caller must hold the rtnl_mutex. + */ +int dev_addr_del(struct net_device *dev, unsigned char *addr, + unsigned char addr_type) +{ + int err; + + ASSERT_RTNL(); + + err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, + addr_type, 0); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + return err; +} +EXPORT_SYMBOL(dev_addr_del); + +/** + * dev_addr_add_multiple - Add device addresses from another device + * @to_dev: device to which addresses will be added + * @from_dev: device from which addresses will be added + * @addr_type: address type - 0 means type will be used from from_dev + * + * Add device addresses of the one device to another. + ** + * The caller must hold the rtnl_mutex. + */ +int dev_addr_add_multiple(struct net_device *to_dev, + struct net_device *from_dev, + unsigned char addr_type) +{ + int err; + + ASSERT_RTNL(); + + if (from_dev->addr_len != to_dev->addr_len) + return -EINVAL; + err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list, + &from_dev->dev_addr_list, + to_dev->addr_len, addr_type, 0); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); + return err; +} +EXPORT_SYMBOL(dev_addr_add_multiple); + +/** + * dev_addr_del_multiple - Delete device addresses by another device + * @to_dev: device where the addresses will be deleted + * @from_dev: device by which addresses the addresses will be deleted + * @addr_type: address type - 0 means type will used from from_dev + * + * Deletes addresses in to device by the list of addresses in from device. + * + * The caller must hold the rtnl_mutex. + */ +int dev_addr_del_multiple(struct net_device *to_dev, + struct net_device *from_dev, + unsigned char addr_type) +{ + ASSERT_RTNL(); + + if (from_dev->addr_len != to_dev->addr_len) + return -EINVAL; + __hw_addr_del_multiple_ii(&to_dev->dev_addr_list, + &from_dev->dev_addr_list, + to_dev->addr_len, addr_type, 0); + call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); + return 0; +} +EXPORT_SYMBOL(dev_addr_del_multiple); + +/* unicast and multicast addresses handling functions */ + int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int glbl) { @@ -4776,6 +5022,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev->gso_max_size = GSO_MAX_SIZE; + dev_addr_init(dev); netdev_init_queues(dev); INIT_LIST_HEAD(&dev->napi_list); @@ -4801,6 +5048,9 @@ void free_netdev(struct net_device *dev) kfree(dev->_tx); + /* Flush device addresses */ + dev_addr_flush(dev); + list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) netif_napi_del(p); -- cgit v0.10.2 From aee64faf236815e0f337408892c01b373cd340f3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 5 May 2009 06:20:51 +0000 Subject: bonding: get rid of CONFIG_PROC_FS ifdefs Remove CONFIG_PROC_FS ifdefs from the code by adding void functions. Signed-off-by: Jiri Pirko drivers/net/bonding/bond_main.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-) Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e3af662..815191d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3459,8 +3459,28 @@ static void bond_destroy_proc_dir(void) bond_proc_dir = NULL; } } + +#else /* !CONFIG_PROC_FS */ + +static int bond_create_proc_entry(struct bonding *bond) +{ +} + +static void bond_remove_proc_entry(struct bonding *bond) +{ +} + +static void bond_create_proc_dir(void) +{ +} + +static void bond_destroy_proc_dir(void) +{ +} + #endif /* CONFIG_PROC_FS */ + /*-------------------------- netdev event handling --------------------------*/ /* @@ -3468,10 +3488,8 @@ static void bond_destroy_proc_dir(void) */ static int bond_event_changename(struct bonding *bond) { -#ifdef CONFIG_PROC_FS bond_remove_proc_entry(bond); bond_create_proc_entry(bond); -#endif down_write(&(bonding_rwsem)); bond_destroy_sysfs_entry(bond); bond_create_sysfs_entry(bond); @@ -4637,9 +4655,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); -#ifdef CONFIG_PROC_FS bond_create_proc_entry(bond); -#endif list_add_tail(&bond->bond_list, &bond_dev_list); return 0; @@ -4677,9 +4693,7 @@ static void bond_deinit(struct net_device *bond_dev) bond_work_cancel_all(bond); -#ifdef CONFIG_PROC_FS bond_remove_proc_entry(bond); -#endif } /* Unregister and free all bond devices. @@ -4698,9 +4712,7 @@ static void bond_free_all(void) bond_destroy(bond); } -#ifdef CONFIG_PROC_FS bond_destroy_proc_dir(); -#endif } /*------------------------- Module initialization ---------------------------*/ @@ -5196,9 +5208,7 @@ static int __init bonding_init(void) goto out; } -#ifdef CONFIG_PROC_FS bond_create_proc_dir(); -#endif init_rwsem(&bonding_rwsem); -- cgit v0.10.2 From c8014fe1d4548da8b9ea54730852c48a7117b03f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 4 May 2009 20:30:01 +0000 Subject: r6040: check for absent PHY Some devices have two R6040 MACs but the second one is not wired to any PHY, therefore the interface is just unusable. Warn the user about that and prevent device from registering. Tested-by: bifferos Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 6f97b47..6562725 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -742,6 +742,14 @@ static int r6040_up(struct net_device *dev) struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int ret; + u16 val; + + /* Check presence of a second PHY */ + val = r6040_phy_read(ioaddr, lp->phy_addr, 2); + if (val == 0xFFFF) { + printk(KERN_ERR DRV_NAME " no second PHY attached\n"); + return -EIO; + } /* Initialise and alloc RX/TX buffers */ r6040_init_txbufs(dev); -- cgit v0.10.2 From ba1cd541ecdaa659c5bf952659c4ad0d0707394d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 4 May 2009 20:30:45 +0000 Subject: r6040: bump version to 0.23 and date to 05May2009 Bump version to 0.23 and date to 05May2009. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 6562725..1508b124 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -49,8 +49,8 @@ #include #define DRV_NAME "r6040" -#define DRV_VERSION "0.22" -#define DRV_RELDATE "25Mar2009" +#define DRV_VERSION "0.23" +#define DRV_RELDATE "05May2009" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ -- cgit v0.10.2 From ae8d7f884a24ee920e417077b2615c6862be687f Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 5 May 2009 01:01:29 +0000 Subject: tcp:fix the code indent Signed-off-by: Shan Wei Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index bda74e8..fc79e34 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1593,7 +1593,7 @@ process: #endif { if (!tcp_prequeue(sk, skb)) - ret = tcp_v4_do_rcv(sk, skb); + ret = tcp_v4_do_rcv(sk, skb); } } else sk_add_backlog(sk, skb); -- cgit v0.10.2 From 78a658d9720ce1b3dd71af3ee6d207ca751a48f5 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Tue, 5 May 2009 01:03:32 +0000 Subject: lasi_82596: fix printk format warning drivers/net/lasi_82596.c:164: warning: format '%lx' expects type 'long unsigned int', but argument 3 has type 'resource_size_t' drivers/net/lasi_82596.c:169: warning: format '%lx' expects type 'long unsigned int', but argument 2 has type 'resource_size_t' Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index efbae4b..a0c5785 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -161,12 +161,12 @@ lan_init_chip(struct parisc_device *dev) if (!dev->irq) { printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n", - __FILE__, dev->hpa.start); + __FILE__, (unsigned long)dev->hpa.start); return -ENODEV; } - printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa.start, - dev->irq); + printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", + (unsigned long)dev->hpa.start, dev->irq); netdevice = alloc_etherdev(sizeof(struct i596_private)); if (!netdevice) -- cgit v0.10.2 From a46fa684fcb7001d79c97f2968696997b3b79064 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Mon, 4 May 2009 05:18:09 +0800 Subject: ocfs2: Don't printk the error when listing too many xattrs. Currently the kernel defines XATTR_LIST_MAX as 65536 in include/linux/limits.h. This is the largest buffer that is used for listing xattrs. But with ocfs2 xattr tree, we actually have no limit for the number. If filesystem has more names than can fit in the buffer, the kernel logs will be pollluted with something like this when listing: (27738,0):ocfs2_iterate_xattr_buckets:3158 ERROR: status = -34 (27738,0):ocfs2_xattr_tree_list_index_block:3264 ERROR: status = -34 So don't print "ERROR" message as this is not an ocfs2 error. Signed-off-by: Tao Ma Signed-off-by: Joel Becker diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 1563101..ba320e2 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -3154,7 +3154,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash)); if (func) { ret = func(inode, bucket, para); - if (ret) + if (ret && ret != -ERANGE) mlog_errno(ret); /* Fall through to bucket_relse() */ } @@ -3261,7 +3261,8 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode, ocfs2_list_xattr_bucket, &xl); if (ret) { - mlog_errno(ret); + if (ret != -ERANGE) + mlog_errno(ret); goto out; } -- cgit v0.10.2 From 2b53bc7bff17341d8b5ac12115f5c2363638e628 Mon Sep 17 00:00:00 2001 From: Coly Li Date: Tue, 5 May 2009 20:03:28 +0800 Subject: ocfs2: update comments in masklog.h In the mainline ocfs2 code, the interface for masklog is in files under /sys/fs/o2cb/masklog, but the comments in fs/ocfs2/cluster/masklog.h reference the old /proc interface. They are out of date. This patch modifies the comments in cluster/masklog.h, which also provides a bash script example on how to change the log mask bits. Signed-off-by: Coly Li Signed-off-by: Joel Becker diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index 7e72a81..696c32e 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h @@ -48,34 +48,33 @@ * only emit the appropriage printk() when the caller passes in a constant * mask, as is almost always the case. * - * All this bitmask nonsense is hidden from the /proc interface so that Joel - * doesn't have an aneurism. Reading the file gives a straight forward - * indication of which bits are on or off: - * ENTRY off - * EXIT off + * All this bitmask nonsense is managed from the files under + * /sys/fs/o2cb/logmask/. Reading the files gives a straightforward + * indication of which bits are allowed (allow) or denied (off/deny). + * ENTRY deny + * EXIT deny * TCP off * MSG off * SOCKET off - * ERROR off - * NOTICE on + * ERROR allow + * NOTICE allow * * Writing changes the state of a given bit and requires a strictly formatted * single write() call: * - * write(fd, "ENTRY on", 8); + * write(fd, "allow", 5); * - * would turn the entry bit on. "1" is also accepted in the place of "on", and - * "off" and "0" behave as expected. + * Echoing allow/deny/off string into the logmask files can flip the bits + * on or off as expected; here is the bash script for example: * - * Some trivial shell can flip all the bits on or off: + * log_mask="/sys/fs/o2cb/log_mask" + * for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do + * echo allow >"$log_mask"/"$node" + * done * - * log_mask="/proc/fs/ocfs2_nodemanager/log_mask" - * cat $log_mask | ( - * while read bit status; do - * # $1 is "on" or "off", say - * echo "$bit $1" > $log_mask - * done - * ) + * The debugfs.ocfs2 tool can also flip the bits with the -l option: + * + * debugfs.ocfs2 -l TCP allow */ /* for task_struct */ -- cgit v0.10.2 From 22cfbbfd9f67b67fe073010f51cb71d3632387d5 Mon Sep 17 00:00:00 2001 From: john stultz Date: Wed, 6 May 2009 11:43:57 +0200 Subject: ntp: adjust SHIFT_PLL to improve NTP convergence The conversion to the ntpv4 reference model f19923937321244e7dc334767eb4b67e0e3d5c74 ("ntp: convert to the NTP4 reference model") in 2.6.19 added nanosecond resolution the adjtimex interface, but also changed the "stiffness" of the frequency adjustments, causing NTP convergence time to greatly increase. SHIFT_PLL, which reduces the stiffness of the freq adjustments, was designed to be inversely linked to HZ, and the reference value of 4 was designed for Unix systems using HZ=100. However Linux's clock steering code mostly independent of HZ. So this patch reduces the SHIFT_PLL value from 4 to 2, which causes NTPd behavior to match kernels prior to 2.6.19, greatly reducing convergence times, and improving close synchronization through environmental thermal changes. The patch also changes some l's to L's in nearby code to avoid misreading 50l as 501. [ Impact: tweak NTP algorithm for faster convergence ] Signed-off-by: John Stultz Acked-by: Rik van Riel Cc: zippel@linux-m68k.org Signed-off-by: Andrew Morton LKML-Reference: <200905051956.n45JuVo9025575@imap1.linux-foundation.org> Signed-off-by: Ingo Molnar diff --git a/include/linux/timex.h b/include/linux/timex.h index aa3475f..0daf961 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -170,17 +170,37 @@ struct timex { #include /* - * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen - * for a slightly underdamped convergence characteristic. SHIFT_KH - * establishes the damping of the FLL and is chosen by wisdom and black - * art. + * SHIFT_PLL is used as a dampening factor to define how much we + * adjust the frequency correction for a given offset in PLL mode. + * It also used in dampening the offset correction, to define how + * much of the current value in time_offset we correct for each + * second. Changing this value changes the stiffness of the ntp + * adjustment code. A lower value makes it more flexible, reducing + * NTP convergence time. A higher value makes it stiffer, increasing + * convergence time, but making the clock more stable. * - * MAXTC establishes the maximum time constant of the PLL. With the - * SHIFT_KG and SHIFT_KF values given and a time constant range from - * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours, - * respectively. + * In David Mills' nanokenrel reference implmentation SHIFT_PLL is 4. + * However this seems to increase convergence time much too long. + * + * https://lists.ntp.org/pipermail/hackers/2008-January/003487.html + * + * In the above mailing list discussion, it seems the value of 4 + * was appropriate for other Unix systems with HZ=100, and that + * SHIFT_PLL should be decreased as HZ increases. However, Linux's + * clock steering implementation is HZ independent. + * + * Through experimentation, a SHIFT_PLL value of 2 was found to allow + * for fast convergence (very similar to the NTPv3 code used prior to + * v2.6.19), with good clock stability. + * + * + * SHIFT_FLL is used as a dampening factor to define how much we + * adjust the frequency correction for a given offset in FLL mode. + * In David Mills' nanokenrel reference implmentation SHIFT_PLL is 2. + * + * MAXTC establishes the maximum time constant of the PLL. */ -#define SHIFT_PLL 4 /* PLL frequency factor (shift) */ +#define SHIFT_PLL 2 /* PLL frequency factor (shift) */ #define SHIFT_FLL 2 /* FLL frequency factor (shift) */ #define MAXTC 10 /* maximum time constant (shift) */ @@ -192,10 +212,10 @@ struct timex { #define SHIFT_USEC 16 /* frequency offset scale (shift) */ #define PPM_SCALE ((s64)NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC)) #define PPM_SCALE_INV_SHIFT 19 -#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \ +#define PPM_SCALE_INV ((1LL << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \ PPM_SCALE + 1) -#define MAXPHASE 500000000l /* max phase error (ns) */ +#define MAXPHASE 500000000L /* max phase error (ns) */ #define MAXFREQ 500000 /* max frequency error (ns/s) */ #define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT) #define MINSEC 256 /* min interval between updates (s) */ -- cgit v0.10.2 From 0e41f715c04f85a40ae6531d660be2241717be1c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2009 11:48:56 +0200 Subject: mac80211: fix various problems in ibss code There are a few problems in the IBSS code: a) it tries to activate interfaces that are down after scanning b) it crashes after scanning on an IBSS iface that isn't active c) since the ssid_len is used as a flag, need to make it visible only after all other settings are set, this helps protect against b) For b), we get a system crash: wlan0: Creating new IBSS network, BSSID ce:f9:88:76:1e:4d BUG: unable to handle kernel NULL pointer dereference at (null) IP: [<...>] ieee80211_sta_find_ibss+0x294/0x37d [mac80211] Call Trace: [<...>] ieee80211_ibss_notify_scan_completed+0x0/0x88 [mac80211] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6030e00..895f485 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -786,8 +786,12 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; if (sdata->vif.type != NL80211_IFTYPE_ADHOC) continue; + if (!sdata->u.ibss.ssid_len) + continue; sdata->u.ibss.last_scan_completed = jiffies; ieee80211_sta_find_ibss(sdata); } @@ -827,9 +831,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, { struct sk_buff *skb; - memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); - sdata->u.ibss.ssid_len = params->ssid_len; - if (params->bssid) { memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); sdata->u.ibss.fixed_bssid = true; @@ -859,6 +860,17 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; sdata->u.ibss.ibss_join_req = jiffies; + memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); + + /* + * The ssid_len setting below is used to see whether + * we are active, and we need all other settings + * before that may get visible. + */ + mb(); + + sdata->u.ibss.ssid_len = params->ssid_len; + set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); -- cgit v0.10.2 From d5edaedc16ebd0635435dec068d49e07a76ba7d9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Apr 2009 23:02:51 +0200 Subject: mac80211: fix PS vs. scan race When somebody changes the PS parameters while scanning is in progress, we enable PS -- during the scan. This is clearly not desirable, and we can just abort enabling PS when scanning since when the scan finishes it will be taken care of. Signed-off-by: Johannes Berg Reviewed-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3610c11..2029b71 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -487,6 +487,13 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, { struct ieee80211_conf *conf = &local->hw.conf; + /* + * If we are scanning right now then the parameters will + * take effect when scan finishes. + */ + if (local->hw_scanning || local->sw_scanning) + return; + if (conf->dynamic_ps_timeout > 0 && !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { mod_timer(&local->dynamic_ps_timer, jiffies + -- cgit v0.10.2 From 9ccebe6148bcb0aba2d89743df2ff182ced505ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2009 10:32:36 +0200 Subject: mac80211: rename max_sleep_interval to max_sleep_period Kalle points out that max_sleep_interval is somewhat confusing because the value is measured in beacon intervals, and not in TU. Rename it to max_sleep_period to be consistent with things like DTIM period that are also measured in beacon intervals. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 446dbf7..81d706d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -559,7 +559,7 @@ enum ieee80211_conf_changed { * @beacon_int: beacon interval (TODO make interface config) * * @listen_interval: listen interval in units of beacon interval - * @max_sleep_interval: the maximum number of beacon intervals to sleep for + * @max_sleep_period: the maximum number of beacon intervals to sleep for * before checking the beacon for a TIM bit (managed mode only); this * value will be only achievable between DTIM frames, the hardware * needs to check for the multicast traffic bit in DTIM beacons. @@ -584,7 +584,7 @@ struct ieee80211_conf { int beacon_int; u32 flags; int power_level, dynamic_ps_timeout; - int max_sleep_interval; + int max_sleep_period; u16 listen_interval; bool radio_enabled; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2029b71..f8925ca 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -562,7 +562,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) maxslp = min_t(int, dtimper, latency / beaconint_us); - local->hw.conf.max_sleep_interval = maxslp; + local->hw.conf.max_sleep_period = maxslp; local->ps_sdata = found; } } else { -- cgit v0.10.2 From 2d72289095e9621158acf1d59a830cfe920fa93b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2009 10:38:26 +0200 Subject: mac80211: internally clear failed scans properly When the IBSS code wants to scan, but that fails, we can get stuck in a situation where you can never scan again. Fix this by properly notifying ourselves when the scan request has failed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 895f485..9fe1f93 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -439,7 +439,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) memcpy(sdata->local->int_scan_req.ssids[0].ssid, ifibss->ssid, IEEE80211_MAX_SSID_LEN); sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; - ieee80211_request_scan(sdata, &sdata->local->int_scan_req); + if (ieee80211_request_scan(sdata, &sdata->local->int_scan_req)) + ieee80211_scan_failed(sdata->local); } static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) @@ -560,7 +561,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) ifibss->ssid, IEEE80211_MAX_SSID_LEN); local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; - ieee80211_request_scan(sdata, &local->int_scan_req); + if (ieee80211_request_scan(sdata, &local->int_scan_req)) + ieee80211_scan_failed(local); } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { int interval = IEEE80211_SCAN_INTERVAL; -- cgit v0.10.2 From f3b85252f081581a8f257545ed748062dce7798b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2009 16:01:47 +0200 Subject: mac80211: fix scan races and rework scanning There are some places marked /* XXX maybe racy? */ and they really are racy because there's no locking. This patch reworks much of the scan code, and introduces proper locking for the scan request as well as the internal scanning (which is necessary for IBSS/managed modes). Helper functions are added to call the scanning code whenever necessary. The scan deferring is changed to simply queue the scanning work instead of trying to start the scan in place, the scanning work will then take care of the rest. Also, currently when internal scans are requested for an interface that is trying to associate, we reject such scans. This was not intended, the mlme code has provisions to scan twice when it can't find the BSS to associate with right away; this has never worked properly. Fix this by not rejecting internal scan requests for an interface that is associating. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 9fe1f93..25ff583 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -432,15 +432,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " "IBSS networks with same SSID (merge)\n", sdata->dev->name); - /* XXX maybe racy? */ - if (sdata->local->scan_req) - return; - - memcpy(sdata->local->int_scan_req.ssids[0].ssid, - ifibss->ssid, IEEE80211_MAX_SSID_LEN); - sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; - if (ieee80211_request_scan(sdata, &sdata->local->int_scan_req)) - ieee80211_scan_failed(sdata->local); + ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); } static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) @@ -553,16 +545,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " "join\n", sdata->dev->name); - /* XXX maybe racy? */ - if (local->scan_req) - return; - - memcpy(local->int_scan_req.ssids[0].ssid, - ifibss->ssid, IEEE80211_MAX_SSID_LEN); - local->int_scan_req.ssids[0].ssid_len = - ifibss->ssid_len; - if (ieee80211_request_scan(sdata, &local->int_scan_req)) - ieee80211_scan_failed(local); + ieee80211_request_internal_scan(sdata, ifibss->ssid, + ifibss->ssid_len); } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { int interval = IEEE80211_SCAN_INTERVAL; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1579bc9..e6fd4bc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -659,6 +659,7 @@ struct ieee80211_local { /* Scanning and BSS list */ + struct mutex scan_mtx; bool sw_scanning, hw_scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request int_scan_req; @@ -947,6 +948,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); /* scan/BSS handling */ void ieee80211_scan_work(struct work_struct *work); +int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, + const u8 *ssid, u8 ssid_len); int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); int ieee80211_scan_results(struct ieee80211_local *local, @@ -960,9 +963,6 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, const char *ie, size_t len); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); -void ieee80211_scan_failed(struct ieee80211_local *local); -int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, - struct cfg80211_scan_request *req); struct ieee80211_bss * ieee80211_bss_info_update(struct ieee80211_local *local, struct ieee80211_rx_status *rx_status, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5ca62ea..e00d124 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -783,6 +783,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_LIST_HEAD(&local->interfaces); mutex_init(&local->iflist_mtx); + mutex_init(&local->scan_mtx); spin_lock_init(&local->key_lock); @@ -1126,6 +1127,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) struct ieee80211_local *local = hw_to_local(hw); mutex_destroy(&local->iflist_mtx); + mutex_destroy(&local->scan_mtx); wiphy_free(local->hw.wiphy); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f8925ca..a2f5e62 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2072,19 +2072,15 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) return 0; } else { if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { + u8 ssid_len = 0; + + if (!(ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL)) + ssid_len = ifmgd->ssid_len; + ifmgd->assoc_scan_tries++; - /* XXX maybe racy? */ - if (local->scan_req) - return -1; - memcpy(local->int_scan_req.ssids[0].ssid, - ifmgd->ssid, IEEE80211_MAX_SSID_LEN); - if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) - local->int_scan_req.ssids[0].ssid_len = 0; - else - local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len; - if (ieee80211_start_scan(sdata, &local->int_scan_req)) - ieee80211_scan_failed(local); + ieee80211_request_internal_scan(sdata, ifmgd->ssid, + ssid_len); ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); @@ -2122,14 +2118,8 @@ static void ieee80211_sta_work(struct work_struct *work) ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { - /* - * The call to ieee80211_start_scan can fail but ieee80211_request_scan - * (which queued ieee80211_sta_work) did not return an error. Thus, call - * ieee80211_scan_failed here if ieee80211_start_scan fails in order to - * notify the scan requester. - */ - if (ieee80211_start_scan(sdata, local->scan_req)) - ieee80211_scan_failed(local); + queue_delayed_work(local->hw.workqueue, &local->scan_work, + round_jiffies_relative(0)); return; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f25b07f..086d216 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -202,18 +202,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, return RX_QUEUED; } -void ieee80211_scan_failed(struct ieee80211_local *local) -{ - if (WARN_ON(!local->scan_req)) - return; - - /* notify cfg80211 about the failed scan */ - if (local->scan_req != &local->int_scan_req) - cfg80211_scan_done(local->scan_req, true); - - local->scan_req = NULL; -} - /* * inform AP that we will go to sleep so that it will buffer the frames * while we scan @@ -274,29 +262,46 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) } } +static void ieee80211_restore_scan_ies(struct ieee80211_local *local) +{ + kfree(local->scan_req->ie); + local->scan_req->ie = local->orig_ies; + local->scan_req->ie_len = local->orig_ies_len; +} + void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + bool was_hw_scan; - if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) - return; + mutex_lock(&local->scan_mtx); - if (WARN_ON(!local->scan_req)) + if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) { + mutex_unlock(&local->scan_mtx); return; + } - if (local->hw_scanning) { - kfree(local->scan_req->ie); - local->scan_req->ie = local->orig_ies; - local->scan_req->ie_len = local->orig_ies_len; + if (WARN_ON(!local->scan_req)) { + mutex_unlock(&local->scan_mtx); + return; } + if (local->hw_scanning) + ieee80211_restore_scan_ies(local); + if (local->scan_req != &local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - if (local->hw_scanning) { - local->hw_scanning = false; + was_hw_scan = local->hw_scanning; + local->hw_scanning = false; + local->sw_scanning = false; + + /* we only have to protect scan_req and hw/sw scan */ + mutex_unlock(&local->scan_mtx); + + if (was_hw_scan) { /* * Somebody might have requested channel change during scan * that we won't have acted upon, try now. ieee80211_hw_config @@ -306,7 +311,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) goto done; } - local->sw_scanning = false; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); netif_tx_lock_bh(local->mdev); @@ -354,6 +358,146 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) } EXPORT_SYMBOL(ieee80211_scan_completed); +static int ieee80211_start_sw_scan(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + + /* + * Hardware/driver doesn't support hw_scan, so use software + * scanning instead. First send a nullfunc frame with power save + * bit on so that AP will buffer the frames for us while we are not + * listening, then send probe requests to each channel and wait for + * the responses. After all channels are scanned, tune back to the + * original channel and send a nullfunc frame with power save bit + * off to trigger the AP to send us all the buffered frames. + * + * Note that while local->sw_scanning is true everything else but + * nullfunc frames and probe requests will be dropped in + * ieee80211_tx_h_check_assoc(). + */ + if (local->ops->sw_scan_start) + local->ops->sw_scan_start(local_to_hw(local)); + + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* disable beaconing */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_ADHOC || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT) + ieee80211_if_config(sdata, + IEEE80211_IFCC_BEACON_ENABLED); + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { + netif_tx_stop_all_queues(sdata->dev); + ieee80211_scan_ps_enable(sdata); + } + } else + netif_tx_stop_all_queues(sdata->dev); + } + mutex_unlock(&local->iflist_mtx); + + local->scan_state = SCAN_SET_CHANNEL; + local->scan_channel_idx = 0; + + netif_addr_lock_bh(local->mdev); + local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + netif_addr_unlock_bh(local->mdev); + + /* TODO: start scan as soon as all nullfunc frames are ACKed */ + queue_delayed_work(local->hw.workqueue, &local->scan_work, + IEEE80211_CHANNEL_TIME); + + return 0; +} + + +static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, + struct cfg80211_scan_request *req) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + int rc; + + if (local->scan_req) + return -EBUSY; + + if (local->ops->hw_scan) { + u8 *ies; + int ielen; + + ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len + req->ie_len, GFP_KERNEL); + if (!ies) + return -ENOMEM; + + ielen = ieee80211_build_preq_ies(local, ies, + req->ie, req->ie_len); + local->orig_ies = req->ie; + local->orig_ies_len = req->ie_len; + req->ie = ies; + req->ie_len = ielen; + } + + local->scan_req = req; + local->scan_sdata = sdata; + + if (req != &local->int_scan_req && + sdata->vif.type == NL80211_IFTYPE_STATION && + (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE || + ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || + ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) { + /* actually wait for the assoc to finish/time out */ + set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); + return 0; + } + + if (local->ops->hw_scan) + local->hw_scanning = true; + else + local->sw_scanning = true; + /* + * Kicking off the scan need not be protected, + * only the scan variable stuff, since now + * local->scan_req is assigned and other callers + * will abort their scan attempts. + * + * This avoids getting a scan_mtx -> iflist_mtx + * dependency, so that the scan completed calls + * have more locking freedom. + */ + mutex_unlock(&local->scan_mtx); + + if (local->ops->hw_scan) + rc = local->ops->hw_scan(local_to_hw(local), + local->scan_req); + else + rc = ieee80211_start_sw_scan(local); + + mutex_lock(&local->scan_mtx); + + if (rc) { + if (local->ops->hw_scan) { + local->hw_scanning = false; + ieee80211_restore_scan_ies(local); + } else + local->sw_scanning = false; + + local->scan_req = NULL; + local->scan_sdata = NULL; + } + + return rc; +} + void ieee80211_scan_work(struct work_struct *work) { struct ieee80211_local *local = @@ -363,17 +507,41 @@ void ieee80211_scan_work(struct work_struct *work) int skip, i; unsigned long next_delay = 0; + mutex_lock(&local->scan_mtx); + if (!sdata || !local->scan_req) { + mutex_unlock(&local->scan_mtx); + return; + } + + if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) { + struct cfg80211_scan_request *req = local->scan_req; + int rc; + + local->scan_req = NULL; + + rc = __ieee80211_start_scan(sdata, req); + mutex_unlock(&local->scan_mtx); + + if (rc) + ieee80211_scan_completed(&local->hw, true); + return; + } + + mutex_unlock(&local->scan_mtx); + /* * Avoid re-scheduling when the sdata is going away. */ - if (!netif_running(sdata->dev)) + if (!netif_running(sdata->dev)) { + ieee80211_scan_completed(&local->hw, true); return; + } switch (local->scan_state) { case SCAN_SET_CHANNEL: /* if no more bands/channels left, complete scan */ if (local->scan_channel_idx >= local->scan_req->n_channels) { - ieee80211_scan_completed(local_to_hw(local), false); + ieee80211_scan_completed(&local->hw, false); return; } skip = 0; @@ -422,166 +590,35 @@ void ieee80211_scan_work(struct work_struct *work) next_delay); } - -int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, - struct cfg80211_scan_request *req) +int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, + struct cfg80211_scan_request *req) { - struct ieee80211_local *local = scan_sdata->local; - struct ieee80211_sub_if_data *sdata; - - if (!req) - return -EINVAL; - - if (local->scan_req && local->scan_req != req) - return -EBUSY; - - local->scan_req = req; - - /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) - * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS - * BSSID: MACAddress - * SSID - * ScanType: ACTIVE, PASSIVE - * ProbeDelay: delay (in microseconds) to be used prior to transmitting - * a Probe frame during active scanning - * ChannelList - * MinChannelTime (>= ProbeDelay), in TU - * MaxChannelTime: (>= MinChannelTime), in TU - */ - - /* MLME-SCAN.confirm - * BSSDescriptionSet - * ResultCode: SUCCESS, INVALID_PARAMETERS - */ - - if (local->sw_scanning || local->hw_scanning) { - if (local->scan_sdata == scan_sdata) - return 0; - return -EBUSY; - } - - if (local->ops->hw_scan) { - u8 *ies; - int rc, ielen; - - ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + req->ie_len, GFP_KERNEL); - if (!ies) - return -ENOMEM; + int res; - ielen = ieee80211_build_preq_ies(local, ies, - req->ie, req->ie_len); - local->orig_ies = req->ie; - local->orig_ies_len = req->ie_len; - req->ie = ies; - req->ie_len = ielen; - - local->hw_scanning = true; - rc = local->ops->hw_scan(local_to_hw(local), req); - if (rc) { - local->hw_scanning = false; - kfree(ies); - req->ie_len = local->orig_ies_len; - req->ie = local->orig_ies; - return rc; - } - local->scan_sdata = scan_sdata; - return 0; - } + mutex_lock(&sdata->local->scan_mtx); + res = __ieee80211_start_scan(sdata, req); + mutex_unlock(&sdata->local->scan_mtx); - /* - * Hardware/driver doesn't support hw_scan, so use software - * scanning instead. First send a nullfunc frame with power save - * bit on so that AP will buffer the frames for us while we are not - * listening, then send probe requests to each channel and wait for - * the responses. After all channels are scanned, tune back to the - * original channel and send a nullfunc frame with power save bit - * off to trigger the AP to send us all the buffered frames. - * - * Note that while local->sw_scanning is true everything else but - * nullfunc frames and probe requests will be dropped in - * ieee80211_tx_h_check_assoc(). - */ - local->sw_scanning = true; - if (local->ops->sw_scan_start) - local->ops->sw_scan_start(local_to_hw(local)); - - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) - continue; - - /* disable beaconing */ - if (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_ADHOC || - sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_if_config(sdata, - IEEE80211_IFCC_BEACON_ENABLED); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { - netif_tx_stop_all_queues(sdata->dev); - ieee80211_scan_ps_enable(sdata); - } - } else - netif_tx_stop_all_queues(sdata->dev); - } - mutex_unlock(&local->iflist_mtx); - - local->scan_state = SCAN_SET_CHANNEL; - local->scan_channel_idx = 0; - local->scan_sdata = scan_sdata; - local->scan_req = req; - - netif_addr_lock_bh(local->mdev); - local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; - local->ops->configure_filter(local_to_hw(local), - FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - netif_addr_unlock_bh(local->mdev); - - /* TODO: start scan as soon as all nullfunc frames are ACKed */ - queue_delayed_work(local->hw.workqueue, &local->scan_work, - IEEE80211_CHANNEL_TIME); - - return 0; + return res; } - -int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, - struct cfg80211_scan_request *req) +int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, + const u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = sdata->local; - struct ieee80211_if_managed *ifmgd; - - if (!req) - return -EINVAL; - - if (local->scan_req && local->scan_req != req) - return -EBUSY; - - local->scan_req = req; + int ret = -EBUSY; - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return ieee80211_start_scan(sdata, req); + mutex_lock(&local->scan_mtx); - /* - * STA has a state machine that might need to defer scanning - * while it's trying to associate/authenticate, therefore we - * queue it up to the state machine in that case. - */ + /* busy scanning */ + if (local->scan_req) + goto unlock; - if (local->sw_scanning || local->hw_scanning) { - if (local->scan_sdata == sdata) - return 0; - return -EBUSY; - } - - ifmgd = &sdata->u.mgd; - set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); - queue_work(local->hw.workqueue, &ifmgd->work); + memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); + local->int_scan_req.ssids[0].ssid_len = ssid_len; - return 0; + ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req); + unlock: + mutex_unlock(&local->scan_mtx); + return ret; } -- cgit v0.10.2 From 57c4d7b4c4986037be51476b8e3025d5ba18d8b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2009 16:10:04 +0200 Subject: mac80211: clean up beacon interval settings We currently have two beacon interval configuration knobs: hw.conf.beacon_int and vif.bss_info.beacon_int. This is rather confusing, even though the former is used when we beacon ourselves and the latter when we are associated to an AP. This just deprecates the hw.conf.beacon_int setting in favour of always using vif.bss_info.beacon_int. Since it touches all the beaconing IBSS code anyway, we can also add support for the cfg80211 IBSS beacon interval configuration easily. NOTE: The hw.conf.beacon_int setting is retained for now due to drivers still using it -- I couldn't untangle all drivers, some are updated in this patch. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index c8fa307..0e5967d 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -316,9 +316,9 @@ int ar9170_set_beacon_timers(struct ar9170 *ar) u32 v = 0; u32 pretbtt = 0; - v |= ar->hw->conf.beacon_int; - if (ar->vif) { + v |= ar->vif->bss_conf.beacon_int; + switch (ar->vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: @@ -326,7 +326,7 @@ int ar9170_set_beacon_timers(struct ar9170 *ar) break; case NL80211_IFTYPE_AP: v |= BIT(24); - pretbtt = (ar->hw->conf.beacon_int - 6) << 16; + pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16; break; default: break; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 1b60906..49c729b 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1337,7 +1337,7 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } - if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) { + if (changed & BSS_CHANGED_BEACON_INT) { err = ar9170_set_beacon_timers(ar); if (err) goto out; @@ -1499,6 +1499,9 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, #endif /* CONFIG_AR9170_LEDS */ } + if (changed & BSS_CHANGED_BEACON_INT) + err = ar9170_set_beacon_timers(ar); + if (changed & BSS_CHANGED_HT) { /* TODO */ err = 0; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c8c658b..e4b1d9e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2756,7 +2756,6 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&sc->lock); - sc->bintval = conf->beacon_int; sc->power_level = conf->power_level; ret = ath5k_chan_set(sc, conf->channel); @@ -3083,6 +3082,10 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct ath5k_softc *sc = hw->priv; + + if (changes & BSS_CHANGED_BEACON_INT) + sc->bintval = bss_conf->beacon_int; + if (changes & BSS_CHANGED_ASSOC) { mutex_lock(&sc->lock); sc->assoc = bss_conf->assoc; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c92d46f..d5084dd 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -590,6 +590,8 @@ struct ath_softc { int led_on_cnt; int led_off_cnt; + int beacon_interval; + struct ath_rfkill rf_kill; struct ath_ani ani; struct ath9k_node_stats nodestats; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index eb4759f..c17b838 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -320,8 +320,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) u64 tsfadjust; int intval; - intval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; + intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; /* * Calculate the TSF offset for this beacon slot, i.e., the @@ -431,8 +430,7 @@ void ath_beacon_tasklet(unsigned long data) * on the tsf to safeguard against missing an swba. */ - intval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; + intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); @@ -711,8 +709,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) /* Setup the beacon configuration parameters */ memset(&conf, 0, sizeof(struct ath_beacon_config)); - conf.beacon_interval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; + conf.beacon_interval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; conf.listen_interval = 1; conf.dtim_period = conf.beacon_interval; conf.dtim_count = 1; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2398d4f..28cc9cd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2358,16 +2358,6 @@ skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) sc->config.txpowlimit = 2 * conf->power_level; - /* - * The HW TSF has to be reset when the beacon interval changes. - * We set the flag here, and ath_beacon_config_ap() would take this - * into account when it gets called through the subsequent - * config_interface() call - with IFCC_BEACON in the changed field. - */ - - if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - sc->sc_flags |= SC_OP_TSF_RESET; - mutex_unlock(&sc->mutex); return 0; @@ -2635,6 +2625,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_bss_assoc_info(sc, vif, bss_conf); } + /* + * The HW TSF has to be reset when the beacon interval changes. + * We set the flag here, and ath_beacon_config_ap() would take this + * into account when it gets called through the subsequent + * config_interface() call - with IFCC_BEACON in the changed field. + */ + + if (changed & BSS_CHANGED_BEACON_INT) { + sc->sc_flags |= SC_OP_TSF_RESET; + sc->beacon_interval = bss_conf->beacon_int; + } + mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index faf2cab..501493f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -971,7 +971,7 @@ int ath_cabq_update(struct ath_softc *sc) else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; - qi.tqi_readyTime = (sc->hw->conf.beacon_int * + qi.tqi_readyTime = (sc->beacon_interval * sc->config.cabqReadytime) / 100; ath_txq_update(sc, qnum, &qi); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a97c6ff..3c693e6 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3468,11 +3468,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (phy->ops->set_rx_antenna) phy->ops->set_rx_antenna(dev, antenna); - /* Update templates for AP/mesh mode. */ - 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_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); @@ -3556,6 +3551,13 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, goto out_unlock_mutex; b43_mac_suspend(dev); + /* Update templates for AP/mesh mode. */ + if (changed & BSS_CHANGED_BEACON_INT && + (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) || + b43_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43_set_beacon_int(dev, conf->beacon_int); + if (changed & BSS_CHANGED_BASIC_RATES) b43_update_basic_rates(dev, conf->basic_rates); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ee202b4..276f314 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2721,11 +2721,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, /* Antennas for RX and management frame TX. */ b43legacy_mgmtframe_txantenna(dev, antenna_tx); - /* Update templates for AP mode. */ - if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) - b43legacy_set_beacon_int(dev, conf->beacon_int); - - if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { b43legacy_radio_turn_on(dev); @@ -2827,6 +2822,11 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, b43legacy_mac_suspend(dev); + if (changed & BSS_CHANGED_BEACON_INT && + (b43legacy_is_mode(wl, NL80211_IFTYPE_AP) || + b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43legacy_set_beacon_int(dev, conf->beacon_int); + if (changed & BSS_CHANGED_BASIC_RATES) b43legacy_update_basic_rates(dev, conf->basic_rates); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 277dfc5..4920dcf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -567,7 +567,8 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); priv->rxon_timing.atim_window = 0; } else { - beacon_int = iwl_adjust_beacon_interval(conf->beacon_int); + beacon_int = iwl_adjust_beacon_interval( + priv->vif->bss_conf.beacon_int); /* TODO: we need to get atim_window from upper stack * for now we set to 0 */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 3dec2d2..cd8a5ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1313,7 +1313,6 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; - hw->conf.beacon_int = 100; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) @@ -2751,7 +2750,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) priv->ibss_beacon = NULL; - priv->beacon_int = priv->hw->conf.beacon_int; + priv->beacon_int = priv->vif->bss_conf.beacon_int; priv->timestamp = 0; if ((priv->iw_mode == NL80211_IFTYPE_STATION)) priv->beacon_int = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a782292..f9d9b65 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -551,7 +551,8 @@ static void iwl3945_setup_rxon_timing(struct iwl_priv *priv) priv->rxon_timing.atim_window = 0; } else { priv->rxon_timing.beacon_interval = - iwl3945_adjust_beacon_interval(conf->beacon_int); + iwl3945_adjust_beacon_interval( + priv->vif->bss_conf.beacon_int); /* TODO: we need to get atim_window from upper stack * for now we set to 0 */ priv->rxon_timing.atim_window = 0; @@ -4211,8 +4212,6 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; - hw->conf.beacon_int = 100; - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->bands[IEEE80211_BAND_2GHZ]; diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index e7289e2..68e47fb 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -380,7 +380,7 @@ static int lbtf_op_config_interface(struct ieee80211_hw *hw, if (beacon) { lbtf_beacon_set(priv, beacon); kfree_skb(beacon); - lbtf_beacon_ctrl(priv, 1, hw->conf.beacon_int); + lbtf_beacon_ctrl(priv, 1, vif->bss_conf.beacon_int); } break; default: diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d4fdc8b..24c95a6 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -553,18 +553,13 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; - printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", + printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d)\n", wiphy_name(hw->wiphy), __func__, - conf->channel->center_freq, conf->radio_enabled, - conf->beacon_int); + conf->channel->center_freq, conf->radio_enabled); data->channel = conf->channel; data->radio_enabled = conf->radio_enabled; - data->beacon_int = 1024 * conf->beacon_int / 1000 * HZ / 1000; - if (data->beacon_int < 1) - data->beacon_int = 1; - - if (!data->started || !data->radio_enabled) + if (!data->started || !data->radio_enabled || !data->beacon_int) del_timer(&data->beacon_timer); else mod_timer(&data->beacon_timer, jiffies + data->beacon_int); @@ -615,6 +610,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + struct mac80211_hwsim_data *data = hw->priv; hwsim_check_magic(vif); @@ -628,6 +624,14 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, vp->aid = info->aid; } + if (changed & BSS_CHANGED_BEACON_INT) { + printk(KERN_DEBUG " %s: BCNINT: %d\n", + wiphy_name(hw->wiphy), info->beacon_int); + data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000; + if (WARN_ON(data->beacon_int)) + data->beacon_int = 1; + } + if (changed & BSS_CHANGED_ERP_CTS_PROT) { printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", wiphy_name(hw->wiphy), info->use_cts_prot); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 81d706d..22c65e8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -149,6 +149,7 @@ struct ieee80211_low_level_stats { * @BSS_CHANGED_ERP_SLOT: slot timing changed * @BSS_CHANGED_HT: 802.11n parameters changed * @BSS_CHANGED_BASIC_RATES: Basic rateset changed + * @BSS_CHANGED_BEACON_INT: Beacon interval changed */ enum ieee80211_bss_change { BSS_CHANGED_ASSOC = 1<<0, @@ -157,6 +158,7 @@ enum ieee80211_bss_change { BSS_CHANGED_ERP_SLOT = 1<<3, BSS_CHANGED_HT = 1<<4, BSS_CHANGED_BASIC_RATES = 1<<5, + BSS_CHANGED_BEACON_INT = 1<<6, }; /** @@ -529,7 +531,7 @@ enum ieee80211_conf_flags { * enum ieee80211_conf_changed - denotes which configuration changed * * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed - * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed + * @_IEEE80211_CONF_CHANGE_BEACON_INTERVAL: DEPRECATED * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed @@ -539,7 +541,7 @@ enum ieee80211_conf_flags { */ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), - IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), + _IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), @@ -548,6 +550,14 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), }; +static inline __deprecated enum ieee80211_conf_changed +__IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void) +{ + return _IEEE80211_CONF_CHANGE_BEACON_INTERVAL; +} +#define IEEE80211_CONF_CHANGE_BEACON_INTERVAL \ + __IEEE80211_CONF_CHANGE_BEACON_INTERVAL() + /** * struct ieee80211_conf - configuration of the device * diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5e1c230..a898ccd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -451,18 +451,11 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, * This is a kludge. beacon interval should really be part * of the beacon information. */ - if (params->interval && (sdata->local->hw.conf.beacon_int != - params->interval)) { - sdata->local->hw.conf.beacon_int = params->interval; - err = ieee80211_hw_config(sdata->local, - IEEE80211_CONF_CHANGE_BEACON_INTERVAL); - if (err < 0) - return err; - /* - * We updated some parameter so if below bails out - * it's not an error. - */ - err = 0; + if (params->interval && + (sdata->vif.bss_conf.beacon_int != params->interval)) { + sdata->vif.bss_conf.beacon_int = params->interval; + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_BEACON_INT); } /* Need to have a beacon head if we don't have one yet */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 25ff583..f4879dad 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -73,6 +73,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; u8 *pos; struct ieee80211_supported_band *sband; + u32 bss_change; if (local->ops->reset_tsf) { /* Reset own TSF to allow time synchronization work. */ @@ -92,8 +93,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, memcpy(ifibss->bssid, bssid, ETH_ALEN); - local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; - sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); @@ -101,6 +100,12 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, local->oper_channel = chan; local->oper_channel_type = NL80211_CHAN_NO_HT; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + sdata->vif.bss_conf.beacon_int = beacon_int; + bss_change = BSS_CHANGED_BEACON_INT; + bss_change |= ieee80211_reset_erp_info(sdata); + ieee80211_bss_info_change_notify(sdata, bss_change); + sband = local->hw.wiphy->bands[chan->band]; /* Build IBSS probe response */ @@ -111,7 +116,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); - mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); mgmt->u.beacon.timestamp = cpu_to_le64(tsf); mgmt->u.beacon.capab_info = cpu_to_le16(capability); @@ -181,8 +186,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss) { + u16 beacon_int = bss->cbss.beacon_interval; + + if (beacon_int < 10) + beacon_int = 10; + __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, - bss->cbss.beacon_interval, + beacon_int, bss->cbss.channel, bss->supp_rates_len, bss->supp_rates, bss->cbss.capability, @@ -464,9 +474,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) sband = local->hw.wiphy->bands[ifibss->channel->band]; - if (local->hw.conf.beacon_int == 0) - local->hw.conf.beacon_int = 100; - capability = WLAN_CAPABILITY_IBSS; if (sdata->default_key) @@ -480,7 +487,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) *pos++ = (u8) (rate / 5); } - __ieee80211_sta_join_ibss(sdata, bssid, local->hw.conf.beacon_int, + __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, ifibss->channel, sband->n_bitrates, supp_rates, capability, 0); } @@ -823,6 +830,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, } else sdata->u.ibss.fixed_bssid = false; + sdata->vif.bss_conf.beacon_int = params->beacon_interval; + sdata->u.ibss.channel = params->channel; sdata->u.ibss.fixed_channel = params->channel_fixed; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e00d124..b254879 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -294,9 +294,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; - if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) - return; - if (!changed) return; @@ -305,6 +302,17 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, &sdata->vif, &sdata->vif.bss_conf, changed); + + /* + * DEPRECATED + * + * ~changed is just there to not do this at resume time + */ + if (changed & BSS_CHANGED_BEACON_INT && ~changed) { + local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; + ieee80211_hw_config(local, + _IEEE80211_CONF_CHANGE_BEACON_INTERVAL); + } } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -971,9 +979,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) debugfs_hw_add(local); - if (local->hw.conf.beacon_int < 10) - local->hw.conf.beacon_int = 100; - if (local->hw.max_listen_interval == 0) local->hw.max_listen_interval = 1; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a2f5e62..bfd571e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -842,6 +842,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.timestamp = bss->cbss.tsf; sdata->vif.bss_conf.dtim_period = bss->dtim_period; + bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, bss->cbss.capability, bss->has_erp_value, bss->erp_value); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 654a8e9..7116220 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -543,9 +543,8 @@ void sta_info_unlink(struct sta_info **sta) spin_unlock_irqrestore(&local->sta_lock, flags); } -static inline int sta_info_buffer_expired(struct ieee80211_local *local, - struct sta_info *sta, - struct sk_buff *skb) +static int sta_info_buffer_expired(struct sta_info *sta, + struct sk_buff *skb) { struct ieee80211_tx_info *info; int timeout; @@ -556,8 +555,9 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local, info = IEEE80211_SKB_CB(skb); /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ - timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 / - 15625) * HZ; + timeout = (sta->listen_interval * + sta->sdata->vif.bss_conf.beacon_int * + 32 / 15625) * HZ; if (timeout < STA_TX_BUFFER_EXPIRE) timeout = STA_TX_BUFFER_EXPIRE; return time_after(jiffies, info->control.jiffies + timeout); @@ -577,7 +577,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, for (;;) { spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); skb = skb_peek(&sta->ps_tx_buf); - if (sta_info_buffer_expired(local, sta, skb)) + if (sta_info_buffer_expired(sta, skb)) skb = __skb_dequeue(&sta->ps_tx_buf); else skb = NULL; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1865622..29df650 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2132,7 +2132,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); + cpu_to_le16(sdata->vif.bss_conf.beacon_int); mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ pos = skb_put(skb, 2); -- cgit v0.10.2 From 2d0ddec5b2b859f06116f631fc0ffe94fbceb556 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2009 16:13:26 +0200 Subject: mac80211: unify config_interface and bss_info_changed The config_interface method is a little strange, it contains the BSSID and beacon updates, while bss_info_changed contains most other BSS information for each interface. This patch removes config_interface and rolls all the information it previously passed to drivers into bss_info_changed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index f718217..2b9e379 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1311,18 +1311,20 @@ static int adm8211_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int adm8211_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) +static void adm8211_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changes) { struct adm8211_priv *priv = dev->priv; + if (!(changes & BSS_CHANGED_BSSID)) + return; + if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { adm8211_set_bssid(dev, conf->bssid); memcpy(priv->bssid, conf->bssid, ETH_ALEN); } - - return 0; } static void adm8211_configure_filter(struct ieee80211_hw *dev, @@ -1753,7 +1755,7 @@ static const struct ieee80211_ops adm8211_ops = { .add_interface = adm8211_add_interface, .remove_interface = adm8211_remove_interface, .config = adm8211_config, - .config_interface = adm8211_config_interface, + .bss_info_changed = adm8211_bss_info_changed, .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 55f947a..cea7f14 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1965,13 +1965,18 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed) return 0; } -static int at76_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) +static void at76_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) { struct at76_priv *priv = hw->priv; at76_dbg(DBG_MAC80211, "%s():", __func__); + + if (!(changed & BSS_CHANGED_BSSID)) + return; + at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:"); mutex_lock(&priv->mtx); @@ -1983,8 +1988,6 @@ static int at76_config_interface(struct ieee80211_hw *hw, at76_join(priv); mutex_unlock(&priv->mtx); - - return 0; } /* must be atomic */ @@ -2076,7 +2079,7 @@ static const struct ieee80211_ops at76_ops = { .add_interface = at76_add_interface, .remove_interface = at76_remove_interface, .config = at76_config, - .config_interface = at76_config_interface, + .bss_info_changed = at76_bss_info_changed, .configure_filter = at76_configure_filter, .start = at76_mac80211_start, .stop = at76_mac80211_stop, diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 49c729b..3bd3a61 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1360,33 +1360,6 @@ out: return err; } -static int ar9170_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (conf->changed & IEEE80211_IFCC_BSSID) { - memcpy(ar->bssid, conf->bssid, ETH_ALEN); - err = ar9170_set_operating_mode(ar); - } - - if (conf->changed & IEEE80211_IFCC_BEACON) { - err = ar9170_update_beacon(ar); - - if (err) - goto out; - err = ar9170_set_beacon_timers(ar); - } - -out: - mutex_unlock(&ar->mutex); - return err; -} - static void ar9170_set_filters(struct work_struct *work) { struct ar9170 *ar = container_of(work, struct ar9170, @@ -1488,6 +1461,17 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&ar->mutex); + if (changed & BSS_CHANGED_BSSID) { + memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN); + err = ar9170_set_operating_mode(ar); + } + + if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { + err = ar9170_update_beacon(ar); + if (!err) + ar9170_set_beacon_timers(ar); + } + ar9170_regwrite_begin(ar); if (changed & BSS_CHANGED_ASSOC) { @@ -1796,7 +1780,6 @@ static const struct ieee80211_ops ar9170_ops = { .add_interface = ar9170_op_add_interface, .remove_interface = ar9170_op_remove_interface, .config = ar9170_op_config, - .config_interface = ar9170_op_config_interface, .configure_filter = ar9170_op_configure_filter, .conf_tx = ar9170_conf_tx, .bss_info_changed = ar9170_op_bss_info_changed, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index e4b1d9e..410fc4cf 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -227,9 +227,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); -static int ath5k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf); static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, @@ -259,7 +256,6 @@ static const struct ieee80211_ops ath5k_hw_ops = { .add_interface = ath5k_add_interface, .remove_interface = ath5k_remove_interface, .config = ath5k_config, - .config_interface = ath5k_config_interface, .configure_filter = ath5k_configure_filter, .set_key = ath5k_set_key, .get_stats = ath5k_get_stats, @@ -2764,44 +2760,6 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) return ret; } -static int -ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - int ret = 0; - - mutex_lock(&sc->lock); - if (sc->vif != vif) { - ret = -EIO; - goto unlock; - } - if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { - /* Cache for later use during resets */ - memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); - /* XXX: assoc id is set to 0 for now, mac80211 doesn't have - * a clean way of letting us retrieve this yet. */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); - mmiowb(); - } - if (conf->changed & IEEE80211_IFCC_BEACON && - (vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_AP)) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) { - ret = -ENOMEM; - goto unlock; - } - ath5k_beacon_update(sc, beacon); - } - -unlock: - mutex_unlock(&sc->lock); - return ret; -} - #define SUPPORTED_FIF_FLAGS \ FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ @@ -3082,15 +3040,40 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + + mutex_lock(&sc->lock); + if (WARN_ON(sc->vif != vif)) + goto unlock; + + if (changes & BSS_CHANGED_BSSID) { + /* Cache for later use during resets */ + memcpy(ah->ah_bssid, bss_conf->bssid, ETH_ALEN); + /* XXX: assoc id is set to 0 for now, mac80211 doesn't have + * a clean way of letting us retrieve this yet. */ + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + mmiowb(); + } if (changes & BSS_CHANGED_BEACON_INT) sc->bintval = bss_conf->beacon_int; if (changes & BSS_CHANGED_ASSOC) { - mutex_lock(&sc->lock); sc->assoc = bss_conf->assoc; if (sc->opmode == NL80211_IFTYPE_STATION) set_beacon_filter(hw, sc->assoc); - mutex_unlock(&sc->lock); } + + if (changes & BSS_CHANGED_BEACON && + (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT || + vif->type == NL80211_IFTYPE_AP)) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + if (beacon) + ath5k_beacon_update(sc, beacon); + } + + unlock: + mutex_unlock(&sc->lock); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 28cc9cd..d3dc8e2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2363,104 +2363,6 @@ skip_chan_change: return 0; } -static int ath9k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; - struct ath_vif *avp = (void *)vif->drv_priv; - u32 rfilt = 0; - int error, i; - - mutex_lock(&sc->mutex); - - /* TODO: Need to decide which hw opmode to use for multi-interface - * cases */ - if (vif->type == NL80211_IFTYPE_AP && - ah->opmode != NL80211_IFTYPE_AP) { - ah->opmode = NL80211_IFTYPE_STATION; - ath9k_hw_setopmode(ah); - memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); - sc->curaid = 0; - ath9k_hw_write_associd(sc); - /* 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 NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - /* Set BSSID */ - memcpy(sc->curbssid, conf->bssid, ETH_ALEN); - memcpy(avp->bssid, conf->bssid, ETH_ALEN); - sc->curaid = 0; - ath9k_hw_write_associd(sc); - - /* Set aggregation protection mode parameters */ - sc->config.ath_aggr_prot = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, - "RX filter 0x%x bssid %pM aid 0x%x\n", - rfilt, sc->curbssid, sc->curaid); - - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; - - break; - default: - break; - } - } - - if ((vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_AP) || - (vif->type == NL80211_IFTYPE_MESH_POINT)) { - if ((conf->changed & IEEE80211_IFCC_BEACON) || - (conf->changed & IEEE80211_IFCC_BEACON_ENABLED && - conf->enable_beacon)) { - /* - * Allocate and setup the beacon frame. - * - * Stop any previous beacon DMA. This may be - * necessary, for example, when an ibss merge - * causes reconfiguration; we may be called - * with beacon transmission active. - */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - - error = ath_beacon_alloc(aphy, vif); - if (error != 0) { - mutex_unlock(&sc->mutex); - return error; - } - - ath_beacon_config(sc, vif); - } - } - - /* Check for WLAN_CAPABILITY_PRIVACY ? */ - 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, - (u16)i, - sc->curbssid); - } - - /* Only legacy IBSS for now */ - if (vif->type == NL80211_IFTYPE_ADHOC) - ath_update_chainmask(sc, 0); - - mutex_unlock(&sc->mutex); - - return 0; -} - #define SUPPORTED_FILTERS \ (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ @@ -2597,9 +2499,92 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; + struct ath_vif *avp = (void *)vif->drv_priv; + u32 rfilt = 0; + int error, i; mutex_lock(&sc->mutex); + /* + * TODO: Need to decide which hw opmode to use for + * multi-interface cases + * XXX: This belongs into add_interface! + */ + if (vif->type == NL80211_IFTYPE_AP && + ah->opmode != NL80211_IFTYPE_AP) { + ah->opmode = NL80211_IFTYPE_STATION; + ath9k_hw_setopmode(ah); + memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); + /* Request full reset to get hw opmode changed properly */ + sc->sc_flags |= SC_OP_FULL_RESET; + } + + if ((changed & BSS_CHANGED_BSSID) && + !is_zero_ether_addr(bss_conf->bssid)) { + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + /* Set BSSID */ + memcpy(sc->curbssid, bss_conf->bssid, ETH_ALEN); + memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); + + /* Set aggregation protection mode parameters */ + sc->config.ath_aggr_prot = 0; + + DPRINTF(sc, ATH_DBG_CONFIG, + "RX filter 0x%x bssid %pM aid 0x%x\n", + rfilt, sc->curbssid, sc->curaid); + + /* need to reconfigure the beacon */ + sc->sc_flags &= ~SC_OP_BEACONS ; + + break; + default: + break; + } + } + + if ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((changed & BSS_CHANGED_BEACON) || + (changed & BSS_CHANGED_BEACON_ENABLED && + bss_conf->enable_beacon)) { + /* + * Allocate and setup the beacon frame. + * + * Stop any previous beacon DMA. This may be + * necessary, for example, when an ibss merge + * causes reconfiguration; we may be called + * with beacon transmission active. + */ + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + + error = ath_beacon_alloc(aphy, vif); + if (!error) + ath_beacon_config(sc, vif); + } + } + + /* Check for WLAN_CAPABILITY_PRIVACY ? */ + 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, + (u16)i, + sc->curbssid); + } + + /* Only legacy IBSS for now */ + if (vif->type == NL80211_IFTYPE_ADHOC) + ath_update_chainmask(sc, 0); + if (changed & BSS_CHANGED_ERP_PREAMBLE) { DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); @@ -2757,7 +2742,6 @@ struct ieee80211_ops ath9k_ops = { .add_interface = ath9k_add_interface, .remove_interface = ath9k_remove_interface, .config = ath9k_config, - .config_interface = ath9k_config_interface, .configure_filter = ath9k_configure_filter, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3c693e6..2615aaf 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3543,12 +3543,38 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; + unsigned long flags; mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev || b43_status(dev) < B43_STAT_STARTED) goto out_unlock_mutex; + + B43_WARN_ON(wl->vif != vif); + + if (changed & BSS_CHANGED_BSSID) { + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + 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 (changed & BSS_CHANGED_BEACON) + b43_update_templates(wl); + } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { + if (changed & BSS_CHANGED_BEACON) + b43_update_templates(wl); + } + b43_write_mac_bssid_templates(dev); + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + } + b43_mac_suspend(dev); /* Update templates for AP/mesh mode. */ @@ -3571,8 +3597,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, b43_mac_enable(dev); out_unlock_mutex: mutex_unlock(&wl->mutex); - - return; } static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -3730,41 +3754,6 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; - - if (!dev) - return -ENODEV; - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - B43_WARN_ON(wl->vif != vif); - if (conf->bssid) - memcpy(wl->bssid, conf->bssid, ETH_ALEN); - else - memset(wl->bssid, 0, ETH_ALEN); - if (b43_status(dev) >= B43_STAT_INITIALIZED) { - 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_BEACON) - b43_update_templates(wl); - } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { - if (conf->changed & IEEE80211_IFCC_BEACON) - b43_update_templates(wl); - } - b43_write_mac_bssid_templates(dev); - } - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); - - return 0; -} - /* Locking: wl->mutex */ static void b43_wireless_core_stop(struct b43_wldev *dev) { @@ -4434,7 +4423,6 @@ static const struct ieee80211_ops b43_hw_ops = { .remove_interface = b43_op_remove_interface, .config = b43_op_config, .bss_info_changed = b43_op_bss_info_changed, - .config_interface = b43_op_config_interface, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, .get_stats = b43_op_get_stats, diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 276f314..07c7898 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2804,6 +2804,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, u32 savedirqs; mutex_lock(&wl->mutex); + B43legacy_WARN_ON(wl->vif != vif); dev = wl->current_dev; phy = &dev->phy; @@ -2817,8 +2818,29 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, goto out_unlock_mutex; } savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43legacy_synchronize_irq(dev); + + if (changed & BSS_CHANGED_BSSID) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { + B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); + if (changed & BSS_CHANGED_BEACON) + b43legacy_update_templates(wl); + } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { + if (changed & BSS_CHANGED_BEACON) + b43legacy_update_templates(wl); + } + b43legacy_write_mac_bssid_templates(dev); + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + } b43legacy_mac_suspend(dev); @@ -2846,8 +2868,6 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); out_unlock_mutex: mutex_unlock(&wl->mutex); - - return; } static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, @@ -2889,40 +2909,6 @@ static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43legacy_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev = wl->current_dev; - unsigned long flags; - - if (!dev) - return -ENODEV; - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - B43legacy_WARN_ON(wl->vif != vif); - if (conf->bssid) - memcpy(wl->bssid, conf->bssid, ETH_ALEN); - else - memset(wl->bssid, 0, ETH_ALEN); - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { - B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); - if (conf->changed & IEEE80211_IFCC_BEACON) - b43legacy_update_templates(wl); - } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { - if (conf->changed & IEEE80211_IFCC_BEACON) - b43legacy_update_templates(wl); - } - b43legacy_write_mac_bssid_templates(dev); - } - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); - - return 0; -} - /* Locking: wl->mutex */ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) { @@ -3563,7 +3549,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .remove_interface = b43legacy_op_remove_interface, .config = b43legacy_op_dev_config, .bss_info_changed = b43legacy_op_bss_info_changed, - .config_interface = b43legacy_op_config_interface, .configure_filter = b43legacy_op_configure_filter, .get_stats = b43legacy_op_get_stats, .get_tx_stats = b43legacy_op_get_tx_stats, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4920dcf..dd8b15e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2623,7 +2623,6 @@ static struct ieee80211_ops iwl_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .config_interface = iwl_mac_config_interface, .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .update_tkip_key = iwl_mac_update_tkip_key, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index cd8a5ed..0f21fc1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2238,15 +2238,69 @@ static void iwl_ht_conf(struct iwl_priv *priv, #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) void iwl_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) { struct iwl_priv *priv = hw->priv; int ret; IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); + if (!iwl_is_alive(priv)) + return; + + mutex_lock(&priv->mutex); + + if (changes & BSS_CHANGED_BEACON && + priv->iw_mode == NL80211_IFTYPE_AP) { + dev_kfree_skb(priv->ibss_beacon); + priv->ibss_beacon = ieee80211_beacon_get(hw, vif); + } + + if ((changes & BSS_CHANGED_BSSID) && !iwl_is_rfkill(priv)) { + /* If there is currently a HW scan going on in the background + * then we need to cancel it else the RXON below will fail. */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARN(priv, "Aborted scan still in progress " + "after 100ms\n"); + IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return; + } + memcpy(priv->staging_rxon.bssid_addr, + bss_conf->bssid, ETH_ALEN); + + /* TODO: Audit driver for usage of these members and see + * if mac80211 deprecates them (priv->bssid looks like it + * shouldn't be there, but I haven't scanned the IBSS code + * to verify) - jpk */ + memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); + + if (priv->iw_mode == NL80211_IFTYPE_AP) + iwlcore_config_ap(priv); + else { + int rc = iwlcore_commit_rxon(priv); + if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) + iwl_rxon_add_station( + priv, priv->active_rxon.bssid_addr, 1); + } + } else if (!iwl_is_rfkill(priv)) { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv); + } + + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + changes & BSS_CHANGED_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + if (beacon) + iwl_mac_beacon_update(hw, beacon); + } + + mutex_unlock(&priv->mutex); + if (changes & BSS_CHANGED_ERP_PREAMBLE) { IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", bss_conf->use_short_preamble); @@ -2305,7 +2359,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, &priv->staging_rxon, sizeof(struct iwl_rxon_cmd)); } - + IWL_DEBUG_MAC80211(priv, "leave\n"); } EXPORT_SYMBOL(iwl_bss_info_changed); @@ -2589,106 +2643,6 @@ out: } EXPORT_SYMBOL(iwl_mac_config); -int iwl_mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - int rc; - - if (conf == NULL) - return -EIO; - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n"); - return 0; - } - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC && - conf->changed & IEEE80211_IFCC_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) - return -ENOMEM; - mutex_lock(&priv->mutex); - rc = iwl_mac_beacon_update(hw, beacon); - mutex_unlock(&priv->mutex); - if (rc) - return rc; - } - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - mutex_lock(&priv->mutex); - - if (conf->bssid) - IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid); - -/* - * very dubious code was here; the probe filtering flag is never set: - * - if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && - !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { - */ - - if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (!conf->bssid) { - conf->bssid = priv->mac_addr; - memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n", - conf->bssid); - } - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = ieee80211_beacon_get(hw, vif); - } - - if (iwl_is_rfkill(priv)) - goto done; - - if (conf->bssid && !is_zero_ether_addr(conf->bssid) && - !is_multicast_ether_addr(conf->bssid)) { - /* If there is currently a HW scan going on in the background - * then we need to cancel it else the RXON below will fail. */ - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress " - "after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - mutex_unlock(&priv->mutex); - return -EAGAIN; - } - memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); - - /* TODO: Audit driver for usage of these members and see - * if mac80211 deprecates them (priv->bssid looks like it - * shouldn't be there, but I haven't scanned the IBSS code - * to verify) - jpk */ - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwlcore_config_ap(priv); - else { - rc = iwlcore_commit_rxon(priv); - if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) - iwl_rxon_add_station( - priv, priv->active_rxon.bssid_addr, 1); - } - - } else { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - } - - done: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - - return 0; -} -EXPORT_SYMBOL(iwl_mac_config_interface); - int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d4c60af..bd7f9d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -281,9 +281,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); void iwl_config_ap(struct iwl_priv *priv); -int iwl_mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf); int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); void iwl_mac_reset_tsf(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f9d9b65..5cd4321 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4106,7 +4106,6 @@ static struct ieee80211_ops iwl3945_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .config_interface = iwl_mac_config_interface, .configure_filter = iwl_configure_filter, .set_key = iwl3945_mac_set_key, .get_tx_stats = iwl_mac_get_tx_stats, diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 68e47fb..10a99e2 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -366,36 +366,6 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) 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, vif->bss_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, @@ -451,6 +421,29 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct lbtf_private *priv = hw->priv; + struct sk_buff *beacon; + + if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_INT)) { + 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, + bss_conf->beacon_int); + } + break; + default: + break; + } + } + + if (changes & BSS_CHANGED_BSSID) { + bool activate = !is_zero_ether_addr(bss_conf->bssid); + lbtf_set_bssid(priv, activate, bss_conf->bssid); + } if (changes & BSS_CHANGED_ERP_PREAMBLE) { if (bss_conf->use_short_preamble) @@ -459,8 +452,6 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, priv->preamble = CMD_TYPE_LONG_PREAMBLE; lbtf_set_radio_control(priv); } - - return; } static const struct ieee80211_ops lbtf_ops = { @@ -470,7 +461,6 @@ static const struct ieee80211_ops lbtf_ops = { .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, }; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 24c95a6..e67b424 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -587,23 +587,6 @@ 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) -{ - struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - - hwsim_check_magic(vif); - if (conf->changed & IEEE80211_IFCC_BSSID) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", - wiphy_name(hw->wiphy), __func__, - conf->bssid); - memcpy(vp->bssid, conf->bssid, ETH_ALEN); - } - return 0; -} - static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -617,6 +600,13 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", wiphy_name(hw->wiphy), __func__, changed); + if (changed & BSS_CHANGED_BSSID) { + printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", + wiphy_name(hw->wiphy), __func__, + info->bssid); + memcpy(vp->bssid, info->bssid, ETH_ALEN); + } + if (changed & BSS_CHANGED_ASSOC) { printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", wiphy_name(hw->wiphy), info->assoc, info->aid); @@ -708,7 +698,6 @@ 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, diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a9a9704..46b288d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3089,19 +3089,6 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) return rc ? -EINVAL : 0; } -static int mwl8k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - u32 changed = conf->changed; - - if (changed & IEEE80211_IFCC_BSSID) - memcpy(mv_vif->bssid, conf->bssid, IEEE80211_ADDR_LEN); - - return 0; -} - struct mwl8k_bss_info_changed_worker { struct mwl8k_work_struct header; struct ieee80211_vif *vif; @@ -3183,8 +3170,12 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, { struct mwl8k_bss_info_changed_worker *worker; struct mwl8k_priv *priv = hw->priv; + struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); int rc; + if (changed & BSS_CHANGED_BSSID) + memcpy(mv_vif->bssid, info->bssid, IEEE80211_ADDR_LEN); + if ((changed & BSS_CHANGED_ASSOC) == 0) return; @@ -3442,7 +3433,6 @@ static const struct ieee80211_ops mwl8k_ops = { .add_interface = mwl8k_add_interface, .remove_interface = mwl8k_remove_interface, .config = mwl8k_config, - .config_interface = mwl8k_config_interface, .bss_info_changed = mwl8k_bss_info_changed, .configure_filter = mwl8k_configure_filter, .set_rts_threshold = mwl8k_set_rts_threshold, diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 7139496..b857852 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -2204,41 +2204,6 @@ out: return ret; } -static int p54_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct p54_common *priv = dev->priv; - int ret = 0; - - mutex_lock(&priv->conf_mutex); - if (conf->changed & IEEE80211_IFCC_BSSID) { - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - ret = p54_setup_mac(dev); - if (ret) - goto out; - } - - if (conf->changed & IEEE80211_IFCC_BEACON) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0); - if (ret) - goto out; - ret = p54_setup_mac(dev); - if (ret) - goto out; - ret = p54_beacon_update(dev, vif); - if (ret) - goto out; - ret = p54_set_edcf(dev); - if (ret) - goto out; - } - -out: - mutex_unlock(&priv->conf_mutex); - return ret; -} - static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -2342,8 +2307,32 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, u32 changed) { struct p54_common *priv = dev->priv; + int ret; + + mutex_lock(&priv->conf_mutex); + if (changed & BSS_CHANGED_BSSID) { + memcpy(priv->bssid, info->bssid, ETH_ALEN); + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + + if (changed & BSS_CHANGED_BEACON) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0); + if (ret) + goto out; + ret = p54_setup_mac(dev); + if (ret) + goto out; + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + } + /* XXX: this mimics having two callbacks... clean up */ + out: + mutex_unlock(&priv->conf_mutex); - if (changed & BSS_CHANGED_ERP_SLOT) { + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) { priv->use_short_slot = info->use_short_slot; p54_set_edcf(dev); } @@ -2364,7 +2353,6 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, p54_setup_mac(dev); } } - } static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, @@ -2619,7 +2607,6 @@ static const struct ieee80211_ops p54_ops = { .sta_notify = p54_sta_notify, .set_key = p54_set_key, .config = p54_config, - .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 411eb9c..6f39ba6 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1580,7 +1580,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index e1be67c..906960f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1879,7 +1879,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 9e630e7..08e8833 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1908,7 +1908,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e03d699..0be3955 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -943,9 +943,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); -int rt2x00mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c41a0b9..c4c06b4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -390,56 +390,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) } EXPORT_SYMBOL_GPL(rt2x00mac_config); -int rt2x00mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(vif); - int update_bssid = 0; - int status = 0; - - /* - * Mac80211 might be calling this function while we are trying - * to remove the device or perhaps suspending it. - */ - if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - return 0; - - spin_lock(&intf->lock); - - /* - * conf->bssid can be NULL if coming from the internal - * beacon update routine. - */ - if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { - update_bssid = 1; - memcpy(&intf->bssid, conf->bssid, ETH_ALEN); - } - - spin_unlock(&intf->lock); - - /* - * Call rt2x00_config_intf() outside of the spinlock context since - * the call will sleep for USB drivers. By using the ieee80211_if_conf - * values as arguments we make keep access to rt2x00_intf thread safe - * even without the lock. - */ - rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, - update_bssid ? conf->bssid : NULL); - - /* - * Update the beacon. - */ - if (conf->changed & (IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED)) - status = rt2x00queue_update_beacon(rt2x00dev, vif, - conf->enable_beacon); - - return status; -} -EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); - void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -623,6 +573,44 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); unsigned int delayed = 0; + int update_bssid = 0; + + /* + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. + */ + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return; + + spin_lock(&intf->lock); + + /* + * conf->bssid can be NULL if coming from the internal + * beacon update routine. + */ + if (changes & BSS_CHANGED_BSSID) { + update_bssid = 1; + memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN); + } + + spin_unlock(&intf->lock); + + /* + * Call rt2x00_config_intf() outside of the spinlock context since + * the call will sleep for USB drivers. By using the ieee80211_if_conf + * values as arguments we make keep access to rt2x00_intf thread safe + * even without the lock. + */ + if (changes & BSS_CHANGED_BSSID) + rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, + update_bssid ? bss_conf->bssid : NULL); + + /* + * Update the beacon. + */ + if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) + rt2x00queue_update_beacon(rt2x00dev, vif, + bss_conf->enable_beacon); /* * When the association status has changed we must reset the link diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 4346cd1..cb521ee 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2735,7 +2735,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 853b2b2..6bd28a6 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2259,7 +2259,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 387c133..7e65d7c 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -702,30 +702,26 @@ static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int rtl8180_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); - else - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); - - return 0; -} - static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct rtl8180_priv *priv = dev->priv; + int i; + + if (changed & BSS_CHANGED_BSSID) { + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], + info->bssid[i]); + + if (is_valid_ether_addr(info->bssid)) + rtl818x_iowrite8(priv, &priv->map->MSR, + RTL818X_MSR_INFRA); + else + rtl818x_iowrite8(priv, &priv->map->MSR, + RTL818X_MSR_NO_LINK); + } if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) priv->rf->conf_erp(dev, info); @@ -770,7 +766,6 @@ static const struct ieee80211_ops rtl8180_ops = { .add_interface = rtl8180_add_interface, .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, - .config_interface = rtl8180_config_interface, .bss_info_changed = rtl8180_bss_info_changed, .configure_filter = rtl8180_configure_filter, }; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index ac558da..158827e 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1090,32 +1090,6 @@ static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int rtl8187_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - u8 reg; - - mutex_lock(&priv->conf_mutex); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) { - reg = RTL818X_MSR_INFRA; - if (priv->is_rtl8187b) - reg |= RTL818X_MSR_ENEDCA; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } else { - reg = RTL818X_MSR_NO_LINK; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } - - mutex_unlock(&priv->conf_mutex); - return 0; -} - /* * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for * example. Thus we have to use raw values for AC_*_PARAM register addresses. @@ -1193,6 +1167,27 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, u32 changed) { struct rtl8187_priv *priv = dev->priv; + int i; + u8 reg; + + if (changed & BSS_CHANGED_BSSID) { + mutex_lock(&priv->conf_mutex); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], + info->bssid[i]); + + if (is_valid_ether_addr(info->bssid)) { + reg = RTL818X_MSR_INFRA; + if (priv->is_rtl8187b) + reg |= RTL818X_MSR_ENEDCA; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } else { + reg = RTL818X_MSR_NO_LINK; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } + + mutex_unlock(&priv->conf_mutex); + } if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) rtl8187_conf_erp(priv, info->use_short_slot, @@ -1274,7 +1269,6 @@ static const struct ieee80211_ops rtl8187_ops = { .add_interface = rtl8187_add_interface, .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, - .config_interface = rtl8187_config_interface, .bss_info_changed = rtl8187_bss_info_changed, .configure_filter = rtl8187_configure_filter, .conf_tx = rtl8187_conf_tx diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index c3a5126..6bdb170 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -755,52 +755,6 @@ static int zd_op_config(struct ieee80211_hw *hw, u32 changed) return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } -static int zd_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct zd_mac *mac = zd_hw_mac(hw); - int associated; - int r; - - 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); - - if (!beacon) - return -ENOMEM; - r = zd_mac_config_beacon(hw, beacon); - kfree_skb(beacon); - - if (r < 0) - return r; - } - - if (conf->changed & IEEE80211_IFCC_BEACON_ENABLED) { - u32 interval; - - if (conf->enable_beacon) - interval = BCN_MODE_IBSS | hw->conf.beacon_int; - else - interval = 0; - - r = zd_set_beacon_interval(&mac->chip, interval); - if (r < 0) - return r; - } - } else - associated = is_valid_ether_addr(conf->bssid); - - spin_lock_irq(&mac->lock); - mac->associated = associated; - spin_unlock_irq(&mac->lock); - - /* TODO: do hardware bssid filtering */ - return 0; -} - static void zd_process_intr(struct work_struct *work) { u16 int_status; @@ -923,9 +877,42 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, { struct zd_mac *mac = zd_hw_mac(hw); unsigned long flags; + int associated; dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); + if (mac->type == NL80211_IFTYPE_MESH_POINT || + mac->type == NL80211_IFTYPE_ADHOC) { + associated = true; + if (changes & BSS_CHANGED_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + if (beacon) { + zd_mac_config_beacon(hw, beacon); + kfree_skb(beacon); + } + } + + if (changes & BSS_CHANGED_BEACON_ENABLED) { + u32 interval; + + if (bss_conf->enable_beacon) + interval = BCN_MODE_IBSS | + bss_conf->beacon_int; + else + interval = 0; + + zd_set_beacon_interval(&mac->chip, interval); + } + } else + associated = is_valid_ether_addr(bss_conf->bssid); + + spin_lock_irq(&mac->lock); + mac->associated = associated; + spin_unlock_irq(&mac->lock); + + /* TODO: do hardware bssid filtering */ + if (changes & BSS_CHANGED_ERP_PREAMBLE) { spin_lock_irqsave(&mac->lock, flags); mac->short_preamble = bss_conf->use_short_preamble; @@ -952,7 +939,6 @@ static const struct ieee80211_ops zd_ops = { .add_interface = zd_op_add_interface, .remove_interface = zd_op_remove_interface, .config = zd_op_config, - .config_interface = zd_op_config_interface, .configure_filter = zd_op_configure_filter, .bss_info_changed = zd_op_bss_info_changed, .get_tsf = zd_op_get_tsf, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 22c65e8..7806e22 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -150,6 +150,12 @@ struct ieee80211_low_level_stats { * @BSS_CHANGED_HT: 802.11n parameters changed * @BSS_CHANGED_BASIC_RATES: Basic rateset changed * @BSS_CHANGED_BEACON_INT: Beacon interval changed + * @BSS_CHANGED_BSSID: BSSID changed, for whatever + * reason (IBSS and managed mode) + * @BSS_CHANGED_BEACON: Beacon data changed, retrieve + * new beacon (beaconing modes) + * @BSS_CHANGED_BEACON_ENABLED: Beaconing should be + * enabled/disabled (beaconing modes) */ enum ieee80211_bss_change { BSS_CHANGED_ASSOC = 1<<0, @@ -159,6 +165,9 @@ enum ieee80211_bss_change { BSS_CHANGED_HT = 1<<4, BSS_CHANGED_BASIC_RATES = 1<<5, BSS_CHANGED_BEACON_INT = 1<<6, + BSS_CHANGED_BSSID = 1<<7, + BSS_CHANGED_BEACON = 1<<8, + BSS_CHANGED_BEACON_ENABLED = 1<<9, }; /** @@ -192,8 +201,11 @@ struct ieee80211_bss_ht_conf { * @basic_rates: bitmap of basic rates, each bit stands for an * index into the rate table configured by the driver in * the current band. + * @bssid: The BSSID for this BSS + * @enable_beacon: whether beaconing should be enabled or not */ struct ieee80211_bss_conf { + const u8 *bssid; /* association related data */ bool assoc; u16 aid; @@ -201,6 +213,7 @@ struct ieee80211_bss_conf { bool use_cts_prot; bool use_short_preamble; bool use_short_slot; + bool enable_beacon; u8 dtim_period; u16 beacon_int; u16 assoc_capability; @@ -660,37 +673,6 @@ struct ieee80211_if_init_conf { }; /** - * enum ieee80211_if_conf_change - interface config change flags - * - * @IEEE80211_IFCC_BSSID: The BSSID changed. - * @IEEE80211_IFCC_BEACON: The beacon for this interface changed - * (currently AP and MESH only), use ieee80211_beacon_get(). - * @IEEE80211_IFCC_BEACON_ENABLED: The enable_beacon value changed. - */ -enum ieee80211_if_conf_change { - IEEE80211_IFCC_BSSID = BIT(0), - IEEE80211_IFCC_BEACON = BIT(1), - IEEE80211_IFCC_BEACON_ENABLED = BIT(2), -}; - -/** - * struct ieee80211_if_conf - configuration of an interface - * - * @changed: parameters that have changed, see &enum ieee80211_if_conf_change. - * @bssid: BSSID of the network we are associated to/creating. - * @enable_beacon: Indicates whether beacons can be sent. - * This is valid only for AP/IBSS/MESH modes. - * - * This structure is passed to the config_interface() callback of - * &struct ieee80211_hw. - */ -struct ieee80211_if_conf { - u32 changed; - const u8 *bssid; - bool enable_beacon; -}; - -/** * enum ieee80211_key_alg - key algorithm * @ALG_WEP: WEP40 or WEP104 * @ALG_TKIP: TKIP @@ -1358,10 +1340,6 @@ enum ieee80211_ampdu_mlme_action { * This function should never fail but returns a negative error code * if it does. * - * @config_interface: Handler for configuration requests related to interfaces - * (e.g. BSSID changes.) - * Returns a negative error code which will be seen in userspace. - * * @bss_info_changed: Handler for configuration requests related to BSS * parameters that may vary during BSS's lifespan, and may affect low * level driver (e.g. assoc/disassoc status, erp parameters). @@ -1463,9 +1441,6 @@ struct ieee80211_ops { void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); int (*config)(struct ieee80211_hw *hw, u32 changed); - int (*config_interface)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf); void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a898ccd..648bac1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -521,8 +521,9 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, kfree(old); - return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON); + return 0; } static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, @@ -573,7 +574,8 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) synchronize_rcu(); kfree(old); - return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + return 0; } /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f4879dad..c87caad 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -95,17 +95,10 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); - local->oper_channel = chan; local->oper_channel_type = NL80211_CHAN_NO_HT; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - sdata->vif.bss_conf.beacon_int = beacon_int; - bss_change = BSS_CHANGED_BEACON_INT; - bss_change |= ieee80211_reset_erp_info(sdata); - ieee80211_bss_info_change_notify(sdata, bss_change); - sband = local->hw.wiphy->bands[chan->band]; /* Build IBSS probe response */ @@ -161,8 +154,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, rcu_assign_pointer(ifibss->presp, skb); - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED); + sdata->vif.bss_conf.beacon_int = beacon_int; + bss_change = BSS_CHANGED_BEACON_INT; + bss_change |= ieee80211_reset_erp_info(sdata); + bss_change |= BSS_CHANGED_BSSID; + bss_change |= BSS_CHANGED_BEACON; + bss_change |= BSS_CHANGED_BEACON_ENABLED; + ieee80211_bss_info_change_notify(sdata, bss_change); rates = 0; for (i = 0; i < supp_rates_len; i++) { @@ -887,7 +885,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) kfree(sdata->u.ibss.ie); skb = sdata->u.ibss.presp; rcu_assign_pointer(sdata->u.ibss.presp, NULL); - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); synchronize_rcu(); kfree_skb(skb); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e6fd4bc..d8de1e1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -906,7 +906,6 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); -int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b254879..c817c9e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -152,82 +152,6 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev) ieee80211_configure_filter(local); } -/* everything else */ - -int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_if_conf conf; - - if (WARN_ON(!netif_running(sdata->dev))) - return 0; - - memset(&conf, 0, sizeof(conf)); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - conf.bssid = sdata->u.mgd.bssid; - else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - conf.bssid = sdata->u.ibss.bssid; - else if (sdata->vif.type == NL80211_IFTYPE_AP) - conf.bssid = sdata->dev->dev_addr; - else if (ieee80211_vif_is_mesh(&sdata->vif)) { - static const u8 zero[ETH_ALEN] = { 0 }; - conf.bssid = zero; - } else { - WARN_ON(1); - return -EINVAL; - } - - if (!local->ops->config_interface) - return 0; - - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - break; - default: - /* do not warn to simplify caller in scan.c */ - changed &= ~IEEE80211_IFCC_BEACON_ENABLED; - if (WARN_ON(changed & IEEE80211_IFCC_BEACON)) - return -EINVAL; - changed &= ~IEEE80211_IFCC_BEACON; - break; - } - - if (changed & IEEE80211_IFCC_BEACON_ENABLED) { - if (local->sw_scanning) { - conf.enable_beacon = false; - } else { - /* - * Beacon should be enabled, but AP mode must - * check whether there is a beacon configured. - */ - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - conf.enable_beacon = - !!rcu_dereference(sdata->u.ap.beacon); - break; - case NL80211_IFTYPE_ADHOC: - conf.enable_beacon = !!sdata->u.ibss.presp; - break; - case NL80211_IFTYPE_MESH_POINT: - conf.enable_beacon = true; - break; - default: - /* not reached */ - WARN_ON(1); - break; - } - } - } - - conf.changed = changed; - - return local->ops->config_interface(local_to_hw(local), - &sdata->vif, &conf); -} - int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan; @@ -297,6 +221,61 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, if (!changed) return; + if (sdata->vif.type == NL80211_IFTYPE_STATION) + sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; + else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; + else if (sdata->vif.type == NL80211_IFTYPE_AP) + sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; + else if (ieee80211_vif_is_mesh(&sdata->vif)) { + static const u8 zero[ETH_ALEN] = { 0 }; + sdata->vif.bss_conf.bssid = zero; + } else { + WARN_ON(1); + return; + } + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + break; + default: + /* do not warn to simplify caller in scan.c */ + changed &= ~BSS_CHANGED_BEACON_ENABLED; + if (WARN_ON(changed & BSS_CHANGED_BEACON)) + return; + break; + } + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (local->sw_scanning) { + sdata->vif.bss_conf.enable_beacon = false; + } else { + /* + * Beacon should be enabled, but AP mode must + * check whether there is a beacon configured. + */ + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + sdata->vif.bss_conf.enable_beacon = + !!rcu_dereference(sdata->u.ap.beacon); + break; + case NL80211_IFTYPE_ADHOC: + sdata->vif.bss_conf.enable_beacon = + !!rcu_dereference(sdata->u.ibss.presp); + break; + case NL80211_IFTYPE_MESH_POINT: + sdata->vif.bss_conf.enable_beacon = true; + break; + default: + /* not reached */ + WARN_ON(1); + break; + } + } + } + if (local->ops->bss_info_changed) local->ops->bss_info_changed(local_to_hw(local), &sdata->vif, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a3e5de..9000b01 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -417,7 +417,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, free_plinks = mesh_plink_availables(sdata); if (free_plinks != sdata->u.mesh.accepting_plinks) - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); ifmsh->housekeeping = false; mod_timer(&ifmsh->housekeeping_timer, @@ -432,8 +432,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) ifmsh->housekeeping = true; queue_work(local->hw.workqueue, &ifmsh->work); - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED); } void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bfd571e..c797119 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2289,12 +2289,8 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; } - if (netif_running(sdata->dev)) { - if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { - printk(KERN_DEBUG "%s: Failed to config new BSSID to " - "the low-level driver\n", sdata->dev->name); - } - } + if (netif_running(sdata->dev)) + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); return ieee80211_sta_commit(sdata); } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 086d216..04e270a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -346,8 +346,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_ADHOC || sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_if_config(sdata, - IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); } mutex_unlock(&local->iflist_mtx); @@ -387,8 +387,8 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_ADHOC || sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_if_config(sdata, - IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 61876eb..2cde9bb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1063,24 +1063,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: /* disable beacon change bits */ - changed &= ~IEEE80211_IFCC_BEACON; + changed &= ~(BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED); /* fall through */ case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - /* - * Driver's config_interface can fail if rfkill is - * enabled. Accommodate this return code. - * FIXME: When mac80211 has knowledge of rfkill - * state the code below can change back to: - * WARN(ieee80211_if_config(sdata, changed)); - * ieee80211_bss_info_change_notify(sdata, ~0); - */ - if (ieee80211_if_config(sdata, changed)) - printk(KERN_DEBUG "%s: failed to configure interface during resume\n", - sdata->dev->name); - else - ieee80211_bss_info_change_notify(sdata, ~0); + ieee80211_bss_info_change_notify(sdata, changed); break; case NL80211_IFTYPE_WDS: break; -- cgit v0.10.2 From 2448798133d747ad339e57099e32a1d1e68aca1c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2009 18:52:52 +0200 Subject: mac80211: add driver ops wrappers In order to later add tracing or verifications to the driver calls mac80211 makes, this patch adds static inline wrappers for all operations. All calls are now written as drv_(local, ...); instead of local->ops->(&local->hw, ...); Where necessary, the wrappers also do existence checking and return default values as appropriate. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 07656d830b..fff24c3 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -16,12 +16,12 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, u16 initiator, u16 reason) { struct ieee80211_local *local = sta->local; - struct ieee80211_hw *hw = &local->hw; int i; /* check if TID is in operational state */ @@ -41,8 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - if (local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, - &sta->sta, tid, NULL)) + if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP, + &sta->sta, tid, NULL)) printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); @@ -278,9 +278,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, goto end; } - if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, - &sta->sta, tid, &start_seq_num); + ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START, + &sta->sta, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); #endif /* CONFIG_MAC80211_HT_DEBUG */ diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 947aaaa..43d00ff 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -16,6 +16,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "wme.h" /** @@ -134,8 +135,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - ret = local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_STOP, - &sta->sta, tid, NULL); + ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP, + &sta->sta, tid, NULL); /* HW shall not deny going back to legacy */ if (WARN_ON(ret)) { @@ -306,8 +307,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) start_seq_num = sta->tid_seq[tid]; - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, - &sta->sta, tid, &start_seq_num); + ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START, + &sta->sta, tid, &start_seq_num); if (ret) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -418,8 +419,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ieee80211_agg_splice_finish(local, sta, tid); spin_unlock(&local->ampdu_lock); - local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL, - &sta->sta, tid, NULL); + drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL, + &sta->sta, tid, NULL); } void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 648bac1..d0ca6da 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -13,6 +13,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "cfg.h" #include "rate.h" #include "mesh.h" @@ -245,12 +246,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, iv32 = key->u.tkip.tx.iv32; iv16 = key->u.tkip.tx.iv16; - if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && - sdata->local->ops->get_tkip_seq) - sdata->local->ops->get_tkip_seq( - local_to_hw(sdata->local), - key->conf.hw_key_idx, - &iv32, &iv16); + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + drv_get_tkip_seq(sdata->local, + key->conf.hw_key_idx, + &iv32, &iv16); seq[0] = iv16 & 0xff; seq[1] = (iv16 >> 8) & 0xff; @@ -1115,7 +1114,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, p.cw_max = params->cwmax; p.cw_min = params->cwmin; p.txop = params->txop; - if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { + if (drv_conf_tx(local, params->queue, &p)) { printk(KERN_DEBUG "%s: failed to set TX queue " "parameters for queue %d\n", local->mdev->name, params->queue); @@ -1296,16 +1295,13 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct ieee80211_local *local = wiphy_priv(wiphy); + int err; if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - int err; + err = drv_set_rts_threshold(local, wiphy->rts_threshold); - if (local->ops->set_rts_threshold) { - err = local->ops->set_rts_threshold( - local_to_hw(local), wiphy->rts_threshold); - if (err) - return err; - } + if (err) + return err; } if (changed & WIPHY_PARAM_RETRY_SHORT) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 5001328..ac79320 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -10,6 +10,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "debugfs.h" @@ -70,11 +71,10 @@ static ssize_t tsf_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ieee80211_local *local = file->private_data; - u64 tsf = 0; + u64 tsf; char buf[100]; - if (local->ops->get_tsf) - tsf = local->ops->get_tsf(local_to_hw(local)); + tsf = drv_get_tsf(local); snprintf(buf, sizeof(buf), "0x%016llx\n", (unsigned long long) tsf); @@ -97,13 +97,13 @@ static ssize_t tsf_write(struct file *file, if (strncmp(buf, "reset", 5) == 0) { if (local->ops->reset_tsf) { - local->ops->reset_tsf(local_to_hw(local)); + drv_reset_tsf(local); printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy)); } } else { tsf = simple_strtoul(buf, NULL, 0); if (local->ops->set_tsf) { - local->ops->set_tsf(local_to_hw(local), tsf); + drv_set_tsf(local, tsf); printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf); } } @@ -150,14 +150,12 @@ static ssize_t format_devstat_counter(struct ieee80211_local *local, char buf[20]; int res; - if (!local->ops->get_stats) - return -EOPNOTSUPP; - rtnl_lock(); - res = local->ops->get_stats(local_to_hw(local), &stats); + res = drv_get_stats(local, &stats); rtnl_unlock(); - if (!res) - res = printvalue(&stats, buf, sizeof(buf)); + if (res) + return res; + res = printvalue(&stats, buf, sizeof(buf)); return simple_read_from_buffer(userbuf, count, ppos, buf, res); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h new file mode 100644 index 0000000..3912b53 --- /dev/null +++ b/net/mac80211/driver-ops.h @@ -0,0 +1,184 @@ +#ifndef __MAC80211_DRIVER_OPS +#define __MAC80211_DRIVER_OPS + +#include +#include "ieee80211_i.h" + +static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) +{ + return local->ops->tx(&local->hw, skb); +} + +static inline int drv_start(struct ieee80211_local *local) +{ + return local->ops->start(&local->hw); +} + +static inline void drv_stop(struct ieee80211_local *local) +{ + local->ops->stop(&local->hw); +} + +static inline int drv_add_interface(struct ieee80211_local *local, + struct ieee80211_if_init_conf *conf) +{ + return local->ops->add_interface(&local->hw, conf); +} + +static inline void drv_remove_interface(struct ieee80211_local *local, + struct ieee80211_if_init_conf *conf) +{ + local->ops->remove_interface(&local->hw, conf); +} + +static inline int drv_config(struct ieee80211_local *local, u32 changed) +{ + return local->ops->config(&local->hw, changed); +} + +static inline void drv_bss_info_changed(struct ieee80211_local *local, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, vif, info, changed); +} + +static inline void drv_configure_filter(struct ieee80211_local *local, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + local->ops->configure_filter(&local->hw, changed_flags, total_flags, + mc_count, mc_list); +} + +static inline int drv_set_tim(struct ieee80211_local *local, + struct ieee80211_sta *sta, bool set) +{ + if (local->ops->set_tim) + return local->ops->set_tim(&local->hw, sta, set); + return 0; +} + +static inline int drv_set_key(struct ieee80211_local *local, + enum set_key_cmd cmd, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + return local->ops->set_key(&local->hw, cmd, vif, sta, key); +} + +static inline void drv_update_tkip_key(struct ieee80211_local *local, + struct ieee80211_key_conf *conf, + const u8 *address, u32 iv32, + u16 *phase1key) +{ + if (local->ops->update_tkip_key) + local->ops->update_tkip_key(&local->hw, conf, address, + iv32, phase1key); +} + +static inline int drv_hw_scan(struct ieee80211_local *local, + struct cfg80211_scan_request *req) +{ + return local->ops->hw_scan(&local->hw, req); +} + +static inline void drv_sw_scan_start(struct ieee80211_local *local) +{ + if (local->ops->sw_scan_start) + local->ops->sw_scan_start(&local->hw); +} + +static inline void drv_sw_scan_complete(struct ieee80211_local *local) +{ + if (local->ops->sw_scan_complete) + local->ops->sw_scan_complete(&local->hw); +} + +static inline int drv_get_stats(struct ieee80211_local *local, + struct ieee80211_low_level_stats *stats) +{ + if (!local->ops->get_stats) + return -EOPNOTSUPP; + return local->ops->get_stats(&local->hw, stats); +} + +static inline void drv_get_tkip_seq(struct ieee80211_local *local, + u8 hw_key_idx, u32 *iv32, u16 *iv16) +{ + if (local->ops->get_tkip_seq) + local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16); +} + +static inline int drv_set_rts_threshold(struct ieee80211_local *local, + u32 value) +{ + if (local->ops->set_rts_threshold) + return local->ops->set_rts_threshold(&local->hw, value); + return 0; +} + +static inline void drv_sta_notify(struct ieee80211_local *local, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + if (local->ops->sta_notify) + local->ops->sta_notify(&local->hw, vif, cmd, sta); +} + +static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + if (local->ops->conf_tx) + return local->ops->conf_tx(&local->hw, queue, params); + return -EOPNOTSUPP; +} + +static inline int drv_get_tx_stats(struct ieee80211_local *local, + struct ieee80211_tx_queue_stats *stats) +{ + return local->ops->get_tx_stats(&local->hw, stats); +} + +static inline u64 drv_get_tsf(struct ieee80211_local *local) +{ + if (local->ops->get_tsf) + return local->ops->get_tsf(&local->hw); + return -1ULL; +} + +static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) +{ + if (local->ops->set_tsf) + local->ops->set_tsf(&local->hw, tsf); +} + +static inline void drv_reset_tsf(struct ieee80211_local *local) +{ + if (local->ops->reset_tsf) + local->ops->reset_tsf(&local->hw); +} + +static inline int drv_tx_last_beacon(struct ieee80211_local *local) +{ + if (local->ops->tx_last_beacon) + return local->ops->tx_last_beacon(&local->hw); + return 1; +} + +static inline int drv_ampdu_action(struct ieee80211_local *local, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, + u16 *ssn) +{ + if (local->ops->ampdu_action) + return local->ops->ampdu_action(&local->hw, action, + sta, tid, ssn); + return -EOPNOTSUPP; +} +#endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c87caad..a8e2323 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -22,6 +22,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #define IEEE80211_SCAN_INTERVAL (2 * HZ) @@ -75,10 +76,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband; u32 bss_change; - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } + + /* Reset own TSF to allow time synchronization work. */ + drv_reset_tsf(local); skb = ifibss->skb; rcu_assign_pointer(ifibss->presp, NULL); @@ -315,12 +315,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bitrates[rx_status->rate_idx].bitrate; rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); - } else if (local && local->ops && local->ops->get_tsf) - /* second best option: get current TSF */ - rx_timestamp = local->ops->get_tsf(local_to_hw(local)); - else - /* can't merge without knowing the TSF */ - rx_timestamp = -1LLU; + } else { + /* + * second best option: get current TSF + * (will return -1 if not supported) + */ + rx_timestamp = drv_get_tsf(local); + } #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" @@ -591,10 +592,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, len < 24 + 2 || !ifibss->presp) return; - if (local->ops->tx_last_beacon) - tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); - else - tx_last_beacon = 1; + tx_last_beacon = drv_tx_last_beacon(local); #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5242597..256fa19 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -20,6 +20,7 @@ #include "debugfs_netdev.h" #include "mesh.h" #include "led.h" +#include "driver-ops.h" /** * DOC: Interface list locking @@ -164,9 +165,7 @@ static int ieee80211_open(struct net_device *dev) } if (local->open_count == 0) { - res = 0; - if (local->ops->start) - res = local->ops->start(local_to_hw(local)); + res = drv_start(local); if (res) goto err_del_bss; /* we're brought up, everything changes */ @@ -199,8 +198,8 @@ static int ieee80211_open(struct net_device *dev) * Validate the MAC address for this device. */ if (!is_valid_ether_addr(dev->dev_addr)) { - if (!local->open_count && local->ops->stop) - local->ops->stop(local_to_hw(local)); + if (!local->open_count) + drv_stop(local); return -EADDRNOTAVAIL; } @@ -241,7 +240,7 @@ static int ieee80211_open(struct net_device *dev) conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); + res = drv_add_interface(local, &conf); if (res) goto err_stop; @@ -328,10 +327,10 @@ static int ieee80211_open(struct net_device *dev) return 0; err_del_interface: - local->ops->remove_interface(local_to_hw(local), &conf); + drv_remove_interface(local, &conf); err_stop: - if (!local->open_count && local->ops->stop) - local->ops->stop(local_to_hw(local)); + if (!local->open_count) + drv_stop(local); err_del_bss: sdata->bss = NULL; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) @@ -544,7 +543,7 @@ static int ieee80211_stop(struct net_device *dev) conf.mac_addr = dev->dev_addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); - local->ops->remove_interface(local_to_hw(local), &conf); + drv_remove_interface(local, &conf); } sdata->bss = NULL; @@ -553,8 +552,7 @@ static int ieee80211_stop(struct net_device *dev) if (netif_running(local->mdev)) dev_close(local->mdev); - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); + drv_stop(local); ieee80211_led_radio(local, 0); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 687acf2..b7e1350 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -16,6 +16,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "debugfs_key.h" #include "aes_ccm.h" #include "aes_cmac.h" @@ -136,8 +137,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, - &sdata->vif, sta, &key->conf); + ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); if (!ret) { spin_lock(&todo_lock); @@ -179,8 +179,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY, - &sdata->vif, sta, &key->conf); + ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif, + sta, &key->conf); if (ret) printk(KERN_ERR "mac80211-%s: failed to remove key " diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c817c9e..b80bc80 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -26,6 +26,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "mesh.h" #include "wep.h" @@ -81,10 +82,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) /* be a bit nasty */ new_flags |= (1<<31); - local->ops->configure_filter(local_to_hw(local), - changed_flags, &new_flags, - local->mdev->mc_count, - local->mdev->mc_list); + drv_configure_filter(local, changed_flags, &new_flags, + local->mdev->mc_count, + local->mdev->mc_list); WARN_ON(new_flags & (1<<31)); @@ -192,7 +192,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) } if (changed && local->open_count) { - ret = local->ops->config(local_to_hw(local), changed); + ret = drv_config(local, changed); /* * Goal: * HW reconfiguration should never fail, the driver has told @@ -276,11 +276,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } } - if (local->ops->bss_info_changed) - local->ops->bss_info_changed(local_to_hw(local), - &sdata->vif, - &sdata->vif.bss_conf, - changed); + drv_bss_info_changed(local, &sdata->vif, + &sdata->vif.bss_conf, changed); /* * DEPRECATED diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c797119..42f33fd 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -23,6 +23,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "led.h" @@ -683,11 +684,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, params.cw_max, params.txop); #endif - if (local->ops->conf_tx && - local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { + if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", local->mdev->name, queue); - } + "parameters for queue %d\n", local->mdev->name, + queue); } } @@ -1982,10 +1982,8 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } + /* Reset own TSF to allow time synchronization work. */ + drv_reset_tsf(local); ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index b38986c..9d3d89a 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -2,6 +2,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "led.h" int __ieee80211_suspend(struct ieee80211_hw *hw) @@ -43,8 +44,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) struct ieee80211_sub_if_data, u.ap); - local->ops->sta_notify(hw, &sdata->vif, - STA_NOTIFY_REMOVE, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + &sta->sta); } spin_unlock_irqrestore(&local->sta_lock, flags); } @@ -57,7 +58,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = sdata->dev->dev_addr; - local->ops->remove_interface(hw, &conf); + drv_remove_interface(local, &conf); } } @@ -67,7 +68,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) /* stop hardware */ if (local->open_count) { ieee80211_led_radio(local, false); - local->ops->stop(hw); + drv_stop(local); } return 0; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a5afb79..6a9d89b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -19,6 +19,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "led.h" #include "mesh.h" #include "wep.h" @@ -773,9 +774,7 @@ static void ap_sta_ps_start(struct sta_info *sta) atomic_inc(&sdata->bss->num_sta_ps); set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); - if (local->ops->sta_notify) - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_SLEEP, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", sdata->dev->name, sta->sta.addr, sta->sta.aid); @@ -792,9 +791,7 @@ static int ap_sta_ps_end(struct sta_info *sta) atomic_dec(&sdata->bss->num_sta_ps); clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); - if (local->ops->sta_notify) - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_AWAKE, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 04e270a..127bd54 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -21,6 +21,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "mesh.h" #define IEEE80211_PROBE_DELAY (HZ / 33) @@ -316,17 +317,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) netif_tx_lock_bh(local->mdev); netif_addr_lock(local->mdev); local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; - local->ops->configure_filter(local_to_hw(local), - FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); + drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); netif_addr_unlock(local->mdev); netif_tx_unlock_bh(local->mdev); - if (local->ops->sw_scan_complete) - local->ops->sw_scan_complete(local_to_hw(local)); + drv_sw_scan_complete(local); mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { @@ -375,8 +374,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) * nullfunc frames and probe requests will be dropped in * ieee80211_tx_h_check_assoc(). */ - if (local->ops->sw_scan_start) - local->ops->sw_scan_start(local_to_hw(local)); + drv_sw_scan_start(local); mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { @@ -405,11 +403,10 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) netif_addr_lock_bh(local->mdev); local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; - local->ops->configure_filter(local_to_hw(local), - FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); + drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); netif_addr_unlock_bh(local->mdev); /* TODO: start scan as soon as all nullfunc frames are ACKed */ @@ -477,8 +474,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->scan_mtx); if (local->ops->hw_scan) - rc = local->ops->hw_scan(local_to_hw(local), - local->scan_req); + rc = drv_hw_scan(local, local->scan_req); else rc = ieee80211_start_sw_scan(local); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7116220..a98ea27 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -19,6 +19,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "sta_info.h" #include "debugfs_sta.h" @@ -346,8 +347,7 @@ int sta_info_insert(struct sta_info *sta) struct ieee80211_sub_if_data, u.ap); - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_ADD, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta); } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -405,8 +405,7 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, if (sta->local->ops->set_tim) { sta->local->tim_in_locked_section = true; - sta->local->ops->set_tim(local_to_hw(sta->local), - &sta->sta, true); + drv_set_tim(sta->local, &sta->sta, true); sta->local->tim_in_locked_section = false; } } @@ -431,8 +430,7 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, if (sta->local->ops->set_tim) { sta->local->tim_in_locked_section = true; - sta->local->ops->set_tim(local_to_hw(sta->local), - &sta->sta, false); + drv_set_tim(sta->local, &sta->sta, false); sta->local->tim_in_locked_section = false; } } @@ -482,8 +480,8 @@ static void __sta_info_unlink(struct sta_info **sta) struct ieee80211_sub_if_data, u.ap); - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_REMOVE, &(*sta)->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + &(*sta)->sta); } if (ieee80211_vif_is_mesh(&sdata->vif)) { diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 38fa111..964b7fa 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -13,6 +13,7 @@ #include #include +#include "driver-ops.h" #include "key.h" #include "tkip.h" #include "wep.h" @@ -307,9 +308,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (is_multicast_ether_addr(ra)) sta_addr = bcast; - key->local->ops->update_tkip_key( - local_to_hw(key->local), &key->conf, - sta_addr, iv32, key->u.tkip.rx[queue].p1k); + drv_update_tkip_key(key->local, &key->conf, sta_addr, + iv32, key->u.tkip.rx[queue].p1k); } } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 29df650..1564a30 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -25,6 +25,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "led.h" #include "mesh.h" #include "wep.h" @@ -1162,7 +1163,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, next = skb->next; len = skb->len; - ret = local->ops->tx(local_to_hw(local), skb); + ret = drv_tx(local, skb); if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { dev_kfree_skb(skb); ret = NETDEV_TX_OK; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 2cde9bb..97b613a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -26,6 +26,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "mesh.h" #include "wme.h" @@ -726,7 +727,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) qparam.txop = 0; for (i = 0; i < local_to_hw(local)->queues; i++) - local->ops->conf_tx(local_to_hw(local), i, &qparam); + drv_conf_tx(local, i, &qparam); } void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, @@ -1000,7 +1001,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* restart hardware */ if (local->open_count) { - res = local->ops->start(hw); + res = drv_start(local); ieee80211_led_radio(local, hw->conf.radio_enabled); } @@ -1013,7 +1014,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = sdata->dev->dev_addr; - res = local->ops->add_interface(hw, &conf); + res = drv_add_interface(local, &conf); } } @@ -1026,8 +1027,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct ieee80211_sub_if_data, u.ap); - local->ops->sta_notify(hw, &sdata->vif, - STA_NOTIFY_ADD, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, + &sta->sta); } spin_unlock_irqrestore(&local->sta_lock, flags); } @@ -1045,8 +1046,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) rcu_read_unlock(); /* setup RTS threshold */ - if (local->ops->set_rts_threshold) - local->ops->set_rts_threshold(hw, hw->wiphy->rts_threshold); + drv_set_rts_threshold(local, hw->wiphy->rts_threshold); /* reconfigure hardware */ ieee80211_hw_config(local, ~0); -- cgit v0.10.2 From e61f234079b49c7e075b12551797fc4954704019 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 24 Apr 2009 00:00:00 +0300 Subject: nl80211: Send timeout event on failed direct probe If the direct probe times out, we need to send the authentication timeout event to notify SME in the same way as we notify on timeout with authentication frames since the direct probe is run as part of the authentication attempt. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 42f33fd..30a0034 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -890,7 +890,7 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_sta_send_apinfo(sdata); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); /* * Most likely AP is not in the range so remove the -- cgit v0.10.2 From d91f190c412aff940a46cabaccf114361c133605 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Apr 2009 15:13:54 +0200 Subject: mac80211_hwsim: fix bogus warning A typo slipped into my patch to configure beacon intervals properly -- this warning is supposed to trigger when the beacon interval is zero, not non-zero. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e67b424..8fa6e6c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -618,7 +618,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, printk(KERN_DEBUG " %s: BCNINT: %d\n", wiphy_name(hw->wiphy), info->beacon_int); data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000; - if (WARN_ON(data->beacon_int)) + if (WARN_ON(!data->beacon_int)) data->beacon_int = 1; } -- cgit v0.10.2 From 16cf438a1eca2b7206bd7ac7763637c2a87c00c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Apr 2009 15:15:25 +0200 Subject: mac80211: fix probe response processing Due to the use of a _REQ_DIRECT_PROBE bit, which is unnecessary (and I wonder why it was done that way), an interesting situation can arise: 1) we try to probe an access point 2) the AP doesn't response in time 3) we tell userspace that we gave up 4) the AP suddenly responds 5) we auth/assoc with the AP I've seen 4) happen in testing with hostapd SIGSTOPped, and when SIGCONTinued it processes the probe requests that came in and send responses. But 5) is not supposed to happen after we tell everybody we've given up on the AP. To fix this, remove the _REQ_DIRECT_PROBE request bit, and process probe responses when we're in the relevant MLME state, namely IEEE80211_STA_MLME_DIRECT_PROBE. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d8de1e1..236ea09 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -248,9 +248,8 @@ struct mesh_preq_queue { #define IEEE80211_STA_EXT_SME BIT(17) /* flags for MLME request */ #define IEEE80211_STA_REQ_SCAN 0 -#define IEEE80211_STA_REQ_DIRECT_PROBE 1 -#define IEEE80211_STA_REQ_AUTH 2 -#define IEEE80211_STA_REQ_RUN 3 +#define IEEE80211_STA_REQ_AUTH 1 +#define IEEE80211_STA_REQ_RUN 2 /* bitfield of allowed auth algs */ #define IEEE80211_AUTH_ALG_OPEN BIT(0) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 30a0034..2ded476 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -915,8 +915,6 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request); - /* Direct probe is sent to broadcast address as some APs * will not answer to direct packet in unassociated state. */ @@ -1738,8 +1736,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); /* direct probe may be part of the association flow */ - if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, - &ifmgd->request)) { + if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) { printk(KERN_DEBUG "%s direct probe responded\n", sdata->dev->name); ieee80211_authenticate(sdata); -- cgit v0.10.2 From 083c4687bc3abc315c73830b9c74ad67e005d8c2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 24 Apr 2009 21:35:57 +0200 Subject: ar9170: handle otus' A-MPDU density definitions Otus uses slightly different set of "Minimum MPDU Start Spacing" values than the 802.11n D2.0 specifies. (the whole table is shifted by one and therefore the 16us spacing is not officially available!) And while we're at it, we also initialize our MAC's density register. So, this annoying _feature_ will not break TX A-MPDU later. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 95bf812..3293e0f 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -207,6 +207,8 @@ enum ar9170_cmd { #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) +#define AR9170_MAC_REG_AMPDU_SET (AR9170_MAC_REG_BASE + 0xba0) + #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 0e5967d..45986b6e 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -72,6 +72,24 @@ int ar9170_set_qos(struct ar9170 *ar) return ar9170_regwrite_result(); } +static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) +{ + u32 val; + + /* don't allow AMPDU density > 8us */ + if (mpdudensity > 6) + return -EINVAL; + + /* Watch out! Otus uses slightly different density values. */ + val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); + + ar9170_regwrite_begin(ar); + ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val); + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + int ar9170_init_mac(struct ar9170 *ar) { ar9170_regwrite_begin(ar); @@ -296,6 +314,11 @@ int ar9170_set_operating_mode(struct ar9170 *ar) if (err) return err; + /* set AMPDU density to 8us. */ + err = ar9170_set_ampdu_density(ar, 6); + if (err) + return err; + ar9170_regwrite_begin(ar); ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 3bd3a61..4ef1d2f 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -151,8 +151,8 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { IEEE80211_HT_CAP_SGI_40 | \ IEEE80211_HT_CAP_DSSSCCK40 | \ IEEE80211_HT_CAP_SM_PS, \ - .ampdu_factor = 3, /* ?? */ \ - .ampdu_density = 7, /* ?? */ \ + .ampdu_factor = 3, \ + .ampdu_density = 6, \ .mcs = { \ .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \ }, \ -- cgit v0.10.2 From 2cfb1f5e20f260e6ff306ba181efee956ba48f54 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 24 Apr 2009 21:41:18 +0200 Subject: ar9170: uncomment powermgt case handle This patch uncomment a few lines that survived the RFCs. However, there is not much to worry about, since AP mode is not officially advertised and supported. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 45986b6e..43aeb69 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -283,9 +283,9 @@ int ar9170_set_operating_mode(struct ar9170 *ar) case NL80211_IFTYPE_ADHOC: pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; break; -/* case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP: pm_mode |= AR9170_MAC_REG_POWERMGT_AP; - break;*/ + break; case NL80211_IFTYPE_WDS: pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; break; -- cgit v0.10.2 From 0ef9ccdd9ec7f2cf28d0605c216d853687f5291d Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 24 Apr 2009 14:09:31 -0700 Subject: cfg80211: remove superfluous !last_request check in reg_device_remove() Commit 0ad8acaf "cfg80211: fix NULL pointer deference in reg_device_remove()" added a check that last_request is non-NULL, rendering the 2nd check superfluous. While there, rearrange the code a bit so it's a little more straight forward. Signed-off-by: Chris Wright Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f38cc39..9fea910 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2100,14 +2100,14 @@ void reg_device_remove(struct wiphy *wiphy) assert_cfg80211_lock(); + kfree(wiphy->regd); + if (last_request) request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); - kfree(wiphy->regd); - if (!last_request || !request_wiphy) - return; - if (request_wiphy != wiphy) + if (!request_wiphy || request_wiphy != wiphy) return; + last_request->wiphy_idx = WIPHY_IDX_STALE; last_request->country_ie_env = ENVIRON_ANY; } -- cgit v0.10.2 From aeca78b9b094d00cccca39e9a1055c74ad83ea69 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 24 Apr 2009 15:26:02 -0700 Subject: net/rfkill/rfkill.c: fix build with CONFIG_RFKILL_LEDS=n net/rfkill/rfkill.c: In function 'update_rfkill_state': net/rfkill/rfkill.c:99: error: implicit declaration of function 'rfkill_led_trigger' Caused by : commit 492301fb5d12e4a77a1010ad2b6f1ed306014123 : Author: Larry Finger : Date: Thu Apr 9 22:14:19 2009 -0500 : : rfkill: Fix broken rfkill LED in 2.6.30-rc1 Cc: Henrique de Moraes Holschuh Cc: Ivo van Doorn Cc: Michael Buesch Cc: David S. Miller Cc: Larry Finger Signed-off-by: Andrew Morton Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index e2d4510..4f5a831 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -75,6 +75,11 @@ static void rfkill_led_trigger_activate(struct led_classdev *led) rfkill_led_trigger(rfkill, rfkill->state); } +#else +static inline void rfkill_led_trigger(struct rfkill *rfkill, + enum rfkill_state state) +{ +} #endif /* CONFIG_RFKILL_LEDS */ static void rfkill_uevent(struct rfkill *rfkill) -- cgit v0.10.2 From ded7a7eaab2a39b7b5c36a2ec3be46f6ebcedba5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sat, 25 Apr 2009 14:09:23 +0200 Subject: ath5k: 5211, don't crypt every protected frame Set null key type even on ar5211, otherwise it en/decrypts every frame with protected bit set which renders the card unusable on encrypted networks. Signed-off-by: Jiri Slaby Cc: Luis R. Rodriguez Cc: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 55122f1..5f07e87 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -1003,7 +1003,7 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) * Note2: Windows driver (ndiswrapper) sets this to * 0x00000714 instead of 0x00000007 */ - if (ah->ah_version > AR5K_AR5211) { + if (ah->ah_version >= AR5K_AR5211) { ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, AR5K_KEYTABLE_TYPE(entry)); -- cgit v0.10.2 From a406ac0dc15b22807b65f5a6590b9cb34d99d4ab Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 25 Apr 2009 21:11:55 +0200 Subject: p54usb: remove some dead code Since "p54: prevent upload of wrong firmwares" we no longer allow outdated LM86 firmwares to be uploaded on ISL3887 (LM87) devices. Therefore we can purge this buggy legacy code altogether. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 6cc6cbc..44ab3cc 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -206,53 +206,6 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) return ret; } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54u_priv *priv = dev->priv; - struct urb *addr_urb, *data_urb; - int err = 0; - - addr_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!addr_urb) - return; - - data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) { - usb_free_urb(addr_urb); - return; - } - - usb_fill_bulk_urb(addr_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - &((struct p54_hdr *)skb->data)->req_id, 4, - p54u_tx_dummy_cb, dev); - usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, FREE_AFTER_TX(skb) ? - p54u_tx_cb : p54u_tx_dummy_cb, skb); - addr_urb->transfer_flags |= URB_ZERO_PACKET; - data_urb->transfer_flags |= URB_ZERO_PACKET; - - usb_anchor_urb(addr_urb, &priv->submitted); - err = usb_submit_urb(addr_urb, GFP_ATOMIC); - if (err) { - usb_unanchor_urb(addr_urb); - goto out; - } - - usb_anchor_urb(data_urb, &priv->submitted); - err = usb_submit_urb(data_urb, GFP_ATOMIC); - if (err) - usb_unanchor_urb(data_urb); - - out: - usb_free_urb(addr_urb); - usb_free_urb(data_urb); - - if (err) - p54_free_skb(dev, skb); -} - static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) { u32 chk = 0; @@ -954,13 +907,10 @@ static int __devinit p54u_probe(struct usb_interface *intf, priv->common.stop = p54u_stop; if (recognized_pipes < P54U_PIPE_NUMBER) { priv->hw_type = P54U_3887; + 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; 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); -- cgit v0.10.2 From 1ca5f2e94c40b04d5dec437cd41fd5ba12aaac31 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 25 Apr 2009 21:12:09 +0200 Subject: p54usb: rework driver for resume This patch redo the driver code so that p54usb no longer hangs the kernel on resume. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 44ab3cc..ec6c954 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -81,6 +81,29 @@ static struct usb_device_id p54u_table[] __devinitdata = { MODULE_DEVICE_TABLE(usb, p54u_table); +static const struct { + u32 intf; + enum p54u_hw_type type; + char fw[FIRMWARE_NAME_MAX]; + char fw_legacy[FIRMWARE_NAME_MAX]; + char hw[20]; +} p54u_fwlist[__NUM_P54U_HWTYPES] = { + { + .type = P54U_NET2280, + .intf = FW_LM86, + .fw = "isl3886usb", + .fw_legacy = "isl3890usb", + .hw = "ISL3886 + net2280", + }, + { + .type = P54U_3887, + .intf = FW_LM87, + .fw = "isl3887usb", + .fw_legacy = "isl3887usb_bare", + .hw = "ISL3887", + }, +}; + static void p54u_rx_cb(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; @@ -125,11 +148,7 @@ static void p54u_rx_cb(struct urb *urb) } skb_reset_tail_pointer(skb); skb_trim(skb, 0); - if (urb->transfer_buffer != skb_tail_pointer(skb)) { - /* this should not happen */ - WARN_ON(1); - urb->transfer_buffer = skb_tail_pointer(skb); - } + urb->transfer_buffer = skb_tail_pointer(skb); } skb_queue_tail(&priv->rx_queue, skb); usb_anchor_urb(urb, &priv->submitted); @@ -378,20 +397,16 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, data, len, &alen, 2000); } -static const char p54u_romboot_3887[] = "~~~~"; -static const char p54u_firmware_upload_3887[] = "<\r"; - -static int p54u_device_reset_3887(struct ieee80211_hw *dev) +static int p54u_device_reset(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING); - u8 buf[4]; if (lock) { ret = usb_lock_device_for_reset(priv->udev, priv->intf); if (ret < 0) { dev_err(&priv->udev->dev, "(p54usb) unable to lock " - " device for reset: %d\n", ret); + "device for reset (%d)!\n", ret); return ret; } } @@ -400,26 +415,34 @@ static int p54u_device_reset_3887(struct ieee80211_hw *dev) if (lock) usb_unlock_device(priv->udev); - if (ret) { + if (ret) dev_err(&priv->udev->dev, "(p54usb) unable to reset " - "device: %d\n", ret); - return ret; - } + "device (%d)!\n", ret); + + return ret; +} + +static const char p54u_romboot_3887[] = "~~~~"; +static int p54u_firmware_reset_3887(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + u8 buf[4]; + int ret; memcpy(&buf, p54u_romboot_3887, sizeof(buf)); ret = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(buf)); if (ret) dev_err(&priv->udev->dev, "(p54usb) unable to jump to " - "boot ROM: %d\n", ret); + "boot ROM (%d)!\n", ret); return ret; } +static const char p54u_firmware_upload_3887[] = "<\r"; static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; int err, alen; u8 carry = 0; u8 *buf, *tmp; @@ -428,51 +451,29 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) struct x2_header *hdr; unsigned long timeout; + err = p54u_firmware_reset_3887(dev); + if (err) + return err; + tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); if (!buf) { dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" "upload buffer!\n"); - err = -ENOMEM; - goto err_bufalloc; - } - - err = p54u_device_reset_3887(dev); - if (err) - goto err_reset; - - err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); - if (err) { - dev_err(&priv->udev->dev, "p54usb: cannot find firmware " - "(isl3887usb)\n"); - err = request_firmware(&fw_entry, "isl3887usb_bare", - &priv->udev->dev); - if (err) - goto err_req_fw_failed; - } - - err = p54_parse_firmware(dev, fw_entry); - if (err) - goto err_upload_failed; - - if (priv->common.fw_interface != FW_LM87) { - dev_err(&priv->udev->dev, "wrong firmware, " - "please get a LM87 firmware and try again.\n"); - err = -EINVAL; - goto err_upload_failed; + return -ENOMEM; } - left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); + left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size); strcpy(buf, p54u_firmware_upload_3887); left -= strlen(p54u_firmware_upload_3887); tmp += strlen(p54u_firmware_upload_3887); - data = fw_entry->data; - remains = fw_entry->size; + data = priv->fw->data; + remains = priv->fw->size; hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887)); memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); - hdr->fw_length = cpu_to_le32(fw_entry->size); + hdr->fw_length = cpu_to_le32(priv->fw->size); hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, sizeof(u32)*2)); left -= sizeof(*hdr); @@ -514,7 +515,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); } - *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); + *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data, + priv->fw->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); @@ -565,19 +567,14 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) if (err) goto err_upload_failed; - err_upload_failed: - release_firmware(fw_entry); - err_req_fw_failed: - err_reset: +err_upload_failed: kfree(buf); - err_bufalloc: return err; } static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; int err, alen; void *buf; @@ -592,33 +589,6 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) return -ENOMEM; } - err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); - if (err) { - dev_err(&priv->udev->dev, "(p54usb) cannot find firmware " - "(isl3886usb)\n"); - err = request_firmware(&fw_entry, "isl3890usb", - &priv->udev->dev); - if (err) { - kfree(buf); - return err; - } - } - - err = p54_parse_firmware(dev, fw_entry); - if (err) { - kfree(buf); - release_firmware(fw_entry); - return err; - } - - if (priv->common.fw_interface != FW_LM86) { - dev_err(&priv->udev->dev, "wrong firmware, " - "please get a LM86(USB) firmware and try again.\n"); - kfree(buf); - release_firmware(fw_entry); - return -EINVAL; - } - #define P54U_WRITE(type, addr, data) \ do {\ err = p54u_write(priv, buf, type,\ @@ -718,8 +688,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); /* finally, we can upload firmware now! */ - remains = fw_entry->size; - data = fw_entry->data; + remains = priv->fw->size; + data = priv->fw->data; offset = ISL38XX_DEV_FIRMWARE_ADDR; while (remains) { @@ -828,12 +798,54 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) #undef P54U_WRITE #undef P54U_READ - fail: - release_firmware(fw_entry); +fail: kfree(buf); return err; } +static int p54u_load_firmware(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + int err, i; + + BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); + + for (i = 0; i < __NUM_P54U_HWTYPES; i++) + if (p54u_fwlist[i].type == priv->hw_type) + break; + + if (i == __NUM_P54U_HWTYPES) + return -EOPNOTSUPP; + + err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev); + if (err) { + dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " + "(%d)!\n", p54u_fwlist[i].fw, err); + + err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy, + &priv->udev->dev); + if (err) + return err; + } + + err = p54_parse_firmware(dev, priv->fw); + if (err) + goto out; + + if (priv->common.fw_interface != p54u_fwlist[i].intf) { + dev_err(&priv->udev->dev, "wrong firmware, please get " + "a firmware for \"%s\" and try again.\n", + p54u_fwlist[i].hw); + err = -EINVAL; + } + +out: + if (err) + release_firmware(priv->fw); + + return err; +} + static int p54u_open(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; @@ -875,6 +887,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, } priv = dev->priv; + priv->hw_type = P54U_INVALID_HW; SET_IEEE80211_DEV(dev, &intf->dev); usb_set_intfdata(intf, dev); @@ -906,34 +919,46 @@ 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) { + /* ISL3887 needs a full reset on resume */ + udev->reset_resume = 1; + err = p54u_device_reset(dev); + priv->hw_type = P54U_3887; 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; - err = p54u_upload_firmware_3887(dev); + priv->upload_fw = p54u_upload_firmware_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; - err = p54u_upload_firmware_net2280(dev); + priv->upload_fw = p54u_upload_firmware_net2280; } + err = p54u_load_firmware(dev); if (err) goto err_free_dev; + err = priv->upload_fw(dev); + if (err) + goto err_free_fw; + p54u_open(dev); err = p54_read_eeprom(dev); p54u_stop(dev); if (err) - goto err_free_dev; + goto err_free_fw; err = p54_register_common(dev, &udev->dev); if (err) - goto err_free_dev; + goto err_free_fw; return 0; - err_free_dev: +err_free_fw: + release_firmware(priv->fw); + +err_free_dev: ieee80211_free_hw(dev); usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -952,20 +977,64 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) priv = dev->priv; usb_put_dev(interface_to_usbdev(intf)); + release_firmware(priv->fw); p54_free_common(dev); ieee80211_free_hw(dev); } static int p54u_pre_reset(struct usb_interface *intf) { + struct ieee80211_hw *dev = usb_get_intfdata(intf); + + if (!dev) + return -ENODEV; + + p54u_stop(dev); return 0; } +static int p54u_resume(struct usb_interface *intf) +{ + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct p54u_priv *priv; + + if (!dev) + return -ENODEV; + + priv = dev->priv; + if (unlikely(!(priv->upload_fw && priv->fw))) + return 0; + + return priv->upload_fw(dev); +} + static int p54u_post_reset(struct usb_interface *intf) { + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct p54u_priv *priv; + int err; + + err = p54u_resume(intf); + if (err) + return err; + + /* reinitialize old device state */ + priv = dev->priv; + if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) + ieee80211_restart_hw(dev); + return 0; } +#ifdef CONFIG_PM + +static int p54u_suspend(struct usb_interface *intf, pm_message_t message) +{ + return p54u_pre_reset(intf); +} + +#endif /* CONFIG_PM */ + static struct usb_driver p54u_driver = { .name = "p54usb", .id_table = p54u_table, @@ -973,6 +1042,11 @@ static struct usb_driver p54u_driver = { .disconnect = p54u_disconnect, .pre_reset = p54u_pre_reset, .post_reset = p54u_post_reset, +#ifdef CONFIG_PM + .suspend = p54u_suspend, + .resume = p54u_resume, + .reset_resume = p54u_resume, +#endif /* CONFIG_PM */ .soft_unbind = 1, }; diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 8bc5898..e935b79 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -123,18 +123,26 @@ struct p54u_rx_info { struct ieee80211_hw *dev; }; +enum p54u_hw_type { + P54U_INVALID_HW, + P54U_NET2280, + P54U_3887, + + /* keep last */ + __NUM_P54U_HWTYPES, +}; + struct p54u_priv { struct p54_common common; struct usb_device *udev; struct usb_interface *intf; - enum { - P54U_NET2280 = 0, - P54U_3887 - } hw_type; + int (*upload_fw)(struct ieee80211_hw *dev); + enum p54u_hw_type hw_type; spinlock_t lock; struct sk_buff_head rx_queue; struct usb_anchor submitted; + const struct firmware *fw; }; #endif /* P54USB_H */ -- cgit v0.10.2 From 90ccda9baccec8223ca5456fbe49adf7264d1543 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 25 Apr 2009 21:32:09 +0200 Subject: ar9170usb: reset device on resume This patch takes care of an outstanding comment in "[PATCH] ar9170usb: fix hang on resume" commit message. >However, the device does not accept the firmware on resume. >and it will exit with: > >> firmware part 1 upload failed (-71). >> device is in a bad state. please reconnect it! Reported-by: Johannes Berg Signed-off-by: Christian Lamparter Tested-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index fddda47..368fc2d 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -689,6 +689,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, aru->common.exec_cmd = ar9170_usb_exec_cmd; aru->common.callback_cmd = ar9170_usb_callback_cmd; + udev->reset_resume = 1; err = ar9170_usb_reset(aru); if (err) goto err_freehw; @@ -805,6 +806,7 @@ static struct usb_driver ar9170_driver = { #ifdef CONFIG_PM .suspend = ar9170_suspend, .resume = ar9170_resume, + .reset_resume = ar9170_resume, #endif /* CONFIG_PM */ }; -- cgit v0.10.2 From 273de92c8461776aaac7b32f8d5889a72b38ea10 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Apr 2009 22:28:55 +0200 Subject: cfg80211: Remove unnecessary ksize() call This removes an unnecessary ksize() call. krealloc() will do this test internally and won't perform any allocation if the space is already sufficient to hold the data. So remove the redundant check. Signed-off-by: Michael Buesch Reviewed-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 723aeb3..5dd909a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -384,11 +384,9 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, } else { u8 *ies = found->pub.information_elements; - if (found->ies_allocated) { - if (ksize(ies) < ielen) - ies = krealloc(ies, ielen, - GFP_ATOMIC); - } else + if (found->ies_allocated) + ies = krealloc(ies, ielen, GFP_ATOMIC); + else ies = kmalloc(ielen, GFP_ATOMIC); if (ies) { -- cgit v0.10.2 From 44e1b98f733e48bb781e4229120e1de5e0c9fdbb Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 26 Apr 2009 11:27:33 +0200 Subject: cfg80211: Use the correct IE buffer pointer If the IE buffer was allocated, the pub.information_elements pointer was also changed to the allocated space. So we must not assume anymore that the pointer points at the "found" tail. So if it was allocated previously, take the codebranch that grows the buffer size (if necessary) and put the data into the allocated buffer. Signed-off-by: Michael Buesch Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5dd909a..10b4887 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -377,7 +377,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, size_t used = dev->wiphy.bss_priv_size + sizeof(*res); size_t ielen = res->pub.len_information_elements; - if (ksize(found) >= used + ielen) { + if (!found->ies_allocated && ksize(found) >= used + ielen) { memcpy(found->pub.information_elements, res->pub.information_elements, ielen); found->pub.len_information_elements = ielen; -- cgit v0.10.2 From ba5101d098d6a8471d1a3147fb610b2ee3dbb397 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 26 Apr 2009 14:40:59 +0200 Subject: ar9170: wrong test on outlen in ar9170_usb_exec_cmd() ? remove redundant test: outlen is unsigned Signed-off-by: Roel Kluin Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 368fc2d..d7b562d 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -350,7 +350,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, goto err_unbuf; } - if (outlen >= 0 && aru->readlen != outlen) { + if (aru->readlen != outlen) { err = -EMSGSIZE; goto err_unbuf; } -- cgit v0.10.2 From bbb33881ae5bfe4197a005dc03b29b7dcc07fa28 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 26 Apr 2009 14:58:40 +0200 Subject: ath5k: Storage class should be before const qualifier commit 8e218fb24faef0bfe95bc91b3c05261e20439527 reverted the previous patch (commit 925be8a3077351edbf2b59ca689105df214a0792). The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser Acked-by: Jiri Slaby Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index c0fb3b0..c85429d 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -640,9 +640,9 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) static inline void ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) { - const static u16 intercepts3[] = + static const u16 intercepts3[] = { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; - const static u16 intercepts3_2[] = + static const u16 intercepts3_2[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; const u16 *ip; int i; -- cgit v0.10.2 From 9eb4e21e289beba9cfe34f24920eee83c144e62f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 26 Apr 2009 16:08:30 +0200 Subject: rt2x00: Move iv_len into tx descriptor data By placing the iv_len into the tx descriptor data and by passing this data to the crypto IV handlers we can save multiple calls to ieee80211_get_hdrlen_from_skb() and some if-statements when copying/removing the IV data from the outgoing frame. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 0b41845..ae31581 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -66,6 +66,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, txdesc->key_idx = hw_key->hw_key_idx; txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + txdesc->iv_len = hw_key->iv_len; if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); @@ -103,34 +104,32 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, return overhead; } -void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len) +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); - if (unlikely(!iv_len)) + if (unlikely(!txdesc->iv_len)) return; /* Copy IV/EIV data */ - memcpy(skbdesc->iv, skb->data + header_length, iv_len); + memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len); } -void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) +void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); - if (unlikely(!iv_len)) + if (unlikely(!txdesc->iv_len)) return; /* Copy IV/EIV data */ - memcpy(skbdesc->iv, skb->data + header_length, iv_len); + memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len); /* Move ieee80211 header */ - memmove(skb->data + iv_len, skb->data, header_length); + memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset); /* Pull buffer to correct size */ - skb_pull(skb, iv_len); + skb_pull(skb, txdesc->iv_len); /* IV/EIV data has officially be stripped */ skbdesc->flags |= FRAME_DESC_IV_STRIPPED; diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index a631613..af3c47b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -295,8 +295,10 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc); unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); -void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len); -void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, + struct txentry_desc *txdesc); +void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, + struct txentry_desc *txdesc); 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, @@ -319,12 +321,12 @@ static inline unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev } static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, - unsigned int iv_len) + struct txentry_desc *txdesc) { } static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, - unsigned int iv_len) + struct txentry_desc *txdesc) { } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index a5664bd..6f78915 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -368,7 +368,6 @@ 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; u8 rate_idx, rate_flags; if (unlikely(rt2x00queue_full(queue))) @@ -390,9 +389,6 @@ 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; - /* * All information is retrieved from the skb->cb array, * now we should claim ownership of the driver part of that @@ -415,9 +411,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags)) - rt2x00crypto_tx_copy_iv(skb, iv_len); + rt2x00crypto_tx_copy_iv(skb, &txdesc); else - rt2x00crypto_tx_remove_iv(skb, iv_len); + rt2x00crypto_tx_remove_iv(skb, &txdesc); } /* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 97e2ab0..e3bfd73 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -280,6 +280,7 @@ enum txentry_desc_flags { * @cipher: Cipher type used for encryption. * @key_idx: Key index used for encryption. * @iv_offset: Position where IV should be inserted by hardware. + * @iv_len: Length of IV data. */ struct txentry_desc { unsigned long flags; @@ -302,6 +303,7 @@ struct txentry_desc { enum cipher cipher; u16 key_idx; u16 iv_offset; + u16 iv_len; }; /** -- cgit v0.10.2 From 9f1661718c7fcf82e25c6aed20b729ee372d9d65 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 26 Apr 2009 16:08:50 +0200 Subject: rt2x00: Add support for L2 padding during TX/RX Some hardware require L2 padding between header and payload because both must be aligned to a 4-byte boundary. This hardware also is easier during the RX path since we no longer need to move the entire payload but rather only the header to remove the padding (mac80211 only wants the payload to be 4-byte aligned). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 0be3955..7c5cbb1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -103,6 +103,15 @@ #define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate)) /* + * Determine the alignment requirement, + * to make sure the 802.11 payload is padded to a 4-byte boundrary + * we must determine the address of the payload and calculate the + * amount of bytes needed to move the data. + */ +#define ALIGN_SIZE(__skb, __header) \ + ( ((unsigned long)((__skb)->data + (__header))) & 3 ) + +/* * Standard timing and size defines. * These values should follow the ieee80211 specifications. */ @@ -590,6 +599,7 @@ enum rt2x00_flags { DRIVER_REQUIRE_SCHEDULED, DRIVER_REQUIRE_DMA, DRIVER_REQUIRE_COPY_IV, + DRIVER_REQUIRE_L2PAD, /* * Driver features diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index ae31581..57ab42c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -65,7 +65,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, __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); + txdesc->iv_offset = txdesc->header_length; txdesc->iv_len = hw_key->iv_len; if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) @@ -132,17 +132,16 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc) skb_pull(skb, txdesc->iv_len); /* IV/EIV data has officially be stripped */ - skbdesc->flags |= FRAME_DESC_IV_STRIPPED; + skbdesc->flags |= SKBDESC_IV_STRIPPED; } -void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) +void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length) { 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[0])) * 4) + ((!!(skbdesc->iv[1])) * 4); - if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) + if (!(skbdesc->flags & SKBDESC_IV_STRIPPED)) return; skb_push(skb, iv_len); @@ -154,14 +153,15 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) memcpy(skb->data + header_length, skbdesc->iv, iv_len); /* IV/EIV data has returned into the frame */ - skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; + skbdesc->flags &= ~SKBDESC_IV_STRIPPED; } -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, unsigned int header_length, struct rxdone_entry_desc *rxdesc) { unsigned int payload_len = rxdesc->size - header_length; + unsigned int align = ALIGN_SIZE(skb, header_length); unsigned int iv_len; unsigned int icv_len; unsigned int transfer = 0; @@ -191,32 +191,48 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, } /* - * 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 than the ICV data. - * When alignment requirements is greater than the - * ICV data we must trim the skb to the correct size - * because we need to remove the extra bytes. + * Make room for new data. There are 2 possibilities + * either the alignment is already present between + * the 802.11 header and payload. In that case we + * we have to move the header less then the iv_len + * since we can use the already available l2pad bytes + * for the iv data. + * When the alignment must be added manually we must + * move the header more then iv_len since we must + * make room for the payload move as well. */ - 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); + if (l2pad) { + skb_push(skb, iv_len - align); + skb_put(skb, icv_len); - /* Move ieee80211 header */ - memmove(skb->data + transfer, - skb->data + transfer + iv_len + align, - header_length); - transfer += header_length; + /* Move ieee80211 header */ + memmove(skb->data + transfer, + skb->data + transfer + (iv_len - align), + header_length); + transfer += header_length; + } else { + 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/EIV data */ memcpy(skb->data + transfer, rxdesc->iv, iv_len); transfer += iv_len; - /* Move payload */ - if (align) { + /* + * Move payload for alignment purposes. Note that + * this is only needed when no l2 padding is present. + */ + if (!l2pad) { memmove(skb->data + transfer, skb->data + transfer + align, payload_len); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5752aaa..e15086a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -227,6 +227,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8 rate_idx, rate_flags; /* @@ -235,13 +236,19 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00queue_unmap_skb(rt2x00dev, entry->skb); /* + * Remove L2 padding which was added during + */ + if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + rt2x00queue_payload_align(entry->skb, true, header_length); + + /* * 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); + rt2x00crypto_tx_insert_iv(entry->skb, header_length); /* * Send frame to debugfs immediately, after this call is completed @@ -325,7 +332,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct ieee80211_supported_band *sband; const struct rt2x00_rate *rate; unsigned int header_length; - unsigned int align; + bool l2pad; unsigned int i; int idx = -1; @@ -348,12 +355,15 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); + /* Trim buffer to correct size */ + skb_trim(entry->skb, rxdesc.size); + /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - align = ((unsigned long)(entry->skb->data + header_length)) & 3; + l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD); /* * Hardware might have stripped the IV/EIV/ICV data, @@ -362,18 +372,11 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * in which case we should reinsert the data into the frame. */ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && - (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, - rxdesc.size); - } - - /* Update data pointers, trim buffer to correct size */ - skb_trim(entry->skb, rxdesc.size); + (rxdesc.flags & RX_FLAG_IV_STRIPPED)) + rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length, + &rxdesc); + else + rt2x00queue_payload_align(entry->skb, l2pad, header_length); /* * Update RX statistics. diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index af3c47b..aa284e4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -113,6 +113,23 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); /** + * rt2x00queue_payload_align - Align 802.11 payload to 4-byte boundary + * @skb: The skb to align + * @l2pad: Should L2 padding be used + * @header_length: Length of 802.11 header + * + * This function prepares the @skb to be send to the device or mac80211. + * If @l2pad is set to true padding will occur between the 802.11 header + * and payload. Otherwise the padding will be done in front of the 802.11 + * header. + * When @l2pad is set the function will check for the &SKBDESC_L2_PADDED + * flag in &skb_frame_desc. If that flag is set, the padding is removed + * and the flag cleared. Otherwise the padding is added and the flag is set. + */ +void rt2x00queue_payload_align(struct sk_buff *skb, + bool l2pad, unsigned int header_length); + +/** * rt2x00queue_write_tx_frame - Write TX frame to hardware * @queue: Queue over which the frame should be send * @skb: The skb to send @@ -299,8 +316,8 @@ void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc); void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc); -void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, +void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length); +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, unsigned int header_length, struct rxdone_entry_desc *rxdesc); #else @@ -330,12 +347,12 @@ static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, { } -static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) +static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, + unsigned int header_length) { } -static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, - unsigned int align, +static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, unsigned int header_length, struct rxdone_entry_desc *rxdesc) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 6f78915..bc1742c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -148,6 +148,35 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) dev_kfree_skb_any(skb); } +void rt2x00queue_payload_align(struct sk_buff *skb, + bool l2pad, unsigned int header_length) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int frame_length = skb->len; + unsigned int align = ALIGN_SIZE(skb, header_length); + + if (!align) + return; + + if (l2pad) { + if (skbdesc->flags & SKBDESC_L2_PADDED) { + /* Remove L2 padding */ + memmove(skb->data + align, skb->data, header_length); + skb_pull(skb, align); + skbdesc->flags &= ~SKBDESC_L2_PADDED; + } else { + /* Add L2 padding */ + skb_push(skb, align); + memmove(skb->data, skb->data + align, header_length); + skbdesc->flags |= SKBDESC_L2_PADDED; + } + } else { + /* Generic payload alignment to 4-byte boundary */ + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + } +} + static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, struct txentry_desc *txdesc) { @@ -259,6 +288,12 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->aifs = entry->queue->aifs; /* + * Header and alignment information. + */ + txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length); + + /* * Check whether this frame is to be acked. */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -416,6 +451,10 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) rt2x00crypto_tx_remove_iv(skb, &txdesc); } + if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) + rt2x00queue_payload_align(entry->skb, true, + txdesc.header_length); + /* * It could be possible that the queue was corrupted and this * call failed. Since we always return NETDEV_TX_OK to mac80211, diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index e3bfd73..13e0ece 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -87,13 +87,16 @@ 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 + * @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by * mac80211 but was stripped for processing by the driver. + * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment, + * the padded bytes are located between header and payload. */ enum skb_frame_desc_flags { SKBDESC_DMA_MAPPED_RX = 1 << 0, SKBDESC_DMA_MAPPED_TX = 1 << 1, - FRAME_DESC_IV_STRIPPED = 1 << 2, + SKBDESC_IV_STRIPPED = 1 << 2, + SKBDESC_L2_PADDED = 1 << 3 }; /** @@ -148,6 +151,7 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) * @RXDONE_MY_BSS: Does this frame originate from device's BSS. * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data. * @RXDONE_CRYPTO_ICV: Driver provided ICV data. + * @RXDONE_L2PAD: 802.11 payload has been padded to 4-byte boundary. */ enum rxdone_entry_desc_flags { RXDONE_SIGNAL_PLCP = 1 << 0, @@ -155,6 +159,7 @@ enum rxdone_entry_desc_flags { RXDONE_MY_BSS = 1 << 2, RXDONE_CRYPTO_IV = 1 << 3, RXDONE_CRYPTO_ICV = 1 << 4, + RXDONE_L2PAD = 1 << 5, }; /** @@ -267,6 +272,8 @@ enum txentry_desc_flags { * * @flags: Descriptor flags (See &enum queue_entry_flags). * @queue: Queue identification (See &enum data_queue_qid). + * @header_length: Length of 802.11 header. + * @l2pad: Amount of padding to align 802.11 payload to 4-byte boundrary. * @length_high: PLCP length high word. * @length_low: PLCP length low word. * @signal: PLCP signal. @@ -287,6 +294,9 @@ struct txentry_desc { enum data_queue_qid queue; + u16 header_length; + u16 l2pad; + u16 length_high; u16 length_low; u16 signal; -- cgit v0.10.2 From 35f00cfcc06bb85e0659f9847400518008d78145 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 26 Apr 2009 16:09:32 +0200 Subject: rt2x00: Implement support for 802.11n Extend rt2x00lib capabilities to support 802.11n, it still lacks aggregation support, but that can be added in the future. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index bfc5d9c..4338c93 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -88,6 +88,9 @@ config RT2X00_LIB_USB config RT2X00_LIB tristate +config RT2X00_LIB_HT + boolean + config RT2X00_LIB_FIRMWARE boolean select FW_LOADER diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index f22d808..776ec2b 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -8,6 +8,7 @@ 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 +rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7c5cbb1..ebe5f27 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -366,6 +366,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) * for @tx_power_a, @tx_power_bg and @channels. * @channels: Device/chipset specific channel values (See &struct rf_channel). * @channels_info: Additional information for channels (See &struct channel_info). + * @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap). */ struct hw_mode_spec { unsigned int supported_bands; @@ -379,6 +380,8 @@ struct hw_mode_spec { unsigned int num_channels; const struct rf_channel *channels; const struct channel_info *channels_info; + + struct ieee80211_sta_ht_cap ht; }; /* @@ -616,6 +619,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_CHANNEL_HT40, }; /* @@ -788,6 +792,13 @@ struct rt2x00_dev { u8 freq_offset; /* + * Calibration information (for rt2800usb & rt2800pci). + * [0] -> BW20 + * [1] -> BW40 + */ + u8 calibration[2]; + + /* * Low level statistics which will have * to be kept up to date while device is running. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 9c2f551..863e399 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -173,6 +173,11 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, libconf.conf = conf; if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { + if (conf_is_ht40(conf)) + __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + else + __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + memcpy(&libconf.rf, &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e15086a..f227084 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -323,19 +323,54 @@ void rt2x00lib_txdone(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); +static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, + struct rxdone_entry_desc *rxdesc) +{ + struct ieee80211_supported_band *sband; + const struct rt2x00_rate *rate; + unsigned int i; + int signal; + int type; + + /* + * For non-HT rates the MCS value needs to contain the + * actually used rate modulation (CCK or OFDM). + */ + if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS) + signal = RATE_MCS(rxdesc->rate_mode, rxdesc->signal); + else + signal = rxdesc->signal; + + type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK); + + sband = &rt2x00dev->bands[rt2x00dev->curr_band]; + for (i = 0; i < sband->n_bitrates; i++) { + rate = rt2x00_get_rate(sband->bitrates[i].hw_value); + + if (((type == RXDONE_SIGNAL_PLCP) && + (rate->plcp == signal)) || + ((type == RXDONE_SIGNAL_BITRATE) && + (rate->bitrate == signal)) || + ((type == RXDONE_SIGNAL_MCS) && + (rate->mcs == signal))) { + return i; + } + } + + WARNING(rt2x00dev, "Frame received with unrecognized signal, " + "signal=0x%.4x, type=%d.\n", signal, type); + return 0; +} + void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { struct rxdone_entry_desc rxdesc; struct sk_buff *skb; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; - struct ieee80211_supported_band *sband; - const struct rt2x00_rate *rate; unsigned int header_length; bool l2pad; - unsigned int i; - int idx = -1; - + int rate_idx; /* * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. @@ -379,26 +414,17 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, rt2x00queue_payload_align(entry->skb, l2pad, header_length); /* - * Update RX statistics. + * Check if the frame was received using HT. In that case, + * the rate is the MCS index and should be passed to mac80211 + * directly. Otherwise we need to translate the signal to + * the correct bitrate index. */ - sband = &rt2x00dev->bands[rt2x00dev->curr_band]; - for (i = 0; i < sband->n_bitrates; i++) { - rate = rt2x00_get_rate(sband->bitrates[i].hw_value); - - if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && - (rate->plcp == rxdesc.signal)) || - ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) && - (rate->bitrate == rxdesc.signal))) { - idx = i; - break; - } - } - - if (idx < 0) { - WARNING(rt2x00dev, "Frame received with unrecognized signal," - "signal=0x%.2x, type=%d.\n", rxdesc.signal, - (rxdesc.dev_flags & RXDONE_SIGNAL_MASK)); - idx = 0; + if (rxdesc.rate_mode == RATE_MODE_CCK || + rxdesc.rate_mode == RATE_MODE_OFDM) { + rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); + } else { + rxdesc.flags |= RX_FLAG_HT; + rate_idx = rxdesc.signal; } /* @@ -408,7 +434,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, rt2x00debug_update_crypto(rt2x00dev, &rxdesc); rx_status->mactime = rxdesc.timestamp; - rx_status->rate_idx = idx; + rx_status->rate_idx = rate_idx; rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi); rx_status->signal = rxdesc.rssi; rx_status->noise = rxdesc.noise; @@ -443,72 +469,84 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .bitrate = 10, .ratemask = BIT(0), .plcp = 0x00, + .mcs = RATE_MCS(RATE_MODE_CCK, 0), }, { .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 20, .ratemask = BIT(1), .plcp = 0x01, + .mcs = RATE_MCS(RATE_MODE_CCK, 1), }, { .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 55, .ratemask = BIT(2), .plcp = 0x02, + .mcs = RATE_MCS(RATE_MODE_CCK, 2), }, { .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 110, .ratemask = BIT(3), .plcp = 0x03, + .mcs = RATE_MCS(RATE_MODE_CCK, 3), }, { .flags = DEV_RATE_OFDM, .bitrate = 60, .ratemask = BIT(4), .plcp = 0x0b, + .mcs = RATE_MCS(RATE_MODE_OFDM, 0), }, { .flags = DEV_RATE_OFDM, .bitrate = 90, .ratemask = BIT(5), .plcp = 0x0f, + .mcs = RATE_MCS(RATE_MODE_OFDM, 1), }, { .flags = DEV_RATE_OFDM, .bitrate = 120, .ratemask = BIT(6), .plcp = 0x0a, + .mcs = RATE_MCS(RATE_MODE_OFDM, 2), }, { .flags = DEV_RATE_OFDM, .bitrate = 180, .ratemask = BIT(7), .plcp = 0x0e, + .mcs = RATE_MCS(RATE_MODE_OFDM, 3), }, { .flags = DEV_RATE_OFDM, .bitrate = 240, .ratemask = BIT(8), .plcp = 0x09, + .mcs = RATE_MCS(RATE_MODE_OFDM, 4), }, { .flags = DEV_RATE_OFDM, .bitrate = 360, .ratemask = BIT(9), .plcp = 0x0d, + .mcs = RATE_MCS(RATE_MODE_OFDM, 5), }, { .flags = DEV_RATE_OFDM, .bitrate = 480, .ratemask = BIT(10), .plcp = 0x08, + .mcs = RATE_MCS(RATE_MODE_OFDM, 6), }, { .flags = DEV_RATE_OFDM, .bitrate = 540, .ratemask = BIT(11), .plcp = 0x0c, + .mcs = RATE_MCS(RATE_MODE_OFDM, 7), }, }; @@ -584,6 +622,8 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, rt2x00dev->bands[IEEE80211_BAND_2GHZ].bitrates = rates; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &rt2x00dev->bands[IEEE80211_BAND_2GHZ]; + memcpy(&rt2x00dev->bands[IEEE80211_BAND_2GHZ].ht_cap, + &spec->ht, sizeof(spec->ht)); } /* @@ -600,6 +640,8 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, rt2x00dev->bands[IEEE80211_BAND_5GHZ].bitrates = &rates[4]; hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &rt2x00dev->bands[IEEE80211_BAND_5GHZ]; + memcpy(&rt2x00dev->bands[IEEE80211_BAND_5GHZ].ht_cap, + &spec->ht, sizeof(spec->ht)); } return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c new file mode 100644 index 0000000..e3cec83 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -0,0 +1,69 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + 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 HT specific routines. + */ + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; + + if (tx_info->control.sta) + txdesc->mpdu_density = + tx_info->control.sta->ht_cap.ampdu_density; + else + txdesc->mpdu_density = 0; + + txdesc->ba_size = 7; /* FIXME: What value is needed? */ + txdesc->stbc = 0; /* FIXME: What value is needed? */ + + txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs); + if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + txdesc->mcs |= 0x08; + + /* + * Convert flags + */ + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); + + /* + * Determine HT Mix/Greenfield rate mode + */ + if (txrate->flags & IEEE80211_TX_RC_MCS) + txdesc->rate_mode = RATE_MODE_HT_MIX; + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) + txdesc->rate_mode = RATE_MODE_HT_GREENFIELD; + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); + if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) + __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); +} diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index aa284e4..ccc7ba4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -48,6 +48,7 @@ struct rt2x00_rate { unsigned short ratemask; unsigned short plcp; + unsigned short mcs; }; extern const struct rt2x00_rate rt2x00_supported_rates[12]; @@ -57,6 +58,14 @@ static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value) return &rt2x00_supported_rates[hw_value & 0xff]; } +#define RATE_MCS(__mode, __mcs) \ + ( (((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff) ) + +static inline int rt2x00_get_rate_mcs(const u16 mcs_value) +{ + return (mcs_value & 0x00ff); +} + /* * Radio control handlers. */ @@ -360,6 +369,21 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, #endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* + * HT handlers. + */ +#ifdef CONFIG_RT2X00_LIB_HT +void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate); +#else +static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate) +{ +} +#endif /* CONFIG_RT2X00_LIB_HT */ + +/* * RFkill handlers. */ #ifdef CONFIG_RT2X00_LIB_RFKILL diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index bc1742c..44e5b32 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -361,6 +361,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Apply TX descriptor handling by components */ rt2x00crypto_create_tx_descriptor(entry, txdesc); + rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); rt2x00queue_create_tx_descriptor_seq(entry, txdesc); rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 13e0ece..b5e0634 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -35,9 +35,12 @@ * for USB devices this restriction does not apply, but the value of * 2432 makes sense since it is big enough to contain the maximum fragment * size according to the ieee802.11 specs. + * The aggregation size depends on support from the driver, but should + * be something around 3840 bytes. */ -#define DATA_FRAME_SIZE 2432 -#define MGMT_FRAME_SIZE 256 +#define DATA_FRAME_SIZE 2432 +#define MGMT_FRAME_SIZE 256 +#define AGGREGATION_SIZE 3840 /** * DOC: Number of entries per queue @@ -148,18 +151,20 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) * * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. + * @RXDONE_SIGNAL_MCS: Signal field contains the mcs value. * @RXDONE_MY_BSS: Does this frame originate from device's BSS. * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data. * @RXDONE_CRYPTO_ICV: Driver provided ICV data. * @RXDONE_L2PAD: 802.11 payload has been padded to 4-byte boundary. */ enum rxdone_entry_desc_flags { - RXDONE_SIGNAL_PLCP = 1 << 0, - RXDONE_SIGNAL_BITRATE = 1 << 1, - RXDONE_MY_BSS = 1 << 2, - RXDONE_CRYPTO_IV = 1 << 3, - RXDONE_CRYPTO_ICV = 1 << 4, - RXDONE_L2PAD = 1 << 5, + RXDONE_SIGNAL_PLCP = BIT(0), + RXDONE_SIGNAL_BITRATE = BIT(1), + RXDONE_SIGNAL_MCS = BIT(2), + RXDONE_MY_BSS = BIT(3), + RXDONE_CRYPTO_IV = BIT(4), + RXDONE_CRYPTO_ICV = BIT(5), + RXDONE_L2PAD = BIT(6), }; /** @@ -168,7 +173,7 @@ enum rxdone_entry_desc_flags { * from &rxdone_entry_desc to a signal value type. */ #define RXDONE_SIGNAL_MASK \ - ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE ) + ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE | RXDONE_SIGNAL_MCS ) /** * struct rxdone_entry_desc: RX Entry descriptor @@ -182,6 +187,7 @@ 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). + * @rate_mode: Rate mode (See @enum rate_modulation). * @cipher: Cipher type used during decryption. * @cipher_status: Decryption status. * @iv: IV/EIV data used during decryption. @@ -195,6 +201,7 @@ struct rxdone_entry_desc { int size; int flags; int dev_flags; + u16 rate_mode; u8 cipher; u8 cipher_status; @@ -248,6 +255,9 @@ struct txdone_entry_desc { * @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. + * @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU. + * @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth. + * @ENTRY_TXD_HT_SHORT_GI: Use short GI. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, @@ -263,6 +273,9 @@ enum txentry_desc_flags { ENTRY_TXD_ENCRYPT_PAIRWISE, ENTRY_TXD_ENCRYPT_IV, ENTRY_TXD_ENCRYPT_MMIC, + ENTRY_TXD_HT_AMPDU, + ENTRY_TXD_HT_BW_40, + ENTRY_TXD_HT_SHORT_GI, }; /** @@ -278,7 +291,11 @@ enum txentry_desc_flags { * @length_low: PLCP length low word. * @signal: PLCP signal. * @service: PLCP service. + * @msc: MCS. + * @stbc: STBC. + * @ba_size: BA size. * @rate_mode: Rate mode (See @enum rate_modulation). + * @mpdu_density: MDPU density. * @retry_limit: Max number of retries. * @aifs: AIFS value. * @ifs: IFS value. @@ -302,7 +319,11 @@ struct txentry_desc { u16 signal; u16 service; + u16 mcs; + u16 stbc; + u16 ba_size; u16 rate_mode; + u16 mpdu_density; short retry_limit; short aifs; -- cgit v0.10.2 From 2516baa63bc7d05a6573a0f584135484ed182a87 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 27 Apr 2009 22:18:10 -0400 Subject: ath5k: correct interrupt storm warning Ben Greear points out that the "too many interrupts" message will never print in the intended case since the interrupt counter will be -1 after the loop. Change it to pre-decrement so it will be 0 on the thousandth iteration. Cc: Ben Greear Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 410fc4cf..7b80ceb 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2505,7 +2505,7 @@ ath5k_intr(int irq, void *dev_id) ath5k_hw_update_mib_counters(ah, &sc->ll_stats); } } - } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0); + } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); -- cgit v0.10.2 From 4edf040afc9237aa8cc90bcf54b521ac47d1ed78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 23 Apr 2009 19:36:00 +0200 Subject: mac80211: Fix handling of retry count of NO_ACK frames in minstrel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the retry count zero (total try count = 1) for frames with IEEE80211_TX_CTL_NO_ACK set. Also remove the check for is_multicast_ether_addr in use_low_rate, which is redundant because all multicasts have IEEE80211_TX_CTL_NO_ACK set. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 3824990..5196006 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -80,8 +80,7 @@ use_low_rate(struct sk_buff *skb) fc = le16_to_cpu(hdr->frame_control); return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || - (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - is_multicast_ether_addr(hdr->addr1)); + (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA); } @@ -245,7 +244,10 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, if (!sta || !mi || use_low_rate(skb)) { ar[0].idx = rate_lowest_index(sband, sta); - ar[0].count = mp->max_retry; + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + ar[0].count = 1; + else + ar[0].count = mp->max_retry; return; } -- cgit v0.10.2 From 922368414e5700d1ed51510e54137359297d78e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 23 Apr 2009 20:06:06 +0200 Subject: mac80211: Fix handling of retry count of NO_ACK frames in PID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make PID check for IEEE80211_TX_CTL_NO_ACK instead of is_multicast_ether_addr when determining whether to use the lowest rate, and set the retry count to 0 (total try count = 1) if IEEE80211_TX_CTL_NO_ACK is set. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index b16801c..2b33e3a 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -289,13 +289,15 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, info->control.rates[0].count = txrc->hw->conf.short_frame_max_tx_count; - /* Send management frames and broadcast/multicast data using lowest - * rate. */ + /* Send management frames and NO_ACK data using lowest rate. */ fc = le16_to_cpu(hdr->frame_control); if (!sta || !spinfo || (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - is_multicast_ether_addr(hdr->addr1)) { + info->flags & IEEE80211_TX_CTL_NO_ACK) { info->control.rates[0].idx = rate_lowest_index(sband, sta); + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->control.rates[0].count = 1; + return; } -- cgit v0.10.2 From 514d65c18ee3595f7f9c9132895ed449f911ecd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 23 Apr 2009 19:36:08 +0200 Subject: iwlwifi: Fix handling of retry count of NO_ACK frames in iwl-{3945|agn}-rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make iwl-{3945|agn}-rs check for IEEE80211_TX_CTL_NO_ACK instead of is_multicast_ether_addr when determining whether to use the lowest rate, and set the retry count to 0 (total try count = 1) if IEEE80211_TX_CTL_NO_ACK is set. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index f63a9c5..814afaf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -683,11 +683,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, if (sta) rate_mask = sta->supp_rates[sband->band]; - /* Send management frames and broadcast/multicast data using lowest - * rate. */ + /* Send management frames and NO_ACK 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) || + info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !priv_sta) { IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); if (!rate_mask) @@ -696,6 +695,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, else info->control.rates[0].idx = rate_lowest_index(sband, sta); + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->control.rates[0].count = 1; return; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3504279..29d38b9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -172,7 +172,7 @@ struct iwl_lq_sta { }; static void rs_rate_scale_perform(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta); static void rs_fill_link_cmd(const struct iwl_priv *priv, @@ -829,7 +829,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); if (!ieee80211_is_data(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1)) + info->flags & IEEE80211_TX_CTL_NO_ACK) return; /* This packet was aggregated but doesn't carry rate scale info */ @@ -995,7 +995,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, /* See if there's a better rate or modulation mode to try. */ if (sta && sta->supp_rates[sband->band]) - rs_rate_scale_perform(priv, hdr, sta, lq_sta); + rs_rate_scale_perform(priv, skb, sta, lq_sta); out: return; } @@ -1975,12 +1975,14 @@ 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 ieee80211_hdr *hdr, + struct sk_buff *skb, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta) { struct ieee80211_hw *hw = priv->hw; struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; int low = IWL_RATE_INVALID; int high = IWL_RATE_INVALID; int index; @@ -2006,11 +2008,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n"); - /* Send management frames and broadcast/multicast data using - * lowest rate. */ + /* Send management frames and NO_ACK data using lowest rate. */ /* TODO: this could probably be improved.. */ if (!ieee80211_is_data(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1)) + info->flags & IEEE80211_TX_CTL_NO_ACK) return; if (!sta || !lq_sta) @@ -2450,16 +2451,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if (sta) mask_bit = sta->supp_rates[sband->band]; - /* Send management frames and broadcast/multicast data using lowest - * rate. */ + /* Send management frames and NO_ACK data using lowest rate. */ if (!ieee80211_is_data(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) { + info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) { if (!mask_bit) info->control.rates[0].idx = rate_lowest_index(sband, NULL); else info->control.rates[0].idx = rate_lowest_index(sband, sta); + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->control.rates[0].count = 1; return; } -- cgit v0.10.2 From 97d3f458a1e3350dfcbdc3b6aefa75d20d59ee17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 23 Apr 2009 19:36:11 +0200 Subject: ath9k: Fix handling of retry count of NO_ACK frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check for IEEE80211_TX_CTL_NO_ACK instead of is_multicast_ether_addr when determining whether to use lowest rate without retries. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 8f3cf10..e526dbc 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1568,12 +1568,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ath_rate_priv *ath_rc_priv = priv_sta; __le16 fc = hdr->frame_control; - /* lowest rate for management and multicast/broadcast frames */ - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta) { + /* lowest rate for management and NO_ACK frames */ + if (!ieee80211_is_data(fc) || + tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) { tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); tx_info->control.rates[0].count = - is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; + (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ? + 1 : ATH_MGT_TXMAXTRY; return; } -- cgit v0.10.2 From 9955151df7c6452cae2ed9649f53d265c91cf155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 23 Apr 2009 19:36:14 +0200 Subject: mac80211: Warn if the rate controller requests retries for a NO_ACK frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To deter future rate scaling algorithm writers from requesting NO_ACK packets to be retried, throw a WARN_ON_ONCE if the algorithm hands us a try count over 1 for NO_ACK packet. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1564a30..36e8e2d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -558,6 +558,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) if (unlikely(!info->control.rates[0].count)) info->control.rates[0].count = 1; + if (WARN_ON_ONCE((info->control.rates[0].count > 1) && + (info->flags & IEEE80211_TX_CTL_NO_ACK))) + info->control.rates[0].count = 1; + if (is_multicast_ether_addr(hdr->addr1)) { /* * XXX: verify the rate is in the basic rateset -- cgit v0.10.2 From 5cff20e6c5a6591a79d3b027af222870f52bb550 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Apr 2009 12:26:17 +0200 Subject: mac80211: tell driver when idle When we aren't doing anything in mac80211, we can turn off much of the hardware, depending on the driver/hw. Not doing anything, aka being idle, means: * no monitor interfaces * no AP/mesh/wds interfaces * any station interfaces are in DISABLED state * any IBSS interfaces aren't trying to be in a network * we aren't trying to scan By creating a new function that verifies these conditions and calling it at strategic points where the states of those conditions change, we can easily make mac80211 tell the driver when we are idle to save power. Additionally, this fixes a small quirk where a recalculated powersave state is passed to the driver even if the hardware is about to stopped completely. This patch intentionally doesn't touch radio_enabled because that is currently implemented to be a soft rfkill which is inappropriate here when we need to be able to wake up with low latency. One thing I'm not entirely sure about is this: phy0: device no longer idle - in use wlan0: direct probe to AP 00:11:24:91:07:4d try 1 wlan0 direct probe responded wlan0: authenticate with AP 00:11:24:91:07:4d wlan0: authenticated > phy0: device now idle > phy0: device no longer idle - in use wlan0: associate with AP 00:11:24:91:07:4d wlan0: RX AssocResp from 00:11:24:91:07:4d (capab=0x401 status=0 aid=1) wlan0: associated Is it appropriate to go into idle state for a short time when we have just authenticated, but not associated yet? This happens only with the userspace SME, because we cannot really know how long it will wait before asking us to associate. Would going idle after a short timeout be more appropriate? We may need to revisit this, depending on what happens. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 8fa6e6c..b1213b6 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -553,9 +553,11 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; - printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d)\n", + printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d idle=%d ps=%d)\n", wiphy_name(hw->wiphy), __func__, - conf->channel->center_freq, conf->radio_enabled); + conf->channel->center_freq, conf->radio_enabled, + !!(conf->flags & IEEE80211_CONF_IDLE), + !!(conf->flags & IEEE80211_CONF_PS)); data->channel = conf->channel; data->radio_enabled = conf->radio_enabled; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7806e22..38dc1cd 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -533,10 +533,16 @@ struct ieee80211_rx_status { * * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only) + * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set + * the driver should be prepared to handle configuration requests but + * may turn the device off as much as possible. Typically, this flag will + * be set when an interface is set UP but not associated or scanning, but + * it can also be unset in that case when monitor interfaces are active. */ enum ieee80211_conf_flags { IEEE80211_CONF_RADIOTAP = (1<<0), IEEE80211_CONF_PS = (1<<1), + IEEE80211_CONF_IDLE = (1<<2), }; @@ -551,6 +557,7 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_POWER: the TX power changed * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed + * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed */ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), @@ -561,6 +568,7 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_POWER = BIT(5), IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), + IEEE80211_CONF_CHANGE_IDLE = BIT(8), }; static inline __deprecated enum ieee80211_conf_changed diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a8e2323..aa53768 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -862,6 +862,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.ssid_len = params->ssid_len; + ieee80211_recalc_idle(sdata->local); + set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); @@ -889,6 +891,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) skb_queue_purge(&sdata->u.ibss.skb_queue); memset(sdata->u.ibss.bssid, 0, ETH_ALEN); + sdata->u.ibss.ssid_len = 0; + + ieee80211_recalc_idle(sdata->local); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 236ea09..03e0d22 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -985,6 +985,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type); void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); void ieee80211_remove_interfaces(struct ieee80211_local *local); +u32 __ieee80211_recalc_idle(struct ieee80211_local *local); +void ieee80211_recalc_idle(struct ieee80211_local *local); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 256fa19..8b6daf0 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -301,6 +301,8 @@ static int ieee80211_open(struct net_device *dev) if (sdata->flags & IEEE80211_SDATA_PROMISC) atomic_inc(&local->iff_promiscs); + hw_reconf_flags |= __ieee80211_recalc_idle(local); + local->open_count++; if (hw_reconf_flags) { ieee80211_hw_config(local, hw_reconf_flags); @@ -548,6 +550,10 @@ static int ieee80211_stop(struct net_device *dev) sdata->bss = NULL; + hw_reconf_flags |= __ieee80211_recalc_idle(local); + + ieee80211_recalc_ps(local, -1); + if (local->open_count == 0) { if (netif_running(local->mdev)) dev_close(local->mdev); @@ -565,8 +571,6 @@ static int ieee80211_stop(struct net_device *dev) hw_reconf_flags = 0; } - ieee80211_recalc_ps(local, -1); - /* do after stop to avoid reconfiguring when we stop anyway */ if (hw_reconf_flags) ieee80211_hw_config(local, hw_reconf_flags); @@ -892,3 +896,73 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) unregister_netdevice(sdata->dev); } } + +static u32 ieee80211_idle_off(struct ieee80211_local *local, + const char *reason) +{ + if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) + return 0; + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: device no longer idle - %s\n", + wiphy_name(local->hw.wiphy), reason); +#endif + + local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 ieee80211_idle_on(struct ieee80211_local *local) +{ + if (local->hw.conf.flags & IEEE80211_CONF_IDLE) + return 0; + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: device now idle\n", + wiphy_name(local->hw.wiphy)); +#endif + + local->hw.conf.flags |= IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +u32 __ieee80211_recalc_idle(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + int count = 0; + + if (local->hw_scanning || local->sw_scanning) + return ieee80211_idle_off(local, "scanning"); + + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + /* do not count disabled managed interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_STATION && + sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED) + continue; + /* do not count unused IBSS interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_ADHOC && + !sdata->u.ibss.ssid_len) + continue; + /* count everything else */ + count++; + } + + if (!count) + return ieee80211_idle_on(local); + else + return ieee80211_idle_off(local, "in use"); + + return 0; +} + +void ieee80211_recalc_idle(struct ieee80211_local *local) +{ + u32 chg; + + mutex_lock(&local->iflist_mtx); + chg = __ieee80211_recalc_idle(local); + mutex_unlock(&local->iflist_mtx); + ieee80211_hw_config(local, chg); +} diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2ded476..5509c5a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -890,6 +890,7 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); /* @@ -938,6 +939,7 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) " timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, @@ -1041,6 +1043,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); + ieee80211_recalc_idle(local); + /* channel(_type) changes are handled by ieee80211_hw_config */ local->oper_channel_type = NL80211_CHAN_NO_HT; @@ -1121,6 +1125,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) " timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, @@ -1141,6 +1146,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: mismatch in privacy configuration and " "mixed-cell disabled - abort association\n", sdata->dev->name); ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); return; } @@ -1279,6 +1285,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) if (ifmgd->flags & IEEE80211_STA_EXT_SME) { /* Wait for SME to request association */ ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(sdata->local); } else ieee80211_associate(sdata); } @@ -1515,6 +1522,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (ifmgd->flags & IEEE80211_STA_EXT_SME) { /* Wait for SME to decide what to do next */ ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); } return; } @@ -2083,6 +2091,7 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) } else { ifmgd->assoc_scan_tries = 0; ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); } } return -1; @@ -2126,6 +2135,8 @@ static void ieee80211_sta_work(struct work_struct *work) } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) return; + ieee80211_recalc_idle(local); + switch (ifmgd->state) { case IEEE80211_STA_MLME_DISABLED: break; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 127bd54..c99ef8d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -302,17 +302,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) /* we only have to protect scan_req and hw/sw scan */ mutex_unlock(&local->scan_mtx); - if (was_hw_scan) { - /* - * Somebody might have requested channel change during scan - * that we won't have acted upon, try now. ieee80211_hw_config - * will set the flag based on actual changes. - */ - ieee80211_hw_config(local, 0); - goto done; - } - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + if (was_hw_scan) + goto done; netif_tx_lock_bh(local->mdev); netif_addr_lock(local->mdev); @@ -351,6 +343,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) mutex_unlock(&local->iflist_mtx); done: + ieee80211_recalc_idle(local); ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); ieee80211_mesh_notify_scan_completed(local); @@ -471,6 +464,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, * dependency, so that the scan completed calls * have more locking freedom. */ + + ieee80211_recalc_idle(local); mutex_unlock(&local->scan_mtx); if (local->ops->hw_scan) @@ -487,6 +482,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, } else local->sw_scanning = false; + ieee80211_recalc_idle(local); + local->scan_req = NULL; local->scan_sdata = NULL; } -- cgit v0.10.2 From fb4a3d35a26aa8ef5049f10666e6a163b4c32855 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Wed, 29 Apr 2009 13:01:58 +0200 Subject: ath9k: uninline ath9k_io{read,write}32 routines The spin_lock handling uses lots of instructions on some archs. With this patch the size of the ath9k module will be significantly smaller. Signed-off-by: Gabor Juhos Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d5084dd..90b6314 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -697,36 +697,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, bool ath9k_wiphy_scanning(struct ath_softc *sc); void ath9k_wiphy_work(struct work_struct *work); -/* - * Read and write, they both share the same lock. We do this to serialize - * reads and writes on Atheros 802.11n PCI devices only. This is required - * as the FIFO on these devices can only accept sanely 2 requests. After - * that the device goes bananas. Serializing the reads/writes prevents this - * from happening. - */ - -static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) -{ - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - iowrite32(val, ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - iowrite32(val, ah->ah_sc->mem + reg_offset); -} - -static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) -{ - u32 val; - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - val = ioread32(ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - val = ioread32(ah->ah_sc->mem + reg_offset); - return val; -} +void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); +unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ec2a7a40..02f4015 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -84,6 +84,38 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) return ath9k_hw_mac_clks(ah, usecs); } +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. After + * that the device goes bananas. Serializing the reads/writes prevents this + * from happening. + */ + +void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) +{ + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + iowrite32(val, ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + iowrite32(val, ah->ah_sc->mem + reg_offset); +} + +unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) +{ + u32 val; + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + val = ioread32(ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + val = ioread32(ah->ah_sc->mem + reg_offset); + return val; +} + bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) { int i; -- cgit v0.10.2 From 206eade5a68f7a06adbe7c65e47fd88843ad0546 Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Wed, 29 Apr 2009 22:00:23 +0200 Subject: rt2x00: Style fix for interval defines Extra parenthesis are not needed in these 2 cases, all other defines in rt2x00 are done without parenthesis so just fixup these 2 cases. Signed-off-by: Alban Browaeys Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index ccc7ba4..39e00b3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -32,8 +32,8 @@ * Interval defines * Both the link tuner as the rfkill will be called once per second. */ -#define LINK_TUNE_INTERVAL ( round_jiffies_relative(HZ) ) -#define RFKILL_POLL_INTERVAL ( 1000 ) +#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) +#define RFKILL_POLL_INTERVAL 1000 /* * rt2x00_rate: Per rate device information -- cgit v0.10.2 From d53d9e67b55f6a9fc3f836c5c392eb41ce5676f4 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 26 Apr 2009 15:47:48 +0200 Subject: rt2x00: Implement support for rt2800usb Add support for the rt2800usb chipset. Current problems: * Cannot scan 11n AP's * No TX during first minute after association * Broken Hardware encryption Includes various patches from Mattias, Felix, Xose and Axel. Signed-off-by: Mattias Nissler Signed-off-by: Felix Fietkau Signed-off-by: Xose Vazquez Perez Signed-off-by: Axel Kollhofer Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 4338c93..18ee7d6 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -77,6 +77,20 @@ config RT73USB When compiled as a module, this driver will be called "rt73usb.ko". +config RT2800USB + tristate "Ralink rt2800 (USB) support" + depends on USB + select RT2X00_LIB_USB + select RT2X00_LIB_HT + select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO + select CRC_CCITT + ---help--- + This adds support for rt2800 wireless chipset family. + Supported chips: RT2770, RT2870 & RT3070. + + When compiled as a module, this driver will be called "rt2800usb.ko". + config RT2X00_LIB_PCI tristate select RT2X00_LIB diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 776ec2b..bfc7226 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_RT2500PCI) += rt2500pci.o obj-$(CONFIG_RT61PCI) += rt61pci.o obj-$(CONFIG_RT2500USB) += rt2500usb.o obj-$(CONFIG_RT73USB) += rt73usb.o +obj-$(CONFIG_RT2800USB) += rt2800usb.o diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c new file mode 100644 index 0000000..812912e --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -0,0 +1,3046 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + 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: rt2800usb + Abstract: rt2800usb device specific routines. + Supported chipsets: RT2800U. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" +#include "rt2800usb.h" + +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 1; +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 + * rt2x00usb_register_read and rt2x00usb_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + * The _lock versions must be used if you already hold the csr_mutex + */ +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RFCSR(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) +#define WAIT_FOR_MCU(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) + +static void rt2800usb_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); + + rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); + + rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + + WAIT_FOR_BBP(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + + WAIT_FOR_RFCSR(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); + rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the MCU becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_MCU(rt2x00dev, ®)) { + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00usb_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); + + reg = 0; + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00usb_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +static const struct rt2x00debug rt2800usb_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2x00usb_register_read, + .write = rt2x00usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2800usb_bbp_read, + .write = rt2800usb_bbp_write, + .word_base = BBP_BASE, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2800usb_rf_write, + .word_base = RF_BASE, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT2X00_LIB_RFKILL +static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); +} +#else +#define rt2800usb_rfkill_poll NULL +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + +#ifdef CONFIG_RT2X00_LIB_LEDS +static void rt2800usb_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + unsigned int bg_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); + unsigned int polarity = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_POLARITY); + unsigned int ledmode = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_MODE); + + if (led->type == LED_TYPE_RADIO) { + rt2800usb_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? 0x20 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2800usb_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * The specs tell us the following levels: + * 0, 1 ,3, 7, 15, 31 + * to determine the level in a simple way we can simply + * work with bitshifting: + * (1 << level) - 1 + */ + rt2800usb_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + (1 << brightness / (LED_FULL / 6)) - 1, + polarity); + } +} + +static int rt2800usb_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; + + rt2x00usb_register_read(led->rt2x00dev, LED_CFG, ®); + rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); + rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); + rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); + rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); + rt2x00usb_register_write(led->rt2x00dev, LED_CFG, reg); + + return 0; +} + +static void rt2800usb_init_led(struct rt2x00_dev *rt2x00dev, + struct rt2x00_led *led, + enum led_type type) +{ + led->rt2x00dev = rt2x00dev; + led->type = type; + led->led_dev.brightness_set = rt2800usb_brightness_set; + led->led_dev.blink_set = rt2800usb_blink_set; + led->flags = LED_INITIALIZED; +} +#endif /* CONFIG_RT2X00_LIB_LEDS */ + +/* + * Configuration handlers. + */ +static void rt2800usb_config_wcid_attr(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct mac_wcid_entry wcid_entry; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + u32 reg; + + offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, + (crypto->cmd == SET_KEY) * crypto->bssidx); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + offset = MAC_IVEIV_ENTRY(key->hw_key_idx); + + memset(&iveiv_entry, 0, sizeof(iveiv_entry)); + if ((crypto->cipher == CIPHER_TKIP) || + (crypto->cipher == CIPHER_TKIP_NO_MIC) || + (crypto->cipher == CIPHER_AES)) + iveiv_entry.iv[3] |= 0x20; + iveiv_entry.iv[3] |= key->keyidx << 6; + rt2x00usb_register_multiwrite(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + offset = MAC_WCID_ENTRY(key->hw_key_idx); + + memset(&wcid_entry, 0, sizeof(wcid_entry)); + if (crypto->cmd == SET_KEY) + memcpy(&wcid_entry, crypto->address, ETH_ALEN); + rt2x00usb_register_multiwrite(rt2x00dev, offset, + &wcid_entry, sizeof(wcid_entry)); +} + +static int rt2800usb_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 offset; + u32 reg; + + if (crypto->cmd == SET_KEY) { + key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; + + 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)); + + offset = 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, + offset, &key_entry, + sizeof(key_entry), + timeout); + } + + /* + * The cipher types are stored over multiple registers + * starting with SHARED_KEY_MODE_BASE each word will have + * 32 bits and contains the cipher types for 2 bssidx each. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + field.bit_offset = 4 * (key->hw_key_idx % 8); + field.bit_mask = 0x7 << field.bit_offset; + + offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + /* + * Update WCID information + */ + rt2800usb_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} + +static int rt2800usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + int timeout; + u32 offset; + + if (crypto->cmd == SET_KEY) { + /* + * 1 pairwise key is possible per AID, this means that the AID + * equals our hw_key_idx. Make sure the WCID starts _after_ the + * last possible shared key entry. + */ + if (crypto->aid > (256 - 32)) + return -ENOSPC; + + key->hw_key_idx = 32 + crypto->aid; + + 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)); + + offset = 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, + offset, &key_entry, + sizeof(key_entry), + timeout); + } + + /* + * Update WCID information + */ + rt2800usb_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} + +static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) +{ + u32 reg; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00usb_register_read(rt2x00dev, RX_FILTER_CFG, ®); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, + !(filter_flags & FIF_CONTROL)); + rt2x00usb_register_write(rt2x00dev, RX_FILTER_CFG, reg); +} + +static void rt2800usb_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) +{ + unsigned int beacon_base; + u32 reg; + + if (flags & CONFIG_UPDATE_TYPE) { + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); + rt2x00usb_register_write(rt2x00dev, beacon_base, 0); + + /* + * Enable synchronisation. + */ + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + } + + if (flags & CONFIG_UPDATE_MAC) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); + + rt2x00usb_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, + conf->mac, sizeof(conf->mac)); + } + + if (flags & CONFIG_UPDATE_BSSID) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); + conf->bssid[1] = cpu_to_le32(reg); + + rt2x00usb_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, + conf->bssid, sizeof(conf->bssid)); + } +} + +static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, + DIV_ROUND_UP(erp->ack_timeout, erp->slot_time)); + rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, + !!erp->short_preamble); + rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, + !!erp->short_preamble); + rt2x00usb_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, + erp->cts_protection ? 2 : 0); + rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, LEGACY_BASIC_RATE, + erp->basic_rates); + rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2x00usb_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); + rt2x00usb_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); + rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); + rt2x00usb_register_write(rt2x00dev, XIFS_TIME_CFG, reg); +} + +static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) +{ + u8 r1; + u8 r3; + + rt2800usb_bbp_read(rt2x00dev, 1, &r1); + rt2800usb_bbp_read(rt2x00dev, 3, &r3); + + /* + * Configure the TX antenna. + */ + switch ((int)ant->tx) { + case 1: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); + break; + case 3: + /* Do nothing */ + break; + } + + /* + * Configure the RX antenna. + */ + switch ((int)ant->rx) { + case 1: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); + break; + case 3: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); + break; + } + + rt2800usb_bbp_write(rt2x00dev, 3, r3); + rt2800usb_bbp_write(rt2x00dev, 1, r1); +} + +static void rt2800usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain; + + if (libconf->rf.channel <= 14) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); + } else if (libconf->rf.channel <= 64) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); + } else if (libconf->rf.channel <= 128) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt2800usb_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + if (rt2x00dev->default_ant.tx == 1) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); + + if (rt2x00dev->default_ant.rx == 1) { + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + } else if (rt2x00dev->default_ant.rx == 2) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + + if (rf->channel > 14) { + /* + * When TX power is below 0, we should increase it by 7 to + * make it a positive value (Minumum value is -7). + * However this means that values between 0 and 7 have + * double meaning, and we should set a 7DBm boost flag. + */ + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, + (info->tx_power1 >= 0)); + + if (info->tx_power1 < 0) + info->tx_power1 += 7; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power1)); + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, + (info->tx_power2 >= 0)); + + if (info->tx_power2 < 0) + info->tx_power2 += 7; + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power2)); + } else { + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power2)); + } + + rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); + + rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); +} + +static void rt2800usb_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u8 rfcsr; + + rt2800usb_rfcsr_write(rt2x00dev, 2, rf->rf1); + rt2800usb_rfcsr_write(rt2x00dev, 2, rf->rf3); + + rt2800usb_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); + rt2800usb_rfcsr_write(rt2x00dev, 6, rfcsr); + + rt2800usb_rfcsr_read(rt2x00dev, 12, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2800usb_rfcsr_write(rt2x00dev, 12, rfcsr); + + rt2800usb_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); + rt2800usb_rfcsr_write(rt2x00dev, 23, rfcsr); + + rt2800usb_rfcsr_write(rt2x00dev, 24, + rt2x00dev->calibration[conf_is_ht40(conf)]); + + rt2800usb_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); + rt2800usb_rfcsr_write(rt2x00dev, 23, rfcsr); +} + +static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u32 reg; + unsigned int tx_pin; + u8 bbp; + + if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + rt2800usb_config_channel_rt2x(rt2x00dev, conf, rf, info); + else + rt2800usb_config_channel_rt3x(rt2x00dev, conf, rf, info); + + /* + * Change BBP settings + */ + rt2800usb_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800usb_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800usb_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800usb_bbp_write(rt2x00dev, 86, 0); + + if (rf->channel <= 14) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + rt2800usb_bbp_write(rt2x00dev, 82, 0x62); + rt2800usb_bbp_write(rt2x00dev, 75, 0x46); + } else { + rt2800usb_bbp_write(rt2x00dev, 82, 0x84); + rt2800usb_bbp_write(rt2x00dev, 75, 0x50); + } + } else { + rt2800usb_bbp_write(rt2x00dev, 82, 0xf2); + + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + rt2800usb_bbp_write(rt2x00dev, 75, 0x46); + else + rt2800usb_bbp_write(rt2x00dev, 75, 0x50); + } + + rt2x00usb_register_read(rt2x00dev, TX_BAND_CFG, ®); + rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); + rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); + rt2x00usb_register_write(rt2x00dev, TX_BAND_CFG, reg); + + tx_pin = 0; + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.tx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); + } + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.rx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); + } + + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); + + rt2x00usb_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + + rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); + rt2800usb_bbp_write(rt2x00dev, 4, bbp); + + rt2800usb_bbp_read(rt2x00dev, 3, &bbp); + rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2800usb_bbp_write(rt2x00dev, 3, bbp); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + if (conf_is_ht40(conf)) { + rt2800usb_bbp_write(rt2x00dev, 69, 0x1a); + rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); + rt2800usb_bbp_write(rt2x00dev, 73, 0x16); + } else { + rt2800usb_bbp_write(rt2x00dev, 69, 0x16); + rt2800usb_bbp_write(rt2x00dev, 70, 0x08); + rt2800usb_bbp_write(rt2x00dev, 73, 0x11); + } + } + + msleep(1); +} + +static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 reg; + u32 value = TXPOWER_G_TO_DEV(txpower); + u8 r1; + + rt2800usb_bbp_read(rt2x00dev, 1, &r1); + rt2x00_set_field8(®, BBP1_TX_POWER, 0); + rt2800usb_bbp_write(rt2x00dev, 1, r1); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_0, ®); + rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_0, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_1, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_2, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_3, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_4, reg); +} + +static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, TX_RTY_CFG, ®); + rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); + rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); + rt2x00usb_register_write(rt2x00dev, TX_RTY_CFG, reg); +} + +static void rt2800usb_config_duration(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); +} + +static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + enum dev_state state = + (libconf->conf->flags & IEEE80211_CONF_PS) ? + STATE_SLEEP : STATE_AWAKE; + u32 reg; + + if (state == STATE_SLEEP) { + rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + + rt2x00usb_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, + libconf->conf->listen_interval - 1); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); + rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + + rt2800usb_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0); + } else { + rt2800usb_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); + + rt2x00usb_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); + rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + } +} + +static void rt2800usb_config(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf, + const unsigned int flags) +{ + /* Always recalculate LNA gain before changing configuration */ + rt2800usb_config_lna_gain(rt2x00dev, libconf); + + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) + rt2800usb_config_channel(rt2x00dev, libconf->conf, + &libconf->rf, &libconf->channel); + if (flags & IEEE80211_CONF_CHANGE_POWER) + rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level); + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2800usb_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) + rt2800usb_config_duration(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_PS) + rt2800usb_config_ps(rt2x00dev, libconf); +} + +/* + * Link tuning + */ +static void rt2800usb_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT0, ®); + qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); +} + +static u8 rt2800usb_get_default_vgc(struct rt2x00_dev *rt2x00dev) +{ + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { + if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) + return 0x1c + (2 * rt2x00dev->lna_gain); + else + return 0x2e + rt2x00dev->lna_gain; + } + + if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + return 0x32 + (rt2x00dev->lna_gain * 5) / 3; + else + return 0x3a + (rt2x00dev->lna_gain * 5) / 3; +} + +static inline void rt2800usb_set_vgc(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, u8 vgc_level) +{ + if (qual->vgc_level != vgc_level) { + rt2800usb_bbp_write(rt2x00dev, 66, vgc_level); + qual->vgc_level = vgc_level; + qual->vgc_level_reg = vgc_level; + } +} + +static void rt2800usb_reset_tuner(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) +{ + rt2800usb_set_vgc(rt2x00dev, qual, + rt2800usb_get_default_vgc(rt2x00dev)); +} + +static void rt2800usb_link_tuner(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, const u32 count) +{ + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) + return; + + /* + * When RSSI is better then -80 increase VGC level with 0x10 + */ + rt2800usb_set_vgc(rt2x00dev, qual, + rt2800usb_get_default_vgc(rt2x00dev) + + ((qual->rssi > -80) * 0x10)); +} + +/* + * Firmware functions + */ +static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) +{ + return FIRMWARE_RT2870; +} + +static bool rt2800usb_check_crc(const u8 *data, const size_t len) +{ + u16 fw_crc; + u16 crc; + + /* + * The last 2 bytes in the firmware array are the crc checksum itself, + * this means that we should never pass those 2 bytes to the crc + * algorithm. + */ + fw_crc = (data[len - 2] << 8 | data[len - 1]); + + /* + * Use the crc ccitt algorithm. + * This will return the same value as the legacy driver which + * used bit ordering reversion on the both the firmware bytes + * before input input as well as on the final output. + * Obviously using crc ccitt directly is much more efficient. + */ + crc = crc_ccitt(~0, data, len - 2); + + /* + * There is a small difference between the crc-itu-t + bitrev and + * the crc-ccitt crc calculation. In the latter method the 2 bytes + * will be swapped, use swab16 to convert the crc to the correct + * value. + */ + crc = swab16(crc); + + return fw_crc == crc; +} + +static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) +{ + u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; + size_t offset = 0; + + /* + * Firmware files: + * There are 2 variations of the rt2870 firmware. + * a) size: 4kb + * b) size: 8kb + * Note that (b) contains 2 seperate firmware blobs of 4k + * within the file. The first blob is the same firmware as (a), + * but the second blob is for the additional chipsets. + */ + if (len != 4096 && len != 8192) + return FW_BAD_LENGTH; + + /* + * Check if we need the upper 4kb firmware data or not. + */ + if ((len == 4096) && + (chipset != 0x2860) && + (chipset != 0x2872) && + (chipset != 0x3070)) + return FW_BAD_VERSION; + + /* + * 8kb firmware files must be checked as if it were + * 2 seperate firmware files. + */ + while (offset < len) { + if (!rt2800usb_check_crc(data + offset, 4096)) + return FW_BAD_CRC; + + offset += 4096; + } + + return FW_OK; +} + +static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) +{ + unsigned int i; + int status; + u32 reg; + u32 offset; + u32 length; + u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; + + /* + * Check which section of the firmware we need. + */ + if ((chipset == 0x2860) || (chipset == 0x2872) || (chipset == 0x3070)) { + offset = 0; + length = 4096; + } else { + offset = 4096; + length = 4096; + } + + /* + * Wait for stable hardware. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + /* + * Write firmware to device. + */ + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + FIRMWARE_IMAGE_BASE, + data + offset, length, + REGISTER_TIMEOUT32(length)); + + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + + /* + * Send firmware request to device to load firmware, + * we need to specify a long timeout time. + */ + status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, + 0, USB_MODE_FIRMWARE, + REGISTER_TIMEOUT_FIRMWARE); + if (status < 0) { + ERROR(rt2x00dev, "Failed to write Firmware to device.\n"); + return status; + } + + /* + * Wait for device to stabilize. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "PBF system register not ready.\n"); + return -EBUSY; + } + + /* + * Initialize firmware. + */ + rt2x00usb_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + msleep(1); + + return 0; +} + +/* + * Initialization functions. + */ +static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + /* + * Wait untill BBP and RF are ready. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, + USB_MODE_RESET, REGISTER_TIMEOUT); + + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2x00usb_register_read(rt2x00dev, BCN_OFFSET0, ®); + rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ + rt2x00usb_register_write(rt2x00dev, BCN_OFFSET0, reg); + + rt2x00usb_register_read(rt2x00dev, BCN_OFFSET1, ®); + rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ + rt2x00usb_register_write(rt2x00dev, BCN_OFFSET1, reg); + + rt2x00usb_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); + rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); + } else { + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + } + + rt2x00usb_register_read(rt2x00dev, TX_LINK_CFG, ®); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); + rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_MRQ_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_RDG_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); + rt2x00usb_register_write(rt2x00dev, TX_LINK_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); + rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MAX_LEN_CFG, ®); + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); + if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && + rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); + else + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); + rt2x00usb_register_write(rt2x00dev, MAX_LEN_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); + + rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); + rt2x00usb_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2x00usb_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2x00usb_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); + + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 3); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_BIG_ENDIAN, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_HDR_SEG_LEN, 0); + rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); + rt2x00usb_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); + + rt2x00usb_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, + IEEE80211_MAX_RTS_THRESHOLD); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); + rt2x00usb_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); + rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + + /* + * ASIC will keep garbage value after boot, clear encryption keys. + */ + for (i = 0; i < 256; i++) { + u32 wcid[2] = { 0xffffffff, 0x00ffffff }; + rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), + wcid, sizeof(wcid)); + + rt2x00usb_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); + rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); + } + + for (i = 0; i < 16; i++) + rt2x00usb_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + + /* + * Clear all beacons + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE4, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE5, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE6, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE7, 0); + + rt2x00usb_register_read(rt2x00dev, USB_CYC_CFG, ®); + rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); + rt2x00usb_register_write(rt2x00dev, USB_CYC_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, HT_FBK_CFG0, ®); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS3FBK, 2); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS4FBK, 3); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); + rt2x00usb_register_write(rt2x00dev, HT_FBK_CFG0, reg); + + rt2x00usb_register_read(rt2x00dev, HT_FBK_CFG1, ®); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS11FBK, 10); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS12FBK, 11); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); + rt2x00usb_register_write(rt2x00dev, HT_FBK_CFG1, reg); + + rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 3); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); + rt2x00usb_register_write(rt2x00dev, LG_FBK_CFG0, reg); + + rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG1, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); + rt2x00usb_register_write(rt2x00dev, LG_FBK_CFG1, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT1, ®); + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT2, ®); + rt2x00usb_register_read(rt2x00dev, TX_STA_CNT0, ®); + rt2x00usb_register_read(rt2x00dev, TX_STA_CNT1, ®); + rt2x00usb_register_read(rt2x00dev, TX_STA_CNT2, ®); + + return 0; +} + +static int rt2800usb_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) + return 0; + + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n"); + return -EACCES; +} + +static int rt2800usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800usb_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + return 0; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; +} + +static int rt2800usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt2800usb_wait_bbp_rf_ready(rt2x00dev) || + rt2800usb_wait_bbp_ready(rt2x00dev))) + return -EACCES; + + rt2800usb_bbp_write(rt2x00dev, 65, 0x2c); + rt2800usb_bbp_write(rt2x00dev, 66, 0x38); + rt2800usb_bbp_write(rt2x00dev, 69, 0x12); + rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); + rt2800usb_bbp_write(rt2x00dev, 73, 0x10); + rt2800usb_bbp_write(rt2x00dev, 81, 0x37); + rt2800usb_bbp_write(rt2x00dev, 82, 0x62); + rt2800usb_bbp_write(rt2x00dev, 83, 0x6a); + rt2800usb_bbp_write(rt2x00dev, 84, 0x99); + rt2800usb_bbp_write(rt2x00dev, 86, 0x00); + rt2800usb_bbp_write(rt2x00dev, 91, 0x04); + rt2800usb_bbp_write(rt2x00dev, 92, 0x00); + rt2800usb_bbp_write(rt2x00dev, 103, 0x00); + rt2800usb_bbp_write(rt2x00dev, 105, 0x05); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + rt2800usb_bbp_write(rt2x00dev, 69, 0x16); + rt2800usb_bbp_write(rt2x00dev, 73, 0x12); + } + + if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) { + rt2800usb_bbp_write(rt2x00dev, 84, 0x19); + } + + if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); + rt2800usb_bbp_write(rt2x00dev, 84, 0x99); + rt2800usb_bbp_write(rt2x00dev, 105, 0x05); + } + + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + rt2800usb_bbp_write(rt2x00dev, reg_id, value); + } + } + + return 0; +} + +static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, + bool bw40, u8 rfcsr24, u8 filter_target) +{ + unsigned int i; + u8 bbp; + u8 rfcsr; + u8 passband; + u8 stopband; + u8 overtuned = 0; + + rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + + rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); + rt2800usb_bbp_write(rt2x00dev, 4, bbp); + + rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); + rt2800usb_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * Set power & frequency of passband test tone + */ + rt2800usb_bbp_write(rt2x00dev, 24, 0); + + for (i = 0; i < 100; i++) { + rt2800usb_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800usb_bbp_read(rt2x00dev, 55, &passband); + if (passband) + break; + } + + /* + * Set power & frequency of stopband test tone + */ + rt2800usb_bbp_write(rt2x00dev, 24, 0x06); + + for (i = 0; i < 100; i++) { + rt2800usb_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800usb_bbp_read(rt2x00dev, 55, &stopband); + + if ((passband - stopband) <= filter_target) { + rfcsr24++; + overtuned += ((passband - stopband) == filter_target); + } else + break; + + rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + } + + rfcsr24 -= !!overtuned; + + rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + return rfcsr24; +} + +static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) +{ + u8 rfcsr; + u8 bbp; + + if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + return 0; + + /* + * Init RF calibration. + */ + rt2800usb_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2800usb_rfcsr_write(rt2x00dev, 30, rfcsr); + msleep(1); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); + rt2800usb_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800usb_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800usb_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800usb_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800usb_rfcsr_write(rt2x00dev, 7, 0x70); + rt2800usb_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800usb_rfcsr_write(rt2x00dev, 10, 0x71); + rt2800usb_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800usb_rfcsr_write(rt2x00dev, 12, 0x7b); + rt2800usb_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800usb_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800usb_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800usb_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800usb_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800usb_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800usb_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800usb_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800usb_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800usb_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800usb_rfcsr_write(rt2x00dev, 27, 0x03); + rt2800usb_rfcsr_write(rt2x00dev, 29, 0x1f); + + /* + * Set RX Filter calibration for 20MHz and 40MHz + */ + rt2x00dev->calibration[0] = + rt2800usb_init_rx_filter(rt2x00dev, false, 0x07, 0x16); + rt2x00dev->calibration[1] = + rt2800usb_init_rx_filter(rt2x00dev, true, 0x27, 0x19); + + /* + * Set back to initial state + */ + rt2800usb_bbp_write(rt2x00dev, 24, 0); + + rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); + rt2800usb_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * set BBP back to BW20 + */ + rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); + rt2800usb_bbp_write(rt2x00dev, 4, bbp); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, + (state == STATE_RADIO_RX_ON) || + (state == STATE_RADIO_RX_ON_LINK)); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); +} + +static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) + return 0; + + msleep(1); + } + + ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); + return -EACCES; +} + +static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 word; + + /* + * Initialize all registers. + */ + if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) || + rt2800usb_init_registers(rt2x00dev) || + rt2800usb_init_bbp(rt2x00dev) || + rt2800usb_init_rfcsr(rt2x00dev))) + return -EIO; + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + udelay(50); + + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); + rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + + rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, ®); + rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); + /* Don't use bulk in aggregation when working with USB 1.1 */ + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, + (rt2x00dev->rx->usb_maxpacket == 512)); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); + /* FIXME: Calculate this value based on Aggregation defines */ + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_LIMIT, 21); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); + rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + /* + * Send signal to firmware during boot time. + */ + rt2800usb_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); + + /* + * Initialize LED control + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); + rt2800usb_mcu_request(rt2x00dev, MCU_LED_1, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); + rt2800usb_mcu_request(rt2x00dev, MCU_LED_2, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); + rt2800usb_mcu_request(rt2x00dev, MCU_LED_3, 0xff, + word & 0xff, (word >> 8) & 0xff); + + return 0; +} + +static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0); + rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2x00usb_register_write(rt2x00dev, TX_PIN_CFG, 0); + + /* Wait for DMA, ignore error */ + rt2800usb_wait_wpdma_ready(rt2x00dev); + + rt2x00usb_disable_radio(rt2x00dev); +} + +static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + + if (state == STATE_AWAKE) + rt2800usb_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); + else + rt2800usb_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + + return 0; +} + +static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + /* + * Before the radio can be enabled, the device first has + * to be woken up. After that it needs a bit of time + * to be fully awake and the radio can be enabled. + */ + rt2800usb_set_state(rt2x00dev, STATE_AWAKE); + msleep(1); + retval = rt2800usb_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + /* + * After the radio has been disablee, the device should + * be put to sleep for powersaving. + */ + rt2800usb_disable_radio(rt2x00dev); + rt2800usb_set_state(rt2x00dev, STATE_SLEEP); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_ON_LINK: + case STATE_RADIO_RX_OFF: + case STATE_RADIO_RX_OFF_LINK: + rt2800usb_toggle_rx(rt2x00dev, state); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: + /* No support, but no error either */ + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2800usb_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, + struct txentry_desc *txdesc) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + __le32 *txi = skbdesc->desc; + __le32 *txwi = &txi[TXINFO_DESC_SIZE / sizeof(__le32)]; + u32 word; + + /* + * Initialize TX Info descriptor + */ + rt2x00_desc_read(txwi, 0, &word); + rt2x00_set_field32(&word, TXWI_W0_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0); + rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); + rt2x00_set_field32(&word, TXWI_W0_TS, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_AMPDU, + test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density); + rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs); + rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs); + rt2x00_set_field32(&word, TXWI_W0_BW, + test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_SHORT_GI, + test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc); + rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); + rt2x00_desc_write(txwi, 0, word); + + rt2x00_desc_read(txwi, 1, &word); + rt2x00_set_field32(&word, TXWI_W1_ACK, + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W1_NSEQ, + test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); + rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, + test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? + txdesc->key_idx : 0xff); + rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, + skb->len - txdesc->l2pad); + rt2x00_set_field32(&word, TXWI_W1_PACKETID, + skbdesc->entry->entry_idx); + rt2x00_desc_write(txwi, 1, word); + + /* + * Always write 0 to IV/EIV fields, hardware will insert the IV + * from the IVEIV register when TXINFO_W0_WIV is set to 0. + * When TXINFO_W0_WIV is set to 1 it will use the IV data + * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which + * crypto entry in the registers should be used to encrypt the frame. + */ + _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); + _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); + + /* + * Initialize TX descriptor + */ + rt2x00_desc_read(txi, 0, &word); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, + skb->len + TXWI_DESC_SIZE); + rt2x00_set_field32(&word, TXINFO_W0_WIV, + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); + rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); + rt2x00_set_field32(&word, TXINFO_W0_SW_USE_LAST_ROUND, 0); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_NEXT_VALID, 0); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_BURST, + test_bit(ENTRY_TXD_BURST, &txdesc->flags)); + rt2x00_desc_write(txi, 0, word); +} + +/* + * TX data initialization + */ +static void rt2800usb_write_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + unsigned int beacon_base; + u32 reg; + + /* + * Add the descriptor in front of the skb. + */ + skb_push(entry->skb, entry->queue->desc_size); + memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len); + skbdesc->desc = entry->skb->data; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + /* + * Write entire beacon with descriptor to register. + */ + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, beacon_base, + entry->skb->data, entry->skb->len, + REGISTER_TIMEOUT32(entry->skb->len)); + + /* + * Clean up the beacon skb. + */ + dev_kfree_skb(entry->skb); + entry->skb = NULL; +} + +static int rt2800usb_get_tx_data_len(struct queue_entry *entry) +{ + int length; + + /* + * The length _must_ include 4 bytes padding, + * it should always be multiple of 4, + * but it must _not_ be a multiple of the USB packet size. + */ + length = roundup(entry->skb->len + 4, 4); + length += (4 * !(length % entry->queue->usb_maxpacket)); + + return length; +} + +static void rt2800usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid queue) +{ + u32 reg; + + if (queue != QID_BEACON) { + rt2x00usb_kick_tx_queue(rt2x00dev, queue); + return; + } + + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) { + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + } +} + +/* + * RX control handlers + */ +static void rt2800usb_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; + __le32 *rxwi; + u32 rxd0; + u32 rxwi0; + u32 rxwi1; + u32 rxwi2; + u32 rxwi3; + + /* + * Copy descriptor to the skbdesc->desc buffer, making it safe from + * moving of frame data in rt2x00usb. + */ + memcpy(skbdesc->desc, rxd, skbdesc->desc_len); + rxd = (__le32 *)skbdesc->desc; + rxwi = &rxd[RXD_DESC_SIZE / sizeof(__le32)]; + + /* + * It is now safe to read the descriptor on all architectures. + */ + rt2x00_desc_read(rxd, 0, &rxd0); + rt2x00_desc_read(rxwi, 0, &rxwi0); + rt2x00_desc_read(rxwi, 1, &rxwi1); + rt2x00_desc_read(rxwi, 2, &rxwi2); + rt2x00_desc_read(rxwi, 3, &rxwi3); + + if (rt2x00_get_field32(rxd0, 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(rxwi0, RXWI_W0_UDF); + rxdesc->cipher_status = + rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR); + } + + if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) { + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. Unfortunately the descriptor doesn't contain + * any fields with the EIV/IV data either, so they can't + * be restored by rt2x00lib. + */ + rxdesc->flags |= RX_FLAG_IV_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; + } + + if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; + + if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) + rxdesc->dev_flags |= RXDONE_L2PAD; + + if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) + rxdesc->flags |= RX_FLAG_SHORT_GI; + + if (rt2x00_get_field32(rxwi1, RXWI_W1_BW)) + rxdesc->flags |= RX_FLAG_40MHZ; + + /* + * Detect RX rate, always use MCS as signal type. + */ + rxdesc->dev_flags |= RXDONE_SIGNAL_MCS; + rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE); + rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS); + + /* + * Mask of 0x8 bit to remove the short preamble flag. + */ + if (rxdesc->rate_mode == RATE_MODE_CCK) + rxdesc->signal &= ~0x8; + + rxdesc->rssi = + (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) + + rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2; + + rxdesc->noise = + (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) + + rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2; + + rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT); + + /* + * Remove RXWI descriptor from start of buffer. + */ + skb_pull(entry->skb, skbdesc->desc_len); + skb_trim(entry->skb, rxdesc->size); +} + +/* + * Device probe functions. + */ +static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + u8 default_lna_gain; + + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + DECLARE_MAC_BUF(macbuf); + + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { + /* + * There is a max of 2 RX streams for RT2870 series + */ + if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if ((word & 0x00ff) == 0x00ff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, + LED_MODE_TXRX_ACTIVITY); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + /* + * During the LNA validation we are going to use + * lna0 as correct value. Note that EEPROM_LNA + * is never validated. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); + default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + + return 0; +} + +static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2870, value, reg); + + /* + * The check for rt2860 is not a typo, some rt2870 hardware + * identifies itself as rt2860 in the CSR register. + */ + if ((rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x2860) && + (rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x2870) && + (rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x3070)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + + if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && + !rt2x00_rf(&rt2x00dev->chip, RF2850) && + !rt2x00_rf(&rt2x00dev->chip, RF2720) && + !rt2x00_rf(&rt2x00dev->chip, RF2750) && + !rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF2020)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); + rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + /* + * Detect if this device has an hardware controlled radio. + */ +#ifdef CONFIG_RT2X00_LIB_RFKILL + if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + + /* + * Store led settings, for correct led behaviour. + */ +#ifdef CONFIG_RT2X00_LIB_LEDS + rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, + &rt2x00dev->led_mcu_reg); +#endif /* CONFIG_RT2X00_LIB_LEDS */ + + return 0; +} + +/* + * RF value list for rt2870 + * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) + */ +static const struct rf_channel rf_vals[] = { + { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, + { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, + { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, + { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, + { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, + { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, + { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, + { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, + { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, + { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, + { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, + { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, + { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, + { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, + { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, + { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, + { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, + { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, + { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, + { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, + { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, + { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, + { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, + { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, + { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, + + /* 802.11 HyperLan 2 */ + { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, + { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, + { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, + { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, + { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, + { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, + { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, + { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, + { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, + { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, + { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, + { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, + { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, + { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, + { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, + { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, + + /* 802.11 UNII */ + { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, + { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, + { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, + { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, + { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, + { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, + { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, + { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, + { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, + { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, + { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, + + /* 802.11 Japan */ + { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, + { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, + { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, + { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, + { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, + { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, + { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, +}; + +/* + * RF value list for rt3070 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_3070[] = { + {1, 241, 2, 2 }, + {2, 241, 2, 7 }, + {3, 242, 2, 2 }, + {4, 242, 2, 7 }, + {5, 243, 2, 2 }, + {6, 243, 2, 7 }, + {7, 244, 2, 2 }, + {8, 244, 2, 7 }, + {9, 245, 2, 2 }, + {10, 245, 2, 7 }, + {11, 246, 2, 2 }, + {12, 246, 2, 7 }, + {13, 247, 2, 2 }, + {14, 248, 2, 4 }, +}; + +static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + struct channel_info *info; + char *tx_power1; + char *tx_power2; + unsigned int i; + u16 eeprom; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK; + rt2x00dev->hw->extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE; + + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Initialize HT information. + */ + spec->ht.ht_supported = true; + spec->ht.cap = + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | + IEEE80211_HT_CAP_RX_STBC | + IEEE80211_HT_CAP_PSMP_SUPPORT; + spec->ht.ampdu_factor = 3; + spec->ht.ampdu_density = 4; + spec->ht.mcs.tx_params = + IEEE80211_HT_MCS_TX_DEFINED | + IEEE80211_HT_MCS_TX_RX_DIFF | + ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + + switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { + case 3: + spec->ht.mcs.rx_mask[2] = 0xff; + case 2: + spec->ht.mcs.rx_mask[1] = 0xff; + case 1: + spec->ht.mcs.rx_mask[0] = 0xff; + spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ + break; + } + + /* + * Initialize hw_mode information. + */ + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; + + if (rt2x00_rf(&rt2x00dev->chip, RF2820) || + rt2x00_rf(&rt2x00dev->chip, RF2720)) { + spec->num_channels = 14; + spec->channels = rf_vals; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || + rt2x00_rf(&rt2x00dev->chip, RF2750)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; + spec->num_channels = ARRAY_SIZE(rf_vals); + spec->channels = rf_vals; + } else if (rt2x00_rf(&rt2x00dev->chip, RF3020) || + rt2x00_rf(&rt2x00dev->chip, RF2020)) { + spec->num_channels = ARRAY_SIZE(rf_vals_3070); + spec->channels = rf_vals_3070; + } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + + for (i = 0; i < 14; i++) { + info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); + } + + if (spec->num_channels > 14) { + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + + for (i = 14; i < spec->num_channels; i++) { + info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); + } + } + + return 0; +} + +static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2800usb_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2800usb_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + retval = rt2800usb_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); + __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static void rt2800usb_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, + u32 *iv32, u16 *iv16) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + + offset = MAC_IVEIV_ENTRY(hw_key_idx); + rt2x00usb_register_multiread(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); + memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); +} + +static int rt2800usb_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); + + rt2x00usb_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); + rt2x00usb_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + return 0; +} + +static int rt2800usb_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; + u32 offset; + + /* + * 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; + + /* + * We only need to perform additional register initialization + * for WMM queues/ + */ + if (queue_idx >= 4) + return 0; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); + field.bit_offset = (queue_idx & 1) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt2x00usb_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt2x00usb_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt2x00usb_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt2x00usb_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); + + /* Update EDCA registers */ + offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); + rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + return 0; +} + +static u64 rt2800usb_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00usb_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; + rt2x00usb_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); + + return tsf; +} + +static const struct ieee80211_ops rt2800usb_mac80211_ops = { + .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, + .get_stats = rt2x00mac_get_stats, + .get_tkip_seq = rt2800usb_get_tkip_seq, + .set_rts_threshold = rt2800usb_set_rts_threshold, + .bss_info_changed = rt2x00mac_bss_info_changed, + .conf_tx = rt2800usb_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2800usb_get_tsf, +}; + +static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { + .probe_hw = rt2800usb_probe_hw, + .get_firmware_name = rt2800usb_get_firmware_name, + .check_firmware = rt2800usb_check_firmware, + .load_firmware = rt2800usb_load_firmware, + .initialize = rt2x00usb_initialize, + .uninitialize = rt2x00usb_uninitialize, + .clear_entry = rt2x00usb_clear_entry, + .set_device_state = rt2800usb_set_device_state, + .rfkill_poll = rt2800usb_rfkill_poll, + .link_stats = rt2800usb_link_stats, + .reset_tuner = rt2800usb_reset_tuner, + .link_tuner = rt2800usb_link_tuner, + .write_tx_desc = rt2800usb_write_tx_desc, + .write_tx_data = rt2x00usb_write_tx_data, + .write_beacon = rt2800usb_write_beacon, + .get_tx_data_len = rt2800usb_get_tx_data_len, + .kick_tx_queue = rt2800usb_kick_tx_queue, + .kill_tx_queue = rt2x00usb_kill_tx_queue, + .fill_rxdone = rt2800usb_fill_rxdone, + .config_shared_key = rt2800usb_config_shared_key, + .config_pairwise_key = rt2800usb_config_pairwise_key, + .config_filter = rt2800usb_config_filter, + .config_intf = rt2800usb_config_intf, + .config_erp = rt2800usb_config_erp, + .config_ant = rt2800usb_config_ant, + .config = rt2800usb_config, +}; + +static const struct data_queue_desc rt2800usb_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = AGGREGATION_SIZE, + .desc_size = RXD_DESC_SIZE + RXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; + +static const struct data_queue_desc rt2800usb_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = AGGREGATION_SIZE, + .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; + +static const struct data_queue_desc rt2800usb_queue_bcn = { + .entry_num = 8 * BEACON_ENTRIES, + .data_size = MGMT_FRAME_SIZE, + .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; + +static const struct rt2x00_ops rt2800usb_ops = { + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 8, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2800usb_queue_rx, + .tx = &rt2800usb_queue_tx, + .bcn = &rt2800usb_queue_bcn, + .lib = &rt2800usb_rt2x00_ops, + .hw = &rt2800usb_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2800usb_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt2800usb module information. + */ +static struct usb_device_id rt2800usb_device_table[] = { + /* ??? */ + { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Abocom */ + { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AirTies */ + { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Amigo */ + { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Amit */ + { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AzureWave */ + { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Buffalo */ + { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Corega */ + { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Edimax */ + { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* EnGenius */ + { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gemtek */ + { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Hawking */ + { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* LevelOne */ + { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Motorola */ + { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ovislink */ + { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Pegatron */ + { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Qcom */ + { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Quanta */ + { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Samsung */ + { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Siemens */ + { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* SMC */ + { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sparklan */ + { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* U-Media*/ + { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ZCOM */ + { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zyxel */ + { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2800 USB Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2870 USB chipset based cards"); +MODULE_DEVICE_TABLE(usb, rt2800usb_device_table); +MODULE_FIRMWARE(FIRMWARE_RT2870); +MODULE_LICENSE("GPL"); + +static struct usb_driver rt2800usb_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2800usb_device_table, + .probe = rt2x00usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +}; + +static int __init rt2800usb_init(void) +{ + return usb_register(&rt2800usb_driver); +} + +static void __exit rt2800usb_exit(void) +{ + usb_deregister(&rt2800usb_driver); +} + +module_init(rt2800usb_init); +module_exit(rt2800usb_exit); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h new file mode 100644 index 0000000..8e4291d --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -0,0 +1,1934 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + 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: rt2800usb + Abstract: Data structures and registers for the rt2800usb module. + Supported chipsets: RT2800U. + */ + +#ifndef RT2800USB_H +#define RT2800USB_H + +/* + * RF chip defines. + * + * RF2820 2.4G 2T3R + * RF2850 2.4G/5G 2T3R + * RF2720 2.4G 1T2R + * RF2750 2.4G/5G 1T2R + * RF3020 2.4G 1T1R + * RF2020 2.4G B/G + */ +#define RF2820 0x0001 +#define RF2850 0x0002 +#define RF2720 0x0003 +#define RF2750 0x0004 +#define RF3020 0x0005 +#define RF2020 0x0006 + +/* + * RT2870 version + */ +#define RT2860C_VERSION 0x28600100 +#define RT2860D_VERSION 0x28600101 +#define RT2880E_VERSION 0x28720200 +#define RT2883_VERSION 0x28830300 +#define RT3070_VERSION 0x30700200 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define DEFAULT_RSSI_OFFSET 120 /* FIXME */ + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x1000 +#define CSR_REG_SIZE 0x0800 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0110 +#define BBP_BASE 0x0000 +#define BBP_SIZE 0x0080 +#define RF_BASE 0x0004 +#define RF_SIZE 0x0010 + +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* + * USB registers. + */ + +/* + * HOST-MCU shared memory + */ +#define HOST_CMD_CSR 0x0404 +#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) + +/* + * INT_SOURCE_CSR: Interrupt source register. + * Write one to clear corresponding bit. + * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c + */ +#define INT_SOURCE_CSR 0x0200 +#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004) +#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800) +#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000) +#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. + */ +#define INT_MASK_CSR 0x0204 +#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004) +#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_MASK_CSR_TBTT FIELD32(0x00000800) +#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000) +#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * WPDMA_GLO_CFG + */ +#define WPDMA_GLO_CFG 0x0208 +#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001) +#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002) +#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004) +#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008) +#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030) +#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040) +#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080) +#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00) +#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000) + +/* + * WPDMA_RST_IDX + */ +#define WPDMA_RST_IDX 0x020c +#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001) +#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002) +#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004) +#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008) +#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010) +#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020) +#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000) + +/* + * DELAY_INT_CFG + */ +#define DELAY_INT_CFG 0x0210 +#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff) +#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00) +#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000) +#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000) +#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000) +#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000) + +/* + * WMM_AIFSN_CFG: Aifsn for each EDCA AC + * AIFSN0: AC_BE + * AIFSN1: AC_BK + * AIFSN1: AC_VI + * AIFSN1: AC_VO + */ +#define WMM_AIFSN_CFG 0x0214 +#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) +#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0) +#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00) +#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000) + +/* + * WMM_CWMIN_CSR: CWmin for each EDCA AC + * CWMIN0: AC_BE + * CWMIN1: AC_BK + * CWMIN1: AC_VI + * CWMIN1: AC_VO + */ +#define WMM_CWMIN_CFG 0x0218 +#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) +#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0) +#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00) +#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000) + +/* + * WMM_CWMAX_CSR: CWmax for each EDCA AC + * CWMAX0: AC_BE + * CWMAX1: AC_BK + * CWMAX1: AC_VI + * CWMAX1: AC_VO + */ +#define WMM_CWMAX_CFG 0x021c +#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) +#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0) +#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00) +#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000) + +/* + * AC_TXOP0: AC_BK/AC_BE TXOP register + * AC0TXOP: AC_BK in unit of 32us + * AC1TXOP: AC_BE in unit of 32us + */ +#define WMM_TXOP0_CFG 0x0220 +#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff) +#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000) + +/* + * AC_TXOP1: AC_VO/AC_VI TXOP register + * AC2TXOP: AC_VI in unit of 32us + * AC3TXOP: AC_VO in unit of 32us + */ +#define WMM_TXOP1_CFG 0x0224 +#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff) +#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) + +/* + * GPIO_CTRL_CFG: + */ +#define GPIO_CTRL_CFG 0x0228 +#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001) +#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002) +#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004) +#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008) +#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010) +#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020) +#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040) +#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080) +#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100) + +/* + * MCU_CMD_CFG + */ +#define MCU_CMD_CFG 0x022c + +/* + * AC_BK register offsets + */ +#define TX_BASE_PTR0 0x0230 +#define TX_MAX_CNT0 0x0234 +#define TX_CTX_IDX0 0x0238 +#define TX_DTX_IDX0 0x023c + +/* + * AC_BE register offsets + */ +#define TX_BASE_PTR1 0x0240 +#define TX_MAX_CNT1 0x0244 +#define TX_CTX_IDX1 0x0248 +#define TX_DTX_IDX1 0x024c + +/* + * AC_VI register offsets + */ +#define TX_BASE_PTR2 0x0250 +#define TX_MAX_CNT2 0x0254 +#define TX_CTX_IDX2 0x0258 +#define TX_DTX_IDX2 0x025c + +/* + * AC_VO register offsets + */ +#define TX_BASE_PTR3 0x0260 +#define TX_MAX_CNT3 0x0264 +#define TX_CTX_IDX3 0x0268 +#define TX_DTX_IDX3 0x026c + +/* + * HCCA register offsets + */ +#define TX_BASE_PTR4 0x0270 +#define TX_MAX_CNT4 0x0274 +#define TX_CTX_IDX4 0x0278 +#define TX_DTX_IDX4 0x027c + +/* + * MGMT register offsets + */ +#define TX_BASE_PTR5 0x0280 +#define TX_MAX_CNT5 0x0284 +#define TX_CTX_IDX5 0x0288 +#define TX_DTX_IDX5 0x028c + +/* + * RX register offsets + */ +#define RX_BASE_PTR 0x0290 +#define RX_MAX_CNT 0x0294 +#define RX_CRX_IDX 0x0298 +#define RX_DRX_IDX 0x029c + +/* + * USB_DMA_CFG + * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns. + * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes. + * PHY_CLEAR: phy watch dog enable. + * TX_CLEAR: Clear USB DMA TX path. + * TXOP_HALT: Halt TXOP count down when TX buffer is full. + * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation. + * RX_BULK_EN: Enable USB DMA Rx. + * TX_BULK_EN: Enable USB DMA Tx. + * EP_OUT_VALID: OUT endpoint data valid. + * RX_BUSY: USB DMA RX FSM busy. + * TX_BUSY: USB DMA TX FSM busy. + */ +#define USB_DMA_CFG 0x02a0 +#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff) +#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00) +#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000) +#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000) +#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000) +#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000) +#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000) +#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000) +#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000) +#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000) +#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000) + +/* + * USB_CYC_CFG + */ +#define USB_CYC_CFG 0x02a4 +#define USB_CYC_CFG_CLOCK_CYCLE FIELD32(0x000000ff) + +/* + * PBF_SYS_CTRL + * HOST_RAM_WRITE: enable Host program ram write selection + */ +#define PBF_SYS_CTRL 0x0400 +#define PBF_SYS_CTRL_READY FIELD32(0x00000080) +#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define PBF_CFG 0x0408 +#define PBF_MAX_PCNT 0x040c +#define PBF_CTRL 0x0410 +#define PBF_INT_STA 0x0414 +#define PBF_INT_ENA 0x0418 + +/* + * BCN_OFFSET0: + */ +#define BCN_OFFSET0 0x042c +#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff) +#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00) +#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000) +#define BCN_OFFSET0_BCN3 FIELD32(0xff000000) + +/* + * BCN_OFFSET1: + */ +#define BCN_OFFSET1 0x0430 +#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff) +#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00) +#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000) +#define BCN_OFFSET1_BCN7 FIELD32(0xff000000) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define TXRXQ_PCNT 0x0438 +#define PBF_DBG 0x043c + +/* + * RF registers + */ +#define RF_CSR_CFG 0x0500 +#define RF_CSR_CFG_DATA FIELD32(0x000000ff) +#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00) +#define RF_CSR_CFG_WRITE FIELD32(0x00010000) +#define RF_CSR_CFG_BUSY FIELD32(0x00020000) + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + * ASIC_REV: 0 + * ASIC_VER: 2870 + */ +#define MAC_CSR0 0x1000 +#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) +#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) + +/* + * MAC_SYS_CTRL: + */ +#define MAC_SYS_CTRL 0x1004 +#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001) +#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002) +#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004) +#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008) +#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010) +#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020) +#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040) +#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080) + +/* + * MAC_ADDR_DW0: STA MAC register 0 + */ +#define MAC_ADDR_DW0 0x1008 +#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_ADDR_DW1: STA MAC register 1 + * UNICAST_TO_ME_MASK: + * Used to mask off bits from byte 5 of the MAC address + * to determine the UNICAST_TO_ME bit for RX frames. + * The full mask is complemented by BSS_ID_MASK: + * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK + */ +#define MAC_ADDR_DW1 0x100c +#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_BSSID_DW0: BSSID register 0 + */ +#define MAC_BSSID_DW0 0x1010 +#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_BSSID_DW1: BSSID register 1 + * BSS_ID_MASK: + * 0: 1-BSSID mode (BSS index = 0) + * 1: 2-BSSID mode (BSS index: Byte5, bit 0) + * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1) + * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2) + * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the + * BSSID. This will make sure that those bits will be ignored + * when determining the MY_BSS of RX frames. + */ +#define MAC_BSSID_DW1 0x1014 +#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000) +#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000) + +/* + * MAX_LEN_CFG: Maximum frame length register. + * MAX_MPDU: rt2860b max 16k bytes + * MAX_PSDU: Maximum PSDU length + * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 + */ +#define MAX_LEN_CFG 0x1018 +#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff) +#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000) +#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000) +#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000) + +/* + * BBP_CSR_CFG: BBP serial control register + * VALUE: Register value to program into BBP + * REG_NUM: Selected BBP register + * READ_CONTROL: 0 write BBP, 1 read BBP + * BUSY: ASIC is busy executing BBP commands + * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks + * BBP_RW_MODE: 0 serial, 1 paralell + */ +#define BBP_CSR_CFG 0x101c +#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff) +#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00) +#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000) +#define BBP_CSR_CFG_BUSY FIELD32(0x00020000) +#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000) +#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000) + +/* + * RF_CSR_CFG0: RF control register + * REGID_AND_VALUE: Register value to program into RF + * BITWIDTH: Selected RF register + * STANDBYMODE: 0 high when standby, 1 low when standby + * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate + * BUSY: ASIC is busy executing RF commands + */ +#define RF_CSR_CFG0 0x1020 +#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000) +#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff) +#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000) +#define RF_CSR_CFG0_SEL FIELD32(0x40000000) +#define RF_CSR_CFG0_BUSY FIELD32(0x80000000) + +/* + * RF_CSR_CFG1: RF control register + * REGID_AND_VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG1 0x1024 +#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000) + +/* + * RF_CSR_CFG2: RF control register + * VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG2 0x1028 +#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff) + +/* + * LED_CFG: LED control + * color LED's: + * 0: off + * 1: blinking upon TX2 + * 2: periodic slow blinking + * 3: always on + * LED polarity: + * 0: active low + * 1: active high + */ +#define LED_CFG 0x102c +#define LED_CFG_ON_PERIOD FIELD32(0x000000ff) +#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00) +#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000) +#define LED_CFG_R_LED_MODE FIELD32(0x03000000) +#define LED_CFG_G_LED_MODE FIELD32(0x0c000000) +#define LED_CFG_Y_LED_MODE FIELD32(0x30000000) +#define LED_CFG_LED_POLAR FIELD32(0x40000000) + +/* + * XIFS_TIME_CFG: MAC timing + * CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX + * OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX + * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX + * when MAC doesn't reference BBP signal BBRXEND + * EIFS: unit 1us + * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer + * + */ +#define XIFS_TIME_CFG 0x1100 +#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff) +#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00) +#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000) +#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000) +#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000) + +/* + * BKOFF_SLOT_CFG: + */ +#define BKOFF_SLOT_CFG 0x1104 +#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff) +#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00) + +/* + * NAV_TIME_CFG: + */ +#define NAV_TIME_CFG 0x1108 +#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff) +#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00) +#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000) +#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000) + +/* + * CH_TIME_CFG: count as channel busy + */ +#define CH_TIME_CFG 0x110c + +/* + * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us + */ +#define PBF_LIFE_TIMER 0x1110 + +/* + * BCN_TIME_CFG: + * BEACON_INTERVAL: in unit of 1/16 TU + * TSF_TICKING: Enable TSF auto counting + * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode + * BEACON_GEN: Enable beacon generator + */ +#define BCN_TIME_CFG 0x1114 +#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff) +#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000) +#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000) +#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000) +#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000) +#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000) + +/* + * TBTT_SYNC_CFG: + */ +#define TBTT_SYNC_CFG 0x1118 + +/* + * TSF_TIMER_DW0: Local lsb TSF timer, read-only + */ +#define TSF_TIMER_DW0 0x111c +#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff) + +/* + * TSF_TIMER_DW1: Local msb TSF timer, read-only + */ +#define TSF_TIMER_DW1 0x1120 +#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff) + +/* + * TBTT_TIMER: TImer remains till next TBTT, read-only + */ +#define TBTT_TIMER 0x1124 + +/* + * INT_TIMER_CFG: + */ +#define INT_TIMER_CFG 0x1128 + +/* + * INT_TIMER_EN: GP-timer and pre-tbtt Int enable + */ +#define INT_TIMER_EN 0x112c + +/* + * CH_IDLE_STA: channel idle time + */ +#define CH_IDLE_STA 0x1130 + +/* + * CH_BUSY_STA: channel busy time + */ +#define CH_BUSY_STA 0x1134 + +/* + * MAC_STATUS_CFG: + * BBP_RF_BUSY: When set to 0, BBP and RF are stable. + * if 1 or higher one of the 2 registers is busy. + */ +#define MAC_STATUS_CFG 0x1200 +#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003) + +/* + * PWR_PIN_CFG: + */ +#define PWR_PIN_CFG 0x1204 + +/* + * AUTOWAKEUP_CFG: Manual power control / status register + * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set + * AUTOWAKE: 0:sleep, 1:awake + */ +#define AUTOWAKEUP_CFG 0x1208 +#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff) +#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00) +#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000) + +/* + * EDCA_AC0_CFG: + */ +#define EDCA_AC0_CFG 0x1300 +#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC1_CFG: + */ +#define EDCA_AC1_CFG 0x1304 +#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC2_CFG: + */ +#define EDCA_AC2_CFG 0x1308 +#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC3_CFG: + */ +#define EDCA_AC3_CFG 0x130c +#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_TID_AC_MAP: + */ +#define EDCA_TID_AC_MAP 0x1310 + +/* + * TX_PWR_CFG_0: + */ +#define TX_PWR_CFG_0 0x1314 +#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000) +#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000) +#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000) +#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_1: + */ +#define TX_PWR_CFG_1 0x1318 +#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000) +#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000) +#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000) +#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_2: + */ +#define TX_PWR_CFG_2 0x131c +#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f) +#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0) +#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00) +#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000) +#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000) +#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000) +#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000) +#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_3: + */ +#define TX_PWR_CFG_3 0x1320 +#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f) +#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0) +#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00) +#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000) +#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000) +#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) +#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) +#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_4: + */ +#define TX_PWR_CFG_4 0x1324 +#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f) +#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) +#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) +#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) + +/* + * TX_PIN_CFG: + */ +#define TX_PIN_CFG 0x1328 +#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) +#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) +#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) +#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008) +#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010) +#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020) +#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040) +#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080) +#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100) +#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200) +#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400) +#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800) +#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000) +#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000) +#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000) +#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000) +#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000) +#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) +#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) +#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) + +/* + * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz + */ +#define TX_BAND_CFG 0x132c +#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001) +#define TX_BAND_CFG_A FIELD32(0x00000002) +#define TX_BAND_CFG_BG FIELD32(0x00000004) + +/* + * TX_SW_CFG0: + */ +#define TX_SW_CFG0 0x1330 + +/* + * TX_SW_CFG1: + */ +#define TX_SW_CFG1 0x1334 + +/* + * TX_SW_CFG2: + */ +#define TX_SW_CFG2 0x1338 + +/* + * TXOP_THRES_CFG: + */ +#define TXOP_THRES_CFG 0x133c + +/* + * TXOP_CTRL_CFG: + */ +#define TXOP_CTRL_CFG 0x1340 + +/* + * TX_RTS_CFG: + * RTS_THRES: unit:byte + * RTS_FBK_EN: enable rts rate fallback + */ +#define TX_RTS_CFG 0x1344 +#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff) +#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00) +#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000) + +/* + * TX_TIMEOUT_CFG: + * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us + * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure + * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation. + * it is recommended that: + * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) + */ +#define TX_TIMEOUT_CFG 0x1348 +#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0) +#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00) +#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000) + +/* + * TX_RTY_CFG: + * SHORT_RTY_LIMIT: short retry limit + * LONG_RTY_LIMIT: long retry limit + * LONG_RTY_THRE: Long retry threshoold + * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * AGG_RTY_MODE: Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable + */ +#define TX_RTY_CFG 0x134c +#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff) +#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00) +#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000) +#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000) +#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000) +#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000) + +/* + * TX_LINK_CFG: + * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us + * MFB_ENABLE: TX apply remote MFB 1:enable + * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable + * 0: not apply remote remote unsolicit (MFS=7) + * TX_MRQ_EN: MCS request TX enable + * TX_RDG_EN: RDG TX enable + * TX_CF_ACK_EN: Piggyback CF-ACK enable + * REMOTE_MFB: remote MCS feedback + * REMOTE_MFS: remote MCS feedback sequence number + */ +#define TX_LINK_CFG 0x1350 +#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff) +#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100) +#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200) +#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400) +#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800) +#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000) +#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000) +#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000) + +/* + * HT_FBK_CFG0: + */ +#define HT_FBK_CFG0 0x1354 +#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f) +#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0) +#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00) +#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000) +#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000) +#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000) +#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000) +#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000) + +/* + * HT_FBK_CFG1: + */ +#define HT_FBK_CFG1 0x1358 +#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f) +#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0) +#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00) +#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000) +#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000) +#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000) +#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000) +#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG0: + */ +#define LG_FBK_CFG0 0x135c +#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000) +#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000) +#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000) +#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000) +#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG1: + */ +#define LG_FBK_CFG1 0x1360 +#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000) + +/* + * CCK_PROT_CFG: CCK Protection + * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd) + * PROTECT_CTRL: Protection control frame type for CCK TX + * 0:none, 1:RTS/CTS, 2:CTS-to-self + * PROTECT_NAV: TXOP protection type for CCK TX + * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect + * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow + * RTS_TH_EN: RTS threshold enable on CCK TX + */ +#define CCK_PROT_CFG 0x1364 +#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * OFDM_PROT_CFG: OFDM Protection + */ +#define OFDM_PROT_CFG 0x1368 +#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM20_PROT_CFG: MM20 Protection + */ +#define MM20_PROT_CFG 0x136c +#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM40_PROT_CFG: MM40 Protection + */ +#define MM40_PROT_CFG 0x1370 +#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF20_PROT_CFG: GF20 Protection + */ +#define GF20_PROT_CFG 0x1374 +#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF40_PROT_CFG: GF40 Protection + */ +#define GF40_PROT_CFG 0x1378 +#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * EXP_CTS_TIME: + */ +#define EXP_CTS_TIME 0x137c + +/* + * EXP_ACK_TIME: + */ +#define EXP_ACK_TIME 0x1380 + +/* + * RX_FILTER_CFG: RX configuration register. + */ +#define RX_FILTER_CFG 0x1400 +#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001) +#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002) +#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004) +#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008) +#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010) +#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020) +#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040) +#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080) +#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100) +#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200) +#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400) +#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800) +#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000) +#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000) +#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000) +#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000) +#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000) + +/* + * AUTO_RSP_CFG: + * AUTORESPONDER: 0: disable, 1: enable + * BAC_ACK_POLICY: 0:long, 1:short preamble + * CTS_40_MMODE: Response CTS 40MHz duplicate mode + * CTS_40_MREF: Response CTS 40MHz duplicate mode + * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble + * DUAL_CTS_EN: Power bit value in control frame + * ACK_CTS_PSM_BIT:Power bit value in control frame + */ +#define AUTO_RSP_CFG 0x1404 +#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001) +#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002) +#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004) +#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008) +#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010) +#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040) +#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080) + +/* + * LEGACY_BASIC_RATE: + */ +#define LEGACY_BASIC_RATE 0x1408 + +/* + * HT_BASIC_RATE: + */ +#define HT_BASIC_RATE 0x140c + +/* + * HT_CTRL_CFG: + */ +#define HT_CTRL_CFG 0x1410 + +/* + * SIFS_COST_CFG: + */ +#define SIFS_COST_CFG 0x1414 + +/* + * RX_PARSER_CFG: + * Set NAV for all received frames + */ +#define RX_PARSER_CFG 0x1418 + +/* + * TX_SEC_CNT0: + */ +#define TX_SEC_CNT0 0x1500 + +/* + * RX_SEC_CNT0: + */ +#define RX_SEC_CNT0 0x1504 + +/* + * CCMP_FC_MUTE: + */ +#define CCMP_FC_MUTE 0x1508 + +/* + * TXOP_HLDR_ADDR0: + */ +#define TXOP_HLDR_ADDR0 0x1600 + +/* + * TXOP_HLDR_ADDR1: + */ +#define TXOP_HLDR_ADDR1 0x1604 + +/* + * TXOP_HLDR_ET: + */ +#define TXOP_HLDR_ET 0x1608 + +/* + * QOS_CFPOLL_RA_DW0: + */ +#define QOS_CFPOLL_RA_DW0 0x160c + +/* + * QOS_CFPOLL_RA_DW1: + */ +#define QOS_CFPOLL_RA_DW1 0x1610 + +/* + * QOS_CFPOLL_QC: + */ +#define QOS_CFPOLL_QC 0x1614 + +/* + * RX_STA_CNT0: RX PLCP error count & RX CRC error count + */ +#define RX_STA_CNT0 0x1700 +#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff) +#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT1: RX False CCA count & RX LONG frame count + */ +#define RX_STA_CNT1 0x1704 +#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff) +#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT2: + */ +#define RX_STA_CNT2 0x1708 +#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff) +#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000) + +/* + * TX_STA_CNT0: TX Beacon count + */ +#define TX_STA_CNT0 0x170c +#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_CNT1: TX tx count + */ +#define TX_STA_CNT1 0x1710 +#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff) +#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000) + +/* + * TX_STA_CNT2: TX tx count + */ +#define TX_STA_CNT2 0x1714 +#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_FIFO: TX Result for specific PID status fifo register + */ +#define TX_STA_FIFO 0x1718 +#define TX_STA_FIFO_VALID FIELD32(0x00000001) +#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) +#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) +#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) +#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080) +#define TX_STA_FIFO_WCID FIELD32(0x0000ff00) +#define TX_STA_FIFO_SUCCESS_RATE FIELD32(0xffff0000) + +/* + * TX_AGG_CNT: Debug counter + */ +#define TX_AGG_CNT 0x171c +#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT0: + */ +#define TX_AGG_CNT0 0x1720 +#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT1: + */ +#define TX_AGG_CNT1 0x1724 +#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT2: + */ +#define TX_AGG_CNT2 0x1728 +#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT3: + */ +#define TX_AGG_CNT3 0x172c +#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT4: + */ +#define TX_AGG_CNT4 0x1730 +#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT5: + */ +#define TX_AGG_CNT5 0x1734 +#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT6: + */ +#define TX_AGG_CNT6 0x1738 +#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT7: + */ +#define TX_AGG_CNT7 0x173c +#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000) + +/* + * MPDU_DENSITY_CNT: + * TX_ZERO_DEL: TX zero length delimiter count + * RX_ZERO_DEL: RX zero length delimiter count + */ +#define MPDU_DENSITY_CNT 0x1740 +#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff) +#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000) + +/* + * Security key table memory. + * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry + * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry + * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry + * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry + * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry + * SHARED_KEY_MODE_BASE: 4-byte * 16-entry + */ +#define MAC_WCID_BASE 0x1800 +#define PAIRWISE_KEY_TABLE_BASE 0x4000 +#define MAC_IVEIV_TABLE_BASE 0x6000 +#define MAC_WCID_ATTRIBUTE_BASE 0x6800 +#define SHARED_KEY_TABLE_BASE 0x6c00 +#define SHARED_KEY_MODE_BASE 0x7000 + +#define MAC_WCID_ENTRY(__idx) \ + ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define MAC_IVEIV_ENTRY(__idx) \ + ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) +#define MAC_WCID_ATTR_ENTRY(__idx) \ + ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define SHARED_KEY_MODE_ENTRY(__idx) \ + ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) + +struct mac_wcid_entry { + u8 mac[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct mac_iveiv_entry { + u8 iv[8]; +} __attribute__ ((packed)); + +/* + * MAC_WCID_ATTRIBUTE: + */ +#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001) +#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e) +#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070) +#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380) + +/* + * SHARED_KEY_MODE: + */ +#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007) +#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070) +#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700) +#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000) +#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000) +#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000) +#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000) +#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000) + +/* + * HOST-MCU communication + */ + +/* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. + */ +#define H2M_MAILBOX_CSR 0x7010 +#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) +#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) + +/* + * H2M_MAILBOX_CID: + */ +#define H2M_MAILBOX_CID 0x7014 + +/* + * H2M_MAILBOX_STATUS: + */ +#define H2M_MAILBOX_STATUS 0x701c + +/* + * H2M_INT_SRC: + */ +#define H2M_INT_SRC 0x7024 + +/* + * H2M_BBP_AGENT: + */ +#define H2M_BBP_AGENT 0x7028 + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD8(0x1f) +#define MCU_LEDCS_POLARITY FIELD8(0x01) + +/* + * HW_CS_CTS_BASE: + * Carrier-sense CTS frame base address. + * It's where mac stores carrier-sense frame for carrier-sense function. + */ +#define HW_CS_CTS_BASE 0x7700 + +/* + * HW_DFS_CTS_BASE: + * FS CTS frame base address. It's where mac stores CTS frame for DFS. + */ +#define HW_DFS_CTS_BASE 0x7780 + +/* + * TXRX control registers - base address 0x3000 + */ + +/* + * TXRX_CSR1: + * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. + */ +#define TXRX_CSR1 0x77d0 + +/* + * HW_DEBUG_SETTING_BASE: + * since NULL frame won't be that long (256 byte) + * We steal 16 tail bytes to save debugging settings + */ +#define HW_DEBUG_SETTING_BASE 0x77f0 +#define HW_DEBUG_SETTING_BASE2 0x7770 + +/* + * HW_BEACON_BASE + * In order to support maximum 8 MBSS and its maximum length + * is 512 bytes for each beacon + * Three section discontinue memory segments will be used. + * 1. The original region for BCN 0~3 + * 2. Extract memory from FCE table for BCN 4~5 + * 3. Extract memory from Pair-wise key table for BCN 6~7 + * It occupied those memory of wcid 238~253 for BCN 6 + * and wcid 222~237 for BCN 7 + * + * IMPORTANT NOTE: Not sure why legacy driver does this, + * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6. + */ +#define HW_BEACON_BASE0 0x7800 +#define HW_BEACON_BASE1 0x7a00 +#define HW_BEACON_BASE2 0x7c00 +#define HW_BEACON_BASE3 0x7e00 +#define HW_BEACON_BASE4 0x7200 +#define HW_BEACON_BASE5 0x7400 +#define HW_BEACON_BASE6 0x5dc0 +#define HW_BEACON_BASE7 0x5bc0 + +#define HW_BEACON_OFFSET(__index) \ + ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \ + (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \ + (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) ) + +/* + * 8051 firmware image. + */ +#define FIRMWARE_RT2870 "rt2870.bin" +#define FIRMWARE_IMAGE_BASE 0x3000 + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * BBP 1: TX Antenna + */ +#define BBP1_TX_POWER FIELD8(0x07) +#define BBP1_TX_ANTENNA FIELD8(0x18) + +/* + * BBP 3: RX Antenna + */ +#define BBP3_RX_ANTENNA FIELD8(0x18) +#define BBP3_HT40_PLUS FIELD8(0x20) + +/* + * BBP 4: Bandwidth + */ +#define BBP4_TX_BF FIELD8(0x01) +#define BBP4_BANDWIDTH FIELD8(0x18) + +/* + * RFCSR registers + * The wordsize of the RFCSR is 8 bits. + */ + +/* + * RFCSR 6: + */ +#define RFCSR6_R FIELD8(0x03) + +/* + * RFCSR 7: + */ +#define RFCSR7_RF_TUNING FIELD8(0x01) + +/* + * RFCSR 12: + */ +#define RFCSR12_TX_POWER FIELD8(0x1f) + +/* + * RFCSR 22: + */ +#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01) + +/* + * RFCSR 23: + */ +#define RFCSR23_FREQ_OFFSET FIELD8(0x7f) + +/* + * RFCSR 30: + */ +#define RFCSR30_RF_CALIBRATION FIELD8(0x80) + +/* + * RF registers + */ + +/* + * RF 2 + */ +#define RF2_ANTENNA_RX2 FIELD32(0x00000040) +#define RF2_ANTENNA_TX1 FIELD32(0x00004000) +#define RF2_ANTENNA_RX1 FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TXPOWER_G FIELD32(0x00003e00) +#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200) +#define RF3_TXPOWER_A FIELD32(0x00003c00) + +/* + * RF 4 + */ +#define RF4_TXPOWER_G FIELD32(0x000007c0) +#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040) +#define RF4_TXPOWER_A FIELD32(0x00000780) +#define RF4_FREQ_OFFSET FIELD32(0x001f8000) +#define RF4_HT40 FIELD32(0x00200000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * EEPROM Version + */ +#define EEPROM_VERSION 0x0001 +#define EEPROM_VERSION_FAE FIELD16(0x00ff) +#define EEPROM_VERSION_VERSION FIELD16(0xff00) + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM ANTENNA config + * RXPATH: 1: 1R, 2: 2R, 3: 3R + * TXPATH: 1: 1T, 2: 2T + */ +#define EEPROM_ANTENNA 0x001a +#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f) +#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00) + +/* + * EEPROM NIC config + * CARDBUS_ACCEL: 0 - enable, 1 - disable + */ +#define EEPROM_NIC 0x001b +#define EEPROM_NIC_HW_RADIO FIELD16(0x0001) +#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002) +#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004) +#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008) +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010) +#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020) +#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040) +#define EEPROM_NIC_WPS_PBC FIELD16(0x0080) +#define EEPROM_NIC_BW40M_BG FIELD16(0x0100) +#define EEPROM_NIC_BW40M_A FIELD16(0x0200) + +/* + * EEPROM frequency + */ +#define EEPROM_FREQ 0x001d +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00) +#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000) + +/* + * EEPROM LED + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED1 0x001e +#define EEPROM_LED2 0x001f +#define EEPROM_LED3 0x0020 +#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM LNA + */ +#define EEPROM_LNA 0x0022 +#define EEPROM_LNA_BG FIELD16(0x00ff) +#define EEPROM_LNA_A0 FIELD16(0xff00) + +/* + * EEPROM RSSI BG offset + */ +#define EEPROM_RSSI_BG 0x0023 +#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI BG2 offset + */ +#define EEPROM_RSSI_BG2 0x0024 +#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00) + +/* + * EEPROM RSSI A offset + */ +#define EEPROM_RSSI_A 0x0025 +#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI A2 offset + */ +#define EEPROM_RSSI_A2 0x0026 +#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) + +/* + * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. + * This is delta in 40MHZ. + * VALUE: Tx Power dalta value (MAX=4) + * TYPE: 1: Plus the delta value, 0: minus the delta value + * TXPOWER: Enable: + */ +#define EEPROM_TXPOWER_DELTA 0x0028 +#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f) +#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040) +#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080) + +/* + * EEPROM TXPOWER 802.11BG + */ +#define EEPROM_TXPOWER_BG1 0x0029 +#define EEPROM_TXPOWER_BG2 0x0030 +#define EEPROM_TXPOWER_BG_SIZE 7 +#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A1 0x003c +#define EEPROM_TXPOWER_A2 0x0053 +#define EEPROM_TXPOWER_A_SIZE 6 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM TXpower byrate: 20MHZ power + */ +#define EEPROM_TXPOWER_BYRATE 0x006f + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0078 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * MCU mailbox commands. + */ +#define MCU_SLEEP 0x30 +#define MCU_WAKEUP 0x31 +#define MCU_RADIO_OFF 0x35 +#define MCU_LED 0x50 +#define MCU_LED_STRENGTH 0x51 +#define MCU_LED_1 0x52 +#define MCU_LED_2 0x53 +#define MCU_LED_3 0x54 +#define MCU_RADAR 0x60 +#define MCU_BOOT_SIGNAL 0x72 +#define MCU_BBP_SIGNAL 0x80 + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 4 * sizeof(__le32) ) +#define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) +#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 1 * sizeof(__le32) ) +#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) + +/* + * TX descriptor format for TX, PRIO and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_SD_PTR0 FIELD32(0xffffffff) + +/* + * Word1 + */ +#define TXD_W1_SD_LEN1 FIELD32(0x00003fff) +#define TXD_W1_LAST_SEC1 FIELD32(0x00004000) +#define TXD_W1_BURST FIELD32(0x00008000) +#define TXD_W1_SD_LEN0 FIELD32(0x3fff0000) +#define TXD_W1_LAST_SEC0 FIELD32(0x40000000) +#define TXD_W1_DMA_DONE FIELD32(0x80000000) + +/* + * Word2 + */ +#define TXD_W2_SD_PTR1 FIELD32(0xffffffff) + +/* + * Word3 + * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI + * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler. + * 0:MGMT, 1:HCCA 2:EDCA + */ +#define TXD_W3_WIV FIELD32(0x01000000) +#define TXD_W3_QSEL FIELD32(0x06000000) +#define TXD_W3_TCO FIELD32(0x20000000) +#define TXD_W3_UCO FIELD32(0x40000000) +#define TXD_W3_ICO FIELD32(0x80000000) + +/* + * TX Info structure + */ + +/* + * Word0 + * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI + * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler. + * 0:MGMT, 1:HCCA 2:EDCA + * USB_DMA_NEXT_VALID: Used ONLY in USB bulk Aggregation, NextValid + * DMA_TX_BURST: used ONLY in USB bulk Aggregation. + * Force USB DMA transmit frame from current selected endpoint + */ +#define TXINFO_W0_USB_DMA_TX_PKT_LEN FIELD32(0x0000ffff) +#define TXINFO_W0_WIV FIELD32(0x01000000) +#define TXINFO_W0_QSEL FIELD32(0x06000000) +#define TXINFO_W0_SW_USE_LAST_ROUND FIELD32(0x08000000) +#define TXINFO_W0_USB_DMA_NEXT_VALID FIELD32(0x40000000) +#define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000) + +/* + * TX WI structure + */ + +/* + * Word0 + * FRAG: 1 To inform TKIP engine this is a fragment. + * MIMO_PS: The remote peer is in dynamic MIMO-PS mode + * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs + * BW: Channel bandwidth 20MHz or 40 MHz + * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED + */ +#define TXWI_W0_FRAG FIELD32(0x00000001) +#define TXWI_W0_MIMO_PS FIELD32(0x00000002) +#define TXWI_W0_CF_ACK FIELD32(0x00000004) +#define TXWI_W0_TS FIELD32(0x00000008) +#define TXWI_W0_AMPDU FIELD32(0x00000010) +#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0) +#define TXWI_W0_TX_OP FIELD32(0x00000300) +#define TXWI_W0_MCS FIELD32(0x007f0000) +#define TXWI_W0_BW FIELD32(0x00800000) +#define TXWI_W0_SHORT_GI FIELD32(0x01000000) +#define TXWI_W0_STBC FIELD32(0x06000000) +#define TXWI_W0_IFS FIELD32(0x08000000) +#define TXWI_W0_PHYMODE FIELD32(0xc0000000) + +/* + * Word1 + */ +#define TXWI_W1_ACK FIELD32(0x00000001) +#define TXWI_W1_NSEQ FIELD32(0x00000002) +#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc) +#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00) +#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define TXWI_W1_PACKETID FIELD32(0xf0000000) + +/* + * Word2 + */ +#define TXWI_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + */ +#define TXWI_W3_EIV FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + * UNICAST_TO_ME: This RX frame is unicast to me. + * MULTICAST: This is a multicast frame. + * BROADCAST: This is a broadcast frame. + * MY_BSS: this frame belongs to the same BSSID. + * CRC_ERROR: CRC error. + * CIPHER_ERROR: 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid. + * AMSDU: rx with 802.3 header, not 802.11 header. + */ + +#define RXD_W0_BA FIELD32(0x00000001) +#define RXD_W0_DATA FIELD32(0x00000002) +#define RXD_W0_NULLDATA FIELD32(0x00000004) +#define RXD_W0_FRAG FIELD32(0x00000008) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010) +#define RXD_W0_MULTICAST FIELD32(0x00000020) +#define RXD_W0_BROADCAST FIELD32(0x00000040) +#define RXD_W0_MY_BSS FIELD32(0x00000080) +#define RXD_W0_CRC_ERROR FIELD32(0x00000100) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600) +#define RXD_W0_AMSDU FIELD32(0x00000800) +#define RXD_W0_HTC FIELD32(0x00001000) +#define RXD_W0_RSSI FIELD32(0x00002000) +#define RXD_W0_L2PAD FIELD32(0x00004000) +#define RXD_W0_AMPDU FIELD32(0x00008000) +#define RXD_W0_DECRYPTED FIELD32(0x00010000) +#define RXD_W0_PLCP_RSSI FIELD32(0x00020000) +#define RXD_W0_CIPHER_ALG FIELD32(0x00040000) +#define RXD_W0_LAST_AMSDU FIELD32(0x00080000) +#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000) + +/* + * RX WI structure + */ + +/* + * Word0 + */ +#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) +#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) +#define RXWI_W0_BSSID FIELD32(0x00001c00) +#define RXWI_W0_UDF FIELD32(0x0000e000) +#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define RXWI_W0_TID FIELD32(0xf0000000) + +/* + * Word1 + */ +#define RXWI_W1_FRAG FIELD32(0x0000000f) +#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) +#define RXWI_W1_MCS FIELD32(0x007f0000) +#define RXWI_W1_BW FIELD32(0x00800000) +#define RXWI_W1_SHORT_GI FIELD32(0x01000000) +#define RXWI_W1_STBC FIELD32(0x06000000) +#define RXWI_W1_PHYMODE FIELD32(0xc0000000) + +/* + * Word2 + */ +#define RXWI_W2_RSSI0 FIELD32(0x000000ff) +#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) +#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) + +/* + * Word3 + */ +#define RXWI_W3_SNR0 FIELD32(0x000000ff) +#define RXWI_W3_SNR1 FIELD32(0x0000ff00) + +/* + * Macro's for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. + */ +#define MIN_G_TXPOWER 0 +#define MIN_A_TXPOWER -7 +#define MAX_G_TXPOWER 31 +#define MAX_A_TXPOWER 15 +#define DEFAULT_TXPOWER 5 + +#define TXPOWER_G_FROM_DEV(__txpower) \ + ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_G_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER) + +#define TXPOWER_A_FROM_DEV(__txpower) \ + ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_A_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER) + +#endif /* RT2800USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ebe5f27..8d933ee 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -147,6 +147,7 @@ struct rt2x00_chip { #define RT2561 0x0302 #define RT2661 0x0401 #define RT2571 0x1300 +#define RT2870 0x1600 u16 rf; u32 rev; -- cgit v0.10.2 From 2f01a1f58889fbfeb68b1bc1b52e4197f3333490 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 29 Apr 2009 23:33:31 +0300 Subject: wl12xx: add driver wl12xx is a driver for TI wl1251 802.11 chipset designed for embedded devices, supporting both SDIO and SPI busses. Currently the driver supports only SPI. Adding support 1253 (the 5 GHz version) should be relatively easy. More information here: http://focus.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?contentId=4711&navigationId=12494&templateId=6123 (Collapsed original sequence of pre-merge patches into single commit for initial merge. -- JWL) Signed-off-by: Kalle Valo Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 2d8434f..91be3e7 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -500,5 +500,6 @@ source "drivers/net/wireless/b43legacy/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/orinoco/Kconfig" +source "drivers/net/wireless/wl12xx/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 0625e91..f2b1861 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -58,3 +58,5 @@ obj-$(CONFIG_P54_COMMON) += p54/ obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o + +obj-$(CONFIG_WL12XX) += wl12xx/ diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig new file mode 100644 index 0000000..20a9633 --- /dev/null +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -0,0 +1,11 @@ +config WL12XX + tristate "TI wl1251/wl1271 support" + depends on MAC80211 && WLAN_80211 && SPI_MASTER && EXPERIMENTAL + select FW_LOADER + select CRC7 + ---help--- + This module adds support for wireless adapters based on + TI wl1251/wl1271 chipsets. + + If you choose to build a module, it'll be called wl12xx. Say N if + unsure. diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile new file mode 100644 index 0000000..d43de27 --- /dev/null +++ b/drivers/net/wireless/wl12xx/Makefile @@ -0,0 +1,4 @@ +wl12xx-objs = main.o spi.o event.o tx.o rx.o \ + ps.o cmd.o acx.o boot.o init.o wl1251.o \ + debugfs.o +obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c new file mode 100644 index 0000000..1cfd458 --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.c @@ -0,0 +1,689 @@ +#include "acx.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "spi.h" +#include "ps.h" + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod) +{ + int ret; + struct acx_fw_gen_frame_rates rates; + + wl12xx_debug(DEBUG_ACX, "acx frame rates"); + + rates.header.id = ACX_FW_GEN_FRAME_RATES; + rates.header.len = sizeof(struct acx_fw_gen_frame_rates) - + sizeof(struct acx_header); + + rates.tx_ctrl_frame_rate = ctrl_rate; + rates.tx_ctrl_frame_mod = ctrl_mod; + rates.tx_mgt_frame_rate = mgt_rate; + rates.tx_mgt_frame_mod = mgt_mod; + + ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates)); + if (ret < 0) { + wl12xx_error("Failed to set FW rates and modulation"); + return ret; + } + + return 0; +} + + +int wl12xx_acx_station_id(struct wl12xx *wl) +{ + int ret, i; + struct dot11_station_id mac; + + wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); + + mac.header.id = DOT11_STATION_ID; + mac.header.len = sizeof(mac) - sizeof(struct acx_header); + + for (i = 0; i < ETH_ALEN; i++) + mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; + + ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac)); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) +{ + struct acx_dot11_default_key default_key; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); + + default_key.header.id = DOT11_DEFAULT_KEY; + default_key.header.len = sizeof(default_key) - + sizeof(struct acx_header); + + default_key.id = key_id; + + ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key)); + if (ret < 0) { + wl12xx_error("Couldnt set default key"); + return ret; + } + + wl->default_key = key_id; + + return 0; +} + +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) +{ + struct acx_wake_up_condition wake_up; + + wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); + + wake_up.header.id = ACX_WAKE_UP_CONDITIONS; + wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header); + + wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; + wake_up.listen_interval = listen_interval; + + return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up)); +} + +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) +{ + int ret; + struct acx_sleep_auth auth; + + wl12xx_debug(DEBUG_ACX, "acx sleep auth"); + + auth.header.id = ACX_SLEEP_AUTH; + auth.header.len = sizeof(auth) - sizeof(struct acx_header); + + auth.sleep_auth = sleep_auth; + + ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth)); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) +{ + struct wl12xx_command cmd; + struct acx_revision *rev; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx fw rev"); + + memset(&cmd, 0, sizeof(cmd)); + + ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + return ret; + } + + rev = (struct acx_revision *) &cmd.parameters; + + /* be careful with the buffer sizes */ + strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); + + /* + * if the firmware version string is exactly + * sizeof(rev->fw_version) long or fw_len is less than + * sizeof(rev->fw_version) it won't be null terminated + */ + buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; + + return 0; +} + +int wl12xx_acx_tx_power(struct wl12xx *wl, int power) +{ + struct acx_current_tx_power ie; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + + if (power < 0 || power > 25) + return -EINVAL; + + memset(&ie, 0, sizeof(ie)); + + ie.header.id = DOT11_CUR_TX_PWR; + ie.header.len = sizeof(ie) - sizeof(struct acx_header); + ie.current_tx_power = power * 10; + + ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + if (ret < 0) { + wl12xx_warning("configure of tx power failed: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_feature_cfg(struct wl12xx *wl) +{ + struct acx_feature_config feature; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx feature cfg"); + + memset(&feature, 0, sizeof(feature)); + + feature.header.id = ACX_FEATURE_CFG; + feature.header.len = sizeof(feature) - sizeof(struct acx_header); + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature.data_flow_options = 0; + feature.options = 0; + + ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature)); + if (ret < 0) + wl12xx_error("Couldnt set HW encryption"); + + return ret; +} + +int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len) +{ + struct wl12xx_command cmd; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx mem map"); + + ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd); + if (ret < 0) + return ret; + else if (cmd.status != CMD_STATUS_SUCCESS) + return -EIO; + + memcpy(mem_map, &cmd.parameters, len); + + return 0; +} + +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *data_path) +{ + struct acx_data_path_params params; + struct wl12xx_command cmd; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data path params"); + + params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; + params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; + + params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; + params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; + + params.tx_complete_threshold = 1; + + params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; + + params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; + + params.header.id = ACX_DATA_PATH_PARAMS; + params.header.len = sizeof(params) - sizeof(struct acx_header); + + ret = wl12xx_cmd_configure(wl, ¶ms, sizeof(params)); + if (ret < 0) + return ret; + + + ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, + sizeof(struct acx_data_path_params_resp), + &cmd); + + if (ret < 0) { + wl12xx_warning("failed to read data path parameters: %d", ret); + return ret; + } else if (cmd.status != CMD_STATUS_SUCCESS) { + wl12xx_warning("data path parameter acx status failed"); + return -EIO; + } + + memcpy(data_path, &cmd.parameters, sizeof(*data_path)); + + return 0; +} + +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) +{ + struct rx_msdu_lifetime msdu_lifetime; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); + + msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME; + msdu_lifetime.header.len = sizeof(msdu_lifetime) - + sizeof(struct acx_header); + msdu_lifetime.lifetime = life_time; + + ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime)); + if (ret < 0) { + wl12xx_warning("failed to set rx msdu life time: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + struct acx_rx_config rx_config; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx config"); + + rx_config.header.id = ACX_RX_CFG; + rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header); + rx_config.config_options = config; + rx_config.filter_options = filter; + + ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_pd_threshold(struct wl12xx *wl) +{ + struct acx_packet_detection packet_detection; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + + /* FIXME: threshold value not set */ + packet_detection.header.id = ACX_PD_THRESHOLD; + packet_detection.header.len = sizeof(packet_detection) - + sizeof(struct acx_header); + + ret = wl12xx_cmd_configure(wl, &packet_detection, + sizeof(packet_detection)); + if (ret < 0) { + wl12xx_warning("failed to set pd threshold: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) +{ + struct acx_slot slot; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx slot"); + + slot.header.id = ACX_SLOT; + slot.header.len = sizeof(slot) - sizeof(struct acx_header); + + slot.wone_index = STATION_WONE_INDEX; + slot.slot_time = slot_time; + + ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot)); + if (ret < 0) { + wl12xx_warning("failed to set slot time: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_group_address_tbl(struct wl12xx *wl) +{ + struct multicast_grp_addr_start multicast; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx group address tbl"); + + /* MAC filtering */ + multicast.header.id = DOT11_GROUP_ADDRESS_TBL; + multicast.header.len = sizeof(multicast) - sizeof(struct acx_header); + + multicast.enabled = 0; + multicast.num_groups = 0; + memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN); + + ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast)); + if (ret < 0) { + wl12xx_warning("failed to set group addr table: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_service_period_timeout(struct wl12xx *wl) +{ + struct acx_rx_timeout rx_timeout; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + + /* RX timeout */ + rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT; + rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header); + + rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF; + + ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout)); + if (ret < 0) { + wl12xx_warning("failed to set service period timeout: %d", + ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) +{ + struct acx_rts_threshold rts; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rts threshold"); + + rts.header.id = DOT11_RTS_THRESHOLD; + rts.header.len = sizeof(rts) - sizeof(struct acx_header); + + rts.threshold = rts_threshold; + + ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts)); + if (ret < 0) { + wl12xx_warning("failed to set rts threshold: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) +{ + struct acx_beacon_filter_option beacon_filter; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); + + beacon_filter.header.id = ACX_BEACON_FILTER_OPT; + beacon_filter.header.len = sizeof(beacon_filter) - + sizeof(struct acx_header); + + beacon_filter.enable = 0; + beacon_filter.max_num_beacons = 0; + + ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter opt: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) +{ + struct acx_beacon_filter_ie_table ie_table; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table.header.id = ACX_BEACON_FILTER_TABLE; + ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header); + + ie_table.num_ie = 0; + memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + + ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter table: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_sg_enable(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex pta; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg enable"); + + pta.header.id = ACX_SG_ENABLE; + pta.header.len = sizeof(pta) - sizeof(struct acx_header); + + pta.enable = SG_ENABLE; + + ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta)); + if (ret < 0) { + wl12xx_warning("failed to set softgemini enable: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_sg_cfg(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex_param param; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + + /* BT-WLAN coext parameters */ + param.header.id = ACX_SG_CFG; + param.header.len = sizeof(param) - sizeof(struct acx_header); + + param.min_rate = RATE_INDEX_24MBPS; + param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param.antenna_type = PTA_ANTENNA_TYPE_DEF; + param.signal_type = PTA_SIGNALING_TYPE_DEF; + param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param.max_cts = PTA_MAX_NUM_CTS_DEF; + param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param.wlan_elp_hp = PTA_ELP_HP_DEF; + param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param.ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl12xx_cmd_configure(wl, ¶m, sizeof(param)); + if (ret < 0) { + wl12xx_warning("failed to set sg config: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_cca_threshold(struct wl12xx *wl) +{ + struct acx_energy_detection detection; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx cca threshold"); + + detection.header.id = ACX_CCA_THRESHOLD; + detection.header.len = sizeof(detection) - sizeof(struct acx_header); + + detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection.tx_energy_detection = 0; + + ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection)); + if (ret < 0) { + wl12xx_warning("failed to set cca threshold: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) +{ + struct acx_beacon_broadcast bb; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb.header.id = ACX_BCN_DTIM_OPTIONS; + bb.header.len = sizeof(bb) - sizeof(struct acx_header); + + bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + + ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) +{ + struct acx_aid acx_aid; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx aid"); + + acx_aid.header.id = ACX_AID; + acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header); + + acx_aid.aid = aid; + + ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid)); + if (ret < 0) { + wl12xx_warning("failed to set aid: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) +{ + struct acx_event_mask mask; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); + + mask.header.id = ACX_EVENT_MBOX_MASK; + mask.header.len = sizeof(mask) - sizeof(struct acx_header); + + /* high event mask is unused */ + mask.high_event_mask = 0xffffffff; + + mask.event_mask = event_mask; + + ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask)); + if (ret < 0) { + wl12xx_warning("failed to set aid: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble ie; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); + + memset(&ie, 0, sizeof(ie)); + + ie.header.id = ACX_PREAMBLE_TYPE; + ie.header.len = sizeof(ie) - sizeof(struct acx_header); + ie.preamble = preamble; + ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + if (ret < 0) { + wl12xx_warning("Setting of preamble failed: %d", ret); + return ret; + } + return 0; +} + +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect ie; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + memset(&ie, 0, sizeof(ie)); + + ie.header.id = ACX_CTS_PROTECTION; + ie.header.len = sizeof(ie) - sizeof(struct acx_header); + ie.ctsprotect = ctsprotect; + ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + if (ret < 0) { + wl12xx_warning("Setting of ctsprotect failed: %d", ret); + return ret; + } + return 0; +} + +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +{ + struct wl12xx_command *answer; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx statistics"); + + answer = kmalloc(sizeof(*answer), GFP_KERNEL); + if (!answer) { + wl12xx_warning("could not allocate memory for acx statistics"); + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer), + answer); + if (ret < 0) { + wl12xx_warning("acx statistics failed: %d", ret); + goto out; + } + + memcpy(stats, answer->parameters, sizeof(*stats)); + +out: + kfree(answer); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h new file mode 100644 index 0000000..fb2d234 --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.h @@ -0,0 +1,1245 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_ACX_H__ +#define __WL12XX_ACX_H__ + +#include "wl12xx.h" + +/* Target's information element */ +struct acx_header { + u16 id; + u16 len; +}; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + u32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + u32 seq_num_miss; +} __attribute__ ((packed)); + +struct acx_revision { + struct acx_header header; + + /* + * The WiLink firmware version, an ASCII string x.x.x.x, + * that uniquely identifies the current firmware. + * The left most digit is incremented each time a + * significant change is made to the firmware, such as + * code redesign or new platform support. + * The second digit is incremented when major enhancements + * are added or major fixes are made. + * The third digit is incremented for each GA release. + * The fourth digit is incremented for each build. + * The first two digits identify a firmware release version, + * in other words, a unique set of features. + * The first three digits identify a GA release. + */ + char fw_version[20]; + + /* + * This 4 byte field specifies the WiLink hardware version. + * bits 0 - 15: Reserved. + * bits 16 - 23: Version ID - The WiLink version ID + * (1 = first spin, 2 = second spin, and so on). + * bits 24 - 31: Chip ID - The WiLink chip ID. + */ + u32 hw_version; +} __attribute__ ((packed)); + +enum wl12xx_psm_mode { + /* Active mode */ + WL12XX_PSM_CAM = 0, + + /* Power save mode */ + WL12XX_PSM_PS = 1, + + /* Extreme low power */ + WL12XX_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +/* Virtual Bit Map update */ +struct vbm_update_request { + __le16 len; + u8 padding[2]; + struct tim tim; +} __attribute__ ((packed)); + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_NUM_STATIONS 1 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 +#define FW_TX_CMPLT_BLOCK_SIZE 16 + +struct acx_data_path_params { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + /* + * Maximum number of packets that can be gathered + * in the TX complete ring before an interrupt + * is generated. + */ + u8 tx_complete_threshold; + + /* Number of pending TX complete entries in cyclic ring.*/ + u8 tx_complete_ring_depth; + + /* + * Max num microseconds since a packet enters the TX + * complete ring until an interrupt is generated. + */ + u32 tx_complete_timeout; +} __attribute__ ((packed)); + + +struct acx_data_path_params_resp { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + u8 pad[2]; + + u32 rx_packet_ring_addr; + u32 tx_packet_ring_addr; + + u32 rx_control_addr; + u32 tx_control_addr; + + u32 tx_complete_addr; +} __attribute__ ((packed)); + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + u32 lifetime; +} __attribute__ ((packed)); + +/* + * RX Config Options Table + * Bit Definition + * === ========== + * 31:14 Reserved + * 13 Copy RX Status - when set, write three receive status words + * to top of rx'd MPDUs. + * When cleared, do not write three status words (added rev 1.5) + * 12 Reserved + * 11 RX Complete upon FCS error - when set, give rx complete + * interrupt for FCS errors, after the rx filtering, e.g. unicast + * frames not to us with FCS error will not generate an interrupt. + * 10 SSID Filter Enable - When set, the WiLink discards all beacon, + * probe request, and probe response frames with an SSID that does + * not match the SSID specified by the host in the START/JOIN + * command. + * When clear, the WiLink receives frames with any SSID. + * 9 Broadcast Filter Enable - When set, the WiLink discards all + * broadcast frames. When clear, the WiLink receives all received + * broadcast frames. + * 8:6 Reserved + * 5 BSSID Filter Enable - When set, the WiLink discards any frames + * with a BSSID that does not match the BSSID specified by the + * host. + * When clear, the WiLink receives frames from any BSSID. + * 4 MAC Addr Filter - When set, the WiLink discards any frames + * with a destination address that does not match the MAC address + * of the adaptor. + * When clear, the WiLink receives frames destined to any MAC + * address. + * 3 Promiscuous - When set, the WiLink receives all valid frames + * (i.e., all frames that pass the FCS check). + * When clear, only frames that pass the other filters specified + * are received. + * 2 FCS - When set, the WiLink includes the FCS with the received + * frame. + * When cleared, the FCS is discarded. + * 1 PLCP header - When set, write all data from baseband to frame + * buffer including PHY header. + * 0 Reserved - Always equal to 0. + * + * RX Filter Options Table + * Bit Definition + * === ========== + * 31:12 Reserved - Always equal to 0. + * 11 Association - When set, the WiLink receives all association + * related frames (association request/response, reassocation + * request/response, and disassociation). When clear, these frames + * are discarded. + * 10 Auth/De auth - When set, the WiLink receives all authentication + * and de-authentication frames. When clear, these frames are + * discarded. + * 9 Beacon - When set, the WiLink receives all beacon frames. + * When clear, these frames are discarded. + * 8 Contention Free - When set, the WiLink receives all contention + * free frames. + * When clear, these frames are discarded. + * 7 Control - When set, the WiLink receives all control frames. + * When clear, these frames are discarded. + * 6 Data - When set, the WiLink receives all data frames. + * When clear, these frames are discarded. + * 5 FCS Error - When set, the WiLink receives frames that have FCS + * errors. + * When clear, these frames are discarded. + * 4 Management - When set, the WiLink receives all management + * frames. + * When clear, these frames are discarded. + * 3 Probe Request - When set, the WiLink receives all probe request + * frames. + * When clear, these frames are discarded. + * 2 Probe Response - When set, the WiLink receives all probe + * response frames. + * When clear, these frames are discarded. + * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK + * frames. + * When clear, these frames are discarded. + * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames + * that have reserved frame types and sub types as defined by the + * 802.11 specification. + * When clear, these frames are discarded. + */ +struct acx_rx_config { + struct acx_header header; + + u32 config_options; + u32 filter_options; +} __attribute__ ((packed)); + +enum { + QOS_AC_BE = 0, + QOS_AC_BK, + QOS_AC_VI, + QOS_AC_VO, + QOS_HIGHEST_AC_INDEX = QOS_AC_VO, +}; + +#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) +#define FIRST_AC_INDEX QOS_AC_BE +#define MAX_NUM_OF_802_1d_TAGS 8 +#define AC_PARAMS_MAX_TSID 15 +#define MAX_APSD_CONF 0xffff + +#define QOS_TX_HIGH_MIN (0) +#define QOS_TX_HIGH_MAX (100) + +#define QOS_TX_HIGH_BK_DEF (25) +#define QOS_TX_HIGH_BE_DEF (35) +#define QOS_TX_HIGH_VI_DEF (35) +#define QOS_TX_HIGH_VO_DEF (35) + +#define QOS_TX_LOW_BK_DEF (15) +#define QOS_TX_LOW_BE_DEF (25) +#define QOS_TX_LOW_VI_DEF (25) +#define QOS_TX_LOW_VO_DEF (25) + +struct acx_tx_queue_qos_config { + struct acx_header header; + + u8 qid; + u8 pad[3]; + + /* Max number of blocks allowd in the queue */ + u16 high_threshold; + + /* Lowest memory blocks guaranteed for this queue */ + u16 low_threshold; +} __attribute__ ((packed)); + +struct acx_packet_detection { + struct acx_header header; + + u32 threshold; +} __attribute__ ((packed)); + + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[6]; +} __attribute__ ((packed)); + + +#define ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) + +struct multicast_grp_addr_start { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __attribute__ ((packed)); + + +#define RX_TIMEOUT_PS_POLL_MIN 0 +#define RX_TIMEOUT_PS_POLL_MAX (200000) +#define RX_TIMEOUT_PS_POLL_DEF (15) +#define RX_TIMEOUT_UPSD_MIN 0 +#define RX_TIMEOUT_UPSD_MAX (200000) +#define RX_TIMEOUT_UPSD_DEF (15) + +struct acx_rx_timeout { + struct acx_header header; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a PS-poll has been + * transmitted. + */ + u16 ps_poll_timeout; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a frame has been sent + * from an UPSD enabled queue. + */ + u16 upsd_timeout; +} __attribute__ ((packed)); + +#define RTS_THRESHOLD_MIN 0 +#define RTS_THRESHOLD_MAX 4096 +#define RTS_THRESHOLD_DEF 2347 + +struct acx_rts_threshold { + struct acx_header header; + + u16 threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 enable; + + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[2]; +} __attribute__ ((packed)); + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; + u8 pad[3]; +} __attribute__ ((packed)); + +enum { + SG_ENABLE = 0, + SG_DISABLE, + SG_SENSE_NO_ACTIVITY, + SG_SENSE_ACTIVE +}; + +struct acx_bt_wlan_coex { + struct acx_header header; + + /* + * 0 -> PTA enabled + * 1 -> PTA disabled + * 2 -> sense no active mode, i.e. + * an interrupt is sent upon + * BT activity. + * 3 -> PTA is switched on in response + * to the interrupt sending. + */ + u8 enable; + u8 pad[3]; +} __attribute__ ((packed)); + +#define PTA_ANTENNA_TYPE_DEF (0) +#define PTA_BT_HP_MAXTIME_DEF (2000) +#define PTA_WLAN_HP_MAX_TIME_DEF (5000) +#define PTA_SENSE_DISABLE_TIMER_DEF (1350) +#define PTA_PROTECTIVE_RX_TIME_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_DEF (1500) +#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) +#define PTA_SIGNALING_TYPE_DEF (1) +#define PTA_AFH_LEVERAGE_ON_DEF (0) +#define PTA_NUMBER_QUIET_CYCLE_DEF (0) +#define PTA_MAX_NUM_CTS_DEF (3) +#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) +#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) +#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) +#define PTA_CYCLE_TIME_FAST_DEF (8700) +#define PTA_RX_FOR_AVALANCHE_DEF (5) +#define PTA_ELP_HP_DEF (0) +#define PTA_ANTI_STARVE_PERIOD_DEF (500) +#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) +#define PTA_ALLOW_PA_SD_DEF (1) +#define PTA_TIME_BEFORE_BEACON_DEF (6300) +#define PTA_HPDM_MAX_TIME_DEF (1600) +#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) +#define PTA_AUTO_MODE_NO_CTS_DEF (0) +#define PTA_BT_HP_RESPECTED_DEF (3) +#define PTA_WLAN_RX_MIN_RATE_DEF (24) +#define PTA_ACK_MODE_DEF (1) + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + /* + * The minimum rate of a received WLAN packet in the STA, + * during protective mode, of which a new BT-HP request + * during this Rx will always be respected and gain the antenna. + */ + u32 min_rate; + + /* Max time the BT HP will be respected. */ + u16 bt_hp_max_time; + + /* Max time the WLAN HP will be respected. */ + u16 wlan_hp_max_time; + + /* + * The time between the last BT activity + * and the moment when the sense mode returns + * to SENSE_INACTIVE. + */ + u16 sense_disable_timer; + + /* Time before the next BT HP instance */ + u16 rx_time_bt_hp; + u16 tx_time_bt_hp; + + /* range: 10-20000 default: 1500 */ + u16 rx_time_bt_hp_fast; + u16 tx_time_bt_hp_fast; + + /* range: 2000-65535 default: 8700 */ + u16 wlan_cycle_fast; + + /* range: 0 - 15000 (Msec) default: 1000 */ + u16 bt_anti_starvation_period; + + /* range 400-10000(Usec) default: 3000 */ + u16 next_bt_lp_packet; + + /* Deafult: worst case for BT DH5 traffic */ + u16 wake_up_beacon; + + /* range: 0-50000(Usec) default: 1050 */ + u16 hp_dm_max_guard_time; + + /* + * This is to prevent both BT & WLAN antenna + * starvation. + * Range: 100-50000(Usec) default:2550 + */ + u16 next_wlan_packet; + + /* 0 -> shared antenna */ + u8 antenna_type; + + /* + * 0 -> TI legacy + * 1 -> Palau + */ + u8 signal_type; + + /* + * BT AFH status + * 0 -> no AFH + * 1 -> from dedicated GPIO + * 2 -> AFH on (from host) + */ + u8 afh_leverage_on; + + /* + * The number of cycles during which no + * TX will be sent after 1 cycle of RX + * transaction in protective mode + */ + u8 quiet_cycle_num; + + /* + * The maximum number of CTSs that will + * be sent for receiving RX packet in + * protective mode + */ + u8 max_cts; + + /* + * The number of WLAN packets + * transferred in common mode before + * switching to BT. + */ + u8 wlan_packets_num; + + /* + * The number of BT packets + * transferred in common mode before + * switching to WLAN. + */ + u8 bt_packets_num; + + /* range: 1-255 default: 5 */ + u8 missed_rx_avalanche; + + /* range: 0-1 default: 1 */ + u8 wlan_elp_hp; + + /* range: 0 - 15 default: 4 */ + u8 bt_anti_starvation_cycles; + + u8 ack_mode_dual_ant; + + /* + * Allow PA_SD assertion/de-assertion + * during enabled BT activity. + */ + u8 pa_sd_enable; + + /* + * Enable/Disable PTA in auto mode: + * Support Both Active & P.S modes + */ + u8 pta_auto_mode_enable; + + /* range: 0 - 20 default: 1 */ + u8 bt_hp_respected_num; +} __attribute__ ((packed)); + +#define CCA_THRSH_ENABLE_ENERGY_D 0x140A +#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + u16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __attribute__ ((packed)); + +#define BCN_RX_TIMEOUT_DEF_VALUE 10000 +#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 +#define RX_BROADCAST_IN_PS_DEF_VALUE 1 +#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 + +struct acx_beacon_broadcast { + struct acx_header header; + + u16 beacon_rx_timeout; + u16 broadcast_timeout; + + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_event_mask { + struct acx_header header; + + u32 event_mask; + u32 high_event_mask; /* Unused */ +} __attribute__ ((packed)); + +#define CFG_RX_FCS BIT(2) +#define CFG_RX_ALL_GOOD BIT(3) +#define CFG_UNI_FILTER_EN BIT(4) +#define CFG_BSSID_FILTER_EN BIT(5) +#define CFG_MC_FILTER_EN BIT(6) +#define CFG_MC_ADDR0_EN BIT(7) +#define CFG_MC_ADDR1_EN BIT(8) +#define CFG_BC_REJECT_EN BIT(9) +#define CFG_SSID_FILTER_EN BIT(10) +#define CFG_RX_INT_FCS_ERROR BIT(11) +#define CFG_RX_INT_ENCRYPTED BIT(12) +#define CFG_RX_WR_RX_STATUS BIT(13) +#define CFG_RX_FILTER_NULTI BIT(14) +#define CFG_RX_RESERVE BIT(15) +#define CFG_RX_TIMESTAMP_TSF BIT(16) + +#define CFG_RX_RSV_EN BIT(0) +#define CFG_RX_RCTS_ACK BIT(1) +#define CFG_RX_PRSP_EN BIT(2) +#define CFG_RX_PREQ_EN BIT(3) +#define CFG_RX_MGMT_EN BIT(4) +#define CFG_RX_FCS_ERROR BIT(5) +#define CFG_RX_DATA_EN BIT(6) +#define CFG_RX_CTL_EN BIT(7) +#define CFG_RX_CF_EN BIT(8) +#define CFG_RX_BCN_EN BIT(9) +#define CFG_RX_AUTH_EN BIT(10) +#define CFG_RX_ASSOC_EN BIT(11) + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +struct acx_fw_gen_frame_rates { + struct acx_header header; + + u8 tx_ctrl_frame_rate; /* RATE_* */ + u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ + u8 tx_mgt_frame_rate; + u8 tx_mgt_frame_mod; +} __attribute__ ((packed)); + +/* STA MAC */ +struct dot11_station_id { + struct acx_header header; + + u8 mac[ETH_ALEN]; + u8 pad[2]; +} __attribute__ ((packed)); + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +struct acx_feature_config { + struct acx_header header; + + u32 options; + u32 data_flow_options; +} __attribute__ ((packed)); + +enum acx_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum acx_key_type { + KEY_WEP_DEFAULT = 0, + KEY_WEP_ADDR = 1, + KEY_AES_GROUP = 4, + KEY_AES_PAIRWISE = 5, + KEY_WEP_GROUP = 6, + KEY_TKIP_MIC_GROUP = 10, + KEY_TKIP_MIC_PAIRWISE = 11, +}; + +/* + * + * key_type_e key size key format + * ---------- --------- ---------- + * 0x00 5, 13, 29 Key data + * 0x01 5, 13, 29 Key data + * 0x04 16 16 bytes of key data + * 0x05 16 16 bytes of key data + * 0x0a 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * 0x0b 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * + */ + +struct acx_set_key { + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_dot11_default_key { + struct acx_header header; + + u8 id; + u8 pad[3]; +} __attribute__ ((packed)); + +struct acx_tsf_info { + struct acx_header header; + + u32 current_tsf_msb; + u32 current_tsf_lsb; + u32 last_TBTT_msb; + u32 last_TBTT_lsb; + u8 last_dtim_count; + u8 pad[3]; +} __attribute__ ((packed)); + +/* 802.11 PS */ +enum acx_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct acx_ps_params { + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u16 null_data_rate; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_wake_up_event { + WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ + WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ + WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ + WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ + WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u16 aid; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 preamble; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 ctsprotect; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_tx_statistics { + u32 internal_desc_overflow; +} __attribute__ ((packed)); + +struct acx_rx_statistics { + u32 out_of_mem; + u32 hdr_overflow; + u32 hw_stuck; + u32 dropped; + u32 fcs_err; + u32 xfr_hint_trig; + u32 path_reset; + u32 reset_counter; +} __attribute__ ((packed)); + +struct acx_dma_statistics { + u32 rx_requested; + u32 rx_errors; + u32 tx_requested; + u32 tx_errors; +} __attribute__ ((packed)); + +struct acx_isr_statistics { + /* host command complete */ + u32 cmd_cmplt; + + /* fiqisr() */ + u32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + u32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + u32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + u32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + u32 rx_rdys; + + /* irqisr() */ + u32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + u32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + u32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + u32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + u32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + u32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + u32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + u32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + u32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + u32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + u32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + u32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + u32 low_rssi; +} __attribute__ ((packed)); + +struct acx_wep_statistics { + /* WEP address keys configured */ + u32 addr_key_count; + + /* default keys configured */ + u32 default_key_count; + + u32 reserved; + + /* number of times that WEP key not found on lookup */ + u32 key_not_found; + + /* number of times that WEP key decryption failed */ + u32 decrypt_fail; + + /* WEP packets decrypted */ + u32 packets; + + /* WEP decrypt interrupts */ + u32 interrupt; +} __attribute__ ((packed)); + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + u32 ps_enter; + + /* the amount of enters into ELP mode */ + u32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + u32 missing_bcns; + + /* the amount of wake on host-access times */ + u32 wake_on_host; + + /* the amount of wake on timer-expire */ + u32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + u32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + u32 tx_without_ps; + + /* the number of received beacons */ + u32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + u32 power_save_off; + + /* the number of entries into power save mode */ + u16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + u16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + u32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + u32 rcvd_awake_beacons; +} __attribute__ ((packed)); + +struct acx_mic_statistics { + u32 rx_pkts; + u32 calc_failure; +} __attribute__ ((packed)); + +struct acx_aes_statistics { + u32 encrypt_fail; + u32 decrypt_fail; + u32 encrypt_packets; + u32 decrypt_packets; + u32 encrypt_interrupt; + u32 decrypt_interrupt; +} __attribute__ ((packed)); + +struct acx_event_statistics { + u32 heart_beat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_transmit_error; + u32 tx_stuck; +} __attribute__ ((packed)); + +struct acx_ps_statistics { + u32 pspoll_timeouts; + u32 upsd_timeouts; + u32 upsd_max_sptime; + u32 upsd_max_apturn; + u32 pspoll_max_apturn; + u32 pspoll_utilization; + u32 upsd_utilization; +} __attribute__ ((packed)); + +struct acx_rxpipe_statistics { + u32 rx_prep_beacon_drop; + u32 descr_host_int_trig_rx_data; + u32 beacon_buffer_thres_host_int_trig_rx_data; + u32 missed_beacon_host_int_trig_rx_data; + u32 tx_xfr_host_int_trig_rx_data; +} __attribute__ ((packed)); + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __attribute__ ((packed)); + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + ACX_RADIO_PARAM = 0x000B, /* Not used */ + ACX_CFG = 0x000C, /* Not used */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_BSS_IN_PS = 0x0012, /* for AP only */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_FEATURE_CFG = 0x0015, + ACX_MISC_CFG = 0x0017, /* Not used */ + ACX_TID_CFG = 0x001A, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_LOW_RSSI = 0x0020, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ + ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, +#ifdef FW_RUNNING_AS_AP + ACX_DTIM_PERIOD = 0x0027, /* for AP only */ +#else + ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ +#endif + ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ + ACX_GPIO_CFG = 0x002A, /* Not used */ + ACX_GPIO_SET = 0x002B, /* Not used */ + ACX_PM_CFG = 0x002C, /* To Be Documented */ + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_AVERAGE_RSSI = 0x002E, /* Not used */ + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ + ACX_LOW_SNR = 0x0037, /* To Be Documented */ + ACX_BEACON_FILTER_TABLE = 0x0038, + ACX_ARP_IP_FILTER = 0x0039, + ACX_ROAMING_STATISTICS_TBL = 0x003B, + ACX_RATE_POLICY = 0x003D, + ACX_CTS_PROTECTION = 0x003E, + ACX_SLEEP_AUTH = 0x003F, + ACX_PREAMBLE_TYPE = 0x0040, + ACX_ERROR_CNT = 0x0041, + ACX_FW_GEN_FRAME_RATES = 0x0042, + ACX_IBSS_FILTER = 0x0044, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, + ACX_TSF_INFO = 0x0046, + ACX_CONFIG_PS_WMM = 0x0049, + ACX_ENABLE_RX_DATA_FILTER = 0x004A, + ACX_SET_RX_DATA_FILTER = 0x004B, + ACX_GET_DATA_FILTER_STATISTICS = 0x004C, + ACX_POWER_LEVEL_TABLE = 0x004D, + ACX_BET_ENABLE = 0x0050, + DOT11_STATION_ID = 0x1001, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_DEFAULT_KEY = 0x1010, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod); +int wl12xx_acx_station_id(struct wl12xx *wl); +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval); +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); +int wl12xx_acx_tx_power(struct wl12xx *wl, int power); +int wl12xx_acx_feature_cfg(struct wl12xx *wl); +int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len); +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *data_path); +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_acx_pd_threshold(struct wl12xx *wl); +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); +int wl12xx_acx_group_address_tbl(struct wl12xx *wl); +int wl12xx_acx_service_period_timeout(struct wl12xx *wl); +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); +int wl12xx_acx_sg_enable(struct wl12xx *wl); +int wl12xx_acx_sg_cfg(struct wl12xx *wl); +int wl12xx_acx_cca_threshold(struct wl12xx *wl); +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect); +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); + +#endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c new file mode 100644 index 0000000..48ac08c --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.c @@ -0,0 +1,295 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "reg.h" +#include "boot.h" +#include "spi.h" +#include "event.h" + +static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) +{ + enable_irq(wl->irq); +} + +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) +{ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +int wl12xx_boot_soft_reset(struct wl12xx *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl12xx_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl12xx_reg_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl12xx_reg_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +int wl12xx_boot_init_seq(struct wl12xx *wl) +{ + u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; + + /* + * col #1: INTEGER_DIVIDER + * col #2: FRACTIONAL_DIVIDER + * col #3: ATTN_BB + * col #4: ALPHA_BB + * col #5: STOP_TIME_BB + * col #6: BB_PLL_LOOP_FILTER + */ + static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { + + { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ + { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ + { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ + { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ + { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ + }; + + /* read NVS params */ + scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); + wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); + + /* read ELP_CMD */ + elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); + wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); + + /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ + ref_freq = scr_pad6 & 0x000000FF; + wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); + + wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); + + /* + * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) + */ + wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); + + /* + * set the clock detect feature to work in the restart wu procedure + * (ELP_CFG_MODE[14]) and Select the clock source type + * (ELP_CFG_MODE[13:12]) + */ + tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; + wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); + + /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ + elp_cmd |= 0x00000040; + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); + + /* PG 1.2: Set the BB PLL stable time to be 1000usec + * (PLL_STABLE_TIME) */ + wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); + + /* PG 1.2: read clock request time */ + init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); + + /* + * PG 1.2: set the clock request time to be ref_clk_settling_time - + * 1ms = 4ms + */ + if (init_data > 0x21) + tmp = init_data - 0x21; + else + tmp = 0; + wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); + + /* set BB PLL configurations in RF AFE */ + wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); + + /* set RF_AFE_REG_5 */ + wl12xx_reg_write32(wl, 0x003058d4, 0x50); + + /* set RF_AFE_CTRL_REG_2 */ + wl12xx_reg_write32(wl, 0x00305948, 0x11c001); + + /* + * change RF PLL and BB PLL divider for VCO clock and adjust VCO + * bais current(RF_AFE_REG_13) + */ + wl12xx_reg_write32(wl, 0x003058f4, 0x1e); + + /* set BB PLL configurations */ + tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; + wl12xx_reg_write32(wl, 0x00305840, tmp); + + /* set fractional divider according to Appendix C-BB PLL + * Calculations + */ + tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; + wl12xx_reg_write32(wl, 0x00305844, tmp); + + /* set the initial data for the sigma delta */ + wl12xx_reg_write32(wl, 0x00305848, 0x3039); + + /* + * set the accumulator attenuation value, calibration loop1 + * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and + * the VCO gain + */ + tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | + (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; + wl12xx_reg_write32(wl, 0x00305854, tmp); + + /* + * set the calibration stop time after holdoff time expires and set + * settling time HOLD_OFF_TIME_BB + */ + tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; + wl12xx_reg_write32(wl, 0x00305858, tmp); + + /* + * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL + * constant leakage current to linearize PFD to 0uA - + * BB_ILOOPF[7:3] + */ + tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; + wl12xx_reg_write32(wl, 0x003058f8, tmp); + + /* + * set regulator output voltage for n divider to + * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], + * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB + * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] + */ + wl12xx_reg_write32(wl, 0x003058f0, 0x29); + + /* enable restart wakeup sequence (ELP_CMD[0]) */ + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); + + /* restart sequence completed */ + udelay(2000); + + return 0; +} + +int wl12xx_boot_run_firmware(struct wl12xx *wl) +{ + int loop, ret; + u32 chip_id, interrupt; + + wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); + + wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl12xx_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (interrupt == 0xffffffff) { + wl12xx_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (interrupt & wl->chip.intr_init_complete) { + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_init_complete); + break; + } + } + + if (loop >= INIT_LOOP) { + wl12xx_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl12xx_set_partition(wl, + wl->chip.p_table[PART_WORK].mem.start, + wl->chip.p_table[PART_WORK].mem.size, + wl->chip.p_table[PART_WORK].reg.start, + wl->chip.p_table[PART_WORK].reg.size); + + wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* enable gpio interrupts */ + wl12xx_boot_enable_interrupts(wl); + + wl->chip.op_target_enable_interrupts(wl); + + /* unmask all mbox events */ + wl->event_mask = 0xffffffff; + + ret = wl12xx_event_unmask(wl); + if (ret < 0) { + wl12xx_error("EVENT mask setting failed"); + return ret; + } + + wl12xx_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h new file mode 100644 index 0000000..4fa7313 --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wl12xx.h" + +int wl12xx_boot_soft_reset(struct wl12xx *wl); +int wl12xx_boot_init_seq(struct wl12xx *wl); +int wl12xx_boot_run_firmware(struct wl12xx *wl); +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#endif diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c new file mode 100644 index 0000000..f73ab60 --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -0,0 +1,353 @@ +#include "cmd.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "spi.h" +#include "ps.h" + +int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len) +{ + struct wl12xx_command cmd; + unsigned long timeout; + size_t cmd_len; + u32 intr; + int ret = 0; + + memset(&cmd, 0, sizeof(cmd)); + cmd.id = type; + cmd.status = 0; + memcpy(cmd.parameters, buf, buf_len); + cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN; + + wl12xx_ps_elp_wakeup(wl); + + wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & wl->chip.intr_cmd_complete)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_cmd_complete); + +out: + wl12xx_ps_elp_sleep(wl); + + return ret; +} + +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd test"); + + ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + if (ret < 0) { + wl12xx_warning("TEST command failed"); + return ret; + } + + if (answer) { + struct wl12xx_command *cmd_answer; + + /* + * The test command got in, we can read the answer. + * The answer would be a wl12xx_command, where the + * parameter array contains the actual answer. + */ + + wl12xx_ps_elp_wakeup(wl); + + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + + wl12xx_ps_elp_sleep(wl); + + cmd_answer = buf; + if (cmd_answer->status != CMD_STATUS_SUCCESS) + wl12xx_error("TEST command answer error: %d", + cmd_answer->status); + } + + return 0; +} + + +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, + void *answer) +{ + struct wl12xx_command *cmd; + struct acx_header header; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd interrogate"); + + header.id = ie_id; + header.len = ie_len - sizeof(header); + + ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header)); + if (ret < 0) { + wl12xx_error("INTERROGATE command failed"); + return ret; + } + + wl12xx_ps_elp_wakeup(wl); + + /* the interrogate command got in, we can read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer, + CMDMBOX_HEADER_LEN + ie_len); + + wl12xx_ps_elp_sleep(wl); + + cmd = answer; + if (cmd->status != CMD_STATUS_SUCCESS) + wl12xx_error("INTERROGATE command error: %d", + cmd->status); + + return 0; + +} + +int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len) +{ + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd configure"); + + ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie, + ie_len); + if (ret < 0) { + wl12xx_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; + +} + +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control) +{ + struct vbm_update_request vbm; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd vbm"); + + /* Count and period will be filled by the target */ + vbm.tim.bitmap_ctrl = bitmap_control; + if (bitmap_len > PARTIAL_VBM_MAX) { + wl12xx_warning("cmd vbm len is %d B, truncating to %d", + bitmap_len, PARTIAL_VBM_MAX); + bitmap_len = PARTIAL_VBM_MAX; + } + memcpy(vbm.tim.pvb_field, bitmap, bitmap_len); + vbm.tim.identity = identity; + vbm.tim.length = bitmap_len + 3; + + vbm.len = cpu_to_le16(bitmap_len + 5); + + ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm)); + if (ret < 0) { + wl12xx_error("VBM command failed"); + return ret; + } + + return 0; +} + +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) +{ + int ret; + u16 cmd_rx, cmd_tx; + + wl12xx_debug(DEBUG_CMD, "cmd data path"); + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel)); + if (ret < 0) { + wl12xx_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + + ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel)); + if (ret < 0) { + wl12xx_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); + + return 0; +} + +int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait) +{ + unsigned long timeout; + struct cmd_join join = {}; + int ret, i; + u8 *bssid; + + /* FIXME: this should be in main.c */ + ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + DEFAULT_HW_GEN_MODULATION_TYPE, + wl->tx_mgmt_frm_rate, + wl->tx_mgmt_frm_mod); + if (ret < 0) + return ret; + + wl12xx_debug(DEBUG_CMD, "cmd join"); + + /* Reverse order BSSID */ + bssid = (u8 *)&join.bssid_lsb; + for (i = 0; i < ETH_ALEN; i++) + bssid[i] = wl->bssid[ETH_ALEN - i - 1]; + + join.rx_config_options = wl->rx_config; + join.rx_filter_options = wl->rx_filter; + + join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + + join.beacon_interval = beacon_interval; + join.dtim_interval = dtim_interval; + join.bss_type = bss_type; + join.channel = wl->channel; + join.ctrl = JOIN_CMD_CTRL_TX_FLUSH; + + ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join)); + if (ret < 0) { + wl12xx_error("failed to initiate cmd join"); + return ret; + } + + timeout = msecs_to_jiffies(JOIN_TIMEOUT); + + /* + * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to + * simplify locking we just sleep instead, for now + */ + if (wait) + msleep(10); + + return 0; +} + +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) +{ + int ret; + struct acx_ps_params ps_params; + + /* FIXME: this should be in ps.c */ + ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int); + if (ret < 0) { + wl12xx_error("Couldnt set wake up conditions"); + return ret; + } + + wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params.ps_mode = ps_mode; + ps_params.send_null_data = 1; + ps_params.retries = 5; + ps_params.hang_over_period = 128; + ps_params.null_data_rate = 1; /* 1 Mbps */ + + ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params, + sizeof(ps_params)); + if (ret < 0) { + wl12xx_error("cmd set_ps_mode failed"); + return ret; + } + + return 0; +} + +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer) +{ + struct cmd_read_write_memory mem_cmd, *mem_answer; + struct wl12xx_command cmd; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd read memory"); + + memset(&mem_cmd, 0, sizeof(mem_cmd)); + mem_cmd.addr = addr; + mem_cmd.size = len; + + ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd)); + if (ret < 0) { + wl12xx_error("read memory command failed: %d", ret); + return ret; + } + + /* the read command got in, we can now read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd, + CMDMBOX_HEADER_LEN + sizeof(mem_cmd)); + + if (cmd.status != CMD_STATUS_SUCCESS) + wl12xx_error("error in read command result: %d", cmd.status); + + mem_answer = (struct cmd_read_write_memory *) cmd.parameters; + memcpy(answer, mem_answer->value, len); + + return 0; +} + +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len) +{ + struct wl12xx_cmd_packet_template template; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); + + memset(&template, 0, sizeof(template)); + + WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); + buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); + template.size = cpu_to_le16(buf_len); + + if (buf) + memcpy(template.template, buf, buf_len); + + ret = wl12xx_cmd_send(wl, cmd_id, &template, + sizeof(template.size) + buf_len); + if (ret < 0) { + wl12xx_warning("cmd set_template failed: %d", ret); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h new file mode 100644 index 0000000..aa307dc --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -0,0 +1,265 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_CMD_H__ +#define __WL12XX_CMD_H__ + +#include "wl12xx.h" + +int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, + void *answer); +int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len); +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control); +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable); +int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer); +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len); + +/* unit ms */ +#define WL12XX_COMMAND_TIMEOUT 2000 + +#define WL12XX_MAX_TEMPLATE_SIZE 300 + +struct wl12xx_cmd_packet_template { + __le16 size; + u8 template[WL12XX_MAX_TEMPLATE_SIZE]; +} __attribute__ ((packed)); + +enum wl12xx_commands { + CMD_RESET = 0, + CMD_INTERROGATE = 1, /*use this to read information elements*/ + CMD_CONFIGURE = 2, /*use this to write information elements*/ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 8, + CMD_STOP_SCAN = 9, + CMD_VBM = 10, + CMD_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_BEACON = 19, + CMD_PROBE_RESP = 20, + CMD_NULL_DATA = 21, + CMD_PROBE_REQ = 22, + CMD_TEST = 23, + CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ + CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ + CMD_NOISE_HIST = 28, + CMD_RX_RESET = 29, + CMD_PS_POLL = 30, + CMD_QOS_NULL_DATA = 31, + CMD_LNA_CONTROL = 32, + CMD_SET_BCN_MODE = 33, + CMD_MEASUREMENT = 34, + CMD_STOP_MEASUREMENT = 35, + CMD_DISCONNECT = 36, + CMD_SET_PS_MODE = 37, + CMD_CHANNEL_SWITCH = 38, + CMD_STOP_CHANNEL_SWICTH = 39, + CMD_AP_DISCOVERY = 40, + CMD_STOP_AP_DISCOVERY = 41, + CMD_SPS_SCAN = 42, + CMD_STOP_SPS_SCAN = 43, + CMD_HEALTH_CHECK = 45, + CMD_DEBUG = 46, + CMD_TRIGGER_SCAN_TO = 47, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +struct wl12xx_command { + u16 id; + u16 status; + u8 parameters[MAX_CMD_PARAMS]; +}; + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + MAX_COMMAND_STATUS = 0xff +}; + + +/* + * CMD_READ_MEMORY + * + * The host issues this command to read the WiLink device memory/registers. + * + * Note: The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +/* + * CMD_WRITE_MEMORY + * + * The host issues this command to write the WiLink device memory/registers. + * + * The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +#define MAX_READ_SIZE 256 + +struct cmd_read_write_memory { + /* The address of the memory to read from or write to.*/ + u32 addr; + + /* The amount of data in bytes to read from or write to the WiLink + * device.*/ + u32 size; + + /* The actual value read from or written to the Wilink. The source + of this field is the Host in WRITE command or the Wilink in READ + command. */ + u8 value[MAX_READ_SIZE]; +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + + +struct basic_scan_parameters { + u32 rx_config_options; + u32 rx_filter_options; + + /* + * Scan options: + * bit 0: When this bit is set, passive scan. + * bit 1: Band, when this bit is set we scan + * in the 5Ghz band. + * bit 2: voice mode, 0 for normal scan. + * bit 3: scan priority, 1 for high priority. + */ + u16 scan_options; + + /* Number of channels to scan */ + u8 num_channels; + + /* Number opf probe requests to send, per channel */ + u8 num_probe_requests; + + /* Rate and modulation for probe requests */ + u16 tx_rate; + + u8 tid_trigger; + u8 ssid_len; + u32 ssid[8]; + +} __attribute__ ((packed)); + +struct basic_scan_channel_parameters { + u32 min_duration; /* in TU */ + u32 max_duration; /* in TU */ + u32 bssid_lsb; + u16 bssid_msb; + + /* + * bits 0-3: Early termination count. + * bits 4-5: Early termination condition. + */ + u8 early_termination; + + u8 tx_power_att; + u8 channel; + u8 pad[3]; +} __attribute__ ((packed)); + +/* SCAN parameters */ +#define SCAN_MAX_NUM_OF_CHANNELS 16 + +struct cmd_scan { + struct basic_scan_parameters params; + struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; +} __attribute__ ((packed)); + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ + + +struct cmd_join { + u32 bssid_lsb; + u16 bssid_msb; + u16 beacon_interval; /* in TBTTs */ + u32 rx_config_options; + u32 rx_filter_options; + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + u16 basic_rate_set; + u8 dtim_interval; + u8 tx_ctrl_frame_rate; /* OBSOLETE */ + u8 tx_ctrl_frame_mod; /* OBSOLETE */ + /* + * bits 0-2: This bitwise field specifies the type + * of BSS to start or join (BSS_TYPE_*). + * bit 4: Band - The radio band in which to join + * or start. + * 0 - 2.4GHz band + * 1 - 5GHz band + * bits 3, 5-7: Reserved + */ + u8 bss_type; + u8 channel; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ctrl; /* JOIN_CMD_CTRL_* */ + u8 tx_mgt_frame_rate; /* OBSOLETE */ + u8 tx_mgt_frame_mod; /* OBSOLETE */ + u8 reserved; +} __attribute__ ((packed)); + + +#endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c new file mode 100644 index 0000000..cdb368c --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -0,0 +1,508 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "debugfs.h" + +#include + +#include "wl12xx.h" +#include "acx.h" + +/* ms */ +#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_ADD(name, parent) \ + wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ + wl, &name## _ops); \ + if (IS_ERR(wl->debugfs.name)) { \ + ret = PTR_ERR(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + goto out; \ + } + +#define DEBUGFS_DEL(name) \ + do { \ + debugfs_remove(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + } while (0) + +#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + wl12xx_debugfs_update_stats(wl); \ + \ + res = scnprintf(buf, buflen, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_FWSTATS_ADD(sub, name) \ + DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) + +#define DEBUGFS_FWSTATS_DEL(sub, name) \ + DEBUGFS_DEL(sub## _ ##name) + +static void wl12xx_debugfs_update_stats(struct wl12xx *wl) +{ + mutex_lock(&wl->mutex); + + if (wl->state == WL12XX_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { + wl12xx_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, + 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", + wl->stats.excessive_retries); + +static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl12xx *wl = file->private_data; + u32 queue_len; + char buf[20]; + int res; + + queue_len = skb_queue_len(&wl->tx_queue); + + res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static const struct file_operations tx_queue_len_ops = { + .read = tx_queue_len_read, + .open = wl12xx_open_file_generic, +}; + +static void wl12xx_debugfs_delete_files(struct wl12xx *wl) +{ + DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_DEL(rx, out_of_mem); + DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); + DEBUGFS_FWSTATS_DEL(rx, hw_stuck); + DEBUGFS_FWSTATS_DEL(rx, dropped); + DEBUGFS_FWSTATS_DEL(rx, fcs_err); + DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_DEL(rx, path_reset); + DEBUGFS_FWSTATS_DEL(rx, reset_counter); + + DEBUGFS_FWSTATS_DEL(dma, rx_requested); + DEBUGFS_FWSTATS_DEL(dma, rx_errors); + DEBUGFS_FWSTATS_DEL(dma, tx_requested); + DEBUGFS_FWSTATS_DEL(dma, tx_errors); + + DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); + DEBUGFS_FWSTATS_DEL(isr, fiqs); + DEBUGFS_FWSTATS_DEL(isr, rx_headers); + DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_DEL(isr, rx_rdys); + DEBUGFS_FWSTATS_DEL(isr, irqs); + DEBUGFS_FWSTATS_DEL(isr, tx_procs); + DEBUGFS_FWSTATS_DEL(isr, decrypt_done); + DEBUGFS_FWSTATS_DEL(isr, dma0_done); + DEBUGFS_FWSTATS_DEL(isr, dma1_done); + DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); + DEBUGFS_FWSTATS_DEL(isr, commands); + DEBUGFS_FWSTATS_DEL(isr, rx_procs); + DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); + DEBUGFS_FWSTATS_DEL(isr, pci_pm); + DEBUGFS_FWSTATS_DEL(isr, wakeups); + DEBUGFS_FWSTATS_DEL(isr, low_rssi); + + DEBUGFS_FWSTATS_DEL(wep, addr_key_count); + DEBUGFS_FWSTATS_DEL(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_DEL(wep, key_not_found); + DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); + DEBUGFS_FWSTATS_DEL(wep, packets); + DEBUGFS_FWSTATS_DEL(wep, interrupt); + + DEBUGFS_FWSTATS_DEL(pwr, ps_enter); + DEBUGFS_FWSTATS_DEL(pwr, elp_enter); + DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); + DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); + DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_DEL(pwr, power_save_off); + DEBUGFS_FWSTATS_DEL(pwr, enable_ps); + DEBUGFS_FWSTATS_DEL(pwr, disable_ps); + DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_DEL(mic, rx_pkts); + DEBUGFS_FWSTATS_DEL(mic, calc_failure); + + DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_DEL(event, heart_beat); + DEBUGFS_FWSTATS_DEL(event, calibration); + DEBUGFS_FWSTATS_DEL(event, rx_mismatch); + DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); + DEBUGFS_FWSTATS_DEL(event, rx_pool); + DEBUGFS_FWSTATS_DEL(event, oom_late); + DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); + DEBUGFS_FWSTATS_DEL(event, tx_stuck); + + DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); + DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); + + DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(retry_count); + DEBUGFS_DEL(excessive_retries); +} + +static int wl12xx_debugfs_add_files(struct wl12xx *wl) +{ + int ret = 0; + + DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_ADD(rx, out_of_mem); + DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); + DEBUGFS_FWSTATS_ADD(rx, hw_stuck); + DEBUGFS_FWSTATS_ADD(rx, dropped); + DEBUGFS_FWSTATS_ADD(rx, fcs_err); + DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_ADD(rx, path_reset); + DEBUGFS_FWSTATS_ADD(rx, reset_counter); + + DEBUGFS_FWSTATS_ADD(dma, rx_requested); + DEBUGFS_FWSTATS_ADD(dma, rx_errors); + DEBUGFS_FWSTATS_ADD(dma, tx_requested); + DEBUGFS_FWSTATS_ADD(dma, tx_errors); + + DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); + DEBUGFS_FWSTATS_ADD(isr, fiqs); + DEBUGFS_FWSTATS_ADD(isr, rx_headers); + DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_ADD(isr, rx_rdys); + DEBUGFS_FWSTATS_ADD(isr, irqs); + DEBUGFS_FWSTATS_ADD(isr, tx_procs); + DEBUGFS_FWSTATS_ADD(isr, decrypt_done); + DEBUGFS_FWSTATS_ADD(isr, dma0_done); + DEBUGFS_FWSTATS_ADD(isr, dma1_done); + DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); + DEBUGFS_FWSTATS_ADD(isr, commands); + DEBUGFS_FWSTATS_ADD(isr, rx_procs); + DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); + DEBUGFS_FWSTATS_ADD(isr, pci_pm); + DEBUGFS_FWSTATS_ADD(isr, wakeups); + DEBUGFS_FWSTATS_ADD(isr, low_rssi); + + DEBUGFS_FWSTATS_ADD(wep, addr_key_count); + DEBUGFS_FWSTATS_ADD(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_ADD(wep, key_not_found); + DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); + DEBUGFS_FWSTATS_ADD(wep, packets); + DEBUGFS_FWSTATS_ADD(wep, interrupt); + + DEBUGFS_FWSTATS_ADD(pwr, ps_enter); + DEBUGFS_FWSTATS_ADD(pwr, elp_enter); + DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); + DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); + DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_ADD(pwr, power_save_off); + DEBUGFS_FWSTATS_ADD(pwr, enable_ps); + DEBUGFS_FWSTATS_ADD(pwr, disable_ps); + DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_ADD(mic, rx_pkts); + DEBUGFS_FWSTATS_ADD(mic, calc_failure); + + DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_ADD(event, heart_beat); + DEBUGFS_FWSTATS_ADD(event, calibration); + DEBUGFS_FWSTATS_ADD(event, rx_mismatch); + DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); + DEBUGFS_FWSTATS_ADD(event, rx_pool); + DEBUGFS_FWSTATS_ADD(event, oom_late); + DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); + DEBUGFS_FWSTATS_ADD(event, tx_stuck); + + DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); + DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); + + DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl12xx_debugfs_delete_files(wl); + + return ret; +} + +void wl12xx_debugfs_reset(struct wl12xx *wl) +{ + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl12xx_debugfs_init(struct wl12xx *wl) +{ + int ret; + + wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(wl->debugfs.rootdir)) { + ret = PTR_ERR(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + goto err; + } + + wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", + wl->debugfs.rootdir); + + if (IS_ERR(wl->debugfs.fw_statistics)) { + ret = PTR_ERR(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + goto err_root; + } + + wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), + GFP_KERNEL); + + if (!wl->stats.fw_stats) { + ret = -ENOMEM; + goto err_fw; + } + + wl->stats.fw_stats_update = jiffies; + + ret = wl12xx_debugfs_add_files(wl); + + if (ret < 0) + goto err_file; + + return 0; + +err_file: + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + +err_fw: + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + +err_root: + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +err: + return ret; +} + +void wl12xx_debugfs_exit(struct wl12xx *wl) +{ + wl12xx_debugfs_delete_files(wl); + + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +} diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/debugfs.h new file mode 100644 index 0000000..562cdcb --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.h @@ -0,0 +1,33 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef WL12XX_DEBUGFS_H +#define WL12XX_DEBUGFS_H + +#include "wl12xx.h" + +int wl12xx_debugfs_init(struct wl12xx *wl); +void wl12xx_debugfs_exit(struct wl12xx *wl); +void wl12xx_debugfs_reset(struct wl12xx *wl); + +#endif /* WL12XX_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c new file mode 100644 index 0000000..99529ca --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.c @@ -0,0 +1,127 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "event.h" +#include "ps.h" + +static int wl12xx_event_scan_complete(struct wl12xx *wl, + struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", + mbox->scheduled_scan_status, + mbox->scheduled_scan_channels); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + return 0; +} + +static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + + wl12xx_event_mbox_dump(mbox); + + vector = mbox->events_vector & ~(mbox->events_mask); + wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + ret = wl12xx_event_scan_complete(wl, mbox); + if (ret < 0) + return ret; + } + + if (vector & BSS_LOSE_EVENT_ID) { + wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + + if (wl->psm_requested && wl->psm) { + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int wl12xx_event_unmask(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl12xx_event_mbox_config(struct wl12xx *wl) +{ + wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox)); + + /* process the descriptor */ + ret = wl12xx_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h new file mode 100644 index 0000000..1f4c2f7 --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.h @@ -0,0 +1,121 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_EVENT_H__ +#define __WL12XX_EVENT_H__ + +/* + * Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + RESERVED1_EVENT_ID = BIT(0), + RESERVED2_EVENT_ID = BIT(1), + MEASUREMENT_START_EVENT_ID = BIT(2), + SCAN_COMPLETE_EVENT_ID = BIT(3), + CALIBRATION_COMPLETE_EVENT_ID = BIT(4), + ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), + PS_REPORT_EVENT_ID = BIT(6), + SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), + HEALTH_REPORT_EVENT_ID = BIT(8), + ACI_DETECTION_EVENT_ID = BIT(9), + DEBUG_REPORT_EVENT_ID = BIT(10), + MAC_STATUS_EVENT_ID = BIT(11), + DISCONNECT_EVENT_COMPLETE_ID = BIT(12), + JOIN_EVENT_COMPLETE_ID = BIT(13), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), + BSS_LOSE_EVENT_ID = BIT(15), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), + RESET_BSS_EVENT_ID = BIT(21), + REGAINED_BSS_EVENT_ID = BIT(22), + ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), + ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), + ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), + + DBG_EVENT_ID = BIT(26), + BT_PTA_SENSE_EVENT_ID = BIT(27), + BT_PTA_PREDICTION_EVENT_ID = BIT(28), + BT_PTA_AVALANCHE_EVENT_ID = BIT(29), + + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), + + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + u16 pad; + u32 report_1; + u32 report_2; + u32 report_3; +} __attribute__ ((packed)); + +struct event_mailbox { + u32 events_vector; + u32 events_mask; + u32 reserved_1; + u32 reserved_2; + + char average_rssi_level; + u8 ps_status; + u8 channel_switch_status; + u8 scheduled_scan_status; + + /* Channels scanned by the scheduled scan */ + u16 scheduled_scan_channels; + + /* If bit 0 is set -> target's fatal error */ + u16 health_report; + u16 bad_fft_counter; + u8 bt_pta_sense_info; + u8 bt_pta_protective_info; + u32 reserved; + u32 debug_report[2]; + + /* Number of FCS errors since last event */ + u32 fcs_err_counter; + + struct event_debug_report report; + u8 average_snr_level; + u8 padding[19]; +} __attribute__ ((packed)); + +int wl12xx_event_unmask(struct wl12xx *wl); +void wl12xx_event_mbox_config(struct wl12xx *wl); +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); + +#endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c new file mode 100644 index 0000000..2a573a6 --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.c @@ -0,0 +1,200 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "init.h" +#include "wl12xx_80211.h" +#include "acx.h" +#include "cmd.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_feature_cfg(wl); + if (ret < 0) { + wl12xx_warning("couldn't set feature config"); + return ret; + } + + ret = wl12xx_acx_default_key(wl, wl->default_key); + if (ret < 0) { + wl12xx_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +int wl12xx_hw_init_templates_config(struct wl12xx *wl) +{ + int ret; + u8 partial_vbm[PARTIAL_VBM_MAX]; + + /* send empty templates for fw memory reservation */ + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, + sizeof + (struct wl12xx_probe_resp_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template)); + if (ret < 0) + return ret; + + /* tim templates, first reserve space then allocate an empty one */ + memset(partial_vbm, 0, PARTIAL_VBM_MAX); + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_phy_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl12xx_acx_group_address_tbl(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_beacon_filter_opt(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_pta(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_sg_enable(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_energy_detection(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_power_auth(struct wl12xx *wl) +{ + return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); +} diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h new file mode 100644 index 0000000..c8b6cd0 --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_INIT_H__ +#define __WL12XX_INIT_H__ + +#include "wl12xx.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); +int wl12xx_hw_init_templates_config(struct wl12xx *wl); +int wl12xx_hw_init_mem_config(struct wl12xx *wl); +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_hw_init_phy_config(struct wl12xx *wl); +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); +int wl12xx_hw_init_pta(struct wl12xx *wl); +int wl12xx_hw_init_energy_detection(struct wl12xx *wl); +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); +int wl12xx_hw_init_power_auth(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c new file mode 100644 index 0000000..744f4ce --- /dev/null +++ b/drivers/net/wireless/wl12xx/main.c @@ -0,0 +1,1358 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251.h" +#include "spi.h" +#include "event.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" +#include "debugfs.h" + +static void wl12xx_disable_interrupts(struct wl12xx *wl) +{ + disable_irq(wl->irq); +} + +static void wl12xx_power_off(struct wl12xx *wl) +{ + wl->set_power(false); +} + +static void wl12xx_power_on(struct wl12xx *wl) +{ + wl->set_power(true); +} + +static irqreturn_t wl12xx_irq(int irq, void *cookie) +{ + struct wl12xx *wl; + + wl12xx_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + schedule_work(&wl->irq_work); + + return IRQ_HANDLED; +} + +static int wl12xx_fetch_firmware(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("firmware size is not multiple of 32 bits: %d", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + + if (!wl->fw) { + wl12xx_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl12xx_fetch_nvs(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get nvs file: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("nvs size is not multiple of 32 bits: %d", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->nvs_len = fw->size; + wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); + + if (!wl->nvs) { + wl12xx_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, fw->data, wl->nvs_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static void wl12xx_fw_wakeup(struct wl12xx *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + if (!(elp_reg & ELPCTRL_WLAN_READY)) { + wl12xx_warning("WLAN not ready"); + elp_reg = ELPCTRL_WAKE_UP_WLAN_READY; + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + } +} + +static int wl12xx_chip_wakeup(struct wl12xx *wl) +{ + int ret = 0; + + wl12xx_power_on(wl); + msleep(wl->chip.power_on_sleep); + wl12xx_spi_reset(wl); + wl12xx_spi_init(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + wl12xx_set_partition(wl, + 0x00000000, + 0x00000000, + REGISTERS_BASE, + REGISTERS_DOWN_SIZE); + + /* ELP module wake up */ + wl12xx_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip.id) { + case CHIP_ID_1251_PG12: + wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", + wl->chip.id); + + wl1251_setup(wl); + + break; + case CHIP_ID_1271_PG10: + case CHIP_ID_1251_PG10: + case CHIP_ID_1251_PG11: + default: + wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl12xx_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl12xx_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +static void wl12xx_filter_work(struct work_struct *work) +{ + struct wl12xx *wl = + container_of(work, struct wl12xx, filter_work); + int ret; + + mutex_lock(&wl->mutex); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out; + +out: + mutex_unlock(&wl->mutex); +} + +int wl12xx_plt_start(struct wl12xx *wl) +{ + int ret; + + wl12xx_notice("power up"); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + return -EBUSY; + } + + wl->state = WL12XX_STATE_PLT; + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + return ret; + + wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + + ret = wl->chip.op_plt_init(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_plt_stop(struct wl12xx *wl) +{ + wl12xx_notice("power down"); + + if (wl->state != WL12XX_STATE_PLT) { + wl12xx_error("cannot power down because not in PLT " + "state: %d", wl->state); + return -EBUSY; + } + + wl12xx_disable_interrupts(wl); + wl12xx_power_off(wl); + + wl->state = WL12XX_STATE_OFF; + + return 0; +} + + +static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl12xx *wl = hw->priv; + + skb_queue_tail(&wl->tx_queue, skb); + + schedule_work(&wl->tx_work); + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { + ieee80211_stop_queues(wl->hw); + + /* + * FIXME: this is racy, the variable is not properly + * protected. Maybe fix this by removing the stupid + * variable altogether and checking the real queue state? + */ + wl->tx_queue_stopped = true; + } + + return NETDEV_TX_OK; +} + +static int wl12xx_op_start(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); + + mutex_lock(&wl->mutex); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + goto out; + + ret = wl->chip.op_hw_init(wl); + if (ret < 0) + goto out; + + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + + wl->state = WL12XX_STATE_ON; + + wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); + +out: + if (ret < 0) + wl12xx_power_off(wl); + + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl12xx_op_stop(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_info("down"); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + WARN_ON(wl->state != WL12XX_STATE_ON); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, true); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + wl->state = WL12XX_STATE_OFF; + + wl12xx_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl12xx_tx_flush(wl); + + wl12xx_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + wl->listen_int = 1; + wl->bss_type = MAX_BSS_TYPE; + + wl->data_in_count = 0; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->next_tx_complete = 0; + wl->elp = false; + wl->psm = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + wl12xx_debugfs_reset(wl); + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct wl12xx *wl = hw->priv; + DECLARE_MAC_BUF(mac); + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + conf->type, print_mac(mac, conf->mac_addr)); + + mutex_lock(&wl->mutex); + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); +} + +static int wl12xx_build_null_data(struct wl12xx *wl) +{ + struct wl12xx_null_data_template template; + + if (!is_zero_ether_addr(wl->bssid)) { + memcpy(template.header.da, wl->bssid, ETH_ALEN); + memcpy(template.header.bssid, wl->bssid, ETH_ALEN); + } else { + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + } + + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC); + + return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, + sizeof(template)); + +} + +static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) +{ + struct wl12xx_ps_poll_template template; + + memcpy(template.bssid, wl->bssid, ETH_ALEN); + memcpy(template.ta, wl->mac_addr, ETH_ALEN); + template.aid = aid; + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); + + return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, + sizeof(template)); + +} + +static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl12xx *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + + mutex_lock(&wl->mutex); + + if (channel != wl->channel) { + /* FIXME: use beacon interval provided by mac80211 */ + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out; + + wl->channel = channel; + } + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out; + + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl12xx_info("psm enabled"); + + wl->psm_requested = true; + + /* + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. + */ + ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else if (!(conf->flags & IEEE80211_CONF_PS) && + wl->psm_requested) { + wl12xx_info("psm disabled"); + + wl->psm_requested = false; + + if (wl->psm) + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + } + + if (conf->power_level != wl->power_level) { + ret = wl12xx_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out; + + wl->power_level = conf->power_level; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL12XX_SUPPORTED_FILTERS; + changed &= WL12XX_SUPPORTED_FILTERS; + + if (changed == 0) + /* no filters which we support changed */ + return; + + /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + + if (*total & FIF_PROMISC_IN_BSS) { + wl->rx_config |= CFG_BSSID_FILTER_EN; + wl->rx_config |= CFG_RX_ALL_GOOD; + } + if (*total & FIF_ALLMULTI) + /* + * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive + * all multicast frames + */ + wl->rx_config &= ~CFG_MC_FILTER_EN; + if (*total & FIF_FCSFAIL) + wl->rx_filter |= CFG_RX_FCS_ERROR; + if (*total & FIF_BCN_PRBRESP_PROMISC) { + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_SSID_FILTER_EN; + } + if (*total & FIF_CONTROL) + wl->rx_filter |= CFG_RX_CTL_EN; + if (*total & FIF_OTHER_BSS) + wl->rx_filter &= ~CFG_BSSID_FILTER_EN; + + /* + * FIXME: workqueues need to be properly cancelled on stop(), for + * now let's just disable changing the filter settings. They will + * be updated any on config(). + */ + /* schedule_work(&wl->filter_work); */ +} + +/* HW encryption */ +static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key, + enum set_key_cmd cmd, + struct ieee80211_key_conf *mac80211_key, + const u8 *addr) +{ + switch (mac80211_key->alg) { + case ALG_WEP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_WEP_DEFAULT; + else + key->key_type = KEY_WEP_ADDR; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_TKIP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_TKIP_MIC_GROUP; + else + key->key_type = KEY_TKIP_MIC_PAIRWISE; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_CCMP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_AES_GROUP; + else + key->key_type = KEY_AES_PAIRWISE; + mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); + return -EOPNOTSUPP; + } + + return 0; +} + +static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct wl12xx *wl = hw->priv; + struct acx_set_key wl_key; + const u8 *addr; + int ret; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); + + memset(&wl_key, 0, sizeof(wl_key)); + + addr = sta ? sta->addr : bcast_addr; + + wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key->alg, key->keyidx, key->keylen, key->flags); + wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + + mutex_lock(&wl->mutex); + + switch (cmd) { + case SET_KEY: + wl_key.key_action = KEY_ADD_OR_REPLACE; + break; + case DISABLE_KEY: + wl_key.key_action = KEY_REMOVE; + break; + default: + wl12xx_error("Unsupported key cmd 0x%x", cmd); + break; + } + + ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr); + if (ret < 0) { + wl12xx_error("Set KEY type failed"); + goto out; + } + + if (wl_key.key_type != KEY_WEP_DEFAULT) + memcpy(wl_key.addr, addr, ETH_ALEN); + + if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) || + (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(wl_key.key, key->key, 16); + memcpy(wl_key.key + 16, key->key + 24, 8); + memcpy(wl_key.key + 24, key->key + 16, 8); + + } else { + memcpy(wl_key.key, key->key, key->keylen); + } + wl_key.key_size = key->keylen; + + wl_key.id = key->keyidx; + wl_key.ssid_profile = 0; + + wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key)); + + if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) { + wl12xx_error("Set KEY failed"); + ret = -EOPNOTSUPP; + goto out; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static int wl12xx_build_basic_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + return index; +} + +static int wl12xx_build_extended_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + + return index; +} + + +static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) +{ + struct wl12xx_probe_req_template template; + struct wl12xx_ie_rates *rates; + char *ptr; + u16 size; + + ptr = (char *)&template; + size = sizeof(struct ieee80211_header); + + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + + /* IEs */ + /* SSID */ + template.ssid.header.id = WLAN_EID_SSID; + template.ssid.header.len = ssid_len; + if (ssid_len && ssid) + memcpy(template.ssid.ssid, ssid, ssid_len); + size += sizeof(struct wl12xx_ie_header) + ssid_len; + ptr += size; + + /* Basic Rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_SUPP_RATES; + rates->header.len = wl12xx_build_basic_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; + + /* Extended rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_EXT_SUPP_RATES; + rates->header.len = wl12xx_build_extended_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + + wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + + return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, + size); +} + +static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests) +{ + int i, ret; + u32 split_scan = 0; + u16 scan_options = 0; + struct cmd_scan *params; + struct wl12xx_command *cmd_answer; + + if (wl->scanning) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + /* High priority scan */ + if (!active_scan) + scan_options |= SCAN_PASSIVE; + if (high_prio) + scan_options |= SCAN_PRIORITY_HIGH; + params->params.scan_options = scan_options; + + params->params.num_channels = num_channels; + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ + params->params.tid_trigger = 0; + + for (i = 0; i < num_channels; i++) { + params->channels[i].min_duration = cpu_to_le32(30000); + params->channels[i].max_duration = cpu_to_le32(60000); + memset(¶ms->channels[i].bssid_lsb, 0xff, 4); + memset(¶ms->channels[i].bssid_msb, 0xff, 2); + params->channels[i].early_termination = 0; + params->channels[i].tx_power_att = 0; + params->channels[i].channel = i + 1; + memset(params->channels[i].pad, 0, 3); + } + + for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) + memset(¶ms->channels[i], 0, + sizeof(struct basic_scan_channel_parameters)); + + if (len && ssid) { + params->params.ssid_len = len; + memcpy(params->params.ssid, ssid, len); + } else { + params->params.ssid_len = 0; + memset(params->params.ssid, 0, 32); + } + + ret = wl12xx_build_probe_req(wl, ssid, len); + if (ret < 0) { + wl12xx_error("PROBE request template failed"); + goto out; + } + + ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan, + sizeof(u32)); + if (ret < 0) { + wl12xx_error("Split SCAN failed"); + goto out; + } + + wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + wl->scanning = true; + + ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + if (ret < 0) + wl12xx_error("SCAN failed"); + + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + + cmd_answer = (struct wl12xx_command *) params; + if (cmd_answer->status != CMD_STATUS_SUCCESS) { + wl12xx_error("TEST command answer error: %d", + cmd_answer->status); + wl->scanning = false; + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; + +} + +static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + struct wl12xx *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl12xx *wl = hw->priv; + int ret; + + ret = wl12xx_acx_rts_threshold(wl, (u16) value); + + if (ret < 0) + wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + + return ret; +} + +static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + enum acx_ps_mode mode; + struct wl12xx *wl = hw->priv; + struct sk_buff *beacon; + int ret; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + wl->aid = bss_conf->aid; + + ret = wl12xx_build_ps_poll(wl, wl->aid); + if (ret < 0) + goto out; + + ret = wl12xx_acx_aid(wl, wl->aid); + if (ret < 0) + goto out; + + /* If we want to go in PSM but we're not there yet */ + if (wl->psm_requested && !wl->psm) { + mode = STATION_POWER_SAVE_MODE; + ret = wl12xx_ps_set_mode(wl, mode); + if (ret < 0) + goto out; + } + } + } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl12xx_warning("Set slot time failed %d", ret); + goto out; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl12xx_warning("Set ctsprotect failed %d", ret); + goto out; + } + } + + if (changed & BSS_CHANGED_BSSID) { + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out; + + if (wl->bss_type != BSS_TYPE_IBSS) { + ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1); + if (ret < 0) + goto out; + } + } + + if (changed & BSS_CHANGED_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, + beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, + beacon->len); + + dev_kfree_skb(beacon); + + if (ret < 0) + goto out; + + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&wl->mutex); +} + + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl12xx_rates[] = { + { .bitrate = 10, + .hw_value = 0x1, + .hw_value_short = 0x1, }, + { .bitrate = 20, + .hw_value = 0x2, + .hw_value_short = 0x2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 0x4, + .hw_value_short = 0x4, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 0x20, + .hw_value_short = 0x20, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 0x8, + .hw_value_short = 0x8, }, + { .bitrate = 90, + .hw_value = 0x10, + .hw_value_short = 0x10, }, + { .bitrate = 120, + .hw_value = 0x40, + .hw_value_short = 0x40, }, + { .bitrate = 180, + .hw_value = 0x80, + .hw_value_short = 0x80, }, + { .bitrate = 240, + .hw_value = 0x200, + .hw_value_short = 0x200, }, + { .bitrate = 360, + .hw_value = 0x400, + .hw_value_short = 0x400, }, + { .bitrate = 480, + .hw_value = 0x800, + .hw_value_short = 0x800, }, + { .bitrate = 540, + .hw_value = 0x1000, + .hw_value_short = 0x1000, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl12xx_channels[] = { + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl12xx_band_2ghz = { + .channels = wl12xx_channels, + .n_channels = ARRAY_SIZE(wl12xx_channels), + .bitrates = wl12xx_rates, + .n_bitrates = ARRAY_SIZE(wl12xx_rates), +}; + +static const struct ieee80211_ops wl12xx_ops = { + .start = wl12xx_op_start, + .stop = wl12xx_op_stop, + .add_interface = wl12xx_op_add_interface, + .remove_interface = wl12xx_op_remove_interface, + .config = wl12xx_op_config, + .configure_filter = wl12xx_op_configure_filter, + .tx = wl12xx_op_tx, + .set_key = wl12xx_op_set_key, + .hw_scan = wl12xx_op_hw_scan, + .bss_info_changed = wl12xx_op_bss_info_changed, + .set_rts_threshold = wl12xx_op_set_rts_threshold, +}; + +static int wl12xx_register_hw(struct wl12xx *wl) +{ + int ret; + + if (wl->mac80211_registered) + return 0; + + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl12xx_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + wl12xx_notice("loaded"); + + return 0; +} + +static int wl12xx_init_ieee80211(struct wl12xx *wl) +{ + /* The tx descriptor buffer and the TKIP space */ + wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) + + WL12XX_TKIP_IV_SPACE; + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; + + SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + + return 0; +} + +#define WL12XX_DEFAULT_CHANNEL 1 +static int __devinit wl12xx_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl12xx *wl; + int ret, i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl12xx_error("no platform data"); + return -ENODEV; + } + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); + if (!hw) { + wl12xx_error("could not alloc ieee80211_hw"); + return -ENOMEM; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->hw = hw; + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + + wl->data_in_count = 0; + + skb_queue_head_init(&wl->tx_queue); + + INIT_WORK(&wl->tx_work, wl12xx_tx_work); + INIT_WORK(&wl->filter_work, wl12xx_filter_work); + wl->channel = WL12XX_DEFAULT_CHANNEL; + wl->scanning = false; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + /* We use the default power on sleep time until we know which chip + * we're using */ + wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; + + wl->next_tx_complete = 0; + + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + + wl->state = WL12XX_STATE_OFF; + mutex_init(&wl->mutex); + + wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; + wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl12xx_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl12xx_error("set power function missing in platform data"); + return -ENODEV; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl12xx_error("irq missing in platform data"); + return -ENODEV; + } + + ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl12xx_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl12xx_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl12xx_register_hw(wl); + if (ret) + goto out_irq; + + wl12xx_debugfs_init(wl); + + wl12xx_notice("initialized"); + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl12xx_remove(struct spi_device *spi) +{ + struct wl12xx *wl = dev_get_drvdata(&spi->dev); + + ieee80211_unregister_hw(wl->hw); + + wl12xx_debugfs_exit(wl); + + free_irq(wl->irq, wl); + kfree(wl->target_mem_map); + kfree(wl->data_path); + kfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + ieee80211_free_hw(wl->hw); + + return 0; +} + + +static struct spi_driver wl12xx_spi_driver = { + .driver = { + .name = "wl12xx", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl12xx_probe, + .remove = __devexit_p(wl12xx_remove), +}; + +static int __init wl12xx_init(void) +{ + int ret; + + ret = spi_register_driver(&wl12xx_spi_driver); + if (ret < 0) { + wl12xx_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl12xx_exit(void) +{ + spi_unregister_driver(&wl12xx_spi_driver); + + wl12xx_notice("unloaded"); +} + +module_init(wl12xx_init); +module_exit(wl12xx_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo , " + "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c new file mode 100644 index 0000000..83a1011 --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.c @@ -0,0 +1,151 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "reg.h" +#include "ps.h" +#include "spi.h" + +#define WL12XX_WAKEUP_TIMEOUT 2000 + +/* Routines to toggle sleep mode while in ELP */ +void wl12xx_ps_elp_sleep(struct wl12xx *wl) +{ + if (wl->elp || !wl->psm) + return; + + wl12xx_debug(DEBUG_PSM, "chip to elp"); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + + wl->elp = true; +} + +int wl12xx_ps_elp_wakeup(struct wl12xx *wl) +{ + unsigned long timeout; + u32 elp_reg; + + if (!wl->elp) + return 0; + + wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); + + timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + /* + * FIXME: we should wait for irq from chip but, as a temporary + * solution to simplify locking, let's poll instead + */ + while (!(elp_reg & ELPCTRL_WLAN_READY)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("elp wakeup timeout"); + return -ETIMEDOUT; + } + msleep(1); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + } + + wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); + + wl->elp = false; + + return 0; +} + +static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) +{ + int ret; + + if (enable) { + wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); + + /* + * FIXME: we should PSM_ELP, but because of firmware wakeup + * problems let's use only PSM_PS + */ + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS); + if (ret < 0) + return ret; + + wl12xx_ps_elp_sleep(wl); + } else { + wl12xx_debug(DEBUG_PSM, "sleep auth cam"); + + /* + * When the target is in ELP, we can only + * access the ELP control register. Thus, + * we have to wake the target up before + * changing the power authorization. + */ + + wl12xx_ps_elp_wakeup(wl); + + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + if (ret < 0) + return ret; + } + + return 0; +} + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl12xx_debug(DEBUG_PSM, "entering psm"); + ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + ret = wl12xx_ps_set_elp(wl, true); + if (ret < 0) + return ret; + + wl->psm = 1; + break; + case STATION_ACTIVE_MODE: + default: + wl12xx_debug(DEBUG_PSM, "leaving psm"); + ret = wl12xx_ps_set_elp(wl, false); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + + wl->psm = 0; + break; + } + + return ret; +} + diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h new file mode 100644 index 0000000..5d7c525 --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.h @@ -0,0 +1,36 @@ +#ifndef __WL12XX_PS_H__ +#define __WL12XX_PS_H__ + +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "acx.h" + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode); +void wl12xx_ps_elp_sleep(struct wl12xx *wl); +int wl12xx_ps_elp_wakeup(struct wl12xx *wl); + + +#endif /* __WL12XX_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h new file mode 100644 index 0000000..e421643 --- /dev/null +++ b/drivers/net/wireless/wl12xx/reg.h @@ -0,0 +1,745 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include +#include "wl12xx.h" + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/* + * Interrupt registers. + * 64 bit interrupt sources registers ws ced. + * sme interupts were removed and new ones were added. + * Order was changed. + */ +#define FIQ_MASK (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) +#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) +#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) +#define IRQ_MASK (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) +#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) +#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) +#define ECPU_MASK (REGISTERS_BASE + 0x0448) +#define FIQ_STS_L (REGISTERS_BASE + 0x044C) +#define FIQ_STS_H (REGISTERS_BASE + 0x0450) +#define IRQ_STS_L (REGISTERS_BASE + 0x0454) +#define IRQ_STS_H (REGISTERS_BASE + 0x0458) +#define INT_STS_ND (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) +#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) +#define INT_ACK (REGISTERS_BASE + 0x046C) +#define INT_ACK_L (REGISTERS_BASE + 0x046C) +#define INT_ACK_H (REGISTERS_BASE + 0x0470) +#define INT_TRIG (REGISTERS_BASE + 0x0474) +#define INT_TRIG_L (REGISTERS_BASE + 0x0474) +#define INT_TRIG_H (REGISTERS_BASE + 0x0478) +#define HOST_STS_L (REGISTERS_BASE + 0x045C) +#define HOST_STS_H (REGISTERS_BASE + 0x0460) +#define HOST_MASK (REGISTERS_BASE + 0x0430) +#define HOST_MASK_L (REGISTERS_BASE + 0x0430) +#define HOST_MASK_H (REGISTERS_BASE + 0x0434) +#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) +#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) + +/* Host Interrupts*/ +#define HINT_MASK (REGISTERS_BASE + 0x0494) +#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) +#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) +#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) +/*1150 spec calls this HINT_STS_RAW*/ +#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) +#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) +#define HINT_ACK (REGISTERS_BASE + 0x04A8) +#define HINT_TRIG (REGISTERS_BASE + 0x04AC) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) +#define ECPU_CTRL (REGISTERS_BASE + 0x0804) +#define HI_CFG (REGISTERS_BASE + 0x0808) +#define EE_START (REGISTERS_BASE + 0x080C) + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) + +#define ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define ELP_CMD (REGISTERS_BASE + 0x5808) +#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define SPARE_A1 (REGISTERS_BASE + 0x0994) +#define SPARE_A2 (REGISTERS_BASE + 0x0998) +#define SPARE_A3 (REGISTERS_BASE + 0x099C) +#define SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define SPARE_B1 (REGISTERS_BASE + 0x5420) +#define SPARE_B2 (REGISTERS_BASE + 0x5424) +#define SPARE_B3 (REGISTERS_BASE + 0x5428) +#define SPARE_B4 (REGISTERS_BASE + 0x542C) +#define SPARE_B5 (REGISTERS_BASE + 0x5430) +#define SPARE_B6 (REGISTERS_BASE + 0x5434) +#define SPARE_B7 (REGISTERS_BASE + 0x5438) +#define SPARE_B8 (REGISTERS_BASE + 0x543C) + +enum wl12xx_acx_int_reg { + ACX_REG_INTERRUPT_TRIG, + ACX_REG_INTERRUPT_TRIG_H, + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ + ACX_REG_INTERRUPT_MASK, + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ + ACX_REG_HINT_MASK_SET, + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ + ACX_REG_HINT_MASK_CLR, + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ + ACX_REG_INTERRUPT_NO_CLEAR, + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ + ACX_REG_INTERRUPT_CLEAR, + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ + ACX_REG_INTERRUPT_ACK, + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ + ACX_REG_SLV_SOFT_RESET, + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ + ACX_REG_EE_START, + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ + ACX_REG_ECPU_CONTROL, + + ACX_REG_TABLE_LEN +}; + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) + + +/* Misc */ + +#define REG_ENABLE_TX_RX (ENABLE) +/* + * Rx configuration (filter) information element + * --------------------------------------------- + */ +#define REG_RX_CONFIG (RX_CFG) +#define REG_RX_FILTER (RX_FILTER_CFG) + + +#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 + +/* promiscuous - receives all valid frames */ +#define RX_CFG_PROMISCUOUS 0x0008 + +/* receives frames from any BSSID */ +#define RX_CFG_BSSID 0x0020 + +/* receives frames destined to any MAC address */ +#define RX_CFG_MAC 0x0010 + +#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 +#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 +#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 +#define RX_CFG_ENABLE_ANY_BSSID 0x0000 + +/* discards all broadcast frames */ +#define RX_CFG_DISABLE_BCAST 0x0200 + +#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 +#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 +#define RX_CFG_COPY_RX_STATUS 0x2000 +#define RX_CFG_TSF 0x10000 + +#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ + | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ + | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) + +#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ + | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define RX_FILTER_OPTION_FILTER_ALL 0 + +#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ + | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) + +#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ + | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ + | CFG_RX_PRSP_EN) + + +/*=============================================== + Phy regs + ===============================================*/ +#define ACX_PHY_ADDR_REG SBB_ADDR +#define ACX_PHY_DATA_REG SBB_DATA +#define ACX_PHY_CTRL_REG SBB_CTL +#define ACX_PHY_REG_WR_MASK 0x00000001ul +#define ACX_PHY_REG_RD_MASK 0x00000002ul + + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define ACX_EE_DATA_REG EE_DATA + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +/* + * Indirect slave register/memory registers + * ---------------------------------------- + */ +#define HW_SLAVE_REG_ADDR_REG 0x00000004 +#define HW_SLAVE_REG_DATA_REG 0x00000008 +#define HW_SLAVE_REG_CTRL_REG 0x0000000c + +#define SLAVE_AUTO_INC 0x00010000 +#define SLAVE_NO_AUTO_INC 0x00000000 +#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 + +#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR +#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA +#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL +#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL + +#define HW_FUNC_EVENT_INT_EN 0x8000 +#define HW_FUNC_EVENT_MASK_REG 0x00000034 + +#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +/* + * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile + * for platforms using active high interrupt level + */ +#ifdef USE_ACTIVE_HIGH +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +#else +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#endif + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) +#define USE_EEPROM 0 +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 512 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +#define ECPU_CONTROL_HALT 0x00000101 + + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + + +enum { + RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ + RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ + RADIO_BAND_JAPAN_4_9_GHZ = 2, + DEFAULT_BAND = RADIO_BAND_2_4GHZ, + INVALID_BAND = 0xFE, + MAX_RADIO_BANDS = 0xFF +}; + +enum { + NO_RATE = 0, + RATE_1MBPS = 0x0A, + RATE_2MBPS = 0x14, + RATE_5_5MBPS = 0x37, + RATE_6MBPS = 0x0B, + RATE_9MBPS = 0x0F, + RATE_11MBPS = 0x6E, + RATE_12MBPS = 0x0A, + RATE_18MBPS = 0x0E, + RATE_22MBPS = 0xDC, + RATE_24MBPS = 0x09, + RATE_36MBPS = 0x0D, + RATE_48MBPS = 0x08, + RATE_54MBPS = 0x0C +}; + +enum { + RATE_INDEX_1MBPS = 0, + RATE_INDEX_2MBPS = 1, + RATE_INDEX_5_5MBPS = 2, + RATE_INDEX_6MBPS = 3, + RATE_INDEX_9MBPS = 4, + RATE_INDEX_11MBPS = 5, + RATE_INDEX_12MBPS = 6, + RATE_INDEX_18MBPS = 7, + RATE_INDEX_22MBPS = 8, + RATE_INDEX_24MBPS = 9, + RATE_INDEX_36MBPS = 10, + RATE_INDEX_48MBPS = 11, + RATE_INDEX_54MBPS = 12, + RATE_INDEX_MAX = RATE_INDEX_54MBPS, + MAX_RATE_INDEX, + INVALID_RATE_INDEX = MAX_RATE_INDEX, + RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF +}; + +enum { + RATE_MASK_1MBPS = 0x1, + RATE_MASK_2MBPS = 0x2, + RATE_MASK_5_5MBPS = 0x4, + RATE_MASK_11MBPS = 0x20, +}; + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + + +#define TNETW1251_CHIP_ID_PG1_0 0x07010101 +#define TNETW1251_CHIP_ID_PG1_1 0x07020101 +#define TNETW1251_CHIP_ID_PG1_2 0x07030101 + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define INTR_TRIG_EVENT_ACK BIT(1) + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#endif diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c new file mode 100644 index 0000000..981ea25 --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.c @@ -0,0 +1,208 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "rx.h" + +static void wl12xx_rx_header(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + u32 rx_packet_ring_addr; + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, + sizeof(struct wl12xx_rx_descriptor)); +} + +static void wl12xx_rx_status(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + status->band = IEEE80211_BAND_2GHZ; + status->mactime = desc->timestamp; + + /* + * The rx status timestamp is a 32 bits value while the TSF is a + * 64 bits one. + * For IBSS merging, TSF is mandatory, so we have to get it + * somehow, so we ask for ACX_TSF_INFO. + * That could be moved to the get_tsf() hook, but unfortunately, + * this one must be atomic, while our SPI routines can sleep. + */ + if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { + u64 mactime; + int ret; + struct wl12xx_command cmd; + struct acx_tsf_info *tsf_info; + + memset(&cmd, 0, sizeof(cmd)); + + ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + sizeof(struct acx_tsf_info), + &cmd); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + return; + } + + tsf_info = (struct acx_tsf_info *)&(cmd.parameters); + + mactime = tsf_info->current_tsf_lsb | + (tsf_info->current_tsf_msb << 31); + + status->mactime = mactime; + } + + status->signal = desc->rssi; + status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / + (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); + status->qual = min(status->qual, 100); + status->qual = max(status->qual, 0); + + /* + * FIXME: guessing that snr needs to be divided by two, otherwise + * the values don't make any sense + */ + status->noise = desc->rssi - desc->snr / 2; + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + status->flag |= RX_FLAG_TSFT; + + if (desc->flags & RX_DESC_ENCRYPTION_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + + if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } + + if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + + /* FIXME: set status->rate_idx */ +} + +static void wl12xx_rx_body(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + struct sk_buff *skb; + struct ieee80211_rx_status status; + u8 *rx_buffer, beacon = 0; + u16 length, *fc; + u32 curr_id, last_id_inc, rx_packet_ring_addr; + + length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); + curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; + last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); + + if (last_id_inc != curr_id) { + wl12xx_warning("curr ID:%d, last ID inc:%d", + curr_id, last_id_inc); + wl->rx_last_id = curr_id; + } else { + wl->rx_last_id = last_id_inc; + } + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + + sizeof(struct wl12xx_rx_descriptor) + 20; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + skb = dev_alloc_skb(length); + if (!skb) { + wl12xx_error("Couldn't allocate RX frame"); + return; + } + + rx_buffer = skb_put(skb, length); + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + + /* The actual lenght doesn't include the target's alignment */ + skb->len = desc->length - PLCP_HEADER_LENGTH; + + fc = (u16 *)skb->data; + + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl12xx_rx_status(wl, desc, &status, beacon); + + wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + ieee80211_rx(wl->hw, skb, &status); +} + +static void wl12xx_rx_ack(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->rx_current_buffer) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_RX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_RX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Toggle buffer ring */ + wl->rx_current_buffer = !wl->rx_current_buffer; +} + + +void wl12xx_rx(struct wl12xx *wl) +{ + struct wl12xx_rx_descriptor rx_desc; + + if (wl->state != WL12XX_STATE_ON) + return; + + /* We first read the frame's header */ + wl12xx_rx_header(wl, &rx_desc); + + /* Now we can read the body */ + wl12xx_rx_body(wl, &rx_desc); + + /* Finally, we need to ACK the RX */ + wl12xx_rx_ack(wl); + + return; +} diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h new file mode 100644 index 0000000..8a23fde --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.h @@ -0,0 +1,122 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_RX_H__ +#define __WL12XX_RX_H__ + +#include + +/* + * RX PATH + * + * The Rx path uses a double buffer and an rx_contro structure, each located + * at a fixed address in the device memory. The host keeps track of which + * buffer is available and alternates between them on a per packet basis. + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet. + * The RX path goes like that: + * 1) The target generates an interrupt each time a new packet is received. + * There are 2 RX interrupts, one for each buffer. + * 2) The host reads the received packet from one of the double buffers. + * 3) The host triggers a target interrupt. + * 4) The target prepares the next RX packet. + */ + +#define WL12XX_RX_MAX_RSSI -30 +#define WL12XX_RX_MIN_RSSI -95 + +#define WL12XX_RX_ALIGN_TO 4 +#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ + ~(WL12XX_RX_ALIGN_TO - 1)) + +#define SHORT_PREAMBLE_BIT BIT(0) +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +#define PLCP_HEADER_LENGTH 8 +#define RX_DESC_PACKETID_SHIFT 11 +#define RX_MAX_PACKET_ID 3 + +#define RX_DESC_VALID_FCS 0x0001 +#define RX_DESC_MATCH_RXADDR1 0x0002 +#define RX_DESC_MCAST 0x0004 +#define RX_DESC_STAINTIM 0x0008 +#define RX_DESC_VIRTUAL_BM 0x0010 +#define RX_DESC_BCAST 0x0020 +#define RX_DESC_MATCH_SSID 0x0040 +#define RX_DESC_MATCH_BSSID 0x0080 +#define RX_DESC_ENCRYPTION_MASK 0x0300 +#define RX_DESC_MEASURMENT 0x0400 +#define RX_DESC_SEQNUM_MASK 0x1800 +#define RX_DESC_MIC_FAIL 0x2000 +#define RX_DESC_DECRYPT_FAIL 0x4000 + +struct wl12xx_rx_descriptor { + u32 timestamp; /* In microseconds */ + u16 length; /* Paylod length, including headers */ + u16 flags; + + /* + * 0 - 802.11 + * 1 - 802.3 + * 2 - IP + * 3 - Raw Codec + */ + u8 type; + + /* + * Recevied Rate: + * 0x0A - 1MBPS + * 0x14 - 2MBPS + * 0x37 - 5_5MBPS + * 0x0B - 6MBPS + * 0x0F - 9MBPS + * 0x6E - 11MBPS + * 0x0A - 12MBPS + * 0x0E - 18MBPS + * 0xDC - 22MBPS + * 0x09 - 24MBPS + * 0x0D - 36MBPS + * 0x08 - 48MBPS + * 0x0C - 54MBPS + */ + u8 rate; + + u8 mod_pre; /* Modulation and preamble */ + u8 channel; + + /* + * 0 - 2.4 Ghz + * 1 - 5 Ghz + */ + u8 band; + + s8 rssi; /* in dB */ + u8 rcpi; /* in dB */ + u8 snr; /* in dB */ +} __attribute__ ((packed)); + +void wl12xx_rx(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c new file mode 100644 index 0000000..abdf171 --- /dev/null +++ b/drivers/net/wireless/wl12xx/spi.c @@ -0,0 +1,358 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "spi.h" +#include "ps.h" + +static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) +{ + /* If the address is lower than REGISTERS_BASE, it means that this is + * a chip-specific register address, so look it up in the registers + * table */ + if (addr < REGISTERS_BASE) { + /* Make sure we don't go over the table */ + if (addr >= ACX_REG_TABLE_LEN) { + wl12xx_error("address out of range (%d)", addr); + return -EINVAL; + } + addr = wl->chip.acx_reg_table[addr]; + } + + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + + +void wl12xx_spi_reset(struct wl12xx *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi reset"); + return; + } + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + memset(cmd, 0xff, WSPI_INIT_CMD_LEN); + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +void wl12xx_spi_init(struct wl12xx *wl) +{ + u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi init"); + return; + } + + memset(crc, 0, sizeof(crc)); + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* + * Set WSPI_INIT_COMMAND + * the data is being send from the MSB to LSB + */ + cmd[2] = 0xff; + cmd[3] = 0xff; + cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; + cmd[0] = 0; + cmd[7] = 0; + cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; + cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + + if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) + cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; + else + cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; + + cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS + | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; + + crc[0] = cmd[1]; + crc[1] = cmd[0]; + crc[2] = cmd[7]; + crc[3] = cmd[6]; + crc[4] = cmd[5]; + + cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; + cmd[4] |= WSPI_INIT_CMD_END; + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); +} + +/* Set the SPI partitions to access the chip addresses + * + * There are two VIRTUAL (SPI) partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +void wl12xx_set_partition(struct wl12xx *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)]; + struct wl12xx_partition *partition; + struct spi_transfer t; + struct spi_message m; + u32 *cmd; + size_t len; + int addr; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + memset(tx_buf, 0, sizeof(tx_buf)); + + cmd = (u32 *) tx_buf; + partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32)); + addr = HW_ACCESS_PART0_SIZE_ADDR; + len = 2 * sizeof(struct wl12xx_partition); + + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + t.tx_buf = tx_buf; + t.len = sizeof(tx_buf); + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); +} + +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + struct spi_transfer t[3]; + struct spi_message m; + char busy_buf[TNETWIF_READ_OFFSET_BYTES]; + u32 cmd; + + cmd = 0; + cmd |= WSPI_CMD_READ; + cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + cmd |= addr & WSPI_CMD_BYTE_ADDR; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 4; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = TNETWIF_READ_OFFSET_BYTES; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = buf; + t[2].len = len; + spi_message_add_tail(&t[2], &m); + + spi_sync(wl->spi, &m); + + /* FIXME: check busy words */ + + wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); +} + +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 cmd; + + cmd = 0; + cmd |= WSPI_CMD_WRITE; + cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + cmd |= addr & WSPI_CMD_BYTE_ADDR; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = sizeof(cmd); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); +} + +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len); +} + +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len); +} + +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); +} + +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); +} + +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); +} + +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h new file mode 100644 index 0000000..fd3227e --- /dev/null +++ b/drivers/net/wireless/wl12xx/spi.h @@ -0,0 +1,109 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_SPI_H__ +#define __WL12XX_SPI_H__ + +#include "cmd.h" +#include "acx.h" +#include "reg.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +#define WSPI_CMD_READ 0x40000000 +#define WSPI_CMD_WRITE 0x00000000 +#define WSPI_CMD_FIXED 0x20000000 +#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 +#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 +#define WSPI_CMD_BYTE_ADDR 0x0001FFFF + +#define WSPI_INIT_CMD_CRC_LEN 5 + +#define WSPI_INIT_CMD_START 0x00 +#define WSPI_INIT_CMD_TX 0x40 +/* the extra bypass bit is sampled by the TNET as '1' */ +#define WSPI_INIT_CMD_BYPASS_BIT 0x80 +#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 +#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 +#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 +#define WSPI_INIT_CMD_IOD 0x40 +#define WSPI_INIT_CMD_IP 0x20 +#define WSPI_INIT_CMD_CS 0x10 +#define WSPI_INIT_CMD_WS 0x08 +#define WSPI_INIT_CMD_WSPI 0x01 +#define WSPI_INIT_CMD_END 0x01 + +#define WSPI_INIT_CMD_LEN 8 + +#define TNETWIF_READ_OFFSET_BYTES 8 +#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ + ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + + +/* Raw target IO, address is not translated */ +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len); + +/* Memory target IO, address is tranlated to partition 0 */ +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); + +/* Registers IO */ +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); + +/* INIT and RESET words */ +void wl12xx_spi_reset(struct wl12xx *wl); +void wl12xx_spi_init(struct wl12xx *wl); +void wl12xx_set_partition(struct wl12xx *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + +static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) +{ + u32 response; + + wl12xx_spi_read(wl, addr, &response, sizeof(u32)); + + return response; +} + +static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_spi_write(wl, addr, &val, sizeof(u32)); +} + +#endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c new file mode 100644 index 0000000..62145e2 --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.c @@ -0,0 +1,557 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "tx.h" +#include "ps.h" + +static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) +{ + int used, data_in_count; + + data_in_count = wl->data_in_count; + + if (data_in_count < data_out_count) + /* data_in_count has wrapped */ + data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; + + used = data_in_count - data_out_count; + + WARN_ON(used < 0); + WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); + + if (used >= DP_TX_PACKET_RING_CHUNK_NUM) + return true; + else + return false; +} + +static int wl12xx_tx_path_status(struct wl12xx *wl) +{ + u32 status, addr, data_out_count; + bool busy; + + addr = wl->data_path->tx_control_addr; + status = wl12xx_mem_read32(wl, addr); + data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; + busy = wl12xx_tx_double_buffer_busy(wl, data_out_count); + + if (busy) + return -EBUSY; + + return 0; +} + +static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] == NULL) { + wl->tx_frames[i] = skb; + return i; + } + + return -EBUSY; +} + +static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr, + struct ieee80211_tx_info *control, u16 fc) +{ + *(u16 *)&tx_hdr->control = 0; + + tx_hdr->control.rate_policy = 0; + + /* 802.11 packets */ + tx_hdr->control.packet_type = 0; + + if (control->flags & IEEE80211_TX_CTL_NO_ACK) + tx_hdr->control.ack_policy = 1; + + tx_hdr->control.tx_complete = 1; + + if ((fc & IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_STYPE_QOS_DATA) || + (fc & IEEE80211_STYPE_QOS_NULLFUNC))) + tx_hdr->control.qos = 1; +} + +/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ +#define MAX_MSDU_SECURITY_LENGTH 16 +#define MAX_MPDU_SECURITY_LENGTH 16 +#define WLAN_QOS_HDR_LEN 26 +#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ + WLAN_QOS_HDR_LEN) +#define HW_BLOCK_SIZE 252 +static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) +{ + u16 payload_len, frag_threshold, mem_blocks; + u16 num_mpdus, mem_blocks_per_frag; + + frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); + + payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH; + + if (payload_len > frag_threshold) { + mem_blocks_per_frag = + ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / + HW_BLOCK_SIZE) + 1; + num_mpdus = payload_len / frag_threshold; + mem_blocks = num_mpdus * mem_blocks_per_frag; + payload_len -= num_mpdus * frag_threshold; + num_mpdus++; + + } else { + mem_blocks_per_frag = 0; + mem_blocks = 0; + num_mpdus = 1; + } + + mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; + + if (num_mpdus > 1) + mem_blocks += min(num_mpdus, mem_blocks_per_frag); + + tx_hdr->num_mem_blocks = mem_blocks; +} + +static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + struct ieee80211_rate *rate; + int id; + u16 fc; + + if (!skb) + return -EINVAL; + + id = wl12xx_tx_id(wl, skb); + if (id < 0) + return id; + + fc = *(u16 *)skb->data; + tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, + sizeof(*tx_hdr)); + + tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); + rate = ieee80211_get_tx_rate(wl->hw, control); + tx_hdr->rate = cpu_to_le16(rate->hw_value); + tx_hdr->expiry_time = cpu_to_le32(1 << 16); + tx_hdr->id = id; + + /* FIXME: how to get the correct queue id? */ + tx_hdr->xmit_queue = 0; + + wl12xx_tx_control(tx_hdr, control, fc); + wl12xx_tx_frag_block_num(tx_hdr); + + return 0; +} + +/* We copy the packet to the target */ +static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + int len; + u32 addr; + + if (!skb) + return -EINVAL; + + tx_hdr = (struct tx_double_buffer_desc *) skb->data; + + if (control->control.hw_key && + control->control.hw_key->alg == ALG_TKIP) { + int hdrlen; + u16 fc; + u8 *pos; + + fc = *(u16 *)(skb->data + sizeof(*tx_hdr)); + tx_hdr->length += WL12XX_TKIP_IV_SPACE; + + hdrlen = ieee80211_hdrlen(fc); + + pos = skb_push(skb, WL12XX_TKIP_IV_SPACE); + memmove(pos, pos + WL12XX_TKIP_IV_SPACE, + sizeof(*tx_hdr) + hdrlen); + } + + /* Revisit. This is a workaround for getting non-aligned packets. + This happens at least with EAPOL packets from the user space. + Our DMA requires packets to be aligned on a 4-byte boundary. + */ + if (unlikely((long)skb->data & 0x03)) { + int offset = (4 - (long)skb->data) & 0x03; + wl12xx_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + + /* align the buffer on a 4-byte boundary */ + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + } else { + wl12xx_info("No handler, fixme!"); + return -EINVAL; + } + } + + /* Our skb->data at this point includes the HW header */ + len = WL12XX_TX_ALIGN(skb->len); + + if (wl->data_in_count & 0x1) + addr = wl->data_path->tx_packet_ring_addr + + wl->data_path->tx_packet_ring_chunk_size; + else + addr = wl->data_path->tx_packet_ring_addr; + + wl12xx_spi_mem_write(wl, addr, skb->data, len); + + wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", + tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); + + return 0; +} + +static void wl12xx_tx_trigger(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->data_in_count & 0x1) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_TX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_TX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Bumping data in */ + wl->data_in_count = (wl->data_in_count + 1) & + TX_STATUS_DATA_OUT_COUNT_MASK; +} + +/* caller must hold wl->mutex */ +static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + int ret = 0; + u8 idx; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + if (unlikely(wl->default_key != idx)) { + ret = wl12xx_acx_default_key(wl, idx); + if (ret < 0) + return ret; + } + } + + ret = wl12xx_tx_path_status(wl); + if (ret < 0) + return ret; + + ret = wl12xx_tx_fill_hdr(wl, skb, info); + if (ret < 0) + return ret; + + ret = wl12xx_tx_send_packet(wl, skb, info); + if (ret < 0) + return ret; + + wl12xx_tx_trigger(wl); + + return ret; +} + +void wl12xx_tx_work(struct work_struct *work) +{ + struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); + struct sk_buff *skb; + bool woken_up = false; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL12XX_STATE_OFF)) + goto out; + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + wl12xx_ps_elp_wakeup(wl); + woken_up = true; + } + + ret = wl12xx_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is full, stop queues */ + wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " + "stop queues"); + ieee80211_stop_queues(wl->hw); + wl->tx_queue_stopped = true; + skb_queue_head(&wl->tx_queue, skb); + goto out; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out; + } + } + +out: + if (woken_up) + wl12xx_ps_elp_sleep(wl); + + mutex_unlock(&wl->mutex); +} + +static const char *wl12xx_tx_parse_status(u8 status) +{ + /* 8 bit status field, one character per bit plus null */ + static char buf[9]; + int i = 0; + + memset(buf, 0, sizeof(buf)); + + if (status & TX_DMA_ERROR) + buf[i++] = 'm'; + if (status & TX_DISABLED) + buf[i++] = 'd'; + if (status & TX_RETRY_EXCEEDED) + buf[i++] = 'r'; + if (status & TX_TIMEOUT) + buf[i++] = 't'; + if (status & TX_KEY_NOT_FOUND) + buf[i++] = 'k'; + if (status & TX_ENCRYPT_FAIL) + buf[i++] = 'e'; + if (status & TX_UNAVAILABLE_PRIORITY) + buf[i++] = 'p'; + + /* bit 0 is unused apparently */ + + return buf; +} + +static void wl12xx_tx_packet_cb(struct wl12xx *wl, + struct tx_result *result) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb; + int hdrlen, ret; + u8 *frame; + + skb = wl->tx_frames[result->id]; + if (skb == NULL) { + wl12xx_error("SKB for packet %d is NULL", result->id); + return; + } + + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (result->status == TX_SUCCESS)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = result->ack_failures + 1; + wl->stats.retry_count += result->ack_failures; + + /* + * We have to remove our private TX header before pushing + * the skb back to mac80211. + */ + frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) { + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen); + skb_pull(skb, WL12XX_TKIP_IV_SPACE); + } + + wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x (%s)", + result->id, skb, result->ack_failures, result->rate, + result->status, wl12xx_tx_parse_status(result->status)); + + + ieee80211_tx_status(wl->hw, skb); + + wl->tx_frames[result->id] = NULL; + + if (wl->tx_queue_stopped) { + wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); + + skb = skb_dequeue(&wl->tx_queue); + + /* The skb can be NULL because tx_work might have been + scheduled before the queue was stopped making the + queue empty */ + + if (skb) { + ret = wl12xx_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is still full */ + wl12xx_debug(DEBUG_TX, "cb: fw buffer " + "still full"); + skb_queue_head(&wl->tx_queue, skb); + return; + } else if (ret < 0) { + dev_kfree_skb(skb); + return; + } + } + + wl12xx_debug(DEBUG_TX, "cb: waking queues"); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + } +} + +/* Called upon reception of a TX complete interrupt */ +void wl12xx_tx_complete(struct wl12xx *wl) +{ + int i, result_index, num_complete = 0; + struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; + + if (unlikely(wl->state != WL12XX_STATE_ON)) + return; + + /* First we read the result */ + wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, + result, sizeof(result)); + + result_index = wl->next_tx_complete; + + for (i = 0; i < ARRAY_SIZE(result); i++) { + result_ptr = &result[result_index]; + + if (result_ptr->done_1 == 1 && + result_ptr->done_2 == 1) { + wl12xx_tx_packet_cb(wl, result_ptr); + + result_ptr->done_1 = 0; + result_ptr->done_2 = 0; + + result_index = (result_index + 1) & + (FW_TX_CMPLT_BLOCK_SIZE - 1); + num_complete++; + } else { + break; + } + } + + /* Every completed frame needs to be acknowledged */ + if (num_complete) { + /* + * If we've wrapped, we have to clear + * the results in 2 steps. + */ + if (result_index > wl->next_tx_complete) { + /* Only 1 write is needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + num_complete * + sizeof(struct tx_result)); + + + } else if (result_index < wl->next_tx_complete) { + /* 2 writes are needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + (FW_TX_CMPLT_BLOCK_SIZE - + wl->next_tx_complete) * + sizeof(struct tx_result)); + + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + (num_complete - + FW_TX_CMPLT_BLOCK_SIZE + + wl->next_tx_complete) * + sizeof(struct tx_result)); + + } else { + /* We have to write the whole array */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + FW_TX_CMPLT_BLOCK_SIZE * + sizeof(struct tx_result)); + } + + } + + wl->next_tx_complete = result_index; +} + +/* caller must hold wl->mutex */ +void wl12xx_tx_flush(struct wl12xx *wl) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* TX failure */ +/* control->flags = 0; FIXME */ + + while ((skb = skb_dequeue(&wl->tx_queue))) { + info = IEEE80211_SKB_CB(skb); + + wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + } + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[i] = NULL; + } +} diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h new file mode 100644 index 0000000..dc82691 --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.h @@ -0,0 +1,215 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_TX_H__ +#define __WL12XX_TX_H__ + +#include + +/* + * + * TX PATH + * + * The Tx path uses a double buffer and a tx_control structure, each located + * at a fixed address in the device's memory. On startup, the host retrieves + * the pointers to these addresses. A double buffer allows for continuous data + * flow towards the device. The host keeps track of which buffer is available + * and alternates between these two buffers on a per packet basis. + * + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet - maximum size Ethernet packet + header + descriptor. + * TX complete indication will be received a-synchronously in a TX done cyclic + * buffer which is composed of 16 tx_result descriptors structures and is used + * in a cyclic manner. + * + * The TX (HOST) procedure is as follows: + * 1. Read the Tx path status, that will give the data_out_count. + * 2. goto 1, if not possible. + * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double + * buffer). + * 3. Copy the packet (preceded by double_buffer_desc), if possible. + * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double + * buffer). + * 4. increment data_in_count. + * 5. Inform the firmware by generating a firmware internal interrupt. + * 6. FW will increment data_out_count after it reads the buffer. + * + * The TX Complete procedure: + * 1. To get a TX complete indication the host enables the tx_complete flag in + * the TX descriptor Structure. + * 2. For each packet with a Tx Complete field set, the firmware adds the + * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 + * and done_2 to 1 to indicate driver ownership. + * 3. The firmware sends a Tx Complete interrupt to the host to trigger the + * host to process the new data. Note: interrupt will be send per packet if + * TX complete indication was requested in tx_control or per crossing + * aggregation threshold. + * 4. After receiving the Tx Complete interrupt, the host reads the + * TxDescriptorDone information in a cyclic manner and clears both done_1 + * and done_2 fields. + * + */ + +#define TX_COMPLETE_REQUIRED_BIT 0x80 +#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf +#define WL12XX_TX_ALIGN_TO 4 +#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \ + ~(WL12XX_TX_ALIGN_TO - 1)) +#define WL12XX_TKIP_IV_SPACE 4 + +struct tx_control { + /* Rate Policy (class) index */ + unsigned rate_policy:3; + + /* When set, no ack policy is expected */ + unsigned ack_policy:1; + + /* + * Packet type: + * 0 -> 802.11 + * 1 -> 802.3 + * 2 -> IP + * 3 -> raw codec + */ + unsigned packet_type:2; + + /* If set, this is a QoS-Null or QoS-Data frame */ + unsigned qos:1; + + /* + * If set, the target triggers the tx complete INT + * upon frame sending completion. + */ + unsigned tx_complete:1; + + /* 2 bytes padding before packet header */ + unsigned xfer_pad:1; + + unsigned reserved:7; +} __attribute__ ((packed)); + + +struct tx_double_buffer_desc { + /* Length of payload, including headers. */ + u16 length; + + /* + * A bit mask that specifies the initial rate to be used + * Possible values are: + * 0x0001 - 1Mbits + * 0x0002 - 2Mbits + * 0x0004 - 5.5Mbits + * 0x0008 - 6Mbits + * 0x0010 - 9Mbits + * 0x0020 - 11Mbits + * 0x0040 - 12Mbits + * 0x0080 - 18Mbits + * 0x0100 - 22Mbits + * 0x0200 - 24Mbits + * 0x0400 - 36Mbits + * 0x0800 - 48Mbits + * 0x1000 - 54Mbits + */ + u16 rate; + + /* Time in us that a packet can spend in the target */ + u32 expiry_time; + + /* index of the TX queue used for this packet */ + u8 xmit_queue; + + /* Used to identify a packet */ + u8 id; + + struct tx_control control; + + /* + * The FW should cut the packet into fragments + * of this size. + */ + u16 frag_threshold; + + /* Numbers of HW queue blocks to be allocated */ + u8 num_mem_blocks; + + u8 reserved; +} __attribute__ ((packed)); + +enum { + TX_SUCCESS = 0, + TX_DMA_ERROR = BIT(7), + TX_DISABLED = BIT(6), + TX_RETRY_EXCEEDED = BIT(5), + TX_TIMEOUT = BIT(4), + TX_KEY_NOT_FOUND = BIT(3), + TX_ENCRYPT_FAIL = BIT(2), + TX_UNAVAILABLE_PRIORITY = BIT(1), +}; + +struct tx_result { + /* + * Ownership synchronization between the host and + * the firmware. If done_1 and done_2 are cleared, + * owned by the FW (no info ready). + */ + u8 done_1; + + /* same as double_buffer_desc->id */ + u8 id; + + /* + * Total air access duration consumed by this + * packet, including all retries and overheads. + */ + u16 medium_usage; + + /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ + u32 medium_delay; + + /* Time between host xfer and tx complete */ + u32 fw_hnadling_time; + + /* The LS-byte of the last TKIP sequence number. */ + u8 lsb_seq_num; + + /* Retry count */ + u8 ack_failures; + + /* At which rate we got a ACK */ + u16 rate; + + u16 reserved; + + /* TX_* */ + u8 status; + + /* See done_1 */ + u8 done_2; +} __attribute__ ((packed)); + +void wl12xx_tx_work(struct work_struct *work); +void wl12xx_tx_complete(struct wl12xx *wl); +void wl12xx_tx_flush(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c new file mode 100644 index 0000000..bd0decd --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -0,0 +1,709 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1251.h" +#include "reg.h" +#include "spi.h" +#include "boot.h" +#include "event.h" +#include "acx.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" + +static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x00016800 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_DOWN_SIZE + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00028000, + .size = 0x00014000 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_WORK_SIZE + }, + }, + + /* WL1251 doesn't use the DRPW partition, so we don't set it here */ +}; + +static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { + [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), + [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), + [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), + [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), + [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), + [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), + [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), + [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), + [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), + [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), + [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) +}; + +static int wl1251_upload_firmware(struct wl12xx *wl) +{ + struct wl12xx_partition_set *p_table = wl->chip.p_table; + int addr, chunk_num, partition_limit; + size_t fw_data_len; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl12xx_reg_read32(wl, CHIP_ID_B)); + + /* 10.0 check firmware length and set partition */ + fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | + (wl->fw[6] << 8) | (wl->fw[7]); + + wl12xx_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len, + CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl12xx_error("firmware length not multiple of four"); + return -EIO; + } + + wl12xx_set_partition(wl, + p_table[PART_DOWN].mem.start, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = p_table[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = p_table[PART_DOWN].mem.start + + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = p_table[PART_DOWN].mem.start + + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + p_table[PART_DOWN].mem.size; + wl12xx_set_partition(wl, + addr, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + } + + /* 10.3 upload the chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1251_upload_nvs(struct wl12xx *wl) +{ + size_t nvs_len, nvs_bytes_written, burst_len; + int nvs_start, i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + nvs_start = wl->fw_len; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl12xx_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl12xx_mem_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* Now we must set the partition correctly */ + wl12xx_set_partition(wl, nvs_start, + wl->chip.p_table[PART_DOWN].mem.size, + wl->chip.p_table[PART_DOWN].reg.start, + wl->chip.p_table[PART_DOWN].reg.size); + + /* And finally we upload the NVS tables */ + nvs_bytes_written = 0; + while (nvs_bytes_written < nvs_len) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + val = cpu_to_le32(val); + + wl12xx_debug(DEBUG_BOOT, + "nvs write table 0x%x: 0x%x", + nvs_start, val); + wl12xx_mem_write32(wl, nvs_start, val); + + nvs_ptr += 4; + nvs_bytes_written += 4; + nvs_start += 4; + } + + return 0; +} + +static int wl1251_boot(struct wl12xx *wl) +{ + int ret = 0, minor_minor_e2_ver; + u32 tmp, boot_data; + + ret = wl12xx_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl->chip.op_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + + /* 6. read the EEPROM parameters */ + tmp = wl12xx_reg_read32(wl, SCR_PAD2); + + /* 7. read bootdata */ + wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; + wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; + tmp = wl12xx_reg_read32(wl, SCR_PAD3); + + /* 8. check bootdata and call restart sequence */ + wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; + minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; + + wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", + wl->boot_attr.radio_type, wl->boot_attr.major, + wl->boot_attr.minor, minor_minor_e2_ver); + + ret = wl12xx_boot_init_seq(wl); + if (ret < 0) + goto out; + + /* 9. NVS processing done */ + boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + + /* 10. check that ECPU_CONTROL_HALT bits are set in + * pWhalBus->uBootData and start uploading firmware + */ + if ((boot_data & ECPU_CONTROL_HALT) == 0) { + wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); + ret = -EIO; + goto out; + } + + ret = wl->chip.op_upload_fw(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl12xx_boot_run_firmware(wl); + if (ret < 0) + goto out; + + /* Get and save the firmware version */ + wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); + +out: + return ret; +} + +static int wl1251_mem_cfg(struct wl12xx *wl) +{ + struct wl1251_acx_config_memory mem_conf; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + + /* memory config */ + mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf.mem_config.rx_mem_block_num = 35; + mem_conf.mem_config.tx_min_mem_block_num = 64; + mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf.mem_config.num_ssid_profiles = 1; + mem_conf.mem_config.debug_buffer_size = + cpu_to_le16(TRACE_BUFFER_MAX_SIZE); + + /* RX queue config */ + mem_conf.rx_queue_config.dma_address = 0; + mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE; + + /* TX queue config */ + for (i = 0; i < MAX_TX_QUEUES; i++) { + mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf.tx_queue_config[i].attributes = i; + } + + mem_conf.header.id = ACX_MEM_CFG; + mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) - + sizeof(struct acx_header); + mem_conf.header.len -= + (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) * + sizeof(struct wl1251_acx_tx_queue_config); + + ret = wl12xx_cmd_configure(wl, &mem_conf, + sizeof(struct wl1251_acx_config_memory)); + if (ret < 0) + wl12xx_warning("wl1251 mem config failed: %d", ret); + + return ret; +} + +static int wl1251_hw_init_mem_config(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl12xx_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, + sizeof(struct wl1251_acx_mem_map)); + if (ret < 0) { + wl12xx_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + return 0; +} + +static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl &= ~flag; + wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +static void wl1251_target_enable_interrupts(struct wl12xx *wl) +{ + /* Enable target's interrupts */ + wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | + WL1251_ACX_INTR_RX1_DATA | + WL1251_ACX_INTR_TX_RESULT | + WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B | + WL1251_ACX_INTR_INIT_COMPLETE; + wl12xx_boot_target_enable_interrupts(wl); +} + +static void wl1251_irq_work(struct work_struct *work) +{ + u32 intr; + struct wl12xx *wl = + container_of(work, struct wl12xx, irq_work); + + mutex_lock(&wl->mutex); + + wl12xx_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + wl12xx_ps_elp_wakeup(wl); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); + + if (wl->data_path) { + wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr, + &wl->rx_counter, sizeof(u32)); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl12xx_warning("RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + + wl->rx_handled = wl->rx_counter; + + + wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + } + + intr &= wl->intr_mask; + + if (intr == 0) { + wl12xx_debug(DEBUG_IRQ, "INTR is 0"); + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + ~(wl->intr_mask)); + + goto out_sleep; + } + + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl12xx_tx_complete(wl); + } + + if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1251_ACX_INTR_EVENT_A) + wl12xx_event_handle(wl, 0); + else + wl12xx_event_handle(wl, 1); + } + + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + +out_sleep: + wl12xx_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static int wl1251_hw_init_txq_fill(u8 qid, + struct acx_tx_queue_qos_config *config, + u32 num_blocks) +{ + config->qid = qid; + + switch (qid) { + case QOS_AC_BE: + config->high_threshold = + (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BE_DEF * num_blocks) / 100; + break; + case QOS_AC_BK: + config->high_threshold = + (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BK_DEF * num_blocks) / 100; + break; + case QOS_AC_VI: + config->high_threshold = + (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VI_DEF * num_blocks) / 100; + break; + case QOS_AC_VO: + config->high_threshold = + (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VO_DEF * num_blocks) / 100; + break; + default: + wl12xx_error("Invalid TX queue id: %d", qid); + return -EINVAL; + } + + return 0; +} + +static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) +{ + struct acx_tx_queue_qos_config config; + struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "acx tx queue config"); + + config.header.id = ACX_TX_QUEUE_CFG; + config.header.len = sizeof(struct acx_tx_queue_qos_config) - + sizeof(struct acx_header); + + for (i = 0; i < MAX_NUM_OF_AC; i++) { + ret = wl1251_hw_init_txq_fill(i, &config, + wl_mem_map->num_tx_mem_blocks); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_configure(wl, &config, sizeof(config)); + if (ret < 0) + return ret; + } + + return 0; +} + +static int wl1251_hw_init_data_path_config(struct wl12xx *wl) +{ + int ret; + + /* asking for the data path parameters */ + wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), + GFP_KERNEL); + if (!wl->data_path) { + wl12xx_error("Couldnt allocate data path parameters"); + return -ENOMEM; + } + + ret = wl12xx_acx_data_path_params(wl, wl->data_path); + if (ret < 0) { + kfree(wl->data_path); + wl->data_path = NULL; + return ret; + } + + return 0; +} + +static int wl1251_hw_init(struct wl12xx *wl) +{ + struct wl1251_acx_mem_map *wl_mem_map; + int ret; + + ret = wl12xx_hw_init_hwenc_config(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl12xx_hw_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + /* Default data path configuration */ + ret = wl1251_hw_init_data_path_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX config */ + ret = wl12xx_hw_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_data_path; + + /* TX queues config */ + ret = wl1251_hw_init_tx_queue_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* PHY layer config */ + ret = wl12xx_hw_init_phy_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacon filtering */ + ret = wl12xx_hw_init_beacon_filter(wl); + if (ret < 0) + goto out_free_data_path; + + /* Bluetooth WLAN coexistence */ + ret = wl12xx_hw_init_pta(wl); + if (ret < 0) + goto out_free_data_path; + + /* Energy detection */ + ret = wl12xx_hw_init_energy_detection(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacons and boradcast settings */ + ret = wl12xx_hw_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_data_path; + + /* Enable data path */ + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Default power state */ + ret = wl12xx_hw_init_power_auth(wl); + if (ret < 0) + goto out_free_data_path; + + wl_mem_map = wl->target_mem_map; + wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl_mem_map->num_tx_mem_blocks, + wl->data_path->tx_control_addr, + wl_mem_map->num_rx_mem_blocks, + wl->data_path->rx_control_addr); + + return 0; + + out_free_data_path: + kfree(wl->data_path); + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} + +static int wl1251_plt_init(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + return ret; + + return 0; +} + +void wl1251_setup(struct wl12xx *wl) +{ + /* FIXME: Is it better to use strncpy here or is this ok? */ + wl->chip.fw_filename = WL1251_FW_NAME; + wl->chip.nvs_filename = WL1251_NVS_NAME; + + /* Now we know what chip we're using, so adjust the power on sleep + * time accordingly */ + wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; + + wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; + wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; + + wl->chip.op_upload_nvs = wl1251_upload_nvs; + wl->chip.op_upload_fw = wl1251_upload_firmware; + wl->chip.op_boot = wl1251_boot; + wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; + wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; + wl->chip.op_hw_init = wl1251_hw_init; + wl->chip.op_plt_init = wl1251_plt_init; + + wl->chip.p_table = wl1251_part_table; + wl->chip.acx_reg_table = wl1251_acx_reg_table; + + INIT_WORK(&wl->irq_work, wl1251_irq_work); +} diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h new file mode 100644 index 0000000..1f4a443 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -0,0 +1,165 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_H__ +#define __WL1251_H__ + +#include + +#include "wl12xx.h" +#include "acx.h" + +#define WL1251_FW_NAME "wl1251-fw.bin" +#define WL1251_NVS_NAME "wl1251-nvs.bin" + +#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ + +void wl1251_setup(struct wl12xx *wl); + + +struct wl1251_acx_memory { + __le16 num_stations; /* number of STAs to be supported. */ + u16 reserved_1; + + /* + * Nmber of memory buffers for the RX mem pool. + * The actual number may be less if there are + * not enough blocks left for the minimum num + * of TX ones. + */ + u8 rx_mem_block_num; + u8 reserved_2; + u8 num_tx_queues; /* From 1 to 16 */ + u8 host_if_options; /* HOST_IF* */ + u8 tx_min_mem_block_num; + u8 num_ssid_profiles; + __le16 debug_buffer_size; +} __attribute__ ((packed)); + + +#define ACX_RX_DESC_MIN 1 +#define ACX_RX_DESC_MAX 127 +#define ACX_RX_DESC_DEF 32 +struct wl1251_acx_rx_queue_config { + u8 num_descs; + u8 pad; + u8 type; + u8 priority; + __le32 dma_address; +} __attribute__ ((packed)); + +#define ACX_TX_DESC_MIN 1 +#define ACX_TX_DESC_MAX 127 +#define ACX_TX_DESC_DEF 16 +struct wl1251_acx_tx_queue_config { + u8 num_descs; + u8 pad[2]; + u8 attributes; +} __attribute__ ((packed)); + +#define MAX_TX_QUEUE_CONFIGS 5 +#define MAX_TX_QUEUES 4 +struct wl1251_acx_config_memory { + struct acx_header header; + + struct wl1251_acx_memory mem_config; + struct wl1251_acx_rx_queue_config rx_queue_config; + struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; +} __attribute__ ((packed)); + +struct wl1251_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + void *queue_memory_start; + void *queue_memory_end; + + void *packet_memory_pool_start; + void *packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; +} __attribute__ ((packed)); + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ + +/* RX packet is ready in Xfer buffer #0 */ +#define WL1251_ACX_INTR_RX0_DATA BIT(0) + +/* TX result(s) are in the TX complete buffer */ +#define WL1251_ACX_INTR_TX_RESULT BIT(1) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_TX_XFR BIT(2) + +/* RX packet is ready in Xfer buffer #1 */ +#define WL1251_ACX_INTR_RX1_DATA BIT(3) + +/* Event was entered to Event MBOX #A */ +#define WL1251_ACX_INTR_EVENT_A BIT(4) + +/* Event was entered to Event MBOX #B */ +#define WL1251_ACX_INTR_EVENT_B BIT(5) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) + +/* Trace meassge on MBOX #A */ +#define WL1251_ACX_INTR_TRACE_A BIT(7) + +/* Trace meassge on MBOX #B */ +#define WL1251_ACX_INTR_TRACE_B BIT(8) + +/* Command processing completion */ +#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) + +/* Init sequence is done */ +#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) + +#define WL1251_ACX_INTR_ALL 0xFFFFFFFF + +#endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h new file mode 100644 index 0000000..4864143 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -0,0 +1,409 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_H__ +#define __WL12XX_H__ + +#include +#include +#include +#include + +#define DRIVER_NAME "wl12xx" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_NETLINK = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl12xx_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl12xx_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl12xx_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl12xx_dump(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl12xx_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN) + +#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | \ + CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | \ + CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) + + +struct boot_attr { + u32 radio_type; + u8 mac_clock; + u8 arm_clock; + int firmware_debug; + u32 minor; + u32 major; + u32 bugfix; +}; + +enum wl12xx_state { + WL12XX_STATE_OFF, + WL12XX_STATE_ON, + WL12XX_STATE_PLT, +}; + +enum wl12xx_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl12xx_partition { + u32 size; + u32 start; +}; + +struct wl12xx_partition_set { + struct wl12xx_partition mem; + struct wl12xx_partition reg; +}; + +struct wl12xx; + +/* FIXME: I'm not sure about this structure name */ +struct wl12xx_chip { + u32 id; + + const char *fw_filename; + const char *nvs_filename; + + char fw_ver[21]; + + unsigned int power_on_sleep; + int intr_cmd_complete; + int intr_init_complete; + + int (*op_upload_fw)(struct wl12xx *wl); + int (*op_upload_nvs)(struct wl12xx *wl); + int (*op_boot)(struct wl12xx *wl); + void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); + void (*op_target_enable_interrupts)(struct wl12xx *wl); + int (*op_hw_init)(struct wl12xx *wl); + int (*op_plt_init)(struct wl12xx *wl); + + struct wl12xx_partition_set *p_table; + enum wl12xx_acx_int_reg *acx_reg_table; +}; + +struct wl12xx_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl12xx_debugfs { + struct dentry *rootdir; + struct dentry *fw_statistics; + + struct dentry *tx_internal_desc_overflow; + + struct dentry *rx_out_of_mem; + struct dentry *rx_hdr_overflow; + struct dentry *rx_hw_stuck; + struct dentry *rx_dropped; + struct dentry *rx_fcs_err; + struct dentry *rx_xfr_hint_trig; + struct dentry *rx_path_reset; + struct dentry *rx_reset_counter; + + struct dentry *dma_rx_requested; + struct dentry *dma_rx_errors; + struct dentry *dma_tx_requested; + struct dentry *dma_tx_errors; + + struct dentry *isr_cmd_cmplt; + struct dentry *isr_fiqs; + struct dentry *isr_rx_headers; + struct dentry *isr_rx_mem_overflow; + struct dentry *isr_rx_rdys; + struct dentry *isr_irqs; + struct dentry *isr_tx_procs; + struct dentry *isr_decrypt_done; + struct dentry *isr_dma0_done; + struct dentry *isr_dma1_done; + struct dentry *isr_tx_exch_complete; + struct dentry *isr_commands; + struct dentry *isr_rx_procs; + struct dentry *isr_hw_pm_mode_changes; + struct dentry *isr_host_acknowledges; + struct dentry *isr_pci_pm; + struct dentry *isr_wakeups; + struct dentry *isr_low_rssi; + + struct dentry *wep_addr_key_count; + struct dentry *wep_default_key_count; + /* skipping wep.reserved */ + struct dentry *wep_key_not_found; + struct dentry *wep_decrypt_fail; + struct dentry *wep_packets; + struct dentry *wep_interrupt; + + struct dentry *pwr_ps_enter; + struct dentry *pwr_elp_enter; + struct dentry *pwr_missing_bcns; + struct dentry *pwr_wake_on_host; + struct dentry *pwr_wake_on_timer_exp; + struct dentry *pwr_tx_with_ps; + struct dentry *pwr_tx_without_ps; + struct dentry *pwr_rcvd_beacons; + struct dentry *pwr_power_save_off; + struct dentry *pwr_enable_ps; + struct dentry *pwr_disable_ps; + struct dentry *pwr_fix_tsf_ps; + /* skipping cont_miss_bcns_spread for now */ + struct dentry *pwr_rcvd_awake_beacons; + + struct dentry *mic_rx_pkts; + struct dentry *mic_calc_failure; + + struct dentry *aes_encrypt_fail; + struct dentry *aes_decrypt_fail; + struct dentry *aes_encrypt_packets; + struct dentry *aes_decrypt_packets; + struct dentry *aes_encrypt_interrupt; + struct dentry *aes_decrypt_interrupt; + + struct dentry *event_heart_beat; + struct dentry *event_calibration; + struct dentry *event_rx_mismatch; + struct dentry *event_rx_mem_empty; + struct dentry *event_rx_pool; + struct dentry *event_oom_late; + struct dentry *event_phy_transmit_error; + struct dentry *event_tx_stuck; + + struct dentry *ps_pspoll_timeouts; + struct dentry *ps_upsd_timeouts; + struct dentry *ps_upsd_max_sptime; + struct dentry *ps_upsd_max_apturn; + struct dentry *ps_pspoll_max_apturn; + struct dentry *ps_pspoll_utilization; + struct dentry *ps_upsd_utilization; + + struct dentry *rxpipe_rx_prep_beacon_drop; + struct dentry *rxpipe_descr_host_int_trig_rx_data; + struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; + struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; + struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; + + struct dentry *tx_queue_len; + + struct dentry *retry_count; + struct dentry *excessive_retries; +}; + +struct wl12xx { + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct spi_device *spi; + + void (*set_power)(bool enable); + int irq; + + enum wl12xx_state state; + struct mutex mutex; + + int physical_mem_addr; + int physical_reg_addr; + int virtual_mem_addr; + int virtual_reg_addr; + + struct wl12xx_chip chip; + + int cmd_box_addr; + int event_box_addr; + struct boot_attr boot_attr; + + u8 *fw; + size_t fw_len; + u8 *nvs; + size_t nvs_len; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 listen_int; + int channel; + + void *target_mem_map; + struct acx_data_path_params_resp *data_path; + + /* Number of TX packets transferred to the FW, modulo 16 */ + u32 data_in_count; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + bool tx_queue_stopped; + + struct work_struct tx_work; + struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; + + /* + * Index pointing to the next TX complete entry + * in the cyclic XT complete array we get from + * the FW. + */ + u32 next_tx_complete; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx frames handled */ + u32 rx_handled; + + /* Current double buffer */ + u32 rx_current_buffer; + u32 rx_last_id; + + /* The target interrupt mask */ + u32 intr_mask; + struct work_struct irq_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + bool scanning; + + /* Our association ID */ + u16 aid; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int tx_mgmt_frm_rate; + unsigned int tx_mgmt_frm_mod; + + unsigned int rx_config; + unsigned int rx_filter; + + /* is firmware in elp mode */ + bool elp; + + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + + /* in dBm */ + int power_level; + + struct wl12xx_stats stats; + struct wl12xx_debugfs debugfs; +}; + +int wl12xx_plt_start(struct wl12xx *wl); +int wl12xx_plt_stop(struct wl12xx *wl); + +#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ +#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define WL12XX_DEFAULT_POWER_LEVEL 20 + +#define WL12XX_TX_QUEUE_MAX_LENGTH 20 + +/* Different chips need different sleep times after power on. WL1271 needs + * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we + * know the chip ID, we change the sleep value in the wl12xx chip structure, + * so in subsequent power ons, we don't waste more time then needed. */ +#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) +#define CHIP_ID_1271_PG10 (0x4030101) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h new file mode 100644 index 0000000..657c2db --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -0,0 +1,156 @@ +#ifndef __WL12XX_80211_H__ +#define __WL12XX_80211_H__ + +#include /* ETH_ALEN */ + +/* RATES */ +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + + +/* This really should be 8, but not for our firmware */ +#define MAX_SUPPORTED_RATES 32 +#define COUNTRY_STRING_LEN 3 +#define MAX_COUNTRY_TRIPLETS 32 + +/* Headers */ +struct ieee80211_header { + __le16 frame_ctl; + __le16 duration_id; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + +struct wl12xx_ie_header { + u8 id; + u8 len; +} __attribute__ ((packed)); + +/* IEs */ + +struct wl12xx_ie_ssid { + struct wl12xx_ie_header header; + char ssid[IW_ESSID_MAX_SIZE]; +} __attribute__ ((packed)); + +struct wl12xx_ie_rates { + struct wl12xx_ie_header header; + u8 rates[MAX_SUPPORTED_RATES]; +} __attribute__ ((packed)); + +struct wl12xx_ie_ds_params { + struct wl12xx_ie_header header; + u8 channel; +} __attribute__ ((packed)); + +struct country_triplet { + u8 channel; + u8 num_channels; + u8 max_tx_power; +} __attribute__ ((packed)); + +struct wl12xx_ie_country { + struct wl12xx_ie_header header; + u8 country_string[COUNTRY_STRING_LEN]; + struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; +} __attribute__ ((packed)); + + +/* Templates */ + +struct wl12xx_beacon_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __attribute__ ((packed)); + +struct wl12xx_null_data_template { + struct ieee80211_header header; +} __attribute__ ((packed)); + +struct wl12xx_ps_poll_template { + u16 fc; + u16 aid; + u8 bssid[ETH_ALEN]; + u8 ta[ETH_ALEN]; +} __attribute__ ((packed)); + +struct wl12xx_qos_null_data_template { + struct ieee80211_header header; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct wl12xx_probe_req_template { + struct ieee80211_header header; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; +} __attribute__ ((packed)); + + +struct wl12xx_probe_resp_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __attribute__ ((packed)); + +#endif diff --git a/include/linux/spi/wl12xx.h b/include/linux/spi/wl12xx.h new file mode 100644 index 0000000..11430ca --- /dev/null +++ b/include/linux/spi/wl12xx.h @@ -0,0 +1,31 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef _LINUX_SPI_WL12XX_H +#define _LINUX_SPI_WL12XX_H + +struct wl12xx_platform_data { + void (*set_power)(bool enable); +}; + +#endif -- cgit v0.10.2 From e430d6074dede3b4d7d87e30296fe3894cb4709c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 27 Apr 2009 23:58:31 +0200 Subject: rt2x00: Add new USB ID for rt2800usb Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 812912e..93ebf24 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2942,6 +2942,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Linksys */ { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Logitec */ { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v0.10.2 From 15e469284d5e89c9113379b68566b0e059a97704 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 28 Apr 2009 20:14:58 +0200 Subject: rt2x00: Synchronize initialization with rt2870 driver Ralink released a new rt2870 driver, these are the obvious differences I could find. It doesn't same to make my device work better, but neither does it seem to regress... Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 93ebf24..cf4a97f 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -984,9 +984,9 @@ static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); - rt2800usb_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); } else { - rt2800usb_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); rt2x00usb_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); @@ -1171,7 +1171,9 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, /* * Check which section of the firmware we need. */ - if ((chipset == 0x2860) || (chipset == 0x2872) || (chipset == 0x3070)) { + if ((chipset == 0x2860) || + (chipset == 0x2872) || + (chipset == 0x3070)) { offset = 0; length = 4096; } else { @@ -1218,6 +1220,22 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, return status; } + msleep(10); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + + /* + * Send signal to firmware during boot time. + */ + rt2800usb_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); + + if ((chipset == 0x3070) || + (chipset == 0x3071) || + (chipset == 0x3572)) { + udelay(200); + rt2800usb_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); + udelay(10); + } + /* * Wait for device to stabilize. */ @@ -1566,6 +1584,14 @@ static int rt2800usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) unsigned int i; u8 value; + /* + * BBP was enabled after firmware was loaded, + * but we need to reactivate it now. + */ + rt2x00usb_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + msleep(1); + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2800usb_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) @@ -1823,8 +1849,12 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, (rt2x00dev->rx->usb_maxpacket == 512)); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); - /* FIXME: Calculate this value based on Aggregation defines */ - rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_LIMIT, 21); + /* + * Total room for RX frames in kilobytes, PBF might still exceed + * this limit so reduce the number to prevent errors. + */ + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_LIMIT, + ((RX_ENTRIES * DATA_FRAME_SIZE) / 1024) - 3); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg); @@ -1835,11 +1865,6 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); /* - * Send signal to firmware during boot time. - */ - rt2800usb_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); - - /* * Initialize LED control */ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); @@ -1879,8 +1904,6 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); - if (state == STATE_AWAKE) rt2800usb_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); else diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 8e4291d..61a8be6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -1375,6 +1375,10 @@ struct mac_iveiv_entry { * H2M_MAILBOX_CID: */ #define H2M_MAILBOX_CID 0x7014 +#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000) +#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000) /* * H2M_MAILBOX_STATUS: @@ -1715,6 +1719,7 @@ struct mac_iveiv_entry { #define MCU_SLEEP 0x30 #define MCU_WAKEUP 0x31 #define MCU_RADIO_OFF 0x35 +#define MCU_CURRENT 0x36 #define MCU_LED 0x50 #define MCU_LED_STRENGTH 0x51 #define MCU_LED_1 0x52 @@ -1723,6 +1728,12 @@ struct mac_iveiv_entry { #define MCU_RADAR 0x60 #define MCU_BOOT_SIGNAL 0x72 #define MCU_BBP_SIGNAL 0x80 +#define MCU_POWER_SAVE 0x83 + +/* + * MCU mailbox tokens + */ +#define TOKEN_WAKUP 3 /* * DMA descriptor defines. -- cgit v0.10.2 From a082381044ce026e83dbd17f8837722b028fc07d Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Thu, 30 Apr 2009 15:55:44 -0400 Subject: ath5k: Allow user/driver to set txpower * Now that we have regulatory control enable the driver to set txpower on hw * Also use txpower table offset so that we can match power range set by user/driver with indices on power table. Tested 2 different cards (a CM9 and an RF5112-based ubnt) and got the same output using a remote machine to measure per-packet rssi (conected the cards using attenuators). I also switched between various tx power levels and i saw an equal power change on the remote machine (so txpower changes as expected) and verified that we have the same output on each rate. Signed-off-by: Nick Kossifidis Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 60c6d2e..04b7345 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1100,11 +1100,12 @@ struct ath5k_hw { /* Values in 0.25dB units */ s16 txp_min_pwr; s16 txp_max_pwr; + /* Values in 0.5dB units */ s16 txp_offset; s16 txp_ofdm; - /* Values in dB units */ - s16 txp_cck_ofdm_pwr_delta; s16 txp_cck_ofdm_gainf_delta; + /* Value in dB units */ + s16 txp_cck_ofdm_pwr_delta; } ah_txpower; struct { @@ -1271,7 +1272,7 @@ extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); 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, u8 ee_mode, u8 txpower); -extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower); +extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); /* * Functions used internaly diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7b80ceb..d70856a 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2747,12 +2747,21 @@ static int ath5k_config(struct ieee80211_hw *hw, u32 changed) { struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; struct ieee80211_conf *conf = &hw->conf; int ret; mutex_lock(&sc->lock); - sc->power_level = conf->power_level; + sc->bintval = conf->beacon_int; + + if ((changed & IEEE80211_CONF_CHANGE_POWER) && + (sc->power_level != conf->power_level)) { + sc->power_level = conf->power_level; + + /* Half dB steps */ + ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); + } ret = ath5k_chan_set(sc, conf->channel); diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index b48b29d..bb61b8e 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -168,9 +168,6 @@ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) * tx power and a Peak to Average Power Detector (PAPD) will try * to measure the gain. * - * TODO: Use propper tx power setting for the probe packet so - * that we don't observe a serious power drop on the receiver - * * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) * just after we enable the probe so that we don't mess with * standard traffic ? Maybe it's time to use sw interrupts and @@ -186,7 +183,7 @@ static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) /* Send the packet with 2dB below max power as * patent doc suggest */ - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4, + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_ofdm - 4, AR5K_PHY_PAPD_PROBE_TXPOWER) | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); @@ -2482,8 +2479,19 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, for (i = 8; i <= 15; i++) rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; - ah->ah_txpower.txp_min_pwr = rates[7]; - ah->ah_txpower.txp_max_pwr = rates[0]; + /* Now that we have all rates setup use table offset to + * match the power range set by user with the power indices + * on PCDAC/PDADC table */ + for (i = 0; i < 16; i++) { + rates[i] += ah->ah_txpower.txp_offset; + /* Don't get out of bounds */ + if (rates[i] > 63) + rates[i] = 63; + } + + /* Min/max in 0.25dB units */ + ah->ah_txpower.txp_min_pwr = 2 * rates[7]; + ah->ah_txpower.txp_max_pwr = 2 * rates[0]; ah->ah_txpower.txp_ofdm = rates[7]; } @@ -2591,16 +2599,37 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, return 0; } -int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower) +int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) { /*Just a try M.F.*/ struct ieee80211_channel *channel = &ah->ah_current_channel; + u8 ee_mode; ATH5K_TRACE(ah->ah_sc); + + switch (channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + case CHANNEL_T: + case CHANNEL_XR: + ee_mode = AR5K_EEPROM_MODE_11A; + break; + case CHANNEL_G: + case CHANNEL_TG: + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_B: + ee_mode = AR5K_EEPROM_MODE_11B; + break; + default: + ATH5K_ERR(ah->ah_sc, + "invalid channel: %d\n", channel->center_freq); + return -EINVAL; + } + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, "changing txpower to %d\n", txpower); - return ath5k_hw_txpower(ah, channel, mode, txpower); + return ath5k_hw_txpower(ah, channel, ee_mode, txpower); } #undef _ATH5K_PHY diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 775fdf7..cb8a9a1 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1000,7 +1000,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * Set TX power (FIXME) */ ret = ath5k_hw_txpower(ah, channel, ee_mode, - AR5K_TUNE_DEFAULT_TXPOWER); + ah->ah_txpower.txp_max_pwr / 2); if (ret) return ret; -- cgit v0.10.2 From cd417519086b223562b50c364d7beab12ef4c62c Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Thu, 30 Apr 2009 15:55:45 -0400 Subject: ath5k: Read Spur channels from EEPROM * Read Spur channel information from EEPROM and use default channels for RF5413 compatible chips that don't have this info on EEPROM. Signed-off-by: Nick Kossifidis Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index c85429d..587c5b8 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -1694,9 +1694,40 @@ ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) return 0; } +static int +ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 offset; + u16 val; + int ret = 0, i; + + offset = AR5K_EEPROM_CTL(ee->ee_version) + + AR5K_EEPROM_N_CTLS(ee->ee_version); + + if (ee->ee_version < AR5K_EEPROM_VERSION_5_3) { + /* No spur info for 5GHz */ + ee->ee_spur_chans[0][0] = AR5K_EEPROM_NO_SPUR; + /* 2 channels for 2GHz (2464/2420) */ + ee->ee_spur_chans[0][1] = AR5K_EEPROM_5413_SPUR_CHAN_1; + ee->ee_spur_chans[1][1] = AR5K_EEPROM_5413_SPUR_CHAN_2; + ee->ee_spur_chans[2][1] = AR5K_EEPROM_NO_SPUR; + } else if (ee->ee_version >= AR5K_EEPROM_VERSION_5_3) { + for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) { + AR5K_EEPROM_READ(offset, val); + ee->ee_spur_chans[i][0] = val; + AR5K_EEPROM_READ(offset + AR5K_EEPROM_N_SPUR_CHANS, + val); + ee->ee_spur_chans[i][1] = val; + offset++; + } + } + + return ret; +} /* - * Initialize eeprom power tables + * Initialize eeprom data structure */ int ath5k_eeprom_init(struct ath5k_hw *ah) @@ -1719,6 +1750,10 @@ ath5k_eeprom_init(struct ath5k_hw *ah) if (err < 0) return err; + err = ath5k_eeprom_read_spur_chans(ah); + if (err < 0) + return err; + return 0; } diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index b0c0606..df9ffa0 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -211,6 +211,23 @@ #define AR5K_EEPROM_I_GAIN 10 #define AR5K_EEPROM_CCK_OFDM_DELTA 15 #define AR5K_EEPROM_N_IQ_CAL 2 +/* 5GHz/2GHz */ +enum ath5k_eeprom_freq_bands{ + AR5K_EEPROM_BAND_5GHZ = 0, + AR5K_EEPROM_BAND_2GHZ = 1, + AR5K_EEPROM_N_FREQ_BANDS, +}; +/* Spur chans per freq band */ +#define AR5K_EEPROM_N_SPUR_CHANS 5 +/* fbin value for chan 2464 x2 */ +#define AR5K_EEPROM_5413_SPUR_CHAN_1 1640 +/* fbin value for chan 2420 x2 */ +#define AR5K_EEPROM_5413_SPUR_CHAN_2 1200 +#define AR5K_EEPROM_SPUR_CHAN_MASK 0x3FFF +#define AR5K_EEPROM_NO_SPUR 0x8000 +#define AR5K_SPUR_CHAN_WIDTH 87 +#define AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz 3125 +#define AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz 6250 #define AR5K_EEPROM_READ(_o, _v) do { \ ret = ath5k_hw_eeprom_read(ah, (_o), &(_v)); \ @@ -436,6 +453,9 @@ struct ath5k_eeprom_info { s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES]; s8 ee_pd_gain_overlap; + /* Spur mitigation data (fbin values for spur channels) */ + u16 ee_spur_chans[AR5K_EEPROM_N_SPUR_CHANS][AR5K_EEPROM_N_FREQ_BANDS]; + u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; -- cgit v0.10.2 From 1889ba0a48688b639c2b2e9e1b0fd8f84e2c37d1 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Thu, 30 Apr 2009 15:55:46 -0400 Subject: ath5k: Put remaining EEPROM data on ee struct * Put remaining EEPROM information on ee struct and remove is_hb63 function. Now we also have rfkill stuff available. Signed-off-by: Nick Kossifidis Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 587c5b8..8c9dd01 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -156,6 +156,17 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; } + AR5K_EEPROM_READ(AR5K_EEPROM_IS_HB63, val); + + if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && val) + ee->ee_is_hb63 = true; + else + ee->ee_is_hb63 = false; + + AR5K_EEPROM_READ(AR5K_EEPROM_RFKILL, val); + ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL); + ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false; + return 0; } @@ -1789,16 +1800,3 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) return 0; } - -bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah) -{ - u16 data; - - ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data); - - if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data) - return true; - else - return false; -} - diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index df9ffa0..46e4d22 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -26,6 +26,13 @@ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ #define AR5K_EEPROM_IS_HB63 0x000b /* Talon detect */ + +#define AR5K_EEPROM_RFKILL 0x0f +#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 + #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ #define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ @@ -66,11 +73,6 @@ #define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ #define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ -#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) @@ -386,6 +388,9 @@ struct ath5k_eeprom_info { u16 ee_version; u16 ee_header; u16 ee_ant_gain; + u8 ee_rfkill_pin; + bool ee_rfkill_pol; + bool ee_is_hb63; u16 ee_misc0; u16 ee_misc1; u16 ee_misc2; diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index cb8a9a1..d419c6a 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -507,7 +507,7 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) scal = AR5K_PHY_SCAL_32MHZ_2417; - else if (ath5k_eeprom_is_hb63(ah)) + else if (ee->ee_is_hb63) scal = AR5K_PHY_SCAL_32MHZ_HB63; else scal = AR5K_PHY_SCAL_32MHZ; @@ -598,9 +598,10 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, /* Set DAC/ADC delays */ if (ah->ah_version == AR5K_AR5212) { u32 scal; + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) scal = AR5K_PHY_SCAL_32MHZ_2417; - else if (ath5k_eeprom_is_hb63(ah)) + else if (ee->ee_is_hb63) scal = AR5K_PHY_SCAL_32MHZ_HB63; else scal = AR5K_PHY_SCAL_32MHZ; -- cgit v0.10.2 From 428cbd4ff4d0f2423f49e499f499f04a636cb152 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Thu, 30 Apr 2009 15:55:47 -0400 Subject: ath5k: Beaconing fixes * Write next beacon timer even on AP mode since without this we get no beacons + ath9k does it too. Docs say that we must write 0 on this register on AP mode to start TSF increment, we do both to be on the safe side. * Fix num_tx_pending function, we never read the register :P that's why we got all those "beacon queue 7 didn't stop messages". * Put full prioriy on beacon queue, lock all queues with lower priority using the arblock and also bypass any arblock by seting the arblock ignore flag. * For the CAB queue (do we need this thing ?, it seems crap) since it's supposed to fire up after each beacon (we don't use it on driver part, ath9k/MadWiFi does), don't make it DBA gated but instead make it fire after each beacon by using the beacon sent gated flag. * Increase bmiss threshold to 10, that's what we used on MadWiFi for a long time. Also when we have pending frames on the beacon queue (we got a beacon that didn't make it on the air) it's more likely that the beacon queue never started, probably due to faulty DBA setting, so change that "beacon queue didn't stop" message. Tested this with AP mode and IBSS mode and seems to work fine ;-) Signed-off-by: Nick Kossifidis Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index d70856a..b48ff7d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1738,35 +1738,6 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, } } -static void ath5k_tasklet_beacon(unsigned long data) -{ - struct ath5k_softc *sc = (struct ath5k_softc *) data; - - /* - * Software beacon alert--time to send a beacon. - * - * In IBSS mode we use this interrupt just to - * keep track of the next TBTT (target beacon - * transmission time) in order to detect wether - * automatic TSF updates happened. - */ - if (sc->opmode == NL80211_IFTYPE_ADHOC) { - /* XXX: only if VEOL suppported */ - u64 tsf = ath5k_hw_get_tsf64(sc->ah); - sc->nexttbtt += sc->bintval; - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "SWBA nexttbtt: %x hw_tu: %x " - "TSF: %llx\n", - sc->nexttbtt, - TSF_TO_TU(tsf), - (unsigned long long) tsf); - } else { - spin_lock(&sc->block); - ath5k_beacon_send(sc); - spin_unlock(&sc->block); - } -} - static void ath5k_tasklet_rx(unsigned long data) { @@ -2120,7 +2091,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->bmisscount++; ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "missed %u consecutive beacons\n", sc->bmisscount); - if (sc->bmisscount > 3) { /* NB: 3 is a guess */ + if (sc->bmisscount > 10) { /* NB: 10 is a guess */ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "stuck beacon time (%u missed)\n", sc->bmisscount); @@ -2141,10 +2112,12 @@ ath5k_beacon_send(struct ath5k_softc *sc) * are still pending on the queue. */ if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { - ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); + ATH5K_WARN(sc, "beacon queue %u didn't start/stop ?\n", sc->bhalq); /* NB: hw still stops DMA, so proceed */ } + /* Note: Beacon buffer is updated on beacon_update when mac80211 + * calls config_interface */ 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", @@ -2301,6 +2274,35 @@ ath5k_beacon_config(struct ath5k_softc *sc) ath5k_hw_set_imr(ah, sc->imask); } +static void ath5k_tasklet_beacon(unsigned long data) +{ + struct ath5k_softc *sc = (struct ath5k_softc *) data; + + /* + * Software beacon alert--time to send a beacon. + * + * In IBSS mode we use this interrupt just to + * keep track of the next TBTT (target beacon + * transmission time) in order to detect wether + * automatic TSF updates happened. + */ + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + /* XXX: only if VEOL suppported */ + u64 tsf = ath5k_hw_get_tsf64(sc->ah); + sc->nexttbtt += sc->bintval; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "SWBA nexttbtt: %x hw_tu: %x " + "TSF: %llx\n", + sc->nexttbtt, + TSF_TO_TU(tsf), + (unsigned long long) tsf); + } else { + spin_lock(&sc->block); + ath5k_beacon_send(sc); + spin_unlock(&sc->block); + } +} + /********************\ * Interrupt handling * diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 5f07e87..579aa0a 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -736,8 +736,8 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) /* When in AP mode zero timer0 to start TSF */ if (ah->ah_op_mode == NL80211_IFTYPE_AP) ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); - else - ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); + + 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); diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 5094c39..73407b3 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -160,7 +160,8 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) if (ah->ah_version == AR5K_AR5210) return false; - pending = (AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT); + pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue)); + pending &= AR5K_QCU_STS_FRMPENDCNT; /* It's possible to have no frames pending even if TXE * is set. To indicate that q has not stopped return @@ -401,14 +402,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) 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_ARBLOCK_IGNORE | AR5K_DCU_MISC_POST_FR_BKOFF_DIS | AR5K_DCU_MISC_BCN_ENABLE); break; case AR5K_TX_QUEUE_CAB: AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_FRSHED_BCN_SENT_GT | AR5K_QCU_MISC_CBREXP_DIS | + AR5K_QCU_MISC_RDY_VEOL_POLICY | AR5K_QCU_MISC_CBREXP_BCN_DIS); ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - -- cgit v0.10.2 From 6f5f39c95af519c24c0187950147eb79d07d1940 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 30 Apr 2009 15:55:48 -0400 Subject: ath5k: Enable AP mode After some debuging we were hitting the following bugs so far... * Due to huge channel list hostapd couldn't get infos from the driver and couldn't set the channel. If we manualy set the channel after hostapd starts (by setting channel to 0 -auto), beacons are sent but they wont show up on scan because they are malformed (they have channel = 0 because hostapd doesn't update the channel info -this is probably a hostapd bug so i'm CCing Jouni) and they get dropped. Bob fixed this by only allowing standard channels to be registered so now hostapd works as expected. * Docs (and HAL source) say that we must write 0 on timer0 when operating on AP mode to start TSF increment but this seems to mess with DBA in many cases and beacon queue never gets started. We fixed that on the previous patch. We have some more things to deal with... * For some reason (hw bug or something else) after restarting hostapd a few times, beacon inteval seems to change from 100ms to a sec (we get one beacon per sec). * We need to set sleep timers on STA mode and enable power saving + support PCF. ...but i think it's time we enable AP support "officialy" so that we can get more feedback from users. I ran ath5k with the mentioned patches + hostapd 0.6.8 and AP mode worked fine (it had some less throughput on my tests than IBSS but it worked). Signed-off-by: Nick Kossifidis Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index b48ff7d..912ffc5 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -516,6 +516,7 @@ ath5k_pci_probe(struct pci_dev *pdev, IEEE80211_HW_NOISE_DBM; hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); -- cgit v0.10.2 From 2bed03ebf62f9d013a455209bf30d7e086120443 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Thu, 30 Apr 2009 15:55:49 -0400 Subject: ath5k: Implement antenna control * Add code to support the various antenna scenarios supported by hw * For now hardcode the default scenario (single or dual omnis with tx/rx diversity working and tx antenna handled by session -hw keeps track on which antenna it got ack from each ap/station and maps each ap/station to one of the antennas-). Signed-off-by: Nick Kossifidis Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 04b7345..33da290 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -209,7 +209,6 @@ #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false -#define AR5K_TUNE_ANT_DIVERSITY true #define AR5K_TUNE_HWTXTRIES 4 #define AR5K_INIT_CARR_SENSE_EN 1 @@ -420,6 +419,17 @@ enum ath5k_driver_mode { AR5K_MODE_MAX = 5 }; +enum ath5k_ant_mode { + AR5K_ANTMODE_DEFAULT = 0, /* default antenna setup */ + AR5K_ANTMODE_FIXED_A = 1, /* only antenna A is present */ + AR5K_ANTMODE_FIXED_B = 2, /* only antenna B is present */ + AR5K_ANTMODE_SINGLE_AP = 3, /* sta locked on a single ap */ + AR5K_ANTMODE_SECTOR_AP = 4, /* AP with tx antenna set on tx desc */ + AR5K_ANTMODE_SECTOR_STA = 5, /* STA with tx antenna set on tx desc */ + AR5K_ANTMODE_DEBUG = 6, /* Debug mode -A -> Rx, B-> Tx- */ + AR5K_ANTMODE_MAX, +}; + /****************\ TX DEFINITIONS @@ -1051,8 +1061,11 @@ struct ath5k_hw { bool ah_software_retry; u32 ah_limit_tx_retries; - u32 ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; - bool ah_ant_diversity; + /* Antenna Control */ + u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; + u8 ah_ant_mode; + u8 ah_tx_ant; + u8 ah_def_ant; u8 ah_sta_id[ETH_ALEN]; @@ -1267,9 +1280,11 @@ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel 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_phy_disable(struct ath5k_hw *ah); +/* Antenna control */ +extern void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode); +extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant); +extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); /* TX power setup */ extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 70d376c..c41ef58 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -133,7 +133,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) 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 diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 912ffc5..6789c5d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1279,7 +1279,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), hw_rate, - info->control.rates[0].count, keyidx, 0, flags, + info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, cts_rate, duration); if (ret) goto err_unmap; @@ -2009,7 +2009,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath5k_hw *ah = sc->ah; struct ath5k_desc *ds; - int ret, antenna = 0; + int ret = 0; + u8 antenna; u32 flags; bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, @@ -2023,23 +2024,35 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } ds = bf->desc; + antenna = ah->ah_tx_ant; flags = AR5K_TXDESC_NOACK; if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { ds->ds_link = bf->daddr; /* self-linked */ flags |= AR5K_TXDESC_VEOL; - /* - * Let hardware handle antenna switching if txantenna is not set - */ - } else { + } else ds->ds_link = 0; - /* - * Switch antenna every 4 beacons if txantenna is not set - * XXX assumes two antennas - */ - if (antenna == 0) - antenna = sc->bsent & 4 ? 2 : 1; - } + + /* + * If we use multiple antennas on AP and use + * the Sectored AP scenario, switch antenna every + * 4 beacons to make sure everybody hears our AP. + * When a client tries to associate, hw will keep + * track of the tx antenna to be used for this client + * automaticaly, based on ACKed packets. + * + * Note: AP still listens and transmits RTS on the + * default antenna which is supposed to be an omni. + * + * Note2: On sectored scenarios it's possible to have + * multiple antennas (1omni -the default- and 14 sectors) + * so if we choose to actually support this mode we need + * to allow user to set how many antennas we have and tweak + * the code below to send beacons on all of them. + */ + if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP) + antenna = sc->bsent & 4 ? 2 : 1; + /* FIXME: If we are in g mode and rate is a CCK rate * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta @@ -2752,12 +2765,16 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; struct ieee80211_conf *conf = &hw->conf; - int ret; + int ret = 0; mutex_lock(&sc->lock); sc->bintval = conf->beacon_int; + ret = ath5k_chan_set(sc, conf->channel); + if (ret < 0) + return ret; + if ((changed & IEEE80211_CONF_CHANGE_POWER) && (sc->power_level != conf->power_level)) { sc->power_level = conf->power_level; @@ -2766,10 +2783,27 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); } - ret = ath5k_chan_set(sc, conf->channel); + /* TODO: + * 1) Move this on config_interface and handle each case + * separately eg. when we have only one STA vif, use + * AR5K_ANTMODE_SINGLE_AP + * + * 2) Allow the user to change antenna mode eg. when only + * one antenna is present + * + * 3) Allow the user to set default/tx antenna when possible + * + * 4) Default mode should handle 90% of the cases, together + * with fixed a/b and single AP modes we should be able to + * handle 99%. Sectored modes are extreme cases and i still + * haven't found a usage for them. If we decide to support them, + * then we must allow the user to set how many tx antennas we + * have available + */ + ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); mutex_unlock(&sc->lock); - return ret; + return 0; } #define SUPPORTED_FIF_FLAGS \ diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 8c9dd01..c56b494 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -208,16 +208,16 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, 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] = + /* Get antenna switch tables */ + ah->ah_ant_ctl[mode][AR5K_ANT_CTL] = (ee->ee_ant_control[mode][0] << 4); - ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = + ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_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] = + ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] = ee->ee_ant_control[mode][6] | (ee->ee_ant_control[mode][7] << 6) | (ee->ee_ant_control[mode][8] << 12) | diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 46e4d22..64be73a 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -240,11 +240,11 @@ enum ath5k_eeprom_freq_bands{ #define AR5K_EEPROM_READ_HDR(_o, _v) \ AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ -enum ath5k_ant_setting { - AR5K_ANT_VARIABLE = 0, /* variable by programming */ - AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ - AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ - AR5K_ANT_MAX = 3, +enum ath5k_ant_table { + AR5K_ANT_CTL = 0, /* Idle switch table settings */ + AR5K_ANT_SWTABLE_A = 1, /* Switch table for antenna A */ + AR5K_ANT_SWTABLE_B = 2, /* Switch table for antenna B */ + AR5K_ANT_MAX, }; enum ath5k_ctl_mode { @@ -461,6 +461,7 @@ struct ath5k_eeprom_info { /* Spur mitigation data (fbin values for spur channels) */ u16 ee_spur_chans[AR5K_EEPROM_N_SPUR_CHANS][AR5K_EEPROM_N_FREQ_BANDS]; + /* Antenna raw switch tables */ u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index bb61b8e..fd93c4e 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1414,25 +1414,189 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) return ret; } +/*****************\ +* Antenna control * +\*****************/ + void /*TODO:Boundary check*/ -ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant) +ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) { ATH5K_TRACE(ah->ah_sc); - /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) - ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA); + ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA); } unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); - /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) - return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA) & 0x7; return false; /*XXX: What do we return for 5210 ?*/ } +/* + * Enable/disable fast rx antenna diversity + */ +static void +ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) +{ + switch (ee_mode) { + case AR5K_EEPROM_MODE_11G: + /* XXX: This is set to + * disabled on initvals !!! */ + case AR5K_EEPROM_MODE_11A: + if (enable) + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_OFDM_DIV_DIS); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_OFDM_DIV_DIS); + break; + case AR5K_EEPROM_MODE_11B: + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_OFDM_DIV_DIS); + break; + default: + return; + } + + if (enable) { + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, + AR5K_PHY_RESTART_DIV_GC, 0xc); + + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, + AR5K_PHY_FAST_ANT_DIV_EN); + } else { + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, + AR5K_PHY_RESTART_DIV_GC, 0x8); + + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, + AR5K_PHY_FAST_ANT_DIV_EN); + } +} + +/* + * Set antenna operating mode + */ +void +ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) +{ + struct ieee80211_channel *channel = &ah->ah_current_channel; + bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div; + bool use_def_for_sg; + u8 def_ant, tx_ant, ee_mode; + u32 sta_id1 = 0; + + def_ant = ah->ah_def_ant; + + ATH5K_TRACE(ah->ah_sc); + + switch (channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + case CHANNEL_T: + case CHANNEL_XR: + ee_mode = AR5K_EEPROM_MODE_11A; + break; + case CHANNEL_G: + case CHANNEL_TG: + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_B: + ee_mode = AR5K_EEPROM_MODE_11B; + break; + default: + ATH5K_ERR(ah->ah_sc, + "invalid channel: %d\n", channel->center_freq); + return; + } + + switch (ant_mode) { + case AR5K_ANTMODE_DEFAULT: + tx_ant = 0; + use_def_for_tx = false; + update_def_on_tx = false; + use_def_for_rts = false; + use_def_for_sg = false; + fast_div = true; + break; + case AR5K_ANTMODE_FIXED_A: + def_ant = 1; + tx_ant = 0; + use_def_for_tx = true; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = true; + fast_div = false; + break; + case AR5K_ANTMODE_FIXED_B: + def_ant = 2; + tx_ant = 0; + use_def_for_tx = true; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = true; + fast_div = false; + break; + case AR5K_ANTMODE_SINGLE_AP: + def_ant = 1; /* updated on tx */ + tx_ant = 0; + use_def_for_tx = true; + update_def_on_tx = true; + use_def_for_rts = true; + use_def_for_sg = true; + fast_div = true; + break; + case AR5K_ANTMODE_SECTOR_AP: + tx_ant = 1; /* variable */ + use_def_for_tx = false; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = false; + fast_div = false; + break; + case AR5K_ANTMODE_SECTOR_STA: + tx_ant = 1; /* variable */ + use_def_for_tx = true; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = false; + fast_div = true; + break; + case AR5K_ANTMODE_DEBUG: + def_ant = 1; + tx_ant = 2; + use_def_for_tx = false; + update_def_on_tx = false; + use_def_for_rts = false; + use_def_for_sg = false; + fast_div = false; + break; + default: + return; + } + + ah->ah_tx_ant = tx_ant; + ah->ah_ant_mode = ant_mode; + + sta_id1 |= use_def_for_tx ? AR5K_STA_ID1_DEFAULT_ANTENNA : 0; + sta_id1 |= update_def_on_tx ? AR5K_STA_ID1_DESC_ANTENNA : 0; + sta_id1 |= use_def_for_rts ? AR5K_STA_ID1_RTS_DEF_ANTENNA : 0; + sta_id1 |= use_def_for_sg ? AR5K_STA_ID1_SELFGEN_DEF_ANT : 0; + + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_ANTENNA_SETTINGS); + + if (sta_id1) + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, sta_id1); + + /* Note: set diversity before default antenna + * because it won't work correctly */ + ath5k_hw_set_fast_div(ah, ee_mode, fast_div); + ath5k_hw_set_def_antenna(ah, def_ant); +} + /****************\ * TX power setup * diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 7070d15..6809b54a 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -1148,6 +1148,11 @@ #define AR5K_STA_ID1_CBCIV_ENDIAN 0x40000000 /* ??? */ #define AR5K_STA_ID1_KEYSRCH_MCAST 0x80000000 /* Do key cache search for mcast frames */ +#define AR5K_STA_ID1_ANTENNA_SETTINGS (AR5K_STA_ID1_DEFAULT_ANTENNA | \ + AR5K_STA_ID1_DESC_ANTENNA | \ + AR5K_STA_ID1_RTS_DEF_ANTENNA | \ + AR5K_STA_ID1_SELFGEN_DEF_ANT) + /* * First BSSID register (MAC address, lower 32bits) */ @@ -2028,7 +2033,9 @@ #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_OFDM_DIV_DIS 0x00000008 /* Disable antenna diversity on OFDM modes */ #define AR5K_PHY_AGCCTL_NF_EN 0x00008000 /* Enable nf calibration to happen (?) */ +#define AR5K_PHY_AGCTL_FLTR_CAL 0x00010000 /* Allow filter calibration (?) */ #define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ /* @@ -2528,7 +2535,7 @@ * PHY CCK Cross-correlator Barker RSSI threshold register [5212+] */ #define AR5K_PHY_CCK_CROSSCORR 0xa208 -#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000000f +#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000003f #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0 /* Same address is used for antenna diversity activation */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index d419c6a..0e075bc 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -698,13 +698,13 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, /* Set antenna idle switch table */ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL, AR5K_PHY_ANT_CTL_SWTABLE_IDLE, - (ah->ah_antenna[ee_mode][0] | + (ah->ah_ant_ctl[ee_mode][0] | AR5K_PHY_ANT_CTL_TXRX_EN)); - /* Set antenna switch table */ - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], + /* Set antenna switch tables */ + ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[0]], AR5K_PHY_ANT_SWITCH_TABLE_0); - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], + ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[1]], AR5K_PHY_ANT_SWITCH_TABLE_1); /* Noise floor threshold */ @@ -1042,17 +1042,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* * In case a fixed antenna was set as default - * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE - * registers. + * use the same switch table twice. */ - 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; + if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A) + ant[0] = ant[1] = AR5K_ANT_SWTABLE_A; + else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B) + ant[0] = ant[1] = AR5K_ANT_SWTABLE_B; + else { + ant[0] = AR5K_ANT_SWTABLE_A; + ant[1] = AR5K_ANT_SWTABLE_B; } /* Commit values from EEPROM */ @@ -1260,6 +1258,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + /* Restore antenna mode */ + ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); /* * Configure QCUs/DCUs -- cgit v0.10.2 From 57e6c56dbb52d680f61dd629759fe2974840ed93 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Thu, 30 Apr 2009 15:55:50 -0400 Subject: ath5k: Add Spur filter support on newer chips * Add spur filter support for RF5413 and later chips Signed-off-by: Nick Kossifidis Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 33da290..8137182 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1278,6 +1278,11 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann /* PHY calibration */ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +/* Spur mitigation */ +bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, + struct ieee80211_channel *channel); +void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, + struct ieee80211_channel *channel); /* Misc PHY functions */ extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index fd93c4e..6737ba0 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1353,6 +1353,257 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, return ret; } +/***************************\ +* Spur mitigation functions * +\***************************/ + +bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u8 refclk_freq; + + if ((ah->ah_radio == AR5K_RF5112) || + (ah->ah_radio == AR5K_RF5413) || + (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) + refclk_freq = 40; + else + refclk_freq = 32; + + if ((channel->center_freq % refclk_freq != 0) && + ((channel->center_freq % refclk_freq < 10) || + (channel->center_freq % refclk_freq > 22))) + return true; + else + return false; +} + +void +ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 mag_mask[4] = {0, 0, 0, 0}; + u32 pilot_mask[2] = {0, 0}; + /* Note: fbin values are scaled up by 2 */ + u16 spur_chan_fbin, chan_fbin, symbol_width, spur_detection_window; + s32 spur_delta_phase, spur_freq_sigma_delta; + s32 spur_offset, num_symbols_x16; + u8 num_symbol_offsets, i, freq_band; + + /* Convert current frequency to fbin value (the same way channels + * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale + * up by 2 so we can compare it later */ + if (channel->hw_value & CHANNEL_2GHZ) { + chan_fbin = (channel->center_freq - 2300) * 10; + freq_band = AR5K_EEPROM_BAND_2GHZ; + } else { + chan_fbin = (channel->center_freq - 4900) * 10; + freq_band = AR5K_EEPROM_BAND_5GHZ; + } + + /* Check if any spur_chan_fbin from EEPROM is + * within our current channel's spur detection range */ + spur_chan_fbin = AR5K_EEPROM_NO_SPUR; + spur_detection_window = AR5K_SPUR_CHAN_WIDTH; + /* XXX: Half/Quarter channels ?*/ + if (channel->hw_value & CHANNEL_TURBO) + spur_detection_window *= 2; + + for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) { + spur_chan_fbin = ee->ee_spur_chans[i][freq_band]; + + /* Note: mask cleans AR5K_EEPROM_NO_SPUR flag + * so it's zero if we got nothing from EEPROM */ + if (spur_chan_fbin == AR5K_EEPROM_NO_SPUR) { + spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; + break; + } + + if ((chan_fbin - spur_detection_window <= + (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK)) && + (chan_fbin + spur_detection_window >= + (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK))) { + spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; + break; + } + } + + /* We need to enable spur filter for this channel */ + if (spur_chan_fbin) { + spur_offset = spur_chan_fbin - chan_fbin; + /* + * Calculate deltas: + * spur_freq_sigma_delta -> spur_offset / sample_freq << 21 + * spur_delta_phase -> spur_offset / chip_freq << 11 + * Note: Both values have 100KHz resolution + */ + /* XXX: Half/Quarter rate channels ? */ + switch (channel->hw_value) { + case CHANNEL_A: + /* Both sample_freq and chip_freq are 40MHz */ + spur_delta_phase = (spur_offset << 17) / 25; + spur_freq_sigma_delta = (spur_delta_phase >> 10); + symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; + break; + case CHANNEL_G: + /* sample_freq -> 40MHz chip_freq -> 44MHz + * (for b compatibility) */ + spur_freq_sigma_delta = (spur_offset << 8) / 55; + spur_delta_phase = (spur_offset << 17) / 25; + symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; + break; + case CHANNEL_T: + case CHANNEL_TG: + /* Both sample_freq and chip_freq are 80MHz */ + spur_delta_phase = (spur_offset << 16) / 25; + spur_freq_sigma_delta = (spur_delta_phase >> 10); + symbol_width = AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz; + break; + default: + return; + } + + /* Calculate pilot and magnitude masks */ + + /* Scale up spur_offset by 1000 to switch to 100HZ resolution + * and divide by symbol_width to find how many symbols we have + * Note: number of symbols is scaled up by 16 */ + num_symbols_x16 = ((spur_offset * 1000) << 4) / symbol_width; + + /* Spur is on a symbol if num_symbols_x16 % 16 is zero */ + if (!(num_symbols_x16 & 0xF)) + /* _X_ */ + num_symbol_offsets = 3; + else + /* _xx_ */ + num_symbol_offsets = 4; + + for (i = 0; i < num_symbol_offsets; i++) { + + /* Calculate pilot mask */ + s32 curr_sym_off = + (num_symbols_x16 / 16) + i + 25; + + /* Pilot magnitude mask seems to be a way to + * declare the boundaries for our detection + * window or something, it's 2 for the middle + * value(s) where the symbol is expected to be + * and 1 on the boundary values */ + u8 plt_mag_map = + (i == 0 || i == (num_symbol_offsets - 1)) + ? 1 : 2; + + if (curr_sym_off >= 0 && curr_sym_off <= 32) { + if (curr_sym_off <= 25) + pilot_mask[0] |= 1 << curr_sym_off; + else if (curr_sym_off >= 27) + pilot_mask[0] |= 1 << (curr_sym_off - 1); + } else if (curr_sym_off >= 33 && curr_sym_off <= 52) + pilot_mask[1] |= 1 << (curr_sym_off - 33); + + /* Calculate magnitude mask (for viterbi decoder) */ + if (curr_sym_off >= -1 && curr_sym_off <= 14) + mag_mask[0] |= + plt_mag_map << (curr_sym_off + 1) * 2; + else if (curr_sym_off >= 15 && curr_sym_off <= 30) + mag_mask[1] |= + plt_mag_map << (curr_sym_off - 15) * 2; + else if (curr_sym_off >= 31 && curr_sym_off <= 46) + mag_mask[2] |= + plt_mag_map << (curr_sym_off - 31) * 2; + else if (curr_sym_off >= 46 && curr_sym_off <= 53) + mag_mask[3] |= + plt_mag_map << (curr_sym_off - 47) * 2; + + } + + /* Write settings on hw to enable spur filter */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_RATE, 0xff); + /* XXX: Self correlator also ? */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_PILOT_MASK_EN | + AR5K_PHY_IQ_CHAN_MASK_EN | + AR5K_PHY_IQ_SPUR_FILT_EN); + + /* Set delta phase and freq sigma delta */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(spur_delta_phase, + AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE) | + AR5K_REG_SM(spur_freq_sigma_delta, + AR5K_PHY_TIMING_11_SPUR_FREQ_SD) | + AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC, + AR5K_PHY_TIMING_11); + + /* Write pilot masks */ + ath5k_hw_reg_write(ah, pilot_mask[0], AR5K_PHY_TIMING_7); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, + AR5K_PHY_TIMING_8_PILOT_MASK_2, + pilot_mask[1]); + + ath5k_hw_reg_write(ah, pilot_mask[0], AR5K_PHY_TIMING_9); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, + AR5K_PHY_TIMING_10_PILOT_MASK_2, + pilot_mask[1]); + + /* Write magnitude masks */ + ath5k_hw_reg_write(ah, mag_mask[0], AR5K_PHY_BIN_MASK_1); + ath5k_hw_reg_write(ah, mag_mask[1], AR5K_PHY_BIN_MASK_2); + ath5k_hw_reg_write(ah, mag_mask[2], AR5K_PHY_BIN_MASK_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_MASK_4, + mag_mask[3]); + + ath5k_hw_reg_write(ah, mag_mask[0], AR5K_PHY_BIN_MASK2_1); + ath5k_hw_reg_write(ah, mag_mask[1], AR5K_PHY_BIN_MASK2_2); + ath5k_hw_reg_write(ah, mag_mask[2], AR5K_PHY_BIN_MASK2_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, + AR5K_PHY_BIN_MASK2_4_MASK_4, + mag_mask[3]); + + } else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & + AR5K_PHY_IQ_SPUR_FILT_EN) { + /* Clean up spur mitigation settings and disable fliter */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_RATE, 0); + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_PILOT_MASK_EN | + AR5K_PHY_IQ_CHAN_MASK_EN | + AR5K_PHY_IQ_SPUR_FILT_EN); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_11); + + /* Clear pilot masks */ + ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_7); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, + AR5K_PHY_TIMING_8_PILOT_MASK_2, + 0); + + ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_9); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, + AR5K_PHY_TIMING_10_PILOT_MASK_2, + 0); + + /* Clear magnitude masks */ + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_1); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_2); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_MASK_4, + 0); + + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_1); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_2); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, + AR5K_PHY_BIN_MASK2_4_MASK_4, + 0); + } +} + +/********************\ + Misc PHY functions +\********************/ + int ath5k_hw_phy_disable(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); @@ -1362,10 +1613,6 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah) return 0; } -/********************\ - Misc PHY functions -\********************/ - /* * Get the PHY Chip revision */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 0e075bc..c1862f8 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -536,26 +536,6 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) return; } -static bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u8 refclk_freq; - - if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413) || - (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) - refclk_freq = 40; - else - refclk_freq = 32; - - if ((channel->center_freq % refclk_freq != 0) && - ((channel->center_freq % refclk_freq < 10) || - (channel->center_freq % refclk_freq > 22))) - return true; - else - return false; -} - /* TODO: Half/Quarter rate */ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, struct ieee80211_channel *channel) @@ -998,7 +978,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_tweak_initval_settings(ah, channel); /* - * Set TX power (FIXME) + * Set TX power */ ret = ath5k_hw_txpower(ah, channel, ee_mode, ah->ah_txpower.txp_max_pwr / 2); @@ -1024,9 +1004,22 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Write OFDM timings on 5212*/ if (ah->ah_version == AR5K_AR5212 && channel->hw_value & CHANNEL_OFDM) { + struct ath5k_eeprom_info *ee = + &ah->ah_capabilities.cap_eeprom; + ret = ath5k_hw_write_ofdm_timings(ah, channel); if (ret) return ret; + + /* Note: According to docs we can have a newer + * EEPROM on old hardware, so we need to verify + * that our hardware is new enough to have spur + * mitigation registers (delta phase etc) */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5424 || + (ah->ah_mac_srev >= AR5K_SREV_AR5424 && + ee->ee_version >= AR5K_EEPROM_VERSION_5_3)) + ath5k_hw_set_spur_mitigation_filter(ah, + channel); } /*Enable/disable 802.11b mode on 5111 -- cgit v0.10.2 From 6752ee90aa7c933294a10dbd9ea51f12dece7eb1 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 30 Apr 2009 15:55:51 -0400 Subject: ath5k: use ctl settings based on current regdomain Update ath5k to use the ctl settings for tx power based on current regulatory domain. Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 6737ba0..d0d1c35 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -2158,8 +2158,6 @@ done: * Get the max edge power for this channel if * we have such data from EEPROM's Conformance Test * Limits (CTL), and limit max power if needed. - * - * FIXME: Only works for world regulatory domains */ static void ath5k_get_max_ctl_power(struct ath5k_hw *ah, @@ -2175,26 +2173,23 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, u8 ctl_idx = 0xFF; u32 target = channel->center_freq; - /* Find out a CTL for our mode that's not mapped - * on a specific reg domain. - * - * TODO: Map our current reg domain to one of the 3 available - * reg domain ids so that we can support more CTLs. */ + ctl_mode = ath_regd_get_band_ctl(&ah->ah_regulatory, channel->band); + switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: - ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_11A; break; case CHANNEL_G: - ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_11G; break; case CHANNEL_B: - ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_11B; break; case CHANNEL_T: - ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_TURBO; break; case CHANNEL_TG: - ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_TURBOG; break; case CHANNEL_XR: /* Fall through */ -- cgit v0.10.2 From 84379cba44042a4caf793f821be8bd1a9b8235c2 Mon Sep 17 00:00:00 2001 From: Paride Legovini Date: Thu, 30 Apr 2009 15:55:52 -0400 Subject: Add LED support for AR5BXB6 IBM Thinkpad PCIe adapters Add LED support on the IBM ThinkPad 11a/b/g Wireless LAN Mini Express Adapter (AR5BXB6), found on the IBM/Lenovo Thinkpad X60/T60/Z60 series. Signed-off-by: Paride Legovini Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index cbdc0b3..876725f 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -53,8 +53,6 @@ /* Devices we match on for LED config info (typically laptops) */ static const struct pci_device_id ath5k_led_devices[] = { - /* IBM-specific AR5212 */ - { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, /* AR5211 */ { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) }, /* HP Compaq nc6xx, nc4000, nx6000 */ @@ -69,6 +67,10 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) }, /* Fukato Datacask Jupiter 1014a (mrb74@gmx.at) */ { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) }, + /* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */ + { ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) }, + /* IBM-specific AR5212 (all others) */ + { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, { } }; -- cgit v0.10.2 From 722404983b9deb21e4f786224201ca2ab27a1c48 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Thu, 30 Apr 2009 13:56:26 -0700 Subject: iwl3945: fix lock dependency Patch seperates rx_used and rx_free into two different atomic contexts. We can now avoid using GFP_ATOMIC for skb allocation and use GFP_KERNEL. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5cd4321..dc0359c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1344,15 +1344,24 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { + + while (1) { + spin_lock_irqsave(&rxq->lock, flags); + + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + return; + } + element = rxq->rx_used.next; rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + spin_unlock_irqrestore(&rxq->lock, flags); /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size, - __GFP_NOWARN | GFP_ATOMIC); + GFP_KERNEL); if (!rxb->skb) { if (net_ratelimit()) IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); @@ -1370,18 +1379,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) */ skb_reserve(rxb->skb, 4); - priv->alloc_rxb_skb++; - list_del(element); - /* Get physical address of RB/SKB */ rxb->real_dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); + + spin_lock_irqsave(&rxq->lock, flags); list_add_tail(&rxb->list, &rxq->rx_free); + priv->alloc_rxb_skb++; rxq->free_count++; + spin_unlock_irqrestore(&rxq->lock, flags); } - spin_unlock_irqrestore(&rxq->lock, flags); } void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) @@ -1414,18 +1423,6 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) spin_unlock_irqrestore(&rxq->lock, flags); } -/* - * this should be called while priv->lock is locked - */ -static void __iwl3945_rx_replenish(void *data) -{ - struct iwl_priv *priv = data; - - iwl3945_rx_allocate(priv); - iwl3945_rx_queue_restock(priv); -} - - void iwl3945_rx_replenish(void *data) { struct iwl_priv *priv = data; @@ -1644,7 +1641,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl3945_rx_replenish(priv); + iwl3945_rx_queue_restock(priv); count = 0; } } -- cgit v0.10.2 From 286d94906587901851906a5e2ddc09bc1a7ba1d9 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 30 Apr 2009 13:56:27 -0700 Subject: iwlagn: disable PS support for iwlagn Some issues in PS prevent us from supporting it reliably. When 4965 goes to sleep it stores some data in host DRAM, reads it back when device wakes up. In 4965 there is a problem that the data is not correct when ucode starts using it upon wakeup. For all iwlagn devices there is a problem where command is sent when PS is enabled. At the moment there is a locking problem with priv->lock not being held and thus not requesting nic access correctly. We disable PS until these issues have been resolved. Signed-off-by: Reinette Chatre Signed-off-by: Mohamed Abbas Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0f21fc1..1366222 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1298,8 +1298,7 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_SUPPORTS_PS; + IEEE80211_HW_SPECTRUM_MGMT; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); -- cgit v0.10.2 From a30199f129e17998f802d3307907560431e78493 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 30 Apr 2009 13:56:28 -0700 Subject: iwlwifi: "is_fat" bit in rate scale match RXON flag This patch change the "is_fat" checking in rate scale to use iwl_is_fat_tx_allowed() to match the sta and RX_ON command setting. Signed-off-by: Wey-Yi Guy Tested-by: Conrad Kostecki Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 29d38b9..0a71bb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1207,8 +1207,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->action = 0; rate_mask = lq_sta->active_mimo2_rate; - if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) + if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) tbl->is_fat = 1; else tbl->is_fat = 0; @@ -1273,8 +1272,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, tbl->action = 0; rate_mask = lq_sta->active_mimo3_rate; - if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) + if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) tbl->is_fat = 1; else tbl->is_fat = 0; @@ -1332,8 +1330,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->action = 0; rate_mask = lq_sta->active_siso_rate; - if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) + if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) tbl->is_fat = 1; else tbl->is_fat = 0; -- cgit v0.10.2 From 4e8e2c824027ed433be3c599294bf093a120ad9d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 30 Apr 2009 13:56:29 -0700 Subject: iwlwifi: replace test_and_set_bit by set_bit in clear stations function This patch replaces test_and_set_bit by set_bit since the bit is not tested anyway Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 17a4dd2..28dd225 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -490,7 +490,7 @@ void iwl_clear_stations_table(struct iwl_priv *priv) /* keep track of static keys */ for (i = 0; i < WEP_KEYS_MAX ; i++) { if (priv->wep_keys[i].key_size) - test_and_set_bit(i, &priv->ucode_key_table); + set_bit(i, &priv->ucode_key_table); } spin_unlock_irqrestore(&priv->sta_lock, flags); -- cgit v0.10.2 From 8bce6121706dd82c266c3f527e592abfb3e164d1 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 1 May 2009 08:20:07 -0400 Subject: wl12xx: correct printk format warnings Fixes warnings: drivers/net/wireless/wl12xx/main.c:87: warning: int format, different type arg (arg 2) drivers/net/wireless/wl12xx/main.c: In function `wl12xx_fetch_nvs': drivers/net/wireless/wl12xx/main.c:125: warning: int format, different type arg (arg 2) drivers/net/wireless/wl12xx/wl1251.c: In function 'wl1251_upload_firmware': drivers/net/wireless/wl12xx/wl1251.c:94: warning: int format, different type arg (arg 2) drivers/net/wireless/wl12xx/wl1251.c:141: warning: int format, different type arg (arg 2) Signed-off-by: Bob Copeland Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 744f4ce..603d611 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -84,7 +84,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl) } if (fw->size % 4) { - wl12xx_error("firmware size is not multiple of 32 bits: %d", + wl12xx_error("firmware size is not multiple of 32 bits: %zu", fw->size); ret = -EILSEQ; goto out; @@ -122,7 +122,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl) } if (fw->size % 4) { - wl12xx_error("nvs size is not multiple of 32 bits: %d", + wl12xx_error("nvs size is not multiple of 32 bits: %zu", fw->size); ret = -EILSEQ; goto out; diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index bd0decd..ce1561a 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -91,7 +91,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl) fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | (wl->fw[6] << 8) | (wl->fw[7]); - wl12xx_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len, + wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, CHUNK_SIZE); if ((fw_data_len % 4) != 0) { @@ -138,7 +138,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl) /* 10.4 upload the last chunk */ addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x", + wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); -- cgit v0.10.2 From 928841b1538df117658ec5977bcf336c27f7747b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Apr 2009 23:02:47 -0700 Subject: Wireless: remove driver_data direct access of struct device In the near future, the driver core is going to not allow direct access to the driver_data pointer in struct device. Instead, the functions dev_get_drvdata() and dev_set_drvdata() should be used. These functions have been around since the beginning, so are backwards compatible with all older kernel versions. Cc: John W. Linville Cc: linux-wireless@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 7740624..ddaa859 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -279,7 +279,7 @@ static int atmel_config(struct pcmcia_device *link) struct pcmcia_device_id *did; dev = link->priv; - did = handle_to_dev(link).driver_data; + did = dev_get_drvdata(&handle_to_dev(link)); DEBUG(0, "atmel_config(0x%p)\n", link); diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 97e5647..7424323 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -3488,7 +3488,7 @@ static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL); static ssize_t show_cfg(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw2100_priv *p = d->driver_data; + struct ipw2100_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->config); } @@ -3497,7 +3497,7 @@ static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw2100_priv *p = d->driver_data; + struct ipw2100_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->status); } @@ -3506,7 +3506,7 @@ static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static ssize_t show_capability(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw2100_priv *p = d->driver_data; + struct ipw2100_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->capability); } @@ -4224,7 +4224,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, 1 - SW based RF kill active (sysfs) 2 - HW based RF kill active 3 - Both HW and SW baed RF kill active */ - struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data; + struct ipw2100_priv *priv = dev_get_drvdata(d); int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | (rf_kill_active(priv) ? 0x2 : 0x0); return sprintf(buf, "%i\n", val); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 9a123fb..c3b3dfe 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -1527,7 +1527,7 @@ static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->status); } @@ -1536,7 +1536,7 @@ static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static ssize_t show_cfg(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->config); } @@ -1545,7 +1545,7 @@ static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); static ssize_t show_nic_type(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); return sprintf(buf, "TYPE: %d\n", priv->nic_type); } @@ -1555,7 +1555,7 @@ static ssize_t show_ucode_version(struct device *d, struct device_attribute *attr, char *buf) { u32 len = sizeof(u32), tmp = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len)) return 0; @@ -1569,7 +1569,7 @@ static ssize_t show_rtc(struct device *d, struct device_attribute *attr, char *buf) { u32 len = sizeof(u32), tmp = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len)) return 0; @@ -1586,14 +1586,15 @@ static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL); static ssize_t show_eeprom_delay(struct device *d, struct device_attribute *attr, char *buf) { - int n = ((struct ipw_priv *)d->driver_data)->eeprom_delay; + struct ipw_priv *p = dev_get_drvdata(d); + int n = p->eeprom_delay; return sprintf(buf, "%i\n", n); } static ssize_t store_eeprom_delay(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); sscanf(buf, "%i", &p->eeprom_delay); return strnlen(buf, count); } @@ -1605,7 +1606,7 @@ static ssize_t show_command_event_reg(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT); return sprintf(buf, "0x%08x\n", reg); @@ -1615,7 +1616,7 @@ static ssize_t store_command_event_reg(struct device *d, const char *buf, size_t count) { u32 reg; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); sscanf(buf, "%x", ®); ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg); @@ -1629,7 +1630,7 @@ static ssize_t show_mem_gpio_reg(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); reg = ipw_read_reg32(p, 0x301100); return sprintf(buf, "0x%08x\n", reg); @@ -1639,7 +1640,7 @@ static ssize_t store_mem_gpio_reg(struct device *d, const char *buf, size_t count) { u32 reg; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); sscanf(buf, "%x", ®); ipw_write_reg32(p, 0x301100, reg); @@ -1653,7 +1654,7 @@ static ssize_t show_indirect_dword(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (priv->status & STATUS_INDIRECT_DWORD) reg = ipw_read_reg32(priv, priv->indirect_dword); @@ -1666,7 +1667,7 @@ static ssize_t store_indirect_dword(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); sscanf(buf, "%x", &priv->indirect_dword); priv->status |= STATUS_INDIRECT_DWORD; @@ -1680,7 +1681,7 @@ static ssize_t show_indirect_byte(struct device *d, struct device_attribute *attr, char *buf) { u8 reg = 0; - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (priv->status & STATUS_INDIRECT_BYTE) reg = ipw_read_reg8(priv, priv->indirect_byte); @@ -1693,7 +1694,7 @@ static ssize_t store_indirect_byte(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); sscanf(buf, "%x", &priv->indirect_byte); priv->status |= STATUS_INDIRECT_BYTE; @@ -1707,7 +1708,7 @@ static ssize_t show_direct_dword(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (priv->status & STATUS_DIRECT_DWORD) reg = ipw_read32(priv, priv->direct_dword); @@ -1720,7 +1721,7 @@ static ssize_t store_direct_dword(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); sscanf(buf, "%x", &priv->direct_dword); priv->status |= STATUS_DIRECT_DWORD; @@ -1747,7 +1748,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, 1 - SW based RF kill active (sysfs) 2 - HW based RF kill active 3 - Both HW and SW baed RF kill active */ - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | (rf_kill_active(priv) ? 0x2 : 0x0); return sprintf(buf, "%i\n", val); @@ -1791,7 +1792,7 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); ipw_radio_kill_sw(priv, buf[0] == '1'); @@ -1803,7 +1804,7 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); int pos = 0, len = 0; if (priv->config & CFG_SPEED_SCAN) { while (priv->speed_scan[pos] != 0) @@ -1818,7 +1819,7 @@ static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); int channel, pos = 0; const char *p = buf; @@ -1857,14 +1858,14 @@ static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0'); } static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (buf[0] == '1') priv->config |= CFG_NET_STATS; else diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index dd8b15e..6cdee0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2268,7 +2268,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%08X\n", priv->debug_level); } @@ -2276,7 +2276,7 @@ static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; int ret; @@ -2299,7 +2299,7 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, static ssize_t show_version(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); struct iwl_alive_resp *palive = &priv->card_alive; ssize_t pos = 0; u16 eeprom_ver; @@ -2330,7 +2330,7 @@ static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_alive(priv)) return -EAGAIN; @@ -2343,7 +2343,7 @@ static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_ready_rf(priv)) return sprintf(buf, "off\n"); @@ -2355,7 +2355,7 @@ static ssize_t store_tx_power(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; int ret; @@ -2373,7 +2373,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); static ssize_t show_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); } @@ -2382,7 +2382,7 @@ static ssize_t store_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; u32 flags; int ret = strict_strtoul(buf, 0, &val); @@ -2411,7 +2411,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); static ssize_t show_filter_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.filter_flags)); @@ -2421,7 +2421,7 @@ static ssize_t store_filter_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; u32 filter_flags; int ret = strict_strtoul(buf, 0, &val); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index dc0359c..9f5191a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3595,7 +3595,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%08X\n", priv->debug_level); } @@ -3603,7 +3603,7 @@ static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; int ret; @@ -3624,7 +3624,7 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_alive(priv)) return -EAGAIN; @@ -3637,7 +3637,7 @@ static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%d\n", priv->tx_power_user_lmt); } @@ -3645,7 +3645,7 @@ static ssize_t store_tx_power(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); char *p = (char *)buf; u32 val; @@ -3663,7 +3663,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); static ssize_t show_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); } @@ -3672,7 +3672,7 @@ static ssize_t store_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); u32 flags = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); @@ -3697,7 +3697,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); static ssize_t show_filter_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.filter_flags)); @@ -3707,7 +3707,7 @@ static ssize_t store_filter_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); u32 filter_flags = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); @@ -3992,7 +3992,7 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_alive(priv)) return -EAGAIN; return sprintf(buf, "0x%08x\n", (int)priv->status); @@ -4004,10 +4004,11 @@ static ssize_t dump_error_log(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { + struct iwl_priv *priv = dev_get_drvdata(d); char *p = (char *)buf; if (p[0] == '1') - iwl3945_dump_nic_error_log((struct iwl_priv *)d->driver_data); + iwl3945_dump_nic_error_log(priv); return strnlen(buf, count); } @@ -4018,10 +4019,11 @@ static ssize_t dump_event_log(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { + struct iwl_priv *priv = dev_get_drvdata(d); char *p = (char *)buf; if (p[0] == '1') - iwl3945_dump_nic_event_log((struct iwl_priv *)d->driver_data); + iwl3945_dump_nic_event_log(priv); return strnlen(buf, count); } -- cgit v0.10.2 From 13792578c88961256dd30e3a5d3fa1ac1ec9a7e0 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Fri, 1 May 2009 13:12:36 +0200 Subject: p54usb: Fixes compile error with CONFIG_PM=n /drivers/net/wireless/p54/p54usb.c: In function 'p54u_probe': /drivers/net/wireless/p54/p54usb.c:923: error: 'struct usb_device' has no member named 'reset_resume' In the struct usb_device the reset_resume attribute is only available when CONFIG_PM is defined. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index ec6c954..f40c0f4 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -919,9 +919,11 @@ 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) { +#ifdef CONFIG_PM /* ISL3887 needs a full reset on resume */ udev->reset_resume = 1; err = p54u_device_reset(dev); +#endif priv->hw_type = P54U_3887; dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); -- cgit v0.10.2 From 1b06bb4087d195d8289919df2f4d95ec3b89769e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 2 May 2009 00:34:48 -0400 Subject: cfg80211: make nl80211_send_mlme_timeout() static Fixes sparse complaint: CHECK net/wireless/nl80211.c net/wireless/nl80211.c:3694:6: warning: symbol 'nl80211_send_mlme_timeout' was not declared. Should it be static? Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b1fc982..3c53c5c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3696,9 +3696,9 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, NL80211_CMD_DISASSOCIATE); } -void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, - struct net_device *netdev, int cmd, - const u8 *addr) +static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int cmd, + const u8 *addr) { struct sk_buff *msg; void *hdr; -- cgit v0.10.2 From 7738231f98578c8cd5b367441b4aa79ce864856f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 May 2009 17:52:10 +0200 Subject: mac80211: report operating frequency rather than current It's not very helpful to see, in iwconfig, the current frequency the card is tuned to if that frequency is currently somewhere across the board because we're scanning. Since we keep track of the frequency the user wants, display that instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 1a649da..6b4eb8d 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -185,7 +185,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - freq->m = local->hw.conf.channel->center_freq; + freq->m = local->oper_channel->center_freq; freq->e = 6; return 0; -- cgit v0.10.2 From 8a7130404948b966e98b1285e777972b4b3f2fa2 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Mon, 4 May 2009 20:46:25 +0400 Subject: ar9170: fix build when !CONFIG_PM Fix this build error when CONFIG_PM is not set: drivers/net/wireless/ath/ar9170/usb.c: In function 'ar9170_usb_probe': drivers/net/wireless/ath/ar9170/usb.c:692: error: 'struct usb_device' has no member named 'reset_resume' Signed-off-by: Alexander Beregalov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index d7b562d..d7c13c0 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -689,7 +689,9 @@ static int ar9170_usb_probe(struct usb_interface *intf, aru->common.exec_cmd = ar9170_usb_exec_cmd; aru->common.callback_cmd = ar9170_usb_callback_cmd; +#ifdef CONFIG_PM udev->reset_resume = 1; +#endif err = ar9170_usb_reset(aru); if (err) goto err_freehw; -- cgit v0.10.2 From 83f8b478ff5ed7d7df0bf91336bbede7b4714771 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 6 May 2009 14:16:15 -0400 Subject: p54: correct merge damage from "p54: more SoftLED updates" Ooops... Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 7fda1a9..db3df94 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -189,10 +189,10 @@ struct p54_common { unsigned long *used_rxkeys; /* LED management */ -#ifdef CONFIG_MAC80211_LEDS +#ifdef CONFIG_P54_LEDS struct p54_led_dev leds[4]; struct delayed_work led_work; -#endif /* CONFIG_MAC80211_LEDS */ +#endif /* CONFIG_P54_LEDS */ u16 softled_state; /* bit field of glowing LEDs */ /* statistics */ -- cgit v0.10.2 From 6cfe62cd58da862db04d4eb61f218f65b0cedbb3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 May 2009 15:48:39 -0400 Subject: mac80211: Fix sparse warning for ssid_len on ieee80211_sta_config_auth() net/mac80211/mlme.c:2079:28: warning: symbol 'ssid_len' shadows an earlier one net/mac80211/mlme.c:2022:12: originally declared here ssid_len is already being declared and checked above so there is no need for it again. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5509c5a..75c487229 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2076,10 +2076,6 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) return 0; } else { if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { - u8 ssid_len = 0; - - if (!(ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL)) - ssid_len = ifmgd->ssid_len; ifmgd->assoc_scan_tries++; -- cgit v0.10.2 From 358623c22c9fd837b3b1b444377037f72553dc9f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 5 May 2009 19:46:08 +0200 Subject: rt2x00: Simplify rt2x00_check_rev rt2x00_check_rev() was too specific for rt2500usb and rt73usb, by adding the mask argument (instead of hardcoding it into the function itself) we can use the function in rt2800usb as well. v2: Fix revision mask for rt2800usb Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 08e8833..1debb88 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1559,7 +1559,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); - if (!rt2x00_check_rev(&rt2x00dev->chip, 0)) { + if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index cf4a97f..257bfb5 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2348,9 +2348,10 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * The check for rt2860 is not a typo, some rt2870 hardware * identifies itself as rt2860 in the CSR register. */ - if ((rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x2860) && - (rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x2870) && - (rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x3070)) { + if (!rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28600000) && + !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28700000) && + !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28800000) && + !rt2x00_check_rev(&rt2x00dev->chip, 0xffff0000, 0x30700000)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8d933ee..419b1b9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -915,11 +915,10 @@ static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset) return chipset->rev; } -static inline u16 rt2x00_check_rev(const struct rt2x00_chip *chipset, - const u32 rev) +static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset, + const u32 mask, const u32 rev) { - return (((chipset->rev & 0xffff0) == rev) && - !!(chipset->rev & 0x0000f)); + return ((chipset->rev & mask) == rev); } /** diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6bd28a6..d10af36 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1846,7 +1846,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2571, value, reg); - if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) { + if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || + !rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } -- cgit v0.10.2 From 2d3babd11f91501f49c6af212e6795bd8954f4d4 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 5 May 2009 20:35:13 +0300 Subject: mac80211: Use a shared function to release frames from RX reorder buf No need to duplicate the same code in two places (and that would be three after the followup patch). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6a9d89b..9f2a29d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2284,6 +2284,34 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) } +static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + int index) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + struct ieee80211_rx_status status; + + if (!tid_agg_rx->reorder_buf[index]) + goto no_frame; + + /* release the reordered frames to stack */ + memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); + sband = hw->wiphy->bands[status.band]; + if (status.flag & RX_FLAG_HT) + rate = sband->bitrates; /* TODO: HT rates */ + else + rate = &sband->bitrates[status.rate_idx]; + __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], + &status, rate); + tid_agg_rx->stored_mpdu_num--; + tid_agg_rx->reorder_buf[index] = NULL; + +no_frame: + tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); +} + + /* * As it function blongs to Rx path it must be called with * the proper rcu_read_lock protection for its flow. @@ -2295,12 +2323,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, u16 mpdu_seq_num, int bar_req) { - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rx_status status; u16 head_seq_num, buf_size; int index; - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; buf_size = tid_agg_rx->buf_size; head_seq_num = tid_agg_rx->head_seq_num; @@ -2325,28 +2349,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - - if (tid_agg_rx->reorder_buf[index]) { - /* release the reordered frames to stack */ - memcpy(&status, - tid_agg_rx->reorder_buf[index]->cb, - sizeof(status)); - sband = local->hw.wiphy->bands[status.band]; - if (status.flag & RX_FLAG_HT) { - /* TODO: HT rates */ - rate = sband->bitrates; - } else { - rate = &sband->bitrates - [status.rate_idx]; - } - __ieee80211_rx_handle_packet(hw, - tid_agg_rx->reorder_buf[index], - &status, rate); - tid_agg_rx->stored_mpdu_num--; - tid_agg_rx->reorder_buf[index] = NULL; - } - tid_agg_rx->head_seq_num = - seq_inc(tid_agg_rx->head_seq_num); + ieee80211_release_reorder_frame(hw, tid_agg_rx, + index); } if (bar_req) return 1; @@ -2380,19 +2384,7 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; while (tid_agg_rx->reorder_buf[index]) { - /* release the reordered frame back to stack */ - memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, - sizeof(status)); - sband = local->hw.wiphy->bands[status.band]; - if (status.flag & RX_FLAG_HT) - rate = sband->bitrates; /* TODO: HT rates */ - else - rate = &sband->bitrates[status.rate_idx]; - __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, rate); - tid_agg_rx->stored_mpdu_num--; - tid_agg_rx->reorder_buf[index] = NULL; - tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); + ieee80211_release_reorder_frame(hw, tid_agg_rx, index); index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; } -- cgit v0.10.2 From 4d050f1daed3babf6fcc337f862a245d31af4452 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 5 May 2009 20:35:14 +0300 Subject: mac80211: Add a timeout for frames in the RX reorder buffer This patch allows skbs to be released from the RX reorder buffer in case they have been there for an unexpectedly long time without us having received the missing frames before them. Previously, these frames were only released when the reorder window moved and that could take very long time unless new frames were received constantly (e.g., TCP connections could be killed more or less indefinitely). This situation should not happen very frequently, but it looks like there are some scenarious that trigger it for some reason. As such, this should be considered mostly a workaround to speed up recovery from unexpected siutation that could result in connections hanging for long periods of time. The changes here will only check for timeout situation when adding new RX frames to the reorder buffer. It does not handle all possible cases, but seems to help for most cases that could result from common network usage (e.g., TCP retrying at least couple of times). For more completely coverage, a timer could be used to periodically check whether there are any frames remaining in the reorder buffer if no new frames are received. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index fff24c3..bc064d7 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -68,6 +68,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, spin_lock_bh(&sta->lock); /* free resources */ kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); + kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time); if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) { kfree(sta->ampdu_mlme.tid_rx[tid]); @@ -268,13 +269,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, /* prepare reordering buffer */ tid_agg_rx->reorder_buf = kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); - if (!tid_agg_rx->reorder_buf) { + tid_agg_rx->reorder_time = + kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC); + if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_ERR "can not allocate reordering buffer " "to tid %d\n", tid); #endif + kfree(tid_agg_rx->reorder_buf); + kfree(tid_agg_rx->reorder_time); kfree(sta->ampdu_mlme.tid_rx[tid]); + sta->ampdu_mlme.tid_rx[tid] = NULL; goto end; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9f2a29d..24d4170 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2313,6 +2313,15 @@ no_frame: /* + * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If + * the skb was added to the buffer longer than this time ago, the earlier + * frames that have not yet been received are assumed to be lost and the skb + * can be released for processing. This may also release other skb's from the + * reorder buffer if there are no additional gaps between the frames. + */ +#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) + +/* * As it function blongs to Rx path it must be called with * the proper rcu_read_lock protection for its flow. */ @@ -2377,13 +2386,49 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* put the frame in the reordering buffer */ tid_agg_rx->reorder_buf[index] = skb; + tid_agg_rx->reorder_time[index] = jiffies; memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus, sizeof(*rxstatus)); tid_agg_rx->stored_mpdu_num++; /* release the buffer until next missing frame */ index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - while (tid_agg_rx->reorder_buf[index]) { + if (!tid_agg_rx->reorder_buf[index] && + tid_agg_rx->stored_mpdu_num > 1) { + /* + * No buffers ready to be released, but check whether any + * frames in the reorder buffer have timed out. + */ + int j; + int skipped = 1; + for (j = (index + 1) % tid_agg_rx->buf_size; j != index; + j = (j + 1) % tid_agg_rx->buf_size) { + if (tid_agg_rx->reorder_buf[j] == NULL) { + skipped++; + continue; + } + if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + + HZ / 10)) + break; + +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "%s: release an RX reorder " + "frame due to timeout on earlier " + "frames\n", + wiphy_name(hw->wiphy)); +#endif + ieee80211_release_reorder_frame(hw, tid_agg_rx, j); + + /* + * Increment the head seq# also for the skipped slots. + */ + tid_agg_rx->head_seq_num = + (tid_agg_rx->head_seq_num + skipped) & + SEQ_MASK; + skipped = 0; + } + } else while (tid_agg_rx->reorder_buf[index]) { ieee80211_release_reorder_frame(hw, tid_agg_rx, index); index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 31a8990..164b16c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -88,6 +88,7 @@ struct tid_ampdu_tx { * struct tid_ampdu_rx - TID aggregation information (Rx). * * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @reorder_time: jiffies when skb was added * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) * @head_seq_num: head sequence number in reordering buffer. * @stored_mpdu_num: number of MPDUs in reordering buffer @@ -99,6 +100,7 @@ struct tid_ampdu_tx { */ struct tid_ampdu_rx { struct sk_buff **reorder_buf; + unsigned long *reorder_time; struct timer_list session_timer; u16 head_seq_num; u16 stored_mpdu_num; -- cgit v0.10.2 From aec6795210db6ba3f4592056d41ac5b1ab41e980 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 5 May 2009 20:35:15 +0300 Subject: mac80211: Comment the order of HT RX reorder handler vs. RX handlers We are currently processing block ack reordering as a separate task before all other RX handlers. In theory, this is wrong since this step should be done only after duplicate removal (see Figure 6-1 in IEEE 802.11n). However, moving this needs some work and the current situation is not too bad. Add a comment here so that this small detail does not get forgotten and who knows, maybe someone has some extra time to take a look at cleaning this up. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 24d4170..d052f40 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2551,6 +2551,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, return; } + /* + * In theory, the block ack reordering should happen after duplicate + * removal (ieee80211_rx_h_check(), which is an RX handler). As such, + * the call to ieee80211_rx_reorder_ampdu() should really be moved to + * happen as a new RX handler between ieee80211_rx_h_check and + * ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for + * the time being, the call can be here since RX reorder buf processing + * will implicitly skip duplicates. We could, in theory at least, + * process frames that ieee80211_rx_h_passive_scan would drop (e.g., + * frames from other than operational channel), but that should not + * happen in normal networks. + */ if (!ieee80211_rx_reorder_ampdu(local, skb, status)) __ieee80211_rx_handle_packet(hw, skb, status, rate); -- cgit v0.10.2 From 7c5a189dc6a43def594fedc7cd8f6886596b65de Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 6 May 2009 01:47:02 +0400 Subject: p54: call p54_wake_free_queues on every p54_free_skb and p54_rx_frame_sent Currently queues are stopped when their length reaches their length limit, but are restarted only when the size of freed range of packet buffer is not less than the size of the largest possible packet. This causes permanent queue stop on radio visibility loss in the middle of ping series: there is plenty of room in the packet buffer, but it is never freed more than 3 (size of 'best effort' queue) * 288 (ping packet plus headers) bytes at once. Signed-off-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b857852..48d81d9 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -822,7 +822,6 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_tx_info *info; struct p54_tx_info *range; unsigned long flags; - u32 freed = 0, last_addr = priv->rx_start; if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) return; @@ -842,7 +841,6 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) ni = IEEE80211_SKB_CB(skb->prev); mr = (struct p54_tx_info *)ni->rate_driver_data; - last_addr = mr->end_addr; } if (skb->next != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *ni; @@ -850,16 +848,11 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) ni = IEEE80211_SKB_CB(skb->next); mr = (struct p54_tx_info *)ni->rate_driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + } __skb_unlink(skb, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); dev_kfree_skb_any(skb); - - if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + - IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) - p54_wake_free_queues(dev); + p54_wake_free_queues(dev); } EXPORT_SYMBOL_GPL(p54_free_skb); @@ -893,8 +886,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) struct sk_buff *entry; u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct p54_tx_info *range = NULL; - u32 freed = 0; - u32 last_addr = priv->rx_start; unsigned long flags; int count, idx; @@ -908,7 +899,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) range = (void *)info->rate_driver_data; if (range->start_addr != addr) { - last_addr = range->end_addr; entry = entry->next; continue; } @@ -919,11 +909,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) ni = IEEE80211_SKB_CB(entry->next); mr = (struct p54_tx_info *)ni->rate_driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + } - last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); @@ -1010,9 +997,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + - IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) - p54_wake_free_queues(dev); + p54_wake_free_queues(dev); } static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, -- cgit v0.10.2 From 4f0fc7c39f2a224b939f22d4dca552b266319525 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 6 May 2009 02:20:00 -0400 Subject: ath9k: make private driver rate tables const On x86 this allows us to do the following small savings: shave off 23 % off of the module's data, and shave off 6 % off of the module's text. We save 456 bytes, for those counting. $ size ath9k.ko text data bss dec hex filename 250794 3628 1600 256022 3e816 ath9k.ko $ size ath9k-old.ko text data bss dec hex filename 239114 15308 1600 256022 3e816 ath9k-old.ko $ du -b ath9k.ko 4034244 ath9k.ko $ du -b ath9k-old.ko 4033788 ath9k-old.ko Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 90b6314..10ffc94 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -576,8 +576,8 @@ struct ath_softc { struct ath_tx tx; struct ath_beacon beacon; struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; - struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; - struct ath_rate_table *cur_rate_table; + const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + const struct ath_rate_table *cur_rate_table; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ath_led radio_led; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index c17b838..3a7154b 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -63,7 +63,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_hw *ah = sc->sc_ah; struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - struct ath_rate_table *rt; + const struct ath_rate_table *rt; int flags, antenna, ctsrate = 0, ctsduration = 0; u8 rate; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 02f4015..041c0f5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -168,7 +168,7 @@ bool ath9k_get_channel_edges(struct ath_hw *ah, } u16 ath9k_hw_computetxtime(struct ath_hw *ah, - struct ath_rate_table *rates, + const struct ath_rate_table *rates, u32 frameLen, u16 rateix, bool shortPreamble) { diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ab34126..ddb24c4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -580,7 +580,8 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah, bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); u32 ath9k_hw_reverse_bits(u32 val, u32 n); bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); -u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, +u16 ath9k_hw_computetxtime(struct ath_hw *ah, + const struct ath_rate_table *rates, u32 frameLen, u16 rateix, bool shortPreamble); void ath9k_hw_get_channel_centers(struct ath_hw *ah, struct ath9k_channel *chan, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d3dc8e2..bbbfdcd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -189,7 +189,7 @@ static u8 parse_mpdudensity(u8 mpdudensity) static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) { - struct ath_rate_table *rate_table = NULL; + const struct ath_rate_table *rate_table = NULL; struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; int i, maxrates; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index e526dbc..ba06e78 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -17,7 +17,7 @@ #include "ath9k.h" -static struct ath_rate_table ar5416_11na_ratetable = { +static const struct ath_rate_table ar5416_11na_ratetable = { 42, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ @@ -155,7 +155,7 @@ static struct ath_rate_table ar5416_11na_ratetable = { /* 4ms frame limit not used for NG mode. The values filled * for HT are the 64K max aggregate limit */ -static struct ath_rate_table ar5416_11ng_ratetable = { +static const struct ath_rate_table ar5416_11ng_ratetable = { 46, { { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ @@ -302,7 +302,7 @@ static struct ath_rate_table ar5416_11ng_ratetable = { WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11a_ratetable = { +static const struct ath_rate_table ar5416_11a_ratetable = { 8, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ @@ -335,7 +335,7 @@ static struct ath_rate_table ar5416_11a_ratetable = { 0, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11g_ratetable = { +static const struct ath_rate_table ar5416_11g_ratetable = { 12, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ @@ -380,7 +380,7 @@ static struct ath_rate_table ar5416_11g_ratetable = { 0, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11b_ratetable = { +static const struct ath_rate_table ar5416_11b_ratetable = { 4, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ @@ -420,7 +420,7 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c) } } -static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, +static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv) { u8 i, j, idx, idx_next; @@ -461,10 +461,11 @@ static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, return ath_rc_priv->valid_rate_index[index]; } -static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, - u8 *next_idx) +static inline +int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, + u8 *next_idx) { u8 i; @@ -500,7 +501,7 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) } static inline int -ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, +ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { @@ -517,7 +518,7 @@ ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, } static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, u32 capflag) { u8 i, hi = 0; @@ -547,7 +548,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, } static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, struct ath_rateset *rateset, u32 capflag) { @@ -592,7 +593,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, } static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, u8 *mcs_set, u32 capflag) { struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; @@ -630,7 +631,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, static u8 ath_rc_ratefind_ht(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, int *is_probing) { u32 dt, best_thruput, this_thruput, now_msec; @@ -748,7 +749,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, return rate; } -static void ath_rc_rate_set_series(struct ath_rate_table *rate_table, +static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate, struct ieee80211_tx_rate_control *txrc, u8 tries, u8 rix, int rtsctsenable) @@ -769,7 +770,7 @@ static void ath_rc_rate_set_series(struct ath_rate_table *rate_table, } static void ath_rc_rate_set_rtscts(struct ath_softc *sc, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, struct ieee80211_tx_info *tx_info) { struct ieee80211_tx_rate *rates = tx_info->control.rates; @@ -807,7 +808,7 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, static u8 ath_rc_rate_getidx(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, u8 rix, u16 stepdown, u16 min_rate) { @@ -838,7 +839,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_rate_control *txrc) { - struct ath_rate_table *rate_table; + const struct ath_rate_table *rate_table; struct sk_buff *skb = txrc->skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->control.rates; @@ -937,7 +938,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, } static bool ath_rc_update_per(struct ath_softc *sc, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, struct ath_tx_info_priv *tx_info_priv, int tx_rate, int xretries, int retries, @@ -1142,7 +1143,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, int rate; u8 last_per; bool state_change = false; - struct ath_rate_table *rate_table = sc->cur_rate_table; + const struct ath_rate_table *rate_table = sc->cur_rate_table; int size = ath_rc_priv->rate_table_size; if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) @@ -1276,7 +1277,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, #undef CHK_RSSI } -static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, +static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate) { int rix; @@ -1300,7 +1301,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, int final_ts_idx, int xretries, int long_retry) { struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - struct ath_rate_table *rate_table; + const struct ath_rate_table *rate_table; struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; u32 i = 0, rix; @@ -1354,9 +1355,11 @@ static void ath_rc_tx_status(struct ath_softc *sc, xretries, long_retry); } -static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, - enum ieee80211_band band, - bool is_ht, bool is_cw_40) +static const +struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, + enum ieee80211_band band, + bool is_ht, + bool is_cw_40) { int mode = 0; @@ -1390,7 +1393,7 @@ static void ath_rc_init(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, - struct ath_rate_table *rate_table) + const struct ath_rate_table *rate_table) { struct ath_rateset *rateset = &ath_rc_priv->neg_rates; u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; @@ -1587,7 +1590,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ath_rate_table *rate_table = NULL; + const struct ath_rate_table *rate_table = NULL; bool is_cw40, is_sgi40; int i, j = 0; @@ -1636,7 +1639,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ath_rate_table *rate_table = NULL; + const struct ath_rate_table *rate_table = NULL; bool oper_cw40 = false, oper_sgi40; bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? true : false; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 501493f..41c4282 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -434,7 +434,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid) { - struct ath_rate_table *rate_table = sc->cur_rate_table; + const struct ath_rate_table *rate_table = sc->cur_rate_table; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -497,7 +497,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) { - struct ath_rate_table *rt = sc->cur_rate_table; + const struct ath_rate_table *rt = sc->cur_rate_table; struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols, mpdudensity; @@ -1407,7 +1407,7 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, int width, int half_gi, bool shortPreamble) { - struct ath_rate_table *rate_table = sc->cur_rate_table; + const struct ath_rate_table *rate_table = sc->cur_rate_table; u32 nbits, nsymbits, duration, nsymbols; u8 rc; int streams, pktlen; @@ -1439,7 +1439,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_rate_table *rt = sc->cur_rate_table; + const struct ath_rate_table *rt = sc->cur_rate_table; struct ath9k_11n_rate_series series[4]; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; -- cgit v0.10.2 From f9dd6b52873ad9fda51a3881c80c96d06ee6a57d Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Wed, 6 May 2009 09:47:30 +0200 Subject: ath9k: remove redundant AR9285 checks The AR_SREV_9285_1[12]_OR_LATER macros already contains the AR_SREV_9285 check. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index a197041..a32d7e7 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -863,7 +863,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, } if (longcal) { - if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); if (OLC_FOR_AR9280_20_LATER) @@ -917,7 +917,7 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { - if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { + if (AR_SREV_9285_12_OR_LATER(ah)) { if (!ar9285_clc(ah, chan)) return false; } else { @@ -947,7 +947,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) } /* Do PA Calibration */ - if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); /* Do NF Calibration after DC offset and other calibrations */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 041c0f5..5879c73 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1345,8 +1345,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, if (AR_SREV_9280(ah)) REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); - if (AR_SREV_9280(ah) || (AR_SREV_9285(ah) && - AR_SREV_9285_12_OR_LATER(ah))) + if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); for (i = 0; i < ah->iniCommon.ia_rows; i++) { -- cgit v0.10.2 From 9dfd6ba353b993d648dcda72480c7ce92cd27c7e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 6 May 2009 20:34:10 +0300 Subject: mac80211: Update SA Query transaction id length IEEE 802.11w/D8.0 changed the length of the SA Query transaction identifier from 16 to 2 octets. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index c52e7fb..dc92359 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -543,7 +543,7 @@ struct ieee80211_tim_ie { u8 virtual_map[1]; } __attribute__ ((packed)); -#define WLAN_SA_QUERY_TR_ID_LEN 16 +#define WLAN_SA_QUERY_TR_ID_LEN 2 struct ieee80211_mgmt { __le16 frame_control; -- cgit v0.10.2 From 22527864ed7ee6c50f3c4d4b03c83c963caf5c0b Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 5 May 2009 19:05:06 +0000 Subject: netxen: fix race in tx ring acccess Fix the distance check between tx ring producer and consumer that could lead to tx ring wrap around. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 9f5ced3..23c974a 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -526,7 +526,7 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, producer = tx_ring->producer; consumer = tx_ring->sw_consumer; - if (nr_desc > find_diff_among(producer, consumer, tx_ring->num_desc)) { + if (nr_desc >= find_diff_among(producer, consumer, tx_ring->num_desc)) { netif_tx_unlock_bh(adapter->netdev); return -EBUSY; } @@ -752,7 +752,7 @@ int netxen_linkevent_request(struct netxen_adapter *adapter, int enable) word = NX_NIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16); req.req_hdr = cpu_to_le64(word); - req.words[0] = cpu_to_le64(enable); + req.words[0] = cpu_to_le64(enable | (enable << 8)); rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); if (rv != 0) { diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index d182167..de9ebbd 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1319,10 +1319,11 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) break; } - if (count) { - tx_ring->sw_consumer = sw_consumer; + tx_ring->sw_consumer = sw_consumer; + + if (count && netif_running(netdev)) { smp_mb(); - if (netif_queue_stopped(netdev) && netif_running(netdev)) { + if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) { netif_tx_lock(netdev); netif_wake_queue(netdev); smp_mb(); @@ -1450,7 +1451,6 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, rds_ring->producer = producer; NXWR32(adapter, rds_ring->crb_rcv_producer, (producer - 1) & (rds_ring->num_desc - 1)); - wmb(); } spin_unlock(&rds_ring->lock); } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 5d79c19..6a496b1 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -809,6 +809,7 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) { netif_carrier_off(netdev); netif_stop_queue(netdev); + smp_mb(); netxen_napi_disable(adapter); if (adapter->stop_port) @@ -1340,7 +1341,7 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) producer = tx_ring->producer; smp_mb(); consumer = tx_ring->sw_consumer; - if ((no_of_desc+2) > find_diff_among(producer, consumer, num_txd)) { + if ((no_of_desc+2) >= find_diff_among(producer, consumer, num_txd)) { netif_stop_queue(netdev); smp_mb(); return NETDEV_TX_BUSY; -- cgit v0.10.2 From 5cf4d323f8864dab818d500ec74f2fcb9ad5bf89 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 5 May 2009 19:05:07 +0000 Subject: netxen: fix mac list management o use standard linked list api for mac addr list management in NX3031. o release mac addresses in firmware in dev close(). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 8dacfbb..d368e24 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1019,8 +1019,8 @@ typedef struct { #define NETXEN_MAC_DEL 2 typedef struct nx_mac_list_s { - struct nx_mac_list_s *next; - uint8_t mac_addr[MAX_ADDR_LEN]; + struct list_head list; + uint8_t mac_addr[ETH_ALEN+2]; } nx_mac_list_t; /* @@ -1213,7 +1213,7 @@ struct netxen_adapter { struct net_device *netdev; struct pci_dev *pdev; - nx_mac_list_t *mac_list; + struct list_head mac_list; u32 curr_window; u32 crb_win; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 23c974a..be643ea 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -470,45 +470,6 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) netxen_nic_set_mcast_addr(adapter, index, null_addr); } -static int nx_p3_nic_add_mac(struct netxen_adapter *adapter, - u8 *addr, nx_mac_list_t **add_list, nx_mac_list_t **del_list) -{ - nx_mac_list_t *cur, *prev; - - /* if in del_list, move it to adapter->mac_list */ - for (cur = *del_list, prev = NULL; cur;) { - if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { - if (prev == NULL) - *del_list = cur->next; - else - prev->next = cur->next; - cur->next = adapter->mac_list; - adapter->mac_list = cur; - return 0; - } - prev = cur; - cur = cur->next; - } - - /* make sure to add each mac address only once */ - for (cur = adapter->mac_list; cur; cur = cur->next) { - if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) - return 0; - } - /* not in del_list, create new entry and add to add_list */ - cur = kmalloc(sizeof(*cur), in_atomic()? GFP_ATOMIC : GFP_KERNEL); - if (cur == NULL) { - printk(KERN_ERR "%s: cannot allocate memory. MAC filtering may" - "not work properly from now.\n", __func__); - return -1; - } - - memcpy(cur->mac_addr, addr, ETH_ALEN); - cur->next = *add_list; - *add_list = cur; - return 0; -} - static int netxen_send_cmd_descs(struct netxen_adapter *adapter, struct cmd_desc_type0 *cmd_desc_arr, int nr_desc) @@ -555,14 +516,12 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, return 0; } -static int nx_p3_sre_macaddr_change(struct net_device *dev, - u8 *addr, unsigned op) +static int +nx_p3_sre_macaddr_change(struct netxen_adapter *adapter, u8 *addr, unsigned op) { - struct netxen_adapter *adapter = netdev_priv(dev); nx_nic_req_t req; nx_mac_req_t *mac_req; u64 word; - int rv; memset(&req, 0, sizeof(nx_nic_req_t)); req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23); @@ -574,28 +533,51 @@ static int nx_p3_sre_macaddr_change(struct net_device *dev, mac_req->op = op; memcpy(mac_req->mac_addr, addr, 6); - rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); - if (rv != 0) { - printk(KERN_ERR "ERROR. Could not send mac update\n"); - return rv; + return netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); +} + +static int nx_p3_nic_add_mac(struct netxen_adapter *adapter, + u8 *addr, struct list_head *del_list) +{ + struct list_head *head; + nx_mac_list_t *cur; + + /* look up if already exists */ + list_for_each(head, del_list) { + cur = list_entry(head, nx_mac_list_t, list); + + if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { + list_move_tail(head, &adapter->mac_list); + return 0; + } } - return 0; + cur = kzalloc(sizeof(nx_mac_list_t), GFP_ATOMIC); + if (cur == NULL) { + printk(KERN_ERR "%s: failed to add mac address filter\n", + adapter->netdev->name); + return -ENOMEM; + } + memcpy(cur->mac_addr, addr, ETH_ALEN); + list_add_tail(&cur->list, &adapter->mac_list); + return nx_p3_sre_macaddr_change(adapter, + cur->mac_addr, NETXEN_MAC_ADD); } void netxen_p3_nic_set_multi(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); - nx_mac_list_t *cur, *next, *del_list, *add_list = NULL; struct dev_mc_list *mc_ptr; u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; u32 mode = VPORT_MISS_MODE_DROP; + LIST_HEAD(del_list); + struct list_head *head; + nx_mac_list_t *cur; - del_list = adapter->mac_list; - adapter->mac_list = NULL; + list_splice_tail_init(&adapter->mac_list, &del_list); - nx_p3_nic_add_mac(adapter, netdev->dev_addr, &add_list, &del_list); - nx_p3_nic_add_mac(adapter, bcast_addr, &add_list, &del_list); + nx_p3_nic_add_mac(adapter, netdev->dev_addr, &del_list); + nx_p3_nic_add_mac(adapter, bcast_addr, &del_list); if (netdev->flags & IFF_PROMISC) { mode = VPORT_MISS_MODE_ACCEPT_ALL; @@ -611,25 +593,20 @@ void netxen_p3_nic_set_multi(struct net_device *netdev) if (netdev->mc_count > 0) { for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { - nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, - &add_list, &del_list); + nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list); } } send_fw_cmd: adapter->set_promisc(adapter, mode); - for (cur = del_list; cur;) { - nx_p3_sre_macaddr_change(netdev, cur->mac_addr, NETXEN_MAC_DEL); - next = cur->next; + head = &del_list; + while (!list_empty(head)) { + cur = list_entry(head->next, nx_mac_list_t, list); + + nx_p3_sre_macaddr_change(adapter, + cur->mac_addr, NETXEN_MAC_DEL); + list_del(&cur->list); kfree(cur); - cur = next; - } - for (cur = add_list; cur;) { - nx_p3_sre_macaddr_change(netdev, cur->mac_addr, NETXEN_MAC_ADD); - next = cur->next; - cur->next = adapter->mac_list; - adapter->mac_list = cur; - cur = next; } } @@ -654,14 +631,15 @@ int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32 mode) void netxen_p3_free_mac_list(struct netxen_adapter *adapter) { - nx_mac_list_t *cur, *next; - - cur = adapter->mac_list; - - while (cur) { - next = cur->next; + nx_mac_list_t *cur; + struct list_head *head = &adapter->mac_list; + + while (!list_empty(head)) { + cur = list_entry(head->next, nx_mac_list_t, list); + nx_p3_sre_macaddr_change(adapter, + cur->mac_addr, NETXEN_MAC_DEL); + list_del(&cur->list); kfree(cur); - cur = next; } } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 6a496b1..a5577f8 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -815,6 +815,9 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->stop_port) adapter->stop_port(adapter); + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_p3_free_mac_list(adapter); + netxen_release_tx_buffers(adapter); FLUSH_SCHEDULED_WORK(); @@ -961,6 +964,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rwlock_init(&adapter->adapter_lock); spin_lock_init(&adapter->tx_clean_lock); + INIT_LIST_HEAD(&adapter->mac_list); err = netxen_setup_pci_map(adapter); if (err) @@ -1114,9 +1118,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { netxen_nic_detach(adapter); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - netxen_p3_free_mac_list(adapter); } if (adapter->portnum == 0) -- cgit v0.10.2 From 3d0a3cc9d72047e4baa76021c897f64fc84cc543 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 5 May 2009 19:05:08 +0000 Subject: netxen: fix bonding support o Pause traffic during mac addr change. o Enable setting mac address for NX3031. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d368e24..9350c86 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1264,9 +1264,10 @@ struct netxen_adapter { int (*enable_phy_interrupts) (struct netxen_adapter *); int (*disable_phy_interrupts) (struct netxen_adapter *); - int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t); + int (*macaddr_set) (struct netxen_adapter *, u8 *); int (*set_mtu) (struct netxen_adapter *, int); int (*set_promisc) (struct netxen_adapter *, u32); + void (*set_multi) (struct net_device *); int (*phy_read) (struct netxen_adapter *, long reg, u32 *); int (*phy_write) (struct netxen_adapter *, long reg, u32 val); int (*init_port) (struct netxen_adapter *, int); @@ -1331,6 +1332,9 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu); int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu); +int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); +int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); + #define NXRD32(adapter, off) \ (adapter->hw_read_wx(adapter, off)) #define NXWR32(adapter, off, val) \ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index be643ea..86c9e78 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -321,27 +321,6 @@ static unsigned crb_hub_agt[64] = #define NETXEN_WINDOW_ONE 0x2000000 /*CRB Window: bit 25 of CRB address */ -int netxen_nic_set_mac(struct net_device *netdev, void *p) -{ - struct netxen_adapter *adapter = netdev_priv(netdev); - struct sockaddr *addr = p; - - if (netif_running(netdev)) - return -EBUSY; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - - /* For P3, MAC addr is not set in NIU */ - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - if (adapter->macaddr_set) - adapter->macaddr_set(adapter, addr->sa_data); - - return 0; -} - #define NETXEN_UNICAST_ADDR(port, index) \ (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8)) #define NETXEN_MCAST_ADDR(port, index) \ @@ -643,6 +622,13 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter) } } +int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) +{ + /* assuming caller has already copied new addr to netdev */ + netxen_p3_nic_set_multi(adapter->netdev); + return 0; +} + #define NETXEN_CONFIG_INTR_COALESCE 3 /* diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index f20c965..d4e8333 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -42,8 +42,6 @@ struct netxen_adapter; void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); -typedef u8 netxen_ethernet_macaddr_t[6]; - /* Nibble or Byte mode for phy interface (GbE mode only) */ #define _netxen_crb_get_bit(var, bit) ((var >> bit) & 0x1) @@ -395,14 +393,6 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); -/* set the MAC address for a given MAC */ -int netxen_niu_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr); - -/* XG version */ -int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr); - /* Generic enable for GbE ports. Will detect the speed of the link. */ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index de9ebbd..4a51c31 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -319,13 +319,15 @@ err_out: void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) { + adapter->macaddr_set = netxen_p2_nic_set_mac_addr; + adapter->set_multi = netxen_p2_nic_set_multi; + switch (adapter->ahw.port_type) { case NETXEN_NIC_GBE: adapter->enable_phy_interrupts = netxen_niu_gbe_enable_phy_interrupts; adapter->disable_phy_interrupts = netxen_niu_gbe_disable_phy_interrupts; - adapter->macaddr_set = netxen_niu_macaddr_set; adapter->set_mtu = netxen_nic_set_mtu_gb; adapter->set_promisc = netxen_niu_set_promiscuous_mode; adapter->phy_read = netxen_niu_gbe_phy_read; @@ -339,7 +341,6 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) netxen_niu_xgbe_enable_phy_interrupts; adapter->disable_phy_interrupts = netxen_niu_xgbe_disable_phy_interrupts; - adapter->macaddr_set = netxen_niu_xg_macaddr_set; adapter->set_mtu = netxen_nic_set_mtu_xgb; adapter->init_port = netxen_niu_xg_init_port; adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode; @@ -353,6 +354,8 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { adapter->set_mtu = nx_fw_cmd_set_mtu; adapter->set_promisc = netxen_p3_nic_set_promisc; + adapter->macaddr_set = netxen_p3_nic_set_mac_addr; + adapter->set_multi = netxen_p3_nic_set_multi; } } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index a5577f8..83dadfd 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -442,20 +442,38 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) if (!is_valid_ether_addr(netdev->perm_addr)) dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr); - else - adapter->macaddr_set(adapter, netdev->dev_addr); return 0; } +int netxen_nic_set_mac(struct net_device *netdev, void *p) +{ + struct netxen_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + if (netif_running(netdev)) { + netif_device_detach(netdev); + netxen_napi_disable(adapter); + } + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + adapter->macaddr_set(adapter, addr->sa_data); + + if (netif_running(netdev)) { + netif_device_attach(netdev); + netxen_napi_enable(adapter); + } + return 0; +} + static void netxen_set_multicast_list(struct net_device *dev) { struct netxen_adapter *adapter = netdev_priv(dev); - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - netxen_p3_nic_set_multi(dev); - else - netxen_p2_nic_set_multi(dev); + adapter->set_multi(dev); } static const struct net_device_ops netxen_netdev_ops = { @@ -782,16 +800,13 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) netxen_nic_driver_name, adapter->portnum); return err; } - adapter->macaddr_set(adapter, netdev->dev_addr); - - netxen_nic_set_link_parameters(adapter); + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + adapter->macaddr_set(adapter, netdev->dev_addr); - netxen_set_multicast_list(netdev); - if (adapter->set_mtu) - adapter->set_mtu(adapter, netdev->mtu); + adapter->set_multi(netdev); + adapter->set_mtu(adapter, netdev->mtu); adapter->ahw.linkup = 0; - mod_timer(&adapter->watchdog_timer, jiffies); netxen_napi_enable(adapter); @@ -800,6 +815,10 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) netxen_linkevent_request(adapter, 1); + else + netxen_nic_set_link_parameters(adapter); + + mod_timer(&adapter->watchdog_timer, jiffies); return 0; } diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 5e2698b..5941c79 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -402,76 +402,6 @@ int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) return 0; } -/* - * Return the current station MAC address. - * Note that the passed-in value must already be in network byte order. - */ -static int netxen_niu_macaddr_get(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t * addr) -{ - u32 stationhigh; - u32 stationlow; - int phy = adapter->physical_port; - u8 val[8]; - - if (addr == NULL) - return -EINVAL; - if ((phy < 0) || (phy > 3)) - return -EINVAL; - - stationhigh = NXRD32(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy)); - stationlow = NXRD32(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy)); - ((__le32 *)val)[1] = cpu_to_le32(stationhigh); - ((__le32 *)val)[0] = cpu_to_le32(stationlow); - - memcpy(addr, val + 2, 6); - - return 0; -} - -/* - * Set the station MAC address. - * Note that the passed-in value must already be in network byte order. - */ -int netxen_niu_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr) -{ - u8 temp[4]; - u32 val; - int phy = adapter->physical_port; - unsigned char mac_addr[6]; - int i; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - for (i = 0; i < 10; i++) { - temp[0] = temp[1] = 0; - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (NXWR32(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), val)) - return -EIO; - - memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (NXWR32(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), val)) - return -2; - - netxen_niu_macaddr_get(adapter, - (netxen_ethernet_macaddr_t *) mac_addr); - if (memcmp(mac_addr, addr, 6) == 0) - break; - } - - if (i == 10) { - printk(KERN_ERR "%s: cannot set Mac addr for %s\n", - netxen_nic_driver_name, adapter->netdev->name); - printk(KERN_ERR "MAC address set: %pM.\n", addr); - printk(KERN_ERR "MAC address get: %pM.\n", mac_addr); - } - return 0; -} - /* Disable a GbE interface */ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) { @@ -561,57 +491,6 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, return 0; } -/* - * Set the MAC address for an XG port - * Note that the passed-in value must already be in network byte order. - */ -int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr) -{ - int phy = adapter->physical_port; - u8 temp[4]; - u32 val; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS)) - return -EIO; - - temp[0] = temp[1] = 0; - switch (phy) { - case 0: - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (NXWR32(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, val)) - return -EIO; - - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (NXWR32(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, val)) - return -EIO; - break; - - case 1: - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (NXWR32(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, val)) - return -EIO; - - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (NXWR32(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, val)) - return -EIO; - break; - - default: - printk(KERN_ERR "Unknown port %d\n", phy); - break; - } - - return 0; -} - int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode) { @@ -636,3 +515,36 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, return 0; } + +int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) +{ + u32 mac_hi, mac_lo; + u32 reg_hi, reg_lo; + + u8 phy = adapter->physical_port; + u8 phy_count = (adapter->ahw.port_type == NETXEN_NIC_XGBE) ? + NETXEN_NIU_MAX_XG_PORTS : NETXEN_NIU_MAX_GBE_PORTS; + + if (phy >= phy_count) + return -EINVAL; + + mac_lo = ((u32)addr[0] << 16) | ((u32)addr[1] << 24); + mac_hi = addr[2] | ((u32)addr[3] << 8) | + ((u32)addr[4] << 16) | ((u32)addr[5] << 24); + + if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { + reg_lo = NETXEN_NIU_XGE_STATION_ADDR_0_1 + (0x10000 * phy); + reg_hi = NETXEN_NIU_XGE_STATION_ADDR_0_HI + (0x10000 * phy); + } else { + reg_lo = NETXEN_NIU_GB_STATION_ADDR_1(phy); + reg_hi = NETXEN_NIU_GB_STATION_ADDR_0(phy); + } + + /* write twice to flush */ + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; + + return 0; +} -- cgit v0.10.2 From 7eaa2b20ca0a471e1c73f72d8c6a0eac2c7838a7 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 6 May 2009 03:00:59 +0000 Subject: mv643xx_eth: fix variable shadowing sparse warning Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index a400d71..352c772 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1807,7 +1807,6 @@ static void mv643xx_eth_program_multicast_filter(struct net_device *dev) if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { int port_num; u32 accept; - int i; oom: port_num = mp->port_num; -- cgit v0.10.2 From 26ef1f17d4741756763d1a399968ce17f236e2fb Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 6 May 2009 03:01:10 +0000 Subject: mv643xx_eth: count handling a link event as one unit of napi work Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 352c772..92a867c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2178,6 +2178,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) if (mp->work_link) { mp->work_link = 0; handle_link_event(mp); + work_done++; continue; } -- cgit v0.10.2 From becfad979d1875aca15ef2a1eda68782e7ac7769 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 6 May 2009 03:01:17 +0000 Subject: mv643xx_eth: minor register definition cleanup Move the definitions for the SDMA and port serial configuration register values to where all the other register definitions live, and expand the shifts to 32 bit constants. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 92a867c..cc16f3e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -88,7 +88,24 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define MAC_ADDR_LOW 0x0014 #define MAC_ADDR_HIGH 0x0018 #define SDMA_CONFIG 0x001c +#define TX_BURST_SIZE_16_64BIT 0x01000000 +#define TX_BURST_SIZE_4_64BIT 0x00800000 +#define BLM_TX_NO_SWAP 0x00000020 +#define BLM_RX_NO_SWAP 0x00000010 +#define RX_BURST_SIZE_16_64BIT 0x00000008 +#define RX_BURST_SIZE_4_64BIT 0x00000004 #define PORT_SERIAL_CONTROL 0x003c +#define SET_MII_SPEED_TO_100 0x01000000 +#define SET_GMII_SPEED_TO_1000 0x00800000 +#define SET_FULL_DUPLEX_MODE 0x00200000 +#define MAX_RX_PACKET_9700BYTE 0x000a0000 +#define DISABLE_AUTO_NEG_SPEED_GMII 0x00002000 +#define DO_NOT_FORCE_LINK_FAIL 0x00000400 +#define SERIAL_PORT_CONTROL_RESERVED 0x00000200 +#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL 0x00000008 +#define DISABLE_AUTO_NEG_FOR_DUPLEX 0x00000004 +#define FORCE_LINK_PASS 0x00000002 +#define SERIAL_PORT_ENABLE 0x00000001 #define PORT_STATUS 0x0044 #define TX_FIFO_EMPTY 0x00000400 #define TX_IN_PROGRESS 0x00000080 @@ -135,15 +152,8 @@ static char mv643xx_eth_driver_version[] = "1.4"; /* - * SDMA configuration register. + * SDMA configuration register default value. */ -#define RX_BURST_SIZE_4_64BIT (2 << 1) -#define RX_BURST_SIZE_16_64BIT (4 << 1) -#define BLM_RX_NO_SWAP (1 << 4) -#define BLM_TX_NO_SWAP (1 << 5) -#define TX_BURST_SIZE_4_64BIT (2 << 22) -#define TX_BURST_SIZE_16_64BIT (4 << 22) - #if defined(__BIG_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ (RX_BURST_SIZE_4_64BIT | \ @@ -160,22 +170,10 @@ static char mv643xx_eth_driver_version[] = "1.4"; /* - * Port serial control register. + * Misc definitions. */ -#define SET_MII_SPEED_TO_100 (1 << 24) -#define SET_GMII_SPEED_TO_1000 (1 << 23) -#define SET_FULL_DUPLEX_MODE (1 << 21) -#define MAX_RX_PACKET_9700BYTE (5 << 17) -#define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13) -#define DO_NOT_FORCE_LINK_FAIL (1 << 10) -#define SERIAL_PORT_CONTROL_RESERVED (1 << 9) -#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL (1 << 3) -#define DISABLE_AUTO_NEG_FOR_DUPLEX (1 << 2) -#define FORCE_LINK_PASS (1 << 1) -#define SERIAL_PORT_ENABLE (1 << 0) - -#define DEFAULT_RX_QUEUE_SIZE 128 -#define DEFAULT_TX_QUEUE_SIZE 256 +#define DEFAULT_RX_QUEUE_SIZE 128 +#define DEFAULT_TX_QUEUE_SIZE 256 /* -- cgit v0.10.2 From 7fd96ce47ff83fc17ab78d465d8e067467a7f51e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 6 May 2009 03:01:22 +0000 Subject: mv643xx_eth: rework receive skb cache alignment On the platforms that mv643xx_eth is used on, the manual skb->data alignment logic in mv643xx_eth can be simplified, as the only case we need to handle is where NET_SKB_PAD is not a multiple of the cache line size. If this is the case, the extra padding we need can be computed at compile time, while if NET_SKB_PAD _is_ a multiple of the cache line size, the code can be optimised out entirely. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index cc16f3e..05bb1c5 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -174,6 +174,7 @@ static char mv643xx_eth_driver_version[] = "1.4"; */ #define DEFAULT_RX_QUEUE_SIZE 128 #define DEFAULT_TX_QUEUE_SIZE 256 +#define SKB_DMA_REALIGN ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES) /* @@ -649,23 +650,20 @@ static int rxq_refill(struct rx_queue *rxq, int budget) refilled = 0; while (refilled < budget && rxq->rx_desc_count < rxq->rx_ring_size) { struct sk_buff *skb; - int unaligned; int rx; struct rx_desc *rx_desc; skb = __skb_dequeue(&mp->rx_recycle); if (skb == NULL) - skb = dev_alloc_skb(mp->skb_size + - dma_get_cache_alignment() - 1); + skb = dev_alloc_skb(mp->skb_size); if (skb == NULL) { mp->oom = 1; goto oom; } - unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); - if (unaligned) - skb_reserve(skb, dma_get_cache_alignment() - unaligned); + if (SKB_DMA_REALIGN) + skb_reserve(skb, SKB_DMA_REALIGN); refilled++; rxq->rx_desc_count++; @@ -964,8 +962,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) if (skb != NULL) { if (skb_queue_len(&mp->rx_recycle) < mp->rx_ring_size && - skb_recycle_check(skb, mp->skb_size + - dma_get_cache_alignment() - 1)) + skb_recycle_check(skb, mp->skb_size)) __skb_queue_head(&mp->rx_recycle, skb); else dev_kfree_skb(skb); @@ -2336,6 +2333,14 @@ static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) * size field are ignored by the hardware. */ mp->skb_size = (skb_size + 7) & ~7; + + /* + * If NET_SKB_PAD is smaller than a cache line, + * netdev_alloc_skb() will cause skb->data to be misaligned + * to a cache line boundary. If this is the case, include + * some extra space to allow re-aligning the data area. + */ + mp->skb_size += SKB_DMA_REALIGN; } static int mv643xx_eth_open(struct net_device *dev) -- cgit v0.10.2 From e0ca84105bca8691f39ef7ff221a88046ba11f23 Mon Sep 17 00:00:00 2001 From: Saeed Bishara Date: Wed, 6 May 2009 03:02:01 +0000 Subject: mv643xx_eth: only unmask RX and TX_END interrupts for available queues It is not a good idea to blindly unmask the RX and TX_END interrupts for all eight queues on all mv643xx_eth hardware, since some variations of the hardware have less than eight transmit/receive queues, and the RX/TX_END interrupts for the queues they don't have can be in use by other interrupt sources. Signed-off-by: Saeed Bishara Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 05bb1c5..d583852 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -123,7 +123,9 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define TX_BW_BURST 0x005c #define INT_CAUSE 0x0060 #define INT_TX_END 0x07f80000 +#define INT_TX_END_0 0x00080000 #define INT_RX 0x000003fc +#define INT_RX_0 0x00000004 #define INT_EXT 0x00000002 #define INT_CAUSE_EXT 0x0064 #define INT_EXT_LINK_PHY 0x00110000 @@ -392,6 +394,7 @@ struct mv643xx_eth_private { struct work_struct tx_timeout_task; struct napi_struct napi; + u32 int_mask; u8 oom; u8 work_link; u8 work_tx; @@ -2058,15 +2061,16 @@ static int mv643xx_eth_collect_events(struct mv643xx_eth_private *mp) u32 int_cause; u32 int_cause_ext; - int_cause = rdlp(mp, INT_CAUSE) & (INT_TX_END | INT_RX | INT_EXT); + int_cause = rdlp(mp, INT_CAUSE) & mp->int_mask; if (int_cause == 0) return 0; int_cause_ext = 0; - if (int_cause & INT_EXT) + if (int_cause & INT_EXT) { + int_cause &= ~INT_EXT; int_cause_ext = rdlp(mp, INT_CAUSE_EXT); + } - int_cause &= INT_TX_END | INT_RX; if (int_cause) { wrlp(mp, INT_CAUSE, ~int_cause); mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) & @@ -2212,7 +2216,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) if (mp->oom) mod_timer(&mp->rx_oom, jiffies + (HZ / 10)); napi_complete(napi); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); } return work_done; @@ -2366,6 +2370,8 @@ static int mv643xx_eth_open(struct net_device *dev) skb_queue_head_init(&mp->rx_recycle); + mp->int_mask = INT_EXT; + for (i = 0; i < mp->rxq_count; i++) { err = rxq_init(mp, i); if (err) { @@ -2375,6 +2381,7 @@ static int mv643xx_eth_open(struct net_device *dev) } rxq_refill(mp->rxq + i, INT_MAX); + mp->int_mask |= INT_RX_0 << i; } if (mp->oom) { @@ -2389,12 +2396,13 @@ static int mv643xx_eth_open(struct net_device *dev) txq_deinit(mp->txq + i); goto out_free; } + mp->int_mask |= INT_TX_END_0 << i; } port_start(mp); wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); return 0; @@ -2538,7 +2546,7 @@ static void mv643xx_eth_netpoll(struct net_device *dev) mv643xx_eth_irq(dev->irq, dev); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); } #endif -- cgit v0.10.2 From 0364d6fd2c353d2d82da865a6f093f97c69b669c Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2009 10:25:01 +0000 Subject: igbvf: cleanup flags and allow for rx checksum to be disabled This patch cleans up a number of unused or unneeded feature flags. As a result of these changes the user should now be able to enable or disable rx checksumming via ethtool. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c index 1dcaa69..ee17a09 100644 --- a/drivers/net/igbvf/ethtool.c +++ b/drivers/net/igbvf/ethtool.c @@ -133,6 +133,24 @@ static int igbvf_set_pauseparam(struct net_device *netdev, return -EOPNOTSUPP; } +static u32 igbvf_get_rx_csum(struct net_device *netdev) +{ + struct igbvf_adapter *adapter = netdev_priv(netdev); + return !(adapter->flags & IGBVF_FLAG_RX_CSUM_DISABLED); +} + +static int igbvf_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct igbvf_adapter *adapter = netdev_priv(netdev); + + if (data) + adapter->flags &= ~IGBVF_FLAG_RX_CSUM_DISABLED; + else + adapter->flags |= IGBVF_FLAG_RX_CSUM_DISABLED; + + return 0; +} + static u32 igbvf_get_tx_csum(struct net_device *netdev) { return ((netdev->features & NETIF_F_IP_CSUM) != 0); @@ -150,8 +168,6 @@ static int igbvf_set_tx_csum(struct net_device *netdev, u32 data) static int igbvf_set_tso(struct net_device *netdev, u32 data) { struct igbvf_adapter *adapter = netdev_priv(netdev); - int i; - struct net_device *v_netdev; if (data) { netdev->features |= NETIF_F_TSO; @@ -159,24 +175,10 @@ static int igbvf_set_tso(struct net_device *netdev, u32 data) } else { netdev->features &= ~NETIF_F_TSO; netdev->features &= ~NETIF_F_TSO6; - /* disable TSO on all VLANs if they're present */ - if (!adapter->vlgrp) - goto tso_out; - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - v_netdev = vlan_group_get_device(adapter->vlgrp, i); - if (!v_netdev) - continue; - - v_netdev->features &= ~NETIF_F_TSO; - v_netdev->features &= ~NETIF_F_TSO6; - vlan_group_set_device(adapter->vlgrp, i, v_netdev); - } } -tso_out: dev_info(&adapter->pdev->dev, "TSO is %s\n", data ? "Enabled" : "Disabled"); - adapter->flags |= FLAG_TSO_FORCE; return 0; } @@ -517,6 +519,8 @@ static const struct ethtool_ops igbvf_ethtool_ops = { .set_ringparam = igbvf_set_ringparam, .get_pauseparam = igbvf_get_pauseparam, .set_pauseparam = igbvf_set_pauseparam, + .get_rx_csum = igbvf_get_rx_csum, + .set_rx_csum = igbvf_set_rx_csum, .get_tx_csum = igbvf_get_tx_csum, .set_tx_csum = igbvf_set_tx_csum, .get_sg = ethtool_op_get_sg, diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h index 4bff35e..2ad6cd7 100644 --- a/drivers/net/igbvf/igbvf.h +++ b/drivers/net/igbvf/igbvf.h @@ -286,11 +286,7 @@ struct igbvf_info { }; /* hardware capability, feature, and workaround flags */ -#define FLAG_HAS_HW_VLAN_FILTER (1 << 0) -#define FLAG_HAS_JUMBO_FRAMES (1 << 1) -#define FLAG_MSI_ENABLED (1 << 2) -#define FLAG_RX_CSUM_ENABLED (1 << 3) -#define FLAG_TSO_FORCE (1 << 4) +#define IGBVF_FLAG_RX_CSUM_DISABLED (1 << 0) #define IGBVF_RX_DESC_ADV(R, i) \ (&((((R).desc))[i].rx_desc)) diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index b774666..44a8eef 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -58,8 +58,7 @@ static void igbvf_reset_interrupt_capability(struct igbvf_adapter *); static struct igbvf_info igbvf_vf_info = { .mac = e1000_vfadapt, - .flags = FLAG_HAS_JUMBO_FRAMES - | FLAG_RX_CSUM_ENABLED, + .flags = 0, .pba = 10, .init_ops = e1000_init_function_pointers_vf, }; @@ -107,8 +106,10 @@ static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter, skb->ip_summed = CHECKSUM_NONE; /* Ignore Checksum bit is set or checksum is disabled through ethtool */ - if ((status_err & E1000_RXD_STAT_IXSM)) + if ((status_err & E1000_RXD_STAT_IXSM) || + (adapter->flags & IGBVF_FLAG_RX_CSUM_DISABLED)) return; + /* TCP/UDP checksum error bit is set */ if (status_err & (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) { @@ -116,6 +117,7 @@ static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter, adapter->hw_csum_err++; return; } + /* It must be a TCP or UDP packet with a valid checksum */ if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2351,15 +2353,6 @@ static int igbvf_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } - /* Jumbo frame size limits */ - if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { - if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { - dev_err(&adapter->pdev->dev, - "Jumbo Frames not supported.\n"); - return -EINVAL; - } - } - #define MAX_STD_JUMBO_FRAME_SIZE 9234 if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { dev_err(&adapter->pdev->dev, "MTU > 9216 not supported.\n"); -- cgit v0.10.2 From 7beb0146fc965ffee928eff53525aac0173b0b07 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2009 10:25:23 +0000 Subject: igb/igbvf: set rx csum always enabled in hw, disable via sw An issue was found in which rx checksum could not be enabled without resetting the interface. The issue was the hardware enable was not being done via ethtool. To resolve this issue and prevent conflicts with VF configuration we will leave the feature always enabled in hardware, and then in software we will choose to ignore the results via a sw flag. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 4e8464b..154c5ac 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -238,7 +238,6 @@ struct igb_adapter { u64 hw_csum_err; u64 hw_csum_good; u32 alloc_rx_buff_failed; - bool rx_csum; u32 gorc; u64 gorc_old; u16 rx_ps_hdr_size; @@ -286,6 +285,7 @@ struct igb_adapter { #define IGB_FLAG_DCA_ENABLED (1 << 1) #define IGB_FLAG_QUAD_PORT_A (1 << 2) #define IGB_FLAG_NEED_CTX_IDX (1 << 3) +#define IGB_FLAG_RX_CSUM_DISABLED (1 << 4) enum e1000_state_t { __IGB_TESTING, diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index b1367ce..b8551a5 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -275,13 +275,17 @@ static int igb_set_pauseparam(struct net_device *netdev, static u32 igb_get_rx_csum(struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); - return adapter->rx_csum; + return !(adapter->flags & IGB_FLAG_RX_CSUM_DISABLED); } static int igb_set_rx_csum(struct net_device *netdev, u32 data) { struct igb_adapter *adapter = netdev_priv(netdev); - adapter->rx_csum = data; + + if (data) + adapter->flags &= ~IGB_FLAG_RX_CSUM_DISABLED; + else + adapter->flags |= IGB_FLAG_RX_CSUM_DISABLED; return 0; } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index bca7e9f..8de8629 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1395,8 +1395,6 @@ static int __devinit igb_probe(struct pci_dev *pdev, igb_validate_mdi_setting(hw); - adapter->rx_csum = 1; - /* Initial Wake on LAN setting If APM wake is enabled in the EEPROM, * enable the ACPI Magic Packet filter */ @@ -2249,13 +2247,12 @@ static void igb_configure_rx(struct igb_adapter *adapter) rxcsum = rd32(E1000_RXCSUM); /* Disable raw packet checksumming */ rxcsum |= E1000_RXCSUM_PCSD; - /* Don't need to set TUOFL or IPOFL, they default to 1 */ - if (!adapter->rx_csum) - rxcsum &= ~(E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPOFL); - else if (adapter->hw.mac.type == e1000_82576) + + if (adapter->hw.mac.type == e1000_82576) /* Enable Receive Checksum Offload for SCTP */ rxcsum |= E1000_RXCSUM_CRCOFL; + /* Don't need to set TUOFL or IPOFL, they default to 1 */ wr32(E1000_RXCSUM, rxcsum); /* Set the default pool for the PF's first queue */ @@ -4455,7 +4452,8 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, skb->ip_summed = CHECKSUM_NONE; /* Ignore Checksum bit is set or checksum is disabled through ethtool */ - if ((status_err & E1000_RXD_STAT_IXSM) || !adapter->rx_csum) + if ((status_err & E1000_RXD_STAT_IXSM) || + (adapter->flags & IGB_FLAG_RX_CSUM_DISABLED)) return; /* TCP/UDP checksum error bit is set */ if (status_err & -- cgit v0.10.2 From dcb4ea2ea2ba990a59db5a4cc402df3c2bd389b3 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2009 10:25:42 +0000 Subject: pci: update 82576 sr-iov quirk with latest device IDs The current quirk doesn't include all 82576 device IDs. This update resolves that. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0254741..c01c119 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2460,6 +2460,8 @@ static void __devinit quirk_i82576_sriov(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10c9, quirk_i82576_sriov); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e6, quirk_i82576_sriov); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e8, quirk_i82576_sriov); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150a, quirk_i82576_sriov); #endif /* CONFIG_PCI_IOV */ -- cgit v0.10.2 From 7a921c93626e7481b5d8788d8511995aa2d2b591 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2009 10:43:28 +0000 Subject: ixgbe: make q_vectors dynamic to reduce netdev size Currently the q_vectors are being allocated statically inside of the adapter struct. This increases the overall size of the adapter struct when we can easily allocate the vectors dynamically. This patch changes that behavior so that the q_vectors are allocated dynamically and the napi structures are automatically allocated inside of the q_vectors as needed. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 4b44a8e..61cb415 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -187,6 +187,7 @@ struct ixgbe_q_vector { u8 tx_itr; u8 rx_itr; u32 eitr; + u32 v_idx; /* vector index in list */ }; /* Helper macros to switch between ints/sec and what the register uses. @@ -230,7 +231,7 @@ struct ixgbe_adapter { struct vlan_group *vlgrp; u16 bd_number; struct work_struct reset_task; - struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS]; + struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; char name[MAX_MSIX_COUNT][IFNAMSIZ + 9]; struct ixgbe_dcb_config dcb_cfg; struct ixgbe_dcb_config temp_dcb_cfg; @@ -367,8 +368,8 @@ 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); -extern void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter); extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); +extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); void ixgbe_napi_add_all(struct ixgbe_adapter *adapter); void ixgbe_napi_del_all(struct ixgbe_adapter *adapter); extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32); diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index bd0a0c2..99e0c10 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -124,13 +124,7 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - adapter->tx_ring = NULL; - adapter->rx_ring = NULL; + ixgbe_clear_interrupt_scheme(adapter); adapter->hw.fc.requested_mode = ixgbe_fc_pfc; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; @@ -144,13 +138,7 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) adapter->hw.fc.requested_mode = ixgbe_fc_default; if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - adapter->tx_ring = NULL; - adapter->rx_ring = NULL; + ixgbe_clear_interrupt_scheme(adapter); adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index d822c92..c0167d6 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1114,7 +1114,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev, } for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { - struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; + struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; if (q_vector->txr_count && !q_vector->rxr_count) /* tx vector gets half the rate */ q_vector->eitr = (adapter->eitr_param >> 1); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index be5eabc..165bfa6 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -468,7 +468,7 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, bool is_vlan = (status & IXGBE_RXD_STAT_VP); u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); - skb_record_rx_queue(skb, q_vector - &adapter->q_vector[0]); + skb_record_rx_queue(skb, q_vector->v_idx); if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_gro_receive(napi, adapter->vlgrp, tag, skb); @@ -835,7 +835,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) * corresponding register. */ for (v_idx = 0; v_idx < q_vectors; v_idx++) { - q_vector = &adapter->q_vector[v_idx]; + q_vector = adapter->q_vector[v_idx]; /* XXX for_each_bit(...) */ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); @@ -984,8 +984,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) struct ixgbe_adapter *adapter = q_vector->adapter; 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); + int i, r_idx, v_idx = q_vector->v_idx; struct ixgbe_ring *rx_ring, *tx_ring; r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); @@ -1303,19 +1302,21 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, int r_idx) { - a->q_vector[v_idx].adapter = a; - set_bit(r_idx, a->q_vector[v_idx].rxr_idx); - a->q_vector[v_idx].rxr_count++; + struct ixgbe_q_vector *q_vector = a->q_vector[v_idx]; + + set_bit(r_idx, q_vector->rxr_idx); + q_vector->rxr_count++; a->rx_ring[r_idx].v_idx = 1 << v_idx; } static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, - int r_idx) + int t_idx) { - a->q_vector[v_idx].adapter = a; - set_bit(r_idx, a->q_vector[v_idx].txr_idx); - a->q_vector[v_idx].txr_count++; - a->tx_ring[r_idx].v_idx = 1 << v_idx; + struct ixgbe_q_vector *q_vector = a->q_vector[v_idx]; + + set_bit(t_idx, q_vector->txr_idx); + q_vector->txr_count++; + a->tx_ring[t_idx].v_idx = 1 << v_idx; } /** @@ -1411,7 +1412,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) (!(_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]); + handler = SET_HANDLER(adapter->q_vector[vector]); if(handler == &ixgbe_msix_clean_rx) { sprintf(adapter->name[vector], "%s-%s-%d", @@ -1427,7 +1428,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) err = request_irq(adapter->msix_entries[vector].vector, handler, 0, adapter->name[vector], - &(adapter->q_vector[vector])); + adapter->q_vector[vector]); if (err) { DPRINTK(PROBE, ERR, "request_irq failed for MSIX interrupt " @@ -1450,7 +1451,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); @@ -1461,7 +1462,7 @@ out: static void ixgbe_set_itr(struct ixgbe_adapter *adapter) { - struct ixgbe_q_vector *q_vector = adapter->q_vector; + struct ixgbe_q_vector *q_vector = adapter->q_vector[0]; u8 current_itr; u32 new_itr = q_vector->eitr; struct ixgbe_ring *rx_ring = &adapter->rx_ring[0]; @@ -1539,6 +1540,7 @@ static irqreturn_t ixgbe_intr(int irq, void *data) struct net_device *netdev = data; struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_q_vector *q_vector = adapter->q_vector[0]; u32 eicr; /* @@ -1566,13 +1568,13 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_fan_failure(adapter, eicr); - if (napi_schedule_prep(&adapter->q_vector[0].napi)) { + if (napi_schedule_prep(&(q_vector->napi))) { adapter->tx_ring[0].total_packets = 0; adapter->tx_ring[0].total_bytes = 0; adapter->rx_ring[0].total_packets = 0; adapter->rx_ring[0].total_bytes = 0; /* would disable interrupts here but EIAM disabled it */ - __napi_schedule(&adapter->q_vector[0].napi); + __napi_schedule(&(q_vector->napi)); } return IRQ_HANDLED; @@ -1583,7 +1585,7 @@ static inline void ixgbe_reset_q_vectors(struct ixgbe_adapter *adapter) int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; for (i = 0; i < q_vectors; i++) { - struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; + struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; bitmap_zero(q_vector->rxr_idx, MAX_RX_QUEUES); bitmap_zero(q_vector->txr_idx, MAX_TX_QUEUES); q_vector->rxr_count = 0; @@ -1634,7 +1636,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); @@ -2135,7 +2137,7 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) for (q_idx = 0; q_idx < q_vectors; q_idx++) { struct napi_struct *napi; - q_vector = &adapter->q_vector[q_idx]; + q_vector = adapter->q_vector[q_idx]; if (!q_vector->rxr_count) continue; napi = &q_vector->napi; @@ -2158,7 +2160,7 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) q_vectors = 1; for (q_idx = 0; q_idx < q_vectors; q_idx++) { - q_vector = &adapter->q_vector[q_idx]; + q_vector = adapter->q_vector[q_idx]; if (!q_vector->rxr_count) continue; napi_disable(&q_vector->napi); @@ -2498,8 +2500,6 @@ int ixgbe_up(struct ixgbe_adapter *adapter) /* hardware has been reset, we need to reload some things */ ixgbe_configure(adapter); - ixgbe_napi_add_all(adapter); - return ixgbe_up_complete(adapter); } @@ -2877,9 +2877,6 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; kfree(adapter->msix_entries); adapter->msix_entries = NULL; - adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; - adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; - ixgbe_set_num_queues(adapter); } else { adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; /* Woot! */ /* @@ -3103,31 +3100,20 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) * mean we disable MSI-X capabilities of the adapter. */ adapter->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), GFP_KERNEL); - if (!adapter->msix_entries) { - adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; - adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; - ixgbe_set_num_queues(adapter); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - err = ixgbe_alloc_queues(adapter); - if (err) { - DPRINTK(PROBE, ERR, "Unable to allocate memory " - "for queues\n"); - goto out; - } - - goto try_msi; - } + if (adapter->msix_entries) { + for (vector = 0; vector < v_budget; vector++) + adapter->msix_entries[vector].entry = vector; - for (vector = 0; vector < v_budget; vector++) - adapter->msix_entries[vector].entry = vector; + ixgbe_acquire_msix_vectors(adapter, v_budget); - ixgbe_acquire_msix_vectors(adapter, v_budget); + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + goto out; + } - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) - goto out; + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + ixgbe_set_num_queues(adapter); -try_msi: err = pci_enable_msi(adapter->pdev); if (!err) { adapter->flags |= IXGBE_FLAG_MSI_ENABLED; @@ -3142,6 +3128,87 @@ out: return err; } +/** + * ixgbe_alloc_q_vectors - Allocate memory for interrupt vectors + * @adapter: board private structure to initialize + * + * We allocate one q_vector per queue interrupt. If allocation fails we + * return -ENOMEM. + **/ +static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) +{ + int q_idx, num_q_vectors; + struct ixgbe_q_vector *q_vector; + int napi_vectors; + int (*poll)(struct napi_struct *, int); + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + napi_vectors = adapter->num_rx_queues; + poll = &ixgbe_clean_rxonly; + } else { + num_q_vectors = 1; + napi_vectors = 1; + poll = &ixgbe_poll; + } + + for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { + q_vector = kzalloc(sizeof(struct ixgbe_q_vector), GFP_KERNEL); + if (!q_vector) + goto err_out; + q_vector->adapter = adapter; + q_vector->v_idx = q_idx; + q_vector->eitr = adapter->eitr_param; + if (q_idx < napi_vectors) + netif_napi_add(adapter->netdev, &q_vector->napi, + (*poll), 64); + adapter->q_vector[q_idx] = q_vector; + } + + return 0; + +err_out: + while (q_idx) { + q_idx--; + q_vector = adapter->q_vector[q_idx]; + netif_napi_del(&q_vector->napi); + kfree(q_vector); + adapter->q_vector[q_idx] = NULL; + } + return -ENOMEM; +} + +/** + * ixgbe_free_q_vectors - Free memory allocated for interrupt vectors + * @adapter: board private structure to initialize + * + * This function frees the memory allocated to the q_vectors. In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. + **/ +static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter) +{ + int q_idx, num_q_vectors; + int napi_vectors; + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + napi_vectors = adapter->num_rx_queues; + } else { + num_q_vectors = 1; + napi_vectors = 1; + } + + for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { + struct ixgbe_q_vector *q_vector = adapter->q_vector[q_idx]; + + adapter->q_vector[q_idx] = NULL; + if (q_idx < napi_vectors) + netif_napi_del(&q_vector->napi); + kfree(q_vector); + } +} + void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { @@ -3173,18 +3240,25 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) /* Number of supported queues */ ixgbe_set_num_queues(adapter); - err = ixgbe_alloc_queues(adapter); - if (err) { - DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); - goto err_alloc_queues; - } - err = ixgbe_set_interrupt_capability(adapter); if (err) { DPRINTK(PROBE, ERR, "Unable to setup interrupt capabilities\n"); goto err_set_interrupt; } + err = ixgbe_alloc_q_vectors(adapter); + if (err) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queue " + "vectors\n"); + goto err_alloc_q_vectors; + } + + err = ixgbe_alloc_queues(adapter); + if (err) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); + goto err_alloc_queues; + } + DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, " "Tx Queue count = %u\n", (adapter->num_rx_queues > 1) ? "Enabled" : @@ -3194,11 +3268,30 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) return 0; +err_alloc_queues: + ixgbe_free_q_vectors(adapter); +err_alloc_q_vectors: + ixgbe_reset_interrupt_capability(adapter); err_set_interrupt: + return err; +} + +/** + * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings + * @adapter: board private structure to clear interrupt scheme on + * + * We go through and clear interrupt specific resources and reset the structure + * to pre-load conditions + **/ +void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) +{ kfree(adapter->tx_ring); kfree(adapter->rx_ring); -err_alloc_queues: - return err; + adapter->tx_ring = NULL; + adapter->rx_ring = NULL; + + ixgbe_free_q_vectors(adapter); + ixgbe_reset_interrupt_capability(adapter); } /** @@ -3619,8 +3712,6 @@ static int ixgbe_open(struct net_device *netdev) ixgbe_configure(adapter); - ixgbe_napi_add_all(adapter); - err = ixgbe_request_irq(adapter); if (err) goto err_req_irq; @@ -3672,55 +3763,6 @@ static int ixgbe_close(struct net_device *netdev) return 0; } -/** - * ixgbe_napi_add_all - prep napi structs for use - * @adapter: private struct - * - * helper function to napi_add each possible q_vector->napi - */ -void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) -{ - int q_idx, q_vectors; - struct net_device *netdev = adapter->netdev; - int (*poll)(struct napi_struct *, int); - - /* check if we already have our netdev->napi_list populated */ - if (&netdev->napi_list != netdev->napi_list.next) - return; - - 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); - } -} - -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) { @@ -3782,11 +3824,7 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) ixgbe_free_all_tx_resources(adapter); ixgbe_free_all_rx_resources(adapter); } - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); + ixgbe_clear_interrupt_scheme(adapter); #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -5012,8 +5050,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, err_register: ixgbe_release_hw_control(adapter); err_hw_init: + ixgbe_clear_interrupt_scheme(adapter); err_sw_init: - ixgbe_reset_interrupt_capability(adapter); err_eeprom: clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); del_timer_sync(&adapter->sfp_timer); @@ -5071,7 +5109,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); - ixgbe_reset_interrupt_capability(adapter); + ixgbe_clear_interrupt_scheme(adapter); ixgbe_release_hw_control(adapter); @@ -5079,8 +5117,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) pci_release_regions(pdev); DPRINTK(PROBE, INFO, "complete\n"); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); free_netdev(netdev); -- cgit v0.10.2 From fdaff1ceac32e1748353e91a420c18141ea153c0 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2009 10:43:47 +0000 Subject: ixgbe: skb_record_rx_queue should record rx queue instead of vector currently ixgbe_receive_skb is passing the vector index to skb_record_rx_queue instead of the queue index. This patch changes that so that the ring index is passed instead. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 165bfa6..2c70fa0 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -461,6 +461,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) **/ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, struct sk_buff *skb, u8 status, + struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc) { struct ixgbe_adapter *adapter = q_vector->adapter; @@ -468,7 +469,7 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, bool is_vlan = (status & IXGBE_RXD_STAT_VP); u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); - skb_record_rx_queue(skb, q_vector->v_idx); + skb_record_rx_queue(skb, ring->queue_index); if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_gro_receive(napi, adapter->vlgrp, tag, skb); @@ -782,7 +783,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, total_rx_packets++; skb->protocol = eth_type_trans(skb, adapter->netdev); - ixgbe_receive_skb(q_vector, skb, staterr, rx_desc); + ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc); next_desc: rx_desc->wb.upper.status_error = 0; -- cgit v0.10.2 From 2012bdc8a5553fc864e78f582c8ce79e762dec42 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2009 10:44:07 +0000 Subject: ixgbe: remove ixgbe_napi_add/del_all references There were still some references to napi_add/del_all left after the dynamic vector allocation patch. This patch removes those references since the ixgbe_napi_add/del_all calls are no longer needed as the napi struct is added when the vector is created, and deleted when the vector is freed. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 61cb415..d743d0e 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -370,8 +370,6 @@ extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *) extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); -void ixgbe_napi_add_all(struct ixgbe_adapter *adapter); -void ixgbe_napi_del_all(struct ixgbe_adapter *adapter); extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32); #endif /* _IXGBE_H_ */ -- cgit v0.10.2 From 3044b8d1ff8c05237652a692fb572a34e4d70146 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 6 May 2009 10:44:26 +0000 Subject: ixgbe: Return PCI_ERS_RESULT_DISCONNECT when bus is disabled According to the "PCI Error Recovery" document, if after a recovery, the bus is disabled, the error_detected function should return PCI_ERS_RESULT_DISCONNECT. Actually ixgbe error_detected function is always returning PCI_ERS_RESULT_NEED_RESET, even if the bus is in failure. This patch just check if the bus is disabled and then returns PCI_ERS_RESULT_DISCONNET. Signed-off-by: Breno Leitao Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 2c70fa0..dd56adb 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5145,6 +5145,9 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) ixgbe_down(adapter); pci_disable_device(pdev); -- cgit v0.10.2 From 9ce77666da48513058e330634a766d4752324f8e Mon Sep 17 00:00:00 2001 From: gouji-new Date: Wed, 6 May 2009 10:44:45 +0000 Subject: ixgbe: Proposed PARCH PCIE legacy I/O port free intel 10Gb NIC driver Traditionally Intel based NIC drivers request I/O port even though it doesn't need that really. Intel PCIE 10Gb driver (ixgbe) also requests I/O port but it doesn't need it either. This is a little inconvenient situation because sometimes we have to handle those cards on the slots where any I/O space is not attached. So we made pach which makes ixgbe driver legacy I/O port free. Signed-off-by: Masayuki Gouji Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index dd56adb..08f4a13 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3773,7 +3773,8 @@ static int ixgbe_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - err = pci_enable_device(pdev); + + err = pci_enable_device_mem(pdev); if (err) { printk(KERN_ERR "ixgbe: Cannot enable PCI device from " "suspend\n"); @@ -4778,7 +4779,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, int i, err, pci_using_dac; u32 part_num, eec; - err = pci_enable_device(pdev); + err = pci_enable_device_mem(pdev); if (err) return err; @@ -4798,9 +4799,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, pci_using_dac = 0; } - err = pci_request_regions(pdev, ixgbe_driver_name); + err = pci_request_selected_regions(pdev, pci_select_bars(pdev, + IORESOURCE_MEM), ixgbe_driver_name); if (err) { - dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err); + dev_err(&pdev->dev, + "pci_request_selected_regions failed 0x%x\n", err); goto err_pci_reg; } @@ -5063,7 +5066,8 @@ err_eeprom: err_ioremap: free_netdev(netdev); err_alloc_etherdev: - pci_release_regions(pdev); + pci_release_selected_regions(pdev, pci_select_bars(pdev, + IORESOURCE_MEM)); err_pci_reg: err_dma: pci_disable_device(pdev); @@ -5115,7 +5119,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) ixgbe_release_hw_control(adapter); iounmap(adapter->hw.hw_addr); - pci_release_regions(pdev); + pci_release_selected_regions(pdev, pci_select_bars(pdev, + IORESOURCE_MEM)); DPRINTK(PROBE, INFO, "complete\n"); @@ -5169,7 +5174,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) pci_ers_result_t result; int err; - if (pci_enable_device(pdev)) { + if (pci_enable_device_mem(pdev)) { DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n"); result = PCI_ERS_RESULT_DISCONNECT; -- cgit v0.10.2 From 4dbc8ef7e1123bb8a591d75a2b84413aa261a9f4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 May 2009 16:50:52 -0700 Subject: net: Make inet_twsk_put similar to sock_put By separating the freeing code from the refcounting decrementing. Probably reducing icache pressure when we still have reference counts to go. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 8554d0e..68a8d89 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -49,19 +49,22 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw, inet_twsk_put(tw); } -void inet_twsk_put(struct inet_timewait_sock *tw) +static noinline void inet_twsk_free(struct inet_timewait_sock *tw) { - if (atomic_dec_and_test(&tw->tw_refcnt)) { - struct module *owner = tw->tw_prot->owner; - twsk_destructor((struct sock *)tw); + struct module *owner = tw->tw_prot->owner; + twsk_destructor((struct sock *)tw); #ifdef SOCK_REFCNT_DEBUG - printk(KERN_DEBUG "%s timewait_sock %p released\n", - tw->tw_prot->name, tw); + pr_debug("%s timewait_sock %p released\n", tw->tw_prot->name, tw); #endif - release_net(twsk_net(tw)); - kmem_cache_free(tw->tw_prot->twsk_prot->twsk_slab, tw); - module_put(owner); - } + release_net(twsk_net(tw)); + kmem_cache_free(tw->tw_prot->twsk_prot->twsk_slab, tw); + module_put(owner); +} + +void inet_twsk_put(struct inet_timewait_sock *tw) +{ + if (atomic_dec_and_test(&tw->tw_refcnt)) + inet_twsk_free(tw); } EXPORT_SYMBOL_GPL(inet_twsk_put); -- cgit v0.10.2 From 4d5b78c055c76bb563c4a43d2adb92735b3b9405 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 6 May 2009 16:52:51 -0700 Subject: net: Add missing rculist.h include to netdevice.h Otherwise list_for_each_entry_rcu() et al. aren't visible and we get build failures in some configurations. Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 02882e2..2af89b6 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -39,6 +39,7 @@ #include #include +#include #include #include -- cgit v0.10.2 From f5f8d86b231e0489c33542c42afbb14d32411ee8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 May 2009 07:08:38 +0000 Subject: tcp: tcp_prequeue() cleanup Small cleanup patch to reduce line lengths, before a change in tcp_prequeue(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index b55b489..ac37228 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -890,30 +890,31 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); - if (!sysctl_tcp_low_latency && tp->ucopy.task) { - __skb_queue_tail(&tp->ucopy.prequeue, skb); - tp->ucopy.memory += skb->truesize; - if (tp->ucopy.memory > sk->sk_rcvbuf) { - struct sk_buff *skb1; - - BUG_ON(sock_owned_by_user(sk)); - - while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { - sk_backlog_rcv(sk, skb1); - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED); - } - - tp->ucopy.memory = 0; - } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { - wake_up_interruptible(sk->sk_sleep); - if (!inet_csk_ack_scheduled(sk)) - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - (3 * TCP_RTO_MIN) / 4, - TCP_RTO_MAX); + if (sysctl_tcp_low_latency || !tp->ucopy.task) + return 0; + + __skb_queue_tail(&tp->ucopy.prequeue, skb); + tp->ucopy.memory += skb->truesize; + if (tp->ucopy.memory > sk->sk_rcvbuf) { + struct sk_buff *skb1; + + BUG_ON(sock_owned_by_user(sk)); + + while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { + sk_backlog_rcv(sk, skb1); + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPPREQUEUEDROPPED); } - return 1; + + tp->ucopy.memory = 0; + } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { + wake_up_interruptible(sk->sk_sleep); + if (!inet_csk_ack_scheduled(sk)) + inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, + (3 * TCP_RTO_MIN) / 4, + TCP_RTO_MAX); } - return 0; + return 1; } -- cgit v0.10.2 From 7aedec2ad5314b173e78ca3f4edb4ceaa02248bb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 May 2009 07:20:39 +0000 Subject: tcp: tcp_prequeue() can use keyed wakeups We can avoid waking up tasks not interested in receive notifications, using wake_up_interruptible_poll() instead of wake_up_interruptible() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index ac37228..87d210b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -908,7 +908,8 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) tp->ucopy.memory = 0; } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { - wake_up_interruptible(sk->sk_sleep); + wake_up_interruptible_poll(sk->sk_sleep, + POLLIN | POLLRDNORM | POLLRDBAND); if (!inet_csk_ack_scheduled(sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * TCP_RTO_MIN) / 4, -- cgit v0.10.2 From afafd5b020a60b72d064e89244cb44a975eb2407 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 7 May 2009 10:38:56 +0000 Subject: ixgbe: always set header length in SRRCTL As per the documentation for 82599 in order to support hardware RSC the header size must be set. This is only currently done for packet split mode. This patch sets the header buffer length for all modes. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 08f4a13..4c38d51 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1754,28 +1754,20 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + srrctl |= (IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & + IXGBE_SRRCTL_BSIZEHDR_MASK; + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { - u16 bufsz = IXGBE_RXBUFFER_2048; - /* grow the amount we can receive on large page machines */ - if (bufsz < (PAGE_SIZE / 2)) - bufsz = (PAGE_SIZE / 2); - /* cap the bufsz at our largest descriptor size */ - bufsz = min((u16)IXGBE_MAX_RXBUFFER, bufsz); - - srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +#if (PAGE_SIZE / 2) > IXGBE_MAX_RXBUFFER + srrctl |= IXGBE_MAX_RXBUFFER >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +#else + srrctl |= (PAGE_SIZE / 2) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +#endif srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; - srrctl |= ((IXGBE_RX_HDR_SIZE << - IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & - IXGBE_SRRCTL_BSIZEHDR_MASK); } else { + srrctl |= ALIGN(rx_ring->rx_buf_len, 1024) >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; 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); -- cgit v0.10.2 From 163de42e240623694562656542adedbca369beaf Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 7 May 2009 10:39:16 +0000 Subject: ixgbe: set queue0 for srrctl configuration correctly for DCB The current configuration is not setting queue 0 correctly for DCB configurations. As a result unconfigured queues are being used to setup the SRRCTL register rx buffer len sizes. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 4c38d51..d64a2d7 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1740,7 +1740,18 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) unsigned long mask; if (adapter->hw.mac.type == ixgbe_mac_82599EB) { - queue0 = index; + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + int dcb_i = adapter->ring_feature[RING_F_DCB].indices; + if (dcb_i == 8) + queue0 = index >> 4; + else if (dcb_i == 4) + queue0 = index >> 5; + else + dev_err(&adapter->pdev->dev, "Invalid DCB " + "configuration\n"); + } else { + queue0 = index; + } } else { mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask; queue0 = index & mask; -- cgit v0.10.2 From dfa12f05f60eb23b1670f3a7756ed814f886a7fb Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 7 May 2009 10:39:35 +0000 Subject: ixgbe: Enable L2 header split in 82599 This enables L2 header split when packet split is enabled for 82599. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d64a2d7..01d8b6b 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1818,7 +1818,8 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) u32 psrtype = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | IXGBE_PSRTYPE_IPV4HDR | - IXGBE_PSRTYPE_IPV6HDR; + IXGBE_PSRTYPE_IPV6HDR | + IXGBE_PSRTYPE_L2HDR; IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); } } else { diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index e49e8af..9fd79a0 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1604,6 +1604,7 @@ #define IXGBE_PSRTYPE_UDPHDR 0x00000020 #define IXGBE_PSRTYPE_IPV4HDR 0x00000100 #define IXGBE_PSRTYPE_IPV6HDR 0x00000200 +#define IXGBE_PSRTYPE_L2HDR 0x00001000 /* SRRCTL bit definitions */ #define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ -- cgit v0.10.2 From bf069c9726b592432ed646e72b910ac3c098d025 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 7 May 2009 10:39:54 +0000 Subject: ixgbe: fix failing to log fan failures We weren't logging the 82598AT fan failure if it occurred before (ixgbe_open) as we hadn't sent up to catch the interrupt that event caused. This patch checks for this failure in: ixgbe_probe - So we can log the failure asap. We check right after we set up the adapter->flags, which is when we know that we have a fan. ixgbe_up_complete - To catch failures that may have happened between probe and when we set up the interrupt that would normally detect the fan failure. To enable all of this we need to initialize the adapter flag with IXGBE_FLAG_FAN_FAIL_CAPABLE when the NIC contained a fan. Signed-off-by: Don Skidmore Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 01d8b6b..4a316e9 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2458,6 +2458,17 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) ixgbe_irq_enable(adapter); /* + * If this adapter has a fan, check to see if we had a failure + * before we enabled the interrupt. + */ + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { + u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + if (esdp & IXGBE_ESDP_SDP1) + DPRINTK(DRV, CRIT, + "Fan has stopped, replace the adapter\n"); + } + + /* * For hot-pluggable SFP+ devices, a new SFP+ module may have * arrived before interrupts were enabled. We need to kick off * the SFP+ module setup first, then try to bring up link. @@ -3382,9 +3393,11 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->ring_feature[RING_F_RSS].indices = rss; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; - if (hw->mac.type == ixgbe_mac_82598EB) + if (hw->mac.type == ixgbe_mac_82598EB) { + if (hw->device_id == IXGBE_DEV_ID_82598AT) + adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598; - else if (hw->mac.type == ixgbe_mac_82599EB) { + } else if (hw->mac.type == ixgbe_mac_82599EB) { adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; adapter->flags |= IXGBE_FLAG_RSC_CAPABLE; adapter->flags |= IXGBE_FLAG_RSC_ENABLED; @@ -4915,6 +4928,17 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (err) goto err_sw_init; + /* + * If there is a fan on this device and it has failed log the + * failure. + */ + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { + u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + if (esdp & IXGBE_ESDP_SDP1) + DPRINTK(PROBE, CRIT, + "Fan has stopped, replace the adapter\n"); + } + /* reset_hw fills in the perm_addr as well */ err = hw->mac.ops.reset_hw(hw); if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { -- cgit v0.10.2 From c9c7d2e5a06cd3a26b6be096949e3371ec2aa123 Mon Sep 17 00:00:00 2001 From: "Nelson, Shannon" Date: Thu, 7 May 2009 10:40:15 +0000 Subject: ixgbe: Typecase '1' for 64 bit shift Make sure we don't get any sign-extend issues when we shift a 1 into bit 31. Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 4a316e9..efb175b 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1307,7 +1307,7 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, set_bit(r_idx, q_vector->rxr_idx); q_vector->rxr_count++; - a->rx_ring[r_idx].v_idx = 1 << v_idx; + a->rx_ring[r_idx].v_idx = (u64)1 << v_idx; } static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, @@ -1317,7 +1317,7 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, set_bit(t_idx, q_vector->txr_idx); q_vector->txr_count++; - a->tx_ring[t_idx].v_idx = 1 << v_idx; + a->tx_ring[t_idx].v_idx = (u64)1 << v_idx; } /** @@ -4057,7 +4057,7 @@ static void ixgbe_watchdog(unsigned long data) int i; for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) - eics |= (1 << i); + eics |= ((u64)1 << i); /* Cause software interrupt to ensure rx rings are cleaned */ switch (hw->mac.type) { -- cgit v0.10.2 From c2d5ab4973bfaa72cbb677801825ce56c8f69b56 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 7 May 2009 11:07:35 +0000 Subject: e1000/e1000e/igb/ixgb: don't txhang after link down after the recent changes to wired drivers to use only netif_carrier_off the driver can have outstanding tx work to complete that will never complete once link is down. Since the intel hardware will hold this tx work forever, the driver notices a tx timeout condition internally and might try to instigate printk and reset of the part with a netif_stop_queue, which doesn't work because link is down. Don't bother arming to tx hang detection when link is down. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 71d4fe1..b455dca 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2646,6 +2646,8 @@ static void e1000_watchdog(unsigned long data) * (Do the reset outside of interrupt context). */ adapter->tx_timeout_count++; schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; } } diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index da6b37e..ccaaee0 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3651,6 +3651,8 @@ link_up: */ adapter->tx_timeout_count++; schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; } } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 8de8629..8784c05 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2711,6 +2711,8 @@ link_up: * (Do the reset outside of interrupt context). */ adapter->tx_timeout_count++; schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; } } diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index cb9ecc4..04cb81a 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1140,6 +1140,8 @@ ixgb_watchdog(unsigned long data) * to get done, so reset controller to flush Tx. * (Do the reset outside of interrupt context). */ schedule_work(&adapter->tx_timeout_task); + /* return immediately since reset is imminent */ + return; } } -- cgit v0.10.2 From 928f308f556f4943e50c5064b546f47bce301f02 Mon Sep 17 00:00:00 2001 From: Matthias Ludwig Date: Thu, 7 May 2009 15:00:12 -0700 Subject: smsc911x: fix calculation of res_size for ioremap fix size of remaped iomem, which is 1 byte to small (e.g. mappes only 0xff bytes instead of 0x100) Signed-off-by: Matthias Ludwig Acked-by: Steve Glendinning Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 9a8528c..3cff840 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1976,7 +1976,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = -ENODEV; goto out_0; } - res_size = res->end - res->start; + res_size = res->end - res->start + 1; irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { -- cgit v0.10.2 From 383ca5b874fad082a61af0f47610a1af83e6bb44 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 14 Apr 2009 14:24:21 +0200 Subject: netfilter: xtables: use NFPROTO_ for xt_proto_init callsites Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2ec8d72..3051dda 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -2201,12 +2201,12 @@ static struct xt_match icmp_matchstruct __read_mostly = { static int __net_init ip_tables_net_init(struct net *net) { - return xt_proto_init(net, AF_INET); + return xt_proto_init(net, NFPROTO_IPV4); } static void __net_exit ip_tables_net_exit(struct net *net) { - xt_proto_fini(net, AF_INET); + xt_proto_fini(net, NFPROTO_IPV4); } static struct pernet_operations ip_tables_net_ops = { diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 219e165..41fbc1e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -2234,12 +2234,12 @@ static struct xt_match icmp6_matchstruct __read_mostly = { static int __net_init ip6_tables_net_init(struct net *net) { - return xt_proto_init(net, AF_INET6); + return xt_proto_init(net, NFPROTO_IPV6); } static void __net_exit ip6_tables_net_exit(struct net *net) { - xt_proto_fini(net, AF_INET6); + xt_proto_fini(net, NFPROTO_IPV6); } static struct pernet_operations ip6_tables_net_ops = { -- cgit v0.10.2 From 4b1e27e99f354ad90a1cbdda352b84763e70ac78 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 14 Apr 2009 14:26:49 +0200 Subject: netfilter: queue: use NFPROTO_ for queue callsites af is an nfproto. Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 5f22c91..c156db2 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -596,7 +596,7 @@ static int __init ip_queue_init(void) #ifdef CONFIG_SYSCTL ipq_sysctl_header = register_sysctl_paths(net_ipv4_ctl_path, ipq_table); #endif - status = nf_register_queue_handler(PF_INET, &nfqh); + status = nf_register_queue_handler(NFPROTO_IPV4, &nfqh); if (status < 0) { printk(KERN_ERR "ip_queue: failed to register queue handler\n"); goto cleanup_sysctl; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index b693f84..1cf3f0c 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -598,7 +598,7 @@ static int __init ip6_queue_init(void) #ifdef CONFIG_SYSCTL ipq_sysctl_header = register_sysctl_paths(net_ipv6_ctl_path, ipq_table); #endif - status = nf_register_queue_handler(PF_INET6, &nfqh); + status = nf_register_queue_handler(NFPROTO_IPV6, &nfqh); if (status < 0) { printk(KERN_ERR "ip6_queue: failed to register queue handler\n"); goto cleanup_sysctl; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 4f2310c..3a6fd77 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -204,10 +204,10 @@ int nf_queue(struct sk_buff *skb, queuenum); switch (pf) { - case AF_INET: + case NFPROTO_IPV4: skb->protocol = htons(ETH_P_IP); break; - case AF_INET6: + case NFPROTO_IPV6: skb->protocol = htons(ETH_P_IPV6); break; } -- cgit v0.10.2 From 4ba351cf866257de3da3fbc8d2bcc3907ee9460f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 14 Apr 2009 14:28:48 +0200 Subject: netfilter: xtables: use NFPROTO_ in standard targets Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 3051dda..5abc276 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -2158,7 +2158,7 @@ static bool icmp_checkentry(const struct xt_mtchk_param *par) static struct xt_target ipt_standard_target __read_mostly = { .name = IPT_STANDARD_TARGET, .targetsize = sizeof(int), - .family = AF_INET, + .family = NFPROTO_IPV4, #ifdef CONFIG_COMPAT .compatsize = sizeof(compat_int_t), .compat_from_user = compat_standard_from_user, @@ -2170,7 +2170,7 @@ static struct xt_target ipt_error_target __read_mostly = { .name = IPT_ERROR_TARGET, .target = ipt_error, .targetsize = IPT_FUNCTION_MAXNAMELEN, - .family = AF_INET, + .family = NFPROTO_IPV4, }; static struct nf_sockopt_ops ipt_sockopts = { @@ -2196,7 +2196,7 @@ static struct xt_match icmp_matchstruct __read_mostly = { .matchsize = sizeof(struct ipt_icmp), .checkentry = icmp_checkentry, .proto = IPPROTO_ICMP, - .family = AF_INET, + .family = NFPROTO_IPV4, }; static int __net_init ip_tables_net_init(struct net *net) diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 41fbc1e..37a850e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -2191,7 +2191,7 @@ static bool icmp6_checkentry(const struct xt_mtchk_param *par) static struct xt_target ip6t_standard_target __read_mostly = { .name = IP6T_STANDARD_TARGET, .targetsize = sizeof(int), - .family = AF_INET6, + .family = NFPROTO_IPV6, #ifdef CONFIG_COMPAT .compatsize = sizeof(compat_int_t), .compat_from_user = compat_standard_from_user, @@ -2203,7 +2203,7 @@ static struct xt_target ip6t_error_target __read_mostly = { .name = IP6T_ERROR_TARGET, .target = ip6t_error, .targetsize = IP6T_FUNCTION_MAXNAMELEN, - .family = AF_INET6, + .family = NFPROTO_IPV6, }; static struct nf_sockopt_ops ip6t_sockopts = { @@ -2229,7 +2229,7 @@ static struct xt_match icmp6_matchstruct __read_mostly = { .matchsize = sizeof(struct ip6t_icmp), .checkentry = icmp6_checkentry, .proto = IPPROTO_ICMPV6, - .family = AF_INET6, + .family = NFPROTO_IPV6, }; static int __net_init ip6_tables_net_init(struct net *net) -- cgit v0.10.2 From ccf5bd8c27daa4184004438273e03d3812b14d75 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 15 Apr 2009 20:27:03 +0200 Subject: netfilter: xtables: remove redundant casts Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 5abc276..7fcbc16 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -280,7 +280,7 @@ static void trace_packet(struct sk_buff *skb, char *hookname, *chainname, *comment; unsigned int rulenum = 0; - table_base = (void *)private->entries[smp_processor_id()]; + table_base = private->entries[smp_processor_id()]; root = get_entry(table_base, private->hook_entry[hook]); hookname = chainname = (char *)hooknames[hook]; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 37a850e..2b52fac 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -312,7 +312,7 @@ static void trace_packet(struct sk_buff *skb, char *hookname, *chainname, *comment; unsigned int rulenum = 0; - table_base = (void *)private->entries[smp_processor_id()]; + table_base = private->entries[smp_processor_id()]; root = get_entry(table_base, private->hook_entry[hook]); hookname = chainname = (char *)hooknames[hook]; -- cgit v0.10.2 From 4f2f6f236af484ada595ff37d0ee1902aa56221f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 15 Apr 2009 20:31:13 +0200 Subject: netfilter: xtables: fix const inconsistency Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 7fcbc16..16b7c09 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -238,8 +238,8 @@ static struct nf_loginfo trace_loginfo = { /* Mildly perf critical (only if packet tracing is on) */ static inline int get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, - char *hookname, char **chainname, - char **comment, unsigned int *rulenum) + const char *hookname, const char **chainname, + const char **comment, unsigned int *rulenum) { struct ipt_standard_target *t = (void *)ipt_get_target(s); @@ -257,8 +257,8 @@ get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, && unconditional(&s->ip)) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname - ? (char *)comments[NF_IP_TRACE_COMMENT_POLICY] - : (char *)comments[NF_IP_TRACE_COMMENT_RETURN]; + ? comments[NF_IP_TRACE_COMMENT_POLICY] + : comments[NF_IP_TRACE_COMMENT_RETURN]; } return 1; } else @@ -277,14 +277,14 @@ static void trace_packet(struct sk_buff *skb, { void *table_base; const struct ipt_entry *root; - char *hookname, *chainname, *comment; + const char *hookname, *chainname, *comment; unsigned int rulenum = 0; table_base = private->entries[smp_processor_id()]; root = get_entry(table_base, private->hook_entry[hook]); - hookname = chainname = (char *)hooknames[hook]; - comment = (char *)comments[NF_IP_TRACE_COMMENT_RULE]; + hookname = chainname = hooknames[hook]; + comment = comments[NF_IP_TRACE_COMMENT_RULE]; IPT_ENTRY_ITERATE(root, private->size - private->hook_entry[hook], diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 2b52fac..4853a3d 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -270,8 +270,8 @@ static struct nf_loginfo trace_loginfo = { /* Mildly perf critical (only if packet tracing is on) */ static inline int get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, - char *hookname, char **chainname, - char **comment, unsigned int *rulenum) + const char *hookname, const char **chainname, + const char **comment, unsigned int *rulenum) { struct ip6t_standard_target *t = (void *)ip6t_get_target(s); @@ -289,8 +289,8 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, && unconditional(&s->ipv6)) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname - ? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY] - : (char *)comments[NF_IP6_TRACE_COMMENT_RETURN]; + ? comments[NF_IP6_TRACE_COMMENT_POLICY] + : comments[NF_IP6_TRACE_COMMENT_RETURN]; } return 1; } else @@ -309,14 +309,14 @@ static void trace_packet(struct sk_buff *skb, { void *table_base; const struct ip6t_entry *root; - char *hookname, *chainname, *comment; + const char *hookname, *chainname, *comment; unsigned int rulenum = 0; table_base = private->entries[smp_processor_id()]; root = get_entry(table_base, private->hook_entry[hook]); - hookname = chainname = (char *)hooknames[hook]; - comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE]; + hookname = chainname = hooknames[hook]; + comment = comments[NF_IP6_TRACE_COMMENT_RULE]; IP6T_ENTRY_ITERATE(root, private->size - private->hook_entry[hook], -- cgit v0.10.2 From 98e86403162d08a30b03426c54c2a8fca1f695d1 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 15 Apr 2009 21:06:05 +0200 Subject: netfilter: xtables: consolidate open-coded logic Signed-off-by: Jan Engelhardt diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 820252a..2455583 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -142,6 +142,12 @@ static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h, return 0; } +static inline __pure +struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + /* Do some firewalling */ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, @@ -249,8 +255,7 @@ letsreturn: /* jump to a udc */ cs[sp].n = i + 1; cs[sp].chaininfo = chaininfo; - cs[sp].e = (struct ebt_entry *) - (((char *)point) + point->next_offset); + cs[sp].e = ebt_next_entry(point); i = 0; chaininfo = (struct ebt_entries *) (base + verdict); #ifdef CONFIG_NETFILTER_DEBUG @@ -266,8 +271,7 @@ letsreturn: sp++; continue; letscontinue: - point = (struct ebt_entry *) - (((char *)point) + point->next_offset); + point = ebt_next_entry(point); i++; } @@ -787,7 +791,7 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s /* this can't be 0, so the loop test is correct */ cl_s[i].cs.n = pos + 1; pos = 0; - cl_s[i].cs.e = ((void *)e + e->next_offset); + cl_s[i].cs.e = ebt_next_entry(e); e = (struct ebt_entry *)(hlp2->data); nentries = hlp2->nentries; cl_s[i].from = chain_nr; @@ -797,7 +801,7 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s continue; } letscontinue: - e = (void *)e + e->next_offset; + e = ebt_next_entry(e); pos++; } return 0; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 831fe18..940e54b 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -231,6 +231,12 @@ static inline struct arpt_entry *get_entry(void *base, unsigned int offset) return (struct arpt_entry *)(base + offset); } +static inline __pure +struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, @@ -295,10 +301,10 @@ unsigned int arpt_do_table(struct sk_buff *skb, continue; } if (table_base + v - != (void *)e + e->next_offset) { + != arpt_next_entry(e)) { /* Save old back ptr in next entry */ struct arpt_entry *next - = (void *)e + e->next_offset; + = arpt_next_entry(e); next->comefrom = (void *)back - table_base; @@ -320,13 +326,13 @@ unsigned int arpt_do_table(struct sk_buff *skb, arp = arp_hdr(skb); if (verdict == ARPT_CONTINUE) - e = (void *)e + e->next_offset; + e = arpt_next_entry(e); else /* Verdict */ break; } } else { - e = (void *)e + e->next_offset; + e = arpt_next_entry(e); } } while (!hotdrop); xt_info_rdunlock_bh(); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 16b7c09..7ec4e40 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -297,6 +297,12 @@ static void trace_packet(struct sk_buff *skb, } #endif +static inline __pure +struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ unsigned int ipt_do_table(struct sk_buff *skb, @@ -385,11 +391,11 @@ ipt_do_table(struct sk_buff *skb, back->comefrom); continue; } - if (table_base + v != (void *)e + e->next_offset + if (table_base + v != ipt_next_entry(e) && !(e->ip.flags & IPT_F_GOTO)) { /* Save old back ptr in next entry */ struct ipt_entry *next - = (void *)e + e->next_offset; + = ipt_next_entry(e); next->comefrom = (void *)back - table_base; /* set back pointer to next entry */ @@ -424,7 +430,7 @@ ipt_do_table(struct sk_buff *skb, datalen = skb->len - ip->ihl * 4; if (verdict == IPT_CONTINUE) - e = (void *)e + e->next_offset; + e = ipt_next_entry(e); else /* Verdict */ break; @@ -432,7 +438,7 @@ ipt_do_table(struct sk_buff *skb, } else { no_match: - e = (void *)e + e->next_offset; + e = ipt_next_entry(e); } } while (!hotdrop); xt_info_rdunlock_bh(); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 4853a3d..9176e98 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -329,6 +329,12 @@ static void trace_packet(struct sk_buff *skb, } #endif +static inline __pure struct ip6t_entry * +ip6t_next_entry(const struct ip6t_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ unsigned int ip6t_do_table(struct sk_buff *skb, @@ -414,11 +420,11 @@ ip6t_do_table(struct sk_buff *skb, back->comefrom); continue; } - if (table_base + v != (void *)e + e->next_offset + if (table_base + v != ip6t_next_entry(e) && !(e->ipv6.flags & IP6T_F_GOTO)) { /* Save old back ptr in next entry */ struct ip6t_entry *next - = (void *)e + e->next_offset; + = ip6t_next_entry(e); next->comefrom = (void *)back - table_base; /* set back pointer to next entry */ @@ -451,7 +457,7 @@ ip6t_do_table(struct sk_buff *skb, = 0x57acc001; #endif if (verdict == IP6T_CONTINUE) - e = (void *)e + e->next_offset; + e = ip6t_next_entry(e); else /* Verdict */ break; @@ -459,7 +465,7 @@ ip6t_do_table(struct sk_buff *skb, } else { no_match: - e = (void *)e + e->next_offset; + e = ip6t_next_entry(e); } } while (!hotdrop); -- cgit v0.10.2 From a1ff4ac84e58503691058e88d55fa48949822683 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 15 Apr 2009 21:28:39 +0200 Subject: netfilter: xtables: reduce indent level by one Cosmetic only. Transformation applied: -if (foo) { long block; } else { short block; } +if (!foo) { short block; continue; } long block; Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 940e54b..ecba246 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -273,66 +273,62 @@ unsigned int arpt_do_table(struct sk_buff *skb, arp = arp_hdr(skb); do { - if (arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { - struct arpt_entry_target *t; - int hdr_len; + struct arpt_entry_target *t; + int hdr_len; - hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + - (2 * skb->dev->addr_len); + if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { + e = arpt_next_entry(e); + continue; + } - ADD_COUNTER(e->counters, hdr_len, 1); + hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + + (2 * skb->dev->addr_len); + ADD_COUNTER(e->counters, hdr_len, 1); - t = arpt_get_target(e); + t = arpt_get_target(e); - /* Standard target? */ - if (!t->u.kernel.target->target) { - int v; + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; - v = ((struct arpt_standard_target *)t)->verdict; - if (v < 0) { - /* Pop from stack? */ - if (v != ARPT_RETURN) { - verdict = (unsigned)(-v) - 1; - break; - } - e = back; - back = get_entry(table_base, - back->comefrom); - continue; - } - if (table_base + v - != arpt_next_entry(e)) { - /* Save old back ptr in next entry */ - struct arpt_entry *next - = arpt_next_entry(e); - next->comefrom = - (void *)back - table_base; - - /* set back pointer to next entry */ - back = next; - } - - e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - * abs. verdicts - */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; - verdict = t->u.kernel.target->target(skb, - &tgpar); - - /* Target might have changed stuff. */ - arp = arp_hdr(skb); - - if (verdict == ARPT_CONTINUE) - e = arpt_next_entry(e); - else - /* Verdict */ + v = ((struct arpt_standard_target *)t)->verdict; + if (v < 0) { + /* Pop from stack? */ + if (v != ARPT_RETURN) { + verdict = (unsigned)(-v) - 1; break; + } + e = back; + back = get_entry(table_base, back->comefrom); + continue; } + if (table_base + v + != arpt_next_entry(e)) { + /* Save old back ptr in next entry */ + struct arpt_entry *next = arpt_next_entry(e); + next->comefrom = (void *)back - table_base; + + /* set back pointer to next entry */ + back = next; + } + + e = get_entry(table_base, v); } else { - e = arpt_next_entry(e); + /* Targets which reenter must return + * abs. verdicts + */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; + verdict = t->u.kernel.target->target(skb, &tgpar); + + /* Target might have changed stuff. */ + arp = arp_hdr(skb); + + if (verdict == ARPT_CONTINUE) + e = arpt_next_entry(e); + else + /* Verdict */ + break; } } while (!hotdrop); xt_info_rdunlock_bh(); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 7ec4e40..82888bc 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -354,91 +354,87 @@ ipt_do_table(struct sk_buff *skb, back = get_entry(table_base, private->underflow[hook]); do { + struct ipt_entry_target *t; + IP_NF_ASSERT(e); IP_NF_ASSERT(back); - if (ip_packet_match(ip, indev, outdev, + if (!ip_packet_match(ip, indev, outdev, &e->ip, mtpar.fragoff)) { - struct ipt_entry_target *t; + no_match: + e = ipt_next_entry(e); + continue; + } - if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) - goto no_match; + if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) + goto no_match; - ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); + ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); - t = ipt_get_target(e); - IP_NF_ASSERT(t->u.kernel.target); + t = ipt_get_target(e); + IP_NF_ASSERT(t->u.kernel.target); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) - /* The packet is traced: log it */ - if (unlikely(skb->nf_trace)) - trace_packet(skb, hook, in, out, - table->name, private, e); + /* The packet is traced: log it */ + if (unlikely(skb->nf_trace)) + trace_packet(skb, hook, in, out, + table->name, private, e); #endif - /* Standard target? */ - if (!t->u.kernel.target->target) { - int v; - - v = ((struct ipt_standard_target *)t)->verdict; - if (v < 0) { - /* Pop from stack? */ - if (v != IPT_RETURN) { - verdict = (unsigned)(-v) - 1; - break; - } - e = back; - back = get_entry(table_base, - back->comefrom); - continue; - } - if (table_base + v != ipt_next_entry(e) - && !(e->ip.flags & IPT_F_GOTO)) { - /* Save old back ptr in next entry */ - struct ipt_entry *next - = ipt_next_entry(e); - next->comefrom - = (void *)back - table_base; - /* set back pointer to next entry */ - back = next; + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; + + v = ((struct ipt_standard_target *)t)->verdict; + if (v < 0) { + /* Pop from stack? */ + if (v != IPT_RETURN) { + verdict = (unsigned)(-v) - 1; + break; } + e = back; + back = get_entry(table_base, back->comefrom); + continue; + } + if (table_base + v != ipt_next_entry(e) + && !(e->ip.flags & IPT_F_GOTO)) { + /* Save old back ptr in next entry */ + struct ipt_entry *next = ipt_next_entry(e); + next->comefrom = (void *)back - table_base; + /* set back pointer to next entry */ + back = next; + } - e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - abs. verdicts */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; + e = get_entry(table_base, v); + } else { + /* Targets which reenter must return + abs. verdicts */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; #ifdef CONFIG_NETFILTER_DEBUG - ((struct ipt_entry *)table_base)->comefrom - = 0xeeeeeeec; + ((struct ipt_entry *)table_base)->comefrom + = 0xeeeeeeec; #endif - verdict = t->u.kernel.target->target(skb, - &tgpar); + verdict = t->u.kernel.target->target(skb, &tgpar); #ifdef CONFIG_NETFILTER_DEBUG - if (((struct ipt_entry *)table_base)->comefrom - != 0xeeeeeeec - && verdict == IPT_CONTINUE) { - printk("Target %s reentered!\n", - t->u.kernel.target->name); - verdict = NF_DROP; - } - ((struct ipt_entry *)table_base)->comefrom - = 0x57acc001; -#endif - /* Target might have changed stuff. */ - ip = ip_hdr(skb); - datalen = skb->len - ip->ihl * 4; - - if (verdict == IPT_CONTINUE) - e = ipt_next_entry(e); - else - /* Verdict */ - break; + if (((struct ipt_entry *)table_base)->comefrom + != 0xeeeeeeec + && verdict == IPT_CONTINUE) { + printk("Target %s reentered!\n", + t->u.kernel.target->name); + verdict = NF_DROP; } - } else { - - no_match: - e = ipt_next_entry(e); + ((struct ipt_entry *)table_base)->comefrom + = 0x57acc001; +#endif + /* Target might have changed stuff. */ + ip = ip_hdr(skb); + datalen = skb->len - ip->ihl * 4; + + if (verdict == IPT_CONTINUE) + e = ipt_next_entry(e); + else + /* Verdict */ + break; } } while (!hotdrop); xt_info_rdunlock_bh(); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 9176e98..a6c2213 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -381,91 +381,87 @@ ip6t_do_table(struct sk_buff *skb, back = get_entry(table_base, private->underflow[hook]); do { + struct ip6t_entry_target *t; + IP_NF_ASSERT(e); IP_NF_ASSERT(back); - if (ip6_packet_match(skb, indev, outdev, &e->ipv6, - &mtpar.thoff, &mtpar.fragoff, &hotdrop)) { - struct ip6t_entry_target *t; + if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, + &mtpar.thoff, &mtpar.fragoff, &hotdrop)) { + no_match: + e = ip6t_next_entry(e); + continue; + } - if (IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) - goto no_match; + if (IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) + goto no_match; - ADD_COUNTER(e->counters, - ntohs(ipv6_hdr(skb)->payload_len) + - sizeof(struct ipv6hdr), 1); + ADD_COUNTER(e->counters, + ntohs(ipv6_hdr(skb)->payload_len) + + sizeof(struct ipv6hdr), 1); - t = ip6t_get_target(e); - IP_NF_ASSERT(t->u.kernel.target); + t = ip6t_get_target(e); + IP_NF_ASSERT(t->u.kernel.target); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) - /* The packet is traced: log it */ - if (unlikely(skb->nf_trace)) - trace_packet(skb, hook, in, out, - table->name, private, e); + /* The packet is traced: log it */ + if (unlikely(skb->nf_trace)) + trace_packet(skb, hook, in, out, + table->name, private, e); #endif - /* Standard target? */ - if (!t->u.kernel.target->target) { - int v; - - v = ((struct ip6t_standard_target *)t)->verdict; - if (v < 0) { - /* Pop from stack? */ - if (v != IP6T_RETURN) { - verdict = (unsigned)(-v) - 1; - break; - } - e = back; - back = get_entry(table_base, - back->comefrom); - continue; - } - if (table_base + v != ip6t_next_entry(e) - && !(e->ipv6.flags & IP6T_F_GOTO)) { - /* Save old back ptr in next entry */ - struct ip6t_entry *next - = ip6t_next_entry(e); - next->comefrom - = (void *)back - table_base; - /* set back pointer to next entry */ - back = next; + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; + + v = ((struct ip6t_standard_target *)t)->verdict; + if (v < 0) { + /* Pop from stack? */ + if (v != IP6T_RETURN) { + verdict = (unsigned)(-v) - 1; + break; } + e = back; + back = get_entry(table_base, back->comefrom); + continue; + } + if (table_base + v != ip6t_next_entry(e) + && !(e->ipv6.flags & IP6T_F_GOTO)) { + /* Save old back ptr in next entry */ + struct ip6t_entry *next = ip6t_next_entry(e); + next->comefrom = (void *)back - table_base; + /* set back pointer to next entry */ + back = next; + } - e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - abs. verdicts */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; + e = get_entry(table_base, v); + } else { + /* Targets which reenter must return + abs. verdicts */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; #ifdef CONFIG_NETFILTER_DEBUG - ((struct ip6t_entry *)table_base)->comefrom - = 0xeeeeeeec; + ((struct ip6t_entry *)table_base)->comefrom + = 0xeeeeeeec; #endif - verdict = t->u.kernel.target->target(skb, - &tgpar); + verdict = t->u.kernel.target->target(skb, &tgpar); #ifdef CONFIG_NETFILTER_DEBUG - if (((struct ip6t_entry *)table_base)->comefrom - != 0xeeeeeeec - && verdict == IP6T_CONTINUE) { - printk("Target %s reentered!\n", - t->u.kernel.target->name); - verdict = NF_DROP; - } - ((struct ip6t_entry *)table_base)->comefrom - = 0x57acc001; -#endif - if (verdict == IP6T_CONTINUE) - e = ip6t_next_entry(e); - else - /* Verdict */ - break; + if (((struct ip6t_entry *)table_base)->comefrom + != 0xeeeeeeec + && verdict == IP6T_CONTINUE) { + printk("Target %s reentered!\n", + t->u.kernel.target->name); + verdict = NF_DROP; } - } else { - - no_match: - e = ip6t_next_entry(e); + ((struct ip6t_entry *)table_base)->comefrom + = 0x57acc001; +#endif + if (verdict == IP6T_CONTINUE) + e = ip6t_next_entry(e); + else + /* Verdict */ + break; } } while (!hotdrop); -- cgit v0.10.2 From 9452258d8173806f67b1be5b3b00c39b052060c8 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 15 Apr 2009 21:31:32 +0200 Subject: netfilter: xtables: remove some goto Combining two ifs, and goto is easily gone. Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 82888bc..cfcb7af 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -359,15 +359,12 @@ ipt_do_table(struct sk_buff *skb, IP_NF_ASSERT(e); IP_NF_ASSERT(back); if (!ip_packet_match(ip, indev, outdev, - &e->ip, mtpar.fragoff)) { - no_match: + &e->ip, mtpar.fragoff) || + IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { e = ipt_next_entry(e); continue; } - if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) - goto no_match; - ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); t = ipt_get_target(e); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index a6c2213..d01b8a3 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -386,15 +386,12 @@ ip6t_do_table(struct sk_buff *skb, IP_NF_ASSERT(e); IP_NF_ASSERT(back); if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, - &mtpar.thoff, &mtpar.fragoff, &hotdrop)) { - no_match: + &mtpar.thoff, &mtpar.fragoff, &hotdrop) || + IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { e = ip6t_next_entry(e); continue; } - if (IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) - goto no_match; - ADD_COUNTER(e->counters, ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr), 1); -- cgit v0.10.2 From 7a6b1c46e28ab0511be26c238d552c00b51b88c5 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 15 Apr 2009 21:35:33 +0200 Subject: netfilter: xtables: remove another level of indent Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index ecba246..7505dff 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -313,23 +313,24 @@ unsigned int arpt_do_table(struct sk_buff *skb, } e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - * abs. verdicts - */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; - verdict = t->u.kernel.target->target(skb, &tgpar); - - /* Target might have changed stuff. */ - arp = arp_hdr(skb); - - if (verdict == ARPT_CONTINUE) - e = arpt_next_entry(e); - else - /* Verdict */ - break; + continue; } + + /* Targets which reenter must return + * abs. verdicts + */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; + verdict = t->u.kernel.target->target(skb, &tgpar); + + /* Target might have changed stuff. */ + arp = arp_hdr(skb); + + if (verdict == ARPT_CONTINUE) + e = arpt_next_entry(e); + else + /* Verdict */ + break; } while (!hotdrop); xt_info_rdunlock_bh(); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index cfcb7af..d91ecd4 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -402,37 +402,35 @@ ipt_do_table(struct sk_buff *skb, } e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - abs. verdicts */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; + continue; + } + + /* Targets which reenter must return + abs. verdicts */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; #ifdef CONFIG_NETFILTER_DEBUG - ((struct ipt_entry *)table_base)->comefrom - = 0xeeeeeeec; + ((struct ipt_entry *)table_base)->comefrom = 0xeeeeeeec; #endif - verdict = t->u.kernel.target->target(skb, &tgpar); + verdict = t->u.kernel.target->target(skb, &tgpar); #ifdef CONFIG_NETFILTER_DEBUG - if (((struct ipt_entry *)table_base)->comefrom - != 0xeeeeeeec - && verdict == IPT_CONTINUE) { - printk("Target %s reentered!\n", - t->u.kernel.target->name); - verdict = NF_DROP; - } - ((struct ipt_entry *)table_base)->comefrom - = 0x57acc001; -#endif - /* Target might have changed stuff. */ - ip = ip_hdr(skb); - datalen = skb->len - ip->ihl * 4; - - if (verdict == IPT_CONTINUE) - e = ipt_next_entry(e); - else - /* Verdict */ - break; + if (((struct ipt_entry *)table_base)->comefrom != 0xeeeeeeec && + verdict == IPT_CONTINUE) { + printk("Target %s reentered!\n", + t->u.kernel.target->name); + verdict = NF_DROP; } + ((struct ipt_entry *)table_base)->comefrom = 0x57acc001; +#endif + /* Target might have changed stuff. */ + ip = ip_hdr(skb); + datalen = skb->len - ip->ihl * 4; + + if (verdict == IPT_CONTINUE) + e = ipt_next_entry(e); + else + /* Verdict */ + break; } while (!hotdrop); xt_info_rdunlock_bh(); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index d01b8a3..5a178be 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -431,35 +431,33 @@ ip6t_do_table(struct sk_buff *skb, } e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - abs. verdicts */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; + continue; + } + + /* Targets which reenter must return + abs. verdicts */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; #ifdef CONFIG_NETFILTER_DEBUG - ((struct ip6t_entry *)table_base)->comefrom - = 0xeeeeeeec; + ((struct ip6t_entry *)table_base)->comefrom = 0xeeeeeeec; #endif - verdict = t->u.kernel.target->target(skb, &tgpar); + verdict = t->u.kernel.target->target(skb, &tgpar); #ifdef CONFIG_NETFILTER_DEBUG - if (((struct ip6t_entry *)table_base)->comefrom - != 0xeeeeeeec - && verdict == IP6T_CONTINUE) { - printk("Target %s reentered!\n", - t->u.kernel.target->name); - verdict = NF_DROP; - } - ((struct ip6t_entry *)table_base)->comefrom - = 0x57acc001; -#endif - if (verdict == IP6T_CONTINUE) - e = ip6t_next_entry(e); - else - /* Verdict */ - break; + if (((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec && + verdict == IP6T_CONTINUE) { + printk("Target %s reentered!\n", + t->u.kernel.target->name); + verdict = NF_DROP; } + ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001; +#endif + if (verdict == IP6T_CONTINUE) + e = ip6t_next_entry(e); + else + /* Verdict */ + break; } while (!hotdrop); #ifdef CONFIG_NETFILTER_DEBUG -- cgit v0.10.2 From bb70dfa5f8ab4a0f1c699ddb3ef0276d91219b7c Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 15 Apr 2009 21:40:13 +0200 Subject: netfilter: xtables: consolidate comefrom debug cast access Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index d91ecd4..7b35c0b 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -311,6 +311,8 @@ ipt_do_table(struct sk_buff *skb, const struct net_device *out, struct xt_table *table) { +#define tb_comefrom ((struct ipt_entry *)table_base)->comefrom + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); const struct iphdr *ip; u_int16_t datalen; @@ -409,18 +411,19 @@ ipt_do_table(struct sk_buff *skb, abs. verdicts */ tgpar.target = t->u.kernel.target; tgpar.targinfo = t->data; + + #ifdef CONFIG_NETFILTER_DEBUG - ((struct ipt_entry *)table_base)->comefrom = 0xeeeeeeec; + tb_comefrom = 0xeeeeeeec; #endif verdict = t->u.kernel.target->target(skb, &tgpar); #ifdef CONFIG_NETFILTER_DEBUG - if (((struct ipt_entry *)table_base)->comefrom != 0xeeeeeeec && - verdict == IPT_CONTINUE) { + if (comefrom != 0xeeeeeeec && verdict == IPT_CONTINUE) { printk("Target %s reentered!\n", t->u.kernel.target->name); verdict = NF_DROP; } - ((struct ipt_entry *)table_base)->comefrom = 0x57acc001; + tb_comefrom = 0x57acc001; #endif /* Target might have changed stuff. */ ip = ip_hdr(skb); @@ -441,6 +444,8 @@ ipt_do_table(struct sk_buff *skb, return NF_DROP; else return verdict; #endif + +#undef tb_comefrom } /* Figures out from what hook each rule can be called: returns 0 if diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 5a178be..5164e0b 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -343,6 +343,8 @@ ip6t_do_table(struct sk_buff *skb, const struct net_device *out, struct xt_table *table) { +#define tb_comefrom ((struct ip6t_entry *)table_base)->comefrom + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); bool hotdrop = false; /* Initializing verdict to NF_DROP keeps gcc happy. */ @@ -440,18 +442,17 @@ ip6t_do_table(struct sk_buff *skb, tgpar.targinfo = t->data; #ifdef CONFIG_NETFILTER_DEBUG - ((struct ip6t_entry *)table_base)->comefrom = 0xeeeeeeec; + tb_comefrom = 0xeeeeeeec; #endif verdict = t->u.kernel.target->target(skb, &tgpar); #ifdef CONFIG_NETFILTER_DEBUG - if (((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec && - verdict == IP6T_CONTINUE) { + if (tb_comefrom != 0xeeeeeeec && verdict == IP6T_CONTINUE) { printk("Target %s reentered!\n", t->u.kernel.target->name); verdict = NF_DROP; } - ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001; + tb_comefrom = 0x57acc001; #endif if (verdict == IP6T_CONTINUE) e = ip6t_next_entry(e); @@ -461,7 +462,7 @@ ip6t_do_table(struct sk_buff *skb, } while (!hotdrop); #ifdef CONFIG_NETFILTER_DEBUG - ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; + tb_comefrom = NETFILTER_LINK_POISON; #endif xt_info_rdunlock_bh(); @@ -472,6 +473,8 @@ ip6t_do_table(struct sk_buff *skb, return NF_DROP; else return verdict; #endif + +#undef tb_comefrom } /* Figures out from what hook each rule can be called: returns 0 if -- cgit v0.10.2 From 451853645f3cb804b523227eca054701e4cbc589 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 5 Apr 2009 10:43:09 +0200 Subject: netfilter: xtables: print hook name instead of mask Users cannot make anything of these numbers. Let's just tell them directly. Signed-off-by: Jan Engelhardt diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 150e5cf..46dba5f 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -329,6 +329,32 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target, } EXPORT_SYMBOL_GPL(xt_find_revision); +static char *textify_hooks(char *buf, size_t size, unsigned int mask) +{ + static const char *const names[] = { + "PREROUTING", "INPUT", "FORWARD", + "OUTPUT", "POSTROUTING", "BROUTING", + }; + unsigned int i; + char *p = buf; + bool np = false; + int res; + + *p = '\0'; + for (i = 0; i < ARRAY_SIZE(names); ++i) { + if (!(mask & (1 << i))) + continue; + res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]); + if (res > 0) { + size -= res; + p += res; + } + np = true; + } + + return buf; +} + int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { @@ -351,9 +377,13 @@ int xt_check_match(struct xt_mtchk_param *par, return -EINVAL; } if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { - printk("%s_tables: %s match: bad hook_mask %#x/%#x\n", + char used[64], allow[64]; + + printk("%s_tables: %s match: used from hooks %s, but only " + "valid from %s\n", xt_prefix[par->family], par->match->name, - par->hook_mask, par->match->hooks); + textify_hooks(used, sizeof(used), par->hook_mask), + textify_hooks(allow, sizeof(allow), par->match->hooks)); return -EINVAL; } if (par->match->proto && (par->match->proto != proto || inv_proto)) { @@ -497,9 +527,13 @@ int xt_check_target(struct xt_tgchk_param *par, return -EINVAL; } if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { - printk("%s_tables: %s target: bad hook_mask %#x/%#x\n", + char used[64], allow[64]; + + printk("%s_tables: %s target: used from hooks %s, but only " + "usable from %s\n", xt_prefix[par->family], par->target->name, - par->hook_mask, par->target->hooks); + textify_hooks(used, sizeof(used), par->hook_mask), + textify_hooks(allow, sizeof(allow), par->target->hooks)); return -EINVAL; } if (par->target->proto && (par->target->proto != proto || inv_proto)) { -- cgit v0.10.2 From dd21ca6de703230785b755c8290365fc1640200e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 5 May 2009 23:22:01 +0000 Subject: bnx2x: free workqueue when driver fail to register Signed-off-by: Stanislaw Gruszka Acked-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index a669bb7..519e207 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11630,13 +11630,20 @@ static struct pci_driver bnx2x_pci_driver = { static int __init bnx2x_init(void) { + int ret; + bnx2x_wq = create_singlethread_workqueue("bnx2x"); if (bnx2x_wq == NULL) { printk(KERN_ERR PFX "Cannot create workqueue\n"); return -ENOMEM; } - return pci_register_driver(&bnx2x_pci_driver); + ret = pci_register_driver(&bnx2x_pci_driver); + if (ret) { + printk(KERN_ERR PFX "Cannot register driver\n"); + destroy_workqueue(bnx2x_wq); + } + return ret; } static void __exit bnx2x_cleanup(void) -- cgit v0.10.2 From 17cb4006bc40eea949f62adbbad99d8b980c0678 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 5 May 2009 23:22:12 +0000 Subject: bnx2x: do not return negative number of received packages Signed-off-by: Stanislaw Gruszka Acked-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 519e207..e01539c 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1546,7 +1546,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) len, cqe, comp_ring_cons); #ifdef BNX2X_STOP_ON_ERROR if (bp->panic) - return -EINVAL; + return 0; #endif bnx2x_update_sge_prod(fp, -- cgit v0.10.2 From 61de71c67caec39df0a854a1ef5be0c6be385c2a Mon Sep 17 00:00:00 2001 From: John Dykstra Date: Fri, 8 May 2009 14:57:01 -0700 Subject: Network Drop Monitor: Fix skb_kill_datagram Commit ead2ceb0ec9f85cff19c43b5cdb2f8a054484431 ("Network Drop Monitor: Adding kfree_skb_clean for non-drops and modifying end-of-line points for skbs") established new conventions for identifying dropped packets. Align skb_kill_datagram() with these conventions so that packets that get dropped just before the copy to userspace are properly tracked. Signed-off-by: John Dykstra Acked-by: Neil Horman Signed-off-by: David S. Miller diff --git a/net/core/datagram.c b/net/core/datagram.c index 22ea437..e2a36f0 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -260,7 +260,9 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) spin_unlock_bh(&sk->sk_receive_queue.lock); } - skb_free_datagram(sk, skb); + kfree_skb(skb); + sk_mem_reclaim_partial(sk); + return err; } -- cgit v0.10.2 From 7a2469ce4d8984722d65628969ad6f8b09da136f Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 8 May 2009 22:02:27 +0000 Subject: netxen: cache msi register offset Store msi target status register offset in adapter struct. This avoids contention on msi_tgt_status table from interrupt hadlers of different pci function. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 9350c86..ab11c2b 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1257,6 +1257,9 @@ struct netxen_adapter { u32 irq; u32 temp; + u32 msi_tgt_status; + u32 resv4; + struct netxen_adapter_stats stats; struct netxen_recv_context recv_ctx; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 83dadfd..edb4bcd 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -525,6 +525,8 @@ netxen_setup_intr(struct netxen_adapter *adapter) request_msi: if (use_msi && !pci_enable_msi(pdev)) { adapter->flags |= NETXEN_NIC_MSI_ENABLED; + adapter->msi_tgt_status = + msi_tgt_status[adapter->ahw.pci_func]; dev_info(&pdev->dev, "using msi interrupts\n"); } else dev_info(&pdev->dev, "using legacy interrupts\n"); @@ -1701,7 +1703,7 @@ static irqreturn_t netxen_msi_intr(int irq, void *data) /* clear interrupt */ adapter->pci_write_immediate(adapter, - msi_tgt_status[adapter->ahw.pci_func], 0xffffffff); + adapter->msi_tgt_status, 0xffffffff); napi_schedule(&sds_ring->napi); return IRQ_HANDLED; -- cgit v0.10.2 From be339aee634d5cb98a8df8d6febe04002ec497f3 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 8 May 2009 22:02:28 +0000 Subject: netxen: fix irq tear down and msix leak. o Fix the order of irq and hardware context teardown. Also synchronize the interrupt in dev close() before releasing tx buffers. o Fix possible msi-x vector leak if available vectors are less than requested. o Request multiple msix vectors only if hardware supports multiple rx queues. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index edb4bcd..c61c1d1 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -175,12 +175,6 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev) struct nx_host_sds_ring *sds_ring; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; - if ((adapter->flags & NETXEN_NIC_MSIX_ENABLED) && - adapter->rss_supported) - adapter->max_sds_rings = (num_online_cpus() >= 4) ? 4 : 2; - else - adapter->max_sds_rings = 1; - if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) return 1; @@ -216,8 +210,9 @@ netxen_napi_disable(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - netxen_nic_disable_int(sds_ring); napi_disable(&sds_ring->napi); + netxen_nic_disable_int(sds_ring); + synchronize_irq(sds_ring->irq); } } @@ -407,11 +402,11 @@ static void netxen_set_msix_bit(struct pci_dev *pdev, int enable) } } -static void netxen_init_msix_entries(struct netxen_adapter *adapter) +static void netxen_init_msix_entries(struct netxen_adapter *adapter, int count) { int i; - for (i = 0; i < MSIX_ENTRIES_PER_ADAPTER; i++) + for (i = 0; i < count; i++) adapter->msix_entries[i].entry = i; } @@ -496,6 +491,15 @@ netxen_setup_intr(struct netxen_adapter *adapter) { struct netxen_legacy_intr_set *legacy_intrp; struct pci_dev *pdev = adapter->pdev; + int err, num_msix; + + if (adapter->rss_supported) { + num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? + MSIX_ENTRIES_PER_ADAPTER : 2; + } else + num_msix = 1; + + adapter->max_sds_rings = 1; adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED); @@ -512,26 +516,35 @@ netxen_setup_intr(struct netxen_adapter *adapter) if (adapter->msix_supported) { - netxen_init_msix_entries(adapter); - if (pci_enable_msix(pdev, adapter->msix_entries, - MSIX_ENTRIES_PER_ADAPTER)) - goto request_msi; + netxen_init_msix_entries(adapter, num_msix); + err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); + if (err == 0) { + adapter->flags |= NETXEN_NIC_MSIX_ENABLED; + netxen_set_msix_bit(pdev, 1); - adapter->flags |= NETXEN_NIC_MSIX_ENABLED; - netxen_set_msix_bit(pdev, 1); - dev_info(&pdev->dev, "using msi-x interrupts\n"); + if (adapter->rss_supported) + adapter->max_sds_rings = num_msix; - } else { -request_msi: - if (use_msi && !pci_enable_msi(pdev)) { - adapter->flags |= NETXEN_NIC_MSI_ENABLED; - adapter->msi_tgt_status = - msi_tgt_status[adapter->ahw.pci_func]; - dev_info(&pdev->dev, "using msi interrupts\n"); - } else - dev_info(&pdev->dev, "using legacy interrupts\n"); - adapter->msix_entries[0].vector = pdev->irq; + dev_info(&pdev->dev, "using msi-x interrupts\n"); + return; + } + + if (err > 0) + pci_disable_msix(pdev); + + /* fall through for msi */ } + + if (use_msi && !pci_enable_msi(pdev)) { + adapter->flags |= NETXEN_NIC_MSI_ENABLED; + adapter->msi_tgt_status = + msi_tgt_status[adapter->ahw.pci_func]; + dev_info(&pdev->dev, "using msi interrupts\n"); + return; + } + + dev_info(&pdev->dev, "using legacy interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; } static void @@ -767,7 +780,7 @@ netxen_nic_request_irq(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - sprintf(sds_ring->name, "%16s[%d]", netdev->name, ring); + sprintf(sds_ring->name, "%s[%d]", netdev->name, ring); err = request_irq(sds_ring->irq, handler, flags, sds_ring->name, sds_ring); if (err) @@ -830,8 +843,6 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) { netif_carrier_off(netdev); netif_stop_queue(netdev); - smp_mb(); - netxen_napi_disable(adapter); if (adapter->stop_port) adapter->stop_port(adapter); @@ -839,6 +850,8 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_p3_free_mac_list(adapter); + netxen_napi_disable(adapter); + netxen_release_tx_buffers(adapter); FLUSH_SCHEDULED_WORK(); @@ -917,10 +930,9 @@ err_out_free_sw: static void netxen_nic_detach(struct netxen_adapter *adapter) { - netxen_nic_free_irq(adapter); - netxen_release_rx_buffers(adapter); netxen_free_hw_resources(adapter); + netxen_nic_free_irq(adapter); netxen_free_sw_resources(adapter); adapter->is_up = 0; -- cgit v0.10.2 From b0b3a75b36afe3b1ed2c12b8817b6326db8ed003 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 8 May 2009 22:02:29 +0000 Subject: netxen: disable msi-x for NC512m adapter This board doesn't suppot msi-x well due to msi-x table mapping (hardware) issue. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index c61c1d1..86ca081 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -292,7 +292,6 @@ static void netxen_check_options(struct netxen_adapter *adapter) switch (adapter->ahw.board_type) { case NETXEN_BRDTYPE_P2_SB31_10G: case NETXEN_BRDTYPE_P2_SB31_10G_CX4: - case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ: adapter->msix_supported = !!use_msi_x; adapter->rss_supported = !!use_msi_x; break; -- cgit v0.10.2 From 23b6cc425d718fce2501d5f60e368cfa44ef7d86 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 8 May 2009 22:02:30 +0000 Subject: netxen: trivial register access cleanup Remove unnecessary length parameter since it's always 4 bytes. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 86c9e78..42ffb825 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -914,17 +914,15 @@ netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, u32 wndw) * In: 'off' is offset from base in 128M pci map */ static int -netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, - ulong *off, int len) +netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, ulong *off) { - unsigned long end = *off + len; crb_128M_2M_sub_block_map_t *m; if (*off >= NETXEN_CRB_MAX) return -1; - if (*off >= NETXEN_PCI_CAMQM && (end <= NETXEN_PCI_CAMQM_2M_END)) { + if (*off >= NETXEN_PCI_CAMQM && (*off < NETXEN_PCI_CAMQM_2M_END)) { *off = (*off - NETXEN_PCI_CAMQM) + NETXEN_PCI_CAMQM_2M_BASE + (ulong)adapter->ahw.pci_base0; return 0; @@ -934,14 +932,13 @@ netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, return -1; *off -= NETXEN_PCI_CRBSPACE; - end = *off + len; /* * Try direct map */ m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; - if (m->valid && (m->start_128M <= *off) && (m->end_128M >= end)) { + if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { *off = *off + m->start_2M - m->start_128M + (ulong)adapter->ahw.pci_base0; return 0; @@ -1036,7 +1033,7 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data) unsigned long flags = 0; int rv; - rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, 4); + rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off); if (rv == -1) { printk(KERN_ERR "%s: invalid offset: 0x%016lx\n", @@ -1066,7 +1063,7 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) int rv; u32 data; - rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, 4); + rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off); if (rv == -1) { printk(KERN_ERR "%s: invalid offset: 0x%016lx\n", -- cgit v0.10.2 From 9948bb6a6db6ad6a8bf2ccaaceb780404f1f43df Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 8 May 2009 06:30:25 +0000 Subject: decnet: Use data ready call back, rather than hand coding it Signed-off-by: Steven Whitehouse Signed-off-by: David S. Miller diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 5d8a2a5..932408d 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -578,6 +578,7 @@ out: static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue) { int err; + int skb_len; /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK @@ -592,22 +593,12 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig if (err) goto out; + skb_len = skb->len; skb_set_owner_r(skb, sk); skb_queue_tail(queue, skb); - /* This code only runs from BH or BH protected context. - * Therefore the plain read_lock is ok here. -DaveM - */ - read_lock(&sk->sk_callback_lock); - if (!sock_flag(sk, SOCK_DEAD)) { - struct socket *sock = sk->sk_socket; - wake_up_interruptible(sk->sk_sleep); - if (sock && sock->fasync_list && - !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) - __kill_fasync(sock->fasync_list, sig, - (sig == SIGURG) ? POLL_PRI : POLL_IN); - } - read_unlock(&sk->sk_callback_lock); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb_len); out: return err; } -- cgit v0.10.2 From ab9c73ccb52f40576ce017528d542eda3c6ae766 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 8 May 2009 13:30:17 +0000 Subject: net: check retval of dev_addr_init() Add missed checking of dev_addr_init return value in alloc_netdev_mq. Signed-off-by: Jiri Pirko net/core/dev.c | 15 ++++++++++++--- 1 files changed, 12 insertions(+), 3 deletions(-) Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 637ea71..14dd725 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5007,13 +5007,16 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, if (!tx) { printk(KERN_ERR "alloc_netdev: Unable to allocate " "tx qdiscs.\n"); - kfree(p); - return NULL; + goto free_p; } dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); dev->padded = (char *)dev - (char *)p; + + if (dev_addr_init(dev)) + goto free_tx; + dev_net_set(dev, &init_net); dev->_tx = tx; @@ -5022,13 +5025,19 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev->gso_max_size = GSO_MAX_SIZE; - dev_addr_init(dev); netdev_init_queues(dev); INIT_LIST_HEAD(&dev->napi_list); setup(dev); strcpy(dev->name, name); return dev; + +free_tx: + kfree(tx); + +free_p: + kfree(p); + return NULL; } EXPORT_SYMBOL(alloc_netdev_mq); -- cgit v0.10.2 From ed9b58bc443a1210b5be1ded6421b17e015bf985 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Sat, 9 May 2009 06:59:16 +0000 Subject: Remove duplicate slow protocol define in bond_3ad.h ETH_P_SLOW is already defined in include/linux/if_ether.h. There's no need to define BOND_ETH_P_LACPDU in drivers/net/bonding/bond_3ad.h Signed-off-by: Richard Genoud Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index a306230..2c46a154 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -26,10 +26,10 @@ #include #include #include +#include // General definitions -#define BOND_ETH_P_LACPDU 0x8809 -#define PKT_TYPE_LACPDU cpu_to_be16(BOND_ETH_P_LACPDU) +#define PKT_TYPE_LACPDU cpu_to_be16(ETH_P_SLOW) #define AD_TIMER_INTERVAL 100 /*msec*/ #define MULTICAST_LACPDU_ADDR {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02} -- cgit v0.10.2 From 980c9e8ceeb69ac4c921173d0d06323f5c678647 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 9 May 2009 22:54:21 -0700 Subject: tun: add tun_flags, owner, group attributes in sysfs This patch adds three attribute files in /sys/class/net/$dev/ for tun devices; allowing userspace to obtain the information which TUNGETIFF offers, and more, but without having to attach to the device in question (which may not be possible if it's in use). It also fixes a bug which has been present in the TUNGETIFF ioctl since its inception, where it would never set IFF_TUN or IFF_TAP according to the device type. (Look carefully at the code which I remove from tun_get_iff() and how the new tun_flags() helper is subtly different). Signed-off-by: David Woodhouse Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 94622e5..4cda69b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -865,6 +865,52 @@ static struct proto tun_proto = { .obj_size = sizeof(struct tun_sock), }; +static int tun_flags(struct tun_struct *tun) +{ + int flags = 0; + + if (tun->flags & TUN_TUN_DEV) + flags |= IFF_TUN; + else + flags |= IFF_TAP; + + if (tun->flags & TUN_NO_PI) + flags |= IFF_NO_PI; + + if (tun->flags & TUN_ONE_QUEUE) + flags |= IFF_ONE_QUEUE; + + if (tun->flags & TUN_VNET_HDR) + flags |= IFF_VNET_HDR; + + return flags; +} + +static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tun_struct *tun = netdev_priv(to_net_dev(dev)); + return sprintf(buf, "0x%x\n", tun_flags(tun)); +} + +static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tun_struct *tun = netdev_priv(to_net_dev(dev)); + return sprintf(buf, "%d\n", tun->owner); +} + +static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tun_struct *tun = netdev_priv(to_net_dev(dev)); + return sprintf(buf, "%d\n", tun->group); +} + +static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); +static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL); +static DEVICE_ATTR(group, 0444, tun_show_group, NULL); + static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) { struct sock *sk; @@ -950,6 +996,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (err < 0) goto err_free_sk; + if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) || + device_create_file(&tun->dev->dev, &dev_attr_owner) || + device_create_file(&tun->dev->dev, &dev_attr_group)) + printk(KERN_ERR "Failed to create tun sysfs files\n"); + sk->sk_destruct = tun_sock_destruct; err = tun_attach(tun, file); @@ -1002,21 +1053,7 @@ static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) strcpy(ifr->ifr_name, tun->dev->name); - ifr->ifr_flags = 0; - - if (ifr->ifr_flags & TUN_TUN_DEV) - ifr->ifr_flags |= IFF_TUN; - else - ifr->ifr_flags |= IFF_TAP; - - if (tun->flags & TUN_NO_PI) - ifr->ifr_flags |= IFF_NO_PI; - - if (tun->flags & TUN_ONE_QUEUE) - ifr->ifr_flags |= IFF_ONE_QUEUE; - - if (tun->flags & TUN_VNET_HDR) - ifr->ifr_flags |= IFF_VNET_HDR; + ifr->ifr_flags = tun_flags(tun); tun_put(tun); return 0; -- cgit v0.10.2 From dc6382ced07d6bad61d0b591fb12ab5da7ca632c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 6 May 2009 22:09:37 +0300 Subject: nl80211 : Add support for configuring MFP NL80211_CMD_ASSOCIATE request must be able to indicate whether management frame protection (IEEE 802.11w) is being used. mac80211 was able to use MFP in client mode only with WEXT, but the new NL80211_ATTR_USE_MFP attribute will allow this to be done with nl80211, too. Since we are currently using nl80211 for MFP only with drivers that use user space SME, only MFP disabled and required values are used. However, the NL80211_ATTR_USE_MFP attribute is an enum that can be extended with MFP optional in the future, if that is needed with some drivers (e.g., if the RSN IE is generated by the driver). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index e9fd13a..58c4ee1 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -494,6 +494,11 @@ enum nl80211_commands { * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this * is used, e.g., with %NL80211_CMD_AUTHENTICATE event * + * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is + * used for the association (&enum nl80211_mfp, represented as a u32); + * this attribute can be used + * with %NL80211_CMD_ASSOCIATE request + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -596,6 +601,8 @@ enum nl80211_attrs { NL80211_ATTR_TIMED_OUT, + NL80211_ATTR_USE_MFP, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1179,4 +1186,14 @@ enum nl80211_key_type { NL80211_KEYTYPE_PEERKEY, }; +/** + * enum nl80211_mfp - Management frame protection state + * @NL80211_MFP_NO: Management frame protection not used + * @NL80211_MFP_REQUIRED: Management frame protection required + */ +enum nl80211_mfp { + NL80211_MFP_NO, + NL80211_MFP_REQUIRED, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b8a7676..47e30e1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -672,6 +672,7 @@ struct cfg80211_auth_request { * @ssid_len: Length of ssid in octets * @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie_len: Length of ie buffer in octets + * @use_mfp: Use management frame protection (IEEE 802.11w) in this association */ struct cfg80211_assoc_request { struct ieee80211_channel *chan; @@ -680,6 +681,7 @@ struct cfg80211_assoc_request { size_t ssid_len; const u8 *ie; size_t ie_len; + bool use_mfp; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d0ca6da..4e627cf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1253,6 +1253,14 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, if (ret) return ret; + if (req->use_mfp) { + sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; + sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; + } else { + sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; + sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; + } + sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; ieee80211_sta_req_auth(sdata); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3c53c5c..7992770 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -122,6 +122,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, + [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, }; /* IE validation */ @@ -3012,6 +3013,17 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } + if (info->attrs[NL80211_ATTR_USE_MFP]) { + enum nl80211_mfp use_mfp = + nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); + if (use_mfp == NL80211_MFP_REQUIRED) + req.use_mfp = true; + else if (use_mfp != NL80211_MFP_NO) { + err = -EINVAL; + goto out; + } + } + err = drv->ops->assoc(&drv->wiphy, dev, &req); out: -- cgit v0.10.2 From 02018b39a75057541c7946a9173561d1a76a0bfe Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 6 May 2009 22:35:58 +0200 Subject: wireless: WL12XX should depend on GENERIC_HARDIRQS m68k allmodconfig: | drivers/net/wireless/wl12xx/main.c: In function 'wl12xx_probe': | drivers/net/wireless/wl12xx/main.c:1273: error: implicit declaration of function 'set_irq_type' | make[1]: *** [drivers/net/wireless/wl12xx/main.o] Error 1 Signed-off-by: Geert Uytterhoeven Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 20a9633..a82c4cd 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -1,6 +1,6 @@ config WL12XX tristate "TI wl1251/wl1271 support" - depends on MAC80211 && WLAN_80211 && SPI_MASTER && EXPERIMENTAL + depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL select FW_LOADER select CRC7 ---help--- -- cgit v0.10.2 From 58905ca5b11a0ff3860f55b789cbbf052f7158a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 May 2009 14:23:01 +0200 Subject: mac80211: fix scan channel race When a software scan starts, it first sets sw_scanning, but leaves the scan_channel "unset" (it currently actually gets initialised to a default). Now, when something else tries to (re)configure the hardware in the window between these two events (after sw_scanning = true, but before scan_channel is set), the current code switches to the (unset!) scan_channel. This causes trouble, especially when switching bands and sending frames on the wrong channel. To work around this, leave scan_channel initialised to NULL and use it to determine whether or not a switch to a different channel should occur (and also use the same condition to check whether to adjust power for scan or not). Additionally, avoid reconfiguring the hardware completely when recalculating idle resulted in no changes, this was the problem that originally led us to discover the race condition in the first place, which was helpfully bisected by Pavel. This part of the patch should not be necessary with the other fixes, but not calling the ieee80211_hw_config function when we know it to be unnecessary is certainly a correct thing to do. Unfortunately, this patch cannot and does not fix the race condition completely, but due to the way the scan code is structured it makes the particular problem Pavel discovered (race while changing channel at the same time as transmitting frames) go away. To fix it completely, more work especially with locking configuration is needed. Bisected-by: Pavel Roskin Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8b6daf0..8c9f1c7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -964,5 +964,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local) mutex_lock(&local->iflist_mtx); chg = __ieee80211_recalc_idle(local); mutex_unlock(&local->iflist_mtx); - ieee80211_hw_config(local, chg); + if (chg) + ieee80211_hw_config(local, chg); } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b80bc80..76df5ea 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -154,15 +154,17 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev) int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { - struct ieee80211_channel *chan; + struct ieee80211_channel *chan, *scan_chan; int ret = 0; int power; enum nl80211_channel_type channel_type; might_sleep(); - if (local->sw_scanning) { - chan = local->scan_channel; + scan_chan = local->scan_channel; + + if (scan_chan) { + chan = scan_chan; channel_type = NL80211_CHAN_NO_HT; } else { chan = local->oper_channel; @@ -176,7 +178,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) changed |= IEEE80211_CONF_CHANGE_CHANNEL; } - if (local->sw_scanning) + if (scan_chan) power = chan->max_power; else power = local->power_constr_level ? @@ -859,8 +861,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (!local->oper_channel) { /* init channel we're on */ local->hw.conf.channel = - local->oper_channel = - local->scan_channel = &sband->channels[0]; + local->oper_channel = &sband->channels[0]; + local->hw.conf.channel_type = NL80211_CHAN_NO_HT; } channels += sband->n_channels; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index c99ef8d..e51b99b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -298,6 +298,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) was_hw_scan = local->hw_scanning; local->hw_scanning = false; local->sw_scanning = false; + local->scan_channel = NULL; /* we only have to protect scan_req and hw/sw scan */ mutex_unlock(&local->scan_mtx); -- cgit v0.10.2 From aa837e1d6bd1a71b3c30c7738b6c29d41512fe7d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 May 2009 16:16:24 +0200 Subject: mac80211: set default QoS values according to spec We've never really cared about the default QoS (WMM) values, but we really should if the AP doesn't send any. This patch makes mac80211 use the default values according to 802.11-2007, and additionally syncs the default values when we disassociate so whatever the last AP said gets "unconfigured". Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 75c487229..c5445ba 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1043,6 +1043,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); + ieee80211_set_wmm_default(sdata); + ieee80211_recalc_idle(local); /* channel(_type) changes are handled by ieee80211_hw_config */ @@ -1658,6 +1660,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (elems.wmm_param) ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, elems.wmm_param_len); + else + ieee80211_set_wmm_default(sdata); if (elems.ht_info_elem && elems.wmm_param && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 97b613a..0689a8f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -708,26 +708,62 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_tx_queue_params qparam; - int i; + int queue; + bool use_11b; + int aCWmin, aCWmax; if (!local->ops->conf_tx) return; memset(&qparam, 0, sizeof(qparam)); - qparam.aifs = 2; - - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && - !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) - qparam.cw_min = 31; - else - qparam.cw_min = 15; + use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && + !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); - qparam.cw_max = 1023; - qparam.txop = 0; + for (queue = 0; queue < local_to_hw(local)->queues; queue++) { + /* Set defaults according to 802.11-2007 Table 7-37 */ + aCWmax = 1023; + if (use_11b) + aCWmin = 31; + else + aCWmin = 15; + + switch (queue) { + case 3: /* AC_BK */ + qparam.cw_max = aCWmin; + qparam.cw_min = aCWmax; + qparam.txop = 0; + qparam.aifs = 7; + break; + default: /* never happens but let's not leave undefined */ + case 2: /* AC_BE */ + qparam.cw_max = aCWmin; + qparam.cw_min = aCWmax; + qparam.txop = 0; + qparam.aifs = 3; + break; + case 1: /* AC_VI */ + qparam.cw_max = aCWmin; + qparam.cw_min = (aCWmin + 1) / 2 - 1; + if (use_11b) + qparam.txop = 6016/32; + else + qparam.txop = 3008/32; + qparam.aifs = 2; + break; + case 0: /* AC_VO */ + qparam.cw_max = (aCWmin + 1) / 2 - 1; + qparam.cw_min = (aCWmin + 1) / 4 - 1; + if (use_11b) + qparam.txop = 3264/32; + else + qparam.txop = 1504/32; + qparam.aifs = 2; + break; + } - for (i = 0; i < local_to_hw(local)->queues; i++) - drv_conf_tx(local, i, &qparam); + drv_conf_tx(local, queue, &qparam); + } } void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, -- cgit v0.10.2 From 0b258582fef3a9b15b2372d99164859361faa8db Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 09:42:33 +0200 Subject: cfg80211: fix wext iw_freq parsing The function to parse a struct iw_freq has a stupid bug, it returns NULL when the channel cannot be found at all, but NULL is supposed to mean "auto". Fix this by checking the return value of ieee80211_get_channel() and returning ERR_PTR(-EINVAL) if it returned NULL (channel not found). This fixes an issue where you could say (in IBSS mode) iwconfig wlan0 channel 21 and it would use channel 1 instead because that's the first available channel with IBSS allowed (which is what the "auto" setting uses). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 5ef82f2..abf6b0a 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -296,22 +296,34 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) { + struct ieee80211_channel *chan; + int f; + + /* + * Parse frequency - return NULL for auto and + * -EINVAL for impossible things. + */ if (freq->e == 0) { if (freq->m < 0) return NULL; - else - return ieee80211_get_channel(wiphy, - ieee80211_channel_to_frequency(freq->m)); + f = ieee80211_channel_to_frequency(freq->m); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; - if (div > 0) - return ieee80211_get_channel(wiphy, freq->m / div); - else + if (div <= 0) return ERR_PTR(-EINVAL); + f = freq->m / div; } + /* + * Look up channel struct and return -EINVAL when + * it cannot be found. + */ + chan = ieee80211_get_channel(wiphy, f); + if (!chan) + return ERR_PTR(-EINVAL); + return chan; } EXPORT_SYMBOL_GPL(cfg80211_wext_freq); -- cgit v0.10.2 From 782571f46fc7d2bbb0288ab0d676c47a88449a5c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 19:31:42 +0200 Subject: iwlwifi: make iwl_set_rate static It's not needed outside iwl-core.c Signed-off-by: Johannes Berg Acked-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1366222..77f4b43 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1120,7 +1120,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) } EXPORT_SYMBOL(iwl_connection_init_rx_config); -void iwl_set_rate(struct iwl_priv *priv) +static void iwl_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; @@ -1166,7 +1166,6 @@ void iwl_set_rate(struct iwl_priv *priv) priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -EXPORT_SYMBOL(iwl_set_rate); void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index bd7f9d9..f3544ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -363,8 +363,6 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv); -void iwl_set_rate(struct iwl_priv *priv); - u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx); static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) -- cgit v0.10.2 From 0c7c10c7cc6bc890d23c8c62b81b4feccd92124b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 8 May 2009 12:34:10 +0300 Subject: mac80211: Drop unencrypted frames based on key setup When using nl80211, we do not have a mechanism to set sdata->drop_unencrypted. Currently, this breaks code that is supposed to drop unencrypted frames when protection is expected since ieee80211_rx_h_decrypt() is optimized to not set rx->key when the frame is not protected. This patch modifies ieee80211_rx_h_decrypt() to set rx->key for all frames and only skip decryption if the frame is not protected. This allows ieee80211_drop_unencrypted() to correctly drop frames even if drop_unencrypted is not set. The changes here are not enough to handle all cases, though. Additional patches will be needed to implement proper IEEE 802.1X PAE for station mode (currently, this is only used for AP mode) and some additional rules are needed for MFP to drop unprotected Robust Action frames prior to having PTK and IGTK configured. In theory, the unprotected frames could and should be dropped in ieee80211_rx_h_decrypt(). However, due to the special case with EAPOL frames that have to be allowed to be received unprotected even when keys are set, it is simpler to only set rx->key and allow the ieee80211_frame_allowed() function to handle the actual dropping of data frames after 802.11->802.3 header conversion. In addition, unprotected robust management frames are dropped before they are processed. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d052f40..bf21e92 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -630,15 +630,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) * possible. */ - if (!ieee80211_has_protected(hdr->frame_control)) { - if (!ieee80211_is_mgmt(hdr->frame_control) || - rx->sta == NULL || !test_sta_flags(rx->sta, WLAN_STA_MFP)) - return RX_CONTINUE; - mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); - if (mmie_keyidx < 0) - return RX_CONTINUE; - } - /* * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. @@ -649,8 +640,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (rx->sta) stakey = rcu_dereference(rx->sta->key); + if (!ieee80211_has_protected(hdr->frame_control)) + mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); + if (!is_multicast_ether_addr(hdr->addr1) && stakey) { rx->key = stakey; + /* Skip decryption if the frame is not protected. */ + if (!ieee80211_has_protected(hdr->frame_control)) + return RX_CONTINUE; } else if (mmie_keyidx >= 0) { /* Broadcast/multicast robust management frame / BIP */ if ((rx->status->flag & RX_FLAG_DECRYPTED) && @@ -661,6 +658,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) return RX_DROP_MONITOR; /* unexpected BIP keyidx */ rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); + } else if (!ieee80211_has_protected(hdr->frame_control)) { + /* + * The frame was not protected, so skip decryption. However, we + * need to set rx->key if there is a key that could have been + * used so that the frame may be dropped if encryption would + * have been expected. + */ + struct ieee80211_key *key = NULL; + if (ieee80211_is_mgmt(hdr->frame_control) && + is_multicast_ether_addr(hdr->addr1) && + (key = rcu_dereference(rx->sdata->default_mgmt_key))) + rx->key = key; + else if ((key = rcu_dereference(rx->sdata->default_key))) + rx->key = key; + return RX_CONTINUE; } else { /* * The device doesn't give us the IV so we won't be -- cgit v0.10.2 From f2ca3ea484a51dc7ea5b738510fd03cb6ca7e2e2 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 8 May 2009 12:36:03 +0300 Subject: mac80211: MFP - Drop unprotected Action frames prior key setup When management frame protection (IEEE 802.11w) is used, unprotected Robust Action frames are not allowed prior to key configuration. However, unprotected Deauthentication and Disassociation frames are allowed at that point, but not after key configuration. Make ieee80211_drop_unencrypted() handle the special cases for MFP by separating the basic Data frame case from Management frame processing and handle the Management frames only if MFP has been negotiated. In addition, do not use sdata->drop_unencrypted for Management frames since the decision on whether to accept the frame depends on the key being configured. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bf21e92..f962bd1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1221,17 +1221,27 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) /* Drop unencrypted frames if key is set. */ if (unlikely(!ieee80211_has_protected(fc) && !ieee80211_is_nullfunc(fc) && - (!ieee80211_is_mgmt(fc) || - (ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && - rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP))) && - (rx->key || rx->sdata->drop_unencrypted))) - return -EACCES; - /* BIP does not use Protected field, so need to check MMIE */ - if (unlikely(rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP) && - ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && - ieee80211_get_mmie_keyidx(rx->skb) < 0 && + ieee80211_is_data(fc) && (rx->key || rx->sdata->drop_unencrypted))) return -EACCES; + if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { + if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && + rx->key)) + return -EACCES; + /* BIP does not use Protected field, so need to check MMIE */ + if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) + && ieee80211_get_mmie_keyidx(rx->skb) < 0 && + rx->key)) + return -EACCES; + /* + * When using MFP, Action frames are not allowed prior to + * having configured keys. + */ + if (unlikely(ieee80211_is_action(fc) && !rx->key && + ieee80211_is_robust_mgmt_frame( + (struct ieee80211_hdr *) rx->skb->data))) + return -EACCES; + } return 0; } -- cgit v0.10.2 From 99c84cb0692729088788d8e1d1cee670154176e4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 14:12:21 +0200 Subject: mac80211: improve scan timing The call to ieee80211_hw_config() is supposed to apply changes synchronously, so once it returns the parameters are applied to the hardware. Thus, there really is no need to delay the probing by the channel switch time again since the channel switch has already happened once we get to this code. Additionally, there is no need to wait for a NAV update (probe delay) when the channel is passively scanned. Remove that extra time too. This cuts scanning time from over 7 seconds to under 4 on ar9170, which is due to the number of channels scanned and ar9170's switch time being advertised as 135ms (my test now indicates it is about 77ms with the current driver, but the difference might also be due to using a different machine with different USB controllers). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e51b99b..e65d74b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -559,24 +559,39 @@ void ieee80211_scan_work(struct work_struct *work) if (skip) break; - next_delay = IEEE80211_PROBE_DELAY + - usecs_to_jiffies(local->hw.channel_change_time); + /* + * Probe delay is used to update the NAV, cf. 11.1.3.2.2 + * (which unfortunately doesn't say _why_ step a) is done, + * but it waits for the probe delay or until a frame is + * received - and the received frame would update the NAV). + * For now, we do not support waiting until a frame is + * received. + * + * In any case, it is not necessary for a passive scan. + */ + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + !local->scan_req->n_ssids) { + next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + break; + } + + next_delay = IEEE80211_PROBE_DELAY; local->scan_state = SCAN_SEND_PROBE; break; case SCAN_SEND_PROBE: - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; - - if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN || - !local->scan_req->n_ssids) - break; for (i = 0; i < local->scan_req->n_ssids; i++) ieee80211_send_probe_req( sdata, NULL, local->scan_req->ssids[i].ssid, local->scan_req->ssids[i].ssid_len, local->scan_req->ie, local->scan_req->ie_len); + + /* + * After sending probe requests, wait for probe responses + * on the channel. + */ next_delay = IEEE80211_CHANNEL_TIME; + local->scan_state = SCAN_SET_CHANNEL; break; } -- cgit v0.10.2 From 5a9940118a616266183c53a9ee4352feadb9c2e8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 8 May 2009 18:30:43 +0200 Subject: rt2x00: Fix chipset detection for rt73usb The lower 4 bytes of the chipset revision must contain a non-zero value. This bug was introduced by "rt2x00: Simplify rt2x00_check_rev". Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d10af36..270dd4e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1847,7 +1847,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_chip(rt2x00dev, RT2571, value, reg); if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || - !rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { + rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } -- cgit v0.10.2 From 9ed6bcce77f75d98af6ee07069deac6041948bee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 20:47:39 +0200 Subject: mac80211: move HT operation mode BSS info There really is no need to have a separate struct for a single variable. The fact that it exists is due to the code legacy, but we can remove that now. Very simple. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 77f4b43..a9a4fce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2225,9 +2225,9 @@ static void iwl_ht_conf(struct iwl_priv *priv, iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = - bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; + bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = - !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); rcu_read_unlock(); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b1213b6..61a4ad7 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -642,7 +642,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_HT) { printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n", wiphy_name(hw->wiphy), - info->ht.operation_mode); + info->ht_operation_mode); } if (changed & BSS_CHANGED_BASIC_RATES) { diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 46b288d..a263d5c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2369,7 +2369,7 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, if (info->use_cts_prot) { prot_mode = MWL8K_FRAME_PROT_11G; } else { - switch (info->ht.operation_mode & + switch (info->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION) { case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 38dc1cd..03591fc 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -171,14 +171,6 @@ enum ieee80211_bss_change { }; /** - * struct ieee80211_bss_ht_conf - BSS's changing HT configuration - * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info) - */ -struct ieee80211_bss_ht_conf { - u16 operation_mode; -}; - -/** * struct ieee80211_bss_conf - holds the BSS's changing parameters * * This structure keeps information about a BSS (and an association @@ -203,6 +195,8 @@ struct ieee80211_bss_ht_conf { * the current band. * @bssid: The BSSID for this BSS * @enable_beacon: whether beaconing should be enabled or not + * @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info). + * This field is only valid when the channel type is one of the HT types. */ struct ieee80211_bss_conf { const u8 *bssid; @@ -219,7 +213,7 @@ struct ieee80211_bss_conf { u16 assoc_capability; u64 timestamp; u32 basic_rates; - struct ieee80211_bss_ht_conf ht; + u16 ht_operation_mode; }; /** diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c5445ba..a1f2332 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -95,16 +95,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss_ht_conf ht; struct sta_info *sta; u32 changed = 0; + u16 ht_opmode; bool enable_ht = true, ht_changed; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - memset(&ht, 0, sizeof(ht)); - /* HT is not supported */ if (!sband->ht_cap.ht_supported) enable_ht = false; @@ -148,19 +146,18 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, IEEE80211_RC_HT_CHANGED); rcu_read_unlock(); - } /* disable HT */ if (!enable_ht) return 0; - ht.operation_mode = le16_to_cpu(hti->operation_mode); + ht_opmode = le16_to_cpu(hti->operation_mode); /* if bss configuration changed store the new one */ - if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) { + if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { changed |= BSS_CHANGED_HT; - sdata->vif.bss_conf.ht = ht; + sdata->vif.bss_conf.ht_operation_mode = ht_opmode; } return changed; -- cgit v0.10.2 From 413ad50a5c15f3bae8075c15b101679f05c37a69 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 21:21:06 +0200 Subject: mac80211: properly track HT operation_mode When we disassociate, we set the channel to non-HT which obviously invalidates any ht_operation_mode setting. But when we then associate with the next AP again, we might still have the ht_operation_mode from the previous AP cached and fail to configure the hardware with the new (but unchanged) operation mode. This patch fixes it by separately tracking whether our cache is valid. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 03e0d22..081c574 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -427,6 +427,12 @@ struct ieee80211_sub_if_data { int drop_unencrypted; + /* + * keep track of whether the HT opmode (stored in + * vif.bss_info.ht_operation_mode) is valid. + */ + bool ht_opmode_valid; + /* Fragment table for host-based reassembly */ struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; unsigned int fragment_next; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a1f2332..6d00e3f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -155,9 +155,11 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, ht_opmode = le16_to_cpu(hti->operation_mode); /* if bss configuration changed store the new one */ - if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { + if (!sdata->ht_opmode_valid || + sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { changed |= BSS_CHANGED_HT; sdata->vif.bss_conf.ht_operation_mode = ht_opmode; + sdata->ht_opmode_valid = true; } return changed; @@ -1047,6 +1049,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, /* channel(_type) changes are handled by ieee80211_hw_config */ local->oper_channel_type = NL80211_CHAN_NO_HT; + /* on the next assoc, re-program HT parameters */ + sdata->ht_opmode_valid = false; + local->power_constr_level = 0; del_timer_sync(&local->dynamic_ps_timer); -- cgit v0.10.2 From 44033f80cefd1d7b474efdabc412476d4bafb8f4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 21:21:41 +0200 Subject: mac80211: remove ieee80211_ht_bss_info This struct is no longer used (and hasn't been for a while). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 03591fc..d10ed17 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -73,22 +73,6 @@ */ /** - * struct ieee80211_ht_bss_info - describing BSS's HT characteristics - * - * This structure describes most essential parameters needed - * to describe 802.11n HT characteristics in a BSS. - * - * @primary_channel: channel number of primery channel - * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width) - * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection) - */ -struct ieee80211_ht_bss_info { - u8 primary_channel; - u8 bss_cap; /* use IEEE80211_HT_IE_CHA_ */ - u8 bss_op_mode; /* use IEEE80211_HT_IE_ */ -}; - -/** * enum ieee80211_max_queues - maximum number of queues * * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. -- cgit v0.10.2 From 19cc10870ece942d287241937944c237130f50f4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 13:44:36 -0700 Subject: iwlwifi: do proper hw restart When the microcode fails for any reason, ask mac80211 to recover instead of trying ourselves and failing at it. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6cdee0b..43bc8a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -190,8 +190,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) priv->cfg->ops->smgmt->clear_station_table(priv); - if (!priv->error_recovering) - priv->start_calib = 0; + priv->start_calib = 0; /* Add the broadcast address so we can send broadcast frames */ if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == @@ -967,23 +966,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -static void iwl_error_recovery(struct iwl_priv *priv) -{ - unsigned long flags; - - memcpy(&priv->staging_rxon, &priv->recovery_rxon, - sizeof(priv->staging_rxon)); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - - iwl_rxon_add_station(priv, priv->bssid, 1); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); - priv->error_recovering = 0; - spin_unlock_irqrestore(&priv->lock, flags); -} - static void iwl_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; @@ -1514,9 +1496,6 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - if (priv->error_recovering) - iwl_error_recovery(priv); - iwl_power_update_mode(priv, 1); /* reassociate for ADHOC mode */ @@ -1715,9 +1694,6 @@ static int __iwl_up(struct iwl_priv *priv) continue; } - /* Clear out the uCode error bit if it is set */ - clear_bit(STATUS_FW_ERROR, &priv->status); - /* start card; "initialize" will load runtime ucode */ iwl_nic_start(priv); @@ -1812,8 +1788,17 @@ static void iwl_bg_restart(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl_down(priv); - queue_work(priv->workqueue, &priv->up); + if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { + mutex_lock(&priv->mutex); + priv->vif = NULL; + priv->is_open = 0; + mutex_unlock(&priv->mutex); + iwl_down(priv); + ieee80211_restart_hw(priv->hw); + } else { + iwl_down(priv); + queue_work(priv->workqueue, &priv->up); + } } static void iwl_bg_rx_replenish(struct work_struct *data) @@ -2007,10 +1992,8 @@ static void iwl_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "enter\n"); - if (!priv->is_open) { - IWL_DEBUG_MAC80211(priv, "leave - skip\n"); + if (!priv->is_open) return; - } priv->is_open = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a9a4fce..aa1e1dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1229,11 +1229,6 @@ void iwl_irq_handle_error(struct iwl_priv *priv) IWL_DEBUG(priv, IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); - if (iwl_is_associated(priv)) { - memcpy(&priv->recovery_rxon, &priv->active_rxon, - sizeof(priv->recovery_rxon)); - priv->error_recovering = 1; - } if (priv->cfg->mod_params->restart_fw) queue_work(priv->workqueue, &priv->restart); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5aa76a7..0f2c1b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -933,7 +933,6 @@ struct iwl_priv { const struct iwl_rxon_cmd active_rxon; struct iwl_rxon_cmd staging_rxon; - int error_recovering; struct iwl_rxon_cmd recovery_rxon; /* 1st responses from initialize and runtime uCode images. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f6c1489..271e5d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1837,23 +1837,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) iwl_release_nic_access(priv); } -static void iwl3945_error_recovery(struct iwl_priv *priv) -{ - unsigned long flags; - - memcpy(&priv->staging_rxon, &priv->recovery_rxon, - sizeof(priv->staging_rxon)); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv); - - priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 1, 0, NULL); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); - priv->error_recovering = 0; - spin_unlock_irqrestore(&priv->lock, flags); -} - static void iwl3945_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; @@ -2683,9 +2666,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv) /* After the ALIVE response, we can send commands to 3945 uCode */ set_bit(STATUS_ALIVE, &priv->status); - /* Clear out the uCode error bit if it is set */ - clear_bit(STATUS_FW_ERROR, &priv->status); - if (iwl_is_rfkill(priv)) return; @@ -2722,9 +2702,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - if (priv->error_recovering) - iwl3945_error_recovery(priv); - /* reassociate for ADHOC mode */ if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, @@ -3231,8 +3208,17 @@ static void iwl3945_bg_restart(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl3945_down(priv); - queue_work(priv->workqueue, &priv->up); + if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { + mutex_lock(&priv->mutex); + priv->vif = NULL; + priv->is_open = 0; + mutex_unlock(&priv->mutex); + iwl3945_down(priv); + ieee80211_restart_hw(priv->hw); + } else { + iwl3945_down(priv); + queue_work(priv->workqueue, &priv->up); + } } static void iwl3945_bg_rx_replenish(struct work_struct *data) -- cgit v0.10.2 From f0f74a0e65a69d4cc579e60f76a30b38ad7dbe06 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 13:44:37 -0700 Subject: iwlwifi: fix PS disable status race iwlwifi internally needs to keep track of whether PS is enabled in the firmware or not. To do this, it keeps a bit in the status flags, called STATUS_POWER_PMI. The code to set this bit looks as follows: static int iwl_set_power(struct iwl_priv *priv, void *cmd) { return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD, sizeof(struct iwl_powertable_cmd), cmd, NULL); } int iwl_power_update_mode(...) { [...] if (final_mode != IWL_POWER_MODE_CAM) set_bit(STATUS_POWER_PMI, &priv->status); iwl_update_power_cmd(priv, &cmd, final_mode); cmd.keep_alive_beacons = 0; if (final_mode == IWL_POWER_INDEX_5) cmd.flags |= IWL_POWER_FAST_PD; ret = iwl_set_power(priv, &cmd); if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); else set_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); [...] } Now, this bit really needs to track what the _firmware_ thinks, not what the driver thinks. Therefore, there is a race condition here -- the driver sets the bit before it knows that the async command sent to the card in the iwl_set_power function has been processed. As a result, the call to update_chain_flags() may think that the card has been woken up (PMI bit cleared) while in reality it hasn't processed the async POWER_TABLE_CMD yet. This leads to bugs -- any commands the update_chain_flags function sends can get stuck and subsequent commands also fail. The fix is almost trivial: since there's no reason to send an async command here (in fact, there almost never should be since many mac80211 callbacks can sleep) just make the function wait for the card to process the command and then return and clear the PMI bit. Signed-off-by: Johannes Berg Acked-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 47c8945..c913069 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -106,9 +106,8 @@ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { /* set card power command */ static int iwl_set_power(struct iwl_priv *priv, void *cmd) { - return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD, - sizeof(struct iwl_powertable_cmd), - cmd, NULL); + return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, + sizeof(struct iwl_powertable_cmd), cmd); } /* decide the right power level according to association status * and battery status -- cgit v0.10.2 From 7af2c460789a78d9c0d4dc7776fcb87acdc71052 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 May 2009 13:44:38 -0700 Subject: iwlwifi: clean up PS code This removes all the dead code that tries to adjust the power saving level based on the system AC state (inacceptable policy in the kernel) or based on overtemp conditions (unused). Also, pass _all_ policy wrt. enabling PS to mac80211, since we do not use the power_disabled internally I now use that to mirror the mac80211 CONF_PS setting. When mac80211 turns off CONF_PS we follow suit. This means that the user power level (which can currently only be set from sysfs) is not touched for mac80211 powersave changes. This means no "association status" checks are necessary since mac80211 will not allow power save to be enabled when not associated. Signed-off-by: Johannes Berg Acked-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 43bc8a6..13a35dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1838,7 +1838,6 @@ void iwl_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); @@ -1914,7 +1913,7 @@ void iwl_post_associate(struct iwl_priv *priv) * 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); + iwl_power_update_mode(priv, 0); /* Enable Rx differential gain and sensitivity calibrations */ iwl_chain_noise_reset(priv); @@ -2465,26 +2464,11 @@ static ssize_t show_power_level(struct device *d, { struct iwl_priv *priv = dev_get_drvdata(d); int mode = priv->power_data.user_power_setting; - int system = priv->power_data.system_power_setting; int level = priv->power_data.power_mode; char *p = buf; - switch (system) { - case IWL_POWER_SYS_AUTO: - p += sprintf(p, "SYSTEM:auto"); - break; - case IWL_POWER_SYS_AC: - p += sprintf(p, "SYSTEM:ac"); - break; - case IWL_POWER_SYS_BATTERY: - p += sprintf(p, "SYSTEM:battery"); - break; - } - - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? - "fixed" : "auto"); - p += sprintf(p, "\tINDEX:%d", level); - p += sprintf(p, "\n"); + p += sprintf(p, "INDEX:%d\t", level); + p += sprintf(p, "USER:%d\n", mode); return p - buf + 1; } @@ -2553,7 +2537,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); 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); @@ -2573,7 +2556,6 @@ 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 735f3f1..a5d6367 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -857,7 +857,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, priv->cfg->ops->lib->update_chain_flags(priv); data->state = IWL_CHAIN_NOISE_DONE; - iwl_power_enable_management(priv); + iwl_power_update_mode(priv, 0); } EXPORT_SYMBOL(iwl_chain_noise_calibration); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index aa1e1dc..112bfa5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1352,7 +1352,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->ibss_beacon = NULL; spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -2576,14 +2575,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_rate(priv); } - if (changed & IEEE80211_CONF_CHANGE_PS) { - 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 (changed & IEEE80211_CONF_CHANGE_PS && + priv->iw_mode == NL80211_IFTYPE_STATION) { + priv->power_data.power_disabled = + !(conf->flags & IEEE80211_CONF_PS); + ret = iwl_power_update_mode(priv, 0); if (ret) IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); - } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -2719,21 +2717,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) iwlcore_commit_rxon(priv); } - iwl_power_update_mode(priv, 0); - - /* Per mac80211.h: This is only used in IBSS mode... */ 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(priv, "leave - not in IBSS\n"); mutex_unlock(&priv->mutex); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0f2c1b2..3049ba2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1075,7 +1075,6 @@ 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-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index c913069..f2ea3f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -41,38 +41,33 @@ #include "iwl-power.h" /* - * Setting power level allow the card to go to sleep when not busy - * there are three factor that decide the power level to go to, they - * are list here with its priority - * 1- critical_power_setting this will be set according to card temperature. - * 2- system_power_setting this will be set by system PM manager. - * 3- user_power_setting this will be set by user either by writing to sys or - * mac80211 + * Setting power level allow the card to go to sleep when not busy. * - * if system_power_setting and user_power_setting is set to auto - * the power level will be decided according to association status and battery - * status. + * The power level is set to INDEX_1 (the least deep state) by + * default, and will, in the future, be the deepest state unless + * otherwise required by pm_qos network latency requirements. * + * Using INDEX_1 without pm_qos is ok because mac80211 will disable + * PS when even checking every beacon for the TIM bit would exceed + * the required latency. */ -#define MSEC_TO_USEC 1024 #define IWL_POWER_RANGE_0_MAX (2) #define IWL_POWER_RANGE_1_MAX (10) - -#define IWL_POWER_ON_BATTERY IWL_POWER_INDEX_5 -#define IWL_POWER_ON_AC_DISASSOC IWL_POWER_MODE_CAM -#define IWL_POWER_ON_AC_ASSOC IWL_POWER_MODE_CAM - - -#define IWL_CT_KILL_TEMPERATURE 110 -#define IWL_MIN_POWER_TEMPERATURE 100 -#define IWL_REDUCED_POWER_TEMPERATURE 95 - +#define NOSLP cpu_to_le16(0), 0, 0 +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 +#define TU_TO_USEC 1024 +#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \ + cpu_to_le32(X1), \ + cpu_to_le32(X2), \ + cpu_to_le32(X3), \ + cpu_to_le32(X4)} /* default power management (not Tx power) table values */ -/* for TIM 0-10 */ -static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { +/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ +static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, @@ -82,8 +77,8 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { }; -/* for TIM = 3-10 */ -static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { +/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ +static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, @@ -92,8 +87,8 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for TIM > 11 */ -static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { +/* for DTIM period > IWL_POWER_RANGE_1_MAX */ +static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, @@ -109,35 +104,12 @@ static int iwl_set_power(struct iwl_priv *priv, void *cmd) return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(struct iwl_powertable_cmd), cmd); } -/* decide the right power level according to association status - * and battery status - */ -static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) -{ - u16 mode; - - switch (priv->power_data.user_power_setting) { - case IWL_POWER_AUTO: - /* if running on battery */ - if (priv->power_data.is_battery_active) - mode = IWL_POWER_ON_BATTERY; - else if (iwl_is_associated(priv)) - mode = IWL_POWER_ON_AC_ASSOC; - else - mode = IWL_POWER_ON_AC_DISASSOC; - break; - default: - mode = priv->power_data.user_power_setting; - break; - } - return mode; -} /* initialize to default */ static void iwl_power_init_handle(struct iwl_priv *priv) { struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; struct iwl_powertable_cmd *cmd; int i; u16 lctl; @@ -156,7 +128,7 @@ static void iwl_power_init_handle(struct iwl_priv *priv) IWL_DEBUG_POWER(priv, "adjust power command flags\n"); - for (i = 0; i < IWL_POWER_MAX; i++) { + for (i = 0; i < IWL_POWER_NUM; i++) { cmd = &pow_data->pwr_range_0[i].cmd; if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) @@ -246,33 +218,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; - /* 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: - final_mode = iwl_get_auto_power_mode(priv); - break; - case IWL_POWER_SYS_BATTERY: - final_mode = IWL_POWER_INDEX_3; - break; - case IWL_POWER_SYS_AC: - final_mode = IWL_POWER_MODE_CAM; - break; - default: - final_mode = IWL_POWER_INDEX_3; - WARN_ON(1); - } - - if (setting->critical_power_setting > final_mode) - final_mode = setting->critical_power_setting; + final_mode = priv->power_data.user_power_setting; - /* driver only support CAM for non STA network */ - if (priv->iw_mode != NL80211_IFTYPE_STATION) + if (setting->power_disabled) final_mode = IWL_POWER_MODE_CAM; - if (iwl_is_ready_rf(priv) && !setting->power_disabled && + if (iwl_is_ready_rf(priv) && ((setting->power_mode != final_mode) || force)) { struct iwl_powertable_cmd cmd; @@ -289,8 +240,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); - else - set_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); @@ -306,51 +255,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) } EXPORT_SYMBOL(iwl_power_update_mode); -/* Allow other iwl code to disable/enable power management active - * this will be useful for rate scale to disable PM during heavy - * Tx/Rx activities - */ -int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) -{ - u16 prev_mode; - int ret = 0; - - if (priv->power_data.power_disabled) - return -EBUSY; - - prev_mode = priv->power_data.user_power_setting; - priv->power_data.user_power_setting = IWL_POWER_MODE_CAM; - 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; -} -EXPORT_SYMBOL(iwl_power_disable_management); - -/* Allow other iwl code to disable/enable power management active - * this will be useful for rate scale to disable PM during high - * volume activities - */ -int iwl_power_enable_management(struct iwl_priv *priv) -{ - int ret = 0; - - priv->power_data.power_disabled = 0; - ret = iwl_power_update_mode(priv, 0); - return ret; -} -EXPORT_SYMBOL(iwl_power_enable_management); - /* set user_power_setting */ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) { - if (mode > IWL_POWER_MAX) + if (mode >= IWL_POWER_NUM) return -EINVAL; priv->power_data.user_power_setting = mode; @@ -359,86 +267,12 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) } 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) -{ - if (mode < IWL_POWER_SYS_MAX) - priv->power_data.system_power_setting = mode; - else - return -EINVAL; - return iwl_power_update_mode(priv, 0); -} -EXPORT_SYMBOL(iwl_power_set_system_mode); - /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { iwl_power_init_handle(priv); - priv->power_data.user_power_setting = IWL_POWER_AUTO; - priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO; - priv->power_data.power_disabled = 0; - priv->power_data.is_battery_active = 0; - priv->power_data.critical_power_setting = 0; + priv->power_data.user_power_setting = IWL_POWER_INDEX_1; + /* default to disabled until mac80211 says otherwise */ + priv->power_data.power_disabled = 1; } EXPORT_SYMBOL(iwl_power_initialize); - -/* set critical_power_setting according to temperature value */ -int iwl_power_temperature_change(struct iwl_priv *priv) -{ - int ret = 0; - s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature); - u16 new_critical = priv->power_data.critical_power_setting; - - if (temperature > IWL_CT_KILL_TEMPERATURE) - return 0; - else if (temperature > IWL_MIN_POWER_TEMPERATURE) - new_critical = IWL_POWER_INDEX_5; - else if (temperature > IWL_REDUCED_POWER_TEMPERATURE) - new_critical = IWL_POWER_INDEX_3; - else - new_critical = IWL_POWER_MODE_CAM; - - if (new_critical != priv->power_data.critical_power_setting) - priv->power_data.critical_power_setting = new_critical; - - if (priv->power_data.critical_power_setting > - priv->power_data.power_mode) - ret = iwl_power_update_mode(priv, 0); - - 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_POWER(priv, "update power\n"); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - /* on starting association we disable power management - * 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 1896339..37ba3bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -40,56 +40,29 @@ enum { IWL_POWER_INDEX_3, IWL_POWER_INDEX_4, IWL_POWER_INDEX_5, - IWL_POWER_AUTO, - IWL_POWER_MAX = IWL_POWER_AUTO, + IWL_POWER_NUM }; -enum { - IWL_POWER_SYS_AUTO, - IWL_POWER_SYS_AC, - IWL_POWER_SYS_BATTERY, - IWL_POWER_SYS_MAX, -}; - - /* Power management (not Tx power) structures */ -#define NOSLP cpu_to_le16(0), 0, 0 -#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 -#define SLP_TOUT(T) cpu_to_le32((T) * MSEC_TO_USEC) -#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \ - cpu_to_le32(X1), \ - cpu_to_le32(X2), \ - cpu_to_le32(X3), \ - cpu_to_le32(X4)} struct iwl_power_vec_entry { struct iwl_powertable_cmd cmd; u8 no_dtim; }; struct iwl_power_mgr { - spinlock_t lock; - struct iwl_power_vec_entry pwr_range_0[IWL_POWER_MAX]; - struct iwl_power_vec_entry pwr_range_1[IWL_POWER_MAX]; - struct iwl_power_vec_entry pwr_range_2[IWL_POWER_MAX]; + struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM]; + struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM]; + struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM]; u32 dtim_period; /* 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 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 */ + u8 user_power_setting; /* set by user through sysfs */ + u8 power_disabled; /* set by mac80211's CONF_PS */ }; -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); void iwl_power_initialize(struct iwl_priv *priv); -int iwl_power_temperature_change(struct iwl_priv *priv); #endif /* __iwl_power_setting_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 271e5d1..c32ec80 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3845,26 +3845,11 @@ static ssize_t show_power_level(struct device *d, { struct iwl_priv *priv = dev_get_drvdata(d); int mode = priv->power_data.user_power_setting; - int system = priv->power_data.system_power_setting; int level = priv->power_data.power_mode; char *p = buf; - switch (system) { - case IWL_POWER_SYS_AUTO: - p += sprintf(p, "SYSTEM:auto"); - break; - case IWL_POWER_SYS_AC: - p += sprintf(p, "SYSTEM:ac"); - break; - case IWL_POWER_SYS_BATTERY: - p += sprintf(p, "SYSTEM:battery"); - break; - } - - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? - "fixed" : "auto"); - p += sprintf(p, "\tINDEX:%d", level); - p += sprintf(p, "\n"); + p += sprintf(p, "INDEX:%d\t", level); + p += sprintf(p, "USER:%d\n", mode); return p - buf + 1; } @@ -4108,7 +4093,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->ibss_beacon = NULL; spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); -- cgit v0.10.2 From d6e933993fdad4a270c557fa5317f668bef1d824 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 8 May 2009 13:44:39 -0700 Subject: iwlagn: improve rate scale table search iwlagn rate scaling will periodically search other rate scale tables to switch to the best table regarding performance. In the past the number of search tables were 3. Every time the rate scale algorithm goes through these available tables in will stay in current table for some time before start searching again. Recent driver support more feature and antenna, so we have more tables to search. This patch make sure we go through all available tables. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 0a71bb5..3fa06af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -100,6 +100,7 @@ struct iwl_scale_tbl_info { u8 is_fat; /* 1 = 40 MHz channel width */ u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ + u8 max_search; /* maximun number of tables we can search */ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ u32 current_rate; /* rate_n_flags, uCode API format */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ @@ -579,6 +580,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, tbl->is_dup = 0; tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); tbl->lq_type = LQ_NONE; + tbl->max_search = IWL_MAX_SEARCH; /* legacy rate format */ if (!(rate_n_flags & RATE_MCS_HT_MSK)) { @@ -612,8 +614,10 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, tbl->lq_type = LQ_MIMO2; /* MIMO3 */ } else { - if (num_of_ant == 3) + if (num_of_ant == 3) { + tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; tbl->lq_type = LQ_MIMO3; + } } } return 0; @@ -771,6 +775,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, tbl->is_fat = 0; tbl->is_SGI = 0; + tbl->max_search = IWL_MAX_SEARCH; } rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); @@ -1026,6 +1031,7 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, lq_sta->total_failed = 0; lq_sta->total_success = 0; lq_sta->flush_timer = jiffies; + lq_sta->action_counter = 0; } /* @@ -1205,6 +1211,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->lq_type = LQ_MIMO2; tbl->is_dup = lq_sta->is_dup; tbl->action = 0; + tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_mimo2_rate; if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) @@ -1270,6 +1277,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, tbl->lq_type = LQ_MIMO3; tbl->is_dup = lq_sta->is_dup; tbl->action = 0; + tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; rate_mask = lq_sta->active_mimo3_rate; if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) @@ -1328,6 +1336,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->is_dup = lq_sta->is_dup; tbl->lq_type = LQ_SISO; tbl->action = 0; + tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_siso_rate; if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) @@ -1384,15 +1393,15 @@ static int rs_move_legacy_other(struct iwl_priv *priv, u8 valid_tx_ant = priv->hw_params.valid_tx_ant; u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret = 0; + u8 update_search_tbl_counter = 0; for (; ;) { + lq_sta->action_counter++; switch (tbl->action) { case IWL_LEGACY_SWITCH_ANTENNA1: case IWL_LEGACY_SWITCH_ANTENNA2: IWL_DEBUG_RATE(priv, "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 && @@ -1408,6 +1417,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (rs_toggle_antenna(valid_tx_ant, &search_tbl->current_rate, search_tbl)) { + update_search_tbl_counter = 1; rs_set_expected_tpt_table(lq_sta, search_tbl); goto out; } @@ -1489,6 +1499,8 @@ out: tbl->action++; if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; return 0; } @@ -1511,6 +1523,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, 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; + u8 update_search_tbl_counter = 0; int ret; for (;;) { @@ -1531,8 +1544,10 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, memcpy(search_tbl, tbl, sz); if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) + &search_tbl->current_rate, search_tbl)) { + update_search_tbl_counter = 1; goto out; + } break; case IWL_SISO_SWITCH_MIMO2_AB: case IWL_SISO_SWITCH_MIMO2_AC: @@ -1586,6 +1601,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, search_tbl->current_rate = rate_n_flags_from_tbl(priv, search_tbl, index, is_green); + update_search_tbl_counter = 1; goto out; case IWL_SISO_SWITCH_MIMO3_ABC: IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n"); @@ -1617,6 +1633,9 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, tbl->action++; if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC) tbl->action = IWL_SISO_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; + return 0; } @@ -1638,6 +1657,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, 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; + u8 update_search_tbl_counter = 0; int ret; for (;;) { @@ -1655,8 +1675,10 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, memcpy(search_tbl, tbl, sz); if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) + &search_tbl->current_rate, search_tbl)) { + update_search_tbl_counter = 1; goto out; + } break; case IWL_MIMO2_SWITCH_SISO_A: case IWL_MIMO2_SWITCH_SISO_B: @@ -1713,6 +1735,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, search_tbl->current_rate = rate_n_flags_from_tbl(priv, search_tbl, index, is_green); + update_search_tbl_counter = 1; goto out; case IWL_MIMO2_SWITCH_MIMO3_ABC: @@ -1745,6 +1768,9 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, tbl->action++; if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; + return 0; } @@ -1768,6 +1794,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, u8 valid_tx_ant = priv->hw_params.valid_tx_ant; u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret; + u8 update_search_tbl_counter = 0; for (;;) { lq_sta->action_counter++; @@ -1866,6 +1893,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, search_tbl->current_rate = rate_n_flags_from_tbl(priv, search_tbl, index, is_green); + update_search_tbl_counter = 1; goto out; } tbl->action++; @@ -1882,6 +1910,9 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, tbl->action++; if (tbl->action > IWL_MIMO3_SWITCH_GI) tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; + return 0; } @@ -2326,8 +2357,7 @@ lq_update: * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) && - lq_sta->action_counter >= 1) { - lq_sta->action_counter = 0; + lq_sta->action_counter > tbl1->max_search) { IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n"); rs_set_stay_in_table(priv, 1, lq_sta); } @@ -2336,7 +2366,7 @@ lq_update: * have been tried and compared, stay in this best modulation * mode for a while before next round of mode comparisons. */ if (lq_sta->enable_counter && - (lq_sta->action_counter >= IWL_ACTION_LIMIT)) { + (lq_sta->action_counter >= tbl1->max_search)) { if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != MAX_TID_COUNT)) { @@ -2350,7 +2380,6 @@ lq_update: lq_sta, sta); } } - lq_sta->action_counter = 0; rs_set_stay_in_table(priv, 0, lq_sta); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index f875136..25050bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -275,6 +275,8 @@ enum { #define IWL_MIMO3_SWITCH_GI 8 +#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI +#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC /*FIXME:RS:add possible actions for MIMO3*/ -- cgit v0.10.2 From 9906a07e1607e86957ac8780c35a9acf425c4c95 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 8 May 2009 13:44:40 -0700 Subject: iwlwifi: more descriptive unsupported hardware message Somehow these pre-production cards are showing up in the community. With this message we hope that it will be clear that the hardware is not supported. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 75517d0..401438a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -285,7 +285,7 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) return 0; err: - IWL_ERR(priv, "Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", eeprom_ver, priv->cfg->eeprom_ver, calib_ver, priv->cfg->eeprom_calib_ver); return -EINVAL; -- cgit v0.10.2 From 43121432e2d3a9018c40e820b1e44f3f180aa0d6 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 8 May 2009 13:44:41 -0700 Subject: iwl3945: read rev id in nic config Read rev id in nic_config instead of nic_init. Nic_config has some checking for rev_id but we actually don't read the rev_id in there. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 41f1d66..5b0c6e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1110,6 +1110,11 @@ static void iwl3945_nic_config(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); + /* Determine HW type */ + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + + IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); + if (rev_id & PCI_CFG_REV_ID_BIT_RTP) IWL_DEBUG_INFO(priv, "RTP type \n"); else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { @@ -1163,7 +1168,6 @@ static void iwl3945_nic_config(struct iwl_priv *priv) int iwl3945_hw_nic_init(struct iwl_priv *priv) { - u8 rev_id; int rc; unsigned long flags; struct iwl_rx_queue *rxq = &priv->rxq; @@ -1172,12 +1176,6 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.init(priv); spin_unlock_irqrestore(&priv->lock, flags); - /* Determine HW type */ - rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); - if (rc) - return rc; - IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); - rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); if (rc) return rc; -- cgit v0.10.2 From fff7a4346c07c30a39910c3b627434fc0e7ccc33 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 May 2009 13:44:42 -0700 Subject: iwlwifi: use #define instead of hard coded value Instead of hard coded value, use the define in iwl-commands.h for better code maintenance Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 112bfa5..597d955 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -960,10 +960,10 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) if (iwl_is_monitor_mode(priv) && !(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) && ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)) { - rx_chain = 0x07 << RXON_RX_CHAIN_VALID_POS; - rx_chain |= 0x06 << RXON_RX_CHAIN_FORCE_SEL_POS; - rx_chain |= 0x07 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; - rx_chain |= 0x01 << RXON_RX_CHAIN_DRIVER_FORCE_POS; + rx_chain = ANT_ABC << RXON_RX_CHAIN_VALID_POS; + rx_chain |= ANT_BC << RXON_RX_CHAIN_FORCE_SEL_POS; + rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; + rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; } priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index dd8766b..065214b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -580,9 +580,10 @@ static void iwl_bg_request_scan(struct work_struct *data) int ret = 0; u32 rate_flags = 0; u16 cmd_len; + u16 rx_chain = 0; enum ieee80211_band band; u8 n_probes = 0; - u8 rx_chain = priv->hw_params.valid_rx_ant; + u8 rx_ant = priv->hw_params.valid_rx_ant; u8 rate; bool is_active = false; @@ -723,7 +724,7 @@ static void iwl_bg_request_scan(struct work_struct *data) * Avoid A (0x1) because of its off-channel reception on A-band. */ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) - rx_chain = 0x6; + rx_ant = ANT_BC; } else { IWL_WARN(priv, "Invalid scan band count\n"); goto done; @@ -735,10 +736,11 @@ static void iwl_bg_request_scan(struct work_struct *data) scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); /* 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) | - (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); + rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; + rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; + rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; + rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; + scan->rx_chain = cpu_to_le16(rx_chain); cmd_len = iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, priv->scan_request->ie, -- cgit v0.10.2 From 38167459da50e3fe9a10635308bfb0048cc36e8e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 May 2009 13:44:43 -0700 Subject: iwlagn: show current rate scale data in debugfs Add "rate_scale_data" debugfs file to show current bit rate (HT and Legacy), plus additional information (rssi, noise, tsf, beacon time stamp). Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3fa06af..4c88e87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -161,6 +161,7 @@ struct iwl_lq_sta { #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; struct dentry *rs_sta_dbgfs_stats_table_file; + struct dentry *rs_sta_dbgfs_rate_scale_data_file; struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; u32 dbg_fixed_rate; #endif @@ -2984,6 +2985,43 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .open = open_file_generic, }; +static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[120]; + int desc = 0; + ssize_t ret; + + struct iwl_lq_sta *lq_sta = file->private_data; + struct iwl_priv *priv; + struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; + + priv = lq_sta->drv; + + if (is_Ht(tbl->lq_type)) + desc += sprintf(buff+desc, + "Bit Rate= %d Mb/s\n", + tbl->expected_tpt[lq_sta->last_txrate_idx]); + else + desc += sprintf(buff+desc, + "Bit Rate= %d Mb/s\n", + iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); + desc += sprintf(buff+desc, + "Signal Level= %d dBm\tNoise Level= %d dBm\n", + priv->last_rx_rssi, priv->last_rx_noise); + desc += sprintf(buff+desc, + "Tsf= 0x%llx\tBeacon time= 0x%08X\n", + priv->last_tsf, priv->last_beacon_time); + + ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); + return ret; +} + +static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { + .read = rs_sta_dbgfs_rate_scale_data_read, + .open = open_file_generic, +}; + static void rs_add_debugfs(void *priv, void *priv_sta, struct dentry *dir) { @@ -2994,6 +3032,9 @@ static void rs_add_debugfs(void *priv, void *priv_sta, lq_sta->rs_sta_dbgfs_stats_table_file = debugfs_create_file("rate_stats_table", 0600, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); + lq_sta->rs_sta_dbgfs_rate_scale_data_file = + debugfs_create_file("rate_scale_data", 0600, dir, + lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = debugfs_create_u8("tx_agg_tid_enable", 0600, dir, &lq_sta->tx_agg_tid_en); @@ -3005,6 +3046,7 @@ static void rs_remove_debugfs(void *priv, void *priv_sta) struct iwl_lq_sta *lq_sta = priv_sta; debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); + debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file); debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); } #endif -- cgit v0.10.2 From 0b4d0ab44fa2f7bda7b14312741ba3f337a02d5a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 May 2009 13:44:44 -0700 Subject: iwlwifi: show qos AC parameters Show current qos AC parameters in sysfs Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 13a35dc..3ebf6cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2475,6 +2475,26 @@ static ssize_t show_power_level(struct device *d, static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, store_power_level); +static ssize_t show_qos(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = buf; + int q; + + for (q = 0; q < AC_NUM; q++) { + p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n"); + p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q, + priv->qos_data.def_qos_parm.ac[q].cw_min, + priv->qos_data.def_qos_parm.ac[q].cw_max, + priv->qos_data.def_qos_parm.ac[q].aifsn, + priv->qos_data.def_qos_parm.ac[q].edca_txop); + } + + return p - buf + 1; +} + +static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -2572,7 +2592,7 @@ static struct attribute *iwl_sysfs_entries[] = { &dev_attr_debug_level.attr, #endif &dev_attr_version.attr, - + &dev_attr_qos.attr, NULL }; -- cgit v0.10.2 From f2c95b04aba3510323381fe49a0539c23da2e8f4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 May 2009 13:44:45 -0700 Subject: iwlwifi: default WMM AC parameters Set the default WMM AC parameters for BK/BE/VI/VO parameters: AC CWmin CW max AIFSN TXOP Limit TXOP Limit (802.11b) (802.11a/g) AC_BK 15 1023 7 0 0 AC_BE 15 1023 3 0 0 AC_VI 7 15 2 188 94 (6.016ms) (3.008ms) AC_VO 3 7 2 102 47 (3.264ms) (1.504ms) Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 597d955..5393fb3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -273,6 +273,14 @@ void iwl_activate_qos(struct iwl_priv *priv, u8 force) } EXPORT_SYMBOL(iwl_activate_qos); +/* + * AC CWmin CW max AIFSN TXOP Limit TXOP Limit + * (802.11b) (802.11a/g) + * AC_BK 15 1023 7 0 0 + * AC_BE 15 1023 3 0 0 + * AC_VI 7 15 2 6.016ms 3.008ms + * AC_VO 3 7 2 3.264ms 1.504ms + */ void iwl_reset_qos(struct iwl_priv *priv) { u16 cw_min = 15; @@ -304,6 +312,7 @@ void iwl_reset_qos(struct iwl_priv *priv) if (priv->qos_data.qos_active) aifs = 3; + /* AC_BE */ priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; @@ -311,6 +320,7 @@ void iwl_reset_qos(struct iwl_priv *priv) priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; if (priv->qos_data.qos_active) { + /* AC_BK */ i = 1; priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); @@ -318,11 +328,12 @@ void iwl_reset_qos(struct iwl_priv *priv) priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + /* AC_VI */ i = 2; priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16((cw_min + 1) / 2 - 1); priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16(cw_max); + cpu_to_le16(cw_min); priv->qos_data.def_qos_parm.ac[i].aifsn = 2; if (is_legacy) priv->qos_data.def_qos_parm.ac[i].edca_txop = @@ -332,11 +343,12 @@ void iwl_reset_qos(struct iwl_priv *priv) cpu_to_le16(3008); priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + /* AC_VO */ i = 3; priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16((cw_min + 1) / 4 - 1); priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16((cw_max + 1) / 2 - 1); + cpu_to_le16((cw_min + 1) / 2 - 1); priv->qos_data.def_qos_parm.ac[i].aifsn = 2; priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; if (is_legacy) -- cgit v0.10.2 From 19eddca67628e5fb722e4ebbbba8c307a884d0e8 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 8 May 2009 17:54:50 -0700 Subject: ath9k: Remove bogus break after return Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5879c73..9e1db85 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1617,11 +1617,9 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: return ath9k_hw_set_reset_power_on(ah); - break; case ATH9K_RESET_WARM: case ATH9K_RESET_COLD: return ath9k_hw_set_reset(ah, type); - break; default: return false; } -- cgit v0.10.2 From 8fbff4b838c53945d6baeafe609c627000f85cd6 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 8 May 2009 17:54:51 -0700 Subject: ath9k: Cleanup ineffective return values This patch makes the return type of some of the functions void as those functions always return true Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 44fee5a..a2fda70 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -694,7 +694,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, #undef TMP_VAL_VPD_TABLE } -static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, +static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) { @@ -805,11 +805,9 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, } *pTxPowerIndexOffset = 0; - - return true; } -static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, +static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, @@ -1041,10 +1039,9 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } - return true; } -static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, +static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, @@ -1065,22 +1062,13 @@ static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; } - if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, + ath9k_hw_set_4k_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } + powerLimit); - if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } + ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); @@ -1168,7 +1156,6 @@ static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, else ah->regulatory.max_power_level = ratesArray[i]; - return 0; } static void ath9k_hw_4k_set_addac(struct ath_hw *ah, @@ -2103,7 +2090,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, return; } -static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, +static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) { @@ -2255,13 +2242,11 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, } *pTxPowerIndexOffset = 0; - - return true; #undef SM_PD_GAIN #undef SM_PDGAIN_B } -static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, +static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, @@ -2549,10 +2534,9 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, targetPowerCckExt.tPow2x[0]; } } - return true; } -static int ath9k_hw_def_set_txpower(struct ath_hw *ah, +static void ath9k_hw_def_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, @@ -2575,22 +2559,13 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; } - if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + ath9k_hw_set_def_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } + powerLimit); - if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } + ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); @@ -2717,8 +2692,6 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, "Invalid chainmask configuration\n"); break; } - - return 0; } static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 7c59dc4..67b8bd12 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -494,7 +494,7 @@ struct eeprom_ops { struct ath9k_channel *chan); void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); - int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, + void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, u8 powerLimit); u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9e1db85..4acfab5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1274,7 +1274,6 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; - int status; switch (chan->chanmode) { case CHANNEL_A: @@ -1376,17 +1375,12 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, if (OLC_FOR_AR9280_20_LATER) ath9k_olc_init(ah); - status = ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); - if (status != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Error initializing transmit power\n"); - return -EIO; - } + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)); if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, @@ -1701,11 +1695,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_set_regs(ah, chan, macmode); if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Failed to set channel\n"); - return false; - } + ath9k_hw_ar9280_set_channel(ah, chan); } else { if (!(ath9k_hw_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, @@ -1714,16 +1704,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } } - if (ah->eep_ops->set_txpower(ah, chan, + ah->eep_ops->set_txpower(ah, chan, ath9k_regd_get_ctl(&ah->regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)) != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Error initializing transmit power\n"); - return false; - } + (u32) ah->regulatory.power_limit)); synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IS_CHAN_B(chan)) @@ -2311,13 +2297,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, 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))) - return -EIO; - } else { + if (AR_SREV_9280_10_OR_LATER(ah)) + ath9k_hw_ar9280_set_channel(ah, chan); + else if (!(ath9k_hw_set_channel(ah, chan))) return -EIO; - } for (i = 0; i < AR_NUM_DCU; i++) REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); @@ -3748,22 +3732,19 @@ bool ath9k_hw_disable(struct ath_hw *ah) return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); } -bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) +void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) { struct ath9k_channel *chan = ah->curchan; struct ieee80211_channel *channel = chan->chan; ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); - if (ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)) != 0) - return false; - - return true; + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)); } void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ddb24c4..dd8508e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -590,7 +590,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah); void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits); bool ath9k_hw_phy_disable(struct ath_hw *ah); bool ath9k_hw_disable(struct ath_hw *ah); -bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); +void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac); void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 5ec9ce9..aaa9415 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -96,9 +96,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) return true; } -bool -ath9k_hw_ar9280_set_channel(struct ath_hw *ah, - struct ath9k_channel *chan) +void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, + struct ath9k_channel *chan) { u16 bMode, fracMode, aModeRefSel = 0; u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; @@ -169,8 +168,6 @@ ath9k_hw_ar9280_set_channel(struct ath_hw *ah, ah->curchan = chan; ah->curchan_rad_index = -1; - - return true; } static void diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 296d0e9..c70f530 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -17,7 +17,7 @@ #ifndef PHY_H #define PHY_H -bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah, +void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); bool ath9k_hw_set_channel(struct ath_hw *ah, -- cgit v0.10.2 From 4e943900fb9675d3a5ebdabc2cd4a9a54edace97 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 9 May 2009 20:06:47 +0200 Subject: cfg80211: constify key mac address in ops The address pointed to by mac_addr can be marked as const. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 47e30e1..35afe97 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -860,13 +860,13 @@ struct cfg80211_ops { struct vif_params *params); int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, u8 *mac_addr, + u8 key_index, const u8 *mac_addr, struct key_params *params); int (*get_key)(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, u8 *mac_addr, void *cookie, + u8 key_index, const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params*)); int (*del_key)(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, u8 *mac_addr); + u8 key_index, const u8 *mac_addr); int (*set_default_key)(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4e627cf..be86e15 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -112,7 +112,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, } static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, u8 *mac_addr, + u8 key_idx, const u8 *mac_addr, struct key_params *params) { struct ieee80211_sub_if_data *sdata; @@ -166,7 +166,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, u8 *mac_addr) + u8 key_idx, const u8 *mac_addr) { struct ieee80211_sub_if_data *sdata; struct sta_info *sta; @@ -208,7 +208,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, u8 *mac_addr, void *cookie, + u8 key_idx, const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *params)) { -- cgit v0.10.2 From cbe8fa9c5e88fd5f554ebc519af3b0ed17dde0dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 9 May 2009 20:09:03 +0200 Subject: cfg80211: put wext data into substructure To make it more apparent in the code what is for wext only (and needs to be #ifdef'ed) put all the info for wext into a substruct in each wireless_dev. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 35afe97..4c74893 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1147,8 +1147,10 @@ struct wireless_dev { #ifdef CONFIG_WIRELESS_EXT /* wext data */ - struct cfg80211_ibss_params wext; - u8 wext_bssid[ETH_ALEN]; + struct { + struct cfg80211_ibss_params ibss; + u8 bssid[ETH_ALEN]; + } wext; #endif }; diff --git a/net/wireless/core.c b/net/wireless/core.c index 2006a4e..15b2a17 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -470,9 +470,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #ifdef CONFIG_WIRELESS_EXT if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) break; - if (!dev->ieee80211_ptr->wext.ssid_len) + if (!dev->ieee80211_ptr->wext.ibss.ssid_len) break; - cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext); + cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss); break; #endif case NETDEV_UNREGISTER: diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 3c38afa..a4a1c34 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -63,7 +63,7 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, return -EALREADY; #ifdef CONFIG_WIRELESS_EXT - wdev->wext.channel = params->channel; + wdev->wext.ibss.channel = params->channel; #endif err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); @@ -90,7 +90,7 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) memset(wdev->bssid, 0, ETH_ALEN); #ifdef CONFIG_WIRELESS_EXT if (!nowext) - wdev->wext.ssid_len = 0; + wdev->wext.ibss.ssid_len = 0; #endif } @@ -116,11 +116,11 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, enum ieee80211_band band; int i; - if (!wdev->wext.beacon_interval) - wdev->wext.beacon_interval = 100; + if (!wdev->wext.ibss.beacon_interval) + wdev->wext.ibss.beacon_interval = 100; /* try to find an IBSS channel if none requested ... */ - if (!wdev->wext.channel) { + if (!wdev->wext.ibss.channel) { for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; @@ -135,27 +135,27 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, continue; if (chan->flags & IEEE80211_CHAN_DISABLED) continue; - wdev->wext.channel = chan; + wdev->wext.ibss.channel = chan; break; } - if (wdev->wext.channel) + if (wdev->wext.ibss.channel) break; } - if (!wdev->wext.channel) + if (!wdev->wext.ibss.channel) return -EINVAL; } /* don't join -- SSID is not there */ - if (!wdev->wext.ssid_len) + if (!wdev->wext.ibss.ssid_len) return 0; if (!netif_running(wdev->netdev)) return 0; return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy), - wdev->netdev, &wdev->wext); + wdev->netdev, &wdev->wext.ibss); } int cfg80211_ibss_wext_siwfreq(struct net_device *dev, @@ -182,7 +182,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, chan->flags & IEEE80211_CHAN_DISABLED)) return -EINVAL; - if (wdev->wext.channel == chan) + if (wdev->wext.ibss.channel == chan) return 0; if (wdev->ssid_len) { @@ -193,11 +193,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, } if (chan) { - wdev->wext.channel = chan; - wdev->wext.channel_fixed = true; + wdev->wext.ibss.channel = chan; + wdev->wext.ibss.channel_fixed = true; } else { /* cfg80211_ibss_wext_join will pick one if needed */ - wdev->wext.channel_fixed = false; + wdev->wext.ibss.channel_fixed = false; } return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); @@ -218,8 +218,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, if (wdev->current_bss) chan = wdev->current_bss->channel; - else if (wdev->wext.channel) - chan = wdev->wext.channel; + else if (wdev->wext.ibss.channel) + chan = wdev->wext.ibss.channel; if (chan) { freq->m = chan->center_freq; @@ -259,9 +259,9 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, if (len > 0 && ssid[len - 1] == '\0') len--; - wdev->wext.ssid = wdev->ssid; - memcpy(wdev->wext.ssid, ssid, len); - wdev->wext.ssid_len = len; + wdev->wext.ibss.ssid = wdev->ssid; + memcpy(wdev->wext.ibss.ssid, ssid, len); + wdev->wext.ibss.ssid_len = len; return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); } @@ -284,10 +284,10 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, data->flags = 1; data->length = wdev->ssid_len; memcpy(ssid, wdev->ssid, data->length); - } else if (wdev->wext.ssid && wdev->wext.ssid_len) { + } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) { data->flags = 1; - data->length = wdev->wext.ssid_len; - memcpy(ssid, wdev->wext.ssid, data->length); + data->length = wdev->wext.ibss.ssid_len; + memcpy(ssid, wdev->wext.ibss.ssid, data->length); } return 0; @@ -318,12 +318,12 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, bssid = NULL; /* both automatic */ - if (!bssid && !wdev->wext.bssid) + if (!bssid && !wdev->wext.ibss.bssid) return 0; /* fixed already - and no change */ - if (wdev->wext.bssid && bssid && - compare_ether_addr(bssid, wdev->wext.bssid) == 0) + if (wdev->wext.ibss.bssid && bssid && + compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) return 0; if (wdev->ssid_len) { @@ -334,10 +334,10 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, } if (bssid) { - memcpy(wdev->wext_bssid, bssid, ETH_ALEN); - wdev->wext.bssid = wdev->wext_bssid; + memcpy(wdev->wext.bssid, bssid, ETH_ALEN); + wdev->wext.ibss.bssid = wdev->wext.bssid; } else - wdev->wext.bssid = NULL; + wdev->wext.ibss.bssid = NULL; return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); } @@ -356,8 +356,8 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; - if (wdev->wext.bssid) { - memcpy(ap_addr->sa_data, wdev->wext.bssid, ETH_ALEN); + if (wdev->wext.ibss.bssid) { + memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); return 0; } -- cgit v0.10.2 From 528769cf1e422d932052be1487459262f3d75333 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 May 2009 10:20:35 +0300 Subject: mac80211: Robust Action frame categories for MFP IEEE 802.11w/D9.0 introduces a mechanism for Action field Category values to be used to select which Action frames are Robust. Public and Vendor-specific categories are marked as not Robust in IEEE 802.11w; HT will be marked not Robust in IEEE 802.11n. A new Vendor-specific Protected category is allocated for Robust vendor-specific Action frames. Another new category, Protected Dual of Action, is introduced for protecting some existing Public Action frames (e.g., IEEE 802.11y protected enablement). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index dc92359..05c29c0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1068,8 +1068,12 @@ enum ieee80211_category { WLAN_CATEGORY_DLS = 2, WLAN_CATEGORY_BACK = 3, WLAN_CATEGORY_PUBLIC = 4, + WLAN_CATEGORY_HT = 7, WLAN_CATEGORY_SA_QUERY = 8, + WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, WLAN_CATEGORY_WMM = 17, + WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, + WLAN_CATEGORY_VENDOR_SPECIFIC = 127, }; /* SPECTRUM_MGMT action code */ @@ -1261,7 +1265,9 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) if (ieee80211_has_protected(hdr->frame_control)) return true; category = ((u8 *) hdr) + 24; - return *category != WLAN_CATEGORY_PUBLIC; + return *category != WLAN_CATEGORY_PUBLIC && + *category != WLAN_CATEGORY_HT && + *category != WLAN_CATEGORY_VENDOR_SPECIFIC; } return false; -- cgit v0.10.2 From e80cf8537ae54ec96c389055d6e9b0ef630c042d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 May 2009 14:43:13 +0200 Subject: cfg80211: disallow interfering with stations on non-AP On non-AP interfaces userspace has no business interfering with the station management, this can confuse mac80211 (and other drivers probably wouldn't support it anyway). Allow adding and removing stations only on AP interfaces. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7992770..a39e464 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1746,6 +1746,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out_rtnl; + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { + err = -EINVAL; + goto out; + } + err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); if (err) goto out; @@ -1789,6 +1795,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out_rtnl; + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { + err = -EINVAL; + goto out; + } + if (!drv->ops->del_station) { err = -EOPNOTSUPP; goto out; -- cgit v0.10.2 From 7be69c0b9aa93ef655db4d46e5654996489d62f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 May 2009 16:06:36 +0200 Subject: wext: fix get_wireless_stats locking Currently, get_wireless_stats is racy by _design_. This is because it returns a buffer, which needs to be statically allocated since it cannot be freed if it was allocated dynamically. Also, SIOCGIWSTATS and /proc/net/wireless use no common lock, and /proc/net/wireless accesses are not synchronised against each other. This is a design flaw in get_wireless_stats since the beginning. This patch fixes it by wrapping /proc/net/wireless accesses with the RTNL so they are protected against each other and SIOCGIWSTATS. The more correct method of fixing this would be to pass in the buffer instead of returning it and have the caller take care of synchronisation of the buffer, but even then most drivers probably assume that their callback is protected by the RTNL like all other wext callbacks. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext.c b/net/wireless/wext.c index cb6a5bb..dc5b47e 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -649,14 +649,28 @@ static int wireless_seq_show(struct seq_file *seq, void *v) return 0; } +static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(dev_base_lock) +{ + rtnl_lock(); + return dev_seq_start(seq, pos); +} + +static void wireless_dev_seq_stop(struct seq_file *seq, void *v) + __releases(dev_base_lock) +{ + dev_seq_stop(seq, v); + rtnl_unlock(); +} + static const struct seq_operations wireless_seq_ops = { - .start = dev_seq_start, + .start = wireless_dev_seq_start, .next = dev_seq_next, - .stop = dev_seq_stop, + .stop = wireless_dev_seq_stop, .show = wireless_seq_show, }; -static int wireless_seq_open(struct inode *inode, struct file *file) +static int seq_open_wireless(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &wireless_seq_ops, sizeof(struct seq_net_private)); @@ -664,7 +678,7 @@ static int wireless_seq_open(struct inode *inode, struct file *file) static const struct file_operations wireless_seq_fops = { .owner = THIS_MODULE, - .open = wireless_seq_open, + .open = seq_open_wireless, .read = seq_read, .llseek = seq_lseek, .release = seq_release_net, -- cgit v0.10.2 From e13cf6e04ebc231653e03ebde4799dc55bf62849 Mon Sep 17 00:00:00 2001 From: john stultz Date: Mon, 11 May 2009 18:13:13 -0700 Subject: ntp: fix comment typos Bernhard Schiffner noticed I had a few comment typos in this patch, (note: to save embarrassment, when making typos, avoid copying and pasting them) so this patch corrects them. [ Impact: cleanup ] Reported-by: Bernhard Schiffner Signed-off-by: John Stultz Cc: riel@redhat.com Cc: akpm@linux-foundation.org LKML-Reference: <1242090794.7214.131.camel@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/include/linux/timex.h b/include/linux/timex.h index 0daf961..9910e3b 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -179,7 +179,7 @@ struct timex { * NTP convergence time. A higher value makes it stiffer, increasing * convergence time, but making the clock more stable. * - * In David Mills' nanokenrel reference implmentation SHIFT_PLL is 4. + * In David Mills' nanokernel reference implementation SHIFT_PLL is 4. * However this seems to increase convergence time much too long. * * https://lists.ntp.org/pipermail/hackers/2008-January/003487.html @@ -196,7 +196,7 @@ struct timex { * * SHIFT_FLL is used as a dampening factor to define how much we * adjust the frequency correction for a given offset in FLL mode. - * In David Mills' nanokenrel reference implmentation SHIFT_PLL is 2. + * In David Mills' nanokernel reference implementation SHIFT_FLL is 2. * * MAXTC establishes the maximum time constant of the PLL. */ -- cgit v0.10.2 From 597d0275736dad9c3bda6f0a00a1c477dc0f37b1 Mon Sep 17 00:00:00 2001 From: Arun R Bharadwaj Date: Thu, 16 Apr 2009 12:13:26 +0530 Subject: timers: Framework for identifying pinned timers * Arun R Bharadwaj [2009-04-16 12:11:36]: This patch creates a new framework for identifying cpu-pinned timers and hrtimers. This framework is needed because pinned timers are expected to fire on the same CPU on which they are queued. So it is essential to identify these and not migrate them, in case there are any. For regular timers, the currently existing add_timer_on() can be used queue pinned timers and subsequently mod_timer_pinned() can be used to modify the 'expires' field. For hrtimers, new modes HRTIMER_ABS_PINNED and HRTIMER_REL_PINNED are added to queue cpu-pinned hrtimer. [ tglx: use .._PINNED mode argument instead of creating tons of new functions ] Signed-off-by: Arun R Bharadwaj Signed-off-by: Thomas Gleixner diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 0d2f7c8..7400900 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -30,8 +30,11 @@ struct hrtimer_cpu_base; * Mode arguments of xxx_hrtimer functions: */ enum hrtimer_mode { - HRTIMER_MODE_ABS, /* Time value is absolute */ - HRTIMER_MODE_REL, /* Time value is relative to now */ + HRTIMER_MODE_ABS = 0x0, /* Time value is absolute */ + HRTIMER_MODE_REL = 0x1, /* Time value is relative to now */ + HRTIMER_MODE_PINNED = 0x02, /* Timer is bound to CPU */ + HRTIMER_MODE_ABS_PINNED = 0x02, + HRTIMER_MODE_REL_PINNED = 0x03, }; /* diff --git a/include/linux/timer.h b/include/linux/timer.h index 6cdb6f3..ccf882e 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -163,7 +163,10 @@ extern void add_timer_on(struct timer_list *timer, int cpu); extern int del_timer(struct timer_list * timer); extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); +extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); +#define TIMER_NOT_PINNED 0 +#define TIMER_PINNED 1 /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index cb8a15c..c71bcd5 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -193,7 +193,8 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, * Switch the timer base to the current CPU when possible. */ static inline struct hrtimer_clock_base * -switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base) +switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, + int pinned) { struct hrtimer_clock_base *new_base; struct hrtimer_cpu_base *new_cpu_base; @@ -907,9 +908,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, ret = remove_hrtimer(timer, base); /* Switch the timer base, if necessary: */ - new_base = switch_hrtimer_base(timer, base); + new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); - if (mode == HRTIMER_MODE_REL) { + if (mode & HRTIMER_MODE_REL) { tim = ktime_add_safe(tim, new_base->get_time()); /* * CONFIG_TIME_LOW_RES is a temporary way for architectures diff --git a/kernel/timer.c b/kernel/timer.c index 5c1e84b..3424dfd 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -604,7 +604,8 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer, } static inline int -__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) +__mod_timer(struct timer_list *timer, unsigned long expires, + bool pending_only, int pinned) { struct tvec_base *base, *new_base; unsigned long flags; @@ -668,7 +669,7 @@ out_unlock: */ int mod_timer_pending(struct timer_list *timer, unsigned long expires) { - return __mod_timer(timer, expires, true); + return __mod_timer(timer, expires, true, TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer_pending); @@ -702,11 +703,33 @@ int mod_timer(struct timer_list *timer, unsigned long expires) if (timer->expires == expires && timer_pending(timer)) return 1; - return __mod_timer(timer, expires, false); + return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer); /** + * mod_timer_pinned - modify a timer's timeout + * @timer: the timer to be modified + * @expires: new timeout in jiffies + * + * mod_timer_pinned() is a way to update the expire field of an + * active timer (if the timer is inactive it will be activated) + * and not allow the timer to be migrated to a different CPU. + * + * mod_timer_pinned(timer, expires) is equivalent to: + * + * del_timer(timer); timer->expires = expires; add_timer(timer); + */ +int mod_timer_pinned(struct timer_list *timer, unsigned long expires) +{ + if (timer->expires == expires && timer_pending(timer)) + return 1; + + return __mod_timer(timer, expires, false, TIMER_PINNED); +} +EXPORT_SYMBOL(mod_timer_pinned); + +/** * add_timer - start a timer * @timer: the timer to be added * @@ -1356,7 +1379,7 @@ signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire, false); + __mod_timer(&timer, expire, false, TIMER_NOT_PINNED); schedule(); del_singleshot_timer_sync(&timer); -- cgit v0.10.2 From 5c333864a6ba811052d52ef14fbed056b9ac3512 Mon Sep 17 00:00:00 2001 From: Arun R Bharadwaj Date: Thu, 16 Apr 2009 12:14:37 +0530 Subject: timers: Identifying the existing pinned timers * Arun R Bharadwaj [2009-04-16 12:11:36]: The following pinned hrtimers have been identified and marked: 1)sched_rt_period_timer 2)tick_sched_timer 3)stack_trace_timer_fn [ tglx: fixup the hrtimer pinned mode ] Signed-off-by: Arun R Bharadwaj Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 2bda693..a9cad1b 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -463,7 +463,7 @@ static void uv_heartbeat(unsigned long ignored) uv_set_scir_bits(bits); /* enable next timer period */ - mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL); + mod_timer_pinned(timer, jiffies + SCIR_CPU_HB_INTERVAL); } static void __cpuinit uv_heartbeat_enable(int cpu) diff --git a/kernel/sched.c b/kernel/sched.c index b902e58..9c5b4d3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -244,7 +244,7 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b) hard = hrtimer_get_expires(&rt_b->rt_period_timer); delta = ktime_to_ns(ktime_sub(hard, soft)); __hrtimer_start_range_ns(&rt_b->rt_period_timer, soft, delta, - HRTIMER_MODE_ABS, 0); + HRTIMER_MODE_ABS_PINNED, 0); } spin_unlock(&rt_b->rt_runtime_lock); } @@ -1154,7 +1154,7 @@ static __init void init_hrtick(void) static void hrtick_start(struct rq *rq, u64 delay) { __hrtimer_start_range_ns(&rq->hrtick_timer, ns_to_ktime(delay), 0, - HRTIMER_MODE_REL, 0); + HRTIMER_MODE_REL_PINNED, 0); } static inline void init_hrtick(void) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index d3f1ef4..2aff39c 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -349,7 +349,7 @@ void tick_nohz_stop_sched_tick(int inidle) if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { hrtimer_start(&ts->sched_timer, expires, - HRTIMER_MODE_ABS); + HRTIMER_MODE_ABS_PINNED); /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) goto out; @@ -395,7 +395,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { hrtimer_start_expires(&ts->sched_timer, - HRTIMER_MODE_ABS); + HRTIMER_MODE_ABS_PINNED); /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) break; @@ -698,7 +698,8 @@ void tick_setup_sched_timer(void) for (;;) { hrtimer_forward(&ts->sched_timer, now, tick_period); - hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS); + hrtimer_start_expires(&ts->sched_timer, + HRTIMER_MODE_ABS_PINNED); /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) break; diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c index 91fd19c..d180554bc 100644 --- a/kernel/trace/trace_sysprof.c +++ b/kernel/trace/trace_sysprof.c @@ -203,7 +203,8 @@ static void start_stack_timer(void *unused) hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer->function = stack_trace_timer_fn; - hrtimer_start(hrtimer, ns_to_ktime(sample_period), HRTIMER_MODE_REL); + hrtimer_start(hrtimer, ns_to_ktime(sample_period), + HRTIMER_MODE_REL_PINNED); } static void start_stack_timers(void) -- cgit v0.10.2 From cd1bb94b4a0531e8211a3774f17de831f8285f76 Mon Sep 17 00:00:00 2001 From: Arun R Bharadwaj Date: Thu, 16 Apr 2009 12:15:34 +0530 Subject: timers: /proc/sys sysctl hook to enable timer migration * Arun R Bharadwaj [2009-04-16 12:11:36]: This patch creates the /proc/sys sysctl interface at /proc/sys/kernel/timer_migration Timer migration is enabled by default. To disable timer migration, when CONFIG_SCHED_DEBUG = y, echo 0 > /proc/sys/kernel/timer_migration Signed-off-by: Arun R Bharadwaj Signed-off-by: Thomas Gleixner diff --git a/include/linux/sched.h b/include/linux/sched.h index b4c38bc..6185040 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1766,6 +1766,7 @@ extern unsigned int sysctl_sched_child_runs_first; extern unsigned int sysctl_sched_features; extern unsigned int sysctl_sched_migration_cost; extern unsigned int sysctl_sched_nr_migrate; +extern unsigned int sysctl_timer_migration; int sched_nr_latency_handler(struct ctl_table *table, int write, struct file *file, void __user *buffer, size_t *length, diff --git a/kernel/sched.c b/kernel/sched.c index 9c5b4d3..7f1dd56 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8731,6 +8731,8 @@ void __init sched_init_smp(void) } #endif /* CONFIG_SMP */ +const_debug unsigned int sysctl_timer_migration = 1; + int in_sched_functions(unsigned long addr) { return in_lock_functions(addr) || diff --git a/kernel/sysctl.c b/kernel/sysctl.c index e3d2c7d..b3ce581 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -324,6 +324,14 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "timer_migration", + .data = &sysctl_timer_migration, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif { .ctl_name = CTL_UNNUMBERED, -- cgit v0.10.2 From eea08f32adb3f97553d49a4f79a119833036000a Mon Sep 17 00:00:00 2001 From: Arun R Bharadwaj Date: Thu, 16 Apr 2009 12:16:41 +0530 Subject: timers: Logic to move non pinned timers * Arun R Bharadwaj [2009-04-16 12:11:36]: This patch migrates all non pinned timers and hrtimers to the current idle load balancer, from all the idle CPUs. Timers firing on busy CPUs are not migrated. While migrating hrtimers, care should be taken to check if migrating a hrtimer would result in a latency or not. So we compare the expiry of the hrtimer with the next timer interrupt on the target cpu and migrate the hrtimer only if it expires *after* the next interrupt on the target cpu. So, added a clockevents_get_next_event() helper function to return the next_event on the target cpu's clock_event_device. [ tglx: cleanups and simplifications ] Signed-off-by: Arun R Bharadwaj Signed-off-by: Thomas Gleixner diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 3a1dbba..20a100f 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -143,3 +143,12 @@ extern void clockevents_notify(unsigned long reason, void *arg); #endif #endif + +#ifdef CONFIG_GENERIC_CLOCKEVENTS +extern ktime_t clockevents_get_next_event(int cpu); +#else +static inline ktime_t clockevents_get_next_event(int cpu) +{ + return (ktime_t) { .tv64 = KTIME_MAX }; +} +#endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 6185040..311dec1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -257,6 +257,7 @@ extern void task_rq_unlock_wait(struct task_struct *p); extern cpumask_var_t nohz_cpu_mask; #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ) extern int select_nohz_load_balancer(int cpu); +extern int get_nohz_load_balancer(void); #else static inline int select_nohz_load_balancer(int cpu) { @@ -1772,6 +1773,17 @@ int sched_nr_latency_handler(struct ctl_table *table, int write, struct file *file, void __user *buffer, size_t *length, loff_t *ppos); #endif +#ifdef CONFIG_SCHED_DEBUG +static inline unsigned int get_sysctl_timer_migration(void) +{ + return sysctl_timer_migration; +} +#else +static inline unsigned int get_sysctl_timer_migration(void) +{ + return 1; +} +#endif extern unsigned int sysctl_sched_rt_period; extern int sysctl_sched_rt_runtime; diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index c71bcd5..b675a67 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include @@ -198,8 +200,19 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, { struct hrtimer_clock_base *new_base; struct hrtimer_cpu_base *new_cpu_base; + int cpu, preferred_cpu = -1; + + cpu = smp_processor_id(); +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) + if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) { + preferred_cpu = get_nohz_load_balancer(); + if (preferred_cpu >= 0) + cpu = preferred_cpu; + } +#endif - new_cpu_base = &__get_cpu_var(hrtimer_bases); +again: + new_cpu_base = &per_cpu(hrtimer_bases, cpu); new_base = &new_cpu_base->clock_base[base->index]; if (base != new_base) { @@ -219,6 +232,40 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, timer->base = NULL; spin_unlock(&base->cpu_base->lock); spin_lock(&new_base->cpu_base->lock); + + /* Optimized away for NOHZ=n SMP=n */ + if (cpu == preferred_cpu) { + /* Calculate clock monotonic expiry time */ +#ifdef CONFIG_HIGH_RES_TIMERS + ktime_t expires = ktime_sub(hrtimer_get_expires(timer), + new_base->offset); +#else + ktime_t expires = hrtimer_get_expires(timer); +#endif + + /* + * Get the next event on target cpu from the + * clock events layer. + * This covers the highres=off nohz=on case as well. + */ + ktime_t next = clockevents_get_next_event(cpu); + + ktime_t delta = ktime_sub(expires, next); + + /* + * We do not migrate the timer when it is expiring + * before the next event on the target cpu because + * we cannot reprogram the target cpu hardware and + * we would cause it to fire late. + */ + if (delta.tv64 < 0) { + cpu = smp_processor_id(); + spin_unlock(&new_base->cpu_base->lock); + spin_lock(&base->cpu_base->lock); + timer->base = base; + goto again; + } + } timer->base = new_base; } return new_base; @@ -236,7 +283,7 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) return base; } -# define switch_hrtimer_base(t, b) (b) +# define switch_hrtimer_base(t, b, p) (b) #endif /* !CONFIG_SMP */ diff --git a/kernel/sched.c b/kernel/sched.c index 7f1dd56..9fe3774 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4244,6 +4244,11 @@ static struct { .load_balancer = ATOMIC_INIT(-1), }; +int get_nohz_load_balancer(void) +{ + return atomic_read(&nohz.load_balancer); +} + /* * This routine will try to nominate the ilb (idle load balancing) * owner among the cpus whose ticks are stopped. ilb owner will do the idle diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index d13be21..ab20ded0 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -18,6 +18,7 @@ #include #include #include +#include /* The registered clock event devices */ static LIST_HEAD(clockevent_devices); @@ -251,4 +252,15 @@ void clockevents_notify(unsigned long reason, void *arg) spin_unlock(&clockevents_lock); } EXPORT_SYMBOL_GPL(clockevents_notify); + +ktime_t clockevents_get_next_event(int cpu) +{ + struct tick_device *td; + struct clock_event_device *dev; + + td = &per_cpu(tick_cpu_device, cpu); + dev = td->evtdev; + + return dev->next_event; +} #endif diff --git a/kernel/timer.c b/kernel/timer.c index 3424dfd..3f841db 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -609,9 +610,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, { struct tvec_base *base, *new_base; unsigned long flags; - int ret; - - ret = 0; + int ret = 0 , cpu; timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); @@ -630,6 +629,18 @@ __mod_timer(struct timer_list *timer, unsigned long expires, new_base = __get_cpu_var(tvec_bases); + cpu = smp_processor_id(); + +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) + if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) { + int preferred_cpu = get_nohz_load_balancer(); + + if (preferred_cpu >= 0) + cpu = preferred_cpu; + } +#endif + new_base = per_cpu(tvec_bases, cpu); + if (base != new_base) { /* * We are trying to schedule the timer on the local CPU. -- cgit v0.10.2 From 08645126dd24872c2e27014f93968f7312e29176 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 May 2009 13:54:58 +0200 Subject: cfg80211: implement wext key handling Move key handling wireless extension ioctls from mac80211 to cfg80211 so that all drivers that implement the cfg80211 operations get wext compatibility. Note that this drops the SIOCGIWENCODE ioctl support for getting IW_ENCODE_RESTRICTED/IW_ENCODE_OPEN. This means that iwconfig will no longer report "Security mode:open" or "Security mode:restricted" for mac80211. However, what we displayed there (the authentication algo used) was actually wrong -- linux/wireless.h states that this setting is meant to differentiate between "Refuse non-encoded packets" and "Accept non-encoded packets". (Combined with "cfg80211: fix a couple of bugs with key ioctls". -- JWL) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4c74893..e69e6c6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1150,6 +1150,7 @@ struct wireless_dev { struct { struct cfg80211_ibss_params ibss; u8 bssid[ETH_ALEN]; + s8 default_key, default_mgmt_key; } wext; #endif }; @@ -1400,6 +1401,15 @@ int cfg80211_wext_siwretry(struct net_device *dev, int cfg80211_wext_giwretry(struct net_device *dev, struct iw_request_info *info, struct iw_param *retry, char *extra); +int cfg80211_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra); +int cfg80211_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf); +int cfg80211_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf); /* * callbacks for asynchronous cfg80211 methods, notification diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 6b4eb8d..d845026 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,100 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr, - int idx, int alg, int remove, - int set_tx_key, const u8 *_key, - size_t key_len) -{ - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - struct ieee80211_key *key; - int err; - - if (alg == ALG_AES_CMAC) { - if (idx < NUM_DEFAULT_KEYS || - idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { - printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d " - "(BIP)\n", sdata->dev->name, idx); - return -EINVAL; - } - } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { - printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", - sdata->dev->name, idx); - return -EINVAL; - } - - if (remove) { - rcu_read_lock(); - - err = 0; - - if (is_broadcast_ether_addr(sta_addr)) { - key = sdata->keys[idx]; - } else { - sta = sta_info_get(local, sta_addr); - if (!sta) { - err = -ENOENT; - goto out_unlock; - } - key = sta->key; - } - - ieee80211_key_free(key); - } else { - key = ieee80211_key_alloc(alg, idx, key_len, _key); - if (!key) - return -ENOMEM; - - sta = NULL; - err = 0; - - rcu_read_lock(); - - if (!is_broadcast_ether_addr(sta_addr)) { - set_tx_key = 0; - /* - * According to the standard, the key index of a - * pairwise key must be zero. However, some AP are - * broken when it comes to WEP key indices, so we - * work around this. - */ - if (idx != 0 && alg != ALG_WEP) { - ieee80211_key_free(key); - err = -EINVAL; - goto out_unlock; - } - - sta = sta_info_get(local, sta_addr); - if (!sta) { - ieee80211_key_free(key); - err = -ENOENT; - goto out_unlock; - } - } - - if (alg == ALG_WEP && - key_len != LEN_WEP40 && key_len != LEN_WEP104) { - ieee80211_key_free(key); - err = -EINVAL; - goto out_unlock; - } - - ieee80211_key_link(key, sdata, sta); - - if (set_tx_key || (!sta && !sdata->default_key && key)) - ieee80211_set_default_key(sdata, idx); - if (alg == ALG_AES_CMAC && - (set_tx_key || (!sta && !sdata->default_mgmt_key && key))) - ieee80211_set_default_mgmt_key(sdata, idx); - } - - out_unlock: - rcu_read_unlock(); - - return err; -} - static int ieee80211_ioctl_siwgenie(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) @@ -472,109 +378,6 @@ static int ieee80211_ioctl_giwtxpower(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *keybuf) -{ - struct ieee80211_sub_if_data *sdata; - int idx, i, alg = ALG_WEP; - u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - int remove = 0, ret; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx == 0) { - if (sdata->default_key) - for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - } else if (idx < 1 || idx > 4) - return -EINVAL; - else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if (erq->length == 0) { - /* No key data - just set the default TX key index */ - ieee80211_set_default_key(sdata, idx); - return 0; - } - - ret = ieee80211_set_encryption( - sdata, bcaddr, - idx, alg, remove, - !sdata->default_key, - keybuf, erq->length); - - if (!ret && sdata->vif.type == NL80211_IFTYPE_STATION) { - if (remove) - sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; - else - sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; - } - - return ret; -} - - -static int ieee80211_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - struct ieee80211_sub_if_data *sdata; - int idx, i; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx < 1 || idx > 4) { - idx = -1; - if (!sdata->default_key) - idx = 0; - else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - - erq->flags = idx + 1; - - if (!sdata->keys[idx]) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - memcpy(key, sdata->keys[idx]->conf.key, - min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); - erq->length = sdata->keys[idx]->conf.keylen; - erq->flags |= IW_ENCODE_ENABLED; - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - switch (sdata->u.mgd.auth_alg) { - case WLAN_AUTH_OPEN: - case WLAN_AUTH_LEAP: - erq->flags |= IW_ENCODE_OPEN; - break; - case WLAN_AUTH_SHARED_KEY: - erq->flags |= IW_ENCODE_RESTRICTED; - break; - } - } - - return 0; -} - static int ieee80211_ioctl_siwpower(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, @@ -809,82 +612,6 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev, } -static int ieee80211_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int uninitialized_var(alg), idx, i, remove = 0; - - switch (ext->alg) { - case IW_ENCODE_ALG_NONE: - remove = 1; - break; - case IW_ENCODE_ALG_WEP: - alg = ALG_WEP; - break; - case IW_ENCODE_ALG_TKIP: - alg = ALG_TKIP; - break; - case IW_ENCODE_ALG_CCMP: - alg = ALG_CCMP; - break; - case IW_ENCODE_ALG_AES_CMAC: - alg = ALG_AES_CMAC; - break; - default: - return -EOPNOTSUPP; - } - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - - idx = erq->flags & IW_ENCODE_INDEX; - if (alg == ALG_AES_CMAC) { - if (idx < NUM_DEFAULT_KEYS + 1 || - idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { - idx = -1; - if (!sdata->default_mgmt_key) - idx = 0; - else for (i = NUM_DEFAULT_KEYS; - i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS; - i++) { - if (sdata->default_mgmt_key == sdata->keys[i]) - { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - } else { - if (idx < 1 || idx > 4) { - idx = -1; - if (!sdata->default_key) - idx = 0; - else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - } - - return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, - remove, - ext->ext_flags & - IW_ENCODE_EXT_SET_TX_KEY, - ext->key, ext->key_len); -} - - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -931,8 +658,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ - (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ - (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ + (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ @@ -941,7 +668,7 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWGENIE */ (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ - (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ (iw_handler) NULL, /* -- hole -- */ diff --git a/net/wireless/core.c b/net/wireless/core.c index 15b2a17..47c20eb 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1,7 +1,7 @@ /* * This is the linux wireless configuration interface. * - * Copyright 2006-2008 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #include @@ -457,6 +457,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, "symlink to netdev!\n"); } dev->ieee80211_ptr->netdev = dev; +#ifdef CONFIG_WIRELESS_EXT + dev->ieee80211_ptr->wext.default_key = -1; + dev->ieee80211_ptr->wext.default_mgmt_key = -1; +#endif mutex_unlock(&rdev->devlist_mtx); break; case NETDEV_GOING_DOWN: diff --git a/net/wireless/core.h b/net/wireless/core.h index 3e49d33..f14b6c5 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -1,7 +1,7 @@ /* * Wireless configuration interface internals. * - * Copyright 2006, 2007 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #ifndef __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H @@ -151,4 +151,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); +/* internal helpers */ +int cfg80211_validate_key_settings(struct key_params *params, int key_idx, + const u8 *mac_addr); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a39e464..f88dbbe 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1,7 +1,7 @@ /* * This is the new netlink-based wireless configuration interface. * - * Copyright 2006, 2007 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #include @@ -1073,6 +1073,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) } err = func(&drv->wiphy, dev, key_idx); +#ifdef CONFIG_WIRELESS_EXT + if (!err) { + if (func == drv->ops->set_default_key) + dev->ieee80211_ptr->wext.default_key = key_idx; + else + dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; + } +#endif out: cfg80211_put_dev(drv); @@ -1111,45 +1119,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (key_idx > 5) + if (cfg80211_validate_key_settings(¶ms, key_idx, mac_addr)) return -EINVAL; - /* - * Disallow pairwise keys with non-zero index unless it's WEP - * (because current deployments use pairwise WEP keys with - * non-zero indizes but 802.11i clearly specifies to use zero) - */ - if (mac_addr && key_idx && - params.cipher != WLAN_CIPHER_SUITE_WEP40 && - params.cipher != WLAN_CIPHER_SUITE_WEP104) - return -EINVAL; - - /* TODO: add definitions for the lengths to linux/ieee80211.h */ - switch (params.cipher) { - case WLAN_CIPHER_SUITE_WEP40: - if (params.key_len != 5) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_TKIP: - if (params.key_len != 32) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_CCMP: - if (params.key_len != 16) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_WEP104: - if (params.key_len != 13) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - if (params.key_len != 16) - return -EINVAL; - break; - default: - return -EINVAL; - } - rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -1210,6 +1182,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); +#ifdef CONFIG_WIRELESS_EXT + if (!err) { + if (key_idx == dev->ieee80211_ptr->wext.default_key) + dev->ieee80211_ptr->wext.default_key = -1; + else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key) + dev->ieee80211_ptr->wext.default_mgmt_key = -1; + } +#endif + out: cfg80211_put_dev(drv); dev_put(dev); diff --git a/net/wireless/util.c b/net/wireless/util.c index 5f7e997..beb226e 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -138,3 +138,48 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) if (wiphy->bands[band]) set_mandatory_flags_band(wiphy->bands[band], band); } + +int cfg80211_validate_key_settings(struct key_params *params, int key_idx, + const u8 *mac_addr) +{ + if (key_idx > 5) + return -EINVAL; + + /* + * Disallow pairwise keys with non-zero index unless it's WEP + * (because current deployments use pairwise WEP keys with + * non-zero indizes but 802.11i clearly specifies to use zero) + */ + if (mac_addr && key_idx && + params->cipher != WLAN_CIPHER_SUITE_WEP40 && + params->cipher != WLAN_CIPHER_SUITE_WEP104) + return -EINVAL; + + /* TODO: add definitions for the lengths to linux/ieee80211.h */ + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + if (params->key_len != 5) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_TKIP: + if (params->key_len != 32) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_CCMP: + if (params->key_len != 16) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_WEP104: + if (params->key_len != 13) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + if (params->key_len != 16) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index abf6b0a..ffc98a8 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -5,12 +5,13 @@ * into cfg80211, when that happens all the exports here go away and * we directly assign the wireless handlers of wireless interfaces. * - * Copyright 2008 Johannes Berg + * Copyright 2008-2009 Johannes Berg */ #include #include #include +#include #include #include #include "core.h" @@ -477,3 +478,257 @@ int cfg80211_wext_giwretry(struct net_device *dev, return 0; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); + +static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *addr, + bool remove, bool tx_key, int idx, + struct key_params *params) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + if (!rdev->ops->set_default_mgmt_key) + return -EOPNOTSUPP; + + if (idx < 4 || idx > 5) + return -EINVAL; + } else if (idx < 0 || idx > 3) + return -EINVAL; + + if (remove) { + err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); + if (!err) { + if (idx == wdev->wext.default_key) + wdev->wext.default_key = -1; + else if (idx == wdev->wext.default_mgmt_key) + wdev->wext.default_mgmt_key = -1; + } + return err; + } else { + if (addr) + tx_key = false; + + if (cfg80211_validate_key_settings(params, idx, addr)) + return -EINVAL; + + err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); + if (err) + return err; + + if (tx_key || (!addr && wdev->wext.default_key == -1)) { + err = rdev->ops->set_default_key(&rdev->wiphy, + dev, idx); + if (!err) + wdev->wext.default_key = idx; + return err; + } + + if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && + (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { + err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, + dev, idx); + if (!err) + wdev->wext.default_mgmt_key = idx; + return err; + } + + return 0; + } +} + +int cfg80211_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int idx, err; + bool remove = false; + struct key_params params; + + /* no use -- only MFP (set_default_mgmt_key) is optional */ + if (!rdev->ops->del_key || + !rdev->ops->add_key || + !rdev->ops->set_default_key) + return -EOPNOTSUPP; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + idx = wdev->wext.default_key; + if (idx < 0) + idx = 0; + } else if (idx < 1 || idx > 4) + return -EINVAL; + else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = true; + else if (erq->length == 0) { + /* No key data - just set the default TX key index */ + err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); + if (!err) + wdev->wext.default_key = idx; + return err; + } + + memset(¶ms, 0, sizeof(params)); + params.key = keybuf; + params.key_len = erq->length; + if (erq->length == 5) + params.cipher = WLAN_CIPHER_SUITE_WEP40; + else if (erq->length == 13) + params.cipher = WLAN_CIPHER_SUITE_WEP104; + else if (!remove) + return -EINVAL; + + return cfg80211_set_encryption(rdev, dev, NULL, remove, + wdev->wext.default_key == -1, + idx, ¶ms); +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode); + +int cfg80211_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + const u8 *addr; + int idx; + bool remove = false; + struct key_params params; + u32 cipher; + + /* no use -- only MFP (set_default_mgmt_key) is optional */ + if (!rdev->ops->del_key || + !rdev->ops->add_key || + !rdev->ops->set_default_key) + return -EOPNOTSUPP; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + remove = true; + cipher = 0; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len == 5) + cipher = WLAN_CIPHER_SUITE_WEP40; + else if (ext->key_len == 13) + cipher = WLAN_CIPHER_SUITE_WEP104; + else + return -EINVAL; + break; + case IW_ENCODE_ALG_TKIP: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case IW_ENCODE_ALG_AES_CMAC: + cipher = WLAN_CIPHER_SUITE_AES_CMAC; + break; + default: + return -EOPNOTSUPP; + } + + if (erq->flags & IW_ENCODE_DISABLED) + remove = true; + + idx = erq->flags & IW_ENCODE_INDEX; + if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + if (idx < 4 || idx > 5) { + idx = wdev->wext.default_mgmt_key; + if (idx < 0) + return -EINVAL; + } else + idx--; + } else { + if (idx < 1 || idx > 4) { + idx = wdev->wext.default_key; + if (idx < 0) + return -EINVAL; + } else + idx--; + } + + addr = ext->addr.sa_data; + if (is_broadcast_ether_addr(addr)) + addr = NULL; + + memset(¶ms, 0, sizeof(params)); + params.key = ext->key; + params.key_len = ext->key_len; + params.cipher = cipher; + + return cfg80211_set_encryption( + rdev, dev, addr, remove, + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, + idx, ¶ms); +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); + +struct giwencode_cookie { + size_t buflen; + char *keybuf; +}; + +static void giwencode_get_key_cb(void *cookie, struct key_params *params) +{ + struct giwencode_cookie *data = cookie; + + if (!params->key) { + data->buflen = 0; + return; + } + + data->buflen = min_t(size_t, data->buflen, params->key_len); + memcpy(data->keybuf, params->key, data->buflen); +} + +int cfg80211_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int idx, err; + struct giwencode_cookie data = { + .keybuf = keybuf, + .buflen = erq->length, + }; + + if (!rdev->ops->get_key) + return -EOPNOTSUPP; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + idx = wdev->wext.default_key; + if (idx < 0) + idx = 0; + } else if (idx < 1 || idx > 4) + return -EINVAL; + else + idx--; + + erq->flags = idx + 1; + + err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data, + giwencode_get_key_cb); + if (!err) { + erq->length = data.buflen; + erq->flags |= IW_ENCODE_ENABLED; + return 0; + } + + if (err == -ENOENT) { + erq->flags |= IW_ENCODE_DISABLED; + erq->length = 0; + return 0; + } + + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); -- cgit v0.10.2 From 0e46724a48fcc3bac1fecea413d20af64a75844f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 May 2009 21:57:55 +0300 Subject: nl80211: Validate MFP flag type when parsing STA flags NL80211_STA_FLAG_MFP was forgotten from sta_flags_policy. The previous version added the flag due to the loop used in parse_station_flags, but the proper behavior would be to allow nla_parse_nested() to go through the policy for all flags. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f88dbbe..2353ddb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1331,6 +1331,7 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, }; static int parse_station_flags(struct nlattr *nla, u32 *staflags) -- cgit v0.10.2 From eccb8e8f0c3af47aeb6dbe4012eb8d4fc888767a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 May 2009 21:57:56 +0300 Subject: nl80211: improve station flags handling It is currently not possible to modify station flags, but that capability would be very useful. This patch introduces a new nl80211 attribute that contains a set/mask for station flags, and updates the internal API (and mac80211) to mirror that. The new attribute is parsed before falling back to the old so that userspace can specify both (if it can) to work on all kernels. Signed-off-by: Johannes Berg Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 58c4ee1..aeefccf 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -25,6 +25,8 @@ * */ +#include + /** * DOC: Station handling * @@ -380,7 +382,7 @@ enum nl80211_commands { * * @NL80211_ATTR_STA_AID: Association ID for the station (u16) * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of - * &enum nl80211_sta_flags. + * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2) * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by * IEEE 802.11 7.3.1.6 (u16). * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported @@ -499,6 +501,9 @@ enum nl80211_commands { * this attribute can be used * with %NL80211_CMD_ASSOCIATE request * + * @NL80211_ATTR_STA_FLAGS2: Attribute containing a + * &struct nl80211_sta_flag_update. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -603,6 +608,8 @@ enum nl80211_attrs { NL80211_ATTR_USE_MFP, + NL80211_ATTR_STA_FLAGS2, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -692,6 +699,18 @@ enum nl80211_sta_flags { }; /** + * struct nl80211_sta_flag_update - station flags mask/set + * @mask: mask of station flags to set + * @set: which values to set them to + * + * Both mask and set contain bits as per &enum nl80211_sta_flags. + */ +struct nl80211_sta_flag_update { + __u32 mask; + __u32 set; +} __attribute__((packed)); + +/** * enum nl80211_rate_info - bitrate information * * These attribute types are used with %NL80211_STA_INFO_TXRATE diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e69e6c6..0dae6b3 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -252,27 +252,6 @@ struct beacon_parameters { }; /** - * enum station_flags - station flags - * - * Station capability flags. Note that these must be the bits - * according to the nl80211 flags. - * - * @STATION_FLAG_CHANGED: station flags were changed - * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X) - * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames - * with short preambles - * @STATION_FLAG_WME: station is WME/QoS capable - * @STATION_FLAG_MFP: station uses management frame protection - */ -enum station_flags { - STATION_FLAG_CHANGED = 1<<0, - STATION_FLAG_AUTHORIZED = 1<sdata; + u32 mask, set; sband = local->hw.wiphy->bands[local->oper_channel->band]; - /* - * FIXME: updating the flags is racy when this function is - * called from ieee80211_change_station(), this will - * be resolved in a future patch. - */ + spin_lock_bh(&sta->lock); + mask = params->sta_flags_mask; + set = params->sta_flags_set; - if (params->station_flags & STATION_FLAG_CHANGED) { - spin_lock_bh(&sta->lock); + if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { sta->flags &= ~WLAN_STA_AUTHORIZED; - if (params->station_flags & STATION_FLAG_AUTHORIZED) + if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) sta->flags |= WLAN_STA_AUTHORIZED; + } + if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; - if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) + if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) sta->flags |= WLAN_STA_SHORT_PREAMBLE; + } + if (mask & BIT(NL80211_STA_FLAG_WME)) { sta->flags &= ~WLAN_STA_WME; - if (params->station_flags & STATION_FLAG_WME) + if (set & BIT(NL80211_STA_FLAG_WME)) sta->flags |= WLAN_STA_WME; + } + if (mask & BIT(NL80211_STA_FLAG_MFP)) { sta->flags &= ~WLAN_STA_MFP; - if (params->station_flags & STATION_FLAG_MFP) + if (set & BIT(NL80211_STA_FLAG_MFP)) sta->flags |= WLAN_STA_MFP; - spin_unlock_bh(&sta->lock); } + spin_unlock_bh(&sta->lock); /* * FIXME: updating the following information is racy when this diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2353ddb..66024ef 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -123,6 +123,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, + [NL80211_ATTR_STA_FLAGS2] = { + .len = sizeof(struct nl80211_sta_flag_update), + }, }; /* IE validation */ @@ -1334,13 +1337,33 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, }; -static int parse_station_flags(struct nlattr *nla, u32 *staflags) +static int parse_station_flags(struct genl_info *info, + struct station_parameters *params) { struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; + struct nlattr *nla; int flag; - *staflags = 0; + /* + * Try parsing the new attribute first so userspace + * can specify both for older kernels. + */ + nla = info->attrs[NL80211_ATTR_STA_FLAGS2]; + if (nla) { + struct nl80211_sta_flag_update *sta_flags; + + sta_flags = nla_data(nla); + params->sta_flags_mask = sta_flags->mask; + params->sta_flags_set = sta_flags->set; + if ((params->sta_flags_mask | + params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) + return -EINVAL; + return 0; + } + + /* if present, parse the old attribute */ + nla = info->attrs[NL80211_ATTR_STA_FLAGS]; if (!nla) return 0; @@ -1348,11 +1371,12 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) nla, sta_flags_policy)) return -EINVAL; - *staflags = STATION_FLAG_CHANGED; + params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1; + params->sta_flags_mask &= ~1; for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) if (flags[flag]) - *staflags |= (1<sta_flags_set |= (1<attrs[NL80211_ATTR_HT_CAPABILITY]); - if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], - ¶ms.station_flags)) + if (parse_station_flags(info, ¶ms)) return -EINVAL; if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) @@ -1718,8 +1741,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); - if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], - ¶ms.station_flags)) + if (parse_station_flags(info, ¶ms)) return -EINVAL; rtnl_lock(); -- cgit v0.10.2 From 3f77316c6b99f596bfbf72c0542f47f7230b702e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 May 2009 21:57:57 +0300 Subject: nl80211: Add IEEE 802.1X PAE control for station mode Add a new NL80211_ATTR_CONTROL_PORT flag for NL80211_CMD_ASSOCIATE to allow user space to indicate that it will control the IEEE 802.1X port in station mode. Previously, mac80211 was always marking the port authorized in station mode. This was enough when drop_unencrypted flag was set. However, drop_unencrypted can currently be controlled only with WEXT and the current nl80211 design does not allow fully secure configuration. Fix this by providing a mechanism for user space to control the IEEE 802.1X port in station mode (i.e., do the same that we are already doing in AP mode). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index aeefccf..2781525 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -504,6 +504,13 @@ enum nl80211_commands { * @NL80211_ATTR_STA_FLAGS2: Attribute containing a * &struct nl80211_sta_flag_update. * + * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls + * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in + * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE + * request, the driver will assume that the port is unauthorized until + * authorized by user space. Otherwise, port is marked authorized by + * default in station mode. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -610,6 +617,8 @@ enum nl80211_attrs { NL80211_ATTR_STA_FLAGS2, + NL80211_ATTR_CONTROL_PORT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0dae6b3..9e17a83 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -655,6 +655,10 @@ struct cfg80211_auth_request { * @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie_len: Length of ie buffer in octets * @use_mfp: Use management frame protection (IEEE 802.11w) in this association + * @control_port: Whether user space controls IEEE 802.1X port, i.e., + * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is + * required to assume that the port is unauthorized until authorized by + * user space. Otherwise, port is marked authorized by default. */ struct cfg80211_assoc_request { struct ieee80211_channel *chan; @@ -664,6 +668,7 @@ struct cfg80211_assoc_request { const u8 *ie; size_t ie_len; bool use_mfp; + bool control_port; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d591a93..6464bfd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1265,6 +1265,11 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; } + if (req->control_port) + sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; + else + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; + sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; ieee80211_sta_req_auth(sdata); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 081c574..56a49ef 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -235,7 +235,7 @@ struct mesh_preq_queue { #define IEEE80211_STA_ASSOCIATED BIT(4) #define IEEE80211_STA_PROBEREQ_POLL BIT(5) #define IEEE80211_STA_CREATE_IBSS BIT(6) -/* hole at 7, please re-use */ +#define IEEE80211_STA_CONTROL_PORT BIT(7) #define IEEE80211_STA_WMM_ENABLED BIT(8) /* hole at 9, please re-use */ #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6d00e3f..2806f6a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1581,8 +1581,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * to between the sta_info_alloc() and sta_info_insert() above. */ - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | - WLAN_STA_AUTHORIZED); + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); + if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + set_sta_flags(sta, WLAN_STA_AUTHORIZED); rates = 0; basic_rates = 0; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index d845026..c143947 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -41,6 +41,7 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, return ret; sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; ieee80211_sta_req_auth(sdata); return 0; } @@ -124,6 +125,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, return ret; sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; ieee80211_sta_req_auth(sdata); return 0; } @@ -181,6 +183,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, if (ret) return ret; sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; ieee80211_sta_req_auth(sdata); return 0; } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 66024ef..cad2813 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -126,6 +126,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_STA_FLAGS2] = { .len = sizeof(struct nl80211_sta_flag_update), }, + [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, }; /* IE validation */ @@ -3040,6 +3041,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) } } + req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; + err = drv->ops->assoc(&drv->wiphy, dev, &req); out: -- cgit v0.10.2 From faa8fdc85347cc76d87b43ea718785661c54f656 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 May 2009 21:57:58 +0300 Subject: nl80211: Add RSC configuration for new keys When setting a key with NL80211_CMD_NEW_KEY, we should allow the key sequence number (RSC) to be set in order to allow replay protection to work correctly for group keys. This patch documents this use for nl80211 and adds the couple of missing pieces in nl80211/cfg80211 and mac80211 to support this. In addition, WEXT SIOCSIWENCODEEXT compat processing in cfg80211 is extended to handle the RSC (this was already specified in WEXT, but just not implemented in cfg80211/mac80211). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2781525..dbea93b 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -79,8 +79,8 @@ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, - * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER - * attributes. + * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER, + * and %NL80211_ATTR_KEY_SEQ attributes. * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX * or %NL80211_ATTR_MAC. * diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6464bfd..77e9ff5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -141,7 +141,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } - key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); + key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key, + params->seq_len, params->seq); if (!key) return -ENOMEM; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b7e1350..827ea8e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -290,9 +290,11 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, - const u8 *key_data) + const u8 *key_data, + size_t seq_len, const u8 *seq) { struct ieee80211_key *key; + int i, j; BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); @@ -318,14 +320,31 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, case ALG_TKIP: key->conf.iv_len = TKIP_IV_LEN; key->conf.icv_len = TKIP_ICV_LEN; + if (seq && seq_len == 6) { + for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { + key->u.tkip.rx[i].iv32 = + get_unaligned_le32(&seq[2]); + key->u.tkip.rx[i].iv16 = + get_unaligned_le16(seq); + } + } break; case ALG_CCMP: key->conf.iv_len = CCMP_HDR_LEN; key->conf.icv_len = CCMP_MIC_LEN; + if (seq && seq_len == CCMP_PN_LEN) { + for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (j = 0; j < CCMP_PN_LEN; j++) + key->u.ccmp.rx_pn[i][j] = + seq[CCMP_PN_LEN - j - 1]; + } break; case ALG_AES_CMAC: key->conf.iv_len = 0; key->conf.icv_len = sizeof(struct ieee80211_mmie); + if (seq && seq_len == 6) + for (j = 0; j < 6; j++) + key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; break; } memcpy(key->conf.key, key_data, key_len); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 215d3ef..9572e00 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -144,7 +144,8 @@ struct ieee80211_key { struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, - const u8 *key_data); + const u8 *key_data, + size_t seq_len, const u8 *seq); /* * Insert a key into data structures (sdata, sta if necessary) * to make it used, free old key. diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cad2813..f0fec2f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1115,6 +1115,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); } + if (info->attrs[NL80211_ATTR_KEY_SEQ]) { + params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); + params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); + } + if (info->attrs[NL80211_ATTR_KEY_IDX]) key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index ffc98a8..f98090b 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -663,6 +663,11 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, params.key_len = ext->key_len; params.cipher = cipher; + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + params.seq = ext->rx_seq; + params.seq_len = 6; + } + return cfg80211_set_encryption( rdev, dev, addr, remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, -- cgit v0.10.2 From f7eef3563cb3f05e7f0db992716c514af6f4d089 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 May 2009 08:36:43 +0200 Subject: wext: remove seq_start/stop sparse annotations Even though they are true, they cause sparse to complain because it doesn't see the __acquires(dev_base_lock) on dev_seq_start() because it is only added to the function in net/core/dev.c, not the header file. To keep track of the nesting correctly we should probably annotate those functions publically, but for now let's just remove the annotation I added to wext. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext.c b/net/wireless/wext.c index dc5b47e..d3bbef7 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -650,14 +650,12 @@ static int wireless_seq_show(struct seq_file *seq, void *v) } static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) { rtnl_lock(); return dev_seq_start(seq, pos); } static void wireless_dev_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) { dev_seq_stop(seq, v); rtnl_unlock(); -- cgit v0.10.2 From 34bfc411f63c8b0efb328b7574fc97bc1714cb29 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 May 2009 19:58:12 +0200 Subject: mac80211: respond to beacon loss report only once The driver might keep reporting beacon loss until we disassociate -- catch that and don't respond to any subsequent events until the probe is either successful or we disassociate. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2806f6a..7835e7d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1182,6 +1182,17 @@ void ieee80211_beacon_loss_work(struct work_struct *work) u.mgd.beacon_loss_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + /* + * The driver has already reported this event and we have + * already sent a probe request. Maybe the AP died and the + * driver keeps reporting until we disassociate... We have + * to ignore that because otherwise we would continually + * reset the timer and never check whether we received a + * probe response! + */ + if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) + return; + #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " -- cgit v0.10.2 From e0502de6fe85b66ee51647eb75bc5af3c885d712 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 May 2009 20:11:26 +0200 Subject: mac80211: split out and decrease probe wait time The time we wait for a probe response after probing an AP due to beacon loss is currently the same as the monitoring interval, 2s. This is far too long, APs should respond to probes within a fraction of that time. To be able to adjust both values, add a new constant IEEE80211_PROBE_WAIT, use it for checking the probe response, and adjust it down to 200ms instead of 2 seconds. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7835e7d..ae03068 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -33,6 +33,7 @@ #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MONITORING_INTERVAL (2 * HZ) +#define IEEE80211_PROBE_WAIT (HZ / 20) #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) @@ -1205,7 +1206,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); + mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); } void ieee80211_beacon_loss(struct ieee80211_vif *vif) @@ -1242,7 +1243,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) } if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && - time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { + time_after(jiffies, sta->last_rx + IEEE80211_PROBE_WAIT)) { printk(KERN_DEBUG "%s: no probe response from AP %pM " "- disassociating\n", sdata->dev->name, ifmgd->bssid); -- cgit v0.10.2 From e0d61887c2ee19bb63f6a8c0e2c149184e879501 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 May 2009 20:47:32 +0200 Subject: mac80211: don't connect to IBSS network with different privacy Even when we find an IBSS with the SSID we're looking for, we may not be able to connect to it because it has a key and we don't, or vice versa. Avoid such situations by checking the privacy capability bit. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index aa53768..c94a695 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -499,6 +499,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) struct ieee80211_channel *chan = NULL; const u8 *bssid = NULL; int active_ibss; + u16 capability; active_ibss = ieee80211_sta_active_ibss(sdata); #ifdef CONFIG_MAC80211_IBSS_DEBUG @@ -509,6 +510,10 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) if (active_ibss) return; + capability = WLAN_CAPABILITY_IBSS; + if (sdata->default_key) + capability |= WLAN_CAPABILITY_PRIVACY; + if (ifibss->fixed_bssid) bssid = ifibss->bssid; if (ifibss->fixed_channel) @@ -517,8 +522,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) bssid = ifibss->bssid; bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, ifibss->ssid, ifibss->ssid_len, - WLAN_CAPABILITY_IBSS, - WLAN_CAPABILITY_IBSS); + capability, + WLAN_CAPABILITY_IBSS | + WLAN_CAPABILITY_PRIVACY); #ifdef CONFIG_MAC80211_IBSS_DEBUG if (bss) -- cgit v0.10.2 From b59066a291ca7c12a1e5b58f3ada5ab6e32cb6bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 May 2009 21:18:38 +0200 Subject: mac80211: IBSS supported rate fixes Currently mac80211 announces a rate set with no basic rates, this fixes it to use 1/2 or 6/9 Mbit as basic rates by default. Additionally, mac80211 will currently adopt the peer's entire rate set, rather than just the basic rate set; fix that too. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c94a695..c236079 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -63,19 +63,18 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, const u8 *bssid, const int beacon_int, struct ieee80211_channel *chan, - const size_t supp_rates_len, - const u8 *supp_rates, + const u32 basic_rates, const u16 capability, u64 tsf) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; - int rates, i, j; + int rates, i; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos; struct ieee80211_supported_band *sband; u32 bss_change; - + u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; /* Reset own TSF to allow time synchronization work. */ drv_reset_tsf(local); @@ -101,6 +100,16 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sband = local->hw.wiphy->bands[chan->band]; + /* build supported rates array */ + pos = supp_rates; + for (i = 0; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; + u8 basic = 0; + if (basic_rates & BIT(i)) + basic = 0x80; + *pos++ = basic | (u8) (rate / 5); + } + /* Build IBSS probe response */ mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); @@ -118,7 +127,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, *pos++ = ifibss->ssid_len; memcpy(pos, ifibss->ssid, ifibss->ssid_len); - rates = supp_rates_len; + rates = sband->n_bitrates; if (rates > 8) rates = 8; pos = skb_put(skb, 2 + rates); @@ -140,8 +149,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, *pos++ = 0; *pos++ = 0; - if (supp_rates_len > 8) { - rates = supp_rates_len - 8; + if (sband->n_bitrates > 8) { + rates = sband->n_bitrates - 8; pos = skb_put(skb, 2 + rates); *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos++ = rates; @@ -162,15 +171,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, bss_change |= BSS_CHANGED_BEACON_ENABLED; ieee80211_bss_info_change_notify(sdata, bss_change); - rates = 0; - for (i = 0; i < supp_rates_len; i++) { - int bitrate = (supp_rates[i] & 0x7f) * 5; - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == bitrate) - rates |= BIT(j); - } - - ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); + ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); ifibss->state = IEEE80211_IBSS_MLME_JOINED; mod_timer(&ifibss->timer, @@ -184,15 +185,35 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss) { + struct ieee80211_supported_band *sband; + u32 basic_rates; + int i, j; u16 beacon_int = bss->cbss.beacon_interval; if (beacon_int < 10) beacon_int = 10; + sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band]; + + basic_rates = 0; + + for (i = 0; i < bss->supp_rates_len; i++) { + int rate = (bss->supp_rates[i] & 0x7f) * 5; + bool is_basic = !!(bss->supp_rates[i] & 0x80); + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) { + if (is_basic) + basic_rates |= BIT(j); + break; + } + } + } + __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, beacon_int, bss->cbss.channel, - bss->supp_rates_len, bss->supp_rates, + basic_rates, bss->cbss.capability, bss->cbss.tsf); } @@ -449,9 +470,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - u8 *pos; u8 bssid[ETH_ALEN]; - u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; u16 capability; int i; @@ -480,15 +499,9 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) else sdata->drop_unencrypted = 0; - pos = supp_rates; - for (i = 0; i < sband->n_bitrates; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, - ifibss->channel, sband->n_bitrates, - supp_rates, capability, 0); + ifibss->channel, 3, /* first two are basic */ + capability, 0); } static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) -- cgit v0.10.2 From d3707d9918d47c0997a6b1e4ae24e7ab55e43796 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 May 2009 22:05:40 +0200 Subject: mac80211: make noack test available There's this internal wifi_wme_noack_test variable that we use to set the QoS control if set. For one, it is unlikely that it is set. Secondly, if set it needs to influence the IEEE80211_TX_CTL_NO_ACK TX control flag, and finally we should also be able to set it at all, so make it available in debugfs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index ac79320..e7682fe 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -135,6 +135,42 @@ static const struct file_operations reset_ops = { .open = mac80211_open_file_generic, }; +static ssize_t noack_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + int res; + char buf[10]; + + res = scnprintf(buf, sizeof(buf), "%d\n", local->wifi_wme_noack_test); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static ssize_t noack_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + char buf[10]; + size_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0); + + return count; +} + +static const struct file_operations noack_ops = { + .read = noack_read, + .write = noack_write, + .open = mac80211_open_file_generic +}; + /* statistics stuff */ #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ @@ -275,6 +311,7 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(wep_iv); DEBUGFS_ADD(tsf); DEBUGFS_ADD_MODE(reset, 0200); + DEBUGFS_ADD(noack); statsd = debugfs_create_dir("statistics", phyd); local->debugfs.statistics = statsd; @@ -330,6 +367,7 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_DEL(wep_iv); DEBUGFS_DEL(tsf); DEBUGFS_DEL(reset); + DEBUGFS_DEL(noack); DEBUGFS_STATS_DEL(transmitted_fragment_count); DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 56a49ef..9d15147 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -766,6 +766,7 @@ struct ieee80211_local { struct dentry *wep_iv; struct dentry *tsf; struct dentry *reset; + struct dentry *noack; struct dentry *statistics; struct local_debugfsdentries_statsdentries { struct dentry *transmitted_fragment_count; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5f9a8d7..8f68bf9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1087,7 +1087,10 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, info->flags |= IEEE80211_TX_CTL_NO_ACK; } else { tx->flags |= IEEE80211_TX_UNICAST; - info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + if (unlikely(local->wifi_wme_noack_test)) + info->flags |= IEEE80211_TX_CTL_NO_ACK; + else + info->flags &= ~IEEE80211_TX_CTL_NO_ACK; } if (tx->flags & IEEE80211_TX_FRAGMENTED) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 0b8ad1f4..45b74f3 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -133,7 +133,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) u8 *p = ieee80211_get_qos_ctl(hdr); u8 ack_policy = 0; tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; - if (local->wifi_wme_noack_test) + if (unlikely(local->wifi_wme_noack_test)) ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << QOS_CONTROL_ACK_POLICY_SHIFT; /* qos header is 2 bytes, second reserved */ -- cgit v0.10.2 From 8b3521eeb7598c3b10c7e14361a7974464527702 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Mon, 11 May 2009 05:52:49 +0000 Subject: ipv4: remove an unused parameter from configure method of fib_rules_ops. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index c2bb5ca..b9b6339 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -48,7 +48,6 @@ struct fib_rules_ops struct flowi *, int); int (*configure)(struct fib_rule *, struct sk_buff *, - struct nlmsghdr *, struct fib_rule_hdr *, struct nlattr **); int (*compare)(struct fib_rule *, diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 98691e1..17d9f49 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -299,7 +299,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) } else if (rule->action == FR_ACT_GOTO) goto errout_free; - err = ops->configure(rule, skb, nlh, frh, tb); + err = ops->configure(rule, skb, frh, tb); if (err < 0) goto errout_free; diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 14fbca5..a2690b1 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -115,7 +115,7 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) } static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh, + struct fib_rule_hdr *frh, struct nlattr **tb) { int err = -EINVAL; diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 6080d71..38904be 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -134,7 +134,7 @@ static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { }; static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh, + struct fib_rule_hdr *frh, struct nlattr **tb) { struct net *net = sock_net(skb->sk); diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index f5de3f9..e1a36db 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -151,7 +151,7 @@ static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = { }; static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh, + struct fib_rule_hdr *frh, struct nlattr **tb) { int err = -EINVAL; -- cgit v0.10.2 From 3a6d54c56326c29c5357655779cfe6cf36481b17 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 11 May 2009 23:37:15 +0000 Subject: net: remove needless (now buggy) & from dev->dev_addr Patch fixes issues with dev->dev_addr changing from array to pointer. Hopefully there are no others. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 8c2e5ab..06009dc 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1845,9 +1845,10 @@ static u16 aggregator_identifier; * Can be called only after the mac address of the bond is set. */ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast) -{ +{ // check that the bond is not initialized yet - if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) { + if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), + bond->dev->dev_addr)) { aggregator_identifier = 0; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 7902e5e..53af71a 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1374,8 +1374,8 @@ static void ibmveth_proc_unregister_driver(void) static int ibmveth_show(struct seq_file *seq, void *v) { struct ibmveth_adapter *adapter = seq->private; - char *current_mac = ((char*) &adapter->netdev->dev_addr); - char *firmware_mac = ((char*) &adapter->mac_addr) ; + char *current_mac = (char *) adapter->netdev->dev_addr; + char *firmware_mac = (char *) &adapter->mac_addr; seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version); diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 3dad1cf..ff9b5c8 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -1423,7 +1423,7 @@ static int prism2_hw_init2(struct net_device *dev, int initial) prism2_check_sta_fw_version(local); if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, - &dev->dev_addr, 6, 1) < 0) { + dev->dev_addr, 6, 1) < 0) { printk("%s: could not get own MAC address\n", dev->name); } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index fa90d1d..22e7185 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -892,7 +892,7 @@ static int ray_dev_init(struct net_device *dev) #endif /* RAY_IMMEDIATE_INIT */ /* copy mac and broadcast addresses to linux device */ - memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); + memcpy(dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); memset(dev->broadcast, 0xff, ETH_ALEN); DEBUG(2, "ray_dev_init ending\n"); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d994c55..af256d4 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1100,8 +1100,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) struct ip6_tnl_parm *p = &t->parms; struct flowi *fl = &t->fl; - memcpy(&dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); - memcpy(&dev->broadcast, &p->raddr, sizeof(struct in6_addr)); + memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); + memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); /* Set up flowi template */ ipv6_addr_copy(&fl->fl6_src, &p->laddr); diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index f72ba77..524ba56 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -167,7 +167,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) tb_ptr->mtu = dev->mtu; tb_ptr->blocked = 0; tb_ptr->addr.type = htonl(TIPC_MEDIA_TYPE_ETH); - memcpy(&tb_ptr->addr.dev_addr, &dev->dev_addr, ETH_ALEN); + memcpy(&tb_ptr->addr.dev_addr, dev->dev_addr, ETH_ALEN); return 0; } -- cgit v0.10.2 From cb1c4b71f6da18fa98bab4af055f391d01bee8ba Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Tue, 12 May 2009 10:47:33 +0000 Subject: cls_cgroup: remove unneeded cgroup_lock We can remove this lock here, since we are in cgroup write handler and thus the cgrp is guaranteed to be valid, and no lock is needed when writing a u32 variable. Signed-off-by: Li Zefan Acked-by: Paul Menage Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 91a3db4..1ab4542 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -62,13 +62,7 @@ static u64 read_classid(struct cgroup *cgrp, struct cftype *cft) static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value) { - if (!cgroup_lock_live_group(cgrp)) - return -ENODEV; - cgrp_cls_state(cgrp)->classid = (u32) value; - - cgroup_unlock(); - return 0; } -- cgit v0.10.2 From 3977d0334b98770b81dfeb248db232c9bb3d3c88 Mon Sep 17 00:00:00 2001 From: Mike Travis Date: Tue, 12 May 2009 10:48:36 +0000 Subject: sfc: modify allocation error message Change error message when alloc_cpumask_var fails. Repairs "cpumask: convert drivers/net/sfc". Signed-off-by: Mike Travis Acked-by: Ben Hutchings Acked-by: David S. Miller Cc: Rusty Russell Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d3e240b..bde8b7a 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -894,9 +894,9 @@ static int efx_wanted_rx_queues(void) int count; int cpu; - if (!alloc_cpumask_var(&core_mask, GFP_KERNEL)) { + if (unlikely(!alloc_cpumask_var(&core_mask, GFP_KERNEL))) { printk(KERN_WARNING - "efx.c: allocation failure, irq balancing hobbled\n"); + "sfc: RSS disabled due to allocation failure\n"); return 1; } -- cgit v0.10.2 From 3699a1c7d42f9a694bb512d91ca457f363a48e38 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 May 2009 10:48:37 +0000 Subject: drivers/net/82596.c: suppress warnings i386 allmodconfig: drivers/net/82596.c: In function 'init_rx_bufs': drivers/net/82596.c:544: warning: cast to pointer from integer of different size drivers/net/82596.c:545: warning: cast to pointer from integer of different size drivers/net/82596.c:548: warning: cast to pointer from integer of different size drivers/net/82596.c:557: warning: cast to pointer from integer of different size drivers/net/82596.c:565: warning: cast to pointer from integer of different size drivers/net/82596.c:569: warning: cast to pointer from integer of different size drivers/net/82596.c:575: warning: cast to pointer from integer of different size drivers/net/82596.c: In function 'rebuild_rx_bufs': drivers/net/82596.c:606: warning: cast to pointer from integer of different size drivers/net/82596.c:608: warning: cast to pointer from integer of different size drivers/net/82596.c: In function 'init_i596_mem': drivers/net/82596.c:680: warning: cast to pointer from integer of different size drivers/net/82596.c:681: warning: cast to pointer from integer of different size drivers/net/82596.c: In function 'i596_rx': drivers/net/82596.c:818: warning: cast to pointer from integer of different size drivers/net/82596.c: In function 'i596_add_cmd': drivers/net/82596.c:975: warning: cast to pointer from integer of different size drivers/net/82596.c:979: warning: cast to pointer from integer of different size drivers/net/82596.c: In function 'i596_start_xmit': drivers/net/82596.c:1088: warning: cast to pointer from integer of different size drivers/net/82596.c:1099: warning: cast to pointer from integer of different size drivers/net/82596.c: In function 'i596_interrupt': drivers/net/82596.c:1404: warning: cast to pointer from integer of different size (ugh) Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/net/82596.c b/drivers/net/82596.c index cca94b9..7754754 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -122,13 +122,13 @@ static char version[] __initdata = #define ISCP_BUSY 0x00010000 #define MACH_IS_APRICOT 0 #else -#define WSWAPrfd(x) ((struct i596_rfd *)(x)) -#define WSWAPrbd(x) ((struct i596_rbd *)(x)) -#define WSWAPiscp(x) ((struct i596_iscp *)(x)) -#define WSWAPscb(x) ((struct i596_scb *)(x)) -#define WSWAPcmd(x) ((struct i596_cmd *)(x)) -#define WSWAPtbd(x) ((struct i596_tbd *)(x)) -#define WSWAPchar(x) ((char *)(x)) +#define WSWAPrfd(x) ((struct i596_rfd *)((long)x)) +#define WSWAPrbd(x) ((struct i596_rbd *)((long)x)) +#define WSWAPiscp(x) ((struct i596_iscp *)((long)x)) +#define WSWAPscb(x) ((struct i596_scb *)((long)x)) +#define WSWAPcmd(x) ((struct i596_cmd *)((long)x)) +#define WSWAPtbd(x) ((struct i596_tbd *)((long)x)) +#define WSWAPchar(x) ((char *)((long)x)) #define ISCP_BUSY 0x0001 #define MACH_IS_APRICOT 1 #endif -- cgit v0.10.2 From a186d2aead8beb164ddb76245d189c66f7021b59 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2009 22:40:12 +0000 Subject: net: remove needless (now buggy) & from dev->dev_addr (part2) Missed part of "&" removal. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index febae70..9208cf5 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -935,7 +935,7 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, if (llc->dev) { sllc.sllc_arphrd = llc->dev->type; - memcpy(&sllc.sllc_mac, &llc->dev->dev_addr, + memcpy(&sllc.sllc_mac, llc->dev->dev_addr, IFHWADDRLEN); } } -- cgit v0.10.2 From 952ee9df26c487f2d73b2dced58ec904f19ea0f8 Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Wed, 13 May 2009 06:04:58 +0000 Subject: mv643xx_eth: Remove a stale PPC_MULTIPLATFORM PPC_MULTIPLATFORM was killed in commit 28794d3 but this stale occurrence was hiding the mv643xx_eth driver in some cases (e.g. Pegasos II) Signed-off-by: Emil Medve Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b8727d5..48b73b0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1,4 +1,3 @@ - # # Network device configuration # @@ -2351,7 +2350,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 + depends on MV64360 || MV64X60 || PPC32 || PLAT_ORION select INET_LRO select PHYLIB help -- cgit v0.10.2 From bff66176bb47b2cf3331d9e42d37ea4094826756 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:09:39 +0000 Subject: ixgbe: Add FCoE feature register defines to 82599 This adds FCoE related register defines to 82599. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 9fd79a0..c2d9ed5 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -478,6 +478,63 @@ #define IXGBE_RTTDTECC_NO_BCN 0x00000100 #define IXGBE_RTTBCNRC 0x04984 +/* FCoE registers */ +#define IXGBE_FCPTRL 0x02410 /* FC User Desc. PTR Low */ +#define IXGBE_FCPTRH 0x02414 /* FC USer Desc. PTR High */ +#define IXGBE_FCBUFF 0x02418 /* FC Buffer Control */ +#define IXGBE_FCDMARW 0x02420 /* FC Receive DMA RW */ +#define IXGBE_FCINVST0 0x03FC0 /* FC Invalid DMA Context Status Reg 0 */ +#define IXGBE_FCINVST(_i) (IXGBE_FCINVST0 + ((_i) * 4)) +#define IXGBE_FCBUFF_VALID (1 << 0) /* DMA Context Valid */ +#define IXGBE_FCBUFF_BUFFSIZE (3 << 3) /* User Buffer Size */ +#define IXGBE_FCBUFF_WRCONTX (1 << 7) /* 0: Initiator, 1: Target */ +#define IXGBE_FCBUFF_BUFFCNT 0x0000ff00 /* Number of User Buffers */ +#define IXGBE_FCBUFF_OFFSET 0xffff0000 /* User Buffer Offset */ +#define IXGBE_FCBUFF_BUFFSIZE_SHIFT 3 +#define IXGBE_FCBUFF_BUFFCNT_SHIFT 8 +#define IXGBE_FCBUFF_OFFSET_SHIFT 16 +#define IXGBE_FCDMARW_WE (1 << 14) /* Write enable */ +#define IXGBE_FCDMARW_RE (1 << 15) /* Read enable */ +#define IXGBE_FCDMARW_FCOESEL 0x000001ff /* FC X_ID: 11 bits */ +#define IXGBE_FCDMARW_LASTSIZE 0xffff0000 /* Last User Buffer Size */ +#define IXGBE_FCDMARW_LASTSIZE_SHIFT 16 + +/* FCoE SOF/EOF */ +#define IXGBE_TEOFF 0x04A94 /* Tx FC EOF */ +#define IXGBE_TSOFF 0x04A98 /* Tx FC SOF */ +#define IXGBE_REOFF 0x05158 /* Rx FC EOF */ +#define IXGBE_RSOFF 0x051F8 /* Rx FC SOF */ +/* FCoE Filter Context Registers */ +#define IXGBE_FCFLT 0x05108 /* FC FLT Context */ +#define IXGBE_FCFLTRW 0x05110 /* FC Filter RW Control */ +#define IXGBE_FCPARAM 0x051d8 /* FC Offset Parameter */ +#define IXGBE_FCFLT_VALID (1 << 0) /* Filter Context Valid */ +#define IXGBE_FCFLT_FIRST (1 << 1) /* Filter First */ +#define IXGBE_FCFLT_SEQID 0x00ff0000 /* Sequence ID */ +#define IXGBE_FCFLT_SEQCNT 0xff000000 /* Sequence Count */ +#define IXGBE_FCFLTRW_RVALDT (1 << 13) /* Fast Re-Validation */ +#define IXGBE_FCFLTRW_WE (1 << 14) /* Write Enable */ +#define IXGBE_FCFLTRW_RE (1 << 15) /* Read Enable */ +/* FCoE Receive Control */ +#define IXGBE_FCRXCTRL 0x05100 /* FC Receive Control */ +#define IXGBE_FCRXCTRL_FCOELLI (1 << 0) /* Low latency interrupt */ +#define IXGBE_FCRXCTRL_SAVBAD (1 << 1) /* Save Bad Frames */ +#define IXGBE_FCRXCTRL_FRSTRDH (1 << 2) /* EN 1st Read Header */ +#define IXGBE_FCRXCTRL_LASTSEQH (1 << 3) /* EN Last Header in Seq */ +#define IXGBE_FCRXCTRL_ALLH (1 << 4) /* EN All Headers */ +#define IXGBE_FCRXCTRL_FRSTSEQH (1 << 5) /* EN 1st Seq. Header */ +#define IXGBE_FCRXCTRL_ICRC (1 << 6) /* Ignore Bad FC CRC */ +#define IXGBE_FCRXCTRL_FCCRCBO (1 << 7) /* FC CRC Byte Ordering */ +#define IXGBE_FCRXCTRL_FCOEVER 0x00000f00 /* FCoE Version: 4 bits */ +#define IXGBE_FCRXCTRL_FCOEVER_SHIFT 8 +/* FCoE Redirection */ +#define IXGBE_FCRECTL 0x0ED00 /* FC Redirection Control */ +#define IXGBE_FCRETA0 0x0ED10 /* FC Redirection Table 0 */ +#define IXGBE_FCRETA(_i) (IXGBE_FCRETA0 + ((_i) * 4)) /* FCoE Redir */ +#define IXGBE_FCRECTL_ENA 0x1 /* FCoE Redir Table Enable */ +#define IXGBE_FCRETA_SIZE 8 /* Max entries in FCRETA */ +#define IXGBE_FCRETA_ENTRY_MASK 0x0000007f /* 7 bits for the queue index */ + /* Stats registers */ #define IXGBE_CRCERRS 0x04000 #define IXGBE_ILLERRC 0x04004 @@ -549,6 +606,13 @@ #define IXGBE_QPRDC(_i) (0x01430 + ((_i) * 0x40)) /* 16 of these */ #define IXGBE_QBTC_L(_i) (0x08700 + ((_i) * 0x8)) /* 16 of these */ #define IXGBE_QBTC_H(_i) (0x08704 + ((_i) * 0x8)) /* 16 of these */ +#define IXGBE_FCCRC 0x05118 /* Count of Good Eth CRC w/ Bad FC CRC */ +#define IXGBE_FCOERPDC 0x0241C /* FCoE Rx Packets Dropped Count */ +#define IXGBE_FCLAST 0x02424 /* FCoE Last Error Count */ +#define IXGBE_FCOEPRC 0x02428 /* Number of FCoE Packets Received */ +#define IXGBE_FCOEDWRC 0x0242C /* Number of FCoE DWords Received */ +#define IXGBE_FCOEPTC 0x08784 /* Number of FCoE Packets Transmitted */ +#define IXGBE_FCOEDWTC 0x08788 /* Number of FCoE DWords Transmitted */ /* Management */ #define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */ @@ -1153,6 +1217,7 @@ /* ETYPE Queue Filter/Select Bit Masks */ #define IXGBE_MAX_ETQF_FILTERS 8 +#define IXGBE_ETQF_FCOE 0x08000000 /* bit 27 */ #define IXGBE_ETQF_BCN 0x10000000 /* bit 28 */ #define IXGBE_ETQF_1588 0x40000000 /* bit 30 */ #define IXGBE_ETQF_FILTER_EN 0x80000000 /* bit 31 */ @@ -1175,6 +1240,7 @@ */ #define IXGBE_ETQF_FILTER_EAPOL 0 #define IXGBE_ETQF_FILTER_BCN 1 +#define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 /* VLAN Control Bit Masks */ #define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ @@ -1579,6 +1645,8 @@ #define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ #define IXGBE_RXDADV_ERR_MASK 0xfff00000 /* RDESC.ERRORS mask */ #define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */ +#define IXGBE_RXDADV_ERR_FCEOFE 0x80000000 /* FCoEFe/IPE */ +#define IXGBE_RXDADV_ERR_FCERR 0x00700000 /* FCERR/FDIRERR */ #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 */ @@ -1598,6 +1666,12 @@ #define IXGBE_RXDADV_STAT_FLM IXGBE_RXD_STAT_FLM /* FDir Match */ #define IXGBE_RXDADV_STAT_VP IXGBE_RXD_STAT_VP /* IEEE VLAN Pkt */ #define IXGBE_RXDADV_STAT_MASK 0x000fffff /* Stat/NEXTP: bit 0-19 */ +#define IXGBE_RXDADV_STAT_FCEOFS 0x00000040 /* FCoE EOF/SOF Stat */ +#define IXGBE_RXDADV_STAT_FCSTAT 0x00000030 /* FCoE Pkt Stat */ +#define IXGBE_RXDADV_STAT_FCSTAT_NOMTCH 0x00000000 /* 00: No Ctxt Match */ +#define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */ +#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */ +#define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */ /* PSRTYPE bit definitions */ #define IXGBE_PSRTYPE_TCPHDR 0x00000010 @@ -1831,6 +1905,16 @@ struct ixgbe_adv_tx_context_desc { #define IXGBE_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */ #define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */ #define IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000/* ESP Encrypt Enable */ +#define IXGBE_ADVTXT_TUCMD_FCOE 0x00008000 /* FCoE Frame Type */ +#define IXGBE_ADVTXD_FCOEF_EOF_MASK (0x3 << 10) /* FC EOF index */ +#define IXGBE_ADVTXD_FCOEF_SOF ((1 << 2) << 10) /* FC SOF index */ +#define IXGBE_ADVTXD_FCOEF_PARINC ((1 << 3) << 10) /* Rel_Off in F_CTL */ +#define IXGBE_ADVTXD_FCOEF_ORIE ((1 << 4) << 10) /* Orientation: End */ +#define IXGBE_ADVTXD_FCOEF_ORIS ((1 << 5) << 10) /* Orientation: Start */ +#define IXGBE_ADVTXD_FCOEF_EOF_N (0x0 << 10) /* 00: EOFn */ +#define IXGBE_ADVTXD_FCOEF_EOF_T (0x1 << 10) /* 01: EOFt */ +#define IXGBE_ADVTXD_FCOEF_EOF_NI (0x2 << 10) /* 10: EOFni */ +#define IXGBE_ADVTXD_FCOEF_EOF_A (0x3 << 10) /* 11: EOFa */ #define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ #define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ -- cgit v0.10.2 From e92cbeac89d4c7b228894a9b8eb37e3ac51afe73 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:10:01 +0000 Subject: ixgbe: Add FCoE feature header to 82599 This adds the FCoE feature header ixgbe_fcoe.h to 82599. This header includes the defines and structures required by the ixgbe driver to support various offload features in 82599 for Fiber Channel over Ethernet (FCoE). These offloads features include Fiber Channel CRC calculation, FCoE SOF/EOF auto insertion, FCoE Sequence Offload (FSO) for large send, and Direct Data Placement (DDP) for large receive. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h new file mode 100644 index 0000000..d054c1d --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -0,0 +1,66 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 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, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_FCOE_H +#define _IXGBE_FCOE_H + +#include + +/* shift bits within STAT fo FCSTAT */ +#define IXGBE_RXDADV_FCSTAT_SHIFT 4 + +/* ddp user buffer */ +#define IXGBE_BUFFCNT_MAX 256 /* 8 bits bufcnt */ +#define IXGBE_FCPTR_ALIGN 16 +#define IXGBE_FCPTR_MAX (IXGBE_BUFFCNT_MAX * sizeof(dma_addr_t)) +#define IXGBE_FCBUFF_4KB 0x0 +#define IXGBE_FCBUFF_8KB 0x1 +#define IXGBE_FCBUFF_16KB 0x2 +#define IXGBE_FCBUFF_64KB 0x3 +#define IXGBE_FCBUFF_MAX 65536 /* 64KB max */ +#define IXGBE_FCBUFF_MIN 4096 /* 4KB min */ +#define IXGBE_FCOE_DDP_MAX 512 /* 9 bits xid */ + +/* fcerr */ +#define IXGBE_FCERR_BADCRC 0x00100000 + +struct ixgbe_fcoe_ddp { + int len; + u32 err; + unsigned int sgc; + struct scatterlist *sgl; + dma_addr_t udp; + unsigned long *udl; +}; + +struct ixgbe_fcoe { + spinlock_t lock; + struct pci_pool *pool; + struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX]; +}; + +#endif /* _IXGBE_FCOE_H */ -- cgit v0.10.2 From d3a2ae6d315382b2dcc7747c5b3b70f0490e9157 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:10:21 +0000 Subject: ixgbe: Add FCoE feature code to 82599 This adds the FCoE feature code ixgbe_fcoe.c to 82599. For a start, this patch only adds ixgbe_configure_fcoe() to configure related register for FCoE to 82599. In patches that follow, I will be adding more functions to ixgbe_fcoe.c to add support of FCoE offload features to 82599. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c new file mode 100644 index 0000000..f8c4d35 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -0,0 +1,60 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 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, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +#include "ixgbe.h" +#include +#include +#include +#include +#include +#include +#include + +/** + * ixgbe_configure_fcoe - configures registers for fcoe at start + * @adapter: ptr to ixgbe adapter + * + * This sets up FCoE related registers + * + * Returns : none + */ +void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + /* L2 filter for FCoE: default to queue 0 */ + IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), + (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); + IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, 0); + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), + IXGBE_ETQS_QUEUE_EN); + IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, + IXGBE_FCRXCTRL_FCOELLI | + IXGBE_FCRXCTRL_FCCRCBO | + (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); +} -- cgit v0.10.2 From bc079228e74d63742255c466d2bce1f42423f219 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:10:44 +0000 Subject: ixgbe: Add infrastructure code for FCoE large send offload to 82599 This adds infrastructure code for FCoE Tx side offload feature to 82599, including Fiber Channel CRC calculation, auto insertion of the start of frame (SOF) and end of frame (EOF) of FCoE packets, and large send by FCoE Sequence Offload (FSO). Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index f8c4d35..e20facd 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -36,6 +36,138 @@ #include /** + * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) + * @adapter: ixgbe adapter + * @tx_ring: tx desc ring + * @skb: associated skb + * @tx_flags: tx flags + * @hdr_len: hdr_len to be returned + * + * This sets up large send offload for FCoE + * + * Returns : 0 indicates no FSO, > 0 for FSO, < 0 for error + */ +int ixgbe_fso(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len) +{ + u8 sof, eof; + u32 vlan_macip_lens; + u32 fcoe_sof_eof; + u32 type_tucmd; + u32 mss_l4len_idx; + int mss = 0; + unsigned int i; + struct ixgbe_tx_buffer *tx_buffer_info; + struct ixgbe_adv_tx_context_desc *context_desc; + struct fc_frame_header *fh; + + if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) { + DPRINTK(DRV, ERR, "Wrong gso type %d:expecting SKB_GSO_FCOE\n", + skb_shinfo(skb)->gso_type); + return -EINVAL; + } + + /* resets the header to point fcoe/fc */ + skb_set_network_header(skb, skb->mac_len); + skb_set_transport_header(skb, skb->mac_len + + sizeof(struct fcoe_hdr)); + + /* sets up SOF and ORIS */ + fcoe_sof_eof = 0; + sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof; + switch (sof) { + case FC_SOF_I2: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIS; + break; + case FC_SOF_I3: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF; + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIS; + break; + case FC_SOF_N2: + break; + case FC_SOF_N3: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF; + break; + default: + DPRINTK(DRV, WARNING, "unknown sof = 0x%x\n", sof); + return -EINVAL; + } + + /* the first byte of the last dword is EOF */ + skb_copy_bits(skb, skb->len - 4, &eof, 1); + /* sets up EOF and ORIE */ + switch (eof) { + case FC_EOF_N: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N; + break; + case FC_EOF_T: + /* lso needs ORIE */ + if (skb_is_gso(skb)) { + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N; + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIE; + } else { + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_T; + } + break; + case FC_EOF_NI: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_NI; + break; + case FC_EOF_A: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A; + break; + default: + DPRINTK(DRV, WARNING, "unknown eof = 0x%x\n", eof); + return -EINVAL; + } + + /* sets up PARINC indicating data offset */ + fh = (struct fc_frame_header *)skb_transport_header(skb); + if (fh->fh_f_ctl[2] & FC_FC_REL_OFF) + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_PARINC; + + /* hdr_len includes fc_hdr if FCoE lso is enabled */ + *hdr_len = sizeof(struct fcoe_crc_eof); + if (skb_is_gso(skb)) + *hdr_len += (skb_transport_offset(skb) + + sizeof(struct fc_frame_header)); + /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */ + vlan_macip_lens = (skb_transport_offset(skb) + + sizeof(struct fc_frame_header)); + vlan_macip_lens |= ((skb_transport_offset(skb) - 4) + << IXGBE_ADVTXD_MACLEN_SHIFT); + vlan_macip_lens |= (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + + /* type_tycmd and mss: set TUCMD.FCoE to enable offload */ + type_tucmd = IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT | + IXGBE_ADVTXT_TUCMD_FCOE; + if (skb_is_gso(skb)) + mss = skb_shinfo(skb)->gso_size; + /* mss_l4len_id: use 1 for FSO as TSO, no need for L4LEN */ + mss_l4len_idx = (mss << IXGBE_ADVTXD_MSS_SHIFT) | + (1 << IXGBE_ADVTXD_IDX_SHIFT); + + /* write context desc */ + i = tx_ring->next_to_use; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = cpu_to_le32(fcoe_sof_eof); + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd); + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); + + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return skb_is_gso(skb); +} + +/** * ixgbe_configure_fcoe - configures registers for fcoe at start * @adapter: ptr to ixgbe adapter * -- cgit v0.10.2 From eacd73f79a106c6a0bc429003ab691024860ab2d Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:11:06 +0000 Subject: ixgbe: Implement FCoE Tx side offload features in base driver of 82599 This patch implements the FCoE Tx side offload features in ixgbe_main.c to 82599 using the Tx offload infrastructure code added in the previous patch. This is achieved by the calling the FCoE Sequence Offload (FSO) function ixgbe_fso() on the transmit path of ixgbe. This patch also includes an EEPROM check to make sure the NIC we're loading on is an offload-enabled SKU. Signed-off-by: Yi Zou Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile index b3f8208..21b41f4 100644 --- a/drivers/net/ixgbe/Makefile +++ b/drivers/net/ixgbe/Makefile @@ -37,3 +37,5 @@ ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe_dcb_82599.o ixgbe_dcb_nl.o + +ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index d743d0e..06859f6 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -36,6 +36,10 @@ #include "ixgbe_type.h" #include "ixgbe_common.h" #include "ixgbe_dcb.h" +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) +#define IXGBE_FCOE +#include "ixgbe_fcoe.h" +#endif /* CONFIG_FCOE or CONFIG_FCOE_MODULE */ #ifdef CONFIG_IXGBE_DCA #include #endif @@ -84,6 +88,8 @@ #define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1) #define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) #define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) +#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 4) +#define IXGBE_TX_FLAGS_FSO (u32)(1 << 5) #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 @@ -298,6 +304,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) #define IXGBE_FLAG_RSC_CAPABLE (u32)(1 << 26) #define IXGBE_FLAG_RSC_ENABLED (u32)(1 << 27) +#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -371,5 +378,11 @@ extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32); +#ifdef IXGBE_FCOE +extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); +extern int ixgbe_fso(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len); +#endif /* IXGBE_FCOE */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 6038ed1..23be4db 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1294,7 +1294,6 @@ s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) return 0; } - static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index efb175b..ee80f6f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "ixgbe.h" #include "ixgbe_common.h" @@ -1810,6 +1811,11 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) /* Decide whether to use packet split mode or not */ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; +#endif /* IXGBE_FCOE */ + /* Set the RX buffer length according to the mode */ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { rx_buf_len = IXGBE_RX_HDR_SIZE; @@ -2241,6 +2247,11 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) netif_set_gso_max_size(netdev, 65536); #endif +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + ixgbe_configure_fcoe(adapter); + +#endif /* IXGBE_FCOE */ ixgbe_configure_tx(adapter); ixgbe_configure_rx(adapter); for (i = 0; i < adapter->num_rx_queues; i++) @@ -3401,6 +3412,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; adapter->flags |= IXGBE_FLAG_RSC_CAPABLE; adapter->flags |= IXGBE_FLAG_RSC_ENABLED; +#ifdef IXGBE_FCOE + adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; +#endif /* IXGBE_FCOE */ } #ifdef CONFIG_IXGBE_DCB @@ -4416,10 +4430,12 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, static int ixgbe_tx_map(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring, - struct sk_buff *skb, unsigned int first) + struct sk_buff *skb, u32 tx_flags, + unsigned int first) { struct ixgbe_tx_buffer *tx_buffer_info; - unsigned int len = skb_headlen(skb); + unsigned int len; + unsigned int total = skb->len; unsigned int offset = 0, size, count = 0, i; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; @@ -4434,6 +4450,11 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, map = skb_shinfo(skb)->dma_maps; + if (tx_flags & IXGBE_TX_FLAGS_FCOE) + /* excluding fcoe_crc_eof for FCoE */ + total -= sizeof(struct fcoe_crc_eof); + + len = min(skb_headlen(skb), total); while (len) { tx_buffer_info = &tx_ring->tx_buffer_info[i]; size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); @@ -4444,6 +4465,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, tx_buffer_info->next_to_watch = i; len -= size; + total -= size; offset += size; count++; @@ -4458,7 +4480,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, struct skb_frag_struct *frag; frag = &skb_shinfo(skb)->frags[f]; - len = frag->size; + len = min((unsigned int)frag->size, total); offset = 0; while (len) { @@ -4475,9 +4497,12 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, tx_buffer_info->next_to_watch = i; len -= size; + total -= size; offset += size; count++; } + if (total == 0) + break; } tx_ring->tx_buffer_info[i].skb = skb; @@ -4519,6 +4544,13 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, olinfo_status |= IXGBE_TXD_POPTS_TXSM << IXGBE_ADVTXD_POPTS_SHIFT; + if (tx_flags & IXGBE_TX_FLAGS_FCOE) { + olinfo_status |= IXGBE_ADVTXD_CC; + olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT); + if (tx_flags & IXGBE_TX_FLAGS_FSO) + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + } + olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT); i = tx_ring->next_to_use; @@ -4615,10 +4647,16 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } - /* three things can cause us to need a context descriptor */ + + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + (skb->protocol == htons(ETH_P_FCOE))) + tx_flags |= IXGBE_TX_FLAGS_FCOE; + + /* four 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)) + (tx_flags & IXGBE_TX_FLAGS_VLAN) || + (tx_flags & IXGBE_TX_FLAGS_FCOE)) count++; count += TXD_USE_COUNT(skb_headlen(skb)); @@ -4630,23 +4668,35 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - if (skb->protocol == htons(ETH_P_IP)) - tx_flags |= IXGBE_TX_FLAGS_IPV4; first = tx_ring->next_to_use; - tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); - if (tso < 0) { - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - if (tso) - tx_flags |= IXGBE_TX_FLAGS_TSO; - else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && - (skb->ip_summed == CHECKSUM_PARTIAL)) - tx_flags |= IXGBE_TX_FLAGS_CSUM; + if (tx_flags & IXGBE_TX_FLAGS_FCOE) { +#ifdef IXGBE_FCOE + /* setup tx offload for FCoE */ + tso = ixgbe_fso(adapter, tx_ring, skb, tx_flags, &hdr_len); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + if (tso) + tx_flags |= IXGBE_TX_FLAGS_FSO; +#endif /* IXGBE_FCOE */ + } else { + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= IXGBE_TX_FLAGS_IPV4; + tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } - count = ixgbe_tx_map(adapter, tx_ring, skb, first); + if (tso) + tx_flags |= IXGBE_TX_FLAGS_TSO; + else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && + (skb->ip_summed == CHECKSUM_PARTIAL)) + tx_flags |= IXGBE_TX_FLAGS_CSUM; + } + count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first); if (count) { ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); @@ -4794,6 +4844,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data]; static int cards_found; int i, err, pci_using_dac; +#ifdef IXGBE_FCOE + u16 device_caps; +#endif u32 part_num, eec; err = pci_enable_device_mem(pdev); @@ -4976,6 +5029,19 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->dcbnl_ops = &dcbnl_ops; #endif +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + if (hw->mac.ops.get_device_caps) { + hw->mac.ops.get_device_caps(hw, &device_caps); + if (!(device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)) { + netdev->features |= NETIF_F_FCOE_CRC; + netdev->features |= NETIF_F_FSO; + } else { + adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; + } + } + } +#endif /* IXGBE_FCOE */ if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index c2d9ed5..b3de723 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1483,6 +1483,7 @@ #endif #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 +#define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 /* PCI Bus Info */ #define IXGBE_PCI_LINK_STATUS 0xB2 -- cgit v0.10.2 From d0ed89373f2da1a0d83697d87441e519caf18cf7 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:11:29 +0000 Subject: ixgbe: Add infrastructure code for FCoE large receive offload to 82599 This adds infrastructure code for FCoE Rx side offload feature to 82599, which provides large receive offload for FCoE by Direct Data Placement (DDP). The ixgbe_fcoe_ddp_get() and ixgbe_fcoe_ddp_put() pair corresponds to the netdev support to FCoE by the function pointers provided in net_device_ops as ndo_fcoe_ddp_setup and ndo_fcoe_ddp_done. The implementation of these in ixgbe is shown in the next patch. Signed-off-by: Yi Zou Signed-off-by: Chris Leech Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 06859f6..5581fa3 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -336,6 +336,9 @@ struct ixgbe_adapter { struct timer_list sfp_timer; struct work_struct multispeed_fiber_task; struct work_struct sfp_config_module_task; +#ifdef IXGBE_FCOE + struct ixgbe_fcoe fcoe; +#endif /* IXGBE_FCOE */ u64 rsc_count; u32 wol; u16 eeprom_version; diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index e20facd..a11c620 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -36,6 +36,311 @@ #include /** + * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type + * @rx_desc: advanced rx descriptor + * + * Returns : true if it is FCoE pkt + */ +static inline bool ixgbe_rx_is_fcoe(union ixgbe_adv_rx_desc *rx_desc) +{ + u16 p; + + p = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info); + if (p & IXGBE_RXDADV_PKTTYPE_ETQF) { + p &= IXGBE_RXDADV_PKTTYPE_ETQF_MASK; + p >>= IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT; + return p == IXGBE_ETQF_FILTER_FCOE; + } + return false; +} + +/** + * ixgbe_fcoe_clear_ddp - clear the given ddp context + * @ddp - ptr to the ixgbe_fcoe_ddp + * + * Returns : none + * + */ +static inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp) +{ + ddp->len = 0; + ddp->err = 0; + ddp->udl = NULL; + ddp->udp = 0UL; + ddp->sgl = NULL; + ddp->sgc = 0; +} + +/** + * ixgbe_fcoe_ddp_put - free the ddp context for a given xid + * @netdev: the corresponding net_device + * @xid: the xid that corresponding ddp will be freed + * + * This is the implementation of net_device_ops.ndo_fcoe_ddp_done + * and it is expected to be called by ULD, i.e., FCP layer of libfc + * to release the corresponding ddp context when the I/O is done. + * + * Returns : data length already ddp-ed in bytes + */ +int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) +{ + int len = 0; + struct ixgbe_fcoe *fcoe; + struct ixgbe_adapter *adapter; + struct ixgbe_fcoe_ddp *ddp; + + if (!netdev) + goto out_ddp_put; + + if (xid >= IXGBE_FCOE_DDP_MAX) + goto out_ddp_put; + + adapter = netdev_priv(netdev); + fcoe = &adapter->fcoe; + ddp = &fcoe->ddp[xid]; + if (!ddp->udl) + goto out_ddp_put; + + len = ddp->len; + /* if there an error, force to invalidate ddp context */ + if (ddp->err) { + spin_lock_bh(&fcoe->lock); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLT, 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLTRW, + (xid | IXGBE_FCFLTRW_WE)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCBUFF, 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCDMARW, + (xid | IXGBE_FCDMARW_WE)); + spin_unlock_bh(&fcoe->lock); + } + if (ddp->sgl) + pci_unmap_sg(adapter->pdev, ddp->sgl, ddp->sgc, + DMA_FROM_DEVICE); + pci_pool_free(fcoe->pool, ddp->udl, ddp->udp); + ixgbe_fcoe_clear_ddp(ddp); + +out_ddp_put: + return len; +} + +/** + * ixgbe_fcoe_ddp_get - called to set up ddp context + * @netdev: the corresponding net_device + * @xid: the exchange id requesting ddp + * @sgl: the scatter-gather list for this request + * @sgc: the number of scatter-gather items + * + * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup + * and is expected to be called from ULD, e.g., FCP layer of libfc + * to set up ddp for the corresponding xid of the given sglist for + * the corresponding I/O. + * + * Returns : 1 for success and 0 for no ddp + */ +int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, + struct scatterlist *sgl, unsigned int sgc) +{ + struct ixgbe_adapter *adapter; + struct ixgbe_hw *hw; + struct ixgbe_fcoe *fcoe; + struct ixgbe_fcoe_ddp *ddp; + struct scatterlist *sg; + unsigned int i, j, dmacount; + unsigned int len; + static const unsigned int bufflen = 4096; + unsigned int firstoff = 0; + unsigned int lastsize; + unsigned int thisoff = 0; + unsigned int thislen = 0; + u32 fcbuff, fcdmarw, fcfltrw; + dma_addr_t addr; + + if (!netdev || !sgl) + return 0; + + adapter = netdev_priv(netdev); + if (xid >= IXGBE_FCOE_DDP_MAX) { + DPRINTK(DRV, WARNING, "xid=0x%x out-of-range\n", xid); + return 0; + } + + fcoe = &adapter->fcoe; + if (!fcoe->pool) { + DPRINTK(DRV, WARNING, "xid=0x%x no ddp pool for fcoe\n", xid); + return 0; + } + + ddp = &fcoe->ddp[xid]; + if (ddp->sgl) { + DPRINTK(DRV, ERR, "xid 0x%x w/ non-null sgl=%p nents=%d\n", + xid, ddp->sgl, ddp->sgc); + return 0; + } + ixgbe_fcoe_clear_ddp(ddp); + + /* setup dma from scsi command sgl */ + dmacount = pci_map_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); + if (dmacount == 0) { + DPRINTK(DRV, ERR, "xid 0x%x DMA map error\n", xid); + return 0; + } + + /* alloc the udl from our ddp pool */ + ddp->udl = pci_pool_alloc(fcoe->pool, GFP_KERNEL, &ddp->udp); + if (!ddp->udl) { + DPRINTK(DRV, ERR, "failed allocated ddp context\n"); + goto out_noddp_unmap; + } + ddp->sgl = sgl; + ddp->sgc = sgc; + + j = 0; + for_each_sg(sgl, sg, dmacount, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + while (len) { + /* get the offset of length of current buffer */ + thisoff = addr & ((dma_addr_t)bufflen - 1); + thislen = min((bufflen - thisoff), len); + /* + * all but the 1st buffer (j == 0) + * must be aligned on bufflen + */ + if ((j != 0) && (thisoff)) + goto out_noddp_free; + /* + * all but the last buffer + * ((i == (dmacount - 1)) && (thislen == len)) + * must end at bufflen + */ + if (((i != (dmacount - 1)) || (thislen != len)) + && ((thislen + thisoff) != bufflen)) + goto out_noddp_free; + + ddp->udl[j] = (u64)(addr - thisoff); + /* only the first buffer may have none-zero offset */ + if (j == 0) + firstoff = thisoff; + len -= thislen; + addr += thislen; + j++; + /* max number of buffers allowed in one DDP context */ + if (j > IXGBE_BUFFCNT_MAX) { + DPRINTK(DRV, ERR, "xid=%x:%d,%d,%d:addr=%llx " + "not enough descriptors\n", + xid, i, j, dmacount, (u64)addr); + goto out_noddp_free; + } + } + } + /* only the last buffer may have non-full bufflen */ + lastsize = thisoff + thislen; + + fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); + fcbuff |= (j << IXGBE_FCBUFF_BUFFCNT_SHIFT); + fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); + fcbuff |= (IXGBE_FCBUFF_VALID); + + fcdmarw = xid; + fcdmarw |= IXGBE_FCDMARW_WE; + fcdmarw |= (lastsize << IXGBE_FCDMARW_LASTSIZE_SHIFT); + + fcfltrw = xid; + fcfltrw |= IXGBE_FCFLTRW_WE; + + /* program DMA context */ + hw = &adapter->hw; + spin_lock_bh(&fcoe->lock); + IXGBE_WRITE_REG(hw, IXGBE_FCPTRL, ddp->udp & DMA_32BIT_MASK); + IXGBE_WRITE_REG(hw, IXGBE_FCPTRH, (u64)ddp->udp >> 32); + IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, fcbuff); + IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, fcdmarw); + /* program filter context */ + IXGBE_WRITE_REG(hw, IXGBE_FCPARAM, 0); + IXGBE_WRITE_REG(hw, IXGBE_FCFLT, IXGBE_FCFLT_VALID); + IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, fcfltrw); + spin_unlock_bh(&fcoe->lock); + + return 1; + +out_noddp_free: + pci_pool_free(fcoe->pool, ddp->udl, ddp->udp); + ixgbe_fcoe_clear_ddp(ddp); + +out_noddp_unmap: + pci_unmap_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); + return 0; +} + +/** + * ixgbe_fcoe_ddp - check ddp status and mark it done + * @adapter: ixgbe adapter + * @rx_desc: advanced rx descriptor + * @skb: the skb holding the received data + * + * This checks ddp status. + * + * Returns : 0 for success and skb will not be delivered to ULD + */ +int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + u16 xid; + u32 sterr, fceofe, fcerr, fcstat; + int rc = -EINVAL; + struct ixgbe_fcoe *fcoe; + struct ixgbe_fcoe_ddp *ddp; + struct fc_frame_header *fh; + + if (!ixgbe_rx_is_fcoe(rx_desc)) + goto ddp_out; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + sterr = le32_to_cpu(rx_desc->wb.upper.status_error); + fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR); + fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE); + if (fcerr == IXGBE_FCERR_BADCRC) + skb->ip_summed = CHECKSUM_NONE; + + skb_reset_network_header(skb); + skb_set_transport_header(skb, skb_network_offset(skb) + + sizeof(struct fcoe_hdr)); + fh = (struct fc_frame_header *)skb_transport_header(skb); + xid = be16_to_cpu(fh->fh_ox_id); + if (xid >= IXGBE_FCOE_DDP_MAX) + goto ddp_out; + + fcoe = &adapter->fcoe; + ddp = &fcoe->ddp[xid]; + if (!ddp->udl) + goto ddp_out; + + ddp->err = (fcerr | fceofe); + if (ddp->err) + goto ddp_out; + + fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT); + if (fcstat) { + /* update length of DDPed data */ + ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); + /* unmap the sg list when FCP_RSP is received */ + if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_FCPRSP) { + pci_unmap_sg(adapter->pdev, ddp->sgl, + ddp->sgc, DMA_FROM_DEVICE); + ddp->sgl = NULL; + ddp->sgc = 0; + } + /* return 0 to bypass going to ULD for DDPed data */ + if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP) + rc = 0; + } + +ddp_out: + return rc; +} + +/** * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) * @adapter: ixgbe adapter * @tx_ring: tx desc ring @@ -178,7 +483,20 @@ int ixgbe_fso(struct ixgbe_adapter *adapter, void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_fcoe *fcoe = &adapter->fcoe; + + /* create the pool for ddp if not created yet */ + if (!fcoe->pool) { + /* allocate ddp pool */ + fcoe->pool = pci_pool_create("ixgbe_fcoe_ddp", + adapter->pdev, IXGBE_FCPTR_MAX, + IXGBE_FCPTR_ALIGN, PAGE_SIZE); + if (!fcoe->pool) + DPRINTK(DRV, ERR, + "failed to allocated FCoE DDP pool\n"); + spin_lock_init(&fcoe->lock); + } /* L2 filter for FCoE: default to queue 0 */ IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); @@ -190,3 +508,25 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) IXGBE_FCRXCTRL_FCCRCBO | (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); } + +/** + * ixgbe_cleanup_fcoe - release all fcoe ddp context resources + * @adapter : ixgbe adapter + * + * Cleans up outstanding ddp context resources + * + * Returns : none + */ +void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) +{ + int i; + struct ixgbe_fcoe *fcoe = &adapter->fcoe; + + /* release ddp resource */ + if (fcoe->pool) { + for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++) + ixgbe_fcoe_ddp_put(adapter->netdev, i); + pci_pool_destroy(fcoe->pool); + fcoe->pool = NULL; + } +} diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index d054c1d..b7f9b63 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -54,7 +54,7 @@ struct ixgbe_fcoe_ddp { unsigned int sgc; struct scatterlist *sgl; dma_addr_t udp; - unsigned long *udl; + u64 *udl; }; struct ixgbe_fcoe { -- cgit v0.10.2 From 332d4a7d981e25d239c5d723a4f35020397dc606 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:11:53 +0000 Subject: ixgbe: Implement FCoE Rx side large receive offload feature to 82599 This patch implements the FCoE Rx side offload feature in ixgbe_main.c to 82599 using the Rx offload infrastructure code added in the previous patch. The large receive offload by Direct Data Placement (DDP) for FCoE is achieved by implementing the ndo_fcoe_ddp_setup and ndo_fcoe_ddp_done in net_device_ops via netdev. It is up to the ULD, i.e., fcoe and libfc to query and setup large receive offload accordingly through the corresponding netdev upon creating fcoe instances. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 5581fa3..db6d3ea 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -386,6 +386,13 @@ extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring, struct sk_buff *skb, u32 tx_flags, u8 *hdr_len); +extern void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter); +extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb); +extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, + struct scatterlist *sgl, unsigned int sgc); +extern int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid); #endif /* IXGBE_FCOE */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ee80f6f..e7c44a3 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -784,6 +784,12 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, total_rx_packets++; skb->protocol = eth_type_trans(skb, adapter->netdev); +#ifdef IXGBE_FCOE + /* if ddp, not passing to ULD unless for FCP_RSP or error */ + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + if (!ixgbe_fcoe_ddp(adapter, rx_desc, skb)) + goto next_desc; +#endif /* IXGBE_FCOE */ ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc); next_desc: @@ -4822,6 +4828,10 @@ static const struct net_device_ops ixgbe_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ixgbe_netpoll, #endif +#ifdef IXGBE_FCOE + .ndo_fcoe_ddp_setup = ixgbe_fcoe_ddp_get, + .ndo_fcoe_ddp_done = ixgbe_fcoe_ddp_put, +#endif /* IXGBE_FCOE */ }; /** @@ -5036,6 +5046,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (!(device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)) { netdev->features |= NETIF_F_FCOE_CRC; netdev->features |= NETIF_F_FSO; + netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; } else { adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; } @@ -5205,6 +5216,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) } #endif +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + ixgbe_cleanup_fcoe(adapter); + +#endif /* IXGBE_FCOE */ if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); -- cgit v0.10.2 From 6d45522c532be430b2ed63ed48a6a9e15328af66 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 13 May 2009 13:12:16 +0000 Subject: ixgbe: Add FCoE related statistics to 82599 This adds FCoE related statistics to 82599, including number Rx-ed and Tx-ed FCoE packets, number of Rx-ed and Tx-ed FCoE packets in dwords, number of bad Fiber Channel CRCs detected in FCoE packets, and number of FCoE packets dropped on the Rx side. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index c0167d6..39fb98f 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -91,6 +91,14 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)}, +#ifdef IXGBE_FCOE + {"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)}, + {"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)}, + {"rx_fcoe_packets", IXGBE_STAT(stats.fcoeprc)}, + {"rx_fcoe_dwords", IXGBE_STAT(stats.fcoedwrc)}, + {"tx_fcoe_packets", IXGBE_STAT(stats.fcoeptc)}, + {"tx_fcoe_dwords", IXGBE_STAT(stats.fcoedwtc)}, +#endif /* IXGBE_FCOE */ }; #define IXGBE_QUEUE_STATS_LEN \ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index e7c44a3..d69a052 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4002,6 +4002,14 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */ adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); +#ifdef IXGBE_FCOE + adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); + adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); + adapter->stats.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); + adapter->stats.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); + adapter->stats.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); + adapter->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); +#endif /* IXGBE_FCOE */ } else { adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index b3de723..38f835d 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2157,6 +2157,12 @@ struct ixgbe_hw_stats { u64 fdirfstat_fremove; u64 fdirmatch; u64 fdirmiss; + u64 fccrc; + u64 fcoerpdc; + u64 fcoeprc; + u64 fcoeptc; + u64 fcoedwrc; + u64 fcoedwtc; }; /* forward declaration */ -- cgit v0.10.2 From d44b5e07c6813e6d747f7f947f1da5f0abf14eb4 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 11 May 2009 21:44:51 +0000 Subject: net/ibmveth: fix panic in probe netdev->dev_addr changed from being an array to being a pointer, so we should not take its address for memcpy(). Signed-off-by: Stephen Rothwell Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 53af71a..0995c43 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1285,7 +1285,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->features |= NETIF_F_LLTX; spin_lock_init(&adapter->stats_lock); - memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); + memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); for(i = 0; irx_buff_pool[i].kobj; -- cgit v0.10.2 From 9dc20c5f78c53bf57fb7874b6e942842e1db20d3 Mon Sep 17 00:00:00 2001 From: John Dykstra Date: Tue, 12 May 2009 15:34:50 +0000 Subject: tcp: tcp_prequeue() can use keyed wakeups When TCP frees up write buffer space, avoid waking up tasks that have done a poll() or select() on the same socket specifying read-side events. This is an extension of a read-side patch by Eric Dumazet. Signed-off-by: John Dykstra Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/stream.c b/net/core/stream.c index 8727cea..a37debf 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -33,7 +33,8 @@ void sk_stream_write_space(struct sock *sk) clear_bit(SOCK_NOSPACE, &sock->flags); if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible(sk->sk_sleep); + wake_up_interruptible_poll(sk->sk_sleep, POLLOUT | + POLLWRNORM | POLLWRBAND); if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT); } -- cgit v0.10.2 From d62fda082c48b417b47a553860abf75d9cf8b591 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 May 2009 20:48:02 +0000 Subject: bnx2: bnx2_tx_int() optimizations When using bnx2 in a high transmit load, bnx2_tx_int() cost is pretty high. There are two reasons. One is an expensive call to bnx2_get_hw_tx_cons(bnapi) for each freed skb One is cpu stalls when accessing skb_is_gso(skb) / skb_shinfo(skb)->nr_frags because of two cache line misses. (One to get skb->end/head to compute skb_shinfo(skb), one to get is_gso/nr_frags) This patch : 1) avoids calling bnx2_get_hw_tx_cons(bnapi) too many times. 2) makes bnx2_start_xmit() cache is_gso & nr_frags into sw_tx_bd descriptor. This uses a litle bit more ram (256 longs per device on x86), but helps a lot. 3) uses a prefetch(&skb->end) to speedup dev_kfree_skb(), bringing cache line that will be needed in skb_release_data() result is 5 % bandwidth increase in benchmarks, involving UDP or TCP receive & transmits, when a cpu is dedicated to ksoftirqd for bnx2. bnx2_tx_int going from 3.33 % cpu to 0.5 % cpu in oprofile Note : skb_dma_unmap() still very expensive but this is for another patch, not related to bnx2 (2.9 % of cpu, while it does nothing on x86_32) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b0cb29d..c37acc1 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2630,14 +2630,15 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) tx_buf = &txr->tx_buf_ring[sw_ring_cons]; skb = tx_buf->skb; + /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */ + prefetch(&skb->end); + /* partial BD completions possible with TSO packets */ - if (skb_is_gso(skb)) { + if (tx_buf->is_gso) { u16 last_idx, last_ring_idx; - last_idx = sw_cons + - skb_shinfo(skb)->nr_frags + 1; - last_ring_idx = sw_ring_cons + - skb_shinfo(skb)->nr_frags + 1; + last_idx = sw_cons + tx_buf->nr_frags + 1; + last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1; if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) { last_idx++; } @@ -2649,7 +2650,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); tx_buf->skb = NULL; - last = skb_shinfo(skb)->nr_frags; + last = tx_buf->nr_frags; for (i = 0; i < last; i++) { sw_cons = NEXT_TX_BD(sw_cons); @@ -2662,7 +2663,8 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) if (tx_pkt == budget) break; - hw_cons = bnx2_get_hw_tx_cons(bnapi); + if (hw_cons == sw_cons) + hw_cons = bnx2_get_hw_tx_cons(bnapi); } txr->hw_tx_cons = hw_cons; @@ -6179,6 +6181,8 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START; last_frag = skb_shinfo(skb)->nr_frags; + tx_buf->nr_frags = last_frag; + tx_buf->is_gso = skb_is_gso(skb); for (i = 0; i < last_frag; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 5b570e1..026ed1c 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6552,6 +6552,8 @@ struct sw_pg { struct sw_tx_bd { struct sk_buff *skb; + unsigned short is_gso; + unsigned short nr_frags; }; #define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT) -- cgit v0.10.2 From 528efc6a54a9e4c03488ee72988567991c9476ba Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:17 +0000 Subject: gigaset: remove obsolete references to m10x state table The separation of state tables for base and M10x has long been removed. Clean up remaining traces of it. Impact: cleanup Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 0048ce9..79c9b0f 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -672,14 +672,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, cs->tty = NULL; cs->tty_dev = NULL; cs->cidmode = cidmode != 0; - - //if(onechannel) { //FIXME - cs->tabnocid = gigaset_tab_nocid_m10x; - cs->tabcid = gigaset_tab_cid_m10x; - //} else { - // cs->tabnocid = gigaset_tab_nocid; - // cs->tabcid = gigaset_tab_cid; - //} + cs->tabnocid = gigaset_tab_nocid; + cs->tabcid = gigaset_tab_cid; init_waitqueue_head(&cs->waitqueue); cs->waiting = 0; diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index e582a48..ec51696 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -160,7 +160,7 @@ // 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring -struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ +struct reply_t gigaset_tab_nocid[] = { /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ @@ -280,7 +280,7 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ }; // 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, 400: hup, 750: accepted icall -struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ +struct reply_t gigaset_tab_cid[] = { /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 747178f..d5f0110 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -282,8 +282,8 @@ struct reply_t { char *command; /* NULL==none */ }; -extern struct reply_t gigaset_tab_cid_m10x[]; -extern struct reply_t gigaset_tab_nocid_m10x[]; +extern struct reply_t gigaset_tab_cid[]; +extern struct reply_t gigaset_tab_nocid[]; struct inbuf_t { unsigned char *rcvbuf; /* usb-gigaset receive buffer */ -- cgit v0.10.2 From 42e3d611158faa2d372ccfb1e17bfde13935de68 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:17 +0000 Subject: gigaset: fix possible oops in error handling Use pr_warning() / pr_err() instead of dev_warn() / dev_err() in two places where the dev pointer isn't guaranteed to be valid. Impact: error handling bugfix Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 820a309..1ebfcab 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -599,8 +599,7 @@ void gigaset_if_init(struct cardstate *cs) if (!IS_ERR(cs->tty_dev)) dev_set_drvdata(cs->tty_dev, cs); else { - dev_warn(cs->dev, - "could not register device to the tty subsystem\n"); + pr_warning("could not register device to the tty subsystem\n"); cs->tty_dev = NULL; } mutex_unlock(&cs->mutex); diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index da6f3ac..9715aad 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c @@ -79,5 +79,5 @@ void gigaset_init_dev_sysfs(struct cardstate *cs) gig_dbg(DEBUG_INIT, "setting up sysfs"); if (device_create_file(cs->tty_dev, &dev_attr_cidmode)) - dev_err(cs->dev, "could not create sysfs attribute\n"); + pr_err("could not create sysfs attribute\n"); } -- cgit v0.10.2 From 1315d69634834f1f485b21b0ed8f10b763a675d2 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:17 +0000 Subject: gigaset: skip unnecessary hex formatting Don't generate the hex representation of the payload data if it isn't actually used afterwards. Impact: optimization Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index b171e75..09202a5 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -246,6 +246,10 @@ static inline void dump_bytes(enum debuglevel level, const char *tag, unsigned char c; static char dbgline[3 * 32 + 1]; int i = 0; + + if (!(gigaset_debuglevel & level)) + return; + while (count-- > 0) { if (i > sizeof(dbgline) - 4) { dbgline[i] = '\0'; -- cgit v0.10.2 From 7226d7c9607b754cdad612b75122d640ff3b85ed Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:17 +0000 Subject: gigaset: fix error return code gigaset_register_to_LL() is expected to print a message and return 0 on failure. Make it do so consistently. Impact: error handling bugfix Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 69a702f..9b22f9c 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -544,11 +544,11 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) gig_dbg(DEBUG_ANY, "Register driver capabilities to LL"); - //iif->id[sizeof(iif->id) - 1]=0; - //strncpy(iif->id, isdnid, sizeof(iif->id) - 1); if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index) - >= sizeof iif->id) - return -ENOMEM; //FIXME EINVAL/...?? + >= sizeof iif->id) { + pr_err("ID too long: %s\n", isdnid); + return 0; + } iif->owner = THIS_MODULE; iif->channels = cs->channels; @@ -568,8 +568,10 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) iif->rcvcallb_skb = NULL; /* Will be set by LL */ iif->statcallb = NULL; /* Will be set by LL */ - if (!register_isdn(iif)) + if (!register_isdn(iif)) { + pr_err("register_isdn failed\n"); return 0; + } cs->myid = iif->channels; /* Set my device id */ return 1; -- cgit v0.10.2 From b3fcb13f1c866ae0330c445c3cb481014c36a02f Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:17 +0000 Subject: gigaset: documentation update Mention handling of unregisteted DECT wireless datasets in README.gigaset. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset index 02c0e93..f6e9eaa 100644 --- a/Documentation/isdn/README.gigaset +++ b/Documentation/isdn/README.gigaset @@ -192,7 +192,6 @@ GigaSet 307x Device Driver 2.6. M105 Undocumented USB Requests ------------------------------ - The Gigaset M105 USB data box understands a couple of useful, but undocumented USB commands. These requests are not used in normal operation (for wireless access to the base), but are needed for access @@ -204,6 +203,20 @@ GigaSet 307x Device Driver M105, try setting that option to "y" via 'make {x,menu}config' and recompiling the driver. +2.7. Unregistered Wireless Devices (M101/M105) + ----------------------------------------- + The main purpose of the ser_gigaset and usb_gigaset drivers is to allow + the M101 and M105 wireless devices to be used as ISDN devices for ISDN + connections through a Gigaset base. Therefore they assume that the device + is registered to a DECT base. + + If the M101/M105 device is not registered to a base, initialization of + the device fails, and a corresponding error message is logged by the + driver. In that situation, a restricted set of functions is available + which includes, in particular, those necessary for registering the device + to a base or for switching it between Fixed Part and Portable Part + modes. For the M105, these commands require the "Support for undocumented + USB requests" configuration option (see section 2.6.) to be enabled. 3. Troubleshooting --------------- @@ -240,6 +253,14 @@ GigaSet 307x Device Driver Recompile the usb_gigaset driver with the kernel configuration option CONFIG_GIGASET_UNDOCREQ set to 'y'. (see section 2.6.) + Problem: + Messages like this: + usb_gigaset 3-2:1.0: Could not initialize the device. + appear in your syslog. + Solution: + Check whether your M10x wireless device is correctly registered to the + Gigaset base. (see section 2.7.) + 3.2. Telling the driver to provide more information ---------------------------------------------- Building the driver with the "Gigaset debugging" kernel configuration -- cgit v0.10.2 From 5a1888ea994bf6b28179255a376e83dfa53c81c5 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:18 +0000 Subject: gigaset: move up Kconfig inclusion point In preparation for porting to kernel CAPI subsystem, include the Gigaset driver's Kconfig directly from ISDN's instead of I4L's. Impact: Kconfig reorganisation, no functional change Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 3d113c6..02bdca6 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -61,4 +61,6 @@ source "drivers/isdn/hardware/Kconfig" endif # ISDN_CAPI +source "drivers/isdn/gigaset/Kconfig" + endif # ISDN diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig index 9ca889a..754b90d 100644 --- a/drivers/isdn/gigaset/Kconfig +++ b/drivers/isdn/gigaset/Kconfig @@ -1,5 +1,6 @@ menuconfig ISDN_DRV_GIGASET tristate "Siemens Gigaset support" + depends on ISDN_I4L select CRC_CCITT select BITREVERSE help diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index 36778b2..ed3510f 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -135,5 +135,3 @@ source "drivers/isdn/act2000/Kconfig" source "drivers/isdn/hysdn/Kconfig" endmenu - -source "drivers/isdn/gigaset/Kconfig" -- cgit v0.10.2 From b88bd95655c7bc059606529e01467594978d7b72 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:18 +0000 Subject: gigaset: remove UNDOCREQ config option Drop the kernel config option GIGASET_UNDOCREQ, permanently activating the code it controlled, as there have been no reports of problems caused by its activation but many problems caused by it being disabled. Also fix a few bad comments while we're at it. Impact: cleanup Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset index f6e9eaa..f996310 100644 --- a/Documentation/isdn/README.gigaset +++ b/Documentation/isdn/README.gigaset @@ -149,10 +149,8 @@ GigaSet 307x Device Driver configuration files and chat scripts in the gigaset-VERSION/ppp directory in the driver packages from http://sourceforge.net/projects/gigaset307x/. Please note that the USB drivers are not able to change the state of the - control lines (the M105 driver can be configured to use some undocumented - control requests, if you really need the control lines, though). This means - you must use "Stupid Mode" if you are using wvdial or you should use the - nocrtscts option of pppd. + control lines. This means you must use "Stupid Mode" if you are using + wvdial or you should use the nocrtscts option of pppd. You must also assure that the ppp_async module is loaded with the parameter flag_time=0. You can do this e.g. by adding a line like @@ -190,20 +188,7 @@ GigaSet 307x Device Driver You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode setting (ttyGxy is ttyGU0 or ttyGB0). -2.6. M105 Undocumented USB Requests - ------------------------------ - The Gigaset M105 USB data box understands a couple of useful, but - undocumented USB commands. These requests are not used in normal - operation (for wireless access to the base), but are needed for access - to the M105's own configuration mode (registration to the base, baudrate - and line format settings, device status queries) via the gigacontr - utility. Their use is controlled by the kernel configuration option - "Support for undocumented USB requests" (CONFIG_GIGASET_UNDOCREQ). If you - encounter error code -ENOTTY when trying to use some features of the - M105, try setting that option to "y" via 'make {x,menu}config' and - recompiling the driver. - -2.7. Unregistered Wireless Devices (M101/M105) +2.6. Unregistered Wireless Devices (M101/M105) ----------------------------------------- The main purpose of the ser_gigaset and usb_gigaset drivers is to allow the M101 and M105 wireless devices to be used as ISDN devices for ISDN @@ -215,8 +200,7 @@ GigaSet 307x Device Driver driver. In that situation, a restricted set of functions is available which includes, in particular, those necessary for registering the device to a base or for switching it between Fixed Part and Portable Part - modes. For the M105, these commands require the "Support for undocumented - USB requests" configuration option (see section 2.6.) to be enabled. + modes. 3. Troubleshooting --------------- @@ -247,19 +231,12 @@ GigaSet 307x Device Driver Select Unimodem mode for all DECT data adapters. (see section 2.4.) Problem: - You want to configure your USB DECT data adapter (M105) but gigacontr - reports an error: "/dev/ttyGU0: Inappropriate ioctl for device". - Solution: - Recompile the usb_gigaset driver with the kernel configuration option - CONFIG_GIGASET_UNDOCREQ set to 'y'. (see section 2.6.) - - Problem: Messages like this: usb_gigaset 3-2:1.0: Could not initialize the device. appear in your syslog. Solution: Check whether your M10x wireless device is correctly registered to the - Gigaset base. (see section 2.7.) + Gigaset base. (see section 2.6.) 3.2. Telling the driver to provide more information ---------------------------------------------- diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig index 754b90d..18ab865 100644 --- a/drivers/isdn/gigaset/Kconfig +++ b/drivers/isdn/gigaset/Kconfig @@ -43,11 +43,4 @@ config GIGASET_DEBUG This enables debugging code in the Gigaset drivers. If in doubt, say yes. -config GIGASET_UNDOCREQ - bool "Support for undocumented USB requests" - help - This enables support for USB requests we only know from - reverse engineering (currently M105 only). If you need - features like configuration mode of M105, say yes. - endif # ISDN_DRV_GIGASET diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index d783851..4deb1ab 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -153,8 +153,6 @@ static inline unsigned tiocm_to_gigaset(unsigned state) return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0); } -#ifdef CONFIG_GIGASET_UNDOCREQ -/* WARNING: EXPERIMENTAL! */ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsigned new_state) { @@ -176,6 +174,11 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, return 0; } +/* + * Set M105 configuration value + * using undocumented device commands reverse engineered from USB traces + * of the Siemens Windows driver + */ static int set_value(struct cardstate *cs, u8 req, u16 val) { struct usb_device *udev = cs->hw.usb->udev; @@ -205,8 +208,10 @@ static int set_value(struct cardstate *cs, u8 req, u16 val) return r < 0 ? r : (r2 < 0 ? r2 : 0); } -/* WARNING: HIGHLY EXPERIMENTAL! */ -// don't use this in an interrupt/BH +/* + * set the baud rate on the internal serial adapter + * using the undocumented parameter setting command + */ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) { u16 val; @@ -237,8 +242,10 @@ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) return set_value(cs, 1, val); } -/* WARNING: HIGHLY EXPERIMENTAL! */ -// don't use this in an interrupt/BH +/* + * set the line format on the internal serial adapter + * using the undocumented parameter setting command + */ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) { u16 val = 0; @@ -274,24 +281,6 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) return set_value(cs, 3, val); } -#else -static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) -{ - return -ENOTTY; -} - -static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) -{ - return -ENOTTY; -} - -static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) -{ - return -ENOTTY; -} -#endif - /*================================================================================================================*/ static int gigaset_init_bchannel(struct bc_state *bcs) @@ -362,10 +351,8 @@ static void gigaset_modem_fill(unsigned long data) } while (again); } -/** - * gigaset_read_int_callback - * - * It is called if the data was received from the device. +/* + * Interrupt Input URB completion routine */ static void gigaset_read_int_callback(struct urb *urb) { @@ -567,18 +554,19 @@ static int gigaset_chars_in_buffer(struct cardstate *cs) return cs->cmdbytes; } +/* + * set the break characters on the internal serial adapter + * using undocumented device commands reverse engineered from USB traces + * of the Siemens Windows driver + */ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) { -#ifdef CONFIG_GIGASET_UNDOCREQ struct usb_device *udev = cs->hw.usb->udev; gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, 0, 0, &buf, 6, 2000); -#else - return -ENOTTY; -#endif } static int gigaset_freebcshw(struct bc_state *bcs) @@ -625,7 +613,6 @@ static int gigaset_initcshw(struct cardstate *cs) ucs->bchars[5] = 0x13; ucs->bulk_out_buffer = NULL; ucs->bulk_out_urb = NULL; - //ucs->urb_cmd_out = NULL; ucs->read_urb = NULL; tasklet_init(&cs->write_tasklet, &gigaset_modem_fill, (unsigned long) cs); @@ -742,7 +729,7 @@ static int gigaset_probe(struct usb_interface *interface, cs->dev = &interface->dev; /* save address of controller structure */ - usb_set_intfdata(interface, cs); // dev_set_drvdata(&interface->dev, cs); + usb_set_intfdata(interface, cs); endpoint = &hostif->endpoint[0].desc; @@ -921,8 +908,7 @@ static const struct gigaset_ops ops = { gigaset_m10x_input, }; -/** - * usb_gigaset_init +/* * This function is called while kernel-module is loaded */ static int __init usb_gigaset_init(void) @@ -952,9 +938,7 @@ error: return -1; } - -/** - * usb_gigaset_exit +/* * This function is called while unloading the kernel-module */ static void __exit usb_gigaset_exit(void) -- cgit v0.10.2 From 0a305720ee597aad41af61e6b6844321d3e24251 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 13 May 2009 12:44:18 +0000 Subject: gigaset: remove unused structure member rcvbytes The B channel data structure member rcvbytes was never set to anything else but zero, so drop it. Impact: cleanup Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 2a4ce96..234cc5d 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -174,9 +174,8 @@ byte_stuff: if (unlikely(fcs != PPP_GOODFCS)) { dev_err(cs->dev, - "Packet checksum at %lu failed, " - "packet is corrupted (%u bytes)!\n", - bcs->rcvbytes, skb->len); + "Checksum failed, %u bytes corrupted!\n", + skb->len); compskb = NULL; gigaset_rcv_error(compskb, cs, bcs); error = 1; diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 79c9b0f..e4141bf 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -565,8 +565,6 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel); gigaset_at_init(&bcs->at_state, bcs, cs, -1); - bcs->rcvbytes = 0; - #ifdef CONFIG_GIGASET_DEBUG bcs->emptycount = 0; #endif diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index d5f0110..a2f6125 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -384,7 +384,6 @@ struct bc_state { int trans_up; /* Counter of packages (upstream) */ struct at_state_t at_state; - unsigned long rcvbytes; __u16 fcs; struct sk_buff *skb; -- cgit v0.10.2 From 9d21493b4beb8f918ba248032fefa393074a5e2b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 17 May 2009 20:55:16 -0700 Subject: net: tx scalability works : trans_start struct net_device trans_start field is a hot spot on SMP and high performance devices, particularly multi queues ones, because every transmitter dirties it. Is main use is tx watchdog and bonding alive checks. But as most devices dont use NETIF_F_LLTX, we have to lock a netdev_queue before calling their ndo_start_xmit(). So it makes sense to move trans_start from net_device to netdev_queue. Its update will occur on a already present (and in exclusive state) cache line, for free. We can do this transition smoothly. An old driver continue to update dev->trans_start, while an updated one updates txq->trans_start. Further patches could also put tx_bytes/tx_packets counters in netdev_queue to avoid dirtying dev->stats (vlan device comes to mind) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 815191d..30b9ea6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2795,7 +2795,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) */ bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks) && + if (time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks) && time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) { slave->link = BOND_LINK_UP; @@ -2827,7 +2827,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || + if (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2*delta_in_ticks) || (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) { slave->link = BOND_LINK_DOWN; @@ -2938,7 +2938,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) * the bond has an IP address) */ if ((slave->state == BOND_STATE_ACTIVE) && - (time_after_eq(jiffies, slave->dev->trans_start + + (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2 * delta_in_ticks) || (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2 * delta_in_ticks)))) { @@ -2982,7 +2982,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) write_lock_bh(&bond->curr_slave_lock); if (!bond->curr_active_slave && - time_before_eq(jiffies, slave->dev->trans_start + + time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks)) { slave->link = BOND_LINK_UP; bond_change_active_slave(bond, slave); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2af89b6..cd547d0 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -470,6 +470,10 @@ struct netdev_queue { */ spinlock_t _xmit_lock ____cacheline_aligned_in_smp; int xmit_lock_owner; + /* + * please use this field instead of dev->trans_start + */ + unsigned long trans_start; } ____cacheline_aligned_in_smp; @@ -819,6 +823,11 @@ struct net_device * One part is mostly used on xmit path (device) */ /* These may be needed for future network-power-down code. */ + + /* + * trans_start here is expensive for high speed devices on SMP, + * please use netdev_queue->trans_start instead. + */ unsigned long trans_start; /* Time (in jiffies) of last Tx */ int watchdog_timeo; /* used by dev_watchdog() */ @@ -1541,6 +1550,8 @@ static inline int netif_carrier_ok(const struct net_device *dev) return !test_bit(__LINK_STATE_NOCARRIER, &dev->state); } +extern unsigned long dev_trans_start(struct net_device *dev); + extern void __netdev_watchdog_up(struct net_device *dev); extern void netif_carrier_on(struct net_device *dev); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 5f5efe4..27d0381 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -196,6 +196,21 @@ void __qdisc_run(struct Qdisc *q) clear_bit(__QDISC_STATE_RUNNING, &q->state); } +unsigned long dev_trans_start(struct net_device *dev) +{ + unsigned long val, res = dev->trans_start; + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + val = netdev_get_tx_queue(dev, i)->trans_start; + if (val && time_after(val, res)) + res = val; + } + dev->trans_start = res; + return res; +} +EXPORT_SYMBOL(dev_trans_start); + static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; @@ -205,25 +220,30 @@ static void dev_watchdog(unsigned long arg) if (netif_device_present(dev) && netif_running(dev) && netif_carrier_ok(dev)) { - int some_queue_stopped = 0; + int some_queue_timedout = 0; unsigned int i; + unsigned long trans_start; for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *txq; txq = netdev_get_tx_queue(dev, i); - if (netif_tx_queue_stopped(txq)) { - some_queue_stopped = 1; + /* + * old device drivers set dev->trans_start + */ + trans_start = txq->trans_start ? : dev->trans_start; + if (netif_tx_queue_stopped(txq) && + time_after(jiffies, (trans_start + + dev->watchdog_timeo))) { + some_queue_timedout = 1; break; } } - if (some_queue_stopped && - time_after(jiffies, (dev->trans_start + - dev->watchdog_timeo))) { + if (some_queue_timedout) { char drivername[64]; - WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n", - dev->name, netdev_drivername(dev, drivername, 64)); + WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n", + dev->name, netdev_drivername(dev, drivername, 64), i); dev->netdev_ops->ndo_tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, @@ -602,8 +622,10 @@ static void transition_one_qdisc(struct net_device *dev, clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state); rcu_assign_pointer(dev_queue->qdisc, new_qdisc); - if (need_watchdog_p && new_qdisc != &noqueue_qdisc) + if (need_watchdog_p && new_qdisc != &noqueue_qdisc) { + dev_queue->trans_start = 0; *need_watchdog_p = 1; + } } void dev_activate(struct net_device *dev) -- cgit v0.10.2 From 61189c78bda846f4682c6003e893362f4305518b Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 13 May 2009 10:09:53 +0000 Subject: dm9601: trivial comment fixes The comments describing the rx/tx headers used a combination of zero- and 1-based indexing, leading to confusion. Signed-off-by: Peter Korsgaard Signed-off-by: David S. Miller diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 6fc4f82..7ae8244 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -497,10 +497,10 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) int len; /* format: - b0: rx status - b1: packet length (incl crc) low - b2: packet length (incl crc) high - b3..n-4: packet data + b1: rx status + b2: packet length (incl crc) low + b3: packet length (incl crc) high + b4..n-4: packet data bn-3..bn: ethernet crc */ @@ -533,8 +533,8 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, int len; /* format: - b0: packet length low - b1: packet length high + b1: packet length low + b2: packet length high b3..n: packet data */ -- cgit v0.10.2 From df18acca8eb13c8cf55fa45e9f9231dc51f64d98 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 13 May 2009 10:10:41 +0000 Subject: smsc95xx: strip ethernet fcs (crc) on receive path The smsc95xx driver was forwarding the trailing fcs on received frames up the stack leading to confusion in tcpdump. Signed-off-by: Peter Korsgaard Tested-by: Steve Glendinning Acked-by: Steve Glendinning Signed-off-by: David S. Miller diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 5a72833..89a91f8 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1134,7 +1134,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (skb->len == size) { if (pdata->use_rx_csum) smsc95xx_rx_csum_offload(skb); - + skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); return 1; @@ -1152,7 +1152,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (pdata->use_rx_csum) smsc95xx_rx_csum_offload(ax_skb); - + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); usbnet_skb_return(dev, ax_skb); -- cgit v0.10.2 From f2a3e626202a87734a47153935ec9d15c7fcf761 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 15 May 2009 06:04:12 +0000 Subject: mdio: Add 10GBASE-T SNR register definition These do not have an in-kernel user but may be useful to user-space. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 26b4eb3..825f1e2 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -46,6 +46,8 @@ /* Media-dependent registers. */ #define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ +#define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A. + * Lanes B-D are numbered 134-136. */ #define MDIO_PMA_10GBR_FECABLE 170 /* 10GBASE-R FEC ability */ #define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */ #define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */ @@ -188,6 +190,11 @@ /* PMA 10GBASE-T TX power register. */ #define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */ +/* PMA 10GBASE-T SNR registers. */ +/* Value is SNR margin in dB, clamped to range [-127, 127], plus 0x8000. */ +#define MDIO_PMA_10GBT_SNR_BIAS 0x8000 +#define MDIO_PMA_10GBT_SNR_MAX 127 + /* PMA 10GBASE-R FEC ability register. */ #define MDIO_PMA_10GBR_FECABLE_ABLE 0x0001 /* FEC ability */ #define MDIO_PMA_10GBR_FECABLE_ERRABLE 0x0002 /* FEC error indic. ability */ -- cgit v0.10.2 From e0b221bf4e07edf2fda645e457dc3c35c2f2f3a9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 15 May 2009 06:05:49 +0000 Subject: mdio: Add XENPAK LASI register definitions These registers were originally defined for XENPAK modules, but are also implemented by many other 10G PHYs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 825f1e2..5685164 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -55,6 +55,14 @@ #define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */ #define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */ +/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */ +#define MDIO_PMA_LASI_RXCTRL 0x9000 /* RX_ALARM control */ +#define MDIO_PMA_LASI_TXCTRL 0x9001 /* TX_ALARM control */ +#define MDIO_PMA_LASI_CTRL 0x9002 /* LASI control */ +#define MDIO_PMA_LASI_RXSTAT 0x9003 /* RX_ALARM status */ +#define MDIO_PMA_LASI_TXSTAT 0x9004 /* TX_ALARM status */ +#define MDIO_PMA_LASI_STAT 0x9005 /* LASI status */ + /* Control register 1. */ /* Enable extended speed selection */ #define MDIO_CTRL1_SPEEDSELEXT (BMCR_SPEED1000 | BMCR_SPEED100) @@ -218,6 +226,26 @@ #define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */ #define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */ +/* LASI RX_ALARM control/status registers. */ +#define MDIO_PMA_LASI_RX_PHYXSLFLT 0x0001 /* PHY XS RX local fault */ +#define MDIO_PMA_LASI_RX_PCSLFLT 0x0008 /* PCS RX local fault */ +#define MDIO_PMA_LASI_RX_PMALFLT 0x0010 /* PMA/PMD RX local fault */ +#define MDIO_PMA_LASI_RX_OPTICPOWERFLT 0x0020 /* RX optical power fault */ +#define MDIO_PMA_LASI_RX_WISLFLT 0x0200 /* WIS local fault */ + +/* LASI TX_ALARM control/status registers. */ +#define MDIO_PMA_LASI_TX_PHYXSLFLT 0x0001 /* PHY XS TX local fault */ +#define MDIO_PMA_LASI_TX_PCSLFLT 0x0008 /* PCS TX local fault */ +#define MDIO_PMA_LASI_TX_PMALFLT 0x0010 /* PMA/PMD TX local fault */ +#define MDIO_PMA_LASI_TX_LASERPOWERFLT 0x0080 /* Laser output power fault */ +#define MDIO_PMA_LASI_TX_LASERTEMPFLT 0x0100 /* Laser temperature fault */ +#define MDIO_PMA_LASI_TX_LASERBICURRFLT 0x0200 /* Laser bias current fault */ + +/* LASI control/status registers. */ +#define MDIO_PMA_LASI_LSALARM 0x0001 /* LS_ALARM enable/status */ +#define MDIO_PMA_LASI_TXALARM 0x0002 /* TX_ALARM enable/status */ +#define MDIO_PMA_LASI_RXALARM 0x0004 /* RX_ALARM enable/status */ + /* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */ #define MDIO_PHY_ID_C45 0x8000 -- cgit v0.10.2 From 6bc5046e6df7d7122631c82ccaa6edf7085331ac Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 15 May 2009 06:06:16 +0000 Subject: sfc: Use generic XENPAK register definitions Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 0421190..db723c5 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -44,18 +44,6 @@ */ #define MAX_BAD_LP_TRIES (5) -/* LASI Control */ -#define PMA_PMD_LASI_CTRL 36866 -#define PMA_PMD_LASI_STATUS 36869 -#define PMA_PMD_LS_ALARM_LBN 0 -#define PMA_PMD_LS_ALARM_WIDTH 1 -#define PMA_PMD_TX_ALARM_LBN 1 -#define PMA_PMD_TX_ALARM_WIDTH 1 -#define PMA_PMD_RX_ALARM_LBN 2 -#define PMA_PMD_RX_ALARM_WIDTH 1 -#define PMA_PMD_AN_ALARM_LBN 3 -#define PMA_PMD_AN_ALARM_WIDTH 1 - /* Extended control register */ #define PMA_PMD_XCONTROL_REG 49152 #define PMA_PMD_EXT_GMII_EN_LBN 1 @@ -579,8 +567,8 @@ static void tenxpress_phy_poll(struct efx_nic *efx) change = true; } else { int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, - PMA_PMD_LASI_STATUS); - if (status & (1 << PMA_PMD_LS_ALARM_LBN)) + MDIO_PMA_LASI_STAT); + if (status & MDIO_PMA_LASI_LSALARM) change = true; } diff --git a/drivers/net/sfc/xenpack.h b/drivers/net/sfc/xenpack.h deleted file mode 100644 index 4e52286..0000000 --- a/drivers/net/sfc/xenpack.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_XENPACK_H -#define EFX_XENPACK_H - -/* Exported functions from Xenpack standard PHY control */ - -#include "mdio_10g.h" - -/****************************************************************************/ -/* XENPACK MDIO register extensions */ -#define MDIO_XP_LASI_RX_CTRL (0x9000) -#define MDIO_XP_LASI_TX_CTRL (0x9001) -#define MDIO_XP_LASI_CTRL (0x9002) -#define MDIO_XP_LASI_RX_STAT (0x9003) -#define MDIO_XP_LASI_TX_STAT (0x9004) -#define MDIO_XP_LASI_STAT (0x9005) - -/* Control/Status bits */ -#define XP_LASI_LS_ALARM (1 << 0) -#define XP_LASI_TX_ALARM (1 << 1) -#define XP_LASI_RX_ALARM (1 << 2) -/* These two are Quake vendor extensions to the standard XENPACK defines */ -#define XP_LASI_LS_INTB (1 << 3) -#define XP_LASI_TEST (1 << 7) - -/* Enable LASI interrupts for PHY */ -static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx) -{ - /* Read to clear LASI status register */ - efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT); - - efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL, - XP_LASI_LS_ALARM); -} - -/* Read the LASI interrupt status to clear the interrupt. */ -static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx) -{ - /* Read to clear link status alarm */ - return efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT); -} - -/* Turn off LASI interrupts */ -static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx) -{ - efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL, 0); -} - -#endif /* EFX_XENPACK_H */ diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index aad2dca..bb2e6af 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -15,7 +15,6 @@ #include #include "efx.h" #include "mdio_10g.h" -#include "xenpack.h" #include "phy.h" #include "falcon.h" @@ -169,7 +168,8 @@ static int xfp_phy_init(struct efx_nic *efx) static void xfp_phy_clear_interrupt(struct efx_nic *efx) { - xenpack_clear_lasi_irqs(efx); + /* Read to clear link status alarm */ + efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT); } static int xfp_link_ok(struct efx_nic *efx) -- cgit v0.10.2 From 7290383191fa57d7f6320e27a03e5a8afee362fd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 15 May 2009 07:59:42 +0000 Subject: drivers/net: Convert #ifdef DEBUG printk(KERN_DEBUG to pr_debug( Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 0ce2db6..d737f6b 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -688,14 +688,11 @@ static void tc_handle_link_change(struct net_device *dev) if (status_change && netif_msg_link(lp)) { phy_print_status(phydev); -#ifdef DEBUG - printk(KERN_DEBUG - "%s: MII BMCR %04x BMSR %04x LPA %04x\n", - dev->name, - phy_read(phydev, MII_BMCR), - phy_read(phydev, MII_BMSR), - phy_read(phydev, MII_LPA)); -#endif + pr_debug("%s: MII BMCR %04x BMSR %04x LPA %04x\n", + dev->name, + phy_read(phydev, MII_BMCR), + phy_read(phydev, MII_BMSR), + phy_read(phydev, MII_LPA)); } } -- cgit v0.10.2 From 62abb45f50dbd53a117aff72ff4e606592edb029 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 15 May 2009 10:22:38 +0000 Subject: de620: fix forgotten semicolon It seems it always was here. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/de620.c b/drivers/net/de620.c index d52f34c..c5cd6e3 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -533,7 +533,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Start real output */ - spin_lock_irqsave(&de620_lock, flags) + spin_lock_irqsave(&de620_lock, flags); PRINTK(("de620_start_xmit: len=%d, bufs 0x%02x\n", (int)skb->len, using_txbuf)); -- cgit v0.10.2 From 64303258961c74f0168e056da14b612ce839dbc1 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 15 May 2009 10:22:39 +0000 Subject: de600: convert PRINTK() to pr_debug() Also remove de600_debug as it is not needed. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/de600.c b/drivers/net/de600.c index de63f1d..c866ca9 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -38,14 +38,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj /* Add more time here if your adapter won't work OK: */ #define DE600_SLOW_DOWN udelay(delay_time) -/* use 0 for production, 1 for verification, >2 for debug */ -#ifdef DE600_DEBUG -#define PRINTK(x) if (de600_debug >= 2) printk x -#else -#define DE600_DEBUG 0 -#define PRINTK(x) /**/ -#endif - #include #include #include @@ -67,10 +59,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj #include "de600.h" -static unsigned int de600_debug = DE600_DEBUG; -module_param(de600_debug, int, 0); -MODULE_PARM_DESC(de600_debug, "DE-600 debug level (0-2)"); - static unsigned int check_lost = 1; module_param(check_lost, bool, 0); MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600"); @@ -193,7 +181,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Start real output */ - PRINTK(("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages)); + pr_debug("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages); if ((len = skb->len) < RUNT) len = RUNT; @@ -259,7 +247,7 @@ static irqreturn_t de600_interrupt(int irq, void *dev_id) irq_status = de600_read_status(dev); do { - PRINTK(("de600_interrupt (%02X)\n", irq_status)); + pr_debug("de600_interrupt (%02X)\n", irq_status); if (irq_status & RX_GOOD) de600_rx_intr(dev); @@ -407,8 +395,7 @@ static struct net_device * __init de600_probe(void) printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name); /* Alpha testers must have the version number to report bugs. */ - if (de600_debug > 1) - printk(version); + pr_debug("%s", version); /* probe for adapter */ err = -ENODEV; -- cgit v0.10.2 From 2818fba1322c469181603a1fbffadf3d3c5cb1e0 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 15 May 2009 10:22:40 +0000 Subject: de620: convert PRINTK() to pr_debug() and cleanup Also remove DE620_DEBUG and de620_debug. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/de620.c b/drivers/net/de620.c index c5cd6e3..039bc1a 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -48,7 +48,6 @@ static const char version[] = * Compile-time options: (see below for descriptions) * -DDE620_IO=0x378 (lpt1) * -DDE620_IRQ=7 (lpt1) - * -DDE602_DEBUG=... * -DSHUTDOWN_WHEN_LOST * -DCOUNT_LOOPS * -DLOWSPEED @@ -98,15 +97,6 @@ static const char version[] = #define SHUTDOWN_WHEN_LOST */ -/* - * Enable debugging by "-DDE620_DEBUG=3" when compiling, - * OR by enabling the following #define - * - * use 0 for production, 1 for verification, >2 for debug - * -#define DE620_DEBUG 3 - */ - #ifdef LOWSPEED /* * Enable this #define if you want to see debugging output that show how long @@ -160,14 +150,6 @@ typedef unsigned char byte; #define RUNT 60 /* Too small Ethernet packet */ #define GIANT 1514 /* largest legal size packet, no fcs */ -#ifdef DE620_DEBUG /* Compile-time configurable */ -#define PRINTK(x) if (de620_debug >= 2) printk x -#else -#define DE620_DEBUG 0 -#define PRINTK(x) /**/ -#endif - - /* * Force media with insmod: * insmod de620.o bnc=1 @@ -186,8 +168,6 @@ static int io = DE620_IO; static int irq = DE620_IRQ; static int clone = DE620_CLONE; -static unsigned int de620_debug = DE620_DEBUG; - static spinlock_t de620_lock; module_param(bnc, int, 0); @@ -195,13 +175,11 @@ module_param(utp, int, 0); module_param(io, int, 0); module_param(irq, int, 0); module_param(clone, int, 0); -module_param(de620_debug, int, 0); MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)"); MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)"); MODULE_PARM_DESC(io, "DE-620 I/O base address,required"); MODULE_PARM_DESC(irq, "DE-620 IRQ number,required"); MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)"); -MODULE_PARM_DESC(de620_debug, "DE-620 debug level (0-2)"); /*********************************************** * * @@ -534,8 +512,8 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Start real output */ spin_lock_irqsave(&de620_lock, flags); - PRINTK(("de620_start_xmit: len=%d, bufs 0x%02x\n", - (int)skb->len, using_txbuf)); + pr_debug("de620_start_xmit: len=%d, bufs 0x%02x\n", + (int)skb->len, using_txbuf); /* select a free tx buffer. if there is one... */ switch (using_txbuf) { @@ -585,12 +563,12 @@ de620_interrupt(int irq_in, void *dev_id) /* Read the status register (_not_ the status port) */ irq_status = de620_get_register(dev, R_STS); - PRINTK(("de620_interrupt (%2.2X)\n", irq_status)); + pr_debug("de620_interrupt (%2.2X)\n", irq_status); if (irq_status & RXGOOD) { do { again = de620_rx_intr(dev); - PRINTK(("again=%d\n", again)); + pr_debug("again=%d\n", again); } while (again && (++bogus_count < 100)); } @@ -622,7 +600,7 @@ static int de620_rx_intr(struct net_device *dev) byte pagelink; byte curr_page; - PRINTK(("de620_rx_intr: next_rx_page = %d\n", next_rx_page)); + pr_debug("de620_rx_intr: next_rx_page = %d\n", next_rx_page); /* Tell the adapter that we are going to read data, and from where */ de620_send_command(dev, W_CR | RRN); @@ -631,8 +609,9 @@ static int de620_rx_intr(struct net_device *dev) /* Deep breath, and away we goooooo */ de620_read_block(dev, (byte *)&header_buf, sizeof(struct header_buf)); - PRINTK(("page status=0x%02x, nextpage=%d, packetsize=%d\n", - header_buf.status, header_buf.Rx_NextPage, header_buf.Rx_ByteCount)); + pr_debug("page status=0x%02x, nextpage=%d, packetsize=%d\n", + header_buf.status, header_buf.Rx_NextPage, + header_buf.Rx_ByteCount); /* Plausible page header? */ pagelink = header_buf.Rx_NextPage; @@ -683,7 +662,7 @@ static int de620_rx_intr(struct net_device *dev) buffer = skb_put(skb,size); /* copy the packet into the buffer */ de620_read_block(dev, buffer, size); - PRINTK(("Read %d bytes\n", size)); + pr_debug("Read %d bytes\n", size); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* deliver it "upstairs" */ /* count all receives */ @@ -696,7 +675,7 @@ static int de620_rx_intr(struct net_device *dev) /* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */ curr_page = de620_get_register(dev, R_CPR); de620_set_register(dev, W_NPRF, next_rx_page); - PRINTK(("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page)); + pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page); return (next_rx_page != curr_page); /* That was slightly tricky... */ } @@ -830,8 +809,7 @@ struct net_device * __init de620_probe(int unit) netdev_boot_setup_check(dev); } - if (de620_debug) - printk(version); + pr_debug("%s", version); printk(KERN_INFO "D-Link DE-620 pocket adapter"); @@ -878,14 +856,13 @@ struct net_device * __init de620_probe(int unit) /* base_addr and irq are already set, see above! */ /* dump eeprom */ - if (de620_debug) { - printk("\nEEPROM contents:\n"); - printk("RAM_Size = 0x%02X\n", nic_data.RAM_Size); - printk("NodeID = %pM\n", nic_data.NodeID); - printk("Model = %d\n", nic_data.Model); - printk("Media = %d\n", nic_data.Media); - printk("SCR = 0x%02x\n", nic_data.SCR); - } + pr_debug("\nEEPROM contents:\n" + "RAM_Size = 0x%02X\n" + "NodeID = %pM\n" + "Model = %d\n" + "Media = %d\n" + "SCR = 0x%02x\n", nic_data.RAM_Size, nic_data.NodeID, + nic_data.Model, nic_data.Media, nic_data.SCR); err = register_netdev(dev); if (err) -- cgit v0.10.2 From c7b1f4f376867356ca001c6a81988cf41fa4dc43 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 15 May 2009 10:22:41 +0000 Subject: mac89x0: remove PRINTK() There are no users of it. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 384e072..e24175a 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -73,8 +73,6 @@ static char *version = or override something. */ #include -#define PRINTK(x) printk x - /* Sources: -- cgit v0.10.2 From ebc06eeb7260ecad3bd69202ba6291138691d27b Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 15 May 2009 10:22:42 +0000 Subject: skfddi: convert PRINTK() to pr_debug() Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index e14aec0..19d343c4 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -159,12 +159,6 @@ MODULE_AUTHOR("Mirko Lindner "); static int num_boards; /* total number of adapters configured */ -#ifdef DRIVERDEBUG -#define PRINTK(s, args...) printk(s, ## args) -#else -#define PRINTK(s, args...) -#endif // DRIVERDEBUG - static const struct net_device_ops skfp_netdev_ops = { .ndo_open = skfp_open, .ndo_stop = skfp_close, @@ -213,7 +207,7 @@ static int skfp_init_one(struct pci_dev *pdev, void __iomem *mem; int err; - PRINTK(KERN_INFO "entering skfp_init_one\n"); + pr_debug(KERN_INFO "entering skfp_init_one\n"); if (num_boards == 0) printk("%s\n", boot_msg); @@ -389,7 +383,7 @@ static int skfp_driver_init(struct net_device *dev) skfddi_priv *bp = &smc->os; int err = -EIO; - PRINTK(KERN_INFO "entering skfp_driver_init\n"); + pr_debug(KERN_INFO "entering skfp_driver_init\n"); // set the io address in private structures bp->base_addr = dev->base_addr; @@ -409,7 +403,7 @@ static int skfp_driver_init(struct net_device *dev) // Determine the required size of the 'shared' memory area. bp->SharedMemSize = mac_drv_check_space(); - PRINTK(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize); + pr_debug(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize); if (bp->SharedMemSize > 0) { bp->SharedMemSize += 16; // for descriptor alignment @@ -433,13 +427,13 @@ static int skfp_driver_init(struct net_device *dev) card_stop(smc); // Reset adapter. - PRINTK(KERN_INFO "mac_drv_init()..\n"); + pr_debug(KERN_INFO "mac_drv_init()..\n"); if (mac_drv_init(smc) != 0) { - PRINTK(KERN_INFO "mac_drv_init() failed.\n"); + pr_debug(KERN_INFO "mac_drv_init() failed.\n"); goto fail; } read_address(smc, NULL); - PRINTK(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n", + pr_debug(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n", smc->hw.fddi_canon_addr.a[0], smc->hw.fddi_canon_addr.a[1], smc->hw.fddi_canon_addr.a[2], @@ -495,7 +489,7 @@ static int skfp_open(struct net_device *dev) struct s_smc *smc = netdev_priv(dev); int err; - PRINTK(KERN_INFO "entering skfp_open\n"); + pr_debug(KERN_INFO "entering skfp_open\n"); /* Register IRQ - support shared interrupts by passing device ptr */ err = request_irq(dev->irq, skfp_interrupt, IRQF_SHARED, dev->name, dev); @@ -868,12 +862,12 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) /* Enable promiscuous mode, if necessary */ if (dev->flags & IFF_PROMISC) { mac_drv_rx_mode(smc, RX_ENABLE_PROMISC); - PRINTK(KERN_INFO "PROMISCUOUS MODE ENABLED\n"); + pr_debug(KERN_INFO "PROMISCUOUS MODE ENABLED\n"); } /* Else, update multicast address table */ else { mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); - PRINTK(KERN_INFO "PROMISCUOUS MODE DISABLED\n"); + pr_debug(KERN_INFO "PROMISCUOUS MODE DISABLED\n"); // Reset all MC addresses mac_clear_multicast(smc); @@ -881,7 +875,7 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); - PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); + pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); } else if (dev->mc_count > 0) { if (dev->mc_count <= FPMAX_MULTICAST) { /* use exact filtering */ @@ -894,12 +888,12 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) (struct fddi_addr *)dmi->dmi_addr, 1); - PRINTK(KERN_INFO "ENABLE MC ADDRESS:"); - PRINTK(" %02x %02x %02x ", + pr_debug(KERN_INFO "ENABLE MC ADDRESS:"); + pr_debug(" %02x %02x %02x ", dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2]); - PRINTK("%02x %02x %02x\n", + pr_debug("%02x %02x %02x\n", dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); @@ -909,11 +903,11 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) } else { // more MC addresses than HW supports mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); - PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); + pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); } } else { // no MC addresses - PRINTK(KERN_INFO "DISABLE ALL MC ADDRESSES\n"); + pr_debug(KERN_INFO "DISABLE ALL MC ADDRESSES\n"); } /* Update adapter filters */ @@ -1067,7 +1061,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) struct s_smc *smc = netdev_priv(dev); skfddi_priv *bp = &smc->os; - PRINTK(KERN_INFO "skfp_send_pkt\n"); + pr_debug(KERN_INFO "skfp_send_pkt\n"); /* * Verify that incoming transmit request is OK @@ -1137,13 +1131,13 @@ static void send_queued_packets(struct s_smc *smc) int frame_status; // HWM tx frame status. - PRINTK(KERN_INFO "send queued packets\n"); + pr_debug(KERN_INFO "send queued packets\n"); for (;;) { // send first buffer from queue skb = skb_dequeue(&bp->SendSkbQueue); if (!skb) { - PRINTK(KERN_INFO "queue empty\n"); + pr_debug(KERN_INFO "queue empty\n"); return; } // queue empty ! @@ -1174,11 +1168,11 @@ static void send_queued_packets(struct s_smc *smc) if ((frame_status & RING_DOWN) != 0) { // Ring is down. - PRINTK("Tx attempt while ring down.\n"); + pr_debug("Tx attempt while ring down.\n"); } else if ((frame_status & OUT_OF_TXD) != 0) { - PRINTK("%s: out of TXDs.\n", bp->dev->name); + pr_debug("%s: out of TXDs.\n", bp->dev->name); } else { - PRINTK("%s: out of transmit resources", + pr_debug("%s: out of transmit resources", bp->dev->name); } @@ -1255,7 +1249,7 @@ static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) static void ResetAdapter(struct s_smc *smc) { - PRINTK(KERN_INFO "[fddi: ResetAdapter]\n"); + pr_debug(KERN_INFO "[fddi: ResetAdapter]\n"); // Stop the adapter. @@ -1301,7 +1295,7 @@ void llc_restart_tx(struct s_smc *smc) { skfddi_priv *bp = &smc->os; - PRINTK(KERN_INFO "[llc_restart_tx]\n"); + pr_debug(KERN_INFO "[llc_restart_tx]\n"); // Try to send queued packets spin_unlock(&bp->DriverLock); @@ -1331,7 +1325,7 @@ void *mac_drv_get_space(struct s_smc *smc, unsigned int size) { void *virt; - PRINTK(KERN_INFO "mac_drv_get_space (%d bytes), ", size); + pr_debug(KERN_INFO "mac_drv_get_space (%d bytes), ", size); virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap); if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) { @@ -1340,9 +1334,9 @@ void *mac_drv_get_space(struct s_smc *smc, unsigned int size) } smc->os.SharedMemHeap += size; // Move heap pointer. - PRINTK(KERN_INFO "mac_drv_get_space end\n"); - PRINTK(KERN_INFO "virt addr: %lx\n", (ulong) virt); - PRINTK(KERN_INFO "bus addr: %lx\n", (ulong) + pr_debug(KERN_INFO "mac_drv_get_space end\n"); + pr_debug(KERN_INFO "virt addr: %lx\n", (ulong) virt); + pr_debug(KERN_INFO "bus addr: %lx\n", (ulong) (smc->os.SharedMemDMA + ((char *) virt - (char *)smc->os.SharedMemAddr))); return (virt); @@ -1372,7 +1366,7 @@ void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size) char *virt; - PRINTK(KERN_INFO "mac_drv_get_desc_mem\n"); + pr_debug(KERN_INFO "mac_drv_get_desc_mem\n"); // Descriptor memory must be aligned on 16-byte boundary. @@ -1381,8 +1375,8 @@ void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size) size = (u_int) (16 - (((unsigned long) virt) & 15UL)); size = size % 16; - PRINTK("Allocate %u bytes alignment gap ", size); - PRINTK("for descriptor memory.\n"); + pr_debug("Allocate %u bytes alignment gap ", size); + pr_debug("for descriptor memory.\n"); if (!mac_drv_get_space(smc, size)) { printk("fddi: Unable to align descriptor memory.\n"); @@ -1516,11 +1510,11 @@ void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) { struct sk_buff *skb; - PRINTK(KERN_INFO "entering mac_drv_tx_complete\n"); + pr_debug(KERN_INFO "entering mac_drv_tx_complete\n"); // Check if this TxD points to a skb if (!(skb = txd->txd_os.skb)) { - PRINTK("TXD with no skb assigned.\n"); + pr_debug("TXD with no skb assigned.\n"); return; } txd->txd_os.skb = NULL; @@ -1536,7 +1530,7 @@ void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) // free the skb dev_kfree_skb_irq(skb); - PRINTK(KERN_INFO "leaving mac_drv_tx_complete\n"); + pr_debug(KERN_INFO "leaving mac_drv_tx_complete\n"); } // mac_drv_tx_complete @@ -1603,7 +1597,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, unsigned short ri; u_int RifLength; - PRINTK(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len); + pr_debug(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len); if (frag_count != 1) { // This is not allowed to happen. printk("fddi: Multi-fragment receive!\n"); @@ -1612,7 +1606,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, } skb = rxd->rxd_os.skb; if (!skb) { - PRINTK(KERN_INFO "No skb in rxd\n"); + pr_debug(KERN_INFO "No skb in rxd\n"); smc->os.MacStat.gen.rx_errors++; goto RequeueRxd; } @@ -1642,7 +1636,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, else { int n; // goos: RIF removal has still to be tested - PRINTK(KERN_INFO "RIF found\n"); + pr_debug(KERN_INFO "RIF found\n"); // Get RIF length from Routing Control (RC) field. cp = virt + FDDI_MAC_HDR_LEN; // Point behind MAC header. @@ -1687,7 +1681,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, return; RequeueRxd: - PRINTK(KERN_INFO "Rx: re-queue RXD.\n"); + pr_debug(KERN_INFO "Rx: re-queue RXD.\n"); mac_drv_requeue_rxd(smc, rxd, frag_count); smc->os.MacStat.gen.rx_errors++; // Count receive packets // not indicated. @@ -1736,7 +1730,7 @@ void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, skb = src_rxd->rxd_os.skb; if (skb == NULL) { // this should not happen - PRINTK("Requeue with no skb in rxd!\n"); + pr_debug("Requeue with no skb in rxd!\n"); skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); if (skb) { // we got a skb @@ -1751,7 +1745,7 @@ void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, rxd->rxd_os.dma_addr = b_addr; } else { // no skb available, use local buffer - PRINTK("Queueing invalid buffer!\n"); + pr_debug("Queueing invalid buffer!\n"); rxd->rxd_os.skb = NULL; v_addr = smc->os.LocalRxBuffer; b_addr = smc->os.LocalRxBufferDMA; @@ -1798,7 +1792,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) struct sk_buff *skb; volatile struct s_smt_fp_rxd *rxd; - PRINTK(KERN_INFO "entering mac_drv_fill_rxd\n"); + pr_debug(KERN_INFO "entering mac_drv_fill_rxd\n"); // Walk through the list of free receive buffers, passing receive // buffers to the HWM as long as RXDs are available. @@ -1806,7 +1800,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) MaxFrameSize = smc->os.MaxFrameSize; // Check if there is any RXD left. while (HWM_GET_RX_FREE(smc) > 0) { - PRINTK(KERN_INFO ".\n"); + pr_debug(KERN_INFO ".\n"); rxd = HWM_GET_CURR_RXD(smc); skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); @@ -1826,7 +1820,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) // keep the receiver running in hope of better times. // Multiple descriptors may point to this local buffer, // so data in it must be considered invalid. - PRINTK("Queueing invalid buffer!\n"); + pr_debug("Queueing invalid buffer!\n"); v_addr = smc->os.LocalRxBuffer; b_addr = smc->os.LocalRxBufferDMA; } @@ -1837,7 +1831,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, FIRST_FRAG | LAST_FRAG); } - PRINTK(KERN_INFO "leaving mac_drv_fill_rxd\n"); + pr_debug(KERN_INFO "leaving mac_drv_fill_rxd\n"); } // mac_drv_fill_rxd @@ -1863,7 +1857,7 @@ void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, struct sk_buff *skb; - PRINTK("entering mac_drv_clear_rxd\n"); + pr_debug("entering mac_drv_clear_rxd\n"); if (frag_count != 1) // This is not allowed to happen. @@ -1919,19 +1913,19 @@ int mac_drv_rx_init(struct s_smc *smc, int len, int fc, { struct sk_buff *skb; - PRINTK("entering mac_drv_rx_init(len=%d)\n", len); + pr_debug("entering mac_drv_rx_init(len=%d)\n", len); // "Received" a SMT or NSA frame of the local SMT. if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) { - PRINTK("fddi: Discard invalid local SMT frame\n"); - PRINTK(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n", + pr_debug("fddi: Discard invalid local SMT frame\n"); + pr_debug(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n", len, la_len, (unsigned long) look_ahead); return (0); } skb = alloc_skb(len + 3, GFP_ATOMIC); if (!skb) { - PRINTK("fddi: Local SMT: skb memory exhausted.\n"); + pr_debug("fddi: Local SMT: skb memory exhausted.\n"); return (0); } skb_reserve(skb, 3); @@ -1981,40 +1975,40 @@ void smt_timer_poll(struct s_smc *smc) ************************/ void ring_status_indication(struct s_smc *smc, u_long status) { - PRINTK("ring_status_indication( "); + pr_debug("ring_status_indication( "); if (status & RS_RES15) - PRINTK("RS_RES15 "); + pr_debug("RS_RES15 "); if (status & RS_HARDERROR) - PRINTK("RS_HARDERROR "); + pr_debug("RS_HARDERROR "); if (status & RS_SOFTERROR) - PRINTK("RS_SOFTERROR "); + pr_debug("RS_SOFTERROR "); if (status & RS_BEACON) - PRINTK("RS_BEACON "); + pr_debug("RS_BEACON "); if (status & RS_PATHTEST) - PRINTK("RS_PATHTEST "); + pr_debug("RS_PATHTEST "); if (status & RS_SELFTEST) - PRINTK("RS_SELFTEST "); + pr_debug("RS_SELFTEST "); if (status & RS_RES9) - PRINTK("RS_RES9 "); + pr_debug("RS_RES9 "); if (status & RS_DISCONNECT) - PRINTK("RS_DISCONNECT "); + pr_debug("RS_DISCONNECT "); if (status & RS_RES7) - PRINTK("RS_RES7 "); + pr_debug("RS_RES7 "); if (status & RS_DUPADDR) - PRINTK("RS_DUPADDR "); + pr_debug("RS_DUPADDR "); if (status & RS_NORINGOP) - PRINTK("RS_NORINGOP "); + pr_debug("RS_NORINGOP "); if (status & RS_VERSION) - PRINTK("RS_VERSION "); + pr_debug("RS_VERSION "); if (status & RS_STUCKBYPASSS) - PRINTK("RS_STUCKBYPASSS "); + pr_debug("RS_STUCKBYPASSS "); if (status & RS_EVENT) - PRINTK("RS_EVENT "); + pr_debug("RS_EVENT "); if (status & RS_RINGOPCHANGE) - PRINTK("RS_RINGOPCHANGE "); + pr_debug("RS_RINGOPCHANGE "); if (status & RS_RES0) - PRINTK("RS_RES0 "); - PRINTK("]\n"); + pr_debug("RS_RES0 "); + pr_debug("]\n"); } // ring_status_indication @@ -2057,17 +2051,17 @@ void smt_stat_counter(struct s_smc *smc, int stat) { // BOOLEAN RingIsUp ; - PRINTK(KERN_INFO "smt_stat_counter\n"); + pr_debug(KERN_INFO "smt_stat_counter\n"); switch (stat) { case 0: - PRINTK(KERN_INFO "Ring operational change.\n"); + pr_debug(KERN_INFO "Ring operational change.\n"); break; case 1: - PRINTK(KERN_INFO "Receive fifo overflow.\n"); + pr_debug(KERN_INFO "Receive fifo overflow.\n"); smc->os.MacStat.gen.rx_errors++; break; default: - PRINTK(KERN_INFO "Unknown status (%d).\n", stat); + pr_debug(KERN_INFO "Unknown status (%d).\n", stat); break; } } // smt_stat_counter @@ -2123,10 +2117,10 @@ void cfm_state_change(struct s_smc *smc, int c_state) s = "SC11_C_WRAP_S"; break; default: - PRINTK(KERN_INFO "cfm_state_change: unknown %d\n", c_state); + pr_debug(KERN_INFO "cfm_state_change: unknown %d\n", c_state); return; } - PRINTK(KERN_INFO "cfm_state_change: %s\n", s); + pr_debug(KERN_INFO "cfm_state_change: %s\n", s); #endif // DRIVERDEBUG } // cfm_state_change @@ -2181,7 +2175,7 @@ void ecm_state_change(struct s_smc *smc, int e_state) s = "unknown"; break; } - PRINTK(KERN_INFO "ecm_state_change: %s\n", s); + pr_debug(KERN_INFO "ecm_state_change: %s\n", s); #endif //DRIVERDEBUG } // ecm_state_change @@ -2236,7 +2230,7 @@ void rmt_state_change(struct s_smc *smc, int r_state) s = "unknown"; break; } - PRINTK(KERN_INFO "[rmt_state_change: %s]\n", s); + pr_debug(KERN_INFO "[rmt_state_change: %s]\n", s); #endif // DRIVERDEBUG } // rmt_state_change @@ -2256,7 +2250,7 @@ void rmt_state_change(struct s_smc *smc, int r_state) ************************/ void drv_reset_indication(struct s_smc *smc) { - PRINTK(KERN_INFO "entering drv_reset_indication\n"); + pr_debug(KERN_INFO "entering drv_reset_indication\n"); smc->os.ResetRequested = TRUE; // Set flag. -- cgit v0.10.2 From 0365e6e4373a5a447746fd7ac26074b92f180311 Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Sun, 17 May 2009 12:32:25 +0000 Subject: ixgbe: Add FCoE Storage MAC Address support This patch implements the Storage Address entrypoint from the net device. It will read the SAN MAC addresses from the EEPROM of the 82599 hardware, and make them available to the FCoE stack through the net device. Also, add/del the SAN MAC address to the netdev dev_addr_list via the kernel api dev_addr_add()/dev_addr_del() when there is a valid SAN MAC supported by the HW. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 23be4db..6bc964f 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -819,6 +819,9 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) /* Store the permanent mac address */ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); + /* Store the permanent SAN mac address */ + hw->mac.ops.get_san_mac_addr(hw, hw->mac.san_addr); + reset_hw_out: return status; } @@ -1294,6 +1297,75 @@ s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) return 0; } +/** + * ixgbe_get_san_mac_addr_offset_82599 - SAN MAC address offset for 82599 + * @hw: pointer to hardware structure + * @san_mac_offset: SAN MAC address offset + * + * This function will read the EEPROM location for the SAN MAC address + * pointer, and returns the value at that location. This is used in both + * get and set mac_addr routines. + **/ +s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, + u16 *san_mac_offset) +{ + /* + * First read the EEPROM pointer to see if the MAC addresses are + * available. + */ + hw->eeprom.ops.read(hw, IXGBE_SAN_MAC_ADDR_PTR, san_mac_offset); + + return 0; +} + +/** + * ixgbe_get_san_mac_addr_82599 - SAN MAC address retrieval for 82599 + * @hw: pointer to hardware structure + * @san_mac_addr: SAN MAC address + * + * Reads the SAN MAC address from the EEPROM, if it's available. This is + * per-port, so set_lan_id() must be called before reading the addresses. + * set_lan_id() is called by identify_sfp(), but this cannot be relied + * upon for non-SFP connections, so we must call it here. + **/ +s32 ixgbe_get_san_mac_addr_82599(struct ixgbe_hw *hw, u8 *san_mac_addr) +{ + u16 san_mac_data, san_mac_offset; + u8 i; + + /* + * First read the EEPROM pointer to see if the MAC addresses are + * available. If they're not, no point in calling set_lan_id() here. + */ + ixgbe_get_san_mac_addr_offset_82599(hw, &san_mac_offset); + + if ((san_mac_offset == 0) || (san_mac_offset == 0xFFFF)) { + /* + * No addresses available in this EEPROM. It's not an + * error though, so just wipe the local address and return. + */ + for (i = 0; i < 6; i++) + san_mac_addr[i] = 0xFF; + + goto san_mac_addr_out; + } + + /* make sure we know which port we need to program */ + hw->mac.ops.set_lan_id(hw); + /* apply the port offset to the address offset */ + (hw->bus.func) ? (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT1_OFFSET) : + (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT0_OFFSET); + for (i = 0; i < 3; i++) { + hw->eeprom.ops.read(hw, san_mac_offset, &san_mac_data); + san_mac_addr[i * 2] = (u8)(san_mac_data); + san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8); + san_mac_offset++; + } + +san_mac_addr_out: + return 0; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, @@ -1303,6 +1375,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82599, .enable_rx_dma = &ixgbe_enable_rx_dma_82599, .get_mac_addr = &ixgbe_get_mac_addr_generic, + .get_san_mac_addr = &ixgbe_get_san_mac_addr_82599, .get_device_caps = &ixgbe_get_device_caps_82599, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d69a052..fe0ac8b 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4799,6 +4799,48 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd); } +/** + * ixgbe_add_sanmac_netdev - Add the SAN MAC address to the corresponding + * netdev->dev_addr_list + * @netdev: network interface device structure + * + * Returns non-zero on failure + **/ +static int ixgbe_add_sanmac_netdev(struct net_device *dev) +{ + int err = 0; + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_mac_info *mac = &adapter->hw.mac; + + if (is_valid_ether_addr(mac->san_addr)) { + rtnl_lock(); + err = dev_addr_add(dev, mac->san_addr, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } + return err; +} + +/** + * ixgbe_del_sanmac_netdev - Removes the SAN MAC address to the corresponding + * netdev->dev_addr_list + * @netdev: network interface device structure + * + * Returns non-zero on failure + **/ +static int ixgbe_del_sanmac_netdev(struct net_device *dev) +{ + int err = 0; + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_mac_info *mac = &adapter->hw.mac; + + if (is_valid_ether_addr(mac->san_addr)) { + rtnl_lock(); + err = dev_addr_del(dev, mac->san_addr, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } + return err; +} + #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs @@ -5159,6 +5201,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ixgbe_setup_dca(adapter); } #endif + /* add san mac addr to netdev */ + ixgbe_add_sanmac_netdev(netdev); dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n"); cards_found++; @@ -5229,6 +5273,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) ixgbe_cleanup_fcoe(adapter); #endif /* IXGBE_FCOE */ + + /* remove the added san mac */ + ixgbe_del_sanmac_netdev(netdev); + if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 38f835d..cb73b30 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1439,6 +1439,7 @@ #define IXGBE_PBANUM0_PTR 0x15 #define IXGBE_PBANUM1_PTR 0x16 #define IXGBE_DEVICE_CAPS 0x2C +#define IXGBE_SAN_MAC_ADDR_PTR 0x28 #define IXGBE_PCIE_MSIX_82599_CAPS 0x72 #define IXGBE_PCIE_MSIX_82598_CAPS 0x62 @@ -1482,6 +1483,8 @@ #define IXGBE_EERD_ATTEMPTS 100000 #endif +#define IXGBE_SAN_MAC_ADDR_PORT0_OFFSET 0x0 +#define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 @@ -2189,6 +2192,7 @@ struct ixgbe_mac_operations { enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); u32 (*get_supported_physical_layer)(struct ixgbe_hw *); s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); + s32 (*get_san_mac_addr)(struct ixgbe_hw *, u8 *); s32 (*get_device_caps)(struct ixgbe_hw *, u16 *); s32 (*stop_adapter)(struct ixgbe_hw *); s32 (*get_bus_info)(struct ixgbe_hw *); @@ -2263,6 +2267,7 @@ struct ixgbe_mac_info { enum ixgbe_mac_type type; u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 san_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; s32 mc_filter_type; u32 mcft_size; u32 vft_size; -- cgit v0.10.2 From aca6bee75fe53ae019b9cabff42095dfb6471fde Mon Sep 17 00:00:00 2001 From: "Waskiewicz Jr, Peter P" Date: Sun, 17 May 2009 12:32:48 +0000 Subject: ixgbe: Add SAN MAC address to the RAR, return the address to DCB After acquiring the SAN MAC address from the EEPROM, we need to program it into one of the RARs. Also, DCB will use this MAC address to run DCBX commands, so it doesn't have to play musical MAC addresses when things like bonding enter the picture. So we need to return the MAC address through the netlink interface to userspace. This also moves the init_rx_addrs() call out of start_hw() and into reset_hw(). We shouldn't try to read any of the RAR information before initializing our internal accounting of the RAR table, which was what was happening. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index e051964..55186dc 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -801,6 +801,12 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc); } + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table + */ + hw->mac.ops.init_rx_addrs(hw); + /* Store the permanent mac address */ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 6bc964f..eaecf5e 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -816,12 +816,29 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) } } + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table. Also reset num_rar_entries to 128, + * since we modify this value when programming the SAN MAC address. + */ + hw->mac.num_rar_entries = 128; + hw->mac.ops.init_rx_addrs(hw); + /* Store the permanent mac address */ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); /* Store the permanent SAN mac address */ hw->mac.ops.get_san_mac_addr(hw, hw->mac.san_addr); + /* Add the SAN MAC address to the RAR only if it's a valid address */ + if (ixgbe_validate_mac_addr(hw->mac.san_addr) == 0) { + hw->mac.ops.set_rar(hw, hw->mac.num_rar_entries - 1, + hw->mac.san_addr, 0, IXGBE_RAH_AV); + + /* Reserve the last RAR for the SAN MAC address */ + hw->mac.num_rar_entries--; + } + reset_hw_out: return status; } diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 60638e2..af39275 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -71,12 +71,6 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) /* Identify the PHY */ hw->phy.ops.identify(hw); - /* - * Store MAC address from RAR0, clear receive address registers, and - * clear the multicast table - */ - hw->mac.ops.init_rx_addrs(hw); - /* Clear the VLAN filter table */ hw->mac.ops.clear_vfta(hw); diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 99e0c10..5d5d390 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -155,10 +155,15 @@ static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, u8 *perm_addr) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - int i; + int i, j; for (i = 0; i < netdev->addr_len; i++) perm_addr[i] = adapter->hw.mac.perm_addr[i]; + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + for (j = 0; j < netdev->addr_len; j++, i++) + perm_addr[i] = adapter->hw.mac.san_addr[j]; + } } static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, -- cgit v0.10.2 From ab6b85c1d7a1bf6c2b27fb542a7b2404e45b7e24 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Sun, 17 May 2009 12:33:08 +0000 Subject: fcoe: consolidates netdev related config and cleanup for spma mode Currently fcoe_netdev_config adds netdev pkt handler for fcoe pkts, fcoe_if_create adds netdev pkt handler for fip packets, a secondary MAC address is added by fcoe_netdev_config and then later cleanup for these netdev related config/adds is done only during fcoe_if_destroy and no cleanup done on error during fcoe interface creation after above netdev config calling in fcoe_if_create. So this patch adds single func for above mentioned cleanup the fcoe_netdev_cleanup and then calls this func on either fcoe interface destroy or exiting from fcoe_if_create due to an error after fcoe/fip related above netdev config is done. Moved netdev pkt handler addition code blocks for fip pkts close to similar code block for foce pkt in fcoe_netdev_config, so that added fcoe_netdev_cleanup could be called on error from fcoe_netdev_config to undo these both additions for fcoe/fip pkt handlers. This move required reference to fcoe_fip_recv in fcoe_netdev_config, so moved fip related functions fcoe_fip_recv, fcoe_fip_send and fcoe_update_src_mac above fcoe_netdev_config. This consolidation will enable spma mode support in next patch to easily add or delete spma mode mac address beside fixing current no cleanup issue during error. Signed-off-by: Vasu Dev Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 94e1e31..04f5005 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -136,6 +136,58 @@ static struct scsi_host_template fcoe_shost_template = { }; /** + * fcoe_fip_recv - handle a received FIP frame. + * @skb: the receive skb + * @dev: associated &net_device + * @ptype: the &packet_type structure which was used to register this handler. + * @orig_dev: original receive &net_device, in case @dev is a bond. + * + * Returns: 0 for success + */ +static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev) +{ + struct fcoe_softc *fc; + + fc = container_of(ptype, struct fcoe_softc, fip_packet_type); + fcoe_ctlr_recv(&fc->ctlr, skb); + return 0; +} + +/** + * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame. + * @fip: FCoE controller. + * @skb: FIP Packet. + */ +static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) +{ + skb->dev = fcoe_from_ctlr(fip)->real_dev; + dev_queue_xmit(skb); +} + +/** + * fcoe_update_src_mac() - Update Ethernet MAC filters. + * @fip: FCoE controller. + * @old: Unicast MAC address to delete if the MAC is non-zero. + * @new: Unicast MAC address to add. + * + * Remove any previously-set unicast MAC filter. + * Add secondary FCoE MAC address filter for our OUI. + */ +static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) +{ + struct fcoe_softc *fc; + + fc = fcoe_from_ctlr(fip); + rtnl_lock(); + if (!is_zero_ether_addr(old)) + dev_unicast_delete(fc->real_dev, old, ETH_ALEN); + dev_unicast_add(fc->real_dev, new, ETH_ALEN); + rtnl_unlock(); +} + +/** * fcoe_lport_config() - sets up the fc_lport * @lp: ptr to the fc_lport * @shost: ptr to the parent scsi host @@ -168,6 +220,29 @@ static int fcoe_lport_config(struct fc_lport *lp) } /** + * fcoe_netdev_cleanup() - clean up netdev configurations + * @fc: ptr to the fcoe_softc + */ +void fcoe_netdev_cleanup(struct fcoe_softc *fc) +{ + u8 flogi_maddr[ETH_ALEN]; + + /* Don't listen for Ethernet packets anymore */ + dev_remove_pack(&fc->fcoe_packet_type); + dev_remove_pack(&fc->fip_packet_type); + + /* Delete secondary MAC addresses */ + rtnl_lock(); + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); + dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); + if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) + dev_unicast_delete(fc->real_dev, + fc->ctlr.data_src_addr, ETH_ALEN); + dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + rtnl_unlock(); +} + +/** * fcoe_netdev_config() - Set up netdev for SW FCoE * @lp : ptr to the fc_lport * @netdev : ptr to the associated netdevice struct @@ -267,6 +342,11 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) fc->fcoe_packet_type.dev = fc->real_dev; dev_add_pack(&fc->fcoe_packet_type); + fc->fip_packet_type.func = fcoe_fip_recv; + fc->fip_packet_type.type = htons(ETH_P_FIP); + fc->fip_packet_type.dev = fc->real_dev; + dev_add_pack(&fc->fip_packet_type); + return 0; } @@ -334,7 +414,6 @@ static int fcoe_if_destroy(struct net_device *netdev) { struct fc_lport *lp = NULL; struct fcoe_softc *fc; - u8 flogi_maddr[ETH_ALEN]; BUG_ON(!netdev); @@ -353,9 +432,10 @@ static int fcoe_if_destroy(struct net_device *netdev) /* Remove the instance from fcoe's list */ fcoe_hostlist_remove(lp); - /* Don't listen for Ethernet packets anymore */ - dev_remove_pack(&fc->fcoe_packet_type); - dev_remove_pack(&fc->fip_packet_type); + /* clean up netdev configurations */ + fcoe_netdev_cleanup(fc); + + /* tear-down the FCoE controller */ fcoe_ctlr_destroy(&fc->ctlr); /* Cleanup the fc_lport */ @@ -370,16 +450,6 @@ static int fcoe_if_destroy(struct net_device *netdev) if (lp->emp) fc_exch_mgr_free(lp->emp); - /* Delete secondary MAC addresses */ - rtnl_lock(); - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); - if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) - dev_unicast_delete(fc->real_dev, - fc->ctlr.data_src_addr, ETH_ALEN); - dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); - rtnl_unlock(); - /* Free the per-CPU revieve threads */ fcoe_percpu_clean(lp); @@ -439,58 +509,6 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { }; /** - * fcoe_fip_recv - handle a received FIP frame. - * @skb: the receive skb - * @dev: associated &net_device - * @ptype: the &packet_type structure which was used to register this handler. - * @orig_dev: original receive &net_device, in case @dev is a bond. - * - * Returns: 0 for success - */ -static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, - struct net_device *orig_dev) -{ - struct fcoe_softc *fc; - - fc = container_of(ptype, struct fcoe_softc, fip_packet_type); - fcoe_ctlr_recv(&fc->ctlr, skb); - return 0; -} - -/** - * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame. - * @fip: FCoE controller. - * @skb: FIP Packet. - */ -static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - skb->dev = fcoe_from_ctlr(fip)->real_dev; - dev_queue_xmit(skb); -} - -/** - * fcoe_update_src_mac() - Update Ethernet MAC filters. - * @fip: FCoE controller. - * @old: Unicast MAC address to delete if the MAC is non-zero. - * @new: Unicast MAC address to add. - * - * Remove any previously-set unicast MAC filter. - * Add secondary FCoE MAC address filter for our OUI. - */ -static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) -{ - struct fcoe_softc *fc; - - fc = fcoe_from_ctlr(fip); - rtnl_lock(); - if (!is_zero_ether_addr(old)) - dev_unicast_delete(fc->real_dev, old, ETH_ALEN); - dev_unicast_add(fc->real_dev, new, ETH_ALEN); - rtnl_unlock(); -} - -/** * fcoe_if_create() - this function creates the fcoe interface * @netdev: pointer the associated netdevice * @@ -531,13 +549,6 @@ static int fcoe_if_create(struct net_device *netdev) goto out_host_put; } - /* configure lport network properties */ - rc = fcoe_netdev_config(lp, netdev); - if (rc) { - FC_DBG("Could not configure netdev for lport\n"); - goto out_host_put; - } - /* * Initialize FIP. */ @@ -545,23 +556,25 @@ static int fcoe_if_create(struct net_device *netdev) fc->ctlr.send = fcoe_fip_send; fc->ctlr.update_mac = fcoe_update_src_mac; - fc->fip_packet_type.func = fcoe_fip_recv; - fc->fip_packet_type.type = htons(ETH_P_FIP); - fc->fip_packet_type.dev = fc->real_dev; - dev_add_pack(&fc->fip_packet_type); + /* configure lport network properties */ + rc = fcoe_netdev_config(lp, netdev); + if (rc) { + FC_DBG("Could not configure netdev for the interface\n"); + goto out_netdev_cleanup; + } /* configure lport scsi host properties */ rc = fcoe_shost_config(lp, shost, &netdev->dev); if (rc) { FC_DBG("Could not configure shost for lport\n"); - goto out_host_put; + goto out_netdev_cleanup; } /* lport exch manager allocation */ rc = fcoe_em_config(lp); if (rc) { FC_DBG("Could not configure em for lport\n"); - goto out_host_put; + goto out_netdev_cleanup; } /* Initialize the library */ @@ -587,6 +600,8 @@ static int fcoe_if_create(struct net_device *netdev) out_lp_destroy: fc_exch_mgr_free(lp->emp); /* Free the EM */ +out_netdev_cleanup: + fcoe_netdev_cleanup(fc); out_host_put: scsi_host_put(lp->host); return rc; -- cgit v0.10.2 From 184dd3459bb334d9061b58faed3610d08d6c7ff8 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Sun, 17 May 2009 12:33:28 +0000 Subject: fcoe: adds spma mode support If we can find a type NETDEV_HW_ADDR_T_SAN mac address from the corresponding netdev for a fcoe interface then sets up added the fc->ctlr.spma flag and stores spma mode address in ctl_src_addr. In case the spma flag is set then:- 1. Adds spma mode MAC address in ctl_src_addr as secondary MAC address, the FLOGI for FIP and pre-FIP will go out using this address. 2. Cleans up stored spma MAC address in ctl_src_addr in fcoe_netdev_cleanup. 3. Sets up spma bit in fip_flags for FIP solicitations along with exiting FPMA bit setting. 4. Initialize the FLOGI FIP MAC descriptor to stored spma MAC address in ctl_src_addr. This is used as proposed FCoE MAC address from initiator along with both SPMA and FPMA bit set in FIP solicitation, in response the switch may grant any FPMA or SPMA mode MAC address to initiator. Removes FIP descriptor type checking against ELS type ELS_FLOGI in fcoe_ctlr_encaps to update a FIP MAC descriptor, instead now checks against FIP_DT_FLOGI. I've tested this with available FPMA-only FCoE switch but since data_src_addr is updated using same old code for both FPMA and SPMA modes with FIP or pre-FIP links, so added SPMA mode will work with SPMA-only switch also provided that switch grants a valid MAC address. Signed-off-by: Vasu Dev Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 04f5005..f2d1612 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -238,6 +238,9 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc) if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr, ETH_ALEN); + if (fc->ctlr.spma) + dev_unicast_delete(fc->real_dev, + fc->ctlr.ctl_src_addr, ETH_ALEN); dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); } @@ -257,6 +260,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) u64 wwnn, wwpn; struct fcoe_softc *fc; u8 flogi_maddr[ETH_ALEN]; + struct netdev_hw_addr *ha; /* Setup lport private data to point to fcoe softc */ fc = lport_priv(lp); @@ -313,9 +317,23 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) skb_queue_head_init(&fc->fcoe_pending_queue); fc->fcoe_pending_queue_active = 0; + /* look for SAN MAC address, if multiple SAN MACs exist, only + * use the first one for SPMA */ + rcu_read_lock(); + for_each_dev_addr(netdev, ha) { + if ((ha->type == NETDEV_HW_ADDR_T_SAN) && + (is_valid_ether_addr(fc->ctlr.ctl_src_addr))) { + memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); + fc->ctlr.spma = 1; + break; + } + } + rcu_read_unlock(); + /* setup Source Mac Address */ - memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, - fc->real_dev->addr_len); + if (!fc->ctlr.spma) + memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, + fc->real_dev->addr_len); wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); fc_set_wwnn(lp, wwnn); @@ -331,6 +349,8 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); + if (fc->ctlr.spma) + dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr, ETH_ALEN); rtnl_unlock(); /* diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index f410f4a..444a06b 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -198,6 +198,8 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) sol->fip.fip_subcode = FIP_SC_SOL; sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW); sol->fip.fip_flags = htons(FIP_FL_FPMA); + if (fip->spma) + sol->fip.fip_flags |= htons(FIP_FL_SPMA); sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW; @@ -350,6 +352,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) kal->fip.fip_dl_len = htons((sizeof(kal->mac) + ports * sizeof(*vn)) / FIP_BPW); kal->fip.fip_flags = htons(FIP_FL_FPMA); + if (fip->spma) + kal->fip.fip_flags |= htons(FIP_FL_SPMA); kal->mac.fd_desc.fip_dtype = FIP_DT_MAC; kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW; @@ -413,6 +417,8 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, cap->fip.fip_subcode = FIP_SC_REQ; cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW); cap->fip.fip_flags = htons(FIP_FL_FPMA); + if (fip->spma) + cap->fip.fip_flags |= htons(FIP_FL_SPMA); cap->encaps.fd_desc.fip_dtype = dtype; cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; @@ -421,8 +427,10 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, memset(mac, 0, sizeof(mac)); mac->fd_desc.fip_dtype = FIP_DT_MAC; mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; - if (dtype != ELS_FLOGI) + if (dtype != FIP_DT_FLOGI) memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN); + else if (fip->spma) + memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); skb->protocol = htons(ETH_P_802_3); skb_reset_mac_header(skb); diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 666cc13..b241060 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -73,6 +73,7 @@ enum fip_state { * @link: current link status for libfc. * @last_link: last link state reported to libfc. * @map_dest: use the FC_MAP mode for destination MAC addresses. + * @spma: supports SPMA server-provided MACs mode * @dest_addr: MAC address of the selected FC forwarder. * @ctl_src_addr: the native MAC address of our local port. * @data_src_addr: the assigned MAC address for the local port after FLOGI. @@ -104,6 +105,7 @@ struct fcoe_ctlr { u8 link; u8 last_link; u8 map_dest; + u8 spma; u8 dest_addr[ETH_ALEN]; u8 ctl_src_addr[ETH_ALEN]; u8 data_src_addr[ETH_ALEN]; -- cgit v0.10.2 From 0331a832a88d4bf34baf289b82e2829763230143 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Sun, 17 May 2009 12:33:52 +0000 Subject: ixgbe: Add RING_F_FCOE for FCoE feature in 82599 Add ring feature for FCoE to make use of the FCoE redirection table in 82599. The FCoE redirection table is a receive side scaling feature for Fiber Channel over Ethernet feature in 82599, enabling distributing FCoE packets to different receive queues based on the exchange id. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index db6d3ea..94b0465 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -161,6 +161,9 @@ enum ixgbe_ring_f_enum { RING_F_DCB, RING_F_VMDQ, RING_F_RSS, +#ifdef IXGBE_FCOE + RING_F_FCOE, +#endif /* IXGBE_FCOE */ RING_F_ARRAY_SIZE /* must be last in enum set */ }; @@ -168,6 +171,9 @@ enum ixgbe_ring_f_enum { #define IXGBE_MAX_DCB_INDICES 8 #define IXGBE_MAX_RSS_INDICES 16 #define IXGBE_MAX_VMDQ_INDICES 16 +#ifdef IXGBE_FCOE +#define IXGBE_MAX_FCOE_INDICES 8 +#endif /* IXGBE_FCOE */ struct ixgbe_ring_feature { int indices; int mask; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index fe0ac8b..68edeab 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1756,6 +1756,17 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) else dev_err(&adapter->pdev->dev, "Invalid DCB " "configuration\n"); +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + struct ixgbe_ring_feature *f; + + rx_ring = &adapter->rx_ring[queue0]; + f = &adapter->ring_feature[RING_F_FCOE]; + if ((queue0 == 0) && (index > rx_ring->reg_idx)) + queue0 = f->mask + index - + rx_ring->reg_idx - 1; + } +#endif /* IXGBE_FCOE */ } else { queue0 = index; } @@ -2842,6 +2853,47 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) return ret; } +#ifdef IXGBE_FCOE +/** + * ixgbe_set_fcoe_queues: Allocate queues for Fiber Channel over Ethernet (FCoE) + * @adapter: board private structure to initialize + * + * FCoE RX FCRETA can use up to 8 rx queues for up to 8 different exchanges. + * The ring feature mask is not used as a mask for FCoE, as it can take any 8 + * rx queues out of the max number of rx queues, instead, it is used as the + * index of the first rx queue used by FCoE. + * + **/ +static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) +{ + bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; + + f->indices = min((int)num_online_cpus(), f->indices); + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { +#ifdef CONFIG_IXGBE_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + DPRINTK(PROBE, INFO, "FCOE enabled with DCB \n"); + ixgbe_set_dcb_queues(adapter); + } +#endif + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { + DPRINTK(PROBE, INFO, "FCOE enabled with RSS \n"); + ixgbe_set_rss_queues(adapter); + } + /* adding FCoE rx rings to the end */ + f->mask = adapter->num_rx_queues; + adapter->num_rx_queues += f->indices; + if (adapter->num_tx_queues == 0) + adapter->num_tx_queues = f->indices; + + ret = true; + } + + return ret; +} + +#endif /* IXGBE_FCOE */ /* * ixgbe_set_num_queues: Allocate queues for device, feature dependant * @adapter: board private structure to initialize @@ -2855,6 +2907,11 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) **/ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) { +#ifdef IXGBE_FCOE + if (ixgbe_set_fcoe_queues(adapter)) + goto done; + +#endif /* IXGBE_FCOE */ #ifdef CONFIG_IXGBE_DCB if (ixgbe_set_dcb_queues(adapter)) goto done; @@ -3030,6 +3087,39 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter) } #endif +#ifdef IXGBE_FCOE +/** + * ixgbe_cache_ring_fcoe - Descriptor ring to register mapping for the FCoE + * @adapter: board private structure to initialize + * + * Cache the descriptor ring offsets for FCoE mode to the assigned rings. + * + */ +static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) +{ + int i, fcoe_i = 0; + bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; + + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { +#ifdef CONFIG_IXGBE_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + ixgbe_cache_ring_dcb(adapter); + fcoe_i = adapter->rx_ring[0].reg_idx + 1; + } +#endif /* CONFIG_IXGBE_DCB */ + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { + ixgbe_cache_ring_rss(adapter); + fcoe_i = f->mask; + } + for (i = 0; i < f->indices; i++, fcoe_i++) + adapter->rx_ring[f->mask + i].reg_idx = fcoe_i; + ret = true; + } + return ret; +} + +#endif /* IXGBE_FCOE */ /** * ixgbe_cache_ring_register - Descriptor ring to register mapping * @adapter: board private structure to initialize @@ -3047,6 +3137,11 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) adapter->rx_ring[0].reg_idx = 0; adapter->tx_ring[0].reg_idx = 0; +#ifdef IXGBE_FCOE + if (ixgbe_cache_ring_fcoe(adapter)) + return; + +#endif /* IXGBE_FCOE */ #ifdef CONFIG_IXGBE_DCB if (ixgbe_cache_ring_dcb(adapter)) return; @@ -3420,6 +3515,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->flags |= IXGBE_FLAG_RSC_ENABLED; #ifdef IXGBE_FCOE adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; #endif /* IXGBE_FCOE */ } -- cgit v0.10.2 From 29ebf6f8c8a99bbda053f1fbdff0570cc5d866b3 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Sun, 17 May 2009 12:34:14 +0000 Subject: ixgbe: Enable FCoE redirection table feature in 82599 Enable using FCoE redirection table feature in 82599. The FCoE redirection table has maximum of eight entries, corresponding to maximum of eight receive queues to be used for distributing incoming FCoE packets. This patch sets up the FCoE redirection table when multiple receive queues are available for FCoE. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index a11c620..d5939de 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -482,8 +482,10 @@ int ixgbe_fso(struct ixgbe_adapter *adapter, */ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) { + int i, fcoe_q, fcoe_i; struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_fcoe *fcoe = &adapter->fcoe; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; /* create the pool for ddp if not created yet */ if (!fcoe->pool) { @@ -497,12 +499,30 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) spin_lock_init(&fcoe->lock); } - /* L2 filter for FCoE: default to queue 0 */ + + /* Enable L2 eth type filter for FCoE */ IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); - IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, 0); - IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), - IXGBE_ETQS_QUEUE_EN); + if (adapter->ring_feature[RING_F_FCOE].indices) { + /* Use multiple rx queues for FCoE by redirection table */ + for (i = 0; i < IXGBE_FCRETA_SIZE; i++) { + fcoe_i = f->mask + i % f->indices; + fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; + fcoe_q = adapter->rx_ring[fcoe_i].reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_FCRETA(i), fcoe_q); + } + IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); + } else { + /* Use single rx queue for FCoE */ + fcoe_i = f->mask; + fcoe_q = adapter->rx_ring[fcoe_i].reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, 0); + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), + IXGBE_ETQS_QUEUE_EN | + (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); + } + IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, IXGBE_FCRXCTRL_FCOELLI | IXGBE_FCRXCTRL_FCCRCBO | -- cgit v0.10.2 From 63f39bd17aa700595fa3e34a61c5c07551dd1b7d Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Sun, 17 May 2009 12:34:35 +0000 Subject: ixgbe: Enable jumbo frame for FCoE feature in 82599 Enable jumbo frame when FCoE feature is enabled in 82599. Use 3K as the receive queue buffer size for receive queues used by FCoE to address for max Fiber Channel frame size as 2148 bytes (with max 2112 bytes of payload). Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 94b0465..3f83a12 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -222,6 +222,10 @@ struct ixgbe_q_vector { (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) #define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 +#ifdef IXGBE_FCOE +/* Use 3K as the baby jumbo frame size for FCoE */ +#define IXGBE_FCOE_JUMBO_FRAME_SIZE 3072 +#endif /* IXGBE_FCOE */ #define OTHER_VECTOR 1 #define NON_Q_VECTORS (OTHER_VECTOR) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 68edeab..1b4af3f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1864,6 +1864,10 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) hlreg0 &= ~IXGBE_HLREG0_JUMBOEN; else hlreg0 |= IXGBE_HLREG0_JUMBOEN; +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + hlreg0 |= IXGBE_HLREG0_JUMBOEN; +#endif IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); @@ -1885,6 +1889,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) adapter->rx_ring[i].tail = IXGBE_RDT(j); adapter->rx_ring[i].rx_buf_len = rx_buf_len; +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + struct ixgbe_ring_feature *f; + f = &adapter->ring_feature[RING_F_FCOE]; + if ((rx_buf_len < IXGBE_FCOE_JUMBO_FRAME_SIZE) && + (i >= f->mask) && (i < f->mask + f->indices)) + adapter->rx_ring[i].rx_buf_len = + IXGBE_FCOE_JUMBO_FRAME_SIZE; + } + +#endif /* IXGBE_FCOE */ ixgbe_configure_srrctl(adapter, j); } @@ -2423,6 +2438,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); } +#ifdef IXGBE_FCOE + /* adjust max frame to be able to do baby jumbo for FCoE */ + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE)) + max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE; + +#endif /* IXGBE_FCOE */ mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) { mhadd &= ~IXGBE_MHADD_MFS_MASK; -- cgit v0.10.2 From 70b77628d8d943b27cc0f72002b5884028aee38c Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Sun, 17 May 2009 12:34:55 +0000 Subject: ixgbe: Set Priority Flow Control low water threshhold for DCB This sets the low water threshhold for priority flow control for 82598 and 82599 controllers in DCB mode. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index af39275..530da90 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1589,6 +1589,13 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) u32 mflcn_reg; u32 fccfg_reg; u32 reg; + u32 rx_pba_size; + +#ifdef CONFIG_DCB + if (hw->fc.requested_mode == ixgbe_fc_pfc) + goto out; + +#endif /* CONFIG_DCB */ mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE); @@ -1651,21 +1658,40 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); - /* Set up and enable Rx high/low water mark thresholds, enable XON. */ - if (hw->fc.current_mode & ixgbe_fc_tx_pause) { - if (hw->fc.send_xon) - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), - (hw->fc.low_water | IXGBE_FCRTL_XONE)); - else - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), - hw->fc.low_water); + reg = IXGBE_READ_REG(hw, IXGBE_MTQC); + /* Thresholds are different for link flow control when in DCB mode */ + if (reg & IXGBE_MTQC_RT_ENA) { + rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); - IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), - (hw->fc.high_water | IXGBE_FCRTH_FCEN)); + /* Always disable XON for LFC when in DCB mode */ + reg = (rx_pba_size >> 2) & 0xFFE0; + if (hw->fc.current_mode & ixgbe_fc_tx_pause) + reg |= IXGBE_FCRTH_FCEN; + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), reg); + } else { + /* + * Set up and enable Rx high/low water mark thresholds, + * enable XON. + */ + if (hw->fc.current_mode & ixgbe_fc_tx_pause) { + if (hw->fc.send_xon) { + IXGBE_WRITE_REG(hw, + IXGBE_FCRTL_82599(packetbuf_num), + (hw->fc.low_water | + IXGBE_FCRTL_XONE)); + } else { + IXGBE_WRITE_REG(hw, + IXGBE_FCRTL_82599(packetbuf_num), + hw->fc.low_water); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), + (hw->fc.high_water | IXGBE_FCRTH_FCEN)); + } } /* Configure pause time (2 TCs per register) */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num)); + reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2)); if ((packetbuf_num & 1) == 0) reg = (reg & 0xFFFF0000) | hw->fc.pause_time; else -- cgit v0.10.2 From 264857b8fe8a16fc95f12e898951fc6bd4bdaa7a Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Sun, 17 May 2009 12:35:16 +0000 Subject: ixgbe: Allow link flow control in DCB mode for 82599 adapters 82599 supports using either link flow control or priority flow control when in DCB mode. The dcbnl interface already supports sending down configurations through rtnetlink that can enable LFC when DCB is enabled, so the driver should take advantage of this. 82598 does not support using LFC when DCB is enabled, so explicitly disable it when we're in DCB mode. This means we always run in PFC mode when DCB is enabled. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 3f83a12..d291d1c 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -252,6 +252,7 @@ struct ixgbe_adapter { struct ixgbe_dcb_config dcb_cfg; struct ixgbe_dcb_config temp_dcb_cfg; u8 dcb_set_bitmap; + enum ixgbe_fc_mode last_lfc_mode; /* Interrupt Throttle Rate */ u32 itr_setting; diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 55186dc..afc9fe3 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -363,7 +363,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) } /* Configure pause time (2 TCs per register) */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num)); + reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2)); if ((packetbuf_num & 1) == 0) reg = (reg & 0xFFFF0000) | hw->fc.pause_time; else diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 530da90..0cc3c47 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1661,9 +1661,10 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) reg = IXGBE_READ_REG(hw, IXGBE_MTQC); /* Thresholds are different for link flow control when in DCB mode */ if (reg & IXGBE_MTQC_RT_ENA) { - rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); - /* Always disable XON for LFC when in DCB mode */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), 0); + + rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); reg = (rx_pba_size >> 2) & 0xFFE0; if (hw->fc.current_mode & ixgbe_fc_tx_pause) reg |= IXGBE_FCRTH_FCEN; diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c index 6220627..f302638 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c @@ -294,6 +294,9 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u32 reg, rx_pba_size; u8 i; + if (!dcb_config->pfc_mode_enable) + goto out; + /* Enable Transmit Priority Flow Control */ reg = IXGBE_READ_REG(hw, IXGBE_RMCS); reg &= ~IXGBE_RMCS_TFCE_802_3X; @@ -341,6 +344,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, /* Configure flow control refresh threshold value */ IXGBE_WRITE_REG(hw, IXGBE_FCRTV, 0x3400); +out: return 0; } diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 5d5d390..6cbff96 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -126,7 +126,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) netdev->netdev_ops->ndo_stop(netdev); ixgbe_clear_interrupt_scheme(adapter); - adapter->hw.fc.requested_mode = ixgbe_fc_pfc; + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + adapter->last_lfc_mode = adapter->hw.fc.current_mode; + adapter->hw.fc.requested_mode = ixgbe_fc_none; + } adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; adapter->flags |= IXGBE_FLAG_DCB_ENABLED; ixgbe_init_interrupt_scheme(adapter); @@ -135,11 +138,13 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) } else { /* Turn off DCB */ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - adapter->hw.fc.requested_mode = ixgbe_fc_default; if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); ixgbe_clear_interrupt_scheme(adapter); + adapter->hw.fc.requested_mode = adapter->last_lfc_mode; + adapter->temp_dcb_cfg.pfc_mode_enable = false; + adapter->dcb_cfg.pfc_mode_enable = false; adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; ixgbe_init_interrupt_scheme(adapter); @@ -329,9 +334,24 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) return ret; } + if (adapter->dcb_cfg.pfc_mode_enable) { + if ((adapter->hw.mac.type != ixgbe_mac_82598EB) && + (adapter->hw.fc.current_mode != ixgbe_fc_pfc)) + adapter->last_lfc_mode = adapter->hw.fc.current_mode; + adapter->hw.fc.requested_mode = ixgbe_fc_pfc; + } else { + if (adapter->hw.mac.type != ixgbe_mac_82598EB) + adapter->hw.fc.requested_mode = adapter->last_lfc_mode; + else + adapter->hw.fc.requested_mode = ixgbe_fc_none; + } + if (netif_running(netdev)) ixgbe_up(adapter); + if (adapter->dcb_cfg.pfc_mode_enable) + adapter->hw.fc.current_mode = ixgbe_fc_pfc; + adapter->dcb_set_bitmap = 0x00; clear_bit(__IXGBE_RESETTING, &adapter->state); return ret; @@ -409,11 +429,17 @@ static u8 ixgbe_dcbnl_getpfcstate(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); + return adapter->dcb_cfg.pfc_mode_enable; } static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.pfc_mode_enable = state; + if (adapter->temp_dcb_cfg.pfc_mode_enable != + adapter->dcb_cfg.pfc_mode_enable) + adapter->dcb_set_bitmap |= BIT_PFC; return; } diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 39fb98f..6c73243 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -270,6 +270,13 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; +#ifdef CONFIG_DCB + if (adapter->dcb_cfg.pfc_mode_enable || + ((hw->mac.type == ixgbe_mac_82598EB) && + (adapter->flags & IXGBE_FLAG_DCB_ENABLED))) + return -EINVAL; + +#endif if (pause->autoneg != AUTONEG_ENABLE) hw->fc.disable_fc_autoneg = true; else @@ -286,6 +293,9 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, else return -EINVAL; +#ifdef CONFIG_DCB + adapter->last_lfc_mode = hw->fc.requested_mode; +#endif hw->mac.ops.setup_fc(hw, 0); return 0; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 1b4af3f..b53f265 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3554,6 +3554,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->dcb_cfg.bw_percentage[DCB_TX_CONFIG][0] = 100; adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100; adapter->dcb_cfg.rx_pba_cfg = pba_equal; + adapter->dcb_cfg.pfc_mode_enable = false; adapter->dcb_cfg.round_robin_enable = false; adapter->dcb_set_bitmap = 0x00; ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, @@ -3564,6 +3565,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) /* default flow control settings */ hw->fc.requested_mode = ixgbe_fc_full; hw->fc.current_mode = ixgbe_fc_full; /* init for ethtool output */ +#ifdef CONFIG_DCB + adapter->last_lfc_mode = hw->fc.current_mode; +#endif hw->fc.high_water = IXGBE_DEFAULT_FCRTH; hw->fc.low_water = IXGBE_DEFAULT_FCRTL; hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; @@ -4319,11 +4323,24 @@ static void ixgbe_watchdog_task(struct work_struct *work) if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + if (link_up) { +#ifdef CONFIG_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) + hw->mac.ops.setup_fc(hw, i); + } else { + hw->mac.ops.setup_fc(hw, 0); + } +#else + hw->mac.ops.setup_fc(hw, 0); +#endif + } + 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; + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); } adapter->link_up = link_up; adapter->link_speed = link_speed; -- cgit v0.10.2 From 8756924c1ecc832c1a5603d10f5cd201e299b312 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Sun, 17 May 2009 12:35:36 +0000 Subject: ixgbe: When in DCB mode with PFC enabled, show LFC is disabled Ethtool should report that link flow control is disabled when in priority flow control mode. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 6c73243..35255b8 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -254,6 +254,13 @@ static void ixgbe_get_pauseparam(struct net_device *netdev, else pause->autoneg = 1; +#ifdef CONFIG_DCB + if (hw->fc.current_mode == ixgbe_fc_pfc) { + pause->rx_pause = 0; + pause->tx_pause = 0; + } + +#endif if (hw->fc.current_mode == ixgbe_fc_rx_pause) { pause->rx_pause = 1; } else if (hw->fc.current_mode == ixgbe_fc_tx_pause) { -- cgit v0.10.2 From 62551d3ea05242d97d47f26fb517b2dfdb752310 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Sun, 17 May 2009 12:35:57 +0000 Subject: ixgbe: Don't reset the hardware when switching between LFC and PFC When running in DCB mode, switching between link flow control and priority flow control shouldn't need to reset the hardware. This removes that reset. This also extends the set_all() dcbnl callback to return a value indicating that the HW config changed, however a reset was not required. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 6cbff96..d56890f 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -28,15 +28,22 @@ #include "ixgbe.h" #include +#include "ixgbe_dcb_82598.h" +#include "ixgbe_dcb_82599.h" /* Callbacks for DCB netlink in the kernel */ #define BIT_DCB_MODE 0x01 #define BIT_PFC 0x02 #define BIT_PG_RX 0x04 #define BIT_PG_TX 0x08 -#define BIT_BCN 0x10 +#define BIT_RESETLINK 0x40 #define BIT_LINKSPEED 0x80 +/* Responses for the DCB_C_SET_ALL command */ +#define DCB_HW_CHG_RST 0 /* DCB configuration changed with reset */ +#define DCB_NO_HW_CHG 1 /* DCB configuration did not change */ +#define DCB_HW_CHG 2 /* DCB configuration changed, no reset */ + int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max) { @@ -195,8 +202,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent != adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) || (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) + adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) { adapter->dcb_set_bitmap |= BIT_PG_TX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, @@ -207,8 +216,10 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] != - adapter->dcb_cfg.bw_percentage[0][bwg_id]) + adapter->dcb_cfg.bw_percentage[0][bwg_id]) { adapter->dcb_set_bitmap |= BIT_PG_RX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, @@ -235,8 +246,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent != adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) || (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) + adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) { adapter->dcb_set_bitmap |= BIT_PG_RX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, @@ -247,8 +260,10 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] != - adapter->dcb_cfg.bw_percentage[1][bwg_id]) + adapter->dcb_cfg.bw_percentage[1][bwg_id]) { adapter->dcb_set_bitmap |= BIT_PG_RX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, @@ -317,21 +332,27 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) struct ixgbe_adapter *adapter = netdev_priv(netdev); int ret; - adapter->dcb_set_bitmap &= ~BIT_BCN; /* no set for BCN */ if (!adapter->dcb_set_bitmap) - return 1; + return DCB_NO_HW_CHG; - while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + /* + * Only take down the adapter if the configuration change + * requires a reset. + */ + if (adapter->dcb_set_bitmap & BIT_RESETLINK) { + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); - if (netif_running(netdev)) - ixgbe_down(adapter); + if (netif_running(netdev)) + ixgbe_down(adapter); + } ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, adapter->ring_feature[RING_F_DCB].indices); if (ret) { - clear_bit(__IXGBE_RESETTING, &adapter->state); - return ret; + if (adapter->dcb_set_bitmap & BIT_RESETLINK) + clear_bit(__IXGBE_RESETTING, &adapter->state); + return DCB_NO_HW_CHG; } if (adapter->dcb_cfg.pfc_mode_enable) { @@ -346,14 +367,25 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) adapter->hw.fc.requested_mode = ixgbe_fc_none; } - if (netif_running(netdev)) - ixgbe_up(adapter); - + if (adapter->dcb_set_bitmap & BIT_RESETLINK) { + if (netif_running(netdev)) + ixgbe_up(adapter); + ret = DCB_HW_CHG_RST; + } else if (adapter->dcb_set_bitmap & BIT_PFC) { + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + ixgbe_dcb_config_pfc_82598(&adapter->hw, + &adapter->dcb_cfg); + else if (adapter->hw.mac.type == ixgbe_mac_82599EB) + ixgbe_dcb_config_pfc_82599(&adapter->hw, + &adapter->dcb_cfg); + ret = DCB_HW_CHG; + } if (adapter->dcb_cfg.pfc_mode_enable) adapter->hw.fc.current_mode = ixgbe_fc_pfc; + if (adapter->dcb_set_bitmap & BIT_RESETLINK) + clear_bit(__IXGBE_RESETTING, &adapter->state); adapter->dcb_set_bitmap = 0x00; - clear_bit(__IXGBE_RESETTING, &adapter->state); return ret; } -- cgit v0.10.2 From e76678dd654545c98a5d0bdc66bd41350573c23e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Sun, 17 May 2009 20:57:47 +0000 Subject: ixgbe: set max desc to prevent total RSC packet size of 64K The performance of hardware RSC is greatly reduced if the total for max rsc descriptors multiplied by the buffer size is greater than 65535. To prevent this we need to adjust the max rsc descriptors appropriately. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index d291d1c..05a2405 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -75,6 +75,8 @@ #define IXGBE_RXBUFFER_128 128 /* Used for packet split */ #define IXGBE_RXBUFFER_256 256 /* Used for packet split */ #define IXGBE_RXBUFFER_2048 2048 +#define IXGBE_RXBUFFER_4096 4096 +#define IXGBE_RXBUFFER_8192 8192 #define IXGBE_MAX_RXBUFFER 16384 /* largest size for a single descriptor */ #define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256 diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index b53f265..4ab17ab 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1995,21 +1995,28 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(j)); rscctrl |= IXGBE_RSCCTL_RSCEN; /* - * if packet split is enabled we can only support up - * to max frags + 1 descriptors. + * we must limit the number of descriptors so that the + * total size of max desc * buf_len is not greater + * than 65535 */ - if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) -#if (MAX_SKB_FRAGS < 3) - rscctrl |= IXGBE_RSCCTL_MAXDESC_1; -#elif (MAX_SKB_FRAGS < 7) - rscctrl |= IXGBE_RSCCTL_MAXDESC_4; -#elif (MAX_SKB_FRAGS < 15) + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { +#if (MAX_SKB_FRAGS > 16) + rscctrl |= IXGBE_RSCCTL_MAXDESC_16; +#elif (MAX_SKB_FRAGS > 8) rscctrl |= IXGBE_RSCCTL_MAXDESC_8; +#elif (MAX_SKB_FRAGS > 4) + rscctrl |= IXGBE_RSCCTL_MAXDESC_4; #else - rscctrl |= IXGBE_RSCCTL_MAXDESC_16; + rscctrl |= IXGBE_RSCCTL_MAXDESC_1; #endif - else - rscctrl |= IXGBE_RSCCTL_MAXDESC_16; + } else { + if (rx_buf_len < IXGBE_RXBUFFER_4096) + rscctrl |= IXGBE_RSCCTL_MAXDESC_16; + else if (rx_buf_len < IXGBE_RXBUFFER_8192) + rscctrl |= IXGBE_RSCCTL_MAXDESC_8; + else + rscctrl |= IXGBE_RSCCTL_MAXDESC_4; + } IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(j), rscctrl); } /* Disable RSC for ACK packets */ -- cgit v0.10.2 From 1fcf03e65650ed888543d33b018bec8dcd95c8e2 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Sun, 17 May 2009 20:58:04 +0000 Subject: ixgbe: Add generic XAUI support to 82599 This patch adds the generic XAUI device support for 82599 controllers. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index eaecf5e..39d7b64 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -347,6 +347,7 @@ enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) switch (hw->device_id) { case IXGBE_DEV_ID_82599: case IXGBE_DEV_ID_82599_KX4: + case IXGBE_DEV_ID_82599_XAUI_LOM: /* Default device ID is mezzanine card KX/KX4 */ media_type = ixgbe_media_type_backplane; break; @@ -1199,6 +1200,8 @@ u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_KX4) physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4; + else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_XAUI) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_XAUI; goto out; break; case IXGBE_AUTOC_LMS_10G_SERIAL: diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 4ab17ab..f9f8831 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -90,6 +90,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = { board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4), board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_XAUI_LOM), + board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP), board_82599 }, diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index cb73b30..ba3ed0f 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -49,6 +49,7 @@ #define IXGBE_DEV_ID_82599 0x10D8 #define IXGBE_DEV_ID_82599_KX4 0x10F7 #define IXGBE_DEV_ID_82599_SFP 0x10FB +#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC /* General Registers */ #define IXGBE_CTRL 0x00000 @@ -1954,6 +1955,7 @@ typedef u32 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x0200 #define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x0400 #define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x0800 +#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000 enum ixgbe_eeprom_type { ixgbe_eeprom_uninitialized = 0, -- cgit v0.10.2 From ba98898eb3fc07ee54566fcc3626354a44355acb Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Sun, 17 May 2009 20:58:21 +0000 Subject: ixgbe: Increase the driver version number Marching along, let's bump the version number to indicate things actually have happened to the driver. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f9f8831..d342619 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -48,7 +48,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.16-k2" +#define DRV_VERSION "2.0.24-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; -- cgit v0.10.2 From 7004bf252c53da18f6b55103e0c92f777f846806 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 18 May 2009 00:34:33 +0000 Subject: net: add tx_packets/tx_bytes/tx_dropped counters in struct netdev_queue offsetof(struct net_device, features)=0x44 offsetof(struct net_device, stats.tx_packets)=0x54 offsetof(struct net_device, stats.tx_bytes)=0x5c offsetof(struct net_device, stats.tx_dropped)=0x6c Network drivers that touch dev->stats.tx_packets/stats.tx_bytes in their tx path can slow down SMP operations, since they dirty a cache line that should stay shared (dev->features is needed in rx and tx paths) We could move away stats field in net_device but it wont help that much. (Two cache lines dirtied in tx path, we can do one only) Better solution is to add tx_packets/tx_bytes/tx_dropped in struct netdev_queue because this structure is already touched in tx path and counters updates will then be free (no increase in size) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cd547d0..f8574e7 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -474,6 +474,9 @@ struct netdev_queue { * please use this field instead of dev->trans_start */ unsigned long trans_start; + unsigned long tx_bytes; + unsigned long tx_packets; + unsigned long tx_dropped; } ____cacheline_aligned_in_smp; diff --git a/net/core/dev.c b/net/core/dev.c index 14dd725..6d3630d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4943,13 +4943,30 @@ void netdev_run_todo(void) * the internal statistics structure is used. */ const struct net_device_stats *dev_get_stats(struct net_device *dev) - { +{ const struct net_device_ops *ops = dev->netdev_ops; if (ops->ndo_get_stats) return ops->ndo_get_stats(dev); - else - return &dev->stats; + else { + unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0; + struct net_device_stats *stats = &dev->stats; + unsigned int i; + struct netdev_queue *txq; + + for (i = 0; i < dev->num_tx_queues; i++) { + txq = netdev_get_tx_queue(dev, i); + tx_bytes += txq->tx_bytes; + tx_packets += txq->tx_packets; + tx_dropped += txq->tx_dropped; + } + if (tx_bytes || tx_packets || tx_dropped) { + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + stats->tx_dropped = tx_dropped; + } + return stats; + } } EXPORT_SYMBOL(dev_get_stats); -- cgit v0.10.2 From 450c4ea15ecb89567e6a75b89cbb8a598a7efb75 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 18 May 2009 00:35:38 +0000 Subject: vlan: use struct netdev_queue counters instead of dev->stats We can update netdev_queue tx_bytes/tx_packets/tx_dropped counters instead of dev->stats ones, to reduce number of cache lines dirtied in xmit path. This fixes a performance problem on SMP when many different cpus take vlan tx path. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 25ba41e..8faacee 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -290,7 +290,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats = &dev->stats; + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); /* Handle non-VLAN frames if they are sent to us, for example by DHCP. @@ -309,7 +309,7 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); skb = __vlan_put_tag(skb, vlan_tci); if (!skb) { - stats->tx_dropped++; + txq->tx_dropped++; return NETDEV_TX_OK; } @@ -317,8 +317,8 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_dev_info(dev)->cnt_inc_headroom_on_tx++; } - stats->tx_packets++; - stats->tx_bytes += skb->len; + txq->tx_packets++; + txq->tx_bytes += skb->len; skb->dev = vlan_dev_info(dev)->real_dev; dev_queue_xmit(skb); @@ -328,15 +328,15 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats = &dev->stats; + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); u16 vlan_tci; vlan_tci = vlan_dev_info(dev)->vlan_id; vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); skb = __vlan_hwaccel_put_tag(skb, vlan_tci); - stats->tx_packets++; - stats->tx_bytes += skb->len; + txq->tx_packets++; + txq->tx_bytes += skb->len; skb->dev = vlan_dev_info(dev)->real_dev; dev_queue_xmit(skb); diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 3628e0a..b55a091 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -279,13 +279,14 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset) { struct net_device *vlandev = (struct net_device *) seq->private; const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); - struct net_device_stats *stats = &vlandev->stats; + const struct net_device_stats *stats; static const char fmt[] = "%30s %12lu\n"; int i; if (!is_vlan_dev(vlandev)) return 0; + stats = dev_get_stats(vlandev); seq_printf(seq, "%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n", vlandev->name, dev_info->vlan_id, -- cgit v0.10.2 From e204a345a0b11c6522ec06e62dee71628a492408 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Mon, 18 May 2009 01:19:12 +0000 Subject: ipv4: cleanup - remove two unused parameters from fib_semantic_match(). Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index ded8c44..ecd3945 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -263,7 +263,6 @@ fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result err = fib_semantic_match(&f->fn_alias, flp, res, - f->fn_key, fz->fz_mask, fz->fz_order); if (err <= 0) goto out; diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index 2c1623d..637b133 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h @@ -22,8 +22,7 @@ struct fib_alias { /* Exported by fib_semantics.c */ extern int fib_semantic_match(struct list_head *head, const struct flowi *flp, - struct fib_result *res, __be32 zone, __be32 mask, - int prefixlen); + struct fib_result *res, int prefixlen); extern void fib_release_info(struct fib_info *); extern struct fib_info *fib_create_info(struct fib_config *cfg); extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index f831df5..9b096d6 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -866,8 +866,7 @@ failure: /* Note! fib_semantic_match intentionally uses RCU list functions. */ int fib_semantic_match(struct list_head *head, const struct flowi *flp, - struct fib_result *res, __be32 zone, __be32 mask, - int prefixlen) + struct fib_result *res, int prefixlen) { struct fib_alias *fa; int nh_sel = 0; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index ec0ae49..9070d11 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1347,8 +1347,7 @@ static int check_leaf(struct trie *t, struct leaf *l, if (l->key != (key & ntohl(mask))) continue; - err = fib_semantic_match(&li->falh, flp, res, - htonl(l->key), mask, plen); + err = fib_semantic_match(&li->falh, flp, res, plen); #ifdef CONFIG_IP_FIB_TRIE_STATS if (err <= 0) -- cgit v0.10.2 From d23a9b5baa1a37ac3620e1ba080965c505053749 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Mon, 18 May 2009 01:47:52 +0000 Subject: ipv4: cleanup: remove unnecessary include. There is no need for net/icmp.h header in net/ipv4/fib_frontend.c. This patch removes the #include net/icmp.h from it. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index cafcc49..e2f9505 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From a6286ee630f6d95f8466e19d7f1ae38d677028ae Mon Sep 17 00:00:00 2001 From: Anant Gole Date: Mon, 18 May 2009 15:19:01 -0700 Subject: net: Add TI DaVinci EMAC driver Add support for TI DaVinci EMAC driver. TI DaVinci Ethernet Media Access Controller module is based upon TI CPPI 3.0 DMA engine and supports 10/100 Mbps on all and Gigabit modes on some TI devices. It supports MII/RMII and has up to 8Kbytes of internal descriptor memory. This driver has been working on several TI devices including DM644x, DM646x and DA830 platforms. The specs of this device are available at: http://www.ti.com/litv/pdf/sprue24a Signed-off-by: Anant Gole Signed-off-by: Kevin Hilman Signed-off-by: Chaithrika U S Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 48b73b0..0fb446e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -926,6 +926,16 @@ config NET_NETX To compile this driver as a module, choose M here. The module will be called netx-eth. +config TI_DAVINCI_EMAC + tristate "TI DaVinci EMAC Support" + depends on ARM && ARCH_DAVINCI + select PHYLIB + help + This driver supports TI's DaVinci Ethernet . + + To compile this driver as a module, choose M here: the module + will be called davinci_emac_driver. This is recommended. + config DM9000 tristate "DM9000 support" depends on ARM || BLACKFIN || MIPS diff --git a/drivers/net/Makefile b/drivers/net/Makefile index dcd5f15..f07a1e9 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -2,6 +2,8 @@ # Makefile for the Linux network (ethercard) device drivers. # +obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o + obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c new file mode 100644 index 0000000..cf689a0 --- /dev/null +++ b/drivers/net/davinci_emac.c @@ -0,0 +1,2832 @@ +/* + * DaVinci Ethernet Medium Access Controller + * + * DaVinci EMAC is based upon CPPI 3.0 TI DMA engine + * + * Copyright (C) 2009 Texas Instruments. + * + * --------------------------------------------------------------------------- + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * --------------------------------------------------------------------------- + * History: + * 0-5 A number of folks worked on this driver in bits and pieces but the major + * contribution came from Suraj Iyer and Anant Gole + * 6.0 Anant Gole - rewrote the driver as per Linux conventions + * 6.1 Chaithrika U S - added support for Gigabit and RMII features, + * PHY layer usage + */ + +/** Pending Items in this driver: + * 1. Use Linux cache infrastcture for DMA'ed memory (dma_xxx functions) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static int debug_level; +module_param(debug_level, int, 0); +MODULE_PARM_DESC(debug_level, "DaVinci EMAC debug level (NETIF_MSG bits)"); + +/* Netif debug messages possible */ +#define DAVINCI_EMAC_DEBUG (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) + +/* version info */ +#define EMAC_MAJOR_VERSION 6 +#define EMAC_MINOR_VERSION 1 +#define EMAC_MODULE_VERSION "6.1" +MODULE_VERSION(EMAC_MODULE_VERSION); +static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; + +/* Configuration items */ +#define EMAC_DEF_PASS_CRC (0) /* Do not pass CRC upto frames */ +#define EMAC_DEF_QOS_EN (0) /* EMAC proprietary QoS disabled */ +#define EMAC_DEF_NO_BUFF_CHAIN (0) /* No buffer chain */ +#define EMAC_DEF_MACCTRL_FRAME_EN (0) /* Discard Maccontrol frames */ +#define EMAC_DEF_SHORT_FRAME_EN (0) /* Discard short frames */ +#define EMAC_DEF_ERROR_FRAME_EN (0) /* Discard error frames */ +#define EMAC_DEF_PROM_EN (0) /* Promiscous disabled */ +#define EMAC_DEF_PROM_CH (0) /* Promiscous channel is 0 */ +#define EMAC_DEF_BCAST_EN (1) /* Broadcast enabled */ +#define EMAC_DEF_BCAST_CH (0) /* Broadcast channel is 0 */ +#define EMAC_DEF_MCAST_EN (1) /* Multicast enabled */ +#define EMAC_DEF_MCAST_CH (0) /* Multicast channel is 0 */ + +#define EMAC_DEF_TXPRIO_FIXED (1) /* TX Priority is fixed */ +#define EMAC_DEF_TXPACING_EN (0) /* TX pacing NOT supported*/ + +#define EMAC_DEF_BUFFER_OFFSET (0) /* Buffer offset to DMA (future) */ +#define EMAC_DEF_MIN_ETHPKTSIZE (60) /* Minimum ethernet pkt size */ +#define EMAC_DEF_MAX_FRAME_SIZE (1500 + 14 + 4 + 4) +#define EMAC_DEF_TX_CH (0) /* Default 0th channel */ +#define EMAC_DEF_RX_CH (0) /* Default 0th channel */ +#define EMAC_DEF_MDIO_TICK_MS (10) /* typically 1 tick=1 ms) */ +#define EMAC_DEF_MAX_TX_CH (1) /* Max TX channels configured */ +#define EMAC_DEF_MAX_RX_CH (1) /* Max RX channels configured */ +#define EMAC_POLL_WEIGHT (64) /* Default NAPI poll weight */ + +/* Buffer descriptor parameters */ +#define EMAC_DEF_TX_MAX_SERVICE (32) /* TX max service BD's */ +#define EMAC_DEF_RX_MAX_SERVICE (64) /* should = netdev->weight */ + +/* EMAC register related defines */ +#define EMAC_ALL_MULTI_REG_VALUE (0xFFFFFFFF) +#define EMAC_NUM_MULTICAST_BITS (64) +#define EMAC_TEARDOWN_VALUE (0xFFFFFFFC) +#define EMAC_TX_CONTROL_TX_ENABLE_VAL (0x1) +#define EMAC_RX_CONTROL_RX_ENABLE_VAL (0x1) +#define EMAC_MAC_HOST_ERR_INTMASK_VAL (0x2) +#define EMAC_RX_UNICAST_CLEAR_ALL (0xFF) +#define EMAC_INT_MASK_CLEAR (0xFF) + +/* RX MBP register bit positions */ +#define EMAC_RXMBP_PASSCRC_MASK BIT(30) +#define EMAC_RXMBP_QOSEN_MASK BIT(29) +#define EMAC_RXMBP_NOCHAIN_MASK BIT(28) +#define EMAC_RXMBP_CMFEN_MASK BIT(24) +#define EMAC_RXMBP_CSFEN_MASK BIT(23) +#define EMAC_RXMBP_CEFEN_MASK BIT(22) +#define EMAC_RXMBP_CAFEN_MASK BIT(21) +#define EMAC_RXMBP_PROMCH_SHIFT (16) +#define EMAC_RXMBP_PROMCH_MASK (0x7 << 16) +#define EMAC_RXMBP_BROADEN_MASK BIT(13) +#define EMAC_RXMBP_BROADCH_SHIFT (8) +#define EMAC_RXMBP_BROADCH_MASK (0x7 << 8) +#define EMAC_RXMBP_MULTIEN_MASK BIT(5) +#define EMAC_RXMBP_MULTICH_SHIFT (0) +#define EMAC_RXMBP_MULTICH_MASK (0x7) +#define EMAC_RXMBP_CHMASK (0x7) + +/* EMAC register definitions/bit maps used */ +# define EMAC_MBP_RXPROMISC (0x00200000) +# define EMAC_MBP_PROMISCCH(ch) (((ch) & 0x7) << 16) +# define EMAC_MBP_RXBCAST (0x00002000) +# define EMAC_MBP_BCASTCHAN(ch) (((ch) & 0x7) << 8) +# define EMAC_MBP_RXMCAST (0x00000020) +# define EMAC_MBP_MCASTCHAN(ch) ((ch) & 0x7) + +/* EMAC mac_control register */ +#define EMAC_MACCONTROL_TXPTYPE (0x200) +#define EMAC_MACCONTROL_TXPACEEN (0x40) +#define EMAC_MACCONTROL_MIIEN (0x20) +#define EMAC_MACCONTROL_GIGABITEN (0x80) +#define EMAC_MACCONTROL_GIGABITEN_SHIFT (7) +#define EMAC_MACCONTROL_FULLDUPLEXEN (0x1) +#define EMAC_MACCONTROL_RMIISPEED_MASK BIT(15) + +/* GIGABIT MODE related bits */ +#define EMAC_DM646X_MACCONTORL_GMIIEN BIT(5) +#define EMAC_DM646X_MACCONTORL_GIG BIT(7) +#define EMAC_DM646X_MACCONTORL_GIGFORCE BIT(17) + +/* EMAC mac_status register */ +#define EMAC_MACSTATUS_TXERRCODE_MASK (0xF00000) +#define EMAC_MACSTATUS_TXERRCODE_SHIFT (20) +#define EMAC_MACSTATUS_TXERRCH_MASK (0x7) +#define EMAC_MACSTATUS_TXERRCH_SHIFT (16) +#define EMAC_MACSTATUS_RXERRCODE_MASK (0xF000) +#define EMAC_MACSTATUS_RXERRCODE_SHIFT (12) +#define EMAC_MACSTATUS_RXERRCH_MASK (0x7) +#define EMAC_MACSTATUS_RXERRCH_SHIFT (8) + +/* EMAC RX register masks */ +#define EMAC_RX_MAX_LEN_MASK (0xFFFF) +#define EMAC_RX_BUFFER_OFFSET_MASK (0xFFFF) + +/* MAC_IN_VECTOR (0x180) register bit fields */ +#define EMAC_DM644X_MAC_IN_VECTOR_HOST_INT (0x20000) +#define EMAC_DM644X_MAC_IN_VECTOR_STATPEND_INT (0x10000) +#define EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC (0x0100) +#define EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC (0x01) + +/** NOTE:: For DM646x the IN_VECTOR has changed */ +#define EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC BIT(EMAC_DEF_RX_CH) +#define EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC BIT(16 + EMAC_DEF_TX_CH) + +/* CPPI bit positions */ +#define EMAC_CPPI_SOP_BIT BIT(31) +#define EMAC_CPPI_EOP_BIT BIT(30) +#define EMAC_CPPI_OWNERSHIP_BIT BIT(29) +#define EMAC_CPPI_EOQ_BIT BIT(28) +#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT BIT(27) +#define EMAC_CPPI_PASS_CRC_BIT BIT(26) +#define EMAC_RX_BD_BUF_SIZE (0xFFFF) +#define EMAC_BD_LENGTH_FOR_CACHE (16) /* only CPPI bytes */ +#define EMAC_RX_BD_PKT_LENGTH_MASK (0xFFFF) + +/* Max hardware defines */ +#define EMAC_MAX_TXRX_CHANNELS (8) /* Max hardware channels */ +#define EMAC_DEF_MAX_MULTICAST_ADDRESSES (64) /* Max mcast addr's */ + +/* EMAC Peripheral Device Register Memory Layout structure */ +#define EMAC_TXIDVER 0x0 +#define EMAC_TXCONTROL 0x4 +#define EMAC_TXTEARDOWN 0x8 +#define EMAC_RXIDVER 0x10 +#define EMAC_RXCONTROL 0x14 +#define EMAC_RXTEARDOWN 0x18 +#define EMAC_TXINTSTATRAW 0x80 +#define EMAC_TXINTSTATMASKED 0x84 +#define EMAC_TXINTMASKSET 0x88 +#define EMAC_TXINTMASKCLEAR 0x8C +#define EMAC_MACINVECTOR 0x90 + +#define EMAC_DM646X_MACEOIVECTOR 0x94 + +#define EMAC_RXINTSTATRAW 0xA0 +#define EMAC_RXINTSTATMASKED 0xA4 +#define EMAC_RXINTMASKSET 0xA8 +#define EMAC_RXINTMASKCLEAR 0xAC +#define EMAC_MACINTSTATRAW 0xB0 +#define EMAC_MACINTSTATMASKED 0xB4 +#define EMAC_MACINTMASKSET 0xB8 +#define EMAC_MACINTMASKCLEAR 0xBC + +#define EMAC_RXMBPENABLE 0x100 +#define EMAC_RXUNICASTSET 0x104 +#define EMAC_RXUNICASTCLEAR 0x108 +#define EMAC_RXMAXLEN 0x10C +#define EMAC_RXBUFFEROFFSET 0x110 +#define EMAC_RXFILTERLOWTHRESH 0x114 + +#define EMAC_MACCONTROL 0x160 +#define EMAC_MACSTATUS 0x164 +#define EMAC_EMCONTROL 0x168 +#define EMAC_FIFOCONTROL 0x16C +#define EMAC_MACCONFIG 0x170 +#define EMAC_SOFTRESET 0x174 +#define EMAC_MACSRCADDRLO 0x1D0 +#define EMAC_MACSRCADDRHI 0x1D4 +#define EMAC_MACHASH1 0x1D8 +#define EMAC_MACHASH2 0x1DC +#define EMAC_MACADDRLO 0x500 +#define EMAC_MACADDRHI 0x504 +#define EMAC_MACINDEX 0x508 + +/* EMAC HDP and Completion registors */ +#define EMAC_TXHDP(ch) (0x600 + (ch * 4)) +#define EMAC_RXHDP(ch) (0x620 + (ch * 4)) +#define EMAC_TXCP(ch) (0x640 + (ch * 4)) +#define EMAC_RXCP(ch) (0x660 + (ch * 4)) + +/* EMAC statistics registers */ +#define EMAC_RXGOODFRAMES 0x200 +#define EMAC_RXBCASTFRAMES 0x204 +#define EMAC_RXMCASTFRAMES 0x208 +#define EMAC_RXPAUSEFRAMES 0x20C +#define EMAC_RXCRCERRORS 0x210 +#define EMAC_RXALIGNCODEERRORS 0x214 +#define EMAC_RXOVERSIZED 0x218 +#define EMAC_RXJABBER 0x21C +#define EMAC_RXUNDERSIZED 0x220 +#define EMAC_RXFRAGMENTS 0x224 +#define EMAC_RXFILTERED 0x228 +#define EMAC_RXQOSFILTERED 0x22C +#define EMAC_RXOCTETS 0x230 +#define EMAC_TXGOODFRAMES 0x234 +#define EMAC_TXBCASTFRAMES 0x238 +#define EMAC_TXMCASTFRAMES 0x23C +#define EMAC_TXPAUSEFRAMES 0x240 +#define EMAC_TXDEFERRED 0x244 +#define EMAC_TXCOLLISION 0x248 +#define EMAC_TXSINGLECOLL 0x24C +#define EMAC_TXMULTICOLL 0x250 +#define EMAC_TXEXCESSIVECOLL 0x254 +#define EMAC_TXLATECOLL 0x258 +#define EMAC_TXUNDERRUN 0x25C +#define EMAC_TXCARRIERSENSE 0x260 +#define EMAC_TXOCTETS 0x264 +#define EMAC_NETOCTETS 0x280 +#define EMAC_RXSOFOVERRUNS 0x284 +#define EMAC_RXMOFOVERRUNS 0x288 +#define EMAC_RXDMAOVERRUNS 0x28C + +/* EMAC DM644x control registers */ +#define EMAC_CTRL_EWCTL (0x4) +#define EMAC_CTRL_EWINTTCNT (0x8) + +/* EMAC MDIO related */ +/* Mask & Control defines */ +#define MDIO_CONTROL_CLKDIV (0xFF) +#define MDIO_CONTROL_ENABLE BIT(30) +#define MDIO_USERACCESS_GO BIT(31) +#define MDIO_USERACCESS_WRITE BIT(30) +#define MDIO_USERACCESS_READ (0) +#define MDIO_USERACCESS_REGADR (0x1F << 21) +#define MDIO_USERACCESS_PHYADR (0x1F << 16) +#define MDIO_USERACCESS_DATA (0xFFFF) +#define MDIO_USERPHYSEL_LINKSEL BIT(7) +#define MDIO_VER_MODID (0xFFFF << 16) +#define MDIO_VER_REVMAJ (0xFF << 8) +#define MDIO_VER_REVMIN (0xFF) + +#define MDIO_USERACCESS(inst) (0x80 + (inst * 8)) +#define MDIO_USERPHYSEL(inst) (0x84 + (inst * 8)) +#define MDIO_CONTROL (0x04) + +/* EMAC DM646X control module registers */ +#define EMAC_DM646X_CMRXINTEN (0x14) +#define EMAC_DM646X_CMTXINTEN (0x18) + +/* EMAC EOI codes for C0 */ +#define EMAC_DM646X_MAC_EOI_C0_RXEN (0x01) +#define EMAC_DM646X_MAC_EOI_C0_TXEN (0x02) + +/** net_buf_obj: EMAC network bufferdata structure + * + * EMAC network buffer data structure + */ +struct emac_netbufobj { + void *buf_token; + char *data_ptr; + int length; +}; + +/** net_pkt_obj: EMAC network packet data structure + * + * EMAC network packet data structure - supports buffer list (for future) + */ +struct emac_netpktobj { + void *pkt_token; /* data token may hold tx/rx chan id */ + struct emac_netbufobj *buf_list; /* array of network buffer objects */ + int num_bufs; + int pkt_length; +}; + +/** emac_tx_bd: EMAC TX Buffer descriptor data structure + * + * EMAC TX Buffer descriptor data structure + */ +struct emac_tx_bd { + int h_next; + int buff_ptr; + int off_b_len; + int mode; /* SOP, EOP, ownership, EOQ, teardown,Qstarv, length */ + struct emac_tx_bd __iomem *next; + void *buf_token; +}; + +/** emac_txch: EMAC TX Channel data structure + * + * EMAC TX Channel data structure + */ +struct emac_txch { + /* Config related */ + u32 num_bd; + u32 service_max; + + /* CPPI specific */ + u32 alloc_size; + void __iomem *bd_mem; + struct emac_tx_bd __iomem *bd_pool_head; + struct emac_tx_bd __iomem *active_queue_head; + struct emac_tx_bd __iomem *active_queue_tail; + struct emac_tx_bd __iomem *last_hw_bdprocessed; + u32 queue_active; + u32 teardown_pending; + u32 *tx_complete; + + /** statistics */ + u32 proc_count; /* TX: # of times emac_tx_bdproc is called */ + u32 mis_queued_packets; + u32 queue_reinit; + u32 end_of_queue_add; + u32 out_of_tx_bd; + u32 no_active_pkts; /* IRQ when there were no packets to process */ + u32 active_queue_count; +}; + +/** emac_rx_bd: EMAC RX Buffer descriptor data structure + * + * EMAC RX Buffer descriptor data structure + */ +struct emac_rx_bd { + int h_next; + int buff_ptr; + int off_b_len; + int mode; + struct emac_rx_bd __iomem *next; + void *data_ptr; + void *buf_token; +}; + +/** emac_rxch: EMAC RX Channel data structure + * + * EMAC RX Channel data structure + */ +struct emac_rxch { + /* configuration info */ + u32 num_bd; + u32 service_max; + u32 buf_size; + char mac_addr[6]; + + /** CPPI specific */ + u32 alloc_size; + void __iomem *bd_mem; + struct emac_rx_bd __iomem *bd_pool_head; + struct emac_rx_bd __iomem *active_queue_head; + struct emac_rx_bd __iomem *active_queue_tail; + u32 queue_active; + u32 teardown_pending; + + /* packet and buffer objects */ + struct emac_netpktobj pkt_queue; + struct emac_netbufobj buf_queue; + + /** statistics */ + u32 proc_count; /* number of times emac_rx_bdproc is called */ + u32 processed_bd; + u32 recycled_bd; + u32 out_of_rx_bd; + u32 out_of_rx_buffers; + u32 queue_reinit; + u32 end_of_queue_add; + u32 end_of_queue; + u32 mis_queued_packets; +}; + +/* emac_priv: EMAC private data structure + * + * EMAC adapter private data structure + */ +struct emac_priv { + u32 msg_enable; + struct net_device *ndev; + struct platform_device *pdev; + struct napi_struct napi; + char mac_addr[6]; + spinlock_t tx_lock; + spinlock_t rx_lock; + void __iomem *remap_addr; + u32 emac_base_phys; + void __iomem *emac_base; + void __iomem *ctrl_base; + void __iomem *emac_ctrl_ram; + u32 ctrl_ram_size; + struct emac_txch *txch[EMAC_DEF_MAX_TX_CH]; + struct emac_rxch *rxch[EMAC_DEF_MAX_RX_CH]; + u32 link; /* 1=link on, 0=link off */ + u32 speed; /* 0=Auto Neg, 1=No PHY, 10,100, 1000 - mbps */ + u32 duplex; /* Link duplex: 0=Half, 1=Full */ + u32 rx_buf_size; + u32 isr_count; + u8 rmii_en; + u8 version; + struct net_device_stats net_dev_stats; + u32 mac_hash1; + u32 mac_hash2; + u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS]; + u32 rx_addr_type; + /* periodic timer required for MDIO polling */ + struct timer_list periodic_timer; + u32 periodic_ticks; + u32 timer_active; + u32 phy_mask; + /* mii_bus,phy members */ + struct mii_bus *mii_bus; + struct phy_device *phydev; + spinlock_t lock; +}; + +/* clock frequency for EMAC */ +static struct clk *emac_clk; +static unsigned long emac_bus_frequency; +static unsigned long mdio_max_freq; + +/* EMAC internal utility function */ +static inline u32 emac_virt_to_phys(void __iomem *addr) +{ + return (u32 __force) io_v2p(addr); +} + +/* Cache macros - Packet buffers would be from skb pool which is cached */ +#define EMAC_VIRT_NOCACHE(addr) (addr) +#define EMAC_CACHE_INVALIDATE(addr, size) \ + dma_cache_maint((void *)addr, size, DMA_FROM_DEVICE) +#define EMAC_CACHE_WRITEBACK(addr, size) \ + dma_cache_maint((void *)addr, size, DMA_TO_DEVICE) +#define EMAC_CACHE_WRITEBACK_INVALIDATE(addr, size) \ + dma_cache_maint((void *)addr, size, DMA_BIDIRECTIONAL) + +/* DM644x does not have BD's in cached memory - so no cache functions */ +#define BD_CACHE_INVALIDATE(addr, size) +#define BD_CACHE_WRITEBACK(addr, size) +#define BD_CACHE_WRITEBACK_INVALIDATE(addr, size) + +/* EMAC TX Host Error description strings */ +static char *emac_txhost_errcodes[16] = { + "No error", "SOP error", "Ownership bit not set in SOP buffer", + "Zero Next Buffer Descriptor Pointer Without EOP", + "Zero Buffer Pointer", "Zero Buffer Length", "Packet Length Error", + "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved" +}; + +/* EMAC RX Host Error description strings */ +static char *emac_rxhost_errcodes[16] = { + "No error", "Reserved", "Ownership bit not set in input buffer", + "Reserved", "Zero Buffer Pointer", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved" +}; + +/* Helper macros */ +#define emac_read(reg) ioread32(priv->emac_base + (reg)) +#define emac_write(reg, val) iowrite32(val, priv->emac_base + (reg)) + +#define emac_ctrl_read(reg) ioread32((priv->ctrl_base + (reg))) +#define emac_ctrl_write(reg, val) iowrite32(val, (priv->ctrl_base + (reg))) + +#define emac_mdio_read(reg) ioread32(bus->priv + (reg)) +#define emac_mdio_write(reg, val) iowrite32(val, (bus->priv + (reg))) + +/** + * emac_dump_regs: Dump important EMAC registers to debug terminal + * @priv: The DaVinci EMAC private adapter structure + * + * Executes ethtool set cmd & sets phy mode + * + */ +static void emac_dump_regs(struct emac_priv *priv) +{ + struct device *emac_dev = &priv->ndev->dev; + + /* Print important registers in EMAC */ + dev_info(emac_dev, "EMAC Basic registers\n"); + dev_info(emac_dev, "EMAC: EWCTL: %08X, EWINTTCNT: %08X\n", + emac_ctrl_read(EMAC_CTRL_EWCTL), + emac_ctrl_read(EMAC_CTRL_EWINTTCNT)); + dev_info(emac_dev, "EMAC: TXID: %08X %s, RXID: %08X %s\n", + emac_read(EMAC_TXIDVER), + ((emac_read(EMAC_TXCONTROL)) ? "enabled" : "disabled"), + emac_read(EMAC_RXIDVER), + ((emac_read(EMAC_RXCONTROL)) ? "enabled" : "disabled")); + dev_info(emac_dev, "EMAC: TXIntRaw:%08X, TxIntMasked: %08X, "\ + "TxIntMasSet: %08X\n", emac_read(EMAC_TXINTSTATRAW), + emac_read(EMAC_TXINTSTATMASKED), emac_read(EMAC_TXINTMASKSET)); + dev_info(emac_dev, "EMAC: RXIntRaw:%08X, RxIntMasked: %08X, "\ + "RxIntMasSet: %08X\n", emac_read(EMAC_RXINTSTATRAW), + emac_read(EMAC_RXINTSTATMASKED), emac_read(EMAC_RXINTMASKSET)); + dev_info(emac_dev, "EMAC: MacIntRaw:%08X, MacIntMasked: %08X, "\ + "MacInVector=%08X\n", emac_read(EMAC_MACINTSTATRAW), + emac_read(EMAC_MACINTSTATMASKED), emac_read(EMAC_MACINVECTOR)); + dev_info(emac_dev, "EMAC: EmuControl:%08X, FifoControl: %08X\n", + emac_read(EMAC_EMCONTROL), emac_read(EMAC_FIFOCONTROL)); + dev_info(emac_dev, "EMAC: MBPEnable:%08X, RXUnicastSet: %08X, "\ + "RXMaxLen=%08X\n", emac_read(EMAC_RXMBPENABLE), + emac_read(EMAC_RXUNICASTSET), emac_read(EMAC_RXMAXLEN)); + dev_info(emac_dev, "EMAC: MacControl:%08X, MacStatus: %08X, "\ + "MacConfig=%08X\n", emac_read(EMAC_MACCONTROL), + emac_read(EMAC_MACSTATUS), emac_read(EMAC_MACCONFIG)); + dev_info(emac_dev, "EMAC: TXHDP[0]:%08X, RXHDP[0]: %08X\n", + emac_read(EMAC_TXHDP(0)), emac_read(EMAC_RXHDP(0))); + dev_info(emac_dev, "EMAC Statistics\n"); + dev_info(emac_dev, "EMAC: rx_good_frames:%d\n", + emac_read(EMAC_RXGOODFRAMES)); + dev_info(emac_dev, "EMAC: rx_broadcast_frames:%d\n", + emac_read(EMAC_RXBCASTFRAMES)); + dev_info(emac_dev, "EMAC: rx_multicast_frames:%d\n", + emac_read(EMAC_RXMCASTFRAMES)); + dev_info(emac_dev, "EMAC: rx_pause_frames:%d\n", + emac_read(EMAC_RXPAUSEFRAMES)); + dev_info(emac_dev, "EMAC: rx_crcerrors:%d\n", + emac_read(EMAC_RXCRCERRORS)); + dev_info(emac_dev, "EMAC: rx_align_code_errors:%d\n", + emac_read(EMAC_RXALIGNCODEERRORS)); + dev_info(emac_dev, "EMAC: rx_oversized_frames:%d\n", + emac_read(EMAC_RXOVERSIZED)); + dev_info(emac_dev, "EMAC: rx_jabber_frames:%d\n", + emac_read(EMAC_RXJABBER)); + dev_info(emac_dev, "EMAC: rx_undersized_frames:%d\n", + emac_read(EMAC_RXUNDERSIZED)); + dev_info(emac_dev, "EMAC: rx_fragments:%d\n", + emac_read(EMAC_RXFRAGMENTS)); + dev_info(emac_dev, "EMAC: rx_filtered_frames:%d\n", + emac_read(EMAC_RXFILTERED)); + dev_info(emac_dev, "EMAC: rx_qos_filtered_frames:%d\n", + emac_read(EMAC_RXQOSFILTERED)); + dev_info(emac_dev, "EMAC: rx_octets:%d\n", + emac_read(EMAC_RXOCTETS)); + dev_info(emac_dev, "EMAC: tx_goodframes:%d\n", + emac_read(EMAC_TXGOODFRAMES)); + dev_info(emac_dev, "EMAC: tx_bcastframes:%d\n", + emac_read(EMAC_TXBCASTFRAMES)); + dev_info(emac_dev, "EMAC: tx_mcastframes:%d\n", + emac_read(EMAC_TXMCASTFRAMES)); + dev_info(emac_dev, "EMAC: tx_pause_frames:%d\n", + emac_read(EMAC_TXPAUSEFRAMES)); + dev_info(emac_dev, "EMAC: tx_deferred_frames:%d\n", + emac_read(EMAC_TXDEFERRED)); + dev_info(emac_dev, "EMAC: tx_collision_frames:%d\n", + emac_read(EMAC_TXCOLLISION)); + dev_info(emac_dev, "EMAC: tx_single_coll_frames:%d\n", + emac_read(EMAC_TXSINGLECOLL)); + dev_info(emac_dev, "EMAC: tx_mult_coll_frames:%d\n", + emac_read(EMAC_TXMULTICOLL)); + dev_info(emac_dev, "EMAC: tx_excessive_collisions:%d\n", + emac_read(EMAC_TXEXCESSIVECOLL)); + dev_info(emac_dev, "EMAC: tx_late_collisions:%d\n", + emac_read(EMAC_TXLATECOLL)); + dev_info(emac_dev, "EMAC: tx_underrun:%d\n", + emac_read(EMAC_TXUNDERRUN)); + dev_info(emac_dev, "EMAC: tx_carrier_sense_errors:%d\n", + emac_read(EMAC_TXCARRIERSENSE)); + dev_info(emac_dev, "EMAC: tx_octets:%d\n", + emac_read(EMAC_TXOCTETS)); + dev_info(emac_dev, "EMAC: net_octets:%d\n", + emac_read(EMAC_NETOCTETS)); + dev_info(emac_dev, "EMAC: rx_sof_overruns:%d\n", + emac_read(EMAC_RXSOFOVERRUNS)); + dev_info(emac_dev, "EMAC: rx_mof_overruns:%d\n", + emac_read(EMAC_RXMOFOVERRUNS)); + dev_info(emac_dev, "EMAC: rx_dma_overruns:%d\n", + emac_read(EMAC_RXDMAOVERRUNS)); +} + +/************************************************************************* + * EMAC MDIO/Phy Functionality + *************************************************************************/ +/** + * emac_get_drvinfo: Get EMAC driver information + * @ndev: The DaVinci EMAC network adapter + * @info: ethtool info structure containing name and version + * + * Returns EMAC driver information (name and version) + * + */ +static void emac_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, emac_version_string); + strcpy(info->version, EMAC_MODULE_VERSION); +} + +/** + * emac_get_settings: Get EMAC settings + * @ndev: The DaVinci EMAC network adapter + * @ecmd: ethtool command + * + * Executes ethool get command + * + */ +static int emac_get_settings(struct net_device *ndev, + struct ethtool_cmd *ecmd) +{ + struct emac_priv *priv = netdev_priv(ndev); + if (priv->phy_mask) + return phy_ethtool_gset(priv->phydev, ecmd); + else + return -EOPNOTSUPP; + +} + +/** + * emac_set_settings: Set EMAC settings + * @ndev: The DaVinci EMAC network adapter + * @ecmd: ethtool command + * + * Executes ethool set command + * + */ +static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ + struct emac_priv *priv = netdev_priv(ndev); + if (priv->phy_mask) + return phy_ethtool_sset(priv->phydev, ecmd); + else + return -EOPNOTSUPP; + +} + +/** + * ethtool_ops: DaVinci EMAC Ethtool structure + * + * Ethtool support for EMAC adapter + * + */ +static const struct ethtool_ops ethtool_ops = { + .get_drvinfo = emac_get_drvinfo, + .get_settings = emac_get_settings, + .set_settings = emac_set_settings, + .get_link = ethtool_op_get_link, +}; + +/** + * emac_update_phystatus: Update Phy status + * @priv: The DaVinci EMAC private adapter structure + * + * Updates phy status and takes action for network queue if required + * based upon link status + * + */ +static void emac_update_phystatus(struct emac_priv *priv) +{ + u32 mac_control; + u32 new_duplex; + u32 cur_duplex; + struct net_device *ndev = priv->ndev; + + mac_control = emac_read(EMAC_MACCONTROL); + cur_duplex = (mac_control & EMAC_MACCONTROL_FULLDUPLEXEN) ? + DUPLEX_FULL : DUPLEX_HALF; + if (priv->phy_mask) + new_duplex = priv->phydev->duplex; + else + new_duplex = DUPLEX_FULL; + + /* We get called only if link has changed (speed/duplex/status) */ + if ((priv->link) && (new_duplex != cur_duplex)) { + priv->duplex = new_duplex; + if (DUPLEX_FULL == priv->duplex) + mac_control |= (EMAC_MACCONTROL_FULLDUPLEXEN); + else + mac_control &= ~(EMAC_MACCONTROL_FULLDUPLEXEN); + } + + if (priv->speed == SPEED_1000 && (priv->version == EMAC_VERSION_2)) { + mac_control = emac_read(EMAC_MACCONTROL); + mac_control |= (EMAC_DM646X_MACCONTORL_GMIIEN | + EMAC_DM646X_MACCONTORL_GIG | + EMAC_DM646X_MACCONTORL_GIGFORCE); + } else { + /* Clear the GIG bit and GIGFORCE bit */ + mac_control &= ~(EMAC_DM646X_MACCONTORL_GIGFORCE | + EMAC_DM646X_MACCONTORL_GIG); + + if (priv->rmii_en && (priv->speed == SPEED_100)) + mac_control |= EMAC_MACCONTROL_RMIISPEED_MASK; + else + mac_control &= ~EMAC_MACCONTROL_RMIISPEED_MASK; + } + + /* Update mac_control if changed */ + emac_write(EMAC_MACCONTROL, mac_control); + + if (priv->link) { + /* link ON */ + if (!netif_carrier_ok(ndev)) + netif_carrier_on(ndev); + /* reactivate the transmit queue if it is stopped */ + if (netif_running(ndev) && netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } else { + /* link OFF */ + if (netif_carrier_ok(ndev)) + netif_carrier_off(ndev); + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + } +} + +/** + * hash_get: Calculate hash value from mac address + * @addr: mac address to delete from hash table + * + * Calculates hash value from mac address + * + */ +static u32 hash_get(u8 *addr) +{ + u32 hash; + u8 tmpval; + int cnt; + hash = 0; + + for (cnt = 0; cnt < 2; cnt++) { + tmpval = *addr++; + hash ^= (tmpval >> 2) ^ (tmpval << 4); + tmpval = *addr++; + hash ^= (tmpval >> 4) ^ (tmpval << 2); + tmpval = *addr++; + hash ^= (tmpval >> 6) ^ (tmpval); + } + + return hash & 0x3F; +} + +/** + * hash_add: Hash function to add mac addr from hash table + * @priv: The DaVinci EMAC private adapter structure + * mac_addr: mac address to delete from hash table + * + * Adds mac address to the internal hash table + * + */ +static int hash_add(struct emac_priv *priv, u8 *mac_addr) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 rc = 0; + u32 hash_bit; + u32 hash_value = hash_get(mac_addr); + + if (hash_value >= EMAC_NUM_MULTICAST_BITS) { + if (netif_msg_drv(priv)) { + dev_err(emac_dev, "DaVinci EMAC: hash_add(): Invalid "\ + "Hash %08x, should not be greater than %08x", + hash_value, (EMAC_NUM_MULTICAST_BITS - 1)); + } + return -1; + } + + /* set the hash bit only if not previously set */ + if (priv->multicast_hash_cnt[hash_value] == 0) { + rc = 1; /* hash value changed */ + if (hash_value < 32) { + hash_bit = BIT(hash_value); + priv->mac_hash1 |= hash_bit; + } else { + hash_bit = BIT((hash_value - 32)); + priv->mac_hash2 |= hash_bit; + } + } + + /* incr counter for num of mcast addr's mapped to "this" hash bit */ + ++priv->multicast_hash_cnt[hash_value]; + + return rc; +} + +/** + * hash_del: Hash function to delete mac addr from hash table + * @priv: The DaVinci EMAC private adapter structure + * mac_addr: mac address to delete from hash table + * + * Removes mac address from the internal hash table + * + */ +static int hash_del(struct emac_priv *priv, u8 *mac_addr) +{ + u32 hash_value; + u32 hash_bit; + + hash_value = hash_get(mac_addr); + if (priv->multicast_hash_cnt[hash_value] > 0) { + /* dec cntr for num of mcast addr's mapped to this hash bit */ + --priv->multicast_hash_cnt[hash_value]; + } + + /* if counter still > 0, at least one multicast address refers + * to this hash bit. so return 0 */ + if (priv->multicast_hash_cnt[hash_value] > 0) + return 0; + + if (hash_value < 32) { + hash_bit = BIT(hash_value); + priv->mac_hash1 &= ~hash_bit; + } else { + hash_bit = BIT((hash_value - 32)); + priv->mac_hash2 &= ~hash_bit; + } + + /* return 1 to indicate change in mac_hash registers reqd */ + return 1; +} + +/* EMAC multicast operation */ +#define EMAC_MULTICAST_ADD 0 +#define EMAC_MULTICAST_DEL 1 +#define EMAC_ALL_MULTI_SET 2 +#define EMAC_ALL_MULTI_CLR 3 + +/** + * emac_add_mcast: Set multicast address in the EMAC adapter (Internal) + * @priv: The DaVinci EMAC private adapter structure + * @action: multicast operation to perform + * mac_addr: mac address to set + * + * Set multicast addresses in EMAC adapter - internal function + * + */ +static void emac_add_mcast(struct emac_priv *priv, u32 action, u8 *mac_addr) +{ + struct device *emac_dev = &priv->ndev->dev; + int update = -1; + + switch (action) { + case EMAC_MULTICAST_ADD: + update = hash_add(priv, mac_addr); + break; + case EMAC_MULTICAST_DEL: + update = hash_del(priv, mac_addr); + break; + case EMAC_ALL_MULTI_SET: + update = 1; + priv->mac_hash1 = EMAC_ALL_MULTI_REG_VALUE; + priv->mac_hash2 = EMAC_ALL_MULTI_REG_VALUE; + break; + case EMAC_ALL_MULTI_CLR: + update = 1; + priv->mac_hash1 = 0; + priv->mac_hash2 = 0; + memset(&(priv->multicast_hash_cnt[0]), 0, + sizeof(priv->multicast_hash_cnt[0]) * + EMAC_NUM_MULTICAST_BITS); + break; + default: + if (netif_msg_drv(priv)) + dev_err(emac_dev, "DaVinci EMAC: add_mcast"\ + ": bad operation %d", action); + break; + } + + /* write to the hardware only if the register status chances */ + if (update > 0) { + emac_write(EMAC_MACHASH1, priv->mac_hash1); + emac_write(EMAC_MACHASH2, priv->mac_hash2); + } +} + +/** + * emac_dev_mcast_set: Set multicast address in the EMAC adapter + * @ndev: The DaVinci EMAC network adapter + * + * Set multicast addresses in EMAC adapter + * + */ +static void emac_dev_mcast_set(struct net_device *ndev) +{ + u32 mbp_enable; + struct emac_priv *priv = netdev_priv(ndev); + + mbp_enable = emac_read(EMAC_RXMBPENABLE); + if (ndev->flags & IFF_PROMISC) { + mbp_enable &= (~EMAC_MBP_PROMISCCH(EMAC_DEF_PROM_CH)); + mbp_enable |= (EMAC_MBP_RXPROMISC); + } else { + mbp_enable = (mbp_enable & ~EMAC_MBP_RXPROMISC); + if ((ndev->flags & IFF_ALLMULTI) || + (ndev->mc_count > EMAC_DEF_MAX_MULTICAST_ADDRESSES)) { + mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); + emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL); + } + if (ndev->mc_count > 0) { + struct dev_mc_list *mc_ptr; + mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); + emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL); + /* program multicast address list into EMAC hardware */ + for (mc_ptr = ndev->mc_list; mc_ptr; + mc_ptr = mc_ptr->next) { + emac_add_mcast(priv, EMAC_MULTICAST_ADD, + (u8 *)mc_ptr->dmi_addr); + } + } else { + mbp_enable = (mbp_enable & ~EMAC_MBP_RXMCAST); + emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL); + } + } + /* Set mbp config register */ + emac_write(EMAC_RXMBPENABLE, mbp_enable); +} + +/************************************************************************* + * EMAC Hardware manipulation + *************************************************************************/ + +/** + * emac_int_disable: Disable EMAC module interrupt (from adapter) + * @priv: The DaVinci EMAC private adapter structure + * + * Disable EMAC interrupt on the adapter + * + */ +static void emac_int_disable(struct emac_priv *priv) +{ + if (priv->version == EMAC_VERSION_2) { + unsigned long flags; + + local_irq_save(flags); + + /* Program C0_Int_En to zero to turn off + * interrupts to the CPU */ + emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0x0); + emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0x0); + /* NOTE: Rx Threshold and Misc interrupts are not disabled */ + + local_irq_restore(flags); + + } else { + /* Set DM644x control registers for interrupt control */ + emac_ctrl_write(EMAC_CTRL_EWCTL, 0x0); + } +} + +/** + * emac_int_enable: Enable EMAC module interrupt (from adapter) + * @priv: The DaVinci EMAC private adapter structure + * + * Enable EMAC interrupt on the adapter + * + */ +static void emac_int_enable(struct emac_priv *priv) +{ + if (priv->version == EMAC_VERSION_2) { + emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0xff); + emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0xff); + + /* In addition to turning on interrupt Enable, we need + * ack by writing appropriate values to the EOI + * register */ + + /* NOTE: Rx Threshold and Misc interrupts are not enabled */ + + /* ack rxen only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_RXEN); + + /* ack txen- only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_TXEN); + + } else { + /* Set DM644x control registers for interrupt control */ + emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1); + } +} + +/** + * emac_irq: EMAC interrupt handler + * @irq: interrupt number + * @dev_id: EMAC network adapter data structure ptr + * + * EMAC Interrupt handler - we only schedule NAPI and not process any packets + * here. EVen the interrupt status is checked (TX/RX/Err) in NAPI poll function + * + * Returns interrupt handled condition + */ +static irqreturn_t emac_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct emac_priv *priv = netdev_priv(ndev); + + ++priv->isr_count; + if (likely(netif_running(priv->ndev))) { + emac_int_disable(priv); + napi_schedule(&priv->napi); + } else { + /* we are closing down, so dont process anything */ + } + return IRQ_HANDLED; +} + +/** EMAC on-chip buffer descriptor memory + * + * WARNING: Please note that the on chip memory is used for both TX and RX + * buffer descriptor queues and is equally divided between TX and RX desc's + * If the number of TX or RX descriptors change this memory pointers need + * to be adjusted. If external memory is allocated then these pointers can + * pointer to the memory + * + */ +#define EMAC_TX_BD_MEM(priv) ((priv)->emac_ctrl_ram) +#define EMAC_RX_BD_MEM(priv) ((priv)->emac_ctrl_ram + \ + (((priv)->ctrl_ram_size) >> 1)) + +/** + * emac_init_txch: TX channel initialization + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device init to setup a TX channel (allocate buffer desc + * create free pool and keep ready for transmission + * + * Returns success(0) or mem alloc failures error code + */ +static int emac_init_txch(struct emac_priv *priv, u32 ch) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 cnt, bd_size; + void __iomem *mem; + struct emac_tx_bd __iomem *curr_bd; + struct emac_txch *txch = NULL; + + txch = kzalloc(sizeof(struct emac_txch), GFP_KERNEL); + if (NULL == txch) { + dev_err(emac_dev, "DaVinci EMAC: TX Ch mem alloc failed"); + return -ENOMEM; + } + priv->txch[ch] = txch; + txch->service_max = EMAC_DEF_TX_MAX_SERVICE; + txch->active_queue_head = NULL; + txch->active_queue_tail = NULL; + txch->queue_active = 0; + txch->teardown_pending = 0; + + /* allocate memory for TX CPPI channel on a 4 byte boundry */ + txch->tx_complete = kzalloc(txch->service_max * sizeof(u32), + GFP_KERNEL); + if (NULL == txch->tx_complete) { + dev_err(emac_dev, "DaVinci EMAC: Tx service mem alloc failed"); + kfree(txch); + return -ENOMEM; + } + + /* allocate buffer descriptor pool align every BD on four word + * boundry for future requirements */ + bd_size = (sizeof(struct emac_tx_bd) + 0xF) & ~0xF; + txch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size; + txch->alloc_size = (((bd_size * txch->num_bd) + 0xF) & ~0xF); + + /* alloc TX BD memory */ + txch->bd_mem = EMAC_TX_BD_MEM(priv); + __memzero((void __force *)txch->bd_mem, txch->alloc_size); + + /* initialize the BD linked list */ + mem = (void __force __iomem *) + (((u32 __force) txch->bd_mem + 0xF) & ~0xF); + txch->bd_pool_head = NULL; + for (cnt = 0; cnt < txch->num_bd; cnt++) { + curr_bd = mem + (cnt * bd_size); + curr_bd->next = txch->bd_pool_head; + txch->bd_pool_head = curr_bd; + } + + /* reset statistics counters */ + txch->out_of_tx_bd = 0; + txch->no_active_pkts = 0; + txch->active_queue_count = 0; + + return 0; +} + +/** + * emac_cleanup_txch: Book-keep function to clean TX channel resources + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number + * + * Called to clean up TX channel resources + * + */ +static void emac_cleanup_txch(struct emac_priv *priv, u32 ch) +{ + struct emac_txch *txch = priv->txch[ch]; + + if (txch) { + if (txch->bd_mem) + txch->bd_mem = NULL; + kfree(txch->tx_complete); + kfree(txch); + priv->txch[ch] = NULL; + } +} + +/** + * emac_net_tx_complete: TX packet completion function + * @priv: The DaVinci EMAC private adapter structure + * @net_data_tokens: packet token - skb pointer + * @num_tokens: number of skb's to free + * @ch: TX channel number + * + * Frees the skb once packet is transmitted + * + */ +static int emac_net_tx_complete(struct emac_priv *priv, + void **net_data_tokens, + int num_tokens, u32 ch) +{ + u32 cnt; + + if (unlikely(num_tokens && netif_queue_stopped(priv->ndev))) + netif_start_queue(priv->ndev); + for (cnt = 0; cnt < num_tokens; cnt++) { + struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt]; + if (skb == NULL) + continue; + priv->net_dev_stats.tx_packets++; + priv->net_dev_stats.tx_bytes += skb->len; + dev_kfree_skb_any(skb); + } + return 0; +} + +/** + * emac_txch_teardown: TX channel teardown + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number + * + * Called to teardown TX channel + * + */ +static void emac_txch_teardown(struct emac_priv *priv, u32 ch) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */ + struct emac_txch *txch = priv->txch[ch]; + struct emac_tx_bd __iomem *curr_bd; + + while ((emac_read(EMAC_TXCP(ch)) & EMAC_TEARDOWN_VALUE) != + EMAC_TEARDOWN_VALUE) { + /* wait till tx teardown complete */ + cpu_relax(); /* TODO: check if this helps ... */ + --teardown_cnt; + if (0 == teardown_cnt) { + dev_err(emac_dev, "EMAC: TX teardown aborted\n"); + break; + } + } + emac_write(EMAC_TXCP(ch), EMAC_TEARDOWN_VALUE); + + /* process sent packets and return skb's to upper layer */ + if (1 == txch->queue_active) { + curr_bd = txch->active_queue_head; + while (curr_bd != NULL) { + emac_net_tx_complete(priv, (void __force *) + &curr_bd->buf_token, 1, ch); + if (curr_bd != txch->active_queue_tail) + curr_bd = curr_bd->next; + else + break; + } + txch->bd_pool_head = txch->active_queue_head; + txch->active_queue_head = + txch->active_queue_tail = NULL; + } +} + +/** + * emac_stop_txch: Stop TX channel operation + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number + * + * Called to stop TX channel operation + * + */ +static void emac_stop_txch(struct emac_priv *priv, u32 ch) +{ + struct emac_txch *txch = priv->txch[ch]; + + if (txch) { + txch->teardown_pending = 1; + emac_write(EMAC_TXTEARDOWN, 0); + emac_txch_teardown(priv, ch); + txch->teardown_pending = 0; + emac_write(EMAC_TXINTMASKCLEAR, BIT(ch)); + } +} + +/** + * emac_tx_bdproc: TX buffer descriptor (packet) processing + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number to process buffer descriptors for + * @budget: number of packets allowed to process + * @pending: indication to caller that packets are pending to process + * + * Processes TX buffer descriptors after packets are transmitted - checks + * ownership bit on the TX * descriptor and requeues it to free pool & frees + * the SKB buffer. Only "budget" number of packets are processed and + * indication of pending packets provided to the caller + * + * Returns number of packets processed + */ +static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget) +{ + struct device *emac_dev = &priv->ndev->dev; + unsigned long flags; + u32 frame_status; + u32 pkts_processed = 0; + u32 tx_complete_cnt = 0; + struct emac_tx_bd __iomem *curr_bd; + struct emac_txch *txch = priv->txch[ch]; + u32 *tx_complete_ptr = txch->tx_complete; + + if (unlikely(1 == txch->teardown_pending)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) { + dev_err(emac_dev, "DaVinci EMAC:emac_tx_bdproc: "\ + "teardown pending\n"); + } + return 0; /* dont handle any pkt completions */ + } + + ++txch->proc_count; + spin_lock_irqsave(&priv->tx_lock, flags); + curr_bd = txch->active_queue_head; + if (NULL == curr_bd) { + emac_write(EMAC_TXCP(ch), + emac_virt_to_phys(txch->last_hw_bdprocessed)); + txch->no_active_pkts++; + spin_unlock_irqrestore(&priv->tx_lock, flags); + return 0; + } + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + while ((curr_bd) && + ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) && + (pkts_processed < budget)) { + emac_write(EMAC_TXCP(ch), emac_virt_to_phys(curr_bd)); + txch->active_queue_head = curr_bd->next; + if (frame_status & EMAC_CPPI_EOQ_BIT) { + if (curr_bd->next) { /* misqueued packet */ + emac_write(EMAC_TXHDP(ch), curr_bd->h_next); + ++txch->mis_queued_packets; + } else { + txch->queue_active = 0; /* end of queue */ + } + } + *tx_complete_ptr = (u32) curr_bd->buf_token; + ++tx_complete_ptr; + ++tx_complete_cnt; + curr_bd->next = txch->bd_pool_head; + txch->bd_pool_head = curr_bd; + --txch->active_queue_count; + pkts_processed++; + txch->last_hw_bdprocessed = curr_bd; + curr_bd = txch->active_queue_head; + if (curr_bd) { + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + } + } /* end of pkt processing loop */ + + emac_net_tx_complete(priv, + (void *)&txch->tx_complete[0], + tx_complete_cnt, ch); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return pkts_processed; +} + +#define EMAC_ERR_TX_OUT_OF_BD -1 + +/** + * emac_send: EMAC Transmit function (internal) + * @priv: The DaVinci EMAC private adapter structure + * @pkt: packet pointer (contains skb ptr) + * @ch: TX channel number + * + * Called by the transmit function to queue the packet in EMAC hardware queue + * + * Returns success(0) or error code (typically out of desc's) + */ +static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch) +{ + unsigned long flags; + struct emac_tx_bd __iomem *curr_bd; + struct emac_txch *txch; + struct emac_netbufobj *buf_list; + + txch = priv->txch[ch]; + buf_list = pkt->buf_list; /* get handle to the buffer array */ + + /* check packet size and pad if short */ + if (pkt->pkt_length < EMAC_DEF_MIN_ETHPKTSIZE) { + buf_list->length += (EMAC_DEF_MIN_ETHPKTSIZE - pkt->pkt_length); + pkt->pkt_length = EMAC_DEF_MIN_ETHPKTSIZE; + } + + spin_lock_irqsave(&priv->tx_lock, flags); + curr_bd = txch->bd_pool_head; + if (curr_bd == NULL) { + txch->out_of_tx_bd++; + spin_unlock_irqrestore(&priv->tx_lock, flags); + return EMAC_ERR_TX_OUT_OF_BD; + } + + txch->bd_pool_head = curr_bd->next; + curr_bd->buf_token = buf_list->buf_token; + /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ + curr_bd->buff_ptr = virt_to_phys(buf_list->data_ptr); + curr_bd->off_b_len = buf_list->length; + curr_bd->h_next = 0; + curr_bd->next = NULL; + curr_bd->mode = (EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT | pkt->pkt_length); + + /* flush the packet from cache if write back cache is present */ + BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + + /* send the packet */ + if (txch->active_queue_head == NULL) { + txch->active_queue_head = curr_bd; + txch->active_queue_tail = curr_bd; + if (1 != txch->queue_active) { + emac_write(EMAC_TXHDP(ch), + emac_virt_to_phys(curr_bd)); + txch->queue_active = 1; + } + ++txch->queue_reinit; + } else { + register struct emac_tx_bd __iomem *tail_bd; + register u32 frame_status; + + tail_bd = txch->active_queue_tail; + tail_bd->next = curr_bd; + txch->active_queue_tail = curr_bd; + tail_bd = EMAC_VIRT_NOCACHE(tail_bd); + tail_bd->h_next = (int)emac_virt_to_phys(curr_bd); + frame_status = tail_bd->mode; + if (frame_status & EMAC_CPPI_EOQ_BIT) { + emac_write(EMAC_TXHDP(ch), emac_virt_to_phys(curr_bd)); + frame_status &= ~(EMAC_CPPI_EOQ_BIT); + tail_bd->mode = frame_status; + ++txch->end_of_queue_add; + } + } + txch->active_queue_count++; + spin_unlock_irqrestore(&priv->tx_lock, flags); + return 0; +} + +/** + * emac_dev_xmit: EMAC Transmit function + * @skb: SKB pointer + * @ndev: The DaVinci EMAC network adapter + * + * Called by the system to transmit a packet - we queue the packet in + * EMAC hardware transmit queue + * + * Returns success(NETDEV_TX_OK) or error code (typically out of desc's) + */ +static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct device *emac_dev = &ndev->dev; + int ret_code; + struct emac_netbufobj tx_buf; /* buffer obj-only single frame support */ + struct emac_netpktobj tx_packet; /* packet object */ + struct emac_priv *priv = netdev_priv(ndev); + + /* If no link, return */ + if (unlikely(!priv->link)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + dev_err(emac_dev, "DaVinci EMAC: No link to transmit"); + return NETDEV_TX_BUSY; + } + + /* Build the buffer and packet objects - Since only single fragment is + * supported, need not set length and token in both packet & object. + * Doing so for completeness sake & to show that this needs to be done + * in multifragment case + */ + tx_packet.buf_list = &tx_buf; + tx_packet.num_bufs = 1; /* only single fragment supported */ + tx_packet.pkt_length = skb->len; + tx_packet.pkt_token = (void *)skb; + tx_buf.length = skb->len; + tx_buf.buf_token = (void *)skb; + tx_buf.data_ptr = skb->data; + EMAC_CACHE_WRITEBACK((unsigned long)skb->data, skb->len); + ndev->trans_start = jiffies; + ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH); + if (unlikely(ret_code != 0)) { + if (ret_code == EMAC_ERR_TX_OUT_OF_BD) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + dev_err(emac_dev, "DaVinci EMAC: xmit() fatal"\ + " err. Out of TX BD's"); + netif_stop_queue(priv->ndev); + } + priv->net_dev_stats.tx_dropped++; + return NETDEV_TX_BUSY; + } + + return NETDEV_TX_OK; +} + +/** + * emac_dev_tx_timeout: EMAC Transmit timeout function + * @ndev: The DaVinci EMAC network adapter + * + * Called when system detects that a skb timeout period has expired + * potentially due to a fault in the adapter in not being able to send + * it out on the wire. We teardown the TX channel assuming a hardware + * error and re-initialize the TX channel for hardware operation + * + */ +static void emac_dev_tx_timeout(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + struct device *emac_dev = &ndev->dev; + + if (netif_msg_tx_err(priv)) + dev_err(emac_dev, "DaVinci EMAC: xmit timeout, restarting TX"); + + priv->net_dev_stats.tx_errors++; + emac_int_disable(priv); + emac_stop_txch(priv, EMAC_DEF_TX_CH); + emac_cleanup_txch(priv, EMAC_DEF_TX_CH); + emac_init_txch(priv, EMAC_DEF_TX_CH); + emac_write(EMAC_TXHDP(0), 0); + emac_write(EMAC_TXINTMASKSET, BIT(EMAC_DEF_TX_CH)); + emac_int_enable(priv); +} + +/** + * emac_net_alloc_rx_buf: Allocate a skb for RX + * @priv: The DaVinci EMAC private adapter structure + * @buf_size: size of SKB data buffer to allocate + * @data_token: data token returned (skb handle for storing in buffer desc) + * @ch: RX channel number + * + * Called during RX channel setup - allocates skb buffer of required size + * and provides the skb handle and allocated buffer data pointer to caller + * + * Returns skb data pointer or 0 on failure to alloc skb + */ +static void *emac_net_alloc_rx_buf(struct emac_priv *priv, int buf_size, + void **data_token, u32 ch) +{ + struct net_device *ndev = priv->ndev; + struct device *emac_dev = &ndev->dev; + struct sk_buff *p_skb; + + p_skb = dev_alloc_skb(buf_size); + if (unlikely(NULL == p_skb)) { + if (netif_msg_rx_err(priv) && net_ratelimit()) + dev_err(emac_dev, "DaVinci EMAC: failed to alloc skb"); + return NULL; + } + + /* set device pointer in skb and reserve space for extra bytes */ + p_skb->dev = ndev; + skb_reserve(p_skb, NET_IP_ALIGN); + *data_token = (void *) p_skb; + EMAC_CACHE_WRITEBACK_INVALIDATE((unsigned long)p_skb->data, buf_size); + return p_skb->data; +} + +/** + * emac_init_rxch: RX channel initialization + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @param: mac address for RX channel + * + * Called during device init to setup a RX channel (allocate buffers and + * buffer descriptors, create queue and keep ready for reception + * + * Returns success(0) or mem alloc failures error code + */ +static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 cnt, bd_size; + void __iomem *mem; + struct emac_rx_bd __iomem *curr_bd; + struct emac_rxch *rxch = NULL; + + rxch = kzalloc(sizeof(struct emac_rxch), GFP_KERNEL); + if (NULL == rxch) { + dev_err(emac_dev, "DaVinci EMAC: RX Ch mem alloc failed"); + return -ENOMEM; + } + priv->rxch[ch] = rxch; + rxch->buf_size = priv->rx_buf_size; + rxch->service_max = EMAC_DEF_RX_MAX_SERVICE; + rxch->queue_active = 0; + rxch->teardown_pending = 0; + + /* save mac address */ + for (cnt = 0; cnt < 6; cnt++) + rxch->mac_addr[cnt] = param[cnt]; + + /* allocate buffer descriptor pool align every BD on four word + * boundry for future requirements */ + bd_size = (sizeof(struct emac_rx_bd) + 0xF) & ~0xF; + rxch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size; + rxch->alloc_size = (((bd_size * rxch->num_bd) + 0xF) & ~0xF); + rxch->bd_mem = EMAC_RX_BD_MEM(priv); + __memzero((void __force *)rxch->bd_mem, rxch->alloc_size); + rxch->pkt_queue.buf_list = &rxch->buf_queue; + + /* allocate RX buffer and initialize the BD linked list */ + mem = (void __force __iomem *) + (((u32 __force) rxch->bd_mem + 0xF) & ~0xF); + rxch->active_queue_head = NULL; + rxch->active_queue_tail = mem; + for (cnt = 0; cnt < rxch->num_bd; cnt++) { + curr_bd = mem + (cnt * bd_size); + /* for future use the last parameter contains the BD ptr */ + curr_bd->data_ptr = emac_net_alloc_rx_buf(priv, + rxch->buf_size, + (void __force **)&curr_bd->buf_token, + EMAC_DEF_RX_CH); + if (curr_bd->data_ptr == NULL) { + dev_err(emac_dev, "DaVinci EMAC: RX buf mem alloc " \ + "failed for ch %d\n", ch); + kfree(rxch); + return -ENOMEM; + } + + /* populate the hardware descriptor */ + curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head); + /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ + curr_bd->buff_ptr = virt_to_phys(curr_bd->data_ptr); + curr_bd->off_b_len = rxch->buf_size; + curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT; + + /* write back to hardware memory */ + BD_CACHE_WRITEBACK_INVALIDATE((u32) curr_bd, + EMAC_BD_LENGTH_FOR_CACHE); + curr_bd->next = rxch->active_queue_head; + rxch->active_queue_head = curr_bd; + } + + /* At this point rxCppi->activeQueueHead points to the first + RX BD ready to be given to RX HDP and rxch->active_queue_tail + points to the last RX BD + */ + return 0; +} + +/** + * emac_rxch_teardown: RX channel teardown + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device stop to teardown RX channel + * + */ +static void emac_rxch_teardown(struct emac_priv *priv, u32 ch) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */ + + while ((emac_read(EMAC_RXCP(ch)) & EMAC_TEARDOWN_VALUE) != + EMAC_TEARDOWN_VALUE) { + /* wait till tx teardown complete */ + cpu_relax(); /* TODO: check if this helps ... */ + --teardown_cnt; + if (0 == teardown_cnt) { + dev_err(emac_dev, "EMAC: RX teardown aborted\n"); + break; + } + } + emac_write(EMAC_RXCP(ch), EMAC_TEARDOWN_VALUE); +} + +/** + * emac_stop_rxch: Stop RX channel operation + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device stop to stop RX channel operation + * + */ +static void emac_stop_rxch(struct emac_priv *priv, u32 ch) +{ + struct emac_rxch *rxch = priv->rxch[ch]; + + if (rxch) { + rxch->teardown_pending = 1; + emac_write(EMAC_RXTEARDOWN, ch); + /* wait for teardown complete */ + emac_rxch_teardown(priv, ch); + rxch->teardown_pending = 0; + emac_write(EMAC_RXINTMASKCLEAR, BIT(ch)); + } +} + +/** + * emac_cleanup_rxch: Book-keep function to clean RX channel resources + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device stop to clean up RX channel resources + * + */ +static void emac_cleanup_rxch(struct emac_priv *priv, u32 ch) +{ + struct emac_rxch *rxch = priv->rxch[ch]; + struct emac_rx_bd __iomem *curr_bd; + + if (rxch) { + /* free the receive buffers previously allocated */ + curr_bd = rxch->active_queue_head; + while (curr_bd) { + if (curr_bd->buf_token) { + dev_kfree_skb_any((struct sk_buff *)\ + curr_bd->buf_token); + } + curr_bd = curr_bd->next; + } + if (rxch->bd_mem) + rxch->bd_mem = NULL; + kfree(rxch); + priv->rxch[ch] = NULL; + } +} + +/** + * emac_set_type0addr: Set EMAC Type0 mac address + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * + * Called internally to set Type0 mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_set_type0addr(struct emac_priv *priv, u32 ch, char *mac_addr) +{ + u32 val; + val = ((mac_addr[5] << 8) | (mac_addr[4])); + emac_write(EMAC_MACSRCADDRLO, val); + + val = ((mac_addr[3] << 24) | (mac_addr[2] << 16) | \ + (mac_addr[1] << 8) | (mac_addr[0])); + emac_write(EMAC_MACSRCADDRHI, val); + val = emac_read(EMAC_RXUNICASTSET); + val |= BIT(ch); + emac_write(EMAC_RXUNICASTSET, val); + val = emac_read(EMAC_RXUNICASTCLEAR); + val &= ~BIT(ch); + emac_write(EMAC_RXUNICASTCLEAR, val); +} + +/** + * emac_set_type1addr: Set EMAC Type1 mac address + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * + * Called internally to set Type1 mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_set_type1addr(struct emac_priv *priv, u32 ch, char *mac_addr) +{ + u32 val; + emac_write(EMAC_MACINDEX, ch); + val = ((mac_addr[5] << 8) | mac_addr[4]); + emac_write(EMAC_MACADDRLO, val); + val = ((mac_addr[3] << 24) | (mac_addr[2] << 16) | \ + (mac_addr[1] << 8) | (mac_addr[0])); + emac_write(EMAC_MACADDRHI, val); + emac_set_type0addr(priv, ch, mac_addr); +} + +/** + * emac_set_type2addr: Set EMAC Type2 mac address + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * @index: index into RX address entries + * @match: match parameter for RX address matching logic + * + * Called internally to set Type2 mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_set_type2addr(struct emac_priv *priv, u32 ch, + char *mac_addr, int index, int match) +{ + u32 val; + emac_write(EMAC_MACINDEX, index); + val = ((mac_addr[3] << 24) | (mac_addr[2] << 16) | \ + (mac_addr[1] << 8) | (mac_addr[0])); + emac_write(EMAC_MACADDRHI, val); + val = ((mac_addr[5] << 8) | mac_addr[4] | ((ch & 0x7) << 16) | \ + (match << 19) | BIT(20)); + emac_write(EMAC_MACADDRLO, val); + emac_set_type0addr(priv, ch, mac_addr); +} + +/** + * emac_setmac: Set mac address in the adapter (internal function) + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * + * Called internally to set the mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_setmac(struct emac_priv *priv, u32 ch, char *mac_addr) +{ + struct device *emac_dev = &priv->ndev->dev; + + if (priv->rx_addr_type == 0) { + emac_set_type0addr(priv, ch, mac_addr); + } else if (priv->rx_addr_type == 1) { + u32 cnt; + for (cnt = 0; cnt < EMAC_MAX_TXRX_CHANNELS; cnt++) + emac_set_type1addr(priv, ch, mac_addr); + } else if (priv->rx_addr_type == 2) { + emac_set_type2addr(priv, ch, mac_addr, ch, 1); + emac_set_type0addr(priv, ch, mac_addr); + } else { + if (netif_msg_drv(priv)) + dev_err(emac_dev, "DaVinci EMAC: Wrong addressing\n"); + } +} + +/** + * emac_dev_setmac_addr: Set mac address in the adapter + * @ndev: The DaVinci EMAC network adapter + * @addr: MAC address to set in device + * + * Called by the system to set the mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) +{ + struct emac_priv *priv = netdev_priv(ndev); + struct emac_rxch *rxch = priv->rxch[EMAC_DEF_RX_CH]; + struct device *emac_dev = &priv->ndev->dev; + struct sockaddr *sa = addr; + DECLARE_MAC_BUF(mac); + + /* Store mac addr in priv and rx channel and set it in EMAC hw */ + memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len); + memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len); + memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len); + emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr); + + if (netif_msg_drv(priv)) + dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %s\n", + print_mac(mac, priv->mac_addr)); + + return 0; +} + +/** + * emac_addbd_to_rx_queue: Recycle RX buffer descriptor + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number to process buffer descriptors for + * @curr_bd: current buffer descriptor + * @buffer: buffer pointer for descriptor + * @buf_token: buffer token (stores skb information) + * + * Prepares the recycled buffer descriptor and addes it to hardware + * receive queue - if queue empty this descriptor becomes the head + * else addes the descriptor to end of queue + * + */ +static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch, + struct emac_rx_bd __iomem *curr_bd, + char *buffer, void *buf_token) +{ + struct emac_rxch *rxch = priv->rxch[ch]; + + /* populate the hardware descriptor */ + curr_bd->h_next = 0; + /* FIXME buff_ptr = dma_map_single(... buffer ...) */ + curr_bd->buff_ptr = virt_to_phys(buffer); + curr_bd->off_b_len = rxch->buf_size; + curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT; + curr_bd->next = NULL; + curr_bd->data_ptr = buffer; + curr_bd->buf_token = buf_token; + + /* write back */ + BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + if (rxch->active_queue_head == NULL) { + rxch->active_queue_head = curr_bd; + rxch->active_queue_tail = curr_bd; + if (0 != rxch->queue_active) { + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(rxch->active_queue_head)); + rxch->queue_active = 1; + } + } else { + struct emac_rx_bd __iomem *tail_bd; + u32 frame_status; + + tail_bd = rxch->active_queue_tail; + rxch->active_queue_tail = curr_bd; + tail_bd->next = curr_bd; + tail_bd = EMAC_VIRT_NOCACHE(tail_bd); + tail_bd->h_next = emac_virt_to_phys(curr_bd); + frame_status = tail_bd->mode; + if (frame_status & EMAC_CPPI_EOQ_BIT) { + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(curr_bd)); + frame_status &= ~(EMAC_CPPI_EOQ_BIT); + tail_bd->mode = frame_status; + ++rxch->end_of_queue_add; + } + } + ++rxch->recycled_bd; +} + +/** + * emac_net_rx_cb: Prepares packet and sends to upper layer + * @priv: The DaVinci EMAC private adapter structure + * @net_pkt_list: Network packet list (received packets) + * + * Invalidates packet buffer memory and sends the received packet to upper + * layer + * + * Returns success or appropriate error code (none as of now) + */ +static int emac_net_rx_cb(struct emac_priv *priv, + struct emac_netpktobj *net_pkt_list) +{ + struct sk_buff *p_skb; + p_skb = (struct sk_buff *)net_pkt_list->pkt_token; + /* set length of packet */ + skb_put(p_skb, net_pkt_list->pkt_length); + EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len); + p_skb->protocol = eth_type_trans(p_skb, priv->ndev); + p_skb->dev->last_rx = jiffies; + netif_receive_skb(p_skb); + priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length; + priv->net_dev_stats.rx_packets++; + return 0; +} + +/** + * emac_rx_bdproc: RX buffer descriptor (packet) processing + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number to process buffer descriptors for + * @budget: number of packets allowed to process + * @pending: indication to caller that packets are pending to process + * + * Processes RX buffer descriptors - checks ownership bit on the RX buffer + * descriptor, sends the receive packet to upper layer, allocates a new SKB + * and recycles the buffer descriptor (requeues it in hardware RX queue). + * Only "budget" number of packets are processed and indication of pending + * packets provided to the caller. + * + * Returns number of packets processed (and indication of pending packets) + */ +static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget) +{ + unsigned long flags; + u32 frame_status; + u32 pkts_processed = 0; + char *new_buffer; + struct emac_rx_bd __iomem *curr_bd; + struct emac_rx_bd __iomem *last_bd; + struct emac_netpktobj *curr_pkt, pkt_obj; + struct emac_netbufobj buf_obj; + struct emac_netbufobj *rx_buf_obj; + void *new_buf_token; + struct emac_rxch *rxch = priv->rxch[ch]; + + if (unlikely(1 == rxch->teardown_pending)) + return 0; + ++rxch->proc_count; + spin_lock_irqsave(&priv->rx_lock, flags); + pkt_obj.buf_list = &buf_obj; + curr_pkt = &pkt_obj; + curr_bd = rxch->active_queue_head; + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + + while ((curr_bd) && + ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) && + (pkts_processed < budget)) { + + new_buffer = emac_net_alloc_rx_buf(priv, rxch->buf_size, + &new_buf_token, EMAC_DEF_RX_CH); + if (unlikely(NULL == new_buffer)) { + ++rxch->out_of_rx_buffers; + goto end_emac_rx_bdproc; + } + + /* populate received packet data structure */ + rx_buf_obj = &curr_pkt->buf_list[0]; + rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr; + rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE; + rx_buf_obj->buf_token = curr_bd->buf_token; + curr_pkt->pkt_token = curr_pkt->buf_list->buf_token; + curr_pkt->num_bufs = 1; + curr_pkt->pkt_length = + (frame_status & EMAC_RX_BD_PKT_LENGTH_MASK); + emac_write(EMAC_RXCP(ch), emac_virt_to_phys(curr_bd)); + ++rxch->processed_bd; + last_bd = curr_bd; + curr_bd = last_bd->next; + rxch->active_queue_head = curr_bd; + + /* check if end of RX queue ? */ + if (frame_status & EMAC_CPPI_EOQ_BIT) { + if (curr_bd) { + ++rxch->mis_queued_packets; + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(curr_bd)); + } else { + ++rxch->end_of_queue; + rxch->queue_active = 0; + } + } + + /* recycle BD */ + emac_addbd_to_rx_queue(priv, ch, last_bd, new_buffer, + new_buf_token); + + /* return the packet to the user - BD ptr passed in + * last parameter for potential *future* use */ + spin_unlock_irqrestore(&priv->rx_lock, flags); + emac_net_rx_cb(priv, curr_pkt); + spin_lock_irqsave(&priv->rx_lock, flags); + curr_bd = rxch->active_queue_head; + if (curr_bd) { + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + } + ++pkts_processed; + } + +end_emac_rx_bdproc: + spin_unlock_irqrestore(&priv->rx_lock, flags); + return pkts_processed; +} + +/** + * emac_hw_enable: Enable EMAC hardware for packet transmission/reception + * @priv: The DaVinci EMAC private adapter structure + * + * Enables EMAC hardware for packet processing - enables PHY, enables RX + * for packet reception and enables device interrupts and then NAPI + * + * Returns success (0) or appropriate error code (none right now) + */ +static int emac_hw_enable(struct emac_priv *priv) +{ + u32 ch, val, mbp_enable, mac_control; + + /* Soft reset */ + emac_write(EMAC_SOFTRESET, 1); + while (emac_read(EMAC_SOFTRESET)) + cpu_relax(); + + /* Disable interrupt & Set pacing for more interrupts initially */ + emac_int_disable(priv); + + /* Full duplex enable bit set when auto negotiation happens */ + mac_control = + (((EMAC_DEF_TXPRIO_FIXED) ? (EMAC_MACCONTROL_TXPTYPE) : 0x0) | + ((priv->speed == 1000) ? EMAC_MACCONTROL_GIGABITEN : 0x0) | + ((EMAC_DEF_TXPACING_EN) ? (EMAC_MACCONTROL_TXPACEEN) : 0x0) | + ((priv->duplex == DUPLEX_FULL) ? 0x1 : 0)); + emac_write(EMAC_MACCONTROL, mac_control); + + mbp_enable = + (((EMAC_DEF_PASS_CRC) ? (EMAC_RXMBP_PASSCRC_MASK) : 0x0) | + ((EMAC_DEF_QOS_EN) ? (EMAC_RXMBP_QOSEN_MASK) : 0x0) | + ((EMAC_DEF_NO_BUFF_CHAIN) ? (EMAC_RXMBP_NOCHAIN_MASK) : 0x0) | + ((EMAC_DEF_MACCTRL_FRAME_EN) ? (EMAC_RXMBP_CMFEN_MASK) : 0x0) | + ((EMAC_DEF_SHORT_FRAME_EN) ? (EMAC_RXMBP_CSFEN_MASK) : 0x0) | + ((EMAC_DEF_ERROR_FRAME_EN) ? (EMAC_RXMBP_CEFEN_MASK) : 0x0) | + ((EMAC_DEF_PROM_EN) ? (EMAC_RXMBP_CAFEN_MASK) : 0x0) | + ((EMAC_DEF_PROM_CH & EMAC_RXMBP_CHMASK) << \ + EMAC_RXMBP_PROMCH_SHIFT) | + ((EMAC_DEF_BCAST_EN) ? (EMAC_RXMBP_BROADEN_MASK) : 0x0) | + ((EMAC_DEF_BCAST_CH & EMAC_RXMBP_CHMASK) << \ + EMAC_RXMBP_BROADCH_SHIFT) | + ((EMAC_DEF_MCAST_EN) ? (EMAC_RXMBP_MULTIEN_MASK) : 0x0) | + ((EMAC_DEF_MCAST_CH & EMAC_RXMBP_CHMASK) << \ + EMAC_RXMBP_MULTICH_SHIFT)); + emac_write(EMAC_RXMBPENABLE, mbp_enable); + emac_write(EMAC_RXMAXLEN, (EMAC_DEF_MAX_FRAME_SIZE & + EMAC_RX_MAX_LEN_MASK)); + emac_write(EMAC_RXBUFFEROFFSET, (EMAC_DEF_BUFFER_OFFSET & + EMAC_RX_BUFFER_OFFSET_MASK)); + emac_write(EMAC_RXFILTERLOWTHRESH, 0); + emac_write(EMAC_RXUNICASTCLEAR, EMAC_RX_UNICAST_CLEAR_ALL); + priv->rx_addr_type = (emac_read(EMAC_MACCONFIG) >> 8) & 0xFF; + + val = emac_read(EMAC_TXCONTROL); + val |= EMAC_TX_CONTROL_TX_ENABLE_VAL; + emac_write(EMAC_TXCONTROL, val); + val = emac_read(EMAC_RXCONTROL); + val |= EMAC_RX_CONTROL_RX_ENABLE_VAL; + emac_write(EMAC_RXCONTROL, val); + emac_write(EMAC_MACINTMASKSET, EMAC_MAC_HOST_ERR_INTMASK_VAL); + + for (ch = 0; ch < EMAC_DEF_MAX_TX_CH; ch++) { + emac_write(EMAC_TXHDP(ch), 0); + emac_write(EMAC_TXINTMASKSET, BIT(ch)); + } + for (ch = 0; ch < EMAC_DEF_MAX_RX_CH; ch++) { + struct emac_rxch *rxch = priv->rxch[ch]; + emac_setmac(priv, ch, rxch->mac_addr); + emac_write(EMAC_RXINTMASKSET, BIT(ch)); + rxch->queue_active = 1; + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(rxch->active_queue_head)); + } + + /* Enable MII */ + val = emac_read(EMAC_MACCONTROL); + val |= (EMAC_MACCONTROL_MIIEN); + emac_write(EMAC_MACCONTROL, val); + + /* Enable NAPI and interrupts */ + napi_enable(&priv->napi); + emac_int_enable(priv); + return 0; + +} + +/** + * emac_poll: EMAC NAPI Poll function + * @ndev: The DaVinci EMAC network adapter + * @budget: Number of receive packets to process (as told by NAPI layer) + * + * NAPI Poll function implemented to process packets as per budget. We check + * the type of interrupt on the device and accordingly call the TX or RX + * packet processing functions. We follow the budget for RX processing and + * also put a cap on number of TX pkts processed through config param. The + * NAPI schedule function is called if more packets pending. + * + * Returns number of packets received (in most cases; else TX pkts - rarely) + */ +static int emac_poll(struct napi_struct *napi, int budget) +{ + unsigned int mask; + struct emac_priv *priv = container_of(napi, struct emac_priv, napi); + struct net_device *ndev = priv->ndev; + struct device *emac_dev = &ndev->dev; + u32 status = 0; + u32 num_pkts = 0; + + if (!netif_running(ndev)) + return 0; + + /* Check interrupt vectors and call packet processing */ + status = emac_read(EMAC_MACINVECTOR); + + mask = EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC; + + if (priv->version == EMAC_VERSION_2) + mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC; + + if (status & mask) { + num_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH, + EMAC_DEF_TX_MAX_SERVICE); + } /* TX processing */ + + if (num_pkts) + return budget; + + mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC; + + if (priv->version == EMAC_VERSION_2) + mask = EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC; + + if (status & mask) { + num_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget); + } /* RX processing */ + + if (num_pkts < budget) { + napi_complete(napi); + emac_int_enable(priv); + } + + if (unlikely(status & EMAC_DM644X_MAC_IN_VECTOR_HOST_INT)) { + u32 ch, cause; + dev_err(emac_dev, "DaVinci EMAC: Fatal Hardware Error\n"); + netif_stop_queue(ndev); + napi_disable(&priv->napi); + + status = emac_read(EMAC_MACSTATUS); + cause = ((status & EMAC_MACSTATUS_TXERRCODE_MASK) >> + EMAC_MACSTATUS_TXERRCODE_SHIFT); + if (cause) { + ch = ((status & EMAC_MACSTATUS_TXERRCH_MASK) >> + EMAC_MACSTATUS_TXERRCH_SHIFT); + if (net_ratelimit()) { + dev_err(emac_dev, "TX Host error %s on ch=%d\n", + &emac_txhost_errcodes[cause][0], ch); + } + } + cause = ((status & EMAC_MACSTATUS_RXERRCODE_MASK) >> + EMAC_MACSTATUS_RXERRCODE_SHIFT); + if (cause) { + ch = ((status & EMAC_MACSTATUS_RXERRCH_MASK) >> + EMAC_MACSTATUS_RXERRCH_SHIFT); + if (netif_msg_hw(priv) && net_ratelimit()) + dev_err(emac_dev, "RX Host error %s on ch=%d\n", + &emac_rxhost_errcodes[cause][0], ch); + } + } /* Host error processing */ + + return num_pkts; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/** + * emac_poll_controller: EMAC Poll controller function + * @ndev: The DaVinci EMAC network adapter + * + * Polled functionality used by netconsole and others in non interrupt mode + * + */ +void emac_poll_controller(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + + emac_int_disable(priv); + emac_irq(ndev->irq, priv); + emac_int_enable(priv); +} +#endif + +/* PHY/MII bus related */ + +/* Wait until mdio is ready for next command */ +#define MDIO_WAIT_FOR_USER_ACCESS\ + while ((emac_mdio_read((MDIO_USERACCESS(0))) &\ + MDIO_USERACCESS_GO) != 0) + +static int emac_mii_read(struct mii_bus *bus, int phy_id, int phy_reg) +{ + unsigned int phy_data = 0; + unsigned int phy_control; + + /* Wait until mdio is ready for next command */ + MDIO_WAIT_FOR_USER_ACCESS; + + phy_control = (MDIO_USERACCESS_GO | + MDIO_USERACCESS_READ | + ((phy_reg << 21) & MDIO_USERACCESS_REGADR) | + ((phy_id << 16) & MDIO_USERACCESS_PHYADR) | + (phy_data & MDIO_USERACCESS_DATA)); + emac_mdio_write(MDIO_USERACCESS(0), phy_control); + + /* Wait until mdio is ready for next command */ + MDIO_WAIT_FOR_USER_ACCESS; + + return emac_mdio_read(MDIO_USERACCESS(0)) & MDIO_USERACCESS_DATA; + +} + +static int emac_mii_write(struct mii_bus *bus, int phy_id, + int phy_reg, u16 phy_data) +{ + + unsigned int control; + + /* until mdio is ready for next command */ + MDIO_WAIT_FOR_USER_ACCESS; + + control = (MDIO_USERACCESS_GO | + MDIO_USERACCESS_WRITE | + ((phy_reg << 21) & MDIO_USERACCESS_REGADR) | + ((phy_id << 16) & MDIO_USERACCESS_PHYADR) | + (phy_data & MDIO_USERACCESS_DATA)); + emac_mdio_write(MDIO_USERACCESS(0), control); + + return 0; +} + +static int emac_mii_reset(struct mii_bus *bus) +{ + unsigned int clk_div; + int mdio_bus_freq = emac_bus_frequency; + + if (mdio_max_freq & mdio_bus_freq) + clk_div = ((mdio_bus_freq / mdio_max_freq) - 1); + else + clk_div = 0xFF; + + clk_div &= MDIO_CONTROL_CLKDIV; + + /* Set enable and clock divider in MDIOControl */ + emac_mdio_write(MDIO_CONTROL, (clk_div | MDIO_CONTROL_ENABLE)); + + return 0; + +} + +static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, PHY_POLL }; + +/* emac_driver: EMAC MII bus structure */ + +static struct mii_bus *emac_mii; + +static void emac_adjust_link(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + struct phy_device *phydev = priv->phydev; + unsigned long flags; + int new_state = 0; + + spin_lock_irqsave(&priv->lock, flags); + + if (phydev->link) { + /* check the mode of operation - full/half duplex */ + if (phydev->duplex != priv->duplex) { + new_state = 1; + priv->duplex = phydev->duplex; + } + if (phydev->speed != priv->speed) { + new_state = 1; + priv->speed = phydev->speed; + } + if (!priv->link) { + new_state = 1; + priv->link = 1; + } + + } else if (priv->link) { + new_state = 1; + priv->link = 0; + priv->speed = 0; + priv->duplex = ~0; + } + if (new_state) { + emac_update_phystatus(priv); + phy_print_status(priv->phydev); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +/************************************************************************* + * Linux Driver Model + *************************************************************************/ + +/** + * emac_devioctl: EMAC adapter ioctl + * @ndev: The DaVinci EMAC network adapter + * @ifrq: request parameter + * @cmd: command parameter + * + * EMAC driver ioctl function + * + * Returns success(0) or appropriate error code + */ +static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) +{ + dev_warn(&ndev->dev, "DaVinci EMAC: ioctl not supported\n"); + + if (!(netif_running(ndev))) + return -EINVAL; + + /* TODO: Add phy read and write and private statistics get feature */ + + return -EOPNOTSUPP; +} + +/** + * emac_dev_open: EMAC device open + * @ndev: The DaVinci EMAC network adapter + * + * Called when system wants to start the interface. We init TX/RX channels + * and enable the hardware for packet reception/transmission and start the + * network queue. + * + * Returns 0 for a successful open, or appropriate error code + */ +static int emac_dev_open(struct net_device *ndev) +{ + struct device *emac_dev = &ndev->dev; + u32 rc, cnt, ch; + int phy_addr; + struct resource *res; + int q, m; + int i = 0; + int k = 0; + struct emac_priv *priv = netdev_priv(ndev); + + netif_carrier_off(ndev); + for (cnt = 0; cnt <= ETH_ALEN; cnt++) + ndev->dev_addr[cnt] = priv->mac_addr[cnt]; + + /* Configuration items */ + priv->rx_buf_size = EMAC_DEF_MAX_FRAME_SIZE + NET_IP_ALIGN; + + /* Clear basic hardware */ + for (ch = 0; ch < EMAC_MAX_TXRX_CHANNELS; ch++) { + emac_write(EMAC_TXHDP(ch), 0); + emac_write(EMAC_RXHDP(ch), 0); + emac_write(EMAC_RXHDP(ch), 0); + emac_write(EMAC_RXINTMASKCLEAR, EMAC_INT_MASK_CLEAR); + emac_write(EMAC_TXINTMASKCLEAR, EMAC_INT_MASK_CLEAR); + } + priv->mac_hash1 = 0; + priv->mac_hash2 = 0; + emac_write(EMAC_MACHASH1, 0); + emac_write(EMAC_MACHASH2, 0); + + /* multi ch not supported - open 1 TX, 1RX ch by default */ + rc = emac_init_txch(priv, EMAC_DEF_TX_CH); + if (0 != rc) { + dev_err(emac_dev, "DaVinci EMAC: emac_init_txch() failed"); + return rc; + } + rc = emac_init_rxch(priv, EMAC_DEF_RX_CH, priv->mac_addr); + if (0 != rc) { + dev_err(emac_dev, "DaVinci EMAC: emac_init_rxch() failed"); + return rc; + } + + /* Request IRQ */ + + while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { + for (i = res->start; i <= res->end; i++) { + if (request_irq(i, emac_irq, IRQF_DISABLED, + ndev->name, ndev)) + goto rollback; + } + k++; + } + + /* Start/Enable EMAC hardware */ + emac_hw_enable(priv); + + /* find the first phy */ + priv->phydev = NULL; + if (priv->phy_mask) { + emac_mii_reset(priv->mii_bus); + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (priv->mii_bus->phy_map[phy_addr]) { + priv->phydev = priv->mii_bus->phy_map[phy_addr]; + break; + } + } + + if (!priv->phydev) { + printk(KERN_ERR "%s: no PHY found\n", ndev->name); + return -1; + } + + priv->phydev = phy_connect(ndev, dev_name(&priv->phydev->dev), + &emac_adjust_link, 0, PHY_INTERFACE_MODE_MII); + + if (IS_ERR(priv->phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", + ndev->name); + return PTR_ERR(priv->phydev); + } + + priv->link = 0; + priv->speed = 0; + priv->duplex = ~0; + + printk(KERN_INFO "%s: attached PHY driver [%s] " + "(mii_bus:phy_addr=%s, id=%x)\n", ndev->name, + priv->phydev->drv->name, dev_name(&priv->phydev->dev), + priv->phydev->phy_id); + } else{ + /* No PHY , fix the link, speed and duplex settings */ + priv->link = 1; + priv->speed = SPEED_100; + priv->duplex = DUPLEX_FULL; + emac_update_phystatus(priv); + } + + if (!netif_running(ndev)) /* debug only - to avoid compiler warning */ + emac_dump_regs(priv); + + if (netif_msg_drv(priv)) + dev_notice(emac_dev, "DaVinci EMAC: Opened %s\n", ndev->name); + + if (priv->phy_mask) + phy_start(priv->phydev); + + return 0; + +rollback: + + dev_err(emac_dev, "DaVinci EMAC: request_irq() failed"); + + for (q = k; k >= 0; k--) { + for (m = i; m >= res->start; m--) + free_irq(m, ndev); + res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k-1); + m = res->end; + } + return -EBUSY; +} + +/** + * emac_dev_stop: EMAC device stop + * @ndev: The DaVinci EMAC network adapter + * + * Called when system wants to stop or down the interface. We stop the network + * queue, disable interrupts and cleanup TX/RX channels. + * + * We return the statistics in net_device_stats structure pulled from emac + */ +static int emac_dev_stop(struct net_device *ndev) +{ + struct resource *res; + int i = 0; + int irq_num; + struct emac_priv *priv = netdev_priv(ndev); + struct device *emac_dev = &ndev->dev; + + /* inform the upper layers. */ + netif_stop_queue(ndev); + napi_disable(&priv->napi); + + netif_carrier_off(ndev); + emac_int_disable(priv); + emac_stop_txch(priv, EMAC_DEF_TX_CH); + emac_stop_rxch(priv, EMAC_DEF_RX_CH); + emac_cleanup_txch(priv, EMAC_DEF_TX_CH); + emac_cleanup_rxch(priv, EMAC_DEF_RX_CH); + emac_write(EMAC_SOFTRESET, 1); + + if (priv->phydev) + phy_disconnect(priv->phydev); + + /* Free IRQ */ + while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, priv->ndev); + i++; + } + + if (netif_msg_drv(priv)) + dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name); + + return 0; +} + +/** + * emac_dev_getnetstats: EMAC get statistics function + * @ndev: The DaVinci EMAC network adapter + * + * Called when system wants to get statistics from the device. + * + * We return the statistics in net_device_stats structure pulled from emac + */ +static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + + /* update emac hardware stats and reset the registers*/ + + priv->net_dev_stats.multicast += emac_read(EMAC_RXMCASTFRAMES); + emac_write(EMAC_RXMCASTFRAMES, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.collisions += (emac_read(EMAC_TXCOLLISION) + + emac_read(EMAC_TXSINGLECOLL) + + emac_read(EMAC_TXMULTICOLL)); + emac_write(EMAC_TXCOLLISION, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_TXSINGLECOLL, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_TXMULTICOLL, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.rx_length_errors += (emac_read(EMAC_RXOVERSIZED) + + emac_read(EMAC_RXJABBER) + + emac_read(EMAC_RXUNDERSIZED)); + emac_write(EMAC_RXOVERSIZED, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_RXJABBER, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_RXUNDERSIZED, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.rx_over_errors += (emac_read(EMAC_RXSOFOVERRUNS) + + emac_read(EMAC_RXMOFOVERRUNS)); + emac_write(EMAC_RXSOFOVERRUNS, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_RXMOFOVERRUNS, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.rx_fifo_errors += emac_read(EMAC_RXDMAOVERRUNS); + emac_write(EMAC_RXDMAOVERRUNS, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.tx_carrier_errors += + emac_read(EMAC_TXCARRIERSENSE); + emac_write(EMAC_TXCARRIERSENSE, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.tx_fifo_errors = emac_read(EMAC_TXUNDERRUN); + emac_write(EMAC_TXUNDERRUN, EMAC_ALL_MULTI_REG_VALUE); + + return &priv->net_dev_stats; +} + +static const struct net_device_ops emac_netdev_ops = { + .ndo_open = emac_dev_open, + .ndo_stop = emac_dev_stop, + .ndo_start_xmit = emac_dev_xmit, + .ndo_set_multicast_list = emac_dev_mcast_set, + .ndo_set_mac_address = emac_dev_setmac_addr, + .ndo_do_ioctl = emac_devioctl, + .ndo_tx_timeout = emac_dev_tx_timeout, + .ndo_get_stats = emac_dev_getnetstats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = emac_poll_controller, +#endif +}; + +/** + * davinci_emac_probe: EMAC device probe + * @pdev: The DaVinci EMAC device that we are removing + * + * Called when probing for emac devicesr. We get details of instances and + * resource information from platform init and register a network device + * and allocate resources necessary for driver to perform + */ +static int __devinit davinci_emac_probe(struct platform_device *pdev) +{ + int rc = 0; + struct resource *res; + struct net_device *ndev; + struct emac_priv *priv; + unsigned long size; + struct emac_platform_data *pdata; + struct device *emac_dev; + + /* obtain emac clock from kernel */ + emac_clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(emac_clk)) { + printk(KERN_ERR "DaVinci EMAC: Failed to get EMAC clock\n"); + return -EBUSY; + } + emac_bus_frequency = clk_get_rate(emac_clk); + /* TODO: Probe PHY here if possible */ + + ndev = alloc_etherdev(sizeof(struct emac_priv)); + if (!ndev) { + printk(KERN_ERR "DaVinci EMAC: Error allocating net_device\n"); + clk_put(emac_clk); + return -ENOMEM; + } + + platform_set_drvdata(pdev, ndev); + priv = netdev_priv(ndev); + priv->pdev = pdev; + priv->ndev = ndev; + priv->msg_enable = netif_msg_init(debug_level, DAVINCI_EMAC_DEBUG); + + spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->rx_lock); + spin_lock_init(&priv->lock); + + pdata = pdev->dev.platform_data; + if (!pdata) { + printk(KERN_ERR "DaVinci EMAC: No platfrom data\n"); + return -ENODEV; + } + + /* MAC addr and PHY mask , RMII enable info from platform_data */ + memcpy(priv->mac_addr, pdata->mac_addr, 6); + priv->phy_mask = pdata->phy_mask; + priv->rmii_en = pdata->rmii_en; + priv->version = pdata->version; + emac_dev = &ndev->dev; + /* Get EMAC platform data */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(emac_dev, "DaVinci EMAC: Error getting res\n"); + rc = -ENOENT; + goto probe_quit; + } + + priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; + size = res->end - res->start + 1; + if (!request_mem_region(res->start, size, ndev->name)) { + dev_err(emac_dev, "DaVinci EMAC: failed request_mem_region() \ + for regs\n"); + rc = -ENXIO; + goto probe_quit; + } + + priv->remap_addr = ioremap(res->start, size); + if (!priv->remap_addr) { + dev_err(emac_dev, "Unable to map IO\n"); + rc = -ENOMEM; + release_mem_region(res->start, size); + goto probe_quit; + } + priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset; + ndev->base_addr = (unsigned long)priv->remap_addr; + + priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; + priv->ctrl_ram_size = pdata->ctrl_ram_size; + priv->emac_ctrl_ram = priv->remap_addr + pdata->ctrl_ram_offset; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(emac_dev, "DaVinci EMAC: Error getting irq res\n"); + rc = -ENOENT; + goto no_irq_res; + } + ndev->irq = res->start; + + if (!is_valid_ether_addr(priv->mac_addr)) { + DECLARE_MAC_BUF(buf); + /* Use random MAC if none passed */ + random_ether_addr(priv->mac_addr); + printk(KERN_WARNING "%s: using random MAC addr: %s\n", + __func__, print_mac(buf, priv->mac_addr)); + } + + ndev->netdev_ops = &emac_netdev_ops; + SET_ETHTOOL_OPS(ndev, ðtool_ops); + netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT); + + /* register the network device */ + SET_NETDEV_DEV(ndev, &pdev->dev); + rc = register_netdev(ndev); + if (rc) { + dev_err(emac_dev, "DaVinci EMAC: Error in register_netdev\n"); + rc = -ENODEV; + goto netdev_reg_err; + } + + clk_enable(emac_clk); + + /* MII/Phy intialisation, mdio bus registration */ + emac_mii = mdiobus_alloc(); + if (emac_mii == NULL) { + dev_err(emac_dev, "DaVinci EMAC: Error allocating mii_bus\n"); + rc = -ENOMEM; + goto mdio_alloc_err; + } + + priv->mii_bus = emac_mii; + emac_mii->name = "emac-mii", + emac_mii->read = emac_mii_read, + emac_mii->write = emac_mii_write, + emac_mii->reset = emac_mii_reset, + emac_mii->irq = mii_irqs, + emac_mii->phy_mask = ~(priv->phy_mask); + emac_mii->parent = &pdev->dev; + emac_mii->priv = priv->remap_addr + pdata->mdio_reg_offset; + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", priv->pdev->id); + mdio_max_freq = pdata->mdio_max_freq; + emac_mii->reset(emac_mii); + + /* Register the MII bus */ + rc = mdiobus_register(emac_mii); + if (rc) + goto mdiobus_quit; + + if (netif_msg_probe(priv)) { + dev_notice(emac_dev, "DaVinci EMAC Probe found device "\ + "(regs: %p, irq: %d)\n", + (void *)priv->emac_base_phys, ndev->irq); + } + return 0; + +mdiobus_quit: + mdiobus_free(emac_mii); + +netdev_reg_err: +mdio_alloc_err: +no_irq_res: + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + iounmap(priv->remap_addr); + +probe_quit: + clk_put(emac_clk); + free_netdev(ndev); + return rc; +} + +/** + * davinci_emac_remove: EMAC device remove + * @pdev: The DaVinci EMAC device that we are removing + * + * Called when removing the device driver. We disable clock usage and release + * the resources taken up by the driver and unregister network device + */ +static int __devexit davinci_emac_remove(struct platform_device *pdev) +{ + struct resource *res; + struct net_device *ndev = platform_get_drvdata(pdev); + struct emac_priv *priv = netdev_priv(ndev); + + dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n"); + + clk_disable(emac_clk); + platform_set_drvdata(pdev, NULL); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mdiobus_unregister(priv->mii_bus); + mdiobus_free(priv->mii_bus); + + release_mem_region(res->start, res->end - res->start + 1); + + unregister_netdev(ndev); + free_netdev(ndev); + iounmap(priv->remap_addr); + + clk_disable(emac_clk); + clk_put(emac_clk); + + return 0; +} + +/** + * davinci_emac_driver: EMAC platform driver structure + * + * We implement only probe and remove functions - suspend/resume and + * others not supported by this module + */ +static struct platform_driver davinci_emac_driver = { + .driver = { + .name = "davinci_emac", + .owner = THIS_MODULE, + }, + .probe = davinci_emac_probe, + .remove = __devexit_p(davinci_emac_remove), +}; + +/** + * davinci_emac_init: EMAC driver module init + * + * Called when initializing the driver. We register the driver with + * the platform. + */ +static int __init davinci_emac_init(void) +{ + return platform_driver_register(&davinci_emac_driver); +} +module_init(davinci_emac_init); + +/** + * davinci_emac_exit: EMAC driver module exit + * + * Called when exiting the driver completely. We unregister the driver with + * the platform and exit + */ +static void __exit davinci_emac_exit(void) +{ + platform_driver_unregister(&davinci_emac_driver); +} +module_exit(davinci_emac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("DaVinci EMAC Maintainer: Anant Gole "); +MODULE_AUTHOR("DaVinci EMAC Maintainer: Chaithrika U S "); +MODULE_DESCRIPTION("DaVinci EMAC Ethernet driver"); -- cgit v0.10.2 From e20dad964aeac229a204e298c563b6ea7ff1e987 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 15 May 2009 23:39:27 +0000 Subject: can: Documentation for the CAN device driver interface This patch documents the CAN netowrk device drivers interface, removes obsolete documentation and adds some useful links to CAN resources. Signed-off-by: Wolfgang Grandegger Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 2035bc4..6cd6627 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -36,10 +36,15 @@ This file contains 6.2 local loopback of sent frames 6.3 CAN controller hardware filters 6.4 The virtual CAN driver (vcan) - 6.5 currently supported CAN hardware - 6.6 todo + 6.5 The CAN network device driver interface + 6.5.1 Netlink interface to set/get devices properties + 6.5.2 Setting the CAN bit-timing + 6.5.3 Starting and stopping the CAN network device + 6.6 supported CAN hardware - 7 Credits + 7 Socket CAN resources + + 8 Credits ============================================================================ @@ -234,6 +239,8 @@ solution for a couple of reasons: the user application using the common CAN filter mechanisms. Inside this filter definition the (interested) type of errors may be selected. The reception of error frames is disabled by default. + The format of the CAN error frame is briefly decribed in the Linux + header file "include/linux/can/error.h". 4. How to use Socket CAN ------------------------ @@ -605,61 +612,213 @@ solution for a couple of reasons: removal of vcan network devices can be managed with the ip(8) tool: - Create a virtual CAN network interface: - ip link add type vcan + $ ip link add type vcan - Create a virtual CAN network interface with a specific name 'vcan42': - ip link add dev vcan42 type vcan + $ ip link add dev vcan42 type vcan - Remove a (virtual CAN) network interface 'vcan42': - ip link del vcan42 - - The tool 'vcan' from the SocketCAN SVN repository on BerliOS is obsolete. - - Virtual CAN network device creation in older Kernels: - In Linux Kernel versions < 2.6.24 the vcan driver creates 4 vcan - netdevices at module load time by default. This value can be changed - with the module parameter 'numdev'. E.g. 'modprobe vcan numdev=8' - - 6.5 currently supported CAN hardware + $ ip link del vcan42 + + 6.5 The CAN network device driver interface + + The CAN network device driver interface provides a generic interface + to setup, configure and monitor CAN network devices. The user can then + configure the CAN device, like setting the bit-timing parameters, via + the netlink interface using the program "ip" from the "IPROUTE2" + utility suite. The following chapter describes briefly how to use it. + Furthermore, the interface uses a common data structure and exports a + set of common functions, which all real CAN network device drivers + should use. Please have a look to the SJA1000 or MSCAN driver to + understand how to use them. The name of the module is can-dev.ko. + + 6.5.1 Netlink interface to set/get devices properties + + The CAN device must be configured via netlink interface. The supported + netlink message types are defined and briefly described in + "include/linux/can/netlink.h". CAN link support for the program "ip" + of the IPROUTE2 utility suite is avaiable and it can be used as shown + below: + + - Setting CAN device properties: + + $ ip link set can0 type can help + Usage: ip link set DEVICE type can + [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | + [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1 + phase-seg2 PHASE-SEG2 [ sjw SJW ] ] + + [ loopback { on | off } ] + [ listen-only { on | off } ] + [ triple-sampling { on | off } ] + + [ restart-ms TIME-MS ] + [ restart ] + + Where: BITRATE := { 1..1000000 } + SAMPLE-POINT := { 0.000..0.999 } + TQ := { NUMBER } + PROP-SEG := { 1..8 } + PHASE-SEG1 := { 1..8 } + PHASE-SEG2 := { 1..8 } + SJW := { 1..4 } + RESTART-MS := { 0 | NUMBER } + + - Display CAN device details and statistics: + + $ ip -details -statistics link show can0 + 2: can0: mtu 16 qdisc pfifo_fast state UP qlen 10 + link/can + can state ERROR-ACTIVE restart-ms 100 + bitrate 125000 sample_point 0.875 + tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1 + sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + clock 8000000 + re-started bus-errors arbit-lost error-warn error-pass bus-off + 41 17457 0 41 42 41 + RX: bytes packets errors dropped overrun mcast + 140859 17608 17457 0 0 0 + TX: bytes packets errors dropped carrier collsns + 861 112 0 41 0 0 + + More info to the above output: + + "" + Shows the list of selected CAN controller modes: LOOPBACK, + LISTEN-ONLY, or TRIPLE-SAMPLING. + + "state ERROR-ACTIVE" + The current state of the CAN controller: "ERROR-ACTIVE", + "ERROR-WARNING", "ERROR-PASSIVE", "BUS-OFF" or "STOPPED" + + "restart-ms 100" + Automatic restart delay time. If set to a non-zero value, a + restart of the CAN controller will be triggered automatically + in case of a bus-off condition after the specified delay time + in milliseconds. By default it's off. + + "bitrate 125000 sample_point 0.875" + Shows the real bit-rate in bits/sec and the sample-point in the + range 0.000..0.999. If the calculation of bit-timing parameters + is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the + bit-timing can be defined by setting the "bitrate" argument. + Optionally the "sample-point" can be specified. By default it's + 0.000 assuming CIA-recommended sample-points. + + "tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1" + Shows the time quanta in ns, propagation segment, phase buffer + segment 1 and 2 and the synchronisation jump width in units of + tq. They allow to define the CAN bit-timing in a hardware + independent format as proposed by the Bosch CAN 2.0 spec (see + chapter 8 of http://www.semiconductors.bosch.de/pdf/can2spec.pdf). + + "sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + clock 8000000" + Shows the bit-timing constants of the CAN controller, here the + "sja1000". The minimum and maximum values of the time segment 1 + and 2, the synchronisation jump width in units of tq, the + bitrate pre-scaler and the CAN system clock frequency in Hz. + These constants could be used for user-defined (non-standard) + bit-timing calculation algorithms in user-space. + + "re-started bus-errors arbit-lost error-warn error-pass bus-off" + Shows the number of restarts, bus and arbitration lost errors, + and the state changes to the error-warning, error-passive and + bus-off state. RX overrun errors are listed in the "overrun" + field of the standard network statistics. + + 6.5.2 Setting the CAN bit-timing + + The CAN bit-timing parameters can always be defined in a hardware + independent format as proposed in the Bosch CAN 2.0 specification + specifying the arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" + and "sjw": + + $ ip link set canX type can tq 125 prop-seg 6 \ + phase-seg1 7 phase-seg2 2 sjw 1 + + If the kernel option CONFIG_CAN_CALC_BITTIMING is enabled, CIA + recommended CAN bit-timing parameters will be calculated if the bit- + rate is specified with the argument "bitrate": + + $ ip link set canX type can bitrate 125000 + + Note that this works fine for the most common CAN controllers with + standard bit-rates but may *fail* for exotic bit-rates or CAN system + clock frequencies. Disabling CONFIG_CAN_CALC_BITTIMING saves some + space and allows user-space tools to solely determine and set the + bit-timing parameters. The CAN controller specific bit-timing + constants can be used for that purpose. They are listed by the + following command: + + $ ip -details link show can0 + ... + sja1000: clock 8000000 tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + + 6.5.3 Starting and stopping the CAN network device + + A CAN network device is started or stopped as usual with the command + "ifconfig canX up/down" or "ip link set canX up/down". Be aware that + you *must* define proper bit-timing parameters for real CAN devices + before you can start it to avoid error-prone default settings: + + $ ip link set canX up type can bitrate 125000 + + A device may enter the "bus-off" state if too much errors occurred on + the CAN bus. Then no more messages are received or sent. An automatic + bus-off recovery can be enabled by setting the "restart-ms" to a + non-zero value, e.g.: + + $ ip link set canX type can restart-ms 100 + + Alternatively, the application may realize the "bus-off" condition + by monitoring CAN error frames and do a restart when appropriate with + the command: + + $ ip link set canX type can restart + + Note that a restart will also create a CAN error frame (see also + chapter 3.4). - On the project website http://developer.berlios.de/projects/socketcan - there are different drivers available: + 6.6 Supported CAN hardware - vcan: Virtual CAN interface driver (if no real hardware is available) - sja1000: Philips SJA1000 CAN controller (recommended) - i82527: Intel i82527 CAN controller - mscan: Motorola/Freescale CAN controller (e.g. inside SOC MPC5200) - ccan: CCAN controller core (e.g. inside SOC h7202) - slcan: For a bunch of CAN adaptors that are attached via a - serial line ASCII protocol (for serial / USB adaptors) + Please check the "Kconfig" file in "drivers/net/can" to get an actual + list of the support CAN hardware. On the Socket CAN project website + (see chapter 7) there might be further drivers available, also for + older kernel versions. - Additionally the different CAN adaptors (ISA/PCI/PCMCIA/USB/Parport) - from PEAK Systemtechnik support the CAN netdevice driver model - since Linux driver v6.0: http://www.peak-system.com/linux/index.htm +7. Socket CAN resources +----------------------- - Please check the Mailing Lists on the berlios OSS project website. + You can find further resources for Socket CAN like user space tools, + support for old kernel versions, more drivers, mailing lists, etc. + at the BerliOS OSS project website for Socket CAN: - 6.6 todo + http://developer.berlios.de/projects/socketcan - The configuration interface for CAN network drivers is still an open - issue that has not been finalized in the socketcan project. Also the - idea of having a library module (candev.ko) that holds functions - that are needed by all CAN netdevices is not ready to ship. - Your contribution is welcome. + If you have questions, bug fixes, etc., don't hesitate to post them to + the Socketcan-Users mailing list. But please search the archives first. -7. Credits +8. Credits ---------- - Oliver Hartkopp (PF_CAN core, filters, drivers, bcm) + Oliver Hartkopp (PF_CAN core, filters, drivers, bcm, SJA1000 driver) Urs Thuermann (PF_CAN core, kernel integration, socket interfaces, raw, vcan) Jan Kizka (RT-SocketCAN core, Socket-API reconciliation) - Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews) + Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews, + CAN device driver interface, MSCAN driver) Robert Schwebel (design reviews, PTXdist integration) Marc Kleine-Budde (design reviews, Kernel 2.6 cleanups, drivers) Benedikt Spranger (reviews) Thomas Gleixner (LKML reviews, coding style, posting hints) - Andrey Volkov (kernel subtree structure, ioctls, mscan driver) + Andrey Volkov (kernel subtree structure, ioctls, MSCAN driver) Matthias Brukner (first SJA1000 CAN netdevice implementation Q2/2003) Klaus Hitschler (PEAK driver integration) Uwe Koppe (CAN netdevices with PF_PACKET approach) Michael Schulze (driver layer loopback requirement, RT CAN drivers review) + Pavel Pisa (Bit-timing calculation) + Sascha Hauer (SJA1000 platform driver) + Sebastian Haas (SJA1000 EMS PCI driver) + Markus Plessing (SJA1000 EMS PCI driver) + Per Dalen (SJA1000 Kvaser PCI driver) + Sam Ravnborg (reviews, coding style, kbuild help) -- cgit v0.10.2 From 4261a2043f1bed16f226c507ea37015090600c0f Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 15 May 2009 23:39:28 +0000 Subject: can: Update MAINTAINERS and CREDITS file Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/CREDITS b/CREDITS index 2520ba6..2b88fb3 100644 --- a/CREDITS +++ b/CREDITS @@ -1253,6 +1253,10 @@ S: 8124 Constitution Apt. 7 S: Sterling Heights, Michigan 48313 S: USA +N: Wolfgang Grandegger +E: wg@grandegger.com +D: Controller Area Network (device drivers) + N: William Greathouse E: wgreathouse@smva.com E: wgreathouse@myfavoritei.com diff --git a/MAINTAINERS b/MAINTAINERS index 3dfe1a7..b5160a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1278,6 +1278,13 @@ F: drivers/net/can/ F: include/linux/can/ F: include/linux/can.h +CAN NETWORK DRIVERS +P: Wolfgang Grandegger +M: wg@grandegger.com +L: socketcan-core@lists.berlios.de (subscribers-only) +W: http://developer.berlios.de/projects/socketcan/ +S: Maintained + CELL BROADBAND ENGINE ARCHITECTURE P: Arnd Bergmann M: arnd@arndb.de -- cgit v0.10.2 From 39549eef3587f1c1e8c65c88a2400d10fd30ea17 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 15 May 2009 23:39:29 +0000 Subject: can: CAN Network device driver and Netlink interface The CAN network device driver interface provides a generic interface to setup, configure and monitor CAN network devices. It exports a set of common data structures and functions, which all real CAN network device drivers should use. Please have a look to the SJA1000 or MSCAN driver to understand how to use them. The name of the module is can-dev.ko. Furthermore, it adds a Netlink interface allowing to configure the CAN device using the program "ip" from the iproute2 utility suite. For further information please check "Documentation/networking/can.txt" Signed-off-by: Wolfgang Grandegger Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 57def0d..77adb8e 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -12,6 +12,29 @@ config CAN_VCAN This driver can also be built as a module. If so, the module will be called vcan. +config CAN_DEV + tristate "Platform CAN drivers with Netlink support" + depends on CAN + default Y + ---help--- + Enables the common framework for platform CAN drivers with Netlink + support. This is the standard library for CAN drivers. + If unsure, say Y. + +config CAN_CALC_BITTIMING + bool "CAN bit-timing calculation" + depends on CAN_DEV + default Y + ---help--- + If enabled, CAN bit-timing parameters will be calculated for the + bit-rate specified via Netlink argument "bitrate" when the device + get started. This works fine for the most common CAN controllers + with standard bit-rates but may fail for exotic bit-rates or CAN + source clock frequencies. Disabling saves some space, but then the + bit-timing parameters must be specified directly using the Netlink + arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". + If unsure, say Y. + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" depends on CAN diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index c4bead7..6c86547 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -3,3 +3,8 @@ # obj-$(CONFIG_CAN_VCAN) += vcan.o + +obj-$(CONFIG_CAN_DEV) += can-dev.o +can-dev-y := dev.o + +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c new file mode 100644 index 0000000..52b0e7d --- /dev/null +++ b/drivers/net/can/dev.c @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2006 Andrey Volkov, Varma Electronics + * Copyright (C) 2008-2009 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MOD_DESC "CAN device driver interface" + +MODULE_DESCRIPTION(MOD_DESC); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Wolfgang Grandegger "); + +#ifdef CONFIG_CAN_CALC_BITTIMING +#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ + +/* + * Bit-timing calculation derived from: + * + * Code based on LinCAN sources and H8S2638 project + * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz + * Copyright 2005 Stanislav Marek + * email: pisa@cmp.felk.cvut.cz + * + * Calculates proper bit-timing parameters for a specified bit-rate + * and sample-point, which can then be used to set the bit-timing + * registers of the CAN controller. You can find more information + * in the header file linux/can/netlink.h. + */ +static int can_update_spt(const struct can_bittiming_const *btc, + int sampl_pt, int tseg, int *tseg1, int *tseg2) +{ + *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000; + if (*tseg2 < btc->tseg2_min) + *tseg2 = btc->tseg2_min; + if (*tseg2 > btc->tseg2_max) + *tseg2 = btc->tseg2_max; + *tseg1 = tseg - *tseg2; + if (*tseg1 > btc->tseg1_max) { + *tseg1 = btc->tseg1_max; + *tseg2 = tseg - *tseg1; + } + return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); +} + +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + struct can_priv *priv = netdev_priv(dev); + const struct can_bittiming_const *btc = priv->bittiming_const; + long rate, best_rate = 0; + long best_error = 1000000000, error = 0; + int best_tseg = 0, best_brp = 0, brp = 0; + int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0; + int spt_error = 1000, spt = 0, sampl_pt; + u64 v64; + + if (!priv->bittiming_const) + return -ENOTSUPP; + + /* Use CIA recommended sample points */ + if (bt->sample_point) { + sampl_pt = bt->sample_point; + } else { + if (bt->bitrate > 800000) + sampl_pt = 750; + else if (bt->bitrate > 500000) + sampl_pt = 800; + else + sampl_pt = 875; + } + + /* tseg even = round down, odd = round up */ + for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; + tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { + tsegall = 1 + tseg / 2; + /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ + brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; + /* chose brp step which is possible in system */ + brp = (brp / btc->brp_inc) * btc->brp_inc; + if ((brp < btc->brp_min) || (brp > btc->brp_max)) + continue; + rate = priv->clock.freq / (brp * tsegall); + error = bt->bitrate - rate; + /* tseg brp biterror */ + if (error < 0) + error = -error; + if (error > best_error) + continue; + best_error = error; + if (error == 0) { + spt = can_update_spt(btc, sampl_pt, tseg / 2, + &tseg1, &tseg2); + error = sampl_pt - spt; + if (error < 0) + error = -error; + if (error > spt_error) + continue; + spt_error = error; + } + best_tseg = tseg / 2; + best_brp = brp; + best_rate = rate; + if (error == 0) + break; + } + + if (best_error) { + /* Error in one-tenth of a percent */ + error = (best_error * 1000) / bt->bitrate; + if (error > CAN_CALC_MAX_ERROR) { + dev_err(dev->dev.parent, + "bitrate error %ld.%ld%% too high\n", + error / 10, error % 10); + return -EDOM; + } else { + dev_warn(dev->dev.parent, "bitrate error %ld.%ld%%\n", + error / 10, error % 10); + } + } + + /* real sample point */ + bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg, + &tseg1, &tseg2); + + v64 = (u64)best_brp * 1000000000UL; + do_div(v64, priv->clock.freq); + bt->tq = (u32)v64; + bt->prop_seg = tseg1 / 2; + bt->phase_seg1 = tseg1 - bt->prop_seg; + bt->phase_seg2 = tseg2; + bt->sjw = 1; + bt->brp = best_brp; + /* real bit-rate */ + bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1)); + + return 0; +} +#else /* !CONFIG_CAN_CALC_BITTIMING */ +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + dev_err(dev->dev.parent, "bit-timing calculation not available\n"); + return -EINVAL; +} +#endif /* CONFIG_CAN_CALC_BITTIMING */ + +/* + * Checks the validity of the specified bit-timing parameters prop_seg, + * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate + * prescaler value brp. You can find more information in the header + * file linux/can/netlink.h. + */ +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + struct can_priv *priv = netdev_priv(dev); + const struct can_bittiming_const *btc = priv->bittiming_const; + int tseg1, alltseg; + u64 brp64; + + if (!priv->bittiming_const) + return -ENOTSUPP; + + tseg1 = bt->prop_seg + bt->phase_seg1; + if (!bt->sjw) + bt->sjw = 1; + if (bt->sjw > btc->sjw_max || + tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || + bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) + return -ERANGE; + + brp64 = (u64)priv->clock.freq * (u64)bt->tq; + if (btc->brp_inc > 1) + do_div(brp64, btc->brp_inc); + brp64 += 500000000UL - 1; + do_div(brp64, 1000000000UL); /* the practicable BRP */ + if (btc->brp_inc > 1) + brp64 *= btc->brp_inc; + bt->brp = (u32)brp64; + + if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) + return -EINVAL; + + alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; + bt->bitrate = priv->clock.freq / (bt->brp * alltseg); + bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; + + return 0; +} + +int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + struct can_priv *priv = netdev_priv(dev); + int err; + + /* Check if the CAN device has bit-timing parameters */ + if (priv->bittiming_const) { + + /* Non-expert mode? Check if the bitrate has been pre-defined */ + if (!bt->tq) + /* Determine bit-timing parameters */ + err = can_calc_bittiming(dev, bt); + else + /* Check bit-timing params and calculate proper brp */ + err = can_fixup_bittiming(dev, bt); + if (err) + return err; + } + + return 0; +} + +/* + * Local echo of CAN messages + * + * CAN network devices *should* support a local echo functionality + * (see Documentation/networking/can.txt). To test the handling of CAN + * interfaces that do not support the local echo both driver types are + * implemented. In the case that the driver does not support the echo + * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core + * to perform the echo as a fallback solution. + */ +static void can_flush_echo_skb(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + int i; + + for (i = 0; i < CAN_ECHO_SKB_MAX; i++) { + if (priv->echo_skb[i]) { + kfree_skb(priv->echo_skb[i]); + priv->echo_skb[i] = NULL; + stats->tx_dropped++; + stats->tx_aborted_errors++; + } + } +} + +/* + * Put the skb on the stack to be looped backed locally lateron + * + * The function is typically called in the start_xmit function + * of the device driver. The driver must protect access to + * priv->echo_skb, if necessary. + */ +void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx) +{ + struct can_priv *priv = netdev_priv(dev); + + /* check flag whether this packet has to be looped back */ + if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { + kfree_skb(skb); + return; + } + + if (!priv->echo_skb[idx]) { + struct sock *srcsk = skb->sk; + + if (atomic_read(&skb->users) != 1) { + struct sk_buff *old_skb = skb; + + skb = skb_clone(old_skb, GFP_ATOMIC); + kfree_skb(old_skb); + if (!skb) + return; + } else + skb_orphan(skb); + + skb->sk = srcsk; + + /* make settings for echo to reduce code in irq context */ + skb->protocol = htons(ETH_P_CAN); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->dev = dev; + + /* save this skb for tx interrupt echo handling */ + priv->echo_skb[idx] = skb; + } else { + /* locking problem with netif_stop_queue() ?? */ + dev_err(dev->dev.parent, "%s: BUG! echo_skb is occupied!\n", + __func__); + kfree_skb(skb); + } +} +EXPORT_SYMBOL_GPL(can_put_echo_skb); + +/* + * Get the skb from the stack and loop it back locally + * + * The function is typically called when the TX done interrupt + * is handled in the device driver. The driver must protect + * access to priv->echo_skb, if necessary. + */ +void can_get_echo_skb(struct net_device *dev, int idx) +{ + struct can_priv *priv = netdev_priv(dev); + + if ((dev->flags & IFF_ECHO) && priv->echo_skb[idx]) { + netif_rx(priv->echo_skb[idx]); + priv->echo_skb[idx] = NULL; + } +} +EXPORT_SYMBOL_GPL(can_get_echo_skb); + +/* + * CAN device restart for bus-off recovery + */ +void can_restart(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct sk_buff *skb; + struct can_frame *cf; + int err; + + BUG_ON(netif_carrier_ok(dev)); + + /* + * No synchronization needed because the device is bus-off and + * no messages can come in or go out. + */ + can_flush_echo_skb(dev); + + /* send restart message upstream */ + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb == NULL) { + err = -ENOMEM; + goto out; + } + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0, sizeof(struct can_frame)); + cf->can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED; + cf->can_dlc = CAN_ERR_DLC; + + netif_rx(skb); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + dev_dbg(dev->dev.parent, "restarted\n"); + priv->can_stats.restarts++; + + /* Now restart the device */ + err = priv->do_set_mode(dev, CAN_MODE_START); + +out: + netif_carrier_on(dev); + if (err) + dev_err(dev->dev.parent, "Error %d during restart", err); +} + +int can_restart_now(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + /* + * A manual restart is only permitted if automatic restart is + * disabled and the device is in the bus-off state + */ + if (priv->restart_ms) + return -EINVAL; + if (priv->state != CAN_STATE_BUS_OFF) + return -EBUSY; + + /* Runs as soon as possible in the timer context */ + mod_timer(&priv->restart_timer, jiffies); + + return 0; +} + +/* + * CAN bus-off + * + * This functions should be called when the device goes bus-off to + * tell the netif layer that no more packets can be sent or received. + * If enabled, a timer is started to trigger bus-off recovery. + */ +void can_bus_off(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + dev_dbg(dev->dev.parent, "bus-off\n"); + + netif_carrier_off(dev); + priv->can_stats.bus_off++; + + if (priv->restart_ms) + mod_timer(&priv->restart_timer, + jiffies + (priv->restart_ms * HZ) / 1000); +} +EXPORT_SYMBOL_GPL(can_bus_off); + +static void can_setup(struct net_device *dev) +{ + dev->type = ARPHRD_CAN; + dev->mtu = sizeof(struct can_frame); + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 10; + + /* New-style flags. */ + dev->flags = IFF_NOARP; + dev->features = NETIF_F_NO_CSUM; +} + +/* + * Allocate and setup space for the CAN network device + */ +struct net_device *alloc_candev(int sizeof_priv) +{ + struct net_device *dev; + struct can_priv *priv; + + dev = alloc_netdev(sizeof_priv, "can%d", can_setup); + if (!dev) + return NULL; + + priv = netdev_priv(dev); + + priv->state = CAN_STATE_STOPPED; + + init_timer(&priv->restart_timer); + + return dev; +} +EXPORT_SYMBOL_GPL(alloc_candev); + +/* + * Free space of the CAN network device + */ +void free_candev(struct net_device *dev) +{ + free_netdev(dev); +} +EXPORT_SYMBOL_GPL(free_candev); + +/* + * Common open function when the device gets opened. + * + * This function should be called in the open function of the device + * driver. + */ +int open_candev(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + if (!priv->bittiming.tq && !priv->bittiming.bitrate) { + dev_err(dev->dev.parent, "bit-timing not yet defined\n"); + return -EINVAL; + } + + setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev); + + return 0; +} +EXPORT_SYMBOL(open_candev); + +/* + * Common close function for cleanup before the device gets closed. + * + * This function should be called in the close function of the device + * driver. + */ +void close_candev(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + if (del_timer_sync(&priv->restart_timer)) + dev_put(dev); + can_flush_echo_skb(dev); +} +EXPORT_SYMBOL_GPL(close_candev); + +/* + * CAN netlink interface + */ +static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { + [IFLA_CAN_STATE] = { .type = NLA_U32 }, + [IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) }, + [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 }, + [IFLA_CAN_RESTART] = { .type = NLA_U32 }, + [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) }, + [IFLA_CAN_BITTIMING_CONST] + = { .len = sizeof(struct can_bittiming_const) }, + [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, +}; + +static int can_changelink(struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct can_priv *priv = netdev_priv(dev); + int err; + + /* We need synchronization with dev->stop() */ + ASSERT_RTNL(); + + if (data[IFLA_CAN_CTRLMODE]) { + struct can_ctrlmode *cm; + + /* Do not allow changing controller mode while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + cm = nla_data(data[IFLA_CAN_CTRLMODE]); + priv->ctrlmode &= ~cm->mask; + priv->ctrlmode |= cm->flags; + } + + if (data[IFLA_CAN_BITTIMING]) { + struct can_bittiming bt; + + /* Do not allow changing bittiming while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); + if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq)) + return -EINVAL; + err = can_get_bittiming(dev, &bt); + if (err) + return err; + memcpy(&priv->bittiming, &bt, sizeof(bt)); + + if (priv->do_set_bittiming) { + /* Finally, set the bit-timing registers */ + err = priv->do_set_bittiming(dev); + if (err) + return err; + } + } + + if (data[IFLA_CAN_RESTART_MS]) { + /* Do not allow changing restart delay while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]); + } + + if (data[IFLA_CAN_RESTART]) { + /* Do not allow a restart while not running */ + if (!(dev->flags & IFF_UP)) + return -EINVAL; + err = can_restart_now(dev); + if (err) + return err; + } + + return 0; +} + +static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + struct can_ctrlmode cm = {.flags = priv->ctrlmode}; + enum can_state state = priv->state; + + if (priv->do_get_state) + priv->do_get_state(dev, &state); + NLA_PUT_U32(skb, IFLA_CAN_STATE, state); + NLA_PUT(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm); + NLA_PUT_U32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms); + NLA_PUT(skb, IFLA_CAN_BITTIMING, + sizeof(priv->bittiming), &priv->bittiming); + NLA_PUT(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock); + if (priv->bittiming_const) + NLA_PUT(skb, IFLA_CAN_BITTIMING_CONST, + sizeof(*priv->bittiming_const), priv->bittiming_const); + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + NLA_PUT(skb, IFLA_INFO_XSTATS, + sizeof(priv->can_stats), &priv->can_stats); + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static struct rtnl_link_ops can_link_ops __read_mostly = { + .kind = "can", + .maxtype = IFLA_CAN_MAX, + .policy = can_policy, + .setup = can_setup, + .changelink = can_changelink, + .fill_info = can_fill_info, + .fill_xstats = can_fill_xstats, +}; + +/* + * Register the CAN network device + */ +int register_candev(struct net_device *dev) +{ + dev->rtnl_link_ops = &can_link_ops; + return register_netdev(dev); +} +EXPORT_SYMBOL_GPL(register_candev); + +/* + * Unregister the CAN network device + */ +void unregister_candev(struct net_device *dev) +{ + unregister_netdev(dev); +} +EXPORT_SYMBOL_GPL(unregister_candev); + +static __init int can_dev_init(void) +{ + int err; + + err = rtnl_link_register(&can_link_ops); + if (!err) + printk(KERN_INFO MOD_DESC "\n"); + + return err; +} +module_init(can_dev_init); + +static __exit void can_dev_exit(void) +{ + rtnl_link_unregister(&can_link_ops); +} +module_exit(can_dev_exit); + +MODULE_ALIAS_RTNL_LINK("can"); diff --git a/include/linux/can/Kbuild b/include/linux/can/Kbuild index eff898a..8cb05aa 100644 --- a/include/linux/can/Kbuild +++ b/include/linux/can/Kbuild @@ -1,3 +1,4 @@ header-y += raw.h header-y += bcm.h header-y += error.h +header-y += netlink.h diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h new file mode 100644 index 0000000..4a37a56 --- /dev/null +++ b/include/linux/can/dev.h @@ -0,0 +1,70 @@ +/* + * linux/can/dev.h + * + * Definitions for the CAN network device driver interface + * + * Copyright (C) 2006 Andrey Volkov + * Varma Electronics Oy + * + * Copyright (C) 2008 Wolfgang Grandegger + * + * Send feedback to + */ + +#ifndef CAN_DEV_H +#define CAN_DEV_H + +#include +#include + +/* + * CAN mode + */ +enum can_mode { + CAN_MODE_STOP = 0, + CAN_MODE_START, + CAN_MODE_SLEEP +}; + +/* + * CAN common private data + */ +#define CAN_ECHO_SKB_MAX 4 + +struct can_priv { + struct can_device_stats can_stats; + + struct can_bittiming bittiming; + struct can_bittiming_const *bittiming_const; + struct can_clock clock; + + enum can_state state; + u32 ctrlmode; + + int restart_ms; + struct timer_list restart_timer; + + struct sk_buff *echo_skb[CAN_ECHO_SKB_MAX]; + + int (*do_set_bittiming)(struct net_device *dev); + int (*do_set_mode)(struct net_device *dev, enum can_mode mode); + int (*do_get_state)(const struct net_device *dev, + enum can_state *state); +}; + +struct net_device *alloc_candev(int sizeof_priv); +void free_candev(struct net_device *dev); + +int open_candev(struct net_device *dev); +void close_candev(struct net_device *dev); + +int register_candev(struct net_device *dev); +void unregister_candev(struct net_device *dev); + +int can_restart_now(struct net_device *dev); +void can_bus_off(struct net_device *dev); + +void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx); +void can_get_echo_skb(struct net_device *dev, int idx); + +#endif /* CAN_DEV_H */ diff --git a/include/linux/can/netlink.h b/include/linux/can/netlink.h new file mode 100644 index 0000000..9ecbb78 --- /dev/null +++ b/include/linux/can/netlink.h @@ -0,0 +1,113 @@ +/* + * linux/can/netlink.h + * + * Definitions for the CAN netlink interface + * + * Copyright (c) 2009 Wolfgang Grandegger + * + * Send feedback to + * + */ + +#ifndef CAN_NETLINK_H +#define CAN_NETLINK_H + +#include + +/* + * CAN bit-timing parameters + * + * For futher information, please read chapter "8 BIT TIMING + * REQUIREMENTS" of the "Bosch CAN Specification version 2.0" + * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf. + */ +struct can_bittiming { + __u32 bitrate; /* Bit-rate in bits/second */ + __u32 sample_point; /* Sample point in one-tenth of a percent */ + __u32 tq; /* Time quanta (TQ) in nanoseconds */ + __u32 prop_seg; /* Propagation segment in TQs */ + __u32 phase_seg1; /* Phase buffer segment 1 in TQs */ + __u32 phase_seg2; /* Phase buffer segment 2 in TQs */ + __u32 sjw; /* Synchronisation jump width in TQs */ + __u32 brp; /* Bit-rate prescaler */ +}; + +/* + * CAN harware-dependent bit-timing constant + * + * Used for calculating and checking bit-timing parameters + */ +struct can_bittiming_const { + char name[16]; /* Name of the CAN controller hardware */ + __u32 tseg1_min; /* Time segement 1 = prop_seg + phase_seg1 */ + __u32 tseg1_max; + __u32 tseg2_min; /* Time segement 2 = phase_seg2 */ + __u32 tseg2_max; + __u32 sjw_max; /* Synchronisation jump width */ + __u32 brp_min; /* Bit-rate prescaler */ + __u32 brp_max; + __u32 brp_inc; +}; + +/* + * CAN clock parameters + */ +struct can_clock { + __u32 freq; /* CAN system clock frequency in Hz */ +}; + +/* + * CAN operational and error states + */ +enum can_state { + CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */ + CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */ + CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */ + CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */ + CAN_STATE_STOPPED, /* Device is stopped */ + CAN_STATE_SLEEPING, /* Device is sleeping */ + CAN_STATE_MAX +}; + +/* + * CAN controller mode + */ +struct can_ctrlmode { + __u32 mask; + __u32 flags; +}; + +#define CAN_CTRLMODE_LOOPBACK 0x1 /* Loopback mode */ +#define CAN_CTRLMODE_LISTENONLY 0x2 /* Listen-only mode */ +#define CAN_CTRLMODE_3_SAMPLES 0x4 /* Triple sampling mode */ + +/* + * CAN device statistics + */ +struct can_device_stats { + __u32 bus_error; /* Bus errors */ + __u32 error_warning; /* Changes to error warning state */ + __u32 error_passive; /* Changes to error passive state */ + __u32 bus_off; /* Changes to bus off state */ + __u32 arbitration_lost; /* Arbitration lost errors */ + __u32 restarts; /* CAN controller re-starts */ +}; + +/* + * CAN netlink interface + */ +enum { + IFLA_CAN_UNSPEC, + IFLA_CAN_BITTIMING, + IFLA_CAN_BITTIMING_CONST, + IFLA_CAN_CLOCK, + IFLA_CAN_STATE, + IFLA_CAN_CTRLMODE, + IFLA_CAN_RESTART_MS, + IFLA_CAN_RESTART, + __IFLA_CAN_MAX +}; + +#define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1) + +#endif /* CAN_NETLINK_H */ -- cgit v0.10.2 From 429da1cc841bc9f2e762fd7272fc2b80314b890a Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 15 May 2009 23:39:30 +0000 Subject: can: Driver for the SJA1000 CAN controller This patch adds the generic Socket-CAN driver for the Philips SJA1000 full CAN controller. Signed-off-by: Wolfgang Grandegger Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 77adb8e..c7e5ce3 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -35,6 +35,12 @@ config CAN_CALC_BITTIMING arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". If unsure, say Y. +config CAN_SJA1000 + depends on CAN_DEV + tristate "Philips SJA1000" + ---help--- + Driver for the SJA1000 CAN controllers from Philips or NXP + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" depends on CAN diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 6c86547..523a941 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -7,4 +7,6 @@ obj-$(CONFIG_CAN_VCAN) += vcan.o obj-$(CONFIG_CAN_DEV) += can-dev.o can-dev-y := dev.o +obj-$(CONFIG_CAN_SJA1000) += sja1000/ + ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile new file mode 100644 index 0000000..893ab2c --- /dev/null +++ b/drivers/net/can/sja1000/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the SJA1000 CAN controller drivers. +# + +obj-$(CONFIG_CAN_SJA1000) += sja1000.o + +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c new file mode 100644 index 0000000..05b38dd --- /dev/null +++ b/drivers/net/can/sja1000/sja1000.c @@ -0,0 +1,637 @@ +/* + * sja1000.c - Philips SJA1000 network device driver + * + * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, + * 38106 Braunschweig, GERMANY + * + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000" + +MODULE_AUTHOR("Oliver Hartkopp "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION(DRV_NAME "CAN netdevice driver"); + +static struct can_bittiming_const sja1000_bittiming_const = { + .name = DRV_NAME, + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 64, + .brp_inc = 1, +}; + +static int sja1000_probe_chip(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + if (dev->base_addr && (priv->read_reg(dev, 0) == 0xFF)) { + printk(KERN_INFO "%s: probing @0x%lX failed\n", + DRV_NAME, dev->base_addr); + return 0; + } + return -1; +} + +static void set_reset_mode(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + unsigned char status = priv->read_reg(dev, REG_MOD); + int i; + + /* disable interrupts */ + priv->write_reg(dev, REG_IER, IRQ_OFF); + + for (i = 0; i < 100; i++) { + /* check reset bit */ + if (status & MOD_RM) { + priv->can.state = CAN_STATE_STOPPED; + return; + } + + priv->write_reg(dev, REG_MOD, MOD_RM); /* reset chip */ + udelay(10); + status = priv->read_reg(dev, REG_MOD); + } + + dev_err(dev->dev.parent, "setting SJA1000 into reset mode failed!\n"); +} + +static void set_normal_mode(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + unsigned char status = priv->read_reg(dev, REG_MOD); + int i; + + for (i = 0; i < 100; i++) { + /* check reset bit */ + if ((status & MOD_RM) == 0) { + priv->can.state = CAN_STATE_ERROR_ACTIVE; + /* enable all interrupts */ + priv->write_reg(dev, REG_IER, IRQ_ALL); + return; + } + + /* set chip to normal mode */ + priv->write_reg(dev, REG_MOD, 0x00); + udelay(10); + status = priv->read_reg(dev, REG_MOD); + } + + dev_err(dev->dev.parent, "setting SJA1000 into normal mode failed!\n"); +} + +static void sja1000_start(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + /* leave reset mode */ + if (priv->can.state != CAN_STATE_STOPPED) + set_reset_mode(dev); + + /* Clear error counters and error code capture */ + priv->write_reg(dev, REG_TXERR, 0x0); + priv->write_reg(dev, REG_RXERR, 0x0); + priv->read_reg(dev, REG_ECC); + + /* leave reset mode */ + set_normal_mode(dev); +} + +static int sja1000_set_mode(struct net_device *dev, enum can_mode mode) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + if (!priv->open_time) + return -EINVAL; + + switch (mode) { + case CAN_MODE_START: + sja1000_start(dev); + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int sja1000_set_bittiming(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct can_bittiming *bt = &priv->can.bittiming; + u8 btr0, btr1; + + btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); + btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | + (((bt->phase_seg2 - 1) & 0x7) << 4); + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + btr1 |= 0x80; + + dev_info(dev->dev.parent, + "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); + + priv->write_reg(dev, REG_BTR0, btr0); + priv->write_reg(dev, REG_BTR1, btr1); + + return 0; +} + +/* + * initialize SJA1000 chip: + * - reset chip + * - set output mode + * - set baudrate + * - enable interrupts + * - start operating mode + */ +static void chipset_init(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + /* set clock divider and output control register */ + priv->write_reg(dev, REG_CDR, priv->cdr | CDR_PELICAN); + + /* set acceptance filter (accept all) */ + priv->write_reg(dev, REG_ACCC0, 0x00); + priv->write_reg(dev, REG_ACCC1, 0x00); + priv->write_reg(dev, REG_ACCC2, 0x00); + priv->write_reg(dev, REG_ACCC3, 0x00); + + priv->write_reg(dev, REG_ACCM0, 0xFF); + priv->write_reg(dev, REG_ACCM1, 0xFF); + priv->write_reg(dev, REG_ACCM2, 0xFF); + priv->write_reg(dev, REG_ACCM3, 0xFF); + + priv->write_reg(dev, REG_OCR, priv->ocr | OCR_MODE_NORMAL); +} + +/* + * transmit a CAN message + * message layout in the sk_buff should be like this: + * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 + * [ can-id ] [flags] [len] [can data (up to 8 bytes] + */ +static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf = (struct can_frame *)skb->data; + uint8_t fi; + uint8_t dlc; + canid_t id; + uint8_t dreg; + int i; + + netif_stop_queue(dev); + + fi = dlc = cf->can_dlc; + id = cf->can_id; + + if (id & CAN_RTR_FLAG) + fi |= FI_RTR; + + if (id & CAN_EFF_FLAG) { + fi |= FI_FF; + dreg = EFF_BUF; + priv->write_reg(dev, REG_FI, fi); + priv->write_reg(dev, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); + priv->write_reg(dev, REG_ID2, (id & 0x001fe000) >> (5 + 8)); + priv->write_reg(dev, REG_ID3, (id & 0x00001fe0) >> 5); + priv->write_reg(dev, REG_ID4, (id & 0x0000001f) << 3); + } else { + dreg = SFF_BUF; + priv->write_reg(dev, REG_FI, fi); + priv->write_reg(dev, REG_ID1, (id & 0x000007f8) >> 3); + priv->write_reg(dev, REG_ID2, (id & 0x00000007) << 5); + } + + for (i = 0; i < dlc; i++) + priv->write_reg(dev, dreg++, cf->data[i]); + + stats->tx_bytes += dlc; + dev->trans_start = jiffies; + + can_put_echo_skb(skb, dev, 0); + + priv->write_reg(dev, REG_CMR, CMD_TR); + + return 0; +} + +static void sja1000_rx(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + uint8_t fi; + uint8_t dreg; + canid_t id; + uint8_t dlc; + int i; + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb == NULL) + return; + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + + fi = priv->read_reg(dev, REG_FI); + dlc = fi & 0x0F; + + if (fi & FI_FF) { + /* extended frame format (EFF) */ + dreg = EFF_BUF; + id = (priv->read_reg(dev, REG_ID1) << (5 + 16)) + | (priv->read_reg(dev, REG_ID2) << (5 + 8)) + | (priv->read_reg(dev, REG_ID3) << 5) + | (priv->read_reg(dev, REG_ID4) >> 3); + id |= CAN_EFF_FLAG; + } else { + /* standard frame format (SFF) */ + dreg = SFF_BUF; + id = (priv->read_reg(dev, REG_ID1) << 3) + | (priv->read_reg(dev, REG_ID2) >> 5); + } + + if (fi & FI_RTR) + id |= CAN_RTR_FLAG; + + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0, sizeof(struct can_frame)); + cf->can_id = id; + cf->can_dlc = dlc; + for (i = 0; i < dlc; i++) + cf->data[i] = priv->read_reg(dev, dreg++); + + while (i < 8) + cf->data[i++] = 0; + + /* release receive buffer */ + priv->write_reg(dev, REG_CMR, CMD_RRB); + + netif_rx(skb); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += dlc; +} + +static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + enum can_state state = priv->can.state; + uint8_t ecc, alc; + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb == NULL) + return -ENOMEM; + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0, sizeof(struct can_frame)); + cf->can_id = CAN_ERR_FLAG; + cf->can_dlc = CAN_ERR_DLC; + + if (isrc & IRQ_DOI) { + /* data overrun interrupt */ + dev_dbg(dev->dev.parent, "data overrun interrupt\n"); + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + stats->rx_over_errors++; + stats->rx_errors++; + priv->write_reg(dev, REG_CMR, CMD_CDO); /* clear bit */ + } + + if (isrc & IRQ_EI) { + /* error warning interrupt */ + dev_dbg(dev->dev.parent, "error warning interrupt\n"); + + if (status & SR_BS) { + state = CAN_STATE_BUS_OFF; + cf->can_id |= CAN_ERR_BUSOFF; + can_bus_off(dev); + } else if (status & SR_ES) { + state = CAN_STATE_ERROR_WARNING; + } else + state = CAN_STATE_ERROR_ACTIVE; + } + if (isrc & IRQ_BEI) { + /* bus error interrupt */ + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + ecc = priv->read_reg(dev, REG_ECC); + + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + switch (ecc & ECC_MASK) { + case ECC_BIT: + cf->data[2] |= CAN_ERR_PROT_BIT; + break; + case ECC_FORM: + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case ECC_STUFF: + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + default: + cf->data[2] |= CAN_ERR_PROT_UNSPEC; + cf->data[3] = ecc & ECC_SEG; + break; + } + /* Error occured during transmission? */ + if ((ecc & ECC_DIR) == 0) + cf->data[2] |= CAN_ERR_PROT_TX; + } + if (isrc & IRQ_EPI) { + /* error passive interrupt */ + dev_dbg(dev->dev.parent, "error passive interrupt\n"); + if (status & SR_ES) + state = CAN_STATE_ERROR_PASSIVE; + else + state = CAN_STATE_ERROR_ACTIVE; + } + if (isrc & IRQ_ALI) { + /* arbitration lost interrupt */ + dev_dbg(dev->dev.parent, "arbitration lost interrupt\n"); + alc = priv->read_reg(dev, REG_ALC); + priv->can.can_stats.arbitration_lost++; + stats->rx_errors++; + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = alc & 0x1f; + } + + if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || + state == CAN_STATE_ERROR_PASSIVE)) { + uint8_t rxerr = priv->read_reg(dev, REG_RXERR); + uint8_t txerr = priv->read_reg(dev, REG_TXERR); + cf->can_id |= CAN_ERR_CRTL; + if (state == CAN_STATE_ERROR_WARNING) { + priv->can.can_stats.error_warning++; + cf->data[1] = (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + } else { + priv->can.can_stats.error_passive++; + cf->data[1] = (txerr > rxerr) ? + CAN_ERR_CRTL_TX_PASSIVE : + CAN_ERR_CRTL_RX_PASSIVE; + } + } + + priv->can.state = state; + + netif_rx(skb); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + return 0; +} + +irqreturn_t sja1000_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + uint8_t isrc, status; + int n = 0; + + /* Shared interrupts and IRQ off? */ + if (priv->read_reg(dev, REG_IER) == IRQ_OFF) + return IRQ_NONE; + + if (priv->pre_irq) + priv->pre_irq(dev); + + while ((isrc = priv->read_reg(dev, REG_IR)) && (n < SJA1000_MAX_IRQ)) { + n++; + status = priv->read_reg(dev, REG_SR); + + if (isrc & IRQ_WUI) + dev_warn(dev->dev.parent, "wakeup interrupt\n"); + + if (isrc & IRQ_TI) { + /* transmission complete interrupt */ + stats->tx_packets++; + can_get_echo_skb(dev, 0); + netif_wake_queue(dev); + } + if (isrc & IRQ_RI) { + /* receive interrupt */ + while (status & SR_RBS) { + sja1000_rx(dev); + status = priv->read_reg(dev, REG_SR); + } + } + if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { + /* error interrupt */ + if (sja1000_err(dev, isrc, status)) + break; + } + } + + if (priv->post_irq) + priv->post_irq(dev); + + if (n >= SJA1000_MAX_IRQ) + dev_dbg(dev->dev.parent, "%d messages handled in ISR", n); + + return (n) ? IRQ_HANDLED : IRQ_NONE; +} +EXPORT_SYMBOL_GPL(sja1000_interrupt); + +static int sja1000_open(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + int err; + + /* set chip into reset mode */ + set_reset_mode(dev); + + /* common open */ + err = open_candev(dev); + if (err) + return err; + + /* register interrupt handler, if not done by the device driver */ + if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) { + err = request_irq(dev->irq, &sja1000_interrupt, priv->irq_flags, + dev->name, (void *)dev); + if (err) { + return -EAGAIN; + close_candev(dev); + } + } + + /* init and start chi */ + sja1000_start(dev); + priv->open_time = jiffies; + + netif_start_queue(dev); + + return 0; +} + +static int sja1000_close(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + netif_stop_queue(dev); + set_reset_mode(dev); + + if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) + free_irq(dev->irq, (void *)dev); + + close_candev(dev); + + priv->open_time = 0; + + return 0; +} + +struct net_device *alloc_sja1000dev(int sizeof_priv) +{ + struct net_device *dev; + struct sja1000_priv *priv; + + dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv); + if (!dev) + return NULL; + + priv = netdev_priv(dev); + + priv->dev = dev; + priv->can.bittiming_const = &sja1000_bittiming_const; + priv->can.do_set_bittiming = sja1000_set_bittiming; + priv->can.do_set_mode = sja1000_set_mode; + + if (sizeof_priv) + priv->priv = (void *)priv + sizeof(struct sja1000_priv); + + return dev; +} +EXPORT_SYMBOL_GPL(alloc_sja1000dev); + +void free_sja1000dev(struct net_device *dev) +{ + free_candev(dev); +} +EXPORT_SYMBOL_GPL(free_sja1000dev); + +static const struct net_device_ops sja1000_netdev_ops = { + .ndo_open = sja1000_open, + .ndo_stop = sja1000_close, + .ndo_start_xmit = sja1000_start_xmit, +}; + +int register_sja1000dev(struct net_device *dev) +{ + if (!sja1000_probe_chip(dev)) + return -ENODEV; + + dev->flags |= IFF_ECHO; /* we support local echo */ + dev->netdev_ops = &sja1000_netdev_ops; + + set_reset_mode(dev); + chipset_init(dev); + + return register_candev(dev); +} +EXPORT_SYMBOL_GPL(register_sja1000dev); + +void unregister_sja1000dev(struct net_device *dev) +{ + set_reset_mode(dev); + unregister_candev(dev); +} +EXPORT_SYMBOL_GPL(unregister_sja1000dev); + +static __init int sja1000_init(void) +{ + printk(KERN_INFO "%s CAN netdevice driver\n", DRV_NAME); + + return 0; +} + +module_init(sja1000_init); + +static __exit void sja1000_exit(void) +{ + printk(KERN_INFO "%s: driver removed\n", DRV_NAME); +} + +module_exit(sja1000_exit); diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h new file mode 100644 index 0000000..ccd3028 --- /dev/null +++ b/drivers/net/can/sja1000/sja1000.h @@ -0,0 +1,180 @@ +/* + * sja1000.h - Philips SJA1000 network device driver + * + * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, + * 38106 Braunschweig, GERMANY + * + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Send feedback to + * + */ + +#ifndef SJA1000_DEV_H +#define SJA1000_DEV_H + +#include +#include + +#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */ + +/* SJA1000 registers - manual section 6.4 (Pelican Mode) */ +#define REG_MOD 0x00 +#define REG_CMR 0x01 +#define REG_SR 0x02 +#define REG_IR 0x03 +#define REG_IER 0x04 +#define REG_ALC 0x0B +#define REG_ECC 0x0C +#define REG_EWL 0x0D +#define REG_RXERR 0x0E +#define REG_TXERR 0x0F +#define REG_ACCC0 0x10 +#define REG_ACCC1 0x11 +#define REG_ACCC2 0x12 +#define REG_ACCC3 0x13 +#define REG_ACCM0 0x14 +#define REG_ACCM1 0x15 +#define REG_ACCM2 0x16 +#define REG_ACCM3 0x17 +#define REG_RMC 0x1D +#define REG_RBSA 0x1E + +/* Common registers - manual section 6.5 */ +#define REG_BTR0 0x06 +#define REG_BTR1 0x07 +#define REG_OCR 0x08 +#define REG_CDR 0x1F + +#define REG_FI 0x10 +#define SFF_BUF 0x13 +#define EFF_BUF 0x15 + +#define FI_FF 0x80 +#define FI_RTR 0x40 + +#define REG_ID1 0x11 +#define REG_ID2 0x12 +#define REG_ID3 0x13 +#define REG_ID4 0x14 + +#define CAN_RAM 0x20 + +/* mode register */ +#define MOD_RM 0x01 +#define MOD_LOM 0x02 +#define MOD_STM 0x04 +#define MOD_AFM 0x08 +#define MOD_SM 0x10 + +/* commands */ +#define CMD_SRR 0x10 +#define CMD_CDO 0x08 +#define CMD_RRB 0x04 +#define CMD_AT 0x02 +#define CMD_TR 0x01 + +/* interrupt sources */ +#define IRQ_BEI 0x80 +#define IRQ_ALI 0x40 +#define IRQ_EPI 0x20 +#define IRQ_WUI 0x10 +#define IRQ_DOI 0x08 +#define IRQ_EI 0x04 +#define IRQ_TI 0x02 +#define IRQ_RI 0x01 +#define IRQ_ALL 0xFF +#define IRQ_OFF 0x00 + +/* status register content */ +#define SR_BS 0x80 +#define SR_ES 0x40 +#define SR_TS 0x20 +#define SR_RS 0x10 +#define SR_TCS 0x08 +#define SR_TBS 0x04 +#define SR_DOS 0x02 +#define SR_RBS 0x01 + +#define SR_CRIT (SR_BS|SR_ES) + +/* ECC register */ +#define ECC_SEG 0x1F +#define ECC_DIR 0x20 +#define ECC_ERR 6 +#define ECC_BIT 0x00 +#define ECC_FORM 0x40 +#define ECC_STUFF 0x80 +#define ECC_MASK 0xc0 + +/* + * Flags for sja1000priv.flags + */ +#define SJA1000_CUSTOM_IRQ_HANDLER 0x1 + +/* + * SJA1000 private data structure + */ +struct sja1000_priv { + struct can_priv can; /* must be the first member */ + int open_time; + struct sk_buff *echo_skb; + + /* the lower-layer is responsible for appropriate locking */ + u8 (*read_reg) (const struct net_device *dev, int reg); + void (*write_reg) (const struct net_device *dev, int reg, u8 val); + void (*pre_irq) (const struct net_device *dev); + void (*post_irq) (const struct net_device *dev); + + void *priv; /* for board-specific data */ + struct net_device *dev; + + unsigned long irq_flags; /* for request_irq() */ + + u16 flags; /* custom mode flags */ + u8 ocr; /* output control register */ + u8 cdr; /* clock divider register */ +}; + +struct net_device *alloc_sja1000dev(int sizeof_priv); +void free_sja1000dev(struct net_device *dev); +int register_sja1000dev(struct net_device *dev); +void unregister_sja1000dev(struct net_device *dev); + +irqreturn_t sja1000_interrupt(int irq, void *dev_id); + +#endif /* SJA1000_DEV_H */ -- cgit v0.10.2 From f534e52f091a7b9f51fb6726710bdf731b663e94 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 15 May 2009 23:39:31 +0000 Subject: can: SJA1000 generic platform bus driver This driver adds support for the SJA1000 chips connected to the "platform bus", which can be found on various embedded systems. Signed-off-by: Sascha Hauer Signed-off-by: Wolfgang Grandegger Signed-off-by: Marc Kleine-Budde Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index c7e5ce3..8fe7974 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -41,6 +41,16 @@ config CAN_SJA1000 ---help--- Driver for the SJA1000 CAN controllers from Philips or NXP +config CAN_SJA1000_PLATFORM + depends on CAN_SJA1000 + tristate "Generic Platform Bus based SJA1000 driver" + ---help--- + This driver adds support for the SJA1000 chips connected to + the "platform bus" (Linux abstraction for directly to the + processor attached devices). Which can be found on various + boards from Phytec (http://www.phytec.de) like the PCM027, + PCM038. + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" depends on CAN diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index 893ab2c..5115cc9 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -3,5 +3,6 @@ # obj-$(CONFIG_CAN_SJA1000) += sja1000.o +obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c new file mode 100644 index 0000000..8017229 --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2005 Sascha Hauer, Pengutronix + * Copyright (C) 2007 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000_platform" + +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); +MODULE_LICENSE("GPL v2"); + +static u8 sp_read_reg(const struct net_device *dev, int reg) +{ + return ioread8((void __iomem *)(dev->base_addr + reg)); +} + +static void sp_write_reg(const struct net_device *dev, int reg, u8 val) +{ + iowrite8(val, (void __iomem *)(dev->base_addr + reg)); +} + +static int sp_probe(struct platform_device *pdev) +{ + int err; + void __iomem *addr; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource *res_mem, *res_irq; + struct sja1000_platform_data *pdata; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "No platform data provided!\n"); + err = -ENODEV; + goto exit; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_mem || !res_irq) { + err = -ENODEV; + goto exit; + } + + if (!request_mem_region(res_mem->start, resource_size(res_mem), + DRV_NAME)) { + err = -EBUSY; + goto exit; + } + + addr = ioremap_nocache(res_mem->start, resource_size(res_mem)); + if (!addr) { + err = -ENOMEM; + goto exit_release; + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_iounmap; + } + priv = netdev_priv(dev); + + dev->base_addr = (unsigned long)addr; + dev->irq = res_irq->start; + priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + priv->read_reg = sp_read_reg; + priv->write_reg = sp_write_reg; + priv->can.clock.freq = pdata->clock; + priv->ocr = pdata->ocr; + priv->cdr = pdata->cdr; + + dev_set_drvdata(&pdev->dev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(&pdev->dev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_free; + } + + dev_info(&pdev->dev, "%s device registered (base_addr=%#lx, irq=%d)\n", + DRV_NAME, dev->base_addr, dev->irq); + return 0; + + exit_free: + free_sja1000dev(dev); + exit_iounmap: + iounmap(addr); + exit_release: + release_mem_region(res_mem->start, resource_size(res_mem)); + exit: + return err; +} + +static int sp_remove(struct platform_device *pdev) +{ + struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct resource *res; + + unregister_sja1000dev(dev); + dev_set_drvdata(&pdev->dev, NULL); + + if (dev->base_addr) + iounmap((void __iomem *)dev->base_addr); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + free_sja1000dev(dev); + + return 0; +} + +static struct platform_driver sp_driver = { + .probe = sp_probe, + .remove = sp_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init sp_init(void) +{ + return platform_driver_register(&sp_driver); +} + +static void __exit sp_exit(void) +{ + platform_driver_unregister(&sp_driver); +} + +module_init(sp_init); +module_exit(sp_exit); diff --git a/include/linux/can/platform/sja1000.h b/include/linux/can/platform/sja1000.h new file mode 100644 index 0000000..37966e6 --- /dev/null +++ b/include/linux/can/platform/sja1000.h @@ -0,0 +1,32 @@ +#ifndef _CAN_PLATFORM_SJA1000_H_ +#define _CAN_PLATFORM_SJA1000_H_ + +/* clock divider register */ +#define CDR_CLKOUT_MASK 0x07 +#define CDR_CLK_OFF 0x08 /* Clock off (CLKOUT pin) */ +#define CDR_RXINPEN 0x20 /* TX1 output is RX irq output */ +#define CDR_CBP 0x40 /* CAN input comparator bypass */ +#define CDR_PELICAN 0x80 /* PeliCAN mode */ + +/* output control register */ +#define OCR_MODE_BIPHASE 0x00 +#define OCR_MODE_TEST 0x01 +#define OCR_MODE_NORMAL 0x02 +#define OCR_MODE_CLOCK 0x03 +#define OCR_TX0_INVERT 0x04 +#define OCR_TX0_PULLDOWN 0x08 +#define OCR_TX0_PULLUP 0x10 +#define OCR_TX0_PUSHPULL 0x18 +#define OCR_TX1_INVERT 0x20 +#define OCR_TX1_PULLDOWN 0x40 +#define OCR_TX1_PULLUP 0x80 +#define OCR_TX1_PUSHPULL 0xc0 + +struct sja1000_platform_data { + u32 clock; /* CAN bus oscillator frequency in Hz */ + + u8 ocr; /* output control register */ + u8 cdr; /* clock divider register */ +}; + +#endif /* !_CAN_PLATFORM_SJA1000_H_ */ -- cgit v0.10.2 From a61a8423c71d6da6f1f6f854d8adcea24b80bef6 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 15 May 2009 23:39:32 +0000 Subject: can: SJA1000 driver for EMS PCI cards The patch adds support for the one or two channel CPC-PCI and CPC-PCIe cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). Signed-off-by: Sebastian Haas Signed-off-by: Markus Plessing Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 8fe7974..f1684cd 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -51,6 +51,13 @@ config CAN_SJA1000_PLATFORM boards from Phytec (http://www.phytec.de) like the PCM027, PCM038. +config CAN_EMS_PCI + tristate "EMS CPC-PCI and CPC-PCIe Card" + depends on PCI && CAN_SJA1000 + ---help--- + This driver is for the one or two channel CPC-PCI and CPC-PCIe + cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" depends on CAN diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index 5115cc9..7772dd2 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o +obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c new file mode 100644 index 0000000..3cd2ff9 --- /dev/null +++ b/drivers/net/can/sja1000/ems_pci.c @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2007 Wolfgang Grandegger + * Copyright (C) 2008 Markus Plessing + * Copyright (C) 2008 Sebastian Haas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "ems_pci" + +MODULE_AUTHOR("Sebastian Haas "); +MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards"); +MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card"); +MODULE_LICENSE("GPL v2"); + +#define EMS_PCI_MAX_CHAN 2 + +struct ems_pci_card { + int channels; + + struct pci_dev *pci_dev; + struct net_device *net_dev[EMS_PCI_MAX_CHAN]; + + void __iomem *conf_addr; + void __iomem *base_addr; +}; + +#define EMS_PCI_CAN_CLOCK (16000000 / 2) + +/* + * Register definitions and descriptions are from LinCAN 0.3.3. + * + * PSB4610 PITA-2 bridge control registers + */ +#define PITA2_ICR 0x00 /* Interrupt Control Register */ +#define PITA2_ICR_INT0 0x00000002 /* [RC] INT0 Active/Clear */ +#define PITA2_ICR_INT0_EN 0x00020000 /* [RW] Enable INT0 */ + +#define PITA2_MISC 0x1c /* Miscellaneous Register */ +#define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */ + +/* + * The board configuration is probably following: + * RX1 is connected to ground. + * TX1 is not connected. + * CLKO is not connected. + * Setting the OCR register to 0xDA is a good idea. + * This means normal output mode , push-pull and the correct polarity. + */ +#define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) + +/* + * In the CDR register, you should set CBP to 1. + * You will probably also want to set the clock divider value to 7 + * (meaning direct oscillator output) because the second SJA1000 chip + * is driven by the first one CLKOUT output. + */ +#define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) +#define EMS_PCI_MEM_SIZE 4096 /* Size of the remapped io-memory */ +#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */ +#define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */ + +#define EMS_PCI_PORT_BYTES 0x4 /* Each register occupies 4 bytes */ + +#define EMS_PCI_VENDOR_ID 0x110a /* PCI device and vendor ID */ +#define EMS_PCI_DEVICE_ID 0x2104 + +static struct pci_device_id ems_pci_tbl[] = { + {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, ems_pci_tbl); + +/* + * Helper to read internal registers from card logic (not CAN) + */ +static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port) +{ + return readb((void __iomem *)card->base_addr + + (port * EMS_PCI_PORT_BYTES)); +} + +static u8 ems_pci_read_reg(const struct net_device *dev, int port) +{ + return readb((void __iomem *)dev->base_addr + + (port * EMS_PCI_PORT_BYTES)); +} + +static void ems_pci_write_reg(const struct net_device *dev, int port, u8 val) +{ + writeb(val, (void __iomem *)dev->base_addr + + (port * EMS_PCI_PORT_BYTES)); +} + +static void ems_pci_post_irq(const struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; + + /* reset int flag of pita */ + writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr + + PITA2_ICR); +} + +/* + * Check if a CAN controller is present at the specified location + * by trying to set 'em into the PeliCAN mode + */ +static inline int ems_pci_check_chan(struct net_device *dev) +{ + unsigned char res; + + /* Make sure SJA1000 is in reset mode */ + ems_pci_write_reg(dev, REG_MOD, 1); + + ems_pci_write_reg(dev, REG_CDR, CDR_PELICAN); + + /* read reset-values */ + res = ems_pci_read_reg(dev, REG_CDR); + + if (res == CDR_PELICAN) + return 1; + + return 0; +} + +static void ems_pci_del_card(struct pci_dev *pdev) +{ + struct ems_pci_card *card = pci_get_drvdata(pdev); + struct net_device *dev; + int i = 0; + + for (i = 0; i < card->channels; i++) { + dev = card->net_dev[i]; + + if (!dev) + continue; + + dev_info(&pdev->dev, "Removing %s.\n", dev->name); + unregister_sja1000dev(dev); + free_sja1000dev(dev); + } + + if (card->base_addr != NULL) + pci_iounmap(card->pci_dev, card->base_addr); + + if (card->conf_addr != NULL) + pci_iounmap(card->pci_dev, card->conf_addr); + + kfree(card); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static void ems_pci_card_reset(struct ems_pci_card *card) +{ + /* Request board reset */ + writeb(0, card->base_addr); +} + +/* + * Probe PCI device for EMS CAN signature and register each available + * CAN channel to SJA1000 Socket-CAN subsystem. + */ +static int __devinit ems_pci_add_card(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct sja1000_priv *priv; + struct net_device *dev; + struct ems_pci_card *card; + int err, i; + + /* Enabling PCI device */ + if (pci_enable_device(pdev) < 0) { + dev_err(&pdev->dev, "Enabling PCI device failed\n"); + return -ENODEV; + } + + /* Allocating card structures to hold addresses, ... */ + card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL); + if (card == NULL) { + dev_err(&pdev->dev, "Unable to allocate memory\n"); + pci_disable_device(pdev); + return -ENOMEM; + } + + pci_set_drvdata(pdev, card); + + card->pci_dev = pdev; + + card->channels = 0; + + /* Remap PITA configuration space, and controller memory area */ + card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE); + if (card->conf_addr == NULL) { + err = -ENOMEM; + + goto failure_cleanup; + } + + card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE); + if (card->base_addr == NULL) { + err = -ENOMEM; + + goto failure_cleanup; + } + + /* Configure PITA-2 parallel interface (enable MUX) */ + writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC); + + /* Check for unique EMS CAN signature */ + if (ems_pci_readb(card, 0) != 0x55 || + ems_pci_readb(card, 1) != 0xAA || + ems_pci_readb(card, 2) != 0x01 || + ems_pci_readb(card, 3) != 0xCB || + ems_pci_readb(card, 4) != 0x11) { + dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n"); + + err = -ENODEV; + goto failure_cleanup; + } + + ems_pci_card_reset(card); + + /* Detect available channels */ + for (i = 0; i < EMS_PCI_MAX_CHAN; i++) { + dev = alloc_sja1000dev(0); + if (dev == NULL) { + err = -ENOMEM; + goto failure_cleanup; + } + + card->net_dev[i] = dev; + priv = netdev_priv(dev); + priv->priv = card; + priv->irq_flags = IRQF_SHARED; + + dev->irq = pdev->irq; + dev->base_addr = (unsigned long)(card->base_addr + + EMS_PCI_CAN_BASE_OFFSET + + (i * EMS_PCI_CAN_CTRL_SIZE)); + + /* Check if channel is present */ + if (ems_pci_check_chan(dev)) { + priv->read_reg = ems_pci_read_reg; + priv->write_reg = ems_pci_write_reg; + priv->post_irq = ems_pci_post_irq; + priv->can.clock.freq = EMS_PCI_CAN_CLOCK; + priv->ocr = EMS_PCI_OCR; + priv->cdr = EMS_PCI_CDR; + + SET_NETDEV_DEV(dev, &pdev->dev); + + /* Enable interrupts from card */ + writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR); + + /* Register SJA1000 device */ + err = register_sja1000dev(dev); + if (err) { + dev_err(&pdev->dev, "Registering device failed " + "(err=%d)\n", err); + free_sja1000dev(dev); + goto failure_cleanup; + } + + card->channels++; + + dev_info(&pdev->dev, "Channel #%d at %#lX, irq %d\n", + i + 1, dev->base_addr, + dev->irq); + } else { + free_sja1000dev(dev); + } + } + + return 0; + +failure_cleanup: + dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err); + + ems_pci_del_card(pdev); + + return err; +} + +static struct pci_driver ems_pci_driver = { + .name = DRV_NAME, + .id_table = ems_pci_tbl, + .probe = ems_pci_add_card, + .remove = ems_pci_del_card, +}; + +static int __init ems_pci_init(void) +{ + return pci_register_driver(&ems_pci_driver); +} + +static void __exit ems_pci_exit(void) +{ + pci_unregister_driver(&ems_pci_driver); +} + +module_init(ems_pci_init); +module_exit(ems_pci_exit); + -- cgit v0.10.2 From 3878fb6fdbceecca20b15748f807340854220f06 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Fri, 15 May 2009 23:39:33 +0000 Subject: The patch adds support for the PCI cards: PCIcan and PCIcanx (1, 2 or 4 channel) from Kvaser (http://www.kvaser.com). Signed-off-by: Per Dalen Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index f1684cd..cfd6c5a 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -58,6 +58,13 @@ config CAN_EMS_PCI This driver is for the one or two channel CPC-PCI and CPC-PCIe cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). +config CAN_KVASER_PCI + tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards" + depends on PCI && CAN_SJA1000 + ---help--- + This driver is for the the PCIcanx and PCIcan cards (1, 2 or + 4 channel) from Kvaser (http://www.kvaser.com). + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" depends on CAN diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index 7772dd2..d6c631f 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o +obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c new file mode 100644 index 0000000..00830b3 --- /dev/null +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2008 Per Dalen + * + * Parts of this software are based on (derived) the following: + * + * - Kvaser linux driver, version 4.72 BETA + * Copyright (C) 2002-2007 KVASER AB + * + * - Lincan driver, version 0.3.3, OCERA project + * Copyright (C) 2004 Pavel Pisa + * Copyright (C) 2001 Arnaud Westenberg + * + * - Socketcan SJA1000 drivers + * Copyright (C) 2007 Wolfgang Grandegger + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, + * 38106 Braunschweig, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "kvaser_pci" + +MODULE_AUTHOR("Per Dalen "); +MODULE_DESCRIPTION("Socket-CAN driver for KVASER PCAN PCI cards"); +MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card"); +MODULE_LICENSE("GPL v2"); + +#define MAX_NO_OF_CHANNELS 4 /* max no of channels on a single card */ + +struct kvaser_pci { + int channel; + struct pci_dev *pci_dev; + struct net_device *slave_dev[MAX_NO_OF_CHANNELS-1]; + void __iomem *conf_addr; + void __iomem *res_addr; + int no_channels; + u8 xilinx_ver; +}; + +#define KVASER_PCI_CAN_CLOCK (16000000 / 2) + +/* + * The board configuration is probably following: + * RX1 is connected to ground. + * TX1 is not connected. + * CLKO is not connected. + * Setting the OCR register to 0xDA is a good idea. + * This means normal output mode , push-pull and the correct polarity. + */ +#define KVASER_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) + +/* + * In the CDR register, you should set CBP to 1. + * You will probably also want to set the clock divider value to 0 + * (meaning divide-by-2), the Pelican bit, and the clock-off bit + * (you will have no need for CLKOUT anyway). + */ +#define KVASER_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) + +/* + * These register values are valid for revision 14 of the Xilinx logic. + */ +#define XILINX_VERINT 7 /* Lower nibble simulate interrupts, + high nibble version number. */ + +#define XILINX_PRESUMED_VERSION 14 + +/* + * Important S5920 registers + */ +#define S5920_INTCSR 0x38 +#define S5920_PTCR 0x60 +#define INTCSR_ADDON_INTENABLE_M 0x2000 + + +#define KVASER_PCI_PORT_BYTES 0x20 + +#define PCI_CONFIG_PORT_SIZE 0x80 /* size of the config io-memory */ +#define PCI_PORT_SIZE 0x80 /* size of a channel io-memory */ +#define PCI_PORT_XILINX_SIZE 0x08 /* size of a xilinx io-memory */ + +#define KVASER_PCI_VENDOR_ID1 0x10e8 /* the PCI device and vendor IDs */ +#define KVASER_PCI_DEVICE_ID1 0x8406 + +#define KVASER_PCI_VENDOR_ID2 0x1a07 /* the PCI device and vendor IDs */ +#define KVASER_PCI_DEVICE_ID2 0x0008 + +static struct pci_device_id kvaser_pci_tbl[] = { + {KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,}, + {KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,}, + { 0,} +}; + +MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl); + +static u8 kvaser_pci_read_reg(const struct net_device *dev, int port) +{ + return ioread8((void __iomem *)(dev->base_addr + port)); +} + +static void kvaser_pci_write_reg(const struct net_device *dev, int port, u8 val) +{ + iowrite8(val, (void __iomem *)(dev->base_addr + port)); +} + +static void kvaser_pci_disable_irq(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct kvaser_pci *board = priv->priv; + u32 intcsr; + + /* Disable interrupts from card */ + intcsr = ioread32(board->conf_addr + S5920_INTCSR); + intcsr &= ~INTCSR_ADDON_INTENABLE_M; + iowrite32(intcsr, board->conf_addr + S5920_INTCSR); +} + +static void kvaser_pci_enable_irq(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct kvaser_pci *board = priv->priv; + u32 tmp_en_io; + + /* Enable interrupts from card */ + tmp_en_io = ioread32(board->conf_addr + S5920_INTCSR); + tmp_en_io |= INTCSR_ADDON_INTENABLE_M; + iowrite32(tmp_en_io, board->conf_addr + S5920_INTCSR); +} + +static int number_of_sja1000_chip(void __iomem *base_addr) +{ + u8 status; + int i; + + for (i = 0; i < MAX_NO_OF_CHANNELS; i++) { + /* reset chip */ + iowrite8(MOD_RM, base_addr + + (i * KVASER_PCI_PORT_BYTES) + REG_MOD); + status = ioread8(base_addr + + (i * KVASER_PCI_PORT_BYTES) + REG_MOD); + /* check reset bit */ + if (!(status & MOD_RM)) + break; + } + + return i; +} + +static void kvaser_pci_del_chan(struct net_device *dev) +{ + struct sja1000_priv *priv; + struct kvaser_pci *board; + int i; + + if (!dev) + return; + priv = netdev_priv(dev); + board = priv->priv; + if (!board) + return; + + dev_info(&board->pci_dev->dev, "Removing device %s\n", + dev->name); + + /* Disable PCI interrupts */ + kvaser_pci_disable_irq(dev); + + for (i = 0; i < board->no_channels - 1; i++) { + if (board->slave_dev[i]) { + dev_info(&board->pci_dev->dev, "Removing device %s\n", + board->slave_dev[i]->name); + unregister_sja1000dev(board->slave_dev[i]); + free_sja1000dev(board->slave_dev[i]); + } + } + unregister_sja1000dev(dev); + + pci_iounmap(board->pci_dev, (void __iomem *)dev->base_addr); + pci_iounmap(board->pci_dev, board->conf_addr); + pci_iounmap(board->pci_dev, board->res_addr); + + free_sja1000dev(dev); +} + +static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, + struct net_device **master_dev, + void __iomem *conf_addr, + void __iomem *res_addr, + unsigned long base_addr) +{ + struct net_device *dev; + struct sja1000_priv *priv; + struct kvaser_pci *board; + int err, init_step; + + dev = alloc_sja1000dev(sizeof(struct kvaser_pci)); + if (dev == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + board = priv->priv; + + board->pci_dev = pdev; + board->channel = channel; + + /* S5920 */ + board->conf_addr = conf_addr; + + /* XILINX board wide address */ + board->res_addr = res_addr; + + if (channel == 0) { + board->xilinx_ver = + ioread8(board->res_addr + XILINX_VERINT) >> 4; + init_step = 2; + + /* Assert PTADR# - we're in passive mode so the other bits are + not important */ + iowrite32(0x80808080UL, board->conf_addr + S5920_PTCR); + + /* Enable interrupts from card */ + kvaser_pci_enable_irq(dev); + } else { + struct sja1000_priv *master_priv = netdev_priv(*master_dev); + struct kvaser_pci *master_board = master_priv->priv; + master_board->slave_dev[channel - 1] = dev; + master_board->no_channels = channel + 1; + board->xilinx_ver = master_board->xilinx_ver; + } + + dev->base_addr = base_addr + channel * KVASER_PCI_PORT_BYTES; + + priv->read_reg = kvaser_pci_read_reg; + priv->write_reg = kvaser_pci_write_reg; + + priv->can.clock.freq = KVASER_PCI_CAN_CLOCK; + + priv->ocr = KVASER_PCI_OCR; + priv->cdr = KVASER_PCI_CDR; + + priv->irq_flags = IRQF_SHARED; + dev->irq = pdev->irq; + + init_step = 4; + + dev_info(&pdev->dev, "base_addr=%#lx conf_addr=%p irq=%d\n", + dev->base_addr, board->conf_addr, dev->irq); + + SET_NETDEV_DEV(dev, &pdev->dev); + + /* Register SJA1000 device */ + err = register_sja1000dev(dev); + if (err) { + dev_err(&pdev->dev, "Registering device failed (err=%d)\n", + err); + goto failure; + } + + if (channel == 0) + *master_dev = dev; + + return 0; + +failure: + kvaser_pci_del_chan(dev); + return err; +} + +static int __devinit kvaser_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct net_device *master_dev = NULL; + struct sja1000_priv *priv; + struct kvaser_pci *board; + int no_channels; + void __iomem *base_addr = NULL; + void __iomem *conf_addr = NULL; + void __iomem *res_addr = NULL; + int i; + + dev_info(&pdev->dev, "initializing device %04x:%04x\n", + pdev->vendor, pdev->device); + + err = pci_enable_device(pdev); + if (err) + goto failure; + + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto failure_release_pci; + + /* S5920 */ + conf_addr = pci_iomap(pdev, 0, PCI_CONFIG_PORT_SIZE); + if (conf_addr == NULL) { + err = -ENODEV; + goto failure_release_regions; + } + + /* XILINX board wide address */ + res_addr = pci_iomap(pdev, 2, PCI_PORT_XILINX_SIZE); + if (res_addr == NULL) { + err = -ENOMEM; + goto failure_iounmap; + } + + base_addr = pci_iomap(pdev, 1, PCI_PORT_SIZE); + if (base_addr == NULL) { + err = -ENOMEM; + goto failure_iounmap; + } + + no_channels = number_of_sja1000_chip(base_addr); + if (no_channels == 0) { + err = -ENOMEM; + goto failure_iounmap; + } + + for (i = 0; i < no_channels; i++) { + err = kvaser_pci_add_chan(pdev, i, &master_dev, + conf_addr, res_addr, + (unsigned long)base_addr); + if (err) + goto failure_cleanup; + } + + priv = netdev_priv(master_dev); + board = priv->priv; + + dev_info(&pdev->dev, "xilinx version=%d number of channels=%d\n", + board->xilinx_ver, board->no_channels); + + pci_set_drvdata(pdev, master_dev); + return 0; + +failure_cleanup: + kvaser_pci_del_chan(master_dev); + +failure_iounmap: + if (conf_addr != NULL) + pci_iounmap(pdev, conf_addr); + if (res_addr != NULL) + pci_iounmap(pdev, res_addr); + if (base_addr != NULL) + pci_iounmap(pdev, base_addr); + +failure_release_regions: + pci_release_regions(pdev); + +failure_release_pci: + pci_disable_device(pdev); + +failure: + return err; + +} + +static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + kvaser_pci_del_chan(dev); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static struct pci_driver kvaser_pci_driver = { + .name = DRV_NAME, + .id_table = kvaser_pci_tbl, + .probe = kvaser_pci_init_one, + .remove = __devexit_p(kvaser_pci_remove_one), +}; + +static int __init kvaser_pci_init(void) +{ + return pci_register_driver(&kvaser_pci_driver); +} + +static void __exit kvaser_pci_exit(void) +{ + pci_unregister_driver(&kvaser_pci_driver); +} + +module_init(kvaser_pci_init); +module_exit(kvaser_pci_exit); -- cgit v0.10.2 From f67f34084914144de55c785163d047d5d8dddd2d Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 18 May 2009 21:46:40 -0700 Subject: netxen: fix msi irq setup The pdev->irq was not saved in netxen_adapter, causing request_irq() with invalid irq number. This was broken in commit be339aee634d5cb98a8df8d6febe04002ec497f3 ("netxen: fix irq tear down and msix leak."). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 86ca081..50477f5 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -539,6 +539,7 @@ netxen_setup_intr(struct netxen_adapter *adapter) adapter->msi_tgt_status = msi_tgt_status[adapter->ahw.pci_func]; dev_info(&pdev->dev, "using msi interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; return; } -- cgit v0.10.2 From 69e3c75f4d541a6eb151b3ef91f34033cb3ad6e1 Mon Sep 17 00:00:00 2001 From: Johann Baudy Date: Mon, 18 May 2009 22:11:22 -0700 Subject: net: TX_RING and packet mmap New packet socket feature that makes packet socket more efficient for transmission. - It reduces number of system call through a PACKET_TX_RING mechanism, based on PACKET_RX_RING (Circular buffer allocated in kernel space which is mmapped from user space). - It minimizes CPU copy using fragmented SKB (almost zero copy). Signed-off-by: Johann Baudy Signed-off-by: David S. Miller diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 07c53d5..a22fd85 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -4,16 +4,18 @@ This file documents the CONFIG_PACKET_MMAP option available with the PACKET socket interface on 2.4 and 2.6 kernels. This type of sockets is used for -capture network traffic with utilities like tcpdump or any other that uses -the libpcap library. - -You can find the latest version of this document at +capture network traffic with utilities like tcpdump or any other that needs +raw access to network interface. +You can find the latest version of this document at: http://pusa.uv.es/~ulisses/packet_mmap/ -Please send me your comments to +Howto can be found at: + http://wiki.gnu-log.net (packet_mmap) +Please send your comments to Ulisses Alonso Camaró + Johann Baudy ------------------------------------------------------------------------------- + Why use PACKET_MMAP @@ -25,19 +27,24 @@ to capture each packet, it requires two if you want to get packet's timestamp (like libpcap always does). In the other hand PACKET_MMAP is very efficient. PACKET_MMAP provides a size -configurable circular buffer mapped in user space. This way reading packets just -needs to wait for them, most of the time there is no need to issue a single -system call. By using a shared buffer between the kernel and the user -also has the benefit of minimizing packet copies. - -It's fine to use PACKET_MMAP to improve the performance of the capture process, -but it isn't everything. At least, if you are capturing at high speeds (this -is relative to the cpu speed), you should check if the device driver of your -network interface card supports some sort of interrupt load mitigation or -(even better) if it supports NAPI, also make sure it is enabled. +configurable circular buffer mapped in user space that can be used to either +send or receive packets. This way reading packets just needs to wait for them, +most of the time there is no need to issue a single system call. Concerning +transmission, multiple packets can be sent through one system call to get the +highest bandwidth. +By using a shared buffer between the kernel and the user also has the benefit +of minimizing packet copies. + +It's fine to use PACKET_MMAP to improve the performance of the capture and +transmission process, but it isn't everything. At least, if you are capturing +at high speeds (this is relative to the cpu speed), you should check if the +device driver of your network interface card supports some sort of interrupt +load mitigation or (even better) if it supports NAPI, also make sure it is +enabled. For transmission, check the MTU (Maximum Transmission Unit) used and +supported by devices of your network. -------------------------------------------------------------------------------- -+ How to use CONFIG_PACKET_MMAP ++ How to use CONFIG_PACKET_MMAP to improve capture process -------------------------------------------------------------------------------- From the user standpoint, you should use the higher level libpcap library, which @@ -57,7 +64,7 @@ the low level details or want to improve libpcap by including PACKET_MMAP support. -------------------------------------------------------------------------------- -+ How to use CONFIG_PACKET_MMAP directly ++ How to use CONFIG_PACKET_MMAP directly to improve capture process -------------------------------------------------------------------------------- From the system calls stand point, the use of PACKET_MMAP involves @@ -66,6 +73,7 @@ the following process: [setup] socket() -------> creation of the capture socket setsockopt() ---> allocation of the circular buffer (ring) + option: PACKET_RX_RING mmap() ---------> mapping of the allocated buffer to the user process @@ -97,13 +105,75 @@ also the mapping of the circular buffer in the user process and the use of this buffer. -------------------------------------------------------------------------------- ++ How to use CONFIG_PACKET_MMAP directly to improve transmission process +-------------------------------------------------------------------------------- +Transmission process is similar to capture as shown below. + +[setup] socket() -------> creation of the transmission socket + setsockopt() ---> allocation of the circular buffer (ring) + option: PACKET_TX_RING + bind() ---------> bind transmission socket with a network interface + mmap() ---------> mapping of the allocated buffer to the + user process + +[transmission] poll() ---------> wait for free packets (optional) + send() ---------> send all packets that are set as ready in + the ring + The flag MSG_DONTWAIT can be used to return + before end of transfer. + +[shutdown] close() --------> destruction of the transmission socket and + deallocation of all associated resources. + +Binding the socket to your network interface is mandatory (with zero copy) to +know the header size of frames used in the circular buffer. + +As capture, each frame contains two parts: + + -------------------- +| struct tpacket_hdr | Header. It contains the status of +| | of this frame +|--------------------| +| data buffer | +. . Data that will be sent over the network interface. +. . + -------------------- + + bind() associates the socket to your network interface thanks to + sll_ifindex parameter of struct sockaddr_ll. + + Initialization example: + + struct sockaddr_ll my_addr; + struct ifreq s_ifr; + ... + + strncpy (s_ifr.ifr_name, "eth0", sizeof(s_ifr.ifr_name)); + + /* get interface index of eth0 */ + ioctl(this->socket, SIOCGIFINDEX, &s_ifr); + + /* fill sockaddr_ll struct to prepare binding */ + my_addr.sll_family = AF_PACKET; + my_addr.sll_protocol = ETH_P_ALL; + my_addr.sll_ifindex = s_ifr.ifr_ifindex; + + /* bind socket to eth0 */ + bind(this->socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_ll)); + + A complete tutorial is available at: http://wiki.gnu-log.net/ + +-------------------------------------------------------------------------------- + PACKET_MMAP settings -------------------------------------------------------------------------------- To setup PACKET_MMAP from user level code is done with a call like + - Capture process setsockopt(fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req)) + - Transmission process + setsockopt(fd, SOL_PACKET, PACKET_TX_RING, (void *) &req, sizeof(req)) The most significant argument in the previous call is the req parameter, this parameter must to have the following structure: @@ -117,11 +187,11 @@ this parameter must to have the following structure: }; This structure is defined in /usr/include/linux/if_packet.h and establishes a -circular buffer (ring) of unswappable memory mapped in the capture process. +circular buffer (ring) of unswappable memory. Being mapped in the capture process allows reading the captured frames and related meta-information like timestamps without requiring a system call. -Captured frames are grouped in blocks. Each block is a physically contiguous +Frames are grouped in blocks. Each block is a physically contiguous region of memory and holds tp_block_size/tp_frame_size frames. The total number of blocks is tp_block_nr. Note that tp_frame_nr is a redundant parameter because @@ -336,6 +406,7 @@ struct tpacket_hdr). If this field is 0 means that the frame is ready to be used for the kernel, If not, there is a frame the user can read and the following flags apply: ++++ Capture process: from include/linux/if_packet.h #define TP_STATUS_COPY 2 @@ -391,6 +462,37 @@ packets are in the ring: It doesn't incur in a race condition to first check the status value and then poll for frames. + +++ Transmission process +Those defines are also used for transmission: + + #define TP_STATUS_AVAILABLE 0 // Frame is available + #define TP_STATUS_SEND_REQUEST 1 // Frame will be sent on next send() + #define TP_STATUS_SENDING 2 // Frame is currently in transmission + #define TP_STATUS_WRONG_FORMAT 4 // Frame format is not correct + +First, the kernel initializes all frames to TP_STATUS_AVAILABLE. To send a +packet, the user fills a data buffer of an available frame, sets tp_len to +current data buffer size and sets its status field to TP_STATUS_SEND_REQUEST. +This can be done on multiple frames. Once the user is ready to transmit, it +calls send(). Then all buffers with status equal to TP_STATUS_SEND_REQUEST are +forwarded to the network device. The kernel updates each status of sent +frames with TP_STATUS_SENDING until the end of transfer. +At the end of each transfer, buffer status returns to TP_STATUS_AVAILABLE. + + header->tp_len = in_i_size; + header->tp_status = TP_STATUS_SEND_REQUEST; + retval = send(this->socket, NULL, 0, 0); + +The user can also use poll() to check if a buffer is available: +(status == TP_STATUS_SENDING) + + struct pollfd pfd; + pfd.fd = fd; + pfd.revents = 0; + pfd.events = POLLOUT; + retval = poll(&pfd, 1, timeout); + -------------------------------------------------------------------------------- + THANKS -------------------------------------------------------------------------------- diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index 18db066..5b2bade 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -46,6 +46,8 @@ struct sockaddr_ll #define PACKET_VERSION 10 #define PACKET_HDRLEN 11 #define PACKET_RESERVE 12 +#define PACKET_TX_RING 13 +#define PACKET_LOSS 14 struct tpacket_stats { @@ -63,14 +65,22 @@ struct tpacket_auxdata __u16 tp_vlan_tci; }; +/* Rx ring - header status */ +#define TP_STATUS_KERNEL 0x0 +#define TP_STATUS_USER 0x1 +#define TP_STATUS_COPY 0x2 +#define TP_STATUS_LOSING 0x4 +#define TP_STATUS_CSUMNOTREADY 0x8 + +/* Tx ring - header status */ +#define TP_STATUS_AVAILABLE 0x0 +#define TP_STATUS_SEND_REQUEST 0x1 +#define TP_STATUS_SENDING 0x2 +#define TP_STATUS_WRONG_FORMAT 0x4 + struct tpacket_hdr { unsigned long tp_status; -#define TP_STATUS_KERNEL 0 -#define TP_STATUS_USER 1 -#define TP_STATUS_COPY 2 -#define TP_STATUS_LOSING 4 -#define TP_STATUS_CSUMNOTREADY 8 unsigned int tp_len; unsigned int tp_snaplen; unsigned short tp_mac; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1b5c3d2..aff494b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -203,6 +203,9 @@ struct skb_shared_info { #ifdef CONFIG_HAS_DMA dma_addr_t dma_maps[MAX_SKB_FRAGS + 1]; #endif + /* Intermediate layers must ensure that destructor_arg + * remains valid until skb destructor */ + void * destructor_arg; }; /* We divide dataref into two halves. The higher 16 bits hold references diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f546e81..766e6b4 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -39,6 +39,7 @@ * will simply extend the hardware address * byte arrays at the end of sockaddr_ll * and packet_mreq. + * Johann Baudy : Added TX RING. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -157,7 +158,25 @@ struct packet_mreq_max }; #ifdef CONFIG_PACKET_MMAP -static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing); +static int packet_set_ring(struct sock *sk, struct tpacket_req *req, + int closing, int tx_ring); + +struct packet_ring_buffer { + char * *pg_vec; + unsigned int head; + unsigned int frames_per_block; + unsigned int frame_size; + unsigned int frame_max; + + unsigned int pg_vec_order; + unsigned int pg_vec_pages; + unsigned int pg_vec_len; + + atomic_t pending; +}; + +struct packet_sock; +static int tpacket_snd(struct packet_sock *po, struct msghdr *msg); #endif static void packet_flush_mclist(struct sock *sk); @@ -167,11 +186,8 @@ struct packet_sock { struct sock sk; struct tpacket_stats stats; #ifdef CONFIG_PACKET_MMAP - char * *pg_vec; - unsigned int head; - unsigned int frames_per_block; - unsigned int frame_size; - unsigned int frame_max; + struct packet_ring_buffer rx_ring; + struct packet_ring_buffer tx_ring; int copy_thresh; #endif struct packet_type prot_hook; @@ -185,12 +201,10 @@ struct packet_sock { struct packet_mclist *mclist; #ifdef CONFIG_PACKET_MMAP atomic_t mapped; - unsigned int pg_vec_order; - unsigned int pg_vec_pages; - unsigned int pg_vec_len; enum tpacket_versions tp_version; unsigned int tp_hdrlen; unsigned int tp_reserve; + unsigned int tp_loss:1; #endif }; @@ -206,36 +220,33 @@ struct packet_skb_cb { #ifdef CONFIG_PACKET_MMAP -static void *packet_lookup_frame(struct packet_sock *po, unsigned int position, - int status) +static void __packet_set_status(struct packet_sock *po, void *frame, int status) { - unsigned int pg_vec_pos, frame_offset; union { struct tpacket_hdr *h1; struct tpacket2_hdr *h2; void *raw; } h; - pg_vec_pos = position / po->frames_per_block; - frame_offset = position % po->frames_per_block; - - h.raw = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size); + h.raw = frame; switch (po->tp_version) { case TPACKET_V1: - if (status != (h.h1->tp_status ? TP_STATUS_USER : - TP_STATUS_KERNEL)) - return NULL; + h.h1->tp_status = status; + flush_dcache_page(virt_to_page(&h.h1->tp_status)); break; case TPACKET_V2: - if (status != (h.h2->tp_status ? TP_STATUS_USER : - TP_STATUS_KERNEL)) - return NULL; + h.h2->tp_status = status; + flush_dcache_page(virt_to_page(&h.h2->tp_status)); break; + default: + printk(KERN_ERR "TPACKET version not supported\n"); + BUG(); } - return h.raw; + + smp_wmb(); } -static void __packet_set_status(struct packet_sock *po, void *frame, int status) +static int __packet_get_status(struct packet_sock *po, void *frame) { union { struct tpacket_hdr *h1; @@ -243,16 +254,66 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status) void *raw; } h; + smp_rmb(); + h.raw = frame; switch (po->tp_version) { case TPACKET_V1: - h.h1->tp_status = status; - break; + flush_dcache_page(virt_to_page(&h.h1->tp_status)); + return h.h1->tp_status; case TPACKET_V2: - h.h2->tp_status = status; - break; + flush_dcache_page(virt_to_page(&h.h2->tp_status)); + return h.h2->tp_status; + default: + printk(KERN_ERR "TPACKET version not supported\n"); + BUG(); + return 0; } } + +static void *packet_lookup_frame(struct packet_sock *po, + struct packet_ring_buffer *rb, + unsigned int position, + int status) +{ + unsigned int pg_vec_pos, frame_offset; + union { + struct tpacket_hdr *h1; + struct tpacket2_hdr *h2; + void *raw; + } h; + + pg_vec_pos = position / rb->frames_per_block; + frame_offset = position % rb->frames_per_block; + + h.raw = rb->pg_vec[pg_vec_pos] + (frame_offset * rb->frame_size); + + if (status != __packet_get_status(po, h.raw)) + return NULL; + + return h.raw; +} + +static inline void *packet_current_frame(struct packet_sock *po, + struct packet_ring_buffer *rb, + int status) +{ + return packet_lookup_frame(po, rb, rb->head, status); +} + +static inline void *packet_previous_frame(struct packet_sock *po, + struct packet_ring_buffer *rb, + int status) +{ + unsigned int previous = rb->head ? rb->head - 1 : rb->frame_max; + return packet_lookup_frame(po, rb, previous, status); +} + +static inline void packet_increment_head(struct packet_ring_buffer *buff) +{ + buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; +} + #endif static inline struct packet_sock *pkt_sk(struct sock *sk) @@ -648,7 +709,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe macoff = netoff - maclen; } - if (macoff + snaplen > po->frame_size) { + if (macoff + snaplen > po->rx_ring.frame_size) { if (po->copy_thresh && atomic_read(&sk->sk_rmem_alloc) + skb->truesize < (unsigned)sk->sk_rcvbuf) { @@ -661,16 +722,16 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe if (copy_skb) skb_set_owner_r(copy_skb, sk); } - snaplen = po->frame_size - macoff; + snaplen = po->rx_ring.frame_size - macoff; if ((int)snaplen < 0) snaplen = 0; } spin_lock(&sk->sk_receive_queue.lock); - h.raw = packet_lookup_frame(po, po->head, TP_STATUS_KERNEL); + h.raw = packet_current_frame(po, &po->rx_ring, TP_STATUS_KERNEL); if (!h.raw) goto ring_is_full; - po->head = po->head != po->frame_max ? po->head+1 : 0; + packet_increment_head(&po->rx_ring); po->stats.tp_packets++; if (copy_skb) { status |= TP_STATUS_COPY; @@ -727,7 +788,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe __packet_set_status(po, h.raw, status); smp_mb(); - { struct page *p_start, *p_end; u8 *h_end = h.raw + macoff + snaplen - 1; @@ -760,10 +820,249 @@ ring_is_full: goto drop_n_restore; } -#endif +static void tpacket_destruct_skb(struct sk_buff *skb) +{ + struct packet_sock *po = pkt_sk(skb->sk); + void * ph; + BUG_ON(skb == NULL); -static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, + if (likely(po->tx_ring.pg_vec)) { + ph = skb_shinfo(skb)->destructor_arg; + BUG_ON(__packet_get_status(po, ph) != TP_STATUS_SENDING); + BUG_ON(atomic_read(&po->tx_ring.pending) == 0); + atomic_dec(&po->tx_ring.pending); + __packet_set_status(po, ph, TP_STATUS_AVAILABLE); + } + + sock_wfree(skb); +} + +static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb, + void * frame, struct net_device *dev, int size_max, + __be16 proto, unsigned char * addr) +{ + union { + struct tpacket_hdr *h1; + struct tpacket2_hdr *h2; + void *raw; + } ph; + int to_write, offset, len, tp_len, nr_frags, len_max; + struct socket *sock = po->sk.sk_socket; + struct page *page; + void *data; + int err; + + ph.raw = frame; + + skb->protocol = proto; + skb->dev = dev; + skb->priority = po->sk.sk_priority; + skb_shinfo(skb)->destructor_arg = ph.raw; + + switch (po->tp_version) { + case TPACKET_V2: + tp_len = ph.h2->tp_len; + break; + default: + tp_len = ph.h1->tp_len; + break; + } + if (unlikely(tp_len > size_max)) { + printk(KERN_ERR "packet size is too long (%d > %d)\n", + tp_len, size_max); + return -EMSGSIZE; + } + + skb_reserve(skb, LL_RESERVED_SPACE(dev)); + skb_reset_network_header(skb); + + data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll); + to_write = tp_len; + + if (sock->type == SOCK_DGRAM) { + err = dev_hard_header(skb, dev, ntohs(proto), addr, + NULL, tp_len); + if (unlikely(err < 0)) + return -EINVAL; + } else if (dev->hard_header_len ) { + /* net device doesn't like empty head */ + if (unlikely(tp_len <= dev->hard_header_len)) { + printk(KERN_ERR "packet size is too short " + "(%d < %d)\n", tp_len, + dev->hard_header_len); + return -EINVAL; + } + + skb_push(skb, dev->hard_header_len); + err = skb_store_bits(skb, 0, data, + dev->hard_header_len); + if (unlikely(err)) + return err; + + data += dev->hard_header_len; + to_write -= dev->hard_header_len; + } + + err = -EFAULT; + page = virt_to_page(data); + offset = offset_in_page(data); + len_max = PAGE_SIZE - offset; + len = ((to_write > len_max) ? len_max : to_write); + + skb->data_len = to_write; + skb->len += to_write; + skb->truesize += to_write; + atomic_add(to_write, &po->sk.sk_wmem_alloc); + + while (likely(to_write)) { + nr_frags = skb_shinfo(skb)->nr_frags; + + if (unlikely(nr_frags >= MAX_SKB_FRAGS)) { + printk(KERN_ERR "Packet exceed the number " + "of skb frags(%lu)\n", + MAX_SKB_FRAGS); + return -EFAULT; + } + + flush_dcache_page(page); + get_page(page); + skb_fill_page_desc(skb, + nr_frags, + page++, offset, len); + to_write -= len; + offset = 0; + len_max = PAGE_SIZE; + len = ((to_write > len_max) ? len_max : to_write); + } + + return tp_len; +} + +static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) +{ + struct socket *sock; + struct sk_buff *skb; + struct net_device *dev; + __be16 proto; + int ifindex, err, reserve = 0; + void * ph; + struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name; + int tp_len, size_max; + unsigned char *addr; + int len_sum = 0; + int status = 0; + + sock = po->sk.sk_socket; + + mutex_lock(&po->pg_vec_lock); + + err = -EBUSY; + if (saddr == NULL) { + ifindex = po->ifindex; + proto = po->num; + addr = NULL; + } else { + err = -EINVAL; + if (msg->msg_namelen < sizeof(struct sockaddr_ll)) + goto out; + if (msg->msg_namelen < (saddr->sll_halen + + offsetof(struct sockaddr_ll, + sll_addr))) + goto out; + ifindex = saddr->sll_ifindex; + proto = saddr->sll_protocol; + addr = saddr->sll_addr; + } + + dev = dev_get_by_index(sock_net(&po->sk), ifindex); + err = -ENXIO; + if (unlikely(dev == NULL)) + goto out; + + reserve = dev->hard_header_len; + + err = -ENETDOWN; + if (unlikely(!(dev->flags & IFF_UP))) + goto out_put; + + size_max = po->tx_ring.frame_size + - sizeof(struct skb_shared_info) + - po->tp_hdrlen + - LL_ALLOCATED_SPACE(dev) + - sizeof(struct sockaddr_ll); + + if (size_max > dev->mtu + reserve) + size_max = dev->mtu + reserve; + + do { + ph = packet_current_frame(po, &po->tx_ring, + TP_STATUS_SEND_REQUEST); + + if (unlikely(ph == NULL)) { + schedule(); + continue; + } + + status = TP_STATUS_SEND_REQUEST; + skb = sock_alloc_send_skb(&po->sk, + LL_ALLOCATED_SPACE(dev) + + sizeof(struct sockaddr_ll), + 0, &err); + + if (unlikely(skb == NULL)) + goto out_status; + + tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, + addr); + + if (unlikely(tp_len < 0)) { + if (po->tp_loss) { + __packet_set_status(po, ph, + TP_STATUS_AVAILABLE); + packet_increment_head(&po->tx_ring); + kfree_skb(skb); + continue; + } else { + status = TP_STATUS_WRONG_FORMAT; + err = tp_len; + goto out_status; + } + } + + skb->destructor = tpacket_destruct_skb; + __packet_set_status(po, ph, TP_STATUS_SENDING); + atomic_inc(&po->tx_ring.pending); + + status = TP_STATUS_SEND_REQUEST; + err = dev_queue_xmit(skb); + if (unlikely(err > 0 && (err = net_xmit_errno(err)) != 0)) + goto out_xmit; + packet_increment_head(&po->tx_ring); + len_sum += tp_len; + } + while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT)) + && (atomic_read(&po->tx_ring.pending)))) + ); + + err = len_sum; + goto out_put; + +out_xmit: + skb->destructor = sock_wfree; + atomic_dec(&po->tx_ring.pending); +out_status: + __packet_set_status(po, ph, status); + kfree_skb(skb); +out_put: + dev_put(dev); +out: + mutex_unlock(&po->pg_vec_lock); + return err; +} +#endif + +static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; @@ -854,6 +1153,19 @@ out: return err; } +static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ +#ifdef CONFIG_PACKET_MMAP + struct sock *sk = sock->sk; + struct packet_sock *po = pkt_sk(sk); + if (po->tx_ring.pg_vec) + return tpacket_snd(po, msg); + else +#endif + return packet_snd(sock, msg, len); +} + /* * Close a PACKET socket. This is fairly simple. We immediately go * to 'closed' state and remove our protocol entry in the device list. @@ -864,6 +1176,9 @@ static int packet_release(struct socket *sock) struct sock *sk = sock->sk; struct packet_sock *po; struct net *net; +#ifdef CONFIG_PACKET_MMAP + struct tpacket_req req; +#endif if (!sk) return 0; @@ -893,11 +1208,13 @@ static int packet_release(struct socket *sock) packet_flush_mclist(sk); #ifdef CONFIG_PACKET_MMAP - if (po->pg_vec) { - struct tpacket_req req; - memset(&req, 0, sizeof(req)); - packet_set_ring(sk, &req, 1); - } + memset(&req, 0, sizeof(req)); + + if (po->rx_ring.pg_vec) + packet_set_ring(sk, &req, 1, 0); + + if (po->tx_ring.pg_vec) + packet_set_ring(sk, &req, 1, 1); #endif /* @@ -1391,7 +1708,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (level != SOL_PACKET) return -ENOPROTOOPT; - switch(optname) { + switch (optname) { case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: { @@ -1415,6 +1732,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv #ifdef CONFIG_PACKET_MMAP case PACKET_RX_RING: + case PACKET_TX_RING: { struct tpacket_req req; @@ -1422,7 +1740,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return -EINVAL; if (copy_from_user(&req,optval,sizeof(req))) return -EFAULT; - return packet_set_ring(sk, &req, 0); + return packet_set_ring(sk, &req, 0, optname == PACKET_TX_RING); } case PACKET_COPY_THRESH: { @@ -1442,7 +1760,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->pg_vec) + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; @@ -1461,13 +1779,26 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->pg_vec) + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; po->tp_reserve = val; return 0; } + case PACKET_LOSS: + { + unsigned int val; + + if (optlen != sizeof(val)) + return -EINVAL; + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) + return -EBUSY; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + po->tp_loss = !!val; + return 0; + } #endif case PACKET_AUXDATA: { @@ -1517,7 +1848,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, if (len < 0) return -EINVAL; - switch(optname) { + switch (optname) { case PACKET_STATISTICS: if (len > sizeof(struct tpacket_stats)) len = sizeof(struct tpacket_stats); @@ -1573,6 +1904,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, val = po->tp_reserve; data = &val; break; + case PACKET_LOSS: + if (len > sizeof(unsigned int)) + len = sizeof(unsigned int); + val = po->tp_loss; + data = &val; + break; #endif default: return -ENOPROTOOPT; @@ -1643,7 +1980,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, { struct sock *sk = sock->sk; - switch(cmd) { + switch (cmd) { case SIOCOUTQ: { int amount = atomic_read(&sk->sk_wmem_alloc); @@ -1705,13 +2042,17 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, unsigned int mask = datagram_poll(file, sock, wait); spin_lock_bh(&sk->sk_receive_queue.lock); - if (po->pg_vec) { - unsigned last = po->head ? po->head-1 : po->frame_max; - - if (packet_lookup_frame(po, last, TP_STATUS_USER)) + if (po->rx_ring.pg_vec) { + if (!packet_previous_frame(po, &po->rx_ring, TP_STATUS_KERNEL)) mask |= POLLIN | POLLRDNORM; } spin_unlock_bh(&sk->sk_receive_queue.lock); + spin_lock_bh(&sk->sk_write_queue.lock); + if (po->tx_ring.pg_vec) { + if (packet_current_frame(po, &po->tx_ring, TP_STATUS_AVAILABLE)) + mask |= POLLOUT | POLLWRNORM; + } + spin_unlock_bh(&sk->sk_write_queue.lock); return mask; } @@ -1788,21 +2129,33 @@ out_free_pgvec: goto out; } -static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing) +static int packet_set_ring(struct sock *sk, struct tpacket_req *req, + int closing, int tx_ring) { char **pg_vec = NULL; struct packet_sock *po = pkt_sk(sk); int was_running, order = 0; + struct packet_ring_buffer *rb; + struct sk_buff_head *rb_queue; __be16 num; - int err = 0; + int err; - if (req->tp_block_nr) { - int i; + rb = tx_ring ? &po->tx_ring : &po->rx_ring; + rb_queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue; - /* Sanity tests and some calculations */ + err = -EBUSY; + if (!closing) { + if (atomic_read(&po->mapped)) + goto out; + if (atomic_read(&rb->pending)) + goto out; + } - if (unlikely(po->pg_vec)) - return -EBUSY; + if (req->tp_block_nr) { + /* Sanity tests and some calculations */ + err = -EBUSY; + if (unlikely(rb->pg_vec)) + goto out; switch (po->tp_version) { case TPACKET_V1: @@ -1813,42 +2166,35 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing break; } + err = -EINVAL; if (unlikely((int)req->tp_block_size <= 0)) - return -EINVAL; + goto out; if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) - return -EINVAL; + goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + - po->tp_reserve)) - return -EINVAL; + po->tp_reserve)) + goto out; if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) - return -EINVAL; + goto out; - po->frames_per_block = req->tp_block_size/req->tp_frame_size; - if (unlikely(po->frames_per_block <= 0)) - return -EINVAL; - if (unlikely((po->frames_per_block * req->tp_block_nr) != - req->tp_frame_nr)) - return -EINVAL; + rb->frames_per_block = req->tp_block_size/req->tp_frame_size; + if (unlikely(rb->frames_per_block <= 0)) + goto out; + if (unlikely((rb->frames_per_block * req->tp_block_nr) != + req->tp_frame_nr)) + goto out; err = -ENOMEM; order = get_order(req->tp_block_size); pg_vec = alloc_pg_vec(req, order); if (unlikely(!pg_vec)) goto out; - - for (i = 0; i < req->tp_block_nr; i++) { - void *ptr = pg_vec[i]; - int k; - - for (k = 0; k < po->frames_per_block; k++) { - __packet_set_status(po, ptr, TP_STATUS_KERNEL); - ptr += req->tp_frame_size; - } - } - /* Done */ - } else { + } + /* Done */ + else { + err = -EINVAL; if (unlikely(req->tp_frame_nr)) - return -EINVAL; + goto out; } lock_sock(sk); @@ -1872,23 +2218,24 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing if (closing || atomic_read(&po->mapped) == 0) { err = 0; #define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; }) - - spin_lock_bh(&sk->sk_receive_queue.lock); - pg_vec = XC(po->pg_vec, pg_vec); - po->frame_max = (req->tp_frame_nr - 1); - po->head = 0; - po->frame_size = req->tp_frame_size; - spin_unlock_bh(&sk->sk_receive_queue.lock); - - order = XC(po->pg_vec_order, order); - req->tp_block_nr = XC(po->pg_vec_len, req->tp_block_nr); - - po->pg_vec_pages = req->tp_block_size/PAGE_SIZE; - po->prot_hook.func = po->pg_vec ? tpacket_rcv : packet_rcv; - skb_queue_purge(&sk->sk_receive_queue); + spin_lock_bh(&rb_queue->lock); + pg_vec = XC(rb->pg_vec, pg_vec); + rb->frame_max = (req->tp_frame_nr - 1); + rb->head = 0; + rb->frame_size = req->tp_frame_size; + spin_unlock_bh(&rb_queue->lock); + + order = XC(rb->pg_vec_order, order); + req->tp_block_nr = XC(rb->pg_vec_len, req->tp_block_nr); + + rb->pg_vec_pages = req->tp_block_size/PAGE_SIZE; + po->prot_hook.func = (po->rx_ring.pg_vec) ? + tpacket_rcv : packet_rcv; + skb_queue_purge(rb_queue); #undef XC if (atomic_read(&po->mapped)) - printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", atomic_read(&po->mapped)); + printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", + atomic_read(&po->mapped)); } mutex_unlock(&po->pg_vec_lock); @@ -1909,11 +2256,13 @@ out: return err; } -static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) +static int packet_mmap(struct file *file, struct socket *sock, + struct vm_area_struct *vma) { struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); - unsigned long size; + unsigned long size, expected_size; + struct packet_ring_buffer *rb; unsigned long start; int err = -EINVAL; int i; @@ -1921,26 +2270,43 @@ static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_st if (vma->vm_pgoff) return -EINVAL; - size = vma->vm_end - vma->vm_start; - mutex_lock(&po->pg_vec_lock); - if (po->pg_vec == NULL) + + expected_size = 0; + for (rb = &po->rx_ring; rb <= &po->tx_ring; rb++) { + if (rb->pg_vec) { + expected_size += rb->pg_vec_len + * rb->pg_vec_pages + * PAGE_SIZE; + } + } + + if (expected_size == 0) goto out; - if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE) + + size = vma->vm_end - vma->vm_start; + if (size != expected_size) goto out; start = vma->vm_start; - for (i = 0; i < po->pg_vec_len; i++) { - struct page *page = virt_to_page(po->pg_vec[i]); - int pg_num; - - for (pg_num = 0; pg_num < po->pg_vec_pages; pg_num++, page++) { - err = vm_insert_page(vma, start, page); - if (unlikely(err)) - goto out; - start += PAGE_SIZE; + for (rb = &po->rx_ring; rb <= &po->tx_ring; rb++) { + if (rb->pg_vec == NULL) + continue; + + for (i = 0; i < rb->pg_vec_len; i++) { + struct page *page = virt_to_page(rb->pg_vec[i]); + int pg_num; + + for (pg_num = 0; pg_num < rb->pg_vec_pages; + pg_num++,page++) { + err = vm_insert_page(vma, start, page); + if (unlikely(err)) + goto out; + start += PAGE_SIZE; + } } } + atomic_inc(&po->mapped); vma->vm_ops = &packet_mmap_ops; err = 0; -- cgit v0.10.2 From 690cc3ffe33ac4a2857583c22d4c6244ae11684d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2009 16:55:10 +0000 Subject: syscall: Implement a convinience function restart_syscall Currently when we have a signal pending we have the functionality to restart that the current system call. There are other cases such as nasty lock ordering issues where it makes sense to have a simple fix that uses try lock and restarts the system call. Buying time to figure out how to rework the locking strategy. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/include/linux/sched.h b/include/linux/sched.h index b4c38bc..d853f6b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2178,6 +2178,12 @@ static inline int test_tsk_need_resched(struct task_struct *tsk) return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED)); } +static inline int restart_syscall(void) +{ + set_tsk_thread_flag(current, TIF_SIGPENDING); + return -ERESTARTNOINTR; +} + static inline int signal_pending(struct task_struct *p) { return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING)); -- cgit v0.10.2 From 336ca57c3b4e2b58ea3273e6d978ab3dfa387b4c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2009 16:57:25 +0000 Subject: net-sysfs: Use rtnl_trylock in sysfs methods. The earlier patch to fix the deadlock between a network device going away and writing to sysfs attributes was incomplete. - It did not set signal_pending so we would leak ERSTARTSYS to user space. - It used ERESTARTSYS which only restarts if sigaction configures it to. - It did not cover store and show for ifalias. So fix all of these up and use the new helper restart_syscall so we get the details correct on what it takes. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 2da59a0..b9641e8 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -78,7 +78,7 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, goto err; if (!rtnl_trylock()) - return -ERESTARTSYS; + return restart_syscall(); if (dev_isalive(net)) { if ((ret = (*set)(net, new)) == 0) @@ -225,7 +225,8 @@ static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, if (len > 0 && buf[len - 1] == '\n') --count; - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); ret = dev_set_alias(netdev, buf, count); rtnl_unlock(); @@ -238,7 +239,8 @@ static ssize_t show_ifalias(struct device *dev, const struct net_device *netdev = to_net_dev(dev); ssize_t ret = 0; - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); if (netdev->ifalias) ret = sprintf(buf, "%s\n", netdev->ifalias); rtnl_unlock(); -- cgit v0.10.2 From 5007392d8512e666107dc356d4c2e05627b9029b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2009 16:58:17 +0000 Subject: net: FIX ipv6_forward sysctl restart Just returning -ERESTARTSYS without a signal pending is not good that will just leak it to userspace. We need return -ERESTARTNOINTR so we always restart and set signal pending so that we fall of the fast path of syscall return and setup the system call restart. So use restart_syscall() which does all of this for us. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a8218bc..9eb61c7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -503,7 +503,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) return 0; if (!rtnl_trylock()) - return -ERESTARTSYS; + return restart_syscall(); if (p == &net->ipv6.devconf_all->forwarding) { __s32 newf = net->ipv6.devconf_all->forwarding; -- cgit v0.10.2 From 9b8adb5ea005fe73acd5dd58f9bd47eafa74c9d1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2009 16:59:21 +0000 Subject: net: Fix devinet_sysctl_forward sysctls are unregistered with the rntl_lock held making it unsafe to unconditionally grab the the rtnl_lock. Instead we need to call rtnl_trylock and restart the system call if we can not grab it. Otherwise we could deadlock at unregistration time. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 126bb91..3863c3a 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1347,7 +1347,8 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, struct net *net = ctl->extra2; if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) { - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) { inet_forward_change(net); } else if (*valp) { -- cgit v0.10.2 From af38f2989572704a846a5577b5ab3b1e2885cbfb Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2009 17:00:41 +0000 Subject: net: Fix bridgeing sysfs handling of rtnl_lock Holding rtnl_lock when we are unregistering the sysfs files can deadlock if we unconditionally take rtnl_lock in a sysfs file. So fix it with the now familiar patter of: rtnl_trylock and syscall_restart() Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 603d892..ee4820a 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -172,7 +172,8 @@ static ssize_t store_stp_state(struct device *d, if (endp == buf) return -EINVAL; - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); br_stp_set_enabled(br, val); rtnl_unlock(); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 02b2d50..4a3cdf8 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -189,7 +189,8 @@ static ssize_t brport_store(struct kobject * kobj, val = simple_strtoul(buf, &endp, 0); if (endp != buf) { - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); if (p->dev && p->br && brport_attr->store) { spin_lock_bh(&p->br->lock); ret = brport_attr->store(p, val); -- cgit v0.10.2 From 26574401fef6766f6c3ca25b5c13febe662d2a32 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2009 17:01:51 +0000 Subject: net: Fix ipoib rtnl_lock sysfs deadlock. Network device sysfs files that grab the rtnl_lock unconditionally will deadlock if accessed when the network device is being unregistered. So use trylock and syscall_restart to avoid this deadlock. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 47d588b..4248c31 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1455,13 +1455,15 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, struct net_device *dev = to_net_dev(d); struct ipoib_dev_priv *priv = netdev_priv(dev); + if (!rtnl_trylock()) + return restart_syscall(); + /* flush paths if we switch modes so that connections are restarted */ if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); ipoib_warn(priv, "enabling connected mode " "will cause multicast packet drops\n"); - rtnl_lock(); dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); rtnl_unlock(); priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; @@ -1473,7 +1475,6 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, if (!strcmp(buf, "datagram\n")) { clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); - rtnl_lock(); if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; if (priv->hca_caps & IB_DEVICE_UD_TSO) @@ -1485,6 +1486,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, return count; } + rtnl_unlock(); return -EINVAL; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 4c57f32..e3bf00d8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -61,7 +61,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) ppriv = netdev_priv(pdev); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); mutex_lock(&ppriv->vlan_mutex); /* @@ -167,7 +168,8 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) ppriv = netdev_priv(pdev); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); mutex_lock(&ppriv->vlan_mutex); list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { if (priv->pkey == pkey) { -- cgit v0.10.2 From 496a60cdcd5d0d884dddf6c3b4ea912923a70f13 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2009 17:02:50 +0000 Subject: net: FIX bonding sysfs rtnl_lock deadlock Sysfs files for a network device can not unconditionally take the rtnl_lock as the bonding sysfs files do. If someone accesses those sysfs files while the network device is being unregistered with the rtnl_lock held we will deadlock. So use trylock and restart_syscall to avoid this problem. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index d287315..3a1b7b0 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -251,7 +251,8 @@ static ssize_t bonding_store_slaves(struct device *d, /* Note: We can't hold bond->lock here, as bond_create grabs it. */ - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); down_write(&(bonding_rwsem)); sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ @@ -1171,7 +1172,8 @@ static ssize_t bonding_store_primary(struct device *d, struct slave *slave; struct bonding *bond = to_bond(d); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); @@ -1288,7 +1290,8 @@ static ssize_t bonding_store_active_slave(struct device *d, struct slave *new_active = NULL; struct bonding *bond = to_bond(d); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); -- cgit v0.10.2 From 93f154b594fe47e4a7e5358b309add449a046cd3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 18 May 2009 22:19:19 -0700 Subject: net: release dst entry in dev_hard_start_xmit() One point of contention in high network loads is the dst_release() performed when a transmited skb is freed. This is because NIC tx completion calls dev_kree_skb() long after original call to dev_queue_xmit(skb). CPU cache is cold and the atomic op in dst_release() stalls. On SMP, this is quite visible if one CPU is 100% handling softirqs for a network device, since dst_clone() is done by other cpus, involving cache line ping pongs. It seems right place to release dst is in dev_hard_start_xmit(), for most devices but ones that are virtual, and some exceptions. David Miller suggested to define a new device flag, set in alloc_netdev_mq() (so that most devices set it at init time), and carefuly unset in devices which dont want a NULL skb->dst in their ndo_start_xmit(). List of devices that must clear this flag is : - loopback device, because it calls netif_rx() and quoting Patrick : "ip_route_input() doesn't accept loopback addresses, so loopback packets already need to have a dst_entry attached." - appletalk/ipddp.c : needs skb->dst in its xmit function - And all devices that call again dev_queue_xmit() from their xmit function (as some classifiers need skb->dst) : bonding, vlan, macvlan, eql, ifb, hdlc_fr Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index da64ba8..f939e92 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -71,6 +71,7 @@ static struct net_device * __init ipddp_init(void) if (!dev) return ERR_PTR(-ENOMEM); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; strcpy(dev->name, "ipddp%d"); if (version_printed++ == 0) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 96d7689..92a9d69 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5148,6 +5148,7 @@ int bond_create(char *name, struct bond_params *params) goto out_rtnl; } + bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; if (!name) { res = dev_alloc_name(bond_dev, "bond%d"); if (res < 0) diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 5210bb1..19b7dd9 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -194,6 +194,7 @@ static void __init eql_setup(struct net_device *dev) dev->type = ARPHRD_SLIP; dev->tx_queue_len = 5; /* Hands them off fast */ + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static int eql_open(struct net_device *dev) diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 60a2630..96713ef 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -156,6 +156,7 @@ static void ifb_setup(struct net_device *dev) dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; random_ether_addr(dev->dev_addr); } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 6f71157..da472c6 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -170,6 +170,7 @@ static void loopback_setup(struct net_device *dev) dev->tx_queue_len = 0; dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->flags = IFF_LOOPBACK; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO | NETIF_F_NO_CSUM diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 329cd50..d5334b4 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -414,6 +414,7 @@ static void macvlan_setup(struct net_device *dev) { ether_setup(dev); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->netdev_ops = &macvlan_netdev_ops; dev->destructor = free_netdev; dev->header_ops = &macvlan_hard_header_ops, diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 8005301..bfa0161 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1054,6 +1054,7 @@ static void pvc_setup(struct net_device *dev) dev->flags = IFF_POINTOPOINT; dev->hard_header_len = 10; dev->addr_len = 2; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static const struct net_device_ops pvc_ops = { diff --git a/include/linux/if.h b/include/linux/if.h index 1108f3e..b9a6229 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -67,6 +67,9 @@ #define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */ #define IFF_MASTER_ARPMON 0x100 /* bonding master, ARP mon in use */ #define IFF_WAN_HDLC 0x200 /* WAN HDLC device */ +#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to + * release skb->dst + */ #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 8faacee..ff7572a 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -739,6 +739,7 @@ void vlan_setup(struct net_device *dev) ether_setup(dev); dev->priv_flags |= IFF_802_1Q_VLAN; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->tx_queue_len = 0; dev->netdev_ops = &vlan_netdev_ops; diff --git a/net/core/dev.c b/net/core/dev.c index 6d3630d..92ebeca 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1688,6 +1688,14 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, goto gso; } + /* + * If device doesnt need skb->dst, release it right now while + * its hot in this cpu cache + */ + if ((dev->priv_flags & IFF_XMIT_DST_RELEASE) && skb->dst) { + dst_release(skb->dst); + skb->dst = NULL; + } rc = ops->ndo_start_xmit(skb, dev); /* * TODO: if skb_orphan() was called by @@ -5045,6 +5053,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, netdev_init_queues(dev); INIT_LIST_HEAD(&dev->napi_list); + dev->priv_flags = IFF_XMIT_DST_RELEASE; setup(dev); strcpy(dev->name, name); return dev; -- cgit v0.10.2 From 8b2d850db275a8934db7e09d79a716435c7b3e0c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 19 May 2009 14:24:37 -0700 Subject: ppp: unset IFF_XMIT_DST_RELEASE in ppp_setup() Jarek pointed pppoe can call back dev_queue_xmit(), and might need skb->dst, so its safer to unset IFF_XMIT_DST_RELEASE on ppp devices. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 8ee9142..639d11b 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1054,6 +1054,7 @@ static void ppp_setup(struct net_device *dev) dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } /* -- cgit v0.10.2 From 381f05172bdca076390abd84813b09ea423ae8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Thu, 14 May 2009 11:45:04 +0000 Subject: r8169: remove useless struct member Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c812e16..b057314 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -479,7 +479,6 @@ struct rtl8169_private { u16 intr_event; u16 napi_event; u16 intr_mask; - int phy_auto_nego_reg; int phy_1000_ctrl_reg; #ifdef CONFIG_R8169_VLAN struct vlan_group *vlgrp; @@ -908,7 +907,6 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, mdio_write(ioaddr, 0x0e, 0x0000); } - tp->phy_auto_nego_reg = auto_nego; tp->phy_1000_ctrl_reg = giga_ctrl; mdio_write(ioaddr, MII_ADVERTISE, auto_nego); -- cgit v0.10.2 From 3577aa1bd7efc9c474f59738d2fb89c168168d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Tue, 19 May 2009 10:46:48 +0000 Subject: r8169: allow true forced mode setting Due to mostly historic reasons, including a lack of reliability of the link handling (especially with the older 8169), the current r8169 driver emulates forced mode setting by limiting the advertised modes. With this change the driver allows real 10/100 forced mode settings on the 8169 and 8101/8102. Original idea by Vincent Steenhoute. The RTL_GIGA_MAC_VER_03 tweak was extracted from Realtek's r8169 v6.010.00 driver. Signed-off-by: Francois Romieu Tested-by: Jean Delvare Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b057314..fb2e50d 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -843,75 +843,81 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - int auto_nego, giga_ctrl; - - auto_nego = mdio_read(ioaddr, MII_ADVERTISE); - auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL); - giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); - giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + int giga_ctrl, bmcr; if (autoneg == AUTONEG_ENABLE) { + int auto_nego; + + auto_nego = mdio_read(ioaddr, MII_ADVERTISE); auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL); - giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - } else { - if (speed == SPEED_10) - auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL; - else if (speed == SPEED_100) - auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL; - else if (speed == SPEED_1000) - giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - - if (duplex == DUPLEX_HALF) - auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL); - - if (duplex == DUPLEX_FULL) - auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF); + auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - /* This tweak comes straight from Realtek's driver. */ - if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && - ((tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_16))) { - auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; - } - } + giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); + giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - /* 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)) { - if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) && - netif_msg_link(tp)) { + /* 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)) { + giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; + } else if (netif_msg_link(tp)) { printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n", dev->name); } - giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - } - auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + bmcr = BMCR_ANENABLE | BMCR_ANRESTART; + + 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); + } + + mdio_write(ioaddr, MII_ADVERTISE, auto_nego); + mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); + } else { + giga_ctrl = 0; + + if (speed == SPEED_10) + bmcr = 0; + else if (speed == SPEED_100) + bmcr = BMCR_SPEED100; + else + return -EINVAL; + + if (duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; - 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); } tp->phy_1000_ctrl_reg = giga_ctrl; - mdio_write(ioaddr, MII_ADVERTISE, auto_nego); - mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); - mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); + mdio_write(ioaddr, MII_BMCR, bmcr); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) { + mdio_write(ioaddr, 0x17, 0x2138); + mdio_write(ioaddr, 0x0e, 0x0260); + } else { + mdio_write(ioaddr, 0x17, 0x2108); + mdio_write(ioaddr, 0x0e, 0x0000); + } + } + return 0; } -- cgit v0.10.2 From aa5aec888585fedcda7cfffc20f75240ad1cb42d Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Tue, 19 May 2009 09:18:34 +0000 Subject: ixgbe: Add semaphore access for PHY initialization for 82599 The SFP+ NIC (device id 0x10fb) needs a semaphore to serialize PHY access, so our PHY init code must honor that same semaphore. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 39d7b64..fef7397 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -109,6 +109,13 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) if (ret_val != 0) goto setup_sfp_out; + /* PHY config will finish before releasing the semaphore */ + ret_val = ixgbe_acquire_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + if (ret_val != 0) { + ret_val = IXGBE_ERR_SWFW_SYNC; + goto setup_sfp_out; + } + hw->eeprom.ops.read(hw, ++data_offset, &data_value); while (data_value != 0xffff) { IXGBE_WRITE_REG(hw, IXGBE_CORECTL, data_value); @@ -119,6 +126,11 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000102); IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000b1d); IXGBE_WRITE_FLUSH(hw); + + /* Release the semaphore */ + ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + /* Delay obtaining semaphore again to allow FW access */ + msleep(hw->eeprom.semaphore_delay); } setup_sfp_out: -- cgit v0.10.2 From 537d58a00a8756189b10ffc1309c0131d57b6320 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Tue, 19 May 2009 09:18:51 +0000 Subject: ixgbe: Change Direct Attach Twinax cable detection for SFP+ NICs The SFF specification for Direct Attach cable detection has now been ratified. Previously, DA cable detect was looking at the Twinaxial bit in byte 9 of the SFP+ EEPROM. The spec now defines active and passive DA cables in byte 8 of the SFP+ EEPROM. This patch changes the cable detection for both 82598 and 82599 SFP+ adapters to conform to the new spec. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 6d385ea..8210b49 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -527,7 +527,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) u8 comp_codes_1g = 0; u8 comp_codes_10g = 0; u8 oui_bytes[3] = {0, 0, 0}; - u8 transmission_media = 0; + u8 cable_tech = 0; u16 enforce_sfp = 0; status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, @@ -543,8 +543,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) &comp_codes_1g); hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); - hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA, - &transmission_media); + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_CABLE_TECHNOLOGY, + &cable_tech); /* ID Module * ========= @@ -557,7 +557,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) * 6 SFP_SR/LR_CORE1 - 82599-specific */ if (hw->mac.type == ixgbe_mac_82598EB) { - if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) hw->phy.sfp_type = ixgbe_sfp_type_da_cu; else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) hw->phy.sfp_type = ixgbe_sfp_type_sr; @@ -566,7 +566,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) else hw->phy.sfp_type = ixgbe_sfp_type_unknown; } else if (hw->mac.type == ixgbe_mac_82599EB) { - if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) if (hw->bus.lan_id == 0) hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; @@ -621,8 +621,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) switch (vendor_oui) { case IXGBE_SFF_VENDOR_OUI_TYCO: - if (transmission_media & - IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) hw->phy.type = ixgbe_phy_tw_tyco; break; case IXGBE_SFF_VENDOR_OUI_FTL: @@ -635,8 +634,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.type = ixgbe_phy_sfp_intel; break; default: - if (transmission_media & - IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) hw->phy.type = ixgbe_phy_tw_unknown; else hw->phy.type = ixgbe_phy_sfp_unknown; @@ -644,8 +642,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) } } - /* All DA cables are supported */ - if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) { + /* All passive DA cables are supported */ + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { status = 0; goto out; } diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index c9964b7..9b700f5 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -39,10 +39,10 @@ #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 +#define IXGBE_SFF_CABLE_TECHNOLOGY 0x8 /* Bitmasks */ -#define IXGBE_SFF_TWIN_AX_CAPABLE 0x80 +#define IXGBE_SFF_DA_PASSIVE_CABLE 0x4 #define IXGBE_SFF_1GBASESX_CAPABLE 0x1 #define IXGBE_SFF_1GBASELX_CAPABLE 0x2 #define IXGBE_SFF_10GBASESR_CAPABLE 0x10 -- cgit v0.10.2 From 0cefafadbbe3947fd97b7560a214eb486069faac Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 19 May 2009 09:19:11 +0000 Subject: ixgbe: Cleanup feature setup code to make the code more readable This is purely a cleanup patch. This collapses some of the code required when we configure our Tx and Rx feature sets, and makes the code more readable and maintainable. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d342619..3d5f7f5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1747,10 +1747,11 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) u32 srrctl; int queue0 = 0; unsigned long mask; + struct ixgbe_ring_feature *feature = adapter->ring_feature; if (adapter->hw.mac.type == ixgbe_mac_82599EB) { if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - int dcb_i = adapter->ring_feature[RING_F_DCB].indices; + int dcb_i = feature[RING_F_DCB].indices; if (dcb_i == 8) queue0 = index >> 4; else if (dcb_i == 4) @@ -1773,7 +1774,7 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) queue0 = index; } } else { - mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask; + mask = (unsigned long) feature[RING_F_RSS].mask; queue0 = index & mask; index = index & mask; } @@ -1804,6 +1805,36 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl); } +static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter) +{ + u32 mrqc = 0; + int mask; + + if (!(adapter->hw.mac.type == ixgbe_mac_82599EB)) + return mrqc; + + mask = adapter->flags & (IXGBE_FLAG_RSS_ENABLED +#ifdef CONFIG_IXGBE_DCB + | IXGBE_FLAG_DCB_ENABLED +#endif + ); + + switch (mask) { + case (IXGBE_FLAG_RSS_ENABLED): + mrqc = IXGBE_MRQC_RSSEN; + break; +#ifdef CONFIG_IXGBE_DCB + case (IXGBE_FLAG_DCB_ENABLED): + mrqc = IXGBE_MRQC_RT8TCEN; + break; +#endif /* CONFIG_IXGBE_DCB */ + default: + break; + } + + return mrqc; +} + /** * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset * @adapter: board private structure @@ -1877,8 +1908,10 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); - /* Setup the HW Rx Head and Tail Descriptor Pointers and - * the Base and Length of the Rx Descriptor Ring */ + /* + * Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring + */ for (i = 0; i < adapter->num_rx_queues; i++) { rdba = adapter->rx_ring[i].dma; j = adapter->rx_ring[i].reg_idx; @@ -1922,23 +1955,8 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) } /* Program MRQC for the distribution of queues */ - if (hw->mac.type == ixgbe_mac_82599EB) { - int mask = adapter->flags & ( - IXGBE_FLAG_RSS_ENABLED - | IXGBE_FLAG_DCB_ENABLED - ); + mrqc = ixgbe_setup_mrqc(adapter); - switch (mask) { - case (IXGBE_FLAG_RSS_ENABLED): - mrqc = IXGBE_MRQC_RSSEN; - break; - case (IXGBE_FLAG_DCB_ENABLED): - mrqc = IXGBE_MRQC_RT8TCEN; - break; - default: - break; - } - } if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { /* Fill out redirection table */ for (i = 0, j = 0; i < 128; i++, j++) { @@ -2842,17 +2860,15 @@ static void ixgbe_reset_task(struct work_struct *work) static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter) { bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_DCB]; - if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - adapter->ring_feature[RING_F_DCB].mask = 0x7 << 3; - adapter->num_rx_queues = - adapter->ring_feature[RING_F_DCB].indices; - adapter->num_tx_queues = - adapter->ring_feature[RING_F_DCB].indices; - ret = true; - } else { - ret = false; - } + if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) + return ret; + + f->mask = 0x7 << 3; + adapter->num_rx_queues = f->indices; + adapter->num_tx_queues = f->indices; + ret = true; return ret; } @@ -2869,13 +2885,12 @@ static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter) static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) { bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_RSS]; if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { - adapter->ring_feature[RING_F_RSS].mask = 0xF; - adapter->num_rx_queues = - adapter->ring_feature[RING_F_RSS].indices; - adapter->num_tx_queues = - adapter->ring_feature[RING_F_RSS].indices; + f->mask = 0xF; + adapter->num_rx_queues = f->indices; + adapter->num_tx_queues = f->indices; ret = true; } else { ret = false; -- cgit v0.10.2 From ab35cd4b8f42b5e4a9338949581a510e98503b28 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 19 May 2009 15:16:34 -0700 Subject: sch_teql: Use net_device internal stats We can slightly reduce size of teqlN structure, not duplicating stats structure in teql_master but using stats field from net_device.stats for tx_errors and from netdev_queue for tx_bytes/tx_packets/tx_dropped values. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 3b64182..428a5ef 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -58,7 +58,6 @@ struct teql_master struct net_device *dev; struct Qdisc *slaves; struct list_head master_list; - struct net_device_stats stats; }; struct teql_sched_data @@ -272,6 +271,7 @@ static inline int teql_resolve(struct sk_buff *skb, static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev) { struct teql_master *master = netdev_priv(dev); + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); struct Qdisc *start, *q; int busy; int nores; @@ -311,8 +311,8 @@ restart: __netif_tx_unlock(slave_txq); master->slaves = NEXT_SLAVE(q); netif_wake_queue(dev); - master->stats.tx_packets++; - master->stats.tx_bytes += length; + txq->tx_packets++; + txq->tx_bytes += length; return 0; } __netif_tx_unlock(slave_txq); @@ -339,10 +339,10 @@ restart: netif_stop_queue(dev); return 1; } - master->stats.tx_errors++; + dev->stats.tx_errors++; drop: - master->stats.tx_dropped++; + txq->tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -395,12 +395,6 @@ static int teql_master_close(struct net_device *dev) return 0; } -static struct net_device_stats *teql_master_stats(struct net_device *dev) -{ - struct teql_master *m = netdev_priv(dev); - return &m->stats; -} - static int teql_master_mtu(struct net_device *dev, int new_mtu) { struct teql_master *m = netdev_priv(dev); @@ -425,7 +419,6 @@ static const struct net_device_ops teql_netdev_ops = { .ndo_open = teql_master_open, .ndo_stop = teql_master_close, .ndo_start_xmit = teql_master_xmit, - .ndo_get_stats = teql_master_stats, .ndo_change_mtu = teql_master_mtu, }; -- cgit v0.10.2 From 3a0c7d2d2bc61e510e900cfbb99c42d4eef2a443 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 19 May 2009 10:15:32 +0000 Subject: myri10ge: allow LRO to be enabled via ethtool Allow myri10ge LRO to be enabled/disabled via ethtool (and by the stack for packet forwarding). Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 140794a..dfd0994 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1300,7 +1300,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, remainder -= MYRI10GE_ALLOC_SIZE; } - if (mgp->csum_flag && myri10ge_lro) { + if (dev->features & NETIF_F_LRO) { rx_frags[0].page_offset += MXGEFW_PAD; rx_frags[0].size -= MXGEFW_PAD; len -= MXGEFW_PAD; @@ -1716,12 +1716,17 @@ static u32 myri10ge_get_rx_csum(struct net_device *netdev) static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) { struct myri10ge_priv *mgp = netdev_priv(netdev); + int err = 0; if (csum_enabled) mgp->csum_flag = MXGEFW_FLAGS_CKSUM; - else + else { + u32 flags = ethtool_op_get_flags(netdev); + err = ethtool_op_set_flags(netdev, (flags & ~ETH_FLAG_LRO)); mgp->csum_flag = 0; - return 0; + + } + return err; } static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) @@ -1904,7 +1909,9 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .get_sset_count = myri10ge_get_sset_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, .set_msglevel = myri10ge_set_msglevel, - .get_msglevel = myri10ge_get_msglevel + .get_msglevel = myri10ge_get_msglevel, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags }; static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) @@ -3910,6 +3917,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; + if (myri10ge_lro) + netdev->features |= NETIF_F_LRO; /* make sure we can get an irq, and that MSI can be * setup (if available). Also ensure netdev->irq -- cgit v0.10.2 From e5488ce56995e987a0cf9689e190b712a616a980 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 19 May 2009 10:16:11 +0000 Subject: myri10ge: update version to 1.5.0-1.415 Update myri10ge driver version to 1.5.0-1.415. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index dfd0994..c9a9aca 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.4-1.412" +#define MYRI10GE_VERSION_STR "1.5.0-1.415" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); -- cgit v0.10.2 From fd2120ca0da9108e53f8db2fe57ab74fca76fd56 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 19 May 2009 15:27:55 -0700 Subject: net: use NLMSG_DEFAULT_SIZE in nlmsg_new() allocations nlmsg_new() adds the size of the netlink header to the value that has been passed as parameter. If NLMSG_GOODSIZE is selected, we request an allocation of one memory page plus the size of the header. Instead, NLMSG_DEFAULT_SIZE should be used since it already substracts the size of the Netlink header. I have the impression that the similar naming in both constant is error prone when using it with nlmsg_new(). This is already documented in include/net/netlink.h Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index 2f05ec1..82c6118 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -87,7 +87,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) if (!dev) return -ENODEV; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { dev_put(dev); return -ENOMEM; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f0fec2f..ade40d50 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -388,7 +388,7 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(dev)) return PTR_ERR(dev); - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) goto out_err; @@ -716,7 +716,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) if (err) return err; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) goto out_err; @@ -989,7 +989,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) goto out; } - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { err = -ENOMEM; goto out; @@ -1600,7 +1600,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) goto out; @@ -1994,7 +1994,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) goto out; @@ -2310,7 +2310,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, goto out; /* Draw up a netlink message to send back */ - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { err = -ENOBUFS; goto out; @@ -2488,7 +2488,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) if (!cfg80211_regdomain) goto out; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { err = -ENOBUFS; goto out; @@ -3541,7 +3541,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) { struct sk_buff *msg; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3582,7 +3582,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3600,7 +3600,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3622,7 +3622,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3676,7 +3676,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!msg) return; @@ -3739,7 +3739,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!msg) return; @@ -3787,7 +3787,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); if (!msg) return; @@ -3822,7 +3822,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3862,7 +3862,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, void *hdr; struct nlattr *nl_freq; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!msg) return; -- cgit v0.10.2 From 9643f4551255ce8b3ef7470aaaf7f435a20f9182 Mon Sep 17 00:00:00 2001 From: Chris Friesen Date: Tue, 19 May 2009 15:31:50 -0700 Subject: ipv4: teach ipconfig about the MTU option in DHCP The DHCP spec allows the server to specify the MTU. This can be useful for netbooting with UDP-based NFS-root on a network using jumbo frames. This patch allows the kernel IP autoconfiguration to handle this option correctly. It would be possible to use initramfs and add a script to set the MTU, but that seems like a complicated solution if no initramfs is otherwise necessary, and would bloat the kernel image more than this code would. This patch was originally submitted to LKML in 2003 by Hans-Peter Jansen. Signed-off-by: Chris Friesen Signed-off-by: David S. Miller diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 88bf051..f8d04c2 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -160,6 +160,9 @@ static char user_dev_name[IFNAMSIZ] __initdata = { 0, }; /* Protocols supported by available interfaces */ static int ic_proto_have_if __initdata = 0; +/* MTU for boot device */ +static int ic_dev_mtu __initdata = 0; + #ifdef IPCONFIG_DYNAMIC static DEFINE_SPINLOCK(ic_recv_lock); static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */ @@ -286,7 +289,7 @@ set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) sin->sin_port = port; } -static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) +static int __init ic_devinet_ioctl(unsigned int cmd, struct ifreq *arg) { int res; @@ -297,6 +300,17 @@ static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) return res; } +static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) +{ + int res; + + mm_segment_t oldfs = get_fs(); + set_fs(get_ds()); + res = dev_ioctl(&init_net, cmd, (struct ifreq __user *) arg); + set_fs(oldfs); + return res; +} + static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg) { int res; @@ -321,20 +335,31 @@ static int __init ic_setup_if(void) memset(&ir, 0, sizeof(ir)); strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name); set_sockaddr(sin, ic_myaddr, 0); - if ((err = ic_dev_ioctl(SIOCSIFADDR, &ir)) < 0) { + if ((err = ic_devinet_ioctl(SIOCSIFADDR, &ir)) < 0) { printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err); return -1; } set_sockaddr(sin, ic_netmask, 0); - if ((err = ic_dev_ioctl(SIOCSIFNETMASK, &ir)) < 0) { + if ((err = ic_devinet_ioctl(SIOCSIFNETMASK, &ir)) < 0) { printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err); return -1; } set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); - if ((err = ic_dev_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { + if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err); return -1; } + /* Handle the case where we need non-standard MTU on the boot link (a network + * using jumbo frames, for instance). If we can't set the mtu, don't error + * out, we'll try to muddle along. + */ + if (ic_dev_mtu != 0) { + strcpy(ir.ifr_name, ic_dev->name); + ir.ifr_mtu = ic_dev_mtu; + if ((err = ic_dev_ioctl(SIOCSIFMTU, &ir)) < 0) + printk(KERN_ERR "IP-Config: Unable to set interface mtu to %d (%d).\n", + ic_dev_mtu, err); + } return 0; } @@ -623,6 +648,7 @@ ic_dhcp_init_options(u8 *options) 12, /* Host name */ 15, /* Domain name */ 17, /* Boot path */ + 26, /* MTU */ 40, /* NIS domain name */ }; @@ -798,6 +824,7 @@ static void __init ic_do_bootp_ext(u8 *ext) { u8 servers; int i; + u16 mtu; #ifdef IPCONFIG_DEBUG u8 *c; @@ -837,6 +864,10 @@ static void __init ic_do_bootp_ext(u8 *ext) if (!root_server_path[0]) ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); break; + case 26: /* Interface MTU */ + memcpy(&mtu, ext+1, sizeof(mtu)); + ic_dev_mtu = ntohs(mtu); + break; case 40: /* NIS Domain name (_not_ DNS) */ ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN); break; @@ -1403,6 +1434,8 @@ static int __init ip_auto_config(void) printk(",\n bootserver=%pI4", &ic_servaddr); printk(", rootserver=%pI4", &root_server_addr); printk(", rootpath=%s", root_server_path); + if (ic_dev_mtu) + printk(", mtu=%d", ic_dev_mtu); printk("\n"); #endif /* !SILENT */ -- cgit v0.10.2 From 8db99e5717507729a9eb49108facb7e528340376 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Tue, 19 May 2009 12:56:48 +0000 Subject: sit: Fail to create tunnel, if it already exists When locating the tunnel, do not continue if it is found. Otherwise a different tunnel with similar configuration would be returned and parts could be overwritten. Signed-off-by: Sascha Hlusiak Signed-off-by: David S. Miller diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 664ab82..e625041 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -165,8 +165,13 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, struct sit_net *sitn = net_generic(net, sit_net_id); for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { - if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) - return t; + if (local == t->parms.iph.saddr && + remote == t->parms.iph.daddr) { + if (create) + return NULL; + else + return t; + } } if (!create) goto failed; -- cgit v0.10.2 From 4fddbf5d7854b0a615c6481988895016f5d038d2 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Tue, 19 May 2009 12:56:49 +0000 Subject: sit: strictly restrict incoming traffic to tunnel link device Check link device when looking up a tunnel. When a tunnel is linked to a interface, traffic from a different interface must not reach the tunnel. This also allows creating of multiple tunnels with the same endpoints, if the link device differs. Signed-off-by: Sascha Hlusiak Signed-off-by: David S. Miller diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e625041..dfedd56 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -80,7 +80,7 @@ struct sit_net { static DEFINE_RWLOCK(ipip6_lock); static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, - __be32 remote, __be32 local) + struct net_device *dev, __be32 remote, __be32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -89,18 +89,25 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) + remote == t->parms.iph.daddr && + (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (t->dev->flags & IFF_UP)) return t; } for (t = sitn->tunnels_r[h0]; t; t = t->next) { - if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) + if (remote == t->parms.iph.daddr && + (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (t->dev->flags & IFF_UP)) return t; } for (t = sitn->tunnels_l[h1]; t; t = t->next) { - if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) + if (local == t->parms.iph.saddr && + (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (t->dev->flags & IFF_UP)) return t; } - if ((t = sitn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) + t = sitn->tunnels_wc[0]; + if ((t != NULL) && (t->dev->flags & IFF_UP)) return t; return NULL; } @@ -166,7 +173,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr) { + remote == t->parms.iph.daddr && + parms->link == t->parms.link) { if (create) return NULL; else @@ -451,7 +459,10 @@ static int ipip6_err(struct sk_buff *skb, u32 info) err = -ENOENT; read_lock(&ipip6_lock); - t = ipip6_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); + t = ipip6_tunnel_lookup(dev_net(skb->dev), + skb->dev, + iph->daddr, + iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -486,8 +497,9 @@ static int ipip6_rcv(struct sk_buff *skb) iph = ip_hdr(skb); read_lock(&ipip6_lock); - if ((tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), - iph->saddr, iph->daddr)) != NULL) { + tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, + iph->saddr, iph->daddr); + if (tunnel != NULL) { secpath_reset(skb); skb->mac_header = skb->network_header; skb_reset_network_header(skb); -- cgit v0.10.2 From 4b2796017487f3c1e423b8e1ada6c94c0a8ea815 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Tue, 19 May 2009 12:56:50 +0000 Subject: sit: ipip6_tunnel_del_prl: return err Typo. When deleting a PRL entry, return status to userspace instead of success. Signed-off-by: Sascha Hlusiak Signed-off-by: David S. Miller diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index dfedd56..3fd0600 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -368,7 +368,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) } out: write_unlock(&ipip6_lock); - return 0; + return err; } static int -- cgit v0.10.2 From 9af28511be10e175eb0cabb2ba5cfafe77408d84 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Tue, 19 May 2009 12:56:51 +0000 Subject: addrconf: refuse isatap eui64 for INADDR_ANY A tunnel with no local ipv4 endpoint would otherwise use the ISATAP linklocal address fe80::5efe:0:0, which is invalid. Rather not add a linklocal address at all. Signed-off-by: Sascha Hlusiak Signed-off-by: David S. Miller diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9eb61c7..31938e5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1520,6 +1520,8 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) int __ipv6_isatap_ifid(u8 *eui, __be32 addr) { + if (addr == 0) + return -1; eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) || ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) || ipv4_is_private_172(addr) || ipv4_is_test_192(addr) || -- cgit v0.10.2 From 645069299a1c7358cf7330afe293f07552f11a5d Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Tue, 19 May 2009 12:56:52 +0000 Subject: sit: stateless autoconf for isatap be sent periodically. The rs_delay can be speficied when adding the PRL entry and defaults to 15 minutes. The RS is sent from every link local adress that's assigned to the tunnel interface. It's directed to the (guessed) linklocal address of the router and is sent through the tunnel. Better: send to ff02::2 encapsuled in unicast directed to router-v4. Signed-off-by: Sascha Hlusiak Signed-off-by: David S. Miller diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 5a9aae4..5eb9b0f 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -44,7 +44,7 @@ struct ip_tunnel_prl { __u16 flags; __u16 __reserved; __u32 datalen; - __u32 __reserved2; + __u32 rs_delay; /* data follows */ }; diff --git a/include/net/ipip.h b/include/net/ipip.h index fdf9bd7..5d3036f 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -28,11 +28,18 @@ struct ip_tunnel unsigned int prl_count; /* # of entries in PRL */ }; +/* ISATAP: default interval between RS in secondy */ +#define IPTUNNEL_RS_DEFAULT_DELAY (900) + struct ip_tunnel_prl_entry { struct ip_tunnel_prl_entry *next; __be32 addr; u16 flags; + unsigned long rs_delay; + struct timer_list rs_timer; + struct ip_tunnel *tunnel; + spinlock_t lock; }; #define IPTUNNEL_XMIT() do { \ diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ab65cc5..e09f12e 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -658,6 +658,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, &icmp6h, NULL, send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); } +EXPORT_SYMBOL(ndisc_send_rs); static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 3fd0600..b3a59bd 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -15,6 +15,7 @@ * Roger Venning : 6to4 support * Nate Thompson : 6to4 support * Fred Templin : isatap support + * Sascha Hlusiak : stateless autoconf for isatap */ #include @@ -222,6 +223,44 @@ failed: return NULL; } +static void ipip6_tunnel_rs_timer(unsigned long data) +{ + struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *) data; + struct inet6_dev *ifp; + struct inet6_ifaddr *addr; + + spin_lock(&p->lock); + ifp = __in6_dev_get(p->tunnel->dev); + + read_lock_bh(&ifp->lock); + for (addr = ifp->addr_list; addr; addr = addr->if_next) { + struct in6_addr rtr; + + if (!(ipv6_addr_type(&addr->addr) & IPV6_ADDR_LINKLOCAL)) + continue; + + /* Send RS to guessed linklocal address of router + * + * Better: send to ff02::2 encapsuled in unicast directly + * to router-v4 instead of guessing the v6 address. + * + * Cisco/Windows seem to not set the u/l bit correctly, + * so we won't guess right. + */ + ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0); + if (!__ipv6_isatap_ifid(rtr.s6_addr + 8, + p->addr)) { + ndisc_send_rs(p->tunnel->dev, &addr->addr, &rtr); + } + } + read_unlock_bh(&ifp->lock); + + mod_timer(&p->rs_timer, jiffies + HZ * p->rs_delay); + spin_unlock(&p->lock); + + return; +} + static struct ip_tunnel_prl_entry * __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) { @@ -280,6 +319,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, continue; kp[c].addr = prl->addr; kp[c].flags = prl->flags; + kp[c].rs_delay = prl->rs_delay; c++; if (kprl.addr != htonl(INADDR_ANY)) break; @@ -329,11 +369,23 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) } p->next = t->prl; + p->tunnel = t; t->prl = p; t->prl_count++; + + spin_lock_init(&p->lock); + setup_timer(&p->rs_timer, ipip6_tunnel_rs_timer, (unsigned long) p); update: p->addr = a->addr; p->flags = a->flags; + p->rs_delay = a->rs_delay; + if (p->rs_delay == 0) + p->rs_delay = IPTUNNEL_RS_DEFAULT_DELAY; + spin_lock(&p->lock); + del_timer(&p->rs_timer); + if (p->flags & PRL_DEFAULT) + mod_timer(&p->rs_timer, jiffies + 1); + spin_unlock(&p->lock); out: write_unlock(&ipip6_lock); return err; @@ -352,6 +404,9 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) if ((*p)->addr == a->addr) { x = *p; *p = x->next; + spin_lock(&x->lock); + del_timer(&x->rs_timer); + spin_unlock(&x->lock); kfree(x); t->prl_count--; goto out; @@ -362,6 +417,9 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) while (t->prl) { x = t->prl; t->prl = t->prl->next; + spin_lock(&x->lock); + del_timer(&x->rs_timer); + spin_unlock(&x->lock); kfree(x); t->prl_count--; } -- cgit v0.10.2 From 97bc54152e3a91dd2dc297e8a084c05e93527e60 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 19 May 2009 16:19:08 -0700 Subject: sfc: Remove lro module parameter GRO/LRO can be controlled through ethtool so this is unnecessary. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index bde8b7a..343e8da1 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -50,16 +50,6 @@ static struct workqueue_struct *reset_workqueue; *************************************************************************/ /* - * Enable large receive offload (LRO) aka soft segment reassembly (SSR) - * - * This sets the default for new devices. It can be controlled later - * using ethtool. - */ -static int lro = true; -module_param(lro, int, 0644); -MODULE_PARM_DESC(lro, "Large receive offload acceleration"); - -/* * Use separate channels for TX and RX events * * Set this to 1 to use separate channels for TX and RX. It allows us @@ -2167,9 +2157,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, if (!net_dev) return -ENOMEM; net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_TSO); - if (lro) - net_dev->features |= NETIF_F_GRO; + NETIF_F_HIGHDMA | NETIF_F_TSO | + NETIF_F_GRO); /* 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); -- cgit v0.10.2 From 038659e7c6b385065cb223872771ac437ef70b62 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 2 May 2009 00:37:17 -0400 Subject: cfg80211: Process regulatory max bandwidth checks for HT40 We are not correctly listening to the regulatory max bandwidth settings. To actually make use of it we need to redesign things a bit. This patch does the work for that. We do this to so we can obey to regulatory rules accordingly for use of HT40. We end up dealing with HT40 by having two passes for each channel. The first check will see if a 20 MHz channel fits into the channel's center freq on a given frequency range. We check for a 20 MHz banwidth channel as that is the maximum an individual channel will use, at least for now. The first pass will go ahead and check if the regulatory rule for that given center of frequency allows 40 MHz bandwidths and we use this to determine whether or not the channel supports HT40 or not. So to support HT40 you'll need at a regulatory rule that allows you to use 40 MHz channels but you're channel must also be enabled and support 20 MHz by itself. The second pass is done after we do the regulatory checks over an device's supported channel list. On each channel we'll check if the control channel and the extension both: o exist o are enabled o regulatory allows 40 MHz bandwidth on its frequency range This work allows allows us to idependently check for HT40- and HT40+. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index fdf07c8..7a89f9f 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -200,8 +200,10 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, continue; if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - r = freq_reg_info(wiphy, ch->center_freq, - &bandwidth, ®_rule); + r = freq_reg_info(wiphy, + ch->center_freq, + bandwidth, + ®_rule); if (r) continue; /* @@ -265,7 +267,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, */ ch = &sband->channels[11]; /* CH 12 */ - r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); if (!r) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) @@ -273,7 +275,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, } ch = &sband->channels[12]; /* CH 13 */ - r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); if (!r) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9e17a83..282d58d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -70,6 +70,9 @@ enum ieee80211_channel_flags { IEEE80211_CHAN_NO_FAT_BELOW = 1<<5, }; +#define IEEE80211_CHAN_NO_HT40 \ + (IEEE80211_CHAN_NO_FAT_ABOVE | IEEE80211_CHAN_NO_FAT_BELOW) + /** * struct ieee80211_channel - channel definition * @@ -1303,9 +1306,10 @@ extern void wiphy_apply_custom_regulatory( * freq_reg_info - get regulatory information for the given frequency * @wiphy: the wiphy for which we want to process this rule for * @center_freq: Frequency in KHz for which we want regulatory information for - * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one - * you can set this to 0. If this frequency is allowed we then set - * this value to the maximum allowed bandwidth. + * @desired_bw_khz: the desired max bandwidth you want to use per + * channel. Note that this is still 20 MHz if you want to use HT40 + * as HT40 makes use of two channels for its 40 MHz width bandwidth. + * If set to 0 we'll assume you want the standard 20 MHz. * @reg_rule: the regulatory rule which we have for this frequency * * Use this function to get the regulatory rule for a specific frequency on @@ -1320,7 +1324,9 @@ extern void wiphy_apply_custom_regulatory( * freq_in_rule_band() for our current definition of a band -- this is purely * subjective and right now its 802.11 specific. */ -extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, +extern int freq_reg_info(struct wiphy *wiphy, + u32 center_freq, + u32 desired_bw_khz, const struct ieee80211_reg_rule **reg_rule); /* diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 537af62..d897528 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -48,12 +48,6 @@ static struct regulatory_request *last_request; /* To trigger userspace events */ static struct platform_device *reg_pdev; -/* Keep the ordering from large to small */ -static u32 supported_bandwidths[] = { - MHZ_TO_KHZ(40), - MHZ_TO_KHZ(20), -}; - /* * Central wireless core regulatory domains, we only need two, * the current one and a world regulatory domain in case we have no @@ -435,19 +429,20 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) return true; } -/* Returns value in KHz */ -static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, - u32 freq) +static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, + u32 center_freq_khz, + u32 bw_khz) { - unsigned int i; - for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) { - u32 start_freq_khz = freq - supported_bandwidths[i]/2; - u32 end_freq_khz = freq + supported_bandwidths[i]/2; - if (start_freq_khz >= freq_range->start_freq_khz && - end_freq_khz <= freq_range->end_freq_khz) - return supported_bandwidths[i]; - } - return 0; + u32 start_freq_khz, end_freq_khz; + + start_freq_khz = center_freq_khz - (bw_khz/2); + end_freq_khz = center_freq_khz + (bw_khz/2); + + if (start_freq_khz >= freq_range->start_freq_khz && + end_freq_khz <= freq_range->end_freq_khz) + return true; + + return false; } /** @@ -847,14 +842,17 @@ static u32 map_regdom_flags(u32 rd_flags) static int freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, - u32 *bandwidth, + u32 desired_bw_khz, const struct ieee80211_reg_rule **reg_rule, const struct ieee80211_regdomain *custom_regd) { int i; bool band_rule_found = false; const struct ieee80211_regdomain *regd; - u32 max_bandwidth = 0; + bool bw_fits = false; + + if (!desired_bw_khz) + desired_bw_khz = MHZ_TO_KHZ(20); regd = custom_regd ? custom_regd : cfg80211_regdomain; @@ -887,38 +885,54 @@ static int freq_reg_info_regd(struct wiphy *wiphy, if (!band_rule_found) band_rule_found = freq_in_rule_band(fr, center_freq); - max_bandwidth = freq_max_bandwidth(fr, center_freq); + bw_fits = reg_does_bw_fit(fr, + center_freq, + desired_bw_khz); - if (max_bandwidth && *bandwidth <= max_bandwidth) { + if (band_rule_found && bw_fits) { *reg_rule = rr; - *bandwidth = max_bandwidth; - break; + return 0; } } if (!band_rule_found) return -ERANGE; - return !max_bandwidth; + return -EINVAL; } EXPORT_SYMBOL(freq_reg_info); -int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, - const struct ieee80211_reg_rule **reg_rule) +int freq_reg_info(struct wiphy *wiphy, + u32 center_freq, + u32 desired_bw_khz, + const struct ieee80211_reg_rule **reg_rule) { assert_cfg80211_lock(); - return freq_reg_info_regd(wiphy, center_freq, - bandwidth, reg_rule, NULL); + return freq_reg_info_regd(wiphy, + center_freq, + desired_bw_khz, + reg_rule, + NULL); } +/* + * Note that right now we assume the desired channel bandwidth + * is always 20 MHz for each individual channel (HT40 uses 20 MHz + * per channel, the primary and the extension channel). To support + * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a + * new ieee80211_channel.target_bw and re run the regulatory check + * on the wiphy with the target_bw specified. Then we can simply use + * that below for the desired_bw_khz below. + */ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, unsigned int chan_idx) { int r; - u32 flags; - u32 max_bandwidth = 0; + u32 flags, bw_flags = 0; + u32 desired_bw_khz = MHZ_TO_KHZ(20); const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; + const struct ieee80211_freq_range *freq_range = NULL; struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; struct wiphy *request_wiphy = NULL; @@ -933,8 +947,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, flags = chan->orig_flags; - r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), - &max_bandwidth, ®_rule); + r = freq_reg_info(wiphy, + MHZ_TO_KHZ(chan->center_freq), + desired_bw_khz, + ®_rule); if (r) { /* @@ -977,6 +993,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, } power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; + + if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + bw_flags = IEEE80211_CHAN_NO_HT40; if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && @@ -987,19 +1007,19 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, * settings */ chan->flags = chan->orig_flags = - map_regdom_flags(reg_rule->flags); + map_regdom_flags(reg_rule->flags) | bw_flags; chan->max_antenna_gain = chan->orig_mag = (int) MBI_TO_DBI(power_rule->max_antenna_gain); - chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); chan->max_power = chan->orig_mpwr = (int) MBM_TO_DBM(power_rule->max_eirp); return; } - chan->flags = flags | map_regdom_flags(reg_rule->flags); + chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); chan->max_antenna_gain = min(chan->orig_mag, (int) MBI_TO_DBI(power_rule->max_antenna_gain)); - chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); if (chan->orig_mpwr) chan->max_power = min(chan->orig_mpwr, (int) MBM_TO_DBM(power_rule->max_eirp)); @@ -1156,6 +1176,93 @@ static void reg_process_beacons(struct wiphy *wiphy) wiphy_update_beacon_reg(wiphy); } +static bool is_ht40_not_allowed(struct ieee80211_channel *chan) +{ + if (!chan) + return true; + if (chan->flags & IEEE80211_CHAN_DISABLED) + return true; + /* This would happen when regulatory rules disallow HT40 completely */ + if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40))) + return true; + return false; +} + +static void reg_process_ht_flags_channel(struct wiphy *wiphy, + enum ieee80211_band band, + unsigned int chan_idx) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *channel; + struct ieee80211_channel *channel_before = NULL, *channel_after = NULL; + unsigned int i; + + assert_cfg80211_lock(); + + sband = wiphy->bands[band]; + BUG_ON(chan_idx >= sband->n_channels); + channel = &sband->channels[chan_idx]; + + if (is_ht40_not_allowed(channel)) { + channel->flags |= IEEE80211_CHAN_NO_HT40; + return; + } + + /* + * We need to ensure the extension channels exist to + * be able to use HT40- or HT40+, this finds them (or not) + */ + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *c = &sband->channels[i]; + if (c->center_freq == (channel->center_freq - 20)) + channel_before = c; + if (c->center_freq == (channel->center_freq + 20)) + channel_after = c; + } + + /* + * Please note that this assumes target bandwidth is 20 MHz, + * if that ever changes we also need to change the below logic + * to include that as well. + */ + if (is_ht40_not_allowed(channel_before)) + channel->flags |= IEEE80211_CHAN_NO_FAT_BELOW; + else + channel->flags &= ~IEEE80211_CHAN_NO_FAT_BELOW; + + if (is_ht40_not_allowed(channel_after)) + channel->flags |= IEEE80211_CHAN_NO_FAT_ABOVE; + else + channel->flags &= ~IEEE80211_CHAN_NO_FAT_ABOVE; +} + +static void reg_process_ht_flags_band(struct wiphy *wiphy, + enum ieee80211_band band) +{ + unsigned int i; + struct ieee80211_supported_band *sband; + + BUG_ON(!wiphy->bands[band]); + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) + reg_process_ht_flags_channel(wiphy, band, i); +} + +static void reg_process_ht_flags(struct wiphy *wiphy) +{ + enum ieee80211_band band; + + if (!wiphy) + return; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (wiphy->bands[band]) + reg_process_ht_flags_band(wiphy, band); + } + +} + void wiphy_update_regulatory(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { @@ -1169,6 +1276,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, } out: reg_process_beacons(wiphy); + reg_process_ht_flags(wiphy); if (wiphy->reg_notifier) wiphy->reg_notifier(wiphy, last_request); } @@ -1179,9 +1287,11 @@ static void handle_channel_custom(struct wiphy *wiphy, const struct ieee80211_regdomain *regd) { int r; - u32 max_bandwidth = 0; + u32 desired_bw_khz = MHZ_TO_KHZ(20); + u32 bw_flags = 0; const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; + const struct ieee80211_freq_range *freq_range = NULL; struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; @@ -1191,8 +1301,11 @@ static void handle_channel_custom(struct wiphy *wiphy, BUG_ON(chan_idx >= sband->n_channels); chan = &sband->channels[chan_idx]; - r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), - &max_bandwidth, ®_rule, regd); + r = freq_reg_info_regd(wiphy, + MHZ_TO_KHZ(chan->center_freq), + desired_bw_khz, + ®_rule, + regd); if (r) { chan->flags = IEEE80211_CHAN_DISABLED; @@ -1200,10 +1313,14 @@ static void handle_channel_custom(struct wiphy *wiphy, } power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; + + if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + bw_flags = IEEE80211_CHAN_NO_HT40; - chan->flags |= map_regdom_flags(reg_rule->flags); + chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); - chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); } -- cgit v0.10.2 From 689da1b3b8b37ff41e79f3fb973c06cdfeef12e5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 2 May 2009 00:37:18 -0400 Subject: wireless: rename IEEE80211_CHAN_NO_FAT_* to HT40-/+ This is more consistent with our nl80211 naming convention for HT40-/+. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5393fb3f..6c1b171 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -603,10 +603,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) return !(ch_info->fat_extension_channel & - IEEE80211_CHAN_NO_FAT_ABOVE); + IEEE80211_CHAN_NO_HT40PLUS); else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) return !(ch_info->fat_extension_channel & - IEEE80211_CHAN_NO_FAT_BELOW); + IEEE80211_CHAN_NO_HT40MINUS); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 401438a..b400bd5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -481,8 +481,8 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* First write that fat is not enabled, and then enable * one by one */ ch_info->fat_extension_channel = - (IEEE80211_CHAN_NO_FAT_ABOVE | - IEEE80211_CHAN_NO_FAT_BELOW); + (IEEE80211_CHAN_NO_HT40PLUS | + IEEE80211_CHAN_NO_HT40MINUS); if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " @@ -561,7 +561,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) fat_extension_chan = 0; else fat_extension_chan = - IEEE80211_CHAN_NO_FAT_BELOW; + IEEE80211_CHAN_NO_HT40MINUS; /* Set up driver's info for lower half */ iwl_set_fat_chan_info(priv, ieeeband, @@ -573,7 +573,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) iwl_set_fat_chan_info(priv, ieeeband, (eeprom_ch_index[ch] + 4), &(eeprom_ch_info[ch]), - IEEE80211_CHAN_NO_FAT_ABOVE); + IEEE80211_CHAN_NO_HT40PLUS); } } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 282d58d..7391ad1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -56,9 +56,9 @@ enum ieee80211_band { * on this channel. * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. - * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel + * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel * is not permitted. - * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel + * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel * is not permitted. */ enum ieee80211_channel_flags { @@ -66,12 +66,12 @@ enum ieee80211_channel_flags { IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, IEEE80211_CHAN_NO_IBSS = 1<<2, IEEE80211_CHAN_RADAR = 1<<3, - IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4, - IEEE80211_CHAN_NO_FAT_BELOW = 1<<5, + IEEE80211_CHAN_NO_HT40PLUS = 1<<4, + IEEE80211_CHAN_NO_HT40MINUS = 1<<5, }; #define IEEE80211_CHAN_NO_HT40 \ - (IEEE80211_CHAN_NO_FAT_ABOVE | IEEE80211_CHAN_NO_FAT_BELOW) + (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) /** * struct ieee80211_channel - channel definition diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ae03068..da582b6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -349,13 +349,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { + if (flags & IEEE80211_CHAN_NO_HT40PLUS) { cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; cap &= ~IEEE80211_HT_CAP_SGI_40; } break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { + if (flags & IEEE80211_CHAN_NO_HT40MINUS) { cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; cap &= ~IEEE80211_HT_CAP_SGI_40; } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index d897528..48db569 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1226,14 +1226,14 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy, * to include that as well. */ if (is_ht40_not_allowed(channel_before)) - channel->flags |= IEEE80211_CHAN_NO_FAT_BELOW; + channel->flags |= IEEE80211_CHAN_NO_HT40MINUS; else - channel->flags &= ~IEEE80211_CHAN_NO_FAT_BELOW; + channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; if (is_ht40_not_allowed(channel_after)) - channel->flags |= IEEE80211_CHAN_NO_FAT_ABOVE; + channel->flags |= IEEE80211_CHAN_NO_HT40PLUS; else - channel->flags &= ~IEEE80211_CHAN_NO_FAT_ABOVE; + channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; } static void reg_process_ht_flags_band(struct wiphy *wiphy, -- cgit v0.10.2 From 768777ea1118f6ff3f1a013557e7bc4f5d2683a4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 2 May 2009 00:37:19 -0400 Subject: mac80211: check if HT40+/- is allowed before sending assoc We weren't checking this at all. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index da582b6..a1944b8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -121,10 +121,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - channel_type = NL80211_CHAN_HT40PLUS; + if (!(local->hw.conf.channel->flags & + IEEE80211_CHAN_NO_HT40PLUS)) + channel_type = NL80211_CHAN_HT40PLUS; break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - channel_type = NL80211_CHAN_HT40MINUS; + if (!(local->hw.conf.channel->flags & + IEEE80211_CHAN_NO_HT40MINUS)) + channel_type = NL80211_CHAN_HT40MINUS; break; } } -- cgit v0.10.2 From 294196ab22c91da974ba1f40d0a7cdcb0b3e6bc3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 2 May 2009 00:37:20 -0400 Subject: cfg80211: check allowed channel type upon userspace requests Thanks to nl80211 userspace can be very specific upon device configuration. Before processing the request for the new HT40 channel types (HT40- or HT40+) we need to ensure we can use them regulatory-wise. This wasn't required with wireless extensions as specifying the channel type wasn't not available and configuration was done towards the end implicitly upon association or reception of beacons from the AP. For the new nl80211 we have to check this when configuring the interfaces explicitly. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ade40d50..0e22b5f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -492,7 +492,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; struct ieee80211_channel *chan; struct ieee80211_sta_ht_cap *ht_cap; - u32 freq, sec_freq; + u32 freq; if (!rdev->ops->set_channel) { result = -EOPNOTSUPP; @@ -518,33 +518,28 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) goto bad_res; - if (channel_type == NL80211_CHAN_HT40MINUS) - sec_freq = freq - 20; - else if (channel_type == NL80211_CHAN_HT40PLUS) - sec_freq = freq + 20; - else - sec_freq = 0; - - ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; - - /* no HT capabilities */ - if (channel_type != NL80211_CHAN_NO_HT && - !ht_cap->ht_supported) + if (channel_type == NL80211_CHAN_HT40MINUS && + (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) + goto bad_res; + else if (channel_type == NL80211_CHAN_HT40PLUS && + (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) goto bad_res; - if (sec_freq) { - struct ieee80211_channel *schan; + /* + * At this point we know if that if HT40 was requested + * we are allowed to use it and the extension channel + * exists. + */ - /* no 40 MHz capabilities */ + ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; + + /* no HT capabilities or intolerant */ + if (channel_type != NL80211_CHAN_NO_HT) { + if (!ht_cap->ht_supported) + goto bad_res; if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) goto bad_res; - - schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); - - /* Secondary channel not allowed */ - if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) - goto bad_res; } result = rdev->ops->set_channel(&rdev->wiphy, chan, -- cgit v0.10.2 From 1ac61302dcd18880e28c29e5728cd4d0efeb5366 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 2 May 2009 00:37:21 -0400 Subject: mac80211/cfg80211: move wiphy specific debugfs entries to cfg80211 This moves the cfg80211 specific stuff to new cfg80211 debugfs entries. Non-mac80211 will also get these entries now. There were only 4 which we take: rts_threshold fragmentation_threshold short_retry_limit long_retry_limit Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e7682fe..11c7231 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -52,14 +52,6 @@ static const struct file_operations name## _ops = { \ DEBUGFS_READONLY_FILE(frequency, 20, "%d", local->hw.conf.channel->center_freq); -DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", - local->hw.wiphy->rts_threshold); -DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", - local->hw.wiphy->frag_threshold); -DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", - local->hw.wiphy->retry_short); -DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", - local->hw.wiphy->retry_long); DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", local->total_ps_buffered); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", @@ -303,10 +295,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.keys = debugfs_create_dir("keys", phyd); DEBUGFS_ADD(frequency); - DEBUGFS_ADD(rts_threshold); - DEBUGFS_ADD(fragmentation_threshold); - DEBUGFS_ADD(short_retry_limit); - DEBUGFS_ADD(long_retry_limit); DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(wep_iv); DEBUGFS_ADD(tsf); @@ -359,10 +347,6 @@ void debugfs_hw_add(struct ieee80211_local *local) void debugfs_hw_del(struct ieee80211_local *local) { DEBUGFS_DEL(frequency); - DEBUGFS_DEL(rts_threshold); - DEBUGFS_DEL(fragmentation_threshold); - DEBUGFS_DEL(short_retry_limit); - DEBUGFS_DEL(long_retry_limit); DEBUGFS_DEL(total_ps_buffered); DEBUGFS_DEL(wep_iv); DEBUGFS_DEL(tsf); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9d15147..3241e76 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -758,10 +758,6 @@ struct ieee80211_local { struct dentry *rcdir; struct dentry *rcname; struct dentry *frequency; - struct dentry *rts_threshold; - struct dentry *fragmentation_threshold; - struct dentry *short_retry_limit; - struct dentry *long_retry_limit; struct dentry *total_ps_buffered; struct dentry *wep_iv; struct dentry *tsf; diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 3c3bc9e..4500549 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -10,6 +10,14 @@ config CFG80211_REG_DEBUG If unsure, say N. +config CFG80211_DEBUGFS + bool "cfg80211 DebugFS entries" + depends on CFG80211 && DEBUG_FS + ---help--- + You can enable this if you want to debugfs entries for cfg80211. + + If unsure, say N. + config WIRELESS_OLD_REGULATORY bool "Old wireless static regulatory definitions" default n diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 14ea01c..f78c483 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o +cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/wireless/core.c b/net/wireless/core.c index 47c20eb..b6ef533 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -17,6 +17,7 @@ #include "nl80211.h" #include "core.h" #include "sysfs.h" +#include "debugfs.h" /* name for sysfs, %d is appended */ #define PHY_NAME "phy" @@ -375,6 +376,8 @@ int wiphy_register(struct wiphy *wiphy) nl80211_send_reg_change_event(&request); } + cfg80211_debugfs_drv_add(drv); + res = 0; out_unlock: mutex_unlock(&cfg80211_mutex); @@ -405,6 +408,8 @@ void wiphy_unregister(struct wiphy *wiphy) /* unlock again before freeing */ mutex_unlock(&drv->mtx); + cfg80211_debugfs_drv_del(drv); + /* If this device got a regulatory hint tell core its * free to listen now to a new shiny device regulatory hint */ reg_device_remove(wiphy); diff --git a/net/wireless/core.h b/net/wireless/core.h index f14b6c5..930a801 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include "reg.h" @@ -50,6 +51,16 @@ struct cfg80211_registered_device { struct cfg80211_scan_request *scan_req; /* protected by RTNL */ unsigned long suspend_at; +#ifdef CONFIG_MAC80211_DEBUGFS + /* Debugfs entries */ + struct wiphy_debugfsdentries { + struct dentry *rts_threshold; + struct dentry *fragmentation_threshold; + struct dentry *short_retry_limit; + struct dentry *long_retry_limit; + } debugfs; +#endif + /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c new file mode 100644 index 0000000..3211e0e --- /dev/null +++ b/net/wireless/debugfs.c @@ -0,0 +1,70 @@ +/* + * cfg80211 debugfs + * + * Copyright 2009 Luis R. Rodriguez + * Copyright 2007 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "core.h" +#include "debugfs.h" + +static int cfg80211_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wiphy *wiphy= file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = cfg80211_open_file_generic, \ +}; + +DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", + wiphy->rts_threshold) +DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", + wiphy->frag_threshold); +DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", + wiphy->retry_short) +DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", + wiphy->retry_long); + +#define DEBUGFS_ADD(name) \ + drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ + &drv->wiphy, &name## _ops); +#define DEBUGFS_DEL(name) \ + debugfs_remove(drv->debugfs.name); \ + drv->debugfs.name = NULL; + +void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) +{ + struct dentry *phyd = drv->wiphy.debugfsdir; + + DEBUGFS_ADD(rts_threshold); + DEBUGFS_ADD(fragmentation_threshold); + DEBUGFS_ADD(short_retry_limit); + DEBUGFS_ADD(long_retry_limit); +} + +void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) +{ + DEBUGFS_DEL(rts_threshold); + DEBUGFS_DEL(fragmentation_threshold); + DEBUGFS_DEL(short_retry_limit); + DEBUGFS_DEL(long_retry_limit); +} diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h new file mode 100644 index 0000000..c226983 --- /dev/null +++ b/net/wireless/debugfs.h @@ -0,0 +1,14 @@ +#ifndef __CFG80211_DEBUGFS_H +#define __CFG80211_DEBUGFS_H + +#ifdef CONFIG_CFG80211_DEBUGFS +void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv); +void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv); +#else +static inline +void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {} +static inline +void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {} +#endif + +#endif /* __CFG80211_DEBUGFS_H */ -- cgit v0.10.2 From 80a3511d70e8fc7ed3fe4417d7b0bf6c3f642f64 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 2 May 2009 00:39:30 -0400 Subject: cfg80211: add debugfs HT40 allow map Here's a screenshot of what this looks like with ath9k: mcgrof@pogo /debug/ieee80211/phy0 $ cat ht40allow_map 2412 HT40 + 2417 HT40 + 2422 HT40 + 2427 HT40 + 2432 HT40 -+ 2437 HT40 -+ 2442 HT40 -+ 2447 HT40 - 2452 HT40 - 2457 HT40 - 2462 HT40 - 2467 Disabled 2472 Disabled 2484 Disabled 5180 HT40 + 5200 HT40 -+ 5220 HT40 -+ 5240 HT40 -+ 5260 HT40 -+ 5280 HT40 -+ 5300 HT40 -+ 5320 HT40 - 5500 HT40 + 5520 HT40 -+ 5540 HT40 -+ 5560 HT40 -+ 5580 HT40 -+ 5600 HT40 -+ 5620 HT40 -+ 5640 HT40 -+ 5660 HT40 -+ 5680 HT40 -+ 5700 HT40 - 5745 HT40 + 5765 HT40 -+ 5785 HT40 -+ 5805 HT40 -+ 5825 HT40 - Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/core.h b/net/wireless/core.h index 930a801..88f234c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -58,6 +58,7 @@ struct cfg80211_registered_device { struct dentry *fragmentation_threshold; struct dentry *short_retry_limit; struct dentry *long_retry_limit; + struct dentry *ht40allow_map; } debugfs; #endif diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index 3211e0e..679ddfc 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c @@ -44,6 +44,65 @@ DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", wiphy->retry_long); +static int ht_print_chan(struct ieee80211_channel *chan, + char *buf, int buf_size, int offset) +{ + if (WARN_ON(offset > buf_size)) + return 0; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + return snprintf(buf + offset, + buf_size - offset, + "%d Disabled\n", + chan->center_freq); + + return snprintf(buf + offset, + buf_size - offset, + "%d HT40 %c%c\n", + chan->center_freq, + (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-', + (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? ' ' : '+'); +} + +static ssize_t ht40allow_map_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wiphy *wiphy = file->private_data; + char *buf; + unsigned int offset = 0, buf_size = PAGE_SIZE, i, r; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&cfg80211_mutex); + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + for (i = 0; i < sband->n_channels; i++) + offset += ht_print_chan(&sband->channels[i], + buf, buf_size, offset); + } + + mutex_unlock(&cfg80211_mutex); + + r = simple_read_from_buffer(user_buf, count, ppos, buf, offset); + + kfree(buf); + + return r; +} + +static const struct file_operations ht40allow_map_ops = { + .read = ht40allow_map_read, + .open = cfg80211_open_file_generic, +}; + #define DEBUGFS_ADD(name) \ drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ &drv->wiphy, &name## _ops); @@ -59,6 +118,7 @@ void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) DEBUGFS_ADD(fragmentation_threshold); DEBUGFS_ADD(short_retry_limit); DEBUGFS_ADD(long_retry_limit); + DEBUGFS_ADD(ht40allow_map); } void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) @@ -67,4 +127,5 @@ void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) DEBUGFS_DEL(fragmentation_threshold); DEBUGFS_DEL(short_retry_limit); DEBUGFS_DEL(long_retry_limit); + DEBUGFS_DEL(ht40allow_map); } -- cgit v0.10.2 From cccaec98a3ddbf20f22604f9ba405781c5f89f0e Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 14 May 2009 18:42:08 +0530 Subject: mac80211: Initialize RX's last received sequence number The STA may drop the very first frame if it happens to be a retried frame. This is because we maintian the last received sequence number per TID for QoS frames and it is initialized to zero through kzalloc during sta_info_alloc and the sequence number of the very first date frame received would be ZERO (as per IEEE 802.11-2007, 7.1.3.4.1). If the frame dropped happens to be an EAP Request Identity(very first frame from the AP), then wpa_supplicnat disconnects the STA and the whole procedure starts again. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a98ea27..3e4348f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -293,6 +293,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); + for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + sta->last_seq_ctrl[i] = cpu_to_le16(USHORT_MAX); + #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Allocated STA %pM\n", wiphy_name(local->hw.wiphy), sta->sta.addr); -- cgit v0.10.2 From 13bdcd90bbce7c07e0dda0ff31e9497b8cabf1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 14 May 2009 17:34:59 +0000 Subject: zd1211rw: Replace ZD_CS_MULTICAST with ZD_CS_NO_ACK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to my tests, all that ZD_CS_MULTICAST does is to disable retrying/waiting for an ACK. Reflect this by renaming the bit to ZD_CS_NO_ACK and setting it based on IEEE80211_TX_CTL_NO_ACK, instead of is_multicast_ether_addr. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6bdb170..40b07b9 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -420,9 +420,9 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; - /* Multicast */ - if (is_multicast_ether_addr(header->addr1)) - cs->control |= ZD_CS_MULTICAST; + /* No ACK expected (multicast, etc.) */ + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + cs->control |= ZD_CS_NO_ACK; /* PS-POLL */ if (ieee80211_is_pspoll(header->frame_control)) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 4c05d3e..7c27591 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -87,7 +87,7 @@ struct zd_ctrlset { /* zd_ctrlset control field */ #define ZD_CS_NEED_RANDOM_BACKOFF 0x01 -#define ZD_CS_MULTICAST 0x02 +#define ZD_CS_NO_ACK 0x02 #define ZD_CS_FRAME_TYPE_MASK 0x0c #define ZD_CS_DATA_FRAME 0x00 -- cgit v0.10.2 From 92778180f7fca7f7797de8020900a7fea175f7e3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 14 May 2009 21:15:36 +0300 Subject: mac80211: Cancel pending probereq poll on beacon RX While the probe request poll is expected to work, it looks like it does not always result in getting a response. The exact reason for this is unclear, but anyway, if we do receive a Beacon frame from our AP, there is no need to disconnect based on the probereq poll. This seems to help keep the connection bit more stable in cases where beacon loss is occurring semi-frequently. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a1944b8..47bc303 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1824,6 +1824,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) return; + if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: cancelling probereq poll due " + "to a received beacon\n", sdata->dev->name); + } +#endif + ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + } + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, len - baselen, &elems, -- cgit v0.10.2 From d8959fbfbad5f75c7df673aaf5112ba5e405ad34 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 14 May 2009 21:28:46 +0300 Subject: ath9k: Fix a check for multicast address for virtual wiphy The broadcast bit is in the first, not the last octet.. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b46badd..76abbbe 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -637,7 +637,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) } /* Send the frame to mac80211 */ - if (hdr->addr1[5] & 0x01) { + if (is_multicast_ether_addr(hdr->addr1)) { int i; /* * Deliver broadcast/multicast frames to all suitable -- cgit v0.10.2 From 9d64a3cfaf3edb548b68ef4eedbadbb875eaa10e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 14 May 2009 21:28:47 +0300 Subject: ath9k: Clean up RX processing a bit This makes use of the local fc variable in bit more places and uses a common helper macro. The part of RX process that delivers skb's to mac80211 is moved to a separate function in preparation for future changes that will need to do this from two places. The modifications here should not result in any functional changes. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 76abbbe..58bb26c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -473,6 +473,37 @@ void ath_flushrecv(struct ath_softc *sc) spin_unlock_bh(&sc->rx.rxflushlock); } +static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)skb->data; + + /* Send the frame to mac80211 */ + if (is_multicast_ether_addr(hdr->addr1)) { + int i; + /* + * Deliver broadcast/multicast frames to all suitable + * virtual wiphys. + */ + /* TODO: filter based on channel configuration */ + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + struct sk_buff *nskb; + if (aphy == NULL) + continue; + nskb = skb_copy(skb, GFP_ATOMIC); + if (nskb) + __ieee80211_rx(aphy->hw, nskb, rx_status); + } + __ieee80211_rx(sc->hw, skb, rx_status); + } else { + /* Deliver unicast frames based on receiver address */ + __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status); + } +} + int ath_rx_tasklet(struct ath_softc *sc, int flush) { #define PA2DESC(_sc, _pa) \ @@ -622,7 +653,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) + } else if (ieee80211_has_protected(fc) && !decrypt_error && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; @@ -631,35 +662,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) } if (ah->sw_mgmt_crypto && (rx_status.flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(hdr->frame_control)) { + ieee80211_is_mgmt(fc)) { /* Use software decrypt for management frames. */ rx_status.flag &= ~RX_FLAG_DECRYPTED; } - /* Send the frame to mac80211 */ - if (is_multicast_ether_addr(hdr->addr1)) { - int i; - /* - * Deliver broadcast/multicast frames to all suitable - * virtual wiphys. - */ - /* TODO: filter based on channel configuration */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - struct sk_buff *nskb; - if (aphy == NULL) - continue; - nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb) - __ieee80211_rx(aphy->hw, nskb, - &rx_status); - } - __ieee80211_rx(sc->hw, skb, &rx_status); - } else { - /* Deliver unicast frames based on receiver address */ - __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, - &rx_status); - } + ath_rx_send_to_mac80211(sc, skb, &rx_status); /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; -- cgit v0.10.2 From cc65965cbb24d2ca2bb70f26cac9d7243349e7e3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 14 May 2009 21:28:48 +0300 Subject: ath9k: Fix PS mode operation to receive buffered broadcast/multicast frames The previous implementation was moving back to NETWORK SLEEP state immediately after receiving a Beacon frame. This means that we are unlikely to receive all the buffered broadcast/multicast frames that would be sent after DTIM Beacon frames. Fix this by parsing the Beacon frame and remaining awake, if needed, to receive the buffered broadcast/multicast frames. The last buffered frame will trigger the move back into NETWORK SLEEP state. If the last broadcast/multicast frame is not received properly (or if the AP fails to send it), the next Beacon frame will work as a backup trigger for returning into NETWORK SLEEP. A new debug type, PS (debug=0x800 module parameter), is added to make it easier to debug potential power save issues in the future. Currently, this is only used for the Beacon frame and buffered broadcast/multicast receiving. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 10ffc94..3425662 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -515,6 +515,7 @@ struct ath_rfkill { #define SC_OP_LED_ON BIT(13) #define SC_OP_SCANNING BIT(14) #define SC_OP_TSF_RESET BIT(15) +#define SC_OP_WAIT_FOR_CAB BIT(16) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 23298b9..db845cf 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -29,6 +29,7 @@ enum ATH_DEBUG { ATH_DBG_BEACON = 0x00000100, ATH_DBG_CONFIG = 0x00000200, ATH_DBG_FATAL = 0x00000400, + ATH_DBG_PS = 0x00000800, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 58bb26c..72e9283 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -473,6 +473,112 @@ void ath_flushrecv(struct ath_softc *sc) spin_unlock_bh(&sc->rx.rxflushlock); } +static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) +{ + /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ + struct ieee80211_mgmt *mgmt; + u8 *pos, *end, id, elen; + struct ieee80211_tim_ie *tim; + + mgmt = (struct ieee80211_mgmt *)skb->data; + pos = mgmt->u.beacon.variable; + end = skb->data + skb->len; + + while (pos + 2 < end) { + id = *pos++; + elen = *pos++; + if (pos + elen > end) + break; + + if (id == WLAN_EID_TIM) { + if (elen < sizeof(*tim)) + break; + tim = (struct ieee80211_tim_ie *) pos; + if (tim->dtim_count != 0) + break; + return tim->bitmap_ctrl & 0x01; + } + + pos += elen; + } + + return false; +} + +static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) +{ + sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); + if (sc->hw->conf.flags & IEEE80211_CONF_PS) + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); +} + +static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt; + + if (skb->len < 24 + 8 + 2 + 2) + return; + + mgmt = (struct ieee80211_mgmt *)skb->data; + if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) + return; /* not from our current AP */ + + if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { + /* We are not in PS mode anymore; remain awake */ + DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " + "awake\n"); + sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); + return; + } + + if (ath_beacon_dtim_pending_cab(skb)) { + /* + * Remain awake waiting for buffered broadcast/multicast + * frames. + */ + DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " + "buffered broadcast/multicast frame(s)\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_CAB; + return; + } + + if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) { + /* + * This can happen if a broadcast frame is dropped or the AP + * fails to send a frame indicating that all CAB frames have + * been delivered. + */ + DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); + } + + /* No more broadcast/multicast frames to be received at this point. */ + ath_rx_ps_back_to_sleep(sc); +} + +static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)skb->data; + + /* Process Beacon and CAB receive in PS state */ + if (ieee80211_is_beacon(hdr->frame_control)) + ath_rx_ps_beacon(sc, skb); + else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && + (ieee80211_is_data(hdr->frame_control) || + ieee80211_is_action(hdr->frame_control)) && + is_multicast_ether_addr(hdr->addr1) && + !ieee80211_has_moredata(hdr->frame_control)) { + DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " + "sleep\n"); + /* + * No more broadcast/multicast frames to be received at this + * point. + */ + ath_rx_ps_back_to_sleep(sc); + } +} + static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_rx_status *rx_status) { @@ -667,8 +773,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) rx_status.flag &= ~RX_FLAG_DECRYPTED; } - ath_rx_send_to_mac80211(sc, skb, &rx_status); - /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, @@ -680,6 +784,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_mpdu = NULL; DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on RX\n"); + ath_rx_send_to_mac80211(sc, skb, &rx_status); break; } bf->bf_dmacontext = bf->bf_buf_addr; @@ -695,11 +800,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) sc->rx.rxotherant = 0; } - if (ieee80211_is_beacon(fc) && - (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); - } + if (unlikely(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) + ath_rx_ps(sc, skb); + + ath_rx_send_to_mac80211(sc, skb, &rx_status); + requeue: list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); -- cgit v0.10.2 From 9f26a952210e44691f784b77bf1f83a500d63f58 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 15 May 2009 12:38:32 +0300 Subject: nl80211: Validate NL80211_ATTR_KEY_SEQ length Validate RSC (NL80211_ATTR_KEY_SEQ) length in nl80211/cfg80211 instead of having to do this in all the drivers. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 827ea8e..ce26756 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -320,7 +320,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, case ALG_TKIP: key->conf.iv_len = TKIP_IV_LEN; key->conf.icv_len = TKIP_ICV_LEN; - if (seq && seq_len == 6) { + if (seq) { for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { key->u.tkip.rx[i].iv32 = get_unaligned_le32(&seq[2]); @@ -332,7 +332,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, case ALG_CCMP: key->conf.iv_len = CCMP_HDR_LEN; key->conf.icv_len = CCMP_MIC_LEN; - if (seq && seq_len == CCMP_PN_LEN) { + if (seq) { for (i = 0; i < NUM_RX_DATA_QUEUES; i++) for (j = 0; j < CCMP_PN_LEN; j++) key->u.ccmp.rx_pn[i][j] = @@ -342,7 +342,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, case ALG_AES_CMAC: key->conf.iv_len = 0; key->conf.icv_len = sizeof(struct ieee80211_mmie); - if (seq && seq_len == 6) + if (seq) for (j = 0; j < 6; j++) key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; break; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0e22b5f..1cf57f5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -77,6 +77,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, + [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, diff --git a/net/wireless/util.c b/net/wireless/util.c index beb226e..b94c860 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -181,5 +181,20 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, return -EINVAL; } + if (params->seq) { + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + /* These ciphers do not use key sequence */ + return -EINVAL; + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + if (params->seq_len != 6) + return -EINVAL; + break; + } + } + return 0; } -- cgit v0.10.2 From cc32abd494c0a8f76f2638e3f3a76e01c68bc9ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 May 2009 11:52:31 +0200 Subject: mac80211: move channel switch code The channel switch code is currently in the spectrum management file, where arguably it belongs. However, it is for managed mode only and uses the structures for that mode only so having it in a more generic file can be confusing. Additionally, my next patch gets simpler with the code here. When/if we ever implement this for IBSS or mesh then we will need to rework the structures it uses anyway at which point we could move the code back. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3241e76..be94465 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -934,6 +934,9 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); int ieee80211_max_network_latency(struct notifier_block *nb, unsigned long data, void *dummy); +void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_sw_ie *sw_elem, + struct ieee80211_bss *bss); /* IBSS code */ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); @@ -1031,14 +1034,6 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len); -void ieee80211_chswitch_timer(unsigned long data); -void ieee80211_chswitch_work(struct work_struct *work); -void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel_sw_ie *sw_elem, - struct ieee80211_bss *bss); -void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - u16 capab_info, u8 *pwr_constr_elem, - u8 pwr_constr_elem_len); /* Suspend/resume and hw reconfiguration */ int ieee80211_reconfig(struct ieee80211_local *local); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 47bc303..41f3c1f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -486,6 +486,103 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, ieee80211_tx_skb(sdata, skb, 0); } +/* spectrum management related things */ +static void ieee80211_chswitch_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); + struct ieee80211_bss *bss; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + if (!netif_running(sdata->dev)) + return; + + bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, + sdata->local->hw.conf.channel->center_freq, + ifmgd->ssid, ifmgd->ssid_len); + if (!bss) + goto exit; + + sdata->local->oper_channel = sdata->local->csa_channel; + /* XXX: shouldn't really modify cfg80211-owned data! */ + if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) + bss->cbss.channel = sdata->local->oper_channel; + + ieee80211_rx_bss_put(sdata->local, bss); +exit: + ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; + ieee80211_wake_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CSA); +} + +static void ieee80211_chswitch_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); +} + +void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_sw_ie *sw_elem, + struct ieee80211_bss *bss) +{ + struct ieee80211_channel *new_ch; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); + + if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) + return; + + if (sdata->local->sw_scanning || sdata->local->hw_scanning) + return; + + /* Disregard subsequent beacons if we are already running a timer + processing a CSA */ + + if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) + return; + + new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); + if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) + return; + + sdata->local->csa_channel = new_ch; + + if (sw_elem->count <= 1) { + queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); + } else { + ieee80211_stop_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CSA); + ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + mod_timer(&ifmgd->chswitch_timer, + jiffies + + msecs_to_jiffies(sw_elem->count * + bss->cbss.beacon_interval)); + } +} + +static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, + u16 capab_info, u8 *pwr_constr_elem, + u8 pwr_constr_elem_len) +{ + struct ieee80211_conf *conf = &sdata->local->hw.conf; + + if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) + return; + + /* Power constraint IE length should be 1 octet */ + if (pwr_constr_elem_len != 1) + return; + + if ((*pwr_constr_elem <= conf->channel->max_power) && + (*pwr_constr_elem != sdata->local->power_constr_level)) { + sdata->local->power_constr_level = *pwr_constr_elem; + ieee80211_hw_config(sdata->local, 0); + } +} + /* powersave */ static void ieee80211_enable_ps(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) @@ -1736,7 +1833,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { struct ieee80211_channel_sw_ie *sw_elem = (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; - ieee80211_process_chanswitch(sdata, sw_elem, bss); + ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); } ieee80211_rx_bss_put(local, bss); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f962bd1..f3a041c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1846,6 +1846,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sizeof(mgmt->u.action.u.chan_switch))) return RX_DROP_MONITOR; + if (sdata->vif.type != NL80211_IFTYPE_STATION) + return RX_DROP_MONITOR; + if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) return RX_DROP_MONITOR; @@ -1856,7 +1859,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (!bss) return RX_DROP_MONITOR; - ieee80211_process_chanswitch(sdata, + ieee80211_sta_process_chanswitch(sdata, &mgmt->u.action.u.chan_switch.sw_elem, bss); ieee80211_rx_bss_put(local, bss); break; diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 48bf78e..6895303 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -84,104 +84,3 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, mgmt->sa, mgmt->bssid, mgmt->u.action.u.measurement.dialog_token); } - -void ieee80211_chswitch_work(struct work_struct *work) -{ - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); - struct ieee80211_bss *bss; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - if (!netif_running(sdata->dev)) - return; - - bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (!bss) - goto exit; - - sdata->local->oper_channel = sdata->local->csa_channel; - /* XXX: shouldn't really modify cfg80211-owned data! */ - if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) - bss->cbss.channel = sdata->local->oper_channel; - - ieee80211_rx_bss_put(sdata->local, bss); -exit: - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; - ieee80211_wake_queues_by_reason(&sdata->local->hw, - IEEE80211_QUEUE_STOP_REASON_CSA); -} - -void ieee80211_chswitch_timer(unsigned long data) -{ - struct ieee80211_sub_if_data *sdata = - (struct ieee80211_sub_if_data *) data; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); -} - -void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel_sw_ie *sw_elem, - struct ieee80211_bss *bss) -{ - struct ieee80211_channel *new_ch; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); - - /* FIXME: Handle ADHOC later */ - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return; - - if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) - return; - - if (sdata->local->sw_scanning || sdata->local->hw_scanning) - return; - - /* Disregard subsequent beacons if we are already running a timer - processing a CSA */ - - if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) - return; - - new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); - if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) - return; - - sdata->local->csa_channel = new_ch; - - if (sw_elem->count <= 1) { - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); - } else { - ieee80211_stop_queues_by_reason(&sdata->local->hw, - IEEE80211_QUEUE_STOP_REASON_CSA); - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; - mod_timer(&ifmgd->chswitch_timer, - jiffies + - msecs_to_jiffies(sw_elem->count * - bss->cbss.beacon_interval)); - } -} - -void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - u16 capab_info, u8 *pwr_constr_elem, - u8 pwr_constr_elem_len) -{ - struct ieee80211_conf *conf = &sdata->local->hw.conf; - - if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) - return; - - /* Power constraint IE length should be 1 octet */ - if (pwr_constr_elem_len != 1) - return; - - if ((*pwr_constr_elem <= conf->channel->max_power) && - (*pwr_constr_elem != sdata->local->power_constr_level)) { - sdata->local->power_constr_level = *pwr_constr_elem; - ieee80211_hw_config(sdata->local, 0); - } -} - -- cgit v0.10.2 From 5bb644a0fd25a5e083ecbfaa92a211db99aa6ef7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 17 May 2009 11:40:42 +0200 Subject: mac80211: cancel/restart all timers across suspend/resume We forgot to cancel all timers in mac80211 when suspending. In particular we forgot to deal with some things that can cause hardware reconfiguration -- while it is down. While at it we go ahead and add a warning in ieee80211_sta_work() if its run while the suspend->resume cycle is in effect. This should not happen and if it does it would indicate there is a bug lurking in either mac80211 or mac80211 drivers. With this now wpa_supplicant doesn't blink when I go to suspend and resume where as before there where issues with some timers running during the suspend->resume cycle. This caused a lot of incorrect assumptions and would at times bring back the device in an incoherent, but mostly recoverable, state. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c236079..ebf7318 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -737,6 +737,9 @@ static void ieee80211_ibss_work(struct work_struct *work) struct ieee80211_if_ibss *ifibss; struct sk_buff *skb; + if (WARN_ON(local->suspended)) + return; + if (!netif_running(sdata->dev)) return; @@ -773,10 +776,36 @@ static void ieee80211_ibss_timer(unsigned long data) struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; + if (local->quiescing) { + ifibss->timer_running = true; + return; + } + set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); queue_work(local->hw.workqueue, &ifibss->work); } +#ifdef CONFIG_PM +void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + + cancel_work_sync(&ifibss->work); + if (del_timer_sync(&ifibss->timer)) + ifibss->timer_running = true; +} + +void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + + if (ifibss->timer_running) { + add_timer(&ifibss->timer); + ifibss->timer_running = false; + } +} +#endif + void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index be94465..8db8d16 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -293,6 +293,7 @@ struct ieee80211_if_managed { int auth_tries; /* retries for auth req */ int assoc_tries; /* retries for assoc req */ + unsigned long timers_running; /* used for quiesce/restart */ bool powersave; /* powersave requested for this iface */ unsigned long request; @@ -333,6 +334,9 @@ struct ieee80211_if_ibss { unsigned long request; unsigned long last_scan_completed; + + bool timer_running; + bool fixed_bssid; bool fixed_channel; @@ -358,6 +362,8 @@ struct ieee80211_if_mesh { struct timer_list mesh_path_timer; struct sk_buff_head skb_queue; + unsigned long timers_running; + bool housekeeping; u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; @@ -609,6 +615,21 @@ struct ieee80211_local { unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; bool tim_in_locked_section; /* see ieee80211_beacon_get() */ + + /* + * suspended is true if we finished all the suspend _and_ we have + * not yet come up from resume. This is to be used by mac80211 + * to ensure driver sanity during suspend and mac80211's own + * sanity. It can eventually be used for WoW as well. + */ + bool suspended; + + /* + * quiescing is true during the suspend process _only_ to + * ease timer cancelling etc. + */ + bool quiescing; + int tx_headroom; /* required headroom for hardware/radiotap */ /* Tasklet and skb queue to process calls from IRQ mode. All frames @@ -937,6 +958,8 @@ int ieee80211_max_network_latency(struct notifier_block *nb, void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel_sw_ie *sw_elem, struct ieee80211_bss *bss); +void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); +void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); /* IBSS code */ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); @@ -949,6 +972,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, struct cfg80211_ibss_params *params); int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); +void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata); +void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata); /* scan/BSS handling */ void ieee80211_scan_work(struct work_struct *work); @@ -959,6 +984,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, int ieee80211_scan_results(struct ieee80211_local *local, struct iw_request_info *info, char *buf, size_t len); +void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9000b01..fc712e6 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -21,6 +21,9 @@ #define CAPAB_OFFSET 17 #define ACCEPT_PLINKS 0x80 +#define TMR_RUNNING_HK 0 +#define TMR_RUNNING_MP 1 + int mesh_allocated; static struct kmem_cache *rm_cache; @@ -45,6 +48,12 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; ifmsh->housekeeping = true; + + if (local->quiescing) { + set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); + return; + } + queue_work(local->hw.workqueue, &ifmsh->work); } @@ -343,6 +352,11 @@ static void ieee80211_mesh_path_timer(unsigned long data) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; + if (local->quiescing) { + set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); + return; + } + queue_work(local->hw.workqueue, &ifmsh->work); } @@ -424,6 +438,32 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); } +#ifdef CONFIG_PM +void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + /* might restart the timer but that doesn't matter */ + cancel_work_sync(&ifmsh->work); + + /* use atomic bitops in case both timers fire at the same time */ + + if (del_timer_sync(&ifmsh->housekeeping_timer)) + set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); + if (del_timer_sync(&ifmsh->mesh_path_timer)) + set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); +} + +void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running)) + add_timer(&ifmsh->housekeeping_timer); + if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) + add_timer(&ifmsh->mesh_path_timer); +} +#endif void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) { diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index d891d7d..832bb50 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -267,6 +267,8 @@ void mesh_path_timer(unsigned long data); void mesh_path_flush_by_nexthop(struct sta_info *sta); void mesh_path_discard_frame(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata); +void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); +void mesh_path_restart(struct ieee80211_sub_if_data *sdata); #ifdef CONFIG_MAC80211_MESH extern int mesh_allocated; @@ -294,10 +296,20 @@ static inline void mesh_path_activate(struct mesh_path *mpath) void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); +void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); +void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); +void mesh_plink_quiesce(struct sta_info *sta); +void mesh_plink_restart(struct sta_info *sta); #else #define mesh_allocated 0 static inline void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} +static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) +{} +static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) +{} +static inline void mesh_plink_quiesce(struct sta_info *sta) {} +static inline void mesh_plink_restart(struct sta_info *sta) {} #endif #endif /* IEEE80211S_H */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 60b35ac..003cb47 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -836,8 +836,14 @@ void mesh_path_timer(unsigned long data) mpath = rcu_dereference(mpath); if (!mpath) goto endmpathtimer; - spin_lock_bh(&mpath->state_lock); sdata = mpath->sdata; + + if (sdata->local->quiescing) { + rcu_read_unlock(); + return; + } + + spin_lock_bh(&mpath->state_lock); if (mpath->flags & MESH_PATH_RESOLVED || (!(mpath->flags & MESH_PATH_RESOLVING))) mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a8bbdec..cb14253 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -266,6 +266,11 @@ static void mesh_plink_timer(unsigned long data) */ sta = (struct sta_info *) data; + if (sta->sdata->local->quiescing) { + sta->plink_timer_was_running = true; + return; + } + spin_lock_bh(&sta->lock); if (sta->ignore_plink_timer) { sta->ignore_plink_timer = false; @@ -322,6 +327,22 @@ static void mesh_plink_timer(unsigned long data) } } +#ifdef CONFIG_PM +void mesh_plink_quiesce(struct sta_info *sta) +{ + if (del_timer_sync(&sta->plink_timer)) + sta->plink_timer_was_running = true; +} + +void mesh_plink_restart(struct sta_info *sta) +{ + if (sta->plink_timer_was_running) { + add_timer(&sta->plink_timer); + sta->plink_timer_was_running = false; + } +} +#endif + static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) { sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 41f3c1f..b61a781 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -37,6 +37,9 @@ #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) +#define TMR_RUNNING_TIMER 0 +#define TMR_RUNNING_CHANSW 1 + /* utils */ static int ecw2cw(int ecw) { @@ -521,6 +524,11 @@ static void ieee80211_chswitch_timer(unsigned long data) (struct ieee80211_sub_if_data *) data; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + if (sdata->local->quiescing) { + set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); + return; + } + queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); } @@ -714,6 +722,9 @@ void ieee80211_dynamic_ps_timer(unsigned long data) { struct ieee80211_local *local = (void *) data; + if (local->quiescing) + return; + queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); } @@ -2108,6 +2119,11 @@ static void ieee80211_sta_timer(unsigned long data) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; + if (local->quiescing) { + set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); + return; + } + set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); queue_work(local->hw.workqueue, &ifmgd->work); } @@ -2240,6 +2256,17 @@ static void ieee80211_sta_work(struct work_struct *work) if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) return; + + /* + * Nothing should have been stuffed into the workqueue during + * the suspend->resume cycle. If this WARN is seen then there + * is a bug with either the driver suspend or something in + * mac80211 stuffing into the workqueue which we haven't yet + * cleared during mac80211's suspend cycle. + */ + if (WARN_ON(local->suspended)) + return; + ifmgd = &sdata->u.mgd; while ((skb = skb_dequeue(&ifmgd->skb_queue))) @@ -2307,6 +2334,38 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) } } +#ifdef CONFIG_PM +void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + /* + * we need to use atomic bitops for the running bits + * only because both timers might fire at the same + * time -- the code here is properly synchronised. + */ + + cancel_work_sync(&ifmgd->work); + cancel_work_sync(&ifmgd->beacon_loss_work); + if (del_timer_sync(&ifmgd->timer)) + set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); + + cancel_work_sync(&ifmgd->chswitch_work); + if (del_timer_sync(&ifmgd->chswitch_timer)) + set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); +} + +void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) + add_timer(&ifmgd->timer); + if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) + add_timer(&ifmgd->chswitch_timer); +} +#endif + /* interface setup */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) { diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9d3d89a..7a549f9 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -2,6 +2,7 @@ #include #include "ieee80211_i.h" +#include "mesh.h" #include "driver-ops.h" #include "led.h" @@ -13,11 +14,30 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) struct sta_info *sta; unsigned long flags; + ieee80211_scan_cancel(local); + ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); + /* flush out all packets */ + synchronize_net(); + + local->quiescing = true; + /* make quiescing visible to timers everywhere */ + mb(); + flush_workqueue(local->hw.workqueue); + /* Don't try to run timers while suspended. */ + del_timer_sync(&local->sta_cleanup); + + /* + * Note that this particular timer doesn't need to be + * restarted at resume. + */ + cancel_work_sync(&local->dynamic_ps_enable_work); + del_timer_sync(&local->dynamic_ps_timer); + /* disable keys */ list_for_each_entry(sdata, &local->interfaces, list) ieee80211_disable_keys(sdata); @@ -35,10 +55,20 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) rcu_read_unlock(); + /* flush again, in case driver queued work */ + flush_workqueue(local->hw.workqueue); + + /* stop hardware - this must stop RX */ + if (local->open_count) { + ieee80211_led_radio(local, false); + drv_stop(local); + } + /* remove STAs */ - if (local->ops->sta_notify) { - spin_lock_irqsave(&local->sta_lock, flags); - list_for_each_entry(sta, &local->sta_list, list) { + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) { + if (local->ops->sta_notify) { + sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, @@ -47,29 +77,43 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, &sta->sta); } - spin_unlock_irqrestore(&local->sta_lock, flags); + + mesh_plink_quiesce(sta); } + spin_unlock_irqrestore(&local->sta_lock, flags); /* remove all interfaces */ list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sdata->vif.type != NL80211_IFTYPE_MONITOR && - netif_running(sdata->dev)) { - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->dev->dev_addr; - drv_remove_interface(local, &conf); + switch(sdata->vif.type) { + case NL80211_IFTYPE_STATION: + ieee80211_sta_quiesce(sdata); + break; + case NL80211_IFTYPE_ADHOC: + ieee80211_ibss_quiesce(sdata); + break; + case NL80211_IFTYPE_MESH_POINT: + ieee80211_mesh_quiesce(sdata); + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: + /* don't tell driver about this */ + continue; + default: + break; } - } - /* flush again, in case driver queued work */ - flush_workqueue(local->hw.workqueue); + if (!netif_running(sdata->dev)) + continue; - /* stop hardware */ - if (local->open_count) { - ieee80211_led_radio(local, false); - drv_stop(local); + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = sdata->dev->dev_addr; + drv_remove_interface(local, &conf); } + + local->suspended = true; + local->quiescing = false; + return 0; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e65d74b..2a8d09a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -631,3 +631,21 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->scan_mtx); return ret; } + +void ieee80211_scan_cancel(struct ieee80211_local *local) +{ + bool swscan; + + cancel_delayed_work_sync(&local->scan_work); + + /* + * Only call this function when a scan can't be + * queued -- mostly at suspend under RTNL. + */ + mutex_lock(&local->scan_mtx); + swscan = local->sw_scanning; + mutex_unlock(&local->scan_mtx); + + if (swscan) + ieee80211_scan_completed(&local->hw, true); +} diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 3e4348f..d5611d8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -611,6 +611,9 @@ static void sta_info_cleanup(unsigned long data) sta_info_cleanup_expire_buffered(local, sta); rcu_read_unlock(); + if (local->quiescing) + return; + local->sta_cleanup.expires = round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); add_timer(&local->sta_cleanup); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 164b16c..f53aa9d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -293,6 +293,7 @@ struct sta_info { __le16 reason; u8 plink_retries; bool ignore_plink_timer; + bool plink_timer_was_running; enum plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0689a8f..ffb6e88 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1034,6 +1034,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct sta_info *sta; unsigned long flags; int res; + bool from_suspend = local->suspended; + + /* + * We're going to start the hardware, at that point + * we are no longer suspended and can RX frames. + */ + local->suspended = false; /* restart hardware */ if (local->open_count) { @@ -1058,6 +1065,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (local->ops->sta_notify) { spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry(sta, &local->sta_list, list) { + sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, @@ -1128,5 +1136,40 @@ int ieee80211_reconfig(struct ieee80211_local *local) ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); + /* + * If this is for hw restart things are still running. + * We may want to change that later, however. + */ + if (!from_suspend) + return 0; + +#ifdef CONFIG_PM + local->suspended = false; + + list_for_each_entry(sdata, &local->interfaces, list) { + switch(sdata->vif.type) { + case NL80211_IFTYPE_STATION: + ieee80211_sta_restart(sdata); + break; + case NL80211_IFTYPE_ADHOC: + ieee80211_ibss_restart(sdata); + break; + case NL80211_IFTYPE_MESH_POINT: + ieee80211_mesh_restart(sdata); + break; + default: + break; + } + } + + add_timer(&local->sta_cleanup); + + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) + mesh_plink_restart(sta); + spin_unlock_irqrestore(&local->sta_lock, flags); +#else + WARN_ON(1); +#endif return 0; } -- cgit v0.10.2 From 6b45784fbe9b31c287ab7f2717e4bd4cdcdd340c Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 15 May 2009 18:59:20 +0530 Subject: ath9k: Print hw reset failure status as signed int Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index bbbfdcd..0e8f6d4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -280,7 +280,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel (%u Mhz) " - "reset status %u\n", + "reset status %d\n", channel->center_freq, r); spin_unlock_bh(&sc->sc_resetlock); return r; @@ -1094,7 +1094,7 @@ void ath_radio_enable(struct ath_softc *sc) if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) ", - "reset status %u\n", + "reset status %d\n", channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); @@ -1146,7 +1146,7 @@ void ath_radio_disable(struct ath_softc *sc) if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) " - "reset status %u\n", + "reset status %d\n", channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); @@ -1709,7 +1709,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); if (r) DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u\n", r); + "Unable to reset hardware; reset status %d\n", r); spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) @@ -2001,7 +2001,7 @@ static int ath9k_start(struct ieee80211_hw *hw) r = ath9k_hw_reset(sc->sc_ah, init_channel, false); if (r) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u " + "Unable to reset hardware; reset status %d " "(freq %u MHz)\n", r, curchan->center_freq); spin_unlock_bh(&sc->sc_resetlock); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 41c4282..3f2bd79 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1070,7 +1070,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); if (r) DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u\n", + "Unable to reset hardware; reset status %d\n", r); spin_unlock_bh(&sc->sc_resetlock); } -- cgit v0.10.2 From d31e20af9f65e38429a3ed32175f8e233bdcd2b2 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 15 May 2009 18:59:21 +0530 Subject: ath9k: Remove unused parameters which are passed to ath_beacon_config_X() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 3a7154b..af5edb8 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -507,8 +507,7 @@ void ath_beacon_tasklet(unsigned long data) * slot. Slots that are not occupied will generate nothing. */ static void ath_beacon_config_ap(struct ath_softc *sc, - struct ath_beacon_config *conf, - struct ath_vif *avp) + struct ath_beacon_config *conf) { u32 nexttbtt, intval; @@ -553,8 +552,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, * we've associated with. */ static void ath_beacon_config_sta(struct ath_softc *sc, - struct ath_beacon_config *conf, - struct ath_vif *avp) + struct ath_beacon_config *conf) { struct ath9k_beacon_state bs; int dtimperiod, dtimcount, sleepduration; @@ -654,7 +652,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, static void ath_beacon_config_adhoc(struct ath_softc *sc, struct ath_beacon_config *conf, - struct ath_vif *avp, struct ieee80211_vif *vif) { u64 tsf; @@ -720,14 +717,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) switch(avp->av_opmode) { case NL80211_IFTYPE_AP: - ath_beacon_config_ap(sc, &conf, avp); + ath_beacon_config_ap(sc, &conf); break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: - ath_beacon_config_adhoc(sc, &conf, avp, vif); + ath_beacon_config_adhoc(sc, &conf, vif); break; case NL80211_IFTYPE_STATION: - ath_beacon_config_sta(sc, &conf, avp); + ath_beacon_config_sta(sc, &conf); break; default: DPRINTF(sc, ATH_DBG_CONFIG, -- cgit v0.10.2 From 6b96f93e962e25d38d7a73c0009597672d87c496 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 15 May 2009 18:59:22 +0530 Subject: ath9k: cleanup beacon parameters configuration This patch configures the beacon timers with beacon interval and beacon period passed through vif.bss_conf. Also cache the currecnt beacon configuration which will be used to configure the beacon timers when the driver triggers it after reset. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3425662..bd2363f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -600,6 +600,7 @@ struct ath_softc { struct ath9k_debug debug; #endif struct ath_bus_ops *bus_ops; + struct ath_beacon_config cur_beacon_conf; }; struct ath_wiphy { diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index af5edb8..57f91a9 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -695,43 +695,50 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) + /* FIXME: Handle properly when vif is NULL */ + if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) ath_beacon_start_adhoc(sc, vif); } void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ath_beacon_config conf; + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + enum nl80211_iftype iftype; /* Setup the beacon configuration parameters */ - memset(&conf, 0, sizeof(struct ath_beacon_config)); - conf.beacon_interval = sc->beacon_interval ? : 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; - if (vif) { - struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; - - switch(avp->av_opmode) { - case NL80211_IFTYPE_AP: - ath_beacon_config_ap(sc, &conf); - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - ath_beacon_config_adhoc(sc, &conf, vif); - break; - case NL80211_IFTYPE_STATION: - ath_beacon_config_sta(sc, &conf); - break; - default: - DPRINTF(sc, ATH_DBG_CONFIG, - "Unsupported beaconing mode\n"); - return; - } + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + iftype = vif->type; - sc->sc_flags |= SC_OP_BEACONS; + cur_conf->beacon_interval = bss_conf->beacon_int; + cur_conf->dtim_period = bss_conf->dtim_period; + cur_conf->listen_interval = 1; + cur_conf->dtim_count = 1; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + } else { + iftype = sc->sc_ah->opmode; } + + + switch (iftype) { + case NL80211_IFTYPE_AP: + ath_beacon_config_ap(sc, cur_conf); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + ath_beacon_config_adhoc(sc, cur_conf, vif); + break; + case NL80211_IFTYPE_STATION: + ath_beacon_config_sta(sc, cur_conf); + break; + default: + DPRINTF(sc, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); + return; + } + + sc->sc_flags |= SC_OP_BEACONS; } -- cgit v0.10.2 From 44710bbc073b2e7ea269cf716b817297cd35ae10 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 15 May 2009 15:39:20 -0500 Subject: b43legacy: Remove unnecessary MMIO in interrupt hotpath This removes unnecessary MMIO accesses in the interrupt hotpath. The patch by Michael Buesch for b43 has been ported to b43legacy. Signed-off-by: Stefano Brivio Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index da59ef0..19a4b0b 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -694,8 +694,8 @@ struct b43legacy_wldev { /* Reason code of the last interrupt. */ u32 irq_reason; u32 dma_reason[6]; - /* saved irq enable/disable state bitfield. */ - u32 irq_savedstate; + /* The currently active generic-interrupt mask. */ + u32 irq_mask; /* Link Quality calculation context. */ struct b43legacy_noise_calculation noisecalc; /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 07c7898..0062b34 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -583,35 +583,6 @@ static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) b43legacy_set_slot_time(dev, 20); } -/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev, - u32 mask) -{ - u32 old_mask; - - old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); - b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask | - mask); - - return old_mask; -} - -/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev, - u32 mask) -{ - u32 old_mask; - - old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); - b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask); - - return old_mask; -} - /* Synchronize IRQ top- and bottom-half. * IRQs must be masked before calling this. * This must not be called with the irq_lock held. @@ -1200,7 +1171,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) /* This is the bottom half of the asynchronous beacon update. */ /* Ignore interrupt in the future. */ - dev->irq_savedstate &= ~B43legacy_IRQ_BEACON; + dev->irq_mask &= ~B43legacy_IRQ_BEACON; cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID); @@ -1209,7 +1180,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) /* Schedule interrupt manually, if busy. */ if (beacon0_valid && beacon1_valid) { b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON); - dev->irq_savedstate |= B43legacy_IRQ_BEACON; + dev->irq_mask |= B43legacy_IRQ_BEACON; return; } @@ -1247,12 +1218,11 @@ static void b43legacy_beacon_update_trigger_work(struct work_struct *work) dev = wl->current_dev; if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) { spin_lock_irq(&wl->irq_lock); - /* update beacon right away or defer to irq */ - dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + /* Update beacon right away or defer to IRQ. */ handle_irq_beacon(dev); /* The handler might have updated the IRQ mask. */ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, - dev->irq_savedstate); + dev->irq_mask); mmiowb(); spin_unlock_irq(&wl->irq_lock); } @@ -1398,7 +1368,7 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) if (reason & B43legacy_IRQ_TX_OK) handle_irq_transmit_status(dev); - b43legacy_interrupt_enable(dev, dev->irq_savedstate); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } @@ -1450,18 +1420,18 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) struct b43legacy_wldev *dev = dev_id; u32 reason; - if (!dev) - return IRQ_NONE; + B43legacy_WARN_ON(!dev); spin_lock(&dev->wl->irq_lock); - if (b43legacy_status(dev) < B43legacy_STAT_STARTED) + if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED)) + /* This can only happen on shared IRQ lines. */ goto out; reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ goto out; ret = IRQ_HANDLED; - reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + reason &= dev->irq_mask; if (!reason) goto out; @@ -1485,10 +1455,9 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) & 0x0000DC00; b43legacy_interrupt_ack(dev, reason); - /* disable all IRQs. They are enabled again in the bottom half. */ - dev->irq_savedstate = b43legacy_interrupt_disable(dev, - B43legacy_IRQ_ALL); - /* save the reason code and call our bottom half. */ + /* Disable all IRQs. They are enabled again in the bottom half. */ + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); + /* Save the reason code and call our bottom half. */ dev->irq_reason = reason; tasklet_schedule(&dev->isr_tasklet); out: @@ -1948,7 +1917,8 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) /* Re-enable IRQs. */ spin_lock_irq(&dev->wl->irq_lock); - b43legacy_interrupt_enable(dev, dev->irq_savedstate); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, + dev->irq_mask); spin_unlock_irq(&dev->wl->irq_lock); } } @@ -1967,10 +1937,9 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) /* Mask IRQs before suspending MAC. Otherwise * the MAC stays busy and won't suspend. */ spin_lock_irq(&dev->wl->irq_lock); - tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); spin_unlock_irq(&dev->wl->irq_lock); b43legacy_synchronize_irq(dev); - dev->irq_savedstate = tmp; b43legacy_power_saving_ctl_bits(dev, -1, 1); b43legacy_write32(dev, B43legacy_MMIO_MACCTL, @@ -2659,7 +2628,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, int antenna_tx; int antenna_rx; int err = 0; - u32 savedirqs; antenna_tx = B43legacy_ANTENNA_DEFAULT; antenna_rx = B43legacy_ANTENNA_DEFAULT; @@ -2699,7 +2667,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); goto out_unlock_mutex; } - savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); spin_unlock_irqrestore(&wl->irq_lock, flags); b43legacy_synchronize_irq(dev); @@ -2738,7 +2706,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, } spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_interrupt_enable(dev, savedirqs); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irqrestore(&wl->irq_lock, flags); out_unlock_mutex: @@ -2801,7 +2769,6 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, struct b43legacy_wldev *dev; struct b43legacy_phy *phy; unsigned long flags; - u32 savedirqs; mutex_lock(&wl->mutex); B43legacy_WARN_ON(wl->vif != vif); @@ -2817,7 +2784,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); goto out_unlock_mutex; } - savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); if (changed & BSS_CHANGED_BSSID) { spin_unlock_irqrestore(&wl->irq_lock, flags); @@ -2862,7 +2829,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, b43legacy_mac_enable(dev); spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_interrupt_enable(dev, savedirqs); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); /* XXX: why? */ mmiowb(); spin_unlock_irqrestore(&wl->irq_lock, flags); @@ -2922,8 +2889,7 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) * setting the status to INITIALIZED, as the interrupt handler * won't care about IRQs then. */ spin_lock_irqsave(&wl->irq_lock, flags); - dev->irq_savedstate = b43legacy_interrupt_disable(dev, - B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */ spin_unlock_irqrestore(&wl->irq_lock, flags); b43legacy_synchronize_irq(dev); @@ -2963,7 +2929,7 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) /* Start data flow (TX/RX) */ b43legacy_mac_enable(dev); - b43legacy_interrupt_enable(dev, dev->irq_savedstate); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); /* Start maintenance work */ b43legacy_periodic_tasks_setup(dev); @@ -3126,7 +3092,7 @@ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) /* IRQ related flags */ dev->irq_reason = 0; memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); - dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE; + dev->irq_mask = B43legacy_IRQ_MASKTEMPLATE; dev->mac_suspended = 1; diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 746d536..51866c9 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -443,7 +443,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev) pio->queue3 = queue; if (dev->dev->id.revision < 3) - dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND; + dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND; b43legacydbg(dev->wl, "PIO initialized\n"); err = 0; -- cgit v0.10.2 From bed420d9c0a642cda3d37b66db0f66f87d8f8185 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 15 May 2009 16:13:43 -0700 Subject: iwlwifi: drop struct iwl3945_hw_key This patch replaces struct iwl3945_hw_key by struct iwl_hw_key. It's not used directly with any host command therefore removal is trivial Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3049ba2..427489a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -503,18 +503,13 @@ struct iwl3945_tid_data { u16 seq_number; }; -struct iwl3945_hw_key { - enum ieee80211_key_alg alg; - int keylen; - u8 key[32]; -}; struct iwl3945_station_entry { struct iwl3945_addsta_cmd sta; struct iwl3945_tid_data tid[MAX_TID_COUNT]; u8 used; u8 ps_status; - struct iwl3945_hw_key keyinfo; + struct iwl_hw_key keyinfo; }; struct iwl_station_entry { diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c32ec80..5d52f227 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -340,7 +340,7 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key)); + memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); memset(&priv->stations_39[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; @@ -578,8 +578,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, int sta_id) { struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - struct iwl3945_hw_key *keyinfo = - &priv->stations_39[sta_id].keyinfo; + struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: -- cgit v0.10.2 From c15ff610453a6daa708f32b1c00b8344d3a462dd Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 15 May 2009 16:13:44 -0700 Subject: iwlwifi: drop iwl3945_tid_data This patch is one of the incremental steps for unifying iwl_station_entry for all HWs, i.e. removing of iwl3945_station_entry This patch drops iwl3945_tid_data and use iwl_tid_data instead. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 427489a..b6b8327 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -499,14 +499,10 @@ struct iwl_qos_info { #define STA_PS_STATUS_WAKE 0 #define STA_PS_STATUS_SLEEP 1 -struct iwl3945_tid_data { - u16 seq_number; -}; - struct iwl3945_station_entry { struct iwl3945_addsta_cmd sta; - struct iwl3945_tid_data tid[MAX_TID_COUNT]; + struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; u8 ps_status; struct iwl_hw_key keyinfo; -- cgit v0.10.2 From 3dcf670baf3d3a9bfc752e59d0b1a8d886230750 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 16 May 2009 23:13:46 +0100 Subject: cfg80211: mark ops as pointer to const This allows drivers to mark their cfg80211_ops tables const. Signed-off-by: David Kilroy Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7391ad1..09a8235 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1073,7 +1073,7 @@ static inline const char *wiphy_name(struct wiphy *wiphy) * The returned pointer must be assigned to each netdev's * ieee80211_ptr for proper operation. */ -struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv); +struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv); /** * wiphy_register - register a wiphy with cfg80211 diff --git a/net/wireless/core.c b/net/wireless/core.c index b6ef533..a5dbea1 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -229,7 +229,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, /* exported functions */ -struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) +struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { static int wiphy_counter; diff --git a/net/wireless/core.h b/net/wireless/core.h index 88f234c..9511c2b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -16,7 +16,7 @@ #include "reg.h" struct cfg80211_registered_device { - struct cfg80211_ops *ops; + const struct cfg80211_ops *ops; struct list_head list; /* we hold this mutex during any call so that * we cannot do multiple calls at once, and also -- cgit v0.10.2 From cf5aa2f1f39d367d449df4c10de3d8e6f9c4443b Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 16 May 2009 23:13:47 +0100 Subject: cfg80211: mark wiphy->privid as pointer to const This allows drivers to use a const pointer as the privid without a cast. Signed-off-by: David Kilroy Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 09a8235..81a3bfa 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -997,7 +997,7 @@ struct wiphy { * know whether it points to a wiphy your driver has registered * or not. Assign this to something global to your driver to * help determine whether you own this wiphy or not. */ - void *privid; + const void *privid; struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; -- cgit v0.10.2 From 4eaf16bc1f92bf772f6d42860e86b399d00b7b94 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 17 May 2009 11:28:42 +0200 Subject: drivers/net: use dev_get_drvdata Eliminate direct accesses to the driver_data field. cf 82ab13b26f15f49be45f15ccc96bfa0b81dfd015 The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct device *dev; expression E; type T; @@ - dev->driver_data = (T)E + dev_set_drvdata(dev, E) @@ struct device *dev; type T; @@ - (T)dev->driver_data + dev_get_drvdata(dev) // Signed-off-by: Julia Lawall Acked-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 596977d..eb89752a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2478,7 +2478,7 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static ssize_t show_qos(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); char *p = buf; int q; -- cgit v0.10.2 From 210dd1bb9b0329bcc1b4f8932022eddc6466980c Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 18 May 2009 03:02:31 +0400 Subject: p54spi: fix incorrect access sequence to DMA_WRITE_CTRL in p54spi_spi_write_dma Host is not allowed to modify DMA_WRITE_CTRL register if bit HOST_ALLOWED in it is not set. Wait for HOST_ALLOWED first. Also get rid of timeout in p54spi_wait_bit as it's been playing a role of workaround for such an incorrect register access. Signed-off-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 59a5e77..272b7e1 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -172,8 +172,6 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) __le32 buffer = p54spi_read32(priv, reg); if ((buffer & bits) == bits) return 1; - - msleep(0); } return 0; } @@ -181,9 +179,6 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, const void *buf, size_t len) { - p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); - if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, cpu_to_le32(HOST_ALLOWED))) { dev_err(&priv->spi->dev, "spi_write_dma not allowed " @@ -191,6 +186,9 @@ static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, return -EAGAIN; } + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len)); p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base); p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len); -- cgit v0.10.2 From 69712e926bad9c163d5ba5597f08084ee7902480 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 18 May 2009 03:02:32 +0400 Subject: p54spi: cosmetic fixes: use even byte count in SPI write; drop unused interrupt status read When SPI write of odd length is requested, p54spi_write splits it into two parts: one for all data, except the last byte, and one for last byte and padding byte. Unfortunately, the length of first part is not amended. It works because all meaningful bytes have proper value and the last byte of odd length SPI write transaction is ignored. p54spi_work has dummy HOST_INTERRUPTS register read at the end. Drop it, as its result is not used and it has no side effects. Signed-off-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 272b7e1..399190b 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -96,7 +96,7 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address, spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; - t[1].len = len; + t[1].len = len & ~1; spi_message_add_tail(&t[1], &m); if (len % 2) { @@ -541,11 +541,6 @@ static void p54spi_work(struct work_struct *work) } ret = p54spi_wq_tx(priv); - if (ret < 0) - goto out; - - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - out: mutex_unlock(&priv->mutex); } -- cgit v0.10.2 From 465b63537f93e82a2606332830801acb64467ec9 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 18 May 2009 03:02:33 +0400 Subject: p54spi: return status of p54spi_wakeup Return whether wakeup operation succeeded. Make use of this return value. Signed-off-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 399190b..5038e8a 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -325,7 +325,7 @@ static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val) p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val)); } -static void p54spi_wakeup(struct p54s_priv *priv) +static int p54spi_wakeup(struct p54s_priv *priv) { /* wake the chip */ p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, @@ -335,13 +335,11 @@ static void p54spi_wakeup(struct p54s_priv *priv) if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, cpu_to_le32(SPI_HOST_INT_READY))) { dev_err(&priv->spi->dev, "INT_READY timeout\n"); - goto out; + return -EBUSY; } p54spi_int_ack(priv, SPI_HOST_INT_READY); - -out: - return; + return 0; } static inline void p54spi_sleep(struct p54s_priv *priv) @@ -374,7 +372,8 @@ static int p54spi_rx(struct p54s_priv *priv) struct sk_buff *skb; u16 len; - p54spi_wakeup(priv); + if (p54spi_wakeup(priv) < 0) + return -EBUSY; /* dummy read to flush SPI DMA controller bug */ p54spi_read16(priv, SPI_ADRS_GEN_PURP_1); @@ -425,7 +424,8 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) struct p54_hdr *hdr = (struct p54_hdr *) skb->data; int ret = 0; - p54spi_wakeup(priv); + if (p54spi_wakeup(priv) < 0) + return -EBUSY; ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len); if (ret < 0) -- cgit v0.10.2 From 6edf534a3214e8fad943d7acd903603f0a5b9ac8 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 18 May 2009 03:02:34 +0400 Subject: p54spi: always call p54spi_sleep in p54spi_tx_frame if p54spi_wakeup succeeded Put chip into sleep state, once it's been awaken. Also, propagate error code to the caller. Signed-off-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 5038e8a..e830a2e 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -434,16 +434,16 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, cpu_to_le32(SPI_HOST_INT_WR_READY))) { dev_err(&priv->spi->dev, "WR_READY timeout\n"); - ret = -1; + ret = -EAGAIN; goto out; } p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); - p54spi_sleep(priv); if (FREE_AFTER_TX(skb)) p54_free_skb(priv->hw, skb); out: + p54spi_sleep(priv); return ret; } -- cgit v0.10.2 From ff561ac84e0bdfe1316ed355669dd73101609f24 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 18 May 2009 03:02:35 +0400 Subject: p54spi: use firmware/DMA bug workaround that work under hight load in p54spi_rx Under high load first data word, read after available data size is sometimes lost in p54spi_rx. It seems to depend on frequency of interrupts and latency of data read request relatively to 'data available' interrupt. The worst consequence of this bug is loss of packet transmission acknowledgement, which in turn causes overflow of tx queues and permanent link loss. Read data size and first data word in one SPI transaction. No packets from LMAC should have length less than 1 word, so this shouldn't interfere with the next read transaction. Also call p54spi_sleep if p54spi_wake succeeded. Signed-off-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index e830a2e..40aeb43 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -371,32 +371,44 @@ static int p54spi_rx(struct p54s_priv *priv) { struct sk_buff *skb; u16 len; + u16 rx_head[2]; +#define READAHEAD_SZ (sizeof(rx_head)-sizeof(u16)) if (p54spi_wakeup(priv) < 0) return -EBUSY; - /* dummy read to flush SPI DMA controller bug */ - p54spi_read16(priv, SPI_ADRS_GEN_PURP_1); - - len = p54spi_read16(priv, SPI_ADRS_DMA_DATA); + /* Read data size and first data word in one SPI transaction + * This is workaround for firmware/DMA bug, + * when first data word gets lost under high load. + */ + p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, rx_head, sizeof(rx_head)); + len = rx_head[0]; if (len == 0) { - dev_err(&priv->spi->dev, "rx request of zero bytes"); + p54spi_sleep(priv); + dev_err(&priv->spi->dev, "rx request of zero bytes\n"); return 0; } - /* Firmware may insert up to 4 padding bytes after the lmac header, * but it does not amend the size of SPI data transfer. * Such packets has correct data size in header, thus referencing * past the end of allocated skb. Reserve extra 4 bytes for this case */ skb = dev_alloc_skb(len + 4); if (!skb) { + p54spi_sleep(priv); dev_err(&priv->spi->dev, "could not alloc skb"); - return 0; + return -ENOMEM; } - p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len); + if (len <= READAHEAD_SZ) { + memcpy(skb_put(skb, len), rx_head + 1, len); + } else { + memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ); + p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, + skb_put(skb, len - READAHEAD_SZ), + len - READAHEAD_SZ); + } p54spi_sleep(priv); /* Put additional bytes to compensate for the possible * alignment-caused truncation */ -- cgit v0.10.2 From 3f0d843b5c94be824c2027f01348f360958e5542 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 May 2009 10:53:18 +0200 Subject: b43/legacy: fix beacon change processing Process beacon change even if the BSSID doesn't change at the same time. Also fix what I think is a small locking error in b43legacy, there's a spin_unlock_irqrestore that looks out of place. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2615aaf..ec8516e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3553,27 +3553,25 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, B43_WARN_ON(wl->vif != vif); + spin_lock_irqsave(&wl->irq_lock, flags); if (changed & BSS_CHANGED_BSSID) { - spin_lock_irqsave(&wl->irq_lock, flags); if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); else memset(wl->bssid, 0, ETH_ALEN); + } - if (b43_status(dev) >= B43_STAT_INITIALIZED) { - 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 (changed & BSS_CHANGED_BEACON) - b43_update_templates(wl); - } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { - if (changed & BSS_CHANGED_BEACON) - b43_update_templates(wl); - } + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + if (changed & BSS_CHANGED_BEACON && + (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) || + b43_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43_update_templates(wl); + + if (changed & BSS_CHANGED_BSSID) b43_write_mac_bssid_templates(dev); - } - spin_unlock_irqrestore(&wl->irq_lock, flags); } + spin_unlock_irqrestore(&wl->irq_lock, flags); b43_mac_suspend(dev); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 0062b34..f6f3fbf 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2787,27 +2787,24 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); if (changed & BSS_CHANGED_BSSID) { - spin_unlock_irqrestore(&wl->irq_lock, flags); b43legacy_synchronize_irq(dev); if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); else memset(wl->bssid, 0, ETH_ALEN); + } + + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (changed & BSS_CHANGED_BEACON && + (b43legacy_is_mode(wl, NL80211_IFTYPE_AP) || + b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43legacy_update_templates(wl); - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { - B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); - if (changed & BSS_CHANGED_BEACON) - b43legacy_update_templates(wl); - } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { - if (changed & BSS_CHANGED_BEACON) - b43legacy_update_templates(wl); - } + if (changed & BSS_CHANGED_BSSID) b43legacy_write_mac_bssid_templates(dev); - } - spin_unlock_irqrestore(&wl->irq_lock, flags); } + spin_unlock_irqrestore(&wl->irq_lock, flags); b43legacy_mac_suspend(dev); -- cgit v0.10.2 From 4de2dc74a1c7dedcfbe8290316f1a239a7c86554 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 18 May 2009 21:28:55 +0400 Subject: p54spi: drop test for FW_STATE_RESET in p54spi_work Drop test for FW_STATE_RESET in p54spi_work as fw_state is never assigned this value. Signed-off-by: Roel Kluin Signed-off-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 40aeb43..83116ba 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -525,8 +525,7 @@ static void p54spi_work(struct work_struct *work) mutex_lock(&priv->mutex); - if (priv->fw_state == FW_STATE_OFF && - priv->fw_state == FW_STATE_RESET) + if (priv->fw_state == FW_STATE_OFF) goto out; ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); -- cgit v0.10.2 From 1071db863b129847cedb65339d1e87ecf5952a8b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 18 May 2009 10:59:52 -0400 Subject: ath5k: update beacons in AP mode ath5k only generated the beacon when bss_info_changed() was called, but for AP mode this is not enough, because the TIM IE would never get updated and consequently PS mode clients wouldn't know about buffered frames. Instead, get a new beacon on every SWBA interrupt. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index dbfe9f4..fb51937 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -242,8 +242,8 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ath5k_softc *sc, - struct sk_buff *skb); +static int ath5k_beacon_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -2127,8 +2127,10 @@ ath5k_beacon_send(struct ath5k_softc *sc) /* NB: hw still stops DMA, so proceed */ } - /* Note: Beacon buffer is updated on beacon_update when mac80211 - * calls config_interface */ + /* refresh the beacon for AP mode */ + if (sc->opmode == NL80211_IFTYPE_AP) + ath5k_beacon_update(sc->hw, sc->vif); + 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", @@ -3047,28 +3049,55 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) ath5k_hw_reset_tsf(sc->ah); } +/* + * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, + * this is called only once at config_bss time, for AP we do it every + * SWBA interrupt so that the TIM will reflect buffered frames. + * + * Called with the beacon lock. + */ static int -ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) +ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - unsigned long flags; int ret; + struct ath5k_softc *sc = hw->priv; + struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + + if (!skb) { + ret = -ENOMEM; + goto out; + } ath5k_debug_dump_skb(sc, skb, "BC ", 1); - spin_lock_irqsave(&sc->block, flags); ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; ret = ath5k_beacon_setup(sc, sc->bbuf); if (ret) sc->bbuf->skb = NULL; +out: + return ret; +} + +/* + * Update the beacon and reconfigure the beacon queues. + */ +static void +ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + int ret; + unsigned long flags; + struct ath5k_softc *sc = hw->priv; + + spin_lock_irqsave(&sc->block, flags); + ret = ath5k_beacon_update(hw, vif); spin_unlock_irqrestore(&sc->block, flags); - if (!ret) { + if (ret == 0) { ath5k_beacon_config(sc); mmiowb(); } - - return ret; } + static void set_beacon_filter(struct ieee80211_hw *hw, bool enable) { @@ -3118,10 +3147,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, (vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT || vif->type == NL80211_IFTYPE_AP)) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - - if (beacon) - ath5k_beacon_update(sc, beacon); + ath5k_beacon_reconfig(hw, vif); } unlock: -- cgit v0.10.2 From 73606d00360cb93963aeb7bfbf8bfdbc51cfab9f Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Mon, 18 May 2009 19:49:25 +0200 Subject: mac80211_hwsim: Group radios Currently all radios receive all traffic on the simulated air if they are tuned to the same channel. This patch introduces the concept of grouping, which allows to assign a radio to certain group. Only radios in the same group can 'see' each other. Each bit in /debug/ieee80211/phy*/hwsim/group represents one group. By default all radios belong to the same group "1", e.g. bit 1 is set. Additionally a radio can belong to several groups. Signed-off-by: Daniel Wagner Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 61a4ad7..574b8bb 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -291,6 +291,14 @@ struct mac80211_hwsim_data { bool ps_poll_pending; struct dentry *debugfs; struct dentry *debugfs_ps; + + /* + * Only radios in the same group can communicate together (the + * channel has to match too). Each bit represents a group. A + * radio can be in more then one group. + */ + u64 group; + struct dentry *debugfs_group; }; @@ -412,7 +420,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (!data2->started || !data2->radio_enabled || !hwsim_ps_rx_ok(data2, skb) || - data->channel->center_freq != data2->channel->center_freq) + data->channel->center_freq != data2->channel->center_freq || + !(data->group & data2->group)) continue; nskb = skb_copy(skb, GFP_ATOMIC); @@ -720,6 +729,7 @@ static void mac80211_hwsim_free(void) spin_unlock_bh(&hwsim_radio_lock); list_for_each_entry(data, &tmplist, list) { + debugfs_remove(data->debugfs_group); debugfs_remove(data->debugfs_ps); debugfs_remove(data->debugfs); ieee80211_unregister_hw(data->hw); @@ -872,6 +882,24 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, "%llu\n"); +static int hwsim_fops_group_read(void *dat, u64 *val) +{ + struct mac80211_hwsim_data *data = dat; + *val = data->group; + return 0; +} + +static int hwsim_fops_group_write(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + data->group = val; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, + hwsim_fops_group_read, hwsim_fops_group_write, + "%llx\n"); + static int __init init_mac80211_hwsim(void) { int i, err = 0; @@ -976,6 +1004,8 @@ static int __init init_mac80211_hwsim(void) hw->wiphy->bands[band] = sband; } + /* By default all radios are belonging to the first group */ + data->group = 1; /* Work to be done prior to ieee80211_register_hw() */ switch (regtest) { @@ -1100,6 +1130,9 @@ static int __init init_mac80211_hwsim(void) data->debugfs_ps = debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); + data->debugfs_group = debugfs_create_file("group", 0666, + data->debugfs, data, + &hwsim_fops_group); setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); -- cgit v0.10.2 From e3da574a0ddd3e90a1e2b788b84b94bc17a75172 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 May 2009 19:56:36 +0200 Subject: cfg80211: allow wext to remove keys that don't exist Some applications using wireless extensions expect to be able to remove a key that doesn't exist. One example is wpa_supplicant which doesn't actually change behaviour when running into an error while trying to do that, but it prints an error message which users interpret as wpa_supplicant having problems. The safe thing to do is not change the behaviour of wireless extensions any more, so when the driver reports -ENOENT let the wext bridge code return success to userspace. To guarantee this, also document that drivers should return -ENOENT when the key doesn't exist. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 81a3bfa..389f1d2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -781,10 +781,11 @@ enum wiphy_params_flags { * @get_key: get information about the key with the given parameters. * @mac_addr will be %NULL when requesting information for a group * key. All pointers given to the @callback function need not be valid - * after it returns. + * after it returns. This function should return an error if it is + * not possible to retrieve the key, -ENOENT if it doesn't exist. * * @del_key: remove a key given the @mac_addr (%NULL for a group key) - * and @key_index + * and @key_index, return -ENOENT if the key doesn't exist. * * @set_default_key: set the default key on an interface * diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index f98090b..711e00a 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -504,6 +504,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, else if (idx == wdev->wext.default_mgmt_key) wdev->wext.default_mgmt_key = -1; } + /* + * Applications using wireless extensions expect to be + * able to delete keys that don't exist, so allow that. + */ + if (err == -ENOENT) + return 0; + return err; } else { if (addr) -- cgit v0.10.2 From 153e080da6a07ed888a0a59c45e28bc7351407ff Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 15 May 2009 02:47:16 -0400 Subject: ath9k: Move PS wakeup/restore calls from isr to tasklet We do not need to do this in ath_isr() and it looks like the modified version ends up being more stable as far as being able receive beacon frames is concerned. Furthermore, this reduces need to move between AWAKE and NETWORK SLEEP states when processing some unrelated interrupts. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0e8f6d4..c161b75 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -455,8 +455,11 @@ static void ath9k_tasklet(unsigned long data) struct ath_softc *sc = (struct ath_softc *)data; u32 status = sc->intrstatus; + ath9k_ps_wakeup(sc); + if (status & ATH9K_INT_FATAL) { ath_reset(sc, false); + ath9k_ps_restore(sc); return; } @@ -471,6 +474,7 @@ static void ath9k_tasklet(unsigned long data) /* re-enable hardware interrupt */ ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_ps_restore(sc); } irqreturn_t ath_isr(int irq, void *dev) @@ -498,14 +502,11 @@ irqreturn_t ath_isr(int irq, void *dev) if (sc->sc_flags & SC_OP_INVALID) return IRQ_NONE; - ath9k_ps_wakeup(sc); /* shared irq, not for us */ - if (!ath9k_hw_intrpend(ah)) { - ath9k_ps_restore(sc); + if (!ath9k_hw_intrpend(ah)) return IRQ_NONE; - } /* * Figure out the reason(s) for the interrupt. Note @@ -520,10 +521,8 @@ irqreturn_t ath_isr(int irq, void *dev) * If there are no status bits set, then this interrupt was not * for me (should have been caught above). */ - if (!status) { - ath9k_ps_restore(sc); + if (!status) return IRQ_NONE; - } /* Cache the status */ sc->intrstatus = status; @@ -560,20 +559,17 @@ irqreturn_t ath_isr(int irq, void *dev) ath9k_hw_set_interrupts(ah, sc->imask); } - if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + if (status & ATH9K_INT_TIM_TIMER) { /* Clear RxAbort bit so that we can * receive frames */ ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); - ath9k_hw_setrxabort(ah, 0); - sched = true; + ath9k_hw_setrxabort(sc->sc_ah, 0); sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } - } chip_reset: - ath9k_ps_restore(sc); ath_debug_stat_interrupt(sc, status); if (sched) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 72e9283..5567517 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -508,8 +508,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) { sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); - if (sc->hw->conf.flags & IEEE80211_CONF_PS) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); } static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) -- cgit v0.10.2 From 49ca37e2d29569d7408f3c92f15c4a33e459a987 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Tue, 12 May 2009 15:23:13 +0400 Subject: Staging: agnx: switch config_interface to bss_info_changed Fix this build error: drivers/staging/agnx/pci.c: In function 'agnx_config_interface': drivers/staging/agnx/pci.c:315: error: dereferencing pointer to incomplete type .. drivers/staging/agnx/pci.c:424: error: unknown field 'config_interface' specified in initializer config_interface was removed in 2d0ddec5b2b ("mac80211: unify config_interface and bss_info_changed") Signed-off-by: Alexander Beregalov Signed-off-by: John W. Linville diff --git a/drivers/staging/agnx/pci.c b/drivers/staging/agnx/pci.c index 25c0ffd..43b3fe3 100644 --- a/drivers/staging/agnx/pci.c +++ b/drivers/staging/agnx/pci.c @@ -303,14 +303,18 @@ static int agnx_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int agnx_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) +static void agnx_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) { struct agnx_priv *priv = dev->priv; void __iomem *ctl = priv->ctl; AGNX_TRACE; + if (!(changed & BSS_CHANGED_BSSID)) + return; + spin_lock(&priv->lock); if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { @@ -323,8 +327,7 @@ static int agnx_config_interface(struct ieee80211_hw *dev, agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1); } spin_unlock(&priv->lock); - return 0; -} /* agnx_config_interface */ +} /* agnx_bss_info_changed */ static void agnx_configure_filter(struct ieee80211_hw *dev, @@ -422,7 +425,7 @@ static struct ieee80211_ops agnx_ops = { .add_interface = agnx_add_interface, .remove_interface = agnx_remove_interface, .config = agnx_config, - .config_interface = agnx_config_interface, + .bss_info_changed = agnx_bss_info_changed, .configure_filter = agnx_configure_filter, .get_stats = agnx_get_stats, .get_tx_stats = agnx_get_tx_stats, -- cgit v0.10.2 From e74fbb412be9baeae5ee61e25dad0b8c1a287494 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 13 May 2009 09:47:38 +0800 Subject: wireless: fix to set dev->broadcast correctly This patch fix to set dev->broadcast correctly, since dev->broadcast is defined as: unsigned char broadcast[MAX_ADDR_LEN]; Signed-off-by: Wei Yongjun Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index f952046..b7b0c46 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -2509,7 +2509,7 @@ static void strip_dev_setup(struct net_device *dev) * netdev_priv(dev) Already holds a pointer to our struct strip */ - *(MetricomAddress *) & dev->broadcast = broadcast_address; + *(MetricomAddress *)dev->broadcast = broadcast_address; dev->dev_addr[0] = 0; dev->addr_len = sizeof(MetricomAddress); -- cgit v0.10.2 From 4776c6e7f66f853011bc1fd6fe37fa63f0b6982c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 13 May 2009 17:04:39 -0400 Subject: cfg80211: return immediately if num reg rules > NL80211_MAX_SUPP_REG_RULES This has no functional change except we save a kfree(rd) and allows us to clean this code up a bit after this. We do avoid an unnecessary kfree(NULL) but calling that was OK too. Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1cf57f5..52a8779 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2567,7 +2567,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) rem_reg_rules) { num_rules++; if (num_rules > NL80211_MAX_SUPP_REG_RULES) - goto bad_reg; + return -EINVAL; } if (!reg_is_valid_request(alpha2)) -- cgit v0.10.2 From d0e18f833d23afefb6751a21d14a2cd71d2d4d66 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 13 May 2009 17:04:40 -0400 Subject: cfg80211: cleanup return calls on nl80211_set_reg() This has no functional change, but it will make the race fix easier to spot in my next patch. Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 52a8779..66e0fb6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2570,15 +2570,19 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - if (!reg_is_valid_request(alpha2)) - return -EINVAL; + if (!reg_is_valid_request(alpha2)) { + r = -EINVAL; + goto bad_reg; + } size_of_regd = sizeof(struct ieee80211_regdomain) + (num_rules * sizeof(struct ieee80211_reg_rule)); rd = kzalloc(size_of_regd, GFP_KERNEL); - if (!rd) - return -ENOMEM; + if (!rd) { + r = -ENOMEM; + goto bad_reg; + } rd->n_reg_rules = num_rules; rd->alpha2[0] = alpha2[0]; @@ -2595,8 +2599,10 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) rule_idx++; - if (rule_idx > NL80211_MAX_SUPP_REG_RULES) + if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { + r = -EINVAL; goto bad_reg; + } } BUG_ON(rule_idx != num_rules); @@ -2604,11 +2610,12 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) mutex_lock(&cfg80211_mutex); r = set_regdom(rd); mutex_unlock(&cfg80211_mutex); + return r; bad_reg: kfree(rd); - return -EINVAL; + return r; } static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) -- cgit v0.10.2 From 61405e97788b1bc4e7c5be5b4ec04a73fc11bac2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 13 May 2009 17:04:41 -0400 Subject: cfg80211: fix in nl80211_set_reg() There is a race on access to last_request and its alpha2 through reg_is_valid_request() and us possibly processing first another regulatory request on another CPU. We avoid this improbably race by locking with the cfg80211_mutex as we should have done in the first place. While at it add the assert on locking on reg_is_valid_request(). Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 66e0fb6..6325040 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2570,6 +2570,8 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + mutex_lock(&cfg80211_mutex); + if (!reg_is_valid_request(alpha2)) { r = -EINVAL; goto bad_reg; @@ -2607,13 +2609,14 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) BUG_ON(rule_idx != num_rules); - mutex_lock(&cfg80211_mutex); r = set_regdom(rd); + mutex_unlock(&cfg80211_mutex); return r; bad_reg: + mutex_unlock(&cfg80211_mutex); kfree(rd); return r; } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 48db569..8d176a8 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -382,6 +382,8 @@ static int call_crda(const char *alpha2) /* Used by nl80211 before kmalloc'ing our regulatory domain */ bool reg_is_valid_request(const char *alpha2) { + assert_cfg80211_lock(); + if (!last_request) return false; -- cgit v0.10.2 From 9c8b3eddc0666255851942df8ec72cd91d22f280 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 19 May 2009 23:37:31 -0400 Subject: ath5k: avoid and warn on potential infinite loop If we are trying to interpolate a curve with slope == 0, the return value will always be the y-coordinate. In this code we are looping until we reach a minimum y-coordinate on a line, which in the 0-slope case can never happen, thus the loop never terminates. The PCDAC steps come from the EEPROM and should never be equal, but we should gracefully handle that case, so warn and bail out. Reported-by: Steven Rostedt Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index d0d1c35..a876ca8 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1897,6 +1897,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, s16 min_pwrL, min_pwrR; s16 pwr_i; + if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1])) + return 0; + if (pwrL[0] == pwrL[1]) min_pwrL = pwrL[0]; else { -- cgit v0.10.2 From e43e820c9cc5cc37ca8fc07d1f18cb29f13a2ce8 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Mon, 18 May 2009 21:43:52 -0400 Subject: cfg80211: fix compile error with CONFIG_CFG80211_DEBUGFS If CONFIG_CFG80211_DEBUGFS is enabled and CONFIG_MAC80211_DEBUGFS is not, compilation fails in net/wireless/debugfs.c: net/wireless/debugfs.c: In function 'cfg80211_debugfs_drv_add': net/wireless/debugfs.c:117: error: 'struct cfg80211_registered_device' has no member named 'debugfs' The debugfs filed is needed if and only if CONFIG_CFG80211_DEBUGFS is enabled, so use that instead of CONFIG_MAC80211_DEBUGFS. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville diff --git a/net/wireless/core.h b/net/wireless/core.h index 9511c2b..ab512bc 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -51,7 +51,7 @@ struct cfg80211_registered_device { struct cfg80211_scan_request *scan_req; /* protected by RTNL */ unsigned long suspend_at; -#ifdef CONFIG_MAC80211_DEBUGFS +#ifdef CONFIG_CFG80211_DEBUGFS /* Debugfs entries */ struct wiphy_debugfsdentries { struct dentry *rts_threshold; -- cgit v0.10.2 From 2c617b0324c4b05e8e08f14407a9be3b7756768f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 19 May 2009 07:26:04 +0200 Subject: rt2x00: Add USB ID for rt2800usb Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 257bfb5..f11e597 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2912,6 +2912,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v0.10.2 From cce4c77b87ce7e71a0f244a3dfb6ac1c3a1bc67e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 May 2009 10:39:34 +0200 Subject: mac80211: fix kernel-doc Moving information from config_interface to bss_info_changed removed struct ieee80211_if_conf which the documentation still refers to, additionally there's one kernel-doc description too much and one other missing, fix all this. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index fbeaffc..e369866 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl @@ -145,7 +145,6 @@ usage should require reading the full document. interface in STA mode at first! !Finclude/net/mac80211.h ieee80211_if_init_conf -!Finclude/net/mac80211.h ieee80211_if_conf diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d10ed17..2d06105 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -173,7 +173,6 @@ enum ieee80211_bss_change { * @timestamp: beacon timestamp * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp - * @ht: BSS's HT configuration * @basic_rates: bitmap of basic rates, each bit stands for an * index into the rate table configured by the driver in * the current band. diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f53aa9d..49a1a1f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -216,6 +216,7 @@ struct sta_ampdu_mlme { * @plink_state: peer link state * @plink_timeout: timeout of peer link * @plink_timer: peer link watch timer + * @plink_timer_was_running: used by suspend/resume to restore timers * @debugfs: debug filesystem info * @sta: station information we share with the driver */ -- cgit v0.10.2 From 9a23f9ca50943c1b4535d22b3acda3c31b4ad072 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 May 2009 17:01:38 +0300 Subject: ath9k: Wake up for TX in mac80211 timeout=0 sleep mode When using timeout=0 (PS-Poll) with mac80211, the driver will need to wake up for TX requests and remain awake until the TX has been completed (ACK received or timeout) or until the buffer frame(s) have been received (in case the TX is for a PS-Poll frame). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bd2363f..0d4ac43 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -516,6 +516,8 @@ struct ath_rfkill { #define SC_OP_SCANNING BIT(14) #define SC_OP_TSF_RESET BIT(15) #define SC_OP_WAIT_FOR_CAB BIT(16) +#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) +#define SC_OP_WAIT_FOR_TX_ACK BIT(18) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); @@ -678,7 +680,9 @@ static inline void ath9k_ps_restore(struct ath_softc *sc) { if (atomic_dec_and_test(&sc->ps_usecount)) if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) ath9k_hw_setpower(sc->sc_ah, sc->sc_ah->restore_mode); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c161b75..7c3a98b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2070,6 +2070,31 @@ static int ath9k_tx(struct ieee80211_hw *hw, goto exit; } + if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { + /* + * We are using PS-Poll and mac80211 can request TX while in + * power save mode. Need to wake up hardware for the TX to be + * completed and if needed, also for RX of buffered frames. + */ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + ath9k_ps_wakeup(sc); + ath9k_hw_setrxabort(sc->sc_ah, 0); + if (ieee80211_is_pspoll(hdr->frame_control)) { + DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a " + "buffered frame\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; + } else { + DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; + } + /* + * The actual restore operation will happen only after + * the sc_flags bit is cleared. We are just dropping + * the ps_usecount here. + */ + ath9k_ps_restore(sc); + } + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* @@ -2307,7 +2332,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK); if (sc->imask & ATH9K_INT_TIM_TIMER) { sc->imask &= ~ATH9K_INT_TIM_TIMER; ath9k_hw_set_interrupts(sc->sc_ah, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 5567517..5e046b5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -560,7 +560,8 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; /* Process Beacon and CAB receive in PS state */ - if (ieee80211_is_beacon(hdr->frame_control)) + if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) && + ieee80211_is_beacon(hdr->frame_control)) ath_rx_ps_beacon(sc, skb); else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && (ieee80211_is_data(hdr->frame_control) || @@ -574,6 +575,16 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) * point. */ ath_rx_ps_back_to_sleep(sc); + } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && + !is_multicast_ether_addr(hdr->addr1) && + !ieee80211_has_morefrags(hdr->frame_control)) { + sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; + DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " + "received PS-Poll data (0x%x)\n", + sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK)); } } @@ -798,7 +809,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) sc->rx.rxotherant = 0; } - if (unlikely(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) + if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_PSPOLL_DATA))) ath_rx_ps(sc, skb); ath_rx_send_to_mac80211(sc, skb, &rx_status); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3f2bd79..a8def4f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1790,6 +1790,16 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, skb_pull(skb, padsize); } + if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { + sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; + DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " + "received TX status (0x%x)\n", + sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK)); + } + if (frame_type == ATH9K_NOT_INTERNAL) ieee80211_tx_status(hw, skb); else -- cgit v0.10.2 From 1ffc1c61bdbe31105d99d65043bbf7ae6d24dbc7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 May 2009 17:01:39 +0300 Subject: ath9k: Do not try to calibrate radio when in sleep mode When the chip is in sleep mode, there is no point trying to calibrate the radio since it will just results in incorrect values being read from registers and other potential issues. In addition, if we actually start processing calibrate, do not allow the chip to be put into sleep until we have completed the calibration step. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7c3a98b..dd54fa7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -329,6 +329,12 @@ static void ath_ani_calibrate(unsigned long data) if (sc->sc_flags & SC_OP_SCANNING) goto set_timer; + /* Only calibrate if awake */ + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) + goto set_timer; + + ath9k_ps_wakeup(sc); + /* Long calibration runs independently of short calibration. */ if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; @@ -380,6 +386,8 @@ static void ath_ani_calibrate(unsigned long data) } } + ath9k_ps_restore(sc); + set_timer: /* * Set timer interval based on previous results. -- cgit v0.10.2 From 54ce846e2c5ade77bc6650d8e8c7e775e01ad859 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 May 2009 17:01:40 +0300 Subject: ath9k: Use TSFOOR interrupt to trigger TSF sync with next Beacon If the chip complains about TSF sync, make sure we remain awake to sync with the next Beacon frame. In theory, this should not be needed since we are currently trying to receive all Beacon frames, anyway, better have this code ready should we ever change that. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dd54fa7..d2ef973 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -480,6 +480,16 @@ static void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_TX) ath_tx_tasklet(sc); + if ((status & ATH9K_INT_TSFOOR) && + (sc->hw->conf.flags & IEEE80211_CONF_PS)) { + /* + * TSF sync does not look correct; remain awake to sync with + * the next Beacon. + */ + DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; + } + /* re-enable hardware interrupt */ ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); ath9k_ps_restore(sc); -- cgit v0.10.2 From aa68aeaaff8bbf58e355eb83b7d0c14ce82b2f12 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 May 2009 17:01:41 +0300 Subject: ath9k: Wake up for RX filter changes We must make sure the chip is awake when changing the RX filter parameters. This could have caused problems, e.g., when changing the interface to promiscuous mode while in sleep mode. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d2ef973..d6545b3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2428,8 +2428,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, *total_flags &= SUPPORTED_FILTERS; sc->rx.rxfilter = *total_flags; + ath9k_ps_wakeup(sc); rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); + ath9k_ps_restore(sc); DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); } -- cgit v0.10.2 From dc8c4585d2e6f3bf5c9d8c0a6036b591bd3baf2e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 May 2009 17:01:42 +0300 Subject: ath9k: Set PM field in frame control when in PS mode mac80211 does not set PM field for normal data frames, so we need to update that based on the current PS mode when using PS-Poll (timeout=0) power save mode. This allows the AP to remain in sync with our PS state. However, there is still a potential race condition between PS state changes when multiple TX queues are used and nullfunc and PS-Poll frames use different queue. That corner case may need to be handled separately by changing which queue is used either in ath9k or mac80211. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d6545b3..77fbc46 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2088,6 +2088,21 @@ static int ath9k_tx(struct ieee80211_hw *hw, goto exit; } + if (sc->hw->conf.flags & IEEE80211_CONF_PS) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + /* + * mac80211 does not set PM field for normal data frames, so we + * need to update that based on the current PS mode. + */ + if (ieee80211_is_data(hdr->frame_control) && + !ieee80211_is_nullfunc(hdr->frame_control) && + !ieee80211_has_pm(hdr->frame_control)) { + DPRINTF(sc, ATH_DBG_PS, "Add PM=1 for a TX frame " + "while in PS mode\n"); + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + } + if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { /* * We are using PS-Poll and mac80211 can request TX while in -- cgit v0.10.2 From 30196673fe17934617b5d5bfd456a0edf057a0b9 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 May 2009 17:01:43 +0300 Subject: mac80211: PS processing for every Beacon with our AID in TIM If the AP includes our AID in the TIM IE, we need to process the Beacon frame as far as PS is concerned (send PS-Poll or nullfunc data with PM=0). The previous code skipped this in cases where the CRC value did not change and it would not change if the AP continues including our AID in the TIM.. There is no need to count the crc32 value for directed_tim with this change, so we can remove that part. In order not to change the order of operations (i.e., update WMM parameters prior to sending PS-Poll), the CRC match is checked twice as only after the PS processing step, the rest of the function is skipped if nothing changed in the Beacon. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b61a781..54a2a1d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1951,16 +1951,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid); - ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim)); + if (ncrc != ifmgd->beacon_crc) { + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, + true); - if (ncrc == ifmgd->beacon_crc) - return; - ifmgd->beacon_crc = ncrc; - - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); - - ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, - elems.wmm_param_len); + ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, + elems.wmm_param_len); + } if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { if (directed_tim) { @@ -1985,6 +1982,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } } + if (ncrc == ifmgd->beacon_crc) + return; + ifmgd->beacon_crc = ncrc; + if (elems.erp_info && elems.erp_info_len >= 1) { erp_valid = true; erp_value = elems.erp_info[0]; -- cgit v0.10.2 From 7e0aae4732067e1bdb546071423a0b3483a79d9a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 19 May 2009 19:25:58 +0300 Subject: mac80211: Do not override AID in the duration field When updating the duration field for TX frames, skip the update for PS-Poll frames that use this field for other purposes (AID). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8f68bf9..a910148 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -872,6 +872,8 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) do { hdr = (void *) skb->data; + if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) + break; /* must not overwrite AID */ next_len = skb->next ? skb->next->len : 0; group_addr = is_multicast_ether_addr(hdr->addr1); -- cgit v0.10.2 From ce4c45e099a81b2bc820b6e145aa9058c5acf0bd Mon Sep 17 00:00:00 2001 From: Alexandre Becholey Date: Tue, 19 May 2009 17:52:56 +0200 Subject: rt73usb: fix for master mode Report status unknown as if there were successfully transmitted. This will avoid hostapd to disassociate because it doesn't understand what a status unknown is. Signed-off-by: Alexandre Becholey Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f227084..57813e7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -260,7 +260,8 @@ void rt2x00lib_txdone(struct queue_entry *entry, * Update TX statistics. */ rt2x00dev->link.qual.tx_success += - test_bit(TXDONE_SUCCESS, &txdesc->flags); + test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags); rt2x00dev->link.qual.tx_failed += test_bit(TXDONE_FAILURE, &txdesc->flags); @@ -278,14 +279,16 @@ void rt2x00lib_txdone(struct queue_entry *entry, tx_info->status.rates[1].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags)) tx_info->flags |= IEEE80211_TX_STAT_ACK; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSFailureCount++; -- cgit v0.10.2 From 175427ce40bd5a3f973a76c46502875f0eed877c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 May 2009 22:16:25 +0200 Subject: mac80211: don't try to do anything on unchanged genIE When the genIE hasn't changed there's no reason to kick the state machine since it won't be able to do anything new -- doing this decreases the useless work we do for reassociating because if we do kick the state machine it will try to find a usable BSS but there might not be one because wpa_supplicant will only change the BSSID a little later. In a sense this is a workaround for userspace behaviour, but on the other hand userspace cannot really keep track of what the kernel currently has for genIE since any process could have changed that while wpa_supplicant wasn't looking. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 54a2a1d..87743e4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2492,6 +2492,13 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + if (len == 0 && ifmgd->extra_ie_len == 0) + return -EALREADY; + + if (len == ifmgd->extra_ie_len && ifmgd->extra_ie && + memcmp(ifmgd->extra_ie, ie, len) == 0) + return -EALREADY; + kfree(ifmgd->extra_ie); if (len == 0) { ifmgd->extra_ie = NULL; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index c143947..a01154e 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -37,12 +37,13 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_STATION) { int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); - if (ret) + if (ret && ret != -EALREADY) return ret; sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - ieee80211_sta_req_auth(sdata); + if (ret != -EALREADY) + ieee80211_sta_req_auth(sdata); return 0; } -- cgit v0.10.2 From c26c2e576dc05d90e8eadc0c6ca273ed7aa12535 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 19 May 2009 18:27:11 -0400 Subject: ath9k: fix custom regulatory call position ath_regd_init() needs to be called with the wiphy already properly set with the bands. Without this the custom regulatory settings were not taking effect, and the device would get the default channel settings from ath9k_[25]ghz_chantable. Reported-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 77fbc46..1839b55 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1430,8 +1430,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, - ath9k_reg_notifier); if (error) goto bad; @@ -1644,14 +1642,19 @@ int ath_attach(u16 devid, struct ath_softc *sc) if (error != 0) return error; - reg = &sc->sc_ah->regulatory; - /* get mac address from hardware and set in mac80211 */ SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); ath_set_hw_capab(sc, hw); + error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + ath9k_reg_notifier); + if (error) + return error; + + reg = &sc->sc_ah->regulatory; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) -- cgit v0.10.2 From db67645db623caa12976293caa95fcd33d8c11b4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 May 2009 09:05:10 +0200 Subject: mac80211: fix parameter confusion when finding IBSS When I fixed the crypto bit I must have done the negative test only -- it is quite clearly impossible to find _any_ IBSS to join with the parameters put the wrong way around. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ebf7318..0b30277 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -535,9 +535,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) bssid = ifibss->bssid; bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, ifibss->ssid, ifibss->ssid_len, - capability, WLAN_CAPABILITY_IBSS | - WLAN_CAPABILITY_PRIVACY); + WLAN_CAPABILITY_PRIVACY, + capability); #ifdef CONFIG_MAC80211_IBSS_DEBUG if (bss) -- cgit v0.10.2 From eeddfd9db3b1c50d49202d0be35aae187fa90129 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 19 May 2009 17:49:46 -0400 Subject: ath9k: set max default eirp to 20 dBm This is always discarded anyway but lets just set this to our safest lowest. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1839b55..5759c94 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -35,14 +35,14 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); #define CHAN2G(_freq, _idx) { \ .center_freq = (_freq), \ .hw_value = (_idx), \ - .max_power = 30, \ + .max_power = 20, \ } #define CHAN5G(_freq, _idx) { \ .band = IEEE80211_BAND_5GHZ, \ .center_freq = (_freq), \ .hw_value = (_idx), \ - .max_power = 30, \ + .max_power = 20, \ } /* Some 2 GHz radios are actually tunable on 2312-2732 -- cgit v0.10.2 From bbcf3f02771e069d0e113fe9bb62c27b671abf97 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 19 May 2009 17:49:47 -0400 Subject: cfg80211: warn when wiphy_apply_custom_regulatory() does nothing Device drivers using wiphy_apply_custom_regulatory() want some regulatory settings applied to their wiphy, if no bands were configured on the wiphy then something went wrong. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8d176a8..df0ced9 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1344,13 +1344,22 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, const struct ieee80211_regdomain *regd) { enum ieee80211_band band; + unsigned int bands_set = 0; mutex_lock(&cfg80211_mutex); for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - if (wiphy->bands[band]) - handle_band_custom(wiphy, band, regd); + if (!wiphy->bands[band]) + continue; + handle_band_custom(wiphy, band, regd); + bands_set++; } mutex_unlock(&cfg80211_mutex); + + /* + * no point in calling this if it won't have any effect + * on your device's supportd bands. + */ + WARN_ON(!bands_set); } EXPORT_SYMBOL(wiphy_apply_custom_regulatory); -- cgit v0.10.2 From 9cef873798dfcdc10ff40b02abf1de935ceeba85 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 May 2009 13:10:14 +0200 Subject: mac80211: fix managed mode BSSID handling Currently, we will ask the driver to configure right away when somebody changes the desired BSSID. That's totally strange because then we will configure the driver without even knowing whether the BSS exists. Change this to only configure the BSSID when associated, and configure a zero BSSID when not associated. As a side effect, this fixes an issue with the iwlwifi driver which doesn't implement sta_notify properly and uses the BSSID instead and gets very confused if the BSSID is cleared before we disassociate, which results in the warning Marcel posted [1] and iwlwifi bug 1995 [2]. [1] http://thread.gmane.org/gmane.linux.kernel.wireless.general/32598 [2] http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1995 Cc: Marcel Holtmann Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 76df5ea..6b7e92e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -219,18 +219,26 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed) { struct ieee80211_local *local = sdata->local; + static const u8 zero[ETH_ALEN] = { 0 }; if (!changed) return; - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; - else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + /* + * While not associated, claim a BSSID of all-zeroes + * so that drivers don't do any weird things with the + * BSSID at that time. + */ + if (sdata->vif.bss_conf.assoc) + sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; + else + sdata->vif.bss_conf.bssid = zero; + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; else if (sdata->vif.type == NL80211_IFTYPE_AP) sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; else if (ieee80211_vif_is_mesh(&sdata->vif)) { - static const u8 zero[ETH_ALEN] = { 0 }; sdata->vif.bss_conf.bssid = zero; } else { WARN_ON(1); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 87743e4..b7f9c60 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -977,6 +977,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, * changed or not. */ bss_info_changed |= BSS_CHANGED_BASIC_RATES; + + /* And the BSSID changed - we're associated now */ + bss_info_changed |= BSS_CHANGED_BSSID; + ieee80211_bss_info_change_notify(sdata, bss_info_changed); /* will be same as sdata */ @@ -1176,6 +1180,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } ieee80211_hw_config(local, config_changed); + + /* And the BSSID changed -- not very interesting here */ + changed |= BSS_CHANGED_BSSID; ieee80211_bss_info_change_notify(sdata, changed); rcu_read_lock(); @@ -2481,9 +2488,6 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; } - if (netif_running(sdata->dev)) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); - return ieee80211_sta_commit(sdata); } -- cgit v0.10.2 From 288ddad5b095ff65812cf1060c67d23c07568871 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 20 May 2009 15:52:40 -0700 Subject: syscall: Sort out syscall_restart name clash. Stephen Rothwell writes: > Today's linux-next build of at least some av32 and arm configs failed like this: > > arch/avr32/kernel/signal.c:216: error: conflicting types for 'restart_syscall' > include/linux/sched.h:2184: error: previous definition of 'restart_syscall' was here > > Caused by commit 690cc3ffe33ac4a2857583c22d4c6244ae11684d ("syscall: > Implement a convinience function restart_syscall") from the net tree. Grrr. Some days it feels like all of the good names are already taken. Let's just rename the two static users in arm and avr32 to get this sorted out. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 80b8b5c..614c9f6 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -532,7 +532,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, return err; } -static inline void restart_syscall(struct pt_regs *regs) +static inline void setup_syscall_restart(struct pt_regs *regs) { regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; @@ -567,7 +567,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, } /* fallthrough */ case -ERESTARTNOINTR: - restart_syscall(regs); + setup_syscall_restart(regs); } } @@ -691,7 +691,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (regs->ARM_r0 == -ERESTARTNOHAND || regs->ARM_r0 == -ERESTARTSYS || regs->ARM_r0 == -ERESTARTNOINTR) { - restart_syscall(regs); + setup_syscall_restart(regs); } } single_step_set(current); diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 803d7be..2722756 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -212,7 +212,7 @@ out: return err; } -static inline void restart_syscall(struct pt_regs *regs) +static inline void setup_syscall_restart(struct pt_regs *regs) { if (regs->r12 == -ERESTART_RESTARTBLOCK) regs->r8 = __NR_restart_syscall; @@ -296,7 +296,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall) } /* fall through */ case -ERESTARTNOINTR: - restart_syscall(regs); + setup_syscall_restart(regs); } } -- cgit v0.10.2 From 04af8cf6f320031090ab6fa4600b912b0c18fb4b Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Wed, 20 May 2009 17:26:23 -0700 Subject: net: Remove unused parameter from fill method in fib_rules_ops. The netlink message header (struct nlmsghdr) is an unused parameter in fill method of fib_rules_ops struct. This patch removes this parameter from this method and fixes the places where this method is called. (include/net/fib_rules.h) Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index b9b6339..ca4b2e8 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -54,7 +54,6 @@ struct fib_rules_ops struct fib_rule_hdr *, struct nlattr **); int (*fill)(struct fib_rule *, struct sk_buff *, - struct nlmsghdr *, struct fib_rule_hdr *); u32 (*default_pref)(struct fib_rules_ops *ops); size_t (*nlmsg_payload)(struct fib_rule *); diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 17d9f49..bd30938 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -500,7 +500,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, if (rule->target) NLA_PUT_U32(skb, FRA_GOTO, rule->target); - if (ops->fill(rule, skb, nlh, frh) < 0) + if (ops->fill(rule, skb, frh) < 0) goto nla_put_failure; return nlmsg_end(skb, nlh); diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index a2690b1..72495f2 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -192,7 +192,7 @@ unsigned dnet_addr_type(__le16 addr) } static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh) + struct fib_rule_hdr *frh) { struct dn_fib_rule *r = (struct dn_fib_rule *)rule; diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 38904be..92d9d97 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -209,7 +209,7 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, } static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh) + struct fib_rule_hdr *frh) { struct fib4_rule *rule4 = (struct fib4_rule *) rule; diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index e1a36db..00a7a5e 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -211,7 +211,7 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, } static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh) + struct fib_rule_hdr *frh) { struct fib6_rule *rule6 = (struct fib6_rule *) rule; -- cgit v0.10.2 From f214856540f6d704e817bf6b26a6bca9e697ee72 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 19 May 2009 21:38:37 +0000 Subject: qeth: avoid crash after detach of replugged device If a qeth device is plugged off, setting the device online stops in state HARDSETUP and a failure is reported to the base cio-layer causing halt/clear to be invoked. Replugging the device again triggers a qeth recovery without notification of the cio-layer. If a device is ungrouped in this state, the qeth set_offline function is not invoked, because the corresponding ccwgroup device is not in state ONLINE. Then incoming traffic is still handled by the qdio layer resulting in a crash in qeth_l_qdio_input_handler, because (part of) the qeth data structures for this device are already removed. Solution: After replugging the device qeth recovery should lead to a working net device. Thus a "LAN offline" result when setting a qeth device online must not report a failure to the base cio-layer. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 172031b..44c1568 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -839,6 +839,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); if (cgdev->state == CCWGROUP_ONLINE) { @@ -974,8 +975,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_warn(&card->gdev->dev, "The LAN is offline\n"); card->lan_online = 0; + return 0; } - return rc; + goto out_remove; } else card->lan_online = 1; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 0ba3817..5873240 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3070,6 +3070,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); if (cgdev->state == CCWGROUP_ONLINE) { @@ -3141,8 +3142,9 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_warn(&card->gdev->dev, "The LAN is offline\n"); card->lan_online = 0; + return 0; } - return rc; + goto out_remove; } else card->lan_online = 1; qeth_set_large_send(card, card->options.large_send); -- cgit v0.10.2 From 8ac6d452281b01b9c7ff382d640b547379e398cd Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 19 May 2009 21:38:38 +0000 Subject: ctcm: avoid crash in ctcm_remove_device Channels are already removed when setting a ctcm-device offline. Thus ctcm_remove_device must not refer to channel information. Solution: delete channel information from the trace call in ctcm_remove_device. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 77f4033..54c4649 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1677,10 +1677,8 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) BUG_ON(priv == NULL); CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, - "removing device %s, r/w = %s/%s, proto : %d", - priv->channel[READ]->netdev->name, - priv->channel[READ]->id, priv->channel[WRITE]->id, - priv->protocol); + "removing device %p, proto : %d", + cgdev, priv->protocol); if (cgdev->state == CCWGROUP_ONLINE) ctcm_shutdown_device(cgdev); -- cgit v0.10.2 From 0666eb06ab12b1f876719ff5b7d39cf3c609dec3 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 19 May 2009 21:38:39 +0000 Subject: qeth: support z/VM VSWITCH Port Isolation z/VM Virtual Switch Port Isolation allows guests on a VLAN UNAWARE virtual switch to be isolated from other guests on the VSWITCH. (See z/VM Apars VM64281 and VM64463). The Linux qeth driver is affected, because it has to handle new error codes introduced with the z/VM VSWITCH Port Isolation support. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index 06f4de1..ec24901 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -181,6 +181,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, + {IPA_RC_L2_MAC_NOT_AUTH_BY_HYP, "L2 mac not authorized by hypervisor"}, + {IPA_RC_L2_MAC_NOT_AUTH_BY_ADP, "L2 mac not authorized by adapter"}, {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 1854882..eecb2ee 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -168,6 +168,8 @@ enum qeth_ipa_return_codes { IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, + IPA_RC_L2_MAC_NOT_AUTH_BY_HYP = 0x200c, + IPA_RC_L2_MAC_NOT_AUTH_BY_ADP = 0x200d, IPA_RC_L2_MAC_NOT_FOUND = 0x2010, IPA_RC_L2_INVALID_VLAN_ID = 0x2015, IPA_RC_L2_DUP_VLAN_ID = 0x2016, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 44c1568..9ca6bab 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -130,7 +130,7 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; mac = &cmd->data.setdelmac.mac[0]; /* MAC already registered, needed in couple/uncouple case */ - if (cmd->hdr.return_code == 0x2005) { + if (cmd->hdr.return_code == IPA_RC_L2_DUP_MAC) { QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", mac, QETH_CARD_IFNAME(card)); cmd->hdr.return_code = 0; @@ -502,6 +502,30 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, if (cmd->hdr.return_code) { QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; + switch (cmd->hdr.return_code) { + case IPA_RC_L2_DUP_MAC: + case IPA_RC_L2_DUP_LAYER3_MAC: + dev_warn(&card->gdev->dev, + "MAC address " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + "already exists\n", + card->dev->dev_addr[0], card->dev->dev_addr[1], + card->dev->dev_addr[2], card->dev->dev_addr[3], + card->dev->dev_addr[4], card->dev->dev_addr[5]); + break; + case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: + case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: + dev_warn(&card->gdev->dev, + "MAC address " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + "is not authorized\n", + card->dev->dev_addr[0], card->dev->dev_addr[1], + card->dev->dev_addr[2], card->dev->dev_addr[3], + card->dev->dev_addr[4], card->dev->dev_addr[5]); + break; + default: + break; + } cmd->hdr.return_code = -EIO; } else { card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; -- cgit v0.10.2 From b91398008cae916c528d907f5d7a9ed54f35b4e9 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 19 May 2009 21:38:40 +0000 Subject: qeth: omit upstream checksumming for HiperSockets For HiperSocket devices receive-path checksumming is not required. Thus NO_CHECKSUMMING is used as default for HiperSocket interfaces. For layer3 devices configured with NO_CHECKSUMMING received skbs should have set their ip_summed field to CHECKSUM_UNNECESSARY. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c827d69..63c9c05 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1140,6 +1140,8 @@ static int qeth_setup_card(struct qeth_card *card) card->ipato.enabled = 0; card->ipato.invert4 = 0; card->ipato.invert6 = 0; + if (card->info.type == QETH_CARD_TYPE_IQD) + card->options.checksum_type = NO_CHECKSUMMING; /* init QDIO stuff */ qeth_init_qdio_info(card); return 0; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 5873240..b36b5cd 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1920,16 +1920,22 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); } - skb->ip_summed = card->options.checksum_type; - if (card->options.checksum_type == HW_CHECKSUMMING) { + switch (card->options.checksum_type) { + case SW_CHECKSUMMING: + skb->ip_summed = CHECKSUM_NONE; + break; + case NO_CHECKSUMMING: + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + case HW_CHECKSUMMING: if ((hdr->hdr.l3.ext_flags & - (QETH_HDR_EXT_CSUM_HDR_REQ | - QETH_HDR_EXT_CSUM_TRANSP_REQ)) == - (QETH_HDR_EXT_CSUM_HDR_REQ | - QETH_HDR_EXT_CSUM_TRANSP_REQ)) + (QETH_HDR_EXT_CSUM_HDR_REQ | + QETH_HDR_EXT_CSUM_TRANSP_REQ)) == + (QETH_HDR_EXT_CSUM_HDR_REQ | + QETH_HDR_EXT_CSUM_TRANSP_REQ)) skb->ip_summed = CHECKSUM_UNNECESSARY; else - skb->ip_summed = SW_CHECKSUMMING; + skb->ip_summed = CHECKSUM_NONE; } return vlan_id; -- cgit v0.10.2 From 9f29f6de56462a363d3cc1d5f000961d622c5888 Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacket Date: Tue, 19 May 2009 21:38:41 +0000 Subject: qeth: Clear SBALF15 in any case for output buffers. Function qeth_clear_output_buffer for HiperSockets may not clear all 16 SBALEs, but only the used ones. The error flag in SBALF15 has to be cleared in any case. Signed-off-by: Klaus-Dieter Wacker Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 63c9c05..2994aa1 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -952,6 +952,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, buf->buffer->element[i].addr = NULL; buf->buffer->element[i].flags = 0; } + buf->buffer->element[15].flags = 0; buf->next_element_to_fill = 0; atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } -- cgit v0.10.2 From aa22437e87469fdee94b5344780b4a3dbb87a154 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 19 May 2009 13:21:07 +0000 Subject: chelsio: Use generic XENPAK LASI register definitions Signed-off-by: Ben Hutchings Acked-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c index 29e0cba..d50907b 100644 --- a/drivers/net/chelsio/mv88x201x.c +++ b/drivers/net/chelsio/mv88x201x.c @@ -86,7 +86,8 @@ static int mv88x201x_reset(struct cphy *cphy, int wait) static int mv88x201x_interrupt_enable(struct cphy *cphy) { /* Enable PHY LASI interrupts. */ - cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, 0x9002, 0x1); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + MDIO_PMA_LASI_LSALARM); /* Enable Marvell interrupts through Elmer0. */ if (t1_is_asic(cphy->adapter)) { @@ -102,7 +103,7 @@ static int mv88x201x_interrupt_enable(struct cphy *cphy) static int mv88x201x_interrupt_disable(struct cphy *cphy) { /* Disable PHY LASI interrupts. */ - cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, 0x9002, 0x0); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0x0); /* Disable Marvell interrupts through Elmer0. */ if (t1_is_asic(cphy->adapter)) { @@ -122,9 +123,9 @@ static int mv88x201x_interrupt_clear(struct cphy *cphy) #ifdef MV88x2010_LINK_STATUS_BUGS /* Required to read twice before clear takes affect. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9003, &val); - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9004, &val); - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9005, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); /* Read this register after the others above it else * the register doesn't clear correctly. @@ -135,12 +136,12 @@ static int mv88x201x_interrupt_clear(struct cphy *cphy) /* Clear link status. */ cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); /* Clear PHY LASI interrupts. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9005, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); #ifdef MV88x2010_LINK_STATUS_BUGS /* Do it again. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9003, &val); - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, 0x9004, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); #endif /* Clear Marvell interrupts through Elmer0. */ -- cgit v0.10.2 From 64318334bf5096a65c7141bea4833910d112d939 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 19 May 2009 13:22:30 +0000 Subject: cxgb3: Use generic XENPAK LASI register definitions Signed-off-by: Ben Hutchings Acked-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index bebc00d..df1f585 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -1007,7 +1007,8 @@ static int ael2005_reset(struct cphy *phy, int wait) int err; unsigned int lasi_ctrl; - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, LASI_CTRL, &lasi_ctrl); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); if (err) return err; diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 3147789..79a113b 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -521,16 +521,6 @@ enum { MAC_RXFIFO_SIZE = 32768 }; -/* 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 */ enum { PHY_LOOPBACK_TX = 1, diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index c8a865a..505a187 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -472,29 +472,31 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) int t3_phy_lasi_intr_enable(struct cphy *phy) { - return t3_mdio_write(phy, MDIO_MMD_PMAPMD, LASI_CTRL, 1); + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + MDIO_PMA_LASI_LSALARM); } int t3_phy_lasi_intr_disable(struct cphy *phy) { - return t3_mdio_write(phy, MDIO_MMD_PMAPMD, LASI_CTRL, 0); + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0); } int t3_phy_lasi_intr_clear(struct cphy *phy) { u32 val; - return t3_mdio_read(phy, MDIO_MMD_PMAPMD, LASI_STAT, &val); + return t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); } int t3_phy_lasi_intr_handler(struct cphy *phy) { unsigned int status; - int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, LASI_STAT, &status); + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, + &status); if (err) return err; - return (status & 1) ? cphy_cause_link_change : 0; + return (status & MDIO_PMA_LASI_LSALARM) ? cphy_cause_link_change : 0; } static const struct adapter_info t3_adap_info[] = { -- cgit v0.10.2 From 86c890ab1b183f8f17ce03c24b62c564e95f957f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 20 May 2009 15:56:02 +0000 Subject: cxgb3: set phy's mdio dev before the phy init sequence mdio's dev field needs to be set before mdio ops occur. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 505a187..fc7db8a 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3866,11 +3866,11 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, return -EINVAL; } + p->phy.mdio.dev = adapter->port[i]; ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, ai->mdio_ops); if (ret) return ret; - p->phy.mdio.dev = adapter->port[i]; mac_prep(&p->mac, adapter, j); /* -- cgit v0.10.2 From 703cebabd173a7fe533d6f21df0347b1f2a9a1e1 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 20 May 2009 15:56:12 +0000 Subject: cxgb: set phy's mdio dev before the phy init sequence mdio's dev field needs to be set before mdio ops occur. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h index 8b5165a..1f095a9 100644 --- a/drivers/net/chelsio/cphy.h +++ b/drivers/net/chelsio/cphy.h @@ -137,10 +137,11 @@ static inline int simple_mdio_write(struct cphy *cphy, int reg, } /* Convenience initializer */ -static inline void cphy_init(struct cphy *phy, adapter_t *adapter, +static inline void cphy_init(struct cphy *phy, struct net_device *dev, int phy_addr, struct cphy_ops *phy_ops, const struct mdio_ops *mdio_ops) { + struct adapter *adapter = netdev_priv(dev); phy->adapter = adapter; phy->ops = phy_ops; if (mdio_ops) { @@ -150,12 +151,13 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, phy->mdio.mdio_read = mdio_ops->read; phy->mdio.mdio_write = mdio_ops->write; } + phy->mdio.dev = dev; } /* Operations of the PHY-instance factory */ struct gphy { /* Construct a PHY instance with the given PHY address */ - struct cphy *(*create)(adapter_t *adapter, int phy_addr, + struct cphy *(*create)(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops); /* diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c index 0632be0..809047a 100644 --- a/drivers/net/chelsio/mv88e1xxx.c +++ b/drivers/net/chelsio/mv88e1xxx.c @@ -353,15 +353,16 @@ static struct cphy_ops mv88e1xxx_ops = { .get_link_status = mv88e1xxx_get_link_status, }; -static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, +static struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops) { + struct adapter *adapter = netdev_priv(dev); struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); if (!cphy) return NULL; - cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops); + cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops); /* Configure particular PHY's to run in a different mode. */ if ((board_info(adapter)->caps & SUPPORTED_TP) && diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c index d50907b..f7136b2 100644 --- a/drivers/net/chelsio/mv88x201x.c +++ b/drivers/net/chelsio/mv88x201x.c @@ -209,7 +209,7 @@ static struct cphy_ops mv88x201x_ops = { MDIO_DEVS_PHYXS | MDIO_DEVS_WIS), }; -static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, +static struct cphy *mv88x201x_phy_create(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops) { u32 val; @@ -218,7 +218,7 @@ static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, if (!cphy) return NULL; - cphy_init(cphy, adapter, phy_addr, &mv88x201x_ops, mdio_ops); + cphy_init(cphy, dev, phy_addr, &mv88x201x_ops, mdio_ops); /* Commands the PHY to enable XFP's clock. */ cphy_mdio_read(cphy, MDIO_MMD_PCS, 0x8300, &val); diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 977c7e0..4c60285 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -167,7 +167,7 @@ static struct cphy_ops my3126_ops = { MDIO_DEVS_PHYXS), }; -static struct cphy *my3126_phy_create(adapter_t *adapter, +static struct cphy *my3126_phy_create(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); @@ -175,7 +175,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter, if (!cphy) return NULL; - cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); + cphy_init(cphy, dev, phy_addr, &my3126_ops, mdio_ops); INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 2564312..17720c6 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -1135,14 +1135,13 @@ int __devinit t1_init_sw_modules(adapter_t *adapter, struct cmac *mac; int phy_addr = bi->mdio_phybaseaddr + i; - adapter->port[i].phy = bi->gphy->create(adapter, phy_addr, - bi->mdio_ops); + adapter->port[i].phy = bi->gphy->create(adapter->port[i].dev, + phy_addr, bi->mdio_ops); if (!adapter->port[i].phy) { CH_ERR("%s: PHY %d initialization failed\n", adapter->name, i); goto error; } - adapter->port[i].phy->mdio.dev = adapter->port[i].dev; adapter->port[i].mac = mac = bi->gmac->create(adapter, i); if (!mac) { -- cgit v0.10.2 From 1f7a2bb4eff75c56a71b3896c36a34e787c5e4e5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 21 May 2009 15:10:05 -0700 Subject: netns: remove leftover debugging message Signed-off-by: Stephen Hemminger Acked-by: "Eric W. Biederman" Signed-off-by: David S. Miller diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 6b3edc9..69d7549 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -198,7 +198,6 @@ static int __init net_ns_init(void) struct net_generic *ng; int err; - printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net)); #ifdef CONFIG_NET_NS net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), SMP_CACHE_BYTES, -- cgit v0.10.2 From ca0f31125c5cf0d48f47c2e1a3785a08876a7e87 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 21 May 2009 15:10:31 -0700 Subject: netns: simplify net_ns_init The net_ns_init code can be simplified. No need to save error code if it is only going to panic if it is set 4 lines later. Signed-off-by: Stephen Hemminger Acked-by: "Eric W. Biederman" Signed-off-by: David S. Miller diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 69d7549..b7292a2 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -196,7 +196,6 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) static int __init net_ns_init(void) { struct net_generic *ng; - int err; #ifdef CONFIG_NET_NS net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), @@ -216,15 +215,14 @@ static int __init net_ns_init(void) rcu_assign_pointer(init_net.gen, ng); mutex_lock(&net_mutex); - err = setup_net(&init_net); + if (setup_net(&init_net)) + panic("Could not setup the initial network namespace"); rtnl_lock(); list_add_tail(&init_net.list, &net_namespace_list); rtnl_unlock(); mutex_unlock(&net_mutex); - if (err) - panic("Could not setup the initial network namespace"); return 0; } -- cgit v0.10.2 From d95ed9275edcb8995bda31005bb3f55e087626d7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 19 May 2009 18:27:17 +0000 Subject: af_packet: Teach to listen for multiple unicast addresses. The the PACKET_ADD_MEMBERSHIP and the PACKET_DROP_MEMBERSHIP setsockopt calls for af_packet already has all of the infrastructure needed to subscribe to multiple mac addresses. All that is missing is a flag to say that the address we want to listen on is a unicast address. So introduce PACKET_MR_UNICAST and wire it up to dev_unicast_add and dev_unicast_delete. Additionally I noticed that errors from dev_mc_add were not propagated from packet_dev_mc so fix that. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index 5b2bade..dea7d6b 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -145,5 +145,6 @@ struct packet_mreq #define PACKET_MR_MULTICAST 0 #define PACKET_MR_PROMISC 1 #define PACKET_MR_ALLMULTI 2 +#define PACKET_MR_UNICAST 3 #endif diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 766e6b4..c7c5d52 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1570,9 +1570,9 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, switch (i->type) { case PACKET_MR_MULTICAST: if (what > 0) - dev_mc_add(dev, i->addr, i->alen, 0); + return dev_mc_add(dev, i->addr, i->alen, 0); else - dev_mc_delete(dev, i->addr, i->alen, 0); + return dev_mc_delete(dev, i->addr, i->alen, 0); break; case PACKET_MR_PROMISC: return dev_set_promiscuity(dev, what); @@ -1580,6 +1580,12 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, case PACKET_MR_ALLMULTI: return dev_set_allmulti(dev, what); break; + case PACKET_MR_UNICAST: + if (what > 0) + return dev_unicast_add(dev, i->addr, i->alen); + else + return dev_unicast_delete(dev, i->addr, i->alen); + break; default:; } return 0; -- cgit v0.10.2 From 4ea7e38696c7e798c47ebbecadfd392f23f814f9 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 21 May 2009 07:36:08 +0000 Subject: dropmon: add ability to detect when hardware dropsrxpackets Patch to add the ability to detect drops in hardware interfaces via dropwatch. Adds a tracepoint to net_rx_action to signal everytime a napi instance is polled. The dropmon code then periodically checks to see if the rx_frames counter has changed, and if so, adds a drop notification to the netlink protocol, using the reserved all-0's vector to indicate the drop location was in hardware, rather than somewhere in the code. Signed-off-by: Neil Horman include/linux/net_dropmon.h | 8 ++ include/trace/napi.h | 11 +++ net/core/dev.c | 5 + net/core/drop_monitor.c | 124 ++++++++++++++++++++++++++++++++++++++++++-- net/core/net-traces.c | 4 + net/core/netpoll.c | 2 6 files changed, 149 insertions(+), 5 deletions(-) Signed-off-by: David S. Miller diff --git a/include/linux/net_dropmon.h b/include/linux/net_dropmon.h index 0217fb8..e8a8b5c 100644 --- a/include/linux/net_dropmon.h +++ b/include/linux/net_dropmon.h @@ -2,12 +2,20 @@ #define __NET_DROPMON_H #include +#include struct net_dm_drop_point { __u8 pc[8]; __u32 count; }; +#define is_drop_point_hw(x) do {\ + int ____i, ____j;\ + for (____i = 0; ____i < 8; i ____i++)\ + ____j |= x[____i];\ + ____j;\ +} while (0) + #define NET_DM_CFG_VERSION 0 #define NET_DM_CFG_ALERT_COUNT 1 #define NET_DM_CFG_ALERT_DELAY 2 diff --git a/include/trace/napi.h b/include/trace/napi.h new file mode 100644 index 0000000..a8989c4 --- /dev/null +++ b/include/trace/napi.h @@ -0,0 +1,11 @@ +#ifndef _TRACE_NAPI_H_ +#define _TRACE_NAPI_H_ + +#include +#include + +DECLARE_TRACE(napi_poll, + TP_PROTO(struct napi_struct *napi), + TP_ARGS(napi)); + +#endif diff --git a/net/core/dev.c b/net/core/dev.c index 92ebeca..3942266 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -126,6 +126,7 @@ #include #include #include +#include #include "net-sysfs.h" @@ -2771,8 +2772,10 @@ static void net_rx_action(struct softirq_action *h) * accidently calling ->poll() when NAPI is not scheduled. */ work = 0; - if (test_bit(NAPI_STATE_SCHED, &n->state)) + if (test_bit(NAPI_STATE_SCHED, &n->state)) { work = n->poll(n, weight); + trace_napi_poll(n); + } WARN_ON_ONCE(work > weight); diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 2797b71..a6c2ac2 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -22,8 +22,10 @@ #include #include #include +#include #include +#include #include @@ -38,7 +40,8 @@ static void send_dm_alert(struct work_struct *unused); * and the work handle that will send up * netlink alerts */ -struct sock *dm_sock; +static int trace_state = TRACE_OFF; +static spinlock_t trace_state_lock = SPIN_LOCK_UNLOCKED; struct per_cpu_dm_data { struct work_struct dm_alert_work; @@ -47,6 +50,13 @@ struct per_cpu_dm_data { struct timer_list send_timer; }; +struct dm_hw_stat_delta { + struct net_device *dev; + struct list_head list; + struct rcu_head rcu; + unsigned long last_drop_val; +}; + static struct genl_family net_drop_monitor_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, @@ -59,7 +69,8 @@ static DEFINE_PER_CPU(struct per_cpu_dm_data, dm_cpu_data); static int dm_hit_limit = 64; static int dm_delay = 1; - +static unsigned long dm_hw_check_delta = 2*HZ; +static LIST_HEAD(hw_stats_list); static void reset_per_cpu_data(struct per_cpu_dm_data *data) { @@ -115,7 +126,7 @@ static void sched_send_work(unsigned long unused) schedule_work(&data->dm_alert_work); } -static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) +static void trace_drop_common(struct sk_buff *skb, void *location) { struct net_dm_alert_msg *msg; struct nlmsghdr *nlh; @@ -159,24 +170,80 @@ out: return; } +static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) +{ + trace_drop_common(skb, location); +} + +static void trace_napi_poll_hit(struct napi_struct *napi) +{ + struct dm_hw_stat_delta *new_stat; + + /* + * Ratelimit our check time to dm_hw_check_delta jiffies + */ + if (!time_after(jiffies, napi->dev->last_rx + dm_hw_check_delta)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(new_stat, &hw_stats_list, list) { + if ((new_stat->dev == napi->dev) && + (napi->dev->stats.rx_dropped != new_stat->last_drop_val)) { + trace_drop_common(NULL, NULL); + new_stat->last_drop_val = napi->dev->stats.rx_dropped; + break; + } + } + rcu_read_unlock(); +} + + +static void free_dm_hw_stat(struct rcu_head *head) +{ + struct dm_hw_stat_delta *n; + n = container_of(head, struct dm_hw_stat_delta, rcu); + kfree(n); +} + static int set_all_monitor_traces(int state) { int rc = 0; + struct dm_hw_stat_delta *new_stat = NULL; + struct dm_hw_stat_delta *temp; + + spin_lock(&trace_state_lock); switch (state) { case TRACE_ON: rc |= register_trace_kfree_skb(trace_kfree_skb_hit); + rc |= register_trace_napi_poll(trace_napi_poll_hit); break; case TRACE_OFF: rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit); + rc |= unregister_trace_napi_poll(trace_napi_poll_hit); tracepoint_synchronize_unregister(); + + /* + * Clean the device list + */ + list_for_each_entry_safe(new_stat, temp, &hw_stats_list, list) { + if (new_stat->dev == NULL) { + list_del_rcu(&new_stat->list); + call_rcu(&new_stat->rcu, free_dm_hw_stat); + } + } break; default: rc = 1; break; } + if (!rc) + trace_state = state; + + spin_unlock(&trace_state_lock); + if (rc) return -EINPROGRESS; return rc; @@ -204,6 +271,44 @@ static int net_dm_cmd_trace(struct sk_buff *skb, return -ENOTSUPP; } +static int dropmon_net_event(struct notifier_block *ev_block, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + struct dm_hw_stat_delta *new_stat = NULL; + struct dm_hw_stat_delta *tmp; + + switch (event) { + case NETDEV_REGISTER: + new_stat = kzalloc(sizeof(struct dm_hw_stat_delta), GFP_KERNEL); + + if (!new_stat) + goto out; + + new_stat->dev = dev; + INIT_RCU_HEAD(&new_stat->rcu); + spin_lock(&trace_state_lock); + list_add_rcu(&new_stat->list, &hw_stats_list); + spin_unlock(&trace_state_lock); + break; + case NETDEV_UNREGISTER: + spin_lock(&trace_state_lock); + list_for_each_entry_safe(new_stat, tmp, &hw_stats_list, list) { + if (new_stat->dev == dev) { + new_stat->dev = NULL; + if (trace_state == TRACE_OFF) { + list_del_rcu(&new_stat->list); + call_rcu(&new_stat->rcu, free_dm_hw_stat); + break; + } + } + } + spin_unlock(&trace_state_lock); + break; + } +out: + return NOTIFY_DONE; +} static struct genl_ops dropmon_ops[] = { { @@ -220,6 +325,10 @@ static struct genl_ops dropmon_ops[] = { }, }; +static struct notifier_block dropmon_net_notifier = { + .notifier_call = dropmon_net_event +}; + static int __init init_net_drop_monitor(void) { int cpu; @@ -243,12 +352,18 @@ static int __init init_net_drop_monitor(void) ret = genl_register_ops(&net_drop_monitor_family, &dropmon_ops[i]); if (ret) { - printk(KERN_CRIT "failed to register operation %d\n", + printk(KERN_CRIT "Failed to register operation %d\n", dropmon_ops[i].cmd); goto out_unreg; } } + rc = register_netdevice_notifier(&dropmon_net_notifier); + if (rc < 0) { + printk(KERN_CRIT "Failed to register netdevice notifier\n"); + goto out_unreg; + } + rc = 0; for_each_present_cpu(cpu) { @@ -259,6 +374,7 @@ static int __init init_net_drop_monitor(void) data->send_timer.data = cpu; data->send_timer.function = sched_send_work; } + goto out; out_unreg: diff --git a/net/core/net-traces.c b/net/core/net-traces.c index c8fb456..b07b25b 100644 --- a/net/core/net-traces.c +++ b/net/core/net-traces.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -27,3 +28,6 @@ DEFINE_TRACE(kfree_skb); EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb); + +DEFINE_TRACE(napi_poll); +EXPORT_TRACEPOINT_SYMBOL_GPL(napi_poll); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 64f51ee..00b14e2 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -24,6 +24,7 @@ #include #include #include +#include /* * We maintain a small pool of fully-sized skbs, to make sure the @@ -137,6 +138,7 @@ static int poll_one_napi(struct netpoll_info *npinfo, set_bit(NAPI_STATE_NPSVC, &napi->state); work = napi->poll(napi, budget); + trace_napi_poll(napi->dev); clear_bit(NAPI_STATE_NPSVC, &napi->state); atomic_dec(&trapped); -- cgit v0.10.2 From a7b11d738282337488ae158c975d76271ad43a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 May 2009 10:34:04 +0000 Subject: genetlink: Introduce genl_register_family_with_ops() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces genl_register_family_with_ops() that registers a genetlink family along with operations from a table. This is used to kill copy'n'paste occurrences in following patches. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 747c255..1b0e3ee 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -88,6 +88,8 @@ struct genl_ops }; extern int genl_register_family(struct genl_family *family); +extern int genl_register_family_with_ops(struct genl_family *family, + struct genl_ops *ops, size_t n_ops); extern int genl_unregister_family(struct genl_family *family); extern int genl_register_ops(struct genl_family *, struct genl_ops *ops); extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 1d3dd30..eed4c6a 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -384,6 +384,52 @@ errout: } /** + * genl_register_family_with_ops - register a generic netlink family + * @family: generic netlink family + * @ops: operations to be registered + * @n_ops: number of elements to register + * + * Registers the specified family and operations from the specified table. + * Only one family may be registered with the same family name or identifier. + * + * The family id may equal GENL_ID_GENERATE causing an unique id to + * be automatically generated and assigned. + * + * Either a doit or dumpit callback must be specified for every registered + * operation or the function will fail. Only one operation structure per + * command identifier may be registered. + * + * See include/net/genetlink.h for more documenation on the operations + * structure. + * + * This is equivalent to calling genl_register_family() followed by + * genl_register_ops() for every operation entry in the table taking + * care to unregister the family on error path. + * + * Return 0 on success or a negative error code. + */ +int genl_register_family_with_ops(struct genl_family *family, + struct genl_ops *ops, size_t n_ops) +{ + int err, i; + + err = genl_register_family(family); + if (err) + return err; + + for (i = 0; i < n_ops; ++i, ++ops) { + err = genl_register_ops(family, ops); + if (err) + goto err_out; + } + return 0; +err_out: + genl_unregister_family(family); + return err; +} +EXPORT_SYMBOL(genl_register_family_with_ops); + +/** * genl_unregister_family - unregister generic netlink family * @family: generic netlink family * -- cgit v0.10.2 From 502664eeaf880d364821521bbced7ae342f77f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 May 2009 10:34:04 +0000 Subject: irda: Use genl_register_family_with_ops() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use genl_register_family_with_ops() instead of a copy. Signed-off-by: MichaÅ‚ MirosÅ‚aw Cc: Samuel Ortiz Signed-off-by: David S. Miller diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index 82c6118..8dd7ed7 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -148,21 +148,8 @@ static struct genl_ops irda_nl_ops[] = { int irda_nl_register(void) { - int err, i; - - err = genl_register_family(&irda_nl_family); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(irda_nl_ops); i++) { - err = genl_register_ops(&irda_nl_family, &irda_nl_ops[i]); - if (err) - goto err_out; - } - return 0; - err_out: - genl_unregister_family(&irda_nl_family); - return err; + return genl_register_family_with_ops(&irda_nl_family, + irda_nl_ops, ARRAY_SIZE(irda_nl_ops)); } void irda_nl_unregister(void) -- cgit v0.10.2 From acb0a200ae48d95e3117608d0225a23e5efa283c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 May 2009 10:34:05 +0000 Subject: tipc: Use genl_register_family_with_ops() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use genl_register_family_with_ops() instead of a copy. This also changes netlink related variable names to be kernel-wide unique for consistency with other users. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index c387217..3c57005 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -68,7 +68,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info) return 0; } -static struct genl_family family = { +static struct genl_family tipc_genl_family = { .id = GENL_ID_GENERATE, .name = TIPC_GENL_NAME, .version = TIPC_GENL_VERSION, @@ -76,39 +76,33 @@ static struct genl_family family = { .maxattr = 0, }; -static struct genl_ops ops = { +static struct genl_ops tipc_genl_ops = { .cmd = TIPC_GENL_CMD, .doit = handle_cmd, }; -static int family_registered = 0; +static int tipc_genl_family_registered; int tipc_netlink_start(void) { + int res; + res = genl_register_family_with_ops(&tipc_genl_family, + &tipc_genl_ops, 1); + if (res) { + err("Failed to register netlink interface\n"); + return res; + } - if (genl_register_family(&family)) - goto err; - - family_registered = 1; - - if (genl_register_ops(&family, &ops)) - goto err_unregister; - + tipc_genl_family_registered = 1; return 0; - - err_unregister: - genl_unregister_family(&family); - family_registered = 0; - err: - err("Failed to register netlink interface\n"); - return -EFAULT; } void tipc_netlink_stop(void) { - if (family_registered) { - genl_unregister_family(&family); - family_registered = 0; - } + if (!tipc_genl_family_registered) + return; + + genl_unregister_family(&tipc_genl_family); + tipc_genl_family_registered = 0; } -- cgit v0.10.2 From 8f698d54532172de3591af1e9394dc669f29e6ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 May 2009 10:34:05 +0000 Subject: ipvs: Use genl_register_family_with_ops() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use genl_register_family_with_ops() instead of a copy. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index e01061f..7c1333c 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3345,22 +3345,8 @@ static struct genl_ops ip_vs_genl_ops[] __read_mostly = { static int __init ip_vs_genl_register(void) { - int ret, i; - - ret = genl_register_family(&ip_vs_genl_family); - if (ret) - return ret; - - for (i = 0; i < ARRAY_SIZE(ip_vs_genl_ops); i++) { - ret = genl_register_ops(&ip_vs_genl_family, &ip_vs_genl_ops[i]); - if (ret) - goto err_out; - } - return 0; - -err_out: - genl_unregister_family(&ip_vs_genl_family); - return ret; + return genl_register_family_with_ops(&ip_vs_genl_family, + ip_vs_genl_ops, ARRAY_SIZE(ip_vs_genl_ops)); } static void ip_vs_genl_unregister(void) -- cgit v0.10.2 From 7ae740df3a9c68622156476dca29991de664fae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 May 2009 10:34:05 +0000 Subject: netlabel: Use genl_register_family_with_ops() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use genl_register_family_with_ops() instead of a copy. This fixes genetlink family leak on error path. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index bf1ab1a..e639298 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -785,18 +785,6 @@ static struct genl_ops netlbl_cipsov4_ops[] = { */ int __init netlbl_cipsov4_genl_init(void) { - int ret_val, i; - - ret_val = genl_register_family(&netlbl_cipsov4_gnl_family); - if (ret_val != 0) - return ret_val; - - for (i = 0; i < ARRAY_SIZE(netlbl_cipsov4_ops); i++) { - ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, - &netlbl_cipsov4_ops[i]); - if (ret_val != 0) - return ret_val; - } - - return 0; + return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family, + netlbl_cipsov4_ops, ARRAY_SIZE(netlbl_cipsov4_ops)); } diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 1821c5d..8203623 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -779,18 +779,6 @@ static struct genl_ops netlbl_mgmt_genl_ops[] = { */ int __init netlbl_mgmt_genl_init(void) { - int ret_val, i; - - ret_val = genl_register_family(&netlbl_mgmt_gnl_family); - if (ret_val != 0) - return ret_val; - - for (i = 0; i < ARRAY_SIZE(netlbl_mgmt_genl_ops); i++) { - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_ops[i]); - if (ret_val != 0) - return ret_val; - } - - return 0; + return genl_register_family_with_ops(&netlbl_mgmt_gnl_family, + netlbl_mgmt_genl_ops, ARRAY_SIZE(netlbl_mgmt_genl_ops)); } diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index f3c5c68..fb357f0 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1478,20 +1478,8 @@ static struct genl_ops netlbl_unlabel_genl_ops[] = { */ int __init netlbl_unlabel_genl_init(void) { - int ret_val, i; - - ret_val = genl_register_family(&netlbl_unlabel_gnl_family); - if (ret_val != 0) - return ret_val; - - for (i = 0; i < ARRAY_SIZE(netlbl_unlabel_genl_ops); i++) { - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_ops[i]); - if (ret_val != 0) - return ret_val; - } - - return 0; + return genl_register_family_with_ops(&netlbl_unlabel_gnl_family, + netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops)); } /* -- cgit v0.10.2 From 0d63cbb535a9525445513389370d35b522a700f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 May 2009 10:34:06 +0000 Subject: wireless: Use genl_register_family_with_ops() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use genl_register_family_with_ops() instead of a copy. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ade40d50..a3a152f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3912,18 +3912,13 @@ nla_put_failure: int nl80211_init(void) { - int err, i; + int err; - err = genl_register_family(&nl80211_fam); + err = genl_register_family_with_ops(&nl80211_fam, + nl80211_ops, ARRAY_SIZE(nl80211_ops)); if (err) return err; - for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) { - err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]); - if (err) - goto err_out; - } - err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); if (err) goto err_out; -- cgit v0.10.2 From 7e0e99ef43b1fab8caf0348e31704c7d15060ce0 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 21 May 2009 13:06:56 +0000 Subject: igb: do not re-register DCA requester on device reset The current driver is re-registering the DCA requester after every reset. Instead of doing this we should only be updating the on board DCA registers and not unregistering/re-registering our requester. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index ffd7315..2ec9809 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -996,6 +996,11 @@ void igb_down(struct igb_adapter *adapter) igb_reset(adapter); igb_clean_all_tx_rings(adapter); igb_clean_all_rx_rings(adapter); +#ifdef CONFIG_IGB_DCA + + /* since we reset the hardware DCA settings were cleared */ + igb_setup_dca(adapter); +#endif } void igb_reinit_locked(struct igb_adapter *adapter) @@ -1457,9 +1462,6 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IGB_FLAG_DCA_ENABLED; dev_info(&pdev->dev, "DCA enabled\n"); - /* Always use CB2 mode, difference is masked - * in the CB driver. */ - wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_CB2); igb_setup_dca(adapter); } #endif @@ -3771,11 +3773,15 @@ static void igb_update_tx_dca(struct igb_ring *tx_ring) static void igb_setup_dca(struct igb_adapter *adapter) { + struct e1000_hw *hw = &adapter->hw; int i; if (!(adapter->flags & IGB_FLAG_DCA_ENABLED)) return; + /* Always use CB2 mode, difference is masked in the CB driver. */ + wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_CB2); + for (i = 0; i < adapter->num_tx_queues; i++) { adapter->tx_ring[i].cpu = -1; igb_update_tx_dca(&adapter->tx_ring[i]); -- cgit v0.10.2 From e35ec126507529ce407136c6b9e36747d89891f9 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 21 May 2009 13:07:12 +0000 Subject: ixgbe: only register DCA requester once The current driver tries to re-register the DCA requester after reset and this is not correct. This change makes it so all we are doing is resetting the DCA registers after reset and not re-adding the requester. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 3d5f7f5..e52798c 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -411,6 +411,9 @@ static void ixgbe_setup_dca(struct ixgbe_adapter *adapter) if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED)) return; + /* always use CB2 mode, difference is masked in the CB driver */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2); + for (i = 0; i < adapter->num_tx_queues; i++) { adapter->tx_ring[i].cpu = -1; ixgbe_update_tx_dca(adapter, &adapter->tx_ring[i]); @@ -432,9 +435,6 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) /* 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); @@ -2767,13 +2767,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) netif_carrier_off(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); @@ -2781,13 +2774,7 @@ void ixgbe_down(struct ixgbe_adapter *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); - } + ixgbe_setup_dca(adapter); #endif } @@ -5354,9 +5341,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&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); } #endif -- cgit v0.10.2 From 7d18f114897ff4358419b14d551e704a4299a440 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 May 2009 23:30:09 -0700 Subject: net: Fix arg to trace_napi_poll() in netpoll. Reproted by Stephen Rothwell. Signed-off-by: David S. Miller diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 00b14e2..67b4f3e 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -138,7 +138,7 @@ static int poll_one_napi(struct netpoll_info *npinfo, set_bit(NAPI_STATE_NPSVC, &napi->state); work = napi->poll(napi, budget); - trace_napi_poll(napi->dev); + trace_napi_poll(napi); clear_bit(NAPI_STATE_NPSVC, &napi->state); atomic_dec(&trapped); -- cgit v0.10.2 From 3699067381a2a518b32c44411a020b007d057417 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 22 May 2009 00:45:28 -0700 Subject: tcp: Unexport TCPv6 GRO functions Sinec the TCPv6 GRO functions are used in the same file where they are defined, we do not need to export them. This was a cut-n-paste from the IPv4 code which does need to export them. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d9dd94b..ea37741 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -941,7 +941,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) return 0; } -struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb) +static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, + struct sk_buff *skb) { struct ipv6hdr *iph = skb_gro_network_header(skb); @@ -961,9 +962,8 @@ struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb) return tcp_gro_receive(head, skb); } -EXPORT_SYMBOL(tcp6_gro_receive); -int tcp6_gro_complete(struct sk_buff *skb) +static int tcp6_gro_complete(struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); struct tcphdr *th = tcp_hdr(skb); @@ -974,7 +974,6 @@ int tcp6_gro_complete(struct sk_buff *skb) return tcp_gro_complete(skb); } -EXPORT_SYMBOL(tcp6_gro_complete); static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, struct tcp_md5sig_key *key, int rst) -- cgit v0.10.2 From 87057825824973f29cf2f37cff1e549170b2d7e6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 May 2009 17:19:36 +0200 Subject: wext: remove atomic requirement for wireless stats The requirement for wireless stats to be atomic is now mostly artificial since we hold the rtnl _and_ the dev_base_lock for iterating the device list. Doing that is not required, just the rtnl is sufficient (and the rtnl is required for other reasons outlined in commit "wext: fix get_wireless_stats locking"). This will fix http://bugzilla.kernel.org/show_bug.cgi?id=13344 and make things easier for drivers. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext.c b/net/wireless/wext.c index d3bbef7..22378da 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -636,8 +636,10 @@ static void wireless_seq_printf_stats(struct seq_file *seq, /* * Print info for /proc/net/wireless (print all entries) */ -static int wireless_seq_show(struct seq_file *seq, void *v) +static int wireless_dev_seq_show(struct seq_file *seq, void *v) { + might_sleep(); + if (v == SEQ_START_TOKEN) seq_printf(seq, "Inter-| sta-| Quality | Discarded " "packets | Missed | WE\n" @@ -651,21 +653,41 @@ static int wireless_seq_show(struct seq_file *seq, void *v) static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) { + struct net *net = seq_file_net(seq); + loff_t off; + struct net_device *dev; + rtnl_lock(); - return dev_seq_start(seq, pos); + if (!*pos) + return SEQ_START_TOKEN; + + off = 1; + for_each_netdev(net, dev) + if (off++ == *pos) + return dev; + return NULL; +} + +static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + + ++*pos; + + return v == SEQ_START_TOKEN ? + first_net_device(net) : next_net_device(v); } static void wireless_dev_seq_stop(struct seq_file *seq, void *v) { - dev_seq_stop(seq, v); rtnl_unlock(); } static const struct seq_operations wireless_seq_ops = { .start = wireless_dev_seq_start, - .next = dev_seq_next, + .next = wireless_dev_seq_next, .stop = wireless_dev_seq_stop, - .show = wireless_seq_show, + .show = wireless_dev_seq_show, }; static int seq_open_wireless(struct inode *inode, struct file *file) -- cgit v0.10.2 From 4ef699fb771d347b31ddafd214c0dd47b90f7f0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 May 2009 21:26:07 +0200 Subject: mac80211: fix probe response wait timing In "mac80211: split out and decrease probe wait time" I tried to reduce the time waiting for a probe response, but failed to take into account the case where we are detecting beacon loss in software -- in that case we still wait the monitoring time rather than the probe wait time. Fix this by refactoring the mod_timer() calls in ieee80211_associated(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b7f9c60..ac6883f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1389,8 +1389,8 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); + mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); goto unlock; - } if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { @@ -1399,15 +1399,16 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) ifmgd->ssid_len, NULL, 0); } + if (!disassoc) + mod_timer(&ifmgd->timer, + jiffies + IEEE80211_MONITORING_INTERVAL); + unlock: rcu_read_unlock(); if (disassoc) ieee80211_set_disassoc(sdata, true, true, WLAN_REASON_PREV_AUTH_NOT_VALID); - else - mod_timer(&ifmgd->timer, jiffies + - IEEE80211_MONITORING_INTERVAL); } -- cgit v0.10.2 From ea2d06395b6de717a5e0c4b6e55f3047cae2131f Mon Sep 17 00:00:00 2001 From: "andrey@cozybit.com" Date: Tue, 19 May 2009 17:20:13 -0700 Subject: libertas: fix GSPI card event handling The GPSI interface driver does not re-enable the Card Event Interrupt, which causes problems after a card event (for example: link-loss) comes in. This can lead, for example, to the card failing to re-associate. This patch ensures that we re-enable the Card Event Interrupt when we handle card events. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index dccd01f..5fa55fe 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -814,6 +814,13 @@ static void if_spi_e2h(struct if_spi_card *card) if (err) goto out; + /* re-enable the card event interrupt */ + spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, + ~IF_SPI_HICU_CARD_EVENT); + + /* generate a card interrupt */ + spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_HOST_EVENT); + spin_lock_irqsave(&priv->driver_lock, flags); lbs_queue_event(priv, cause & 0xff); spin_unlock_irqrestore(&priv->driver_lock, flags); -- cgit v0.10.2 From e70a5ac5d27166cfe5bfbe8f63017af3b09d72ce Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 19 May 2009 19:48:18 -0700 Subject: libertas: define macros for SDIO model numbers replace direct usages of SDIO model numbers with defined macros. Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 55864c1..69d7fd31 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -66,19 +66,19 @@ struct if_sdio_model { static struct if_sdio_model if_sdio_models[] = { { /* 8385 */ - .model = 0x04, + .model = IF_SDIO_MODEL_8385, .helper = "sd8385_helper.bin", .firmware = "sd8385.bin", }, { /* 8686 */ - .model = 0x0B, + .model = IF_SDIO_MODEL_8686, .helper = "sd8686_helper.bin", .firmware = "sd8686.bin", }, { /* 8688 */ - .model = 0x10, + .model = IF_SDIO_MODEL_8688, .helper = "sd8688_helper.bin", .firmware = "sd8688.bin", }, @@ -118,7 +118,7 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) int ret, reg; u16 scratch; - if (card->model == 0x04) + if (card->model == IF_SDIO_MODEL_8385) reg = IF_SDIO_SCRATCH_OLD; else reg = IF_SDIO_SCRATCH; @@ -216,7 +216,7 @@ static int if_sdio_handle_event(struct if_sdio_card *card, lbs_deb_enter(LBS_DEB_SDIO); - if (card->model == 0x04) { + if (card->model == IF_SDIO_MODEL_8385) { event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); if (ret) goto out; @@ -829,10 +829,10 @@ static int if_sdio_probe(struct sdio_func *func, if (sscanf(func->card->info[i], "ID: %x", &model) == 1) break; - if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) { - model = 4; - break; - } + if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) { + model = IF_SDIO_MODEL_8385; + break; + } } if (i == func->card->num_info) { diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index 37ada2c..cea343f 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h @@ -12,6 +12,10 @@ #ifndef _LBS_IF_SDIO_H #define _LBS_IF_SDIO_H +#define IF_SDIO_MODEL_8385 0x04 +#define IF_SDIO_MODEL_8686 0x0b +#define IF_SDIO_MODEL_8688 0x10 + #define IF_SDIO_IOPORT 0x00 #define IF_SDIO_H_INT_MASK 0x04 -- cgit v0.10.2 From b136a1414c94b4bda1057b4ffde26253d2527628 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 19 May 2009 19:48:19 -0700 Subject: libertas: get SD8688 rx length with one CMD52 Usually, the 16-bit rx length is read from scratch pad registers with two CMD52 transactions: SD8385: IF_SDIO_SCRATCH_OLD (0x80fe/0x80ff) SD8686/SD8688: IF_SDIO_SCRATCH (0x34/0x35) Alternatively, SD8688 firmware offers an enhanced method for driver to read an 8-bit rx length (in units) with a single CMD52: IF_SDIO_RX_UNIT 0x43 is read one time after firmware is ready. IF_SDIO_RX_LEN 0x42 is read every time when rx interrupt is received. Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 69d7fd31..e998c12 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -107,6 +107,8 @@ struct if_sdio_card { struct workqueue_struct *workqueue; struct work_struct packet_worker; + + u8 rx_unit; }; /********************************************************************/ @@ -136,6 +138,46 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) return scratch; } +static u8 if_sdio_read_rx_unit(struct if_sdio_card *card) +{ + int ret; + u8 rx_unit; + + rx_unit = sdio_readb(card->func, IF_SDIO_RX_UNIT, &ret); + + if (ret) + rx_unit = 0; + + return rx_unit; +} + +static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err) +{ + int ret; + u16 rx_len; + + switch (card->model) { + case IF_SDIO_MODEL_8385: + case IF_SDIO_MODEL_8686: + rx_len = if_sdio_read_scratch(card, &ret); + break; + case IF_SDIO_MODEL_8688: + default: /* for newer chipsets */ + rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret); + if (!ret) + rx_len <<= card->rx_unit; + else + rx_len = 0xffff; /* invalid length */ + + break; + } + + if (err) + *err = ret; + + return rx_len; +} + static int if_sdio_handle_cmd(struct if_sdio_card *card, u8 *buffer, unsigned size) { @@ -254,7 +296,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) lbs_deb_enter(LBS_DEB_SDIO); - size = if_sdio_read_scratch(card, &ret); + size = if_sdio_read_rx_len(card, &ret); if (ret) goto out; @@ -923,10 +965,21 @@ static int if_sdio_probe(struct sdio_func *func, priv->fw_ready = 1; + sdio_claim_host(func); + + /* + * Get rx_unit if the chip is SD8688 or newer. + * SD8385 & SD8686 do not have rx_unit. + */ + if ((card->model != IF_SDIO_MODEL_8385) + && (card->model != IF_SDIO_MODEL_8686)) + card->rx_unit = if_sdio_read_rx_unit(card); + else + card->rx_unit = 0; + /* * Enable interrupts now that everything is set up */ - sdio_claim_host(func); sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); sdio_release_host(func); if (ret) diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index cea343f..d3a4fbe 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h @@ -44,6 +44,9 @@ #define IF_SDIO_SCRATCH_OLD 0x80fe #define IF_SDIO_FIRMWARE_OK 0xfedc +#define IF_SDIO_RX_LEN 0x42 +#define IF_SDIO_RX_UNIT 0x43 + #define IF_SDIO_EVENT 0x80fc #define IF_SDIO_BLOCK_SIZE 256 -- cgit v0.10.2 From d26285f873c3066fefe648b47b9ecf3ec18bcfbc Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 19 May 2009 19:48:20 -0700 Subject: libertas: implement function init/shutdown commands for SD8688 SD8688 is a WLAN/Bluetooth combo chip and both functions are supported in a single firmware image. FUNC_INIT and FUNC_SHUTDOWN commands are implemented to utilize the multiple function feature. When SD8688 card is inserted, the firmware image should be downloaded only once through either WLAN function (Libertas driver) or Bluetooth function (Bluetooth driver). This patch adds function init/shutdown for SD8688 WLAN function only. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index cbaafa6..a4455ec 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -321,6 +321,8 @@ struct lbs_private { u32 monitormode; u8 fw_ready; + u8 fn_init_required; + u8 fn_shutdown_required; }; extern struct cmd_confirm_sleep confirm_sleep; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 8ff8ac9..fe8f0cb 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -86,6 +86,8 @@ #define CMD_MESH_CONFIG_OLD 0x00a3 #define CMD_MESH_CONFIG 0x00ac #define CMD_SET_BOOT2_VER 0x00a5 +#define CMD_FUNC_INIT 0x00a9 +#define CMD_FUNC_SHUTDOWN 0x00aa #define CMD_802_11_BEACON_CTRL 0x00b0 /* For the IEEE Power Save */ diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index e998c12..478d766 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -61,6 +61,7 @@ struct if_sdio_model { int model; const char *helper; const char *firmware; + struct if_sdio_card *card; }; static struct if_sdio_model if_sdio_models[] = { @@ -69,18 +70,21 @@ static struct if_sdio_model if_sdio_models[] = { .model = IF_SDIO_MODEL_8385, .helper = "sd8385_helper.bin", .firmware = "sd8385.bin", + .card = NULL, }, { /* 8686 */ .model = IF_SDIO_MODEL_8686, .helper = "sd8686_helper.bin", .firmware = "sd8686.bin", + .card = NULL, }, { /* 8688 */ .model = IF_SDIO_MODEL_8688, .helper = "sd8688_helper.bin", .firmware = "sd8688.bin", + .card = NULL, }, }; @@ -539,7 +543,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card) ret = 0; release: - sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); sdio_release_host(card->func); kfree(chunk_buffer); release_fw: @@ -675,7 +678,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card) ret = 0; release: - sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); sdio_release_host(card->func); kfree(chunk_buffer); release_fw: @@ -718,6 +720,9 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) goto out; success: + sdio_claim_host(card->func); + sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); + sdio_release_host(card->func); ret = 0; out: @@ -903,6 +908,8 @@ static int if_sdio_probe(struct sdio_func *func, goto free; } + if_sdio_models[i].card = card; + card->helper = if_sdio_models[i].helper; card->firmware = if_sdio_models[i].firmware; @@ -985,6 +992,12 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto reclaim; + /* + * FUNC_INIT is required for SD8688 WLAN/BT multiple functions + */ + priv->fn_init_required = + (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; + ret = lbs_start_card(priv); if (ret) goto err_activate_card; @@ -1025,23 +1038,30 @@ static void if_sdio_remove(struct sdio_func *func) { struct if_sdio_card *card; struct if_sdio_packet *packet; + int ret; lbs_deb_enter(LBS_DEB_SDIO); card = sdio_get_drvdata(func); + lbs_stop_card(card->priv); + card->priv->surpriseremoved = 1; lbs_deb_sdio("call remove card\n"); - lbs_stop_card(card->priv); lbs_remove_card(card->priv); flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); sdio_claim_host(func); + + /* Disable interrupts */ + sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret); + sdio_release_irq(func); sdio_disable_func(func); + sdio_release_host(func); while (card->packets) { @@ -1084,8 +1104,23 @@ static int __init if_sdio_init_module(void) static void __exit if_sdio_exit_module(void) { + int i; + struct if_sdio_card *card; + lbs_deb_enter(LBS_DEB_SDIO); + for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) { + card = if_sdio_models[i].card; + + /* + * FUNC_SHUTDOWN is required for SD8688 WLAN/BT + * multiple functions + */ + if (card && card->priv) + card->priv->fn_shutdown_required = + (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; + } + sdio_unregister_driver(&if_sdio_driver); lbs_deb_leave(LBS_DEB_SDIO); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 89575e4..a58a123 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1002,9 +1002,17 @@ static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; s16 curlevel = 0, minlevel = 0, maxlevel = 0; + struct cmd_header cmd; lbs_deb_enter(LBS_DEB_FW); + if (priv->fn_init_required) { + memset(&cmd, 0, sizeof(cmd)); + if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), + lbs_cmd_copyback, (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_INIT command failed\n"); + } + /* Read MAC address from firmware */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); @@ -1192,6 +1200,9 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->mesh_open = 0; priv->infra_open = 0; + priv->fn_init_required = 0; + priv->fn_shutdown_required = 0; + /* Setup the OS Interface to our functions */ dev->netdev_ops = &lbs_netdev_ops; dev->watchdog_timeo = 5 * HZ; @@ -1373,11 +1384,20 @@ void lbs_stop_card(struct lbs_private *priv) struct net_device *dev; struct cmd_ctrl_node *cmdnode; unsigned long flags; + struct cmd_header cmd; lbs_deb_enter(LBS_DEB_MAIN); if (!priv) goto out; + + if (priv->fn_shutdown_required) { + memset(&cmd, 0, sizeof(cmd)); + if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd), + lbs_cmd_copyback, (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n"); + } + dev = priv->dev; netif_stop_queue(dev); -- cgit v0.10.2 From 267a90127472be70b02ab13cbd355b5013e2aa51 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 20 May 2009 21:56:39 +0300 Subject: ath9k: Optimize TBTT/DTIM calculation for timers The previous version used a simple loop to go through all Beacon frames when determining the next TBTT and DTIM count. This is not too bad for the case where the setup happens before timesync (i.e., very small TSF), but this can become very heavy operation if a short Beacon interval is used and the current TSF is large. In preparation for a patch to update timer setup based on Beacon timestamp, optimize this routine to take fixed time regardless of the actual TSF value. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 57f91a9..a21b213 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -559,6 +559,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, int cfpperiod, cfpcount; u32 nexttbtt = 0, intval, tsftu; u64 tsf; + int num_beacons, offset, dtim_dec_count, cfp_dec_count; memset(&bs, 0, sizeof(bs)); intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; @@ -586,14 +587,27 @@ static void ath_beacon_config_sta(struct ath_softc *sc, */ tsf = ath9k_hw_gettsf64(sc->sc_ah); tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - do { + + num_beacons = tsftu / intval + 1; + offset = tsftu % intval; + nexttbtt = tsftu - offset; + if (offset) nexttbtt += intval; - if (--dtimcount < 0) { - dtimcount = dtimperiod - 1; - if (--cfpcount < 0) - cfpcount = cfpperiod - 1; - } - } while (nexttbtt < tsftu); + + /* DTIM Beacon every dtimperiod Beacon */ + dtim_dec_count = num_beacons % dtimperiod; + /* CFP every cfpperiod DTIM Beacon */ + cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; + if (dtim_dec_count) + cfp_dec_count++; + + dtimcount -= dtim_dec_count; + if (dtimcount < 0) + dtimcount += dtimperiod; + + cfpcount -= cfp_dec_count; + if (cfpcount < 0) + cfpcount += cfpperiod; bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; -- cgit v0.10.2 From ccdfeab6536ae55d43436ffaae949afde6e962ca Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 20 May 2009 21:59:08 +0300 Subject: ath9k: Update Beacon timers based on timestamp from the AP Some APs seem to drift away from the expected TBTT (timestamp % beacon_int_in_usec differs quite a bit from zero) which can result in us waking up way too early to receive a Beacon frame. In order to work around this, re-configure the Beacon timers after having received a Beacon frame from the AP (i.e., when we know the offset between the expected TBTT and the actual time the AP is sending out the Beacon frame). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0d4ac43..796a3ad 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -518,6 +518,7 @@ struct ath_rfkill { #define SC_OP_WAIT_FOR_CAB BIT(16) #define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) #define SC_OP_WAIT_FOR_TX_ACK BIT(18) +#define SC_OP_BEACON_SYNC BIT(19) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5759c94..61da08a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -487,7 +487,7 @@ static void ath9k_tasklet(unsigned long data) * the next Beacon. */ DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); - sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } /* re-enable hardware interrupt */ @@ -914,6 +914,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, if (avp->av_opmode == NL80211_IFTYPE_STATION) { sc->curaid = bss_conf->aid; ath9k_hw_write_associd(sc); + + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->sc_flags |= SC_OP_BEACON_SYNC; } /* Configure the beacon */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 5e046b5..5014a19 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -521,6 +521,13 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) return; /* not from our current AP */ + if (sc->sc_flags & SC_OP_BEACON_SYNC) { + sc->sc_flags &= ~SC_OP_BEACON_SYNC; + DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " + "timestamp from the AP\n"); + ath_beacon_config(sc, NULL); + } + if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { /* We are not in PS mode anymore; remain awake */ DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " -- cgit v0.10.2 From a971be223f243311a8014ddfc721f68e3ef2da9c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 May 2009 12:02:05 +0200 Subject: mac80211: correct probe wait time My first patch submission used 200ms, which I then somehow managed to revert back to the earlier 50ms I had used for some tests in the second patch submission -- but that was wrong, I should have used 200ms here. Correct that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ac6883f..509469c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -33,7 +33,7 @@ #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MONITORING_INTERVAL (2 * HZ) -#define IEEE80211_PROBE_WAIT (HZ / 20) +#define IEEE80211_PROBE_WAIT (HZ / 5) #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) -- cgit v0.10.2 From e31a16d6f64ef0e324c6f54d5112703c3f13a9c4 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 21 May 2009 21:47:03 +0800 Subject: wireless: move some utility functions from mac80211 to cfg80211 The patch moves some utility functions from mac80211 to cfg80211. Because these functions are doing generic 802.11 operations so they are not mac80211 specific. The moving allows some fullmac drivers to be also benefit from these utility functions. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 4ef1d2f..99df9dd 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1555,7 +1555,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (key->alg) { case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) ktype = AR9170_ENC_ALG_WEP64; else ktype = AR9170_ENC_ALG_WEP128; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 579aa0a..ec35503 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -1038,9 +1038,9 @@ int ath5k_keycache_type(const struct ieee80211_key_conf *key) case ALG_CCMP: return AR5K_KEYTABLE_TYPE_CCM; case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) return AR5K_KEYTABLE_TYPE_40; - else if (key->keylen == LEN_WEP104) + else if (key->keylen == WLAN_KEY_LEN_WEP104) return AR5K_KEYTABLE_TYPE_104; return -EINVAL; default: diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4acfab5..1579c94 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2472,14 +2472,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, } break; case ATH9K_CIPHER_WEP: - if (k->kv_len < LEN_WEP40) { + if (k->kv_len < WLAN_KEY_LEN_WEP40) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, "WEP key length %u too small\n", k->kv_len); return false; } - if (k->kv_len <= LEN_WEP40) + if (k->kv_len <= WLAN_KEY_LEN_WEP40) keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= LEN_WEP104) + else if (k->kv_len <= WLAN_KEY_LEN_WEP104) keyType = AR_KEYTABLE_TYPE_104; else keyType = AR_KEYTABLE_TYPE_128; @@ -2498,7 +2498,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, key2 = get_unaligned_le32(k->kv_val + 6); key3 = get_unaligned_le16(k->kv_val + 10); key4 = get_unaligned_le32(k->kv_val + 12); - if (k->kv_len <= LEN_WEP104) + if (k->kv_len <= WLAN_KEY_LEN_WEP104) key4 &= 0xff; /* diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ec8516e..cb4a871 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3637,7 +3637,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, err = -EINVAL; switch (key->alg) { case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) algorithm = B43_SEC_ALGO_WEP40; else algorithm = B43_SEC_ALGO_WEP104; diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 57ab42c..bc4e81e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -33,7 +33,7 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) { switch (key->alg) { case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) return CIPHER_WEP64; else return CIPHER_WEP128; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 05c29c0..34de8b2 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -493,6 +493,7 @@ struct ieee80211s_hdr { /* Mesh flags */ #define MESH_FLAGS_AE_A4 0x1 #define MESH_FLAGS_AE_A5_A6 0x2 +#define MESH_FLAGS_AE 0x3 #define MESH_FLAGS_PS_DEEP 0x4 /** @@ -1085,6 +1086,14 @@ enum ieee80211_spectrum_mgmt_actioncode { WLAN_ACTION_SPCT_CHL_SWITCH = 4, }; +/* Security key length */ +enum ieee80211_key_len { + WLAN_KEY_LEN_WEP40 = 5, + WLAN_KEY_LEN_WEP104 = 13, + WLAN_KEY_LEN_CCMP = 16, + WLAN_KEY_LEN_TKIP = 32, +}; + /* * IEEE 802.11-2007 7.3.2.9 Country information element * diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 389f1d2..f20da7d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1244,6 +1244,53 @@ extern int ieee80211_radiotap_iterator_init( extern int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator); +extern const unsigned char rfc1042_header[6]; +extern const unsigned char bridge_tunnel_header[6]; + +/** + * ieee80211_get_hdrlen_from_skb - get header length from data + * + * Given an skb with a raw 802.11 header at the data pointer this function + * returns the 802.11 header length in bytes (not including encryption + * headers). If the data in the sk_buff is too short to contain a valid 802.11 + * header the function returns 0. + * + * @skb: the frame + */ +unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); + +/** + * ieee80211_hdrlen - get header length in bytes from frame control + * @fc: frame control field in little-endian format + */ +unsigned int ieee80211_hdrlen(__le16 fc); + +/** + * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3 + * @skb: the 802.11 data frame + * @addr: the device MAC address + * @iftype: the virtual interface type + */ +int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, + enum nl80211_iftype iftype); + +/** + * ieee80211_data_from_8023 - convert an 802.3 frame to 802.11 + * @skb: the 802.3 frame + * @addr: the device MAC address + * @iftype: the virtual interface type + * @bssid: the network bssid (used only for iftype STATION and ADHOC) + * @qos: build 802.11 QoS data frame + */ +int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, + enum nl80211_iftype iftype, u8 *bssid, bool qos); + +/** + * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame + * @skb: the data frame + */ +unsigned int cfg80211_classify8021d(struct sk_buff *skb); + /* * Regulatory helper functions for wiphys */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2d06105..d72346f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -672,16 +672,6 @@ enum ieee80211_key_alg { }; /** - * enum ieee80211_key_len - key length - * @LEN_WEP40: WEP 5-byte long key - * @LEN_WEP104: WEP 13-byte long key - */ -enum ieee80211_key_len { - LEN_WEP40 = 5, - LEN_WEP104 = 13, -}; - -/** * enum ieee80211_key_flags - key flags * * These flags are used for communication about keys between the driver @@ -1812,24 +1802,6 @@ struct sk_buff * ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /** - * ieee80211_get_hdrlen_from_skb - get header length from data - * - * Given an skb with a raw 802.11 header at the data pointer this function - * returns the 802.11 header length in bytes (not including encryption - * headers). If the data in the sk_buff is too short to contain a valid 802.11 - * header the function returns 0. - * - * @skb: the frame - */ -unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); - -/** - * ieee80211_hdrlen - get header length in bytes from frame control - * @fc: frame control field in little-endian format - */ -unsigned int ieee80211_hdrlen(__le16 fc); - -/** * ieee80211_get_tkip_key - get a TKIP rc4 for skb * * This function computes a TKIP rc4 key for an skb. It computes diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8db8d16..c088c46 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1085,8 +1085,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) /* utility functions/constants */ extern void *mac80211_wiphy_privid; /* for wiphy privid */ -extern const unsigned char rfc1042_header[6]; -extern const unsigned char bridge_tunnel_header[6]; u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum nl80211_iftype type); int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 832bb50..c7d7281 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -191,12 +191,8 @@ struct mesh_rmc { #define PLINK_CATEGORY 30 #define MESH_PATH_SEL_CATEGORY 32 -/* Mesh Header Flags */ -#define IEEE80211S_FLAGS_AE 0x3 - /* Public interfaces */ /* Various */ -int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, struct ieee80211_sub_if_data *sdata); int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f3a041c..6a9b8e6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1247,93 +1247,12 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) } static int -ieee80211_data_to_8023(struct ieee80211_rx_data *rx) +__ieee80211_data_to_8023(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - u16 hdrlen, ethertype; - u8 *payload; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN] __aligned(2); - struct sk_buff *skb = rx->skb; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) - return -1; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - /* convert IEEE 802.11 header + possible LLC headers into Ethernet - * header - * IEEE 802.11 address fields: - * ToDS FromDS Addr1 Addr2 Addr3 Addr4 - * 0 0 DA SA BSSID n/a - * 0 1 DA BSSID SA n/a - * 1 0 BSSID SA DA n/a - * 1 1 RA TA DA SA - */ - memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); - memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); - - switch (hdr->frame_control & - cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case cpu_to_le16(IEEE80211_FCTL_TODS): - if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP && - sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) - return -1; - break; - case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): - if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS && - sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) - return -1; - if (ieee80211_vif_is_mesh(&sdata->vif)) { - struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *) - (skb->data + hdrlen); - hdrlen += ieee80211_get_mesh_hdrlen(meshdr); - if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { - memcpy(dst, meshdr->eaddr1, ETH_ALEN); - memcpy(src, meshdr->eaddr2, ETH_ALEN); - } - } - break; - case cpu_to_le16(IEEE80211_FCTL_FROMDS): - if (sdata->vif.type != NL80211_IFTYPE_STATION || - (is_multicast_ether_addr(dst) && - !compare_ether_addr(src, dev->dev_addr))) - return -1; - break; - case cpu_to_le16(0): - if (sdata->vif.type != NL80211_IFTYPE_ADHOC) - return -1; - break; - } - - if (unlikely(skb->len - hdrlen < 8)) - return -1; - - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - compare_ether_addr(payload, bridge_tunnel_header) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - struct ethhdr *ehdr; - __be16 len; - - skb_pull(skb, hdrlen); - len = htons(skb->len); - ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); - memcpy(ehdr->h_dest, dst, ETH_ALEN); - memcpy(ehdr->h_source, src, ETH_ALEN); - ehdr->h_proto = len; - } - return 0; + return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); } /* @@ -1472,7 +1391,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (!(rx->flags & IEEE80211_RX_AMSDU)) return RX_CONTINUE; - err = ieee80211_data_to_8023(rx); + err = __ieee80211_data_to_8023(rx); if (unlikely(err)) return RX_DROP_UNUSABLE; @@ -1658,7 +1577,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) return RX_DROP_MONITOR; - err = ieee80211_data_to_8023(rx); + err = __ieee80211_data_to_8023(rx); if (unlikely(err)) return RX_DROP_UNUSABLE; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ffb6e88..949d857 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -35,15 +35,6 @@ /* privid for wiphys to determine whether they belong to us or not */ void *mac80211_wiphy_privid = &mac80211_wiphy_privid; -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -const unsigned char rfc1042_header[] __aligned(2) = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -const unsigned char bridge_tunnel_header[] __aligned(2) = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; - struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) { struct ieee80211_local *local; @@ -103,70 +94,6 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, return NULL; } -unsigned int ieee80211_hdrlen(__le16 fc) -{ - unsigned int hdrlen = 24; - - if (ieee80211_is_data(fc)) { - if (ieee80211_has_a4(fc)) - hdrlen = 30; - if (ieee80211_is_data_qos(fc)) - hdrlen += IEEE80211_QOS_CTL_LEN; - goto out; - } - - if (ieee80211_is_ctl(fc)) { - /* - * ACK and CTS are 10 bytes, all others 16. To see how - * to get this condition consider - * subtype mask: 0b0000000011110000 (0x00F0) - * ACK subtype: 0b0000000011010000 (0x00D0) - * CTS subtype: 0b0000000011000000 (0x00C0) - * bits that matter: ^^^ (0x00E0) - * value of those: 0b0000000011000000 (0x00C0) - */ - if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) - hdrlen = 10; - else - hdrlen = 16; - } -out: - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_hdrlen); - -unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data; - unsigned int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - hdrlen = ieee80211_hdrlen(hdr->frame_control); - if (unlikely(hdrlen > skb->len)) - return 0; - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); - -int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) -{ - int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; - /* 7.1.3.5a.2 */ - switch (ae) { - case 0: - return 6; - case 1: - return 12; - case 2: - return 18; - case 3: - return 24; - default: - return 6; - } -} - void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 45b74f3..694343b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -23,34 +23,6 @@ */ const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; -static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0}; - -/* Given a data frame determine the 802.1p/1d tag to use. */ -static unsigned int classify_1d(struct sk_buff *skb) -{ - unsigned int dscp; - - /* skb->priority values from 256->263 are magic values to - * directly indicate a specific 802.1d priority. This is used - * to allow 802.1d priority to be passed directly in from VLAN - * tags, etc. - */ - if (skb->priority >= 256 && skb->priority <= 263) - return skb->priority - 256; - - switch (skb->protocol) { - case htons(ETH_P_IP): - dscp = ip_hdr(skb)->tos & 0xfc; - break; - - default: - return 0; - } - - return dscp >> 5; -} - - static int wme_downgrade_ac(struct sk_buff *skb) { switch (skb->priority) { @@ -94,7 +66,7 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) /* use the data classifier to determine what 802.1d tag the * data frame has */ - skb->priority = classify_1d(skb); + skb->priority = cfg80211_classify8021d(skb); /* in case we are a client verify acm is not set for this ac */ while (unlikely(local->wmm_acm & BIT(skb->priority))) { diff --git a/net/wireless/util.c b/net/wireless/util.c index b94c860..d072bff 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -4,7 +4,9 @@ * Copyright 2007-2009 Johannes Berg */ #include +#include #include +#include #include "core.h" struct ieee80211_rate * @@ -198,3 +200,306 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, return 0; } + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +const unsigned char rfc1042_header[] __aligned(2) = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +EXPORT_SYMBOL(rfc1042_header); + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +const unsigned char bridge_tunnel_header[] __aligned(2) = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +EXPORT_SYMBOL(bridge_tunnel_header); + +unsigned int ieee80211_hdrlen(__le16 fc) +{ + unsigned int hdrlen = 24; + + if (ieee80211_is_data(fc)) { + if (ieee80211_has_a4(fc)) + hdrlen = 30; + if (ieee80211_is_data_qos(fc)) + hdrlen += IEEE80211_QOS_CTL_LEN; + goto out; + } + + if (ieee80211_is_ctl(fc)) { + /* + * ACK and CTS are 10 bytes, all others 16. To see how + * to get this condition consider + * subtype mask: 0b0000000011110000 (0x00F0) + * ACK subtype: 0b0000000011010000 (0x00D0) + * CTS subtype: 0b0000000011000000 (0x00C0) + * bits that matter: ^^^ (0x00E0) + * value of those: 0b0000000011000000 (0x00C0) + */ + if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) + hdrlen = 10; + else + hdrlen = 16; + } +out: + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_hdrlen); + +unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = + (const struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (unlikely(hdrlen > skb->len)) + return 0; + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); + +int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) +{ + int ae = meshhdr->flags & MESH_FLAGS_AE; + /* 7.1.3.5a.2 */ + switch (ae) { + case 0: + return 6; + case 1: + return 12; + case 2: + return 18; + case 3: + return 24; + default: + return 6; + } +} + +int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, + enum nl80211_iftype iftype) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 hdrlen, ethertype; + u8 *payload; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN] __aligned(2); + + if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) + return -1; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + + /* convert IEEE 802.11 header + possible LLC headers into Ethernet + * header + * IEEE 802.11 address fields: + * ToDS FromDS Addr1 Addr2 Addr3 Addr4 + * 0 0 DA SA BSSID n/a + * 0 1 DA BSSID SA n/a + * 1 0 BSSID SA DA n/a + * 1 1 RA TA DA SA + */ + memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); + + switch (hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case cpu_to_le16(IEEE80211_FCTL_TODS): + if (unlikely(iftype != NL80211_IFTYPE_AP && + iftype != NL80211_IFTYPE_AP_VLAN)) + return -1; + break; + case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + if (unlikely(iftype != NL80211_IFTYPE_WDS && + iftype != NL80211_IFTYPE_MESH_POINT)) + return -1; + if (iftype == NL80211_IFTYPE_MESH_POINT) { + struct ieee80211s_hdr *meshdr = + (struct ieee80211s_hdr *) (skb->data + hdrlen); + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); + if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { + memcpy(dst, meshdr->eaddr1, ETH_ALEN); + memcpy(src, meshdr->eaddr2, ETH_ALEN); + } + } + break; + case cpu_to_le16(IEEE80211_FCTL_FROMDS): + if (iftype != NL80211_IFTYPE_STATION || + (is_multicast_ether_addr(dst) && + !compare_ether_addr(src, addr))) + return -1; + break; + case cpu_to_le16(0): + if (iftype != NL80211_IFTYPE_ADHOC) + return -1; + break; + } + + if (unlikely(skb->len - hdrlen < 8)) + return -1; + + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + struct ethhdr *ehdr; + __be16 len; + + skb_pull(skb, hdrlen); + len = htons(skb->len); + ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dst, ETH_ALEN); + memcpy(ehdr->h_source, src, ETH_ALEN); + ehdr->h_proto = len; + } + return 0; +} +EXPORT_SYMBOL(ieee80211_data_to_8023); + +int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, + enum nl80211_iftype iftype, u8 *bssid, bool qos) +{ + struct ieee80211_hdr hdr; + u16 hdrlen, ethertype; + __le16 fc; + const u8 *encaps_data; + int encaps_len, skip_header_bytes; + int nh_pos, h_pos; + int head_need; + + if (unlikely(skb->len < ETH_HLEN)) + return -EINVAL; + + nh_pos = skb_network_header(skb) - skb->data; + h_pos = skb_transport_header(skb) - skb->data; + + /* convert Ethernet header to proper 802.11 header (based on + * operation mode) */ + ethertype = (skb->data[12] << 8) | skb->data[13]; + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); + + switch (iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); + /* DA BSSID SA */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 24; + break; + case NL80211_IFTYPE_STATION: + fc |= cpu_to_le16(IEEE80211_FCTL_TODS); + /* BSSID SA DA */ + memcpy(hdr.addr1, bssid, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + hdrlen = 24; + break; + case NL80211_IFTYPE_ADHOC: + /* DA SA BSSID */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, bssid, ETH_ALEN); + hdrlen = 24; + break; + default: + return -EOPNOTSUPP; + } + + if (qos) { + fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + hdrlen += 2; + } + + hdr.frame_control = fc; + hdr.duration_id = 0; + hdr.seq_ctrl = 0; + + skip_header_bytes = ETH_HLEN; + if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { + encaps_data = bridge_tunnel_header; + encaps_len = sizeof(bridge_tunnel_header); + skip_header_bytes -= 2; + } else if (ethertype > 0x600) { + encaps_data = rfc1042_header; + encaps_len = sizeof(rfc1042_header); + skip_header_bytes -= 2; + } else { + encaps_data = NULL; + encaps_len = 0; + } + + skb_pull(skb, skip_header_bytes); + nh_pos -= skip_header_bytes; + h_pos -= skip_header_bytes; + + head_need = hdrlen + encaps_len - skb_headroom(skb); + + if (head_need > 0 || skb_cloned(skb)) { + head_need = max(head_need, 0); + if (head_need) + skb_orphan(skb); + + if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { + printk(KERN_ERR "failed to reallocate Tx buffer\n"); + return -ENOMEM; + } + skb->truesize += head_need; + } + + if (encaps_data) { + memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); + nh_pos += encaps_len; + h_pos += encaps_len; + } + + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + + nh_pos += hdrlen; + h_pos += hdrlen; + + /* Update skb pointers to various headers since this modified frame + * is going to go through Linux networking code that may potentially + * need things like pointer to IP header. */ + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, nh_pos); + skb_set_transport_header(skb, h_pos); + + return 0; +} +EXPORT_SYMBOL(ieee80211_data_from_8023); + +/* Given a data frame determine the 802.1p/1d tag to use. */ +unsigned int cfg80211_classify8021d(struct sk_buff *skb) +{ + unsigned int dscp; + + /* skb->priority values from 256->263 are magic values to + * directly indicate a specific 802.1d priority. This is used + * to allow 802.1d priority to be passed directly in from VLAN + * tags, etc. + */ + if (skb->priority >= 256 && skb->priority <= 263) + return skb->priority - 256; + + switch (skb->protocol) { + case htons(ETH_P_IP): + dscp = ip_hdr(skb)->tos & 0xfc; + break; + default: + return 0; + } + + return dscp >> 5; +} +EXPORT_SYMBOL(cfg80211_classify8021d); -- cgit v0.10.2 From bb9f8692f5043efef0dcef048cdd1db68299c2cb Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 21 May 2009 21:20:45 +0800 Subject: iwmc3200wifi: Add new Intel Wireless Multicomm 802.11 driver This driver supports Intel's full MAC wireless multicomm 802.11 hardware. Although the hardware is a 802.11agn device, we currently only support 802.11ag, in managed and ad-hoc mode (no AP mode for now). Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 91be3e7..a67d292 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -501,5 +501,6 @@ source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/orinoco/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" +source "drivers/net/wireless/iwmc3200wifi/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index f2b1861..7a4647e 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -60,3 +60,5 @@ obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o obj-$(CONFIG_WL12XX) += wl12xx/ + +obj-$(CONFIG_IWM) += iwmc3200wifi/ diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig new file mode 100644 index 0000000..ae84dda --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -0,0 +1,23 @@ +config IWM + tristate "Intel Wireless Multicomm 3200 WiFi driver" + depends on MMC && WLAN_80211 && EXPERIMENTAL + select LIB80211 + select FW_LOADER + select RFKILL + +config IWM_DEBUG + bool "Enable full debugging output in iwmc3200wifi" + depends on IWM && DEBUG_FS + ---help--- + This option will enable debug tracing and setting for iwm + + You can set the debug level and module through debugfs. By + default all modules are set to the IWL_DL_ERR level. + To see the list of debug modules and levels, see iwm/debug.h + + For example, if you want the full MLME debug output: + echo 0xff > /debug/iwm/phyN/debug/mlme + + Or, if you want the full debug, for all modules: + echo 0xff > /debug/iwm/phyN/debug/level + echo 0xff > /debug/iwm/phyN/debug/modules diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile new file mode 100644 index 0000000..7cb415e --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_IWM) := iwmc3200wifi.o +iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o +iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o + +iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/iwmc3200wifi/bus.h b/drivers/net/wireless/iwmc3200wifi/bus.h new file mode 100644 index 0000000..836663e --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/bus.h @@ -0,0 +1,57 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __IWM_BUS_H__ +#define __IWM_BUS_H__ + +#include "iwm.h" + +struct iwm_if_ops { + int (*enable)(struct iwm_priv *iwm); + int (*disable)(struct iwm_priv *iwm); + int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count); + + int (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir); + void (*debugfs_exit)(struct iwm_priv *iwm); + + const char *umac_name; + const char *calib_lmac_name; + const char *lmac_name; +}; + +static inline int iwm_bus_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) +{ + return iwm->bus_ops->send_chunk(iwm, buf, count); +} + +static inline int iwm_bus_enable(struct iwm_priv *iwm) +{ + return iwm->bus_ops->enable(iwm); +} + +static inline int iwm_bus_disable(struct iwm_priv *iwm) +{ + return iwm->bus_ops->disable(iwm); +} + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c new file mode 100644 index 0000000..3256ad2 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -0,0 +1,409 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "commands.h" +#include "cfg80211.h" +#include "debug.h" + +#define RATETAB_ENT(_rate, _rateid, _flags) \ + { \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ + } + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_rate iwm_rates[] = { + RATETAB_ENT(10, 0x1, 0), + RATETAB_ENT(20, 0x2, 0), + RATETAB_ENT(55, 0x4, 0), + RATETAB_ENT(110, 0x8, 0), + RATETAB_ENT(60, 0x10, 0), + RATETAB_ENT(90, 0x20, 0), + RATETAB_ENT(120, 0x40, 0), + RATETAB_ENT(180, 0x80, 0), + RATETAB_ENT(240, 0x100, 0), + RATETAB_ENT(360, 0x200, 0), + RATETAB_ENT(480, 0x400, 0), + RATETAB_ENT(540, 0x800, 0), +}; + +#define iwm_a_rates (iwm_rates + 4) +#define iwm_a_rates_size 8 +#define iwm_g_rates (iwm_rates + 0) +#define iwm_g_rates_size 12 + +static struct ieee80211_channel iwm_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static struct ieee80211_channel iwm_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +static struct ieee80211_supported_band iwm_band_2ghz = { + .channels = iwm_2ghz_channels, + .n_channels = ARRAY_SIZE(iwm_2ghz_channels), + .bitrates = iwm_g_rates, + .n_bitrates = iwm_g_rates_size, +}; + +static struct ieee80211_supported_band iwm_band_5ghz = { + .channels = iwm_5ghz_a_channels, + .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels), + .bitrates = iwm_a_rates, + .n_bitrates = iwm_a_rates_size, +}; + +int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) +{ + struct wiphy *wiphy = iwm_to_wiphy(iwm); + struct iwm_bss_info *bss, *next; + struct iwm_umac_notif_bss_info *umac_bss; + struct ieee80211_mgmt *mgmt; + struct ieee80211_channel *channel; + struct ieee80211_supported_band *band; + s32 signal; + int freq; + + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { + umac_bss = bss->bss; + mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); + + if (umac_bss->band == UMAC_BAND_2GHZ) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else if (umac_bss->band == UMAC_BAND_5GHZ) + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + else { + IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); + return -EINVAL; + } + + freq = ieee80211_channel_to_frequency(umac_bss->channel); + channel = ieee80211_get_channel(wiphy, freq); + signal = umac_bss->rssi * 100; + + if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt, + le16_to_cpu(umac_bss->frame_len), + signal, GFP_KERNEL)) + return -EINVAL; + } + + return 0; +} + +static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct net_device *ndev; + struct wireless_dev *wdev; + struct iwm_priv *iwm; + u32 old_mode; + + /* we're under RTNL */ + ndev = __dev_get_by_index(&init_net, ifindex); + if (!ndev) + return -ENODEV; + + wdev = ndev->ieee80211_ptr; + iwm = ndev_to_iwm(ndev); + old_mode = iwm->conf.mode; + + switch (type) { + case NL80211_IFTYPE_STATION: + iwm->conf.mode = UMAC_MODE_BSS; + break; + case NL80211_IFTYPE_ADHOC: + iwm->conf.mode = UMAC_MODE_IBSS; + break; + default: + return -EOPNOTSUPP; + } + + wdev->iftype = type; + + if ((old_mode == iwm->conf.mode) || !iwm->umac_profile) + return 0; + + iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode); + + if (iwm->umac_profile_active) { + int ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + } + + return 0; +} + +static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret; + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) { + IWM_ERR(iwm, "Scan while device is not ready\n"); + return -EIO; + } + + if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) { + IWM_ERR(iwm, "Scanning already\n"); + return -EAGAIN; + } + + if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) { + IWM_ERR(iwm, "Scanning being aborted\n"); + return -EAGAIN; + } + + set_bit(IWM_STATUS_SCANNING, &iwm->status); + + ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids); + if (ret) { + clear_bit(IWM_STATUS_SCANNING, &iwm->status); + return ret; + } + + iwm->scan_request = request; + return 0; +} + +static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + if (changed & WIPHY_PARAM_RTS_THRESHOLD && + (iwm->conf.rts_threshold != wiphy->rts_threshold)) { + int ret; + + iwm->conf.rts_threshold = wiphy->rts_threshold; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_RTS_THRESHOLD, + iwm->conf.rts_threshold); + if (ret < 0) + return ret; + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD && + (iwm->conf.frag_threshold != wiphy->frag_threshold)) { + int ret; + + iwm->conf.frag_threshold = wiphy->frag_threshold; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_FRAG_THRESHOLD, + iwm->conf.frag_threshold); + if (ret < 0) + return ret; + } + + return 0; +} + +static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + struct ieee80211_channel *chan = params->channel; + struct cfg80211_bss *bss; + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + /* UMAC doesn't support creating IBSS network with specified bssid. + * This should be removed after we have join only mode supported. */ + if (params->bssid) + return -EOPNOTSUPP; + + bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, + params->ssid, params->ssid_len); + if (!bss) { + iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len); + schedule_timeout_interruptible(2 * HZ); + bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, + params->ssid, params->ssid_len); + } + /* IBSS join only mode is not supported by UMAC ATM */ + if (bss) { + cfg80211_put_bss(bss); + return -EOPNOTSUPP; + } + + iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); + iwm->umac_profile->ibss.band = chan->band; + iwm->umac_profile->ibss.channel = iwm->channel; + iwm->umac_profile->ssid.ssid_len = params->ssid_len; + memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); + + if (params->bssid) + memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN); + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + if (iwm->umac_profile_active) + return iwm_invalidate_mlme_profile(iwm); + + return 0; +} + +static struct cfg80211_ops iwm_cfg80211_ops = { + .change_virtual_intf = iwm_cfg80211_change_iface, + .scan = iwm_cfg80211_scan, + .set_wiphy_params = iwm_cfg80211_set_wiphy_params, + .join_ibss = iwm_cfg80211_join_ibss, + .leave_ibss = iwm_cfg80211_leave_ibss, +}; + +struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) +{ + int ret = 0; + struct wireless_dev *wdev; + + /* + * We're trying to have the following memory + * layout: + * + * +-------------------------+ + * | struct wiphy | + * +-------------------------+ + * | struct iwm_priv | + * +-------------------------+ + * | bus private data | + * | (e.g. iwm_priv_sdio) | + * +-------------------------+ + * + */ + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + dev_err(dev, "Couldn't allocate wireless device\n"); + return ERR_PTR(-ENOMEM); + } + + wdev->wiphy = wiphy_new(&iwm_cfg80211_ops, + sizeof(struct iwm_priv) + sizeof_bus); + if (!wdev->wiphy) { + dev_err(dev, "Couldn't allocate wiphy device\n"); + ret = -ENOMEM; + goto out_err_new; + } + + set_wiphy_dev(wdev->wiphy, dev); + wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + ret = wiphy_register(wdev->wiphy); + if (ret < 0) { + dev_err(dev, "Couldn't register wiphy device\n"); + goto out_err_register; + } + + return wdev; + + out_err_register: + wiphy_free(wdev->wiphy); + + out_err_new: + kfree(wdev); + + return ERR_PTR(ret); +} + +void iwm_wdev_free(struct iwm_priv *iwm) +{ + struct wireless_dev *wdev = iwm_to_wdev(iwm); + + if (!wdev) + return; + + wiphy_unregister(wdev->wiphy); + wiphy_free(wdev->wiphy); + kfree(wdev); +} diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.h b/drivers/net/wireless/iwmc3200wifi/cfg80211.h new file mode 100644 index 0000000..56a3414 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.h @@ -0,0 +1,31 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __IWM_CFG80211_H__ +#define __IWM_CFG80211_H__ + +int iwm_cfg80211_inform_bss(struct iwm_priv *iwm); +struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev); +void iwm_wdev_free(struct iwm_priv *iwm); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c new file mode 100644 index 0000000..834a7f5 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -0,0 +1,920 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "hal.h" +#include "umac.h" +#include "commands.h" +#include "debug.h" + +static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, + u8 lmac_cmd_id, + const void *lmac_payload, + u16 lmac_payload_size, + u8 resp) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_lmac_cmd lmac_cmd; + + lmac_cmd.id = lmac_cmd_id; + + umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH; + umac_cmd.resp = resp; + + return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd, + lmac_payload, lmac_payload_size); +} + +int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, + bool resp) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + + umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; + umac_cmd.resp = resp; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, + payload, payload_size); +} + +static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = +{ + {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, + {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, + {4, 3, 0, COEX_CALIBRATION_FLAGS}, + {4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS}, + {4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS}, + {4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, + {4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, + {4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, + {6, 3, 0, COEX_XOR_RF_ON_FLAGS}, + {4, 3, 0, COEX_RF_OFF_FLAGS}, + {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, + {4, 3, 0, COEX_RSRVD1_FLAGS}, + {4, 3, 0, COEX_RSRVD2_FLAGS} +}; + +static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = +{ + {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, + {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, + {5, 5, 0, COEX_CALIBRATION_FLAGS}, + {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, + {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, + {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, + {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, + {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, + {1, 1, 0, COEX_RF_ON_FLAGS}, + {1, 1, 0, COEX_RF_OFF_FLAGS}, + {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, + {1, 1, 0, COEX_RSRVD1_FLAGS}, + {1, 1, 0, COEX_RSRVD2_FLAGS} +}; + +int iwm_send_prio_table(struct iwm_priv *iwm) +{ + struct iwm_coex_prio_table_cmd coex_table_cmd; + u32 coex_enabled, mode_enabled; + + memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd)); + + coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; + + switch (iwm->conf.coexist_mode) { + case COEX_MODE_XOR: + case COEX_MODE_CM: + coex_enabled = 1; + break; + default: + coex_enabled = 0; + break; + } + + switch (iwm->conf.mode) { + case UMAC_MODE_BSS: + case UMAC_MODE_IBSS: + mode_enabled = 1; + break; + default: + mode_enabled = 0; + break; + } + + if (coex_enabled && mode_enabled) { + coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK | + COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | + COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; + + switch (iwm->conf.coexist_mode) { + case COEX_MODE_XOR: + memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, + sizeof(iwm_sta_xor_prio_tbl)); + break; + case COEX_MODE_CM: + memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl, + sizeof(iwm_sta_cm_prio_tbl)); + break; + default: + IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", + iwm->conf.coexist_mode); + break; + } + } else + IWM_WARN(iwm, "coexistense disabled\n"); + + return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, + &coex_table_cmd, + sizeof(struct iwm_coex_prio_table_cmd), 1); +} + +int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) +{ + struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; + + memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); + + cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.flags = + cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK); + + return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, + sizeof(struct iwm_lmac_cal_cfg_cmd), 1); +} + +int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) +{ + struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; + + memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); + + cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested); + + return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, + sizeof(struct iwm_lmac_cal_cfg_cmd), 0); +} + +int iwm_store_rxiq_calib_result(struct iwm_priv *iwm) +{ + struct iwm_calib_rxiq *rxiq; + u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); + int grplen = sizeof(struct iwm_calib_rxiq_group); + + rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL); + if (!rxiq) { + IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n"); + return -ENOMEM; + } + + eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); + if (IS_ERR(eeprom_rxiq)) { + IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n"); + return PTR_ERR(eeprom_rxiq); + } + + iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq; + iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq); + + rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD; + rxiq->hdr.first_grp = 0; + rxiq->hdr.grp_num = 1; + rxiq->hdr.all_data_valid = 1; + + memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen); + memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen); + + return 0; +} + +int iwm_send_calib_results(struct iwm_priv *iwm) +{ + int i, ret = 0; + + for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) { + if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM, + &iwm->calib_done_map)) { + IWM_DBG_CMD(iwm, DBG, + "Send calibration %d result\n", i); + ret |= iwm_send_lmac_ptrough_cmd(iwm, + REPLY_PHY_CALIBRATION_CMD, + iwm->calib_res[i].buf, + iwm->calib_res[i].size, 0); + + kfree(iwm->calib_res[i].buf); + iwm->calib_res[i].buf = NULL; + iwm->calib_res[i].size = 0; + } + } + + return ret; +} + +int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_reset reset; + + reset.flags = reset_flags; + + umac_cmd.id = UMAC_CMD_OPCODE_RESET; + umac_cmd.resp = resp; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset, + sizeof(struct iwm_umac_cmd_reset)); +} + +int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_set_param_fix param; + + if ((tbl != UMAC_PARAM_TBL_CFG_FIX) && + (tbl != UMAC_PARAM_TBL_FA_CFG_FIX)) + return -EINVAL; + + umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX; + umac_cmd.resp = 0; + + param.tbl = cpu_to_le16(tbl); + param.key = cpu_to_le16(key); + param.value = cpu_to_le32(value); + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ¶m, + sizeof(struct iwm_umac_cmd_set_param_fix)); +} + +int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, + void *payload, u16 payload_size) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_set_param_var *param_hdr; + u8 *param; + int ret; + + param = kzalloc(payload_size + + sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL); + if (!param) { + IWM_ERR(iwm, "Couldn't allocate param\n"); + return -ENOMEM; + } + + param_hdr = (struct iwm_umac_cmd_set_param_var *)param; + + umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR; + umac_cmd.resp = 0; + + param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR); + param_hdr->key = cpu_to_le16(key); + param_hdr->len = cpu_to_le16(payload_size); + memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var), + payload, payload_size); + + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param, + sizeof(struct iwm_umac_cmd_set_param_var) + + payload_size); + kfree(param); + + return ret; +} + +int iwm_send_umac_config(struct iwm_priv *iwm, + __le32 reset_flags) +{ + int ret; + + /* Use UMAC default values */ + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, + CFG_FRAG_THRESHOLD, + iwm->conf.frag_threshold); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_RTS_THRESHOLD, + iwm->conf.rts_threshold); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_CTS_TO_SELF, iwm->conf.cts_to_self); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_COEX_MODE, iwm->conf.coexist_mode); + if (ret < 0) + return ret; + + /* + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_ASSOCIATION_TIMEOUT, + iwm->conf.assoc_timeout); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_ROAM_TIMEOUT, + iwm->conf.roam_timeout); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_WIRELESS_MODE, + WIRELESS_MODE_11A | WIRELESS_MODE_11G); + if (ret < 0) + return ret; + */ + + ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR, + iwm_to_ndev(iwm)->dev_addr, ETH_ALEN); + if (ret < 0) + return ret; + + /* UMAC PM static configurations */ + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_LEGACY_RX_TIMEOUT, 0x12C); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_LEGACY_TX_TIMEOUT, 0x15E); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_CTRL_FLAGS, 0x30001); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80); + if (ret < 0) + return ret; + + /* reset UMAC */ + ret = iwm_send_umac_reset(iwm, reset_flags, 1); + if (ret < 0) + return ret; + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, + WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); + return ret; + } + + return ret; +} + +int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id) +{ + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_tx_info *tx_info = skb_to_tx_info(skb); + + udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */ + udma_cmd.credit_group = pool_id; + udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; + udma_cmd.lmac_offset = 0; + + umac_cmd.id = REPLY_TX; + umac_cmd.color = tx_info->color; + umac_cmd.resp = 0; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, + skb->data, skb->len); +} + +static int iwm_target_read(struct iwm_priv *iwm, __le32 address, + u8 *response, u32 resp_size) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + struct iwm_nonwifi_cmd *cmd; + u16 seq_num; + int ret = 0; + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ; + target_cmd.addr = address; + target_cmd.op1_sz = cpu_to_le32(resp_size); + target_cmd.op2 = 0; + target_cmd.handle_by_hw = 0; + target_cmd.resp = 1; + target_cmd.eop = 1; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); + if (ret < 0) + IWM_ERR(iwm, "Couldn't send READ command\n"); + + /* When succeding, the send_target routine returns the seq number */ + seq_num = ret; + + ret = wait_event_interruptible_timeout(iwm->nonwifi_queue, + (cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num, + UMAC_HDI_OUT_OPCODE_READ)) != NULL, + 2 * HZ); + + if (!ret) { + IWM_ERR(iwm, "Didn't receive a target READ answer\n"); + return ret; + } + + memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr), + resp_size); + + kfree(cmd); + + return ret; +} + +int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) +{ + int ret; + u8 mac_align[ALIGN(ETH_ALEN, 8)]; + + ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), + mac_align, sizeof(mac_align)); + if (ret < 0) + return ret; + + if (is_valid_ether_addr(mac_align)) + memcpy(mac, mac_align, ETH_ALEN); + else { + IWM_ERR(iwm, "Invalid EEPROM MAC\n"); + memcpy(mac, iwm->conf.mac_addr, ETH_ALEN); + get_random_bytes(&mac[3], 3); + } + + return 0; +} + +int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) +{ + struct iwm_umac_tx_key_id tx_key_id; + + if (!iwm->default_key || !iwm->default_key->in_use) + return -EINVAL; + + tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; + tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - + sizeof(struct iwm_umac_wifi_if)); + + tx_key_id.key_idx = key_idx; + + return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); +} + +static int iwm_check_profile(struct iwm_priv *iwm) +{ + if (!iwm->umac_profile_active) + return -EAGAIN; + + if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) { + IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n", + iwm->umac_profile->sec.ucast_cipher); + return -EAGAIN; + } + + if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 && + iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 && + iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP && + iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) { + IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n", + iwm->umac_profile->sec.mcast_cipher); + return -EAGAIN; + } + + if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || + iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && + (iwm->umac_profile->sec.ucast_cipher != + iwm->umac_profile->sec.mcast_cipher)) { + IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n"); + } + + return 0; +} + +int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, + struct iwm_key *key) +{ + int ret; + u8 cmd[64], *sta_addr, *key_data, key_len; + s8 key_idx; + u16 cmd_size = 0; + struct iwm_umac_key_hdr *key_hdr = &key->hdr; + struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; + struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; + struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; + struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; + + if (set_tx_key) + iwm->default_key = key; + + /* + * We check if our current profile is valid. + * If not, we dont push the key, we just cache them, + * so that with the next siwsessid call, the keys + * will be actually pushed. + */ + if (!remove) { + ret = iwm_check_profile(iwm); + if (ret < 0) + return ret; + } + + sta_addr = key->hdr.mac; + key_data = key->key; + key_len = key->key_len; + key_idx = key->hdr.key_idx; + + if (!remove) { + IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", + key_idx, set_tx_key); + IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); + IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", + key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); + + IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", + iwm->umac_profile->sec.mcast_cipher, + iwm->umac_profile->sec.ucast_cipher); + IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", + iwm->umac_profile->sec.auth_type, + iwm->umac_profile->sec.flags); + + switch (key->alg) { + case UMAC_CIPHER_TYPE_WEP_40: + wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; + wep40->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&wep40->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + memcpy(wep40->key, key_data, key_len); + wep40->static_key = 1; + + cmd_size = sizeof(struct iwm_umac_key_wep40); + break; + + case UMAC_CIPHER_TYPE_WEP_104: + wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; + wep104->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&wep104->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + memcpy(wep104->key, key_data, key_len); + wep104->static_key = 1; + + cmd_size = sizeof(struct iwm_umac_key_wep104); + break; + + case UMAC_CIPHER_TYPE_CCMP: + key_hdr->key_idx++; + ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; + ccmp->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&ccmp->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + + memcpy(ccmp->key, key_data, key_len); + + if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) + memcpy(ccmp->iv_count, key->rx_seq, 6); + + cmd_size = sizeof(struct iwm_umac_key_ccmp); + break; + + case UMAC_CIPHER_TYPE_TKIP: + key_hdr->key_idx++; + tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; + tkip->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&tkip->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + + memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); + memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, + IWM_TKIP_MIC_SIZE); + memcpy(tkip->mic_rx_key, + key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, + IWM_TKIP_MIC_SIZE); + + if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) + memcpy(ccmp->iv_count, key->rx_seq, 6); + + cmd_size = sizeof(struct iwm_umac_key_tkip); + break; + + default: + return -ENOTSUPP; + } + + if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || + (key->alg == UMAC_CIPHER_TYPE_TKIP)) + /* + * UGLY_UGLY_UGLY + * Copied HACK from the MWG driver. + * Without it, the key is set before the second + * EAPOL frame is sent, and the latter is thus + * encrypted. + */ + schedule_timeout_interruptible(usecs_to_jiffies(300)); + + ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); + if (ret < 0) + goto err; + + /* + * We need a default key only if it is set and + * if we're doing WEP. + */ + if (iwm->default_key == key && + ((key->alg == UMAC_CIPHER_TYPE_WEP_40) || + (key->alg == UMAC_CIPHER_TYPE_WEP_104))) { + ret = iwm_set_tx_key(iwm, key_idx); + if (ret < 0) + goto err; + } + } else { + struct iwm_umac_key_remove key_remove; + + key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; + key_remove.hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_remove) - + sizeof(struct iwm_umac_wifi_if)); + memcpy(&key_remove.key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + + ret = iwm_send_wifi_if_cmd(iwm, &key_remove, + sizeof(struct iwm_umac_key_remove), + 1); + if (ret < 0) + return ret; + + iwm->keys[key_idx].in_use = 0; + } + + return 0; + + err: + kfree(key); + return ret; +} + + +int iwm_send_mlme_profile(struct iwm_priv *iwm) +{ + int ret, i; + struct iwm_umac_profile profile; + + memcpy(&profile, iwm->umac_profile, sizeof(profile)); + + profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE; + profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) - + sizeof(struct iwm_umac_wifi_if)); + + ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); + if (ret < 0) { + IWM_ERR(iwm, "Send profile command failed\n"); + return ret; + } + + /* Wait for the profile to be active */ + ret = wait_event_interruptible_timeout(iwm->mlme_queue, + iwm->umac_profile_active == 1, + 3 * HZ); + if (!ret) + return -EBUSY; + + + for (i = 0; i < IWM_NUM_KEYS; i++) + if (iwm->keys[i].in_use) { + int default_key = 0; + struct iwm_key *key = &iwm->keys[i]; + + if (key == iwm->default_key) + default_key = 1; + + /* Wait for the profile before sending the keys */ + wait_event_interruptible_timeout(iwm->mlme_queue, + (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || + test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), + 3 * HZ); + + ret = iwm_set_key(iwm, 0, default_key, key); + if (ret < 0) + return ret; + } + + return 0; +} + +int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) +{ + int ret; + struct iwm_umac_invalidate_profile invalid; + + invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; + invalid.hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) - + sizeof(struct iwm_umac_wifi_if)); + + invalid.reason = WLAN_REASON_UNSPECIFIED; + + ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); + if (ret < 0) + return ret; + + ret = wait_event_interruptible_timeout(iwm->mlme_queue, + (iwm->umac_profile_active == 0), + 2 * HZ); + if (!ret) + return -EBUSY; + + return 0; +} + +int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_stats_req stats_req; + + stats_req.flags = cpu_to_le32(flags); + + umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST; + umac_cmd.resp = 0; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req, + sizeof(struct iwm_umac_cmd_stats_req)); +} + +int iwm_send_umac_channel_list(struct iwm_priv *iwm) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_get_channel_list *ch_list; + int size = sizeof(struct iwm_umac_cmd_get_channel_list) + + sizeof(struct iwm_umac_channel_info) * 4; + int ret; + + ch_list = kzalloc(size, GFP_KERNEL); + if (!ch_list) { + IWM_ERR(iwm, "Couldn't allocate channel list cmd\n"); + return -ENOMEM; + } + + ch_list->ch[0].band = UMAC_BAND_2GHZ; + ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID; + + ch_list->ch[1].band = UMAC_BAND_5GHZ; + ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID; + + ch_list->ch[2].band = UMAC_BAND_2GHZ; + ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; + + ch_list->ch[3].band = UMAC_BAND_5GHZ; + ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; + + ch_list->count = cpu_to_le16(4); + + umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST; + umac_cmd.resp = 1; + + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size); + + kfree(ch_list); + + return ret; +} + +int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, + int ssid_num) +{ + struct iwm_umac_cmd_scan_request req; + int i, ret; + + memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request)); + + req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST; + req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request) + - sizeof(struct iwm_umac_wifi_if)); + req.type = UMAC_WIFI_IF_SCAN_TYPE_USER; + req.timeout = 2; + req.seq_num = iwm->scan_id; + req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX); + + for (i = 0; i < req.ssid_num; i++) { + memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len); + req.ssids[i].ssid_len = ssids[i].ssid_len; + } + + ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't send scan request\n"); + return ret; + } + + iwm->scan_id = iwm->scan_id++ % IWM_SCAN_ID_MAX; + + return 0; +} + +int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len) +{ + struct cfg80211_ssid one_ssid; + + if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status)) + return 0; + + one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN); + memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len); + + return iwm_scan_ssids(iwm, &one_ssid, 1); +} + +int iwm_target_reset(struct iwm_priv *iwm) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT; + target_cmd.addr = 0; + target_cmd.op1_sz = 0; + target_cmd.op2 = 0; + target_cmd.handle_by_hw = 0; + target_cmd.resp = 0; + target_cmd.eop = 1; + + return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); +} diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h new file mode 100644 index 0000000..36b13a1 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -0,0 +1,419 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_COMMANDS_H__ +#define __IWM_COMMANDS_H__ + +#include + +#define IWM_BARKER_REBOOT_NOTIFICATION 0xF +#define IWM_ACK_BARKER_NOTIFICATION 0x10 + +/* UMAC commands */ +#define UMAC_RST_CTRL_FLG_LARC_CLK_EN 0x0001 +#define UMAC_RST_CTRL_FLG_LARC_RESET 0x0002 +#define UMAC_RST_CTRL_FLG_FUNC_RESET 0x0004 +#define UMAC_RST_CTRL_FLG_DEV_RESET 0x0008 +#define UMAC_RST_CTRL_FLG_WIFI_CORE_EN 0x0010 +#define UMAC_RST_CTRL_FLG_WIFI_LINK_EN 0x0040 +#define UMAC_RST_CTRL_FLG_WIFI_MLME_EN 0x0080 +#define UMAC_RST_CTRL_FLG_NVM_RELOAD 0x0100 + +struct iwm_umac_cmd_reset { + __le32 flags; +} __attribute__ ((packed)); + +#define UMAC_PARAM_TBL_ORD_FIX 0x0 +#define UMAC_PARAM_TBL_ORD_VAR 0x1 +#define UMAC_PARAM_TBL_CFG_FIX 0x2 +#define UMAC_PARAM_TBL_CFG_VAR 0x3 +#define UMAC_PARAM_TBL_BSS_TRK 0x4 +#define UMAC_PARAM_TBL_FA_CFG_FIX 0x5 +#define UMAC_PARAM_TBL_STA 0x6 +#define UMAC_PARAM_TBL_CHN 0x7 +#define UMAC_PARAM_TBL_STATISTICS 0x8 + +/* fast access table */ +enum { + CFG_FRAG_THRESHOLD = 0, + CFG_FRAME_RETRY_LIMIT, + CFG_OS_QUEUE_UTIL_TH, + CFG_RX_FILTER, + /* <-- LAST --> */ + FAST_ACCESS_CFG_TBL_FIX_LAST +}; + +/* fixed size table */ +enum { + CFG_POWER_INDEX = 0, + CFG_PM_LEGACY_RX_TIMEOUT, + CFG_PM_LEGACY_TX_TIMEOUT, + CFG_PM_CTRL_FLAGS, + CFG_PM_KEEP_ALIVE_IN_BEACONS, + CFG_BT_ON_THRESHOLD, + CFG_RTS_THRESHOLD, + CFG_CTS_TO_SELF, + CFG_COEX_MODE, + CFG_WIRELESS_MODE, + CFG_ASSOCIATION_TIMEOUT, + CFG_ROAM_TIMEOUT, + CFG_CAPABILITY_SUPPORTED_RATES, + CFG_SCAN_ALLOWED_UNASSOC_FLAGS, + CFG_SCAN_ALLOWED_MAIN_ASSOC_FLAGS, + CFG_SCAN_ALLOWED_PAN_ASSOC_FLAGS, + CFG_SCAN_INTERNAL_PERIODIC_ENABLED, + CFG_SCAN_IMM_INTERNAL_PERIODIC_SCAN_ON_INIT, + CFG_SCAN_DEFAULT_PERIODIC_FREQ_SEC, + CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, + CFG_TLC_SUPPORTED_TX_HT_RATES, + CFG_TLC_SUPPORTED_TX_RATES, + CFG_TLC_VALID_ANTENNA, + CFG_TLC_SPATIAL_STREAM_SUPPORTED, + CFG_TLC_RETRY_PER_RATE, + CFG_TLC_RETRY_PER_HT_RATE, + CFG_TLC_FIXED_RATE, + CFG_TLC_FIXED_RATE_FLAGS, + CFG_TLC_CONTROL_FLAGS, + CFG_TLC_SR_MIN_FAIL, + CFG_TLC_SR_MIN_PASS, + CFG_TLC_HT_STAY_IN_COL_PASS_THRESH, + CFG_TLC_HT_STAY_IN_COL_FAIL_THRESH, + CFG_TLC_LEGACY_STAY_IN_COL_PASS_THRESH, + CFG_TLC_LEGACY_STAY_IN_COL_FAIL_THRESH, + CFG_TLC_HT_FLUSH_STATS_PACKETS, + CFG_TLC_LEGACY_FLUSH_STATS_PACKETS, + CFG_TLC_LEGACY_FLUSH_STATS_MS, + CFG_TLC_HT_FLUSH_STATS_MS, + CFG_TLC_STAY_IN_COL_TIME_OUT, + CFG_TLC_AGG_SHORT_LIM, + CFG_TLC_AGG_LONG_LIM, + CFG_TLC_HT_SR_NO_DECREASE, + CFG_TLC_LEGACY_SR_NO_DECREASE, + CFG_TLC_SR_FORCE_DECREASE, + CFG_TLC_SR_ALLOW_INCREASE, + CFG_TLC_AGG_SET_LONG, + CFG_TLC_AUTO_AGGREGATION, + CFG_TLC_AGG_THRESHOLD, + CFG_TLC_TID_LOAD_THRESHOLD, + CFG_TLC_BLOCK_ACK_TIMEOUT, + CFG_TLC_NO_BA_COUNTED_AS_ONE, + CFG_TLC_NUM_BA_STREAMS_ALLOWED, + CFG_TLC_NUM_BA_STREAMS_PRESENT, + CFG_TLC_RENEW_ADDBA_DELAY, + CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, + CFG_TLC_IS_STABLE_IN_HT, + CFG_RLC_CHAIN_CTRL, + CFG_TRK_TABLE_OP_MODE, + CFG_TRK_TABLE_RSSI_THRESHOLD, + CFG_TX_PWR_TARGET, /* Used By xVT */ + CFG_TX_PWR_LIMIT_USR, + CFG_TX_PWR_LIMIT_BSS, /* 11d limit */ + CFG_TX_PWR_LIMIT_BSS_CONSTRAINT, /* 11h constraint */ + CFG_TX_PWR_MODE, + CFG_MLME_DBG_NOTIF_BLOCK, + CFG_BT_OFF_BECONS_INTERVALS, + CFG_BT_FRAG_DURATION, + + /* <-- LAST --> */ + CFG_TBL_FIX_LAST +}; + +/* variable size table */ +enum { + CFG_NET_ADDR = 0, + CFG_PROFILE, + /* <-- LAST --> */ + CFG_TBL_VAR_LAST +}; + +struct iwm_umac_cmd_set_param_fix { + __le16 tbl; + __le16 key; + __le32 value; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_set_param_var { + __le16 tbl; + __le16 key; + __le16 len; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_get_param { + __le16 tbl; + __le16 key; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_get_param_resp { + __le16 tbl; + __le16 key; + __le16 len; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_eeprom_proxy_hdr { + __le32 type; + __le32 offset; + __le32 len; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_eeprom_proxy { + struct iwm_umac_cmd_eeprom_proxy_hdr hdr; + u8 buf[0]; +} __attribute__ ((packed)); + +#define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1 +#define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2 + +#define UMAC_CHANNEL_FLAG_VALID BIT(0) +#define UMAC_CHANNEL_FLAG_IBSS BIT(1) +#define UMAC_CHANNEL_FLAG_ACTIVE BIT(3) +#define UMAC_CHANNEL_FLAG_RADAR BIT(4) +#define UMAC_CHANNEL_FLAG_DFS BIT(7) + +struct iwm_umac_channel_info { + u8 band; + u8 type; + u8 reserved; + u8 flags; + __le32 channels_mask; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_get_channel_list { + __le16 count; + __le16 reserved; + struct iwm_umac_channel_info ch[0]; +} __attribute__ ((packed)); + + +/* UMAC WiFi interface commands */ + +/* Coexistence mode */ +#define COEX_MODE_SA 0x1 +#define COEX_MODE_XOR 0x2 +#define COEX_MODE_CM 0x3 +#define COEX_MODE_MAX 0x4 + +/* Wireless mode */ +#define WIRELESS_MODE_11A 0x1 +#define WIRELESS_MODE_11G 0x2 + +#define UMAC_PROFILE_EX_IE_REQUIRED 0x1 +#define UMAC_PROFILE_QOS_ALLOWED 0x2 + +/* Scanning */ +#define UMAC_WIFI_IF_PROBE_OPTION_MAX 10 + +#define UMAC_WIFI_IF_SCAN_TYPE_USER 0x0 +#define UMAC_WIFI_IF_SCAN_TYPE_UMAC_RESERVED 0x1 +#define UMAC_WIFI_IF_SCAN_TYPE_HOST_PERIODIC 0x2 +#define UMAC_WIFI_IF_SCAN_TYPE_MAX 0x3 + +struct iwm_umac_ssid { + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_scan_request { + struct iwm_umac_wifi_if hdr; + __le32 type; /* UMAC_WIFI_IF_SCAN_TYPE_* */ + u8 ssid_num; + u8 seq_num; + u8 timeout; /* In seconds */ + u8 reserved; + struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX]; +} __attribute__ ((packed)); + +#define UMAC_CIPHER_TYPE_NONE 0xFF +#define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00 +#define UMAC_CIPHER_TYPE_WEP_40 0x01 +#define UMAC_CIPHER_TYPE_WEP_104 0x02 +#define UMAC_CIPHER_TYPE_TKIP 0x04 +#define UMAC_CIPHER_TYPE_CCMP 0x08 + +/* Supported authentication types - bitmap */ +#define UMAC_AUTH_TYPE_OPEN 0x00 +#define UMAC_AUTH_TYPE_LEGACY_PSK 0x01 +#define UMAC_AUTH_TYPE_8021X 0x02 +#define UMAC_AUTH_TYPE_RSNA_PSK 0x04 + +/* iwm_umac_security.flag is WPA supported -- bits[0:0] */ +#define UMAC_SEC_FLG_WPA_ON_POS 0 +#define UMAC_SEC_FLG_WPA_ON_SEED 1 +#define UMAC_SEC_FLG_WPA_ON_MSK (UMAC_SEC_FLG_WPA_ON_SEED << \ + UMAC_SEC_FLG_WPA_ON_POS) + +/* iwm_umac_security.flag is WPA2 supported -- bits [1:1] */ +#define UMAC_SEC_FLG_RSNA_ON_POS 1 +#define UMAC_SEC_FLG_RSNA_ON_SEED 1 +#define UMAC_SEC_FLG_RSNA_ON_MSK (UMAC_SEC_FLG_RSNA_ON_SEED << \ + UMAC_SEC_FLG_RSNA_ON_POS) + +/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ +#define UMAC_SEC_FLG_WSC_ON_POS 2 +#define UMAC_SEC_FLG_WSC_ON_SEED 1 + +/* Legacy profile can use only WEP40 and WEP104 for encryption and + * OPEN or PSK for authentication */ +#define UMAC_SEC_FLG_LEGACY_PROFILE 0 + +struct iwm_umac_security { + u8 auth_type; + u8 ucast_cipher; + u8 mcast_cipher; + u8 flags; +} __attribute__ ((packed)); + +struct iwm_umac_ibss { + u8 beacon_interval; /* in millisecond */ + u8 atim; /* in millisecond */ + s8 join_only; + u8 band; + u8 channel; + u8 reserved[3]; +} __attribute__ ((packed)); + +#define UMAC_MODE_BSS 0 +#define UMAC_MODE_IBSS 1 + +#define UMAC_BSSID_MAX 4 + +struct iwm_umac_profile { + struct iwm_umac_wifi_if hdr; + __le32 mode; + struct iwm_umac_ssid ssid; + u8 bssid[UMAC_BSSID_MAX][ETH_ALEN]; + struct iwm_umac_security sec; + struct iwm_umac_ibss ibss; + __le32 channel_2ghz; + __le32 channel_5ghz; + __le16 flags; + u8 wireless_mode; + u8 bss_num; +} __attribute__ ((packed)); + +struct iwm_umac_invalidate_profile { + struct iwm_umac_wifi_if hdr; + u8 reason; + u8 reserved[3]; +} __attribute__ ((packed)); + +/* Encryption key commands */ +struct iwm_umac_key_wep40 { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 key[WLAN_KEY_LEN_WEP40]; + u8 static_key; + u8 reserved[2]; +} __attribute__ ((packed)); + +struct iwm_umac_key_wep104 { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 key[WLAN_KEY_LEN_WEP104]; + u8 static_key; + u8 reserved[2]; +} __attribute__ ((packed)); + +#define IWM_TKIP_KEY_SIZE 16 +#define IWM_TKIP_MIC_SIZE 8 +struct iwm_umac_key_tkip { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 iv_count[6]; + u8 reserved[2]; + u8 tkip_key[IWM_TKIP_KEY_SIZE]; + u8 mic_rx_key[IWM_TKIP_MIC_SIZE]; + u8 mic_tx_key[IWM_TKIP_MIC_SIZE]; +} __attribute__ ((packed)); + +struct iwm_umac_key_ccmp { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 iv_count[6]; + u8 reserved[2]; + u8 key[WLAN_KEY_LEN_CCMP]; +} __attribute__ ((packed)); + +struct iwm_umac_key_remove { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_tx_key_id { + struct iwm_umac_wifi_if hdr; + u8 key_idx; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_stats_req { + __le32 flags; +} __attribute__ ((packed)); + +/* LMAC commands */ +int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); +int iwm_send_prio_table(struct iwm_priv *iwm); +int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); +int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); +int iwm_send_calib_results(struct iwm_priv *iwm); +int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); + +/* UMAC commands */ +int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, + bool resp); +int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp); +int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value); +int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, + void *payload, u16 payload_size); +int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags); +int iwm_send_mlme_profile(struct iwm_priv *iwm); +int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); +int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); +int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); +int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, + struct iwm_key *key); +int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); +int iwm_send_umac_channel_list(struct iwm_priv *iwm); +int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, + int ssid_num); +int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); + +/* UDMA commands */ +int iwm_target_reset(struct iwm_priv *iwm); +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h new file mode 100644 index 0000000..8fbb42d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/debug.h @@ -0,0 +1,124 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __IWM_DEBUG_H__ +#define __IWM_DEBUG_H__ + +#define IWM_ERR(p, f, a...) dev_err(iwm_to_dev(p), f, ## a) +#define IWM_WARN(p, f, a...) dev_warn(iwm_to_dev(p), f, ## a) +#define IWM_INFO(p, f, a...) dev_info(iwm_to_dev(p), f, ## a) +#define IWM_CRIT(p, f, a...) dev_crit(iwm_to_dev(p), f, ## a) + +#ifdef CONFIG_IWM_DEBUG + +#define IWM_DEBUG_MODULE(i, level, module, f, a...) \ +do { \ + if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ + dev_printk(KERN_INFO, (iwm_to_dev(i)), \ + "%s " f, __func__ , ## a); \ +} while (0) + +#define IWM_HEXDUMP(i, level, module, pref, buf, len) \ +do { \ + if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ + print_hex_dump(KERN_INFO, pref, DUMP_PREFIX_OFFSET, \ + 16, 1, buf, len, 1); \ +} while (0) + +#else + +#define IWM_DEBUG_MODULE(i, level, module, f, a...) +#define IWM_HEXDUMP(i, level, module, pref, buf, len) + +#endif /* CONFIG_IWM_DEBUG */ + +/* Debug modules */ +enum iwm_debug_module_id { + IWM_DM_BOOT = 0, + IWM_DM_FW, + IWM_DM_SDIO, + IWM_DM_NTF, + IWM_DM_RX, + IWM_DM_TX, + IWM_DM_MLME, + IWM_DM_CMD, + IWM_DM_WEXT, + __IWM_DM_NR, +}; +#define IWM_DM_DEFAULT 0 + +#define IWM_DBG_BOOT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, BOOT, f, ## a) +#define IWM_DBG_FW(i, l, f, a...) IWM_DEBUG_MODULE(i, l, FW, f, ## a) +#define IWM_DBG_SDIO(i, l, f, a...) IWM_DEBUG_MODULE(i, l, SDIO, f, ## a) +#define IWM_DBG_NTF(i, l, f, a...) IWM_DEBUG_MODULE(i, l, NTF, f, ## a) +#define IWM_DBG_RX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, RX, f, ## a) +#define IWM_DBG_TX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, TX, f, ## a) +#define IWM_DBG_MLME(i, l, f, a...) IWM_DEBUG_MODULE(i, l, MLME, f, ## a) +#define IWM_DBG_CMD(i, l, f, a...) IWM_DEBUG_MODULE(i, l, CMD, f, ## a) +#define IWM_DBG_WEXT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, WEXT, f, ## a) + +/* Debug levels */ +enum iwm_debug_level { + IWM_DL_NONE = 0, + IWM_DL_ERR, + IWM_DL_WARN, + IWM_DL_INFO, + IWM_DL_DBG, +}; +#define IWM_DL_DEFAULT IWM_DL_ERR + +struct iwm_debugfs { + struct iwm_priv *iwm; + struct dentry *rootdir; + struct dentry *devdir; + struct dentry *dbgdir; + struct dentry *txdir; + struct dentry *rxdir; + struct dentry *busdir; + + u32 dbg_level; + struct dentry *dbg_level_dentry; + + unsigned long dbg_modules; + struct dentry *dbg_modules_dentry; + + u8 dbg_module[__IWM_DM_NR]; + struct dentry *dbg_module_dentries[__IWM_DM_NR]; + + struct dentry *txq_dentry; + struct dentry *tx_credit_dentry; + struct dentry *rx_ticket_dentry; +}; + +#ifdef CONFIG_IWM_DEBUG +int iwm_debugfs_init(struct iwm_priv *iwm); +void iwm_debugfs_exit(struct iwm_priv *iwm); +#else +static inline int iwm_debugfs_init(struct iwm_priv *iwm) +{ + return 0; +} +static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {} +#endif + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c new file mode 100644 index 0000000..0fa7b91 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -0,0 +1,453 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "rx.h" +#include "debug.h" + +static struct { + u8 id; + char *name; +} iwm_debug_module[__IWM_DM_NR] = { + {IWM_DM_BOOT, "boot"}, + {IWM_DM_FW, "fw"}, + {IWM_DM_SDIO, "sdio"}, + {IWM_DM_NTF, "ntf"}, + {IWM_DM_RX, "rx"}, + {IWM_DM_TX, "tx"}, + {IWM_DM_MLME, "mlme"}, + {IWM_DM_CMD, "cmd"}, + {IWM_DM_WEXT, "wext"}, +}; + +#define add_dbg_module(dbg, name, id, initlevel) \ +do { \ + struct dentry *d; \ + dbg.dbg_module[id] = (initlevel); \ + d = debugfs_create_x8(name, 0600, dbg.dbgdir, \ + &(dbg.dbg_module[id])); \ + if (!IS_ERR(d)) \ + dbg.dbg_module_dentries[id] = d; \ +} while (0) + +static int iwm_debugfs_u32_read(void *data, u64 *val) +{ + struct iwm_priv *iwm = data; + + *val = iwm->dbg.dbg_level; + return 0; +} + +static int iwm_debugfs_dbg_level_write(void *data, u64 val) +{ + struct iwm_priv *iwm = data; + int i; + + iwm->dbg.dbg_level = val; + + for (i = 0; i < __IWM_DM_NR; i++) + iwm->dbg.dbg_module[i] = val; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level, + iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write, + "%llu\n"); + +static int iwm_debugfs_dbg_modules_write(void *data, u64 val) +{ + struct iwm_priv *iwm = data; + int i, bit; + + iwm->dbg.dbg_modules = val; + + for (i = 0; i < __IWM_DM_NR; i++) + iwm->dbg.dbg_module[i] = 0; + + for_each_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR) + iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, + iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, + "%llu\n"); + +static int iwm_txrx_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + + +static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + char *buf; + int i, buf_len = 4096; + size_t len = 0; + ssize_t ret; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < IWM_TX_QUEUES; i++) { + struct iwm_tx_queue *txq = &iwm->txq[i]; + struct sk_buff *skb; + int j; + unsigned long flags; + + spin_lock_irqsave(&txq->queue.lock, flags); + + skb = (struct sk_buff *)&txq->queue; + + len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i); + len += snprintf(buf + len, buf_len - len, "\tStopped: %d\n", + __netif_subqueue_stopped(iwm_to_ndev(iwm), + txq->id)); + len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n", + txq->concat_count); + len += snprintf(buf + len, buf_len - len, "\tQueue len: %d\n", + skb_queue_len(&txq->queue)); + for (j = 0; j < skb_queue_len(&txq->queue); j++) { + struct iwm_tx_info *tx_info; + + skb = skb->next; + tx_info = skb_to_tx_info(skb); + + len += snprintf(buf + len, buf_len - len, + "\tSKB #%d\n", j); + len += snprintf(buf + len, buf_len - len, + "\t\tsta: %d\n", tx_info->sta); + len += snprintf(buf + len, buf_len - len, + "\t\tcolor: %d\n", tx_info->color); + len += snprintf(buf + len, buf_len - len, + "\t\ttid: %d\n", tx_info->tid); + } + + spin_unlock_irqrestore(&txq->queue.lock, flags); + } + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); + kfree(buf); + + return ret; +} + +static ssize_t iwm_debugfs_tx_credit_read(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + struct iwm_tx_credit *credit = &iwm->tx_credit; + char *buf; + int i, buf_len = 4096; + size_t len = 0; + ssize_t ret; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += snprintf(buf + len, buf_len - len, + "NR pools: %d\n", credit->pool_nr); + len += snprintf(buf + len, buf_len - len, + "pools map: 0x%lx\n", credit->full_pools_map); + + len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n"); + for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) { + len += snprintf(buf + len, buf_len - len, + "pools entry #%d\n", i); + len += snprintf(buf + len, buf_len - len, + "\tid: %d\n", + credit->pools[i].id); + len += snprintf(buf + len, buf_len - len, + "\tsid: %d\n", + credit->pools[i].sid); + len += snprintf(buf + len, buf_len - len, + "\tmin_pages: %d\n", + credit->pools[i].min_pages); + len += snprintf(buf + len, buf_len - len, + "\tmax_pages: %d\n", + credit->pools[i].max_pages); + len += snprintf(buf + len, buf_len - len, + "\talloc_pages: %d\n", + credit->pools[i].alloc_pages); + len += snprintf(buf + len, buf_len - len, + "\tfreed_pages: %d\n", + credit->pools[i].total_freed_pages); + } + + len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n"); + for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) { + len += snprintf(buf + len, buf_len - len, + "spools entry #%d\n", i); + len += snprintf(buf + len, buf_len - len, + "\tid: %d\n", + credit->spools[i].id); + len += snprintf(buf + len, buf_len - len, + "\tmax_pages: %d\n", + credit->spools[i].max_pages); + len += snprintf(buf + len, buf_len - len, + "\talloc_pages: %d\n", + credit->spools[i].alloc_pages); + + } + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); + kfree(buf); + + return ret; +} + +static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + struct iwm_rx_ticket_node *ticket, *next; + char *buf; + int buf_len = 4096, i; + size_t len = 0; + ssize_t ret; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { + len += snprintf(buf + len, buf_len - len, "Ticket #%d\n", + ticket->ticket->id); + len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n", + ticket->ticket->action); + len += snprintf(buf + len, buf_len - len, "\tflags: 0x%x\n", + ticket->ticket->flags); + } + + for (i = 0; i < IWM_RX_ID_HASH; i++) { + struct iwm_rx_packet *packet, *nxt; + struct list_head *pkt_list = &iwm->rx_packets[i]; + if (!list_empty(pkt_list)) { + len += snprintf(buf + len, buf_len - len, + "Packet hash #%d\n", i); + list_for_each_entry_safe(packet, nxt, pkt_list, node) { + len += snprintf(buf + len, buf_len - len, + "\tPacket id: %d\n", + packet->id); + len += snprintf(buf + len, buf_len - len, + "\tPacket length: %lu\n", + packet->pkt_size); + } + } + } + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); + kfree(buf); + + return ret; +} + + +static const struct file_operations iwm_debugfs_txq_fops = { + .owner = THIS_MODULE, + .open = iwm_txrx_open, + .read = iwm_debugfs_txq_read, +}; + +static const struct file_operations iwm_debugfs_tx_credit_fops = { + .owner = THIS_MODULE, + .open = iwm_txrx_open, + .read = iwm_debugfs_tx_credit_read, +}; + +static const struct file_operations iwm_debugfs_rx_ticket_fops = { + .owner = THIS_MODULE, + .open = iwm_txrx_open, + .read = iwm_debugfs_rx_ticket_read, +}; + +int iwm_debugfs_init(struct iwm_priv *iwm) +{ + int i, result; + char devdir[16]; + + iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + result = PTR_ERR(iwm->dbg.rootdir); + if (!result || IS_ERR(iwm->dbg.rootdir)) { + if (result == -ENODEV) { + IWM_ERR(iwm, "DebugFS (CONFIG_DEBUG_FS) not " + "enabled in kernel config\n"); + result = 0; /* No debugfs support */ + } + IWM_ERR(iwm, "Couldn't create rootdir: %d\n", result); + goto error; + } + + snprintf(devdir, sizeof(devdir), "%s", wiphy_name(iwm_to_wiphy(iwm))); + + iwm->dbg.devdir = debugfs_create_dir(devdir, iwm->dbg.rootdir); + result = PTR_ERR(iwm->dbg.devdir); + if (IS_ERR(iwm->dbg.devdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create devdir: %d\n", result); + goto error; + } + + iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.dbgdir); + if (IS_ERR(iwm->dbg.dbgdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create dbgdir: %d\n", result); + goto error; + } + + iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.rxdir); + if (IS_ERR(iwm->dbg.rxdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create rx dir: %d\n", result); + goto error; + } + + iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.txdir); + if (IS_ERR(iwm->dbg.txdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create tx dir: %d\n", result); + goto error; + } + + iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.busdir); + if (IS_ERR(iwm->dbg.busdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create bus dir: %d\n", result); + goto error; + } + + if (iwm->bus_ops->debugfs_init) { + result = iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir); + if (result < 0) { + IWM_ERR(iwm, "Couldn't create bus entry: %d\n", result); + goto error; + } + } + + + iwm->dbg.dbg_level = IWM_DL_NONE; + iwm->dbg.dbg_level_dentry = + debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm, + &fops_iwm_dbg_level); + result = PTR_ERR(iwm->dbg.dbg_level_dentry); + if (IS_ERR(iwm->dbg.dbg_level_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create dbg_level: %d\n", result); + goto error; + } + + + iwm->dbg.dbg_modules = IWM_DM_DEFAULT; + iwm->dbg.dbg_modules_dentry = + debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm, + &fops_iwm_dbg_modules); + result = PTR_ERR(iwm->dbg.dbg_modules_dentry); + if (IS_ERR(iwm->dbg.dbg_modules_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create dbg_modules: %d\n", result); + goto error; + } + + for (i = 0; i < __IWM_DM_NR; i++) + add_dbg_module(iwm->dbg, iwm_debug_module[i].name, + iwm_debug_module[i].id, IWM_DL_DEFAULT); + + iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200, + iwm->dbg.txdir, iwm, + &iwm_debugfs_txq_fops); + result = PTR_ERR(iwm->dbg.txq_dentry); + if (IS_ERR(iwm->dbg.txq_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create tx queue: %d\n", result); + goto error; + } + + iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200, + iwm->dbg.txdir, iwm, + &iwm_debugfs_tx_credit_fops); + result = PTR_ERR(iwm->dbg.tx_credit_dentry); + if (IS_ERR(iwm->dbg.tx_credit_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create tx credit: %d\n", result); + goto error; + } + + iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200, + iwm->dbg.rxdir, iwm, + &iwm_debugfs_rx_ticket_fops); + result = PTR_ERR(iwm->dbg.rx_ticket_dentry); + if (IS_ERR(iwm->dbg.rx_ticket_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create rx ticket: %d\n", result); + goto error; + } + + return 0; + + error: + return result; +} + +void iwm_debugfs_exit(struct iwm_priv *iwm) +{ + int i; + + for (i = 0; i < __IWM_DM_NR; i++) + debugfs_remove(iwm->dbg.dbg_module_dentries[i]); + + debugfs_remove(iwm->dbg.dbg_modules_dentry); + debugfs_remove(iwm->dbg.dbg_level_dentry); + debugfs_remove(iwm->dbg.txq_dentry); + debugfs_remove(iwm->dbg.tx_credit_dentry); + debugfs_remove(iwm->dbg.rx_ticket_dentry); + if (iwm->bus_ops->debugfs_exit) + iwm->bus_ops->debugfs_exit(iwm); + + debugfs_remove(iwm->dbg.busdir); + debugfs_remove(iwm->dbg.dbgdir); + debugfs_remove(iwm->dbg.txdir); + debugfs_remove(iwm->dbg.rxdir); + debugfs_remove(iwm->dbg.devdir); + debugfs_remove(iwm->dbg.rootdir); +} diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c new file mode 100644 index 0000000..0f34b84 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -0,0 +1,187 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include + +#include "iwm.h" +#include "umac.h" +#include "commands.h" +#include "eeprom.h" + +static struct iwm_eeprom_entry eeprom_map[] = { + [IWM_EEPROM_SIG] = + {"Signature", IWM_EEPROM_SIG_OFF, IWM_EEPROM_SIG_LEN}, + + [IWM_EEPROM_VERSION] = + {"Version", IWM_EEPROM_VERSION_OFF, IWM_EEPROM_VERSION_LEN}, + + [IWM_EEPROM_OEM_HW_VERSION] = + {"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF, + IWM_EEPROM_OEM_HW_VERSION_LEN}, + + [IWM_EEPROM_MAC_VERSION] = + {"MAC version", IWM_EEPROM_MAC_VERSION_OFF, IWM_EEPROM_MAC_VERSION_LEN}, + + [IWM_EEPROM_CARD_ID] = + {"Card ID", IWM_EEPROM_CARD_ID_OFF, IWM_EEPROM_CARD_ID_LEN}, + + [IWM_EEPROM_RADIO_CONF] = + {"Radio config", IWM_EEPROM_RADIO_CONF_OFF, IWM_EEPROM_RADIO_CONF_LEN}, + + [IWM_EEPROM_SKU_CAP] = + {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, + + [IWM_EEPROM_CALIB_RXIQ_OFFSET] = + {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, + + [IWM_EEPROM_CALIB_RXIQ] = + {"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN}, +}; + + +static int iwm_eeprom_read(struct iwm_priv *iwm, u8 eeprom_id) +{ + int ret; + u32 entry_size, chunk_size, data_offset = 0, addr_offset = 0; + u32 addr; + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_eeprom_proxy eeprom_cmd; + + if (eeprom_id > (IWM_EEPROM_LAST - 1)) + return -EINVAL; + + entry_size = eeprom_map[eeprom_id].length; + + if (eeprom_id >= IWM_EEPROM_INDIRECT_DATA) { + /* indirect data */ + u32 off_id = eeprom_id - IWM_EEPROM_INDIRECT_DATA + + IWM_EEPROM_INDIRECT_OFFSET; + + eeprom_map[eeprom_id].offset = + *(u16 *)(iwm->eeprom + eeprom_map[off_id].offset) << 1; + } + + addr = eeprom_map[eeprom_id].offset; + + udma_cmd.eop = 1; + udma_cmd.credit_group = 0x4; + udma_cmd.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD; + udma_cmd.lmac_offset = 0; + + umac_cmd.id = UMAC_CMD_OPCODE_EEPROM_PROXY; + umac_cmd.resp = 1; + + while (entry_size > 0) { + chunk_size = min_t(u32, entry_size, IWM_MAX_EEPROM_DATA_LEN); + + eeprom_cmd.hdr.type = + cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ); + eeprom_cmd.hdr.offset = cpu_to_le32(addr + addr_offset); + eeprom_cmd.hdr.len = cpu_to_le32(chunk_size); + + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, + &umac_cmd, &eeprom_cmd, + sizeof(struct iwm_umac_cmd_eeprom_proxy)); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't read eeprom\n"); + return ret; + } + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_EEPROM_PROXY, + IWM_SRC_UMAC, 2*HZ); + if (ret < 0) { + IWM_ERR(iwm, "Did not get any eeprom answer\n"); + return ret; + } + + data_offset += chunk_size; + addr_offset += chunk_size; + entry_size -= chunk_size; + } + + return 0; +} + +u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id) +{ + if (!iwm->eeprom) + return ERR_PTR(-ENODEV); + + return iwm->eeprom + eeprom_map[eeprom_id].offset; +} + +int iwm_eeprom_init(struct iwm_priv *iwm) +{ + int i, ret = 0; + char name[32]; + + iwm->eeprom = kzalloc(IWM_EEPROM_LEN, GFP_KERNEL); + if (!iwm->eeprom) + return -ENOMEM; + + for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET)) + break; +#endif + ret = iwm_eeprom_read(iwm, i); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", + i, eeprom_map[i].name); + break; + } + } + + IWM_DBG_BOOT(iwm, DBG, "EEPROM dump:\n"); + for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { + memset(name, 0, 32); + sprintf(name, "%s: ", eeprom_map[i].name); + + IWM_HEXDUMP(iwm, DBG, BOOT, name, + iwm->eeprom + eeprom_map[i].offset, + eeprom_map[i].length); + } + + return ret; +} + +void iwm_eeprom_exit(struct iwm_priv *iwm) +{ + kfree(iwm->eeprom); +} diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h new file mode 100644 index 0000000..cdb31a6 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h @@ -0,0 +1,114 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_EEPROM_H__ +#define __IWM_EEPROM_H__ + +enum { + IWM_EEPROM_SIG = 0, + IWM_EEPROM_FIRST = IWM_EEPROM_SIG, + IWM_EEPROM_VERSION, + IWM_EEPROM_OEM_HW_VERSION, + IWM_EEPROM_MAC_VERSION, + IWM_EEPROM_CARD_ID, + IWM_EEPROM_RADIO_CONF, + IWM_EEPROM_SKU_CAP, + + IWM_EEPROM_INDIRECT_OFFSET, + IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, + + IWM_EEPROM_INDIRECT_DATA, + IWM_EEPROM_CALIB_RXIQ = IWM_EEPROM_INDIRECT_DATA, + + IWM_EEPROM_LAST, +}; + +#define IWM_EEPROM_SIG_OFF 0x00 +#define IWM_EEPROM_VERSION_OFF (0x54 << 1) +#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) +#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) +#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) +#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) +#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) +#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) + +#define IWM_EEPROM_SIG_LEN 4 +#define IWM_EEPROM_VERSION_LEN 2 +#define IWM_EEPROM_OEM_HW_VERSION_LEN 2 +#define IWM_EEPROM_MAC_VERSION_LEN 1 +#define IWM_EEPROM_CARD_ID_LEN 2 +#define IWM_EEPROM_RADIO_CONF_LEN 2 +#define IWM_EEPROM_SKU_CAP_LEN 2 +#define IWM_EEPROM_INDIRECT_LEN 2 + +#define IWM_MAX_EEPROM_DATA_LEN 240 +#define IWM_EEPROM_LEN 0x800 + +#define IWM_EEPROM_MIN_ALLOWED_VERSION 0x0610 +#define IWM_EEPROM_MAX_ALLOWED_VERSION 0x0700 +#define IWM_EEPROM_CURRENT_VERSION 0x0612 + +#define IWM_EEPROM_SKU_CAP_BAND_24GHZ (1 << 4) +#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) +#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) + +enum { + IWM_EEPROM_CALIB_CAL_HDR, + IWM_EEPROM_CALIB_TX_POWER, + IWM_EEPROM_CALIB_XTAL, + IWM_EEPROM_CALIB_TEMPERATURE, + IWM_EEPROM_CALIB_RX_BB_FILTER, + IWM_EEPROM_CALIB_RX_IQ, + IWM_EEPROM_CALIB_MAX, +}; + +#define IWM_EEPROM_CALIB_RXIQ_OFF (IWM_EEPROM_CALIB_CONFIG_OFF + \ + (IWM_EEPROM_CALIB_RX_IQ << 1)) +#define IWM_EEPROM_CALIB_RXIQ_LEN sizeof(struct iwm_lmac_calib_rxiq) + +struct iwm_eeprom_entry { + char *name; + u32 offset; + u32 length; +}; + +int iwm_eeprom_init(struct iwm_priv *iwm); +void iwm_eeprom_exit(struct iwm_priv *iwm); +u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c new file mode 100644 index 0000000..db4ba08 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -0,0 +1,388 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "hal.h" +#include "umac.h" +#include "debug.h" +#include "fw.h" +#include "commands.h" + +static const char fw_barker[] = "*WESTOPFORNOONE*"; + +/* + * @op_code: Op code we're looking for. + * @index: There can be several instances of the same opcode within + * the firmware. Index specifies which one we're looking for. + */ +static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, + u16 op_code, u32 index) +{ + int offset = -EINVAL, fw_offset; + u32 op_index = 0; + const u8 *fw_ptr; + struct iwm_fw_hdr_rec *rec; + + fw_offset = 0; + fw_ptr = fw->data; + + /* We first need to look for the firmware barker */ + if (memcmp(fw_ptr, fw_barker, IWM_HDR_BARKER_LEN)) { + IWM_ERR(iwm, "No barker string in this FW\n"); + return -EINVAL; + } + + if (fw->size < IWM_HDR_LEN) { + IWM_ERR(iwm, "FW is too small (%d)\n", fw->size); + return -EINVAL; + } + + fw_offset += IWM_HDR_BARKER_LEN; + + while (fw_offset < fw->size) { + rec = (struct iwm_fw_hdr_rec *)(fw_ptr + fw_offset); + + IWM_DBG_FW(iwm, DBG, "FW: op_code: 0x%x, len: %d @ 0x%x\n", + rec->op_code, rec->len, fw_offset); + + if (rec->op_code == IWM_HDR_REC_OP_INVALID) { + IWM_DBG_FW(iwm, DBG, "Reached INVALID op code\n"); + break; + } + + if (rec->op_code == op_code) { + if (op_index == index) { + fw_offset += sizeof(struct iwm_fw_hdr_rec); + offset = fw_offset; + goto out; + } + op_index++; + } + + fw_offset += sizeof(struct iwm_fw_hdr_rec) + rec->len; + } + + out: + return offset; +} + +static int iwm_load_firmware_chunk(struct iwm_priv *iwm, + const struct firmware *fw, + struct iwm_fw_img_desc *img_desc) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + u32 chunk_size; + const u8 *chunk_ptr; + int ret = 0; + + IWM_DBG_FW(iwm, INFO, "Loading FW chunk: %d bytes @ 0x%x\n", + img_desc->length, img_desc->address); + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; + target_cmd.handle_by_hw = 1; + target_cmd.op2 = 0; + target_cmd.resp = 0; + target_cmd.eop = 1; + + chunk_size = img_desc->length; + chunk_ptr = fw->data + img_desc->offset; + + while (chunk_size > 0) { + u32 tmp_chunk_size; + + tmp_chunk_size = min_t(u32, chunk_size, + IWM_MAX_NONWIFI_CMD_BUFF_SIZE); + + target_cmd.addr = cpu_to_le32(img_desc->address + + (chunk_ptr - fw->data - img_desc->offset)); + target_cmd.op1_sz = cpu_to_le32(tmp_chunk_size); + + IWM_DBG_FW(iwm, DBG, "\t%d bytes @ 0x%x\n", + tmp_chunk_size, target_cmd.addr); + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, chunk_ptr); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't load FW chunk\n"); + break; + } + + chunk_size -= tmp_chunk_size; + chunk_ptr += tmp_chunk_size; + } + + return ret; +} +/* + * To load a fw image to the target, we basically go through the + * fw, looking for OP_MEM_DESC records. Once we found one, we + * pass it to iwm_load_firmware_chunk(). + * The OP_MEM_DESC records contain the actuall memory chunk to be + * sent, but also the destination address. + */ +static int iwm_load_img(struct iwm_priv *iwm, const char *img_name) +{ + const struct firmware *fw; + struct iwm_fw_img_desc *img_desc; + struct iwm_fw_img_ver *ver; + int ret = 0, fw_offset; + u32 opcode_idx = 0, build_date; + char *build_tag; + + ret = request_firmware(&fw, img_name, iwm_to_dev(iwm)); + if (ret) { + IWM_ERR(iwm, "Request firmware failed"); + return ret; + } + + IWM_DBG_FW(iwm, INFO, "Start to load FW %s\n", img_name); + + while (1) { + fw_offset = iwm_fw_op_offset(iwm, fw, + IWM_HDR_REC_OP_MEM_DESC, + opcode_idx); + if (fw_offset < 0) + break; + + img_desc = (struct iwm_fw_img_desc *)(fw->data + fw_offset); + ret = iwm_load_firmware_chunk(iwm, fw, img_desc); + if (ret < 0) + goto err_release_fw; + opcode_idx++; + }; + + /* Read firmware version */ + fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0); + if (fw_offset < 0) + goto err_release_fw; + + ver = (struct iwm_fw_img_ver *)(fw->data + fw_offset); + + /* Read build tag */ + fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_TAG, 0); + if (fw_offset < 0) + goto err_release_fw; + + build_tag = (char *)(fw->data + fw_offset); + + /* Read build date */ + fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_DATE, 0); + if (fw_offset < 0) + goto err_release_fw; + + build_date = *(u32 *)(fw->data + fw_offset); + + IWM_INFO(iwm, "%s:\n", img_name); + IWM_INFO(iwm, "\tVersion: %02X.%02X\n", ver->major, ver->minor); + IWM_INFO(iwm, "\tBuild tag: %s\n", build_tag); + IWM_INFO(iwm, "\tBuild date: %x-%x-%x\n", + IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), + IWM_BUILD_DAY(build_date)); + + + err_release_fw: + release_firmware(fw); + + return ret; +} + +static int iwm_load_umac(struct iwm_priv *iwm) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + int ret; + + ret = iwm_load_img(iwm, iwm->bus_ops->umac_name); + if (ret < 0) + return ret; + + /* We've loaded the UMAC, we can tell the target to jump there */ + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_JUMP; + target_cmd.addr = cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR); + target_cmd.op1_sz = 0; + target_cmd.op2 = 0; + target_cmd.handle_by_hw = 0; + target_cmd.resp = 1 ; + target_cmd.eop = 1; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); + if (ret < 0) + IWM_ERR(iwm, "Couldn't send JMP command\n"); + + return ret; +} + +static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) +{ + int ret; + + ret = iwm_load_img(iwm, img_name); + if (ret < 0) + return ret; + + return iwm_send_umac_reset(iwm, + cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0); +} + +/* + * We currently have to load 3 FWs: + * 1) The UMAC (Upper MAC). + * 2) The calibration LMAC (Lower MAC). + * We then send the calibration init command, so that the device can + * run a first calibration round. + * 3) The operational LMAC, which replaces the calibration one when it's + * done with the first calibration round. + * + * Once those 3 FWs have been loaded, we send the periodic calibration + * command, and then the device is available for regular 802.11 operations. + */ +int iwm_load_fw(struct iwm_priv *iwm) +{ + int ret; + + /* We first start downloading the UMAC */ + ret = iwm_load_umac(iwm); + if (ret < 0) { + IWM_ERR(iwm, "UMAC loading failed\n"); + return ret; + } + + /* Handle UMAC_ALIVE notification */ + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_ALIVE, IWM_SRC_UMAC, + WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Handle UMAC_ALIVE failed: %d\n", ret); + return ret; + } + + /* UMAC is alive, we can download the calibration LMAC */ + ret = iwm_load_lmac(iwm, iwm->bus_ops->calib_lmac_name); + if (ret) { + IWM_ERR(iwm, "Calibration LMAC loading failed\n"); + return ret; + } + + /* Handle UMAC_INIT_COMPLETE notification */ + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Handle INIT_COMPLETE failed for calibration " + "LMAC: %d\n", ret); + return ret; + } + + /* Read EEPROM data */ + ret = iwm_eeprom_init(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't init eeprom array\n"); + return ret; + } + +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (iwm->conf.hw_b0) { + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map); + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, + &iwm->conf.periodic_calib_map); + } +#endif + /* Read RX IQ calibration result from EEPROM */ + if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) { + iwm_store_rxiq_calib_result(iwm); + set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); + } + + iwm_send_prio_table(iwm); + iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map); + + while (iwm->calib_done_map != iwm->conf.init_calib_map) { + ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, + IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for calibration result timeout\n"); + goto out; + } + IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " + "0x%lx, requested calibrations: 0x%lx\n", + iwm->calib_done_map, iwm->conf.init_calib_map); + } + + /* Handle LMAC CALIBRATION_COMPLETE notification */ + ret = iwm_notif_handle(iwm, CALIBRATION_COMPLETE_NOTIFICATION, + IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for CALIBRATION_COMPLETE timeout\n"); + goto out; + } + + IWM_INFO(iwm, "LMAC calibration done: 0x%lx\n", iwm->calib_done_map); + + iwm_send_umac_reset(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET), 1); + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, + WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); + goto out; + } + + /* Download the operational LMAC */ + ret = iwm_load_lmac(iwm, iwm->bus_ops->lmac_name); + if (ret) { + IWM_ERR(iwm, "LMAC loading failed\n"); + goto out; + } + + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret); + goto out; + } + + iwm_send_prio_table(iwm); + iwm_send_calib_results(iwm); + iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map); + + return 0; + + out: + iwm_eeprom_exit(iwm); + return ret; +} diff --git a/drivers/net/wireless/iwmc3200wifi/fw.h b/drivers/net/wireless/iwmc3200wifi/fw.h new file mode 100644 index 0000000..c70a3b4 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/fw.h @@ -0,0 +1,100 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_FW_H__ +#define __IWM_FW_H__ + +/** + * struct iwm_fw_hdr_rec - An iwm firmware image is a + * concatenation of various records. Each of them is + * defined by an ID (aka op code), a length, and the + * actual data. + * @op_code: The record ID, see IWM_HDR_REC_OP_* + * + * @len: The record payload length + * + * @buf: The record payload + */ +struct iwm_fw_hdr_rec { + u16 op_code; + u16 len; + u8 buf[0]; +}; + +/* Header's definitions */ +#define IWM_HDR_LEN (512) +#define IWM_HDR_BARKER_LEN (16) + +/* Header's opcodes */ +#define IWM_HDR_REC_OP_INVALID (0x00) +#define IWM_HDR_REC_OP_BUILD_DATE (0x01) +#define IWM_HDR_REC_OP_BUILD_TAG (0x02) +#define IWM_HDR_REC_OP_SW_VER (0x03) +#define IWM_HDR_REC_OP_HW_SKU (0x04) +#define IWM_HDR_REC_OP_BUILD_OPT (0x05) +#define IWM_HDR_REC_OP_MEM_DESC (0x06) +#define IWM_HDR_REC_USERDEFS (0x07) + +/* Header's records length (in bytes) */ +#define IWM_HDR_REC_LEN_BUILD_DATE (4) +#define IWM_HDR_REC_LEN_BUILD_TAG (64) +#define IWM_HDR_REC_LEN_SW_VER (4) +#define IWM_HDR_REC_LEN_HW_SKU (4) +#define IWM_HDR_REC_LEN_BUILD_OPT (4) +#define IWM_HDR_REC_LEN_MEM_DESC (12) +#define IWM_HDR_REC_LEN_USERDEF (64) + +#define IWM_BUILD_YEAR(date) ((date >> 16) & 0xffff) +#define IWM_BUILD_MONTH(date) ((date >> 8) & 0xff) +#define IWM_BUILD_DAY(date) (date & 0xff) + +struct iwm_fw_img_desc { + u32 offset; + u32 address; + u32 length; +}; + +struct iwm_fw_img_ver { + u8 minor; + u8 major; + u16 reserved; +}; + +int iwm_load_fw(struct iwm_priv *iwm); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c new file mode 100644 index 0000000..ee127fe4 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/hal.c @@ -0,0 +1,464 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +/* + * Hardware Abstraction Layer for iwm. + * + * This file mostly defines an abstraction API for + * sending various commands to the target. + * + * We have 2 types of commands: wifi and non-wifi ones. + * + * - wifi commands: + * They are used for sending LMAC and UMAC commands, + * and thus are the most commonly used ones. + * There are 2 different wifi command types, the regular + * one and the LMAC one. The former is used to send + * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h) + * while the latter is used for sending commands to the + * LMAC. If you look at LMAC commands you'll se that they + * are actually regular iwlwifi target commands encapsulated + * into a special UMAC command called UMAC passthrough. + * This is due to the fact the the host talks exclusively + * to the UMAC and so there needs to be a special UMAC + * command for talking to the LMAC. + * This is how a wifi command is layed out: + * ------------------------ + * | iwm_udma_out_wifi_hdr | + * ------------------------ + * | SW meta_data (32 bits) | + * ------------------------ + * | iwm_dev_cmd_hdr | + * ------------------------ + * | payload | + * | .... | + * + * - non-wifi, or general commands: + * Those commands are handled by the device's bootrom, + * and are typically sent when the UMAC and the LMAC + * are not yet available. + * * This is how a non-wifi command is layed out: + * --------------------------- + * | iwm_udma_out_nonwifi_hdr | + * --------------------------- + * | payload | + * | .... | + + * + * All the commands start with a UDMA header, which is + * basically a 32 bits field. The 4 LSB there define + * an opcode that allows the target to differentiate + * between wifi (opcode is 0xf) and non-wifi commands + * (opcode is [0..0xe]). + * + * When a command (wifi or non-wifi) is supposed to receive + * an answer, we queue the command buffer. When we do receive + * a command response from the UMAC, we go through the list + * of pending command, and pass both the command and the answer + * to the rx handler. Each command is sent with a unique + * sequence id, and the answer is sent with the same one. This + * is how we're supposed to match an answer with its command. + * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi() + * for the implementation details. + */ +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "hal.h" +#include "umac.h" +#include "debug.h" + +static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, + struct iwm_nonwifi_cmd *cmd, + struct iwm_udma_nonwifi_cmd *udma_cmd) +{ + INIT_LIST_HEAD(&cmd->pending); + + spin_lock(&iwm->cmd_lock); + + cmd->resp_received = 0; + + cmd->seq_num = iwm->nonwifi_seq_num; + udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); + + cmd->seq_num = iwm->nonwifi_seq_num++; + iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; + + if (udma_cmd->resp) + list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd); + + spin_unlock(&iwm->cmd_lock); + + cmd->buf.start = cmd->buf.payload; + cmd->buf.len = 0; + + memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); +} + +u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) +{ + u16 seq_num = iwm->wifi_seq_num; + + iwm->wifi_seq_num++; + iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX; + + return seq_num; +} + +static void iwm_wifi_cmd_init(struct iwm_priv *iwm, + struct iwm_wifi_cmd *cmd, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + struct iwm_lmac_cmd *lmac_cmd, + u16 payload_size) +{ + INIT_LIST_HEAD(&cmd->pending); + + spin_lock(&iwm->cmd_lock); + + cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm); + umac_cmd->seq_num = cpu_to_le16(cmd->seq_num); + + if (umac_cmd->resp) + list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd); + + spin_unlock(&iwm->cmd_lock); + + cmd->buf.start = cmd->buf.payload; + cmd->buf.len = 0; + + if (lmac_cmd) { + cmd->buf.start -= sizeof(struct iwm_lmac_hdr); + + lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num); + lmac_cmd->count = cpu_to_le16(payload_size); + + memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd)); + + umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr)); + } else + umac_cmd->count = 0; + + umac_cmd->count = cpu_to_le16(payload_size + + le16_to_cpu(umac_cmd->count)); + udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) + + le16_to_cpu(umac_cmd->count)); + + memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); + memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd)); +} + +void iwm_cmd_flush(struct iwm_priv *iwm) +{ + struct iwm_wifi_cmd *wcmd, *wnext; + struct iwm_nonwifi_cmd *nwcmd, *nwnext; + + list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) { + list_del(&wcmd->pending); + kfree(wcmd); + } + + list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd, + pending) { + list_del(&nwcmd->pending); + kfree(nwcmd); + } +} + +struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num) +{ + struct iwm_wifi_cmd *cmd, *next; + + list_for_each_entry_safe(cmd, next, &iwm->wifi_pending_cmd, pending) + if (cmd->seq_num == seq_num) { + list_del(&cmd->pending); + return cmd; + } + + return NULL; +} + +struct iwm_nonwifi_cmd * +iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, u8 seq_num, u8 cmd_opcode) +{ + struct iwm_nonwifi_cmd *cmd, *next; + + list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending) + if ((cmd->seq_num == seq_num) && + (cmd->udma_cmd.opcode == cmd_opcode) && + (cmd->resp_received)) { + list_del(&cmd->pending); + return cmd; + } + + return NULL; +} + +static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm, + struct iwm_udma_out_nonwifi_hdr *hdr, + struct iwm_udma_nonwifi_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode); + SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1); + SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW, + cmd->handle_by_hw); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); + SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM, + le16_to_cpu(cmd->seq_num)); + + hdr->addr = cmd->addr; + hdr->op1_sz = cmd->op1_sz; + hdr->op2 = cmd->op2; +} + +static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm, + struct iwm_nonwifi_cmd *cmd) +{ + struct iwm_udma_out_nonwifi_hdr *udma_hdr; + struct iwm_nonwifi_cmd_buff *buf; + struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd; + + buf = &cmd->buf; + + buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr); + buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr); + + udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start); + + iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd); + + IWM_DBG_CMD(iwm, DBG, + "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, " + "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, " + "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp, + udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr, + udma_cmd->op1_sz, udma_cmd->op2); + + return iwm_bus_send_chunk(iwm, buf->start, buf->len); +} + +void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop) +{ + struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf; + + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop); +} + +void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, + struct iwm_udma_out_wifi_hdr *hdr, + struct iwm_udma_wifi_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); + + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT, + le16_to_cpu(cmd->count)); + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group); + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid); + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset); +} + +void iwm_build_umac_hdr(struct iwm_priv *iwm, + struct iwm_umac_fw_cmd_hdr *hdr, + struct iwm_umac_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT, + le16_to_cpu(cmd->count)); + SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color); + SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp); + + hdr->cmd.cmd = cmd->id; + hdr->cmd.seq_num = cmd->seq_num; +} + +static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_wifi_out_hdr *umac_hdr; + struct iwm_wifi_cmd_buff *buf; + struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd; + struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd; + int ret; + + buf = &cmd->buf; + + buf->start -= sizeof(struct iwm_umac_wifi_out_hdr); + buf->len += sizeof(struct iwm_umac_wifi_out_hdr); + + umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start); + + iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd); + iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd); + + IWM_DBG_CMD(iwm, DBG, + "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, " + "eop = 0x%x, count = 0x%x, credit_group = 0x%x, " + "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n", + UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id, + udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group, + udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num); + + if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH) + IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n", + cmd->lmac_cmd.id); + + ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len); + + /* We keep sending UMAC reset regardless of the command credits. + * The UMAC is supposed to be reset anyway and the Tx credits are + * reinitialized afterwards. If we are lucky, the reset could + * still be done even though we have run out of credits for the + * command pool at this moment.*/ + if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) { + IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n", + umac_cmd->id); + return ret; + } + + return iwm_bus_send_chunk(iwm, buf->start, buf->len); +} + +/* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */ +int iwm_hal_send_target_cmd(struct iwm_priv *iwm, + struct iwm_udma_nonwifi_cmd *udma_cmd, + const void *payload) +{ + struct iwm_nonwifi_cmd *cmd; + int ret; + + cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); + if (!cmd) { + IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n"); + return -ENOMEM; + } + + iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); + + if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || + cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { + cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz); + memcpy(&cmd->buf.payload, payload, cmd->buf.len); + } + + ret = iwm_send_udma_nonwifi_cmd(iwm, cmd); + + if (!udma_cmd->resp) + kfree(cmd); + + if (ret < 0) + return ret; + + return cmd->seq_num; +} + +static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, + struct iwm_lmac_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + hdr->id = cmd->id; + hdr->flags = 0; /* Is this ever used? */ + hdr->seq_num = cmd->seq_num; +} + +/* + * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC. + * Sending command to the LMAC is equivalent to sending a + * regular UMAC command with the LMAC passtrough or the LMAC + * wrapper UMAC command IDs. + */ +int iwm_hal_send_host_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + struct iwm_lmac_cmd *lmac_cmd, + const void *payload, u16 payload_size) +{ + struct iwm_wifi_cmd *cmd; + struct iwm_lmac_hdr *hdr; + int lmac_hdr_len = 0; + int ret; + + cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL); + if (!cmd) { + IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n"); + return -ENOMEM; + } + + iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size); + + if (lmac_cmd) { + hdr = (struct iwm_lmac_hdr *)(cmd->buf.start); + + iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd); + lmac_hdr_len = sizeof(struct iwm_lmac_hdr); + } + + memcpy(cmd->buf.payload, payload, payload_size); + cmd->buf.len = le16_to_cpu(umac_cmd->count); + + ret = iwm_send_udma_wifi_cmd(iwm, cmd); + + /* We free the cmd if we're not expecting any response */ + if (!umac_cmd->resp) + kfree(cmd); + return ret; +} + +/* + * iwm_hal_send_umac_cmd(): This is a special case for + * iwm_hal_send_host_cmd() to send direct UMAC cmd (without + * LMAC involved). + */ +int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + const void *payload, u16 payload_size) +{ + return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL, + payload, payload_size); +} diff --git a/drivers/net/wireless/iwmc3200wifi/hal.h b/drivers/net/wireless/iwmc3200wifi/hal.h new file mode 100644 index 0000000..0adfdc8 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/hal.h @@ -0,0 +1,236 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef _IWM_HAL_H_ +#define _IWM_HAL_H_ + +#include "umac.h" + +#define GET_VAL8(s, name) ((s >> name##_POS) & name##_SEED) +#define GET_VAL16(s, name) ((le16_to_cpu(s) >> name##_POS) & name##_SEED) +#define GET_VAL32(s, name) ((le32_to_cpu(s) >> name##_POS) & name##_SEED) + +#define SET_VAL8(s, name, val) \ +do { \ + s = (s & ~(name##_SEED << name##_POS)) | \ + ((val & name##_SEED) << name##_POS); \ +} while (0) + +#define SET_VAL16(s, name, val) \ +do { \ + s = cpu_to_le16((le16_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ + ((val & name##_SEED) << name##_POS)); \ +} while (0) + +#define SET_VAL32(s, name, val) \ +do { \ + s = cpu_to_le32((le32_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ + ((val & name##_SEED) << name##_POS)); \ +} while (0) + + +#define UDMA_UMAC_INIT { .eop = 1, \ + .credit_group = 0x4, \ + .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ + .lmac_offset = 0 } +#define UDMA_LMAC_INIT { .eop = 1, \ + .credit_group = 0x4, \ + .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ + .lmac_offset = 4 } + + +/* UDMA IN OP CODE -- cmd bits [3:0] */ +#define UDMA_IN_OPCODE_MASK 0xF + +#define UDMA_IN_OPCODE_GENERAL_RESP 0x0 +#define UDMA_IN_OPCODE_READ_RESP 0x1 +#define UDMA_IN_OPCODE_WRITE_RESP 0x2 +#define UDMA_IN_OPCODE_PERS_WRITE_RESP 0x5 +#define UDMA_IN_OPCODE_PERS_READ_RESP 0x6 +#define UDMA_IN_OPCODE_RD_MDFY_WR_RESP 0x7 +#define UDMA_IN_OPCODE_EP_MNGMT_MSG 0x8 +#define UDMA_IN_OPCODE_CRDT_CHNG_MSG 0x9 +#define UDMA_IN_OPCODE_CNTRL_DATABASE_MSG 0xA +#define UDMA_IN_OPCODE_SW_MSG 0xB +#define UDMA_IN_OPCODE_WIFI 0xF +#define UDMA_IN_OPCODE_WIFI_LMAC 0x1F +#define UDMA_IN_OPCODE_WIFI_UMAC 0x2F + +/* HW API: udma_hdi_nonwifi API (OUT and IN) */ + +/* iwm_udma_nonwifi_cmd request response -- bits [9:9] */ +#define UDMA_HDI_OUT_NW_CMD_RESP_POS 9 +#define UDMA_HDI_OUT_NW_CMD_RESP_SEED 0x1 + +/* iwm_udma_nonwifi_cmd handle by HW -- bits [11:11] */ +#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_POS 11 +#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_SEED 0x1 + +/* iwm_udma_nonwifi_cmd sequence-number -- bits [12:15] */ +#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_POS 12 +#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_SEED 0xF + +/* UDMA IN Non-WIFI HW sequence number -- bits [12:15] */ +#define UDMA_IN_NW_HW_SEQ_NUM_POS 12 +#define UDMA_IN_NW_HW_SEQ_NUM_SEED 0xF + +/* UDMA IN Non-WIFI HW signature -- bits [16:31] */ +#define UDMA_IN_NW_HW_SIG_POS 16 +#define UDMA_IN_NW_HW_SIG_SEED 0xFFFF + +/* fixed signature */ +#define UDMA_IN_NW_HW_SIG 0xCBBC + +/* UDMA IN Non-WIFI HW block length -- bits [32:35] */ +#define UDMA_IN_NW_HW_LENGTH_SEED 0xF +#define UDMA_IN_NW_HW_LENGTH_POS 32 + +/* End of HW API: udma_hdi_nonwifi API (OUT and IN) */ + +#define IWM_SDIO_FW_MAX_CHUNK_SIZE 2032 +#define IWM_MAX_WIFI_HEADERS_SIZE 32 +#define IWM_MAX_NONWIFI_HEADERS_SIZE 16 +#define IWM_MAX_NONWIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ + IWM_MAX_NONWIFI_HEADERS_SIZE) +#define IWM_MAX_WIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ + IWM_MAX_WIFI_HEADERS_SIZE) + +#define IWM_HAL_CONCATENATE_BUF_SIZE 8192 + +struct iwm_wifi_cmd_buff { + u16 len; + u8 *start; + u8 hdr[IWM_MAX_WIFI_HEADERS_SIZE]; + u8 payload[IWM_MAX_WIFI_CMD_BUFF_SIZE]; +}; + +struct iwm_nonwifi_cmd_buff { + u16 len; + u8 *start; + u8 hdr[IWM_MAX_NONWIFI_HEADERS_SIZE]; + u8 payload[IWM_MAX_NONWIFI_CMD_BUFF_SIZE]; +}; + +struct iwm_udma_nonwifi_cmd { + u8 opcode; + u8 eop; + u8 resp; + u8 handle_by_hw; + __le32 addr; + __le32 op1_sz; + __le32 op2; + __le16 seq_num; +}; + +struct iwm_udma_wifi_cmd { + __le16 count; + u8 eop; + u8 credit_group; + u8 ra_tid; + u8 lmac_offset; +}; + +struct iwm_umac_cmd { + u8 id; + __le16 count; + u8 resp; + __le16 seq_num; + u8 color; +}; + +struct iwm_lmac_cmd { + u8 id; + __le16 count; + u8 resp; + __le16 seq_num; +}; + +struct iwm_nonwifi_cmd { + u16 seq_num; + bool resp_received; + struct list_head pending; + struct iwm_udma_nonwifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_lmac_cmd lmac_cmd; + struct iwm_nonwifi_cmd_buff buf; + u32 flags; +}; + +struct iwm_wifi_cmd { + u16 seq_num; + struct list_head pending; + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_lmac_cmd lmac_cmd; + struct iwm_wifi_cmd_buff buf; + u32 flags; +}; + +void iwm_cmd_flush(struct iwm_priv *iwm); + +struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, + u16 seq_num); +struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, + u8 seq_num, u8 cmd_opcode); + + +int iwm_hal_send_target_cmd(struct iwm_priv *iwm, + struct iwm_udma_nonwifi_cmd *ucmd, + const void *payload); + +int iwm_hal_send_host_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + struct iwm_lmac_cmd *lmac_cmd, + const void *payload, u16 payload_size); + +int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + const void *payload, u16 payload_size); + +u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm); + +void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop); +void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, + struct iwm_udma_out_wifi_hdr *hdr, + struct iwm_udma_wifi_cmd *cmd); +void iwm_build_umac_hdr(struct iwm_priv *iwm, + struct iwm_umac_fw_cmd_hdr *hdr, + struct iwm_umac_cmd *cmd); +#endif /* _IWM_HAL_H_ */ diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h new file mode 100644 index 0000000..3b29681 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -0,0 +1,350 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_H__ +#define __IWM_H__ + +#include +#include +#include + +#include "debug.h" +#include "hal.h" +#include "umac.h" +#include "lmac.h" +#include "eeprom.h" + +#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" +#define IWM_AUTHOR "" + +#define CONFIG_IWM_B0_HW_SUPPORT 1 + +#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX +#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA +#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW +#define IWM_SRC_NUM 3 + +#define IWM_POWER_INDEX_MIN 0 +#define IWM_POWER_INDEX_MAX 5 +#define IWM_POWER_INDEX_DEFAULT 3 + +struct iwm_conf { + u32 sdio_ior_timeout; + unsigned long init_calib_map; + unsigned long periodic_calib_map; + bool reset_on_fatal_err; + bool auto_connect; + bool wimax_not_present; + bool enable_qos; + u32 mode; + + u32 power_index; + u32 frag_threshold; + u32 rts_threshold; + bool cts_to_self; + + u32 assoc_timeout; + u32 roam_timeout; + u32 wireless_mode; + u32 coexist_mode; + + u8 ibss_band; + u8 ibss_channel; + + u8 mac_addr[ETH_ALEN]; +#ifdef CONFIG_IWM_B0_HW_SUPPORT + bool hw_b0; +#endif +}; + +enum { + COEX_MODE_SA = 1, + COEX_MODE_XOR, + COEX_MODE_CM, + COEX_MODE_MAX, +}; + +struct iwm_if_ops; +struct iwm_wifi_cmd; + +struct pool_entry { + int id; /* group id */ + int sid; /* super group id */ + int min_pages; /* min capacity in pages */ + int max_pages; /* max capacity in pages */ + int alloc_pages; /* allocated # of pages. incresed by driver */ + int total_freed_pages; /* total freed # of pages. incresed by UMAC */ +}; + +struct spool_entry { + int id; + int max_pages; + int alloc_pages; +}; + +struct iwm_tx_credit { + spinlock_t lock; + int pool_nr; + unsigned long full_pools_map; /* bitmap for # of filled tx pools */ + struct pool_entry pools[IWM_MACS_OUT_GROUPS]; + struct spool_entry spools[IWM_MACS_OUT_SGROUPS]; +}; + +struct iwm_notif { + struct list_head pending; + u32 cmd_id; + void *cmd; + u8 src; + void *buf; + unsigned long buf_size; +}; + +struct iwm_sta_info { + u8 addr[ETH_ALEN]; + bool valid; + bool qos; + u8 color; +}; + +struct iwm_tx_info { + u8 sta; + u8 color; + u8 tid; +}; + +struct iwm_rx_info { + unsigned long rx_size; + unsigned long rx_buf_size; +}; + +#define IWM_NUM_KEYS 4 + +struct iwm_umac_key_hdr { + u8 mac[ETH_ALEN]; + u8 key_idx; + u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */ +} __attribute__ ((packed)); + +struct iwm_key { + struct iwm_umac_key_hdr hdr; + u8 in_use; + u8 alg; + u32 flags; + u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; + u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; + u8 key_len; + u8 key[32]; +}; + +#define IWM_RX_ID_HASH 0xff +#define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH) + +#define IWM_STA_TABLE_NUM 16 +#define IWM_TX_LIST_SIZE 64 +#define IWM_RX_LIST_SIZE 256 + +#define IWM_SCAN_ID_MAX 0xff + +#define IWM_STATUS_READY 0 +#define IWM_STATUS_SCANNING 1 +#define IWM_STATUS_SCAN_ABORTING 2 +#define IWM_STATUS_ASSOCIATING 3 +#define IWM_STATUS_ASSOCIATED 4 + +#define IWM_RADIO_RFKILL_OFF 0 +#define IWM_RADIO_RFKILL_HW 1 +#define IWM_RADIO_RFKILL_SW 2 + +struct iwm_tx_queue { + int id; + struct sk_buff_head queue; + struct workqueue_struct *wq; + struct work_struct worker; + u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; + int concat_count; + u8 *concat_ptr; +}; + +/* Queues 0 ~ 3 for AC data, 5 for iPAN */ +#define IWM_TX_QUEUES 5 +#define IWM_TX_DATA_QUEUES 4 +#define IWM_TX_CMD_QUEUE 4 + +struct iwm_bss_info { + struct list_head node; + struct cfg80211_bss *cfg_bss; + struct iwm_umac_notif_bss_info *bss; +}; + +typedef int (*iwm_handler)(struct iwm_priv *priv, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd); + +#define IWM_WATCHDOG_PERIOD (6 * HZ) + +struct iwm_priv { + struct wireless_dev *wdev; + struct iwm_if_ops *bus_ops; + + struct iwm_conf conf; + + unsigned long status; + unsigned long radio; + + struct list_head pending_notif; + wait_queue_head_t notif_queue; + + wait_queue_head_t nonwifi_queue; + + unsigned long calib_done_map; + struct { + u8 *buf; + u32 size; + } calib_res[CALIBRATION_CMD_NUM]; + + struct iwm_umac_profile *umac_profile; + bool umac_profile_active; + + u8 bssid[ETH_ALEN]; + u8 channel; + u16 rate; + + struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; + struct list_head bss_list; + + void (*nonwifi_rx_handlers[UMAC_HDI_IN_OPCODE_NONWIFI_MAX]) + (struct iwm_priv *priv, u8 *buf, unsigned long buf_size); + + const iwm_handler *umac_handlers; + const iwm_handler *lmac_handlers; + DECLARE_BITMAP(lmac_handler_map, LMAC_COMMAND_ID_NUM); + DECLARE_BITMAP(umac_handler_map, LMAC_COMMAND_ID_NUM); + DECLARE_BITMAP(udma_handler_map, LMAC_COMMAND_ID_NUM); + + struct list_head wifi_pending_cmd; + struct list_head nonwifi_pending_cmd; + u16 wifi_seq_num; + u8 nonwifi_seq_num; + spinlock_t cmd_lock; + + u32 core_enabled; + + u8 scan_id; + struct cfg80211_scan_request *scan_request; + + struct sk_buff_head rx_list; + struct list_head rx_tickets; + struct list_head rx_packets[IWM_RX_ID_HASH]; + struct workqueue_struct *rx_wq; + struct work_struct rx_worker; + + struct iwm_tx_credit tx_credit; + struct iwm_tx_queue txq[IWM_TX_QUEUES]; + + struct iwm_key keys[IWM_NUM_KEYS]; + struct iwm_key *default_key; + + wait_queue_head_t mlme_queue; + + struct iw_statistics wstats; + struct delayed_work stats_request; + + struct iwm_debugfs dbg; + + u8 *eeprom; + struct timer_list watchdog; + struct work_struct reset_worker; + struct rfkill *rfkill; + + char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +static inline void *iwm_private(struct iwm_priv *iwm) +{ + BUG_ON(!iwm); + return &iwm->private; +} + +#define hw_to_iwm(h) (h->iwm) +#define iwm_to_dev(i) (wiphy_dev(i->wdev->wiphy)) +#define iwm_to_wiphy(i) (i->wdev->wiphy) +#define wiphy_to_iwm(w) (struct iwm_priv *)(wiphy_priv(w)) +#define iwm_to_wdev(i) (i->wdev) +#define wdev_to_iwm(w) (struct iwm_priv *)(wdev_priv(w)) +#define iwm_to_ndev(i) (i->wdev->netdev) +#define ndev_to_iwm(n) (wdev_to_iwm(n->ieee80211_ptr)) +#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) +#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) + +extern const struct iw_handler_def iwm_iw_handler_def; + +void *iwm_if_alloc(int sizeof_bus, struct device *dev, + struct iwm_if_ops *if_ops); +void iwm_if_free(struct iwm_priv *iwm); +int iwm_mode_to_nl80211_iftype(int mode); +int iwm_priv_init(struct iwm_priv *iwm); +void iwm_reset(struct iwm_priv *iwm); +void iwm_tx_credit_init_pools(struct iwm_priv *iwm, + struct iwm_umac_notif_alive *alive); +int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb); +int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, + u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size); +int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout); +void iwm_init_default_profile(struct iwm_priv *iwm, + struct iwm_umac_profile *profile); +void iwm_link_on(struct iwm_priv *iwm); +void iwm_link_off(struct iwm_priv *iwm); +int iwm_up(struct iwm_priv *iwm); +int iwm_down(struct iwm_priv *iwm); + +/* TX API */ +void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); +void iwm_tx_worker(struct work_struct *work); +int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); + +/* RX API */ +void iwm_rx_setup_handlers(struct iwm_priv *iwm); +int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size); +int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, + struct iwm_wifi_cmd *cmd); +void iwm_rx_free(struct iwm_priv *iwm); + +/* RF Kill API */ +int iwm_rfkill_init(struct iwm_priv *iwm); +void iwm_rfkill_exit(struct iwm_priv *iwm); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h new file mode 100644 index 0000000..db2e5ee --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -0,0 +1,457 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_LMAC_H__ +#define __IWM_LMAC_H__ + +struct iwm_lmac_hdr { + u8 id; + u8 flags; + __le16 seq_num; +} __attribute__ ((packed)); + +/* LMAC commands */ +#define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1 + +struct iwm_lmac_cal_cfg_elt { + __le32 enable; /* 1 means LMAC needs to do something */ + __le32 start; /* 1 to start calibration, 0 to stop */ + __le32 send_res; /* 1 for sending back results */ + __le32 apply_res; /* 1 for applying calibration results to HW */ + __le32 reserved; +} __attribute__ ((packed)); + +struct iwm_lmac_cal_cfg_status { + struct iwm_lmac_cal_cfg_elt init; + struct iwm_lmac_cal_cfg_elt periodic; + __le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */ +} __attribute__ ((packed)); + +struct iwm_lmac_cal_cfg_cmd { + struct iwm_lmac_cal_cfg_status ucode_cfg; + struct iwm_lmac_cal_cfg_status driver_cfg; + __le32 reserved; +} __attribute__ ((packed)); + +struct iwm_lmac_cal_cfg_resp { + __le32 status; +} __attribute__ ((packed)); + +#define IWM_CARD_STATE_SW_HW_ENABLED 0x00 +#define IWM_CARD_STATE_HW_DISABLED 0x01 +#define IWM_CARD_STATE_SW_DISABLED 0x02 +#define IWM_CARD_STATE_CTKILL_DISABLED 0x04 +#define IWM_CARD_STATE_IS_RXON 0x10 + +struct iwm_lmac_card_state { + __le32 flags; +} __attribute__ ((packed)); + +/** + * COEX_PRIORITY_TABLE_CMD + * + * Priority entry for each state + * Will keep two tables, for STA and WIPAN + */ +enum { + /* UN-ASSOCIATION PART */ + COEX_UNASSOC_IDLE = 0, + COEX_UNASSOC_MANUAL_SCAN, + COEX_UNASSOC_AUTO_SCAN, + + /* CALIBRATION */ + COEX_CALIBRATION, + COEX_PERIODIC_CALIBRATION, + + /* CONNECTION */ + COEX_CONNECTION_ESTAB, + + /* ASSOCIATION PART */ + COEX_ASSOCIATED_IDLE, + COEX_ASSOC_MANUAL_SCAN, + COEX_ASSOC_AUTO_SCAN, + COEX_ASSOC_ACTIVE_LEVEL, + + /* RF ON/OFF */ + COEX_RF_ON, + COEX_RF_OFF, + COEX_STAND_ALONE_DEBUG, + + /* IPNN */ + COEX_IPAN_ASSOC_LEVEL, + + /* RESERVED */ + COEX_RSRVD1, + COEX_RSRVD2, + + COEX_EVENTS_NUM +}; + +#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK 0x1 +#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK 0x2 +#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK 0x4 + +struct coex_event { + u8 req_prio; + u8 win_med_prio; + u8 reserved; + u8 flags; +} __attribute__ ((packed)); + +#define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1 +#define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4 +#define COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK 0x8 +#define COEX_FLAGS_COEX_ENABLE_MSK 0x80 + +struct iwm_coex_prio_table_cmd { + u8 flags; + u8 reserved[3]; + struct coex_event sta_prio[COEX_EVENTS_NUM]; +} __attribute__ ((packed)); + +/* Coexistence definitions + * + * Constants to fill in the Priorities' Tables + * RP - Requested Priority + * WP - Win Medium Priority: priority assigned when the contention has been won + * FLAGS - Combination of COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK and + * COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK + */ + +#define COEX_UNASSOC_IDLE_FLAGS 0 +#define COEX_UNASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_UNASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_CALIBRATION_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_PERIODIC_CALIBRATION_FLAGS 0 +/* COEX_CONNECTION_ESTAB: we need DELAY_MEDIUM_FREE_NTFY to let WiMAX + * disconnect from network. */ +#define COEX_CONNECTION_ESTAB_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) +#define COEX_ASSOCIATED_IDLE_FLAGS 0 +#define COEX_ASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_ASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0 +#define COEX_RF_ON_FLAGS 0 +#define COEX_RF_OFF_FLAGS 0 +#define COEX_STAND_ALONE_DEBUG_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_IPAN_ASSOC_LEVEL_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) +#define COEX_RSRVD1_FLAGS 0 +#define COEX_RSRVD2_FLAGS 0 +/* XOR_RF_ON is the event wrapping all radio ownership. We need + * DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. */ +#define COEX_XOR_RF_ON_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) + +/* LMAC OP CODES */ +#define REPLY_PAD 0x0 +#define REPLY_ALIVE 0x1 +#define REPLY_ERROR 0x2 +#define REPLY_ECHO 0x3 +#define REPLY_HALT 0x6 + +/* RXON state commands */ +#define REPLY_RX_ON 0x10 +#define REPLY_RX_ON_ASSOC 0x11 +#define REPLY_RX_OFF 0x12 +#define REPLY_QOS_PARAM 0x13 +#define REPLY_RX_ON_TIMING 0x14 +#define REPLY_INTERNAL_QOS_PARAM 0x15 +#define REPLY_RX_INT_TIMEOUT_CNFG 0x16 +#define REPLY_NULL 0x17 + +/* Multi-Station support */ +#define REPLY_ADD_STA 0x18 +#define REPLY_REMOVE_STA 0x19 +#define REPLY_RESET_ALL_STA 0x1a + +/* RX, TX */ +#define REPLY_ALM_RX 0x1b +#define REPLY_TX 0x1c +#define REPLY_TXFIFO_FLUSH 0x1e + +/* MISC commands */ +#define REPLY_MGMT_MCAST_KEY 0x1f +#define REPLY_WEPKEY 0x20 +#define REPLY_INIT_IV 0x21 +#define REPLY_WRITE_MIB 0x22 +#define REPLY_READ_MIB 0x23 +#define REPLY_RADIO_FE 0x24 +#define REPLY_TXFIFO_CFG 0x25 +#define REPLY_WRITE_READ 0x26 +#define REPLY_INSTALL_SEC_KEY 0x27 + + +#define REPLY_RATE_SCALE 0x47 +#define REPLY_LEDS_CMD 0x48 +#define REPLY_TX_LINK_QUALITY_CMD 0x4e +#define REPLY_ANA_MIB_OVERRIDE_CMD 0x4f +#define REPLY_WRITE2REG_CMD 0x50 + +/* winfi-wifi coexistence */ +#define COEX_PRIORITY_TABLE_CMD 0x5a +#define COEX_MEDIUM_NOTIFICATION 0x5b +#define COEX_EVENT_CMD 0x5c + +/* more Protocol and Protocol-test commands */ +#define REPLY_MAX_SLEEP_TIME_CMD 0x61 +#define CALIBRATION_CFG_CMD 0x65 +#define CALIBRATION_RES_NOTIFICATION 0x66 +#define CALIBRATION_COMPLETE_NOTIFICATION 0x67 + +/* Measurements */ +#define REPLY_QUIET_CMD 0x71 +#define REPLY_CHANNEL_SWITCH 0x72 +#define CHANNEL_SWITCH_NOTIFICATION 0x73 + +#define REPLY_SPECTRUM_MEASUREMENT_CMD 0x74 +#define SPECTRUM_MEASURE_NOTIFICATION 0x75 +#define REPLY_MEASUREMENT_ABORT_CMD 0x76 + +/* Power Management */ +#define POWER_TABLE_CMD 0x77 +#define SAVE_RESTORE_ADRESS_CMD 0x78 +#define REPLY_WATERMARK_CMD 0x79 +#define PM_DEBUG_STATISTIC_NOTIFIC 0x7B +#define PD_FLUSH_N_NOTIFICATION 0x7C + +/* Scan commands and notifications */ +#define REPLY_SCAN_REQUEST_CMD 0x80 +#define REPLY_SCAN_ABORT_CMD 0x81 +#define SCAN_START_NOTIFICATION 0x82 +#define SCAN_RESULTS_NOTIFICATION 0x83 +#define SCAN_COMPLETE_NOTIFICATION 0x84 + +/* Continuous TX commands */ +#define REPLY_CONT_TX_CMD 0x85 +#define END_OF_CONT_TX_NOTIFICATION 0x86 + +/* Timer/Eeprom commands */ +#define TIMER_CMD 0x87 +#define EEPROM_WRITE_CMD 0x88 + +/* PAPD commands */ +#define FEEDBACK_REQUEST_NOTIFICATION 0x8b +#define REPLY_CW_CMD 0x8c + +/* IBSS/AP commands Continue */ +#define BEACON_NOTIFICATION 0x90 +#define REPLY_TX_BEACON 0x91 +#define REPLY_REQUEST_ATIM 0x93 +#define WHO_IS_AWAKE_NOTIFICATION 0x94 +#define TX_PWR_DBM_LIMIT_CMD 0x95 +#define QUIET_NOTIFICATION 0x96 +#define TX_PWR_TABLE_CMD 0x97 +#define TX_ANT_CONFIGURATION_CMD 0x98 +#define MEASURE_ABORT_NOTIFICATION 0x99 +#define REPLY_CALIBRATION_TUNE 0x9a + +/* bt config command */ +#define REPLY_BT_CONFIG 0x9b +#define REPLY_STATISTICS_CMD 0x9c +#define STATISTICS_NOTIFICATION 0x9d + +/* RF-KILL commands and notifications */ +#define REPLY_CARD_STATE_CMD 0xa0 +#define CARD_STATE_NOTIFICATION 0xa1 + +/* Missed beacons notification */ +#define MISSED_BEACONS_NOTIFICATION 0xa2 +#define MISSED_BEACONS_NOTIFICATION_TH_CMD 0xa3 + +#define REPLY_CT_KILL_CONFIG_CMD 0xa4 + +/* HD commands and notifications */ +#define REPLY_HD_PARAMS_CMD 0xa6 +#define HD_PARAMS_NOTIFICATION 0xa7 +#define SENSITIVITY_CMD 0xa8 +#define U_APSD_PARAMS_CMD 0xa9 +#define NOISY_PLATFORM_CMD 0xaa +#define ILLEGAL_CMD 0xac +#define REPLY_PHY_CALIBRATION_CMD 0xb0 +#define REPLAY_RX_GAIN_CALIB_CMD 0xb1 + +/* WiPAN commands */ +#define REPLY_WIPAN_PARAMS_CMD 0xb2 +#define REPLY_WIPAN_RX_ON_CMD 0xb3 +#define REPLY_WIPAN_RX_ON_TIMING 0xb4 +#define REPLY_WIPAN_TX_PWR_TABLE_CMD 0xb5 +#define REPLY_WIPAN_RXON_ASSOC_CMD 0xb6 +#define REPLY_WIPAN_QOS_PARAM 0xb7 +#define WIPAN_REPLY_WEPKEY 0xb8 + +/* BeamForming commands */ +#define BEAMFORMER_CFG_CMD 0xba +#define BEAMFORMEE_NOTIFICATION 0xbb + +/* TGn new Commands */ +#define REPLY_RX_PHY_CMD 0xc0 +#define REPLY_RX_MPDU_CMD 0xc1 +#define REPLY_MULTICAST_HASH 0xc2 +#define REPLY_KDR_RX 0xc3 +#define REPLY_RX_DSP_EXT_INFO 0xc4 +#define REPLY_COMPRESSED_BA 0xc5 + +/* PNC commands */ +#define PNC_CONFIG_CMD 0xc8 +#define PNC_UPDATE_TABLE_CMD 0xc9 +#define XVT_GENERAL_CTRL_CMD 0xca +#define REPLY_LEGACY_RADIO_FE 0xdd + +/* WoWLAN commands */ +#define WOWLAN_PATTERNS 0xe0 +#define WOWLAN_WAKEUP_FILTER 0xe1 +#define WOWLAN_TSC_RSC_PARAM 0xe2 +#define WOWLAN_TKIP_PARAM 0xe3 +#define WOWLAN_KEK_KCK_MATERIAL 0xe4 +#define WOWLAN_GET_STATUSES 0xe5 +#define WOWLAN_TX_POWER_PER_DB 0xe6 +#define REPLY_WOWLAN_GET_STATUSES WOWLAN_GET_STATUSES + +#define REPLY_DEBUG_CMD 0xf0 +#define REPLY_DSP_DEBUG_CMD 0xf1 +#define REPLY_DEBUG_MONITOR_CMD 0xf2 +#define REPLY_DEBUG_XVT_CMD 0xf3 +#define REPLY_DEBUG_DC_CALIB 0xf4 +#define REPLY_DYNAMIC_BP 0xf5 + +/* General purpose Commands */ +#define REPLY_GP1_CMD 0xfa +#define REPLY_GP2_CMD 0xfb +#define REPLY_GP3_CMD 0xfc +#define REPLY_GP4_CMD 0xfd +#define REPLY_REPLAY_WRAPPER 0xfe +#define REPLY_FRAME_DURATION_CALC_CMD 0xff + +#define LMAC_COMMAND_ID_MAX 0xff +#define LMAC_COMMAND_ID_NUM (LMAC_COMMAND_ID_MAX + 1) + + +/* Calibration */ + +enum { + PHY_CALIBRATE_DC_CMD = 0, + PHY_CALIBRATE_LO_CMD = 1, + PHY_CALIBRATE_RX_BB_CMD = 2, + PHY_CALIBRATE_TX_IQ_CMD = 3, + PHY_CALIBRATE_RX_IQ_CMD = 4, + PHY_CALIBRATION_NOISE_CMD = 5, + PHY_CALIBRATE_AGC_TABLE_CMD = 6, + PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 7, + PHY_CALIBRATE_OPCODES_NUM, + SHILOH_PHY_CALIBRATE_DC_CMD = 8, + SHILOH_PHY_CALIBRATE_LO_CMD = 9, + SHILOH_PHY_CALIBRATE_RX_BB_CMD = 10, + SHILOH_PHY_CALIBRATE_TX_IQ_CMD = 11, + SHILOH_PHY_CALIBRATE_RX_IQ_CMD = 12, + SHILOH_PHY_CALIBRATION_NOISE_CMD = 13, + SHILOH_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + SHILOH_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + SHILOH_PHY_CALIBRATE_BASE_BAND_CMD = 16, + SHILOH_PHY_CALIBRATE_TXIQ_PERIODIC_CMD = 17, + CALIBRATION_CMD_NUM, +}; + +struct iwm_lmac_calib_hdr { + u8 opcode; + u8 first_grp; + u8 grp_num; + u8 all_data_valid; +} __attribute__ ((packed)); + +#define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7 +#define IWM_CALIB_FREQ_GROUPS_NR 5 +#define IWM_CALIB_DC_MODES_NR 12 + +struct iwm_calib_rxiq_entry { + u16 ptam_postdist_ars; + u16 ptam_postdist_arc; +} __attribute__ ((packed)); + +struct iwm_calib_rxiq_group { + struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR]; +} __attribute__ ((packed)); + +struct iwm_lmac_calib_rxiq { + struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR]; +} __attribute__ ((packed)); + +struct iwm_calib_rxiq { + struct iwm_lmac_calib_hdr hdr; + struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR]; +} __attribute__ ((packed)); + +#define LMAC_STA_ID_SEED 0x0f +#define LMAC_STA_ID_POS 0 + +#define LMAC_STA_COLOR_SEED 0x7 +#define LMAC_STA_COLOR_POS 4 + +struct iwm_lmac_power_report { + u8 pa_status; + u8 pa_integ_res_A[3]; + u8 pa_integ_res_B[3]; + u8 pa_integ_res_C[3]; +} __attribute__ ((packed)); + +struct iwm_lmac_tx_resp { + u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */ + u8 bt_kill_cnt; + __le16 retry_cnt; + __le32 initial_tx_rate; + __le16 wireless_media_time; + struct iwm_lmac_power_report power_report; + __le32 tfd_info; + __le16 seq_ctl; + __le16 byte_cnt; + u8 tlc_rate_info; + u8 ra_tid; + __le16 frame_ctl; + __le32 status; +} __attribute__ ((packed)); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c new file mode 100644 index 0000000..6a2640f --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -0,0 +1,680 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "bus.h" +#include "umac.h" +#include "commands.h" +#include "hal.h" +#include "fw.h" +#include "rx.h" + +static struct iwm_conf def_iwm_conf = { + + .sdio_ior_timeout = 5000, + .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + BIT(PHY_CALIBRATE_LO_CMD) | + BIT(PHY_CALIBRATE_TX_IQ_CMD) | + BIT(PHY_CALIBRATE_RX_IQ_CMD), + .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + BIT(PHY_CALIBRATE_LO_CMD) | + BIT(PHY_CALIBRATE_TX_IQ_CMD) | + BIT(PHY_CALIBRATE_RX_IQ_CMD) | + BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), + .reset_on_fatal_err = 1, + .auto_connect = 1, + .wimax_not_present = 0, + .enable_qos = 1, + .mode = UMAC_MODE_BSS, + + /* UMAC configuration */ + .power_index = 0, + .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, + .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, + .cts_to_self = 0, + + .assoc_timeout = 2, + .roam_timeout = 10, + .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G, + .coexist_mode = COEX_MODE_CM, + + /* IBSS */ + .ibss_band = UMAC_BAND_2GHZ, + .ibss_channel = 1, + + .mac_addr = {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03}, +}; + +static int modparam_reset; +module_param_named(reset, modparam_reset, bool, 0644); +MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); + +int iwm_mode_to_nl80211_iftype(int mode) +{ + switch (mode) { + case UMAC_MODE_BSS: + return NL80211_IFTYPE_STATION; + case UMAC_MODE_IBSS: + return NL80211_IFTYPE_ADHOC; + default: + return NL80211_IFTYPE_UNSPECIFIED; + } + + return 0; +} + +static void iwm_statistics_request(struct work_struct *work) +{ + struct iwm_priv *iwm = + container_of(work, struct iwm_priv, stats_request.work); + + iwm_send_umac_stats_req(iwm, 0); +} + +static void iwm_reset_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + struct iwm_umac_profile *profile = NULL; + int uninitialized_var(ret), retry = 0; + + iwm = container_of(work, struct iwm_priv, reset_worker); + + if (iwm->umac_profile_active) { + profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); + if (profile) + memcpy(profile, iwm->umac_profile, sizeof(*profile)); + else + IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); + } + + iwm_down(iwm); + + while (retry++ < 3) { + ret = iwm_up(iwm); + if (!ret) + break; + + schedule_timeout_uninterruptible(10 * HZ); + } + + if (ret) { + IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); + + kfree(profile); + return; + } + + if (profile) { + IWM_DBG_MLME(iwm, DBG, "Resend UMAC profile\n"); + memcpy(iwm->umac_profile, profile, sizeof(*profile)); + iwm_send_mlme_profile(iwm); + kfree(profile); + } +} + +static void iwm_watchdog(unsigned long data) +{ + struct iwm_priv *iwm = (struct iwm_priv *)data; + + IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n"); + + if (modparam_reset) + schedule_work(&iwm->reset_worker); +} + +int iwm_priv_init(struct iwm_priv *iwm) +{ + int i; + char name[32]; + + iwm->status = 0; + INIT_LIST_HEAD(&iwm->pending_notif); + init_waitqueue_head(&iwm->notif_queue); + init_waitqueue_head(&iwm->nonwifi_queue); + init_waitqueue_head(&iwm->mlme_queue); + memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); + spin_lock_init(&iwm->tx_credit.lock); + INIT_LIST_HEAD(&iwm->wifi_pending_cmd); + INIT_LIST_HEAD(&iwm->nonwifi_pending_cmd); + iwm->wifi_seq_num = UMAC_WIFI_SEQ_NUM_BASE; + iwm->nonwifi_seq_num = UMAC_NONWIFI_SEQ_NUM_BASE; + spin_lock_init(&iwm->cmd_lock); + iwm->scan_id = 1; + INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); + INIT_WORK(&iwm->reset_worker, iwm_reset_worker); + INIT_LIST_HEAD(&iwm->bss_list); + + skb_queue_head_init(&iwm->rx_list); + INIT_LIST_HEAD(&iwm->rx_tickets); + for (i = 0; i < IWM_RX_ID_HASH; i++) + INIT_LIST_HEAD(&iwm->rx_packets[i]); + + INIT_WORK(&iwm->rx_worker, iwm_rx_worker); + + iwm->rx_wq = create_singlethread_workqueue(KBUILD_MODNAME "_rx"); + if (!iwm->rx_wq) + return -EAGAIN; + + for (i = 0; i < IWM_TX_QUEUES; i++) { + INIT_WORK(&iwm->txq[i].worker, iwm_tx_worker); + snprintf(name, 32, KBUILD_MODNAME "_tx_%d", i); + iwm->txq[i].id = i; + iwm->txq[i].wq = create_singlethread_workqueue(name); + if (!iwm->txq[i].wq) + return -EAGAIN; + + skb_queue_head_init(&iwm->txq[i].queue); + } + + for (i = 0; i < IWM_NUM_KEYS; i++) + memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); + + iwm->default_key = NULL; + + init_timer(&iwm->watchdog); + iwm->watchdog.function = iwm_watchdog; + iwm->watchdog.data = (unsigned long)iwm; + + return 0; +} + +/* + * We reset all the structures, and we reset the UMAC. + * After calling this routine, you're expected to reload + * the firmware. + */ +void iwm_reset(struct iwm_priv *iwm) +{ + struct iwm_notif *notif, *next; + + if (test_bit(IWM_STATUS_READY, &iwm->status)) + iwm_target_reset(iwm); + + iwm->status = 0; + iwm->scan_id = 1; + + list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { + list_del(¬if->pending); + kfree(notif->buf); + kfree(notif); + } + + iwm_cmd_flush(iwm); + + flush_workqueue(iwm->rx_wq); + + iwm_link_off(iwm); +} + +/* + * Notification code: + * + * We're faced with the following issue: Any host command can + * have an answer or not, and if there's an answer to expect, + * it can be treated synchronously or asynchronously. + * To work around the synchronous answer case, we implemented + * our notification mechanism. + * When a code path needs to wait for a command response + * synchronously, it calls notif_handle(), which waits for the + * right notification to show up, and then process it. Before + * starting to wait, it registered as a waiter for this specific + * answer (by toggling a bit in on of the handler_map), so that + * the rx code knows that it needs to send a notification to the + * waiting processes. It does so by calling iwm_notif_send(), + * which adds the notification to the pending notifications list, + * and then wakes the waiting processes up. + */ +int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, + u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size) +{ + struct iwm_notif *notif; + + notif = kzalloc(sizeof(struct iwm_notif), GFP_KERNEL); + if (!notif) { + IWM_ERR(iwm, "Couldn't alloc memory for notification\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(¬if->pending); + notif->cmd = cmd; + notif->cmd_id = cmd_id; + notif->src = source; + notif->buf = kzalloc(buf_size, GFP_KERNEL); + if (!notif->buf) { + IWM_ERR(iwm, "Couldn't alloc notification buffer\n"); + kfree(notif); + return -ENOMEM; + } + notif->buf_size = buf_size; + memcpy(notif->buf, buf, buf_size); + list_add_tail(¬if->pending, &iwm->pending_notif); + + wake_up_interruptible(&iwm->notif_queue); + + return 0; +} + +static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd, + u8 source) +{ + struct iwm_notif *notif, *next; + + list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { + if ((notif->cmd_id == cmd) && (notif->src == source)) { + list_del(¬if->pending); + return notif; + } + } + + return NULL; +} + +static struct iwm_notif *iwm_notif_wait(struct iwm_priv *iwm, u32 cmd, + u8 source, long timeout) +{ + int ret; + struct iwm_notif *notif; + unsigned long *map = NULL; + + switch (source) { + case IWM_SRC_LMAC: + map = &iwm->lmac_handler_map[0]; + break; + case IWM_SRC_UMAC: + map = &iwm->umac_handler_map[0]; + break; + case IWM_SRC_UDMA: + map = &iwm->udma_handler_map[0]; + break; + } + + set_bit(cmd, map); + + ret = wait_event_interruptible_timeout(iwm->notif_queue, + ((notif = iwm_notif_find(iwm, cmd, source)) != NULL), + timeout); + clear_bit(cmd, map); + + if (!ret) + return NULL; + + return notif; +} + +int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout) +{ + int ret; + struct iwm_notif *notif; + + notif = iwm_notif_wait(iwm, cmd, source, timeout); + if (!notif) + return -ETIME; + + ret = iwm_rx_handle_resp(iwm, notif->buf, notif->buf_size, notif->cmd); + kfree(notif->buf); + kfree(notif); + + return ret; +} + +static int iwm_config_boot_params(struct iwm_priv *iwm) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + int ret; + + /* check Wimax is off and config debug monitor */ + if (iwm->conf.wimax_not_present) { + u32 data1 = 0x1f; + u32 addr1 = 0x606BE258; + + u32 data2_set = 0x0; + u32 data2_clr = 0x1; + u32 addr2 = 0x606BE100; + + u32 data3 = 0x1; + u32 addr3 = 0x606BEC00; + + target_cmd.resp = 0; + target_cmd.handle_by_hw = 0; + target_cmd.eop = 1; + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; + target_cmd.addr = cpu_to_le32(addr1); + target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); + target_cmd.op2 = 0; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); + if (ret < 0) { + IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); + return ret; + } + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE; + target_cmd.addr = cpu_to_le32(addr2); + target_cmd.op1_sz = cpu_to_le32(data2_set); + target_cmd.op2 = cpu_to_le32(data2_clr); + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); + if (ret < 0) { + IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); + return ret; + } + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; + target_cmd.addr = cpu_to_le32(addr3); + target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); + target_cmd.op2 = 0; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data3); + if (ret < 0) { + IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); + return ret; + } + } + + return 0; +} + +void iwm_init_default_profile(struct iwm_priv *iwm, + struct iwm_umac_profile *profile) +{ + memset(profile, 0, sizeof(struct iwm_umac_profile)); + + profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; + profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_NONE; + profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_NONE; + + if (iwm->conf.enable_qos) + profile->flags |= cpu_to_le16(UMAC_PROFILE_QOS_ALLOWED); + + profile->wireless_mode = iwm->conf.wireless_mode; + profile->mode = cpu_to_le32(iwm->conf.mode); + + profile->ibss.atim = 0; + profile->ibss.beacon_interval = 100; + profile->ibss.join_only = 0; + profile->ibss.band = iwm->conf.ibss_band; + profile->ibss.channel = iwm->conf.ibss_channel; +} + +void iwm_link_on(struct iwm_priv *iwm) +{ + netif_carrier_on(iwm_to_ndev(iwm)); + netif_tx_wake_all_queues(iwm_to_ndev(iwm)); + + iwm_send_umac_stats_req(iwm, 0); +} + +void iwm_link_off(struct iwm_priv *iwm) +{ + struct iw_statistics *wstats = &iwm->wstats; + int i; + + netif_tx_stop_all_queues(iwm_to_ndev(iwm)); + netif_carrier_off(iwm_to_ndev(iwm)); + + for (i = 0; i < IWM_TX_QUEUES; i++) { + skb_queue_purge(&iwm->txq[i].queue); + + iwm->txq[i].concat_count = 0; + iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; + + flush_workqueue(iwm->txq[i].wq); + } + + iwm_rx_free(iwm); + + cancel_delayed_work(&iwm->stats_request); + memset(wstats, 0, sizeof(struct iw_statistics)); + wstats->qual.updated = IW_QUAL_ALL_INVALID; + + del_timer_sync(&iwm->watchdog); +} + +static void iwm_bss_list_clean(struct iwm_priv *iwm) +{ + struct iwm_bss_info *bss, *next; + + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { + list_del(&bss->node); + kfree(bss->bss); + kfree(bss); + } +} + +static int iwm_channels_init(struct iwm_priv *iwm) +{ + int ret; + +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (iwm->conf.hw_b0) { + IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n"); + return 0; + } +#endif + + ret = iwm_send_umac_channel_list(iwm); + if (ret) { + IWM_ERR(iwm, "Send channel list failed\n"); + return ret; + } + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Didn't get a channel list notification\n"); + return ret; + } + + return 0; +} + +int iwm_up(struct iwm_priv *iwm) +{ + int ret; + struct iwm_notif *notif_reboot, *notif_ack = NULL; + + ret = iwm_bus_enable(iwm); + if (ret) { + IWM_ERR(iwm, "Couldn't enable function\n"); + return ret; + } + + iwm_rx_setup_handlers(iwm); + + /* Wait for initial BARKER_REBOOT from hardware */ + notif_reboot = iwm_notif_wait(iwm, IWM_BARKER_REBOOT_NOTIFICATION, + IWM_SRC_UDMA, 2 * HZ); + if (!notif_reboot) { + IWM_ERR(iwm, "Wait for REBOOT_BARKER timeout\n"); + goto err_disable; + } + + /* We send the barker back */ + ret = iwm_bus_send_chunk(iwm, notif_reboot->buf, 16); + if (ret) { + IWM_ERR(iwm, "REBOOT barker response failed\n"); + kfree(notif_reboot); + goto err_disable; + } + + kfree(notif_reboot->buf); + kfree(notif_reboot); + + /* Wait for ACK_BARKER from hardware */ + notif_ack = iwm_notif_wait(iwm, IWM_ACK_BARKER_NOTIFICATION, + IWM_SRC_UDMA, 2 * HZ); + if (!notif_ack) { + IWM_ERR(iwm, "Wait for ACK_BARKER timeout\n"); + goto err_disable; + } + + kfree(notif_ack->buf); + kfree(notif_ack); + + /* We start to config static boot parameters */ + ret = iwm_config_boot_params(iwm); + if (ret) { + IWM_ERR(iwm, "Config boot parameters failed\n"); + goto err_disable; + } + + ret = iwm_read_mac(iwm, iwm_to_ndev(iwm)->dev_addr); + if (ret) { + IWM_ERR(iwm, "MAC reading failed\n"); + goto err_disable; + } + + /* We can load the FWs */ + ret = iwm_load_fw(iwm); + if (ret) { + IWM_ERR(iwm, "FW loading failed\n"); + goto err_disable; + } + + /* We configure the UMAC and enable the wifi module */ + ret = iwm_send_umac_config(iwm, + cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | + cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_LINK_EN) | + cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_MLME_EN)); + if (ret) { + IWM_ERR(iwm, "UMAC config failed\n"); + goto err_fw; + } + + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Didn't get a wifi core status notification\n"); + goto err_fw; + } + + if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | + UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { + IWM_DBG_BOOT(iwm, DBG, "Not all cores enabled:0x%x\n", + iwm->core_enabled); + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Didn't get a core status notification\n"); + goto err_fw; + } + + if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | + UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { + IWM_ERR(iwm, "Not all cores enabled: 0x%x\n", + iwm->core_enabled); + goto err_fw; + } else { + IWM_INFO(iwm, "All cores enabled\n"); + } + } + + iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), + GFP_KERNEL); + if (!iwm->umac_profile) { + IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); + goto err_fw; + } + + iwm_init_default_profile(iwm, iwm->umac_profile); + + ret = iwm_channels_init(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't init channels\n"); + goto err_profile; + } + + /* Set the READY bit to indicate interface is brought up successfully */ + set_bit(IWM_STATUS_READY, &iwm->status); + + return 0; + + err_profile: + kfree(iwm->umac_profile); + iwm->umac_profile = NULL; + + err_fw: + iwm_eeprom_exit(iwm); + + err_disable: + ret = iwm_bus_disable(iwm); + if (ret < 0) + IWM_ERR(iwm, "Couldn't disable function\n"); + + return -EIO; +} + +int iwm_down(struct iwm_priv *iwm) +{ + int ret; + + /* The interface is already down */ + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return 0; + + if (iwm->scan_request) { + cfg80211_scan_done(iwm->scan_request, true); + iwm->scan_request = NULL; + } + + clear_bit(IWM_STATUS_READY, &iwm->status); + + iwm_eeprom_exit(iwm); + kfree(iwm->umac_profile); + iwm->umac_profile = NULL; + iwm_bss_list_clean(iwm); + + iwm->default_key = NULL; + iwm->core_enabled = 0; + + ret = iwm_bus_disable(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't disable function\n"); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c new file mode 100644 index 0000000..eec7201 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -0,0 +1,172 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +/* + * This is the netdev related hooks for iwm. + * + * Some interesting code paths: + * + * iwm_open() (Called at netdev interface bringup time) + * -> iwm_up() (main.c) + * -> iwm_bus_enable() + * -> if_sdio_enable() (In case of an SDIO bus) + * -> sdio_enable_func() + * -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker) + * -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker) + * -> iwm_load_fw() (fw.c) + * -> iwm_load_umac() + * -> iwm_load_lmac() (Calibration LMAC) + * -> iwm_load_lmac() (Operational LMAC) + * -> iwm_send_umac_config() + * + * iwm_stop() (Called at netdev interface bringdown time) + * -> iwm_down() + * -> iwm_bus_disable() + * -> if_sdio_disable() (In case of an SDIO bus) + * -> sdio_disable_func() + */ +#include + +#include "iwm.h" +#include "cfg80211.h" +#include "debug.h" + +static int iwm_open(struct net_device *ndev) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret = 0; + + if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) + ret = iwm_up(iwm); + + return ret; +} + +static int iwm_stop(struct net_device *ndev) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret = 0; + + if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) + ret = iwm_down(iwm); + + return ret; +} + +/* + * iwm AC to queue mapping + * + * AC_VO -> queue 3 + * AC_VI -> queue 2 + * AC_BE -> queue 1 + * AC_BK -> queue 0 + */ +static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + +static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + skb->priority = cfg80211_classify8021d(skb); + + return iwm_1d_to_queue[skb->priority]; +} + +static const struct net_device_ops iwm_netdev_ops = { + .ndo_open = iwm_open, + .ndo_stop = iwm_stop, + .ndo_start_xmit = iwm_xmit_frame, + .ndo_select_queue = iwm_select_queue, +}; + +void *iwm_if_alloc(int sizeof_bus, struct device *dev, + struct iwm_if_ops *if_ops) +{ + struct net_device *ndev; + struct wireless_dev *wdev; + struct iwm_priv *iwm; + int ret = 0; + + wdev = iwm_wdev_alloc(sizeof_bus, dev); + if (!wdev) { + dev_err(dev, "no memory for wireless device instance\n"); + return ERR_PTR(-ENOMEM); + } + + iwm = wdev_to_iwm(wdev); + iwm->bus_ops = if_ops; + iwm->wdev = wdev; + iwm_priv_init(iwm); + wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); + + ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, + IWM_TX_QUEUES); + if (!ndev) { + dev_err(dev, "no memory for network device instance\n"); + goto out_wdev; + } + + ndev->netdev_ops = &iwm_netdev_ops; + ndev->wireless_handlers = &iwm_iw_handler_def; + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + ret = register_netdev(ndev); + if (ret < 0) { + dev_err(dev, "Failed to register netdev: %d\n", ret); + goto out_ndev; + } + + wdev->netdev = ndev; + + ret = iwm_rfkill_init(iwm); + if (ret) { + dev_err(dev, "Failed to init rfkill\n"); + goto out_rfkill; + } + + return iwm; + + out_rfkill: + unregister_netdev(ndev); + + out_ndev: + free_netdev(ndev); + + out_wdev: + iwm_wdev_free(iwm); + return ERR_PTR(ret); +} + +void iwm_if_free(struct iwm_priv *iwm) +{ + int i; + + if (!iwm_to_ndev(iwm)) + return; + + iwm_rfkill_exit(iwm); + unregister_netdev(iwm_to_ndev(iwm)); + free_netdev(iwm_to_ndev(iwm)); + iwm_wdev_free(iwm); + destroy_workqueue(iwm->rx_wq); + for (i = 0; i < IWM_TX_QUEUES; i++) + destroy_workqueue(iwm->txq[i].wq); +} diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c new file mode 100644 index 0000000..4ca8b49 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rfkill.c @@ -0,0 +1,88 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include + +#include "iwm.h" + +static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) +{ + struct iwm_priv *iwm = data; + + switch (state) { + case RFKILL_STATE_UNBLOCKED: + if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) + return -EBUSY; + + if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && + (iwm_to_ndev(iwm)->flags & IFF_UP)) + iwm_up(iwm); + + break; + case RFKILL_STATE_SOFT_BLOCKED: + if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) + iwm_down(iwm); + + break; + default: + break; + } + + return 0; +} + +int iwm_rfkill_init(struct iwm_priv *iwm) +{ + int ret; + + iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); + if (!iwm->rfkill) { + IWM_ERR(iwm, "Unable to allocate rfkill device\n"); + return -ENOMEM; + } + + iwm->rfkill->name = KBUILD_MODNAME; + iwm->rfkill->data = iwm; + iwm->rfkill->state = RFKILL_STATE_UNBLOCKED; + iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle; + + ret = rfkill_register(iwm->rfkill); + if (ret) { + IWM_ERR(iwm, "Failed to register rfkill device\n"); + goto fail; + } + + return 0; + fail: + rfkill_free(iwm->rfkill); + return ret; +} + +void iwm_rfkill_exit(struct iwm_priv *iwm) +{ + if (iwm->rfkill) + rfkill_unregister(iwm->rfkill); + + rfkill_free(iwm->rfkill); + iwm->rfkill = NULL; +} diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c new file mode 100644 index 0000000..d73cf96 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -0,0 +1,1431 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "hal.h" +#include "umac.h" +#include "lmac.h" +#include "commands.h" +#include "rx.h" +#include "cfg80211.h" +#include "eeprom.h" + +static int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr) +{ + if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) || + (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL)) + return -EINVAL; + + return 0; +} + +static inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr) +{ + return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr), + 16); +} + +/* + * Notification handlers: + * + * For every possible notification we can receive from the + * target, we have a handler. + * When we get a target notification, and there is no one + * waiting for it, it's just processed through the rx code + * path: + * + * iwm_rx_handle() + * -> iwm_rx_handle_umac() + * -> iwm_rx_handle_wifi() + * -> iwm_rx_handle_resp() + * -> iwm_ntf_*() + * + * OR + * + * -> iwm_rx_handle_non_wifi() + * + * If there are processes waiting for this notification, then + * iwm_rx_handle_wifi() just wakes those processes up and they + * grab the pending notification. + */ +static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_error *error; + struct iwm_fw_error_hdr *fw_err; + + error = (struct iwm_umac_notif_error *)buf; + fw_err = &error->err; + + + IWM_ERR(iwm, "%cMAC FW ERROR:\n", + (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); + IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); + IWM_ERR(iwm, "\tStatus: 0x%x\n", le32_to_cpu(fw_err->status)); + IWM_ERR(iwm, "\tPC: 0x%x\n", le32_to_cpu(fw_err->pc)); + IWM_ERR(iwm, "\tblink1: %d\n", le32_to_cpu(fw_err->blink1)); + IWM_ERR(iwm, "\tblink2: %d\n", le32_to_cpu(fw_err->blink2)); + IWM_ERR(iwm, "\tilink1: %d\n", le32_to_cpu(fw_err->ilink1)); + IWM_ERR(iwm, "\tilink2: %d\n", le32_to_cpu(fw_err->ilink2)); + IWM_ERR(iwm, "\tData1: 0x%x\n", le32_to_cpu(fw_err->data1)); + IWM_ERR(iwm, "\tData2: 0x%x\n", le32_to_cpu(fw_err->data2)); + IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num)); + IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status)); + IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); + IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); + + return 0; +} + +static int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_alive *alive_resp = + (struct iwm_umac_notif_alive *)(buf); + u16 status = le16_to_cpu(alive_resp->status); + + if (status == UMAC_NTFY_ALIVE_STATUS_ERR) { + IWM_ERR(iwm, "Receive error UMAC_ALIVE\n"); + return -EIO; + } + + iwm_tx_credit_init_pools(iwm, alive_resp); + + return 0; +} + +static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_init_complete *init_complete = + (struct iwm_umac_notif_init_complete *)(buf); + u16 status = le16_to_cpu(init_complete->status); + + if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) { + IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); + set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + } else { + IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); + clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + } + + return 0; +} + +static int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + int pool_nr, total_freed_pages; + unsigned long pool_map; + int i, id; + struct iwm_umac_notif_page_dealloc *dealloc = + (struct iwm_umac_notif_page_dealloc *)buf; + + pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT); + pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK); + + IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, " + "update map 0x%lx\n", pool_nr, pool_map); + + spin_lock(&iwm->tx_credit.lock); + + for (i = 0; i < pool_nr; i++) { + id = GET_VAL32(dealloc->grp_info[i], + UMAC_DEALLOC_NTFY_GROUP_NUM); + if (test_bit(id, &pool_map)) { + total_freed_pages = GET_VAL32(dealloc->grp_info[i], + UMAC_DEALLOC_NTFY_PAGE_CNT); + iwm_tx_credit_inc(iwm, id, total_freed_pages); + } + } + + spin_unlock(&iwm->tx_credit.lock); + + return 0; +} + +static int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n"); + + return 0; +} + +static int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]); + + return 0; +} + +static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_lmac_tx_resp *tx_resp; + struct iwm_umac_wifi_in_hdr *hdr; + + tx_resp = (struct iwm_lmac_tx_resp *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + hdr = (struct iwm_umac_wifi_in_hdr *)buf; + + IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); + + IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", + le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); + IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); + IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", + le16_to_cpu(tx_resp->retry_cnt)); + IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); + IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", + le16_to_cpu(tx_resp->byte_cnt)); + IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); + + return 0; +} + + +static int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + u8 opcode; + u8 *calib_buf; + struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + + opcode = hdr->opcode; + + BUG_ON(opcode >= CALIBRATION_CMD_NUM || + opcode < PHY_CALIBRATE_OPCODES_NUM); + + IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n", + opcode); + + buf_size -= sizeof(struct iwm_umac_wifi_in_hdr); + calib_buf = iwm->calib_res[opcode].buf; + + if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) { + kfree(calib_buf); + calib_buf = kzalloc(buf_size, GFP_KERNEL); + if (!calib_buf) { + IWM_ERR(iwm, "Memory allocation failed: calib_res\n"); + return -ENOMEM; + } + iwm->calib_res[opcode].buf = calib_buf; + iwm->calib_res[opcode].size = buf_size; + } + + memcpy(calib_buf, hdr, buf_size); + set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map); + + return 0; +} + +static int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_NTF(iwm, DBG, "Calibration completed\n"); + + return 0; +} + +static int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_lmac_cal_cfg_resp *cal_resp; + + cal_resp = (struct iwm_lmac_cal_cfg_resp *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + + IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n", + le32_to_cpu(cal_resp->status)); + + return 0; +} + +static int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_wifi_status *status = + (struct iwm_umac_notif_wifi_status *)buf; + + iwm->core_enabled |= le16_to_cpu(status->status); + + return 0; +} + +static struct iwm_rx_ticket_node * +iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket) +{ + struct iwm_rx_ticket_node *ticket_node; + + ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL); + if (!ticket_node) { + IWM_ERR(iwm, "Couldn't allocate ticket node\n"); + return ERR_PTR(-ENOMEM); + } + + ticket_node->ticket = kzalloc(sizeof(struct iwm_rx_ticket), GFP_KERNEL); + if (!ticket_node->ticket) { + IWM_ERR(iwm, "Couldn't allocate RX ticket\n"); + kfree(ticket_node); + return ERR_PTR(-ENOMEM); + } + + memcpy(ticket_node->ticket, ticket, sizeof(struct iwm_rx_ticket)); + INIT_LIST_HEAD(&ticket_node->node); + + return ticket_node; +} + +static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node) +{ + kfree(ticket_node->ticket); + kfree(ticket_node); +} + +static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id) +{ + u8 id_hash = IWM_RX_ID_GET_HASH(id); + struct list_head *packet_list; + struct iwm_rx_packet *packet, *next; + + packet_list = &iwm->rx_packets[id_hash]; + + list_for_each_entry_safe(packet, next, packet_list, node) + if (packet->id == id) + return packet; + + return NULL; +} + +static struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf, + u32 size, u16 id) +{ + struct iwm_rx_packet *packet; + + packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL); + if (!packet) { + IWM_ERR(iwm, "Couldn't allocate packet\n"); + return ERR_PTR(-ENOMEM); + } + + packet->skb = dev_alloc_skb(size); + if (!packet->skb) { + IWM_ERR(iwm, "Couldn't allocate packet SKB\n"); + kfree(packet); + return ERR_PTR(-ENOMEM); + } + + packet->pkt_size = size; + + skb_put(packet->skb, size); + memcpy(packet->skb->data, buf, size); + INIT_LIST_HEAD(&packet->node); + packet->id = id; + + return packet; +} + +void iwm_rx_free(struct iwm_priv *iwm) +{ + struct iwm_rx_ticket_node *ticket, *nt; + struct iwm_rx_packet *packet, *np; + int i; + + list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) { + list_del(&ticket->node); + iwm_rx_ticket_node_free(ticket); + } + + for (i = 0; i < IWM_RX_ID_HASH; i++) { + list_for_each_entry_safe(packet, np, &iwm->rx_packets[i], + node) { + list_del(&packet->node); + kfree_skb(packet->skb); + kfree(packet); + } + } +} + +static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_rx_ticket *ntf_rx_ticket = + (struct iwm_umac_notif_rx_ticket *)buf; + struct iwm_rx_ticket *ticket = + (struct iwm_rx_ticket *)ntf_rx_ticket->tickets; + int i, schedule_rx = 0; + + for (i = 0; i < ntf_rx_ticket->num_tickets; i++) { + struct iwm_rx_ticket_node *ticket_node; + + switch (le16_to_cpu(ticket->action)) { + case IWM_RX_TICKET_RELEASE: + case IWM_RX_TICKET_DROP: + /* We can push the packet to the stack */ + ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket); + if (IS_ERR(ticket_node)) + return PTR_ERR(ticket_node); + + IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", + ticket->id); + list_add_tail(&ticket_node->node, &iwm->rx_tickets); + + /* + * We received an Rx ticket, most likely there's + * a packet pending for it, it's not worth going + * through the packet hash list to double check. + * Let's just fire the rx worker.. + */ + schedule_rx = 1; + + break; + + default: + IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n", + ticket->action); + } + + ticket++; + } + + if (schedule_rx) + queue_work(iwm->rx_wq, &iwm->rx_worker); + + return 0; +} + +static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_wifi_in_hdr *wifi_hdr; + struct iwm_rx_packet *packet; + u16 id, buf_offset; + u32 packet_size; + + IWM_DBG_NTF(iwm, DBG, "\n"); + + wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; + id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); + buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); + packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); + + IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", + wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); + IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); + IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); + + packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id); + if (IS_ERR(packet)) + return PTR_ERR(packet); + + list_add_tail(&packet->node, &iwm->rx_packets[IWM_RX_ID_GET_HASH(id)]); + + /* We might (unlikely) have received the packet _after_ the ticket */ + queue_work(iwm->rx_wq, &iwm->rx_worker); + + return 0; +} + +/* MLME handlers */ +static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_assoc_start *start; + + start = (struct iwm_umac_notif_assoc_start *)buf; + + set_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + + IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", + start->bssid, le32_to_cpu(start->roam_reason)); + + wake_up_interruptible(&iwm->mlme_queue); + + return 0; +} + +static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_assoc_complete *complete = + (struct iwm_umac_notif_assoc_complete *)buf; + union iwreq_data wrqu; + + IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", + complete->bssid, complete->status); + + memset(&wrqu, 0, sizeof(wrqu)); + + clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + + switch (le32_to_cpu(complete->status)) { + case UMAC_ASSOC_COMPLETE_SUCCESS: + set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + memcpy(iwm->bssid, complete->bssid, ETH_ALEN); + iwm->channel = complete->channel; + + iwm_link_on(iwm); + + memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); + break; + case UMAC_ASSOC_COMPLETE_FAILURE: + clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + memset(iwm->bssid, 0, ETH_ALEN); + iwm->channel = 0; + + iwm_link_off(iwm); + default: + break; + } + + if (iwm->conf.mode == UMAC_MODE_IBSS) { + cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); + return 0; + } + + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL); + + return 0; +} + +static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_profile_invalidate *invalid; + + invalid = (struct iwm_umac_notif_profile_invalidate *)buf; + + IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", + le32_to_cpu(invalid->reason)); + + clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + + iwm->umac_profile_active = 0; + memset(iwm->bssid, 0, ETH_ALEN); + iwm->channel = 0; + + iwm_link_off(iwm); + + wake_up_interruptible(&iwm->mlme_queue); + + return 0; +} + +static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + int ret; + struct iwm_umac_notif_scan_complete *scan_complete = + (struct iwm_umac_notif_scan_complete *)buf; + u32 result = le32_to_cpu(scan_complete->result); + + IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n", + le32_to_cpu(scan_complete->type), + le32_to_cpu(scan_complete->result), + scan_complete->seq_num); + + if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) { + IWM_ERR(iwm, "Scan complete while device not scanning\n"); + return -EIO; + } + if (!iwm->scan_request) + return 0; + + ret = iwm_cfg80211_inform_bss(iwm); + + cfg80211_scan_done(iwm->scan_request, + (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret); + iwm->scan_request = NULL; + + return ret; +} + +static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_sta_info *umac_sta = + (struct iwm_umac_notif_sta_info *)buf; + struct iwm_sta_info *sta; + int i; + + switch (le32_to_cpu(umac_sta->opcode)) { + case UMAC_OPCODE_ADD_MODIFY: + sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; + + IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, " + "addr = %pM, qos = %d\n", + sta->valid ? "Modify" : "Add", + GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), + GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), + umac_sta->mac_addr, + umac_sta->flags & UMAC_STA_FLAG_QOS); + + sta->valid = 1; + sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS; + sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR); + memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN); + break; + case UMAC_OPCODE_REMOVE: + IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, " + "addr = %pM\n", + GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), + GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), + umac_sta->mac_addr); + + sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; + + if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN)) + sta->valid = 0; + + break; + case UMAC_OPCODE_CLEAR_ALL: + for (i = 0; i < IWM_STA_TABLE_NUM; i++) + iwm->sta_table[i].valid = 0; + + break; + default: + break; + } + + return 0; +} + +static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct wiphy *wiphy = iwm_to_wiphy(iwm); + struct ieee80211_mgmt *mgmt; + struct iwm_umac_notif_bss_info *umac_bss = + (struct iwm_umac_notif_bss_info *)buf; + struct ieee80211_channel *channel; + struct ieee80211_supported_band *band; + struct iwm_bss_info *bss, *next; + s32 signal; + int freq; + u16 frame_len = le16_to_cpu(umac_bss->frame_len); + size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len; + + mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); + + IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid); + IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type)); + IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n", + le32_to_cpu(umac_bss->timestamp)); + IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n", + le16_to_cpu(umac_bss->table_idx)); + IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band); + IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel); + IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi); + IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len); + + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) + if (bss->bss->table_idx == umac_bss->table_idx) + break; + + if (&bss->node != &iwm->bss_list) { + /* Remove the old BSS entry, we will add it back later. */ + list_del(&bss->node); + kfree(bss->bss); + } else { + /* New BSS entry */ + + bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL); + if (!bss) { + IWM_ERR(iwm, "Couldn't allocate bss_info\n"); + return -ENOMEM; + } + } + + bss->bss = kzalloc(bss_len, GFP_KERNEL); + if (!bss) { + kfree(bss); + IWM_ERR(iwm, "Couldn't allocate bss\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&bss->node); + memcpy(bss->bss, umac_bss, bss_len); + + if (umac_bss->band == UMAC_BAND_2GHZ) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else if (umac_bss->band == UMAC_BAND_5GHZ) + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + else { + IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); + goto err; + } + + freq = ieee80211_channel_to_frequency(umac_bss->channel); + channel = ieee80211_get_channel(wiphy, freq); + signal = umac_bss->rssi * 100; + + bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel, + mgmt, frame_len, + signal, GFP_KERNEL); + if (!bss->cfg_bss) + goto err; + + list_add_tail(&bss->node, &iwm->bss_list); + + return 0; + err: + kfree(bss->bss); + kfree(bss); + + return -EINVAL; +} + +static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_bss_removed *bss_rm = + (struct iwm_umac_notif_bss_removed *)buf; + struct iwm_bss_info *bss, *next; + u16 table_idx; + int i; + + for (i = 0; i < le32_to_cpu(bss_rm->count); i++) { + table_idx = (le16_to_cpu(bss_rm->entries[i]) + & IWM_BSS_REMOVE_INDEX_MSK); + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) + if (bss->bss->table_idx == cpu_to_le16(table_idx)) { + struct ieee80211_mgmt *mgmt; + + mgmt = (struct ieee80211_mgmt *) + (bss->bss->frame_buf); + IWM_DBG_MLME(iwm, ERR, + "BSS removed: %pM\n", + mgmt->bssid); + list_del(&bss->node); + kfree(bss->bss); + kfree(bss); + } + } + + return 0; +} + +static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_mgt_frame *mgt_frame = + (struct iwm_umac_notif_mgt_frame *)buf; + struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; + u8 *ie; + unsigned int event; + union iwreq_data wrqu; + + IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, + le16_to_cpu(mgt_frame->len)); + + if (ieee80211_is_assoc_req(mgt->frame_control)) { + ie = mgt->u.assoc_req.variable;; + event = IWEVASSOCREQIE; + } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { + ie = mgt->u.reassoc_req.variable;; + event = IWEVASSOCREQIE; + } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { + ie = mgt->u.assoc_resp.variable;; + event = IWEVASSOCRESPIE; + } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { + ie = mgt->u.reassoc_resp.variable;; + event = IWEVASSOCRESPIE; + } else { + IWM_ERR(iwm, "Unsupported management frame"); + return 0; + } + + wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + + IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length); + wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie); + + return 0; +} + +static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_wifi_if *notif = + (struct iwm_umac_notif_wifi_if *)buf; + + switch (notif->status) { + case WIFI_IF_NTFY_ASSOC_START: + return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_ASSOC_COMPLETE: + return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: + return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_CONNECTION_TERMINATED: + IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); + break; + case WIFI_IF_NTFY_SCAN_COMPLETE: + return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_STA_TABLE_CHANGE: + return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: + IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); + break; + case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: + return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: + return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd); + break; + case WIFI_IF_NTFY_MGMT_FRAME: + return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd); + case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START: + case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE: + case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START: + case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT: + case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START: + case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE: + case WIFI_DBG_IF_NTFY_CNCT_ATC_START: + case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION: + case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP: + case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP: + IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n", + notif->status); + break; + default: + IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status); + break; + } + + return 0; +} + +#define IWM_STATS_UPDATE_INTERVAL (2 * HZ) + +static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf; + struct iw_statistics *wstats = &iwm->wstats; + u16 max_rate = 0; + int i; + + IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n"); + + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) { + max_rate = max_t(u16, max_rate, + max(le16_to_cpu(stats->tx_rate[i]), + le16_to_cpu(stats->rx_rate[i]))); + } + /* UMAC passes rate info multiplies by 2 */ + iwm->rate = max_rate >> 1; + } + + wstats->status = 0; + + wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid); + wstats->discard.code = le32_to_cpu(stats->rx_drop_decode); + wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly); + wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry); + + wstats->miss.beacon = le32_to_cpu(stats->missed_beacons); + + /* according to cfg80211 */ + if (stats->rssi_dbm < -110) + wstats->qual.qual = 0; + else if (stats->rssi_dbm > -40) + wstats->qual.qual = 70; + else + wstats->qual.qual = stats->rssi_dbm + 110; + + wstats->qual.level = stats->rssi_dbm; + wstats->qual.noise = stats->noise_dbm; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL); + + mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD)); + + return 0; +} + +static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy = + (struct iwm_umac_cmd_eeprom_proxy *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr; + u32 hdr_offset = le32_to_cpu(hdr->offset); + u32 hdr_len = le32_to_cpu(hdr->len); + u32 hdr_type = le32_to_cpu(hdr->type); + + IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n", + hdr_type, hdr_len, hdr_offset); + + if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) + return -EINVAL; + +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) { + if (eeprom_proxy->buf[0] == 0xff) + iwm->conf.hw_b0 = 1; + } +#endif + + switch (hdr_type) { + case IWM_UMAC_CMD_EEPROM_TYPE_READ: + memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); + break; + case IWM_UMAC_CMD_EEPROM_TYPE_WRITE: + default: + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_cmd_get_channel_list *ch_list = + (struct iwm_umac_cmd_get_channel_list *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + struct wiphy *wiphy = iwm_to_wiphy(iwm); + struct ieee80211_supported_band *band; + int i; + + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + + for (i = 0; i < band->n_channels; i++) { + unsigned long ch_mask_0 = + le32_to_cpu(ch_list->ch[0].channels_mask); + unsigned long ch_mask_2 = + le32_to_cpu(ch_list->ch[2].channels_mask); + + if (!test_bit(i, &ch_mask_0)) + band->channels[i].flags |= IEEE80211_CHAN_DISABLED; + + if (!test_bit(i, &ch_mask_2)) + band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; + } + + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < min(band->n_channels, 32); i++) { + unsigned long ch_mask_1 = + le32_to_cpu(ch_list->ch[1].channels_mask); + unsigned long ch_mask_3 = + le32_to_cpu(ch_list->ch[3].channels_mask); + + if (!test_bit(i, &ch_mask_1)) + band->channels[i].flags |= IEEE80211_CHAN_DISABLED; + + if (!test_bit(i, &ch_mask_3)) + band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; + } + + return 0; +} + +static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_wifi_if *hdr = + (struct iwm_umac_wifi_if *)cmd->buf.payload; + + IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " + "oid is %d\n", hdr->oid); + + switch (hdr->oid) { + case UMAC_WIFI_IF_CMD_SET_PROFILE: + iwm->umac_profile_active = 1; + wake_up_interruptible(&iwm->mlme_queue); + break; + default: + break; + } + + return 0; +} + +static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + u32 flags = le32_to_cpu(state->flags); + + IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n", + flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", + flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); + + if (flags & IWM_CARD_STATE_HW_DISABLED) + set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + else + clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + + return 0; +} + +static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size) +{ + struct iwm_umac_wifi_in_hdr *wifi_hdr; + struct iwm_wifi_cmd *cmd; + u8 source, cmd_id; + u16 seq_num; + u32 count; + u8 resp; + + wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; + cmd_id = wifi_hdr->sw_hdr.cmd.cmd; + + source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); + if (source >= IWM_SRC_NUM) { + IWM_CRIT(iwm, "invalid source %d\n", source); + return -EINVAL; + } + + count = (GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT)); + count += sizeof(struct iwm_umac_wifi_in_hdr) - + sizeof(struct iwm_dev_cmd_hdr); + if (count > buf_size) { + IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size); + return -EINVAL; + } + + resp = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_STATUS); + + seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); + + IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n", + cmd_id, source, seq_num); + + /* + * If this is a response to a previously sent command, there must + * be a pending command for this sequence number. + */ + cmd = iwm_get_pending_wifi_cmd(iwm, seq_num); + + /* Notify the caller only for sync commands. */ + switch (source) { + case UMAC_HDI_IN_SOURCE_FHRX: + if (iwm->lmac_handlers[cmd_id] && + test_bit(cmd_id, &iwm->lmac_handler_map[0])) + return iwm_notif_send(iwm, cmd, cmd_id, source, + buf, count); + break; + case UMAC_HDI_IN_SOURCE_FW: + if (iwm->umac_handlers[cmd_id] && + test_bit(cmd_id, &iwm->umac_handler_map[0])) + return iwm_notif_send(iwm, cmd, cmd_id, source, + buf, count); + break; + case UMAC_HDI_IN_SOURCE_UDMA: + break; + } + + return iwm_rx_handle_resp(iwm, buf, count, cmd); +} + +int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + u8 source, cmd_id; + struct iwm_umac_wifi_in_hdr *wifi_hdr; + int ret = 0; + + wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; + cmd_id = wifi_hdr->sw_hdr.cmd.cmd; + + source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); + + IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source); + + switch (source) { + case UMAC_HDI_IN_SOURCE_FHRX: + if (iwm->lmac_handlers[cmd_id]) + ret = iwm->lmac_handlers[cmd_id] + (iwm, buf, buf_size, cmd); + break; + case UMAC_HDI_IN_SOURCE_FW: + if (iwm->umac_handlers[cmd_id]) + ret = iwm->umac_handlers[cmd_id] + (iwm, buf, buf_size, cmd); + break; + case UMAC_HDI_IN_SOURCE_UDMA: + ret = -EINVAL; + break; + } + + kfree(cmd); + + return ret; +} + +static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size) +{ + u8 seq_num; + struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf; + struct iwm_nonwifi_cmd *cmd, *next; + + seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); + + /* + * We received a non wifi answer. + * Let's check if there's a pending command for it, and if so + * replace the command payload with the buffer, and then wake the + * callers up. + * That means we only support synchronised non wifi command response + * schemes. + */ + list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending) + if (cmd->seq_num == seq_num) { + cmd->resp_received = 1; + cmd->buf.len = buf_size; + memcpy(cmd->buf.hdr, buf, buf_size); + wake_up_interruptible(&iwm->nonwifi_queue); + } + + return 0; +} + +static int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size) +{ + int ret = 0; + u8 op_code; + unsigned long buf_offset = 0; + struct iwm_udma_in_hdr *hdr; + + /* + * To allow for a more efficient bus usage, UMAC + * messages are encapsulated into UDMA ones. This + * way we can have several UMAC messages in one bus + * transfer. + * A UDMA frame size is always aligned on 16 bytes, + * and a UDMA frame must not start with a UMAC_PAD_TERMINAL + * word. This is how we parse a bus frame into several + * UDMA ones. + */ + while (buf_offset < buf_size) { + + hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset); + + if (iwm_rx_check_udma_hdr(hdr) < 0) { + IWM_DBG_RX(iwm, DBG, "End of frame\n"); + break; + } + + op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE); + + IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code); + + if (op_code == UMAC_HDI_IN_OPCODE_WIFI) { + ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset, + buf_size - buf_offset); + } else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) { + if (GET_VAL32(hdr->cmd, + UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) != + UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) { + IWM_ERR(iwm, "Incorrect hw signature\n"); + return -EINVAL; + } + ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset, + buf_size - buf_offset); + } else { + IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code); + ret |= -EINVAL; + } + + buf_offset += iwm_rx_resp_size(hdr); + } + + return ret; +} + +int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size) +{ + struct iwm_udma_in_hdr *hdr; + + hdr = (struct iwm_udma_in_hdr *)buf; + + switch (le32_to_cpu(hdr->cmd)) { + case UMAC_REBOOT_BARKER: + return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, + IWM_SRC_UDMA, buf, buf_size); + case UMAC_ACK_BARKER: + return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION, + IWM_SRC_UDMA, NULL, 0); + default: + IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd); + return iwm_rx_handle_umac(iwm, buf, buf_size); + } + + return 0; +} + +static const iwm_handler iwm_umac_handlers[] = +{ + [UMAC_NOTIFY_OPCODE_ERROR] = iwm_ntf_error, + [UMAC_NOTIFY_OPCODE_ALIVE] = iwm_ntf_umac_alive, + [UMAC_NOTIFY_OPCODE_INIT_COMPLETE] = iwm_ntf_init_complete, + [UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS] = iwm_ntf_wifi_status, + [UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_mlme, + [UMAC_NOTIFY_OPCODE_PAGE_DEALLOC] = iwm_ntf_tx_credit_update, + [UMAC_NOTIFY_OPCODE_RX_TICKET] = iwm_ntf_rx_ticket, + [UMAC_CMD_OPCODE_RESET] = iwm_ntf_umac_reset, + [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, + [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, + [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, + [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, + [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, +}; + +static const iwm_handler iwm_lmac_handlers[] = +{ + [REPLY_TX] = iwm_ntf_tx, + [REPLY_ALIVE] = iwm_ntf_lmac_version, + [CALIBRATION_RES_NOTIFICATION] = iwm_ntf_calib_res, + [CALIBRATION_COMPLETE_NOTIFICATION] = iwm_ntf_calib_complete, + [CALIBRATION_CFG_CMD] = iwm_ntf_calib_cfg, + [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, + [CARD_STATE_NOTIFICATION] = iwm_ntf_card_state, +}; + +void iwm_rx_setup_handlers(struct iwm_priv *iwm) +{ + iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers; + iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers; +} + +static void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len) +{ + struct ieee80211_hdr *hdr; + unsigned int hdr_len; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_has_protected(hdr->frame_control)) + return; + + hdr_len = ieee80211_hdrlen(hdr->frame_control); + if (hdr_total_len <= hdr_len) + return; + + memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len); + skb_pull(skb, (hdr_total_len - hdr_len)); +} + +static void iwm_rx_adjust_packet(struct iwm_priv *iwm, + struct iwm_rx_packet *packet, + struct iwm_rx_ticket_node *ticket_node) +{ + u32 payload_offset = 0, payload_len; + struct iwm_rx_ticket *ticket = ticket_node->ticket; + struct iwm_rx_mpdu_hdr *mpdu_hdr; + struct ieee80211_hdr *hdr; + + mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data; + payload_offset += sizeof(struct iwm_rx_mpdu_hdr); + /* Padding is 0 or 2 bytes */ + payload_len = le16_to_cpu(mpdu_hdr->len) + + (le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK); + payload_len -= ticket->tail_len; + + IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, " + "ticket offset:%d ticket tail len:%d\n", + payload_len, payload_offset, ticket->payload_offset, + ticket->tail_len); + + IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len); + + skb_pull(packet->skb, payload_offset); + skb_trim(packet->skb, payload_len); + + iwm_remove_iv(packet->skb, ticket->payload_offset); + + hdr = (struct ieee80211_hdr *) packet->skb->data; + if (ieee80211_is_data_qos(hdr->frame_control)) { + /* UMAC handed QOS_DATA frame with 2 padding bytes appended + * to the qos_ctl field in IEEE 802.11 headers. */ + memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2, + packet->skb->data, + ieee80211_hdrlen(hdr->frame_control) - + IEEE80211_QOS_CTL_LEN); + hdr = (struct ieee80211_hdr *) skb_pull(packet->skb, + IEEE80211_QOS_CTL_LEN + 2); + hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + } + + IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ", + packet->skb->data, packet->skb->len); +} + +static void classify8023(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + /* frame has qos control */ + skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK; + } else { + skb->priority = 0; + } +} + +static void iwm_rx_process_packet(struct iwm_priv *iwm, + struct iwm_rx_packet *packet, + struct iwm_rx_ticket_node *ticket_node) +{ + int ret; + struct sk_buff *skb = packet->skb; + struct wireless_dev *wdev = iwm_to_wdev(iwm); + struct net_device *ndev = iwm_to_ndev(iwm); + + IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id); + + switch (le16_to_cpu(ticket_node->ticket->action)) { + case IWM_RX_TICKET_RELEASE: + IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); + classify8023(skb); + iwm_rx_adjust_packet(iwm, packet, ticket_node); + ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); + if (ret < 0) { + IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " + "%d\n", ret); + break; + } + + IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); + + skb->dev = iwm_to_ndev(iwm); + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + memset(skb->cb, 0, sizeof(skb->cb)); + + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += skb->len; + + if (netif_rx(skb) == NET_RX_DROP) { + IWM_ERR(iwm, "Packet dropped\n"); + ndev->stats.rx_dropped++; + } + break; + case IWM_RX_TICKET_DROP: + IWM_DBG_RX(iwm, DBG, "DROP packet\n"); + kfree_skb(packet->skb); + break; + default: + IWM_ERR(iwm, "Unknow ticket action: %d\n", + le16_to_cpu(ticket_node->ticket->action)); + kfree_skb(packet->skb); + } + + kfree(packet); + iwm_rx_ticket_node_free(ticket_node); +} + +/* + * Rx data processing: + * + * We're receiving Rx packet from the LMAC, and Rx ticket from + * the UMAC. + * To forward a target data packet upstream (i.e. to the + * kernel network stack), we must have received an Rx ticket + * that tells us we're allowed to release this packet (ticket + * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates, + * among other things, where valid data actually starts in the Rx + * packet. + */ +void iwm_rx_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + struct iwm_rx_ticket_node *ticket, *next; + + iwm = container_of(work, struct iwm_priv, rx_worker); + + /* + * We go through the tickets list and if there is a pending + * packet for it, we push it upstream. + * We stop whenever a ticket is missing its packet, as we're + * supposed to send the packets in order. + */ + list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { + struct iwm_rx_packet *packet = + iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id)); + + if (!packet) { + IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d " + "to be handled first\n", + le16_to_cpu(ticket->ticket->id)); + return; + } + + list_del(&ticket->node); + list_del(&packet->node); + iwm_rx_process_packet(iwm, packet, ticket); + } +} + diff --git a/drivers/net/wireless/iwmc3200wifi/rx.h b/drivers/net/wireless/iwmc3200wifi/rx.h new file mode 100644 index 0000000..da0db91 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rx.h @@ -0,0 +1,60 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_RX_H__ +#define __IWM_RX_H__ + +#include + +#include "umac.h" + +struct iwm_rx_ticket_node { + struct list_head node; + struct iwm_rx_ticket *ticket; +}; + +struct iwm_rx_packet { + struct list_head node; + u16 id; + struct sk_buff *skb; + unsigned long pkt_size; +}; + +void iwm_rx_worker(struct work_struct *work); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c new file mode 100644 index 0000000..edc0a00 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -0,0 +1,516 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +/* + * This is the SDIO bus specific hooks for iwm. + * It also is the module's entry point. + * + * Interesting code paths: + * iwm_sdio_probe() (Called by an SDIO bus scan) + * -> iwm_if_alloc() (netdev.c) + * -> iwm_wdev_alloc() (cfg80211.c, allocates and register our wiphy) + * -> wiphy_new() + * -> wiphy_register() + * -> alloc_netdev_mq() + * -> register_netdev() + * + * iwm_sdio_remove() + * -> iwm_if_free() (netdev.c) + * -> unregister_netdev() + * -> iwm_wdev_free() (cfg80211.c) + * -> wiphy_unregister() + * -> wiphy_free() + * + * iwm_sdio_isr() (called in process context from the SDIO core code) + * -> queue_work(.., isr_worker) + * -- [async] --> iwm_sdio_isr_worker() + * -> iwm_rx_handle() + */ + +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "bus.h" +#include "sdio.h" + +static void iwm_sdio_isr_worker(struct work_struct *work) +{ + struct iwm_sdio_priv *hw; + struct iwm_priv *iwm; + struct iwm_rx_info *rx_info; + struct sk_buff *skb; + u8 *rx_buf; + unsigned long rx_size; + + hw = container_of(work, struct iwm_sdio_priv, isr_worker); + iwm = hw_to_iwm(hw); + + while (!skb_queue_empty(&iwm->rx_list)) { + skb = skb_dequeue(&iwm->rx_list); + rx_info = skb_to_rx_info(skb); + rx_size = rx_info->rx_size; + rx_buf = skb->data; + + IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size); + if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0) + IWM_WARN(iwm, "RX error\n"); + + kfree_skb(skb); + } +} + +static void iwm_sdio_isr(struct sdio_func *func) +{ + struct iwm_priv *iwm; + struct iwm_sdio_priv *hw; + struct iwm_rx_info *rx_info; + struct sk_buff *skb; + unsigned long buf_size, read_size; + int ret; + u8 val; + + hw = sdio_get_drvdata(func); + iwm = hw_to_iwm(hw); + + buf_size = hw->blk_size; + + /* We're checking the status */ + val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret); + if (val == 0 || ret < 0) { + IWM_ERR(iwm, "Wrong INTR_STATUS\n"); + return; + } + + /* See if we have free buffers */ + if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) { + IWM_ERR(iwm, "No buffer for more Rx frames\n"); + return; + } + + /* We first read the transaction size */ + read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret); + read_size = read_size << 8; + + if (ret < 0) { + IWM_ERR(iwm, "Couldn't read the xfer size\n"); + return; + } + + /* We need to clear the INT register */ + sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't clear the INT register\n"); + return; + } + + while (buf_size < read_size) + buf_size <<= 1; + + skb = dev_alloc_skb(buf_size); + if (!skb) { + IWM_ERR(iwm, "Couldn't alloc RX skb\n"); + return; + } + rx_info = skb_to_rx_info(skb); + rx_info->rx_size = read_size; + rx_info->rx_buf_size = buf_size; + + /* Now we can read the actual buffer */ + ret = sdio_memcpy_fromio(func, skb_put(skb, read_size), + IWM_SDIO_DATA_ADDR, read_size); + + /* The skb is put on a driver's specific Rx SKB list */ + skb_queue_tail(&iwm->rx_list, skb); + + /* We can now schedule the actual worker */ + queue_work(hw->isr_wq, &hw->isr_worker); +} + +static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw) +{ + struct iwm_priv *iwm = hw_to_iwm(hw); + + flush_workqueue(hw->isr_wq); + + skb_queue_purge(&iwm->rx_list); +} + +/* Bus ops */ +static int if_sdio_enable(struct iwm_priv *iwm) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + int ret; + + sdio_claim_host(hw->func); + + ret = sdio_enable_func(hw->func); + if (ret) { + IWM_ERR(iwm, "Couldn't enable the device: is TOP driver " + "loaded and functional?\n"); + goto release_host; + } + + iwm_reset(iwm); + + ret = sdio_claim_irq(hw->func, iwm_sdio_isr); + if (ret) { + IWM_ERR(iwm, "Failed to claim irq: %d\n", ret); + goto release_host; + } + + sdio_writeb(hw->func, 1, IWM_SDIO_INTR_ENABLE_ADDR, &ret); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't enable INTR: %d\n", ret); + goto release_irq; + } + + sdio_release_host(hw->func); + + IWM_DBG_SDIO(iwm, INFO, "IWM SDIO enable\n"); + + return 0; + + release_irq: + sdio_release_irq(hw->func); + release_host: + sdio_release_host(hw->func); + + return ret; +} + +static int if_sdio_disable(struct iwm_priv *iwm) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + int ret; + + iwm_reset(iwm); + + sdio_claim_host(hw->func); + sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); + if (ret < 0) + IWM_WARN(iwm, "Couldn't disable INTR: %d\n", ret); + + sdio_release_irq(hw->func); + sdio_disable_func(hw->func); + sdio_release_host(hw->func); + + iwm_sdio_rx_free(hw); + + IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); + + return 0; +} + +static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + int aligned_count = ALIGN(count, hw->blk_size); + int ret; + + if ((unsigned long)buf & 0x3) { + IWM_ERR(iwm, "buf <%p> is not dword aligned\n", buf); + /* TODO: Is this a hardware limitation? use get_unligned */ + return -EINVAL; + } + + sdio_claim_host(hw->func); + ret = sdio_memcpy_toio(hw->func, IWM_SDIO_DATA_ADDR, buf, + aligned_count); + sdio_release_host(hw->func); + + return ret; +} + +/* debugfs hooks */ +static int iwm_debugfs_sdio_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + char *buf; + u8 cccr; + int buf_len = 4096, ret; + size_t len = 0; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + sdio_claim_host(hw->func); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IOEx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IOEx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IOEx: 0x%x\n", cccr); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IORx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IORx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IORx: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IENx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IENx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IENx: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_INTx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_INTx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_INTx: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_ABORT, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_ABORTx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_ABORT: 0x%x\n", cccr); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IF, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IF\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IF: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CAPS, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_CAPS\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_CAPS: 0x%x\n", cccr); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CIS, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_CIS\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_CIS: 0x%x\n", cccr); + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); +err: + sdio_release_host(hw->func); + + kfree(buf); + + return ret; +} + +static const struct file_operations iwm_debugfs_sdio_fops = { + .owner = THIS_MODULE, + .open = iwm_debugfs_sdio_open, + .read = iwm_debugfs_sdio_read, +}; + +static int if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir) +{ + int result; + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + + hw->cccr_dentry = debugfs_create_file("cccr", 0200, + parent_dir, iwm, + &iwm_debugfs_sdio_fops); + result = PTR_ERR(hw->cccr_dentry); + if (IS_ERR(hw->cccr_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create CCCR entry: %d\n", result); + return result; + } + + return 0; +} + +static void if_sdio_debugfs_exit(struct iwm_priv *iwm) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + + debugfs_remove(hw->cccr_dentry); +} + +static struct iwm_if_ops if_sdio_ops = { + .enable = if_sdio_enable, + .disable = if_sdio_disable, + .send_chunk = if_sdio_send_chunk, + .debugfs_init = if_sdio_debugfs_init, + .debugfs_exit = if_sdio_debugfs_exit, + .umac_name = "iwmc3200wifi-umac-sdio.bin", + .calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin", + .lmac_name = "iwmc3200wifi-lmac-sdio.bin", +}; + +static int iwm_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct iwm_priv *iwm; + struct iwm_sdio_priv *hw; + struct device *dev = &func->dev; + int ret; + + /* check if TOP has already initialized the card */ + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret) { + dev_err(dev, "wait for TOP to enable the device\n"); + sdio_release_host(func); + return ret; + } + + ret = sdio_set_block_size(func, IWM_SDIO_BLK_SIZE); + + sdio_disable_func(func); + sdio_release_host(func); + + if (ret < 0) { + dev_err(dev, "Failed to set block size: %d\n", ret); + return ret; + } + + iwm = iwm_if_alloc(sizeof(struct iwm_sdio_priv), dev, &if_sdio_ops); + if (IS_ERR(iwm)) { + dev_err(dev, "allocate SDIO interface failed\n"); + return PTR_ERR(iwm); + } + + hw = iwm_private(iwm); + hw->iwm = iwm; + + ret = iwm_debugfs_init(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Debugfs registration failed\n"); + goto if_free; + } + + sdio_set_drvdata(func, hw); + + hw->func = func; + hw->blk_size = IWM_SDIO_BLK_SIZE; + + hw->isr_wq = create_singlethread_workqueue(KBUILD_MODNAME "_sdio"); + if (!hw->isr_wq) { + ret = -ENOMEM; + goto debugfs_exit; + } + + INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker); + + dev_info(dev, "IWM SDIO probe\n"); + + return 0; + + debugfs_exit: + iwm_debugfs_exit(iwm); + if_free: + iwm_if_free(iwm); + return ret; +} + +static void iwm_sdio_remove(struct sdio_func *func) +{ + struct iwm_sdio_priv *hw = sdio_get_drvdata(func); + struct iwm_priv *iwm = hw_to_iwm(hw); + struct device *dev = &func->dev; + + iwm_debugfs_exit(iwm); + iwm_if_free(iwm); + destroy_workqueue(hw->isr_wq); + + sdio_set_drvdata(func, NULL); + + dev_info(dev, "IWM SDIO remove\n"); + + return; +} + +static const struct sdio_device_id iwm_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) }, + { /* end: all zeroes */ }, +}; +MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); + +static struct sdio_driver iwm_sdio_driver = { + .name = "iwm_sdio", + .id_table = iwm_sdio_ids, + .probe = iwm_sdio_probe, + .remove = iwm_sdio_remove, +}; + +static int __init iwm_sdio_init_module(void) +{ + int ret; + + ret = sdio_register_driver(&iwm_sdio_driver); + + return ret; +} + +static void __exit iwm_sdio_exit_module(void) +{ + sdio_unregister_driver(&iwm_sdio_driver); +} + +module_init(iwm_sdio_init_module); +module_exit(iwm_sdio_exit_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(IWM_COPYRIGHT " " IWM_AUTHOR); diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h new file mode 100644 index 0000000..b3c156b --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/sdio.h @@ -0,0 +1,67 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_SDIO_H__ +#define __IWM_SDIO_H__ + +#define SDIO_VENDOR_ID_INTEL 0x89 +#define SDIO_DEVICE_ID_IWM 0x1403 + +#define IWM_SDIO_DATA_ADDR 0x0 +#define IWM_SDIO_INTR_ENABLE_ADDR 0x14 +#define IWM_SDIO_INTR_STATUS_ADDR 0x13 +#define IWM_SDIO_INTR_CLEAR_ADDR 0x13 +#define IWM_SDIO_INTR_GET_SIZE_ADDR 0x2C + +#define IWM_SDIO_BLK_SIZE 256 + +#define iwm_to_if_sdio(i) (struct iwm_sdio_priv *)(iwm->private) + +struct iwm_sdio_priv { + struct sdio_func *func; + struct iwm_priv *iwm; + + struct workqueue_struct *isr_wq; + struct work_struct isr_worker; + + struct dentry *cccr_dentry; + + unsigned int blk_size; +}; + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c new file mode 100644 index 0000000..e3b4f79 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/tx.c @@ -0,0 +1,492 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +/* + * iwm Tx theory of operation: + * + * 1) We receive a 802.3 frame from the stack + * 2) We convert it to a 802.11 frame [iwm_xmit_frame] + * 3) We queue it to its corresponding tx queue [iwm_xmit_frame] + * 4) We schedule the tx worker. There is one worker per tx + * queue. [iwm_xmit_frame] + * 5) The tx worker is scheduled + * 6) We go through every queued skb on the tx queue, and for each + * and every one of them: [iwm_tx_worker] + * a) We check if we have enough Tx credits (see below for a Tx + * credits description) for the frame length. [iwm_tx_worker] + * b) If we do, we aggregate the Tx frame into a UDMA one, by + * concatenating one REPLY_TX command per Tx frame. [iwm_tx_worker] + * c) When we run out of credits, or when we reach the maximum + * concatenation size, we actually send the concatenated UDMA + * frame. [iwm_tx_worker] + * + * When we run out of Tx credits, the skbs are filling the tx queue, + * and eventually we will stop the netdev queue. [iwm_tx_worker] + * The tx queue is emptied as we're getting new tx credits, by + * scheduling the tx_worker. [iwm_tx_credit_inc] + * The netdev queue is started again when we have enough tx credits, + * and when our tx queue has some reasonable amout of space available + * (i.e. half of the max size). [iwm_tx_worker] + */ + +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "commands.h" +#include "hal.h" +#include "umac.h" +#include "bus.h" + +#define IWM_UMAC_PAGE_ALLOC_WRAP 0xffff + +#define BYTES_TO_PAGES(n) (1 + ((n) >> ilog2(IWM_UMAC_PAGE_SIZE)) - \ + (((n) & (IWM_UMAC_PAGE_SIZE - 1)) == 0)) + +#define pool_id_to_queue(id) ((id < IWM_TX_CMD_QUEUE) ? id : id - 1) +#define queue_to_pool_id(q) ((q < IWM_TX_CMD_QUEUE) ? q : q + 1) + +/* require to hold tx_credit lock */ +static int iwm_tx_credit_get(struct iwm_tx_credit *tx_credit, int id) +{ + struct pool_entry *pool = &tx_credit->pools[id]; + struct spool_entry *spool = &tx_credit->spools[pool->sid]; + int spool_pages; + + /* number of pages can be taken from spool by this pool */ + spool_pages = spool->max_pages - spool->alloc_pages + + max(pool->min_pages - pool->alloc_pages, 0); + + return min(pool->max_pages - pool->alloc_pages, spool_pages); +} + +static bool iwm_tx_credit_ok(struct iwm_priv *iwm, int id, int nb) +{ + u32 npages = BYTES_TO_PAGES(nb); + + if (npages <= iwm_tx_credit_get(&iwm->tx_credit, id)) + return 1; + + set_bit(id, &iwm->tx_credit.full_pools_map); + + IWM_DBG_TX(iwm, DBG, "LINK: stop txq[%d], available credit: %d\n", + pool_id_to_queue(id), + iwm_tx_credit_get(&iwm->tx_credit, id)); + + return 0; +} + +void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages) +{ + struct pool_entry *pool; + struct spool_entry *spool; + int freed_pages; + int queue; + + BUG_ON(id >= IWM_MACS_OUT_GROUPS); + + pool = &iwm->tx_credit.pools[id]; + spool = &iwm->tx_credit.spools[pool->sid]; + + freed_pages = total_freed_pages - pool->total_freed_pages; + IWM_DBG_TX(iwm, DBG, "Free %d pages for pool[%d]\n", freed_pages, id); + + if (!freed_pages) { + IWM_DBG_TX(iwm, DBG, "No pages are freed by UMAC\n"); + return; + } else if (freed_pages < 0) + freed_pages += IWM_UMAC_PAGE_ALLOC_WRAP + 1; + + if (pool->alloc_pages > pool->min_pages) { + int spool_pages = pool->alloc_pages - pool->min_pages; + spool_pages = min(spool_pages, freed_pages); + spool->alloc_pages -= spool_pages; + } + + pool->alloc_pages -= freed_pages; + pool->total_freed_pages = total_freed_pages; + + IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " + "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, + pool->total_freed_pages, pool->sid, spool->alloc_pages); + + if (test_bit(id, &iwm->tx_credit.full_pools_map) && + (pool->alloc_pages < pool->max_pages / 2)) { + clear_bit(id, &iwm->tx_credit.full_pools_map); + + queue = pool_id_to_queue(id); + + IWM_DBG_TX(iwm, DBG, "LINK: start txq[%d], available " + "credit: %d\n", queue, + iwm_tx_credit_get(&iwm->tx_credit, id)); + queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); + } +} + +static void iwm_tx_credit_dec(struct iwm_priv *iwm, int id, int alloc_pages) +{ + struct pool_entry *pool; + struct spool_entry *spool; + int spool_pages; + + IWM_DBG_TX(iwm, DBG, "Allocate %d pages for pool[%d]\n", + alloc_pages, id); + + BUG_ON(id >= IWM_MACS_OUT_GROUPS); + + pool = &iwm->tx_credit.pools[id]; + spool = &iwm->tx_credit.spools[pool->sid]; + + spool_pages = pool->alloc_pages + alloc_pages - pool->min_pages; + + if (pool->alloc_pages >= pool->min_pages) + spool->alloc_pages += alloc_pages; + else if (spool_pages > 0) + spool->alloc_pages += spool_pages; + + pool->alloc_pages += alloc_pages; + + IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " + "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, + pool->total_freed_pages, pool->sid, spool->alloc_pages); +} + +int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb) +{ + u32 npages = BYTES_TO_PAGES(nb); + int ret = 0; + + spin_lock(&iwm->tx_credit.lock); + + if (!iwm_tx_credit_ok(iwm, id, nb)) { + IWM_DBG_TX(iwm, DBG, "No credit avaliable for pool[%d]\n", id); + ret = -ENOSPC; + goto out; + } + + iwm_tx_credit_dec(iwm, id, npages); + + out: + spin_unlock(&iwm->tx_credit.lock); + return ret; +} + +/* + * Since we're on an SDIO or USB bus, we are not sharing memory + * for storing to be transmitted frames. The host needs to push + * them upstream. As a consequence there needs to be a way for + * the target to let us know if it can actually take more TX frames + * or not. This is what Tx credits are for. + * + * For each Tx HW queue, we have a Tx pool, and then we have one + * unique super pool (spool), which is actually a global pool of + * all the UMAC pages. + * For each Tx pool we have a min_pages, a max_pages fields, and a + * alloc_pages fields. The alloc_pages tracks the number of pages + * currently allocated from the tx pool. + * Here are the rules to check if given a tx frame we have enough + * tx credits for it: + * 1) We translate the frame length into a number of UMAC pages. + * Let's call them n_pages. + * 2) For the corresponding tx pool, we check if n_pages + + * pool->alloc_pages is higher than pool->min_pages. min_pages + * represent a set of pre-allocated pages on the tx pool. If + * that's the case, then we need to allocate those pages from + * the spool. We can do so until we reach spool->max_pages. + * 3) Each tx pool is not allowed to allocate more than pool->max_pages + * from the spool, so once we're over min_pages, we can allocate + * pages from the spool, but not more than max_pages. + * + * When the tx code path needs to send a tx frame, it checks first + * if it has enough tx credits, following those rules. [iwm_tx_credit_get] + * If it does, it then updates the pool and spool counters and + * then send the frame. [iwm_tx_credit_alloc and iwm_tx_credit_dec] + * On the other side, when the UMAC is done transmitting frames, it + * will send a credit update notification to the host. This is when + * the pool and spool counters gets to be decreased. [iwm_tx_credit_inc, + * called from rx.c:iwm_ntf_tx_credit_update] + * + */ +void iwm_tx_credit_init_pools(struct iwm_priv *iwm, + struct iwm_umac_notif_alive *alive) +{ + int i, sid, pool_pages; + + spin_lock(&iwm->tx_credit.lock); + + iwm->tx_credit.pool_nr = le16_to_cpu(alive->page_grp_count); + iwm->tx_credit.full_pools_map = 0; + memset(&iwm->tx_credit.spools[0], 0, sizeof(struct spool_entry)); + + IWM_DBG_TX(iwm, DBG, "Pools number is %d\n", iwm->tx_credit.pool_nr); + + for (i = 0; i < iwm->tx_credit.pool_nr; i++) { + __le32 page_grp_state = alive->page_grp_state[i]; + + iwm->tx_credit.pools[i].id = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_GRP_NUM); + iwm->tx_credit.pools[i].sid = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_SGRP_NUM); + iwm->tx_credit.pools[i].min_pages = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE); + iwm->tx_credit.pools[i].max_pages = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE); + iwm->tx_credit.pools[i].alloc_pages = 0; + iwm->tx_credit.pools[i].total_freed_pages = 0; + + sid = iwm->tx_credit.pools[i].sid; + pool_pages = iwm->tx_credit.pools[i].min_pages; + + if (iwm->tx_credit.spools[sid].max_pages == 0) { + iwm->tx_credit.spools[sid].id = sid; + iwm->tx_credit.spools[sid].max_pages = + GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE); + iwm->tx_credit.spools[sid].alloc_pages = 0; + } + + iwm->tx_credit.spools[sid].alloc_pages += pool_pages; + + IWM_DBG_TX(iwm, DBG, "Pool idx: %d, id: %d, sid: %d, capacity " + "min: %d, max: %d, pool alloc: %d, total_free: %d, " + "super poll alloc: %d\n", + i, iwm->tx_credit.pools[i].id, + iwm->tx_credit.pools[i].sid, + iwm->tx_credit.pools[i].min_pages, + iwm->tx_credit.pools[i].max_pages, + iwm->tx_credit.pools[i].alloc_pages, + iwm->tx_credit.pools[i].total_freed_pages, + iwm->tx_credit.spools[sid].alloc_pages); + } + + spin_unlock(&iwm->tx_credit.lock); +} + +#define IWM_UDMA_HDR_LEN sizeof(struct iwm_umac_wifi_out_hdr) + +static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb, + int pool_id, u8 *buf) +{ + struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf; + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_tx_info *tx_info = skb_to_tx_info(skb); + + udma_cmd.count = cpu_to_le16(skb->len + + sizeof(struct iwm_umac_fw_cmd_hdr)); + /* set EOP to 0 here. iwm_udma_wifi_hdr_set_eop() will be + * called later to set EOP for the last packet. */ + udma_cmd.eop = 0; + udma_cmd.credit_group = pool_id; + udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; + udma_cmd.lmac_offset = 0; + + umac_cmd.id = REPLY_TX; + umac_cmd.count = cpu_to_le16(skb->len); + umac_cmd.color = tx_info->color; + umac_cmd.resp = 0; + umac_cmd.seq_num = cpu_to_le16(iwm_alloc_wifi_cmd_seq(iwm)); + + iwm_build_udma_wifi_hdr(iwm, &hdr->hw_hdr, &udma_cmd); + iwm_build_umac_hdr(iwm, &hdr->sw_hdr, &umac_cmd); + + memcpy(buf + sizeof(*hdr), skb->data, skb->len); + + return 0; +} + +static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, + struct iwm_tx_queue *txq) +{ + int ret; + + if (!txq->concat_count) + return 0; + + IWM_DBG_TX(iwm, DBG, "Send concatenated Tx: queue %d, %d bytes\n", + txq->id, txq->concat_count); + + /* mark EOP for the last packet */ + iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1); + + ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count); + + txq->concat_count = 0; + txq->concat_ptr = txq->concat_buf; + + return ret; +} + +#define CONFIG_IWM_TX_CONCATENATED 1 + +void iwm_tx_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + struct iwm_tx_info *tx_info = NULL; + struct sk_buff *skb; + int cmdlen, ret; + struct iwm_tx_queue *txq; + int pool_id; + + txq = container_of(work, struct iwm_tx_queue, worker); + iwm = container_of(txq, struct iwm_priv, txq[txq->id]); + + pool_id = queue_to_pool_id(txq->id); + + while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && + !skb_queue_empty(&txq->queue)) { + + skb = skb_dequeue(&txq->queue); + tx_info = skb_to_tx_info(skb); + cmdlen = IWM_UDMA_HDR_LEN + skb->len; + + IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " + "%d, color: %d\n", txq->id, skb, tx_info->sta, + tx_info->color); + +#if !CONFIG_IWM_TX_CONCATENATED + /* temporarily keep this to comparing the performance */ + ret = iwm_send_packet(iwm, skb, pool_id); +#else + + if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE) + iwm_tx_send_concat_packets(iwm, txq); + + ret = iwm_tx_credit_alloc(iwm, pool_id, cmdlen); + if (ret) { + IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " + "%d, Tx worker stopped\n", txq->id); + skb_queue_head(&txq->queue, skb); + break; + } + + txq->concat_ptr = txq->concat_buf + txq->concat_count; + iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); + txq->concat_count += ALIGN(cmdlen, 16); +#endif + kfree_skb(skb); + } + + iwm_tx_send_concat_packets(iwm, txq); + + if (__netif_subqueue_stopped(iwm_to_ndev(iwm), txq->id) && + !test_bit(pool_id, &iwm->tx_credit.full_pools_map) && + (skb_queue_len(&txq->queue) < IWM_TX_LIST_SIZE / 2)) { + IWM_DBG_TX(iwm, DBG, "LINK: start netif_subqueue[%d]", txq->id); + netif_wake_subqueue(iwm_to_ndev(iwm), txq->id); + } +} + +int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct iwm_priv *iwm = ndev_to_iwm(netdev); + struct net_device *ndev = iwm_to_ndev(iwm); + struct wireless_dev *wdev = iwm_to_wdev(iwm); + u8 *dst_addr; + struct iwm_tx_info *tx_info; + struct iwm_tx_queue *txq; + struct iwm_sta_info *sta_info; + u8 sta_id; + u16 queue; + int ret; + + if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " + "not associated\n"); + netif_tx_stop_all_queues(netdev); + goto drop; + } + + queue = skb_get_queue_mapping(skb); + BUG_ON(queue >= IWM_TX_DATA_QUEUES); /* no iPAN yet */ + + txq = &iwm->txq[queue]; + + /* No free space for Tx, tx_worker is too slow */ + if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { + IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); + netif_stop_subqueue(netdev, queue); + return NETDEV_TX_BUSY; + } + + ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype, + iwm->bssid, 0); + if (ret) { + IWM_ERR(iwm, "build wifi header failed\n"); + goto drop; + } + + dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1; + + for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) { + sta_info = &iwm->sta_table[sta_id]; + if (sta_info->valid && + !memcmp(dst_addr, sta_info->addr, ETH_ALEN)) + break; + } + + if (sta_id == IWM_STA_TABLE_NUM) { + IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n", + dst_addr); + goto drop; + } + + tx_info = skb_to_tx_info(skb); + tx_info->sta = sta_id; + tx_info->color = sta_info->color; + /* UMAC uses TID 8 (vs. 0) for non QoS packets */ + if (sta_info->qos) + tx_info->tid = skb->priority; + else + tx_info->tid = IWM_UMAC_MGMT_TID; + + skb_queue_tail(&iwm->txq[queue].queue, skb); + + queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); + + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + return NETDEV_TX_OK; + + drop: + ndev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h new file mode 100644 index 0000000..4a95cce --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -0,0 +1,744 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_UMAC_H__ +#define __IWM_UMAC_H__ + +struct iwm_udma_in_hdr { + __le32 cmd; + __le32 size; +} __attribute__ ((packed)); + +struct iwm_udma_out_nonwifi_hdr { + __le32 cmd; + __le32 addr; + __le32 op1_sz; + __le32 op2; +} __attribute__ ((packed)); + +struct iwm_udma_out_wifi_hdr { + __le32 cmd; + __le32 meta_data; +} __attribute__ ((packed)); + +/* Sequence numbering */ +#define UMAC_WIFI_SEQ_NUM_BASE 1 +#define UMAC_WIFI_SEQ_NUM_MAX 0x4000 +#define UMAC_NONWIFI_SEQ_NUM_BASE 1 +#define UMAC_NONWIFI_SEQ_NUM_MAX 0x10 + +/* MAC address address */ +#define WICO_MAC_ADDRESS_ADDR 0x604008F8 + +/* RA / TID */ +#define UMAC_HDI_ACT_TBL_IDX_TID_POS 0 +#define UMAC_HDI_ACT_TBL_IDX_TID_SEED 0xF + +#define UMAC_HDI_ACT_TBL_IDX_RA_POS 4 +#define UMAC_HDI_ACT_TBL_IDX_RA_SEED 0xF + +#define UMAC_HDI_ACT_TBL_IDX_RA_UMAC 0xF +#define UMAC_HDI_ACT_TBL_IDX_TID_UMAC 0x9 +#define UMAC_HDI_ACT_TBL_IDX_TID_LMAC 0xA + +#define UMAC_HDI_ACT_TBL_IDX_HOST_CMD \ + ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ + (UMAC_HDI_ACT_TBL_IDX_TID_UMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) +#define UMAC_HDI_ACT_TBL_IDX_UMAC_CMD \ + ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ + (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) + +/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ +#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 +#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF + +/* iwm_umac_notif_alive.page_grp_state Super group number -- bits [7:4] */ +#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_POS 4 +#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_SEED 0xF + +/* iwm_umac_notif_alive.page_grp_state Group min size -- bits [15:8] */ +#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_POS 8 +#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_SEED 0xFF + +/* iwm_umac_notif_alive.page_grp_state Group max size -- bits [23:16] */ +#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_POS 16 +#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_SEED 0xFF + +/* iwm_umac_notif_alive.page_grp_state Super group max size -- bits [31:24] */ +#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_POS 24 +#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_SEED 0xFF + +/* Barkers */ +#define UMAC_REBOOT_BARKER 0xdeadbeef +#define UMAC_ACK_BARKER 0xfeedbabe +#define UMAC_PAD_TERMINAL 0xadadadad + +/* UMAC JMP address */ +#define UMAC_MU_FW_INST_DATA_12_ADDR 0xBF0000 + +/* iwm_umac_hdi_out_hdr.cmd OP code -- bits [3:0] */ +#define UMAC_HDI_OUT_CMD_OPCODE_POS 0 +#define UMAC_HDI_OUT_CMD_OPCODE_SEED 0xF + +/* iwm_umac_hdi_out_hdr.cmd End-Of-Transfer -- bits [10:10] */ +#define UMAC_HDI_OUT_CMD_EOT_POS 10 +#define UMAC_HDI_OUT_CMD_EOT_SEED 0x1 + +/* iwm_umac_hdi_out_hdr.cmd UTFD only usage -- bits [11:11] */ +#define UMAC_HDI_OUT_CMD_UTFD_ONLY_POS 11 +#define UMAC_HDI_OUT_CMD_UTFD_ONLY_SEED 0x1 + +/* iwm_umac_hdi_out_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ +#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 +#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF + +/* iwm_umac_hdi_out_hdr.cmd Signature -- bits [31:16] */ +#define UMAC_HDI_OUT_CMD_SIGNATURE_POS 16 +#define UMAC_HDI_OUT_CMD_SIGNATURE_SEED 0xFFFF + +/* iwm_umac_hdi_out_hdr.meta_data Byte count -- bits [11:0] */ +#define UMAC_HDI_OUT_BYTE_COUNT_POS 0 +#define UMAC_HDI_OUT_BYTE_COUNT_SEED 0xFFF + +/* iwm_umac_hdi_out_hdr.meta_data Credit group -- bits [15:12] */ +#define UMAC_HDI_OUT_CREDIT_GRP_POS 12 +#define UMAC_HDI_OUT_CREDIT_GRP_SEED 0xF + +/* iwm_umac_hdi_out_hdr.meta_data RA/TID -- bits [23:16] */ +#define UMAC_HDI_OUT_RATID_POS 16 +#define UMAC_HDI_OUT_RATID_SEED 0xFF + +/* iwm_umac_hdi_out_hdr.meta_data LMAC offset -- bits [31:24] */ +#define UMAC_HDI_OUT_LMAC_OFFSET_POS 24 +#define UMAC_HDI_OUT_LMAC_OFFSET_SEED 0xFF + +/* Signature */ +#define UMAC_HDI_OUT_SIGNATURE 0xCBBC + +/* buffer alignment */ +#define UMAC_HDI_BUF_ALIGN_MSK 0xF + +/* iwm_umac_hdi_in_hdr.cmd OP code -- bits [3:0] */ +#define UMAC_HDI_IN_CMD_OPCODE_POS 0 +#define UMAC_HDI_IN_CMD_OPCODE_SEED 0xF + +/* iwm_umac_hdi_in_hdr.cmd Non-WiFi API response -- bits [6:4] */ +#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_POS 4 +#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_SEED 0x7 + +/* iwm_umac_hdi_in_hdr.cmd WiFi API source -- bits [5:4] */ +#define UMAC_HDI_IN_CMD_SOURCE_POS 4 +#define UMAC_HDI_IN_CMD_SOURCE_SEED 0x3 + +/* iwm_umac_hdi_in_hdr.cmd WiFi API EOT -- bits [6:6] */ +#define UMAC_HDI_IN_CMD_EOT_POS 6 +#define UMAC_HDI_IN_CMD_EOT_SEED 0x1 + +/* iwm_umac_hdi_in_hdr.cmd timestamp present -- bits [7:7] */ +#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_POS 7 +#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_SEED 0x1 + +/* iwm_umac_hdi_in_hdr.cmd WiFi Non-last AMSDU -- bits [8:8] */ +#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_POS 8 +#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_SEED 0x1 + +/* iwm_umac_hdi_in_hdr.cmd WiFi HW sequence number -- bits [31:9] */ +#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_POS 9 +#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_SEED 0x7FFFFF + +/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF + +/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW signature -- bits [16:31] */ +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_POS 16 +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_SEED 0xFFFF + +/* Fixed Non-WiFi signature */ +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG 0xCBBC + +/* IN NTFY op-codes */ +#define UMAC_NOTIFY_OPCODE_ALIVE 0xA1 +#define UMAC_NOTIFY_OPCODE_INIT_COMPLETE 0xA2 +#define UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS 0xA3 +#define UMAC_NOTIFY_OPCODE_ERROR 0xA4 +#define UMAC_NOTIFY_OPCODE_DEBUG 0xA5 +#define UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER 0xB0 +#define UMAC_NOTIFY_OPCODE_STATS 0xB1 +#define UMAC_NOTIFY_OPCODE_PAGE_DEALLOC 0xB3 +#define UMAC_NOTIFY_OPCODE_RX_TICKET 0xB4 +#define UMAC_NOTIFY_OPCODE_MAX (UMAC_NOTIFY_OPCODE_RX_TICKET -\ + UMAC_NOTIFY_OPCODE_ALIVE + 1) +#define UMAC_NOTIFY_OPCODE_FIRST (UMAC_NOTIFY_OPCODE_ALIVE) + +/* HDI OUT OP CODE */ +#define UMAC_HDI_OUT_OPCODE_PING 0x0 +#define UMAC_HDI_OUT_OPCODE_READ 0x1 +#define UMAC_HDI_OUT_OPCODE_WRITE 0x2 +#define UMAC_HDI_OUT_OPCODE_JUMP 0x3 +#define UMAC_HDI_OUT_OPCODE_REBOOT 0x4 +#define UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT 0x5 +#define UMAC_HDI_OUT_OPCODE_READ_PERSISTENT 0x6 +#define UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE 0x7 +/* #define UMAC_HDI_OUT_OPCODE_RESERVED 0x8..0xA */ +#define UMAC_HDI_OUT_OPCODE_WRITE_AUX_REG 0xB +#define UMAC_HDI_OUT_OPCODE_WIFI 0xF + +/* HDI IN OP CODE -- Non WiFi*/ +#define UMAC_HDI_IN_OPCODE_PING 0x0 +#define UMAC_HDI_IN_OPCODE_READ 0x1 +#define UMAC_HDI_IN_OPCODE_WRITE 0x2 +#define UMAC_HDI_IN_OPCODE_WRITE_PERSISTENT 0x5 +#define UMAC_HDI_IN_OPCODE_READ_PERSISTENT 0x6 +#define UMAC_HDI_IN_OPCODE_READ_MODIFY_WRITE 0x7 +#define UMAC_HDI_IN_OPCODE_EP_MGMT 0x8 +#define UMAC_HDI_IN_OPCODE_CREDIT_CHANGE 0x9 +#define UMAC_HDI_IN_OPCODE_CTRL_DATABASE 0xA +#define UMAC_HDI_IN_OPCODE_WRITE_AUX_REG 0xB +#define UMAC_HDI_IN_OPCODE_NONWIFI_MAX \ + (UMAC_HDI_IN_OPCODE_WRITE_AUX_REG + 1) +#define UMAC_HDI_IN_OPCODE_WIFI 0xF + +/* HDI IN SOURCE */ +#define UMAC_HDI_IN_SOURCE_FHRX 0x0 +#define UMAC_HDI_IN_SOURCE_UDMA 0x1 +#define UMAC_HDI_IN_SOURCE_FW 0x2 +#define UMAC_HDI_IN_SOURCE_RESERVED 0x3 + +/* OUT CMD op-codes */ +#define UMAC_CMD_OPCODE_ECHO 0x01 +#define UMAC_CMD_OPCODE_HALT 0x02 +#define UMAC_CMD_OPCODE_RESET 0x03 +#define UMAC_CMD_OPCODE_BULK_EP_INACT_TIMEOUT 0x09 +#define UMAC_CMD_OPCODE_URB_CANCEL_ACK 0x0A +#define UMAC_CMD_OPCODE_DCACHE_FLUSH 0x0B +#define UMAC_CMD_OPCODE_EEPROM_PROXY 0x0C +#define UMAC_CMD_OPCODE_TX_ECHO 0x0D +#define UMAC_CMD_OPCODE_DBG_MON 0x0E +#define UMAC_CMD_OPCODE_INTERNAL_TX 0x0F +#define UMAC_CMD_OPCODE_SET_PARAM_FIX 0x10 +#define UMAC_CMD_OPCODE_SET_PARAM_VAR 0x11 +#define UMAC_CMD_OPCODE_GET_PARAM 0x12 +#define UMAC_CMD_OPCODE_DBG_EVENT_WRAPPER 0x13 +#define UMAC_CMD_OPCODE_TARGET 0x14 +#define UMAC_CMD_OPCODE_STATISTIC_REQUEST 0x15 +#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 +#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 +#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 +#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA +#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB +#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC +#define UMAC_CMD_OPCODE_WIFI_IF_WRAPPER 0xFD +#define UMAC_CMD_OPCODE_WIFI_WRAPPER 0xFE +#define UMAC_CMD_OPCODE_WIFI_PASS_THROUGH 0xFF + +/* UMAC WiFi interface op-codes */ +#define UMAC_WIFI_IF_CMD_SET_PROFILE 0x11 +#define UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE 0x12 +#define UMAC_WIFI_IF_CMD_SET_EXCLUDE_LIST 0x13 +#define UMAC_WIFI_IF_CMD_SCAN_REQUEST 0x14 +#define UMAC_WIFI_IF_CMD_SCAN_CONFIG 0x15 +#define UMAC_WIFI_IF_CMD_ADD_WEP40_KEY 0x16 +#define UMAC_WIFI_IF_CMD_ADD_WEP104_KEY 0x17 +#define UMAC_WIFI_IF_CMD_ADD_TKIP_KEY 0x18 +#define UMAC_WIFI_IF_CMD_ADD_CCMP_KEY 0x19 +#define UMAC_WIFI_IF_CMD_REMOVE_KEY 0x1A +#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B +#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C +#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E +#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 + +/* UMAC WiFi interface ports */ +#define UMAC_WIFI_IF_FLG_PORT_DEF 0x00 +#define UMAC_WIFI_IF_FLG_PORT_PAN 0x01 +#define UMAC_WIFI_IF_FLG_PORT_PAN_INVALID WIFI_IF_FLG_PORT_DEF + +/* UMAC WiFi interface actions */ +#define UMAC_WIFI_IF_FLG_ACT_GET 0x10 +#define UMAC_WIFI_IF_FLG_ACT_SET 0x20 + +/* iwm_umac_fw_cmd_hdr.meta_data byte count -- bits [11:0] */ +#define UMAC_FW_CMD_BYTE_COUNT_POS 0 +#define UMAC_FW_CMD_BYTE_COUNT_SEED 0xFFF + +/* iwm_umac_fw_cmd_hdr.meta_data status -- bits [15:12] */ +#define UMAC_FW_CMD_STATUS_POS 12 +#define UMAC_FW_CMD_STATUS_SEED 0xF + +/* iwm_umac_fw_cmd_hdr.meta_data full TX command by Driver -- bits [16:16] */ +#define UMAC_FW_CMD_TX_DRV_FULL_CMD_POS 16 +#define UMAC_FW_CMD_TX_DRV_FULL_CMD_SEED 0x1 + +/* iwm_umac_fw_cmd_hdr.meta_data TX command by FW -- bits [17:17] */ +#define UMAC_FW_CMD_TX_FW_CMD_POS 17 +#define UMAC_FW_CMD_TX_FW_CMD_SEED 0x1 + +/* iwm_umac_fw_cmd_hdr.meta_data TX plaintext mode -- bits [18:18] */ +#define UMAC_FW_CMD_TX_PLAINTEXT_POS 18 +#define UMAC_FW_CMD_TX_PLAINTEXT_SEED 0x1 + +/* iwm_umac_fw_cmd_hdr.meta_data STA color -- bits [22:20] */ +#define UMAC_FW_CMD_TX_STA_COLOR_POS 20 +#define UMAC_FW_CMD_TX_STA_COLOR_SEED 0x7 + +/* iwm_umac_fw_cmd_hdr.meta_data TX life time (TU) -- bits [31:24] */ +#define UMAC_FW_CMD_TX_LIFETIME_TU_POS 24 +#define UMAC_FW_CMD_TX_LIFETIME_TU_SEED 0xFF + +/* iwm_dev_cmd_hdr.flags Response required -- bits [5:5] */ +#define UMAC_DEV_CMD_FLAGS_RESP_REQ_POS 5 +#define UMAC_DEV_CMD_FLAGS_RESP_REQ_SEED 0x1 + +/* iwm_dev_cmd_hdr.flags Aborted command -- bits [6:6] */ +#define UMAC_DEV_CMD_FLAGS_ABORT_POS 6 +#define UMAC_DEV_CMD_FLAGS_ABORT_SEED 0x1 + +/* iwm_dev_cmd_hdr.flags Internal command -- bits [7:7] */ +#define DEV_CMD_FLAGS_FLD_INTERNAL_POS 7 +#define DEV_CMD_FLAGS_FLD_INTERNAL_SEED 0x1 + +/* Rx */ +/* Rx actions */ +#define IWM_RX_TICKET_DROP 0x0 +#define IWM_RX_TICKET_RELEASE 0x1 +#define IWM_RX_TICKET_SNIFFER 0x2 +#define IWM_RX_TICKET_ENQUEUE 0x3 + +/* Rx flags */ +#define IWM_RX_TICKET_PAD_SIZE_MSK 0x2 +#define IWM_RX_TICKET_SPECIAL_SNAP_MSK 0x4 +#define IWM_RX_TICKET_AMSDU_MSK 0x8 +#define IWM_RX_TICKET_DROP_REASON_POS 4 +#define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << RX_TICKET_FLAGS_DROP_REASON_POS) + +#define IWM_RX_DROP_NO_DROP 0x0 +#define IWM_RX_DROP_BAD_CRC 0x1 +/* L2P no address match */ +#define IWM_RX_DROP_LMAC_ADDR_FILTER 0x2 +/* Multicast address not in list */ +#define IWM_RX_DROP_MCAST_ADDR_FILTER 0x3 +/* Control frames are not sent to the driver */ +#define IWM_RX_DROP_CTL_FRAME 0x4 +/* Our frame is back */ +#define IWM_RX_DROP_OUR_TX 0x5 +/* Association class filtering */ +#define IWM_RX_DROP_CLASS_FILTER 0x6 +/* Duplicated frame */ +#define IWM_RX_DROP_DUPLICATE_FILTER 0x7 +/* Decryption error */ +#define IWM_RX_DROP_SEC_ERR 0x8 +/* Unencrypted frame while encryption is on */ +#define IWM_RX_DROP_SEC_NO_ENCRYPTION 0x9 +/* Replay check failure */ +#define IWM_RX_DROP_SEC_REPLAY_ERR 0xa +/* uCode and FW key color mismatch, check before replay */ +#define IWM_RX_DROP_SEC_KEY_COLOR_MISMATCH 0xb +#define IWM_RX_DROP_SEC_TKIP_COUNTER_MEASURE 0xc +/* No fragmentations Db is found */ +#define IWM_RX_DROP_FRAG_NO_RESOURCE 0xd +/* Fragmention Db has seqCtl mismatch Vs. non-1st frag */ +#define IWM_RX_DROP_FRAG_ERR 0xe +#define IWM_RX_DROP_FRAG_LOST 0xf +#define IWM_RX_DROP_FRAG_COMPLETE 0x10 +/* Should be handled by UMAC */ +#define IWM_RX_DROP_MANAGEMENT 0x11 +/* STA not found by UMAC */ +#define IWM_RX_DROP_NO_STATION 0x12 +/* NULL or QoS NULL */ +#define IWM_RX_DROP_NULL_DATA 0x13 +#define IWM_RX_DROP_BA_REORDER_OLD_SEQCTL 0x14 +#define IWM_RX_DROP_BA_REORDER_DUPLICATE 0x15 + +struct iwm_rx_ticket { + __le16 action; + __le16 id; + __le16 flags; + u8 payload_offset; /* includes: MAC header, pad, IV */ + u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */ +} __attribute__ ((packed)); + +struct iwm_rx_mpdu_hdr { + __le16 len; + __le16 reserved; +} __attribute__ ((packed)); + +/* UMAC SW WIFI API */ + +struct iwm_dev_cmd_hdr { + u8 cmd; + u8 flags; + __le16 seq_num; +} __attribute__ ((packed)); + +struct iwm_umac_fw_cmd_hdr { + __le32 meta_data; + struct iwm_dev_cmd_hdr cmd; +} __attribute__ ((packed)); + +struct iwm_umac_wifi_out_hdr { + struct iwm_udma_out_wifi_hdr hw_hdr; + struct iwm_umac_fw_cmd_hdr sw_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_nonwifi_out_hdr { + struct iwm_udma_out_nonwifi_hdr hw_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_wifi_in_hdr { + struct iwm_udma_in_hdr hw_hdr; + struct iwm_umac_fw_cmd_hdr sw_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_nonwifi_in_hdr { + struct iwm_udma_in_hdr hw_hdr; + __le32 time_stamp; +} __attribute__ ((packed)); + +#define IWM_UMAC_PAGE_SIZE 0x200 + +/* Notify structures */ +struct iwm_fw_version { + u8 minor; + u8 major; + __le16 id; +}; + +struct iwm_fw_build { + u8 type; + u8 subtype; + u8 platform; + u8 opt; +}; + +struct iwm_fw_alive_hdr { + struct iwm_fw_version ver; + struct iwm_fw_build build; + __le32 os_build; + __le32 log_hdr_addr; + __le32 log_buf_addr; + __le32 sys_timer_addr; +}; + +#define WAIT_NOTIF_TIMEOUT (2 * HZ) +#define SCAN_COMPLETE_TIMEOUT (3 * HZ) + +#define UMAC_NTFY_ALIVE_STATUS_ERR 0xDEAD +#define UMAC_NTFY_ALIVE_STATUS_OK 0xCAFE + +#define UMAC_NTFY_INIT_COMPLETE_STATUS_ERR 0xDEAD +#define UMAC_NTFY_INIT_COMPLETE_STATUS_OK 0xCAFE + +#define UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN 0x40 +#define UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN 0x80 + +#define IWM_MACS_OUT_GROUPS 6 +#define IWM_MACS_OUT_SGROUPS 1 + + +#define WIFI_IF_NTFY_ASSOC_START 0x80 +#define WIFI_IF_NTFY_ASSOC_COMPLETE 0x81 +#define WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE 0x82 +#define WIFI_IF_NTFY_CONNECTION_TERMINATED 0x83 +#define WIFI_IF_NTFY_SCAN_COMPLETE 0x84 +#define WIFI_IF_NTFY_STA_TABLE_CHANGE 0x85 +#define WIFI_IF_NTFY_EXTENDED_IE_REQUIRED 0x86 +#define WIFI_IF_NTFY_RADIO_PREEMPTION 0x87 +#define WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED 0x88 +#define WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED 0x89 +#define WIFI_IF_NTFY_LINK_QUALITY_STATISTICS 0x8A +#define WIFI_IF_NTFY_MGMT_FRAME 0x8B + +/* DEBUG INDICATIONS */ +#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START 0xE0 +#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE 0xE1 +#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START 0xE2 +#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT 0xE3 +#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START 0xE4 +#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE 0xE5 +#define WIFI_DBG_IF_NTFY_CNCT_ATC_START 0xE6 +#define WIFI_DBG_IF_NTFY_COEX_NOTIFICATION 0xE7 +#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 +#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 + +/* Notification structures */ +struct iwm_umac_notif_wifi_if { + struct iwm_umac_wifi_in_hdr hdr; + u8 status; + u8 flags; + __le16 buf_size; +} __attribute__ ((packed)); + +#define UMAC_ROAM_REASON_FIRST_SELECTION 0x1 +#define UMAC_ROAM_REASON_AP_DEAUTH 0x2 +#define UMAC_ROAM_REASON_AP_CONNECT_LOST 0x3 +#define UMAC_ROAM_REASON_RSSI 0x4 +#define UMAC_ROAM_REASON_AP_ASSISTED_ROAM 0x5 +#define UMAC_ROAM_REASON_IBSS_COALESCING 0x6 + +struct iwm_umac_notif_assoc_start { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 roam_reason; + u8 bssid[ETH_ALEN]; + u8 reserved[2]; +} __attribute__ ((packed)); + +#define UMAC_ASSOC_COMPLETE_SUCCESS 0x0 +#define UMAC_ASSOC_COMPLETE_FAILURE 0x1 + +struct iwm_umac_notif_assoc_complete { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 status; + u8 bssid[ETH_ALEN]; + u8 band; + u8 channel; +} __attribute__ ((packed)); + +#define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0 +#define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1 +#define UMAC_PROFILE_INVALID_REQUEST 0x2 +#define UMAC_PROFILE_INVALID_RF_PREEMPTED 0x3 + +struct iwm_umac_notif_profile_invalidate { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 reason; +} __attribute__ ((packed)); + +#define UMAC_SCAN_RESULT_SUCCESS 0x0 +#define UMAC_SCAN_RESULT_ABORTED 0x1 +#define UMAC_SCAN_RESULT_REJECTED 0x2 +#define UMAC_SCAN_RESULT_FAILED 0x3 + +struct iwm_umac_notif_scan_complete { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 type; + __le32 result; + u8 seq_num; +} __attribute__ ((packed)); + +#define UMAC_OPCODE_ADD_MODIFY 0x0 +#define UMAC_OPCODE_REMOVE 0x1 +#define UMAC_OPCODE_CLEAR_ALL 0x2 + +#define UMAC_STA_FLAG_QOS 0x1 + +struct iwm_umac_notif_sta_info { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 opcode; + u8 mac_addr[ETH_ALEN]; + u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */ + u8 flags; +} __attribute__ ((packed)); + +#define UMAC_BAND_2GHZ 0 +#define UMAC_BAND_5GHZ 1 + +#define UMAC_CHANNEL_WIDTH_20MHZ 0 +#define UMAC_CHANNEL_WIDTH_40MHZ 1 + +struct iwm_umac_notif_bss_info { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 type; + __le32 timestamp; + __le16 table_idx; + __le16 frame_len; + u8 band; + u8 channel; + s8 rssi; + u8 reserved; + u8 frame_buf[1]; +} __attribute__ ((packed)); + +#define IWM_BSS_REMOVE_INDEX_MSK 0x0fff +#define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00 + +#define IWM_BSS_REMOVE_FLG_AGE 0x1000 +#define IWM_BSS_REMOVE_FLG_TIMEOUT 0x2000 +#define IWM_BSS_REMOVE_FLG_TABLE_FULL 0x4000 + +struct iwm_umac_notif_bss_removed { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 count; + __le16 entries[0]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_mgt_frame { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le16 len; + u8 frame[1]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_alive { + struct iwm_umac_wifi_in_hdr hdr; + __le16 status; + __le16 reserved1; + struct iwm_fw_alive_hdr alive_data; + __le16 reserved2; + __le16 page_grp_count; + __le32 page_grp_state[IWM_MACS_OUT_GROUPS]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_init_complete { + __le16 status; + __le16 reserved; +} __attribute__ ((packed)); + +/* error categories */ +enum { + UMAC_SYS_ERR_CAT_NONE = 0, + UMAC_SYS_ERR_CAT_BOOT, + UMAC_SYS_ERR_CAT_UMAC, + UMAC_SYS_ERR_CAT_UAXM, + UMAC_SYS_ERR_CAT_LMAC, + UMAC_SYS_ERR_CAT_MAX +}; + +struct iwm_fw_error_hdr { + __le32 category; + __le32 status; + __le32 pc; + __le32 blink1; + __le32 blink2; + __le32 ilink1; + __le32 ilink2; + __le32 data1; + __le32 data2; + __le32 line_num; + __le32 umac_status; + __le32 lmac_status; + __le32 sdio_status; +} __attribute__ ((packed)); + +struct iwm_umac_notif_error { + struct iwm_umac_wifi_in_hdr hdr; + struct iwm_fw_error_hdr err; +} __attribute__ ((packed)); + +#define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0 +#define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff +#define UMAC_DEALLOC_NTFY_CHANGES_MSK_POS 8 +#define UMAC_DEALLOC_NTFY_CHANGES_MSK_SEED 0xffffff +#define UMAC_DEALLOC_NTFY_PAGE_CNT_POS 0 +#define UMAC_DEALLOC_NTFY_PAGE_CNT_SEED 0xffffff +#define UMAC_DEALLOC_NTFY_GROUP_NUM_POS 24 +#define UMAC_DEALLOC_NTFY_GROUP_NUM_SEED 0xf + +struct iwm_umac_notif_page_dealloc { + struct iwm_umac_wifi_in_hdr hdr; + __le32 changes; + __le32 grp_info[IWM_MACS_OUT_GROUPS]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_wifi_status { + struct iwm_umac_wifi_in_hdr hdr; + __le16 status; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwm_umac_notif_rx_ticket { + struct iwm_umac_wifi_in_hdr hdr; + u8 num_tickets; + u8 reserved[3]; + struct iwm_rx_ticket tickets[1]; +} __attribute__ ((packed)); + +/* Tx/Rx rates window (number of max of last update window per second) */ +#define UMAC_NTF_RATE_SAMPLE_NR 4 + +#define IWM_UMAC_MGMT_TID 8 +#define IWM_UMAC_TID_NR 8 + +struct iwm_umac_notif_stats { + struct iwm_umac_wifi_in_hdr hdr; + __le32 flags; + __le32 timestamp; + __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ + __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; + __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; + s32 rssi_dbm; + s32 noise_dbm; + __le32 supp_rates; + __le32 missed_beacons; + __le32 rx_beacons; + __le32 rx_dir_pkts; + __le32 rx_nondir_pkts; + __le32 rx_multicast; + __le32 rx_errors; + __le32 rx_drop_other_bssid; + __le32 rx_drop_decode; + __le32 rx_drop_reassembly; + __le32 rx_drop_bad_len; + __le32 rx_drop_overflow; + __le32 rx_drop_crc; + __le32 rx_drop_missed; + __le32 tx_dir_pkts; + __le32 tx_nondir_pkts; + __le32 tx_failure; + __le32 tx_errors; + __le32 tx_drop_max_retry; + __le32 tx_err_abort; + __le32 tx_err_carrier; + __le32 rx_bytes; + __le32 tx_bytes; + __le32 tx_power; + __le32 tx_max_power; + __le32 roam_threshold; + __le32 ap_assoc_nr; + __le32 scan_full; + __le32 scan_abort; + __le32 ap_nr; + __le32 roam_nr; + __le32 roam_missed_beacons; + __le32 roam_rssi; + __le32 roam_unassoc; + __le32 roam_deauth; + __le32 roam_ap_loadblance; +} __attribute__ ((packed)); + +/* WiFi interface wrapper header */ +struct iwm_umac_wifi_if { + u8 oid; + u8 flags; + __le16 buf_size; +} __attribute__ ((packed)); + +#define IWM_SEQ_NUM_HOST_MSK 0x0000 +#define IWM_SEQ_NUM_UMAC_MSK 0x4000 +#define IWM_SEQ_NUM_LMAC_MSK 0x8000 +#define IWM_SEQ_NUM_MSK 0xC000 + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c new file mode 100644 index 0000000..584c94d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -0,0 +1,723 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "umac.h" +#include "commands.h" +#include "debug.h" + +static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iw_statistics *wstats = &iwm->wstats; + + if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + memset(wstats, 0, sizeof(struct iw_statistics)); + wstats->qual.updated = IW_QUAL_ALL_INVALID; + } + + return wstats; +} + +static int iwm_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (freq->flags == IW_FREQ_AUTO) + return 0; + + /* frequency/channel can only be set in IBSS mode */ + if (iwm->conf.mode != UMAC_MODE_IBSS) + return -EOPNOTSUPP; + + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); +} + +static int iwm_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + + freq->e = 0; + freq->m = iwm->channel; + + return 0; +} + +static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (is_zero_ether_addr(ap_addr->sa_data) || + is_broadcast_ether_addr(ap_addr->sa_data)) { + IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n", + iwm->umac_profile->bssid[0]); + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); + iwm->umac_profile->bss_num = 0; + } else { + IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n", + ap_addr->sa_data); + memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data, + ETH_ALEN); + iwm->umac_profile->bss_num = 1; + } + + if (iwm->umac_profile_active) { + if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) + return 0; + + iwm_invalidate_mlme_profile(iwm); + } + + if (iwm->umac_profile->ssid.ssid_len) + return iwm_send_mlme_profile(iwm); + + return 0; +} + +static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); + case UMAC_MODE_BSS: + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + ap_addr->sa_family = ARPHRD_ETHER; + memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN); + } else + memset(&ap_addr->sa_data, 0, ETH_ALEN); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int iwm_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + size_t len = data->length; + int ret; + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (len > 0 && ssid[len - 1] == '\0') + len--; + + if (iwm->umac_profile_active) { + if (iwm->umac_profile->ssid.ssid_len == len && + !memcmp(iwm->umac_profile->ssid.ssid, ssid, len)) + return 0; + + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + + iwm->umac_profile->ssid.ssid_len = len; + memcpy(iwm->umac_profile->ssid.ssid, ssid, len); + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + data->length = iwm->umac_profile->ssid.ssid_len; + if (data->length) { + memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length); + data->flags = 1; + } else + data->flags = 0; + + return 0; +} + +static struct iwm_key * +iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use, + struct iw_encode_ext *ext, u8 alg) +{ + struct iwm_key *key = &iwm->keys[key_idx]; + + memset(key, 0, sizeof(struct iwm_key)); + memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN); + key->hdr.key_idx = key_idx; + if (is_broadcast_ether_addr(ext->addr.sa_data)) + key->hdr.multicast = 1; + + key->in_use = in_use; + key->flags = ext->ext_flags; + key->alg = alg; + key->key_len = ext->key_len; + memcpy(key->key, ext->key, ext->key_len); + + return key; +} + +static int iwm_wext_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + rate->value = iwm->rate * 1000000; + + return 0; +} + +static int iwm_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key_buf) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iwm_key *uninitialized_var(key); + int idx, i, uninitialized_var(alg), remove = 0, ret; + + IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length); + IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); + + if (!iwm->umac_profile) { + IWM_ERR(iwm, "UMAC profile not allocated yet\n"); + return -ENODEV; + } + + if (erq->length == WLAN_KEY_LEN_WEP40) { + alg = UMAC_CIPHER_TYPE_WEP_40; + iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40; + iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; + } else if (erq->length == WLAN_KEY_LEN_WEP104) { + alg = UMAC_CIPHER_TYPE_WEP_104; + iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104; + iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104; + } + + if (erq->flags & IW_ENCODE_RESTRICTED) + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + else + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + if (iwm->default_key) + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + else + iwm->default_key = &iwm->keys[idx]; + } else if (idx < 1 || idx > 4) { + return -EINVAL; + } else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + else if (erq->length == 0) { + if (!iwm->keys[idx].in_use) + return -EINVAL; + iwm->default_key = &iwm->keys[idx]; + } + + if (erq->length) { + key = &iwm->keys[idx]; + memset(key, 0, sizeof(struct iwm_key)); + memset(key->hdr.mac, 0xff, ETH_ALEN); + key->hdr.key_idx = idx; + key->hdr.multicast = 1; + key->in_use = !remove; + key->alg = alg; + key->key_len = erq->length; + memcpy(key->key, key_buf, erq->length); + + IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n", + idx, !!iwm->default_key); + } + + if (remove) { + if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) { + int j; + for (j = 0; j < IWM_NUM_KEYS; j++) + if (iwm->keys[j].in_use) { + struct iwm_key *k = &iwm->keys[j]; + + k->in_use = 0; + ret = iwm_set_key(iwm, remove, 0, k); + if (ret < 0) + return ret; + } + + iwm->umac_profile->sec.ucast_cipher = + UMAC_CIPHER_TYPE_NONE; + iwm->umac_profile->sec.mcast_cipher = + UMAC_CIPHER_TYPE_NONE; + iwm->umac_profile->sec.auth_type = + UMAC_AUTH_TYPE_OPEN; + + return 0; + } else { + key->in_use = 0; + return iwm_set_key(iwm, remove, 0, key); + } + } + + /* + * If we havent set a profile yet, we cant set keys. + * Keys will be pushed after we're associated. + */ + if (!iwm->umac_profile_active) + return 0; + + /* + * If there is a current active profile, but no + * default key, it's not worth trying to associate again. + */ + if (!iwm->default_key) + return 0; + + /* + * Here we have an active profile, but a key setting changed. + * We thus have to invalidate the current profile, and push the + * new one. Keys will be pushed when association takes place. + */ + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + int idx, i; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx < 1 || idx > 4) { + idx = -1; + if (!iwm->default_key) { + erq->length = 0; + erq->flags |= IW_ENCODE_NOKEY; + return 0; + } else + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + if (idx < 0) + return -EINVAL; + } else + idx--; + + erq->flags = idx + 1; + + if (!iwm->keys[idx].in_use) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + + memcpy(key, iwm->keys[idx].key, + min_t(int, erq->length, iwm->keys[idx].key_len)); + erq->length = iwm->keys[idx].key_len; + erq->flags |= IW_ENCODE_ENABLED; + + if (iwm->umac_profile->mode == UMAC_MODE_BSS) { + switch (iwm->umac_profile->sec.auth_type) { + case UMAC_AUTH_TYPE_OPEN: + erq->flags |= IW_ENCODE_OPEN; + break; + default: + erq->flags |= IW_ENCODE_RESTRICTED; + break; + } + } + + return 0; +} + +static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) +{ + if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; + else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; + else + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + + return 0; +} + +static int iwm_wext_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + u32 power_index; + + if (wrq->disabled) { + power_index = IWM_POWER_INDEX_MIN; + goto set; + } else + power_index = IWM_POWER_INDEX_DEFAULT; + + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_ON: + case IW_POWER_MODE: + case IW_POWER_ALL_R: + break; + default: + return -EINVAL; + } + + set: + if (power_index == iwm->conf.power_index) + return 0; + + iwm->conf.power_index = power_index; + + return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); +} + +static int iwm_wext_giwpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN); + + return 0; +} + +static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) + *auth_type = UMAC_AUTH_TYPE_8021X; + else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + else + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } else { + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); + return -EINVAL; + } + + return 0; +} + +static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast) +{ + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : + &iwm->umac_profile->sec.mcast_cipher; + + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + break; + case IW_AUTH_CIPHER_WEP40: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; + break; + case IW_AUTH_CIPHER_TKIP: + *profile_cipher = UMAC_CIPHER_TYPE_TKIP; + break; + case IW_AUTH_CIPHER_CCMP: + *profile_cipher = UMAC_CIPHER_TYPE_CCMP; + break; + case IW_AUTH_CIPHER_WEP104: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; + break; + default: + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + switch (auth_alg) { + case IW_AUTH_ALG_OPEN_SYSTEM: + *auth_type = UMAC_AUTH_TYPE_OPEN; + break; + case IW_AUTH_ALG_SHARED_KEY: + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { + if (*auth_type == UMAC_AUTH_TYPE_8021X) + return -EINVAL; + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + } else { + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } + break; + case IW_AUTH_ALG_LEAP: + default: + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_wext_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + int ret; + + if ((data->flags) & + (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT | + IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) { + /* We need to invalidate the current profile */ + if (iwm->umac_profile_active) { + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + } + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + return iwm_set_wpa_version(iwm, data->value); + break; + case IW_AUTH_CIPHER_PAIRWISE: + return iwm_set_cipher(iwm, data->value, 1); + break; + case IW_AUTH_CIPHER_GROUP: + return iwm_set_cipher(iwm, data->value, 0); + break; + case IW_AUTH_KEY_MGMT: + return iwm_set_key_mgt(iwm, data->value); + break; + case IW_AUTH_80211_AUTH_ALG: + return iwm_set_auth_alg(iwm, data->value); + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_wext_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + return 0; +} + +static int iwm_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iwm_key *key; + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + int uninitialized_var(alg), idx, i, remove = 0; + + IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg); + IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len); + IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags); + IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); + IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length); + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + remove = 1; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len == WLAN_KEY_LEN_WEP40) + alg = UMAC_CIPHER_TYPE_WEP_40; + else if (ext->key_len == WLAN_KEY_LEN_WEP104) + alg = UMAC_CIPHER_TYPE_WEP_104; + else { + IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len); + return -EINVAL; + } + + break; + case IW_ENCODE_ALG_TKIP: + alg = UMAC_CIPHER_TYPE_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + alg = UMAC_CIPHER_TYPE_CCMP; + break; + default: + return -EOPNOTSUPP; + } + + idx = erq->flags & IW_ENCODE_INDEX; + + if (idx == 0) { + if (iwm->default_key) + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + } else if (idx < 1 || idx > 4) { + return -EINVAL; + } else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + else if ((erq->length == 0) || + (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { + iwm->default_key = &iwm->keys[idx]; + if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP) + return iwm_set_tx_key(iwm, idx); + } + + key = iwm_key_init(iwm, idx, !remove, ext, alg); + + return iwm_set_key(iwm, remove, !iwm->default_key, key); +} + +static const iw_handler iwm_handlers[] = +{ + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ + (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ + (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ + (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ + (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */ + (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */ + (iw_handler) NULL, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ + (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ + (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE */ + (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ + (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ + (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ + (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ + (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ + (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ + (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ + (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ + (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) NULL, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ + (iw_handler) NULL, /* -- hole -- */ +}; + +const struct iw_handler_def iwm_iw_handler_def = { + .num_standard = ARRAY_SIZE(iwm_handlers), + .standard = (iw_handler *) iwm_handlers, + .get_wireless_stats = iwm_get_wireless_stats, +}; + -- cgit v0.10.2 From 2c7e57981f24e9f8b732ecf1c01e16111d21b7a5 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 21 May 2009 11:32:34 -0700 Subject: libertas: read SD8688 firmware status from new register The scratch pad register is used to store firmware status after firmware is downloaded and initialized. After firmware status is verified OK, the same register is used to store RX packet length. Hence the firmware status code is no longer valid afterwards. SD8688 firmware introduces a new register for firmware status which will never be overwritten. Also add scratch_reg variable to if_sdio_card structure and initialize it based on the model of the card during probe. Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 478d766..a7e3fc1 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -100,6 +100,7 @@ struct if_sdio_card { int model; unsigned long ioport; + unsigned int scratch_reg; const char *helper; const char *firmware; @@ -119,19 +120,21 @@ struct if_sdio_card { /* I/O */ /********************************************************************/ +/* + * For SD8385/SD8686, this function reads firmware status after + * the image is downloaded, or reads RX packet length when + * interrupt (with IF_SDIO_H_INT_UPLD bit set) is received. + * For SD8688, this function reads firmware status only. + */ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) { - int ret, reg; + int ret; u16 scratch; - if (card->model == IF_SDIO_MODEL_8385) - reg = IF_SDIO_SCRATCH_OLD; - else - reg = IF_SDIO_SCRATCH; - - scratch = sdio_readb(card->func, reg, &ret); + scratch = sdio_readb(card->func, card->scratch_reg, &ret); if (!ret) - scratch |= sdio_readb(card->func, reg + 1, &ret) << 8; + scratch |= sdio_readb(card->func, card->scratch_reg + 1, + &ret) << 8; if (err) *err = ret; @@ -706,6 +709,8 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) if (ret) goto out; + lbs_deb_sdio("firmware status = %#x\n", scratch); + if (scratch == IF_SDIO_FIRMWARE_OK) { lbs_deb_sdio("firmware already loaded\n"); goto success; @@ -893,6 +898,20 @@ static int if_sdio_probe(struct sdio_func *func, card->func = func; card->model = model; + + switch (card->model) { + case IF_SDIO_MODEL_8385: + card->scratch_reg = IF_SDIO_SCRATCH_OLD; + break; + case IF_SDIO_MODEL_8686: + card->scratch_reg = IF_SDIO_SCRATCH; + break; + case IF_SDIO_MODEL_8688: + default: /* for newer chipsets */ + card->scratch_reg = IF_SDIO_FW_STATUS; + break; + } + spin_lock_init(&card->lock); card->workqueue = create_workqueue("libertas_sdio"); INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index d3a4fbe..60c9b2f 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h @@ -42,6 +42,7 @@ #define IF_SDIO_SCRATCH 0x34 #define IF_SDIO_SCRATCH_OLD 0x80fe +#define IF_SDIO_FW_STATUS 0x40 #define IF_SDIO_FIRMWARE_OK 0xfedc #define IF_SDIO_RX_LEN 0x42 -- cgit v0.10.2 From 749e091ee0065ed366cc26c115abc237e07ed786 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Thu, 21 May 2009 13:44:21 -0700 Subject: iwl3945: improve 3945 leds 'tpt' is a delta throughput (number of packets) and is corelated to brightness of the LED. We already maintain a delta of packets in rxtxpackets. There is no need to calculate this delta again which was affecting the behaviour of LEDS. Also add two new callback functions for ASSOCIATED/DISASSOCIATED states where LED's will be *on* for associated state and *off* for disassociated state. This fixes http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1771. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index ac22f59..bd7e520 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -44,6 +44,15 @@ #include "iwl-core.h" #include "iwl-dev.h" +#ifdef CONFIG_IWLWIFI_DEBUG +static const char *led_type_str[] = { + __stringify(IWL_LED_TRG_TX), + __stringify(IWL_LED_TRG_RX), + __stringify(IWL_LED_TRG_ASSOC), + __stringify(IWL_LED_TRG_RADIO), + NULL +}; +#endif /* CONFIG_IWLWIFI_DEBUG */ static const struct { u16 brightness; @@ -61,7 +70,7 @@ static const struct { {10, 110, 110}, {5, 130, 130}, {0, 167, 167}, - /*SOLID_ON*/ + /* SOLID_ON */ {-1, IWL_LED_SOLID, 0} }; @@ -143,6 +152,30 @@ static int iwl3945_led_off(struct iwl_priv *priv, int led_id) } /* + * Set led on in case of association + * */ +static int iwl3945_led_associate(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED(priv, "Associated\n"); + + priv->allow_blinking = 1; + return iwl3945_led_on(priv, led_id); +} +/* Set Led off in case of disassociation */ +static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED(priv, "Disassociated\n"); + + priv->allow_blinking = 0; + if (iwl_is_rfkill(priv)) + iwl3945_led_off(priv, led_id); + else + iwl3945_led_on(priv, led_id); + + return 0; +} + +/* * brightness call back function for Tx/Rx LED */ static int iwl3945_led_associated(struct iwl_priv *priv, int led_id) @@ -165,26 +198,21 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { struct iwl_led *led = container_of(led_cdev, - struct iwl_led, led_dev); + struct iwl_led, led_dev); struct iwl_priv *priv = led->priv; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n", + led_type_str[led->type], brightness); + switch (brightness) { case LED_FULL: - if (led->type == IWL_LED_TRG_ASSOC) { - priv->allow_blinking = 1; - IWL_DEBUG_LED(priv, "MAC is associated\n"); - } if (led->led_on) led->led_on(priv, IWL_LED_LINK); break; case LED_OFF: - if (led->type == IWL_LED_TRG_ASSOC) { - priv->allow_blinking = 0; - IWL_DEBUG_LED(priv, "MAC is disassociated\n"); - } if (led->led_off) led->led_off(priv, IWL_LED_LINK); break; @@ -197,8 +225,6 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, } } - - /* * Register led class with the system */ @@ -237,12 +263,12 @@ static int iwl3945_led_register_led(struct iwl_priv *priv, static inline u8 get_blink_rate(struct iwl_priv *priv) { int index; - u64 current_tpt = priv->rxtxpackets; - s64 tpt = current_tpt - priv->led_tpt; + s64 tpt = priv->rxtxpackets; if (tpt < 0) tpt = -tpt; - priv->led_tpt = current_tpt; + + IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt); if (!priv->allow_blinking) index = IWL_MAX_BLINK_TBL; @@ -250,13 +276,9 @@ static inline u8 get_blink_rate(struct iwl_priv *priv) for (index = 0; index < IWL_MAX_BLINK_TBL; index++) if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE)) break; - return index; -} -static inline int is_rf_kill(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index); + return index; } /* @@ -272,7 +294,7 @@ void iwl3945_led_background(struct iwl_priv *priv) priv->last_blink_time = 0; return; } - if (is_rf_kill(priv)) { + if (iwl_is_rfkill(priv)) { priv->last_blink_time = 0; return; } @@ -341,8 +363,8 @@ int iwl3945_led_register(struct iwl_priv *priv) IWL_LED_TRG_ASSOC, 0, trigger); /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on; + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate; priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; if (ret) -- cgit v0.10.2 From 2681b20ba2a255ea20a168c0ebe519c40b55e57e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 21 May 2009 13:44:22 -0700 Subject: iwlwifi: add Greenfield support for 11n Add "Greenfield" support for all devices except 4965 and 3945. "Greenfield" is part of 11n features to improve HT performance. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 4c88e87..a1b0ff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -652,19 +652,19 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, return 1; } -/* FIXME:RS: in 4965 we don't use greenfield at all */ -/* FIXME:RS: don't use greenfield for now in TX */ -#if 0 -static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) +/* in 4965 we don't use greenfield at all */ +static inline u8 rs_use_green(struct iwl_priv *priv, + struct ieee80211_conf *conf) { - return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present; -} -#endif -static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) -{ - return 0; + u8 is_green; + + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) + is_green = 0; + else + is_green = (conf_is_ht(conf) && + priv->current_ht_config.is_green_field && + !priv->current_ht_config.non_GF_STA_present); + return is_green; } /** @@ -2061,6 +2061,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, active_tbl = 1 - lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); + if (is_legacy(tbl->lq_type)) + lq_sta->is_green = 0; + else + lq_sta->is_green = rs_use_green(priv, conf); is_green = lq_sta->is_green; /* current tx rate */ @@ -2896,7 +2900,8 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); desc += sprintf(buff+desc, " %s", (tbl->is_fat) ? "40MHz" : "20MHz"); - desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : ""); + desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", + (lq_sta->is_green) ? "GF enabled" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", lq_sta->last_rate_n_flags); @@ -2959,13 +2964,14 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, return -ENOMEM; for (i = 0; i < LQ_SIZE; i++) { - desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" + desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n" "rate=0x%X\n", lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_fat, lq_sta->lq_info[i].is_dup, + lq_sta->is_green, lq_sta->lq_info[i].current_rate); for (j = 0; j < IWL_RATE_COUNT; j++) { desc += sprintf(buff+desc, -- cgit v0.10.2 From 62161aefa403a3f8d603b061f5688cf00928a2cc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 21 May 2009 13:44:23 -0700 Subject: iwlwifi: Temperature sensor voltage reading for 5150 The temperature measurement by uCode for 5150 and 5000 are different CSR_HW_REV_TYPE_5150: temperature sensor output voltage CSR_HW_REV_TYPE_5000: temperature in Celsius temperature related operation for 5150 is measured by temperature sensor output voltage; additional conversion is required for set and store the temperature. To make sure support different HW design; implement _ops method for temperature related functions (temperature reading and set ct kill threshold) Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a98ff4e..97131e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -788,6 +788,12 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { .nrg_th_ofdm = 100, }; +static void iwl4965_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Kelvin */ + priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); +} + /** * iwl4965_hw_set_hw_params * @@ -822,7 +828,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_chains_num = 2; priv->hw_params.valid_tx_ant = ANT_A | ANT_B; priv->hw_params.valid_rx_ant = ANT_A | ANT_B; - priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + if (priv->cfg->ops->lib->temp_ops.set_ct_kill) + priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); priv->hw_params.sens = &iwl4965_sensitivity; @@ -2331,9 +2338,12 @@ static struct iwl_lib_ops iwl4965_lib = { }, .send_tx_power = iwl4965_send_tx_power, .update_chain_flags = iwl_update_chain_flags, - .temperature = iwl4965_temperature_calib, .post_associate = iwl_post_associate, .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl4965_temperature_calib, + .set_ct_kill = iwl4965_set_ct_threshold, + }, }; static struct iwl_ops iwl4965_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 15cac70..4ef6804 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -87,6 +87,18 @@ #define IWL50_NUM_AMPDU_QUEUES 10 #define IWL50_FIRST_AMPDU_QUEUE 10 +/* 5150 only */ +#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) + +static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) +{ + u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, + EEPROM_5000_TEMPERATURE); + /* offset = temperature - voltage / coef */ + s32 offset = (s32)(temp_calib[0] - temp_calib[1] / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); + return offset; +} + /* Fixed (non-configurable) rx data from phy */ /** diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d731a83..e61b67d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -434,15 +434,19 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } -static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv) +static void iwl5150_set_ct_threshold(struct iwl_priv *priv) { - const s32 volt2temp_coef = -5; - u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, - EEPROM_5000_TEMPERATURE); - /* offset = temperate - voltage / coef */ - s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef; - s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset; - return threshold * volt2temp_coef; + const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - + iwl_temp_calib_to_offset(priv); + + priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; +} + +static void iwl5000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; } /* @@ -868,17 +872,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_5150: - /* 5150 wants in Kelvin */ - priv->hw_params.ct_kill_threshold = - iwl5150_get_ct_threshold(priv); - break; - default: - /* all others want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; - break; - } + if (priv->cfg->ops->lib->temp_ops.set_ct_kill) + priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); /* Set initial calibration set */ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { @@ -900,7 +895,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) break; } - return 0; } @@ -1434,6 +1428,17 @@ static void iwl5000_temperature(struct iwl_priv *priv) priv->temperature = le32_to_cpu(priv->statistics.general.temperature); } +static void iwl5150_temperature(struct iwl_priv *priv) +{ + u32 vt = 0; + s32 offset = iwl_temp_calib_to_offset(priv); + + vt = le32_to_cpu(priv->statistics.general.temperature); + vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; + /* now vt hold the temperature in Kelvin */ + priv->temperature = KELVIN_TO_CELSIUS(vt); +} + /* Calc max signal level (dBm) among 3 possible receivers */ int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp) @@ -1511,7 +1516,6 @@ struct iwl_lib_ops iwl5000_lib = { .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, - .temperature = iwl5000_temperature, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, @@ -1538,6 +1542,59 @@ struct iwl_lib_ops iwl5000_lib = { }, .post_associate = iwl_post_associate, .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5000_temperature, + .set_ct_kill = iwl5000_set_ct_threshold, + }, +}; + +static struct iwl_lib_ops iwl5150_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwl5000_txq_set_sched, + .txq_agg_enable = iwl5000_txq_agg_enable, + .txq_agg_disable = iwl5000_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwl5000_rx_handler_setup, + .setup_deferred_work = iwl5000_setup_deferred_work, + .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, + .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, + .send_tx_power = iwl5000_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .apm_ops = { + .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, + .config = iwl5000_nic_config, + .set_pwr_src = iwl_set_pwr_src, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_5000_REG_BAND_1_CHANNELS, + EEPROM_5000_REG_BAND_2_CHANNELS, + EEPROM_5000_REG_BAND_3_CHANNELS, + EEPROM_5000_REG_BAND_4_CHANNELS, + EEPROM_5000_REG_BAND_5_CHANNELS, + EEPROM_5000_REG_BAND_24_FAT_CHANNELS, + EEPROM_5000_REG_BAND_52_FAT_CHANNELS + }, + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + .calib_version = iwl5000_eeprom_calib_version, + .query_addr = iwl5000_eeprom_query_addr, + }, + .post_associate = iwl_post_associate, + .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5150_temperature, + .set_ct_kill = iwl5150_set_ct_threshold, + }, }; struct iwl_ops iwl5000_ops = { @@ -1547,6 +1604,13 @@ struct iwl_ops iwl5000_ops = { .smgmt = &iwl5000_station_mgmt, }; +static struct iwl_ops iwl5150_ops = { + .lib = &iwl5150_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, + .smgmt = &iwl5000_station_mgmt, +}; + struct iwl_mod_params iwl50_mod_params = { .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, @@ -1642,7 +1706,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .ucode_api_max = IWL5150_UCODE_API_MAX, .ucode_api_min = IWL5150_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, + .ops = &iwl5150_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f3544ea..a0ed415 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -112,6 +112,19 @@ struct iwl_hcmd_utils_ops { struct iwl_rx_phy_res *rx_resp); }; +struct iwl_apm_ops { + int (*init)(struct iwl_priv *priv); + int (*reset)(struct iwl_priv *priv); + void (*stop)(struct iwl_priv *priv); + void (*config)(struct iwl_priv *priv); + int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); +}; + +struct iwl_temp_ops { + void (*temperature)(struct iwl_priv *priv); + void (*set_ct_kill)(struct iwl_priv *priv); +}; + struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); @@ -149,23 +162,20 @@ struct iwl_lib_ops { int (*is_valid_rtc_data_addr)(u32 addr); /* 1st ucode load */ int (*load_ucode)(struct iwl_priv *priv); - /* power management */ - struct { - int (*init)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); - void (*stop)(struct iwl_priv *priv); - void (*config)(struct iwl_priv *priv); - int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); - } apm_ops; + /* power management */ + struct iwl_apm_ops apm_ops; + /* power */ int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - void (*temperature) (struct iwl_priv *priv); void (*post_associate) (struct iwl_priv *priv); void (*config_ap) (struct iwl_priv *priv); /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; + + /* temperature */ + struct iwl_temp_ops temp_ops; }; struct iwl_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index fae8426..73739cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -582,8 +582,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, iwl_leds_background(priv); - if (priv->cfg->ops->lib->temperature && change) - priv->cfg->ops->lib->temperature(priv); + if (priv->cfg->ops->lib->temp_ops.temperature && change) + priv->cfg->ops->lib->temp_ops.temperature(priv); } EXPORT_SYMBOL(iwl_rx_statistics); -- cgit v0.10.2 From 59620e9fd631703ecdc7a6d304231b45560b8d26 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 22 May 2009 11:58:36 +0300 Subject: rndis_wlan: fix support for bcm4320a Old variant of bcm4320 doesn't handle setting configuration parameters correctly. One symptom is that MAC gets partially overwritten when any config parameters are set. This patch disables config-params for bcm4320a (and generic rndis-wlan). Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 52fc647..addd7a5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2275,7 +2275,17 @@ end: } -static int bcm4320_early_init(struct usbnet *usbdev) +static int bcm4320a_early_init(struct usbnet *usbdev) +{ + /* bcm4320a doesn't handle configuration parameters well. Try + * set any and you get partially zeroed mac and broken device. + */ + + return 0; +} + + +static int bcm4320b_early_init(struct usbnet *usbdev) { struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); char buf[8]; @@ -2515,7 +2525,7 @@ static const struct driver_info bcm4320b_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wext_reset, - .early_init = bcm4320_early_init, + .early_init = bcm4320b_early_init, .link_change = rndis_wext_link_change, }; @@ -2528,7 +2538,7 @@ static const struct driver_info bcm4320a_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wext_reset, - .early_init = bcm4320_early_init, + .early_init = bcm4320a_early_init, .link_change = rndis_wext_link_change, }; @@ -2541,7 +2551,7 @@ static const struct driver_info rndis_wext_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wext_reset, - .early_init = bcm4320_early_init, + .early_init = bcm4320a_early_init, .link_change = rndis_wext_link_change, }; -- cgit v0.10.2 From 9656e85ba24a9814f1705e0e3639281d15d6a419 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 22 May 2009 17:40:12 +0300 Subject: rndis_wlan: remove CAP_SUPPORT_TXPOWER/OID_802_11_TX_POWER_LEVEL code BCM4320 doesn't support OID_802_11_TX_POWER_LEVEL (chip implements the command but setting value has no effect and getting txpower value always returns 0xff, full power). So remove the code for cleanup. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index addd7a5..4b3e046 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2,7 +2,7 @@ * Driver for RNDIS based wireless USB devices. * * Copyright (C) 2007 by Bjorge Dijkstra - * Copyright (C) 2008 by Jussi Kivilinna + * Copyright (C) 2008-2009 by Jussi Kivilinna * * 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 @@ -309,7 +309,6 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, #define CAP_MODE_80211B 2 #define CAP_MODE_80211G 4 #define CAP_MODE_MASK 7 -#define CAP_SUPPORT_TXPOWER 8 #define WORK_LINK_UP (1<<0) #define WORK_LINK_DOWN (1<<1) @@ -1849,18 +1848,10 @@ static int rndis_iw_get_txpower(struct net_device *dev, struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power; - int ret = 0, len; if (priv->radio_on) { - if (priv->caps & CAP_SUPPORT_TXPOWER) { - len = sizeof(tx_power); - ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, - &tx_power, &len); - if (ret != 0) - return ret; - } else - /* fake incase not supported */ - tx_power = cpu_to_le32(get_bcm4320_power(priv)); + /* fake since changing tx_power (by userlevel) not supported */ + tx_power = cpu_to_le32(get_bcm4320_power(priv)); wrqu->txpower.flags = IW_TXPOW_MWATT; wrqu->txpower.value = le32_to_cpu(tx_power); @@ -1873,7 +1864,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); - return ret; + return 0; } @@ -1883,7 +1874,6 @@ static int rndis_iw_set_txpower(struct net_device *dev, struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power = 0; - int ret = 0; if (!wrqu->txpower.disabled) { if (wrqu->txpower.flags == IW_TXPOW_MWATT) @@ -1906,22 +1896,10 @@ static int rndis_iw_set_txpower(struct net_device *dev, devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); if (le32_to_cpu(tx_power) != 0) { - if (priv->caps & CAP_SUPPORT_TXPOWER) { - /* turn radio on first */ - if (!priv->radio_on) - disassociate(usbdev, 1); - - ret = rndis_set_oid(usbdev, OID_802_11_TX_POWER_LEVEL, - &tx_power, sizeof(tx_power)); - if (ret != 0) - ret = -EOPNOTSUPP; - return ret; - } else { - /* txpower unsupported, just turn radio on */ - if (!priv->radio_on) - return disassociate(usbdev, 1); - return 0; /* all ready on */ - } + /* txpower unsupported, just turn radio on */ + if (!priv->radio_on) + return disassociate(usbdev, 1); + return 0; /* all ready on */ } /* tx_power == 0, turn off radio */ @@ -2130,16 +2108,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) __le32 items[8]; } networks_supported; int len, retval, i, n; - __le32 tx_power; struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - /* determine if supports setting txpower */ - len = sizeof(tx_power); - retval = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, &tx_power, - &len); - if (retval == 0 && le32_to_cpu(tx_power) != 0xFF) - priv->caps |= CAP_SUPPORT_TXPOWER; - /* determine supported modes */ len = sizeof(networks_supported); retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED, -- cgit v0.10.2 From b4703a2e32fdffbf83caf699817b21c4fc6d987c Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 22 May 2009 17:40:20 +0300 Subject: rndis_wlan: explain bits used in key setup code. Driver uses some unnamed bits to control encryption setup. Move these to enumerations with proper names explaining their meaning. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 4b3e046..0416800 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -196,6 +196,18 @@ enum ndis_80211_priv_filter { ndis_80211_priv_8021x_wep }; +enum ndis_80211_addkey_bits { + ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28), + ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29), + ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30), + ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31), +}; + +enum ndis_80211_addwep_bits { + ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30), + ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31), +}; + struct ndis_80211_ssid { __le32 length; u8 essid[NDIS_802_11_LENGTH_SSID]; @@ -998,7 +1010,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) memcpy(&ndis_key.material, key, key_len); if (index == priv->encr_tx_key_index) { - ndis_key.index |= cpu_to_le32(1 << 31); + ndis_key.index |= ndis_80211_addwep_transmit_key; ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, IW_AUTH_CIPHER_NONE); if (ret) @@ -1044,7 +1056,8 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) if (bssid) { /* pairwise key */ if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) - remove_key.index |= cpu_to_le32(1 << 30); + remove_key.index |= + ndis_80211_addkey_pairwise_key; memcpy(remove_key.bssid, bssid, sizeof(remove_key.bssid)); } else @@ -1626,7 +1639,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { memcpy(ndis_key.rsc, ext->rx_seq, 6); - ndis_key.index |= cpu_to_le32(1 << 29); + ndis_key.index |= ndis_80211_addkey_set_init_recv_seq; } addr = ext->addr.sa_data; @@ -1638,12 +1651,12 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, get_bssid(usbdev, ndis_key.bssid); } else { /* pairwise key */ - ndis_key.index |= cpu_to_le32(1 << 30); + ndis_key.index |= ndis_80211_addkey_pairwise_key; memcpy(ndis_key.bssid, addr, ETH_ALEN); } if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - ndis_key.index |= cpu_to_le32(1 << 31); + ndis_key.index |= ndis_80211_addkey_transmit_key; if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { /* wpa_supplicant gives us the Michael MIC RX/TX keys in -- cgit v0.10.2 From b145ee0ce1e325497e5bb91f78f1545b552b518f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 22 May 2009 17:40:27 +0300 Subject: rndis_wlan: split add_wpa_key from rndis_iw_set_encode_ext Split add_wpa_key() from rndis_iw_set_encode_ext so that conversion to cfg80211 would be easier later on. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 0416800..98f6ff7 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1033,6 +1033,73 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) } +static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, + int index, const struct sockaddr *addr, + const u8 *rx_seq, int alg, int flags) +{ + struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct ndis_80211_key ndis_key; + int ret; + + if (index < 0 || index >= 4) + return -EINVAL; + if (key_len > sizeof(ndis_key.material) || key_len < 0) + return -EINVAL; + if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq) + return -EINVAL; + if ((flags & ndis_80211_addkey_pairwise_key) && !addr) + return -EINVAL; + + devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, + !!(flags & ndis_80211_addkey_transmit_key), + !!(flags & ndis_80211_addkey_pairwise_key), + !!(flags & ndis_80211_addkey_set_init_recv_seq)); + + memset(&ndis_key, 0, sizeof(ndis_key)); + + ndis_key.size = cpu_to_le32(sizeof(ndis_key) - + sizeof(ndis_key.material) + key_len); + ndis_key.length = cpu_to_le32(key_len); + ndis_key.index = cpu_to_le32(index) | flags; + + if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) { + /* wpa_supplicant gives us the Michael MIC RX/TX keys in + * different order than NDIS spec, so swap the order here. */ + memcpy(ndis_key.material, key, 16); + memcpy(ndis_key.material + 16, key + 24, 8); + memcpy(ndis_key.material + 24, key + 16, 8); + } else + memcpy(ndis_key.material, key, key_len); + + if (flags & ndis_80211_addkey_set_init_recv_seq) + memcpy(ndis_key.rsc, rx_seq, 6); + + if (flags & ndis_80211_addkey_pairwise_key) { + /* pairwise key */ + memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); + } else { + /* group key */ + if (priv->infra_mode == ndis_80211_infra_adhoc) + memset(ndis_key.bssid, 0xff, ETH_ALEN); + else + get_bssid(usbdev, ndis_key.bssid); + } + + ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, + le32_to_cpu(ndis_key.size)); + devdbg(usbdev, "add_wpa_key: OID_802_11_ADD_KEY -> %08X", ret); + if (ret != 0) + return ret; + + priv->encr_key_len[index] = key_len; + memcpy(&priv->encr_keys[index], ndis_key.material, key_len); + if (flags & ndis_80211_addkey_transmit_key) + priv->encr_tx_key_index = index; + + return 0; +} + + /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { @@ -1602,9 +1669,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - struct ndis_80211_key ndis_key; - int keyidx, ret; - u8 *addr; + int keyidx, flags; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1627,58 +1692,16 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) return remove_key(usbdev, keyidx, NULL); - if (ext->key_len > sizeof(ndis_key.material)) - return -1; - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key) - - sizeof(ndis_key.material) + ext->key_len); - ndis_key.length = cpu_to_le32(ext->key_len); - ndis_key.index = cpu_to_le32(keyidx); - - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { - memcpy(ndis_key.rsc, ext->rx_seq, 6); - ndis_key.index |= ndis_80211_addkey_set_init_recv_seq; - } - - addr = ext->addr.sa_data; - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - /* group key */ - if (priv->infra_mode == ndis_80211_infra_adhoc) - memset(ndis_key.bssid, 0xff, ETH_ALEN); - else - get_bssid(usbdev, ndis_key.bssid); - } else { - /* pairwise key */ - ndis_key.index |= ndis_80211_addkey_pairwise_key; - memcpy(ndis_key.bssid, addr, ETH_ALEN); - } - + flags = 0; + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) + flags |= ndis_80211_addkey_set_init_recv_seq; + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) + flags |= ndis_80211_addkey_pairwise_key; if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - ndis_key.index |= ndis_80211_addkey_transmit_key; - - if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { - /* wpa_supplicant gives us the Michael MIC RX/TX keys in - * different order than NDIS spec, so swap the order here. */ - memcpy(ndis_key.material, ext->key, 16); - memcpy(ndis_key.material + 16, ext->key + 24, 8); - memcpy(ndis_key.material + 24, ext->key + 16, 8); - } else - memcpy(ndis_key.material, ext->key, ext->key_len); + flags |= ndis_80211_addkey_transmit_key; - ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, - le32_to_cpu(ndis_key.size)); - devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret); - if (ret != 0) - return ret; - - priv->encr_key_len[keyidx] = ext->key_len; - memcpy(&priv->encr_keys[keyidx], ndis_key.material, ext->key_len); - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - priv->encr_tx_key_index = keyidx; - - return 0; + return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, + ext->rx_seq, ext->alg, flags); } -- cgit v0.10.2 From 9839178e92bf205728c754aeb1933f631a9962d9 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 22 May 2009 17:40:34 +0300 Subject: rndis_wlan: do not try to restore wpa keys using add_wep_key() set_infra_mode() tried to restore wpa keys using add_wep_key(). This never worked so prevent driver from trying. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 98f6ff7..c254fdf 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -405,6 +405,7 @@ struct rndis_wext_private { int encr_tx_key_index; char encr_keys[4][32]; int encr_key_len[4]; + char encr_key_wpa[4]; int wpa_version; int wpa_keymgmt; int wpa_authalg; @@ -956,7 +957,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) if (priv->wpa_keymgmt == 0 || priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { for (i = 0; i < 4; i++) { - if (priv->encr_key_len[i] > 0) + if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i]) add_wep_key(usbdev, priv->encr_keys[i], priv->encr_key_len[i], i); } @@ -1027,6 +1028,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) } priv->encr_key_len[index] = key_len; + priv->encr_key_wpa[index] = 0; memcpy(&priv->encr_keys[index], key, key_len); return 0; @@ -1092,7 +1094,8 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, return ret; priv->encr_key_len[index] = key_len; - memcpy(&priv->encr_keys[index], ndis_key.material, key_len); + priv->encr_key_wpa[index] = 1; + if (flags & ndis_80211_addkey_transmit_key) priv->encr_tx_key_index = index; @@ -1112,6 +1115,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) return 0; priv->encr_key_len[index] = 0; + priv->encr_key_wpa[index] = 0; memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || -- cgit v0.10.2 From 3b91c3604d000205fb4e56b5ddd6b77b22ad4689 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 21 May 2009 19:16:14 +0200 Subject: rt2x00: Add new rt2800usb USB ID's for Sweex The USB ID with unknown manufacturer is apparently sweex, copy it to the correct location of the list and add 2 additional USB ID's also belonging to Sweex. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f11e597..aae7aa7 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2881,8 +2881,6 @@ static const struct rt2x00_ops rt2800usb_ops = { * rt2800usb module information. */ static struct usb_device_id rt2800usb_device_table[] = { - /* ??? */ - { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Abocom */ { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -3027,6 +3025,10 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sparklan */ { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sweex */ + { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, /* U-Media*/ { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, /* ZCOM */ -- cgit v0.10.2 From 8a566afea0639fc387add782bc799009512a911b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 21 May 2009 19:16:46 +0200 Subject: rt2x00: Remove usage of IEEE80211_CONF_CHANGE_BEACON_INTERVAL IEEE80211_CONF_CHANGE_BEACON_INTERVAL was deprecated a month ago, it is about time to remove all usage from the rt2x00 drivers and use the correct beacon interval configuration through the bss_info structure. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 6f39ba6..0197531 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -335,10 +335,11 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, - erp->ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); @@ -371,6 +372,11 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); + rt2x00pci_register_read(rt2x00dev, CSR18, ®); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); @@ -503,24 +509,6 @@ static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, CSR11, reg); } -static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); - rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - - rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, - libconf->conf->beacon_int * 16); - rt2x00pci_register_write(rt2x00dev, CSR12, reg); -} - static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -558,8 +546,6 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2400pci_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt2400pci_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt2400pci_config_ps(rt2x00dev, libconf); } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 906960f..f95cb64 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -341,10 +341,11 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, - erp->ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); @@ -377,6 +378,11 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); + rt2x00pci_register_read(rt2x00dev, CSR18, ®); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); @@ -552,24 +558,6 @@ static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, CSR11, reg); } -static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); - rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - - rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, - libconf->conf->beacon_int * 16); - rt2x00pci_register_write(rt2x00dev, CSR12, reg); -} - static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -609,8 +597,6 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2500pci_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt2500pci_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt2500pci_config_ps(rt2x00dev, libconf); } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 1debb88..69f966f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -503,6 +503,10 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); + rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, erp->beacon_int * 4); + rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); + rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time); rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs); rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs); @@ -632,17 +636,6 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2500usb_rf_write(rt2x00dev, 3, rf3); } -static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 reg; - - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); - rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, - libconf->conf->beacon_int * 4); - rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); -} - static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -680,8 +673,6 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt2500usb_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt2500usb_config_ps(rt2x00dev, libconf); } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index aae7aa7..142ad34 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -616,6 +616,11 @@ static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); rt2x00usb_register_write(rt2x00dev, XIFS_TIME_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); } static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, @@ -955,17 +960,6 @@ static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_write(rt2x00dev, TX_RTY_CFG, reg); } -static void rt2800usb_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); -} - static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -1010,8 +1004,6 @@ static void rt2800usb_config(struct rt2x00_dev *rt2x00dev, rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2800usb_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt2800usb_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt2800usb_config_ps(rt2x00dev, libconf); } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 419b1b9..2b64a61 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -417,6 +417,8 @@ struct rt2x00lib_erp { short pifs; short difs; short eifs; + + u16 beacon_int; }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 863e399..c5bbf0b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -106,6 +106,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, } erp.basic_rates = bss_conf->basic_rates; + erp.beacon_int = bss_conf->beacon_int; rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index cb521ee..a8bf5c4 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -603,15 +603,22 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); @@ -938,25 +945,6 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } -static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); -} - static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -1016,8 +1004,6 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt61pci_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt61pci_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt61pci_config_ps(rt2x00dev, libconf); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 270dd4e..211a3d6 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -566,15 +566,22 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -834,25 +841,6 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); } -static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); - rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - - rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); - rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); -} - static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -906,8 +894,6 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt73usb_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt73usb_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt73usb_config_ps(rt2x00dev, libconf); } -- cgit v0.10.2 From 0848e297c2107dbc12a91a1709c879c73bd188d8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 May 2009 11:01:46 -0700 Subject: iwlwifi: support NVM access (EEPROM/OTP) Two type of NVM available for devices 1000, 6000 and after, adding support to read OTP lower blocks if OTP is used instead of EEPROM. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index eb89752a..fd36734 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2298,8 +2298,10 @@ static ssize_t show_version(struct device *d, if (priv->eeprom) { eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", - eeprom_ver); + pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM", eeprom_ver); + } else { pos += sprintf(buf + pos, "EEPROM not initialzed\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 6e98314..3d50ef9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -89,6 +89,7 @@ /* EEPROM reads */ #define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_OTP_GP_REG (CSR_BASE+0x034) #define CSR_GIO_REG (CSR_BASE+0x03C) #define CSR_GP_UCODE (CSR_BASE+0x044) #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) @@ -226,6 +227,10 @@ #define CSR_EEPROM_GP_VALID_MSK (0x00000007) #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) +#define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ +#define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ +#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ +#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ /* CSR GIO */ #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index db06980..2cf014f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -68,7 +68,7 @@ struct iwl_debugfs { struct dentry *dir_rf; struct dir_data_files { struct dentry *file_sram; - struct dentry *file_eeprom; + struct dentry *file_nvm; struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ffc4be3..713f9ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -292,7 +292,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, return ret; } -static ssize_t iwl_dbgfs_eeprom_read(struct file *file, +static ssize_t iwl_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -306,7 +306,7 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, buf_size = 4 * eeprom_len + 256; if (eeprom_len % 16) { - IWL_ERR(priv, "EEPROM size is not multiple of 16.\n"); + IWL_ERR(priv, "NVM size is not multiple of 16.\n"); return -ENODATA; } @@ -318,6 +318,13 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, } ptr = priv->eeprom; + if (!ptr) { + IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); + return -ENOMEM; + } + pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM"); for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, @@ -419,7 +426,6 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN ? "passive only" : "active/passive"); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; @@ -564,7 +570,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); -DEBUGFS_READ_FILE_OPS(eeprom); +DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); @@ -598,7 +604,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); - DEBUGFS_ADD_FILE(eeprom, data); + DEBUGFS_ADD_FILE(nvm, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); @@ -629,7 +635,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) if (!priv->dbgfs) return; - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b6b8327..8282def 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -814,6 +814,11 @@ enum { MEASUREMENT_ACTIVE = (1 << 1), }; +enum iwl_nvm_type { + NVM_DEVICE_TYPE_EEPROM = 0, + NVM_DEVICE_TYPE_OTP, +}; + /* interrupt statistics */ struct isr_statistics { u32 hw; @@ -1024,6 +1029,7 @@ struct iwl_priv { /* eeprom */ u8 *eeprom; + int nvm_device_type; struct iwl_eeprom_calib_info *calib_info; enum nl80211_iftype iw_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index b400bd5..9cc063b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -152,6 +152,32 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); +static int iwlcore_get_nvm_type(struct iwl_priv *priv) +{ + u32 otpgp; + int nvm_type; + + /* OTP only valid for CP/PP and after */ + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_3945: + case CSR_HW_REV_TYPE_4965: + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5150: + nvm_type = NVM_DEVICE_TYPE_EEPROM; + break; + default: + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) + nvm_type = NVM_DEVICE_TYPE_OTP; + else + nvm_type = NVM_DEVICE_TYPE_EEPROM; + break; + } + return nvm_type; +} + /* * The device's EEPROM semaphore prevents conflicts between driver and uCode * when accessing the EEPROM; each access is a series of pulses to/from the @@ -198,6 +224,35 @@ const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) } EXPORT_SYMBOL(iwlcore_eeprom_query_addr); +static int iwl_init_otp_access(struct iwl_priv *priv) +{ + int ret; + + /* Enable 40MHz radio clock */ + _iwl_write32(priv, CSR_GP_CNTRL, + _iwl_read32(priv, CSR_GP_CNTRL) | + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* wait for clock to be ready */ + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); + if (ret < 0) + IWL_ERR(priv, "Time out access OTP\n"); + else { + ret = iwl_grab_nic_access(priv); + if (!ret) { + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + iwl_release_nic_access(priv); + } + } + return ret; +} + /** * iwl_eeprom_init - read EEPROM contents * @@ -209,11 +264,18 @@ int iwl_eeprom_init(struct iwl_priv *priv) { u16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - int sz = priv->cfg->eeprom_size; + int sz; int ret; u16 addr; + u32 otpgp; + + priv->nvm_device_type = iwlcore_get_nvm_type(priv); /* allocate eeprom */ + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + priv->cfg->eeprom_size = + OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; + sz = priv->cfg->eeprom_size; priv->eeprom = kzalloc(sz, GFP_KERNEL); if (!priv->eeprom) { ret = -ENOMEM; @@ -235,30 +297,77 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOENT; goto err; } - - /* eeprom is an array of 16bit values */ - for (addr = 0; addr < sz; addr += sizeof(u16)) { - u32 r; - - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); - goto done; + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + ret = iwl_init_otp_access(priv); + if (ret) { + IWL_ERR(priv, "Failed to initialize OTP access.\n"); + ret = -ENOENT; + goto err; + } + _iwl_write32(priv, CSR_EEPROM_GP, + iwl_read32(priv, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); + /* clear */ + _iwl_write32(priv, CSR_OTP_GP_REG, + iwl_read32(priv, CSR_OTP_GP_REG) | + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + + for (addr = 0; addr < sz; addr += sizeof(u16)) { + u32 r; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + goto done; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + /* check for ECC errors: */ + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { + /* stop in this case */ + IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); + goto done; + } + if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { + /* continue in this case */ + _iwl_write32(priv, CSR_OTP_GP_REG, + iwl_read32(priv, CSR_OTP_GP_REG) | + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); + IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); + } + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + } + } else { + /* eeprom is an array of 16bit values */ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + u32 r; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); + goto done; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } ret = 0; done: priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); err: if (ret) - kfree(priv->eeprom); + iwl_eeprom_free(priv); alloc_err: return ret; } @@ -301,6 +410,8 @@ EXPORT_SYMBOL(iwl_eeprom_query_addr); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) { + if (!priv->eeprom) + return 0; return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); } EXPORT_SYMBOL(iwl_eeprom_query16); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 3479153..195b4ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -179,6 +179,10 @@ struct iwl_eeprom_channel { #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) +/* OTP */ +#define OTP_LOWER_BLOCKS_TOTAL (3) +#define OTP_BLOCK_SIZE (0x400) + /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -- cgit v0.10.2 From a8b50a0a966d7ac313f624c6ab4996231a5fe25a Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 22 May 2009 11:01:47 -0700 Subject: iwlcore: register locks Add new lock to be used when accessing some registers. Also move the register lock and iwl_grab_nic_access inside the function for register access. This will prevent from forgetting to hold locks and nic access in the right way and make code easier to maintain. We over use the priv->lock spin lock and I guess we need to add new one for Tx queue after that we might need to change most of these lock to BH and just keep priv->lock as irq type. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 5b0c6e5..8bed044 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -98,7 +98,6 @@ const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945] = { * ... and set IWL_EVT_DISABLE to 1. */ void iwl3945_disable_events(struct iwl_priv *priv) { - int ret; int i; u32 base; /* SRAM address of event log header */ u32 disable_ptr; /* SRAM address of event-disable bitmap array */ @@ -159,26 +158,17 @@ void iwl3945_disable_events(struct iwl_priv *priv) return; } - ret = iwl_grab_nic_access(priv); - if (ret) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32))); array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32))); - iwl_release_nic_access(priv); if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n", disable_ptr); - ret = iwl_grab_nic_access(priv); for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) iwl_write_targ_mem(priv, disable_ptr + (i * sizeof(u32)), evt_disable[i]); - iwl_release_nic_access(priv); } else { IWL_DEBUG_INFO(priv, "Selected uCode log events may be disabled\n"); IWL_DEBUG_INFO(priv, " by writing \"1\"s into disable bitmap\n"); @@ -908,55 +898,30 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - if (src == IWL_PWR_SRC_VAUX) { if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VAUX, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl_release_nic_access(priv); iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VAUX_PWR_SRC, CSR_GPIO_IN_BIT_AUX_POWER, 5000); - } else { - iwl_release_nic_access(priv); } } else { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl_release_nic_access(priv); iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ } - spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return 0; } static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { - int rc; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr); iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma); iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0); @@ -973,23 +938,11 @@ static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* fake read to flush all prev I/O */ iwl_read_direct32(priv, FH39_RSSR_CTRL); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } static int iwl3945_tx_reset(struct iwl_priv *priv) { - int rc; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } /* bypass mode */ iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2); @@ -1017,8 +970,6 @@ static int iwl3945_tx_reset(struct iwl_priv *priv) FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -1061,7 +1012,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) static int iwl3945_apm_init(struct iwl_priv *priv) { - int ret = 0; + int ret; iwl_power_initialize(priv); @@ -1083,10 +1034,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) goto out; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); @@ -1097,7 +1044,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); out: return ret; } @@ -1196,22 +1142,13 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv) iwl3945_rx_init(priv, rxq); - spin_lock_irqsave(&priv->lock, flags); /* Look at using this instead: rxq->need_update = 1; iwl_rx_queue_update_write_ptr(priv, rxq); */ - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7); - iwl_release_nic_access(priv); - - spin_unlock_irqrestore(&priv->lock, flags); rc = iwl3945_txq_ctx_reset(priv); if (rc) @@ -1243,14 +1180,6 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) { int txq_id; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->lock, flags); - iwl3945_hw_txq_ctx_free(priv); - return; - } /* stop SCD */ iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); @@ -1263,9 +1192,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) 1000); } - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl3945_hw_txq_ctx_free(priv); } @@ -1310,12 +1236,8 @@ static void iwl3945_apm_stop(struct iwl_priv *priv) static int iwl3945_apm_reset(struct iwl_priv *priv) { - int rc; - unsigned long flags; - iwl3945_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); @@ -1325,36 +1247,31 @@ static int iwl3945_apm_reset(struct iwl_priv *priv) iwl_poll_direct_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - rc = iwl_grab_nic_access(priv); - if (!rc) { - iwl_write_prph(priv, APMG_CLK_CTRL_REG, - APMG_CLK_VAL_BSM_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_CTRL_REG, + APMG_CLK_VAL_BSM_CLK_RQT); - iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); - iwl_write_prph(priv, APMG_RTC_INT_STT_REG, + iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF); - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - udelay(10); + /* enable DMA */ + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + udelay(10); - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - iwl_release_nic_access(priv); - } /* Clear the 'host command active' bit... */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return 0; } /** @@ -2500,14 +2417,6 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) int iwl3945_hw_rxq_stop(struct iwl_priv *priv) { int rc; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0); rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS, @@ -2515,28 +2424,17 @@ int iwl3945_hw_rxq_stop(struct iwl_priv *priv) if (rc < 0) IWL_ERR(priv, "Can't stop Rx DMA.\n"); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int rc; - unsigned long flags; int txq_id = txq->q.id; struct iwl3945_shared *shared_data = priv->shared_virt; shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0); iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0); @@ -2546,11 +2444,9 @@ int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); - iwl_release_nic_access(priv); /* fake read to flush all prev. writes */ iwl_read32(priv, FH39_TSSR_CBB_BASE); - spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -2858,10 +2754,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) inst_len = priv->ucode_init.len; data_len = priv->ucode_init_data.len; - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); @@ -2875,10 +2767,8 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) le32_to_cpu(*image)); rc = iwl3945_verify_bsm(priv); - if (rc) { - iwl_release_nic_access(priv); + if (rc) return rc; - } /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); @@ -2910,8 +2800,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - iwl_release_nic_access(priv); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 97131e6..4be7bd29 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -163,10 +163,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) inst_len = priv->ucode_init.len; data_len = priv->ucode_init_data.len; - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); @@ -179,10 +175,8 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) _iwl_write_prph(priv, reg_offset, le32_to_cpu(*image)); ret = iwl4965_verify_bsm(priv); - if (ret) { - iwl_release_nic_access(priv); + if (ret) return ret; - } /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); @@ -211,7 +205,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) * (e.g. when powering back up after power-save shutdown) */ iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - iwl_release_nic_access(priv); return 0; } @@ -229,20 +222,12 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) { dma_addr_t pinst; dma_addr_t pdata; - unsigned long flags; int ret = 0; /* bits 35:4 for 4965 */ pinst = priv->ucode_code.p_addr >> 4; pdata = priv->ucode_data_backup.p_addr >> 4; - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - /* Tell bootstrap uCode where to find image to load */ iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); @@ -253,10 +238,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) * that all new ptr/size info is in place */ iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); - iwl_release_nic_access(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); return ret; @@ -358,10 +339,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv) goto out; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); @@ -372,7 +349,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); out: return ret; } @@ -454,11 +430,9 @@ static void iwl4965_apm_stop(struct iwl_priv *priv) static int iwl4965_apm_reset(struct iwl_priv *priv) { int ret = 0; - unsigned long flags; iwl4965_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -475,9 +449,6 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) udelay(10); - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; /* Enable DMA and BSM Clock */ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); @@ -488,14 +459,10 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); out: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; } @@ -681,18 +648,11 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; unsigned long flags; - int ret; int i, chan; u32 reg_val; spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - /* Clear 4965's internal Tx Scheduler data base */ priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR); a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET; @@ -759,10 +719,9 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return 0; } static struct iwl_sensitivity_ranges iwl4965_sensitivity = { @@ -1840,8 +1799,6 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { - int ret = 0; - if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { IWL_WARN(priv, @@ -1851,10 +1808,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, return -EINVAL; } - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl4965_tx_queue_stop_scheduler(priv, txq_id); iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); @@ -1868,8 +1821,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl_txq_ctx_deactivate(priv, txq_id); iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); - iwl_release_nic_access(priv); - return 0; } @@ -1911,7 +1862,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; - int ret; u16 ra_tid; if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || @@ -1929,11 +1879,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } /* Stop this Tx queue before configuring it */ iwl4965_tx_queue_stop_scheduler(priv, txq_id); @@ -1966,7 +1911,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e61b67d..bec5f8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -124,10 +124,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); @@ -137,8 +133,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); - return ret; } @@ -165,12 +159,9 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) static int iwl5000_apm_reset(struct iwl_priv *priv) { int ret = 0; - unsigned long flags; iwl5000_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); @@ -193,10 +184,6 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) goto out; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); @@ -205,11 +192,7 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) /* disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - - iwl_release_nic_access(priv); - out: - spin_unlock_irqrestore(&priv->lock, flags); return ret; } @@ -252,11 +235,9 @@ static void iwl5000_nic_config(struct iwl_priv *priv) * (PCIe power is lost before PERST# is asserted), * causing ME FW to lose ownership and not being able to obtain it back. */ - iwl_grab_nic_access(priv); iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); } @@ -537,19 +518,9 @@ static int iwl5000_load_section(struct iwl_priv *priv, struct fw_desc *image, u32 dst_addr) { - int ret = 0; - unsigned long flags; - dma_addr_t phy_addr = image->p_addr; u32 byte_cnt = image->len; - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); @@ -578,8 +549,6 @@ static int iwl5000_load_section(struct iwl_priv *priv, FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -740,18 +709,11 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; unsigned long flags; - int ret; int i, chan; u32 reg_val; spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR); a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET; for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET; @@ -819,7 +781,6 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_txq_ctx_activate(priv, 8); iwl_txq_ctx_activate(priv, 9); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -1000,7 +961,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; - int ret; u16 ra_tid; if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || @@ -1018,11 +978,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } /* Stop this Tx queue before configuring it */ iwl5000_tx_queue_stop_scheduler(priv, txq_id); @@ -1058,7 +1013,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -1067,8 +1021,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { - int ret; - if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { IWL_ERR(priv, @@ -1078,10 +1030,6 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, return -EINVAL; } - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl5000_tx_queue_stop_scheduler(priv, txq_id); iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id)); @@ -1095,8 +1043,6 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl_txq_ctx_deactivate(priv, txq_id); iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); - iwl_release_nic_access(priv); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fd36734..4e41038 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -503,24 +503,12 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int ret; - unsigned long flags; int txq_id = txq->q.id; - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - /* Circular buffer (TFD queue in DRAM) physical base address */ iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -709,6 +697,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; + unsigned long reg_flags; IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", @@ -720,32 +709,25 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32( - priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - iwl_release_nic_access(priv); - } + iwl_write_direct32(priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); if (!(flags & RXON_CARD_DISABLED)) { iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32( - priv, HBUS_TARG_MBX_C, + iwl_write_direct32(priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - iwl_release_nic_access(priv); - } } if (flags & RF_CARD_DISABLED) { iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); iwl_read32(priv, CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&priv->reg_lock, reg_flags); if (!iwl_grab_nic_access(priv)) iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } } @@ -774,14 +756,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) - goto err; - if (src == IWL_PWR_SRC_VAUX) { if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, @@ -793,10 +767,7 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) ~APMG_PS_CTRL_MSK_PWR_SRC); } - iwl_release_nic_access(priv); -err: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return 0; } /** @@ -1587,13 +1558,8 @@ static void __iwl_down(struct iwl_priv *priv) iwl_txq_ctx_stop(priv); iwl_rxq_stop(priv); - spin_lock_irqsave(&priv->lock, flags); - if (!iwl_grab_nic_access(priv)) { - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); + iwl_write_prph(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); @@ -2707,6 +2673,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base); + /* this spin lock will be used in apm_ops.init and EEPROM access + * we should init now + */ + spin_lock_init(&priv->reg_lock); iwl_hw_detect(priv); IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", priv->cfg->name, priv->hw_rev); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6c1b171..c7cbb2e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1588,10 +1588,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log @@ -1607,8 +1603,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 } } - iwl_release_nic_access(priv); - return ret; } @@ -1626,10 +1620,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWL49_RTC_INST_LOWER_BOUND); @@ -1650,8 +1640,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, } } - iwl_release_nic_access(priv); - if (!errcnt) IWL_DEBUG_INFO(priv, "ucode image in INSTRUCTION memory is good\n"); @@ -1760,7 +1748,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 data2, line; u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - int ret; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); @@ -1772,12 +1759,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) return; } - ret = iwl_grab_nic_access(priv); - if (ret) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - count = iwl_read_targ_mem(priv, base); if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { @@ -1804,7 +1785,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, ilink1, ilink2); - iwl_release_nic_access(priv); } EXPORT_SYMBOL(iwl_dump_nic_error_log); @@ -1813,7 +1793,6 @@ EXPORT_SYMBOL(iwl_dump_nic_error_log); /** * iwl_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) @@ -1859,7 +1838,6 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, void iwl_dump_nic_event_log(struct iwl_priv *priv) { - int ret; u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ @@ -1877,12 +1855,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) return; } - ret = iwl_grab_nic_access(priv); - if (ret) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - /* event log header */ capacity = iwl_read_targ_mem(priv, base); mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); @@ -1894,7 +1866,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - iwl_release_nic_access(priv); return; } @@ -1909,7 +1880,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) /* (then/else) start at top of log */ iwl_print_event_log(priv, 0, next_entry, mode); - iwl_release_nic_access(priv); } EXPORT_SYMBOL(iwl_dump_nic_event_log); @@ -2016,11 +1986,11 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) /* wake up ucode */ msleep(10); - spin_lock_irqsave(&priv->lock, flags); iwl_read32(priv, CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&priv->reg_lock, flags); if (!iwl_grab_nic_access(priv)) iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->reg_lock, flags); if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 713f9ed..03006c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -172,7 +172,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, struct iwl_priv *priv = (struct iwl_priv *)file->private_data; const size_t bufsz = sizeof(buf); - iwl_grab_nic_access(priv); for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ priv->dbgfs->sram_len - i); @@ -192,7 +191,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); } pos += scnprintf(buf + pos, bufsz - pos, "\n"); - iwl_release_nic_access(priv); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8282def..1310c41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -896,6 +896,7 @@ struct iwl_priv { /* spinlock */ spinlock_t lock; /* protect general shared data */ spinlock_t hcmd_lock; /* protect hcmd */ + spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; /* basic pci-network driver stuff */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 9cc063b..cefa501 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -240,14 +240,12 @@ static int iwl_init_otp_access(struct iwl_priv *priv) if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { - ret = iwl_grab_nic_access(priv); if (!ret) { iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - iwl_release_nic_access(priv); } } return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 083ea1f..d30cb02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -131,9 +131,23 @@ static inline void __iwl_set_bit(const char *f, u32 l, IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); _iwl_write32(priv, reg, val); } -#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m) +static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + __iwl_set_bit(__FILE__, __LINE__, p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #else -#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m) +static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + _iwl_set_bit(p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #endif static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) @@ -148,19 +162,30 @@ static inline void __iwl_clear_bit(const char *f, u32 l, IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); _iwl_write32(priv, reg, val); } -#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m) +static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + __iwl_clear_bit(__FILE__, __LINE__, p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #else -#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m) +static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + _iwl_clear_bit(p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #endif static inline int _iwl_grab_nic_access(struct iwl_priv *priv) { int ret; u32 val; -#ifdef CONFIG_IWLWIFI_DEBUG - if (atomic_read(&priv->restrict_refcnt)) - return 0; -#endif + /* 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, @@ -170,12 +195,10 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) if (ret < 0) { val = _iwl_read32(priv, CSR_GP_CNTRL); IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); return -EIO; } -#ifdef CONFIG_IWLWIFI_DEBUG - atomic_inc(&priv->restrict_refcnt); -#endif return 0; } @@ -183,9 +206,6 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) static inline int __iwl_grab_nic_access(const char *f, u32 l, struct iwl_priv *priv) { - if (atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Grabbing access while already held %s %d.\n", f, l); - IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); return _iwl_grab_nic_access(priv); } @@ -198,18 +218,13 @@ static inline int __iwl_grab_nic_access(const char *f, u32 l, static inline void _iwl_release_nic_access(struct iwl_priv *priv) { -#ifdef CONFIG_IWLWIFI_DEBUG - if (atomic_dec_and_test(&priv->restrict_refcnt)) -#endif - _iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + _iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } #ifdef CONFIG_IWLWIFI_DEBUG static inline void __iwl_release_nic_access(const char *f, u32 l, struct iwl_priv *priv) { - if (atomic_read(&priv->restrict_refcnt) <= 0) - IWL_ERR(priv, "Release unheld nic access at line %s %d.\n", f, l); IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); _iwl_release_nic_access(priv); @@ -230,16 +245,37 @@ static inline u32 __iwl_read_direct32(const char *f, u32 l, struct iwl_priv *priv, u32 reg) { u32 value = _iwl_read_direct32(priv, reg); - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s %d\n", f, l); IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, f, l); return value; } -#define iwl_read_direct32(priv, reg) \ - __iwl_read_direct32(__FILE__, __LINE__, priv, reg) +static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return value; +} + #else -#define iwl_read_direct32 _iwl_read_direct32 +static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + value = _iwl_read_direct32(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return value; + +} #endif static inline void _iwl_write_direct32(struct iwl_priv *priv, @@ -247,19 +283,17 @@ static inline void _iwl_write_direct32(struct iwl_priv *priv, { _iwl_write32(priv, reg, value); } -#ifdef CONFIG_IWLWIFI_DEBUG -static void __iwl_write_direct32(const char *f , u32 line, - struct iwl_priv *priv, u32 reg, u32 value) +static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); - _iwl_write_direct32(priv, reg, value); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_direct32(priv, reg, value); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } -#define iwl_write_direct32(priv, reg, value) \ - __iwl_write_direct32(__func__, __LINE__, priv, reg, value) -#else -#define iwl_write_direct32 _iwl_write_direct32 -#endif static inline void iwl_write_reg_buf(struct iwl_priv *priv, u32 reg, u32 len, u32 *values) @@ -268,14 +302,23 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv, if ((priv != NULL) && (values != NULL)) { for (; 0 < len; len -= count, reg += count, values++) - _iwl_write_direct32(priv, reg, *values); + iwl_write_direct32(priv, reg, *values); } } static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, int timeout) { - return _iwl_poll_bit(priv, addr, mask, mask, timeout); + int t = 0; + + do { + if ((iwl_read_direct32(priv, addr) & mask) == mask) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -305,20 +348,18 @@ static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) rmb(); return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_prph(const char *f, u32 line, - struct iwl_priv *priv, u32 reg) +static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); - return _iwl_read_prph(priv, reg); -} + unsigned long reg_flags; + u32 val; -#define iwl_read_prph(priv, reg) \ - __iwl_read_prph(__func__, __LINE__, priv, reg) -#else -#define iwl_read_prph _iwl_read_prph -#endif + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + val = _iwl_read_prph(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return val; +} static inline void _iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) @@ -328,83 +369,107 @@ static inline void _iwl_write_prph(struct iwl_priv *priv, wmb(); _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write_prph(const char *f, u32 line, - struct iwl_priv *priv, u32 addr, u32 val) + +static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); - _iwl_write_prph(priv, addr, val); -} + unsigned long reg_flags; -#define iwl_write_prph(priv, addr, val) \ - __iwl_write_prph(__func__, __LINE__, priv, addr, val); -#else -#define iwl_write_prph _iwl_write_prph -#endif + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_prph(priv, addr, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +} #define _iwl_set_bits_prph(priv, reg, mask) \ _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bits_prph(const char *f, u32 line, - struct iwl_priv *priv, - u32 reg, u32 mask) + +static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); + unsigned long reg_flags; + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); _iwl_set_bits_prph(priv, reg, mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } -#define iwl_set_bits_prph(priv, reg, mask) \ - __iwl_set_bits_prph(__func__, __LINE__, priv, reg, mask) -#else -#define iwl_set_bits_prph _iwl_set_bits_prph -#endif #define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bits_mask_prph(const char *f, u32 line, - struct iwl_priv *priv, u32 reg, u32 bits, u32 mask) +static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); _iwl_set_bits_mask_prph(priv, reg, bits, mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } -#define iwl_set_bits_mask_prph(priv, reg, bits, mask) \ - __iwl_set_bits_mask_prph(__func__, __LINE__, priv, reg, bits, mask) -#else -#define iwl_set_bits_mask_prph _iwl_set_bits_mask_prph -#endif static inline void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) { - u32 val = _iwl_read_prph(priv, reg); + unsigned long reg_flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + val = _iwl_read_prph(priv, reg); _iwl_write_prph(priv, reg, (val & ~mask)); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) { - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + unsigned long reg_flags; + u32 value; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + + _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); rmb(); - return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return value; } static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) { - iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, u32 len, u32 *values) { - iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - for (; 0 < len; len -= sizeof(u32), values++) - iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + for (; 0 < len; len -= sizeof(u32), values++) + _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); + + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 73739cf..7a43282 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -145,13 +145,7 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) goto exit_unlock; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto exit_unlock; - - /* Device expects a multiple of 8 */ iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write & ~0x7); - iwl_release_nic_access(priv); /* Else device is assumed to be awake */ } else { @@ -403,19 +397,10 @@ EXPORT_SYMBOL(iwl_rx_queue_reset); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { - int ret; - unsigned long flags; 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); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - if (priv->cfg->mod_params->amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; else @@ -452,35 +437,19 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) (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; } int iwl_rxq_stop(struct iwl_priv *priv) { - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (unlikely(ret)) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } /* stop Rx DMA */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } EXPORT_SYMBOL(iwl_rxq_stop); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a82cca0..85ae7a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -102,13 +102,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) return ret; } - /* restore this queue's parameters in nic hardware. */ - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; iwl_write_direct32(priv, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); - iwl_release_nic_access(priv); /* else not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ @@ -429,11 +424,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) goto error_kw; } spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (unlikely(ret)) { - spin_unlock_irqrestore(&priv->lock, flags); - goto error_reset; - } /* Turn off all Tx DMA fifos */ priv->cfg->ops->lib->txq_set_sched(priv, 0); @@ -441,7 +431,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) /* Tell NIC where to find the "keep warm" buffer */ iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); /* Alloc and init all Tx queues, including the command queue (#4) */ @@ -460,7 +449,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error: iwl_hw_txq_ctx_free(priv); - error_reset: iwl_free_dma_ptr(priv, &priv->kw); error_kw: iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); @@ -478,10 +466,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) /* Turn off all Tx DMA fifos */ spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->lock, flags); - return; - } priv->cfg->ops->lib->txq_set_sched(priv, 0); @@ -492,7 +476,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); } - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); /* Deallocate memory for all Tx queues */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5d52f227..8e68803 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1686,7 +1686,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) u32 i; u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - int rc; base = le32_to_cpu(priv->card_alive.error_event_table_ptr); @@ -1695,11 +1694,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) return; } - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } count = iwl_read_targ_mem(priv, base); @@ -1734,8 +1728,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) ilink1, ilink2, data1); } - iwl_release_nic_access(priv); - } #define EVENT_START_OFFSET (6 * sizeof(u32)) @@ -1743,7 +1735,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) /** * iwl3945_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) @@ -1786,7 +1777,6 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) { - int rc; u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ @@ -1800,12 +1790,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) return; } - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - /* event log header */ capacity = iwl_read_targ_mem(priv, base); mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); @@ -1817,7 +1801,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - iwl_release_nic_access(priv); return; } @@ -1833,7 +1816,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) /* (then/else) start at top of log */ iwl3945_print_event_log(priv, 0, next_entry, mode); - iwl_release_nic_access(priv); } static void iwl3945_irq_tasklet(struct iwl_priv *priv) @@ -1952,11 +1934,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) priv->isr_stats.tx++; iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32(priv, FH39_TCSR_CREDIT - (FH39_SRVC_CHNL), 0x0); - iwl_release_nic_access(priv); - } + iwl_write_direct32(priv, FH39_TCSR_CREDIT + (FH39_SRVC_CHNL), 0x0); handled |= CSR_INT_BIT_FH_TX; } @@ -2131,10 +2110,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWL39_RTC_INST_LOWER_BOUND); @@ -2155,7 +2130,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le } } - iwl_release_nic_access(priv); if (!errcnt) IWL_DEBUG_INFO(priv, @@ -2179,10 +2153,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log @@ -2203,8 +2173,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 } } - iwl_release_nic_access(priv); - return rc; } @@ -2528,20 +2496,11 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv) { dma_addr_t pinst; dma_addr_t pdata; - int rc = 0; - unsigned long flags; /* bits 31:0 for 3945 */ pinst = priv->ucode_code.p_addr; pdata = priv->ucode_data_backup.p_addr; - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - /* Tell bootstrap uCode where to find image to load */ iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); @@ -2553,13 +2512,9 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv) iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); - iwl_release_nic_access(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); - return rc; + return 0; } /** @@ -2612,7 +2567,6 @@ static void iwl3945_init_alive_start(struct iwl_priv *priv) */ static void iwl3945_alive_start(struct iwl_priv *priv) { - int rc = 0; int thermal_spin = 0; u32 rfkill; @@ -2637,15 +2591,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv) priv->cfg->ops->smgmt->clear_station_table(priv); - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARN(priv, "Can not read RFKILL status from adapter\n"); - return; - } - rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); - iwl_release_nic_access(priv); if (rfkill & 0x1) { clear_bit(STATUS_RF_KILL_HW, &priv->status); @@ -2791,13 +2738,8 @@ static void __iwl3945_down(struct iwl_priv *priv) iwl3945_hw_txq_ctx_stop(priv); iwl3945_hw_rxq_stop(priv); - spin_lock_irqsave(&priv->lock, flags); - if (!iwl_grab_nic_access(priv)) { - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); + iwl_write_prph(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); @@ -4288,6 +4230,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, 0x41, 0x00); + /* this spin lock will be used in apm_ops.init and EEPROM access + * we should init now + */ + spin_lock_init(&priv->reg_lock); + /* amp init */ err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { -- cgit v0.10.2 From a9c146b369cd8facbbbec7d8b31440f6eaa43e03 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 May 2009 11:01:48 -0700 Subject: iwlwifi: report the rate index as an MCS rate number If transmit in HT rate, report the rate index as an MCS rate number instead of an index. so "iw" can display correct BitRate Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index a1b0ff5..23a58b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -270,6 +270,8 @@ const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { {"60", "64QAM 5/6"} }; +#define MCS_INDEX_PER_STREAM (8) + static inline u8 rs_extract_rate(u32 rate_n_flags) { return (u8)(rate_n_flags & 0xFF); @@ -2518,12 +2520,33 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, } } - if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) - rate_idx = rate_lowest_index(sband, sta); - else if (sband->band == IEEE80211_BAND_5GHZ) + if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { rate_idx -= IWL_FIRST_OFDM_RATE; - + /* 6M and 9M shared same MCS index */ + rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; + if (rs_extract_rate(lq_sta->last_rate_n_flags) >= + IWL_RATE_MIMO3_6M_PLCP) + rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM); + else if (rs_extract_rate(lq_sta->last_rate_n_flags) >= + IWL_RATE_MIMO2_6M_PLCP) + rate_idx = rate_idx + MCS_INDEX_PER_STREAM; + info->control.rates[0].flags = IEEE80211_TX_RC_MCS; + if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; + if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; + if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; + } else { + if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + rate_idx = rate_lowest_index(sband, sta); + else if (sband->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + } info->control.rates[0].idx = rate_idx; + } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, -- cgit v0.10.2 From a2b0f02e4795bfde5f11720a10af8923cb98b654 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 May 2009 11:01:49 -0700 Subject: iwlwifi: support "pure 40MHz" in RXON command Fix the bug when using 11n "pure 40MHz" mode cause uCode crashing by adding support for "pure 40MHz" in RX_ON command flag. the "mode" field (bits 25:26) has value of 0-3 0 = 20 MHz only 1 = 40MHz only 2 = Mixed 3 = Reserved Control Channel ID (bit 22) is valid only in Mixed mode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 4be7bd29..7df4116 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -293,10 +293,12 @@ restart: queue_work(priv->workqueue, &priv->restart); } -static int is_fat_channel(__le32 rxon_flags) +static bool is_fat_channel(__le32 rxon_flags) { - return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || - (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); + int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) + >> RXON_FLG_CHANNEL_MODE_POS; + return ((chan_mod == CHANNEL_MODE_PURE_40) || + (chan_mod == CHANNEL_MODE_MIXED)); } /* @@ -1490,7 +1492,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) struct iwl4965_txpowertable_cmd cmd = { 0 }; int ret; u8 band = 0; - u8 is_fat = 0; + bool is_fat = false; u8 ctrl_chan_high = 0; if (test_bit(STATUS_SCANNING, &priv->status)) { @@ -1568,7 +1570,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; - u8 is_fat = 0; + bool is_fat = false; u8 ctrl_chan_high = 0; struct iwl4965_channel_switch_cmd cmd = { 0 }; const struct iwl_channel_info *ch_info; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 7b84d52..e581dc3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -614,8 +614,18 @@ enum { #define RXON_FLG_CHANNEL_MODE_POS (25) #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) -#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25) -#define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25) + +/* channel mode */ +enum { + CHANNEL_MODE_LEGACY = 0, + CHANNEL_MODE_PURE_40 = 1, + CHANNEL_MODE_MIXED = 2, + CHANNEL_MODE_RESERVED = 3, +}; +#define RXON_FLG_CHANNEL_MODE_LEGACY cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS) +#define RXON_FLG_CHANNEL_MODE_PURE_40 cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS) +#define RXON_FLG_CHANNEL_MODE_MIXED cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS) + /* CTS to self (if spec allows) flag */ #define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c7cbb2e..a15f795 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -617,19 +617,23 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; if ((!iwl_ht_conf->is_ht) || - (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || - (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)) + (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)) return 0; + /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 + * the bit will not set if it is pure 40MHz case + */ if (sta_ht_inf) { - if ((!sta_ht_inf->ht_supported) || - (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))) + if (!sta_ht_inf->ht_supported) return 0; } - return iwl_is_channel_extension(priv, priv->band, - le16_to_cpu(priv->staging_rxon.channel), - iwl_ht_conf->extension_chan_offset); + if (iwl_ht_conf->ht_protection & IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) + return 1; + else + return iwl_is_channel_extension(priv, priv->band, + le16_to_cpu(priv->staging_rxon.channel), + iwl_ht_conf->extension_chan_offset); } EXPORT_SYMBOL(iwl_is_fat_tx_allowed); @@ -799,42 +803,51 @@ EXPORT_SYMBOL(iwl_rate_get_lowest_plcp); 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) { - rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK | + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_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)) - rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; - else - rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK); - - /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; - break; - case IEEE80211_HT_PARAM_CHA_SEC_NONE: - default: - rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; - break; + /* FIXME: if the definition of ht_protection changed, the "translation" + * will be needed for rxon->flags + */ + rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); + + /* Set up channel bandwidth: + * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ + /* clear the HT channel mode before set the mode */ + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + if (iwl_is_fat_tx_allowed(priv, NULL)) { + /* pure 40 fat */ + if (rxon->flags & RXON_FLG_FAT_PROT_MSK) + rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; + else { + /* Note: control channel is opposite of extension channel */ + switch (ht_info->extension_chan_offset) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; + break; + case IEEE80211_HT_PARAM_CHA_SEC_NONE: + default: + /* channel location only valid if in Mixed mode */ + IWL_ERR(priv, "invalid extension channel offset\n"); + break; + } + } + } else { + rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; } - val = ht_info->ht_protection; - - rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); - if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); @@ -1122,8 +1135,9 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) priv->staging_rxon.cck_basic_rates = (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; - priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + /* clear both MIX and PURE40 mode flag */ + priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | + RXON_FLG_CHANNEL_MODE_PURE_40); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 065214b..f6d4af5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -586,6 +586,7 @@ static void iwl_bg_request_scan(struct work_struct *data) u8 rx_ant = priv->hw_params.valid_rx_ant; u8 rate; bool is_active = false; + int chan_mod; conf = ieee80211_get_hw_conf(priv->hw); @@ -703,7 +704,9 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { band = IEEE80211_BAND_2GHZ; scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { + chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK) + >> RXON_FLG_CHANNEL_MODE_POS; + if (chan_mod == CHANNEL_MODE_PURE_40) { rate = IWL_RATE_6M_PLCP; } else { rate = IWL_RATE_1M_PLCP; -- cgit v0.10.2 From ef850d7cb301bda9155c096269557a4586b58071 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 22 May 2009 11:01:50 -0700 Subject: iwlcore: support ICT interrupt Add ICT interrupt handler support, ICT should improve CPU utilization since it does not require target read which is very expensive. This interrupt handler only added to 5000 cards and newer. Device will write interrupts to ICT shared table to inform driver about its interrupts. These patches will not touch 3945 and 4965 interrupt handlers and tasklet. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8bed044..fd65e1c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2838,6 +2838,7 @@ static struct iwl_lib_ops iwl3945_lib = { .send_tx_power = iwl3945_send_tx_power, .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, .post_associate = iwl3945_post_associate, + .isr = iwl_isr_legacy, .config_ap = iwl3945_config_ap, }; @@ -2871,7 +2872,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, - .mod_params = &iwl3945_mod_params + .mod_params = &iwl3945_mod_params, + .use_isr_legacy = true }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2883,7 +2885,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, - .mod_params = &iwl3945_mod_params + .mod_params = &iwl3945_mod_params, + .use_isr_legacy = true }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 7df4116..a0b2941 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2286,6 +2286,7 @@ static struct iwl_lib_ops iwl4965_lib = { .update_chain_flags = iwl_update_chain_flags, .post_associate = iwl_post_associate, .config_ap = iwl_config_ap, + .isr = iwl_isr_legacy, .temp_ops = { .temperature = iwl4965_temperature_calib, .set_ct_kill = iwl4965_set_ct_threshold, @@ -2310,6 +2311,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, + .use_isr_legacy = true }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index bec5f8c..89e1477 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1487,6 +1487,7 @@ struct iwl_lib_ops iwl5000_lib = { .query_addr = iwl5000_eeprom_query_addr, }, .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwl5000_temperature, @@ -1536,6 +1537,7 @@ static struct iwl_lib_ops iwl5150_lib = { .query_addr = iwl5000_eeprom_query_addr, }, .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwl5150_temperature, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4e41038..fa24b01 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -937,7 +937,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -static void iwl_irq_tasklet(struct iwl_priv *priv) +static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) { u32 inta, handled = 0; u32 inta_fh; @@ -1121,6 +1121,174 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } +/* tasklet for iwlagn interrupt */ +static void iwl_irq_tasklet(struct iwl_priv *priv) +{ + u32 inta = 0; + u32 handled = 0; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + spin_lock_irqsave(&priv->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + */ + iwl_write32(priv, CSR_INT, priv->inta); + + inta = priv->inta; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & IWL_DL_ISR) { + /* just for debug */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); + IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", + inta, inta_mask); + } +#endif + /* saved interrupt in inta variable now we can reset priv->inta */ + priv->inta = 0; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + priv->isr_stats.hw++; + iwl_irq_handle_error(priv); + + handled |= CSR_INT_BIT_HW_ERR; + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_SCD) { + IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " + "the frame/frames.\n"); + priv->isr_stats.sch++; + } + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) { + IWL_DEBUG_ISR(priv, "Alive interrupt\n"); + priv->isr_stats.alive++; + } + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio" : "enable radio"); + + priv->isr_stats.rfkill++; + + /* driver only loads ucode once setting the interface up. + * the driver allows loading the ucode even if the radio + * is killed. Hence update the killswitch state here. The + * rfkill handler will care about restarting if needed. + */ + if (!test_bit(STATUS_ALIVE, &priv->status)) { + if (hw_rf_kill) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + queue_work(priv->workqueue, &priv->rf_kill); + } + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERR(priv, "Microcode CT kill error detected.\n"); + priv->isr_stats.ctkill++; + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERR(priv, "Microcode SW error detected. " + " Restarting 0x%X.\n", inta); + priv->isr_stats.sw++; + priv->isr_stats.sw_err = inta; + iwl_irq_handle_error(priv); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_txq_update_write_ptr(priv, &priv->txq[0]); + iwl_txq_update_write_ptr(priv, &priv->txq[1]); + iwl_txq_update_write_ptr(priv, &priv->txq[2]); + iwl_txq_update_write_ptr(priv, &priv->txq[3]); + iwl_txq_update_write_ptr(priv, &priv->txq[4]); + iwl_txq_update_write_ptr(priv, &priv->txq[5]); + + priv->isr_stats.wakeup++; + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + IWL_DEBUG_ISR(priv, "Rx interrupt\n"); + iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_RX_MASK); + iwl_rx_handle(priv); + priv->isr_stats.rx++; + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + } + + if (inta & CSR_INT_BIT_FH_TX) { + iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); + IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + priv->isr_stats.tx++; + handled |= CSR_INT_BIT_FH_TX; + /* FH finished to write, send event */ + priv->ucode_write_complete = 1; + wake_up_interruptible(&priv->wait_command_queue); + } + + if (inta & ~handled) { + IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); + priv->isr_stats.unhandled++; + } + + if (inta & ~CSR_INI_SET_MASK) { + IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", + inta & ~CSR_INI_SET_MASK); + } + + + /* Re-enable all interrupts */ + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl_enable_interrupts(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + +} + /****************************************************************************** * @@ -1550,6 +1718,8 @@ static void __iwl_down(struct iwl_priv *priv) test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; + /* device going down, Stop using ICT table */ + iwl_disable_ict(priv); spin_lock_irqsave(&priv->lock, flags); iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -1633,6 +1803,8 @@ static int __iwl_up(struct iwl_priv *priv) /* clear (again), then enable host interrupts */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + /* enable dram interrupt */ + iwl_reset_ict(priv); iwl_enable_interrupts(priv); /* really make sure rfkill handshake bits are cleared */ @@ -2533,8 +2705,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->statistics_periodic.data = (unsigned long)priv; priv->statistics_periodic.function = iwl_bg_statistics_periodic; - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); + if (!priv->cfg->use_isr_legacy) + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); + else + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet_legacy, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -2735,8 +2911,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(priv->pci_dev); - err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, - DRV_NAME, priv); + iwl_alloc_isr_ict(priv); + err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, + IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); goto out_disable_msi; @@ -2793,6 +2970,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); out_free_irq: free_irq(priv->pci_dev->irq, priv); + iwl_free_isr_ict(priv); out_disable_msi: pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); @@ -2874,6 +3052,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_uninit_drv(priv); + iwl_free_isr_ict(priv); + if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a15f795..12f0183 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -39,6 +39,7 @@ #include "iwl-rfkill.h" #include "iwl-power.h" #include "iwl-sta.h" +#include "iwl-helpers.h" MODULE_DESCRIPTION("iwl core"); @@ -59,6 +60,8 @@ MODULE_LICENSE("GPL"); IWL_RATE_##pp##M_INDEX, \ IWL_RATE_##np##M_INDEX } +static irqreturn_t iwl_isr(int irq, void *data); + /* * Parameter order: * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate @@ -1501,7 +1504,266 @@ void iwl_enable_interrupts(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_enable_interrupts); -irqreturn_t iwl_isr(int irq, void *data) + +#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) + +/* Free dram table */ +void iwl_free_isr_ict(struct iwl_priv *priv) +{ + if (priv->ict_tbl_vir) { + pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) + + PAGE_SIZE, priv->ict_tbl_vir, + priv->ict_tbl_dma); + priv->ict_tbl_vir = NULL; + } +} +EXPORT_SYMBOL(iwl_free_isr_ict); + + +/* allocate dram shared table it is a PAGE_SIZE aligned + * also reset all data related to ICT table interrupt. + */ +int iwl_alloc_isr_ict(struct iwl_priv *priv) +{ + + if (priv->cfg->use_isr_legacy) + return 0; + /* allocate shrared data table */ + priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) * + ICT_COUNT) + PAGE_SIZE, + &priv->ict_tbl_dma); + if (!priv->ict_tbl_vir) + return -ENOMEM; + + /* align table to PAGE_SIZE boundry */ + priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE); + + IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n", + (unsigned long long)priv->ict_tbl_dma, + (unsigned long long)priv->aligned_ict_tbl_dma, + (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); + + priv->ict_tbl = priv->ict_tbl_vir + + (priv->aligned_ict_tbl_dma - priv->ict_tbl_dma); + + IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n", + priv->ict_tbl, priv->ict_tbl_vir, + (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); + + /* reset table and index to all 0 */ + memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); + priv->ict_index = 0; + + return 0; +} +EXPORT_SYMBOL(iwl_alloc_isr_ict); + +/* Device is going up inform it about using ICT interrupt table, + * also we need to tell the driver to start using ICT interrupt. + */ +int iwl_reset_ict(struct iwl_priv *priv) +{ + u32 val; + unsigned long flags; + + if (!priv->ict_tbl_vir) + return 0; + + spin_lock_irqsave(&priv->lock, flags); + iwl_disable_interrupts(priv); + + memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT); + + val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; + + val |= CSR_DRAM_INT_TBL_ENABLE; + val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; + + IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X " + "aligned dma address %Lx\n", + val, (unsigned long long)priv->aligned_ict_tbl_dma); + + iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val); + priv->use_ict = true; + priv->ict_index = 0; + iwl_write32(priv, CSR_INT, CSR_INI_SET_MASK); + iwl_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL(iwl_reset_ict); + +/* Device is going down disable ict interrupt usage */ +void iwl_disable_ict(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + priv->use_ict = false; + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(iwl_disable_ict); + +/* interrupt handler using ict table, with this interrupt driver will + * stop using INTA register to get device's interrupt, reading this register + * is expensive, device will write interrupts in ICT dram table, increment + * index then will fire interrupt to driver, driver will OR all ICT table + * entries from current index up to table entry with 0 value. the result is + * the interrupt we need to service, driver will set the entries back to 0 and + * set index. + */ +irqreturn_t iwl_isr_ict(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 val = 0; + + if (!priv) + return IRQ_NONE; + + /* dram interrupt table not set yet, + * use legacy interrupt. + */ + if (!priv->use_ict) + return iwl_isr(irq, data); + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. + */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!priv->ict_tbl[priv->ict_index]) { + IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); + goto none; + } + + /* read all entries that not 0 start with ict_index */ + while (priv->ict_tbl[priv->ict_index]) { + + val |= priv->ict_tbl[priv->ict_index]; + IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", + priv->ict_index, + priv->ict_tbl[priv->ict_index]); + priv->ict_tbl[priv->ict_index] = 0; + priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, + ICT_COUNT); + + } + + /* We should not get this value, just ignore it. */ + if (val == 0xffffffff) + val = 0; + + inta = (0xff & val) | ((0xff00 & val) << 16); + IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", + inta, inta_mask, val); + + inta &= CSR_INI_SET_MASK; + priv->inta |= inta; + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta)) + tasklet_schedule(&priv->irq_tasklet); + else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) { + /* Allow interrupt if was disabled by this handler and + * no tasklet was schedules, We should not enable interrupt, + * tasklet will enable it. + */ + iwl_enable_interrupts(priv); + } + + spin_unlock(&priv->lock); + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. + * only Re-enable if disabled by irq. + */ + if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) + iwl_enable_interrupts(priv); + + spin_unlock(&priv->lock); + return IRQ_NONE; +} +EXPORT_SYMBOL(iwl_isr_ict); + + +static irqreturn_t iwl_isr(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 inta_fh; + + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta) { + IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared. It might have already raised + * an interrupt */ + IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); + goto unplugged; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & (IWL_DL_ISR)) { + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " + "fh 0x%08x\n", inta, inta_mask, inta_fh); + } +#endif + + priv->inta |= inta; + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta)) + tasklet_schedule(&priv->irq_tasklet); + else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) + iwl_enable_interrupts(priv); + + unplugged: + spin_unlock(&priv->lock); + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + /* only Re-enable if diabled by irq and no schedules tasklet. */ + if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) + iwl_enable_interrupts(priv); + + spin_unlock(&priv->lock); + return IRQ_NONE; +} + +irqreturn_t iwl_isr_legacy(int irq, void *data) { struct iwl_priv *priv = data; u32 inta, inta_mask; @@ -1558,7 +1820,7 @@ irqreturn_t iwl_isr(int irq, void *data) spin_unlock(&priv->lock); return IRQ_NONE; } -EXPORT_SYMBOL(iwl_isr); +EXPORT_SYMBOL(iwl_isr_legacy); int iwl_send_bt_config(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a0ed415..cbd87af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -170,6 +170,7 @@ struct iwl_lib_ops { void (*update_chain_flags)(struct iwl_priv *priv); void (*post_associate) (struct iwl_priv *priv); void (*config_ap) (struct iwl_priv *priv); + irqreturn_t (*isr) (int irq, void *data); /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; @@ -239,6 +240,7 @@ struct iwl_cfg { u8 valid_tx_ant; u8 valid_rx_ant; bool need_pll_cfg; + bool use_isr_legacy; }; /*************************** @@ -466,7 +468,13 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, *****************************************************/ void iwl_disable_interrupts(struct iwl_priv *priv); void iwl_enable_interrupts(struct iwl_priv *priv); -irqreturn_t iwl_isr(int irq, void *data); +irqreturn_t iwl_isr_legacy(int irq, void *data); +int iwl_reset_ict(struct iwl_priv *priv); +void iwl_disable_ict(struct iwl_priv *priv); +int iwl_alloc_isr_ict(struct iwl_priv *priv); +void iwl_free_isr_ict(struct iwl_priv *priv); +irqreturn_t iwl_isr_ict(int irq, void *data); + static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) { int pos; diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 3d50ef9..34c123e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -97,6 +97,7 @@ #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) #define CSR_LED_REG (CSR_BASE+0x094) +#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) /* Analog phase-lock-loop configuration */ @@ -256,6 +257,11 @@ /* HPET MEM debug */ #define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) + +/* DRAM INT TABLE */ +#define CSR_DRAM_INT_TBL_ENABLE (1 << 31) +#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) + /*=== HBUS (Host-side Bus) ===*/ #define HBUS_BASE (0x400) /* diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1310c41..2076742 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1048,6 +1048,14 @@ struct iwl_priv { /*End*/ struct iwl_hw_params hw_params; + /* INT ICT Table */ + u32 *ict_tbl; + dma_addr_t ict_tbl_dma; + dma_addr_t aligned_ict_tbl_dma; + int ict_index; + void *ict_tbl_vir; + u32 inta; + bool use_ict; /* Current association information needed to configure the * hardware */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8e68803..639893d 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4290,8 +4290,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_enable_msi(priv->pci_dev); - err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, - DRV_NAME, priv); + err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, + IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); goto out_disable_msi; -- cgit v0.10.2 From 4752c93c30441f98f7ed723001b1a5e3e5619829 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 22 May 2009 11:01:51 -0700 Subject: iwlcore: Allow skb allocation from tasklet. If RX queue becomes empty then we need to restock the queue from tasklet to prevent ucode from starving. A caller to iwl_rx_allocate will decide if allocated buffer should come from GFP_ATOMIC or GFP_KERNEL. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fa24b01..be1058b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -831,6 +831,7 @@ void iwl_rx_handle(struct iwl_priv *priv) unsigned long flags; u8 fill_rx = 0; u32 count = 8; + int total_empty; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ @@ -841,7 +842,12 @@ void iwl_rx_handle(struct iwl_priv *priv) if (i == r) IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); - if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + /* calculate total frames need to be restock after handling RX */ + total_empty = r - priv->rxq.write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) fill_rx = 1; while (i != r) { @@ -918,7 +924,7 @@ void iwl_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - iwl_rx_queue_restock(priv); + iwl_rx_replenish_now(priv); count = 0; } } @@ -926,7 +932,10 @@ void iwl_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl_rx_queue_restock(priv); + if (fill_rx) + iwl_rx_replenish_now(priv); + else + iwl_rx_queue_restock(priv); } /* call this function to flush any scheduled tasklet */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index cbd87af..87df1b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -318,10 +318,11 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); +void iwl_rx_replenish_now(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); 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); +void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority); void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); /* Handlers */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2076742..770cd1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -382,6 +382,7 @@ struct iwl_rx_queue { u32 read; u32 write; u32 free_count; + u32 write_actual; struct list_head rx_free; struct list_head rx_used; int need_update; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 7a43282..c845089 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -145,12 +145,14 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) goto exit_unlock; } - iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write & ~0x7); + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); /* Else device is assumed to be awake */ } else { /* Device expects a multiple of 8 */ - iwl_write32(priv, rx_wrt_ptr_reg, q->write & ~0x7); + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); } q->need_update = 0; @@ -212,7 +214,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if (write != (rxq->write & ~0x7)) { + if (rxq->write_actual != (rxq->write & ~0x7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); @@ -232,7 +234,7 @@ EXPORT_SYMBOL(iwl_rx_queue_restock); * Also restock the Rx queue via iwl_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -void iwl_rx_allocate(struct iwl_priv *priv) +void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; @@ -254,7 +256,8 @@ void iwl_rx_allocate(struct iwl_priv *priv) /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, - GFP_KERNEL); + priority); + if (!rxb->skb) { IWL_CRIT(priv, "Can not allocate SKB buffers\n"); /* We don't reschedule replenish work here -- we will @@ -289,7 +292,7 @@ void iwl_rx_replenish(struct iwl_priv *priv) { unsigned long flags; - iwl_rx_allocate(priv); + iwl_rx_allocate(priv, GFP_KERNEL); spin_lock_irqsave(&priv->lock, flags); iwl_rx_queue_restock(priv); @@ -297,6 +300,14 @@ void iwl_rx_replenish(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rx_replenish); +void iwl_rx_replenish_now(struct iwl_priv *priv) +{ + iwl_rx_allocate(priv, GFP_ATOMIC); + + iwl_rx_queue_restock(priv); +} +EXPORT_SYMBOL(iwl_rx_replenish_now); + /* Assumes that the skb field of the buffers in 'pool' is kept accurate. * If an SKB has been detached, the POOL needs to have its SKB set to NULL @@ -352,6 +363,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; + rxq->write_actual = 0; rxq->free_count = 0; rxq->need_update = 0; return 0; @@ -390,6 +402,7 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; + rxq->write_actual = 0; rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); } -- cgit v0.10.2 From 40cefda9ce11c44a2531d07af812900aa5f3ce9d Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 22 May 2009 11:01:52 -0700 Subject: iwlcore: Add support for periodic RX interrupt Periodic RX interrupt needed with ICT interrupt to prevent RX race. Sending RX interrupt require many steps to be done in the the device: 1- write interrupt to current index in ICT table. 2- dma RX frame. 3- update RX shared data to indicate last write index. 4- send interrupt. This could lead to RX race, driver could receive RX interrupt but the shared data changes does not reflect that. this could lead to RX race, RX periodic will solve this race Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index be1058b..889574d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1107,9 +1107,9 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) priv->isr_stats.unhandled++; } - if (inta & ~CSR_INI_SET_MASK) { + if (inta & ~(priv->inta_mask)) { IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~CSR_INI_SET_MASK); + inta & ~priv->inta_mask); IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); } @@ -1260,12 +1260,37 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* All uCode command responses, including Tx command responses, * Rx "responses" (frame-received notification), and other * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | + CSR_INT_BIT_RX_PERIODIC)) { IWL_DEBUG_ISR(priv, "Rx interrupt\n"); - iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_RX_MASK); + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + iwl_write32(priv, CSR_FH_INT_STATUS, + CSR49_FH_INT_RX_MASK); + } + if (inta & CSR_INT_BIT_RX_PERIODIC) { + handled |= CSR_INT_BIT_RX_PERIODIC; + iwl_write32(priv, CSR_INT, CSR_INT_BIT_RX_PERIODIC); + } + /* Sending RX interrupt require many steps to be done in the + * the device: + * 1- write interrupt to current index in ICT table. + * 2- dma RX frame. + * 3- update RX shared data to indicate last write index. + * 4- send interrupt. + * This could lead to RX race, driver could receive RX interrupt + * but the shared data changes does not reflect this. + * this could lead to RX race, RX periodic will solve this race + */ + iwl_write32(priv, CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_DIS); iwl_rx_handle(priv); + /* Only set RX periodic if real RX is received. */ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) + iwl_write32(priv, CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_ENA); + priv->isr_stats.rx++; - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } if (inta & CSR_INT_BIT_FH_TX) { @@ -1283,9 +1308,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) priv->isr_stats.unhandled++; } - if (inta & ~CSR_INI_SET_MASK) { + if (inta & ~(priv->inta_mask)) { IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~CSR_INI_SET_MASK); + inta & ~priv->inta_mask); } @@ -2808,6 +2833,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); priv->cfg = cfg; priv->pci_dev = pdev; + priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG priv->debug_level = priv->cfg->mod_params->debug; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 12f0183..e93ddb7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1500,7 +1500,7 @@ void iwl_enable_interrupts(struct iwl_priv *priv) { IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); + iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); } EXPORT_SYMBOL(iwl_enable_interrupts); @@ -1554,6 +1554,8 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv) memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); priv->ict_index = 0; + /* add periodic RX interrupt */ + priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC; return 0; } EXPORT_SYMBOL(iwl_alloc_isr_ict); @@ -1586,7 +1588,7 @@ int iwl_reset_ict(struct iwl_priv *priv) iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val); priv->use_ict = true; priv->ict_index = 0; - iwl_write32(priv, CSR_INT, CSR_INI_SET_MASK); + iwl_write32(priv, CSR_INT, priv->inta_mask); iwl_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -1668,7 +1670,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", inta, inta_mask, val); - inta &= CSR_INI_SET_MASK; + inta &= priv->inta_mask; priv->inta |= inta; /* iwl_irq_tasklet() will service interrupts and re-enable them */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 34c123e..e2fafb8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -100,6 +100,7 @@ #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) /* @@ -129,12 +130,14 @@ #define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN (0x02000000) #define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME (0x08000000) +#define CSR_INT_PERIODIC_DIS (0x00) +#define CSR_INT_PERIODIC_ENA (0xFF) /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ #define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ #define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ -#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ +#define CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */ #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 770cd1b..f9a3fd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1058,6 +1058,7 @@ struct iwl_priv { u32 inta; bool use_ict; + u32 inta_mask; /* Current association information needed to configure the * hardware */ u16 assoc_id; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 639893d..c434f49 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1944,9 +1944,9 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) priv->isr_stats.unhandled++; } - if (inta & ~CSR_INI_SET_MASK) { + if (inta & ~priv->inta_mask) { IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~CSR_INI_SET_MASK); + inta & ~priv->inta_mask); IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); } @@ -4184,6 +4184,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); priv->cfg = cfg; priv->pci_dev = pdev; + priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG priv->debug_level = iwl3945_mod_params.debug; -- cgit v0.10.2 From 0324c14b6f3730eb155dcff864b9c0cf8c893c5f Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 22 May 2009 11:01:53 -0700 Subject: iwlcore: Set rb_timeout to 0x10 for devices with ICT rb value should be 0x10 for devices using ICT. RX interrupt was not performing well with 0 value Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index c845089..2b8d40b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -412,7 +412,10 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { 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 */ + u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ + + if (!priv->cfg->use_isr_legacy) + rb_timeout = RX_RB_TIMEOUT; if (priv->cfg->mod_params->amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; -- cgit v0.10.2 From 086ed117c918f07fd40323ab5adc64c52ea7c1b8 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 22 May 2009 11:01:54 -0700 Subject: iwlagn: co-exist with AMT Enable using iwlwifi driver in AMT system. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 889574d..0a5507c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1792,6 +1792,49 @@ static void iwl_down(struct iwl_priv *priv) iwl_cancel_deferred_work(priv); } +#define HW_READY_TIMEOUT (50) + +static int iwl_set_hw_ready(struct iwl_priv *priv) +{ + int ret = 0; + + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + HW_READY_TIMEOUT); + if (ret != -ETIMEDOUT) + priv->hw_ready = true; + else + priv->hw_ready = false; + + IWL_DEBUG_INFO(priv, "hardware %s\n", + (priv->hw_ready == 1) ? "ready" : "not ready"); + return ret; +} + +static int iwl_prepare_card_hw(struct iwl_priv *priv) +{ + int ret = 0; + + IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n"); + + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PREPARE); + + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, + CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); + + if (ret != -ETIMEDOUT) + iwl_set_hw_ready(priv); + + return ret; +} + #define MAX_HW_RESTARTS 5 static int __iwl_up(struct iwl_priv *priv) @@ -1809,6 +1852,13 @@ static int __iwl_up(struct iwl_priv *priv) return -EIO; } + iwl_prepare_card_hw(priv); + + if (!priv->hw_ready) { + IWL_WARN(priv, "Exit HW not ready\n"); + return -EIO; + } + /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); @@ -2896,6 +2946,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); + iwl_prepare_card_hw(priv); + if (!priv->hw_ready) { + IWL_WARN(priv, "Failed, HW not ready\n"); + goto out_iounmap; + } + /* amp init */ err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index e2fafb8..f03dae1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -126,9 +126,9 @@ #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) -#define CSR_HW_IF_CONFIG_REG_BIT_PCI_OWN_SEM (0x00400000) -#define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN (0x02000000) -#define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME (0x08000000) +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) +#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) #define CSR_INT_PERIODIC_DIS (0x00) #define CSR_INT_PERIODIC_ENA (0xFF) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f9a3fd6..2dafc26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1113,7 +1113,7 @@ struct iwl_priv { u32 disable_tx_power_cal; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; - + bool hw_ready; /*For 3945*/ #define IWL_DEFAULT_TX_POWER 0x0F -- cgit v0.10.2 From a2e2322d83df82a57ba456cfa604c8b8f7b04670 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 22 May 2009 11:01:55 -0700 Subject: iwlwifi: check for valid band for channel info when display channel info in debugfs, always check for valid band before access the pointer and display information for 1000 NIC, it only support "bgn" mode, so there is no 5.2GHz channels available to display. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 03006c6..af70229 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -380,50 +380,53 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); - channels = supp_band->channels; + if (supp_band) { + channels = supp_band->channels; - pos += scnprintf(buf + pos, bufsz - pos, - "Displaying %d channels in 2.4GHz band 802.11bg):\n", - supp_band->n_channels); - - for (i = 0; i < supp_band->n_channels; i++) pos += scnprintf(buf + pos, bufsz - pos, - "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); + "Displaying %d channels in 2.4GHz band 802.11bg):\n", + supp_band->n_channels); + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); - channels = supp_band->channels; + if (supp_band) { + channels = supp_band->channels; - pos += scnprintf(buf + pos, bufsz - pos, - "Displaying %d channels in 5.2GHz band (802.11a)\n", - supp_band->n_channels); - - for (i = 0; i < supp_band->n_channels; i++) pos += scnprintf(buf + pos, bufsz - pos, - "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); + "Displaying %d channels in 5.2GHz band (802.11a)\n", + supp_band->n_channels); + + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; -- cgit v0.10.2 From 8e29291650ee53a8609d9cc3a303dcbe9aa9b542 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Sun, 24 May 2009 03:16:51 +0000 Subject: mlx4_en: Removed redundant stride variable Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 7bcc49d..be487fa 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -559,7 +559,6 @@ int mlx4_en_start_port(struct net_device *dev) struct mlx4_en_rx_ring *rx_ring; int rx_index = 0; int tx_index = 0; - u16 stride; int err = 0; int i; int j; @@ -573,8 +572,6 @@ int mlx4_en_start_port(struct net_device *dev) dev->mtu = min(dev->mtu, priv->max_mtu); mlx4_en_calc_rx_buf(dev); mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); - stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + - DS_SIZE * priv->num_frags); /* Configure rx cq's and rings */ for (i = 0; i < priv->rx_ring_num; i++) { cq = &priv->rx_cq[i]; -- cgit v0.10.2 From 38aab07c14adbf3c7257793d764a91923341e96a Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Sun, 24 May 2009 03:17:11 +0000 Subject: mlx4_en: Fix partial rings feature In case of allocation failure, the actual ring size is rounded down to nearest power of 2. The remaining descriptors are freed. The CQ and SRQ are allocated with the actual size and the mask is updated. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c index a276125..21786ad 100644 --- a/drivers/net/mlx4/en_cq.c +++ b/drivers/net/mlx4/en_cq.c @@ -89,6 +89,9 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) *cq->mcq.arm_db = 0; memset(cq->buf, 0, cq->buf_size); + if (!cq->is_tx) + cq->size = priv->rx_ring[cq->ring].actual_size; + err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx); if (err) diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index be487fa..0cd185a 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -556,7 +556,6 @@ int mlx4_en_start_port(struct net_device *dev) struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_cq *cq; struct mlx4_en_tx_ring *tx_ring; - struct mlx4_en_rx_ring *rx_ring; int rx_index = 0; int tx_index = 0; int err = 0; @@ -572,10 +571,15 @@ int mlx4_en_start_port(struct net_device *dev) dev->mtu = min(dev->mtu, priv->max_mtu); mlx4_en_calc_rx_buf(dev); mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); + /* Configure rx cq's and rings */ + err = mlx4_en_activate_rx_rings(priv); + if (err) { + mlx4_err(mdev, "Failed to activate RX rings\n"); + return err; + } for (i = 0; i < priv->rx_ring_num; i++) { cq = &priv->rx_cq[i]; - rx_ring = &priv->rx_ring[i]; err = mlx4_en_activate_cq(priv, cq); if (err) { @@ -591,20 +595,14 @@ int mlx4_en_start_port(struct net_device *dev) goto cq_err; } mlx4_en_arm_cq(priv, cq); - + priv->rx_ring[i].cqn = cq->mcq.cqn; ++rx_index; } - err = mlx4_en_activate_rx_rings(priv); - if (err) { - mlx4_err(mdev, "Failed to activate RX rings\n"); - goto cq_err; - } - err = mlx4_en_config_rss_steer(priv); if (err) { mlx4_err(mdev, "Failed configuring rss steering\n"); - goto rx_err; + goto cq_err; } /* Configure tx cq's and rings */ @@ -691,12 +689,11 @@ tx_err: } mlx4_en_release_rss_steer(priv); -rx_err: - for (i = 0; i < priv->rx_ring_num; i++) - mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); cq_err: while (rx_index--) mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); + for (i = 0; i < priv->rx_ring_num; i++) + mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); return err; /* need to close devices */ } diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 9ee873e..6bfab6e 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -202,12 +202,35 @@ static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); } +static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, + int index) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct skb_frag_struct *skb_frags; + struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride); + dma_addr_t dma; + int nr; + + skb_frags = ring->rx_info + (index << priv->log_rx_info); + for (nr = 0; nr < priv->num_frags; nr++) { + mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr); + dma = be64_to_cpu(rx_desc->data[nr].addr); + + mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); + pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, + PCI_DMA_FROMDEVICE); + put_page(skb_frags[nr].page); + } +} + static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) { struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_rx_ring *ring; int ring_ind; int buf_ind; + int new_size; for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) { for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { @@ -220,18 +243,30 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) "enough rx buffers\n"); return -ENOMEM; } else { - if (netif_msg_rx_err(priv)) - mlx4_warn(mdev, - "Only %d buffers allocated\n", - ring->actual_size); - goto out; + new_size = rounddown_pow_of_two(ring->actual_size); + mlx4_warn(mdev, "Only %d buffers allocated " + "reducing ring size to %d", + ring->actual_size, new_size); + goto reduce_rings; } } ring->actual_size++; ring->prod++; } } -out: + return 0; + +reduce_rings: + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { + ring = &priv->rx_ring[ring_ind]; + while (ring->actual_size > new_size) { + ring->actual_size--; + ring->prod--; + mlx4_en_free_rx_desc(priv, ring, ring->actual_size); + } + ring->size_mask = ring->actual_size - 1; + } + return 0; } @@ -255,7 +290,7 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, ++num; ++ring->prod; } - if ((u32) (ring->prod - ring->cons) == ring->size) + if ((u32) (ring->prod - ring->cons) == ring->actual_size) ring->full = 1; return num; @@ -264,33 +299,17 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring) { - struct mlx4_en_dev *mdev = priv->mdev; - struct skb_frag_struct *skb_frags; - struct mlx4_en_rx_desc *rx_desc; - dma_addr_t dma; int index; - int nr; mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", ring->cons, ring->prod); /* Unmap and free Rx buffers */ - BUG_ON((u32) (ring->prod - ring->cons) > ring->size); + BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); while (ring->cons != ring->prod) { index = ring->cons & ring->size_mask; - rx_desc = ring->buf + (index << ring->log_stride); - skb_frags = ring->rx_info + (index << priv->log_rx_info); mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index); - - for (nr = 0; nr < priv->num_frags; nr++) { - mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr); - dma = be64_to_cpu(rx_desc->data[nr].addr); - - mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); - pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, - PCI_DMA_FROMDEVICE); - put_page(skb_frags[nr].page); - } + mlx4_en_free_rx_desc(priv, ring, index); ++ring->cons; } } @@ -454,7 +473,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) mlx4_en_update_rx_prod_db(ring); /* Configure SRQ representing the ring */ - ring->srq.max = ring->size; + ring->srq.max = ring->actual_size; ring->srq.max_gs = max_gs; ring->srq.wqe_shift = ilog2(ring->stride); -- cgit v0.10.2 From 18af3e7c4535be88f864fc4bcff9a97fb4ae3731 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Sun, 24 May 2009 05:27:41 +0000 Subject: myri10ge: fix the invokation of lro_flush_all Fix the way we check whether lro_flush_all should be called in the myri10ge driver. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index c9a9aca..d317011 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1422,6 +1422,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) { struct myri10ge_rx_done *rx_done = &ss->rx_done; struct myri10ge_priv *mgp = ss->mgp; + struct net_device *netdev = mgp->dev; unsigned long rx_bytes = 0; unsigned long rx_packets = 0; unsigned long rx_ok; @@ -1455,7 +1456,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) ss->stats.rx_packets += rx_packets; ss->stats.rx_bytes += rx_bytes; - if (myri10ge_lro) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&rx_done->lro_mgr); /* restock receive rings if needed */ -- cgit v0.10.2 From 2552c31be3bcc7681e603cde44d97b66e4a885f0 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Sun, 24 May 2009 05:27:51 +0000 Subject: myri10ge: drop myri10ge_lro module parameter Drop the myri10ge_lro module parameter now that we have ethtool to enable/disable LRO in the myri10ge driver. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index d317011..675f677 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -327,10 +327,6 @@ static int myri10ge_debug = -1; /* defaults above */ module_param(myri10ge_debug, int, 0); MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); -static int myri10ge_lro = 1; -module_param(myri10ge_lro, int, S_IRUGO); -MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload"); - static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS; module_param(myri10ge_lro_max_pkts, int, S_IRUGO); MODULE_PARM_DESC(myri10ge_lro_max_pkts, @@ -3918,8 +3914,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; - if (myri10ge_lro) - netdev->features |= NETIF_F_LRO; + netdev->features |= NETIF_F_LRO; /* make sure we can get an irq, and that MSI can be * setup (if available). Also ensure netdev->irq -- cgit v0.10.2 From dddc045e2fdd4eb8d7dfac29bff191d639fff8c3 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Sun, 24 May 2009 05:27:59 +0000 Subject: myri10ge: Add support for vlan_features Add support for netdev->vlan_features in the myri10ge driver. Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 675f677..7e28b461 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.5.0-1.415" +#define MYRI10GE_VERSION_STR "1.5.0-1.418" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -3916,6 +3916,12 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_LRO; + netdev->vlan_features |= mgp->features; + if (mgp->fw_ver_tiny < 37) + netdev->vlan_features &= ~NETIF_F_TSO6; + if (mgp->fw_ver_tiny < 32) + netdev->vlan_features &= ~NETIF_F_TSO; + /* make sure we can get an irq, and that MSI can be * setup (if available). Also ensure netdev->irq * is set to correct value if MSI is enabled */ -- cgit v0.10.2 From 82c49a352e0fd7af7e79a922b863f33f619f3209 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 22 May 2009 22:11:37 +0000 Subject: skbuff: Move new code into __copy_skb_header Hi: skbuff: Move new __skb_clone code into __copy_skb_header It seems that people just keep on adding stuff to __skb_clone instead __copy_skb_header. This is wrong as it means your brand-new attributes won't always get copied as you intended. This patch moves them to the right place, and adds a comment to prevent this from happening again. Signed-off-by: Herbert Xu Thanks, Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d152394..e47afb2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -538,6 +538,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif new->protocol = old->protocol; new->mark = old->mark; + new->iif = old->iif; __nf_copy(new, old); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) @@ -550,10 +551,18 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif #endif new->vlan_tci = old->vlan_tci; +#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) + new->do_not_encrypt = old->do_not_encrypt; + new->requeue = old->requeue; +#endif skb_copy_secmark(new, old); } +/* + * You should not add any new code to this function. Add it to + * __copy_skb_header above instead. + */ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) { #define C(x) n->x = skb->x @@ -569,16 +578,11 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->cloned = 1; n->nohdr = 0; n->destructor = NULL; - C(iif); C(tail); C(end); C(head); C(data); C(truesize); -#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) - C(do_not_encrypt); - C(requeue); -#endif atomic_set(&n->users, 1); atomic_inc(&(skb_shinfo(skb)->dataref)); -- cgit v0.10.2 From 9bcb97cace615a9f57fca0b9d788e7d234d7fc95 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 22 May 2009 22:20:02 +0000 Subject: skbuff: Copy csum instead of csum_start/csum_offset Hi: skbuff: Copy csum instead of csum_start/csum_offset It's easier to copy the u32 csum instead of its two u16 constituents. Signed-off-by: Herbert Xu Cheers, Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index e47afb2..47fbbb8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -526,8 +526,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->sp = secpath_get(old->sp); #endif memcpy(new->cb, old->cb, sizeof(old->cb)); - new->csum_start = old->csum_start; - new->csum_offset = old->csum_offset; + new->csum = old->csum; new->local_df = old->local_df; new->pkt_type = old->pkt_type; new->ip_summed = old->ip_summed; -- cgit v0.10.2 From 7df3bb8f59ca8e346bb834006c257cc367c6250a Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:44 +0000 Subject: mISDN: Add watchdog functionality to hfcmulti driver This patch was made by Titus Moldovan and provides IOCTL functions for enabling and disabling the controller's built in watchdog. The use is optional. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 663b77f..5765e19 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -62,6 +62,7 @@ struct hfcm_hw { u_char r_sci_msk; u_char r_tx0, r_tx1; u_char a_st_ctrl0[8]; + u_char r_bert_wd_md; timer_t timer; }; diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 0b28141..ca153de 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -4013,11 +4013,41 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, static int channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) { + struct hfc_multi *hc = dch->hw; int ret = 0; + int wd_mode, wd_cnt; switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = 0; + cq->op = MISDN_CTRL_HFC_OP; + break; + case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ + wd_cnt = cq->p1 & 0xf; + wd_mode = !!(cq->p1 >> 4); + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG + "%s: MISDN_CTRL_HFC_WD_INIT mode %s counter 0x%x\n", + __func__, wd_mode ? "AUTO" : "MANUAL", wd_cnt); + /* set the watchdog timer */ + HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4)); + hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0); + if (hc->ctype == HFC_TYPE_XHFC) + hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */; + /* init the watchdog register and reset the counter */ + HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); + if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { + /* enable the watchdog output for Speech-Design */ + HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7); + HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15); + HFC_outb(hc, R_GPIO_OUT1, 0); + HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15); + } + break; + case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n", + __func__); + HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); break; default: printk(KERN_WARNING "%s: unknown Op %x\n", diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index 5da3d95..cf97459 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -362,7 +362,8 @@ clear_channelmap(u_int nr, u_char *map) #define MISDN_CTRL_HFC_RECEIVE_ON 0x4006 #define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007 #define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008 - +#define MISDN_CTRL_HFC_WD_INIT 0x4009 +#define MISDN_CTRL_HFC_WD_RESET 0x400A /* socket options */ #define MISDN_TIME_STAMP 0x0001 -- cgit v0.10.2 From a5355c27d26001865a5ac32c868c82a523c275d3 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:45 +0000 Subject: mISDN: DSP now uses ring buffer for echo canceler DSP now uses ring buffer for echo canceler. Added missing include in l1oip_codec.c Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 98a33c58f..0a4a362 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -112,7 +112,8 @@ struct dsp_conf { #define DSP_DTMF_NPOINTS 102 -#define ECHOCAN_BUFLEN (4*128) +#define ECHOCAN_BUFF_SIZE 0x400 /* must be 2**n */ +#define ECHOCAN_BUFF_MASK 0x3ff /* -1 */ struct dsp_dtmf { int treshold; /* above this is dtmf (square of) */ diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c index e4ecba3..bbfd1b8 100644 --- a/drivers/isdn/mISDN/l1oip_codec.c +++ b/drivers/isdn/mISDN/l1oip_codec.c @@ -48,6 +48,7 @@ NOTE: The bytes are handled as they are law-encoded. #include #include +#include #include "core.h" #include "l1oip.h" -- cgit v0.10.2 From 7cfa153dd709f15188fe84b78ae76387841fe17b Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:46 +0000 Subject: mISDN: Echo canceler now gets delay information from hardware Added tx-fifo information for calculation of current delay to sync tx and rx streams for echo canceler. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 5765e19..c4878cc 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -44,6 +44,7 @@ struct hfc_chan { int conf; /* conference setting of TX slot */ int txpending; /* if there is currently data in */ /* the FIFO 0=no, 1=yes, 2=splloop */ + int Zfill; /* rx-fifo level on last hfcmulti_tx */ int rx_off; /* set to turn fifo receive off */ int coeff_count; /* curren coeff block */ s32 *coeff; /* memory pointer to 8 coeff blocks */ diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index ca153de..3a7c26c 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -1945,6 +1945,9 @@ next_frame: "%d!=%d\n", __func__, hc->id + 1, temp, z2); z2 = temp; /* repeat unti Z2 is equal */ } + hc->chan[ch].Zfill = z1 - z2; + if (hc->chan[ch].Zfill < 0) + hc->chan[ch].Zfill += hc->Zlen; Zspace = z2 - z1; if (Zspace <= 0) Zspace += hc->Zlen; @@ -2031,6 +2034,7 @@ next_frame: /* Have to prep the audio data */ hc->write_fifo(hc, d, ii - i); + hc->chan[ch].Zfill += ii - i; *idxp = ii; /* if not all data has been written */ @@ -2226,7 +2230,7 @@ next_frame: if (dch) recv_Dchannel(dch); else - recv_Bchannel(bch); + recv_Bchannel(bch, MISDN_ID_ANY); *sp = skb; again++; goto next_frame; @@ -2258,7 +2262,7 @@ next_frame: "(z1=%04x, z2=%04x) TRANS\n", __func__, hc->id + 1, ch, Zsize, z1, z2); /* only bch is transparent */ - recv_Bchannel(bch); + recv_Bchannel(bch, hc->chan[ch].Zfill); *sp = skb; } } diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 641a9cd..60dc925 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -452,7 +452,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, } bz->za[new_f2].z2 = cpu_to_le16(new_z2); bz->f2 = new_f2; /* next buffer */ - recv_Bchannel(bch); + recv_Bchannel(bch, MISDN_ID_ANY); } } @@ -541,35 +541,45 @@ receive_dmsg(struct hfc_pci *hc) * check for transparent receive data and read max one 'poll' size if avail */ static void -hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) +hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, + struct bzfifo *txbz, u_char *bdata) { - __le16 *z1r, *z2r; - int new_z2, fcnt, maxlen; - u_char *ptr, *ptr1; + __le16 *z1r, *z2r, *z1t, *z2t; + int new_z2, fcnt_rx, fcnt_tx, maxlen; + u_char *ptr, *ptr1; - z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ + z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ z2r = z1r + 1; + z1t = &txbz->za[MAX_B_FRAMES].z1; + z2t = z1t + 1; - fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); - if (!fcnt) + fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); + if (!fcnt_rx) return; /* no data avail */ - if (fcnt <= 0) - fcnt += B_FIFO_SIZE; /* bytes actually buffered */ - new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ + if (fcnt_rx <= 0) + fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */ + new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - if (fcnt > MAX_DATA_SIZE) { /* flush, if oversized */ + if (fcnt_rx > MAX_DATA_SIZE) { /* flush, if oversized */ *z2r = cpu_to_le16(new_z2); /* new position */ return; } - bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC); + fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); + if (fcnt_tx <= 0) + fcnt_tx += B_FIFO_SIZE; + /* fcnt_tx contains available bytes in tx-fifo */ + fcnt_tx = B_FIFO_SIZE - fcnt_tx; + /* remaining bytes to send (bytes in tx-fifo) */ + + bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC); if (bch->rx_skb) { - ptr = skb_put(bch->rx_skb, fcnt); - if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = fcnt; /* complete transfer */ + ptr = skb_put(bch->rx_skb, fcnt_rx); + if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) + maxlen = fcnt_rx; /* complete transfer */ else maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); /* maximum */ @@ -577,14 +587,14 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); /* start of data */ memcpy(ptr, ptr1, maxlen); /* copy data */ - fcnt -= maxlen; + fcnt_rx -= maxlen; - if (fcnt) { /* rest remaining */ + if (fcnt_rx) { /* rest remaining */ ptr += maxlen; ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, fcnt); /* rest */ + memcpy(ptr, ptr1, fcnt_rx); /* rest */ } - recv_Bchannel(bch); + recv_Bchannel(bch, fcnt_tx); /* bch, id */ } else printk(KERN_WARNING "HFCPCI: receive out of memory\n"); @@ -600,26 +610,28 @@ main_rec_hfcpci(struct bchannel *bch) struct hfc_pci *hc = bch->hw; int rcnt, real_fifo; int receive = 0, count = 5; - struct bzfifo *bz; + struct bzfifo *txbz, *rxbz; u_char *bdata; struct zt *zp; if ((bch->nr & 2) && (!hc->hw.bswapped)) { - bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; + rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; + txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; real_fifo = 1; } else { - bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; + rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; + txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1; real_fifo = 0; } Begin: count--; - if (bz->f1 != bz->f2) { + if (rxbz->f1 != rxbz->f2) { if (bch->debug & DEBUG_HW_BCHANNEL) printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", - bch->nr, bz->f1, bz->f2); - zp = &bz->za[bz->f2]; + bch->nr, rxbz->f1, rxbz->f2); + zp = &rxbz->za[rxbz->f2]; rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); if (rcnt < 0) @@ -630,8 +642,8 @@ Begin: "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", bch->nr, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt); - hfcpci_empty_bfifo(bch, bz, bdata, rcnt); - rcnt = bz->f1 - bz->f2; + hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt); + rcnt = rxbz->f1 - rxbz->f2; if (rcnt < 0) rcnt += MAX_B_FRAMES + 1; if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { @@ -644,7 +656,7 @@ Begin: else receive = 0; } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { - hfcpci_empty_fifo_trans(bch, bz, bdata); + hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata); return; } else receive = 0; diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 9c427fb..6b7704c 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -947,7 +947,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, if (fifo->dch) recv_Dchannel(fifo->dch); if (fifo->bch) - recv_Bchannel(fifo->bch); + recv_Bchannel(fifo->bch, MISDN_ID_ANY); if (fifo->ech) recv_Echannel(fifo->ech, &hw->dch); @@ -969,7 +969,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, } else { /* deliver transparent data to layer2 */ if (rx_skb->len >= poll) - recv_Bchannel(fifo->bch); + recv_Bchannel(fifo->bch, MISDN_ID_ANY); } spin_unlock(&hw->lock); } diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 0a4a362..4a1c444d 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -262,5 +262,5 @@ extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len); extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, - int len); + int len, unsigned int txlen); diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 3083338..1c49368 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -710,7 +710,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) /* pipeline */ if (dsp->pipeline.inuse) dsp_pipeline_process_rx(&dsp->pipeline, skb->data, - skb->len); + skb->len, hh->id); /* change volume if requested */ if (dsp->rx_volume) dsp_change_volume(skb, dsp->rx_volume); diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 18cf87c..ac61f19 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -347,7 +347,8 @@ void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len) entry->elem->process_tx(entry->p, data, len); } -void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) +void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len, + unsigned int txlen) { struct dsp_pipeline_entry *entry; @@ -356,7 +357,7 @@ void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) list_for_each_entry_reverse(entry, &pipeline->list, list) if (entry->elem->process_rx) - entry->elem->process_rx(entry->p, data, len); + entry->elem->process_rx(entry->p, data, len, txlen); } diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index ab1168a..0481a0c 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -185,13 +185,13 @@ recv_Echannel(struct dchannel *ech, struct dchannel *dch) EXPORT_SYMBOL(recv_Echannel); void -recv_Bchannel(struct bchannel *bch) +recv_Bchannel(struct bchannel *bch, unsigned int id) { struct mISDNhead *hh; hh = mISDN_HEAD_P(bch->rx_skb); hh->prim = PH_DATA_IND; - hh->id = MISDN_ID_ANY; + hh->id = id; if (bch->rcount >= 64) { printk(KERN_WARNING "B-channel %p receive queue overflow, " "fushing!\n", bch); diff --git a/include/linux/mISDNdsp.h b/include/linux/mISDNdsp.h index 6b71d2d..2c483d4 100644 --- a/include/linux/mISDNdsp.h +++ b/include/linux/mISDNdsp.h @@ -12,7 +12,8 @@ struct mISDN_dsp_element { void *(*new)(const char *arg); void (*free)(void *p); void (*process_tx)(void *p, unsigned char *data, int len); - void (*process_rx)(void *p, unsigned char *data, int len); + void (*process_rx)(void *p, unsigned char *data, int len, + unsigned int txlen); int num_args; struct mISDN_dsp_element_arg *args; diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index 97ffdc1..ce900f4 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -185,7 +185,7 @@ extern int dchannel_senddata(struct dchannel *, struct sk_buff *); extern int bchannel_senddata(struct bchannel *, struct sk_buff *); extern void recv_Dchannel(struct dchannel *); extern void recv_Echannel(struct dchannel *, struct dchannel *); -extern void recv_Bchannel(struct bchannel *); +extern void recv_Bchannel(struct bchannel *, unsigned int id); extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *); extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *); extern void confirm_Bsend(struct bchannel *bch); -- cgit v0.10.2 From 44e095897d745a03d71611fd318f26d8b12a4771 Mon Sep 17 00:00:00 2001 From: Frank Seidel Date: Fri, 22 May 2009 11:04:47 +0000 Subject: mISDN: Reduce stack size in dsp_cmx_send() Reduce stack size memory footprint of mISDN_dsp. (From 1468 bytes for dsp_cmx_send on i386 down to 44). Signed-off-by: Frank Seidel Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 3a7c26c..fc76f40 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -104,7 +104,7 @@ * If unsure, don't give this parameter. * * dslot: - * NOTE: only one poll value must be given for every card. + * NOTE: only one dslot value must be given for every card. * Also this value must be given for non-E1 cards. If omitted, the E1 * card has D-channel on time slot 16, which is default. * If 1..15 or 17..31, an alternate time slot is used for D-channel. diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 58c43e4..ac84146 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1592,7 +1592,8 @@ dsp_cmx_send(void *arg) struct dsp_conf_member *member; struct dsp *dsp; int mustmix, members; - s32 mixbuffer[MAX_POLL+100], *c; + static s32 mixbuffer[MAX_POLL+100]; + s32 *c; u8 *p, *q; int r, rr; int jittercheck = 0, delay, i; -- cgit v0.10.2 From ba3af34ec9866dddac36c15947f867eb8e889bbc Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:47 +0000 Subject: mISDN: Fixed missing spin lock on pipeline process Need to protect the complete pipeline. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 1c49368..621ea9b 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -704,6 +704,8 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) break; } + spin_lock_irqsave(&dsp_lock, flags); + /* decrypt if enabled */ if (dsp->bf_enable) dsp_bf_decrypt(dsp, skb->data, skb->len); @@ -741,11 +743,11 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) } } /* we need to process receive data if software */ - spin_lock_irqsave(&dsp_lock, flags); if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { /* process data from card at cmx */ dsp_cmx_receive(dsp, skb); } + spin_unlock_irqrestore(&dsp_lock, flags); if (dsp->rx_disabled) { -- cgit v0.10.2 From e73f6b2260daf02793071e5ce06ea87df762920a Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:48 +0000 Subject: mISDN: Added layer-1-hold feature Add IMHOLD_L1 ioctl. The feature will be disabled on closing. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 508945d..530f68977 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -292,7 +292,7 @@ static int data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) { struct mISDN_ctrl_req cq; - int err = -EINVAL, val; + int err = -EINVAL, val[2]; struct mISDNchannel *bchan, *next; lock_sock(sk); @@ -328,12 +328,27 @@ data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) err = -EINVAL; break; } - if (get_user(val, (int __user *)p)) { + val[0] = cmd; + if (get_user(val[1], (int __user *)p)) { err = -EFAULT; break; } err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, - CONTROL_CHANNEL, &val); + CONTROL_CHANNEL, val); + break; + case IMHOLD_L1: + if (sk->sk_protocol != ISDN_P_LAPD_NT + && sk->sk_protocol != ISDN_P_LAPD_TE) { + err = -EINVAL; + break; + } + val[0] = cmd; + if (get_user(val[1], (int __user *)p)) { + err = -EFAULT; + break; + } + err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, + CONTROL_CHANNEL, val); break; default: err = -EINVAL; diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index b452dea..c75af76 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -122,8 +122,11 @@ da_deactivate(struct FsmInst *fi, int event, void *arg) } read_unlock_irqrestore(&mgr->lock, flags); /* All TEI are inactiv */ - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); - mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); + if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { + mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, + NULL, 1); + mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); + } } static void @@ -132,9 +135,11 @@ da_ui(struct FsmInst *fi, int event, void *arg) struct manager *mgr = fi->userdata; /* restart da timer */ - mISDN_FsmDelTimer(&mgr->datimer, 2); - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); - + if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { + mISDN_FsmDelTimer(&mgr->datimer, 2); + mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, + NULL, 2); + } } static void @@ -1103,6 +1108,7 @@ free_teimanager(struct manager *mgr) { struct layer2 *l2, *nl2; + test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { /* not locked lock is taken in release tei */ mgr->up = NULL; @@ -1133,13 +1139,26 @@ static int ctrl_teimanager(struct manager *mgr, void *arg) { /* currently we only have one option */ - int clean = *((int *)arg); - - if (clean) - test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); - else - test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); - return 0; + int *val = (int *)arg; + int ret = 0; + + switch (val[0]) { + case IMCLEAR_L2: + if (val[1]) + test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); + else + test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); + break; + case IMHOLD_L1: + if (val[1]) + test_and_set_bit(OPTION_L1_HOLD, &mgr->options); + else + test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); + break; + default: + ret = -EINVAL; + } + return ret; } /* This function does create a L2 for fixed TEI in NT Mode */ diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index cf97459..0b28fd1 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -229,6 +229,7 @@ #define OPTION_L2_PTP 2 #define OPTION_L2_FIXEDTEI 3 #define OPTION_L2_CLEANUP 4 +#define OPTION_L1_HOLD 5 /* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ #define MISDN_MAX_IDLEN 20 @@ -317,6 +318,7 @@ struct ph_info { #define IMCTRLREQ _IOR('I', 69, int) #define IMCLEAR_L2 _IOR('I', 70, int) #define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename) +#define IMHOLD_L1 _IOR('I', 72, int) static inline int test_channelmap(u_int nr, u_char *map) -- cgit v0.10.2 From b5df5a5c3bf0f809d854ad7156ce26b709b533c0 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:48 +0000 Subject: mISDN: Fix DTMF locking bug issue DTMF digits were sent up to socket in locked state. Receive audio stream was not enabled in certain condition. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index fc76f40..bc0d3ef 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -1817,8 +1817,8 @@ hfcmulti_dtmf(struct hfc_multi *hc) coeff[(co<<1)|1] = mantissa; } if (debug & DEBUG_HFCMULTI_DTMF) - printk("%s: DTMF ready %08x %08x %08x %08x " - "%08x %08x %08x %08x\n", __func__, + printk(" DTMF ready %08x %08x %08x %08x " + "%08x %08x %08x %08x\n", coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5], coeff[6], coeff[7]); hc->chan[ch].coeff_count++; diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 4a1c444d..41c6cfd 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -124,7 +124,7 @@ struct dsp_dtmf { /* buffers one full dtmf frame */ u8 lastwhat, lastdigit; int count; - u8 digits[16]; /* just the dtmf result */ + u8 digits[16]; /* dtmf result */ }; diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 621ea9b..6b49398 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -311,6 +311,7 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) /* check dtmf hardware */ dsp_dtmf_hardware(dsp); + dsp_rx_off(dsp); break; case DTMF_TONE_STOP: /* turn off DTMF */ if (dsp_debug & DEBUG_DSP_CORE) @@ -657,11 +658,10 @@ get_features(struct mISDNchannel *ch) static int dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) { - struct dsp *dsp = container_of(ch, struct dsp, ch); + struct dsp *dsp = container_of(ch, struct dsp, ch); struct mISDNhead *hh; int ret = 0; - u8 *digits; - int cont; + u8 *digits = NULL; u_long flags; hh = mISDN_HEAD_P(skb); @@ -716,40 +716,43 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) /* change volume if requested */ if (dsp->rx_volume) dsp_change_volume(skb, dsp->rx_volume); - /* check if dtmf soft decoding is turned on */ if (dsp->dtmf.software) { digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); + } + /* we need to process receive data if software */ + if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { + /* process data from card at cmx */ + dsp_cmx_receive(dsp, skb); + } + + spin_unlock_irqrestore(&dsp_lock, flags); + + /* send dtmf result, if any */ + if (digits) { while (*digits) { + int k; struct sk_buff *nskb; if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s: digit" "(%c) to layer %s\n", __func__, *digits, dsp->name); - cont = DTMF_TONE_VAL | *digits; + k = *digits | DTMF_TONE_VAL; nskb = _alloc_mISDN_skb(PH_CONTROL_IND, - MISDN_ID_ANY, sizeof(int), &cont, - GFP_ATOMIC); + MISDN_ID_ANY, sizeof(int), &k, + GFP_ATOMIC); if (nskb) { if (dsp->up) { if (dsp->up->send( dsp->up, nskb)) - dev_kfree_skb(nskb); + dev_kfree_skb(nskb); } else dev_kfree_skb(nskb); } digits++; } } - /* we need to process receive data if software */ - if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { - /* process data from card at cmx */ - dsp_cmx_receive(dsp, skb); - } - - spin_unlock_irqrestore(&dsp_lock, flags); - if (dsp->rx_disabled) { /* if receive is not allowed */ break; @@ -789,7 +792,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) if (dsp->up) { if (dsp->up->send( dsp->up, nskb)) - dev_kfree_skb(nskb); + dev_kfree_skb(nskb); } else dev_kfree_skb(nskb); } -- cgit v0.10.2 From bc138ec4ac58bb83e2d9d5c12328d5452294c1f0 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:49 +0000 Subject: mISDN: Hardware acceleration is now possible in conjunction with audio recording Audio recording requires software audio processing. Both hardware and software processing is simultaniously possible now. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 41c6cfd..564ea3e 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -151,6 +151,15 @@ struct dsp_tone { struct timer_list tl; }; +/*************** + * echo stuff * + ***************/ + +struct dsp_echo { + int software; /* echo is generated by software */ + int hardware; /* echo is generated by hardware */ +}; + /***************** * general stuff * *****************/ @@ -161,7 +170,7 @@ struct dsp { struct mISDNchannel *up; unsigned char name[64]; int b_active; - int echo; /* echo is enabled */ + struct dsp_echo echo; int rx_disabled; /* what the user wants */ int rx_is_off; /* what the card is */ int tx_mix; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index ac84146..d19b4f6 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -163,8 +163,9 @@ dsp_cmx_debug(struct dsp *dsp) printk(KERN_DEBUG "-----Current DSP\n"); list_for_each_entry(odsp, &dsp_ilist, list) { - printk(KERN_DEBUG "* %s echo=%d txmix=%d", - odsp->name, odsp->echo, odsp->tx_mix); + printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d", + odsp->name, odsp->echo.hardware, odsp->echo.software, + odsp->tx_mix); if (odsp->conf) printk(" (Conf %d)", odsp->conf->id); if (dsp == odsp) @@ -177,10 +178,12 @@ dsp_cmx_debug(struct dsp *dsp) list_for_each_entry(member, &conf->mlist, list) { printk(KERN_DEBUG " - member = %s (slot_tx %d, bank_tx %d, " - "slot_rx %d, bank_rx %d hfc_conf %d)%s\n", + "slot_rx %d, bank_rx %d hfc_conf %d " + "tx_data %d rx_is_off %d)%s\n", member->dsp->name, member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx, member->dsp->hfc_conf, + member->dsp->tx_data, member->dsp->rx_is_off, (member->dsp == dsp) ? " *this*" : ""); } } @@ -385,7 +388,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) int freeunits[8]; u_char freeslots[256]; int same_hfc = -1, same_pcm = -1, current_conf = -1, - all_conf = 1; + all_conf = 1, tx_data = 0; /* dsp gets updated (no conf) */ if (!conf) { @@ -409,7 +412,7 @@ one_member: /* process hw echo */ if (dsp->features.pcm_banks < 1) return; - if (!dsp->echo) { + if (!dsp->echo.software && !dsp->echo.hardware) { /* NO ECHO: remove PCM slot if assigned */ if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { if (dsp_debug & DEBUG_DSP_CMX) @@ -427,10 +430,15 @@ one_member: } return; } + /* echo is enabled, find out if we use soft or hardware */ + dsp->echo.software = dsp->tx_data; + dsp->echo.hardware = 0; /* ECHO: already echo */ if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && - dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) + dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) { + dsp->echo.hardware = 1; return; + } /* ECHO: if slot already assigned */ if (dsp->pcm_slot_tx >= 0) { dsp->pcm_slot_rx = dsp->pcm_slot_tx; @@ -443,6 +451,7 @@ one_member: dsp->pcm_slot_tx); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->echo.hardware = 1; return; } /* ECHO: find slot */ @@ -472,6 +481,7 @@ one_member: "%s no slot available for echo\n", __func__); /* no more slots available */ + dsp->echo.software = 1; return; } /* assign free slot */ @@ -485,6 +495,7 @@ one_member: __func__, dsp->name, dsp->pcm_slot_tx); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->echo.hardware = 1; return; } @@ -554,7 +565,7 @@ conf_software: return; } /* check if member has echo turned on */ - if (member->dsp->echo) { + if (member->dsp->echo.hardware || member->dsp->echo.software) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s dsp %s cannot form a conf, because " @@ -592,10 +603,9 @@ conf_software: if (member->dsp->tx_data) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_data is turned on\n", + "%s dsp %s tx_data is turned on\n", __func__, member->dsp->name); - goto conf_software; + tx_data = 1; } /* check if pipeline exists */ if (member->dsp->pipeline.inuse) { @@ -794,7 +804,7 @@ conf_software: nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); conf->hardware = 1; - conf->software = 0; + conf->software = tx_data; return; /* if members have one bank (or on the same chip) */ } else { @@ -904,7 +914,7 @@ conf_software: nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); conf->hardware = 1; - conf->software = 0; + conf->software = tx_data; return; } } @@ -1295,17 +1305,25 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) int r, rr, t, tt, o_r, o_rr; int preload = 0; struct mISDNhead *hh, *thh; + int tx_data_only = 0; /* don't process if: */ if (!dsp->b_active) { /* if not active */ dsp->last_tx = 0; return; } - if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ + if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */ + dsp->echo.hardware) && /* OR hardware echo */ dsp->tx_R == dsp->tx_W && /* AND no tx-data */ !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ - dsp->last_tx = 0; - return; + if (!dsp->tx_data) { /* no tx_data for user space required */ + dsp->last_tx = 0; + return; + } + if (dsp->conf && dsp->conf->software && dsp->conf->hardware) + tx_data_only = 1; + if (dsp->conf->software && dsp->echo.hardware) + tx_data_only = 1; } #ifdef CMX_DEBUG @@ -1388,7 +1406,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) /* PROCESS DATA (one member / no conf) */ if (!conf || members <= 1) { /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* -> send tx-data if available or use 0-volume */ while (r != rr && t != tt) { *d++ = p[t]; /* write tx_buff */ @@ -1438,7 +1456,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) o_r = (o_rr - rr + r) & CMX_BUFF_MASK; /* start rx-pointer at current read position*/ /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* * -> copy other member's rx-data, * if tx-data is available, mix @@ -1486,7 +1504,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) #endif /* PROCESS DATA (three or more members) */ /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* * -> substract rx-data from conf-data, * if tx-data is available, mix @@ -1550,27 +1568,40 @@ send_packet: * becuase we want what we send, not what we filtered */ if (dsp->tx_data) { - /* PREPARE RESULT */ - txskb = mI_alloc_skb(len, GFP_ATOMIC); - if (!txskb) { - printk(KERN_ERR - "FATAL ERROR in mISDN_dsp.o: " - "cannot alloc %d bytes\n", len); + if (tx_data_only) { + hh->prim = DL_DATA_REQ; + hh->id = 0; + /* queue and trigger */ + skb_queue_tail(&dsp->sendq, nskb); + schedule_work(&dsp->workq); + /* exit because only tx_data is used */ + return; } else { - thh = mISDN_HEAD_P(txskb); - thh->prim = DL_DATA_REQ; - thh->id = 0; - memcpy(skb_put(txskb, len), nskb->data+preload, len); - /* queue (trigger later) */ - skb_queue_tail(&dsp->sendq, txskb); + txskb = mI_alloc_skb(len, GFP_ATOMIC); + if (!txskb) { + printk(KERN_ERR + "FATAL ERROR in mISDN_dsp.o: " + "cannot alloc %d bytes\n", len); + } else { + thh = mISDN_HEAD_P(txskb); + thh->prim = DL_DATA_REQ; + thh->id = 0; + memcpy(skb_put(txskb, len), nskb->data+preload, + len); + /* queue (trigger later) */ + skb_queue_tail(&dsp->sendq, txskb); + } } } + + /* send data only to card, if we don't just calculated tx_data */ /* adjust volume */ if (dsp->tx_volume) dsp_change_volume(nskb, dsp->tx_volume); /* pipeline */ if (dsp->pipeline.inuse) - dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); + dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, + nskb->len); /* crypt */ if (dsp->bf_enable) dsp_bf_encrypt(dsp, nskb->data, nskb->len); @@ -1891,10 +1922,8 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) /* no conf */ if (!dsp->conf) { - /* in case of hardware (echo) */ - if (dsp->pcm_slot_tx >= 0) - return; - if (dsp->echo) { + /* in case of software echo */ + if (dsp->echo.software) { nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { hh = mISDN_HEAD_P(nskb); @@ -1910,7 +1939,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) if (dsp->conf->hardware) return; list_for_each_entry(member, &dsp->conf->mlist, list) { - if (dsp->echo || member->dsp != dsp) { + if (dsp->echo.software || member->dsp != dsp) { nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { hh = mISDN_HEAD_P(nskb); diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 6b49398..a0e0af8 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -203,13 +203,13 @@ dsp_rx_off_member(struct dsp *dsp) else if (dsp->dtmf.software) rx_off = 0; /* echo in software */ - else if (dsp->echo && dsp->pcm_slot_tx < 0) + else if (dsp->echo.software) rx_off = 0; /* bridge in software */ - else if (dsp->conf) { - if (dsp->conf->software) - rx_off = 0; - } + else if (dsp->conf && dsp->conf->software) + rx_off = 0; + /* data is not required by user space and not required + * for echo dtmf detection, soft-echo, soft-bridging */ if (rx_off == dsp->rx_is_off) return; @@ -415,7 +415,7 @@ tone_off: dsp_rx_off(dsp); break; case DSP_ECHO_ON: /* enable echo */ - dsp->echo = 1; /* soft echo */ + dsp->echo.software = 1; /* soft echo */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); dsp_cmx_hardware(dsp->conf, dsp); @@ -424,7 +424,8 @@ tone_off: dsp_cmx_debug(dsp); break; case DSP_ECHO_OFF: /* disable echo */ - dsp->echo = 0; + dsp->echo.software = 0; + dsp->echo.hardware = 0; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); dsp_cmx_hardware(dsp->conf, dsp); @@ -722,7 +723,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); } /* we need to process receive data if software */ - if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { + if (dsp->conf && dsp->conf->software) { /* process data from card at cmx */ dsp_cmx_receive(dsp, skb); } -- cgit v0.10.2 From 5b277b8605f4c8fbd13302df33ab4570f844c1ff Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 25 May 2009 00:50:02 -0700 Subject: mISDN: Fix TEI and SAPI handling Added SAPI value to use SAPIs different than 0. Now fixed TEIs work in NT mode. This allows PTP endpoint to be connected to PTMP ports together with other PTMP endpoints. New enhanced version, thanks to Sam Ravnborg for the hints. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index d6e2863..2d2f581 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -2068,7 +2068,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) } struct layer2 * -create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) +create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei, + int sapi) { struct layer2 *l2; struct channel_req rq; @@ -2089,7 +2090,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_LAPD, &l2->flag); test_and_set_bit(FLG_LAPD_NET, &l2->flag); test_and_set_bit(FLG_MOD128, &l2->flag); - l2->sapi = 0; + l2->sapi = sapi; l2->maxlen = MAX_DFRAME_LEN; if (test_bit(OPTION_L2_PMX, &options)) l2->window = 7; @@ -2099,7 +2100,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_PTP, &l2->flag); if (test_bit(OPTION_L2_FIXEDTEI, &options)) test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = (u_int)arg; + l2->tei = tei; l2->T200 = 1000; l2->N200 = 3; l2->T203 = 10000; @@ -2114,7 +2115,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_LAPD, &l2->flag); test_and_set_bit(FLG_MOD128, &l2->flag); test_and_set_bit(FLG_ORIG, &l2->flag); - l2->sapi = 0; + l2->sapi = sapi; l2->maxlen = MAX_DFRAME_LEN; if (test_bit(OPTION_L2_PMX, &options)) l2->window = 7; @@ -2124,7 +2125,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_PTP, &l2->flag); if (test_bit(OPTION_L2_FIXEDTEI, &options)) test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = (u_int)arg; + l2->tei = tei; l2->T200 = 1000; l2->N200 = 3; l2->T203 = 10000; @@ -2180,7 +2181,7 @@ x75create(struct channel_req *crq) if (crq->protocol != ISDN_P_B_X75SLP) return -EPROTONOSUPPORT; - l2 = create_l2(crq->ch, crq->protocol, 0, 0); + l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0); if (!l2) return -ENOMEM; crq->ch = &l2->ch; diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h index 6293f80..9547fb3 100644 --- a/drivers/isdn/mISDN/layer2.h +++ b/drivers/isdn/mISDN/layer2.h @@ -90,7 +90,7 @@ enum { #define L2_STATE_COUNT (ST_L2_8+1) extern struct layer2 *create_l2(struct mISDNchannel *, u_int, - u_long, u_long); + u_long, int, int); extern int tei_l2(struct layer2 *, u_int, u_long arg); diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index c75af76..55a7c3d 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -426,7 +426,7 @@ done: } static void -put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) +put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei) { struct sk_buff *skb; u_char bp[8]; @@ -440,9 +440,8 @@ put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) bp[4] = ri >> 8; bp[5] = ri & 0xff; bp[6] = m_id; - bp[7] = (tei << 1) | 1; - skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), - 8, bp, GFP_ATOMIC); + bp[7] = ((tei << 1) & 0xff) | 1; + skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC); if (!skb) { printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); return; @@ -777,7 +776,7 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) } static struct layer2 * -create_new_tei(struct manager *mgr, int tei) +create_new_tei(struct manager *mgr, int tei, int sapi) { u_long opt = 0; u_long flags; @@ -786,12 +785,12 @@ create_new_tei(struct manager *mgr, int tei) if (!mgr->up) return NULL; - if (tei < 64) + if ((tei >= 0) && (tei < 64)) test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) test_and_set_bit(OPTION_L2_PMX, &opt); - l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); + l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); if (!l2) { printk(KERN_WARNING "%s:no memory for layer2\n", __func__); return NULL; @@ -839,12 +838,17 @@ new_tei_req(struct manager *mgr, u_char *dp) ri += dp[1]; if (!mgr->up) goto denied; - tei = get_free_tei(mgr); + if (!(dp[3] & 1)) /* Extension bit != 1 */ + goto denied; + if (dp[3] != 0xff) + tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */ + else + tei = get_free_tei(mgr); if (tei < 0) { printk(KERN_WARNING "%s:No free tei\n", __func__); goto denied; } - l2 = create_new_tei(mgr, tei); + l2 = create_new_tei(mgr, tei, CTRL_SAPI); if (!l2) goto denied; else @@ -976,8 +980,6 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) __func__, dev_name(&mgr->ch.st->dev->dev), crq->protocol, crq->adr.dev, crq->adr.channel, crq->adr.sapi, crq->adr.tei); - if (crq->adr.sapi != 0) /* not supported yet */ - return -EINVAL; if (crq->adr.tei > GROUP_TEI) return -EINVAL; if (crq->adr.tei < 64) @@ -1024,8 +1026,8 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) } return 0; } - l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, - (u_long)crq->adr.tei); + l2 = create_l2(crq->ch, crq->protocol, opt, + crq->adr.tei, crq->adr.sapi); if (!l2) return -ENOMEM; l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); @@ -1166,7 +1168,7 @@ static int check_data(struct manager *mgr, struct sk_buff *skb) { struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret, tei; + int ret, tei, sapi; struct layer2 *l2; if (*debug & DEBUG_L2_CTRL) @@ -1178,18 +1180,18 @@ check_data(struct manager *mgr, struct sk_buff *skb) return -ENOTCONN; if (skb->len != 3) return -ENOTCONN; - if (skb->data[0] != 0) - /* only SAPI 0 command */ - return -ENOTCONN; + if (skb->data[0] & 3) /* EA0 and CR must be 0 */ + return -EINVAL; + sapi = skb->data[0] >> 2; if (!(skb->data[1] & 1)) /* invalid EA1 */ return -EINVAL; - tei = skb->data[1] >> 0; + tei = skb->data[1] >> 1; if (tei > 63) /* not a fixed tei */ return -ENOTCONN; if ((skb->data[2] & ~0x10) != SABME) return -ENOTCONN; /* We got a SABME for a fixed TEI */ - l2 = create_new_tei(mgr, tei); + l2 = create_new_tei(mgr, tei, sapi); if (!l2) return -ENOMEM; ret = l2->ch.send(&l2->ch, skb); -- cgit v0.10.2 From 3dc403939c73ac372f2c95b5099dfdf396fe4ecc Mon Sep 17 00:00:00 2001 From: Frank Seidel Date: Fri, 22 May 2009 11:04:51 +0000 Subject: mISDN: Add allocation of recvbuf[1500] at run time to reduce stack size Before: 1656 bytes on i386, now 164. Modified by Andreas Eversberg Signed-off-by: Frank Seidel Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index abe5749..ea3c3aa 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -663,18 +663,28 @@ l1oip_socket_thread(void *data) struct iovec iov; mm_segment_t oldfs; struct sockaddr_in sin_rx; - unsigned char recvbuf[1500]; + unsigned char *recvbuf; + size_t recvbuf_size = 1500; int recvlen; struct socket *socket = NULL; DECLARE_COMPLETION(wait); + /* allocate buffer memory */ + recvbuf = kmalloc(recvbuf_size, GFP_KERNEL); + if (!recvbuf) { + printk(KERN_ERR "%s: Failed to alloc recvbuf.\n", __func__); + ret = -ENOMEM; + goto fail; + } + /* make daemon */ allow_signal(SIGTERM); /* create socket */ if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) { printk(KERN_ERR "%s: Failed to create socket.\n", __func__); - return -EIO; + ret = -EIO; + goto fail; } /* set incoming address */ @@ -730,10 +740,10 @@ l1oip_socket_thread(void *data) __func__); while (!signal_pending(current)) { iov.iov_base = recvbuf; - iov.iov_len = sizeof(recvbuf); + iov.iov_len = recvbuf_size; oldfs = get_fs(); set_fs(KERNEL_DS); - recvlen = sock_recvmsg(socket, &msg, sizeof(recvbuf), 0); + recvlen = sock_recvmsg(socket, &msg, recvbuf_size, 0); set_fs(oldfs); if (recvlen > 0) { l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); @@ -760,6 +770,9 @@ l1oip_socket_thread(void *data) __func__); fail: + /* free recvbuf */ + kfree(recvbuf); + /* close socket */ if (socket) sock_release(socket); -- cgit v0.10.2 From d796509a57777bc0f8f336e360695fad665c59f5 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:51 +0000 Subject: mISDN: Add "sapi" information to debug messages Using sapi values other than 0 work now. The "OpenBSC" project does not require special kernel patch anymore. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 2d2f581..9c2589e 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -99,7 +99,7 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...) if (!(*debug & DEBUG_L2_FSM)) return; va_start(va, fmt); - printk(KERN_DEBUG "l2 (tei %d): ", l2->tei); + printk(KERN_DEBUG "l2 (sapi %d tei %d): ", l2->sapi, l2->tei); vprintk(fmt, va); printk("\n"); va_end(va); @@ -1859,20 +1859,18 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) psapi >>= 2; ptei >>= 1; if (psapi != l2->sapi) { - /* not our bussiness - * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", - * __func__, - * psapi, l2->sapi); - */ + /* not our bussiness */ + if (*debug & DEBUG_L2) + printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n", + __func__, psapi, l2->sapi); dev_kfree_skb(skb); return 0; } if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { - /* not our bussiness - * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", - * __func__, - * ptei, l2->tei, psapi); - */ + /* not our bussiness */ + if (*debug & DEBUG_L2) + printk(KERN_DEBUG "%s: tei %d/%d mismatch\n", + __func__, ptei, l2->tei); dev_kfree_skb(skb); return 0; } @@ -1927,8 +1925,8 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) int ret = -EINVAL; if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n", - __func__, hh->prim, hh->id, l2->tei); + printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n", + __func__, hh->prim, hh->id, l2->sapi, l2->tei); switch (hh->prim) { case PH_DATA_IND: ret = ph_data_indication(l2, hh, skb); diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 55a7c3d..778b660 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -227,7 +227,7 @@ tei_debug(struct FsmInst *fi, char *fmt, ...) if (!(*debug & DEBUG_L2_TEIFSM)) return; va_start(va, fmt); - printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); + printk(KERN_DEBUG "sapi(%d) tei(%d): ", tm->l2->sapi, tm->l2->tei); vprintk(fmt, va); printk("\n"); va_end(va); @@ -1191,9 +1191,16 @@ check_data(struct manager *mgr, struct sk_buff *skb) if ((skb->data[2] & ~0x10) != SABME) return -ENOTCONN; /* We got a SABME for a fixed TEI */ + if (*debug & DEBUG_L2_CTRL) + printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n", + __func__, sapi, tei); l2 = create_new_tei(mgr, tei, sapi); - if (!l2) + if (!l2) { + if (*debug & DEBUG_L2_CTRL) + printk(KERN_DEBUG "%s: failed to create new tei\n", + __func__); return -ENOMEM; + } ret = l2->ch.send(&l2->ch, skb); return ret; } -- cgit v0.10.2 From 5df3b8bcc7826b85a2d233dd20da3ed247e1dc1d Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 22 May 2009 11:04:52 +0000 Subject: mISDN: Fix skb leak in error cases If the channel receive function returns an error the skb must be freed. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 530f68977..2a2c30a 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -209,7 +209,7 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; - goto drop; + goto done; } memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); @@ -230,19 +230,21 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, __func__, mISDN_HEAD_ID(skb)); err = -ENODEV; - if (!_pms(sk)->ch.peer || - (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb))) - goto drop; - - err = len; + if (!_pms(sk)->ch.peer) + goto done; + err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb); + if (err) + goto done; + else { + skb = NULL; + err = len; + } done: + if (skb) + kfree_skb(skb); release_sock(sk); return err; - -drop: - kfree_skb(skb); - goto done; } static int -- cgit v0.10.2 From db9bb63a1b5b65df41d112a8c21adbbfc6a4ac08 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 22 May 2009 11:04:53 +0000 Subject: mISDN: Add XHFC support for embedded Speech-Design board to hfcmulti New version without emulating arch specific stuff for the other architectures, the special IO and init functions for the 8xx microcontroller are in a separate include file. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index fd112ae..3024566 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -13,7 +13,7 @@ config MISDN_HFCPCI config MISDN_HFCMULTI tristate "Support for HFC multiport cards (HFC-4S/8S/E1)" - depends on PCI + depends on PCI || 8xx depends on MISDN help Enable support for cards with Cologne Chip AG's HFC multiport @@ -23,6 +23,15 @@ config MISDN_HFCMULTI * HFC-8S (8 S/T interfaces on one chip) * HFC-E1 (E1 interface for 2Mbit ISDN) +config MISDN_HFCMULTI_8xx + boolean "Support for XHFC embedded board in HFC multiport driver" + depends on MISDN + depends on MISDN_HFCMULTI + depends on 8xx + default 8xx + help + Enable support for the XHFC embedded solution from Speech Design. + config MISDN_HFCUSB tristate "Support for HFC-S USB based TAs" depends on USB diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index c4878cc..0c77386 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -17,6 +17,16 @@ #define PCI_ENA_REGIO 0x01 #define PCI_ENA_MEMIO 0x02 +#define XHFC_IRQ 4 /* SIU_IRQ2 */ +#define XHFC_MEMBASE 0xFE000000 +#define XHFC_MEMSIZE 0x00001000 +#define XHFC_OFFSET 0x00001000 +#define PA_XHFC_A0 0x0020 /* PA10 */ +#define PB_XHFC_IRQ1 0x00000100 /* PB23 */ +#define PB_XHFC_IRQ2 0x00000200 /* PB22 */ +#define PB_XHFC_IRQ3 0x00000400 /* PB21 */ +#define PB_XHFC_IRQ4 0x00000800 /* PB20 */ + /* * NOTE: some registers are assigned multiple times due to different modes * also registers are assigned differen for HFC-4s/8s and HFC-E1 @@ -81,6 +91,11 @@ struct hfcm_hw { #define HFC_CFG_CRC4 10 /* disable CRC-4 Multiframe mode, */ /* use double frame instead. */ +#define HFC_TYPE_E1 1 /* controller is HFC-E1 */ +#define HFC_TYPE_4S 4 /* controller is HFC-4S */ +#define HFC_TYPE_8S 8 /* controller is HFC-8S */ +#define HFC_TYPE_XHFC 5 /* controller is XHFC */ + #define HFC_CHIP_EXRAM_128 0 /* external ram 128k */ #define HFC_CHIP_EXRAM_512 1 /* external ram 256k */ #define HFC_CHIP_REVISION0 2 /* old fifo handling */ @@ -88,19 +103,22 @@ struct hfcm_hw { #define HFC_CHIP_PCM_MASTER 4 /* PCM is master */ #define HFC_CHIP_RX_SYNC 5 /* disable pll sync for pcm */ #define HFC_CHIP_DTMF 6 /* DTMF decoding is enabled */ -#define HFC_CHIP_ULAW 7 /* ULAW mode */ -#define HFC_CHIP_CLOCK2 8 /* double clock mode */ -#define HFC_CHIP_E1CLOCK_GET 9 /* always get clock from E1 interface */ -#define HFC_CHIP_E1CLOCK_PUT 10 /* always put clock from E1 interface */ -#define HFC_CHIP_WATCHDOG 11 /* whether we should send signals */ +#define HFC_CHIP_CONF 7 /* conference handling is enabled */ +#define HFC_CHIP_ULAW 8 /* ULAW mode */ +#define HFC_CHIP_CLOCK2 9 /* double clock mode */ +#define HFC_CHIP_E1CLOCK_GET 10 /* always get clock from E1 interface */ +#define HFC_CHIP_E1CLOCK_PUT 11 /* always put clock from E1 interface */ +#define HFC_CHIP_WATCHDOG 12 /* whether we should send signals */ /* to the watchdog */ -#define HFC_CHIP_B410P 12 /* whether we have a b410p with echocan in */ +#define HFC_CHIP_B410P 13 /* whether we have a b410p with echocan in */ /* hw */ -#define HFC_CHIP_PLXSD 13 /* whether we have a Speech-Design PLX */ +#define HFC_CHIP_PLXSD 14 /* whether we have a Speech-Design PLX */ +#define HFC_CHIP_EMBSD 15 /* whether we have a SD Embedded board */ #define HFC_IO_MODE_PCIMEM 0x00 /* normal memory mapped IO */ #define HFC_IO_MODE_REGIO 0x01 /* PCI io access */ #define HFC_IO_MODE_PLXSD 0x02 /* access HFC via PLX9030 */ +#define HFC_IO_MODE_EMBSD 0x03 /* direct access */ /* table entry in the PCI devices list */ struct hm_map { @@ -113,6 +131,7 @@ struct hm_map { int opticalsupport; int dip_type; int io_mode; + int irq; }; struct hfc_multi { @@ -120,7 +139,7 @@ struct hfc_multi { struct hm_map *mtyp; int id; int pcm; /* id of pcm bus */ - int type; + int ctype; /* controller type */ int ports; u_int irq; /* irq used by card */ @@ -160,10 +179,16 @@ struct hfc_multi { int len); void (*write_fifo)(struct hfc_multi *hc, u_char *data, int len); - u_long pci_origmembase, plx_origmembase, dsp_origmembase; + u_long pci_origmembase, plx_origmembase; void __iomem *pci_membase; /* PCI memory */ void __iomem *plx_membase; /* PLX memory */ - u_char *dsp_membase; /* DSP on PLX */ + u_long xhfc_origmembase; + u_char *xhfc_membase; + u_long *xhfc_memaddr, *xhfc_memdata; +#ifdef CONFIG_MISDN_HFCMULTI_8xx + struct immap *immap; +#endif + u_long pb_irqmsk; /* Portbit mask to check the IRQ line */ u_long pci_iobase; /* PCI IO */ struct hfcm_hw hw; /* remember data of write-only-registers */ diff --git a/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h new file mode 100644 index 0000000..45ddced --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h @@ -0,0 +1,167 @@ +/* + * For License see notice in hfc_multi.c + * + * special IO and init functions for the embedded XHFC board + * from Speech Design + * + */ + +#include + +/* Change this to the value used by your board */ +#ifndef IMAP_ADDR +#define IMAP_ADDR 0xFFF00000 +#endif + +static void +#ifdef HFC_REGISTER_DEBUG +HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val, + const char *function, int line) +#else +HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(reg, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + writeb(val, hc->xhfc_memdata); +} +static u_char +#ifdef HFC_REGISTER_DEBUG +HFC_inb_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line) +#else +HFC_inb_embsd(struct hfc_multi *hc, u_char reg) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(reg, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + return readb(hc->xhfc_memdata); +} +static u_short +#ifdef HFC_REGISTER_DEBUG +HFC_inw_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line) +#else +HFC_inw_embsd(struct hfc_multi *hc, u_char reg) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(reg, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + return readb(hc->xhfc_memdata); +} +static void +#ifdef HFC_REGISTER_DEBUG +HFC_wait_embsd(struct hfc_multi *hc, const char *function, int line) +#else +HFC_wait_embsd(struct hfc_multi *hc) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(R_STATUS, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + while (readb(hc->xhfc_memdata) & V_BUSY) + cpu_relax(); +} + +/* write fifo data (EMBSD) */ +void +write_fifo_embsd(struct hfc_multi *hc, u_char *data, int len) +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + *hc->xhfc_memaddr = A_FIFO_DATA0; + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + while (len) { + *hc->xhfc_memdata = *data; + data++; + len--; + } +} + +/* read fifo data (EMBSD) */ +void +read_fifo_embsd(struct hfc_multi *hc, u_char *data, int len) +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + *hc->xhfc_memaddr = A_FIFO_DATA0; + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + while (len) { + *data = (u_char)(*hc->xhfc_memdata); + data++; + len--; + } +} + +static int +setup_embedded(struct hfc_multi *hc, struct hm_map *m) +{ + printk(KERN_INFO + "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", + m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); + + hc->pci_dev = NULL; + if (m->clock2) + test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); + + hc->leds = m->leds; + hc->ledstate = 0xAFFEAFFE; + hc->opticalsupport = m->opticalsupport; + + hc->pci_iobase = 0; + hc->pci_membase = 0; + hc->xhfc_membase = NULL; + hc->xhfc_memaddr = NULL; + hc->xhfc_memdata = NULL; + + /* set memory access methods */ + if (m->io_mode) /* use mode from card config */ + hc->io_mode = m->io_mode; + switch (hc->io_mode) { + case HFC_IO_MODE_EMBSD: + test_and_set_bit(HFC_CHIP_EMBSD, &hc->chip); + hc->slots = 128; /* required */ + /* fall through */ + hc->HFC_outb = HFC_outb_embsd; + hc->HFC_inb = HFC_inb_embsd; + hc->HFC_inw = HFC_inw_embsd; + hc->HFC_wait = HFC_wait_embsd; + hc->read_fifo = read_fifo_embsd; + hc->write_fifo = write_fifo_embsd; + hc->xhfc_origmembase = XHFC_MEMBASE + XHFC_OFFSET * hc->id; + hc->xhfc_membase = (u_char *)ioremap(hc->xhfc_origmembase, + XHFC_MEMSIZE); + if (!hc->xhfc_membase) { + printk(KERN_WARNING + "HFC-multi: failed to remap xhfc address space. " + "(internal error)\n"); + return -EIO; + } + hc->xhfc_memaddr = (u_long *)(hc->xhfc_membase + 4); + hc->xhfc_memdata = (u_long *)(hc->xhfc_membase); + printk(KERN_INFO + "HFC-multi: xhfc_membase:%#lx xhfc_origmembase:%#lx " + "xhfc_memaddr:%#lx xhfc_memdata:%#lx\n", + (u_long)hc->xhfc_membase, hc->xhfc_origmembase, + (u_long)hc->xhfc_memaddr, (u_long)hc->xhfc_memdata); + break; + default: + printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); + return -EIO; + } + + /* Prepare the MPC8XX PortA 10 as output (address/data selector) */ + hc->immap = (struct immap *)(IMAP_ADDR); + hc->immap->im_ioport.iop_papar &= ~(PA_XHFC_A0); + hc->immap->im_ioport.iop_paodr &= ~(PA_XHFC_A0); + hc->immap->im_ioport.iop_padir |= PA_XHFC_A0; + + /* Prepare the MPC8xx PortB __X__ as input (ISDN__X__IRQ) */ + hc->pb_irqmsk = (PB_XHFC_IRQ1 << hc->id); + hc->immap->im_cpm.cp_pbpar &= ~(hc->pb_irqmsk); + hc->immap->im_cpm.cp_pbodr &= ~(hc->pb_irqmsk); + hc->immap->im_cpm.cp_pbdir &= ~(hc->pb_irqmsk); + + /* At this point the needed config is done */ + /* fifos are still not enabled */ + return 0; +} diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index bc0d3ef..5be4edf 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -139,6 +139,10 @@ * Selects interface with clock source for mISDN and applications. * Set to card number starting with 1. Set to -1 to disable. * By default, the first card is used as clock source. + * + * hwid: + * NOTE: only one hwid value must be given once + * Enable special embedded devices with XHFC controllers. */ /* @@ -206,6 +210,11 @@ static int clock; static uint timer; static uint clockdelay_te = CLKDEL_TE; static uint clockdelay_nt = CLKDEL_NT; +#define HWID_NONE 0 +#define HWID_MINIP4 1 +#define HWID_MINIP8 2 +#define HWID_MINIP16 3 +static uint hwid = HWID_NONE; static int HFC_cnt, Port_cnt, PCM_cnt = 99; @@ -223,6 +232,7 @@ module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); +module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ #ifdef HFC_REGISTER_DEBUG #define HFC_outb(hc, reg, val) \ @@ -252,6 +262,10 @@ module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); #define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc)) #endif +#ifdef CONFIG_MISDN_HFCMULTI_8xx +#include "hfc_multi_8xx.h" +#endif + /* HFC_IO_MODE_PCIMEM */ static void #ifdef HFC_REGISTER_DEBUG @@ -928,7 +942,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) writel(pv, plx_acc_32); if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { pcmmaster = hc; - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_PLXSD) printk(KERN_DEBUG "Schedule SYNC_I\n"); @@ -949,7 +963,8 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) pv |= PLX_SYNC_O_EN; writel(pv, plx_acc_32); /* switch to jatt PLL, if not disabled by RX_SYNC */ - if (hc->type == 1 && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { + if (hc->ctype == HFC_TYPE_E1 + && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { if (debug & DEBUG_HFCMULTI_PLXSD) printk(KERN_DEBUG "Schedule jatt PLL\n"); hc->e1_resync |= 2; /* switch to jatt */ @@ -961,7 +976,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) printk(KERN_DEBUG "id=%d (0x%p) = PCM master syncronized " "with QUARTZ\n", hc->id, hc); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { /* Use the crystal clock for the PCM master card */ if (debug & DEBUG_HFCMULTI_PLXSD) @@ -972,7 +987,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) if (debug & DEBUG_HFCMULTI_PLXSD) printk(KERN_DEBUG "QUARTZ is automatically " - "enabled by HFC-%dS\n", hc->type); + "enabled by HFC-%dS\n", hc->ctype); } plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); @@ -1060,13 +1075,16 @@ release_io_hfcmulti(struct hfc_multi *hc) /* disable memory mapped ports / io ports */ test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ - pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); + if (hc->pci_dev) + pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); if (hc->pci_membase) iounmap(hc->pci_membase); if (hc->plx_membase) iounmap(hc->plx_membase); if (hc->pci_iobase) release_region(hc->pci_iobase, 8); + if (hc->xhfc_membase) + iounmap((void *)hc->xhfc_membase); if (hc->pci_dev) { pci_disable_device(hc->pci_dev); @@ -1100,8 +1118,9 @@ init_chip(struct hfc_multi *hc) /* revision check */ if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __func__); - val = HFC_inb(hc, R_CHIP_ID)>>4; - if (val != 0x8 && val != 0xc && val != 0xe) { + val = HFC_inb(hc, R_CHIP_ID); + if ((val>>4) != 0x8 && (val>>4) != 0xc && (val>>4) != 0xe + && (val>>1) != 0x31) { printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); err = -EIO; goto out; @@ -1109,8 +1128,9 @@ init_chip(struct hfc_multi *hc) rev = HFC_inb(hc, R_CHIP_RV); printk(KERN_INFO "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", - val, rev, (rev == 0) ? " (old FIFO handling)" : ""); - if (rev == 0) { + val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ? + " (old FIFO handling)" : ""); + if (hc->ctype != HFC_TYPE_XHFC && rev == 0) { test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); printk(KERN_WARNING "HFC_multi: NOTE: Your chip is revision 0, " @@ -1152,6 +1172,12 @@ init_chip(struct hfc_multi *hc) hc->Zlen = 8000; hc->DTMFbase = 0x2000; } + if (hc->ctype == HFC_TYPE_XHFC) { + hc->Flen = 0x8; + hc->Zmin = 0x0; + hc->Zlen = 64; + hc->DTMFbase = 0x0; + } hc->max_trans = poll << 1; if (hc->max_trans > hc->Zlen) hc->max_trans = hc->Zlen; @@ -1211,6 +1237,9 @@ init_chip(struct hfc_multi *hc) hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ } + if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) + hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ + /* we only want the real Z2 read-pointer for revision > 0 */ if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) hc->hw.r_ram_sz |= V_FZ_MD; @@ -1234,15 +1263,24 @@ init_chip(struct hfc_multi *hc) /* soft reset */ HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); - HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, 0x0C /* R_FIFO_THRES */, + 0x11 /* 16 Bytes TX/RX */); + else + HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); HFC_outb(hc, R_FIFO_MD, 0); - hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | V_RLD_EPR; + if (hc->ctype == HFC_TYPE_XHFC) + hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES; + else + hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES + | V_RLD_EPR; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); udelay(100); hc->hw.r_cirm = 0; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); udelay(100); - HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); /* Speech Design PLX bridge pcm and sync mode */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { @@ -1278,13 +1316,16 @@ init_chip(struct hfc_multi *hc) HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ + else if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) + HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */ else HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); for (i = 0; i < 256; i++) { HFC_outb_nodebug(hc, R_SLOT, i); HFC_outb_nodebug(hc, A_SL_CFG, 0); - HFC_outb_nodebug(hc, A_CONF, 0); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb_nodebug(hc, A_CONF, 0); hc->slot_owner[i] = -1; } @@ -1296,6 +1337,9 @@ init_chip(struct hfc_multi *hc) HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); } + if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) + HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */); + /* B410P GPIO */ if (test_bit(HFC_CHIP_B410P, &hc->chip)) { printk(KERN_NOTICE "Setting GPIOs\n"); @@ -1424,7 +1468,7 @@ controller_fail: hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; /* set E1 state machine IRQ */ - if (hc->type == 1) + if (hc->ctype == HFC_TYPE_E1) hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; /* set DTMF detection */ @@ -1444,7 +1488,8 @@ controller_fail: r_conf_en = V_CONF_EN | V_ULAW; else r_conf_en = V_CONF_EN; - HFC_outb(hc, R_CONF_EN, r_conf_en); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, R_CONF_EN, r_conf_en); /* setting leds */ switch (hc->leds) { @@ -1468,16 +1513,23 @@ controller_fail: break; } + if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) { + hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */ + HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); + } + /* set master clock */ if (hc->masterclk >= 0) { if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: setting ST master clock " "to port %d (0..%d)\n", __func__, hc->masterclk, hc->ports-1); - hc->hw.r_st_sync = hc->masterclk | V_AUTO_SYNC; + hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC); HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); } + + /* setting misc irq */ HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); if (debug & DEBUG_HFCMULTI_INIT) @@ -1929,7 +1981,7 @@ next_frame: Fspace = 1; } /* one frame only for ST D-channels, to allow resending */ - if (hc->type != 1 && dch) { + if (hc->ctype != HFC_TYPE_E1 && dch) { if (f1 != f2) Fspace = 0; } @@ -1971,12 +2023,22 @@ next_frame: "slot_tx %d\n", __func__, ch, slot_tx); /* connect slot */ - HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | - V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0xc0 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); HFC_wait_nodebug(hc); - HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | - V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0xc0 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1); HFC_wait_nodebug(hc); } @@ -2004,10 +2066,22 @@ next_frame: "FIFO data: channel %d slot_tx %d\n", __func__, ch, slot_tx); /* disconnect slot */ - HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0x80 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); HFC_wait_nodebug(hc); - HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0x80 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1); HFC_wait_nodebug(hc); } @@ -2327,7 +2401,7 @@ handle_timer_irq(struct hfc_multi *hc) spin_unlock_irqrestore(&HFClock, flags); } - if (hc->type != 1 || hc->e1_state == 1) + if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) for (ch = 0; ch <= 31; ch++) { if (hc->created[hc->chan[ch].port]) { hfcmulti_tx(hc, ch); @@ -2350,7 +2424,7 @@ handle_timer_irq(struct hfc_multi *hc) } } } - if (hc->type == 1 && hc->created[0]) { + if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { dch = hc->chan[hc->dslot].dch; if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { /* LOS */ @@ -2610,7 +2684,10 @@ hfcmulti_interrupt(int intno, void *dev_id) "card %d, this is no bug.\n", hc->id + 1, irqsem); irqsem = hc->id + 1; #endif - +#ifdef CONFIG_MISDN_HFCMULTI_8xx + if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk) + goto irq_notforus; +#endif if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, flags); plx_acc = hc->plx_membase + PLX_INTCSR; @@ -2650,7 +2727,7 @@ hfcmulti_interrupt(int intno, void *dev_id) } hc->irqcnt++; if (r_irq_statech) { - if (hc->type != 1) + if (hc->ctype != HFC_TYPE_E1) ph_state_irq(hc, r_irq_statech); } if (status & V_EXT_IRQSTA) @@ -2664,7 +2741,7 @@ hfcmulti_interrupt(int intno, void *dev_id) r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ if (r_irq_misc & V_STA_IRQ) { - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { /* state machine */ dch = hc->chan[hc->dslot].dch; e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); @@ -2786,7 +2863,8 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, if (hc->slot_owner[oslot_tx<<1] == ch) { HFC_outb(hc, R_SLOT, oslot_tx << 1); HFC_outb(hc, A_SL_CFG, 0); - HFC_outb(hc, A_CONF, 0); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, A_CONF, 0); hc->slot_owner[oslot_tx<<1] = -1; } else { if (debug & DEBUG_HFCMULTI_MODE) @@ -2839,7 +2917,9 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, flow_tx, routing, conf); HFC_outb(hc, R_SLOT, slot_tx << 1); HFC_outb(hc, A_SL_CFG, (ch<<1) | routing); - HFC_outb(hc, A_CONF, (conf < 0) ? 0 : (conf | V_CONF_SL)); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, A_CONF, + (conf < 0) ? 0 : (conf | V_CONF_SL)); hc->slot_owner[slot_tx << 1] = ch; hc->chan[ch].slot_tx = slot_tx; hc->chan[ch].bank_tx = bank_tx; @@ -2889,7 +2969,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, A_IRQ_MSK, 0); HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); - if (hc->chan[ch].bch && hc->type != 1) { + if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] &= ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); @@ -2965,8 +3045,13 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, /* enable TX fifo */ HFC_outb(hc, R_FIFO, ch << 1); HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | - V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 | + V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); @@ -2976,13 +3061,19 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, /* enable RX fifo */ HFC_outb(hc, R_FIFO, (ch<<1)|1); HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 | + V_HDLC_TRP); + /* Enable FIFO, no interrupt*/ + else + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | + V_HDLC_TRP); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); } - if (hc->type != 1) { + if (hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); @@ -3003,7 +3094,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, /* enable TX fifo */ HFC_outb(hc, R_FIFO, ch<<1); HFC_wait(hc); - if (hc->type == 1 || hc->chan[ch].bch) { + if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) { /* E1 or B-channel */ HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); HFC_outb(hc, A_SUBCH_CFG, 0); @@ -3019,7 +3110,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, R_FIFO, (ch<<1)|1); HFC_wait(hc); HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); - if (hc->type == 1 || hc->chan[ch].bch) + if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ else HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ @@ -3028,7 +3119,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_wait(hc); if (hc->chan[ch].bch) { test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); - if (hc->type != 1) { + if (hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3) == 0) ? V_B1_EN : V_B2_EN; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); @@ -3108,7 +3199,7 @@ hfcm_l1callback(struct dchannel *dch, u_int cmd) case HW_RESET_REQ: /* start activation */ spin_lock_irqsave(&hc->lock, flags); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_RESET_REQ no BRI\n", @@ -3129,7 +3220,7 @@ hfcm_l1callback(struct dchannel *dch, u_int cmd) case HW_DEACT_REQ: /* start deactivation */ spin_lock_irqsave(&hc->lock, flags); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_DEACT_REQ no BRI\n", @@ -3163,7 +3254,7 @@ hfcm_l1callback(struct dchannel *dch, u_int cmd) break; case HW_POWERUP_REQ: spin_lock_irqsave(&hc->lock, flags); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_POWERUP_REQ no BRI\n", @@ -3240,7 +3331,7 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) __func__, hc->chan[dch->slot].port, hc->ports-1); /* start activation */ - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { ph_state_change(dch); if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG @@ -3273,7 +3364,7 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) __func__, hc->chan[dch->slot].port, hc->ports-1); /* start deactivation */ - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: PH_DEACTIVATE no BRI\n", @@ -3493,6 +3584,8 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) features->hfc_id = hc->id; if (test_bit(HFC_CHIP_DTMF, &hc->chip)) features->hfc_dtmf = 1; + if (test_bit(HFC_CHIP_CONF, &hc->chip)) + features->hfc_conf = 1; features->hfc_loops = 0; if (test_bit(HFC_CHIP_B410P, &hc->chip)) { features->hfc_echocanhw = 1; @@ -3630,7 +3723,7 @@ ph_state_change(struct dchannel *dch) hc = dch->hw; ch = dch->slot; - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (dch->dev.D.protocol == ISDN_P_TE_E1) { if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG @@ -3755,7 +3848,7 @@ hfcmulti_initmode(struct dchannel *dch) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __func__); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { hc->chan[hc->dslot].slot_tx = -1; hc->chan[hc->dslot].slot_rx = -1; hc->chan[hc->dslot].conf = -1; @@ -3904,6 +3997,11 @@ hfcmulti_initmode(struct dchannel *dch) } if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) hc->hw.a_st_ctrl0[pt] |= V_TX_LI; + if (hc->ctype == HFC_TYPE_XHFC) { + hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */; + HFC_outb(hc, 0x35 /* A_ST_CTRL3 */, + 0x7c << 1 /* V_ST_PULSE */); + } /* line setup */ HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]); /* disable E-channel */ @@ -3990,7 +4088,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; - if (hc->type == 1) + if (hc->ctype == HFC_TYPE_E1) ch = rq->adr.channel; else ch = (rq->adr.channel - 1) + (dch->slot - 2); @@ -4081,7 +4179,7 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) switch (rq->protocol) { case ISDN_P_TE_S0: case ISDN_P_NT_S0: - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { err = -EINVAL; break; } @@ -4089,7 +4187,7 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) break; case ISDN_P_TE_E1: case ISDN_P_NT_E1: - if (hc->type != 1) { + if (hc->ctype != HFC_TYPE_E1) { err = -EINVAL; break; } @@ -4156,13 +4254,13 @@ init_card(struct hfc_multi *hc) disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); - if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, IRQF_SHARED, + if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED, "HFC-multi", hc)) { printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", - hc->pci_dev->irq); + hc->irq); + hc->irq = 0; return -EIO; } - hc->irq = hc->pci_dev->irq; if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); @@ -4269,6 +4367,10 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, hc->ledstate = 0xAFFEAFFE; hc->opticalsupport = m->opticalsupport; + hc->pci_iobase = 0; + hc->pci_membase = NULL; + hc->plx_membase = NULL; + /* set memory access methods */ if (m->io_mode) /* use mode from card config */ hc->io_mode = m->io_mode; @@ -4276,44 +4378,12 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, case HFC_IO_MODE_PLXSD: test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); hc->slots = 128; /* required */ - /* fall through */ - case HFC_IO_MODE_PCIMEM: hc->HFC_outb = HFC_outb_pcimem; hc->HFC_inb = HFC_inb_pcimem; hc->HFC_inw = HFC_inw_pcimem; hc->HFC_wait = HFC_wait_pcimem; hc->read_fifo = read_fifo_pcimem; hc->write_fifo = write_fifo_pcimem; - break; - case HFC_IO_MODE_REGIO: - hc->HFC_outb = HFC_outb_regio; - hc->HFC_inb = HFC_inb_regio; - hc->HFC_inw = HFC_inw_regio; - hc->HFC_wait = HFC_wait_regio; - hc->read_fifo = read_fifo_regio; - hc->write_fifo = write_fifo_regio; - break; - default: - printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - hc->HFC_outb_nodebug = hc->HFC_outb; - hc->HFC_inb_nodebug = hc->HFC_inb; - hc->HFC_inw_nodebug = hc->HFC_inw; - hc->HFC_wait_nodebug = hc->HFC_wait; -#ifdef HFC_REGISTER_DEBUG - hc->HFC_outb = HFC_outb_debug; - hc->HFC_inb = HFC_inb_debug; - hc->HFC_inw = HFC_inw_debug; - hc->HFC_wait = HFC_wait_debug; -#endif - hc->pci_iobase = 0; - hc->pci_membase = NULL; - hc->plx_membase = NULL; - - switch (hc->io_mode) { - case HFC_IO_MODE_PLXSD: hc->plx_origmembase = hc->pci_dev->resource[0].start; /* MEMBASE 1 is PLX PCI Bridge */ @@ -4361,6 +4431,12 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); break; case HFC_IO_MODE_PCIMEM: + hc->HFC_outb = HFC_outb_pcimem; + hc->HFC_inb = HFC_inb_pcimem; + hc->HFC_inw = HFC_inw_pcimem; + hc->HFC_wait = HFC_wait_pcimem; + hc->read_fifo = read_fifo_pcimem; + hc->write_fifo = write_fifo_pcimem; hc->pci_origmembase = hc->pci_dev->resource[1].start; if (!hc->pci_origmembase) { printk(KERN_WARNING @@ -4377,12 +4453,18 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, pci_disable_device(hc->pci_dev); return -EIO; } - printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d " - "HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, + printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ " + "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); break; case HFC_IO_MODE_REGIO: + hc->HFC_outb = HFC_outb_regio; + hc->HFC_inb = HFC_inb_regio; + hc->HFC_inw = HFC_inw_regio; + hc->HFC_wait = HFC_wait_regio; + hc->read_fifo = read_fifo_regio; + hc->write_fifo = write_fifo_regio; hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; if (!hc->pci_iobase) { printk(KERN_WARNING @@ -4464,7 +4546,7 @@ release_port(struct hfc_multi *hc, struct dchannel *dch) dch->timer.function = NULL; } - if (hc->type == 1) { /* E1 */ + if (hc->ctype == HFC_TYPE_E1) { /* E1 */ /* remove sync */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { hc->syncronized = 0; @@ -4863,9 +4945,15 @@ init_multi_port(struct hfc_multi *hc, int pt) test_and_set_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i + 2].cfg); } - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", - hc->type, HFC_cnt + 1, pt + 1); - ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); + if (hc->ctype == HFC_TYPE_XHFC) { + snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d", + HFC_cnt + 1, pt + 1); + ret = mISDN_register_device(&dch->dev, NULL, name); + } else { + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", + hc->ctype, HFC_cnt + 1, pt + 1); + ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); + } if (ret) goto free_chan; hc->created[pt] = 1; @@ -4876,9 +4964,9 @@ free_chan: } static int -hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) +hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, + const struct pci_device_id *ent) { - struct hm_map *m = (struct hm_map *)ent->driver_data; int ret_err = 0; int pt; struct hfc_multi *hc; @@ -4913,16 +5001,18 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) } spin_lock_init(&hc->lock); hc->mtyp = m; - hc->type = m->type; + hc->ctype = m->type; hc->ports = m->ports; hc->id = HFC_cnt; hc->pcm = pcm[HFC_cnt]; hc->io_mode = iomode[HFC_cnt]; - if (dslot[HFC_cnt] < 0 && hc->type == 1) { + if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) { hc->dslot = 0; printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " "31 B-channels\n"); - } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 && hc->type == 1) { + } + if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 + && hc->ctype == HFC_TYPE_E1) { hc->dslot = dslot[HFC_cnt]; printk(KERN_INFO "HFC-E1 card has alternating D-channel on " "time slot %d\n", dslot[HFC_cnt]); @@ -4944,8 +5034,11 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < (poll >> 1); i++) hc->silence_data[i] = hc->silence; - if (!(type[HFC_cnt] & 0x200)) - test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); + if (hc->ctype != HFC_TYPE_XHFC) { + if (!(type[HFC_cnt] & 0x200)) + test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); + test_and_set_bit(HFC_CHIP_CONF, &hc->chip); + } if (type[HFC_cnt] & 0x800) test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); @@ -4969,8 +5062,18 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_NOTICE "Watchdog enabled\n"); } - /* setup pci, hc->slots may change due to PLXSD */ - ret_err = setup_pci(hc, pdev, ent); + if (pdev && ent) + /* setup pci, hc->slots may change due to PLXSD */ + ret_err = setup_pci(hc, pdev, ent); + else +#ifdef CONFIG_MISDN_HFCMULTI_8xx + ret_err = setup_embedded(hc, m); +#else + { + printk(KERN_WARNING "Embedded IO Mode not selected\n"); + ret_err = -EIO; + } +#endif if (ret_err) { if (hc == syncmaster) syncmaster = NULL; @@ -4978,7 +5081,17 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) return ret_err; } - /* crate channels */ + hc->HFC_outb_nodebug = hc->HFC_outb; + hc->HFC_inb_nodebug = hc->HFC_inb; + hc->HFC_inw_nodebug = hc->HFC_inw; + hc->HFC_wait_nodebug = hc->HFC_wait; +#ifdef HFC_REGISTER_DEBUG + hc->HFC_outb = HFC_outb_debug; + hc->HFC_inb = HFC_inb_debug; + hc->HFC_inw = HFC_inw_debug; + hc->HFC_wait = HFC_wait_debug; +#endif + /* create channels */ for (pt = 0; pt < hc->ports; pt++) { if (Port_cnt >= MAX_PORTS) { printk(KERN_ERR "too many ports (max=%d).\n", @@ -4986,7 +5099,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) ret_err = -EINVAL; goto free_card; } - if (hc->type == 1) + if (hc->ctype == HFC_TYPE_E1) ret_err = init_e1_port(hc, m); else ret_err = init_multi_port(hc, pt); @@ -5070,6 +5183,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); /* initialize hardware */ + hc->irq = (m->irq) ? : hc->pci_dev->irq; ret_err = init_card(hc); if (ret_err) { printk(KERN_ERR "init card returns %d\n", ret_err); @@ -5120,45 +5234,47 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev) #define VENDOR_PRIM "PrimuX" static const struct hm_map hfcm_map[] = { -/*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0}, -/*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0}, -/*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0}, -/*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0}, -/*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0}, -/*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0}, -/*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0}, -/*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0}, -/*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO}, -/*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0}, -/*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0}, -/*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0}, - -/*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0}, +/*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0}, +/*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, +/*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, +/*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, +/*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0}, +/*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0}, +/*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, +/*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0}, +/*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0}, +/*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0}, +/*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0}, +/*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0}, + +/*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0}, /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, - HFC_IO_MODE_REGIO}, -/*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0}, -/*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0}, + HFC_IO_MODE_REGIO, 0}, +/*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0}, +/*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0}, -/*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0}, -/*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, -/*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, +/*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0}, +/*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, +/*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, -/*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0}, -/*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0}, -/*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, -/*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, +/*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, +/*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0}, +/*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, +/*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, -/*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0}, -/*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0}, -/*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0}, +/*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0}, +/*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0}, +/*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0}, /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, - HFC_IO_MODE_PLXSD}, + HFC_IO_MODE_PLXSD, 0}, /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, - HFC_IO_MODE_PLXSD}, -/*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0}, -/*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0}, -/*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0}, + HFC_IO_MODE_PLXSD, 0}, +/*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0}, +/*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0}, +/*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0}, +/*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0, + HFC_IO_MODE_EMBSD, XHFC_IRQ}, }; #undef H @@ -5265,7 +5381,7 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) "Please contact the driver maintainer for support.\n"); return -ENODEV; } - ret = hfcmulti_init(pdev, ent); + ret = hfcmulti_init(m, pdev, ent); if (ret) return ret; HFC_cnt++; @@ -5295,6 +5411,8 @@ static int __init HFCmulti_init(void) { int err; + int i, xhfc = 0; + struct hm_map m; printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); @@ -5342,11 +5460,43 @@ HFCmulti_init(void) if (!clock) clock = 1; + /* Register the embedded devices. + * This should be done before the PCI cards registration */ + switch (hwid) { + case HWID_MINIP4: + xhfc = 1; + m = hfcm_map[31]; + break; + case HWID_MINIP8: + xhfc = 2; + m = hfcm_map[31]; + break; + case HWID_MINIP16: + xhfc = 4; + m = hfcm_map[31]; + break; + default: + xhfc = 0; + } + + for (i = 0; i < xhfc; ++i) { + err = hfcmulti_init(&m, NULL, NULL); + if (err) { + printk(KERN_ERR "error registering embedded driver: " + "%x\n", err); + return -err; + } + HFC_cnt++; + printk(KERN_INFO "%d devices registered\n", HFC_cnt); + } + + /* Register the PCI cards */ err = pci_register_driver(&hfcmultipci_driver); if (err < 0) { printk(KERN_ERR "error registering pci driver: %x\n", err); return err; } + return 0; } diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index d19b4f6..0586618 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -947,6 +947,10 @@ conf_software: if (current_conf >= 0) { join_members: list_for_each_entry(member, &conf->mlist, list) { + /* if no conference engine on our chip, change to + * software */ + if (!member->dsp->features.hfc_conf) + goto conf_software; /* in case of hdlc, change to software */ if (member->dsp->hdlc) goto conf_software; diff --git a/include/linux/mISDNdsp.h b/include/linux/mISDNdsp.h index 2c483d4..41d1eeb 100644 --- a/include/linux/mISDNdsp.h +++ b/include/linux/mISDNdsp.h @@ -25,6 +25,7 @@ extern void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem); struct dsp_features { int hfc_id; /* unique id to identify the chip (or -1) */ int hfc_dtmf; /* set if HFCmulti card supports dtmf */ + int hfc_conf; /* set if HFCmulti card supports conferences */ int hfc_loops; /* set if card supports tone loops */ int hfc_echocanhw; /* set if card supports echocancelation*/ int pcm_id; /* unique id to identify the pcm bus (or -1) */ -- cgit v0.10.2 From ddacd14e8db9b9c4434d00545f6483fe01f02991 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 22 May 2009 11:04:53 +0000 Subject: mISDN: get_free_devid() failure ignored dev->id is unsigned so a get_free_devid() error is ignored. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 9426c98..21d34be 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -214,7 +214,7 @@ get_free_devid(void) if (!test_and_set_bit(i, (u_long *)&device_ids)) break; if (i > MAX_DEVICE_ID) - return -1; + return -EBUSY; return i; } @@ -224,10 +224,10 @@ mISDN_register_device(struct mISDNdevice *dev, { int err; - dev->id = get_free_devid(); - err = -EBUSY; - if (dev->id < 0) + err = get_free_devid(); + if (err < 0) goto error1; + dev->id = err; device_initialize(&dev->dev); if (name && name[0]) -- cgit v0.10.2 From 7245a2fe3c10ed7c2e9b1c8a83af5919c0cc0a89 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:55 +0000 Subject: mISDN: Add PCI ID for Junghanns 8S card new id for HFC-8S Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 5be4edf..50e9f4d 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -5275,6 +5275,7 @@ static const struct hm_map hfcm_map[] = { /*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0}, /*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0, HFC_IO_MODE_EMBSD, XHFC_IRQ}, +/*32*/ {VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0}, }; #undef H @@ -5328,6 +5329,8 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = { PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ + { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, + PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S */ /* Cards with HFC-E1 Chip */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3038ac2..4bdff98 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1914,6 +1914,7 @@ #define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540 #define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550 #define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552 +#define PCI_SUBDEVICE_ID_CCD_JH8S 0xB55B #define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560 #define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562 #define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563 -- cgit v0.10.2 From eac74af9b547e29c9634ed5eff4d514349e73310 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 22 May 2009 11:04:56 +0000 Subject: mISDN: Cleanup debug messages This patch make debug printk's KERN_DEBUG and also fix some codestyle issues. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 50e9f4d..d60f5b7 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -275,7 +275,7 @@ HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) #endif { - writeb(val, (hc->pci_membase)+reg); + writeb(val, hc->pci_membase + reg); } static u_char #ifdef HFC_REGISTER_DEBUG @@ -284,7 +284,7 @@ HFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) #endif { - return readb((hc->pci_membase)+reg); + return readb(hc->pci_membase + reg); } static u_short #ifdef HFC_REGISTER_DEBUG @@ -293,7 +293,7 @@ HFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) #endif { - return readw((hc->pci_membase)+reg); + return readw(hc->pci_membase + reg); } static void #ifdef HFC_REGISTER_DEBUG @@ -302,7 +302,8 @@ HFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) HFC_wait_pcimem(struct hfc_multi *hc) #endif { - while (readb((hc->pci_membase)+R_STATUS) & V_BUSY); + while (readb(hc->pci_membase + R_STATUS) & V_BUSY) + cpu_relax(); } /* HFC_IO_MODE_REGIO */ @@ -314,7 +315,7 @@ HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) #endif { - outb(reg, (hc->pci_iobase)+4); + outb(reg, hc->pci_iobase + 4); outb(val, hc->pci_iobase); } static u_char @@ -324,7 +325,7 @@ HFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inb_regio(struct hfc_multi *hc, u_char reg) #endif { - outb(reg, (hc->pci_iobase)+4); + outb(reg, hc->pci_iobase + 4); return inb(hc->pci_iobase); } static u_short @@ -334,7 +335,7 @@ HFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inw_regio(struct hfc_multi *hc, u_char reg) #endif { - outb(reg, (hc->pci_iobase)+4); + outb(reg, hc->pci_iobase + 4); return inw(hc->pci_iobase); } static void @@ -344,8 +345,9 @@ HFC_wait_regio(struct hfc_multi *hc, const char *function, int line) HFC_wait_regio(struct hfc_multi *hc) #endif { - outb(R_STATUS, (hc->pci_iobase)+4); - while (inb(hc->pci_iobase) & V_BUSY); + outb(R_STATUS, hc->pci_iobase + 4); + while (inb(hc->pci_iobase) & V_BUSY) + cpu_relax(); } #ifdef HFC_REGISTER_DEBUG @@ -364,14 +366,14 @@ HFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, if (regname[0] == '\0') strcpy(regname, "register"); - bits[7] = '0'+(!!(val&1)); - bits[6] = '0'+(!!(val&2)); - bits[5] = '0'+(!!(val&4)); - bits[4] = '0'+(!!(val&8)); - bits[3] = '0'+(!!(val&16)); - bits[2] = '0'+(!!(val&32)); - bits[1] = '0'+(!!(val&64)); - bits[0] = '0'+(!!(val&128)); + bits[7] = '0' + (!!(val & 1)); + bits[6] = '0' + (!!(val & 2)); + bits[5] = '0' + (!!(val & 4)); + bits[4] = '0' + (!!(val & 8)); + bits[3] = '0' + (!!(val & 16)); + bits[2] = '0' + (!!(val & 32)); + bits[1] = '0' + (!!(val & 64)); + bits[0] = '0' + (!!(val & 128)); printk(KERN_DEBUG "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", hc->id, reg, regname, val, bits, function, line); @@ -394,14 +396,14 @@ HFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) if (regname[0] == '\0') strcpy(regname, "register"); - bits[7] = '0'+(!!(val&1)); - bits[6] = '0'+(!!(val&2)); - bits[5] = '0'+(!!(val&4)); - bits[4] = '0'+(!!(val&8)); - bits[3] = '0'+(!!(val&16)); - bits[2] = '0'+(!!(val&32)); - bits[1] = '0'+(!!(val&64)); - bits[0] = '0'+(!!(val&128)); + bits[7] = '0' + (!!(val & 1)); + bits[6] = '0' + (!!(val & 2)); + bits[5] = '0' + (!!(val & 4)); + bits[4] = '0' + (!!(val & 8)); + bits[3] = '0' + (!!(val & 16)); + bits[2] = '0' + (!!(val & 32)); + bits[1] = '0' + (!!(val & 64)); + bits[0] = '0' + (!!(val & 128)); printk(KERN_DEBUG "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", hc->id, reg, regname, val, bits, function, line); @@ -481,6 +483,7 @@ write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) len--; } } + /* read fifo data (REGIO) */ static void read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) @@ -526,7 +529,6 @@ read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) } } - static void enable_hwirq(struct hfc_multi *hc) { @@ -1011,7 +1013,7 @@ plxsd_checksync(struct hfc_multi *hc, int rm) if (hc->syncronized) { if (syncmaster == NULL) { if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_WARNING "%s: GOT sync on card %d" + printk(KERN_DEBUG "%s: GOT sync on card %d" " (id=%d)\n", __func__, hc->id + 1, hc->id); hfcmulti_resync(hc, hc, rm); @@ -1019,7 +1021,7 @@ plxsd_checksync(struct hfc_multi *hc, int rm) } else { if (syncmaster == hc) { if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_WARNING "%s: LOST sync on card %d" + printk(KERN_DEBUG "%s: LOST sync on card %d" " (id=%d)\n", __func__, hc->id + 1, hc->id); hfcmulti_resync(hc, NULL, rm); @@ -1068,7 +1070,7 @@ release_io_hfcmulti(struct hfc_multi *hc) pv &= ~PLX_DSP_RES_N; writel(pv, plx_acc_32); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: PCM off: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n", __func__, pv); spin_unlock_irqrestore(&plx_lock, plx_flags); } @@ -1119,8 +1121,8 @@ init_chip(struct hfc_multi *hc) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __func__); val = HFC_inb(hc, R_CHIP_ID); - if ((val>>4) != 0x8 && (val>>4) != 0xc && (val>>4) != 0xe - && (val>>1) != 0x31) { + if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe && + (val >> 1) != 0x31) { printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); err = -EIO; goto out; @@ -1202,7 +1204,7 @@ init_chip(struct hfc_multi *hc) writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: slave/term: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n", __func__, pv); /* * If we are the 3rd PLXSD card or higher, we must turn @@ -1230,8 +1232,9 @@ init_chip(struct hfc_multi *hc) writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: term off: PLX_GPIO=%x\n", - __func__, pv); + printk(KERN_DEBUG + "%s: term off: PLX_GPIO=%x\n", + __func__, pv); } spin_unlock_irqrestore(&HFClock, hfc_flags); hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ @@ -1292,13 +1295,13 @@ init_chip(struct hfc_multi *hc) pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; pv |= PLX_SYNC_O_EN; if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: master: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n", __func__, pv); } else { pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); pv &= ~PLX_SYNC_O_EN; if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: slave: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n", __func__, pv); } writel(pv, plx_acc_32); @@ -1410,8 +1413,8 @@ controller_fail: writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: master: PLX_GPIO" - "=%x\n", __func__, pv); + printk(KERN_DEBUG "%s: master: " + "PLX_GPIO=%x\n", __func__, pv); } hc->hw.r_pcm_md0 |= V_PCM_MD; HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); @@ -1445,7 +1448,7 @@ controller_fail: writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: reset off: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n", __func__, pv); } @@ -1878,7 +1881,7 @@ hfcmulti_dtmf(struct hfc_multi *hc) hc->chan[ch].coeff_count = 0; skb = mI_alloc_skb(512, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING "%s: No memory for skb\n", + printk(KERN_DEBUG "%s: No memory for skb\n", __func__); continue; } @@ -2104,7 +2107,7 @@ next_frame: printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, - temp ? "HDLC":"TRANS"); + temp ? "HDLC" : "TRANS"); /* Have to prep the audio data */ hc->write_fifo(hc, d, ii - i); @@ -2780,13 +2783,13 @@ hfcmulti_interrupt(int intno, void *dev_id) handle_timer_irq(hc); } - if (r_irq_misc & V_DTMF_IRQ) { + if (r_irq_misc & V_DTMF_IRQ) hfcmulti_dtmf(hc); - } + if (r_irq_misc & V_IRQ_PROC) { static int irq_proc_cnt; if (!irq_proc_cnt++) - printk(KERN_WARNING "%s: got V_IRQ_PROC -" + printk(KERN_DEBUG "%s: got V_IRQ_PROC -" " this should not happen\n", __func__); } @@ -2936,7 +2939,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, else flow_rx = 0xc0; /* ST->(FIFO,PCM) */ /* put on slot */ - routing = bank_rx?0x80:0xc0; /* reversed */ + routing = bank_rx ? 0x80 : 0xc0; /* reversed */ if (conf >= 0 || bank_rx > 1) routing = 0x40; /* loop */ if (debug & DEBUG_HFCMULTI_MODE) @@ -2971,7 +2974,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_wait(hc); if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] &= - ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN; + ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); /* undocumented: delay after R_ST_SEL */ udelay(1); @@ -3505,9 +3508,9 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) switch (hh->id) { case HFC_SPL_LOOP_ON: /* set sample loop */ if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: HFC_SPL_LOOP_ON (len = %d)\n", - __func__, skb->len); + printk(KERN_DEBUG + "%s: HFC_SPL_LOOP_ON (len = %d)\n", + __func__, skb->len); ret = 0; break; case HFC_SPL_LOOP_OFF: /* set silence */ @@ -3716,8 +3719,7 @@ ph_state_change(struct dchannel *dch) int ch, i; if (!dch) { - printk(KERN_WARNING "%s: ERROR given dch is NULL\n", - __func__); + printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__); return; } hc = dch->hw; @@ -3738,14 +3740,15 @@ ph_state_change(struct dchannel *dch) switch (dch->state) { case (1): if (hc->e1_state != 1) { - for (i = 1; i <= 31; i++) { - /* reset fifos on e1 activation */ - HFC_outb_nodebug(hc, R_FIFO, (i << 1) | 1); - HFC_wait_nodebug(hc); - HFC_outb_nodebug(hc, - R_INC_RES_FIFO, V_RES_F); - HFC_wait_nodebug(hc); - } + for (i = 1; i <= 31; i++) { + /* reset fifos on e1 activation */ + HFC_outb_nodebug(hc, R_FIFO, + (i << 1) | 1); + HFC_wait_nodebug(hc); + HFC_outb_nodebug(hc, R_INC_RES_FIFO, + V_RES_F); + HFC_wait_nodebug(hc); + } } test_and_set_bit(FLG_ACTIVE, &dch->Flags); _queue_data(&dch->dev.D, PH_ACTIVATE_IND, @@ -4045,12 +4048,12 @@ open_dchannel(struct hfc_multi *hc, struct dchannel *dch, return -EINVAL; if ((dch->dev.D.protocol != ISDN_P_NONE) && (dch->dev.D.protocol != rq->protocol)) { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_WARNING "%s: change protocol %x to %x\n", - __func__, dch->dev.D.protocol, rq->protocol); + if (debug & DEBUG_HFCMULTI_MODE) + printk(KERN_DEBUG "%s: change protocol %x to %x\n", + __func__, dch->dev.D.protocol, rq->protocol); } - if ((dch->dev.D.protocol == ISDN_P_TE_S0) - && (rq->protocol != ISDN_P_TE_S0)) + if ((dch->dev.D.protocol == ISDN_P_TE_S0) && + (rq->protocol != ISDN_P_TE_S0)) l1_event(dch->l1, CLOSE_CHANNEL); if (dch->dev.D.protocol != rq->protocol) { if (rq->protocol == ISDN_P_TE_S0) { @@ -4127,9 +4130,9 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) wd_cnt = cq->p1 & 0xf; wd_mode = !!(cq->p1 >> 4); if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: MISDN_CTRL_HFC_WD_INIT mode %s counter 0x%x\n", - __func__, wd_mode ? "AUTO" : "MANUAL", wd_cnt); + printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s" + ", counter 0x%x\n", __func__, + wd_mode ? "AUTO" : "MANUAL", wd_cnt); /* set the watchdog timer */ HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4)); hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0); @@ -4139,8 +4142,8 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { /* enable the watchdog output for Speech-Design */ - HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7); - HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15); + HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7); + HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15); HFC_outb(hc, R_GPIO_OUT1, 0); HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15); } @@ -4319,7 +4322,7 @@ error: } if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: free irq %d\n", __func__, hc->irq); + printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); if (hc->irq) { free_irq(hc->irq, hc); hc->irq = 0; @@ -4624,7 +4627,7 @@ release_card(struct hfc_multi *hc) int ch; if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: release card (%d) entered\n", + printk(KERN_DEBUG "%s: release card (%d) entered\n", __func__, hc->id); /* unregister clock source */ @@ -4653,7 +4656,7 @@ release_card(struct hfc_multi *hc) /* release hardware & irq */ if (hc->irq) { if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: free irq %d\n", + printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); free_irq(hc->irq, hc); hc->irq = 0; @@ -4662,17 +4665,17 @@ release_card(struct hfc_multi *hc) release_io_hfcmulti(hc); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: remove instance from list\n", + printk(KERN_DEBUG "%s: remove instance from list\n", __func__); list_del(&hc->list); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: delete instance\n", __func__); + printk(KERN_DEBUG "%s: delete instance\n", __func__); if (hc == syncmaster) syncmaster = NULL; kfree(hc); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: card successfully removed\n", + printk(KERN_DEBUG "%s: card successfully removed\n", __func__); } @@ -4695,7 +4698,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); dch->dev.D.send = handle_dmsg; dch->dev.D.ctrl = hfcm_dctrl; - dch->dev.nrbchan = (hc->dslot)?30:31; + dch->dev.nrbchan = (hc->dslot) ? 30 : 31; dch->slot = hc->dslot; hc->chan[hc->dslot].dch = dch; hc->chan[hc->dslot].port = 0; @@ -4937,7 +4940,7 @@ init_multi_port(struct hfc_multi *hc, int pt) } /* disable E-channel */ if (port[Port_cnt] & 0x004) { - if (debug & DEBUG_HFCMULTI_INIT) + if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: PROTOCOL disable E-channel: " "card(%d) port(%d)\n", @@ -5222,7 +5225,7 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev) spin_unlock_irqrestore(&HFClock, flags); } else { if (debug) - printk(KERN_WARNING "%s: drvdata allready removed\n", + printk(KERN_DEBUG "%s: drvdata allready removed\n", __func__); } } diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 60dc925..776afc8 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -257,7 +257,7 @@ reset_hfcpci(struct hfc_pci *hc) Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* Clear already pending ints */ - if (Read_hfc(hc, HFCPCI_INT_S1)); + val = Read_hfc(hc, HFCPCI_INT_S1); /* set NT/TE mode */ hfcpci_setmode(hc); @@ -499,7 +499,8 @@ receive_dmsg(struct hfc_pci *hc) df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ df->za[df->f2 & D_FREG_MASK].z2 = - cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1)); + cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & + (D_FIFO_SIZE - 1)); } else { dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC); if (!dch->rx_skb) { @@ -966,6 +967,7 @@ static void ph_state_nt(struct dchannel *dch) { struct hfc_pci *hc = dch->hw; + u_char val; if (dch->debug) printk(KERN_DEBUG "%s: NT newstate %x\n", @@ -979,7 +981,7 @@ ph_state_nt(struct dchannel *dch) hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* Clear already pending ints */ - if (Read_hfc(hc, HFCPCI_INT_S1)); + val = Read_hfc(hc, HFCPCI_INT_S1); Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); udelay(10); Write_hfc(hc, HFCPCI_STATES, 4); @@ -1268,8 +1270,7 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) rx_slot = (bc>>8) & 0xff; tx_slot = (bc>>16) & 0xff; bc = bc & 0xff; - } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && - (protocol > ISDN_P_NONE)) + } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE)) printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", __func__); if (hc->chanlimit > 1) { @@ -1327,8 +1328,8 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) case (ISDN_P_B_RAW): bch->state = protocol; bch->nr = bc; - hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); - hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); + hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); if (bc & 2) { hc->hw.sctrl |= SCTRL_B2_ENA; hc->hw.sctrl_r |= SCTRL_B2_ENA; @@ -1362,8 +1363,8 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) case (ISDN_P_B_HDLC): bch->state = protocol; bch->nr = bc; - hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); - hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); + hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); if (bc & 2) { hc->hw.sctrl |= SCTRL_B2_ENA; hc->hw.sctrl_r |= SCTRL_B2_ENA; @@ -1457,7 +1458,7 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) switch (protocol) { case (ISDN_P_B_RAW): bch->state = protocol; - hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; @@ -1482,7 +1483,7 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) break; case (ISDN_P_B_HDLC): bch->state = protocol; - hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.last_bfifo_cnt[1] = 0; @@ -2047,7 +2048,8 @@ setup_hw(struct hfc_pci *hc) printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); return 1; } - hc->hw.pci_io = (char __iomem *)(unsigned long)hc->pdev->resource[1].start; + hc->hw.pci_io = + (char __iomem *)(unsigned long)hc->pdev->resource[1].start; if (!hc->hw.pci_io) { printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); @@ -2289,7 +2291,7 @@ hfc_remove_pci(struct pci_dev *pdev) release_card(card); else if (debug) - printk(KERN_WARNING "%s: drvdata already removed\n", + printk(KERN_DEBUG "%s: drvdata already removed\n", __func__); } diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c index de3795e..9c7c645 100644 --- a/drivers/isdn/mISDN/dsp_audio.c +++ b/drivers/isdn/mISDN/dsp_audio.c @@ -210,9 +210,8 @@ dsp_audio_generate_seven(void) j = 0; for (k = 0; k < 256; k++) { if (dsp_audio_alaw_to_s32[k] - < dsp_audio_alaw_to_s32[i]) { - j++; - } + < dsp_audio_alaw_to_s32[i]) + j++; } sorted_alaw[j] = i; } diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 0586618..9c7c0d1 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -238,7 +238,7 @@ dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC); if (!member) { - printk(KERN_ERR "kmalloc struct dsp_conf_member failed\n"); + printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n"); return -ENOMEM; } member->dsp = dsp; @@ -317,7 +317,7 @@ static struct dsp_conf conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC); if (!conf) { - printk(KERN_ERR "kmalloc struct dsp_conf failed\n"); + printk(KERN_ERR "kzalloc struct dsp_conf failed\n"); return NULL; } INIT_LIST_HEAD(&conf->mlist); @@ -1389,7 +1389,8 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) while (r != rr && t != tt) { #ifdef CMX_TX_DEBUG if (strlen(debugbuf) < 48) - sprintf(debugbuf+strlen(debugbuf), " %02x", p[t]); + sprintf(debugbuf+strlen(debugbuf), " %02x", + p[t]); #endif *d++ = p[t]; /* write tx_buff */ t = (t+1) & CMX_BUFF_MASK; diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index a0e0af8..c357506 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -280,7 +280,7 @@ dsp_fill_empty(struct dsp *dsp) static int dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) { - struct sk_buff *nskb; + struct sk_buff *nskb; int ret = 0; int cont; u8 *data; @@ -558,7 +558,7 @@ tone_off: dsp->pipeline.inuse = 1; dsp_cmx_hardware(dsp->conf, dsp); ret = dsp_pipeline_build(&dsp->pipeline, - len > 0 ? (char *)data : NULL); + len > 0 ? data : NULL); dsp_cmx_hardware(dsp->conf, dsp); dsp_rx_off(dsp); } @@ -720,7 +720,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) /* check if dtmf soft decoding is turned on */ if (dsp->dtmf.software) { digits = dsp_dtmf_goertzel_decode(dsp, skb->data, - skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); + skb->len, (dsp_options&DSP_OPT_ULAW) ? 1 : 0); } /* we need to process receive data if software */ if (dsp->conf && dsp->conf->software) { @@ -952,7 +952,7 @@ dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) int err = 0; if (debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); switch (cmd) { case OPEN_CHANNEL: @@ -1175,9 +1175,9 @@ static int dsp_init(void) /* init conversion tables */ dsp_audio_generate_law_tables(); - dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a; - dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32: - dsp_audio_alaw_to_s32; + dsp_silence = (dsp_options&DSP_OPT_ULAW) ? 0xff : 0x2a; + dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW) ? + dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32; dsp_audio_generate_s2law_table(); dsp_audio_generate_seven(); dsp_audio_generate_mix_table(); diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h index 8a20af4..21dbd15 100644 --- a/drivers/isdn/mISDN/dsp_ecdis.h +++ b/drivers/isdn/mISDN/dsp_ecdis.h @@ -91,7 +91,7 @@ int16_t amp) && det->tone_cycle_duration <= 475*8) { det->good_cycles++; if (det->good_cycles > 2) - det->hit = TRUE; + det->hit = TRUE; } det->tone_cycle_duration = 0; } diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c index 7a9af66..1debf53 100644 --- a/drivers/isdn/mISDN/dsp_tones.c +++ b/drivers/isdn/mISDN/dsp_tones.c @@ -253,18 +253,24 @@ static struct pattern { {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_DIALPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL}, + {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, + NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, + NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALPBX, - {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, NULL}, - {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, NULL}, + {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, + NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_RINGING, @@ -434,7 +440,7 @@ dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) /* unlocking is not required, because we don't expect a response */ nskb = _alloc_mISDN_skb(PH_CONTROL_REQ, - (len)?HFC_SPL_LOOP_ON:HFC_SPL_LOOP_OFF, len, sample, + (len) ? HFC_SPL_LOOP_ON : HFC_SPL_LOOP_OFF, len, sample, GFP_ATOMIC); if (nskb) { if (dsp->ch.peer) { @@ -498,8 +504,7 @@ dsp_tone(struct dsp *dsp, int tone) /* we turn off the tone */ if (!tone) { - if (dsp->features.hfc_loops) - if (timer_pending(&tonet->tl)) + if (dsp->features.hfc_loops && timer_pending(&tonet->tl)) del_timer(&tonet->tl); if (dsp->features.hfc_loops) dsp_tone_hw_message(dsp, NULL, 0); diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index ea3c3aa..d9cf83b 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -308,8 +308,8 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, /* assemble frame */ *p++ = (L1OIP_VERSION<<6) /* version and coding */ - | (hc->pri?0x20:0x00) /* type */ - | (hc->id?0x10:0x00) /* id */ + | (hc->pri ? 0x20 : 0x00) /* type */ + | (hc->id ? 0x10 : 0x00) /* id */ | localcodec; if (hc->id) { *p++ = hc->id>>24; /* id */ @@ -317,7 +317,7 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, *p++ = hc->id>>8; *p++ = hc->id; } - *p++ = (multi == 1)?0x80:0x00 + channel; /* m-flag, channel */ + *p++ = (multi == 1) ? 0x80 : 0x00 + channel; /* m-flag, channel */ if (multi == 1) *p++ = len; /* length */ *p++ = timebase>>8; /* time base */ @@ -401,12 +401,12 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, } /* prepare message */ - nskb = mI_alloc_skb((remotecodec == 3)?(len<<1):len, GFP_ATOMIC); + nskb = mI_alloc_skb((remotecodec == 3) ? (len<<1) : len, GFP_ATOMIC); if (!nskb) { printk(KERN_ERR "%s: No mem for skb.\n", __func__); return; } - p = skb_put(nskb, (remotecodec == 3)?(len<<1):len); + p = skb_put(nskb, (remotecodec == 3) ? (len<<1) : len); if (remotecodec == 1 && ulaw) l1oip_alaw_to_ulaw(buf, len, p); @@ -458,7 +458,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, hc->chan[channel].disorder_flag ^= 1; if (nskb) #endif - queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); + queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); } } @@ -749,8 +749,8 @@ l1oip_socket_thread(void *data) l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); } else { if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_WARNING "%s: broken pipe on socket\n", - __func__); + printk(KERN_WARNING + "%s: broken pipe on socket\n", __func__); } } @@ -925,7 +925,7 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) p = skb->data; l = skb->len; while (l) { - ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; + ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME; l1oip_socket_send(hc, 0, dch->slot, 0, hc->chan[dch->slot].tx_counter++, p, ll); p += ll; @@ -1173,7 +1173,7 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) p = skb->data; l = skb->len; while (l) { - ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; + ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME; l1oip_socket_send(hc, hc->codec, bch->slot, 0, hc->chan[bch->slot].tx_counter, p, ll); hc->chan[bch->slot].tx_counter += ll; @@ -1331,8 +1331,8 @@ init_card(struct l1oip *hc, int pri, int bundle) spin_lock_init(&hc->socket_lock); hc->idx = l1oip_cnt; hc->pri = pri; - hc->d_idx = pri?16:3; - hc->b_num = pri?30:2; + hc->d_idx = pri ? 16 : 3; + hc->b_num = pri ? 30 : 2; hc->bundle = bundle; if (hc->pri) sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1); @@ -1517,9 +1517,9 @@ l1oip_init(void) if (debug & DEBUG_L1OIP_INIT) printk(KERN_DEBUG "%s: interface %d is %s with %s.\n", - __func__, l1oip_cnt, pri?"PRI":"BRI", - bundle?"bundled IP packet for all B-channels" - :"seperate IP packets for every B-channel"); + __func__, l1oip_cnt, pri ? "PRI" : "BRI", + bundle ? "bundled IP packet for all B-channels" : + "seperate IP packets for every B-channel"); hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC); if (!hc) { diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 2a2c30a..c36f521 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -222,7 +222,7 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } else { /* use default for L2 messages */ if ((sk->sk_protocol == ISDN_P_LAPD_TE) || (sk->sk_protocol == ISDN_P_LAPD_NT)) - mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; + mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; } if (*debug & DEBUG_SOCKET) diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 778b660..bfcdd97 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -872,7 +872,6 @@ ph_data_ind(struct manager *mgr, struct sk_buff *skb) __func__, skb->len); goto done; } - if (*debug & DEBUG_L2_TEI) if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ goto done; diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index bbd99d3..5b7e9bf 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -259,7 +259,7 @@ mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, return ret; } -static struct file_operations mISDN_fops = { +static const struct file_operations mISDN_fops = { .read = mISDN_read, .poll = mISDN_poll, .ioctl = mISDN_ioctl, diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index 0b28fd1..45100b3 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -292,19 +292,19 @@ struct mISDN_devrename { /* MPH_INFORMATION_REQ payload */ struct ph_info_ch { - __u32 protocol; - __u64 Flags; + __u32 protocol; + __u64 Flags; }; struct ph_info_dch { - struct ph_info_ch ch; - __u16 state; - __u16 num_bch; + struct ph_info_ch ch; + __u16 state; + __u16 num_bch; }; struct ph_info { - struct ph_info_dch dch; - struct ph_info_ch bch[]; + struct ph_info_dch dch; + struct ph_info_ch bch[]; }; /* timer device ioctl */ -- cgit v0.10.2 From 8c90e11e3543d7de612194a042a148caeaab5f1d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 May 2009 11:04:57 +0000 Subject: mISDN: Use kernel_{send,recv}msg instead of open coding Reducing the number of direct users of sock_{recv,send}msg. Modified version to match the latest context. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h index a23d575..bc26c89 100644 --- a/drivers/isdn/mISDN/l1oip.h +++ b/drivers/isdn/mISDN/l1oip.h @@ -76,7 +76,7 @@ struct l1oip { struct sockaddr_in sin_local; /* local socket name */ struct sockaddr_in sin_remote; /* remote socket name */ struct msghdr sendmsg; /* ip message to send */ - struct iovec sendiov; /* iov for message */ + struct kvec sendiov; /* iov for message */ /* frame */ struct l1oip_chan chan[128]; /* channel instances */ diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index d9cf83b..990e6a7 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -279,7 +279,6 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, int multi = 0; u8 frame[len+32]; struct socket *socket = NULL; - mm_segment_t oldfs; if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n", @@ -352,10 +351,7 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, "= %d)\n", __func__, len); hc->sendiov.iov_base = frame; hc->sendiov.iov_len = len; - oldfs = get_fs(); - set_fs(KERNEL_DS); - len = sock_sendmsg(socket, &hc->sendmsg, len); - set_fs(oldfs); + len = kernel_sendmsg(socket, &hc->sendmsg, &hc->sendiov, 1, len); /* give socket back */ hc->socket = socket; /* no locking required */ @@ -660,8 +656,6 @@ l1oip_socket_thread(void *data) struct l1oip *hc = (struct l1oip *)data; int ret = 0; struct msghdr msg; - struct iovec iov; - mm_segment_t oldfs; struct sockaddr_in sin_rx; unsigned char *recvbuf; size_t recvbuf_size = 1500; @@ -718,16 +712,12 @@ l1oip_socket_thread(void *data) msg.msg_namelen = sizeof(sin_rx); msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; /* build send message */ hc->sendmsg.msg_name = &hc->sin_remote; hc->sendmsg.msg_namelen = sizeof(hc->sin_remote); hc->sendmsg.msg_control = NULL; hc->sendmsg.msg_controllen = 0; - hc->sendmsg.msg_iov = &hc->sendiov; - hc->sendmsg.msg_iovlen = 1; /* give away socket */ spin_lock(&hc->socket_lock); @@ -739,12 +729,12 @@ l1oip_socket_thread(void *data) printk(KERN_DEBUG "%s: socket created and open\n", __func__); while (!signal_pending(current)) { - iov.iov_base = recvbuf; - iov.iov_len = recvbuf_size; - oldfs = get_fs(); - set_fs(KERNEL_DS); - recvlen = sock_recvmsg(socket, &msg, recvbuf_size, 0); - set_fs(oldfs); + struct kvec iov = { + .iov_base = recvbuf, + .iov_len = sizeof(recvbuf), + }; + recvlen = kernel_recvmsg(socket, &msg, &iov, 1, + sizeof(recvbuf), 0); if (recvlen > 0) { l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); } else { -- cgit v0.10.2 From b0579d7459aaa979b96016f3cac5e59fd3cb72b5 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 22 May 2009 11:04:58 +0000 Subject: mISDN: Fix DTMF detection enable/disable DTMF detection was enabled when it was not supposed to. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 564ea3e..18af868 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -116,6 +116,7 @@ struct dsp_conf { #define ECHOCAN_BUFF_MASK 0x3ff /* -1 */ struct dsp_dtmf { + int enable; /* dtmf is enabled */ int treshold; /* above this is dtmf (square of) */ int software; /* dtmf uses software decoding */ int hardware; /* dtmf uses hardware decoding */ diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index c357506..c12cd2f 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -306,6 +306,7 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) "to %d\n", *((int *)data)); dsp->dtmf.treshold = (*(int *)data) * 10000; } + dsp->dtmf.enable = 1; /* init goertzel */ dsp_dtmf_goertzel_init(dsp); @@ -316,6 +317,7 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) case DTMF_TONE_STOP: /* turn off DTMF */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: stop dtmf\n", __func__); + dsp->dtmf.enable = 0; dsp->dtmf.hardware = 0; dsp->dtmf.software = 0; break; diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c index efc371c..9ae2d33 100644 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ b/drivers/isdn/mISDN/dsp_dtmf.c @@ -51,6 +51,9 @@ void dsp_dtmf_hardware(struct dsp *dsp) { int hardware = 1; + if (!dsp->dtmf.enable) + return; + if (!dsp->features.hfc_dtmf) hardware = 0; -- cgit v0.10.2 From daebafed7fef54fcc73d2d01431122cfd578d1e0 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 25 May 2009 00:56:56 -0700 Subject: mISDN: Added PCI ID for new Junghanns.net Single E1 cards. The new ID is validated by Cologne Chip. LEDs control is also supported. Signed-off-by: Andreas Eversberg Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index d60f5b7..e1dab30 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -5357,6 +5357,10 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = { PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ + + { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, + PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */ + { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_ANY_ID, PCI_ANY_ID, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4bdff98..12db06c 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1914,6 +1914,7 @@ #define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540 #define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550 #define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552 +#define PCI_SUBDEVICE_ID_CCD_JHSE1 0xB553 #define PCI_SUBDEVICE_ID_CCD_JH8S 0xB55B #define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560 #define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562 -- cgit v0.10.2 From e3804cbebb67887879102925961d41b503f7fbe3 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Mon, 25 May 2009 01:53:53 -0700 Subject: net: remove COMPAT_NET_DEV_OPS All drivers are already converted to new net_device_ops API and nobody uses old API anymore. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0fb446e..efa659f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -25,15 +25,6 @@ menuconfig NETDEVICES # that for each of the symbols. if NETDEVICES -config COMPAT_NET_DEV_OPS - default y - bool "Enable older network device API compatibility" - ---help--- - This option enables kernel compatibility with older network devices - that do not use net_device_ops interface. - - If unsure, say Y. - config IFB tristate "Intermediate Functional Block support" depends on NET_CLS_ACT diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f8574e7..ae3c209 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -901,44 +901,6 @@ struct net_device /* max exchange id for FCoE LRO by ddp */ unsigned int fcoe_ddp_xid; #endif - -#ifdef CONFIG_COMPAT_NET_DEV_OPS - struct { - int (*init)(struct net_device *dev); - void (*uninit)(struct net_device *dev); - int (*open)(struct net_device *dev); - int (*stop)(struct net_device *dev); - int (*hard_start_xmit) (struct sk_buff *skb, - struct net_device *dev); - u16 (*select_queue)(struct net_device *dev, - struct sk_buff *skb); - void (*change_rx_flags)(struct net_device *dev, - int flags); - void (*set_rx_mode)(struct net_device *dev); - void (*set_multicast_list)(struct net_device *dev); - int (*set_mac_address)(struct net_device *dev, - void *addr); - int (*validate_addr)(struct net_device *dev); - int (*do_ioctl)(struct net_device *dev, - struct ifreq *ifr, int cmd); - int (*set_config)(struct net_device *dev, - struct ifmap *map); - int (*change_mtu)(struct net_device *dev, int new_mtu); - int (*neigh_setup)(struct net_device *dev, - struct neigh_parms *); - void (*tx_timeout) (struct net_device *dev); - struct net_device_stats* (*get_stats)(struct net_device *dev); - void (*vlan_rx_register)(struct net_device *dev, - struct vlan_group *grp); - void (*vlan_rx_add_vid)(struct net_device *dev, - unsigned short vid); - void (*vlan_rx_kill_vid)(struct net_device *dev, - unsigned short vid); -#ifdef CONFIG_NET_POLL_CONTROLLER - void (*poll_controller)(struct net_device *dev); -#endif - }; -#endif }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/net/802/fddi.c b/net/802/fddi.c index 539e606..3ef0ab0 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c @@ -185,10 +185,6 @@ static const struct header_ops fddi_header_ops = { static void fddi_setup(struct net_device *dev) { dev->header_ops = &fddi_header_ops; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = fddi_change_mtu, -#endif - dev->type = ARPHRD_FDDI; dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */ diff --git a/net/802/hippi.c b/net/802/hippi.c index 313b9eb..cd3e8e9 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -193,11 +193,6 @@ static const struct header_ops hippi_header_ops = { static void hippi_setup(struct net_device *dev) { -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = hippi_change_mtu; - dev->set_mac_address = hippi_mac_addr; - dev->neigh_setup = hippi_neigh_setup_dev; -#endif dev->header_ops = &hippi_header_ops; /* diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index ff7572a..1e2ad4c 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -644,7 +644,6 @@ static int vlan_dev_init(struct net_device *dev) dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; dev->netdev_ops = &vlan_netdev_ops; } - netdev_resync_ops(dev); if (is_vlan_dev(real_dev)) subclass = 1; diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c index 72277d7..6c8016f 100644 --- a/net/appletalk/dev.c +++ b/net/appletalk/dev.c @@ -9,21 +9,10 @@ #include #include -#ifdef CONFIG_COMPAT_NET_DEV_OPS -static int ltalk_change_mtu(struct net_device *dev, int mtu) -{ - return -EINVAL; -} -#endif - static void ltalk_setup(struct net_device *dev) { /* Fill in the fields of the device structure with localtalk-generic values. */ -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = ltalk_change_mtu; -#endif - dev->type = ARPHRD_LOCALTLK; dev->hard_header_len = LTALK_HLEN; dev->mtu = LTALK_MTU; diff --git a/net/core/dev.c b/net/core/dev.c index 3942266..241613f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4580,39 +4580,6 @@ unsigned long netdev_fix_features(unsigned long features, const char *name) } EXPORT_SYMBOL(netdev_fix_features); -/* Some devices need to (re-)set their netdev_ops inside - * ->init() or similar. If that happens, we have to setup - * the compat pointers again. - */ -void netdev_resync_ops(struct net_device *dev) -{ -#ifdef CONFIG_COMPAT_NET_DEV_OPS - const struct net_device_ops *ops = dev->netdev_ops; - - dev->init = ops->ndo_init; - dev->uninit = ops->ndo_uninit; - dev->open = ops->ndo_open; - dev->change_rx_flags = ops->ndo_change_rx_flags; - dev->set_rx_mode = ops->ndo_set_rx_mode; - dev->set_multicast_list = ops->ndo_set_multicast_list; - dev->set_mac_address = ops->ndo_set_mac_address; - dev->validate_addr = ops->ndo_validate_addr; - dev->do_ioctl = ops->ndo_do_ioctl; - dev->set_config = ops->ndo_set_config; - dev->change_mtu = ops->ndo_change_mtu; - dev->neigh_setup = ops->ndo_neigh_setup; - dev->tx_timeout = ops->ndo_tx_timeout; - dev->get_stats = ops->ndo_get_stats; - dev->vlan_rx_register = ops->ndo_vlan_rx_register; - dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ops->ndo_poll_controller; -#endif -#endif -} -EXPORT_SYMBOL(netdev_resync_ops); - /** * register_netdevice - register a network device * @dev: device to register @@ -4652,23 +4619,6 @@ int register_netdevice(struct net_device *dev) dev->iflink = -1; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - /* Netdevice_ops API compatibility support. - * This is temporary until all network devices are converted. - */ - if (dev->netdev_ops) { - netdev_resync_ops(dev); - } else { - char drivername[64]; - pr_info("%s (%s): not using net_device_ops yet\n", - dev->name, netdev_drivername(dev, drivername, 64)); - - /* This works only because net_device_ops and the - compatibility structure are the same. */ - dev->netdev_ops = (void *) &(dev->init); - } -#endif - /* Init, if this function is available */ if (dev->netdev_ops->ndo_init) { ret = dev->netdev_ops->ndo_init(dev); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 280352a..5a883af 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -337,11 +337,6 @@ const struct header_ops eth_header_ops ____cacheline_aligned = { void ether_setup(struct net_device *dev) { dev->header_ops = ð_header_ops; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = eth_change_mtu; - dev->set_mac_address = eth_mac_addr; - dev->validate_addr = eth_validate_addr; -#endif dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; dev->mtu = ETH_DATA_LEN; -- cgit v0.10.2 From d0fc1d5e3fe869f8a32a2bc1dd02d8383a057164 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 25 May 2009 22:41:51 -0700 Subject: iwmc3200wifi: fix link error when CFG80211 is not selected The patch makes iwmc3200wifi select CFG80211 instead of LIB80211. This fixed module link error reported by Randy Dunlap when compiling iwmc3200wifi without cfg80211 selected. WIRELESS_EXT is also selected by iwmc3200wifi. Signed-off-by: Zhu Yi Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index ae84dda..41bd4b2 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -1,7 +1,8 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" depends on MMC && WLAN_80211 && EXPERIMENTAL - select LIB80211 + select WIRELESS_EXT + select CFG80211 select FW_LOADER select RFKILL -- cgit v0.10.2 From dfa9264fe1a0c1b46e11c6a4cd3251cd5e1afb71 Mon Sep 17 00:00:00 2001 From: Gabriel Paubert Date: Mon, 25 May 2009 22:46:19 -0700 Subject: net: Remove obsolete MV64360 config option Signed-off-by: Gabriel Paubert Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index efa659f..8de123d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2351,7 +2351,7 @@ config UGETH_TX_ON_DEMAND config MV643XX_ETH tristate "Marvell Discovery (643XX) and Orion ethernet support" - depends on MV64360 || MV64X60 || PPC32 || PLAT_ORION + depends on MV64X60 || PPC32 || PLAT_ORION select INET_LRO select PHYLIB help -- cgit v0.10.2 From a1dcb6628b9489504a3be2515580fc4de891f94a Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Mon, 25 May 2009 22:47:01 -0700 Subject: pkt_sched: gen_estimator: Fix signed integers right-shifts. Right-shifts of signed integers are implementation-defined so unportable. With feedback from: Eric Dumazet Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 6d62d46..78e5bfc 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -128,12 +128,12 @@ static void est_timer(unsigned long arg) npackets = e->bstats->packets; brate = (nbytes - e->last_bytes)<<(7 - idx); e->last_bytes = nbytes; - e->avbps += ((s64)(brate - e->avbps)) >> e->ewma_log; + e->avbps += (brate >> e->ewma_log) - (e->avbps >> e->ewma_log); e->rate_est->bps = (e->avbps+0xF)>>5; rate = (npackets - e->last_packets)<<(12 - idx); e->last_packets = npackets; - e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log; + e->avpps += (rate >> e->ewma_log) - (e->avpps >> e->ewma_log); e->rate_est->pps = (e->avpps+0x1FF)>>10; skip: read_unlock(&est_lock); -- cgit v0.10.2 From e88aae7bb1dc50457489d1d7c81dcf4db23ccf94 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Sun, 24 May 2009 23:52:35 +0000 Subject: net: sh_eth: fix cache coherency issue Fix the problem that may not work receive process by cache coherency issue. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: David S. Miller diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 3ab28bb..a742297 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -250,6 +250,8 @@ static void sh_eth_ring_format(struct net_device *ndev) mdp->rx_skbuff[i] = skb; if (skb == NULL) break; + dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz, + DMA_FROM_DEVICE); skb->dev = ndev; /* Mark as being used by this device. */ #if defined(CONFIG_CPU_SUBTYPE_SH7763) reserve = SH7763_SKB_ALIGN @@ -559,6 +561,8 @@ static int sh_eth_rx(struct net_device *ndev) mdp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ + dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz, + DMA_FROM_DEVICE); skb->dev = ndev; #if defined(CONFIG_CPU_SUBTYPE_SH7763) reserve = SH7763_SKB_ALIGN -- cgit v0.10.2 From 0029d64af5d72049e2170e4609fa83bd1f3f07cd Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Sun, 24 May 2009 23:53:20 +0000 Subject: net: sh_eth: fix TX/RX descriptor not set physical memory Fix the probrem that TX/RX descirptor not set physical memory. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: David S. Miller diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index a742297..eb76835 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -263,26 +263,20 @@ static void sh_eth_ring_format(struct net_device *ndev) #endif /* RX descriptor */ rxdesc = &mdp->rx_ring[i]; - rxdesc->addr = (u32)skb->data & ~0x3UL; + rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP); /* The size of the buffer is 16 byte boundary. */ - rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); /* Rx descriptor address set */ if (i == 0) { - ctrl_outl((u32)rxdesc, ioaddr + RDLAR); + ctrl_outl(mdp->rx_desc_dma, ioaddr + RDLAR); #if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)rxdesc, ioaddr + RDFAR); + ctrl_outl(mdp->rx_desc_dma, ioaddr + RDFAR); #endif } } - /* Rx descriptor address set */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)rxdesc, ioaddr + RDFXR); - ctrl_outl(0x1, ioaddr + RDFFR); -#endif - mdp->dirty_rx = (u32) (i - RX_RING_SIZE); /* Mark the last entry as wrapping the ring. */ @@ -298,19 +292,13 @@ static void sh_eth_ring_format(struct net_device *ndev) txdesc->buffer_length = 0; if (i == 0) { /* Tx descriptor address set */ - ctrl_outl((u32)txdesc, ioaddr + TDLAR); + ctrl_outl(mdp->tx_desc_dma, ioaddr + TDLAR); #if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)txdesc, ioaddr + TDFAR); + ctrl_outl(mdp->tx_desc_dma, ioaddr + TDFAR); #endif } } - /* Tx descriptor address set */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)txdesc, ioaddr + TDFXR); - ctrl_outl(0x1, ioaddr + TDFFR); -#endif - txdesc->status |= cpu_to_edmac(mdp, TD_TDLE); } @@ -536,7 +524,8 @@ static int sh_eth_rx(struct net_device *ndev) if (desc_status & RD_RFS10) mdp->stats.rx_over_errors++; } else { - swaps((char *)(rxdesc->addr & ~0x3), pkt_len + 2); + swaps(phys_to_virt(ALIGN(rxdesc->addr, 4)), + pkt_len + 2); skb = mdp->rx_skbuff[entry]; mdp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); @@ -554,7 +543,7 @@ static int sh_eth_rx(struct net_device *ndev) entry = mdp->dirty_rx % RX_RING_SIZE; rxdesc = &mdp->rx_ring[entry]; /* The size of the buffer is 16 byte boundary. */ - rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); if (mdp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(mdp->rx_buf_sz); @@ -573,7 +562,7 @@ static int sh_eth_rx(struct net_device *ndev) skb_reserve(skb, RX_OFFSET); #endif skb->ip_summed = CHECKSUM_NONE; - rxdesc->addr = (u32)skb->data & ~0x3UL; + rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); } if (entry >= RX_RING_SIZE - 1) rxdesc->status |= @@ -959,9 +948,9 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) entry = mdp->cur_tx % TX_RING_SIZE; mdp->tx_skbuff[entry] = skb; txdesc = &mdp->tx_ring[entry]; - txdesc->addr = (u32)(skb->data); + txdesc->addr = virt_to_phys(skb->data); /* soft swap. */ - swaps((char *)(txdesc->addr & ~0x3), skb->len + 2); + swaps(phys_to_virt(ALIGN(txdesc->addr, 4)), skb->len + 2); /* write back */ __flush_purge_region(skb->data, skb->len); if (skb->len < ETHERSMALL) -- cgit v0.10.2 From 862df49750e7ca9369c04d8d8105b3cc5d976e0d Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Sun, 24 May 2009 23:53:40 +0000 Subject: net: sh_eth: fix receive desciptor loop Fix the problem that this driver not update rxdesc in sh_eth_rx. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: David S. Miller diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index eb76835..728c419 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -536,6 +536,7 @@ static int sh_eth_rx(struct net_device *ndev) } rxdesc->status |= cpu_to_edmac(mdp, RD_RACT); entry = (++mdp->cur_rx) % RX_RING_SIZE; + rxdesc = &mdp->rx_ring[entry]; } /* Refill the Rx ring buffers. */ -- cgit v0.10.2 From 380af9e390ec81e74a2fd7fad948a8b12eeec7da Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Sun, 24 May 2009 23:54:21 +0000 Subject: net: sh_eth: CPU dependency code collect to "struct sh_eth_cpu_data" This improves readability by collecting CPU dependency code. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: David S. Miller diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 728c419..19571f7 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -2,7 +2,7 @@ * SuperH Ethernet device driver * * Copyright (C) 2006-2008 Nobuhiro Iwamatsu - * Copyright (C) 2008 Renesas Solutions Corp. + * Copyright (C) 2008-2009 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -33,6 +33,176 @@ #include "sh_eth.h" +/* There is CPU dependent code */ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) +#define SH_ETH_HAS_TSU 1 +static void sh_eth_chip_reset(struct net_device *ndev) +{ + /* reset device */ + ctrl_outl(ARSTR_ARSTR, ARSTR); + mdelay(1); +} + +static void sh_eth_reset(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + int cnt = 100; + + ctrl_outl(EDSR_ENALL, ioaddr + EDSR); + ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + while (cnt > 0) { + if (!(ctrl_inl(ioaddr + EDMR) & 0x3)) + break; + mdelay(1); + cnt--; + } + if (cnt < 0) + printk(KERN_ERR "Device reset fail\n"); + + /* Table Init */ + ctrl_outl(0x0, ioaddr + TDLAR); + ctrl_outl(0x0, ioaddr + TDFAR); + ctrl_outl(0x0, ioaddr + TDFXR); + ctrl_outl(0x0, ioaddr + TDFFR); + ctrl_outl(0x0, ioaddr + RDLAR); + ctrl_outl(0x0, ioaddr + RDFAR); + ctrl_outl(0x0, ioaddr + RDFXR); + ctrl_outl(0x0, ioaddr + RDFFR); +} + +static void sh_eth_set_duplex(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + if (mdp->duplex) /* Full */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); + else /* Half */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); +} + +static void sh_eth_set_rate(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + switch (mdp->speed) { + case 10: /* 10BASE */ + ctrl_outl(GECMR_10, ioaddr + GECMR); + break; + case 100:/* 100BASE */ + ctrl_outl(GECMR_100, ioaddr + GECMR); + break; + case 1000: /* 1000BASE */ + ctrl_outl(GECMR_1000, ioaddr + GECMR); + break; + default: + break; + } +} + +/* sh7763 */ +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .chip_reset = sh_eth_chip_reset, + .set_duplex = sh_eth_set_duplex, + .set_rate = sh_eth_set_rate, + + .ecsr_value = ECSR_ICD | ECSR_MPD, + .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, + + .tx_check = EESR_TC1 | EESR_FTC, + .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \ + EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \ + EESR_ECI, + .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \ + EESR_TFE, + + .apr = 1, + .mpr = 1, + .tpauser = 1, + .bculr = 1, + .hw_swap = 1, + .rpadir = 1, + .no_trimd = 1, + .no_ade = 1, +}; + +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) +#define SH_ETH_RESET_DEFAULT 1 +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, + + .apr = 1, + .mpr = 1, + .tpauser = 1, + .hw_swap = 1, +}; +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +#define SH_ETH_RESET_DEFAULT 1 +#define SH_ETH_HAS_TSU 1 +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, +}; +#endif + +static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd) +{ + if (!cd->ecsr_value) + cd->ecsr_value = DEFAULT_ECSR_INIT; + + if (!cd->ecsipr_value) + cd->ecsipr_value = DEFAULT_ECSIPR_INIT; + + if (!cd->fcftr_value) + cd->fcftr_value = DEFAULT_FIFO_F_D_RFF | \ + DEFAULT_FIFO_F_D_RFD; + + if (!cd->fdr_value) + cd->fdr_value = DEFAULT_FDR_INIT; + + if (!cd->rmcr_value) + cd->rmcr_value = DEFAULT_RMCR_VALUE; + + if (!cd->tx_check) + cd->tx_check = DEFAULT_TX_CHECK; + + if (!cd->eesr_err_check) + cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK; + + if (!cd->tx_error_check) + cd->tx_error_check = DEFAULT_TX_ERROR_CHECK; +} + +#if defined(SH_ETH_RESET_DEFAULT) +/* Chip Reset */ +static void sh_eth_reset(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + mdelay(3); + ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); +} +#endif + +#if defined(CONFIG_CPU_SH4) +static void sh_eth_set_receive_align(struct sk_buff *skb) +{ + int reserve; + + reserve = SH4_SKB_RX_ALIGN - ((u32)skb->data & (SH4_SKB_RX_ALIGN - 1)); + if (reserve) + skb_reserve(skb, reserve); +} +#else +static void sh_eth_set_receive_align(struct sk_buff *skb) +{ + skb_reserve(skb, SH2_SH3_SKB_RX_ALIGN); +} +#endif + + /* CPU <-> EDMAC endian convert */ static inline __u32 cpu_to_edmac(struct sh_eth_private *mdp, u32 x) { @@ -165,41 +335,6 @@ static struct mdiobb_ops bb_ops = { .get_mdio_data = sh_get_mdio, }; -/* Chip Reset */ -static void sh_eth_reset(struct net_device *ndev) -{ - u32 ioaddr = ndev->base_addr; - -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - int cnt = 100; - - ctrl_outl(EDSR_ENALL, ioaddr + EDSR); - ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); - while (cnt > 0) { - if (!(ctrl_inl(ioaddr + EDMR) & 0x3)) - break; - mdelay(1); - cnt--; - } - if (cnt < 0) - printk(KERN_ERR "Device reset fail\n"); - - /* Table Init */ - ctrl_outl(0x0, ioaddr + TDLAR); - ctrl_outl(0x0, ioaddr + TDFAR); - ctrl_outl(0x0, ioaddr + TDFXR); - ctrl_outl(0x0, ioaddr + TDFFR); - ctrl_outl(0x0, ioaddr + RDLAR); - ctrl_outl(0x0, ioaddr + RDFAR); - ctrl_outl(0x0, ioaddr + RDFXR); - ctrl_outl(0x0, ioaddr + RDFFR); -#else - ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); - mdelay(3); - ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); -#endif -} - /* free skb and descriptor buffer */ static void sh_eth_ring_free(struct net_device *ndev) { @@ -228,7 +363,7 @@ static void sh_eth_ring_free(struct net_device *ndev) /* format skb and descriptor buffer */ static void sh_eth_ring_format(struct net_device *ndev) { - u32 ioaddr = ndev->base_addr, reserve = 0; + u32 ioaddr = ndev->base_addr; struct sh_eth_private *mdp = netdev_priv(ndev); int i; struct sk_buff *skb; @@ -253,14 +388,8 @@ static void sh_eth_ring_format(struct net_device *ndev) dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz, DMA_FROM_DEVICE); skb->dev = ndev; /* Mark as being used by this device. */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - reserve = SH7763_SKB_ALIGN - - ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1)); - if (reserve) - skb_reserve(skb, reserve); -#else - skb_reserve(skb, RX_OFFSET); -#endif + sh_eth_set_receive_align(skb); + /* RX descriptor */ rxdesc = &mdp->rx_ring[i]; rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); @@ -321,7 +450,7 @@ static int sh_eth_ring_init(struct net_device *ndev) mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * RX_RING_SIZE, GFP_KERNEL); if (!mdp->rx_skbuff) { - printk(KERN_ERR "%s: Cannot allocate Rx skb\n", ndev->name); + dev_err(&ndev->dev, "Cannot allocate Rx skb\n"); ret = -ENOMEM; return ret; } @@ -329,7 +458,7 @@ static int sh_eth_ring_init(struct net_device *ndev) mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * TX_RING_SIZE, GFP_KERNEL); if (!mdp->tx_skbuff) { - printk(KERN_ERR "%s: Cannot allocate Tx skb\n", ndev->name); + dev_err(&ndev->dev, "Cannot allocate Tx skb\n"); ret = -ENOMEM; goto skb_ring_free; } @@ -340,8 +469,8 @@ static int sh_eth_ring_init(struct net_device *ndev) GFP_KERNEL); if (!mdp->rx_ring) { - printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", - ndev->name, rx_ringsize); + dev_err(&ndev->dev, "Cannot allocate Rx Ring (size %d bytes)\n", + rx_ringsize); ret = -ENOMEM; goto desc_ring_free; } @@ -353,8 +482,8 @@ static int sh_eth_ring_init(struct net_device *ndev) mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma, GFP_KERNEL); if (!mdp->tx_ring) { - printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", - ndev->name, tx_ringsize); + dev_err(&ndev->dev, "Cannot allocate Tx Ring (size %d bytes)\n", + tx_ringsize); ret = -ENOMEM; goto desc_ring_free; } @@ -384,44 +513,43 @@ static int sh_eth_dev_init(struct net_device *ndev) /* Descriptor format */ sh_eth_ring_format(ndev); - ctrl_outl(RPADIR_INIT, ioaddr + RPADIR); + if (mdp->cd->rpadir) + ctrl_outl(mdp->cd->rpadir_value, ioaddr + RPADIR); /* all sh_eth int mask */ ctrl_outl(0, ioaddr + EESIPR); -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(EDMR_EL, ioaddr + EDMR); -#else - ctrl_outl(0, ioaddr + EDMR); /* Endian change */ +#if defined(__LITTLE_ENDIAN__) + if (mdp->cd->hw_swap) + ctrl_outl(EDMR_EL, ioaddr + EDMR); + else #endif + ctrl_outl(0, ioaddr + EDMR); /* FIFO size set */ - ctrl_outl((FIFO_SIZE_T | FIFO_SIZE_R), ioaddr + FDR); + ctrl_outl(mdp->cd->fdr_value, ioaddr + FDR); ctrl_outl(0, ioaddr + TFTR); /* Frame recv control */ - ctrl_outl(0, ioaddr + RMCR); + ctrl_outl(mdp->cd->rmcr_value, ioaddr + RMCR); rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5; tx_int_var = mdp->tx_int_var = DESC_I_TINT2; ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER); -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - /* Burst sycle set */ - ctrl_outl(0x800, ioaddr + BCULR); -#endif + if (mdp->cd->bculr) + ctrl_outl(0x800, ioaddr + BCULR); /* Burst sycle set */ - ctrl_outl((FIFO_F_D_RFF | FIFO_F_D_RFD), ioaddr + FCFTR); + ctrl_outl(mdp->cd->fcftr_value, ioaddr + FCFTR); -#if !defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(0, ioaddr + TRIMD); -#endif + if (!mdp->cd->no_trimd) + ctrl_outl(0, ioaddr + TRIMD); /* Recv frame limit set register */ ctrl_outl(RFLR_VALUE, ioaddr + RFLR); ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR); - ctrl_outl((DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff), ioaddr + EESIPR); + ctrl_outl(mdp->cd->eesipr_value, ioaddr + EESIPR); /* PAUSE Prohibition */ val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) | @@ -429,24 +557,25 @@ static int sh_eth_dev_init(struct net_device *ndev) ctrl_outl(val, ioaddr + ECMR); + if (mdp->cd->set_rate) + mdp->cd->set_rate(ndev); + /* E-MAC Status Register clear */ - ctrl_outl(ECSR_INIT, ioaddr + ECSR); + ctrl_outl(mdp->cd->ecsr_value, ioaddr + ECSR); /* E-MAC Interrupt Enable register */ - ctrl_outl(ECSIPR_INIT, ioaddr + ECSIPR); + ctrl_outl(mdp->cd->ecsipr_value, ioaddr + ECSIPR); /* Set MAC address */ update_mac_address(ndev); /* mask reset */ -#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(APR_AP, ioaddr + APR); - ctrl_outl(MPR_MP, ioaddr + MPR); - ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7710) - ctrl_outl(BCFR_UNLIMITED, ioaddr + BCFR); -#endif + if (mdp->cd->apr) + ctrl_outl(APR_AP, ioaddr + APR); + if (mdp->cd->mpr) + ctrl_outl(MPR_MP, ioaddr + MPR); + if (mdp->cd->tpauser) + ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); /* Setting the Rx mode will start the Rx process. */ ctrl_outl(EDRRR_R, ioaddr + EDRRR); @@ -495,7 +624,7 @@ static int sh_eth_rx(struct net_device *ndev) int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx; struct sk_buff *skb; u16 pkt_len = 0; - u32 desc_status, reserve = 0; + u32 desc_status; rxdesc = &mdp->rx_ring[entry]; while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) { @@ -524,8 +653,10 @@ static int sh_eth_rx(struct net_device *ndev) if (desc_status & RD_RFS10) mdp->stats.rx_over_errors++; } else { - swaps(phys_to_virt(ALIGN(rxdesc->addr, 4)), - pkt_len + 2); + if (!mdp->cd->hw_swap) + sh_eth_soft_swap( + phys_to_virt(ALIGN(rxdesc->addr, 4)), + pkt_len + 2); skb = mdp->rx_skbuff[entry]; mdp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); @@ -554,14 +685,8 @@ static int sh_eth_rx(struct net_device *ndev) dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz, DMA_FROM_DEVICE); skb->dev = ndev; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - reserve = SH7763_SKB_ALIGN - - ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1)); - if (reserve) - skb_reserve(skb, reserve); -#else - skb_reserve(skb, RX_OFFSET); -#endif + sh_eth_set_receive_align(skb); + skb->ip_summed = CHECKSUM_NONE; rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); } @@ -587,6 +712,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) struct sh_eth_private *mdp = netdev_priv(ndev); u32 ioaddr = ndev->base_addr; u32 felic_stat; + u32 link_stat; + u32 mask; if (intr_status & EESR_ECI) { felic_stat = ctrl_inl(ioaddr + ECSR); @@ -595,7 +722,14 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) mdp->stats.tx_carrier_errors++; if (felic_stat & ECSR_LCHNG) { /* Link Changed */ - u32 link_stat = (ctrl_inl(ioaddr + PSR)); + if (mdp->cd->no_psr) { + if (mdp->link == PHY_DOWN) + link_stat = 0; + else + link_stat = PHY_ST_LINK; + } else { + link_stat = (ctrl_inl(ioaddr + PSR)); + } if (!(link_stat & PHY_ST_LINK)) { /* Link Down : disable tx and rx */ ctrl_outl(ctrl_inl(ioaddr + ECMR) & @@ -627,17 +761,15 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (intr_status & EESR_RFRMER) { /* Receive Frame Overflow int */ mdp->stats.rx_frame_errors++; - printk(KERN_ERR "Receive Frame Overflow\n"); + dev_err(&ndev->dev, "Receive Frame Overflow\n"); } } -#if !defined(CONFIG_CPU_SUBTYPE_SH7763) - if (intr_status & EESR_ADE) { - if (intr_status & EESR_TDE) { - if (intr_status & EESR_TFE) - mdp->stats.tx_fifo_errors++; - } + + if (!mdp->cd->no_ade) { + if (intr_status & EESR_ADE && intr_status & EESR_TDE && + intr_status & EESR_TFE) + mdp->stats.tx_fifo_errors++; } -#endif if (intr_status & EESR_RDE) { /* Receive Descriptor Empty int */ @@ -645,24 +777,24 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R) ctrl_outl(EDRRR_R, ioaddr + EDRRR); - printk(KERN_ERR "Receive Descriptor Empty\n"); + dev_err(&ndev->dev, "Receive Descriptor Empty\n"); } if (intr_status & EESR_RFE) { /* Receive FIFO Overflow int */ mdp->stats.rx_fifo_errors++; - printk(KERN_ERR "Receive FIFO Overflow\n"); + dev_err(&ndev->dev, "Receive FIFO Overflow\n"); } - if (intr_status & (EESR_TWB | EESR_TABT | -#if !defined(CONFIG_CPU_SUBTYPE_SH7763) - EESR_ADE | -#endif - EESR_TDE | EESR_TFE)) { + + mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE; + if (mdp->cd->no_ade) + mask &= ~EESR_ADE; + if (intr_status & mask) { /* Tx error */ u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR); /* dmesg */ - printk(KERN_ERR "%s:TX error. status=%8.8x cur_tx=%8.8x ", - ndev->name, intr_status, mdp->cur_tx); - printk(KERN_ERR "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", + dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ", + intr_status, mdp->cur_tx); + dev_err(&ndev->dev, "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", mdp->dirty_tx, (u32) ndev->state, edtrr); /* dirty buffer free */ sh_eth_txfree(ndev); @@ -681,6 +813,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) { struct net_device *ndev = netdev; struct sh_eth_private *mdp = netdev_priv(ndev); + struct sh_eth_cpu_data *cd = mdp->cd; irqreturn_t ret = IRQ_NONE; u32 ioaddr, boguscnt = RX_RING_SIZE; u32 intr_status = 0; @@ -693,7 +826,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) /* Clear interrupt */ if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF | EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF | - TX_CHECK | EESR_ERR_CHECK)) { + cd->tx_check | cd->eesr_err_check)) { ctrl_outl(intr_status, ioaddr + EESR); ret = IRQ_HANDLED; } else @@ -710,12 +843,12 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) } /* Tx Check */ - if (intr_status & TX_CHECK) { + if (intr_status & cd->tx_check) { sh_eth_txfree(ndev); netif_wake_queue(ndev); } - if (intr_status & EESR_ERR_CHECK) + if (intr_status & cd->eesr_err_check) sh_eth_error(ndev, intr_status); if (--boguscnt < 0) { @@ -750,32 +883,15 @@ static void sh_eth_adjust_link(struct net_device *ndev) if (phydev->duplex != mdp->duplex) { new_state = 1; mdp->duplex = phydev->duplex; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - if (mdp->duplex) { /* FULL */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, - ioaddr + ECMR); - } else { /* Half */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, - ioaddr + ECMR); - } -#endif + if (mdp->cd->set_duplex) + mdp->cd->set_duplex(ndev); } if (phydev->speed != mdp->speed) { new_state = 1; mdp->speed = phydev->speed; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - switch (mdp->speed) { - case 10: /* 10BASE */ - ctrl_outl(GECMR_10, ioaddr + GECMR); break; - case 100:/* 100BASE */ - ctrl_outl(GECMR_100, ioaddr + GECMR); break; - case 1000: /* 1000BASE */ - ctrl_outl(GECMR_1000, ioaddr + GECMR); break; - default: - break; - } -#endif + if (mdp->cd->set_rate) + mdp->cd->set_rate(ndev); } if (mdp->link == PHY_DOWN) { ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF) @@ -815,8 +931,9 @@ static int sh_eth_phy_init(struct net_device *ndev) dev_err(&ndev->dev, "phy_connect failed\n"); return PTR_ERR(phydev); } + dev_info(&ndev->dev, "attached phy %i to driver %s\n", - phydev->addr, phydev->drv->name); + phydev->addr, phydev->drv->name); mdp->phydev = phydev; @@ -854,7 +971,7 @@ static int sh_eth_open(struct net_device *ndev) #endif ndev->name, ndev); if (ret) { - printk(KERN_ERR "Can not assign IRQ number to %s\n", CARDNAME); + dev_err(&ndev->dev, "Can not assign IRQ number\n"); return ret; } @@ -951,7 +1068,9 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) txdesc = &mdp->tx_ring[entry]; txdesc->addr = virt_to_phys(skb->data); /* soft swap. */ - swaps(phys_to_virt(ALIGN(txdesc->addr, 4)), skb->len + 2); + if (!mdp->cd->hw_swap) + sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)), + skb->len + 2); /* write back */ __flush_purge_region(skb->data, skb->len); if (skb->len < ETHERSMALL) @@ -1053,7 +1172,7 @@ static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq, return phy_mii_ioctl(phydev, if_mii(rq), cmd); } - +#if defined(SH_ETH_HAS_TSU) /* Multicast reception directions set */ static void sh_eth_set_multicast_list(struct net_device *ndev) { @@ -1098,6 +1217,7 @@ static void sh_eth_tsu_init(u32 ioaddr) ctrl_outl(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */ ctrl_outl(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */ } +#endif /* SH_ETH_HAS_TSU */ /* MDIO bus release function */ static int sh_mdio_release(struct net_device *ndev) @@ -1187,7 +1307,9 @@ static const struct net_device_ops sh_eth_netdev_ops = { .ndo_stop = sh_eth_close, .ndo_start_xmit = sh_eth_start_xmit, .ndo_get_stats = sh_eth_get_stats, +#if defined(SH_ETH_HAS_TSU) .ndo_set_multicast_list = sh_eth_set_multicast_list, +#endif .ndo_tx_timeout = sh_eth_tx_timeout, .ndo_do_ioctl = sh_eth_do_ioctl, .ndo_validate_addr = eth_validate_addr, @@ -1213,7 +1335,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) ndev = alloc_etherdev(sizeof(struct sh_eth_private)); if (!ndev) { - printk(KERN_ERR "%s: could not allocate device.\n", CARDNAME); + dev_err(&pdev->dev, "Could not allocate device.\n"); ret = -ENOMEM; goto out; } @@ -1246,6 +1368,10 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* EDMAC endian */ mdp->edmac_endian = pd->edmac_endian; + /* set cpu data */ + mdp->cd = &sh_eth_my_cpu_data; + sh_eth_set_default_cpu_data(mdp->cd); + /* set function */ ndev->netdev_ops = &sh_eth_netdev_ops; ndev->watchdog_timeo = TX_TIMEOUT; @@ -1258,13 +1384,10 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* First device only init */ if (!devno) { -#if defined(ARSTR) - /* reset device */ - ctrl_outl(ARSTR_ARSTR, ARSTR); - mdelay(1); -#endif + if (mdp->cd->chip_reset) + mdp->cd->chip_reset(ndev); -#if defined(SH_TSU_ADDR) +#if defined(SH_ETH_HAS_TSU) /* TSU init (Init only)*/ sh_eth_tsu_init(SH_TSU_ADDR); #endif @@ -1281,8 +1404,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) goto out_unregister; /* pritnt device infomation */ - printk(KERN_INFO "%s: %s at 0x%x, ", - ndev->name, CARDNAME, (u32) ndev->base_addr); + pr_info("Base address at 0x%x, ", + (u32)ndev->base_addr); for (i = 0; i < 5; i++) printk("%02X:", ndev->dev_addr[i]); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 1537e13..eec6c4a 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -2,7 +2,7 @@ * SuperH Ethernet device driver * * Copyright (C) 2006-2008 Nobuhiro Iwamatsu - * Copyright (C) 2008 Renesas Solutions Corp. + * Copyright (C) 2008-2009 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -39,12 +39,10 @@ #define ETHERSMALL 60 #define PKT_BUF_SZ 1538 -#ifdef CONFIG_CPU_SUBTYPE_SH7763 - -#define SH7763_SKB_ALIGN 32 +#if defined(CONFIG_CPU_SUBTYPE_SH7763) /* Chip Base Address */ # define SH_TSU_ADDR 0xFEE01800 -# define ARSTR SH_TSU_ADDR +# define ARSTR SH_TSU_ADDR /* Chip Registers */ /* E-DMAC */ @@ -143,8 +141,8 @@ # define FWNLCR1 0xB0 # define FWALCR1 0x40 -#else /* CONFIG_CPU_SUBTYPE_SH7763 */ -# define RX_OFFSET 2 /* skb offset */ +#else /* #elif defined(CONFIG_CPU_SUBTYPE_SH7763) */ +/* This section is SH3 or SH2 */ #ifndef CONFIG_CPU_SUBTYPE_SH7619 /* Chip base address */ # define SH_TSU_ADDR 0xA7000804 @@ -243,6 +241,30 @@ #endif /* CONFIG_CPU_SUBTYPE_SH7763 */ +/* There are avoid compile error... */ +#if !defined(BCULR) +#define BCULR 0x0fc +#endif +#if !defined(TRIMD) +#define TRIMD 0x0fc +#endif +#if !defined(APR) +#define APR 0x0fc +#endif +#if !defined(MPR) +#define MPR 0x0fc +#endif +#if !defined(TPAUSER) +#define TPAUSER 0x0fc +#endif + +/* Driver's parameters */ +#if defined(CONFIG_CPU_SH4) +#define SH4_SKB_RX_ALIGN 32 +#else +#define SH2_SH3_SKB_RX_ALIGN 2 +#endif + /* * Register's bits */ @@ -261,11 +283,10 @@ enum GECMR_BIT { /* EDMR */ enum DMAC_M_BIT { + EDMR_EL = 0x40, /* Litte endian */ EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, #ifdef CONFIG_CPU_SUBTYPE_SH7763 - EDMR_SRST = 0x03, - EMDR_DESC_R = 0x30, /* Descriptor reserve size */ - EDMR_EL = 0x40, /* Litte endian */ + EDMR_SRST = 0x03, #else /* CONFIG_CPU_SUBTYPE_SH7763 */ EDMR_SRST = 0x01, #endif @@ -307,47 +328,43 @@ enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, }; /* EESR */ enum EESR_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7763 - EESR_TWB = 0x40000000, -#else - EESR_TWB = 0xC0000000, - EESR_TC1 = 0x20000000, - EESR_TUC = 0x10000000, - EESR_ROC = 0x80000000, -#endif - EESR_TABT = 0x04000000, - EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000, -#ifndef CONFIG_CPU_SUBTYPE_SH7763 - EESR_ADE = 0x00800000, -#endif - EESR_ECI = 0x00400000, - EESR_FTC = 0x00200000, EESR_TDE = 0x00100000, - EESR_TFE = 0x00080000, EESR_FRC = 0x00040000, - EESR_RDE = 0x00020000, EESR_RFE = 0x00010000, -#ifndef CONFIG_CPU_SUBTYPE_SH7763 - EESR_CND = 0x00000800, -#endif - EESR_DLC = 0x00000400, - EESR_CD = 0x00000200, EESR_RTO = 0x00000100, - EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040, - EESR_CELF = 0x00000020, EESR_RRF = 0x00000010, - EESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, - EESR_PRE = 0x00000002, EESR_CERF = 0x00000001, -}; - - -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -# define TX_CHECK (EESR_TC1 | EESR_FTC) -# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ - | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI) -# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE) - -#else -# define TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO) -# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ - | EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI) -# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE) -#endif + EESR_TWB1 = 0x80000000, + EESR_TWB = 0x40000000, /* same as TWB0 */ + EESR_TC1 = 0x20000000, + EESR_TUC = 0x10000000, + EESR_ROC = 0x08000000, + EESR_TABT = 0x04000000, + EESR_RABT = 0x02000000, + EESR_RFRMER = 0x01000000, /* same as RFCOF */ + EESR_ADE = 0x00800000, + EESR_ECI = 0x00400000, + EESR_FTC = 0x00200000, /* same as TC or TC0 */ + EESR_TDE = 0x00100000, + EESR_TFE = 0x00080000, /* same as TFUF */ + EESR_FRC = 0x00040000, /* same as FR */ + EESR_RDE = 0x00020000, + EESR_RFE = 0x00010000, + EESR_CND = 0x00000800, + EESR_DLC = 0x00000400, + EESR_CD = 0x00000200, + EESR_RTO = 0x00000100, + EESR_RMAF = 0x00000080, + EESR_CEEF = 0x00000040, + EESR_CELF = 0x00000020, + EESR_RRF = 0x00000010, + EESR_RTLF = 0x00000008, + EESR_RTSF = 0x00000004, + EESR_PRE = 0x00000002, + EESR_CERF = 0x00000001, +}; + +#define DEFAULT_TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | \ + EESR_RTO) +#define DEFAULT_EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | \ + EESR_RDE | EESR_RFRMER | EESR_ADE | \ + EESR_TFE | EESR_TDE | EESR_ECI) +#define DEFAULT_TX_ERROR_CHECK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | \ + EESR_TFE) /* EESIPR */ enum DMAC_IM_BIT { @@ -386,12 +403,8 @@ enum FCFTR_BIT { FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004, FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001, }; -#define FIFO_F_D_RFF (FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0) -#ifndef CONFIG_CPU_SUBTYPE_SH7619 -#define FIFO_F_D_RFD (FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0) -#else -#define FIFO_F_D_RFD (FCFTR_RFD0) -#endif +#define DEFAULT_FIFO_F_D_RFF (FCFTR_RFF2 | FCFTR_RFF1 | FCFTR_RFF0) +#define DEFAULT_FIFO_F_D_RFD (FCFTR_RFD2 | FCFTR_RFD1 | FCFTR_RFD0) /* Transfer descriptor bit */ enum TD_STS_BIT { @@ -404,60 +417,38 @@ enum TD_STS_BIT { #define TD_TFP (TD_TFP1|TD_TFP0) /* RMCR */ -enum RECV_RST_BIT { RMCR_RST = 0x01, }; +#define DEFAULT_RMCR_VALUE 0x00000000 + /* ECMR */ enum FELIC_MODE_BIT { -#ifdef CONFIG_CPU_SUBTYPE_SH7763 ECMR_TRCCM = 0x04000000, ECMR_RCSC = 0x00800000, ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000, -#endif ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020, - ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002, - ECMR_PRM = 0x00000001, + ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, + ECMR_DM = 0x00000002, ECMR_PRM = 0x00000001, }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF |\ - ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT) -#elif CONFIG_CPU_SUBTYPE_SH7619 -#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF) -#else -#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT) -#endif - /* ECSR */ enum ECSR_STATUS_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7763 ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10, -#endif ECSR_LCHNG = 0x04, ECSR_MPD = 0x02, ECSR_ICD = 0x01, }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -# define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP) -#else -# define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \ - ECSR_LCHNG | ECSR_ICD | ECSIPR_MPDIP) -#endif +#define DEFAULT_ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | ECSR_LCHNG | \ + ECSR_ICD | ECSIPR_MPDIP) /* ECSIPR */ enum ECSIPR_STATUS_MASK_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7763 ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10, -#endif ECSIPR_LCHNGIP = 0x04, ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01, }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -# define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) -#else -# define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \ - ECSIPR_ICDIP | ECSIPR_MPDIP) -#endif +#define DEFAULT_ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | \ + ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) /* APR */ enum APR_BIT { @@ -483,23 +474,12 @@ enum RPADIR_BIT { RPADIR_PADR = 0x0003f, }; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) -# define RPADIR_INIT (0x00) -#else -# define RPADIR_INIT (RPADIR_PADS1) -#endif - /* RFLR */ #define RFLR_VALUE 0x1000 /* FDR */ -enum FIFO_SIZE_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7619 - FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007, -#else - FIFO_SIZE_T = 0x00000100, FIFO_SIZE_R = 0x00000001, -#endif -}; +#define DEFAULT_FDR_INIT 0x00000707 + enum phy_offsets { PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3, PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6, @@ -633,7 +613,43 @@ struct sh_eth_rxdesc { u32 pad0; /* padding data */ } __attribute__((aligned(2), packed)); +/* This structure is used by each CPU dependency handling. */ +struct sh_eth_cpu_data { + /* optional functions */ + void (*chip_reset)(struct net_device *ndev); + void (*set_duplex)(struct net_device *ndev); + void (*set_rate)(struct net_device *ndev); + + /* mandatory initialize value */ + unsigned long eesipr_value; + + /* optional initialize value */ + unsigned long ecsr_value; + unsigned long ecsipr_value; + unsigned long fdr_value; + unsigned long fcftr_value; + unsigned long rpadir_value; + unsigned long rmcr_value; + + /* interrupt checking mask */ + unsigned long tx_check; + unsigned long eesr_err_check; + unsigned long tx_error_check; + + /* hardware features */ + unsigned no_psr:1; /* EtherC DO NOT have PSR */ + unsigned apr:1; /* EtherC have APR */ + unsigned mpr:1; /* EtherC have MPR */ + unsigned tpauser:1; /* EtherC have TPAUSER */ + unsigned bculr:1; /* EtherC have BCULR */ + unsigned hw_swap:1; /* E-DMAC have DE bit in EDMR */ + unsigned rpadir:1; /* E-DMAC have RPADIR */ + unsigned no_trimd:1; /* E-DMAC DO NOT have TRIMD */ + unsigned no_ade:1; /* E-DMAC DO NOT have ADE bit in EESR */ +}; + struct sh_eth_private { + struct sh_eth_cpu_data *cd; dma_addr_t rx_desc_dma; dma_addr_t tx_desc_dma; struct sh_eth_rxdesc *rx_ring; @@ -661,11 +677,7 @@ struct sh_eth_private { struct net_device_stats tsu_stats; /* TSU forward status */ }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -/* SH7763 has endian control register */ -#define swaps(x, y) -#else -static void swaps(char *src, int len) +static inline void sh_eth_soft_swap(char *src, int len) { #ifdef __LITTLE_ENDIAN__ u32 *p = (u32 *)src; @@ -676,5 +688,5 @@ static void swaps(char *src, int len) *p = swab32(*p); #endif } -#endif /* CONFIG_CPU_SUBTYPE_SH7763 */ -#endif + +#endif /* #ifndef __SH_ETH_H__ */ -- cgit v0.10.2 From 65ac8851490ec97a96759af729132c96f925a795 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Sun, 24 May 2009 23:54:30 +0000 Subject: net: sh_eth: Add support SH7724 Signed-off-by: Yoshihiro Shimoda Signed-off-by: Kuninori Morimoto Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8de123d..43a5254 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -516,15 +516,16 @@ config STNIC config SH_ETH tristate "Renesas SuperH Ethernet support" depends on SUPERH && \ - (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7763 || \ - CPU_SUBTYPE_SH7619) + (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \ + CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \ + CPU_SUBTYPE_SH7724) select CRC32 select MII select MDIO_BITBANG select PHYLIB help Renesas SuperH Ethernet device driver. - This driver support SH7710, SH7712, SH7763 and SH7619. + This driver support SH7710, SH7712, SH7763, SH7619, and SH7724. config SUNLANCE tristate "Sun LANCE support" diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 19571f7..cdd73b9 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -34,7 +34,57 @@ #include "sh_eth.h" /* There is CPU dependent code */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) +#if defined(CONFIG_CPU_SUBTYPE_SH7724) +#define SH_ETH_RESET_DEFAULT 1 +static void sh_eth_set_duplex(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + if (mdp->duplex) /* Full */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); + else /* Half */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); +} + +static void sh_eth_set_rate(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + switch (mdp->speed) { + case 10: /* 10BASE */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR); + break; + case 100:/* 100BASE */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR); + break; + default: + break; + } +} + +/* SH7724 */ +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .set_duplex = sh_eth_set_duplex, + .set_rate = sh_eth_set_rate, + + .ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD, + .ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP, + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x01ff009f, + + .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO, + .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE | + EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI, + .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE, + + .apr = 1, + .mpr = 1, + .tpauser = 1, + .hw_swap = 1, +}; + +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) #define SH_ETH_HAS_TSU 1 static void sh_eth_chip_reset(struct net_device *ndev) { diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index eec6c4a..9afe5b4 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -40,6 +40,8 @@ #define PKT_BUF_SZ 1538 #if defined(CONFIG_CPU_SUBTYPE_SH7763) +/* This CPU register maps is very difference by other SH4 CPU */ + /* Chip Base Address */ # define SH_TSU_ADDR 0xFEE01800 # define ARSTR SH_TSU_ADDR @@ -141,7 +143,59 @@ # define FWNLCR1 0xB0 # define FWALCR1 0x40 -#else /* #elif defined(CONFIG_CPU_SUBTYPE_SH7763) */ +#elif defined(CONFIG_CPU_SH4) /* #if defined(CONFIG_CPU_SUBTYPE_SH7763) */ +/* EtherC */ +#define ECMR 0x100 +#define RFLR 0x108 +#define ECSR 0x110 +#define ECSIPR 0x118 +#define PIR 0x120 +#define PSR 0x128 +#define RDMLR 0x140 +#define IPGR 0x150 +#define APR 0x154 +#define MPR 0x158 +#define TPAUSER 0x164 +#define RFCF 0x160 +#define TPAUSECR 0x168 +#define BCFRR 0x16c +#define MAHR 0x1c0 +#define MALR 0x1c8 +#define TROCR 0x1d0 +#define CDCR 0x1d4 +#define LCCR 0x1d8 +#define CNDCR 0x1dc +#define CEFCR 0x1e4 +#define FRECR 0x1e8 +#define TSFRCR 0x1ec +#define TLFRCR 0x1f0 +#define RFCR 0x1f4 +#define MAFCR 0x1f8 +#define RTRATE 0x1fc + +/* E-DMAC */ +#define EDMR 0x000 +#define EDTRR 0x008 +#define EDRRR 0x010 +#define TDLAR 0x018 +#define RDLAR 0x020 +#define EESR 0x028 +#define EESIPR 0x030 +#define TRSCER 0x038 +#define RMFCR 0x040 +#define TFTR 0x048 +#define FDR 0x050 +#define RMCR 0x058 +#define TFUCR 0x064 +#define RFOCR 0x068 +#define FCFTR 0x070 +#define RPADIR 0x078 +#define TRIMD 0x07c +#define RBWAR 0x0c8 +#define RDFAR 0x0cc +#define TBRAR 0x0d4 +#define TDFAR 0x0d8 +#else /* #elif defined(CONFIG_CPU_SH4) */ /* This section is SH3 or SH2 */ #ifndef CONFIG_CPU_SUBTYPE_SH7619 /* Chip base address */ @@ -426,7 +480,7 @@ enum FELIC_MODE_BIT { ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020, - ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, + ECMR_RTM = 0x00000010, ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002, ECMR_PRM = 0x00000001, }; -- cgit v0.10.2 From 08baf561083bc27a953aa087dd8a664bb2b88e8e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 25 May 2009 22:58:01 -0700 Subject: net: txq_trans_update() helper We would like to get rid of netdev->trans_start = jiffies; that about all net drivers have to use in their start_xmit() function, and use txq->trans_start instead. This can be done generically in core network, as suggested by David. Some devices, (particularly loopback) dont need trans_start update, because they dont have transmit watchdog. We could add a new device flag, or rely on fact that txq->tran_start can be updated is txq->xmit_lock_owner is different than -1. Use a helper function to hide our choice. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ae3c209..586b71f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1674,6 +1674,12 @@ static inline void __netif_tx_unlock_bh(struct netdev_queue *txq) spin_unlock_bh(&txq->_xmit_lock); } +static inline void txq_trans_update(struct netdev_queue *txq) +{ + if (txq->xmit_lock_owner != -1) + txq->trans_start = jiffies; +} + /** * netif_tx_lock - grab network device transmit lock * @dev: network device diff --git a/net/core/dev.c b/net/core/dev.c index 241613f..5eb3e48 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1698,6 +1698,8 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, skb->dst = NULL; } rc = ops->ndo_start_xmit(skb, dev); + if (rc == 0) + txq_trans_update(txq); /* * TODO: if skb_orphan() was called by * dev->hard_start_xmit() (for example, the unmodified @@ -1727,6 +1729,7 @@ gso: skb->next = nskb; return rc; } + txq_trans_update(txq); if (unlikely(netif_tx_queue_stopped(txq) && skb->next)) return NETDEV_TX_BUSY; } while (skb->next); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 67b4f3e..7ab31a7 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -302,8 +302,11 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) { if (__netif_tx_trylock(txq)) { - if (!netif_tx_queue_stopped(txq)) + if (!netif_tx_queue_stopped(txq)) { status = ops->ndo_start_xmit(skb, dev); + if (status == NETDEV_TX_OK) + txq_trans_update(txq); + } __netif_tx_unlock(txq); if (status == NETDEV_TX_OK) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 0666a82..b8ccd3c 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3438,6 +3438,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) retry_now: ret = (*xmit)(pkt_dev->skb, odev); if (likely(ret == NETDEV_TX_OK)) { + txq_trans_update(txq); pkt_dev->last_ok = 1; pkt_dev->sofar++; pkt_dev->seq_num++; diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 428a5ef..a886496 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -308,6 +308,7 @@ restart: if (!netif_tx_queue_stopped(slave_txq) && !netif_tx_queue_frozen(slave_txq) && slave_ops->ndo_start_xmit(skb, slave) == 0) { + txq_trans_update(slave_txq); __netif_tx_unlock(slave_txq); master->slaves = NEXT_SLAVE(q); netif_wake_queue(dev); -- cgit v0.10.2 From d3f65f7c3cf11b036bbc01f22ac5c958570e724c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 25 May 2009 23:48:43 -0700 Subject: atl1: use netdev->stats Get rid of private struct net_device_stats in "struct atl1e_adapter", and use one provided in struct net_device instead. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/atl1e/atl1e.h b/drivers/net/atl1e/atl1e.h index 2bf63b4..ba48220 100644 --- a/drivers/net/atl1e/atl1e.h +++ b/drivers/net/atl1e/atl1e.h @@ -429,7 +429,6 @@ struct atl1e_adapter { struct mii_if_info mii; /* MII interface info */ struct atl1e_hw hw; struct atl1e_hw_stats hw_stats; - struct net_device_stats net_stats; bool have_msi; u32 wol; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index adac061..c271b75 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1153,7 +1153,7 @@ static struct net_device_stats *atl1e_get_stats(struct net_device *netdev) { struct atl1e_adapter *adapter = netdev_priv(netdev); struct atl1e_hw_stats *hw_stats = &adapter->hw_stats; - struct net_device_stats *net_stats = &adapter->net_stats; + struct net_device_stats *net_stats = &netdev->stats; net_stats->rx_packets = hw_stats->rx_ok; net_stats->tx_packets = hw_stats->tx_ok; @@ -1181,7 +1181,7 @@ static struct net_device_stats *atl1e_get_stats(struct net_device *netdev) net_stats->tx_aborted_errors = hw_stats->tx_abort_col; net_stats->tx_window_errors = hw_stats->tx_late_col; - return &adapter->net_stats; + return net_stats; } static void atl1e_update_hw_stats(struct atl1e_adapter *adapter) @@ -1309,7 +1309,7 @@ static irqreturn_t atl1e_intr(int irq, void *data) /* link event */ if (status & (ISR_GPHY | ISR_MANUAL)) { - adapter->net_stats.tx_carrier_errors++; + netdev->stats.tx_carrier_errors++; atl1e_link_chg_event(adapter); break; } -- cgit v0.10.2 From 646cdb32831eebe8c2f742c293d0d266326854d9 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Tue, 26 May 2009 12:35:25 +0000 Subject: 3c50x: convert printk() to pr_() Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 1c5344a..367bec6 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -281,7 +281,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) autoirq = probe_irq_off(irq_mask); if (autoirq == 0) { - printk(KERN_WARNING "%s probe at %#x failed to detect IRQ line.\n", + pr_warning("%s probe at %#x failed to detect IRQ line.\n", mname, ioaddr); release_region(ioaddr, EL1_IO_EXTENT); return -EAGAIN; @@ -297,16 +297,16 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) if (autoirq) dev->irq = autoirq; - printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n", + pr_info("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq); #ifdef CONFIG_IP_MULTICAST - printk(KERN_WARNING "WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); + pr_warning("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); #endif if (el_debug) - printk(KERN_DEBUG "%s", version); + pr_debug("%s", version); lp = netdev_priv(dev); memset(lp, 0, sizeof(struct net_local)); @@ -343,7 +343,7 @@ static int el_open(struct net_device *dev) unsigned long flags; if (el_debug > 2) - printk(KERN_DEBUG "%s: Doing el_open()...", dev->name); + pr_debug("%s: Doing el_open()...\n", dev->name); retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev); if (retval) @@ -374,7 +374,7 @@ static void el_timeout(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug) - printk(KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", + pr_debug("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); dev->stats.tx_errors++; @@ -483,14 +483,13 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->loading = 0; dev->trans_start = jiffies; if (el_debug > 2) - printk(KERN_DEBUG " queued xmit.\n"); + pr_debug(" queued xmit.\n"); dev_kfree_skb(skb); return 0; } /* A receive upset our load, despite our best efforts */ if (el_debug > 2) - printk(KERN_DEBUG "%s: burped during tx load.\n", - dev->name); + pr_debug("%s: burped during tx load.\n", dev->name); spin_lock_irqsave(&lp->lock, flags); } while (1); } @@ -540,11 +539,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) */ if (el_debug > 3) - printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", - dev->name, axsr); + pr_debug("%s: el_interrupt() aux=%#02x\n", dev->name, axsr); if (lp->loading == 1 && !lp->txing) - printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n", + pr_warning("%s: Inconsistent state loading while not in tx\n", dev->name); if (lp->txing) { @@ -555,19 +553,17 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) int txsr = inb(TX_STATUS); if (lp->loading == 1) { - if (el_debug > 2) { - printk(KERN_DEBUG "%s: Interrupt while loading [", - dev->name); - printk(" txsr=%02x gp=%04x rp=%04x]\n", - txsr, inw(GP_LOW), inw(RX_LOW)); - } + if (el_debug > 2) + pr_debug("%s: Interrupt while loading [txsr=%02x gp=%04x rp=%04x]\n", + dev->name, txsr, inw(GP_LOW), inw(RX_LOW)); + /* Force a reload */ lp->loading = 2; spin_unlock(&lp->lock); goto out; } if (el_debug > 6) - printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x", + pr_debug("%s: txsr=%02x gp=%04x rp=%04x\n", dev->name, txsr, inw(GP_LOW), inw(RX_LOW)); if ((axsr & 0x80) && (txsr & TX_READY) == 0) { @@ -576,7 +572,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * on trying or reset immediately ? */ if (el_debug > 1) - printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n", + pr_debug("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n", dev->name, txsr, axsr, inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); @@ -587,7 +583,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * Timed out */ if (el_debug) - printk(KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name); + pr_debug("%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name); outb(AX_SYS, AX_CMD); lp->txing = 0; dev->stats.tx_aborted_errors++; @@ -598,7 +594,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) */ if (el_debug > 6) - printk(KERN_DEBUG " retransmitting after a collision.\n"); + pr_debug("%s: retransmitting after a collision.\n", dev->name); /* * Poor little chip can't reset its own start * pointer @@ -616,9 +612,8 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) */ dev->stats.tx_packets++; if (el_debug > 6) - printk(KERN_DEBUG " Tx succeeded %s\n", - (txsr & TX_RDY) ? "." : - "but tx is busy!"); + pr_debug("%s: Tx succeeded %s\n", dev->name, + (txsr & TX_RDY) ? "." : "but tx is busy!"); /* * This is safe the interrupt is atomic WRT itself. */ @@ -633,7 +628,8 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) int rxsr = inb(RX_STATUS); if (el_debug > 5) - printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS), inw(RX_LOW)); + pr_debug("%s: rxsr=%02x txsr=%02x rp=%04x\n", + dev->name, rxsr, inb(TX_STATUS), inw(RX_LOW)); /* * Just reading rx_status fixes most errors. */ @@ -643,7 +639,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) /* Handled to avoid board lock-up. */ dev->stats.rx_length_errors++; if (el_debug > 5) - printk(KERN_DEBUG " runt.\n"); + pr_debug("%s: runt.\n", dev->name); } else if (rxsr & RX_GOOD) { /* * Receive worked. @@ -654,12 +650,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * Nothing? Something is broken! */ if (el_debug > 2) - printk(KERN_DEBUG "%s: No packet seen, rxsr=%02x **resetting 3c501***\n", + pr_debug("%s: No packet seen, rxsr=%02x **resetting 3c501***\n", dev->name, rxsr); el_reset(dev); } - if (el_debug > 3) - printk(KERN_DEBUG ".\n"); } /* @@ -695,11 +689,11 @@ static void el_receive(struct net_device *dev) pkt_len = inw(RX_LOW); if (el_debug > 4) - printk(KERN_DEBUG " el_receive %d.\n", pkt_len); + pr_debug(" el_receive %d.\n", pkt_len); if (pkt_len < 60 || pkt_len > 1536) { if (el_debug) - printk(KERN_DEBUG "%s: bogus packet, length=%d\n", + pr_debug("%s: bogus packet, length=%d\n", dev->name, pkt_len); dev->stats.rx_over_errors++; return; @@ -718,8 +712,7 @@ static void el_receive(struct net_device *dev) outw(0x00, GP_LOW); if (skb == NULL) { - printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", - dev->name); + pr_info("%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; return; } else { @@ -753,7 +746,7 @@ static void el_reset(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug > 2) - printk(KERN_INFO "3c501 reset..."); + pr_info("3c501 reset...\n"); outb(AX_RESET, AX_CMD); /* Reset the chip */ /* Aux control, irq and loopback enabled */ outb(AX_LOOP, AX_CMD); @@ -787,7 +780,7 @@ static int el1_close(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug > 2) - printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", + pr_info("%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr); netif_stop_queue(dev); diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 4f08bd9..134638a 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -234,16 +234,16 @@ el2_probe1(struct net_device *dev, int ioaddr) } if (ei_debug && version_printed++ == 0) - printk(version); + pr_debug("%s", version); dev->base_addr = ioaddr; - printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); + pr_info("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%pM", dev->dev_addr); + pr_cont("%pM", dev->dev_addr); /* Map the 8390 back into the window. */ outb(ECNTRL_THIN, ioaddr + 0x406); @@ -256,7 +256,8 @@ el2_probe1(struct net_device *dev, int ioaddr) outb_p(E8390_PAGE0, ioaddr + E8390_CMD); /* Probe for, turn on and clear the board's shared memory. */ - if (ei_debug > 2) printk(" memory jumpers %2.2x ", membase_reg); + if (ei_debug > 2) + pr_cont(" memory jumpers %2.2x ", membase_reg); outb(EGACFR_NORM, ioaddr + 0x405); /* Enable RAM */ /* This should be probed for (or set via an ioctl()) at run-time. @@ -268,7 +269,7 @@ el2_probe1(struct net_device *dev, int ioaddr) #else ei_status.interface_num = dev->mem_end & 0xf; #endif - printk(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex"); + pr_cont(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex"); if ((membase_reg & 0xf0) == 0) { dev->mem_start = 0; @@ -292,7 +293,7 @@ el2_probe1(struct net_device *dev, int ioaddr) writel(test_val, mem_base + i); if (readl(mem_base) != 0xba5eba5e || readl(mem_base + i) != test_val) { - printk("3c503: memory failure or memory address conflict.\n"); + pr_warning("3c503: memory failure or memory address conflict.\n"); dev->mem_start = 0; ei_status.name = "3c503-PIO"; iounmap(mem_base); @@ -344,7 +345,7 @@ el2_probe1(struct net_device *dev, int ioaddr) if (dev->irq == 2) dev->irq = 9; else if (dev->irq > 5 && dev->irq != 9) { - printk("3c503: configured interrupt %d invalid, will use autoIRQ.\n", + pr_warning("3c503: configured interrupt %d invalid, will use autoIRQ.\n", dev->irq); dev->irq = 0; } @@ -359,7 +360,7 @@ el2_probe1(struct net_device *dev, int ioaddr) goto out1; if (dev->mem_start) - printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", + pr_info("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", dev->name, ei_status.name, (wordlength+1)<<3, dev->mem_start, dev->mem_end-1); @@ -367,7 +368,7 @@ el2_probe1(struct net_device *dev, int ioaddr) { ei_status.tx_start_page = EL2_MB1_START_PG; ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES; - printk("\n%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n", + pr_info("%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n", dev->name, ei_status.name, (wordlength+1)<<3); } release_region(ioaddr + 0x400, 8); @@ -435,15 +436,16 @@ static void el2_reset_8390(struct net_device *dev) { if (ei_debug > 1) { - printk("%s: Resetting the 3c503 board...", dev->name); - printk("%#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR), + pr_debug("%s: Resetting the 3c503 board...", dev->name); + pr_cont(" %#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR), E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR)); } outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL); ei_status.txing = 0; outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); el2_init_card(dev); - if (ei_debug > 1) printk("done\n"); + if (ei_debug > 1) + pr_cont("done\n"); } /* Initialize the 3c503 GA registers after a reset. */ @@ -529,7 +531,7 @@ el2_block_output(struct net_device *dev, int count, { if(!boguscount--) { - printk("%s: FIFO blocked in el2_block_output.\n", dev->name); + pr_notice("%s: FIFO blocked in el2_block_output.\n", dev->name); el2_reset_8390(dev); goto blocked; } @@ -581,7 +583,7 @@ el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_pag { if(!boguscount--) { - printk("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name); + pr_notice("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name); memset(hdr, 0x00, sizeof(struct e8390_pkt_hdr)); el2_reset_8390(dev); goto blocked; @@ -645,7 +647,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring { if(!boguscount--) { - printk("%s: FIFO blocked in el2_block_input.\n", dev->name); + pr_notice("%s: FIFO blocked in el2_block_input.\n", dev->name); el2_reset_8390(dev); goto blocked; } @@ -707,7 +709,7 @@ init_module(void) for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ - printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n"); + pr_notice("3c503.c: Presently autoprobing (not recommended) for a single card.\n"); } dev = alloc_eip_netdev(); if (!dev) @@ -720,7 +722,7 @@ init_module(void) continue; } free_netdev(dev); - printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); + pr_warning("3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); break; } if (found) diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 2de1c9c..b284994 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -126,26 +126,25 @@ * *********************************************************/ -static const char filename[] = __FILE__; +#define filename __FILE__ -static const char timeout_msg[] = "*** timeout at %s:%s (line %d) ***\n"; +#define timeout_msg "*** timeout at %s:%s (line %d) ***\n" #define TIMEOUT_MSG(lineno) \ - printk(timeout_msg, filename,__func__,(lineno)) + pr_notice(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 "*** invalid pcb length %d at %s:%s (line %d) ***\n" #define INVALID_PCB_MSG(len) \ - printk(invalid_pcb_msg, (len),filename,__func__,__LINE__) + pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__) -static char search_msg[] __initdata = KERN_INFO "%s: Looking for 3c505 adapter at address %#x..."; +#define search_msg "%s: Looking for 3c505 adapter at address %#x..." -static char stilllooking_msg[] __initdata = "still looking..."; +#define stilllooking_msg "still looking..." -static char found_msg[] __initdata = "found.\n"; +#define found_msg "found.\n" -static char notfound_msg[] __initdata = "not found (reason = %d)\n"; +#define notfound_msg "not found (reason = %d)\n" -static char couldnot_msg[] __initdata = KERN_INFO "%s: 3c505 not found\n"; +#define couldnot_msg "%s: 3c505 not found\n" /********************************************************* * @@ -284,7 +283,7 @@ static inline void adapter_reset(struct net_device *dev) outb_control(orig_hcr, dev); if (!start_receive(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: start receive command failed \n", dev->name); + pr_err("%s: start receive command failed\n", dev->name); } /* Check to make sure that a DMA transfer hasn't timed out. This should @@ -296,7 +295,9 @@ static inline void check_3c505_dma(struct net_device *dev) elp_device *adapter = netdev_priv(dev); if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) { unsigned long flags, f; - printk(KERN_ERR "%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma)); + pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name, + adapter->current_dma.direction ? "download" : "upload", + get_dma_residue(dev->dma)); spin_lock_irqsave(&adapter->lock, flags); adapter->dmaing = 0; adapter->busy = 0; @@ -321,7 +322,7 @@ static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte) if (inb_status(base_addr) & HCRE) return false; } - printk(KERN_WARNING "3c505: send_pcb_slow timed out\n"); + pr_warning("3c505: send_pcb_slow timed out\n"); return true; } @@ -333,7 +334,7 @@ static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte) if (inb_status(base_addr) & HCRE) return false; } - printk(KERN_WARNING "3c505: send_pcb_fast timed out\n"); + pr_warning("3c505: send_pcb_fast timed out\n"); return true; } @@ -386,7 +387,7 @@ static bool send_pcb(struct net_device *dev, pcb_struct * pcb) /* Avoid contention */ if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) { if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name); + pr_debug("%s: send_pcb entered while threaded\n", dev->name); } return false; } @@ -424,14 +425,15 @@ static bool send_pcb(struct net_device *dev, pcb_struct * pcb) case ASF_PCB_NAK: #ifdef ELP_DEBUG - printk(KERN_DEBUG "%s: send_pcb got NAK\n", dev->name); + pr_debug("%s: send_pcb got NAK\n", dev->name); #endif goto abort; } } if (elp_debug >= 1) - printk(KERN_DEBUG "%s: timeout waiting for PCB acknowledge (status %02x)\n", dev->name, inb_status(dev->base_addr)); + pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n", + dev->name, inb_status(dev->base_addr)); goto abort; sti_abort: @@ -481,7 +483,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); - printk(KERN_INFO "%s: status %02x\n", dev->name, stat); + pr_info("%s: status %02x\n", dev->name, stat); return false; } pcb->length = inb_command(dev->base_addr); @@ -518,7 +520,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) /* safety check total length vs data length */ if (total_length != (pcb->length + 2)) { if (elp_debug >= 2) - printk(KERN_WARNING "%s: mangled PCB received\n", dev->name); + pr_warning("%s: mangled PCB received\n", dev->name); set_hsf(dev, HSF_PCB_NAK); return false; } @@ -527,7 +529,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) if (test_and_set_bit(0, (void *) &adapter->busy)) { if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) { set_hsf(dev, HSF_PCB_NAK); - printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name); + pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name); pcb->command = 0; return true; } else { @@ -552,7 +554,7 @@ static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: restarting receiver\n", dev->name); + pr_debug("%s: restarting receiver\n", dev->name); tx_pcb->command = CMD_RECEIVE_PACKET; tx_pcb->length = sizeof(struct Rcv_pkt); tx_pcb->data.rcv_pkt.buf_seg @@ -586,7 +588,7 @@ static void receive_packet(struct net_device *dev, int len) skb = dev_alloc_skb(rlen + 2); if (!skb) { - printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name); + pr_warning("%s: memory squeeze, dropping packet\n", dev->name); target = adapter->dma_buffer; adapter->current_dma.target = NULL; /* FIXME: stats */ @@ -604,7 +606,8 @@ static void receive_packet(struct net_device *dev, int len) /* if this happens, we die */ if (test_and_set_bit(0, (void *) &adapter->dmaing)) - printk(KERN_ERR "%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction); + pr_err("%s: rx blocked, DMA in progress, dir %d\n", + dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 0; adapter->current_dma.length = rlen; @@ -623,14 +626,14 @@ static void receive_packet(struct net_device *dev, int len) release_dma_lock(flags); if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: rx DMA transfer started\n", dev->name); + pr_debug("%s: rx DMA transfer started\n", dev->name); } if (adapter->rx_active) adapter->rx_active--; if (!adapter->busy) - printk(KERN_WARNING "%s: receive_packet called, busy not set.\n", dev->name); + pr_warning("%s: receive_packet called, busy not set.\n", dev->name); } /****************************************************** @@ -655,12 +658,13 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) * has a DMA transfer finished? */ if (inb_status(dev->base_addr) & DONE) { - if (!adapter->dmaing) { - printk(KERN_WARNING "%s: phantom DMA completed\n", dev->name); - } - if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr)); - } + if (!adapter->dmaing) + pr_warning("%s: phantom DMA completed\n", dev->name); + + if (elp_debug >= 3) + pr_debug("%s: %s DMA complete, status %02x\n", dev->name, + adapter->current_dma.direction ? "tx" : "rx", + inb_status(dev->base_addr)); outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev); if (adapter->current_dma.direction) { @@ -682,7 +686,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) int t = adapter->rx_backlog.length[adapter->rx_backlog.out]; adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out); if (elp_debug >= 2) - printk(KERN_DEBUG "%s: receiving backlogged packet (%d)\n", dev->name, t); + pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t); receive_packet(dev, t); } else { adapter->busy = 0; @@ -713,21 +717,23 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) len = adapter->irx_pcb.data.rcv_resp.pkt_len; dlen = adapter->irx_pcb.data.rcv_resp.buf_len; if (adapter->irx_pcb.data.rcv_resp.timeout != 0) { - printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name); + pr_err("%s: interrupt - packet not received correctly\n", dev->name); } else { if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen); + pr_debug("%s: interrupt - packet received of length %i (%i)\n", + dev->name, len, dlen); } if (adapter->irx_pcb.command == 0xff) { if (elp_debug >= 2) - printk(KERN_DEBUG "%s: adding packet to backlog (len = %d)\n", dev->name, dlen); + pr_debug("%s: adding packet to backlog (len = %d)\n", + dev->name, dlen); adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen; adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in); } else { receive_packet(dev, dlen); } if (elp_debug >= 3) - printk(KERN_DEBUG "%s: packet received\n", dev->name); + pr_debug("%s: packet received\n", dev->name); } break; @@ -737,7 +743,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_CONFIGURE_82586_RESPONSE: adapter->got[CMD_CONFIGURE_82586] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: interrupt - configure response received\n", dev->name); + pr_debug("%s: interrupt - configure response received\n", dev->name); break; /* @@ -746,7 +752,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_CONFIGURE_ADAPTER_RESPONSE: adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: Adapter memory configuration %s.\n", dev->name, + pr_debug("%s: Adapter memory configuration %s.\n", dev->name, adapter->irx_pcb.data.failed ? "failed" : "succeeded"); break; @@ -756,7 +762,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_LOAD_MULTICAST_RESPONSE: adapter->got[CMD_LOAD_MULTICAST_LIST] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: Multicast address list loading %s.\n", dev->name, + pr_debug("%s: Multicast address list loading %s.\n", dev->name, adapter->irx_pcb.data.failed ? "failed" : "succeeded"); break; @@ -766,7 +772,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_SET_ADDRESS_RESPONSE: adapter->got[CMD_SET_STATION_ADDRESS] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: Ethernet address setting %s.\n", dev->name, + pr_debug("%s: Ethernet address setting %s.\n", dev->name, adapter->irx_pcb.data.failed ? "failed" : "succeeded"); break; @@ -783,7 +789,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res; adapter->got[CMD_NETWORK_STATISTICS] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name); + pr_debug("%s: interrupt - statistics response received\n", dev->name); break; /* @@ -791,17 +797,17 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) */ case CMD_TRANSMIT_PACKET_COMPLETE: if (elp_debug >= 3) - printk(KERN_DEBUG "%s: interrupt - packet sent\n", dev->name); + pr_debug("%s: interrupt - packet sent\n", dev->name); if (!netif_running(dev)) break; switch (adapter->irx_pcb.data.xmit_resp.c_stat) { case 0xffff: dev->stats.tx_aborted_errors++; - printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name); + pr_info("%s: transmit timed out, network cable problem?\n", dev->name); break; case 0xfffe: dev->stats.tx_fifo_errors++; - printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name); + pr_info("%s: transmit timed out, FIFO underrun\n", dev->name); break; } netif_wake_queue(dev); @@ -811,11 +817,12 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) * some unknown PCB */ default: - printk(KERN_DEBUG "%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command); + pr_debug("%s: unknown PCB received - %2.2x\n", + dev->name, adapter->irx_pcb.command); break; } } else { - printk(KERN_WARNING "%s: failed to read PCB on interrupt\n", dev->name); + pr_warning("%s: failed to read PCB on interrupt\n", dev->name); adapter_reset(dev); } } @@ -844,13 +851,13 @@ static int elp_open(struct net_device *dev) int retval; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to open device\n", dev->name); + pr_debug("%s: request to open device\n", dev->name); /* * make sure we actually found the device */ if (adapter == NULL) { - printk(KERN_ERR "%s: Opening a non-existent physical device\n", dev->name); + pr_err("%s: Opening a non-existent physical device\n", dev->name); return -EAGAIN; } /* @@ -880,17 +887,17 @@ static int elp_open(struct net_device *dev) * install our interrupt service routine */ if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) { - printk(KERN_ERR "%s: could not allocate IRQ%d\n", dev->name, dev->irq); + pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq); return retval; } if ((retval = request_dma(dev->dma, dev->name))) { free_irq(dev->irq, dev); - printk(KERN_ERR "%s: could not allocate DMA%d channel\n", dev->name, dev->dma); + pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma); return retval; } adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE); if (!adapter->dma_buffer) { - printk(KERN_ERR "%s: could not allocate DMA buffer\n", dev->name); + pr_err("%s: could not allocate DMA buffer\n", dev->name); free_dma(dev->dma); free_irq(dev->irq, dev); return -ENOMEM; @@ -906,7 +913,7 @@ static int elp_open(struct net_device *dev) * configure adapter memory: we need 10 multicast addresses, default==0 */ if (elp_debug >= 3) - printk(KERN_DEBUG "%s: sending 3c505 memory configuration command\n", dev->name); + pr_debug("%s: sending 3c505 memory configuration command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY; adapter->tx_pcb.data.memconf.cmd_q = 10; adapter->tx_pcb.data.memconf.rcv_q = 20; @@ -917,7 +924,7 @@ static int elp_open(struct net_device *dev) adapter->tx_pcb.length = sizeof(struct Memconf); adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send memory configuration command\n", dev->name); + pr_err("%s: couldn't send memory configuration command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout)); @@ -930,13 +937,13 @@ static int elp_open(struct net_device *dev) * configure adapter to receive broadcast messages and wait for response */ if (elp_debug >= 3) - printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name); + pr_debug("%s: sending 82586 configure command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_82586; adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; adapter->tx_pcb.length = 2; adapter->got[CMD_CONFIGURE_82586] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name); + pr_err("%s: couldn't send 82586 configure command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout)); @@ -952,7 +959,7 @@ static int elp_open(struct net_device *dev) */ prime_rx(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: %d receive PCBs active\n", dev->name, adapter->rx_active); + pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active); /* * device is now officially open! @@ -982,7 +989,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb) if (test_and_set_bit(0, (void *) &adapter->busy)) { if (elp_debug >= 2) - printk(KERN_DEBUG "%s: transmit blocked\n", dev->name); + pr_debug("%s: transmit blocked\n", dev->name); return false; } @@ -1004,7 +1011,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb) } /* if this happens, we die */ if (test_and_set_bit(0, (void *) &adapter->dmaing)) - printk(KERN_DEBUG "%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); + pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 1; adapter->current_dma.start_time = jiffies; @@ -1030,7 +1037,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb) release_dma_lock(flags); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name); + pr_debug("%s: DMA transfer started\n", dev->name); return true; } @@ -1044,9 +1051,10 @@ static void elp_timeout(struct net_device *dev) int stat; stat = inb_status(dev->base_addr); - printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command"); + pr_warning("%s: transmit timed out, lost %s?\n", dev->name, + (stat & ACRF) ? "interrupt" : "command"); if (elp_debug >= 1) - printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat); + pr_debug("%s: status %#02x\n", dev->name, stat); dev->trans_start = jiffies; dev->stats.tx_dropped++; netif_wake_queue(dev); @@ -1068,7 +1076,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) check_3c505_dma(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to send packet of length %d\n", dev->name, (int) skb->len); + pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len); netif_stop_queue(dev); @@ -1077,13 +1085,13 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if (!send_packet(dev, skb)) { if (elp_debug >= 2) { - printk(KERN_DEBUG "%s: failed to transmit packet\n", dev->name); + pr_debug("%s: failed to transmit packet\n", dev->name); } spin_unlock_irqrestore(&adapter->lock, flags); return 1; } if (elp_debug >= 3) - printk(KERN_DEBUG "%s: packet of length %d sent\n", dev->name, (int) skb->len); + pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len); /* * start the transmit timeout @@ -1107,7 +1115,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev) elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request for stats\n", dev->name); + pr_debug("%s: request for stats\n", dev->name); /* If the device is closed, just return the latest stats we have, - we cannot ask from the adapter without interrupts */ @@ -1119,7 +1127,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev) adapter->tx_pcb.length = 0; adapter->got[CMD_NETWORK_STATISTICS] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send get statistics command\n", dev->name); + pr_err("%s: couldn't send get statistics command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout)); @@ -1169,7 +1177,7 @@ static int elp_close(struct net_device *dev) elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to close device\n", dev->name); + pr_debug("%s: request to close device\n", dev->name); netif_stop_queue(dev); @@ -1213,7 +1221,7 @@ static void elp_set_mc_list(struct net_device *dev) unsigned long flags; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to set multicast list\n", dev->name); + pr_debug("%s: request to set multicast list\n", dev->name); spin_lock_irqsave(&adapter->lock, flags); @@ -1228,7 +1236,7 @@ static void elp_set_mc_list(struct net_device *dev) } adapter->got[CMD_LOAD_MULTICAST_LIST] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send set_multicast command\n", dev->name); + pr_err("%s: couldn't send set_multicast command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout)); @@ -1247,14 +1255,14 @@ static void elp_set_mc_list(struct net_device *dev) * and wait for response */ if (elp_debug >= 3) - printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name); + pr_debug("%s: sending 82586 configure command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_82586; adapter->tx_pcb.length = 2; adapter->got[CMD_CONFIGURE_82586] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) { spin_unlock_irqrestore(&adapter->lock, flags); - printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name); + pr_err("%s: couldn't send 82586 configure command\n", dev->name); } else { unsigned long timeout = jiffies + TIMEOUT; @@ -1283,17 +1291,17 @@ static int __init elp_sense(struct net_device *dev) orig_HSR = inb_status(addr); if (elp_debug > 0) - printk(search_msg, name, addr); + pr_debug(search_msg, name, addr); if (orig_HSR == 0xff) { if (elp_debug > 0) - printk(notfound_msg, 1); + pr_cont(notfound_msg, 1); goto out; } /* Wait for a while; the adapter may still be booting up */ if (elp_debug > 0) - printk(stilllooking_msg); + pr_cont(stilllooking_msg); if (orig_HSR & DIR) { /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */ @@ -1301,7 +1309,7 @@ static int __init elp_sense(struct net_device *dev) msleep(300); if (inb_status(addr) & DIR) { if (elp_debug > 0) - printk(notfound_msg, 2); + pr_cont(notfound_msg, 2); goto out; } } else { @@ -1310,7 +1318,7 @@ static int __init elp_sense(struct net_device *dev) msleep(300); if (!(inb_status(addr) & DIR)) { if (elp_debug > 0) - printk(notfound_msg, 3); + pr_cont(notfound_msg, 3); goto out; } } @@ -1318,7 +1326,7 @@ static int __init elp_sense(struct net_device *dev) * It certainly looks like a 3c505. */ if (elp_debug > 0) - printk(found_msg); + pr_cont(found_msg); return 0; out: @@ -1349,7 +1357,7 @@ static int __init elp_autodetect(struct net_device *dev) /* could not find an adapter */ if (elp_debug > 0) - printk(couldnot_msg, dev->name); + pr_debug(couldnot_msg, dev->name); return 0; /* Because of this, the layer above will return -ENODEV */ } @@ -1424,16 +1432,16 @@ static int __init elplus_setup(struct net_device *dev) /* Nope, it's ignoring the command register. This means that * either it's still booting up, or it's died. */ - printk(KERN_ERR "%s: command register wouldn't drain, ", dev->name); + pr_err("%s: command register wouldn't drain, ", dev->name); if ((inb_status(dev->base_addr) & 7) == 3) { /* If the adapter status is 3, it *could* still be booting. * Give it the benefit of the doubt for 10 seconds. */ - printk("assuming 3c505 still starting\n"); + pr_cont("assuming 3c505 still starting\n"); timeout = jiffies + 10*HZ; while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7)); if (inb_status(dev->base_addr) & 7) { - printk(KERN_ERR "%s: 3c505 failed to start\n", dev->name); + pr_err("%s: 3c505 failed to start\n", dev->name); } else { okay = 1; /* It started */ } @@ -1441,7 +1449,7 @@ static int __init elplus_setup(struct net_device *dev) /* Otherwise, it must just be in a strange * state. We probably need to kick it. */ - printk("3c505 is sulking\n"); + pr_cont("3c505 is sulking\n"); } } for (tries = 0; tries < 5 && okay; tries++) { @@ -1454,18 +1462,19 @@ static int __init elplus_setup(struct net_device *dev) adapter->tx_pcb.length = 0; cookie = probe_irq_on(); if (!send_pcb(dev, &adapter->tx_pcb)) { - printk(KERN_ERR "%s: could not send first PCB\n", dev->name); + pr_err("%s: could not send first PCB\n", dev->name); probe_irq_off(cookie); continue; } if (!receive_pcb(dev, &adapter->rx_pcb)) { - printk(KERN_ERR "%s: could not read first PCB\n", dev->name); + pr_err("%s: could not read first PCB\n", dev->name); probe_irq_off(cookie); continue; } if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) || (adapter->rx_pcb.length != 6)) { - printk(KERN_ERR "%s: first PCB wrong (%d, %d)\n", dev->name, adapter->rx_pcb.command, adapter->rx_pcb.length); + pr_err("%s: first PCB wrong (%d, %d)\n", dev->name, + adapter->rx_pcb.command, adapter->rx_pcb.length); probe_irq_off(cookie); continue; } @@ -1474,32 +1483,32 @@ static int __init elplus_setup(struct net_device *dev) /* It's broken. Do a hard reset to re-initialise the board, * and try again. */ - printk(KERN_INFO "%s: resetting adapter\n", dev->name); + pr_info("%s: resetting adapter\n", dev->name); outb_control(adapter->hcr_val | FLSH | ATTN, dev); outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev); } - printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name); + pr_err("%s: failed to initialise 3c505\n", dev->name); goto out; okay: if (dev->irq) { /* Is there a preset IRQ? */ int rpt = probe_irq_off(cookie); if (dev->irq != rpt) { - printk(KERN_WARNING "%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt); + pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt); } /* if dev->irq == probe_irq_off(cookie), all is well */ } else /* No preset IRQ; just use what we can detect */ dev->irq = probe_irq_off(cookie); switch (dev->irq) { /* Legal, sane? */ case 0: - printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n", + pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n", dev->name); goto out; case 1: case 6: case 8: case 13: - printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n", + pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n", dev->name, dev->irq); goto out; } @@ -1521,7 +1530,7 @@ static int __init elplus_setup(struct net_device *dev) dev->dma = dev->mem_start & 7; } else { - printk(KERN_WARNING "%s: warning, DMA channel not specified, using default\n", dev->name); + pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name); dev->dma = ELP_DMA; } } @@ -1529,11 +1538,8 @@ static int __init elplus_setup(struct net_device *dev) /* * print remainder of startup message */ - printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, " - "addr %pM, ", - dev->name, dev->base_addr, dev->irq, dev->dma, - dev->dev_addr); - + pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ", + dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr); /* * read more information from the adapter */ @@ -1544,9 +1550,10 @@ static int __init elplus_setup(struct net_device *dev) !receive_pcb(dev, &adapter->rx_pcb) || (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) || (adapter->rx_pcb.length != 10)) { - printk("not responding to second PCB\n"); + pr_cont("not responding to second PCB\n"); } - printk("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers, adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz); + pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers, + adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz); /* * reconfigure the adapter memory to better suit our purposes @@ -1563,10 +1570,10 @@ static int __init elplus_setup(struct net_device *dev) !receive_pcb(dev, &adapter->rx_pcb) || (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) || (adapter->rx_pcb.length != 2)) { - printk(KERN_ERR "%s: could not configure adapter memory\n", dev->name); + pr_err("%s: could not configure adapter memory\n", dev->name); } if (adapter->rx_pcb.data.configure) { - printk(KERN_ERR "%s: adapter configuration failed\n", dev->name); + pr_err("%s: adapter configuration failed\n", dev->name); } dev->netdev_ops = &elp_netdev_ops; @@ -1631,17 +1638,17 @@ int __init init_module(void) dev->dma = dma[this_dev]; } else { dev->dma = ELP_DMA; - printk(KERN_WARNING "3c505.c: warning, using default DMA channel,\n"); + pr_warning("3c505.c: warning, using default DMA channel,\n"); } if (io[this_dev] == 0) { if (this_dev) { free_netdev(dev); break; } - printk(KERN_NOTICE "3c505.c: module autoprobe not recommended, give io=xx.\n"); + pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n"); } if (elplus_setup(dev) != 0) { - printk(KERN_WARNING "3c505.c: Failed to register card at 0x%x.\n", io[this_dev]); + pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]); free_netdev(dev); break; } diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index fbbaf82..96b8665 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -364,7 +364,7 @@ static const struct net_device_ops netdev_ops = { static int __init el16_probe1(struct net_device *dev, int ioaddr) { - static unsigned char init_ID_done, version_printed; + static unsigned char init_ID_done; int i, irq, irqval, retval; struct net_local *lp; @@ -391,10 +391,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) goto out; } - if (net_debug && version_printed++ == 0) - printk(version); - - printk("%s: 3c507 at %#x,", dev->name, ioaddr); + pr_info("%s: 3c507 at %#x,", dev->name, ioaddr); /* We should make a few more checks here, like the first three octets of the S.A. for the manufacturer's code. */ @@ -403,7 +400,8 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) irqval = request_irq(irq, &el16_interrupt, 0, DRV_NAME, dev); if (irqval) { - printk(KERN_ERR "3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval); + pr_cont("\n"); + pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval); retval = -EAGAIN; goto out; } @@ -414,7 +412,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) outb(0x01, ioaddr + MISC_CTRL); for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %pM", dev->dev_addr); + pr_cont(" %pM", dev->dev_addr); if (mem_start) net_debug = mem_start & 7; @@ -443,18 +441,18 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0; dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f; - printk(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq, + pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq, dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1); if (net_debug) - printk(version); + pr_debug("%s", version); lp = netdev_priv(dev); memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); lp->base = ioremap(dev->mem_start, RX_BUF_END); if (!lp->base) { - printk(KERN_ERR "3c507: unable to remap memory\n"); + pr_err("3c507: unable to remap memory\n"); retval = -EAGAIN; goto out1; } @@ -488,20 +486,20 @@ static void el16_tx_timeout (struct net_device *dev) void __iomem *shmem = lp->base; if (net_debug > 1) - printk ("%s: transmit timed out, %s? ", dev->name, + pr_debug("%s: transmit timed out, %s? ", dev->name, readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ if (lp->last_restart == dev->stats.tx_packets) { if (net_debug > 1) - printk ("Resetting board.\n"); + pr_cont("Resetting board.\n"); /* Completely reset the adaptor. */ init_82586_mem (dev); lp->tx_pkts_in_ring = 0; } else { /* Issue the channel attention signal and hope it "gets better". */ if (net_debug > 1) - printk ("Kicking board.\n"); + pr_cont("Kicking board.\n"); writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD); outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */ lp->last_restart = dev->stats.tx_packets; @@ -553,7 +551,8 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) void __iomem *shmem; if (dev == NULL) { - printk ("net_interrupt(): irq %d for unknown device.\n", irq); + pr_err("%s: net_interrupt(): irq %d for unknown device.\n", + dev->name, irq); return IRQ_NONE; } @@ -566,7 +565,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) status = readw(shmem+iSCB_STATUS); if (net_debug > 4) { - printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); + pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); } /* Disable the 82586's input to the interrupt line. */ @@ -577,7 +576,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) unsigned short tx_status = readw(shmem+lp->tx_reap); if (!(tx_status & 0x8000)) { if (net_debug > 5) - printk("Tx command incomplete (%#x).\n", lp->tx_reap); + pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap); break; } /* Tx unsuccessful or some interesting status bit set. */ @@ -591,7 +590,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) } dev->stats.tx_packets++; if (net_debug > 5) - printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); + pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); lp->tx_reap += TX_BUF_SIZE; if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE) lp->tx_reap = TX_BUF_START; @@ -606,7 +605,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) if (status & 0x4000) { /* Packet received. */ if (net_debug > 5) - printk("Received packet, rx_head %04x.\n", lp->rx_head); + pr_debug("Received packet, rx_head %04x.\n", lp->rx_head); el16_rx(dev); } @@ -615,7 +614,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) if ((status & 0x0700) != 0x0200 && netif_running(dev)) { if (net_debug) - printk("%s: Command unit stopped, status %04x, restarting.\n", + pr_debug("%s: Command unit stopped, status %04x, restarting.\n", dev->name, status); /* If this ever occurs we should really re-write the idle loop, reset the Tx list, and do a complete restart of the command unit. @@ -627,7 +626,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ if (net_debug) - printk("%s: Rx unit stopped, status %04x, restarting.\n", + pr_debug("%s: Rx unit stopped, status %04x, restarting.\n", dev->name, status); init_rx_bufs(dev); writew(RX_BUF_START,shmem+iSCB_RFA); @@ -753,9 +752,8 @@ static void init_82586_mem(struct net_device *dev) int boguscnt = 50; while (readw(shmem+iSCB_STATUS) == 0) if (--boguscnt == 0) { - printk("%s: i82586 initialization timed out with status %04x, " - "cmd %04x.\n", dev->name, - readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD)); + pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n", + dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD)); break; } /* Issue channel-attn -- the 82586 won't start. */ @@ -765,7 +763,7 @@ static void init_82586_mem(struct net_device *dev) /* Disable loopback and enable interrupts. */ outb(0x84, ioaddr + MISC_CTRL); if (net_debug > 4) - printk("%s: Initialized 82586, status %04x.\n", dev->name, + pr_debug("%s: Initialized 82586, status %04x.\n", dev->name, readw(shmem+iSCB_STATUS)); return; } @@ -810,7 +808,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length lp->tx_head = TX_BUF_START; if (net_debug > 4) { - printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", + pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", dev->name, ioaddr, length, tx_block, lp->tx_head); } @@ -838,7 +836,7 @@ static void el16_rx(struct net_device *dev) if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 || (pkt_len & 0xC000) != 0xC000) { - printk(KERN_ERR "%s: Rx frame at %#x corrupted, " + pr_err("%s: Rx frame at %#x corrupted, " "status %04x cmd %04x next %04x " "data-buf @%04x %04x.\n", dev->name, rx_head, frame_status, rfd_cmd, @@ -858,8 +856,7 @@ static void el16_rx(struct net_device *dev) pkt_len &= 0x3fff; skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { - printk(KERN_ERR "%s: Memory squeeze, " - "dropping packet.\n", + pr_err("%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; break; @@ -926,7 +923,7 @@ MODULE_PARM_DESC(irq, "(ignored)"); int __init init_module(void) { if (io == 0) - printk("3c507: You should not use auto-probing with insmod!\n"); + pr_notice("3c507: You should not use auto-probing with insmod!\n"); dev_3c507 = el16_probe(-1); return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0; } diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 393e4e7..8d9aa49 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -257,7 +257,7 @@ static int el3_isa_id_sequence(__be16 *phys_addr) && !memcmp(phys_addr, el3_devs[i]->dev_addr, ETH_ALEN)) { if (el3_debug > 3) - printk(KERN_DEBUG "3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", + pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", phys_addr[0] & 0xff, phys_addr[0] >> 8, phys_addr[1] & 0xff, phys_addr[1] >> 8, phys_addr[2] & 0xff, phys_addr[2] >> 8); @@ -574,19 +574,18 @@ static int __devinit el3_common_init(struct net_device *dev) err = register_netdev(dev); if (err) { - printk(KERN_ERR "Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n", + pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n", dev->base_addr, dev->irq); release_region(dev->base_addr, EL3_IO_EXTENT); return err; } - printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, " - "address %pM, IRQ %d.\n", + pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n", dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], dev->dev_addr, dev->irq); if (el3_debug > 0) - printk(KERN_INFO "%s", version); + pr_info("%s", version); return 0; } @@ -625,8 +624,8 @@ static int __init el3_mca_probe(struct device *device) irq = pos5 & 0x0f; - printk(KERN_INFO "3c529: found %s at slot %d\n", - el3_mca_adapter_names[mdev->index], slot + 1); + pr_info("3c529: found %s at slot %d\n", + el3_mca_adapter_names[mdev->index], slot + 1); /* claim the slot */ strncpy(mdev->name, el3_mca_adapter_names[mdev->index], @@ -638,7 +637,7 @@ static int __init el3_mca_probe(struct device *device) irq = mca_device_transform_irq(mdev, irq); ioaddr = mca_device_transform_ioport(mdev, ioaddr); if (el3_debug > 2) { - printk(KERN_DEBUG "3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); + pr_debug("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); } EL3WINDOW(0); for (i = 0; i < 3; i++) @@ -761,7 +760,7 @@ static ushort id_read_eeprom(int index) word = (word << 1) + (inb(id_port) & 0x01); if (el3_debug > 3) - printk(KERN_DEBUG " 3c509 EEPROM word %d %#4.4x.\n", index, word); + pr_debug(" 3c509 EEPROM word %d %#4.4x.\n", index, word); return word; } @@ -783,13 +782,13 @@ el3_open(struct net_device *dev) EL3WINDOW(0); if (el3_debug > 3) - printk(KERN_DEBUG "%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, + pr_debug("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS)); el3_up(dev); if (el3_debug > 3) - printk(KERN_DEBUG "%s: Opened 3c509 IRQ %d status %4.4x.\n", + pr_debug("%s: Opened 3c509 IRQ %d status %4.4x.\n", dev->name, dev->irq, inw(ioaddr + EL3_STATUS)); return 0; @@ -801,8 +800,7 @@ el3_tx_timeout (struct net_device *dev) int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ - printk(KERN_WARNING "%s: transmit timed out, Tx_status %2.2x status %4.4x " - "Tx FIFO room %d.\n", + pr_warning("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d.\n", dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), inw(ioaddr + TX_FREE)); dev->stats.tx_errors++; @@ -826,7 +824,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; if (el3_debug > 4) { - printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n", + pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n", dev->name, skb->len, inw(ioaddr + EL3_STATUS)); } #if 0 @@ -835,7 +833,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) ushort status = inw(ioaddr + EL3_STATUS); if (status & 0x0001 /* IRQ line active, missed one. */ && inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */ - printk(KERN_DEBUG "%s: Missed interrupt, status then %04x now %04x" + pr_debug("%s: Missed interrupt, status then %04x now %04x" " Tx %2.2x Rx %4.4x.\n", dev->name, status, inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS), inw(ioaddr + RX_STATUS)); @@ -909,7 +907,7 @@ el3_interrupt(int irq, void *dev_id) if (el3_debug > 4) { status = inw(ioaddr + EL3_STATUS); - printk(KERN_DEBUG "%s: interrupt, status %4.4x.\n", dev->name, status); + pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status); } while ((status = inw(ioaddr + EL3_STATUS)) & @@ -920,7 +918,7 @@ el3_interrupt(int irq, void *dev_id) if (status & TxAvailable) { if (el3_debug > 5) - printk(KERN_DEBUG " TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue (dev); @@ -958,7 +956,7 @@ el3_interrupt(int irq, void *dev_id) } if (--i < 0) { - printk(KERN_ERR "%s: Infinite loop in interrupt, status %4.4x.\n", + pr_err("%s: Infinite loop in interrupt, status %4.4x.\n", dev->name, status); /* Clear all interrupts. */ outw(AckIntr | 0xFF, ioaddr + EL3_CMD); @@ -969,7 +967,7 @@ el3_interrupt(int irq, void *dev_id) } if (el3_debug > 4) { - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); } spin_unlock(&lp->lock); @@ -1017,7 +1015,7 @@ static void update_stats(struct net_device *dev) int ioaddr = dev->base_addr; if (el3_debug > 5) - printk(" Updating the statistics.\n"); + pr_debug(" Updating the statistics.\n"); /* Turn off statistics updates while reading. */ outw(StatsDisable, ioaddr + EL3_CMD); /* Switch to the stats window, and read everything. */ @@ -1047,7 +1045,7 @@ el3_rx(struct net_device *dev) short rx_status; if (el3_debug > 5) - printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", + pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ @@ -1069,7 +1067,7 @@ el3_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len+5); if (el3_debug > 4) - printk("Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte */ @@ -1088,12 +1086,12 @@ el3_rx(struct net_device *dev) outw(RxDiscard, ioaddr + EL3_CMD); dev->stats.rx_dropped++; if (el3_debug) - printk("%s: Couldn't allocate a sk_buff of size %d.\n", + pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } inw(ioaddr + EL3_STATUS); /* Delay. */ while (inw(ioaddr + EL3_STATUS) & 0x1000) - printk(KERN_DEBUG " Waiting for 3c509 to discard packet, status %x.\n", + pr_debug(" Waiting for 3c509 to discard packet, status %x.\n", inw(ioaddr + EL3_STATUS) ); } @@ -1114,7 +1112,7 @@ set_multicast_list(struct net_device *dev) static int old; if (old != dev->mc_count) { old = dev->mc_count; - printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); + pr_debug("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); } } spin_lock_irqsave(&lp->lock, flags); @@ -1137,7 +1135,7 @@ el3_close(struct net_device *dev) struct el3_private *lp = netdev_priv(dev); if (el3_debug > 2) - printk("%s: Shutting down ethercard.\n", dev->name); + pr_debug("%s: Shutting down ethercard.\n", dev->name); el3_down(dev); @@ -1384,30 +1382,30 @@ el3_up(struct net_device *dev) EL3WINDOW(4); net_diag = inw(ioaddr + WN4_NETDIAG); net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */ - printk("%s: ", dev->name); + pr_info("%s: ", dev->name); switch (dev->if_port & 0x0c) { case 12: /* force full-duplex mode if 3c5x9b */ if (sw_info & 0x000f) { - printk("Forcing 3c5x9b full-duplex mode"); + pr_cont("Forcing 3c5x9b full-duplex mode"); break; } case 8: /* set full-duplex mode based on eeprom config setting */ if ((sw_info & 0x000f) && (sw_info & 0x8000)) { - printk("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)"); + pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)"); break; } default: /* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */ - printk("Setting 3c5x9/3c5x9B half-duplex mode"); + pr_cont("Setting 3c5x9/3c5x9B half-duplex mode"); net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */ } outw(net_diag, ioaddr + WN4_NETDIAG); - printk(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); + pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); if (el3_debug > 3) - printk("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag); + pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag); /* Enable link beat and jabber check. */ outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); } @@ -1535,7 +1533,7 @@ static int __init el3_init_module(void) } if (id_port >= 0x200) { id_port = 0; - printk(KERN_ERR "No I/O port available for 3c509 activation.\n"); + pr_err("No I/O port available for 3c509 activation.\n"); } else { ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS); if (!ret) -- cgit v0.10.2 From 39738e161f7315bfa8f31a91d2262f93d818a7cd Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Tue, 26 May 2009 12:35:26 +0000 Subject: 3c5xx: convert printk() to pr_() Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 167bf23..7fd0ff7 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -420,7 +420,7 @@ int init_module(void) if (debug >= 0) corkscrew_debug = debug; if (corkscrew_debug) - printk(version); + pr_debug("%s", version); while (corkscrew_scan(-1)) found++; return found ? 0 : -ENODEV; @@ -437,7 +437,7 @@ struct net_device *tc515_probe(int unit) if (corkscrew_debug > 0 && !printed) { printed = 1; - printk(version); + pr_debug("%s", version); } return dev; @@ -516,7 +516,7 @@ static struct net_device *corkscrew_scan(int unit) if (pnp_device_attach(idev) < 0) continue; if (pnp_activate_dev(idev) < 0) { - printk("pnp activate failed (out of resources?)\n"); + pr_warning("pnp activate failed (out of resources?)\n"); pnp_device_detach(idev); continue; } @@ -531,9 +531,9 @@ static struct net_device *corkscrew_scan(int unit) continue; } if(corkscrew_debug) - printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", + pr_debug("ISAPNP reports %s at i/o 0x%x, irq %d\n", (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); - printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", + pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ SET_NETDEV_DEV(dev, &idev->dev); @@ -552,7 +552,7 @@ no_pnp: if (!check_device(ioaddr)) continue; - printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", + pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); err = corkscrew_setup(dev, ioaddr, NULL, cards_found++); if (!err) @@ -625,7 +625,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, list_add(&vp->list, &root_corkscrew_dev); #endif - printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); + pr_info("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); spin_lock_init(&vp->lock); @@ -648,19 +648,19 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, } checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) - printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - printk(" %pM", dev->dev_addr); + pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); + pr_cont(" %pM", dev->dev_addr); if (eeprom[16] == 0x11c7) { /* Corkscrew */ if (request_dma(dev->dma, "3c515")) { - printk(", DMA %d allocation failed", dev->dma); + pr_cont(", DMA %d allocation failed", dev->dma); dev->dma = 0; } else - printk(", DMA %d", dev->dma); + pr_cont(", DMA %d", dev->dma); } - printk(", IRQ %d\n", dev->irq); + pr_cont(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15)) - printk(KERN_WARNING " *** Warning: this IRQ is unlikely to work! ***\n"); + pr_warning(" *** Warning: this IRQ is unlikely to work! ***\n"); { char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" }; @@ -669,9 +669,9 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, vp->available_media = inw(ioaddr + Wn3_Options); config = inl(ioaddr + Wn3_Config); if (corkscrew_debug > 1) - printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n", + pr_info(" Internal config register is %4.4x, transceivers %#x.\n", config, inw(ioaddr + Wn3_Options)); - printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", + pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", 8 << config & Ram_size, config & Ram_width ? "word" : "byte", ram_split[(config & Ram_split) >> Ram_split_shift], @@ -682,7 +682,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, dev->if_port = vp->default_media; } if (vp->media_override != 7) { - printk(KERN_INFO " Media override to transceiver type %d (%s).\n", + pr_info(" Media override to transceiver type %d (%s).\n", vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; @@ -718,7 +718,7 @@ static int corkscrew_open(struct net_device *dev) if (vp->media_override != 7) { if (corkscrew_debug > 1) - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", + pr_info("%s: Media override to transceiver %d (%s).\n", dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; @@ -729,7 +729,7 @@ static int corkscrew_open(struct net_device *dev) dev->if_port = media_tbl[dev->if_port].next; if (corkscrew_debug > 1) - printk("%s: Initial media type %s.\n", + pr_debug("%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); init_timer(&vp->timer); @@ -744,7 +744,7 @@ static int corkscrew_open(struct net_device *dev) outl(config, ioaddr + Wn3_Config); if (corkscrew_debug > 1) { - printk("%s: corkscrew_open() InternalConfig %8.8x.\n", + pr_debug("%s: corkscrew_open() InternalConfig %8.8x.\n", dev->name, config); } @@ -777,7 +777,7 @@ static int corkscrew_open(struct net_device *dev) if (corkscrew_debug > 1) { EL3WINDOW(4); - printk("%s: corkscrew_open() irq %d media status %4.4x.\n", + pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n", dev->name, dev->irq, inw(ioaddr + Wn4_Media)); } @@ -814,8 +814,7 @@ static int corkscrew_open(struct net_device *dev) if (vp->full_bus_master_rx) { /* Boomerang bus master. */ vp->cur_rx = vp->dirty_rx = 0; if (corkscrew_debug > 2) - printk("%s: Filling in the Rx ring.\n", - dev->name); + pr_debug("%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; if (i < (RX_RING_SIZE - 1)) @@ -877,7 +876,7 @@ static void corkscrew_timer(unsigned long data) int ok = 0; if (corkscrew_debug > 1) - printk("%s: Media selection timer tick happened, %s.\n", + pr_debug("%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); spin_lock_irqsave(&vp->lock, flags); @@ -894,12 +893,12 @@ static void corkscrew_timer(unsigned long data) if (media_status & Media_LnkBeat) { ok = 1; if (corkscrew_debug > 1) - printk("%s: Media %s has link beat, %x.\n", + pr_debug("%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } else if (corkscrew_debug > 1) - printk("%s: Media %s is has no link beat, %x.\n", + pr_debug("%s: Media %s is has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); @@ -907,7 +906,7 @@ static void corkscrew_timer(unsigned long data) break; default: /* Other media types handled by Tx timeouts. */ if (corkscrew_debug > 1) - printk("%s: Media %s is has no indication, %x.\n", + pr_debug("%s: Media %s is has no indication, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); @@ -925,12 +924,12 @@ static void corkscrew_timer(unsigned long data) if (dev->if_port == 8) { /* Go back to default. */ dev->if_port = vp->default_media; if (corkscrew_debug > 1) - printk("%s: Media selection failing, using default %s port.\n", + pr_debug("%s: Media selection failing, using default %s port.\n", dev->name, media_tbl[dev->if_port].name); } else { if (corkscrew_debug > 1) - printk("%s: Media selection failed, now trying %s port.\n", + pr_debug("%s: Media selection failed, now trying %s port.\n", dev->name, media_tbl[dev->if_port].name); vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; @@ -953,7 +952,7 @@ static void corkscrew_timer(unsigned long data) spin_unlock_irqrestore(&vp->lock, flags); if (corkscrew_debug > 1) - printk("%s: Media selection timer finished, %s.\n", + pr_debug("%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); #endif /* AUTOMEDIA */ @@ -966,23 +965,21 @@ static void corkscrew_timeout(struct net_device *dev) struct corkscrew_private *vp = netdev_priv(dev); int ioaddr = dev->base_addr; - printk(KERN_WARNING - "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + pr_warning("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); /* Slight code bloat to be user friendly. */ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) - printk(KERN_WARNING - "%s: Transmitter encountered 16 collisions -- network" + pr_warning("%s: Transmitter encountered 16 collisions --" " network cable problem?\n", dev->name); #ifndef final_version - printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n", + pr_debug(" Flags; bus-master %d, full %d; dirty %d current %d.\n", vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx); - printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), + pr_debug(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), &vp->tx_ring[0]); for (i = 0; i < TX_RING_SIZE; i++) { - printk(" %d: %p length %8.8x status %8.8x\n", i, + pr_debug(" %d: %p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], vp->tx_ring[i].length, vp->tx_ring[i].status); } @@ -1023,7 +1020,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, else prev_entry = NULL; if (corkscrew_debug > 3) - printk("%s: Trying to send a packet, Tx index %d.\n", + pr_debug("%s: Trying to send a packet, Tx index %d.\n", dev->name, vp->cur_tx); /* vp->tx_full = 1; */ vp->tx_skbuff[entry] = skb; @@ -1102,7 +1099,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (corkscrew_debug > 2) - printk("%s: Tx error, status %2.2x.\n", + pr_debug("%s: Tx error, status %2.2x.\n", dev->name, tx_status); if (tx_status & 0x04) dev->stats.tx_fifo_errors++; @@ -1143,7 +1140,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) status = inw(ioaddr + EL3_STATUS); if (corkscrew_debug > 4) - printk("%s: interrupt, status %4.4x, timer %d.\n", + pr_debug("%s: interrupt, status %4.4x, timer %d.\n", dev->name, status, latency); if ((status & 0xE000) != 0xE000) { static int donedidthis; @@ -1151,7 +1148,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) Ignore a single early interrupt, but don't hang the machine for other interrupt problems. */ if (donedidthis++ > 100) { - printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", + pr_err("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", dev->name, status, netif_running(dev)); free_irq(dev->irq, dev); dev->irq = -1; @@ -1160,14 +1157,14 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) do { if (corkscrew_debug > 5) - printk("%s: In interrupt loop, status %4.4x.\n", + pr_debug("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & RxComplete) corkscrew_rx(dev); if (status & TxAvailable) { if (corkscrew_debug > 5) - printk(" TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue(dev); @@ -1212,19 +1209,20 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat; if (corkscrew_debug > 4) - printk("%s: Updating stats.\n", dev->name); + pr_debug("%s: Updating stats.\n", dev->name); update_stats(ioaddr, dev); /* DEBUG HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) { int win, reg; - printk("%s: Updating stats failed, disabling stats as an" - " interrupt source.\n", dev->name); + pr_notice("%s: Updating stats failed, disabling stats as an interrupt source.\n", + dev->name); for (win = 0; win < 8; win++) { EL3WINDOW(win); - printk("\n Vortex window %d:", win); + pr_notice("Vortex window %d:", win); for (reg = 0; reg < 16; reg++) - printk(" %2.2x", inb(ioaddr + reg)); + pr_cont(" %2.2x", inb(ioaddr + reg)); + pr_cont("\n"); } EL3WINDOW(7); outw(SetIntrEnb | TxAvailable | @@ -1246,9 +1244,8 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) } if (--i < 0) { - printk(KERN_ERR "%s: Too much work in interrupt, status %4.4x. " - "Disabling functions (%4.4x).\n", dev->name, - status, SetStatusEnb | ((~status) & 0x7FE)); + pr_err("%s: Too much work in interrupt, status %4.4x. Disabling functions (%4.4x).\n", + dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); /* Disable all pending interrupts. */ outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); @@ -1262,7 +1259,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) spin_unlock(&lp->lock); if (corkscrew_debug > 4) - printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status); + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); return IRQ_HANDLED; } @@ -1273,13 +1270,13 @@ static int corkscrew_rx(struct net_device *dev) short rx_status; if (corkscrew_debug > 5) - printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", + pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); while ((rx_status = inw(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ unsigned char rx_error = inb(ioaddr + RxErrors); if (corkscrew_debug > 2) - printk(" Rx error: status %2.2x.\n", + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) @@ -1299,7 +1296,7 @@ static int corkscrew_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len + 5 + 2); if (corkscrew_debug > 4) - printk("Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ @@ -1318,7 +1315,7 @@ static int corkscrew_rx(struct net_device *dev) break; continue; } else if (corkscrew_debug) - printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); + pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } outw(RxDiscard, ioaddr + EL3_CMD); dev->stats.rx_dropped++; @@ -1338,13 +1335,13 @@ static int boomerang_rx(struct net_device *dev) int rx_status; if (corkscrew_debug > 5) - printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", + pr_debug(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) { if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; if (corkscrew_debug > 2) - printk(" Rx error: status %2.2x.\n", + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) @@ -1364,7 +1361,7 @@ static int boomerang_rx(struct net_device *dev) dev->stats.rx_bytes += pkt_len; if (corkscrew_debug > 4) - printk("Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); /* Check if the packet is long enough to just accept without @@ -1385,7 +1382,7 @@ static int boomerang_rx(struct net_device *dev) temp = skb_put(skb, pkt_len); /* Remove this checking code for final release. */ if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp) - printk("%s: Warning -- the skbuff addresses do not match" + pr_warning("%s: Warning -- the skbuff addresses do not match" " in boomerang_rx: %p vs. %p / %p.\n", dev->name, isa_bus_to_virt(vp-> @@ -1427,12 +1424,11 @@ static int corkscrew_close(struct net_device *dev) netif_stop_queue(dev); if (corkscrew_debug > 1) { - printk("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n", + pr_debug("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n", dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); - printk("%s: corkscrew close stats: rx_nocopy %d rx_copy %d" - " tx_queued %d.\n", dev->name, rx_nocopy, rx_copy, - queued_packet); + pr_debug("%s: corkscrew close stats: rx_nocopy %d rx_copy %d tx_queued %d.\n", + dev->name, rx_nocopy, rx_copy, queued_packet); } del_timer(&vp->timer); @@ -1534,7 +1530,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { if (corkscrew_debug > 3) - printk("%s: Setting promiscuous mode.\n", + pr_debug("%s: Setting promiscuous mode.\n", dev->name); new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm; } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 8f734d7..cdd955c 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -176,7 +176,7 @@ sizeof(nop_cmd) = 8; if(!p->scb->cmd) break; \ DELAY_16(); \ if(i == 1023) { \ - printk(KERN_WARNING "%s:%d: scb_cmd timed out .. resetting i82586\n",\ + pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\ dev->name,__LINE__); \ elmc_id_reset586(); } } } @@ -291,7 +291,7 @@ static int elmc_open(struct net_device *dev) ret = request_irq(dev->irq, &elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); if (ret) { - printk(KERN_ERR "%s: couldn't get irq %d\n", dev->name, dev->irq); + pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq); elmc_id_reset586(); return ret; } @@ -371,9 +371,9 @@ static void alloc586(struct net_device *dev) DELAY(2); - if (p->iscp->busy) { - printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name); - } + if (p->iscp->busy) + pr_err("%s: Init-Problems (alloc).\n", dev->name); + memset((char *) p->scb, 0, sizeof(struct scb_struct)); } @@ -470,7 +470,7 @@ static int __init do_elmc_probe(struct net_device *dev) mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev); /* if we get this far, adapter has been found - carry on */ - printk(KERN_INFO "%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1); + pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1); /* Now we extract configuration info from the card. The 3c523 provides information in two of the POS registers, but @@ -507,7 +507,7 @@ static int __init do_elmc_probe(struct net_device *dev) memset(pr, 0, sizeof(struct priv)); pr->slot = slot; - printk(KERN_INFO "%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, + pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, dev->base_addr); /* Determine if we're using the on-board transceiver (i.e. coax) or @@ -529,7 +529,7 @@ static int __init do_elmc_probe(struct net_device *dev) size = 0x4000; /* check for 16K mem */ if (!check586(dev, dev->mem_start, size)) { - printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, + pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, dev->mem_start); retval = -ENODEV; goto err_out; @@ -546,7 +546,7 @@ static int __init do_elmc_probe(struct net_device *dev) pr->num_recv_buffs = NUM_RECV_BUFFS_16; /* dump all the assorted information */ - printk(KERN_INFO "%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name, + pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name, dev->irq, dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end - 1); @@ -555,7 +555,7 @@ static int __init do_elmc_probe(struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(dev->base_addr + i); - printk(KERN_INFO "%s: hardware address %pM\n", + pr_info("%s: hardware address %pM\n", dev->name, dev->dev_addr); dev->netdev_ops = &netdev_ops; @@ -660,7 +660,7 @@ static int init586(struct net_device *dev) } if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) { - printk(KERN_WARNING "%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status); + pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status); return 1; } /* @@ -686,7 +686,8 @@ static int init586(struct net_device *dev) } if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) { - printk(KERN_WARNING "%s (elmc): individual address setup command failed: %04x\n", dev->name, ias_cmd->cmd_status); + pr_warning("%s (elmc): individual address setup command failed: %04x\n", + dev->name, ias_cmd->cmd_status); return 1; } /* @@ -707,7 +708,7 @@ static int init586(struct net_device *dev) s = jiffies; while (!(tdr_cmd->cmd_status & STAT_COMPL)) { if (time_after(jiffies, s + 30*HZ/100)) { - printk(KERN_WARNING "%s: %d Problems while running the TDR.\n", dev->name, __LINE__); + pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__); result = 1; break; } @@ -723,14 +724,14 @@ static int init586(struct net_device *dev) if (result & TDR_LNK_OK) { /* empty */ } else if (result & TDR_XCVR_PRB) { - printk(KERN_WARNING "%s: TDR: Transceiver problem!\n", dev->name); + pr_warning("%s: TDR: Transceiver problem!\n", dev->name); } else if (result & TDR_ET_OPN) { - printk(KERN_WARNING "%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK); + pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK); } else if (result & TDR_ET_SRT) { if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */ - printk(KERN_WARNING "%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK); + pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK); } else { - printk(KERN_WARNING "%s: TDR: Unknown status %04x\n", dev->name, result); + pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result); } } /* @@ -774,11 +775,11 @@ static int init586(struct net_device *dev) /* I don't understand this: do we really need memory after the init? */ int len = ((char *) p->iscp - (char *) ptr - 8) / 6; if (len <= 0) { - printk(KERN_ERR "%s: Ooooops, no memory for MC-Setup!\n", dev->name); + pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name); } else { if (len < num_addrs) { num_addrs = len; - printk(KERN_WARNING "%s: Sorry, can only apply %d MC-Address(es).\n", + pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n", dev->name, num_addrs); } mc_cmd = (struct mcsetup_cmd_struct *) ptr; @@ -799,7 +800,7 @@ static int init586(struct net_device *dev) break; } if (!(mc_cmd->cmd_status & STAT_COMPL)) { - printk(KERN_WARNING "%s: Can't apply multicast-address-list.\n", dev->name); + pr_warning("%s: Can't apply multicast-address-list.\n", dev->name); } } } @@ -812,7 +813,7 @@ static int init586(struct net_device *dev) p->xmit_buffs[i] = (struct tbd_struct *) ptr; /* TBD */ ptr = (char *) ptr + sizeof(struct tbd_struct); if ((void *) ptr > (void *) p->iscp) { - printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n", dev->name); + pr_err("%s: not enough shared-mem for your configuration!\n", dev->name); return 1; } memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct)); @@ -936,7 +937,8 @@ elmc_interrupt(int irq, void *dev_id) if (stat & STAT_CNA) { /* CU went 'not ready' */ if (netif_running(dev)) { - printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); + pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n", + dev->name, (int) stat, (int) p->scb->status); } } #endif @@ -951,7 +953,8 @@ elmc_interrupt(int irq, void *dev_id) p->scb->cmd = RUC_RESUME; elmc_attn586(); } else { - printk(KERN_WARNING "%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); + pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", + dev->name, (int) stat, (int) p->scb->status); elmc_rnr_int(dev); } } @@ -995,11 +998,11 @@ static void elmc_rcv_int(struct net_device *dev) dev->stats.rx_dropped++; } } else { - printk(KERN_WARNING "%s: received oversized frame.\n", dev->name); + pr_warning("%s: received oversized frame.\n", dev->name); dev->stats.rx_dropped++; } } else { /* frame !(ok), only with 'save-bad-frames' */ - printk(KERN_WARNING "%s: oops! rfd-error-status: %04x\n", dev->name, status); + pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status); dev->stats.rx_errors++; } p->rfd_top->status = 0; @@ -1028,7 +1031,7 @@ static void elmc_rnr_int(struct net_device *dev) alloc_rfa(dev, (char *) p->rfd_first); startrecv586(dev); /* restart RU */ - printk(KERN_WARNING "%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status); + pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status); } @@ -1043,7 +1046,7 @@ static void elmc_xmt_int(struct net_device *dev) status = p->xmit_cmds[p->xmit_last]->cmd_status; if (!(status & STAT_COMPL)) { - printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); + pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); } if (status & STAT_OK) { dev->stats.tx_packets++; @@ -1051,18 +1054,18 @@ static void elmc_xmt_int(struct net_device *dev) } else { dev->stats.tx_errors++; if (status & TCMD_LATECOLL) { - printk(KERN_WARNING "%s: late collision detected.\n", dev->name); + pr_warning("%s: late collision detected.\n", dev->name); dev->stats.collisions++; } else if (status & TCMD_NOCARRIER) { dev->stats.tx_carrier_errors++; - printk(KERN_WARNING "%s: no carrier detected.\n", dev->name); + pr_warning("%s: no carrier detected.\n", dev->name); } else if (status & TCMD_LOSTCTS) { - printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name); + pr_warning("%s: loss of CTS detected.\n", dev->name); } else if (status & TCMD_UNDERRUN) { dev->stats.tx_fifo_errors++; - printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name); + pr_warning("%s: DMA underrun detected.\n", dev->name); } else if (status & TCMD_MAXCOLL) { - printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name); + pr_warning("%s: Max. collisions exceeded.\n", dev->name); dev->stats.collisions += 16; } } @@ -1099,10 +1102,11 @@ static void elmc_timeout(struct net_device *dev) struct priv *p = netdev_priv(dev); /* COMMAND-UNIT active? */ if (p->scb->status & CU_ACTIVE) { -#ifdef DEBUG - printk("%s: strange ... timeout with CU active?!?\n", dev->name); - printk("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, (int) p->xmit_cmds[0]->cmd_status, (int) p->nop_cmds[0]->cmd_status, (int) p->nop_cmds[1]->cmd_status, (int) p->nop_point); -#endif + pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name); + pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, + (int)p->xmit_cmds[0]->cmd_status, + (int)p->nop_cmds[0]->cmd_status, + (int)p->nop_cmds[1]->cmd_status, (int)p->nop_point); p->scb->cmd = CUC_ABORT; elmc_attn586(); WAIT_4_SCB_CMD(); @@ -1112,10 +1116,10 @@ static void elmc_timeout(struct net_device *dev) WAIT_4_SCB_CMD(); netif_wake_queue(dev); } else { -#ifdef DEBUG - printk("%s: xmitter timed out, try to restart! stat: %04x\n", dev->name, p->scb->status); - printk("%s: command-stats: %04x %04x\n", dev->name, p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status); -#endif + pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n", + dev->name, p->scb->status); + pr_debug("%s: command-stats: %04x %04x\n", dev->name, + p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status); elmc_close(dev); elmc_open(dev); } @@ -1162,7 +1166,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) break; } if (i == 15) { - printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name); + pr_warning("%s: Can't start transmit-command.\n", dev->name); } } #else @@ -1287,11 +1291,12 @@ int __init init_module(void) free_netdev(dev); if (io[this_dev]==0) break; - printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); + pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); } if(found==0) { - if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n"); + if (io[0]==0) + pr_notice("3c523.c: No 3c523 cards found\n"); return -ENXIO; } else return 0; } diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index b61073c..c10ca30 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -125,8 +125,6 @@ static const char* cardname = DRV_NAME; #define NET_DEBUG 2 #endif -#undef DEBUG_IRQ - static unsigned int mc32_debug = NET_DEBUG; /* The number of low I/O ports used by the ethercard. */ @@ -351,15 +349,15 @@ static int __init mc32_probe1(struct net_device *dev, int slot) /* Time to play MCA games */ if (mc32_debug && version_printed++ == 0) - printk(KERN_DEBUG "%s", version); + pr_debug("%s", version); - printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot); + pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot); POS = mca_read_stored_pos(slot, 2); if(!(POS&1)) { - printk(" disabled.\n"); + pr_cont("disabled.\n"); return -ENODEV; } @@ -370,7 +368,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) POS = mca_read_stored_pos(slot, 4); if(!(POS&1)) { - printk("memory window disabled.\n"); + pr_cont("memory window disabled.\n"); return -ENODEV; } @@ -379,7 +377,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) i=(POS>>4)&3; if(i==3) { - printk("invalid memory window.\n"); + pr_cont("invalid memory window.\n"); return -ENODEV; } @@ -392,11 +390,11 @@ static int __init mc32_probe1(struct net_device *dev, int slot) if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname)) { - printk("io 0x%3lX, which is busy.\n", dev->base_addr); + pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr); return -EBUSY; } - printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n", + pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n", dev->base_addr, dev->irq, dev->mem_start, i/1024); @@ -416,7 +414,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) dev->dev_addr[i] = mca_read_pos(slot,3); } - printk("%s: Address %pM", dev->name, dev->dev_addr); + pr_info("%s: Address %pM ", dev->name, dev->dev_addr); mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); @@ -424,9 +422,9 @@ static int __init mc32_probe1(struct net_device *dev, int slot) POS = mca_read_stored_pos(slot, 4); if(POS&2) - printk(" : BNC port selected.\n"); + pr_cont(": BNC port selected.\n"); else - printk(" : AUI port selected.\n"); + pr_cont(": AUI port selected.\n"); POS=inb(dev->base_addr+HOST_CTRL); POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET; @@ -447,7 +445,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev); if (err) { release_region(dev->base_addr, MC32_IO_EXTENT); - printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); + pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); goto err_exit_ports; } @@ -463,7 +461,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) i++; if(i == 1000) { - printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); + pr_err("%s: failed to boot adapter.\n", dev->name); err = -ENODEV; goto err_exit_irq; } @@ -475,10 +473,10 @@ static int __init mc32_probe1(struct net_device *dev, int slot) if(base>0) { if(base < 0x0C) - printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1], + pr_err("%s: %s%s.\n", dev->name, failures[base-1], base<0x0A?" test failure":""); else - printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); + pr_err("%s: unknown failure %d.\n", dev->name, base); err = -ENODEV; goto err_exit_irq; } @@ -494,7 +492,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) udelay(50); if(n>100) { - printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); + pr_err("%s: mailbox read fail (%d).\n", dev->name, i); err = -ENODEV; goto err_exit_irq; } @@ -527,7 +525,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) init_completion(&lp->execution_cmd); init_completion(&lp->xceiver_cmd); - printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", + pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); dev->netdev_ops = &netdev_ops; @@ -939,7 +937,7 @@ static int mc32_open(struct net_device *dev) */ if(mc32_command(dev, 8, descnumbuffs, 4)) { - printk("%s: %s rejected our buffer configuration!\n", + pr_info("%s: %s rejected our buffer configuration!\n", dev->name, cardname); mc32_close(dev); return -ENOBUFS; @@ -995,7 +993,7 @@ static int mc32_open(struct net_device *dev) static void mc32_timeout(struct net_device *dev) { - printk(KERN_WARNING "%s: transmit timed out?\n", dev->name); + pr_warning("%s: transmit timed out?\n", dev->name); /* Try to restart the adaptor. */ netif_wake_queue(dev); } @@ -1335,11 +1333,9 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) { status=inb(ioaddr+HOST_CMD); -#ifdef DEBUG_IRQ - printk("Status TX%d RX%d EX%d OV%d BC%d\n", + pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n", (status&7), (status>>3)&7, (status>>6)&1, (status>>7)&1, boguscount); -#endif switch(status&7) { @@ -1354,7 +1350,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) complete(&lp->xceiver_cmd); break; default: - printk("%s: strange tx ack %d\n", dev->name, status&7); + pr_notice("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) @@ -1376,7 +1372,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) mc32_start_transceiver(dev); break; default: - printk("%s: strange rx ack %d\n", + pr_notice("%s: strange rx ack %d\n", dev->name, status&7); } status>>=3; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c566984..a6e8a2d 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -828,14 +828,14 @@ static int vortex_resume(struct pci_dev *pdev) pci_restore_state(pdev); err = pci_enable_device(pdev); if (err) { - printk(KERN_WARNING "%s: Could not enable device \n", + pr_warning("%s: Could not enable device\n", dev->name); return err; } pci_set_master(pdev); if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev)) { - printk(KERN_WARNING "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); + pr_warning("%s: Could not reserve IRQ %d\n", dev->name, dev->irq); pci_disable_device(pdev); return -EBUSY; } @@ -894,7 +894,7 @@ static int __devexit vortex_eisa_remove(struct device *device) dev = eisa_get_drvdata(edev); if (!dev) { - printk("vortex_eisa_remove called for Compaq device!\n"); + pr_err("vortex_eisa_remove called for Compaq device!\n"); BUG(); } @@ -1051,7 +1051,7 @@ static int __devinit vortex_probe1(struct device *gendev, struct eisa_device *edev = NULL; if (!printed_version) { - printk (version); + pr_info("%s", version); printed_version = 1; } @@ -1068,7 +1068,7 @@ static int __devinit vortex_probe1(struct device *gendev, dev = alloc_etherdev(sizeof(*vp)); retval = -ENOMEM; if (!dev) { - printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); + pr_err(PFX "unable to allocate etherdev, aborting\n"); goto out; } SET_NETDEV_DEV(dev, gendev); @@ -1100,9 +1100,9 @@ static int __devinit vortex_probe1(struct device *gendev, print_info = (vortex_debug > 1); if (print_info) - printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); + pr_info("See Documentation/networking/vortex.txt\n"); - printk(KERN_INFO "%s: 3Com %s %s at %p.\n", + pr_info("%s: 3Com %s %s at %p.\n", print_name, pdev ? "PCI" : "EISA", vci->name, @@ -1144,10 +1144,9 @@ static int __devinit vortex_probe1(struct device *gendev, chip only. */ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", + pr_info("%s: Overriding PCI latency timer (CFLT) setting of %d, new value is %d.\n", print_name, pci_latency, new_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); } } } @@ -1236,17 +1235,17 @@ static int __devinit vortex_probe1(struct device *gendev, checksum = (checksum ^ (checksum >> 8)) & 0xff; } if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) - printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); + pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) - printk(" %pM", dev->dev_addr); + pr_cont(" %pM", dev->dev_addr); /* Unfortunately an all zero eeprom passes the checksum and this gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) { retval = -EINVAL; - printk(KERN_ERR "*** EEPROM MAC address is invalid.\n"); + pr_err("*** EEPROM MAC address is invalid.\n"); goto free_ring; /* With every pack */ } EL3WINDOW(2); @@ -1254,17 +1253,17 @@ static int __devinit vortex_probe1(struct device *gendev, iowrite8(dev->dev_addr[i], ioaddr + i); if (print_info) - printk(", IRQ %d\n", dev->irq); + pr_cont(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (dev->irq <= 0 || dev->irq >= nr_irqs) - printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", + pr_warning(" *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); EL3WINDOW(4); step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; if (print_info) { - printk(KERN_INFO " product code %02x%02x rev %02x.%d date %02d-" - "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], + pr_info(" product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n", + eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); } @@ -1279,8 +1278,7 @@ static int __devinit vortex_probe1(struct device *gendev, } if (print_info) { - printk(KERN_INFO "%s: CardBus functions mapped " - "%16.16llx->%p\n", + pr_info("%s: CardBus functions mapped %16.16llx->%p\n", print_name, (unsigned long long)pci_resource_start(pdev, 2), vp->cb_fn_base); @@ -1307,7 +1305,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (vp->info1 & 0x8000) { vp->full_duplex = 1; if (print_info) - printk(KERN_INFO "Full duplex capable\n"); + pr_info("Full duplex capable\n"); } { @@ -1319,9 +1317,9 @@ static int __devinit vortex_probe1(struct device *gendev, vp->available_media = 0x40; config = ioread32(ioaddr + Wn3_Config); if (print_info) { - printk(KERN_DEBUG " Internal config register is %4.4x, " - "transceivers %#x.\n", config, ioread16(ioaddr + Wn3_Options)); - printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", + pr_debug(" Internal config register is %4.4x, transceivers %#x.\n", + config, ioread16(ioaddr + Wn3_Options)); + pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", 8 << RAM_SIZE(config), RAM_WIDTH(config) ? "word" : "byte", ram_split[RAM_SPLIT(config)], @@ -1336,7 +1334,7 @@ static int __devinit vortex_probe1(struct device *gendev, } if (vp->media_override != 7) { - printk(KERN_INFO "%s: Media override to transceiver type %d (%s).\n", + pr_info("%s: Media override to transceiver type %d (%s).\n", print_name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; @@ -1369,8 +1367,8 @@ static int __devinit vortex_probe1(struct device *gendev, if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; if (print_info) { - printk(KERN_INFO " MII transceiver found at address %d," - " status %4x.\n", phyx, mii_status); + pr_info(" MII transceiver found at address %d, status %4x.\n", + phyx, mii_status); } if ((mii_status & 0x0040) == 0) mii_preamble_required++; @@ -1378,7 +1376,7 @@ static int __devinit vortex_probe1(struct device *gendev, } mii_preamble_required--; if (phy_idx == 0) { - printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); + pr_warning(" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE); @@ -1394,7 +1392,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (vp->capabilities & CapBusMaster) { vp->full_bus_master_tx = 1; if (print_info) { - printk(KERN_INFO " Enabling bus-master transmits and %s receives.\n", + pr_info(" Enabling bus-master transmits and %s receives.\n", (vp->info2 & 1) ? "early" : "whole-frame" ); } vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; @@ -1414,7 +1412,7 @@ static int __devinit vortex_probe1(struct device *gendev, dev->netdev_ops = &vortex_netdev_ops; if (print_info) { - printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n", + pr_info("%s: scatter/gather %sabled. h/w checksums %sabled\n", print_name, (dev->features & NETIF_F_SG) ? "en":"dis", (dev->features & NETIF_F_IP_CSUM) ? "en":"dis"); @@ -1442,7 +1440,7 @@ free_region: if (vp->must_free_region) release_region(dev->base_addr, vci->io_size); free_netdev(dev); - printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); + pr_err(PFX "vortex_probe1 fails. Returns %d\n", retval); out: return retval; } @@ -1464,13 +1462,13 @@ issue_and_wait(struct net_device *dev, int cmd) for (i = 0; i < 100000; i++) { if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) { if (vortex_debug > 1) - printk(KERN_INFO "%s: command 0x%04x took %d usecs\n", + pr_info("%s: command 0x%04x took %d usecs\n", dev->name, cmd, i * 10); return; } udelay(10); } - printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", + pr_err("%s: command 0x%04x did not complete! Status=0x%x\n", dev->name, cmd, ioread16(ioaddr + EL3_STATUS)); } @@ -1480,7 +1478,7 @@ vortex_set_duplex(struct net_device *dev) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; - printk(KERN_INFO "%s: setting %s-duplex.\n", + pr_info("%s: setting %s-duplex.\n", dev->name, (vp->full_duplex) ? "full" : "half"); EL3WINDOW(3); @@ -1522,7 +1520,7 @@ vortex_up(struct net_device *dev) pci_restore_state(VORTEX_PCI(vp)); err = pci_enable_device(VORTEX_PCI(vp)); if (err) { - printk(KERN_WARNING "%s: Could not enable device \n", + pr_warning("%s: Could not enable device\n", dev->name); goto err_out; } @@ -1533,14 +1531,14 @@ vortex_up(struct net_device *dev) config = ioread32(ioaddr + Wn3_Config); if (vp->media_override != 7) { - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", + pr_info("%s: Media override to transceiver %d (%s).\n", dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { if (vp->has_nway) { if (vortex_debug > 1) - printk(KERN_INFO "%s: using NWAY device table, not %d\n", + pr_info("%s: using NWAY device table, not %d\n", dev->name, dev->if_port); dev->if_port = XCVR_NWAY; } else { @@ -1549,13 +1547,13 @@ vortex_up(struct net_device *dev) while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; if (vortex_debug > 1) - printk(KERN_INFO "%s: first available media type: %s\n", + pr_info("%s: first available media type: %s\n", dev->name, media_tbl[dev->if_port].name); } } else { dev->if_port = vp->default_media; if (vortex_debug > 1) - printk(KERN_INFO "%s: using default media %s\n", + pr_info("%s: using default media %s\n", dev->name, media_tbl[dev->if_port].name); } @@ -1570,13 +1568,13 @@ vortex_up(struct net_device *dev) vp->rx_oom_timer.function = rx_oom_timer; if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Initial media type %s.\n", + pr_debug("%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); vp->full_duplex = vp->mii.force_media; config = BFINS(config, dev->if_port, 20, 4); if (vortex_debug > 6) - printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); + pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config); iowrite32(config, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { @@ -1602,7 +1600,7 @@ vortex_up(struct net_device *dev) if (vortex_debug > 1) { EL3WINDOW(4); - printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n", + pr_debug("%s: vortex_up() irq %d media status %4.4x.\n", dev->name, dev->irq, ioread16(ioaddr + Wn4_Media)); } @@ -1704,13 +1702,13 @@ vortex_open(struct net_device *dev) /* Use the now-standard shared IRQ implementation. */ if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) { - printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); + pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq); goto err; } if (vp->full_bus_master_rx) { /* Boomerang bus master. */ if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); + pr_debug("%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1)); @@ -1728,7 +1726,7 @@ vortex_open(struct net_device *dev) } if (i != RX_RING_SIZE) { int j; - printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name); + pr_emerg("%s: no memory for rx ring\n", dev->name); for (j = 0; j < i; j++) { if (vp->rx_skbuff[j]) { dev_kfree_skb(vp->rx_skbuff[j]); @@ -1750,7 +1748,7 @@ err_free_irq: free_irq(dev->irq, dev); err: if (vortex_debug > 1) - printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); + pr_err("%s: vortex_open() fails: returning %d\n", dev->name, retval); out: return retval; } @@ -1766,9 +1764,9 @@ vortex_timer(unsigned long data) int media_status, old_window; if (vortex_debug > 2) { - printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", + pr_debug("%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); - printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); + pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo); } disable_irq_lockdep(dev->irq); @@ -1781,12 +1779,12 @@ vortex_timer(unsigned long data) netif_carrier_on(dev); ok = 1; if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n", + pr_debug("%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } else { netif_carrier_off(dev); if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n", + pr_debug("%s: Media %s has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } } @@ -1802,7 +1800,7 @@ vortex_timer(unsigned long data) break; default: /* Other media types handled by Tx timeouts. */ if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n", + pr_debug("%s: Media %s has no indication, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); ok = 1; } @@ -1822,13 +1820,11 @@ vortex_timer(unsigned long data) if (dev->if_port == XCVR_Default) { /* Go back to default. */ dev->if_port = vp->default_media; if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection failing, using default " - "%s port.\n", + pr_debug("%s: Media selection failing, using default %s port.\n", dev->name, media_tbl[dev->if_port].name); } else { if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection failed, now trying " - "%s port.\n", + pr_debug("%s: Media selection failed, now trying %s port.\n", dev->name, media_tbl[dev->if_port].name); next_tick = media_tbl[dev->if_port].wait; } @@ -1843,13 +1839,13 @@ vortex_timer(unsigned long data) iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, ioaddr + EL3_CMD); if (vortex_debug > 1) - printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config); + pr_debug("wrote 0x%08x to Wn3_Config\n", config); /* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */ } leave_media_alone: if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", + pr_debug("%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); EL3WINDOW(old_window); @@ -1865,21 +1861,21 @@ static void vortex_tx_timeout(struct net_device *dev) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; - printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, ioread8(ioaddr + TxStatus), ioread16(ioaddr + EL3_STATUS)); EL3WINDOW(4); - printk(KERN_ERR " diagnostics: net %04x media %04x dma %08x fifo %04x\n", + pr_err(" diagnostics: net %04x media %04x dma %08x fifo %04x\n", ioread16(ioaddr + Wn4_NetDiag), ioread16(ioaddr + Wn4_Media), ioread32(ioaddr + PktStatus), ioread16(ioaddr + Wn4_FIFODiag)); /* Slight code bloat to be user friendly. */ if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88) - printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" + pr_err("%s: Transmitter encountered 16 collisions --" " network cable problem?\n", dev->name); if (ioread16(ioaddr + EL3_STATUS) & IntLatch) { - printk(KERN_ERR "%s: Interrupt posted but not delivered --" + pr_err("%s: Interrupt posted but not delivered --" " IRQ blocked by another device?\n", dev->name); /* Bad idea here.. but we might as well handle a few events. */ { @@ -1903,7 +1899,7 @@ static void vortex_tx_timeout(struct net_device *dev) dev->stats.tx_errors++; if (vp->full_bus_master_tx) { - printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name); + pr_debug("%s: Resetting the Tx ring pointer.\n", dev->name); if (vp->cur_tx - vp->dirty_tx > 0 && ioread32(ioaddr + DownListPtr) == 0) iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); @@ -1938,7 +1934,7 @@ vortex_error(struct net_device *dev, int status) unsigned char tx_status = 0; if (vortex_debug > 2) { - printk(KERN_ERR "%s: vortex_error(), status=0x%x\n", dev->name, status); + pr_err("%s: vortex_error(), status=0x%x\n", dev->name, status); } if (status & TxComplete) { /* Really "TxError" for us. */ @@ -1946,10 +1942,10 @@ vortex_error(struct net_device *dev, int status) /* Presumably a tx-timeout. We must merely re-enable. */ if (vortex_debug > 2 || (tx_status != 0x88 && vortex_debug > 0)) { - printk(KERN_ERR "%s: Transmit error, Tx status register %2.2x.\n", + pr_err("%s: Transmit error, Tx status register %2.2x.\n", dev->name, tx_status); if (tx_status == 0x82) { - printk(KERN_ERR "Probably a duplex mismatch. See " + pr_err("Probably a duplex mismatch. See " "Documentation/networking/vortex.txt\n"); } dump_tx_ring(dev); @@ -1975,13 +1971,13 @@ vortex_error(struct net_device *dev, int status) if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat; if (vortex_debug > 4) - printk(KERN_DEBUG "%s: Updating stats.\n", dev->name); + pr_debug("%s: Updating stats.\n", dev->name); update_stats(ioaddr, dev); /* HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ if (DoneDidThat == 0 && ioread16(ioaddr + EL3_STATUS) & StatsFull) { - printk(KERN_WARNING "%s: Updating statistics failed, disabling " + pr_warning("%s: Updating statistics failed, disabling " "stats as an interrupt source.\n", dev->name); EL3WINDOW(5); iowrite16(SetIntrEnb | (ioread16(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD); @@ -1998,7 +1994,7 @@ vortex_error(struct net_device *dev, int status) u16 fifo_diag; EL3WINDOW(4); fifo_diag = ioread16(ioaddr + Wn4_FIFODiag); - printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n", + pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n", dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { @@ -2006,7 +2002,7 @@ vortex_error(struct net_device *dev, int status) /* 0x80000000 PCI master abort. */ /* 0x40000000 PCI target abort. */ if (vortex_debug) - printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); + pr_err("%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); /* In this case, blow the card away */ /* Must not enter D3 or we can't legally issue the reset! */ @@ -2075,7 +2071,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) while (--i > 0 && (tx_status = ioread8(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n", + pr_debug("%s: Tx error, status %2.2x.\n", dev->name, tx_status); if (tx_status & 0x04) dev->stats.tx_fifo_errors++; if (tx_status & 0x38) dev->stats.tx_aborted_errors++; @@ -2101,14 +2097,14 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (vortex_debug > 6) { - printk(KERN_DEBUG "boomerang_start_xmit()\n"); - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", + pr_debug("boomerang_start_xmit()\n"); + pr_debug("%s: Trying to send a packet, Tx index %d.\n", dev->name, vp->cur_tx); } if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { if (vortex_debug > 0) - printk(KERN_WARNING "%s: BUG! Tx Ring full, refusing to send buffer.\n", + pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", dev->name); netif_stop_queue(dev); return 1; @@ -2204,7 +2200,7 @@ vortex_interrupt(int irq, void *dev_id) status = ioread16(ioaddr + EL3_STATUS); if (vortex_debug > 6) - printk("vortex_interrupt(). status=0x%4x\n", status); + pr_debug("vortex_interrupt(). status=0x%4x\n", status); if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs cause this */ @@ -2219,19 +2215,19 @@ vortex_interrupt(int irq, void *dev_id) goto handler_exit; if (vortex_debug > 4) - printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", + pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, ioread8(ioaddr + Timer)); do { if (vortex_debug > 5) - printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", + pr_debug("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & RxComplete) vortex_rx(dev); if (status & TxAvailable) { if (vortex_debug > 5) - printk(KERN_DEBUG " TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue (dev); @@ -2263,8 +2259,8 @@ vortex_interrupt(int irq, void *dev_id) } if (--work_done < 0) { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x.\n", dev->name, status); + pr_warning("%s: Too much work in interrupt, status %4.4x.\n", + dev->name, status); /* Disable all pending interrupts. */ do { vp->deferred |= status; @@ -2281,7 +2277,7 @@ vortex_interrupt(int irq, void *dev_id) } while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); if (vortex_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); handler_exit: spin_unlock(&vp->lock); @@ -2313,14 +2309,14 @@ boomerang_interrupt(int irq, void *dev_id) status = ioread16(ioaddr + EL3_STATUS); if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); + pr_debug("boomerang_interrupt. status=0x%4x\n", status); if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs can cause this */ if (status == 0xffff) { /* h/w no longer present (hotplug)? */ if (vortex_debug > 1) - printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); + pr_debug("boomerang_interrupt(1): status = 0xffff\n"); goto handler_exit; } @@ -2330,16 +2326,16 @@ boomerang_interrupt(int irq, void *dev_id) } if (vortex_debug > 4) - printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", + pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, ioread8(ioaddr + Timer)); do { if (vortex_debug > 5) - printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", + pr_debug("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & UpComplete) { iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD); if (vortex_debug > 5) - printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n"); + pr_debug("boomerang_interrupt->boomerang_rx\n"); boomerang_rx(dev); } @@ -2374,7 +2370,7 @@ boomerang_interrupt(int irq, void *dev_id) dev_kfree_skb_irq(skb); vp->tx_skbuff[entry] = NULL; } else { - printk(KERN_DEBUG "boomerang_interrupt: no skb!\n"); + pr_debug("boomerang_interrupt: no skb!\n"); } /* dev->stats.tx_packets++; Counted below. */ dirty_tx++; @@ -2382,7 +2378,7 @@ boomerang_interrupt(int irq, void *dev_id) vp->dirty_tx = dirty_tx; if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) { if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt: wake queue\n"); + pr_debug("boomerang_interrupt: wake queue\n"); netif_wake_queue (dev); } } @@ -2392,8 +2388,8 @@ boomerang_interrupt(int irq, void *dev_id) vortex_error(dev, status); if (--work_done < 0) { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x.\n", dev->name, status); + pr_warning("%s: Too much work in interrupt, status %4.4x.\n", + dev->name, status); /* Disable all pending interrupts. */ do { vp->deferred |= status; @@ -2413,7 +2409,7 @@ boomerang_interrupt(int irq, void *dev_id) } while ((status = ioread16(ioaddr + EL3_STATUS)) & IntLatch); if (vortex_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); handler_exit: spin_unlock(&vp->lock); @@ -2428,13 +2424,13 @@ static int vortex_rx(struct net_device *dev) short rx_status; if (vortex_debug > 5) - printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n", + pr_debug("vortex_rx(): status %4.4x, rx_status %4.4x.\n", ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus)); while ((rx_status = ioread16(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ unsigned char rx_error = ioread8(ioaddr + RxErrors); if (vortex_debug > 2) - printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) dev->stats.rx_over_errors++; if (rx_error & 0x02) dev->stats.rx_length_errors++; @@ -2448,7 +2444,7 @@ static int vortex_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len + 5); if (vortex_debug > 4) - printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ @@ -2478,8 +2474,8 @@ static int vortex_rx(struct net_device *dev) break; continue; } else if (vortex_debug > 0) - printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " - "size %d.\n", dev->name, pkt_len); + pr_notice("%s: No memory to allocate a sk_buff of size %d.\n", + dev->name, pkt_len); dev->stats.rx_dropped++; } issue_and_wait(dev, RxDiscard); @@ -2498,7 +2494,7 @@ boomerang_rx(struct net_device *dev) int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; if (vortex_debug > 5) - printk(KERN_DEBUG "boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS)); + pr_debug("boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS)); while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ if (--rx_work_limit < 0) @@ -2506,7 +2502,7 @@ boomerang_rx(struct net_device *dev) if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; if (vortex_debug > 2) - printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) dev->stats.rx_over_errors++; if (rx_error & 0x02) dev->stats.rx_length_errors++; @@ -2520,7 +2516,7 @@ boomerang_rx(struct net_device *dev) dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr); if (vortex_debug > 4) - printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); /* Check if the packet is long enough to just accept without @@ -2566,7 +2562,7 @@ boomerang_rx(struct net_device *dev) if (skb == NULL) { static unsigned long last_jif; if (time_after(jiffies, last_jif + 10 * HZ)) { - printk(KERN_WARNING "%s: memory shortage\n", dev->name); + pr_warning("%s: memory shortage\n", dev->name); last_jif = jiffies; } if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) @@ -2598,7 +2594,7 @@ rx_oom_timer(unsigned long arg) if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ boomerang_rx(dev); if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, + pr_debug("%s: rx_oom_timer %s\n", dev->name, ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); } spin_unlock_irq(&vp->lock); @@ -2655,9 +2651,9 @@ vortex_close(struct net_device *dev) vortex_down(dev, 1); if (vortex_debug > 1) { - printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", + pr_debug("%s: vortex_close() status %4.4x, Tx status %2.2x.\n", dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus)); - printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" + pr_debug("%s: vortex close stats: rx_nocopy %d rx_copy %d" " tx_queued %d Rx pre-checksummed %d.\n", dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits); } @@ -2666,8 +2662,7 @@ vortex_close(struct net_device *dev) if (vp->rx_csumhits && (vp->drv_flags & HAS_HWCKSM) == 0 && (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) { - printk(KERN_WARNING "%s supports hardware checksums, and we're " - "not using them!\n", dev->name); + pr_warning("%s supports hardware checksums, and we're not using them!\n", dev->name); } #endif @@ -2717,16 +2712,16 @@ dump_tx_ring(struct net_device *dev) int i; int stalled = ioread32(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ - printk(KERN_ERR " Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", + pr_err(" Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", vp->full_bus_master_tx, vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, vp->cur_tx, vp->cur_tx % TX_RING_SIZE); - printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", + pr_err(" Transmit list %8.8x vs. %p.\n", ioread32(ioaddr + DownListPtr), &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); issue_and_wait(dev, DownStall); for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_ERR " %d: @%p length %8.8x status %8.8x\n", i, + pr_err(" %d: @%p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], #if DO_ZEROCOPY le32_to_cpu(vp->tx_ring[i].frag[0].length), @@ -2970,7 +2965,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { if (vortex_debug > 3) - printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name); + pr_notice("%s: Setting promiscuous mode.\n", dev->name); new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast; @@ -3145,8 +3140,7 @@ static void acpi_set_WOL(struct net_device *dev) iowrite16(RxEnable, ioaddr + EL3_CMD); if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) { - printk(KERN_INFO "%s: WOL not supported.\n", - pci_name(VORTEX_PCI(vp))); + pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp))); vp->enable_wol = 0; return; @@ -3164,7 +3158,7 @@ static void __devexit vortex_remove_one(struct pci_dev *pdev) struct vortex_private *vp; if (!dev) { - printk("vortex_remove_one called for Compaq device!\n"); + pr_err("vortex_remove_one called for Compaq device!\n"); BUG(); } -- cgit v0.10.2 From b93d584772347323334253d5b21c4d720718d7da Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Tue, 26 May 2009 12:35:27 +0000 Subject: 8139*: convert printk() to pr_() Also convert DPRINTK to pr_debug and dev_printk to dev_. Signed-off-by: Alexander Beregalov Signed-off-by: David S. Miller diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 02330f3..c9fc0ff 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -471,8 +471,7 @@ static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail, u32 status, u32 len) { if (netif_msg_rx_err (cp)) - printk (KERN_DEBUG - "%s: rx err, slot %d status 0x%x len %d\n", + pr_debug("%s: rx err, slot %d status 0x%x len %d\n", cp->dev->name, rx_tail, status, len); cp->dev->stats.rx_errors++; if (status & RxErrFrame) @@ -547,7 +546,7 @@ rx_status_loop: } if (netif_msg_rx_status(cp)) - printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n", + pr_debug("%s: rx slot %d status 0x%x len %d\n", dev->name, rx_tail, status, len); buflen = cp->rx_buf_sz + NET_IP_ALIGN; @@ -626,7 +625,7 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) return IRQ_NONE; if (netif_msg_intr(cp)) - printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n", + pr_debug("%s: intr, status %04x cmd %02x cpcmd %04x\n", dev->name, status, cpr8(Cmd), cpr16(CpCmd)); cpw16(IntrStatus, status & ~cp_rx_intr_mask); @@ -658,7 +657,7 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status); pci_write_config_word(cp->pdev, PCI_STATUS, pci_status); - printk(KERN_ERR "%s: PCI bus error, status=%04x, PCI status=%04x\n", + pr_err("%s: PCI bus error, status=%04x, PCI status=%04x\n", dev->name, status, pci_status); /* TODO: reset hardware */ @@ -705,7 +704,7 @@ static void cp_tx (struct cp_private *cp) if (status & LastFrag) { if (status & (TxError | TxFIFOUnder)) { if (netif_msg_tx_err(cp)) - printk(KERN_DEBUG "%s: tx err, status 0x%x\n", + pr_debug("%s: tx err, status 0x%x\n", cp->dev->name, status); cp->dev->stats.tx_errors++; if (status & TxOWC) @@ -722,7 +721,7 @@ static void cp_tx (struct cp_private *cp) cp->dev->stats.tx_packets++; cp->dev->stats.tx_bytes += skb->len; if (netif_msg_tx_done(cp)) - printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail); + pr_debug("%s: tx done, slot %d\n", cp->dev->name, tx_tail); } dev_kfree_skb_irq(skb); } @@ -755,7 +754,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); spin_unlock_irqrestore(&cp->lock, intr_flags); - printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", + pr_err(PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); return 1; } @@ -882,7 +881,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) } cp->tx_head = entry; if (netif_msg_tx_queued(cp)) - printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", + pr_debug("%s: tx queued, slot %d, skblen %d\n", dev->name, entry, skb->len); if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); @@ -996,7 +995,7 @@ static void cp_reset_hw (struct cp_private *cp) schedule_timeout_uninterruptible(10); } - printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name); + pr_err("%s: hardware reset timeout\n", cp->dev->name); } static inline void cp_start_hw (struct cp_private *cp) @@ -1166,7 +1165,7 @@ static int cp_open (struct net_device *dev) int rc; if (netif_msg_ifup(cp)) - printk(KERN_DEBUG "%s: enabling interface\n", dev->name); + pr_debug("%s: enabling interface\n", dev->name); rc = cp_alloc_rings(cp); if (rc) @@ -1201,7 +1200,7 @@ static int cp_close (struct net_device *dev) napi_disable(&cp->napi); if (netif_msg_ifdown(cp)) - printk(KERN_DEBUG "%s: disabling interface\n", dev->name); + pr_debug("%s: disabling interface\n", dev->name); spin_lock_irqsave(&cp->lock, flags); @@ -1224,7 +1223,7 @@ static void cp_tx_timeout(struct net_device *dev) unsigned long flags; int rc; - printk(KERN_WARNING "%s: Transmit timeout, status %2x %4x %4x %4x\n", + pr_warning("%s: Transmit timeout, status %2x %4x %4x %4x\n", dev->name, cpr8(Cmd), cpr16(CpCmd), cpr16(IntrStatus), cpr16(IntrMask)); @@ -1873,7 +1872,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) #ifndef MODULE static int version_printed; if (version_printed++ == 0) - printk("%s", version); + pr_info("%s", version); #endif if (pdev->vendor == PCI_VENDOR_ID_REALTEK && @@ -1995,8 +1994,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out_iomap; - printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, " - "%pM, IRQ %d\n", + pr_info("%s: RTL-8139C+ at 0x%lx, %pM, IRQ %d\n", dev->name, dev->base_addr, dev->dev_addr, @@ -2113,7 +2111,7 @@ static struct pci_driver cp_driver = { static int __init cp_init (void) { #ifdef MODULE - printk("%s", version); + pr_info("%s", version); #endif return pci_register_driver(&cp_driver); } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index d901775..8ae72ec 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -126,19 +126,12 @@ #undef RTL8139_NDEBUG -#if RTL8139_DEBUG -/* note: prints function name for you */ -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) -#else -# define DPRINTK(fmt, args...) -#endif - #ifdef RTL8139_NDEBUG # define assert(expr) do {} while (0) #else # define assert(expr) \ if(unlikely(!(expr))) { \ - printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + pr_err("Assertion failed! %s,%s,%s,line=%d\n", \ #expr, __FILE__, __func__, __LINE__); \ } #endif @@ -784,8 +777,8 @@ static __devinit struct net_device * rtl8139_init_board (struct pci_dev *pdev) /* set this immediately, we need to know before * we talk to the chip directly */ - DPRINTK("PIO region size == 0x%02X\n", pio_len); - DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); + pr_debug("PIO region size == 0x%02lX\n", pio_len); + pr_debug("MMIO region size == 0x%02lX\n", mmio_len); retry: if (use_io) { @@ -865,19 +858,17 @@ retry: } /* if unknown chip, assume array element #0, original RTL-8139 in this case */ - dev_printk (KERN_DEBUG, &pdev->dev, - "unknown chip version, assuming RTL-8139\n"); - dev_printk (KERN_DEBUG, &pdev->dev, - "TxConfig = 0x%lx\n", RTL_R32 (TxConfig)); + dev_dbg(&pdev->dev, "unknown chip version, assuming RTL-8139\n"); + dev_dbg(&pdev->dev, "TxConfig = 0x%lx\n", RTL_R32 (TxConfig)); tp->chipset = 0; match: - DPRINTK ("chipset id (%d) == index %d, '%s'\n", + pr_debug("chipset id (%d) == index %d, '%s'\n", version, i, rtl_chip_info[i].name); if (tp->chipset >= CH_8139B) { u8 new_tmp8 = tmp8 = RTL_R8 (Config1); - DPRINTK("PCI PM wakeup\n"); + pr_debug("PCI PM wakeup\n"); if ((rtl_chip_info[tp->chipset].flags & HasLWake) && (tmp8 & LWAKE)) new_tmp8 &= ~LWAKE; @@ -896,7 +887,7 @@ match: } } } else { - DPRINTK("Old chip wakeup\n"); + pr_debug("Old chip wakeup\n"); tmp8 = RTL_R8 (Config1); tmp8 &= ~(SLEEP | PWRDN); RTL_W8 (Config1, tmp8); @@ -949,7 +940,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, { static int printed_version; if (!printed_version++) - printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); + pr_info(RTL8139_DRIVER_NAME "\n"); } #endif @@ -965,7 +956,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->subsystem_vendor == PCI_VENDOR_ID_ATHEROS && pdev->subsystem_device == PCI_DEVICE_ID_REALTEK_8139) { - printk(KERN_INFO "8139too: OQO Model 2 detected. Forcing PIO\n"); + pr_info("8139too: OQO Model 2 detected. Forcing PIO\n"); use_io = 1; } @@ -1018,21 +1009,20 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, tp->mii.reg_num_mask = 0x1f; /* dev is fully set up and ready to use now */ - DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); + pr_debug("about to register device named %s (%p)...\n", dev->name, dev); i = register_netdev (dev); if (i) goto err_out; pci_set_drvdata (pdev, dev); - printk (KERN_INFO "%s: %s at 0x%lx, " - "%pM, IRQ %d\n", + pr_info("%s: %s at 0x%lx, %pM, IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, dev->dev_addr, dev->irq); - printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", + pr_debug("%s: Identified 8139 chip type '%s'\n", dev->name, rtl_chip_info[tp->chipset].name); /* Find the connected MII xcvrs. @@ -1046,14 +1036,12 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, if (mii_status != 0xffff && mii_status != 0x0000) { u16 advertising = mdio_read(dev, phy, 4); tp->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " - "advertising %4.4x.\n", + pr_info("%s: MII transceiver %d status 0x%4.4x advertising %4.4x.\n", dev->name, phy, mii_status, advertising); } } if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " - "transceiver.\n", + pr_info("%s: No MII transceivers found! Assuming SYM transceiver.\n", dev->name); tp->phys[0] = 32; } @@ -1073,13 +1061,13 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) tp->mii.full_duplex = full_duplex[board_idx]; if (tp->mii.full_duplex) { - printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); + pr_info("%s: Media type forced to Full Duplex.\n", dev->name); /* Changing the MII-advertised media because might prevent re-connection. */ tp->mii.force_media = 1; } if (tp->default_port) { - printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n", + pr_info(" Forcing %dMbps %s-duplex operation.\n", (option & 0x20 ? 100 : 10), (option & 0x10 ? "full" : "half")); mdio_write(dev, tp->phys[0], 0, @@ -1342,7 +1330,7 @@ static int rtl8139_open (struct net_device *dev) netif_start_queue (dev); if (netif_msg_ifup(tp)) - printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#llx IRQ %d" + pr_debug("%s: rtl8139_open() ioaddr %#llx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, (unsigned long long)pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), @@ -1404,7 +1392,7 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic); } - DPRINTK("init buffer addresses\n"); + pr_debug("init buffer addresses\n"); /* Lock Config[01234] and BMCR register writes */ RTL_W8 (Cfg9346, Cfg9346_Lock); @@ -1566,14 +1554,13 @@ static inline void rtl8139_thread_iter (struct net_device *dev, tp->mii.full_duplex = duplex; if (mii_lpa) { - printk (KERN_INFO - "%s: Setting %s-duplex based on MII #%d link" + pr_info("%s: Setting %s-duplex based on MII #%d link" " partner ability of %4.4x.\n", dev->name, tp->mii.full_duplex ? "full" : "half", tp->phys[0], mii_lpa); } else { - printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + pr_info("%s: media is unconnected, link down, or incompatible connection\n", dev->name); } #if 0 @@ -1588,11 +1575,11 @@ static inline void rtl8139_thread_iter (struct net_device *dev, rtl8139_tune_twister (dev, tp); - DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", + pr_debug("%s: Media selection tick, Link partner %4.4x.\n", dev->name, RTL_R16 (NWayLPAR)); - DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n", + pr_debug("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n", dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus)); - DPRINTK ("%s: Chip config %2.2x %2.2x.\n", + pr_debug("%s: Chip config %2.2x %2.2x.\n", dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); } @@ -1652,14 +1639,14 @@ static void rtl8139_tx_timeout_task (struct work_struct *work) int i; u8 tmp8; - printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x " - "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd), + pr_debug("%s: Transmit timeout, status %2.2x %4.4x %4.4x media %2.2x.\n", + dev->name, RTL_R8 (ChipCmd), RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus)); /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", + pr_debug("%s: Tx queue start entry %ld dirty entry %ld.\n", dev->name, tp->cur_tx, tp->dirty_tx); for (i = 0; i < NUM_TX_DESC; i++) - printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", + pr_debug("%s: Tx descriptor %d is %8.8lx.%s\n", dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); @@ -1741,7 +1728,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&tp->lock, flags); if (netif_msg_tx_queued(tp)) - printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", + pr_debug("%s: Queued Tx packet size %u to slot %d.\n", dev->name, len, entry); return 0; @@ -1772,7 +1759,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev, if (txstatus & (TxOutOfWindow | TxAborted)) { /* There was an major error, log it. */ if (netif_msg_tx_err(tp)) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + pr_debug("%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); dev->stats.tx_errors++; if (txstatus & TxAborted) { @@ -1803,7 +1790,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev, #ifndef RTL8139_NDEBUG if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", + pr_err("%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } @@ -1828,12 +1815,12 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, #endif if (netif_msg_rx_err (tp)) - printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n", + pr_debug("%s: Ethernet frame had errors, status %8.8x.\n", dev->name, rx_status); dev->stats.rx_errors++; if (!(rx_status & RxStatusOK)) { if (rx_status & RxTooLong) { - DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", + pr_debug("%s: Oversized Ethernet frame, status %4.4x!\n", dev->name, rx_status); /* A.C.: The chip hangs here. */ } @@ -1866,7 +1853,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, break; } if (tmp_work <= 0) - printk (KERN_WARNING PFX "rx stop wait too long\n"); + pr_warning(PFX "rx stop wait too long\n"); /* restart receive */ tmp_work = 200; while (--tmp_work > 0) { @@ -1877,7 +1864,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, break; } if (tmp_work <= 0) - printk (KERN_WARNING PFX "tx/rx enable wait too long\n"); + pr_warning(PFX "tx/rx enable wait too long\n"); /* and reinitialize all rx related registers */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -1888,7 +1875,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, RTL_W32 (RxConfig, tp->rx_config); tp->cur_rx = 0; - DPRINTK("init buffer addresses\n"); + pr_debug("init buffer addresses\n"); /* Lock Config[01234] and BMCR register writes */ RTL_W8 (Cfg9346, Cfg9346_Lock); @@ -1942,7 +1929,7 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, unsigned int cur_rx = tp->cur_rx; unsigned int rx_size = 0; - DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," + pr_debug("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); @@ -1962,17 +1949,17 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, pkt_size = rx_size - 4; if (netif_msg_rx_status(tp)) - printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," + pr_debug("%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); #if RTL8139_DEBUG > 2 { int i; - DPRINTK ("%s: Frame contents ", dev->name); + pr_debug("%s: Frame contents ", dev->name); for (i = 0; i < 70; i++) - printk (" %2.2x", + pr_cont(" %2.2x", rx_ring[ring_offset + i]); - printk (".\n"); + pr_cont(".\n"); } #endif @@ -1984,12 +1971,12 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, if (!tp->fifo_copy_timeout) tp->fifo_copy_timeout = jiffies + 2; else if (time_after(jiffies, tp->fifo_copy_timeout)) { - DPRINTK ("%s: hung FIFO. Reset.", dev->name); + pr_debug("%s: hung FIFO. Reset.", dev->name); rx_size = 0; goto no_early_rx; } if (netif_msg_intr(tp)) { - printk(KERN_DEBUG "%s: fifo copy in progress.", + pr_debug("%s: fifo copy in progress.", dev->name); } tp->xstats.early_rx++; @@ -2033,8 +2020,7 @@ no_early_rx: netif_receive_skb (skb); } else { if (net_ratelimit()) - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", + pr_warning("%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; } @@ -2049,12 +2035,10 @@ no_early_rx: if (unlikely(!received || rx_size == 0xfff0)) rtl8139_isr_ack(tp); -#if RTL8139_DEBUG > 1 - DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," + pr_debug("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); -#endif tp->cur_rx = cur_rx; @@ -2075,7 +2059,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev, void __iomem *ioaddr, int status, int link_changed) { - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", + pr_debug("%s: Abnormal interrupt, status %8.8x.\n", dev->name, status); assert (dev != NULL); @@ -2104,7 +2088,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev, pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status); - printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", + pr_err("%s: PCI Bus error %4.4x.\n", dev->name, pci_cmd_status); } } @@ -2198,7 +2182,7 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) out: spin_unlock (&tp->lock); - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", + pr_debug("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); return IRQ_RETVAL(handled); } @@ -2249,7 +2233,7 @@ static int rtl8139_close (struct net_device *dev) napi_disable(&tp->napi); if (netif_msg_ifdown(tp)) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", + pr_debug("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); spin_lock_irqsave (&tp->lock, flags); @@ -2527,7 +2511,7 @@ static void __set_rx_mode (struct net_device *dev) int i, rx_mode; u32 tmp; - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", + pr_debug("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, dev->flags, RTL_R32 (RxConfig)); /* Note: do not reorder, GCC is clever about common statements. */ @@ -2643,7 +2627,7 @@ static int __init rtl8139_init_module (void) * even if no 8139 board is found. */ #ifdef MODULE - printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); + pr_info(RTL8139_DRIVER_NAME "\n"); #endif return pci_register_driver(&rtl8139_pci_driver); -- cgit v0.10.2 From 3c514ce2f9ae20c06fb17c7ccff40cad1516cc41 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Tue, 26 May 2009 13:50:15 +0000 Subject: igb: add RQDPC (Receive Queue Drop Packet Count) register macro Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 0bd7728..6e59245 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -142,6 +142,7 @@ enum { #define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */ #define E1000_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */ +#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40)) /* Split and Replication RX Control - RW */ /* * Convenience macros -- cgit v0.10.2 From 8c0ab70ab9cc849af59ef6592bd652a938b21c79 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 26 May 2009 13:50:31 +0000 Subject: igb: Implement reading of reg RQDPC (Receive Queue Drop Packet Count) Based on the previous patches from Jesper Dangaard Brouer Implement reading the per queue drop stats register RQDPC (Receive Queue Drop Packet Count). It counts the number of packets dropped by a queue due to lack of descriptors available. Notice RQDPC (Receive Queue Drop Packet Count) stats only gets incremented, if the DROP_EN bit it set (in the SRRCTL register for that queue). If DROP_EN bit is NOT set, then the some what equivalent count is stored in RNBC (not per queue basis). The RQDPC register is only 12 bit, thus the precision might suffer due to overrun in-netween the watchdog polling interval. Signed-off-by: Jeff Kirsher CC: Jesper Dangaard Brouer Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 154c5ac..b2c98de 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -137,11 +137,17 @@ struct igb_buffer { }; }; -struct igb_queue_stats { +struct igb_tx_queue_stats { u64 packets; u64 bytes; }; +struct igb_rx_queue_stats { + u64 packets; + u64 bytes; + u64 drops; +}; + struct igb_ring { struct igb_adapter *adapter; /* backlink */ void *desc; /* descriptor ring memory */ @@ -167,12 +173,13 @@ struct igb_ring { union { /* TX */ struct { - struct igb_queue_stats tx_stats; + struct igb_tx_queue_stats tx_stats; bool detect_tx_hung; }; /* RX */ struct { - struct igb_queue_stats rx_stats; + struct igb_rx_queue_stats rx_stats; + u64 rx_queue_drops; struct napi_struct napi; int set_itr; struct igb_ring *buddy; diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index b8551a5..2ae98f9 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -96,9 +96,10 @@ static const struct igb_stats igb_gstrings_stats[] = { }; #define IGB_QUEUE_STATS_LEN \ - ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues + \ - ((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \ - (sizeof(struct igb_queue_stats) / sizeof(u64))) + (((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues)* \ + (sizeof(struct igb_rx_queue_stats) / sizeof(u64))) + \ + ((((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \ + (sizeof(struct igb_tx_queue_stats) / sizeof(u64)))) #define IGB_GLOBAL_STATS_LEN \ sizeof(igb_gstrings_stats) / sizeof(struct igb_stats) #define IGB_STATS_LEN (IGB_GLOBAL_STATS_LEN + IGB_QUEUE_STATS_LEN) @@ -1960,7 +1961,8 @@ static void igb_get_ethtool_stats(struct net_device *netdev, { struct igb_adapter *adapter = netdev_priv(netdev); u64 *queue_stat; - int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64); + int stat_count_tx = sizeof(struct igb_tx_queue_stats) / sizeof(u64); + int stat_count_rx = sizeof(struct igb_rx_queue_stats) / sizeof(u64); int j; int i; @@ -1973,14 +1975,14 @@ static void igb_get_ethtool_stats(struct net_device *netdev, for (j = 0; j < adapter->num_tx_queues; j++) { int k; queue_stat = (u64 *)&adapter->tx_ring[j].tx_stats; - for (k = 0; k < stat_count; k++) + for (k = 0; k < stat_count_tx; k++) data[i + k] = queue_stat[k]; i += k; } for (j = 0; j < adapter->num_rx_queues; j++) { int k; queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats; - for (k = 0; k < stat_count; k++) + for (k = 0; k < stat_count_rx; k++) data[i + k] = queue_stat[k]; i += k; } @@ -2014,6 +2016,8 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) p += ETH_GSTRING_LEN; sprintf(p, "rx_queue_%u_bytes", i); p += ETH_GSTRING_LEN; + sprintf(p, "rx_queue_%u_drops", i); + p += ETH_GSTRING_LEN; } /* BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */ break; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 2ec9809..4ae8133 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3588,8 +3588,25 @@ void igb_update_stats(struct igb_adapter *adapter) /* Rx Errors */ + if (hw->mac.type != e1000_82575) { + u32 rqdpc_tmp; + int i; + /* Read out drops stats per RX queue. Notice RQDPC (Receive + * Queue Drop Packet Count) stats only gets incremented, if + * the DROP_EN but it set (in the SRRCTL register for that + * queue). If DROP_EN bit is NOT set, then the some what + * equivalent count is stored in RNBC (not per queue basis). + * Also note the drop count is due to lack of available + * descriptors. + */ + for (i = 0; i < adapter->num_rx_queues; i++) { + rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0xFFF; + adapter->rx_ring[i].rx_stats.drops += rqdpc_tmp; + } + } + /* RLEC on some newer hardware can be incorrect so build - * our own version based on RUC and ROC */ + * our own version based on RUC and ROC */ adapter->net_stats.rx_errors = adapter->stats.rxerrc + adapter->stats.crcerrs + adapter->stats.algnerrc + adapter->stats.ruc + adapter->stats.roc + -- cgit v0.10.2 From 3ea73afafb8cd237a823ec5d0a0a2f2396b03b33 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 26 May 2009 13:50:48 +0000 Subject: igb: Record host memory receive overflow in net_stats Based on previous patch from Jesper Dangaard Brouer. The RNBC (Receive No Buffers Count) register for the 82576, indicate that frames were received when there were no available buffers in host memory to store those frames (receive descriptor head and tail pointers were equal). The packet is still received by the NIC if there is space in the FIFO on the NIC. As the RNBC value is not a packet drop, the driver stores this value in net_stats.rx_fifo_errors to indicate that there were no system buffers available for the incoming packet. Actual dropped packets are counted in the MPC value. Saving the stats in dev->net_stats makes it visible via /proc/net/dev as "fifo", and thus viewable to ifconfig as "overruns" and 'netstat -i' as "RX-OVR". The Receive No Buffers Count (RNBC) can already be queried by ethtool -S as "rx_no_buffer_count". Signed-off-by: Jeff Kirsher CC: Jesper Dangaard Brouer Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 2ae98f9..9598ac0 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -64,6 +64,7 @@ static const struct igb_stats igb_gstrings_stats[] = { { "rx_crc_errors", IGB_STAT(stats.crcerrs) }, { "rx_frame_errors", IGB_STAT(net_stats.rx_frame_errors) }, { "rx_no_buffer_count", IGB_STAT(stats.rnbc) }, + { "rx_queue_drop_packet_count", IGB_STAT(net_stats.rx_fifo_errors) }, { "rx_missed_errors", IGB_STAT(stats.mpc) }, { "tx_aborted_errors", IGB_STAT(stats.ecol) }, { "tx_carrier_errors", IGB_STAT(stats.tncrs) }, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 4ae8133..8e93750 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3590,6 +3590,7 @@ void igb_update_stats(struct igb_adapter *adapter) if (hw->mac.type != e1000_82575) { u32 rqdpc_tmp; + u64 rqdpc_total = 0; int i; /* Read out drops stats per RX queue. Notice RQDPC (Receive * Queue Drop Packet Count) stats only gets incremented, if @@ -3602,9 +3603,18 @@ void igb_update_stats(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0xFFF; adapter->rx_ring[i].rx_stats.drops += rqdpc_tmp; + rqdpc_total += adapter->rx_ring[i].rx_stats.drops; } + adapter->net_stats.rx_fifo_errors = rqdpc_total; } + /* Note RNBC (Receive No Buffers Count) is an not an exact + * drop count as the hardware FIFO might save the day. Thats + * one of the reason for saving it in rx_fifo_errors, as its + * potentially not a true drop. + */ + adapter->net_stats.rx_fifo_errors += adapter->stats.rnbc; + /* RLEC on some newer hardware can be incorrect so build * our own version based on RUC and ROC */ adapter->net_stats.rx_errors = adapter->stats.rxerrc + -- cgit v0.10.2 From cbe7a81a7370e2c4560b48e42e741bd1476bc700 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 26 May 2009 13:51:05 +0000 Subject: igb/e1000e: update PSSR_MDIX value to reflect correct bit The phy port status register has the MDI-X status bit on bit 11, not bit 3 as is currently setup in the define. This patch corrects that so the correct bit is checked on igp PHY types. Signed-off-by: Alexander Duyck Acked-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index d8b8229..6cdb703 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -253,7 +253,7 @@ enum e1e_registers { #define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 #define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_MDIX 0x0800 #define IGP01E1000_PSSR_SPEED_MASK 0xC000 #define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h index 3228a86..ebe4b61 100644 --- a/drivers/net/igb/e1000_phy.h +++ b/drivers/net/igb/e1000_phy.h @@ -80,7 +80,7 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw); #define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ #define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 #define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_MDIX 0x0800 #define IGP01E1000_PSSR_SPEED_MASK 0xC000 #define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 #define IGP02E1000_PHY_CHANNEL_NUM 4 -- cgit v0.10.2 From f7c86a3252af7f1222f9ebce66f3654ad3aa9ff0 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Tue, 26 May 2009 20:40:09 -0700 Subject: ixgbe: Remove device ID 0x10d8 Device ID 0x10d8 is the default silicon device ID for 82599. However, the device will not be functional without an EEPROM, so we want to prevent the driver from loading on the device. Otherwise, the driver will load, but no PHY setup or PCIe setup will occur, causing the device to be unusable. To prevent users from encountering this, just remove the device ID. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index fef7397..5d27830 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -357,7 +357,6 @@ enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) } switch (hw->device_id) { - case IXGBE_DEV_ID_82599: case IXGBE_DEV_ID_82599_KX4: case IXGBE_DEV_ID_82599_XAUI_LOM: /* Default device ID is mezzanine card KX/KX4 */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index ba3ed0f..df1f703 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -46,7 +46,6 @@ #define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 #define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1 #define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 -#define IXGBE_DEV_ID_82599 0x10D8 #define IXGBE_DEV_ID_82599_KX4 0x10F7 #define IXGBE_DEV_ID_82599_SFP 0x10FB #define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC -- cgit v0.10.2 From 8ca783ab78e3fa518885c4fef93d0972e450a4de Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Tue, 26 May 2009 20:40:47 -0700 Subject: ixgbe: fix 82598 SFP initialization after driver load. If we loaded the driver with out a SFP module plugged in it would leave it in a state that make it later unable to link when a module was plugged in. This patch corrects that by: ixgbe_probe() - moving the check for IXGBE_ERR_SFP_NOT_PRESENT from after get_invariants() to after reset_hw() as now reset_hw() is where this condition will be indentified. ixgbe_reset_hw_82598() - Enable this function to now return IXGBE_ERR_SFP_NOT_PRESENT. ixgbe_identify_sfp_module_generic() - This where the lack of SFP module is detected. Modifications are added to allow a different return value for modules that just haven't been plugged in yet. Other functions were updated to allow correct logging. Signed-off-by: Don Skidmore Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index afc9fe3..88e8350 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -698,6 +698,7 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) { s32 status = 0; + s32 phy_status = 0; u32 ctrl; u32 gheccr; u32 i; @@ -745,13 +746,17 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) /* PHY ops must be identified and initialized prior to reset */ /* Init PHY and function pointers, perform SFP setup */ - status = hw->phy.ops.init(hw); - if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) + phy_status = hw->phy.ops.init(hw); + if (phy_status == IXGBE_ERR_SFP_NOT_SUPPORTED) goto reset_hw_out; + else if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT) + goto no_phy_reset; + hw->phy.ops.reset(hw); } +no_phy_reset: /* * Prevent the PCI-E bus from from hanging by disabling PCI-E master * access and verify no pending requests before reset @@ -811,6 +816,9 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); reset_hw_out: + if (phy_status) + status = phy_status; + return status; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index e52798c..f9223ac 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2599,7 +2599,10 @@ int ixgbe_up(struct ixgbe_adapter *adapter) void ixgbe_reset(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; - if (hw->mac.ops.init_hw(hw)) + int err; + + err = hw->mac.ops.init_hw(hw); + if (err && (err != IXGBE_ERR_SFP_NOT_PRESENT)) dev_err(&adapter->pdev->dev, "Hardware Error\n"); /* reprogram the RAR[0] in case user changed it. */ @@ -5167,20 +5170,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, INIT_WORK(&adapter->sfp_config_module_task, ixgbe_sfp_config_module_task); - err = ii->get_invariants(hw); - if (err == IXGBE_ERR_SFP_NOT_PRESENT) { - /* start a kernel thread to watch for a module to arrive */ - set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); - err = 0; - } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - DPRINTK(PROBE, ERR, "failed to load because an " - "unsupported SFP+ module type was detected.\n"); - goto err_hw_init; - } else if (err) { - goto err_hw_init; - } + ii->get_invariants(hw); /* setup the private structure */ err = ixgbe_sw_init(adapter); @@ -5200,7 +5190,18 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* reset_hw fills in the perm_addr as well */ err = hw->mac.ops.reset_hw(hw); - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + if (err == IXGBE_ERR_SFP_NOT_PRESENT && + hw->mac.type == ixgbe_mac_82598EB) { + /* + * Start a kernel thread to watch for a module to arrive. + * Only do this for 82598, since 82599 will generate + * interrupts on module arrival. + */ + set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + mod_timer(&adapter->sfp_timer, + round_jiffies(jiffies + (2 * HZ))); + err = 0; + } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { dev_err(&adapter->pdev->dev, "failed to load because an " "unsupported SFP+ module type was detected.\n"); goto err_sw_init; diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 8210b49..e43d624 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -530,11 +530,22 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) u8 cable_tech = 0; u16 enforce_sfp = 0; + if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { + hw->phy.sfp_type = ixgbe_sfp_type_not_present; + status = IXGBE_ERR_SFP_NOT_PRESENT; + goto out; + } + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, &identifier); - if (status == IXGBE_ERR_SFP_NOT_PRESENT) { + if (status == IXGBE_ERR_SFP_NOT_PRESENT || status == IXGBE_ERR_I2C) { + status = IXGBE_ERR_SFP_NOT_PRESENT; hw->phy.sfp_type = ixgbe_sfp_type_not_present; + if (hw->phy.type != ixgbe_phy_nl) { + hw->phy.id = 0; + hw->phy.type = ixgbe_phy_unknown; + } goto out; } -- cgit v0.10.2 From 9c5cd6708008fcc3dbced6e4b97aa5ecd0634a85 Mon Sep 17 00:00:00 2001 From: Tanli Chang Date: Tue, 26 May 2009 20:45:50 -0700 Subject: niu: Add support for C10NEM This patch is for supporting C10NEM. C10NEM is a switch module, which has back-to-back XAUI link connected to blades. Signed-off-by: Tanli Chang Signed-off-by: David S. Miller diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 2b17453..0d9de5a 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -1317,7 +1317,7 @@ static int bcm8704_reset(struct niu *np) err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, MII_BMCR); - if (err < 0) + if (err < 0 || err == 0xffff) return err; err |= BMCR_RESET; err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, @@ -2042,7 +2042,7 @@ static int link_status_10g_bcm8706(struct niu *np, int *link_up_p) err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, BCM8704_PMD_RCV_SIGDET); - if (err < 0) + if (err < 0 || err == 0xffff) goto out; if (!(err & PMD_RCV_SIGDET_GLOBAL)) { err = 0; @@ -2083,8 +2083,6 @@ static int link_status_10g_bcm8706(struct niu *np, int *link_up_p) out: *link_up_p = link_up; - if (np->flags & NIU_FLAGS_HOTPLUG_PHY) - err = 0; return err; } @@ -2220,10 +2218,17 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) if (phy_present != phy_present_prev) { /* state change */ if (phy_present) { + /* A NEM was just plugged in */ np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT; if (np->phy_ops->xcvr_init) err = np->phy_ops->xcvr_init(np); if (err) { + err = mdio_read(np, np->phy_addr, + BCM8704_PHYXS_DEV_ADDR, MII_BMCR); + if (err == 0xffff) { + /* No mdio, back-to-back XAUI */ + goto out; + } /* debounce */ np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; } @@ -2234,13 +2239,21 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) np->dev->name); } } - if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) +out: + if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) { err = link_status_10g_bcm8706(np, link_up_p); + if (err == 0xffff) { + /* No mdio, back-to-back XAUI: it is C10NEM */ + *link_up_p = 1; + np->link_config.active_speed = SPEED_10000; + np->link_config.active_duplex = DUPLEX_FULL; + } + } } spin_unlock_irqrestore(&np->lock, flags); - return err; + return 0; } static int niu_link_status(struct niu *np, int *link_up_p) @@ -2312,6 +2325,12 @@ static const struct niu_phy_ops phy_ops_10g_fiber_hotplug = { .link_status = link_status_10g_hotplug, }; +static const struct niu_phy_ops phy_ops_niu_10g_hotplug = { + .serdes_init = serdes_init_niu_10g_fiber, + .xcvr_init = xcvr_init_10g_bcm8706, + .link_status = link_status_10g_hotplug, +}; + static const struct niu_phy_ops phy_ops_10g_copper = { .serdes_init = serdes_init_10g, .link_status = link_status_10g, /* XXX */ @@ -2358,6 +2377,11 @@ static const struct niu_phy_template phy_template_10g_fiber_hotplug = { .phy_addr_base = 8, }; +static const struct niu_phy_template phy_template_niu_10g_hotplug = { + .ops = &phy_ops_niu_10g_hotplug, + .phy_addr_base = 8, +}; + static const struct niu_phy_template phy_template_10g_copper = { .ops = &phy_ops_10g_copper, .phy_addr_base = 10, @@ -2542,8 +2566,16 @@ static int niu_determine_phy_disposition(struct niu *np) case NIU_FLAGS_10G | NIU_FLAGS_FIBER: /* 10G Fiber */ default: - tp = &phy_template_niu_10g_fiber; - phy_addr_off += np->port; + if (np->flags & NIU_FLAGS_HOTPLUG_PHY) { + tp = &phy_template_niu_10g_hotplug; + if (np->port == 0) + phy_addr_off = 8; + if (np->port == 1) + phy_addr_off = 12; + } else { + tp = &phy_template_niu_10g_fiber; + phy_addr_off += np->port; + } break; } } else { @@ -2630,11 +2662,11 @@ static int niu_init_link(struct niu *np) msleep(200); } err = niu_serdes_init(np); - if (err) + if (err && !(np->flags & NIU_FLAGS_HOTPLUG_PHY)) return err; msleep(200); err = niu_xcvr_init(np); - if (!err) + if (!err || (np->flags & NIU_FLAGS_HOTPLUG_PHY)) niu_link_status(np, &ignore); return 0; } @@ -9346,6 +9378,11 @@ static int __devinit niu_get_of_props(struct niu *np) if (model) strcpy(np->vpd.model, model); + if (of_find_property(dp, "hot-swappable-phy", &prop_len)) { + np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER | + NIU_FLAGS_HOTPLUG_PHY); + } + return 0; #else return -EINVAL; -- cgit v0.10.2 From 3d6593e9cc40d0eacc03f75f90834794a4a477df Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 26 May 2009 20:49:03 -0700 Subject: net/ucc_geth: allow to set mac address on running device Inspired by the patch for 8139too (bda6a15a). Currently we can't set mac address on a running ucc_geth device. But this is needed when you use this device as a bonding slave in bonding device in balance-alb mode. So add this feature for ucc_geth device. Signed-off-by: Kevin Hao Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index f18017d..0cf22c4 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3325,6 +3325,37 @@ static void ucc_netpoll(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ +static int ucc_geth_set_mac_addr(struct net_device *dev, void *p) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * If device is not running, we will set mac addr register + * when opening the device. + */ + if (!netif_running(dev)) + return 0; + + spin_lock_irq(&ugeth->lock); + init_mac_station_addr_regs(dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5], + &ugeth->ug_regs->macstnaddr1, + &ugeth->ug_regs->macstnaddr2); + spin_unlock_irq(&ugeth->lock); + + return 0; +} + /* Called when something needs to use the ethernet device */ /* Returns 0 for success. */ static int ucc_geth_open(struct net_device *dev) @@ -3501,7 +3532,7 @@ static const struct net_device_ops ucc_geth_netdev_ops = { .ndo_stop = ucc_geth_close, .ndo_start_xmit = ucc_geth_start_xmit, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = ucc_geth_set_mac_addr, .ndo_change_mtu = eth_change_mtu, .ndo_set_multicast_list = ucc_geth_set_multi, .ndo_tx_timeout = ucc_geth_timeout, -- cgit v0.10.2 From f21b75e9d6471d7f4e2110774819be7beafc86d5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 26 May 2009 20:54:48 -0700 Subject: r8169: Use a different default for each family The r8169 driver supports 3 different families of network chips (RTL8169, RTL8168 and RTL8101). When an unknown version is found, the driver currently always defaults to the RTL8169 variant. This has very little chance to ever work for chips of the other families. So better define a per-family default. Signed-off-by: Jean Delvare Acked-by: Francois Romieu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index fb2e50d..0ec0605 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -94,6 +94,7 @@ static const int multicast_filter_limit = 32; #define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) enum mac_version { + RTL_GIGA_MAC_NONE = 0x00, RTL_GIGA_MAC_VER_01 = 0x01, // 8169 RTL_GIGA_MAC_VER_02 = 0x02, // 8169S RTL_GIGA_MAC_VER_03 = 0x03, // 8110S @@ -1300,7 +1301,8 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, - { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ + /* Catch-all */ + { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE } }, *p = mac_info; u32 reg; @@ -1308,12 +1310,6 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, while ((reg & p->mask) != p->val) p++; tp->mac_version = p->mac_version; - - if (p->mask == 0x00000000) { - struct pci_dev *pdev = tp->pci_dev; - - dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg); - } } static void rtl8169_print_mac_version(struct rtl8169_private *tp) @@ -1889,6 +1885,7 @@ static const struct rtl_cfg_info { u16 intr_event; u16 napi_event; unsigned features; + u8 default_ver; } rtl_cfg_infos [] = { [RTL_CFG_0] = { .hw_start = rtl_hw_start_8169, @@ -1897,7 +1894,8 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_GMII + .features = RTL_FEATURE_GMII, + .default_ver = RTL_GIGA_MAC_VER_01, }, [RTL_CFG_1] = { .hw_start = rtl_hw_start_8168, @@ -1906,7 +1904,8 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | TxErr | TxOK | RxOK | RxErr, .napi_event = TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI, + .default_ver = RTL_GIGA_MAC_VER_11, }, [RTL_CFG_2] = { .hw_start = rtl_hw_start_8101, @@ -1915,7 +1914,8 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_MSI + .features = RTL_FEATURE_MSI, + .default_ver = RTL_GIGA_MAC_VER_13, } }; @@ -2096,6 +2096,15 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Identify chip attached to board */ rtl8169_get_mac_version(tp, ioaddr); + /* Use appropriate default if unknown */ + if (tp->mac_version == RTL_GIGA_MAC_NONE) { + if (netif_msg_probe(tp)) { + dev_notice(&pdev->dev, + "unknown MAC, using family default\n"); + } + tp->mac_version = cfg->default_ver; + } + rtl8169_print_mac_version(tp); for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) { @@ -2103,13 +2112,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) break; } if (i == ARRAY_SIZE(rtl_chip_info)) { - /* Unknown chip: assume array element #0, original RTL-8169 */ - if (netif_msg_probe(tp)) { - dev_printk(KERN_DEBUG, &pdev->dev, - "unknown chip version, assuming %s\n", - rtl_chip_info[0].name); - } - i = 0; + dev_err(&pdev->dev, + "driver bug, MAC version not found in rtl_chip_info\n"); + goto err_out_msi_5; } tp->chipset = i; -- cgit v0.10.2 From 2b0cc7f78ba55e831c16fb8cb5c204d9d2ecc398 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 21:05:19 -0700 Subject: net: Remove bogus reference to BUS_ID_SIZE in sysfs code. BUS_ID_SIZE is really no more, and device names are dynamically allocated and thus can be any necessary size. So remove the BUG check here making sure BUS_ID_SIZE is at least as large as IFNAMSIZ. Signed-off-by: David S. Miller diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index b9641e8..3994680 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -499,7 +499,6 @@ int netdev_register_kobject(struct net_device *net) dev->platform_data = net; dev->groups = groups; - BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); dev_set_name(dev, "%s", net->name); #ifdef CONFIG_SYSFS -- cgit v0.10.2 From 0e53c7f954a1e616df74723630dc844c211f6be5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 21:09:33 -0700 Subject: ixp4xx_eth: Remove references to BUS_ID_SIZE. Use MII_BUS_ID_SIZE instead. Signed-off-by: David S. Miller diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index a740053..322c49b 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -1149,7 +1149,7 @@ static int __devinit eth_init_one(struct platform_device *pdev) struct net_device *dev; struct eth_plat_info *plat = pdev->dev.platform_data; u32 regs_phys; - char phy_id[BUS_ID_SIZE]; + char phy_id[MII_BUS_ID_SIZE + 3]; int err; if (!(dev = alloc_etherdev(sizeof(struct port)))) @@ -1207,7 +1207,7 @@ static int __devinit eth_init_one(struct platform_device *pdev) __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control); udelay(50); - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy); + snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, "0", plat->phy); port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0, PHY_INTERFACE_MODE_MII); if ((err = IS_ERR(port->phydev))) -- cgit v0.10.2 From 21a8cfe120c581091722fb146540a2033af16a57 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 21:10:22 -0700 Subject: cpmac: Remove references to BUS_ID_SIZE, use MII_BUS_ID_SIZE. Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index af305c0..cfb4198 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -202,7 +202,7 @@ struct cpmac_priv { void __iomem *regs; struct mii_bus *mii_bus; struct phy_device *phy; - char phy_name[BUS_ID_SIZE]; + char phy_name[MII_BUS_ID_SIZE + 3]; int oldlink, oldspeed, oldduplex; u32 msg_enable; struct net_device *dev; -- cgit v0.10.2 From 0a372eb91f9d507701a901c2f62ed31ca67fd66c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 21:11:09 -0700 Subject: sh_eth: Remove references to BUS_ID_SIZE, use MII_BUS_ID_SIZE instead. Signed-off-by: David S. Miller diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index cdd73b9..0709b75 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -964,7 +964,7 @@ static void sh_eth_adjust_link(struct net_device *ndev) static int sh_eth_phy_init(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); - char phy_id[BUS_ID_SIZE]; + char phy_id[MII_BUS_ID_SIZE + 3]; struct phy_device *phydev = NULL; snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, -- cgit v0.10.2 From 079e24ed80c8a91dd2884b88820bac6f340aaa83 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 21:15:00 -0700 Subject: nl80211: Eliminate reference to BUS_ID_SIZE. It's going away. Just leave the constant "20" here so that behavior doesn't change. Signed-off-by: David S. Miller diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 56d729c..4b4d3c8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -57,7 +57,7 @@ static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, - .len = BUS_ID_SIZE-1 }, + .len = 20-1 }, [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, -- cgit v0.10.2 From 8e401eccd3a62fb57f117bb09b7c1fc70ab19e8c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 21:16:25 -0700 Subject: phy: Eliminate references to BUS_ID_SIZE. Just use the constant 20 to keep things working. If someone is so motivated, this can be converted over to dynamic strings. I tried and it's a lot of work. But for now this is good enough. Signed-off-by: David S. Miller diff --git a/include/linux/phy.h b/include/linux/phy.h index c216e4e..b1368b8 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -79,7 +79,7 @@ typedef enum { * Need to be a little smaller than phydev->dev.bus_id to leave room * for the ":%02x" */ -#define MII_BUS_ID_SIZE (BUS_ID_SIZE - 3) +#define MII_BUS_ID_SIZE (20 - 3) /* * The Bus class for PHYs. Devices which provide access to @@ -407,7 +407,7 @@ struct phy_driver { /* A Structure for boards to register fixups with the PHY Lib */ struct phy_fixup { struct list_head list; - char bus_id[BUS_ID_SIZE]; + char bus_id[20]; u32 phy_uid; u32 phy_uid_mask; int (*run)(struct phy_device *phydev); -- cgit v0.10.2 From b74be6119e9e38390395f08767b7c84de9023b38 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 10:20:23 +0800 Subject: ACPICA: Update error/warning interfaces Moved the module name and line number to the end of the message. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 1c9e250..fbe7823 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -1033,11 +1033,12 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); + acpi_os_printf("ACPI Error: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1047,12 +1048,12 @@ acpi_exception(const char *module_name, { va_list args; - acpi_os_printf("ACPI Exception (%s-%04d): %s, ", module_name, - line_number, acpi_format_exception(status)); + acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status)); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1061,11 +1062,12 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number); + acpi_os_printf("ACPI Warning: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1074,10 +1076,6 @@ acpi_info(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - /* - * Removed module_name, line_number, and acpica version, not needed - * for info output - */ acpi_os_printf("ACPI: "); va_start(args, format); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 4db89e9..a868df6 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -375,7 +375,7 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); acpi_status acpi_leave_sleep_state(u8 sleep_state); /* - * Debug output + * Error/Warning output */ void ACPI_INTERNAL_VAR_XFACE acpi_error(const char *module_name, @@ -394,6 +394,9 @@ void ACPI_INTERNAL_VAR_XFACE acpi_info(const char *module_name, u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3); +/* + * Debug output + */ #ifdef ACPI_DEBUG_OUTPUT void ACPI_INTERNAL_VAR_XFACE -- cgit v0.10.2 From 8eb7b2477c4e4fec4788605e4edb5f7acafb59ff Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 10:28:22 +0800 Subject: ACPICA: Fix a few warnings for gcc 3.4.4 Mostly for acpiexec, one in the core subsystem. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 7b2fb60..23d5505 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -81,9 +81,9 @@ acpi_status acpi_hw_clear_acpi_status(void) ACPI_FUNCTION_TRACE(hw_clear_acpi_status); - ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %0llX\n", + ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", ACPI_BITMASK_ALL_FIXED_STATUS, - acpi_gbl_xpm1a_status.address)); + ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 8e2cdc5..935c5d7 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -62,4 +62,8 @@ */ #define ACPI_UNUSED_VAR __attribute__ ((unused)) +#ifdef _ANSI +#define inline +#endif + #endif /* __ACGCC_H__ */ -- cgit v0.10.2 From 33a1d461d294722dd15ffe17651bdd48b5763883 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 10:48:57 +0800 Subject: ACPICA: Change behavior of object copy for mutex/event objects When copying these internal objects, cannot simply copy the underlying OS object. A new OS object must be created. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 919624f..0f0c64b 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -676,6 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, { u16 reference_count; union acpi_operand_object *next_object; + acpi_status status; /* Save fields from destination that we don't want to overwrite */ @@ -768,6 +769,28 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, } break; + /* + * For Mutex and Event objects, we cannot simply copy the underlying + * OS object. We must create a new one. + */ + case ACPI_TYPE_MUTEX: + + status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex); + if (ACPI_FAILURE(status)) { + return status; + } + break; + + case ACPI_TYPE_EVENT: + + status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, + &dest_desc->event. + os_semaphore); + if (ACPI_FAILURE(status)) { + return status; + } + break; + default: /* Nothing to do for other simple objects */ break; -- cgit v0.10.2 From 41bdd8e9809665d6a13e49137661a8f2e5a7dc51 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 10:51:06 +0800 Subject: ACPICA: Remove unused global variables Remove two unused/obsolete variables. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 16e5210..3d87362 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -362,9 +362,6 @@ extern u8 acpi_gbl_method_executing; extern u8 acpi_gbl_abort_method; extern u8 acpi_gbl_db_terminate_threads; -ACPI_EXTERN int optind; -ACPI_EXTERN char *optarg; - ACPI_EXTERN u8 acpi_gbl_db_opt_tables; ACPI_EXTERN u8 acpi_gbl_db_opt_stats; ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; -- cgit v0.10.2 From 10b6575b5d84d21e2eab01df2284288e5fdf7887 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 11:39:10 +0800 Subject: ACPICA: Fix possible warnings for ACPI_THREAD_ID on 64-bit build Warnings can be generated for printf-like statements that output the ACPI_THREAD_ID on 64-bit builds, since this type can expand to 64-bits depending on how it is defined. Use the %p format specifier to allow the output to automatically expand to 64 bits. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index d301c1f..d7cb030 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -373,11 +373,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, walk_state->thread->thread_id) && (obj_desc != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, - "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", - (unsigned long)walk_state->thread->thread_id, + "Thread %p cannot release Mutex [%4.4s] acquired by thread %p", + ACPI_CAST_PTR(void, walk_state->thread->thread_id), acpi_ut_get_node_name(obj_desc->mutex.node), - (unsigned long)obj_desc->mutex.owner_thread-> - thread_id)); + ACPI_CAST_PTR(void, + obj_desc->mutex.owner_thread-> + thread_id))); return_ACPI_STATUS(AE_AML_NOT_OWNER); } diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 38821f5..527d729 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -179,9 +179,9 @@ acpi_debug_print(u32 requested_debug_level, if (thread_id != acpi_gbl_prev_thread_id) { if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf - ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", - (unsigned long)acpi_gbl_prev_thread_id, - (unsigned long)thread_id); + ("\n**** Context Switch from TID %p to TID %p ****\n\n", + ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id), + ACPI_CAST_PTR(void, thread_id)); } acpi_gbl_prev_thread_id = thread_id; @@ -194,7 +194,7 @@ acpi_debug_print(u32 requested_debug_level, acpi_os_printf("%8s-%04ld ", module_name, line_number); if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf("[%04lX] ", (unsigned long)thread_id); + acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id)); } acpi_os_printf("[%02ld] %-22.22s: ", diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 26c93a7..80bb651 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -230,17 +230,18 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { if (i == mutex_id) { ACPI_ERROR((AE_INFO, - "Mutex [%s] already acquired by this thread [%X]", + "Mutex [%s] already acquired by this thread [%p]", acpi_ut_get_mutex_name (mutex_id), - this_thread_id)); + ACPI_CAST_PTR(void, + this_thread_id))); return (AE_ALREADY_ACQUIRED); } ACPI_ERROR((AE_INFO, - "Invalid acquire order: Thread %X owns [%s], wants [%s]", - this_thread_id, + "Invalid acquire order: Thread %p owns [%s], wants [%s]", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(i), acpi_ut_get_mutex_name(mutex_id))); @@ -251,24 +252,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) #endif ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX attempting to acquire Mutex [%s]\n", - (unsigned long)this_thread_id, + "Thread %p attempting to acquire Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX acquired Mutex [%s]\n", - (unsigned long)this_thread_id, + "Thread %p acquired Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; } else { ACPI_EXCEPTION((AE_INFO, status, - "Thread %lX could not acquire Mutex [%X]", - (unsigned long)this_thread_id, mutex_id)); + "Thread %p could not acquire Mutex [%X]", + ACPI_CAST_PTR(void, this_thread_id), mutex_id)); } return (status); @@ -293,9 +294,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) ACPI_FUNCTION_NAME(ut_release_mutex); this_thread_id = acpi_os_get_thread_id(); - ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX releasing Mutex [%s]\n", - (unsigned long)this_thread_id, + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { -- cgit v0.10.2 From 35d7c1cfe5262480d3d8e6ccd7e4caf3a9c8ab39 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 12:41:27 +0800 Subject: ACPICA: Cleanup byte/word/dword extraction macros, fix possible warnings Removed unnecessary masking. For the 64-bit macros, removed the structure overlay. Fixes aliasing warnings seen with gcc 4+ compilers. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index f555d927..37ba576 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -429,20 +429,12 @@ typedef unsigned long long acpi_integer; /* Data manipulation */ -#define ACPI_LOWORD(l) ((u16)(u32)(l)) -#define ACPI_HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF)) -#define ACPI_LOBYTE(l) ((u8)(u16)(l)) -#define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) - -/* Full 64-bit integer must be available on both 32-bit and 64-bit platforms */ - -struct acpi_integer_overlay { - u32 lo_dword; - u32 hi_dword; -}; - -#define ACPI_LODWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword) -#define ACPI_HIDWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword) +#define ACPI_LOBYTE(integer) ((u8) (u16)(integer)) +#define ACPI_HIBYTE(integer) ((u8) (((u16)(integer)) >> 8)) +#define ACPI_LOWORD(integer) ((u16) (u32)(integer)) +#define ACPI_HIWORD(integer) ((u16)(((u32)(integer)) >> 16)) +#define ACPI_LODWORD(integer64) ((u32) (u64)(integer64)) +#define ACPI_HIDWORD(integer64) ((u32)(((u64)(integer64)) >> 32)) #define ACPI_SET_BIT(target,bit) ((target) |= (bit)) #define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) -- cgit v0.10.2 From b21245a85e62ea7eeb5b7562ce98cf8b0aecbd26 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 12:52:51 +0800 Subject: ACPICA: Fix printf format warnings for 64-bit build Fix warnings caused by size_t and ACPI_SIZE changing to 64 bits. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index ae3dc10..af8e6bc 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -149,7 +149,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) name_buffer = ACPI_ALLOCATE_ZEROED(size); if (!name_buffer) { - ACPI_ERROR((AE_INFO, "Allocation failure")); + ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); return_PTR(NULL); } diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 71e655d..e5fe7c8 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -284,9 +284,9 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, "FADT (revision %u) is longer than ACPI 2.0 version, " - "truncating length 0x%X to 0x%zX", - table->revision, (unsigned)length, - sizeof(struct acpi_table_fadt))); + "truncating length 0x%X to 0x%X", + table->revision, length, + (u32)sizeof(struct acpi_table_fadt))); } /* Clear the entire local FADT */ -- cgit v0.10.2 From 65259094c3e038519a2d8fa6fbc6256f04ad6535 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 12:57:40 +0800 Subject: ACPICA: Fix possible dereference of null pointer Fix dereference of possibly null pointer "Predefined" in the case where the method is not one of the predefined methods. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index d9e8cbc..7f8e066 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -144,7 +144,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, pathname = acpi_ns_get_external_pathname(node); if (!pathname) { - pathname = ACPI_CAST_PTR(char, predefined->info.name); + return AE_OK; /* Could not get pathname, ignore */ } /* @@ -230,10 +230,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } exit: - if (pathname != predefined->info.name) { - ACPI_FREE(pathname); - } - + ACPI_FREE(pathname); return (status); } -- cgit v0.10.2 From e4c1ebfc65c125b1289144f5815715f238367683 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 13:02:06 +0800 Subject: ACPICA: Miscellaneous lint changes Unused variables/headers, casting, etc. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index d0a0807..4721f58 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -51,7 +51,7 @@ ACPI_MODULE_NAME("evxfevnt") /* Local prototypes */ -acpi_status +static acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); @@ -785,7 +785,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) * block device. NULL if the GPE is one of the FADT-defined GPEs. * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context) { diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index f9b4f51..7e86563 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -45,6 +45,10 @@ #include "accommon.h" #include "acnamesp.h" +#ifdef ACPI_ASL_COMPILER +#include "amlcode.h" +#endif + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nssearch") diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 88b5a2c..d3f77a5 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -593,9 +593,6 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, } else { temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); - if (!temp_size_needed) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } } } else { /* diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index e5fe7c8..82b02dc 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -441,7 +441,7 @@ static void acpi_tb_convert_fadt(void) &acpi_gbl_FADT, fadt_info_table [i].length), - address32); + (u64) address32); } } } @@ -469,7 +469,6 @@ static void acpi_tb_convert_fadt(void) static void acpi_tb_validate_fadt(void) { char *name; - u32 *address32; struct acpi_generic_address *address64; u8 length; u32 i; @@ -505,15 +504,12 @@ static void acpi_tb_validate_fadt(void) for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { /* - * Generate pointers to the 32-bit and 64-bit addresses, get the - * register length (width), and the register name + * Generate pointer to the 64-bit address, get the register + * length (width) and the register name */ address64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, fadt_info_table[i].address64); - address32 = - ACPI_ADD_PTR(u32, &acpi_gbl_FADT, - fadt_info_table[i].address32); length = *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, fadt_info_table[i].length); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index f865d5a..63e8232 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -472,7 +472,7 @@ acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) * lock may block, and also since the execution of a namespace walk * must be allowed to use the interpreter. */ - acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); + (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); acpi_ns_delete_namespace_by_owner(owner_id); -- cgit v0.10.2 From ba9c3f550e5792fbce2bbd7a429bf6f6d1f45fda Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 13:13:48 +0800 Subject: ACPICA: Fix miscellaneous warnings under gcc 4+ Some possible warnings with gcc 4+, especially with extended warnings enabled Signed-off-by: Bob Moore Signed-off-by: Lin Ming diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index dab3f48..02e6caa 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -734,7 +734,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ - obj_desc->reference.value = opcode - AML_LOCAL_OP; + obj_desc->reference.value = + ((u32)opcode) - AML_LOCAL_OP; obj_desc->reference.class = ACPI_REFCLASS_LOCAL; #ifndef ACPI_NO_METHOD_EXECUTION @@ -754,7 +755,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ - obj_desc->reference.value = opcode - AML_ARG_OP; + obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP; obj_desc->reference.class = ACPI_REFCLASS_ARG; #ifndef ACPI_NO_METHOD_EXECUTION diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 40f92bf..e46c821 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -102,7 +102,7 @@ acpi_ds_result_pop(union acpi_operand_object **object, /* Return object of the top element and clean that top element result stack */ walk_state->result_count--; - index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; *object = state->results.obj_desc[index]; if (!*object) { @@ -186,7 +186,7 @@ acpi_ds_result_push(union acpi_operand_object * object, /* Assign the address of object to the top free element of result stack */ - index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; state->results.obj_desc[index] = object; walk_state->result_count++; diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 69a2aa5..395212b 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -338,13 +338,17 @@ acpi_resource_to_address64(struct acpi_resource *resource, switch (resource->type) { case ACPI_RESOURCE_TYPE_ADDRESS16: - address16 = (struct acpi_resource_address16 *)&resource->data; + address16 = + ACPI_CAST_PTR(struct acpi_resource_address16, + &resource->data); ACPI_COPY_ADDRESS(out, address16); break; case ACPI_RESOURCE_TYPE_ADDRESS32: - address32 = (struct acpi_resource_address32 *)&resource->data; + address32 = + ACPI_CAST_PTR(struct acpi_resource_address32, + &resource->data); ACPI_COPY_ADDRESS(out, address32); break; -- cgit v0.10.2 From 2b09ce98a25e467455ecd81354cc18381628be75 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 13:22:38 +0800 Subject: ACPICA: Fix implementation of AML BreakPoint operator (break to debugger) The AML BreakPoint opcode will now cause a break into the AML debugger if it is present/configured. This matches the expected behavior per the ACPI specification. Previously, only a message was output. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index b4c87b5..584d766 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -1386,14 +1386,19 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, case AML_BREAK_POINT_OP: - /* Call up to the OS service layer to handle this */ - - status = - acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, - "Executed AML Breakpoint opcode"); + /* + * Set the single-step flag. This will cause the debugger (if present) + * to break to the console within the AML debugger at the start of the + * next AML instruction. + */ + ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); + ACPI_DEBUGGER_EXEC(acpi_os_printf + ("**break** Executed AML BreakPoint opcode\n")); - /* If and when it returns, all done. */ + /* Call to the OSL in case OS wants a piece of the action */ + status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, + "Executed AML Breakpoint opcode"); break; case AML_BREAK_OP: -- cgit v0.10.2 From e0c437bcca6926b541c738b5c64445654750b365 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 22 Apr 2009 13:39:47 +0800 Subject: ACPICA: Linux OSL: cleanup/update/merge Merge the OSL with the actual file used by Linux, so that the file does not require patching when integrated with Linux. General cleanup and some restructuring. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 6d49b2a..fcb8e4b 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -1,11 +1,11 @@ /****************************************************************************** * - * Name: aclinux.h - OS specific defines, etc. + * Name: aclinux.h - OS specific defines, etc. for Linux * *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2009, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,10 +44,13 @@ #ifndef __ACLINUX_H__ #define __ACLINUX_H__ +/* Common (in-kernel/user-space) ACPICA configuration */ + #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 #define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE + #ifdef __KERNEL__ #include @@ -63,15 +66,18 @@ #include #include -/* Host-dependent types and defines */ +/* Host-dependent types and defines for in-kernel ACPICA */ #define ACPI_MACHINE_WIDTH BITS_PER_LONG -#define acpi_cache_t struct kmem_cache -#define acpi_spinlock spinlock_t * #define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); #define strtoul simple_strtoul -#else /* !__KERNEL__ */ +#define acpi_cache_t struct kmem_cache +#define acpi_spinlock spinlock_t * +#define acpi_cpu_flags unsigned long +#define acpi_thread_id struct task_struct * + +#else /* !__KERNEL__ */ #include #include @@ -79,6 +85,11 @@ #include #include +/* Host-dependent types and defines for user-space ACPICA */ + +#define ACPI_FLUSH_CPU_CACHE() +#define acpi_thread_id pthread_t + #if defined(__ia64__) || defined(__x86_64__) #define ACPI_MACHINE_WIDTH 64 #define COMPILER_DEPENDENT_INT64 long @@ -94,17 +105,17 @@ #define __cdecl #endif -#define ACPI_FLUSH_CPU_CACHE() -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ /* Linux uses GCC */ #include "acgcc.h" -#define acpi_cpu_flags unsigned long - -#define acpi_thread_id struct task_struct * +#ifdef __KERNEL__ +/* + * Overrides for in-kernel ACPICA + */ static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; @@ -119,30 +130,32 @@ static inline acpi_thread_id acpi_os_get_thread_id(void) #include static inline void *acpi_os_allocate(acpi_size size) { - return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); + return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); } + static inline void *acpi_os_allocate_zeroed(acpi_size size) { - return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); + return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); } static inline void *acpi_os_acquire_object(acpi_cache_t * cache) { return kmem_cache_zalloc(cache, - irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); + irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); } -#define ACPI_ALLOCATE(a) acpi_os_allocate(a) -#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a) -#define ACPI_FREE(a) kfree(a) +#define ACPI_ALLOCATE(a) acpi_os_allocate(a) +#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a) +#define ACPI_FREE(a) kfree(a) -/* - * We need to show where it is safe to preempt execution of ACPICA - */ -#define ACPI_PREEMPTION_POINT() \ - do { \ - if (!irqs_disabled()) \ - cond_resched(); \ +/* Used within ACPICA to show where it is safe to preempt execution */ + +#define ACPI_PREEMPTION_POINT() \ + do { \ + if (!irqs_disabled()) \ + cond_resched(); \ } while (0) -#endif /* __ACLINUX_H__ */ +#endif /* __KERNEL__ */ + +#endif /* __ACLINUX_H__ */ -- cgit v0.10.2 From ba9e2ae443feb7231d9631ea0f62b63e26cfb9b1 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 24 Apr 2009 10:43:43 +0800 Subject: ACPICA: Update version to 20090422. Version 20090422. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index a868df6..60b76a3 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -47,7 +47,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20090320 +#define ACPI_CA_VERSION 0x20090422 #include "actypes.h" #include "actbl.h" -- cgit v0.10.2 From 10a3b461a258f52b17fb8e35edf3625726eca9a8 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 10:02:34 +0800 Subject: ACPICA: Mutex support: Fix release ordering issue and current sync level Fixes a problem where if multiple mutexes of the same sync level are acquired but then not released in strict opposite order, the current sync level becomes confused and can cause errors. ACPICA BZ 471. http://acpica.org/bugzilla/show_bug.cgi?id=471 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index d7cb030..77a592a 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -83,6 +83,15 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) if (obj_desc->mutex.prev) { (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; + + /* + * Migrate the previous sync level associated with this mutex to the + * previous mutex on the list so that it may be preserved. This handles + * the case where several mutexes have been acquired at the same level, + * but are not released in opposite order. + */ + (obj_desc->mutex.prev)->mutex.original_sync_level = + obj_desc->mutex.original_sync_level; } else { thread->acquired_mutex_list = obj_desc->mutex.next; } @@ -349,6 +358,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; + u8 previous_sync_level; ACPI_FUNCTION_TRACE(ex_release_mutex); @@ -404,14 +414,21 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } + /* + * Get the previous sync_level from the head of the acquired mutex list. + * This handles the case where several mutexes at the same level have been + * acquired, but are not released in reverse order. + */ + previous_sync_level = + walk_state->thread->acquired_mutex_list->mutex.original_sync_level; + status = acpi_ex_release_mutex_object(obj_desc); if (obj_desc->mutex.acquisition_depth == 0) { /* Restore the original sync_level */ - walk_state->thread->current_sync_level = - obj_desc->mutex.original_sync_level; + walk_state->thread->current_sync_level = previous_sync_level; } return_ACPI_STATUS(status); } -- cgit v0.10.2 From 315c728887f198d12eb6ec7ef9d88483018c11cb Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 10:04:33 +0800 Subject: ACPICA: Fix allowable release order for ASL mutex objects The ACPI 4.0 specification has been changed to make the SyncLevel for mutex objects more useful. When releasing a mutex, the synclevel of the mutex must now be the same as the current sync level. This makes more sense. This change updates the code to match the spec. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 77a592a..2f01142 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -402,10 +402,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, } /* - * The sync level of the mutex must be less than or equal to the current - * sync level + * The sync level of the mutex must be equal to the current sync level. In + * other words, the current level means that at least one mutex at that + * level is currently being held. Attempting to release a mutex of a + * different level can only mean that the mutex ordering rule is being + * violated. This behavior is clarified in ACPI 4.0 specification. */ - if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { + if (obj_desc->mutex.sync_level != + walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", acpi_ut_get_node_name(obj_desc->mutex.node), @@ -423,10 +427,13 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, walk_state->thread->acquired_mutex_list->mutex.original_sync_level; status = acpi_ex_release_mutex_object(obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } if (obj_desc->mutex.acquisition_depth == 0) { - /* Restore the original sync_level */ + /* Restore the previous sync_level */ walk_state->thread->current_sync_level = previous_sync_level; } -- cgit v0.10.2 From a76b7727364ebb77b25983427623757d2c99bbc3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 10:06:19 +0800 Subject: ACPICA: Fix DebugObject output for DdbHandle objects Was putting several extra spaces on the next line. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 90d6061..6efd07a 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -193,10 +193,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_REFCLASS_TABLE: + /* Case for ddb_handle */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "Table Index 0x%X\n", source_desc->reference.value)); - break; + return; default: break; -- cgit v0.10.2 From 474caffdc1ab35e9bcb1f88768442e3a4079a10d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 10:10:16 +0800 Subject: ACPICA: Additional validation of _PRT packages (resource mgr) Fixes a possible fault when parsing an ill-formed _PRT package. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index d3f77a5..3c4dcc3 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -547,7 +547,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, if (!package_element || (package_element->common.type != ACPI_TYPE_PACKAGE)) { - return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } /* -- cgit v0.10.2 From 8c725bf93706db976e9de495579ca625d493e809 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 10:27:51 +0800 Subject: ACPICA: Simplify and optimize NsGetNextNode function Reduced parameter count and reduced code for this frequently used function. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 46cb5b4..94cdc2b 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -99,10 +99,19 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_walk_callback user_function, void *context, void **return_value); -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node - *parent, struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node + *parent, + struct acpi_namespace_node *child); +struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, + struct + acpi_namespace_node + *parent, + struct + acpi_namespace_node + *child); + /* * nsparse - table parsing */ diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index aceb931..efc971a 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -334,9 +334,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) /* Get the next node in this scope (NULL if none) */ - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { /* Found a child node - detach any attached object */ @@ -345,8 +343,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) /* Check if this node has any children */ - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* * There is at least one child of this node, * visit the node @@ -432,9 +429,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) * Get the next child of this parent node. When child_node is NULL, * the first child of the parent is returned */ - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (deletion_node) { acpi_ns_delete_children(deletion_node); @@ -452,8 +447,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) /* Check if this node has any children */ - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* * There is at least one child of this node, * visit the node diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 83e3aa6..35539df 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -52,8 +52,7 @@ ACPI_MODULE_NAME("nswalk") * * FUNCTION: acpi_ns_get_next_node * - * PARAMETERS: Type - Type of node to be searched for - * parent_node - Parent node whose children we are + * PARAMETERS: parent_node - Parent node whose children we are * getting * child_node - Previous child that was found. * The NEXT child will be returned @@ -66,27 +65,68 @@ ACPI_MODULE_NAME("nswalk") * within Scope is returned. * ******************************************************************************/ -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node - *parent_node, struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node + *parent_node, + struct acpi_namespace_node *child_node) { - struct acpi_namespace_node *next_node = NULL; - ACPI_FUNCTION_ENTRY(); if (!child_node) { /* It's really the parent's _scope_ that we want */ - next_node = parent_node->child; + return parent_node->child; } - else { - /* Start search at the NEXT node */ - - next_node = acpi_ns_get_next_valid_node(child_node); + /* + * Get the next node. + * + * If we are at the end of this peer list, return NULL + */ + if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { + return NULL; } + /* Otherwise just return the next peer */ + + return child_node->peer; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_next_node_typed + * + * PARAMETERS: Type - Type of node to be searched for + * parent_node - Parent node whose children we are + * getting + * child_node - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node + * within Scope is returned. + * + ******************************************************************************/ + +struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, + struct + acpi_namespace_node + *parent_node, + struct + acpi_namespace_node + *child_node) +{ + struct acpi_namespace_node *next_node = NULL; + + ACPI_FUNCTION_ENTRY(); + + next_node = acpi_ns_get_next_node(parent_node, child_node); + + /* If any type is OK, we are done */ if (type == ACPI_TYPE_ANY) { @@ -186,9 +226,7 @@ acpi_ns_walk_namespace(acpi_object_type type, /* Get the next node in this scope. Null if not found */ status = AE_OK; - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { /* Found next child, get the type if we are not searching for ANY */ @@ -269,8 +307,7 @@ acpi_ns_walk_namespace(acpi_object_type type, * function has specified that the maximum depth has been reached. */ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* There is at least one child of this node, visit it */ diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 1c7efc1..dd33d8b 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -268,7 +268,7 @@ acpi_get_next_object(acpi_object_type type, /* Internal function does the real work */ - node = acpi_ns_get_next_node(type, parent_node, child_node); + node = acpi_ns_get_next_node_typed(type, parent_node, child_node); if (!node) { status = AE_NOT_FOUND; goto unlock_and_exit; -- cgit v0.10.2 From 06366c149232f64c89f513f188ccc6783d0e444f Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 21 May 2009 10:29:28 +0800 Subject: ACPICA: Fix reference count issues for DdbHandle object Fix a problem where the DdbHandle could be prematurely deleted, possibly causing a fault. Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 3deb20a..c0348ff 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -229,6 +229,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, walk_state); if (ACPI_FAILURE(status)) { (void)acpi_ex_unload_table(ddb_handle); + + acpi_ut_remove_reference(ddb_handle); return_ACPI_STATUS(status); } } @@ -454,6 +456,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } + /* Remove the reference by added by acpi_ex_store above */ + + acpi_ut_remove_reference(ddb_handle); + /* Invoke table handler if present */ if (acpi_gbl_table_handler) { @@ -530,8 +536,5 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) (void)acpi_tb_release_owner_id(table_index); acpi_tb_set_table_loaded_flag(table_index, FALSE); - /* Table unloaded, remove a reference to the ddb_handle object */ - - acpi_ut_remove_reference(ddb_handle); return_ACPI_STATUS(AE_OK); } -- cgit v0.10.2 From e0be6f5a9863b626c19f0be04946c6285cc9db56 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 21 May 2009 10:32:02 +0800 Subject: ACPICA: Invalidate DdbHandle after table unload Mark the DdbHandle as invalid after the table it refers to is unloaded. This is needed because the handle itself may not be deleted after the table unload, depending on whether it has been stored in a named object by the caller. Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index c0348ff..0731fd6 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -91,6 +91,7 @@ acpi_ex_add_table(u32 table_index, /* Init the table handle */ + obj_desc->common.flags |= AOPOBJ_DATA_VALID; obj_desc->reference.class = ACPI_REFCLASS_TABLE; *ddb_handle = obj_desc; @@ -501,13 +502,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) /* * Validate the handle - * Although the handle is partially validated in acpi_ex_reconfiguration(), + * Although the handle is partially validated in acpi_ex_reconfiguration() * when it calls acpi_ex_resolve_operands(), the handle is more completely * validated here. + * + * Handle must be a valid operand object of type reference. Also, the + * ddb_handle must still be marked valid (table has not been previously + * unloaded) */ if ((!ddb_handle) || (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || - (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE)) { + (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) || + (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -515,6 +521,12 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) table_index = table_desc->reference.value; + /* Ensure the table is still loaded */ + + if (!acpi_tb_is_table_loaded(table_index)) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + /* Invoke table handler if present */ if (acpi_gbl_table_handler) { @@ -536,5 +548,10 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) (void)acpi_tb_release_owner_id(table_index); acpi_tb_set_table_loaded_flag(table_index, FALSE); + /* + * Invalidate the handle. We do this because the handle may be stored + * in a named object and may not be actually deleted until much later. + */ + ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID; return_ACPI_STATUS(AE_OK); } -- cgit v0.10.2 From b2f7ddcfcb9c2436896cb339a7ff70245648f033 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 21 May 2009 10:42:09 +0800 Subject: ACPICA: New: AcpiInstallMethod - install a single control method This interface enables the override or creation of a single control method. Useful to repair a bug or install a missing method. Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2ec394a..882b4b5 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -205,6 +205,7 @@ struct acpi_namespace_node { #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ +#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ #define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index ff851c5..067f967 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -483,7 +483,7 @@ typedef enum { #define AML_METHOD_ARG_COUNT 0x07 #define AML_METHOD_SERIALIZED 0x08 -#define AML_METHOD_SYNCH_LEVEL 0xF0 +#define AML_METHOD_SYNC_LEVEL 0xF0 /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index a57ad25..02b25d2 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start, * ACPI 2.0: sync_level = sync_level in method declaration */ obj_desc->method.sync_level = (u8) - ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4); + ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); } /* Attach the new object to the method Node */ diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 89d141f..ec52461 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} }; -static struct acpi_exdump_info acpi_ex_dump_method[8] = { +static struct acpi_exdump_info acpi_ex_dump_method[9] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, - {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), + "Parameter Count"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 3eb20bf..60f3af0 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) return_VOID; } + if (node->flags & ANOBJ_ALLOCATED_BUFFER) { + + /* Free the dynamic aml buffer */ + + if (obj_desc->common.type == ACPI_TYPE_METHOD) { + ACPI_FREE(obj_desc->method.aml_start); + } + } + /* Clear the entry in all cases */ node->object = NULL; diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 9589fea..f23593d 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -45,6 +45,8 @@ #include #include "accommon.h" #include "acnamesp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfname") @@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) } ACPI_EXPORT_SYMBOL(acpi_get_object_info) + +/****************************************************************************** + * + * FUNCTION: acpi_install_method + * + * PARAMETERS: Buffer - An ACPI table containing one control method + * + * RETURN: Status + * + * DESCRIPTION: Install a control method into the namespace. If the method + * name already exists in the namespace, it is overwritten. The + * input buffer must contain a valid DSDT or SSDT containing a + * single control method. + * + ******************************************************************************/ +acpi_status acpi_install_method(u8 *buffer) +{ + struct acpi_table_header *table = + ACPI_CAST_PTR(struct acpi_table_header, buffer); + u8 *aml_buffer; + u8 *aml_start; + char *path; + struct acpi_namespace_node *node; + union acpi_operand_object *method_obj; + struct acpi_parse_state parser_state; + u32 aml_length; + u16 opcode; + u8 method_flags; + acpi_status status; + + /* Parameter validation */ + + if (!buffer) { + return AE_BAD_PARAMETER; + } + + /* Table must be a DSDT or SSDT */ + + if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { + return AE_BAD_HEADER; + } + + /* First AML opcode in the table must be a control method */ + + parser_state.aml = buffer + sizeof(struct acpi_table_header); + opcode = acpi_ps_peek_opcode(&parser_state); + if (opcode != AML_METHOD_OP) { + return AE_BAD_PARAMETER; + } + + /* Extract method information from the raw AML */ + + parser_state.aml += acpi_ps_get_opcode_size(opcode); + parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); + path = acpi_ps_get_next_namestring(&parser_state); + method_flags = *parser_state.aml++; + aml_start = parser_state.aml; + aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); + + /* + * Allocate resources up-front. We don't want to have to delete a new + * node from the namespace if we cannot allocate memory. + */ + aml_buffer = ACPI_ALLOCATE(aml_length); + if (!aml_buffer) { + return AE_NO_MEMORY; + } + + method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); + if (!method_obj) { + ACPI_FREE(aml_buffer); + return AE_NO_MEMORY; + } + + /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto error_exit; + } + + /* The lookup either returns an existing node or creates a new one */ + + status = + acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, + NULL, &node); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE(status)) { /* ns_lookup */ + if (status != AE_ALREADY_EXISTS) { + goto error_exit; + } + + /* Node existed previously, make sure it is a method node */ + + if (node->type != ACPI_TYPE_METHOD) { + status = AE_TYPE; + goto error_exit; + } + } + + /* Copy the method AML to the local buffer */ + + ACPI_MEMCPY(aml_buffer, aml_start, aml_length); + + /* Initialize the method object with the new method's information */ + + method_obj->method.aml_start = aml_buffer; + method_obj->method.aml_length = aml_length; + + method_obj->method.param_count = (u8) + (method_flags & AML_METHOD_ARG_COUNT); + + method_obj->method.method_flags = (u8) + (method_flags & ~AML_METHOD_ARG_COUNT); + + if (method_flags & AML_METHOD_SERIALIZED) { + method_obj->method.sync_level = (u8) + ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); + } + + /* + * Now that it is complete, we can attach the new method object to + * the method Node (detaches/deletes any existing object) + */ + status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); + + /* + * Flag indicates AML buffer is dynamic, must be deleted later. + * Must be set only after attach above. + */ + node->flags |= ANOBJ_ALLOCATED_BUFFER; + + /* Remove local reference to the method object */ + + acpi_ut_remove_reference(method_obj); + return status; + +error_exit: + + ACPI_FREE(aml_buffer); + ACPI_FREE(method_obj); + return status; +} +ACPI_EXPORT_SYMBOL(acpi_install_method) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 60b76a3..c3b08d3 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -201,6 +201,8 @@ acpi_evaluate_object_typed(acpi_handle object, acpi_status acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer); +acpi_status acpi_install_method(u8 *buffer); + acpi_status acpi_get_next_object(acpi_object_type type, acpi_handle parent, -- cgit v0.10.2 From 3c59f96081259358d9d5d677f4839c36391806b6 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 10:51:53 +0800 Subject: ACPICA: Update Load() to use operation region interfaces Replace memory mapping with region access calls. Now, all region accesses go through the region handler as they should. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 0731fd6..eca6f63 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -47,6 +47,7 @@ #include "acnamesp.h" #include "actables.h" #include "acdispat.h" +#include "acevents.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exconfig") @@ -57,6 +58,10 @@ acpi_ex_add_table(u32 table_index, struct acpi_namespace_node *parent_node, union acpi_operand_object **ddb_handle); +static acpi_status +acpi_ex_region_read(union acpi_operand_object *obj_desc, + u32 length, u8 *buffer); + /******************************************************************************* * * FUNCTION: acpi_ex_add_table @@ -257,6 +262,48 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, /******************************************************************************* * + * FUNCTION: acpi_ex_region_read + * + * PARAMETERS: obj_desc - Region descriptor + * Length - Number of bytes to read + * Buffer - Pointer to where to put the data + * + * RETURN: Status + * + * DESCRIPTION: Read data from an operation region. The read starts from the + * beginning of the region. + * + ******************************************************************************/ + +static acpi_status +acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) +{ + acpi_status status; + acpi_integer value; + acpi_physical_address address; + u32 i; + + address = obj_desc->region.address; + + /* Bytewise reads */ + + for (i = 0; i < length; i++) { + status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, + address, 8, &value); + if (ACPI_FAILURE(status)) { + return status; + } + + *buffer = (u8)value; + buffer++; + address++; + } + + return AE_OK; +} + +/******************************************************************************* + * * FUNCTION: acpi_ex_load_op * * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be @@ -317,18 +364,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } } - /* - * Map the table header and get the actual table length. The region - * length is not guaranteed to be the same as the table length. - */ - table = acpi_os_map_memory(obj_desc->region.address, - sizeof(struct acpi_table_header)); + /* Get the table header first so we can get the table length */ + + table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); if (!table) { return_ACPI_STATUS(AE_NO_MEMORY); } + status = + acpi_ex_region_read(obj_desc, + sizeof(struct acpi_table_header), + ACPI_CAST_PTR(u8, table)); length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + ACPI_FREE(table); + + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Must have at least an ACPI table header */ @@ -337,10 +389,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } /* - * The memory region is not guaranteed to remain stable and we must - * copy the table to a local buffer. For example, the memory region - * is corrupted after suspend on some machines. Dynamically loaded - * tables are usually small, so this overhead is minimal. + * The original implementation simply mapped the table, with no copy. + * However, the memory region is not guaranteed to remain stable and + * we must copy the table to a local buffer. For example, the memory + * region is corrupted after suspend on some machines. Dynamically + * loaded tables are usually small, so this overhead is minimal. + * + * The latest implementation (5/2009) does not use a mapping at all. + * We use the low-level operation region interface to read the table + * instead of the obvious optimization of using a direct mapping. + * This maintains a consistent use of operation regions across the + * entire subsystem. This is important if additional processing must + * be performed in the (possibly user-installed) operation region + * handler. For example, acpi_exec and ASLTS depend on this. */ /* Allocate a buffer for the table */ @@ -350,17 +411,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_NO_MEMORY); } - /* Map the entire table and copy it */ + /* Read the entire table */ - table = acpi_os_map_memory(obj_desc->region.address, length); - if (!table) { + status = acpi_ex_region_read(obj_desc, length, + ACPI_CAST_PTR(u8, + table_desc.pointer)); + if (ACPI_FAILURE(status)) { ACPI_FREE(table_desc.pointer); - return_ACPI_STATUS(AE_NO_MEMORY); + return_ACPI_STATUS(status); } - ACPI_MEMCPY(table_desc.pointer, table, length); - acpi_os_unmap_memory(table, length); - table_desc.address = obj_desc->region.address; break; -- cgit v0.10.2 From f5407af3f271ed4cd6655cf30d419d77e0f8bfaa Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 10:56:52 +0800 Subject: ACPICA: Simplify internal operation region interface Changed address parameter to a simple offset. This removes the need for the caller to access the region object to obtain the physical address. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 07e2013..0bba148 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -139,7 +139,7 @@ acpi_status acpi_ev_initialize_op_regions(void); acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - acpi_physical_address address, + u32 region_offset, u32 bit_width, acpi_integer * value); acpi_status diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 538d632..98c7f9c 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -275,7 +275,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * * PARAMETERS: region_obj - Internal region object * Function - Read or Write operation - * Address - Where in the space to read or write + * region_offset - Where in the region to read or write * bit_width - Field width in bits (8, 16, 32, or 64) * Value - Pointer to in or out value, must be * full 64-bit acpi_integer @@ -290,7 +290,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - acpi_physical_address address, + u32 region_offset, u32 bit_width, acpi_integer * value) { acpi_status status; @@ -396,7 +396,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", ®ion_obj->region.handler->address_space, handler, - ACPI_FORMAT_NATIVE_UINT(address), + ACPI_FORMAT_NATIVE_UINT(region_obj->region.address + + region_offset), acpi_ut_get_region_name(region_obj->region. space_id))); @@ -412,8 +413,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* Call the handler */ - status = handler(function, address, bit_width, value, - handler_desc->address_space.context, + status = handler(function, + (region_obj->region.address + region_offset), + bit_width, value, handler_desc->address_space.context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index eca6f63..277fd60 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -280,23 +280,22 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) { acpi_status status; acpi_integer value; - acpi_physical_address address; + u32 region_offset = 0; u32 i; - address = obj_desc->region.address; - /* Bytewise reads */ for (i = 0; i < length; i++) { status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, - address, 8, &value); + region_offset, 8, + &value); if (ACPI_FAILURE(status)) { return status; } *buffer = (u8)value; buffer++; - address++; + region_offset++; } return AE_OK; diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 99cee61..d4075b8 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -222,7 +222,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, { acpi_status status; union acpi_operand_object *rgn_desc; - acpi_physical_address address; + u32 region_offset; ACPI_FUNCTION_TRACE(ex_access_region); @@ -243,7 +243,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, * 3) The current offset into the field */ rgn_desc = obj_desc->common_field.region_obj; - address = rgn_desc->region.address + + region_offset = obj_desc->common_field.base_byte_offset + field_datum_byte_offset; if ((function & ACPI_IO_MASK) == ACPI_READ) { @@ -260,16 +260,18 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, field_datum_byte_offset, ACPI_CAST_PTR(void, - address))); + (rgn_desc-> + region. + address + + region_offset)))); /* Invoke the appropriate address_space/op_region handler */ - status = acpi_ev_address_space_dispatch(rgn_desc, function, - address, - ACPI_MUL_8(obj_desc-> - common_field. - access_byte_width), - value); + status = + acpi_ev_address_space_dispatch(rgn_desc, function, region_offset, + ACPI_MUL_8(obj_desc->common_field. + access_byte_width), + value); if (ACPI_FAILURE(status)) { if (status == AE_NOT_IMPLEMENTED) { -- cgit v0.10.2 From c446eed6187addf9f76ee0028abed32393aef27e Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Thu, 21 May 2009 10:59:15 +0800 Subject: ACPICA: Eliminate extra call to NsGetParentNode Was called twice in the same function with the same parameter. Alex Chiang. Signed-off-by: Alex Chiang Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index dd33d8b..4071bad 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -162,6 +162,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_type) acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) { struct acpi_namespace_node *node; + struct acpi_namespace_node *parent_node; acpi_status status; if (!ret_handle) { @@ -189,12 +190,12 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) /* Get the parent entry */ - *ret_handle = - acpi_ns_convert_entry_to_handle(acpi_ns_get_parent_node(node)); + parent_node = acpi_ns_get_parent_node(node); + *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); /* Return exception if parent is null */ - if (!acpi_ns_get_parent_node(node)) { + if (!parent_node) { status = AE_NULL_ENTRY; } -- cgit v0.10.2 From 3362a6badb4fe75e198885b125b21ccf846861b4 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Thu, 21 May 2009 11:03:29 +0800 Subject: ACPICA: Region deletion: Ensure region object is removed from handler list Prevents a possible fault when a dynamic operation region is deleted. ACPICA BZ 507. http://acpica.org/bugzilla/show_bug.cgi?id=507 Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index a5ee23b..bc17103 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) union acpi_operand_object *handler_desc; union acpi_operand_object *second_desc; union acpi_operand_object *next_desc; + union acpi_operand_object **last_obj_ptr; ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); @@ -223,6 +224,26 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) */ handler_desc = object->region.handler; if (handler_desc) { + next_desc = + handler_desc->address_space.region_list; + last_obj_ptr = + &handler_desc->address_space.region_list; + + /* Remove the region object from the handler's list */ + + while (next_desc) { + if (next_desc == object) { + *last_obj_ptr = + next_desc->region.next; + break; + } + + /* Walk the linked list of handler */ + + last_obj_ptr = &next_desc->region.next; + next_desc = next_desc->region.next; + } + if (handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { -- cgit v0.10.2 From 0fb2787bf2fa5dbe02ffd61ca3ce842c50769573 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Tue, 26 May 2009 21:41:18 -0700 Subject: ixgbe: Fix build warning This patch fixes a build warning due to an unused label. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f9223ac..dff1da8 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5354,7 +5354,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, err_register: ixgbe_release_hw_control(adapter); -err_hw_init: ixgbe_clear_interrupt_scheme(adapter); err_sw_init: err_eeprom: -- cgit v0.10.2 From b1cd843be74ba0dcc6c42db7b11b76d63be149f6 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 11:05:03 +0800 Subject: ACPICA: Disable preservation of SCI enable bit (SCI_EN) Preserving this bit breaks some machines. Not preserving this bit seems to work OK in all cases, even though this goes against the ACPI spec. http://bugzilla.kernel.org/show_bug.cgi?id=13289 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 882b4b5..ee986ed 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -789,11 +789,14 @@ struct acpi_bit_register_info { /* For control registers, both ignored and reserved bits must be preserved */ /* - * The ACPI spec says to ignore PM1_CTL.SCI_EN (bit 0) - * but we need to be able to write ACPI_BITREG_SCI_ENABLE directly - * as a BIOS workaround on some machines. + * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the + * ACPI specification to be a "preserved" bit - "OSPM always preserves this + * bit position", section 4.7.3.2.1. However, on some machines the OS must + * write a one to this bit after resume for the machine to work properly. + * To enable this, we no longer attempt to preserve this bit. No machines + * are known to fail if the bit is not preserved. (May 2009) */ -#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bits 9 */ +#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bit 9 */ #define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ #define ACPI_PM1_CONTROL_PRESERVED_BITS \ (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) -- cgit v0.10.2 From d6a1cd4975a5ffaa21a961be04a469519edf50d6 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 21 May 2009 11:06:53 +0800 Subject: ACPICA: Update version to 20090521. Update version number. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index c3b08d3..82ec6a3 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -47,7 +47,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20090422 +#define ACPI_CA_VERSION 0x20090521 #include "actypes.h" #include "actbl.h" -- cgit v0.10.2 From 42da6994ca6d20ad1d4e30255dee98047db454e7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:19 +0000 Subject: gro: Open-code frags copy in skb_gro_receive gcc does a poor job at generating code for the memcpy of the frags array in skb_gro_receive, which is the primary purpose of that function when merging frags. In particular, it can't utilise the alignment information of the source and destination. This patch open-codes the copy so we process words instead of bytes. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d429c41..c88426b 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2673,6 +2673,9 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) if (skb_shinfo(p)->frag_list) goto merge; else if (skb_headlen(skb) <= skb_gro_offset(skb)) { + skb_frag_t *frag; + int i; + if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags > MAX_SKB_FRAGS) return -E2BIG; @@ -2682,9 +2685,9 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) skb_shinfo(skb)->frags[0].size -= skb_gro_offset(skb) - skb_headlen(skb); - memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags, - skb_shinfo(skb)->frags, - skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); + frag = skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + *frag++ = skb_shinfo(skb)->frags[i]; skb_shinfo(p)->nr_frags += skb_shinfo(skb)->nr_frags; skb_shinfo(skb)->nr_frags = 0; -- cgit v0.10.2 From 78a478d0efd9e86e5345b436e130497b4e5846e8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:21 +0000 Subject: gro: Inline skb_gro_header and cache frag0 virtual address The function skb_gro_header is called four times per packet which quickly adds up at 10Gb/s. This patch inlines it to allow better optimisations. Some architectures perform multiplication for page_address, which is done by each skb_gro_header invocation. This patch caches that value in skb->cb to avoid the unnecessary multiplications. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 586b71f..61890ed 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1008,6 +1008,9 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi, void netif_napi_del(struct napi_struct *napi); struct napi_gro_cb { + /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ + void *frag0; + /* This indicates where we are processing relative to skb->data. */ int data_offset; @@ -1107,9 +1110,9 @@ extern int dev_restart(struct net_device *dev); #ifdef CONFIG_NETPOLL_TRAP extern int netpoll_trap(void); #endif -extern void *skb_gro_header(struct sk_buff *skb, unsigned int hlen); extern int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb); +extern void skb_gro_reset_offset(struct sk_buff *skb); static inline unsigned int skb_gro_offset(const struct sk_buff *skb) { @@ -1126,23 +1129,28 @@ static inline void skb_gro_pull(struct sk_buff *skb, unsigned int len) NAPI_GRO_CB(skb)->data_offset += len; } -static inline void skb_gro_reset_offset(struct sk_buff *skb) +static inline void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) { - NAPI_GRO_CB(skb)->data_offset = 0; + unsigned int offset = skb_gro_offset(skb); + + hlen += offset; + if (!NAPI_GRO_CB(skb)->frag0 || + unlikely(skb_shinfo(skb)->frags[0].size + skb_headlen(skb) < hlen)) + return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; + + return NAPI_GRO_CB(skb)->frag0 + offset; } static inline void *skb_gro_mac_header(struct sk_buff *skb) { return skb_headlen(skb) ? skb_mac_header(skb) : - page_address(skb_shinfo(skb)->frags[0].page) + - skb_shinfo(skb)->frags[0].page_offset; + NAPI_GRO_CB(skb)->frag0; } static inline void *skb_gro_network_header(struct sk_buff *skb) { return skb_headlen(skb) ? skb_network_header(skb) : - page_address(skb_shinfo(skb)->frags[0].page) + - skb_shinfo(skb)->frags[0].page_offset + skb_network_offset(skb); + NAPI_GRO_CB(skb)->frag0 + skb_network_offset(skb); } static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, diff --git a/net/core/dev.c b/net/core/dev.c index 5eb3e48..bdb1a73 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2390,21 +2390,6 @@ void napi_gro_flush(struct napi_struct *napi) } EXPORT_SYMBOL(napi_gro_flush); -void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) -{ - unsigned int offset = skb_gro_offset(skb); - - hlen += offset; - if (unlikely(skb_headlen(skb) || - skb_shinfo(skb)->frags[0].size < hlen || - PageHighMem(skb_shinfo(skb)->frags[0].page))) - return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; - - return page_address(skb_shinfo(skb)->frags[0].page) + - skb_shinfo(skb)->frags[0].page_offset + offset; -} -EXPORT_SYMBOL(skb_gro_header); - int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff **pp = NULL; @@ -2520,6 +2505,18 @@ int napi_skb_finish(int ret, struct sk_buff *skb) } EXPORT_SYMBOL(napi_skb_finish); +void skb_gro_reset_offset(struct sk_buff *skb) +{ + NAPI_GRO_CB(skb)->data_offset = 0; + NAPI_GRO_CB(skb)->frag0 = NULL; + + if (!skb_headlen(skb) && !PageHighMem(skb_shinfo(skb)->frags[0].page)) + NAPI_GRO_CB(skb)->frag0 = + page_address(skb_shinfo(skb)->frags[0].page) + + skb_shinfo(skb)->frags[0].page_offset; +} +EXPORT_SYMBOL(skb_gro_reset_offset); + int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { skb_gro_reset_offset(skb); -- cgit v0.10.2 From 67147ba99aeb48f2863e03b68e090088a34c1b5d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:22 +0000 Subject: gro: Localise offset/headlen in skb_gro_offset This patch stores the offset/headlen in local variables as they're used repeatedly in skb_gro_offset. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c88426b..168e949 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2666,13 +2666,15 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) struct sk_buff *nskb; unsigned int headroom; unsigned int len = skb_gro_len(skb); + unsigned int offset = skb_gro_offset(skb); + unsigned int headlen = skb_headlen(skb); if (p->len + len >= 65536) return -E2BIG; if (skb_shinfo(p)->frag_list) goto merge; - else if (skb_headlen(skb) <= skb_gro_offset(skb)) { + else if (headlen <= offset) { skb_frag_t *frag; int i; @@ -2680,10 +2682,8 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) MAX_SKB_FRAGS) return -E2BIG; - skb_shinfo(skb)->frags[0].page_offset += - skb_gro_offset(skb) - skb_headlen(skb); - skb_shinfo(skb)->frags[0].size -= - skb_gro_offset(skb) - skb_headlen(skb); + skb_shinfo(skb)->frags[0].page_offset += offset - headlen; + skb_shinfo(skb)->frags[0].size -= offset - headlen; frag = skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) @@ -2736,16 +2736,13 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) p = nskb; merge: - if (skb_gro_offset(skb) > skb_headlen(skb)) { - skb_shinfo(skb)->frags[0].page_offset += - skb_gro_offset(skb) - skb_headlen(skb); - skb_shinfo(skb)->frags[0].size -= - skb_gro_offset(skb) - skb_headlen(skb); - skb_gro_reset_offset(skb); - skb_gro_pull(skb, skb_headlen(skb)); + if (offset > headlen) { + skb_shinfo(skb)->frags[0].page_offset += offset - headlen; + skb_shinfo(skb)->frags[0].size -= offset - headlen; + offset = headlen; } - __skb_pull(skb, skb_gro_offset(skb)); + __skb_pull(skb, offset); p->prev->next = skb; p->prev = skb; -- cgit v0.10.2 From 78d3fd0b7de844a6dad56e9620fc9d2271b32ab9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:23 +0000 Subject: gro: Only use skb_gro_header for completely non-linear packets Currently skb_gro_header is used for packets which put the hardware header in skb->data with the rest in frags. Since the drivers that need this optimisation all provide completely non-linear packets, we can gain extra optimisations by only performing the frag0 optimisation for completely non-linear packets. In particular, we can simply test frag0 (instead of skb_headlen) to see whether the optimisation is in force. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 61890ed..d1afc3b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1135,22 +1135,23 @@ static inline void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) hlen += offset; if (!NAPI_GRO_CB(skb)->frag0 || - unlikely(skb_shinfo(skb)->frags[0].size + skb_headlen(skb) < hlen)) + unlikely(skb_shinfo(skb)->frags[0].size < hlen)) { + NAPI_GRO_CB(skb)->frag0 = NULL; return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; + } return NAPI_GRO_CB(skb)->frag0 + offset; } static inline void *skb_gro_mac_header(struct sk_buff *skb) { - return skb_headlen(skb) ? skb_mac_header(skb) : - NAPI_GRO_CB(skb)->frag0; + return NAPI_GRO_CB(skb)->frag0 ?: skb_mac_header(skb); } static inline void *skb_gro_network_header(struct sk_buff *skb) { - return skb_headlen(skb) ? skb_network_header(skb) : - NAPI_GRO_CB(skb)->frag0 + skb_network_offset(skb); + return (NAPI_GRO_CB(skb)->frag0 ?: skb->data) + + skb_network_offset(skb); } static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, diff --git a/net/core/dev.c b/net/core/dev.c index bdb1a73..f9d90c5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2510,7 +2510,8 @@ void skb_gro_reset_offset(struct sk_buff *skb) NAPI_GRO_CB(skb)->data_offset = 0; NAPI_GRO_CB(skb)->frag0 = NULL; - if (!skb_headlen(skb) && !PageHighMem(skb_shinfo(skb)->frags[0].page)) + if (skb->mac_header == skb->tail && + !PageHighMem(skb_shinfo(skb)->frags[0].page)) NAPI_GRO_CB(skb)->frag0 = page_address(skb_shinfo(skb)->frags[0].page) + skb_shinfo(skb)->frags[0].page_offset; -- cgit v0.10.2 From 745898eaf0eb7a04a56dec1188d9148259510863 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:24 +0000 Subject: tcp: Optimise GRO port comparisons Instead of doing two 16-bit operations for the source/destination ports, we can do one 32-bit operation to take care both. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7a0f0b2..ff6adec 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2544,7 +2544,7 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) th2 = tcp_hdr(p); - if ((th->source ^ th2->source) | (th->dest ^ th2->dest)) { + if (*(u32 *)&th->source ^ *(u32 *)&th2->source) { NAPI_GRO_CB(p)->same_flow = 0; continue; } -- cgit v0.10.2 From 4a9a2968a17eae42ef5dffca8b37534c864e30cc Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:25 +0000 Subject: tcp: Remove unnecessary window comparisons for GRO The window has already been checked as part of the flag word so there is no need to check it explicitly. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ff6adec..313960e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2559,7 +2559,7 @@ found: flush |= flags & TCP_FLAG_CWR; flush |= (flags ^ tcp_flag_word(th2)) & ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH); - flush |= (th->ack_seq ^ th2->ack_seq) | (th->window ^ th2->window); + flush |= th->ack_seq ^ th2->ack_seq; for (i = sizeof(*th); !flush && i < thlen; i += 4) flush |= *(u32 *)((u8 *)th + i) ^ *(u32 *)((u8 *)th2 + i); -- cgit v0.10.2 From 30a3ae30c775e2723f86ef70746ad3cb4404a4c9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:26 +0000 Subject: tcp: Optimise len/mss comparison Instead of checking len > mss || len == 0, we can accomplish both by checking (len - 1) > mss using the unsigned wraparound. At nearly a million times a second, this might just help. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 313960e..68342d4 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2566,7 +2566,7 @@ found: mss = skb_shinfo(p)->gso_size; - flush |= (len > mss) | !len; + flush |= (len - 1) >= mss; flush |= (ntohl(th2->seq) + skb_gro_len(p)) ^ ntohl(th->seq); if (flush || skb_gro_receive(head, skb)) { -- cgit v0.10.2 From 7489594cb249aeb178287c9a43a9e4f366044259 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:27 +0000 Subject: gro: Optimise length comparison in skb_gro_header By caching frag0_len, we can avoid checking both frag0 and the length separately in skb_gro_header. This helps as skb_gro_header is called four times per packet which amounts to a few million times at 10Gb/s. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d1afc3b..2e44a04 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1011,6 +1011,9 @@ struct napi_gro_cb { /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ void *frag0; + /* Length of frag0. */ + unsigned int frag0_len; + /* This indicates where we are processing relative to skb->data. */ int data_offset; @@ -1134,9 +1137,9 @@ static inline void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) unsigned int offset = skb_gro_offset(skb); hlen += offset; - if (!NAPI_GRO_CB(skb)->frag0 || - unlikely(skb_shinfo(skb)->frags[0].size < hlen)) { + if (NAPI_GRO_CB(skb)->frag0_len < hlen) { NAPI_GRO_CB(skb)->frag0 = NULL; + NAPI_GRO_CB(skb)->frag0_len = 0; return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; } diff --git a/net/core/dev.c b/net/core/dev.c index f9d90c5..b1722a2 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2509,12 +2509,15 @@ void skb_gro_reset_offset(struct sk_buff *skb) { NAPI_GRO_CB(skb)->data_offset = 0; NAPI_GRO_CB(skb)->frag0 = NULL; + NAPI_GRO_CB(skb)->frag0_len = 0; if (skb->mac_header == skb->tail && - !PageHighMem(skb_shinfo(skb)->frags[0].page)) + !PageHighMem(skb_shinfo(skb)->frags[0].page)) { NAPI_GRO_CB(skb)->frag0 = page_address(skb_shinfo(skb)->frags[0].page) + skb_shinfo(skb)->frags[0].page_offset; + NAPI_GRO_CB(skb)->frag0_len = skb_shinfo(skb)->frags[0].size; + } } EXPORT_SYMBOL(skb_gro_reset_offset); -- cgit v0.10.2 From a5b1cf288d4200506ab62fbb86cc81ace948a306 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:28 +0000 Subject: gro: Avoid unnecessary comparison after skb_gro_header For the overwhelming majority of cases, skb_gro_header's return value cannot be NULL. Yet we must check it because of its current form. This patch splits it up into multiple functions in order to avoid this. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2e44a04..371ece5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1132,18 +1132,23 @@ static inline void skb_gro_pull(struct sk_buff *skb, unsigned int len) NAPI_GRO_CB(skb)->data_offset += len; } -static inline void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) +static inline void *skb_gro_header_fast(struct sk_buff *skb, + unsigned int offset) { - unsigned int offset = skb_gro_offset(skb); + return NAPI_GRO_CB(skb)->frag0 + offset; +} - hlen += offset; - if (NAPI_GRO_CB(skb)->frag0_len < hlen) { - NAPI_GRO_CB(skb)->frag0 = NULL; - NAPI_GRO_CB(skb)->frag0_len = 0; - return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; - } +static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen) +{ + return NAPI_GRO_CB(skb)->frag0_len < hlen; +} - return NAPI_GRO_CB(skb)->frag0 + offset; +static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen, + unsigned int offset) +{ + NAPI_GRO_CB(skb)->frag0 = NULL; + NAPI_GRO_CB(skb)->frag0_len = 0; + return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; } static inline void *skb_gro_mac_header(struct sk_buff *skb) diff --git a/net/core/dev.c b/net/core/dev.c index b1722a2..cd29e61 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2590,17 +2590,24 @@ struct sk_buff *napi_frags_skb(struct napi_struct *napi) { struct sk_buff *skb = napi->skb; struct ethhdr *eth; + unsigned int hlen; + unsigned int off; napi->skb = NULL; skb_reset_mac_header(skb); skb_gro_reset_offset(skb); - eth = skb_gro_header(skb, sizeof(*eth)); - if (!eth) { - napi_reuse_skb(napi, skb); - skb = NULL; - goto out; + off = skb_gro_offset(skb); + hlen = off + sizeof(*eth); + eth = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + eth = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!eth)) { + napi_reuse_skb(napi, skb); + skb = NULL; + goto out; + } } skb_gro_pull(skb, sizeof(*eth)); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 1706896..644cc55 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1246,13 +1246,20 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff **pp = NULL; struct sk_buff *p; struct iphdr *iph; + unsigned int hlen; + unsigned int off; int flush = 1; int proto; int id; - iph = skb_gro_header(skb, sizeof(*iph)); - if (unlikely(!iph)) - goto out; + off = skb_gro_offset(skb); + hlen = off + sizeof(*iph); + iph = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + iph = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!iph)) + goto out; + } proto = iph->protocol & (MAX_INET_PROTOS - 1); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 68342d4..c3dcec5 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2518,20 +2518,30 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) unsigned int thlen; unsigned int flags; unsigned int mss = 1; + unsigned int hlen; + unsigned int off; int flush = 1; int i; - th = skb_gro_header(skb, sizeof(*th)); - if (unlikely(!th)) - goto out; + off = skb_gro_offset(skb); + hlen = off + sizeof(*th); + th = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + th = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!th)) + goto out; + } thlen = th->doff * 4; if (thlen < sizeof(*th)) goto out; - th = skb_gro_header(skb, thlen); - if (unlikely(!th)) - goto out; + hlen = off + thlen; + if (skb_gro_header_hard(skb, hlen)) { + th = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!th)) + goto out; + } skb_gro_pull(skb, thlen); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 61f5538..b6215be 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -817,13 +817,20 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, struct sk_buff *p; struct ipv6hdr *iph; unsigned int nlen; + unsigned int hlen; + unsigned int off; int flush = 1; int proto; __wsum csum; - iph = skb_gro_header(skb, sizeof(*iph)); - if (unlikely(!iph)) - goto out; + off = skb_gro_offset(skb); + hlen = off + sizeof(*iph); + iph = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + iph = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!iph)) + goto out; + } skb_gro_pull(skb, sizeof(*iph)); skb_set_transport_header(skb, skb_gro_offset(skb)); -- cgit v0.10.2 From 1075f3f65d0e0f49351b7d4310e9f94483972a51 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:29 +0000 Subject: ipv4: Use 32-bit loads for ID and length in GRO This patch optimises the IPv4 GRO code by using 32-bit loads (instead of 16-bit ones) on the ID and length checks in the receive function. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 644cc55..5abee4c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1248,9 +1248,9 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, struct iphdr *iph; unsigned int hlen; unsigned int off; + unsigned int id; int flush = 1; int proto; - int id; off = skb_gro_offset(skb); hlen = off + sizeof(*iph); @@ -1274,9 +1274,9 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) goto out_unlock; - flush = ntohs(iph->tot_len) != skb_gro_len(skb) || - iph->frag_off != htons(IP_DF); - id = ntohs(iph->id); + id = ntohl(*(u32 *)&iph->id); + flush = (u16)((ntohl(*(u32 *)iph) ^ skb_gro_len(skb)) | (id ^ IP_DF)); + id >>= 16; for (p = *head; p; p = p->next) { struct iphdr *iph2; -- cgit v0.10.2 From cb18978cbf454c236db5e4191a12ef71eef9b3a0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:31 +0000 Subject: gro: Open-code final pskb_may_pull As we know the only packets which need the final pskb_may_pull are completely non-linear, and have all the required bits in frag0, we can perform a straight memcpy instead of going through pskb_may_pull and doing skb_copy_bits. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index cd29e61..ed4550f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2452,10 +2452,25 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) ret = GRO_HELD; pull: - if (unlikely(!pskb_may_pull(skb, skb_gro_offset(skb)))) { - if (napi->gro_list == skb) - napi->gro_list = skb->next; - ret = GRO_DROP; + if (skb_headlen(skb) < skb_gro_offset(skb)) { + int grow = skb_gro_offset(skb) - skb_headlen(skb); + + BUG_ON(skb->end - skb->tail < grow); + + memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow); + + skb->tail += grow; + skb->data_len -= grow; + + skb_shinfo(skb)->frags[0].page_offset += grow; + skb_shinfo(skb)->frags[0].size -= grow; + + if (unlikely(!skb_shinfo(skb)->frags[0].size)) { + put_page(skb_shinfo(skb)->frags[0].page); + memmove(skb_shinfo(skb)->frags, + skb_shinfo(skb)->frags + 1, + --skb_shinfo(skb)->nr_frags); + } } ok: -- cgit v0.10.2 From 66e92fcf1ded5dd0da30d016ed47882eb183ec71 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:32 +0000 Subject: gro: Nasty optimisations for page frags in skb_gro_receive This patch reverses the direction of the frags array copy in skb_gro_receive in order simplify the loop conditional. It also avoids touching the first element of the original frags array. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 168e949..19afb18 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2676,21 +2676,26 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) goto merge; else if (headlen <= offset) { skb_frag_t *frag; - int i; + skb_frag_t *frag2; + int i = skb_shinfo(skb)->nr_frags; + int nr_frags = skb_shinfo(p)->nr_frags + i; + + offset -= headlen; - if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags > - MAX_SKB_FRAGS) + if (nr_frags > MAX_SKB_FRAGS) return -E2BIG; - skb_shinfo(skb)->frags[0].page_offset += offset - headlen; - skb_shinfo(skb)->frags[0].size -= offset - headlen; + skb_shinfo(p)->nr_frags = nr_frags; + skb_shinfo(skb)->nr_frags = 0; - frag = skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - *frag++ = skb_shinfo(skb)->frags[i]; + frag = skb_shinfo(p)->frags + nr_frags; + frag2 = skb_shinfo(skb)->frags + i; + do { + *--frag = *--frag2; + } while (--i); - skb_shinfo(p)->nr_frags += skb_shinfo(skb)->nr_frags; - skb_shinfo(skb)->nr_frags = 0; + frag->page_offset += offset; + frag->size -= offset; skb->truesize -= skb->data_len; skb->len -= skb->data_len; -- cgit v0.10.2 From 9aaa156cf9b7e9d9ed899f254283b91c4e3c36c8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:33 +0000 Subject: gro: Store shinfo in local variable in skb_gro_receive This patch stores the two shinfo pointers in local variables because they're used over and over again in skb_gro_receive. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 19afb18..8e815e6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2664,6 +2664,8 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) { struct sk_buff *p = *head; struct sk_buff *nskb; + struct skb_shared_info *skbinfo = skb_shinfo(skb); + struct skb_shared_info *pinfo = skb_shinfo(p); unsigned int headroom; unsigned int len = skb_gro_len(skb); unsigned int offset = skb_gro_offset(skb); @@ -2672,24 +2674,24 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) if (p->len + len >= 65536) return -E2BIG; - if (skb_shinfo(p)->frag_list) + if (pinfo->frag_list) goto merge; else if (headlen <= offset) { skb_frag_t *frag; skb_frag_t *frag2; - int i = skb_shinfo(skb)->nr_frags; - int nr_frags = skb_shinfo(p)->nr_frags + i; + int i = skbinfo->nr_frags; + int nr_frags = pinfo->nr_frags + i; offset -= headlen; if (nr_frags > MAX_SKB_FRAGS) return -E2BIG; - skb_shinfo(p)->nr_frags = nr_frags; - skb_shinfo(skb)->nr_frags = 0; + pinfo->nr_frags = nr_frags; + skbinfo->nr_frags = 0; - frag = skb_shinfo(p)->frags + nr_frags; - frag2 = skb_shinfo(skb)->frags + i; + frag = pinfo->frags + nr_frags; + frag2 = skbinfo->frags + i; do { *--frag = *--frag2; } while (--i); @@ -2726,7 +2728,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p); skb_shinfo(nskb)->frag_list = p; - skb_shinfo(nskb)->gso_size = skb_shinfo(p)->gso_size; + skb_shinfo(nskb)->gso_size = pinfo->gso_size; skb_header_release(p); nskb->prev = p; @@ -2742,8 +2744,8 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) merge: if (offset > headlen) { - skb_shinfo(skb)->frags[0].page_offset += offset - headlen; - skb_shinfo(skb)->frags[0].size -= offset - headlen; + skbinfo->frags[0].page_offset += offset - headlen; + skbinfo->frags[0].size -= offset - headlen; offset = headlen; } -- cgit v0.10.2 From a2a804cddfe65f18f903985e8a8d04c7c9eec354 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 26 May 2009 18:50:34 +0000 Subject: tcp: Do not check flush when comparing options for GRO There is no need to repeatedly check flush when comparing TCP options for GRO as it will be false 99% of the time where it matters. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c3dcec5..0fb8b44 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2570,7 +2570,7 @@ found: flush |= (flags ^ tcp_flag_word(th2)) & ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH); flush |= th->ack_seq ^ th2->ack_seq; - for (i = sizeof(*th); !flush && i < thlen; i += 4) + for (i = sizeof(*th); i < thlen; i += 4) flush |= *(u32 *)((u8 *)th + i) ^ *(u32 *)((u8 *)th2 + i); -- cgit v0.10.2 From a17c859849402315613a0015ac8fbf101acf0cc1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 27 May 2009 17:50:35 +0200 Subject: netfilter: conntrack: add support for DCCP handshake sequence to ctnetlink This patch adds CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ that exposes the u64 handshake sequence number to user-space. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 1a865e4..ed4ef8d 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -101,6 +101,7 @@ enum ctattr_protoinfo_dccp { CTA_PROTOINFO_DCCP_UNSPEC, CTA_PROTOINFO_DCCP_STATE, CTA_PROTOINFO_DCCP_ROLE, + CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, __CTA_PROTOINFO_DCCP_MAX, }; #define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1) diff --git a/include/net/netlink.h b/include/net/netlink.h index eddb502..007bdb0 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -940,6 +940,15 @@ static inline u64 nla_get_u64(const struct nlattr *nla) } /** + * nla_get_be64 - return payload of __be64 attribute + * @nla: __be64 netlink attribute + */ +static inline __be64 nla_get_be64(const struct nlattr *nla) +{ + return *(__be64 *) nla_data(nla); +} + +/** * nla_get_flag - return payload of flag attribute * @nla: flag netlink attribute */ diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 8e757dd..11801c4 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -635,6 +635,8 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state); NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_ROLE, ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]); + NLA_PUT_BE64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, + cpu_to_be64(ct->proto.dccp.handshake_seq)); nla_nest_end(skb, nest_parms); read_unlock_bh(&dccp_lock); return 0; @@ -647,6 +649,7 @@ nla_put_failure: static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 }, + [CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 }, }; static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) @@ -679,6 +682,10 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER; ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT; } + if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) { + ct->proto.dccp.handshake_seq = + be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ])); + } write_unlock_bh(&dccp_lock); return 0; } -- cgit v0.10.2 From 824fb38e99cd5334629b340a2ae1ba0917cc35ab Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 26 May 2009 23:38:10 +0000 Subject: r6040: check and update media status This patch removes the not-that-useful message in the r6040_timer which prints the PHY status. Instead replace it with a call to mii_check_media which will update the link status and print it on startup. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 1508b124..ed63d23 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -401,6 +401,9 @@ static void r6040_init_mac_regs(struct net_device *dev) * we may got called by r6040_tx_timeout which has left * some unsent tx buffers */ iowrite16(0x01, ioaddr + MTPR); + + /* Check media */ + mii_check_media(&lp->mii_if, 1, 1); } static void r6040_tx_timeout(struct net_device *dev) @@ -528,6 +531,8 @@ static int r6040_phy_mode_chk(struct net_device *dev) phy_dat = 0x0000; } + mii_check_media(&lp->mii_if, 0, 1); + return phy_dat; }; @@ -810,7 +815,6 @@ static void r6040_timer(unsigned long data) lp->phy_mode = phy_mode; lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode; iowrite16(lp->mcr0, ioaddr); - printk(KERN_INFO "Link Change %x \n", ioread16(ioaddr)); } /* Timer active again */ -- cgit v0.10.2 From 0bb32417ff0f6ac385e4eec3ef6641950bbb3694 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 27 May 2009 00:55:08 +0000 Subject: bridge: avoid an extra space in br_fdb_update() Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index a48f5ef..cb3e97b 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -398,7 +398,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, if (unlikely(fdb->is_local)) { if (net_ratelimit()) printk(KERN_WARNING "%s: received packet with " - " own address as source address\n", + "own address as source address\n", source->dev->name); } else { /* fastpath: update of existing entry */ -- cgit v0.10.2 From 1ce8e7b57b3a4527ef83da1c5c7bd8a6b9d87b56 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 May 2009 04:42:37 +0000 Subject: net: ALIGN/PTR_ALIGN cleanup in alloc_netdev_mq()/netdev_priv() Use ALIGN() and PTR_ALIGN() macros instead of handcoding them. Get rid of NETDEV_ALIGN_CONST ugly define Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 371ece5..14efce3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -905,7 +905,6 @@ struct net_device #define to_net_dev(d) container_of(d, struct net_device, dev) #define NETDEV_ALIGN 32 -#define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) static inline struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev, @@ -976,9 +975,7 @@ static inline bool netdev_uses_trailer_tags(struct net_device *dev) */ static inline void *netdev_priv(const struct net_device *dev) { - return (char *)dev + ((sizeof(struct net_device) - + NETDEV_ALIGN_CONST) - & ~NETDEV_ALIGN_CONST); + return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN); } /* Set the sysfs physical device reference for the network logical device diff --git a/net/core/dev.c b/net/core/dev.c index ed4550f..32ceee1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4988,18 +4988,18 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, struct netdev_queue *tx; struct net_device *dev; size_t alloc_size; - void *p; + struct net_device *p; BUG_ON(strlen(name) >= sizeof(dev->name)); alloc_size = sizeof(struct net_device); if (sizeof_priv) { /* ensure 32-byte alignment of private area */ - alloc_size = (alloc_size + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; + alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); alloc_size += sizeof_priv; } /* ensure 32-byte alignment of whole construct */ - alloc_size += NETDEV_ALIGN_CONST; + alloc_size += NETDEV_ALIGN - 1; p = kzalloc(alloc_size, GFP_KERNEL); if (!p) { @@ -5014,8 +5014,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, goto free_p; } - dev = (struct net_device *) - (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + dev = PTR_ALIGN(p, NETDEV_ALIGN); dev->padded = (char *)dev - (char *)p; if (dev_addr_init(dev)) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6b7e92e..e37770c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -735,9 +735,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, * +-------------------------+ * */ - priv_size = ((sizeof(struct ieee80211_local) + - NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + - priv_data_len; + priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; wiphy = wiphy_new(&mac80211_config_ops, priv_size); @@ -754,9 +752,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.wiphy = wiphy; - local->hw.priv = (char *)local + - ((sizeof(struct ieee80211_local) + - NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); BUG_ON(!ops->tx); BUG_ON(!ops->start); -- cgit v0.10.2 From 553e2335625e6c96cb6d76c0d63cfc1034747614 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 May 2009 10:34:50 +0000 Subject: net: use netdev stats in b44, sundance, via-rhine and via-velocity Use struct net_device_stats provided in struct net_device instead of private ones. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/b44.c b/drivers/net/b44.c index b70b81e..36d4d37 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -782,7 +782,7 @@ static int b44_rx(struct b44 *bp, int budget) drop_it: b44_recycle_rx(bp, cons, bp->rx_prod); drop_it_no_recycle: - bp->stats.rx_dropped++; + bp->dev->stats.rx_dropped++; goto next_pkt; } @@ -1647,7 +1647,7 @@ static int b44_close(struct net_device *dev) static struct net_device_stats *b44_get_stats(struct net_device *dev) { struct b44 *bp = netdev_priv(dev); - struct net_device_stats *nstat = &bp->stats; + struct net_device_stats *nstat = &dev->stats; struct b44_hw_stats *hwstat = &bp->hw_stats; /* Convert HW stats into netdevice stats. */ diff --git a/drivers/net/b44.h b/drivers/net/b44.h index e678498..0443f68 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -384,7 +384,6 @@ struct b44 { struct timer_list timer; - struct net_device_stats stats; struct b44_hw_stats hw_stats; struct ssb_device *sdev; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index c399b19..545f81b 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -369,7 +369,6 @@ struct netdev_private { struct sk_buff* tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_ring_dma; dma_addr_t rx_ring_dma; - struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; @@ -975,7 +974,7 @@ static void tx_timeout(struct net_device *dev) dev->if_port = 0; dev->trans_start = jiffies; - np->stats.tx_errors++; + dev->stats.tx_errors++; if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { netif_wake_queue(dev); } @@ -1123,7 +1122,7 @@ reset_tx (struct net_device *dev) else dev_kfree_skb (skb); np->tx_skbuff[i] = NULL; - np->stats.tx_dropped++; + dev->stats.tx_dropped++; } } np->cur_tx = np->dirty_tx = 0; @@ -1181,15 +1180,15 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) if (netif_msg_tx_err(np)) printk("%s: Transmit error status %4.4x.\n", dev->name, tx_status); - np->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & 0x10) - np->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & 0x08) - np->stats.collisions++; + dev->stats.collisions++; if (tx_status & 0x04) - np->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & 0x02) - np->stats.tx_window_errors++; + dev->stats.tx_window_errors++; /* ** This reset has been verified on @@ -1313,11 +1312,15 @@ static void rx_poll(unsigned long data) if (netif_msg_rx_err(np)) printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", frame_status); - np->stats.rx_errors++; - if (frame_status & 0x00100000) np->stats.rx_length_errors++; - if (frame_status & 0x00010000) np->stats.rx_fifo_errors++; - if (frame_status & 0x00060000) np->stats.rx_frame_errors++; - if (frame_status & 0x00080000) np->stats.rx_crc_errors++; + dev->stats.rx_errors++; + if (frame_status & 0x00100000) + dev->stats.rx_length_errors++; + if (frame_status & 0x00010000) + dev->stats.rx_fifo_errors++; + if (frame_status & 0x00060000) + dev->stats.rx_frame_errors++; + if (frame_status & 0x00080000) + dev->stats.rx_crc_errors++; if (frame_status & 0x00100000) { printk(KERN_WARNING "%s: Oversized Ethernet frame," " status %8.8x.\n", @@ -1485,22 +1488,22 @@ static struct net_device_stats *get_stats(struct net_device *dev) the vulnerability window is very small and statistics are non-critical. */ /* The chip only need report frame silently dropped. */ - np->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); - np->stats.tx_packets += ioread16(ioaddr + TxFramesOK); - np->stats.rx_packets += ioread16(ioaddr + RxFramesOK); - np->stats.collisions += ioread8(ioaddr + StatsLateColl); - np->stats.collisions += ioread8(ioaddr + StatsMultiColl); - np->stats.collisions += ioread8(ioaddr + StatsOneColl); - np->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); + dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); + dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK); + dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK); + dev->stats.collisions += ioread8(ioaddr + StatsLateColl); + dev->stats.collisions += ioread8(ioaddr + StatsMultiColl); + dev->stats.collisions += ioread8(ioaddr + StatsOneColl); + dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); ioread8(ioaddr + StatsTxDefer); for (i = StatsTxDefer; i <= StatsMcastRx; i++) ioread8(ioaddr + i); - np->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); - np->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; - np->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); - np->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; - return &np->stats; + return &dev->stats; } static void set_rx_mode(struct net_device *dev) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 45daba7..d3489a3 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -388,7 +388,6 @@ struct rhine_private { long pioaddr; struct net_device *dev; struct napi_struct napi; - struct net_device_stats stats; spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ @@ -1209,7 +1208,7 @@ static void rhine_tx_timeout(struct net_device *dev) enable_irq(rp->pdev->irq); dev->trans_start = jiffies; - rp->stats.tx_errors++; + dev->stats.tx_errors++; netif_wake_queue(dev); } @@ -1237,7 +1236,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) /* packet too long, drop it */ dev_kfree_skb(skb); rp->tx_skbuff[entry] = NULL; - rp->stats.tx_dropped++; + dev->stats.tx_dropped++; return 0; } @@ -1378,29 +1377,33 @@ static void rhine_tx(struct net_device *dev) printk(KERN_DEBUG "%s: Transmit error, " "Tx status %8.8x.\n", dev->name, txstatus); - rp->stats.tx_errors++; - if (txstatus & 0x0400) rp->stats.tx_carrier_errors++; - if (txstatus & 0x0200) rp->stats.tx_window_errors++; - if (txstatus & 0x0100) rp->stats.tx_aborted_errors++; - if (txstatus & 0x0080) rp->stats.tx_heartbeat_errors++; + dev->stats.tx_errors++; + if (txstatus & 0x0400) + dev->stats.tx_carrier_errors++; + if (txstatus & 0x0200) + dev->stats.tx_window_errors++; + if (txstatus & 0x0100) + dev->stats.tx_aborted_errors++; + if (txstatus & 0x0080) + dev->stats.tx_heartbeat_errors++; if (((rp->quirks & rqRhineI) && txstatus & 0x0002) || (txstatus & 0x0800) || (txstatus & 0x1000)) { - rp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); break; /* Keep the skb - we try again */ } /* Transmitter restarted in 'abnormal' handler. */ } else { if (rp->quirks & rqRhineI) - rp->stats.collisions += (txstatus >> 3) & 0x0F; + dev->stats.collisions += (txstatus >> 3) & 0x0F; else - rp->stats.collisions += txstatus & 0x0F; + dev->stats.collisions += txstatus & 0x0F; if (debug > 6) printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", (txstatus >> 3) & 0xF, txstatus & 0xF); - rp->stats.tx_bytes += rp->tx_skbuff[entry]->len; - rp->stats.tx_packets++; + dev->stats.tx_bytes += rp->tx_skbuff[entry]->len; + dev->stats.tx_packets++; } /* Free the original skb. */ if (rp->tx_skbuff_dma[entry]) { @@ -1455,21 +1458,24 @@ static int rhine_rx(struct net_device *dev, int limit) printk(KERN_WARNING "%s: Oversized Ethernet " "frame %p vs %p.\n", dev->name, rp->rx_head_desc, &rp->rx_ring[entry]); - rp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) printk(KERN_DEBUG "rhine_rx() Rx " "error was %8.8x.\n", desc_status); - rp->stats.rx_errors++; - if (desc_status & 0x0030) rp->stats.rx_length_errors++; - if (desc_status & 0x0048) rp->stats.rx_fifo_errors++; - if (desc_status & 0x0004) rp->stats.rx_frame_errors++; + dev->stats.rx_errors++; + if (desc_status & 0x0030) + dev->stats.rx_length_errors++; + if (desc_status & 0x0048) + dev->stats.rx_fifo_errors++; + if (desc_status & 0x0004) + dev->stats.rx_frame_errors++; if (desc_status & 0x0002) { /* this can also be updated outside the interrupt handler */ spin_lock(&rp->lock); - rp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; spin_unlock(&rp->lock); } } @@ -1513,8 +1519,8 @@ static int rhine_rx(struct net_device *dev, int limit) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - rp->stats.rx_bytes += pkt_len; - rp->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; } entry = (++rp->cur_rx) % RX_RING_SIZE; rp->rx_head_desc = &rp->rx_ring[entry]; @@ -1599,8 +1605,8 @@ static void rhine_error(struct net_device *dev, int intr_status) if (intr_status & IntrLinkChange) rhine_check_media(dev, 0); if (intr_status & IntrStatsMax) { - rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); + dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); + dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); clear_tally_counters(ioaddr); } if (intr_status & IntrTxAborted) { @@ -1654,12 +1660,12 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev) unsigned long flags; spin_lock_irqsave(&rp->lock, flags); - rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); + dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); + dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); clear_tally_counters(ioaddr); spin_unlock_irqrestore(&rp->lock, flags); - return &rp->stats; + return &dev->stats; } static void rhine_set_rx_mode(struct net_device *dev) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 754a4b1..e2a7725 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1385,7 +1385,7 @@ static void velocity_free_td_ring(struct velocity_info *vptr) static int velocity_rx_srv(struct velocity_info *vptr, int status) { - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; int rd_curr = vptr->rx.curr; int works = 0; @@ -1519,7 +1519,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr, static int velocity_receive_frame(struct velocity_info *vptr, int idx) { void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]); struct rx_desc *rd = &(vptr->rx.ring[idx]); int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; @@ -1532,7 +1532,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) } if (rd->rdesc0.RSR & RSR_MAR) - vptr->stats.multicast++; + stats->multicast++; skb = rd_info->skb; @@ -1634,7 +1634,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) int idx; int works = 0; struct velocity_td_info *tdinfo; - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; for (qnum = 0; qnum < vptr->tx.numq; qnum++) { for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0; @@ -2324,22 +2324,22 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) /* If the hardware is down, don't touch MII */ if(!netif_running(dev)) - return &vptr->stats; + return &dev->stats; spin_lock_irq(&vptr->lock); velocity_update_hw_mibs(vptr); spin_unlock_irq(&vptr->lock); - vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; - vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; - vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; + dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; + dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; + dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; // unsigned long rx_dropped; /* no space in linux buffers */ - vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; + dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; /* detailed rx_errors: */ // unsigned long rx_length_errors; // unsigned long rx_over_errors; /* receiver ring buff overflow */ - vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; + dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; // unsigned long rx_frame_errors; /* recv'd frame alignment error */ // unsigned long rx_fifo_errors; /* recv'r fifo overrun */ // unsigned long rx_missed_errors; /* receiver missed packet */ @@ -2347,7 +2347,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) /* detailed tx_errors */ // unsigned long tx_fifo_errors; - return &vptr->stats; + return &dev->stats; } diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index ea43e18..4cd3f6c 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1503,7 +1503,6 @@ struct velocity_info { struct pci_dev *pdev; struct net_device *dev; - struct net_device_stats stats; struct vlan_group *vlgrp; u8 ip_addr[4]; -- cgit v0.10.2 From 2a91525c20d3aae15b33c189514b9e20e30ef8a8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 May 2009 11:30:05 +0000 Subject: net: net/core/sock.c cleanup Pure style cleanup patch. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/sock.c b/net/core/sock.c index 7dbf3ff..58dec9d 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -212,6 +212,7 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; /* Maximal space eaten by iovec or ancilliary data plus some space */ int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); +EXPORT_SYMBOL(sysctl_optmem_max); static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) { @@ -444,7 +445,7 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) int sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { - struct sock *sk=sock->sk; + struct sock *sk = sock->sk; int val; int valbool; struct linger ling; @@ -463,15 +464,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname, if (get_user(val, (int __user *)optval)) return -EFAULT; - valbool = val?1:0; + valbool = val ? 1 : 0; lock_sock(sk); - switch(optname) { + switch (optname) { case SO_DEBUG: - if (val && !capable(CAP_NET_ADMIN)) { + if (val && !capable(CAP_NET_ADMIN)) ret = -EACCES; - } else + else sock_valbool_flag(sk, SOCK_DBG, valbool); break; case SO_REUSEADDR: @@ -582,7 +583,7 @@ set_rcvbuf: ret = -EINVAL; /* 1003.1g */ break; } - if (copy_from_user(&ling,optval,sizeof(ling))) { + if (copy_from_user(&ling, optval, sizeof(ling))) { ret = -EFAULT; break; } @@ -690,9 +691,8 @@ set_rcvbuf: case SO_MARK: if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else { + else sk->sk_mark = val; - } break; /* We implement the SO_SNDLOWAT etc to @@ -704,6 +704,7 @@ set_rcvbuf: release_sock(sk); return ret; } +EXPORT_SYMBOL(sock_setsockopt); int sock_getsockopt(struct socket *sock, int level, int optname, @@ -727,7 +728,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, memset(&v, 0, sizeof(v)); - switch(optname) { + switch (optname) { case SO_DEBUG: v.val = sock_flag(sk, SOCK_DBG); break; @@ -762,7 +763,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, case SO_ERROR: v.val = -sock_error(sk); - if (v.val==0) + if (v.val == 0) v.val = xchg(&sk->sk_err_soft, 0); break; @@ -816,7 +817,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_RCVTIMEO: - lv=sizeof(struct timeval); + lv = sizeof(struct timeval); if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) { v.tm.tv_sec = 0; v.tm.tv_usec = 0; @@ -827,7 +828,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_SNDTIMEO: - lv=sizeof(struct timeval); + lv = sizeof(struct timeval); if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) { v.tm.tv_sec = 0; v.tm.tv_usec = 0; @@ -842,7 +843,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_SNDLOWAT: - v.val=1; + v.val = 1; break; case SO_PASSCRED: @@ -1002,6 +1003,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, return sk; } +EXPORT_SYMBOL(sk_alloc); void sk_free(struct sock *sk) { @@ -1026,6 +1028,7 @@ void sk_free(struct sock *sk) put_net(sock_net(sk)); sk_prot_free(sk->sk_prot_creator, sk); } +EXPORT_SYMBOL(sk_free); /* * Last sock_put should drop referrence to sk->sk_net. It has already @@ -1126,7 +1129,6 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) out: return newsk; } - EXPORT_SYMBOL_GPL(sk_clone); void sk_setup_caps(struct sock *sk, struct dst_entry *dst) @@ -1177,6 +1179,7 @@ void sock_wfree(struct sk_buff *skb) sk->sk_write_space(sk); sock_put(sk); } +EXPORT_SYMBOL(sock_wfree); /* * Read buffer destructor automatically called from kfree_skb. @@ -1188,6 +1191,7 @@ void sock_rfree(struct sk_buff *skb) atomic_sub(skb->truesize, &sk->sk_rmem_alloc); sk_mem_uncharge(skb->sk, skb->truesize); } +EXPORT_SYMBOL(sock_rfree); int sock_i_uid(struct sock *sk) @@ -1199,6 +1203,7 @@ int sock_i_uid(struct sock *sk) read_unlock(&sk->sk_callback_lock); return uid; } +EXPORT_SYMBOL(sock_i_uid); unsigned long sock_i_ino(struct sock *sk) { @@ -1209,6 +1214,7 @@ unsigned long sock_i_ino(struct sock *sk) read_unlock(&sk->sk_callback_lock); return ino; } +EXPORT_SYMBOL(sock_i_ino); /* * Allocate a skb from the socket's send buffer. @@ -1217,7 +1223,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, gfp_t priority) { if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { - struct sk_buff * skb = alloc_skb(size, priority); + struct sk_buff *skb = alloc_skb(size, priority); if (skb) { skb_set_owner_w(skb, sk); return skb; @@ -1225,6 +1231,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, } return NULL; } +EXPORT_SYMBOL(sock_wmalloc); /* * Allocate a skb from the socket's receive buffer. @@ -1261,6 +1268,7 @@ void *sock_kmalloc(struct sock *sk, int size, gfp_t priority) } return NULL; } +EXPORT_SYMBOL(sock_kmalloc); /* * Free an option memory block. @@ -1270,11 +1278,12 @@ void sock_kfree_s(struct sock *sk, void *mem, int size) kfree(mem); atomic_sub(size, &sk->sk_omem_alloc); } +EXPORT_SYMBOL(sock_kfree_s); /* It is almost wait_for_tcp_memory minus release_sock/lock_sock. I think, these locks should be removed for datagram sockets. */ -static long sock_wait_for_wmem(struct sock * sk, long timeo) +static long sock_wait_for_wmem(struct sock *sk, long timeo) { DEFINE_WAIT(wait); @@ -1392,6 +1401,7 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, { return sock_alloc_send_pskb(sk, size, 0, noblock, errcode); } +EXPORT_SYMBOL(sock_alloc_send_skb); static void __lock_sock(struct sock *sk) { @@ -1460,7 +1470,6 @@ int sk_wait_data(struct sock *sk, long *timeo) finish_wait(sk->sk_sleep, &wait); return rc; } - EXPORT_SYMBOL(sk_wait_data); /** @@ -1541,7 +1550,6 @@ suppress_allocation: atomic_sub(amt, prot->memory_allocated); return 0; } - EXPORT_SYMBOL(__sk_mem_schedule); /** @@ -1560,7 +1568,6 @@ void __sk_mem_reclaim(struct sock *sk) (atomic_read(prot->memory_allocated) < prot->sysctl_mem[0])) *prot->memory_pressure = 0; } - EXPORT_SYMBOL(__sk_mem_reclaim); @@ -1575,78 +1582,92 @@ int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_bind); int sock_no_connect(struct socket *sock, struct sockaddr *saddr, int len, int flags) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_connect); int sock_no_socketpair(struct socket *sock1, struct socket *sock2) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_socketpair); int sock_no_accept(struct socket *sock, struct socket *newsock, int flags) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_accept); int sock_no_getname(struct socket *sock, struct sockaddr *saddr, int *len, int peer) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_getname); -unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt) +unsigned int sock_no_poll(struct file *file, struct socket *sock, poll_table *pt) { return 0; } +EXPORT_SYMBOL(sock_no_poll); int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_ioctl); int sock_no_listen(struct socket *sock, int backlog) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_listen); int sock_no_shutdown(struct socket *sock, int how) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_shutdown); int sock_no_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_setsockopt); int sock_no_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_getsockopt); int sock_no_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t len) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_sendmsg); int sock_no_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t len, int flags) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_recvmsg); int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) { /* Mirror missing mmap method error code */ return -ENODEV; } +EXPORT_SYMBOL(sock_no_mmap); ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { @@ -1660,6 +1681,7 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz kunmap(page); return res; } +EXPORT_SYMBOL(sock_no_sendpage); /* * Default Socket Callbacks @@ -1723,6 +1745,7 @@ void sk_send_sigurg(struct sock *sk) if (send_sigurg(&sk->sk_socket->file->f_owner)) sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI); } +EXPORT_SYMBOL(sk_send_sigurg); void sk_reset_timer(struct sock *sk, struct timer_list* timer, unsigned long expires) @@ -1730,7 +1753,6 @@ void sk_reset_timer(struct sock *sk, struct timer_list* timer, if (!mod_timer(timer, expires)) sock_hold(sk); } - EXPORT_SYMBOL(sk_reset_timer); void sk_stop_timer(struct sock *sk, struct timer_list* timer) @@ -1738,7 +1760,6 @@ void sk_stop_timer(struct sock *sk, struct timer_list* timer) if (timer_pending(timer) && del_timer(timer)) __sock_put(sk); } - EXPORT_SYMBOL(sk_stop_timer); void sock_init_data(struct socket *sock, struct sock *sk) @@ -1797,6 +1818,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) atomic_set(&sk->sk_refcnt, 1); atomic_set(&sk->sk_drops, 0); } +EXPORT_SYMBOL(sock_init_data); void lock_sock_nested(struct sock *sk, int subclass) { @@ -1812,7 +1834,6 @@ void lock_sock_nested(struct sock *sk, int subclass) mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_); local_bh_enable(); } - EXPORT_SYMBOL(lock_sock_nested); void release_sock(struct sock *sk) @@ -1895,7 +1916,6 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname, return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); } - EXPORT_SYMBOL(sock_common_getsockopt); #ifdef CONFIG_COMPAT @@ -1925,7 +1945,6 @@ int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, msg->msg_namelen = addr_len; return err; } - EXPORT_SYMBOL(sock_common_recvmsg); /* @@ -1938,7 +1957,6 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname, return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); } - EXPORT_SYMBOL(sock_common_setsockopt); #ifdef CONFIG_COMPAT @@ -1989,7 +2007,6 @@ void sk_common_release(struct sock *sk) sk_refcnt_debug_release(sk); sock_put(sk); } - EXPORT_SYMBOL(sk_common_release); static DEFINE_RWLOCK(proto_list_lock); @@ -2171,7 +2188,6 @@ out_free_sock_slab: out: return -ENOBUFS; } - EXPORT_SYMBOL(proto_register); void proto_unregister(struct proto *prot) @@ -2198,7 +2214,6 @@ void proto_unregister(struct proto *prot) prot->twsk_prot->twsk_slab = NULL; } } - EXPORT_SYMBOL(proto_unregister); #ifdef CONFIG_PROC_FS @@ -2324,33 +2339,3 @@ static int __init proto_init(void) subsys_initcall(proto_init); #endif /* PROC_FS */ - -EXPORT_SYMBOL(sk_alloc); -EXPORT_SYMBOL(sk_free); -EXPORT_SYMBOL(sk_send_sigurg); -EXPORT_SYMBOL(sock_alloc_send_skb); -EXPORT_SYMBOL(sock_init_data); -EXPORT_SYMBOL(sock_kfree_s); -EXPORT_SYMBOL(sock_kmalloc); -EXPORT_SYMBOL(sock_no_accept); -EXPORT_SYMBOL(sock_no_bind); -EXPORT_SYMBOL(sock_no_connect); -EXPORT_SYMBOL(sock_no_getname); -EXPORT_SYMBOL(sock_no_getsockopt); -EXPORT_SYMBOL(sock_no_ioctl); -EXPORT_SYMBOL(sock_no_listen); -EXPORT_SYMBOL(sock_no_mmap); -EXPORT_SYMBOL(sock_no_poll); -EXPORT_SYMBOL(sock_no_recvmsg); -EXPORT_SYMBOL(sock_no_sendmsg); -EXPORT_SYMBOL(sock_no_sendpage); -EXPORT_SYMBOL(sock_no_setsockopt); -EXPORT_SYMBOL(sock_no_shutdown); -EXPORT_SYMBOL(sock_no_socketpair); -EXPORT_SYMBOL(sock_rfree); -EXPORT_SYMBOL(sock_setsockopt); -EXPORT_SYMBOL(sock_wfree); -EXPORT_SYMBOL(sock_wmalloc); -EXPORT_SYMBOL(sock_i_uid); -EXPORT_SYMBOL(sock_i_ino); -EXPORT_SYMBOL(sysctl_optmem_max); -- cgit v0.10.2 From 385a154cac8763284f65cdfa25f6796c9eb1ca21 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 27 May 2009 15:48:07 -0700 Subject: net: correct a comment for the final #endif Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 14efce3..8e03b06 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1975,4 +1975,4 @@ static inline u32 dev_ethtool_get_flags(struct net_device *dev) } #endif /* __KERNEL__ */ -#endif /* _LINUX_DEV_H */ +#endif /* _LINUX_NETDEVICE_H */ -- cgit v0.10.2 From 5615968a70845157adaffc11062c997d045339ee Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 May 2009 16:56:47 -0700 Subject: appletalk: Add proper locking around IPDDP routing table. Signed-off-by: David S. Miller diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index f939e92..9832b75 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -39,6 +39,7 @@ static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson \n"; static struct ipddp_route *ipddp_route_list; +static DEFINE_SPINLOCK(ipddp_route_lock); #ifdef CONFIG_IPDDP_ENCAP static int ipddp_mode = IPDDP_ENCAP; @@ -50,7 +51,7 @@ static int ipddp_mode = IPDDP_DECAP; static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); +static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static const struct net_device_ops ipddp_netdev_ops = { @@ -119,6 +120,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) struct ipddp_route *rt; struct atalk_addr *our_addr; + spin_lock(&ipddp_route_lock); + /* * Find appropriate route to use, based only on IP number. */ @@ -127,8 +130,10 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) if(rt->ip == paddr) break; } - if(rt == NULL) + if(rt == NULL) { + spin_unlock(&ipddp_route_lock); return 0; + } our_addr = atalk_find_dev_addr(rt->dev); @@ -174,6 +179,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) dev_kfree_skb(skb); + spin_unlock(&ipddp_route_lock); + return 0; } @@ -196,7 +203,9 @@ static int ipddp_create(struct ipddp_route *new_rt) return -ENETUNREACH; } - if (ipddp_find_route(rt)) { + spin_lock_bh(&ipddp_route_lock); + if (__ipddp_find_route(rt)) { + spin_unlock_bh(&ipddp_route_lock); kfree(rt); return -EEXIST; } @@ -204,6 +213,8 @@ static int ipddp_create(struct ipddp_route *new_rt) rt->next = ipddp_route_list; ipddp_route_list = rt; + spin_unlock_bh(&ipddp_route_lock); + return 0; } @@ -216,6 +227,7 @@ static int ipddp_delete(struct ipddp_route *rt) struct ipddp_route **r = &ipddp_route_list; struct ipddp_route *tmp; + spin_lock_bh(&ipddp_route_lock); while((tmp = *r) != NULL) { if(tmp->ip == rt->ip @@ -223,19 +235,21 @@ static int ipddp_delete(struct ipddp_route *rt) && tmp->at.s_node == rt->at.s_node) { *r = tmp->next; + spin_unlock_bh(&ipddp_route_lock); kfree(tmp); return 0; } r = &tmp->next; } + spin_unlock_bh(&ipddp_route_lock); return (-ENOENT); } /* * Find a routing entry, we only return a FULL match */ -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) +static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) { struct ipddp_route *f; @@ -253,7 +267,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct ipddp_route __user *rt = ifr->ifr_data; - struct ipddp_route rcp; + struct ipddp_route rcp, rcp2, *rp; if(!capable(CAP_NET_ADMIN)) return -EPERM; @@ -267,9 +281,19 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return (ipddp_create(&rcp)); case SIOCFINDIPDDPRT: - if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route))) - return -EFAULT; - return 0; + spin_lock_bh(&ipddp_route_lock); + rp = __ipddp_find_route(&rcp); + if (rp) + memcpy(&rcp2, rp, sizeof(rcp2)); + spin_unlock_bh(&ipddp_route_lock); + + if (rp) { + if (copy_to_user(rt, &rcp2, + sizeof(struct ipddp_route))) + return -EFAULT; + return 0; + } else + return -ENOENT; case SIOCDELIPDDPRT: return (ipddp_delete(&rcp)); -- cgit v0.10.2 From 438263ac58f8c2a3a409b7d4e68a37725bd95818 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 May 2009 17:09:44 -0700 Subject: aoe: Remove superfluous clearing of skb fields in new_skb(). This code uses alloc_skb() which clears them out for us. Signed-off-by: David S. Miller diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 31693bc..965ece2 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -34,13 +34,6 @@ new_skb(ulong len) skb_reset_mac_header(skb); skb_reset_network_header(skb); skb->protocol = __constant_htons(ETH_P_AOE); - skb->priority = 0; - skb->next = skb->prev = NULL; - - /* tell the network layer not to perform IP checksums - * or to get the NIC to do it - */ - skb->ip_summed = CHECKSUM_NONE; } return skb; } -- cgit v0.10.2 From ae71fabbe55552afc01f2bc797bee6838db22485 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 May 2009 17:27:01 -0700 Subject: wavelan: Remove bogus debugging on skb->next being non-NULL. This eliminates explicit references to the SKB list handling implementation. Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 3ab3eb9..25d27b6 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2869,10 +2869,6 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) if (lp->tx_n_in_use == (NTXBLOCKS - 1)) return 1; } -#ifdef DEBUG_TX_ERROR - if (skb->next) - printk(KERN_INFO "skb has next\n"); -#endif /* Do we need some padding? */ /* Note : on wireless the propagation time is in the order of 1us, diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index e55b339..1a90d69 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3107,11 +3107,6 @@ wavelan_packet_xmit(struct sk_buff * skb, * so the Tx buffer is now free */ } -#ifdef DEBUG_TX_ERROR - if (skb->next) - printk(KERN_INFO "skb has next\n"); -#endif - /* Check if we need some padding */ /* Note : on wireless the propagation time is in the order of 1us, * and we don't have the Ethernet specific requirement of beeing -- cgit v0.10.2 From a1091aae19b1d9c85d91c86915a611387f67a26b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 00:48:16 -0700 Subject: p54: Use SKB list handling helpers instead of by-hand code. Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 48d81d9..b618bd1 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_tx_info *range; unsigned long flags; - if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) + if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue))) return; - /* - * don't try to free an already unlinked skb + /* There used to be a check here to see if the SKB was on the + * TX queue or not. This can never happen because all SKBs we + * see here successfully went through p54_assign_address() + * which means the SKB is on the ->tx_queue. */ - if (unlikely((!skb->next) || (!skb->prev))) - return; spin_lock_irqsave(&priv->tx_queue.lock, flags); info = IEEE80211_SKB_CB(skb); range = (void *)info->rate_driver_data; - if (skb->prev != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_first(&priv->tx_queue, skb)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb->prev); + ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb)); mr = (struct p54_tx_info *)ni->rate_driver_data; } - if (skb->next != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_last(&priv->tx_queue, skb)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb->next); + ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb)); mr = (struct p54_tx_info *)ni->rate_driver_data; } __skb_unlink(skb, &priv->tx_queue); @@ -864,15 +864,13 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, unsigned long flags; spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { + skb_queue_walk(&priv->tx_queue, entry) { struct p54_hdr *hdr = (struct p54_hdr *) entry->data; if (hdr->req_id == req_id) { spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return entry; } - entry = entry->next; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return NULL; @@ -890,24 +888,22 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = (struct sk_buff *) priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { + skb_queue_walk(&priv->tx_queue, entry) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); struct p54_hdr *entry_hdr; struct p54_tx_data *entry_data; unsigned int pad = 0, frame_len; range = (void *)info->rate_driver_data; - if (range->start_addr != addr) { - entry = entry->next; + if (range->start_addr != addr) continue; - } - if (entry->next != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_last(&priv->tx_queue, entry)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(entry->next); + ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, + entry)); mr = (struct p54_tx_info *)ni->rate_driver_data; } @@ -1168,23 +1164,21 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, } } - entry = priv->tx_queue.next; - while (left--) { + skb_queue_walk(&priv->tx_queue, entry) { u32 hole_size; info = IEEE80211_SKB_CB(entry); range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { - target_skb = entry->prev; + target_skb = skb_queue_prev(&priv->tx_queue, entry); hole_size -= len; target_addr = last_addr; } largest_hole = max(largest_hole, hole_size); last_addr = range->end_addr; - entry = entry->next; } if (!target_skb && priv->rx_end - last_addr >= len) { - target_skb = priv->tx_queue.prev; + target_skb = skb_peek_tail(&priv->tx_queue); largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { info = IEEE80211_SKB_CB(target_skb); @@ -2090,7 +2084,6 @@ out: static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct sk_buff *skb; mutex_lock(&priv->conf_mutex); priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -2105,8 +2098,7 @@ static void p54_stop(struct ieee80211_hw *dev) p54_tx_cancel(dev, priv->cached_beacon); priv->stop(dev); - while ((skb = skb_dequeue(&priv->tx_queue))) - kfree_skb(skb); + skb_queue_purge(&priv->tx_queue); priv->cached_beacon = NULL; priv->tsf_high32 = priv->tsf_low32 = 0; mutex_unlock(&priv->conf_mutex); -- cgit v0.10.2 From 46c37672d7fff0097385eb0cbd01aa0254dad0aa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 01:22:57 -0700 Subject: rtl8187: Remove pointless check in rtl8187_rx_cb(). First of all, it exposes the SKB list implementation. Second of all it's not needed. If we get called here, we successfully enqueued the URB with the linked SKB and such a completion only gets called one time on such an SKB. Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 6499ccc..3f22cc0 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -321,12 +321,7 @@ static void rtl8187_rx_cb(struct urb *urb) unsigned long f; spin_lock_irqsave(&priv->rx_queue.lock, f); - if (skb->next) - __skb_unlink(skb, &priv->rx_queue); - else { - spin_unlock_irqrestore(&priv->rx_queue.lock, f); - return; - } + __skb_unlink(skb, &priv->rx_queue); spin_unlock_irqrestore(&priv->rx_queue.lock, f); skb_put(skb, urb->actual_length); -- cgit v0.10.2 From b6211ae7f2e56837c6a4849316396d1535606e90 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 16:36:47 -0700 Subject: atm: Use SKB queue and list helpers instead of doing it by-hand. Signed-off-by: David S. Miller diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 3100a89..bfa8fa9 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -445,9 +445,10 @@ free_skb: */ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) { + struct sk_buff_head queue; int err; struct br2684_vcc *brvcc; - struct sk_buff *skb; + struct sk_buff *skb, *tmp; struct sk_buff_head *rq; struct br2684_dev *brdev; struct net_device *net_dev; @@ -505,29 +506,20 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) barrier(); atmvcc->push = br2684_push; + __skb_queue_head_init(&queue); rq = &sk_atm(atmvcc)->sk_receive_queue; spin_lock_irqsave(&rq->lock, flags); - if (skb_queue_empty(rq)) { - skb = NULL; - } else { - /* NULL terminate the list. */ - rq->prev->next = NULL; - skb = rq->next; - } - rq->prev = rq->next = (struct sk_buff *)rq; - rq->qlen = 0; + skb_queue_splice_init(rq, &queue); spin_unlock_irqrestore(&rq->lock, flags); - while (skb) { - struct sk_buff *next = skb->next; + skb_queue_walk_safe(&queue, skb, tmp) { + struct net_device *dev = skb->dev; - skb->next = skb->prev = NULL; - br2684_push(atmvcc, skb); - skb->dev->stats.rx_bytes -= skb->len; - skb->dev->stats.rx_packets--; + dev->stats.rx_bytes -= skb->len; + dev->stats.rx_packets--; - skb = next; + br2684_push(atmvcc, skb); } __module_get(THIS_MODULE); return 0; diff --git a/net/atm/clip.c b/net/atm/clip.c index 3dc0a3a..5597b87 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -445,9 +445,9 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) static int clip_mkip(struct atm_vcc *vcc, int timeout) { + struct sk_buff_head *rq, queue; struct clip_vcc *clip_vcc; - struct sk_buff *skb; - struct sk_buff_head *rq; + struct sk_buff *skb, *tmp; unsigned long flags; if (!vcc->push) @@ -469,39 +469,28 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout) vcc->push = clip_push; vcc->pop = clip_pop; + __skb_queue_head_init(&queue); rq = &sk_atm(vcc)->sk_receive_queue; spin_lock_irqsave(&rq->lock, flags); - if (skb_queue_empty(rq)) { - skb = NULL; - } else { - /* NULL terminate the list. */ - rq->prev->next = NULL; - skb = rq->next; - } - rq->prev = rq->next = (struct sk_buff *)rq; - rq->qlen = 0; + skb_queue_splice_init(rq, &queue); spin_unlock_irqrestore(&rq->lock, flags); /* re-process everything received between connection setup and MKIP */ - while (skb) { - struct sk_buff *next = skb->next; - - skb->next = skb->prev = NULL; + skb_queue_walk_safe(&queue, skb, tmp) { if (!clip_devs) { atm_return(vcc, skb->truesize); kfree_skb(skb); } else { + struct net_device *dev = skb->dev; unsigned int len = skb->len; skb_get(skb); clip_push(vcc, skb); - skb->dev->stats.rx_packets--; - skb->dev->stats.rx_bytes -= len; + dev->stats.rx_packets--; + dev->stats.rx_bytes -= len; kfree_skb(skb); } - - skb = next; } return 0; } -- cgit v0.10.2 From bec571ec762a4cf855ad4446f833086fc154b60e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 16:43:52 -0700 Subject: decnet: Use SKB queue and list helpers instead of doing it by-hand. Signed-off-by: David S. Miller diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 9647d91..bccb388 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1250,14 +1250,8 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (skb) { amount = skb->len; } else { - skb = sk->sk_receive_queue.next; - for (;;) { - if (skb == - (struct sk_buff *)&sk->sk_receive_queue) - break; + skb_queue_walk(&sk->sk_receive_queue, skb) amount += skb->len; - skb = skb->next; - } } release_sock(sk); err = put_user(amount, (int __user *)arg); @@ -1644,13 +1638,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int target) { - struct sk_buff *skb = q->next; + struct sk_buff *skb; int len = 0; if (flags & MSG_OOB) return !skb_queue_empty(q) ? 1 : 0; - while(skb != (struct sk_buff *)q) { + skb_queue_walk(q, skb) { struct dn_skb_cb *cb = DN_SKB_CB(skb); len += skb->len; @@ -1666,8 +1660,6 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int /* minimum data length for read exceeded */ if (len >= target) return 1; - - skb = skb->next; } return 0; @@ -1683,7 +1675,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, size_t target = size > 1 ? 1 : 0; size_t copied = 0; int rv = 0; - struct sk_buff *skb, *nskb; + struct sk_buff *skb, *n; struct dn_skb_cb *cb = NULL; unsigned char eor = 0; long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); @@ -1758,7 +1750,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, finish_wait(sk->sk_sleep, &wait); } - for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) { + skb_queue_walk_safe(queue, skb, n) { unsigned int chunk = skb->len; cb = DN_SKB_CB(skb); @@ -1775,7 +1767,6 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, skb_pull(skb, chunk); eor = cb->nsp_flags & 0x40; - nskb = skb->next; if (skb->len == 0) { skb_unlink(skb, queue); diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index 2013c25..da04f45 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -382,7 +382,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff { struct dn_skb_cb *cb = DN_SKB_CB(skb); struct dn_scp *scp = DN_SK(sk); - struct sk_buff *skb2, *list, *ack = NULL; + struct sk_buff *skb2, *n, *ack = NULL; int wakeup = 0; int try_retrans = 0; unsigned long reftime = cb->stamp; @@ -390,9 +390,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff unsigned short xmit_count; unsigned short segnum; - skb2 = q->next; - list = (struct sk_buff *)q; - while(list != skb2) { + skb_queue_walk_safe(q, skb2, n) { struct dn_skb_cb *cb2 = DN_SKB_CB(skb2); if (dn_before_or_equal(cb2->segnum, acknum)) @@ -400,8 +398,6 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff /* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */ - skb2 = skb2->next; - if (ack == NULL) continue; -- cgit v0.10.2 From de1033428baf1940bbbbf9e66b073ee0a577f5e0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 16:46:29 -0700 Subject: econet: Use SKB queue and list helpers instead of doing it by-hand. Signed-off-by: David S. Miller diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 6f479fa..8121bf0 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -901,15 +901,10 @@ static void aun_tx_ack(unsigned long seq, int result) struct ec_cb *eb; spin_lock_irqsave(&aun_queue_lock, flags); - skb = skb_peek(&aun_queue); - while (skb && skb != (struct sk_buff *)&aun_queue) - { - struct sk_buff *newskb = skb->next; + skb_queue_walk(&aun_queue, skb) { eb = (struct ec_cb *)&skb->cb; if (eb->seq == seq) goto foundit; - - skb = newskb; } spin_unlock_irqrestore(&aun_queue_lock, flags); printk(KERN_DEBUG "AUN: unknown sequence %ld\n", seq); @@ -982,23 +977,18 @@ static void aun_data_available(struct sock *sk, int slen) static void ab_cleanup(unsigned long h) { - struct sk_buff *skb; + struct sk_buff *skb, *n; unsigned long flags; spin_lock_irqsave(&aun_queue_lock, flags); - skb = skb_peek(&aun_queue); - while (skb && skb != (struct sk_buff *)&aun_queue) - { - struct sk_buff *newskb = skb->next; + skb_queue_walk_safe(&aun_queue, skb, n) { struct ec_cb *eb = (struct ec_cb *)&skb->cb; - if ((jiffies - eb->start) > eb->timeout) - { + if ((jiffies - eb->start) > eb->timeout) { tx_result(skb->sk, eb->cookie, ECTYPE_TRANSMIT_NOT_PRESENT); skb_unlink(skb, &aun_queue); kfree_skb(skb); } - skb = newskb; } spin_unlock_irqrestore(&aun_queue_lock, flags); -- cgit v0.10.2 From fe442683853a2c0863b700acc4328b4d73090206 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 22 Apr 2009 16:53:08 -0700 Subject: wimax/i2400m: generate fake source MAC address with random_ether_addr() The WiMAX i2400m driver needs to generate a fake source MAC address to fake an ethernet header (for destination, the card's MAC is used). This is the source of the packet, which is the basestation it came from. The basestation's mac address is not usable for this, as it uses its own namespace and it is not always available. Currently the fake source MAC address was being set to all zeros, which was causing trouble with bridging. Use random_ether_addr() to generate a proper one that creates no trouble. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 07a54ba..a21318b 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -62,6 +62,7 @@ * unregister_netdev() */ #include "i2400m.h" +#include #include #include #include @@ -650,6 +651,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) result = i2400m_read_mac_addr(i2400m); if (result < 0) goto error_read_mac_addr; + random_ether_addr(i2400m->src_mac_addr); result = register_netdev(net_dev); /* Okey dokey, bring it up */ if (result < 0) { diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 3ae2df3..434ba31 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -323,6 +323,10 @@ struct i2400m_roq; * delivered. Then the driver can release them to the host. See * drivers/net/i2400m/rx.c for details. * + * @src_mac_addr: MAC address used to make ethernet packets be coming + * from. This is generated at i2400m_setup() time and used during + * the life cycle of the instance. See i2400m_fake_eth_header(). + * * @init_mutex: Mutex used for serializing the device bringup * sequence; this way if the device reboots in the middle, we * don't try to do a bringup again while we are tearing down the @@ -421,6 +425,7 @@ struct i2400m { unsigned rx_pl_num, rx_pl_max, rx_pl_min, rx_num, rx_size_acc, rx_size_min, rx_size_max; struct i2400m_roq *rx_roq; /* not under rx_lock! */ + u8 src_mac_addr[ETH_HLEN]; struct mutex msg_mutex; /* serialize command execution */ struct completion msg_completion; diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 6b1fe7a..9653f47 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -404,10 +404,12 @@ static void i2400m_rx_fake_eth_header(struct net_device *net_dev, void *_eth_hdr, __be16 protocol) { + struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct ethhdr *eth_hdr = _eth_hdr; memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); - memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest)); + memcpy(eth_hdr->h_source, i2400m->src_mac_addr, + sizeof(eth_hdr->h_source)); eth_hdr->h_proto = protocol; } -- cgit v0.10.2 From 44b849d11bf6801a642dd1aa9a70e470d046d273 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Mon, 30 Mar 2009 17:51:54 -0700 Subject: wimax/i2400m: trace commands sent from user space on the "echo" pipe When commands are sent from user space, trace both the command sent and the answer received over the "echo" pipe instead of over the "trace" pipe when command tracing is enabled. As well, when the device sends a reports/indications, send it over the "echo" pipe. The "trace" pipe is used by the device to send firmware traces; gets confusing. Another named pipe makes it easier to split debug information. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index a21318b..d33389f 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -231,13 +231,20 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, d_fnstart(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p " "msg_len %zu genl_info %p)\n", wimax_dev, i2400m, msg_buf, msg_len, genl_info); + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", + msg_buf, msg_len, GFP_KERNEL); ack_skb = i2400m_msg_to_dev(i2400m, msg_buf, msg_len); result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) goto error_msg_to_dev; - if (unlikely(i2400m->trace_msg_from_user)) - wimax_msg(&i2400m->wimax_dev, "trace", - msg_buf, msg_len, GFP_KERNEL); + if (unlikely(i2400m->trace_msg_from_user)) { + const void *ack_data; + size_t ack_len; + ack_data = wimax_msg_data_len(ack_skb, &ack_len); + wimax_msg(&i2400m->wimax_dev, "echo", + ack_data, ack_len, GFP_KERNEL); + } result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); error_msg_to_dev: d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index f9fc389..a4adc78 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -309,6 +309,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx, skb_get(skb_rx); i2400m_queue_work(i2400m, i2400m_report_hook_work, GFP_KERNEL, &args, sizeof(args)); + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", + l3l4_hdr, size, GFP_KERNEL); result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size, GFP_KERNEL); if (result < 0) -- cgit v0.10.2 From 223beea23810577353c4cc71ce2f44dbba0d4e16 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Mon, 13 Apr 2009 10:26:34 -0700 Subject: wimax/i2400m: allow kernel commands to device to be logged too By running 'echo 1 > /sys/kernel/debug/wimax:wmxX/i2400m/trace_msg_from_user', the driver will echo to user space all the commands being sent to the device from user space, along with the responses. However, this only helps with the commands being sent from user space; with this patch, the trace hook is moved to i2400m_msg_to_dev(), which is the single access point for running commands to the device (both by user space and the kernel driver). This allows better debugging by having a complete stream of commands/acks and reports. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index b3cadb6..0f58418 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -721,6 +721,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, ack_timeout = HZ; }; + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL); /* The RX path in rx.c will put any response for this message * in i2400m->ack_skb and wake us up. If we cancel the wait, * we need to change the value of i2400m->ack_skb to something @@ -755,6 +757,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len); /* Check the ack and deliver it if it is ok */ + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", + ack_l3l4_hdr, ack_len, GFP_KERNEL); result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len); if (result < 0) { dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n", diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index d33389f..ef16c57 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -231,20 +231,10 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, d_fnstart(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p " "msg_len %zu genl_info %p)\n", wimax_dev, i2400m, msg_buf, msg_len, genl_info); - if (unlikely(i2400m->trace_msg_from_user)) - wimax_msg(&i2400m->wimax_dev, "echo", - msg_buf, msg_len, GFP_KERNEL); ack_skb = i2400m_msg_to_dev(i2400m, msg_buf, msg_len); result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) goto error_msg_to_dev; - if (unlikely(i2400m->trace_msg_from_user)) { - const void *ack_data; - size_t ack_len; - ack_data = wimax_msg_data_len(ack_skb, &ack_len); - wimax_msg(&i2400m->wimax_dev, "echo", - ack_data, ack_len, GFP_KERNEL); - } result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); error_msg_to_dev: d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " -- cgit v0.10.2 From 8ac1101f8cd58a62517ba86745bc000d3a21f09b Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Sat, 25 Apr 2009 00:26:14 -0700 Subject: wimax/i2400m: factor out 'state report's TLV handling to a function i2400m_report_state_hook() is going to get messier as we add handling code. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index 0f58418..b42e347 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -400,7 +400,53 @@ out: /* - * Parse a 'state report' and extract carrier on/off information + * Process a TLV from a 'state report' + * + * @i2400m: device descriptor + * @tlv: pointer to the TLV header; it has been already validated for + * consistent size. + * @tag: for error messages + * + * Act on the TLVs from a 'state report'. + */ +static +void i2400m_report_state_parse_tlv(struct i2400m *i2400m, + const struct i2400m_tlv_hdr *tlv, + const char *tag) +{ + struct device *dev = i2400m_dev(i2400m); + const struct i2400m_tlv_media_status *ms; + const struct i2400m_tlv_system_state *ss; + const struct i2400m_tlv_rf_switches_status *rfss; + + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) { + ss = container_of(tlv, typeof(*ss), hdr); + d_printf(2, dev, "%s: system state TLV " + "found (0x%04x), state 0x%08x\n", + tag, I2400M_TLV_SYSTEM_STATE, + le32_to_cpu(ss->state)); + i2400m_report_tlv_system_state(i2400m, ss); + } + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) { + rfss = container_of(tlv, typeof(*rfss), hdr); + d_printf(2, dev, "%s: RF status TLV " + "found (0x%04x), sw 0x%02x hw 0x%02x\n", + tag, I2400M_TLV_RF_STATUS, + le32_to_cpu(rfss->sw_rf_switch), + le32_to_cpu(rfss->hw_rf_switch)); + i2400m_report_tlv_rf_switches_status(i2400m, rfss); + } + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) { + ms = container_of(tlv, typeof(*ms), hdr); + d_printf(2, dev, "%s: Media Status TLV: %u\n", + tag, le32_to_cpu(ms->media_status)); + i2400m_report_tlv_media_status(i2400m, ms); + } +} + + +/* + * Parse a 'state report' and extract information * * @i2400m: device descriptor * @l3l4_hdr: pointer to message; it has been already validated for @@ -409,13 +455,7 @@ out: * declaration is assumed to be congruent with @size (as in * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * - * Extract from the report state the system state TLV and infer from - * there if we have a carrier or not. Update our local state and tell - * netdev. - * - * When setting the carrier, it's fine to set OFF twice (for example), - * as netif_carrier_off() will not generate two OFF events (just on - * the transitions). + * Walk over the TLVs in a report state and act on them. */ static void i2400m_report_state_hook(struct i2400m *i2400m, @@ -424,9 +464,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m, { struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv; - const struct i2400m_tlv_system_state *ss; - const struct i2400m_tlv_rf_switches_status *rfss; - const struct i2400m_tlv_media_status *ms; size_t tlv_size = le16_to_cpu(l3l4_hdr->length); d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", @@ -434,34 +471,8 @@ void i2400m_report_state_hook(struct i2400m *i2400m, tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, - tlv_size, tlv))) { - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, - sizeof(*ss))) { - ss = container_of(tlv, typeof(*ss), hdr); - d_printf(2, dev, "%s: system state TLV " - "found (0x%04x), state 0x%08x\n", - tag, I2400M_TLV_SYSTEM_STATE, - le32_to_cpu(ss->state)); - i2400m_report_tlv_system_state(i2400m, ss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, - sizeof(*rfss))) { - rfss = container_of(tlv, typeof(*rfss), hdr); - d_printf(2, dev, "%s: RF status TLV " - "found (0x%04x), sw 0x%02x hw 0x%02x\n", - tag, I2400M_TLV_RF_STATUS, - le32_to_cpu(rfss->sw_rf_switch), - le32_to_cpu(rfss->hw_rf_switch)); - i2400m_report_tlv_rf_switches_status(i2400m, rfss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, - sizeof(*ms))) { - ms = container_of(tlv, typeof(*ms), hdr); - d_printf(2, dev, "%s: Media Status TLV: %u\n", - tag, le32_to_cpu(ms->media_status)); - i2400m_report_tlv_media_status(i2400m, ms); - } - } + tlv_size, tlv))) + i2400m_report_state_parse_tlv(i2400m, tlv, tag); d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", i2400m, l3l4_hdr, size, tag); } -- cgit v0.10.2 From 052991d7ac7f7b2c0319e6ccd2e8a48a71f2bd58 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Sat, 2 May 2009 02:50:03 -0700 Subject: wimax/i2400m: remove redundant readiness checks from i2400m_report_tlv_*() Functions i2400m_report_tlv*() are only called from i2400m_report_hook(), called in a workqueue by i2400m_report_hook_work(). The scheduler checks for device readiness before scheduling. Added an extra check for readiness in i2400m_report_hook_work(), which makes all the checks down the line redundant. Obviously the device state could change in the middle, but error handling would take care of that. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index b42e347..bd193ae 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state); - if (unlikely(i2400m->ready == 0)) /* act if up */ - goto out; if (i2400m->state != i2400m_state) { i2400m->state = i2400m_state; wake_up_all(&i2400m->state_wq); @@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, i2400m->bus_reset(i2400m, I2400M_RT_WARM); break; }; -out: d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", i2400m, ss, i2400m_state); } @@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status); - if (unlikely(i2400m->ready == 0)) /* act if up */ - goto out; switch (status) { case I2400M_MEDIA_STATUS_LINK_UP: netif_carrier_on(net_dev); @@ -393,7 +388,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, dev_err(dev, "HW BUG? unknown media status %u\n", status); }; -out: d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n", i2400m, ms, status); } diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index a4adc78..7643850 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws) struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws); struct i2400m_report_hook_args *args = (void *) iw->pl; - i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); + if (iw->i2400m->ready) + i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); kfree_skb(args->skb_rx); i2400m_put(iw->i2400m); kfree(iw); -- cgit v0.10.2 From 52a8d9630890f2289354d03e8751bf0eba2b3376 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 5 May 2009 21:05:16 -0700 Subject: wimax: document why wimax_msg_*() operations can be used in any state Funcion documentation for wimax_msg_alloc() and wimax_msg_send() needs to clarify that they can be used in the very early stages of a wimax_dev lifecycle. Signed-off-by: Inaky Perez-Gonzalez diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index 9ad4d89..d631a17 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c @@ -108,6 +108,12 @@ * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as * wimax_msg_send() depends on skb->data being placed at the * beginning of the user message. + * + * Unlike other WiMAX stack calls, this call can be used way early, + * even before wimax_dev_add() is called, as long as the + * wimax_dev->net_dev pointer is set to point to a proper + * net_dev. This is so that drivers can use it early in case they need + * to send stuff around or communicate with user space. */ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, const char *pipe_name, @@ -115,7 +121,7 @@ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, gfp_t gfp_flags) { int result; - struct device *dev = wimax_dev->net_dev->dev.parent; + struct device *dev = wimax_dev_to_dev(wimax_dev); size_t msg_size; void *genl_msg; struct sk_buff *skb; @@ -161,7 +167,6 @@ error_genlmsg_put: error_new: nlmsg_free(skb); return ERR_PTR(result); - } EXPORT_SYMBOL_GPL(wimax_msg_alloc); @@ -256,10 +261,16 @@ EXPORT_SYMBOL_GPL(wimax_msg_len); * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as * wimax_msg_send() depends on skb->data being placed at the * beginning of the user message. + * + * Unlike other WiMAX stack calls, this call can be used way early, + * even before wimax_dev_add() is called, as long as the + * wimax_dev->net_dev pointer is set to point to a proper + * net_dev. This is so that drivers can use it early in case they need + * to send stuff around or communicate with user space. */ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) { - struct device *dev = wimax_dev->net_dev->dev.parent; + struct device *dev = wimax_dev_to_dev(wimax_dev); void *msg = skb->data; size_t size = skb->len; might_sleep(); -- cgit v0.10.2 From a0a4c4c9e54ee4255f46eedb572ad69ee34c77b6 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 30 Apr 2009 14:39:21 -0700 Subject: wimax/i2400m: sdio: set the block size before enabling the function From a fix by Cindy H Kao: Block size has to be set before sending IOE enable because the firmware reads the block size register before it reads IOE register. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 5ac5e767..777c981 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -409,19 +409,19 @@ int i2400ms_probe(struct sdio_func *func, i2400m->bus_fw_names = i2400ms_bus_fw_names; i2400m->bus_bm_mac_addr_impaired = 1; - result = i2400ms_enable_function(i2400ms->func); - if (result < 0) { - dev_err(dev, "Cannot enable SDIO function: %d\n", result); - goto error_func_enable; - } - sdio_claim_host(func); result = sdio_set_block_size(func, I2400MS_BLK_SIZE); + sdio_release_host(func); if (result < 0) { dev_err(dev, "Failed to set block size: %d\n", result); goto error_set_blk_size; } - sdio_release_host(func); + + result = i2400ms_enable_function(i2400ms->func); + if (result < 0) { + dev_err(dev, "Cannot enable SDIO function: %d\n", result); + goto error_func_enable; + } result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); if (result < 0) { @@ -440,12 +440,12 @@ int i2400ms_probe(struct sdio_func *func, error_debugfs_add: i2400m_release(i2400m); error_setup: - sdio_set_drvdata(func, NULL); sdio_claim_host(func); -error_set_blk_size: sdio_disable_func(func); sdio_release_host(func); error_func_enable: +error_set_blk_size: + sdio_set_drvdata(func, NULL); free_netdev(net_dev); error_alloc_netdev: return result; -- cgit v0.10.2 From 7f0333eb2f98bbfece4fbfe21076d0a3e49f0bb0 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 13 May 2009 06:20:29 -0700 Subject: wimax: Add netlink interface to get device state wimax connection manager / daemon has to know what is current state of the device. Previously it was only possible to get notification whet state has changed. Note: By mistake, the new generic netlink's number for WIMAX_GNL_OP_STATE_GET was declared inserting into the existing list of API calls, not appending; thus, it'd break existing API. Fixed by Inaky Perez-Gonzalez by moving to the tail, where we add to the interface, not modify the interface. Thanks to Stephen Hemminger for catching this. Signed-off-by: Paulius Zaleckas diff --git a/include/linux/wimax.h b/include/linux/wimax.h index c89de7f..2f7a6b7 100644 --- a/include/linux/wimax.h +++ b/include/linux/wimax.h @@ -78,6 +78,7 @@ enum { WIMAX_GNL_OP_RFKILL, /* Run wimax_rfkill() */ WIMAX_GNL_OP_RESET, /* Run wimax_rfkill() */ WIMAX_GNL_RE_STATE_CHANGE, /* Report: status change */ + WIMAX_GNL_OP_STATE_GET, /* Request for current state */ }; @@ -113,6 +114,10 @@ enum { WIMAX_GNL_RESET_IFIDX = 1, }; +/* Atributes for wimax_state_get() */ +enum { + WIMAX_GNL_STGET_IFIDX = 1, +}; /* * Attributes for the Report State Change diff --git a/net/wimax/Makefile b/net/wimax/Makefile index 5b80b94..8f1510d 100644 --- a/net/wimax/Makefile +++ b/net/wimax/Makefile @@ -6,6 +6,7 @@ wimax-y := \ op-msg.o \ op-reset.o \ op-rfkill.o \ + op-state-get.o \ stack.o wimax-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/net/wimax/debug-levels.h b/net/wimax/debug-levels.h index 1c29123..0975adb 100644 --- a/net/wimax/debug-levels.h +++ b/net/wimax/debug-levels.h @@ -36,6 +36,7 @@ enum d_module { D_SUBMODULE_DECLARE(op_msg), D_SUBMODULE_DECLARE(op_reset), D_SUBMODULE_DECLARE(op_rfkill), + D_SUBMODULE_DECLARE(op_state_get), D_SUBMODULE_DECLARE(stack), }; diff --git a/net/wimax/debugfs.c b/net/wimax/debugfs.c index 94d216a..6c9bedb 100644 --- a/net/wimax/debugfs.c +++ b/net/wimax/debugfs.c @@ -61,6 +61,7 @@ int wimax_debugfs_add(struct wimax_dev *wimax_dev) __debugfs_register("wimax_dl_", op_msg, dentry); __debugfs_register("wimax_dl_", op_reset, dentry); __debugfs_register("wimax_dl_", op_rfkill, dentry); + __debugfs_register("wimax_dl_", op_state_get, dentry); __debugfs_register("wimax_dl_", stack, dentry); result = 0; out: diff --git a/net/wimax/op-state-get.c b/net/wimax/op-state-get.c new file mode 100644 index 0000000..a76b8fc --- /dev/null +++ b/net/wimax/op-state-get.c @@ -0,0 +1,86 @@ +/* + * Linux WiMAX + * Implement and export a method for getting a WiMAX device current state + * + * Copyright (C) 2009 Paulius Zaleckas + * + * Based on previous WiMAX core work by: + * Copyright (C) 2008 Intel Corporation + * Inaky Perez-Gonzalez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "wimax-internal.h" + +#define D_SUBMODULE op_state_get +#include "debug-levels.h" + + +static const +struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1] = { + [WIMAX_GNL_STGET_IFIDX] = { + .type = NLA_U32, + }, +}; + + +/* + * Exporting to user space over generic netlink + * + * Parse the state get command from user space, return a combination + * value that describe the current state. + * + * No attributes. + */ +static +int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info) +{ + int result, ifindex; + struct wimax_dev *wimax_dev; + struct device *dev; + + d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); + result = -ENODEV; + if (info->attrs[WIMAX_GNL_STGET_IFIDX] == NULL) { + printk(KERN_ERR "WIMAX_GNL_OP_STATE_GET: can't find IFIDX " + "attribute\n"); + goto error_no_wimax_dev; + } + ifindex = nla_get_u32(info->attrs[WIMAX_GNL_STGET_IFIDX]); + wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); + if (wimax_dev == NULL) + goto error_no_wimax_dev; + dev = wimax_dev_to_dev(wimax_dev); + /* Execute the operation and send the result back to user space */ + result = wimax_state_get(wimax_dev); + dev_put(wimax_dev->net_dev); +error_no_wimax_dev: + d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); + return result; +} + + +struct genl_ops wimax_gnl_state_get = { + .cmd = WIMAX_GNL_OP_STATE_GET, + .flags = GENL_ADMIN_PERM, + .policy = wimax_gnl_state_get_policy, + .doit = wimax_gnl_doit_state_get, + .dumpit = NULL, +}; diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 933e1422..79fb7d7 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init); extern struct genl_ops wimax_gnl_msg_from_user, wimax_gnl_reset, - wimax_gnl_rfkill; + wimax_gnl_rfkill, + wimax_gnl_state_get; static struct genl_ops *wimax_gnl_ops[] = { &wimax_gnl_msg_from_user, &wimax_gnl_reset, &wimax_gnl_rfkill, + &wimax_gnl_state_get, }; @@ -533,6 +535,7 @@ struct d_level D_LEVEL[] = { D_SUBMODULE_DEFINE(op_msg), D_SUBMODULE_DEFINE(op_reset), D_SUBMODULE_DEFINE(op_rfkill), + D_SUBMODULE_DEFINE(op_state_get), D_SUBMODULE_DEFINE(stack), }; size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); -- cgit v0.10.2 From 2618ab774ea015089c6eb84787f7ede6f2a2cbd0 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 8 May 2009 15:51:44 -0700 Subject: wimax/i2400m: usb: fix device reset on autosuspend while not yet idle When the i2400m is connected to a network, the host interface (USB) cannot be suspended. For that to happen, the device has to have negotiated with the basestation to put the link on IDLE state. If the host tries to put the device in standby while it is connected but not idle, the device resets, as the driver should not do that. To avoid triggering that, when the USB susbsytem requires the driver to autosuspend the device, the driver checks if the device is not yet idle. If it is not, the request is requested (will be retried again later on after the autosuspend timeout). At some point the device will enter idle and the request will succeed (unless of course, there is network traffic, but at that point, there is no idle neither in the link or the host interface). Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index ca4151a..1785132 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) #ifdef CONFIG_PM struct usb_device *usb_dev = i2400mu->usb_dev; #endif + unsigned is_autosuspend = 0; struct i2400m *i2400m = &i2400mu->i2400m; +#ifdef CONFIG_PM + if (usb_dev->auto_pm > 0) + is_autosuspend = 1; +#endif + d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); if (i2400m->updown == 0) goto no_firmware; - d_printf(1, dev, "fw up, requesting standby\n"); + if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { + /* ugh -- the device is connected and this suspend + * request is an autosuspend one (not a system standby + * / hibernate). + * + * The only way the device can go to standby is if the + * link with the base station is in IDLE mode; that + * were the case, we'd be in status + * I2400M_SS_CONNECTED_IDLE. But we are not. + * + * If we *tell* him to go power save now, it'll reset + * as a precautionary measure, so if this is an + * autosuspend thing, say no and it'll come back + * later, when the link is IDLE + */ + result = -EBADF; + d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " + "not entering powersave\n"); + goto error_not_now; + } + d_printf(1, dev, "fw up: entering powersave\n"); atomic_dec(&i2400mu->do_autopm); result = i2400m_cmd_enter_powersave(i2400m); atomic_inc(&i2400mu->do_autopm); -#ifdef CONFIG_PM - if (result < 0 && usb_dev->auto_pm == 0) { + if (result < 0 && !is_autosuspend) { /* System suspend, can't fail */ dev_err(dev, "failed to suspend, will reset on resume\n"); result = 0; } -#endif if (result < 0) goto error_enter_powersave; i2400mu_notification_release(i2400mu); - d_printf(1, dev, "fw up, got standby\n"); + d_printf(1, dev, "powersave requested\n"); error_enter_powersave: +error_not_now: no_firmware: d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", iface, pm_msg.event, result); -- cgit v0.10.2 From 7481806dcfd07e9a636155554f6f4b4fbd976381 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 22 May 2009 00:41:11 -0700 Subject: wimax: a new API call was added, increment minor protocol version number As the 'state_get' API call was added, we need to increase the minor protocol version number so applications that depend on the can check it's presence. Signed-off-by: Inaky Perez-Gonzalez diff --git a/include/linux/wimax.h b/include/linux/wimax.h index 2f7a6b7..4fdcc56 100644 --- a/include/linux/wimax.h +++ b/include/linux/wimax.h @@ -59,7 +59,7 @@ enum { * M - Major: change if removing or modifying an existing call. * m - minor: change when adding a new call */ - WIMAX_GNL_VERSION = 00, + WIMAX_GNL_VERSION = 01, /* Generic NetLink attributes */ WIMAX_GNL_ATTR_INVALID = 0x00, WIMAX_GNL_ATTR_MAX = 10, -- cgit v0.10.2 From 915219441d566f1da0caa0e262be49b666159e17 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 21:35:47 -0700 Subject: tcp: Use SKB queue and list helpers instead of doing it by-hand. Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0fb8b44..17b89c5 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -439,12 +439,14 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) !tp->urg_data || before(tp->urg_seq, tp->copied_seq) || !before(tp->urg_seq, tp->rcv_nxt)) { + struct sk_buff *skb; + answ = tp->rcv_nxt - tp->copied_seq; /* Subtract 1, if FIN is in queue. */ - if (answ && !skb_queue_empty(&sk->sk_receive_queue)) - answ -= - tcp_hdr((struct sk_buff *)sk->sk_receive_queue.prev)->fin; + skb = skb_peek_tail(&sk->sk_receive_queue); + if (answ && skb) + answ -= tcp_hdr(skb)->fin; } else answ = tp->urg_seq - tp->copied_seq; release_sock(sk); @@ -1382,11 +1384,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Next get a buffer. */ - skb = skb_peek(&sk->sk_receive_queue); - do { - if (!skb) - break; - + skb_queue_walk(&sk->sk_receive_queue, skb) { /* Now that we have two receive queues this * shouldn't happen. */ @@ -1403,8 +1401,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (tcp_hdr(skb)->fin) goto found_fin_ok; WARN_ON(!(flags & MSG_PEEK)); - skb = skb->next; - } while (skb != (struct sk_buff *)&sk->sk_receive_queue); + } /* Well, if we have backlog, try to process it now yet. */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index eeb8a92..ba34a23 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4426,7 +4426,7 @@ drop: } __skb_queue_head(&tp->out_of_order_queue, skb); } else { - struct sk_buff *skb1 = tp->out_of_order_queue.prev; + struct sk_buff *skb1 = skb_peek_tail(&tp->out_of_order_queue); u32 seq = TCP_SKB_CB(skb)->seq; u32 end_seq = TCP_SKB_CB(skb)->end_seq; @@ -4443,15 +4443,18 @@ drop: } /* Find place to insert this segment. */ - do { + while (1) { if (!after(TCP_SKB_CB(skb1)->seq, seq)) break; - } while ((skb1 = skb1->prev) != - (struct sk_buff *)&tp->out_of_order_queue); + if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) { + skb1 = NULL; + break; + } + skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1); + } /* Do skb overlap to previous one? */ - if (skb1 != (struct sk_buff *)&tp->out_of_order_queue && - before(seq, TCP_SKB_CB(skb1)->end_seq)) { + if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { /* All the bits are present. Drop. */ __kfree_skb(skb); @@ -4463,24 +4466,41 @@ drop: tcp_dsack_set(sk, seq, TCP_SKB_CB(skb1)->end_seq); } else { - skb1 = skb1->prev; + if (skb_queue_is_first(&tp->out_of_order_queue, + skb1)) + skb1 = NULL; + else + skb1 = skb_queue_prev( + &tp->out_of_order_queue, + skb1); } } - __skb_queue_after(&tp->out_of_order_queue, skb1, skb); + if (!skb1) + __skb_queue_head(&tp->out_of_order_queue, skb); + else + __skb_queue_after(&tp->out_of_order_queue, skb1, skb); /* And clean segments covered by new one as whole. */ - while ((skb1 = skb->next) != - (struct sk_buff *)&tp->out_of_order_queue && - after(end_seq, TCP_SKB_CB(skb1)->seq)) { - if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) { + if (skb1 && !skb_queue_is_last(&tp->out_of_order_queue, skb1)) { + struct sk_buff *n; + + skb1 = skb_queue_next(&tp->out_of_order_queue, skb1); + skb_queue_walk_from_safe(&tp->out_of_order_queue, + skb1, n) { + if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) + break; + if (before(end_seq, + TCP_SKB_CB(skb1)->end_seq)) { + tcp_dsack_extend(sk, + TCP_SKB_CB(skb1)->seq, + end_seq); + break; + } + __skb_unlink(skb1, &tp->out_of_order_queue); tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, - end_seq); - break; + TCP_SKB_CB(skb1)->end_seq); + __kfree_skb(skb1); } - __skb_unlink(skb1, &tp->out_of_order_queue); - tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, - TCP_SKB_CB(skb1)->end_seq); - __kfree_skb(skb1); } add_sack: @@ -4492,7 +4512,10 @@ add_sack: static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *list) { - struct sk_buff *next = skb->next; + struct sk_buff *next = NULL; + + if (!skb_queue_is_last(list, skb)) + next = skb_queue_next(list, skb); __skb_unlink(skb, list); __kfree_skb(skb); @@ -4503,6 +4526,9 @@ static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, /* Collapse contiguous sequence of skbs head..tail with * sequence numbers start..end. + * + * If tail is NULL, this means until the end of the list. + * * Segments with FIN/SYN are not collapsed (only because this * simplifies code) */ @@ -4511,15 +4537,23 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end) { - struct sk_buff *skb; + struct sk_buff *skb, *n; + bool end_of_skbs; /* First, check that queue is collapsible and find * the point where collapsing can be useful. */ - for (skb = head; skb != tail;) { + skb = head; +restart: + end_of_skbs = true; + skb_queue_walk_from_safe(list, skb, n) { + if (skb == tail) + break; /* No new bits? It is possible on ofo queue. */ if (!before(start, TCP_SKB_CB(skb)->end_seq)) { skb = tcp_collapse_one(sk, skb, list); - continue; + if (!skb) + break; + goto restart; } /* The first skb to collapse is: @@ -4529,16 +4563,24 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, */ if (!tcp_hdr(skb)->syn && !tcp_hdr(skb)->fin && (tcp_win_from_space(skb->truesize) > skb->len || - before(TCP_SKB_CB(skb)->seq, start) || - (skb->next != tail && - TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb->next)->seq))) + before(TCP_SKB_CB(skb)->seq, start))) { + end_of_skbs = false; break; + } + + if (!skb_queue_is_last(list, skb)) { + struct sk_buff *next = skb_queue_next(list, skb); + if (next != tail && + TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(next)->seq) { + end_of_skbs = false; + break; + } + } /* Decided to skip this, advance start seq. */ start = TCP_SKB_CB(skb)->end_seq; - skb = skb->next; } - if (skb == tail || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin) + if (end_of_skbs || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin) return; while (before(start, end)) { @@ -4583,7 +4625,8 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, } if (!before(start, TCP_SKB_CB(skb)->end_seq)) { skb = tcp_collapse_one(sk, skb, list); - if (skb == tail || + if (!skb || + skb == tail || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin) return; @@ -4610,17 +4653,21 @@ static void tcp_collapse_ofo_queue(struct sock *sk) head = skb; for (;;) { - skb = skb->next; + struct sk_buff *next = NULL; + + if (!skb_queue_is_last(&tp->out_of_order_queue, skb)) + next = skb_queue_next(&tp->out_of_order_queue, skb); + skb = next; /* Segment is terminated when we see gap or when * we are at the end of all the queue. */ - if (skb == (struct sk_buff *)&tp->out_of_order_queue || + if (!skb || after(TCP_SKB_CB(skb)->seq, end) || before(TCP_SKB_CB(skb)->end_seq, start)) { tcp_collapse(sk, &tp->out_of_order_queue, head, skb, start, end); head = skb; - if (skb == (struct sk_buff *)&tp->out_of_order_queue) + if (!skb) break; /* Start new segment */ start = TCP_SKB_CB(skb)->seq; @@ -4681,10 +4728,11 @@ static int tcp_prune_queue(struct sock *sk) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); tcp_collapse_ofo_queue(sk); - tcp_collapse(sk, &sk->sk_receive_queue, - sk->sk_receive_queue.next, - (struct sk_buff *)&sk->sk_receive_queue, - tp->copied_seq, tp->rcv_nxt); + if (!skb_queue_empty(&sk->sk_receive_queue)) + tcp_collapse(sk, &sk->sk_receive_queue, + skb_peek(&sk->sk_receive_queue), + NULL, + tp->copied_seq, tp->rcv_nxt); sk_mem_reclaim(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) -- cgit v0.10.2 From 528be7ff823c3d0fc08c91f31b1e84c5f2681762 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 23:26:33 -0700 Subject: irda: Use SKB queue and list helpers instead of doing it by-hand. Signed-off-by: David S. Miller diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 2562ebc..7af2e74 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -982,17 +982,12 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) { struct sk_buff *tx_skb; struct sk_buff *skb; - int count; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - /* Initialize variables */ - count = skb_queue_len(&self->wx_list); - /* Resend unacknowledged frame(s) */ - skb = skb_peek(&self->wx_list); - while (skb != NULL) { + skb_queue_walk(&self->wx_list, skb) { irlap_wait_min_turn_around(self, &self->qos_tx); /* We copy the skb to be retransmitted since we will have to @@ -1011,21 +1006,12 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) /* * Set poll bit on the last frame retransmitted */ - if (count-- == 1) + if (skb_queue_is_last(&self->wx_list, skb)) tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ else tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */ irlap_send_i_frame(self, tx_skb, command); - - /* - * If our skb is the last buffer in the list, then - * we are finished, if not, move to the next sk-buffer - */ - if (skb == skb_peek_tail(&self->wx_list)) - skb = NULL; - else - skb = skb->next; } #if 0 /* Not yet */ /* -- cgit v0.10.2 From dfe9a837987aacaffbce020fbf54d8e0afa4bde1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 May 2009 23:31:56 -0700 Subject: llc: Kill outdated and incorrect comment. This comment suggested storing two pieces of state in the LLC skb control block, and in fact we do. Someone did the implementation but never killed this todo comment :-) Signed-off-by: David S. Miller diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 3477624..c6bab39 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -79,10 +79,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) if (unlikely(!ev->ind_prim && !ev->cfm_prim)) { /* indicate or confirm not required */ - /* XXX this is not very pretty, perhaps we should store - * XXX indicate/confirm-needed state in the llc_conn_state_ev - * XXX control block of the SKB instead? -DaveM - */ if (!skb->next) goto out_kfree_skb; goto out_skb_put; -- cgit v0.10.2 From 28679751a924c11f7135641f26e99249385de5b4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 May 2009 19:26:37 +0000 Subject: net: dont update dev->trans_start in 10GB drivers Followup of commits 9d21493b4beb8f918ba248032fefa393074a5e2b and 08baf561083bc27a953aa087dd8a664bb2b88e8e (net: tx scalability works : trans_start) (net: txq_trans_update() helper) Now that core network takes care of trans_start updates, dont do it in drivers themselves, if possible. Multi queue drivers can avoid one cache miss (on dev->trans_start) in their start_xmit() handler. Exceptions are NETIF_F_LLTX drivers (vxge & tehuti) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index ae2f6b5..5f17d80 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -478,8 +478,6 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev) be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt); - netdev->trans_start = jiffies; - be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; } diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index e01539c..fbf1352 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10617,7 +10617,6 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) mmiowb(); fp->tx_bd_prod += nbd; - dev->trans_start = jiffies; if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { /* We want bnx2x_tx_int to "see" the updated tx_bd_prod diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 5e97a1a..3711d64 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1879,7 +1879,6 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) cpl->vlan_valid = 0; send: - dev->trans_start = jiffies; ret = t1_sge_tx(skb, adapter, 0, dev); /* If transmit busy, and we reallocated skb's due to headroom limit, diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 73d569e..49e64af 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1286,7 +1286,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (vlan_tx_tag_present(skb) && pi->vlan_grp) qs->port_stats[SGE_PSTAT_VLANINS]++; - dev->trans_start = jiffies; spin_unlock(&q->lock); /* diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 9080f07..8005b60 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -661,8 +661,6 @@ static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) 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; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 04cb81a..6eb7f37 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1488,7 +1488,6 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (count) { ixgb_tx_queue(adapter, count, vlan_id, tx_flags); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index dff1da8..924aa5e 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4863,7 +4863,6 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (count) { ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); } else { diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index ac6fc49..1c83a96 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -819,7 +819,6 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Ring doorbell! */ wmb(); writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL); - dev->trans_start = jiffies; /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 7e28b461..c9a30d3 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2892,7 +2892,6 @@ again: tx->stop_queue++; netif_tx_stop_queue(netdev_queue); } - dev->trans_start = jiffies; return 0; abort_linearize: diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 50477f5..98737ef 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1496,7 +1496,6 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) netxen_nic_update_cmd_producer(adapter, tx_ring, producer); adapter->stats.xmitcalled++; - netdev->trans_start = jiffies; return NETDEV_TX_OK; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c92ced2..0b0778d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2108,7 +2108,6 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) 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); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 80562ea..2bc73ed 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4299,7 +4299,6 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) s2io_stop_tx_queue(sp, fifo->fifo_no); } mac_control->stats_info->sw_stat.mem_allocated += skb->truesize; - dev->trans_start = jiffies; spin_unlock_irqrestore(&fifo->tx_lock, flags); if (sp->config.intr_type == MSI_X) diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 04379571..b67ccca 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -438,6 +438,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) kfree_skb(skb); return -EPIPE; } + efx->net_dev->trans_start = jiffies; } return 0; diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index d6681ed..14a1478 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -360,13 +360,6 @@ inline int efx_xmit(struct efx_nic *efx, /* Map fragments for DMA and add to TX queue */ rc = efx_enqueue_skb(tx_queue, skb); - if (unlikely(rc != NETDEV_TX_OK)) - goto out; - - /* Update last TX timer */ - efx->net_dev->trans_start = jiffies; - - out: return rc; } diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 7f4a968..093807a 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -1718,8 +1718,9 @@ static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); #endif - ndev->trans_start = jiffies; - +#ifdef BDX_LLTX + ndev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ +#endif priv->net_stats.tx_packets++; priv->net_stats.tx_bytes += skb->len; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index b7f08f3..6c838b3 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -677,7 +677,7 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, return VXGE_HW_OK; } -/* select a vpath to trasmit the packet */ +/* select a vpath to transmit the packet */ static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb, int *do_lock) { @@ -992,7 +992,9 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN); vxge_hw_fifo_txdl_post(fifo_hw, dtr); - dev->trans_start = jiffies; +#ifdef NETIF_F_LLTX + dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ +#endif spin_unlock_irqrestore(&fifo->tx_lock, flags); VXGE_COMPLETE_VPATH_TX(fifo); -- cgit v0.10.2 From cdd0db058d64f2619b08e7d098ee0014aa0a5bc1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 28 May 2009 00:00:41 +0000 Subject: net: dont update dev->trans_start Second round of drivers for Gb cards (and NIU one I forgot in the 10GB round) Now that core network takes care of trans_start updates, dont do it in drivers themselves, if possible. Drivers can avoid one cache miss (on dev->trans_start) in their start_xmit() handler. Exceptions are NETIF_F_LLTX drivers Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 57bc715..08419ee 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2573,7 +2573,6 @@ restart: netif_wake_queue(dev); } - dev->trans_start = jiffies; return NETDEV_TX_OK; overflow: diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index fc1092b..ac76136 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2113,7 +2113,6 @@ static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1c_tx_map(adapter, skb, tpd, type); atl1c_tx_queue(adapter, skb, tpd, type); - netdev->trans_start = jiffies; spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index c271b75..a01383d 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1893,7 +1893,7 @@ static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1e_tx_map(adapter, skb, tpd); atl1e_tx_queue(adapter, tpd_req, tpd); - netdev->trans_start = jiffies; + netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 13f0bdc..fccfbf2 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2431,7 +2431,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1_tx_queue(adapter, count, ptpd); atl1_update_mailbox(adapter); mmiowb(); - netdev->trans_start = jiffies; return NETDEV_TX_OK; } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index c37acc1..83ee0f5 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6211,7 +6211,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mmiowb(); txr->tx_prod = prod; - dev->trans_start = jiffies; if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) { netif_tx_stop_queue(txq); diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 4a1b554..895d721 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -539,7 +539,7 @@ rio_tx_timeout (struct net_device *dev) dev->name, readl (ioaddr + TxStatus)); rio_free_tx(dev, 0); dev->if_port = 0; - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ } /* allocate and initialize Tx and Rx descriptors */ @@ -610,7 +610,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) if (np->link_status == 0) { /* Link Down */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } ioaddr = dev->base_addr; entry = np->cur_tx % TX_RING_SIZE; @@ -665,9 +665,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) writel (0, dev->base_addr + TFDListPtr1); } - /* NETDEV WATCHDOG timer */ - dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static irqreturn_t diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 9a32d0c..79fe1ee 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3365,7 +3365,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (count) { e1000_tx_queue(adapter, tx_ring, tx_flags, count); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index ccaaee0..f012cc6 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4149,7 +4149,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); if (count) { e1000_tx_queue(adapter, tx_flags, count); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 310ee03..26151fa 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1163,7 +1163,7 @@ static void hamachi_tx_timeout(struct net_device *dev) hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); /* Trigger an immediate transmit demand. */ - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ hmp->stats.tx_errors++; /* Restart the chip's Tx/Rx processes . */ @@ -1364,7 +1364,6 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) hmp->tx_full = 1; netif_stop_queue(dev); } - dev->trans_start = jiffies; if (hamachi_debug > 4) { printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 8e93750..958b287 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3344,7 +3344,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, if (count) { igb_tx_queue_adv(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4); } else { diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 44a8eef..5f7ba1a4 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2270,7 +2270,6 @@ static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb, if (count) { igbvf_tx_queue_adv(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ igbvf_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 4); } else { diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 621a7c0..1e3c63d 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1939,7 +1939,6 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) 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, diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 0d9de5a..edac3a0 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6777,8 +6777,6 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_tx_wake_queue(txq); } - dev->trans_start = jiffies; - out: return NETDEV_TX_OK; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index d531614..940962a 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1204,9 +1204,7 @@ again: if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev)) netif_start_queue(ndev); - /* set the transmit start time to catch transmit timeouts */ - ndev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void ns83820_update_stats(struct ns83820 *dev) @@ -1626,7 +1624,7 @@ static void ns83820_tx_watch(unsigned long data) ); #endif - if (time_after(jiffies, ndev->trans_start + 1*HZ) && + if (time_after(jiffies, dev_trans_start(ndev) + 1*HZ) && dev->tx_done_idx != dev->tx_free_idx) { printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n", ndev->name, diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index cadc32c..8a823ec 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2617,7 +2617,6 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) &port_regs->CommonRegs.reqQProducerIndex, qdev->req_producer_index); - ndev->trans_start = jiffies; if (netif_msg_tx_queued(qdev)) printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n", ndev->name, qdev->req_producer_index, skb->len); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0ec0605..7fa88d2 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3279,8 +3279,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); - dev->trans_start = jiffies; - tp->cur_tx += frags + 1; smp_wmb(); diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 55ccd51..13b8ca4 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1204,8 +1204,6 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb); - dev->trans_start = jiffies; - dirty_tx = tp->dirty_tx; if ((tp->cur_tx - NUM_TX_DESC) == dirty_tx) { netif_stop_queue(dev); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c11cdd0..60d502e 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2837,8 +2837,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - dev->trans_start = jiffies; - return NETDEV_TX_OK; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a2ff9cb..6b5946f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1690,7 +1690,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod); - dev->trans_start = jiffies; return NETDEV_TX_OK; mapping_unwind: diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eb65e25..a39b534 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5194,9 +5194,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } out_unlock: - mmiowb(); - - dev->trans_start = jiffies; + mmiowb(); return NETDEV_TX_OK; } @@ -5407,9 +5405,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) } out_unlock: - mmiowb(); - - dev->trans_start = jiffies; + mmiowb(); return NETDEV_TX_OK; } diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 7477ffd..3c7a505 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -717,7 +717,7 @@ static void yellowfin_tx_timeout(struct net_device *dev) if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_wake_queue (dev); /* Typical path */ - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ dev->stats.tx_errors++; } @@ -876,7 +876,6 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue (dev); /* Typical path */ else yp->tx_full = 1; - dev->trans_start = jiffies; if (yellowfin_debug > 4) { printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n", -- cgit v0.10.2 From 28e72216d7e7af7050f171a87c1eecba93d01ea6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 28 May 2009 10:44:30 +0000 Subject: net: unset IFF_XMIT_DST_RELEASE in ipip_tunnel_setup() ipip_tunnel_xmit() might need skb->dst, so tell dev_hard_start_xmit() to no release it. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 9054139..bb2f1b1 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -713,6 +713,7 @@ static void ipip_tunnel_setup(struct net_device *dev) dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static void ipip_tunnel_init(struct net_device *dev) -- cgit v0.10.2 From a489e51c1a69c3aa7e7aea925f71c92be5cedbb1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 28 May 2009 11:14:49 +0000 Subject: atm: unset IFF_XMIT_DST_RELEASE in clip_setup() clip_start_xmit() needs skb->dst so tell dev_hard_start_xmit() to no release it. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/atm/clip.c b/net/atm/clip.c index 5597b87..fb7623c 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -557,6 +557,7 @@ static void clip_setup(struct net_device *dev) /* without any more elaborate queuing. 100 is a reasonable */ /* compromise between decent burst-tolerance and protection */ /* against memory hogs. */ + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static int clip_create(int number) -- cgit v0.10.2 From 108bfa895cacd1a7c1767e85be105b213e5dce50 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 28 May 2009 22:35:10 +0000 Subject: net: unset IFF_XMIT_DST_RELEASE in ipgre_tunnel_setup() ipgre_tunnel_xmit() might need skb->dst, so tell dev_hard_start_xmit() to no release it. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index e62510d..77436e2 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1238,6 +1238,7 @@ static void ipgre_tunnel_setup(struct net_device *dev) dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static int ipgre_tunnel_init(struct net_device *dev) -- cgit v0.10.2 From 5d23a1d2a317e272f171d7818f600fde324eaceb Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 27 May 2009 15:10:42 +0000 Subject: net: replace dma_sync_single with dma_sync_single_for_cpu This replaces dma_sync_single() with dma_sync_single_for_cpu() because dma_sync_single() is an obsolete API; include/linux/dma-mapping.h says: /* Backwards compat, remove in 2.7.x */ #define dma_sync_single dma_sync_single_for_cpu #define dma_sync_sg dma_sync_sg_for_cpu Signed-off-by: FUJITA Tomonori Signed-off-by: David S. Miller diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index b72b3d6..fbf4645 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -253,7 +253,7 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) skb = dev_alloc_skb(length + 2); if (likely(skb != NULL)) { skb_reserve(skb, 2); - dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr, + dma_sync_single_for_cpu(NULL, ep->descs->rdesc[entry].buf_addr, length, DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, ep->rx_buf[entry], length); skb_put(skb, length); @@ -331,7 +331,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) ep->descs->tdesc[entry].tdesc1 = TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); skb_copy_and_csum_dev(skb, ep->tx_buf[entry]); - dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr, + dma_sync_single_for_cpu(NULL, ep->descs->tdesc[entry].buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb(skb); diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 322c49b..1fcf838 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -561,8 +561,8 @@ static int eth_poll(struct napi_struct *napi, int budget) dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN, RX_BUFF_SIZE, DMA_FROM_DEVICE); #else - dma_sync_single(&dev->dev, desc->data - NET_IP_ALIGN, - RX_BUFF_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(&dev->dev, desc->data - NET_IP_ALIGN, + RX_BUFF_SIZE, DMA_FROM_DEVICE); memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4); #endif diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 0caf74c..0a46778 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -402,7 +402,8 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, for (i = 0; i < npages; ++i) mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, + npages * sizeof (u64), DMA_TO_DEVICE); return 0; } @@ -549,8 +550,8 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list for (i = 0; i < npages; ++i) fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, fmr->dma_handle, - npages * sizeof(u64), DMA_TO_DEVICE); + dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); fmr->mpt->key = cpu_to_be32(key); fmr->mpt->lkey = cpu_to_be32(key); diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 765a7f5..08b1a28 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -731,8 +731,8 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget) dma_unmap_single(&dev->dev, desc->data, RX_SIZE, DMA_FROM_DEVICE); #else - dma_sync_single(&dev->dev, desc->data, - RX_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(&dev->dev, desc->data, + RX_SIZE, DMA_FROM_DEVICE); memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], ALIGN(desc->pkt_len, 4) / 4); #endif -- cgit v0.10.2 From 4d5ef9f0f588045d5e53e51816bd619d82385676 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 28 May 2009 00:58:41 +0000 Subject: korina: periodically poll the media This patch makes the korina driver poll the media for link change. This is actually required on Mikrotik RB532 (not RB532A) for korina to operate properly. Signed-off-by: Felix Fietkau Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/korina.c b/drivers/net/korina.c index dc23856..b4cf602 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -133,6 +133,7 @@ struct korina_private { int dma_halt_cnt; int dma_run_cnt; struct napi_struct napi; + struct timer_list media_check_timer; struct mii_if_info mii_if; struct net_device *dev; int phy_addr; @@ -664,6 +665,15 @@ static void korina_check_media(struct net_device *dev, unsigned int init_media) &lp->eth_regs->ethmac2); } +static void korina_poll_media(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct korina_private *lp = netdev_priv(dev); + + korina_check_media(dev, 0); + mod_timer(&lp->media_check_timer, jiffies + HZ); +} + static void korina_set_carrier(struct mii_if_info *mii) { if (mii->force_media) { @@ -1034,6 +1044,7 @@ static int korina_open(struct net_device *dev) dev->name, lp->und_irq); goto err_free_ovr_irq; } + mod_timer(&lp->media_check_timer, jiffies + 1); out: return ret; @@ -1053,6 +1064,8 @@ static int korina_close(struct net_device *dev) struct korina_private *lp = netdev_priv(dev); u32 tmp; + del_timer(&lp->media_check_timer); + /* Disable interrupts */ disable_irq(lp->rx_irq); disable_irq(lp->tx_irq); @@ -1183,6 +1196,7 @@ static int korina_probe(struct platform_device *pdev) ": cannot register net device %d\n", rc); goto probe_err_register; } + setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev); out: return rc; -- cgit v0.10.2 From 5d4e039b2cb1ca4de9774344ea7b61ad7fa1b0a1 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 May 2009 01:05:00 +0000 Subject: bonding: allow bond in mode balance-alb to work properly in bridge -try4.3 [PATCH net-next] bonding: allow bond in mode balance-alb to work properly in bridge -try4.3 (updated) changes v4.2 -> v4.3 - memcpy the address always, not just in case it differs from master->dev_addr - compare_ether_addr_64bits() is not used so there is no direct need to make new header file (I think it would be good to have bond stuff in separate file anyway). changes v4.1 -> v4.2 - use skb->pkt_type == PACKET_HOST compare rather then comparing skb dest addr against skb->dev->dev_addr The problem is described in following bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=487763 Basically here's what's going on. In every mode, bonding interface uses the same mac address for all enslaved devices (except fail_over_mac). Only balance-alb will simultaneously use multiple MAC addresses across different slaves. When you put this kind of bond device into a bridge it will only add one of mac adresses into a hash list of mac addresses, say X. This mac address is marked as local. But this bonding interface also has mac address Y. Now then packet arrives with destination address Y, this address is not marked as local and the packed looks like it needs to be forwarded. This packet is then lost which is wrong. Notice that interfaces can be added and removed from bond while it is in bridge. *** When the multiple addresses for bridge port approach failed to solve this issue due to STP I started to think other way to solve this. I returned to previous solution but tweaked one. This patch solves the situation in the bonding without touching bridge code. For every incoming frame to bonding the destination address is compared to current address of the slave device from which tha packet came. If these two match destination address is replaced by mac address of the master. This address is known by bridge so it is delivered properly. Note that the comparsion is not made directly, it's used skb->pkt_type == PACKET_HOST instead. This is "set" previously in eth_type_trans(). I experimentally tried that this works as good as searching through the slave list (v4 of this patch). Jirka Signed-off-by: Jiri Pirko Signed-off-by: Eric Dumazet Signed-off-by: Andy Gospodarek Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8e03b06..1eaf5ae 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1917,6 +1917,16 @@ static inline void netif_set_gso_max_size(struct net_device *dev, dev->gso_max_size = size; } +static inline void skb_bond_set_mac_by_master(struct sk_buff *skb, + struct net_device *master) +{ + if (skb->pkt_type == PACKET_HOST) { + u16 *dest = (u16 *) eth_hdr(skb)->h_dest; + + memcpy(dest, master->dev_addr, ETH_ALEN); + } +} + /* On bonding slaves other than the currently active slave, suppress * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and * ARP on active-backup slaves with arp_validate enabled. @@ -1930,6 +1940,14 @@ static inline int skb_bond_should_drop(struct sk_buff *skb) if (master->priv_flags & IFF_MASTER_ARPMON) dev->last_rx = jiffies; + if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) { + /* Do address unmangle. The local destination address + * will be always the one master has. Provides the right + * functionality in a bridge. + */ + skb_bond_set_mac_by_master(skb, master); + } + if (dev->priv_flags & IFF_SLAVE_INACTIVE) { if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && skb->protocol == __cpu_to_be16(ETH_P_ARP)) -- cgit v0.10.2 From 2df9001edc382c331f338f45d259feeaa740c418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 May 2009 15:02:29 -0700 Subject: tcp: fix loop in ofo handling code and reduce its complexity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Somewhat luckily, I was looking into these parts with very fine comb because I've made somewhat similar changes on the same area (conflicts that arose weren't that lucky though). The loop was very much overengineered recently in commit 915219441d566 (tcp: Use SKB queue and list helpers instead of doing it by-hand), while it basically just wants to know if there are skbs after 'skb'. Also it got broken because skb1 = skb->next got translated into skb1 = skb1->next (though abstracted) improperly. Note that 'skb1' is pointing to previous sk_buff than skb or NULL if at head. Two things went wrong: - We'll kfree 'skb' on the first iteration instead of the skbuff following 'skb' (it would require required SACK reneging to recover I think). - The list head case where 'skb1' is NULL is checked too early and the loop won't execute whereas it previously did. Conclusion, mostly revert the recent changes which makes the cset very messy looking but using proper accessor in the previous-like version. The effective changes against the original can be viewed with: git-diff 915219441d566f1da0caa0e262be49b666159e17^ \ net/ipv4/tcp_input.c | sed -n -e '57,70 p' Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ba34a23..2bdb0da 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4481,26 +4481,20 @@ drop: __skb_queue_after(&tp->out_of_order_queue, skb1, skb); /* And clean segments covered by new one as whole. */ - if (skb1 && !skb_queue_is_last(&tp->out_of_order_queue, skb1)) { - struct sk_buff *n; + while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) { + skb1 = skb_queue_next(&tp->out_of_order_queue, skb); - skb1 = skb_queue_next(&tp->out_of_order_queue, skb1); - skb_queue_walk_from_safe(&tp->out_of_order_queue, - skb1, n) { - if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) - break; - if (before(end_seq, - TCP_SKB_CB(skb1)->end_seq)) { - tcp_dsack_extend(sk, - TCP_SKB_CB(skb1)->seq, - end_seq); - break; - } - __skb_unlink(skb1, &tp->out_of_order_queue); + if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) + break; + if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) { tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, - TCP_SKB_CB(skb1)->end_seq); - __kfree_skb(skb1); + end_seq); + break; } + __skb_unlink(skb1, &tp->out_of_order_queue); + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, + TCP_SKB_CB(skb1)->end_seq); + __kfree_skb(skb1); } add_sack: -- cgit v0.10.2 From 60df914e295a21a223e43a7ee01e0c73c64dd111 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 May 2009 15:15:30 -0700 Subject: veth: dont release skb->dst in veth_xmit() No need to release skb->dst, its now done by core network. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8e56fcf..87197dd 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -176,8 +176,6 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) if (dev->features & NETIF_F_NO_CSUM) skb->ip_summed = rcv_priv->ip_summed; - dst_release(skb->dst); - skb->dst = NULL; skb->mark = 0; secpath_reset(skb); nf_reset(skb); -- cgit v0.10.2 From 91a455f089810625eb94a36ccc40ae963f451b06 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 29 May 2009 03:39:45 +0000 Subject: netdev: bfin_mac: drop useless IRQF_SHARED from Blackfin EMAC interrupt The IRQ used by the Blackfin EMAC is internal to the peripheral and cannot be used to generate any other interrupt, so there is no point in marking it as IRQF_SHARED. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: David S. Miller diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 9f971ed..1905532 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -1108,7 +1108,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) /* now, enable interrupts */ /* register irq handler */ rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt, - IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev); + IRQF_DISABLED, "EMAC_RX", ndev); if (rc) { dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n"); rc = -EBUSY; -- cgit v0.10.2 From 805a8ab3ce1be83e9a98c21a625ebbb549a2d317 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Fri, 29 May 2009 03:40:43 +0000 Subject: netdev: bfin_mac: fix malformed UDP packet transmission when polling with KGDB Writes to the DMA descriptors may sit in the internal Blackfin data buffers and not actually be available when the DMA engine goes to fetch them. This does not typically happen, but when dealing with short/fast packets such as UDP and polling KGDB, this occurs much more frequently. Same goes for heavy loads as seen by netperf tests or large scp transfers. So force the buffers to drain with SSYNC otherwise we get random malformed packets. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: David S. Miller diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 1905532..38d34ce 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -688,6 +688,12 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb, } } + /* make sure the internal data buffers in the core are drained + * so that the DMA descriptors are completely written when the + * DMA engine goes to fetch them below + */ + SSYNC(); + /* enable this packet's dma */ current_tx_ptr->desc_a.config |= DMAEN; -- cgit v0.10.2 From 015dac8886b5c48d62ebc33a964b9086d6a71bd7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 29 May 2009 03:41:15 +0000 Subject: netdev: bfin_mac: fix performance issue found by netperf - Remove dead long delay - Use proper defines - Remove broken implementation of the TX DMA Data Alignment TXDWA feature Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: David S. Miller diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 38d34ce..f0f1eb9 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -194,13 +194,13 @@ static int desc_list_init(void) struct dma_descriptor *b = &(r->desc_b); /* allocate a new skb for next time receive */ - new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); + new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN); if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": init: low on mem - packet dropped\n"); goto init_error; } - skb_reserve(new_skb, 2); + skb_reserve(new_skb, NET_IP_ALIGN); r->skb = new_skb; /* @@ -566,9 +566,9 @@ static void adjust_tx_list(void) */ if (current_tx_ptr->next->next == tx_list_head) { while (tx_list_head->status.status_word == 0) { - mdelay(1); + udelay(10); if (tx_list_head->status.status_word != 0 - || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) { + || !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) { goto adjust_head; } if (timeout_cnt-- < 0) { @@ -606,86 +606,28 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { u16 *data; - + u32 data_align = (unsigned long)(skb->data) & 0x3; current_tx_ptr->skb = skb; - if (ANOMALY_05000285) { - /* - * TXDWA feature is not avaible to older revision < 0.3 silicon - * of BF537 - * - * Only if data buffer is ODD WORD alignment, we do not - * need to memcpy - */ - u32 data_align = (u32)(skb->data) & 0x3; - if (data_align == 0x2) { - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 1; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range((u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else { - *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); - memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, - skb->len); - current_tx_ptr->desc_a.start_addr = - (u32)current_tx_ptr->packet; - if (current_tx_ptr->status.status_word != 0) - current_tx_ptr->status.status_word = 0; - blackfin_dcache_flush_range( - (u32)current_tx_ptr->packet, - (u32)(current_tx_ptr->packet + skb->len + 2)); - } + if (data_align == 0x2) { + /* move skb->data to current_tx_ptr payload */ + data = (u16 *)(skb->data) - 1; + *data = (u16)(skb->len); + current_tx_ptr->desc_a.start_addr = (u32)data; + /* this is important! */ + blackfin_dcache_flush_range((u32)data, + (u32)((u8 *)data + skb->len + 4)); } else { - /* - * TXDWA feature is avaible to revision < 0.3 silicon of - * BF537 and always avaible to BF52x - */ - u32 data_align = (u32)(skb->data) & 0x3; - if (data_align == 0x0) { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl |= TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 2; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range( - (u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else if (data_align == 0x2) { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl &= ~TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 1; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range( - (u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl &= ~TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); - memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, - skb->len); - current_tx_ptr->desc_a.start_addr = - (u32)current_tx_ptr->packet; - if (current_tx_ptr->status.status_word != 0) - current_tx_ptr->status.status_word = 0; - blackfin_dcache_flush_range( - (u32)current_tx_ptr->packet, - (u32)(current_tx_ptr->packet + skb->len + 2)); - } + *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); + memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, + skb->len); + current_tx_ptr->desc_a.start_addr = + (u32)current_tx_ptr->packet; + if (current_tx_ptr->status.status_word != 0) + current_tx_ptr->status.status_word = 0; + blackfin_dcache_flush_range( + (u32)current_tx_ptr->packet, + (u32)(current_tx_ptr->packet + skb->len + 2)); } /* make sure the internal data buffers in the core are drained @@ -698,7 +640,7 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb, current_tx_ptr->desc_a.config |= DMAEN; /* tx dma is running, just return */ - if (bfin_read_DMA2_IRQ_STATUS() & 0x08) + if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN) goto out; /* tx dma is not running */ @@ -724,7 +666,7 @@ static void bfin_mac_rx(struct net_device *dev) /* allocate a new skb for next time receive */ skb = current_rx_ptr->skb; - new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); + new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN); if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": rx: low on mem - packet dropped\n"); @@ -732,7 +674,7 @@ static void bfin_mac_rx(struct net_device *dev) goto out; } /* reserve 2 bytes for RXDWA padding */ - skb_reserve(new_skb, 2); + skb_reserve(new_skb, NET_IP_ALIGN); current_rx_ptr->skb = new_skb; current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2; -- cgit v0.10.2 From 080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Fri, 29 May 2009 03:41:48 +0000 Subject: netdev: bfin_mac: add Blackfin MII bus to platform bus to allow DSA access When we register the MII bus to the platfrom bus, the Distributed Switch Architecture can hook in transparently. Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index f0f1eb9..955a469 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -971,7 +971,8 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) { struct net_device *ndev; struct bfin_mac_local *lp; - int rc, i; + struct platform_device *pd; + int rc; ndev = alloc_etherdev(sizeof(struct bfin_mac_local)); if (!ndev) { @@ -996,13 +997,6 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) goto out_err_probe_mac; } - /* set the GPIO pins to Ethernet mode */ - rc = peripheral_request_list(pin_req, DRV_NAME); - if (rc) { - dev_err(&pdev->dev, "Requesting peripherals failed!\n"); - rc = -EFAULT; - goto out_err_setup_pin_mux; - } /* * Is it valid? (Did bootloader initialize it?) @@ -1018,26 +1012,14 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) setup_mac_addr(ndev->dev_addr); - /* MDIO bus initial */ - 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; - - rc = mdiobus_register(lp->mii_bus); - if (rc) { - dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); - goto out_err_mdiobus_register; + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "Cannot get platform device bfin_mii_bus!\n"); + rc = -ENODEV; + goto out_err_probe_mac; } + pd = pdev->dev.platform_data; + lp->mii_bus = platform_get_drvdata(pd); + lp->mii_bus->priv = ndev; rc = mii_probe(ndev); if (rc) { @@ -1079,11 +1061,8 @@ out_err_reg_ndev: out_err_request_irq: out_err_mii_probe: 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: platform_set_drvdata(pdev, NULL); free_netdev(ndev); @@ -1098,8 +1077,7 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - mdiobus_unregister(lp->mii_bus); - mdiobus_free(lp->mii_bus); + lp->mii_bus->priv = NULL; unregister_netdev(ndev); @@ -1137,6 +1115,74 @@ static int bfin_mac_resume(struct platform_device *pdev) #define bfin_mac_resume NULL #endif /* CONFIG_PM */ +static int __devinit bfin_mii_bus_probe(struct platform_device *pdev) +{ + struct mii_bus *miibus; + int rc, i; + + /* + * We are setting up a network card, + * so set the GPIO pins to Ethernet mode + */ + rc = peripheral_request_list(pin_req, DRV_NAME); + if (rc) { + dev_err(&pdev->dev, "Requesting peripherals failed!\n"); + return rc; + } + + rc = -ENOMEM; + miibus = mdiobus_alloc(); + if (miibus == NULL) + goto out_err_alloc; + miibus->read = bfin_mdiobus_read; + miibus->write = bfin_mdiobus_write; + miibus->reset = bfin_mdiobus_reset; + + miibus->parent = &pdev->dev; + miibus->name = "bfin_mii_bus"; + snprintf(miibus->id, MII_BUS_ID_SIZE, "0"); + miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (miibus->irq == NULL) + goto out_err_alloc; + for (i = 0; i < PHY_MAX_ADDR; ++i) + miibus->irq[i] = PHY_POLL; + + rc = mdiobus_register(miibus); + if (rc) { + dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); + goto out_err_mdiobus_register; + } + + platform_set_drvdata(pdev, miibus); + return 0; + +out_err_mdiobus_register: + mdiobus_free(miibus); +out_err_alloc: + peripheral_free_list(pin_req); + + return rc; +} + +static int __devexit bfin_mii_bus_remove(struct platform_device *pdev) +{ + struct mii_bus *miibus = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + mdiobus_unregister(miibus); + mdiobus_free(miibus); + peripheral_free_list(pin_req); + return 0; +} + +static struct platform_driver bfin_mii_bus_driver = { + .probe = bfin_mii_bus_probe, + .remove = __devexit_p(bfin_mii_bus_remove), + .driver = { + .name = "bfin_mii_bus", + .owner = THIS_MODULE, + }, +}; + static struct platform_driver bfin_mac_driver = { .probe = bfin_mac_probe, .remove = __devexit_p(bfin_mac_remove), @@ -1150,7 +1196,11 @@ static struct platform_driver bfin_mac_driver = { static int __init bfin_mac_init(void) { - return platform_driver_register(&bfin_mac_driver); + int ret; + ret = platform_driver_register(&bfin_mii_bus_driver); + if (!ret) + return platform_driver_register(&bfin_mac_driver); + return -ENODEV; } module_init(bfin_mac_init); @@ -1158,6 +1208,7 @@ module_init(bfin_mac_init); static void __exit bfin_mac_cleanup(void) { platform_driver_unregister(&bfin_mac_driver); + platform_driver_unregister(&bfin_mii_bus_driver); } module_exit(bfin_mac_cleanup); -- cgit v0.10.2 From c3a8c5b644118b5e2cfd0690b1dcea904a792c52 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Fri, 29 May 2009 12:52:38 +0000 Subject: cxgb3: move away from LLTX cxgb3 no longer advertizes LLTX. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 0b87fee..1fe4b07 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -3059,7 +3059,6 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; - netdev->features |= NETIF_F_LLTX; netdev->features |= NETIF_F_GRO; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 49e64af..0b97882 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1241,7 +1241,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) q = &qs->txq[TXQ_ETH]; txq = netdev_get_tx_queue(dev, qidx); - spin_lock(&q->lock); reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); credits = q->size - q->in_use; @@ -1252,7 +1251,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) dev_err(&adap->pdev->dev, "%s: Tx ring %u full while queue awake!\n", dev->name, q->cntxt_id & 7); - spin_unlock(&q->lock); return NETDEV_TX_BUSY; } @@ -1286,8 +1284,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (vlan_tx_tag_present(skb) && pi->vlan_grp) qs->port_stats[SGE_PSTAT_VLANINS]++; - spin_unlock(&q->lock); - /* * We do not use Tx completion interrupts to free DMAd Tx packets. * This is good for performamce but means that we rely on new Tx @@ -2857,11 +2853,12 @@ static void sge_timer_tx(unsigned long data) unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; unsigned long next_period; - if (spin_trylock(&qs->txq[TXQ_ETH].lock)) { - tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], - TX_RECLAIM_TIMER_CHUNK); - spin_unlock(&qs->txq[TXQ_ETH].lock); + if (__netif_tx_trylock(qs->tx_q)) { + tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], + TX_RECLAIM_TIMER_CHUNK); + __netif_tx_unlock(qs->tx_q); } + if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD], TX_RECLAIM_TIMER_CHUNK); @@ -2869,8 +2866,8 @@ static void sge_timer_tx(unsigned long data) } next_period = TX_RECLAIM_PERIOD >> - (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / - TX_RECLAIM_TIMER_CHUNK); + (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / + TX_RECLAIM_TIMER_CHUNK); mod_timer(&qs->tx_reclaim_timer, jiffies + next_period); } -- cgit v0.10.2 From 744514249f0656e2d50bb57585241670c2d4f32b Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Fri, 29 May 2009 12:52:44 +0000 Subject: cxgb3: Add Aeluros 2020 phy support Add support for the AEL2020 phy. Add PCI IDs of the boards using this phy. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index df1f585..9fe008e 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -44,12 +44,33 @@ enum { AEL_I2C_STAT = 0xc30c, AEL2005_GPIO_CTRL = 0xc214, AEL2005_GPIO_STAT = 0xc215, + + AEL2020_GPIO_INTR = 0xc103, /* Latch High (LH) */ + AEL2020_GPIO_CTRL = 0xc108, /* Store Clear (SC) */ + AEL2020_GPIO_STAT = 0xc10c, /* Read Only (RO) */ + AEL2020_GPIO_CFG = 0xc110, /* Read Write (RW) */ + + AEL2020_GPIO_SDA = 0, /* IN: i2c serial data */ + AEL2020_GPIO_MODDET = 1, /* IN: Module Detect */ + AEL2020_GPIO_0 = 3, /* IN: unassigned */ + AEL2020_GPIO_1 = 2, /* OUT: unassigned */ + AEL2020_GPIO_LSTAT = AEL2020_GPIO_1, /* wired to link status LED */ }; enum { edc_none, edc_sr, edc_twinax }; /* PHY module I2C device address */ -#define MODULE_DEV_ADDR 0xa0 +enum { + MODULE_DEV_ADDR = 0xa0, + SFF_DEV_ADDR = 0xa2, +}; + +/* PHY transceiver type */ +enum { + phy_transtype_unknown = 0, + phy_transtype_sfp = 3, + phy_transtype_xfp = 6, +}; #define AEL2005_MODDET_IRQ 4 @@ -86,6 +107,37 @@ static void ael100x_txon(struct cphy *phy) msleep(30); } +/* + * Read an 8-bit word from a device attached to the PHY's i2c bus. + */ +static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) +{ + int i, err; + unsigned int stat, data; + + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL, + (dev_addr << 8) | (1 << 8) | word_addr); + if (err) + return err; + + for (i = 0; i < 200; i++) { + msleep(1); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); + if (err) + return err; + if ((stat & 3) == 1) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA, + &data); + if (err) + return err; + return data >> 8; + } + } + CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n", + phy->mdio.prtad, dev_addr, word_addr); + return -ETIMEDOUT; +} + static int ael1002_power_down(struct cphy *phy, int enable) { int err; @@ -199,6 +251,51 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, return 0; } +/* + * Decode our module type. + */ +static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + + if (delay_ms) + msleep(delay_ms); + + /* see SFF-8472 for below */ + v = ael_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 = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6); + if (v < 0) + return v; + if (v != 4) + goto unknown; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10); + if (v < 0) + return v; + + if (v & 0x80) { + v = ael_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; +} + +/* + * Code to support the Aeluros/NetLogic 2005 10Gb PHY. + */ static int ael2005_setup_sr_edc(struct cphy *phy) { static struct reg_val regs[] = { @@ -893,35 +990,7 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) return err; } -static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) -{ - int i, err; - unsigned int stat, data; - - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL, - (dev_addr << 8) | (1 << 8) | word_addr); - if (err) - return err; - - for (i = 0; i < 5; i++) { - msleep(1); - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); - if (err) - return err; - if ((stat & 3) == 1) { - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, 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->mdio.prtad, word_addr); - return -ETIMEDOUT; -} - -static int get_module_type(struct cphy *phy, int delay_ms) +static int ael2005_get_module_type(struct cphy *phy, int delay_ms) { int v; unsigned int stat; @@ -933,39 +1002,7 @@ static int get_module_type(struct cphy *phy, int delay_ms) 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; + return ael2xxx_get_module_type(phy, delay_ms); } static int ael2005_intr_enable(struct cphy *phy) @@ -1024,7 +1061,7 @@ static int ael2005_reset(struct cphy *phy, int wait) msleep(50); - err = get_module_type(phy, 0); + err = ael2005_get_module_type(phy, 0); if (err < 0) return err; phy->modtype = err; @@ -1062,7 +1099,7 @@ static int ael2005_intr_handler(struct cphy *phy) return ret; /* modules have max 300 ms init time after hot plug */ - ret = get_module_type(phy, 300); + ret = ael2005_get_module_type(phy, 300); if (ret < 0) return ret; @@ -1113,6 +1150,662 @@ int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, } /* + * Setup EDC and other parameters for operation with an optical module. + */ +static int ael2020_setup_sr_edc(struct cphy *phy) +{ + static struct reg_val regs[] = { + /* set CDR offset to 10 */ + { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a }, + + /* adjust 10G RX bias current */ + { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 }, + { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 }, + { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + err = set_phy_regs(phy, regs); + msleep(50); + if (err) + return err; + + phy->priv = edc_sr; + return 0; +} + +/* + * Setup EDC and other parameters for operation with an TWINAX module. + */ +static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) +{ + /* set uC to 40MHz */ + static struct reg_val uCclock40MHz[] = { + { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 }, + { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 }, + { 0, 0, 0, 0 } + }; + + /* activate uC clock */ + static struct reg_val uCclockActivate[] = { + { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 }, + { 0, 0, 0, 0 } + }; + + /* set PC to start of SRAM and activate uC */ + static struct reg_val uCactivate[] = { + { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 }, + { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, + { 0, 0, 0, 0 } + }; + + /* TWINAX EDC firmware */ + static u16 twinax_edc[] = { + 0xd800, 0x4009, + 0xd801, 0x2fff, + 0xd802, 0x300f, + 0xd803, 0x40aa, + 0xd804, 0x401c, + 0xd805, 0x401e, + 0xd806, 0x2ff4, + 0xd807, 0x3dc4, + 0xd808, 0x2035, + 0xd809, 0x3035, + 0xd80a, 0x6524, + 0xd80b, 0x2cb2, + 0xd80c, 0x3012, + 0xd80d, 0x1002, + 0xd80e, 0x26e2, + 0xd80f, 0x3022, + 0xd810, 0x1002, + 0xd811, 0x27d2, + 0xd812, 0x3022, + 0xd813, 0x1002, + 0xd814, 0x2822, + 0xd815, 0x3012, + 0xd816, 0x1002, + 0xd817, 0x2492, + 0xd818, 0x3022, + 0xd819, 0x1002, + 0xd81a, 0x2772, + 0xd81b, 0x3012, + 0xd81c, 0x1002, + 0xd81d, 0x23d2, + 0xd81e, 0x3022, + 0xd81f, 0x1002, + 0xd820, 0x22cd, + 0xd821, 0x301d, + 0xd822, 0x27f2, + 0xd823, 0x3022, + 0xd824, 0x1002, + 0xd825, 0x5553, + 0xd826, 0x0307, + 0xd827, 0x2522, + 0xd828, 0x3022, + 0xd829, 0x1002, + 0xd82a, 0x2142, + 0xd82b, 0x3012, + 0xd82c, 0x1002, + 0xd82d, 0x4016, + 0xd82e, 0x5e63, + 0xd82f, 0x0344, + 0xd830, 0x2142, + 0xd831, 0x3012, + 0xd832, 0x1002, + 0xd833, 0x400e, + 0xd834, 0x2522, + 0xd835, 0x3022, + 0xd836, 0x1002, + 0xd837, 0x2b52, + 0xd838, 0x3012, + 0xd839, 0x1002, + 0xd83a, 0x2742, + 0xd83b, 0x3022, + 0xd83c, 0x1002, + 0xd83d, 0x25e2, + 0xd83e, 0x3022, + 0xd83f, 0x1002, + 0xd840, 0x2fa4, + 0xd841, 0x3dc4, + 0xd842, 0x6624, + 0xd843, 0x414b, + 0xd844, 0x56b3, + 0xd845, 0x03c6, + 0xd846, 0x866b, + 0xd847, 0x400c, + 0xd848, 0x2712, + 0xd849, 0x3012, + 0xd84a, 0x1002, + 0xd84b, 0x2c4b, + 0xd84c, 0x309b, + 0xd84d, 0x56b3, + 0xd84e, 0x03c3, + 0xd84f, 0x866b, + 0xd850, 0x400c, + 0xd851, 0x2272, + 0xd852, 0x3022, + 0xd853, 0x1002, + 0xd854, 0x2742, + 0xd855, 0x3022, + 0xd856, 0x1002, + 0xd857, 0x25e2, + 0xd858, 0x3022, + 0xd859, 0x1002, + 0xd85a, 0x2fb4, + 0xd85b, 0x3dc4, + 0xd85c, 0x6624, + 0xd85d, 0x56b3, + 0xd85e, 0x03c3, + 0xd85f, 0x866b, + 0xd860, 0x401c, + 0xd861, 0x2c45, + 0xd862, 0x3095, + 0xd863, 0x5b53, + 0xd864, 0x2372, + 0xd865, 0x3012, + 0xd866, 0x13c2, + 0xd867, 0x5cc3, + 0xd868, 0x2712, + 0xd869, 0x3012, + 0xd86a, 0x1312, + 0xd86b, 0x2b52, + 0xd86c, 0x3012, + 0xd86d, 0x1002, + 0xd86e, 0x2742, + 0xd86f, 0x3022, + 0xd870, 0x1002, + 0xd871, 0x2582, + 0xd872, 0x3022, + 0xd873, 0x1002, + 0xd874, 0x2142, + 0xd875, 0x3012, + 0xd876, 0x1002, + 0xd877, 0x628f, + 0xd878, 0x2985, + 0xd879, 0x33a5, + 0xd87a, 0x25e2, + 0xd87b, 0x3022, + 0xd87c, 0x1002, + 0xd87d, 0x5653, + 0xd87e, 0x03d2, + 0xd87f, 0x401e, + 0xd880, 0x6f72, + 0xd881, 0x1002, + 0xd882, 0x628f, + 0xd883, 0x2304, + 0xd884, 0x3c84, + 0xd885, 0x6436, + 0xd886, 0xdff4, + 0xd887, 0x6436, + 0xd888, 0x2ff5, + 0xd889, 0x3005, + 0xd88a, 0x8656, + 0xd88b, 0xdfba, + 0xd88c, 0x56a3, + 0xd88d, 0xd05a, + 0xd88e, 0x2972, + 0xd88f, 0x3012, + 0xd890, 0x1392, + 0xd891, 0xd05a, + 0xd892, 0x56a3, + 0xd893, 0xdfba, + 0xd894, 0x0383, + 0xd895, 0x6f72, + 0xd896, 0x1002, + 0xd897, 0x2b45, + 0xd898, 0x3005, + 0xd899, 0x4178, + 0xd89a, 0x5653, + 0xd89b, 0x0384, + 0xd89c, 0x2a62, + 0xd89d, 0x3012, + 0xd89e, 0x1002, + 0xd89f, 0x2f05, + 0xd8a0, 0x3005, + 0xd8a1, 0x41c8, + 0xd8a2, 0x5653, + 0xd8a3, 0x0382, + 0xd8a4, 0x0002, + 0xd8a5, 0x4218, + 0xd8a6, 0x2474, + 0xd8a7, 0x3c84, + 0xd8a8, 0x6437, + 0xd8a9, 0xdff4, + 0xd8aa, 0x6437, + 0xd8ab, 0x2ff5, + 0xd8ac, 0x3c05, + 0xd8ad, 0x8757, + 0xd8ae, 0xb888, + 0xd8af, 0x9787, + 0xd8b0, 0xdff4, + 0xd8b1, 0x6724, + 0xd8b2, 0x866a, + 0xd8b3, 0x6f72, + 0xd8b4, 0x1002, + 0xd8b5, 0x2641, + 0xd8b6, 0x3021, + 0xd8b7, 0x1001, + 0xd8b8, 0xc620, + 0xd8b9, 0x0000, + 0xd8ba, 0xc621, + 0xd8bb, 0x0000, + 0xd8bc, 0xc622, + 0xd8bd, 0x00ce, + 0xd8be, 0xc623, + 0xd8bf, 0x007f, + 0xd8c0, 0xc624, + 0xd8c1, 0x0032, + 0xd8c2, 0xc625, + 0xd8c3, 0x0000, + 0xd8c4, 0xc627, + 0xd8c5, 0x0000, + 0xd8c6, 0xc628, + 0xd8c7, 0x0000, + 0xd8c8, 0xc62c, + 0xd8c9, 0x0000, + 0xd8ca, 0x0000, + 0xd8cb, 0x2641, + 0xd8cc, 0x3021, + 0xd8cd, 0x1001, + 0xd8ce, 0xc502, + 0xd8cf, 0x53ac, + 0xd8d0, 0xc503, + 0xd8d1, 0x2cd3, + 0xd8d2, 0xc600, + 0xd8d3, 0x2a6e, + 0xd8d4, 0xc601, + 0xd8d5, 0x2a2c, + 0xd8d6, 0xc605, + 0xd8d7, 0x5557, + 0xd8d8, 0xc60c, + 0xd8d9, 0x5400, + 0xd8da, 0xc710, + 0xd8db, 0x0700, + 0xd8dc, 0xc711, + 0xd8dd, 0x0f06, + 0xd8de, 0xc718, + 0xd8df, 0x0700, + 0xd8e0, 0xc719, + 0xd8e1, 0x0f06, + 0xd8e2, 0xc720, + 0xd8e3, 0x4700, + 0xd8e4, 0xc721, + 0xd8e5, 0x0f06, + 0xd8e6, 0xc728, + 0xd8e7, 0x0700, + 0xd8e8, 0xc729, + 0xd8e9, 0x1207, + 0xd8ea, 0xc801, + 0xd8eb, 0x7f50, + 0xd8ec, 0xc802, + 0xd8ed, 0x7760, + 0xd8ee, 0xc803, + 0xd8ef, 0x7fce, + 0xd8f0, 0xc804, + 0xd8f1, 0x520e, + 0xd8f2, 0xc805, + 0xd8f3, 0x5c11, + 0xd8f4, 0xc806, + 0xd8f5, 0x3c51, + 0xd8f6, 0xc807, + 0xd8f7, 0x4061, + 0xd8f8, 0xc808, + 0xd8f9, 0x49c1, + 0xd8fa, 0xc809, + 0xd8fb, 0x3840, + 0xd8fc, 0xc80a, + 0xd8fd, 0x0000, + 0xd8fe, 0xc821, + 0xd8ff, 0x0002, + 0xd900, 0xc822, + 0xd901, 0x0046, + 0xd902, 0xc844, + 0xd903, 0x182f, + 0xd904, 0xc013, + 0xd905, 0xf341, + 0xd906, 0xc084, + 0xd907, 0x0030, + 0xd908, 0xc904, + 0xd909, 0x1401, + 0xd90a, 0xcb0c, + 0xd90b, 0x0004, + 0xd90c, 0xcb0e, + 0xd90d, 0xa00a, + 0xd90e, 0xcb0f, + 0xd90f, 0xc0c0, + 0xd910, 0xcb10, + 0xd911, 0xc0c0, + 0xd912, 0xcb11, + 0xd913, 0x00a0, + 0xd914, 0xcb12, + 0xd915, 0x0007, + 0xd916, 0xc241, + 0xd917, 0xa000, + 0xd918, 0xc243, + 0xd919, 0x7fe0, + 0xd91a, 0xc604, + 0xd91b, 0x000e, + 0xd91c, 0xc609, + 0xd91d, 0x00f5, + 0xd91e, 0xc611, + 0xd91f, 0x000e, + 0xd920, 0xc660, + 0xd921, 0x9600, + 0xd922, 0xc687, + 0xd923, 0x0004, + 0xd924, 0xc60a, + 0xd925, 0x04f5, + 0xd926, 0x0000, + 0xd927, 0x2641, + 0xd928, 0x3021, + 0xd929, 0x1001, + 0xd92a, 0xc620, + 0xd92b, 0x14e5, + 0xd92c, 0xc621, + 0xd92d, 0xc53d, + 0xd92e, 0xc622, + 0xd92f, 0x3cbe, + 0xd930, 0xc623, + 0xd931, 0x4452, + 0xd932, 0xc624, + 0xd933, 0xc5c5, + 0xd934, 0xc625, + 0xd935, 0xe01e, + 0xd936, 0xc627, + 0xd937, 0x0000, + 0xd938, 0xc628, + 0xd939, 0x0000, + 0xd93a, 0xc62c, + 0xd93b, 0x0000, + 0xd93c, 0x0000, + 0xd93d, 0x2b84, + 0xd93e, 0x3c74, + 0xd93f, 0x6435, + 0xd940, 0xdff4, + 0xd941, 0x6435, + 0xd942, 0x2806, + 0xd943, 0x3006, + 0xd944, 0x8565, + 0xd945, 0x2b24, + 0xd946, 0x3c24, + 0xd947, 0x6436, + 0xd948, 0x1002, + 0xd949, 0x2b24, + 0xd94a, 0x3c24, + 0xd94b, 0x6436, + 0xd94c, 0x4045, + 0xd94d, 0x8656, + 0xd94e, 0x5663, + 0xd94f, 0x0302, + 0xd950, 0x401e, + 0xd951, 0x1002, + 0xd952, 0x2807, + 0xd953, 0x31a7, + 0xd954, 0x20c4, + 0xd955, 0x3c24, + 0xd956, 0x6724, + 0xd957, 0x1002, + 0xd958, 0x2807, + 0xd959, 0x3187, + 0xd95a, 0x20c4, + 0xd95b, 0x3c24, + 0xd95c, 0x6724, + 0xd95d, 0x1002, + 0xd95e, 0x24f4, + 0xd95f, 0x3c64, + 0xd960, 0x6436, + 0xd961, 0xdff4, + 0xd962, 0x6436, + 0xd963, 0x1002, + 0xd964, 0x2006, + 0xd965, 0x3d76, + 0xd966, 0xc161, + 0xd967, 0x6134, + 0xd968, 0x6135, + 0xd969, 0x5443, + 0xd96a, 0x0303, + 0xd96b, 0x6524, + 0xd96c, 0x00fb, + 0xd96d, 0x1002, + 0xd96e, 0x20d4, + 0xd96f, 0x3c24, + 0xd970, 0x2025, + 0xd971, 0x3005, + 0xd972, 0x6524, + 0xd973, 0x1002, + 0xd974, 0xd019, + 0xd975, 0x2104, + 0xd976, 0x3c24, + 0xd977, 0x2105, + 0xd978, 0x3805, + 0xd979, 0x6524, + 0xd97a, 0xdff4, + 0xd97b, 0x4005, + 0xd97c, 0x6524, + 0xd97d, 0x2e8d, + 0xd97e, 0x303d, + 0xd97f, 0x2408, + 0xd980, 0x35d8, + 0xd981, 0x5dd3, + 0xd982, 0x0307, + 0xd983, 0x8887, + 0xd984, 0x63a7, + 0xd985, 0x8887, + 0xd986, 0x63a7, + 0xd987, 0xdffd, + 0xd988, 0x00f9, + 0xd989, 0x1002, + 0xd98a, 0x0000, + }; + int i, err; + + /* set uC clock and activate it */ + err = set_phy_regs(phy, uCclock40MHz); + msleep(500); + if (err) + return err; + err = set_phy_regs(phy, uCclockActivate); + msleep(500); + if (err) + return err; + + /* write TWINAX EDC firmware into PHY */ + for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], + twinax_edc[i + 1]); + /* activate uC */ + err = set_phy_regs(phy, uCactivate); + if (!err) + phy->priv = edc_twinax; + return err; +} + +/* + * Return Module Type. + */ +static int ael2020_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + unsigned int stat; + + v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat); + if (v) + return v; + + if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) { + /* module absent */ + return phy_modtype_none; + } + + return ael2xxx_get_module_type(phy, delay_ms); +} + +/* + * Enable PHY interrupts. We enable "Module Detection" interrupts (on any + * state transition) and then generic Link Alarm Status Interrupt (LASI). + */ +static int ael2020_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0x2 << (AEL2020_GPIO_MODDET*4)); + return err ? err : t3_phy_lasi_intr_enable(phy); +} + +/* + * Disable PHY interrupts. The mirror of the above ... + */ +static int ael2020_intr_disable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0x1 << (AEL2020_GPIO_MODDET*4)); + return err ? err : t3_phy_lasi_intr_disable(phy); +} + +/* + * Clear PHY interrupt state. + */ +static int ael2020_intr_clear(struct cphy *phy) +{ + /* + * The GPIO Interrupt register on the AEL2020 is a "Latching High" + * (LH) register which is cleared to the current state when it's read. + * Thus, we simply read the register and discard the result. + */ + unsigned int stat; + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + return err ? err : t3_phy_lasi_intr_clear(phy); +} + +/* + * Reset the PHY and put it into a canonical operating state. + */ +static int ael2020_reset(struct cphy *phy, int wait) +{ + static struct reg_val regs0[] = { + /* Erratum #2: CDRLOL asserted, causing PMA link down status */ + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, + + /* force XAUI to send LF when RX_LOS is asserted */ + { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, + + /* RX_LOS pin is active high */ + { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, + 0x0020, 0x0020 }, + + /* output Module's Loss Of Signal (LOS) to LED */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x0004 }, + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + unsigned int lasi_ctrl; + + /* grab current interrupt state */ + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); + if (err) + return err; + + err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125); + if (err) + return err; + msleep(100); + + /* basic initialization for all module types */ + phy->priv = edc_none; + err = set_phy_regs(phy, regs0); + if (err) + return err; + + /* determine module type and perform appropriate initialization */ + err = ael2020_get_module_type(phy, 0); + if (err < 0) + return err; + phy->modtype = (u8)err; + if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) + err = ael2020_setup_twinax_edc(phy, err); + else + err = ael2020_setup_sr_edc(phy); + 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; +} + +/* + * Handle a PHY interrupt. + */ +static int ael2020_intr_handler(struct cphy *phy) +{ + unsigned int stat; + int ret, edc_needed, cause = 0; + + ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + if (ret) + return ret; + + if (stat & (0x1 << AEL2020_GPIO_MODDET)) { + /* modules have max 300 ms init time after hot plug */ + ret = ael2020_get_module_type(phy, 300); + if (ret < 0) + return ret; + + phy->modtype = (u8)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 = ael2020_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 ael2020_ops = { + .reset = ael2020_reset, + .intr_enable = ael2020_intr_enable, + .intr_disable = ael2020_intr_disable, + .intr_clear = ael2020_intr_clear, + .intr_handler = ael2020_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_IRQ, "10GBASE-R"); + msleep(125); + return 0; +} + +/* * Get link status for a 10GBASE-X device. */ static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 79a113b..301221a 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -802,6 +802,8 @@ 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_ael2020_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, diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 1fe4b07..4bc2656 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -91,6 +91,8 @@ static const struct pci_device_id cxgb3_pci_tbl[] = { CH_DEVICE(0x31, 3), /* T3B20 */ CH_DEVICE(0x32, 1), /* T3B02 */ CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */ + CH_DEVICE(0x36, 3), /* S320E-CR */ + CH_DEVICE(0x37, 7), /* N320E-G2 */ {0,} }; diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index fc7db8a..766314c 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -526,6 +526,11 @@ static const struct adapter_info t3_adap_info[] = { F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, &mi1_mdio_ext_ops, "Chelsio T310" }, + {1, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | + F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL, + { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio N320E-G2" }, }; /* @@ -552,6 +557,8 @@ static const struct port_type_info port_types[] = { { t3_qt2045_phy_prep }, { t3_ael1006_phy_prep }, { NULL }, + { NULL }, + { t3_ael2020_phy_prep }, }; #define VPD_ENTRY(name, len) \ -- cgit v0.10.2 From f22a563b0a4c2a84b6ff8831306532b64c9c1747 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Fri, 29 May 2009 12:52:49 +0000 Subject: cxgb3: add support for the Aquantia 10G-BT phy Add support for the Aquantia AQ1002 10G-BaseT phy. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile index 3434679..29aff78 100644 --- a/drivers/net/cxgb3/Makefile +++ b/drivers/net/cxgb3/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_CHELSIO_T3) += cxgb3.o cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \ - xgmac.o sge.o l2t.o cxgb3_offload.o + xgmac.o sge.o l2t.o cxgb3_offload.o aq100x.o diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c new file mode 100644 index 0000000..c51e50d --- /dev/null +++ b/drivers/net/cxgb3/aq100x.c @@ -0,0 +1,355 @@ +/* + * 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 + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 "common.h" +#include "regs.h" + +enum { + /* MDIO_DEV_PMA_PMD registers */ + AQ_LINK_STAT = 0xe800, + AQ_IMASK_PMA = 0xf000, + + /* MDIO_DEV_XGXS registers */ + AQ_XAUI_RX_CFG = 0xc400, + AQ_XAUI_TX_CFG = 0xe400, + + /* MDIO_DEV_ANEG registers */ + AQ_100M_CTRL = 0x0010, + AQ_10G_CTRL = 0x0020, + AQ_1G_CTRL = 0xc400, + AQ_ANEG_STAT = 0xc800, + + /* MDIO_DEV_VEND1 registers */ + AQ_FW_VERSION = 0x0020, + AQ_IFLAG_GLOBAL = 0xfc00, + AQ_IMASK_GLOBAL = 0xff00, +}; + +#define AQBIT(x) (1 << (x)) +#define IMASK_PMA AQBIT(0x2) +#define IMASK_GLOBAL AQBIT(0xf) +#define ADV_1G_FULL AQBIT(0xf) +#define ADV_1G_HALF AQBIT(0xe) +#define ADV_10G_FULL AQBIT(0xc) +#define AQ_RESET (AQBIT(0xe) | AQBIT(0xf)) +#define AQ_LOWPOWER AQBIT(0xb) + +static int aq100x_reset(struct cphy *phy, int wait) +{ + /* + * Ignore the caller specified wait time; always wait for the reset to + * complete. Can take up to 3s. + */ + int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000); + + if (err) + CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n", + phy->mdio.prtad, err); + + return err; +} + +static int aq100x_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL); + return err; +} + +static int aq100x_intr_disable(struct cphy *phy) +{ + return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0); +} + +static int aq100x_intr_clear(struct cphy *phy) +{ + unsigned int v; + + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v); + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return 0; +} + +static int aq100x_intr_handler(struct cphy *phy) +{ + int err; + unsigned int cause, v; + + err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause); + if (err) + return err; + + /* Read (and reset) the latching version of the status */ + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return cphy_cause_link_change; +} + +static int aq100x_power_down(struct cphy *phy, int off) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, off); +} + +static int aq100x_autoneg_enable(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_autoneg_restart(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map) +{ + unsigned int adv; + int err; + + /* 10G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_10000baseT_Full) + adv |= ADV_10G_FULL; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_10G_CTRL, + ADV_10G_FULL, adv); + if (err) + return err; + + /* 1G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_1000baseT_Full) + adv |= ADV_1G_FULL; + if (advertise_map & ADVERTISED_1000baseT_Half) + adv |= ADV_1G_HALF; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL, + ADV_1G_FULL | ADV_1G_HALF, adv); + if (err) + return err; + + /* 100M, pause advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise_map & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise_map & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise_map & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_100M_CTRL, 0xfe0, adv); + + return err; +} + +static int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + BMCR_LOOPBACK, enable); +} + +static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + /* no can do */ + return -1; +} + +static int aq100x_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + int err; + unsigned int v; + + if (link_ok) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v); + if (err) + return err; + + *link_ok = v & 1; + if (!*link_ok) + return 0; + } + + err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v); + if (err) + return err; + + if (speed) { + switch (v & 0x6) { + case 0x6: + *speed = SPEED_10000; + break; + case 0x4: + *speed = SPEED_1000; + break; + case 0x2: + *speed = SPEED_100; + break; + case 0x0: + *speed = SPEED_10; + break; + } + } + + if (duplex) + *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF; + + return 0; +} + +static struct cphy_ops aq100x_ops = { + .reset = aq100x_reset, + .intr_enable = aq100x_intr_enable, + .intr_disable = aq100x_intr_disable, + .intr_clear = aq100x_intr_clear, + .intr_handler = aq100x_intr_handler, + .autoneg_enable = aq100x_autoneg_enable, + .autoneg_restart = aq100x_autoneg_restart, + .advertise = aq100x_advertise, + .set_loopback = aq100x_set_loopback, + .set_speed_duplex = aq100x_set_speed_duplex, + .get_link_status = aq100x_get_link_status, + .power_down = aq100x_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + unsigned int v, v2, gpio, wait; + int err; + + cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, + SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T"); + + /* + * The PHY has been out of reset ever since the system powered up. So + * we do a hard reset over here. + */ + gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL; + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0); + msleep(1); + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio); + + /* + * Give it enough time to load the firmware and get ready for mdio. + */ + msleep(1000); + wait = 500; /* in 10ms increments */ + do { + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err || v == 0xffff) { + + /* Allow prep_adapter to succeed when ffff is read */ + + CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n", + phy_addr, err, v); + goto done; + } + + v &= AQ_RESET; + if (v) + msleep(10); + } while (v && --wait); + if (v) { + CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n", + phy_addr, v); + + goto done; /* let prep_adapter succeed */ + } + + /* Datasheet says 3s max but this has been observed */ + wait = (500 - wait) * 10 + 1000; + if (wait > 3000) + CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait); + + /* Firmware version check. */ + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); + if (v != 30) { + CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", + phy_addr, v); + return 0; /* allow t3_prep_adapter to succeed */ + } + + /* + * The PHY should start in really-low-power mode. Prepare it for normal + * operations. + */ + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err) + return err; + if (v & AQ_LOWPOWER) { + err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1, + AQ_LOWPOWER, 0); + if (err) + return err; + msleep(10); + } else + CH_WARN(adapter, "PHY%d does not start in low power mode.\n", + phy_addr); + + /* + * Verify XAUI settings, but let prep succeed no matter what. + */ + v = v2 = 0; + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v); + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2); + if (v != 0x1b || v2 != 0x1b) + CH_WARN(adapter, + "PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n", + phy_addr, v, v2); + +done: + return err; +} diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 301221a..d21b705 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -808,4 +808,6 @@ 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); +int t3_aq100x_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/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 766314c..6a45447 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -557,7 +557,7 @@ static const struct port_type_info port_types[] = { { t3_qt2045_phy_prep }, { t3_ael1006_phy_prep }, { NULL }, - { NULL }, + { t3_aq100x_phy_prep }, { t3_ael2020_phy_prep }, }; -- cgit v0.10.2 From ae63e808f508c38fe65e23a1480c85d5bd00ecbd Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 27 May 2009 05:42:36 +0000 Subject: bonding: use bond_is_lb() when it's appropriate Signed-off-by: Jiri Pirko Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 92a9d69..2f4329e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2405,8 +2405,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_3ad_handle_link_change(slave, BOND_LINK_DOWN); - if (bond->params.mode == BOND_MODE_TLB || - bond->params.mode == BOND_MODE_ALB) + if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index ca849d2..41ceca1 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -286,8 +286,7 @@ static inline unsigned long slave_last_rx(struct bonding *bond, static inline void bond_set_slave_inactive_flags(struct slave *slave) { struct bonding *bond = netdev_priv(slave->dev->master); - if (bond->params.mode != BOND_MODE_TLB && - bond->params.mode != BOND_MODE_ALB) + if (!bond_is_lb(bond)) slave->state = BOND_STATE_BACKUP; slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; if (slave_do_arp_validate(bond, slave)) -- cgit v0.10.2 From ccffad25b5136958d4769ed6de5e87992dd9c65c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 22 May 2009 23:22:17 +0000 Subject: net: convert unicast addr list This patch converts unicast address list to standard list_head using previously introduced struct netdev_hw_addr. It also relaxes the locking. Original spinlock (still used for multicast addresses) is not needed and is no longer used for a protection of this list. All reading and writing takes place under rtnl (with no changes). I also removed a possibility to specify the length of the address while adding or deleting unicast address. It's always dev->addr_len. The convertion touched especially e1000 and ixgbe codes when the change is not so trivial. Signed-off-by: Jiri Pirko drivers/net/bnx2.c | 13 +-- drivers/net/e1000/e1000_main.c | 24 +++-- drivers/net/ixgbe/ixgbe_common.c | 14 ++-- drivers/net/ixgbe/ixgbe_common.h | 4 +- drivers/net/ixgbe/ixgbe_main.c | 6 +- drivers/net/ixgbe/ixgbe_type.h | 4 +- drivers/net/macvlan.c | 11 +- drivers/net/mv643xx_eth.c | 11 +- drivers/net/niu.c | 7 +- drivers/net/virtio_net.c | 7 +- drivers/s390/net/qeth_l2_main.c | 6 +- drivers/scsi/fcoe/fcoe.c | 16 ++-- include/linux/netdevice.h | 18 ++-- net/8021q/vlan.c | 4 +- net/8021q/vlan_dev.c | 10 +- net/core/dev.c | 195 +++++++++++++++++++++++++++----------- net/dsa/slave.c | 10 +- net/packet/af_packet.c | 4 +- 18 files changed, 227 insertions(+), 137 deletions(-) Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 83ee0f5..f530172 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "bnx2.h" #include "bnx2_fw.h" @@ -3310,7 +3311,7 @@ bnx2_set_rx_mode(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); u32 rx_mode, sort_mode; - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; int i; if (!netif_running(dev)) @@ -3369,21 +3370,19 @@ bnx2_set_rx_mode(struct net_device *dev) sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN; } - uc_ptr = NULL; if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) { rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS; sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN | BNX2_RPM_SORT_USER0_PROM_VLAN; } else if (!(dev->flags & IFF_PROMISC)) { - uc_ptr = dev->uc_list; - /* Add all entries into to the match filter list */ - for (i = 0; i < dev->uc_count; i++) { - bnx2_set_mac_addr(bp, uc_ptr->da_addr, + i = 0; + list_for_each_entry(ha, &dev->uc_list, list) { + bnx2_set_mac_addr(bp, ha->addr, i + BNX2_START_UNICAST_ADDRESS_INDEX); sort_mode |= (1 << (i + BNX2_START_UNICAST_ADDRESS_INDEX)); - uc_ptr = uc_ptr->next; + i++; } } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 79fe1ee..74667e5 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2330,7 +2330,8 @@ static void e1000_set_rx_mode(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; + bool use_uc = false; struct dev_addr_list *mc_ptr; u32 rctl; u32 hash_value; @@ -2369,12 +2370,11 @@ static void e1000_set_rx_mode(struct net_device *netdev) rctl |= E1000_RCTL_VFE; } - uc_ptr = NULL; if (netdev->uc_count > rar_entries - 1) { rctl |= E1000_RCTL_UPE; } else if (!(netdev->flags & IFF_PROMISC)) { rctl &= ~E1000_RCTL_UPE; - uc_ptr = netdev->uc_list; + use_uc = true; } ew32(RCTL, rctl); @@ -2392,13 +2392,20 @@ static void e1000_set_rx_mode(struct net_device *netdev) * if there are not 14 addresses, go ahead and clear the filters * -- with 82571 controllers only 0-13 entries are filled here */ + i = 1; + if (use_uc) + list_for_each_entry(ha, &netdev->uc_list, list) { + if (i == rar_entries) + break; + e1000_rar_set(hw, ha->addr, i++); + } + + WARN_ON(i == rar_entries); + mc_ptr = netdev->mc_list; - for (i = 1; i < rar_entries; i++) { - if (uc_ptr) { - e1000_rar_set(hw, uc_ptr->da_addr, i); - uc_ptr = uc_ptr->next; - } else if (mc_ptr) { + for (; i < rar_entries; i++) { + if (mc_ptr) { e1000_rar_set(hw, mc_ptr->da_addr, i); mc_ptr = mc_ptr->next; } else { @@ -2408,7 +2415,6 @@ static void e1000_set_rx_mode(struct net_device *netdev) E1000_WRITE_FLUSH(); } } - WARN_ON(uc_ptr != NULL); /* load any remaining addresses into the hash table */ diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 0cc3c47..6f79409 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "ixgbe.h" #include "ixgbe_common.h" @@ -1356,15 +1358,14 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) * 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) +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, + struct list_head *uc_list) { - u8 *addr; u32 i; u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc; u32 uc_addr_in_use; u32 fctrl; - u32 vmdq; + struct netdev_hw_addr *ha; /* * Clear accounting of old secondary address list, @@ -1382,10 +1383,9 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, } /* Add the new addresses */ - for (i = 0; i < addr_count; i++) { + list_for_each_entry(ha, uc_list, list) { hw_dbg(hw, " Adding the secondary addresses:\n"); - addr = next(hw, &addr_list, &vmdq); - ixgbe_add_uc_addr(hw, addr, vmdq); + ixgbe_add_uc_addr(hw, ha->addr, 0); } if (hw->addr_ctrl.overflow_promisc) { diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index dd26089..b2a4b2c 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -59,8 +59,8 @@ 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_update_uc_addr_list_generic(struct ixgbe_hw *hw, + struct list_head *uc_list); s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 924aa5e..de70a2d 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2181,11 +2181,7 @@ static void ixgbe_set_rx_mode(struct net_device *netdev) IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); /* 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); + hw->mac.ops.update_uc_addr_list(hw, &netdev->uc_list); /* reprogram multicast list */ addr_count = netdev->mc_count; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index df1f703..a8a8243 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -30,6 +30,7 @@ #include #include +#include /* Vendor ID */ #define IXGBE_INTEL_VENDOR_ID 0x8086 @@ -2223,8 +2224,7 @@ struct ixgbe_mac_operations { 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_uc_addr_list)(struct ixgbe_hw *, struct list_head *); s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, ixgbe_mc_addr_itr); s32 (*enable_mc)(struct ixgbe_hw *); diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d5334b4..021d994 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -232,7 +232,7 @@ static int macvlan_open(struct net_device *dev) if (macvlan_addr_busy(vlan->port, dev->dev_addr)) goto out; - err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN); + err = dev_unicast_add(lowerdev, dev->dev_addr); if (err < 0) goto out; if (dev->flags & IFF_ALLMULTI) { @@ -244,7 +244,7 @@ static int macvlan_open(struct net_device *dev) return 0; del_unicast: - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); out: return err; } @@ -258,7 +258,7 @@ static int macvlan_stop(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(lowerdev, -1); - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); macvlan_hash_del(vlan); return 0; @@ -282,10 +282,11 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) if (macvlan_addr_busy(vlan->port, addr->sa_data)) return -EBUSY; - if ((err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN))) + err = dev_unicast_add(lowerdev, addr->sa_data); + if (err) return err; - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); macvlan_hash_change_addr(vlan, addr->sa_data); } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 1361ddc..b4e18a5 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -55,6 +55,7 @@ #include #include #include +#include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; @@ -1721,20 +1722,20 @@ static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) static u32 uc_addr_filter_mask(struct net_device *dev) { - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; u32 nibbles; if (dev->flags & IFF_PROMISC) return 0; nibbles = 1 << (dev->dev_addr[5] & 0x0f); - for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) { - if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5)) + list_for_each_entry(ha, &dev->uc_list, list) { + if (memcmp(dev->dev_addr, ha->addr, 5)) return 0; - if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0) + if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0) return 0; - nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f); + nibbles |= 1 << (ha->addr[5] & 0x0f); } return nibbles; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index edac3a0..fa61a12 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -6362,6 +6363,7 @@ static void niu_set_rx_mode(struct net_device *dev) struct niu *np = netdev_priv(dev); int i, alt_cnt, err; struct dev_addr_list *addr; + struct netdev_hw_addr *ha; unsigned long flags; u16 hash[16] = { 0, }; @@ -6383,9 +6385,8 @@ static void niu_set_rx_mode(struct net_device *dev) if (alt_cnt) { int index = 0; - for (addr = dev->uc_list; addr; addr = addr->next) { - err = niu_set_alt_mac(np, index, - addr->da_addr); + list_for_each_entry(ha, &dev->uc_list, list) { + err = niu_set_alt_mac(np, index, ha->addr); if (err) printk(KERN_WARNING PFX "%s: Error %d " "adding alt mac %d\n", diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 6cc5bcd..0c9ca67 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -680,6 +680,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) u8 promisc, allmulti; struct virtio_net_ctrl_mac *mac_data; struct dev_addr_list *addr; + struct netdev_hw_addr *ha; void *buf; int i; @@ -718,9 +719,9 @@ static void virtnet_set_rx_mode(struct net_device *dev) /* Store the unicast list and count in the front of the buffer */ mac_data->entries = dev->uc_count; - addr = dev->uc_list; - for (i = 0; i < dev->uc_count; i++, addr = addr->next) - memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN); + i = 0; + list_for_each_entry(ha, &dev->uc_list, list) + memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN); sg_set_buf(&sg[0], mac_data, sizeof(mac_data->entries) + (dev->uc_count * ETH_ALEN)); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 9ca6bab..ecd3d06 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "qeth_core.h" @@ -640,6 +641,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; struct dev_addr_list *dm; + struct netdev_hw_addr *ha; if (card->info.type == QETH_CARD_TYPE_OSN) return ; @@ -653,8 +655,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) for (dm = dev->mc_list; dm; dm = dm->next) qeth_l2_add_mc(card, dm->da_addr, 0); - for (dm = dev->uc_list; dm; dm = dm->next) - qeth_l2_add_mc(card, dm->da_addr, 1); + list_for_each_entry(ha, &dev->uc_list, list) + qeth_l2_add_mc(card, ha->addr, 1); spin_unlock_bh(&card->mclock); if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ce33f10..f791348 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -182,8 +182,8 @@ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) fc = fcoe_from_ctlr(fip); rtnl_lock(); if (!is_zero_ether_addr(old)) - dev_unicast_delete(fc->real_dev, old, ETH_ALEN); - dev_unicast_add(fc->real_dev, new, ETH_ALEN); + dev_unicast_delete(fc->real_dev, old); + dev_unicast_add(fc->real_dev, new); rtnl_unlock(); } @@ -233,13 +233,11 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc) /* Delete secondary MAC addresses */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); + dev_unicast_delete(fc->real_dev, flogi_maddr); if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) - dev_unicast_delete(fc->real_dev, - fc->ctlr.data_src_addr, ETH_ALEN); + dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr); if (fc->ctlr.spma) - dev_unicast_delete(fc->real_dev, - fc->ctlr.ctl_src_addr, ETH_ALEN); + dev_unicast_delete(fc->real_dev, fc->ctlr.ctl_src_addr); dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); } @@ -347,9 +345,9 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); + dev_unicast_add(fc->real_dev, flogi_maddr); if (fc->ctlr.spma) - dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr, ETH_ALEN); + dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr); dev_mc_add(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1eaf5ae..bbfabf3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -215,9 +215,12 @@ struct netdev_hw_addr { struct list_head list; unsigned char addr[MAX_ADDR_LEN]; unsigned char type; -#define NETDEV_HW_ADDR_T_LAN 1 -#define NETDEV_HW_ADDR_T_SAN 2 -#define NETDEV_HW_ADDR_T_SLAVE 3 +#define NETDEV_HW_ADDR_T_LAN 1 +#define NETDEV_HW_ADDR_T_SAN 2 +#define NETDEV_HW_ADDR_T_SLAVE 3 +#define NETDEV_HW_ADDR_T_UNICAST 4 + int refcount; + bool synced; struct rcu_head rcu_head; }; @@ -773,10 +776,11 @@ struct net_device unsigned char addr_len; /* hardware address length */ unsigned short dev_id; /* for shared network cards */ - spinlock_t addr_list_lock; - struct dev_addr_list *uc_list; /* Secondary unicast mac addresses */ + struct list_head uc_list; /* Secondary unicast mac + addresses */ int uc_count; /* Number of installed ucasts */ int uc_promisc; + spinlock_t addr_list_lock; struct dev_addr_list *mc_list; /* Multicast mac addresses */ int mc_count; /* Number of installed mcasts */ unsigned int promiscuity; @@ -1836,8 +1840,8 @@ extern int dev_addr_del_multiple(struct net_device *to_dev, /* Functions used for secondary unicast and multicast support */ extern void dev_set_rx_mode(struct net_device *dev); extern void __dev_set_rx_mode(struct net_device *dev); -extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen); -extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); +extern int dev_unicast_delete(struct net_device *dev, void *addr); +extern int dev_unicast_add(struct net_device *dev, void *addr); extern int dev_unicast_sync(struct net_device *to, struct net_device *from); extern void dev_unicast_unsync(struct net_device *to, struct net_device *from); extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index d1e1054..714e1c3 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -378,13 +378,13 @@ static void vlan_sync_address(struct net_device *dev, * the new address */ if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) && !compare_ether_addr(vlandev->dev_addr, dev->dev_addr)) - dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN); + dev_unicast_delete(dev, vlandev->dev_addr); /* vlan address was equal to the old address and is different from * the new address */ if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) && compare_ether_addr(vlandev->dev_addr, dev->dev_addr)) - dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN); + dev_unicast_add(dev, vlandev->dev_addr); memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN); } diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 1e2ad4c..96bad8f 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -441,7 +441,7 @@ static int vlan_dev_open(struct net_device *dev) return -ENETDOWN; if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { - err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN); + err = dev_unicast_add(real_dev, dev->dev_addr); if (err < 0) goto out; } @@ -470,7 +470,7 @@ clear_allmulti: dev_set_allmulti(real_dev, -1); del_unicast: if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) - dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(real_dev, dev->dev_addr); out: netif_carrier_off(dev); return err; @@ -492,7 +492,7 @@ static int vlan_dev_stop(struct net_device *dev) dev_set_promiscuity(real_dev, -1); if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) - dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); + dev_unicast_delete(real_dev, dev->dev_addr); netif_carrier_off(dev); return 0; @@ -511,13 +511,13 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p) goto out; if (compare_ether_addr(addr->sa_data, real_dev->dev_addr)) { - err = dev_unicast_add(real_dev, addr->sa_data, ETH_ALEN); + err = dev_unicast_add(real_dev, addr->sa_data); if (err < 0) return err; } if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) - dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(real_dev, dev->dev_addr); out: memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); diff --git a/net/core/dev.c b/net/core/dev.c index 32ceee1..e2fcc5f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3473,8 +3473,9 @@ void dev_set_rx_mode(struct net_device *dev) /* hw addresses list handling functions */ -static int __hw_addr_add(struct list_head *list, unsigned char *addr, - int addr_len, unsigned char addr_type) +static int __hw_addr_add(struct list_head *list, int *delta, + unsigned char *addr, int addr_len, + unsigned char addr_type) { struct netdev_hw_addr *ha; int alloc_size; @@ -3482,6 +3483,15 @@ static int __hw_addr_add(struct list_head *list, unsigned char *addr, if (addr_len > MAX_ADDR_LEN) return -EINVAL; + list_for_each_entry(ha, list, list) { + if (!memcmp(ha->addr, addr, addr_len) && + ha->type == addr_type) { + ha->refcount++; + return 0; + } + } + + alloc_size = sizeof(*ha); if (alloc_size < L1_CACHE_BYTES) alloc_size = L1_CACHE_BYTES; @@ -3490,7 +3500,11 @@ static int __hw_addr_add(struct list_head *list, unsigned char *addr, return -ENOMEM; memcpy(ha->addr, addr, addr_len); ha->type = addr_type; + ha->refcount = 1; + ha->synced = false; list_add_tail_rcu(&ha->list, list); + if (delta) + (*delta)++; return 0; } @@ -3502,29 +3516,30 @@ static void ha_rcu_free(struct rcu_head *head) kfree(ha); } -static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr, - int addr_len, unsigned char addr_type, - int ignore_index) +static int __hw_addr_del(struct list_head *list, int *delta, + unsigned char *addr, int addr_len, + unsigned char addr_type) { struct netdev_hw_addr *ha; - int i = 0; list_for_each_entry(ha, list, list) { - if (i++ != ignore_index && - !memcmp(ha->addr, addr, addr_len) && + if (!memcmp(ha->addr, addr, addr_len) && (ha->type == addr_type || !addr_type)) { + if (--ha->refcount) + return 0; list_del_rcu(&ha->list); call_rcu(&ha->rcu_head, ha_rcu_free); + if (delta) + (*delta)--; return 0; } } return -ENOENT; } -static int __hw_addr_add_multiple_ii(struct list_head *to_list, - struct list_head *from_list, - int addr_len, unsigned char addr_type, - int ignore_index) +static int __hw_addr_add_multiple(struct list_head *to_list, int *to_delta, + struct list_head *from_list, int addr_len, + unsigned char addr_type) { int err; struct netdev_hw_addr *ha, *ha2; @@ -3532,7 +3547,8 @@ static int __hw_addr_add_multiple_ii(struct list_head *to_list, list_for_each_entry(ha, from_list, list) { type = addr_type ? addr_type : ha->type; - err = __hw_addr_add(to_list, ha->addr, addr_len, type); + err = __hw_addr_add(to_list, to_delta, ha->addr, + addr_len, type); if (err) goto unroll; } @@ -3543,27 +3559,69 @@ unroll: if (ha2 == ha) break; type = addr_type ? addr_type : ha2->type; - __hw_addr_del_ii(to_list, ha2->addr, addr_len, type, - ignore_index); + __hw_addr_del(to_list, to_delta, ha2->addr, + addr_len, type); } return err; } -static void __hw_addr_del_multiple_ii(struct list_head *to_list, - struct list_head *from_list, - int addr_len, unsigned char addr_type, - int ignore_index) +static void __hw_addr_del_multiple(struct list_head *to_list, int *to_delta, + struct list_head *from_list, int addr_len, + unsigned char addr_type) { struct netdev_hw_addr *ha; unsigned char type; list_for_each_entry(ha, from_list, list) { type = addr_type ? addr_type : ha->type; - __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type, - ignore_index); + __hw_addr_del(to_list, to_delta, ha->addr, + addr_len, addr_type); + } +} + +static int __hw_addr_sync(struct list_head *to_list, int *to_delta, + struct list_head *from_list, int *from_delta, + int addr_len) +{ + int err = 0; + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, from_list, list) { + if (!ha->synced) { + err = __hw_addr_add(to_list, to_delta, ha->addr, + addr_len, ha->type); + if (err) + break; + ha->synced = true; + ha->refcount++; + } else if (ha->refcount == 1) { + __hw_addr_del(to_list, to_delta, ha->addr, + addr_len, ha->type); + __hw_addr_del(from_list, from_delta, ha->addr, + addr_len, ha->type); + } } + return err; } +static void __hw_addr_unsync(struct list_head *to_list, int *to_delta, + struct list_head *from_list, int *from_delta, + int addr_len) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, from_list, list) { + if (ha->synced) { + __hw_addr_del(to_list, to_delta, ha->addr, + addr_len, ha->type); + ha->synced = false; + __hw_addr_del(from_list, from_delta, ha->addr, + addr_len, ha->type); + } + } +} + + static void __hw_addr_flush(struct list_head *list) { struct netdev_hw_addr *ha, *tmp; @@ -3594,7 +3652,7 @@ static int dev_addr_init(struct net_device *dev) INIT_LIST_HEAD(&dev->dev_addr_list); memset(addr, 0, sizeof(*addr)); - err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr), + err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(*addr), NETDEV_HW_ADDR_T_LAN); if (!err) { /* @@ -3626,7 +3684,7 @@ int dev_addr_add(struct net_device *dev, unsigned char *addr, ASSERT_RTNL(); - err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len, + err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, dev->addr_len, addr_type); if (!err) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); @@ -3649,11 +3707,20 @@ int dev_addr_del(struct net_device *dev, unsigned char *addr, unsigned char addr_type) { int err; + struct netdev_hw_addr *ha; ASSERT_RTNL(); - err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, - addr_type, 0); + /* + * We can not remove the first address from the list because + * dev->dev_addr points to that. + */ + ha = list_first_entry(&dev->dev_addr_list, struct netdev_hw_addr, list); + if (ha->addr == dev->dev_addr && ha->refcount == 1) + return -ENOENT; + + err = __hw_addr_del(&dev->dev_addr_list, NULL, addr, dev->addr_len, + addr_type); if (!err) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); return err; @@ -3680,9 +3747,9 @@ int dev_addr_add_multiple(struct net_device *to_dev, if (from_dev->addr_len != to_dev->addr_len) return -EINVAL; - err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list, - &from_dev->dev_addr_list, - to_dev->addr_len, addr_type, 0); + err = __hw_addr_add_multiple(&to_dev->dev_addr_list, NULL, + &from_dev->dev_addr_list, + to_dev->addr_len, addr_type); if (!err) call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); return err; @@ -3707,9 +3774,9 @@ int dev_addr_del_multiple(struct net_device *to_dev, if (from_dev->addr_len != to_dev->addr_len) return -EINVAL; - __hw_addr_del_multiple_ii(&to_dev->dev_addr_list, - &from_dev->dev_addr_list, - to_dev->addr_len, addr_type, 0); + __hw_addr_del_multiple(&to_dev->dev_addr_list, NULL, + &from_dev->dev_addr_list, + to_dev->addr_len, addr_type); call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); return 0; } @@ -3779,24 +3846,22 @@ int __dev_addr_add(struct dev_addr_list **list, int *count, * dev_unicast_delete - Release secondary unicast address. * @dev: device * @addr: address to delete - * @alen: length of @addr * * Release reference to a secondary unicast address and remove it * from the device if the reference count drops to zero. * * The caller must hold the rtnl_mutex. */ -int dev_unicast_delete(struct net_device *dev, void *addr, int alen) +int dev_unicast_delete(struct net_device *dev, void *addr) { int err; ASSERT_RTNL(); - netif_addr_lock_bh(dev); - err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0); + err = __hw_addr_del(&dev->uc_list, &dev->uc_count, addr, + dev->addr_len, NETDEV_HW_ADDR_T_UNICAST); if (!err) __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); return err; } EXPORT_SYMBOL(dev_unicast_delete); @@ -3805,24 +3870,22 @@ EXPORT_SYMBOL(dev_unicast_delete); * dev_unicast_add - add a secondary unicast address * @dev: device * @addr: address to add - * @alen: length of @addr * * Add a secondary unicast address to the device or increase * the reference count if it already exists. * * The caller must hold the rtnl_mutex. */ -int dev_unicast_add(struct net_device *dev, void *addr, int alen) +int dev_unicast_add(struct net_device *dev, void *addr) { int err; ASSERT_RTNL(); - netif_addr_lock_bh(dev); - err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0); + err = __hw_addr_add(&dev->uc_list, &dev->uc_count, addr, + dev->addr_len, NETDEV_HW_ADDR_T_UNICAST); if (!err) __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); return err; } EXPORT_SYMBOL(dev_unicast_add); @@ -3879,8 +3942,7 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, * @from: source device * * Add newly added addresses to the destination device and release - * addresses that have no users left. The source device must be - * locked by netif_tx_lock_bh. + * addresses that have no users left. * * This function is intended to be called from the dev->set_rx_mode * function of layered software devices. @@ -3889,12 +3951,15 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from) { int err = 0; - netif_addr_lock_bh(to); - err = __dev_addr_sync(&to->uc_list, &to->uc_count, - &from->uc_list, &from->uc_count); + ASSERT_RTNL(); + + if (to->addr_len != from->addr_len) + return -EINVAL; + + err = __hw_addr_sync(&to->uc_list, &to->uc_count, + &from->uc_list, &from->uc_count, to->addr_len); if (!err) __dev_set_rx_mode(to); - netif_addr_unlock_bh(to); return err; } EXPORT_SYMBOL(dev_unicast_sync); @@ -3910,18 +3975,33 @@ EXPORT_SYMBOL(dev_unicast_sync); */ void dev_unicast_unsync(struct net_device *to, struct net_device *from) { - netif_addr_lock_bh(from); - netif_addr_lock(to); + ASSERT_RTNL(); - __dev_addr_unsync(&to->uc_list, &to->uc_count, - &from->uc_list, &from->uc_count); - __dev_set_rx_mode(to); + if (to->addr_len != from->addr_len) + return; - netif_addr_unlock(to); - netif_addr_unlock_bh(from); + __hw_addr_unsync(&to->uc_list, &to->uc_count, + &from->uc_list, &from->uc_count, to->addr_len); + __dev_set_rx_mode(to); } EXPORT_SYMBOL(dev_unicast_unsync); +static void dev_unicast_flush(struct net_device *dev) +{ + /* rtnl_mutex must be held here */ + + __hw_addr_flush(&dev->uc_list); + dev->uc_count = 0; +} + +static void dev_unicast_init(struct net_device *dev) +{ + /* rtnl_mutex must be held here */ + + INIT_LIST_HEAD(&dev->uc_list); +} + + static void __dev_addr_discard(struct dev_addr_list **list) { struct dev_addr_list *tmp; @@ -3940,9 +4020,6 @@ static void dev_addr_discard(struct net_device *dev) { netif_addr_lock_bh(dev); - __dev_addr_discard(&dev->uc_list); - dev->uc_count = 0; - __dev_addr_discard(&dev->mc_list); dev->mc_count = 0; @@ -4535,6 +4612,7 @@ static void rollback_registered(struct net_device *dev) /* * Flush the unicast and multicast chains */ + dev_unicast_flush(dev); dev_addr_discard(dev); if (dev->netdev_ops->ndo_uninit) @@ -5020,6 +5098,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, if (dev_addr_init(dev)) goto free_tx; + dev_unicast_init(dev); + dev_net_set(dev, &init_net); dev->_tx = tx; @@ -5223,6 +5303,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* * Flush the unicast and multicast chains */ + dev_unicast_flush(dev); dev_addr_discard(dev); netdev_unregister_kobject(dev); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index ed13118..2175e6d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -67,7 +67,7 @@ static int dsa_slave_open(struct net_device *dev) return -ENETDOWN; if (compare_ether_addr(dev->dev_addr, master->dev_addr)) { - err = dev_unicast_add(master, dev->dev_addr, ETH_ALEN); + err = dev_unicast_add(master, dev->dev_addr); if (err < 0) goto out; } @@ -90,7 +90,7 @@ clear_allmulti: dev_set_allmulti(master, -1); del_unicast: if (compare_ether_addr(dev->dev_addr, master->dev_addr)) - dev_unicast_delete(master, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(master, dev->dev_addr); out: return err; } @@ -108,7 +108,7 @@ static int dsa_slave_close(struct net_device *dev) dev_set_promiscuity(master, -1); if (compare_ether_addr(dev->dev_addr, master->dev_addr)) - dev_unicast_delete(master, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(master, dev->dev_addr); return 0; } @@ -147,13 +147,13 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a) goto out; if (compare_ether_addr(addr->sa_data, master->dev_addr)) { - err = dev_unicast_add(master, addr->sa_data, ETH_ALEN); + err = dev_unicast_add(master, addr->sa_data); if (err < 0) return err; } if (compare_ether_addr(dev->dev_addr, master->dev_addr)) - dev_unicast_delete(master, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(master, dev->dev_addr); out: memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c7c5d52..6da9f38 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1582,9 +1582,9 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, break; case PACKET_MR_UNICAST: if (what > 0) - return dev_unicast_add(dev, i->addr, i->alen); + return dev_unicast_add(dev, i->addr); else - return dev_unicast_delete(dev, i->addr, i->alen); + return dev_unicast_delete(dev, i->addr); break; default:; } -- cgit v0.10.2 From cd39c7a5717191c677a140565bda2f1ca485ecd8 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 25 May 2009 16:52:47 +0000 Subject: mac8390: use printk MAC address format mac8390: use printk MAC address format Signed-off-by: Finn Thain Signed-off-by: David S. Miller diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 8e88486..0585df1 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -620,19 +620,12 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd /* Good, done, now spit out some messages */ printk(KERN_INFO "%s: %s in slot %X (type %s)\n", - dev->name, ndev->board->name, ndev->board->slot, cardname[type]); - printk(KERN_INFO "MAC "); - { - int i; - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - } - printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", - dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4, - dev->mem_start, access_bitmode?32:16); + dev->name, ndev->board->name, ndev->board->slot, cardname[type]); + printk(KERN_INFO + "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", + dev->dev_addr, dev->irq, + (unsigned int)(dev->mem_end - dev->mem_start) >> 10, + dev->mem_start, access_bitmode ? 32 : 16); return 0; } -- cgit v0.10.2 From e13f93188b8a3b418da2a02dfa1a46718cf4607b Mon Sep 17 00:00:00 2001 From: Tadashi Abe Date: Mon, 25 May 2009 20:53:27 +0000 Subject: irda-usb: suspend/resume support This patch adds power management suspend/resume hooks for irda-usb. Signed-off-by: Tadashi Abe Signed-off-by: David S. Miller diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 006ba23..394b2b1 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1859,6 +1859,42 @@ static void irda_usb_disconnect(struct usb_interface *intf) IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __func__); } +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int irda_usb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + netif_device_detach(self->netdev); + + if (self->tx_urb != NULL) + usb_kill_urb(self->tx_urb); + if (self->speed_urb != NULL) + usb_kill_urb(self->speed_urb); + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_kill_urb(self->rx_urb[i]); + } + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int irda_usb_resume(struct usb_interface *intf) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_submit_urb(self->rx_urb[i], GFP_KERNEL); + } + + netif_device_attach(self->netdev); + return 0; +} +#endif + /*------------------------------------------------------------------*/ /* * USB device callbacks @@ -1868,6 +1904,10 @@ static struct usb_driver irda_driver = { .probe = irda_usb_probe, .disconnect = irda_usb_disconnect, .id_table = dongles, +#ifdef CONFIG_PM + .suspend = irda_usb_suspend, + .resume = irda_usb_resume, +#endif }; /************************* MODULE CALLBACKS *************************/ -- cgit v0.10.2 From 644233073458653e4b7fb474d9a8bdbbfd37739a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 27 May 2009 03:41:39 +0000 Subject: fec: Add FEC support for MX35 processor Add FEC support for MX35 processor. Signed-off-by: Fabio Estevam Acked-by: Sascha Hauer Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 43a5254..3df8fc4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1859,8 +1859,8 @@ config 68360_ENET the Motorola 68360 processor. config FEC - bool "FEC ethernet controller (of ColdFire CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 + bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" + depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 || ARCH_MX35 help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire and Freescale i.MX processors. -- cgit v0.10.2 From 342a437ef625953e8bdeee3bc1605ccd27a38863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Goddard=20Rosa?= Date: Fri, 29 May 2009 22:13:58 -0700 Subject: usbnet: ratelimit warning messages invoked from callback handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Warning messages coming from rtl8150 driver can flood the console and make a DTV/set-top-box unable to decode video/audio frames. 'Pegasus' driver handles this situation similarly, preventing this from happening there. It happens with a low cost BCM MIPS embedded platform, whenever timeout errors were coming from usbnet device, making platform unusable for viewer watching. Signed-off-by: André Goddard Rosa Signed-off-by: David S. Miller diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index f9fb454..fcc6fa0 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -221,7 +221,8 @@ static void ctrl_callback(struct urb *urb) case -ENOENT: break; default: - dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags); @@ -442,10 +443,12 @@ static void read_bulk_callback(struct urb *urb) case -ENOENT: return; /* the urb is in unlink state */ case -ETIME: - dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); goto goon; default: - dev_warn(&urb->dev->dev, "Rx status %d\n", status); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "Rx status %d\n", status); goto goon; } -- cgit v0.10.2 From 86d15cd83363a9787039895cb1a1b6be50f82ad3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 30 May 2009 23:04:46 -0700 Subject: net: unset IFF_XMIT_DST_RELEASE for qeth and ipoib Last two drivers that need skb->dst in their start_xmit() function Tell dev_hard_start_xmit() to no release it by unsetting IFF_XMIT_DST_RELEASE Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index ab2c192..69c6304 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1053,6 +1053,7 @@ static void ipoib_setup(struct net_device *dev) dev->tx_queue_len = ipoib_sendq_size * 2; dev->features = (NETIF_F_VLAN_CHALLENGED | NETIF_F_HIGHDMA); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b36b5cd..cb64b0b 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3012,6 +3012,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; SET_NETDEV_DEV(card->dev, &card->gdev->dev); return register_netdev(card->dev); -- cgit v0.10.2 From 128ced8f9d59bb3e36fbb4df87bd9d881f0a4463 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Sat, 30 May 2009 07:55:48 +0000 Subject: can: some fixes and cleanups to the initial device driver interface This patch fixes a few errors sneaked into the initial version of the device driver interface. Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 52b0e7d..574dadd 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -477,7 +477,7 @@ int open_candev(struct net_device *dev) return 0; } -EXPORT_SYMBOL(open_candev); +EXPORT_SYMBOL_GPL(open_candev); /* * Common close function for cleanup before the device gets closed. diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 3cd2ff9..88a4649 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -218,14 +218,12 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE); if (card->conf_addr == NULL) { err = -ENOMEM; - goto failure_cleanup; } card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE); if (card->base_addr == NULL) { err = -ENOMEM; - goto failure_cleanup; } @@ -239,7 +237,6 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, ems_pci_readb(card, 3) != 0xCB || ems_pci_readb(card, 4) != 0x11) { dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n"); - err = -ENODEV; goto failure_cleanup; } diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 05b38dd..b689964 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -532,8 +532,8 @@ static int sja1000_open(struct net_device *dev) err = request_irq(dev->irq, &sja1000_interrupt, priv->irq_flags, dev->name, (void *)dev); if (err) { - return -EAGAIN; close_candev(dev); + return -EAGAIN; } } -- cgit v0.10.2 From 255a9154319d3cf475d527458037758935f6445b Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Sat, 30 May 2009 07:55:49 +0000 Subject: can: sja1000: stop misusing member base_addr of struct net_device As discussed on the netdev mailing list, the member "base_addr" of "struct net_device" should not be (mis)used to store the virtual address to the SJA1000 register area. According to David Miller, it's only use is to allow ISA and similar primitive bus devices to have their I/O ports changed via ifconfig. The virtual address is now stored in the private data structure of the SJA1000 device and the callback functions use "struct sja1000_priv" instead of the unneeded "struct net_device". Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 88a4649..121b641 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -99,25 +99,21 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl); */ static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port) { - return readb((void __iomem *)card->base_addr - + (port * EMS_PCI_PORT_BYTES)); + return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES)); } -static u8 ems_pci_read_reg(const struct net_device *dev, int port) +static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port) { - return readb((void __iomem *)dev->base_addr - + (port * EMS_PCI_PORT_BYTES)); + return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES)); } -static void ems_pci_write_reg(const struct net_device *dev, int port, u8 val) +static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) { - writeb(val, (void __iomem *)dev->base_addr - + (port * EMS_PCI_PORT_BYTES)); + writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES)); } -static void ems_pci_post_irq(const struct net_device *dev) +static void ems_pci_post_irq(const struct sja1000_priv *priv) { - struct sja1000_priv *priv = netdev_priv(dev); struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; /* reset int flag of pita */ @@ -129,17 +125,17 @@ static void ems_pci_post_irq(const struct net_device *dev) * Check if a CAN controller is present at the specified location * by trying to set 'em into the PeliCAN mode */ -static inline int ems_pci_check_chan(struct net_device *dev) +static inline int ems_pci_check_chan(const struct sja1000_priv *priv) { unsigned char res; /* Make sure SJA1000 is in reset mode */ - ems_pci_write_reg(dev, REG_MOD, 1); + ems_pci_write_reg(priv, REG_MOD, 1); - ems_pci_write_reg(dev, REG_CDR, CDR_PELICAN); + ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN); /* read reset-values */ - res = ems_pci_read_reg(dev, REG_CDR); + res = ems_pci_read_reg(priv, REG_CDR); if (res == CDR_PELICAN) return 1; @@ -257,12 +253,11 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, priv->irq_flags = IRQF_SHARED; dev->irq = pdev->irq; - dev->base_addr = (unsigned long)(card->base_addr - + EMS_PCI_CAN_BASE_OFFSET - + (i * EMS_PCI_CAN_CTRL_SIZE)); + priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET + + (i * EMS_PCI_CAN_CTRL_SIZE); /* Check if channel is present */ - if (ems_pci_check_chan(dev)) { + if (ems_pci_check_chan(priv)) { priv->read_reg = ems_pci_read_reg; priv->write_reg = ems_pci_write_reg; priv->post_irq = ems_pci_post_irq; @@ -286,9 +281,8 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->channels++; - dev_info(&pdev->dev, "Channel #%d at %#lX, irq %d\n", - i + 1, dev->base_addr, - dev->irq); + dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n", + i + 1, priv->reg_base, dev->irq); } else { free_sja1000dev(dev); } diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c index 00830b3..7dd7769 100644 --- a/drivers/net/can/sja1000/kvaser_pci.c +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -117,14 +117,15 @@ static struct pci_device_id kvaser_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl); -static u8 kvaser_pci_read_reg(const struct net_device *dev, int port) +static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port) { - return ioread8((void __iomem *)(dev->base_addr + port)); + return ioread8(priv->reg_base + port); } -static void kvaser_pci_write_reg(const struct net_device *dev, int port, u8 val) +static void kvaser_pci_write_reg(const struct sja1000_priv *priv, + int port, u8 val) { - iowrite8(val, (void __iomem *)(dev->base_addr + port)); + iowrite8(val, priv->reg_base + port); } static void kvaser_pci_disable_irq(struct net_device *dev) @@ -199,7 +200,7 @@ static void kvaser_pci_del_chan(struct net_device *dev) } unregister_sja1000dev(dev); - pci_iounmap(board->pci_dev, (void __iomem *)dev->base_addr); + pci_iounmap(board->pci_dev, priv->reg_base); pci_iounmap(board->pci_dev, board->conf_addr); pci_iounmap(board->pci_dev, board->res_addr); @@ -210,7 +211,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, struct net_device **master_dev, void __iomem *conf_addr, void __iomem *res_addr, - unsigned long base_addr) + void __iomem *base_addr) { struct net_device *dev; struct sja1000_priv *priv; @@ -252,7 +253,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, board->xilinx_ver = master_board->xilinx_ver; } - dev->base_addr = base_addr + channel * KVASER_PCI_PORT_BYTES; + priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES; priv->read_reg = kvaser_pci_read_reg; priv->write_reg = kvaser_pci_write_reg; @@ -267,8 +268,8 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, init_step = 4; - dev_info(&pdev->dev, "base_addr=%#lx conf_addr=%p irq=%d\n", - dev->base_addr, board->conf_addr, dev->irq); + dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n", + priv->reg_base, board->conf_addr, dev->irq); SET_NETDEV_DEV(dev, &pdev->dev); @@ -343,7 +344,7 @@ static int __devinit kvaser_pci_init_one(struct pci_dev *pdev, for (i = 0; i < no_channels; i++) { err = kvaser_pci_add_chan(pdev, i, &master_dev, conf_addr, res_addr, - (unsigned long)base_addr); + base_addr); if (err) goto failure_cleanup; } diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index b689964..571f133 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -89,7 +89,7 @@ static int sja1000_probe_chip(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - if (dev->base_addr && (priv->read_reg(dev, 0) == 0xFF)) { + if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) { printk(KERN_INFO "%s: probing @0x%lX failed\n", DRV_NAME, dev->base_addr); return 0; @@ -100,11 +100,11 @@ static int sja1000_probe_chip(struct net_device *dev) static void set_reset_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(dev, REG_MOD); + unsigned char status = priv->read_reg(priv, REG_MOD); int i; /* disable interrupts */ - priv->write_reg(dev, REG_IER, IRQ_OFF); + priv->write_reg(priv, REG_IER, IRQ_OFF); for (i = 0; i < 100; i++) { /* check reset bit */ @@ -113,9 +113,9 @@ static void set_reset_mode(struct net_device *dev) return; } - priv->write_reg(dev, REG_MOD, MOD_RM); /* reset chip */ + priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */ udelay(10); - status = priv->read_reg(dev, REG_MOD); + status = priv->read_reg(priv, REG_MOD); } dev_err(dev->dev.parent, "setting SJA1000 into reset mode failed!\n"); @@ -124,7 +124,7 @@ static void set_reset_mode(struct net_device *dev) static void set_normal_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(dev, REG_MOD); + unsigned char status = priv->read_reg(priv, REG_MOD); int i; for (i = 0; i < 100; i++) { @@ -132,14 +132,14 @@ static void set_normal_mode(struct net_device *dev) if ((status & MOD_RM) == 0) { priv->can.state = CAN_STATE_ERROR_ACTIVE; /* enable all interrupts */ - priv->write_reg(dev, REG_IER, IRQ_ALL); + priv->write_reg(priv, REG_IER, IRQ_ALL); return; } /* set chip to normal mode */ - priv->write_reg(dev, REG_MOD, 0x00); + priv->write_reg(priv, REG_MOD, 0x00); udelay(10); - status = priv->read_reg(dev, REG_MOD); + status = priv->read_reg(priv, REG_MOD); } dev_err(dev->dev.parent, "setting SJA1000 into normal mode failed!\n"); @@ -154,9 +154,9 @@ static void sja1000_start(struct net_device *dev) set_reset_mode(dev); /* Clear error counters and error code capture */ - priv->write_reg(dev, REG_TXERR, 0x0); - priv->write_reg(dev, REG_RXERR, 0x0); - priv->read_reg(dev, REG_ECC); + priv->write_reg(priv, REG_TXERR, 0x0); + priv->write_reg(priv, REG_RXERR, 0x0); + priv->read_reg(priv, REG_ECC); /* leave reset mode */ set_normal_mode(dev); @@ -198,8 +198,8 @@ static int sja1000_set_bittiming(struct net_device *dev) dev_info(dev->dev.parent, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); - priv->write_reg(dev, REG_BTR0, btr0); - priv->write_reg(dev, REG_BTR1, btr1); + priv->write_reg(priv, REG_BTR0, btr0); + priv->write_reg(priv, REG_BTR1, btr1); return 0; } @@ -217,20 +217,20 @@ static void chipset_init(struct net_device *dev) struct sja1000_priv *priv = netdev_priv(dev); /* set clock divider and output control register */ - priv->write_reg(dev, REG_CDR, priv->cdr | CDR_PELICAN); + priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN); /* set acceptance filter (accept all) */ - priv->write_reg(dev, REG_ACCC0, 0x00); - priv->write_reg(dev, REG_ACCC1, 0x00); - priv->write_reg(dev, REG_ACCC2, 0x00); - priv->write_reg(dev, REG_ACCC3, 0x00); + priv->write_reg(priv, REG_ACCC0, 0x00); + priv->write_reg(priv, REG_ACCC1, 0x00); + priv->write_reg(priv, REG_ACCC2, 0x00); + priv->write_reg(priv, REG_ACCC3, 0x00); - priv->write_reg(dev, REG_ACCM0, 0xFF); - priv->write_reg(dev, REG_ACCM1, 0xFF); - priv->write_reg(dev, REG_ACCM2, 0xFF); - priv->write_reg(dev, REG_ACCM3, 0xFF); + priv->write_reg(priv, REG_ACCM0, 0xFF); + priv->write_reg(priv, REG_ACCM1, 0xFF); + priv->write_reg(priv, REG_ACCM2, 0xFF); + priv->write_reg(priv, REG_ACCM3, 0xFF); - priv->write_reg(dev, REG_OCR, priv->ocr | OCR_MODE_NORMAL); + priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL); } /* @@ -261,27 +261,27 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) if (id & CAN_EFF_FLAG) { fi |= FI_FF; dreg = EFF_BUF; - priv->write_reg(dev, REG_FI, fi); - priv->write_reg(dev, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); - priv->write_reg(dev, REG_ID2, (id & 0x001fe000) >> (5 + 8)); - priv->write_reg(dev, REG_ID3, (id & 0x00001fe0) >> 5); - priv->write_reg(dev, REG_ID4, (id & 0x0000001f) << 3); + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); + priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8)); + priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5); + priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3); } else { dreg = SFF_BUF; - priv->write_reg(dev, REG_FI, fi); - priv->write_reg(dev, REG_ID1, (id & 0x000007f8) >> 3); - priv->write_reg(dev, REG_ID2, (id & 0x00000007) << 5); + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3); + priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5); } for (i = 0; i < dlc; i++) - priv->write_reg(dev, dreg++, cf->data[i]); + priv->write_reg(priv, dreg++, cf->data[i]); stats->tx_bytes += dlc; dev->trans_start = jiffies; can_put_echo_skb(skb, dev, 0); - priv->write_reg(dev, REG_CMR, CMD_TR); + priv->write_reg(priv, REG_CMR, CMD_TR); return 0; } @@ -304,22 +304,22 @@ static void sja1000_rx(struct net_device *dev) skb->dev = dev; skb->protocol = htons(ETH_P_CAN); - fi = priv->read_reg(dev, REG_FI); + fi = priv->read_reg(priv, REG_FI); dlc = fi & 0x0F; if (fi & FI_FF) { /* extended frame format (EFF) */ dreg = EFF_BUF; - id = (priv->read_reg(dev, REG_ID1) << (5 + 16)) - | (priv->read_reg(dev, REG_ID2) << (5 + 8)) - | (priv->read_reg(dev, REG_ID3) << 5) - | (priv->read_reg(dev, REG_ID4) >> 3); + id = (priv->read_reg(priv, REG_ID1) << (5 + 16)) + | (priv->read_reg(priv, REG_ID2) << (5 + 8)) + | (priv->read_reg(priv, REG_ID3) << 5) + | (priv->read_reg(priv, REG_ID4) >> 3); id |= CAN_EFF_FLAG; } else { /* standard frame format (SFF) */ dreg = SFF_BUF; - id = (priv->read_reg(dev, REG_ID1) << 3) - | (priv->read_reg(dev, REG_ID2) >> 5); + id = (priv->read_reg(priv, REG_ID1) << 3) + | (priv->read_reg(priv, REG_ID2) >> 5); } if (fi & FI_RTR) @@ -330,13 +330,13 @@ static void sja1000_rx(struct net_device *dev) cf->can_id = id; cf->can_dlc = dlc; for (i = 0; i < dlc; i++) - cf->data[i] = priv->read_reg(dev, dreg++); + cf->data[i] = priv->read_reg(priv, dreg++); while (i < 8) cf->data[i++] = 0; /* release receive buffer */ - priv->write_reg(dev, REG_CMR, CMD_RRB); + priv->write_reg(priv, REG_CMR, CMD_RRB); netif_rx(skb); @@ -371,7 +371,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(dev, REG_CMR, CMD_CDO); /* clear bit */ + priv->write_reg(priv, REG_CMR, CMD_CDO); /* clear bit */ } if (isrc & IRQ_EI) { @@ -392,7 +392,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) priv->can.can_stats.bus_error++; stats->rx_errors++; - ecc = priv->read_reg(dev, REG_ECC); + ecc = priv->read_reg(priv, REG_ECC); cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; @@ -426,7 +426,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (isrc & IRQ_ALI) { /* arbitration lost interrupt */ dev_dbg(dev->dev.parent, "arbitration lost interrupt\n"); - alc = priv->read_reg(dev, REG_ALC); + alc = priv->read_reg(priv, REG_ALC); priv->can.can_stats.arbitration_lost++; stats->rx_errors++; cf->can_id |= CAN_ERR_LOSTARB; @@ -435,8 +435,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || state == CAN_STATE_ERROR_PASSIVE)) { - uint8_t rxerr = priv->read_reg(dev, REG_RXERR); - uint8_t txerr = priv->read_reg(dev, REG_TXERR); + uint8_t rxerr = priv->read_reg(priv, REG_RXERR); + uint8_t txerr = priv->read_reg(priv, REG_TXERR); cf->can_id |= CAN_ERR_CRTL; if (state == CAN_STATE_ERROR_WARNING) { priv->can.can_stats.error_warning++; @@ -471,15 +471,15 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) int n = 0; /* Shared interrupts and IRQ off? */ - if (priv->read_reg(dev, REG_IER) == IRQ_OFF) + if (priv->read_reg(priv, REG_IER) == IRQ_OFF) return IRQ_NONE; if (priv->pre_irq) - priv->pre_irq(dev); + priv->pre_irq(priv); - while ((isrc = priv->read_reg(dev, REG_IR)) && (n < SJA1000_MAX_IRQ)) { + while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) { n++; - status = priv->read_reg(dev, REG_SR); + status = priv->read_reg(priv, REG_SR); if (isrc & IRQ_WUI) dev_warn(dev->dev.parent, "wakeup interrupt\n"); @@ -494,7 +494,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) /* receive interrupt */ while (status & SR_RBS) { sja1000_rx(dev); - status = priv->read_reg(dev, REG_SR); + status = priv->read_reg(priv, REG_SR); } } if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { @@ -505,7 +505,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) } if (priv->post_irq) - priv->post_irq(dev); + priv->post_irq(priv); if (n >= SJA1000_MAX_IRQ) dev_dbg(dev->dev.parent, "%d messages handled in ISR", n); diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index ccd3028..302d2c7 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -155,14 +155,15 @@ struct sja1000_priv { struct sk_buff *echo_skb; /* the lower-layer is responsible for appropriate locking */ - u8 (*read_reg) (const struct net_device *dev, int reg); - void (*write_reg) (const struct net_device *dev, int reg, u8 val); - void (*pre_irq) (const struct net_device *dev); - void (*post_irq) (const struct net_device *dev); + u8 (*read_reg) (const struct sja1000_priv *priv, int reg); + void (*write_reg) (const struct sja1000_priv *priv, int reg, u8 val); + void (*pre_irq) (const struct sja1000_priv *priv); + void (*post_irq) (const struct sja1000_priv *priv); void *priv; /* for board-specific data */ struct net_device *dev; + void __iomem *reg_base; /* ioremap'ed address to registers */ unsigned long irq_flags; /* for request_irq() */ u16 flags; /* custom mode flags */ diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 8017229..628374c 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -37,14 +37,14 @@ MODULE_AUTHOR("Sascha Hauer "); MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); MODULE_LICENSE("GPL v2"); -static u8 sp_read_reg(const struct net_device *dev, int reg) +static u8 sp_read_reg(const struct sja1000_priv *priv, int reg) { - return ioread8((void __iomem *)(dev->base_addr + reg)); + return ioread8(priv->reg_base + reg); } -static void sp_write_reg(const struct net_device *dev, int reg, u8 val) +static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val) { - iowrite8(val, (void __iomem *)(dev->base_addr + reg)); + iowrite8(val, priv->reg_base + reg); } static int sp_probe(struct platform_device *pdev) @@ -89,9 +89,9 @@ static int sp_probe(struct platform_device *pdev) } priv = netdev_priv(dev); - dev->base_addr = (unsigned long)addr; dev->irq = res_irq->start; priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + priv->reg_base = addr; priv->read_reg = sp_read_reg; priv->write_reg = sp_write_reg; priv->can.clock.freq = pdata->clock; @@ -108,8 +108,8 @@ static int sp_probe(struct platform_device *pdev) goto exit_free; } - dev_info(&pdev->dev, "%s device registered (base_addr=%#lx, irq=%d)\n", - DRV_NAME, dev->base_addr, dev->irq); + dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n", + DRV_NAME, priv->reg_base, dev->irq); return 0; exit_free: @@ -125,13 +125,14 @@ static int sp_probe(struct platform_device *pdev) static int sp_remove(struct platform_device *pdev) { struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); struct resource *res; unregister_sja1000dev(dev); dev_set_drvdata(&pdev->dev, NULL); - if (dev->base_addr) - iounmap((void __iomem *)dev->base_addr); + if (priv->reg_base) + iounmap(priv->reg_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); -- cgit v0.10.2 From d1a277c584d0862dbf51991baea947ea5f2ce6bf Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Sat, 30 May 2009 07:55:50 +0000 Subject: can: sja1000: generic OF platform bus driver This patch adds a generic driver for SJA1000 chips on the OpenFirmware platform bus found on embedded PowerPC systems. You need a SJA1000 node definition in your flattened device tree source (DTS) file similar to: can@3,100 { compatible = "nxp,sja1000"; reg = <3 0x100 0x80>; interrupts = <2 0>; interrupt-parent = <&mpic>; nxp,external-clock-frequency = <16000000>; }; See also Documentation/powerpc/dts-bindings/can/sja1000.txt. CC: devicetree-discuss@ozlabs.org Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/Documentation/powerpc/dts-bindings/can/sja1000.txt b/Documentation/powerpc/dts-bindings/can/sja1000.txt new file mode 100644 index 0000000..d6d209d --- /dev/null +++ b/Documentation/powerpc/dts-bindings/can/sja1000.txt @@ -0,0 +1,53 @@ +Memory mapped SJA1000 CAN controller from NXP (formerly Philips) + +Required properties: + +- compatible : should be "nxp,sja1000". + +- reg : should specify the chip select, address offset and size required + to map the registers of the SJA1000. The size is usually 0x80. + +- interrupts: property with a value describing the interrupt source + (number and sensitivity) required for the SJA1000. + +Optional properties: + +- nxp,external-clock-frequency : Frequency of the external oscillator + clock in Hz. Note that the internal clock frequency used by the + SJA1000 is half of that value. If not specified, a default value + of 16000000 (16 MHz) is used. + +- nxp,tx-output-mode : operation mode of the TX output control logic: + <0x0> : bi-phase output mode + <0x1> : normal output mode (default) + <0x2> : test output mode + <0x3> : clock output mode + +- nxp,tx-output-config : TX output pin configuration: + <0x01> : TX0 invert + <0x02> : TX0 pull-down (default) + <0x04> : TX0 pull-up + <0x06> : TX0 push-pull + <0x08> : TX1 invert + <0x10> : TX1 pull-down + <0x20> : TX1 pull-up + <0x30> : TX1 push-pull + +- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin. + If not specified or if the specified value is 0, the CLKOUT pin + will be disabled. + +- nxp,no-comparator-bypass : Allows to disable the CAN input comperator. + +For futher information, please have a look to the SJA1000 data sheet. + +Examples: + +can@3,100 { + compatible = "nxp,sja1000"; + reg = <3 0x100 0x80>; + interrupts = <2 0>; + interrupt-parent = <&mpic>; + nxp,external-clock-frequency = <16000000>; +}; + diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index cfd6c5a..d5e18812 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -51,6 +51,15 @@ config CAN_SJA1000_PLATFORM boards from Phytec (http://www.phytec.de) like the PCM027, PCM038. +config CAN_SJA1000_OF_PLATFORM + depends on CAN_SJA1000 && PPC_OF + tristate "Generic OF Platform Bus based SJA1000 driver" + ---help--- + This driver adds support for the SJA1000 chips connected to + the OpenFirmware "platform bus" found on embedded systems with + OpenFirmware bindings, e.g. if you have a PowerPC based system + you may want to enable this option. + config CAN_EMS_PCI tristate "EMS CPC-PCI and CPC-PCIe Card" depends on PCI && CAN_SJA1000 diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index d6c631f..9d0c08d 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o +obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c new file mode 100644 index 0000000..aa953fb --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -0,0 +1,233 @@ +/* + * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus + * + * Copyright (C) 2008-2009 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This is a generic driver for SJA1000 chips on the OpenFirmware platform + * bus found on embedded PowerPC systems. You need a SJA1000 CAN node + * definition in your flattened device tree source (DTS) file similar to: + * + * can@3,100 { + * compatible = "nxp,sja1000"; + * reg = <3 0x100 0x80>; + * interrupts = <2 0>; + * interrupt-parent = <&mpic>; + * nxp,external-clock-frequency = <16000000>; + * }; + * + * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further + * information. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000_of_platform" + +MODULE_AUTHOR("Wolfgang Grandegger "); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); +MODULE_LICENSE("GPL v2"); + +#define SJA1000_OFP_CAN_CLOCK (16000000 / 2) + +#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN +#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) + +static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) +{ + return in_8(priv->reg_base + reg); +} + +static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + out_8(priv->reg_base + reg, val); +} + +static int __devexit sja1000_ofp_remove(struct of_device *ofdev) +{ + struct net_device *dev = dev_get_drvdata(&ofdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); + struct device_node *np = ofdev->node; + struct resource res; + + dev_set_drvdata(&ofdev->dev, NULL); + + unregister_sja1000dev(dev); + free_sja1000dev(dev); + iounmap(priv->reg_base); + irq_dispose_mapping(dev->irq); + + of_address_to_resource(np, 0, &res); + release_mem_region(res.start, resource_size(&res)); + + return 0; +} + +static int __devinit sja1000_ofp_probe(struct of_device *ofdev, + const struct of_device_id *id) +{ + struct device_node *np = ofdev->node; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource res; + const u32 *prop; + int err, irq, res_size, prop_size; + void __iomem *base; + + err = of_address_to_resource(np, 0, &res); + if (err) { + dev_err(&ofdev->dev, "invalid address\n"); + return err; + } + + res_size = resource_size(&res); + + if (!request_mem_region(res.start, res_size, DRV_NAME)) { + dev_err(&ofdev->dev, "couldn't request %#x..%#x\n", + res.start, res.end); + return -EBUSY; + } + + base = ioremap_nocache(res.start, res_size); + if (!base) { + dev_err(&ofdev->dev, "couldn't ioremap %#x..%#x\n", + res.start, res.end); + err = -ENOMEM; + goto exit_release_mem; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + dev_err(&ofdev->dev, "no irq found\n"); + err = -ENODEV; + goto exit_unmap_mem; + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_dispose_irq; + } + + priv = netdev_priv(dev); + + priv->read_reg = sja1000_ofp_read_reg; + priv->write_reg = sja1000_ofp_write_reg; + + prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->can.clock.freq = *prop / 2; + else + priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ + + prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= *prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + + prop = of_get_property(np, "nxp,tx-output-config", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + + prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32)) && *prop) { + u32 divider = priv->can.clock.freq * 2 / *prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; + else + priv->cdr |= CDR_CLKOUT_MASK; + } else { + priv->cdr |= CDR_CLK_OFF; /* default */ + } + + prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); + if (!prop) + priv->cdr |= CDR_CBP; /* default */ + + priv->irq_flags = IRQF_SHARED; + priv->reg_base = base; + + dev->irq = irq; + + dev_info(&ofdev->dev, + "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", + priv->reg_base, dev->irq, priv->can.clock.freq, + priv->ocr, priv->cdr); + + dev_set_drvdata(&ofdev->dev, dev); + SET_NETDEV_DEV(dev, &ofdev->dev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_free_sja1000; + } + + return 0; + +exit_free_sja1000: + free_sja1000dev(dev); +exit_dispose_irq: + irq_dispose_mapping(irq); +exit_unmap_mem: + iounmap(base); +exit_release_mem: + release_mem_region(res.start, res_size); + + return err; +} + +static struct of_device_id __devinitdata sja1000_ofp_table[] = { + {.compatible = "nxp,sja1000"}, + {}, +}; + +static struct of_platform_driver sja1000_ofp_driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .probe = sja1000_ofp_probe, + .remove = __devexit_p(sja1000_ofp_remove), + .match_table = sja1000_ofp_table, +}; + +static int __init sja1000_ofp_init(void) +{ + return of_register_platform_driver(&sja1000_ofp_driver); +} +module_init(sja1000_ofp_init); + +static void __exit sja1000_ofp_exit(void) +{ + return of_unregister_platform_driver(&sja1000_ofp_driver); +}; +module_exit(sja1000_ofp_exit); diff --git a/include/linux/can/platform/sja1000.h b/include/linux/can/platform/sja1000.h index 37966e6..01ee2ae 100644 --- a/include/linux/can/platform/sja1000.h +++ b/include/linux/can/platform/sja1000.h @@ -13,6 +13,7 @@ #define OCR_MODE_TEST 0x01 #define OCR_MODE_NORMAL 0x02 #define OCR_MODE_CLOCK 0x03 +#define OCR_MODE_MASK 0x07 #define OCR_TX0_INVERT 0x04 #define OCR_TX0_PULLDOWN 0x08 #define OCR_TX0_PULLUP 0x10 @@ -21,6 +22,8 @@ #define OCR_TX1_PULLDOWN 0x40 #define OCR_TX1_PULLUP 0x80 #define OCR_TX1_PUSHPULL 0xc0 +#define OCR_TX_MASK 0xfc +#define OCR_TX_SHIFT 2 struct sja1000_platform_data { u32 clock; /* CAN bus oscillator frequency in Hz */ -- cgit v0.10.2 From 69bd4ae5dc1ddb3c01e7668c7fd088904082a70c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 31 May 2009 10:57:07 +0000 Subject: cpmac: remove unused variable. This patch removes the unused variables in cpmac_hw_error, cpmac_tx_timeout and cpmac_probe. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index cfb4198..08e2f67 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -731,7 +731,6 @@ static void cpmac_clear_tx(struct net_device *dev) static void cpmac_hw_error(struct work_struct *work) { - int i; struct cpmac_priv *priv = container_of(work, struct cpmac_priv, reset_work); @@ -818,7 +817,6 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) static void cpmac_tx_timeout(struct net_device *dev) { - int i; struct cpmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); @@ -1110,7 +1108,7 @@ static int external_switch; static int __devinit cpmac_probe(struct platform_device *pdev) { - int rc, phy_id, i; + int rc, phy_id; char *mdio_bus_id = "0"; struct resource *mem; struct cpmac_priv *priv; -- cgit v0.10.2 From 0220ff7fc35913dcd8cdf8fb3a0966caf4aed2f3 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 31 May 2009 10:59:15 +0000 Subject: cpmac: prevent fatal exception in cpmac_end_xmit We should not be stopping the subqueues in cpmac_end_xmit but rather test the status of them. Replace the calls to netif_subqueue_stop by __netif_subqueue_stopped. This fixes an unrecoverable exception from happening when running the driver. Signed-off-by: Stefan Weil Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 08e2f67..58afafb 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -615,13 +615,13 @@ static void cpmac_end_xmit(struct net_device *dev, int queue) dev_kfree_skb_irq(desc->skb); desc->skb = NULL; - if (netif_subqueue_stopped(dev, queue)) + if (__netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); } else { if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: end_xmit: spurious interrupt\n", dev->name); - if (netif_subqueue_stopped(dev, queue)) + if (__netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); } } -- cgit v0.10.2 From 56d417b12e57dfe11c9b7ba4bea3882c62a55815 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Mon, 1 Jun 2009 03:07:33 -0700 Subject: IPv6: Add 'autoconf' and 'disable_ipv6' module parameters Add 'autoconf' and 'disable_ipv6' parameters to the IPv6 module. The first controls if IPv6 addresses are autoconfigured from prefixes received in Router Advertisements. The IPv6 loopback (::1) and link-local addresses are still configured. The second controls if IPv6 addresses are desired at all. No IPv6 addresses will be added to any interfaces. Signed-off-by: Brian Haley Signed-off-by: David S. Miller diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 3ffd233..8be7623 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1057,6 +1057,13 @@ disable_ipv6 - BOOLEAN address. Default: FALSE (enable IPv6 operation) + When this value is changed from 1 to 0 (IPv6 is being enabled), + it will dynamically create a link-local address on the given + interface and start Duplicate Address Detection, if necessary. + + When this value is changed from 0 to 1 (IPv6 is being disabled), + it will dynamically delete all address on the given interface. + accept_dad - INTEGER Whether to accept DAD (Duplicate Address Detection). 0: Disable DAD diff --git a/Documentation/networking/ipv6.txt b/Documentation/networking/ipv6.txt index 268e5c1..9fd7e21 100644 --- a/Documentation/networking/ipv6.txt +++ b/Documentation/networking/ipv6.txt @@ -33,3 +33,40 @@ disable A reboot is required to enable IPv6. +autoconf + + Specifies whether to enable IPv6 address autoconfiguration + on all interfaces. This might be used when one does not wish + for addresses to be automatically generated from prefixes + received in Router Advertisements. + + The possible values and their effects are: + + 0 + IPv6 address autoconfiguration is disabled on all interfaces. + + Only the IPv6 loopback address (::1) and link-local addresses + will be added to interfaces. + + 1 + IPv6 address autoconfiguration is enabled on all interfaces. + + This is the default value. + +disable_ipv6 + + Specifies whether to disable IPv6 on all interfaces. + This might be used when no IPv6 addresses are desired. + + The possible values and their effects are: + + 0 + IPv6 is enabled on all interfaces. + + This is the default value. + + 1 + IPv6 is disabled on all interfaces. + + No IPv6 addresses will be added to interfaces. + diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 476d946..c662efa 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -169,6 +169,12 @@ struct ipv6_devconf { __s32 accept_dad; void *sysctl; }; + +struct ipv6_params { + __s32 disable_ipv6; + __s32 autoconf; +}; +extern struct ipv6_params ipv6_defaults; #endif /* index values for the variables in ipv6_devconf */ diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 31938e5..c348837 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -591,7 +591,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, { struct inet6_ifaddr *ifa = NULL; struct rt6_info *rt; - struct net *net = dev_net(idev->dev); int hash; int err = 0; int addr_type = ipv6_addr_type(addr); @@ -608,7 +607,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, goto out2; } - if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) { + if (idev->cnf.disable_ipv6) { err = -EACCES; goto out2; } @@ -1752,6 +1751,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) __u32 prefered_lft; int addr_type; struct inet6_dev *in6_dev; + struct net *net = dev_net(dev); pinfo = (struct prefix_info *) opt; @@ -1809,7 +1809,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (addrconf_finite_timeout(rt_expires)) rt_expires *= HZ; - rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, + rt = rt6_lookup(net, &pinfo->prefix, NULL, dev->ifindex, 1); if (rt && addrconf_is_prefix_route(rt)) { @@ -1846,7 +1846,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) struct inet6_ifaddr * ifp; struct in6_addr addr; int create = 0, update_lft = 0; - struct net *net = dev_net(dev); if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); @@ -3988,6 +3987,75 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table, return addrconf_fixup_forwarding(table, valp, val); } +static void dev_disable_change(struct inet6_dev *idev) +{ + if (!idev || !idev->dev) + return; + + if (idev->cnf.disable_ipv6) + addrconf_notify(NULL, NETDEV_DOWN, idev->dev); + else + addrconf_notify(NULL, NETDEV_UP, idev->dev); +} + +static void addrconf_disable_change(struct net *net, __s32 newf) +{ + struct net_device *dev; + struct inet6_dev *idev; + + read_lock(&dev_base_lock); + for_each_netdev(net, dev) { + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) { + int changed = (!idev->cnf.disable_ipv6) ^ (!newf); + idev->cnf.disable_ipv6 = newf; + if (changed) + dev_disable_change(idev); + } + rcu_read_unlock(); + } + read_unlock(&dev_base_lock); +} + +static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) +{ + struct net *net; + + net = (struct net *)table->extra2; + + if (p == &net->ipv6.devconf_dflt->disable_ipv6) + return 0; + + if (!rtnl_trylock()) + return restart_syscall(); + + if (p == &net->ipv6.devconf_all->disable_ipv6) { + __s32 newf = net->ipv6.devconf_all->disable_ipv6; + net->ipv6.devconf_dflt->disable_ipv6 = newf; + addrconf_disable_change(net, newf); + } else if ((!*p) ^ (!old)) + dev_disable_change((struct inet6_dev *)table->extra1); + + rtnl_unlock(); + return 0; +} + +static +int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int *valp = ctl->data; + int val = *valp; + int ret; + + ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + + if (write) + ret = addrconf_disable_ipv6(ctl, valp, val); + return ret; +} + static struct addrconf_sysctl_table { struct ctl_table_header *sysctl_header; @@ -4225,7 +4293,8 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.disable_ipv6, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = addrconf_sysctl_disable, + .strategy = sysctl_intvec, }, { .ctl_name = CTL_UNNUMBERED, @@ -4346,6 +4415,10 @@ static int addrconf_init_net(struct net *net) dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); if (dflt == NULL) goto err_alloc_dflt; + } else { + /* these will be inherited by all namespaces */ + dflt->autoconf = ipv6_defaults.autoconf; + dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; } net->ipv6.devconf_all = all; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index b6215be..85b3d00 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -72,9 +72,21 @@ MODULE_LICENSE("GPL"); static struct list_head inetsw6[SOCK_MAX]; static DEFINE_SPINLOCK(inetsw6_lock); -static int disable_ipv6 = 0; -module_param_named(disable, disable_ipv6, int, 0); -MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional"); +struct ipv6_params ipv6_defaults = { + .disable_ipv6 = 0, + .autoconf = 1, +}; + +static int disable_ipv6_mod = 0; + +module_param_named(disable, disable_ipv6_mod, int, 0444); +MODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional"); + +module_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444); +MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces"); + +module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444); +MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces"); static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) { @@ -1038,7 +1050,7 @@ static int __init inet6_init(void) for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) INIT_LIST_HEAD(r); - if (disable_ipv6) { + if (disable_ipv6_mod) { printk(KERN_INFO "IPv6: Loaded, but administratively disabled, " "reboot required to enable\n"); @@ -1227,7 +1239,7 @@ module_init(inet6_init); static void __exit inet6_exit(void) { - if (disable_ipv6) + if (disable_ipv6_mod) return; /* First of all disallow new sockets creation. */ -- cgit v0.10.2 From c930a66220bac0815cca74eef94ada221377ffba Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 31 May 2009 20:44:54 +0000 Subject: atl1c_main.c: add wait_for_idle routine Slight refactoring of duplicated wait for idle checks Spelling fix Signed-off-by: Joe Perches Acked-by: jie.yang@atheros.com Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index ac76136..cd547a2 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -164,6 +164,24 @@ static inline void atl1c_irq_reset(struct atl1c_adapter *adapter) } /* + * atl1c_wait_until_idle - wait up to AT_HW_MAX_IDLE_DELAY reads + * of the idle status register until the device is actually idle + */ +static u32 atl1c_wait_until_idle(struct atl1c_hw *hw) +{ + int timeout; + u32 data; + + for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { + AT_READ_REG(hw, REG_IDLE_STATUS, &data); + if ((data & IDLE_STATUS_MASK) == 0) + return 0; + msleep(1); + } + return data; +} + +/* * atl1c_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -1106,7 +1124,6 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter) static int atl1c_stop_mac(struct atl1c_hw *hw) { u32 data; - int timeout; AT_READ_REG(hw, REG_RXQ_CTRL, &data); data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN | @@ -1117,25 +1134,13 @@ static int atl1c_stop_mac(struct atl1c_hw *hw) data &= ~TXQ_CTRL_EN; AT_WRITE_REG(hw, REG_TWSI_CTRL, data); - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &data); - if ((data & (IDLE_STATUS_RXQ_NO_IDLE | - IDLE_STATUS_TXQ_NO_IDLE)) == 0) - break; - msleep(1); - } + atl1c_wait_until_idle(hw); AT_READ_REG(hw, REG_MAC_CTRL, &data); data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN); AT_WRITE_REG(hw, REG_MAC_CTRL, data); - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &data); - if ((data & IDLE_STATUS_MASK) == 0) - return 0; - msleep(1); - } - return data; + return (int)atl1c_wait_until_idle(hw); } static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw) @@ -1178,8 +1183,6 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) { struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; struct pci_dev *pdev = adapter->pdev; - u32 idle_status_data = 0; - int timeout = 0; int ret; AT_WRITE_REG(hw, REG_IMR, 0); @@ -1198,15 +1201,10 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) AT_WRITE_FLUSH(hw); msleep(10); /* Wait at least 10ms for All module to be Idle */ - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data); - if ((idle_status_data & IDLE_STATUS_MASK) == 0) - break; - msleep(1); - } - if (timeout >= AT_HW_MAX_IDLE_DELAY) { + + if (atl1c_wait_until_idle(hw)) { dev_err(&pdev->dev, - "MAC state machine cann't be idle since" + "MAC state machine can't be idle since" " disabled for 10ms second\n"); return -1; } -- cgit v0.10.2 From bbd5898d39ab9f855c732f6f07e40e95b05cf52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Mon, 1 Jun 2009 00:35:16 +0000 Subject: Phonet: fix accounting race between gprs_writeable() and gprs_xmit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the unlikely event that gprs_writeable() and gprs_xmit() check for writeability at the same, we could stop the device queue forever. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 4aa8885..851f6a3 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -212,8 +212,9 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += len; } - if (!pep_writeable(sk)) - netif_stop_queue(dev); + netif_stop_queue(dev); + if (pep_writeable(sk)) + netif_wake_queue(dev); return 0; } -- cgit v0.10.2 From fa202592796499dade5b3854643eaf0eed4d34ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Mon, 1 Jun 2009 01:18:55 +0000 Subject: f_phonet: dev_kfree_skb instead of dev_kfree_skb_any in TX callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Network device TX is never run in IRQ context, and skb is freed outside of the IRQ-disabling spin lock. So checking for IRQ was a waste of time here. Signed-off-by: Rémi Denis-Courmont Signed-off-by: Felipe Balbi Signed-off-by: David S. Miller diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index c1abeb8..54451ee 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -255,7 +255,7 @@ out_unlock: spin_unlock_irqrestore(&port->lock, flags); out: if (unlikely(skb)) { - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); dev->stats.tx_dropped++; } return 0; -- cgit v0.10.2 From c69367fd6730a330c4ba54e9e699733439cbbabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Mon, 1 Jun 2009 01:18:56 +0000 Subject: f_phonet: no need to check for carrier - scheduler does it internally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 54451ee..d6b4871 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -188,8 +188,7 @@ static struct usb_descriptor_header *hs_pn_function[] = { static int pn_net_open(struct net_device *dev) { - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); + netif_wake_queue(dev); return 0; } @@ -219,8 +218,7 @@ static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req) } dev_kfree_skb_any(skb); - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); + netif_wake_queue(dev); } static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev) @@ -383,7 +381,6 @@ static void __pn_reset(struct usb_function *f) struct phonet_port *port = netdev_priv(dev); netif_carrier_off(dev); - netif_stop_queue(dev); port->usb = NULL; usb_ep_disable(fp->out_ep); @@ -427,8 +424,6 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) fp->in_ep->driver_data = fp; netif_carrier_on(dev); - if (netif_running(dev)) - netif_wake_queue(dev); for (i = 0; i < phonet_rxq_size; i++) pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC); } @@ -610,7 +605,6 @@ int __init gphonet_setup(struct usb_gadget *gadget) port = netdev_priv(dev); spin_lock_init(&port->lock); netif_carrier_off(dev); - netif_stop_queue(dev); SET_NETDEV_DEV(dev, &gadget->dev); err = register_netdev(dev); -- cgit v0.10.2 From b61b8af0f3883b451bb9c3b3eaea4379aca9f36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Mon, 1 Jun 2009 01:18:57 +0000 Subject: usb: gadget: f_phonet: fix memory allocation sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: Felipe Balbi Signed-off-by: David S. Miller diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index d6b4871..96fb118 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -569,9 +569,10 @@ static struct net_device *dev; int __init phonet_bind_config(struct usb_configuration *c) { struct f_phonet *fp; - int err; + int err, size; - fp = kzalloc(sizeof(*fp), GFP_KERNEL); + size = sizeof(*fp) + (phonet_rxq_size * sizeof(struct usb_request *)); + fp = kzalloc(size, GFP_KERNEL); if (!fp) return -ENOMEM; @@ -596,9 +597,7 @@ int __init gphonet_setup(struct usb_gadget *gadget) /* Create net device */ BUG_ON(dev); - dev = alloc_netdev(sizeof(*port) - + (phonet_rxq_size * sizeof(struct usb_request *)), - "upnlink%d", pn_net_setup); + dev = alloc_netdev(sizeof(*port), "upnlink%d", pn_net_setup); if (!dev) return -ENOMEM; -- cgit v0.10.2 From dae9de8e13a8a5154688e4c788e65399b4718707 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Tue, 2 Jun 2009 00:20:26 -0700 Subject: IPv6: Print error value when skb allocation fails Print-out the error value when sock_alloc_send_skb() fails in the IPv6 neighbor discovery code - can be useful for debugging. Signed-off-by: Brian Haley Signed-off-by: David S. Miller diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e09f12e..1d13d99 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -465,8 +465,8 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev, 1, &err); if (!skb) { ND_PRINTK0(KERN_ERR - "ICMPv6 ND: %s() failed to allocate an skb.\n", - __func__); + "ICMPv6 ND: %s() failed to allocate an skb, err=%d.\n", + __func__, err); return NULL; } @@ -1562,8 +1562,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, 1, &err); if (buff == NULL) { ND_PRINTK0(KERN_ERR - "ICMPv6 Redirect: %s() failed to allocate an skb.\n", - __func__); + "ICMPv6 Redirect: %s() failed to allocate an skb, err=%d.\n", + __func__, err); goto release; } -- cgit v0.10.2 From 4d52cfbef6266092d535237ba5a4b981458ab171 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Jun 2009 00:42:16 -0700 Subject: net: ipv4/ip_sockglue.c cleanups Pure cleanups Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 43c0585..21b0187 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -157,38 +157,39 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) /* Ordered by supposed usage frequency */ if (flags & 1) ip_cmsg_recv_pktinfo(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_ttl(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_tos(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_opts(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_retopts(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_security(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_dstaddr(msg, skb); } +EXPORT_SYMBOL(ip_cmsg_recv); int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) { @@ -203,7 +204,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) switch (cmsg->cmsg_type) { case IP_RETOPTS: err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); - err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); + err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), + err < 40 ? err : 40); if (err) return err; break; @@ -238,7 +240,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) struct ip_ra_chain *ip_ra_chain; DEFINE_RWLOCK(ip_ra_lock); -int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)) +int ip_ra_control(struct sock *sk, unsigned char on, + void (*destructor)(struct sock *)) { struct ip_ra_chain *ra, *new_ra, **rap; @@ -248,7 +251,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; write_lock_bh(&ip_ra_lock); - for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { + for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { if (ra->sk == sk) { if (on) { write_unlock_bh(&ip_ra_lock); @@ -416,7 +419,8 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) /* Reset and regenerate socket error */ spin_lock_bh(&sk->sk_error_queue.lock); sk->sk_err = 0; - if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { + skb2 = skb_peek(&sk->sk_error_queue); + if (skb2 != NULL) { sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; spin_unlock_bh(&sk->sk_error_queue.lock); sk->sk_error_report(sk); @@ -431,8 +435,8 @@ out: /* - * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on - * an IP socket. + * Socket option code for IP. This is the end of the line after any + * TCP,UDP etc options on an IP socket. */ static int do_ip_setsockopt(struct sock *sk, int level, @@ -474,7 +478,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, switch (optname) { case IP_OPTIONS: { - struct ip_options * opt = NULL; + struct ip_options *opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; err = ip_options_get_from_user(sock_net(sk), &opt, @@ -556,9 +560,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, } break; case IP_TTL: - if (optlen<1) + if (optlen < 1) goto e_inval; - if (val != -1 && (val < 1 || val>255)) + if (val != -1 && (val < 0 || val > 255)) goto e_inval; inet->uc_ttl = val; break; @@ -570,7 +574,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, inet->hdrincl = val ? 1 : 0; break; case IP_MTU_DISCOVER: - if (val<0 || val>3) + if (val < 0 || val > 3) goto e_inval; inet->pmtudisc = val; break; @@ -582,7 +586,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, case IP_MULTICAST_TTL: if (sk->sk_type == SOCK_STREAM) goto e_inval; - if (optlen<1) + if (optlen < 1) goto e_inval; if (val == -1) val = 1; @@ -591,7 +595,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, inet->mc_ttl = val; break; case IP_MULTICAST_LOOP: - if (optlen<1) + if (optlen < 1) goto e_inval; inet->mc_loop = !!val; break; @@ -613,7 +617,8 @@ static int do_ip_setsockopt(struct sock *sk, int level, } else { memset(&mreq, 0, sizeof(mreq)); if (optlen >= sizeof(struct in_addr) && - copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr))) + copy_from_user(&mreq.imr_address, optval, + sizeof(struct in_addr))) break; } @@ -677,7 +682,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, } case IP_MSFILTER: { - extern int sysctl_igmp_max_msf; struct ip_msfilter *msf; if (optlen < IP_MSFILTER_SIZE(0)) @@ -831,7 +835,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, } case MCAST_MSFILTER: { - extern int sysctl_igmp_max_msf; struct sockaddr_in *psin; struct ip_msfilter *msf = NULL; struct group_filter *gsf = NULL; @@ -849,9 +852,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, break; } err = -EFAULT; - if (copy_from_user(gsf, optval, optlen)) { + if (copy_from_user(gsf, optval, optlen)) goto mc_msf_out; - } + /* numsrc >= (4G-140)/128 overflow in 32 bits */ if (gsf->gf_numsrc >= 0x1ffffff || gsf->gf_numsrc > sysctl_igmp_max_msf) { @@ -879,7 +882,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, msf->imsf_fmode = gsf->gf_fmode; msf->imsf_numsrc = gsf->gf_numsrc; err = -EADDRNOTAVAIL; - for (i=0; igf_numsrc; ++i) { + for (i = 0; i < gsf->gf_numsrc; ++i) { psin = (struct sockaddr_in *)&gsf->gf_slist[i]; if (psin->sin_family != AF_INET) @@ -890,7 +893,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, gsf = NULL; err = ip_mc_msfilter(sk, msf, ifindex); - mc_msf_out: +mc_msf_out: kfree(msf); kfree(gsf); break; @@ -900,7 +903,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, break; case IP_FREEBIND: - if (optlen<1) + if (optlen < 1) goto e_inval; inet->freebind = !!val; break; @@ -957,6 +960,7 @@ int ip_setsockopt(struct sock *sk, int level, #endif return err; } +EXPORT_SYMBOL(ip_setsockopt); #ifdef CONFIG_COMPAT int compat_ip_setsockopt(struct sock *sk, int level, int optname, @@ -986,13 +990,12 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, #endif return err; } - EXPORT_SYMBOL(compat_ip_setsockopt); #endif /* - * Get the options. Note for future reference. The GET of IP options gets the - * _received_ ones. The set sets the _sent_ ones. + * Get the options. Note for future reference. The GET of IP options gets + * the _received_ ones. The set sets the _sent_ ones. */ static int do_ip_getsockopt(struct sock *sk, int level, int optname, @@ -1143,7 +1146,8 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, return -EFAULT; } err = ip_mc_gsfget(sk, &gsf, - (struct group_filter __user *)optval, optlen); + (struct group_filter __user *)optval, + optlen); release_sock(sk); return err; } @@ -1187,7 +1191,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, } release_sock(sk); - if (len < sizeof(int) && len > 0 && val>=0 && val<=255) { + if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) { unsigned char ucval = (unsigned char)val; len = 1; if (put_user(len, optlen)) @@ -1230,6 +1234,7 @@ int ip_getsockopt(struct sock *sk, int level, #endif return err; } +EXPORT_SYMBOL(ip_getsockopt); #ifdef CONFIG_COMPAT int compat_ip_getsockopt(struct sock *sk, int level, int optname, @@ -1262,11 +1267,5 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname, #endif return err; } - EXPORT_SYMBOL(compat_ip_getsockopt); #endif - -EXPORT_SYMBOL(ip_cmsg_recv); - -EXPORT_SYMBOL(ip_getsockopt); -EXPORT_SYMBOL(ip_setsockopt); -- cgit v0.10.2 From f771bef98004d9d141b085d987a77d06669d4f4f Mon Sep 17 00:00:00 2001 From: Nivedita Singhvi Date: Thu, 28 May 2009 07:00:46 +0000 Subject: ipv4: New multicast-all socket option After some discussion offline with Christoph Lameter and David Stevens regarding multicast behaviour in Linux, I'm submitting a slightly modified patch from the one Christoph submitted earlier. This patch provides a new socket option IP_MULTICAST_ALL. In this case, default behaviour is _unchanged_ from the current Linux standard. The socket option is set by default to provide original behaviour. Sockets wishing to receive data only from multicast groups they join explicitly will need to clear this socket option. Signed-off-by: Nivedita Singhvi Signed-off-by: Christoph Lameter Acked-by: David Stevens Signed-off-by: David S. Miller diff --git a/include/linux/in.h b/include/linux/in.h index d60122a..cf196da 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -107,6 +107,7 @@ struct in_addr { #define MCAST_JOIN_SOURCE_GROUP 46 #define MCAST_LEAVE_SOURCE_GROUP 47 #define MCAST_MSFILTER 48 +#define IP_MULTICAST_ALL 49 #define MCAST_EXCLUDE 0 #define MCAST_INCLUDE 1 diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index de0ecc7..20a6957 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -130,7 +130,8 @@ struct inet_sock { freebind:1, hdrincl:1, mc_loop:1, - transparent:1; + transparent:1, + mc_all:1; int mc_index; __be32 mc_addr; struct ip_mc_socklist *mc_list; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 5abee4c..d873621 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -375,6 +375,7 @@ lookup_protocol: inet->uc_ttl = -1; inet->mc_loop = 1; inet->mc_ttl = 1; + inet->mc_all = 1; inet->mc_index = 0; inet->mc_list = NULL; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 9eb6219..e6058a5 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2196,7 +2196,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) break; } if (!pmc) - return 1; + return inet->mc_all; psl = pmc->sflist; if (!psl) return pmc->sfmode == MCAST_EXCLUDE; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 21b0187..cb49936 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -453,6 +453,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, (1<= sizeof(int)) { @@ -898,6 +899,13 @@ mc_msf_out: kfree(gsf); break; } + case IP_MULTICAST_ALL: + if (optlen < 1) + goto e_inval; + if (val != 0 && val != 1) + goto e_inval; + inet->mc_all = val; + break; case IP_ROUTER_ALERT: err = ip_ra_control(sk, val ? 1 : 0, NULL); break; @@ -1151,6 +1159,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, release_sock(sk); return err; } + case IP_MULTICAST_ALL: + val = inet->mc_all; + break; case IP_PKTOPTIONS: { struct msghdr msg; -- cgit v0.10.2 From 453a608277355735190e05c43f909808e0f73641 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 20:27:13 +0000 Subject: mlx4_en: Giving interface name in debug messages For each debug message, the message will show interface name in case that the net device was registered, and PCI bus ID with port number if we were not registered yet. Messages that are not port/netdev specific stayed in the old format Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 0cd185a..fea65e7 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -51,14 +51,14 @@ static void mlx4_en_vlan_rx_register(struct net_device *dev, struct vlan_group * struct mlx4_en_dev *mdev = priv->mdev; int err; - mlx4_dbg(HW, priv, "Registering VLAN group:%p\n", grp); + en_dbg(HW, priv, "Registering VLAN group:%p\n", grp); priv->vlgrp = grp; mutex_lock(&mdev->state_lock); if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, grp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -72,15 +72,15 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) if (!priv->vlgrp) return; - mlx4_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n", - vid, vlan_group_get_device(priv->vlgrp, vid)); + en_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n", + vid, vlan_group_get_device(priv->vlgrp, vid)); /* Add VID to port VLAN filter */ mutex_lock(&mdev->state_lock); if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -94,9 +94,8 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (!priv->vlgrp) return; - mlx4_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp " - "entry:%p)\n", vid, priv->vlgrp, - vlan_group_get_device(priv->vlgrp, vid)); + en_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp entry:%p)\n", + vid, priv->vlgrp, vlan_group_get_device(priv->vlgrp, vid)); vlan_group_set_device(priv->vlgrp, vid, NULL); /* Remove VID from port VLAN filter */ @@ -104,7 +103,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -150,9 +149,10 @@ static void mlx4_en_do_set_mac(struct work_struct *work) err = mlx4_register_mac(mdev->dev, priv->port, priv->mac, &priv->mac_index); if (err) - mlx4_err(mdev, "Failed changing HW MAC address\n"); + en_err(priv, "Failed changing HW MAC address\n"); } else - mlx4_dbg(HW, priv, "Port is down, exiting...\n"); + en_dbg(HW, priv, "Port is down while " + "registering mac, exiting...\n"); mutex_unlock(&mdev->state_lock); } @@ -174,7 +174,6 @@ static void mlx4_en_clear_list(struct net_device *dev) static void mlx4_en_cache_mclist(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; struct dev_mc_list *mclist; struct dev_mc_list *tmp; struct dev_mc_list *plist = NULL; @@ -182,7 +181,7 @@ static void mlx4_en_cache_mclist(struct net_device *dev) for (mclist = dev->mc_list; mclist; mclist = mclist->next) { tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC); if (!tmp) { - mlx4_err(mdev, "failed to allocate multicast list\n"); + en_err(priv, "failed to allocate multicast list\n"); mlx4_en_clear_list(dev); return; } @@ -219,13 +218,13 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) mutex_lock(&mdev->state_lock); if (!mdev->device_up) { - mlx4_dbg(HW, priv, "Card is not up, ignoring " - "multicast change.\n"); + en_dbg(HW, priv, "Card is not up, " + "ignoring multicast change.\n"); goto out; } if (!priv->port_up) { - mlx4_dbg(HW, priv, "Port is down, ignoring " - "multicast change.\n"); + en_dbg(HW, priv, "Port is down, " + "ignoring multicast change.\n"); goto out; } @@ -236,29 +235,27 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) if (dev->flags & IFF_PROMISC) { if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { if (netif_msg_rx_status(priv)) - mlx4_warn(mdev, "Port:%d entering promiscuous mode\n", - priv->port); + en_warn(priv, "Entering promiscuous mode\n"); priv->flags |= MLX4_EN_FLAG_PROMISC; /* Enable promiscouos mode */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 1); if (err) - mlx4_err(mdev, "Failed enabling " - "promiscous mode\n"); + en_err(priv, "Failed enabling " + "promiscous mode\n"); /* Disable port multicast filter (unconditionally) */ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling " - "multicast filter\n"); + en_err(priv, "Failed disabling " + "multicast filter\n"); /* Disable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); if (err) - mlx4_err(mdev, "Failed disabling " - "VLAN filter\n"); + en_err(priv, "Failed disabling VLAN filter\n"); } goto out; } @@ -269,20 +266,19 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) if (priv->flags & MLX4_EN_FLAG_PROMISC) { if (netif_msg_rx_status(priv)) - mlx4_warn(mdev, "Port:%d leaving promiscuous mode\n", - priv->port); + en_warn(priv, "Leaving promiscuous mode\n"); priv->flags &= ~MLX4_EN_FLAG_PROMISC; /* Disable promiscouos mode */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); if (err) - mlx4_err(mdev, "Failed disabling promiscous mode\n"); + en_err(priv, "Failed disabling promiscous mode\n"); /* Enable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed enabling VLAN filter\n"); + en_err(priv, "Failed enabling VLAN filter\n"); } /* Enable/disable the multicast filter according to IFF_ALLMULTI */ @@ -290,12 +286,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling multicast filter\n"); + en_err(priv, "Failed disabling multicast filter\n"); } else { err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling multicast filter\n"); + en_err(priv, "Failed disabling multicast filter\n"); /* Flush mcast filter and init it with broadcast address */ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, @@ -314,7 +310,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_ENABLE); if (err) - mlx4_err(mdev, "Failed enabling multicast filter\n"); + en_err(priv, "Failed enabling multicast filter\n"); mlx4_en_clear_list(dev); } @@ -346,10 +342,10 @@ static void mlx4_en_tx_timeout(struct net_device *dev) struct mlx4_en_dev *mdev = priv->mdev; if (netif_msg_timer(priv)) - mlx4_warn(mdev, "Tx timeout called on port:%d\n", priv->port); + en_warn(priv, "Tx timeout called on port:%d\n", priv->port); priv->port_stats.tx_timeout++; - mlx4_dbg(DRV, priv, "Scheduling watchdog\n"); + en_dbg(DRV, priv, "Scheduling watchdog\n"); queue_work(mdev->workqueue, &priv->watchdog_task); } @@ -378,8 +374,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) */ priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1; priv->rx_usecs = MLX4_EN_RX_COAL_TIME; - mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - " - "rx_frames:%d rx_usecs:%d\n", + en_dbg(INTR, priv, "Default coalesing params for mtu:%d - " + "rx_frames:%d rx_usecs:%d\n", priv->dev->mtu, priv->rx_frames, priv->rx_usecs); /* Setup cq moderation params */ @@ -412,7 +408,6 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) { unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_cq *cq; unsigned long packets; unsigned long rate; @@ -472,11 +467,11 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) moder_time = priv->rx_usecs; } - mlx4_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", - tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period); + en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", + tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period); - mlx4_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu " - "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n", + en_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu " + "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n", priv->last_moder_time, moder_time, period, packets, avg_pkt_size, rate); @@ -487,8 +482,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) cq->moder_time = moder_time; err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed modifying moderation for cq:%d " - "on port:%d\n", i, priv->port); + en_err(priv, "Failed modifying moderation for cq:%d\n", i); break; } } @@ -511,8 +505,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work) err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); if (err) - mlx4_dbg(HW, priv, "Could not update stats for " - "port:%d\n", priv->port); + en_dbg(HW, priv, "Could not update stats \n"); mutex_lock(&mdev->state_lock); if (mdev->device_up) { @@ -536,12 +529,10 @@ static void mlx4_en_linkstate(struct work_struct *work) * report to system log */ if (priv->last_link_state != linkstate) { if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { - if (netif_msg_link(priv)) - mlx4_info(mdev, "Port %d - link down\n", priv->port); + en_dbg(LINK, priv, "Link Down\n"); netif_carrier_off(priv->dev); } else { - if (netif_msg_link(priv)) - mlx4_info(mdev, "Port %d - link up\n", priv->port); + en_dbg(LINK, priv, "Link Up\n"); netif_carrier_on(priv->dev); } } @@ -563,19 +554,19 @@ int mlx4_en_start_port(struct net_device *dev) int j; if (priv->port_up) { - mlx4_dbg(DRV, priv, "start port called while port already up\n"); + en_dbg(DRV, priv, "start port called while port already up\n"); return 0; } /* Calculate Rx buf size */ dev->mtu = min(dev->mtu, priv->max_mtu); mlx4_en_calc_rx_buf(dev); - mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); + en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); /* Configure rx cq's and rings */ err = mlx4_en_activate_rx_rings(priv); if (err) { - mlx4_err(mdev, "Failed to activate RX rings\n"); + en_err(priv, "Failed to activate RX rings\n"); return err; } for (i = 0; i < priv->rx_ring_num; i++) { @@ -583,14 +574,14 @@ int mlx4_en_start_port(struct net_device *dev) err = mlx4_en_activate_cq(priv, cq); if (err) { - mlx4_err(mdev, "Failed activating Rx CQ\n"); + en_err(priv, "Failed activating Rx CQ\n"); goto cq_err; } for (j = 0; j < cq->size; j++) cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed setting cq moderation parameters"); + en_err(priv, "Failed setting cq moderation parameters"); mlx4_en_deactivate_cq(priv, cq); goto cq_err; } @@ -601,7 +592,7 @@ int mlx4_en_start_port(struct net_device *dev) err = mlx4_en_config_rss_steer(priv); if (err) { - mlx4_err(mdev, "Failed configuring rss steering\n"); + en_err(priv, "Failed configuring rss steering\n"); goto cq_err; } @@ -611,16 +602,16 @@ int mlx4_en_start_port(struct net_device *dev) cq = &priv->tx_cq[i]; err = mlx4_en_activate_cq(priv, cq); if (err) { - mlx4_err(mdev, "Failed allocating Tx CQ\n"); + en_err(priv, "Failed allocating Tx CQ\n"); goto tx_err; } err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed setting cq moderation parameters"); + en_err(priv, "Failed setting cq moderation parameters"); mlx4_en_deactivate_cq(priv, cq); goto tx_err; } - mlx4_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); + en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); cq->buf->wqe_index = cpu_to_be16(0xffff); /* Configure ring */ @@ -628,7 +619,7 @@ int mlx4_en_start_port(struct net_device *dev) err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, priv->rx_ring[0].srq.srqn); if (err) { - mlx4_err(mdev, "Failed allocating Tx ring\n"); + en_err(priv, "Failed allocating Tx ring\n"); mlx4_en_deactivate_cq(priv, cq); goto tx_err; } @@ -646,30 +637,30 @@ int mlx4_en_start_port(struct net_device *dev) priv->prof->rx_pause, priv->prof->rx_ppp); if (err) { - mlx4_err(mdev, "Failed setting port general configurations" - " for port %d, with error %d\n", priv->port, err); + en_err(priv, "Failed setting port general configurations " + "for port %d, with error %d\n", priv->port, err); goto tx_err; } /* Set default qp number */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); if (err) { - mlx4_err(mdev, "Failed setting default qp numbers\n"); + en_err(priv, "Failed setting default qp numbers\n"); goto tx_err; } /* Set port mac number */ - mlx4_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); + en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); err = mlx4_register_mac(mdev->dev, priv->port, priv->mac, &priv->mac_index); if (err) { - mlx4_err(mdev, "Failed setting port mac\n"); + en_err(priv, "Failed setting port mac\n"); goto tx_err; } /* Init port */ - mlx4_dbg(HW, priv, "Initializing port\n"); + en_dbg(HW, priv, "Initializing port\n"); err = mlx4_INIT_PORT(mdev->dev, priv->port); if (err) { - mlx4_err(mdev, "Failed Initializing port\n"); + en_err(priv, "Failed Initializing port\n"); goto mac_err; } @@ -706,8 +697,7 @@ void mlx4_en_stop_port(struct net_device *dev) int i; if (!priv->port_up) { - mlx4_dbg(DRV, priv, "stop port (%d) called while port already down\n", - priv->port); + en_dbg(DRV, priv, "stop port called while port already down\n"); return; } netif_stop_queue(dev); @@ -752,13 +742,13 @@ static void mlx4_en_restart(struct work_struct *work) struct mlx4_en_dev *mdev = priv->mdev; struct net_device *dev = priv->dev; - mlx4_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); + en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); mutex_lock(&mdev->state_lock); if (priv->port_up) { mlx4_en_stop_port(dev); if (mlx4_en_start_port(dev)) - mlx4_err(mdev, "Failed restarting port %d\n", priv->port); + en_err(priv, "Failed restarting port %d\n", priv->port); } mutex_unlock(&mdev->state_lock); } @@ -774,14 +764,14 @@ static int mlx4_en_open(struct net_device *dev) mutex_lock(&mdev->state_lock); if (!mdev->device_up) { - mlx4_err(mdev, "Cannot open - device down/disabled\n"); + en_err(priv, "Cannot open - device down/disabled\n"); err = -EBUSY; goto out; } /* Reset HW statistics and performance counters */ if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) - mlx4_dbg(HW, priv, "Failed dumping statistics\n"); + en_dbg(HW, priv, "Failed dumping statistics\n"); memset(&priv->stats, 0, sizeof(priv->stats)); memset(&priv->pstats, 0, sizeof(priv->pstats)); @@ -798,7 +788,7 @@ static int mlx4_en_open(struct net_device *dev) mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) - mlx4_err(mdev, "Failed starting port:%d\n", priv->port); + en_err(priv, "Failed starting port:%d\n", priv->port); out: mutex_unlock(&mdev->state_lock); @@ -811,8 +801,7 @@ static int mlx4_en_close(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - if (netif_msg_ifdown(priv)) - mlx4_info(mdev, "Close called for port:%d\n", priv->port); + en_dbg(IFDOWN, priv, "Close port called\n"); mutex_lock(&mdev->state_lock); @@ -844,7 +833,6 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_port_profile *prof = priv->prof; int i; @@ -873,7 +861,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) return 0; err: - mlx4_err(mdev, "Failed to allocate NIC resources\n"); + en_err(priv, "Failed to allocate NIC resources\n"); return -ENOMEM; } @@ -883,7 +871,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - mlx4_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); + en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); /* Unregister device - this will close the port if it was up */ if (priv->registered) @@ -912,11 +900,11 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) struct mlx4_en_dev *mdev = priv->mdev; int err = 0; - mlx4_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", + en_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", dev->mtu, new_mtu); if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { - mlx4_err(mdev, "Bad MTU size:%d.\n", new_mtu); + en_err(priv, "Bad MTU size:%d.\n", new_mtu); return -EPERM; } dev->mtu = new_mtu; @@ -926,13 +914,13 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) if (!mdev->device_up) { /* NIC is probably restarting - let watchdog task reset * the port */ - mlx4_dbg(DRV, priv, "Change MTU called with card down!?\n"); + en_dbg(DRV, priv, "Change MTU called with card down!?\n"); } else { mlx4_en_stop_port(dev); mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) { - mlx4_err(mdev, "Failed restarting port:%d\n", + en_err(priv, "Failed restarting port:%d\n", priv->port); queue_work(mdev->workqueue, &priv->watchdog_task); } @@ -1006,7 +994,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; priv->mac = mdev->dev->caps.def_mac[priv->port]; if (ILLEGAL_MAC(priv->mac)) { - mlx4_err(mdev, "Port: %d, invalid mac burned: 0x%llx, quiting\n", + en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", priv->port, priv->mac); err = -EINVAL; goto out; @@ -1025,7 +1013,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); if (err) { - mlx4_err(mdev, "Failed to allocate page for rx qps\n"); + en_err(priv, "Failed to allocate page for rx qps\n"); goto out; } priv->allocated = 1; @@ -1068,9 +1056,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, netif_carrier_off(dev); err = register_netdev(dev); if (err) { - mlx4_err(mdev, "Netdev registration failed\n"); + en_err(priv, "Netdev registration failed for port %d\n", port); goto out; } + + en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); + en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); + priv->registered = 1; queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); return 0; diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c index c1bd040..3290fec 100644 --- a/drivers/net/mlx4/en_params.c +++ b/drivers/net/mlx4/en_params.c @@ -371,7 +371,7 @@ static int mlx4_en_set_pauseparam(struct net_device *dev, priv->prof->rx_pause, priv->prof->rx_ppp); if (err) - mlx4_err(mdev, "Failed setting pause params to\n"); + en_err(priv, "Failed setting pause params\n"); return err; } @@ -421,13 +421,13 @@ static int mlx4_en_set_ringparam(struct net_device *dev, err = mlx4_en_alloc_resources(priv); if (err) { - mlx4_err(mdev, "Failed reallocating port resources\n"); + en_err(priv, "Failed reallocating port resources\n"); goto out; } if (port_up) { err = mlx4_en_start_port(dev); if (err) - mlx4_err(mdev, "Failed starting port\n"); + en_err(priv, "Failed starting port\n"); } out: diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 6bfab6e..5a14899 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -114,8 +114,8 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, goto out; page_alloc->offset = priv->frag_info[i].frag_align; - mlx4_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n", - i, page_alloc->page); + en_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n", + i, page_alloc->page); } return 0; @@ -136,8 +136,8 @@ static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv, for (i = 0; i < priv->num_frags; i++) { page_alloc = &ring->page_alloc[i]; - mlx4_dbg(DRV, priv, "Freeing allocator:%d count:%d\n", - i, page_count(page_alloc->page)); + en_dbg(DRV, priv, "Freeing allocator:%d count:%d\n", + i, page_count(page_alloc->page)); put_page(page_alloc->page); page_alloc->page = NULL; @@ -214,10 +214,10 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, skb_frags = ring->rx_info + (index << priv->log_rx_info); for (nr = 0; nr < priv->num_frags; nr++) { - mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr); + en_dbg(DRV, priv, "Freeing fragment:%d\n", nr); dma = be64_to_cpu(rx_desc->data[nr].addr); - mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); + en_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, PCI_DMA_FROMDEVICE); put_page(skb_frags[nr].page); @@ -226,7 +226,6 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_rx_ring *ring; int ring_ind; int buf_ind; @@ -239,14 +238,14 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) if (mlx4_en_prepare_rx_desc(priv, ring, ring->actual_size)) { if (ring->actual_size < MLX4_EN_MIN_RX_SIZE) { - mlx4_err(mdev, "Failed to allocate " - "enough rx buffers\n"); + en_err(priv, "Failed to allocate " + "enough rx buffers\n"); return -ENOMEM; } else { new_size = rounddown_pow_of_two(ring->actual_size); - mlx4_warn(mdev, "Only %d buffers allocated " - "reducing ring size to %d", - ring->actual_size, new_size); + en_warn(priv, "Only %d buffers allocated " + "reducing ring size to %d", + ring->actual_size, new_size); goto reduce_rings; } } @@ -282,8 +281,7 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, ring->size_mask); if (err) { if (netif_msg_rx_err(priv)) - mlx4_warn(priv->mdev, - "Failed preparing rx descriptor\n"); + en_warn(priv, "Failed preparing rx descriptor\n"); priv->port_stats.rx_alloc_failed++; break; } @@ -301,14 +299,14 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, { int index; - mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", - ring->cons, ring->prod); + en_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", + ring->cons, ring->prod); /* Unmap and free Rx buffers */ BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); while (ring->cons != ring->prod) { index = ring->cons & ring->size_mask; - mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index); + en_dbg(DRV, priv, "Processing descriptor:%d\n", index); mlx4_en_free_rx_desc(priv, ring, index); ++ring->cons; } @@ -373,10 +371,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, sizeof(struct skb_frag_struct)); ring->rx_info = vmalloc(tmp); if (!ring->rx_info) { - mlx4_err(mdev, "Failed allocating rx_info ring\n"); + en_err(priv, "Failed allocating rx_info ring\n"); return -ENOMEM; } - mlx4_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n", + en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n", ring->rx_info, tmp); err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, @@ -386,7 +384,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, err = mlx4_en_map_buffer(&ring->wqres.buf); if (err) { - mlx4_err(mdev, "Failed to map RX buffer\n"); + en_err(priv, "Failed to map RX buffer\n"); goto err_hwq; } ring->buf = ring->wqres.buf.direct.buf; @@ -404,7 +402,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, sizeof(struct net_lro_desc), GFP_KERNEL); if (!ring->lro.lro_arr) { - mlx4_err(mdev, "Failed to allocate lro array\n"); + en_err(priv, "Failed to allocate lro array\n"); goto err_map; } ring->lro.get_frag_header = mlx4_en_get_frag_header; @@ -455,7 +453,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) /* Initialize page allocators */ err = mlx4_en_init_allocator(priv, ring); if (err) { - mlx4_err(mdev, "Failed initializing ring allocator\n"); + en_err(priv, "Failed initializing ring allocator\n"); ring_ind--; goto err_allocator; } @@ -486,7 +484,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) err = mlx4_srq_alloc(mdev->dev, mdev->priv_pdn, &ring->wqres.mtt, ring->wqres.db.dma, &ring->srq); if (err){ - mlx4_err(mdev, "Failed to allocate srq\n"); + en_err(priv, "Failed to allocate srq\n"); ring_ind--; goto err_srq; } @@ -601,7 +599,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv, skb = dev_alloc_skb(SMALL_PACKET_SIZE + NET_IP_ALIGN); if (!skb) { - mlx4_dbg(RX_ERR, priv, "Failed allocating skb\n"); + en_dbg(RX_ERR, priv, "Failed allocating skb\n"); return NULL; } skb->dev = priv->dev; @@ -680,7 +678,6 @@ static void mlx4_en_copy_desc(struct mlx4_en_priv *priv, int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_cqe *cqe; struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; struct skb_frag_struct *skb_frags; @@ -717,14 +714,14 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud /* Drop packet on bad receive or bad checksum */ if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_ERROR)) { - mlx4_err(mdev, "CQE completed in error - vendor " + en_err(priv, "CQE completed in error - vendor " "syndrom:%d syndrom:%d\n", ((struct mlx4_err_cqe *) cqe)->vendor_err_syndrome, ((struct mlx4_err_cqe *) cqe)->syndrome); goto next; } if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) { - mlx4_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); + en_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); goto next; } @@ -874,7 +871,7 @@ static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16 u16 res = MLX4_EN_ALLOC_SIZE % stride; u16 offset = MLX4_EN_ALLOC_SIZE - stride - res + align; - mlx4_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d " + en_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d " "res:%d offset:%d\n", stride, align, res, offset); return offset; } @@ -919,10 +916,10 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) priv->rx_skb_size = eff_mtu; priv->log_rx_info = ROUNDUP_LOG2(i * sizeof(struct skb_frag_struct)); - mlx4_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d " + en_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d " "num_frags:%d):\n", eff_mtu, priv->num_frags); for (i = 0; i < priv->num_frags; i++) { - mlx4_dbg(DRV, priv, " frag:%d - size:%d prefix:%d align:%d " + en_dbg(DRV, priv, " frag:%d - size:%d prefix:%d align:%d " "stride:%d last_offset:%d\n", i, priv->frag_info[i].frag_size, priv->frag_info[i].frag_prefix_size, @@ -942,12 +939,12 @@ void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, int i; rss_map->size = roundup_pow_of_two(num_entries); - mlx4_dbg(DRV, priv, "Setting default RSS map of %d entires\n", - rss_map->size); + en_dbg(DRV, priv, "Setting default RSS map of %d entires\n", + rss_map->size); for (i = 0; i < rss_map->size; i++) { rss_map->map[i] = i % num_rings; - mlx4_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); + en_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); } } @@ -962,13 +959,13 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, context = kmalloc(sizeof *context , GFP_KERNEL); if (!context) { - mlx4_err(mdev, "Failed to allocate qp context\n"); + en_err(priv, "Failed to allocate qp context\n"); return -ENOMEM; } err = mlx4_qp_alloc(mdev->dev, qpn, qp); if (err) { - mlx4_err(mdev, "Failed to allocate qp #%d\n", qpn); + en_err(priv, "Failed to allocate qp #%x\n", qpn); goto out; } qp->event = mlx4_en_sqp_event; @@ -1000,12 +997,11 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) int err = 0; int good_qps = 0; - mlx4_dbg(DRV, priv, "Configuring rss steering for port %u\n", priv->port); + en_dbg(DRV, priv, "Configuring rss steering\n"); err = mlx4_qp_reserve_range(mdev->dev, rss_map->size, rss_map->size, &rss_map->base_qpn); if (err) { - mlx4_err(mdev, "Failed reserving %d qps for port %u\n", - rss_map->size, priv->port); + en_err(priv, "Failed reserving %d qps\n", rss_map->size); return err; } @@ -1025,13 +1021,13 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) /* Configure RSS indirection qp */ err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); if (err) { - mlx4_err(mdev, "Failed to reserve range for RSS " - "indirection qp\n"); + en_err(priv, "Failed to reserve range for RSS " + "indirection qp\n"); goto rss_err; } err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); if (err) { - mlx4_err(mdev, "Failed to allocate RSS indirection QP\n"); + en_err(priv, "Failed to allocate RSS indirection QP\n"); goto reserve_err; } rss_map->indir_qp.event = mlx4_en_sqp_event; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 1c83a96..95703f9 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -68,15 +68,15 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, tmp = size * sizeof(struct mlx4_en_tx_info); ring->tx_info = vmalloc(tmp); if (!ring->tx_info) { - mlx4_err(mdev, "Failed allocating tx_info ring\n"); + en_err(priv, "Failed allocating tx_info ring\n"); return -ENOMEM; } - mlx4_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", + en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", ring->tx_info, tmp); ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL); if (!ring->bounce_buf) { - mlx4_err(mdev, "Failed allocating bounce buffer\n"); + en_err(priv, "Failed allocating bounce buffer\n"); err = -ENOMEM; goto err_tx; } @@ -85,31 +85,31 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, 2 * PAGE_SIZE); if (err) { - mlx4_err(mdev, "Failed allocating hwq resources\n"); + en_err(priv, "Failed allocating hwq resources\n"); goto err_bounce; } err = mlx4_en_map_buffer(&ring->wqres.buf); if (err) { - mlx4_err(mdev, "Failed to map TX buffer\n"); + en_err(priv, "Failed to map TX buffer\n"); goto err_hwq_res; } ring->buf = ring->wqres.buf.direct.buf; - mlx4_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " - "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, - ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); + en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " + "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, + ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn); if (err) { - mlx4_err(mdev, "Failed reserving qp for tx ring.\n"); + en_err(priv, "Failed reserving qp for tx ring.\n"); goto err_map; } err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); if (err) { - mlx4_err(mdev, "Failed allocating qp %d\n", ring->qpn); + en_err(priv, "Failed allocating qp %d\n", ring->qpn); goto err_reserve; } ring->qp.event = mlx4_en_sqp_event; @@ -135,7 +135,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring) { struct mlx4_en_dev *mdev = priv->mdev; - mlx4_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); + en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); mlx4_qp_remove(mdev->dev, &ring->qp); mlx4_qp_free(mdev->dev, &ring->qp); @@ -274,12 +274,12 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) /* Skip last polled descriptor */ ring->cons += ring->last_nr_txbb; - mlx4_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", + en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", ring->cons, ring->prod); if ((u32) (ring->prod - ring->cons) > ring->size) { if (netif_msg_tx_err(priv)) - mlx4_warn(priv->mdev, "Tx consumer passed producer!\n"); + en_warn(priv, "Tx consumer passed producer!\n"); return 0; } @@ -292,7 +292,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) } if (cnt) - mlx4_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); + en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); return cnt; } @@ -321,7 +321,7 @@ void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num num = 0; } prio_map[prio] = ring; - mlx4_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring); + en_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring); num++; } } @@ -539,7 +539,6 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev, int *lso_header_size) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; int real_size; if (skb_is_gso(skb)) { @@ -553,14 +552,14 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev, real_size += DS_SIZE; else { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "Non-linear headers\n"); + en_warn(priv, "Non-linear headers\n"); dev_kfree_skb_any(skb); return 0; } } if (unlikely(*lso_header_size > MAX_LSO_HDR_SIZE)) { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "LSO header size too big\n"); + en_warn(priv, "LSO header size too big\n"); dev_kfree_skb_any(skb); return 0; } @@ -669,7 +668,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) nr_txbb = desc_size / TXBB_SIZE; if (unlikely(nr_txbb > MAX_DESC_TXBBS)) { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "Oversized header or SG list\n"); + en_warn(priv, "Oversized header or SG list\n"); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -695,7 +694,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Now that we know what Tx ring to use */ if (unlikely(!priv->port_up)) { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "xmit: port down!\n"); + en_warn(priv, "xmit: port down!\n"); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index ef840ab..c92b382 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -55,20 +55,36 @@ #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) -#define mlx4_dbg(mlevel, priv, format, arg...) \ - if (NETIF_MSG_##mlevel & priv->msg_enable) \ - printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\ - (dev_name(&priv->mdev->pdev->dev)) , ## arg) +#define en_print(level, priv, format, arg...) \ + { \ + if ((priv)->registered) \ + printk(level "%s: %s: " format, DRV_NAME, \ + (priv->dev)->name, ## arg); \ + else \ + printk(level "%s: %s: Port %d: " format, \ + DRV_NAME, dev_name(&priv->mdev->pdev->dev), \ + (priv)->port, ## arg); \ + } + +#define en_dbg(mlevel, priv, format, arg...) \ + { \ + if (NETIF_MSG_##mlevel & priv->msg_enable) \ + en_print(KERN_DEBUG, priv, format, ## arg) \ + } +#define en_warn(priv, format, arg...) \ + en_print(KERN_WARNING, priv, format, ## arg) +#define en_err(priv, format, arg...) \ + en_print(KERN_ERR, priv, format, ## arg) #define mlx4_err(mdev, format, arg...) \ printk(KERN_ERR "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) #define mlx4_info(mdev, format, arg...) \ printk(KERN_INFO "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) #define mlx4_warn(mdev, format, arg...) \ printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) /* * Device constants -- cgit v0.10.2 From a2b28737a2c504ad4306eec30fc893e7f4513359 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 23:20:18 +0000 Subject: mlx4_en: Moved all module parameters handling to en_main.c en_params.c file now only handles Ethtool functionality Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 510633f..23955d8 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -51,6 +51,60 @@ static const char mlx4_en_version[] = DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; +#define MLX4_EN_PARM_INT(X, def_val, desc) \ + static unsigned int X = def_val;\ + module_param(X , uint, 0444); \ + MODULE_PARM_DESC(X, desc); + + +/* + * Device scope module parameters + */ + + +/* Use a XOR rathern than Toeplitz hash function for RSS */ +MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS"); + +/* RSS hash type mask - default to */ +MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask"); + +/* Number of LRO sessions per Rx ring (rounded up to a power of two) */ +MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, + "Number of LRO sessions per ring or disabled (0)"); + +/* Priority pausing */ +MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." + " Per priority bit mask"); +MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." + " Per priority bit mask"); + +static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) +{ + struct mlx4_en_profile *params = &mdev->profile; + int i; + + params->rss_xor = (rss_xor != 0); + params->rss_mask = rss_mask & 0x1f; + params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); + for (i = 1; i <= MLX4_MAX_PORTS; i++) { + params->prof[i].rx_pause = 1; + params->prof[i].rx_ppp = pfcrx; + params->prof[i].tx_pause = 1; + params->prof[i].tx_ppp = pfctx; + params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; + params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; + } + if (pfcrx || pfctx) { + params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM; + params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM; + } else { + params->prof[1].tx_ring_num = 1; + params->prof[2].tx_ring_num = 1; + } + + return 0; +} + static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, enum mlx4_dev_event event, int port) { diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c index 3290fec..91d8116 100644 --- a/drivers/net/mlx4/en_params.c +++ b/drivers/net/mlx4/en_params.c @@ -38,64 +38,6 @@ #include "mlx4_en.h" #include "en_port.h" -#define MLX4_EN_PARM_INT(X, def_val, desc) \ - static unsigned int X = def_val;\ - module_param(X , uint, 0444); \ - MODULE_PARM_DESC(X, desc); - - -/* - * Device scope module parameters - */ - - -/* Use a XOR rathern than Toeplitz hash function for RSS */ -MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS"); - -/* RSS hash type mask - default to */ -MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask"); - -/* Number of LRO sessions per Rx ring (rounded up to a power of two) */ -MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, - "Number of LRO sessions per ring or disabled (0)"); - -/* Priority pausing */ -MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." - " Per priority bit mask"); -MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." - " Per priority bit mask"); - -int mlx4_en_get_profile(struct mlx4_en_dev *mdev) -{ - struct mlx4_en_profile *params = &mdev->profile; - int i; - - params->rss_xor = (rss_xor != 0); - params->rss_mask = rss_mask & 0x1f; - params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); - for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = 1; - params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = 1; - params->prof[i].tx_ppp = pfctx; - params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; - params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - } - if (pfcrx || pfctx) { - params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM; - params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM; - } else { - params->prof[1].tx_ring_num = 1; - params->prof[2].tx_ring_num = 1; - } - - return 0; -} - - -/* - * Ethtool support - */ static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv) { diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index c92b382..174ae86 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -516,8 +516,6 @@ void mlx4_en_stop_port(struct net_device *dev); void mlx4_en_free_resources(struct mlx4_en_priv *priv); int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); -int mlx4_en_get_profile(struct mlx4_en_dev *mdev); - int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, int entries, int ring, enum cq_type mode); void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); -- cgit v0.10.2 From 9e47edaa1ae2efad7db0c8c7fb53e4431bb35364 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 23:21:20 +0000 Subject: mlx4_en renamed en_params.c to en_ethtool.c Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile index 21040a0..1fd068e 100644 --- a/drivers/net/mlx4/Makefile +++ b/drivers/net/mlx4/Makefile @@ -5,5 +5,5 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ obj-$(CONFIG_MLX4_EN) += mlx4_en.o -mlx4_en-y := en_main.o en_tx.o en_rx.o en_params.o en_port.o en_cq.o \ +mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ en_resources.o en_netdev.o diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c new file mode 100644 index 0000000..91d8116 --- /dev/null +++ b/drivers/net/mlx4/en_ethtool.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. 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 + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 +#include +#include + +#include "mlx4_en.h" +#include "en_port.h" + + +static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv) +{ + int i; + + priv->port_stats.lro_aggregated = 0; + priv->port_stats.lro_flushed = 0; + priv->port_stats.lro_no_desc = 0; + + for (i = 0; i < priv->rx_ring_num; i++) { + priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated; + priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed; + priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc; + } +} + +static void +mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + + sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); + strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); + sprintf(drvinfo->fw_version, "%d.%d.%d", + (u16) (mdev->dev->caps.fw_ver >> 32), + (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff), + (u16) (mdev->dev->caps.fw_ver & 0xffff)); + strncpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), 32); + drvinfo->n_stats = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +static u32 mlx4_en_get_tso(struct net_device *dev) +{ + return (dev->features & NETIF_F_TSO) != 0; +} + +static int mlx4_en_set_tso(struct net_device *dev, u32 data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + if (data) { + if (!priv->mdev->LSO_support) + return -EPERM; + dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); + } else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + return 0; +} + +static u32 mlx4_en_get_rx_csum(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + return priv->rx_csum; +} + +static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + priv->rx_csum = (data != 0); + return 0; +} + +static const char main_strings[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", + "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", + "rx_length_errors", "rx_over_errors", "rx_crc_errors", + "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", + "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", + "tx_heartbeat_errors", "tx_window_errors", + + /* port statistics */ + "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets", + "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", + "rx_csum_good", "rx_csum_none", "tx_chksum_offload", + + /* packet statistics */ + "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3", + "rx_prio_4", "rx_prio_5", "rx_prio_6", "rx_prio_7", "tx_prio_0", + "tx_prio_1", "tx_prio_2", "tx_prio_3", "tx_prio_4", "tx_prio_5", + "tx_prio_6", "tx_prio_7", +}; +#define NUM_MAIN_STATS 21 +#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) + +static u32 mlx4_en_get_msglevel(struct net_device *dev) +{ + return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; +} + +static void mlx4_en_set_msglevel(struct net_device *dev, u32 val) +{ + ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable = val; +} + +static void mlx4_en_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + + return; +} + +static int mlx4_en_get_sset_count(struct net_device *dev, int sset) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + if (sset != ETH_SS_STATS) + return -EOPNOTSUPP; + + return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2; +} + +static void mlx4_en_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, uint64_t *data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int index = 0; + int i; + + spin_lock_bh(&priv->stats_lock); + + mlx4_en_update_lro_stats(priv); + + for (i = 0; i < NUM_MAIN_STATS; i++) + data[index++] = ((unsigned long *) &priv->stats)[i]; + for (i = 0; i < NUM_PORT_STATS; i++) + data[index++] = ((unsigned long *) &priv->port_stats)[i]; + for (i = 0; i < priv->tx_ring_num; i++) { + data[index++] = priv->tx_ring[i].packets; + data[index++] = priv->tx_ring[i].bytes; + } + for (i = 0; i < priv->rx_ring_num; i++) { + data[index++] = priv->rx_ring[i].packets; + data[index++] = priv->rx_ring[i].bytes; + } + for (i = 0; i < NUM_PKT_STATS; i++) + data[index++] = ((unsigned long *) &priv->pkstats)[i]; + spin_unlock_bh(&priv->stats_lock); + +} + +static void mlx4_en_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int index = 0; + int i; + + if (stringset != ETH_SS_STATS) + return; + + /* Add main counters */ + for (i = 0; i < NUM_MAIN_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); + for (i = 0; i < NUM_PORT_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, + main_strings[i + NUM_MAIN_STATS]); + for (i = 0; i < priv->tx_ring_num; i++) { + sprintf(data + (index++) * ETH_GSTRING_LEN, + "tx%d_packets", i); + sprintf(data + (index++) * ETH_GSTRING_LEN, + "tx%d_bytes", i); + } + for (i = 0; i < priv->rx_ring_num; i++) { + sprintf(data + (index++) * ETH_GSTRING_LEN, + "rx%d_packets", i); + sprintf(data + (index++) * ETH_GSTRING_LEN, + "rx%d_bytes", i); + } + for (i = 0; i < NUM_PKT_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, + main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); +} + +static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->autoneg = AUTONEG_DISABLE; + cmd->supported = SUPPORTED_10000baseT_Full; + cmd->advertising = SUPPORTED_10000baseT_Full; + if (netif_carrier_ok(dev)) { + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + } else { + cmd->speed = -1; + cmd->duplex = -1; + } + return 0; +} + +static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + if ((cmd->autoneg == AUTONEG_ENABLE) || + (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL)) + return -EINVAL; + + /* Nothing to change */ + return 0; +} + +static int mlx4_en_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + coal->tx_coalesce_usecs = 0; + coal->tx_max_coalesced_frames = 0; + coal->rx_coalesce_usecs = priv->rx_usecs; + coal->rx_max_coalesced_frames = priv->rx_frames; + + coal->pkt_rate_low = priv->pkt_rate_low; + coal->rx_coalesce_usecs_low = priv->rx_usecs_low; + coal->pkt_rate_high = priv->pkt_rate_high; + coal->rx_coalesce_usecs_high = priv->rx_usecs_high; + coal->rate_sample_interval = priv->sample_interval; + coal->use_adaptive_rx_coalesce = priv->adaptive_rx_coal; + return 0; +} + +static int mlx4_en_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int err, i; + + priv->rx_frames = (coal->rx_max_coalesced_frames == + MLX4_EN_AUTO_CONF) ? + MLX4_EN_RX_COAL_TARGET / + priv->dev->mtu + 1 : + coal->rx_max_coalesced_frames; + priv->rx_usecs = (coal->rx_coalesce_usecs == + MLX4_EN_AUTO_CONF) ? + MLX4_EN_RX_COAL_TIME : + coal->rx_coalesce_usecs; + + /* Set adaptive coalescing params */ + priv->pkt_rate_low = coal->pkt_rate_low; + priv->rx_usecs_low = coal->rx_coalesce_usecs_low; + priv->pkt_rate_high = coal->pkt_rate_high; + priv->rx_usecs_high = coal->rx_coalesce_usecs_high; + priv->sample_interval = coal->rate_sample_interval; + priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce; + priv->last_moder_time = MLX4_EN_AUTO_CONF; + if (priv->adaptive_rx_coal) + return 0; + + for (i = 0; i < priv->rx_ring_num; i++) { + priv->rx_cq[i].moder_cnt = priv->rx_frames; + priv->rx_cq[i].moder_time = priv->rx_usecs; + err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]); + if (err) + return err; + } + return 0; +} + +static int mlx4_en_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + priv->prof->tx_pause = pause->tx_pause != 0; + priv->prof->rx_pause = pause->rx_pause != 0; + err = mlx4_SET_PORT_general(mdev->dev, priv->port, + priv->rx_skb_size + ETH_FCS_LEN, + priv->prof->tx_pause, + priv->prof->tx_ppp, + priv->prof->rx_pause, + priv->prof->rx_ppp); + if (err) + en_err(priv, "Failed setting pause params\n"); + + return err; +} + +static void mlx4_en_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + pause->tx_pause = priv->prof->tx_pause; + pause->rx_pause = priv->prof->rx_pause; +} + +static int mlx4_en_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + u32 rx_size, tx_size; + int port_up = 0; + int err = 0; + + if (param->rx_jumbo_pending || param->rx_mini_pending) + return -EINVAL; + + rx_size = roundup_pow_of_two(param->rx_pending); + rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); + rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); + tx_size = roundup_pow_of_two(param->tx_pending); + tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); + tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); + + if (rx_size == priv->prof->rx_ring_size && + tx_size == priv->prof->tx_ring_size) + return 0; + + mutex_lock(&mdev->state_lock); + if (priv->port_up) { + port_up = 1; + mlx4_en_stop_port(dev); + } + + mlx4_en_free_resources(priv); + + priv->prof->tx_ring_size = tx_size; + priv->prof->rx_ring_size = rx_size; + + err = mlx4_en_alloc_resources(priv); + if (err) { + en_err(priv, "Failed reallocating port resources\n"); + goto out; + } + if (port_up) { + err = mlx4_en_start_port(dev); + if (err) + en_err(priv, "Failed starting port\n"); + } + +out: + mutex_unlock(&mdev->state_lock); + return err; +} + +static void mlx4_en_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + + memset(param, 0, sizeof(*param)); + param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; + param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; + param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size; + param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size; +} + +const struct ethtool_ops mlx4_en_ethtool_ops = { + .get_drvinfo = mlx4_en_get_drvinfo, + .get_settings = mlx4_en_get_settings, + .set_settings = mlx4_en_set_settings, +#ifdef NETIF_F_TSO + .get_tso = mlx4_en_get_tso, + .set_tso = mlx4_en_set_tso, +#endif + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_link = ethtool_op_get_link, + .get_rx_csum = mlx4_en_get_rx_csum, + .set_rx_csum = mlx4_en_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_ipv6_csum, + .get_strings = mlx4_en_get_strings, + .get_sset_count = mlx4_en_get_sset_count, + .get_ethtool_stats = mlx4_en_get_ethtool_stats, + .get_wol = mlx4_en_get_wol, + .get_msglevel = mlx4_en_get_msglevel, + .set_msglevel = mlx4_en_set_msglevel, + .get_coalesce = mlx4_en_get_coalesce, + .set_coalesce = mlx4_en_set_coalesce, + .get_pauseparam = mlx4_en_get_pauseparam, + .set_pauseparam = mlx4_en_set_pauseparam, + .get_ringparam = mlx4_en_get_ringparam, + .set_ringparam = mlx4_en_set_ringparam, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, +}; + + + + + diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c deleted file mode 100644 index 91d8116..0000000 --- a/drivers/net/mlx4/en_params.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2007 Mellanox Technologies. 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 - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 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 -#include -#include - -#include "mlx4_en.h" -#include "en_port.h" - - -static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv) -{ - int i; - - priv->port_stats.lro_aggregated = 0; - priv->port_stats.lro_flushed = 0; - priv->port_stats.lro_no_desc = 0; - - for (i = 0; i < priv->rx_ring_num; i++) { - priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated; - priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed; - priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc; - } -} - -static void -mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - - sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); - strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); - sprintf(drvinfo->fw_version, "%d.%d.%d", - (u16) (mdev->dev->caps.fw_ver >> 32), - (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff), - (u16) (mdev->dev->caps.fw_ver & 0xffff)); - strncpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), 32); - drvinfo->n_stats = 0; - drvinfo->regdump_len = 0; - drvinfo->eedump_len = 0; -} - -static u32 mlx4_en_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -static int mlx4_en_set_tso(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - if (data) { - if (!priv->mdev->LSO_support) - return -EPERM; - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - return 0; -} - -static u32 mlx4_en_get_rx_csum(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - return priv->rx_csum; -} - -static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - priv->rx_csum = (data != 0); - return 0; -} - -static const char main_strings[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", - "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", - "rx_length_errors", "rx_over_errors", "rx_crc_errors", - "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", - "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", - "tx_heartbeat_errors", "tx_window_errors", - - /* port statistics */ - "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets", - "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", - "rx_csum_good", "rx_csum_none", "tx_chksum_offload", - - /* packet statistics */ - "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3", - "rx_prio_4", "rx_prio_5", "rx_prio_6", "rx_prio_7", "tx_prio_0", - "tx_prio_1", "tx_prio_2", "tx_prio_3", "tx_prio_4", "tx_prio_5", - "tx_prio_6", "tx_prio_7", -}; -#define NUM_MAIN_STATS 21 -#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) - -static u32 mlx4_en_get_msglevel(struct net_device *dev) -{ - return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; -} - -static void mlx4_en_set_msglevel(struct net_device *dev, u32 val) -{ - ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable = val; -} - -static void mlx4_en_get_wol(struct net_device *netdev, - struct ethtool_wolinfo *wol) -{ - wol->supported = 0; - wol->wolopts = 0; - - return; -} - -static int mlx4_en_get_sset_count(struct net_device *dev, int sset) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - if (sset != ETH_SS_STATS) - return -EOPNOTSUPP; - - return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2; -} - -static void mlx4_en_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, uint64_t *data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int index = 0; - int i; - - spin_lock_bh(&priv->stats_lock); - - mlx4_en_update_lro_stats(priv); - - for (i = 0; i < NUM_MAIN_STATS; i++) - data[index++] = ((unsigned long *) &priv->stats)[i]; - for (i = 0; i < NUM_PORT_STATS; i++) - data[index++] = ((unsigned long *) &priv->port_stats)[i]; - for (i = 0; i < priv->tx_ring_num; i++) { - data[index++] = priv->tx_ring[i].packets; - data[index++] = priv->tx_ring[i].bytes; - } - for (i = 0; i < priv->rx_ring_num; i++) { - data[index++] = priv->rx_ring[i].packets; - data[index++] = priv->rx_ring[i].bytes; - } - for (i = 0; i < NUM_PKT_STATS; i++) - data[index++] = ((unsigned long *) &priv->pkstats)[i]; - spin_unlock_bh(&priv->stats_lock); - -} - -static void mlx4_en_get_strings(struct net_device *dev, - uint32_t stringset, uint8_t *data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int index = 0; - int i; - - if (stringset != ETH_SS_STATS) - return; - - /* Add main counters */ - for (i = 0; i < NUM_MAIN_STATS; i++) - strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); - for (i = 0; i < NUM_PORT_STATS; i++) - strcpy(data + (index++) * ETH_GSTRING_LEN, - main_strings[i + NUM_MAIN_STATS]); - for (i = 0; i < priv->tx_ring_num; i++) { - sprintf(data + (index++) * ETH_GSTRING_LEN, - "tx%d_packets", i); - sprintf(data + (index++) * ETH_GSTRING_LEN, - "tx%d_bytes", i); - } - for (i = 0; i < priv->rx_ring_num; i++) { - sprintf(data + (index++) * ETH_GSTRING_LEN, - "rx%d_packets", i); - sprintf(data + (index++) * ETH_GSTRING_LEN, - "rx%d_bytes", i); - } - for (i = 0; i < NUM_PKT_STATS; i++) - strcpy(data + (index++) * ETH_GSTRING_LEN, - main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); -} - -static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - cmd->autoneg = AUTONEG_DISABLE; - cmd->supported = SUPPORTED_10000baseT_Full; - cmd->advertising = SUPPORTED_10000baseT_Full; - if (netif_carrier_ok(dev)) { - cmd->speed = SPEED_10000; - cmd->duplex = DUPLEX_FULL; - } else { - cmd->speed = -1; - cmd->duplex = -1; - } - return 0; -} - -static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - if ((cmd->autoneg == AUTONEG_ENABLE) || - (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL)) - return -EINVAL; - - /* Nothing to change */ - return 0; -} - -static int mlx4_en_get_coalesce(struct net_device *dev, - struct ethtool_coalesce *coal) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - coal->tx_coalesce_usecs = 0; - coal->tx_max_coalesced_frames = 0; - coal->rx_coalesce_usecs = priv->rx_usecs; - coal->rx_max_coalesced_frames = priv->rx_frames; - - coal->pkt_rate_low = priv->pkt_rate_low; - coal->rx_coalesce_usecs_low = priv->rx_usecs_low; - coal->pkt_rate_high = priv->pkt_rate_high; - coal->rx_coalesce_usecs_high = priv->rx_usecs_high; - coal->rate_sample_interval = priv->sample_interval; - coal->use_adaptive_rx_coalesce = priv->adaptive_rx_coal; - return 0; -} - -static int mlx4_en_set_coalesce(struct net_device *dev, - struct ethtool_coalesce *coal) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int err, i; - - priv->rx_frames = (coal->rx_max_coalesced_frames == - MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TARGET / - priv->dev->mtu + 1 : - coal->rx_max_coalesced_frames; - priv->rx_usecs = (coal->rx_coalesce_usecs == - MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TIME : - coal->rx_coalesce_usecs; - - /* Set adaptive coalescing params */ - priv->pkt_rate_low = coal->pkt_rate_low; - priv->rx_usecs_low = coal->rx_coalesce_usecs_low; - priv->pkt_rate_high = coal->pkt_rate_high; - priv->rx_usecs_high = coal->rx_coalesce_usecs_high; - priv->sample_interval = coal->rate_sample_interval; - priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce; - priv->last_moder_time = MLX4_EN_AUTO_CONF; - if (priv->adaptive_rx_coal) - return 0; - - for (i = 0; i < priv->rx_ring_num; i++) { - priv->rx_cq[i].moder_cnt = priv->rx_frames; - priv->rx_cq[i].moder_time = priv->rx_usecs; - err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]); - if (err) - return err; - } - return 0; -} - -static int mlx4_en_set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *pause) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - int err; - - priv->prof->tx_pause = pause->tx_pause != 0; - priv->prof->rx_pause = pause->rx_pause != 0; - err = mlx4_SET_PORT_general(mdev->dev, priv->port, - priv->rx_skb_size + ETH_FCS_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - if (err) - en_err(priv, "Failed setting pause params\n"); - - return err; -} - -static void mlx4_en_get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *pause) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - pause->tx_pause = priv->prof->tx_pause; - pause->rx_pause = priv->prof->rx_pause; -} - -static int mlx4_en_set_ringparam(struct net_device *dev, - struct ethtool_ringparam *param) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - u32 rx_size, tx_size; - int port_up = 0; - int err = 0; - - if (param->rx_jumbo_pending || param->rx_mini_pending) - return -EINVAL; - - rx_size = roundup_pow_of_two(param->rx_pending); - rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); - rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); - tx_size = roundup_pow_of_two(param->tx_pending); - tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); - tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); - - if (rx_size == priv->prof->rx_ring_size && - tx_size == priv->prof->tx_ring_size) - return 0; - - mutex_lock(&mdev->state_lock); - if (priv->port_up) { - port_up = 1; - mlx4_en_stop_port(dev); - } - - mlx4_en_free_resources(priv); - - priv->prof->tx_ring_size = tx_size; - priv->prof->rx_ring_size = rx_size; - - err = mlx4_en_alloc_resources(priv); - if (err) { - en_err(priv, "Failed reallocating port resources\n"); - goto out; - } - if (port_up) { - err = mlx4_en_start_port(dev); - if (err) - en_err(priv, "Failed starting port\n"); - } - -out: - mutex_unlock(&mdev->state_lock); - return err; -} - -static void mlx4_en_get_ringparam(struct net_device *dev, - struct ethtool_ringparam *param) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - - memset(param, 0, sizeof(*param)); - param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; - param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; - param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size; - param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size; -} - -const struct ethtool_ops mlx4_en_ethtool_ops = { - .get_drvinfo = mlx4_en_get_drvinfo, - .get_settings = mlx4_en_get_settings, - .set_settings = mlx4_en_set_settings, -#ifdef NETIF_F_TSO - .get_tso = mlx4_en_get_tso, - .set_tso = mlx4_en_set_tso, -#endif - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_link = ethtool_op_get_link, - .get_rx_csum = mlx4_en_get_rx_csum, - .set_rx_csum = mlx4_en_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .get_strings = mlx4_en_get_strings, - .get_sset_count = mlx4_en_get_sset_count, - .get_ethtool_stats = mlx4_en_get_ethtool_stats, - .get_wol = mlx4_en_get_wol, - .get_msglevel = mlx4_en_get_msglevel, - .set_msglevel = mlx4_en_set_msglevel, - .get_coalesce = mlx4_en_get_coalesce, - .set_coalesce = mlx4_en_set_coalesce, - .get_pauseparam = mlx4_en_get_pauseparam, - .set_pauseparam = mlx4_en_set_pauseparam, - .get_ringparam = mlx4_en_get_ringparam, - .set_ringparam = mlx4_en_set_ringparam, - .get_flags = ethtool_op_get_flags, - .set_flags = ethtool_op_set_flags, -}; - - - - - -- cgit v0.10.2 From 3c2fa83f9c2bbb3e91992a2fc443b7104a07e0bc Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 23:22:18 +0000 Subject: mlx4_en: Work with part of the ports. If the initialization of one of the ports failed, there is no need to fail the other one as well. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 23955d8..b510000 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -248,28 +248,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev) /* Create a netdev for each port */ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { mlx4_info(mdev, "Activating port:%d\n", i); - if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) { + if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) mdev->pndev[i] = NULL; - goto err_free_netdev; - } } return mdev; - -err_free_netdev: - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - if (mdev->pndev[i]) - mlx4_en_destroy_netdev(mdev->pndev[i]); - } - - mutex_lock(&mdev->state_lock); - mdev->device_up = false; - mutex_unlock(&mdev->state_lock); - flush_workqueue(mdev->workqueue); - - /* Stop event queue before we drop down to release shared SW state */ - destroy_workqueue(mdev->workqueue); - err_mr: mlx4_mr_free(dev, &mdev->mr); err_uar: -- cgit v0.10.2 From 3db36fb2c88d68ee28d20845d5bb805ea9a7f6d8 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 23:23:13 +0000 Subject: mlx4_en: Coalescing target is equal for all mtu's The interrupt moderation should not depend on number of incoming bytes, but on number of incoming packets. The previous scheme caused very high interrupts rate for small messages when big MTU was configured. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index 91d8116..091f990 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -268,8 +268,7 @@ static int mlx4_en_set_coalesce(struct net_device *dev, priv->rx_frames = (coal->rx_max_coalesced_frames == MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TARGET / - priv->dev->mtu + 1 : + MLX4_EN_RX_COAL_TARGET : coal->rx_max_coalesced_frames; priv->rx_usecs = (coal->rx_coalesce_usecs == MLX4_EN_AUTO_CONF) ? diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index fea65e7..16a634f 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -372,7 +372,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) * satisfy our coelsing target. * - moder_time is set to a fixed value. */ - priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1; + priv->rx_frames = MLX4_EN_RX_COAL_TARGET; priv->rx_usecs = MLX4_EN_RX_COAL_TIME; en_dbg(INTR, priv, "Default coalesing params for mtu:%d - " "rx_frames:%d rx_usecs:%d\n", diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 174ae86..fcbfcfc 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -143,8 +143,8 @@ enum { #define MLX4_EN_DEF_TX_RING_SIZE 1024 #define MLX4_EN_DEF_RX_RING_SIZE 1024 -/* Target number of bytes to coalesce with interrupt moderation */ -#define MLX4_EN_RX_COAL_TARGET 0x20000 +/* Target number of packets to coalesce with interrupt moderation */ +#define MLX4_EN_RX_COAL_TARGET 44 #define MLX4_EN_RX_COAL_TIME 0x10 #define MLX4_EN_TX_COAL_PKTS 5 -- cgit v0.10.2 From f813cad836ab14b764cfe76f42a3b50bb9677b30 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 23:24:07 +0000 Subject: mlx4_en: multiqueue support By default the driver opens 8 TX queues (defined by MLX4_EN_NUM_TX_RINGS). If the driver is configured to support Per Priority Flow Control, we open 8 additional TX rings. dev->real_num_tx_queues is always set to be MLX4_EN_NUM_TX_RINGS. The mlx4_en_select_queue() function uses standard hashing (skb_tx_hash) in case that PPFC is not supported or the skb contain a vlan tag, otherwise the queue is selected according to vlan priority. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index b510000..9ed4a15 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -93,13 +93,8 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->prof[i].tx_ppp = pfctx; params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - } - if (pfcrx || pfctx) { - params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM; - params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM; - } else { - params->prof[1].tx_ring_num = 1; - params->prof[2].tx_ring_num = 1; + params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS + + (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS; } return 0; diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 16a634f..37e4d30 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -934,6 +934,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_open = mlx4_en_open, .ndo_stop = mlx4_en_close, .ndo_start_xmit = mlx4_en_xmit, + .ndo_select_queue = mlx4_en_select_queue, .ndo_get_stats = mlx4_en_get_stats, .ndo_set_multicast_list = mlx4_en_set_multicast, .ndo_set_mac_address = mlx4_en_set_mac, @@ -956,7 +957,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, int i; int err; - dev = alloc_etherdev(sizeof(struct mlx4_en_priv)); + dev = alloc_etherdev_mq(sizeof(struct mlx4_en_priv), prof->tx_ring_num); if (dev == NULL) { mlx4_err(mdev, "Net device allocation failed\n"); return -ENOMEM; @@ -1018,14 +1019,12 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, } priv->allocated = 1; - /* Populate Tx priority mappings */ - mlx4_en_set_prio_map(priv, priv->tx_prio_map, prof->tx_ring_num); - /* * Initialize netdev entry points */ dev->netdev_ops = &mlx4_netdev_ops; dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; + dev->real_num_tx_queues = MLX4_EN_NUM_TX_RINGS; SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops); diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 95703f9..3719d1a 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -297,34 +297,6 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) return cnt; } -void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num) -{ - int block = 8 / ring_num; - int extra = 8 - (block * ring_num); - int num = 0; - u16 ring = 1; - int prio; - - if (ring_num == 1) { - for (prio = 0; prio < 8; prio++) - prio_map[prio] = 0; - return; - } - - for (prio = 0; prio < 8; prio++) { - if (extra && (num == block + 1)) { - ring++; - num = 0; - extra--; - } else if (!extra && (num == block)) { - ring++; - num = 0; - } - prio_map[prio] = ring; - en_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring); - num++; - } -} static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) { @@ -386,18 +358,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) if (unlikely(ring->blocked)) { if ((u32) (ring->prod - ring->cons) <= ring->size - HEADROOM - MAX_DESC_TXBBS) { - - /* TODO: support multiqueue netdevs. Currently, we block - * when *any* ring is full. Note that: - * - 2 Tx rings can unblock at the same time and call - * netif_wake_queue(), which is OK since this - * operation is idempotent. - * - We might wake the queue just after another ring - * stopped it. This is no big deal because the next - * transmission on that ring would stop the queue. - */ ring->blocked = 0; - netif_wake_queue(dev); + netif_tx_wake_queue(netdev_get_tx_queue(dev, cq->ring)); priv->port_stats.wake_queue++; } } @@ -616,21 +578,20 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; } -static int get_vlan_info(struct mlx4_en_priv *priv, struct sk_buff *skb, - u16 *vlan_tag) +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) { - int tx_ind; + struct mlx4_en_priv *priv = netdev_priv(dev); + u16 vlan_tag = 0; - /* Obtain VLAN information if present */ - if (priv->vlgrp && vlan_tx_tag_present(skb)) { - *vlan_tag = vlan_tx_tag_get(skb); - /* Set the Tx ring to use according to vlan priority */ - tx_ind = priv->tx_prio_map[*vlan_tag >> 13]; - } else { - *vlan_tag = 0; - tx_ind = 0; + /* If we support per priority flow control and the packet contains + * a vlan tag, send the packet to the TX ring assigned to that priority + */ + if (priv->prof->rx_ppp && priv->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13); } - return tx_ind; + + return skb_tx_hash(dev, skb); } int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) @@ -650,7 +611,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t dma; u32 index; __be32 op_own; - u16 vlan_tag; + u16 vlan_tag = 0; int i; int lso_header_size; void *fragptr; @@ -673,15 +634,16 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - tx_ind = get_vlan_info(priv, skb, &vlan_tag); + tx_ind = skb->queue_mapping; ring = &priv->tx_ring[tx_ind]; + if (priv->vlgrp && vlan_tx_tag_present(skb)) + vlan_tag = vlan_tx_tag_get(skb); /* Check available TXBBs And 2K spare for prefetch */ if (unlikely(((int)(ring->prod - ring->cons)) > ring->size - HEADROOM - MAX_DESC_TXBBS)) { - /* every full Tx ring stops queue. - * TODO: implement multi-queue support (per-queue stop) */ - netif_stop_queue(dev); + /* every full Tx ring stops queue */ + netif_tx_stop_queue(netdev_get_tx_queue(dev, tx_ind)); ring->blocked = 1; priv->port_stats.queue_stopped++; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index fcbfcfc..4de8db0 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -139,8 +139,10 @@ enum { #define MLX4_EN_MIN_RX_SIZE (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES) #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) -#define MLX4_EN_TX_RING_NUM 9 -#define MLX4_EN_DEF_TX_RING_SIZE 1024 +#define MLX4_EN_SMALL_PKT_SIZE 64 +#define MLX4_EN_NUM_TX_RINGS 8 +#define MLX4_EN_NUM_PPP_RINGS 8 +#define MLX4_EN_DEF_TX_RING_SIZE 512 #define MLX4_EN_DEF_RX_RING_SIZE 1024 /* Target number of packets to coalesce with interrupt moderation */ @@ -478,7 +480,6 @@ struct mlx4_en_priv { int base_qpn; struct mlx4_en_rss_map rss_map; - u16 tx_prio_map[8]; u32 flags; #define MLX4_EN_FLAG_PROMISC 0x1 u32 tx_ring_num; @@ -526,6 +527,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_poll_tx_cq(unsigned long data); void mlx4_en_tx_irq(struct mlx4_cq *mcq); +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, @@ -560,7 +562,6 @@ void mlx4_en_calc_rx_buf(struct net_device *dev); void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, struct mlx4_en_rss_map *rss_map, int num_entries, int num_rings); -void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num); int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); -- cgit v0.10.2 From e486973e9c1477bf2be13c3883ada9ee87222e72 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 23:28:29 +0000 Subject: mlx4_en: Added vlan_features support Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 37e4d30..0a7e78a 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -1038,7 +1038,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, * Set driver features */ dev->features |= NETIF_F_SG; + dev->vlan_features |= NETIF_F_SG; dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; dev->features |= NETIF_F_HIGHDMA; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | @@ -1048,6 +1050,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (mdev->LSO_support) { dev->features |= NETIF_F_TSO; dev->features |= NETIF_F_TSO6; + dev->vlan_features |= NETIF_F_TSO; + dev->vlan_features |= NETIF_F_TSO6; } mdev->pndev[port] = dev; -- cgit v0.10.2 From d455e5b165a367a628110ec2d18807ea10052cd1 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 1 Jun 2009 23:29:42 +0000 Subject: mlx4_en: Updated driver version Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 4de8db0..d43a9e4 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -49,8 +49,8 @@ #include "en_port.h" #define DRV_NAME "mlx4_en" -#define DRV_VERSION "1.4.0" -#define DRV_RELDATE "Sep 2008" +#define DRV_VERSION "1.4.1.1" +#define DRV_RELDATE "June 2009" #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) -- cgit v0.10.2 From 874ab9233eeddb85fd2dd85131c145bde75da39a Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 2 Jun 2009 13:58:56 +0200 Subject: netfilter: nf_ct_tcp: TCP simultaneous open support The patch below adds supporting TCP simultaneous open to conntrack. The unused LISTEN state is replaced by a new state (SYN_SENT2) denoting the second SYN sent from the reply direction in the new case. The state table is updated and the function tcp_in_window is modified to handle simultaneous open. The functionality can fairly easily be tested by socat. A sample tcpdump recording 23:21:34.244733 IP (tos 0x0, ttl 64, id 49224, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.254.2020 > 192.168.0.1.2020: S, cksum 0xe75f (correct), 3383710133:3383710133(0) win 5840 23:21:34.244783 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40) 192.168.0.1.2020 > 192.168.0.254.2020: R, cksum 0x0253 (correct), 0:0(0) ack 3383710134 win 0 23:21:36.038680 IP (tos 0x0, ttl 64, id 28092, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.1.2020 > 192.168.0.254.2020: S, cksum 0x704b (correct), 2634546729:2634546729(0) win 5840 23:21:36.038777 IP (tos 0x0, ttl 64, id 49225, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.254.2020 > 192.168.0.1.2020: S, cksum 0xb179 (correct), 3383710133:3383710133(0) ack 2634546730 win 5840 23:21:36.038847 IP (tos 0x0, ttl 64, id 28093, offset 0, flags [DF], proto TCP (6), length 52) 192.168.0.1.2020 > 192.168.0.254.2020: ., cksum 0xebad (correct), ack 3383710134 win 2920 and the corresponding netlink events: [NEW] tcp 6 120 SYN_SENT src=192.168.0.254 dst=192.168.0.1 sport=2020 dport=2020 [UNREPLIED] src=192.168.0.1 dst=192.168.0.254 sport=2020 dport=2020 [UPDATE] tcp 6 120 LISTEN src=192.168.0.254 dst=192.168.0.1 sport=2020 dport=2020 src=192.168.0.1 dst=192.168.0.254 sport=2020 dport=2020 [UPDATE] tcp 6 60 SYN_RECV src=192.168.0.254 dst=192.168.0.1 sport=2020 dport=2020 src=192.168.0.1 dst=192.168.0.254 sport=2020 dport=2020 [UPDATE] tcp 6 432000 ESTABLISHED src=192.168.0.254 dst=192.168.0.1 sport=2020 dport=2020 src=192.168.0.1 dst=192.168.0.254 sport=2020 dport=2020 [ASSURED] The RST packet was dropped in the raw table, thus it did not reach conntrack. nfnetlink_conntrack is unpatched so it shows the new SYN_SENT2 state as the old unused LISTEN. With TCP simultaneous open support we satisfy REQ-2 in RFC 5382 ;-) . Additional minor correction in this patch is that in order to catch uninitialized reply directions, "td_maxwin == 0" is used instead of "td_end == 0" because the former can't be true except in uninitialized state while td_end may accidentally be equal to zero in the mid of a connection. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h index 3066789..74c27ca 100644 --- a/include/linux/netfilter/nf_conntrack_tcp.h +++ b/include/linux/netfilter/nf_conntrack_tcp.h @@ -15,7 +15,8 @@ enum tcp_conntrack { TCP_CONNTRACK_LAST_ACK, TCP_CONNTRACK_TIME_WAIT, TCP_CONNTRACK_CLOSE, - TCP_CONNTRACK_LISTEN, + TCP_CONNTRACK_LISTEN, /* obsolete */ +#define TCP_CONNTRACK_SYN_SENT2 TCP_CONNTRACK_LISTEN TCP_CONNTRACK_MAX, TCP_CONNTRACK_IGNORE }; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index b5ccf2b..4c7f6f0 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -59,7 +59,7 @@ static const char *const tcp_conntrack_names[] = { "LAST_ACK", "TIME_WAIT", "CLOSE", - "LISTEN" + "SYN_SENT2", }; #define SECS * HZ @@ -82,6 +82,7 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { [TCP_CONNTRACK_LAST_ACK] = 30 SECS, [TCP_CONNTRACK_TIME_WAIT] = 2 MINS, [TCP_CONNTRACK_CLOSE] = 10 SECS, + [TCP_CONNTRACK_SYN_SENT2] = 2 MINS, }; #define sNO TCP_CONNTRACK_NONE @@ -93,7 +94,7 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { #define sLA TCP_CONNTRACK_LAST_ACK #define sTW TCP_CONNTRACK_TIME_WAIT #define sCL TCP_CONNTRACK_CLOSE -#define sLI TCP_CONNTRACK_LISTEN +#define sS2 TCP_CONNTRACK_SYN_SENT2 #define sIV TCP_CONNTRACK_MAX #define sIG TCP_CONNTRACK_IGNORE @@ -123,6 +124,7 @@ enum tcp_bit_set { * * NONE: initial state * SYN_SENT: SYN-only packet seen + * SYN_SENT2: SYN-only packet seen from reply dir, simultaneous open * SYN_RECV: SYN-ACK packet seen * ESTABLISHED: ACK packet seen * FIN_WAIT: FIN packet seen @@ -131,26 +133,24 @@ enum tcp_bit_set { * TIME_WAIT: last ACK seen * CLOSE: closed connection (RST) * - * LISTEN state is not used. - * * Packets marked as IGNORED (sIG): * if they may be either invalid or valid * and the receiver may send back a connection * closing RST or a SYN/ACK. * * Packets marked as INVALID (sIV): - * if they are invalid - * or we do not support the request (simultaneous open) + * if we regard them as truly invalid packets */ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { { /* ORIGINAL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sS2 }, /* * sNO -> sSS Initialize a new connection * sSS -> sSS Retransmitted SYN - * sSR -> sIG Late retransmitted SYN? + * sS2 -> sS2 Late retransmitted SYN + * sSR -> sIG * sES -> sIG Error: SYNs in window outside the SYN_SENT state * are errors. Receiver will reply with RST * and close the connection. @@ -161,22 +161,30 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sSS Reopened connection (RFC 1122). * sCL -> sSS */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*synack*/ { sIV, sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, /* - * A SYN/ACK from the client is always invalid: - * - either it tries to set up a simultaneous open, which is - * not supported; - * - or the firewall has just been inserted between the two hosts - * during the session set-up. The SYN will be retransmitted - * by the true client (or it'll time out). + * sNO -> sIV Too late and no reason to do anything + * sSS -> sIV Client can't send SYN and then SYN/ACK + * sS2 -> sSR SYN/ACK sent to SYN2 in simultaneous open + * sSR -> sIG + * sES -> sIG Error: SYNs in window outside the SYN_SENT state + * are errors. Receiver will reply with RST + * and close the connection. + * Or we are not in sync and hold a dead connection. + * sFW -> sIG + * sCW -> sIG + * sLA -> sIG + * sTW -> sIG + * sCL -> sIG */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, /* * sNO -> sIV Too late and no reason to do anything... * sSS -> sIV Client migth not send FIN in this state: * we enforce waiting for a SYN/ACK reply first. + * sS2 -> sIV * sSR -> sFW Close started. * sES -> sFW * sFW -> sLA FIN seen in both directions, waiting for @@ -187,11 +195,12 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, /* * sNO -> sES Assumed. * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. + * sS2 -> sIV * sSR -> sES Established state is reached. * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. @@ -200,29 +209,31 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW Retransmitted last ACK. Remain in the same state. * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } }, { /* REPLY */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*syn*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sS2 }, /* * sNO -> sIV Never reached. - * sSS -> sIV Simultaneous open, not supported - * sSR -> sIV Simultaneous open, not supported. - * sES -> sIV Server may not initiate a connection. + * sSS -> sS2 Simultaneous open + * sS2 -> sS2 Retransmitted simultaneous SYN + * sSR -> sIV Invalid SYN packets sent by the server + * sES -> sIV * sFW -> sIV * sCW -> sIV * sLA -> sIV * sTW -> sIV Reopened connection, but server may not do it. * sCL -> sIV */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, /* * sSS -> sSR Standard open. + * sS2 -> sSR Simultaneous open * sSR -> sSR Retransmitted SYN/ACK. * sES -> sIG Late retransmitted SYN/ACK? * sFW -> sIG Might be SYN/ACK answering ignored SYN @@ -231,10 +242,11 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sIG * sCL -> sIG */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, /* * sSS -> sIV Server might not send FIN in this state. + * sS2 -> sIV * sSR -> sFW Close started. * sES -> sFW * sFW -> sLA FIN seen in both directions. @@ -243,10 +255,11 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIG }, /* * sSS -> sIG Might be a half-open connection. + * sS2 -> sIG * sSR -> sSR Might answer late resent SYN. * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. @@ -255,8 +268,8 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW Retransmitted last ACK. * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } } }; @@ -521,13 +534,14 @@ static bool tcp_in_window(const struct nf_conn *ct, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); - if (sender->td_end == 0) { + if (sender->td_maxwin == 0) { /* * Initialize sender data. */ - if (tcph->syn && tcph->ack) { + if (tcph->syn) { /* - * Outgoing SYN-ACK in reply to a SYN. + * SYN-ACK in reply to a SYN + * or SYN from reply direction in simultaneous open. */ sender->td_end = sender->td_maxend = end; @@ -543,6 +557,9 @@ static bool tcp_in_window(const struct nf_conn *ct, && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) sender->td_scale = receiver->td_scale = 0; + if (!tcph->ack) + /* Simultaneous open */ + return true; } else { /* * We are in the middle of a connection, @@ -1068,7 +1085,7 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.tcp.seen[1].td_end = 0; ct->proto.tcp.seen[1].td_maxend = 0; - ct->proto.tcp.seen[1].td_maxwin = 1; + ct->proto.tcp.seen[1].td_maxwin = 0; ct->proto.tcp.seen[1].td_scale = 0; /* tcp_packet will set them */ @@ -1310,6 +1327,13 @@ static struct ctl_table tcp_compat_sysctl_table[] = { .proc_handler = proc_dointvec_jiffies, }, { + .procname = "ip_conntrack_tcp_timeout_syn_sent2", + .data = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT2], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { .procname = "ip_conntrack_tcp_timeout_syn_recv", .data = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV], .maxlen = sizeof(unsigned int), -- cgit v0.10.2 From f49c857ff20a660850bf8014716d0df6175e1883 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:03:33 +0200 Subject: netfilter: nfnetlink: cleanup for nfnetlink_rcv_msg() function This patch cleans up the message handling path in two aspects: * it uses NLMSG_LENGTH() instead of NLMSG_SPACE() like rtnetlink does in this case to check if there is enough room for the Netlink/nfnetlink headers. No need to check for the padding room. * it removes a redundant header size checking that has been already do at the beginning of the function. Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b8ab37a..9dbd570 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -136,7 +136,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EPERM; /* All the messages must at least contain nfgenmsg */ - if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg))) return 0; type = nlh->nlmsg_type; @@ -160,19 +160,14 @@ replay: { int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); - u_int16_t attr_count = ss->cb[cb_id].attr_count; - struct nlattr *cda[attr_count+1]; - - if (likely(nlh->nlmsg_len >= min_len)) { - struct nlattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - err = nla_parse(cda, attr_count, attr, attrlen, - ss->cb[cb_id].policy); - if (err < 0) - return err; - } else - return -EINVAL; + struct nlattr *cda[ss->cb[cb_id].attr_count + 1]; + struct nlattr *attr = (void *)nlh + min_len; + int attrlen = nlh->nlmsg_len - min_len; + + err = nla_parse(cda, ss->cb[cb_id].attr_count, + attr, attrlen, ss->cb[cb_id].policy); + if (err < 0) + return err; err = nc->call(nfnl, skb, nlh, cda); if (err == -EAGAIN) -- cgit v0.10.2 From 8b0a231d4d6336baf10f13b6142fd5c1f628247e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:03:34 +0200 Subject: netfilter: ctnetlink: remove nowait parameter from *fill_info() This patch is a cleanup, it removes the `nowait' parameter from all *fill_info() function since it is always set to one. Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index c523f0b..2d7d69f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -350,8 +350,7 @@ nla_put_failure: static int ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, - int event, int nowait, - const struct nf_conn *ct) + int event, const struct nf_conn *ct) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; @@ -362,7 +361,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); - nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; + nlh->nlmsg_flags = pid ? NLM_F_MULTI : 0; nfmsg->nfgen_family = nf_ct_l3num(ct); nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -637,8 +636,7 @@ restart: } if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, - IPCTNL_MSG_CT_NEW, - 1, ct) < 0) { + IPCTNL_MSG_CT_NEW, ct) < 0) { cb->args[1] = (unsigned long)ct; goto out; } @@ -880,7 +878,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, rcu_read_lock(); err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, - IPCTNL_MSG_CT_NEW, 1, ct); + IPCTNL_MSG_CT_NEW, ct); rcu_read_unlock(); nf_ct_put(ct); if (err <= 0) @@ -1503,9 +1501,7 @@ nla_put_failure: static int ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, - int event, - int nowait, - const struct nf_conntrack_expect *exp) + int event, const struct nf_conntrack_expect *exp) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; @@ -1515,7 +1511,7 @@ ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); - nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; + nlh->nlmsg_flags = pid ? NLM_F_MULTI : 0; nfmsg->nfgen_family = exp->tuple.src.l3num; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -1617,10 +1613,11 @@ restart: continue; cb->args[1] = 0; } - if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, + if (ctnetlink_exp_fill_info(skb, + NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, - 1, exp) < 0) { + exp) < 0) { if (!atomic_inc_not_zero(&exp->use)) continue; cb->args[1] = (unsigned long)exp; @@ -1689,8 +1686,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, rcu_read_lock(); err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, - nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, - 1, exp); + nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp); rcu_read_unlock(); if (err <= 0) goto free; -- cgit v0.10.2 From f2f3e38c63c58a3d39bd710039af8bbd15ecaff6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:03:35 +0200 Subject: netfilter: ctnetlink: rename tuple() by nf_ct_tuple() macro definition This patch move the internal tuple() macro definition to the header file as nf_ct_tuple(). Signed-off-by: Pablo Neira Ayuso diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 6c3f964..b909241 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -144,6 +144,8 @@ static inline u_int8_t nf_ct_protonum(const struct nf_conn *ct) return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; } +#define nf_ct_tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) + /* get master conntrack via master expectation */ #define master_ct(conntr) (conntr->master) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 2d7d69f..3553f39 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -346,8 +346,6 @@ nla_put_failure: return -1; } -#define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) - static int ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, const struct nf_conn *ct) @@ -369,14 +367,14 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); @@ -509,7 +507,8 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, if (!item->report && !nfnetlink_has_listeners(group)) return NOTIFY_DONE; - skb = ctnetlink_alloc_skb(tuple(ct, IP_CT_DIR_ORIGINAL), GFP_ATOMIC); + skb = ctnetlink_alloc_skb(nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL), + GFP_ATOMIC); if (!skb) goto errout; @@ -528,14 +527,14 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); -- cgit v0.10.2 From 96bcf938dc9637e8bb8b2c5d7885d72af5cd10af Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:07:39 +0200 Subject: netfilter: ctnetlink: use nlmsg_* helper function to build messages Replaces the old macros to build Netlink messages with the new nlmsg_*() helper functions. Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 3553f39..5c14867 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -353,13 +353,14 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; struct nlattr *nest_parms; - unsigned char *b = skb_tail_pointer(skb); + unsigned int flags = pid ? NLM_F_MULTI : 0; event |= NFNL_SUBSYS_CTNETLINK << 8; - nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = pid ? NLM_F_MULTI : 0; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = nf_ct_l3num(ct); nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -392,12 +393,12 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, ctnetlink_dump_nat_seq_adj(skb, ct) < 0) goto nla_put_failure; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; + nlmsg_end(skb, nlh); return skb->len; nlmsg_failure: nla_put_failure: - nlmsg_trim(skb, b); + nlmsg_cancel(skb, nlh); return -1; } @@ -431,7 +432,7 @@ ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp) #define NLA_TYPE_SIZE(type) nla_total_size(sizeof(type)) /* proto independant part */ - len = NLMSG_SPACE(sizeof(struct nfgenmsg)) + len = NLMSG_ALIGN(sizeof(struct nfgenmsg)) + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ @@ -471,7 +472,7 @@ ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp) len += l4proto->nla_size; rcu_read_unlock(); - return alloc_skb(len, gfp); + return nlmsg_new(len, gfp); } static int ctnetlink_conntrack_event(struct notifier_block *this, @@ -484,7 +485,6 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, struct nf_conn *ct = item->ct; struct sk_buff *skb; unsigned int type; - sk_buff_data_t b; unsigned int flags = 0, group; /* ignore our fake conntrack entry */ @@ -512,13 +512,12 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, if (!skb) goto errout; - b = skb->tail; - type |= NFNL_SUBSYS_CTNETLINK << 8; - nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, item->pid, 0, type, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = flags; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = nf_ct_l3num(ct); nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -582,12 +581,13 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, #endif rcu_read_unlock(); - nlh->nlmsg_len = skb->tail - b; + nlmsg_end(skb, nlh); nfnetlink_send(skb, item->pid, group, item->report); return NOTIFY_DONE; nla_put_failure: rcu_read_unlock(); + nlmsg_cancel(skb, nlh); nlmsg_failure: kfree_skb(skb); errout: @@ -609,7 +609,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct nf_conn *ct, *last; struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; - struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); + struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; rcu_read_lock(); @@ -789,7 +789,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; struct nf_conn *ct; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -844,7 +844,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_tuple tuple; struct nf_conn *ct; struct sk_buff *skb2 = NULL; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -869,8 +869,8 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ct = nf_ct_tuplehash_to_ctrack(h); err = -ENOMEM; - skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb2) { + skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb2 == NULL) { nf_ct_put(ct); return -ENOMEM; } @@ -1322,7 +1322,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, { struct nf_conntrack_tuple otuple, rtuple; struct nf_conntrack_tuple_hash *h = NULL; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -1504,13 +1504,14 @@ ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - unsigned char *b = skb_tail_pointer(skb); + unsigned int flags = pid ? NLM_F_MULTI : 0; event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; - nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = pid ? NLM_F_MULTI : 0; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = exp->tuple.src.l3num; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -1518,12 +1519,12 @@ ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, if (ctnetlink_exp_dump_expect(skb, exp) < 0) goto nla_put_failure; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; + nlmsg_end(skb, nlh); return skb->len; nlmsg_failure: nla_put_failure: - nlmsg_trim(skb, b); + nlmsg_cancel(skb, nlh); return -1; } @@ -1537,7 +1538,6 @@ static int ctnetlink_expect_event(struct notifier_block *this, struct nf_conntrack_expect *exp = item->exp; struct sk_buff *skb; unsigned int type; - sk_buff_data_t b; int flags = 0; if (events & IPEXP_NEW) { @@ -1550,17 +1550,16 @@ static int ctnetlink_expect_event(struct notifier_block *this, !nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) return NOTIFY_DONE; - skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb) + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (skb == NULL) goto errout; - b = skb->tail; - type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; - nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, item->pid, 0, type, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = flags; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = exp->tuple.src.l3num; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -1570,12 +1569,13 @@ static int ctnetlink_expect_event(struct notifier_block *this, goto nla_put_failure; rcu_read_unlock(); - nlh->nlmsg_len = skb->tail - b; + nlmsg_end(skb, nlh); nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report); return NOTIFY_DONE; nla_put_failure: rcu_read_unlock(); + nlmsg_cancel(skb, nlh); nlmsg_failure: kfree_skb(skb); errout: @@ -1595,7 +1595,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = &init_net; struct nf_conntrack_expect *exp, *last; - struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); + struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); struct hlist_node *n; u_int8_t l3proto = nfmsg->nfgen_family; @@ -1648,7 +1648,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; struct sk_buff *skb2; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -1679,8 +1679,8 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, } err = -ENOMEM; - skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb2) + skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb2 == NULL) goto out; rcu_read_lock(); @@ -1708,7 +1708,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_expect *exp; struct nf_conntrack_tuple tuple; struct nf_conntrack_helper *h; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct hlist_node *n, *next; u_int8_t u3 = nfmsg->nfgen_family; unsigned int i; @@ -1849,7 +1849,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, { struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; -- cgit v0.10.2 From 03b64f518a893512d32f07a10b053e558beafcaf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:08:27 +0200 Subject: netfilter: ctnetlink: cleanup message-size calculation This patch cleans up the message calculation to make it similar to rtnetlink, moreover, it removes unneeded verbose information. Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 5c14867..58fde0e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -403,76 +403,55 @@ nla_put_failure: } #ifdef CONFIG_NF_CONNTRACK_EVENTS -/* - * The general structure of a ctnetlink event is - * - * CTA_TUPLE_ORIG - * - * CTA_TUPLE_REPLY - * - * CTA_ID - * ... - * CTA_PROTOINFO - * - * CTA_TUPLE_MASTER - * - * - * Therefore the formular is - * - * size = sizeof(headers) + sizeof(generic_nlas) + 3 * sizeof(tuple_nlas) - * + sizeof(protoinfo_nlas) - */ -static struct sk_buff * -ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp) +static inline size_t +ctnetlink_proto_size(const struct nf_conn *ct) { struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; - int len; - -#define NLA_TYPE_SIZE(type) nla_total_size(sizeof(type)) - - /* proto independant part */ - len = NLMSG_ALIGN(sizeof(struct nfgenmsg)) - + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ - + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ - + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ - + 3 * NLA_TYPE_SIZE(u_int8_t) /* CTA_PROTO_NUM */ - + NLA_TYPE_SIZE(u_int32_t) /* CTA_ID */ - + NLA_TYPE_SIZE(u_int32_t) /* CTA_STATUS */ + size_t len = 0; + + rcu_read_lock(); + l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); + len += l3proto->nla_size; + + l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + len += l4proto->nla_size; + rcu_read_unlock(); + + return len; +} + +static inline size_t +ctnetlink_nlmsg_size(const struct nf_conn *ct) +{ + return NLMSG_ALIGN(sizeof(struct nfgenmsg)) + + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ + + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ + + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ + + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */ + + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */ + + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */ #ifdef CONFIG_NF_CT_ACCT - + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ - + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_PACKETS */ - + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_BYTES */ + + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ + + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */ + + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */ #endif - + NLA_TYPE_SIZE(u_int32_t) /* CTA_TIMEOUT */ - + nla_total_size(0) /* CTA_PROTOINFO */ - + nla_total_size(0) /* CTA_HELP */ - + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */ + + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */ + + nla_total_size(0) /* CTA_PROTOINFO */ + + nla_total_size(0) /* CTA_HELP */ + + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */ #ifdef CONFIG_NF_CONNTRACK_SECMARK - + NLA_TYPE_SIZE(u_int32_t) /* CTA_SECMARK */ + + nla_total_size(sizeof(u_int32_t)) /* CTA_SECMARK */ #endif #ifdef CONFIG_NF_NAT_NEEDED - + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */ - + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_POS */ - + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_BEFORE */ - + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_AFTER */ + + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */ + + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */ #endif #ifdef CONFIG_NF_CONNTRACK_MARK - + NLA_TYPE_SIZE(u_int32_t) /* CTA_MARK */ + + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */ #endif - ; - -#undef NLA_TYPE_SIZE - - rcu_read_lock(); - l3proto = __nf_ct_l3proto_find(tuple->src.l3num); - len += l3proto->nla_size; - - l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); - len += l4proto->nla_size; - rcu_read_unlock(); - - return nlmsg_new(len, gfp); + + ctnetlink_proto_size(ct) + ; } static int ctnetlink_conntrack_event(struct notifier_block *this, @@ -507,9 +486,8 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, if (!item->report && !nfnetlink_has_listeners(group)) return NOTIFY_DONE; - skb = ctnetlink_alloc_skb(nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL), - GFP_ATOMIC); - if (!skb) + skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC); + if (skb == NULL) goto errout; type |= NFNL_SUBSYS_CTNETLINK << 8; -- cgit v0.10.2 From 274d383b9c1906847a64bbb267b0183599ce86a0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:08:38 +0200 Subject: netfilter: conntrack: don't report events on module removal During the module removal there are no possible event listeners since ctnetlink must be removed before to allow removing nf_conntrack. This patch removes the event reporting for the module removal case which is not of any use in the existing code. Signed-off-by: Pablo Neira Ayuso diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b909241..2ba36dd 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -203,7 +203,7 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); extern void nf_conntrack_hash_insert(struct nf_conn *ct); -extern void nf_conntrack_flush(struct net *net, u32 pid, int report); +extern void nf_conntrack_flush_report(struct net *net, u32 pid, int report); extern bool nf_ct_get_tuplepr(const struct sk_buff *skb, unsigned int nhoff, u_int16_t l3num, diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 8020db6..f59c4ed 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1001,7 +1001,7 @@ struct __nf_ct_flush_report { int report; }; -static int kill_all(struct nf_conn *i, void *data) +static int kill_report(struct nf_conn *i, void *data) { struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data; @@ -1013,6 +1013,11 @@ static int kill_all(struct nf_conn *i, void *data) return 1; } +static int kill_all(struct nf_conn *i, void *data) +{ + return 1; +} + void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size) { if (vmalloced) @@ -1023,15 +1028,15 @@ void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size) } EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); -void nf_conntrack_flush(struct net *net, u32 pid, int report) +void nf_conntrack_flush_report(struct net *net, u32 pid, int report) { struct __nf_ct_flush_report fr = { .pid = pid, .report = report, }; - nf_ct_iterate_cleanup(net, kill_all, &fr); + nf_ct_iterate_cleanup(net, kill_report, &fr); } -EXPORT_SYMBOL_GPL(nf_conntrack_flush); +EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); static void nf_conntrack_cleanup_init_net(void) { @@ -1045,7 +1050,7 @@ static void nf_conntrack_cleanup_net(struct net *net) nf_ct_event_cache_flush(net); nf_conntrack_ecache_fini(net); i_see_dead_people: - nf_conntrack_flush(net, 0, 0); + nf_ct_iterate_cleanup(net, kill_all, NULL); if (atomic_read(&net->ct.count) != 0) { schedule(); goto i_see_dead_people; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 58fde0e..3a20de1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -777,9 +777,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else { /* Flush the whole table */ - nf_conntrack_flush(&init_net, - NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_flush_report(&init_net, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); return 0; } -- cgit v0.10.2 From 6bfea1984aea86089907caf8974513c2402a3b3d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:08:44 +0200 Subject: netfilter: conntrack: remove events flags from userspace exposed file This patch moves the event flags from linux/netfilter/nf_conntrack_common.h to net/netfilter/nf_conntrack_ecache.h. This flags are not of any use from userspace. Signed-off-by: Pablo Neira Ayuso diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index 885cbe2..a8248ee 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -75,75 +75,6 @@ enum ip_conntrack_status { IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), }; -/* Connection tracking event bits */ -enum ip_conntrack_events -{ - /* New conntrack */ - IPCT_NEW_BIT = 0, - IPCT_NEW = (1 << IPCT_NEW_BIT), - - /* Expected connection */ - IPCT_RELATED_BIT = 1, - IPCT_RELATED = (1 << IPCT_RELATED_BIT), - - /* Destroyed conntrack */ - IPCT_DESTROY_BIT = 2, - IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), - - /* Timer has been refreshed */ - IPCT_REFRESH_BIT = 3, - IPCT_REFRESH = (1 << IPCT_REFRESH_BIT), - - /* Status has changed */ - IPCT_STATUS_BIT = 4, - IPCT_STATUS = (1 << IPCT_STATUS_BIT), - - /* Update of protocol info */ - IPCT_PROTOINFO_BIT = 5, - IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), - - /* Volatile protocol info */ - IPCT_PROTOINFO_VOLATILE_BIT = 6, - IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT), - - /* New helper for conntrack */ - IPCT_HELPER_BIT = 7, - IPCT_HELPER = (1 << IPCT_HELPER_BIT), - - /* Update of helper info */ - IPCT_HELPINFO_BIT = 8, - IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT), - - /* Volatile helper info */ - IPCT_HELPINFO_VOLATILE_BIT = 9, - IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT), - - /* NAT info */ - IPCT_NATINFO_BIT = 10, - IPCT_NATINFO = (1 << IPCT_NATINFO_BIT), - - /* Counter highest bit has been set, unused */ - IPCT_COUNTER_FILLING_BIT = 11, - IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT), - - /* Mark is set */ - IPCT_MARK_BIT = 12, - IPCT_MARK = (1 << IPCT_MARK_BIT), - - /* NAT sequence adjustment */ - IPCT_NATSEQADJ_BIT = 13, - IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), - - /* Secmark is set */ - IPCT_SECMARK_BIT = 14, - IPCT_SECMARK = (1 << IPCT_SECMARK_BIT), -}; - -enum ip_conntrack_expect_events { - IPEXP_NEW_BIT = 0, - IPEXP_NEW = (1 << IPEXP_NEW_BIT), -}; - #ifdef __KERNEL__ struct ip_conntrack_stat { diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 0ff0dc6..892b8cd 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -11,6 +11,75 @@ #include #include +/* Connection tracking event bits */ +enum ip_conntrack_events +{ + /* New conntrack */ + IPCT_NEW_BIT = 0, + IPCT_NEW = (1 << IPCT_NEW_BIT), + + /* Expected connection */ + IPCT_RELATED_BIT = 1, + IPCT_RELATED = (1 << IPCT_RELATED_BIT), + + /* Destroyed conntrack */ + IPCT_DESTROY_BIT = 2, + IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), + + /* Timer has been refreshed */ + IPCT_REFRESH_BIT = 3, + IPCT_REFRESH = (1 << IPCT_REFRESH_BIT), + + /* Status has changed */ + IPCT_STATUS_BIT = 4, + IPCT_STATUS = (1 << IPCT_STATUS_BIT), + + /* Update of protocol info */ + IPCT_PROTOINFO_BIT = 5, + IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), + + /* Volatile protocol info */ + IPCT_PROTOINFO_VOLATILE_BIT = 6, + IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT), + + /* New helper for conntrack */ + IPCT_HELPER_BIT = 7, + IPCT_HELPER = (1 << IPCT_HELPER_BIT), + + /* Update of helper info */ + IPCT_HELPINFO_BIT = 8, + IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT), + + /* Volatile helper info */ + IPCT_HELPINFO_VOLATILE_BIT = 9, + IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT), + + /* NAT info */ + IPCT_NATINFO_BIT = 10, + IPCT_NATINFO = (1 << IPCT_NATINFO_BIT), + + /* Counter highest bit has been set, unused */ + IPCT_COUNTER_FILLING_BIT = 11, + IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT), + + /* Mark is set */ + IPCT_MARK_BIT = 12, + IPCT_MARK = (1 << IPCT_MARK_BIT), + + /* NAT sequence adjustment */ + IPCT_NATSEQADJ_BIT = 13, + IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), + + /* Secmark is set */ + IPCT_SECMARK_BIT = 14, + IPCT_SECMARK = (1 << IPCT_SECMARK_BIT), +}; + +enum ip_conntrack_expect_events { + IPEXP_NEW_BIT = 0, + IPEXP_NEW = (1 << IPEXP_NEW_BIT), +}; + #ifdef CONFIG_NF_CONNTRACK_EVENTS struct nf_conntrack_ecache { struct nf_conn *ct; -- cgit v0.10.2 From 17e6e4eac070607a35464ea7e2c5eceac32e5eca Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 2 Jun 2009 20:08:46 +0200 Subject: netfilter: conntrack: simplify event caching system This patch simplifies the conntrack event caching system by removing several events: * IPCT_[*]_VOLATILE, IPCT_HELPINFO and IPCT_NATINFO has been deleted since the have no clients. * IPCT_COUNTER_FILLING which is a leftover of the 32-bits counter days. * IPCT_REFRESH which is not of any use since we always include the timeout in the messages. After this patch, the existing events are: * IPCT_NEW, IPCT_RELATED and IPCT_DESTROY, that are used to identify addition and deletion of entries. * IPCT_STATUS, that notes that the status bits have changes, eg. IPS_SEEN_REPLY and IPS_ASSURED. * IPCT_PROTOINFO, that reports that internal protocol information has changed, eg. the TCP, DCCP and SCTP protocol state. * IPCT_HELPER, that a helper has been assigned or unassigned to this entry. * IPCT_MARK and IPCT_SECMARK, that reports that the mark has changed, this covers the case when a mark is set to zero. * IPCT_NATSEQADJ, to report that there's updates in the NAT sequence adjustment. Signed-off-by: Pablo Neira Ayuso diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 892b8cd..2e17a2d 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -26,52 +26,28 @@ enum ip_conntrack_events IPCT_DESTROY_BIT = 2, IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), - /* Timer has been refreshed */ - IPCT_REFRESH_BIT = 3, - IPCT_REFRESH = (1 << IPCT_REFRESH_BIT), - /* Status has changed */ - IPCT_STATUS_BIT = 4, + IPCT_STATUS_BIT = 3, IPCT_STATUS = (1 << IPCT_STATUS_BIT), /* Update of protocol info */ - IPCT_PROTOINFO_BIT = 5, + IPCT_PROTOINFO_BIT = 4, IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), - /* Volatile protocol info */ - IPCT_PROTOINFO_VOLATILE_BIT = 6, - IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT), - /* New helper for conntrack */ - IPCT_HELPER_BIT = 7, + IPCT_HELPER_BIT = 5, IPCT_HELPER = (1 << IPCT_HELPER_BIT), - /* Update of helper info */ - IPCT_HELPINFO_BIT = 8, - IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT), - - /* Volatile helper info */ - IPCT_HELPINFO_VOLATILE_BIT = 9, - IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT), - - /* NAT info */ - IPCT_NATINFO_BIT = 10, - IPCT_NATINFO = (1 << IPCT_NATINFO_BIT), - - /* Counter highest bit has been set, unused */ - IPCT_COUNTER_FILLING_BIT = 11, - IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT), - /* Mark is set */ - IPCT_MARK_BIT = 12, + IPCT_MARK_BIT = 6, IPCT_MARK = (1 << IPCT_MARK_BIT), /* NAT sequence adjustment */ - IPCT_NATSEQADJ_BIT = 13, + IPCT_NATSEQADJ_BIT = 7, IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), /* Secmark is set */ - IPCT_SECMARK_BIT = 14, + IPCT_SECMARK_BIT = 8, IPCT_SECMARK = (1 << IPCT_SECMARK_BIT), }; diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 23b2c2e..c6ab3d9 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -91,7 +91,6 @@ static int icmp_packet(struct nf_conn *ct, nf_ct_kill_acct(ct, ctinfo, skb); } else { atomic_inc(&ct->proto.icmp.count); - nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct); nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); } diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 9903227..a0acd96 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -104,7 +104,6 @@ static int icmpv6_packet(struct nf_conn *ct, nf_ct_kill_acct(ct, ctinfo, skb); } else { atomic_inc(&ct->proto.icmp.count); - nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct); nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); } diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f59c4ed..b54c234 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -398,11 +398,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) help = nfct_help(ct); if (help && help->helper) nf_conntrack_event_cache(IPCT_HELPER, ct); -#ifdef CONFIG_NF_NAT_NEEDED - if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || - test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) - nf_conntrack_event_cache(IPCT_NATINFO, ct); -#endif + nf_conntrack_event_cache(master_ct(ct) ? IPCT_RELATED : IPCT_NEW, ct); return NF_ACCEPT; @@ -807,8 +803,6 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, unsigned long extra_jiffies, int do_acct) { - int event = 0; - NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); NF_CT_ASSERT(skb); @@ -821,7 +815,6 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, /* If not in hash table, timer will not be active yet */ if (!nf_ct_is_confirmed(ct)) { ct->timeout.expires = extra_jiffies; - event = IPCT_REFRESH; } else { unsigned long newtime = jiffies + extra_jiffies; @@ -832,7 +825,6 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, && del_timer(&ct->timeout)) { ct->timeout.expires = newtime; add_timer(&ct->timeout); - event = IPCT_REFRESH; } } @@ -849,10 +841,6 @@ acct: } spin_unlock_bh(&nf_conntrack_lock); - - /* must be unlocked when calling event cache */ - if (event) - nf_conntrack_event_cache(event, ct); } EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 00fecc3..5509dd1 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -338,11 +338,9 @@ static void update_nl_seq(struct nf_conn *ct, u32 nl_seq, if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) { info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; - nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, ct); } else if (oldest != NUM_SEQ_TO_REMEMBER && after(nl_seq, info->seq_aft_nl[dir][oldest])) { info->seq_aft_nl[dir][oldest] = nl_seq; - nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, ct); } } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 3a20de1..b1b9e4f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -477,7 +477,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, type = IPCTNL_MSG_CT_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; group = NFNLGRP_CONNTRACK_NEW; - } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { + } else if (events) { type = IPCTNL_MSG_CT_NEW; group = NFNLGRP_CONNTRACK_UPDATE; } else diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 4c7f6f0..b7e8a82 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -991,7 +991,6 @@ static int tcp_packet(struct nf_conn *ct, timeout = tcp_timeouts[new_state]; write_unlock_bh(&tcp_lock); - nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct); if (new_state != old_state) nf_conntrack_event_cache(IPCT_PROTOINFO, ct); -- cgit v0.10.2 From e34d5c1a4f9919a81b4ea4591d7383245f35cb8e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 3 Jun 2009 10:32:06 +0200 Subject: netfilter: conntrack: replace notify chain by function pointer This patch removes the notify chain infrastructure and replace it by a simple function pointer. This issue has been mentioned in the mailing list several times: the use of the notify chain adds too much overhead for something that is only used by ctnetlink. This patch also changes nfnetlink_send(). It seems that gfp_any() returns GFP_KERNEL for user-context request, like those via ctnetlink, inside the RCU read-side section which is not valid. Using GFP_KERNEL is also evil since netlink may schedule(), this leads to "scheduling while atomic" bug reports. Signed-off-by: Pablo Neira Ayuso diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index c600083..2214e51 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -75,7 +75,7 @@ extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); extern int nfnetlink_has_listeners(unsigned int group); extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, - int echo); + int echo, gfp_t flags); extern void nfnetlink_set_err(u32 pid, u32 group, int error); extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 2e17a2d..1afb907 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -6,7 +6,6 @@ #define _NF_CONNTRACK_ECACHE_H #include -#include #include #include #include @@ -69,9 +68,13 @@ struct nf_ct_event { int report; }; -extern struct atomic_notifier_head nf_conntrack_chain; -extern int nf_conntrack_register_notifier(struct notifier_block *nb); -extern int nf_conntrack_unregister_notifier(struct notifier_block *nb); +struct nf_ct_event_notifier { + int (*fcn)(unsigned int events, struct nf_ct_event *item); +}; + +extern struct nf_ct_event_notifier *nf_conntrack_event_cb; +extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); +extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); extern void __nf_ct_event_cache_init(struct nf_conn *ct); @@ -97,13 +100,23 @@ nf_conntrack_event_report(enum ip_conntrack_events event, u32 pid, int report) { - struct nf_ct_event item = { - .ct = ct, - .pid = pid, - .report = report - }; - if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) - atomic_notifier_call_chain(&nf_conntrack_chain, event, &item); + struct nf_ct_event_notifier *notify; + + rcu_read_lock(); + notify = rcu_dereference(nf_conntrack_event_cb); + if (notify == NULL) + goto out_unlock; + + if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { + struct nf_ct_event item = { + .ct = ct, + .pid = pid, + .report = report + }; + notify->fcn(event, &item); + } +out_unlock: + rcu_read_unlock(); } static inline void @@ -118,9 +131,13 @@ struct nf_exp_event { int report; }; -extern struct atomic_notifier_head nf_ct_expect_chain; -extern int nf_ct_expect_register_notifier(struct notifier_block *nb); -extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb); +struct nf_exp_event_notifier { + int (*fcn)(unsigned int events, struct nf_exp_event *item); +}; + +extern struct nf_exp_event_notifier *nf_expect_event_cb; +extern int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *nb); +extern void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *nb); static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, @@ -128,12 +145,23 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, u32 pid, int report) { - struct nf_exp_event item = { - .exp = exp, - .pid = pid, - .report = report - }; - atomic_notifier_call_chain(&nf_ct_expect_chain, event, &item); + struct nf_exp_event_notifier *notify; + + rcu_read_lock(); + notify = rcu_dereference(nf_expect_event_cb); + if (notify == NULL) + goto out_unlock; + + { + struct nf_exp_event item = { + .exp = exp, + .pid = pid, + .report = report + }; + notify->fcn(event, &item); + } +out_unlock: + rcu_read_unlock(); } static inline void diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index dee4190..5516b3e 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -16,24 +16,32 @@ #include #include #include -#include #include #include #include #include -ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); -EXPORT_SYMBOL_GPL(nf_conntrack_chain); +static DEFINE_MUTEX(nf_ct_ecache_mutex); -ATOMIC_NOTIFIER_HEAD(nf_ct_expect_chain); -EXPORT_SYMBOL_GPL(nf_ct_expect_chain); +struct nf_ct_event_notifier *nf_conntrack_event_cb __read_mostly; +EXPORT_SYMBOL_GPL(nf_conntrack_event_cb); + +struct nf_exp_event_notifier *nf_expect_event_cb __read_mostly; +EXPORT_SYMBOL_GPL(nf_expect_event_cb); /* deliver cached events and clear cache entry - must be called with locally * disabled softirqs */ static inline void __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) { + struct nf_ct_event_notifier *notify; + + rcu_read_lock(); + notify = rcu_dereference(nf_conntrack_event_cb); + if (notify == NULL) + goto out_unlock; + if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) && ecache->events) { struct nf_ct_event item = { @@ -42,14 +50,15 @@ __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) .report = 0 }; - atomic_notifier_call_chain(&nf_conntrack_chain, - ecache->events, - &item); + notify->fcn(ecache->events, &item); } ecache->events = 0; nf_ct_put(ecache->ct); ecache->ct = NULL; + +out_unlock: + rcu_read_unlock(); } /* Deliver all cached events for a particular conntrack. This is called @@ -111,26 +120,68 @@ void nf_conntrack_ecache_fini(struct net *net) free_percpu(net->ct.ecache); } -int nf_conntrack_register_notifier(struct notifier_block *nb) +int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) { - return atomic_notifier_chain_register(&nf_conntrack_chain, nb); + int ret = 0; + struct nf_ct_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_conntrack_event_cb); + if (notify != NULL) { + ret = -EBUSY; + goto out_unlock; + } + rcu_assign_pointer(nf_conntrack_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + return ret; + +out_unlock: + mutex_unlock(&nf_ct_ecache_mutex); + return ret; } EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier); -int nf_conntrack_unregister_notifier(struct notifier_block *nb) +void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *new) { - return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb); + struct nf_ct_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_conntrack_event_cb); + BUG_ON(notify != new); + rcu_assign_pointer(nf_conntrack_event_cb, NULL); + mutex_unlock(&nf_ct_ecache_mutex); } EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); -int nf_ct_expect_register_notifier(struct notifier_block *nb) +int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *new) { - return atomic_notifier_chain_register(&nf_ct_expect_chain, nb); + int ret = 0; + struct nf_exp_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_expect_event_cb); + if (notify != NULL) { + ret = -EBUSY; + goto out_unlock; + } + rcu_assign_pointer(nf_expect_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + return ret; + +out_unlock: + mutex_unlock(&nf_ct_ecache_mutex); + return ret; } EXPORT_SYMBOL_GPL(nf_ct_expect_register_notifier); -int nf_ct_expect_unregister_notifier(struct notifier_block *nb) +void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new) { - return atomic_notifier_chain_unregister(&nf_ct_expect_chain, nb); + struct nf_exp_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_expect_event_cb); + BUG_ON(notify != new); + rcu_assign_pointer(nf_expect_event_cb, NULL); + mutex_unlock(&nf_ct_ecache_mutex); } EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b1b9e4f..4448b06 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -454,13 +453,12 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct) ; } -static int ctnetlink_conntrack_event(struct notifier_block *this, - unsigned long events, void *ptr) +static int +ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; struct nlattr *nest_parms; - struct nf_ct_event *item = (struct nf_ct_event *)ptr; struct nf_conn *ct = item->ct; struct sk_buff *skb; unsigned int type; @@ -468,7 +466,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, /* ignore our fake conntrack entry */ if (ct == &nf_conntrack_untracked) - return NOTIFY_DONE; + return 0; if (events & IPCT_DESTROY) { type = IPCTNL_MSG_CT_DELETE; @@ -481,10 +479,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, type = IPCTNL_MSG_CT_NEW; group = NFNLGRP_CONNTRACK_UPDATE; } else - return NOTIFY_DONE; + return 0; if (!item->report && !nfnetlink_has_listeners(group)) - return NOTIFY_DONE; + return 0; skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC); if (skb == NULL) @@ -560,8 +558,8 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, rcu_read_unlock(); nlmsg_end(skb, nlh); - nfnetlink_send(skb, item->pid, group, item->report); - return NOTIFY_DONE; + nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); + return 0; nla_put_failure: rcu_read_unlock(); @@ -570,7 +568,7 @@ nlmsg_failure: kfree_skb(skb); errout: nfnetlink_set_err(0, group, -ENOBUFS); - return NOTIFY_DONE; + return 0; } #endif /* CONFIG_NF_CONNTRACK_EVENTS */ @@ -1507,12 +1505,11 @@ nla_put_failure: } #ifdef CONFIG_NF_CONNTRACK_EVENTS -static int ctnetlink_expect_event(struct notifier_block *this, - unsigned long events, void *ptr) +static int +ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - struct nf_exp_event *item = (struct nf_exp_event *)ptr; struct nf_conntrack_expect *exp = item->exp; struct sk_buff *skb; unsigned int type; @@ -1522,11 +1519,11 @@ static int ctnetlink_expect_event(struct notifier_block *this, type = IPCTNL_MSG_EXP_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; } else - return NOTIFY_DONE; + return 0; if (!item->report && !nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) - return NOTIFY_DONE; + return 0; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (skb == NULL) @@ -1548,8 +1545,9 @@ static int ctnetlink_expect_event(struct notifier_block *this, rcu_read_unlock(); nlmsg_end(skb, nlh); - nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report); - return NOTIFY_DONE; + nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, + item->report, GFP_ATOMIC); + return 0; nla_put_failure: rcu_read_unlock(); @@ -1558,7 +1556,7 @@ nlmsg_failure: kfree_skb(skb); errout: nfnetlink_set_err(0, 0, -ENOBUFS); - return NOTIFY_DONE; + return 0; } #endif static int ctnetlink_exp_done(struct netlink_callback *cb) @@ -1864,12 +1862,12 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, } #ifdef CONFIG_NF_CONNTRACK_EVENTS -static struct notifier_block ctnl_notifier = { - .notifier_call = ctnetlink_conntrack_event, +static struct nf_ct_event_notifier ctnl_notifier = { + .fcn = ctnetlink_conntrack_event, }; -static struct notifier_block ctnl_notifier_exp = { - .notifier_call = ctnetlink_expect_event, +static struct nf_exp_event_notifier ctnl_notifier_exp = { + .fcn = ctnetlink_expect_event, }; #endif diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 9dbd570..92761a9 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -107,9 +107,10 @@ int nfnetlink_has_listeners(unsigned int group) } EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); -int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) +int nfnetlink_send(struct sk_buff *skb, u32 pid, + unsigned group, int echo, gfp_t flags) { - return nlmsg_notify(nfnl, skb, pid, group, echo, gfp_any()); + return nlmsg_notify(nfnl, skb, pid, group, echo, flags); } EXPORT_SYMBOL_GPL(nfnetlink_send); -- cgit v0.10.2 From 6e50912a442947d5fafd296ca6fdcbeb36b163ff Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 2 Jun 2009 11:28:01 +0000 Subject: e1000e: enable CRC stripping by default CRC stripping should be enabled by default but was not if it was not specified as a module parameter. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index e909f96..1342e0b1 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c @@ -427,6 +427,8 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) e1000_validate_option(&crc_stripping, &opt, adapter); if (crc_stripping == OPTION_ENABLED) adapter->flags2 |= FLAG2_CRC_STRIPPING; + } else { + adapter->flags2 |= FLAG2_CRC_STRIPPING; } } { /* Kumeran Lock Loss Workaround */ -- cgit v0.10.2 From 918d7197aa18a562eb7dc37b80a87e9ff1d7f7d9 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 2 Jun 2009 11:28:20 +0000 Subject: e1000e: do not attempt to disable smart powerdown if not supported During reset, the driver was attempting to disable the Smart Powerdown feature even if the part does not support Smart Powerdown. Check for support before attempting to disable the feature. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index f012cc6..7e412d1 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2799,7 +2799,8 @@ void e1000e_reset(struct e1000_adapter *adapter) e1000e_reset_adaptive(hw); e1000_get_phy_info(hw); - if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) { + if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && + !(adapter->flags & FLAG_SMART_POWER_DOWN)) { u16 phy_data = 0; /* * speed up time to link by disabling smart power down, ignore -- cgit v0.10.2 From 3ec2a2b80f3eb53851fe4cef9e65b5d33376ef89 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 2 Jun 2009 11:28:39 +0000 Subject: e1000e: correct flow control thresholds The flow control thresholds, i.e. high and low watermarks of the Rx FIFO for when the hardware should transmit PAUSE frames (XON and XOFF, respectively), need to be tuned for more efficient use of the FIFO. The logic to set the thresholds for parts that support early-receive (ERT) was also wrong in that it should check whether jumbo frames are in use. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 243aa49..9acfecd 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -469,6 +469,8 @@ #define AUTO_READ_DONE_TIMEOUT 10 /* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ #define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ /* Transmit Configuration Word */ diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 7e412d1..b7a46c5 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2751,23 +2751,25 @@ void e1000e_reset(struct e1000_adapter *adapter) /* * flow control settings * - * The high water mark must be low enough to fit one full frame + * The high water mark must be low enough to fit two full frame * (or the size used for early receive) above it in the Rx FIFO. * Set it to the lower of: * - 90% of the Rx FIFO size, and * - the full Rx FIFO size minus the early receive size (for parts * with ERT support assuming ERT set to E1000_ERT_2048), or - * - the full Rx FIFO size minus one full frame + * - the full Rx FIFO size minus two full frames */ - if (adapter->flags & FLAG_HAS_ERT) + if ((adapter->flags & FLAG_HAS_ERT) && + (adapter->netdev->mtu > ETH_DATA_LEN)) hwm = min(((pba << 10) * 9 / 10), ((pba << 10) - (E1000_ERT_2048 << 3))); else hwm = min(((pba << 10) * 9 / 10), - ((pba << 10) - adapter->max_frame_size)); + ((pba << 10) - (2 * adapter->max_frame_size))); - fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ - fc->low_water = fc->high_water - 8; + fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */ + fc->low_water = (fc->high_water - (2 * adapter->max_frame_size)); + fc->low_water &= E1000_FCRTL_RTL; /* 8-byte granularity */ if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) fc->pause_time = 0xFFFF; -- cgit v0.10.2 From 2adc55c959940fc680074392eddbd5585a76f3d9 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 2 Jun 2009 11:28:58 +0000 Subject: e1000e: specify max supported frame size in adapter struct By putting the maximum frame size supported by the hardware into the adapter structure, the change_mtu entry point function can be cleaned up of checks for all the different max frame sizes supported by Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 6c01a207..8203964 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -341,8 +341,10 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, &eeprom_data) < 0) break; - if (eeprom_data & NVM_WORD1A_ASPM_MASK) - adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) { + adapter->flags |= FLAG_HAS_JUMBO_FRAMES; + adapter->max_hw_frame_size = DEFAULT_JUMBO; + } } break; default: @@ -1672,6 +1674,7 @@ struct e1000_info e1000_82571_info = { | FLAG_TARC_SPEED_MODE_BIT /* errata */ | FLAG_APME_CHECK_PORT_B, .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_igp, @@ -1688,6 +1691,7 @@ struct e1000_info e1000_82572_info = { | FLAG_HAS_CTRLEXT_ON_LOAD | FLAG_TARC_SPEED_MODE_BIT, /* errata */ .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_igp, @@ -1706,6 +1710,7 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_ERT | FLAG_HAS_SWSM_ON_LOAD, .pba = 20, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_m88, @@ -1724,6 +1729,7 @@ struct e1000_info e1000_82574_info = { | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, .pba = 20, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_bm, @@ -1740,6 +1746,7 @@ struct e1000_info e1000_82583_info = { | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, .pba = 20, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_bm, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index f37360a..b9dc612 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -96,6 +96,8 @@ struct e1000_info; /* Number of packet split data buffers (not including the header buffer) */ #define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) +#define DEFAULT_JUMBO 9234 + enum e1000_boards { board_82571, board_82572, @@ -293,6 +295,7 @@ struct e1000_adapter { u32 eeprom_wol; u32 wol; u32 pba; + u32 max_hw_frame_size; bool fc_autoneg; @@ -309,6 +312,7 @@ struct e1000_info { unsigned int flags; unsigned int flags2; u32 pba; + u32 max_hw_frame_size; s32 (*get_variants)(struct e1000_adapter *); struct e1000_mac_operations *mac_ops; struct e1000_phy_operations *phy_ops; diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 8964838..6cc3bdf 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -1422,6 +1422,7 @@ struct e1000_info e1000_es2_info = { | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_80003es2lan, .mac_ops = &es2_mac_ops, .phy_ops = &es2_phy_ops, diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 6d1aab6..b63d987 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -382,6 +382,11 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) if (rc) return rc; + if (adapter->hw.phy.type == e1000_phy_ife) { + adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; + } + if ((adapter->hw.mac.type == e1000_ich8lan) && (adapter->hw.phy.type == e1000_phy_igp_3)) adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; @@ -2595,6 +2600,7 @@ struct e1000_info e1000_ich8_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 8, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, @@ -2613,6 +2619,7 @@ struct e1000_info e1000_ich9_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 10, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, @@ -2631,6 +2638,7 @@ struct e1000_info e1000_ich10_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 10, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index b7a46c5..4072fbb 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4212,27 +4212,17 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) struct e1000_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; - if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) || - (max_frame > MAX_JUMBO_FRAME_SIZE)) { - e_err("Invalid MTU setting\n"); + /* Jumbo frame support */ + if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) && + !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { + e_err("Jumbo Frames not supported.\n"); return -EINVAL; } - /* Jumbo frame size limits */ - if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { - if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { - e_err("Jumbo Frames not supported.\n"); - return -EINVAL; - } - if (adapter->hw.phy.type == e1000_phy_ife) { - e_err("Jumbo Frames not supported.\n"); - return -EINVAL; - } - } - -#define MAX_STD_JUMBO_FRAME_SIZE 9234 - if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { - e_err("MTU > 9216 not supported.\n"); + /* Supported frame sizes */ + if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) || + (max_frame > adapter->max_hw_frame_size)) { + e_err("Unsupported MTU setting\n"); return -EINVAL; } @@ -4848,6 +4838,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->flags2 = ei->flags2; adapter->hw.adapter = adapter; adapter->hw.mac.type = ei->mac; + adapter->max_hw_frame_size = ei->max_hw_frame_size; adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; mmio_start = pci_resource_start(pdev, 0); -- cgit v0.10.2 From a4f58f5455ba0efda36fb33c37074922d1527a10 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 2 Jun 2009 11:29:18 +0000 Subject: e1000e: add support for 82577/82578 GbE LOM parts This patch provides support for the next generation Intel desktop and mobile gigabit ethernet LOM adapters. These adapters are the follow-on parts to the LOMs tied to the prior ICH chipsets and are comprised of a MAC in the PCH chipset and an external PHY (82577 for mobile and 82578 for desktop versions). New features consist of PHY wakeup to save power by completely turning off the MAC while in Sx state, and 4K jumbo frames. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 8203964..c4b3f4f 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -1587,6 +1587,7 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) static struct e1000_mac_operations e82571_mac_ops = { /* .check_mng_mode: mac type dependent */ /* .check_for_link: media type dependent */ + .id_led_init = e1000e_id_led_init, .cleanup_led = e1000e_cleanup_led_generic, .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, .get_bus_info = e1000e_get_bus_info_pcie, @@ -1598,6 +1599,7 @@ static struct e1000_mac_operations e82571_mac_ops = { .init_hw = e1000_init_hw_82571, .setup_link = e1000_setup_link_82571, /* .setup_physical_interface: media type dependent */ + .setup_led = e1000e_setup_led_generic, }; static struct e1000_phy_operations e82_phy_ops_igp = { diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 9acfecd..674a47e 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -56,6 +56,7 @@ /* Wake Up Control */ #define E1000_WUC_APME 0x00000001 /* APM Enable */ #define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ @@ -65,6 +66,13 @@ #define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ #define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +/* Wake Up Status */ +#define E1000_WUS_LNKC E1000_WUFC_LNKC +#define E1000_WUS_MAG E1000_WUFC_MAG +#define E1000_WUS_EX E1000_WUFC_EX +#define E1000_WUS_MC E1000_WUFC_MC +#define E1000_WUS_BC E1000_WUFC_BC + /* Extended Device Control */ #define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ @@ -77,6 +85,7 @@ #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 */ +#define E1000_CTRL_EXT_PHYPDEN 0x00100000 /* Receive Descriptor bit definitions */ #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ @@ -140,6 +149,7 @@ #define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ #define E1000_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min threshold size */ #define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ #define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ /* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ #define E1000_RCTL_SZ_2048 0x00000000 /* Rx buffer size 2048 */ @@ -153,6 +163,7 @@ #define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ #define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ #define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ #define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ @@ -255,11 +266,16 @@ #define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX /* LED Control */ +#define E1000_PHY_LED0_MODE_MASK 0x00000007 +#define E1000_PHY_LED0_IVRT 0x00000008 +#define E1000_PHY_LED0_MASK 0x0000001F + #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 #define E1000_LEDCTL_LED0_IVRT 0x00000040 #define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_MODE_LINK_UP 0x2 #define E1000_LEDCTL_MODE_LED_ON 0xE #define E1000_LEDCTL_MODE_LED_OFF 0xF @@ -676,6 +692,8 @@ #define IFE_C_E_PHY_ID 0x02A80310 #define BME1000_E_PHY_ID 0x01410CB0 #define BME1000_E_PHY_ID_R2 0x01410CB1 +#define I82577_E_PHY_ID 0x01540050 +#define I82578_E_PHY_ID 0x004DD040 /* M88E1000 Specific Registers */ #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ @@ -729,6 +747,9 @@ #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 +#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020 +#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C + /* BME1000 PHY Specific Control Register */ #define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index b9dc612..d6e491b 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -98,6 +98,49 @@ struct e1000_info; #define DEFAULT_JUMBO 9234 +/* BM/HV Specific Registers */ +#define BM_PORT_CTRL_PAGE 769 + +#define PHY_UPPER_SHIFT 21 +#define BM_PHY_REG(page, reg) \ + (((reg) & MAX_PHY_REG_ADDRESS) |\ + (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\ + (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT))) + +/* PHY Wakeup Registers and defines */ +#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0) +#define BM_WUC PHY_REG(BM_WUC_PAGE, 1) +#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2) +#define BM_WUS PHY_REG(BM_WUC_PAGE, 3) +#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2))) +#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2))) +#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2))) +#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2))) +#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1))) + +#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */ +#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */ +#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */ +#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */ +#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */ +#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */ +#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */ + +#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */ +#define HV_SCC_LOWER PHY_REG(778, 17) +#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */ +#define HV_ECOL_LOWER PHY_REG(778, 19) +#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */ +#define HV_MCC_LOWER PHY_REG(778, 21) +#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */ +#define HV_LATECOL_LOWER PHY_REG(778, 24) +#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */ +#define HV_COLC_LOWER PHY_REG(778, 26) +#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */ +#define HV_DC_LOWER PHY_REG(778, 28) +#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ +#define HV_TNCRS_LOWER PHY_REG(778, 30) + enum e1000_boards { board_82571, board_82572, @@ -108,6 +151,7 @@ enum e1000_boards { board_ich8lan, board_ich9lan, board_ich10lan, + board_pchlan, }; struct e1000_queue_stats { @@ -305,6 +349,7 @@ struct e1000_adapter { unsigned int flags2; struct work_struct downshift_task; struct work_struct update_phy_task; + struct work_struct led_blink_task; }; struct e1000_info { @@ -355,6 +400,7 @@ struct e1000_info { /* CRC Stripping defines */ #define FLAG2_CRC_STRIPPING (1 << 0) +#define FLAG2_HAS_PHY_WAKEUP (1 << 1) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -408,6 +454,7 @@ extern struct e1000_info e1000_82583_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_pch_info; extern struct e1000_info e1000_es2_info; extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num); @@ -429,6 +476,7 @@ extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw); extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); +extern s32 e1000e_setup_led_generic(struct e1000_hw *hw); extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); extern s32 e1000e_led_on_generic(struct e1000_hw *hw); extern s32 e1000e_led_off_generic(struct e1000_hw *hw); @@ -497,6 +545,15 @@ extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); extern s32 e1000e_check_downshift(struct e1000_hw *hw); +extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); +extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw); +extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw); +extern s32 e1000_check_polarity_82577(struct e1000_hw *hw); +extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw); +extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw); +extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw); static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) { diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 6cc3bdf..ae5d736 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -1366,6 +1366,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) } static struct e1000_mac_operations es2_mac_ops = { + .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000e_check_mng_mode_generic, /* check_for_link dependent on media type */ .cleanup_led = e1000e_cleanup_led_generic, @@ -1379,6 +1380,7 @@ static struct e1000_mac_operations es2_mac_ops = { .init_hw = e1000_init_hw_80003es2lan, .setup_link = e1000e_setup_link, /* setup_physical_interface dependent on media type */ + .setup_led = e1000e_setup_led_generic, }; static struct e1000_phy_operations es2_phy_ops = { diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 4d25ede..3d64356 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -776,6 +776,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) u32 after; u32 i; u32 toggle; + u32 mask; /* * The status register is Read Only, so a write should fail. @@ -788,17 +789,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) case e1000_80003es2lan: toggle = 0x7FFFF3FF; break; - case e1000_82573: - case e1000_82574: - case e1000_82583: - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: + default: toggle = 0x7FFFF033; break; - default: - toggle = 0xFFFFF833; - break; } before = er32(STATUS); @@ -844,11 +837,18 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); + mask = 0x8003FFFF; + switch (mac->type) { + case e1000_ich10lan: + case e1000_pchlan: + mask |= (1 << 18); + break; + default: + break; + } for (i = 0; i < mac->rar_entry_count; i++) REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), - ((mac->type == e1000_ich10lan) ? - 0x8007FFFF : 0x8003FFFF), - 0xFFFFFFFF); + mask, 0xFFFFFFFF); for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); @@ -1786,15 +1786,22 @@ static int e1000_set_wol(struct net_device *netdev, /* bit defines for adapter->led_status */ #define E1000_LED_ON 0 -static void e1000_led_blink_callback(unsigned long data) +static void e1000e_led_blink_task(struct work_struct *work) { - struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, led_blink_task); if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) adapter->hw.mac.ops.led_off(&adapter->hw); else adapter->hw.mac.ops.led_on(&adapter->hw); +} + +static void e1000_led_blink_callback(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + schedule_work(&adapter->led_blink_task); mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); } @@ -1807,7 +1814,9 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) data = INT_MAX; if ((hw->phy.type == e1000_phy_ife) || + (hw->mac.type == e1000_pchlan) || (hw->mac.type == e1000_82574)) { + INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task); if (!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 6cdb703..fce3f05 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -193,7 +193,11 @@ enum e1e_registers { E1000_RXCSUM = 0x05000, /* Rx Checksum Control - RW */ E1000_RFCTL = 0x05008, /* Receive Filter Control */ E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */ - E1000_RA = 0x05400, /* Receive Address - RW Array */ + E1000_RAL_BASE = 0x05400, /* Receive Address Low - RW */ +#define E1000_RAL(_n) (E1000_RAL_BASE + ((_n) * 8)) +#define E1000_RA (E1000_RAL(0)) + E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */ +#define E1000_RAH(_n) (E1000_RAH_BASE + ((_n) * 8)) E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */ E1000_WUC = 0x05800, /* Wakeup Control - RW */ E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */ @@ -368,6 +372,10 @@ enum e1e_registers { #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_DEV_ID_PCH_M_HV_LM 0x10EA +#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB +#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF +#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 #define E1000_REVISION_4 4 @@ -383,6 +391,7 @@ enum e1000_mac_type { e1000_ich8lan, e1000_ich9lan, e1000_ich10lan, + e1000_pchlan, }; enum e1000_media_type { @@ -417,6 +426,8 @@ enum e1000_phy_type { e1000_phy_igp_3, e1000_phy_ife, e1000_phy_bm, + e1000_phy_82578, + e1000_phy_82577, }; enum e1000_bus_width { @@ -720,6 +731,7 @@ struct e1000_host_mng_command_info { /* Function pointers and static data for the MAC. */ struct e1000_mac_operations { + s32 (*id_led_init)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *); s32 (*check_for_link)(struct e1000_hw *); s32 (*cleanup_led)(struct e1000_hw *); @@ -733,11 +745,13 @@ struct e1000_mac_operations { s32 (*init_hw)(struct e1000_hw *); s32 (*setup_link)(struct e1000_hw *); s32 (*setup_physical_interface)(struct e1000_hw *); + s32 (*setup_led)(struct e1000_hw *); }; /* Function pointers for the PHY. */ struct e1000_phy_operations { s32 (*acquire_phy)(struct e1000_hw *); + s32 (*check_polarity)(struct e1000_hw *); s32 (*check_reset_block)(struct e1000_hw *); s32 (*commit_phy)(struct e1000_hw *); s32 (*force_speed_duplex)(struct e1000_hw *); diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index b63d987..b69c819 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -48,6 +48,10 @@ * 82567LF-3 Gigabit Network Connection * 82567LM-3 Gigabit Network Connection * 82567LM-4 Gigabit Network Connection + * 82577LM Gigabit Network Connection + * 82577LC Gigabit Network Connection + * 82578DM Gigabit Network Connection + * 82578DC Gigabit Network Connection */ #include @@ -116,6 +120,8 @@ #define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 #define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 +#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */ + /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ union ich8_hws_flash_status { @@ -186,6 +192,14 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 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 s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); +static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_led_on_pchlan(struct e1000_hw *hw); +static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -213,6 +227,41 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) #define ew32flash(reg,val) __ew32flash(hw, (reg), (val)) /** + * e1000_init_phy_params_pchlan - Initialize PHY function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific PHY parameters and function pointers. + **/ +static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + + phy->addr = 1; + phy->reset_delay_us = 100; + + phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + phy->ops.read_phy_reg = e1000_read_phy_reg_hv; + phy->ops.write_phy_reg = e1000_write_phy_reg_hv; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + phy->id = e1000_phy_unknown; + e1000e_get_phy_id(hw); + phy->type = e1000e_get_phy_type_from_id(phy->id); + + if (phy->type == e1000_phy_82577) { + phy->ops.check_polarity = e1000_check_polarity_82577; + phy->ops.force_speed_duplex = + e1000_phy_force_speed_duplex_82577; + phy->ops.get_cable_length = e1000_get_cable_length_82577; + phy->ops.get_phy_info = e1000_get_phy_info_82577; + phy->ops.commit_phy = e1000e_phy_sw_reset; + } + + return ret_val; +} + +/** * e1000_init_phy_params_ich8lan - Initialize PHY function pointers * @hw: pointer to the HW structure * @@ -273,6 +322,8 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) break; } + phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + return 0; } @@ -358,6 +409,36 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) /* Set if manageability features are enabled. */ mac->arc_subsystem_valid = 1; + /* LED operations */ + switch (mac->type) { + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + /* ID LED init */ + mac->ops.id_led_init = e1000e_id_led_init; + /* setup LED */ + mac->ops.setup_led = e1000e_setup_led_generic; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_ich8lan; + mac->ops.led_off = e1000_led_off_ich8lan; + break; + case e1000_pchlan: + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_pchlan; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_pchlan; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_pchlan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_pchlan; + mac->ops.led_off = e1000_led_off_pchlan; + break; + default: + break; + } + /* Enable PCS Lock-loss workaround for ICH8 */ if (mac->type == e1000_ich8lan) e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1); @@ -378,7 +459,10 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) if (rc) return rc; - rc = e1000_init_phy_params_ich8lan(hw); + if (hw->mac.type == e1000_pchlan) + rc = e1000_init_phy_params_pchlan(hw); + else + rc = e1000_init_phy_params_ich8lan(hw); if (rc) return rc; @@ -415,12 +499,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) while (timeout) { extcnf_ctrl = er32(EXTCNF_CTRL); - extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; - ew32(EXTCNF_CTRL, extcnf_ctrl); - extcnf_ctrl = er32(EXTCNF_CTRL); - if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) - break; + if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) { + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = er32(EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + } mdelay(1); timeout--; } @@ -560,6 +647,53 @@ static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) } /** + * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be + * done after every PHY reset. + **/ +static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + if (hw->mac.type != e1000_pchlan) + return ret_val; + + if (((hw->phy.type == e1000_phy_82577) && + ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || + ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { + /* Disable generation of early preamble */ + ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431); + if (ret_val) + return ret_val; + + /* Preamble tuning for SSC */ + ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204); + if (ret_val) + return ret_val; + } + + if (hw->phy.type == e1000_phy_82578) { + /* + * Return registers to default by doing a soft reset then + * writing 0x3140 to the control register. + */ + if (hw->phy.revision < 2) { + e1000e_phy_sw_reset(hw); + ret_val = e1e_wphy(hw, PHY_CONTROL, 0x3140); + } + } + + /* Select page 0 */ + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + hw->phy.addr = 1; + e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** * e1000_phy_hw_reset_ich8lan - Performs a PHY reset * @hw: pointer to the HW structure * @@ -580,6 +714,12 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) if (ret_val) return ret_val; + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + if (ret_val) + return ret_val; + } + /* * Initialize the PHY from the NVM on ICH platforms. This * is needed due to an issue where the NVM configuration is @@ -706,7 +846,7 @@ static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE)); if (phy->polarity_correction) { - ret_val = e1000_check_polarity_ife_ich8lan(hw); + ret_val = phy->ops.check_polarity(hw); if (ret_val) return ret_val; } else { @@ -746,6 +886,8 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) break; case e1000_phy_igp_3: case e1000_phy_bm: + case e1000_phy_82578: + case e1000_phy_82577: return e1000e_get_phy_info_igp(hw); break; default: @@ -1857,6 +1999,79 @@ static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) } /** + * e1000_id_led_init_pchlan - store LED configurations + * @hw: pointer to the HW structure + * + * PCH does not control LEDs via the LEDCTL register, rather it uses + * the PHY LED configuration register. + * + * PCH also does not have an "always on" or "always off" mode which + * complicates the ID feature. Instead of using the "on" mode to indicate + * in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()), + * use "link_up" mode. The LEDs will still ID on request if there is no + * link based on logic in e1000_led_[on|off]_pchlan(). + **/ +static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; + const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; + u16 data, i, temp, shift; + + /* Get default ID LED modes */ + ret_val = hw->nvm.ops.valid_led_default(hw, &data); + if (ret_val) + goto out; + + mac->ledctl_default = er32(LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; + shift = (i * 5); + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_on << shift); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_on << shift); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + } + +out: + return ret_val; +} + +/** * e1000_get_bus_info_ich8lan - Get/Set the bus type and width * @hw: pointer to the HW structure * @@ -1965,6 +2180,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) kab |= E1000_KABGTXD_BGSQLBIAS; ew32(KABGTXD, kab); + if (hw->mac.type == e1000_pchlan) + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + return ret_val; } @@ -1990,7 +2208,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) e1000_initialize_hw_bits_ich8lan(hw); /* Initialize identification LED */ - ret_val = e1000e_id_led_init(hw); + ret_val = mac->ops.id_led_init(hw); if (ret_val) { hw_dbg(hw, "Error initializing identification LED\n"); return ret_val; @@ -2036,6 +2254,16 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) ew32(CTRL_EXT, ctrl_ext); /* + * The 82578 Rx buffer will stall if wakeup is enabled in host and + * the ME. Reading the BM_WUC register will clear the host wakeup bit. + * Reset the phy after disabling host wakeup to reset the Rx buffer. + */ + if (hw->phy.type == e1000_phy_82578) { + e1e_rphy(hw, BM_WUC, &i); + e1000e_phy_hw_reset_generic(hw); + } + + /* * Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link * because the symbol error count will increment wildly if there @@ -2059,6 +2287,9 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) /* Extended Device Control */ reg = er32(CTRL_EXT); reg |= (1 << 22); + /* Enable PHY low-power state when MAC is at D3 w/o WoL */ + if (hw->mac.type >= e1000_pchlan) + reg |= E1000_CTRL_EXT_PHYPDEN; ew32(CTRL_EXT, reg); /* Transmit Descriptor Control 0 */ @@ -2135,6 +2366,14 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) return ret_val; ew32(FCTTV, hw->fc.pause_time); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + ret_val = hw->phy.ops.write_phy_reg(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 27), + hw->fc.pause_time); + if (ret_val) + return ret_val; + } return e1000e_set_fc_watermarks(hw); } @@ -2174,18 +2413,26 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) if (ret_val) return ret_val; - if (hw->phy.type == e1000_phy_igp_3) { + switch (hw->phy.type) { + case e1000_phy_igp_3: ret_val = e1000e_copper_link_setup_igp(hw); if (ret_val) return ret_val; - } else if (hw->phy.type == e1000_phy_bm) { + break; + case e1000_phy_bm: + case e1000_phy_82578: ret_val = e1000e_copper_link_setup_m88(hw); if (ret_val) return ret_val; - } - - if (hw->phy.type == e1000_phy_ife) { - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, ®_data); + break; + case e1000_phy_82577: + ret_val = e1000_copper_link_setup_82577(hw); + if (ret_val) + return ret_val; + break; + case e1000_phy_ife: + ret_val = hw->phy.ops.read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, + ®_data); if (ret_val) return ret_val; @@ -2203,9 +2450,13 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) reg_data |= IFE_PMC_AUTO_MDIX; break; } - ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data); + ret_val = hw->phy.ops.write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, + reg_data); if (ret_val) return ret_val; + break; + default: + break; } return e1000e_setup_copper_link(hw); } @@ -2422,18 +2673,26 @@ 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 and ICH10 devices. + * Should only be called for applicable parts. **/ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) { u32 phy_ctrl; - if ((hw->mac.type == e1000_ich10lan) || - (hw->mac.type == e1000_ich9lan)) { + switch (hw->mac.type) { + case e1000_ich9lan: + case e1000_ich10lan: + case e1000_pchlan: phy_ctrl = er32(PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE; ew32(PHY_CTRL, phy_ctrl); + + /* Workaround SWFLAG unexpectedly set during S0->Sx */ + if (hw->mac.type == e1000_pchlan) + udelay(500); + default: + break; } return; @@ -2487,13 +2746,99 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) } /** + * e1000_setup_led_pchlan - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use. + **/ +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw) +{ + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_mode1); +} + +/** + * e1000_cleanup_led_pchlan - Restore the default LED operation + * @hw: pointer to the HW structure + * + * Return the LED back to the default configuration. + **/ +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) +{ + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_default); +} + +/** + * e1000_led_on_pchlan - Turn LEDs on + * @hw: pointer to the HW structure + * + * Turn on the LEDs. + **/ +static s32 e1000_led_on_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode2; + u32 i, led; + + /* + * If no link, then turn LED on by setting the invert bit + * for each LED that's mode is "link_up" in ledctl_mode2. + */ + if (!(er32(STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data); +} + +/** + * e1000_led_off_pchlan - Turn LEDs off + * @hw: pointer to the HW structure + * + * Turn off the LEDs. + **/ +static s32 e1000_led_off_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode1; + u32 i, led; + + /* + * If no link, then turn LED off by clearing the invert bit + * for each LED that's mode is "link_up" in ledctl_mode1. + */ + if (!(er32(STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data); +} + +/** * 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 + * 0. 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) @@ -2503,7 +2848,8 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) e1000e_get_cfg_done(hw); /* If EEPROM is not marked present, init the IGP 3 PHY manually */ - if (hw->mac.type != e1000_ich10lan) { + if ((hw->mac.type != e1000_ich10lan) && + (hw->mac.type != e1000_pchlan)) { if (((er32(EECD) & E1000_EECD_PRES) == 0) && (hw->phy.type == e1000_phy_igp_3)) { e1000e_phy_init_script_igp3(hw); @@ -2529,6 +2875,7 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) { u32 temp; + u16 phy_data; e1000e_clear_hw_cntrs_base(hw); @@ -2546,22 +2893,42 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) temp = er32(IAC); temp = er32(ICRXOC); + /* Clear PHY statistics registers */ + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + hw->phy.ops.read_phy_reg(hw, HV_SCC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_SCC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_ECOL_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_ECOL_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_MCC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_MCC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_LATECOL_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_LATECOL_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_COLC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_COLC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_DC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_DC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_TNCRS_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_TNCRS_LOWER, &phy_data); + } } static struct e1000_mac_operations ich8_mac_ops = { + .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000_check_mng_mode_ich8lan, .check_for_link = e1000e_check_for_copper_link, - .cleanup_led = e1000_cleanup_led_ich8lan, + /* cleanup_led dependent on mac type */ .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, .get_bus_info = e1000_get_bus_info_ich8lan, .get_link_up_info = e1000_get_link_up_info_ich8lan, - .led_on = e1000_led_on_ich8lan, - .led_off = e1000_led_off_ich8lan, + /* led_on dependent on mac type */ + /* led_off dependent on mac type */ .update_mc_addr_list = e1000e_update_mc_addr_list_generic, .reset_hw = e1000_reset_hw_ich8lan, .init_hw = e1000_init_hw_ich8lan, .setup_link = e1000_setup_link_ich8lan, .setup_physical_interface= e1000_setup_copper_link_ich8lan, + /* id_led_init dependent on mac type */ }; static struct e1000_phy_operations ich8_phy_ops = { @@ -2644,3 +3011,21 @@ struct e1000_info e1000_ich10_info = { .phy_ops = &ich8_phy_ops, .nvm_ops = &ich8_nvm_ops, }; + +struct e1000_info e1000_pch_info = { + .mac = e1000_pchlan, + .flags = FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_HAS_JUMBO_FRAMES + | FLAG_APME_IN_WUC, + .pba = 26, + .max_hw_frame_size = 4096, + .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 18a4f59..be6d9e9 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -378,6 +378,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) mac->get_link_status = 0; + if (hw->phy.type == e1000_phy_82578) { + ret_val = e1000_link_stall_workaround_hv(hw); + if (ret_val) + return ret_val; + } + /* * Check if there was DownShift, must be checked * immediately after link-up @@ -1406,6 +1412,38 @@ s32 e1000e_id_led_init(struct e1000_hw *hw) } /** + * e1000e_setup_led_generic - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use and saves the current state + * of the LED so it can be later restored. + **/ +s32 e1000e_setup_led_generic(struct e1000_hw *hw) +{ + u32 ledctl; + + if (hw->mac.ops.setup_led != e1000e_setup_led_generic) { + return -E1000_ERR_CONFIG; + } + + if (hw->phy.media_type == e1000_media_type_fiber) { + ledctl = er32(LEDCTL); + hw->mac.ledctl_default = ledctl; + /* Turn off LED0 */ + ledctl &= ~(E1000_LEDCTL_LED0_IVRT | + E1000_LEDCTL_LED0_BLINK | + E1000_LEDCTL_LED0_MODE_MASK); + ledctl |= (E1000_LEDCTL_MODE_LED_OFF << + E1000_LEDCTL_LED0_MODE_SHIFT); + ew32(LEDCTL, ledctl); + } else if (hw->phy.media_type == e1000_media_type_copper) { + ew32(LEDCTL, hw->mac.ledctl_mode1); + } + + return 0; +} + +/** * e1000e_cleanup_led_generic - Set LED config to default operation * @hw: pointer to the HW structure * diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 4072fbb..2cb704d 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -62,6 +62,7 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_ich8lan] = &e1000_ich8_info, [board_ich9lan] = &e1000_ich9_info, [board_ich10lan] = &e1000_ich10_info, + [board_pchlan] = &e1000_pch_info, }; #ifdef DEBUG @@ -2308,6 +2309,23 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) if (adapter->flags2 & FLAG2_CRC_STRIPPING) rctl |= E1000_RCTL_SECRC; + /* Workaround Si errata on 82577 PHY - configure IPG for jumbos */ + if ((hw->phy.type == e1000_phy_82577) && (rctl & E1000_RCTL_LPE)) { + u16 phy_data; + + e1e_rphy(hw, PHY_REG(770, 26), &phy_data); + phy_data &= 0xfff8; + phy_data |= (1 << 2); + e1e_wphy(hw, PHY_REG(770, 26), phy_data); + + e1e_rphy(hw, 22, &phy_data); + phy_data &= 0x0fff; + phy_data |= (1 << 14); + e1e_wphy(hw, 0x10, 0x2823); + e1e_wphy(hw, 0x11, 0x0003); + e1e_wphy(hw, 22, phy_data); + } + /* Setup buffer sizes */ rctl &= ~E1000_RCTL_SZ_4096; rctl |= E1000_RCTL_BSEX; @@ -2789,6 +2807,8 @@ void e1000e_reset(struct e1000_adapter *adapter) e1000_get_hw_control(adapter); ew32(WUC, 0); + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) + e1e_wphy(&adapter->hw, BM_WUC, 0); if (mac->ops.init_hw(hw)) e_err("Hardware Error\n"); @@ -3269,6 +3289,7 @@ void e1000e_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; + u16 phy_data; /* * Prevent stats update while adapter is being reset, or if the pci @@ -3288,11 +3309,34 @@ void e1000e_update_stats(struct e1000_adapter *adapter) adapter->stats.roc += er32(ROC); adapter->stats.mpc += er32(MPC); - adapter->stats.scc += er32(SCC); - adapter->stats.ecol += er32(ECOL); - adapter->stats.mcc += er32(MCC); - adapter->stats.latecol += er32(LATECOL); - adapter->stats.dc += er32(DC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_SCC_UPPER, &phy_data); + e1e_rphy(hw, HV_SCC_LOWER, &phy_data); + adapter->stats.scc += phy_data; + + e1e_rphy(hw, HV_ECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_ECOL_LOWER, &phy_data); + adapter->stats.ecol += phy_data; + + e1e_rphy(hw, HV_MCC_UPPER, &phy_data); + e1e_rphy(hw, HV_MCC_LOWER, &phy_data); + adapter->stats.mcc += phy_data; + + e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data); + adapter->stats.latecol += phy_data; + + e1e_rphy(hw, HV_DC_UPPER, &phy_data); + e1e_rphy(hw, HV_DC_LOWER, &phy_data); + adapter->stats.dc += phy_data; + } else { + adapter->stats.scc += er32(SCC); + adapter->stats.ecol += er32(ECOL); + adapter->stats.mcc += er32(MCC); + adapter->stats.latecol += er32(LATECOL); + adapter->stats.dc += er32(DC); + } adapter->stats.xonrxc += er32(XONRXC); adapter->stats.xontxc += er32(XONTXC); adapter->stats.xoffrxc += er32(XOFFRXC); @@ -3310,13 +3354,28 @@ void e1000e_update_stats(struct e1000_adapter *adapter) hw->mac.tx_packet_delta = er32(TPT); adapter->stats.tpt += hw->mac.tx_packet_delta; - hw->mac.collision_delta = er32(COLC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_COLC_UPPER, &phy_data); + e1e_rphy(hw, HV_COLC_LOWER, &phy_data); + hw->mac.collision_delta = phy_data; + } else { + hw->mac.collision_delta = er32(COLC); + } adapter->stats.colc += hw->mac.collision_delta; adapter->stats.algnerrc += er32(ALGNERRC); adapter->stats.rxerrc += er32(RXERRC); - if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583)) - adapter->stats.tncrs += er32(TNCRS); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data); + e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data); + adapter->stats.tncrs += phy_data; + } else { + if ((hw->mac.type != e1000_82574) && + (hw->mac.type != e1000_82583)) + adapter->stats.tncrs += er32(TNCRS); + } adapter->stats.cexterr += er32(CEXTERR); adapter->stats.tsctc += er32(TSCTC); adapter->stats.tsctfc += er32(TSCTFC); @@ -4342,6 +4401,81 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } +static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) +{ + struct e1000_hw *hw = &adapter->hw; + u32 i, mac_reg; + u16 phy_reg; + int retval = 0; + + /* copy MAC RARs to PHY RARs */ + for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) { + mac_reg = er32(RAL(i)); + e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF)); + mac_reg = er32(RAH(i)); + e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* copy MAC MTA to PHY MTA */ + for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) { + mac_reg = E1000_READ_REG_ARRAY(hw, E1000_MTA, i); + e1e_wphy(hw, BM_MTA(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_MTA(i) + 1, (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* configure PHY Rx Control register */ + e1e_rphy(&adapter->hw, BM_RCTL, &phy_reg); + mac_reg = er32(RCTL); + if (mac_reg & E1000_RCTL_UPE) + phy_reg |= BM_RCTL_UPE; + if (mac_reg & E1000_RCTL_MPE) + phy_reg |= BM_RCTL_MPE; + phy_reg &= ~(BM_RCTL_MO_MASK); + if (mac_reg & E1000_RCTL_MO_3) + phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT) + << BM_RCTL_MO_SHIFT); + if (mac_reg & E1000_RCTL_BAM) + phy_reg |= BM_RCTL_BAM; + if (mac_reg & E1000_RCTL_PMCF) + phy_reg |= BM_RCTL_PMCF; + mac_reg = er32(CTRL); + if (mac_reg & E1000_CTRL_RFCE) + phy_reg |= BM_RCTL_RFCE; + e1e_wphy(&adapter->hw, BM_RCTL, phy_reg); + + /* enable PHY wakeup in MAC register */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN); + + /* configure and enable PHY wakeup in PHY registers */ + e1e_wphy(&adapter->hw, BM_WUFC, wufc); + e1e_wphy(&adapter->hw, BM_WUC, E1000_WUC_PME_EN); + + /* activate PHY wakeup */ + retval = hw->phy.ops.acquire_phy(hw); + if (retval) { + e_err("Could not acquire PHY\n"); + return retval; + } + e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); + retval = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); + if (retval) { + e_err("Could not read PHY page 769\n"); + goto out; + } + phy_reg |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT; + retval = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); + if (retval) + e_err("Could not set PHY Host Wakeup bit\n"); +out: + hw->phy.ops.release_phy(hw); + + return retval; +} + static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -4384,8 +4518,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) #define E1000_CTRL_ADVD3WUC 0x00100000 /* phy power management enable */ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 - ctrl |= E1000_CTRL_ADVD3WUC | - E1000_CTRL_EN_PHY_PWR_MGMT; + ctrl |= E1000_CTRL_ADVD3WUC; + if (!(adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)) + ctrl |= E1000_CTRL_EN_PHY_PWR_MGMT; ew32(CTRL, ctrl); if (adapter->hw.phy.media_type == e1000_media_type_fiber || @@ -4403,8 +4538,17 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) /* Allow time for pending master requests to run */ e1000e_disable_pcie_master(&adapter->hw); - ew32(WUC, E1000_WUC_PME_EN); - ew32(WUFC, wufc); + if ((adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) && + !(hw->mac.ops.check_mng_mode(hw))) { + /* enable wakeup by the PHY */ + retval = e1000_init_phy_wakeup(adapter, wufc); + if (retval) + return retval; + } else { + /* enable wakeup by the MAC */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PME_EN); + } } else { ew32(WUC, 0); ew32(WUFC, 0); @@ -4547,8 +4691,37 @@ static int e1000_resume(struct pci_dev *pdev) } e1000e_power_up_phy(adapter); + + /* report the system wakeup cause from S3/S4 */ + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) { + u16 phy_data; + + e1e_rphy(&adapter->hw, BM_WUS, &phy_data); + if (phy_data) { + e_info("PHY Wakeup cause - %s\n", + phy_data & E1000_WUS_EX ? "Unicast Packet" : + phy_data & E1000_WUS_MC ? "Multicast Packet" : + phy_data & E1000_WUS_BC ? "Broadcast Packet" : + phy_data & E1000_WUS_MAG ? "Magic Packet" : + phy_data & E1000_WUS_LNKC ? "Link Status " + " Change" : "other"); + } + e1e_wphy(&adapter->hw, BM_WUS, ~0); + } else { + u32 wus = er32(WUS); + if (wus) { + e_info("MAC Wakeup cause - %s\n", + wus & E1000_WUS_EX ? "Unicast Packet" : + wus & E1000_WUS_MC ? "Multicast Packet" : + wus & E1000_WUS_BC ? "Broadcast Packet" : + wus & E1000_WUS_MAG ? "Magic Packet" : + wus & E1000_WUS_LNKC ? "Link Status Change" : + "other"); + } + ew32(WUS, ~0); + } + e1000e_reset(adapter); - ew32(WUS, ~0); e1000_init_manageability(adapter); @@ -4994,6 +5167,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* APME bit in EEPROM is mapped to WUC.APME */ eeprom_data = er32(WUC); eeprom_apme_mask = E1000_WUC_APME; + if (eeprom_data & E1000_WUC_PHY_WAKE) + adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP; } else if (adapter->flags & FLAG_APME_IN_CTRL3) { if (adapter->flags & FLAG_APME_CHECK_PORT_B && (adapter->hw.bus.func == 1)) @@ -5195,6 +5370,11 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index dc4a9cb..e23459c 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -37,6 +37,9 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw); static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg); static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read); +static u32 e1000_get_phy_addr_for_hv_page(u32 page); +static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read); /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = @@ -54,6 +57,55 @@ static const u16 e1000_igp_2_cable_length_table[] = #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ ARRAY_SIZE(e1000_igp_2_cable_length_table) +#define BM_PHY_REG_PAGE(offset) \ + ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF)) +#define BM_PHY_REG_NUM(offset) \ + ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\ + (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\ + ~MAX_PHY_REG_ADDRESS))) + +#define HV_INTC_FC_PAGE_START 768 +#define I82578_ADDR_REG 29 +#define I82577_ADDR_REG 16 +#define I82577_CFG_REG 22 +#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15) +#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */ +#define I82577_CTRL_REG 23 +#define I82577_CTRL_DOWNSHIFT_MASK (7 << 10) + +/* 82577 specific PHY registers */ +#define I82577_PHY_CTRL_2 18 +#define I82577_PHY_STATUS_2 26 +#define I82577_PHY_DIAG_STATUS 31 + +/* I82577 PHY Status 2 */ +#define I82577_PHY_STATUS2_REV_POLARITY 0x0400 +#define I82577_PHY_STATUS2_MDIX 0x0800 +#define I82577_PHY_STATUS2_SPEED_MASK 0x0300 +#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200 + +/* I82577 PHY Control 2 */ +#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400 +#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200 + +/* I82577 PHY Diagnostics Status */ +#define I82577_DSTATUS_CABLE_LENGTH 0x03FC +#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2 + +/* BM PHY Copper Specific Control 1 */ +#define BM_CS_CTRL1 16 + +/* BM PHY Copper Specific Status */ +#define BM_CS_STATUS 17 +#define BM_CS_STATUS_LINK_UP 0x0400 +#define BM_CS_STATUS_RESOLVED 0x0800 +#define BM_CS_STATUS_SPEED_MASK 0xC000 +#define BM_CS_STATUS_SPEED_1000 0x8000 + +#define HV_MUX_DATA_CTRL PHY_REG(776, 16) +#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400 +#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004 + /** * e1000e_check_reset_block_generic - Check if PHY reset is blocked * @hw: pointer to the HW structure @@ -82,23 +134,48 @@ s32 e1000e_check_reset_block_generic(struct e1000_hw *hw) s32 e1000e_get_phy_id(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; + s32 ret_val = 0; u16 phy_id; + u16 retry_count = 0; - ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); - if (ret_val) - return ret_val; + if (!(phy->ops.read_phy_reg)) + goto out; - phy->id = (u32)(phy_id << 16); - udelay(20); - ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); - if (ret_val) - return ret_val; + while (retry_count < 2) { + ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; - phy->id |= (u32)(phy_id & PHY_REVISION_MASK); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + phy->id = (u32)(phy_id << 16); + udelay(20); + ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; - return 0; + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + + if (phy->id != 0 && phy->id != PHY_REVISION_MASK) + goto out; + + /* + * If the PHY ID is still unknown, we may have an 82577i + * without link. We will try again after setting Slow + * MDIC mode. No harm in trying again in this case since + * the PHY ID is unknown at this point anyway + */ + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + retry_count++; + } +out: + /* Revert to MDIO fast mode, if applicable */ + if (retry_count) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; } /** @@ -410,6 +487,43 @@ s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) } /** + * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link + * @hw: pointer to the HW structure + * + * Sets up Carrier-sense on Transmit and downshift values. + **/ +s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = phy->ops.read_phy_reg(hw, I82577_CFG_REG, &phy_data); + if (ret_val) + goto out; + + phy_data |= I82577_CFG_ASSERT_CRS_ON_TX; + + /* Enable downshift */ + phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; + + ret_val = phy->ops.write_phy_reg(hw, I82577_CFG_REG, phy_data); + if (ret_val) + goto out; + + /* Set number of link attempts before downshift */ + ret_val = phy->ops.read_phy_reg(hw, I82577_CTRL_REG, &phy_data); + if (ret_val) + goto out; + phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK; + ret_val = phy->ops.write_phy_reg(hw, I82577_CTRL_REG, phy_data); + +out: + return ret_val; +} + +/** * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link * @hw: pointer to the HW structure * @@ -427,8 +541,8 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) if (ret_val) return ret_val; - /* For newer PHYs this bit is downshift enable */ - if (phy->type == e1000_phy_m88) + /* For BM PHY this bit is downshift enable */ + if (phy->type != e1000_phy_bm) phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; /* @@ -520,10 +634,27 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) /* Commit the changes. */ ret_val = e1000e_commit_phy(hw); - if (ret_val) + if (ret_val) { hw_dbg(hw, "Error committing the PHY changes\n"); + return ret_val; + } - return ret_val; + if (phy->type == e1000_phy_82578) { + ret_val = phy->ops.read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* 82578 PHY - set the downshift count to 1x. */ + phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE; + phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK; + ret_val = phy->ops.write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + return 0; } /** @@ -1251,6 +1382,8 @@ s32 e1000e_check_downshift(struct e1000_hw *hw) switch (phy->type) { case e1000_phy_m88: case e1000_phy_gg82563: + case e1000_phy_82578: + case e1000_phy_82577: offset = M88E1000_PHY_SPEC_STATUS; mask = M88E1000_PSSR_DOWNSHIFT; break; @@ -1886,6 +2019,12 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) case BME1000_E_PHY_ID_R2: phy_type = e1000_phy_bm; break; + case I82578_E_PHY_ID: + phy_type = e1000_phy_82578; + break; + case I82577_E_PHY_ID: + phy_type = e1000_phy_82577; + break; default: phy_type = e1000_phy_unknown; break; @@ -2181,11 +2320,16 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read) { s32 ret_val; - u16 reg = ((u16)offset) & PHY_REG_MASK; + u16 reg = BM_PHY_REG_NUM(offset); u16 phy_reg = 0; u8 phy_acquired = 1; + /* Gig must be disabled for MDIO accesses to page 800 */ + if ((hw->mac.type == e1000_pchlan) && + (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE))) + hw_dbg(hw, "Attempting to access page 800 while gig enabled\n"); + ret_val = hw->phy.ops.acquire_phy(hw); if (ret_val) { phy_acquired = 0; @@ -2289,3 +2433,524 @@ static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active) return 0; } + +s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) +{ + s32 ret_val = 0; + u16 data = 0; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */ + hw->phy.addr = 1; + ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1, + (0x2180 | (slow << 10))); + + /* dummy read when reverting to fast mode - throw away result */ + if (!slow) + e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000_read_phy_reg_hv - Read HV 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 + * semaphore before exiting. + **/ +s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(er32(STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* 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); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + data, true); + goto out; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + if ((hw->phy.type != e1000_phy_82578) || + ((reg != I82578_ADDR_REG) && + (reg != I82578_ADDR_REG + 1))) { + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + goto out; + } + hw->phy.addr = phy_addr; + } + } + + ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release_phy(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; +} + +/** + * e1000_write_phy_reg_hv - Write HV 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 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(er32(STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* 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); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + &data, false); + goto out; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + /* + * Workaround MDIO accesses being disabled after entering IEEE Power + * Down (whenever bit 11 of the PHY Control register is set) + */ + if ((hw->phy.type == e1000_phy_82578) && + (hw->phy.revision >= 1) && + (hw->phy.addr == 2) && + ((MAX_PHY_REG_ADDRESS & reg) == 0) && + (data & (1 << 11))) { + u16 data2 = 0x7EFF; + hw->phy.ops.release_phy(hw); + ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, + &data2, false); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + } + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + if ((hw->phy.type != e1000_phy_82578) || + ((reg != I82578_ADDR_REG) && + (reg != I82578_ADDR_REG + 1))) { + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + goto out; + } + hw->phy.addr = phy_addr; + } + } + + ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release_phy(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; +} + +/** + * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page + * @page: page to be accessed + **/ +static u32 e1000_get_phy_addr_for_hv_page(u32 page) +{ + u32 phy_addr = 2; + + if (page >= HV_INTC_FC_PAGE_START) + phy_addr = 1; + + return phy_addr; +} + +/** + * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers + * @hw: pointer to the HW structure + * @offset: register offset to be read or written + * @data: pointer to the data to be read or written + * @read: determines if operation is read or written + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retreived information in data. Release any acquired + * semaphores before exiting. Note that the procedure to read these regs + * uses the address port and data port to read/write. + **/ +static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read) +{ + s32 ret_val; + u32 addr_reg = 0; + u32 data_reg = 0; + u8 phy_acquired = 1; + + /* This takes care of the difference with desktop vs mobile phy */ + addr_reg = (hw->phy.type == e1000_phy_82578) ? + I82578_ADDR_REG : I82577_ADDR_REG; + data_reg = addr_reg + 1; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) { + hw_dbg(hw, "Could not acquire PHY\n"); + phy_acquired = 0; + goto out; + } + + /* All operations in this function are phy address 2 */ + hw->phy.addr = 2; + + /* masking with 0x3F to remove the page from offset */ + ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F); + if (ret_val) { + hw_dbg(hw, "Could not write PHY the HV address register\n"); + goto out; + } + + /* Read or write the data value next */ + if (read) + ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data); + else + ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data); + + if (ret_val) { + hw_dbg(hw, "Could not read data value from HV data register\n"); + goto out; + } + +out: + if (phy_acquired == 1) + hw->phy.ops.release_phy(hw); + return ret_val; +} + +/** + * e1000_link_stall_workaround_hv - Si workaround + * @hw: pointer to the HW structure + * + * This function works around a Si bug where the link partner can get + * a link up indication before the PHY does. If small packets are sent + * by the link partner they can be placed in the packet buffer without + * being properly accounted for by the PHY and will stall preventing + * further packets from being received. The workaround is to clear the + * packet buffer after the PHY detects link up. + **/ +s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 data; + + if (hw->phy.type != e1000_phy_82578) + goto out; + + /* check if link is up and at 1Gbps */ + ret_val = hw->phy.ops.read_phy_reg(hw, BM_CS_STATUS, &data); + if (ret_val) + goto out; + + data &= BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_MASK; + + if (data != (BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_1000)) + goto out; + + mdelay(200); + + /* flush the packets in the fifo buffer */ + ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC | + HV_MUX_DATA_CTRL_FORCE_SPEED); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC); + +out: + return ret_val; +} + +/** + * e1000_check_polarity_82577 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + **/ +s32 e1000_check_polarity_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data); + + if (!ret_val) + phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + **/ +s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + ret_val = phy->ops.read_phy_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = phy->ops.write_phy_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + /* + * Clear Auto-Crossover to force MDI manually. 82577 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_CTRL_2, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX; + phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX; + + ret_val = phy->ops.write_phy_reg(hw, I82577_PHY_CTRL_2, phy_data); + if (ret_val) + goto out; + + hw_dbg(hw, "I82577_PHY_CTRL_2: %X\n", phy_data); + + udelay(1); + + if (phy->autoneg_wait_to_complete) { + hw_dbg(hw, "Waiting for forced speed/duplex link on 82577 phy\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_82577 - Retrieve I82577 PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + **/ +s32 e1000_get_phy_info_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + phy->polarity_correction = true; + + ret_val = e1000_check_polarity_82577(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false; + + if ((data & I82577_PHY_STATUS2_SPEED_MASK) == + I82577_PHY_STATUS2_SPEED_1000MBPS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_phy_reg(hw, PHY_1000T_STATUS, &data); + if (ret_val) + goto out; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return ret_val; +} + +/** + * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY + * @hw: pointer to the HW structure + * + * Reads the diagnostic status register and verifies result is valid before + * placing it in the phy_cable_length field. + **/ +s32 e1000_get_cable_length_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, length; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data); + if (ret_val) + goto out; + + length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >> + I82577_DSTATUS_CABLE_LENGTH_SHIFT; + + if (length == E1000_CABLE_LENGTH_UNDEFINED) + ret_val = E1000_ERR_PHY; + + phy->cable_length = length; + +out: + return ret_val; +} -- cgit v0.10.2 From 37289d9c1e72a186ea5f28bee79efeb1d4e7309c Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 2 Jun 2009 11:29:37 +0000 Subject: e1000e: workaround a Tx hang on 82577/82578 With bi-directional stress traffic, the receiver could hang causing the hardware to stop and a "Detected Tx Unit Hang" message dumped to the system logfile. Temporarily workaround this issue by disabling Tx flow control by default. The issue is currently being investigated and a follow-on patch will be provided to revert this when it is resolved. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index b69c819..9e23f50f 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -2348,8 +2348,13 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) * the default flow control setting, so we explicitly * set it to full. */ - if (hw->fc.requested_mode == e1000_fc_default) - hw->fc.requested_mode = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_default) { + /* Workaround h/w hang when Tx flow control enabled */ + if (hw->mac.type == e1000_pchlan) + hw->fc.requested_mode = e1000_fc_rx_pause; + else + hw->fc.requested_mode = e1000_fc_full; + } /* * Save off the requested flow control mode for use later. Depending -- cgit v0.10.2 From 3be8c940a64009afc484c380cb0f8f4a07136519 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 2 Jun 2009 11:29:56 +0000 Subject: e1000e: bump the version number Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 2cb704d..38694c7 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -48,7 +48,7 @@ #include "e1000.h" -#define DRV_VERSION "0.3.3.4-k4" +#define DRV_VERSION "1.0.2-k2" char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; -- cgit v0.10.2 From dfbf97f3ac980b69dfbc41c83a208211a38443e8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Jun 2009 05:13:45 +0000 Subject: net: add _skb_dst opaque field struct sk_buff uses one union to define dst and rtable fields. We want to replace direct access to these pointers by accessors. First patch adds a new "unsigned long _skb_dst;" opaque field in this union. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index aff494b..d4d7c66 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -325,6 +325,7 @@ struct sk_buff { union { struct dst_entry *dst; struct rtable *rtable; + unsigned long _skb_dst; }; #ifdef CONFIG_XFRM struct sec_path *sp; -- cgit v0.10.2 From 511c3f92ad5b6d9f8f6464be1b4f85f0422be91a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Jun 2009 05:14:27 +0000 Subject: net: skb->rtable accessor Define skb_rtable(const struct sk_buff *skb) accessor to get rtable from skb Delete skb->rtable field Setting rtable is not allowed, just set dst instead as rtable is an alias. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 9832b75..78cea5e 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -115,7 +115,7 @@ static struct net_device * __init ipddp_init(void) */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) { - __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway; + __be32 paddr = skb_rtable(skb)->rt_gateway; struct ddpehdr *ddp; struct ipddp_route *rt; struct atalk_addr *our_addr; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d4d7c66..a3ae3c5 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -324,7 +324,6 @@ struct sk_buff { union { struct dst_entry *dst; - struct rtable *rtable; unsigned long _skb_dst; }; #ifdef CONFIG_XFRM @@ -427,6 +426,11 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb, enum dma_data_direction dir); #endif +static inline struct rtable *skb_rtable(const struct sk_buff *skb) +{ + return (struct rtable *)skb->_skb_dst; +} + extern void kfree_skb(struct sk_buff *skb); extern void consume_skb(struct sk_buff *skb); extern void __kfree_skb(struct sk_buff *skb); diff --git a/include/net/route.h b/include/net/route.h index 4e8cae0..40f6346 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -210,7 +210,7 @@ static inline struct inet_peer *rt_get_peer(struct rtable *rt) static inline int inet_iif(const struct sk_buff *skb) { - return skb->rtable->rt_iif; + return skb_rtable(skb)->rt_iif; } #endif /* _ROUTE_H */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index e4a418f..e0ceb66 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -228,6 +228,7 @@ int nf_bridge_copy_header(struct sk_buff *skb) static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct rtable *rt; if (nf_bridge->mask & BRNF_PKT_TYPE) { skb->pkt_type = PACKET_OTHERHOST; @@ -235,12 +236,13 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) } nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; - skb->rtable = bridge_parent_rtable(nf_bridge->physindev); - if (!skb->rtable) { + rt = bridge_parent_rtable(nf_bridge->physindev); + if (!rt) { kfree_skb(skb); return 0; } - dst_hold(&skb->rtable->u.dst); + dst_hold(&rt->u.dst); + skb->dst = &rt->u.dst; skb->dev = nf_bridge->physindev; nf_bridge_push_encap_header(skb); @@ -338,6 +340,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) struct net_device *dev = skb->dev; struct iphdr *iph = ip_hdr(skb); struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct rtable *rt; int err; if (nf_bridge->mask & BRNF_PKT_TYPE) { @@ -347,7 +350,6 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; if (dnat_took_place(skb)) { if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { - struct rtable *rt; struct flowi fl = { .nl_u = { .ip4_u = { @@ -404,12 +406,13 @@ bridged_dnat: skb->pkt_type = PACKET_HOST; } } else { - skb->rtable = bridge_parent_rtable(nf_bridge->physindev); - if (!skb->rtable) { + rt = bridge_parent_rtable(nf_bridge->physindev); + if (!rt) { kfree_skb(skb); return 0; } - dst_hold(&skb->rtable->u.dst); + dst_hold(&rt->u.dst); + skb->dst = &rt->u.dst; } skb->dev = nf_bridge->physindev; @@ -628,9 +631,11 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (skb->rtable && skb->rtable == bridge_parent_rtable(in)) { - dst_release(&skb->rtable->u.dst); - skb->rtable = NULL; + struct rtable *rt = skb_rtable(skb); + + if (rt && rt == bridge_parent_rtable(in)) { + dst_release(&rt->u.dst); + skb->dst = NULL; } return NF_ACCEPT; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index d1dd952..2cf48ba 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -452,7 +452,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, struct sk_buff *skb) { struct rtable *rt; - struct flowi fl = { .oif = skb->rtable->rt_iif, + struct flowi fl = { .oif = skb_rtable(skb)->rt_iif, .nl_u = { .ip4_u = { .daddr = ip_hdr(skb)->saddr, .saddr = ip_hdr(skb)->daddr, @@ -514,7 +514,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; - if (rxskb->rtable->rt_type != RTN_LOCAL) + if (skb_rtable(rxskb)->rt_type != RTN_LOCAL) return; dst = dccp_v4_route_skb(net, ctl_sk, rxskb); @@ -567,7 +567,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ - if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return 0; /* discard, don't send a reset here */ if (dccp_bad_service_code(sk, service)) { diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index f11931c..816494f 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -474,7 +474,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) return 1; } - paddr = skb->rtable->rt_gateway; + paddr = skb_rtable(skb)->rt_gateway; if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev)) return 0; @@ -817,7 +817,7 @@ static int arp_process(struct sk_buff *skb) if (arp->ar_op == htons(ARPOP_REQUEST) && ip_route_input(skb, tip, sip, 0, dev) == 0) { - rt = skb->rtable; + rt = skb_rtable(skb); addr_type = rt->rt_type; if (addr_type == RTN_LOCAL) { diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 3f50807..94f75ef 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -356,7 +356,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct ipcm_cookie ipc; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net *net = dev_net(rt->u.dst.dev); struct sock *sk; struct inet_sock *inet; @@ -416,7 +416,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct iphdr *iph; int room; struct icmp_bxm icmp_param; - struct rtable *rt = skb_in->rtable; + struct rtable *rt = skb_rtable(skb_in); struct ipcm_cookie ipc; __be32 saddr; u8 tos; @@ -596,7 +596,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) RT_TOS(tos), rt2->u.dst.dev); dst_release(&rt2->u.dst); - rt2 = skb_in->rtable; + rt2 = skb_rtable(skb_in); skb_in->dst = odst; } @@ -926,7 +926,7 @@ static void icmp_address(struct sk_buff *skb) static void icmp_address_reply(struct sk_buff *skb) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net_device *dev = skb->dev; struct in_device *in_dev; struct in_ifaddr *ifa; @@ -970,7 +970,7 @@ static void icmp_discard(struct sk_buff *skb) int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net *net = dev_net(rt->u.dst.dev); if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index e6058a5..afabd27 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -948,7 +948,7 @@ int igmp_rcv(struct sk_buff *skb) case IGMPV2_HOST_MEMBERSHIP_REPORT: case IGMPV3_HOST_MEMBERSHIP_REPORT: /* Is it our report looped back? */ - if (skb->rtable->fl.iif == 0) + if (skb_rtable(skb)->fl.iif == 0) break; /* don't rely on MC router hearing unicast reports */ if (skb->pkt_type == PACKET_MULTICAST || diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index df3fe50..0761cd9 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -81,7 +81,7 @@ int ip_forward(struct sk_buff *skb) if (!xfrm4_route_forward(skb)) goto drop; - rt = skb->rtable; + rt = skb_rtable(skb); if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) goto sr_failed; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 77436e2..85ddad4 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -602,7 +602,7 @@ static int ipgre_rcv(struct sk_buff *skb) #ifdef CONFIG_NET_IPGRE_BROADCAST if (ipv4_is_multicast(iph->daddr)) { /* Looped back packet, drop it! */ - if (skb->rtable->fl.iif == 0) + if (skb_rtable(skb)->fl.iif == 0) goto drop; stats->multicast++; skb->pkt_type = PACKET_BROADCAST; @@ -704,7 +704,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (skb->protocol == htons(ETH_P_IP)) { - rt = skb->rtable; + rt = skb_rtable(skb); if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 40f6206..cea784b 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -357,7 +357,7 @@ static int ip_rcv_finish(struct sk_buff *skb) if (iph->ihl > 5 && ip_rcv_options(skb)) goto drop; - rt = skb->rtable; + rt = skb_rtable(skb); if (rt->rt_type == RTN_MULTICAST) { IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST, skb->len); diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 2c88da6..7e1074f 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -102,7 +102,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) sptr = skb_network_header(skb); dptr = dopt->__data; - daddr = skb->rtable->rt_spec_dst; + daddr = skb_rtable(skb)->rt_spec_dst; if (sopt->rr) { optlen = sptr[sopt->rr+1]; @@ -257,7 +257,7 @@ int ip_options_compile(struct net *net, struct rtable *rt = NULL; if (skb != NULL) { - rt = skb->rtable; + rt = skb_rtable(skb); optptr = (unsigned char *)&(ip_hdr(skb)[1]); } else optptr = opt->__data; @@ -550,7 +550,7 @@ void ip_forward_options(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); unsigned char * optptr; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); unsigned char *raw = skb_network_header(skb); if (opt->rr_needaddr) { @@ -598,7 +598,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) __be32 nexthop; struct iphdr *iph = ip_hdr(skb); unsigned char *optptr = skb_network_header(skb) + opt->srr; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct rtable *rt2; int err; @@ -623,13 +623,13 @@ int ip_options_rcv_srr(struct sk_buff *skb) } memcpy(&nexthop, &optptr[srrptr-1], 4); - rt = skb->rtable; - skb->rtable = NULL; + rt = skb_rtable(skb); + skb->dst = NULL; err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); - rt2 = skb->rtable; + rt2 = skb_rtable(skb); if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { ip_rt_put(rt2); - skb->rtable = rt; + skb->dst = &rt->u.dst; return -EINVAL; } ip_rt_put(rt); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ea19c37..8d845eb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -140,7 +140,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, __be32 saddr, __be32 daddr, struct ip_options *opt) { struct inet_sock *inet = inet_sk(sk); - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct iphdr *iph; /* Build the IP header. */ @@ -238,7 +238,7 @@ static int ip_finish_output(struct sk_buff *skb) int ip_mc_output(struct sk_buff *skb) { struct sock *sk = skb->sk; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net_device *dev = rt->u.dst.dev; /* @@ -319,7 +319,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) /* Skip all of this if the packet is already routed, * f.e. by something like SCTP. */ - rt = skb->rtable; + rt = skb_rtable(skb); if (rt != NULL) goto packet_routed; @@ -440,7 +440,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) unsigned int mtu, hlen, left, len, ll_rs, pad; int offset; __be16 not_last_frag; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); int err = 0; dev = rt->u.dst.dev; @@ -1362,7 +1362,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar } replyopts; struct ipcm_cookie ipc; __be32 daddr; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); if (ip_options_echo(&replyopts.opt, skb)) return; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index cb49936..fc7993e 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -57,7 +57,7 @@ static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) { struct in_pktinfo info; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); info.ipi_addr.s_addr = ip_hdr(skb)->daddr; if (rt) { diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index bb2f1b1..0c6e7bf 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -416,7 +416,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!dst) { /* NBMA tunnel */ - if ((rt = skb->rtable) == NULL) { + if ((rt = skb_rtable(skb)) == NULL) { stats->tx_fifo_errors++; goto tx_error; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 13e9dd30..69dd058 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1354,7 +1354,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local if (net->ipv4.vif_table[vif].dev != skb->dev) { int true_vifi; - if (skb->rtable->fl.iif == 0) { + if (skb_rtable(skb)->fl.iif == 0) { /* It is our own packet, looped back. Very complicated situation... @@ -1430,7 +1430,7 @@ int ip_mr_input(struct sk_buff *skb) { struct mfc_cache *cache; struct net *net = dev_net(skb->dev); - int local = skb->rtable->rt_flags&RTCF_LOCAL; + int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL; /* Packet is looped back after forward, it should not be forwarded second time, but still can be delivered locally. @@ -1646,7 +1646,7 @@ int ipmr_get_route(struct net *net, { int err; struct mfc_cache *cache; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); read_lock(&mrt_lock); cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst); diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index f389f60..c0992c7 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -72,7 +72,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par) return NF_ACCEPT; mr = par->targinfo; - rt = skb->rtable; + rt = skb_rtable(skb); newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE); if (!newsrc) { printk("MASQUERADE: %s ate my IP address\n", par->out->name); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index cf7a42b..155c008 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -140,7 +140,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct iphdr *iph; struct tcphdr *tcph; int oldlen, datalen; @@ -218,7 +218,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct iphdr *iph; struct udphdr *udph; int datalen, oldlen; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 28205e5..f20060a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1064,7 +1064,8 @@ work_done: out: return 0; } -static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) +static int rt_intern_hash(unsigned hash, struct rtable *rt, + struct rtable **rp, struct sk_buff *skb) { struct rtable *rth, **rthp; unsigned long now; @@ -1114,7 +1115,10 @@ restart: spin_unlock_bh(rt_hash_lock_addr(hash)); rt_drop(rt); - *rp = rth; + if (rp) + *rp = rth; + else + skb->dst = &rth->u.dst; return 0; } @@ -1210,7 +1214,10 @@ restart: rcu_assign_pointer(rt_hash_table[hash].chain, rt); spin_unlock_bh(rt_hash_lock_addr(hash)); - *rp = rt; + if (rp) + *rp = rt; + else + skb->dst = &rt->u.dst; return 0; } @@ -1407,7 +1414,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, &netevent); rt_del(hash, rth); - if (!rt_intern_hash(hash, rt, &rt)) + if (!rt_intern_hash(hash, rt, &rt, NULL)) ip_rt_put(rt); goto do_next; } @@ -1473,7 +1480,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) void ip_rt_send_redirect(struct sk_buff *skb) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct in_device *in_dev = in_dev_get(rt->u.dst.dev); if (!in_dev) @@ -1521,7 +1528,7 @@ out: static int ip_error(struct sk_buff *skb) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); unsigned long now; int code; @@ -1698,7 +1705,7 @@ static void ipv4_link_failure(struct sk_buff *skb) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - rt = skb->rtable; + rt = skb_rtable(skb); if (rt) dst_set_expires(&rt->u.dst, 0); } @@ -1858,7 +1865,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, in_dev_put(in_dev); hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); - return rt_intern_hash(hash, rth, &skb->rtable); + return rt_intern_hash(hash, rth, NULL, skb); e_nobufs: in_dev_put(in_dev); @@ -2019,7 +2026,7 @@ static int ip_mkroute_input(struct sk_buff *skb, /* put it into the cache */ hash = rt_hash(daddr, saddr, fl->iif, rt_genid(dev_net(rth->u.dst.dev))); - return rt_intern_hash(hash, rth, &skb->rtable); + return rt_intern_hash(hash, rth, NULL, skb); } /* @@ -2175,7 +2182,7 @@ local_input: } rth->rt_type = res.type; hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); - err = rt_intern_hash(hash, rth, &skb->rtable); + err = rt_intern_hash(hash, rth, NULL, skb); goto done; no_route: @@ -2244,7 +2251,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); rcu_read_unlock(); - skb->rtable = rth; + skb->dst = &rth->u.dst; return 0; } RT_CACHE_STAT_INC(in_hlist_search); @@ -2420,7 +2427,7 @@ static int ip_mkroute_output(struct rtable **rp, if (err == 0) { hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, rt_genid(dev_net(dev_out))); - err = rt_intern_hash(hash, rth, rp); + err = rt_intern_hash(hash, rth, rp, NULL); } return err; @@ -2763,7 +2770,7 @@ static int rt_fill_info(struct net *net, struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait, unsigned int flags) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct rtmsg *r; struct nlmsghdr *nlh; long expires; @@ -2907,7 +2914,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); local_bh_enable(); - rt = skb->rtable; + rt = skb_rtable(skb); if (err == 0 && rt->u.dst.error) err = -rt->u.dst.error; } else { @@ -2927,7 +2934,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (err) goto errout_free; - skb->rtable = rt; + skb->dst = &rt->u.dst; if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fc79e34..319c885 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -546,7 +546,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (skb->rtable->rt_type != RTN_LOCAL) + if (skb_rtable(skb)->rt_type != RTN_LOCAL) return; /* Swap the send and the receive. */ @@ -1185,7 +1185,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) #endif /* Never answer to SYNs send to broadcast or multicast */ - if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) goto drop; /* TW buckets are converted to open requests without diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c index 8a3875e..497b222 100644 --- a/net/netfilter/nf_conntrack_netbios_ns.c +++ b/net/netfilter/nf_conntrack_netbios_ns.c @@ -48,7 +48,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, { struct nf_conntrack_expect *exp; struct iphdr *iph = ip_hdr(skb); - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct in_device *in_dev; __be32 mask = 0; diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index fad596b..b6b588b 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -258,10 +258,10 @@ META_COLLECTOR(int_rtclassid) META_COLLECTOR(int_rtiif) { - if (unlikely(skb->rtable == NULL)) + if (unlikely(skb_rtable(skb) == NULL)) *err = -1; else - dst->value = skb->rtable->fl.iif; + dst->value = skb_rtable(skb)->fl.iif; } /************************************************************************** diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 8eb3e61..cb2c50d 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -393,7 +393,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr, return 0; /* Is this a broadcast address? */ - if (skb && skb->rtable->rt_flags & RTCF_BROADCAST) + if (skb && skb_rtable(skb)->rt_flags & RTCF_BROADCAST) return 0; return 1; @@ -572,7 +572,7 @@ static void sctp_v4_get_saddr(struct sctp_sock *sk, /* What interface did this skb arrive on? */ static int sctp_v4_skb_iif(const struct sk_buff *skb) { - return skb->rtable->rt_iif; + return skb_rtable(skb)->rt_iif; } /* Was this packet marked by Explicit Congestion Notification? */ @@ -848,8 +848,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - &skb->rtable->rt_src, - &skb->rtable->rt_dst); + &skb_rtable(skb)->rt_src, + &skb_rtable(skb)->rt_dst); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; -- cgit v0.10.2 From adf30907d63893e4208dfe3f5c88ae12bc2f25d5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Jun 2009 05:19:30 +0000 Subject: net: skb->dst accessors Define three accessors to get/set dst attached to a skb struct dst_entry *skb_dst(const struct sk_buff *skb) void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) void skb_dst_drop(struct sk_buff *skb) This one should replace occurrences of : dst_release(skb->dst) skb->dst = NULL; Delete skb->dst field Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 4248c31..181b1f3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1394,8 +1394,8 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, struct ipoib_dev_priv *priv = netdev_priv(dev); int e = skb_queue_empty(&priv->cm.skb_queue); - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); skb_queue_tail(&priv->cm.skb_queue, skb); if (e) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 69c6304..e319d91 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -561,7 +561,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) struct ipoib_neigh *neigh; unsigned long flags; - neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); + neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev); if (!neigh) { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -570,9 +570,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->lock, flags); - path = __path_find(dev, skb->dst->neighbour->ha + 4); + path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4); if (!path) { - path = path_rec_create(dev, skb->dst->neighbour->ha + 4); + path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4); if (!path) goto err_path; @@ -605,7 +605,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) goto err_drop; } } else - ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); } else { neigh->ah = NULL; @@ -635,15 +635,15 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(skb->dev); /* Look up path record for unicasts */ - if (skb->dst->neighbour->ha[4] != 0xff) { + if (skb_dst(skb)->neighbour->ha[4] != 0xff) { neigh_add_path(skb, dev); return; } /* Add in the P_Key for multicasts */ - skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; - skb->dst->neighbour->ha[9] = priv->pkey & 0xff; - ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb); + skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; + skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff; + ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb); } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, @@ -708,16 +708,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) struct ipoib_neigh *neigh; unsigned long flags; - if (likely(skb->dst && skb->dst->neighbour)) { - if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { + if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) { + if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) { ipoib_path_lookup(skb, dev); return NETDEV_TX_OK; } - neigh = *to_ipoib_neigh(skb->dst->neighbour); + neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour); if (unlikely((memcmp(&neigh->dgid.raw, - skb->dst->neighbour->ha + 4, + skb_dst(skb)->neighbour->ha + 4, sizeof(union ib_gid))) || (neigh->dev != dev))) { spin_lock_irqsave(&priv->lock, flags); @@ -743,7 +743,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } } else if (neigh->ah) { - ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha)); + ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); return NETDEV_TX_OK; } @@ -772,7 +772,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) && (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) { ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n", - skb->dst ? "neigh" : "dst", + skb_dst(skb) ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), IPOIB_QPN(phdr->hwaddr), phdr->hwaddr + 4); @@ -817,7 +817,7 @@ static int ipoib_hard_header(struct sk_buff *skb, * destination address onto the front of the skb so we can * figure out where to send the packet later. */ - if ((!skb->dst || !skb->dst->neighbour) && daddr) { + if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 425e311..a0e9753 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -261,7 +261,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, skb->dev = dev; - if (!skb->dst || !skb->dst->neighbour) { + if (!skb_dst(skb) || !skb_dst(skb)->neighbour) { /* put pseudoheader back on for next time */ skb_push(skb, sizeof (struct ipoib_pseudoheader)); } @@ -707,10 +707,10 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) out: if (mcast && mcast->ah) { - if (skb->dst && - skb->dst->neighbour && - !*to_ipoib_neigh(skb->dst->neighbour)) { - struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour, + if (skb_dst(skb) && + skb_dst(skb)->neighbour && + !*to_ipoib_neigh(skb_dst(skb)->neighbour)) { + struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev); if (neigh) { diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 5981deb..e7935d0 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -433,8 +433,7 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s * to the inner packet either */ secpath_reset(skb); - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); po = pppox_sk(session_sock); @@ -976,7 +975,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) skb->ip_summed = CHECKSUM_NONE; - else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, @@ -1172,14 +1171,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) nf_reset(skb); /* Get routing info from the tunnel socket */ - dst_release(skb->dst); - skb->dst = dst_clone(__sk_dst_get(sk_tun)); + skb_dst_drop(skb); + skb_dst_set(skb, dst_clone(__sk_dst_get(sk_tun))); pppol2tp_skb_set_owner_w(skb, sk_tun); /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) skb->ip_summed = CHECKSUM_NONE; - else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 2994aa1..74c49d9 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2937,8 +2937,8 @@ int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) if (card->info.type == QETH_CARD_TYPE_OSN) return cast_type; - if (skb->dst && skb->dst->neighbour) { - cast_type = skb->dst->neighbour->type; + if (skb_dst(skb) && skb_dst(skb)->neighbour) { + cast_type = skb_dst(skb)->neighbour->type; if ((cast_type == RTN_BROADCAST) || (cast_type == RTN_MULTICAST) || (cast_type == RTN_ANYCAST)) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index cb64b0b..6f2386e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2549,9 +2549,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, /* IPv4 */ hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); memset(hdr->hdr.l3.dest_addr, 0, 12); - if ((skb->dst) && (skb->dst->neighbour)) { + if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = - *((u32 *) skb->dst->neighbour->primary_key); + *((u32 *) skb_dst(skb)->neighbour->primary_key); } else { /* fill in destination address used in ip header */ *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = @@ -2562,9 +2562,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); if (card->info.type == QETH_CARD_TYPE_IQD) hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; - if ((skb->dst) && (skb->dst->neighbour)) { + if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { memcpy(hdr->hdr.l3.dest_addr, - skb->dst->neighbour->primary_key, 16); + skb_dst(skb)->neighbour->primary_key, 16); } else { /* fill in destination address used in ip header */ memcpy(hdr->hdr.l3.dest_addr, diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a3ae3c5..9ef6eb2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -323,7 +323,6 @@ struct sk_buff { struct net_device *dev; union { - struct dst_entry *dst; unsigned long _skb_dst; }; #ifdef CONFIG_XFRM @@ -426,9 +425,19 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb, enum dma_data_direction dir); #endif +static inline struct dst_entry *skb_dst(const struct sk_buff *skb) +{ + return (struct dst_entry *)skb->_skb_dst; +} + +static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) +{ + skb->_skb_dst = (unsigned long)dst; +} + static inline struct rtable *skb_rtable(const struct sk_buff *skb) { - return (struct rtable *)skb->_skb_dst; + return (struct rtable *)skb_dst(skb); } extern void kfree_skb(struct sk_buff *skb); diff --git a/include/net/dst.h b/include/net/dst.h index 6be3b08..7fc409c 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -195,6 +195,12 @@ struct dst_entry * dst_clone(struct dst_entry * dst) } extern void dst_release(struct dst_entry *dst); +static inline void skb_dst_drop(struct sk_buff *skb) +{ + if (skb->_skb_dst) + dst_release(skb_dst(skb)); + skb->_skb_dst = 0UL; +} /* Children define the path of the packet through the * Linux networking. Thus, destinations are stackable. @@ -246,7 +252,7 @@ static inline void dst_negative_advice(struct dst_entry **dst_p) static inline void dst_link_failure(struct sk_buff *skb) { - struct dst_entry * dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); if (dst && dst->ops && dst->ops->link_failure) dst->ops->link_failure(skb); } @@ -265,13 +271,13 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout) /* Output packet to network from transport. */ static inline int dst_output(struct sk_buff *skb) { - return skb->dst->output(skb); + return skb_dst(skb)->output(skb); } /* Input packet from network to transport. */ static inline int dst_input(struct sk_buff *skb) { - return skb->dst->input(skb); + return skb_dst(skb)->input(skb); } static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie) diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index f74665d..22c73a7 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h @@ -100,7 +100,7 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo, if (unlikely(sk = skb_steal_sock(skb))) return sk; - else return __inet6_lookup(dev_net(skb->dst->dev), hashinfo, + else return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, &ipv6_hdr(skb)->saddr, sport, &ipv6_hdr(skb)->daddr, ntohs(dport), inet6_iif(skb)); diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index a44e224..d522dcf 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -385,7 +385,7 @@ static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo, if (unlikely(sk = skb_steal_sock(skb))) return sk; else - return __inet_lookup(dev_net(skb->dst->dev), hashinfo, + return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, iph->saddr, sport, iph->daddr, dport, inet_iif(skb)); } diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 5f53db7..0e1b8ae 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -142,7 +142,7 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, static inline int ipv6_unicast_destination(struct sk_buff *skb) { - struct rt6_info *rt = (struct rt6_info *) skb->dst; + struct rt6_info *rt = (struct rt6_info *) skb_dst(skb); return rt->rt6i_flags & RTF_LOCAL; } diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 2e9f5c0..736bca4 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -994,7 +994,7 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir, return __xfrm_policy_check(sk, ndir, skb, family); return (!net->xfrm.policy_count[dir] && !skb->sp) || - (skb->dst->flags & DST_NOPOLICY) || + (skb_dst(skb)->flags & DST_NOPOLICY) || __xfrm_policy_check(sk, ndir, skb, family); } @@ -1048,7 +1048,7 @@ static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) struct net *net = dev_net(skb->dev); return !net->xfrm.policy_count[XFRM_POLICY_OUT] || - (skb->dst->flags & DST_NOXFRM) || + (skb_dst(skb)->flags & DST_NOXFRM) || __xfrm_route_forward(skb, family); } diff --git a/net/atm/br2684.c b/net/atm/br2684.c index bfa8fa9..2912665f 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -228,7 +228,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) struct br2684_dev *brdev = BRPRIV(dev); struct br2684_vcc *brvcc; - pr_debug("br2684_start_xmit, skb->dst=%p\n", skb->dst); + pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb)); read_lock(&devs_lock); brvcc = pick_outgoing_vcc(skb, brdev); if (brvcc == NULL) { diff --git a/net/atm/clip.c b/net/atm/clip.c index fb7623c..e65a3b1 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -369,16 +369,16 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; pr_debug("clip_start_xmit (skb %p)\n", skb); - if (!skb->dst) { - printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n"); + if (!skb_dst(skb)) { + printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; return 0; } - if (!skb->dst->neighbour) { + if (!skb_dst(skb)->neighbour) { #if 0 - skb->dst->neighbour = clip_find_neighbour(skb->dst, 1); - if (!skb->dst->neighbour) { + skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1); + if (!skb_dst(skb)->neighbour) { dev_kfree_skb(skb); /* lost that one */ dev->stats.tx_dropped++; return 0; @@ -389,7 +389,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_dropped++; return 0; } - entry = NEIGH2ENTRY(skb->dst->neighbour); + entry = NEIGH2ENTRY(skb_dst(skb)->neighbour); if (!entry->vccs) { if (time_after(jiffies, entry->expires)) { /* should be resolved */ @@ -406,7 +406,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) } pr_debug("neigh %p, vccs %p\n", entry, entry->vccs); ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; - pr_debug("using neighbour %p, vcc %p\n", skb->dst->neighbour, vcc); + pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc); if (entry->vccs->encap) { void *here; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index e0ceb66..d22f611 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -242,7 +242,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) return 0; } dst_hold(&rt->u.dst); - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); skb->dev = nf_bridge->physindev; nf_bridge_push_encap_header(skb); @@ -322,7 +322,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) skb->dev = bridge_parent(skb->dev); if (skb->dev) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); nf_bridge_pull_encap_header(skb); @@ -375,7 +375,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) /* - Bridged-and-DNAT'ed traffic doesn't * require ip_forwarding. */ if (((struct dst_entry *)rt)->dev == dev) { - skb->dst = (struct dst_entry *)rt; + skb_dst_set(skb, (struct dst_entry *)rt); goto bridged_dnat; } /* we are sure that forwarding is disabled, so printing @@ -389,7 +389,7 @@ free_skb: kfree_skb(skb); return 0; } else { - if (skb->dst->dev == dev) { + if (skb_dst(skb)->dev == dev) { bridged_dnat: /* Tell br_nf_local_out this is a * bridged frame */ @@ -412,7 +412,7 @@ bridged_dnat: return 0; } dst_hold(&rt->u.dst); - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); } skb->dev = nf_bridge->physindev; @@ -633,10 +633,8 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb, { struct rtable *rt = skb_rtable(skb); - if (rt && rt == bridge_parent_rtable(in)) { - dst_release(&rt->u.dst); - skb->dst = NULL; - } + if (rt && rt == bridge_parent_rtable(in)) + skb_dst_drop(skb); return NF_ACCEPT; } @@ -851,7 +849,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, return NF_ACCEPT; #ifdef CONFIG_NETFILTER_DEBUG - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL\n"); goto print_error; } diff --git a/net/core/dev.c b/net/core/dev.c index e2fcc5f..34b49a6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1693,10 +1693,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, * If device doesnt need skb->dst, release it right now while * its hot in this cpu cache */ - if ((dev->priv_flags & IFF_XMIT_DST_RELEASE) && skb->dst) { - dst_release(skb->dst); - skb->dst = NULL; - } + if (dev->priv_flags & IFF_XMIT_DST_RELEASE) + skb_dst_drop(skb); + rc = ops->ndo_start_xmit(skb, dev); if (rc == 0) txq_trans_update(txq); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a1cbce7..c54229b 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1088,8 +1088,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, struct neighbour *n1 = neigh; write_unlock_bh(&neigh->lock); /* On shaper/eql skb->dst->neighbour != neigh :( */ - if (skb->dst && skb->dst->neighbour) - n1 = skb->dst->neighbour; + if (skb_dst(skb) && skb_dst(skb)->neighbour) + n1 = skb_dst(skb)->neighbour; n1->output(skb); write_lock_bh(&neigh->lock); } @@ -1182,7 +1182,7 @@ EXPORT_SYMBOL(neigh_compat_output); int neigh_resolve_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh; int rc = 0; @@ -1229,7 +1229,7 @@ EXPORT_SYMBOL(neigh_resolve_output); int neigh_connected_output(struct sk_buff *skb) { int err; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; @@ -1298,8 +1298,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, if (time_before(tbl->proxy_timer.expires, sched_next)) sched_next = tbl->proxy_timer.expires; } - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); dev_hold(skb->dev); __skb_queue_tail(&tbl->proxy_queue, skb); mod_timer(&tbl->proxy_timer, sched_next); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 8e815e6..6adf19e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -381,7 +381,7 @@ static void kfree_skbmem(struct sk_buff *skb) static void skb_release_head_state(struct sk_buff *skb) { - dst_release(skb->dst); + skb_dst_drop(skb); #ifdef CONFIG_XFRM secpath_put(skb->sp); #endif @@ -521,7 +521,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->transport_header = old->transport_header; new->network_header = old->network_header; new->mac_header = old->mac_header; - new->dst = dst_clone(old->dst); + skb_dst_set(new, dst_clone(skb_dst(old))); #ifdef CONFIG_XFRM new->sp = secpath_get(old->sp); #endif diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2cf48ba..a0a36c9 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -507,7 +507,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) const struct iphdr *rxiph; struct sk_buff *skb; struct dst_entry *dst; - struct net *net = dev_net(rxskb->dst->dev); + struct net *net = dev_net(skb_dst(rxskb)->dev); struct sock *ctl_sk = net->dccp.v4_ctl_sk; /* Never send a reset in response to a reset. */ @@ -528,7 +528,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) rxiph = ip_hdr(rxskb); dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr, rxiph->daddr); - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); bh_lock_sock(ctl_sk); err = ip_build_and_send_pkt(skb, ctl_sk, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index b963f35..05ea744 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -314,8 +314,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) struct ipv6hdr *rxip6h; struct sk_buff *skb; struct flowi fl; - struct net *net = dev_net(rxskb->dst->dev); + struct net *net = dev_net(skb_dst(rxskb)->dev); struct sock *ctl_sk = net->dccp.v6_ctl_sk; + struct dst_entry *dst; if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; @@ -342,8 +343,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) security_skb_classify_flow(rxskb, &fl); /* sk = NULL, but it is safe for now. RST socket required. */ - if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) { - if (xfrm_lookup(net, &skb->dst, &fl, NULL, 0) >= 0) { + if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { + if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { + skb_dst_set(skb, dst); ip6_xmit(ctl_sk, skb, &fl, NULL, 0); DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); diff --git a/net/dccp/output.c b/net/dccp/output.c index 36bcc00..c0e88c1 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -350,7 +350,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, /* Reserve space for headers. */ skb_reserve(skb, sk->sk_prot->max_header); - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); dreq = dccp_rsk(req); if (inet_rsk(req)->acked) /* increase ISS upon retransmission */ diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index bccb388..a5e3a59 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1075,6 +1075,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) int err = 0; unsigned char type; long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + struct dst_entry *dst; lock_sock(sk); @@ -1102,8 +1103,9 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) } release_sock(sk); - dst_release(xchg(&newsk->sk_dst_cache, skb->dst)); - skb->dst = NULL; + dst = skb_dst(skb); + dst_release(xchg(&newsk->sk_dst_cache, dst)); + skb_dst_set(skb, NULL); DN_SK(newsk)->state = DN_CR; DN_SK(newsk)->addrrem = cb->src_port; diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 05b5aa0..923786b 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -204,7 +204,7 @@ static void dn_short_error_report(struct neighbour *neigh, struct sk_buff *skb) static int dn_neigh_output_packet(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *)dst; struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; @@ -224,7 +224,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb) static int dn_long_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3; @@ -270,7 +270,7 @@ static int dn_long_output(struct sk_buff *skb) static int dn_short_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; @@ -313,7 +313,7 @@ static int dn_short_output(struct sk_buff *skb) */ static int dn_phase3_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index da04f45..a65e929 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -85,7 +85,7 @@ static void dn_nsp_send(struct sk_buff *skb) dst = sk_dst_check(sk, 0); if (dst) { try_again: - skb->dst = dst; + skb_dst_set(skb, dst); dst_output(skb); return; } @@ -582,7 +582,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, * to be able to send disc packets out which have no socket * associations. */ - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); dst_output(skb); } @@ -611,7 +611,7 @@ void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg, int ddl = 0; gfp_t gfp = GFP_ATOMIC; - dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl, + dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb_dst(skb), ddl, NULL, cb->src_port, cb->dst_port); } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 0cc4394..1d6ca8a 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -678,7 +678,7 @@ out: static int dn_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *)dst; struct net_device *dev = dst->dev; struct dn_skb_cb *cb = DN_SKB_CB(skb); @@ -717,7 +717,7 @@ error: static int dn_forward(struct sk_buff *skb) { struct dn_skb_cb *cb = DN_SKB_CB(skb); - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct dn_dev *dn_db = dst->dev->dn_ptr; struct dn_route *rt; struct neighbour *neigh = dst->neighbour; @@ -730,7 +730,7 @@ static int dn_forward(struct sk_buff *skb) goto drop; /* Ensure that we have enough space for headers */ - rt = (struct dn_route *)skb->dst; + rt = (struct dn_route *)skb_dst(skb); header_len = dn_db->use_long ? 21 : 6; if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len)) goto drop; @@ -1392,7 +1392,8 @@ make_route: goto e_neighbour; hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); - dn_insert_route(rt, hash, (struct dn_route **)&skb->dst); + dn_insert_route(rt, hash, &rt); + skb_dst_set(skb, &rt->u.dst); done: if (neigh) @@ -1424,7 +1425,7 @@ static int dn_route_input(struct sk_buff *skb) struct dn_skb_cb *cb = DN_SKB_CB(skb); unsigned hash = dn_hash(cb->src, cb->dst); - if (skb->dst) + if (skb_dst(skb)) return 0; rcu_read_lock(); @@ -1437,7 +1438,7 @@ static int dn_route_input(struct sk_buff *skb) (rt->fl.iif == cb->iif)) { dst_use(&rt->u.dst, jiffies); rcu_read_unlock(); - skb->dst = (struct dst_entry *)rt; + skb_dst_set(skb, (struct dst_entry *)rt); return 0; } } @@ -1449,7 +1450,7 @@ static int dn_route_input(struct sk_buff *skb) static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait, unsigned int flags) { - struct dn_route *rt = (struct dn_route *)skb->dst; + struct dn_route *rt = (struct dn_route *)skb_dst(skb); struct rtmsg *r; struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); @@ -1554,7 +1555,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void err = dn_route_input(skb); local_bh_enable(); memset(cb, 0, sizeof(struct dn_skb_cb)); - rt = (struct dn_route *)skb->dst; + rt = (struct dn_route *)skb_dst(skb); if (!err && -rt->u.dst.error) err = rt->u.dst.error; } else { @@ -1570,7 +1571,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void skb->dev = NULL; if (err) goto out_free; - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; @@ -1622,15 +1623,15 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) rt = rcu_dereference(rt->u.dst.dn_next), idx++) { if (idx < s_idx) continue; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1, NLM_F_MULTI) <= 0) { - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); rcu_read_unlock_bh(); goto done; } - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); } rcu_read_unlock_bh(); } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 816494f..8a3881e 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -468,7 +468,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) __be32 paddr; struct neighbour *n; - if (!skb->dst) { + if (!skb_dst(skb)) { printk(KERN_DEBUG "arp_find is called with dst==NULL\n"); kfree_skb(skb); return 1; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 94f75ef..97c410e 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -591,13 +591,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) goto relookup_failed; /* Ugh! */ - odst = skb_in->dst; + odst = skb_dst(skb_in); err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src, RT_TOS(tos), rt2->u.dst.dev); dst_release(&rt2->u.dst); rt2 = skb_rtable(skb_in); - skb_in->dst = odst; + skb_dst_set(skb_in, odst); } if (err) @@ -659,7 +659,7 @@ static void icmp_unreach(struct sk_buff *skb) u32 info = 0; struct net *net; - net = dev_net(skb->dst->dev); + net = dev_net(skb_dst(skb)->dev); /* * Incomplete header ? @@ -822,7 +822,7 @@ static void icmp_echo(struct sk_buff *skb) { struct net *net; - net = dev_net(skb->dst->dev); + net = dev_net(skb_dst(skb)->dev); if (!net->ipv4.sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; @@ -873,7 +873,7 @@ static void icmp_timestamp(struct sk_buff *skb) out: return; out_err: - ICMP_INC_STATS_BH(dev_net(skb->dst->dev), ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); goto out; } diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index afabd27..01b4284 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -311,7 +311,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) return NULL; } - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); skb->dev = dev; skb_reserve(skb, LL_RESERVED_SPACE(dev)); @@ -659,7 +659,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, return -1; } - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); skb_reserve(skb, LL_RESERVED_SPACE(dev)); diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 0761cd9..a2991bc 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -42,7 +42,7 @@ static int ip_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); + IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -123,7 +123,7 @@ sr_failed: too_many_hops: /* Tell the sender its packet died... */ - IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_INHDRERRORS); + IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_INHDRERRORS); icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); drop: kfree_skb(skb); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 7985346..1f1b824 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -573,7 +573,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) struct ipq *qp; struct net *net; - net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev); + net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); /* Start by cleaning up the memory. */ diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 85ddad4..44e2a3d 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -643,8 +643,7 @@ static int ipgre_rcv(struct sk_buff *skb) stats->rx_packets++; stats->rx_bytes += len; skb->dev = tunnel->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); skb_reset_network_header(skb); @@ -698,7 +697,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if ((dst = tiph->daddr) == 0) { /* NBMA tunnel */ - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { stats->tx_fifo_errors++; goto tx_error; } @@ -712,7 +711,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) else if (skb->protocol == htons(ETH_P_IPV6)) { struct in6_addr *addr6; int addr_type; - struct neighbour *neigh = skb->dst->neighbour; + struct neighbour *neigh = skb_dst(skb)->neighbour; if (neigh == NULL) goto tx_error; @@ -766,10 +765,10 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (df) mtu = dst_mtu(&rt->u.dst) - dev->hard_header_len - tunnel->hlen; else - mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (skb->protocol == htons(ETH_P_IP)) { df |= (old_iph->frag_off&htons(IP_DF)); @@ -783,14 +782,14 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } #ifdef CONFIG_IPV6 else if (skb->protocol == htons(ETH_P_IPV6)) { - struct rt6_info *rt6 = (struct rt6_info *)skb->dst; + struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); - if (rt6 && mtu < dst_mtu(skb->dst) && mtu >= IPV6_MIN_MTU) { + if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) { if ((tunnel->parms.iph.daddr && !ipv4_is_multicast(tunnel->parms.iph.daddr)) || rt6->rt6i_dst.plen == 128) { rt6->rt6i_flags |= RTF_MODIFIED; - skb->dst->metrics[RTAX_MTU-1] = mtu; + skb_dst(skb)->metrics[RTAX_MTU-1] = mtu; } } @@ -837,8 +836,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index cea784b..490ce20 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -329,7 +329,7 @@ static int ip_rcv_finish(struct sk_buff *skb) * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { @@ -344,9 +344,9 @@ static int ip_rcv_finish(struct sk_buff *skb) } #ifdef CONFIG_NET_CLS_ROUTE - if (unlikely(skb->dst->tclassid)) { + if (unlikely(skb_dst(skb)->tclassid)) { struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id()); - u32 idx = skb->dst->tclassid; + u32 idx = skb_dst(skb)->tclassid; st[idx&0xFF].o_packets++; st[idx&0xFF].o_bytes += skb->len; st[(idx>>16)&0xFF].i_packets++; diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 7e1074f..94bf105 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -143,7 +143,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) __be32 addr; memcpy(&addr, sptr+soffset-1, 4); - if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) { + if (inet_addr_type(dev_net(skb_dst(skb)->dev), addr) != RTN_LOCAL) { dopt->ts_needtime = 1; soffset += 8; } @@ -624,12 +624,12 @@ int ip_options_rcv_srr(struct sk_buff *skb) memcpy(&nexthop, &optptr[srrptr-1], 4); rt = skb_rtable(skb); - skb->dst = NULL; + skb_dst_set(skb, NULL); err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); rt2 = skb_rtable(skb); if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { ip_rt_put(rt2); - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); return -EINVAL; } ip_rt_put(rt); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8d845eb..3d6167f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -95,7 +95,7 @@ int __ip_local_out(struct sk_buff *skb) iph->tot_len = htons(skb->len); ip_send_check(iph); - return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev, + return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, dst_output); } @@ -118,7 +118,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb) __skb_pull(newskb, skb_network_offset(newskb)); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; - WARN_ON(!newskb->dst); + WARN_ON(!skb_dst(newskb)); netif_rx(newskb); return 0; } @@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); static inline int ip_finish_output2(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct rtable *rt = (struct rtable *)dst; struct net_device *dev = dst->dev; unsigned int hh_len = LL_RESERVED_SPACE(dev); @@ -217,14 +217,14 @@ static inline int ip_skb_dst_mtu(struct sk_buff *skb) struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL; return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ? - skb->dst->dev->mtu : dst_mtu(skb->dst); + skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); } static int ip_finish_output(struct sk_buff *skb) { #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) /* Policy lookup after SNAT yielded a new policy */ - if (skb->dst->xfrm != NULL) { + if (skb_dst(skb)->xfrm != NULL) { IPCB(skb)->flags |= IPSKB_REROUTED; return dst_output(skb); } @@ -296,7 +296,7 @@ int ip_mc_output(struct sk_buff *skb) int ip_output(struct sk_buff *skb) { - struct net_device *dev = skb->dst->dev; + struct net_device *dev = skb_dst(skb)->dev; IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len); @@ -355,7 +355,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) } sk_setup_caps(sk, &rt->u.dst); } - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); packet_routed: if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) @@ -401,8 +401,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->pkt_type = from->pkt_type; to->priority = from->priority; to->protocol = from->protocol; - dst_release(to->dst); - to->dst = dst_clone(from->dst); + skb_dst_drop(to); + skb_dst_set(to, dst_clone(skb_dst(from))); to->dev = from->dev; to->mark = from->mark; @@ -1294,7 +1294,7 @@ int ip_push_pending_frames(struct sock *sk) * on dst refcount */ inet->cork.dst = NULL; - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); if (iph->protocol == IPPROTO_ICMP) icmp_out_count(net, ((struct icmphdr *) diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 0c6e7bf..93e2b78 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -370,8 +370,7 @@ static int ipip_rcv(struct sk_buff *skb) tunnel->dev->stats.rx_packets++; tunnel->dev->stats.rx_bytes += skb->len; skb->dev = tunnel->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); ipip_ecn_decapsulate(iph, skb); netif_rx(skb); @@ -447,15 +446,15 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (tiph->frag_off) mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); else - mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; if (mtu < 68) { stats->collisions++; ip_rt_put(rt); goto tx_error; } - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); df |= (old_iph->frag_off&htons(IP_DF)); @@ -502,8 +501,8 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 69dd058..ffd9861 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -651,7 +651,7 @@ static int ipmr_cache_report(struct net *net, ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */ msg = (struct igmpmsg *)skb_network_header(skb); msg->im_vif = vifi; - skb->dst = dst_clone(pkt->dst); + skb_dst_set(skb, dst_clone(skb_dst(pkt))); /* * Add our header @@ -1201,7 +1201,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr) iph->protocol = IPPROTO_IPIP; iph->ihl = 5; iph->tot_len = htons(skb->len); - ip_select_ident(iph, skb->dst, NULL); + ip_select_ident(iph, skb_dst(skb), NULL); ip_send_check(iph); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); @@ -1212,7 +1212,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); + IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -1290,8 +1290,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) vif->pkt_out++; vif->bytes_out += skb->len; - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); ip_decrease_ttl(ip_hdr(skb)); /* FIXME: forward and output firewalls used to be called here. @@ -1543,8 +1543,7 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen) skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); reg_dev->stats.rx_bytes += skb->len; reg_dev->stats.rx_packets++; nf_reset(skb); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index fdf6811..1725dc0 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -12,7 +12,7 @@ /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) { - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); const struct iphdr *iph = ip_hdr(skb); struct rtable *rt; struct flowi fl = {}; @@ -41,8 +41,8 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) return -1; /* Drop old route. */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); } else { /* non-local src, find valid iif to satisfy * rp-filter when calling ip_route_input. */ @@ -50,7 +50,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) if (ip_route_output_key(net, &rt, &fl) != 0) return -1; - odst = skb->dst; + odst = skb_dst(skb); if (ip_route_input(skb, iph->daddr, iph->saddr, RT_TOS(iph->tos), rt->u.dst.dev) != 0) { dst_release(&rt->u.dst); @@ -60,18 +60,22 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) dst_release(odst); } - if (skb->dst->error) + if (skb_dst(skb)->error) return -1; #ifdef CONFIG_XFRM if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && - xfrm_decode_session(skb, &fl, AF_INET) == 0) - if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0)) + xfrm_decode_session(skb, &fl, AF_INET) == 0) { + struct dst_entry *dst = skb_dst(skb); + skb_dst_set(skb, NULL); + if (xfrm_lookup(net, &dst, &fl, skb->sk, 0)) return -1; + skb_dst_set(skb, dst); + } #endif /* Change in oif may mean change in hh_len. */ - hh_len = skb->dst->dev->hard_header_len; + hh_len = skb_dst(skb)->dev->hard_header_len; if (skb_headroom(skb) < hh_len && pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC)) return -1; @@ -92,7 +96,7 @@ int ip_xfrm_me_harder(struct sk_buff *skb) if (xfrm_decode_session(skb, &fl, AF_INET) < 0) return -1; - dst = skb->dst; + dst = skb_dst(skb); if (dst->xfrm) dst = ((struct xfrm_dst *)dst)->route; dst_hold(dst); @@ -100,11 +104,11 @@ int ip_xfrm_me_harder(struct sk_buff *skb) if (xfrm_lookup(dev_net(dst->dev), &dst, &fl, skb->sk, 0) < 0) return -1; - dst_release(skb->dst); - skb->dst = dst; + skb_dst_drop(skb); + skb_dst_set(skb, dst); /* Change in oif may mean change in hh_len. */ - hh_len = skb->dst->dev->hard_header_len; + hh_len = skb_dst(skb)->dev->hard_header_len; if (skb_headroom(skb) < hh_len && pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC)) return -1; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 0b4b6e0..c93ae44 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -108,17 +108,16 @@ static void send_reset(struct sk_buff *oldskb, int hook) addr_type = RTN_LOCAL; /* ip_route_me_harder expects skb->dst to be set */ - dst_hold(oldskb->dst); - nskb->dst = oldskb->dst; + skb_dst_set(nskb, dst_clone(skb_dst(oldskb))); if (ip_route_me_harder(nskb, addr_type)) goto free_nskb; - niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); + niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); nskb->ip_summed = CHECKSUM_NONE; /* "Never happens" */ - if (nskb->len > dst_mtu(nskb->dst)) + if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index b7dd695..5567bd0 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -167,10 +167,9 @@ nf_nat_in(unsigned int hooknum, ret = nf_nat_fn(hooknum, skb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && - daddr != ip_hdr(skb)->daddr) { - dst_release(skb->dst); - skb->dst = NULL; - } + daddr != ip_hdr(skb)->daddr) + skb_dst_drop(skb); + return ret; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index f774651..3dc9171 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -343,7 +343,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); skb_reset_network_header(skb); iph = ip_hdr(skb); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f20060a..a849bb1 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1118,7 +1118,7 @@ restart: if (rp) *rp = rth; else - skb->dst = &rth->u.dst; + skb_dst_set(skb, &rth->u.dst); return 0; } @@ -1217,7 +1217,7 @@ restart: if (rp) *rp = rt; else - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); return 0; } @@ -2251,7 +2251,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); rcu_read_unlock(); - skb->dst = &rth->u.dst; + skb_dst_set(skb, &rth->u.dst); return 0; } RT_CACHE_STAT_INC(in_hlist_search); @@ -2934,7 +2934,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (err) goto errout_free; - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; @@ -2975,15 +2975,15 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) continue; if (rt_is_expired(rt)) continue; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1, NLM_F_MULTI) <= 0) { - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); rcu_read_unlock_bh(); goto done; } - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); } rcu_read_unlock_bh(); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 319c885..5a1ca26 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -590,7 +590,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.csumoffset = offsetof(struct tcphdr, check) / 2; arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0; - net = dev_net(skb->dst->dev); + net = dev_net(skb_dst(skb)->dev); ip_send_reply(net->ipv4.tcp_sock, skb, &arg, arg.iov[0].iov_len); @@ -617,7 +617,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, ]; } rep; struct ip_reply_arg arg; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof(arg)); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 79c39dc..416fc4c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2202,7 +2202,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, /* Reserve space for headers. */ skb_reserve(skb, MAX_TCP_HEADER); - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); mss = dst_metric(dst, RTAX_ADVMSS); if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7a1d1ce..8f4158d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -328,7 +328,7 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, if (unlikely(sk = skb_steal_sock(skb))) return sk; else - return __udp4_lib_lookup(dev_net(skb->dst->dev), iph->saddr, sport, + return __udp4_lib_lookup(dev_net(skb_dst(skb)->dev), iph->saddr, sport, iph->daddr, dport, inet_iif(skb), udptable); } @@ -1237,7 +1237,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, struct sock *sk; struct udphdr *uh; unsigned short ulen; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb_rtable(skb); __be32 saddr, daddr; struct net *net = dev_net(skb->dev); diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 4ec2162..f9f922a 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -23,7 +23,7 @@ int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb) static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) { - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { const struct iphdr *iph = ip_hdr(skb); if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 7135279..3444f3b 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -28,7 +28,7 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb) */ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct iphdr *top_iph; int flags; @@ -41,7 +41,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->ihl = 5; top_iph->version = 4; - top_iph->protocol = xfrm_af2proto(skb->dst->ops->family); + top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); /* DS disclosed */ top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos, diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 8c3180a..c908bd9 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -29,7 +29,7 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df) goto out; - dst = skb->dst; + dst = skb_dst(skb); mtu = dst_mtu(dst); if (skb->len > mtu) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); @@ -72,7 +72,7 @@ EXPORT_SYMBOL(xfrm4_prepare_output); static int xfrm4_output_finish(struct sk_buff *skb) { #ifdef CONFIG_NETFILTER - if (!skb->dst->xfrm) { + if (!skb_dst(skb)->xfrm) { IPCB(skb)->flags |= IPSKB_REROUTED; return dst_output(skb); } @@ -87,6 +87,6 @@ static int xfrm4_output_finish(struct sk_buff *skb) int xfrm4_output(struct sk_buff *skb) { return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb, - NULL, skb->dst->dev, xfrm4_output_finish, + NULL, skb_dst(skb)->dev, xfrm4_output_finish, !(IPCB(skb)->flags & IPSKB_REROUTED)); } diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 1c7f400..4aae658 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -277,7 +277,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb) if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || !pskb_may_pull(skb, (skb_transport_offset(skb) + ((skb_transport_header(skb)[1] + 1) << 3)))) { - IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); kfree_skb(skb); return -1; @@ -288,7 +288,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb) dstbuf = opt->dst1; #endif - dst = dst_clone(skb->dst); + dst = dst_clone(skb_dst(skb)); if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { dst_release(dst); skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; @@ -333,7 +333,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || !pskb_may_pull(skb, (skb_transport_offset(skb) + ((skb_transport_header(skb)[1] + 1) << 3)))) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); kfree_skb(skb); return -1; @@ -343,7 +343,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || skb->pkt_type != PACKET_HOST) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -358,7 +358,7 @@ looped_back: * processed by own */ if (!addr) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -384,7 +384,7 @@ looped_back: goto unknown_rh; /* Silently discard invalid RTH type 2 */ if (hdr->hdrlen != 2 || hdr->segments_left != 1) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); kfree_skb(skb); return -1; @@ -403,7 +403,7 @@ looped_back: n = hdr->hdrlen >> 1; if (hdr->segments_left > n) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ((&hdr->segments_left) - @@ -417,7 +417,7 @@ looped_back: if (skb_cloned(skb)) { /* the copy is a forwarded packet */ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); return -1; @@ -440,13 +440,13 @@ looped_back: if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr, IPPROTO_ROUTING) < 0) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; } - if (!ipv6_chk_home_addr(dev_net(skb->dst->dev), addr)) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) { + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -458,7 +458,7 @@ looped_back: } if (ipv6_addr_is_multicast(addr)) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -468,17 +468,17 @@ looped_back: ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr); ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr); - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); ip6_route_input(skb); - if (skb->dst->error) { + if (skb_dst(skb)->error) { skb_push(skb, skb->data - skb_network_header(skb)); dst_input(skb); return -1; } - if (skb->dst->dev->flags&IFF_LOOPBACK) { + if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) { if (ipv6_hdr(skb)->hop_limit <= 1) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0, skb->dev); @@ -494,7 +494,7 @@ looped_back: return -1; unknown_rh: - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb_network_header(skb)); return -1; @@ -552,11 +552,11 @@ void ipv6_exthdrs_exit(void) **********************************/ /* - * Note: we cannot rely on skb->dst before we assign it in ip6_route_input(). + * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input(). */ static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb) { - return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev); + return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev); } /* Router Alert as of RFC 2711 */ @@ -581,7 +581,7 @@ static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) { const unsigned char *nh = skb_network_header(skb); u32 pkt_len; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 3c3732d..cc4797d 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -228,7 +228,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) __inet6_csk_dst_store(sk, dst, NULL, NULL); } - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); /* Restore final destination back after routing done */ ipv6_addr_copy(&fl.fl6_dst, &np->daddr); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index bc1a920..c3a07d7 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -48,7 +48,7 @@ inline int ip6_rcv_finish( struct sk_buff *skb) { - if (skb->dst == NULL) + if (skb_dst(skb) == NULL) ip6_route_input(skb); return dst_input(skb); @@ -91,7 +91,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt * arrived via the sending interface (ethX), because of the * nature of scoping architecture. --yoshfuji */ - IP6CB(skb)->iif = skb->dst ? ip6_dst_idev(skb->dst)->dev->ifindex : dev->ifindex; + IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) goto err; @@ -161,7 +161,7 @@ static int ip6_input_finish(struct sk_buff *skb) int nexthdr, raw; u8 hash; struct inet6_dev *idev; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); /* * Parse extension headers @@ -169,7 +169,7 @@ static int ip6_input_finish(struct sk_buff *skb) rcu_read_lock(); resubmit: - idev = ip6_dst_idev(skb->dst); + idev = ip6_dst_idev(skb_dst(skb)); if (!pskb_pull(skb, skb_transport_offset(skb))) goto discard; nhoff = IP6CB(skb)->nhoff; @@ -242,8 +242,8 @@ int ip6_mc_input(struct sk_buff *skb) struct ipv6hdr *hdr; int deliver; - IP6_UPD_PO_STATS_BH(dev_net(skb->dst->dev), - ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCAST, + IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev), + ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST, skb->len); hdr = ipv6_hdr(skb); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 735a2bf..c8dc8e5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -78,7 +78,7 @@ int __ip6_local_out(struct sk_buff *skb) len = 0; ipv6_hdr(skb)->payload_len = htons(len); - return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev, + return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, dst_output); } @@ -96,7 +96,7 @@ EXPORT_SYMBOL_GPL(ip6_local_out); static int ip6_output_finish(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); if (dst->hh) return neigh_hh_output(dst->hh, skb); @@ -117,7 +117,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) __skb_pull(newskb, skb_network_offset(newskb)); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; - WARN_ON(!newskb->dst); + WARN_ON(!skb_dst(newskb)); netif_rx(newskb); return 0; @@ -126,7 +126,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) static int ip6_output2(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct net_device *dev = dst->dev; skb->protocol = htons(ETH_P_IPV6); @@ -134,7 +134,7 @@ static int ip6_output2(struct sk_buff *skb) if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; - struct inet6_dev *idev = ip6_dst_idev(skb->dst); + struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && ((mroute6_socket(dev_net(dev)) && @@ -172,21 +172,21 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ? - skb->dst->dev->mtu : dst_mtu(skb->dst); + skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); } int ip6_output(struct sk_buff *skb) { - struct inet6_dev *idev = ip6_dst_idev(skb->dst); + struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); if (unlikely(idev->cnf.disable_ipv6)) { - IP6_INC_STATS(dev_net(skb->dst->dev), idev, + IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev, IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); return 0; } if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || - dst_allfrag(skb->dst)) + dst_allfrag(skb_dst(skb))) return ip6_fragment(skb, ip6_output2); else return ip6_output2(skb); @@ -202,7 +202,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, struct net *net = sock_net(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct in6_addr *first_hop = &fl->fl6_dst; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct ipv6hdr *hdr; u8 proto = fl->proto; int seg_len = skb->len; @@ -222,7 +222,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, if (skb_headroom(skb) < head_room) { struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); if (skb2 == NULL) { - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); return -ENOBUFS; @@ -276,7 +276,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, mtu = dst_mtu(dst); if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) { - IP6_UPD_PO_STATS(net, ip6_dst_idev(skb->dst), + IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUT, skb->len); return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, dst_output); @@ -286,7 +286,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); kfree_skb(skb); return -EMSGSIZE; } @@ -416,7 +416,7 @@ static inline int ip6_forward_finish(struct sk_buff *skb) int ip6_forward(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct ipv6hdr *hdr = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); struct net *net = dev_net(dst->dev); @@ -485,7 +485,7 @@ int ip6_forward(struct sk_buff *skb) IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); goto drop; } - dst = skb->dst; + dst = skb_dst(skb); /* IPv6 specs say nothing about it, but it is clear that we cannot send redirects to source routed frames. @@ -566,8 +566,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->pkt_type = from->pkt_type; to->priority = from->priority; to->protocol = from->protocol; - dst_release(to->dst); - to->dst = dst_clone(from->dst); + skb_dst_drop(to); + skb_dst_set(to, dst_clone(skb_dst(from))); to->dev = from->dev; to->mark = from->mark; @@ -624,7 +624,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { struct sk_buff *frag; - struct rt6_info *rt = (struct rt6_info*)skb->dst; + struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; @@ -632,7 +632,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) __be32 frag_id = 0; int ptr, offset = 0, err=0; u8 *prevhdr, nexthdr = 0; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); hlen = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; @@ -644,9 +644,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) * check should be redundant, but it's free.) */ if (!skb->local_df) { - skb->dev = skb->dst->dev; + skb->dev = skb_dst(skb)->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); kfree_skb(skb); return -EMSGSIZE; @@ -696,7 +696,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) *prevhdr = NEXTHDR_FRAGMENT; tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC); if (!tmp_hdr) { - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); return -ENOMEM; } @@ -809,7 +809,7 @@ slow_path: if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); err = -ENOMEM; goto fail; @@ -873,16 +873,16 @@ slow_path: if (err) goto fail; - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGCREATES); } - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGOKS); kfree_skb(skb); return err; fail: - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); kfree_skb(skb); return err; @@ -1516,10 +1516,10 @@ int ip6_push_pending_frames(struct sock *sk) skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); if (proto == IPPROTO_ICMPV6) { - struct inet6_dev *idev = ip6_dst_idev(skb->dst); + struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type); ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); @@ -1545,8 +1545,8 @@ void ip6_flush_pending_frames(struct sock *sk) struct sk_buff *skb; while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { - if (skb->dst) - IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb->dst), + if (skb_dst(skb)) + IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index af256d4..404d16a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -532,8 +532,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (!skb2) return 0; - dst_release(skb2->dst); - skb2->dst = NULL; + skb_dst_drop(skb2); + skb_pull(skb2, offset); skb_reset_network_header(skb2); eiph = ip_hdr(skb2); @@ -560,21 +560,21 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ip_rt_put(rt); goto out; } - skb2->dst = (struct dst_entry *)rt; + skb_dst_set(skb2, (struct dst_entry *)rt); } else { ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) || - skb2->dst->dev->type != ARPHRD_TUNNEL) + skb_dst(skb2)->dev->type != ARPHRD_TUNNEL) goto out; } /* change mtu on this route */ if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) { - if (rel_info > dst_mtu(skb2->dst)) + if (rel_info > dst_mtu(skb_dst(skb2))) goto out; - skb2->dst->ops->update_pmtu(skb2->dst, rel_info); + skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info); } icmp_send(skb2, rel_type, rel_code, htonl(rel_info)); @@ -606,8 +606,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (!skb2) return 0; - dst_release(skb2->dst); - skb2->dst = NULL; + skb_dst_drop(skb2); skb_pull(skb2, offset); skb_reset_network_header(skb2); @@ -720,8 +719,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, skb->pkt_type = PACKET_HOST; memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); skb->dev = t->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); dscp_ecn_decapsulate(t, ipv6h, skb); @@ -885,8 +883,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, } if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (skb->len > mtu) { *pmtu = mtu; err = -EMSGSIZE; @@ -910,8 +908,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, kfree_skb(skb); skb = new_skb; } - dst_release(skb->dst); - skb->dst = dst_clone(dst); + skb_dst_drop(skb); + skb_dst_set(skb, dst_clone(dst)); skb->transport_header = skb->network_header; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 228be55..a35d8fc 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -398,10 +398,9 @@ static int pim6_rcv(struct sk_buff *skb) skb->protocol = htons(ETH_P_IPV6); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; - dst_release(skb->dst); + skb_dst_drop(skb); reg_dev->stats.rx_bytes += skb->len; reg_dev->stats.rx_packets++; - skb->dst = NULL; nf_reset(skb); netif_rx(skb); dev_put(reg_dev); @@ -849,7 +848,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); - skb->dst = dst_clone(pkt->dst); + skb_dst_set(skb, dst_clone(skb_dst(pkt))); skb->ip_summed = CHECKSUM_UNNECESSARY; } @@ -1487,7 +1486,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) static inline int ip6mr_forward2_finish(struct sk_buff *skb) { - IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTFORWDATAGRAMS); return dst_output(skb); } @@ -1532,8 +1531,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) if (!dst) goto out_free; - dst_release(skb->dst); - skb->dst = dst; + skb_dst_drop(skb); + skb_dst_set(skb, dst); /* * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally @@ -1722,7 +1721,7 @@ int ip6mr_get_route(struct net *net, { int err; struct mfc6_cache *cache; - struct rt6_info *rt = (struct rt6_info *)skb->dst; + struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); read_lock(&mrt_lock); cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 4b48819..4b264ed 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1448,6 +1448,7 @@ static void mld_sendpack(struct sk_buff *skb) struct net *net = dev_net(skb->dev); int err; struct flowi fl; + struct dst_entry *dst; IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); @@ -1459,9 +1460,9 @@ static void mld_sendpack(struct sk_buff *skb) IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), mldlen, 0)); - skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); + dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); - if (!skb->dst) { + if (!dst) { err = -ENOMEM; goto err_out; } @@ -1470,7 +1471,8 @@ static void mld_sendpack(struct sk_buff *skb) &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0); + err = xfrm_lookup(net, &dst, &fl, NULL, 0); + skb_dst_set(skb, dst); if (err) goto err_out; @@ -1775,6 +1777,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) IPV6_TLV_ROUTERALERT, 2, 0, 0, IPV6_TLV_PADN, 0 }; struct flowi fl; + struct dst_entry *dst; if (type == ICMPV6_MGM_REDUCTION) snd_addr = &in6addr_linklocal_allrouters; @@ -1828,8 +1831,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) idev = in6_dev_get(skb->dev); - skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); - if (!skb->dst) { + dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); + if (!dst) { err = -ENOMEM; goto err_out; } @@ -1838,11 +1841,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0); + err = xfrm_lookup(net, &dst, &fl, NULL, 0); if (err) goto err_out; - + skb_dst_set(skb, dst); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, dst_output); out: diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1d13d99..9eb68e9 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -530,7 +530,7 @@ void ndisc_send_skb(struct sk_buff *skb, return; } - skb->dst = dst; + skb_dst_set(skb, dst); idev = in6_dev_get(dst->dev); IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); @@ -1612,7 +1612,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, len, IPPROTO_ICMPV6, csum_partial(icmph, len, 0)); - buff->dst = dst; + skb_dst_set(buff, dst); idev = in6_dev_get(dst->dev); IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 834cea6..d5ed92b 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -12,7 +12,7 @@ int ip6_route_me_harder(struct sk_buff *skb) { - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); struct ipv6hdr *iph = ipv6_hdr(skb); struct dst_entry *dst; struct flowi fl = { @@ -28,9 +28,15 @@ int ip6_route_me_harder(struct sk_buff *skb) #ifdef CONFIG_XFRM if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && - xfrm_decode_session(skb, &fl, AF_INET6) == 0) - if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0)) + xfrm_decode_session(skb, &fl, AF_INET6) == 0) { + struct dst_entry *dst2 = skb_dst(skb); + + if (xfrm_lookup(net, &dst2, &fl, skb->sk, 0)) { + skb_dst_set(skb, NULL); return -1; + } + skb_dst_set(skb, dst2); + } #endif if (dst->error) { @@ -41,9 +47,9 @@ int ip6_route_me_harder(struct sk_buff *skb) } /* Drop old route. */ - dst_release(skb->dst); + skb_dst_drop(skb); - skb->dst = dst; + skb_dst_set(skb, dst); return 0; } EXPORT_SYMBOL(ip6_route_me_harder); diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 5a2d0a4..5a7f00c 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -112,7 +112,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) return; } - nskb->dst = dst; + skb_dst_set(nskb, dst); skb_reserve(nskb, hh_len + dst->header_len); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e99307f..36a090d 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -625,7 +625,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); skb_put(skb, length); skb_reset_network_header(skb); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index e9ac7a1..54a387d 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -267,7 +267,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, struct sk_buff *prev, *next; struct net_device *dev; int offset, end; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); if (fq->q.last_in & INET_FRAG_COMPLETE) goto err; @@ -277,7 +277,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); if ((unsigned int)end > IPV6_MAXPLEN) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ((u8 *)&fhdr->frag_off - @@ -310,7 +310,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, /* RFC2460 says always send parameter problem in * this case. -DaveM */ - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, offsetof(struct ipv6hdr, payload_len)); @@ -434,7 +434,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, return -1; err: - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -1; @@ -576,9 +576,9 @@ static int ipv6_frag_rcv(struct sk_buff *skb) struct frag_hdr *fhdr; struct frag_queue *fq; struct ipv6hdr *hdr = ipv6_hdr(skb); - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); /* Jumbo payload inhibits frag. header */ if (hdr->payload_len==0) @@ -595,17 +595,17 @@ static int ipv6_frag_rcv(struct sk_buff *skb) /* It is not a fragmented frame */ skb->transport_header += sizeof(struct frag_hdr); IP6_INC_STATS_BH(net, - ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS); + ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMOKS); IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb); return 1; } if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) - ip6_evictor(net, ip6_dst_idev(skb->dst)); + ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, - ip6_dst_idev(skb->dst))) != NULL) { + ip6_dst_idev(skb_dst(skb)))) != NULL) { int ret; spin_lock(&fq->q.lock); @@ -617,12 +617,12 @@ static int ipv6_frag_rcv(struct sk_buff *skb) return ret; } - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -1; fail_hdr: - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); return -1; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 032a5ec..658293e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -800,7 +800,7 @@ void ip6_route_input(struct sk_buff *skb) if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) flags |= RT6_LOOKUP_F_IFACE; - skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); + skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input)); } static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, @@ -911,7 +911,7 @@ static void ip6_link_failure(struct sk_buff *skb) icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); - rt = (struct rt6_info *) skb->dst; + rt = (struct rt6_info *) skb_dst(skb); if (rt) { if (rt->rt6i_flags&RTF_CACHE) { dst_set_expires(&rt->u.dst, 0); @@ -1868,7 +1868,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) static int ip6_pkt_drop(struct sk_buff *skb, int code, int ipstats_mib_noroutes) { int type; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); switch (ipstats_mib_noroutes) { case IPSTATS_MIB_INNOROUTES: type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); @@ -1895,7 +1895,7 @@ static int ip6_pkt_discard(struct sk_buff *skb) static int ip6_pkt_discard_out(struct sk_buff *skb) { - skb->dev = skb->dst->dev; + skb->dev = skb_dst(skb)->dev; return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES); } @@ -1908,7 +1908,7 @@ static int ip6_pkt_prohibit(struct sk_buff *skb) static int ip6_pkt_prohibit_out(struct sk_buff *skb) { - skb->dev = skb->dst->dev; + skb->dev = skb_dst(skb)->dev; return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); } @@ -2366,7 +2366,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index b3a59bd..68e5230 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -575,8 +575,7 @@ static int ipip6_rcv(struct sk_buff *skb) tunnel->dev->stats.rx_packets++; tunnel->dev->stats.rx_bytes += skb->len; skb->dev = tunnel->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); ipip6_ecn_decapsulate(iph, skb); netif_rx(skb); @@ -638,8 +637,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (dev->priv_flags & IFF_ISATAP) { struct neighbour *neigh = NULL; - if (skb->dst) - neigh = skb->dst->neighbour; + if (skb_dst(skb)) + neigh = skb_dst(skb)->neighbour; if (neigh == NULL) { if (net_ratelimit()) @@ -663,8 +662,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!dst) { struct neighbour *neigh = NULL; - if (skb->dst) - neigh = skb->dst->neighbour; + if (skb_dst(skb)) + neigh = skb_dst(skb)->neighbour; if (neigh == NULL) { if (net_ratelimit()) @@ -714,7 +713,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (tiph->frag_off) mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); else - mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; if (mtu < 68) { stats->collisions++; @@ -723,8 +722,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (tunnel->parms.iph.daddr && skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (tunnel->parms.iph.daddr && skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (skb->len > mtu) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); @@ -768,8 +767,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb_reset_network_header(skb); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); IPCB(skb)->flags = 0; - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ea37741..53b6a41 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -981,9 +981,10 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); + struct dst_entry *dst; __be32 *topt; if (ts) @@ -1052,8 +1053,9 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, * Underlying function will use this to retrieve the network * namespace */ - if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { - if (xfrm_lookup(net, &buff->dst, &fl, NULL, 0) >= 0) { + if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { + if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { + skb_dst_set(buff, dst); ip6_xmit(ctl_sk, buff, &fl, NULL, 0); TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); if (rst) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8905712..fc333d8 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -177,10 +177,9 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, if (unlikely(sk = skb_steal_sock(skb))) return sk; - else - return __udp6_lib_lookup(dev_net(skb->dst->dev), &iph->saddr, sport, - &iph->daddr, dport, inet6_iif(skb), - udptable); + return __udp6_lib_lookup(dev_net(skb_dst(skb)->dev), &iph->saddr, sport, + &iph->daddr, dport, inet6_iif(skb), + udptable); } /* diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index e20529b..3927832 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -31,7 +31,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) */ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct ipv6hdr *top_iph; int dsfield; @@ -45,7 +45,7 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, sizeof(top_iph->flow_lbl)); - top_iph->nexthdr = xfrm_af2proto(skb->dst->ops->family); + top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); dsfield = XFRM_MODE_SKB_CB(skb)->tos; dsfield = INET_ECN_encapsulate(dsfield, dsfield); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 5ee5a03..c4f4eef 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -30,7 +30,7 @@ EXPORT_SYMBOL(xfrm6_find_1stfragopt); static int xfrm6_tunnel_check_size(struct sk_buff *skb) { int mtu, ret = 0; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); mtu = dst_mtu(dst); if (mtu < IPV6_MIN_MTU) @@ -90,6 +90,6 @@ static int xfrm6_output_finish(struct sk_buff *skb) int xfrm6_output(struct sk_buff *skb) { - return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dst->dev, + return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev, xfrm6_output_finish); } diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 425ab144..5874657 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -260,8 +260,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_send_check(ip_hdr(skb)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -324,8 +324,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, } /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -388,8 +388,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) @@ -465,8 +465,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) @@ -553,8 +553,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n"); goto tx_error; } - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); df |= (old_iph->frag_off & htons(IP_DF)); @@ -596,8 +596,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. @@ -665,8 +665,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n"); goto tx_error; } - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); @@ -702,8 +702,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. @@ -775,8 +775,8 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_send_check(ip_hdr(skb)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -828,8 +828,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, } /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -900,8 +900,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop the old route when skb is not shared */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); ip_vs_nat_icmp(skb, pp, cp, 0); @@ -975,8 +975,8 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop the old route when skb is not shared */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); ip_vs_nat_icmp_v6(skb, pp, cp, 0); diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 117b801..a6d6ec3 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -176,7 +176,7 @@ static bool gre_invert_tuple(struct nf_conntrack_tuple *tuple, static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, struct nf_conntrack_tuple *tuple) { - struct net *net = dev_net(skb->dev ? skb->dev : skb->dst->dev); + struct net *net = dev_net(skb->dev ? skb->dev : skb_dst(skb)->dev); const struct gre_hdr_pptp *pgrehdr; struct gre_hdr_pptp _pgrehdr; __be16 srckey; diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 4f3b1f8..eda64c1 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -73,11 +73,11 @@ tcpmss_mangle_packet(struct sk_buff *skb, } if (info->mss == XT_TCPMSS_CLAMP_PMTU) { - if (dst_mtu(skb->dst) <= minlen) { + if (dst_mtu(skb_dst(skb)) <= minlen) { if (net_ratelimit()) printk(KERN_ERR "xt_TCPMSS: " "unknown or invalid path-MTU (%u)\n", - dst_mtu(skb->dst)); + dst_mtu(skb_dst(skb))); return -1; } if (in_mtu <= minlen) { @@ -86,7 +86,7 @@ tcpmss_mangle_packet(struct sk_buff *skb, "invalid path-MTU (%u)\n", in_mtu); return -1; } - newmss = min(dst_mtu(skb->dst), in_mtu) - minlen; + newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen; } else newmss = info->mss; diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c index 328bd20..4cbfebd 100644 --- a/net/netfilter/xt_policy.c +++ b/net/netfilter/xt_policy.c @@ -86,7 +86,7 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info, unsigned short family) { const struct xt_policy_elem *e; - const struct dst_entry *dst = skb->dst; + const struct dst_entry *dst = skb_dst(skb); int strict = info->flags & XT_POLICY_MATCH_STRICT; int i, pos; diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c index 6741928..484d168 100644 --- a/net/netfilter/xt_realm.c +++ b/net/netfilter/xt_realm.c @@ -25,7 +25,7 @@ static bool realm_mt(const struct sk_buff *skb, const struct xt_match_param *par) { const struct xt_realm_info *info = par->matchinfo; - const struct dst_entry *dst = skb->dst; + const struct dst_entry *dst = skb_dst(skb); return (info->id == (dst->tclassid & info->mask)) ^ info->invert; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6da9f38..4f76e55 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -372,8 +372,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct goto oom; /* drop any routing info */ - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); /* drop conntrack reference */ nf_reset(skb); @@ -621,8 +620,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet skb_set_owner_r(skb, sk); skb->dev = NULL; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); /* drop conntrack reference */ nf_reset(skb); diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 0ef4e30..9402a7f 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -84,7 +84,7 @@ static u32 flow_get_dst(const struct sk_buff *skb) case htons(ETH_P_IPV6): return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); default: - return addr_fold(skb->dst) ^ (__force u16)skb->protocol; + return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; } } @@ -163,7 +163,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb) break; } default: - res = addr_fold(skb->dst) ^ (__force u16)skb->protocol; + res = addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; } return res; @@ -251,8 +251,8 @@ fallback: static u32 flow_get_rtclassid(const struct sk_buff *skb) { #ifdef CONFIG_NET_CLS_ROUTE - if (skb->dst) - return skb->dst->tclassid; + if (skb_dst(skb)) + return skb_dst(skb)->tclassid; #endif return 0; } diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index bdf1f41..dd872d5 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -137,7 +137,7 @@ static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp, u32 id, h; int iif, dont_cache = 0; - if ((dst = skb->dst) == NULL) + if ((dst = skb_dst(skb)) == NULL) goto failure; id = dst->tclassid; diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index b6b588b..266151a 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -246,11 +246,11 @@ META_COLLECTOR(int_tcindex) META_COLLECTOR(int_rtclassid) { - if (unlikely(skb->dst == NULL)) + if (unlikely(skb_dst(skb) == NULL)) *err = -1; else #ifdef CONFIG_NET_CLS_ROUTE - dst->value = skb->dst->tclassid; + dst->value = skb_dst(skb)->tclassid; #else dst->value = 0; #endif diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 33133d2..8706920 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -149,7 +149,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) break; } default: - h = (unsigned long)skb->dst ^ skb->protocol; + h = (unsigned long)skb_dst(skb) ^ skb->protocol; h2 = (unsigned long)skb->sk; } diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index a886496..cb1cb1e 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -222,7 +222,7 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * { struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0); struct teql_sched_data *q = qdisc_priv(dev_queue->qdisc); - struct neighbour *mn = skb->dst->neighbour; + struct neighbour *mn = skb_dst(skb)->neighbour; struct neighbour *n = q->ncache; if (mn->tbl == NULL) @@ -262,8 +262,8 @@ static inline int teql_resolve(struct sk_buff *skb, return -ENODEV; if (dev->header_ops == NULL || - skb->dst == NULL || - skb->dst->neighbour == NULL) + skb_dst(skb) == NULL || + skb_dst(skb)->neighbour == NULL) return 0; return __teql_resolve(skb, skb_res, dev); } diff --git a/net/sctp/output.c b/net/sctp/output.c index f0c91df..b764114 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -405,10 +405,10 @@ int sctp_packet_transmit(struct sctp_packet *packet) sctp_assoc_sync_pmtu(asoc); } } - nskb->dst = dst_clone(tp->dst); - if (!nskb->dst) + dst = dst_clone(tp->dst); + skb_dst_set(nskb, dst); + if (dst) goto no_route; - dst = nskb->dst; /* Build the SCTP header. */ sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e185961..6c2d615 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -918,7 +918,7 @@ static void xs_udp_data_ready(struct sock *sk, int len) UDPX_INC_STATS_BH(sk, UDP_MIB_INDATAGRAMS); /* Something worked... */ - dst_confirm(skb->dst); + dst_confirm(skb_dst(skb)); xprt_adjust_cwnd(task, copied); xprt_update_rtt(task); diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b4a1317..e0009c1 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -251,8 +251,7 @@ resume: nf_reset(skb); if (decaps) { - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); netif_rx(skb); return 0; } else { diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index c235597..b9fe131 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -22,7 +22,7 @@ static int xfrm_output2(struct sk_buff *skb); static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev) - skb_headroom(skb); int ntail = dst->dev->needed_tailroom - skb_tailroom(skb); @@ -39,7 +39,7 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) static int xfrm_output_one(struct sk_buff *skb, int err) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct xfrm_state *x = dst->xfrm; struct net *net = xs_net(x); @@ -94,12 +94,13 @@ resume: goto error_nolock; } - if (!(skb->dst = dst_pop(dst))) { + dst = dst_pop(dst); + if (!dst) { XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); err = -EHOSTUNREACH; goto error_nolock; } - dst = skb->dst; + skb_dst_set(skb, dst); x = dst->xfrm; } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)); @@ -119,16 +120,16 @@ int xfrm_output_resume(struct sk_buff *skb, int err) while (likely((err = xfrm_output_one(skb, err)) == 0)) { nf_reset(skb); - err = skb->dst->ops->local_out(skb); + err = skb_dst(skb)->ops->local_out(skb); if (unlikely(err != 1)) goto out; - if (!skb->dst->xfrm) + if (!skb_dst(skb)->xfrm) return dst_output(skb); - err = nf_hook(skb->dst->ops->family, + err = nf_hook(skb_dst(skb)->ops->family, NF_INET_POST_ROUTING, skb, - NULL, skb->dst->dev, xfrm_output2); + NULL, skb_dst(skb)->dev, xfrm_output2); if (unlikely(err != 1)) goto out; } @@ -179,7 +180,7 @@ static int xfrm_output_gso(struct sk_buff *skb) int xfrm_output(struct sk_buff *skb) { - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); int err; if (skb_is_gso(skb)) @@ -202,7 +203,7 @@ int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) struct xfrm_mode *inner_mode; if (x->sel.family == AF_UNSPEC) inner_mode = xfrm_ip2inner_mode(x, - xfrm_af2proto(skb->dst->ops->family)); + xfrm_af2proto(skb_dst(skb)->ops->family)); else inner_mode = x->inner_mode; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9c068ab..cb81ca3 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2027,6 +2027,8 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) { struct net *net = dev_net(skb->dev); struct flowi fl; + struct dst_entry *dst; + int res; if (xfrm_decode_session(skb, &fl, family) < 0) { /* XXX: we should have something like FWDHDRERROR here. */ @@ -2034,7 +2036,11 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) return 0; } - return xfrm_lookup(net, &skb->dst, &fl, NULL, 0) == 0; + dst = skb_dst(skb); + + res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0; + skb_dst_set(skb, dst); + return res; } EXPORT_SYMBOL(__xfrm_route_forward); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2fcad7c..4bfc615 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4503,7 +4503,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, * when the packet is on it's final way out. * NOTE: there appear to be some IPv6 multicast cases where skb->dst * is NULL, in this case go ahead and apply access control. */ - if (skb->dst != NULL && skb->dst->xfrm != NULL) + if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL) return NF_ACCEPT; #endif secmark_active = selinux_secmark_enabled(); diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index c0eb720..72b1845 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -447,7 +447,7 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, struct dst_entry *dst; int rc = 0; - dst = skb->dst; + dst = skb_dst(skb); if (dst) { struct dst_entry *dst_test; -- cgit v0.10.2 From e5b9215ef9a274eb9fb65f6aa4602ad82d10a6cb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Jun 2009 05:20:21 +0000 Subject: net: skb cleanup Can remove anonymous union now it has one field. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 9ef6eb2..7305da9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -322,9 +322,7 @@ struct sk_buff { ktime_t tstamp; struct net_device *dev; - union { - unsigned long _skb_dst; - }; + unsigned long _skb_dst; #ifdef CONFIG_XFRM struct sec_path *sp; #endif -- cgit v0.10.2 From 32d0c1e1bee16781e94c7ea8c75499696bce0a33 Mon Sep 17 00:00:00 2001 From: Haiying Wang Date: Tue, 2 Jun 2009 04:04:13 +0000 Subject: net/phy/marvell: update m88e1111 support for SGMII mode Disable fiber/copper auto selection for Marvell m88e1111 SGMII support. Signed-off-by: Haiying Wang Signed-off-by: David S. Miller diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 7a3ec9d..dd6f54d 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -243,6 +243,7 @@ static int m88e1111_config_init(struct phy_device *phydev) temp &= ~(MII_M1111_HWCFG_MODE_MASK); temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); if (err < 0) -- cgit v0.10.2 From fbcc0e2ce5a4fde63c7f33153bd7e3a4791e01c8 Mon Sep 17 00:00:00 2001 From: Haiying Wang Date: Tue, 2 Jun 2009 04:04:14 +0000 Subject: fsl_pq_mido: Set the first UCC as the mii management interface master Current code makes the UCC whose register range includes the current mdio register to be the MII managemnt interface master of the QE. If there is more than one mdio bus for QE, the UCC of the last mdio bus will be the MII management interface master which will make the primary mdio bus working unproperly, e.g. can not get the right clock. Normally the primary mdio bus is the first UEC's mdio bus. This patch allows the first UCC to be the MII management interface master of the multiple UCC mdio buses. Signed-off-by: Haiying Wang Signed-off-by: David S. Miller diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index d12e0e0..3af5813 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -301,13 +301,17 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, of_device_is_compatible(np, "ucc_geth_phy")) { #ifdef CONFIG_UCC_GETH u32 id; + static u32 mii_mng_master; tbipa = ®s->utbipar; if ((err = get_ucc_id_for_range(addr, addr + size, &id))) goto err_free_irqs; - ucc_set_qe_mux_mii_mng(id - 1); + if (!mii_mng_master) { + mii_mng_master = id; + ucc_set_qe_mux_mii_mng(id - 1); + } #else err = -ENODEV; goto err_free_irqs; -- cgit v0.10.2 From 047584ce94108012288554a5f84585d792cc7f8f Mon Sep 17 00:00:00 2001 From: Haiying Wang Date: Tue, 2 Jun 2009 04:04:15 +0000 Subject: net/ucc_geth: Add SGMII support for UEC GETH driver Signed-off-by: Haiying Wang Signed-off-by: David S. Miller diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h index 2701753..4459d20 100644 --- a/arch/powerpc/include/asm/qe.h +++ b/arch/powerpc/include/asm/qe.h @@ -668,6 +668,8 @@ struct ucc_slow_pram { #define UCC_GETH_UPSMR_RMM 0x00001000 #define UCC_GETH_UPSMR_CAM 0x00000400 #define UCC_GETH_UPSMR_BRO 0x00000200 +#define UCC_GETH_UPSMR_SMM 0x00000080 +#define UCC_GETH_UPSMR_SGMM 0x00000020 /* UCC Transmit On Demand Register (UTODR) */ #define UCC_SLOW_TOD 0x8000 diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 0cf22c4..fd6140b 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved. * * Author: Shlomi Gridish * Li Yang @@ -65,6 +65,8 @@ static DEFINE_SPINLOCK(ugeth_lock); +static void uec_configure_serdes(struct net_device *dev); + static struct { u32 msg_enable; } debug = { -1 }; @@ -1410,6 +1412,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { upsmr |= UCC_GETH_UPSMR_TBIM; } + if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII)) + upsmr |= UCC_GETH_UPSMR_SGMM; + out_be32(&uf_regs->upsmr, upsmr); /* Disable autonegotiation in tbi mode, because by default it @@ -1554,6 +1559,9 @@ static int init_phy(struct net_device *dev) return -ENODEV; } + if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) + uec_configure_serdes(dev); + phydev->supported &= (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | @@ -1569,7 +1577,41 @@ static int init_phy(struct net_device *dev) return 0; } +/* Initialize TBI PHY interface for communicating with the + * SERDES lynx PHY on the chip. We communicate with this PHY + * through the MDIO bus on each controller, treating it as a + * "normal" PHY at the address found in the UTBIPA register. We assume + * that the UTBIPA register is valid. Either the MDIO bus code will set + * it to a value that doesn't conflict with other PHYs on the bus, or the + * value doesn't matter, as there are no other PHYs on the bus. + */ +static void uec_configure_serdes(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + + if (!ugeth->tbiphy) { + printk(KERN_WARNING "SGMII mode requires that the device " + "tree specify a tbi-handle\n"); + return; + } + + /* + * If the link is already up, we must already be ok, and don't need to + * configure and reset the TBI<->SerDes link. Maybe U-Boot configured + * everything for us? Resetting it takes the link down and requires + * several seconds for it to come back. + */ + if (phy_read(ugeth->tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS) + return; + + /* Single clk mode, mii mode off(for serdes communication) */ + phy_write(ugeth->tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS); + phy_write(ugeth->tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT); + + phy_write(ugeth->tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS); + +} static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) { @@ -3523,6 +3565,8 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type) return PHY_INTERFACE_MODE_RGMII_RXID; if (strcasecmp(phy_connection_type, "rtbi") == 0) return PHY_INTERFACE_MODE_RTBI; + if (strcasecmp(phy_connection_type, "sgmii") == 0) + return PHY_INTERFACE_MODE_SGMII; return PHY_INTERFACE_MODE_MII; } @@ -3567,6 +3611,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, + PHY_INTERFACE_MODE_SGMII, }; ugeth_vdbg("%s: IN", __func__); @@ -3682,6 +3727,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_TBI: case PHY_INTERFACE_MODE_RTBI: + case PHY_INTERFACE_MODE_SGMII: max_speed = SPEED_1000; break; default: @@ -3756,6 +3802,37 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth->ndev = dev; ugeth->node = np; + /* Find the TBI PHY. If it's not there, we don't support SGMII */ + ph = of_get_property(np, "tbi-handle", NULL); + if (ph) { + struct device_node *tbi = of_find_node_by_phandle(*ph); + struct of_device *ofdev; + struct mii_bus *bus; + const unsigned int *id; + + if (!tbi) + return 0; + + mdio = of_get_parent(tbi); + if (!mdio) + return 0; + + ofdev = of_find_device_by_node(mdio); + + of_node_put(mdio); + + id = of_get_property(tbi, "reg", NULL); + if (!id) + return 0; + of_node_put(tbi); + + bus = dev_get_drvdata(&ofdev->dev); + if (!bus) + return 0; + + ugeth->tbiphy = bus->phy_map[*id]; + } + return 0; } diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index dca628a..deb962b 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright (C) Freescale Semicondutor, Inc. 2006-2009. All rights reserved. * * Author: Shlomi Gridish * @@ -193,6 +193,31 @@ struct ucc_geth { #define ENET_TBI_MII_JD 0x10 /* Jitter diagnostics */ #define ENET_TBI_MII_TBICON 0x11 /* TBI control */ +/* TBI MDIO register bit fields*/ +#define TBISR_LSTATUS 0x0004 +#define TBICON_CLK_SELECT 0x0020 +#define TBIANA_ASYMMETRIC_PAUSE 0x0100 +#define TBIANA_SYMMETRIC_PAUSE 0x0080 +#define TBIANA_HALF_DUPLEX 0x0040 +#define TBIANA_FULL_DUPLEX 0x0020 +#define TBICR_PHY_RESET 0x8000 +#define TBICR_ANEG_ENABLE 0x1000 +#define TBICR_RESTART_ANEG 0x0200 +#define TBICR_FULL_DUPLEX 0x0100 +#define TBICR_SPEED1_SET 0x0040 + +#define TBIANA_SETTINGS ( \ + TBIANA_ASYMMETRIC_PAUSE \ + | TBIANA_SYMMETRIC_PAUSE \ + | TBIANA_FULL_DUPLEX \ + ) +#define TBICR_SETTINGS ( \ + TBICR_PHY_RESET \ + | TBICR_ANEG_ENABLE \ + | TBICR_FULL_DUPLEX \ + | TBICR_SPEED1_SET \ + ) + /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control Rx */ @@ -1188,6 +1213,7 @@ struct ucc_geth_private { struct ugeth_mii_info *mii_info; struct phy_device *phydev; + struct phy_device *tbiphy; phy_interface_t phy_interface; int max_speed; uint32_t msg_enable; -- cgit v0.10.2 From a84db7949eab7a42e715192f62c55c554e195e54 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Apr 2009 15:41:39 +0800 Subject: sctp: fix error cause codes of ADD-IP extension RFC5061 had changed the error cause codes for Dynamic Address Reconfiguration As the following: Cause Code Value Cause Code --------- ---------------- 0x00A0 Request to Delete Last Remaining IP Address 0x00A1 Operation Refused Due to Resource Shortage 0x00A2 Request to Delete Source IP Address 0x00A3 Association Aborted Due to Illegal ASCONF-ACK 0x00A4 Request Refused - No Authorization This patch fix the error cause codes. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/include/linux/sctp.h b/include/linux/sctp.h index c2731bf..b464b9d 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -487,17 +487,17 @@ typedef enum { * * Value Cause Code * --------- ---------------- - * 0x0100 Request to Delete Last Remaining IP Address. - * 0x0101 Operation Refused Due to Resource Shortage. - * 0x0102 Request to Delete Source IP Address. - * 0x0103 Association Aborted due to illegal ASCONF-ACK - * 0x0104 Request refused - no authorization. + * 0x00A0 Request to Delete Last Remaining IP Address. + * 0x00A1 Operation Refused Due to Resource Shortage. + * 0x00A2 Request to Delete Source IP Address. + * 0x00A3 Association Aborted due to illegal ASCONF-ACK + * 0x00A4 Request refused - no authorization. */ - SCTP_ERROR_DEL_LAST_IP = cpu_to_be16(0x0100), - SCTP_ERROR_RSRC_LOW = cpu_to_be16(0x0101), - SCTP_ERROR_DEL_SRC_IP = cpu_to_be16(0x0102), - SCTP_ERROR_ASCONF_ACK = cpu_to_be16(0x0103), - SCTP_ERROR_REQ_REFUSED = cpu_to_be16(0x0104), + SCTP_ERROR_DEL_LAST_IP = cpu_to_be16(0x00A0), + SCTP_ERROR_RSRC_LOW = cpu_to_be16(0x00A1), + SCTP_ERROR_DEL_SRC_IP = cpu_to_be16(0x00A2), + SCTP_ERROR_ASCONF_ACK = cpu_to_be16(0x00A3), + SCTP_ERROR_REQ_REFUSED = cpu_to_be16(0x00A4), /* AUTH Section 4. New Error Cause * -- cgit v0.10.2 From a987f762cafb25c0fedf88f15e328edd897210ed Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Apr 2009 15:44:29 +0800 Subject: sctp: fix report unrecognized parameter in ACSONF-ACK RFC5061 Section 5.2. Upon Reception of an ASCONF Chunk V2) In processing the chunk, the receiver should build a response message with the appropriate error TLVs, as specified in the Parameter type bits, for any ASCONF Parameter it does not understand. To indicate an unrecognized parameter, Cause Type 8 should be used as defined in the ERROR in Section 3.3.10.8, [RFC4960]. The endpoint may also use the response to carry rejections for other reasons, such as resource shortages, etc., using the Error Cause TLV and an appropriate error condition. So we should indicate an unrecognized parameter with error SCTP_ERROR_UNKNOWN_PARAM in ACSONF-ACK chunk, not SCTP_ERROR_INV_PARAM. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 6851ee9..c78e31b 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2959,7 +2959,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, sctp_assoc_set_primary(asoc, peer); break; default: - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_UNKNOWN_PARAM; break; } @@ -3273,7 +3273,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, retval = 1; break; - case SCTP_ERROR_INV_PARAM: + case SCTP_ERROR_UNKNOWN_PARAM: /* Disable sending this type of asconf parameter in * future. */ -- cgit v0.10.2 From 945e5abceef8bdb85d8455e7f9a3cd647dd8b156 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 16 Apr 2009 14:21:02 +0800 Subject: sctp: fix the error code when ASCONF is received with invalid address Use Unresolvable Address error cause instead of Invalid Mandatory Parameter error cause when process ASCONF chunk with invalid address since address parameters are not mandatory in the ASCONF chunk. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index c78e31b..61cc607 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2864,19 +2864,19 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, switch (addr_param->v4.param_hdr.type) { case SCTP_PARAM_IPV6_ADDRESS: if (!asoc->peer.ipv6_address) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; break; case SCTP_PARAM_IPV4_ADDRESS: if (!asoc->peer.ipv4_address) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; break; default: - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; } af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); if (unlikely(!af)) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0); @@ -2886,7 +2886,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, * make sure we check for that) */ if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb)) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; switch (asconf_param->param_hdr.type) { case SCTP_PARAM_ADD_IP: @@ -2954,7 +2954,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, peer = sctp_assoc_lookup_paddr(asoc, &addr); if (!peer) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; sctp_assoc_set_primary(asoc, peer); break; -- cgit v0.10.2 From 4553e88d876e7eb29db3e8f632101398900d2194 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Apr 2009 16:36:14 +0800 Subject: sctp: fix a typo in net/sctp/sm_statetable.c Just fix a typo in net/sctp/sm_statetable.c. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 5c8186d..6d9b3aa 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -698,7 +698,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { TYPE_SCTP_FUNC(sctp_sf_do_prm_asconf), \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ TYPE_SCTP_FUNC(sctp_sf_error_shutdown), \ -} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ +} /* TYPE_SCTP_PRIMITIVE_ASCONF */ /* The primary index for this table is the primitive type. * The secondary index for this table is the state. -- cgit v0.10.2 From a2c395846cf6abfdda3c04a19a0982adbb6469c2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Apr 2009 16:35:11 +0800 Subject: sctp: fix to only enable IPv6 address support on PF_INET6 socket If socket is create by PF_INET type, it can not used IPv6 address to send/recv DATA. So only enable IPv6 address support on PF_INET6 socket. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/associola.c b/net/sctp/associola.c index f4b2304..e7b69a7 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -293,7 +293,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a * told otherwise. */ asoc->peer.ipv4_address = 1; - asoc->peer.ipv6_address = 1; + if (asoc->base.sk->sk_family == PF_INET6) + asoc->peer.ipv6_address = 1; INIT_LIST_HEAD(&asoc->asocs); asoc->autoclose = sp->autoclose; -- cgit v0.10.2 From 6345b19985e9f3ec31b61720de01806e3ef680fe Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 26 Apr 2009 23:13:35 +0800 Subject: sctp: fix panic when T2-shutdown timer expire on removed transport If T2-shutdown timer is expired on a removed transport, kernel panic will occur when we do failure management on that transport. You can reproduce this use the following sequence: Endpoint A Endpoint B (ESTABLISHED) (ESTABLISHED) <----------------- SHUTDOWN (SRC=X) ASCONF -----------------> (Delete IP Address = X) <----------------- ASCONF-ACK (Success Indication) <----------------- SHUTDOWN (T2-shutdown timer expire) This patch fixed the problem. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/associola.c b/net/sctp/associola.c index e7b69a7..3be28fe 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -567,6 +567,14 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, if (asoc->init_last_sent_to == peer) asoc->init_last_sent_to = NULL; + /* If we remove the transport an SHUTDOWN was last sent to, set it + * to NULL. Combined with the update of the retran path above, this + * will cause the next SHUTDOWN to be sent to the next available + * transport, maintaining the cycle. + */ + if (asoc->shutdown_last_sent_to == peer) + asoc->shutdown_last_sent_to = NULL; + asoc->peer.transport_count--; sctp_transport_free(peer); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 55a61aa..10abc07 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5432,9 +5432,13 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, if (!reply) goto nomem; - /* Do some failure management (Section 8.2). */ - sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, - SCTP_TRANSPORT(asoc->shutdown_last_sent_to)); + /* Do some failure management (Section 8.2). + * If we remove the transport an SHUTDOWN was last sent to, don't + * do failure management. + */ + if (asoc->shutdown_last_sent_to) + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, + SCTP_TRANSPORT(asoc->shutdown_last_sent_to)); /* Set the transport for the SHUTDOWN/ACK chunk and the timeout for * the T2-shutdown timer. -- cgit v0.10.2 From 10a43cea7da841cf85a778a1a4d367fb2de7cbce Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 26 Apr 2009 23:14:42 +0800 Subject: sctp: fix panic when T4-rto timer expire on removed transport If T4-rto timer is expired on a removed transport, kernel panic will occur when we do failure management on that transport. You can reproduce this use the following sequence: Endpoint A Endpoint B (ESTABLISHED) (ESTABLISHED) <----------------- ASCONF (SRC=X) ASCONF -----------------> (Delete IP Address = X) <----------------- ASCONF-ACK (Success Indication) <----------------- ASCONF (T4-rto timer expire) This patch fixed the problem. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 3be28fe..8d3aef9 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -575,6 +575,13 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, if (asoc->shutdown_last_sent_to == peer) asoc->shutdown_last_sent_to = NULL; + /* If we remove the transport an ASCONF was last sent to, set it to + * NULL. + */ + if (asoc->addip_last_asconf && + asoc->addip_last_asconf->transport == peer) + asoc->addip_last_asconf->transport = NULL; + asoc->peer.transport_count--; sctp_transport_free(peer); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 10abc07..7288192 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5475,7 +5475,9 @@ sctp_disposition_t sctp_sf_t4_timer_expire( * detection on the appropriate destination address as defined in * RFC2960 [5] section 8.1 and 8.2. */ - sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); + if (transport) + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, + SCTP_TRANSPORT(transport)); /* Reconfig T4 timer and transport. */ sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T4, SCTP_CHUNK(chunk)); -- cgit v0.10.2 From d48e074dfdada552fa53f5eab807540f352e0d5d Mon Sep 17 00:00:00 2001 From: Jean-Mickael Guerin Date: Wed, 13 May 2009 00:03:20 +0200 Subject: sctp: fix sack_timeout sysctl min and max types sctp_sack_timeout is defined as int, but the sysctl's maxsize is set to sizeof(long) and the min/max are defined as long. Signed-off-by: jean-mickael.guerin@6wind.com Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index f58e994..63eabbc 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -49,8 +49,8 @@ static int zero = 0; static int one = 1; static int timer_max = 86400000; /* ms in one day */ static int int_max = INT_MAX; -static long sack_timer_min = 1; -static long sack_timer_max = 500; +static int sack_timer_min = 1; +static int sack_timer_max = 500; extern int sysctl_sctp_mem[3]; extern int sysctl_sctp_rmem[3]; @@ -223,7 +223,7 @@ static ctl_table sctp_table[] = { .ctl_name = NET_SCTP_SACK_TIMEOUT, .procname = "sack_timeout", .data = &sctp_sack_timeout, - .maxlen = sizeof(long), + .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, -- cgit v0.10.2 From 9919b455fc00c995ef8141848bdc0709ce50bf36 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 May 2009 21:52:51 +0800 Subject: sctp: fix to choose alternate destination when retransmit ASCONF chunk RFC 5061 Section 5.1 ASCONF Chunk Procedures said: B4) Re-transmit the ASCONF Chunk last sent and if possible choose an alternate destination address (please refer to [RFC4960], Section 6.4.1). An endpoint MUST NOT add new parameters to this chunk; it MUST be the same (including its Sequence Number) as the last ASCONF sent. An endpoint MAY, however, bundle an additional ASCONF with new ASCONF parameters with the next Sequence Number. For details, see Section 5.5. This patch fix to choose an alternate destination address when re-transmit the ASCONF chunk, with some dup codes cleanup. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 23f08fe..edfcacf 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1939,10 +1939,8 @@ void sctp_association_free(struct sctp_association *); void sctp_association_put(struct sctp_association *); void sctp_association_hold(struct sctp_association *); -struct sctp_transport *sctp_assoc_choose_init_transport( - struct sctp_association *); -struct sctp_transport *sctp_assoc_choose_shutdown_transport( - struct sctp_association *); +struct sctp_transport *sctp_assoc_choose_alter_transport( + struct sctp_association *, struct sctp_transport *); void sctp_assoc_update_retran_path(struct sctp_association *); struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *, const union sctp_addr *); diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 8d3aef9..39f5166 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1284,49 +1284,21 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) ntohs(t->ipaddr.v4.sin_port)); } -/* Choose the transport for sending a INIT packet. */ -struct sctp_transport *sctp_assoc_choose_init_transport( - struct sctp_association *asoc) +/* Choose the transport for sending retransmit packet. */ +struct sctp_transport *sctp_assoc_choose_alter_transport( + struct sctp_association *asoc, struct sctp_transport *last_sent_to) { - struct sctp_transport *t; - - /* Use the retran path. If the last INIT was sent over the + /* If this is the first time packet is sent, use the active path, + * else use the retran path. If the last packet was sent over the * retran path, update the retran path and use it. */ - if (!asoc->init_last_sent_to) { - t = asoc->peer.active_path; - } else { - if (asoc->init_last_sent_to == asoc->peer.retran_path) - sctp_assoc_update_retran_path(asoc); - t = asoc->peer.retran_path; - } - - SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association" - " %p addr: ", - " port: %d\n", - asoc, - (&t->ipaddr), - ntohs(t->ipaddr.v4.sin_port)); - - return t; -} - -/* Choose the transport for sending a SHUTDOWN packet. */ -struct sctp_transport *sctp_assoc_choose_shutdown_transport( - struct sctp_association *asoc) -{ - /* If this is the first time SHUTDOWN is sent, use the active path, - * else use the retran path. If the last SHUTDOWN was sent over the - * retran path, update the retran path and use it. - */ - if (!asoc->shutdown_last_sent_to) + if (!last_sent_to) return asoc->peer.active_path; else { - if (asoc->shutdown_last_sent_to == asoc->peer.retran_path) + if (last_sent_to == asoc->peer.retran_path) sctp_assoc_update_retran_path(asoc); return asoc->peer.retran_path; } - } /* Update the association's pmtu and frag_point by going through all the diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index e2020eb..86426aa 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -686,7 +686,8 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, { struct sctp_transport *t; - t = sctp_assoc_choose_shutdown_transport(asoc); + t = sctp_assoc_choose_alter_transport(asoc, + asoc->shutdown_last_sent_to); asoc->shutdown_last_sent_to = t; asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; chunk->transport = t; @@ -777,7 +778,7 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds, { struct sctp_transport *t; - t = asoc->peer.active_path; + t = sctp_assoc_choose_alter_transport(asoc, chunk->transport); asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto; chunk->transport = t; } @@ -1379,7 +1380,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, case SCTP_CMD_INIT_CHOOSE_TRANSPORT: chunk = cmd->obj.ptr; - t = sctp_assoc_choose_init_transport(asoc); + t = sctp_assoc_choose_alter_transport(asoc, + asoc->init_last_sent_to); asoc->init_last_sent_to = t; chunk->transport = t; t->init_sent_count++; -- cgit v0.10.2 From c6ba68a26645dbc5029a9faa5687ebe6fcfc53e4 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 1 Jun 2009 12:41:15 -0400 Subject: sctp: support non-blocking version of the new sctp_connectx() API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior implementation of the new sctp_connectx() call that returns an association ID did not work correctly on non-blocking socket. This is because we could not return both a EINPROGRESS error and an association id. This is a new implementation that supports this. Originally from Ivan Skytte Jørgensen diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index b259fc5..1580c04 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -147,6 +147,8 @@ enum sctp_optname { #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX + SCTP_SOCKOPT_CONNECTX3, /* CONNECTX requests. (new implementation) */ +#define SCTP_SOCKOPT_CONNECTX3 SCTP_SOCKOPT_CONNECTX3 }; /* diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 39f5166..525864b 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1470,6 +1470,10 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp) { int assoc_id; int error = 0; + + /* If the id is already assigned, keep it. */ + if (asoc->assoc_id) + return error; retry: if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp))) return -ENOMEM; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5fb3a8c..7c3dfd2 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk, goto out_free; } + /* In case the user of sctp_connectx() wants an association + * id back, assign one now. + */ + if (assoc_id) { + err = sctp_assoc_set_id(asoc, GFP_KERNEL); + if (err < 0) + goto out_free; + } + err = sctp_primitive_ASSOCIATE(asoc, NULL); if (err < 0) { goto out_free; @@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk, timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); - if (!err && assoc_id) + if ((err == 0 || err == -EINPROGRESS) && assoc_id) *assoc_id = asoc->assoc_id; /* Don't free association on exit. */ @@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, return assoc_id; } +/* + * New (hopefully final) interface for the API. The option buffer is used + * both for the returned association id and the addresses. + */ +SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len, + char __user *optval, + int __user *optlen) +{ + sctp_assoc_t assoc_id = 0; + int err = 0; + + if (len < sizeof(assoc_id)) + return -EINVAL; + + err = __sctp_setsockopt_connectx(sk, + (struct sockaddr __user *)(optval + sizeof(assoc_id)), + len - sizeof(assoc_id), &assoc_id); + + if (err == 0 || err == -EINPROGRESS) { + if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) + return -EFAULT; + if (put_user(sizeof(assoc_id), optlen)) + return -EFAULT; + } + + return err; +} + /* API 3.1.4 close() - UDP Style Syntax * Applications use close() to perform graceful shutdown (as described in * Section 10.1 of [SCTP]) on ALL the associations currently represented @@ -5578,6 +5615,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_local_addrs(sk, len, optval, optlen); break; + case SCTP_SOCKOPT_CONNECTX3: + retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); + break; case SCTP_DEFAULT_SEND_PARAM: retval = sctp_getsockopt_default_send_param(sk, len, optval, optlen); -- cgit v0.10.2 From 85c7859190c4197a7c34066db14c25903c401187 Mon Sep 17 00:00:00 2001 From: Denis Karpov Date: Thu, 4 Jun 2009 02:34:22 +0900 Subject: FAT: add 'errors' mount option On severe errors FAT remounts itself in read-only mode. Allow to specify FAT fs desired behavior through 'errors' mount option: panic, continue or remount read-only. `mount -t [fat|vfat] -o errors=[panic,remount-ro,continue] \ ` This is analog to ext2 fs 'errors' mount option. Signed-off-by: Denis Karpov Signed-off-by: OGAWA Hirofumi diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt index 3a5ddc9..7d41c0d 100644 --- a/Documentation/filesystems/vfat.txt +++ b/Documentation/filesystems/vfat.txt @@ -132,6 +132,11 @@ rodir -- FAT has the ATTR_RO (read-only) attribute. But on Windows, If you want to use ATTR_RO as read-only flag even for the directory, set this option. +errors=panic|continue|remount-ro + -- specify FAT behavior on critical errors: panic, continue + without doing anything or remount the partition in + read-only mode (default behavior). + : 0,1,yes,no,true,false TODO diff --git a/fs/fat/cache.c b/fs/fat/cache.c index b426022..923990e 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -241,7 +241,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) while (*fclus < cluster) { /* prevent the infinite loop of cluster chain */ if (*fclus > limit) { - fat_fs_panic(sb, "%s: detected the cluster chain loop" + fat_fs_error(sb, "%s: detected the cluster chain loop" " (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); nr = -EIO; @@ -252,7 +252,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) if (nr < 0) goto out; else if (nr == FAT_ENT_FREE) { - fat_fs_panic(sb, "%s: invalid cluster chain" + fat_fs_error(sb, "%s: invalid cluster chain" " (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); nr = -EIO; @@ -285,7 +285,7 @@ static int fat_bmap_cluster(struct inode *inode, int cluster) if (ret < 0) return ret; else if (ret == FAT_ENT_EOF) { - fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)", + fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); return -EIO; } diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 3a7f603..7e7924c 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -1334,7 +1334,7 @@ found: goto error_remove; } if (dir->i_size & (sbi->cluster_size - 1)) { - fat_fs_panic(sb, "Odd directory size"); + fat_fs_error(sb, "Odd directory size"); dir->i_size = (dir->i_size + sbi->cluster_size - 1) & ~((loff_t)sbi->cluster_size - 1); } diff --git a/fs/fat/fat.h b/fs/fat/fat.h index ea440d6..ed10896 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -17,6 +17,10 @@ #define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */ #define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */ +#define FAT_ERRORS_CONT 1 /* ignore error and continue */ +#define FAT_ERRORS_PANIC 2 /* panic on error */ +#define FAT_ERRORS_RO 3 /* remount r/o on error */ + struct fat_mount_options { uid_t fs_uid; gid_t fs_gid; @@ -26,6 +30,7 @@ struct fat_mount_options { char *iocharset; /* Charset used for filename input/display */ unsigned short shortname; /* flags for shortname display/create rule */ unsigned char name_check; /* r = relaxed, n = normal, s = strict */ + unsigned char errors; /* On error: continue, panic, remount-ro */ unsigned short allow_utime;/* permission for setting the [am]time */ unsigned quiet:1, /* set = fake successful chmods and chowns */ showexec:1, /* set = only set x bit for com/exe/bat */ @@ -310,7 +315,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent, extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2); /* fat/misc.c */ -extern void fat_fs_panic(struct super_block *s, const char *fmt, ...) +extern void fat_fs_error(struct super_block *s, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) __cold; extern void fat_clusters_flush(struct super_block *sb); extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index da6eea4..60c31f7 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -345,7 +345,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { fatent_brelse(fatent); - fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry); + fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); return -EIO; } @@ -557,7 +557,7 @@ int fat_free_clusters(struct inode *inode, int cluster) err = cluster; goto error; } else if (cluster == FAT_ENT_FREE) { - fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF", + fat_fs_error(sb, "%s: deleting FAT entry beyond EOF", __func__); err = -EIO; goto error; diff --git a/fs/fat/file.c b/fs/fat/file.c index 0a7f4a9..6214287 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -213,7 +213,7 @@ static int fat_free(struct inode *inode, int skip) fatent_brelse(&fatent); return 0; } else if (ret == FAT_ENT_FREE) { - fat_fs_panic(sb, + fat_fs_error(sb, "%s: invalid cluster chain (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); ret = -EIO; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 296785a..2b90522 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -76,7 +76,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock, return 0; if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { - fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", + fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)", MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); return -EIO; } @@ -834,6 +834,12 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",flush"); if (opts->tz_utc) seq_puts(m, ",tz=UTC"); + if (opts->errors == FAT_ERRORS_CONT) + seq_puts(m, ",errors=continue"); + else if (opts->errors == FAT_ERRORS_PANIC) + seq_puts(m, ",errors=panic"); + else + seq_puts(m, ",errors=remount-ro"); return 0; } @@ -846,7 +852,8 @@ enum { Opt_charset, Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, - Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err, + Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, + Opt_err_panic, Opt_err_ro, Opt_err, }; static const match_table_t fat_tokens = { @@ -869,6 +876,11 @@ static const match_table_t fat_tokens = { {Opt_showexec, "showexec"}, {Opt_debug, "debug"}, {Opt_immutable, "sys_immutable"}, + {Opt_flush, "flush"}, + {Opt_tz_utc, "tz=UTC"}, + {Opt_err_cont, "errors=continue"}, + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, {Opt_obsolate, "conv=binary"}, {Opt_obsolate, "conv=text"}, {Opt_obsolate, "conv=auto"}, @@ -880,8 +892,6 @@ static const match_table_t fat_tokens = { {Opt_obsolate, "cvf_format=%20s"}, {Opt_obsolate, "cvf_options=%100s"}, {Opt_obsolate, "posix"}, - {Opt_flush, "flush"}, - {Opt_tz_utc, "tz=UTC"}, {Opt_err, NULL}, }; static const match_table_t msdos_tokens = { @@ -951,6 +961,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, opts->numtail = 1; opts->usefree = opts->nocase = 0; opts->tz_utc = 0; + opts->errors = FAT_ERRORS_RO; *debug = 0; if (!options) @@ -1043,6 +1054,15 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, case Opt_tz_utc: opts->tz_utc = 1; break; + case Opt_err_cont: + opts->errors = FAT_ERRORS_CONT; + break; + case Opt_err_panic: + opts->errors = FAT_ERRORS_PANIC; + break; + case Opt_err_ro: + opts->errors = FAT_ERRORS_RO; + break; /* msdos specific */ case Opt_dots: diff --git a/fs/fat/misc.c b/fs/fat/misc.c index ac39ebc..a6c2047 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -12,14 +12,19 @@ #include "fat.h" /* - * fat_fs_panic reports a severe file system problem and sets the file system - * read-only. The file system can be made writable again by remounting it. + * fat_fs_error reports a file system problem that might indicate fa data + * corruption/inconsistency. Depending on 'errors' mount option the + * panic() is called, or error message is printed FAT and nothing is done, + * or filesystem is remounted read-only (default behavior). + * In case the file system is remounted read-only, it can be made writable + * again by remounting it. */ -void fat_fs_panic(struct super_block *s, const char *fmt, ...) +void fat_fs_error(struct super_block *s, const char *fmt, ...) { + struct fat_mount_options *opts = &MSDOS_SB(s)->options; va_list args; - printk(KERN_ERR "FAT: Filesystem panic (dev %s)\n", s->s_id); + printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id); printk(KERN_ERR " "); va_start(args, fmt); @@ -27,13 +32,14 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...) va_end(args); printk("\n"); - if (!(s->s_flags & MS_RDONLY)) { + if (opts->errors == FAT_ERRORS_PANIC) + panic(" FAT fs panic from previous error\n"); + else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) { s->s_flags |= MS_RDONLY; printk(KERN_ERR " File system has been set read-only\n"); } } - -EXPORT_SYMBOL_GPL(fat_fs_panic); +EXPORT_SYMBOL_GPL(fat_fs_error); /* Flushes the number of free clusters on FAT32 */ /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ @@ -124,7 +130,7 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) mark_inode_dirty(inode); } if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { - fat_fs_panic(sb, "clusters badly computed (%d != %llu)", + fat_fs_error(sb, "clusters badly computed (%d != %llu)", new_fclus, (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); fat_cache_inval_inode(inode); diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index da3f361..72f5c64 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -608,7 +608,7 @@ error_inode: sinfo.bh = NULL; } if (corrupt < 0) { - fat_fs_panic(new_dir->i_sb, + fat_fs_error(new_dir->i_sb, "%s: Filesystem corrupted (i_pos %lld)", __func__, sinfo.i_pos); } diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index a0e00e3..cb6ddb8 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -1030,7 +1030,7 @@ error_inode: sinfo.bh = NULL; } if (corrupt < 0) { - fat_fs_panic(new_dir->i_sb, + fat_fs_error(new_dir->i_sb, "%s: Filesystem corrupted (i_pos %lld)", __func__, sinfo.i_pos); } -- cgit v0.10.2 From 55aa4e0f16aa55e4b8cbe40b11e09cf029848f02 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 25 May 2009 21:28:47 +0200 Subject: ath5k: avoid leaking mutex in ath5k_config Reported-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index fb51937..dd6dc8d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2779,7 +2779,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) ret = ath5k_chan_set(sc, conf->channel); if (ret < 0) - return ret; + goto unlock; if ((changed & IEEE80211_CONF_CHANGE_POWER) && (sc->power_level != conf->power_level)) { @@ -2808,8 +2808,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) */ ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); +unlock: mutex_unlock(&sc->lock); - return 0; + return ret; } #define SUPPORTED_FIF_FLAGS \ -- cgit v0.10.2 From f488b72de5bb2f380c157135922bac3ca1648564 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 22 May 2009 21:19:40 +0200 Subject: net/libertas: make SPI interface big endian aware The comment (which I remove) says that the translation is done SPI routines. IMHO this can't work because the SPI driver does not know whether the incomming bytes are part of the registers/bytes which need to be flipped or part of packet data which has to remain untouched. While adding le helpers I also removed spu_write_u32() which has no users. Tested-by: Andrey Yurovsky Signed-off-by: Sebastian Andrzej Siewior Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 5fa55fe..ea23c5d 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -119,9 +119,6 @@ static struct chip_ident chip_id_to_device_name[] = { * First we have to put a SPU register name on the bus. Then we can * either read from or write to that register. * - * For 16-bit transactions, byte order on the bus is big-endian. - * We don't have to worry about that here, though. - * The translation takes place in the SPI routines. */ static void spu_transaction_init(struct if_spi_card *card) @@ -147,7 +144,7 @@ static void spu_transaction_finish(struct if_spi_card *card) static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; - u16 reg_out = reg | IF_SPI_WRITE_OPERATION_MASK; + u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK); /* You must give an even number of bytes to the SPU, even if it * doesn't care about the last one. */ @@ -169,16 +166,10 @@ out: static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val) { - return spu_write(card, reg, (u8 *)&val, sizeof(u16)); -} + u16 buff; -static inline int spu_write_u32(struct if_spi_card *card, u16 reg, u32 val) -{ - /* The lower 16 bits are written first. */ - u16 out[2]; - out[0] = val & 0xffff; - out[1] = (val & 0xffff0000) >> 16; - return spu_write(card, reg, (u8 *)&out, sizeof(u32)); + buff = cpu_to_le16(val); + return spu_write(card, reg, (u8 *)&buff, sizeof(u16)); } static inline int spu_reg_is_port_reg(u16 reg) @@ -198,7 +189,7 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) unsigned int i, delay; int err = 0; u16 zero = 0; - u16 reg_out = reg | IF_SPI_READ_OPERATION_MASK; + u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK); /* You must take an even number of bytes from the SPU, even if you * don't care about the last one. */ @@ -236,18 +227,25 @@ out: /* Read 16 bits from an SPI register */ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) { - return spu_read(card, reg, (u8 *)val, sizeof(u16)); + u16 buf; + int ret; + + ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); + if (ret == 0) + *val = le16_to_cpup(&buf); + return ret; } /* Read 32 bits from an SPI register. * The low 16 bits are read first. */ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) { - u16 buf[2]; + u32 buf; int err; - err = spu_read(card, reg, (u8 *)buf, sizeof(u32)); + + err = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); if (!err) - *val = buf[0] | (buf[1] << 16); + *val = le32_to_cpup(&buf); return err; } -- cgit v0.10.2 From ce2ebc9b8ddac020aa06c83a6d084c34017d835d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 22 May 2009 21:33:21 +0200 Subject: rt2x00: Add new rt2800usb USB ID's new patch to add more usb_dev to rt2800usb.c . IDs 'stolen' from the latest Ralink linux driver(2009_0520_RT3070_Linux_STA_v2.1.1.0.tar.gz) Signed-off-by: Xose Vazquez Perez Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 142ad34..3756166 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2927,12 +2927,17 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Edimax */ { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Encore */ + { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, /* EnGenius */ { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -2951,6 +2956,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, /* LevelOne */ { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -2970,6 +2977,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Pegatron */ { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Philips */ { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ @@ -2981,6 +2989,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Quanta */ { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ralink */ + { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -3005,6 +3014,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, /* SMC */ { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -3029,6 +3039,8 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Zinwell */ { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v0.10.2 From df29ff379425954cb74b7beb642ca5b43ae557ae Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 22 May 2009 14:37:54 -0700 Subject: iwlwifi: fix merge error This hunk of code was removed in patch "iwlwifi: do not cancel delayed work inside spin_lock_irqsave" submitted at http://marc.info/?l=linux-wireless&m=124267503030042&w=2 This same patch in this repo does not remove this hunk. Remove it here. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e93ddb7..a9da06f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2685,13 +2685,6 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) if (!iwl_is_ready_rf(priv)) return -EAGAIN; - cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - return -EAGAIN; - } - iwlcore_commit_rxon(priv); return 0; -- cgit v0.10.2 From d77b034f62d4b8c6c39450d99de224b9b2c5debb Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 22 May 2009 14:37:55 -0700 Subject: iwlwifi: fix otp access init Polling function returns positive time if polling was needed to read value. This is still success. Signed-off-by: Reinette Chatre CC: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index cefa501..7d7554a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -240,13 +240,11 @@ static int iwl_init_otp_access(struct iwl_priv *priv) if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { - if (!ret) { - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - } + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); } return ret; } -- cgit v0.10.2 From 5fd164e96cb9dc111f75468378de38c67b0fd161 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 May 2009 20:01:21 -0400 Subject: libertas: simplify and clean up association/start/join setup Some of the parameters for association/join/start commands aren't used (like the FH and CF IEs for IBSS, and the FH IE for BSS), so get rid of their unions to reduce indirection. Also clean up structure names for kernel style. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a0e440c..d4d1d80 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -219,11 +219,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, 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.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set)); - memcpy(&cmd.bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); + memcpy(&cmd.bss.ibss, &bss->ss.ibss, + sizeof(struct ieee_ie_ibss_param_set)); cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", @@ -260,7 +259,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, */ lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); - cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); + cmd.bss.ibss.atimwindow = bss->atimwindow; if (assoc_req->secinfo.wep_enabled) { u16 tmp = le16_to_cpu(cmd.bss.capability); @@ -343,14 +342,14 @@ static int lbs_adhoc_start(struct lbs_private *priv, WARN_ON(!assoc_req->channel); /* set Physical parameter set */ - cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; - cmd.phyparamset.dsparamset.len = 1; - cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; + cmd.ds.elementid = WLAN_EID_DS_PARAMS; + cmd.ds.len = 1; + cmd.ds.channel = assoc_req->channel; /* set IBSS parameter set */ - cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS; - cmd.ssparamset.ibssparamset.len = 2; - cmd.ssparamset.ibssparamset.atimwindow = 0; + cmd.ibss.elementid = WLAN_EID_IBSS_PARAMS; + cmd.ibss.len = 2; + cmd.ibss.atimwindow = cpu_to_le16(0); /* set capability info */ tmpcap = WLAN_CAPABILITY_IBSS; @@ -1560,8 +1559,8 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, u8 *pos; u16 tmpcap, tmplen; struct mrvlietypes_ssidparamset *ssid; - struct mrvlietypes_phyparamset *phy; - struct mrvlietypes_ssparamset *ss; + struct mrvlietypes_dsparamset *ds; + struct mrvlietypes_cfparamset *cf; struct mrvlietypes_ratesparamset *rates; struct mrvlietypes_rsnparamset *rsn; @@ -1594,20 +1593,18 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, memcpy(ssid->ssid, bss->ssid, tmplen); pos += sizeof(ssid->header) + tmplen; - phy = (struct mrvlietypes_phyparamset *) pos; - phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); - tmplen = sizeof(phy->fh_ds.dsparamset); - phy->header.len = cpu_to_le16(tmplen); - memcpy(&phy->fh_ds.dsparamset, - &bss->phyparamset.dsparamset.currentchan, - tmplen); - pos += sizeof(phy->header) + tmplen; - - ss = (struct mrvlietypes_ssparamset *) pos; - ss->header.type = cpu_to_le16(TLV_TYPE_CF); - tmplen = sizeof(ss->cf_ibss.cfparamset); - ss->header.len = cpu_to_le16(tmplen); - pos += sizeof(ss->header) + tmplen; + ds = (struct mrvlietypes_dsparamset *) pos; + ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); + ds->header.len = cpu_to_le16(1); + ds->channel = bss->phy.ds.channel; + pos += sizeof(ds->header) + 1; + + cf = (struct mrvlietypes_cfparamset *) pos; + cf->header.type = cpu_to_le16(TLV_TYPE_CF); + tmplen = sizeof(*cf) - sizeof (cf->header); + cf->header.len = cpu_to_le16(tmplen); + /* IE payload should be zeroed, firmware fills it in for us */ + pos += sizeof(*cf); rates = (struct mrvlietypes_ratesparamset *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); @@ -1643,7 +1640,7 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, } /* update curbssparams */ - priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; + priv->curbssparams.channel = bss->phy.ds.channel; if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; @@ -1669,7 +1666,7 @@ int lbs_ret_80211_associate(struct lbs_private *priv, { int ret = 0; union iwreq_data wrqu; - struct ieeetypes_assocrsp *passocrsp; + struct ieee_assoc_response *passocrsp; struct bss_descriptor *bss; u16 status_code; @@ -1682,7 +1679,7 @@ int lbs_ret_80211_associate(struct lbs_private *priv, } bss = &priv->in_progress_assoc_req->bss; - passocrsp = (struct ieeetypes_assocrsp *) &resp->params; + passocrsp = (struct ieee_assoc_response *) &resp->params; /* * Older FW versions map the IEEE 802.11 Status Code in the association diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a4455ec..d0de8c7 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -340,7 +340,7 @@ struct bss_descriptor { u32 rssi; u32 channel; u16 beaconperiod; - u32 atimwindow; + __le16 atimwindow; /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ u8 mode; @@ -350,8 +350,8 @@ struct bss_descriptor { unsigned long last_scanned; - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; + union ieee_phy_param_set phy; + union ieee_ss_param_set ss; struct ieeetypes_countryinfofullset countryinfo; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 391c54a..463ff97 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -278,7 +278,7 @@ struct cmd_ds_802_11_associate { } __attribute__ ((packed)); struct cmd_ds_802_11_associate_rsp { - struct ieeetypes_assocrsp assocRsp; + struct ieee_assoc_response response; } __attribute__ ((packed)); struct cmd_ds_802_11_set_wep { @@ -535,9 +535,11 @@ struct cmd_ds_802_11_ad_hoc_start { u8 bsstype; __le16 beaconperiod; u8 dtimperiod; /* Reserved on v9 and later */ - union IEEEtypes_ssparamset ssparamset; - union ieeetypes_phyparamset phyparamset; - __le16 probedelay; + struct ieee_ie_ibss_param_set ibss; + u8 reserved1[4]; + struct ieee_ie_ds_param_set ds; + u8 reserved2[4]; + __le16 probedelay; /* Reserved on v9 and later */ __le16 capability; u8 rates[MAX_RATES]; u8 tlv_memory_size_pad[100]; @@ -558,8 +560,10 @@ struct adhoc_bssdesc { u8 dtimperiod; __le64 timestamp; __le64 localtime; - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; + struct ieee_ie_ds_param_set ds; + u8 reserved1[4]; + struct ieee_ie_ibss_param_set ibss; + u8 reserved2[4]; __le16 capability; u8 rates[MAX_RATES]; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8124db3..38b0560 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -513,10 +513,10 @@ void lbs_scan_worker(struct work_struct *work) static int lbs_process_bss(struct bss_descriptor *bss, uint8_t **pbeaconinfo, int *bytesleft) { - struct ieeetypes_fhparamset *pFH; - struct ieeetypes_dsparamset *pDS; - struct ieeetypes_cfparamset *pCF; - struct ieeetypes_ibssparamset *pibss; + struct ieee_ie_fh_param_set *fh; + struct ieee_ie_ds_param_set *ds; + struct ieee_ie_cf_param_set *cf; + struct ieee_ie_ibss_param_set *ibss; DECLARE_SSID_BUF(ssid); struct ieeetypes_countryinfoset *pcountryinfo; uint8_t *pos, *end, *p; @@ -616,32 +616,28 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; case WLAN_EID_FH_PARAMS: - pFH = (struct ieeetypes_fhparamset *) pos; - memmove(&bss->phyparamset.fhparamset, pFH, - sizeof(struct ieeetypes_fhparamset)); + fh = (struct ieee_ie_fh_param_set *) pos; + memcpy(&bss->phy.fh, fh, sizeof(*fh)); lbs_deb_scan("got FH IE\n"); break; case WLAN_EID_DS_PARAMS: - pDS = (struct ieeetypes_dsparamset *) pos; - bss->channel = pDS->currentchan; - memcpy(&bss->phyparamset.dsparamset, pDS, - sizeof(struct ieeetypes_dsparamset)); + ds = (struct ieee_ie_ds_param_set *) pos; + bss->channel = ds->channel; + memcpy(&bss->phy.ds, ds, sizeof(*ds)); lbs_deb_scan("got DS IE, channel %d\n", bss->channel); break; case WLAN_EID_CF_PARAMS: - pCF = (struct ieeetypes_cfparamset *) pos; - memcpy(&bss->ssparamset.cfparamset, pCF, - sizeof(struct ieeetypes_cfparamset)); + cf = (struct ieee_ie_cf_param_set *) pos; + memcpy(&bss->ss.cf, cf, sizeof(*cf)); lbs_deb_scan("got CF IE\n"); break; case WLAN_EID_IBSS_PARAMS: - pibss = (struct ieeetypes_ibssparamset *) pos; - bss->atimwindow = le16_to_cpu(pibss->atimwindow); - memmove(&bss->ssparamset.ibssparamset, pibss, - sizeof(struct ieeetypes_ibssparamset)); + ibss = (struct ieee_ie_ibss_param_set *) pos; + bss->atimwindow = ibss->atimwindow; + memcpy(&bss->ss.ibss, ibss, sizeof(*ibss)); lbs_deb_scan("got IBSS IE\n"); break; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index de03b9c..b8d2ce9 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -8,7 +8,7 @@ #include #include -struct ieeetypes_cfparamset { +struct ieee_ie_cf_param_set { u8 elementid; u8 len; u8 cfpcnt; @@ -18,18 +18,18 @@ struct ieeetypes_cfparamset { } __attribute__ ((packed)); -struct ieeetypes_ibssparamset { +struct ieee_ie_ibss_param_set { u8 elementid; u8 len; __le16 atimwindow; } __attribute__ ((packed)); -union IEEEtypes_ssparamset { - struct ieeetypes_cfparamset cfparamset; - struct ieeetypes_ibssparamset ibssparamset; +union ieee_ss_param_set { + struct ieee_ie_cf_param_set cf; + struct ieee_ie_ibss_param_set ibss; } __attribute__ ((packed)); -struct ieeetypes_fhparamset { +struct ieee_ie_fh_param_set { u8 elementid; u8 len; __le16 dwelltime; @@ -38,18 +38,18 @@ struct ieeetypes_fhparamset { u8 hopindex; } __attribute__ ((packed)); -struct ieeetypes_dsparamset { +struct ieee_ie_ds_param_set { u8 elementid; u8 len; - u8 currentchan; + u8 channel; } __attribute__ ((packed)); -union ieeetypes_phyparamset { - struct ieeetypes_fhparamset fhparamset; - struct ieeetypes_dsparamset dsparamset; +union ieee_phy_param_set { + struct ieee_ie_fh_param_set fh; + struct ieee_ie_ds_param_set ds; } __attribute__ ((packed)); -struct ieeetypes_assocrsp { +struct ieee_assoc_response { __le16 capability; __le16 statuscode; __le16 aid; @@ -149,42 +149,17 @@ struct mrvlietypes_chanlistparamset { struct chanscanparamset chanscanparam[1]; } __attribute__ ((packed)); -struct cfparamset { +struct mrvlietypes_cfparamset { + struct mrvlietypesheader header; u8 cfpcnt; u8 cfpperiod; __le16 cfpmaxduration; __le16 cfpdurationremaining; } __attribute__ ((packed)); -struct ibssparamset { - __le16 atimwindow; -} __attribute__ ((packed)); - -struct mrvlietypes_ssparamset { - struct mrvlietypesheader header; - union { - struct cfparamset cfparamset[1]; - struct ibssparamset ibssparamset[1]; - } cf_ibss; -} __attribute__ ((packed)); - -struct fhparamset { - __le16 dwelltime; - u8 hopset; - u8 hoppattern; - u8 hopindex; -} __attribute__ ((packed)); - -struct dsparamset { - u8 currentchan; -} __attribute__ ((packed)); - -struct mrvlietypes_phyparamset { +struct mrvlietypes_dsparamset { struct mrvlietypesheader header; - union { - struct fhparamset fhparamset[1]; - struct dsparamset dsparamset[1]; - } fh_ds; + u8 channel; } __attribute__ ((packed)); struct mrvlietypes_rsnparamset { -- cgit v0.10.2 From 75b6a61a47353fd404277ae3f2dda03af96a8c1a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 May 2009 20:03:09 -0400 Subject: libertas: restyle Marvell & IEEE TLV structure names Easier to read and more conformant with kernel style. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 4bc46a6..9a5408e 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -207,7 +207,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, COUNTRY_CODE_LEN + 1 + - sizeof(struct ieeetypes_subbandset) * nr_subband); + sizeof(struct ieee_subbandset) * nr_subband); return 0; } @@ -302,11 +302,9 @@ done: * @param parsed_region_chan pointer to parsed_region_chan_11d * @return 0 */ -static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* - countryinfo, +static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo, u8 band, - struct parsed_region_chan_11d * - parsed_region_chan) + struct parsed_region_chan_11d *parsed_region_chan) { u8 nr_subband, nrchan; u8 lastchan, firstchan; @@ -331,7 +329,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); if ((*(countryinfo->countrycode)) == 0 - || (countryinfo->len <= COUNTRY_CODE_LEN)) { + || (countryinfo->header.len <= COUNTRY_CODE_LEN)) { /* No region Info or Wrong region info: treat as No 11D info */ goto done; } @@ -349,8 +347,8 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, COUNTRY_CODE_LEN); - nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / - sizeof(struct ieeetypes_subbandset); + nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) / + sizeof(struct ieee_subbandset); for (j = 0, lastchan = 0; j < nr_subband; j++) { @@ -502,7 +500,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, { struct cmd_ds_802_11d_domain_info *pdomaininfo = &cmd->params.domaininfo; - struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; + struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain; u8 nr_subband = priv->domainreg.nr_subband; lbs_deb_enter(LBS_DEB_11D); @@ -524,16 +522,16 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, sizeof(domain->countrycode)); domain->header.len = - cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + + cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) + sizeof(domain->countrycode)); if (nr_subband) { memcpy(domain->subband, priv->domainreg.subband, - nr_subband * sizeof(struct ieeetypes_subbandset)); + nr_subband * sizeof(struct ieee_subbandset)); cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + le16_to_cpu(domain->header.len) + - sizeof(struct mrvlietypesheader) + + sizeof(struct mrvl_ie_header) + S_DS_GEN); } else { cmd->size = @@ -556,7 +554,7 @@ done: int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) { struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; - struct mrvlietypes_domainparamset *domain = &domaininfo->domain; + struct mrvl_ie_domain_param_set *domain = &domaininfo->domain; u16 action = le16_to_cpu(domaininfo->action); s16 ret = 0; u8 nr_subband = 0; @@ -567,7 +565,7 @@ int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) (int)le16_to_cpu(resp->size)); nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / - sizeof(struct ieeetypes_subbandset); + sizeof(struct ieee_subbandset); lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 4f4f47f..fb75d3e 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -20,35 +20,36 @@ struct cmd_ds_command; /** Data structure for Country IE*/ -struct ieeetypes_subbandset { +struct ieee_subbandset { u8 firstchan; u8 nrchan; u8 maxtxpwr; } __attribute__ ((packed)); -struct ieeetypes_countryinfoset { - u8 element_id; - u8 len; +struct ieee_ie_country_info_set { + struct ieee_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; + struct ieee_subbandset subband[1]; }; -struct ieeetypes_countryinfofullset { - u8 element_id; - u8 len; +struct ieee_ie_country_info_full_set { + struct ieee_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; + struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; } __attribute__ ((packed)); -struct mrvlietypes_domainparamset { - struct mrvlietypesheader header; +struct mrvl_ie_domain_param_set { + struct mrvl_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; + struct ieee_subbandset subband[1]; } __attribute__ ((packed)); struct cmd_ds_802_11d_domain_info { __le16 action; - struct mrvlietypes_domainparamset domain; + struct mrvl_ie_domain_param_set domain; } __attribute__ ((packed)); /** domain regulatory information */ @@ -57,7 +58,7 @@ struct lbs_802_11d_domain_reg { u8 countrycode[COUNTRY_CODE_LEN]; /** No. of subband*/ u8 nr_subband; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; + struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; }; struct chan_power_11d { diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index d4d1d80..75c67c9 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -342,13 +342,13 @@ static int lbs_adhoc_start(struct lbs_private *priv, WARN_ON(!assoc_req->channel); /* set Physical parameter set */ - cmd.ds.elementid = WLAN_EID_DS_PARAMS; - cmd.ds.len = 1; + cmd.ds.header.id = WLAN_EID_DS_PARAMS; + cmd.ds.header.len = 1; cmd.ds.channel = assoc_req->channel; /* set IBSS parameter set */ - cmd.ibss.elementid = WLAN_EID_IBSS_PARAMS; - cmd.ibss.len = 2; + cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; + cmd.ibss.header.len = 2; cmd.ibss.atimwindow = cpu_to_le16(0); /* set capability info */ @@ -1558,11 +1558,11 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, struct bss_descriptor *bss = &assoc_req->bss; u8 *pos; u16 tmpcap, tmplen; - struct mrvlietypes_ssidparamset *ssid; - struct mrvlietypes_dsparamset *ds; - struct mrvlietypes_cfparamset *cf; - struct mrvlietypes_ratesparamset *rates; - struct mrvlietypes_rsnparamset *rsn; + struct mrvl_ie_ssid_param_set *ssid; + struct mrvl_ie_ds_param_set *ds; + struct mrvl_ie_cf_param_set *cf; + struct mrvl_ie_rates_param_set *rates; + struct mrvl_ie_rsn_param_set *rsn; lbs_deb_enter(LBS_DEB_ASSOC); @@ -1586,27 +1586,27 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, pos += sizeof(passo->bcnperiod); pos += sizeof(passo->dtimperiod); - ssid = (struct mrvlietypes_ssidparamset *) pos; + ssid = (struct mrvl_ie_ssid_param_set *) pos; ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); tmplen = bss->ssid_len; ssid->header.len = cpu_to_le16(tmplen); memcpy(ssid->ssid, bss->ssid, tmplen); pos += sizeof(ssid->header) + tmplen; - ds = (struct mrvlietypes_dsparamset *) pos; + ds = (struct mrvl_ie_ds_param_set *) pos; ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); ds->header.len = cpu_to_le16(1); ds->channel = bss->phy.ds.channel; pos += sizeof(ds->header) + 1; - cf = (struct mrvlietypes_cfparamset *) pos; + cf = (struct mrvl_ie_cf_param_set *) pos; cf->header.type = cpu_to_le16(TLV_TYPE_CF); tmplen = sizeof(*cf) - sizeof (cf->header); cf->header.len = cpu_to_le16(tmplen); /* IE payload should be zeroed, firmware fills it in for us */ pos += sizeof(*cf); - rates = (struct mrvlietypes_ratesparamset *) pos; + rates = (struct mrvl_ie_rates_param_set *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); memcpy(&rates->rates, &bss->rates, MAX_RATES); tmplen = MAX_RATES; @@ -1628,7 +1628,7 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, lbs_set_basic_rate_flags(rates->rates, tmplen); if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - rsn = (struct mrvlietypes_rsnparamset *) pos; + rsn = (struct mrvl_ie_rsn_param_set *) pos; /* WPA_IE or WPA2_IE */ rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); tmplen = (u16) assoc_req->wpa_ie[1]; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c455b9a..ed079c1 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1470,8 +1470,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, break; case CMD_802_11_LED_GPIO_CTRL: { - struct mrvlietypes_ledgpio *gpio = - (struct mrvlietypes_ledgpio*) + struct mrvl_ie_ledgpio *gpio = + (struct mrvl_ie_ledgpio*) cmdptr->params.ledgpio.data; memmove(&cmdptr->params.ledgpio, diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 50e28a0..811ffc3 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -183,12 +183,12 @@ out_unlock: */ static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) { - struct mrvlietypesheader *tlv_h; + struct mrvl_ie_header *tlv_h; uint16_t length; ssize_t pos = 0; while (pos < size) { - tlv_h = (struct mrvlietypesheader *) tlv; + tlv_h = (struct mrvl_ie_header *) tlv; if (!tlv_h->len) return NULL; if (tlv_h->type == cpu_to_le16(tlv_type)) @@ -206,7 +206,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, size_t count, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *subscribed; - struct mrvlietypes_thresholds *got; + struct mrvl_ie_thresholds *got; struct lbs_private *priv = file->private_data; ssize_t ret = 0; size_t pos = 0; @@ -259,7 +259,7 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *events; - struct mrvlietypes_thresholds *tlv; + struct mrvl_ie_thresholds *tlv; struct lbs_private *priv = file->private_data; ssize_t buf_size; int value, freq, new_mask; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index d0de8c7..9e11f90 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -353,7 +353,7 @@ struct bss_descriptor { union ieee_phy_param_set phy; union ieee_ss_param_set ss; - struct ieeetypes_countryinfofullset countryinfo; + struct ieee_ie_country_info_full_set countryinfo; u8 wpa_ie[MAX_WPA_IE_LEN]; size_t wpa_ie_len; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 38b0560..e5e30b2 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -27,12 +27,12 @@ + 40) /* 40 for WPAIE */ //! Memory needed to store a max sized channel List TLV for a firmware scan -#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \ +#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \ + (MRVDRV_MAX_CHANNELS_PER_SCAN \ * sizeof(struct chanscanparamset))) //! Memory needed to store a max number/size SSID TLV for a firmware scan -#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) +#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set)) //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ @@ -211,7 +211,7 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, */ static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) { - struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; + struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv; ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); @@ -249,7 +249,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, int chan_count) { size_t size = sizeof(struct chanscanparamset) *chan_count; - struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv; + struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); memcpy(chan_tlv->chanscanparam, chan_list, size); @@ -270,7 +270,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, static int lbs_scan_add_rates_tlv(uint8_t *tlv) { int i; - struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv; + struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); tlv += sizeof(rate_tlv->header); @@ -518,7 +518,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, struct ieee_ie_cf_param_set *cf; struct ieee_ie_ibss_param_set *ibss; DECLARE_SSID_BUF(ssid); - struct ieeetypes_countryinfoset *pcountryinfo; + struct ieee_ie_country_info_set *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; uint16_t beaconsize = 0; @@ -642,20 +642,23 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; case WLAN_EID_COUNTRY: - pcountryinfo = (struct ieeetypes_countryinfoset *) pos; + pcountryinfo = (struct ieee_ie_country_info_set *) pos; lbs_deb_scan("got COUNTRY IE\n"); - if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) - || pcountryinfo->len > 254) { - lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n", - pcountryinfo->len, sizeof(pcountryinfo->countrycode)); + if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode) + || pcountryinfo->header.len > 254) { + lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n", + __func__, + pcountryinfo->header.len, + sizeof(pcountryinfo->countrycode)); ret = -1; goto done; } - memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); + memcpy(&bss->countryinfo, pcountryinfo, + pcountryinfo->header.len + 2); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", (uint8_t *) pcountryinfo, - (int) (pcountryinfo->len + 2)); + (int) (pcountryinfo->header.len + 2)); break; case WLAN_EID_EXT_SUPP_RATES: diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index b8d2ce9..1055ecf 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -8,9 +8,14 @@ #include #include -struct ieee_ie_cf_param_set { - u8 elementid; +struct ieee_ie_header { + u8 id; u8 len; +} __attribute__ ((packed)); + +struct ieee_ie_cf_param_set { + struct ieee_ie_header header; + u8 cfpcnt; u8 cfpperiod; __le16 cfpmaxduration; @@ -19,8 +24,8 @@ struct ieee_ie_cf_param_set { struct ieee_ie_ibss_param_set { - u8 elementid; - u8 len; + struct ieee_ie_header header; + __le16 atimwindow; } __attribute__ ((packed)); @@ -30,8 +35,8 @@ union ieee_ss_param_set { } __attribute__ ((packed)); struct ieee_ie_fh_param_set { - u8 elementid; - u8 len; + struct ieee_ie_header header; + __le16 dwelltime; u8 hopset; u8 hoppattern; @@ -39,8 +44,8 @@ struct ieee_ie_fh_param_set { } __attribute__ ((packed)); struct ieee_ie_ds_param_set { - u8 elementid; - u8 len; + struct ieee_ie_header header; + u8 channel; } __attribute__ ((packed)); @@ -98,28 +103,28 @@ struct ieee_assoc_response { #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) /** TLV related data structures*/ -struct mrvlietypesheader { +struct mrvl_ie_header { __le16 type; __le16 len; } __attribute__ ((packed)); -struct mrvlietypes_data { - struct mrvlietypesheader header; +struct mrvl_ie_data { + struct mrvl_ie_header header; u8 Data[1]; } __attribute__ ((packed)); -struct mrvlietypes_ratesparamset { - struct mrvlietypesheader header; +struct mrvl_ie_rates_param_set { + struct mrvl_ie_header header; u8 rates[1]; } __attribute__ ((packed)); -struct mrvlietypes_ssidparamset { - struct mrvlietypesheader header; +struct mrvl_ie_ssid_param_set { + struct mrvl_ie_header header; u8 ssid[1]; } __attribute__ ((packed)); -struct mrvlietypes_wildcardssidparamset { - struct mrvlietypesheader header; +struct mrvl_ie_wildcard_ssid_param_set { + struct mrvl_ie_header header; u8 MaxSsidlength; u8 ssid[1]; } __attribute__ ((packed)); @@ -144,66 +149,66 @@ struct chanscanparamset { __le16 maxscantime; } __attribute__ ((packed)); -struct mrvlietypes_chanlistparamset { - struct mrvlietypesheader header; +struct mrvl_ie_chanlist_param_set { + struct mrvl_ie_header header; struct chanscanparamset chanscanparam[1]; } __attribute__ ((packed)); -struct mrvlietypes_cfparamset { - struct mrvlietypesheader header; +struct mrvl_ie_cf_param_set { + struct mrvl_ie_header header; u8 cfpcnt; u8 cfpperiod; __le16 cfpmaxduration; __le16 cfpdurationremaining; } __attribute__ ((packed)); -struct mrvlietypes_dsparamset { - struct mrvlietypesheader header; +struct mrvl_ie_ds_param_set { + struct mrvl_ie_header header; u8 channel; } __attribute__ ((packed)); -struct mrvlietypes_rsnparamset { - struct mrvlietypesheader header; +struct mrvl_ie_rsn_param_set { + struct mrvl_ie_header header; u8 rsnie[1]; } __attribute__ ((packed)); -struct mrvlietypes_tsftimestamp { - struct mrvlietypesheader header; +struct mrvl_ie_tsf_timestamp { + struct mrvl_ie_header header; __le64 tsftable[1]; } __attribute__ ((packed)); /** Local Power capability */ -struct mrvlietypes_powercapability { - struct mrvlietypesheader header; +struct mrvl_ie_power_capability { + struct mrvl_ie_header header; s8 minpower; s8 maxpower; } __attribute__ ((packed)); /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */ -struct mrvlietypes_thresholds { - struct mrvlietypesheader header; +struct mrvl_ie_thresholds { + struct mrvl_ie_header header; u8 value; u8 freq; } __attribute__ ((packed)); -struct mrvlietypes_beaconsmissed { - struct mrvlietypesheader header; +struct mrvl_ie_beacons_missed { + struct mrvl_ie_header header; u8 beaconmissed; u8 reserved; } __attribute__ ((packed)); -struct mrvlietypes_numprobes { - struct mrvlietypesheader header; +struct mrvl_ie_num_probes { + struct mrvl_ie_header header; __le16 numprobes; } __attribute__ ((packed)); -struct mrvlietypes_bcastprobe { - struct mrvlietypesheader header; +struct mrvl_ie_bcast_probe { + struct mrvl_ie_header header; __le16 bcastprobe; } __attribute__ ((packed)); -struct mrvlietypes_numssidprobe { - struct mrvlietypesheader header; +struct mrvl_ie_num_ssid_probe { + struct mrvl_ie_header header; __le16 numssidprobe; } __attribute__ ((packed)); @@ -212,8 +217,8 @@ struct led_pin { u8 pin; } __attribute__ ((packed)); -struct mrvlietypes_ledgpio { - struct mrvlietypesheader header; +struct mrvl_ie_ledgpio { + struct mrvl_ie_header header; struct led_pin ledpin[1]; } __attribute__ ((packed)); @@ -225,8 +230,8 @@ struct led_bhv { } __attribute__ ((packed)); -struct mrvlietypes_ledbhv { - struct mrvlietypesheader header; +struct mrvl_ie_ledbhv { + struct mrvl_ie_header header; struct led_bhv ledbhv[1]; } __attribute__ ((packed)); -- cgit v0.10.2 From be0d76e48f6cc1f8b01eeb5efbeea41f2efdab49 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 May 2009 20:05:25 -0400 Subject: libertas: convert CMD_802_11_AUTHENTICATE to a direct command And fix up setting authentication suite for v9+ firmware too. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 75c67c9..d004170 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -19,8 +19,9 @@ static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/* The firmware needs certain bits masked out of the beacon-derviced capability - * field when associating/joining to BSSs. +/* The firmware needs the following bits masked out of the beacon-derived + * capability field when associating/joining to a BSS: + * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) */ #define CAPINFO_MASK (~(0xda00)) @@ -102,6 +103,52 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) } +static u8 iw_auth_to_ieee_auth(u8 auth) +{ + if (auth == IW_AUTH_ALG_OPEN_SYSTEM) + return 0x00; + else if (auth == IW_AUTH_ALG_SHARED_KEY) + return 0x01; + else if (auth == IW_AUTH_ALG_LEAP) + return 0x80; + + lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth); + return 0; +} + +/** + * @brief This function prepares the authenticate command. AUTHENTICATE only + * sets the authentication suite for future associations, as the firmware + * handles authentication internally during the ASSOCIATE command. + * + * @param priv A pointer to struct lbs_private structure + * @param bssid The peer BSSID with which to authenticate + * @param auth The authentication mode to use (from wireless.h) + * + * @return 0 or -1 + */ +static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth) +{ + struct cmd_ds_802_11_authenticate cmd; + int ret = -1; + DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.bssid, bssid, ETH_ALEN); + + cmd.authtype = iw_auth_to_ieee_auth(auth); + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bssid), cmd.authtype); + + ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); + + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + /** * @brief Associate to a specific BSS discovered in a scan * @@ -118,11 +165,15 @@ static int lbs_associate(struct lbs_private *priv, 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 out; + /* FW v9 and higher indicate authentication suites as a TLV in the + * association command, not as a separate authentication command. + */ + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_authentication(priv, assoc_req->bss.bssid, + priv->secinfo.auth_mode); + if (ret) + goto out; + } /* Use short preamble only when both the BSS and firmware support it */ if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && @@ -1466,57 +1517,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) /** - * @brief This function prepares command of authenticate. - * - * @param priv A pointer to struct lbs_private structure - * @param cmd A pointer to cmd_ds_command structure - * @param pdata_buf Void cast of pointer to a BSSID to authenticate with - * - * @return 0 or -1 - */ -int lbs_cmd_80211_authenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf) -{ - struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; - int ret = -1; - u8 *bssid = pdata_buf; - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) - + S_DS_GEN); - - /* translate auth mode to 802.11 defined wire value */ - switch (priv->secinfo.auth_mode) { - case IW_AUTH_ALG_OPEN_SYSTEM: - pauthenticate->authtype = 0x00; - break; - case IW_AUTH_ALG_SHARED_KEY: - pauthenticate->authtype = 0x01; - break; - case IW_AUTH_ALG_LEAP: - pauthenticate->authtype = 0x80; - break; - default: - lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", - priv->secinfo.auth_mode); - goto out; - } - - memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - - lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", - bssid, pauthenticate->authtype); - ret = 0; - -out: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -/** * @brief Deauthenticate from a specific BSS * * @param priv A pointer to struct lbs_private structure @@ -1557,12 +1557,13 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, struct assoc_request *assoc_req = pdata_buf; struct bss_descriptor *bss = &assoc_req->bss; u8 *pos; - u16 tmpcap, tmplen; + u16 tmpcap, tmplen, tmpauth; struct mrvl_ie_ssid_param_set *ssid; struct mrvl_ie_ds_param_set *ds; struct mrvl_ie_cf_param_set *cf; struct mrvl_ie_rates_param_set *rates; struct mrvl_ie_rsn_param_set *rsn; + struct mrvl_ie_auth_type *auth; lbs_deb_enter(LBS_DEB_ASSOC); @@ -1627,6 +1628,21 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, */ lbs_set_basic_rate_flags(rates->rates, tmplen); + /* Firmware v9+ indicate authentication suites as a TLV */ + if (priv->fwrelease >= 0x09000000) { + DECLARE_MAC_BUF(mac); + + auth = (struct mrvl_ie_auth_type *) pos; + auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth->header.len = cpu_to_le16(2); + tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); + auth->auth = cpu_to_le16(tmpauth); + pos += sizeof(auth->header) + 2; + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bss->bssid), priv->secinfo.auth_mode); + } + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { rsn = (struct mrvl_ie_rsn_param_set *) pos; /* WPA_IE or WPA2_IE */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index ed079c1..bd740fc 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1220,8 +1220,7 @@ static void lbs_submit_command(struct lbs_private *priv, command = le16_to_cpu(cmd->command); /* These commands take longer */ - if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || - command == CMD_802_11_AUTHENTICATE) + if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE) timeo = 5 * HZ; lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", @@ -1420,10 +1419,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_AUTHENTICATE: - ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); - break; - case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bcf2a97..a830eca 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -225,7 +225,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): break; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 463ff97..4c930bd 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -250,7 +250,9 @@ struct cmd_ds_gspi_bus_config { } __attribute__ ((packed)); struct cmd_ds_802_11_authenticate { - u8 macaddr[ETH_ALEN]; + struct cmd_header hdr; + + u8 bssid[ETH_ALEN]; u8 authtype; u8 reserved[10]; } __attribute__ ((packed)); @@ -770,7 +772,6 @@ 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_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_rf_antenna rant; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 1055ecf..4ad3bb6 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -99,6 +99,7 @@ struct ieee_assoc_response { #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) #define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) +#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) @@ -177,6 +178,12 @@ struct mrvl_ie_tsf_timestamp { __le64 tsftable[1]; } __attribute__ ((packed)); +/* v9 and later firmware only */ +struct mrvl_ie_auth_type { + struct mrvl_ie_header header; + __le16 auth; +} __attribute__ ((packed)); + /** Local Power capability */ struct mrvl_ie_power_capability { struct mrvl_ie_header header; -- cgit v0.10.2 From 822ac03a07cc9e714727a6d49ea050b92483f82a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 May 2009 20:07:14 -0400 Subject: libertas: convert CMD_802_11_ASSOCIATE to a direct command Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index d004170..cb73720 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -12,8 +12,6 @@ #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 }; static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = @@ -149,6 +147,249 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth return ret; } + +static int lbs_assoc_post(struct lbs_private *priv, + struct cmd_ds_802_11_associate_response *resp) +{ + int ret = 0; + union iwreq_data wrqu; + struct bss_descriptor *bss; + u16 status_code; + + lbs_deb_enter(LBS_DEB_ASSOC); + + if (!priv->in_progress_assoc_req) { + lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + /* + * Older FW versions map the IEEE 802.11 Status Code in the association + * response to the following values returned in resp->statuscode: + * + * IEEE Status Code Marvell Status Code + * 0 -> 0x0000 ASSOC_RESULT_SUCCESS + * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * others -> 0x0003 ASSOC_RESULT_REFUSED + * + * Other response codes: + * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) + * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for + * association response from the AP) + */ + + status_code = le16_to_cpu(resp->statuscode); + if (priv->fwrelease < 0x09000000) { + switch (status_code) { + case 0x00: + break; + case 0x01: + lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); + break; + case 0x02: + lbs_deb_assoc("ASSOC_RESP: internal timer " + "expired while waiting for the AP\n"); + break; + case 0x03: + lbs_deb_assoc("ASSOC_RESP: association " + "refused by AP\n"); + break; + case 0x04: + lbs_deb_assoc("ASSOC_RESP: authentication " + "refused by AP\n"); + break; + default: + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " + " unknown\n", status_code); + break; + } + } else { + /* v9+ returns the AP's association response */ + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code); + } + + if (status_code) { + lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + + lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", + (void *) (resp + sizeof (resp->hdr)), + le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr)); + + /* Send a Media Connected event, according to the Spec */ + priv->connect_status = LBS_CONNECTED; + + /* Update current SSID and BSSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; + priv->NF[TYPE_RXPD][TYPE_AVG] = 0; + + memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); + memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); + priv->nextSNRNF = 0; + priv->numSNRNF = 0; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + +/** + * @brief This function prepares an association-class command. + * + * @param priv A pointer to struct lbs_private structure + * @param assoc_req The association request describing the BSS to associate + * or reassociate with + * @param command The actual command, either CMD_802_11_ASSOCIATE or + * CMD_802_11_REASSOCIATE + * + * @return 0 or -1 + */ +static int lbs_associate(struct lbs_private *priv, + struct assoc_request *assoc_req, + u16 command) +{ + struct cmd_ds_802_11_associate cmd; + int ret = 0; + struct bss_descriptor *bss = &assoc_req->bss; + u8 *pos = &(cmd.iebuf[0]); + u16 tmpcap, tmplen, tmpauth; + struct mrvl_ie_ssid_param_set *ssid; + struct mrvl_ie_ds_param_set *ds; + struct mrvl_ie_cf_param_set *cf; + struct mrvl_ie_rates_param_set *rates; + struct mrvl_ie_rsn_param_set *rsn; + struct mrvl_ie_auth_type *auth; + + lbs_deb_enter(LBS_DEB_ASSOC); + + BUG_ON((command != CMD_802_11_ASSOCIATE) && + (command != CMD_802_11_REASSOCIATE)); + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.command = cpu_to_le16(command); + + /* Fill in static fields */ + memcpy(cmd.bssid, bss->bssid, ETH_ALEN); + cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); + + /* Capability info */ + tmpcap = (bss->capability & CAPINFO_MASK); + if (bss->mode == IW_MODE_INFRA) + tmpcap |= WLAN_CAPABILITY_ESS; + cmd.capability = cpu_to_le16(tmpcap); + lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); + + /* SSID */ + ssid = (struct mrvl_ie_ssid_param_set *) pos; + ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); + tmplen = bss->ssid_len; + ssid->header.len = cpu_to_le16(tmplen); + memcpy(ssid->ssid, bss->ssid, tmplen); + pos += sizeof(ssid->header) + tmplen; + + ds = (struct mrvl_ie_ds_param_set *) pos; + ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); + ds->header.len = cpu_to_le16(1); + ds->channel = bss->phy.ds.channel; + pos += sizeof(ds->header) + 1; + + cf = (struct mrvl_ie_cf_param_set *) pos; + cf->header.type = cpu_to_le16(TLV_TYPE_CF); + tmplen = sizeof(*cf) - sizeof (cf->header); + cf->header.len = cpu_to_le16(tmplen); + /* IE payload should be zeroed, firmware fills it in for us */ + pos += sizeof(*cf); + + rates = (struct mrvl_ie_rates_param_set *) pos; + rates->header.type = cpu_to_le16(TLV_TYPE_RATES); + memcpy(&rates->rates, &bss->rates, MAX_RATES); + tmplen = MAX_RATES; + if (get_common_rates(priv, rates->rates, &tmplen)) { + ret = -1; + goto done; + } + pos += sizeof(rates->header) + tmplen; + rates->header.len = cpu_to_le16(tmplen); + lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); + + /* Copy the infra. association rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(rates->rates, tmplen); + + /* Firmware v9+ indicate authentication suites as a TLV */ + if (priv->fwrelease >= 0x09000000) { + DECLARE_MAC_BUF(mac); + + auth = (struct mrvl_ie_auth_type *) pos; + auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth->header.len = cpu_to_le16(2); + tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); + auth->auth = cpu_to_le16(tmpauth); + pos += sizeof(auth->header) + 2; + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bss->bssid), priv->secinfo.auth_mode); + } + + /* WPA/WPA2 IEs */ + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { + rsn = (struct mrvl_ie_rsn_param_set *) pos; + /* WPA_IE or WPA2_IE */ + rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); + tmplen = (u16) assoc_req->wpa_ie[1]; + rsn->header.len = cpu_to_le16(tmplen); + memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn, + sizeof(rsn->header) + tmplen); + pos += sizeof(rsn->header) + tmplen; + } + + cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) + + (u16)(pos - (u8 *) &cmd.iebuf)); + + /* update curbssparams */ + priv->curbssparams.channel = bss->phy.ds.channel; + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto done; + } + + ret = lbs_cmd_with_response(priv, command, &cmd); + if (ret == 0) { + ret = lbs_assoc_post(priv, + (struct cmd_ds_802_11_associate_response *) &cmd); + } + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + /** * @brief Associate to a specific BSS discovered in a scan * @@ -157,7 +398,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth * * @return 0-success, otherwise fail */ -static int lbs_associate(struct lbs_private *priv, +static int lbs_try_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret; @@ -184,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv, if (ret) goto out; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } +static int lbs_adhoc_post(struct lbs_private *priv, + struct cmd_ds_802_11_ad_hoc_result *resp) +{ + int ret = 0; + u16 command = le16_to_cpu(resp->hdr.command); + u16 result = le16_to_cpu(resp->hdr.result); + union iwreq_data wrqu; + struct bss_descriptor *bss; + DECLARE_SSID_BUF(ssid); + + lbs_deb_enter(LBS_DEB_JOIN); + + if (!priv->in_progress_assoc_req) { + lbs_deb_join("ADHOC_RESP: no in-progress association " + "request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + /* + * Join result code 0 --> SUCCESS + */ + if (result) { + 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; + } + + /* 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, resp->bssid, ETH_ALEN); + } + + /* Set the BSSID from the joined/started descriptor */ + memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + /* Set the new SSID to current SSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", + print_ssid(ssid, bss->ssid, bss->ssid_len), + priv->curbssparams.bssid, + priv->curbssparams.channel); + +done: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + /** * @brief Join an adhoc network found in a previous scan * @@ -337,8 +642,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, } 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); + if (ret == 0) { + ret = lbs_adhoc_post(priv, + (struct cmd_ds_802_11_ad_hoc_result *)&cmd); + } out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -445,7 +752,8 @@ static int lbs_adhoc_start(struct lbs_private *priv, 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); + ret = lbs_adhoc_post(priv, + (struct cmd_ds_802_11_ad_hoc_result *)&cmd); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -770,7 +1078,7 @@ static int assoc_helper_essid(struct lbs_private *priv, assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); if (bss != NULL) { memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - ret = lbs_associate(priv, assoc_req); + ret = lbs_try_associate(priv, assoc_req); } else { lbs_deb_assoc("SSID not found; cannot associate\n"); } @@ -822,8 +1130,9 @@ static int assoc_helper_bssid(struct lbs_private *priv, memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); if (assoc_req->mode == IW_MODE_INFRA) { - ret = lbs_associate(priv, assoc_req); - lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); + ret = lbs_try_associate(priv, assoc_req); + lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n", + ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { lbs_adhoc_join(priv, assoc_req); } @@ -1549,299 +1858,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], return ret; } -int lbs_cmd_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_associate *passo = &cmd->params.associate; - int ret = 0; - struct assoc_request *assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - u8 *pos; - u16 tmpcap, tmplen, tmpauth; - struct mrvl_ie_ssid_param_set *ssid; - struct mrvl_ie_ds_param_set *ds; - struct mrvl_ie_cf_param_set *cf; - struct mrvl_ie_rates_param_set *rates; - struct mrvl_ie_rsn_param_set *rsn; - struct mrvl_ie_auth_type *auth; - - lbs_deb_enter(LBS_DEB_ASSOC); - - pos = (u8 *) passo; - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); - - memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); - pos += sizeof(passo->peerstaaddr); - - /* set the listen interval */ - passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); - - pos += sizeof(passo->capability); - pos += sizeof(passo->listeninterval); - pos += sizeof(passo->bcnperiod); - pos += sizeof(passo->dtimperiod); - - ssid = (struct mrvl_ie_ssid_param_set *) pos; - ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); - tmplen = bss->ssid_len; - ssid->header.len = cpu_to_le16(tmplen); - memcpy(ssid->ssid, bss->ssid, tmplen); - pos += sizeof(ssid->header) + tmplen; - - ds = (struct mrvl_ie_ds_param_set *) pos; - ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); - ds->header.len = cpu_to_le16(1); - ds->channel = bss->phy.ds.channel; - pos += sizeof(ds->header) + 1; - - cf = (struct mrvl_ie_cf_param_set *) pos; - cf->header.type = cpu_to_le16(TLV_TYPE_CF); - tmplen = sizeof(*cf) - sizeof (cf->header); - cf->header.len = cpu_to_le16(tmplen); - /* IE payload should be zeroed, firmware fills it in for us */ - pos += sizeof(*cf); - - rates = (struct mrvl_ie_rates_param_set *) pos; - rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - memcpy(&rates->rates, &bss->rates, MAX_RATES); - tmplen = MAX_RATES; - if (get_common_rates(priv, rates->rates, &tmplen)) { - ret = -1; - goto done; - } - pos += sizeof(rates->header) + tmplen; - rates->header.len = cpu_to_le16(tmplen); - lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); - - /* Copy the infra. association rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(rates->rates, tmplen); - - /* Firmware v9+ indicate authentication suites as a TLV */ - if (priv->fwrelease >= 0x09000000) { - DECLARE_MAC_BUF(mac); - - auth = (struct mrvl_ie_auth_type *) pos; - auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); - auth->header.len = cpu_to_le16(2); - tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); - auth->auth = cpu_to_le16(tmpauth); - pos += sizeof(auth->header) + 2; - - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bss->bssid), priv->secinfo.auth_mode); - } - - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - rsn = (struct mrvl_ie_rsn_param_set *) pos; - /* WPA_IE or WPA2_IE */ - rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); - tmplen = (u16) assoc_req->wpa_ie[1]; - rsn->header.len = cpu_to_le16(tmplen); - memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); - lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, - sizeof(rsn->header) + tmplen); - pos += sizeof(rsn->header) + tmplen; - } - - /* update curbssparams */ - priv->curbssparams.channel = bss->phy.ds.channel; - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); - - /* set the capability info */ - tmpcap = (bss->capability & CAPINFO_MASK); - if (bss->mode == IW_MODE_INFRA) - tmpcap |= WLAN_CAPABILITY_ESS; - passo->capability = cpu_to_le16(tmpcap); - lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -int lbs_ret_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - int ret = 0; - union iwreq_data wrqu; - struct ieee_assoc_response *passocrsp; - struct bss_descriptor *bss; - u16 status_code; - - lbs_deb_enter(LBS_DEB_ASSOC); - - if (!priv->in_progress_assoc_req) { - lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - passocrsp = (struct ieee_assoc_response *) &resp->params; - - /* - * Older FW versions map the IEEE 802.11 Status Code in the association - * response to the following values returned in passocrsp->statuscode: - * - * IEEE Status Code Marvell Status Code - * 0 -> 0x0000 ASSOC_RESULT_SUCCESS - * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * others -> 0x0003 ASSOC_RESULT_REFUSED - * - * Other response codes: - * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) - * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for - * association response from the AP) - */ - - status_code = le16_to_cpu(passocrsp->statuscode); - switch (status_code) { - case 0x00: - break; - case 0x01: - lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); - break; - case 0x02: - lbs_deb_assoc("ASSOC_RESP: internal timer " - "expired while waiting for the AP\n"); - break; - case 0x03: - lbs_deb_assoc("ASSOC_RESP: association " - "refused by AP\n"); - break; - case 0x04: - lbs_deb_assoc("ASSOC_RESP: authentication " - "refused by AP\n"); - break; - default: - lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " - " unknown\n", status_code); - break; - } - - if (status_code) { - lbs_mac_event_disconnected(priv); - ret = -1; - goto done; - } - - lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, - le16_to_cpu(resp->size) - S_DS_GEN); - - /* Send a Media Connected event, according to the Spec */ - priv->connect_status = LBS_CONNECTED; - - /* Update current SSID and BSSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; - priv->NF[TYPE_RXPD][TYPE_AVG] = 0; - - memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); - memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); - priv->nextSNRNF = 0; - priv->numSNRNF = 0; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -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 *adhoc_resp; - union iwreq_data wrqu; - struct bss_descriptor *bss; - DECLARE_SSID_BUF(ssid); - - lbs_deb_enter(LBS_DEB_JOIN); - - 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 " - "request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - /* - * Join result code 0 --> SUCCESS - */ - if (result) { - 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; - } - - /* 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, adhoc_resp->bssid, ETH_ALEN); - } - - /* Set the BSSID from the joined/started descriptor */ - memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - /* Set the new SSID to current SSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", - print_ssid(ssid, bss->ssid, bss->ssid_len), - priv->curbssparams.bssid, - priv->curbssparams.channel); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 8b7336d..6e765e9 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -8,22 +8,9 @@ void lbs_association_worker(struct work_struct *work); struct assoc_request *lbs_get_association_request(struct lbs_private *priv); -struct cmd_ds_command; -int lbs_cmd_80211_authenticate(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, 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_associate(struct lbs_private *priv, - struct cmd_ds_command *resp); #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index bd740fc..01db705 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1414,11 +1414,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action); break; - case CMD_802_11_ASSOCIATE: - case CMD_802_11_REASSOCIATE: - ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); - break; - case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index a830eca..14b3d56 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -210,12 +210,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_reg_access(priv, respcmd, resp); break; - case CMD_RET_802_11_ASSOCIATE: - case CMD_RET(CMD_802_11_ASSOCIATE): - case CMD_RET(CMD_802_11_REASSOCIATE): - ret = lbs_ret_80211_associate(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); diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 4c930bd..0a2e291 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -265,22 +265,23 @@ struct cmd_ds_802_11_deauthenticate { } __attribute__ ((packed)); struct cmd_ds_802_11_associate { - u8 peerstaaddr[6]; + struct cmd_header hdr; + + u8 bssid[6]; __le16 capability; __le16 listeninterval; __le16 bcnperiod; u8 dtimperiod; - -#if 0 - mrvlietypes_ssidparamset_t ssidParamSet; - mrvlietypes_phyparamset_t phyparamset; - mrvlietypes_ssparamset_t ssparamset; - mrvlietypes_ratesparamset_t ratesParamSet; -#endif + u8 iebuf[512]; /* Enough for required and most optional IEs */ } __attribute__ ((packed)); -struct cmd_ds_802_11_associate_rsp { - struct ieee_assoc_response response; +struct cmd_ds_802_11_associate_response { + struct cmd_header hdr; + + __le16 capability; + __le16 statuscode; + __le16 aid; + u8 iebuf[512]; } __attribute__ ((packed)); struct cmd_ds_802_11_set_wep { @@ -771,7 +772,6 @@ struct cmd_ds_command { /* command Body */ union { struct cmd_ds_802_11_ps_mode psmode; - struct cmd_ds_802_11_associate associate; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_rf_antenna rant; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 4ad3bb6..99905df 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -54,13 +54,6 @@ union ieee_phy_param_set { struct ieee_ie_ds_param_set ds; } __attribute__ ((packed)); -struct ieee_assoc_response { - __le16 capability; - __le16 statuscode; - __le16 aid; - u8 iebuffer[1]; -} __attribute__ ((packed)); - /** TLV type ID definition */ #define PROPRIETARY_TLV_BASE_ID 0x0100 -- cgit v0.10.2 From 2fa7a98fc96abe431e5d54d97104cdca197391fa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 May 2009 20:09:58 -0400 Subject: libertas: fix WPA adhoc network creation Oddly enough, the firmware's JOIN/START commands don't appear to have any facility for setting custom IEs, thus the started adhoc network doesn't advertise its WPA capability in the beacon. Whee! Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index cb73720..b9b3741 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -711,11 +711,13 @@ static int lbs_adhoc_start(struct lbs_private *priv, /* set capability info */ tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); + if (assoc_req->secinfo.wep_enabled || + assoc_req->secinfo.WPAenabled || + assoc_req->secinfo.WPA2enabled) { + lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n"); tmpcap |= WLAN_CAPABILITY_PRIVACY; } else - lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); + lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n"); cmd.capability = cpu_to_le16(tmpcap); -- cgit v0.10.2 From e535c7566e1318ccfa015e297f0309994f7bc078 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 May 2009 11:18:45 +0200 Subject: mac80211: deprecate conf.beacon_int properly Ivo has updated the driver to no longer use the change flag, so we can remove that, but rt2x00 and ath5k still use the actual value so let's mark it as deprecated too. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d72346f..0270aa6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -527,7 +527,6 @@ enum ieee80211_conf_flags { * enum ieee80211_conf_changed - denotes which configuration changed * * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed - * @_IEEE80211_CONF_CHANGE_BEACON_INTERVAL: DEPRECATED * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed @@ -538,7 +537,6 @@ enum ieee80211_conf_flags { */ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), - _IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), @@ -548,14 +546,6 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_IDLE = BIT(8), }; -static inline __deprecated enum ieee80211_conf_changed -__IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void) -{ - return _IEEE80211_CONF_CHANGE_BEACON_INTERVAL; -} -#define IEEE80211_CONF_CHANGE_BEACON_INTERVAL \ - __IEEE80211_CONF_CHANGE_BEACON_INTERVAL() - /** * struct ieee80211_conf - configuration of the device * @@ -564,7 +554,7 @@ __IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void) * @flags: configuration flags defined above * * @radio_enabled: when zero, driver is required to switch off the radio. - * @beacon_int: beacon interval (TODO make interface config) + * @beacon_int: DEPRECATED, DO NOT USE * * @listen_interval: listen interval in units of beacon interval * @max_sleep_period: the maximum number of beacon intervals to sleep for @@ -589,7 +579,7 @@ __IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void) * number of transmissions not the number of retries */ struct ieee80211_conf { - int beacon_int; + int __deprecated beacon_int; u32 flags; int power_level, dynamic_ps_timeout; int max_sleep_period; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e37770c..2683df9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -289,16 +289,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, drv_bss_info_changed(local, &sdata->vif, &sdata->vif.bss_conf, changed); - /* - * DEPRECATED - * - * ~changed is just there to not do this at resume time - */ - if (changed & BSS_CHANGED_BEACON_INT && ~changed) { - local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; - ieee80211_hw_config(local, - _IEEE80211_CONF_CHANGE_BEACON_INTERVAL); - } + /* DEPRECATED */ + local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) -- cgit v0.10.2 From 6b347bff145f9a8a0972ca8fc3c44dd1f91b0f16 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 23 May 2009 21:09:28 +0200 Subject: rt2x00: Remove last usage of beacon_int from ieee80211_config This removes the last usage of beacon_int inside the iee80211_config structure from rt2x00. The attempt is a bit hackish, and subject to change in the future when the entire rt2x00_dev structure is cleaned up and restructured. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0197531..435f945 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -520,7 +520,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, CSR20, ®); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, - (libconf->conf->beacon_int - 20) * 16); + (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index f95cb64..08b30d0 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -569,7 +569,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, CSR20, ®); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, - (libconf->conf->beacon_int - 20) * 16); + (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 69f966f..66daf68 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -647,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, - libconf->conf->beacon_int - 20); + rt2x00dev->beacon_int - 20); rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 2b64a61..a498dde 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -802,6 +802,11 @@ struct rt2x00_dev { u8 calibration[2]; /* + * Beacon interval. + */ + u16 beacon_int; + + /* * Low level statistics which will have * to be kept up to date while device is running. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index c5bbf0b..3e019a1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -108,6 +108,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; + /* Update global beacon interval time, this is needed for PS support */ + rt2x00dev->beacon_int = bss_conf->beacon_int; + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a8bf5c4..49b29ff 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -956,7 +956,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, MAC_CSR11, ®); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, - libconf->conf->beacon_int - 10); + rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 211a3d6..c188488 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -852,7 +852,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, - libconf->conf->beacon_int - 10); + rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); -- cgit v0.10.2 From 51b50fbeb574f581c0b112e035541f42fa3e604a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 24 May 2009 16:42:30 +0200 Subject: cfg80211: validate AID of stations being added We have some validation code in mac80211 but said code will force an invalid AID to 0 which isn't a valid AID either; instead require a valid AID (1-2007) to be passed in from userspace in cfg80211 already. Also move the code before the race comment since it can only be executed during STA addition and thus is not racy. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 77e9ff5..cdfdb2e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -664,18 +664,19 @@ static void sta_apply_parameters(struct ieee80211_local *local, spin_unlock_bh(&sta->lock); /* + * cfg80211 validates this (1-2007) and allows setting the AID + * only when creating a new station entry + */ + if (params->aid) + sta->sta.aid = params->aid; + + /* * FIXME: updating the following information is racy when this * function is called from ieee80211_change_station(). * However, all this information should be static so * maybe we should just reject attemps to change it. */ - if (params->aid) { - sta->sta.aid = params->aid; - if (sta->sta.aid > IEEE80211_MAX_AID) - sta->sta.aid = 0; /* XXX: should this be an error? */ - } - if (params->listen_interval >= 0) sta->listen_interval = params->listen_interval; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4b4d3c8..19dc796 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1738,7 +1738,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); + params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + if (!params.aid || params.aid > IEEE80211_MAX_AID) + return -EINVAL; + if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) params.ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); -- cgit v0.10.2 From 362a415dce2130b0e4cebfc8f8fbd8128baff308 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 24 May 2009 16:43:15 +0200 Subject: nl80211: bounce scan request back to userspace When a scan finishes only the program that asked for it knows what kind of scan it was; let's tell everybody else about the scan parameters as well so they can evaluate the result of the scan better. Also helps with debugging. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 19dc796..909ebd6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3563,11 +3563,43 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); } +static int nl80211_add_scan_req(struct sk_buff *msg, + struct cfg80211_registered_device *rdev) +{ + struct cfg80211_scan_request *req = rdev->scan_req; + struct nlattr *nest; + int i; + + if (WARN_ON(!req)) + return 0; + + nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); + if (!nest) + goto nla_put_failure; + for (i = 0; i < req->n_ssids; i++) + NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); + nla_nest_end(msg, nest); + + nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); + if (!nest) + goto nla_put_failure; + for (i = 0; i < req->n_channels; i++) + NLA_PUT_U32(msg, i, req->channels[i]->center_freq); + nla_nest_end(msg, nest); + + if (req->ie) + NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); + + return 0; + nla_put_failure: + return -ENOBUFS; +} + static int nl80211_send_scan_donemsg(struct sk_buff *msg, - struct cfg80211_registered_device *rdev, - struct net_device *netdev, - u32 pid, u32 seq, int flags, - u32 cmd) + struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u32 pid, u32 seq, int flags, + u32 cmd) { void *hdr; @@ -3578,7 +3610,8 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); - /* XXX: we should probably bounce back the request? */ + /* ignore errors and send incomplete event anyway */ + nl80211_add_scan_req(msg, rdev); return genlmsg_end(msg, hdr); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index df59440..e95b638 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -29,13 +29,14 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) goto out; WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); - wiphy_to_dev(request->wiphy)->scan_req = NULL; if (aborted) nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); else nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); + wiphy_to_dev(request->wiphy)->scan_req = NULL; + #ifdef CONFIG_WIRELESS_EXT if (!aborted) { memset(&wrqu, 0, sizeof(wrqu)); -- cgit v0.10.2 From 8fc0fee09245fe740d81aded36f4af6db1054015 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 24 May 2009 16:57:19 +0200 Subject: cfg80211: use key size constants Instead of hardcoding the key length for validation, use the constants Zhu Yi recently added and add one for AES_CMAC too. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 34de8b2..a9173d5 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1092,6 +1092,7 @@ enum ieee80211_key_len { WLAN_KEY_LEN_WEP104 = 13, WLAN_KEY_LEN_CCMP = 16, WLAN_KEY_LEN_TKIP = 32, + WLAN_KEY_LEN_AES_CMAC = 16, }; /* diff --git a/net/wireless/util.c b/net/wireless/util.c index d072bff..5be9ed7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -157,26 +157,25 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, params->cipher != WLAN_CIPHER_SUITE_WEP104) return -EINVAL; - /* TODO: add definitions for the lengths to linux/ieee80211.h */ switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: - if (params->key_len != 5) + if (params->key_len != WLAN_KEY_LEN_WEP40) return -EINVAL; break; case WLAN_CIPHER_SUITE_TKIP: - if (params->key_len != 32) + if (params->key_len != WLAN_KEY_LEN_TKIP) return -EINVAL; break; case WLAN_CIPHER_SUITE_CCMP: - if (params->key_len != 16) + if (params->key_len != WLAN_KEY_LEN_CCMP) return -EINVAL; break; case WLAN_CIPHER_SUITE_WEP104: - if (params->key_len != 13) + if (params->key_len != WLAN_KEY_LEN_WEP104) return -EINVAL; break; case WLAN_CIPHER_SUITE_AES_CMAC: - if (params->key_len != 16) + if (params->key_len != WLAN_KEY_LEN_AES_CMAC) return -EINVAL; break; default: -- cgit v0.10.2 From d651ae32789cabfb78bdd1f3467bf034ae267d68 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Sun, 24 May 2009 20:43:50 +0300 Subject: iwlwifi: avoid build warning in iwl-core. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building when CONFIG_IWLWIFI_DEBUG is not set, we get the following warning: /work/src/w/drivers/net/wireless/iwlwifi/iwl-core.c: In function ‘iwl_isr’: /work/src/w/drivers/net/wireless/iwlwifi/iwl-core.c:1707: warning: unused variable ‘inta_fh’ This patch avoids this warning by adding #ifdef CONFIG_IWLWIFI_DEBUG before the declaration of inta_fh in iwl_isr() in drivers/net/wireless/iwlwifi/iwl-core.c Signed-off-by: Rami Rosen Acked-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a9da06f..ddd2219 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1704,8 +1704,9 @@ static irqreturn_t iwl_isr(int irq, void *data) { struct iwl_priv *priv = data; u32 inta, inta_mask; +#ifdef CONFIG_IWLWIFI_DEBUG u32 inta_fh; - +#endif if (!priv) return IRQ_NONE; -- cgit v0.10.2 From b63b0ea2c18bba44c934ec619ba47488553c3aa3 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 26 May 2009 11:10:46 +0800 Subject: iwmc3200wifi: fix fragmentation threshold setting We were sending the fragmentation threshold value to the wrong table, causing an LMAC assert when setting it from wext. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 3256ad2..96f714e 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -268,7 +268,7 @@ static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) iwm->conf.frag_threshold = wiphy->frag_threshold; - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, CFG_FRAG_THRESHOLD, iwm->conf.frag_threshold); if (ret < 0) -- cgit v0.10.2 From 1bb563334858f48f65b58bab6d10b54080f4ee42 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 May 2009 12:17:52 -0700 Subject: iwmc3200wifi: fix printk format Fix printk format for size_t variable: drivers/net/wireless/iwmc3200wifi/fw.c:75: warning: format '%d' expects type 'int', but argument 4 has type 'size_t' Signed-off-by: Randy Dunlap Cc: ilw@linux.intel.com Acked-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index db4ba08..ec1a15a 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -72,7 +72,7 @@ static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, } if (fw->size < IWM_HDR_LEN) { - IWM_ERR(iwm, "FW is too small (%d)\n", fw->size); + IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size); return -EINVAL; } -- cgit v0.10.2 From 7ba10a8efe501e26d995aa9b6dc13395518a87e4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 May 2009 09:41:06 +0200 Subject: mac80211: fix transposed min/max CW values I accidentally transposed these in the patch that "fixed" the defaults, leading to extremely low throughput because of the huge min CW. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 949d857..31284c9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -657,15 +657,15 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) switch (queue) { case 3: /* AC_BK */ - qparam.cw_max = aCWmin; - qparam.cw_min = aCWmax; + qparam.cw_max = aCWmax; + qparam.cw_min = aCWmin; qparam.txop = 0; qparam.aifs = 7; break; default: /* never happens but let's not leave undefined */ case 2: /* AC_BE */ - qparam.cw_max = aCWmin; - qparam.cw_min = aCWmax; + qparam.cw_max = aCWmax; + qparam.cw_min = aCWmin; qparam.txop = 0; qparam.aifs = 3; break; -- cgit v0.10.2 From 034d655ee7b79a2f48ba4c2b620d2864a6e0aa14 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 May 2009 10:35:29 +0200 Subject: cfg80211: disallow interfering with stations on non-AP (part 2) On non-AP interfaces userspace has no business interfering with the station management, this can confuse mac80211 (and other drivers probably wouldn't support it anyway). Allow adding and removing stations only on AP interfaces. (Reconcile this w/ previous version of patch posted with same subject... -- JWL) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 909ebd6..fd392ff 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1687,6 +1687,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out_rtnl; + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { + err = -EINVAL; + goto out; + } + err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); if (err) goto out; -- cgit v0.10.2 From b74444f8a9039603715973a56df588a5d800c4ef Mon Sep 17 00:00:00 2001 From: Jeff Hansen Date: Wed, 27 May 2009 12:48:27 +0000 Subject: ath9k: Reset SC_OP_TSF_RESET flag after stuck beacon I have a TrendNet 652-BRP running OpenWRT + ath9k very well. The only problem is that the beacon gets stuck maybe once a day. After Vasanthakumar Thiagarajan's "ath9k: cleanup beacon parameters configuration" patch, ath9k would nearly re-configure the beacons after it detected the stuck beacon, and did a reset. But it would fail the SC_OP_TSF_RESET check in ath_beacon_config_ap. This patch gets the beacon fully reconfigured after the reset. Signed-off-by: Jeff Hansen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index a21b213..0c67ed2 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -411,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data) } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, "beacon is officially stuck\n"); + sc->sc_flags |= SC_OP_TSF_RESET; ath_reset(sc, false); } -- cgit v0.10.2 From bedf087af96a24861d09586ac25c26691300ff4c Mon Sep 17 00:00:00 2001 From: Jeff Hansen Date: Wed, 27 May 2009 12:48:28 +0000 Subject: ath9k: Combine legacy and 11n rc statistics This patch combines the legacy and 11n rcstats into one, using the normal rate table indices instead of two separate indices for each mode. Legacy rates also get all of the PER and retry information, now, too. Signed-off-by: Jeff Hansen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 97df20c..80115ea 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -224,111 +224,66 @@ static const struct file_operations fops_interrupt = { .owner = THIS_MODULE }; -static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_tx_info_priv *tx_info_priv = NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - int final_ts_idx, idx; - - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; - idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; - - sc->debug.stats.n_rcstats[idx].success++; -} - -static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) +void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) { struct ath_tx_info_priv *tx_info_priv = NULL; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->status.rates; int final_ts_idx, idx; + struct ath_rc_stats *stats; tx_info_priv = ATH_TX_INFO_PRIV(tx_info); final_ts_idx = tx_info_priv->tx.ts_rateindex; idx = rates[final_ts_idx].idx; - - sc->debug.stats.legacy_rcstats[idx].success++; + stats = &sc->debug.stats.rcstats[idx]; + stats->success++; } -void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - if (conf_is_ht(&sc->hw->conf)) - ath_debug_stat_11n_rc(sc, skb); - else - ath_debug_stat_legacy_rc(sc, skb); -} - -/* FIXME: legacy rates, later on .. */ void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per) { - if (conf_is_ht(&sc->hw->conf)) { - int idx = sc->cur_rate_table->info[rix].dot11rate; + struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix]; - sc->debug.stats.n_rcstats[idx].xretries += xretries; - sc->debug.stats.n_rcstats[idx].retries += retries; - sc->debug.stats.n_rcstats[idx].per = per; - } + stats->xretries += xretries; + stats->retries += retries; + stats->per = per; } -static ssize_t ath_read_file_stat_11n_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - char buf[1024]; - unsigned int len = 0; + char *buf; + unsigned int len = 0, max; int i = 0; + ssize_t retval; - len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", - "Retries", "XRetries", "PER"); - - for (i = 0; i <= 15; i++) { - len += snprintf(buf + len, sizeof(buf) - len, - "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, - sc->debug.stats.n_rcstats[i].success, - sc->debug.stats.n_rcstats[i].retries, - sc->debug.stats.n_rcstats[i].xretries, - sc->debug.stats.n_rcstats[i].per); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} + if (sc->cur_rate_table == NULL) + return 0; -static ssize_t ath_read_file_stat_legacy_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; - int i = 0; + max = 80 + sc->cur_rate_table->rate_cnt * 64; + buf = kmalloc(max + 1, GFP_KERNEL); + if (buf == NULL) + return 0; + buf[max] = 0; - len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); + len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", + "Retries", "XRetries", "PER"); for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { - len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", - sc->cur_rate_table->info[i].ratekbps / 1000, - sc->debug.stats.legacy_rcstats[i].success); + u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; + struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; + + len += snprintf(buf + len, max - len, + "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, + (ratekbps % 1000) / 100, stats->success, + stats->retries, stats->xretries, + stats->per); } - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - - if (sc->cur_rate_table == NULL) - return 0; - - if (conf_is_ht(&sc->hw->conf)) - return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); - else - return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return retval; } static const struct file_operations fops_rcstat = { diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index db845cf..cf9146a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -80,11 +80,7 @@ struct ath_interrupt_stats { u32 dtim; }; -struct ath_legacy_rc_stats { - u32 success; -}; - -struct ath_11n_rc_stats { +struct ath_rc_stats { u32 success; u32 retries; u32 xretries; @@ -93,8 +89,7 @@ struct ath_11n_rc_stats { struct ath_stats { struct ath_interrupt_stats istats; - struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ - struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ + struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; }; struct ath9k_debug { -- cgit v0.10.2 From 2493928e4dbefa1869413cf24b7f605b9b69d0d2 Mon Sep 17 00:00:00 2001 From: Jeff Hansen Date: Wed, 27 May 2009 12:48:29 +0000 Subject: ath9k: Add "debug" file to debugfs This patch adds the debug file to the ath9k debugfs, which lets you modify the debug_mask at runtime, without having to reload the ath9k module. Signed-off-by: Jeff Hansen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 80115ea..a42d631 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -44,6 +44,38 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file) return 0; } +static ssize_t read_file_debug(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[32]; + unsigned int len = 0; + len += snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_debug(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long mask; + char buf[32]; + if (copy_from_user(buf, user_buf, (sizeof(buf) - 1) < count ? + (sizeof(buf) - 1) : count)) + return 0; + buf[sizeof(buf)-1] = 0; + if (strict_strtoul(buf, 0, &mask) == 0) + sc->debug.debug_mask = mask; + return count; +} + +static const struct file_operations fops_debug = { + .read = read_file_debug, + .write = write_file_debug, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -461,6 +493,11 @@ int ath9k_init_debug(struct ath_softc *sc) if (!sc->debug.debugfs_phy) goto err; + sc->debug.debugfs_debug = debugfs_create_file("debug", + S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); + if (!sc->debug.debugfs_debug) + goto err; + sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, sc->debug.debugfs_phy, sc, &fops_dma); if (!sc->debug.debugfs_dma) @@ -498,6 +535,7 @@ void ath9k_exit_debug(struct ath_softc *sc) debugfs_remove(sc->debug.debugfs_rcstat); debugfs_remove(sc->debug.debugfs_interrupt); debugfs_remove(sc->debug.debugfs_dma); + debugfs_remove(sc->debug.debugfs_debug); debugfs_remove(sc->debug.debugfs_phy); } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index cf9146a..edda15b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -95,6 +95,7 @@ struct ath_stats { struct ath9k_debug { int debug_mask; struct dentry *debugfs_phy; + struct dentry *debugfs_debug; struct dentry *debugfs_dma; struct dentry *debugfs_interrupt; struct dentry *debugfs_rcstat; -- cgit v0.10.2 From 2c5b9e511fee1a856ffe6332e15c72a20d2c72f6 Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Wed, 27 May 2009 14:03:09 -0400 Subject: wireless: libertas: fix unaligned accesses Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 14b3d56..c42d3fa 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -5,7 +5,7 @@ #include #include #include - +#include #include #include "host.h" @@ -154,11 +154,11 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_CMD); /* store the non average value */ - priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); - priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); + priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); + priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor); - priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); - priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); + priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); + priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor); priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e5e30b2..601b542 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1129,7 +1129,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, goto done; } - bytesleft = le16_to_cpu(scanresp->bssdescriptsize); + bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); scanrespsize = le16_to_cpu(resp->size); -- cgit v0.10.2 From 86ab04c8c1df51df7d6d3709da546e0163ac856b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 27 May 2009 22:56:05 -0400 Subject: mac80211: handle -EALREADY on cfg80211 op assoc req When the SME requests to associate to an open AP ieee80211_sta_set_extra_ie() can be called with zero IE length. When this happens or when the extra IE has already been set -EALREADY is passed down and the supplicant will complain that the operation is already in progress and it will not let us associate. We correct this by treating -EALREADY from ieee80211_sta_set_extra_ie() as a success just as we do for wext. Cc: Shan.Palanisamy@Atheros.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index cdfdb2e..d2fc18c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1256,7 +1256,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); - if (ret) + if (ret && ret != -EALREADY) return ret; if (req->use_mfp) { -- cgit v0.10.2 From 73ca5203366235f8a43e490767284ba8cfd8c479 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 28 May 2009 10:27:37 -0400 Subject: ath5k: remove conf->beacon_int usage ieee80211_conf->beacon_int was deprecated and removed in a cleanup patch, however it was accidentally added back to ath5k in the change "ath5k: Allow user/driver to set txpower." Remove it once more, fixing the following warning: [13091.968902] WARNING: at drivers/net/wireless/ath/ath5k/base.c:2167 warn_slowpath_null+0x15/0x1a() [13091.968906] Hardware name: MacBook1,1 [13091.968909] Modules linked in: usb_storage fuse i915 drm af_packet acpi_cpufreq binfmt_misc dm_mirror dm_region_hash dm_log dm_multipath dm_mod snd_hda_codec_idt snd_hda_intel snd_hda_codec snd_seq_dummy hid_apple arc4 ecb snd_seq_oss snd_seq_midi_event usbhid snd_seq ath5k mac80211 appletouch snd_seq_device snd_pcm_oss snd_mixer_oss sky2 snd_pcm ath processor cfg80211 snd_timer sg ohci1394 snd uhci_hcd bitrev ieee1394 joydev ehci_hcd crc32 snd_page_alloc button ac thermal battery sr_mod applesmc cdrom evdev input_polldev unix [last unloaded: microcode] [13091.968985] Pid: 2132, comm: phy0 Tainted: G W 2.6.30-rc5-wl #118 [13091.968988] Call Trace: [13091.968994] [] warn_slowpath_fmt+0x77/0xa6 [13091.969003] [] ? _spin_unlock+0x2c/0x41 [13091.969008] [] ? _spin_lock_irqsave+0x15/0x69 [13091.969012] [] ? _spin_unlock_irqrestore+0x34/0x5d [13091.969019] [] ? trace_hardirqs_off+0xb/0xd [13091.969024] [] ? _spin_unlock_irqrestore+0x34/0x5d [13091.969029] [] ? trace_hardirqs_off+0xb/0xd [13091.969034] [] ? _spin_unlock_irqrestore+0x34/0x5d [13091.969039] [] warn_slowpath_null+0x15/0x1a [13091.969054] [] ath5k_beacon_update_timers+0x44/0x27f [ath5k] [13091.969059] [] ? vprintk+0x2dd/0x312 [13091.969063] [] ? release_console_sem+0x1a6/0x1d3 [13091.969076] [] ath5k_reset_tsf+0x1d/0x2c [ath5k] [13091.969095] [] __ieee80211_sta_join_ibss+0x35/0x3aa [mac80211] [13091.969102] [] ? extract_entropy+0x47/0x8a [13091.969121] [] ieee80211_sta_find_ibss+0x2de/0x32f [mac80211] [13091.969126] [] ? mutex_lock_nested+0x28b/0x2a5 [13091.969145] [] ? ieee80211_ibss_notify_scan_completed+0x1c/0x6f [mac80211] [13091.969164] [] ieee80211_ibss_notify_scan_completed+0x57/0x6f [mac80211] [13091.969182] [] ieee80211_scan_completed+0x31a/0x33f [mac80211] [13091.969201] [] ieee80211_scan_work+0xcb/0x18b [mac80211] [13091.969207] [] worker_thread+0x1b1/0x28e [13091.969212] [] ? worker_thread+0x16c/0x28e [13091.969230] [] ? ieee80211_scan_work+0x0/0x18b [mac80211] [13091.969237] [] ? autoremove_wake_function+0x0/0x38 [13091.969242] [] ? worker_thread+0x0/0x28e [13091.969246] [] kthread+0x4a/0x70 [13091.971460] [] ? kthread+0x0/0x70 [13091.971467] [] kernel_thread_helper+0x7/0x10 [13091.971470] ---[ end trace 8defaa5d15c50cef ]--- Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index dd6dc8d..ab2048b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2775,8 +2775,6 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&sc->lock); - sc->bintval = conf->beacon_int; - ret = ath5k_chan_set(sc, conf->channel); if (ret < 0) goto unlock; -- cgit v0.10.2 From 546256fbd06d70a87381020ea8553fb78c9abf43 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 28 May 2009 19:25:28 +0300 Subject: ath9k: Add sanity check for beacon_int in adhoc/mesh case It looks like mac80211 can request the driver to start beaconing with a beacon interval of zero in some cases (at least for mesh point). This does not sound correct and something may need to be fixed in mac80211. However, taken into account the unpleasantness of getting stuck in an infinite busy loop with rtnl_lock held, let's add a quick workaround in the driver to avoid the worst symptom while someone more familiar with the mesh implementation can figure out what should be done with mac80211 as far as beacon interval configuration is concerned. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 0c67ed2..3639a2e 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -674,6 +674,14 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + /* + * It looks like mac80211 may end up using beacon interval of zero in + * some cases (at least for mesh point). Avoid getting into an + * infinite loop by using a bit safer value instead.. + */ + if (intval == 0) + intval = 100; + /* Pull nexttbtt forward to reflect the current TSF */ nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); -- cgit v0.10.2 From c768b58d62d3106f0f670d35d1e7820c14ba769a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 28 May 2009 17:36:04 -0400 Subject: ar9170: add support for 1-stage firmware You can get the stage 1 firmware from here: http://www.kernel.org/pub/linux/kernel/people/mcgrof/firmware/ar9170/ar9170.fw md5sum: 34feec4ec0eae3bb92c7c1ea2dfb4530 sha1sum: 6e5250498b815c2940d97242de31e054ae44e079 Its license: http://www.kernel.org/pub/linux/kernel/people/mcgrof/firmware/ar9170/LICENSE This is a new firmware, tested with WNDA3100. Cc: Peter Grabienski Cc: Stephen Chen Cc: Michael Fortin Cc: Johnny Cheng Cc: Yuan-Gu Wei Cc: Joerg Albert Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index d7c13c0..3c97c09 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -51,6 +51,7 @@ MODULE_AUTHOR("Johannes Berg "); MODULE_AUTHOR("Christian Lamparter "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); +MODULE_FIRMWARE("ar9170.fw"); MODULE_FIRMWARE("ar9170-1.fw"); MODULE_FIRMWARE("ar9170-2.fw"); @@ -504,17 +505,23 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru) { int err = 0; - err = request_firmware(&aru->init_values, "ar9170-1.fw", + err = request_firmware(&aru->firmware, "ar9170.fw", &aru->udev->dev); - if (err) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - return err; + if (!err) { + aru->init_values = NULL; + return 0; } + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found, trying old firmware...\n"); + + err = request_firmware(&aru->init_values, "ar9170-1.fw", + &aru->udev->dev); + err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); if (err) { release_firmware(aru->init_values); - dev_err(&aru->udev->dev, "firmware file not found.\n"); + dev_err(&aru->udev->dev, "file with init values not found.\n"); return err; } @@ -548,6 +555,9 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) { int err; + if (!aru->init_values) + goto upload_fw_start; + /* First, upload initial values to device RAM */ err = ar9170_usb_upload(aru, aru->init_values->data, aru->init_values->size, 0x102800, false); @@ -557,6 +567,8 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) return err; } +upload_fw_start: + /* Then, upload the firmware itself and start it */ return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, 0x200000, true); -- cgit v0.10.2 From bdf6d32f933bf28dfdca325281ee5266c753dc67 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 28 May 2009 17:36:05 -0400 Subject: ar9170: add AVM FRITZ devices This adds: USB 0x057C:0x8401 AVM FRITZ!WLAN USB Stick N USB 0x057C:0x8402 AVM FRITZ!WLAN USB Stick N 2.4 These devices require the 1-stage firmware, if not present we don't continue. Cc: Peter Grabienski Cc: Stephen Chen Cc: Michael Fortin Cc: Johnny Cheng Cc: Yuan-Gu Wei Cc: Joerg Albert Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 3c97c09..71579e4 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -55,6 +55,10 @@ MODULE_FIRMWARE("ar9170.fw"); MODULE_FIRMWARE("ar9170-1.fw"); MODULE_FIRMWARE("ar9170-2.fw"); +enum ar9170_requirements { + AR9170_REQ_FW1_ONLY = 1, +}; + static struct usb_device_id ar9170_usb_ids[] = { /* Atheros 9170 */ { USB_DEVICE(0x0cf3, 0x9170) }, @@ -82,6 +86,10 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x2019, 0x5304) }, /* IO-Data WNGDNUS2 */ { USB_DEVICE(0x04bb, 0x093f) }, + /* AVM FRITZ!WLAN USB Stick N */ + { USB_DEVICE(0x057C, 0x8401) }, + /* AVM FRITZ!WLAN USB Stick N 2.4 */ + { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, /* terminate */ {} @@ -512,6 +520,12 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru) return 0; } + if (aru->req_one_stage_fw) { + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found and is required for this device\n"); + return -EINVAL; + } + dev_err(&aru->udev->dev, "ar9170.fw firmware file " "not found, trying old firmware...\n"); @@ -668,6 +682,15 @@ err_out: return err; } +static bool ar9170_requires_one_stage(const struct usb_device_id *id) +{ + if (!id->driver_info) + return false; + if (id->driver_info == AR9170_REQ_FW1_ONLY) + return true; + return false; +} + static int ar9170_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -688,6 +711,8 @@ static int ar9170_usb_probe(struct usb_interface *intf, aru->intf = intf; ar = &aru->common; + aru->req_one_stage_fw = ar9170_requires_one_stage(id); + usb_set_intfdata(intf, aru); SET_IEEE80211_DEV(ar->hw, &udev->dev); diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index ac42586..69f4bce 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -62,6 +62,8 @@ struct ar9170_usb { struct usb_anchor rx_submitted; struct usb_anchor tx_submitted; + bool req_one_stage_fw; + spinlock_t cmdlock; struct completion cmd_wait; int readlen; -- cgit v0.10.2 From 3b8bcfd5d31ea0fec58681d035544ace707d2536 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 30 May 2009 01:39:53 +0200 Subject: net: introduce pre-up netdev notifier NETDEV_UP is called after the device is set UP, but sometimes it is useful to be able to veto the device UP. Introduce a new NETDEV_PRE_UP notifier that can be used for exactly this. The first use case will be cfg80211 denying interfaces to be set UP if the device is known to be rfkill'ed. Signed-off-by: Johannes Berg Acked-by: David S. Miller Signed-off-by: John W. Linville diff --git a/include/linux/notifier.h b/include/linux/notifier.h index b86fa2f..81bc252 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -198,6 +198,7 @@ static inline int notifier_to_errno(int ret) #define NETDEV_CHANGENAME 0x000A #define NETDEV_FEAT_CHANGE 0x000B #define NETDEV_BONDING_FAILOVER 0x000C +#define NETDEV_PRE_UP 0x000D #define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_RESTART SYS_DOWN diff --git a/net/core/dev.c b/net/core/dev.c index 34b49a6..1f38401 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1048,7 +1048,7 @@ void dev_load(struct net *net, const char *name) int dev_open(struct net_device *dev) { const struct net_device_ops *ops = dev->netdev_ops; - int ret = 0; + int ret; ASSERT_RTNL(); @@ -1065,6 +1065,11 @@ int dev_open(struct net_device *dev) if (!netif_device_present(dev)) return -ENODEV; + ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev); + ret = notifier_to_errno(ret); + if (ret) + return ret; + /* * Call device private open method */ -- cgit v0.10.2 From 729e9c7663190d71fe5e29831634df80f38199c1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 31 May 2009 18:24:34 -0400 Subject: cfg80211: fix for duplicate userspace replies This fixes an incorrect assumption (BUG_ON) made in cfg80211 when handling country IE regulatory requests. The assumption was that we won't try to call_crda() twice for the same event and therefore we will not recieve two replies through nl80211 for the regulatory request. As it turns out it is true we don't call_crda() twice for the same event, however, kobject_uevent_env() *might* send the udev event twice and/or userspace can simply process the udev event twice. We remove the BUG_ON() and simply ignore the duplicate request. For details refer to this thread: http://marc.info/?l=linux-wireless&m=124149987921337&w=2 Cc: stable@kernel.org Reported-by: Maxim Levitsky Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f87ac1d..ea4c299 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2171,7 +2171,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * the country IE rd with what CRDA believes that country should have */ - BUG_ON(!country_ie_regdomain); + /* + * Userspace could have sent two replies with only + * one kernel request. By the second reply we would have + * already processed and consumed the country_ie_regdomain. + */ + if (!country_ie_regdomain) + return -EALREADY; BUG_ON(rd == country_ie_regdomain); /* -- cgit v0.10.2 From 4c4c671aea16d2795f29c7a369518c3c36e15d2a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Jun 2009 14:29:52 +0200 Subject: mac80211_hwsim: remove deprecated radio_enabled This removes the use of the deprecated radio_enabled setting and code associated with that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 574b8bb..e789c6e 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -280,7 +280,6 @@ struct mac80211_hwsim_data { struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; struct ieee80211_channel *channel; - int radio_enabled; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; int started; @@ -418,8 +417,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (data == data2) continue; - if (!data2->started || !data2->radio_enabled || - !hwsim_ps_rx_ok(data2, skb) || + if (!data2->started || !hwsim_ps_rx_ok(data2, skb) || data->channel->center_freq != data2->channel->center_freq || !(data->group & data2->group)) continue; @@ -441,7 +439,6 @@ static bool 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; bool ack; struct ieee80211_tx_info *txi; @@ -453,13 +450,6 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } - if (!data->radio_enabled) { - printk(KERN_DEBUG "%s: dropped TX frame since radio " - "disabled\n", wiphy_name(hw->wiphy)); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - ack = mac80211_hwsim_tx_frame(hw, skb); txi = IEEE80211_SKB_CB(skb); @@ -546,7 +536,7 @@ static void mac80211_hwsim_beacon(unsigned long arg) struct ieee80211_hw *hw = (struct ieee80211_hw *) arg; struct mac80211_hwsim_data *data = hw->priv; - if (!data->started || !data->radio_enabled) + if (!data->started) return; ieee80211_iterate_active_interfaces_atomic( @@ -562,15 +552,14 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; - printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d idle=%d ps=%d)\n", + printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", wiphy_name(hw->wiphy), __func__, - conf->channel->center_freq, conf->radio_enabled, + conf->channel->center_freq, !!(conf->flags & IEEE80211_CONF_IDLE), !!(conf->flags & IEEE80211_CONF_PS)); data->channel = conf->channel; - data->radio_enabled = conf->radio_enabled; - if (!data->started || !data->radio_enabled || !data->beacon_int) + if (!data->started || !data->beacon_int) del_timer(&data->beacon_timer); else mod_timer(&data->beacon_timer, jiffies + data->beacon_int); @@ -787,8 +776,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) pspoll->aid = cpu_to_le16(0xc000 | vp->aid); memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); memcpy(pspoll->ta, mac, ETH_ALEN); - if (data->radio_enabled && - !mac80211_hwsim_tx_frame(data->hw, skb)) + if (!mac80211_hwsim_tx_frame(data->hw, skb)) printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); dev_kfree_skb(skb); } @@ -819,8 +807,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, memcpy(hdr->addr1, vp->bssid, ETH_ALEN); memcpy(hdr->addr2, mac, ETH_ALEN); memcpy(hdr->addr3, vp->bssid, ETH_ALEN); - if (data->radio_enabled && - !mac80211_hwsim_tx_frame(data->hw, skb)) + if (!mac80211_hwsim_tx_frame(data->hw, skb)) printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); dev_kfree_skb(skb); } -- cgit v0.10.2 From f46f0dc3f1e7bda2621617d5a379f8983ad1d5f8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 1 Jun 2009 21:41:31 +0200 Subject: ar9170: fix beacon plcp settings This patch fixes a simple copy & paste error that affected beacon transmission in 802.11a mode. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 43aeb69..72c7b5d 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -398,10 +398,10 @@ int ar9170_update_beacon(struct ar9170 *ar) /* XXX: use skb->cb info */ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); + ((skb->len + 4) << (3 + 16)) + 0x0400); else ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); + ((skb->len + 4) << 16) + 0x001b); ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); -- cgit v0.10.2 From b9ad462e34b6eb8380c8534684326bb395b29c9f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 1 Jun 2009 21:41:36 +0200 Subject: ar9170: update hardware definitions This patch only contains a few uncritical updates for the hardware definition header. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 3293e0f..3c8004f 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -207,7 +207,8 @@ enum ar9170_cmd { #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) -#define AR9170_MAC_REG_AMPDU_SET (AR9170_MAC_REG_BASE + 0xba0) +#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) +#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) @@ -376,7 +377,6 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) #define AR9170_RX_ERROR_FATAL 0x80 struct ar9170_cmd_tx_status { - __le16 unkn; u8 dst[ETH_ALEN]; __le32 rate; __le16 status; @@ -394,6 +394,7 @@ struct ar9170_cmd_ba_failed_count { struct ar9170_cmd_response { u8 flag; u8 type; + __le16 padding; union { struct ar9170_cmd_tx_status tx_status; diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 72c7b5d..706262f 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -84,7 +84,7 @@ static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val); + ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); ar9170_regwrite_finish(); return ar9170_regwrite_result(); -- cgit v0.10.2 From d7433390e49152101c1b31c08e38caf2a05a1169 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 1 Jun 2009 21:41:50 +0200 Subject: ar9170: 40mhz fixes This patch replace a few constant magics which may affected the device when operating in a 40MHz channel. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 6ce2075..df86f70 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -401,7 +401,7 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) int i, err; u32 val; bool is_2ghz = band == IEEE80211_BAND_2GHZ; - bool is_40mhz = false; /* XXX: for now */ + bool is_40mhz = conf_is_ht40(&ar->hw->conf); ar9170_regwrite_begin(ar); @@ -1200,7 +1200,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, return -ENOSYS; } - if (0 /* 2 streams capable */) + if (ar->eeprom.tx_mask != 1) tmp |= 0x100; err = ar9170_write_reg(ar, 0x1c5804, tmp); @@ -1214,7 +1214,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, freqpar = ar9170_get_hw_dyn_params(channel, bw); vals[0] = cpu_to_le32(channel->center_freq * 1000); - vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1); + vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); vals[2] = cpu_to_le32(offs << 2 | 1); vals[3] = cpu_to_le32(freqpar->coeff_exp); vals[4] = cpu_to_le32(freqpar->coeff_man); -- cgit v0.10.2 From 29ceff5d58afbb2c98bb748057788f02b8db20e5 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 1 Jun 2009 21:42:01 +0200 Subject: ar9170: introduce functions for MAC programming This patch introduces 3 new function which are used to update the MAC state, whenever needed... e.g: after a band switch. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 17bd3ea..77dc647 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -215,6 +215,9 @@ int ar9170_update_multicast(struct ar9170 *ar); int ar9170_update_frame_filter(struct ar9170 *ar); int ar9170_set_operating_mode(struct ar9170 *ar); int ar9170_set_beacon_timers(struct ar9170 *ar); +int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); +int ar9170_set_slot_time(struct ar9170 *ar); +int ar9170_set_basic_rates(struct ar9170 *ar); int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); int ar9170_update_beacon(struct ar9170 *ar); void ar9170_new_beacon(struct work_struct *work); diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 706262f..d9f1f46 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -38,6 +38,55 @@ #include "ar9170.h" #include "cmd.h" +int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) +{ + u32 val; + + if (conf_is_ht40(&ar->hw->conf)) + val = 0x010a; + else { + if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) + val = 0x105; + else + val = 0x104; + } + + return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); +} + +int ar9170_set_slot_time(struct ar9170 *ar) +{ + u32 slottime = 20; + + if (!ar->vif) + return 0; + + if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || + ar->vif->bss_conf.use_short_slot) + slottime = 9; + + return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); +} + +int ar9170_set_basic_rates(struct ar9170 *ar) +{ + u8 cck, ofdm; + + if (!ar->vif) + return 0; + + ofdm = ar->vif->bss_conf.basic_rates >> 4; + + /* FIXME: is still necessary? */ + if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) + cck = 0; + else + cck = ar->vif->bss_conf.basic_rates & 0xf; + + return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, + ofdm << 8 | cck); +} + int ar9170_set_qos(struct ar9170 *ar) { ar9170_regwrite_begin(ar); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 99df9dd..c54c42e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1344,15 +1344,21 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + + /* adjust slot time for 5 GHz */ + err = ar9170_set_slot_time(ar); + if (err) + goto out; + + err = ar9170_set_dyn_sifs_ack(ar); + if (err) + goto out; + err = ar9170_set_channel(ar, hw->conf.channel, AR9170_RFI_NONE, nl80211_to_ar9170(hw->conf.channel_type)); if (err) goto out; - /* adjust slot time for 5 GHz */ - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) - err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, - 9 << 10); } out: @@ -1464,15 +1470,19 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) { memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN); err = ar9170_set_operating_mode(ar); + if (err) + goto out; } if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { err = ar9170_update_beacon(ar); - if (!err) - ar9170_set_beacon_timers(ar); - } + if (err) + goto out; - ar9170_regwrite_begin(ar); + err = ar9170_set_beacon_timers(ar); + if (err) + goto out; + } if (changed & BSS_CHANGED_ASSOC) { ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; @@ -1483,8 +1493,11 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, #endif /* CONFIG_AR9170_LEDS */ } - if (changed & BSS_CHANGED_BEACON_INT) + if (changed & BSS_CHANGED_BEACON_INT) { err = ar9170_set_beacon_timers(ar); + if (err) + goto out; + } if (changed & BSS_CHANGED_HT) { /* TODO */ @@ -1492,31 +1505,18 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_SLOT) { - u32 slottime = 20; - - if (bss_conf->use_short_slot) - slottime = 9; - - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); + err = ar9170_set_slot_time(ar); + if (err) + goto out; } if (changed & BSS_CHANGED_BASIC_RATES) { - u32 cck, ofdm; - - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { - ofdm = bss_conf->basic_rates; - cck = 0; - } else { - /* four cck rates */ - cck = bss_conf->basic_rates & 0xf; - ofdm = bss_conf->basic_rates >> 4; - } - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, - ofdm << 8 | cck); + err = ar9170_set_basic_rates(ar); + if (err) + goto out; } - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); +out: mutex_unlock(&ar->mutex); } -- cgit v0.10.2 From 864cc02e7c0ed9a83be0c35c05df1941abcc792d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 23 May 2009 20:28:21 +0200 Subject: ar9170: use bitop macros for tx filter flags This patch fixes a bug in configure_filter's (sub-)routines. We never really cleared the flags once we updated the hardware state, so we wasted our resources by applying already active settings. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 77dc647..1247dcb9 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -140,7 +140,7 @@ struct ar9170 { struct work_struct filter_config_work; u64 cur_mc_hash, want_mc_hash; u32 cur_filter, want_filter; - unsigned int filter_changed; + unsigned long filter_changed; unsigned int filter_state; bool sniffer_enabled; @@ -195,7 +195,7 @@ struct ar9170_sta_info { #define IS_STARTED(a) (a->state >= AR9170_STARTED) #define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) -#define AR9170_FILTER_CHANGED_PROMISC BIT(0) +#define AR9170_FILTER_CHANGED_MODE BIT(0) #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) #define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c54c42e..201989a 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -957,6 +957,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw) mutex_lock(&ar->mutex); + ar->filter_changed = 0; + /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) @@ -1376,20 +1378,26 @@ static void ar9170_set_filters(struct work_struct *work) return ; mutex_lock(&ar->mutex); - if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { + if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE, + &ar->filter_changed)) { err = ar9170_set_operating_mode(ar); if (err) goto unlock; } - if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { + if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST, + &ar->filter_changed)) { err = ar9170_update_multicast(ar); if (err) goto unlock; } - if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) + if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, + &ar->filter_changed)) { err = ar9170_update_frame_filter(ar); + if (err) + goto unlock; + } unlock: mutex_unlock(&ar->mutex); @@ -1419,7 +1427,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, int i; /* always get broadcast frames */ - mchash = 1ULL << (0xff>>2); + mchash = 1ULL << (0xff >> 2); for (i = 0; i < mc_count; i++) { if (WARN_ON(!mclist)) @@ -1429,7 +1437,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, } ar->want_mc_hash = mchash; } - ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; + set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); } if (changed_flags & FIF_CONTROL) { @@ -1445,12 +1453,14 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, else ar->want_filter = ar->cur_filter & ~filter; - ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; + set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, + &ar->filter_changed); } if (changed_flags & FIF_PROMISC_IN_BSS) { ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; + set_bit(AR9170_FILTER_CHANGED_MODE, + &ar->filter_changed); } if (likely(IS_STARTED(ar))) -- cgit v0.10.2 From 95cf8769bba6ea595994f786ea63f7e2948133de Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 23 May 2009 20:28:38 +0200 Subject: ar9170: kill duplicated HT feature flag This patch removes a redundant flag. .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ > IEEE80211_HT_CAP_SM_PS | \ < [...] \ > IEEE80211_HT_CAP_SM_PS, \ < .ampdu_factor = 3, \ Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 201989a..1657e89 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -146,7 +146,6 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { { \ .ht_supported = true, \ .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ - IEEE80211_HT_CAP_SM_PS | \ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_40 | \ IEEE80211_HT_CAP_DSSSCCK40 | \ -- cgit v0.10.2 From 2431fe9a4b43ccf03589fa661662da6bfbd97282 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 25 May 2009 21:51:19 +0200 Subject: ar9170: fix LED power state handling This patch fixes a minor visual bug in the led code, which left the LED in the wrong power state when it was toggled in a _unexpected_ way (e.g: enabling the LED twice). Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 1247dcb9..396b240 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -91,6 +91,7 @@ struct ar9170_led { struct led_classdev l; char name[32]; unsigned int toggled; + bool last_state; bool registered; }; diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c index 341cead..3c8a572 100644 --- a/drivers/net/wireless/ath/ar9170/led.c +++ b/drivers/net/wireless/ath/ar9170/led.c @@ -101,9 +101,12 @@ static void ar9170_led_brightness_set(struct led_classdev *led, struct ar9170_led *arl = container_of(led, struct ar9170_led, l); struct ar9170 *ar = arl->ar; - arl->toggled++; + if (arl->last_state != !!brightness) { + arl->toggled++; + arl->last_state = !!brightness; + } - if (likely(IS_ACCEPTING_CMD(ar) && brightness)) + if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); } -- cgit v0.10.2 From b55d6bcf9b7082ae613e5d532608abcd409164ca Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 23 May 2009 20:31:21 +0200 Subject: ar9170: fix lockdep warning on hibernate This patch takes care of Johannes' deadlock report by moving the mutex_lock right after cancel_work_sync in ar9170_op_stop. Besides, the janitor does not need to hold the mutex anymore, so this extra lines can be removed as well. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 1657e89..63528f1 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -343,7 +343,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work) if (unlikely(!IS_STARTED(ar))) return ; - mutex_lock(&ar->mutex); /* recycle the garbage back to mac80211... one by one. */ while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { #ifdef AR9170_QUEUE_DEBUG @@ -369,8 +368,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work) if (skb_queue_len(&ar->global_tx_status_waste) > 0) queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, msecs_to_jiffies(100)); - - mutex_unlock(&ar->mutex); } static void ar9170_handle_command_response(struct ar9170 *ar, @@ -1013,10 +1010,10 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) flush_workqueue(ar->hw->workqueue); - mutex_lock(&ar->mutex); cancel_delayed_work_sync(&ar->tx_status_janitor); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); + mutex_lock(&ar->mutex); skb_queue_purge(&ar->global_tx_status_waste); skb_queue_purge(&ar->global_tx_status); -- cgit v0.10.2 From 66d008139c61d610f3ade9b46ad610e2cd277fb9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 28 May 2009 17:04:27 +0200 Subject: ar9170usb: more minor fixes This patch contains a few more mostly random fixes for the USB front-end. 1. handle irq command response, instead of printing it to the console. 2. remove fixed FIXME. (real fix: "ar9170usb: reset device on resume". ) 3. some more one-liner. - get rid of a useless "return;" - add a few branch prediction hints in hot-paths etc. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 396b240..4c4b08f 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -207,6 +207,7 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); void ar9170_unregister(struct ar9170 *ar); void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, bool update_statistics, u16 tx_status); +void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); /* MAC */ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 63528f1..b889fda 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -370,8 +370,7 @@ static void ar9170_tx_status_janitor(struct work_struct *work) msecs_to_jiffies(100)); } -static void ar9170_handle_command_response(struct ar9170 *ar, - void *buf, u32 len) +void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) { struct ar9170_cmd_response *cmd = (void *) buf; diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 71579e4..f752698 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -102,7 +102,7 @@ static void ar9170_usb_tx_urb_complete_free(struct urb *urb) struct ar9170_usb *aru = (struct ar9170_usb *) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - if (!aru) { + if (unlikely(!aru)) { dev_kfree_skb_irq(skb); return ; } @@ -135,8 +135,8 @@ static void ar9170_usb_irq_completed(struct urb *urb) goto resubmit; } - print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET, - urb->transfer_buffer, urb->actual_length); + ar9170_handle_command_response(&aru->common, urb->transfer_buffer, + urb->actual_length); resubmit: usb_anchor_urb(urb, &aru->rx_submitted); @@ -186,16 +186,15 @@ resubmit: usb_anchor_urb(urb, &aru->rx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { + if (unlikely(err)) { usb_unanchor_urb(urb); - dev_kfree_skb_irq(skb); + goto free; } return ; free: dev_kfree_skb_irq(skb); - return; } static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, @@ -346,7 +345,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, usb_anchor_urb(urb, &aru->tx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { + if (unlikely(err)) { usb_unanchor_urb(urb); usb_free_urb(urb); goto err_unbuf; @@ -427,7 +426,7 @@ static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) unsigned long flags; u32 in, out; - if (!buffer) + if (unlikely(!buffer)) return ; in = le32_to_cpup((__le32 *)buffer); @@ -728,7 +727,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, #ifdef CONFIG_PM udev->reset_resume = 1; -#endif +#endif /* CONFIG_PM */ err = ar9170_usb_reset(aru); if (err) goto err_freehw; @@ -813,11 +812,6 @@ static int ar9170_resume(struct usb_interface *intf) usb_unpoison_anchored_urbs(&aru->rx_submitted); usb_unpoison_anchored_urbs(&aru->tx_submitted); - /* - * FIXME: firmware upload will fail on resume. - * but this is better than a hang! - */ - err = ar9170_usb_init_device(aru); if (err) goto err_unrx; -- cgit v0.10.2 From 6d7db193f2097d2f12fdc6b2300439a91a3196be Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 1 Jun 2009 22:49:25 +0200 Subject: ar9170: cancel led worker properly on exit "[PATCH 3/4 v2] ar9170: fix LED power state handling" revealed a bug which can cause a ugly crash. The delayed worker is canceled before the LED class functions are unregistered... So, if something manages to update the LEDs while unregister routine is running the timer could fire _after_ the module has been unloaded. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c index 3c8a572..63fda6c 100644 --- a/drivers/net/wireless/ath/ar9170/led.c +++ b/drivers/net/wireless/ath/ar9170/led.c @@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work) mutex_lock(&ar->mutex); for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].toggled) { + if (ar->leds[i].registered && ar->leds[i].toggled) { led_val |= 1 << i; tmp = 70 + 200 / (ar->leds[i].toggled); @@ -101,6 +101,9 @@ static void ar9170_led_brightness_set(struct led_classdev *led, struct ar9170_led *arl = container_of(led, struct ar9170_led, l); struct ar9170 *ar = arl->ar; + if (unlikely(!arl->registered)) + return ; + if (arl->last_state != !!brightness) { arl->toggled++; arl->last_state = !!brightness; @@ -139,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar) { int i; - cancel_delayed_work_sync(&ar->led_work); - for (i = 0; i < AR9170_NUM_LEDS; i++) if (ar->leds[i].registered) { led_classdev_unregister(&ar->leds[i].l); ar->leds[i].registered = false; + ar->leds[i].toggled = 0; } + + cancel_delayed_work_sync(&ar->led_work); } int ar9170_register_leds(struct ar9170 *ar) -- cgit v0.10.2 From 939cab83ea592fcf4d854563d6c71d813a691872 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 2 Jun 2009 15:52:20 +0800 Subject: iwmc3200wifi: shrink calibration lmac name iwmc3200wifi: trim down calibration firmware name The patch trims down iwmc3200wifi calibration firmware name from iwmc3200wifi-lmac-calib-sdio.bin to iwmc3200wifi-calib-sdio.bin. We can shorten the firmware name because all calibration is done by LMAC. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index edc0a00..b54da67 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -395,7 +395,7 @@ static struct iwm_if_ops if_sdio_ops = { .debugfs_init = if_sdio_debugfs_init, .debugfs_exit = if_sdio_debugfs_exit, .umac_name = "iwmc3200wifi-umac-sdio.bin", - .calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin", + .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", .lmac_name = "iwmc3200wifi-lmac-sdio.bin", }; -- cgit v0.10.2 From 328d84fb3614d006254c990a6224ce437147a5ac Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 27 May 2009 10:12:51 +0200 Subject: wireless/p54: prepare for FIRMWARE_NAME_MAX removal We're going to remove the FIRMWARE_NAME_MAX definition in order to avoid any firmware name length restriction. This patch gets rid of the statically allocated p54usb firmware string, and replaces them with const char pointers. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index f40c0f4..0e877a1 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -84,8 +84,8 @@ MODULE_DEVICE_TABLE(usb, p54u_table); static const struct { u32 intf; enum p54u_hw_type type; - char fw[FIRMWARE_NAME_MAX]; - char fw_legacy[FIRMWARE_NAME_MAX]; + const char *fw; + const char *fw_legacy; char hw[20]; } p54u_fwlist[__NUM_P54U_HWTYPES] = { { -- cgit v0.10.2 From 6bc61f4d8e2fa3d54017c29b58603e8771158a25 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 1 Jun 2009 18:04:36 -0700 Subject: libertas: improve function init/shutdown handling for SD8688 This patch is to incorporate Dan Williams' comments for commit: "libertas: implement function init/shutdown commands for SD8688" 1. remove fn_init_required and fn_shutdown_required variables from lbs_private structure. If required, __lbs_cmd() will be called directly to send function init/shutdown command for SD8688 in if_sdio_probe() or if_sdio_remove() callback. 2. add global variable "user_rmmod" to distinguish between the module removal case and the card removal case. This flag will be checked in if_sdio_remove() against SD8688 card to determine whether or not the function shutdown command needs to be sent. 3. remove "card" from if_sdio_model structure as it cannot store card pointers for multiple cards. Besides, it's no longer needed to store the "card" pointer with changes #1 & #2 above. Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 9e11f90..f9ec69e 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -321,8 +321,6 @@ struct lbs_private { u32 monitormode; u8 fw_ready; - u8 fn_init_required; - u8 fn_shutdown_required; }; extern struct cmd_confirm_sleep confirm_sleep; diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index a7e3fc1..8cdb88c 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -39,8 +39,24 @@ #include "decl.h" #include "defs.h" #include "dev.h" +#include "cmd.h" #include "if_sdio.h" +/* The if_sdio_remove() callback function is called when + * user removes this module from kernel space or ejects + * the card from the slot. The driver handles these 2 cases + * differently for SD8688 combo chip. + * If the user is removing the module, the FUNC_SHUTDOWN + * command for SD8688 is sent to the firmware. + * If the card is removed, there is no need to send this command. + * + * The variable 'user_rmmod' is used to distinguish these two + * scenarios. This flag is initialized as FALSE in case the card + * is removed, and will be set to TRUE for module removal when + * module_exit function is called. + */ +static u8 user_rmmod; + static char *lbs_helper_name = NULL; module_param_named(helper_name, lbs_helper_name, charp, 0644); @@ -61,7 +77,6 @@ struct if_sdio_model { int model; const char *helper; const char *firmware; - struct if_sdio_card *card; }; static struct if_sdio_model if_sdio_models[] = { @@ -70,21 +85,18 @@ static struct if_sdio_model if_sdio_models[] = { .model = IF_SDIO_MODEL_8385, .helper = "sd8385_helper.bin", .firmware = "sd8385.bin", - .card = NULL, }, { /* 8686 */ .model = IF_SDIO_MODEL_8686, .helper = "sd8686_helper.bin", .firmware = "sd8686.bin", - .card = NULL, }, { /* 8688 */ .model = IF_SDIO_MODEL_8688, .helper = "sd8688_helper.bin", .firmware = "sd8688.bin", - .card = NULL, }, }; @@ -927,8 +939,6 @@ static int if_sdio_probe(struct sdio_func *func, goto free; } - if_sdio_models[i].card = card; - card->helper = if_sdio_models[i].helper; card->firmware = if_sdio_models[i].firmware; @@ -1014,8 +1024,16 @@ static int if_sdio_probe(struct sdio_func *func, /* * FUNC_INIT is required for SD8688 WLAN/BT multiple functions */ - priv->fn_init_required = - (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; + if (card->model == IF_SDIO_MODEL_8688) { + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send function INIT command\n"); + if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), + lbs_cmd_copyback, (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_INIT cmd failed\n"); + } ret = lbs_start_card(priv); if (ret) @@ -1057,30 +1075,39 @@ static void if_sdio_remove(struct sdio_func *func) { struct if_sdio_card *card; struct if_sdio_packet *packet; - int ret; lbs_deb_enter(LBS_DEB_SDIO); card = sdio_get_drvdata(func); - lbs_stop_card(card->priv); + if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) { + /* + * FUNC_SHUTDOWN is required for SD8688 WLAN/BT + * multiple functions + */ + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send function SHUTDOWN command\n"); + if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN, + &cmd, sizeof(cmd), lbs_cmd_copyback, + (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); + } card->priv->surpriseremoved = 1; lbs_deb_sdio("call remove card\n"); + lbs_stop_card(card->priv); lbs_remove_card(card->priv); flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); sdio_claim_host(func); - - /* Disable interrupts */ - sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret); - sdio_release_irq(func); sdio_disable_func(func); - sdio_release_host(func); while (card->packets) { @@ -1116,6 +1143,9 @@ static int __init if_sdio_init_module(void) ret = sdio_register_driver(&if_sdio_driver); + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; @@ -1123,22 +1153,10 @@ static int __init if_sdio_init_module(void) static void __exit if_sdio_exit_module(void) { - int i; - struct if_sdio_card *card; - lbs_deb_enter(LBS_DEB_SDIO); - for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) { - card = if_sdio_models[i].card; - - /* - * FUNC_SHUTDOWN is required for SD8688 WLAN/BT - * multiple functions - */ - if (card && card->priv) - card->priv->fn_shutdown_required = - (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; - } + /* Set the flag as user is removing this module. */ + user_rmmod = 1; sdio_unregister_driver(&if_sdio_driver); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a58a123..89575e4 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1002,17 +1002,9 @@ static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; s16 curlevel = 0, minlevel = 0, maxlevel = 0; - struct cmd_header cmd; lbs_deb_enter(LBS_DEB_FW); - if (priv->fn_init_required) { - memset(&cmd, 0, sizeof(cmd)); - if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), - lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_INIT command failed\n"); - } - /* Read MAC address from firmware */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); @@ -1200,9 +1192,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->mesh_open = 0; priv->infra_open = 0; - priv->fn_init_required = 0; - priv->fn_shutdown_required = 0; - /* Setup the OS Interface to our functions */ dev->netdev_ops = &lbs_netdev_ops; dev->watchdog_timeo = 5 * HZ; @@ -1384,20 +1373,11 @@ void lbs_stop_card(struct lbs_private *priv) struct net_device *dev; struct cmd_ctrl_node *cmdnode; unsigned long flags; - struct cmd_header cmd; lbs_deb_enter(LBS_DEB_MAIN); if (!priv) goto out; - - if (priv->fn_shutdown_required) { - memset(&cmd, 0, sizeof(cmd)); - if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd), - lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n"); - } - dev = priv->dev; netif_stop_queue(dev); -- cgit v0.10.2 From 0f6399c4c525b518644a9b09f8d6fb125a418c4d Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 2 Jun 2009 00:05:04 -0400 Subject: nl80211: use GFP_ATOMIC for michael mic failure message nl80211_michael_mic_failure can be called in atomic context but does a GFP_KERNEL allocation. Fixes the error below: [ 126.793225] BUG: sleeping function called from invalid context at mm/slab.c:3055 [ 126.793234] in_atomic(): 1, irqs_disabled(): 0, pid: 0, name: swapper [ 126.793241] 2 locks held by swapper/0: [ 126.793246] #0: (&sc->rxbuflock){+.-.+.}, at: [] ath5k_tasklet_rx+0x34/0x55e [ath5k] [ 126.793294] #1: (rcu_read_lock){.+.+.+}, at: [] __ieee80211_rx+0x7e/0x563 [mac80211] [ 126.793342] Pid: 0, comm: swapper Not tainted 2.6.30-rc7-wl #124 [ 126.793347] Call Trace: [ 126.793361] [] ? __debug_show_held_locks+0x1e/0x20 [ 126.793380] [] __might_sleep+0x100/0x107 [ 126.793386] [] kmem_cache_alloc+0x35/0x170 [ 126.793393] [] ? __alloc_skb+0x2e/0x117 [ 126.793397] [] ? mark_held_locks+0x43/0x5b [ 126.793402] [] __alloc_skb+0x2e/0x117 [ 126.793419] [] nl80211_michael_mic_failure+0x2a/0x1fa [cfg80211] [ 126.793425] [] ? trace_hardirqs_on_caller+0xf6/0x130 [ 126.793430] [] ? trace_hardirqs_on+0xb/0xd [ 126.793444] [] cfg80211_michael_mic_failure+0x30/0x38 [cfg80211] [ 126.793463] [] mac80211_ev_michael_mic_failure+0xfd/0x108 [mac80211] [ 126.793480] [] ieee80211_rx_h_michael_mic_verify+0xd4/0x117 [mac80211] [ 126.793499] [] ieee80211_invoke_rx_handlers+0xdde/0x1963 [mac80211] [ 126.793505] [] ? sched_clock+0x3f/0x64 [ 126.793511] [] ? sched_clock+0x3f/0x64 [ 126.793516] [] ? trace_hardirqs_off+0xb/0xd [ 126.793521] [] ? sched_clock+0x3f/0x64 [ 126.793526] [] ? __lock_acquire+0x62c/0x1271 [ 126.793545] [] __ieee80211_rx_handle_packet+0x543/0x564 [mac80211] [ 126.793564] [] __ieee80211_rx+0x4e2/0x563 [mac80211] [ 126.793577] [] ath5k_tasklet_rx+0x4e4/0x55e [ath5k] [ 126.793583] [] ? restore_nocheck_notrace+0x0/0xe [ 126.793589] [] tasklet_action+0x92/0xe5 [ 126.793594] [] __do_softirq+0xb1/0x182 [ 126.793599] [] do_softirq+0x30/0x48 [ 126.793603] [] irq_exit+0x3d/0x74 [ 126.793609] [] do_IRQ+0x76/0x8c [ 126.793613] [] common_interrupt+0x2e/0x34 [ 126.793618] [] ? timer_list_show+0x277/0x939 [ 126.793630] [] ? acpi_idle_enter_bm+0x266/0x291 [processor] [ 126.793636] [] cpuidle_idle_call+0x6a/0x9c [ 126.793640] [] cpu_idle+0x53/0x87 [ 126.793645] [] rest_init+0x6c/0x6e [ 126.793651] [] start_kernel+0x286/0x28b [ 126.793656] [] __init_begin+0x37/0x3c Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fd392ff..2416856 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3871,7 +3871,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!msg) return; @@ -3895,7 +3895,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); return; nla_put_failure: -- cgit v0.10.2 From 19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jun 2009 13:01:37 +0200 Subject: rfkill: rewrite This patch completely rewrites the rfkill core to address the following deficiencies: * all rfkill drivers need to implement polling where necessary rather than having one central implementation * updating the rfkill state cannot be done from arbitrary contexts, forcing drivers to use schedule_work and requiring lots of code * rfkill drivers need to keep track of soft/hard blocked internally -- the core should do this * the rfkill API has many unexpected quirks, for example being asymmetric wrt. alloc/free and register/unregister * rfkill can call back into a driver from within a function the driver called -- this is prone to deadlocks and generally should be avoided * rfkill-input pointlessly is a separate module * drivers need to #ifdef rfkill functions (unless they want to depend on or select RFKILL) -- rfkill should provide inlines that do nothing if it isn't compiled in * the rfkill structure is not opaque -- drivers need to initialise it correctly (lots of sanity checking code required) -- instead force drivers to pass the right variables to rfkill_alloc() * the documentation is hard to read because it always assumes the reader is completely clueless and contains way TOO MANY CAPS * the rfkill code needlessly uses a lot of locks and atomic operations in locked sections * fix LED trigger to actually change the LED when the radio state changes -- this wasn't done before Tested-by: Alan Jenkins Signed-off-by: Henrique de Moraes Holschuh [thinkpad] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 40c3a3f..de941e3 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -1,571 +1,130 @@ -rfkill - RF switch subsystem support -==================================== +rfkill - RF kill switch support +=============================== -1 Introduction -2 Implementation details -3 Kernel driver guidelines -3.1 wireless device drivers -3.2 platform/switch drivers -3.3 input device drivers -4 Kernel API -5 Userspace support +1. Introduction +2. Implementation details +3. Kernel driver guidelines +4. Kernel API +5. Userspace support -1. Introduction: +1. Introduction -The rfkill switch subsystem exists to add a generic interface to circuitry that -can enable or disable the signal output of a wireless *transmitter* of any -type. By far, the most common use is to disable radio-frequency transmitters. +The rfkill subsystem provides a generic interface to disabling any radio +transmitter in the system. When a transmitter is blocked, it shall not +radiate any power. -Note that disabling the signal output means that the the transmitter is to be -made to not emit any energy when "blocked". rfkill is not about blocking data -transmissions, it is about blocking energy emission. +The subsystem also provides the ability to react on button presses and +disable all transmitters of a certain type (or all). This is intended for +situations where transmitters need to be turned off, for example on +aircraft. -The rfkill subsystem offers support for keys and switches often found on -laptops to enable wireless devices like WiFi and Bluetooth, so that these keys -and switches actually perform an action in all wireless devices of a given type -attached to the system. -The buttons to enable and disable the wireless transmitters are important in -situations where the user is for example using his laptop on a location where -radio-frequency transmitters _must_ be disabled (e.g. airplanes). -Because of this requirement, userspace support for the keys should not be made -mandatory. Because userspace might want to perform some additional smarter -tasks when the key is pressed, rfkill provides userspace the possibility to -take over the task to handle the key events. - -=============================================================================== -2: Implementation details +2. Implementation details The rfkill subsystem is composed of various components: the rfkill class, the rfkill-input module (an input layer handler), and some specific input layer events. -The rfkill class provides kernel drivers with an interface that allows them to -know when they should enable or disable a wireless network device transmitter. -This is enabled by the CONFIG_RFKILL Kconfig option. - -The rfkill class support makes sure userspace will be notified of all state -changes on rfkill devices through uevents. It provides a notification chain -for interested parties in the kernel to also get notified of rfkill state -changes in other drivers. It creates several sysfs entries which can be used -by userspace. See section "Userspace support". - -The rfkill-input module provides the kernel with the ability to implement a -basic response when the user presses a key or button (or toggles a switch) -related to rfkill functionality. It is an in-kernel implementation of default -policy of reacting to rfkill-related input events and neither mandatory nor -required for wireless drivers to operate. It is enabled by the -CONFIG_RFKILL_INPUT Kconfig option. - -rfkill-input is a rfkill-related events input layer handler. This handler will -listen to all rfkill key events and will change the rfkill state of the -wireless devices accordingly. With this option enabled userspace could either -do nothing or simply perform monitoring tasks. - -The rfkill-input module also provides EPO (emergency power-off) functionality -for all wireless transmitters. This function cannot be overridden, and it is -always active. rfkill EPO is related to *_RFKILL_ALL input layer events. - - -Important terms for the rfkill subsystem: - -In order to avoid confusion, we avoid the term "switch" in rfkill when it is -referring to an electronic control circuit that enables or disables a -transmitter. We reserve it for the physical device a human manipulates -(which is an input device, by the way): - -rfkill switch: - - A physical device a human manipulates. Its state can be perceived by - the kernel either directly (through a GPIO pin, ACPI GPE) or by its - effect on a rfkill line of a wireless device. - -rfkill controller: - - A hardware circuit that controls the state of a rfkill line, which a - kernel driver can interact with *to modify* that state (i.e. it has - either write-only or read/write access). - -rfkill line: - - An input channel (hardware or software) of a wireless device, which - causes a wireless transmitter to stop emitting energy (BLOCK) when it - is active. Point of view is extremely important here: rfkill lines are - always seen from the PoV of a wireless device (and its driver). - -soft rfkill line/software rfkill line: - - A rfkill line the wireless device driver can directly change the state - of. Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED. - -hard rfkill line/hardware rfkill line: - - A rfkill line that works fully in hardware or firmware, and that cannot - be overridden by the kernel driver. The hardware device or the - firmware just exports its status to the driver, but it is read-only. - Related to rfkill_state RFKILL_STATE_HARD_BLOCKED. - -The enum rfkill_state describes the rfkill state of a transmitter: - -When a rfkill line or rfkill controller is in the RFKILL_STATE_UNBLOCKED state, -the wireless transmitter (radio TX circuit for example) is *enabled*. When the -it is in the RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the -wireless transmitter is to be *blocked* from operating. - -RFKILL_STATE_SOFT_BLOCKED indicates that a call to toggle_radio() can change -that state. RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio() -will not be able to change the state and will return with a suitable error if -attempts are made to set the state to RFKILL_STATE_UNBLOCKED. - -RFKILL_STATE_HARD_BLOCKED is used by drivers to signal that the device is -locked in the BLOCKED state by a hardwire rfkill line (typically an input pin -that, when active, forces the transmitter to be disabled) which the driver -CANNOT override. - -Full rfkill functionality requires two different subsystems to cooperate: the -input layer and the rfkill class. The input layer issues *commands* to the -entire system requesting that devices registered to the rfkill class change -state. The way this interaction happens is not complex, but it is not obvious -either: - -Kernel Input layer: - - * Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and - other such events when the user presses certain keys, buttons, or - toggles certain physical switches. - - THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE - KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT. It is - used to issue *commands* for the system to change behaviour, and these - commands may or may not be carried out by some kernel driver or - userspace application. It follows that doing user feedback based only - on input events is broken, as there is no guarantee that an input event - will be acted upon. - - Most wireless communication device drivers implementing rfkill - functionality MUST NOT generate these events, and have no reason to - register themselves with the input layer. Doing otherwise is a common - misconception. There is an API to propagate rfkill status change - information, and it is NOT the input layer. - -rfkill class: - - * Calls a hook in a driver to effectively change the wireless - transmitter state; - * Keeps track of the wireless transmitter state (with help from - the driver); - * Generates userspace notifications (uevents) and a call to a - notification chain (kernel) when there is a wireless transmitter - state change; - * Connects a wireless communications driver with the common rfkill - control system, which, for example, allows actions such as - "switch all bluetooth devices offline" to be carried out by - userspace or by rfkill-input. - - THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES - NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL - EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS. Doing otherwise is - a layering violation. - - Most wireless data communication drivers in the kernel have just to - implement the rfkill class API to work properly. Interfacing to the - input layer is not often required (and is very often a *bug*) on - wireless drivers. - - Platform drivers often have to attach to the input layer to *issue* - (but never to listen to) rfkill events for rfkill switches, and also to - the rfkill class to export a control interface for the platform rfkill - controllers to the rfkill subsystem. This does NOT mean the rfkill - switch is attached to a rfkill class (doing so is almost always wrong). - It just means the same kernel module is the driver for different - devices (rfkill switches and rfkill controllers). - - -Userspace input handlers (uevents) or kernel input handlers (rfkill-input): - - * Implements the policy of what should happen when one of the input - layer events related to rfkill operation is received. - * Uses the sysfs interface (userspace) or private rfkill API calls - to tell the devices registered with the rfkill class to change - their state (i.e. translates the input layer event into real - action). - - * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0 - (power off all transmitters) in a special way: it ignores any - overrides and local state cache and forces all transmitters to the - RFKILL_STATE_SOFT_BLOCKED state (including those which are already - supposed to be BLOCKED). - * rfkill EPO will remain active until rfkill-input receives an - EV_SW SW_RFKILL_ALL 1 event. While the EPO is active, transmitters - are locked in the blocked state (rfkill will refuse to unblock them). - * rfkill-input implements different policies that the user can - select for handling EV_SW SW_RFKILL_ALL 1. It will unlock rfkill, - and either do nothing (leave transmitters blocked, but now unlocked), - restore the transmitters to their state before the EPO, or unblock - them all. - -Userspace uevent handler or kernel platform-specific drivers hooked to the -rfkill notifier chain: - - * Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents, - in order to know when a device that is registered with the rfkill - class changes state; - * Issues feedback notifications to the user; - * In the rare platforms where this is required, synthesizes an input - event to command all *OTHER* rfkill devices to also change their - statues when a specific rfkill device changes state. - - -=============================================================================== -3: Kernel driver guidelines - -Remember: point-of-view is everything for a driver that connects to the rfkill -subsystem. All the details below must be measured/perceived from the point of -view of the specific driver being modified. - -The first thing one needs to know is whether his driver should be talking to -the rfkill class or to the input layer. In rare cases (platform drivers), it -could happen that you need to do both, as platform drivers often handle a -variety of devices in the same driver. - -Do not mistake input devices for rfkill controllers. The only type of "rfkill -switch" device that is to be registered with the rfkill class are those -directly controlling the circuits that cause a wireless transmitter to stop -working (or the software equivalent of them), i.e. what we call a rfkill -controller. Every other kind of "rfkill switch" is just an input device and -MUST NOT be registered with the rfkill class. - -A driver should register a device with the rfkill class when ALL of the -following conditions are met (they define a rfkill controller): - -1. The device is/controls a data communications wireless transmitter; - -2. The kernel can interact with the hardware/firmware to CHANGE the wireless - transmitter state (block/unblock TX operation); - -3. The transmitter can be made to not emit any energy when "blocked": - rfkill is not about blocking data transmissions, it is about blocking - energy emission; - -A driver should register a device with the input subsystem to issue -rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX, -SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met: - -1. It is directly related to some physical device the user interacts with, to - command the O.S./firmware/hardware to enable/disable a data communications - wireless transmitter. - - Examples of the physical device are: buttons, keys and switches the user - will press/touch/slide/switch to enable or disable the wireless - communication device. - -2. It is NOT slaved to another device, i.e. there is no other device that - issues rfkill-related input events in preference to this one. - - Please refer to the corner cases and examples section for more details. - -When in doubt, do not issue input events. For drivers that should generate -input events in some platforms, but not in others (e.g. b43), the best solution -is to NEVER generate input events in the first place. That work should be -deferred to a platform-specific kernel module (which will know when to generate -events through the rfkill notifier chain) or to userspace. This avoids the -usual maintenance problems with DMI whitelisting. - - -Corner cases and examples: -==================================== - -1. If the device is an input device that, because of hardware or firmware, -causes wireless transmitters to be blocked regardless of the kernel's will, it -is still just an input device, and NOT to be registered with the rfkill class. - -2. If the wireless transmitter switch control is read-only, it is an input -device and not to be registered with the rfkill class (and maybe not to be made -an input layer event source either, see below). - -3. If there is some other device driver *closer* to the actual hardware the -user interacted with (the button/switch/key) to issue an input event, THAT is -the device driver that should be issuing input events. - -E.g: - [RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input] - (platform driver) (wireless card driver) - -The user is closer to the RFKILL slide switch plaform driver, so the driver -which must issue input events is the platform driver looking at the GPIO -hardware, and NEVER the wireless card driver (which is just a slave). It is -very likely that there are other leaves than just the WLAN card rf-kill input -(e.g. a bluetooth card, etc)... - -On the other hand, some embedded devices do this: - - [RFKILL slider switch] -- [WLAN card rf-kill input] - (wireless card driver) - -In this situation, the wireless card driver *could* register itself as an input -device and issue rf-kill related input events... but in order to AVOID the need -for DMI whitelisting, the wireless card driver does NOT do it. Userspace (HAL) -or a platform driver (that exists only on these embedded devices) will do the -dirty job of issuing the input events. - - -COMMON MISTAKES in kernel drivers, related to rfkill: -==================================== - -1. NEVER confuse input device keys and buttons with input device switches. - - 1a. Switches are always set or reset. They report the current state - (on position or off position). - - 1b. Keys and buttons are either in the pressed or not-pressed state, and - that's it. A "button" that latches down when you press it, and - unlatches when you press it again is in fact a switch as far as input - devices go. - -Add the SW_* events you need for switches, do NOT try to emulate a button using -KEY_* events just because there is no such SW_* event yet. Do NOT try to use, -for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead. - -2. Input device switches (sources of EV_SW events) DO store their current state -(so you *must* initialize it by issuing a gratuitous input layer event on -driver start-up and also when resuming from sleep), and that state CAN be -queried from userspace through IOCTLs. There is no sysfs interface for this, -but that doesn't mean you should break things trying to hook it to the rfkill -class to get a sysfs interface :-) - -3. Do not issue *_RFKILL_ALL events by default, unless you are sure it is the -correct event for your switch/button. These events are emergency power-off -events when they are trying to turn the transmitters off. An example of an -input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill -switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch. -An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by -default, is any sort of hot key that is type-specific (e.g. the one for WLAN). - - -3.1 Guidelines for wireless device drivers ------------------------------------------- - -(in this text, rfkill->foo means the foo field of struct rfkill). - -1. Each independent transmitter in a wireless device (usually there is only one -transmitter per device) should have a SINGLE rfkill class attached to it. - -2. If the device does not have any sort of hardware assistance to allow the -driver to rfkill the device, the driver should emulate it by taking all actions -required to silence the transmitter. - -3. If it is impossible to silence the transmitter (i.e. it still emits energy, -even if it is just in brief pulses, when there is no data to transmit and there -is no hardware support to turn it off) do NOT lie to the users. Do not attach -it to a rfkill class. The rfkill subsystem does not deal with data -transmission, it deals with energy emission. If the transmitter is emitting -energy, it is not blocked in rfkill terms. - -4. It doesn't matter if the device has multiple rfkill input lines affecting -the same transmitter, their combined state is to be exported as a single state -per transmitter (see rule 1). - -This rule exists because users of the rfkill subsystem expect to get (and set, -when possible) the overall transmitter rfkill state, not of a particular rfkill -line. +The rfkill class is provided for kernel drivers to register their radio +transmitter with the kernel, provide methods for turning it on and off and, +optionally, letting the system know about hardware-disabled states that may +be implemented on the device. This code is enabled with the CONFIG_RFKILL +Kconfig option, which drivers can "select". -5. The wireless device driver MUST NOT leave the transmitter enabled during -suspend and hibernation unless: +The rfkill class code also notifies userspace of state changes, this is +achieved via uevents. It also provides some sysfs files for userspace to +check the status of radio transmitters. See the "Userspace support" section +below. - 5.1. The transmitter has to be enabled for some sort of functionality - like wake-on-wireless-packet or autonomous packed forwarding in a mesh - network, and that functionality is enabled for this suspend/hibernation - cycle. -AND +The rfkill-input code implements a basic response to rfkill buttons -- it +implements turning on/off all devices of a certain class (or all). - 5.2. The device was not on a user-requested BLOCKED state before - the suspend (i.e. the driver must NOT unblock a device, not even - to support wake-on-wireless-packet or remain in the mesh). +When the device is hard-blocked (either by a call to rfkill_set_hw_state() +or from query_hw_block) set_block() will be invoked but drivers can well +ignore the method call since they can use the return value of the function +rfkill_set_hw_state() to sync the software state instead of keeping track +of calls to set_block(). -In other words, there is absolutely no allowed scenario where a driver can -automatically take action to unblock a rfkill controller (obviously, this deals -with scenarios where soft-blocking or both soft and hard blocking is happening. -Scenarios where hardware rfkill lines are the only ones blocking the -transmitter are outside of this rule, since the wireless device driver does not -control its input hardware rfkill lines in the first place). -6. During resume, rfkill will try to restore its previous state. +The entire functionality is spread over more than one subsystem: -7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio -until it is resumed. + * The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and + SW_RFKILL_ALL -- when the user presses a button. Drivers for radio + transmitters generally do not register to the input layer, unless the + device really provides an input device (i.e. a button that has no + effect other than generating a button press event) + * The rfkill-input code hooks up to these events and switches the soft-block + of the various radio transmitters, depending on the button type. -Example of a WLAN wireless driver connected to the rfkill subsystem: --------------------------------------------------------------------- + * The rfkill drivers turn off/on their transmitters as requested. -A certain WLAN card has one input pin that causes it to block the transmitter -and makes the status of that input pin available (only for reading!) to the -kernel driver. This is a hard rfkill input line (it cannot be overridden by -the kernel driver). + * The rfkill class will generate userspace notifications (uevents) to tell + userspace what the current state is. -The card also has one PCI register that, if manipulated by the driver, causes -it to block the transmitter. This is a soft rfkill input line. -It has also a thermal protection circuitry that shuts down its transmitter if -the card overheats, and makes the status of that protection available (only for -reading!) to the kernel driver. This is also a hard rfkill input line. -If either one of these rfkill lines are active, the transmitter is blocked by -the hardware and forced offline. +3. Kernel driver guidelines -The driver should allocate and attach to its struct device *ONE* instance of -the rfkill class (there is only one transmitter). -It can implement the get_state() hook, and return RFKILL_STATE_HARD_BLOCKED if -either one of its two hard rfkill input lines are active. If the two hard -rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft -rfkill input line is active. Only if none of the rfkill input lines are -active, will it return RFKILL_STATE_UNBLOCKED. +Drivers for radio transmitters normally implement only the rfkill class. +These drivers may not unblock the transmitter based on own decisions, they +should act on information provided by the rfkill class only. -Since the device has a hardware rfkill line, it IS subject to state changes -external to rfkill. Therefore, the driver must make sure that it calls -rfkill_force_state() to keep the status always up-to-date, and it must do a -rfkill_force_state() on resume from sleep. +Platform drivers might implement input devices if the rfkill button is just +that, a button. If that button influences the hardware then you need to +implement an rfkill class instead. This also applies if the platform provides +a way to turn on/off the transmitter(s). -Every time the driver gets a notification from the card that one of its rfkill -lines changed state (polling might be needed on badly designed cards that don't -generate interrupts for such events), it recomputes the rfkill state as per -above, and calls rfkill_force_state() to update it. +During suspend/hibernation, transmitters should only be left enabled when +wake-on wlan or similar functionality requires it and the device wasn't +blocked before suspend/hibernate. Note that it may be necessary to update +the rfkill subsystem's idea of what the current state is at resume time if +the state may have changed over suspend. -The driver should implement the toggle_radio() hook, that: -1. Returns an error if one of the hardware rfkill lines are active, and the -caller asked for RFKILL_STATE_UNBLOCKED. -2. Activates the soft rfkill line if the caller asked for state -RFKILL_STATE_SOFT_BLOCKED. It should do this even if one of the hard rfkill -lines are active, effectively double-blocking the transmitter. - -3. Deactivates the soft rfkill line if none of the hardware rfkill lines are -active and the caller asked for RFKILL_STATE_UNBLOCKED. - -=============================================================================== -4: Kernel API +4. Kernel API To build a driver with rfkill subsystem support, the driver should depend on -(or select) the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT. +(or select) the Kconfig symbol RFKILL. The hardware the driver talks to may be write-only (where the current state of the hardware is unknown), or read-write (where the hardware can be queried about its current state). -The rfkill class will call the get_state hook of a device every time it needs -to know the *real* current state of the hardware. This can happen often, but -it does not do any polling, so it is not enough on hardware that is subject -to state changes outside of the rfkill subsystem. - -Therefore, calling rfkill_force_state() when a state change happens is -mandatory when the device has a hardware rfkill line, or when something else -like the firmware could cause its state to be changed without going through the -rfkill class. - -Some hardware provides events when its status changes. In these cases, it is -best for the driver to not provide a get_state hook, and instead register the -rfkill class *already* with the correct status, and keep it updated using -rfkill_force_state() when it gets an event from the hardware. - -rfkill_force_state() must be used on the device resume handlers to update the -rfkill status, should there be any chance of the device status changing during -the sleep. - -There is no provision for a statically-allocated rfkill struct. You must -use rfkill_allocate() to allocate one. - -You should: - - rfkill_allocate() - - modify rfkill fields (flags, name) - - modify state to the current hardware state (THIS IS THE ONLY TIME - YOU CAN ACCESS state DIRECTLY) - - rfkill_register() +Calling rfkill_set_hw_state() when a state change happens is required from +rfkill drivers that control devices that can be hard-blocked unless they also +assign the poll_hw_block() callback (then the rfkill core will poll the +device). Don't do this unless you cannot get the event in any other way. -The only way to set a device to the RFKILL_STATE_HARD_BLOCKED state is through -a suitable return of get_state() or through rfkill_force_state(). -When a device is in the RFKILL_STATE_HARD_BLOCKED state, the only way to switch -it to a different state is through a suitable return of get_state() or through -rfkill_force_state(). -If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED -when that device is already at the RFKILL_STATE_HARD_BLOCKED state, it should -not return an error. Instead, it should try to double-block the transmitter, -so that its state will change from RFKILL_STATE_HARD_BLOCKED to -RFKILL_STATE_SOFT_BLOCKED should the hardware blocking cease. - -Please refer to the source for more documentation. - -=============================================================================== -5: Userspace support - -rfkill devices issue uevents (with an action of "change"), with the following -environment variables set: - -RFKILL_NAME -RFKILL_STATE -RFKILL_TYPE +5. Userspace support -The ABI for these variables is defined by the sysfs attributes. It is best -to take a quick look at the source to make sure of the possible values. - -It is expected that HAL will trap those, and bridge them to DBUS, etc. These -events CAN and SHOULD be used to give feedback to the user about the rfkill -status of the system. - -Input devices may issue events that are related to rfkill. These are the -various KEY_* events and SW_* events supported by rfkill-input.c. - -Userspace may not change the state of an rfkill switch in response to an -input event, it should refrain from changing states entirely. - -Userspace cannot assume it is the only source of control for rfkill switches. -Their state can change due to firmware actions, direct user actions, and the -rfkill-input EPO override for *_RFKILL_ALL. - -When rfkill-input is not active, userspace must initiate a rfkill status -change by writing to the "state" attribute in order for anything to happen. - -Take particular care to implement EV_SW SW_RFKILL_ALL properly. When that -switch is set to OFF, *every* rfkill device *MUST* be immediately put into the -RFKILL_STATE_SOFT_BLOCKED state, no questions asked. - -The following sysfs entries will be created: +The following sysfs entries exist for every rfkill device: name: Name assigned by driver to this key (interface or driver name). type: Name of the key type ("wlan", "bluetooth", etc). state: Current state of the transmitter 0: RFKILL_STATE_SOFT_BLOCKED - transmitter is forced off, but one can override it - by a write to the state attribute; + transmitter is turned off by software 1: RFKILL_STATE_UNBLOCKED - transmiter is NOT forced off, and may operate if - all other conditions for such operation are met - (such as interface is up and configured, etc); + transmiter is (potentially) active 2: RFKILL_STATE_HARD_BLOCKED transmitter is forced off by something outside of - the driver's control. One cannot set a device to - this state through writes to the state attribute; - claim: 1: Userspace handles events, 0: Kernel handles events - -Both the "state" and "claim" entries are also writable. For the "state" entry -this means that when 1 or 0 is written, the device rfkill state (if not yet in -the requested state), will be will be toggled accordingly. - -For the "claim" entry writing 1 to it means that the kernel no longer handles -key events even though RFKILL_INPUT input was enabled. When "claim" has been -set to 0, userspace should make sure that it listens for the input events or -check the sysfs "state" entry regularly to correctly perform the required tasks -when the rkfill key is pressed. - -A note about input devices and EV_SW events: - -In order to know the current state of an input device switch (like -SW_RFKILL_ALL), you will need to use an IOCTL. That information is not -available through sysfs in a generic way at this time, and it is not available -through the rfkill class AT ALL. + the driver's control. + claim: 0: Kernel handles events (currently always reads that value) + +rfkill devices also issue uevents (with an action of "change"), with the +following environment variables set: + +RFKILL_NAME +RFKILL_STATE +RFKILL_TYPE + +The contents of these variables corresponds to the "name", "state" and +"type" sysfs files explained above. diff --git a/MAINTAINERS b/MAINTAINERS index e18baa4..2f6a8fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4753,9 +4753,9 @@ S: Supported F: fs/reiserfs/ RFKILL -P: Ivo van Doorn -M: IvDoorn@gmail.com -L: netdev@vger.kernel.org +P: Johannes Berg +M: johannes@sipsolutions.net +L: linux-wireless@vger.kernel.org S: Maintained F Documentation/rfkill.txt F: net/rfkill/ diff --git a/arch/arm/mach-pxa/tosa-bt.c b/arch/arm/mach-pxa/tosa-bt.c index bde42aa..c31e601 100644 --- a/arch/arm/mach-pxa/tosa-bt.c +++ b/arch/arm/mach-pxa/tosa-bt.c @@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data) gpio_set_value(data->gpio_reset, 0); } -static int tosa_bt_toggle_radio(void *data, enum rfkill_state state) +static int tosa_bt_set_block(void *data, bool blocked) { - pr_info("BT_RADIO going: %s\n", - state == RFKILL_STATE_UNBLOCKED ? "on" : "off"); + pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on"); - if (state == RFKILL_STATE_UNBLOCKED) { + if (!blocked) { pr_info("TOSA_BT: going ON\n"); tosa_bt_on(data); } else { pr_info("TOSA_BT: going OFF\n"); tosa_bt_off(data); } + return 0; } +static const struct rfkill_ops tosa_bt_rfkill_ops = { + .set_block = tosa_bt_set_block, +}; + static int tosa_bt_probe(struct platform_device *dev) { int rc; @@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev) if (rc) goto err_pwr_dir; - rfk = rfkill_allocate(&dev->dev, RFKILL_TYPE_BLUETOOTH); + rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, + &tosa_bt_rfkill_ops, data); if (!rfk) { rc = -ENOMEM; goto err_rfk_alloc; } - rfk->name = "tosa-bt"; - rfk->toggle_radio = tosa_bt_toggle_radio; - rfk->data = data; -#ifdef CONFIG_RFKILL_LEDS - rfk->led_trigger.name = "tosa-bt"; -#endif + rfkill_set_led_trigger_name(rfk, "tosa-bt"); rc = rfkill_register(rfk); if (rc) @@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev) return 0; err_rfkill: - if (rfk) - rfkill_free(rfk); - rfk = NULL; + rfkill_destroy(rfk); err_rfk_alloc: tosa_bt_off(data); err_pwr_dir: @@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); - if (rfk) + if (rfk) { rfkill_unregister(rfk); + rfkill_destroy(rfk); + } rfk = NULL; tosa_bt_off(data); diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index afac5b6..58ce807 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 837135f..5ddd8c4 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev) return 0; } -static int hso_radio_toggle(void *data, enum rfkill_state state) +static int hso_rfkill_set_block(void *data, bool blocked) { struct hso_device *hso_dev = data; - int enabled = (state == RFKILL_STATE_UNBLOCKED); + int enabled = !blocked; int rv; mutex_lock(&hso_dev->mutex); @@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state) return rv; } +static const struct rfkill_ops hso_rfkill_ops = { + .set_block = hso_rfkill_set_block, +}; + /* Creates and sets up everything for rfkill */ static void hso_create_rfkill(struct hso_device *hso_dev, struct usb_interface *interface) @@ -2506,29 +2510,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev, struct device *dev = &hso_net->net->dev; char *rfkn; - hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, - RFKILL_TYPE_WWAN); - if (!hso_net->rfkill) { - dev_err(dev, "%s - Out of memory\n", __func__); - return; - } rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) { - rfkill_free(hso_net->rfkill); - hso_net->rfkill = NULL; + if (!rfkn) dev_err(dev, "%s - Out of memory\n", __func__); - return; - } + snprintf(rfkn, 20, "hso-%d", interface->altsetting->desc.bInterfaceNumber); - hso_net->rfkill->name = rfkn; - hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED; - hso_net->rfkill->data = hso_dev; - hso_net->rfkill->toggle_radio = hso_radio_toggle; + + hso_net->rfkill = rfkill_alloc(rfkn, + &interface_to_usbdev(interface)->dev, + RFKILL_TYPE_WWAN, + &hso_rfkill_ops, hso_dev); + if (!hso_net->rfkill) { + dev_err(dev, "%s - Out of memory\n", __func__); + kfree(rfkn); + return; + } if (rfkill_register(hso_net->rfkill) < 0) { + rfkill_destroy(hso_net->rfkill); kfree(rfkn); - hso_net->rfkill->name = NULL; - rfkill_free(hso_net->rfkill); hso_net->rfkill = NULL; dev_err(dev, "%s - Failed to register rfkill\n", __func__); return; @@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface) hso_stop_net_device(network_table[i]); cancel_work_sync(&network_table[i]->async_put_intf); cancel_work_sync(&network_table[i]->async_get_intf); - if (rfk) + if (rfk) { rfkill_unregister(rfk); + rfkill_destroy(rfk); + } hso_free_net_device(network_table[i]); } } diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 796a3ad..515880a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -460,12 +460,9 @@ struct ath_led { bool registered; }; -/* Rfkill */ -#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ - struct ath_rfkill { struct rfkill *rfkill; - struct delayed_work rfkill_poll; + struct rfkill_ops ops; char rfkill_name[32]; }; @@ -509,8 +506,6 @@ struct ath_rfkill { #define SC_OP_RXFLUSH BIT(7) #define SC_OP_LED_ASSOCIATED BIT(8) #define SC_OP_RFKILL_REGISTERED BIT(9) -#define SC_OP_RFKILL_SW_BLOCKED BIT(10) -#define SC_OP_RFKILL_HW_BLOCKED BIT(11) #define SC_OP_WAIT_FOR_BEACON BIT(12) #define SC_OP_LED_ON BIT(13) #define SC_OP_SCANNING BIT(14) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 61da08a..f7baa40 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) ah->rfkill_polarity; } -/* h/w rfkill poll function */ -static void ath_rfkill_poll(struct work_struct *work) +/* s/w rfkill handlers */ +static int ath_rfkill_set_block(void *data, bool blocked) { - 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; + struct ath_softc *sc = data; - rfkill_force_state(sc->rf_kill.rfkill, state); - } + if (blocked) + ath_radio_disable(sc); + else + ath_radio_enable(sc); - queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, - msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); + return 0; } -/* s/w rfkill handler */ -static int ath_sw_toggle_radio(void *data, enum rfkill_state state) +static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data) { struct ath_softc *sc = data; + bool blocked = !!ath_is_rfkill_set(sc); - 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; - } + if (rfkill_set_hw_state(rfkill, blocked)) + ath_radio_disable(sc); + else + ath_radio_enable(sc); } /* 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); + sc->rf_kill.ops.set_block = ath_rfkill_set_block; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + sc->rf_kill.ops.poll = ath_rfkill_poll_state; + + snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), + "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); + + sc->rf_kill.rfkill = rfkill_alloc(sc->rf_kill.rfkill_name, + wiphy_dev(sc->hw->wiphy), + RFKILL_TYPE_WLAN, + &sc->rf_kill.ops, sc); 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; - return 0; } /* Deinitialize rfkill */ static void ath_deinit_rfkill(struct ath_softc *sc) { - if (sc->sc_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); + rfkill_destroy(sc->rf_kill.rfkill); sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; - sc->rf_kill.rfkill = NULL; } } static int ath_start_rfkill_poll(struct ath_softc *sc) { - if (sc->sc_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); + rfkill_destroy(sc->rf_kill.rfkill); /* Deinitialize the device */ ath_cleanup(sc); @@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc) goto error_attach; #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* Initialze h/w Rfkill */ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); - /* Initialize s/w rfkill */ error = ath_init_sw_rfkill(sc); if (error) @@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) } else sc->rx.rxlink = NULL; -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif + rfkill_pause_polling(sc->rf_kill.rfkill); + /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 168411d..ccdf20a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_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, PCI_D3hot); @@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* - * check the h/w rfkill state on resume - * and start the rfkill poll timer - */ - if (sc->sc_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/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 21572e4..07a99e3 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -102,7 +102,7 @@ config B43_LEDS # if it's possible. config B43_RFKILL bool - depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) + depends on B43 && (RFKILL = y || RFKILL = B43) default y # This config option automatically enables b43 HW-RNG support, diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 76f4c7b..9a498d3 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -87,7 +87,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev, } static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, - const char *name, char *default_trigger, + const char *name, const char *default_trigger, u8 led_index, bool activelow) { int err; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cb4a871..1d3e400 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3470,7 +3470,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { - b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + b43_software_rfkill(dev, false); b43info(dev->wl, "Radio turned on by software\n"); if (!dev->radio_hw_enable) { b43info(dev->wl, "The hardware RF-kill button " @@ -3478,7 +3478,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) "Press the button to turn it on.\n"); } } else { - b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + b43_software_rfkill(dev, true); b43info(dev->wl, "Radio turned off by software\n"); } } diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index c836c07..816e028 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) } static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { struct b43_phy *phy = &dev->phy; - if (state == RFKILL_STATE_UNBLOCKED) { + if (!blocked) { if (phy->radio_on) return; b43_radio_write16(dev, 0x0004, 0x00C0); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e176b6e..6d24162 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev) phy->channel = ops->get_default_chan(dev); - ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + ops->software_rfkill(dev, false); err = ops->init(dev); if (err) { b43err(dev->wl, "PHY init failed\n"); @@ -104,7 +104,7 @@ err_phy_exit: if (ops->exit) ops->exit(dev); err_block_rf: - ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + ops->software_rfkill(dev, true); return err; } @@ -113,7 +113,7 @@ 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); + ops->software_rfkill(dev, true); if (ops->exit) ops->exit(dev); } @@ -295,18 +295,13 @@ err_restore_cookie: return err; } -void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) +void b43_software_rfkill(struct b43_wldev *dev, bool blocked) { struct b43_phy *phy = &dev->phy; - if (state == RFKILL_STATE_HARD_BLOCKED) { - /* We cannot hardware-block the device */ - state = RFKILL_STATE_SOFT_BLOCKED; - } - b43_mac_suspend(dev); - phy->ops->software_rfkill(dev, state); - phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); + phy->ops->software_rfkill(dev, blocked); + phy->radio_on = !blocked; b43_mac_enable(dev); } diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index b2d9910..f4c2d79 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -159,7 +159,7 @@ struct b43_phy_operations { /* Radio */ bool (*supports_hwpctl)(struct b43_wldev *dev); - void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); + void (*software_rfkill)(struct b43_wldev *dev, bool blocked); 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); @@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); /** * b43_software_rfkill - Turn the radio ON or OFF in software. */ -void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); +void b43_software_rfkill(struct b43_wldev *dev, bool blocked); /** * b43_phy_txpower_check - Check TX power output. diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e7b98f0..5300232 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) } static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, might_sleep(); - if (state == RFKILL_STATE_UNBLOCKED) { + if (!blocked) { /* Turn radio ON */ if (phy->radio_on) return; diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 58e319d..ea0d3a3 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) } static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { //TODO } diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8bcfda5..be7b560 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) } static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) {//TODO } diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 9e1d00b..9604784 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43_rfkill_poll(struct input_polled_dev *poll_dev) +static void b43_rfkill_poll(struct rfkill *rfkill, void *data) { - struct b43_wldev *dev = poll_dev->private; + struct b43_wldev *dev = data; struct b43_wl *wl = dev->wl; bool enabled; - bool report_change = 0; mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { @@ -60,68 +59,55 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) enabled = b43_is_hw_radio_enabled(dev); if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; - report_change = 1; b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); + enabled = !rfkill_set_hw_state(rfkill, !enabled); + if (enabled != dev->phy.radio_on) + b43_software_rfkill(dev, !enabled); } mutex_unlock(&wl->mutex); - - /* send the radio switch event to the system - note both a key press - * and a release are required */ - if (unlikely(report_change)) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); - } } /* Called when the RFKILL toggled in software. */ -static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) +static int b43_rfkill_soft_set(void *data, bool blocked) { struct b43_wldev *dev = data; struct b43_wl *wl = dev->wl; - int err = -EBUSY; + int err = -EINVAL; - if (!wl->rfkill.registered) - return 0; + if (WARN_ON(!wl->rfkill.registered)) + return -EINVAL; mutex_lock(&wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; + + if (!dev->radio_hw_enable) + goto out_unlock; + + if (!blocked != dev->phy.radio_on) + b43_software_rfkill(dev, blocked); err = 0; - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!dev->radio_hw_enable) { - /* No luck. We can't toggle the hardware RF-kill - * button from software. */ - err = -EBUSY; - goto out_unlock; - } - if (!dev->phy.radio_on) - b43_software_rfkill(dev, state); - break; - case RFKILL_STATE_SOFT_BLOCKED: - if (dev->phy.radio_on) - b43_software_rfkill(dev, state); - break; - default: - b43warn(wl, "Received unexpected rfkill state %d.\n", state); - break; - } out_unlock: mutex_unlock(&wl->mutex); - return err; } -char *b43_rfkill_led_name(struct b43_wldev *dev) +const char *b43_rfkill_led_name(struct b43_wldev *dev) { struct b43_rfkill *rfk = &(dev->wl->rfkill); if (!rfk->registered) return NULL; - return rfkill_get_led_name(rfk->rfkill); + return rfkill_get_led_trigger_name(rfk->rfkill); } +static const struct rfkill_ops b43_rfkill_ops = { + .set_block = b43_rfkill_soft_set, + .poll = b43_rfkill_poll, +}; + void b43_rfkill_init(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; @@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev) rfk->registered = 0; - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto out_error; snprintf(rfk->name, sizeof(rfk->name), "b43-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; - - rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) { - rfkill_free(rfk->rfkill); - goto err_freed_rfk; - } - - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - rfk->poll_dev->input->name = rfk->name; - rfk->poll_dev->input->id.bustype = BUS_HOST; - rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; - rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); + rfk->rfkill = rfkill_alloc(rfk->name, + dev->dev->dev, + RFKILL_TYPE_WLAN, + &b43_rfkill_ops, dev); + if (!rfk->rfkill) + goto out_error; err = rfkill_register(rfk->rfkill); if (err) - goto err_free_polldev; - -#ifdef CONFIG_RFKILL_INPUT_MODULE - /* B43 RF-kill isn't useful without the rfkill-input subsystem. - * Try to load the module. */ - err = request_module("rfkill-input"); - if (err) - b43warn(wl, "Failed to load the rfkill-input module. " - "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; + goto err_free; rfk->registered = 1; return; -err_unreg_rfk: - rfkill_unregister(rfk->rfkill); -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -err_freed_rfk: - rfk->rfkill = NULL; -out_error: + err_free: + rfkill_destroy(rfk->rfkill); + out_error: rfk->registered = 0; b43warn(wl, "RF-kill button init failed\n"); } @@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev) return; rfk->registered = 0; - input_unregister_polled_device(rfk->poll_dev); rfkill_unregister(rfk->rfkill); - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; + rfkill_destroy(rfk->rfkill); rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index adacf93..da497e0 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h @@ -7,14 +7,11 @@ struct b43_wldev; #ifdef CONFIG_B43_RFKILL #include -#include struct b43_rfkill { /* The RFKILL subsystem data structure */ struct rfkill *rfkill; - /* The poll device for the RFKILL input button */ - struct input_polled_dev *poll_dev; /* Did initialization succeed? Used for freeing. */ bool registered; /* The unique name of this rfkill switch */ @@ -26,7 +23,7 @@ struct b43_rfkill { void b43_rfkill_init(struct b43_wldev *dev); void b43_rfkill_exit(struct b43_wldev *dev); -char * b43_rfkill_led_name(struct b43_wldev *dev); +const char *b43_rfkill_led_name(struct b43_wldev *dev); #else /* CONFIG_B43_RFKILL */ diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index d4f628a..6893f43 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -47,7 +47,7 @@ config B43LEGACY_LEDS # if it's possible. config B43LEGACY_RFKILL bool - depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) + depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) default y # This config option automatically enables b43 HW-RNG support, diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 3ea55b1..538d311 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev, static int b43legacy_register_led(struct b43legacy_wldev *dev, struct b43legacy_led *led, - const char *name, char *default_trigger, + const char *name, + const char *default_trigger, u8 led_index, bool activelow) { int err; diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 4b0c7d2..c6230a6 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) +static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) { - struct b43legacy_wldev *dev = poll_dev->private; + struct b43legacy_wldev *dev = data; struct b43legacy_wl *wl = dev->wl; bool enabled; - bool report_change = 0; mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { @@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) enabled = b43legacy_is_hw_radio_enabled(dev); if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; - report_change = 1; b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); + enabled = !rfkill_set_hw_state(rfkill, !enabled); + if (enabled != dev->phy.radio_on) { + if (enabled) + b43legacy_radio_turn_on(dev); + else + b43legacy_radio_turn_off(dev, 0); + } } mutex_unlock(&wl->mutex); - - /* send the radio switch event to the system - note both a key press - * and a release are required */ - if (unlikely(report_change)) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); - } } /* Called when the RFKILL toggled in software. * This is called without locking. */ -static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) +static int b43legacy_rfkill_soft_set(void *data, bool blocked) { struct b43legacy_wldev *dev = data; struct b43legacy_wl *wl = dev->wl; - int err = -EBUSY; + int ret = -EINVAL; if (!wl->rfkill.registered) - return 0; + return -EINVAL; mutex_lock(&wl->mutex); if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) goto out_unlock; - err = 0; - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!dev->radio_hw_enable) { - /* No luck. We can't toggle the hardware RF-kill - * button from software. */ - err = -EBUSY; - goto out_unlock; - } - if (!dev->phy.radio_on) + + if (!dev->radio_hw_enable) + goto out_unlock; + + if (!blocked != dev->phy.radio_on) { + if (!blocked) b43legacy_radio_turn_on(dev); - break; - case RFKILL_STATE_SOFT_BLOCKED: - if (dev->phy.radio_on) + else b43legacy_radio_turn_off(dev, 0); - break; - default: - b43legacywarn(wl, "Received unexpected rfkill state %d.\n", - state); - break; } + ret = 0; out_unlock: mutex_unlock(&wl->mutex); - - return err; + return ret; } -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) { struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); if (!rfk->registered) return NULL; - return rfkill_get_led_name(rfk->rfkill); + return rfkill_get_led_trigger_name(rfk->rfkill); } +static const struct rfkill_ops b43legacy_rfkill_ops = { + .set_block = b43legacy_rfkill_soft_set, + .poll = b43legacy_rfkill_poll, +}; + void b43legacy_rfkill_init(struct b43legacy_wldev *dev) { struct b43legacy_wl *wl = dev->wl; @@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) rfk->registered = 0; - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto out_error; snprintf(rfk->name, sizeof(rfk->name), "b43legacy-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; - - rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) { - rfkill_free(rfk->rfkill); - goto err_freed_rfk; - } - - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43legacy_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - - rfk->poll_dev->input->name = rfk->name; - rfk->poll_dev->input->id.bustype = BUS_HOST; - rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; - rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); + rfk->rfkill = rfkill_alloc(rfk->name, + dev->dev->dev, + RFKILL_TYPE_WLAN, + &b43legacy_rfkill_ops, dev); + if (!rfk->rfkill) + goto out_error; err = rfkill_register(rfk->rfkill); if (err) - goto err_free_polldev; - -#ifdef CONFIG_RFKILL_INPUT_MODULE - /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. - * Try to load the module. */ - err = request_module("rfkill-input"); - if (err) - b43legacywarn(wl, "Failed to load the rfkill-input module." - "The built-in radio LED will not work.\n"); -#endif /* CONFIG_RFKILL_INPUT */ - - err = input_register_polled_device(rfk->poll_dev); - if (err) - goto err_unreg_rfk; + goto err_free; rfk->registered = 1; return; -err_unreg_rfk: - rfkill_unregister(rfk->rfkill); -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -err_freed_rfk: - rfk->rfkill = NULL; -out_error: + err_free: + rfkill_destroy(rfk->rfkill); + out_error: rfk->registered = 0; b43legacywarn(wl, "RF-kill button init failed\n"); } @@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) return; rfk->registered = 0; - input_unregister_polled_device(rfk->poll_dev); rfkill_unregister(rfk->rfkill); - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; + rfkill_destroy(rfk->rfkill); rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h index 11150a8..adffc50 100644 --- a/drivers/net/wireless/b43legacy/rfkill.h +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -6,16 +6,12 @@ struct b43legacy_wldev; #ifdef CONFIG_B43LEGACY_RFKILL #include -#include -#include struct b43legacy_rfkill { /* The RFKILL subsystem data structure */ struct rfkill *rfkill; - /* The poll device for the RFKILL input button */ - struct input_polled_dev *poll_dev; /* Did initialization succeed? Used for freeing. */ bool registered; /* The unique name of this rfkill switch */ @@ -27,7 +23,7 @@ struct b43legacy_rfkill { void b43legacy_rfkill_init(struct b43legacy_wldev *dev); void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); +const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); #else /* CONFIG_B43LEGACY_RFKILL */ diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 8304f64..6fe259f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -5,15 +5,14 @@ config IWLWIFI select FW_LOADER select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS - select RFKILL if IWLWIFI_RFKILL config IWLWIFI_LEDS bool "Enable LED support in iwlagn and iwl3945 drivers" depends on IWLWIFI config IWLWIFI_RFKILL - bool "Enable RF kill support in iwlagn and iwl3945 drivers" - depends on IWLWIFI + def_bool y + depends on IWLWIFI && RFKILL config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 65605ad..1314993 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -36,42 +36,37 @@ #include "iwl-core.h" /* software rf-kill from user */ -static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) +static int iwl_rfkill_soft_rf_kill(void *data, bool blocked) { struct iwl_priv *priv = data; - int err = 0; if (!priv->rfkill) - return 0; + return -EINVAL; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; - IWL_DEBUG_RF_KILL(priv, "we received soft RFKILL set to state %d\n", state); + IWL_DEBUG_RF_KILL(priv, "received soft RFKILL: block=%d\n", blocked); + mutex_lock(&priv->mutex); - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (iwl_is_rfkill_hw(priv)) { - err = -EBUSY; - goto out_unlock; - } + if (iwl_is_rfkill_hw(priv)) + goto out_unlock; + + if (!blocked) iwl_radio_kill_sw_enable_radio(priv); - break; - case RFKILL_STATE_SOFT_BLOCKED: + else iwl_radio_kill_sw_disable_radio(priv); - break; - default: - IWL_WARN(priv, "we received unexpected RFKILL state %d\n", - state); - break; - } + out_unlock: mutex_unlock(&priv->mutex); - - return err; + return 0; } +static const struct rfkill_ops iwl_rfkill_ops = { + .set_block = iwl_rfkill_soft_rf_kill, +}; + int iwl_rfkill_init(struct iwl_priv *priv) { struct device *device = wiphy_dev(priv->hw->wiphy); @@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv) BUG_ON(device == NULL); IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); - priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + priv->rfkill = rfkill_alloc(priv->cfg->name, + device, + RFKILL_TYPE_WLAN, + &iwl_rfkill_ops, priv); if (!priv->rfkill) { IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); ret = -ENOMEM; goto error; } - priv->rfkill->name = priv->cfg->name; - priv->rfkill->data = priv; - priv->rfkill->state = RFKILL_STATE_UNBLOCKED; - priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; - - priv->rfkill->dev.class->suspend = NULL; - priv->rfkill->dev.class->resume = NULL; - ret = rfkill_register(priv->rfkill); if (ret) { IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); @@ -102,11 +92,10 @@ int iwl_rfkill_init(struct iwl_priv *priv) } IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return ret; + return 0; free_rfkill: - if (priv->rfkill != NULL) - rfkill_free(priv->rfkill); + rfkill_destroy(priv->rfkill); priv->rfkill = NULL; error: @@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init); void iwl_rfkill_unregister(struct iwl_priv *priv) { - if (priv->rfkill) + if (priv->rfkill) { rfkill_unregister(priv->rfkill); + rfkill_destroy(priv->rfkill); + } priv->rfkill = NULL; } @@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) if (!priv->rfkill) return; - if (iwl_is_rfkill_hw(priv)) { - rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); - return; - } - - if (!iwl_is_rfkill_sw(priv)) - rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED); + if (rfkill_set_hw_state(priv->rfkill, + !!iwl_is_rfkill_hw(priv))) + iwl_radio_kill_sw_disable_radio(priv); else - rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED); + iwl_radio_kill_sw_enable_radio(priv); } EXPORT_SYMBOL(iwl_rfkill_set_hw_state); diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c index 4ca8b49..8ee2c3c 100644 --- a/drivers/net/wireless/iwmc3200wifi/rfkill.c +++ b/drivers/net/wireless/iwmc3200wifi/rfkill.c @@ -25,47 +25,42 @@ #include "iwm.h" -static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) +static int iwm_rfkill_set_block(void *data, bool blocked) { struct iwm_priv *iwm = data; - switch (state) { - case RFKILL_STATE_UNBLOCKED: + if (!blocked) { if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) return -EBUSY; if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && (iwm_to_ndev(iwm)->flags & IFF_UP)) - iwm_up(iwm); - - break; - case RFKILL_STATE_SOFT_BLOCKED: + return iwm_up(iwm); + } else { if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - iwm_down(iwm); - - break; - default: - break; + return iwm_down(iwm); } return 0; } +static const struct rfkill_ops iwm_rfkill_ops = { + .set_block = iwm_rfkill_set_block, +}; + int iwm_rfkill_init(struct iwm_priv *iwm) { int ret; - iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); + iwm->rfkill = rfkill_alloc(KBUILD_MODNAME, + iwm_to_dev(iwm), + RFKILL_TYPE_WLAN, + &iwm_rfkill_ops, iwm); if (!iwm->rfkill) { IWM_ERR(iwm, "Unable to allocate rfkill device\n"); return -ENOMEM; } - iwm->rfkill->name = KBUILD_MODNAME; - iwm->rfkill->data = iwm; - iwm->rfkill->state = RFKILL_STATE_UNBLOCKED; - iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle; - ret = rfkill_register(iwm->rfkill); if (ret) { IWM_ERR(iwm, "Failed to register rfkill device\n"); @@ -74,15 +69,15 @@ int iwm_rfkill_init(struct iwm_priv *iwm) return 0; fail: - rfkill_free(iwm->rfkill); + rfkill_destroy(iwm->rfkill); return ret; } void iwm_rfkill_exit(struct iwm_priv *iwm) { - if (iwm->rfkill) + if (iwm->rfkill) { rfkill_unregister(iwm->rfkill); - - rfkill_free(iwm->rfkill); + rfkill_destroy(iwm->rfkill); + } iwm->rfkill = NULL; } diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 284ebac..c682ac5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -21,7 +21,7 @@ config ACER_WMI depends on NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 - depends on RFKILL + depends on RFKILL || RFKILL = n select ACPI_WMI ---help--- This is a driver for newer Acer (and Wistron) laptops. It adds @@ -60,7 +60,7 @@ config DELL_LAPTOP depends on DCDBAS depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE - depends on RFKILL + depends on RFKILL || RFKILL = n depends on POWER_SUPPLY default n ---help--- @@ -117,7 +117,7 @@ config HP_WMI tristate "HP WMI extras" depends on ACPI_WMI depends on INPUT - depends on RFKILL + depends on RFKILL || RFKILL = n help Say Y here if you want to support WMI-based hotkeys on HP laptops and to read data from WMI such as docking or ambient light sensor state. @@ -196,14 +196,13 @@ config THINKPAD_ACPI tristate "ThinkPad ACPI Laptop Extras" depends on ACPI depends on INPUT + depends on RFKILL || RFKILL = n select BACKLIGHT_LCD_SUPPORT select BACKLIGHT_CLASS_DEVICE select HWMON select NVRAM select NEW_LEDS select LEDS_CLASS - select NET - select RFKILL ---help--- This is a driver for the IBM and Lenovo ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video @@ -338,9 +337,9 @@ config EEEPC_LAPTOP depends on ACPI depends on INPUT depends on EXPERIMENTAL + depends on RFKILL || RFKILL = n select BACKLIGHT_CLASS_DEVICE select HWMON - select RFKILL ---help--- This driver supports the Fn-Fx keys on Eee PC laptops. It also adds the ability to switch camera/wlan on/off. @@ -405,9 +404,8 @@ config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI depends on INPUT + depends on RFKILL || RFKILL = n select INPUT_POLLDEV - select NET - select RFKILL select BACKLIGHT_CLASS_DEVICE ---help--- This driver adds support for access to certain system settings diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 62d02b3..b618fa5 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored) status = get_u32(&state, ACER_CAP_WIRELESS); if (ACPI_SUCCESS(status)) - rfkill_force_state(wireless_rfkill, state ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(wireless_rfkill, !!state); if (has_cap(ACER_CAP_BLUETOOTH)) { status = get_u32(&state, ACER_CAP_BLUETOOTH); if (ACPI_SUCCESS(status)) - rfkill_force_state(bluetooth_rfkill, state ? - RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(bluetooth_rfkill, !!state); } schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); } -static int acer_rfkill_set(void *data, enum rfkill_state state) +static int acer_rfkill_set(void *data, bool blocked) { acpi_status status; - u32 *cap = data; - status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); + u32 cap = (unsigned long)data; + status = set_u32(!!blocked, cap); if (ACPI_FAILURE(status)) return -ENODEV; return 0; } -static struct rfkill * acer_rfkill_register(struct device *dev, -enum rfkill_type type, char *name, u32 cap) +static const struct rfkill_ops acer_rfkill_ops = { + .set_block = acer_rfkill_set, +}; + +static struct rfkill *acer_rfkill_register(struct device *dev, + enum rfkill_type type, + char *name, u32 cap) { int err; u32 state; - u32 *data; struct rfkill *rfkill_dev; - rfkill_dev = rfkill_allocate(dev, type); + rfkill_dev = rfkill_alloc(name, dev, type, + &acer_rfkill_ops, + (void *)(unsigned long)cap); if (!rfkill_dev) return ERR_PTR(-ENOMEM); - rfkill_dev->name = name; get_u32(&state, cap); - rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED; - data = kzalloc(sizeof(u32), GFP_KERNEL); - if (!data) { - rfkill_free(rfkill_dev); - return ERR_PTR(-ENOMEM); - } - *data = cap; - rfkill_dev->data = data; - rfkill_dev->toggle_radio = acer_rfkill_set; + rfkill_set_sw_state(rfkill_dev, !state); err = rfkill_register(rfkill_dev); if (err) { - kfree(rfkill_dev->data); - rfkill_free(rfkill_dev); + rfkill_destroy(rfkill_dev); return ERR_PTR(err); } return rfkill_dev; @@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev) RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", ACER_CAP_BLUETOOTH); if (IS_ERR(bluetooth_rfkill)) { - kfree(wireless_rfkill->data); rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); return PTR_ERR(bluetooth_rfkill); } } @@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev) static void acer_rfkill_exit(void) { cancel_delayed_work_sync(&acer_rfkill_work); - kfree(wireless_rfkill->data); + rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); + if (has_cap(ACER_CAP_BLUETOOTH)) { - kfree(bluetooth_rfkill->data); rfkill_unregister(bluetooth_rfkill); + rfkill_destroy(bluetooth_rfkill); } return; } diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index af9f430..2faf0e1 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, result[3]: NVRAM format version number */ -static int dell_rfkill_set(int radio, enum rfkill_state state) +static int dell_rfkill_set(void *data, bool blocked) { struct calling_interface_buffer buffer; - int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; + int disable = blocked ? 0 : 1; + unsigned long radio = (unsigned long)data; memset(&buffer, 0, sizeof(struct calling_interface_buffer)); buffer.input[0] = (1 | (radio<<8) | (disable << 16)); @@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state) return 0; } -static int dell_wifi_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(1, state); -} - -static int dell_bluetooth_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(2, state); -} - -static int dell_wwan_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(3, state); -} - -static int dell_rfkill_get(int bit, enum rfkill_state *state) +static void dell_rfkill_query(struct rfkill *rfkill, void *data) { struct calling_interface_buffer buffer; int status; - int new_state = RFKILL_STATE_HARD_BLOCKED; + int bit = (unsigned long)data + 16; memset(&buffer, 0, sizeof(struct calling_interface_buffer)); dell_send_request(&buffer, 17, 11); status = buffer.output[1]; - if (status & (1<<16)) - new_state = RFKILL_STATE_SOFT_BLOCKED; - - if (status & (1<name = "dell-wifi"; - wifi_rfkill->toggle_radio = dell_wifi_set; - wifi_rfkill->get_state = dell_wifi_get; + } ret = rfkill_register(wifi_rfkill); if (ret) goto err_wifi; } if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { - bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); - if (!bluetooth_rfkill) + bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, + RFKILL_TYPE_BLUETOOTH, + &dell_rfkill_ops, (void *) 2); + if (!bluetooth_rfkill) { + ret = -ENOMEM; goto err_bluetooth; - bluetooth_rfkill->name = "dell-bluetooth"; - bluetooth_rfkill->toggle_radio = dell_bluetooth_set; - bluetooth_rfkill->get_state = dell_bluetooth_get; + } ret = rfkill_register(bluetooth_rfkill); if (ret) goto err_bluetooth; } if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { - wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); - if (!wwan_rfkill) + wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, + &dell_rfkill_ops, (void *) 3); + if (!wwan_rfkill) { + ret = -ENOMEM; goto err_wwan; - wwan_rfkill->name = "dell-wwan"; - wwan_rfkill->toggle_radio = dell_wwan_set; - wwan_rfkill->get_state = dell_wwan_get; + } ret = rfkill_register(wwan_rfkill); if (ret) goto err_wwan; @@ -285,22 +255,15 @@ static int dell_setup_rfkill(void) return 0; err_wwan: - if (wwan_rfkill) - rfkill_free(wwan_rfkill); - if (bluetooth_rfkill) { + rfkill_destroy(wwan_rfkill); + if (bluetooth_rfkill) rfkill_unregister(bluetooth_rfkill); - bluetooth_rfkill = NULL; - } err_bluetooth: - if (bluetooth_rfkill) - rfkill_free(bluetooth_rfkill); - if (wifi_rfkill) { + rfkill_destroy(bluetooth_rfkill); + if (wifi_rfkill) rfkill_unregister(wifi_rfkill); - wifi_rfkill = NULL; - } err_wifi: - if (wifi_rfkill) - rfkill_free(wifi_rfkill); + rfkill_destroy(wifi_rfkill); return ret; } diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 353a898..1208d0c 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd) * Rfkill helpers */ -static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) -{ - if (state == RFKILL_STATE_SOFT_BLOCKED) - return set_acpi(CM_ASL_WLAN, 0); - else - return set_acpi(CM_ASL_WLAN, 1); -} - -static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) +static bool eeepc_wlan_rfkill_blocked(void) { if (get_acpi(CM_ASL_WLAN) == 1) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - return 0; + return false; + return true; } -static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) +static int eeepc_rfkill_set(void *data, bool blocked) { - if (state == RFKILL_STATE_SOFT_BLOCKED) - return set_acpi(CM_ASL_BLUETOOTH, 0); - else - return set_acpi(CM_ASL_BLUETOOTH, 1); + unsigned long asl = (unsigned long)data; + return set_acpi(asl, !blocked); } -static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) -{ - if (get_acpi(CM_ASL_BLUETOOTH) == 1) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - return 0; -} +static const struct rfkill_ops eeepc_rfkill_ops = { + .set_block = eeepc_rfkill_set, +}; /* * Sys helpers @@ -531,9 +514,9 @@ static int notify_brn(void) static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) { - enum rfkill_state state; struct pci_dev *dev; struct pci_bus *bus = pci_find_bus(0, 1); + bool blocked; if (event != ACPI_NOTIFY_BUS_CHECK) return; @@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) return; } - eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state); - - if (state == RFKILL_STATE_UNBLOCKED) { + blocked = eeepc_wlan_rfkill_blocked(); + if (!blocked) { dev = pci_get_slot(bus, 0); if (dev) { /* Device already present */ @@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) } } - rfkill_force_state(ehotk->eeepc_wlan_rfkill, state); + rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked); } static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) @@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device) eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); if (get_acpi(CM_ASL_WLAN) != -1) { - ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_WLAN); + ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan", + &device->dev, + RFKILL_TYPE_WLAN, + &eeepc_rfkill_ops, + (void *)CM_ASL_WLAN); if (!ehotk->eeepc_wlan_rfkill) goto wlan_fail; - ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; - ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; - ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; - if (get_acpi(CM_ASL_WLAN) == 1) { - ehotk->eeepc_wlan_rfkill->state = - RFKILL_STATE_UNBLOCKED; - rfkill_set_default(RFKILL_TYPE_WLAN, - RFKILL_STATE_UNBLOCKED); - } else { - ehotk->eeepc_wlan_rfkill->state = - RFKILL_STATE_SOFT_BLOCKED; - rfkill_set_default(RFKILL_TYPE_WLAN, - RFKILL_STATE_SOFT_BLOCKED); - } + rfkill_set_global_sw_state(RFKILL_TYPE_WLAN, + get_acpi(CM_ASL_WLAN) != 1); result = rfkill_register(ehotk->eeepc_wlan_rfkill); if (result) goto wlan_fail; @@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device) if (get_acpi(CM_ASL_BLUETOOTH) != -1) { ehotk->eeepc_bluetooth_rfkill = - rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); + rfkill_alloc("eeepc-bluetooth", + &device->dev, + RFKILL_TYPE_BLUETOOTH, + &eeepc_rfkill_ops, + (void *)CM_ASL_BLUETOOTH); if (!ehotk->eeepc_bluetooth_rfkill) goto bluetooth_fail; - ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; - ehotk->eeepc_bluetooth_rfkill->toggle_radio = - eeepc_bluetooth_rfkill_set; - ehotk->eeepc_bluetooth_rfkill->get_state = - eeepc_bluetooth_rfkill_state; - if (get_acpi(CM_ASL_BLUETOOTH) == 1) { - ehotk->eeepc_bluetooth_rfkill->state = - RFKILL_STATE_UNBLOCKED; - rfkill_set_default(RFKILL_TYPE_BLUETOOTH, - RFKILL_STATE_UNBLOCKED); - } else { - ehotk->eeepc_bluetooth_rfkill->state = - RFKILL_STATE_SOFT_BLOCKED; - rfkill_set_default(RFKILL_TYPE_BLUETOOTH, - RFKILL_STATE_SOFT_BLOCKED); - } - + rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH, + get_acpi(CM_ASL_BLUETOOTH) != 1); result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); if (result) goto bluetooth_fail; @@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device) return 0; bluetooth_fail: - if (ehotk->eeepc_bluetooth_rfkill) - rfkill_free(ehotk->eeepc_bluetooth_rfkill); + rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); rfkill_unregister(ehotk->eeepc_wlan_rfkill); - ehotk->eeepc_wlan_rfkill = NULL; wlan_fail: - if (ehotk->eeepc_wlan_rfkill) - rfkill_free(ehotk->eeepc_wlan_rfkill); + rfkill_destroy(ehotk->eeepc_wlan_rfkill); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); ehotk_fail: diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index fe171fa..8d93114 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void) return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); } -static int hp_wmi_wifi_set(void *data, enum rfkill_state state) +static int hp_wmi_set_block(void *data, bool blocked) { - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100); -} + unsigned long b = (unsigned long) data; + int query = BIT(b + 8) | ((!!blocked) << b); -static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state) -{ - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200); + return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); } -static int hp_wmi_wwan_set(void *data, enum rfkill_state state) -{ - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400); -} +static const struct rfkill_ops hp_wmi_rfkill_ops = { + .set_block = hp_wmi_set_block, +}; -static int hp_wmi_wifi_state(void) +static bool hp_wmi_wifi_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x100) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } -static int hp_wmi_bluetooth_state(void) +static bool hp_wmi_bluetooth_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x10000) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } -static int hp_wmi_wwan_state(void) +static bool hp_wmi_wwan_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x1000000) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } static ssize_t show_display(struct device *dev, struct device_attribute *attr, @@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context) } } else if (eventcode == 0x5) { if (wifi_rfkill) - rfkill_force_state(wifi_rfkill, - hp_wmi_wifi_state()); + rfkill_set_sw_state(wifi_rfkill, + hp_wmi_wifi_state()); if (bluetooth_rfkill) - rfkill_force_state(bluetooth_rfkill, - hp_wmi_bluetooth_state()); + rfkill_set_sw_state(bluetooth_rfkill, + hp_wmi_bluetooth_state()); if (wwan_rfkill) - rfkill_force_state(wwan_rfkill, - hp_wmi_wwan_state()); + rfkill_set_sw_state(wwan_rfkill, + hp_wmi_wwan_state()); } else printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", eventcode); @@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) goto add_sysfs_error; if (wireless & 0x1) { - wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); - wifi_rfkill->name = "hp-wifi"; - wifi_rfkill->state = hp_wmi_wifi_state(); - wifi_rfkill->toggle_radio = hp_wmi_wifi_set; + wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, + RFKILL_TYPE_WLAN, + &hp_wmi_rfkill_ops, + (void *) 0); + rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state()); err = rfkill_register(wifi_rfkill); if (err) - goto add_sysfs_error; + goto register_wifi_error; } if (wireless & 0x2) { - bluetooth_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_BLUETOOTH); - bluetooth_rfkill->name = "hp-bluetooth"; - bluetooth_rfkill->state = hp_wmi_bluetooth_state(); - bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; + bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, + RFKILL_TYPE_BLUETOOTH, + &hp_wmi_rfkill_ops, + (void *) 1); + rfkill_set_sw_state(bluetooth_rfkill, + hp_wmi_bluetooth_state()); err = rfkill_register(bluetooth_rfkill); if (err) goto register_bluetooth_error; } if (wireless & 0x4) { - wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); - wwan_rfkill->name = "hp-wwan"; - wwan_rfkill->state = hp_wmi_wwan_state(); - wwan_rfkill->toggle_radio = hp_wmi_wwan_set; + wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, + RFKILL_TYPE_WWAN, + &hp_wmi_rfkill_ops, + (void *) 2); + rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state()); err = rfkill_register(wwan_rfkill); if (err) goto register_wwan_err; @@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) return 0; register_wwan_err: + rfkill_destroy(wwan_rfkill); if (bluetooth_rfkill) rfkill_unregister(bluetooth_rfkill); register_bluetooth_error: + rfkill_destroy(bluetooth_rfkill); if (wifi_rfkill) rfkill_unregister(wifi_rfkill); +register_wifi_error: + rfkill_destroy(wifi_rfkill); add_sysfs_error: cleanup_sysfs(device); return err; @@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) { cleanup_sysfs(device); - if (wifi_rfkill) + if (wifi_rfkill) { rfkill_unregister(wifi_rfkill); - if (bluetooth_rfkill) + rfkill_destroy(wifi_rfkill); + } + if (bluetooth_rfkill) { rfkill_unregister(bluetooth_rfkill); - if (wwan_rfkill) + rfkill_destroy(wifi_rfkill); + } + if (wwan_rfkill) { rfkill_unregister(wwan_rfkill); + rfkill_destroy(wwan_rfkill); + } return 0; } diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f1963b0..aec0b27 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -128,11 +128,11 @@ enum sony_nc_rfkill { SONY_BLUETOOTH, SONY_WWAN, SONY_WIMAX, - SONY_RFKILL_MAX, + N_SONY_RFKILL, }; -static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX]; -static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900}; +static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; +static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; static void sony_nc_rfkill_update(void); /*********** Input Devices ***********/ @@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void) { int i; - for (i = 0; i < SONY_RFKILL_MAX; i++) { - if (sony_rfkill_devices[i]) + for (i = 0; i < N_SONY_RFKILL; i++) { + if (sony_rfkill_devices[i]) { rfkill_unregister(sony_rfkill_devices[i]); + rfkill_destroy(sony_rfkill_devices[i]); + } } } -static int sony_nc_rfkill_get(void *data, enum rfkill_state *state) -{ - int result; - int argument = sony_rfkill_address[(long) data]; - - sony_call_snc_handle(0x124, 0x200, &result); - if (result & 0x1) { - sony_call_snc_handle(0x124, argument, &result); - if (result & 0xf) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - } else { - *state = RFKILL_STATE_HARD_BLOCKED; - } - - return 0; -} - -static int sony_nc_rfkill_set(void *data, enum rfkill_state state) +static int sony_nc_rfkill_set(void *data, bool blocked) { int result; int argument = sony_rfkill_address[(long) data] + 0x100; - if (state == RFKILL_STATE_UNBLOCKED) + if (!blocked) argument |= 0xff0000; return sony_call_snc_handle(0x124, argument, &result); } -static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) -{ - int err = 0; - struct rfkill *sony_wifi_rfkill; - - sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); - if (!sony_wifi_rfkill) - return -1; - sony_wifi_rfkill->name = "sony-wifi"; - sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wifi_rfkill->get_state = sony_nc_rfkill_get; - sony_wifi_rfkill->data = (void *)SONY_WIFI; - err = rfkill_register(sony_wifi_rfkill); - if (err) - rfkill_free(sony_wifi_rfkill); - else { - sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill; - sony_nc_rfkill_set(sony_wifi_rfkill->data, - RFKILL_STATE_UNBLOCKED); - } - return err; -} +static const struct rfkill_ops sony_rfkill_ops = { + .set_block = sony_nc_rfkill_set, +}; -static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) +static int sony_nc_setup_rfkill(struct acpi_device *device, + enum sony_nc_rfkill nc_type) { int err = 0; - struct rfkill *sony_bluetooth_rfkill; - - sony_bluetooth_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_BLUETOOTH); - if (!sony_bluetooth_rfkill) - return -1; - sony_bluetooth_rfkill->name = "sony-bluetooth"; - sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; - sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; - err = rfkill_register(sony_bluetooth_rfkill); - if (err) - rfkill_free(sony_bluetooth_rfkill); - else { - sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill; - sony_nc_rfkill_set(sony_bluetooth_rfkill->data, - RFKILL_STATE_UNBLOCKED); + struct rfkill *rfk; + enum rfkill_type type; + const char *name; + + switch (nc_type) { + case SONY_WIFI: + type = RFKILL_TYPE_WLAN; + name = "sony-wifi"; + break; + case SONY_BLUETOOTH: + type = RFKILL_TYPE_BLUETOOTH; + name = "sony-bluetooth"; + break; + case SONY_WWAN: + type = RFKILL_TYPE_WWAN; + name = "sony-wwan"; + break; + case SONY_WIMAX: + type = RFKILL_TYPE_WIMAX; + name = "sony-wimax"; + break; + default: + return -EINVAL; } - return err; -} -static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) -{ - int err = 0; - struct rfkill *sony_wwan_rfkill; + rfk = rfkill_alloc(name, &device->dev, type, + &sony_rfkill_ops, (void *)nc_type); + if (!rfk) + return -ENOMEM; - sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); - if (!sony_wwan_rfkill) - return -1; - sony_wwan_rfkill->name = "sony-wwan"; - sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wwan_rfkill->get_state = sony_nc_rfkill_get; - sony_wwan_rfkill->data = (void *)SONY_WWAN; - err = rfkill_register(sony_wwan_rfkill); - if (err) - rfkill_free(sony_wwan_rfkill); - else { - sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill; - sony_nc_rfkill_set(sony_wwan_rfkill->data, - RFKILL_STATE_UNBLOCKED); + err = rfkill_register(rfk); + if (err) { + rfkill_destroy(rfk); + return err; } + sony_rfkill_devices[nc_type] = rfk; + sony_nc_rfkill_set((void *)nc_type, false); return err; } -static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) +static void sony_nc_rfkill_update() { - int err = 0; - struct rfkill *sony_wimax_rfkill; + enum sony_nc_rfkill i; + int result; + bool hwblock; - sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); - if (!sony_wimax_rfkill) - return -1; - sony_wimax_rfkill->name = "sony-wimax"; - sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wimax_rfkill->get_state = sony_nc_rfkill_get; - sony_wimax_rfkill->data = (void *)SONY_WIMAX; - err = rfkill_register(sony_wimax_rfkill); - if (err) - rfkill_free(sony_wimax_rfkill); - else { - sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill; - sony_nc_rfkill_set(sony_wimax_rfkill->data, - RFKILL_STATE_UNBLOCKED); - } - return err; -} + sony_call_snc_handle(0x124, 0x200, &result); + hwblock = !(result & 0x1); -static void sony_nc_rfkill_update() -{ - int i; - enum rfkill_state state; + for (i = 0; i < N_SONY_RFKILL; i++) { + int argument = sony_rfkill_address[i]; - for (i = 0; i < SONY_RFKILL_MAX; i++) { - if (sony_rfkill_devices[i]) { - sony_rfkill_devices[i]-> - get_state(sony_rfkill_devices[i]->data, - &state); - rfkill_force_state(sony_rfkill_devices[i], state); + if (!sony_rfkill_devices[i]) + continue; + + if (hwblock) { + if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) + sony_nc_rfkill_set(sony_rfkill_devices[i], + true); + continue; } + + sony_call_snc_handle(0x124, argument, &result); + rfkill_set_states(sony_rfkill_devices[i], + !(result & 0xf), false); } } @@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device) } if (result & 0x1) - sony_nc_setup_wifi_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WIFI); if (result & 0x2) - sony_nc_setup_bluetooth_rfkill(device); + sony_nc_setup_rfkill(device, SONY_BLUETOOTH); if (result & 0x1c) - sony_nc_setup_wwan_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WWAN); if (result & 0x20) - sony_nc_setup_wimax_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WIMAX); return 0; } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 912be65..cfcafa4 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -166,13 +166,6 @@ enum { #define TPACPI_MAX_ACPI_ARGS 3 -/* rfkill switches */ -enum { - TPACPI_RFK_BLUETOOTH_SW_ID = 0, - TPACPI_RFK_WWAN_SW_ID, - TPACPI_RFK_UWB_SW_ID, -}; - /* printk headers */ #define TPACPI_LOG TPACPI_FILE ": " #define TPACPI_EMERG KERN_EMERG TPACPI_LOG @@ -1005,67 +998,237 @@ static int __init tpacpi_check_std_acpi_brightness_support(void) return 0; } -static int __init tpacpi_new_rfkill(const unsigned int id, - struct rfkill **rfk, +static void printk_deprecated_attribute(const char * const what, + const char * const details) +{ + tpacpi_log_usertask("deprecated sysfs attribute"); + printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " + "will be removed. %s\n", + what, details); +} + +/************************************************************************* + * rfkill and radio control support helpers + */ + +/* + * ThinkPad-ACPI firmware handling model: + * + * WLSW (master wireless switch) is event-driven, and is common to all + * firmware-controlled radios. It cannot be controlled, just monitored, + * as expected. It overrides all radio state in firmware + * + * The kernel, a masked-off hotkey, and WLSW can change the radio state + * (TODO: verify how WLSW interacts with the returned radio state). + * + * The only time there are shadow radio state changes, is when + * masked-off hotkeys are used. + */ + +/* + * Internal driver API for radio state: + * + * int: < 0 = error, otherwise enum tpacpi_rfkill_state + * bool: true means radio blocked (off) + */ +enum tpacpi_rfkill_state { + TPACPI_RFK_RADIO_OFF = 0, + TPACPI_RFK_RADIO_ON +}; + +/* rfkill switches */ +enum tpacpi_rfk_id { + TPACPI_RFK_BLUETOOTH_SW_ID = 0, + TPACPI_RFK_WWAN_SW_ID, + TPACPI_RFK_UWB_SW_ID, + TPACPI_RFK_SW_MAX +}; + +static const char *tpacpi_rfkill_names[] = { + [TPACPI_RFK_BLUETOOTH_SW_ID] = "bluetooth", + [TPACPI_RFK_WWAN_SW_ID] = "wwan", + [TPACPI_RFK_UWB_SW_ID] = "uwb", + [TPACPI_RFK_SW_MAX] = NULL +}; + +/* ThinkPad-ACPI rfkill subdriver */ +struct tpacpi_rfk { + struct rfkill *rfkill; + enum tpacpi_rfk_id id; + const struct tpacpi_rfk_ops *ops; +}; + +struct tpacpi_rfk_ops { + /* firmware interface */ + int (*get_status)(void); + int (*set_status)(const enum tpacpi_rfkill_state); +}; + +static struct tpacpi_rfk *tpacpi_rfkill_switches[TPACPI_RFK_SW_MAX]; + +/* Query FW and update rfkill sw state for a given rfkill switch */ +static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk) +{ + int status; + + if (!tp_rfk) + return -ENODEV; + + status = (tp_rfk->ops->get_status)(); + if (status < 0) + return status; + + rfkill_set_sw_state(tp_rfk->rfkill, + (status == TPACPI_RFK_RADIO_OFF)); + + return status; +} + +/* Query FW and update rfkill sw state for all rfkill switches */ +static void tpacpi_rfk_update_swstate_all(void) +{ + unsigned int i; + + for (i = 0; i < TPACPI_RFK_SW_MAX; i++) + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]); +} + +/* + * Sync the HW-blocking state of all rfkill switches, + * do notice it causes the rfkill core to schedule uevents + */ +static void tpacpi_rfk_update_hwblock_state(bool blocked) +{ + unsigned int i; + struct tpacpi_rfk *tp_rfk; + + for (i = 0; i < TPACPI_RFK_SW_MAX; i++) { + tp_rfk = tpacpi_rfkill_switches[i]; + if (tp_rfk) { + if (rfkill_set_hw_state(tp_rfk->rfkill, + blocked)) { + /* ignore -- we track sw block */ + } + } + } +} + +/* Call to get the WLSW state from the firmware */ +static int hotkey_get_wlsw(void); + +/* Call to query WLSW state and update all rfkill switches */ +static bool tpacpi_rfk_check_hwblock_state(void) +{ + int res = hotkey_get_wlsw(); + int hw_blocked; + + /* When unknown or unsupported, we have to assume it is unblocked */ + if (res < 0) + return false; + + hw_blocked = (res == TPACPI_RFK_RADIO_OFF); + tpacpi_rfk_update_hwblock_state(hw_blocked); + + return hw_blocked; +} + +static int tpacpi_rfk_hook_set_block(void *data, bool blocked) +{ + struct tpacpi_rfk *tp_rfk = data; + int res; + + dbg_printk(TPACPI_DBG_RFKILL, + "request to change radio state to %s\n", + blocked ? "blocked" : "unblocked"); + + /* try to set radio state */ + res = (tp_rfk->ops->set_status)(blocked ? + TPACPI_RFK_RADIO_OFF : TPACPI_RFK_RADIO_ON); + + /* and update the rfkill core with whatever the FW really did */ + tpacpi_rfk_update_swstate(tp_rfk); + + return (res < 0) ? res : 0; +} + +static const struct rfkill_ops tpacpi_rfk_rfkill_ops = { + .set_block = tpacpi_rfk_hook_set_block, +}; + +static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, + const struct tpacpi_rfk_ops *tp_rfkops, const enum rfkill_type rfktype, const char *name, - const bool set_default, - int (*toggle_radio)(void *, enum rfkill_state), - int (*get_state)(void *, enum rfkill_state *)) + const bool set_default) { + struct tpacpi_rfk *atp_rfk; int res; - enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED; + bool initial_sw_state = false; + int initial_sw_status; - res = get_state(NULL, &initial_state); - if (res < 0) { + BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); + + initial_sw_status = (tp_rfkops->get_status)(); + if (initial_sw_status < 0) { printk(TPACPI_ERR "failed to read initial state for %s, error %d; " - "will turn radio off\n", name, res); - } else if (set_default) { - /* try to set the initial state as the default for the rfkill - * type, since we ask the firmware to preserve it across S5 in - * NVRAM */ - if (rfkill_set_default(rfktype, - (initial_state == RFKILL_STATE_UNBLOCKED) ? - RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED) == -EPERM) - vdbg_printk(TPACPI_DBG_RFKILL, - "Default state for %s cannot be changed\n", - name); - } - - *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); - if (!*rfk) { + "will turn radio off\n", name, initial_sw_status); + } else { + initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); + if (set_default) { + /* try to set the initial state as the default for the + * rfkill type, since we ask the firmware to preserve + * it across S5 in NVRAM */ + rfkill_set_global_sw_state(rfktype, initial_sw_state); + } + } + + atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL); + if (atp_rfk) + atp_rfk->rfkill = rfkill_alloc(name, + &tpacpi_pdev->dev, + rfktype, + &tpacpi_rfk_rfkill_ops, + atp_rfk); + if (!atp_rfk || !atp_rfk->rfkill) { printk(TPACPI_ERR "failed to allocate memory for rfkill class\n"); + kfree(atp_rfk); return -ENOMEM; } - (*rfk)->name = name; - (*rfk)->get_state = get_state; - (*rfk)->toggle_radio = toggle_radio; - (*rfk)->state = initial_state; + atp_rfk->id = id; + atp_rfk->ops = tp_rfkops; + + rfkill_set_states(atp_rfk->rfkill, initial_sw_state, + tpacpi_rfk_check_hwblock_state()); - res = rfkill_register(*rfk); + res = rfkill_register(atp_rfk->rfkill); if (res < 0) { printk(TPACPI_ERR "failed to register %s rfkill switch: %d\n", name, res); - rfkill_free(*rfk); - *rfk = NULL; + rfkill_destroy(atp_rfk->rfkill); + kfree(atp_rfk); return res; } + tpacpi_rfkill_switches[id] = atp_rfk; return 0; } -static void printk_deprecated_attribute(const char * const what, - const char * const details) +static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id) { - tpacpi_log_usertask("deprecated sysfs attribute"); - printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " - "will be removed. %s\n", - what, details); + struct tpacpi_rfk *tp_rfk; + + BUG_ON(id >= TPACPI_RFK_SW_MAX); + + tp_rfk = tpacpi_rfkill_switches[id]; + if (tp_rfk) { + rfkill_unregister(tp_rfk->rfkill); + tpacpi_rfkill_switches[id] = NULL; + kfree(tp_rfk); + } } static void printk_deprecated_rfkill_attribute(const char * const what) @@ -1074,6 +1237,112 @@ static void printk_deprecated_rfkill_attribute(const char * const what) "Please switch to generic rfkill before year 2010"); } +/* sysfs enable ------------------------------------------------ */ +static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id, + struct device_attribute *attr, + char *buf) +{ + int status; + + printk_deprecated_rfkill_attribute(attr->attr.name); + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state()) { + status = TPACPI_RFK_RADIO_OFF; + } else { + status = tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + if (status < 0) + return status; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", + (status == TPACPI_RFK_RADIO_ON) ? 1 : 0); +} + +static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res; + + printk_deprecated_rfkill_attribute(attr->attr.name); + + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + + tpacpi_disclose_usertask(attr->attr.name, "set to %ld\n", t); + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state() && !!t) + return -EPERM; + + res = tpacpi_rfkill_switches[id]->ops->set_status((!!t) ? + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF); + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + + return (res < 0) ? res : count; +} + +/* procfs -------------------------------------------------------------- */ +static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) +{ + int len = 0; + + if (id >= TPACPI_RFK_SW_MAX) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else { + int status; + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state()) { + status = TPACPI_RFK_RADIO_OFF; + } else { + status = tpacpi_rfk_update_swstate( + tpacpi_rfkill_switches[id]); + if (status < 0) + return status; + } + + len += sprintf(p + len, "status:\t\t%s\n", + (status == TPACPI_RFK_RADIO_ON) ? + "enabled" : "disabled"); + len += sprintf(p + len, "commands:\tenable, disable\n"); + } + + return len; +} + +static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) +{ + char *cmd; + int status = -1; + int res = 0; + + if (id >= TPACPI_RFK_SW_MAX) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) + status = TPACPI_RFK_RADIO_ON; + else if (strlencmp(cmd, "disable") == 0) + status = TPACPI_RFK_RADIO_OFF; + else + return -EINVAL; + } + + if (status != -1) { + tpacpi_disclose_usertask("procfs", "attempt to %s %s\n", + (status == TPACPI_RFK_RADIO_ON) ? + "enable" : "disable", + tpacpi_rfkill_names[id]); + res = (tpacpi_rfkill_switches[id]->ops->set_status)(status); + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + } + + return res; +} + /************************************************************************* * thinkpad-acpi driver attributes */ @@ -1127,8 +1396,6 @@ static DRIVER_ATTR(version, S_IRUGO, #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES -static void tpacpi_send_radiosw_update(void); - /* wlsw_emulstate ------------------------------------------------------ */ static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, char *buf) @@ -1144,11 +1411,10 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv, if (parse_strtoul(buf, 1, &t)) return -EINVAL; - if (tpacpi_wlsw_emulstate != t) { - tpacpi_wlsw_emulstate = !!t; - tpacpi_send_radiosw_update(); - } else + if (tpacpi_wlsw_emulstate != !!t) { tpacpi_wlsw_emulstate = !!t; + tpacpi_rfk_update_hwblock_state(!t); /* negative logic */ + } return count; } @@ -1463,17 +1729,23 @@ static struct attribute_set *hotkey_dev_attributes; /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) -static int hotkey_get_wlsw(int *status) +static int hotkey_get_wlsw(void) { + int status; + + if (!tp_features.hotkey_wlsw) + return -ENODEV; + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES - if (dbg_wlswemul) { - *status = !!tpacpi_wlsw_emulstate; - return 0; - } + if (dbg_wlswemul) + return (tpacpi_wlsw_emulstate) ? + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif - if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) + + if (!acpi_evalf(hkey_handle, &status, "WLSW", "d")) return -EIO; - return 0; + + return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } static int hotkey_get_tablet_mode(int *status) @@ -2107,12 +2379,16 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res, s; - res = hotkey_get_wlsw(&s); + int res; + res = hotkey_get_wlsw(); if (res < 0) return res; - return snprintf(buf, PAGE_SIZE, "%d\n", !!s); + /* Opportunistic update */ + tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); } static struct device_attribute dev_attr_hotkey_radio_sw = @@ -2223,30 +2499,52 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { &dev_attr_hotkey_wakeup_hotunplug_complete.attr, }; -static void bluetooth_update_rfk(void); -static void wan_update_rfk(void); -static void uwb_update_rfk(void); +/* + * Sync both the hw and sw blocking state of all switches + */ static void tpacpi_send_radiosw_update(void) { int wlsw; - /* Sync these BEFORE sending any rfkill events */ - if (tp_features.bluetooth) - bluetooth_update_rfk(); - if (tp_features.wan) - wan_update_rfk(); - if (tp_features.uwb) - uwb_update_rfk(); + /* + * We must sync all rfkill controllers *before* issuing any + * rfkill input events, or we will race the rfkill core input + * handler. + * + * tpacpi_inputdev_send_mutex works as a syncronization point + * for the above. + * + * We optimize to avoid numerous calls to hotkey_get_wlsw. + */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { + wlsw = hotkey_get_wlsw(); + + /* Sync hw blocking state first if it is hw-blocked */ + if (wlsw == TPACPI_RFK_RADIO_OFF) + tpacpi_rfk_update_hwblock_state(true); + + /* Sync sw blocking state */ + tpacpi_rfk_update_swstate_all(); + + /* Sync hw blocking state last if it is hw-unblocked */ + if (wlsw == TPACPI_RFK_RADIO_ON) + tpacpi_rfk_update_hwblock_state(false); + + /* Issue rfkill input event for WLSW switch */ + if (!(wlsw < 0)) { mutex_lock(&tpacpi_inputdev_send_mutex); input_report_switch(tpacpi_inputdev, - SW_RFKILL_ALL, !!wlsw); + SW_RFKILL_ALL, (wlsw > 0)); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); } + + /* + * this can be unconditional, as we will poll state again + * if userspace uses the notify to read data + */ hotkey_radio_sw_notify_change(); } @@ -3056,8 +3354,6 @@ enum { #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" -static struct rfkill *tpacpi_bluetooth_rfkill; - static void bluetooth_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ @@ -3067,83 +3363,47 @@ static void bluetooth_suspend(pm_message_t state) "bluetooth power down on resume request failed\n"); } -static int bluetooth_get_radiosw(void) +static int bluetooth_get_status(void) { int status; - if (!tp_features.bluetooth) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) return (tpacpi_bluetooth_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) return -EIO; return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static void bluetooth_update_rfk(void) +static int bluetooth_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tpacpi_bluetooth_rfkill) - return; - - status = bluetooth_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_bluetooth_rfkill, status); - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); -} - -static int bluetooth_set_radiosw(int radio_on, int update_rfk) -{ - int status; - - if (!tp_features.bluetooth) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s bluetooth\n", radio_on ? "enable" : "disable"); + "will attempt to %s bluetooth\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) { - tpacpi_bluetooth_emulstate = !!radio_on; - if (update_rfk) - bluetooth_update_rfk(); + tpacpi_bluetooth_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ - if (radio_on) + if (state == TPACPI_RFK_RADIO_ON) status = TP_ACPI_BLUETOOTH_RADIOSSW; else status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) return -EIO; - if (update_rfk) - bluetooth_update_rfk(); - return 0; } @@ -3152,35 +3412,16 @@ static ssize_t bluetooth_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - int status; - - printk_deprecated_rfkill_attribute("bluetooth_enable"); - - status = bluetooth_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", - (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_BLUETOOTH_SW_ID, + attr, buf); } static ssize_t bluetooth_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long t; - int res; - - printk_deprecated_rfkill_attribute("bluetooth_enable"); - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t); - - res = bluetooth_set_radiosw(t, 1); - - return (res) ? res : count; + return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_BLUETOOTH_SW_ID, + attr, buf, count); } static struct device_attribute dev_attr_bluetooth_enable = @@ -3198,23 +3439,10 @@ static const struct attribute_group bluetooth_attr_group = { .attrs = bluetooth_attributes, }; -static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) -{ - int bts = bluetooth_get_radiosw(); - - if (bts < 0) - return bts; - - *state = bts; - return 0; -} - -static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops bluetooth_tprfk_ops = { + .get_status = bluetooth_get_status, + .set_status = bluetooth_set_status, +}; static void bluetooth_shutdown(void) { @@ -3230,13 +3458,12 @@ static void bluetooth_shutdown(void) static void bluetooth_exit(void) { - bluetooth_shutdown(); - - if (tpacpi_bluetooth_rfkill) - rfkill_unregister(tpacpi_bluetooth_rfkill); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &bluetooth_attr_group); + + tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); + + bluetooth_shutdown(); } static int __init bluetooth_init(struct ibm_init_struct *iibm) @@ -3277,20 +3504,18 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) if (!tp_features.bluetooth) return 1; - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &bluetooth_attr_group); - if (res) - return res; - res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, - &tpacpi_bluetooth_rfkill, + &bluetooth_tprfk_ops, RFKILL_TYPE_BLUETOOTH, TPACPI_RFK_BLUETOOTH_SW_NAME, - true, - tpacpi_bluetooth_rfk_set, - tpacpi_bluetooth_rfk_get); + true); + if (res) + return res; + + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &bluetooth_attr_group); if (res) { - bluetooth_exit(); + tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); return res; } @@ -3300,46 +3525,12 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) /* procfs -------------------------------------------------------------- */ static int bluetooth_read(char *p) { - int len = 0; - int status = bluetooth_get_radiosw(); - - if (!tp_features.bluetooth) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status == RFKILL_STATE_UNBLOCKED) ? - "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; + return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); } static int bluetooth_write(char *buf) { - char *cmd; - int state = -1; - - if (!tp_features.bluetooth) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - state = 1; - } else if (strlencmp(cmd, "disable") == 0) { - state = 0; - } else - return -EINVAL; - } - - if (state != -1) { - tpacpi_disclose_usertask("procfs bluetooth", - "attempt to %s\n", - state ? "enable" : "disable"); - bluetooth_set_radiosw(state, 1); - } - - return 0; + return tpacpi_rfk_procfs_write(TPACPI_RFK_BLUETOOTH_SW_ID, buf); } static struct ibm_struct bluetooth_driver_data = { @@ -3365,8 +3556,6 @@ enum { #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" -static struct rfkill *tpacpi_wan_rfkill; - static void wan_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ @@ -3376,83 +3565,47 @@ static void wan_suspend(pm_message_t state) "WWAN power down on resume request failed\n"); } -static int wan_get_radiosw(void) +static int wan_get_status(void) { int status; - if (!tp_features.wan) - return -ENODEV; - - /* WLSW overrides WWAN in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) return (tpacpi_wwan_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) return -EIO; return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; -} - -static void wan_update_rfk(void) -{ - int status; - - if (!tpacpi_wan_rfkill) - return; - - status = wan_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_wan_rfkill, status); - - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static int wan_set_radiosw(int radio_on, int update_rfk) +static int wan_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tp_features.wan) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s WWAN\n", radio_on ? "enable" : "disable"); + "will attempt to %s wwan\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) { - tpacpi_wwan_emulstate = !!radio_on; - if (update_rfk) - wan_update_rfk(); + tpacpi_wwan_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ - if (radio_on) + if (state == TPACPI_RFK_RADIO_ON) status = TP_ACPI_WANCARD_RADIOSSW; else status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) return -EIO; - if (update_rfk) - wan_update_rfk(); - return 0; } @@ -3461,35 +3614,16 @@ static ssize_t wan_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - int status; - - printk_deprecated_rfkill_attribute("wwan_enable"); - - status = wan_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", - (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_WWAN_SW_ID, + attr, buf); } static ssize_t wan_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long t; - int res; - - printk_deprecated_rfkill_attribute("wwan_enable"); - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t); - - res = wan_set_radiosw(t, 1); - - return (res) ? res : count; + return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_WWAN_SW_ID, + attr, buf, count); } static struct device_attribute dev_attr_wan_enable = @@ -3507,23 +3641,10 @@ static const struct attribute_group wan_attr_group = { .attrs = wan_attributes, }; -static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) -{ - int wans = wan_get_radiosw(); - - if (wans < 0) - return wans; - - *state = wans; - return 0; -} - -static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops wan_tprfk_ops = { + .get_status = wan_get_status, + .set_status = wan_set_status, +}; static void wan_shutdown(void) { @@ -3539,13 +3660,12 @@ static void wan_shutdown(void) static void wan_exit(void) { - wan_shutdown(); - - if (tpacpi_wan_rfkill) - rfkill_unregister(tpacpi_wan_rfkill); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &wan_attr_group); + + tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); + + wan_shutdown(); } static int __init wan_init(struct ibm_init_struct *iibm) @@ -3584,20 +3704,19 @@ static int __init wan_init(struct ibm_init_struct *iibm) if (!tp_features.wan) return 1; - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &wan_attr_group); - if (res) - return res; - res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, - &tpacpi_wan_rfkill, + &wan_tprfk_ops, RFKILL_TYPE_WWAN, TPACPI_RFK_WWAN_SW_NAME, - true, - tpacpi_wan_rfk_set, - tpacpi_wan_rfk_get); + true); + if (res) + return res; + + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &wan_attr_group); + if (res) { - wan_exit(); + tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); return res; } @@ -3607,48 +3726,12 @@ static int __init wan_init(struct ibm_init_struct *iibm) /* procfs -------------------------------------------------------------- */ static int wan_read(char *p) { - int len = 0; - int status = wan_get_radiosw(); - - tpacpi_disclose_usertask("procfs wan", "read"); - - if (!tp_features.wan) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status == RFKILL_STATE_UNBLOCKED) ? - "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; + return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); } static int wan_write(char *buf) { - char *cmd; - int state = -1; - - if (!tp_features.wan) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - state = 1; - } else if (strlencmp(cmd, "disable") == 0) { - state = 0; - } else - return -EINVAL; - } - - if (state != -1) { - tpacpi_disclose_usertask("procfs wan", - "attempt to %s\n", - state ? "enable" : "disable"); - wan_set_radiosw(state, 1); - } - - return 0; + return tpacpi_rfk_procfs_write(TPACPI_RFK_WWAN_SW_ID, buf); } static struct ibm_struct wan_driver_data = { @@ -3672,108 +3755,59 @@ enum { #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" -static struct rfkill *tpacpi_uwb_rfkill; - -static int uwb_get_radiosw(void) +static int uwb_get_status(void) { int status; - if (!tp_features.uwb) - return -ENODEV; - - /* WLSW overrides UWB in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) return (tpacpi_uwb_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) return -EIO; return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static void uwb_update_rfk(void) +static int uwb_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tpacpi_uwb_rfkill) - return; - - status = uwb_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_uwb_rfkill, status); - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); -} - -static int uwb_set_radiosw(int radio_on, int update_rfk) -{ - int status; - - if (!tp_features.uwb) - return -ENODEV; - - /* WLSW overrides UWB in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s UWB\n", radio_on ? "enable" : "disable"); + "will attempt to %s UWB\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) { - tpacpi_uwb_emulstate = !!radio_on; - if (update_rfk) - uwb_update_rfk(); + tpacpi_uwb_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif - status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0; + if (state == TPACPI_RFK_RADIO_ON) + status = TP_ACPI_UWB_RADIOSSW; + else + status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) return -EIO; - if (update_rfk) - uwb_update_rfk(); - return 0; } /* --------------------------------------------------------------------- */ -static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) -{ - int uwbs = uwb_get_radiosw(); - - if (uwbs < 0) - return uwbs; - - *state = uwbs; - return 0; -} - -static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops uwb_tprfk_ops = { + .get_status = uwb_get_status, + .set_status = uwb_set_status, +}; static void uwb_exit(void) { - if (tpacpi_uwb_rfkill) - rfkill_unregister(tpacpi_uwb_rfkill); + tpacpi_destroy_rfkill(TPACPI_RFK_UWB_SW_ID); } static int __init uwb_init(struct ibm_init_struct *iibm) @@ -3813,13 +3847,10 @@ static int __init uwb_init(struct ibm_init_struct *iibm) return 1; res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, - &tpacpi_uwb_rfkill, + &uwb_tprfk_ops, RFKILL_TYPE_UWB, TPACPI_RFK_UWB_SW_NAME, - false, - tpacpi_uwb_rfk_set, - tpacpi_uwb_rfk_get); - + false); return res; } diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 4345089..81d31ea 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -45,7 +45,6 @@ #include #include #include -#include #include @@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) struct toshiba_acpi_dev { struct platform_device *p_dev; - struct rfkill *rfk_dev; - struct input_polled_dev *poll_dev; + struct rfkill *bt_rfk; const char *bt_name; - const char *rfk_name; - - bool last_rfk_state; struct mutex mutex; }; static struct toshiba_acpi_dev toshiba_acpi = { .bt_name = "Toshiba Bluetooth", - .rfk_name = "Toshiba RFKill Switch", - .last_rfk_state = false, }; /* Bluetooth rfkill handlers */ @@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present) return hci_result; } -static u32 hci_get_bt_on(bool *on) -{ - u32 hci_result; - u32 value, value2; - - value = 0; - value2 = 0x0001; - hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); - if (hci_result == HCI_SUCCESS) - *on = (value & HCI_WIRELESS_BT_POWER) && - (value & HCI_WIRELESS_BT_ATTACH); - - return hci_result; -} - static u32 hci_get_radio_state(bool *radio_state) { u32 hci_result; @@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state) return hci_result; } -static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state) +static int bt_rfkill_set_block(void *data, bool blocked) { + struct toshiba_acpi_dev *dev = data; u32 result1, result2; u32 value; + int err; bool radio_state; - struct toshiba_acpi_dev *dev = data; - value = (state == RFKILL_STATE_UNBLOCKED); + value = (blocked == false); - if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) - return -EFAULT; + mutex_lock(&dev->mutex); + if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) { + err = -EBUSY; + goto out; + } - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!radio_state) - return -EPERM; - break; - case RFKILL_STATE_SOFT_BLOCKED: - break; - default: - return -EINVAL; + if (!radio_state) { + err = 0; + goto out; } - mutex_lock(&dev->mutex); hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); - mutex_unlock(&dev->mutex); if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) - return -EFAULT; - - return 0; + err = -EBUSY; + else + err = 0; + out: + mutex_unlock(&dev->mutex); + return err; } -static void bt_poll_rfkill(struct input_polled_dev *poll_dev) +static void bt_rfkill_poll(struct rfkill *rfkill, void *data) { - bool state_changed; bool new_rfk_state; bool value; u32 hci_result; - struct toshiba_acpi_dev *dev = poll_dev->private; + struct toshiba_acpi_dev *dev = data; + + mutex_lock(&dev->mutex); hci_result = hci_get_radio_state(&value); - if (hci_result != HCI_SUCCESS) - return; /* Can't do anything useful */ + if (hci_result != HCI_SUCCESS) { + /* Can't do anything useful */ + mutex_unlock(&dev->mutex); + } new_rfk_state = value; - mutex_lock(&dev->mutex); - state_changed = new_rfk_state != dev->last_rfk_state; - dev->last_rfk_state = new_rfk_state; mutex_unlock(&dev->mutex); - if (unlikely(state_changed)) { - rfkill_force_state(dev->rfk_dev, - new_rfk_state ? - RFKILL_STATE_SOFT_BLOCKED : - RFKILL_STATE_HARD_BLOCKED); - input_report_switch(poll_dev->input, SW_RFKILL_ALL, - new_rfk_state); - input_sync(poll_dev->input); - } + if (rfkill_set_hw_state(rfkill, !new_rfk_state)) + bt_rfkill_set_block(data, true); } +static const struct rfkill_ops toshiba_rfk_ops = { + .set_block = bt_rfkill_set_block, + .poll = bt_rfkill_poll, +}; + static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; static struct backlight_device *toshiba_backlight_device; static int force_fan; @@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = { static void toshiba_acpi_exit(void) { - if (toshiba_acpi.poll_dev) { - input_unregister_polled_device(toshiba_acpi.poll_dev); - input_free_polled_device(toshiba_acpi.poll_dev); + if (toshiba_acpi.bt_rfk) { + rfkill_unregister(toshiba_acpi.bt_rfk); + rfkill_destroy(toshiba_acpi.bt_rfk); } - if (toshiba_acpi.rfk_dev) - rfkill_unregister(toshiba_acpi.rfk_dev); - if (toshiba_backlight_device) backlight_device_unregister(toshiba_backlight_device); @@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void) acpi_status status = AE_OK; u32 hci_result; bool bt_present; - bool bt_on; - bool radio_on; int ret = 0; if (acpi_disabled) @@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void) /* Register rfkill switch for Bluetooth */ if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { - toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev, - RFKILL_TYPE_BLUETOOTH); - if (!toshiba_acpi.rfk_dev) { + toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name, + &toshiba_acpi.p_dev->dev, + RFKILL_TYPE_BLUETOOTH, + &toshiba_rfk_ops, + &toshiba_acpi); + if (!toshiba_acpi.bt_rfk) { printk(MY_ERR "unable to allocate rfkill device\n"); toshiba_acpi_exit(); return -ENOMEM; } - toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; - toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio; - toshiba_acpi.rfk_dev->data = &toshiba_acpi; - - if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED; - } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS && - radio_on) { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED; - } else { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED; - } - - ret = rfkill_register(toshiba_acpi.rfk_dev); + ret = rfkill_register(toshiba_acpi.bt_rfk); if (ret) { printk(MY_ERR "unable to register rfkill device\n"); - toshiba_acpi_exit(); - return -ENOMEM; - } - - /* Register input device for kill switch */ - toshiba_acpi.poll_dev = input_allocate_polled_device(); - if (!toshiba_acpi.poll_dev) { - printk(MY_ERR - "unable to allocate kill-switch input device\n"); - toshiba_acpi_exit(); - return -ENOMEM; - } - toshiba_acpi.poll_dev->private = &toshiba_acpi; - toshiba_acpi.poll_dev->poll = bt_poll_rfkill; - toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */ - - toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name; - toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST; - /* Toshiba USB ID */ - toshiba_acpi.poll_dev->input->id.vendor = 0x0930; - set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit); - set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit); - input_report_switch(toshiba_acpi.poll_dev->input, - SW_RFKILL_ALL, TRUE); - input_sync(toshiba_acpi.poll_dev->input); - - ret = input_register_polled_device(toshiba_acpi.poll_dev); - if (ret) { - printk(MY_ERR - "unable to register kill-switch input device\n"); + rfkill_destroy(toshiba_acpi.bt_rfk); toshiba_acpi_exit(); return ret; } diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 3f0eaa3..7e09c5c 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -311,6 +311,7 @@ unifdef-y += ptrace.h unifdef-y += qnx4_fs.h unifdef-y += quota.h unifdef-y += random.h +unifdef-y += rfkill.h unifdef-y += irqnr.h unifdef-y += reboot.h unifdef-y += reiserfs_fs.h diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index de18ef2..090852c 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -4,6 +4,7 @@ /* * Copyright (C) 2006 - 2007 Ivo van Doorn * Copyright (C) 2007 Dmitry Torokhov + * Copyright 2009 Johannes Berg * * 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 @@ -21,6 +22,24 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* define userspace visible states */ +#define RFKILL_STATE_SOFT_BLOCKED 0 +#define RFKILL_STATE_UNBLOCKED 1 +#define RFKILL_STATE_HARD_BLOCKED 2 + +/* and that's all userspace gets */ +#ifdef __KERNEL__ +/* don't allow anyone to use these in the kernel */ +enum rfkill_user_states { + RFKILL_USER_STATE_SOFT_BLOCKED = RFKILL_STATE_SOFT_BLOCKED, + RFKILL_USER_STATE_UNBLOCKED = RFKILL_STATE_UNBLOCKED, + RFKILL_USER_STATE_HARD_BLOCKED = RFKILL_STATE_HARD_BLOCKED, +}; +#undef RFKILL_STATE_SOFT_BLOCKED +#undef RFKILL_STATE_UNBLOCKED +#undef RFKILL_STATE_HARD_BLOCKED + #include #include #include @@ -30,109 +49,267 @@ /** * enum rfkill_type - type of rfkill switch. - * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. - * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. - * RFKILL_TYPE_UWB: switch is on a ultra wideband device. - * RFKILL_TYPE_WIMAX: switch is on a WiMAX device. - * RFKILL_TYPE_WWAN: switch is on a wireless WAN device. + * + * @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. + * @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. + * @RFKILL_TYPE_UWB: switch is on a ultra wideband device. + * @RFKILL_TYPE_WIMAX: switch is on a WiMAX device. + * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device. + * @NUM_RFKILL_TYPES: number of defined rfkill types */ enum rfkill_type { - RFKILL_TYPE_WLAN , + RFKILL_TYPE_WLAN, RFKILL_TYPE_BLUETOOTH, RFKILL_TYPE_UWB, RFKILL_TYPE_WIMAX, RFKILL_TYPE_WWAN, - RFKILL_TYPE_MAX, + NUM_RFKILL_TYPES, }; -enum rfkill_state { - RFKILL_STATE_SOFT_BLOCKED = 0, /* Radio output blocked */ - RFKILL_STATE_UNBLOCKED = 1, /* Radio output allowed */ - RFKILL_STATE_HARD_BLOCKED = 2, /* Output blocked, non-overrideable */ - RFKILL_STATE_MAX, /* marker for last valid state */ +/* this is opaque */ +struct rfkill; + +/** + * struct rfkill_ops - rfkill driver methods + * + * @poll: poll the rfkill block state(s) -- only assign this method + * when you need polling. When called, simply call one of the + * rfkill_set{,_hw,_sw}_state family of functions. If the hw + * is getting unblocked you need to take into account the return + * value of those functions to make sure the software block is + * properly used. + * @query: query the rfkill block state(s) and call exactly one of the + * rfkill_set{,_hw,_sw}_state family of functions. Assign this + * method if input events can cause hardware state changes to make + * the rfkill core query your driver before setting a requested + * block. + * @set_block: turn the transmitter on (blocked == false) or off + * (blocked == true) -- this is called only while the transmitter + * is not hard-blocked, but note that the core's view of whether + * the transmitter is hard-blocked might differ from your driver's + * view due to race conditions, so it is possible that it is still + * called at the same time as you are calling rfkill_set_hw_state(). + * This callback must be assigned. + */ +struct rfkill_ops { + void (*poll)(struct rfkill *rfkill, void *data); + void (*query)(struct rfkill *rfkill, void *data); + int (*set_block)(void *data, bool blocked); }; +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /** - * struct rfkill - rfkill control structure. - * @name: Name of the switch. - * @type: Radio type which the button controls, the value stored - * here should be a value from enum rfkill_type. - * @state: State of the switch, "UNBLOCKED" means radio can operate. - * @mutex: Guards switch state transitions. It serializes callbacks - * and also protects the state. - * @data: Pointer to the RF button drivers private data which will be - * passed along when toggling radio state. - * @toggle_radio(): Mandatory handler to control state of the radio. - * only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are - * valid parameters. - * @get_state(): handler to read current radio state from hardware, - * may be called from atomic context, should return 0 on success. - * Either this handler OR judicious use of rfkill_force_state() is - * MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED. - * @led_trigger: A LED trigger for this button's LED. - * @dev: Device structure integrating the switch into device tree. - * @node: Used to place switch into list of all switches known to the - * the system. - * - * This structure represents a RF switch located on a network device. + * rfkill_alloc - allocate rfkill structure + * @name: name of the struct -- the string is not copied internally + * @parent: device that has rf switch on it + * @type: type of the switch (RFKILL_TYPE_*) + * @ops: rfkill methods + * @ops_data: data passed to each method + * + * This function should be called by the transmitter driver to allocate an + * rfkill structure. Returns %NULL on failure. */ -struct rfkill { - const char *name; - enum rfkill_type type; - - /* the mutex serializes callbacks and also protects - * the state */ - struct mutex mutex; - enum rfkill_state state; - void *data; - int (*toggle_radio)(void *data, enum rfkill_state state); - int (*get_state)(void *data, enum rfkill_state *state); +struct rfkill * __must_check rfkill_alloc(const char *name, + struct device *parent, + const enum rfkill_type type, + const struct rfkill_ops *ops, + void *ops_data); -#ifdef CONFIG_RFKILL_LEDS - struct led_trigger led_trigger; -#endif +/** + * rfkill_register - Register a rfkill structure. + * @rfkill: rfkill structure to be registered + * + * This function should be called by the transmitter driver to register + * the rfkill structure needs to be registered. Before calling this function + * the driver needs to be ready to service method calls from rfkill. + */ +int __must_check rfkill_register(struct rfkill *rfkill); - struct device dev; - struct list_head node; - enum rfkill_state state_for_resume; -}; -#define to_rfkill(d) container_of(d, struct rfkill, dev) +/** + * rfkill_pause_polling(struct rfkill *rfkill) + * + * Pause polling -- say transmitter is off for other reasons. + * NOTE: not necessary for suspend/resume -- in that case the + * core stops polling anyway + */ +void rfkill_pause_polling(struct rfkill *rfkill); -struct rfkill * __must_check rfkill_allocate(struct device *parent, - enum rfkill_type type); -void rfkill_free(struct rfkill *rfkill); -int __must_check rfkill_register(struct rfkill *rfkill); +/** + * rfkill_resume_polling(struct rfkill *rfkill) + * + * Pause polling -- say transmitter is off for other reasons. + * NOTE: not necessary for suspend/resume -- in that case the + * core stops polling anyway + */ +void rfkill_resume_polling(struct rfkill *rfkill); + + +/** + * rfkill_unregister - Unregister a rfkill structure. + * @rfkill: rfkill structure to be unregistered + * + * This function should be called by the network driver during device + * teardown to destroy rfkill structure. Until it returns, the driver + * needs to be able to service method calls. + */ void rfkill_unregister(struct rfkill *rfkill); -int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state); -int rfkill_set_default(enum rfkill_type type, enum rfkill_state state); +/** + * rfkill_destroy - free rfkill structure + * @rfkill: rfkill structure to be destroyed + * + * Destroys the rfkill structure. + */ +void rfkill_destroy(struct rfkill *rfkill); + +/** + * rfkill_set_hw_state - Set the internal rfkill hardware block state + * @rfkill: pointer to the rfkill class to modify. + * @state: the current hardware block state to set + * + * rfkill drivers that get events when the hard-blocked state changes + * use this function to notify the rfkill core (and through that also + * userspace) of the current state -- they should also use this after + * resume if the state could have changed. + * + * You need not (but may) call this function if poll_state is assigned. + * + * This function can be called in any context, even from within rfkill + * callbacks. + * + * The function returns the combined block state (true if transmitter + * should be blocked) so that drivers need not keep track of the soft + * block state -- which they might not be able to. + */ +bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked); + +/** + * rfkill_set_sw_state - Set the internal rfkill software block state + * @rfkill: pointer to the rfkill class to modify. + * @state: the current software block state to set + * + * rfkill drivers that get events when the soft-blocked state changes + * (yes, some platforms directly act on input but allow changing again) + * use this function to notify the rfkill core (and through that also + * userspace) of the current state -- they should also use this after + * resume if the state could have changed. + * + * This function can be called in any context, even from within rfkill + * callbacks. + * + * The function returns the combined block state (true if transmitter + * should be blocked). + */ +bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked); + +/** + * rfkill_set_states - Set the internal rfkill block states + * @rfkill: pointer to the rfkill class to modify. + * @sw: the current software block state to set + * @hw: the current hardware block state to set + * + * This function can be called in any context, even from within rfkill + * callbacks. + */ +void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw); /** - * rfkill_state_complement - return complementar state - * @state: state to return the complement of + * rfkill_set_global_sw_state - set global sw block default + * @type: rfkill type to set default for + * @blocked: default to set * - * Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED, - * returns RFKILL_STATE_UNBLOCKED otherwise. + * This function sets the global default -- use at boot if your platform has + * an rfkill switch. If not early enough this call may be ignored. + * + * XXX: instead of ignoring -- how about just updating all currently + * registered drivers? */ -static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state) +void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked); +#else /* !RFKILL */ +static inline struct rfkill * __must_check +rfkill_alloc(const char *name, + struct device *parent, + const enum rfkill_type type, + const struct rfkill_ops *ops, + void *ops_data) +{ + return ERR_PTR(-ENODEV); +} + +static inline int __must_check rfkill_register(struct rfkill *rfkill) +{ + if (rfkill == ERR_PTR(-ENODEV)) + return 0; + return -EINVAL; +} + +static inline void rfkill_pause_polling(struct rfkill *rfkill) +{ +} + +static inline void rfkill_resume_polling(struct rfkill *rfkill) +{ +} + +static inline void rfkill_unregister(struct rfkill *rfkill) +{ +} + +static inline void rfkill_destroy(struct rfkill *rfkill) +{ +} + +static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) +{ + return blocked; +} + +static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) +{ + return blocked; +} + +static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) +{ +} + +static inline void rfkill_set_global_sw_state(const enum rfkill_type type, + bool blocked) { - return (state == RFKILL_STATE_UNBLOCKED) ? - RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; } +#endif /* RFKILL || RFKILL_MODULE */ + +#ifdef CONFIG_RFKILL_LEDS /** - * rfkill_get_led_name - Get the LED trigger name for the button's LED. + * rfkill_get_led_trigger_name - Get the LED trigger name for the button's LED. * This function might return a NULL pointer if registering of the - * LED trigger failed. - * Use this as "default_trigger" for the LED. + * LED trigger failed. Use this as "default_trigger" for the LED. */ -static inline char *rfkill_get_led_name(struct rfkill *rfkill) -{ -#ifdef CONFIG_RFKILL_LEDS - return (char *)(rfkill->led_trigger.name); +const char *rfkill_get_led_trigger_name(struct rfkill *rfkill); + +/** + * rfkill_set_led_trigger_name -- set the LED trigger name + * @rfkill: rfkill struct + * @name: LED trigger name + * + * This function sets the LED trigger name of the radio LED + * trigger that rfkill creates. It is optional, but if called + * must be called before rfkill_register() to be effective. + */ +void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name); #else +static inline const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) +{ return NULL; -#endif } +static inline void +rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) +{ +} +#endif + +#endif /* __KERNEL__ */ + #endif /* RFKILL_H */ diff --git a/include/net/wimax.h b/include/net/wimax.h index 6b3824e..2af7bf8 100644 --- a/include/net/wimax.h +++ b/include/net/wimax.h @@ -253,7 +253,6 @@ struct net_device; struct genl_info; struct wimax_dev; -struct input_dev; /** * struct wimax_dev - Generic WiMAX device @@ -293,8 +292,8 @@ struct input_dev; * See wimax_reset()'s documentation. * * @name: [fill] A way to identify this device. We need to register a - * name with many subsystems (input for RFKILL, workqueue - * creation, etc). We can't use the network device name as that + * name with many subsystems (rfkill, workqueue creation, etc). + * We can't use the network device name as that * might change and in some instances we don't know it yet (until * we don't call register_netdev()). So we generate an unique one * using the driver name and device bus id, place it here and use @@ -316,9 +315,6 @@ struct input_dev; * * @rfkill: [private] integration into the RF-Kill infrastructure. * - * @rfkill_input: [private] virtual input device to process the - * hardware RF Kill switches. - * * @rf_sw: [private] State of the software radio switch (OFF/ON) * * @rf_hw: [private] State of the hardware radio switch (OFF/ON) diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index 7f807b3..b47f72f 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -10,22 +10,15 @@ menuconfig RFKILL To compile this driver as a module, choose M here: the module will be called rfkill. -config RFKILL_INPUT - tristate "Input layer to RF switch connector" - depends on RFKILL && INPUT - help - Say Y here if you want kernel automatically toggle state - of RF switches on and off when user presses appropriate - button or a key on the keyboard. Without this module you - need a some kind of userspace application to control - state of the switches. - - To compile this driver as a module, choose M here: the - module will be called rfkill-input. - # LED trigger support config RFKILL_LEDS bool - depends on RFKILL && LEDS_TRIGGERS + depends on RFKILL + depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS default y +config RFKILL_INPUT + bool + depends on RFKILL + depends on INPUT = y || RFKILL = INPUT + default y diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile index b38c430..6621053 100644 --- a/net/rfkill/Makefile +++ b/net/rfkill/Makefile @@ -2,5 +2,6 @@ # Makefile for the RF switch subsystem. # -obj-$(CONFIG_RFKILL) += rfkill.o -obj-$(CONFIG_RFKILL_INPUT) += rfkill-input.o +rfkill-y += core.o +rfkill-$(CONFIG_RFKILL_INPUT) += input.o +obj-$(CONFIG_RFKILL) += rfkill.o diff --git a/net/rfkill/core.c b/net/rfkill/core.c new file mode 100644 index 0000000..30a6f8d --- /dev/null +++ b/net/rfkill/core.c @@ -0,0 +1,896 @@ +/* + * Copyright (C) 2006 - 2007 Ivo van Doorn + * Copyright (C) 2007 Dmitry Torokhov + * Copyright 2009 Johannes Berg + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rfkill.h" + +#define POLL_INTERVAL (5 * HZ) + +#define RFKILL_BLOCK_HW BIT(0) +#define RFKILL_BLOCK_SW BIT(1) +#define RFKILL_BLOCK_SW_PREV BIT(2) +#define RFKILL_BLOCK_ANY (RFKILL_BLOCK_HW |\ + RFKILL_BLOCK_SW |\ + RFKILL_BLOCK_SW_PREV) +#define RFKILL_BLOCK_SW_SETCALL BIT(31) + +struct rfkill { + spinlock_t lock; + + const char *name; + enum rfkill_type type; + + unsigned long state; + + bool registered; + bool suspended; + + const struct rfkill_ops *ops; + void *data; + +#ifdef CONFIG_RFKILL_LEDS + struct led_trigger led_trigger; + const char *ledtrigname; +#endif + + struct device dev; + struct list_head node; + + struct delayed_work poll_work; + struct work_struct uevent_work; + struct work_struct sync_work; +}; +#define to_rfkill(d) container_of(d, struct rfkill, dev) + + + +MODULE_AUTHOR("Ivo van Doorn "); +MODULE_AUTHOR("Johannes Berg "); +MODULE_DESCRIPTION("RF switch support"); +MODULE_LICENSE("GPL"); + + +/* + * The locking here should be made much smarter, we currently have + * a bit of a stupid situation because drivers might want to register + * the rfkill struct under their own lock, and take this lock during + * rfkill method calls -- which will cause an AB-BA deadlock situation. + * + * To fix that, we need to rework this code here to be mostly lock-free + * and only use the mutex for list manipulations, not to protect the + * various other global variables. Then we can avoid holding the mutex + * around driver operations, and all is happy. + */ +static LIST_HEAD(rfkill_list); /* list of registered rf switches */ +static DEFINE_MUTEX(rfkill_global_mutex); + +static unsigned int rfkill_default_state = 1; +module_param_named(default_state, rfkill_default_state, uint, 0444); +MODULE_PARM_DESC(default_state, + "Default initial state for all radio types, 0 = radio off"); + +static struct { + bool cur, def; +} rfkill_global_states[NUM_RFKILL_TYPES]; + +static unsigned long rfkill_states_default_locked; + +static bool rfkill_epo_lock_active; + + +#ifdef CONFIG_RFKILL_LEDS +static void rfkill_led_trigger_event(struct rfkill *rfkill) +{ + struct led_trigger *trigger; + + if (!rfkill->registered) + return; + + trigger = &rfkill->led_trigger; + + if (rfkill->state & RFKILL_BLOCK_ANY) + led_trigger_event(trigger, LED_OFF); + else + led_trigger_event(trigger, LED_FULL); +} + +static void rfkill_led_trigger_activate(struct led_classdev *led) +{ + struct rfkill *rfkill; + + rfkill = container_of(led->trigger, struct rfkill, led_trigger); + + rfkill_led_trigger_event(rfkill); +} + +const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) +{ + return rfkill->led_trigger.name; +} +EXPORT_SYMBOL(rfkill_get_led_trigger_name); + +void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) +{ + BUG_ON(!rfkill); + + rfkill->ledtrigname = name; +} +EXPORT_SYMBOL(rfkill_set_led_trigger_name); + +static int rfkill_led_trigger_register(struct rfkill *rfkill) +{ + rfkill->led_trigger.name = rfkill->ledtrigname + ? : dev_name(&rfkill->dev); + rfkill->led_trigger.activate = rfkill_led_trigger_activate; + return led_trigger_register(&rfkill->led_trigger); +} + +static void rfkill_led_trigger_unregister(struct rfkill *rfkill) +{ + led_trigger_unregister(&rfkill->led_trigger); +} +#else +static void rfkill_led_trigger_event(struct rfkill *rfkill) +{ +} + +static inline int rfkill_led_trigger_register(struct rfkill *rfkill) +{ + return 0; +} + +static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill) +{ +} +#endif /* CONFIG_RFKILL_LEDS */ + +static void rfkill_uevent(struct rfkill *rfkill) +{ + if (!rfkill->registered || rfkill->suspended) + return; + + kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); +} + +static bool __rfkill_set_hw_state(struct rfkill *rfkill, + bool blocked, bool *change) +{ + unsigned long flags; + bool prev, any; + + BUG_ON(!rfkill); + + spin_lock_irqsave(&rfkill->lock, flags); + prev = !!(rfkill->state & RFKILL_BLOCK_HW); + if (blocked) + rfkill->state |= RFKILL_BLOCK_HW; + else + rfkill->state &= ~RFKILL_BLOCK_HW; + *change = prev != blocked; + any = rfkill->state & RFKILL_BLOCK_ANY; + spin_unlock_irqrestore(&rfkill->lock, flags); + + rfkill_led_trigger_event(rfkill); + + return any; +} + +/** + * rfkill_set_block - wrapper for set_block method + * + * @rfkill: the rfkill struct to use + * @blocked: the new software state + * + * Calls the set_block method (when applicable) and handles notifications + * etc. as well. + */ +static void rfkill_set_block(struct rfkill *rfkill, bool blocked) +{ + unsigned long flags; + int err; + + /* + * Some platforms (...!) generate input events which affect the + * _hard_ kill state -- whenever something tries to change the + * current software state query the hardware state too. + */ + if (rfkill->ops->query) + rfkill->ops->query(rfkill, rfkill->data); + + spin_lock_irqsave(&rfkill->lock, flags); + if (rfkill->state & RFKILL_BLOCK_SW) + rfkill->state |= RFKILL_BLOCK_SW_PREV; + else + rfkill->state &= ~RFKILL_BLOCK_SW_PREV; + + if (blocked) + rfkill->state |= RFKILL_BLOCK_SW; + else + rfkill->state &= ~RFKILL_BLOCK_SW; + + rfkill->state |= RFKILL_BLOCK_SW_SETCALL; + spin_unlock_irqrestore(&rfkill->lock, flags); + + if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) + return; + + err = rfkill->ops->set_block(rfkill->data, blocked); + + spin_lock_irqsave(&rfkill->lock, flags); + if (err) { + /* + * Failed -- reset status to _prev, this may be different + * from what set set _PREV to earlier in this function + * if rfkill_set_sw_state was invoked. + */ + if (rfkill->state & RFKILL_BLOCK_SW_PREV) + rfkill->state |= RFKILL_BLOCK_SW; + else + rfkill->state &= ~RFKILL_BLOCK_SW; + } + rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; + rfkill->state &= ~RFKILL_BLOCK_SW_PREV; + spin_unlock_irqrestore(&rfkill->lock, flags); + + rfkill_led_trigger_event(rfkill); + rfkill_uevent(rfkill); +} + +/** + * __rfkill_switch_all - Toggle state of all switches of given type + * @type: type of interfaces to be affected + * @state: the new state + * + * This function sets the state of all switches of given type, + * unless a specific switch is claimed by userspace (in which case, + * that switch is left alone) or suspended. + * + * Caller must have acquired rfkill_global_mutex. + */ +static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) +{ + struct rfkill *rfkill; + + rfkill_global_states[type].cur = blocked; + list_for_each_entry(rfkill, &rfkill_list, node) { + if (rfkill->type != type) + continue; + + rfkill_set_block(rfkill, blocked); + } +} + +/** + * rfkill_switch_all - Toggle state of all switches of given type + * @type: type of interfaces to be affected + * @state: the new state + * + * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). + * Please refer to __rfkill_switch_all() for details. + * + * Does nothing if the EPO lock is active. + */ +void rfkill_switch_all(enum rfkill_type type, bool blocked) +{ + mutex_lock(&rfkill_global_mutex); + + if (!rfkill_epo_lock_active) + __rfkill_switch_all(type, blocked); + + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_epo - emergency power off all transmitters + * + * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, + * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. + * + * The global state before the EPO is saved and can be restored later + * using rfkill_restore_states(). + */ +void rfkill_epo(void) +{ + struct rfkill *rfkill; + int i; + + mutex_lock(&rfkill_global_mutex); + + rfkill_epo_lock_active = true; + list_for_each_entry(rfkill, &rfkill_list, node) + rfkill_set_block(rfkill, true); + + for (i = 0; i < NUM_RFKILL_TYPES; i++) { + rfkill_global_states[i].def = rfkill_global_states[i].cur; + rfkill_global_states[i].cur = true; + } + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_restore_states - restore global states + * + * Restore (and sync switches to) the global state from the + * states in rfkill_default_states. This can undo the effects of + * a call to rfkill_epo(). + */ +void rfkill_restore_states(void) +{ + int i; + + mutex_lock(&rfkill_global_mutex); + + rfkill_epo_lock_active = false; + for (i = 0; i < NUM_RFKILL_TYPES; i++) + __rfkill_switch_all(i, rfkill_global_states[i].def); + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_remove_epo_lock - unlock state changes + * + * Used by rfkill-input manually unlock state changes, when + * the EPO switch is deactivated. + */ +void rfkill_remove_epo_lock(void) +{ + mutex_lock(&rfkill_global_mutex); + rfkill_epo_lock_active = false; + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_is_epo_lock_active - returns true EPO is active + * + * Returns 0 (false) if there is NOT an active EPO contidion, + * and 1 (true) if there is an active EPO contition, which + * locks all radios in one of the BLOCKED states. + * + * Can be called in atomic context. + */ +bool rfkill_is_epo_lock_active(void) +{ + return rfkill_epo_lock_active; +} + +/** + * rfkill_get_global_sw_state - returns global state for a type + * @type: the type to get the global state of + * + * Returns the current global state for a given wireless + * device type. + */ +bool rfkill_get_global_sw_state(const enum rfkill_type type) +{ + return rfkill_global_states[type].cur; +} + +void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked) +{ + mutex_lock(&rfkill_global_mutex); + + /* don't allow unblock when epo */ + if (rfkill_epo_lock_active && !blocked) + goto out; + + /* too late */ + if (rfkill_states_default_locked & BIT(type)) + goto out; + + rfkill_states_default_locked |= BIT(type); + + rfkill_global_states[type].cur = blocked; + rfkill_global_states[type].def = blocked; + out: + mutex_unlock(&rfkill_global_mutex); +} +EXPORT_SYMBOL(rfkill_set_global_sw_state); + + +bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) +{ + bool ret, change; + + ret = __rfkill_set_hw_state(rfkill, blocked, &change); + + if (!rfkill->registered) + return ret; + + if (change) + schedule_work(&rfkill->uevent_work); + + return ret; +} +EXPORT_SYMBOL(rfkill_set_hw_state); + +static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) +{ + u32 bit = RFKILL_BLOCK_SW; + + /* if in a ops->set_block right now, use other bit */ + if (rfkill->state & RFKILL_BLOCK_SW_SETCALL) + bit = RFKILL_BLOCK_SW_PREV; + + if (blocked) + rfkill->state |= bit; + else + rfkill->state &= ~bit; +} + +bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) +{ + unsigned long flags; + bool prev, hwblock; + + BUG_ON(!rfkill); + + spin_lock_irqsave(&rfkill->lock, flags); + prev = !!(rfkill->state & RFKILL_BLOCK_SW); + __rfkill_set_sw_state(rfkill, blocked); + hwblock = !!(rfkill->state & RFKILL_BLOCK_HW); + blocked = blocked || hwblock; + spin_unlock_irqrestore(&rfkill->lock, flags); + + if (!rfkill->registered) + return blocked; + + if (prev != blocked && !hwblock) + schedule_work(&rfkill->uevent_work); + + rfkill_led_trigger_event(rfkill); + + return blocked; +} +EXPORT_SYMBOL(rfkill_set_sw_state); + +void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) +{ + unsigned long flags; + bool swprev, hwprev; + + BUG_ON(!rfkill); + + spin_lock_irqsave(&rfkill->lock, flags); + + /* + * No need to care about prev/setblock ... this is for uevent only + * and that will get triggered by rfkill_set_block anyway. + */ + swprev = !!(rfkill->state & RFKILL_BLOCK_SW); + hwprev = !!(rfkill->state & RFKILL_BLOCK_HW); + __rfkill_set_sw_state(rfkill, sw); + + spin_unlock_irqrestore(&rfkill->lock, flags); + + if (!rfkill->registered) + return; + + if (swprev != sw || hwprev != hw) + schedule_work(&rfkill->uevent_work); + + rfkill_led_trigger_event(rfkill); +} +EXPORT_SYMBOL(rfkill_set_states); + +static ssize_t rfkill_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + + return sprintf(buf, "%s\n", rfkill->name); +} + +static const char *rfkill_get_type_str(enum rfkill_type type) +{ + switch (type) { + case RFKILL_TYPE_WLAN: + return "wlan"; + case RFKILL_TYPE_BLUETOOTH: + return "bluetooth"; + case RFKILL_TYPE_UWB: + return "ultrawideband"; + case RFKILL_TYPE_WIMAX: + return "wimax"; + case RFKILL_TYPE_WWAN: + return "wwan"; + default: + BUG(); + } + + BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1); +} + +static ssize_t rfkill_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + + return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); +} + +static u8 user_state_from_blocked(unsigned long state) +{ + if (state & RFKILL_BLOCK_HW) + return RFKILL_USER_STATE_HARD_BLOCKED; + if (state & RFKILL_BLOCK_SW) + return RFKILL_USER_STATE_SOFT_BLOCKED; + + return RFKILL_USER_STATE_UNBLOCKED; +} + +static ssize_t rfkill_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + unsigned long flags; + u32 state; + + spin_lock_irqsave(&rfkill->lock, flags); + state = rfkill->state; + spin_unlock_irqrestore(&rfkill->lock, flags); + + return sprintf(buf, "%d\n", user_state_from_blocked(state)); +} + +static ssize_t rfkill_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + /* + * The intention was that userspace can only take control over + * a given device when/if rfkill-input doesn't control it due + * to user_claim. Since user_claim is currently unsupported, + * we never support changing the state from userspace -- this + * can be implemented again later. + */ + + return -EPERM; +} + +static ssize_t rfkill_claim_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", 0); +} + +static ssize_t rfkill_claim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return -EOPNOTSUPP; +} + +static struct device_attribute rfkill_dev_attrs[] = { + __ATTR(name, S_IRUGO, rfkill_name_show, NULL), + __ATTR(type, S_IRUGO, rfkill_type_show, NULL), + __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), + __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), + __ATTR_NULL +}; + +static void rfkill_release(struct device *dev) +{ + struct rfkill *rfkill = to_rfkill(dev); + + kfree(rfkill); +} + +static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct rfkill *rfkill = to_rfkill(dev); + unsigned long flags; + u32 state; + int error; + + error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); + if (error) + return error; + error = add_uevent_var(env, "RFKILL_TYPE=%s", + rfkill_get_type_str(rfkill->type)); + if (error) + return error; + spin_lock_irqsave(&rfkill->lock, flags); + state = rfkill->state; + spin_unlock_irqrestore(&rfkill->lock, flags); + error = add_uevent_var(env, "RFKILL_STATE=%d", + user_state_from_blocked(state)); + return error; +} + +void rfkill_pause_polling(struct rfkill *rfkill) +{ + BUG_ON(!rfkill); + + if (!rfkill->ops->poll) + return; + + cancel_delayed_work_sync(&rfkill->poll_work); +} +EXPORT_SYMBOL(rfkill_pause_polling); + +void rfkill_resume_polling(struct rfkill *rfkill) +{ + BUG_ON(!rfkill); + + if (!rfkill->ops->poll) + return; + + schedule_work(&rfkill->poll_work.work); +} +EXPORT_SYMBOL(rfkill_resume_polling); + +static int rfkill_suspend(struct device *dev, pm_message_t state) +{ + struct rfkill *rfkill = to_rfkill(dev); + + rfkill_pause_polling(rfkill); + + rfkill->suspended = true; + + return 0; +} + +static int rfkill_resume(struct device *dev) +{ + struct rfkill *rfkill = to_rfkill(dev); + bool cur; + + mutex_lock(&rfkill_global_mutex); + cur = rfkill_global_states[rfkill->type].cur; + rfkill_set_block(rfkill, cur); + mutex_unlock(&rfkill_global_mutex); + + rfkill->suspended = false; + + schedule_work(&rfkill->uevent_work); + + rfkill_resume_polling(rfkill); + + return 0; +} + +static struct class rfkill_class = { + .name = "rfkill", + .dev_release = rfkill_release, + .dev_attrs = rfkill_dev_attrs, + .dev_uevent = rfkill_dev_uevent, + .suspend = rfkill_suspend, + .resume = rfkill_resume, +}; + + +struct rfkill * __must_check rfkill_alloc(const char *name, + struct device *parent, + const enum rfkill_type type, + const struct rfkill_ops *ops, + void *ops_data) +{ + struct rfkill *rfkill; + struct device *dev; + + if (WARN_ON(!ops)) + return NULL; + + if (WARN_ON(!ops->set_block)) + return NULL; + + if (WARN_ON(!name)) + return NULL; + + if (WARN_ON(type >= NUM_RFKILL_TYPES)) + return NULL; + + rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); + if (!rfkill) + return NULL; + + spin_lock_init(&rfkill->lock); + INIT_LIST_HEAD(&rfkill->node); + rfkill->type = type; + rfkill->name = name; + rfkill->ops = ops; + rfkill->data = ops_data; + + dev = &rfkill->dev; + dev->class = &rfkill_class; + dev->parent = parent; + device_initialize(dev); + + return rfkill; +} +EXPORT_SYMBOL(rfkill_alloc); + +static void rfkill_poll(struct work_struct *work) +{ + struct rfkill *rfkill; + + rfkill = container_of(work, struct rfkill, poll_work.work); + + /* + * Poll hardware state -- driver will use one of the + * rfkill_set{,_hw,_sw}_state functions and use its + * return value to update the current status. + */ + rfkill->ops->poll(rfkill, rfkill->data); + + schedule_delayed_work(&rfkill->poll_work, + round_jiffies_relative(POLL_INTERVAL)); +} + +static void rfkill_uevent_work(struct work_struct *work) +{ + struct rfkill *rfkill; + + rfkill = container_of(work, struct rfkill, uevent_work); + + rfkill_uevent(rfkill); +} + +static void rfkill_sync_work(struct work_struct *work) +{ + struct rfkill *rfkill; + bool cur; + + rfkill = container_of(work, struct rfkill, sync_work); + + mutex_lock(&rfkill_global_mutex); + cur = rfkill_global_states[rfkill->type].cur; + rfkill_set_block(rfkill, cur); + mutex_unlock(&rfkill_global_mutex); +} + +int __must_check rfkill_register(struct rfkill *rfkill) +{ + static unsigned long rfkill_no; + struct device *dev = &rfkill->dev; + int error; + + BUG_ON(!rfkill); + + mutex_lock(&rfkill_global_mutex); + + if (rfkill->registered) { + error = -EALREADY; + goto unlock; + } + + dev_set_name(dev, "rfkill%lu", rfkill_no); + rfkill_no++; + + if (!(rfkill_states_default_locked & BIT(rfkill->type))) { + /* first of its kind */ + BUILD_BUG_ON(NUM_RFKILL_TYPES > + sizeof(rfkill_states_default_locked) * 8); + rfkill_states_default_locked |= BIT(rfkill->type); + rfkill_global_states[rfkill->type].cur = + rfkill_global_states[rfkill->type].def; + } + + list_add_tail(&rfkill->node, &rfkill_list); + + error = device_add(dev); + if (error) + goto remove; + + error = rfkill_led_trigger_register(rfkill); + if (error) + goto devdel; + + rfkill->registered = true; + + if (rfkill->ops->poll) { + INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); + schedule_delayed_work(&rfkill->poll_work, + round_jiffies_relative(POLL_INTERVAL)); + } + + INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work); + + INIT_WORK(&rfkill->sync_work, rfkill_sync_work); + schedule_work(&rfkill->sync_work); + + mutex_unlock(&rfkill_global_mutex); + return 0; + + devdel: + device_del(&rfkill->dev); + remove: + list_del_init(&rfkill->node); + unlock: + mutex_unlock(&rfkill_global_mutex); + return error; +} +EXPORT_SYMBOL(rfkill_register); + +void rfkill_unregister(struct rfkill *rfkill) +{ + BUG_ON(!rfkill); + + if (rfkill->ops->poll) + cancel_delayed_work_sync(&rfkill->poll_work); + + cancel_work_sync(&rfkill->uevent_work); + cancel_work_sync(&rfkill->sync_work); + + rfkill->registered = false; + + device_del(&rfkill->dev); + + mutex_lock(&rfkill_global_mutex); + list_del_init(&rfkill->node); + mutex_unlock(&rfkill_global_mutex); + + rfkill_led_trigger_unregister(rfkill); +} +EXPORT_SYMBOL(rfkill_unregister); + +void rfkill_destroy(struct rfkill *rfkill) +{ + if (rfkill) + put_device(&rfkill->dev); +} +EXPORT_SYMBOL(rfkill_destroy); + + +static int __init rfkill_init(void) +{ + int error; + int i; + + for (i = 0; i < NUM_RFKILL_TYPES; i++) + rfkill_global_states[i].def = !rfkill_default_state; + + error = class_register(&rfkill_class); + if (error) + goto out; + +#ifdef CONFIG_RFKILL_INPUT + error = rfkill_handler_init(); + if (error) + class_unregister(&rfkill_class); +#endif + + out: + return error; +} +subsys_initcall(rfkill_init); + +static void __exit rfkill_exit(void) +{ +#ifdef CONFIG_RFKILL_INPUT + rfkill_handler_exit(); +#endif + class_unregister(&rfkill_class); +} +module_exit(rfkill_exit); diff --git a/net/rfkill/input.c b/net/rfkill/input.c new file mode 100644 index 0000000..a7295ad --- /dev/null +++ b/net/rfkill/input.c @@ -0,0 +1,342 @@ +/* + * Input layer to RF Kill interface connector + * + * Copyright (c) 2007 Dmitry Torokhov + * Copyright 2009 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * If you ever run into a situation in which you have a SW_ type rfkill + * input device, then you can revive code that was removed in the patch + * "rfkill-input: remove unused code". + */ + +#include +#include +#include +#include +#include +#include + +#include "rfkill.h" + +enum rfkill_input_master_mode { + RFKILL_INPUT_MASTER_UNLOCK = 0, + RFKILL_INPUT_MASTER_RESTORE = 1, + RFKILL_INPUT_MASTER_UNBLOCKALL = 2, + NUM_RFKILL_INPUT_MASTER_MODES +}; + +/* Delay (in ms) between consecutive switch ops */ +#define RFKILL_OPS_DELAY 200 + +static enum rfkill_input_master_mode rfkill_master_switch_mode = + RFKILL_INPUT_MASTER_UNBLOCKALL; +module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); +MODULE_PARM_DESC(master_switch_mode, + "SW_RFKILL_ALL ON should: 0=do nothing (only unlock); 1=restore; 2=unblock all"); + +static spinlock_t rfkill_op_lock; +static bool rfkill_op_pending; +static unsigned long rfkill_sw_pending[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; +static unsigned long rfkill_sw_state[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; + +enum rfkill_sched_op { + RFKILL_GLOBAL_OP_EPO = 0, + RFKILL_GLOBAL_OP_RESTORE, + RFKILL_GLOBAL_OP_UNLOCK, + RFKILL_GLOBAL_OP_UNBLOCK, +}; + +static enum rfkill_sched_op rfkill_master_switch_op; +static enum rfkill_sched_op rfkill_op; + +static void __rfkill_handle_global_op(enum rfkill_sched_op op) +{ + unsigned int i; + + switch (op) { + case RFKILL_GLOBAL_OP_EPO: + rfkill_epo(); + break; + case RFKILL_GLOBAL_OP_RESTORE: + rfkill_restore_states(); + break; + case RFKILL_GLOBAL_OP_UNLOCK: + rfkill_remove_epo_lock(); + break; + case RFKILL_GLOBAL_OP_UNBLOCK: + rfkill_remove_epo_lock(); + for (i = 0; i < NUM_RFKILL_TYPES; i++) + rfkill_switch_all(i, false); + break; + default: + /* memory corruption or bug, fail safely */ + rfkill_epo(); + WARN(1, "Unknown requested operation %d! " + "rfkill Emergency Power Off activated\n", + op); + } +} + +static void __rfkill_handle_normal_op(const enum rfkill_type type, + const bool complement) +{ + bool blocked; + + blocked = rfkill_get_global_sw_state(type); + if (complement) + blocked = !blocked; + + rfkill_switch_all(type, blocked); +} + +static void rfkill_op_handler(struct work_struct *work) +{ + unsigned int i; + bool c; + + spin_lock_irq(&rfkill_op_lock); + do { + if (rfkill_op_pending) { + enum rfkill_sched_op op = rfkill_op; + rfkill_op_pending = false; + memset(rfkill_sw_pending, 0, + sizeof(rfkill_sw_pending)); + spin_unlock_irq(&rfkill_op_lock); + + __rfkill_handle_global_op(op); + + spin_lock_irq(&rfkill_op_lock); + + /* + * handle global ops first -- during unlocked period + * we might have gotten a new global op. + */ + if (rfkill_op_pending) + continue; + } + + if (rfkill_is_epo_lock_active()) + continue; + + for (i = 0; i < NUM_RFKILL_TYPES; i++) { + if (__test_and_clear_bit(i, rfkill_sw_pending)) { + c = __test_and_clear_bit(i, rfkill_sw_state); + spin_unlock_irq(&rfkill_op_lock); + + __rfkill_handle_normal_op(i, c); + + spin_lock_irq(&rfkill_op_lock); + } + } + } while (rfkill_op_pending); + spin_unlock_irq(&rfkill_op_lock); +} + +static DECLARE_DELAYED_WORK(rfkill_op_work, rfkill_op_handler); +static unsigned long rfkill_last_scheduled; + +static unsigned long rfkill_ratelimit(const unsigned long last) +{ + const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); + return (time_after(jiffies, last + delay)) ? 0 : delay; +} + +static void rfkill_schedule_ratelimited(void) +{ + if (delayed_work_pending(&rfkill_op_work)) + return; + schedule_delayed_work(&rfkill_op_work, + rfkill_ratelimit(rfkill_last_scheduled)); + rfkill_last_scheduled = jiffies; +} + +static void rfkill_schedule_global_op(enum rfkill_sched_op op) +{ + unsigned long flags; + + spin_lock_irqsave(&rfkill_op_lock, flags); + rfkill_op = op; + rfkill_op_pending = true; + if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { + /* bypass the limiter for EPO */ + cancel_delayed_work(&rfkill_op_work); + schedule_delayed_work(&rfkill_op_work, 0); + rfkill_last_scheduled = jiffies; + } else + rfkill_schedule_ratelimited(); + spin_unlock_irqrestore(&rfkill_op_lock, flags); +} + +static void rfkill_schedule_toggle(enum rfkill_type type) +{ + unsigned long flags; + + if (rfkill_is_epo_lock_active()) + return; + + spin_lock_irqsave(&rfkill_op_lock, flags); + if (!rfkill_op_pending) { + __set_bit(type, rfkill_sw_pending); + __change_bit(type, rfkill_sw_state); + rfkill_schedule_ratelimited(); + } + spin_unlock_irqrestore(&rfkill_op_lock, flags); +} + +static void rfkill_schedule_evsw_rfkillall(int state) +{ + if (state) + rfkill_schedule_global_op(rfkill_master_switch_op); + else + rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); +} + +static void rfkill_event(struct input_handle *handle, unsigned int type, + unsigned int code, int data) +{ + if (type == EV_KEY && data == 1) { + switch (code) { + case KEY_WLAN: + rfkill_schedule_toggle(RFKILL_TYPE_WLAN); + break; + case KEY_BLUETOOTH: + rfkill_schedule_toggle(RFKILL_TYPE_BLUETOOTH); + break; + case KEY_UWB: + rfkill_schedule_toggle(RFKILL_TYPE_UWB); + break; + case KEY_WIMAX: + rfkill_schedule_toggle(RFKILL_TYPE_WIMAX); + break; + } + } else if (type == EV_SW && code == SW_RFKILL_ALL) + rfkill_schedule_evsw_rfkillall(data); +} + +static int rfkill_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "rfkill"; + + /* causes rfkill_start() to be called */ + error = input_register_handle(handle); + if (error) + goto err_free_handle; + + error = input_open_device(handle); + if (error) + goto err_unregister_handle; + + return 0; + + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; +} + +static void rfkill_start(struct input_handle *handle) +{ + /* + * Take event_lock to guard against configuration changes, we + * should be able to deal with concurrency with rfkill_event() + * just fine (which event_lock will also avoid). + */ + spin_lock_irq(&handle->dev->event_lock); + + if (test_bit(EV_SW, handle->dev->evbit) && + test_bit(SW_RFKILL_ALL, handle->dev->swbit)) + rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL, + handle->dev->sw)); + + spin_unlock_irq(&handle->dev->event_lock); +} + +static void rfkill_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id rfkill_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, + .evbit = { BIT(EV_SW) }, + .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, + }, + { } +}; + +static struct input_handler rfkill_handler = { + .name = "rfkill", + .event = rfkill_event, + .connect = rfkill_connect, + .start = rfkill_start, + .disconnect = rfkill_disconnect, + .id_table = rfkill_ids, +}; + +int __init rfkill_handler_init(void) +{ + switch (rfkill_master_switch_mode) { + case RFKILL_INPUT_MASTER_UNBLOCKALL: + rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNBLOCK; + break; + case RFKILL_INPUT_MASTER_RESTORE: + rfkill_master_switch_op = RFKILL_GLOBAL_OP_RESTORE; + break; + case RFKILL_INPUT_MASTER_UNLOCK: + rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNLOCK; + break; + default: + return -EINVAL; + } + + spin_lock_init(&rfkill_op_lock); + + /* Avoid delay at first schedule */ + rfkill_last_scheduled = + jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; + return input_register_handler(&rfkill_handler); +} + +void __exit rfkill_handler_exit(void) +{ + input_unregister_handler(&rfkill_handler); + cancel_delayed_work_sync(&rfkill_op_work); +} diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c deleted file mode 100644 index 60a34f3..0000000 --- a/net/rfkill/rfkill-input.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Input layer to RF Kill interface connector - * - * Copyright (c) 2007 Dmitry Torokhov - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "rfkill-input.h" - -MODULE_AUTHOR("Dmitry Torokhov "); -MODULE_DESCRIPTION("Input layer to RF switch connector"); -MODULE_LICENSE("GPL"); - -enum rfkill_input_master_mode { - RFKILL_INPUT_MASTER_DONOTHING = 0, - RFKILL_INPUT_MASTER_RESTORE = 1, - RFKILL_INPUT_MASTER_UNBLOCKALL = 2, - RFKILL_INPUT_MASTER_MAX, /* marker */ -}; - -/* Delay (in ms) between consecutive switch ops */ -#define RFKILL_OPS_DELAY 200 - -static enum rfkill_input_master_mode rfkill_master_switch_mode = - RFKILL_INPUT_MASTER_UNBLOCKALL; -module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); -MODULE_PARM_DESC(master_switch_mode, - "SW_RFKILL_ALL ON should: 0=do nothing; 1=restore; 2=unblock all"); - -enum rfkill_global_sched_op { - RFKILL_GLOBAL_OP_EPO = 0, - RFKILL_GLOBAL_OP_RESTORE, - RFKILL_GLOBAL_OP_UNLOCK, - RFKILL_GLOBAL_OP_UNBLOCK, -}; - -struct rfkill_task { - struct delayed_work dwork; - - /* ensures that task is serialized */ - struct mutex mutex; - - /* protects everything below */ - spinlock_t lock; - - /* pending regular switch operations (1=pending) */ - unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - - /* should the state be complemented (1=yes) */ - unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - - bool global_op_pending; - enum rfkill_global_sched_op op; - - /* last time it was scheduled */ - unsigned long last_scheduled; -}; - -static void __rfkill_handle_global_op(enum rfkill_global_sched_op op) -{ - unsigned int i; - - switch (op) { - case RFKILL_GLOBAL_OP_EPO: - rfkill_epo(); - break; - case RFKILL_GLOBAL_OP_RESTORE: - rfkill_restore_states(); - break; - case RFKILL_GLOBAL_OP_UNLOCK: - rfkill_remove_epo_lock(); - break; - case RFKILL_GLOBAL_OP_UNBLOCK: - rfkill_remove_epo_lock(); - for (i = 0; i < RFKILL_TYPE_MAX; i++) - rfkill_switch_all(i, RFKILL_STATE_UNBLOCKED); - break; - default: - /* memory corruption or bug, fail safely */ - rfkill_epo(); - WARN(1, "Unknown requested operation %d! " - "rfkill Emergency Power Off activated\n", - op); - } -} - -static void __rfkill_handle_normal_op(const enum rfkill_type type, - const bool c) -{ - enum rfkill_state state; - - state = rfkill_get_global_state(type); - if (c) - state = rfkill_state_complement(state); - - rfkill_switch_all(type, state); -} - -static void rfkill_task_handler(struct work_struct *work) -{ - struct rfkill_task *task = container_of(work, - struct rfkill_task, dwork.work); - bool doit = true; - - mutex_lock(&task->mutex); - - spin_lock_irq(&task->lock); - while (doit) { - if (task->global_op_pending) { - enum rfkill_global_sched_op op = task->op; - task->global_op_pending = false; - memset(task->sw_pending, 0, sizeof(task->sw_pending)); - spin_unlock_irq(&task->lock); - - __rfkill_handle_global_op(op); - - /* make sure we do at least one pass with - * !task->global_op_pending */ - spin_lock_irq(&task->lock); - continue; - } else if (!rfkill_is_epo_lock_active()) { - unsigned int i = 0; - - while (!task->global_op_pending && - i < RFKILL_TYPE_MAX) { - if (test_and_clear_bit(i, task->sw_pending)) { - bool c; - c = test_and_clear_bit(i, - task->sw_togglestate); - spin_unlock_irq(&task->lock); - - __rfkill_handle_normal_op(i, c); - - spin_lock_irq(&task->lock); - } - i++; - } - } - doit = task->global_op_pending; - } - spin_unlock_irq(&task->lock); - - mutex_unlock(&task->mutex); -} - -static struct rfkill_task rfkill_task = { - .dwork = __DELAYED_WORK_INITIALIZER(rfkill_task.dwork, - rfkill_task_handler), - .mutex = __MUTEX_INITIALIZER(rfkill_task.mutex), - .lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock), -}; - -static unsigned long rfkill_ratelimit(const unsigned long last) -{ - const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); - return (time_after(jiffies, last + delay)) ? 0 : delay; -} - -static void rfkill_schedule_ratelimited(void) -{ - if (!delayed_work_pending(&rfkill_task.dwork)) { - schedule_delayed_work(&rfkill_task.dwork, - rfkill_ratelimit(rfkill_task.last_scheduled)); - rfkill_task.last_scheduled = jiffies; - } -} - -static void rfkill_schedule_global_op(enum rfkill_global_sched_op op) -{ - unsigned long flags; - - spin_lock_irqsave(&rfkill_task.lock, flags); - rfkill_task.op = op; - rfkill_task.global_op_pending = true; - if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { - /* bypass the limiter for EPO */ - cancel_delayed_work(&rfkill_task.dwork); - schedule_delayed_work(&rfkill_task.dwork, 0); - rfkill_task.last_scheduled = jiffies; - } else - rfkill_schedule_ratelimited(); - spin_unlock_irqrestore(&rfkill_task.lock, flags); -} - -static void rfkill_schedule_toggle(enum rfkill_type type) -{ - unsigned long flags; - - if (rfkill_is_epo_lock_active()) - return; - - spin_lock_irqsave(&rfkill_task.lock, flags); - if (!rfkill_task.global_op_pending) { - set_bit(type, rfkill_task.sw_pending); - change_bit(type, rfkill_task.sw_togglestate); - rfkill_schedule_ratelimited(); - } - spin_unlock_irqrestore(&rfkill_task.lock, flags); -} - -static void rfkill_schedule_evsw_rfkillall(int state) -{ - if (state) { - switch (rfkill_master_switch_mode) { - case RFKILL_INPUT_MASTER_UNBLOCKALL: - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNBLOCK); - break; - case RFKILL_INPUT_MASTER_RESTORE: - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_RESTORE); - break; - case RFKILL_INPUT_MASTER_DONOTHING: - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNLOCK); - break; - default: - /* memory corruption or driver bug! fail safely */ - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); - WARN(1, "Unknown rfkill_master_switch_mode (%d), " - "driver bug or memory corruption detected!\n", - rfkill_master_switch_mode); - break; - } - } else - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); -} - -static void rfkill_event(struct input_handle *handle, unsigned int type, - unsigned int code, int data) -{ - if (type == EV_KEY && data == 1) { - enum rfkill_type t; - - switch (code) { - case KEY_WLAN: - t = RFKILL_TYPE_WLAN; - break; - case KEY_BLUETOOTH: - t = RFKILL_TYPE_BLUETOOTH; - break; - case KEY_UWB: - t = RFKILL_TYPE_UWB; - break; - case KEY_WIMAX: - t = RFKILL_TYPE_WIMAX; - break; - default: - return; - } - rfkill_schedule_toggle(t); - return; - } else if (type == EV_SW) { - switch (code) { - case SW_RFKILL_ALL: - rfkill_schedule_evsw_rfkillall(data); - return; - default: - return; - } - } -} - -static int rfkill_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) -{ - struct input_handle *handle; - int error; - - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = "rfkill"; - - /* causes rfkill_start() to be called */ - error = input_register_handle(handle); - if (error) - goto err_free_handle; - - error = input_open_device(handle); - if (error) - goto err_unregister_handle; - - return 0; - - err_unregister_handle: - input_unregister_handle(handle); - err_free_handle: - kfree(handle); - return error; -} - -static void rfkill_start(struct input_handle *handle) -{ - /* Take event_lock to guard against configuration changes, we - * should be able to deal with concurrency with rfkill_event() - * just fine (which event_lock will also avoid). */ - spin_lock_irq(&handle->dev->event_lock); - - if (test_bit(EV_SW, handle->dev->evbit)) { - if (test_bit(SW_RFKILL_ALL, handle->dev->swbit)) - rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL, - handle->dev->sw)); - /* add resync for further EV_SW events here */ - } - - spin_unlock_irq(&handle->dev->event_lock); -} - -static void rfkill_disconnect(struct input_handle *handle) -{ - input_close_device(handle); - input_unregister_handle(handle); - kfree(handle); -} - -static const struct input_device_id rfkill_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, - .evbit = { BIT(EV_SW) }, - .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, - }, - { } -}; - -static struct input_handler rfkill_handler = { - .event = rfkill_event, - .connect = rfkill_connect, - .disconnect = rfkill_disconnect, - .start = rfkill_start, - .name = "rfkill", - .id_table = rfkill_ids, -}; - -static int __init rfkill_handler_init(void) -{ - if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX) - return -EINVAL; - - /* - * The penalty to not doing this is a possible RFKILL_OPS_DELAY delay - * at the first use. Acceptable, but if we can avoid it, why not? - */ - rfkill_task.last_scheduled = - jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; - return input_register_handler(&rfkill_handler); -} - -static void __exit rfkill_handler_exit(void) -{ - input_unregister_handler(&rfkill_handler); - cancel_delayed_work_sync(&rfkill_task.dwork); - rfkill_remove_epo_lock(); -} - -module_init(rfkill_handler_init); -module_exit(rfkill_handler_exit); diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h deleted file mode 100644 index fe8df6b..0000000 --- a/net/rfkill/rfkill-input.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2007 Ivo van Doorn - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#ifndef __RFKILL_INPUT_H -#define __RFKILL_INPUT_H - -void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); -void rfkill_epo(void); -void rfkill_restore_states(void); -void rfkill_remove_epo_lock(void); -bool rfkill_is_epo_lock_active(void); -enum rfkill_state rfkill_get_global_state(const enum rfkill_type type); - -#endif /* __RFKILL_INPUT_H */ diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c deleted file mode 100644 index 4f5a831..0000000 --- a/net/rfkill/rfkill.c +++ /dev/null @@ -1,855 +0,0 @@ -/* - * Copyright (C) 2006 - 2007 Ivo van Doorn - * Copyright (C) 2007 Dmitry Torokhov - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -/* Get declaration of rfkill_switch_all() to shut up sparse. */ -#include "rfkill-input.h" - - -MODULE_AUTHOR("Ivo van Doorn "); -MODULE_VERSION("1.0"); -MODULE_DESCRIPTION("RF switch support"); -MODULE_LICENSE("GPL"); - -static LIST_HEAD(rfkill_list); /* list of registered rf switches */ -static DEFINE_MUTEX(rfkill_global_mutex); - -static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; -module_param_named(default_state, rfkill_default_state, uint, 0444); -MODULE_PARM_DESC(default_state, - "Default initial state for all radio types, 0 = radio off"); - -struct rfkill_gsw_state { - enum rfkill_state current_state; - enum rfkill_state default_state; -}; - -static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX]; -static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; -static bool rfkill_epo_lock_active; - - -#ifdef CONFIG_RFKILL_LEDS -static void rfkill_led_trigger(struct rfkill *rfkill, - enum rfkill_state state) -{ - struct led_trigger *led = &rfkill->led_trigger; - - if (!led->name) - return; - if (state != RFKILL_STATE_UNBLOCKED) - led_trigger_event(led, LED_OFF); - else - led_trigger_event(led, LED_FULL); -} - -static void rfkill_led_trigger_activate(struct led_classdev *led) -{ - struct rfkill *rfkill = container_of(led->trigger, - struct rfkill, led_trigger); - - rfkill_led_trigger(rfkill, rfkill->state); -} -#else -static inline void rfkill_led_trigger(struct rfkill *rfkill, - enum rfkill_state state) -{ -} -#endif /* CONFIG_RFKILL_LEDS */ - -static void rfkill_uevent(struct rfkill *rfkill) -{ - kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); -} - -static void update_rfkill_state(struct rfkill *rfkill) -{ - enum rfkill_state newstate, oldstate; - - if (rfkill->get_state) { - mutex_lock(&rfkill->mutex); - if (!rfkill->get_state(rfkill->data, &newstate)) { - oldstate = rfkill->state; - rfkill->state = newstate; - if (oldstate != newstate) - rfkill_uevent(rfkill); - } - mutex_unlock(&rfkill->mutex); - } - rfkill_led_trigger(rfkill, rfkill->state); -} - -/** - * rfkill_toggle_radio - wrapper for toggle_radio hook - * @rfkill: the rfkill struct to use - * @force: calls toggle_radio even if cache says it is not needed, - * and also makes sure notifications of the state will be - * sent even if it didn't change - * @state: the new state to call toggle_radio() with - * - * Calls rfkill->toggle_radio, enforcing the API for toggle_radio - * calls and handling all the red tape such as issuing notifications - * if the call is successful. - * - * Suspended devices are not touched at all, and -EAGAIN is returned. - * - * Note that the @force parameter cannot override a (possibly cached) - * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of - * RFKILL_STATE_HARD_BLOCKED implements either get_state() or - * rfkill_force_state(), so the cache either is bypassed or valid. - * - * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED - * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to - * give the driver a hint that it should double-BLOCK the transmitter. - * - * Caller must have acquired rfkill->mutex. - */ -static int rfkill_toggle_radio(struct rfkill *rfkill, - enum rfkill_state state, - int force) -{ - int retval = 0; - enum rfkill_state oldstate, newstate; - - if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) - return -EBUSY; - - oldstate = rfkill->state; - - if (rfkill->get_state && !force && - !rfkill->get_state(rfkill->data, &newstate)) { - rfkill->state = newstate; - } - - switch (state) { - case RFKILL_STATE_HARD_BLOCKED: - /* typically happens when refreshing hardware state, - * such as on resume */ - state = RFKILL_STATE_SOFT_BLOCKED; - break; - case RFKILL_STATE_UNBLOCKED: - /* force can't override this, only rfkill_force_state() can */ - if (rfkill->state == RFKILL_STATE_HARD_BLOCKED) - return -EPERM; - break; - case RFKILL_STATE_SOFT_BLOCKED: - /* nothing to do, we want to give drivers the hint to double - * BLOCK even a transmitter that is already in state - * RFKILL_STATE_HARD_BLOCKED */ - break; - default: - WARN(1, KERN_WARNING - "rfkill: illegal state %d passed as parameter " - "to rfkill_toggle_radio\n", state); - return -EINVAL; - } - - if (force || state != rfkill->state) { - retval = rfkill->toggle_radio(rfkill->data, state); - /* never allow a HARD->SOFT downgrade! */ - if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED) - rfkill->state = state; - } - - if (force || rfkill->state != oldstate) - rfkill_uevent(rfkill); - - rfkill_led_trigger(rfkill, rfkill->state); - return retval; -} - -/** - * __rfkill_switch_all - Toggle state of all switches of given type - * @type: type of interfaces to be affected - * @state: the new state - * - * This function toggles the state of all switches of given type, - * unless a specific switch is claimed by userspace (in which case, - * that switch is left alone) or suspended. - * - * Caller must have acquired rfkill_global_mutex. - */ -static void __rfkill_switch_all(const enum rfkill_type type, - const enum rfkill_state state) -{ - struct rfkill *rfkill; - - if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX), - KERN_WARNING - "rfkill: illegal state %d or type %d " - "passed as parameter to __rfkill_switch_all\n", - state, type)) - return; - - rfkill_global_states[type].current_state = state; - list_for_each_entry(rfkill, &rfkill_list, node) { - if (rfkill->type == type) { - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, state, 0); - mutex_unlock(&rfkill->mutex); - rfkill_led_trigger(rfkill, rfkill->state); - } - } -} - -/** - * rfkill_switch_all - Toggle state of all switches of given type - * @type: type of interfaces to be affected - * @state: the new state - * - * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). - * Please refer to __rfkill_switch_all() for details. - * - * Does nothing if the EPO lock is active. - */ -void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) -{ - mutex_lock(&rfkill_global_mutex); - if (!rfkill_epo_lock_active) - __rfkill_switch_all(type, state); - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL(rfkill_switch_all); - -/** - * rfkill_epo - emergency power off all transmitters - * - * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, - * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. - * - * The global state before the EPO is saved and can be restored later - * using rfkill_restore_states(). - */ -void rfkill_epo(void) -{ - struct rfkill *rfkill; - int i; - - mutex_lock(&rfkill_global_mutex); - - rfkill_epo_lock_active = true; - list_for_each_entry(rfkill, &rfkill_list, node) { - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); - mutex_unlock(&rfkill->mutex); - } - for (i = 0; i < RFKILL_TYPE_MAX; i++) { - rfkill_global_states[i].default_state = - rfkill_global_states[i].current_state; - rfkill_global_states[i].current_state = - RFKILL_STATE_SOFT_BLOCKED; - } - mutex_unlock(&rfkill_global_mutex); - rfkill_led_trigger(rfkill, rfkill->state); -} -EXPORT_SYMBOL_GPL(rfkill_epo); - -/** - * rfkill_restore_states - restore global states - * - * Restore (and sync switches to) the global state from the - * states in rfkill_default_states. This can undo the effects of - * a call to rfkill_epo(). - */ -void rfkill_restore_states(void) -{ - int i; - - mutex_lock(&rfkill_global_mutex); - - rfkill_epo_lock_active = false; - for (i = 0; i < RFKILL_TYPE_MAX; i++) - __rfkill_switch_all(i, rfkill_global_states[i].default_state); - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL_GPL(rfkill_restore_states); - -/** - * rfkill_remove_epo_lock - unlock state changes - * - * Used by rfkill-input manually unlock state changes, when - * the EPO switch is deactivated. - */ -void rfkill_remove_epo_lock(void) -{ - mutex_lock(&rfkill_global_mutex); - rfkill_epo_lock_active = false; - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock); - -/** - * rfkill_is_epo_lock_active - returns true EPO is active - * - * Returns 0 (false) if there is NOT an active EPO contidion, - * and 1 (true) if there is an active EPO contition, which - * locks all radios in one of the BLOCKED states. - * - * Can be called in atomic context. - */ -bool rfkill_is_epo_lock_active(void) -{ - return rfkill_epo_lock_active; -} -EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active); - -/** - * rfkill_get_global_state - returns global state for a type - * @type: the type to get the global state of - * - * Returns the current global state for a given wireless - * device type. - */ -enum rfkill_state rfkill_get_global_state(const enum rfkill_type type) -{ - return rfkill_global_states[type].current_state; -} -EXPORT_SYMBOL_GPL(rfkill_get_global_state); - -/** - * rfkill_force_state - Force the internal rfkill radio state - * @rfkill: pointer to the rfkill class to modify. - * @state: the current radio state the class should be forced to. - * - * This function updates the internal state of the radio cached - * by the rfkill class. It should be used when the driver gets - * a notification by the firmware/hardware of the current *real* - * state of the radio rfkill switch. - * - * Devices which are subject to external changes on their rfkill - * state (such as those caused by a hardware rfkill line) MUST - * have their driver arrange to call rfkill_force_state() as soon - * as possible after such a change. - * - * This function may not be called from an atomic context. - */ -int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) -{ - enum rfkill_state oldstate; - - BUG_ON(!rfkill); - if (WARN((state >= RFKILL_STATE_MAX), - KERN_WARNING - "rfkill: illegal state %d passed as parameter " - "to rfkill_force_state\n", state)) - return -EINVAL; - - mutex_lock(&rfkill->mutex); - - oldstate = rfkill->state; - rfkill->state = state; - - if (state != oldstate) - rfkill_uevent(rfkill); - - mutex_unlock(&rfkill->mutex); - rfkill_led_trigger(rfkill, rfkill->state); - - return 0; -} -EXPORT_SYMBOL(rfkill_force_state); - -static ssize_t rfkill_name_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct rfkill *rfkill = to_rfkill(dev); - - return sprintf(buf, "%s\n", rfkill->name); -} - -static const char *rfkill_get_type_str(enum rfkill_type type) -{ - switch (type) { - case RFKILL_TYPE_WLAN: - return "wlan"; - case RFKILL_TYPE_BLUETOOTH: - return "bluetooth"; - case RFKILL_TYPE_UWB: - return "ultrawideband"; - case RFKILL_TYPE_WIMAX: - return "wimax"; - case RFKILL_TYPE_WWAN: - return "wwan"; - default: - BUG(); - } -} - -static ssize_t rfkill_type_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct rfkill *rfkill = to_rfkill(dev); - - return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); -} - -static ssize_t rfkill_state_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct rfkill *rfkill = to_rfkill(dev); - - update_rfkill_state(rfkill); - return sprintf(buf, "%d\n", rfkill->state); -} - -static ssize_t rfkill_state_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct rfkill *rfkill = to_rfkill(dev); - unsigned long state; - int error; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - error = strict_strtoul(buf, 0, &state); - if (error) - return error; - - /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ - if (state != RFKILL_STATE_UNBLOCKED && - state != RFKILL_STATE_SOFT_BLOCKED) - return -EINVAL; - - error = mutex_lock_killable(&rfkill->mutex); - if (error) - return error; - - if (!rfkill_epo_lock_active) - error = rfkill_toggle_radio(rfkill, state, 0); - else - error = -EPERM; - - mutex_unlock(&rfkill->mutex); - - return error ? error : count; -} - -static ssize_t rfkill_claim_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", 0); -} - -static ssize_t rfkill_claim_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return -EOPNOTSUPP; -} - -static struct device_attribute rfkill_dev_attrs[] = { - __ATTR(name, S_IRUGO, rfkill_name_show, NULL), - __ATTR(type, S_IRUGO, rfkill_type_show, NULL), - __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), - __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), - __ATTR_NULL -}; - -static void rfkill_release(struct device *dev) -{ - struct rfkill *rfkill = to_rfkill(dev); - - kfree(rfkill); - module_put(THIS_MODULE); -} - -#ifdef CONFIG_PM -static int rfkill_suspend(struct device *dev, pm_message_t state) -{ - struct rfkill *rfkill = to_rfkill(dev); - - /* mark class device as suspended */ - if (dev->power.power_state.event != state.event) - dev->power.power_state = state; - - /* store state for the resume handler */ - rfkill->state_for_resume = rfkill->state; - - return 0; -} - -static int rfkill_resume(struct device *dev) -{ - struct rfkill *rfkill = to_rfkill(dev); - enum rfkill_state newstate; - - if (dev->power.power_state.event != PM_EVENT_ON) { - mutex_lock(&rfkill->mutex); - - dev->power.power_state.event = PM_EVENT_ON; - - /* - * rfkill->state could have been modified before we got - * called, and won't be updated by rfkill_toggle_radio() - * in force mode. Sync it FIRST. - */ - if (rfkill->get_state && - !rfkill->get_state(rfkill->data, &newstate)) - rfkill->state = newstate; - - /* - * If we are under EPO, kick transmitter offline, - * otherwise restore to pre-suspend state. - * - * Issue a notification in any case - */ - rfkill_toggle_radio(rfkill, - rfkill_epo_lock_active ? - RFKILL_STATE_SOFT_BLOCKED : - rfkill->state_for_resume, - 1); - - mutex_unlock(&rfkill->mutex); - rfkill_led_trigger(rfkill, rfkill->state); - } - - return 0; -} -#else -#define rfkill_suspend NULL -#define rfkill_resume NULL -#endif - -static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct rfkill *rfkill = to_rfkill(dev); - int error; - - error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); - if (error) - return error; - error = add_uevent_var(env, "RFKILL_TYPE=%s", - rfkill_get_type_str(rfkill->type)); - if (error) - return error; - error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state); - return error; -} - -static struct class rfkill_class = { - .name = "rfkill", - .dev_release = rfkill_release, - .dev_attrs = rfkill_dev_attrs, - .suspend = rfkill_suspend, - .resume = rfkill_resume, - .dev_uevent = rfkill_dev_uevent, -}; - -static int rfkill_check_duplicity(const struct rfkill *rfkill) -{ - struct rfkill *p; - unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - - memset(seen, 0, sizeof(seen)); - - list_for_each_entry(p, &rfkill_list, node) { - if (WARN((p == rfkill), KERN_WARNING - "rfkill: illegal attempt to register " - "an already registered rfkill struct\n")) - return -EEXIST; - set_bit(p->type, seen); - } - - /* 0: first switch of its kind */ - return (test_bit(rfkill->type, seen)) ? 1 : 0; -} - -static int rfkill_add_switch(struct rfkill *rfkill) -{ - int error; - - mutex_lock(&rfkill_global_mutex); - - error = rfkill_check_duplicity(rfkill); - if (error < 0) - goto unlock_out; - - if (!error) { - /* lock default after first use */ - set_bit(rfkill->type, rfkill_states_lockdflt); - rfkill_global_states[rfkill->type].current_state = - rfkill_global_states[rfkill->type].default_state; - } - - rfkill_toggle_radio(rfkill, - rfkill_global_states[rfkill->type].current_state, - 0); - - list_add_tail(&rfkill->node, &rfkill_list); - - error = 0; -unlock_out: - mutex_unlock(&rfkill_global_mutex); - - return error; -} - -static void rfkill_remove_switch(struct rfkill *rfkill) -{ - mutex_lock(&rfkill_global_mutex); - list_del_init(&rfkill->node); - mutex_unlock(&rfkill_global_mutex); - - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); - mutex_unlock(&rfkill->mutex); -} - -/** - * rfkill_allocate - allocate memory for rfkill structure. - * @parent: device that has rf switch on it - * @type: type of the switch (RFKILL_TYPE_*) - * - * This function should be called by the network driver when it needs - * rfkill structure. Once the structure is allocated the driver should - * finish its initialization by setting the name, private data, enable_radio - * and disable_radio methods and then register it with rfkill_register(). - * - * NOTE: If registration fails the structure shoudl be freed by calling - * rfkill_free() otherwise rfkill_unregister() should be used. - */ -struct rfkill * __must_check rfkill_allocate(struct device *parent, - enum rfkill_type type) -{ - struct rfkill *rfkill; - struct device *dev; - - if (WARN((type >= RFKILL_TYPE_MAX), - KERN_WARNING - "rfkill: illegal type %d passed as parameter " - "to rfkill_allocate\n", type)) - return NULL; - - rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); - if (!rfkill) - return NULL; - - mutex_init(&rfkill->mutex); - INIT_LIST_HEAD(&rfkill->node); - rfkill->type = type; - - dev = &rfkill->dev; - dev->class = &rfkill_class; - dev->parent = parent; - device_initialize(dev); - - __module_get(THIS_MODULE); - - return rfkill; -} -EXPORT_SYMBOL(rfkill_allocate); - -/** - * rfkill_free - Mark rfkill structure for deletion - * @rfkill: rfkill structure to be destroyed - * - * Decrements reference count of the rfkill structure so it is destroyed. - * Note that rfkill_free() should _not_ be called after rfkill_unregister(). - */ -void rfkill_free(struct rfkill *rfkill) -{ - if (rfkill) - put_device(&rfkill->dev); -} -EXPORT_SYMBOL(rfkill_free); - -static void rfkill_led_trigger_register(struct rfkill *rfkill) -{ -#ifdef CONFIG_RFKILL_LEDS - int error; - - if (!rfkill->led_trigger.name) - rfkill->led_trigger.name = dev_name(&rfkill->dev); - if (!rfkill->led_trigger.activate) - rfkill->led_trigger.activate = rfkill_led_trigger_activate; - error = led_trigger_register(&rfkill->led_trigger); - if (error) - rfkill->led_trigger.name = NULL; -#endif /* CONFIG_RFKILL_LEDS */ -} - -static void rfkill_led_trigger_unregister(struct rfkill *rfkill) -{ -#ifdef CONFIG_RFKILL_LEDS - if (rfkill->led_trigger.name) { - led_trigger_unregister(&rfkill->led_trigger); - rfkill->led_trigger.name = NULL; - } -#endif -} - -/** - * rfkill_register - Register a rfkill structure. - * @rfkill: rfkill structure to be registered - * - * This function should be called by the network driver when the rfkill - * structure needs to be registered. Immediately from registration the - * switch driver should be able to service calls to toggle_radio. - */ -int __must_check rfkill_register(struct rfkill *rfkill) -{ - static atomic_t rfkill_no = ATOMIC_INIT(0); - struct device *dev = &rfkill->dev; - int error; - - if (WARN((!rfkill || !rfkill->toggle_radio || - rfkill->type >= RFKILL_TYPE_MAX || - rfkill->state >= RFKILL_STATE_MAX), - KERN_WARNING - "rfkill: attempt to register a " - "badly initialized rfkill struct\n")) - return -EINVAL; - - dev_set_name(dev, "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1); - - rfkill_led_trigger_register(rfkill); - - error = rfkill_add_switch(rfkill); - if (error) { - rfkill_led_trigger_unregister(rfkill); - return error; - } - - error = device_add(dev); - if (error) { - rfkill_remove_switch(rfkill); - rfkill_led_trigger_unregister(rfkill); - return error; - } - - return 0; -} -EXPORT_SYMBOL(rfkill_register); - -/** - * rfkill_unregister - Unregister a rfkill structure. - * @rfkill: rfkill structure to be unregistered - * - * This function should be called by the network driver during device - * teardown to destroy rfkill structure. Note that rfkill_free() should - * _not_ be called after rfkill_unregister(). - */ -void rfkill_unregister(struct rfkill *rfkill) -{ - BUG_ON(!rfkill); - device_del(&rfkill->dev); - rfkill_remove_switch(rfkill); - rfkill_led_trigger_unregister(rfkill); - put_device(&rfkill->dev); -} -EXPORT_SYMBOL(rfkill_unregister); - -/** - * rfkill_set_default - set initial value for a switch type - * @type - the type of switch to set the default state of - * @state - the new default state for that group of switches - * - * Sets the initial state rfkill should use for a given type. - * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED - * and RFKILL_STATE_UNBLOCKED. - * - * This function is meant to be used by platform drivers for platforms - * that can save switch state across power down/reboot. - * - * The default state for each switch type can be changed exactly once. - * After a switch of that type is registered, the default state cannot - * be changed anymore. This guards against multiple drivers it the - * same platform trying to set the initial switch default state, which - * is not allowed. - * - * Returns -EPERM if the state has already been set once or is in use, - * so drivers likely want to either ignore or at most printk(KERN_NOTICE) - * if this function returns -EPERM. - * - * Returns 0 if the new default state was set, or an error if it - * could not be set. - */ -int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) -{ - int error; - - if (WARN((type >= RFKILL_TYPE_MAX || - (state != RFKILL_STATE_SOFT_BLOCKED && - state != RFKILL_STATE_UNBLOCKED)), - KERN_WARNING - "rfkill: illegal state %d or type %d passed as " - "parameter to rfkill_set_default\n", state, type)) - return -EINVAL; - - mutex_lock(&rfkill_global_mutex); - - if (!test_and_set_bit(type, rfkill_states_lockdflt)) { - rfkill_global_states[type].default_state = state; - rfkill_global_states[type].current_state = state; - error = 0; - } else - error = -EPERM; - - mutex_unlock(&rfkill_global_mutex); - return error; -} -EXPORT_SYMBOL_GPL(rfkill_set_default); - -/* - * Rfkill module initialization/deinitialization. - */ -static int __init rfkill_init(void) -{ - int error; - int i; - - /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ - if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED && - rfkill_default_state != RFKILL_STATE_UNBLOCKED) - return -EINVAL; - - for (i = 0; i < RFKILL_TYPE_MAX; i++) - rfkill_global_states[i].default_state = rfkill_default_state; - - error = class_register(&rfkill_class); - if (error) { - printk(KERN_ERR "rfkill: unable to register rfkill class\n"); - return error; - } - - return 0; -} - -static void __exit rfkill_exit(void) -{ - class_unregister(&rfkill_class); -} - -subsys_initcall(rfkill_init); -module_exit(rfkill_exit); diff --git a/net/rfkill/rfkill.h b/net/rfkill/rfkill.h new file mode 100644 index 0000000..d1117cb --- /dev/null +++ b/net/rfkill/rfkill.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007 Ivo van Doorn + * Copyright 2009 Johannes Berg + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef __RFKILL_INPUT_H +#define __RFKILL_INPUT_H + +/* core code */ +void rfkill_switch_all(const enum rfkill_type type, bool blocked); +void rfkill_epo(void); +void rfkill_restore_states(void); +void rfkill_remove_epo_lock(void); +bool rfkill_is_epo_lock_active(void); +bool rfkill_get_global_sw_state(const enum rfkill_type type); + +/* input handler */ +int rfkill_handler_init(void); +void rfkill_handler_exit(void); + +#endif /* __RFKILL_INPUT_H */ diff --git a/net/wimax/Kconfig b/net/wimax/Kconfig index 1b46747..0bdbb69 100644 --- a/net/wimax/Kconfig +++ b/net/wimax/Kconfig @@ -1,23 +1,9 @@ # # WiMAX LAN device configuration # -# Note the ugly 'depends on' on WIMAX: that disallows RFKILL to be a -# module if WIMAX is to be linked in. The WiMAX code is done in such a -# way that it doesn't require and explicit dependency on RFKILL in -# case an embedded system wants to rip it out. -# -# As well, enablement of the RFKILL code means we need the INPUT layer -# support to inject events coming from hw rfkill switches. That -# dependency could be killed if input.h provided appropriate means to -# work when input is disabled. - -comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled" - depends on INPUT = n && RFKILL != n menuconfig WIMAX tristate "WiMAX Wireless Broadband support" - depends on (y && RFKILL != m) || m - depends on (INPUT && RFKILL != n) || RFKILL = n help Select to configure support for devices that provide diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index a3616e2..bb102e4 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -29,8 +29,8 @@ * A non-polled generic rfkill device is embedded into the WiMAX * subsystem's representation of a device. * - * FIXME: Need polled support? use a timer or add the implementation - * to the stack. + * FIXME: Need polled support? Let drivers provide a poll routine + * and hand it to rfkill ops then? * * All device drivers have to do is after wimax_dev_init(), call * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update @@ -43,7 +43,7 @@ * wimax_rfkill() Kernel calling wimax_rfkill() * __wimax_rf_toggle_radio() * - * wimax_rfkill_toggle_radio() RF-Kill subsytem calling + * wimax_rfkill_set_radio_block() RF-Kill subsytem calling * __wimax_rf_toggle_radio() * * __wimax_rf_toggle_radio() @@ -65,15 +65,11 @@ #include #include #include -#include #include "wimax-internal.h" #define D_SUBMODULE op_rfkill #include "debug-levels.h" -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - - /** * wimax_report_rfkill_hw - Reports changes in the hardware RF switch * @@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, int result; struct device *dev = wimax_dev_to_dev(wimax_dev); enum wimax_st wimax_state; - enum rfkill_state rfkill_state; d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); BUG_ON(state == WIMAX_RF_QUERY); @@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, if (state != wimax_dev->rf_hw) { wimax_dev->rf_hw = state; - rfkill_state = state == WIMAX_RF_ON ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; if (wimax_dev->rf_hw == WIMAX_RF_ON && wimax_dev->rf_sw == WIMAX_RF_ON) wimax_state = WIMAX_ST_READY; else wimax_state = WIMAX_ST_RADIO_OFF; + + rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); + __wimax_state_change(wimax_dev, wimax_state); - input_report_key(wimax_dev->rfkill_input, KEY_WIMAX, - rfkill_state); } error_not_ready: mutex_unlock(&wimax_dev->mutex); @@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, else wimax_state = WIMAX_ST_RADIO_OFF; __wimax_state_change(wimax_dev, wimax_state); + rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); } error_not_ready: mutex_unlock(&wimax_dev->mutex); @@ -249,36 +244,31 @@ out_no_change: * * NOTE: This call will block until the operation is completed. */ -static -int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state) +static int wimax_rfkill_set_radio_block(void *data, bool blocked) { int result; struct wimax_dev *wimax_dev = data; struct device *dev = wimax_dev_to_dev(wimax_dev); enum wimax_rf_state rf_state; - d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); - switch (state) { - case RFKILL_STATE_SOFT_BLOCKED: + d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked); + rf_state = WIMAX_RF_ON; + if (blocked) rf_state = WIMAX_RF_OFF; - break; - case RFKILL_STATE_UNBLOCKED: - rf_state = WIMAX_RF_ON; - break; - default: - BUG(); - } mutex_lock(&wimax_dev->mutex); if (wimax_dev->state <= __WIMAX_ST_QUIESCING) - result = 0; /* just pretend it didn't happen */ + result = 0; else result = __wimax_rf_toggle_radio(wimax_dev, rf_state); mutex_unlock(&wimax_dev->mutex); - d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n", - wimax_dev, state, result); + d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n", + wimax_dev, blocked, result); return result; } +static const struct rfkill_ops wimax_rfkill_ops = { + .set_block = wimax_rfkill_set_radio_block, +}; /** * wimax_rfkill - Set the software RF switch state for a WiMAX device @@ -322,6 +312,7 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state) result = __wimax_rf_toggle_radio(wimax_dev, state); if (result < 0) goto error; + rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); break; case WIMAX_RF_QUERY: break; @@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) { int result; struct rfkill *rfkill; - struct input_dev *input_dev; struct device *dev = wimax_dev_to_dev(wimax_dev); d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); /* Initialize RF Kill */ result = -ENOMEM; - rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX); + rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX, + &wimax_rfkill_ops, wimax_dev); if (rfkill == NULL) goto error_rfkill_allocate; + + d_printf(1, dev, "rfkill %p\n", rfkill); + wimax_dev->rfkill = rfkill; - rfkill->name = wimax_dev->name; - rfkill->state = RFKILL_STATE_UNBLOCKED; - rfkill->data = wimax_dev; - rfkill->toggle_radio = wimax_rfkill_toggle_radio; - - /* Initialize the input device for the hw key */ - input_dev = input_allocate_device(); - if (input_dev == NULL) - goto error_input_allocate; - wimax_dev->rfkill_input = input_dev; - d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev); - - input_dev->name = wimax_dev->name; - /* FIXME: get a real device bus ID and stuff? do we care? */ - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0xffff; - input_dev->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WIMAX, input_dev->keybit); - - /* Register both */ - result = input_register_device(wimax_dev->rfkill_input); - if (result < 0) - goto error_input_register; result = rfkill_register(wimax_dev->rfkill); if (result < 0) goto error_rfkill_register; @@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); return 0; - /* if rfkill_register() suceeds, can't use rfkill_free() any - * more, only rfkill_unregister() [it owns the refcount]; with - * the input device we have the same issue--hence the if. */ error_rfkill_register: - input_unregister_device(wimax_dev->rfkill_input); - wimax_dev->rfkill_input = NULL; -error_input_register: - if (wimax_dev->rfkill_input) - input_free_device(wimax_dev->rfkill_input); -error_input_allocate: - rfkill_free(wimax_dev->rfkill); + rfkill_destroy(wimax_dev->rfkill); error_rfkill_allocate: d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); return result; @@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev) { struct device *dev = wimax_dev_to_dev(wimax_dev); d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); - rfkill_unregister(wimax_dev->rfkill); /* frees */ - input_unregister_device(wimax_dev->rfkill_input); + rfkill_unregister(wimax_dev->rfkill); + rfkill_destroy(wimax_dev->rfkill); d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); } -#else /* #ifdef CONFIG_RFKILL */ - -void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ -} -EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw); - -void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ -} -EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw); - -int wimax_rfkill(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ - return WIMAX_RF_ON << 1 | WIMAX_RF_ON; -} -EXPORT_SYMBOL_GPL(wimax_rfkill); - -int wimax_rfkill_add(struct wimax_dev *wimax_dev) -{ - return 0; -} - -void wimax_rfkill_rm(struct wimax_dev *wimax_dev) -{ -} - -#endif /* #ifdef CONFIG_RFKILL */ - - /* * Exporting to user space over generic netlink * -- cgit v0.10.2 From c64fb01627e24725d1f9d535e4426475a4415753 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jun 2009 13:01:38 +0200 Subject: rfkill: create useful userspace interface The new code added by this patch will make rfkill create a misc character device /dev/rfkill that userspace can use to control rfkill soft blocks and get status of devices as well as events when the status changes. Using it is very simple -- when you open it you can read a number of times to get the initial state, and every further read blocks (you can poll) on getting the next event from the kernel. The same structure you read is also used when writing to it to change the soft block of a given device, all devices of a given type, or all devices. This also makes CONFIG_RFKILL_INPUT selectable again in order to be able to test without it present since its functionality can now be replaced by userspace entirely and distros and users may not want the input part of rfkill interfering with their userspace code. We will also write a userspace daemon to handle all that and consequently add the input code to the feature removal schedule. In order to have rfkilld support both kernels with and without CONFIG_RFKILL_INPUT (or new kernels after its eventual removal) we also add an ioctl (that only exists if rfkill-input is present) to disable rfkill-input. It is not very efficient, but at least gives the correct behaviour in all cases. Signed-off-by: Johannes Berg Acked-by: Marcel Holtmann Signed-off-by: John W. Linville diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index de491a3..edb2f0b 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -437,3 +437,10 @@ Why: Superseded by tdfxfb. I2C/DDC support used to live in a separate driver but this caused driver conflicts. Who: Jean Delvare Krzysztof Helt + +--------------------------- + +What: CONFIG_RFKILL_INPUT +When: 2.6.33 +Why: Should be implemented in userspace, policy daemon. +Who: Johannes Berg diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 090852c..7c116f6 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -22,34 +22,17 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include /* define userspace visible states */ #define RFKILL_STATE_SOFT_BLOCKED 0 #define RFKILL_STATE_UNBLOCKED 1 #define RFKILL_STATE_HARD_BLOCKED 2 -/* and that's all userspace gets */ -#ifdef __KERNEL__ -/* don't allow anyone to use these in the kernel */ -enum rfkill_user_states { - RFKILL_USER_STATE_SOFT_BLOCKED = RFKILL_STATE_SOFT_BLOCKED, - RFKILL_USER_STATE_UNBLOCKED = RFKILL_STATE_UNBLOCKED, - RFKILL_USER_STATE_HARD_BLOCKED = RFKILL_STATE_HARD_BLOCKED, -}; -#undef RFKILL_STATE_SOFT_BLOCKED -#undef RFKILL_STATE_UNBLOCKED -#undef RFKILL_STATE_HARD_BLOCKED - -#include -#include -#include -#include -#include -#include - /** * enum rfkill_type - type of rfkill switch. * + * @RFKILL_TYPE_ALL: toggles all switches (userspace only) * @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. * @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. * @RFKILL_TYPE_UWB: switch is on a ultra wideband device. @@ -58,6 +41,7 @@ enum rfkill_user_states { * @NUM_RFKILL_TYPES: number of defined rfkill types */ enum rfkill_type { + RFKILL_TYPE_ALL = 0, RFKILL_TYPE_WLAN, RFKILL_TYPE_BLUETOOTH, RFKILL_TYPE_UWB, @@ -66,6 +50,62 @@ enum rfkill_type { NUM_RFKILL_TYPES, }; +/** + * enum rfkill_operation - operation types + * @RFKILL_OP_ADD: a device was added + * @RFKILL_OP_DEL: a device was removed + * @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device + * @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all) + */ +enum rfkill_operation { + RFKILL_OP_ADD = 0, + RFKILL_OP_DEL, + RFKILL_OP_CHANGE, + RFKILL_OP_CHANGE_ALL, +}; + +/** + * struct rfkill_event - events for userspace on /dev/rfkill + * @idx: index of dev rfkill + * @type: type of the rfkill struct + * @op: operation code + * @hard: hard state (0/1) + * @soft: soft state (0/1) + * + * Structure used for userspace communication on /dev/rfkill, + * used for events from the kernel and control to the kernel. + */ +struct rfkill_event { + __u32 idx; + __u8 type; + __u8 op; + __u8 soft, hard; +} __packed; + +/* ioctl for turning off rfkill-input (if present) */ +#define RFKILL_IOC_MAGIC 'R' +#define RFKILL_IOC_NOINPUT 1 +#define RFKILL_IOCTL_NOINPUT _IO(RFKILL_IOC_MAGIC, RFKILL_IOC_NOINPUT) + +/* and that's all userspace gets */ +#ifdef __KERNEL__ +/* don't allow anyone to use these in the kernel */ +enum rfkill_user_states { + RFKILL_USER_STATE_SOFT_BLOCKED = RFKILL_STATE_SOFT_BLOCKED, + RFKILL_USER_STATE_UNBLOCKED = RFKILL_STATE_UNBLOCKED, + RFKILL_USER_STATE_HARD_BLOCKED = RFKILL_STATE_HARD_BLOCKED, +}; +#undef RFKILL_STATE_SOFT_BLOCKED +#undef RFKILL_STATE_UNBLOCKED +#undef RFKILL_STATE_HARD_BLOCKED + +#include +#include +#include +#include +#include +#include + /* this is opaque */ struct rfkill; @@ -84,11 +124,7 @@ struct rfkill; * the rfkill core query your driver before setting a requested * block. * @set_block: turn the transmitter on (blocked == false) or off - * (blocked == true) -- this is called only while the transmitter - * is not hard-blocked, but note that the core's view of whether - * the transmitter is hard-blocked might differ from your driver's - * view due to race conditions, so it is possible that it is still - * called at the same time as you are calling rfkill_set_hw_state(). + * (blocked == true) -- ignore and return 0 when hard blocked. * This callback must be assigned. */ struct rfkill_ops { diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index b47f72f..fd7600d 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -18,7 +18,7 @@ config RFKILL_LEDS default y config RFKILL_INPUT - bool + bool "RF switch input support" depends on RFKILL depends on INPUT = y || RFKILL = INPUT - default y + default y if !EMBEDDED diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 30a6f8d..2230aa6 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -28,6 +28,10 @@ #include #include #include +#include +#include +#include +#include #include "rfkill.h" @@ -49,6 +53,8 @@ struct rfkill { unsigned long state; + u32 idx; + bool registered; bool suspended; @@ -69,6 +75,18 @@ struct rfkill { }; #define to_rfkill(d) container_of(d, struct rfkill, dev) +struct rfkill_int_event { + struct list_head list; + struct rfkill_event ev; +}; + +struct rfkill_data { + struct list_head list; + struct list_head events; + struct mutex mtx; + wait_queue_head_t read_wait; + bool input_handler; +}; MODULE_AUTHOR("Ivo van Doorn "); @@ -90,6 +108,7 @@ MODULE_LICENSE("GPL"); */ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ static DEFINE_MUTEX(rfkill_global_mutex); +static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ static unsigned int rfkill_default_state = 1; module_param_named(default_state, rfkill_default_state, uint, 0444); @@ -171,12 +190,48 @@ static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill) } #endif /* CONFIG_RFKILL_LEDS */ -static void rfkill_uevent(struct rfkill *rfkill) +static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill, + enum rfkill_operation op) +{ + unsigned long flags; + + ev->idx = rfkill->idx; + ev->type = rfkill->type; + ev->op = op; + + spin_lock_irqsave(&rfkill->lock, flags); + ev->hard = !!(rfkill->state & RFKILL_BLOCK_HW); + ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW | + RFKILL_BLOCK_SW_PREV)); + spin_unlock_irqrestore(&rfkill->lock, flags); +} + +static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op) +{ + struct rfkill_data *data; + struct rfkill_int_event *ev; + + list_for_each_entry(data, &rfkill_fds, list) { + ev = kzalloc(sizeof(*ev), GFP_KERNEL); + if (!ev) + continue; + rfkill_fill_event(&ev->ev, rfkill, op); + mutex_lock(&data->mtx); + list_add_tail(&ev->list, &data->events); + mutex_unlock(&data->mtx); + wake_up_interruptible(&data->read_wait); + } +} + +static void rfkill_event(struct rfkill *rfkill) { if (!rfkill->registered || rfkill->suspended) return; kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); + + /* also send event to /dev/rfkill */ + rfkill_send_events(rfkill, RFKILL_OP_CHANGE); } static bool __rfkill_set_hw_state(struct rfkill *rfkill, @@ -260,9 +315,12 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) spin_unlock_irqrestore(&rfkill->lock, flags); rfkill_led_trigger_event(rfkill); - rfkill_uevent(rfkill); + rfkill_event(rfkill); } +#ifdef CONFIG_RFKILL_INPUT +static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); + /** * __rfkill_switch_all - Toggle state of all switches of given type * @type: type of interfaces to be affected @@ -299,6 +357,9 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) */ void rfkill_switch_all(enum rfkill_type type, bool blocked) { + if (atomic_read(&rfkill_input_disabled)) + return; + mutex_lock(&rfkill_global_mutex); if (!rfkill_epo_lock_active) @@ -321,6 +382,9 @@ void rfkill_epo(void) struct rfkill *rfkill; int i; + if (atomic_read(&rfkill_input_disabled)) + return; + mutex_lock(&rfkill_global_mutex); rfkill_epo_lock_active = true; @@ -331,6 +395,7 @@ void rfkill_epo(void) rfkill_global_states[i].def = rfkill_global_states[i].cur; rfkill_global_states[i].cur = true; } + mutex_unlock(&rfkill_global_mutex); } @@ -345,6 +410,9 @@ void rfkill_restore_states(void) { int i; + if (atomic_read(&rfkill_input_disabled)) + return; + mutex_lock(&rfkill_global_mutex); rfkill_epo_lock_active = false; @@ -361,6 +429,9 @@ void rfkill_restore_states(void) */ void rfkill_remove_epo_lock(void) { + if (atomic_read(&rfkill_input_disabled)) + return; + mutex_lock(&rfkill_global_mutex); rfkill_epo_lock_active = false; mutex_unlock(&rfkill_global_mutex); @@ -391,9 +462,12 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type) { return rfkill_global_states[type].cur; } +#endif void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked) { + BUG_ON(type == RFKILL_TYPE_ALL); + mutex_lock(&rfkill_global_mutex); /* don't allow unblock when epo */ @@ -537,6 +611,15 @@ static ssize_t rfkill_type_show(struct device *dev, return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); } +static ssize_t rfkill_idx_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + + return sprintf(buf, "%d\n", rfkill->idx); +} + static u8 user_state_from_blocked(unsigned long state) { if (state & RFKILL_BLOCK_HW) @@ -594,6 +677,7 @@ static ssize_t rfkill_claim_store(struct device *dev, static struct device_attribute rfkill_dev_attrs[] = { __ATTR(name, S_IRUGO, rfkill_name_show, NULL), __ATTR(type, S_IRUGO, rfkill_type_show, NULL), + __ATTR(index, S_IRUGO, rfkill_idx_show, NULL), __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), __ATTR_NULL @@ -708,7 +792,7 @@ struct rfkill * __must_check rfkill_alloc(const char *name, if (WARN_ON(!name)) return NULL; - if (WARN_ON(type >= NUM_RFKILL_TYPES)) + if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES)) return NULL; rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); @@ -754,7 +838,9 @@ static void rfkill_uevent_work(struct work_struct *work) rfkill = container_of(work, struct rfkill, uevent_work); - rfkill_uevent(rfkill); + mutex_lock(&rfkill_global_mutex); + rfkill_event(rfkill); + mutex_unlock(&rfkill_global_mutex); } static void rfkill_sync_work(struct work_struct *work) @@ -785,6 +871,7 @@ int __must_check rfkill_register(struct rfkill *rfkill) goto unlock; } + rfkill->idx = rfkill_no; dev_set_name(dev, "rfkill%lu", rfkill_no); rfkill_no++; @@ -819,6 +906,7 @@ int __must_check rfkill_register(struct rfkill *rfkill) INIT_WORK(&rfkill->sync_work, rfkill_sync_work); schedule_work(&rfkill->sync_work); + rfkill_send_events(rfkill, RFKILL_OP_ADD); mutex_unlock(&rfkill_global_mutex); return 0; @@ -848,6 +936,7 @@ void rfkill_unregister(struct rfkill *rfkill) device_del(&rfkill->dev); mutex_lock(&rfkill_global_mutex); + rfkill_send_events(rfkill, RFKILL_OP_DEL); list_del_init(&rfkill->node); mutex_unlock(&rfkill_global_mutex); @@ -862,6 +951,227 @@ void rfkill_destroy(struct rfkill *rfkill) } EXPORT_SYMBOL(rfkill_destroy); +static int rfkill_fop_open(struct inode *inode, struct file *file) +{ + struct rfkill_data *data; + struct rfkill *rfkill; + struct rfkill_int_event *ev, *tmp; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + INIT_LIST_HEAD(&data->events); + mutex_init(&data->mtx); + init_waitqueue_head(&data->read_wait); + + mutex_lock(&rfkill_global_mutex); + mutex_lock(&data->mtx); + /* + * start getting events from elsewhere but hold mtx to get + * startup events added first + */ + list_add(&data->list, &rfkill_fds); + + list_for_each_entry(rfkill, &rfkill_list, node) { + ev = kzalloc(sizeof(*ev), GFP_KERNEL); + if (!ev) + goto free; + rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); + list_add_tail(&ev->list, &data->events); + } + mutex_unlock(&data->mtx); + mutex_unlock(&rfkill_global_mutex); + + file->private_data = data; + + return nonseekable_open(inode, file); + + free: + mutex_unlock(&data->mtx); + mutex_unlock(&rfkill_global_mutex); + mutex_destroy(&data->mtx); + list_for_each_entry_safe(ev, tmp, &data->events, list) + kfree(ev); + kfree(data); + return -ENOMEM; +} + +static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait) +{ + struct rfkill_data *data = file->private_data; + unsigned int res = POLLOUT | POLLWRNORM; + + poll_wait(file, &data->read_wait, wait); + + mutex_lock(&data->mtx); + if (!list_empty(&data->events)) + res = POLLIN | POLLRDNORM; + mutex_unlock(&data->mtx); + + return res; +} + +static bool rfkill_readable(struct rfkill_data *data) +{ + bool r; + + mutex_lock(&data->mtx); + r = !list_empty(&data->events); + mutex_unlock(&data->mtx); + + return r; +} + +static ssize_t rfkill_fop_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct rfkill_data *data = file->private_data; + struct rfkill_int_event *ev; + unsigned long sz; + int ret; + + mutex_lock(&data->mtx); + + while (list_empty(&data->events)) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto out; + } + mutex_unlock(&data->mtx); + ret = wait_event_interruptible(data->read_wait, + rfkill_readable(data)); + mutex_lock(&data->mtx); + + if (ret) + goto out; + } + + ev = list_first_entry(&data->events, struct rfkill_int_event, + list); + + sz = min_t(unsigned long, sizeof(ev->ev), count); + ret = sz; + if (copy_to_user(buf, &ev->ev, sz)) + ret = -EFAULT; + + list_del(&ev->list); + kfree(ev); + out: + mutex_unlock(&data->mtx); + return ret; +} + +static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct rfkill *rfkill; + struct rfkill_event ev; + + /* we don't need the 'hard' variable but accept it */ + if (count < sizeof(ev) - 1) + return -EINVAL; + + if (copy_from_user(&ev, buf, sizeof(ev) - 1)) + return -EFAULT; + + if (ev.op != RFKILL_OP_CHANGE && ev.op != RFKILL_OP_CHANGE_ALL) + return -EINVAL; + + if (ev.type >= NUM_RFKILL_TYPES) + return -EINVAL; + + mutex_lock(&rfkill_global_mutex); + + if (ev.op == RFKILL_OP_CHANGE_ALL) { + if (ev.type == RFKILL_TYPE_ALL) { + enum rfkill_type i; + for (i = 0; i < NUM_RFKILL_TYPES; i++) + rfkill_global_states[i].cur = ev.soft; + } else { + rfkill_global_states[ev.type].cur = ev.soft; + } + } + + list_for_each_entry(rfkill, &rfkill_list, node) { + if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL) + continue; + + if (rfkill->type != ev.type && ev.type != RFKILL_TYPE_ALL) + continue; + + rfkill_set_block(rfkill, ev.soft); + } + mutex_unlock(&rfkill_global_mutex); + + return count; +} + +static int rfkill_fop_release(struct inode *inode, struct file *file) +{ + struct rfkill_data *data = file->private_data; + struct rfkill_int_event *ev, *tmp; + + mutex_lock(&rfkill_global_mutex); + list_del(&data->list); + mutex_unlock(&rfkill_global_mutex); + + mutex_destroy(&data->mtx); + list_for_each_entry_safe(ev, tmp, &data->events, list) + kfree(ev); + +#ifdef CONFIG_RFKILL_INPUT + if (data->input_handler) + atomic_dec(&rfkill_input_disabled); +#endif + + kfree(data); + + return 0; +} + +#ifdef CONFIG_RFKILL_INPUT +static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rfkill_data *data = file->private_data; + + if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC) + return -ENOSYS; + + if (_IOC_NR(cmd) != RFKILL_IOC_NOINPUT) + return -ENOSYS; + + mutex_lock(&data->mtx); + + if (!data->input_handler) { + atomic_inc(&rfkill_input_disabled); + data->input_handler = true; + } + + mutex_unlock(&data->mtx); + + return 0; +} +#endif + +static const struct file_operations rfkill_fops = { + .open = rfkill_fop_open, + .read = rfkill_fop_read, + .write = rfkill_fop_write, + .poll = rfkill_fop_poll, + .release = rfkill_fop_release, +#ifdef CONFIG_RFKILL_INPUT + .unlocked_ioctl = rfkill_fop_ioctl, + .compat_ioctl = rfkill_fop_ioctl, +#endif +}; + +static struct miscdevice rfkill_miscdev = { + .name = "rfkill", + .fops = &rfkill_fops, + .minor = MISC_DYNAMIC_MINOR, +}; static int __init rfkill_init(void) { @@ -875,10 +1185,19 @@ static int __init rfkill_init(void) if (error) goto out; + error = misc_register(&rfkill_miscdev); + if (error) { + class_unregister(&rfkill_class); + goto out; + } + #ifdef CONFIG_RFKILL_INPUT error = rfkill_handler_init(); - if (error) + if (error) { + misc_deregister(&rfkill_miscdev); class_unregister(&rfkill_class); + goto out; + } #endif out: @@ -891,6 +1210,7 @@ static void __exit rfkill_exit(void) #ifdef CONFIG_RFKILL_INPUT rfkill_handler_exit(); #endif + misc_deregister(&rfkill_miscdev); class_unregister(&rfkill_class); } module_exit(rfkill_exit); -- cgit v0.10.2 From 7643a2c3fcc13cd6fbd731f214463547383418ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jun 2009 13:01:39 +0200 Subject: cfg80211: move txpower wext from mac80211 This patch introduces new cfg80211 API to set the TX power via cfg80211, puts the wext code into cfg80211 and updates mac80211 to use all that. The -ENETDOWN bits are a hack but will go away soon. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f20da7d..8b8e4b8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -752,6 +752,21 @@ enum wiphy_params_flags { }; /** + * enum tx_power_setting - TX power adjustment + * + * @TX_POWER_AUTOMATIC: the dbm parameter is ignored + * @TX_POWER_LIMITED: limit TX power by the dbm parameter + * @TX_POWER_FIXED: fix TX power to the dbm parameter + * @TX_POWER_OFF: turn off completely (will go away) + */ +enum tx_power_setting { + TX_POWER_AUTOMATIC, + TX_POWER_LIMITED, + TX_POWER_FIXED, + TX_POWER_OFF, +}; + +/** * struct cfg80211_ops - backend description for wireless configuration * * This struct is registered by fullmac card drivers and/or wireless stacks @@ -837,6 +852,11 @@ enum wiphy_params_flags { * @changed bitfield (see &enum wiphy_params_flags) describes which values * have changed. The actual parameter values are available in * struct wiphy. If returning an error, no value should be changed. + * + * @set_tx_power: set the transmit power according to the parameters + * @get_tx_power: store the current TX power into the dbm variable; + * return 0 if successful; or -ENETDOWN if successful but power + * is disabled (this will go away) */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy); @@ -928,6 +948,10 @@ struct cfg80211_ops { int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); + + int (*set_tx_power)(struct wiphy *wiphy, + enum tx_power_setting type, int dbm); + int (*get_tx_power)(struct wiphy *wiphy, int *dbm); }; /* @@ -1451,6 +1475,12 @@ int cfg80211_wext_siwencode(struct net_device *dev, int cfg80211_wext_giwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf); +int cfg80211_wext_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *keybuf); +int cfg80211_wext_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *keybuf); /* * callbacks for asynchronous cfg80211 methods, notification diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d2fc18c..81258ac 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1334,6 +1334,58 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return 0; } +static int ieee80211_set_tx_power(struct wiphy *wiphy, + enum tx_power_setting type, int dbm) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_channel *chan = local->hw.conf.channel; + u32 changes = 0; + bool radio_enabled = true; + + switch (type) { + case TX_POWER_AUTOMATIC: + local->user_power_level = -1; + break; + case TX_POWER_LIMITED: + if (dbm < 0) + return -EINVAL; + local->user_power_level = dbm; + break; + case TX_POWER_FIXED: + if (dbm < 0) + return -EINVAL; + /* TODO: move to cfg80211 when it knows the channel */ + if (dbm > chan->max_power) + return -EINVAL; + local->user_power_level = dbm; + break; + case TX_POWER_OFF: + radio_enabled = false; + break; + } + + if (radio_enabled != local->hw.conf.radio_enabled) { + changes |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; + local->hw.conf.radio_enabled = radio_enabled; + } + + ieee80211_hw_config(local, changes); + + return 0; +} + +static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + *dbm = local->hw.conf.power_level; + + if (!local->hw.conf.radio_enabled) + return -ENETDOWN; + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1373,4 +1425,6 @@ struct cfg80211_ops mac80211_config_ops = { .join_ibss = ieee80211_join_ibss, .leave_ibss = ieee80211_leave_ibss, .set_wiphy_params = ieee80211_set_wiphy_params, + .set_tx_power = ieee80211_set_tx_power, + .get_tx_power = ieee80211_get_tx_power, }; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index a01154e..d2d81b1 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -306,82 +306,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwtxpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_channel* chan = local->hw.conf.channel; - bool reconf = false; - u32 reconf_flags = 0; - int new_power_level; - - if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) - return -EINVAL; - if (data->txpower.flags & IW_TXPOW_RANGE) - return -EINVAL; - if (!chan) - return -EINVAL; - - /* only change when not disabling */ - if (!data->txpower.disabled) { - if (data->txpower.fixed) { - if (data->txpower.value < 0) - return -EINVAL; - new_power_level = data->txpower.value; - /* - * Debatable, but we cannot do a fixed power - * level above the regulatory constraint. - * Use "iwconfig wlan0 txpower 15dBm" instead. - */ - if (new_power_level > chan->max_power) - return -EINVAL; - } else { - /* - * Automatic power level setting, max being the value - * passed in from userland. - */ - if (data->txpower.value < 0) - new_power_level = -1; - else - new_power_level = data->txpower.value; - } - - reconf = true; - - /* - * ieee80211_hw_config() will limit to the channel's - * max power and possibly power constraint from AP. - */ - local->user_power_level = new_power_level; - } - - if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { - local->hw.conf.radio_enabled = !(data->txpower.disabled); - reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; - ieee80211_led_radio(local, local->hw.conf.radio_enabled); - } - - if (reconf || reconf_flags) - ieee80211_hw_config(local, reconf_flags); - - return 0; -} - -static int ieee80211_ioctl_giwtxpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - data->txpower.fixed = 1; - data->txpower.disabled = !(local->hw.conf.radio_enabled); - data->txpower.value = local->hw.conf.power_level; - data->txpower.flags = IW_TXPOW_DBM; - - return 0; -} - static int ieee80211_ioctl_siwpower(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, @@ -658,8 +582,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ + (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ + (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 711e00a..9fbfb85 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -744,3 +744,83 @@ int cfg80211_wext_giwencode(struct net_device *dev, return err; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); + +int cfg80211_wext_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + enum tx_power_setting type; + int dbm = 0; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + + if (!rdev->ops->set_tx_power) + return -EOPNOTSUPP; + + /* only change when not disabling */ + if (!data->txpower.disabled) { + if (data->txpower.fixed) { + /* + * wext doesn't support negative values, see + * below where it's for automatic + */ + if (data->txpower.value < 0) + return -EINVAL; + dbm = data->txpower.value; + type = TX_POWER_FIXED; + /* TODO: do regulatory check! */ + } else { + /* + * Automatic power level setting, max being the value + * passed in from userland. + */ + if (data->txpower.value < 0) { + type = TX_POWER_AUTOMATIC; + } else { + dbm = data->txpower.value; + type = TX_POWER_LIMITED; + } + } + } else { + type = TX_POWER_OFF; + } + + return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); + +int cfg80211_wext_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int err, val; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + + if (!rdev->ops->get_tx_power) + return -EOPNOTSUPP; + + err = rdev->ops->get_tx_power(wdev->wiphy, &val); + /* HACK!!! */ + if (err && err != -ENETDOWN) + return err; + + /* well... oh well */ + data->txpower.fixed = 1; + data->txpower.disabled = err == -ENETDOWN; + data->txpower.value = val; + data->txpower.flags = IW_TXPOW_DBM; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); -- cgit v0.10.2 From 6081162e2ed78dfcf149b076b047078ab1445cc2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jun 2009 13:01:40 +0200 Subject: rfkill: add function to query state Sometimes it is necessary to know how the state is, and it is easier to query rfkill than keep track of it somewhere else, so add a function for that. This could later be expanded to return hard/soft block, but so far that isn't necessary. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 7c116f6..ee3edde 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -261,6 +261,13 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw); * registered drivers? */ void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked); + +/** + * rfkill_blocked - query rfkill block + * + * @rfkill: rfkill struct to query + */ +bool rfkill_blocked(struct rfkill *rfkill); #else /* !RFKILL */ static inline struct rfkill * __must_check rfkill_alloc(const char *name, @@ -313,6 +320,11 @@ static inline void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked) { } + +static inline bool rfkill_blocked(struct rfkill *rfkill) +{ + return false; +} #endif /* RFKILL || RFKILL_MODULE */ diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 2230aa6..91e9168 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -773,6 +773,19 @@ static struct class rfkill_class = { .resume = rfkill_resume, }; +bool rfkill_blocked(struct rfkill *rfkill) +{ + unsigned long flags; + u32 state; + + spin_lock_irqsave(&rfkill->lock, flags); + state = rfkill->state; + spin_unlock_irqrestore(&rfkill->lock, flags); + + return !!(state & RFKILL_BLOCK_ANY); +} +EXPORT_SYMBOL(rfkill_blocked); + struct rfkill * __must_check rfkill_alloc(const char *name, struct device *parent, -- cgit v0.10.2 From 1f87f7d3a3b42b20f34cb03f0fd1a41c3d0e27f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jun 2009 13:01:41 +0200 Subject: cfg80211: add rfkill support To be easier on drivers and users, have cfg80211 register an rfkill structure that drivers can access. When soft-killed, simply take down all interfaces; when hard-killed the driver needs to notify us and we will take down the interfaces after the fact. While rfkilled, interfaces cannot be set UP. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h index e8852c0..28cc03b 100644 --- a/include/asm-generic/errno.h +++ b/include/asm-generic/errno.h @@ -106,4 +106,6 @@ #define EOWNERDEAD 130 /* Owner died */ #define ENOTRECOVERABLE 131 /* State not recoverable */ +#define ERFKILL 132 /* Operation not possible due to RF-kill */ + #endif diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 8b8e4b8..1a21895 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -757,13 +757,11 @@ enum wiphy_params_flags { * @TX_POWER_AUTOMATIC: the dbm parameter is ignored * @TX_POWER_LIMITED: limit TX power by the dbm parameter * @TX_POWER_FIXED: fix TX power to the dbm parameter - * @TX_POWER_OFF: turn off completely (will go away) */ enum tx_power_setting { TX_POWER_AUTOMATIC, TX_POWER_LIMITED, TX_POWER_FIXED, - TX_POWER_OFF, }; /** @@ -855,8 +853,10 @@ enum tx_power_setting { * * @set_tx_power: set the transmit power according to the parameters * @get_tx_power: store the current TX power into the dbm variable; - * return 0 if successful; or -ENETDOWN if successful but power - * is disabled (this will go away) + * return 0 if successful + * + * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting + * functions to adjust rfkill hw state */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy); @@ -952,6 +952,8 @@ struct cfg80211_ops { int (*set_tx_power)(struct wiphy *wiphy, enum tx_power_setting type, int dbm); int (*get_tx_power)(struct wiphy *wiphy, int *dbm); + + void (*rfkill_poll)(struct wiphy *wiphy); }; /* @@ -1666,4 +1668,23 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, */ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); +/** + * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state + * @wiphy: the wiphy + * @blocked: block status + */ +void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked); + +/** + * wiphy_rfkill_start_polling - start polling rfkill + * @wiphy: the wiphy + */ +void wiphy_rfkill_start_polling(struct wiphy *wiphy); + +/** + * wiphy_rfkill_stop_polling - stop polling rfkill + * @wiphy: the wiphy + */ +void wiphy_rfkill_stop_polling(struct wiphy *wiphy); + #endif /* __NET_CFG80211_H */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0270aa6..17d61d1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -526,7 +526,7 @@ enum ieee80211_conf_flags { /** * enum ieee80211_conf_changed - denotes which configuration changed * - * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed + * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed @@ -536,7 +536,7 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed */ enum ieee80211_conf_changed { - IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), + _IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), @@ -546,6 +546,14 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_IDLE = BIT(8), }; +static inline __deprecated enum ieee80211_conf_changed +__IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) +{ + return _IEEE80211_CONF_CHANGE_RADIO_ENABLED; +} +#define IEEE80211_CONF_CHANGE_RADIO_ENABLED \ + __IEEE80211_CONF_CHANGE_RADIO_ENABLED() + /** * struct ieee80211_conf - configuration of the device * @@ -585,7 +593,7 @@ struct ieee80211_conf { int max_sleep_period; u16 listen_interval; - bool radio_enabled; + bool __deprecated radio_enabled; u8 long_frame_max_tx_count, short_frame_max_tx_count; @@ -1396,6 +1404,10 @@ enum ieee80211_ampdu_mlme_action { * is the first frame we expect to perform the action on. Notice * that TX/RX_STOP can pass NULL for this parameter. * Returns a negative error code on failure. + * + * @rfkill_poll: Poll rfkill hardware state. If you need this, you also + * need to set wiphy->rfkill_poll to %true before registration, + * and need to call wiphy_rfkill_set_hw_state() in the callback. */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1444,6 +1456,8 @@ struct ieee80211_ops { int (*ampdu_action)(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn); + + void (*rfkill_poll)(struct ieee80211_hw *hw); }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 81258ac..a9211cc 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1340,7 +1340,6 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_channel *chan = local->hw.conf.channel; u32 changes = 0; - bool radio_enabled = true; switch (type) { case TX_POWER_AUTOMATIC: @@ -1359,14 +1358,6 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, return -EINVAL; local->user_power_level = dbm; break; - case TX_POWER_OFF: - radio_enabled = false; - break; - } - - if (radio_enabled != local->hw.conf.radio_enabled) { - changes |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; - local->hw.conf.radio_enabled = radio_enabled; } ieee80211_hw_config(local, changes); @@ -1380,12 +1371,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) *dbm = local->hw.conf.power_level; - if (!local->hw.conf.radio_enabled) - return -ENETDOWN; - return 0; } +static void ieee80211_rfkill_poll(struct wiphy *wiphy) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + drv_rfkill_poll(local); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1427,4 +1422,5 @@ struct cfg80211_ops mac80211_config_ops = { .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, + .rfkill_poll = ieee80211_rfkill_poll, }; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 3912b53..b13446a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -181,4 +181,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, sta, tid, ssn); return -EOPNOTSUPP; } + + +static inline void drv_rfkill_poll(struct ieee80211_local *local) +{ + if (local->ops->rfkill_poll) + local->ops->rfkill_poll(&local->hw); +} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8c9f1c7..b7c8a44 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -170,7 +170,7 @@ static int ieee80211_open(struct net_device *dev) goto err_del_bss; /* we're brought up, everything changes */ hw_reconf_flags = ~0; - ieee80211_led_radio(local, local->hw.conf.radio_enabled); + ieee80211_led_radio(local, true); } /* @@ -560,7 +560,7 @@ static int ieee80211_stop(struct net_device *dev) drv_stop(local); - ieee80211_led_radio(local, 0); + ieee80211_led_radio(local, false); flush_workqueue(local->hw.workqueue); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 31284c9..22f6381 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -973,7 +973,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (local->open_count) { res = drv_start(local); - ieee80211_led_radio(local, hw->conf.radio_enabled); + ieee80211_led_radio(local, true); } /* add interfaces */ diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 4500549..4428dd5 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -1,5 +1,6 @@ config CFG80211 - tristate "Improved wireless configuration API" + tristate "Improved wireless configuration API" + depends on RFKILL || !RFKILL config CFG80211_REG_DEBUG bool "cfg80211 regulatory debugging" diff --git a/net/wireless/core.c b/net/wireless/core.c index a5dbea1..3b74b88 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "nl80211.h" @@ -227,6 +228,41 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, return 0; } +static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) +{ + struct cfg80211_registered_device *drv = data; + + drv->ops->rfkill_poll(&drv->wiphy); +} + +static int cfg80211_rfkill_set_block(void *data, bool blocked) +{ + struct cfg80211_registered_device *drv = data; + struct wireless_dev *wdev; + + if (!blocked) + return 0; + + rtnl_lock(); + mutex_lock(&drv->devlist_mtx); + + list_for_each_entry(wdev, &drv->netdev_list, list) + dev_close(wdev->netdev); + + mutex_unlock(&drv->devlist_mtx); + rtnl_unlock(); + + return 0; +} + +static void cfg80211_rfkill_sync_work(struct work_struct *work) +{ + struct cfg80211_registered_device *drv; + + drv = container_of(work, struct cfg80211_registered_device, rfkill_sync); + cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); +} + /* exported functions */ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) @@ -274,6 +310,18 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) drv->wiphy.dev.class = &ieee80211_class; drv->wiphy.dev.platform_data = drv; + drv->rfkill_ops.set_block = cfg80211_rfkill_set_block; + drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev), + &drv->wiphy.dev, RFKILL_TYPE_WLAN, + &drv->rfkill_ops, drv); + + if (!drv->rfkill) { + kfree(drv); + return NULL; + } + + INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); + /* * Initialize wiphy parameters to IEEE 802.11 MIB default values. * Fragmentation and RTS threshold are disabled by default with the @@ -356,6 +404,10 @@ int wiphy_register(struct wiphy *wiphy) if (res) goto out_unlock; + res = rfkill_register(drv->rfkill); + if (res) + goto out_rm_dev; + list_add(&drv->list, &cfg80211_drv_list); /* add to debugfs */ @@ -379,16 +431,41 @@ int wiphy_register(struct wiphy *wiphy) cfg80211_debugfs_drv_add(drv); res = 0; -out_unlock: + goto out_unlock; + + out_rm_dev: + device_del(&drv->wiphy.dev); + out_unlock: mutex_unlock(&cfg80211_mutex); return res; } EXPORT_SYMBOL(wiphy_register); +void wiphy_rfkill_start_polling(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + + if (!drv->ops->rfkill_poll) + return; + drv->rfkill_ops.poll = cfg80211_rfkill_poll; + rfkill_resume_polling(drv->rfkill); +} +EXPORT_SYMBOL(wiphy_rfkill_start_polling); + +void wiphy_rfkill_stop_polling(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + + rfkill_pause_polling(drv->rfkill); +} +EXPORT_SYMBOL(wiphy_rfkill_stop_polling); + void wiphy_unregister(struct wiphy *wiphy) { struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + rfkill_unregister(drv->rfkill); + /* protect the device list */ mutex_lock(&cfg80211_mutex); @@ -425,6 +502,7 @@ EXPORT_SYMBOL(wiphy_unregister); void cfg80211_dev_free(struct cfg80211_registered_device *drv) { struct cfg80211_internal_bss *scan, *tmp; + rfkill_destroy(drv->rfkill); mutex_destroy(&drv->mtx); mutex_destroy(&drv->devlist_mtx); list_for_each_entry_safe(scan, tmp, &drv->bss_list, list) @@ -438,6 +516,15 @@ void wiphy_free(struct wiphy *wiphy) } EXPORT_SYMBOL(wiphy_free); +void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + + if (rfkill_set_hw_state(drv->rfkill, blocked)) + schedule_work(&drv->rfkill_sync); +} +EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); + static int cfg80211_netdev_notifier_call(struct notifier_block * nb, unsigned long state, void *ndev) @@ -446,7 +533,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, struct cfg80211_registered_device *rdev; if (!dev->ieee80211_ptr) - return 0; + return NOTIFY_DONE; rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); @@ -492,9 +579,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, } mutex_unlock(&rdev->devlist_mtx); break; + case NETDEV_PRE_UP: + if (rfkill_blocked(rdev->rfkill)) + return notifier_from_errno(-ERFKILL); + break; } - return 0; + return NOTIFY_DONE; } static struct notifier_block cfg80211_netdev_notifier = { diff --git a/net/wireless/core.h b/net/wireless/core.h index ab512bc..bfa340c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include "reg.h" @@ -24,6 +26,11 @@ struct cfg80211_registered_device { * any call is in progress */ struct mutex mtx; + /* rfkill support */ + struct rfkill_ops rfkill_ops; + struct rfkill *rfkill; + struct work_struct rfkill_sync; + /* ISO / IEC 3166 alpha2 for which this device is receiving * country IEs on, this can help disregard country IEs from APs * on the same alpha2 quickly. The alpha2 may differ from diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 9fbfb85..d030c53 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -764,6 +764,8 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, /* only change when not disabling */ if (!data->txpower.disabled) { + rfkill_set_sw_state(rdev->rfkill, false); + if (data->txpower.fixed) { /* * wext doesn't support negative values, see @@ -787,7 +789,9 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, } } } else { - type = TX_POWER_OFF; + rfkill_set_sw_state(rdev->rfkill, true); + schedule_work(&rdev->rfkill_sync); + return 0; } return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);; @@ -811,13 +815,12 @@ int cfg80211_wext_giwtxpower(struct net_device *dev, return -EOPNOTSUPP; err = rdev->ops->get_tx_power(wdev->wiphy, &val); - /* HACK!!! */ - if (err && err != -ENETDOWN) + if (err) return err; /* well... oh well */ data->txpower.fixed = 1; - data->txpower.disabled = err == -ENETDOWN; + data->txpower.disabled = rfkill_blocked(rdev->rfkill); data->txpower.value = val; data->txpower.flags = IW_TXPOW_DBM; -- cgit v0.10.2 From 76963bb602ba91927130a0140d5757a5969e08ac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jun 2009 13:01:42 +0200 Subject: iwm: port to new cfg80211 rfkill Which means removing all rfkill code since it only does soft-kill which cfg80211 will now handle in exactly the same way the driver did. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 41bd4b2..a907aa9 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -4,7 +4,6 @@ config IWM select WIRELESS_EXT select CFG80211 select FW_LOADER - select RFKILL config IWM_DEBUG bool "Enable full debugging output in iwmc3200wifi" diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile index 7cb415e..927f022 100644 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ b/drivers/net/wireless/iwmc3200wifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWM) := iwmc3200wifi.o iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o -iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o +iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 3b29681..635c16e 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -343,8 +343,4 @@ int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd); void iwm_rx_free(struct iwm_priv *iwm); -/* RF Kill API */ -int iwm_rfkill_init(struct iwm_priv *iwm); -void iwm_rfkill_exit(struct iwm_priv *iwm); - #endif diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index eec7201..68e2c3b 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -136,17 +136,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, wdev->netdev = ndev; - ret = iwm_rfkill_init(iwm); - if (ret) { - dev_err(dev, "Failed to init rfkill\n"); - goto out_rfkill; - } - return iwm; - out_rfkill: - unregister_netdev(ndev); - out_ndev: free_netdev(ndev); @@ -162,7 +153,6 @@ void iwm_if_free(struct iwm_priv *iwm) if (!iwm_to_ndev(iwm)) return; - iwm_rfkill_exit(iwm); unregister_netdev(iwm_to_ndev(iwm)); free_netdev(iwm_to_ndev(iwm)); iwm_wdev_free(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c deleted file mode 100644 index 8ee2c3c..0000000 --- a/drivers/net/wireless/iwmc3200wifi/rfkill.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation - * Samuel Ortiz - * Zhu Yi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include - -#include "iwm.h" - -static int iwm_rfkill_set_block(void *data, bool blocked) -{ - struct iwm_priv *iwm = data; - - if (!blocked) { - if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) - return -EBUSY; - - if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && - (iwm_to_ndev(iwm)->flags & IFF_UP)) - return iwm_up(iwm); - } else { - if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - return iwm_down(iwm); - } - - return 0; -} - -static const struct rfkill_ops iwm_rfkill_ops = { - .set_block = iwm_rfkill_set_block, -}; - -int iwm_rfkill_init(struct iwm_priv *iwm) -{ - int ret; - - iwm->rfkill = rfkill_alloc(KBUILD_MODNAME, - iwm_to_dev(iwm), - RFKILL_TYPE_WLAN, - &iwm_rfkill_ops, iwm); - if (!iwm->rfkill) { - IWM_ERR(iwm, "Unable to allocate rfkill device\n"); - return -ENOMEM; - } - - ret = rfkill_register(iwm->rfkill); - if (ret) { - IWM_ERR(iwm, "Failed to register rfkill device\n"); - goto fail; - } - - return 0; - fail: - rfkill_destroy(iwm->rfkill); - return ret; -} - -void iwm_rfkill_exit(struct iwm_priv *iwm) -{ - if (iwm->rfkill) { - rfkill_unregister(iwm->rfkill); - rfkill_destroy(iwm->rfkill); - } - iwm->rfkill = NULL; -} -- cgit v0.10.2 From 581f725ccd7e697074aa057fa86bf99b54052c95 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 2 Jun 2009 19:28:55 +0530 Subject: ath9k: Fix write callback of 'debug' which configures debug mask Handle error condition on copy_from_user() properly and make sure a NUL terminated char[] is sent to strict_strtoul() for proper conversion. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a42d631..6d20725 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -49,8 +49,9 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf, { struct ath_softc *sc = file->private_data; char buf[32]; - unsigned int len = 0; - len += snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); + unsigned int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -60,12 +61,17 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, struct ath_softc *sc = file->private_data; unsigned long mask; char buf[32]; - if (copy_from_user(buf, user_buf, (sizeof(buf) - 1) < count ? - (sizeof(buf) - 1) : count)) - return 0; - buf[sizeof(buf)-1] = 0; - if (strict_strtoul(buf, 0, &mask) == 0) - sc->debug.debug_mask = mask; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &mask)) + return -EINVAL; + + sc->debug.debug_mask = mask; return count; } -- cgit v0.10.2 From e03e5ffd8d3327d23d76be5d63cfbbb537b1af59 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 2 Jun 2009 16:30:56 -0400 Subject: ath: make regulatory parsing more verbose on debug This should help when reviewing issues regarding regulatory domain on ath5k/ath9k/ar9170. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 7a89f9f..eef370bd 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -366,11 +366,17 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) if (rd & COUNTRY_ERD_FLAG) { /* EEPROM value is a country code */ u16 cc = rd & ~COUNTRY_ERD_FLAG; + printk(KERN_DEBUG + "ath: EEPROM indicates we should expect " + "a country code\n"); for (i = 0; i < ARRAY_SIZE(allCountries); i++) if (allCountries[i].countryCode == cc) return true; } else { /* EEPROM value is a regpair value */ + if (rd != CTRY_DEFAULT) + printk(KERN_DEBUG "ath: EEPROM indicates we " + "should expect a direct regpair map\n"); for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) if (regDomainPairs[i].regDmnEnum == rd) return true; @@ -477,6 +483,11 @@ ath_regd_init(struct ath_regulatory *reg, struct country_code_to_enum_rd *country = NULL; u16 regdmn; + if (!reg) + return -EINVAL; + + printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd); + if (!ath_regd_is_eeprom_valid(reg)) { printk(KERN_ERR "ath: Invalid EEPROM contents\n"); return -EINVAL; @@ -486,20 +497,30 @@ ath_regd_init(struct ath_regulatory *reg, reg->country_code = ath_regd_get_default_country(regdmn); if (reg->country_code == CTRY_DEFAULT && - regdmn == CTRY_DEFAULT) + regdmn == CTRY_DEFAULT) { + printk(KERN_DEBUG "ath: EEPROM indicates default " + "country code should be used\n"); reg->country_code = CTRY_UNITED_STATES; + } if (reg->country_code == CTRY_DEFAULT) { country = NULL; } else { + printk(KERN_DEBUG "ath: doing EEPROM country->regdmn " + "map search\n"); country = ath_regd_find_country(reg->country_code); if (country == NULL) { printk(KERN_DEBUG - "ath: Country is NULL!!!!, cc= %d\n", + "ath: no valid country maps found for " + "country code: 0x%0x\n", reg->country_code); return -EINVAL; - } else + } else { regdmn = country->regDmnEnum; + printk(KERN_DEBUG "ath: country maps to " + "regdmn code: 0x%0x\n", + regdmn); + } } reg->regpair = ath_get_regpair(regdmn); @@ -523,7 +544,7 @@ ath_regd_init(struct ath_regulatory *reg, printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", reg->alpha2[0], reg->alpha2[1]); - printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n", + printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", reg->regpair->regDmnEnum); ath_regd_init_wiphy(reg, wiphy, reg_notifier); -- cgit v0.10.2 From 60fd2b67014440091770ac5738301c7fa4c4159c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 2 Jun 2009 16:31:10 -0400 Subject: cfg80211: make ieee80211_get_mesh_hdrlen() static Fixes spares warning: net/wireless/util.c:261:5: warning: symbol 'ieee80211_get_mesh_hdrlen' was not declared. Should it be static? Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/util.c b/net/wireless/util.c index 5be9ed7..2555069 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -258,7 +258,7 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) +static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) { int ae = meshhdr->flags & MESH_FLAGS_AE; /* 7.1.3.5a.2 */ -- cgit v0.10.2 From 7e189a12c246f55fe087efe345fe5f4cbe0be545 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 2 Jun 2009 18:38:14 -0400 Subject: mac80211: extend sta kdoc - explain when they are added Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d5611d8..a360bce 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -44,6 +44,15 @@ * When the insertion fails (sta_info_insert()) returns non-zero), the * structure will have been freed by sta_info_insert()! * + * sta entries are added by mac80211 when you establish a link with a + * peer. This means different things for the different type of interfaces + * we support. For a regular station this mean we add the AP sta when we + * receive an assocation response from the AP. For IBSS this occurs when + * we receive a probe response or a beacon from target IBSS network. For + * WDS we add the sta for the peer imediately upon device open. When using + * AP mode we add stations for each respective station upon request from + * userspace through nl80211. + * * Because there are debugfs entries for each station, and adding those * must be able to sleep, it is also possible to "pin" a station entry, * that means it can be removed from the hash table but not be freed. -- cgit v0.10.2 From 894df1cbc376310163d41c50c891db41296056bf Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 2 Jun 2009 15:43:25 -0700 Subject: mac80211: removed unused variable in ieee80211_tx() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a910148..1436f74 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1238,7 +1238,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, bool txpending) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; struct ieee80211_tx_data tx; ieee80211_tx_result res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1270,7 +1269,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, return; } - sta = tx.sta; tx.channel = local->hw.conf.channel; info->band = tx.channel->band; -- cgit v0.10.2 From 72828b1b3cabecfce4321877aa526a2bd21acf0c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 2 Jun 2009 23:03:06 -0400 Subject: ath5k: disable beacon interrupt when interface is down When we remove the active interface, there's no need to continue sending beacons; doing so would cause a null pointer deref in ieee80211_beacon_get(). Disable the interrupt in remove_interface and add a WARN_ON(!vif) in case there are other instances lurking. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ab2048b..85a00db 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2070,6 +2070,13 @@ err_unmap: return ret; } +static void ath5k_beacon_disable(struct ath5k_softc *sc) +{ + sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); + ath5k_hw_set_imr(sc->ah, sc->imask); + ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); +} + /* * Transmit a beacon frame at SWBA. Dynamic updates to the * frame contents are done as needed and the slot time is @@ -2757,6 +2764,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, goto end; ath5k_hw_set_lladdr(sc->ah, mac); + ath5k_beacon_disable(sc); sc->vif = NULL; end: mutex_unlock(&sc->lock); @@ -3060,7 +3068,14 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { int ret; struct ath5k_softc *sc = hw->priv; - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct sk_buff *skb; + + if (WARN_ON(!vif)) { + ret = -EINVAL; + goto out; + } + + skb = ieee80211_beacon_get(hw, vif); if (!skb) { ret = -ENOMEM; -- cgit v0.10.2 From 2ec2c68c11af95075f29e370970eb97c89234e2e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jun 2009 09:55:29 +0200 Subject: rfkill: always init poll delayed work The rfkill core didn't initialise the poll delayed work because it assumed that polling was always done by specifying the poll function. cfg80211, however, would like to start polling only later, which is a valid use case and easy to support, so change rfkill to always initialise the poll delayed work and thus allow starting polling by calling the rfkill_resume_polling() function after registration. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 91e9168..11b7314 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -909,16 +909,15 @@ int __must_check rfkill_register(struct rfkill *rfkill) rfkill->registered = true; - if (rfkill->ops->poll) { - INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); - schedule_delayed_work(&rfkill->poll_work, - round_jiffies_relative(POLL_INTERVAL)); - } - + INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work); - INIT_WORK(&rfkill->sync_work, rfkill_sync_work); + + if (rfkill->ops->poll) + schedule_delayed_work(&rfkill->poll_work, + round_jiffies_relative(POLL_INTERVAL)); schedule_work(&rfkill->sync_work); + rfkill_send_events(rfkill, RFKILL_OP_ADD); mutex_unlock(&rfkill_global_mutex); -- cgit v0.10.2 From f71fea23a27ba8ec53375832aab6a80fc14622e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jun 2009 10:17:59 +0200 Subject: rfkill: document /dev/rfkill Add some blurb about /dev/rfkill to the documentation and fix the "transmiter" spelling error. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index de941e3..1b74b5f 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -113,7 +113,7 @@ The following sysfs entries exist for every rfkill device: 0: RFKILL_STATE_SOFT_BLOCKED transmitter is turned off by software 1: RFKILL_STATE_UNBLOCKED - transmiter is (potentially) active + transmitter is (potentially) active 2: RFKILL_STATE_HARD_BLOCKED transmitter is forced off by something outside of the driver's control. @@ -128,3 +128,9 @@ RFKILL_TYPE The contents of these variables corresponds to the "name", "state" and "type" sysfs files explained above. + +An alternative userspace interface exists as a misc device /dev/rfkill, +which allows userspace to obtain and set the state of rfkill devices and +sets of devices. It also notifies userspace about device addition and +removal. The API is a simple read/write API that is defined in +linux/rfkill.h. -- cgit v0.10.2 From 0aa8204b46e0fb155a98074d53f8b31ca04269b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Jun 2009 18:30:31 +0200 Subject: cfg80211: fix Kconfig for users of cfg80211 * iwm doesn't depend on cfg80211 or wireless extensions * rndis wlan selects cfg80211 - needs to depend * mac80211 selects cfg80211 - needs to depend Signed-off-by: Johannes Berg Acked-by: Randy Dunlap Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8673241..daf4c80 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -333,11 +333,11 @@ config USB_ZD1201 config USB_NET_RNDIS_WLAN tristate "Wireless RNDIS USB support" depends on USB && WLAN_80211 && EXPERIMENTAL + depends on CFG80211 select USB_USBNET select USB_NET_CDCETHER select USB_NET_RNDIS_HOST select WIRELESS_EXT - select CFG80211 ---help--- This is a driver for wireless RNDIS devices. These are USB based adapters found in devices such as: diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index a907aa9..1eccb6d 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -1,8 +1,8 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" depends on MMC && WLAN_80211 && EXPERIMENTAL + depends on CFG80211 select WIRELESS_EXT - select CFG80211 select FW_LOADER config IWM_DEBUG diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 9cbf545..ba2643a 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -1,16 +1,19 @@ config MAC80211 tristate "Generic IEEE 802.11 Networking Stack (mac80211)" + depends on CFG80211 select CRYPTO select CRYPTO_ECB select CRYPTO_ARC4 select CRYPTO_AES select CRC32 select WIRELESS_EXT - select CFG80211 ---help--- This option enables the hardware independent IEEE 802.11 networking stack. +comment "CFG80211 needs to be enabled for MAC80211" + depends on CFG80211=n + config MAC80211_DEFAULT_PS bool "enable powersave by default" depends on MAC80211 -- cgit v0.10.2 From 4e8a301929bfa017e6ffe11e3cf78ccaf8492801 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 2 Jun 2009 14:23:59 +0200 Subject: ocfs2: Fix possible deadlock in ocfs2_global_read_dquot() It is not possible to get a read lock and then try to get the same write lock in one thread as that can block on downconvert being requested by other node leading to deadlock. So first drop the quota lock for reading and only after that get it for writing. Signed-off-by: Jan Kara Signed-off-by: Joel Becker diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index 1ed0f7c..edfa60c 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c @@ -421,6 +421,7 @@ int ocfs2_global_read_dquot(struct dquot *dquot) OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes; if (!dquot->dq_off) { /* No real quota entry? */ /* Upgrade to exclusive lock for allocation */ + ocfs2_qinfo_unlock(info, 0); err = ocfs2_qinfo_lock(info, 1); if (err < 0) goto out_qlock; @@ -435,7 +436,8 @@ int ocfs2_global_read_dquot(struct dquot *dquot) out_qlock: if (ex) ocfs2_qinfo_unlock(info, 1); - ocfs2_qinfo_unlock(info, 0); + else + ocfs2_qinfo_unlock(info, 0); out: if (err < 0) mlog_errno(err); -- cgit v0.10.2 From b4c30de39a2596503e888a7b47d19792f25913d6 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 2 Jun 2009 14:24:00 +0200 Subject: ocfs2: Fix lock inversion in ocfs2_local_read_info() This function is called with dqio_mutex held but it has to acquire lock from global quota file which ranks above this lock. This is not deadlockable lock inversion since this code path is take only during mount when noone else can race with us but let's clean this up to silence lockdep. We just drop the dqio_mutex in the beginning of the function and reacquire it in the end since we don't need it - noone can race with us at this moment. Signed-off-by: Jan Kara Signed-off-by: Joel Becker diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index 07deec5..71cf410 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -655,6 +655,9 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) struct ocfs2_quota_recovery *rec; int locked = 0; + /* We don't need the lock and we have to acquire quota file locks + * which will later depend on this lock */ + mutex_unlock(&sb_dqopt(sb)->dqio_mutex); info->dqi_maxblimit = 0x7fffffffffffffffLL; info->dqi_maxilimit = 0x7fffffffffffffffLL; oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); @@ -733,6 +736,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) goto out_err; } + mutex_lock(&sb_dqopt(sb)->dqio_mutex); return 0; out_err: if (oinfo) { @@ -746,6 +750,7 @@ out_err: kfree(oinfo); } brelse(bh); + mutex_lock(&sb_dqopt(sb)->dqio_mutex); return -1; } -- cgit v0.10.2 From 65bac575e35915801ea518b9d8d8824367d125c8 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 2 Jun 2009 14:24:01 +0200 Subject: ocfs2: Fix possible deadlock with quotas in ocfs2_setattr() We called vfs_dq_transfer() with global quota file lock held. This can lead to deadlocks as if vfs_dq_transfer() has to allocate new quota structure, it calls ocfs2_dquot_acquire() which tries to get quota file lock again and this can block if another node requested the lock in the mean time. Since we have to call vfs_dq_transfer() with transaction already started and quota file lock ranks above the transaction start, we cannot just rely on ocfs2_dquot_acquire() or ocfs2_dquot_release() on getting the lock if they need it. We fix the problem by acquiring pointers to all quota structures needed by vfs_dq_transfer() already before calling the function. By this we are sure that all quota structures are properly allocated and they can be freed only after we drop references to them. Thus we don't need quota file lock anywhere inside vfs_dq_transfer(). Signed-off-by: Jan Kara Signed-off-by: Joel Becker diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index c2a87c8..1a96cac 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -894,9 +894,9 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) struct ocfs2_super *osb = OCFS2_SB(sb); struct buffer_head *bh = NULL; handle_t *handle = NULL; - int locked[MAXQUOTAS] = {0, 0}; - int credits, qtype; - struct ocfs2_mem_dqinfo *oinfo; + int qtype; + struct dquot *transfer_from[MAXQUOTAS] = { }; + struct dquot *transfer_to[MAXQUOTAS] = { }; mlog_entry("(0x%p, '%.*s')\n", dentry, dentry->d_name.len, dentry->d_name.name); @@ -969,30 +969,37 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { - credits = OCFS2_INODE_UPDATE_CREDITS; + /* + * Gather pointers to quota structures so that allocation / + * freeing of quota structures happens here and not inside + * vfs_dq_transfer() where we have problems with lock ordering + */ if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid && OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { - oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv; - status = ocfs2_lock_global_qf(oinfo, 1); - if (status < 0) + transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, + USRQUOTA); + transfer_from[USRQUOTA] = dqget(sb, inode->i_uid, + USRQUOTA); + if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) { + status = -ESRCH; goto bail_unlock; - credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) + - ocfs2_calc_qdel_credits(sb, USRQUOTA); - locked[USRQUOTA] = 1; + } } if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid && OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { - oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv; - status = ocfs2_lock_global_qf(oinfo, 1); - if (status < 0) + transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, + GRPQUOTA); + transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid, + GRPQUOTA); + if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) { + status = -ESRCH; goto bail_unlock; - credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) + - ocfs2_calc_qdel_credits(sb, GRPQUOTA); - locked[GRPQUOTA] = 1; + } } - handle = ocfs2_start_trans(osb, credits); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS + + 2 * ocfs2_quota_trans_credits(sb)); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -1030,12 +1037,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) bail_commit: ocfs2_commit_trans(osb, handle); bail_unlock: - for (qtype = 0; qtype < MAXQUOTAS; qtype++) { - if (!locked[qtype]) - continue; - oinfo = sb_dqinfo(sb, qtype)->dqi_priv; - ocfs2_unlock_global_qf(oinfo, 1); - } ocfs2_inode_unlock(inode, 1); bail_unlock_rw: if (size_change) @@ -1043,6 +1044,12 @@ bail_unlock_rw: bail: brelse(bh); + /* Release quota pointers in case we acquired them */ + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + dqput(transfer_to[qtype]); + dqput(transfer_from[qtype]); + } + if (!status && attr->ia_valid & ATTR_MODE) { status = ocfs2_acl_chmod(inode); if (status < 0) -- cgit v0.10.2 From 80d73f15d12f087f3fe074f8a4d6e5c5624f2b47 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 2 Jun 2009 14:24:02 +0200 Subject: ocfs2: Fix possible deadlock in quota recovery In ocfs2_finish_quota_recovery() we acquired global quota file lock and started recovering local quota file. During this process we need to get quota structures, which calls ocfs2_dquot_acquire() which gets global quota file lock again. This second lock can block in case some other node has requested the quota file lock in the mean time. Fix the problem by moving quota file locking down into the function where it is really needed. Then dqget() or dqput() won't be called with the lock held. Signed-off-by: Jan Kara Signed-off-by: Joel Becker diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index 71cf410..5a460fa 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -444,10 +444,6 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type); - status = ocfs2_lock_global_qf(oinfo, 1); - if (status < 0) - goto out; - list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) { chunk = rchunk->rc_chunk; hbh = NULL; @@ -480,12 +476,18 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, type); goto out_put_bh; } + status = ocfs2_lock_global_qf(oinfo, 1); + if (status < 0) { + mlog_errno(status); + goto out_put_dquot; + } + handle = ocfs2_start_trans(OCFS2_SB(sb), OCFS2_QSYNC_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); - goto out_put_dquot; + goto out_drop_lock; } mutex_lock(&sb_dqopt(sb)->dqio_mutex); spin_lock(&dq_data_lock); @@ -523,6 +525,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, out_commit: mutex_unlock(&sb_dqopt(sb)->dqio_mutex); ocfs2_commit_trans(OCFS2_SB(sb), handle); +out_drop_lock: + ocfs2_unlock_global_qf(oinfo, 1); out_put_dquot: dqput(dquot); out_put_bh: @@ -537,8 +541,6 @@ out_put_bh: if (status < 0) break; } - ocfs2_unlock_global_qf(oinfo, 1); -out: if (status < 0) free_recovery_list(&(rec->r_list[type])); mlog_exit(status); -- cgit v0.10.2 From edd45c08499a3e9d4c25431cd2b6a9ce5f692c92 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 2 Jun 2009 14:24:03 +0200 Subject: ocfs2: Correct ordering of ip_alloc_sem and localloc locks for directories We use ordering ip_alloc_sem -> local alloc locks in ocfs2_write_begin(). So change lock ordering in ocfs2_extend_dir() and ocfs2_expand_inline_dir() to also use this lock ordering. Signed-off-by: Jan Kara Acked-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index c575230..b358f3b 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -2900,6 +2900,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, alloc = ocfs2_clusters_for_bytes(sb, bytes); dx_alloc = 0; + down_write(&oi->ip_alloc_sem); + if (ocfs2_supports_indexed_dirs(osb)) { credits += ocfs2_add_dir_index_credits(sb); @@ -2940,8 +2942,6 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, goto out; } - down_write(&oi->ip_alloc_sem); - /* * Prepare for worst case allocation scenario of two separate * extents in the unindexed tree. @@ -2953,7 +2953,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, if (IS_ERR(handle)) { ret = PTR_ERR(handle); mlog_errno(ret); - goto out_sem; + goto out; } if (vfs_dq_alloc_space_nodirty(dir, @@ -3172,10 +3172,8 @@ out_commit: ocfs2_commit_trans(osb, handle); -out_sem: - up_write(&oi->ip_alloc_sem); - out: + up_write(&oi->ip_alloc_sem); if (data_ac) ocfs2_free_alloc_context(data_ac); if (meta_ac) @@ -3322,11 +3320,15 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, brelse(new_bh); new_bh = NULL; + down_write(&OCFS2_I(dir)->ip_alloc_sem); + drop_alloc_sem = 1; dir_i_size = i_size_read(dir); credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; goto do_extend; } + down_write(&OCFS2_I(dir)->ip_alloc_sem); + drop_alloc_sem = 1; dir_i_size = i_size_read(dir); mlog(0, "extending dir %llu (i_size = %lld)\n", (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size); @@ -3370,9 +3372,6 @@ do_extend: credits++; /* For attaching the new dirent block to the * dx_root */ - down_write(&OCFS2_I(dir)->ip_alloc_sem); - drop_alloc_sem = 1; - handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); @@ -3435,10 +3434,10 @@ bail_bh: *new_de_bh = new_bh; get_bh(*new_de_bh); bail: - if (drop_alloc_sem) - up_write(&OCFS2_I(dir)->ip_alloc_sem); if (handle) ocfs2_commit_trans(osb, handle); + if (drop_alloc_sem) + up_write(&OCFS2_I(dir)->ip_alloc_sem); if (data_ac) ocfs2_free_alloc_context(data_ac); -- cgit v0.10.2 From 83273932fbefb6ceef9c0b82ac4d23900728f4d9 Mon Sep 17 00:00:00 2001 From: Srinivas Eeda Date: Wed, 3 Jun 2009 17:02:55 -0700 Subject: ocfs2: timer to queue scan of all orphan slots When a dentry is unlinked, the unlinking node takes an EX on the dentry lock before moving the dentry to the orphan directory. Other nodes that have this dentry in cache have a PR on the same dentry lock. When the EX is requested, the other nodes flag the corresponding inode as MAYBE_ORPHANED during downconvert. The inode is finally deleted when the last node to iput the inode sees that i_nlink==0 and the MAYBE_ORPHANED flag is set. A problem arises if a node is forced to free dentry locks because of memory pressure. If this happens, the node will no longer get downconvert notifications for the dentries that have been unlinked on another node. If it also happens that node is actively using the corresponding inode and happens to be the one performing the last iput on that inode, it will fail to delete the inode as it will not have the MAYBE_ORPHANED flag set. This patch fixes this shortcoming by introducing a periodic scan of the orphan directories to delete such inodes. Care has been taken to distribute the workload across the cluster so that no one node has to perform the task all the time. Signed-off-by: Srinivas Eeda Signed-off-by: Joel Becker diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index e15fc7d..6cdeaa7 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -248,6 +248,10 @@ static struct ocfs2_lock_res_ops ocfs2_nfs_sync_lops = { .flags = 0, }; +static struct ocfs2_lock_res_ops ocfs2_orphan_scan_lops = { + .flags = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB, +}; + static struct ocfs2_lock_res_ops ocfs2_dentry_lops = { .get_osb = ocfs2_get_dentry_osb, .post_unlock = ocfs2_dentry_post_unlock, @@ -637,6 +641,19 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res, &ocfs2_nfs_sync_lops, osb); } +static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res, + struct ocfs2_super *osb) +{ + struct ocfs2_orphan_scan_lvb *lvb; + + ocfs2_lock_res_init_once(res); + ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name); + ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN, + &ocfs2_orphan_scan_lops, osb); + lvb = ocfs2_dlm_lvb(&res->l_lksb); + lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; +} + void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, struct ocfs2_file_private *fp) { @@ -2352,6 +2369,37 @@ void ocfs2_inode_unlock(struct inode *inode, mlog_exit_void(); } +int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex) +{ + struct ocfs2_lock_res *lockres; + struct ocfs2_orphan_scan_lvb *lvb; + int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; + int status = 0; + + lockres = &osb->osb_orphan_scan.os_lockres; + status = ocfs2_cluster_lock(osb, lockres, level, 0, 0); + if (status < 0) + return status; + + lvb = ocfs2_dlm_lvb(&lockres->l_lksb); + if (lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION) + *seqno = be32_to_cpu(lvb->lvb_os_seqno); + return status; +} + +void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex) +{ + struct ocfs2_lock_res *lockres; + struct ocfs2_orphan_scan_lvb *lvb; + int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; + + lockres = &osb->osb_orphan_scan.os_lockres; + lvb = ocfs2_dlm_lvb(&lockres->l_lksb); + lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; + lvb->lvb_os_seqno = cpu_to_be32(seqno); + ocfs2_cluster_unlock(osb, lockres, level); +} + int ocfs2_super_lock(struct ocfs2_super *osb, int ex) { @@ -2842,6 +2890,7 @@ local: ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb); ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb); ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb); + ocfs2_orphan_scan_lock_res_init(&osb->osb_orphan_scan.os_lockres, osb); osb->cconn = conn; @@ -2878,6 +2927,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb, ocfs2_lock_res_free(&osb->osb_super_lockres); ocfs2_lock_res_free(&osb->osb_rename_lockres); ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres); + ocfs2_lock_res_free(&osb->osb_orphan_scan.os_lockres); ocfs2_cluster_disconnect(osb->cconn, hangup_pending); osb->cconn = NULL; @@ -3061,6 +3111,7 @@ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb) ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres); ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres); ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres); + ocfs2_simple_drop_lockres(osb, &osb->osb_orphan_scan.os_lockres); } int ocfs2_drop_inode_locks(struct inode *inode) diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index e1fd572..31b90d7 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h @@ -62,6 +62,14 @@ struct ocfs2_qinfo_lvb { __be32 lvb_free_entry; }; +#define OCFS2_ORPHAN_LVB_VERSION 1 + +struct ocfs2_orphan_scan_lvb { + __u8 lvb_version; + __u8 lvb_reserved[3]; + __be32 lvb_os_seqno; +}; + /* ocfs2_inode_lock_full() 'arg_flags' flags */ /* don't wait on recovery. */ #define OCFS2_META_LOCK_RECOVERY (0x01) @@ -113,6 +121,9 @@ int ocfs2_super_lock(struct ocfs2_super *osb, int ex); void ocfs2_super_unlock(struct ocfs2_super *osb, int ex); +int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex); +void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex); + int ocfs2_rename_lock(struct ocfs2_super *osb); void ocfs2_rename_unlock(struct ocfs2_super *osb); int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex); diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index a20a0f1..44ed768 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #define MLOG_MASK_PREFIX ML_JOURNAL #include @@ -52,6 +54,8 @@ DEFINE_SPINLOCK(trans_inc_lock); +#define ORPHAN_SCAN_SCHEDULE_TIMEOUT 300000 + static int ocfs2_force_read_journal(struct inode *inode); static int ocfs2_recover_node(struct ocfs2_super *osb, int node_num, int slot_num); @@ -1841,6 +1845,109 @@ bail: return status; } +/* + * Scan timer should get fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT. Add some + * randomness to the timeout to minimize multple nodes firing the timer at the + * same time. + */ +static inline unsigned long ocfs2_orphan_scan_timeout(void) +{ + unsigned long time; + + get_random_bytes(&time, sizeof(time)); + time = ORPHAN_SCAN_SCHEDULE_TIMEOUT + (time % 5000); + return msecs_to_jiffies(time); +} + +/* + * ocfs2_queue_orphan_scan calls ocfs2_queue_recovery_completion for + * every slot, queuing a recovery of the slot on the ocfs2_wq thread. This + * is done to catch any orphans that are left over in orphan directories. + * + * ocfs2_queue_orphan_scan gets called every ORPHAN_SCAN_SCHEDULE_TIMEOUT + * seconds. It gets an EX lock on os_lockres and checks sequence number + * stored in LVB. If the sequence number has changed, it means some other + * node has done the scan. This node skips the scan and tracks the + * sequence number. If the sequence number didn't change, it means a scan + * hasn't happened. The node queues a scan and increments the + * sequence number in the LVB. + */ +void ocfs2_queue_orphan_scan(struct ocfs2_super *osb) +{ + struct ocfs2_orphan_scan *os; + int status, i; + u32 seqno = 0; + + os = &osb->osb_orphan_scan; + + status = ocfs2_orphan_scan_lock(osb, &seqno, DLM_LOCK_EX); + if (status < 0) { + if (status != -EAGAIN) + mlog_errno(status); + goto out; + } + + if (os->os_seqno != seqno) { + os->os_seqno = seqno; + goto unlock; + } + + for (i = 0; i < osb->max_slots; i++) + ocfs2_queue_recovery_completion(osb->journal, i, NULL, NULL, + NULL); + /* + * We queued a recovery on orphan slots, increment the sequence + * number and update LVB so other node will skip the scan for a while + */ + seqno++; +unlock: + ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX); +out: + return; +} + +/* Worker task that gets fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT millsec */ +void ocfs2_orphan_scan_work(struct work_struct *work) +{ + struct ocfs2_orphan_scan *os; + struct ocfs2_super *osb; + + os = container_of(work, struct ocfs2_orphan_scan, + os_orphan_scan_work.work); + osb = os->os_osb; + + mutex_lock(&os->os_lock); + ocfs2_queue_orphan_scan(osb); + schedule_delayed_work(&os->os_orphan_scan_work, + ocfs2_orphan_scan_timeout()); + mutex_unlock(&os->os_lock); +} + +void ocfs2_orphan_scan_stop(struct ocfs2_super *osb) +{ + struct ocfs2_orphan_scan *os; + + os = &osb->osb_orphan_scan; + mutex_lock(&os->os_lock); + cancel_delayed_work(&os->os_orphan_scan_work); + mutex_unlock(&os->os_lock); +} + +int ocfs2_orphan_scan_init(struct ocfs2_super *osb) +{ + struct ocfs2_orphan_scan *os; + + os = &osb->osb_orphan_scan; + os->os_osb = osb; + mutex_init(&os->os_lock); + + INIT_DELAYED_WORK(&os->os_orphan_scan_work, + ocfs2_orphan_scan_work); + schedule_delayed_work(&os->os_orphan_scan_work, + ocfs2_orphan_scan_timeout()); + return 0; +} + struct ocfs2_orphan_filldir_priv { struct inode *head; struct ocfs2_super *osb; diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index eb7b763..61045ee 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -144,6 +144,10 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb, } /* Exported only for the journal struct init code in super.c. Do not call. */ +int ocfs2_orphan_scan_init(struct ocfs2_super *osb); +void ocfs2_orphan_scan_stop(struct ocfs2_super *osb); +void ocfs2_orphan_scan_exit(struct ocfs2_super *osb); + void ocfs2_complete_recovery(struct work_struct *work); void ocfs2_wait_for_recovery(struct ocfs2_super *osb); diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 1386281..1fde52c 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -151,6 +151,14 @@ struct ocfs2_lock_res { #endif }; +struct ocfs2_orphan_scan { + struct mutex os_lock; + struct ocfs2_super *os_osb; + struct ocfs2_lock_res os_lockres; /* lock to synchronize scans */ + struct delayed_work os_orphan_scan_work; + u32 os_seqno; /* incremented on every scan */ +}; + struct ocfs2_dlm_debug { struct kref d_refcnt; struct dentry *d_locking_state; @@ -341,6 +349,8 @@ struct ocfs2_super unsigned int *osb_orphan_wipes; wait_queue_head_t osb_wipe_event; + struct ocfs2_orphan_scan osb_orphan_scan; + /* used to protect metaecc calculation check of xattr. */ spinlock_t osb_xattr_lock; diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h index a53ce87..fcdba09 100644 --- a/fs/ocfs2/ocfs2_lockid.h +++ b/fs/ocfs2/ocfs2_lockid.h @@ -48,6 +48,7 @@ enum ocfs2_lock_type { OCFS2_LOCK_TYPE_FLOCK, OCFS2_LOCK_TYPE_QINFO, OCFS2_LOCK_TYPE_NFS_SYNC, + OCFS2_LOCK_TYPE_ORPHAN_SCAN, OCFS2_NUM_LOCK_TYPES }; @@ -85,6 +86,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type) case OCFS2_LOCK_TYPE_NFS_SYNC: c = 'Y'; break; + case OCFS2_LOCK_TYPE_ORPHAN_SCAN: + c = 'P'; + break; default: c = '\0'; } @@ -104,6 +108,7 @@ static char *ocfs2_lock_type_strings[] = { [OCFS2_LOCK_TYPE_OPEN] = "Open", [OCFS2_LOCK_TYPE_FLOCK] = "Flock", [OCFS2_LOCK_TYPE_QINFO] = "Quota", + [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan", }; static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 79ff8d9..44ac27e 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1802,6 +1802,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) ocfs2_truncate_log_shutdown(osb); + ocfs2_orphan_scan_stop(osb); + /* This will disable recovery and flush any recovery work. */ ocfs2_recovery_exit(osb); @@ -1957,6 +1959,13 @@ static int ocfs2_initialize_super(struct super_block *sb, goto bail; } + status = ocfs2_orphan_scan_init(osb); + if (status) { + mlog(ML_ERROR, "Unable to initialize delayed orphan scan\n"); + mlog_errno(status); + goto bail; + } + init_waitqueue_head(&osb->checkpoint_event); atomic_set(&osb->needs_checkpoint, 0); -- cgit v0.10.2 From 15633a220ffe74fc61bc8117e6a89a494011ea3d Mon Sep 17 00:00:00 2001 From: Srinivas Eeda Date: Wed, 3 Jun 2009 17:02:56 -0700 Subject: ocfs2 patch to track delayed orphan scan timer statistics Patch to track delayed orphan scan timer statistics. Modifies ocfs2_osb_dump to print the following: Orphan Scan=> Local: 10 Global: 21 Last Scan: 67 seconds ago Signed-off-by: Srinivas Eeda Signed-off-by: Joel Becker diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 44ed768..4a3b9e6 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -1900,6 +1900,8 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb) * number and update LVB so other node will skip the scan for a while */ seqno++; + os->os_count++; + os->os_scantime = CURRENT_TIME; unlock: ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX); out: @@ -1939,6 +1941,8 @@ int ocfs2_orphan_scan_init(struct ocfs2_super *osb) os = &osb->osb_orphan_scan; os->os_osb = osb; + os->os_count = 0; + os->os_scantime = CURRENT_TIME; mutex_init(&os->os_lock); INIT_DELAYED_WORK(&os->os_orphan_scan_work, diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 1fde52c..ab285be 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -156,7 +156,9 @@ struct ocfs2_orphan_scan { struct ocfs2_super *os_osb; struct ocfs2_lock_res os_lockres; /* lock to synchronize scans */ struct delayed_work os_orphan_scan_work; - u32 os_seqno; /* incremented on every scan */ + struct timespec os_scantime; /* time this node ran the scan */ + u32 os_count; /* tracks node specific scans */ + u32 os_seqno; /* tracks cluster wide scans */ }; struct ocfs2_dlm_debug { diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 44ac27e..d05f3ca 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -208,6 +208,7 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) int i; struct ocfs2_cluster_connection *cconn = osb->cconn; struct ocfs2_recovery_map *rm = osb->recovery_map; + struct ocfs2_orphan_scan *os; out += snprintf(buf + out, len - out, "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", @@ -309,6 +310,13 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) i, osb->slot_recovery_generations[i]); } + os = &osb->osb_orphan_scan; + out += snprintf(buf + out, len - out, "Orphan Scan=> "); + out += snprintf(buf + out, len - out, "Local: %u Global: %u ", + os->os_count, os->os_seqno); + out += snprintf(buf + out, len - out, " Last Scan: %lu seconds ago\n", + (get_seconds() - os->os_scantime.tv_sec)); + return out; } -- cgit v0.10.2 From 73be192b17e43b6dc4f492dab41d70ab5b9d2908 Mon Sep 17 00:00:00 2001 From: Joel Becker Date: Tue, 6 Jan 2009 14:57:08 -0800 Subject: ocfs2: Add statistics for the checksum and ecc operations. It would be nice to know how often we get checksum failures. Even better, how many of them we can fix with the single bit ecc. So, we add a statistics structure. The structure can be installed into debugfs wherever the user wants. For ocfs2, we'll put it in the superblock-specific debugfs directory and pass it down from our higher-level functions. The stats are only registered with debugfs when the filesystem supports metadata ecc. Signed-off-by: Joel Becker diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c index 2a947c4..a1163b8 100644 --- a/fs/ocfs2/blockcheck.c +++ b/fs/ocfs2/blockcheck.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -222,6 +225,155 @@ void ocfs2_hamming_fix_block(void *data, unsigned int blocksize, ocfs2_hamming_fix(data, blocksize * 8, 0, fix); } + +/* + * Debugfs handling. + */ + +#ifdef CONFIG_DEBUG_FS + +static int blockcheck_u64_get(void *data, u64 *val) +{ + *val = *(u64 *)data; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n"); + +static struct dentry *blockcheck_debugfs_create(const char *name, + struct dentry *parent, + u64 *value) +{ + return debugfs_create_file(name, S_IFREG | S_IRUSR, parent, value, + &blockcheck_fops); +} + +static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats) +{ + if (stats) { + debugfs_remove(stats->b_debug_check); + stats->b_debug_check = NULL; + debugfs_remove(stats->b_debug_failure); + stats->b_debug_failure = NULL; + debugfs_remove(stats->b_debug_recover); + stats->b_debug_recover = NULL; + debugfs_remove(stats->b_debug_dir); + stats->b_debug_dir = NULL; + } +} + +static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats, + struct dentry *parent) +{ + int rc = -EINVAL; + + if (!stats) + goto out; + + stats->b_debug_dir = debugfs_create_dir("blockcheck", parent); + if (!stats->b_debug_dir) + goto out; + + stats->b_debug_check = + blockcheck_debugfs_create("blocks_checked", + stats->b_debug_dir, + &stats->b_check_count); + + stats->b_debug_failure = + blockcheck_debugfs_create("checksums_failed", + stats->b_debug_dir, + &stats->b_failure_count); + + stats->b_debug_recover = + blockcheck_debugfs_create("ecc_recoveries", + stats->b_debug_dir, + &stats->b_recover_count); + if (stats->b_debug_check && stats->b_debug_failure && + stats->b_debug_recover) + rc = 0; + +out: + if (rc) + ocfs2_blockcheck_debug_remove(stats); + return rc; +} +#else +static inline int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats, + struct dentry *parent) +{ + return 0; +} + +static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +/* Always-called wrappers for starting and stopping the debugfs files */ +int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats, + struct dentry *parent) +{ + return ocfs2_blockcheck_debug_install(stats, parent); +} + +void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats) +{ + ocfs2_blockcheck_debug_remove(stats); +} + +static void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats) +{ + u64 new_count; + + if (!stats) + return; + + spin_lock(&stats->b_lock); + stats->b_check_count++; + new_count = stats->b_check_count; + spin_unlock(&stats->b_lock); + + if (!new_count) + mlog(ML_NOTICE, "Block check count has wrapped\n"); +} + +static void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats *stats) +{ + u64 new_count; + + if (!stats) + return; + + spin_lock(&stats->b_lock); + stats->b_failure_count++; + new_count = stats->b_failure_count; + spin_unlock(&stats->b_lock); + + if (!new_count) + mlog(ML_NOTICE, "Checksum failure count has wrapped\n"); +} + +static void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats *stats) +{ + u64 new_count; + + if (!stats) + return; + + spin_lock(&stats->b_lock); + stats->b_recover_count++; + new_count = stats->b_recover_count; + spin_unlock(&stats->b_lock); + + if (!new_count) + mlog(ML_NOTICE, "ECC recovery count has wrapped\n"); +} + + + +/* + * These are the low-level APIs for using the ocfs2_block_check structure. + */ + /* * This function generates check information for a block. * data is the block to be checked. bc is a pointer to the @@ -266,12 +418,15 @@ void ocfs2_block_check_compute(void *data, size_t blocksize, * Again, the data passed in should be the on-disk endian. */ int ocfs2_block_check_validate(void *data, size_t blocksize, - struct ocfs2_block_check *bc) + struct ocfs2_block_check *bc, + struct ocfs2_blockcheck_stats *stats) { int rc = 0; struct ocfs2_block_check check; u32 crc, ecc; + ocfs2_blockcheck_inc_check(stats); + check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); check.bc_ecc = le16_to_cpu(bc->bc_ecc); @@ -282,6 +437,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, if (crc == check.bc_crc32e) goto out; + ocfs2_blockcheck_inc_failure(stats); mlog(ML_ERROR, "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", (unsigned int)check.bc_crc32e, (unsigned int)crc); @@ -292,8 +448,10 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, /* And check the crc32 again */ crc = crc32_le(~0, data, blocksize); - if (crc == check.bc_crc32e) + if (crc == check.bc_crc32e) { + ocfs2_blockcheck_inc_recover(stats); goto out; + } mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", (unsigned int)check.bc_crc32e, (unsigned int)crc); @@ -366,7 +524,8 @@ void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr, * Again, the data passed in should be the on-disk endian. */ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, - struct ocfs2_block_check *bc) + struct ocfs2_block_check *bc, + struct ocfs2_blockcheck_stats *stats) { int i, rc = 0; struct ocfs2_block_check check; @@ -377,6 +536,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, if (!nr) return 0; + ocfs2_blockcheck_inc_check(stats); + check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); check.bc_ecc = le16_to_cpu(bc->bc_ecc); @@ -388,6 +549,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, if (crc == check.bc_crc32e) goto out; + ocfs2_blockcheck_inc_failure(stats); mlog(ML_ERROR, "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", (unsigned int)check.bc_crc32e, (unsigned int)crc); @@ -416,8 +578,10 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, /* And check the crc32 again */ for (i = 0, crc = ~0; i < nr; i++) crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); - if (crc == check.bc_crc32e) + if (crc == check.bc_crc32e) { + ocfs2_blockcheck_inc_recover(stats); goto out; + } mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", (unsigned int)check.bc_crc32e, (unsigned int)crc); @@ -448,9 +612,11 @@ int ocfs2_validate_meta_ecc(struct super_block *sb, void *data, struct ocfs2_block_check *bc) { int rc = 0; + struct ocfs2_super *osb = OCFS2_SB(sb); - if (ocfs2_meta_ecc(OCFS2_SB(sb))) - rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc); + if (ocfs2_meta_ecc(osb)) + rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc, + &osb->osb_ecc_stats); return rc; } @@ -468,9 +634,11 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb, struct ocfs2_block_check *bc) { int rc = 0; + struct ocfs2_super *osb = OCFS2_SB(sb); - if (ocfs2_meta_ecc(OCFS2_SB(sb))) - rc = ocfs2_block_check_validate_bhs(bhs, nr, bc); + if (ocfs2_meta_ecc(osb)) + rc = ocfs2_block_check_validate_bhs(bhs, nr, bc, + &osb->osb_ecc_stats); return rc; } diff --git a/fs/ocfs2/blockcheck.h b/fs/ocfs2/blockcheck.h index 70ec3fe..d4b69fe 100644 --- a/fs/ocfs2/blockcheck.h +++ b/fs/ocfs2/blockcheck.h @@ -21,6 +21,24 @@ #define OCFS2_BLOCKCHECK_H +/* Count errors and error correction from blockcheck.c */ +struct ocfs2_blockcheck_stats { + spinlock_t b_lock; + u64 b_check_count; /* Number of blocks we've checked */ + u64 b_failure_count; /* Number of failed checksums */ + u64 b_recover_count; /* Number of blocks fixed by ecc */ + + /* + * debugfs entries, used if this is passed to + * ocfs2_blockcheck_stats_debugfs_install() + */ + struct dentry *b_debug_dir; /* Parent of the debugfs files */ + struct dentry *b_debug_check; /* Exposes b_check_count */ + struct dentry *b_debug_failure; /* Exposes b_failure_count */ + struct dentry *b_debug_recover; /* Exposes b_recover_count */ +}; + + /* High level block API */ void ocfs2_compute_meta_ecc(struct super_block *sb, void *data, struct ocfs2_block_check *bc); @@ -37,11 +55,18 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb, void ocfs2_block_check_compute(void *data, size_t blocksize, struct ocfs2_block_check *bc); int ocfs2_block_check_validate(void *data, size_t blocksize, - struct ocfs2_block_check *bc); + struct ocfs2_block_check *bc, + struct ocfs2_blockcheck_stats *stats); void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr, struct ocfs2_block_check *bc); int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, - struct ocfs2_block_check *bc); + struct ocfs2_block_check *bc, + struct ocfs2_blockcheck_stats *stats); + +/* Debug Initialization */ +int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats, + struct dentry *parent); +void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats); /* * Hamming code functions diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index ab285be..18c1d9e 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -47,6 +47,9 @@ #include "ocfs2_fs.h" #include "ocfs2_lockid.h" +/* For struct ocfs2_blockcheck_stats */ +#include "blockcheck.h" + /* Most user visible OCFS2 inodes will have very few pieces of * metadata, but larger files (including bitmaps, etc) must be taken * into account when designing an access scheme. We allow a small @@ -305,6 +308,7 @@ struct ocfs2_super struct ocfs2_dinode *local_alloc_copy; struct ocfs2_quota_recovery *quota_rec; + struct ocfs2_blockcheck_stats osb_ecc_stats; struct ocfs2_alloc_stats alloc_stats; char dev_str[20]; /* "major,minor" of the device */ diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index d05f3ca..86f500c 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -118,10 +118,12 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb); static int ocfs2_check_volume(struct ocfs2_super *osb); static int ocfs2_verify_volume(struct ocfs2_dinode *di, struct buffer_head *bh, - u32 sectsize); + u32 sectsize, + struct ocfs2_blockcheck_stats *stats); static int ocfs2_initialize_super(struct super_block *sb, struct buffer_head *bh, - int sector_size); + int sector_size, + struct ocfs2_blockcheck_stats *stats); static int ocfs2_get_sector(struct super_block *sb, struct buffer_head **bh, int block, @@ -711,7 +713,8 @@ out: static int ocfs2_sb_probe(struct super_block *sb, struct buffer_head **bh, - int *sector_size) + int *sector_size, + struct ocfs2_blockcheck_stats *stats) { int status, tmpstat; struct ocfs1_vol_disk_hdr *hdr; @@ -777,7 +780,8 @@ static int ocfs2_sb_probe(struct super_block *sb, goto bail; } di = (struct ocfs2_dinode *) (*bh)->b_data; - status = ocfs2_verify_volume(di, *bh, blksize); + memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats)); + status = ocfs2_verify_volume(di, *bh, blksize, stats); if (status >= 0) goto bail; brelse(*bh); @@ -983,6 +987,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) struct ocfs2_super *osb = NULL; struct buffer_head *bh = NULL; char nodestr[8]; + struct ocfs2_blockcheck_stats stats; mlog_entry("%p, %p, %i", sb, data, silent); @@ -992,13 +997,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) } /* probe for superblock */ - status = ocfs2_sb_probe(sb, &bh, §or_size); + status = ocfs2_sb_probe(sb, &bh, §or_size, &stats); if (status < 0) { mlog(ML_ERROR, "superblock probe failed!\n"); goto read_super_error; } - status = ocfs2_initialize_super(sb, bh, sector_size); + status = ocfs2_initialize_super(sb, bh, sector_size, &stats); osb = OCFS2_SB(sb); if (status < 0) { mlog_errno(status); @@ -1108,6 +1113,18 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } + if (ocfs2_meta_ecc(osb)) { + status = ocfs2_blockcheck_stats_debugfs_install( + &osb->osb_ecc_stats, + osb->osb_debug_root); + if (status) { + mlog(ML_ERROR, + "Unable to create blockcheck statistics " + "files\n"); + goto read_super_error; + } + } + status = ocfs2_mount_volume(sb); if (osb->root_inode) inode = igrab(osb->root_inode); @@ -1849,6 +1866,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) if (osb->cconn) ocfs2_dlm_shutdown(osb, hangup_needed); + ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats); debugfs_remove(osb->osb_debug_root); if (hangup_needed) @@ -1896,7 +1914,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu static int ocfs2_initialize_super(struct super_block *sb, struct buffer_head *bh, - int sector_size) + int sector_size, + struct ocfs2_blockcheck_stats *stats) { int status; int i, cbits, bbits; @@ -1955,6 +1974,9 @@ static int ocfs2_initialize_super(struct super_block *sb, atomic_set(&osb->alloc_stats.bg_allocs, 0); atomic_set(&osb->alloc_stats.bg_extends, 0); + /* Copy the blockcheck stats from the superblock probe */ + osb->osb_ecc_stats = *stats; + ocfs2_init_node_maps(osb); snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u", @@ -2192,7 +2214,8 @@ bail: */ static int ocfs2_verify_volume(struct ocfs2_dinode *di, struct buffer_head *bh, - u32 blksz) + u32 blksz, + struct ocfs2_blockcheck_stats *stats) { int status = -EAGAIN; @@ -2205,7 +2228,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di, OCFS2_FEATURE_INCOMPAT_META_ECC) { status = ocfs2_block_check_validate(bh->b_data, bh->b_size, - &di->i_check); + &di->i_check, + stats); if (status) goto out; } -- cgit v0.10.2 From 06c59bb896ce23c56829f6acf667faebd51dd3b8 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Tue, 19 May 2009 06:47:20 +0800 Subject: ocfs2: Remove redundant gotos in ocfs2_mount_volume() Signed-off-by: Tao Ma Signed-off-by: Joel Becker diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 86f500c..4e6b8e7 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1791,13 +1791,8 @@ static int ocfs2_mount_volume(struct super_block *sb) } status = ocfs2_truncate_log_init(osb); - if (status < 0) { + if (status < 0) mlog_errno(status); - goto leave; - } - - if (ocfs2_mount_local(osb)) - goto leave; leave: if (unlock_super) -- cgit v0.10.2 From 6ba5f9c74365263db161941b1e7467cdba06a5fe Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 3 Jun 2009 13:38:59 +0000 Subject: cxgb3: Update FW to 7.4.0 Update FW to 7.4. Bump up driver revision. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 7bf963e..9d0bd9d 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -35,10 +35,10 @@ #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb3" /* Driver version */ -#define DRV_VERSION "1.1.2-ko" +#define DRV_VERSION "1.1.3-ko" /* Firmware version */ #define FW_VERSION_MAJOR 7 -#define FW_VERSION_MINOR 1 +#define FW_VERSION_MINOR 4 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/firmware/Makefile b/firmware/Makefile index 96c3dd8..621de8e 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -41,7 +41,7 @@ fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ cxgb3/t3c_psram-1.1.0.bin \ - cxgb3/t3fw-7.1.0.bin + cxgb3/t3fw-7.4.0.bin fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \ diff --git a/firmware/WHENCE b/firmware/WHENCE index bb8fda8..0f5649a 100644 --- a/firmware/WHENCE +++ b/firmware/WHENCE @@ -412,7 +412,7 @@ Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter File: cxgb3/t3b_psram-1.1.0.bin.ihex File: cxgb3/t3c_psram-1.1.0.bin.ihex -file: cxgb3/t3fw-7.1.0.bin.ihex +file: cxgb3/t3fw-7.4.0.bin.ihex License: GPLv2 or OpenIB.org BSD license, no source visible diff --git a/firmware/cxgb3/t3fw-7.1.0.bin.ihex b/firmware/cxgb3/t3fw-7.1.0.bin.ihex deleted file mode 100644 index 1042f75..0000000 --- a/firmware/cxgb3/t3fw-7.1.0.bin.ihex +++ /dev/null @@ -1,1885 +0,0 @@ -:1000000060007400200380002003700000001000D6 -:1000100000002000E100028400070000E1000288E7 -:1000200000010000E0000000E00000A0010000006E -:1000300044444440E3000183200200002001E0002A -:100040002001FF101FFFD0001FFFC000E300043C91 -:1000500002000000200069881FFFC290200069D0C4 -:100060001FFFC29420006A101FFFC29820006A84FC -:100070001FFFC29C200003C0C00000E43100EA3131 -:1000800000A13100A03103020002ED306E2A05000C -:10009000ED3100020002160012FFDBC03014FFDA5F -:1000A000D30FD30FD30F03431F244C107249F0D347 -:1000B0000FD30FD30F12FFD5230A00240A00D30F4A -:1000C000D30FD30F03431F244C107249F0D30FD327 -:1000D0000FD30F14FFCE03421F14FFCB03421F1296 -:1000E000FFCCC0302D37302D37342D37382D373CED -:1000F000233D017233ED00020012FFC4C0302F37E0 -:10010000002F37102F37202F3730233D017233ED6A -:1001100000020012FFBEC0302737002737102737F4 -:1001200020273730233D017233ED03020012FFB95F -:1001300013FFBA0C0200932012FFB913FFB90C028F -:1001400000932012FFB8C0319320822012FFB71312 -:10015000FFB7932012FFB715FFB316FFB6C030D715 -:100160002005660160001B00000000000000000088 -:10017000043605000200D30FD30F05330C6E3B1479 -:100180000747140704437631E604360505330C6F40 -:100190003BED00020012FFA615FFA3230A00D720A3 -:1001A000070443043E0505330C0747146F3BF00377 -:1001B000020012FFA1C03014FFA1D30FD30FD30F41 -:1001C0009340B4447249F2D30FD30FD30F14FF9B63 -:1001D000834014FF9B834012FF9B230A0014FF9A65 -:1001E000D30FD30FD30F9340B4447249F2D30FD33C -:1001F0000FD30F14FF95834012FF95C92F832084DE -:10020000218522BC22743B0F8650B4559630B433FE -:100210007433F463FFE60000653FE1655FDE12FFC3 -:100220007C230A0028374028374428374828374C91 -:10023000233D017233ED03020000020012FF7AC079 -:1002400032032E0503020012FF7813FF819320C0B2 -:1002500011014931004831010200C00014FF7E0441 -:10026000D23115FF7D945014FF7D04D33115FF7CEE -:10027000945014FF7C04D43115FF7C24560014FFE5 -:100280007B04D53115FF7B24560010FF7A03000054 -:10029000000000000000000000000000000000005E -:1002A000000000000000000000000000000000004E -:1002B000000000000000000000000000000000003E -:1002C000000000000000000000000000000000002E -:1002D000000000000000000000000000000000001E -:1002E000000000000000000000000000000000000E -:1002F00000000000000000000000000000000000FE -:1003000000000000000000000000000000000000ED -:1003100000000000000000000000000000000000DD -:1003200000000000000000000000000000000000CD -:1003300000000000000000000000000000000000BD -:1003400000000000000000000000000000000000AD -:10035000000000000000000000000000000000009D -:10036000000000000000000000000000000000008D -:10037000000000000000000000000000000000007D -:10038000000000000000000000000000000000006D -:10039000000000000000000000000000000000005D -:1003A000000000000000000000000000000000004D -:1003B000000000000000000000000000000000003D -:1003C000000000000000000000000000000000002D -:1003D000000000000000000000000000000000001D -:1003E000000000000000000000000000000000000D -:1003F00000000000000000000000000000000000FD -:1004000000000000000000000000000000000000EC -:1004100000000000000000000000000000000000DC -:1004200063FFFC000000000000000000000000006E -:100430000000000000000000000000001FFC0000A1 -:100440001FFC0000E30005C81FFC00001FFC0000AB -:10045000E30005C81FFC00001FFC0000E30005C806 -:100460001FFFC0001FFFC000E30005C81FFFC00042 -:100470001FFFC018E30005C81FFFC0181FFFC018EA -:10048000E30005E01FFFC0181FFFC28CE30005E07A -:100490001FFFC28C1FFFC28CE30008541FFFC290D5 -:1004A0001FFFC58CE3000854200000002000016AF3 -:1004B000E3000B502000018020000180E3000CBC11 -:1004C0002000020020000203E3000CBC2000021CFC -:1004D00020000220E3000CC02000022020000226A1 -:1004E000E3000CC42000023C20000240E3000CCCDE -:1004F0002000024020000249E3000CD02000024C02 -:1005000020000250E3000CDC2000025020000259C1 -:10051000E3000CE02000025C20000260E3000CEC31 -:100520002000026020000269E3000CF02000026C51 -:1005300020000270E3000CFC200002702000027911 -:10054000E3000D002000028C2000028CE3000D0C63 -:100550002000029020000293E3000D0C200002AC6A -:10056000200002B0E3000D10200002D0200002F2B3 -:10057000E3000D14200003B0200003B0E3000D38A9 -:10058000200003B0200003B0E3000D38200003B0CA -:10059000200003B0E3000D38200003B0200003B0BA -:1005A000E3000D38200003B020006BA8E3000D38F5 -:1005B00020006BA820006BA8E3007530000000004D -:1005C00000000000000000001FFC00001FFC0000F5 -:1005D0001FFFC5901FFFC67020006BA820006BA8EE -:1005E000DEFFFE000000080CDEADBEEF1FFFC2A064 -:1005F0001FFCFE001FFFC0941FFFC5C0300000009D -:10060000003FFFFF8040000010000000080FFFFFC8 -:100610001FFFC26D000FFFFF804FFFFF8000000033 -:1006200000000880B000000560500000600000007D -:1006300040000011350000004100000010000001E2 -:1006400020000000000010007FFFFFFF40000000BE -:1006500005000000800000190400000000000800F0 -:1006600010000005806000007000000020000009FC -:10067000001FF8008000001EA0000000F80000002D -:1006800007FFFFFF080000001800000001008001C4 -:10069000420000001FFFC21D1FFFC0DC00010080E0 -:1006A000604000001A0000000C0000000000300054 -:1006B000600008008000001C000100008000001A9B -:1006C00080000018FC0000008000000100004000D5 -:1006D000030000008000040050000003FFFFBFFF84 -:1006E0001FFFC3D400000FFFFFFFF000000016D073 -:1006F0000000FFF7A50000001FFFC4B01FFFC4618A -:100700000001000800000B20202FFF801FFFC455B0 -:1007100000002C00FFFEFFF800FFFFFF1FFFC57861 -:1007200000002000FFFFDFFF0000FFEF01001100CD -:100730001FFFC3D21FFFC590FFFFEFFF0000FFFBAD -:100740001FFFC6301FFFBEA0FFFFF7FF1FFFC064E3 -:100750000000FFFD1FFFC6200001FBD01FFFC5B03A -:100760001FFFC6601FFFC591E0FFFE001FFFC5A071 -:10077000000080001FFFC53C1FFFC5B41FFFC068FD -:100780001FFFC4D01FFCFFD800010081E10006005C -:10079000000027101FFCFE301FFCFE70E10002006D -:1007A0001FFFC5381FFFC5500003D0901FFFC56451 -:1007B0002B5063802B5079802B5090802B50A6803B -:1007C0001FFFC4690100110F202FFE0020300080A0 -:1007D000202FFF000000FFFF0001FFF82B50B200A8 -:1007E0002B50B208000100102B50B1802B50B2806A -:1007F0002B50BA00000100112B50BD282B50BC809B -:100800002B50BDA020300000DFFFFE005000000292 -:1008100000C0000002000000FFFFF7F41FFFC06CE3 -:10082000000FF80004400000001000000C40000021 -:100830001C400000E00000A01FFFC5401FFD000895 -:100840001FFFC5541FFFC5681FFFC57CE100069050 -:10085000E10006EC000000000000000000000000C5 -:100860000000000001000000000000000000000087 -:100870000000000020100040201000402010004028 -:1008800020140080200C0000200C0000200C000030 -:1008900020100040201400802014008020140080CC -:1008A000201800C0201C0100201C0100201C010099 -:1008B00020200140201800C0201800C0201800C0CF -:1008C000201C0100201800C0201800C0201800C003 -:1008D000201C010020200140202001402020014058 -:1008E00020200940202009402020094020200940E4 -:1008F00020240980FFFFFFFFFFFFFFFFFFFFFFFF37 -:1009000000000000000000000000000000000000E7 -:1009100000000000200052FC200051CC200052FCBE -:10092000200052FC200051082000510820005108EE -:1009300020004F4820004F4820004F4020004EAC80 -:1009400020004D5420004B342000490800000000D6 -:1009500000000000200052CC200051982000523CA2 -:100960002000523C20004FF020004FF020004FF0BC -:1009700020004FF020004FF020004F3820004FF0B3 -:1009800020004C7420004AE4200048B4000000001D -:100990000000000020000BE0200038BC200004C054 -:1009A000200044A820000BD820003FB4200003F012 -:1009B000200044682000489020003CC420003BE018 -:1009C00020003838200036C42000343420002F9412 -:1009D00020003A3C20002BF4200028282000653419 -:1009E000200023B4200020942000204020001D2C53 -:1009F000200018402000157020000DEC20000C2471 -:100A00002000113420001320200041AC20003C784D -:100A100020000BE8200004C00000000000000000DF -:100A200000000000000000000000000000000000C6 -:100A300000000000000000000000000000000000B6 -:100A400000000000000000000000000000000000A6 -:100A50000000000000000000000000000000000096 -:100A60000000000000000000000000000000000086 -:100A70000000000000000000000000000000000076 -:100A80000000000000000000000000000000000066 -:100A900000000000000000003264000000000000C0 -:100AA0003264000064006400640064006400640058 -:100AB000640064000000000000000000000000006E -:100AC0000000000000000000000000000000000026 -:100AD0000000000000000000000000000000000016 -:100AE0000000000000000000000000000000000006 -:100AF00000000000000000000000000000001000E6 -:100B000000000000000000000000000000000000E5 -:100B100000000000000010000000000000000000C5 -:100B200000000000000000000043238000000000DF -:100B300000000000000000000000000000000000B5 -:100B400000000000000000000000000000000000A5 -:100B5000005C94015D94025E94035F940043000086 -:100B60000000000000000000000000000000000085 -:100B70000000000000000000000000000000000075 -:100B80000000000000000000000000000000000065 -:100B9000005C90015D90025E90035F900053000046 -:100BA0000000000000000000000000000000000045 -:100BB0000000000000000000000000000000000035 -:100BC0000000000000000000000000000000000025 -:100BD000009C94001D90019D94029E94039F940498 -:100BE0000894050994060A94070B9400430000003A -:100BF00000000000000000000000000000000000F5 -:100C000000000000000000000000000000000000E4 -:100C1000009C90019D90029E90071D90039F900460 -:100C20007890057990067A90077B90005300000039 -:100C300000000000000000000000000000000000B4 -:100C400000000000000000000000000000000000A4 -:100C500000DC94001D9001DD9402DE9403DF940417 -:100C60000494050594060694070794080894090956 -:100C7000940A0A940B0B940043000000000000004B -:100C80000000000000000000000000000000000064 -:100C900000DC9001DD9002DE900B1D9003DF9004DC -:100CA000B49005B59006B69007B79008B89009B90A -:100CB000900ABA900BBB90005300000063FFFC0049 -:100CC0002000696410FFFF0A00000000200069880E -:100CD00000D23110FFFE0A0000000000200069D0A1 -:100CE00000D33110FFFE0A000000000020006A104F -:100CF00000D43110FFFE0A000000000020006A84CA -:100D000000D53110FFFE0A000000000063FFFC0068 -:100D1000E00000A012FFF78220028257C82163FF83 -:100D2000FC12FFF303E83004EE3005C0309320944A -:100D300021952263FFFC00001FFFD000000400206B -:100D40001FFFC5901FFFC670200A0011FFFB13FF95 -:100D5000FB03E63101020016FFFA17FFFAD30F7703 -:100D60006B069060B4667763F85415505419E60F1B -:100D7000140063FFF90000006C1004C020D10F00C4 -:100D80006C1004C0C71AEF06D830BC2BD720857270 -:100D90000D4211837105450B957202330C237601C8 -:100DA0007B3B04233D089371A32D12EEFE19EEFE4A -:100DB000A2767D632C2E0A00088202280A01038E87 -:100DC000380E0E42C8EE29A67E6D4A050020880026 -:100DD000308C8271D10FC0F0028F387FC0EA63FF80 -:100DE000E400C0F1C050037E0CA2EE0E3D1208825A -:100DF0000203F538050542CB5729A67E2FDC100FDC -:100E00004F366DFA0500208800308CBC75C0300864 -:100E1000E208280A01058338030342C93E29A67E59 -:100E20000D480CD30F6D8A0500208800B08C8271AC -:100E3000D10FC05008F53875C0C163FFBBC0600258 -:100E4000863876C0DA63FFD46C101216EED8C1F87B -:100E5000C1E72B221E2C221DC0D07BC12F292006CA -:100E6000D7B0299CFACC57282070288CFF282470F2 -:100E700064915C2AB0000EA80C6481670FA90C6411 -:100E800092B3C1E97EA13969AC2F600036292006F2 -:100E9000D7D0299CFACC57282070288CFF282470A2 -:100EA0006491352AD0000EA80C6481640FA90C64EB -:100EB000931BC1E97EA10968AC09C020D10F0000D5 -:100EC000002D25028A32C0900A6F5065F5AD2924A5 -:100ED000670908476585A92F200C18EEB50CFE118F -:100EE000A8EE28E286B44978930260057A19EEB13B -:100EF00009F90A2992A3689007882009880C65855A -:100F00006627E28564756065558E7BC104D9B06043 -:100F10000001C0908B941CEEA80B88148CC40B0BA2 -:100F200047A8CC18EEA609BB1008CC029C7018EE9E -:100F3000A41CEEA508A8010B88020C4C021BEEA114 -:100F40009C710B880298722C90232B902204C8105D -:100F500006BB100C4C1208BB0228902107CC100CC9 -:100F600088100C88020B88021CEE998B330CBB0195 -:100F70008C340B880298739C999C748B958C399B4C -:100F80007588968B38987688979C799B7898771C8B -:100F9000EE9028E2850CFC082DC4CF08480B28E60B -:100FA0008565550B2B221E2D221D7BD9022B0A0095 -:100FB00064BF062CB00728B000DA2006880A288211 -:100FC0004CC0D10B8000DBA065AFE763FEEB0000F7 -:100FD000292070659E9C6004E42A207065AEC36081 -:100FE00004DB00002EB0032C2067D4E065C1058A25 -:100FF000328C330AFF500C4554BC5564F4E619EEAC -:1010000075882A09A90109880C64821BC0926000B6 -:10101000DD2ED0032A2067D4E065A0D88A328B3336 -:101020000AFC500B4554BC5564C4B919EE6A882AB1 -:1010300009A9017989D50BEA5064A4DD0CEE11C031 -:10104000F02F16132E16168AE78CE82A16128EE950 -:10105000DFC0AAEA7EAB01B1CF0BA85065834288FE -:1010600037DBC0AE89991E789B022BCC012B161B57 -:1010700029120E2B0A0029161A7FC3077FC9027E88 -:10108000AB01C0B165B4988B352F0A002A0A007AEB -:10109000C30564C3C72F0A0165F4842B12162B16EF -:1010A00019005104C0C100CC1A2CCCFF2C16170C0F -:1010B000FC132C16182B121A2A121BDC505818FA83 -:1010C000C0D0C0902E5CF42C12172812182F121BBF -:1010D0002A121A08FF010CAA018834074C0AAB8BAC -:1010E0002812192BC6162F86082A86092E74102955 -:1010F00024672E70038975B1EA2A7403B0990949EF -:101100000C659DB52B20672D250265B3F42B221E9F -:101110002C221D7BC901C0B064BD9E2CB00728B035 -:1011200000DA2006880A28824CC0D10B8000DBA0A0 -:1011300065AFE763FD8389BAB19965909788341CE0 -:10114000EE2698BA8F331EEE1F0F4F542FB42C8DFE -:101150002A8A320EDD020CAC017DC9660A49516F44 -:1011600092608A3375A65B2CB0130AED510DCD0148 -:101170000D0D410C0C417DC9492EB012B0EE65E356 -:10118000C2C0D08E378CB88A368FB97CA3077AC993 -:10119000027EFB01C0D1CED988350AAD020E8E0881 -:1011A00078EB022DAC0189B7DAC0AF9B79BB01B1F6 -:1011B000CADCB0C0B07DA3077AD9027CEB01C0B114 -:1011C00064B15DC091292467C020D10F00008ADA84 -:1011D000B1AA64A0BC2E20672D250265E30B1FED8C -:1011E000F98A3218EDFE0FAF0108FF0C65F2860A8E -:1011F00048516F820260027DC090292467090A4726 -:1012000065A2F27BC901C0B064BCAE2CB00728B0A7 -:1012100000DA2006880A28824CC0D10B8000DBA0AF -:1012200065AFE763FC9300000CE9506492EB0CEFB0 -:1012300011C080281611AFBF2F16198EF88BF7DA60 -:10124000E08FF92B1610ABFB7FBB01B1EA0CA85065 -:101250006580D68837DCE0AF89991C789B022CEC3E -:10126000012C161B29120C2C0A0029161A7AE307E6 -:101270007AE9027FBB01C0C165C2A48B352C0A008C -:101280002A0A007AE30564E1CA2C0A0164CE1160DF -:10129000028D88341BEDD198DA8F331EEDCA0F4FC3 -:1012A000542FD42C8C2A8A320ECC020BAB010CBBEF -:1012B0000C65BF0E0A49516E920263FF058A330A1C -:1012C000AB5064BEFD2CD0130AEE510ECE010E0EB3 -:1012D000410C0C410ECC0C65CEE82FD012B0FF654E -:1012E000F26EC0B08E378CD88A362FD2097CA30715 -:1012F0007AC9027EFB01C0B165BEC78835DBA0AEEE -:101300008E78EB01B1AB89D7DAC0AF9D79DB01B143 -:10131000CAC0C07BA3077AB9027DEB01C0C165CE0C -:10132000A1C090292467C020D10F88378C3698142B -:101330000CE90C29161408F80C981D78FB072812E4 -:1013400014B088281614891D9F159B16C0F02B1207 -:101350001429161A2B161B8B147AE30B7AE90688CC -:10136000158E1678EB01C0F165F1B929121A2F120A -:10137000118A352E121B9A1AAFEE2F1210C0A0AF91 -:101380009F79FB01B1EE9F11881AC0F098107AE3A3 -:101390000A7EA9052A12017A8B01C0F164F08160EE -:1013A000018289368B3799170BE80C981F09C90CF5 -:1013B00029161578EB07281215B088281615D9C0FC -:1013C0009A199E188A1F2E12152A161A2E161BDA23 -:1013D000C0C0E08C177F930B7FA90688188F1978FF -:1013E000FB01C0E165E13D29121A2F12138A352E47 -:1013F000121B9A1BAFEE2F1212C0A0AF9F79FB01F8 -:10140000B1EE9F13881BC0F098127AE30A7EA905FB -:101410002A12037A8B01C0F165F1092E12162E16DD -:10142000192A121B005104C0E100EE1AB0EE2E166C -:10143000170EFF132F16180FCC01ACAA2F121A0E7D -:10144000BC01ACFC7FCB01B1AA2A161B2C161A6377 -:10145000FC6200007FB30263FE3163FE2B7EB302A9 -:1014600063FC3463FC2E00006450C0DA20DBF058CB -:1014700015DEC020D10FC09163FD7E00C09163FADC -:101480004CDA20DB70C0D12E0A80C09A2924682C47 -:1014900070075814CED2A0D10F034C0B18ED51DBBE -:1014A000C0A82878C3022BCDF8D9B063FA65000034 -:1014B0002A2C74DB40580E5063FAE80000002D25FA -:1014C000027BC901C0B064B0172CB00728B000DAA5 -:1014D0002006880A28824CC0D10B8000DBA065AFB3 -:1014E000E7C020D10FC09163FC04022A02580250C9 -:1014F0000AA202060000022A0258024D0AA20206AF -:101500000000DB70DA20C0D12E0A80C09E2924683A -:101510002C70075814AEC020D10FC09463FBCF00CD -:10152000C09663FBC9C09663FBC400002A2C74DB21 -:1015300030DC405BFE13DBA0C2A02AB4002F200CDD -:1015400063FF27008D358CB77DCB0263FDD263FC32 -:10155000718F358ED77FEB0263FDC563FC6400009D -:101560006C1004C020D10F006C1004C020D10F00FB -:101570006C10042B221E28221DC0A0C09429240612 -:101580002A25027B8901DBA0C9B913ED08DA2028DE -:10159000B0002CB00703880A28824CC0D10B800011 -:1015A000DBA065AFE7C020D10F0000006C1004295C -:1015B00020062A2102689805289CF965811A0A0AE2 -:1015C0004C65A0F016ECFB2B629E1AECF86FB8028B -:1015D0006000F12AA22668A0078B200ABB0C65B028 -:1015E000E32A629D64A0DD2B200C0CBC11A6CC2D3F -:1015F000C2866FD9026000D71DECEF0DBD0A2DD257 -:10160000A368D0078E200DEE0C65E0C327C285C00D -:10161000E06470BB1DECF468434D1CECF38A2B0CAA -:10162000AA029A7089200899110D99029971882A45 -:1016300098748F329F75282104088811987718ECC8 -:10164000E40CBF11A6FF2DF285A8B82E84CF2DDCA7 -:10165000282DF685C85A2A2C74DB40580DE7D2A0F5 -:10166000D10FC020D10F00002C9CF964C08D2C201C -:10167000668931B1CC0C0C472C24666FC669709E0C -:101680006618ECDA89308F2B0989400B991009FF15 -:101690000208FF029F708C2008CC110DCC029C71B7 -:1016A0008A339A7389329972882A98748F349F7515 -:1016B00063FF820000CC57DA20DB30DC405814B8DE -:1016C000C020D10F00DA20C0B658154763FFE500EF -:1016D000DA2058154563FFDC00DA20DB30DC40DD22 -:1016E000505815C7D2A0D10F2B21045813DA1DEC86 -:1016F000BD2B200CC0E02E246663FF842F2123C065 -:10170000C87FC30263FF792C20662B2104B1CC0C67 -:101710000C472C24665813CF1DECB32B200CC0E0D3 -:101720002E246663FF5A00006C1004C0B7C0A116D7 -:10173000ECB015ECA2D720D840B822C04005350245 -:101740009671957002A438040442C94B1AEC95199D -:10175000EC9629A67EC140D30F6D4A050080880013 -:10176000208C220A88A272D10FC05008A53875B00B -:10177000E363FFD76C100893149412292006655276 -:1017800088C0716898052A9CF965A29816EC892989 -:1017900021028A1409094C6590C78AA00A6A512A55 -:1017A000ACFD65A0BCCC5FDB30DA208C1258147C19 -:1017B000C0519A14C7BF9BA98E142EE20968E0603D -:1017C0002F629E1DEC7A6FF8026000812DD2266890 -:1017D000D0052F22007DF9752C629DC79064C06DE5 -:1017E0009C118A142B200C2AA0200CBD11A6DD0A06 -:1017F0004F14BFA809880129D286AF88288C09799F -:101800008B551FEC6C0FBF0A2FF2A368F00528223E -:10181000007F894329D285D49065907760003D0090 -:10182000002B200C1FEC640CBD11A6DD29D2860F05 -:10183000BF0A6E96102FF2A368F00488207F8905F6 -:1018400029D285659165DA205814E7600013DA2003 -:10185000C0B65814E5600009C09063FFB9DA20589B -:1018600014E28914899109FE506551E48C128D149B -:10187000DA20DBD08DD09E100D6D515813549A1480 -:1018800064A208C75F8FA195A9C0510F0F479F128F -:1018900063FEFB00C091C0F12820062C2066288C36 -:1018A000F9A7CC0C0C472C24666FC6088D148DD17B -:1018B00070DE01C090DD90648159C9D32A12012BDA -:1018C00021045813648A14C0B02B24668EA92AA060 -:1018D000200E28141CEC438D1415EC37C1700A77C8 -:1018E0003685562DDC28AC2C9C13DED0A8557CD335 -:1018F000022EDDF8D3E0DA40055B02DC305BFF8AC4 -:10190000D4A028200CB455C0D02B0A882F0A800CF4 -:101910008C11A6CC29C285AF3FAB9929C6851CEC9A -:101920002CDEF0AC882D84CF28120329120478F322 -:10193000022EFDF8289020D3E007880CC17008081B -:1019400047289420087736657FAB891413EC2A89E1 -:1019500090C0F47797491BEC28C1CA28210485144C -:10196000099E4006EE11875304881185520E8802A5 -:101970000C88029BA09FA18F2B9DA598A497A7954B -:10198000A603FF029FA22C200C1EEC11AECE0CCCA5 -:101990001106CC082BC2852DE4CF2BBC202BC6858D -:1019A0002A2C748B12580D14D2A0D10F28203DC0C0 -:1019B000E07C877F2E24670E0A4765A07B1AEC0F18 -:1019C00088201EEBFD8F148EE48FF40888110A889E -:1019D000020F8F14AFEE1FEC0A98910FEE029E904B -:1019E0001EEC09C0801AEBFA2CD285AABAB8CC2812 -:1019F000A4CF2CD6852C21022F20700ECC02B1FF53 -:101A00002F24702C2502C020D10F87148770070760 -:101A10004763FD6E282123C099798B0263FE9ADD0E -:101A2000F063FE9500DA20DB308C12DD505814F4A0 -:101A3000D2A0D10FC0E163FF7A8B148C12DD50C0AD -:101A4000AA2E0A802A2468DA20581360D2A0D10F67 -:101A5000007096552B629E6EB8531DEBD42DD22686 -:101A600068D0048E207DE9452A629DCBAF2B2104EE -:101A70002C20665812F8C090292466821418EBE2D4 -:101A80008F2108FF019F21C020D10F008B10C9B802 -:101A90008CA00C6C51CCCC8E241FEBD08DE19E140D -:101AA0000FDD029DE18810658FA9C020D10FDA20DB -:101AB000C0B658144DC020D10F0000006C1006298C -:101AC0002102C0D07597102A32047FA70A8B357F78 -:101AD000BF052D25020DD902090C4C65C18216EBFC -:101AE000B41EEBB228629EC0FA78F3026001882926 -:101AF000E2266890078A2009AA0C65A17A2A629DCD -:101B0000DFA064A1772B200C0CBC11A6CC29C286C7 -:101B1000C08C79830260015719EBA709B90A299291 -:101B2000A3689007882009880C65814327C2851C1B -:101B3000EBA964713A8931098B140CBB016FB11D9B -:101B40002C20669F10B1CC0C0C472C24666EC6026C -:101B500060014009FF5065F13A8A102AAC188934B7 -:101B6000C0C47F973C18EBAA1BEBA98F359C719BD7 -:101B7000708B209D7408BB029B72C08298751BEB12 -:101B8000A50F08409B730F881198777FF70B2F21C3 -:101B900002284A0008FF022F2502C0B4600004009A -:101BA0000000C0B07E97048F362F25227D970488D1 -:101BB000372825217C9736C0F1C0900AF9382F3C90 -:101BC0002009094264908619EB7618EB7728967EF7 -:101BD00000F08800A08C00F08800A08C00F0880045 -:101BE000A08C2A629D2DE4A22AAC182A669D893019 -:101BF0007797388F338A3218EB8007BE0B2C21047D -:101C0000B4BB04CC1198E0C08498E1882B9DE59A80 -:101C1000E69FE71AEB78099F4006FF110FCC020AF6 -:101C2000880298E2C1FC0FCC022CE604C9B82C2033 -:101C30000C1EEB670CCA11AECC06AA0829A2852D92 -:101C4000C4CF09B90B29A685CF5CC020D10FC081B4 -:101C5000C0900F8938C08779880263FF7263FF667E -:101C600000CC57DA20DB30DC4058134DC020D10FB8 -:101C7000DA205813DD63FFE8C0A063FE82DA20C0DB -:101C8000B65813D963FFD900DB402A2C74580C5A7C -:101C9000D2A0D10F8A102B210458126E1EEB44C023 -:101CA000D02D246663FEB1006C1006D62019EB3FE0 -:101CB0001EEB4128610217EB3E08084C65805F8AE5 -:101CC000300A6A5169A3572B729E6EB83F2A92263A -:101CD00068A0048C607AC9342A729D2C4CFECAAB71 -:101CE0002B600CB64F0CBD11A7DD28D2860EBE0AA4 -:101CF00078FB269C112EE2A32C160068E0052F62CB -:101D0000007EF91522D285CF2560000D00DA60C073 -:101D1000B65813B5C85A60010F00DA605813B2659F -:101D20005106DC40DB308D30DA600D6D51581227E2 -:101D3000D3A064A0F384A1C05104044763FF6D00E5 -:101D4000C0B02C60668931B1CC0C0C472C64666F36 -:101D5000C60270960A2B610458123EC0B02B64660E -:101D60006550B42A3C10C0E7DC20C0D1C0F002DFCF -:101D7000380F0F4264F09019EB0A18EB0B28967E8F -:101D80008D106DDA0500A08800C08CC0A089301DC0 -:101D9000EB1A77975388328C108F3302CE0BC02406 -:101DA00092E12261049DE00422118D6B9BE59FE787 -:101DB00098E61FEB100998400688110822020FDDF3 -:101DC00002C18D9DE208220292E4B4C22E600C1F73 -:101DD000EB000CE811A7882C8285AFEE0C220B2BB0 -:101DE000E4CF228685D2A0D10F28600CD2A08C111E -:101DF00019EAF80C8D11A988A7DD2ED2852B84CF86 -:101E00000ECC0B2CD685D10FC0F00ADF387FE8024C -:101E100063FF6C63FF6000002A6C74C0B2DC20DDDD -:101E20004058121CC0B063FF63C020D10F000000F7 -:101E30006C10042C221D2A221EC049D320293006F2 -:101E4000243468C0407AC105DDA060000200C0D023 -:101E50006E9738C08F2E0A802B3014C09629340616 -:101E60000EBB022E31022B34147E8004243502DE98 -:101E7000407AC10EC8ABDBD0DA302C0A00580A76A3 -:101E80002E31020E0F4CC8FEC020D10F6895F828E5 -:101E9000310208084C658FEF1AEAC61CEAC42BA26F -:101EA0009EC09A7B9B462BC22668B0048D307BD99E -:101EB0003B29A29DC0E3CB9394901BEAD72D31041C -:101EC0009B9608DD110EDD029D979D9112EAD4C00C -:101ED000E524C4A22E34062F310228A29D02FF025F -:101EE000288C3028A69D2F3502C020D10FDA30C0B3 -:101EF000B658133DC020D10F6C10062920066898F3 -:101F000005289CF965825D29210209094C6592101A -:101F1000CD51DB30DA20044C025812A1C051D3A0BD -:101F2000C7AF2A360AC0E019EAA31DEAA91FEAA230 -:101F30008A3A16EA9FB1AC64C13528629E6F880266 -:101F40006001F129DC332992266890078B2009BBB8 -:101F50000C65B1E027629DC08E6471D82B200C0CFB -:101F6000BC11A6CC29C2867983026001D219EA91FC -:101F700009B90A2992A397106890082822000988B5 -:101F80000C6581BB27C2856471B5292006299CF99F -:101F90006491EC2C20668931B1CC0C0C472C246662 -:101FA0006EC6026001A109F85065819B883689F4EC -:101FB000088C14AC991CEA810C99022C21049970AC -:101FC00019EA980808479971892A0988100899021E -:101FD00018EA95089902997228301329301204885A -:101FE0001006991008990228302C9A740C88100851 -:101FF000C802098802987389379975883898768A53 -:1020000039C0819A771AEA888935987B9978098945 -:10201000140A9902997A8A30893277A73618EA76B3 -:102020008F33987CC084987D882B2E761129761268 -:102030002F761319EA700A9F4006FF1104CA11098E -:1020400088020FAA02987EC1F90FAA022A7610C050 -:10205000AA600001C0A6ADBF0CBC11A6CC29C285E8 -:102060002EF4CF09A90B29C685655107C020D10FD1 -:102070002B200C0CBC1106CC0828C28609B90A6FAB -:10208000890260012E2992A36890082A220009AAD9 -:102090000C65A11F2AC28564A11928203D0828408B -:1020A00064808C843504841464408485F574537F83 -:1020B0008436048414644077745374293013C08CBC -:1020C00079886CC0902924670908476580ED8820CD -:1020D00089F484351FEA4B048414A4940F440294B9 -:1020E000A014EA4608881104880298A1843698A3AF -:1020F000048414A4990F990299A219EA42ADB42854 -:10210000C2852E44CF288C1028C6852821022F2076 -:1021100070098802B2FF2F2470282502C020D10F39 -:1021200000CC57DA20DB30DC4058121DC020D10F24 -:10213000C09163FF8FDA20C0B65812AB63FFE10095 -:10214000DA205812A963FFD88A102B2104581141B4 -:102150001DEA201FEA192B200CC0E02E24668A3AC3 -:1021600063FE480000DA20DB30DC40DD50581324E9 -:10217000D2A0D10F2A2C74DB40580B1FD2A0D10F54 -:10218000292123C08879830263FE202A12002C2093 -:10219000662B21042CCC010C0C472C246658112DE5 -:1021A0001DEA0C1FEA052B200CC0E02E24668A3A9B -:1021B00063FDF800DA2058128C63FF64DA205BFFBD -:1021C0001CD2A0D10F0000006C10089515C061C191 -:1021D000B0D9402A203DC0400BAA010A64382A2009 -:1021E0000629160668A8052CACF965C33B1DE9F263 -:1021F0006440052F120564F29C2621021EE9EE06BA -:10220000064C6562E315E9EA6440D98A3529300352 -:102210009A140A990C6490CC2C200C8B149C110CF1 -:10222000CC11A5CC9C122CC286B4BB7CB30260023C -:10223000D38F110EFE0A2EE2A368E0098620D30F89 -:102240000E660C6562BE88122882856482B6891487 -:1022500064905EDA80D9308C201EE9E81FE9E91D20 -:10226000E9D68B148DD4D4B07FB718B88A293C1026 -:10227000853608C6110E66029681058514A5D50F10 -:10228000550295800418146D8927889608CB11088B -:1022900088140EBB02A8D8299C200F88029BA19805 -:1022A000A088929BA3088814A8D80F880298A22A15 -:1022B000AC1019E9D4C0C08F141EE9C586128D1167 -:1022C000286285AEDD08FF0B2CD4CF2821022F66B3 -:1022D000858B352A2070098802ABAA2825022A247A -:1022E00070C020D10F29529E18E9B16F9802600288 -:1022F0000828822668800829220008990C6591F92F -:102300002A529DC1CA9A1364A1EF2B200C262006E5 -:102310000CB811A5882D82860EBE0A7DC30260020C -:10232000022EE2A368E0082F22000EFF0C65F1F3F5 -:10233000288285DE806481FF9810266CF96461FF35 -:102340002C20668831B1CC0C0C472C24666EC6025A -:102350006001BC08FD5065D1B617E9B419E9981AB7 -:10236000E99F2C21048B2D2830102F211D0C881063 -:102370000BFB090C88020A880209BB0264415289DE -:1023800010C04D9B90979198928D35D9E064D06C98 -:10239000D730DBD0D8307FD713273C10BCE92632AA -:1023A000168C3996E69CE78A37B4389AE80B1314F2 -:1023B0006430492A821686799A9696978C778A7D18 -:1023C0009C982B82172C7C209A9A2A9C189B998681 -:1023D0007BB03BB8896DB9218BC996A52692162A88 -:1023E000AC18B8999BA196A08BC786CD9BA22B92C7 -:1023F0001596A49BA386CB2CCC2026A605C0346BB7 -:10240000D4200D3B0C0DD8090E880A7FB705C0906B -:102410009988BC88C0900B1A126DAA069988998B6E -:10242000288C18C0D01BE9831CE98216E978B1FF1B -:102430002A211C23E6130F0F4F26E6122F251D7F9E -:10244000A906C0F0C08028251D05F6111AE9718F74 -:10245000202BE6152CE6162DE61726E6180AFA02BA -:102460002AE614292006299CF96490FF29200C8D66 -:1024700015C0801AE9570C9C11AA99A5CCDA202B1B -:10248000C2852894CF0B4B0B2BC685C0B08C165839 -:102490001114D2A0D10F8A356FA548D8308BD56DD5 -:1024A000A90C8A860A8A14CBA97AB337288C10C063 -:1024B00080282467080B4765B112DA20DB302C1224 -:1024C00006581137D3A0C0C1C0D02DA4039C1563FA -:1024D000FD26863664610C8910C04D9B90979198BB -:1024E0009263FEA4C08163FFC78A15CCA7DA20DB04 -:1024F000308C1658112BC020D10FDA20C0B65811DD -:10250000BA63FFE400DA208B115811B763FFD900DA -:102510009E178A132B210458104F8E17C0B02B24FE -:102520006663FE34C08063FE09DA20DB308C16DD82 -:1025300050581233D2A0D10FDA205811AB63FFA844 -:102540002D2123C0C87DC30263FE0D8A132B2104F5 -:102550002C20669817B1CC0C0C472C246658103DE3 -:102560008E17C0D02D246663FDEE0000262123B017 -:102570006606064F262523656EF128206A7F8705AB -:102580000829416490A5C0D01BE91C19E92B26201D -:102590000723E61BB16609FA022BE61A28200A2D4A -:1025A000E61D2AE61E09880228E61C88260606473C -:1025B00028E6202B220826E53E2BE6212D24072C99 -:1025C00020062A206468C347B44463FE9EDB30DAE9 -:1025D000208D15C0CE2E0A802C24688C1658107BB6 -:1025E000D2A0D10F8E102A321616E8F30A2A1486CA -:1025F000662BE61297E127E61328E614AA66096619 -:102600000296E02EEC4869ED50C14663FD7A000069 -:1026100064AFB419E8E928201689920A880C009161 -:102620000400881AA8B8982963FF9C002B21046E27 -:10263000B81E2C2066B8CC0C0C472C2466C9C09E52 -:10264000178A135810048E17C0348F20C0D02D2441 -:1026500066C06826240663FF2C008D35C08064D0D8 -:102660004AD9E0DC30DBE0DF301AE8F4B188B4FFAF -:1026700017E8F486C9249DFF8DC82CCC102D463058 -:102680000767012D46320A66011DE8EE264631AD88 -:102690006D2D463326F21597B796B684C3BCBB940E -:1026A000B58D35299C107D83C22F211DC14663FD48 -:1026B0004B0000006C1006292006289CF86582C398 -:1026C0002921022B200C09094C6590E116E8B90C70 -:1026D000BA11A6AA2DA2862C0A127DC3026002900E -:1026E00019E8B509B90A2992A36890078C2009CC8A -:1026F0000C65C27C29A2856492762D629E1AE8AB95 -:102700006FD8026002722AA22629160168A0082B3F -:1027100022000ABB0C65B26029629DC18C6492588C -:102720002A21200A806099102C203CC7EF000F3E20 -:10273000010B3EB1BD0FDB390BBB098F260DBD115F -:102740002DDC1C0D0D410EDD038E27B1DD0D0D417D -:102750000FEE0C0DBB0B2BBC1C0BB7027EC71C2C49 -:1027600021257BCB162D1AFC0CBA0C0DA16000099B -:102770003E01073EB1780987390B770A77EB026093 -:10278000020A2C2123282121B1CC0C0C4F2C25230B -:102790007C8B29B0CD2D2523C855DA20DB30580F8E -:1027A000FA292102CC96C0E80E9E022E2502CC57B3 -:1027B000DA20DB30DC4058107AC020D10F2C2066A4 -:1027C0008931B1CC0C0C472C24666EC6026001D353 -:1027D00009FD5065D1CD2F0A012E30112922146434 -:1027E000E01128221B090C4400C10400FA1A0A88CF -:1027F0000228261B2E3010C0A0C0B088301CE86E06 -:1028000094129513C04125203C2CC022088D1477CA -:1028100087052F0A010CFA38C0F2C0840858010F4E -:102820005F010F4B3805354007BB10C0F0084F382B -:1028300008FF100FBB0228ECFEC0F0084F38842BB5 -:102840000BA8100AFF102A21200F88020B8802080B -:10285000440218E87D8F110844022821250A2A1411 -:102860000828140488110A88022A210494F08B2075 -:1028700004E41008BB1104BB02C04A04BB029BF174 -:10288000842A08AB110BEB0294F40A54110B440296 -:102890000555100D1B4094F707BB100B550208554A -:1028A00002C08195F68433C05094F3B1948B329575 -:1028B000F898F99BF2C080C1BC24261498FB9BF5C4 -:1028C00099FA853895FC843A94FD8B3B9BFE8839B8 -:1028D00098FF853525F6108436851324F6118B373D -:1028E00084122BF612C0B064C08189307797468D70 -:1028F0003288332E30108F111CE840099940069918 -:10290000112CF614C0C42CF6158C2B2DF61A28F6B3 -:102910001B2BF61904A81109880208EE0219E835E4 -:10292000C18008EE0209C90229F6162EF618C09ECB -:10293000600004000000C09A2F200C18E8250CFE4F -:1029400011A8FFA6EE2DE2852BF4CF0D9D0B2DE6F1 -:1029500085C87F8A268929A7AA9A260A990C090977 -:102960004829252565504CC020D10F00C09A63FF2F -:10297000C6DA2058109D63FE34DA20C0B658109A8B -:1029800063FE2A00689738C020D10F0000DA20DBF0 -:1029900070581057C0B0C0C10ACA390ACB3865BDDB -:1029A000E063FE098A102B2104580F2AC0B02B24A3 -:1029B0006663FE21DB402A2C7458090FD2A0D10F88 -:1029C000DA20580F2F63FCF76C1004C020D10F00E1 -:1029D0006C1004290A801EE81D1FE81D1CE7F50C79 -:1029E0002B11ACBB2C2CFC2DB2850FCC029ED19CA4 -:1029F000D0C051C07013E81914E81818E8162AB2AC -:102A000085A82804240A234691A986B8AA2AB6854F -:102A1000A98827849F25649FD10F00006C100AD6D7 -:102A200030283010292006288CF964829B68980B86 -:102A30002A9CF965A1B2022A02580F1189371BE7B7 -:102A4000DEC89164520E2A21020A0C4C65C2588DD0 -:102A50003019E7D774D7052E212365E29E2F929E69 -:102A60001AE7D36FF8026002532AA22668A0082C46 -:102A700022000ACC0C65C2442A929D64A23E9A159B -:102A80001FE7CD8D67C1E664D00E2B620618E7CA3A -:102A900064B0052880217B8B422B200C18E7C50CE5 -:102AA000BC11A8CC29C28679EB450FBE0A2EE2A341 -:102AB00068E0048F207EF9372CC2859C1864C233ED -:102AC0002B212F87660B7B360B790C6F9D266ED2E0 -:102AD000462C203D7BC740CE5560001E2A200CC1ED -:102AE000B28C205810759A1864A2458D6763FFCF89 -:102AF000C0C063FFC5D7B063FFD300C0E060000271 -:102B00002E60030EDB0C6EB20EDC700CEA11AA6AAA -:102B10002AAC20580199D7A0DA20DB70C1C82D213A -:102B20002058101B8C268B279A160CBB0C7AB334BA -:102B30008F18896399F3886298F28E659EF82D60EC -:102B4000108A189D1768D729C0D09DA92C22182B50 -:102B500022139CAB9BAA97A58E667E73026000979A -:102B6000CF5860001FDA208B16580FE165A138633B -:102B7000FFBDC081C0908F18C0A29AF999FB98FA46 -:102B800097F563FFD2DB30DA20DC40580F85C05167 -:102B9000D6A0C0C02BA0102CA4039B172C12080297 -:102BA0002A02066B02DF702D60038E179D149E10A3 -:102BB0000CDD11C0E0AD6D2DDC205801188C148B9C -:102BC00016ACAC2C64038A268929ABAA0A990C9A04 -:102BD00026886609094829252507880C98662F222A -:102BE00018A7FF2F261863FE96DA20DB30DC40DDC5 -:102BF00050581083D2A0D10FC0302C20668961B10B -:102C0000CC0C0C472C24666EC6026000D2C0300982 -:102C1000FD5065D0CA8E6764E069647066DB608CC5 -:102C200018DF70DA202D60038E170CDD119E10ADB9 -:102C30006D2DDC201EE7845800F9232618DA208B3E -:102C400016DC402F2213DD50B1FF2F2613580F241E -:102C5000D2A0D10F0028203D084840658DE76F9530 -:102C60003EDA308DB56D990C8CA80C8C14CACF7CD3 -:102C7000D32D2AAC10C090292467090D4764DDC507 -:102C8000600092002C1208066B022D6C20077F0258 -:102C90008E17DA209E101EE76B58007D63FF9A00A6 -:102CA000C09163FFD1000000655081DA20DB60DC59 -:102CB00040580F3BC020C0F02FA403D10FDA20C032 -:102CC000B6580FC963FFE000006F950263FD6CDA30 -:102CD00020DB30DC40DD50C4E0580EBCD2A0D10F68 -:102CE0008A152B2104580E5B232466286010981740 -:102CF00063FF2100DA20580FBC63FFABC858DB30FC -:102D0000DA20580EA12A210265AF9CC09409A902BD -:102D100029250263FF91DB30DC40DD50C0A32E0A81 -:102D2000802A2468DA20580EA9D2A0D10FC020D161 -:102D30000FDA202B200C580FC563FF6B6C10042892 -:102D40002006C062288CF8658125C050C7DF2B2281 -:102D50001BC0E12A206B29212300A104B099292559 -:102D600023B1AA00EC1A0BC4010A0A442A246B04FA -:102D7000E4390DCC030CBB012B261B6440692920D0 -:102D80000C1BE70B0C9A110BAA082FA2861BE70954 -:102D90006FF9026000B60B9B0A2BB2A368B0082C37 -:102DA00022000BCC0C65C0A42BA2851DE72D64B0BE -:102DB0009B8C2B2421040DCC029CB08820C0C5081C -:102DC00088110C880298B1882A08441198B48F346D -:102DD00094B79FB5C0401EE6FE2DA2850E9E082525 -:102DE000E4CF2DDC282DA68529210209094C689401 -:102DF0001A689820C9402A210265A00B2A221E2B9E -:102E0000221D7AB10265A079C020D10F2C21236543 -:102E1000CFDE6000082E21212D21237EDBD52B2241 -:102E20001E2F221D2525027BF901C0B064BFC413EB -:102E3000E6DF2CB00728B000DA2003880A28824C8D -:102E4000C0D10B8000DBA065AFE763FFA62A2C741E -:102E5000C0B02C0A02580D951CE7039CA08B2008DB -:102E6000BB1106BB029BA1893499A263FF790000C4 -:102E7000262468DA20DB30DC40DD50580FE1D2A098 -:102E8000D10FDA202B200C580F58C020D10F000092 -:102E90006C1006073D14C080DC30DB40DA20C047F0 -:102EA000C02123BC30032838080842774001B1DD37 -:102EB00064815A1EE6BB19E6BC29E67ED30F6DDAA3 -:102EC0000500508800308CC0E0C02025A03C14E6EE -:102ED000BAB6D38FC0C0D00F87142440220F8940C8 -:102EE000941077F704C081048238C0F10B2810C019 -:102EF00044C02204540104FD3802520102FE380885 -:102F0000DD10821C07EE100E6E020EDD02242CFE78 -:102F1000C0E004FE380AEE100E88020D88028DAB68 -:102F20001EE6AA08D8020E880298B0C0E80428104D -:102F30000E5E0184A025A125084411084402052540 -:102F400014045511043402C0810E8E3994B18FAA35 -:102F500084109FB475660C26A11FC0F2062614606B -:102F60000009000026A120C0F20626140565020F04 -:102F7000770107873905E6100778100866020655BD -:102F80000295B625A1040AE611085811082802087E -:102F9000660296B7C060644056649053067E11C0C6 -:102FA000F489C288C30B340B96459847994618E6B6 -:102FB000919F410459110E99021FE68F020E470896 -:102FC000D80298420E99029F40C1E00E990299449E -:102FD0002FA00CB4380CF91114E67E1EE675A4FF80 -:102FE000AE992E928526F4CF0E880B289685D10FA8 -:102FF0002BA00C1FE66F1CE6760CBE11ACBBAFEE2F -:103000002DE28526B4CF0D3D0B2DE685D10FC08076 -:1030100005283878480263FEA263FE966C1006C04D -:10302000C06570F18830C030088714778712C0B04F -:10303000C0A619E661299022C030CC97C03160004B -:1030400003C0B0C0A6C0E0C091C0D4C08225203C5F -:103050000B3F109712831CC0700858010D5D0108CA -:103060009738C0800B9838077710048810086802DA -:10307000087702C0800D98382D3CFE0888100D9E00 -:10308000388D2B0AEE1008EE0207EE020CB8100F76 -:10309000DD02053B400EDD029D408920043D100805 -:1030A00099110D99022D210409A90208DD119941F8 -:1030B000872A05B9100D3D020ABB110DBB02087726 -:1030C0000297442821258712082814048811071E16 -:1030D0004007EE100E990275660926211F06261478 -:1030E000600006002621200626140868029B470976 -:1030F0008802984629200CD2C0C0800C9E111BE685 -:10310000341FE62BAB99AFEE2DE2852894CF0DADA1 -:103110000B2DE685D10FDD40C0A6C0B08E51CAE0B0 -:10312000B2AAB1BB2DDC108F500E783698100877FC -:103130000C9FD898D989538F52991199DB9FDA7EC9 -:103140008309B1CC255C10C97763FFCF88108D113E -:1031500008E70C9751AD8DD7F078DB01B1F79D539F -:1031600097528830C030088714088840648ED5652F -:10317000BEC963FEBC0000006C1004D720B03A88C2 -:1031800020C0308221CAA0742B1E2972046D080F42 -:10319000C980C9918575B133A2527A3B0B742B0853 -:1031A00063FFE900649FECD10FD240D10F00000013 -:1031B0006C1008D630C0709515DA408E3914E5FED3 -:1031C0009A1464E0026451FC2920062A9CF865A246 -:1031D0005F2A21020A0B4C65B21F2C320015E5F460 -:1031E00074C7052D212365D3242E529E1AE5F06F56 -:1031F000E80260021B2AA22668A0082B22000ABB54 -:103200000C65B20C2E529D1DE5EB64E2038B386415 -:10321000B22D9E16C8BC8D691EE5E864D0052EE06F -:10322000217BEB492E200C18E5E20CEF11A8FF29B9 -:10323000F286C186798B4A17E5DF07E70A2772A372 -:10324000687004882077893925F2856452A2272185 -:103250002E07B73607B90C6F9D01D7B089696E92FA -:103260004228203D7B873C8A15CDAF600018C1B253 -:103270008C202A200C580E90D5A064A2AC8B6863D9 -:10328000FFCBC05063FFC3C0E06000022E60030E9E -:103290009B0C6EB20EDC700CEA11AA6A2AAC285B99 -:1032A000FFB6D7A0DA20DB70C1C42D211F580E381D -:1032B0008C268B27D4A00CBB0C7AB3258A63C090D4 -:1032C0009A538862995898528F659F598E679E5B72 -:1032D0008D6697559D5A8B687B7B748B15CEB3603A -:1032E000000DDA20DB40580E0265A10D63FFCC0013 -:1032F000DA20DB308C14580DAAD6A0C0C0C0D19DF6 -:10330000152CA403DA20DB60DF70DC50C0E0256000 -:10331000039E101EE5C10C5D11AD6D2DDC285BFF19 -:103320003F8E66A5A88F67286403AF7F77FB01B146 -:10333000EE9E669F678D268C29A4DD0DCC0C9D2604 -:103340008B680C0C482C252507BB0C9B6863FEC3BF -:103350002C20668961B1CC0C0C472C24666EC60209 -:103360006000B809FD5065D0B2CBBF8E69CBEBDBF6 -:1033700060DC50DF70DA201EE5BC2D6003C0809851 -:10338000100CDD11AD6D2DDC285BFF248B15C942BF -:103390008A2629220904AA082A26060A990C09095C -:1033A0004829252565B13CC020D10F00DB602D6C7C -:1033B00028DF70DA20C0C01EE5AC9C10DC505BFE3C -:1033C000B463FFC7002D203D0D4D4065DDF96FE56D -:1033D00022DA308F456DE90C8EAA0E8E14C9E37E79 -:1033E000F3112AAC10C090292467090F4764FDD758 -:1033F00060014100C09163FFED00881565814CDAE2 -:1034000020DB608C14580D66C020C09029A403D125 -:103410000FDA20C0B6580DF463FFDE008A162B21A8 -:1034200004580C8CC0A02A24668B6863FF3A000005 -:10343000002B9CF965B0C5DA20580C9163FD910012 -:103440002B200C0CBA11A5AA2FA286C1C27FC302E1 -:103450006000FC0DB90A2992A36890078C2009CC62 -:103460000C65C0EB26A2856460E52C20668931B12D -:10347000CC0C0C472C24666FC60270960ADAE02B3F -:103480002104580C74272466893077974B18E55926 -:103490001DE55A8A328B33C0F42C2104099E400664 -:1034A000EE1104CC110ECC029F61C1E00ECC029D46 -:1034B000608F2B9A669B679C64976508FF029F62EA -:1034C0002F200C18E5430CFE11A5EE2DE285A8FF78 -:1034D00027F4CF2DDC202DE6858F1565F091C020D7 -:1034E000D10F00002A2C748B14580643D2A0D10FA0 -:1034F00000DA20DBE0580DBC63FEFE0000DA20DBC2 -:10350000308C148D15580E3ED2A0D10F00008815B6 -:10351000C888DA20DB30580C9C2A210265AEDAC05C -:103520009409A90229250263FECFDA202B200C582A -:103530000DC763FEC4272468DA20DB302C12042D6B -:1035400012052E0A80580CA163FC7C00C020D10F0C -:10355000DA20580DA58A15CDA1DA20033B022C12E2 -:1035600004580D0F27A403C020D10F00C020D10F95 -:103570002A2C748B14580620D2A0D10F6C100C2862 -:103580002102941008084C6583621FE50929F29E08 -:103590006F98026003661DE50529D2266890082A07 -:1035A000220009AA0C65A3542CF29D64C34E2B2063 -:1035B0000C0CB611AF66286286C1EC78E30260039A -:1035C0004619E4FC09B90A2992A36890078A2009E0 -:1035D000AA0C65A33224628564432CC0E12A310918 -:1035E000C07027246689359A11992A8836991298CD -:1035F0002B89379813992C883899140858149815E2 -:10360000982D89392A25042E251D29251C28302886 -:10361000C09228243C2A30290808479816098901B5 -:103620002A243D2A311599170A094109A90C299C18 -:10363000EC29251F7E87192D2A000DA06000083E69 -:10364000010A3EB1AD08DA390EAA110A990C2925F2 -:103650001F2A211F18E5060A8160C1D0941A951B04 -:1036600001083E00053EB184054839843C259CFC98 -:103670000D883629201408AA1C8D3D2726182E26D1 -:10368000132E26142E261527261B2E246B2724677F -:1036900027246808581C0909432924142932112AAF -:1036A000252E28252F27252427252527252C2725A6 -:1036B000232525202425212D2522841A2D211C8512 -:1036C0001B6FD202600209C0A099186D080AB1AA46 -:1036D00000A10400E91A7D9B0263FFEE8918C080F7 -:1036E000C0E1C070C0D29B1D951B961C9C1E16E4A9 -:1036F000D12C203D15E4E00C0B400DCC010BE7383C -:103700001DE4C30A77100CE8380B8810C0C49C4134 -:103710000877029D40B0A80988118B209C499D48DC -:10372000954B9643087702861418E4D115E4B9083E -:10373000770205BB029B4A9B429746881287110875 -:10374000DA149A4E0D88100D77110877021AE4AC3E -:1037500006D8140D6610087702974FC78F984D98BA -:103760004C9845871598440715140D55110A5502B4 -:10377000954715E4C18A262D46102D46182D462062 -:103780002C46112C46192C46212B46122B461A2862 -:1037900046142846152B46228816254624254626FB -:1037A0008B170A0C48090D4885130EDD1105CC1145 -:1037B0000839400BEB390299101EE4B00DCC020D14 -:1037C0005511082D400655022E461316E47B0FDDD9 -:1037D00011254616080840851B0188100DBB02867E -:1037E000671DE4A70988020CBB0219E4771CE4A555 -:1037F0002B46172D461BA7661BE4A4C0702C461C45 -:103800000988028C1E28461E2B4623C0908B1D293A -:10381000461D29461F18E49D29462728462529319B -:10382000162E200629246A243117962D2425238656 -:103830001CCCE1272407C0D7090E4064E0829A29F6 -:1038400009284164809164409B2D2406C098094951 -:1038500036280AA024628501C404A844282104242F -:1038600066850888118E3F8A3E2D32100EA41800FE -:10387000C4040EAE1800EE110ACA530EDD02C0E3F6 -:103880000E880298C11EE48209084E9EC08E2094C4 -:10389000C398C59DC418E44E1DE47F05EE110EAA21 -:1038A000020DAA02A8B82784CF9AC21EE44024F2CF -:1038B0009D27E4A2244C1824F69D655052C020D1C7 -:1038C0000F2D2406C0A0C09809493604A93863FF0B -:1038D0007FC0A063FE070000654F6DC098C0A82A96 -:1038E000240663FF6B2D2406C09063FF63CC57DA78 -:1038F00020DB308C10580C2AC020D10F00DA20C0F9 -:10390000B6580CB963FFE500DA20580CB763FFDC4A -:103910002A2C748B10580538D2A0D10F6C100628B1 -:1039200020068A336F8202600161C05013E42029AF -:10393000210216E41F699204252502D9502C201576 -:103940009A2814E41D8F2627200B0AFE0C04770901 -:103950002B711C64E1398E428D436FBC0260016F94 -:1039600000E104B0C800881A08A80808D8029827FF -:103970002B200668B32ECE972B221E2C221D011160 -:10398000027BC901C0B064B0172CB00728B000DAC0 -:103990002003880A28824CC0D10B8000DBA065AFD1 -:1039A000E7C020D10F2D206464DFCA8B29C0F10B42 -:1039B000AB0C66BFC02B200C0CBC11A6CC28C28659 -:1039C0002E0A0878EB611EE3FB0EBE0A2EE2A36806 -:1039D000E0052822007E894F29C2851EE4076490F5 -:1039E000461FE4159E90C084989128200A95930F55 -:1039F000880298928E200FEE029E942F2007882630 -:103A00002F950A98969A972E200625240768E34357 -:103A10002921022AC2851DE3EE2AAC20ADBD25D4A2 -:103A2000CF2AC68563FF4E002E2065CBEDC08228CD -:103A30002465C9F605E4310002002A62821BE3F71F -:103A40002941020BAA022A668209E4312921026374 -:103A5000FF23000064DFB88F422E201600F1040D12 -:103A6000EE0C00EE1AAEAE9E2963FFA38A202B3225 -:103A700021B1AA9AB0293221283223B499293621BA -:103A80007989A92B32222B362163FFA0C020D10FC8 -:103A90009F27252415ACB828751C2B2006C0C12EE5 -:103AA000BCFE64E0AB68B7772DBCFD65DEC72D209A -:103AB00064C0F064D0868E290EAE0C66E089C0F139 -:103AC00028205A288CFE08CF3865FEE863FF58008E -:103AD00000E0049310C0810AF30C038339C78F08F8 -:103AE000D80308A80108F80C080819A83303C80C63 -:103AF000A8B828751C030B472B24158310CBB700DF -:103B0000E104B0BC00CC1AACAC0CDC029C27659E76 -:103B10005EC0B20B990209094F29250263FE5000CD -:103B20002D206A0D2D4165DF7EDA20C0B0580C755E -:103B300064AF18C0F163FEEF9F2763FFD02E221FF2 -:103B400065EE3263FF79000028221F658E2763FF30 -:103B50006E252406252502C09063FE196C100665AB -:103B600071332B4C18C0C7293C18C0A1C08009A8CC -:103B7000380808426481101CE38A1AE38B2AC67E47 -:103B80002A5CFDD30F6DAA0500B08800908C894097 -:103B9000C0A00988471FE3B4080B47094C50090D22 -:103BA0005304DD10B4CC04CC100D5D029D310CBB70 -:103BB000029B3088438E2098350FEE029E328D2670 -:103BC000D850A6DD9D268E40C0900E5E5064E097D2 -:103BD0001CE39A1EE389038B0BC0F49FB19EB02DAA -:103BE000200A99B30CDD029DB28F200CFF029FB416 -:103BF0008E262D20079EB68C282DB50A9CB7292429 -:103C0000072F20062B206469F339CBB61DE36B2305 -:103C100020168DD20B330C00D10400331AB48DA3BF -:103C2000C3932922200C13E36A1FE3610C2E11AF0A -:103C3000EEA3222924CF2FE285D2A00FDD0B2DE6A3 -:103C400085D10F002E200CB48C0CEB111FE3611DED -:103C5000E358AFEEADBB22B28529E4CF02C20B22FE -:103C6000B685D2A0D10F00002E200C1CE3511FE31B -:103C7000580CEB11AFEEACBB22B28529E4CF028227 -:103C80000B22B685D2A0D10FC0D00BAD387DC802B3 -:103C900063FEEC63FEE08E40272C747BEE12DA703C -:103CA000C0B32C3C18DD50580A7B8940C08063FEAD -:103CB000E3DE60DA20DB30DC40DD505800059A108E -:103CC000DB50077A0258044C881063FEF8000000AD -:103CD0006C100692121EE3428C40AE2D0C8C472EC7 -:103CE0003C1804CA0BD9A07DA30229ADF875C30204 -:103CF000600084C0B0C023C0A09D106D0844B89F70 -:103D00000EB80A8D900EB70BB8770D6D36ADAA9D23 -:103D1000800D660CD8F000808800708C879068B1A8 -:103D200024B22277D3278891C0D0CB879890279C44 -:103D30001000708800F08C9D91CB6FC08108BB0390 -:103D400075CB3663FFB4B1222EEC1863FFD4859295 -:103D50000D770C86939790A6D67D6B01B1559693FF -:103D60009592600016B3CC2D9C188810D9D078D3CA -:103D7000C729DDF863FFC100C0238A421BE3470067 -:103D8000CD322D44029B3092318942854379A10581 -:103D90001EE3430E550187121BE334897095350BE2 -:103DA0009902993288420A880C98428676A6A6968D -:103DB000768F44AFAF9F44D10F0000006C10089382 -:103DC00011D6308830C091086351080847059838EB -:103DD0009812282102293CFD08084C6581656591EF -:103DE000628A630A2B5065B18B0A6F142E0AFF7C1E -:103DF000A60A2C205ACCC42D0A022D245A7FE00298 -:103E0000600215892888261FE32609880C65820F21 -:103E10002E200B0FEE0B2DE0FE2EE0FF08DD110E25 -:103E2000DD021EE320AEDD1EE3201CE3200EDD01DB -:103E30000DCC37C180084837B88DB4889810896098 -:103E40001AE2DE7B96218B622AA0219C147BA317A9 -:103E50009D132A200C8B108C20580B978C148D13DB -:103E6000DBA0CEAC6001C4002E200C1BE2D10CEA1A -:103E7000110BAA082BA2861FE2CF7BDB3B0FEF0AB8 -:103E80002FF2A368F0052822007F892C2BA28564DD -:103E9000B0AA87628826DE700C7936097A0C6FAD7D -:103EA0001C8F279B1508FF0C77F3197E7B729D13DF -:103EB0009C149B15CF56600025C0B063FFD0D790EF -:103EC00063FFDD00009D139C14DA20DB70580B08A3 -:103ED0008B158C148D1365A06A8E6263FFCC00DA9B -:103EE000208B11DC40580AAED6A08B15C051DE7075 -:103EF000DA20DC60DD405BFF768D138C14D9A02EB8 -:103F0000200C1BE2AB1FE2B20CEA11AFEFC0E0AB3A -:103F1000AA2BA2852EF4CF0B990B29A68563FF1D32 -:103F200000DA20DC60DD40DE708912282007DF50D7 -:103F3000A9882824075BFF09D2A0D10F00DBE0DAB3 -:103F400020580B296550EF2A20140A3A4065A0EB4F -:103F5000DB60DC40DD30022A0258099CD6A064A058 -:103F6000D584A183A0040447030547951203635138 -:103F7000C05163FE5C2C2006D30F28CCFD6480A5C5 -:103F800068C704C0932924062C2006C0B18D641F85 -:103F9000E28A9D279D289D298FF29D2600F104002D -:103FA000BB1A00F004B0BE0EDD01C0F0ADBB8D65E4 -:103FB0002F24070D0E5E01EE11AEBB2E0AFEB0BB24 -:103FC0000B0B190EBB36C0E20B0B470EBB372B2475 -:103FD0001618E2820A09450D0B422B240B29240AEC -:103FE000B4BE2E240C7D88572920162FCCFDB09D01 -:103FF0000A5C520DCC362C246465FDEC0C0C476435 -:10400000CDE618E26D8E2888820C9F0C008104009A -:10401000FF1AAFEE9E2963FDCF1CE29C63FE1300E6 -:104020001CE29363FE0C8D6563FFA500DA202B2054 -:104030000C580B06645F0FC020D10F00C020D10FB9 -:10404000C093292416C09363FFA000006C1004C025 -:104050006017E2561DE259C3812931012A3008292F -:10406000240A78A108C3B27BA172D260D10FC0C16B -:104070006550512625022AD0202F200B290AFB2B20 -:1040800020142E201526241509BB010DFF0928F147 -:104090001C2B2414A8EE2EF51C64A0B52B221E2880 -:1040A000221D0111027B8901DB6064B0172CB0076F -:1040B00028B000DA2007880A28824CC0D10B800083 -:1040C000DBA065AFE7DB30DC40DD50DA205800D8FC -:1040D000292102090B4CCAB2D2A0D10F00CC5A2C14 -:1040E00030087BC1372ED02064E02D022A02033B2A -:1040F00002DC40DD505800CED2A0D10F2B2014B0EE -:10410000BB2B24140B0F4164F0827CB7CAC0C10CD6 -:104110009C022C2502D2A0D10FC020D10F2E200648 -:1041200069E2C12F21020F0F4C69F1B8262406263F -:1041300025022B221E28221D2A200B2920150DAA1C -:10414000092CA11C262415AC9929A51C7B814A6049 -:104150000049B0BB2B24140B0D41CBD67CB7022CED -:1041600025022B221E2E221D7BE9022B0A0064B0A1 -:10417000172CB00728B000DA2007880A28824CC024 -:10418000D10B8000DBA065AFE7C020D10F2624064D -:10419000D2A0D10F26240663FFC7DB601DE20764AF -:1041A000BF422CB00728B000DA2007880A28824CCA -:1041B000C0D10B8000DBA065AFE71DE1FF63FF24EA -:1041C0006C1004282006C0646F8564CA5B29201423 -:1041D0007D9726DA20DB30DC40055D025800192986 -:1041E0002102090A4CC8A3C020D10F00C0B10B9B0B -:1041F000022B2502C020D10F0000022A02033B023D -:104200002C0A015800CAC9AADA20DB30DC40580960 -:10421000E429A011D3A07E97082C0AFD0C9C012C48 -:10422000A411C0512D201406DD022D241463FFA219 -:10423000DA20DB30DC40DD50C0E0580964D2A0D188 -:104240000F0000006C100616E1DA1CE1DA65513B44 -:10425000C0E117E1D62821028B2008084C65807B3D -:104260002932000969516993722A629E6EA8482A10 -:10427000722668A0027AB93F2A629DB44FCBA72B61 -:10428000200C0CBD1106DD0828D28678FB150CBF6A -:104290000A2FF2A368F00488207F89072DD285D3E6 -:1042A0000F65D0602A210419E202D30F7A9B1DDA30 -:1042B00020580864600024002C21041BE1FD7CBB15 -:1042C00013DA20C0B658085FC9536000EFDA2058EF -:1042D0000A46600006DA20C0B6580A436550DDDCA5 -:1042E00040DB308D30DA200D6D515808B8D3A06412 -:1042F000A0CA1CE1B0C05184A18EA00404470E0ED8 -:104300004763FF50002B2104C08C8931C070DF70DF -:1043100009F950098F386EB8172C2066AECC0C0CFA -:10432000472C24667CFB099D105808CA8D10272451 -:104330006694D11EE1B6B8DC9ED0655056C0D7B8A1 -:104340003AC0B1C0F00CBF380F0F42CBF119E19465 -:1043500018E19628967EB04BD30F6DBA0500A08861 -:1043600000C08C2C200CC0201DE19A0CCF11A6FFA0 -:104370002EF285ADCC27C4CF0E4E0B2EF685D10F75 -:10438000C0800AB83878D0CD63FFC1008E300E0EE1 -:104390004763FEBD2A2C742B0A01044D025808BD48 -:1043A0002F200C12E18B0CF911A699A2FF27F4CF54 -:1043B000289285D2A008480B289685D10FC020D11D -:1043C0000F0000006C1004C060CB55DB30DC4005F2 -:1043D0005D02022A025BFF9B29210209084CC88268 -:1043E000D2A0D10F2B2014B0BB2B24140B0C41CB2B -:1043F000C57DB7EBC0C10C9C022C2502D2A0D10F09 -:104400000000022A02033B02066C02C0D0C7F72E4E -:10441000201428310126250228240A0FEE012E241B -:104420001458010D63FFA300262406D2A0D10F006B -:104430006C1006282102D62008084C65809D2B2090 -:104440000C12E15B0CB811A2882A8286B5497A93D6 -:104450000260009719E15809B90A2992A3689008E7 -:104460002A620009AA0C65A0822882851CE1636487 -:1044700080799C80B887B14B9B819B10655074C03C -:10448000A7D970280A01C0D0078D380D0D42CBDEA8 -:104490001FE1441EE1452EF67ED830D30F6D4A054C -:1044A00000808800908C2E3008C0A000EE322E7460 -:1044B0000028600C19E1470C8D11A2DDA988C020ED -:1044C0002CD2852284CFD2A00CBC0B2CD685D10F48 -:1044D000C0F0038F387FA0C063FFB400CC582A6CB3 -:1044E00074DB30DC405807F1C020D10FDA60580986 -:1044F000BE63FFE7DD402A6C74C0B0DC705808650D -:104500002E30088B1000EE322E740028600C19E15A -:10451000300C8D11A2DDA988C0202CD2852284CF39 -:10452000D2A00CBC0B2CD685D10F00006C10042936 -:104530002014282006B199292414688124C0AF2CA6 -:104540000A012B21022C24067BA004C0D02D2502B9 -:10455000022A02033B02044C02C0D05800BFD2A082 -:10456000D10FC020D10F00006C1004293101C2B45A -:1045700029240A2A3011C28378A16C7BA169645076 -:10458000472C2006C0686FC562CA572D20147CD7FF -:1045900022DA20DB30DC40DD505BFFA52921020957 -:1045A0000E4CC8E2C020D10FC0F10F9F022F250290 -:1045B000C020D10FDA20DB30C0C05BFFDC28201424 -:1045C00006880228241463FFC72920151BE0FB2A54 -:1045D000200BC0C09C240BAA092BA11C2C2415ABBA -:1045E0009929A51C63FF9900C020D10FDA20DB3088 -:1045F000DC40DD50C0E0580875D2A0D10F000000AB -:104600006C1004CB5513E0F625221F0D46110655FC -:104610000CA32326221E25261F06440B24261E73C8 -:104620004B1DC852D240D10F280A80C04024261FFB -:10463000A82828261E28261DD240D10FC020D10F21 -:10464000244DF824261E63FFD80000006C100428B7 -:104650002006D6206E85026000DE17E0D51DE0DC66 -:1046600019E0D5C0C1C0202A8CFC64A1322B6102A4 -:10467000B44E0B0B4C65B0A82B600C2A62000CB832 -:10468000110788082F828609B90A7FE30260009F1C -:104690002992A368900509AA0C65A09328828564D5 -:1046A000808DB8891BE0DA94819B8065514DC0B73D -:1046B000B838C0A1C0E009AE380E0E4264E0481A16 -:1046C000E0B81FE0B92FA67EB04A6DAA0500808829 -:1046D00000908CC0A02E600C0CE811A7882F82855A -:1046E000ADEE0F4F0B2F86852B600622E4CF68B10D -:1046F0002A296015C0B2C99AD2A02D61022B640686 -:104700000CDD022D6502D10FC0E008AE387EB0B7D7 -:1047100063FFAB00226406D2A0D10F00D2A0D10F5C -:1047200000CC57DA60DB30DC4058089DC020D10F48 -:10473000DA6058092D63FFE80028221E29221D781F -:104740009902280A00C176C1C1C1D21BE0A5C124CB -:10475000AB6B6480437891402A80000CAF0C64F00E -:10476000AE0DAE0C64E0A802AF0C64F0A207AE0C74 -:1047700064E09C2FACE864F0962EACE764E0902FE8 -:10478000ACE664F08A2A800708A80B088A027B83BB -:10479000022A8DF8D8A065AFBBC0906000730000FE -:1047A0002B600C0CB811A7882E82866EE87909BAA6 -:1047B0000A2AA2A368A0048E607AE96B2A82856423 -:1047C000A0651FE08DC0E32E64069EA19FA01FE0A0 -:1047D000B92E600A92A30FEE029EA28E600FEE0227 -:1047E0009EA42F60147AFF4722A417ADBE2F8285A6 -:1047F00022E4CF2FFC182F868563FE702A6C74C0CC -:10480000B1DC90DD405807A31DE072C0C163FEC457 -:10481000D9A0DA60DB30DC40DD50C2F0C1E009FE37 -:10482000395807EAD2A0D10FDA605808EF63FEF0DA -:104830002CA4170DBE0829828522E4CF299C1829B3 -:10484000868564500C2A6C74044B0258016BD2A00C -:10485000D10FC020D10F00006C10062B221E282281 -:104860001D93107B8901C0B0C0C9C03BC1F20406D2 -:10487000401DE05BC0E2C0740747010E4E01AD2D44 -:104880009E11C0402E0A1464B06E6D084428221D8B -:104890007B81652AB0007EA13B7FA1477B51207CB4 -:1048A000A14968A91768AA1473A111C09F79A10C26 -:1048B000C18B78A107C1AE290A1E29B4007CA12BA7 -:1048C0002AB0070BAB0BDAB07DB3022ABDF8DBA030 -:1048D000CAA563FFB428B01089116987BB649FB86B -:1048E00063FFDC00647FB463FFD50000646FD0C059 -:1048F00041C1AE2AB40063FFC62B2102CEBE2A22DC -:104900001D2B221E7AB12A8C107CB1217AB901C0EC -:10491000B0C9B913E026DA2028B0002CB00703880C -:104920000A28824CC0D10B8000DBA065AFE7D240E3 -:10493000D10F8910659FD463FFF300006C1008C08D -:10494000D0C8598C302921020C0C4760000C8E30E5 -:104950000E1E5065E19E292102C0C116E015090B0B -:104960004C65B0908A300A6E5168E3026000852F72 -:10497000629E1BE00E6EF8532BB22668B0052E2205 -:10498000007BE94727629DB748CB7F97102B200C0F -:10499000B04E0CBF11A6FF29F2869E12798B4117EB -:1049A000E00507B70A2772A368700488207789306A -:1049B00029F285DF90D7906590652A210419E03CA3 -:1049C0007A9B22DA2058069F600029002C21041BC4 -:1049D000E0387CBB18DA20C0B658069AC958600186 -:1049E0004CC09063FFCCDA2058087F600006DA20C4 -:1049F000C0B658087D655135DC40DB308D30DA209B -:104A00000D6D515806F2C0D0D3A064A12029210217 -:104A1000C05184A18CA00404470C0C4763FF3E00E6 -:104A2000C09C8831DBD008F850089B3828210498B6 -:104A3000116E8823282066AC8C0C0C472C24667CD5 -:104A4000BB159F139E148A108B115807028E148F6A -:104A500013C0D02D24668A30C092C1C81BDFEC7F02 -:104A6000A6099BF099F12CF40827FC106550A4B816 -:104A70003ADF70C051C08007583808084264806728 -:104A800018DFC819DFC929867E6A420AD30F6DE98B -:104A90000500A08800F08CC0A08930B4E37F962880 -:104AA000C0F207E90B2C94089B909F912F200C12C9 -:104AB000DFC80CF811A688298285A2FF2DF4CFD279 -:104AC000A009330B238685D10F22200C891218DF11 -:104AD000C00C2B11A6BBA8222D24CF2CB285D2A0AE -:104AE0000C990B29B685D10FC087C0900A59387927 -:104AF000809663FF8ADB30DA20C0C1C0D05BFF56EE -:104B0000292102C0D02A9CFE65AE4D2D2502C09001 -:104B100063FE45009E142A2C74C0B1DC70DD405841 -:104B200006DD8E14C0D01BDFB9C1C863FF6AC02088 -:104B3000D10F00006C100628210216DF9D08084CDA -:104B400065821929629E6F980260022019DF9829F8 -:104B500092266890078A2009AA0C65A20F27629DF9 -:104B6000C0CC6472072B21048E31C0A0DDA00EFEE4 -:104B7000500ECD386EB8102C2066B1CC0C0C472CE2 -:104B800024667CDB026001EFC0C12930081BDF8A8C -:104B900064909C2F0AFFC0D3B09E64E10268921318 -:104BA0006450882A2C74044B025800930AA202060F -:104BB000000000002B200C2721040CBC11A6CC29DE -:104BC000C286280A087983026001B919DF7A09B917 -:104BD0000A2992A36890082E220009EE0C65E1A430 -:104BE0002EC28564E19E26200713DF836E7B026060 -:104BF000019A17DF7A1FDF8319DFB0C0D228200A9D -:104C000093E09DE1A9690F880298E22F90802A9491 -:104C100080B1FF07FF029FE32EC2851FDF6D0EDE0E -:104C20000BAFBF2AF4CF2EC685655F76C020D10FAB -:104C30002830102930112E301300993200ED3264E3 -:104C400080EE2A30141FDF9D00AA3278EF050F9EF8 -:104C5000092DE47F1EDF9B66A0050F98092A84803A -:104C6000B4A718DF98C76F009104AE9EDDE000AFD7 -:104C70001A00C31A6EE1052DB2000DED0C1EDF9275 -:104C800008D81C063303AE882A848B2EB02E2784C6 -:104C90008C03EE010FEE022EB42E58018F63FEFF3F -:104CA0002931082925042830142E3109B088648060 -:104CB000A32E240AC0812E30162CB4232E240BB42C -:104CC000EF2F240C8C378B36292504DEB0DFC00C87 -:104CD0008F390B8E390FEE0264EEC4089F1101C4A8 -:104CE000048D380CB81800C4040CBE1800EE110E68 -:104CF000DD02C0E30EFF021EDF669F719E701EDFA5 -:104D0000658F2098739D7405FF110BCD53C180985A -:104D1000750FDD020EDD029D721EDF242A24662F30 -:104D2000629D2AE4A22FFC182F669D63FE7100008D -:104D3000002F30121BDF6600FA3278FF050B980B4C -:104D40002A847F66D0050B9A0B2DA4802A3011008F -:104D5000AA3263FF442F240A9E2B63FF56CC57DAF6 -:104D600020DB30DC4058070EC020D10F00DA20C015 -:104D7000B658079D63FFE500DA70580636C0A02AD2 -:104D8000246663FE02DA2058079863FFCFB16928D2 -:104D9000200A8620090947991129240798107F8144 -:104DA0002693E027E50A9AE388109DE119DF428DFA -:104DB00011096F029FE42DE416098802C0D398E21E -:104DC0002A240763FE5100001DDF0B0868118F11B4 -:104DD000892B93E008FF02C08F9FE50D990299E2AD -:104DE000047F11C0D49DE108FF029FE463FFD0005F -:104DF0006C1004C020D10F006C100485210D3811F7 -:104E000014DEE98622A42408660C962205330B934F -:104E100021743B13C862D230D10FC030BC29992114 -:104E200099209322D230D10F233DF8932163FFE3E1 -:104E30006C100AD620941817DEDED930B8389819CD -:104E40009914655252C0E1D2E02E61021DDEDB0EE4 -:104E50000E4C65E1628F308E190F6F512FFCFD658E -:104E6000F1558EE129D0230E8F5077E66B8F181EF7 -:104E7000DF18B0FF0FF4110F1F146590CE18DF1567 -:104E80008C60A8CCC0B119DEC928600B09CC0B0D11 -:104E9000880929811C28811A2A0A0009880C08BA65 -:104EA000381BDF0B0CA90A2992947B9B0260008CB3 -:104EB0002B600C94160CBD11A7DD29D286B8487959 -:104EC00083026000D219DEBB09B80A2882A39817B2 -:104ED0006880026000A36000A51ADEFF84180AEE55 -:104EE00001CA981BDEB28C192BB0008CC06EB313B4 -:104EF0001DDEAF0C1C520DCC0B2DC295C0A17EDB6C -:104F0000AE6000380C0C5360000900000018DEF1A0 -:104F10008C60A8CCC0B119DEA528600B09CC0B0DA4 -:104F2000880929811C28811A2A0A0009880C08BAD4 -:104F3000380CA90A2992947E930263FF72DA60C04A -:104F4000BA58072964507360026600001ADE988C14 -:104F5000192AA0008CC06EA31A18DE940C1C5208EB -:104F6000CC0B18DEDB2BC295C0A178B30263FF3FE8 -:104F700063FFC9000C0C5363FF09896078991829F5 -:104F8000D285C9922B729E1DDE896EB8232DD22642 -:104F9000991369D00B60000DDA6058071360001791 -:104FA0000088607D890A9A1A29729D9C129915CFF2 -:104FB00095DA60C0B658070C6551F58D148C18DB76 -:104FC000D08DD0066A020D6D51580580D3A09A1479 -:104FD00064A1DD82A085A1B8AF9F19050547020233 -:104FE000479518C05163FE602B6104C08C8931C0A5 -:104FF000A009F950098A386EB81F2C6066A2CC0C43 -:105000000C472C64667CAB119F119E1B8A155805BA -:10501000918E1B8F11C0A02A64669F1164F0E12954 -:1050200012032812096DF9172F810300908DAEFE2F -:105030000080889F9200908C008088B89900908CA6 -:1050400065514E8A10851A8B301FDE6B88122960DD -:105050000708580A2C82942D61040ECC0C2C8694DF -:105060006FDB3C1CDE95AC9C29C0800B5D50A29987 -:1050700009094729C48065D0DA2E600CC0D01FDE34 -:10508000540CE811AFEEA7882282852DE4CF0242AE -:105090000B228685D2A0D10F8E300E0E4763FDA65F -:1050A000A29C0C0C472C64077AB6CD8B602E600A4C -:1050B000280AFF08E80C64810E18DE7E831682132E -:1050C000B33902330B2C34162D350AC02392319F8D -:1050D00030C020923308B20208E80292349832C0FD -:1050E000802864072B600CD2A01CDE390CBE11A7EF -:1050F000EE2DE285ACBB28B4CF0D9D0B2DE685D1FE -:105100000F8B1888138D30B88C0D8F470D4950B414 -:10511000990499100D0D5F04DD1009FF029F800DA9 -:10512000BB029B8165508D851AB83AC0F1C0800CD6 -:10513000F83808084264806B1BDE1A19DE1B29B69A -:105140007E8D18B0DD6DDA0500A08800C08CC0A08F -:1051500063FEF30082138B161DDE2B28600AC0E06D -:105160002EC4800D880202B20B99239F20C0D298D2 -:10517000229D2122600CB2BB0C2D11A7DD28D28507 -:1051800008BB0B18DE132BD685A8222E24CFD2A065 -:10519000D10F9E1B851A2A6C748B185BFF178E1B10 -:1051A00063FEA300C087C0900AF93879809263FF3C -:1051B00086C020D10F9E1B2A6C74C0B18D18580573 -:1051C000358E1B851A63FE7E886B8213891608BE96 -:1051D000110ECE0202920B9E25B4991EDE069F2070 -:1051E0000E88029822C0EF04D8110E88029824C0BD -:1051F000E49E21C080D2A02B600C2864071CDDF443 -:105200000CBE11A7EE2DE285ACBB28B4CF0D9D0BD3 -:105210002DE685D10F0000006C1004C020D10F00D6 -:105220006C10048633C071C030600001B1330031AE -:105230000400741A0462017460F1D10F6C1004024E -:105240002A02033B025BFFF61CDDDC1BDE24C79F4A -:1052500088B009A903098A019AB079801EC0F00FAD -:10526000E4311DDDD30002002BD2821EDE1D2AC1D7 -:10527000020EBB022BD6820AE431D10F28C102C133 -:105280009009880208084F28C50208E431D10F00B0 -:105290006C1004C0C00CE43112DDC81ADDC5000278 -:1052A0000029A28218DE111BDE0F2621020B9901B4 -:1052B00008660129A68226250206E43114DE0C15B3 -:1052C000DE07236A902326128550242611252613F3 -:1052D000222C40D10F0000006C1008D6102B0A645D -:1052E000291AB41ADDB20D23111CDDB30F2511B834 -:1052F0001898130E551118DDFEAC55A838AA332C9A -:1053000080FF2A80FEA933288D0129800108AA1177 -:105310002880000CAA0208881109880208AA1C2803 -:105320008C0828160458084C14DDA40AA70224414E -:10533000162A30802B120407AA28580847B1338B4D -:1053400013B4559A6004AC28B4662C56277B69E0E8 -:1053500016DDDB9412C050C0D017DD979D15D370B9 -:10536000D4102F60802E60829F169E178816728937 -:105370001A8D128C402A607F0DCC282B3A200CAA63 -:1053800028580835C0B10ABE372E35408F1772F93C -:105390001A8D128C402A60810DCC282B3A200CAA41 -:1053A0002858082DC0B10ABE372E3542B233B44456 -:1053B000B1556952B6B466C0508F15B877D370B284 -:1053C000FF9F156EF899D10F6C1004C021D10F000A -:1053D0006C1004270A001CDD761FDD871EDD8A1D88 -:1053E000DD731ADDB51BDDC3C02824B0006D2A753E -:1053F000AA48288080C09164806100410415DD6E58 -:10540000C03125502E00361A0655010595390C5627 -:10541000110C66082962966E974D0D590A2992243F -:1054200068900812DDA702420872993B2362951228 -:10543000DD6BCB349F300282020E4402C092993160 -:1054400094329233AD52246295C090244C1024665D -:105450009524B0002924A0AA42292480B177B14420 -:1054600004044224B400D10FD10FD10F6C10041AE0 -:10547000DD4F2AA00058021C5BFFD5022A02033B25 -:10548000025BFFD11BDD4DC9A12CB102C0D40DCCF4 -:10549000020C0C4F2CB5020CE431D10FC0A00AE471 -:1054A0003118DD430002002F828219DD562EB10231 -:1054B00009FF022F86820EE431D10F006C1004C068 -:1054C0002002E43114DD3D16DD3A00020022628242 -:1054D000234102732F0603E431C020D10F19DD8769 -:1054E0001ADD862841020A2A010988012A668228D3 -:1054F000450208E43115DD7D12DD8225461DD10F00 -:105500006C1004292006289CF96480A02A9CFD6563 -:10551000A0968A288D262F0A087AD9042B221FC824 -:10552000BD2C206464C0812E22090EAE0C66E0788A -:105530002B200C1EDD1F0CBC11AECC28C28619DD41 -:105540001D78F3026000AD09B90A2992A36890089A -:105550002E220009EE0C65E09B29C2851FDD276421 -:1055600090929F90C0E41FDD349E9128200AC0E0F5 -:105570009E930F8802989288200F880298942F207B -:10558000079A979D962F950A2E24072820062920F2 -:105590006468833328C28512DD0E288C20A2B22EC7 -:1055A00024CF28C685C020D10FC020D10F2A206A61 -:1055B0000111020A2A4165AF52DA20C0B05805D164 -:1055C00064AFE5C021D10F00649FC81FDCFB2D2014 -:1055D000168FF209DD0C00F10400DD1AADAD9D2936 -:1055E00012DCFC28C285A2B22E24CF288C2028C62B -:1055F00085C020D10FC021D10F0000006C100426FF -:105600000A001BDD4015DCEC28206517DCE9288C3E -:10561000FE6480940C4D110DBD082CD2F52BD2F4F4 -:105620002ED2F77CB13DB4BB2BD6F47BE9052BD24F -:10563000F62BD6F47CB92C2AD2F62AD6F52AD6F443 -:1056400006E4310002002872822AFAFF0041042990 -:105650000A012F510200991A0A9903098801287634 -:10566000820FE4312624652BD2F48E5A2CD2F5B069 -:10567000EE9E5A7BCB1629D2F62FD2F70CB80C0926 -:10568000FF0C08FF0C0F2F14C8F96000320BCA0C76 -:105690000A2A14CEA92B5102C0C20CBB020B0B4F1D -:1056A0002B55020BE431D10F00DB30DA205BFF9485 -:1056B0001BDD1564AF5D0C4D11ADBD63FFA800008F -:1056C00006E4310002002F728218DCD42E51020849 -:1056D000FF022F76820EE431D10F00006C1004C05F -:1056E0003003E43116DCB315DCB40002002462821E -:1056F00074472118DD05875A084801286682CD7352 -:1057000019DD030C2A11AA9922928329928472919D -:10571000038220CC292B51020BE431C020D10F0091 -:105720001FDCFC2E51020FEE012E55020EE431B0AB -:105730002DB17C9C5A12DCF708DD112D5619D10FC2 -:105740006C10061BDC9A1EDC9C22B0001ADCF36F86 -:1057500023721DDCDAC04818DCF21FDCF0DC10D547 -:10576000C083F000808600508A6D4A4F0F35110DBE -:1057700034092440800B560A296294B1330E55092E -:105780002251400F44110C440A874009A80C02889A -:105790003622514107883608770CA89929669497D4 -:1057A00040296295874109A80C0288360788360887 -:1057B000770CA8992966959741030342B1380808E8 -:1057C0004298F0D10F1CDCD713DCD827B00023326D -:1057D000B5647057C091C0D016DCD615DCD4C0407B -:1057E0002AC00003884328C4006D793C004104B1FD -:1057F0004400971A7780148E502FB2952DB695AF2E -:10580000EE2EED2006EE369E5060001877A009833C -:10581000509D5023B69560000223B295223D20068C -:10582000223622B695B455B8BBD10F000388432861 -:10583000C400D10F6C1004C04004E43115DCBE007C -:105840000200885013DCBDCB815BFFBD1CDCBC0CAF -:105850002D11ADCC2BC2822AC28394507BAB142E67 -:10586000C28429C2850ABD0C0E990C0D990C092918 -:10587000146000050BA90C092914993015DC4F2A76 -:1058800051020AE4312A2CFC58004B2B32000AA2A8 -:10589000022BBCFF9B30CCB6C8A4D2A0D10F000015 -:1058A00004E4311EDC430002002DE2822FBAFF2CFB -:1058B00051020FDD012DE6820CE431D10F00000012 -:1058C0006C1004D10F0000006C1004C020D10F0038 -:1058D0006C100413DC9BC0D103230923318DC0A0BD -:1058E0006F340260008D19DC321BDC3317DC940C42 -:1058F0002811A8772672832572822CFAFF765147E9 -:1059000088502E7285255C0425768275E9052572FE -:10591000842576827659292E72842E76822E76837D -:105920000AE4310002002392820021042FB1020018 -:10593000D61A0C66030633012396820FE4312672D1 -:105940008325728260000200D8A07659220AE431D1 -:1059500000020023928200210400D21A2FB1020C0F -:1059600022030232012296820FE431D280D10F004D -:10597000D280D10FC020D10F6C1004DB30862015EF -:10598000DC0B280A00282502DA2028B0002CB007FA -:1059900005880A28824C2D0A010B8000DBA065AF28 -:1059A000E61ADC040A4A0A29A2A3C7BF769101D1EC -:1059B0000F2BA6A3D10F00006C1004C0D1C7CF1BC2 -:1059C000DBFE19DBFB17DBF90C2811A87786758540 -:1059D00074C0A076516288508E77B455957475E97D -:1059E00003857695747659278F769F759F740AE4A0 -:1059F00031000200239282B42E2FB10200E1040094 -:105A0000D61A0C66030633012396820FE43186759D -:105A100083747639280AE4310002002E9282B4227F -:105A200000210424B10200DF1A0CFF030FEE012E47 -:105A3000968204E431D280D10FD8A07651D6D2809C -:105A4000D10F00006C1004290A801EDC001FDC004E -:105A50001CDBD80C2B11ACBB2C2CFC2DB2850FCC35 -:105A6000029ED19CD0C051C07013DBFC14DBFB182C -:105A7000DBF92AB285A82804240A234691A986B80E -:105A8000AA2AB685A98827849F25649FD10F000084 -:105A90006C100419DC2C0C2A11A9A98990C48479F2 -:105AA0008B761BDC1AABAC2AC2832CC2847AC16809 -:105AB0008AA02BBC30D3A064A05E0B2B0A2CB2A30F -:105AC00019DBE568C0071DDC20D30F7DC94AA92971 -:105AD000299D0129901F68913270A603D3A0CA9E08 -:105AE000689210C7AF2AB6A32A2CFC5BFFB3D23052 -:105AF000D10F000013DBC503A3018C311DDBB60CF5 -:105B00008C140DCC012CB6A363FFDC00C020D10F98 -:105B1000DA205BFFCCC020D10FC020D10F000000E5 -:105B20006C1004DB30C0D019DBA1DA202830002251 -:105B3000300708481209880A28824CDC200B8000B4 -:105B40001BDB9C0C4A11ABAA29A28409290B29A6AC -:105B500084D10F006C1004C04118DB9517DB970C43 -:105B60002611A727277030A866256286007104A336 -:105B70005500441A75414822628415DBB802320B85 -:105B8000C922882117DB940884140744017549054C -:105B9000C834C020D10FD10F0809471DDBEBC0B2BC -:105BA0008E201FDB820E0E43AFEC2BC4A00FEE0A3B -:105BB0002DE6242A6284C0200A990B296684D10F1D -:105BC000C020D10F6C1004DB30C0D018DB78DA2095 -:105BD00025300022300708580A28824CDC200B8030 -:105BE000008931709E121BDB720C4A11ABAA29A2EC -:105BF0008409290B29A684D10F09C95268532600AC -:105C0000910418DB6DC0A12F811200AA1A0AFF02AD -:105C10002F85121EDB670C4D11AEDD2CD2840C2CAF -:105C20000B2CD684D10FC0811FDB64B89A0A0A47B7 -:105C30002EF11200A10400881A08EE022EF5121DA2 -:105C4000DB5C0C4C11ADCC2BC2840B2B0B2BC68414 -:105C5000D10F00006C1004DB30C0D019DB54DA2007 -:105C600028300022300709880A28824CDC200B806B -:105C7000001CDB4F0C4B11ACBB2AB2840A2A0B2A46 -:105C8000B684D10F6C1004C04118DB4916DB4B0CF5 -:105C90002711A626266030A872252286006104A35B -:105CA0005500441A75410822228402320BD10F009C -:105CB000C020D10F6C100415DBA502491429561120 -:105CC0002452120208430F8811C073008104003669 -:105CD0001A008104C78F00771A087703074401066A -:105CE0004402245612D10F006C10066E230260008D -:105CF000AC6420A7C0A0851013DB7E16DB94C040E7 -:105D0000A6AA2BA2AE0B194164906668915D6892B9 -:105D10005268933C2AA2AA283C7F288C7F0A0A4D0D -:105D20002980012880002AACF208881109880275B0 -:105D300089462B3D0129B0002BB0010899110B9920 -:105D4000027A9934B8332A2A00B1447249B160000A -:105D50004A7FBF0715DB7F63FFB90000253AE86380 -:105D6000FFB10000253AE863FFA90000250A64633B -:105D7000FFA1C05A63FF9C0000705F082534FF0537 -:105D80008C142C34FE70AF0B0A8D142E3D012AE4C6 -:105D9000012DE400DA405BFD5063FFA7D10FD10F66 -:105DA0006C10041ADB0519DB021CDB6A1BDB6BC001 -:105DB00080C07160000D00000022A430B1AA299CAF -:105DC000107B915F26928679C2156E6262C0206D4B -:105DD000080AB12200210400741A764BDB63FFEE3F -:105DE0002292850D6311032514645FCFD650032DD5 -:105DF000436DD9039820B4220644146D492298209B -:105E000098219822982398249825982698279828AE -:105E10009829982A982B982C982D982E982F222CD8 -:105E20004063FF971EDAE327E68027E681D10F0063 -:105E3000C02063FF830000006C1004C062C04112E8 -:105E4000DADE1ADADA13DB452AA00023322D19DB59 -:105E50003F2BACFE2992AE6EA30260008E090E406D -:105E60002D1AC2C2CD0EDC392C251664B0895BFF19 -:105E70009E15DB3B1ADAE52B3AE80A3A015805761B -:105E80002B21160ABB28D3A02B560058058D8B500A -:105E90000ABB082A0A0058058C15DB322D21022C7A -:105EA0003AE80C3C2804DD022D25029C505805845C -:105EB0008B50AABBC0A15805841CDB2B2D21020CE2 -:105EC0003C2806DD0213DB292D25029C3058057C79 -:105ED0008B30AABBC0A258057C2A2102C0B40BAAF1 -:105EE000020A0A4F2A2502580590D10F242423C301 -:105EF000CC2C251663FF760018DB211CDB1D19DB7B -:105F00001E1BDB1C17DAF085202E0AFD1FDB1D2D62 -:105F1000202E24F47A24F47E24F4820EDD0124F46D -:105F2000862E0AF707552806DD02C0750EDD01052D -:105F30000506AB5BA959C0E8AC5C24C4AB0EDD021E -:105F400027C4AC2E0ADFA85527B4EC0EDD0124B41B -:105F5000EBC2E027942C0EDD0224942B2E0A800D38 -:105F60000D4627546C24546B0EDD022D242E63FE47 -:105F7000FC0000006C10042A0A302B0A035BFF4D62 -:105F800012DAF3C390292616C3A1C0B3C08A28260B -:105F9000175BFF48C03CC3B12B26161ADA872AA02C -:105FA0002023261764A079C3A2C0B15BFF42C3A21D -:105FB000C0B15BFF40C3C22C2616C2AFC0B12326BE -:105FC000175BFF3CC28F282616C0FE2F2617C2E2A1 -:105FD0002E26162A0AA1C0B1C0D82D26175BFF3580 -:105FE0002A0AA12A2616C3A6C0B3C1922926175B86 -:105FF000FF31C3C62C2616C1B32A0AA22B2617C00E -:10600000B35BFF2C290AA2292616C185282617C2B0 -:10601000FB2F2616C0E72E26171DDADA2D2610D103 -:106020000FC3A2C0B35BFF2363FF82006C10041C8C -:10603000DAA41BDA9118DAD417DAD516DAD515DA1C -:10604000D5C0E0C0D414DAA01FDA5CC0288FF06D90 -:106050002A36DAC0D9C07C5B020FC90C1CDA9A0C54 -:106060009C28A8C3A6C22A36802A2584A4C2A7CC0D -:106070002D248C2B248A2B24872E248BB1BB2E36E7 -:106080009F2C369E2C369DB1AC1CDA7B1BDAC3C02C -:10609000286D2A33DAC0D9C07C5B020FC90C1CDA28 -:1060A000890C9C28A8C3A6C22A36802B2584A4C2AA -:1060B000B1BBA7CC2D248C2E248B2A248A2E369F6C -:1060C0002C369E2C369DB1ACC07919DA791BDAB525 -:1060D00013DAB31ADAB318DAB414DA7A16DAB404C3 -:1060E000F42812DAB304660C040506A252A858AAD2 -:1060F0005AA3539B3029A50027848AC091C0A52AA2 -:10610000848C29848B17DAAC18DAABA75726361D96 -:1061100026361E2E361F16DAA913DAA9A655043321 -:106120000C2826C82E75002D54AC2E54AB2E54AA24 -:106130002326E62326E52E26E7D10F006C10061352 -:10614000DA8717DA8224723D2232937F2F0B6D0893 -:10615000052832937F8F0263FFF3C0C4C0B01ADA00 -:1061600016C051D94004593929A4206E44020BB5F8 -:1061700002C3281EDA11DDB025E422052D392DE4F5 -:1061800021C0501EDA9019DA8018DA8016DA821DE2 -:10619000DA8E94102A724517DA4C6DA94BD450B39D -:1061A000557A5B17DF50756B071FDA038FF00F5FAF -:1061B0000C12DA4402F228AE2222D681D54013DA3C -:1061C00041746B0715D9FD855005450C035328B163 -:1061D00045A73FA832A93322369D22369E24368019 -:1061E0002B369F2BF48B2CF48C14DA5C24424DC09C -:1061F00030041414C84C6D0806B133041414C8429A -:1062000063FFF20015D9EAC4400031041AD9EBC08B -:10621000D193A200DD1AC138B0DD9DA318DA502B4E -:10622000824D29824E29A51C2882537A871E2C5420 -:10623000008E106FE45D12D9E02F211D23211C2F49 -:10624000251B04330C23251C23251AD10FC06218EB -:10625000DA3F88807E87D989102654006F94191BF5 -:10626000D9D62AB11C0A1A1404AA0C2AB51C2AB5BC -:106270001D2AB51A2AB51BD10F1BD9CF2AB11C0A6A -:106280001A1403AA0C2AB51C2AB51D2AB51A2AB558 -:106290001BD10F001CD9C92BC11D2DC11C2BC51B27 -:1062A00003DD0C2DC51C2DC51AD10F006C1006196D -:1062B000D9C214DA2612DA2915DA44C73FC0E02E13 -:1062C00056A82E56A92E56AA2E56AB23262918D9E3 -:1062D000EADB101CDA3EC0D42A42452D16019C1080 -:1062E00000B0890A880C2896005BFF942B22E318E3 -:1062F000D9B20B5B149B842A22E48B84B1AA0A5A7C -:10630000140BAA0C9A852922E509591499862F2283 -:10631000CD0F5F149F875BFF455BFF1623463BC194 -:10632000B01DD9A51CDA032AD1022C463A0BAA02C9 -:106330000A0A4F2AD50258047C5BFEBF5BFE98C058 -:1063400050C0B016D99B14D9A317DA12C0C0C73EEB -:1063500093122C262DC0306000430000007F9F0F59 -:10636000B155091914659FF4C0500AA9027FA7EF1F -:1063700018D98FDA5008580A28822C2B0A000B8073 -:1063800000005104D2A0C091C7AF00991A0A990326 -:106390009912CE33642067D3202B200795138C12DB -:1063A0002A62827CA85F18D98108580A28822CDAD0 -:1063B000500B8000D2A0643FDA8A310A8A1404AA02 -:1063C00001C8298B210B8B1404BB017BA945DDA0DF -:1063D0007A7B081DD9792DD2000DAD0CDB3019D98F -:1063E000731AD9B82812030ADA28088C021DD9F5C5 -:1063F00009880A28823C0DAA080B8000652F97D3D4 -:1064000020C0B063FF97CB53B1550050040A09195F -:1064100063FF4900DAB07B7B071AD9678AA00ABA02 -:106420000C1BD9A88C310BAB280C8A141CD9E6ACF8 -:10643000BB1CD9E504AA012BC68163FF907FA7C7C7 -:1064400063FF62006C100427221EC08008E4311B29 -:10645000D9580002002AB28219D958003104C0610B -:1064600000661A2991020A6A022AB68209E43115E5 -:10647000D9B30C3811A8532832822432842A8CFCD8 -:106480007841102921022A368297A009690229251C -:1064900002D10F002B21022C32850B6B022CCCFC7D -:1064A0002C368297C02B2502D10F00006C1004C03F -:1064B000E71DD93B1CD93D0D4911D7208B228A20DD -:1064C0000B4B0BD2A007A80C9B72288CF4C8346F1E -:1064D0008E026000A21FD933A298AF7B78B334C973 -:1064E0003DC081C0F0028F380F0F42C9FA2CD67E12 -:1064F000D5206D4A0500308800508C8870089808B7 -:1065000078B16CD2A09870D10FC0F0038F387FE0C3 -:10651000DE63FFD8027B0CAFBB0B990C643046D80E -:1065200030C0F1C05002F5380505426450792CD6D0 -:106530007E0B36122F6C100F4F366DFA05008088D7 -:1065400000208C06440CC081250A0003B208237C7D -:106550000C0385380505426450592CD67E6D4A05DA -:1065600000208800308CD2A0A798BC889870D10FEA -:10657000D2A0BC799970D10FD2302BAD08C0F1C038 -:10658000500BF538050542CB552CD67E083F14C17B -:10659000600F660C064636D30F6D6A050020880032 -:1065A000B08C827063FF2D00C05003F53875E08019 -:1065B00063FF7A00C06002863876E0A063FF9A002D -:1065C000C05003F53875E0C363FFBD006C1004D6FE -:1065D0002068520F695324DA20DB30DC405800F089 -:1065E000D2A0D10FDA20DB30DC405800ED9A242411 -:1065F000240EC02122640FC020D10F00B83BB04C44 -:106600002A2C7489242D200E2E200FA4DDB1EE2E0D -:10661000240FB0DD2D240E2890072D9003A488B000 -:1066200088B1DD2D94032894075BFFA069511DC03C -:10663000E082242A600F18D9662A240329600E8F6D -:106640002029240708FF029F209E64D10FC020D17B -:106650000F0000006C1004942319D95EC0B3083AEF -:10666000110BAA02992019D8D29A2116D8D0C0505D -:1066700028929D2564A2288C1828969DD10F000091 -:106680006C1004282066C038232406B788282466A6 -:10669000D10F00006C1006035A0C0D36110D5C1161 -:1066A000D8208B2282210CBB0C06550F9B82023214 -:1066B0000B928113D8BCD920A38F6450531CD8B837 -:1066C000C0D71BD8B9A256C0E1290A0004E938098D -:1066D000094276F34A044302C99E2BC67E6DAA0581 -:1066E00000208800308C8981A95909FA0C64A079AE -:1066F00099818A82C8ADD290D10FC06002E6387607 -:10670000D0DA63FFD4C020BC89998199809282D16C -:106710000F7F2304292DF8998165BFD963FFE50018 -:10672000028F0CA3FF0F3312931003AA0CD340CB9C -:106730009E2BC67E86106D6A0500208800308CBCBA -:1067400082290A0004F308240A010349380909428E -:10675000CA982BC67E6DAA0500208800308C0F5980 -:106760000CA989BC99998163FF87BC89998163FFD2 -:1067700080C06002E63876D0BA63FFB4C0700247CA -:106780003877D0D063FFCA006C100414D895C1527A -:10679000A424CA3028221D73811B292102CD952AE9 -:1067A000300075A912DA20033B022C30072D0A02B3 -:1067B0005801C2653FDDD10F2B300703BB0BDAB0A8 -:1067C00074B3022ABDF8D3A063FFC6006C1004297D -:1067D0002006C0706E9741292102C08F2A2014C064 -:1067E000B62B240606AA022A241479800227250241 -:1067F0002A221E2C221D7AC10EC8ABDA20DB302CD7 -:106800000A00033D025BF8146450752D21020D0D42 -:106810004CC9D3C020D10F00002E9CFB64E0822F16 -:1068200021020F0F4C65F0911AD8621CD86029A282 -:106830009EC08A798B5D2BC22668B0048D207BD9DF -:106840005229A29DC0F364904A97901DD8732E21BF -:10685000049D9608EE110FEE029E979E9118D86F38 -:10686000C0E527C4A22E24062BA29D2F21022BBCFB -:106870003008FF022F25022BA69DC020D10F00005B -:10688000002F300068F938DA20DB30DC4058004453 -:1068900063FF7700022A022B0A065800D3220A005F -:1068A000D10F655010283000688924022A02033B6A -:1068B00002DC4058003BC020D10FD270D10F000045 -:1068C0002A2C74033B02044C025BFEF863FF3B007E -:1068D000DB30DC402A2C745BFEF5C020D10F0000B9 -:1068E0006C1004C83F89268829A399992609880C29 -:1068F000080848282525CC52C020D10FDB402A2C7F -:10690000745BF93DD2A0D10F6C1004D820D730822F -:10691000220D451105220C928264207407420B134C -:10692000D821D420A383732302242DF885807451A9 -:106930004CBC82C0906D081600408800708C77397E -:1069400003D720C0918680743901D420746102631A -:10695000FFE2CA98C097C0411BD8A0C0A00B8B0C07 -:106960000B4A380A0A42C9AA1DD80E1CD80F2CD6C9 -:106970007EC140D30F6D4A0500208800308C97807F -:10698000D270D10FBC8FC0E00F4E387E90E263FF13 -:10699000D6BC8292819280C0209282D10F000000EA -:1069A0006C1006C0D71CD7FE1BD8000D4911D7208C -:1069B0002E221F28221D0E4E0BD280078A0C2E7607 -:1069C0001F2AAC80C8346FAE026000CB2F0A801A39 -:1069D000D804A29EAA7A7EA33FC93FC0E1C050025C -:1069E000E538050542CA552BC67EDB20D30F6D4A1C -:1069F0000500308800B08C2E721DAE9E0EA50C6472 -:106A00005086D2802E761DC091298403D10FC050AC -:106A100003E53875D0D363FFCD15D7F1027E0CA501 -:106A2000EE643051C0A1250A0002A538033A0205E0 -:106A300005426450922BC67E0E35129510255C10CF -:106A4000054536D30F6D5A0500A08800208CC0A1E3 -:106A5000A3E2C05023FA8003730C03A538AF73057B -:106A600005426450722BC67E851005450C6D5A0593 -:106A700000208800308CD280C0A10E9B0CAB7BAF75 -:106A8000BB2B761D2A8403D10FD280C0C1AF7D2DD0 -:106A9000761D2C8403D10F00D2302E8D08C0F1C09A -:106AA000500EF538050542CB592BC67E0A3F14C15E -:106AB000600F660C064636D30F6D6A05002088000D -:106AC000E08C22721D63FF03C061C05003653875FE -:106AD000D80263FF6263FF5CC05002A53875D0879F -:106AE00063FF8100C06003F63876D0BF63FFB90052 -:106AF0006C10042A201529201614D7AF0A990CCB44 -:106B00009D2E200B04ED092BD11C8F2809BC36AC1F -:106B1000AA0CBB0C2BD51C0A0A472A2415CAAF8B1A -:106B2000438942B0A800910400881AA8FF0FBB0255 -:106B30009B278F260FB80C783B1AC020D10F00007E -:106B4000292102C0A20A9902292502C021D10F00E1 -:106B50008B2763FFDC2BD11C0CAA0C0A0A472A24C2 -:106B600015ACBB2BD51CC9AE8B438C288F42B0AD66 -:106B700000F10400DD1AADCC0CBB029B27DA20B774 -:106B8000EB580019C021D10F9F2763FFEF000000D1 -:106B90006C100428203C64304705306000073E013B -:106BA000053EB156076539054928C77FA933030655 -:106BB00041076603B166060641A6337E871E222181 -:106BC00025291AFC732B1502380C09816000063E3A -:106BD00001023EB12406423903220AD10FD230D13C -:106BE0000FC05163FFC000006C100427221EC0803C -:106BF00008E4311DD76F0002002CD2821BD76F0032 -:106C00003104C06100661A2BB1020C6C022CD682D2 -:106C10000BE43119D7F20C3A11AA932832829780EB -:106C2000253282243284B45525368275410A2921C1 -:106C300002096902292502D10F2A21022B32830A77 -:106C40006A022B36822A2502D10F00006C1004192B -:106C5000D76327221EC08009770208E4311DD7546C -:106C60000002002CD2821BD754003104C0610066A0 -:106C70001A2BB1020C6C022CD6820BE43119D7D737 -:106C80000C3A11AA932832829780253282243284CA -:106C9000B45525368275410B2A21020A6A022A253B -:106CA00002D10F002B21022C32830B6B022C368277 -:106CB0002B2502D10F0000006C10041BD73D0C2ABD -:106CC00011ABAA29A286B438798B221BD73A19D7DF -:106CD000610B2B0A2BB2A309290868B00274B90D05 -:106CE000299D0129901F6E920822A285D10FC020F4 -:106CF000D10FC892C020D10FDA205BEF35C020D170 -:106D00000F0000006C100414D72A28429E19D727C0 -:106D10006F88026000BA2992266890078A2009AA23 -:106D20000C65A0AC2A429DC0DC64A0A42B200C19E9 -:106D3000D7210CBC11A4CC2EC28609B90A7ED3027D -:106D400060009A2992A36890078D2009DD0C65D018 -:106D50008C25C2856450862D2104C0306ED80D2C40 -:106D60002066B8CC0C0C472C246665C07B1CD79CD5 -:106D700018D7281AD71E19D72F1DD724C0E49E5123 -:106D80009D508F209357935599539A569A5408FFC4 -:106D9000021AD73A9F5288269F5A9E599D58935E51 -:106DA0009C5D935C9A5B080848058811985FC0D881 -:106DB0001FD7080CB911A499289285AFBF23F4CF2F -:106DC000288C402896858E262D24069E29C020D109 -:106DD0000FCA33DA20C0B65BFF84C72FD10FC93A80 -:106DE000DA205BFF81C72FD10FDBD05BFE1A232493 -:106DF000662B200C63FF7500C72FD10FC72FD10F53 -:106E00006C1004C85B29200668941C689607C02093 -:106E1000D10FC020D10FDA20DB30DC40DD502E0A4C -:106E2000005BFE6AD2A0D10F2E200C18D6E10CEF29 -:106E300011A8FF29F286C088798B751AD6DE0AEA76 -:106E40000A2AA2A368A0048B207AB96423F285647D -:106E5000305E1CD6E82A0A802D2068292067282168 -:106E6000040B991104881109880208DD02C09428D6 -:106E70004A1008DD0218D6E0993198308B2B9A37EA -:106E80009D340CBB029B32C0C09C359C362A2C74AE -:106E9000DB40C0D318D6CF29F285A8EE299C202C40 -:106EA000E4CF29F6852D2406DD405BFDFAD2A0D182 -:106EB0000FDA20DBE05BFF4CC020D10F6C100AD64C -:106EC000302A2006941128ACF86583872B2122C034 -:106ED000F22A21246550082AAC010A0A4F2A2524E7 -:106EE0007ABB0260037F2C21020C0C4C65C3192E67 -:106EF00022158D32C0910EDD0C65D39088381ED6D8 -:106F0000AC64836B8C37C0B8C0960CB9399914B493 -:106F10009A9A120D991199138F6718D6A7C9FB2851 -:106F200080217F83168B142C22002A200C5BFF62A9 -:106F3000D4A064A3A88F6760002800002B200C89D0 -:106F4000120CBA11AEAA2CA2861DD69A7C9B3E0DBD -:106F5000BD0A2DD2A368D00488207D893024A28563 -:106F600064436427212E07F73607F90C6F9D01D77C -:106F7000F0DA20DB70C1C42D211F5BFF0589268854 -:106F800027DDA009880C7A8B179A10600006C04094 -:106F900063FFCC0000DA208B105BFED58D1065A25C -:106FA00067C0E09E488C649C498B658A669B4A9AC0 -:106FB0004B97458F677F7302600120CD529D10DA99 -:106FC00020DB302C12015BFE768D10C051D6A08FD5 -:106FD000A7C0C08A68974D9A4C8869896A984E996B -:106FE0004F8E6A8A69AE7E77EB01B1AA9E6A9A6972 -:106FF0008B60C0A00B8E1477B701C0A1C091C08474 -:1070000093159D179516C0D025203CC03008580117 -:10701000089338C082083310085B010535400B9D8A -:107020003807DD100BAB100E19402A211F079910ED -:1070300003DD020DBB020553100933020A55112965 -:1070400021250A2A140929140499110A99020933DD -:10705000028A2B2921040BAA021BD6E208991109E6 -:1070600055020855020BAA029A40892088140899F3 -:107070001109880219D6631DD6DC09880298418B54 -:107080002A9346954783150DBB0285168D179B44A1 -:107090008A658966AACAA97C77CB01B1AA07FB0CCD -:1070A0009C669A6588268E29AD87972607EE0C0E7A -:1070B0000E482E25259B672B200C87131ED63D0CD2 -:1070C000B911AE99289285A78828968517D641C010 -:1070D00090A7BB29B4CF871863FE3C008C60C0E04A -:1070E000C091C0F0C034C0B82A210428203C08AAAE -:1070F000110B8B01038301039F380B9B39C03208AE -:10710000FF10038801089E380C881407EE100FEE5C -:107110000203880108983905BF1029211F0ABB11F5 -:1071200007881008FF020BAA0218D6350929140394 -:10713000AA022B212583200B2B1404BB1108331129 -:107140000FBB020B99028B148F2A0B3302083302F8 -:107150008B2B6470868868974D984C8769886A93F2 -:10716000419946974E984FC07077C701C0719A47B2 -:1071700018D69E0B7C100CEC0208F802984418D626 -:107180009B0CBC0208CC029C402A200C295CFEC04F -:10719000801FD6071CD60F0CAE112B2124ACAAAF32 -:1071A000EEB0BB8F132CE28528A4CFAFCC2CE685A4 -:1071B0002A22152B2524B1AA2A26156490DBC9D2D0 -:1071C0008F262E22090DFF082F26060FEE0C0E0E1D -:1071D000482E25256550E4C020D10F00C070934192 -:1071E0009F4499469A4777C70A1CD5F32CC022C002 -:1071F000810C87381CD67F0B781008E80208B8028B -:107200000C8802984063FF8000CC57DA20DB608C4A -:10721000115BFDE3292102689806689403C020D120 -:107220000F2B221EC0A029221D2A25027B9901C0F6 -:10723000B064BFE813D5DE2CB00728B000DA200315 -:10724000880A28824CC0D10B8000DBA065AFE763C1 -:10725000FFCA000068A779DA20DB30DC40DD505B34 -:10726000FEE8D2A0D10FC16DC19D29252C6000047C -:1072700029252CD6902624672F2468DA20DB308C31 -:1072800011DD502E0A805BFD51D2A0D10FC168C123 -:10729000A82A252C63FFDD000000C8DF8C268B297F -:1072A000ADCC9C260CBB0C0B0B482B25252A2C7433 -:1072B000DB602C12015BFD94D2A0D10F2A2C748BC1 -:1072C000115BF6CDD2A0D10FDA205BFE4763FF3809 -:1072D00000DA20C0B15BFE8B65AF2D63FBEDDA20D9 -:1072E0002B200C5BFE5A63FF1F00000012D6428267 -:1072F00020028257C82163FFFC12D63E03E8300407 -:10730000EE3005B13093209421952263FFFC0000FC -:1073100010D63A910092019302940311D611821073 -:1073200001EA30A21101F031C04004E4160002006D -:1073300011D6338210234A00032202921011D5FD88 -:10734000C021921004E43184038302820181000091 -:10735000D23001230000000010D62A910092019340 -:1073600002940311D600821001EA30A21101F1311A -:10737000C04004E41600020011D621821013D5A7E4 -:10738000032202921004E43184038302820181000B -:1073900000D330013300000010D61B91008101653D -:1073A000104981026510448103CF1F92019302941A -:1073B0000311D5EE821001EA30A21101F231C04072 -:1073C00004E41600020011D60D821013D58E03229C -:1073D00002921004E431840383028201C0109103FD -:1073E00091029101810000D43001430012D5BDC04B -:1073F0003028374028374428374828374C233D0168 -:107400007233ED03020063FFFC00000010D5FF9112 -:107410000092019302940311D5FD8210921011D5B0 -:10742000AF8310032202921011D5FA12D5C1921027 -:10743000C04004E41600020011D5F1821013D5A853 -:10744000032202921004E43184038302820181004A -:1074500000D53001530000006C10026E322FD62090 -:10746000056F04043F04745B2A05440C00410400CA -:10747000331A220A006D490D73630403660CB122AE -:107480000F2211031314736302222C01D10FC83B86 -:10749000D10F000073630CC021D10F000000000069 -:1074A00044495630C020D10F6C10020040046B4C90 -:1074B00007032318020219D10F020319C020D10FAC -:1074C0006C100202EA30D10F6C1002CC2503F031AF -:1074D00060000F006F220503F1316000056F230586 -:1074E00003F231000200D10F6C1002CC2502F03003 -:1074F000D10F00006F220402F130D10F6F2304027C -:10750000F230D10FC020D10F6C1002220A20230AC2 -:10751000006D280E28374028374428374828374C34 -:10752000233D01030200D10F6C100202E431D10FA0 -:107530000A0000004368656C73696F204657204459 -:10754000454255473D3020284275696C7420576587 -:1075500064204F63742020382031353A35303A3575 -:1075600030205044542032303038206F6E20636C0D -:10757000656F70617472613A2F686F6D652F666513 -:107580006C69782F772F66775F372E30292C20563D -:10759000657273696F6E2054337878203030372EDF -:1075A00030312E3030202D203130303730313030F6 -:0875B000100701006F4EF8BB4B -:00000001FF diff --git a/firmware/cxgb3/t3fw-7.4.0.bin.ihex b/firmware/cxgb3/t3fw-7.4.0.bin.ihex new file mode 100644 index 0000000..38dda94 --- /dev/null +++ b/firmware/cxgb3/t3fw-7.4.0.bin.ihex @@ -0,0 +1,1917 @@ +:1000000060007400200380002003700000001000D6 +:1000100000002000E100028400070000E1000288E7 +:1000200000010000E0000000E00000A0010000006E +:1000300044444440E3000183200200002001E0002A +:100040002001FF101FFFD0001FFFC000E300043C91 +:100050000200000020006B741FFFC29020006BBCE8 +:100060001FFFC29420006BFC1FFFC29820006C7021 +:100070001FFFC29C200003C0C00000E43100EA3131 +:1000800000A13100A03103020002ED306E2A05000C +:10009000ED3100020002160012FFDBC03014FFDA5F +:1000A000D30FD30FD30F03431F244C107249F0D347 +:1000B0000FD30FD30F12FFD5230A00240A00D30F4A +:1000C000D30FD30F03431F244C107249F0D30FD327 +:1000D0000FD30F14FFCE03421F14FFCB03421F1296 +:1000E000FFCCC0302D37302D37342D37382D373CED +:1000F000233D017233ED00020012FFC4C0302F37E0 +:10010000002F37102F37202F3730233D017233ED6A +:1001100000020012FFBEC0302737002737102737F4 +:1001200020273730233D017233ED03020012FFB95F +:1001300013FFBA0C0200932012FFB913FFB90C028F +:1001400000932012FFB8C0319320822012FFB71312 +:10015000FFB7932012FFB715FFB316FFB6C030D715 +:100160002005660160001B00000000000000000088 +:10017000043605000200D30FD30F05330C6E3B1479 +:100180000747140704437631E604360505330C6F40 +:100190003BED00020012FFA615FFA3230A00D720A3 +:1001A000070443043E0505330C0747146F3BF00377 +:1001B000020012FFA1C03014FFA1D30FD30FD30F41 +:1001C0009340B4447249F2D30FD30FD30F14FF9B63 +:1001D000834014FF9B834012FF9B230A0014FF9A65 +:1001E000D30FD30FD30F9340B4447249F2D30FD33C +:1001F0000FD30F14FF95834012FF95C92F832084DE +:10020000218522BC22743B0F8650B4559630B433FE +:100210007433F463FFE60000653FE1655FDE12FFC3 +:100220007C230A0028374028374428374828374C91 +:10023000233D017233ED03020000020012FF7AC079 +:1002400032032E0503020012FF7813FF819320C0B2 +:1002500011014931004831010200C00014FF7E0441 +:10026000D23115FF7D945014FF7D04D33115FF7CEE +:10027000945014FF7C04D43115FF7C24560014FFE5 +:100280007B04D53115FF7B24560010FF7A03000054 +:10029000000000000000000000000000000000005E +:1002A000000000000000000000000000000000004E +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:1003000000000000000000000000000000000000ED +:1003100000000000000000000000000000000000DD +:1003200000000000000000000000000000000000CD +:1003300000000000000000000000000000000000BD +:1003400000000000000000000000000000000000AD +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B000000000000000000000000000000000003D +:1003C000000000000000000000000000000000002D +:1003D000000000000000000000000000000000001D +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:1004000000000000000000000000000000000000EC +:1004100000000000000000000000000000000000DC +:1004200063FFFC000000000000000000000000006E +:100430000000000000000000000000001FFC0000A1 +:100440001FFC0000E30005C81FFC00001FFC0000AB +:10045000E30005C81FFC00001FFC0000E30005C806 +:100460001FFFC0001FFFC000E30005C81FFFC00042 +:100470001FFFC018E30005C81FFFC0181FFFC018EA +:10048000E30005E01FFFC0181FFFC290E30005E076 +:100490001FFFC2901FFFC290E30008581FFFC290C9 +:1004A0001FFFC58CE3000858200000002000016AEF +:1004B000E3000B542000018020000180E3000CC009 +:1004C0002000020020000203E3000CC02000021CF8 +:1004D00020000220E3000CC420000220200002269D +:1004E000E3000CC82000023C20000240E3000CD0D6 +:1004F0002000024020000249E3000CD42000024CFE +:1005000020000250E3000CE02000025020000259BD +:10051000E3000CE42000025C20000260E3000CF029 +:100520002000026020000269E3000CF42000026C4D +:1005300020000270E3000D0020000270200002790C +:10054000E3000D042000028C2000028CE3000D105B +:100550002000029020000293E3000D10200002AC66 +:10056000200002B0E3000D14200002D0200002F2AF +:10057000E3000D18200003B0200003B0E3000D3CA1 +:10058000200003B0200003B0E3000D3C200003B0C6 +:10059000200003B0E3000D3C200003B0200003B0B6 +:1005A000E3000D3C200003B020006D94E3000D3CFF +:1005B00020006D9420006D94E3007720000000007F +:1005C00000000000000000001FFC00001FFC0000F5 +:1005D0001FFFC5901FFFC67020006D9820006D980A +:1005E000DEFFFE000000080CDEADBEEF1FFFC2A064 +:1005F0001FFCFE001FFFC0941FFFC5C0300000009D +:10060000003FFFFF8040000010000000080FFFFFC8 +:100610001FFFC26D000FFFFF804FFFFF8000000033 +:1006200000000880B000000560500000600000007D +:1006300040000011350000004100000010000001E2 +:100640002000000000001000400000000500000035 +:1006500080000019040000000000080010000005E0 +:10066000806000007000000020000009001FF800FA +:100670008000001EA0000000F800000007FFFFFF40 +:100680000800000018000000010080014200000086 +:100690001FFFC21D1FFFC0DC000100806040000082 +:1006A0001A0000000C0000001000000A00003000DA +:1006B000600008008000001C000100008000001A9B +:1006C00080000018FC0000008000000100004000D5 +:1006D000030000008000040050000003FFFFBFFF84 +:1006E0001FFFC3D400000FFFFFFFF000000016D073 +:1006F0000000FFF7A50000001FFFC4B01FFFC4618A +:100700000001000800000B20202FFF801FFFC455B0 +:1007100000002C00FFFEFFF800FFFFFF1FFFC57861 +:1007200000002000FFFFDFFF0000FFEF01001100CD +:100730001FFFC3D21FFFC590FFFFEFFF0000FFFBAD +:100740001FFFC6301FFFBEA0FFFFF7FF1FFFC064E3 +:100750000000FFFD1FFFC6200001FBD01FFFC5B03A +:100760001FFFC6601FFFC591E0FFFE001FFFC5A071 +:10077000000080001FFFC53C1FFFC5B41FFFC068FD +:100780001FFFC4D01FFCFFD8000100817FFFFFFFC7 +:10079000E1000600000027101FFCFE301FFCFE7069 +:1007A000E10002001FFFC5381FFFC5500003D090B5 +:1007B0001FFFC5642B5063802B5079802B50908095 +:1007C0002B50A6801FFFC4690100110F202FFE00CF +:1007D00020300080202FFF000000FFFF0001FFF805 +:1007E0002B50B2002B50B208000100102B50B180EA +:1007F0002B50B2802B50BA00000100112B50BD28A5 +:100800002B50BC802B50BDA020300000DFFFFE002D +:100810005000000200C0000002000000FFFFF7F4DB +:100820001FFFC06C000FF800044000000010000023 +:100830000C4000001C400000E00000A01FFFC5406D +:100840001FFD00081FFFC5541FFFC5681FFFC57CA3 +:10085000E1000690E10006EC00000000000000004E +:100860000000000000000000010000000000000087 +:100870000000000000000000201000402010004098 +:100880002010004020140080200C0000200C0000EC +:10089000200C000020100040201400802014008054 +:1008A00020140080201800C0201C0100201C010022 +:1008B000201C010020200140201800C0201800C08A +:1008C000201800C0201C0100201800C0201800C003 +:1008D000201800C0201C01002020014020200140E1 +:1008E00020200140202009402020094020200940EC +:1008F0002020094020240980FFFFFFFFFFFFFFFFAA +:10090000FFFFFFFF000000000000000000000000EB +:100910000000000000000000200054902000536000 +:1009200020005490200054902000529C2000529CA3 +:100930002000529C200050DC200050DC200050D4CD +:100940002000504020004EE820004CC820004A9C67 +:100950000000000000000000200054602000532C24 +:10096000200053D0200053D0200051842000518417 +:10097000200051842000518420005184200050CC5C +:100980002000518420004E0820004C7820004A4866 +:10099000000000000000000020000BE820003A30BA +:1009A000200004C02000463C20000BE0200041480D +:1009B000200003F0200045FC20004A2420003E5483 +:1009C00020003D70200039AC2000383C200035ACC0 +:1009D0002000310C20003BCC20002D6C2000280092 +:1009E000200067182000238C2000206C2000201895 +:1009F00020001D04200018182000154820000E2C8F +:100A000020000C2C2000110C200012F82000434084 +:100A100020003E0820000BF0200004C00000000071 +:100A200000000000000000000000000000000000C6 +:100A300000000000000000000000000000000000B6 +:100A400000000000000000000000000000000000A6 +:100A50000000000000000000000000000000000096 +:100A60000000000000000000000000000000000086 +:100A70000000000000000000000000000000000076 +:100A80000000000000000000000000000000000066 +:100A900000000000000000000000000032640000C0 +:100AA0000000000032640000640064006400640020 +:100AB00064006400640064000000000000000000A6 +:100AC0000000000000000000000000000000000026 +:100AD0000000000000000000000000000000000016 +:100AE0000000000000000000000000000000000006 +:100AF00000000000000000000000000000000000F6 +:100B000000001000000000000000000000000000D5 +:100B100000000000000000000000100000000000C5 +:100B200000000000000000000000000000432380DF +:100B300000000000000000000000000000000000B5 +:100B400000000000000000000000000000000000A5 +:100B500000000000005C94015D94025E94035F94C9 +:100B60000043000000000000000000000000000042 +:100B70000000000000000000000000000000000075 +:100B80000000000000000000000000000000000065 +:100B900000000000005C90015D90025E90035F9099 +:100BA00000530000000000000000000000000000F2 +:100BB0000000000000000000000000000000000035 +:100BC0000000000000000000000000000000000025 +:100BD00000000000009C94001D90019D94029E94D2 +:100BE000039F94040894050994060A94070B940043 +:100BF00043000000000000000000000000000000B2 +:100C000000000000000000000000000000000000E4 +:100C100000000000009C90019D90029E90071D9096 +:100C2000039F90047890057990067A90077B900056 +:100C30005300000000000000000000000000000061 +:100C400000000000000000000000000000000000A4 +:100C50000000000000DC94001D9001DD9402DE9491 +:100C600003DF94040494050594060694070794088A +:100C700008940909940A0A940B0B9400430000009D +:100C80000000000000000000000000000000000064 +:100C90000000000000DC9001DD9002DE900B1D9052 +:100CA00003DF9004B49005B59006B69007B790089E +:100CB000B89009B9900ABA900BBB9000530000009D +:100CC00063FFFC0020006B5010FFFF0A00000000D3 +:100CD00020006B7400D23110FFFE0A0000000000FB +:100CE00020006BBC00D33110FFFE0A0000000000A2 +:100CF00020006BFC00D43110FFFE0A000000000051 +:100D000020006C7000D53110FFFE0A0000000000CA +:100D100063FFFC00E00000A012FFF7822002825770 +:100D2000C82163FFFC12FFF303E83004EE3005C076 +:100D30003093209421952263FFFC00001FFFD00018 +:100D4000000400201FFFC5901FFFC670200A00117D +:100D5000FFFB13FFFB03E63101020016FFFA17FF4A +:100D6000FAD30F776B069060B4667763F85415B5C5 +:100D7000541A610F140063FFF90000006C1004C0E6 +:100D800020D10F006C1004C0C71AEF06D830BC2B5E +:100D9000D72085720D4211837105450B9572023380 +:100DA0000C2376017B3B04233D089371A32D12EEA7 +:100DB000FE19EEFEA2767D632C2E0A000882022820 +:100DC0000A01038E380E0E42C8EE29A67E6D4A0532 +:100DD00000208800308C8271D10FC0F0028F387FE4 +:100DE000C0EA63FFE400C0F1C050037E0CA2EE0E27 +:100DF0003D1208820203F538050542CB5729A67E2D +:100E00002FDC100F4F366DFA0500208800308CBCA7 +:100E100075C03008E208280A01058338030342C977 +:100E20003E29A67E0D480CD30F6D8A050020880050 +:100E3000B08C8271D10FC05008F53875C0C163FF06 +:100E4000BBC06002863876C0DA63FFD46C1012161D +:100E5000EED8C1F9C1E8C1C72B221E28221DC0D07F +:100E60007B81312920060BB702299CFA655008289E +:100E70002072288CFF28247264915C2AB0000CA890 +:100E80000C6481670EA90C6492B37FA13769AC2F03 +:100E90006000340000282006D7D0288CFACC572ACE +:100EA00020722AACFF2A24726481352AD0000CA952 +:100EB0000C6491640EAC0C64C31B7FA10768AC0783 +:100EC000C020D10F002D25028A32C0900A6E5065D5 +:100ED000E5B5292467090F4765F5B12C200C1FEEF5 +:100EE000B50CCE11AFEE29E286B4487983026005D5 +:100EF0008219EEB109C90A2992A36890078F2009C7 +:100F0000FF0C65F56E2FE28564F56865559628221D +:100F10001D7B8105D9B060000200C0908B9417EE54 +:100F2000A70B881487740B0B47A87718EEA509BB8D +:100F30001008770297F018EEA317EEA408A8010B8B +:100F400088020747021BEEA097F10B880298F22750 +:100F500090232B902204781006BB1007471208BB81 +:100F6000022890210777100C88100788020B88024E +:100F700017EE988B3307BB0187340B880298F397E1 +:100F80009997F48B9587399BF588968B3898F688D6 +:100F90009797F99BF898F717EE8F28E28507C7080F +:100FA0002D74CF08480B28E68565550F2B221E2887 +:100FB000221D7B89022B0A0064BF042CB00728B0D5 +:100FC00000DA2006880A28824CC0D10B8000DBA002 +:100FD00065AFE763FEE90000292072659E9C60040E +:100FE000E72A207265AEC36004DE00002EB0032C39 +:100FF0002067D4E065C1058A328C330AFF500C4566 +:1010000054BC5564F4EB19EE74882A09A9010988C7 +:101010000C64821FC0926000DD2ED0032A2067D4AA +:10102000E065A0D88A328B330AFC500B4554BC557E +:1010300064C4BE19EE69882A09A9017989D50BEA29 +:101040005064A4E30CEE11C0F02F16132E16168A6E +:10105000E78CE82A16128EE9DFC0AAEA7EAB01B15E +:10106000CF0BA8506583468837DBC0AE89991E78C0 +:101070009B022BCC012B161B29120E2B0A002916C2 +:101080001A7FC3077FC9027EAB01C0B165B49D8BD7 +:10109000352F0A002A0A007AC30564C3CB2F0A0140 +:1010A00065F4892B12162B1619005104C0C100CC0F +:1010B0001A2CCCFF2C16170CFC132C16182B121AFA +:1010C0002A121BDC50581974C0D0C0902E5CF42C2E +:1010D00012172812182F121B2A121A08FF010CAA25 +:1010E000018834074C0AAB8B2812192BC6162F86A1 +:1010F000082A86092E74102924672E70038975B179 +:10110000EA2A7403B09909490C659DB32B20672D19 +:10111000250265B3FA2B221E2C221D7BC901C0B00B +:1011200064BD9C2CB00728B000DA2006880A28820B +:101130004CC0D10B8000DBA065AFE763FD8189BAAD +:10114000B19965909788341CEE2598BA8F331EEEBE +:101150001E0F4F542FB42C8D2A8A320EDD020CAC98 +:10116000017DC9660A49516F92608A3375A65B2C6E +:10117000B0130AED510DCD010D0D410C0C417DC98F +:10118000492EB012B0EE65E3C6C0D08E378CB88A57 +:10119000368FB97CA3077AC9027EFB01C0D1CED9B4 +:1011A00088350AAD020E8E0878EB022DAC0189B7A6 +:1011B000DAC0AF9B79BB01B1CADCB0C0B07DA30778 +:1011C0007AD9027CEB01C0B164B161C09129246776 +:1011D000C020D10F00008ADAB1AA64A0C02C206719 +:1011E0002D250265C3111DEDF88A321EEDFD0DADF2 +:1011F000010EDD0C65D28A0A4E516FE20260028157 +:10120000C090292467090F4765F2F828221D7B89C1 +:10121000022B0A0064BCA82CB00728B000DA200614 +:10122000880A28824CC0D10B8000DBA065AFE76341 +:10123000FC8D00000CE9506492ED0CEF11C0802889 +:101240001611AFBF2F16198EF88BF7DAE08FF92B36 +:101250001610ABFB7FBB01B1EA0CA8506580D688A5 +:1012600037DCE0AF89991C789B022CEC012C161B13 +:1012700029120C2C0A0029161A7AE3077AE9027F50 +:10128000BB01C0C165C2A58B352C0A002A0A007AB1 +:10129000E30564E1CA2C0A0164CE0D60028E883435 +:1012A0001BEDCF98DA8F331EEDC80F4F542FD42C7F +:1012B0008C2A8A320ECC020BAB010CBB0C65BF0A28 +:1012C0000A49516E920263FF018A330AAB5064BE31 +:1012D000F92CD0130AEE510ECE010E0E410C0C412A +:1012E0000ECC0C65CEE42FD012B0FF65F26EC0B00C +:1012F0008E378CD88A362FD2097CA3077AC9027E12 +:10130000FB01C0B165BEC38835DBA0AE8E78EB01B2 +:10131000B1AB89D7DAC0AF9D79DB01B1CAC0C07B60 +:10132000A3077AB9027DEB01C0C165CE9DC09029AB +:101330002467C020D10F88378C3698140CE90C290B +:10134000161408F80C981D78FB07281214B088288A +:101350001614891D9F159B16C0F02B121429161AFE +:101360002B161B8B147AE30B7AE90688158E1678F8 +:10137000EB01C0F165F1BA29121A2F12118A352E2C +:10138000121B9A1AAFEE2F1210C0A0AF9F79FB016B +:10139000B1EE9F11881AC0F098107AE30A7EA90571 +:1013A0002A12017A8B01C0F164F0816001838936D1 +:1013B0008B3799170BE80C981F09C90C291615785B +:1013C000EB07281215B088281615D9C09A199E184F +:1013D0008A1F2E12152A161A2E161BDAC0C0E08C90 +:1013E000177F930B7FA90688188F1978FB01C0E13E +:1013F00065E13E29121A2F12138A352E121B9A1BF1 +:10140000AFEE2F1212C0A0AF9F79FB01B1EE9F1378 +:10141000881BC0F098127AE30A7EA9052A12037A83 +:101420008B01C0F165F10A2E12162E16192A121B15 +:10143000005104C0E100EE1AB0EE2E16170EFF1395 +:101440002F16180FCC01ACAA2F121A0EBC01ACFC3F +:101450007FCB01B1AA2A161B2C161A63FC5E000072 +:101460007FB30263FE3163FE2B7EB30263FC306305 +:10147000FC2A00006450C0DA20DBC0581648C020A7 +:10148000D10FC09163FD7A00C09163FA44DA20DB8A +:1014900070C0D12E0A80C09A2924682C7007581574 +:1014A00038D2A0D10F03470B18ED4FDB70A8287876 +:1014B00073022B7DF8D9B063FA6100002A2C74DB2B +:1014C00040580EB363FAE4000029221D2D25027B4B +:1014D0009901C0B0C9B62CB00728B000DA20068840 +:1014E0000A28824CC0D10B8000DBA065AFE7C0208A +:1014F000D10FC09163FBFF00022A025802440AA2E6 +:1015000002060000022A025802410AA20206000056 +:10151000DB70DA20C0D12E0A80C09E2924682C708E +:1015200007581517C020D10FC09463FBC9C096633C +:10153000FBC4C09663FBBF002A2C74DB30DC405B2D +:10154000FE11DBA0C2A02AB4002C200C63FF2700F0 +:101550008D358CB77DCB0263FDD263FC6D8F358EEC +:10156000D77FEB0263FDC563FC6000006C1004C014 +:1015700020D10F006C1004C020D10F006C10042B80 +:10158000221E28221DC0A0C0942924062A25027BE1 +:101590008901DBA0C9B913ED06DA2028B0002CB010 +:1015A0000703880A28824CC0D10B8000DBA065AFFE +:1015B000E7C020D10F0000006C10042C20062A2167 +:1015C0000268C80528CCF965812E0A094C6591048A +:1015D0008F30C1B80F8F147FB00528212365812774 +:1015E00016ECF529629E6F98026000F819ECF1295B +:1015F00092266890078A2009AA0C65A0E72A629DB6 +:1016000064A0E12B200C0CB911A6992D92866FD9FC +:10161000026000DB1DECE90DBD0A2DD2A368D007E6 +:101620008E200DEE0C65E0C7279285C0E06470BF88 +:101630001DECEE68434E1CECED8A2B0CAA029A704E +:1016400089200899110D99029971882A98748F320E +:101650009F75282104088811987718ECDE0CBF11BB +:10166000A6FF2DF285A8B82E84CF2DDC282DF68577 +:10167000C85A2A2C74DB40580E46D2A0D10FC02085 +:10168000D10F00000029CCF96490B12C206689317B +:10169000B1CC0C0C472C24666EC60260008509F89C +:1016A0005065807F1CECD38A2B0F08400B881008F4 +:1016B000AA020CAA029A7089200899110D99029920 +:1016C00071883398738C329C728A2A9A74893499FF +:1016D0007563FF7D00CC57DA20DB30DC4058151DE8 +:1016E000C020D10F00DA20C0B65815AC63FFE5006A +:1016F000DA205815AA63FFDC00DA20DB30DC40DD9D +:1017000050581638D2A0D10FC858DA20DB30581400 +:101710008A2A210265AFBDC09409A9022925026366 +:10172000FFB200002B21045814351DECAFC0E02E91 +:1017300024668F302B200C0F8F1463FF662921380D +:10174000C08879830263FF5B2C20662B2104B1CC17 +:101750000C0C472C24665814291DECA3C0E02E2441 +:10176000668F302B200C0F8F1463FF376C1004C072 +:10177000B7C0A116ECA015EC92D720D840B822C073 +:10178000400535029671957002A438040442C94B95 +:101790001AEC8519EC8629A67EC140D30F6D4A0547 +:1017A00000808800208C220A88A272D10FC05008C5 +:1017B000A53875B0E363FFD76C1006931394112915 +:1017C0002006655288C0716898052A9CF965A29820 +:1017D00016EC792921028A1309094C6590CD8AA05B +:1017E0000A6A512AACFD65A0C2CC5FDB30DA208CDE +:1017F000115814D8C0519A13C7BF9BA98E132EE25B +:101800000968E0602F629E1DEC6A6FF80260008438 +:101810002DD22668D0052F22007DF9782C629DC735 +:101820009064C0709C108A132B200C2AA0200CBD41 +:1018300011A6DD0A4F14BFA809880129D286AF88F6 +:10184000288C09798B591FEC5C0FBF0A2FF2A36813 +:10185000F0052822007F894729D285D490659075AC +:1018600060004300002B200C1FEC540CBD11A6DDC2 +:1018700029D2860FBF0A6E96102FF2A368F0048853 +:10188000207F890529D285659165DA20581543C9DD +:101890005C6001FF00DA20C0B658154060000C0003 +:1018A000C09063FFB50000DA2058153C6551E48D07 +:1018B000138C11DBD08DD0022A020D6D515813AD5F +:1018C0009A1364A1CEC75F8FA195A9C0510F0F478E +:1018D0009F1163FEFD00C091C0F12820062C2066F8 +:1018E000288CF9A7CC0C0C472C24666FC6098D13E5 +:1018F0008DD170DE02290A00099D02648159C9D385 +:101900008A102B21045813BD8A13C0B02B24662ED5 +:10191000A2092AA0200E28141CEC338D1315EC27E5 +:10192000C1700A773685562DDC28AC2C9C12DED08F +:10193000A8557CD3022EDDF8D3E0DA40055B02DC4B +:10194000305BFF8AD4A028200CB455C0D02B0A8865 +:101950002F0A800C8C11A6CC29C285AF3FAB9929E8 +:10196000C6851CEC1CDEF0AC882D84CF2812022921 +:10197000120378F3022EFDF8289020D3E007880C9C +:10198000C170080847289420087736657FAB891313 +:1019900013EC1A8990C0F47797491BEC18C1CA2838 +:1019A00021048513099E4006EE1187530488118592 +:1019B000520E88020C88029BA09FA18F2B9DA59898 +:1019C000A497A795A603FF029FA22C200C1EEC0152 +:1019D000AECE0CCC1106CC082BC2852DE4CF2BBC8F +:1019E000202BC6852A2C748B11580D69D2A0D10FDB +:1019F00028203DC0E07C877F2E24670E0A4765A023 +:101A00007B1AEBFF88201EEBED8F138EE48FF4081A +:101A100088110A88020F8F14AFEE1FEBFA98910F0E +:101A2000EE029E901EEBF9C0801AEBEA2CD285AA3A +:101A3000BAB8CC28A4CF2CD6852C21022F20720E28 +:101A4000CC02B1FF2F24722C2502C020D10F8713A6 +:101A5000877007074763FD6E282138C099798B028C +:101A600063FE9ADDF063FE9500DA20DB308C11DD39 +:101A70005058155CD2A0D10FC0E163FF7A8B138C54 +:101A800011DD50C0AA2E0A802A2468DA205813BC1F +:101A9000D2A0D10FC020D10F6C1006292102C0D0D6 +:101AA0007597102A32047FA70A8B357FBF052D2535 +:101AB000020DD902090C4C65C18216EBBE1EEBBCAF +:101AC00028629EC0FA78F30260018829E2266890B5 +:101AD000078A2009AA0C65A17A2A629DDFA064A169 +:101AE000772B200C0CBC11A6CC29C286C08C798324 +:101AF0000260015719EBB109B90A2992A36890074E +:101B0000882009880C65814327C2851CEBB364716A +:101B10003A8931098B140CBB016FB11D2C20669FD3 +:101B200010B1CC0C0C472C24666EC6026001400933 +:101B3000FF5065F13A8A102AAC188934C0C47F97E7 +:101B40003C18EBB31BEBB28F359C719B708B209DC7 +:101B50007408BB029B72C08298751BEBAE0F0840E5 +:101B60009B730F881198777FF70B2F2102284A006B +:101B700008FF022F2502C0B4600004000000C0B0BE +:101B80007E97048F362F25227D97048837282521BC +:101B90007C9736C0F1C0900AF9382F3C20090942E1 +:101BA00064908619EB8018EB8128967E00F08800FF +:101BB000A08C00F08800A08C00F08800A08C2A6225 +:101BC0009D2DE4A22AAC182A669D89307797388F1C +:101BD000338A3218EB8A07BE0B2C2104B4BB04CC29 +:101BE0001198E0C08498E1882B9DE59AE69FE71A5A +:101BF000EB82099F4006FF110FCC020A880298E28F +:101C0000C1FC0FCC022CE604C9B82C200C1EEB71D1 +:101C10000CCA11AECC06AA0829A2852DC4CF09B9D9 +:101C20000B29A685CF5CC020D10FC081C0900F8941 +:101C300038C08779880263FF7263FF6600CC57DA89 +:101C400020DB30DC405813C3C020D10FDA205814F9 +:101C50005363FFE8C0A063FE82DA20C0B658144F79 +:101C600063FFD900DB402A2C74580CC9D2A0D10FD5 +:101C70008A102B21045812E11EEB4EC0D02D246691 +:101C800063FEB1006C1006D62019EB491EEB4B2801 +:101C9000610217EB4808084C65805F8A300A6A5178 +:101CA00069A3572B729E6EB83F2A922668A0048CB7 +:101CB000607AC9342A729D2C4CFECAAB2B600CB6DC +:101CC0004F0CBD11A7DD28D2860EBE0A78FB269CDC +:101CD000112EE2A32C160068E0052F62007EF91594 +:101CE00022D285CF2560000D00DA60C0B658142BD3 +:101CF000C85A60010F00DA60581428655106DC40AC +:101D0000DB308D30DA600D6D5158129AD3A064A08B +:101D1000F384A1C05104044763FF6D00C0B02C6080 +:101D2000668931B1CC0C0C472C64666FC602709684 +:101D30000A2B61045812B1C0B02B64666550B42AF6 +:101D40003C10C0E7DC20C0D1C0F002DF380F0F42EA +:101D500064F09019EB1418EB1528967E8D106DDA4F +:101D60000500A08800C08CC0A089301DEB247797A7 +:101D70005388328C108F3302CE0BC02492E1226143 +:101D8000049DE00422118D6B9BE59FE798E61FEB15 +:101D90001A0998400688110822020FDD02C18D9DA4 +:101DA000E208220292E4B4C22E600C1FEB0A0CE897 +:101DB00011A7882C8285AFEE0C220B2BE4CF228654 +:101DC00085D2A0D10F28600CD2A08C1119EB020C87 +:101DD0008D11A988A7DD2ED2852B84CF0ECC0B2C9C +:101DE000D685D10FC0F00ADF387FE80263FF6C634D +:101DF000FF6000002A6C74C0B2DC20DD4058128FF6 +:101E0000C0B063FF63C020D10F0000006C10042C31 +:101E1000221D2A221EC049D320293006243468C03E +:101E2000407AC105DDA060000200C0D06E9738C0C6 +:101E30008F2E0A802B3014C0962934060EBB022E3A +:101E400031022B34147E8004243502DE407AC10E28 +:101E5000C8ABDBD0DA302C0A00580AE52E31020E6E +:101E60000F4CC8FEC020D10F6895F8283102080831 +:101E70004C658FEF1AEAD01CEACE2BA29EC09A7B4B +:101E80009B462BC22668B0048D307BD93B29A29D8E +:101E9000C0E3CB9394901BEAE02D31049B9608DDC0 +:101EA000110EDD029D979D9112EADDC0E524C4A2CA +:101EB0002E34062F310228A29D02FF02288C3028E2 +:101EC000A69D2F3502C020D10FDA30C0B65813B30B +:101ED000C020D10F6C1006292006689805289CF9AF +:101EE00065825D29210209094C659210CD51DB30D4 +:101EF000DA20044C02581317C051D3A0C7AF2A36BA +:101F00000AC0E019EAAD1DEAB31FEAAC8A3A16EA44 +:101F1000A9B1AC64C13528629E6F88026001F129C5 +:101F2000DC332992266890078B2009BB0C65B1E051 +:101F300027629DC08E6471D82B200C0CBC11A6CCDE +:101F400029C2867983026001D219EA9B09B90A295C +:101F500092A3971068900828220009880C6581BB1D +:101F600027C2856471B5292006299CF96491EC2C5F +:101F700020668931B1CC0C0C472C24666EC60260F9 +:101F800001A109F85065819B883689F4088C14AC4E +:101F9000991CEA8B0C99022C2104997019EAA1086A +:101FA00008479971892A09881008990218EA9E0839 +:101FB000990299722830132930120488100699105A +:101FC00008990228302C9A740C881008C8020988D5 +:101FD00002987389379975883898768A39C0819ABA +:101FE000771AEA918935987B99780989140A9902B8 +:101FF000997A8A30893277A73618EA808F33987CAD +:10200000C084987D882B2E76112976122F7613198D +:10201000EA7A0A9F4006FF1104CA110988020FAA32 +:1020200002987EC1F90FAA022A7610C0AA600001A8 +:10203000C0A6ADBF0CBC11A6CC29C2852EF4CF0919 +:10204000A90B29C685655107C020D10F2B200C0C88 +:10205000BC1106CC0828C28609B90A6F8902600142 +:102060002E2992A36890082A220009AA0C65A11FB4 +:102070002AC28564A11928203D08284064808C84E8 +:102080003504841464408485F574537F8436048455 +:1020900014644077745374293013C08C79886CC0F1 +:1020A000902924670908476580ED882089F48435E4 +:1020B0001FEA55048414A4940F440294A014EA5017 +:1020C00008881104880298A1843698A3048414A473 +:1020D000990F990299A219EA4CADB428C2852E44F1 +:1020E000CF288C1028C6852821022F20720988024B +:1020F000B2FF2F2472282502C020D10F00CC57DA5E +:1021000020DB30DC40581293C020D10FC09163FF18 +:102110008FDA20C0B658132163FFE100DA2058138C +:102120001F63FFD88A102B21045811B41DEA2A1FFF +:10213000EA232B200CC0E02E24668A3A63FE480076 +:1021400000DA20DB30DC40DD505813A6D2A0D10FDE +:102150002A2C74DB40580B8ED2A0D10F292138C015 +:102160008879830263FE202A12002C20662B21042A +:102170002CCC010C0C472C24665811A01DEA161F0C +:10218000EA0F2B200CC0E02E24668A3A63FDF8008B +:10219000DA2058130263FF64DA205BFF1CD2A0D15F +:1021A0000F0000006C10089515C061C1B0D9402A1D +:1021B000203DC0400BAA010A64382A2006291606D1 +:1021C00068A8052CACF965C33B1DE9FC6440052FEC +:1021D000120564F29C2621021EE9F806064C65628F +:1021E000E315E9F46440D98A352930039A140A9931 +:1021F0000C6490CC2C200C8B149C110CCC11A5CC15 +:102200009C122CC286B4BB7CB3026002D38F110E29 +:10221000FE0A2EE2A368E0098620D30F0E660C6545 +:1022200062BE88122882856482B6891464905EDA60 +:1022300080D9308C201EE9F21FE9F31DE9E08B14F0 +:102240008DD4D4B07FB718B88A293C10853608C61B +:10225000110E66029681058514A5D50F550295804D +:102260000418146D8927889608CB110888140EBBB2 +:1022700002A8D8299C200F88029BA198A088929B35 +:10228000A3088814A8D80F880298A22AAC1019E9CC +:10229000DEC0C08F141EE9CF86128D11286285AE74 +:1022A000DD08FF0B2CD4CF2821022F66858B352A21 +:1022B0002072098802ABAA2825022A2472C020D1E4 +:1022C0000F29529E18E9BB6F9802600208288226E7 +:1022D00068800829220008990C6591F92A529DC14D +:1022E000CA9A1364A1EF2B200C2620060CB811A566 +:1022F000882D82860EBE0A7DC3026002022EE2A3F2 +:1023000068E0082F22000EFF0C65F1F3288285DEBD +:10231000806481FF9810266CF96461FF2C20668828 +:1023200031B1CC0C0C472C24666EC6026001BC088F +:10233000FD5065D1B617E9BD19E9A21AE9A92C210A +:10234000048B2D2830102F211D0C88100BFB090C3D +:1023500088020A880209BB026441528910C04D9B61 +:1023600090979198928D35D9E064D06CD730DBD0BE +:10237000D8307FD713273C10BCE92632168C39960B +:10238000E69CE78A37B4389AE80B13146430492A7C +:10239000821686799A9696978C778A7D9C982B825E +:1023A000172C7C209A9A2A9C189B99867BB03BB864 +:1023B000896DB9218BC996A52692162AAC18B899B1 +:1023C0009BA196A08BC786CD9BA22B921596A49B12 +:1023D000A386CB2CCC2026A605C0346BD4200D3B85 +:1023E0000C0DD8090E880A7FB705C0909988BC8863 +:1023F000C0900B1A126DAA069988998B288C18C068 +:10240000D01BE98C1CE98B16E981B1FF2A211C2322 +:10241000E6130F0F4F26E6122F251D7FA906C0F0E9 +:10242000C08028251D05F6111AE97A8F202BE615A4 +:102430002CE6162DE61726E6180AFA022AE61429D3 +:102440002006299CF96490FF29200C8D15C0801A64 +:10245000E9610C9C11AA99A5CCDA202BC28528949D +:10246000CF0B4B0B2BC685C0B08C1658118AD2A04F +:10247000D10F8A356FA548D8308BD56DA90C8A86C7 +:102480000A8A14CBA97AB337288C10C08028246715 +:10249000080B4765B112DA20DB302C12065811AD5B +:1024A000D3A0C0C1C0D02DA4039C1563FD268636E1 +:1024B00064610C8910C04D9B909791989263FEA423 +:1024C000C08163FFC78A15CCA7DA20DB308C165891 +:1024D00011A1C020D10FDA20C0B658123063FFE43A +:1024E00000DA208B1158122D63FFD9009E178A1332 +:1024F0002B21045810C28E17C0B02B246663FE3403 +:10250000C08063FE09DA20DB308C16DD505812B52E +:10251000D2A0D10FDA2058122163FFA82D2138C094 +:10252000C87DC30263FE0D8A132B21042C206698FC +:1025300017B1CC0C0C472C24665810B08E17C0D0A5 +:102540002D246663FDEE0000262138B06606064F96 +:10255000262538656EF128206A7F870508294164A1 +:1025600090A5C0D01BE92619E93426200723E61BD5 +:10257000B16609FA022BE61A28200A2DE61D2AE682 +:102580001E09880228E61C882606064728E6202B16 +:10259000220826E53E2BE6212D24072C20062A20A2 +:1025A0006468C347B44463FE9EDB30DA208D15C0F7 +:1025B000CE2E0A802C24688C165810F1D2A0D10F90 +:1025C0008E102A321616E8FD0A2A1486662BE612A9 +:1025D00097E127E61328E614AA6609660296E02E1C +:1025E000EC4869ED50C14663FD7A000064AFB41950 +:1025F000E8F328201689920A880C00910400881AB2 +:10260000A8B8982963FF9C002B21046EB81E2C20CB +:1026100066B8CC0C0C472C2466C9C09E178A135888 +:1026200010778E17C0348F20C0D02D2466C0682646 +:10263000240663FF2C008D35C08064D04AD9E0DCCD +:1026400030DBE0DF301AE8FDB188B4FF17E8FD8623 +:10265000C9249DFF8DC82CCC102D46300767012D55 +:1026600046320A66011DE8F7264631AD6D2D463328 +:1026700026F21597B796B684C3BCBB94B58D3529A1 +:102680009C107D83C22F211DC14663FD4B000000BD +:102690006C1006292006289CF86582BF2921022B90 +:1026A000200C09094C6590E116E8C30CBA11A6AAE2 +:1026B0002DA2862C0A127DC30260028C19E8BF0984 +:1026C000B90A2992A36890078C2009CC0C65C278BE +:1026D00029A2856492722D629E1AE8B56FD80260B5 +:1026E000026E2AA22629160168A0082B22000ABB26 +:1026F0000C65B25C29629DC18C6492542A21200A27 +:10270000806099102C203CC7EF000F3E010B3EB1BA +:10271000BD0FDB390BBB098F260DBD112DDC1C0D48 +:102720000D410EDD038E27B1DD0D0D410FEE0C0DB9 +:10273000BB0B2BBC1C0BB7027EC71C2C21257BCBF3 +:10274000162D1AFC0CBA0C0DA16000093E01073EC3 +:10275000B1780987390B770A77EB0260020A2C21DE +:1027600023282121B1CC0C0C4F2C25237C8B29B0A4 +:10277000CD2D2523C855DA20DB3058106F292102D2 +:10278000CC96C0E80E9E022E2502CC57DA20DB3014 +:10279000DC405810F0C020D10F2C20668931B1CC1C +:1027A0000C0C472C24666EC6026001D309FD5065EF +:1027B000D1CD2F0A012E301129221464E0112822D4 +:1027C0001B090C4400C10400FA1A0A880228261BBF +:1027D0002E3010C0A0C0B0941295131CE878883039 +:1027E0002CC022088D14778704C0F10CFA38C04140 +:1027F000C0F225203CC0840858010F5F010F4B3800 +:1028000005354007BB10C0F0084F3808FF100FBB5C +:102810000228ECFEC0F0084F38842B0BA8100AFFEA +:10282000102A21200F88020B880208440218E8862B +:102830008F110844022821250A2A14082814048824 +:10284000110A88022A210494F08B2004E41008BBAA +:102850001104BB02C04A04BB029BF1842A08AB11DD +:102860000BEB0294F40A54110B44020555100D1B96 +:102870004094F707BB100B5502085502C08195F62E +:102880008433C05094F3B1948B3295F898F99BF24D +:10289000C080C1BC24261499FA9BF598FB85389515 +:1028A000FC843A94FD8B3B9BFE883998FF85352547 +:1028B000F6108436851324F6118B3784122BF6120A +:1028C000C0B064C07E89307797438D3288332E3014 +:1028D000108F111CE84A0999400699112CF614C072 +:1028E000C42CF6158C2B2DF61A28F61B2BF6190482 +:1028F000A81109880208EE0219E840C18008EE021A +:1029000009C90229F6162EF618C09E600001C09A69 +:102910002F200C18E8300CFE11A8FFA6EE2DE28542 +:102920002BF4CF0D9D0B2DE685C87F8A268929A71C +:10293000AA9A260A990C090948292525655050C0EC +:1029400020D10F00C09A63FFC6DA2058111463FE2D +:1029500038DA20C0B658111163FE2E0068973C2B60 +:102960009CFD64BE24C020D10FDA20DB705810CD4E +:10297000C0C0C0D10ADA390ADC3865CDE063FE098F +:102980008A102B2104580F9DC0B02B246663FE21B2 +:10299000DB402A2C7458097ED2A0D10FDA20580FC0 +:1029A000A263FCF76C1004C020D10F006C10042946 +:1029B0000A801EE8261FE8261CE7FF0C2B11ACBB83 +:1029C0002C2CFC2DB2850FCC029ED19CD0C051C0C6 +:1029D0007013E82214E82118E81F2AB285A82804F9 +:1029E000240A234691A986B8AA2AB685A9882784ED +:1029F0009F25649FD10F00006C100AD6302830103C +:102A0000292006288CF964829B68980B2A9CF9651A +:102A1000A1B2022A02580F8489371BE7E8C89164E3 +:102A2000520E2A21020A0C4C65C2588D3019E7E17A +:102A300074D7052E212365E29E2F929E1AE7DD6F43 +:102A4000F8026002532AA22668A0082C22000ACCB1 +:102A50000C65C2442A929D64A23E9A151FE7D78D49 +:102A600067C1E6C8DD2B620618E7D564B00528808B +:102A7000217B8B432B200C18E7CF0CBC11A8CC2951 +:102A8000C28679EB460FBE0A2EE2A368E0052F222C +:102A9000007EF9372CC2859C1864C2332B212F8706 +:102AA000660B7B360B790C6F9D266ED2462C203D33 +:102AB0007BC740CE5560001E2A200CC1B28C205826 +:102AC00010F79A1864A2458D6763FFCFC0C063FFFB +:102AD000C5D7B063FFD300C0E06000022E60030ED4 +:102AE000DB0C6EB20EDC700CEA11AA6A2AAC20581C +:102AF0000199D7A0DA20DB70C1C82D212058109190 +:102B00008C268B279A160CBB0C7AB3348F188963EA +:102B100099F3886298F28E659EF82D60108A189D50 +:102B20001768D729C0D09DA92C22182B22139CAB43 +:102B30009BAA97A58E667E7302600097CF586000AF +:102B40001FDA208B1658105765A13863FFBDC0816E +:102B5000C0908F18C0A29AF999FB98FA97F563FF75 +:102B6000D2DB30DA20DC40580FFBC051D6A0C0C009 +:102B70002BA0102CA4039B172C1208022A02066B10 +:102B800002DF702D60038E179D149E100CDD11C0A6 +:102B9000E0AD6D2DDC205801188C148B16ACAC2CDC +:102BA00064038A268929ABAA0A990C9A26886609A1 +:102BB000094829252507880C98662F2218A7FF2F7A +:102BC000261863FE96DA20DB30DC40DD5058110514 +:102BD000D2A0D10FC0302C20668961B1CC0C0C473B +:102BE0002C24666EC6026000D2C03009FD5065D04C +:102BF000CA8E6764E069647066DB608C18DF70DA27 +:102C0000202D60038E170CDD119E10AD6D2DDC2084 +:102C10001EE78D5800F9232618DA208B16DC402F8A +:102C20002213DD50B1FF2F2613580F9AD2A0D10FD7 +:102C30000028203D084840658DE76F953EDA308DCD +:102C4000B56D990C8CA80C8C14CACF7CD32D2AACF2 +:102C500010C090292467090D4764DDC5600092000B +:102C60002C1208066B022D6C20077F028E17DA20CB +:102C70009E101EE77458007D63FF9A00C09163FFA9 +:102C8000D1000000655081DA20DB60DC40580FB1D4 +:102C9000C020C0F02FA403D10FDA20C0B658103FD7 +:102CA00063FFE000006F950263FD6CDA20DB30DC2F +:102CB00040DD50C4E0580F32D2A0D10F8A152B212D +:102CC00004580ECE232466286010981763FF210055 +:102CD000DA2058103263FFABC858DB30DA20580FC7 +:102CE000162A210265AF9CC09409A9022925026316 +:102CF000FF91DB30DC40DD50C0A32E0A802A24681F +:102D0000DA20580F1FD2A0D10FC020D10FDA202B0C +:102D1000200C58104763FF6B6C1004282006C0621B +:102D2000288CF8658125C050C7DF2B221BC0E12A03 +:102D3000206B29212300A104B099292523B1AA00E1 +:102D4000EC1A0BC4010A0A442A246B04E4390DCCA2 +:102D5000030CBB012B261B64406929200C1BE715C3 +:102D60000C9A110BAA082FA2861BE7136FF90260B9 +:102D700000B60B9B0A2BB2A368B0082C22000BCC28 +:102D80000C65C0A42BA2851DE73664B09B8C2B2458 +:102D900021040DCC029CB08820C0C50888110C8885 +:102DA0000298B1882A08441198B48F3494B79FB51B +:102DB000C0401EE7082DA2850E9E0825E4CF2DDC1D +:102DC000282DA68529210209094C68941A689820A3 +:102DD000C9402A210265A00B2A221E2B221D7AB18E +:102DE0000265A079C020D10F2C212365CFDE6000C1 +:102DF000082E21212D21237EDBD52B221E2F221DE3 +:102E00002525027BF901C0B064BFC413E6E92CB0EC +:102E10000728B000DA2003880A28824CC0D10B8032 +:102E200000DBA065AFE763FFA62A2C74C0B02C0AB4 +:102E300002580E081CE70C9CA08B2008BB1106BB97 +:102E4000029BA1893499A263FF790000262468DAE5 +:102E500020DB30DC40DD50581063D2A0D10FDA20E7 +:102E60002B200C580FCEC020D10F00006C1006078D +:102E70003D14C080DC30DB40DA20C047C02123BCD9 +:102E800030032838080842774001B1DD64815A1EBA +:102E9000E6C519E6C629E67ED30F6DDA050050882F +:102EA00000308CC0E0C02025A03C14E6C4B6D38F0F +:102EB000C0C0D00F87142440220F8940941077F7A8 +:102EC00004C081048238C0F10B2810C044C0220421 +:102ED000540104FD3802520102FE3808DD10821C44 +:102EE00007EE100E6E020EDD02242CFEC0E004FE82 +:102EF000380AEE100E88020D88028DAB1EE6B4086B +:102F0000D8020E880298B0C0E80428100E5E018432 +:102F1000A025A125084411084402052514045511D3 +:102F2000043402C0810E8E3994B18FAA84109FB4EC +:102F300075660C26A11FC0F2062614600009000069 +:102F400026A120C0F20626140565020F7701078727 +:102F50003905E61007781008660206550295B62571 +:102F6000A1040AE61108581108280208660296B75B +:102F7000C060644056649053067E11C0F489C288D4 +:102F8000C30B340B96459847994618E69B9F41041E +:102F900059110E99021FE699020E4708D80298426D +:102FA0000E99029F40C1E00E990299442FA00CB4E3 +:102FB000380CF91114E6881EE67FA4FFAE992E9214 +:102FC0008526F4CF0E880B289685D10F2BA00C1FD9 +:102FD000E6791CE6800CBE11ACBBAFEE2DE2852677 +:102FE000B4CF0D3D0B2DE685D10FC0800528387874 +:102FF000480263FEA263FE966C1006C0C06570F1C5 +:103000008830C030088714778712C0B0C0A619E690 +:103010006B299022C030CC97C031600003C0B0C093 +:10302000A6C0E0C091C0D4C08225203C0B3F1097C1 +:1030300012831CC0700858010D5D01089738C080CC +:103040000B9838077710048810086802087702C0C8 +:10305000800D98382D3CFE0888100D9E388D2B0A67 +:10306000EE1008EE0207EE020CB8100FDD02053B71 +:10307000400EDD029D408920043D100899110D99F4 +:10308000022D210409A90208DD119941872A05B9F9 +:10309000100D3D020ABB110DBB02087702974428B0 +:1030A00021258712082814048811071E4007EE10F6 +:1030B0000E990275660926211F0626146000060077 +:1030C0002621200626140868029B47098802984694 +:1030D00029200CD2C0C0800C9E111BE63E1FE63595 +:1030E000AB99AFEE2DE2852894CF0DAD0B2DE68583 +:1030F000D10FDD40C0A6C0B08E51CAE0B2AAB1BBAC +:103100002DDC108F500E7836981008770C9FD898C9 +:10311000D989538F52991199DB9FDA7E8309B1CCFB +:10312000255C10C97763FFCF88108D1108E70C97D5 +:1031300051AD8DD7F078DB01B1F79D5397528830B0 +:10314000C030088714088840648ED565BEC963FE08 +:10315000BC0000006C1004D720B03A8820C0308238 +:1031600021CAA0742B1E2972046D080FC980C99151 +:103170008575B133A2527A3B0B742B0863FFE900CB +:10318000649FECD10FD240D10F0000006C100AD622 +:10319000302E3027D950DA4015E6092430269A150A +:1031A00029160464E0026493732920062A9CF865BA +:1031B000A3CE2A2102270A040A0B4C65B3978C3050 +:1031C00074C7052D212365D4A0C0A62B0A032C2289 +:1031D00000580F0B64A3B917E5F78E389A1664E30D +:1031E000BA2F6027285021C9F37E8311C2B08C20EA +:1031F0002A200C580F2AD7A0CDA16004A200C2B08B +:103200008C202A200C580EFED7A064A4862F212ED5 +:103210008B680FBF360FB90C6F9D54296027D5B04E +:103220006E920528203D7B8F4CDA20DB50C1C42DE7 +:10323000211F580EC48B269A189A1989272AAC3850 +:103240000B990C7A93538963C08099738F62987835 +:103250009F728E659E798D679D7B8C6695759C7A35 +:103260008E687E53026000B18B1465B050600038E8 +:10327000DBF063FFA5008A14C9A92E60030E9B0C26 +:103280006EB2A5DC500CEA11AA6A2AAC285BFFB129 +:10329000D5A063FF93C0E063FFE2DA208B18580EDD +:1032A0008165A2B163FF9E0000DA20DB308C1558E7 +:1032B0000E29D6A0C0C0C0D12D16042CA403DC70EA +:1032C000DA20DB60DF502D6003C0E09E109D171EEA +:1032D000E5D20CDD110D6D082DDC285BFF478E66F5 +:1032E0008F678817AF5FA8A828640375FB01B1EE4C +:1032F0008A189E669F6789268829AA9909880C9949 +:10330000268E6808084805EE0C28252515E5AC9E94 +:103310006865EECC63FEE6000000C9432F21232B35 +:1033200021212FFC010F0F4F2F25237FBB026003AC +:10333000142C20668961B1CC0C0C472C24666EC617 +:103340000260022809FD5065D22264E1B62E602792 +:1033500064E1B0DC70DF50DA20DB601EE5C32D6075 +:1033600003C08098100CDD11AD6D2DDC285BFF22B1 +:10337000644181C0442B0A008C202A200C580EA0E6 +:103380000AA70265A00FC0B02C22002A200C580EFC +:103390009CD7A064AFEFDA20C1BCC1C82D21208F1B +:1033A000188E268929AFEE9E260E990C0909482908 +:1033B0002525580E64C090C050C0C288609A191E5E +:1033C000E57FC0A12EE022088F14778704C0810E0C +:1033D0008938C0800B93102D203C2921200CDC0162 +:1033E00004DB010929140BA8380CA5380D3D401C3D +:1033F000E5968B2B088810075510085502053302F7 +:103400002821250F154003BB020CBB0207551005F0 +:10341000D3100828140ADD11048811098802053325 +:10342000022921040833029B70C0808A201BE58F8B +:1034300008AA110BAA029A71C0A1852A93769574E5 +:1034400008931103DD020ADD029D778C63C1DC9CC9 +:10345000738B6298789A799B72232214C0C0B1351D +:103460002526149C7B9D75937A2B621A9B7C2A627D +:103470001C9A7D28621D987E25621B957F2362170A +:103480002376102D62182D76112C62192C76126479 +:10349000E0B98E6077E73DC0FE13E5571DE558C1E2 +:1034A000818A628B630495110E9C4006CC110C55E9 +:1034B00002247615085502C0802D76148D2B2B76AC +:1034C0001B2A761A28761925761803DD022D761622 +:1034D0006000030000C0FA2E200C19E53E18E53507 +:1034E000A9E90CEE11A8EEC0802DE2852894CF0D3D +:1034F000FD0B2DE685DA208B198C158D14580D6582 +:10350000D2A0D10FDC70DF50DB602D6C28C0A01E74 +:10351000E5569A10DA205BFE5563FE53002B203DE2 +:103520000B4B4065BC826FE527DA308F556DE90C97 +:103530008EAA0E8E14C9E87EF3162AAC10C090290C +:103540002467090F4764FC6060015F00C0FA63FFF5 +:1035500085C09163FFE88814658168DA20DB608CA0 +:1035600015580D7CC020C09029A403D10F8A162BBA +:103570002104580CA2C0A02A24668E6863FDCA00EC +:10358000002B9CF965B0FDDA20580CA763FC2200E3 +:1035900000DA20C0B6580E0163FFBA002B200C0CD5 +:1035A000BE11A7EE2DE286C1C27DC30260011819CB +:1035B000E50209B90A2992A36890082A220009AAFB +:1035C0000C65A10326E2856460FD2C20668931B17B +:1035D000CC0C0C472C24666FC60270960C8A162BF6 +:1035E0002104580C86C0D02D24668E3077E74D1C00 +:1035F000E5021BE5028F328833C0A42D21040E9909 +:103600004006991104DD1109DD029A61C19009DDBE +:10361000029B60C0908B2B9D649F66986799650C98 +:10362000BB029B6228200C1AE4EBAA8A0C8811A723 +:10363000882F828529A4CF2FFC202F86858A1465A8 +:10364000A0A6C020D10FB0FC8B142C2523C8B70234 +:103650002A02066B02580CB82A210265AEF7C0D8C0 +:103660000DAD022D250263FEEC008E14C8E8DA20B1 +:10367000DB30580CB12A210265AEDA07AF022F25E4 +:103680000263FED100DA20DB308C158D14580E5504 +:10369000D2A0D10FDA202B200C580DC063FEB6004B +:1036A000DA202B200C580DE263FEAADA20DB308CE6 +:1036B000152D12042E0A80280A00282468580CB000 +:1036C00063FAE500C020D10FDA20580DB48914CD7B +:1036D00092DA20DB308C15580D1FDBA0C020C0A073 +:1036E0002AB403D10FC020D10F2A2C748B15580691 +:1036F00028D2A0D10F0000006C100C2821029410D9 +:1037000008084C6583621FE4AB29F29E6F98026043 +:1037100003661DE4A729D2266890082A220009AA78 +:103720000C65A3542CF29D64C34E2B200C0CB611D7 +:10373000AF66286286C1EC78E30260034619E49E16 +:1037400009B90A2992A36890078A2009AA0C65A3DF +:103750003224628564432CC0E12A3109C0702724D9 +:103760006689359A11992A88369912982B89379843 +:1037700013992C883899140858149815982D89395C +:103780002A25042E251D29251C283028C0922824EE +:103790003C2A302908084798160989012A243D2A1D +:1037A000311599170A094109A90C299CEC29251FF3 +:1037B0007E87192D2A000DA06000083E010A3EB147 +:1037C000AD08DA390EAA110A990C29251F2A211FE2 +:1037D00018E4A80A8160C1D0941A951B01083E0024 +:1037E000053EB184054839843C259CFC0D8836296A +:1037F000201408AA1C8D3D2726182E26132E2614C9 +:103800002E261527261B2E246B27246727246808BD +:10381000581C0909432924142932112A252E282548 +:103820002F27252427252527252C27252325252037 +:103830002425212D2522841A2D211C851B6FD202BF +:10384000600209C0A099186D080AB1AA00A104007D +:10385000E91A7D9B0263FFEE8918C080C0E1C07049 +:10386000C0D29B1D951B961C9C1E16E4722C203DFD +:1038700015E4820C0B400DCC010BE7381DE4640A03 +:1038800077100CE8380B8810C0C49C410877029D63 +:1038900040B0A80988118B209C499D48954B9643C0 +:1038A000087702861418E47315E45A08770205BBFA +:1038B000029B4A9B4297468812871108DA149A4E57 +:1038C0000D88100D77110877021AE44E06D8140DF2 +:1038D0006610087702974FC78F984D984C98458788 +:1038E0001598440715140D55110A5502954715E40E +:1038F000638A262D46102D46182D46202C46112C65 +:1039000046192C46212B46122B461A2846142846C7 +:10391000152B462288162546242546268B170A0C89 +:1039200048090D4885130EDD1105CC110839400BEF +:10393000EB390299101EE4520DCC020D5511082DE1 +:10394000400655022E461316E41D0FDD11254616BE +:10395000080840851B0188100DBB0286671DE449DD +:103960000988020CBB0219E4191CE4472B46172DE9 +:10397000461BA7661BE446C0702C461C0988028CB7 +:103980001E28461E2B4623C0908B1D29461D294606 +:103990001F18E43F2946272846252931162E2006E0 +:1039A00029246A243117962D242538861CCCE1273A +:1039B0002407C0D7090E4064E0829A29092841648F +:1039C000809164409B2D2406C098094936280AA09E +:1039D00024628501C404A84428210424668508883B +:1039E000118E3F8A3E2D32100EA41800C4040EAE74 +:1039F0001800EE110ACA530EDD02C0E30E880298C9 +:103A0000C11EE42409084E9EC08E2094C398C59D13 +:103A1000C418E3F01DE42105EE110EAA020DAA025E +:103A2000A8B82784CF9AC21EE3E224F29D27E4A21D +:103A3000244C1824F69D655052C020D10F2D240629 +:103A4000C0A0C09809493604A93863FF7FC0A063AD +:103A5000FE070000654F6DC098C0A82A240663FFCA +:103A60006B2D2406C09063FF63CC57DA20DB308CCB +:103A700010580C38C020D10F00DA20C0B6580CC73F +:103A800063FFE500DA20580CC563FFDC2A2C748B39 +:103A90001058053FD2A0D10F6C10062820068A339B +:103AA0006F8202600161C05013E3C229210216E354 +:103AB000C1699204252502D9502C20159A2814E3B7 +:103AC000BF8F2627200B0AFE0C0477092B711C647C +:103AD000E1398E428D436FBC0260016F00E104B09A +:103AE000C800881A08A80808D80298272B2006685A +:103AF000B32ECE972B221E2C221D0111027BC90151 +:103B0000C0B064B0172CB00728B000DA2003880AD0 +:103B100028824CC0D10B8000DBA065AFE7C020D16C +:103B20000F2D206464DFCA8B29C0F10BAB0C66BF7C +:103B3000C02B200C0CBC11A6CC28C2862E0A0878FB +:103B4000EB611EE39D0EBE0A2EE2A368E00528226B +:103B5000007E894F29C2851EE3A96490461FE3B603 +:103B60009E90C084989128200A95930F880298927D +:103B70008E200FEE029E942F200788262F950A98FC +:103B8000969A972E200625240768E3432921022AC6 +:103B9000C2851DE3902AAC20ADBD25D4CF2AC685B1 +:103BA00063FF4E002E2065CBEDC082282465C9F648 +:103BB00005E4310002002A62821BE3982941020BCE +:103BC000AA022A668209E43129210263FF23000048 +:103BD00064DFB88F422E201600F1040DEE0C00EECB +:103BE0001AAEAE9E2963FFA38A202B3221B1AA9A76 +:103BF000B0293221283223B4992936217989A92B79 +:103C000032222B362163FFA0C020D10F9F2725240D +:103C100015ACB828751C2B2006C0C12EBCFE64E074 +:103C2000AB68B7772DBCFD65DEC72D2064C0F0649E +:103C3000D0868E290EAE0C66E089C0F128205A2865 +:103C40008CFE08CF3865FEE863FF580000E004935F +:103C500010C0810AF30C038339C78F08D80308A862 +:103C60000108F80C080819A83303C80CA8B828756F +:103C70001C030B472B24158310CBB700E104B0BC09 +:103C800000CC1AACAC0CDC029C27659E5EC0B20B6B +:103C9000990209094F29250263FE50002D206A0D63 +:103CA0002D4165DF7EDA20C0B0580C8F64AF18C09C +:103CB000F163FEEF9F2763FFD02E221F65EE326374 +:103CC000FF79000028221F658E2763FF6E252406DA +:103CD00029210263FE1B00006C10066571332B4C1A +:103CE00018C0C7293C18C0A1C08009A838080842DC +:103CF0006481101CE32C1AE32D2AC67E2A5CFDD3B6 +:103D00000F6DAA0500B08800908C8940C0A009887A +:103D1000471FE355080B47094C50090D5304DD10AC +:103D2000B4CC04CC100D5D029D310CBB029B3088DD +:103D3000438E2098350FEE029E328D26D850A6DD98 +:103D40009D268E40C0900E5E5064E0971CE33B1EA3 +:103D5000E32B038B0BC0F49FB19EB02D200A99B3C7 +:103D60000CDD029DB28F200CFF029FB48E262D2009 +:103D7000079EB68C282DB50A9CB72924072F20064C +:103D80002B206469F339CBB61DE30D2320168DD2A9 +:103D90000B330C00D10400331AB48DA3C393292232 +:103DA000200C13E30C1FE3030C2E11AFEEA322290A +:103DB00024CF2FE285D2A00FDD0B2DE685D10F0099 +:103DC0002E200CB48C0CEB111FE3031DE2FAAFEEB6 +:103DD000ADBB22B28529E4CF02C20B22B685D2A0A8 +:103DE000D10F00002E200C1CE2F31FE2FA0CEB11A5 +:103DF000AFEEACBB22B28529E4CF02820B22B6859E +:103E0000D2A0D10FC0D00BAD387DC80263FEEC63E9 +:103E1000FEE08E40272C747BEE12DA70C0B32C3C8F +:103E200018DD50580A868940C08063FEE3066E02A2 +:103E3000022A02DB30DC40DD505800049A10DB50CF +:103E4000DA70580453881063FEF700006C10069275 +:103E5000121EE2E48C40AE2D0C8C472E3C1804CA96 +:103E60000BD9A07DA30229ADF875C302600084C000 +:103E7000B0C023C0A09D106D0844B89F0EB80A8D35 +:103E8000900EB70BB8770D6D36ADAA9D800D660C00 +:103E9000D8F000808800708C879068B124B22277B7 +:103EA000D3278891C0D0CB879890279C100070882A +:103EB00000F08C9D91CB6FC08108BB0375CB36633E +:103EC000FFB4B1222EEC1863FFD485920D770C86D7 +:103ED000939790A6D67D6B01B1559693959260000D +:103EE00016B3CC2D9C188810D9D078D3C729DDF80B +:103EF00063FFC100C0238A421BE2E900CD322D449A +:103F0000029B3092318942854379A1051EE2E50E7C +:103F1000550187121BE2D5897095350B99029932AC +:103F200088420A880C98428676A6A696768F44AF79 +:103F3000AF9F44D10F0000006C10089311D6308859 +:103F400030C0910863510808470598389812282115 +:103F500002293CFD08084C6581656591628A630A07 +:103F60002B5065B18B0A6F142E0AFF7CA60A2C20F9 +:103F70005ACCC42D0A022D245A7FE0026002158912 +:103F80002888261FE2C809880C65820F2E200B0F97 +:103F9000EE0B2DE0FE2EE0FF08DD110EDD021EE22D +:103FA000C2AEDD1EE2C21CE2C20EDD010DCC37C185 +:103FB00080084837B88DB488981089601AE2807BF1 +:103FC00096218B622AA0219C147BA3179D132A2083 +:103FD0000C8B108C20580BB18C148D13DBA0CEAC45 +:103FE0006001C4002E200C1BE2730CEA110BAA081E +:103FF0002BA2861FE2717BDB3B0FEF0A2FF2A36837 +:10400000F0052822007F892C2BA28564B0AA876244 +:104010008826DE700C7936097A0C6FAD1C8F279BD1 +:104020001508FF0C77F3197E7B729D139C149B156A +:10403000CF56600025C0B063FFD0D79063FFDD008E +:10404000009D139C14DA20DB70580B168B158C1412 +:104050008D1365A06A8E6263FFCC00DA208B11DCC1 +:1040600040580ABCD6A08B15C051DE70DA20DC6047 +:10407000DD405BFF768D138C14D9A02E200C1BE243 +:104080004D1FE2540CEA11AFEFC0E0ABAA2BA285A2 +:104090002EF4CF0B990B29A68563FF1D00DA20DCD7 +:1040A00060DD40DE708912282007DF50A9882824AF +:1040B000075BFF09D2A0D10F00DBE0DA20580B37F5 +:1040C0006550EF2A20140A3A4065A0EBDB60DC4023 +:1040D000DD30022A025809A7D6A064A0D584A183A6 +:1040E000A00404470305479512036351C05163FEC2 +:1040F0005C2C2006D30F28CCFD6480A568C704C0C3 +:10410000932924062C2006C0B18D641FE22C9D2724 +:104110009D289D298FF29D2600F10400BB1A00F016 +:1041200004B0BE0EDD01C0F0ADBB8D652F24070DC0 +:104130000E5E01EE11AEBB2E0AFEB0BB0B0B190ECC +:10414000BB36C0E20B0B470EBB372B241618E224FC +:104150000A09450D0B422B240B29240AB4BE2E2438 +:104160000C7D88572920162FCCFDB09D0A5C520D7E +:10417000CC362C246465FDEC0C0C4764CDE618E2CB +:104180000F8E2888820C9F0C00810400FF1AAFEE6E +:104190009E2963FDCF1CE23E63FE13001CE23563E3 +:1041A000FE0C8D6563FFA500DA202B200C580B2038 +:1041B000645F0FC020D10F00C020D10FC09329240D +:1041C00016C09363FFA000006C1004C06017E1F8F4 +:1041D0001DE1FBC3812931012A300829240A78A175 +:1041E00008C3B27BA172D260D10FC0C16550512605 +:1041F00025022AD0202F200B290AFB2B20142E2049 +:104200001526241509BB010DFF0928F11C2B2414C8 +:10421000A8EE2EF51C64A0A92B221E28221D011138 +:10422000027B8901DB6064B0172CB00728B000DA8C +:104230002007880A28824CC0D10B8000DBA065AF24 +:10424000E7DB30DC40DD50DA205800DE29210209AE +:104250000B4CCAB2D2A0D10F00CC5A2C30087BC173 +:10426000372ED02064E02D022A02033B02DC40DD21 +:10427000505800D4D2A0D10F2B2014B0BB2B241443 +:104280000B0F4164F0797CB7CAC0C10C9C022C258D +:1042900002D2A0D10FC020D10F2E200669E2C12684 +:1042A00024062B221E2F221D29200B2820150D99B4 +:1042B000092A911C262415AA8828951C7BF149609F +:1042C0000048B0BB2B24140B0A4164A0627CB702E7 +:1042D0002C25022B221E2C221DD30F7BC901C0B01E +:1042E000C9B62CB00728B000DA2007880A28824C0B +:1042F000C0D10B8000DBA065AFE7C020D10F00006C +:10430000262406D2A0D10F0000DB601DE1AC64BF03 +:104310004F2CB00728B000DA2007880A28824CC04A +:10432000D10B8000DBA065AFE71DE1A463FF310086 +:1043300026240663FF9C00006C1004282006260A31 +:10434000046F856364502A2920147D9724022A0271 +:10435000DB30DC40DD50580019292102090A4CC825 +:10436000A2C020D10FC0B10B9B022B2502C020D1CF +:104370000F00022A02033B022C0A015800D1C9AAED +:10438000DA20DB30DC405809F329A011D3A07E9756 +:10439000082C0AFD0C9C012CA411C0512D201406E0 +:1043A000DD022D241463FFA4DA20DB30DC40DD5075 +:1043B000C0E0580973D2A0D10F0000006C1006169F +:1043C000E17D1CE17D655157C0E117E179282102AB +:1043D0002D220008084C6580932B32000B6951296F +:1043E0009CFD6590872A629E6EA84C2A722668A062 +:1043F000027AD9432A629DCBAD7CBE502B200C0C97 +:10440000BD11A6DD28D2862F4C0478FB160CBF0AFE +:104410002FF2A368F0052822007F89072DD285D3CB +:104420000F65D0742A210419E1A3D30F7A9B2EDAE9 +:104430002058086E600035002D21041BE19E7DBBD5 +:1044400024DA20C0B6580869CA546001030B2B5007 +:104450002B240BB4BB0B0B472B240C63FFA0DA20DF +:10446000580A4E600006DA20C0B6580A4C6550E083 +:10447000DC40DB302D3200022A020D6D515808BDA0 +:104480001CE14ED3A064A0C8C05184A18EA0040436 +:10449000470E0E4763FF3500002B2104C08C893185 +:1044A000C070DF7009F950098F386EB8172C20667C +:1044B000AECC0C0C472C24667CFB099D105808CF11 +:1044C0008D1027246694D11EE151B8DC9ED0655032 +:1044D00056C0D7B83AC0B1C0F00CBF380F0F42CBAE +:1044E000F119E13018E13228967EB04BD30F6DBA46 +:1044F0000500A08800C08C2C200CC0201DE1360CCB +:10450000CF11A6FF2EF285ADCC27C4CF0E4E0B2EB9 +:10451000F685D10FC0800AB83878D0CD63FFC100CE +:104520008E300E0E4763FEA12A2C742B0A01044D17 +:10453000025808C22F200C12E1270CF911A699A2EB +:10454000FF27F4CF289285D2A008480B289685D162 +:104550000FC020D10F0000006C1004C060CB55DBF1 +:1045600030DC40055D02022A025BFF94292102092A +:10457000084CC882D2A0D10F2B2014B0BB2B24141E +:104580000B0C41CBC57DB7EBC0C10C9C022C2502A6 +:10459000D2A0D10F0000022A02033B02066C02C027 +:1045A000D0C7F72E201428310126250228240A0F0F +:1045B000EE012E241458010E63FFA300262406D218 +:1045C000A0D10F006C1006282102D62008084C65E7 +:1045D000809D2B200C12E0F70CB811A2882A82864D +:1045E000B5497A930260009719E0F409B90A299253 +:1045F000A36890082A620009AA0C65A08228828517 +:104600001CE0FF6480799C80B887B14B9B819B1034 +:10461000655074C0A7D970280A01C0D0078D380D25 +:104620000D42CBDE1FE0E01EE0E12EF67ED830D357 +:104630000F6D4A0500808800908C2E3008C0A000C5 +:10464000EE322E740028600C19E0E30C8D11A2DD0F +:10465000A988C0202CD2852284CFD2A00CBC0B2CE0 +:10466000D685D10FC0F0038F387FA0C063FFB400A0 +:10467000CC582A6C74DB30DC405807F6C020D10FD0 +:10468000DA605809C663FFE7DD402A6C74C0B0DC0D +:104690007058086A2E30088B1000EE322E740028F5 +:1046A000600C19E0CC0C8D11A2DDA988C0202CD2A1 +:1046B000852284CFD2A00CBC0B2CD685D10F000054 +:1046C0006C1004292014282006B19929241468812B +:1046D00024C0AF2C0A012B21022C24067BA004C08D +:1046E000D02D2502022A02033B02044C02C0D058FE +:1046F00000C0D2A0D10FC020D10F00006C1004293F +:104700003101C2B429240A2A3011C28378A16C7BFA +:10471000A1696450472C2006C0686FC562CA572D36 +:1047200020147CD722DA20DB30DC40DD505BFFA593 +:10473000292102090E4CC8E2C020D10FC0F10F9F01 +:10474000022F2502C020D10FDA20DB30C0C05BFF72 +:10475000DC28201406880228241463FFC7292015AA +:104760001BE0972A200BC0C09C240BAA092BA11C7C +:104770002C2415AB9929A51C63FF9900C020D10FEB +:10478000DA20DB30DC40DD50C0E058087DD2A0D11B +:104790000F0000006C1004CB5513E09225221F0D72 +:1047A000461106550CA32326221E25261F06440B60 +:1047B00024261E734B1DC852D240D10F280A80C038 +:1047C0004024261FA82828261E28261DD240D10FA7 +:1047D000C020D10F244DF824261E63FFD80000000E +:1047E0006C1004D620282006C0706E85026000D4AC +:1047F0001DE07919E07112E06F2A8CFC64A1302B66 +:104800006102B44C0B0B4C65B0A22B600C8A600C9F +:10481000B8110288082E828609B90A7EC302600098 +:104820009A2992A368900509AA0C65A08E28828512 +:10483000648088B8891BE07594819B80655155C060 +:10484000B7B8382A0A01C0C009AC380C0C4264C0A1 +:10485000421FE0541EE0562EF67EB04AD30F6DAADA +:104860000500808800908CC0A029600C0C9C11A2CF +:10487000CC2BC285AD990B4B0B2BC6852860062728 +:1048800094CF6881222D6015D2A0C9D2C0E22E64D7 +:1048900006D10F00C0F008AF387FB0BD63FFB10094 +:1048A000276406D2A0D10F00D2A0D10F00CC57DAD6 +:1048B00060DB30DC405808A7C020D10FDA6058090F +:1048C0003763FFE80028221E29221DD30F789901A3 +:1048D000C080C1D6C1C11BE043C122AB6B64804222 +:1048E00078913F2A80000CAE0C64E0BB02AF0C64F0 +:1048F000F0B52EACEC64E0AF0DAF0C64F0A92EACBB +:10490000E864E0A32FACE764F09D2EACE664E0978A +:104910002F800708F80BDA807B83022A8DF8D8A055 +:1049200065AFBC28612308D739D97060007B0000CF +:104930002B600C0CB811A2882C82862A0A087CAB4A +:104940007E09BA0A2AA2A368A0052C62007AC96F60 +:104950002A828564A0691FE029276504C0E3C0C4DA +:104960002E64069CA11CE0549FA02E600A97A30C05 +:10497000EE029EA28F600CFF029FA42E60147AEFBD +:104980004627A417ADBC2F828527C4CF2FFC202F2C +:10499000868563FE692A6C74C0B1DC90DD405807DF +:1049A000A71DE00C63FEC100D9A0DA60DB30C2D0E5 +:1049B000C1E0DC4009DE39DD505807F1D2A0D10F4B +:1049C000DA605808F663FEE4290A0129A4170DBF2E +:1049D000082E828527F4CF2EEC202E868564500B7E +:1049E0002A6C74DB4058016AD2A0D10FC020D10FCD +:1049F0006C10062B221E28221D93107B8901C0B04B +:104A0000C0C9C03BC1F20406401DDFF6C0E2C0745D +:104A10000747010E4E01AD2D9E11C0402E0A1464B1 +:104A2000B06E6D084428221D7B81652AB0007EA1EE +:104A30003B7FA1477B51207CA14968A91768AA1434 +:104A400073A111C09F79A10CC18B78A107C1AE29B8 +:104A50000A1E29B4007CA12B2AB0070BAB0BDAB0DD +:104A60007DB3022ABDF8DBA0CAA563FFB428B0104D +:104A700089116987BB649FB863FFDC00647FB463FE +:104A8000FFD50000646FD0C041C1AE2AB40063FFFF +:104A9000C62B2102CEBE2A221D2B221E7AB12A8CC1 +:104AA000107CB1217AB901C0B0C9B913DFC1DA20D5 +:104AB00028B0002CB00703880A28824CC0D10B8094 +:104AC00000DBA065AFE7D240D10F8910659FD463AA +:104AD000FFF300006C1008C0D0C8598C30292102A7 +:104AE0000C0C4760000C8E300E1E5065E19E292193 +:104AF00002C0C116DFB0090B4C65B0908A300A6E57 +:104B00005168E3026000852F629E1BDFA96EF85397 +:104B10002BB22668B0052E22007BE94727629DB79D +:104B200048CB7F97102B200CB04E0CBF11A6FF294D +:104B3000F2869E12798B4117DFA007B70A2772A36E +:104B4000687004882077893029F285DF90D79065D6 +:104B500090652A210419DFD77A9B22DA205806A310 +:104B6000600029002C21041BDFD37CBB18DA20C095 +:104B7000B658069EC95860014CC09063FFCCDA203D +:104B8000580886600006DA20C0B65808846551359A +:104B9000DC40DB308D30DA200D6D515806F6C0D088 +:104BA000D3A064A120292102C05184A18CA00404B7 +:104BB000470C0C4763FF3E00C09C8831DBD008F8EF +:104BC00050089B3828210498116E8823282066AC51 +:104BD0008C0C0C472C24667CBB159F139E148A10EA +:104BE0008B115807068E148F13C0D02D24668A307F +:104BF000C092C1C81BDF867FA6099BF099F12CF4F7 +:104C00000827FC106550A4B83ADF70C051C0800777 +:104C1000583808084264806718DF6319DF64298602 +:104C20007E6A420AD30F6DE90500A08800F08CC0AF +:104C3000A08930B4E37F9628C0F207E90B2C9408D2 +:104C40009B909F912F200C12DF630CF811A68829EE +:104C50008285A2FF2DF4CFD2A009330B238685D104 +:104C60000F22200C891218DF5B0C2B11A6BBA82287 +:104C70002D24CF2CB285D2A00C990B29B685D10F4B +:104C8000C087C0900A593879809663FF8ADB30DA92 +:104C900020C0C1C0D05BFF56292102C0D02A9CFE93 +:104CA00065AE4D2D2502C09063FE45009E142A2C52 +:104CB00074C0B1DC70DD405806E18E14C0D01BDF3B +:104CC00053C1C863FF6AC020D10F00006C100628D2 +:104CD000210216DF3808084C65821929629E6F98F8 +:104CE0000260022019DF332992266890078A200982 +:104CF000AA0C65A20F27629DC0CC6472072B210409 +:104D00008E31C0A0DDA00EFE500ECD386EB8102C36 +:104D10002066B1CC0C0C472C24667CDB026001EFD2 +:104D2000C0C12930081BDF2564909C2F0AFFC0D327 +:104D3000B09E64E1026892136450882A2C74044B7C +:104D4000025800930AA20206000000002B200C2744 +:104D500021040CBC11A6CC29C286280A087983023A +:104D60006001B919DF1509B90A2992A36890082EC4 +:104D7000220009EE0C65E1A42EC28564E19E262086 +:104D80000713DF1E6E7B0260019A17DF151FDF1EFF +:104D900019DF4BC0D228200A93E09DE1A9690F8852 +:104DA0000298E22F90802A9480B1FF07FF029FE3D0 +:104DB0002EC2851FDF080EDE0BAFBF2AF4CF2EC632 +:104DC00085655F76C020D10F2830102930112E3034 +:104DD0001300993200ED326480EE2A30141FDF3860 +:104DE00000AA3278EF050F9E092DE47F1EDF36669C +:104DF000A0050F98092A8480B4A718DF33C76F0075 +:104E00009104AE9EDDE000AF1A00C31A6EE1052DDD +:104E1000B2000DED0C1EDF2D08D81C063303AE8842 +:104E20002A848B2EB02E27848C03EE010FEE022EE7 +:104E3000B42E58018F63FEFF29310829250428303C +:104E4000142E3109B0886480A32E240AC0812E302C +:104E5000162CB4232E240BB4EF2F240C8C378B3656 +:104E6000292504DEB0DFC00C8F390B8E390FEE021E +:104E700064EEC4089F1101C4048D380CB81800C436 +:104E8000040CBE1800EE110EDD02C0E30EFF021E80 +:104E9000DF019F719E701EDF008F2098739D740547 +:104EA000FF110BCD53C18098750FDD020EDD029D01 +:104EB000721EDEBF2A24662F629D2AE4A22FFC18F0 +:104EC0002F669D63FE710000002F30121BDF010072 +:104ED000FA3278FF050B980B2A847F66D0050B9A6F +:104EE0000B2DA4802A301100AA3263FF442F240A1C +:104EF0009E2B63FF56CC57DA20DB30DC4058071579 +:104F0000C020D10F00DA20C0B65807A463FFE50027 +:104F1000DA7058063AC0A02A246663FE02DA2058E6 +:104F2000079F63FFCFB16928200A862009094799A6 +:104F30001129240798107F812693E027E50A9AE338 +:104F400088109DE119DEDD8D11096F029FE42DE4CB +:104F500016098802C0D398E22A240763FE51000094 +:104F60001DDEA60868118F11892B93E008FF02C08F +:104F70008F9FE50D990299E2047F11C0D49DE1084D +:104F8000FF029FE463FFD0006C1004C020D10F002B +:104F90006C100485210D381114DE848622A42408A7 +:104FA000660C962205330B9321743B13C862D230F2 +:104FB000D10FC030BC29992199209322D230D10F32 +:104FC000233DF8932163FFE36C100AD62094181751 +:104FD000DE79D930B83898199914655252C0E1D2A7 +:104FE000E02E61021DDE760E0E4C65E1628F308E82 +:104FF000190F6F512FFCFD65F1558EE129D0230E5D +:105000008F5077E66B8F181EDEB3B0FF0FF4110FD1 +:105010001F146590CE18DEB08C60A8CCC0B119DE2C +:105020006428600B09CC0B0D880929811C28811A82 +:105030002A0A0009880C08BA381BDEA60CA90A291E +:1050400092947B9B0260008C2B600C94160CBD111B +:10505000A7DD29D286B8487983026000D219DE56CE +:1050600009B80A2882A398176880026000A360002C +:10507000A51ADE9A84180AEE01CA981BDE4D8C1917 +:105080002BB0008CC06EB3131DDE4A0C1C520DCC2D +:105090000B2DC295C0A17EDBAE6000380C0C5360B6 +:1050A000000900000018DE8C8C60A8CCC0B119DEAD +:1050B0004028600B09CC0B0D880929811C28811A16 +:1050C0002A0A0009880C08BA380CA90A2992947E89 +:1050D000930263FF72DA60C0BA580730645073609D +:1050E000026600001ADE338C192AA0008CC06EA361 +:1050F0001A18DE2F0C1C5208CC0B18DE762BC2952A +:10510000C0A178B30263FF3F63FFC9000C0C536377 +:10511000FF09896078991829D285C9922B729E1D42 +:10512000DE246EB8232DD226991369D00B60000DB2 +:10513000DA6058071A6000170088607D890A9A1A99 +:1051400029729D9C129915CF95DA60C0B658071345 +:105150006551F58D148C18DBD08DD0066A020D6D6B +:1051600051580584D3A09A1464A1DD82A085A1B80A +:10517000AF9F190505470202479518C05163FE60AD +:105180002B6104C08C8931C0A009F950098A386E9E +:10519000B81F2C6066A2CC0C0C472C64667CAB114B +:1051A0009F119E1B8A155805958E1B8F11C0A02A32 +:1051B00064669F1164F0E12912032812096DF91742 +:1051C0002F810300908DAEFE0080889F9200908C0E +:1051D000008088B89900908C65514E8A10851A8B92 +:1051E000301FDE06881229600708580A2C82942D89 +:1051F00061040ECC0C2C86946FDB3C1CDE30AC9C26 +:1052000029C0800B5D50A29909094729C48065D047 +:10521000DA2E600CC0D01FDDEF0CE811AFEEA788CE +:105220002282852DE4CF02420B228685D2A0D10FA7 +:105230008E300E0E4763FDA6A29C0C0C472C640713 +:105240007AB6CD8B602E600A280AFF08E80C6481CC +:105250000E18DE1983168213B33902330B2C341661 +:105260002D350AC02392319F30C020923308B202FC +:1052700008E80292349832C0802864072B600CD270 +:10528000A01CDDD40CBE11A7EE2DE285ACBB28B46A +:10529000CF0D9D0B2DE685D10F8B1888138D30B85F +:1052A0008C0D8F470D4950B4990499100D0D5F0472 +:1052B000DD1009FF029F800DBB029B8165508D852B +:1052C0001AB83AC0F1C0800CF83808084264806B04 +:1052D0001BDDB519DDB629B67E8D18B0DD6DDA059A +:1052E00000A08800C08CC0A063FEF30082138B1660 +:1052F0001DDDC628600AC0E02EC4800D880202B2FF +:105300000B99239F20C0D298229D2122600CB2BB12 +:105310000C2D11A7DD28D28508BB0B18DDAE2BD6CE +:1053200085A8222E24CFD2A0D10F9E1B851A2A6CCD +:10533000748B185BFF178E1B63FEA300C087C090A1 +:105340000AF93879809263FF86C020D10F9E1B2A0C +:105350006C74C0B18D185805398E1B851A63FE7E9A +:10536000886B8213891608BE110ECE0202920B9E24 +:1053700025B4991EDDA19F200E88029822C0EF045B +:10538000D8110E88029824C0E49E21C080D2A02BA0 +:10539000600C2864071CDD8F0CBE11A7EE2DE28582 +:1053A000ACBB28B4CF0D9D0B2DE685D10F000000BE +:1053B0006C1004C020D10F006C10048633C071C083 +:1053C00030600001B13300310400741A04620174CA +:1053D00060F1D10F6C1004022A02033B025BFFF65E +:1053E0001CDD771BDDBFC79F88B009A903098A01AF +:1053F0009AB079801EC0F00FE4311DDD6E0002000E +:105400002BD2821EDDB82AC1020EBB022BD6820A25 +:10541000E431D10F28C102C19009880208084F2841 +:10542000C50208E431D10F006C1004C0C00CE43197 +:1054300012DD631ADD6000020029A28218DDAC1BB8 +:10544000DDAA2621020B990108660129A6822625DC +:105450000206E43114DDA715DDA2236A902326128B +:105460008550242611252613222C40D10F00000040 +:105470006C1008D6102B0A64291AB41ADD4D0D23BE +:10548000111CDD4E0F2511B81898130E551118DD9B +:1054900099AC55A838AA332C80FF2A80FEA933285E +:1054A0008D0129800108AA112880000CAA02088811 +:1054B0001109880208AA1C288C08281604580862BA +:1054C00014DD3F0AA7022441162A30802B1204075C +:1054D000AA2858085DB1338B13B4559A6004AC28E0 +:1054E000B4662C56277B69E016DD769412C050C056 +:1054F000D017DD329D15D370D4102F60802E6082BE +:105500009F169E17881672891A8D128C402A607F0A +:105510000DCC282B3A200CAA2858084BC0B10ABE43 +:10552000372E35408F1772F91A8D128C402A608100 +:105530000DCC282B3A200CAA28580843C0B10ABE2B +:10554000372E3542B233B444B1556952B6B466C051 +:10555000508F15B877D370B2FF9F156EF899D10FA1 +:105560006C1004C021D10F006C1004270A001CDD50 +:10557000111FDD221EDD251DDD0E1ADD501BDD5E37 +:10558000C02824B0006D2A75AA48288080C0916484 +:10559000806100410415DD09C03125502E00361A06 +:1055A0000655010595390C56110C66082962966E50 +:1055B000974D0D590A29922468900812DD42024243 +:1055C0000872993B23629512DD06CB349F3002822C +:1055D000020E4402C092993194329233AD52246249 +:1055E00095C090244C1024669524B0002924A0AACC +:1055F00042292480B177B14404044224B400D10F7D +:10560000D10FD10F6C10041ADCEA2AA00058021C3A +:105610005BFFD5022A02033B025BFFD11BDCE8C91A +:10562000A12CB102C0D40DCC020C0C4F2CB5020C35 +:10563000E431D10FC0A00AE43118DCDE0002002FF3 +:10564000828219DCF12EB10209FF022F86820EE45C +:1056500031D10F006C1004C02002E43114DCD816E4 +:10566000DCD5000200226282234102732F0603E48C +:1056700031C020D10F19DD221ADD212841020A2A6A +:10568000010988012A668228450208E43115DD18DF +:1056900012DD1D25461DD10F6C1004292006289C03 +:1056A000F96480A02A9CFD65A0968A288D262F0A81 +:1056B000087AD9042B221FC8BD2C206464C0812E17 +:1056C00022090EAE0C66E0782B200C1EDCBA0CBC56 +:1056D00011AECC28C28619DCB878F3026000AD099F +:1056E000B90A2992A36890082E220009EE0C65E001 +:1056F0009B29C2851FDCC26490929F90C0E41FDC8E +:10570000CE9E9128200AC0E09E930F88029892882E +:10571000200F880298942F20079A979D962F950A1C +:105720002E240728200629206468833328C2851286 +:10573000DCA9288C20A2B22E24CF28C685C020D177 +:105740000FC020D10F2A206A0111020A2A4165AF39 +:1057500052DA20C0B05805E464AFE5C021D10F0093 +:10576000649FC81FDC962D20168FF209DD0C00F116 +:105770000400DD1AADAD9D2912DC9728C285A2B2C6 +:105780002E24CF288C2028C685C020D10FC021D13F +:105790000F0000006C1004260A001BDCDB15DC8700 +:1057A00028206517DC84288CFE6480940C4D110D34 +:1057B000BD082CD2F52BD2F42ED2F77CB13DB4BB70 +:1057C0002BD6F47BE9052BD2F62BD6F47CB92C2A08 +:1057D000D2F62AD6F52AD6F406E431000200287261 +:1057E000822AFAFF004104290A012F510200991A66 +:1057F0000A99030988012876820FE4312624652B53 +:10580000D2F48E5A2CD2F5B0EE9E5A7BCB1629D20A +:10581000F62FD2F70CB80C09FF0C08FF0C0F2F1451 +:10582000C8F96000320BCA0C0A2A14CEA92B510207 +:10583000C0C20CBB020B0B4F2B55020BE431D10F36 +:1058400000DB30DA205BFF941BDCB064AF5D0C4DF5 +:1058500011ADBD63FFA8000006E4310002002F7205 +:105860008218DC6E2E510208FF022F76820EE43180 +:10587000D10F00006C1004C03003E43116DC4E156B +:10588000DC4F00020024628274472118DCA0875A92 +:10589000084801286682CD7319DC9E0C2A11AA994A +:1058A0002292832992847291038220CC292B510267 +:1058B0000BE431C020D10F001FDC972E51020FEEF8 +:1058C000012E55020EE431B02DB17C9C5A12DC92AF +:1058D00008DD112D5619D10F6C10061BDC351EDCAE +:1058E0003722B0001ADC8E6F23721DDC75C0481899 +:1058F000DC8D1FDC8BDC10D5C083F000808600506F +:105900008A6D4A4F0F35110D34092440800B560A19 +:10591000296294B1330E55092251400F44110C44B1 +:105920000A874009A80C02883622514107883608A8 +:10593000770CA8992966949740296295874109A810 +:105940000C02883607883608770CA899296695973F +:1059500041030342B13808084298F0D10F1CDC72B1 +:1059600013DC7327B0002332B5647057C091C0D0E8 +:1059700016DC7115DC6FC0402AC00003884328C4C0 +:10598000006D793C004104B14400971A7780148E71 +:10599000502FB2952DB695AFEE2EED2006EE369E29 +:1059A0005060001877A00983509D5023B695600081 +:1059B0000223B295223D2006223622B695B455B870 +:1059C000BBD10F0003884328C400D10F6C1004C062 +:1059D0004004E43115DC59000200885013DC58CB38 +:1059E000815BFFBD1CDC570C2D11ADCC2BC2822A74 +:1059F000C28394507BAB142EC28429C2850ABD0C8D +:105A00000E990C0D990C0929146000050BA90C09BD +:105A10002914993015DBEA2A51020AE4312A2CFCB8 +:105A200058004B2B32000AA2022BBCFF9B30CCB695 +:105A3000C8A4D2A0D10F000004E4311EDBDE0002B6 +:105A4000002DE2822FBAFF2C51020FDD012DE682DC +:105A50000CE431D10F0000006C1004D10F000000E5 +:105A60006C1004C020D10F006C100413DC36C0D1C0 +:105A700003230923318DC0A06F340260008D19DB30 +:105A8000CD1BDBCE17DC2F0C2811A87726728325BF +:105A900072822CFAFF76514788502E7285255C045D +:105AA00025768275E9052572842576827659292E18 +:105AB00072842E76822E76830AE4310002002392CD +:105AC000820021042FB10200D61A0C6603063301AE +:105AD0002396820FE43126728325728260000200D1 +:105AE000D8A07659220AE4310002002392820021D4 +:105AF0000400D21A2FB1020C220302320122968234 +:105B00000FE431D280D10F00D280D10FC020D10F4D +:105B10006C1004DB30862015DBA6280A002825023D +:105B2000DA2028B0002CB00705880A28824C2D0AFC +:105B3000010B8000DBA065AFE61ADB9F0A4A0A2949 +:105B4000A2A3C7BF769101D10F2BA6A3D10F00004E +:105B50006C1004C0D1C7CF1BDB9919DB9617DB94FF +:105B60000C2811A87786758574C0A076516288507C +:105B70008E77B455957475E90385769574765927B3 +:105B80008F769F759F740AE431000200239282B4DD +:105B90002E2FB10200E10400D61A0C660306330171 +:105BA0002396820FE431867583747639280AE431AE +:105BB0000002002E9282B42200210424B10200DFF0 +:105BC0001A0CFF030FEE012E968204E431D280D12D +:105BD0000FD8A07651D6D280D10F00006C100429C6 +:105BE0000A801EDB9A1FDB9A1CDB730C2B11ACBBEB +:105BF0002C2CFC2DB2850FCC029ED19CD0C051C064 +:105C00007013DB9614DB9518DB932AB285A8280461 +:105C1000240A234691A986B8AA2AB685A98827848A +:105C20009F25649FD10F00006C100419DBC70C2A5C +:105C300011A9A98990C484798B761BDBB5ABAC2AFA +:105C4000C2832CC2847AC1688AA02BBC30D3A064E2 +:105C5000A05E0B2B0A2CB2A319DB7F68C0071DDBEB +:105C6000BBD30F7DC94AA929299D0129901F68919D +:105C70003270A603D3A0CA9E689210C7AF2AB6A3FB +:105C80002A2CFC5BFFB3D230D10F000013DBB10331 +:105C9000A3018C311DDB510C8C140DCC012CB6A34F +:105CA00063FFDC00C020D10FDA205BFFCCC020D125 +:105CB0000FC020D10F0000006C1004DB30C0D019E1 +:105CC000DB3CDA2028300022300708481209880A15 +:105CD00028824CDC200B80001BDB370C4A11ABAA5E +:105CE00029A28409290B29A684D10F006C1004C0B5 +:105CF0004118DB3017DB320C2611A727277030A89C +:105D000066256286007104A35500441A7541482235 +:105D1000628415DB5202320BC922882117DB2F085F +:105D20008414074401754905C834C020D10FD10F30 +:105D30000809471DDB86C0B28E201FDB1D0E0E43F7 +:105D4000AFEC2BC4A00FEE0A2DE6242A6284C020FB +:105D50000A990B296684D10FC020D10F6C1004DB87 +:105D600030C0D018DB13DA20253000223007085865 +:105D70000A28824CDC200B80008931709E121BDBCC +:105D80000D0C4A11ABAA29A28409290B29A684D19A +:105D90000F09C95268532600910418DB08C0A12FCF +:105DA000811200AA1A0AFF022F85121EDB020C4D77 +:105DB00011AEDD2CD2840C2C0B2CD684D10FC081DB +:105DC0001FDAFFB89A0A0A472EF11200A1040088D0 +:105DD0001A08EE022EF5121DDAF70C4C11ADCC2B81 +:105DE000C2840B2B0B2BC684D10F00006C1004DB7C +:105DF00030C0D019DAEFDA202830002230070988C5 +:105E00000A28824CDC200B80001CDAEA0C4B11AC17 +:105E1000BB2AB2840A2A0B2AB684D10F6C1004C0A4 +:105E20004118DAE416DAE60C2711A626266030A817 +:105E300072252286006104A35500441A7541082288 +:105E4000228402320BD10F00C020D10F6C10041538 +:105E5000DB410249142956112452120208430F88CB +:105E600011C07300810400361A008104C78F0077C7 +:105E70001A087703074401064402245612D10F0082 +:105E80006C10066E23026000AC6420A7C0A08510D1 +:105E900013DB1916DB30C040A6AA2BA2AE0B1941AA +:105EA00064906668915D68925268933C2AA2AA2821 +:105EB0003C7F288C7F0A0A4D2980012880002AAC6B +:105EC000F20888110988027589462B3D0129B00026 +:105ED0002BB0010899110B99027A9934B8332A2A08 +:105EE00000B1447249B160004A7FBF0715DB1B63F4 +:105EF000FFB90000253AE863FFB10000253AE863E6 +:105F0000FFA90000250A6463FFA1C05A63FF9C003B +:105F100000705F082534FF058C142C34FE70AF0B25 +:105F20000A8D142E3D012AE4012DE400DA405BFDC8 +:105F30005063FFA7D10FD10F6C10041ADAA019DA41 +:105F40009D1CDB061BDB07C080C07160000D0000DC +:105F50000022A430B1AA299C107B915F26928679F9 +:105F6000C2156E6262C0206D080AB12200210400D1 +:105F7000741A764BDB63FFEE2292850D63110325C5 +:105F800014645FCFD650032D436DD9039820B422FB +:105F90000644146D49229820982198229823982429 +:105FA00098259826982798289829982A982B982CED +:105FB000982D982E982F222C4063FF971EDA7E276B +:105FC000E68027E681D10F00C02063FF8300000038 +:105FD0006C1004C062C04112DA791ADA7513DAE182 +:105FE0002AA00023322D19DADB2BACFE2992AE6EEB +:105FF000A30260008E090E402D1AC2C2CD0EDC39FC +:106000002C251664B0895BFF9E15DAD71ADAD12BDE +:106010003AE80A3A0158058C2B21160ABB28D3A06E +:106020009B505805A32B52000ABB082A0A005805AA +:10603000A215DACE2D21022C3AE80C3C2804DD0210 +:106040002D25029C5058059A8B50AABBC0A158051B +:106050009A1CDAC72D21020C3C2806DD0213DAC592 +:106060002D25029C305805928B30AABBC0A2580542 +:10607000922A2102C0B40BAA020A0A4F2A2502580A +:1060800005A6D10F242423C3CC2C251663FF76004C +:1060900018DABD1CDAB919DABA1BDAB817DA8B8547 +:1060A000202E0AFD1FDAB92D202E24F47A24F47E46 +:1060B00024F4820EDD0124F4862E0AF70755280603 +:1060C000DD02C0750EDD01050506AB5BA959C0E810 +:1060D000AC5C24C4AB0EDD0227C4AC2E0ADFA8558D +:1060E00027B4EC0EDD0124B4EBC2E027942C0EDDC6 +:1060F0000224942B2E0A800D0D4627546C24546BD9 +:106100000EDD022D242E63FEFC0000006C10042A1C +:106110000A302B0A035BFF4D12DA8FC39029261633 +:10612000C3A1C0B3C08A2826175BFF48C03CC3B1D7 +:106130002B26161ADA222AA02023261764A079C358 +:10614000A2C0B15BFF42C3A2C0B15BFF40C3C22C7F +:106150002616C2AFC0B12326175BFF3CC28F28268C +:1061600016C0FE2F2617C2E22E26162A0AA1C0B19B +:10617000C0D82D26175BFF352A0AA12A2616C3A6EA +:10618000C0B3C1922926175BFF31C3C62C2616C1A6 +:10619000B32A0AA22B2617C0B35BFF2C290AA22917 +:1061A0002616C185282617C2FB2F2616C0E72E26E5 +:1061B000171DDA762D2610D10FC3A2C0B35BFF23C3 +:1061C00063FF82006C10041CDA3F1BDA2C18DA70B3 +:1061D00017DA7116DA7115DA71C0E0C0D414DA3B3F +:1061E0001FD9F7C0288FF06D2A36DAC0D9C07C5B82 +:1061F000020FC90C1CDA350C9C28A8C3A6C22A368B +:10620000802A2584A4C2A7CC2D248C2B248A2B245D +:10621000872E248BB1BB2E369F2C369E2C369DB1FB +:10622000AC1CDA161BDA5FC0286D2A33DAC0D9C07D +:106230007C5B020FC90C1CDA240C9C28A8C3A6C2E4 +:106240002A36802B2584A4C2B1BBA7CC2D248C2E4A +:10625000248B2A248A2E369F2C369E2C369DB1AC58 +:10626000C07919DA141BDA5113DA4F1ADA4F18DA37 +:106270005014DA1516DA5004F42812DA4F04660CBA +:10628000040506A252A858AA5AA3539B3029A50078 +:1062900027848AC091C0A52A848C29848B17DA4868 +:1062A00018DA47A75726361D26361E2E361F16DA51 +:1062B0004513DA45A65504330C2826C82E75002D43 +:1062C00054AC2E54AB2E54AA2326E62326E52E26C4 +:1062D000E7D10F006C100613DA2317DA1E24723D83 +:1062E0002232937F2F0B6D08052832937F8F026334 +:1062F000FFF3C0C4C0B01AD9B1C051D94004593954 +:1063000029A4206E44020BB502C3281ED9ACDDB00F +:1063100025E422052D392DE421C0501EDA2C19DA8E +:106320001C18DA1C16DA1E1DDA2A94102A72451778 +:10633000D9E76DA94BD450B3557A5B17DF50756B15 +:10634000071FD99E8FF00F5F0C12D9DF02F228AE23 +:106350002222D681D54013D9DC746B0715D99885D4 +:106360005005450C035328B145A73FA832A9332255 +:10637000369D22369E2436802B369F2BF48B2CF4B0 +:106380008C14D9F824424DC030041414C84C6D0844 +:1063900006B133041414C84263FFF20015D985C452 +:1063A000400031041AD986C0D193A200DD1AC13849 +:1063B000B0DD9DA318D9EC2B824D29824E29A51C56 +:1063C0002882537A871E2C54008E106FE45D12D9F8 +:1063D0007B2F211D23211C2F251B04330C23251C5F +:1063E00023251AD10FC06218D9DB88807E87D9890E +:1063F000102654006F94191BD9712AB11C0A1A1463 +:1064000004AA0C2AB51C2AB51D2AB51A2AB51BD117 +:106410000F1BD96A2AB11C0A1A1403AA0C2AB51C2C +:106420002AB51D2AB51A2AB51BD10F001CD9642B19 +:10643000C11D2DC11C2BC51B03DD0C2DC51C2DC57D +:106440001AD10F006C100619D95D14D9C212D9C522 +:1064500015D9E0C73FC0E02E56A82E56A92E56AA41 +:106460002E56AB23262918D985DB101CD9DAC0D4C7 +:106470002A42452D16019C1000B0890A880C2896E6 +:10648000005BFF942B22E318D94D0B5B149B842AED +:1064900022E48B84B1AA0A5A140BAA0C9A852922E9 +:1064A000E509591499862F22CD0F5F149F875BFF52 +:1064B000455BFF1623463BC1B01DD9401CD99E2A1F +:1064C000D1022C463A0BAA020A0A4F2AD5025804D6 +:1064D000925BFEBF5BFE98C050C0B016D93614D98F +:1064E0003E17D9AEC0C0C73E93122C262DC03060D7 +:1064F00000440000007F9F0FB155091914659FF4F7 +:10650000C0500AA9027FA7EF18D92ADA5008580A02 +:1065100028822C2B0A000B8000005104D2A0C091CD +:10652000C7AF00991A0A99039912CE3864206BD329 +:10653000202B20072516032C12022A62827CA863D6 +:1065400018D91C01110208580A28822CDA500B8035 +:1065500000D2A0643FD58A310A8A1404AA01C82A4D +:106560002B22010B8B1404BB017BA945DDA07A7B98 +:10657000081DD9122DD2000DAD0CDB3019D90D1A22 +:10658000D95288130ADA28DC801DD99009880A2894 +:10659000823C0DAA080B8000652F93D320C0B06306 +:1065A000FF9400007FAF34B1550050040A0919630D +:1065B000FF42DAB07B7B081AD9012AA2000ABA0C82 +:1065C0001BD9428C310BAB280C8A141CD980ACBB74 +:1065D0001CD98004AA012BC68163FF8F645F60C051 +:1065E00050C0B0C7CE9C1263FF5500006C1004274A +:1065F000221EC08008E4311BD8EF0002002AB282BC +:1066000019D8EF003104C06100661A2991020A6AA4 +:10661000022AB68209E43115D94A0C3811A8532848 +:1066200032822432842A8CFC7841102921022A36B5 +:106630008297A0096902292502D10F002B21022C83 +:1066400032850B6B022CCCFC2C368297C02B25029A +:10665000D10F00006C1004C0E71DD8D21CD8D40D97 +:106660004911D7208B228A200B4B0BD2A007A80CF4 +:106670009B72288CF4C8346F8E026000A31FD8CAA6 +:10668000A298AF7B78B334C93DC081C0F0028F3887 +:106690000F0F42C9FA2CD67ED5206D4A05003088EE +:1066A00000508C887008980878B16DD2A09870D18D +:1066B0000FC0F0038F387FE0DE63FFD8027B0CAFA2 +:1066C000BB0B990C643047D830C0F1C05002F5388C +:1066D0000505426450792CD67E0B36122F6C100FB4 +:1066E0004F366DFA0500808800208C06440CC0816E +:1066F000C05003B208237C0C038538050542645062 +:106700005A2CD67ED30F6D4A0500208800308CD2DB +:10671000A0A798BC889870D10FD2A0BC799970D1ED +:106720000FD2302BAD08C0F1C0500BF53805054233 +:10673000CB542CD67E083F14260A100F660C064652 +:10674000366D6A0500208800B08C827063FF2D00D2 +:10675000C05003F53875E08063FF7A00C0600286A0 +:106760003876E09F63FF9900C05003F53875E0C4A8 +:1067700063FFBE006C1004D62068520F695324DA00 +:1067800020DB30DC405800F3D2A0D10FDA20DB3020 +:10679000DC405800F09A2424240EC02122640FC04B +:1067A00020D10F00B83BB04C2A2C7489242D200E28 +:1067B0002E200FA4DDB1EE2E240FB0DD2D240E28E7 +:1067C00090072D9003A488B088B1DD2D9403289400 +:1067D000075BFFA069511DC0E082242A600F18D812 +:1067E000FE2A240329600E8F2029240708FF029F18 +:1067F000209E64D10FC020D10F0000006C100494C3 +:106800002319D8F6C0B3083A110BAA02992019D857 +:10681000699A2116D867C05028929D2564A2288CB9 +:106820001828969DD10F00006C1004282066C038EF +:10683000232406B788282466D10F00006C100603B5 +:106840005A0C0D36110D5C11D8208B2282210CBB05 +:106850000C06550F9B8202320B928113D853D9201C +:10686000A38F6450561CD84FC0D71BD850A256C017 +:10687000E1C09004E93809094276F34F044302CAA3 +:10688000912BC67ED30F6DAA0500208800308C891D +:1068900081A95909FA0C64A07D99818A8264A00FAC +:1068A000D290D10FC06002E63876D0D763FFD10016 +:1068B000C020BC89998199809282D10F7F230429BD +:1068C0002DF8998165BFD863FFE50000028F0CA306 +:1068D000FF0F3312931003AA0CD3406490402BC6D1 +:1068E0007E8610D30F6D6A0500208800308CBC8234 +:1068F000C090A4F3C041034938090942CA9B2BC682 +:106900007E6DAA0500208800308C0F590CA989BC27 +:1069100099998163FF8400BC89998163FF7C00C0E1 +:106920006002E63876D0B963FFB300C07002473822 +:1069300077D0CD63FFC700006C100414D82AC15271 +:10694000A424CA3128221D73811C292102659016B6 +:106950002A300075A912022A02033B022C3007C01C +:10696000D25801D0653FDCD10F2B300703BB0B0B96 +:10697000BA0274B3022ABDF8D3A063FFC4000000BA +:106980006C1004292006C0706E9741292102C08F27 +:106990002A2014C0B62B240606AA022A24147980C1 +:1069A000022725022A221E2C221D7AC10EC8ABDA2C +:1069B00020DB302C0A00033D025BF80D6450742D7F +:1069C00021020D0D4CC9D3C020D10F00002E9CFB1D +:1069D00064E0822F21020F0F4C65F0911AD7F61C4C +:1069E000D7F429A29EC08A798B5D2BC22668B00499 +:1069F0008D207BD95229A29DC0F364904A97901DA7 +:106A0000D8062E21049D9608EE110FEE029E979E49 +:106A10009118D802C0E527C4A22E24062BA29D2FD0 +:106A200021022BBC3008FF022F25022BA69DC0207F +:106A3000D10F00002F300068F939DA20DB30044C28 +:106A40000258004463FF7700022A022B0A0658000E +:106A5000D3220A00D10F6550102830006889240223 +:106A60002A02033B02DC4058003BC020D10FD27009 +:106A7000D10F00002A2C74033B02044C025BFEF58C +:106A800063FF3B00DB30DC402A2C745BFEF2C0204D +:106A9000D10F00006C1004C83F89268829A399995A +:106AA0002609880C080848282525CC52C020D10F7B +:106AB000DB402A2C745BF936D2A0D10F6C1004D8BD +:106AC00020D73082220D451105220C928264207459 +:106AD00007420B13D7B5D420A383732302242DF8C8 +:106AE000858074514CBC82C0906D081600408800AF +:106AF000708C773903D720C0918680743901D420F7 +:106B000074610263FFE2CA98C097C0411BD835C0C8 +:106B1000A00B8B0C0B4A380A0A42C9AA1DD7A21C2B +:106B2000D7A32CD67EC140D30F6D4A050020880024 +:106B3000308C9780D270D10FBC8FC0E00F4E387E62 +:106B400090E263FFD6BC8292819280C0209282D173 +:106B50000F0000006C1006C0D71CD7921BD7940DF5 +:106B60004911D7202E221F28221D0E4E0BD280073E +:106B70008A0C2E761F2AAC80C8346FAE026000CB20 +:106B80002F0A801AD798A29EAA7A7EA33FC93FC037 +:106B9000E1C05002E538050542CA552BC67EDB2010 +:106BA000D30F6D4A0500308800B08C2E721DAE9E4A +:106BB0000EA50C645086D2802E761DC091298403C8 +:106BC000D10FC05003E53875D0D363FFCD15D785FD +:106BD000027E0CA5EE643051C0A1250A0002A53842 +:106BE000033A020505426450922BC67E0E3512957B +:106BF00010255C10054536D30F6D5A0500A088009E +:106C0000208CC0A1A3E2C05023FA8003730C03A51B +:106C100038AF730505426450722BC67E851005455A +:106C20000C6D5A0500208800308CD280C0A10E9BCC +:106C30000CAB7BAFBB2B761D2A8403D10FD280C057 +:106C4000C1AF7D2D761D2C8403D10F00D2302E8D47 +:106C500008C0F1C0500EF538050542CB592BC67E51 +:106C60000A3F14C1600F660C064636D30F6D6A05E5 +:106C700000208800E08C22721D63FF03C061C050B9 +:106C800003653875D80263FF6263FF5CC05002A5DC +:106C90003875D08763FF8100C06003F63876D0BFB7 +:106CA00063FFB9006C10042A201529201614D7435D +:106CB0000A990CCB9D2E200B04ED092BD11C8F289B +:106CC00009BC36ACAA0CBB0C2BD51C0A0A472A24DB +:106CD00015CAAF8B438942B0A800910400881AA856 +:106CE000FF0FBB029B278F260FB80C783B1AC020E2 +:106CF000D10F0000292102C0A20A9902292502C051 +:106D000021D10F008B2763FFDC2BD11C0CAA0C0AAE +:106D10000A472A2415ACBB2BD51CC9AE8B438C2843 +:106D20008F42B0AD00F10400DD1AADCC0CBB029B6C +:106D300027DA20B7EB580019C021D10F9F2763FF36 +:106D4000EF0000006C100428203C643047053060E0 +:106D500000073E01053EB156076539054928C77F42 +:106D6000A933030641076603B166060641A6337ED2 +:106D7000871E222125291AFC732B1502380C098144 +:106D80006000063E01023EB12406423903220AD1C8 +:106D90000FD230D10FC05163FFC000006C10042728 +:106DA000221EC08008E4311DD7030002002CD282CD +:106DB0001BD703003104C06100661A2BB1020C6CB2 +:106DC000022CD6820BE43119D7870C3A11AA9328EA +:106DD00032829780253282243284B45525368275DA +:106DE000410A292102096902292502D10F2A21021B +:106DF0002B32830A6A022B36822A2502D10F000029 +:106E00006C100418D6EC0C2711087708267286251A +:106E10003C04765B1315D6E805220A2222A36820DB +:106E200002742904227285D10FC020D10F00000006 +:106E30006C100419D6EB27221EC08009770208E4E3 +:106E4000311DD6DC0002002CD2821BD6DC003104BE +:106E5000C06100661A2BB1020C6C022CD6820BE4C6 +:106E60003119D7600C3A11AA9328328297802532C3 +:106E700082243284B45525368275410B2A21020AB8 +:106E80006A022A2502D10F002B21022C32830B6BC0 +:106E9000022C36822B2502D10F0000006C10041B3F +:106EA000D6C50C2A11ABAA29A286B438798B221B2D +:106EB000D6C219D6E80B2B0A2BB2A309290868B051 +:106EC0000274B90D299D0129901F6E920822A28596 +:106ED000D10FC020D10FC892C020D10FDA205BEEB5 +:106EE000B3C020D10F0000006C100414D6B22842A9 +:106EF0009E19D6AF6F88026000BA29922668900763 +:106F00008A2009AA0C65A0AC2A429DC0DC64A0A41A +:106F10002B200C19D6A90CBC11A4CC2EC28609B901 +:106F20000A7ED30260009A2992A36890078D2009F7 +:106F3000DD0C65D08C25C2856450862D2104C030BF +:106F40006ED80D2C2066B8CC0C0C472C246665C07E +:106F50007B1CD72518D6AF1AD6A619D6B61DD6AB28 +:106F6000C0E49E519D508F209357935599539A5644 +:106F70009A5408FF021AD6C29F5288269F5A9E59D9 +:106F80009D58935E9C5D935C9A5B08084805881148 +:106F9000985FC0D81FD6900CB911A499289285AFDC +:106FA000BF23F4CF288C402896858E262D24069E5C +:106FB00029C020D10FCA33DA20C0B65BFF78C72FB3 +:106FC000D10FC93ADA205BFF75C72FD10FDBD05B39 +:106FD000FE0B2324662B200C63FF7500C72FD10FF7 +:106FE000C72FD10F6C1004C85B29200668941C6859 +:106FF0009607C020D10FC020D10FDA20DB30DC4053 +:10700000DD502E0A005BFE5ED2A0D10F2E200C18A0 +:10701000D6690CEF11A8FF29F286C088798B791AFE +:10702000D6660AEA0A2AA2A368A0048B207AB96865 +:1070300023F2856430621BD670290A802C206828D0 +:1070400020672D21040B881104DD1108DD020DCC11 +:1070500002C0842D4A100DCC021DD66898319D3097 +:107060008A2B99379C340BAA02C0C09C359C369A57 +:10707000322A2C74DB4028F285C0D3288C2028F6D5 +:10708000852C25042D24061FD653DD40AFEE2CE4BD +:10709000CF5BFDEAD2A0D10F00DA20DBE05BFF3F3F +:1070A000C020D10F6C100AD6302A200624160128E1 +:1070B000ACF86583862B2122C0F22A2124CC572AE2 +:1070C000AC010A0A4F2A25247ABB0260037F2C21D7 +:1070D000020C0C4C65C3192E22158D32C0910EDDA9 +:1070E0000C65D39088381ED63364836B8C37C0B858 +:1070F000C0960CB9399914B49A9A120D9911991332 +:107100008F6718D62EC9FB2880217F83168B142CFD +:1071100022002A200C5BFF61D4A064A3B38F6760B8 +:10712000002800002B200C89120CBA11AEAA2CA248 +:10713000861DD6217C9B3E0DBD0A2DD2A368D004AE +:1071400088207D893024A28564436427212E07F797 +:107150003607F90C6F9D01D7F0DA20DB70C1C42D22 +:10716000211F5BFEF889268827DDA009880C7A8B11 +:10717000179A10600006C04063FFCC0000DA208B35 +:10718000105BFEC88D1065A267C0E09E488C649CB1 +:10719000498B658A669B4A9A4B97458F677F730236 +:1071A000600120CD529D10DA20DB302C12015BFEF5 +:1071B000698D10C051D6A08FA7C0C08A68974D9A1C +:1071C0004C8869896A984E994F8E6A8A69AE7E7733 +:1071D000EB01B1AA9E6A9A698B60C0A00B8E1477EE +:1071E000B701C0A1C091C08493159D179516C0D05A +:1071F00025203CC030085801089338C0820833105D +:10720000085B010535400B9D3807DD100BAB100EF8 +:1072100019402A211F07991003DD020DBB020553F7 +:10722000100933020A55112921250A2A14092914A3 +:107230000499110A99020933028A2B2921040BAA05 +:10724000021BD66A0899110955020855020BAA02B9 +:107250009A408920881408991109880219D5EA1DD5 +:10726000D66409880298418B2A9346954783150D69 +:10727000BB0285168D179B448A658966AACAA97CBC +:1072800077CB01B1AA07FB0C9C669A6588268E29EC +:10729000AD87972607EE0C0E0E482E25259B672BF3 +:1072A000200C87131ED5C40CB911AE99289285A75E +:1072B0008828968517D5C8C090A7BB29B4CF871852 +:1072C00063FE3C008C60C0E0C091C0F0C034C0B828 +:1072D0002A210428203C08AA110B8B0103830103F7 +:1072E0009F380B9B39C03208FF10038801089E3875 +:1072F0000C881407EE100FEE020388010898390578 +:10730000BF1029211F0ABB1107881008FF020BAA12 +:107310000218D5BC09291403AA022B212583200BAE +:107320002B1404BB110833110FBB020B99028B14F1 +:107330008F2A0B33020833028B2B64708688689780 +:107340004D984C8769886A93419946974E984FC0EB +:107350007077C701C0719A4718D6260B7C100CECC9 +:107360000208F802984418D6230CBC0208CC029CF0 +:10737000402A200C295CFEC0801FD58E1CD5960C9F +:10738000AE112B2124ACAAAFEEB0BB8F132CE2853B +:1073900028A4CFAFCC2CE6852A22152B2524B1AA10 +:1073A0002A26156490DBC9D28F262E22090DFF08EC +:1073B0002F26060FEE0C0E0E482E25256550E4C034 +:1073C00020D10F00C07093419F4499469A4777C7D8 +:1073D0000A1CD57A2CC022C0810C87381CD6070B1A +:1073E000781008E80208B8020C8802984063FF8011 +:1073F00000CC57DA20DB608C115BFDD629210268B6 +:107400009806689403C020D10F2B221EC0A0292209 +:107410001D2A25027B9901C0B064BFE813D5652CF5 +:10742000B00728B000DA2003880A28824CC0D10BAC +:107430008000DBA065AFE763FFCA000068A779DAC8 +:1074400020DB30DC40DD505BFEE7D2A0D10FC16D08 +:10745000C19D29252C60000429252CD6902624675F +:107460002F2468DA20DB308C11DD502E0A805BFD82 +:1074700044D2A0D10FC168C1A82A252C63FFDD002A +:107480000000C8DF8C268B29ADCC9C260CBB0C0BD6 +:107490000B482B25252A2C74DB602C12015BFD8701 +:1074A000D2A0D10F2A2C748B115BF6B9D2A0D10FC8 +:1074B000DA205BFE3A63FF3800DA20C0B15BFE8A57 +:1074C00064ABF1655F352D2124B1DD2D252463FFEB +:1074D0001FDA202B200C5BFE5663FF1412D5C882E6 +:1074E00020028257C82163FFFC12D5C403E8300490 +:1074F000EE3005B13093209421952263FFFC00000B +:1075000010D5C0910092019302940311D597821077 +:1075100001EA30A21101F031C04004E4160002007B +:1075200011D5B98210234A00032202921011D5828C +:10753000C021921004E4318403830282018100009F +:10754000D23001230000000010D5B09100920193C9 +:1075500002940311D586821001EA30A21101F131A3 +:10756000C04004E41600020011D5A7821013D52BE9 +:10757000032202921004E431840383028201810019 +:1075800000D330013300000010D5A19100810165C6 +:10759000104981026510448103CF1F920193029428 +:1075A0000311D574821001EA30A21101F231C040FA +:1075B00004E41600020011D593821013D5130322A0 +:1075C00002921004E431840383028201C01091030B +:1075D00091029101810000D43001430012D542C0D4 +:1075E0003028374028374428374828374C233D0176 +:1075F0007233ED03020063FFFC00000010D585919B +:107600000092019302940311D5838210921011D538 +:10761000348310032202921011D58012D5469210A5 +:10762000C04004E41600020011D577821013D52D56 +:10763000032202921004E431840383028201810058 +:1076400000D53001530000006C10026E322FD6209E +:10765000056F04043F04745B2A05440C00410400D8 +:10766000331A220A006D490D73630403660CB122BC +:107670000F2211031314736302222C01D10FC83B94 +:10768000D10F000073630CC021D10F000000000077 +:1076900044495630C020D10F6C10020040046B4C9E +:1076A00007032318020219D10F020319C020D10FBA +:1076B0006C100202EA30D10F6C1002CC2503F031BD +:1076C00060000F006F220503F1316000056F230594 +:1076D00003F231000200D10F6C1002CC2502F03011 +:1076E000D10F00006F220402F130D10F6F2304028A +:1076F000F230D10FC020D10F6C1002220A20230AD1 +:10770000006D280E28374028374428374828374C42 +:10771000233D01030200D10F6C100202E431D10FAE +:107720000A004368656C73696F20465720444542E0 +:1077300055473D3020284275696C74204672692097 +:107740004D61792020382031363A30373A333620AF +:107750005044542032303039206F6E20636C656F96 +:1077600070617472612E6173696364657369676EB9 +:107770006572732E636F6D3A2F686F6D652F666546 +:107780006C69782F772F66775F372E31292C20563A +:10779000657273696F6E2054337878203030372EDD +:1077A00030342E3030202D203130303730343030EE +:0877B000100704000071489469 +:00000001FF -- cgit v0.10.2 From 56c8f140719e6f62836fb645d3fd96c6289907fb Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 3 Jun 2009 06:19:15 +0000 Subject: cxgb3: minor aq100x phy fixes Use generic MDIO generic values. Based on Ben Hutchings'review comments. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c index c51e50d..b1fd5bf 100644 --- a/drivers/net/cxgb3/aq100x.c +++ b/drivers/net/cxgb3/aq100x.c @@ -43,8 +43,6 @@ enum { AQ_XAUI_TX_CFG = 0xe400, /* MDIO_DEV_ANEG registers */ - AQ_100M_CTRL = 0x0010, - AQ_10G_CTRL = 0x0020, AQ_1G_CTRL = 0xc400, AQ_ANEG_STAT = 0xc800, @@ -54,14 +52,15 @@ enum { AQ_IMASK_GLOBAL = 0xff00, }; -#define AQBIT(x) (1 << (x)) -#define IMASK_PMA AQBIT(0x2) -#define IMASK_GLOBAL AQBIT(0xf) -#define ADV_1G_FULL AQBIT(0xf) -#define ADV_1G_HALF AQBIT(0xe) -#define ADV_10G_FULL AQBIT(0xc) -#define AQ_RESET (AQBIT(0xe) | AQBIT(0xf)) -#define AQ_LOWPOWER AQBIT(0xb) +enum { + IMASK_PMA = 1 << 2, + IMASK_GLOBAL = 1 << 15, + ADV_1G_FULL = 1 << 15, + ADV_1G_HALF = 1 << 14, + ADV_10G_FULL = 1 << 12, + AQ_RESET = (1 << 14) | (1 << 15), + AQ_LOWPOWER = 1 << 12, +}; static int aq100x_reset(struct cphy *phy, int wait) { @@ -160,7 +159,7 @@ static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map) adv = 0; if (advertise_map & ADVERTISED_10000baseT_Full) adv |= ADV_10G_FULL; - err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_10G_CTRL, + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, ADV_10G_FULL, adv); if (err) return err; @@ -186,7 +185,8 @@ static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map) adv |= ADVERTISE_PAUSE_CAP; if (advertise_map & ADVERTISED_Asym_Pause) adv |= ADVERTISE_PAUSE_ASYM; - err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_100M_CTRL, 0xfe0, adv); + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE, + 0xfe0, adv); return err; } -- cgit v0.10.2 From 278b2513f76161a9cf1ebddd620dc9d1714fe573 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 Jun 2009 21:20:51 -0700 Subject: gso: Stop fraglists from escaping As it stands skb fraglists can get past the check in dev_queue_xmit if the skb is marked as GSO. In particular, if the packet doesn't have the proper checksums for GSO, but can otherwise be handled by the underlying device, we will not perform the fraglist check on it at all. If the underlying device cannot handle fraglists, then this will break. The fix is as simple as moving the fraglist check from the device check into skb_gso_ok. This has caused crashes with Xen when used together with GRO which can generate GSO packets with fraglists. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index bbfabf3..2a80138 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1903,15 +1903,14 @@ static inline int net_gso_ok(int features, int gso_type) static inline int skb_gso_ok(struct sk_buff *skb, int features) { - return net_gso_ok(features, skb_shinfo(skb)->gso_type); + return net_gso_ok(features, skb_shinfo(skb)->gso_type) && + (!skb_shinfo(skb)->frag_list || (features & NETIF_F_FRAGLIST)); } static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) { return skb_is_gso(skb) && (!skb_gso_ok(skb, dev->features) || - (skb_shinfo(skb)->frag_list && - !(dev->features & NETIF_F_FRAGLIST)) || unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); } -- cgit v0.10.2 From 2307f866f542f3397d24f78d0efd74f4ab214a96 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Wed, 3 Jun 2009 21:43:26 -0700 Subject: ipv4: remove ip_mc_drop_socket() declaration from af_inet.c. ip_mc_drop_socket() method is declared in linux/igmp.h, which is included anyhow in af_inet.c. So there is no need for this declaration. This patch removes it from af_inet.c. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index d873621..566ea6c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -116,7 +116,6 @@ #include #endif -extern void ip_mc_drop_socket(struct sock *sk); /* The inetsw table contains everything that inet_create needs to * build a new socket. -- cgit v0.10.2 From c722c625dbe2758d53365c0ed7d401b0e286f2cf Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 Jun 2009 21:45:55 -0700 Subject: tun: Only wake up writers When I added socket accounting to tun I inadvertently introduced spurious wake-up events that kills qemu performance. The problem occurs when qemu polls on the tun fd for read, and then transmits packets. For each packet transmitted, we will wake up qemu even if it only cares about read events. Now this affects all sockets, but it is only a new problem for tun. So this patch tries to fix it for tun first and we can then look at the problem in general. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4cda69b..3f0cdc1 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -844,12 +844,12 @@ static void tun_sock_write_space(struct sock *sk) if (!sock_writeable(sk)) return; - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_sync(sk->sk_sleep); - if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) return; + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_sync(sk->sk_sleep); + tun = container_of(sk, struct tun_sock, sk)->tun; kill_fasync(&tun->fasync, SIGIO, POLL_OUT); } -- cgit v0.10.2 From 5c726166692449dfd570bf4497d427f1ea200ad3 Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Wed, 3 Jun 2009 21:54:29 -0700 Subject: TI DaVinci EMAC: Remove print_mac, DECLARE_MAC_BUF Use printk format specifier for MAC address. Remove DECALRE_MAC_BUF and print_mac() usage in the driver. Signed-off-by: Chaithrika U S Signed-off-by: David S. Miller diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index cf689a0..0e9b9f9 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1819,7 +1819,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) struct emac_rxch *rxch = priv->rxch[EMAC_DEF_RX_CH]; struct device *emac_dev = &priv->ndev->dev; struct sockaddr *sa = addr; - DECLARE_MAC_BUF(mac); /* Store mac addr in priv and rx channel and set it in EMAC hw */ memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len); @@ -1828,8 +1827,8 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr); if (netif_msg_drv(priv)) - dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %s\n", - print_mac(mac, priv->mac_addr)); + dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %pM\n", + priv->mac_addr); return 0; } @@ -2683,11 +2682,10 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) ndev->irq = res->start; if (!is_valid_ether_addr(priv->mac_addr)) { - DECLARE_MAC_BUF(buf); /* Use random MAC if none passed */ random_ether_addr(priv->mac_addr); - printk(KERN_WARNING "%s: using random MAC addr: %s\n", - __func__, print_mac(buf, priv->mac_addr)); + printk(KERN_WARNING "%s: using random MAC addr: %pM\n", + __func__, priv->mac_addr); } ndev->netdev_ops = &emac_netdev_ops; -- cgit v0.10.2 From a5e78820966e17c2316866e00047e4e7e5480f04 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Thu, 4 Jun 2009 16:54:42 +0200 Subject: netfilter: x_tables: added hook number into match extension parameter structure. Signed-off-by: Evgeniy Polyakov Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index c9efe03..1030b75 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -184,9 +184,10 @@ struct xt_counters_info * @matchinfo: per-match data * @fragoff: packet is a fragment, this is the data offset * @thoff: position of transport header relative to skb->data - * @hotdrop: drop packet if we had inspection problems + * @hook: hook number given packet came from * @family: Actual NFPROTO_* through which the function is invoked * (helpful when match->family == NFPROTO_UNSPEC) + * @hotdrop: drop packet if we had inspection problems */ struct xt_match_param { const struct net_device *in, *out; @@ -194,8 +195,9 @@ struct xt_match_param { const void *matchinfo; int fragoff; unsigned int thoff; - bool *hotdrop; + unsigned int hooknum; u_int8_t family; + bool *hotdrop; }; /** diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 2455583..37928d5 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -170,7 +170,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb, mtpar.in = tgpar.in = in; mtpar.out = tgpar.out = out; mtpar.hotdrop = &hotdrop; - tgpar.hooknum = hook; + mtpar.hooknum = tgpar.hooknum = hook; read_lock_bh(&table->lock); private = table->private; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 7b35c0b..5bf7c3f 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -343,7 +343,7 @@ ipt_do_table(struct sk_buff *skb, mtpar.in = tgpar.in = in; mtpar.out = tgpar.out = out; mtpar.family = tgpar.family = NFPROTO_IPV4; - tgpar.hooknum = hook; + mtpar.hooknum = tgpar.hooknum = hook; IP_NF_ASSERT(table->valid_hooks & (1 << hook)); xt_info_rdlock_bh(); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 5164e0b..ced1f2c 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -369,7 +369,7 @@ ip6t_do_table(struct sk_buff *skb, mtpar.in = tgpar.in = in; mtpar.out = tgpar.out = out; mtpar.family = tgpar.family = NFPROTO_IPV6; - tgpar.hooknum = hook; + mtpar.hooknum = tgpar.hooknum = hook; IP_NF_ASSERT(table->valid_hooks & (1 << hook)); -- cgit v0.10.2 From c587de0b8d6e194f7a1719fc6af8a81b4e8916d2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Jun 2009 11:44:07 -0700 Subject: iwlwifi: unify station management This patch unifies 3945 and AGN station management It also removes useless struct iwl_station_mgmt ops and cleanups a bit the interface Signed-off-by: Tomas Winkler Tested-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 814afaf..5eb538d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -38,6 +38,7 @@ #include "iwl-commands.h" #include "iwl-3945.h" +#include "iwl-sta.h" #define RS_NAME "iwl-3945-rs" @@ -714,13 +715,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !rs_sta->ibss_sta_added) { - u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); + u8 sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n", hdr->addr1); - sta_id = iwl3945_add_station(priv, - hdr->addr1, 0, CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, false, + CMD_ASYNC, NULL); } if (sta_id != IWL_INVALID_STATION) rs_sta->ibss_sta_added = 1; @@ -975,7 +976,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); - sta = ieee80211_find_sta(hw, priv->stations_39[sta_id].sta.sta.addr); + sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index fd65e1c3..46288e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -769,35 +769,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) return ; } -u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr) -{ - int i, start = IWL_AP_ID; - int ret = IWL_INVALID_STATION; - unsigned long flags; - - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || - (priv->iw_mode == NL80211_IFTYPE_AP)) - start = IWL_STA_ID; - - if (is_broadcast_ether_addr(addr)) - return priv->hw_params.bcast_sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - for (i = start; i < priv->hw_params.max_stations; i++) - if ((priv->stations_39[i].used) && - (!compare_ether_addr - (priv->stations_39[i].sta.sta.addr, addr))) { - ret = i; - goto out; - } - - IWL_DEBUG_INFO(priv, "can not find STA %pM (total %d)\n", - addr, priv->num_stations); - out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return ret; -} - /** * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * @@ -875,13 +846,13 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) { unsigned long flags_spin; - struct iwl3945_station_entry *station; + struct iwl_station_entry *station; if (sta_id == IWL_INVALID_STATION) return IWL_INVALID_STATION; spin_lock_irqsave(&priv->sta_lock, flags_spin); - station = &priv->stations_39[sta_id]; + station = &priv->stations[sta_id]; station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; station->sta.rate_n_flags = cpu_to_le16(tx_rate); @@ -889,8 +860,7 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&station->sta, flags); + iwl_send_add_sta(priv, &station->sta, flags); IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n", sta_id, tx_rate); return sta_id; @@ -2029,7 +1999,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ @@ -2040,7 +2010,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) == + if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -2050,9 +2020,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == NL80211_IFTYPE_STATION)) - if (priv->cfg->ops->smgmt->add_station(priv, - priv->active_rxon.bssid_addr, 1, 0, NULL) - == IWL_INVALID_STATION) { + if (iwl_add_station(priv, priv->active_rxon.bssid_addr, + true, CMD_SYNC, NULL) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding AP address for transmit\n"); return -EIO; } @@ -2466,13 +2435,25 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len) } } + static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { - u16 size = (u16)sizeof(struct iwl3945_addsta_cmd); - memcpy(data, cmd, size); - return size; + struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data; + addsta->mode = cmd->mode; + memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify)); + memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo)); + addsta->station_flags = cmd->station_flags; + addsta->station_flags_msk = cmd->station_flags_msk; + addsta->tid_disable_tx = cpu_to_le16(0); + addsta->rate_n_flags = cmd->rate_n_flags; + addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; + addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; + addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; + + return (u16)sizeof(struct iwl3945_addsta_cmd); } + /** * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table */ @@ -2842,15 +2823,6 @@ static struct iwl_lib_ops iwl3945_lib = { .config_ap = iwl3945_config_ap, }; -static struct iwl_station_mgmt_ops iwl3945_station_mgmt = { - .add_station = iwl3945_add_station, -#if 0 - .remove_station = iwl3945_remove_station, -#endif - .find_station = iwl3945_hw_find_station, - .clear_station_table = iwl3945_clear_stations_table, -}; - static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .get_hcmd_size = iwl3945_get_hcmd_size, .build_addsta_hcmd = iwl3945_build_addsta_hcmd, @@ -2860,7 +2832,6 @@ static struct iwl_ops iwl3945_ops = { .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, - .smgmt = &iwl3945_station_mgmt, }; static struct iwl_cfg iwl3945_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index da87528f..4d8a325 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -202,12 +202,6 @@ struct iwl3945_ibss_seq { * for use by iwl-*.c * *****************************************************************************/ -struct iwl3945_addsta_cmd; -extern int iwl3945_send_add_station(struct iwl_priv *priv, - struct iwl3945_addsta_cmd *sta, u8 flags); -extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid, - int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); -extern void iwl3945_clear_stations_table(struct iwl_priv *priv); extern int iwl3945_power_init_handle(struct iwl_priv *priv); extern int iwl3945_eeprom_init(struct iwl_priv *priv); extern int iwl3945_calc_db_from_ratio(int sig_ratio); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a0b2941..8f3d4bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2221,13 +2221,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->txpower_work); } -static struct iwl_station_mgmt_ops iwl4965_station_mgmt = { - .add_station = iwl_add_station_flags, - .remove_station = iwl_remove_station, - .find_station = iwl_find_station, - .clear_station_table = iwl_clear_stations_table, -}; - static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -2297,7 +2290,6 @@ static struct iwl_ops iwl4965_ops = { .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, - .smgmt = &iwl4965_station_mgmt, }; struct iwl_cfg iwl4965_agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ab29aab..b3c648c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -651,7 +651,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv) goto restart; } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, @@ -1049,7 +1049,10 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { u16 size = (u16)sizeof(struct iwl_addsta_cmd); - memcpy(data, cmd, size); + struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; + memcpy(addsta, cmd, size); + /* resrved in 5000 */ + addsta->rate_n_flags = cpu_to_le16(0); return size; } @@ -1423,13 +1426,6 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWL49_RSSI_OFFSET; } -struct iwl_station_mgmt_ops iwl5000_station_mgmt = { - .add_station = iwl_add_station_flags, - .remove_station = iwl_remove_station, - .find_station = iwl_find_station, - .clear_station_table = iwl_clear_stations_table, -}; - struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -1549,14 +1545,12 @@ struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, - .smgmt = &iwl5000_station_mgmt, }; static struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, - .smgmt = &iwl5000_station_mgmt, }; struct iwl_mod_params iwl50_mod_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 7236382..bd438d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -72,7 +72,6 @@ static struct iwl_ops iwl6000_ops = { .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl6000_hcmd_utils, - .smgmt = &iwl5000_station_mgmt, }; struct iwl_cfg iwl6000_2ag_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 23a58b0..2cdd191 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2502,15 +2502,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, - hdr->addr1); + u8 sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); - sta_id = priv->cfg->ops->smgmt->add_station(priv, - hdr->addr1, 0, - CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, + false, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2598,7 +2596,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, + u8 sta_id = iwl_find_station(priv, sta->addr); /* for IBSS the call are from tasklet */ @@ -2606,9 +2604,8 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); - sta_id = priv->cfg->ops->smgmt->add_station(priv, - sta->addr, 0, - CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, sta->addr, false, + CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0a5507c..e6ecb3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -188,7 +188,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); priv->start_calib = 0; @@ -1617,7 +1617,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, @@ -1703,7 +1703,7 @@ static void __iwl_down(struct iwl_priv *priv) iwl_leds_unregister(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -1903,7 +1903,7 @@ static int __iwl_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -2348,7 +2348,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } addr = sta ? sta->addr : iwl_bcast_addr; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -3121,7 +3121,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_rx_queue_free(priv, &priv->rxq); iwl_hw_txq_ctx_free(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); iwl_eeprom_free(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e581dc3..b3229f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1067,7 +1067,7 @@ struct iwl_addsta_cmd { * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ __le16 tid_disable_tx; - __le16 reserved1; + __le16 rate_n_flags; /* 3945 only */ /* TID for which to add block-ack support. * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ddd2219..51cae4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1389,7 +1389,7 @@ int iwl_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -2680,7 +2680,7 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* dont commit rxon if rf-kill is on*/ if (!iwl_is_ready_rf(priv)) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 87df1b7..4173a40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -83,15 +83,6 @@ struct iwl_cmd; #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 -struct iwl_station_mgmt_ops { - u8 (*add_station)(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); - int (*remove_station)(struct iwl_priv *priv, const u8 *addr, - int is_ap); - u8 (*find_station)(struct iwl_priv *priv, const u8 *addr); - void (*clear_station_table)(struct iwl_priv *priv); -}; - struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); @@ -183,7 +174,6 @@ struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; - const struct iwl_station_mgmt_ops *smgmt; }; struct iwl_mod_params { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2dafc26..28c39cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -70,7 +70,6 @@ extern struct iwl_ops iwl5000_ops; extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_hcmd_ops iwl5000_hcmd; extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; -extern struct iwl_station_mgmt_ops iwl5000_station_mgmt; /* shared functions from iwl-5000.c */ extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len); @@ -290,11 +289,11 @@ struct iwl_frame { #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) enum { - /* CMD_SIZE_NORMAL = 0, */ + CMD_SYNC = 0, + CMD_SIZE_NORMAL = 0, + CMD_NO_SKB = 0, CMD_SIZE_HUGE = (1 << 0), - /* CMD_SYNC = 0, */ CMD_ASYNC = (1 << 1), - /* CMD_NO_SKB = 0, */ CMD_WANT_SKB = (1 << 2), }; @@ -1119,8 +1118,6 @@ struct iwl_priv { struct iwl3945_notif_statistics statistics_39; - struct iwl3945_station_entry stations_39[IWL_STATION_COUNT]; - u32 sta_supp_rates; }; /*iwl_priv */ diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 0eb939c..5ea3bc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) return IWL_AP_ID; } else { u8 *da = ieee80211_get_DA(hdr); - return priv->cfg->ops->smgmt->find_station(priv, da); + return iwl_find_station(priv, da); } } EXPORT_SYMBOL(iwl_get_ra_sta_id); @@ -86,8 +86,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) spin_lock_irqsave(&priv->sta_lock, flags); - if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && - !(priv->stations_39[sta_id].used & IWL_STA_DRIVER_ACTIVE)) + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n", sta_id); @@ -228,15 +227,16 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, } /** - * iwl_add_station_flags - Add station to tables in driver and device + * iwl_add_station - Add station to tables in driver and device */ -u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_sta_ht_cap *ht_info) +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, + struct ieee80211_sta_ht_cap *ht_info) { - int i; - int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; + int i; + int sta_id = IWL_INVALID_STATION; + u16 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -288,6 +288,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, priv->iw_mode != NL80211_IFTYPE_ADHOC) iwl_set_ht_add_station(priv, sta_id, ht_info); + /* 3945 only */ + rate = (priv->band == IEEE80211_BAND_5GHZ) ? + IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; + /* Turn on both antennas for the station... */ + station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); /* Add station to device's station table */ @@ -295,12 +301,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, return sta_id; } -EXPORT_SYMBOL(iwl_add_station_flags); +EXPORT_SYMBOL(iwl_add_station); static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + u8 sta_id = iwl_find_station(priv, addr); BUG_ON(sta_id == IWL_INVALID_STATION); @@ -408,7 +414,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, /** * iwl_remove_station - Remove driver's knowledge of station. */ -int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) { int sta_id = IWL_INVALID_STATION; int i, ret = -EINVAL; @@ -767,7 +773,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, unsigned long flags; int i; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -946,7 +952,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd); * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, * which requires station table entry to exist). */ -static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) +static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) { int i, r; struct iwl_link_quality_cmd link_cmd = { @@ -995,7 +1001,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) * there is only one AP station with id= IWL_AP_ID * NOTE: mutex must be held before calling this function */ -int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) { struct ieee80211_sta *sta; struct ieee80211_sta_ht_cap ht_config; @@ -1020,8 +1026,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rcu_read_unlock(); } - sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap, - 0, cur_ht_config); + sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); /* Set up default rate scaling table in device's station table */ iwl_sta_init_lq(priv, addr, is_ap); @@ -1054,7 +1059,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If we are an AP, then find the station, or use BCAST */ case NL80211_IFTYPE_AP: - sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); + sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; return priv->hw_params.bcast_sta_id; @@ -1062,13 +1067,13 @@ 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 NL80211_IFTYPE_ADHOC: - sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); + sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; /* Create new station table entry */ - sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, false, + CMD_ASYNC, NULL); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -1111,7 +1116,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, unsigned long flags; int sta_id; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -1133,7 +1138,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) unsigned long flags; int sta_id; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); return -ENXIO; @@ -1168,7 +1173,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) { /* FIXME: need locking over ps_status ??? */ - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + u8 sta_id = iwl_find_station(priv, addr); if (sta_id != IWL_INVALID_STATION) { u8 sta_awake = priv->stations[sta_id]. diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 59a586b..6deebad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -51,16 +51,15 @@ void iwl_update_tkip_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key); -int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); -int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); 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, +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); int iwl_sta_rx_agg_start(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5c10b87..745eaae 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -95,144 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = { /* the rest are 0 by default */ }; -/*************** STATION TABLE MANAGEMENT **** - * mac80211 should be examined to determine if sta_info is duplicating - * the functionality provided here - */ - -/**************************************************************/ -#if 0 /* temporary disable till we add real remove station */ -/** - * iwl3945_remove_station - Remove driver's knowledge of station. - * - * NOTE: This does not remove station from device's station table. - */ -static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int index = IWL_INVALID_STATION; - int i; - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) - if (priv->stations_39[i].used && - !compare_ether_addr(priv->stations_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (unlikely(index == IWL_INVALID_STATION)) - goto out; - - if (priv->stations_39[index].used) { - priv->stations_39[index].used = 0; - priv->num_stations--; - } - - BUG_ON(priv->num_stations < 0); - -out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; -} -#endif - -/** - * iwl3945_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -void iwl3945_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->num_stations = 0; - memset(priv->stations_39, 0, sizeof(priv->stations_39)); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -/** - * iwl3945_add_station - Add station to station tables in driver and device - */ -u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info) -{ - int i; - int index = IWL_INVALID_STATION; - struct iwl3945_station_entry *station; - unsigned long flags_spin; - u8 rate; - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { - if (!compare_ether_addr(priv->stations_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (!priv->stations_39[i].used && - index == IWL_INVALID_STATION) - index = i; - } - - /* These two conditions has the same outcome but keep them separate - since they have different meaning */ - if (unlikely(index == IWL_INVALID_STATION)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - if (priv->stations_39[index].used && - !compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr); - station = &priv->stations_39[index]; - station->used = 1; - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd)); - memcpy(station->sta.sta.addr, addr, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = index; - station->sta.station_flags = 0; - - if (priv->band == IEEE80211_BAND_5GHZ) - rate = IWL_RATE_6M_PLCP; - else - rate = IWL_RATE_1M_PLCP; - - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = - iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&station->sta, flags); - return index; - -} - /** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags @@ -289,32 +151,31 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, key_flags &= ~STA_KEY_FLG_INVALID; spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations_39[sta_id].keyinfo.alg = keyconf->alg; - priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen; - memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key, + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, keyconf->keylen); - memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key, + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); - if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) == STA_KEY_FLG_NO_ENC) - priv->stations_39[sta_id].sta.key.key_offset = + priv->stations[sta_id].sta.key.key_offset = iwl_get_free_ucode_key_index(priv); /* else, we are overriding an existing key => no need to allocated room * in uCode. */ - WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, "no space for a new key"); - priv->stations_39[sta_id].sta.key.key_flags = key_flags; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n"); - ret = iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -340,17 +201,16 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); - memset(&priv->stations_39[sta_id].sta.key, 0, + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); - priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n"); - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); return 0; } @@ -578,7 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, int sta_id) { struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo; + struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -753,7 +613,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - seq_number = priv->stations_39[sta_id].tid[tid].seq_number & + seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | (hdr->seq_ctrl & @@ -813,7 +673,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; if (qc) - priv->stations_39[sta_id].tid[tid].seq_number = seq_number; + priv->stations[sta_id].tid[tid].seq_number = seq_number; } else { wait_write_ptr = 1; txq->need_update = 0; @@ -2589,7 +2449,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) goto restart; } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); @@ -2681,7 +2541,7 @@ static void __iwl3945_down(struct iwl_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); iwl3945_led_unregister(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -2833,7 +2693,7 @@ static int __iwl3945_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -3247,7 +3107,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) case NL80211_IFTYPE_ADHOC: priv->assoc_id = 1; - priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL); + iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -3438,7 +3298,7 @@ void iwl3945_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); - priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL); + iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL); } iwl3945_send_beacon_cmd(priv); @@ -3469,7 +3329,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static_key = !iwl_is_associated(priv); if (!static_key) { - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -4044,7 +3904,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -4407,7 +4267,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_hw_txq_ctx_free(priv); iwl3945_unset_hw_params(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); -- cgit v0.10.2 From d14d44407b9f06e3cf967fcef28ccb780caf0583 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Jun 2009 11:44:08 -0700 Subject: iwl3945: port allow skb allocation in tasklet patch Port "iwlcore: Allow skb allocation from tasklet." to 3945 If RX queue becomes empty then we need to restock the queue from tasklet to prevent ucode from starving. A caller to iwl_rx_allocate will decide if allocated buffer should come from GFP_ATOMIC or GFP_KERNEL. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 745eaae..92fa1a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1176,7 +1176,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) + if ((rxq->write_actual != (rxq->write & ~0x7)) || (abs(rxq->write - rxq->read) > 7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; @@ -1197,7 +1197,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) * Also restock the Rx queue via iwl3945_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -static void iwl3945_rx_allocate(struct iwl_priv *priv) +static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; @@ -1220,7 +1220,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size, - GFP_KERNEL); + priority); if (!rxb->skb) { if (net_ratelimit()) IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); @@ -1279,6 +1279,7 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; rxq->free_count = 0; + rxq->write_actual = 0; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -1287,13 +1288,21 @@ void iwl3945_rx_replenish(void *data) struct iwl_priv *priv = data; unsigned long flags; - iwl3945_rx_allocate(priv); + iwl3945_rx_allocate(priv, GFP_KERNEL); spin_lock_irqsave(&priv->lock, flags); iwl3945_rx_queue_restock(priv); spin_unlock_irqrestore(&priv->lock, flags); } +static void iwl3945_rx_replenish_now(struct iwl_priv *priv) +{ + iwl3945_rx_allocate(priv, GFP_ATOMIC); + + iwl3945_rx_queue_restock(priv); +} + + /* Assumes that the skb field of the buffers in 'pool' is kept accurate. * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to @@ -1416,13 +1425,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) unsigned long flags; u8 fill_rx = 0; u32 count = 8; + int total_empty = 0; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; i = rxq->read; - if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + /* calculate total frames need to be restock after handling RX */ + total_empty = r - priv->rxq.write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) @@ -1499,7 +1514,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - iwl3945_rx_queue_restock(priv); + iwl3945_rx_replenish_now(priv); count = 0; } } @@ -1507,7 +1522,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl3945_rx_queue_restock(priv); + if (fill_rx) + iwl3945_rx_replenish_now(priv); + else + iwl3945_rx_queue_restock(priv); } /* call this function to flush any scheduled tasklet */ -- cgit v0.10.2 From ee5006a19c9e040d715efb75a6f4fa78764869ce Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Jun 2009 11:44:09 -0700 Subject: iwl3945/iwlwifi: fix led bug when SW rfkill Patch fixes the bug at http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1903 when SW rfkill is invoked by 'iwconfig txpower off', the existing connection disassociates and led off command is sent to the device which returns error as rfkill is 'true'. Patch fixes this by just avoiding sending the led off/on command when disassociated. The main purpose of the led_disassociate callback is to start or stop the blinking. There are three states in led 1) Always on when radio is on 2) Always off when radio is off 3) blink when associated and if there is some traffic. In this callback 'allow_blinking' needs to be set false when associated, as LED will be always on. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index bd7e520..225e5f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -167,10 +167,6 @@ static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) IWL_DEBUG_LED(priv, "Disassociated\n"); priv->allow_blinking = 0; - if (iwl_is_rfkill(priv)) - iwl3945_led_off(priv, led_id); - else - iwl3945_led_on(priv, led_id); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 19680f7..5e64252 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -176,10 +176,6 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id) static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) { priv->allow_blinking = 0; - if (iwl_is_rfkill(priv)) - iwl4965_led_off_reg(priv, led_id); - else - iwl4965_led_on_reg(priv, led_id); return 0; } -- cgit v0.10.2 From 258c44a0c02a7ffbb9555747008d6bf9a3ea58a0 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Wed, 3 Jun 2009 11:44:10 -0700 Subject: iwlagn: delay ict interrupt. Wait until ucode is loaded and driver receive ALIVE_REPLY then switch to ICT interrupt. This ensures we receive all interrupts indicating successful ucode load. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e6ecb3f..b77208d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1887,8 +1887,6 @@ static int __iwl_up(struct iwl_priv *priv) /* clear (again), then enable host interrupts */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - /* enable dram interrupt */ - iwl_reset_ict(priv); iwl_enable_interrupts(priv); /* really make sure rfkill handshake bits are cleared */ @@ -1962,6 +1960,9 @@ static void iwl_bg_alive_start(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + /* enable dram interrupt */ + iwl_reset_ict(priv); + mutex_lock(&priv->mutex); iwl_alive_start(priv); mutex_unlock(&priv->mutex); -- cgit v0.10.2 From 13c33a09b3703c2956345482017600434c853889 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 3 Jun 2009 11:44:11 -0700 Subject: iwlwifi: add value and range define for link quality command Instead of hardcoding the link quality parameters inside the functions, adding #define in iwl-commands.h to shared by different functions. Also include the valid range for number of link quality parameters. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 2cdd191..ff20e504 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2787,9 +2787,10 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, repeat_rate--; } - lq_cmd->agg_params.agg_frame_cnt_limit = 64; - lq_cmd->agg_params.agg_dis_start_th = 3; - lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); + lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX; + lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + lq_cmd->agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); } static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index b3229f2..c87033b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1913,6 +1913,18 @@ struct iwl_link_qual_general_params { u8 start_rate_index[LINK_QUAL_AC_NUM]; } __attribute__ ((packed)); +#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ +#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535) +#define LINK_QUAL_AGG_TIME_LIMIT_MIN (0) + +#define LINK_QUAL_AGG_DISABLE_START_DEF (3) +#define LINK_QUAL_AGG_DISABLE_START_MAX (255) +#define LINK_QUAL_AGG_DISABLE_START_MIN (0) + +#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) +#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64) +#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) + /** * struct iwl_link_qual_agg_params * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 5ea3bc7..2addf73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -985,8 +985,9 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) link_cmd.general_params.single_stream_ant_msk = first_antenna(priv->hw_params.valid_tx_ant); link_cmd.general_params.dual_stream_ant_msk = 3; - link_cmd.agg_params.agg_dis_start_th = 3; - link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); + link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd.agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); /* Update the rate scaling for control frame Tx to AP */ link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; -- cgit v0.10.2 From c18bd87b65fa5f39abb0ab1b82bca416c23cb6dd Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Wed, 3 Jun 2009 11:44:12 -0700 Subject: iwlwifi: fix comment describing disable_11n Fixing a comment in the code describing this module parameter. The description printed when user runs "modinfo" is correct. Reported-by: Jiajia Zheng Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4173a40..b52d0fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -182,7 +182,7 @@ struct iwl_mod_params { int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ - int disable_11n; /* def: 0 = disable 11n capabilities */ + int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ -- cgit v0.10.2 From 2489e4ea6cfd1c0f3fe839f90363abccbbdb7745 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 3 Jun 2009 22:24:48 +0200 Subject: ar9170: remove deprecated code This patch removes code (deprecated by "cfg80211: add rfkill support" ) main.c: In function 'ar9170_op_config': main.c:1306: warning: '__IEEE80211_CONF_CHANGE_RADIO_ENABLED' is deprecated (declared at include/net/mac80211.h:551) and a useless device state. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 4c4b08f..c7cba66 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -102,7 +102,6 @@ enum ar9170_device_state { AR9170_STOPPED, AR9170_IDLE, AR9170_STARTED, - AR9170_ASSOCIATED, }; struct ar9170_rxstream_mpdu_merge { diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index b889fda..b104d7e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1303,11 +1303,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&ar->mutex); - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - /* TODO */ - err = 0; - } - if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* TODO */ err = 0; @@ -1490,8 +1485,6 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; - #ifndef CONFIG_AR9170_LEDS /* enable assoc LED. */ err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); -- cgit v0.10.2 From 0c0c9e7076b69f93678e4ec711e2bf237398e623 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 Jun 2009 08:22:25 +0200 Subject: wimax: depend on rfkill properly My mistake, I should have added that when cleaning up rfkill and changing wimax. Reported-by: Randy Dunlap Signed-off-by: Johannes Berg Acked-by: Inaky Perez-Gonzalez Signed-off-by: John W. Linville diff --git a/net/wimax/Kconfig b/net/wimax/Kconfig index 0bdbb69..e4d97ab 100644 --- a/net/wimax/Kconfig +++ b/net/wimax/Kconfig @@ -4,6 +4,7 @@ menuconfig WIMAX tristate "WiMAX Wireless Broadband support" + depends on RFKILL || !RFKILL help Select to configure support for devices that provide -- cgit v0.10.2 From 61f5abcab152cbee3a041f8b9bcfe7afc83409ca Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 5 Jun 2009 13:18:07 +0200 Subject: netfilter: xt_NFQUEUE: use NFPROTO_UNSPEC We can use wildcard matching here, just like ab4f21e6fb1c09b13c4c3cb8357babe8223471bd ("xtables: use NFPROTO_UNSPEC in more extensions"). Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index f9977b3..6e0f84d 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c @@ -34,21 +34,7 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) static struct xt_target nfqueue_tg_reg[] __read_mostly = { { .name = "NFQUEUE", - .family = NFPROTO_IPV4, - .target = nfqueue_tg, - .targetsize = sizeof(struct xt_NFQ_info), - .me = THIS_MODULE, - }, - { - .name = "NFQUEUE", - .family = NFPROTO_IPV6, - .target = nfqueue_tg, - .targetsize = sizeof(struct xt_NFQ_info), - .me = THIS_MODULE, - }, - { - .name = "NFQUEUE", - .family = NFPROTO_ARP, + .family = NFPROTO_UNSPEC, .target = nfqueue_tg, .targetsize = sizeof(struct xt_NFQ_info), .me = THIS_MODULE, -- cgit v0.10.2 From 10662aa3083f869c645cc2abf5d66849001e2f5d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 5 Jun 2009 13:24:24 +0200 Subject: netfilter: xt_NFQUEUE: queue balancing support Adds support for specifying a range of queues instead of a single queue id. Flows will be distributed across the given range. This is useful for multicore systems: Instead of having a single application read packets from a queue, start multiple instances on queues x, x+1, .. x+n. Each instance can process flows independently. Packets for the same connection are put into the same queue. Signed-off-by: Holger Eitzenberger Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/xt_NFQUEUE.h b/include/linux/netfilter/xt_NFQUEUE.h index 982a89f..2584f4a 100644 --- a/include/linux/netfilter/xt_NFQUEUE.h +++ b/include/linux/netfilter/xt_NFQUEUE.h @@ -15,4 +15,9 @@ struct xt_NFQ_info { __u16 queuenum; }; +struct xt_NFQ_info_v1 { + __u16 queuenum; + __u16 queues_total; +}; + #endif /* _XT_NFQ_TARGET_H */ diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index 6e0f84d..498b451 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c @@ -11,6 +11,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -23,6 +27,8 @@ MODULE_ALIAS("ipt_NFQUEUE"); MODULE_ALIAS("ip6t_NFQUEUE"); MODULE_ALIAS("arpt_NFQUEUE"); +static u32 jhash_initval __read_mostly; + static unsigned int nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) { @@ -31,6 +37,72 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) return NF_QUEUE_NR(tinfo->queuenum); } +static u32 hash_v4(const struct sk_buff *skb) +{ + const struct iphdr *iph = ip_hdr(skb); + u32 ipaddr; + + /* packets in either direction go into same queue */ + ipaddr = iph->saddr ^ iph->daddr; + + return jhash_2words(ipaddr, iph->protocol, jhash_initval); +} + +static unsigned int +nfqueue_tg4_v1(struct sk_buff *skb, const struct xt_target_param *par) +{ + const struct xt_NFQ_info_v1 *info = par->targinfo; + u32 queue = info->queuenum; + + if (info->queues_total > 1) + queue = hash_v4(skb) % info->queues_total + queue; + return NF_QUEUE_NR(queue); +} + +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) +static u32 hash_v6(const struct sk_buff *skb) +{ + const struct ipv6hdr *ip6h = ipv6_hdr(skb); + u32 addr[4]; + + addr[0] = ip6h->saddr.s6_addr32[0] ^ ip6h->daddr.s6_addr32[0]; + addr[1] = ip6h->saddr.s6_addr32[1] ^ ip6h->daddr.s6_addr32[1]; + addr[2] = ip6h->saddr.s6_addr32[2] ^ ip6h->daddr.s6_addr32[2]; + addr[3] = ip6h->saddr.s6_addr32[3] ^ ip6h->daddr.s6_addr32[3]; + + return jhash2(addr, ARRAY_SIZE(addr), jhash_initval); +} + +static unsigned int +nfqueue_tg6_v1(struct sk_buff *skb, const struct xt_target_param *par) +{ + const struct xt_NFQ_info_v1 *info = par->targinfo; + u32 queue = info->queuenum; + + if (info->queues_total > 1) + queue = hash_v6(skb) % info->queues_total + queue; + return NF_QUEUE_NR(queue); +} +#endif + +static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par) +{ + const struct xt_NFQ_info_v1 *info = par->targinfo; + u32 maxid; + + if (info->queues_total == 0) { + pr_err("NFQUEUE: number of total queues is 0\n"); + return false; + } + maxid = info->queues_total - 1 + info->queuenum; + if (maxid > 0xffff) { + pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n", + info->queues_total, maxid); + return false; + } + return true; +} + static struct xt_target nfqueue_tg_reg[] __read_mostly = { { .name = "NFQUEUE", @@ -39,10 +111,31 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = { .targetsize = sizeof(struct xt_NFQ_info), .me = THIS_MODULE, }, + { + .name = "NFQUEUE", + .revision = 1, + .family = NFPROTO_IPV4, + .checkentry = nfqueue_tg_v1_check, + .target = nfqueue_tg4_v1, + .targetsize = sizeof(struct xt_NFQ_info_v1), + .me = THIS_MODULE, + }, +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) + { + .name = "NFQUEUE", + .revision = 1, + .family = NFPROTO_IPV6, + .checkentry = nfqueue_tg_v1_check, + .target = nfqueue_tg6_v1, + .targetsize = sizeof(struct xt_NFQ_info_v1), + .me = THIS_MODULE, + }, +#endif }; static int __init nfqueue_tg_init(void) { + get_random_bytes(&jhash_initval, sizeof(jhash_initval)); return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); } -- cgit v0.10.2 From 17f2f52be0edb6d1ff5a3675f2bc545aea2dbf76 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 5 Jun 2009 13:26:21 +0200 Subject: netfilter: ipt_MASQUERADE: remove redundant rwlock The lock "protects" an assignment and a comparision of an integer. When the caller of device_cmp() evaluates the result, nat->masq_index may already have been changed (regardless if the lock is there or not). So, the lock either has to be held during nf_ct_iterate_cleanup(), or can be removed. This does the latter. Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index f389f60..855505d 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -27,9 +27,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("Xtables: automatic-address SNAT"); -/* Lock protects masq region inside conntrack */ -static DEFINE_RWLOCK(masq_lock); - /* FIXME: Multiple targets. --RR */ static bool masquerade_tg_check(const struct xt_tgchk_param *par) { @@ -79,9 +76,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par) return NF_DROP; } - write_lock_bh(&masq_lock); nat->masq_index = par->out->ifindex; - write_unlock_bh(&masq_lock); /* Transfer from original range. */ newrange = ((struct nf_nat_range) @@ -97,16 +92,11 @@ static int device_cmp(struct nf_conn *i, void *ifindex) { const struct nf_conn_nat *nat = nfct_nat(i); - int ret; if (!nat) return 0; - read_lock_bh(&masq_lock); - ret = (nat->masq_index == (int)(long)ifindex); - read_unlock_bh(&masq_lock); - - return ret; + return nat->masq_index == (int)(long)ifindex; } static int masq_device_event(struct notifier_block *this, -- cgit v0.10.2 From 3c2e1c11d9126d765ab40207150cb6f9869637f1 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Wed, 3 Jun 2009 15:05:17 +0000 Subject: forcedeth: remove device id macros This patch removes the device id macros and instead uses the constants directly. The areas in which logic expressions where using the macros now instead use feature/workaround flags. No new functionality has been introduced in this patch, only clean up of flags and macros. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 1dce555..1409b45 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -77,27 +77,31 @@ * Hardware access: */ -#define DEV_NEED_TIMERIRQ 0x000001 /* set the timer irq flag in the irq mask */ -#define DEV_NEED_LINKTIMER 0x000002 /* poll link settings. Relies on the timer irq */ -#define DEV_HAS_LARGEDESC 0x000004 /* device supports jumbo frames and needs packet format 2 */ -#define DEV_HAS_HIGH_DMA 0x000008 /* device supports 64bit dma */ -#define DEV_HAS_CHECKSUM 0x000010 /* device supports tx and rx checksum offloads */ -#define DEV_HAS_VLAN 0x000020 /* device supports vlan tagging and striping */ -#define DEV_HAS_MSI 0x000040 /* device supports MSI */ -#define DEV_HAS_MSI_X 0x000080 /* device supports MSI-X */ -#define DEV_HAS_POWER_CNTRL 0x000100 /* device supports power savings */ -#define DEV_HAS_STATISTICS_V1 0x000200 /* device supports hw statistics version 1 */ -#define DEV_HAS_STATISTICS_V2 0x000600 /* device supports hw statistics version 2 */ -#define DEV_HAS_STATISTICS_V3 0x000e00 /* device supports hw statistics version 3 */ -#define DEV_HAS_TEST_EXTENDED 0x001000 /* device supports extended diagnostic test */ -#define DEV_HAS_MGMT_UNIT 0x002000 /* device supports management unit */ -#define DEV_HAS_CORRECT_MACADDR 0x004000 /* device supports correct mac address order */ -#define DEV_HAS_COLLISION_FIX 0x008000 /* device supports tx collision fix */ -#define DEV_HAS_PAUSEFRAME_TX_V1 0x010000 /* device supports tx pause frames version 1 */ -#define DEV_HAS_PAUSEFRAME_TX_V2 0x020000 /* device supports tx pause frames version 2 */ -#define DEV_HAS_PAUSEFRAME_TX_V3 0x040000 /* device supports tx pause frames version 3 */ -#define DEV_NEED_TX_LIMIT 0x080000 /* device needs to limit tx */ -#define DEV_HAS_GEAR_MODE 0x100000 /* device supports gear mode */ +#define DEV_NEED_TIMERIRQ 0x0000001 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0000002 /* poll link settings. Relies on the timer irq */ +#define DEV_HAS_LARGEDESC 0x0000004 /* device supports jumbo frames and needs packet format 2 */ +#define DEV_HAS_HIGH_DMA 0x0000008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x0000010 /* device supports tx and rx checksum offloads */ +#define DEV_HAS_VLAN 0x0000020 /* device supports vlan tagging and striping */ +#define DEV_HAS_MSI 0x0000040 /* device supports MSI */ +#define DEV_HAS_MSI_X 0x0000080 /* device supports MSI-X */ +#define DEV_HAS_POWER_CNTRL 0x0000100 /* device supports power savings */ +#define DEV_HAS_STATISTICS_V1 0x0000200 /* device supports hw statistics version 1 */ +#define DEV_HAS_STATISTICS_V2 0x0000600 /* device supports hw statistics version 2 */ +#define DEV_HAS_STATISTICS_V3 0x0000e00 /* device supports hw statistics version 3 */ +#define DEV_HAS_TEST_EXTENDED 0x0001000 /* device supports extended diagnostic test */ +#define DEV_HAS_MGMT_UNIT 0x0002000 /* device supports management unit */ +#define DEV_HAS_CORRECT_MACADDR 0x0004000 /* device supports correct mac address order */ +#define DEV_HAS_COLLISION_FIX 0x0008000 /* device supports tx collision fix */ +#define DEV_HAS_PAUSEFRAME_TX_V1 0x0010000 /* device supports tx pause frames version 1 */ +#define DEV_HAS_PAUSEFRAME_TX_V2 0x0020000 /* device supports tx pause frames version 2 */ +#define DEV_HAS_PAUSEFRAME_TX_V3 0x0040000 /* device supports tx pause frames version 3 */ +#define DEV_NEED_TX_LIMIT 0x0080000 /* device needs to limit tx */ +#define DEV_NEED_TX_LIMIT2 0x0180000 /* device needs to limit tx, expect for some revs */ +#define DEV_HAS_GEAR_MODE 0x0200000 /* device supports gear mode */ +#define DEV_NEED_PHY_INIT_FIX 0x0400000 /* device needs specific phy workaround */ +#define DEV_NEED_LOW_POWER_FIX 0x0800000 /* device needs special power up workaround */ +#define DEV_NEED_MSI_FIX 0x1000000 /* device needs msi workaround */ enum { NvRegIrqStatus = 0x000, @@ -1271,14 +1275,7 @@ static int phy_init(struct net_device *dev) } } if (np->phy_model == PHY_MODEL_REALTEK_8201) { - if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { + if (np->driver_data & DEV_NEED_PHY_INIT_FIX) { phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); phy_reserved |= PHY_REALTEK_INIT7; if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { @@ -1469,14 +1466,7 @@ static int phy_init(struct net_device *dev) } } if (np->phy_model == PHY_MODEL_REALTEK_8201) { - if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { + if (np->driver_data & DEV_NEED_PHY_INIT_FIX) { phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); phy_reserved |= PHY_REALTEK_INIT7; if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { @@ -5844,8 +5834,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i /* take phy and nic out of low power mode */ powerstate = readl(base + NvRegPowerState2); powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK; - if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) && + if ((id->driver_data & DEV_NEED_LOW_POWER_FIX) && pci_dev->revision >= 0xA3) powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3; writel(powerstate, base + NvRegPowerState2); @@ -5901,14 +5890,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i /* Limit the number of tx's outstanding for hw bug */ if (id->driver_data & DEV_NEED_TX_LIMIT) { np->tx_limit = 1; - if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_39) && + if ((id->driver_data & DEV_NEED_TX_LIMIT2) && pci_dev->revision >= 0xA2) np->tx_limit = 0; } @@ -6158,7 +6140,8 @@ static int nv_resume(struct pci_dev *pdev) for (i = 0;i <= np->register_size/sizeof(u32); i++) writel(np->saved_config_space[i], base+i*sizeof(u32)); - pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE); + if (np->driver_data & DEV_NEED_MSI_FIX) + pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE); /* restore phy state, including autoneg */ phy_init(dev); @@ -6207,160 +6190,160 @@ static void nv_shutdown(struct pci_dev *pdev) static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1), + PCI_DEVICE(0x10DE, 0x01C3), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2), + PCI_DEVICE(0x10DE, 0x0066), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3), + PCI_DEVICE(0x10DE, 0x00D6), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), + PCI_DEVICE(0x10DE, 0x0086), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), + PCI_DEVICE(0x10DE, 0x008C), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), + PCI_DEVICE(0x10DE, 0x00E6), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), + PCI_DEVICE(0x10DE, 0x00DF), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* CK804 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), + PCI_DEVICE(0x10DE, 0x0056), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* CK804 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), + PCI_DEVICE(0x10DE, 0x0057), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), + PCI_DEVICE(0x10DE, 0x0037), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), + PCI_DEVICE(0x10DE, 0x0038), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP51 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + PCI_DEVICE(0x10DE, 0x0268), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX, }, { /* MCP51 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + PCI_DEVICE(0x10DE, 0x0269), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX, }, { /* MCP55 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + PCI_DEVICE(0x10DE, 0x0372), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX, }, { /* MCP55 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + PCI_DEVICE(0x10DE, 0x0373), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03E5), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03E6), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03EE), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03EF), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0450), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0451), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0452), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0453), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054C), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054D), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054E), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054F), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DC), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DD), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DE), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DF), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0760), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0761), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0762), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0763), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB0), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB1), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB2), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB3), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, {0,}, }; -- cgit v0.10.2 From 3df81c4e950a7e38a8ef98f818abc3eed76b3fb2 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Wed, 3 Jun 2009 15:05:35 +0000 Subject: forcedeth: addition of new mcp89 device id This patch adds a new device id for mcp89 chipset. Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 1409b45..b60a304 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -6345,6 +6345,10 @@ static struct pci_device_id pci_tbl[] = { PCI_DEVICE(0x10DE, 0x0AB3), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, + { /* MCP89 Ethernet Controller */ + PCI_DEVICE(0x10DE, 0x0D7D), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX, + }, {0,}, }; -- cgit v0.10.2 From a93958ac980f0ce594ad90657ecbc595ff157a40 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sun, 7 Jun 2009 03:54:37 -0700 Subject: removal of forcedeth device ids This patch removes the forcedeth device ids from pci_ids.h The forcedeth driver uses the device id constants directly in its source file. [ Need to keep PCI_DEVICE_ID_NVIDIA_NVENET_15 in order to keep drivers/pci/quirks.c building -DaveM ] Signed-off-by: Ayaz Abdulla Signed-off-by: David S. Miller diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 12db06c..b87c51a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1066,8 +1066,6 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036 -#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037 -#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e #define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800 0x0041 @@ -1078,21 +1076,16 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 -#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056 -#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057 #define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 #define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d #define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 -#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066 #define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069 #define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 -#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086 #define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089 #define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a -#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e #define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT 0x0090 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX 0x0091 @@ -1108,15 +1101,12 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 -#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6 #define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9 #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da -#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df #define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 -#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6 #define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0 @@ -1176,7 +1166,6 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc #define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1 -#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3 #define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 @@ -1199,8 +1188,6 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F -#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268 -#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282 @@ -1247,46 +1234,21 @@ #define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E -#define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372 #define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 -#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5 -#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC -#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE -#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448 -#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450 -#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 -#define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452 -#define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS 0x0542 -#define PCI_DEVICE_ID_NVIDIA_NVENET_24 0x054C -#define PCI_DEVICE_ID_NVIDIA_NVENET_25 0x054D -#define PCI_DEVICE_ID_NVIDIA_NVENET_26 0x054E -#define PCI_DEVICE_ID_NVIDIA_NVENET_27 0x054F -#define PCI_DEVICE_ID_NVIDIA_NVENET_28 0x07DC -#define PCI_DEVICE_ID_NVIDIA_NVENET_29 0x07DD -#define PCI_DEVICE_ID_NVIDIA_NVENET_30 0x07DE -#define PCI_DEVICE_ID_NVIDIA_NVENET_31 0x07DF #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE 0x056C #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS 0x0752 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE 0x0759 -#define PCI_DEVICE_ID_NVIDIA_NVENET_32 0x0760 -#define PCI_DEVICE_ID_NVIDIA_NVENET_33 0x0761 -#define PCI_DEVICE_ID_NVIDIA_NVENET_34 0x0762 -#define PCI_DEVICE_ID_NVIDIA_NVENET_35 0x0763 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS 0x07D8 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS 0x0AA2 -#define PCI_DEVICE_ID_NVIDIA_NVENET_36 0x0AB0 -#define PCI_DEVICE_ID_NVIDIA_NVENET_37 0x0AB1 -#define PCI_DEVICE_ID_NVIDIA_NVENET_38 0x0AB2 -#define PCI_DEVICE_ID_NVIDIA_NVENET_39 0x0AB3 #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_TT128 0x9128 -- cgit v0.10.2 From 7d217d7ffc3433d8b157e1fb6c68a07197a182d5 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Sun, 7 Jun 2009 05:01:00 -0700 Subject: cfg80211: errno.h: define ERFKILL Commit 1f87f7d3 (cfg80211: add rfkill support) added ERFKILL to asm-generic/errno.h, but alpha, mips, parisc and sparc use their own numbering scheme and do not include asm-generic/errno.h. We need to add definition of ERFKILL for them. Signed-off-by: Alexander Beregalov Acked-by: Ralf Baechle Acked-by: Kyle McMartin Signed-off-by: David S. Miller diff --git a/arch/alpha/include/asm/errno.h b/arch/alpha/include/asm/errno.h index 69e2655..98099bd 100644 --- a/arch/alpha/include/asm/errno.h +++ b/arch/alpha/include/asm/errno.h @@ -120,4 +120,6 @@ #define EOWNERDEAD 136 /* Owner died */ #define ENOTRECOVERABLE 137 /* State not recoverable */ +#define ERFKILL 138 /* Operation not possible due to RF-kill */ + #endif diff --git a/arch/mips/include/asm/errno.h b/arch/mips/include/asm/errno.h index 3c0d840..a0efc73 100644 --- a/arch/mips/include/asm/errno.h +++ b/arch/mips/include/asm/errno.h @@ -119,6 +119,8 @@ #define EOWNERDEAD 165 /* Owner died */ #define ENOTRECOVERABLE 166 /* State not recoverable */ +#define ERFKILL 167 /* Operation not possible due to RF-kill */ + #define EDQUOT 1133 /* Quota exceeded */ #ifdef __KERNEL__ diff --git a/arch/parisc/include/asm/errno.h b/arch/parisc/include/asm/errno.h index e2f3ddc..9992abd 100644 --- a/arch/parisc/include/asm/errno.h +++ b/arch/parisc/include/asm/errno.h @@ -120,5 +120,6 @@ #define EOWNERDEAD 254 /* Owner died */ #define ENOTRECOVERABLE 255 /* State not recoverable */ +#define ERFKILL 256 /* Operation not possible due to RF-kill */ #endif diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h index a9ef172..4e2bc49 100644 --- a/arch/sparc/include/asm/errno.h +++ b/arch/sparc/include/asm/errno.h @@ -110,4 +110,6 @@ #define EOWNERDEAD 132 /* Owner died */ #define ENOTRECOVERABLE 133 /* State not recoverable */ +#define ERFKILL 134 /* Operation not possible due to RF-kill */ + #endif -- cgit v0.10.2 From bdf0a550c81c293f22bc511e3cd2d0bf1d847d47 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 11:09:58 +0000 Subject: ixgbe: Enable ACPI WoL capabilities for 82599 The 82599 KX4 device defaults to legacy power management, or APME. This puts the device into ACPI mode, which allows more robust WoL setups to work properly. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index de70a2d..043acab 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5282,6 +5282,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, case IXGBE_DEV_ID_82599_KX4: adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX | IXGBE_WUFC_MC | IXGBE_WUFC_BC); + /* Enable ACPI wakeup in GRC */ + IXGBE_WRITE_REG(hw, IXGBE_GRC, + (IXGBE_READ_REG(hw, IXGBE_GRC) & ~IXGBE_GRC_APME)); break; default: adapter->wol = 0; -- cgit v0.10.2 From 1479ad4fbfbc801898dce1ac2d4d44f0c774ecc5 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 11:10:17 +0000 Subject: ixgbe: Change the 82599 PHY DSP restart logic When reprogramming the 82599 analog PHY to either SFI optical or Direct Attach Twinax, we need to restart the DSP in the PHY. The current method can cause contention with our FW which is managing PHY state, and will cause unexpected link flaps. This patch fixes the DSP restart by issuing an AN_RESTART in the MAC, which will properly propagate the DSP restart to the PHY. This ensures we don't collide with the FW. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 5d27830..a7611bb 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -122,10 +122,9 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); hw->eeprom.ops.read(hw, ++data_offset, &data_value); } - /* Now restart DSP */ - IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000102); - IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000b1d); - IXGBE_WRITE_FLUSH(hw); + /* Now restart DSP by setting Restart_AN */ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, + (IXGBE_READ_REG(hw, IXGBE_AUTOC) | IXGBE_AUTOC_AN_RESTART)); /* Release the semaphore */ ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); -- cgit v0.10.2 From da4dd0f7ca3fa667b7bba5fd34adceaf3fb84a9b Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 11:10:35 +0000 Subject: ixgbe: Add ethtool offline test support This patch adds support for the ethtool internal test engine. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 05a2405..c5f73ed 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -223,6 +223,10 @@ struct ixgbe_q_vector { #define IXGBE_TX_CTXTDESC_ADV(R, i) \ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) +#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) +#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc) +#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc) + #define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 #ifdef IXGBE_FCOE /* Use 3K as the baby jumbo frame size for FCoE */ @@ -327,6 +331,10 @@ struct ixgbe_adapter { struct pci_dev *pdev; struct net_device_stats net_stats; + u32 test_icr; + struct ixgbe_ring test_tx_ring; + struct ixgbe_ring test_rx_ring; + /* structs defined in ixgbe_hw.h */ struct ixgbe_hw hw; u16 msg_enable; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 35255b8..583cc5a 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -118,6 +118,13 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { IXGBE_PB_STATS_LEN + \ IXGBE_QUEUE_STATS_LEN) +static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN + static int ixgbe_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { @@ -743,6 +750,7 @@ static void ixgbe_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); drvinfo->n_stats = IXGBE_STATS_LEN; + drvinfo->testinfo_len = IXGBE_TEST_LEN; drvinfo->regdump_len = ixgbe_get_regs_len(netdev); } @@ -884,6 +892,8 @@ err_setup: static int ixgbe_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { + case ETH_SS_TEST: + return IXGBE_TEST_LEN; case ETH_SS_STATS: return IXGBE_STATS_LEN; default: @@ -938,6 +948,10 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, int i; switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *ixgbe_gstrings_test, + IXGBE_TEST_LEN * ETH_GSTRING_LEN); + break; case ETH_SS_STATS: for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { memcpy(p, ixgbe_gstrings_stats[i].stat_string, @@ -975,6 +989,815 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, } } +static int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_hw *hw = &adapter->hw; + bool link_up; + u32 link_speed = 0; + *data = 0; + + hw->mac.ops.check_link(hw, &link_speed, &link_up, true); + if (link_up) + return *data; + else + *data = 1; + return *data; +} + +/* ethtool register test data */ +struct ixgbe_reg_test { + u16 reg; + u8 array_len; + u8 test_type; + u32 mask; + u32 write; +}; + +/* In the hardware, registers are laid out either singly, in arrays + * spaced 0x40 bytes apart, or in contiguous tables. We assume + * most tests take place on arrays or single registers (handled + * as a single-element array) and special-case the tables. + * Table tests are always pattern tests. + * + * We also make provision for some required setup steps by specifying + * registers to be written without any read-back testing. + */ + +#define PATTERN_TEST 1 +#define SET_READ_TEST 2 +#define WRITE_NO_TEST 3 +#define TABLE32_TEST 4 +#define TABLE64_TEST_LO 5 +#define TABLE64_TEST_HI 6 + +/* default 82599 register test */ +static struct ixgbe_reg_test reg_test_82599[] = { + { IXGBE_FCRTL_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCRTH_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, + { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, + { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, + { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFF80 }, + { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000001, 0x00000001 }, + { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x8001FFFF, 0x800CFFFF }, + { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +/* default 82598 register test */ +static struct ixgbe_reg_test reg_test_82598[] = { + { IXGBE_FCRTL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, + { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + /* Enable all four RX queues before testing. */ + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, + /* RDH is read-only for 82598, only test RDT. */ + { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TIPG, 1, PATTERN_TEST, 0x000000FF, 0x000000FF }, + { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000003, 0x00000003 }, + { IXGBE_DTXCTL, 1, SET_READ_TEST, 0x00000005, 0x00000005 }, + { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x800CFFFF, 0x800CFFFF }, + { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + u32 pat, val, before; \ + const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { \ + before = readl(adapter->hw.hw_addr + R); \ + writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if (val != (_test[pat] & W & M)) { \ + DPRINTK(DRV, ERR, "pattern test reg %04X failed: got "\ + "0x%08X expected 0x%08X\n", \ + R, val, (_test[pat] & W & M)); \ + *data = R; \ + writel(before, adapter->hw.hw_addr + R); \ + return 1; \ + } \ + writel(before, adapter->hw.hw_addr + R); \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + u32 val, before; \ + before = readl(adapter->hw.hw_addr + R); \ + writel((W & M), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if ((W & M) != (val & M)) { \ + DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\ + "expected 0x%08X\n", R, (val & M), (W & M)); \ + *data = R; \ + writel(before, (adapter->hw.hw_addr + R)); \ + return 1; \ + } \ + writel(before, (adapter->hw.hw_addr + R)); \ +} + +static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_reg_test *test; + u32 value, before, after; + u32 i, toggle; + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + toggle = 0x7FFFF30F; + test = reg_test_82599; + } else { + toggle = 0x7FFFF3FF; + test = reg_test_82598; + } + + /* + * Because the status register is such a special case, + * we handle it separately from the rest of the register + * tests. Some bits are read-only, some toggle, and some + * are writeable on newer MACs. + */ + before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS); + value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle); + after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle; + if (value != after) { + DPRINTK(DRV, ERR, "failed STATUS register test got: " + "0x%08X expected: 0x%08X\n", after, value); + *data = 1; + return 1; + } + /* restore previous status */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before); + + /* + * Perform the remainder of the register test, looping through + * the test table until we either fail or reach the null entry. + */ + while (test->reg) { + for (i = 0; i < test->array_len; i++) { + switch (test->test_type) { + case PATTERN_TEST: + REG_PATTERN_TEST(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case SET_READ_TEST: + REG_SET_AND_CHECK(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case WRITE_NO_TEST: + writel(test->write, + (adapter->hw.hw_addr + test->reg) + + (i * 0x40)); + break; + case TABLE32_TEST: + REG_PATTERN_TEST(test->reg + (i * 4), + test->mask, + test->write); + break; + case TABLE64_TEST_LO: + REG_PATTERN_TEST(test->reg + (i * 8), + test->mask, + test->write); + break; + case TABLE64_TEST_HI: + REG_PATTERN_TEST((test->reg + 4) + (i * 8), + test->mask, + test->write); + break; + } + } + test++; + } + + *data = 0; + return 0; +} + +static int ixgbe_eeprom_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_hw *hw = &adapter->hw; + if (hw->eeprom.ops.validate_checksum(hw, NULL)) + *data = 1; + else + *data = 0; + return *data; +} + +static irqreturn_t ixgbe_test_intr(int irq, void *data) +{ + struct net_device *netdev = (struct net_device *) data; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->test_icr |= IXGBE_READ_REG(&adapter->hw, IXGBE_EICR); + + return IRQ_HANDLED; +} + +static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct net_device *netdev = adapter->netdev; + u32 mask, i = 0, shared_int = true; + u32 irq = adapter->pdev->irq; + + *data = 0; + + /* Hook up test interrupt handler just for this test */ + if (adapter->msix_entries) { + /* NOTE: we don't test MSI-X interrupts here, yet */ + return 0; + } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + shared_int = false; + if (request_irq(irq, &ixgbe_test_intr, 0, netdev->name, + netdev)) { + *data = 1; + return -1; + } + } else if (!request_irq(irq, &ixgbe_test_intr, IRQF_PROBE_SHARED, + netdev->name, netdev)) { + shared_int = false; + } else if (request_irq(irq, &ixgbe_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; + return -1; + } + DPRINTK(HW, INFO, "testing %s interrupt\n", + (shared_int ? "shared" : "unshared")); + + /* Disable all the interrupts */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + msleep(10); + + /* Test each interrupt */ + for (; i < 10; i++) { + /* Interrupt to test */ + mask = 1 << i; + + if (!shared_int) { + /* + * Disable the interrupts to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, + ~mask & 0x00007FFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, + ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr & mask) { + *data = 3; + break; + } + } + + /* + * Enable the interrupt to be reported in the cause + * register and then force the same interrupt and see + * if one gets posted. If an interrupt was not posted + * to the bus, the test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + msleep(10); + + if (!(adapter->test_icr &mask)) { + *data = 4; + break; + } + + if (!shared_int) { + /* + * Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, + ~mask & 0x00007FFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, + ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr) { + *data = 5; + break; + } + } + } + + /* Disable all the interrupts */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + msleep(10); + + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + + return *data; +} + +static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + u32 reg_ctl; + int i; + + /* shut down the DMA engines now so they can be reinitialized later */ + + /* first Rx */ + reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + reg_ctl &= ~IXGBE_RXCTRL_RXEN; + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl); + reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(0)); + reg_ctl &= ~IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(0), reg_ctl); + + /* now Tx */ + reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(0)); + reg_ctl &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(0), reg_ctl); + if (hw->mac.type == ixgbe_mac_82599EB) { + reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); + reg_ctl &= ~IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_ctl); + } + + ixgbe_reset(adapter); + + if (tx_ring->desc && tx_ring->tx_buffer_info) { + for (i = 0; i < tx_ring->count; i++) { + struct ixgbe_tx_buffer *buf = + &(tx_ring->tx_buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, buf->length, + PCI_DMA_TODEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (rx_ring->desc && rx_ring->rx_buffer_info) { + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_rx_buffer *buf = + &(rx_ring->rx_buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, + IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (tx_ring->desc) { + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; + } + if (rx_ring->desc) { + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; + } + + kfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + kfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + + return; +} + +static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + u32 rctl, reg_data; + int i, ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + if (!tx_ring->count) + tx_ring->count = IXGBE_DEFAULT_TXD; + + tx_ring->tx_buffer_info = kcalloc(tx_ring->count, + sizeof(struct ixgbe_tx_buffer), + GFP_KERNEL); + if (!(tx_ring->tx_buffer_info)) { + ret_val = 1; + goto err_nomem; + } + + tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, + &tx_ring->dma))) { + ret_val = 2; + goto err_nomem; + } + tx_ring->next_to_use = tx_ring->next_to_clean = 0; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAL(0), + ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0), + ((u64) tx_ring->dma >> 32)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0), + tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data |= IXGBE_HLREG0_TXPADEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL); + reg_data |= IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data); + } + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(0)); + reg_data |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data); + + for (i = 0; i < tx_ring->count; i++) { + struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i); + struct sk_buff *skb; + unsigned int size = 1024; + + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, size); + tx_ring->tx_buffer_info[i].skb = skb; + tx_ring->tx_buffer_info[i].length = skb->len; + tx_ring->tx_buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma); + desc->lower.data = cpu_to_le32(skb->len); + desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP | + IXGBE_TXD_CMD_IFCS | + IXGBE_TXD_CMD_RS); + desc->upper.data = 0; + } + + /* Setup Rx Descriptor ring and Rx buffers */ + + if (!rx_ring->count) + rx_ring->count = IXGBE_DEFAULT_RXD; + + rx_ring->rx_buffer_info = kcalloc(rx_ring->count, + sizeof(struct ixgbe_rx_buffer), + GFP_KERNEL); + if (!(rx_ring->rx_buffer_info)) { + ret_val = 4; + goto err_nomem; + } + + rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc); + rx_ring->size = ALIGN(rx_ring->size, 4096); + if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, + &rx_ring->dma))) { + ret_val = 5; + goto err_nomem; + } + rx_ring->next_to_use = rx_ring->next_to_clean = 0; + + rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl & ~IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAL(0), + ((u64)rx_ring->dma & 0xFFFFFFFF)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAH(0), + ((u64) rx_ring->dma >> 32)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDLEN(0), rx_ring->size); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDH(0), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), 0); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data &= ~IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RDRXCTL); +#define IXGBE_RDRXCTL_RDMTS_MASK 0x00000003 /* Receive Descriptor Minimum + Threshold Size mask */ + reg_data &= ~IXGBE_RDRXCTL_RDMTS_MASK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDRXCTL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MCSTCTRL); +#define IXGBE_MCSTCTRL_MO_MASK 0x00000003 /* Multicast Offset mask */ + reg_data &= ~IXGBE_MCSTCTRL_MO_MASK; + reg_data |= adapter->hw.mac.mc_filter_type; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_MCSTCTRL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(0)); + reg_data |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data); + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + int j = adapter->rx_ring[0].reg_idx; + u32 k; + for (k = 0; k < 10; k++) { + if (IXGBE_READ_REG(&adapter->hw, + IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE) + break; + else + msleep(1); + } + } + + rctl |= IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl); + + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_legacy_rx_desc *rx_desc = + IXGBE_RX_DESC(*rx_ring, i); + struct sk_buff *skb; + + skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL); + if (!skb) { + ret_val = 6; + goto err_nomem; + } + skb_reserve(skb, NET_IP_ALIGN); + rx_ring->rx_buffer_info[i].skb = skb; + rx_ring->rx_buffer_info[i].dma = + pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + rx_desc->buffer_addr = + cpu_to_le64(rx_ring->rx_buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + +err_nomem: + ixgbe_free_desc_rings(adapter); + return ret_val; +} + +static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 reg_data; + + /* right now we only support MAC loopback in the driver */ + + /* Setup MAC loopback */ + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data |= IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_AUTOC); + reg_data &= ~IXGBE_AUTOC_LMS_MASK; + reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data); + + /* Disable Atlas Tx lanes; re-enabled in reset path */ + if (hw->mac.type == ixgbe_mac_82598EB) { + u8 atlas; + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, atlas); + } + + return 0; +} + +static void ixgbe_loopback_cleanup(struct ixgbe_adapter *adapter) +{ + u32 reg_data; + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data &= ~IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); +} + +static void ixgbe_create_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size &= ~1; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int ixgbe_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + frame_size &= ~1; + if (*(skb->data + 3) == 0xFF) { + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) { + return 0; + } + } + return 13; +} + +static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i, j, k, l, lc, good_cnt, ret_val = 0; + unsigned long time; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), rx_ring->count - 1); + + /* + * Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + + if (rx_ring->count <= tx_ring->count) + lc = ((tx_ring->count / 64) * 2) + 1; + else + lc = ((rx_ring->count / 64) * 2) + 1; + + k = l = 0; + for (j = 0; j <= lc; j++) { + for (i = 0; i < 64; i++) { + ixgbe_create_lbtest_frame( + tx_ring->tx_buffer_info[k].skb, + 1024); + pci_dma_sync_single_for_device(pdev, + tx_ring->tx_buffer_info[k].dma, + tx_ring->tx_buffer_info[k].length, + PCI_DMA_TODEVICE); + if (unlikely(++k == tx_ring->count)) + k = 0; + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), k); + msleep(200); + /* set the start time for the receive */ + time = jiffies; + good_cnt = 0; + do { + /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rx_ring->rx_buffer_info[l].dma, + IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + ret_val = ixgbe_check_lbtest_frame( + rx_ring->rx_buffer_info[l].skb, 1024); + if (!ret_val) + good_cnt++; + if (++l == rx_ring->count) + l = 0; + /* + * time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while (good_cnt < 64 && jiffies < (time + 20)); + if (good_cnt != 64) { + /* ret_val is the same as mis-compare */ + ret_val = 13; + break; + } + if (jiffies >= (time + 20)) { + /* Error code for time out error */ + ret_val = 14; + break; + } + } + + return ret_val; +} + +static int ixgbe_loopback_test(struct ixgbe_adapter *adapter, u64 *data) +{ + *data = ixgbe_setup_desc_rings(adapter); + if (*data) + goto out; + *data = ixgbe_setup_loopback_test(adapter); + if (*data) + goto err_loopback; + *data = ixgbe_run_loopback_test(adapter); + ixgbe_loopback_cleanup(adapter); + +err_loopback: + ixgbe_free_desc_rings(adapter); +out: + return *data; +} + +static void ixgbe_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + bool if_running = netif_running(netdev); + + set_bit(__IXGBE_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + DPRINTK(HW, INFO, "offline testing starting\n"); + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if (ixgbe_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + ixgbe_reset(adapter); + + DPRINTK(HW, INFO, "register testing starting\n"); + if (ixgbe_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "eeprom testing starting\n"); + if (ixgbe_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "interrupt testing starting\n"); + if (ixgbe_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "loopback testing starting\n"); + if (ixgbe_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + + clear_bit(__IXGBE_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + DPRINTK(HW, INFO, "online testing starting\n"); + /* Online tests */ + if (ixgbe_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + clear_bit(__IXGBE_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, struct ethtool_wolinfo *wol) @@ -1201,6 +2024,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_msglevel = ixgbe_set_msglevel, .get_tso = ethtool_op_get_tso, .set_tso = ixgbe_set_tso, + .self_test = ixgbe_diag_test, .get_strings = ixgbe_get_strings, .phys_id = ixgbe_phys_id, .get_sset_count = ixgbe_get_sset_count, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 043acab..0a3e8a3 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2598,12 +2598,19 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) int err; err = hw->mac.ops.init_hw(hw); - if (err && (err != IXGBE_ERR_SFP_NOT_PRESENT)) - dev_err(&adapter->pdev->dev, "Hardware Error\n"); + switch (err) { + case 0: + case IXGBE_ERR_SFP_NOT_PRESENT: + break; + case IXGBE_ERR_MASTER_REQUESTS_PENDING: + dev_err(&adapter->pdev->dev, "master disable timed out\n"); + break; + default: + dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err); + } /* reprogram the RAR[0] in case user changed it. */ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); - } /** -- cgit v0.10.2 From 50ac58ba1d707df33f0c398ae700214e49bf918f Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 11:10:53 +0000 Subject: ixgbe: Harden the 82599 multispeed fiber autotry mechanism 82599 supports multispeed fiber optical modules (10Gbps/1Gbps). Some scenarios can cause the autotry mechanism to not negotiate link properly. What needs to happen is the driver must flap the Tx laser to induce an Rx Loss of Signal on the link partner. This will restart the autotry mechanism to get link into a known state. The software definable pin (SDP) 3 on the 0x10fb NIC is wired to cause a Tx LOS event, which triggers the Rx LOS we require. Signed-off-by: Peter P Waskiewicz Jr Acked-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index a7611bb..84b83f7 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -461,12 +461,23 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); bool link_up = false; bool negotiation; + int i; /* Mask off requested but non-supported speeds */ hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation); speed &= phy_link_speed; /* + * When the driver changes the link speeds that it can support, + * it sets autotry_restart to true to indicate that we need to + * initiate a new autotry session with the link partner. To do + * so, we set the speed then disable and re-enable the tx laser, to + * alert the link partner that it also needs to restart autotry on its + * end. This is consistent with true clause 37 autoneg, which also + * involves a loss of signal. + */ + + /* * Try each speed one by one, highest priority first. We do this in * software because 10gb fiber doesn't support speed autonegotiation. */ @@ -474,21 +485,52 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, speedcnt++; highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL; - /* Set hardware SDP's */ + /* If we already have link at this speed, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); + + if ((phy_link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up) + goto out; + + /* Set the module link speed */ esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - ixgbe_setup_mac_link_speed_82599(hw, - IXGBE_LINK_SPEED_10GB_FULL, - autoneg, - autoneg_wait_to_complete); - - msleep(50); + /* Allow module to change analog characteristics (1G->10G) */ + msleep(40); - /* If we have link, just jump out */ - hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); - if (link_up) + status = ixgbe_setup_mac_link_speed_82599(hw, + IXGBE_LINK_SPEED_10GB_FULL, + autoneg, + autoneg_wait_to_complete); + if (status != 0) goto out; + + /* Flap the tx laser if it has not already been done */ + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + udelay(100); + + /* Enable tx laser; allow 2ms to light up per spec */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + msleep(2); + + hw->mac.autotry_restart = false; + } + + /* The controller may take up to 500ms at 10g to acquire link */ + for (i = 0; i < 5; i++) { + /* Wait for the link partner to also set speed */ + msleep(100); + + /* If we have link, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, + &link_up, false); + if (link_up) + goto out; + } } if (speed & IXGBE_LINK_SPEED_1GB_FULL) { @@ -496,16 +538,44 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN) highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL; - /* Set hardware SDP's */ + /* If we already have link at this speed, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); + + if ((phy_link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up) + goto out; + + /* Set the module link speed */ esdp_reg &= ~IXGBE_ESDP_SDP5; esdp_reg |= IXGBE_ESDP_SDP5_DIR; IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - ixgbe_setup_mac_link_speed_82599( - hw, IXGBE_LINK_SPEED_1GB_FULL, autoneg, - autoneg_wait_to_complete); + /* Allow module to change analog characteristics (10G->1G) */ + msleep(40); - msleep(50); + status = ixgbe_setup_mac_link_speed_82599(hw, + IXGBE_LINK_SPEED_1GB_FULL, + autoneg, + autoneg_wait_to_complete); + if (status != 0) + goto out; + + /* Flap the tx laser if it has not already been done */ + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + udelay(100); + + /* Enable tx laser; allow 2ms to light up per spec */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + msleep(2); + + hw->mac.autotry_restart = false; + } + + /* Wait for the link partner to also set speed */ + msleep(100); /* If we have link, just jump out */ hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); @@ -591,6 +661,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + u32 start_autoc = autoc; u32 orig_autoc = 0; u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK; u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; @@ -603,6 +674,11 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, hw->mac.ops.get_link_capabilities(hw, &link_capabilities, &autoneg); speed &= link_capabilities; + if (speed == IXGBE_LINK_SPEED_UNKNOWN) { + status = IXGBE_ERR_LINK_SETUP; + goto out; + } + /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ if (hw->mac.orig_link_settings_stored) orig_autoc = hw->mac.orig_autoc; @@ -610,11 +686,9 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, orig_autoc = autoc; - if (speed == IXGBE_LINK_SPEED_UNKNOWN) { - status = IXGBE_ERR_LINK_SETUP; - } else if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || - link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || - link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { + if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || + link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || + link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { /* Set KX4/KX/KR support according to speed requested */ autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP); if (speed & IXGBE_LINK_SPEED_10GB_FULL) @@ -646,7 +720,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, } } - if (status == 0) { + if (autoc != start_autoc) { /* Restart link */ autoc |= IXGBE_AUTOC_AN_RESTART; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); @@ -680,6 +754,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, msleep(50); } +out: return status; } @@ -1144,6 +1219,9 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) } IXGBE_WRITE_FLUSH(hw); + /* We need to run link autotry after the driver loads */ + hw->mac.autotry_restart = true; + return 0; } diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 6f79409..4d36cd3 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -2068,6 +2068,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) hw->mac.ops.check_link(hw, &speed, &link_up, false); if (!link_up) { + autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); msleep(10); diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index e43d624..453e966 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -606,6 +606,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_setup_needed = true; /* Determine if the SFP+ PHY is dual speed or not. */ + hw->phy.multispeed_fiber = false; if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index a8a8243..199b288 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1265,8 +1265,10 @@ #define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */ /* ESDP Bit Masks */ -#define IXGBE_ESDP_SDP0 0x00000001 -#define IXGBE_ESDP_SDP1 0x00000002 +#define IXGBE_ESDP_SDP0 0x00000001 /* SDP0 Data Value */ +#define IXGBE_ESDP_SDP1 0x00000002 /* SDP1 Data Value */ +#define IXGBE_ESDP_SDP2 0x00000004 /* SDP2 Data Value */ +#define IXGBE_ESDP_SDP3 0x00000008 /* SDP3 Data Value */ #define IXGBE_ESDP_SDP4 0x00000010 /* SDP4 Data Value */ #define IXGBE_ESDP_SDP5 0x00000020 /* SDP5 Data Value */ #define IXGBE_ESDP_SDP6 0x00000040 /* SDP6 Data Value */ @@ -2281,6 +2283,7 @@ struct ixgbe_mac_info { bool orig_link_settings_stored; bool autoneg; bool autoneg_succeeded; + bool autotry_restart; }; struct ixgbe_phy_info { -- cgit v0.10.2 From 620fa036b2459ca9acf7484c8074147f0dda68da Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Thu, 4 Jun 2009 11:11:13 +0000 Subject: ixgbe: Fix 82599 adapter link flickering issues Fix autoneg restart issues in flow control path which might create endless link flickering due to known timing issues with 82599 adapters. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 88e8350..b992304 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -293,6 +293,17 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) u32 rmcs_reg; u32 reg; +#ifdef CONFIG_DCB + if (hw->fc.requested_mode == ixgbe_fc_pfc) + goto out; + +#endif /* CONFIG_DCB */ + /* Negotiate the fc mode to use */ + ret_val = ixgbe_fc_autoneg(hw); + if (ret_val) + goto out; + + /* Disable any previous flow control settings */ fctrl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); fctrl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); @@ -304,14 +315,20 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) * 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 + * 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. +#ifdef CONFIG_DCB + * 4: Priority Flow Control is enabled. +#endif */ switch (hw->fc.current_mode) { case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ break; case ixgbe_fc_rx_pause: /* @@ -336,6 +353,11 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) fctrl_reg |= IXGBE_FCTRL_RFCE; rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; break; +#ifdef CONFIG_DCB + case ixgbe_fc_pfc: + goto out; + break; +#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = -IXGBE_ERR_CONFIG; @@ -343,7 +365,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) break; } - /* Enable 802.3x based flow control settings. */ + /* Set 802.3x based flow control settings. */ fctrl_reg |= IXGBE_FCTRL_DPF; IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg); IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); @@ -377,79 +399,6 @@ out: } /** - * 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. - **/ -static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) -{ - s32 ret_val = 0; - ixgbe_link_speed speed; - bool link_up; - - /* Validate the packetbuf configuration */ - if (packetbuf_num < 0 || packetbuf_num > 7) { - hw_dbg(hw, "Invalid packet buffer number [%d], expected range is" - " 0-7\n", packetbuf_num); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * Validate the water mark configuration. Zero water marks are invalid - * because it causes the controller to just blast out fc packets. - */ - if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { - if (hw->fc.requested_mode != ixgbe_fc_none) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - } - - /* - * Validate the requested mode. Strict IEEE mode does not allow - * ixgbe_fc_rx_pause because it will cause testing anomalies. - */ - if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { - hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * 10gig 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.requested_mode == ixgbe_fc_default) - hw->fc.requested_mode = ixgbe_fc_full; - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - - hw->fc.current_mode = hw->fc.requested_mode; - - /* Decide whether to use autoneg or not. */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && - (speed == IXGBE_LINK_SPEED_1GB_FULL)) - ret_val = ixgbe_fc_autoneg(hw); - - if (ret_val) - goto out; - - ret_val = ixgbe_fc_enable_82598(hw, packetbuf_num); - -out: - return ret_val; -} - -/** * ixgbe_setup_mac_link_82598 - Configures MAC link settings * @hw: pointer to hardware structure * @@ -488,13 +437,6 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) } } - /* - * 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. - */ - ixgbe_setup_fc_82598(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); @@ -581,6 +523,11 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, else *speed = IXGBE_LINK_SPEED_1GB_FULL; + /* if link is down, zero out the current_mode */ + if (*link_up == false) { + hw->fc.current_mode = ixgbe_fc_none; + hw->fc.fc_was_autonegged = false; + } out: return 0; } @@ -1168,7 +1115,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .disable_mc = &ixgbe_disable_mc_generic, .clear_vfta = &ixgbe_clear_vfta_82598, .set_vfta = &ixgbe_set_vfta_82598, - .setup_fc = &ixgbe_setup_fc_82598, + .fc_enable = &ixgbe_fc_enable_82598, }; static struct ixgbe_eeprom_operations eeprom_ops_82598 = { diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 84b83f7..4d83e59 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -413,9 +413,6 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) } } - /* Set up flow control */ - status = ixgbe_setup_fc_generic(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); @@ -641,6 +638,11 @@ s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, else *speed = IXGBE_LINK_SPEED_100_FULL; + /* if link is down, zero out the current_mode */ + if (*link_up == false) { + hw->fc.current_mode = ixgbe_fc_none; + hw->fc.fc_was_autonegged = false; + } return 0; } @@ -747,9 +749,6 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, } } - /* Set up flow control */ - status = ixgbe_setup_fc_generic(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); } @@ -1509,7 +1508,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .disable_mc = &ixgbe_disable_mc_generic, .clear_vfta = &ixgbe_clear_vfta_82599, .set_vfta = &ixgbe_set_vfta_82599, - .setup_fc = &ixgbe_setup_fc_generic, + .fc_enable = &ixgbe_fc_enable_generic, .init_uta_tables = &ixgbe_init_uta_tables_82599, .setup_sfp = &ixgbe_setup_sfp_modules_82599, }; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 4d36cd3..db339d6 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -85,6 +85,9 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); IXGBE_WRITE_FLUSH(hw); + /* Setup flow control */ + ixgbe_setup_fc(hw, 0); + /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -1577,17 +1580,16 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) } /** - * ixgbe_fc_enable - Enable flow control + * ixgbe_fc_enable_generic - Enable flow control * @hw: pointer to hardware structure * @packetbuf_num: packet buffer number (0-7) * * Enable flow control according to the current settings. **/ -s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; - u32 mflcn_reg; - u32 fccfg_reg; + u32 mflcn_reg, fccfg_reg; u32 reg; u32 rx_pba_size; @@ -1596,7 +1598,12 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) goto out; #endif /* CONFIG_DCB */ + /* Negotiate the fc mode to use */ + ret_val = ixgbe_fc_autoneg(hw); + if (ret_val) + goto out; + /* Disable any previous flow control settings */ mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE); @@ -1616,7 +1623,10 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) */ switch (hw->fc.current_mode) { case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ break; case ixgbe_fc_rx_pause: /* @@ -1645,7 +1655,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) case ixgbe_fc_pfc: goto out; break; -#endif +#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = -IXGBE_ERR_CONFIG; @@ -1653,7 +1663,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) break; } - /* Enable 802.3x based flow control settings. */ + /* Set 802.3x based flow control settings. */ mflcn_reg |= IXGBE_MFLCN_DPF; IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); @@ -1661,10 +1671,12 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) reg = IXGBE_READ_REG(hw, IXGBE_MTQC); /* Thresholds are different for link flow control when in DCB mode */ if (reg & IXGBE_MTQC_RT_ENA) { + rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); + /* Always disable XON for LFC when in DCB mode */ - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), 0); + reg = (rx_pba_size >> 5) & 0xFFE0; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), reg); - rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); reg = (rx_pba_size >> 2) & 0xFFE0; if (hw->fc.current_mode & ixgbe_fc_tx_pause) reg |= IXGBE_FCRTH_FCEN; @@ -1709,100 +1721,41 @@ out: * ixgbe_fc_autoneg - Configure flow control * @hw: pointer to hardware structure * - * Negotiates flow control capabilities with link partner using autoneg and - * applies the results. + * Compares our advertised flow control capabilities to those advertised by + * our link partner, and determines the proper flow control mode to use. **/ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) { s32 ret_val = 0; - u32 i, reg, pcs_anadv_reg, pcs_lpab_reg; - - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + ixgbe_link_speed speed; + u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; + bool link_up; /* - * The possible values of fc.current_mode 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. - * 4: Priority Flow Control is enabled. - * other: Invalid. + * AN should have completed when the cable was plugged in. + * Look for reasons to bail out. Bail out if: + * - FC autoneg is disabled, or if + * - we don't have multispeed fiber, or if + * - we're not running at 1G, or if + * - link is not up, or if + * - link is up but AN did not complete, or if + * - link is up and AN completed but timed out + * + * Since we're being called from an LSC, link is already know to be up. + * So use link_up_wait_to_complete=false. */ - switch (hw->fc.current_mode) { - case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; - case ixgbe_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is - * disabled by software override. Since there really - * isn't a way to advertise that we are capable of RX - * Pause ONLY, we will advertise that we support both - * symmetric and asymmetric Rx PAUSE. Later, we will - * disable the adapter's ability to send PAUSE frames. - */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; - case ixgbe_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is - * disabled by software override. - */ - reg |= (IXGBE_PCS1GANA_ASM_PAUSE); - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); - break; - case ixgbe_fc_full: - /* Flow control (both Rx and Tx) is enabled by SW override. */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; - break; -#endif - default: - hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = -IXGBE_ERR_CONFIG; - goto out; - break; - } - - IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); - - /* Set PCS register for autoneg */ - /* Enable and restart autoneg */ - reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; - - /* Disable AN timeout */ - if (hw->fc.strict_ieee) - reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; - - hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); - IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); - - /* See if autonegotiation has succeeded */ - hw->mac.autoneg_succeeded = 0; - for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msleep(10); - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); - if ((reg & (IXGBE_PCS1GLSTA_LINK_OK | - IXGBE_PCS1GLSTA_AN_COMPLETE)) == - (IXGBE_PCS1GLSTA_LINK_OK | - IXGBE_PCS1GLSTA_AN_COMPLETE)) { - if (!(reg & IXGBE_PCS1GLSTA_AN_TIMED_OUT)) - hw->mac.autoneg_succeeded = 1; - break; - } - } - - if (!hw->mac.autoneg_succeeded) { - /* Autoneg failed to achieve a link, so we turn fc off */ - hw->fc.current_mode = ixgbe_fc_none; - hw_dbg(hw, "Flow Control = NONE.\n"); + hw->mac.ops.check_link(hw, &speed, &link_up, false); + linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); + + if (hw->fc.disable_fc_autoneg || + !hw->phy.multispeed_fiber || + (speed != IXGBE_LINK_SPEED_1GB_FULL) || + !link_up || + ((linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || + ((linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + hw_dbg(hw, "Autoneg FC was skipped.\n"); goto out; } @@ -1845,21 +1798,23 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) hw_dbg(hw, "Flow Control = NONE.\n"); } + /* Record that current_mode is the result of a successful autoneg */ + hw->fc.fc_was_autonegged = true; + out: return ret_val; } /** - * ixgbe_setup_fc_generic - Set up flow control + * ixgbe_setup_fc - Set up flow control * @hw: pointer to hardware structure * - * Sets up flow control. + * Called at init time to set up flow control. **/ -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; - ixgbe_link_speed speed; - bool link_up; + u32 reg; #ifdef CONFIG_DCB if (hw->fc.requested_mode == ixgbe_fc_pfc) { @@ -1881,16 +1836,14 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) * because it causes the controller to just blast out fc packets. */ if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { - if (hw->fc.requested_mode != ixgbe_fc_none) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; } /* * Validate the requested mode. Strict IEEE mode does not allow - * ixgbe_fc_rx_pause because it will cause testing anomalies. + * ixgbe_fc_rx_pause because it will cause us to fail at UNH. */ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict " @@ -1907,21 +1860,77 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) hw->fc.requested_mode = ixgbe_fc_full; /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. + * Set up the 1G flow control advertisement registers so the HW will be + * able to do fc autoneg once the cable is plugged in. If we end up + * using 10g instead, this is harmless. */ - hw->fc.current_mode = hw->fc.requested_mode; - - /* Decide whether to use autoneg or not. */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && - (speed == IXGBE_LINK_SPEED_1GB_FULL)) - ret_val = ixgbe_fc_autoneg(hw); + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); - if (ret_val) + /* + * The possible values of fc.requested_mode 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. +#ifdef CONFIG_DCB + * 4: Priority Flow Control is enabled. +#endif + * other: Invalid. + */ + switch (hw->fc.requested_mode) { + case ixgbe_fc_none: + /* Flow control completely disabled by software override. */ + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + reg |= (IXGBE_PCS1GANA_ASM_PAUSE); + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); + break; + case ixgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; +#ifdef CONFIG_DCB + case ixgbe_fc_pfc: goto out; + break; +#endif /* CONFIG_DCB */ + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = -IXGBE_ERR_CONFIG; + goto out; + break; + } + + IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); - ret_val = ixgbe_fc_enable(hw, packetbuf_num); + /* Enable and restart autoneg to inform the link partner */ + reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; + + /* Disable AN timeout */ + if (hw->fc.strict_ieee) + reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; + + IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); + hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg); out: return ret_val; diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index b2a4b2c..0d34d4d 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -64,8 +64,8 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num); -s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packtetbuf_num); +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packtetbuf_num); s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw); s32 ixgbe_validate_mac_addr(u8 *mac_addr); diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index f4417fc..589f62c 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -295,7 +295,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, /* If PFC is disabled globally then fall back to LFC. */ if (!dcb_config->pfc_mode_enable) { for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.setup_fc(hw, i); + hw->mac.ops.fc_enable(hw, i); goto out; } diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 583cc5a..1c11045 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -283,6 +283,7 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_fc_info fc; #ifdef CONFIG_DCB if (adapter->dcb_cfg.pfc_mode_enable || @@ -291,26 +292,37 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, return -EINVAL; #endif + + fc = hw->fc; + if (pause->autoneg != AUTONEG_ENABLE) - hw->fc.disable_fc_autoneg = true; + fc.disable_fc_autoneg = true; else - hw->fc.disable_fc_autoneg = false; + fc.disable_fc_autoneg = false; if (pause->rx_pause && pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_full; + fc.requested_mode = ixgbe_fc_full; else if (pause->rx_pause && !pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_rx_pause; + fc.requested_mode = ixgbe_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_tx_pause; + fc.requested_mode = ixgbe_fc_tx_pause; else if (!pause->rx_pause && !pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_none; + fc.requested_mode = ixgbe_fc_none; else return -EINVAL; #ifdef CONFIG_DCB - adapter->last_lfc_mode = hw->fc.requested_mode; + adapter->last_lfc_mode = fc.requested_mode; #endif - hw->mac.ops.setup_fc(hw, 0); + + /* if the thing changed then we'll update and use new autoneg */ + if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) { + hw->fc = fc; + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); + else + ixgbe_reset(adapter); + } return 0; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 0a3e8a3..9684632 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4344,12 +4344,12 @@ static void ixgbe_watchdog_task(struct work_struct *work) #ifdef CONFIG_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.setup_fc(hw, i); + hw->mac.ops.fc_enable(hw, i); } else { - hw->mac.ops.setup_fc(hw, 0); + hw->mac.ops.fc_enable(hw, 0); } #else - hw->mac.ops.setup_fc(hw, 0); + hw->mac.ops.fc_enable(hw, 0); #endif } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 199b288..4402552 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1368,8 +1368,6 @@ #define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ #define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ -#define FIBER_LINK_UP_LIMIT 50 - /* PCS1GLSTA Bit Masks */ #define IXGBE_PCS1GLSTA_LINK_OK 1 #define IXGBE_PCS1GLSTA_SYNK_OK 0x10 @@ -2094,7 +2092,8 @@ struct ixgbe_fc_info { u16 pause_time; /* Flow Control Pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ - bool disable_fc_autoneg; /* Turn off autoneg FC mode */ + bool disable_fc_autoneg; /* Do not autonegotiate FC */ + bool fc_was_autonegged; /* Is current_mode the result of autonegging? */ enum ixgbe_fc_mode current_mode; /* FC mode in effect */ enum ixgbe_fc_mode requested_mode; /* FC mode requested by caller */ }; @@ -2236,7 +2235,7 @@ struct ixgbe_mac_operations { s32 (*init_uta_tables)(struct ixgbe_hw *); /* Flow Control */ - s32 (*setup_fc)(struct ixgbe_hw *, s32); + s32 (*fc_enable)(struct ixgbe_hw *, s32); }; struct ixgbe_phy_operations { -- cgit v0.10.2 From 74766013a131f1e1c2fe8fd138e12841eb708060 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Thu, 4 Jun 2009 11:11:34 +0000 Subject: ixgbe: ethtool support to change advertised link modes of 82599 adapters Add ethtool support to change advertised link modes/autoneg settings of 82599 multispeed fiber adapters. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 4d83e59..3f36d83 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -464,6 +464,15 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation); speed &= phy_link_speed; + /* Set autoneg_advertised value based on input link speed */ + hw->phy.autoneg_advertised = 0; + + 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; + /* * When the driver changes the link speeds that it can support, * it sets autotry_restart to true to indicate that we need to diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 1c11045..e0feaf5 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -136,11 +136,12 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->supported = SUPPORTED_10000baseT_Full; ecmd->autoneg = AUTONEG_ENABLE; ecmd->transceiver = XCVR_EXTERNAL; - if (hw->phy.media_type == ixgbe_media_type_copper) { + if ((hw->phy.media_type == ixgbe_media_type_copper) || + (hw->mac.type == ixgbe_mac_82599EB)) { ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_TP | SUPPORTED_Autoneg); + SUPPORTED_Autoneg); - ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg); + ecmd->advertising = ADVERTISED_Autoneg; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) ecmd->advertising |= ADVERTISED_10000baseT_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) @@ -155,7 +156,15 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->advertising |= (ADVERTISED_10000baseT_Full | ADVERTISED_1000baseT_Full); - ecmd->port = PORT_TP; + if (hw->phy.media_type == ixgbe_media_type_copper) { + ecmd->supported |= SUPPORTED_TP; + ecmd->advertising |= ADVERTISED_TP; + ecmd->port = PORT_TP; + } else { + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_FIBRE; + } } else if (hw->phy.media_type == ixgbe_media_type_backplane) { /* Set as FIBRE until SERDES defined in kernel */ switch (hw->device_id) { @@ -203,16 +212,10 @@ static int ixgbe_set_settings(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 advertised, old; - s32 err; + s32 err = 0; - switch (hw->phy.media_type) { - case ixgbe_media_type_fiber: - if ((ecmd->autoneg == AUTONEG_ENABLE) || - (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) - return -EINVAL; - /* in this case we currently only support 10Gb/FULL */ - break; - case ixgbe_media_type_copper: + if ((hw->phy.media_type == ixgbe_media_type_copper) || + (hw->mac.type == ixgbe_mac_82599EB)) { /* 10000/copper and 1000/copper must autoneg * this function does not support any duplex forcing, but can * limit the advertising of the adapter to only 10000 or 1000 */ @@ -228,20 +231,23 @@ static int ixgbe_set_settings(struct net_device *netdev, advertised |= IXGBE_LINK_SPEED_1GB_FULL; if (old == advertised) - break; + return err; /* this sets the link speed and restarts auto-neg */ + hw->mac.autotry_restart = true; err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); if (err) { DPRINTK(PROBE, INFO, "setup link failed with code %d\n", err); hw->mac.ops.setup_link_speed(hw, old, true, true); } - break; - default: - break; + } else { + /* in this case we currently only support 10Gb/FULL */ + if ((ecmd->autoneg == AUTONEG_ENABLE) || + (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) + return -EINVAL; } - return 0; + return err; } static void ixgbe_get_pauseparam(struct net_device *netdev, -- cgit v0.10.2 From 21fa4e66bd0bedfa4ed6aa6f7008b2aff6d45c8d Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 4 Jun 2009 15:59:49 +0000 Subject: ixgbe: use rx_buffer_info->dma instead of nr_frags to determine skb unmap This patch changes the driver so that it uses rx_buffer_info->dma to determine if it needs to unmap the page instead of sh_info->nr_frags. This helps to prevent a cache line miss when receiving small packets as the rx_buffer_info data should already be in the cache. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 9684632..e1efa1d 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -708,7 +708,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, prefetch(skb->data - NET_IP_ALIGN); rx_buffer_info->skb = NULL; - if (len && !skb_shinfo(skb)->nr_frags) { + if (rx_buffer_info->dma) { pci_unmap_single(pdev, rx_buffer_info->dma, rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); -- cgit v0.10.2 From fe49f04aa8c0f74c363cbb1e9852a0d7769b5a99 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 4 Jun 2009 16:00:09 +0000 Subject: ixgbe: move v_idx into q_vector and use as index only The v_idx value was being used as both a bitmask and an index. This change makes it so that the q_vector contains the index and allows for much of the code to be simplified since disabling a q_vector involves only clearing one bit in the interrupt bitmask. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index c5f73ed..00c303a 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -148,10 +148,6 @@ struct ixgbe_ring { int cpu; #endif struct ixgbe_queue_stats stats; - u64 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 work_limit; /* max work per interrupt */ u16 rx_buf_len; @@ -193,6 +189,9 @@ struct ixgbe_ring_feature { */ struct ixgbe_q_vector { struct ixgbe_adapter *adapter; + unsigned int v_idx; /* index of q_vector within array, also used for + * finding the bit in EICR and friends that + * represents the vector for this ring */ struct napi_struct napi; DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */ DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */ @@ -201,7 +200,6 @@ struct ixgbe_q_vector { u8 tx_itr; u8 rx_itr; u32 eitr; - u32 v_idx; /* vector index in list */ }; /* Helper macros to switch between ints/sec and what the register uses. @@ -401,7 +399,8 @@ extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *) extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); -extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32); +extern void ixgbe_write_eitr(struct ixgbe_q_vector *); +extern int ethtool_ioctl(struct ifreq *ifr); #ifdef IXGBE_FCOE extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index e0feaf5..003b6e5 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -840,7 +840,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } - temp_tx_ring[i].v_idx = adapter->tx_ring[i].v_idx; } need_update = true; } @@ -870,7 +869,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } - temp_rx_ring[i].v_idx = adapter->rx_ring[i].v_idx; } need_update = true; } @@ -1987,8 +1985,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev, else /* rx only or mixed */ q_vector->eitr = adapter->eitr_param; - ixgbe_write_eitr(adapter, i, - EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + ixgbe_write_eitr(q_vector); } return 0; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index e1efa1d..2500e8b 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -186,6 +186,22 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction, } } +static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); + } +} + static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, struct ixgbe_tx_buffer *tx_buffer_info) @@ -248,14 +264,13 @@ static void ixgbe_tx_timeout(struct net_device *netdev); /** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes - * @adapter: board private structure + * @q_vector: structure containing interrupt and ring information * @tx_ring: tx ring to clean - * - * returns true if transmit work is done **/ -static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, +static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, struct ixgbe_ring *tx_ring) { + struct ixgbe_adapter *adapter = q_vector->adapter; struct net_device *netdev = adapter->netdev; union ixgbe_adv_tx_desc *tx_desc, *eop_desc; struct ixgbe_tx_buffer *tx_buffer_info; @@ -329,18 +344,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, } /* re-arm the interrupt */ - if (count >= tx_ring->work_limit) { - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, - tx_ring->v_idx); - else if (tx_ring->v_idx & 0xFFFFFFFF) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), - tx_ring->v_idx); - else - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), - (tx_ring->v_idx >> 32)); - } - + if (count >= tx_ring->work_limit) + ixgbe_irq_rearm_queues(adapter, ((u64)1 << q_vector->v_idx)); tx_ring->total_bytes += total_bytes; tx_ring->total_packets += total_packets; @@ -875,12 +880,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) /* rx only */ q_vector->eitr = adapter->eitr_param; - /* - * since this is initial set up don't need to call - * ixgbe_write_eitr helper - */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), - EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + ixgbe_write_eitr(q_vector); } if (adapter->hw.mac.type == ixgbe_mac_82598EB) @@ -965,17 +965,19 @@ update_itr_done: /** * ixgbe_write_eitr - write EITR register in hardware specific way - * @adapter: pointer to adapter struct - * @v_idx: vector index into q_vector array - * @itr_reg: new value to be written in *register* format, not ints/s + * @q_vector: structure containing interrupt and ring information * * This function is made to be called by ethtool and by the driver * when it needs to update EITR registers at runtime. Hardware * specific quirks/differences are taken care of here. */ -void ixgbe_write_eitr(struct ixgbe_adapter *adapter, int v_idx, u32 itr_reg) +void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector) { + struct ixgbe_adapter *adapter = q_vector->adapter; struct ixgbe_hw *hw = &adapter->hw; + int v_idx = q_vector->v_idx; + u32 itr_reg = EITR_INTS_PER_SEC_TO_REG(q_vector->eitr); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { /* must write high and low 16 bits to reset counter */ itr_reg |= (itr_reg << 16); @@ -994,7 +996,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) struct ixgbe_adapter *adapter = q_vector->adapter; u32 new_itr; u8 current_itr, ret_itr; - int i, r_idx, v_idx = q_vector->v_idx; + int i, r_idx; struct ixgbe_ring *rx_ring, *tx_ring; r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); @@ -1044,14 +1046,13 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) } if (new_itr != q_vector->eitr) { - u32 itr_reg; + /* do an exponential smoothing */ + new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); /* save the algorithm value here, not the smoothed one */ q_vector->eitr = new_itr; - /* do an exponential smoothing */ - new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); - itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); - ixgbe_write_eitr(adapter, v_idx, itr_reg); + + ixgbe_write_eitr(q_vector); } return; @@ -1130,6 +1131,40 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) return IRQ_HANDLED; } +static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask); + } + /* skip the flush */ +} + +static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), mask); + } + /* skip the flush */ +} + static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) { struct ixgbe_q_vector *q_vector = data; @@ -1149,7 +1184,7 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) #endif tx_ring->total_bytes = 0; tx_ring->total_packets = 0; - ixgbe_clean_tx_irq(adapter, tx_ring); + ixgbe_clean_tx_irq(q_vector, tx_ring); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, r_idx + 1); } @@ -1185,13 +1220,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) 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 */ - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); - else if (rx_ring->v_idx & 0xFFFFFFFF) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), rx_ring->v_idx); - else - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), - (rx_ring->v_idx >> 32)); + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); napi_schedule(&q_vector->napi); return IRQ_HANDLED; @@ -1205,23 +1234,6 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) return IRQ_HANDLED; } -static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter, - u64 qmask) -{ - u32 mask; - - if (adapter->hw.mac.type == ixgbe_mac_82598EB) { - mask = (IXGBE_EIMS_RTX_QUEUE & qmask); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); - } else { - mask = (qmask & 0xFFFFFFFF); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask); - mask = (qmask >> 32); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask); - } - /* skip the flush */ -} - /** * ixgbe_clean_rxonly - msix (aka one shot) rx clean routine * @napi: napi struct with our devices info in it @@ -1254,7 +1266,8 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - ixgbe_irq_enable_queues(adapter, rx_ring->v_idx); + ixgbe_irq_enable_queues(adapter, + ((u64)1 << q_vector->v_idx)); } return work_done; @@ -1276,7 +1289,6 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) struct ixgbe_ring *rx_ring = NULL; int work_done = 0, i; long r_idx; - u64 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 */ @@ -1290,7 +1302,6 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) ixgbe_update_rx_dca(adapter, rx_ring); #endif ixgbe_clean_rx_irq(q_vector, 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); } @@ -1303,7 +1314,8 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - ixgbe_irq_enable_queues(adapter, enable_mask); + ixgbe_irq_enable_queues(adapter, + ((u64)1 << q_vector->v_idx)); return 0; } @@ -1316,7 +1328,6 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, set_bit(r_idx, q_vector->rxr_idx); q_vector->rxr_count++; - a->rx_ring[r_idx].v_idx = (u64)1 << v_idx; } static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, @@ -1326,7 +1337,6 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, set_bit(t_idx, q_vector->txr_idx); q_vector->txr_count++; - a->tx_ring[t_idx].v_idx = (u64)1 << v_idx; } /** @@ -1505,14 +1515,13 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter) } if (new_itr != q_vector->eitr) { - u32 itr_reg; + /* do an exponential smoothing */ + new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); /* save the algorithm value here, not the smoothed one */ q_vector->eitr = new_itr; - /* do an exponential smoothing */ - new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); - itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); - ixgbe_write_eitr(adapter, 0, itr_reg); + + ixgbe_write_eitr(q_vector); } return; @@ -2805,7 +2814,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) } #endif - tx_clean_complete = ixgbe_clean_tx_irq(adapter, adapter->tx_ring); + tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring); ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget); if (!tx_clean_complete) @@ -3324,8 +3333,8 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) if (!q_vector) goto err_out; q_vector->adapter = adapter; - q_vector->v_idx = q_idx; q_vector->eitr = adapter->eitr_param; + q_vector->v_idx = q_idx; if (q_idx < napi_vectors) netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64); @@ -4216,57 +4225,43 @@ static void ixgbe_watchdog(unsigned long data) { struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; struct ixgbe_hw *hw = &adapter->hw; + u64 eics = 0; + int i; - /* 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)) { - u64 eics = 0; - int i; + /* + * Do the watchdog outside of interrupt context due to the lovely + * delays that some of the newer hardware requires + */ - for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) - eics |= ((u64)1 << i); + if (test_bit(__IXGBE_DOWN, &adapter->state)) + goto watchdog_short_circuit; - /* Cause software interrupt to ensure rx rings are cleaned */ - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - IXGBE_WRITE_REG(hw, IXGBE_EICS, (u32)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)); - } - break; - case ixgbe_mac_82599EB: - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(0), - (u32)(eics & 0xFFFFFFFF)); - IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(1), - (u32)(eics >> 32)); - } 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)); - } - break; - default: - break; - } - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + 2 * HZ)); + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + /* + * 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)); + goto watchdog_reschedule; + } + + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbe_q_vector *qv = adapter->q_vector[i]; + if (qv->rxr_count || qv->txr_count) + eics |= ((u64)1 << i); } + /* Cause software interrupt to ensure rx rings are cleaned */ + ixgbe_irq_rearm_queues(adapter, eics); + +watchdog_reschedule: + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); + +watchdog_short_circuit: schedule_work(&adapter->watchdog_task); } -- cgit v0.10.2 From 91281fd36c7670904e0b315e273e896d907adc36 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 4 Jun 2009 16:00:27 +0000 Subject: ixgbe: move tx processing into NAPI context This patch moves the tx cleanup processing out of the MSI-X interrupt processing and gives it it's own napi routine. This allows the driver to process TX cleanup in a polling context instead of in an interrupt context which prevents TX from starving RX. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 2500e8b..f81fff5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1178,17 +1178,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++) { tx_ring = &(adapter->tx_ring[r_idx]); -#ifdef CONFIG_IXGBE_DCA - if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_tx_dca(adapter, tx_ring); -#endif tx_ring->total_bytes = 0; tx_ring->total_packets = 0; - ixgbe_clean_tx_irq(q_vector, tx_ring); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, r_idx + 1); } + /* disable interrupts on this vector only */ + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + napi_schedule(&q_vector->napi); + return IRQ_HANDLED; } @@ -1228,8 +1227,36 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) { - ixgbe_msix_clean_rx(irq, data); - ixgbe_msix_clean_tx(irq, data); + struct ixgbe_q_vector *q_vector = data; + struct ixgbe_adapter *adapter = q_vector->adapter; + struct ixgbe_ring *ring; + int r_idx; + int i; + + if (!q_vector->txr_count && !q_vector->rxr_count) + return IRQ_HANDLED; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + ring = &(adapter->tx_ring[r_idx]); + ring->total_bytes = 0; + ring->total_packets = 0; + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + 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++) { + ring = &(adapter->rx_ring[r_idx]); + ring->total_bytes = 0; + ring->total_packets = 0; + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); + } + + /* disable interrupts on this vector only */ + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + napi_schedule(&q_vector->napi); return IRQ_HANDLED; } @@ -1274,21 +1301,34 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) } /** - * ixgbe_clean_rxonly_many - msix (aka one shot) rx clean routine + * ixgbe_clean_rxtx_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) +static int ixgbe_clean_rxtx_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; + struct ixgbe_ring *ring = NULL; int work_done = 0, i; long r_idx; + bool tx_clean_complete = true; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + ring = &(adapter->tx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + ixgbe_update_tx_dca(adapter, ring); +#endif + tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring); + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + r_idx + 1); + } /* attempt to distribute budget to each queue fairly, but don't allow * the budget to go below 1 because we'll exit polling */ @@ -1296,18 +1336,18 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) 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]); + ring = &(adapter->rx_ring[r_idx]); #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_rx_dca(adapter, rx_ring); + ixgbe_update_rx_dca(adapter, ring); #endif - ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget); + ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget); 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]); + ring = &(adapter->rx_ring[r_idx]); /* If all Rx work done, exit the polling mode */ if (work_done < budget) { napi_complete(napi); @@ -1321,6 +1361,46 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) return work_done; } + +/** + * ixgbe_clean_txonly - msix (aka one shot) tx 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 is optimized for cleaning one queue only on a single + * q_vector!!! + **/ +static int ixgbe_clean_txonly(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 *tx_ring = NULL; + int work_done = 0; + long r_idx; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + tx_ring = &(adapter->tx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + ixgbe_update_tx_dca(adapter, tx_ring); +#endif + + if (!ixgbe_clean_tx_irq(q_vector, tx_ring)) + work_done = budget; + + /* If all Rx work done, exit the polling mode */ + if (work_done < budget) { + napi_complete(napi); + if (adapter->itr_setting & 1) + ixgbe_set_itr_msix(q_vector); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx)); + } + + return work_done; +} + static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, int r_idx) { @@ -2213,12 +2293,15 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) 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 = &q_vector->napi; - if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) && - (q_vector->rxr_count > 1)) - napi->poll = &ixgbe_clean_rxonly_many; + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + if (!q_vector->rxr_count || !q_vector->txr_count) { + if (q_vector->txr_count == 1) + napi->poll = &ixgbe_clean_txonly; + else if (q_vector->rxr_count == 1) + napi->poll = &ixgbe_clean_rxonly; + } + } napi_enable(napi); } @@ -2236,8 +2319,6 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) for (q_idx = 0; q_idx < q_vectors; q_idx++) { q_vector = adapter->q_vector[q_idx]; - if (!q_vector->rxr_count) - continue; napi_disable(&q_vector->napi); } } @@ -3321,7 +3402,7 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; napi_vectors = adapter->num_rx_queues; - poll = &ixgbe_clean_rxonly; + poll = &ixgbe_clean_rxtx_many; } else { num_q_vectors = 1; napi_vectors = 1; @@ -3335,9 +3416,7 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) q_vector->adapter = adapter; q_vector->eitr = adapter->eitr_param; q_vector->v_idx = q_idx; - if (q_idx < napi_vectors) - netif_napi_add(adapter->netdev, &q_vector->napi, - (*poll), 64); + netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64); adapter->q_vector[q_idx] = q_vector; } @@ -3365,22 +3444,16 @@ err_out: static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter) { int q_idx, num_q_vectors; - int napi_vectors; - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - napi_vectors = adapter->num_rx_queues; - } else { + else num_q_vectors = 1; - napi_vectors = 1; - } for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[q_idx]; - adapter->q_vector[q_idx] = NULL; - if (q_idx < napi_vectors) - netif_napi_del(&q_vector->napi); + netif_napi_del(&q_vector->napi); kfree(q_vector); } } -- cgit v0.10.2 From df647b5ca3c3a84e5e5f8e7da36b5ffc17276ec7 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 16:00:47 +0000 Subject: ixgbe: Add a second feature flags variable, move HW RSC capability there This adds a second feature flag variable to use for future feature expansion. Add HW RSC to this new feature flags variable. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 00c303a..59167d7 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -317,10 +317,11 @@ struct ixgbe_adapter { #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) #define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24) #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) -#define IXGBE_FLAG_RSC_CAPABLE (u32)(1 << 26) -#define IXGBE_FLAG_RSC_ENABLED (u32)(1 << 27) #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) + u32 flags2; +#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) +#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 003b6e5..ce9cf7e 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1997,13 +1997,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data) ethtool_op_set_flags(netdev, data); - if (!(adapter->flags & IXGBE_FLAG_RSC_CAPABLE)) + if (!(adapter->flags & IXGBE_FLAG2_RSC_CAPABLE)) return 0; /* if state changes we need to update adapter->flags and reset */ if ((!!(data & ETH_FLAG_LRO)) != - (!!(adapter->flags & IXGBE_FLAG_RSC_ENABLED))) { - adapter->flags ^= IXGBE_FLAG_RSC_ENABLED; + (!!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED))) { + adapter->flags ^= IXGBE_FLAG2_RSC_ENABLED; if (netif_running(netdev)) ixgbe_reinit_locked(adapter); else diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f81fff5..2553173 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -748,7 +748,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, prefetch(next_rxd); cleaned_count++; - if (adapter->flags & IXGBE_FLAG_RSC_CAPABLE) + if (adapter->flags & IXGBE_FLAG2_RSC_CAPABLE) rsc_count = ixgbe_get_rsc_count(rx_desc); if (rsc_count) { @@ -1968,7 +1968,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); } } else { - if (!(adapter->flags & IXGBE_FLAG_RSC_ENABLED) && + if (!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED) && (netdev->mtu <= ETH_DATA_LEN)) rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; else @@ -2097,7 +2097,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); } - if (adapter->flags & IXGBE_FLAG_RSC_ENABLED) { + if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) { /* Enable 82599 HW-RSC */ for (i = 0; i < adapter->num_rx_queues; i++) { j = adapter->rx_ring[i].reg_idx; @@ -3632,8 +3632,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598; } else if (hw->mac.type == ixgbe_mac_82599EB) { adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; - adapter->flags |= IXGBE_FLAG_RSC_CAPABLE; - adapter->flags |= IXGBE_FLAG_RSC_ENABLED; + adapter->flags |= IXGBE_FLAG2_RSC_CAPABLE; + adapter->flags |= IXGBE_FLAG2_RSC_ENABLED; #ifdef IXGBE_FCOE adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; @@ -5323,7 +5323,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - if (adapter->flags & IXGBE_FLAG_RSC_ENABLED) + if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) netdev->features |= NETIF_F_LRO; /* make sure the EEPROM is good */ -- cgit v0.10.2 From bfde493ee279b345d31e3178832971606b5b854f Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 16:01:06 +0000 Subject: ixgbe: Add hardware defines for Flow Director for 82599 Flow Director is a Rx filter mechanism designed to match Rx flows back to the same CPU that the flow's Tx occurred from. This patch adds the first piece, the defines for the hardware registers, to enable this feature in 82599 hardware. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 4402552..68cac36 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -231,6 +231,34 @@ #define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ +/* Flow Director registers */ +#define IXGBE_FDIRCTRL 0x0EE00 +#define IXGBE_FDIRHKEY 0x0EE68 +#define IXGBE_FDIRSKEY 0x0EE6C +#define IXGBE_FDIRDIP4M 0x0EE3C +#define IXGBE_FDIRSIP4M 0x0EE40 +#define IXGBE_FDIRTCPM 0x0EE44 +#define IXGBE_FDIRUDPM 0x0EE48 +#define IXGBE_FDIRIP6M 0x0EE74 +#define IXGBE_FDIRM 0x0EE70 + +/* Flow Director Stats registers */ +#define IXGBE_FDIRFREE 0x0EE38 +#define IXGBE_FDIRLEN 0x0EE4C +#define IXGBE_FDIRUSTAT 0x0EE50 +#define IXGBE_FDIRFSTAT 0x0EE54 +#define IXGBE_FDIRMATCH 0x0EE58 +#define IXGBE_FDIRMISS 0x0EE5C + +/* Flow Director Programming registers */ +#define IXGBE_FDIRSIPv6(_i) (0x0EE0C + ((_i) * 4)) /* 3 of these (0-2) */ +#define IXGBE_FDIRIPSA 0x0EE18 +#define IXGBE_FDIRIPDA 0x0EE1C +#define IXGBE_FDIRPORT 0x0EE20 +#define IXGBE_FDIRVLAN 0x0EE24 +#define IXGBE_FDIRHASH 0x0EE28 +#define IXGBE_FDIRCMD 0x0EE2C + /* Transmit DMA registers */ #define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/ #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) @@ -1652,6 +1680,9 @@ #define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */ #define IXGBE_RXDADV_ERR_FCEOFE 0x80000000 /* FCoEFe/IPE */ #define IXGBE_RXDADV_ERR_FCERR 0x00700000 /* FCERR/FDIRERR */ +#define IXGBE_RXDADV_ERR_FDIR_LEN 0x00100000 /* FDIR Length error */ +#define IXGBE_RXDADV_ERR_FDIR_DROP 0x00200000 /* FDIR Drop error */ +#define IXGBE_RXDADV_ERR_FDIR_COLL 0x00400000 /* FDIR Collision error */ #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 */ @@ -1784,6 +1815,82 @@ #endif +enum ixgbe_fdir_pballoc_type { + IXGBE_FDIR_PBALLOC_64K = 0, + IXGBE_FDIR_PBALLOC_128K, + IXGBE_FDIR_PBALLOC_256K, +}; +#define IXGBE_FDIR_PBALLOC_SIZE_SHIFT 16 + +/* Flow Director register values */ +#define IXGBE_FDIRCTRL_PBALLOC_64K 0x00000001 +#define IXGBE_FDIRCTRL_PBALLOC_128K 0x00000002 +#define IXGBE_FDIRCTRL_PBALLOC_256K 0x00000003 +#define IXGBE_FDIRCTRL_INIT_DONE 0x00000008 +#define IXGBE_FDIRCTRL_PERFECT_MATCH 0x00000010 +#define IXGBE_FDIRCTRL_REPORT_STATUS 0x00000020 +#define IXGBE_FDIRCTRL_REPORT_STATUS_ALWAYS 0x00000080 +#define IXGBE_FDIRCTRL_DROP_Q_SHIFT 8 +#define IXGBE_FDIRCTRL_FLEX_SHIFT 16 +#define IXGBE_FDIRCTRL_SEARCHLIM 0x00800000 +#define IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT 24 +#define IXGBE_FDIRCTRL_FULL_THRESH_MASK 0xF0000000 +#define IXGBE_FDIRCTRL_FULL_THRESH_SHIFT 28 + +#define IXGBE_FDIRTCPM_DPORTM_SHIFT 16 +#define IXGBE_FDIRUDPM_DPORTM_SHIFT 16 +#define IXGBE_FDIRIP6M_DIPM_SHIFT 16 +#define IXGBE_FDIRM_VLANID 0x00000001 +#define IXGBE_FDIRM_VLANP 0x00000002 +#define IXGBE_FDIRM_POOL 0x00000004 +#define IXGBE_FDIRM_L3P 0x00000008 +#define IXGBE_FDIRM_L4P 0x00000010 +#define IXGBE_FDIRM_FLEX 0x00000020 +#define IXGBE_FDIRM_DIPv6 0x00000040 + +#define IXGBE_FDIRFREE_FREE_MASK 0xFFFF +#define IXGBE_FDIRFREE_FREE_SHIFT 0 +#define IXGBE_FDIRFREE_COLL_MASK 0x7FFF0000 +#define IXGBE_FDIRFREE_COLL_SHIFT 16 +#define IXGBE_FDIRLEN_MAXLEN_MASK 0x3F +#define IXGBE_FDIRLEN_MAXLEN_SHIFT 0 +#define IXGBE_FDIRLEN_MAXHASH_MASK 0x7FFF0000 +#define IXGBE_FDIRLEN_MAXHASH_SHIFT 16 +#define IXGBE_FDIRUSTAT_ADD_MASK 0xFFFF +#define IXGBE_FDIRUSTAT_ADD_SHIFT 0 +#define IXGBE_FDIRUSTAT_REMOVE_MASK 0xFFFF0000 +#define IXGBE_FDIRUSTAT_REMOVE_SHIFT 16 +#define IXGBE_FDIRFSTAT_FADD_MASK 0x00FF +#define IXGBE_FDIRFSTAT_FADD_SHIFT 0 +#define IXGBE_FDIRFSTAT_FREMOVE_MASK 0xFF00 +#define IXGBE_FDIRFSTAT_FREMOVE_SHIFT 8 +#define IXGBE_FDIRPORT_DESTINATION_SHIFT 16 +#define IXGBE_FDIRVLAN_FLEX_SHIFT 16 +#define IXGBE_FDIRHASH_BUCKET_VALID_SHIFT 15 +#define IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT 16 + +#define IXGBE_FDIRCMD_CMD_MASK 0x00000003 +#define IXGBE_FDIRCMD_CMD_ADD_FLOW 0x00000001 +#define IXGBE_FDIRCMD_CMD_REMOVE_FLOW 0x00000002 +#define IXGBE_FDIRCMD_CMD_QUERY_REM_FILT 0x00000003 +#define IXGBE_FDIRCMD_CMD_QUERY_REM_HASH 0x00000007 +#define IXGBE_FDIRCMD_FILTER_UPDATE 0x00000008 +#define IXGBE_FDIRCMD_IPv6DMATCH 0x00000010 +#define IXGBE_FDIRCMD_L4TYPE_UDP 0x00000020 +#define IXGBE_FDIRCMD_L4TYPE_TCP 0x00000040 +#define IXGBE_FDIRCMD_L4TYPE_SCTP 0x00000060 +#define IXGBE_FDIRCMD_IPV6 0x00000080 +#define IXGBE_FDIRCMD_CLEARHT 0x00000100 +#define IXGBE_FDIRCMD_DROP 0x00000200 +#define IXGBE_FDIRCMD_INT 0x00000400 +#define IXGBE_FDIRCMD_LAST 0x00000800 +#define IXGBE_FDIRCMD_COLLISION 0x00001000 +#define IXGBE_FDIRCMD_QUEUE_EN 0x00008000 +#define IXGBE_FDIRCMD_RX_QUEUE_SHIFT 16 +#define IXGBE_FDIRCMD_VT_POOL_SHIFT 24 +#define IXGBE_FDIR_INIT_DONE_POLL 10 +#define IXGBE_FDIRCMD_CMD_POLL 10 + /* Transmit Descriptor - Legacy */ struct ixgbe_legacy_tx_desc { u64 buffer_addr; /* Address of the descriptor's data buffer */ @@ -1957,6 +2064,45 @@ typedef u32 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x0800 #define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000 +/* Software ATR hash keys */ +#define IXGBE_ATR_BUCKET_HASH_KEY 0xE214AD3D +#define IXGBE_ATR_SIGNATURE_HASH_KEY 0x14364D17 + +/* Software ATR input stream offsets and masks */ +#define IXGBE_ATR_VLAN_OFFSET 0 +#define IXGBE_ATR_SRC_IPV6_OFFSET 2 +#define IXGBE_ATR_SRC_IPV4_OFFSET 14 +#define IXGBE_ATR_DST_IPV6_OFFSET 18 +#define IXGBE_ATR_DST_IPV4_OFFSET 30 +#define IXGBE_ATR_SRC_PORT_OFFSET 34 +#define IXGBE_ATR_DST_PORT_OFFSET 36 +#define IXGBE_ATR_FLEX_BYTE_OFFSET 38 +#define IXGBE_ATR_VM_POOL_OFFSET 40 +#define IXGBE_ATR_L4TYPE_OFFSET 41 + +#define IXGBE_ATR_L4TYPE_MASK 0x3 +#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4 +#define IXGBE_ATR_L4TYPE_UDP 0x1 +#define IXGBE_ATR_L4TYPE_TCP 0x2 +#define IXGBE_ATR_L4TYPE_SCTP 0x3 +#define IXGBE_ATR_HASH_MASK 0x7fff + +/* Flow Director ATR input struct. */ +struct ixgbe_atr_input { + /* Byte layout in order, all values with MSB first: + * + * vlan_id - 2 bytes + * src_ip - 16 bytes + * dst_ip - 16 bytes + * src_port - 2 bytes + * dst_port - 2 bytes + * flex_bytes - 2 bytes + * vm_pool - 1 byte + * l4type - 1 byte + */ + u8 byte_stream[42]; +}; + enum ixgbe_eeprom_type { ixgbe_eeprom_uninitialized = 0, ixgbe_eeprom_spi, @@ -2348,6 +2494,7 @@ struct ixgbe_info { #define IXGBE_ERR_SFP_NOT_SUPPORTED -19 #define IXGBE_ERR_SFP_NOT_PRESENT -20 #define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT -21 +#define IXGBE_ERR_FDIR_REINIT_FAILED -23 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ -- cgit v0.10.2 From ffff47720318860933b2af84d1912af8b2e621f2 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 16:01:25 +0000 Subject: ixgbe: Add Flow Director init and modify functions for 82599 This patch adds the functions for ixgbe to initialize Flow Director. It also has the function APIs to add Flow Director filters from the base driver. This also includes ATR, Application Targeted Routing, which is a feature set of Flow Director. This is the hash-based mechanism to automatically identify flows and add filters based on the hash, and direct the Rx of that flow back to that same CPU. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 59167d7..7adf959 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -402,6 +402,61 @@ extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); extern void ixgbe_write_eitr(struct ixgbe_q_vector *); extern int ethtool_ioctl(struct ifreq *ifr); +extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw); +extern s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc); +extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc); +extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u8 queue); +extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue); +extern u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *input, u32 key); +extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, + u16 vlan_id); +extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 src_addr); +extern s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 dst_addr); +extern s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4); +extern s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4); +extern s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, + u16 src_port); +extern s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, + u16 dst_port); +extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, + u16 flex_byte); +extern s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, + u8 vm_pool); +extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, + u8 l4type); +extern s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, + u16 *vlan_id); +extern s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 *src_addr); +extern s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 *dst_addr); +extern s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4); +extern s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4); +extern s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, + u16 *src_port); +extern s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, + u16 *dst_port); +extern s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, + u16 *flex_byte); +extern s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, + u8 *vm_pool); +extern s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, + u8 *l4type); #ifdef IXGBE_FCOE extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 3f36d83..5c2627b 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1165,6 +1165,931 @@ s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw) } /** + * ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables. + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) +{ + int i; + u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); + fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE; + + /* + * Before starting reinitialization process, + * FDIRCMD.CMD must be zero. + */ + for (i = 0; i < IXGBE_FDIRCMD_CMD_POLL; i++) { + if (!(IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & + IXGBE_FDIRCMD_CMD_MASK)) + break; + udelay(10); + } + if (i >= IXGBE_FDIRCMD_CMD_POLL) { + hw_dbg(hw ,"Flow Director previous command isn't complete, " + "aborting table re-initialization. \n"); + return IXGBE_ERR_FDIR_REINIT_FAILED; + } + + IXGBE_WRITE_REG(hw, IXGBE_FDIRFREE, 0); + IXGBE_WRITE_FLUSH(hw); + /* + * 82599 adapters flow director init flow cannot be restarted, + * Workaround 82599 silicon errata by performing the following steps + * before re-writing the FDIRCTRL control register with the same value. + * - write 1 to bit 8 of FDIRCMD register & + * - write 0 to bit 8 of FDIRCMD register + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, + (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) | + IXGBE_FDIRCMD_CLEARHT)); + IXGBE_WRITE_FLUSH(hw); + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, + (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & + ~IXGBE_FDIRCMD_CLEARHT)); + IXGBE_WRITE_FLUSH(hw); + /* + * Clear FDIR Hash register to clear any leftover hashes + * waiting to be programmed. + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, 0x00); + IXGBE_WRITE_FLUSH(hw); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + + /* Poll init-done after we write FDIRCTRL register */ + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + udelay(10); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) { + hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); + return IXGBE_ERR_FDIR_REINIT_FAILED; + } + + /* Clear FDIR statistics registers (read to clear) */ + IXGBE_READ_REG(hw, IXGBE_FDIRUSTAT); + IXGBE_READ_REG(hw, IXGBE_FDIRFSTAT); + IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); + IXGBE_READ_REG(hw, IXGBE_FDIRMISS); + IXGBE_READ_REG(hw, IXGBE_FDIRLEN); + + return 0; +} + +/** + * ixgbe_init_fdir_signature_82599 - Initialize Flow Director signature filters + * @hw: pointer to hardware structure + * @pballoc: which mode to allocate filters with + **/ +s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) +{ + u32 fdirctrl = 0; + u32 pbsize; + int i; + + /* + * Before enabling Flow Director, the Rx Packet Buffer size + * must be reduced. The new value is the current size minus + * flow director memory usage size. + */ + pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc)); + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), + (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize)); + + /* + * The defaults in the HW for RX PB 1-7 are not zero and so should be + * intialized to zero for non DCB mode otherwise actual total RX PB + * would be bigger than programmed and filter space would run into + * the PB 0 region. + */ + for (i = 1; i < 8; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + + /* Send interrupt when 64 filters are left */ + fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT; + + /* Set the maximum length per hash bucket to 0xA filters */ + fdirctrl |= 0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT; + + switch (pballoc) { + case IXGBE_FDIR_PBALLOC_64K: + /* 8k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K; + break; + case IXGBE_FDIR_PBALLOC_128K: + /* 16k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K; + break; + case IXGBE_FDIR_PBALLOC_256K: + /* 32k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K; + break; + default: + /* bad value */ + return IXGBE_ERR_CONFIG; + }; + + /* Move the flexible bytes to use the ethertype - shift 6 words */ + fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT); + + fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS; + + /* Prime the keys for hashing */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, + htonl(IXGBE_ATR_BUCKET_HASH_KEY)); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, + htonl(IXGBE_ATR_SIGNATURE_HASH_KEY)); + + /* + * Poll init-done after we write the register. Estimated times: + * 10G: PBALLOC = 11b, timing is 60us + * 1G: PBALLOC = 11b, timing is 600us + * 100M: PBALLOC = 11b, timing is 6ms + * + * Multiple these timings by 4 if under full Rx load + * + * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for + * 1 msec per poll time. If we're at line rate and drop to 100M, then + * this might not finish in our poll time, but we can live with that + * for now. + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + msleep(1); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) + hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); + + return 0; +} + +/** + * ixgbe_init_fdir_perfect_82599 - Initialize Flow Director perfect filters + * @hw: pointer to hardware structure + * @pballoc: which mode to allocate filters with + **/ +s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) +{ + u32 fdirctrl = 0; + u32 pbsize; + int i; + + /* + * Before enabling Flow Director, the Rx Packet Buffer size + * must be reduced. The new value is the current size minus + * flow director memory usage size. + */ + pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc)); + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), + (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize)); + + /* + * The defaults in the HW for RX PB 1-7 are not zero and so should be + * intialized to zero for non DCB mode otherwise actual total RX PB + * would be bigger than programmed and filter space would run into + * the PB 0 region. + */ + for (i = 1; i < 8; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + + /* Send interrupt when 64 filters are left */ + fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT; + + switch (pballoc) { + case IXGBE_FDIR_PBALLOC_64K: + /* 2k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K; + break; + case IXGBE_FDIR_PBALLOC_128K: + /* 4k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K; + break; + case IXGBE_FDIR_PBALLOC_256K: + /* 8k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K; + break; + default: + /* bad value */ + return IXGBE_ERR_CONFIG; + }; + + /* Turn perfect match filtering on */ + fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH; + fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS; + + /* Move the flexible bytes to use the ethertype - shift 6 words */ + fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT); + + /* Prime the keys for hashing */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, + htonl(IXGBE_ATR_BUCKET_HASH_KEY)); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, + htonl(IXGBE_ATR_SIGNATURE_HASH_KEY)); + + /* + * Poll init-done after we write the register. Estimated times: + * 10G: PBALLOC = 11b, timing is 60us + * 1G: PBALLOC = 11b, timing is 600us + * 100M: PBALLOC = 11b, timing is 6ms + * + * Multiple these timings by 4 if under full Rx load + * + * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for + * 1 msec per poll time. If we're at line rate and drop to 100M, then + * this might not finish in our poll time, but we can live with that + * for now. + */ + + /* Set the maximum length per hash bucket to 0xA filters */ + fdirctrl |= (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + msleep(1); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) + hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n"); + + return 0; +} + + +/** + * ixgbe_atr_compute_hash_82599 - Compute the hashes for SW ATR + * @stream: input bitstream to compute the hash on + * @key: 32-bit hash key + **/ +u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, u32 key) +{ + /* + * The algorithm is as follows: + * Hash[15:0] = Sum { S[n] x K[n+16] }, n = 0...350 + * where Sum {A[n]}, n = 0...n is bitwise XOR of A[0], A[1]...A[n] + * and A[n] x B[n] is bitwise AND between same length strings + * + * K[n] is 16 bits, defined as: + * for n modulo 32 >= 15, K[n] = K[n % 32 : (n % 32) - 15] + * for n modulo 32 < 15, K[n] = + * K[(n % 32:0) | (31:31 - (14 - (n % 32)))] + * + * S[n] is 16 bits, defined as: + * for n >= 15, S[n] = S[n:n - 15] + * for n < 15, S[n] = S[(n:0) | (350:350 - (14 - n))] + * + * To simplify for programming, the algorithm is implemented + * in software this way: + * + * Key[31:0], Stream[335:0] + * + * tmp_key[11 * 32 - 1:0] = 11{Key[31:0] = key concatenated 11 times + * int_key[350:0] = tmp_key[351:1] + * int_stream[365:0] = Stream[14:0] | Stream[335:0] | Stream[335:321] + * + * hash[15:0] = 0; + * for (i = 0; i < 351; i++) { + * if (int_key[i]) + * hash ^= int_stream[(i + 15):i]; + * } + */ + + union { + u64 fill[6]; + u32 key[11]; + u8 key_stream[44]; + } tmp_key; + + u8 *stream = (u8 *)atr_input; + u8 int_key[44]; /* upper-most bit unused */ + u8 hash_str[46]; /* upper-most 2 bits unused */ + u16 hash_result = 0; + int i, j, k, h; + + /* + * Initialize the fill member to prevent warnings + * on some compilers + */ + tmp_key.fill[0] = 0; + + /* First load the temporary key stream */ + for (i = 0; i < 6; i++) { + u64 fillkey = ((u64)key << 32) | key; + tmp_key.fill[i] = fillkey; + } + + /* + * Set the interim key for the hashing. Bit 352 is unused, so we must + * shift and compensate when building the key. + */ + + int_key[0] = tmp_key.key_stream[0] >> 1; + for (i = 1, j = 0; i < 44; i++) { + unsigned int this_key = tmp_key.key_stream[j] << 7; + j++; + int_key[i] = (u8)(this_key | (tmp_key.key_stream[j] >> 1)); + } + + /* + * Set the interim bit string for the hashing. Bits 368 and 367 are + * unused, so shift and compensate when building the string. + */ + hash_str[0] = (stream[40] & 0x7f) >> 1; + for (i = 1, j = 40; i < 46; i++) { + unsigned int this_str = stream[j] << 7; + j++; + if (j > 41) + j = 0; + hash_str[i] = (u8)(this_str | (stream[j] >> 1)); + } + + /* + * Now compute the hash. i is the index into hash_str, j is into our + * key stream, k is counting the number of bits, and h interates within + * each byte. + */ + for (i = 45, j = 43, k = 0; k < 351 && i >= 2 && j >= 0; i--, j--) { + for (h = 0; h < 8 && k < 351; h++, k++) { + if (int_key[j] & (1 << h)) { + /* + * Key bit is set, XOR in the current 16-bit + * string. Example of processing: + * h = 0, + * tmp = (hash_str[i - 2] & 0 << 16) | + * (hash_str[i - 1] & 0xff << 8) | + * (hash_str[i] & 0xff >> 0) + * So tmp = hash_str[15 + k:k], since the + * i + 2 clause rolls off the 16-bit value + * h = 7, + * tmp = (hash_str[i - 2] & 0x7f << 9) | + * (hash_str[i - 1] & 0xff << 1) | + * (hash_str[i] & 0x80 >> 7) + */ + int tmp = (hash_str[i] >> h); + tmp |= (hash_str[i - 1] << (8 - h)); + tmp |= (int)(hash_str[i - 2] & ((1 << h) - 1)) + << (16 - h); + hash_result ^= (u16)tmp; + } + } + } + + return hash_result; +} + +/** + * ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream + * @input: input stream to modify + * @vlan: the VLAN id to load + **/ +s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan) +{ + input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] = vlan >> 8; + input->byte_stream[IXGBE_ATR_VLAN_OFFSET] = vlan & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address + * @input: input stream to modify + * @src_addr: the IP address to load + **/ +s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr) +{ + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] = src_addr >> 24; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] = + (src_addr >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] = + (src_addr >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET] = src_addr & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address + * @input: input stream to modify + * @dst_addr: the IP address to load + **/ +s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr) +{ + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] = dst_addr >> 24; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] = + (dst_addr >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] = + (dst_addr >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET] = dst_addr & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_src_ipv6_82599 - Sets the source IPv6 address + * @input: input stream to modify + * @src_addr_1: the first 4 bytes of the IP address to load + * @src_addr_2: the second 4 bytes of the IP address to load + * @src_addr_3: the third 4 bytes of the IP address to load + * @src_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4) +{ + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] = + (src_addr_4 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] = + (src_addr_4 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] = src_addr_4 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4] = src_addr_3 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] = + (src_addr_3 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] = + (src_addr_3 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] = src_addr_3 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8] = src_addr_2 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] = + (src_addr_2 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] = + (src_addr_2 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] = src_addr_2 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12] = src_addr_1 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] = + (src_addr_1 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] = + (src_addr_1 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] = src_addr_1 >> 24; + + return 0; +} + +/** + * ixgbe_atr_set_dst_ipv6_82599 - Sets the destination IPv6 address + * @input: input stream to modify + * @dst_addr_1: the first 4 bytes of the IP address to load + * @dst_addr_2: the second 4 bytes of the IP address to load + * @dst_addr_3: the third 4 bytes of the IP address to load + * @dst_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4) +{ + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] = + (dst_addr_4 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] = + (dst_addr_4 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] = dst_addr_4 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4] = dst_addr_3 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] = + (dst_addr_3 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] = + (dst_addr_3 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] = dst_addr_3 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8] = dst_addr_2 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] = + (dst_addr_2 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] = + (dst_addr_2 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] = dst_addr_2 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12] = dst_addr_1 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] = + (dst_addr_1 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] = + (dst_addr_1 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] = dst_addr_1 >> 24; + + return 0; +} + +/** + * ixgbe_atr_set_src_port_82599 - Sets the source port + * @input: input stream to modify + * @src_port: the source port to load + **/ +s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port) +{ + input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1] = src_port >> 8; + input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] = src_port & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_dst_port_82599 - Sets the destination port + * @input: input stream to modify + * @dst_port: the destination port to load + **/ +s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port) +{ + input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1] = dst_port >> 8; + input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] = dst_port & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_flex_byte_82599 - Sets the flexible bytes + * @input: input stream to modify + * @flex_bytes: the flexible bytes to load + **/ +s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte) +{ + input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] = flex_byte >> 8; + input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET] = flex_byte & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_vm_pool_82599 - Sets the Virtual Machine pool + * @input: input stream to modify + * @vm_pool: the Virtual Machine pool to load + **/ +s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, u8 vm_pool) +{ + input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool; + + return 0; +} + +/** + * ixgbe_atr_set_l4type_82599 - Sets the layer 4 packet type + * @input: input stream to modify + * @l4type: the layer 4 type value to load + **/ +s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type) +{ + input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET] = l4type; + + return 0; +} + +/** + * ixgbe_atr_get_vlan_id_82599 - Gets the VLAN id from the ATR input stream + * @input: input stream to search + * @vlan: the VLAN id to load + **/ +s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) +{ + *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET]; + *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8; + + return 0; +} + +/** + * ixgbe_atr_get_src_ipv4_82599 - Gets the source IPv4 address + * @input: input stream to search + * @src_addr: the IP address to load + **/ +s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr) +{ + *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET]; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] << 16; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_dst_ipv4_82599 - Gets the destination IPv4 address + * @input: input stream to search + * @dst_addr: the IP address to load + **/ +s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr) +{ + *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET]; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] << 16; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_src_ipv6_82599 - Gets the source IPv6 address + * @input: input stream to search + * @src_addr_1: the first 4 bytes of the IP address to load + * @src_addr_2: the second 4 bytes of the IP address to load + * @src_addr_3: the third 4 bytes of the IP address to load + * @src_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4) +{ + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12]; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] << 16; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] << 24; + + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8]; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] << 8; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] << 16; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] << 24; + + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4]; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] << 8; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] << 16; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] << 24; + + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET]; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] << 8; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] << 16; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_dst_ipv6_82599 - Gets the destination IPv6 address + * @input: input stream to search + * @dst_addr_1: the first 4 bytes of the IP address to load + * @dst_addr_2: the second 4 bytes of the IP address to load + * @dst_addr_3: the third 4 bytes of the IP address to load + * @dst_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4) +{ + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12]; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] << 8; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] << 16; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] << 24; + + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8]; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] << 8; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] << 16; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] << 24; + + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4]; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] << 8; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] << 16; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] << 24; + + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET]; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] << 8; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] << 16; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_src_port_82599 - Gets the source port + * @input: input stream to modify + * @src_port: the source port to load + * + * Even though the input is given in big-endian, the FDIRPORT registers + * expect the ports to be programmed in little-endian. Hence the need to swap + * endianness when retrieving the data. This can be confusing since the + * internal hash engine expects it to be big-endian. + **/ +s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port) +{ + *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8; + *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1]; + + return 0; +} + +/** + * ixgbe_atr_get_dst_port_82599 - Gets the destination port + * @input: input stream to modify + * @dst_port: the destination port to load + * + * Even though the input is given in big-endian, the FDIRPORT registers + * expect the ports to be programmed in little-endian. Hence the need to swap + * endianness when retrieving the data. This can be confusing since the + * internal hash engine expects it to be big-endian. + **/ +s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port) +{ + *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8; + *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1]; + + return 0; +} + +/** + * ixgbe_atr_get_flex_byte_82599 - Gets the flexible bytes + * @input: input stream to modify + * @flex_bytes: the flexible bytes to load + **/ +s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte) +{ + *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET]; + *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8; + + return 0; +} + +/** + * ixgbe_atr_get_vm_pool_82599 - Gets the Virtual Machine pool + * @input: input stream to modify + * @vm_pool: the Virtual Machine pool to load + **/ +s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool) +{ + *vm_pool = input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET]; + + return 0; +} + +/** + * ixgbe_atr_get_l4type_82599 - Gets the layer 4 packet type + * @input: input stream to modify + * @l4type: the layer 4 type value to load + **/ +s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, u8 *l4type) +{ + *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET]; + + return 0; +} + +/** + * ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter + * @hw: pointer to hardware structure + * @stream: input bitstream + * @queue: queue index to direct traffic to + **/ +s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u8 queue) +{ + u64 fdirhashcmd; + u64 fdircmd; + u32 fdirhash; + u16 bucket_hash, sig_hash; + u8 l4type; + + bucket_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_BUCKET_HASH_KEY); + + /* bucket_hash is only 15 bits */ + bucket_hash &= IXGBE_ATR_HASH_MASK; + + sig_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_SIGNATURE_HASH_KEY); + + /* Get the l4type in order to program FDIRCMD properly */ + /* lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 */ + ixgbe_atr_get_l4type_82599(input, &l4type); + + /* + * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits + * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH. + */ + fdirhash = sig_hash << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash; + + fdircmd = (IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE | + IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN); + + switch (l4type & IXGBE_ATR_L4TYPE_MASK) { + case IXGBE_ATR_L4TYPE_TCP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP; + break; + case IXGBE_ATR_L4TYPE_UDP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP; + break; + case IXGBE_ATR_L4TYPE_SCTP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP; + break; + default: + hw_dbg(hw, "Error on l4type input\n"); + return IXGBE_ERR_CONFIG; + } + + if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) + fdircmd |= IXGBE_FDIRCMD_IPV6; + + fdircmd |= ((u64)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT); + fdirhashcmd = ((fdircmd << 32) | fdirhash); + + IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd); + + return 0; +} + +/** + * ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter + * @hw: pointer to hardware structure + * @input: input bitstream + * @queue: queue index to direct traffic to + * + * Note that the caller to this function must lock before calling, since the + * hardware writes must be protected from one another. + **/ +s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue) +{ + u32 fdircmd = 0; + u32 fdirhash; + u32 src_ipv4, dst_ipv4; + u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4; + u16 src_port, dst_port, vlan_id, flex_bytes; + u16 bucket_hash; + u8 l4type; + + /* Get our input values */ + ixgbe_atr_get_l4type_82599(input, &l4type); + + /* + * Check l4type formatting, and bail out before we touch the hardware + * if there's a configuration issue + */ + switch (l4type & IXGBE_ATR_L4TYPE_MASK) { + case IXGBE_ATR_L4TYPE_TCP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP; + break; + case IXGBE_ATR_L4TYPE_UDP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP; + break; + case IXGBE_ATR_L4TYPE_SCTP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP; + break; + default: + hw_dbg(hw, "Error on l4type input\n"); + return IXGBE_ERR_CONFIG; + } + + bucket_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_BUCKET_HASH_KEY); + + /* bucket_hash is only 15 bits */ + bucket_hash &= IXGBE_ATR_HASH_MASK; + + ixgbe_atr_get_vlan_id_82599(input, &vlan_id); + ixgbe_atr_get_src_port_82599(input, &src_port); + ixgbe_atr_get_dst_port_82599(input, &dst_port); + ixgbe_atr_get_flex_byte_82599(input, &flex_bytes); + + fdirhash = soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash; + + /* Now figure out if we're IPv4 or IPv6 */ + if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) { + /* IPv6 */ + ixgbe_atr_get_src_ipv6_82599(input, &src_ipv6_1, &src_ipv6_2, + &src_ipv6_3, &src_ipv6_4); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(0), src_ipv6_1); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(1), src_ipv6_2); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(2), src_ipv6_3); + /* The last 4 bytes is the same register as IPv4 */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv6_4); + + fdircmd |= IXGBE_FDIRCMD_IPV6; + fdircmd |= IXGBE_FDIRCMD_IPv6DMATCH; + } else { + /* IPv4 */ + ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4); + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4); + + } + + ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4); + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPDA, dst_ipv4); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id | + (flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT))); + IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port | + (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT))); + + fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW; + fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE; + fdircmd |= IXGBE_FDIRCMD_LAST; + fdircmd |= IXGBE_FDIRCMD_QUEUE_EN; + fdircmd |= queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT; + + IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash); + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd); + + return 0; +} +/** * ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register * @hw: pointer to hardware structure * @reg: analog register to read -- cgit v0.10.2 From c4cf55e5d2e9353c6054eb0e22fc1d0a9a48f045 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 16:01:43 +0000 Subject: ixgbe: Enable Flow Director hashing in 82599 This patch enables Flow Director's ATR functionality to the main base driver for 82599. Signed-off-by: Peter P Waskiewicz Jr Acked-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 7adf959..f2206e2 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -126,6 +126,8 @@ struct ixgbe_ring { unsigned int count; /* amount of descriptors */ unsigned int next_to_use; unsigned int next_to_clean; + u8 atr_sample_rate; + u8 atr_count; int queue_index; /* needed for multiqueue queue management */ union { @@ -148,6 +150,7 @@ struct ixgbe_ring { int cpu; #endif struct ixgbe_queue_stats stats; + unsigned long reinit_state; u16 work_limit; /* max work per interrupt */ u16 rx_buf_len; @@ -159,6 +162,7 @@ enum ixgbe_ring_f_enum { RING_F_DCB, RING_F_VMDQ, RING_F_RSS, + RING_F_FDIR, #ifdef IXGBE_FCOE RING_F_FCOE, #endif /* IXGBE_FCOE */ @@ -169,6 +173,7 @@ enum ixgbe_ring_f_enum { #define IXGBE_MAX_DCB_INDICES 8 #define IXGBE_MAX_RSS_INDICES 16 #define IXGBE_MAX_VMDQ_INDICES 16 +#define IXGBE_MAX_FDIR_INDICES 64 #ifdef IXGBE_FCOE #define IXGBE_MAX_FCOE_INDICES 8 #endif /* IXGBE_FCOE */ @@ -317,6 +322,8 @@ struct ixgbe_adapter { #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) #define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24) #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) +#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27) #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) u32 flags2; @@ -356,6 +363,10 @@ struct ixgbe_adapter { struct timer_list sfp_timer; struct work_struct multispeed_fiber_task; struct work_struct sfp_config_module_task; + u32 fdir_pballoc; + u32 atr_sample_rate; + spinlock_t fdir_perfect_lock; + struct work_struct fdir_reinit_task; #ifdef IXGBE_FCOE struct ixgbe_fcoe fcoe; #endif /* IXGBE_FCOE */ @@ -368,6 +379,7 @@ enum ixbge_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, __IXGBE_DOWN, + __IXGBE_FDIR_INIT_DONE, __IXGBE_SFP_MODULE_NOT_FOUND }; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index ce9cf7e..86f4f3e 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -68,6 +68,8 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)}, {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)}, {"hw_rsc_count", IXGBE_STAT(rsc_count)}, + {"fdir_match", IXGBE_STAT(stats.fdirmatch)}, + {"fdir_miss", IXGBE_STAT(stats.fdirmiss)}, {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)}, {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)}, {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)}, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 2553173..ca7c5d5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1123,8 +1123,24 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (hw->mac.type == ixgbe_mac_82598EB) ixgbe_check_fan_failure(adapter, eicr); - if (hw->mac.type == ixgbe_mac_82599EB) + if (hw->mac.type == ixgbe_mac_82599EB) { ixgbe_check_sfp_event(adapter, eicr); + + /* Handle Flow Director Full threshold interrupt */ + if (eicr & IXGBE_EICR_FLOW_DIR) { + int i; + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR); + /* Disable transmits before FDIR Re-initialization */ + netif_tx_stop_all_queues(netdev); + for (i = 0; i < adapter->num_tx_queues; i++) { + struct ixgbe_ring *tx_ring = + &adapter->tx_ring[i]; + if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE, + &tx_ring->reinit_state)) + schedule_work(&adapter->fdir_reinit_task); + } + } + } if (!test_bit(__IXGBE_DOWN, &adapter->state)) IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); @@ -1623,6 +1639,9 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) mask |= IXGBE_EIMS_GPI_SDP1; mask |= IXGBE_EIMS_GPI_SDP2; } + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + mask |= IXGBE_EIMS_FLOW_DIR; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); ixgbe_irq_enable_queues(adapter, ~0); @@ -2376,6 +2395,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) static void ixgbe_configure(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; int i; ixgbe_set_rx_mode(netdev); @@ -2397,6 +2417,15 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) ixgbe_configure_fcoe(adapter); #endif /* IXGBE_FCOE */ + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) { + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].atr_sample_rate = + adapter->atr_sample_rate; + ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc); + } else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) { + ixgbe_init_fdir_perfect_82599(hw, adapter->fdir_pballoc); + } + ixgbe_configure_tx(adapter); ixgbe_configure_rx(adapter); for (i = 0; i < adapter->num_rx_queues; i++) @@ -2653,6 +2682,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err); } + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_FDIR_INIT_DONE, + &(adapter->tx_ring[i].reinit_state)); + /* enable transmits */ netif_tx_start_all_queues(netdev); @@ -2848,6 +2881,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); cancel_work_sync(&adapter->watchdog_task); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + cancel_work_sync(&adapter->fdir_reinit_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; @@ -2982,6 +3019,38 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) return ret; } +/** + * ixgbe_set_fdir_queues: Allocate queues for Flow Director + * @adapter: board private structure to initialize + * + * Flow Director is an advanced Rx filter, attempting to get Rx flows back + * to the original CPU that initiated the Tx session. This runs in addition + * to RSS, so if a packet doesn't match an FDIR filter, we can still spread the + * Rx load across CPUs using RSS. + * + **/ +static bool inline ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter) +{ + bool ret = false; + struct ixgbe_ring_feature *f_fdir = &adapter->ring_feature[RING_F_FDIR]; + + f_fdir->indices = min((int)num_online_cpus(), f_fdir->indices); + f_fdir->mask = 0; + + /* Flow Director must have RSS enabled */ + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED && + ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)))) { + adapter->num_tx_queues = f_fdir->indices; + adapter->num_rx_queues = f_fdir->indices; + ret = true; + } else { + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + } + return ret; +} + #ifdef IXGBE_FCOE /** * ixgbe_set_fcoe_queues: Allocate queues for Fiber Channel over Ethernet (FCoE) @@ -3046,6 +3115,9 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) goto done; #endif + if (ixgbe_set_fdir_queues(adapter)) + goto done; + if (ixgbe_set_rss_queues(adapter)) goto done; @@ -3216,6 +3288,31 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter) } #endif +/** + * ixgbe_cache_ring_fdir - Descriptor ring to register mapping for Flow Director + * @adapter: board private structure to initialize + * + * Cache the descriptor ring offsets for Flow Director to the assigned rings. + * + **/ +static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter) +{ + int i; + bool ret = false; + + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED && + ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) || + (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))) { + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = i; + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].reg_idx = i; + ret = true; + } + + return ret; +} + #ifdef IXGBE_FCOE /** * ixgbe_cache_ring_fcoe - Descriptor ring to register mapping for the FCoE @@ -3276,6 +3373,9 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) return; #endif + if (ixgbe_cache_ring_fdir(adapter)) + return; + if (ixgbe_cache_ring_rss(adapter)) return; } @@ -3369,6 +3469,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->atr_sample_rate = 0; ixgbe_set_num_queues(adapter); err = pci_enable_msi(adapter->pdev); @@ -3634,6 +3737,11 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; adapter->flags |= IXGBE_FLAG2_RSC_CAPABLE; adapter->flags |= IXGBE_FLAG2_RSC_ENABLED; + adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->ring_feature[RING_F_FDIR].indices = + IXGBE_MAX_FDIR_INDICES; + adapter->atr_sample_rate = 20; + adapter->fdir_pballoc = 0; #ifdef IXGBE_FCOE adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; @@ -4223,6 +4331,8 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */ adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); + adapter->stats.fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); + adapter->stats.fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS); #ifdef IXGBE_FCOE adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); @@ -4388,6 +4498,30 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work) } /** + * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_fdir_reinit_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + fdir_reinit_task); + struct ixgbe_hw *hw = &adapter->hw; + int i; + + if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_FDIR_INIT_DONE, + &(adapter->tx_ring[i].reinit_state)); + } else { + DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, " + "ignored adding FDIR ATR filters \n"); + } + /* Done FDIR Re-initialization, enable transmits */ + netif_tx_start_all_queues(adapter->netdev); +} + +/** * ixgbe_watchdog_task - worker thread to bring link up * @work: pointer to work_struct containing our data **/ @@ -4814,6 +4948,58 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, writel(i, adapter->hw.hw_addr + tx_ring->tail); } +static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, + int queue, u32 tx_flags) +{ + /* Right now, we support IPv4 only */ + struct ixgbe_atr_input atr_input; + struct tcphdr *th; + struct udphdr *uh; + struct iphdr *iph = ip_hdr(skb); + struct ethhdr *eth = (struct ethhdr *)skb->data; + u16 vlan_id, src_port, dst_port, flex_bytes; + u32 src_ipv4_addr, dst_ipv4_addr; + u8 l4type = 0; + + /* check if we're UDP or TCP */ + if (iph->protocol == IPPROTO_TCP) { + th = tcp_hdr(skb); + src_port = th->source; + dst_port = th->dest; + l4type |= IXGBE_ATR_L4TYPE_TCP; + /* l4type IPv4 type is 0, no need to assign */ + } else if(iph->protocol == IPPROTO_UDP) { + uh = udp_hdr(skb); + src_port = uh->source; + dst_port = uh->dest; + l4type |= IXGBE_ATR_L4TYPE_UDP; + /* l4type IPv4 type is 0, no need to assign */ + } else { + /* Unsupported L4 header, just bail here */ + return; + } + + memset(&atr_input, 0, sizeof(struct ixgbe_atr_input)); + + vlan_id = (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK) >> + IXGBE_TX_FLAGS_VLAN_SHIFT; + src_ipv4_addr = iph->saddr; + dst_ipv4_addr = iph->daddr; + flex_bytes = eth->h_proto; + + ixgbe_atr_set_vlan_id_82599(&atr_input, vlan_id); + ixgbe_atr_set_src_port_82599(&atr_input, dst_port); + ixgbe_atr_set_dst_port_82599(&atr_input, src_port); + ixgbe_atr_set_flex_byte_82599(&atr_input, flex_bytes); + ixgbe_atr_set_l4type_82599(&atr_input, l4type); + /* src and dst are inverted, think how the receiver sees them */ + ixgbe_atr_set_src_ipv4_82599(&atr_input, dst_ipv4_addr); + ixgbe_atr_set_dst_ipv4_82599(&atr_input, src_ipv4_addr); + + /* This assumes the Rx queue and Tx queue are bound to the same CPU */ + ixgbe_fdir_add_signature_filter_82599(&adapter->hw, &atr_input, queue); +} + static int __ixgbe_maybe_stop_tx(struct net_device *netdev, struct ixgbe_ring *tx_ring, int size) { @@ -4848,6 +5034,9 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) { struct ixgbe_adapter *adapter = netdev_priv(dev); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) + return smp_processor_id(); + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) return 0; /* All traffic should default to class 0 */ @@ -4932,6 +5121,17 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first); if (count) { + /* add the ATR filter if ATR is on */ + if (tx_ring->atr_sample_rate) { + ++tx_ring->atr_count; + if ((tx_ring->atr_count >= tx_ring->atr_sample_rate) && + test_bit(__IXGBE_FDIR_INIT_DONE, + &tx_ring->reinit_state)) { + ixgbe_atr(adapter, skb, tx_ring->queue_index, + tx_flags); + tx_ring->atr_count = 0; + } + } ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); @@ -5314,6 +5514,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_FCOE_CRC; netdev->features |= NETIF_F_FSO; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + DPRINTK(DRV, INFO, "FCoE enabled, " + "disabling Flow Director\n"); + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= + ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->atr_sample_rate = 0; } else { adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; } @@ -5412,6 +5618,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task); + #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; @@ -5474,6 +5684,9 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->sfp_task); cancel_work_sync(&adapter->multispeed_fiber_task); cancel_work_sync(&adapter->sfp_config_module_task); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + cancel_work_sync(&adapter->fdir_reinit_task); flush_scheduled_work(); #ifdef CONFIG_IXGBE_DCA -- cgit v0.10.2 From ae540af18597a441bf17a26389179465ea4b9c36 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 4 Jun 2009 16:02:04 +0000 Subject: ixgbe: Re-adjust ring layouts to have better cacheline efficiency This patch rearranges the ixgbe_ring struct to make better use of cacheline efficiency. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index f2206e2..cd22323 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -121,19 +121,18 @@ struct ixgbe_queue_stats { struct ixgbe_ring { void *desc; /* descriptor ring memory */ - dma_addr_t dma; /* phys. address of descriptor ring */ - unsigned int size; /* length in bytes */ - unsigned int count; /* amount of descriptors */ - unsigned int next_to_use; - unsigned int next_to_clean; - u8 atr_sample_rate; - u8 atr_count; - - int queue_index; /* needed for multiqueue queue management */ union { struct ixgbe_tx_buffer *tx_buffer_info; struct ixgbe_rx_buffer *rx_buffer_info; }; + u8 atr_sample_rate; + u8 atr_count; + u16 count; /* amount of descriptors */ + u16 rx_buf_len; + u16 next_to_use; + u16 next_to_clean; + + u8 queue_index; /* needed for multiqueue queue management */ u16 head; u16 tail; @@ -141,20 +140,24 @@ struct ixgbe_ring { unsigned int total_bytes; unsigned int total_packets; - u16 reg_idx; /* holds the special value that gets the hardware register - * offset associated with this ring, which is different - * for DCB and RSS modes */ - #ifdef CONFIG_IXGBE_DCA /* cpu for tx queue */ int cpu; #endif + + u16 work_limit; /* max work per interrupt */ + u16 reg_idx; /* holds the special value that gets + * the hardware register offset + * associated with this ring, which is + * different for DCB and RSS modes + */ + struct ixgbe_queue_stats stats; unsigned long reinit_state; + u64 rsc_count; /* stat for coalesced packets */ - u16 work_limit; /* max work per interrupt */ - u16 rx_buf_len; - u64 rsc_count; /* stat for coalesced packets */ + unsigned int size; /* length in bytes */ + dma_addr_t dma; /* phys. address of descriptor ring */ }; enum ixgbe_ring_f_enum { -- cgit v0.10.2 From 794caeb259bc5d341bcc80dd37820073147a231c Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 16:02:24 +0000 Subject: ixgbe: Add FW detection and warning for 82599 SFP+ adapters 82599 has a FW running that helps manage the internal SFI PHY. There are also a number of pre-production samples of these SFI-based devices in the field. This patch adds a check to look for the firmware running on all SFP+ based adapters, and displays a warning to the system log if a pre-production adapter is identified. The driver will continue loading though, with no functional degradation. Also remove an old function prototype from ixgbe_82599.c that isn't being used. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 5c2627b..1984cab 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -71,10 +71,10 @@ s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw); s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw); s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val); s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_start_hw_rev_0_82599(struct ixgbe_hw *hw); s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw); s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw); u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); +static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { @@ -2142,8 +2142,9 @@ s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { u32 q_num; + s32 ret_val; - ixgbe_start_hw_generic(hw); + ret_val = ixgbe_start_hw_generic(hw); /* Clear the rate limiters */ for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) { @@ -2155,7 +2156,10 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) /* We need to run link autotry after the driver loads */ hw->mac.autotry_restart = true; - return 0; + if (ret_val == 0) + ret_val = ixgbe_verify_fw_version_82599(hw); + + return ret_val; } /** @@ -2407,6 +2411,54 @@ san_mac_addr_out: return 0; } +/** + * ixgbe_verify_fw_version_82599 - verify fw version for 82599 + * @hw: pointer to hardware structure + * + * Verifies that installed the firmware version is 0.6 or higher + * for SFI devices. All 82599 SFI devices should have version 0.6 or higher. + * + * Returns IXGBE_ERR_EEPROM_VERSION if the FW is not present or + * if the FW version is not supported. + **/ +static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_EEPROM_VERSION; + u16 fw_offset, fw_ptp_cfg_offset; + u16 fw_version = 0; + + /* firmware check is only necessary for SFI devices */ + if (hw->phy.media_type != ixgbe_media_type_fiber) { + status = 0; + goto fw_version_out; + } + + /* get the offset to the Firmware Module block */ + hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); + + if ((fw_offset == 0) || (fw_offset == 0xFFFF)) + goto fw_version_out; + + /* get the offset to the Pass Through Patch Configuration block */ + hw->eeprom.ops.read(hw, (fw_offset + + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR), + &fw_ptp_cfg_offset); + + if ((fw_ptp_cfg_offset == 0) || (fw_ptp_cfg_offset == 0xFFFF)) + goto fw_version_out; + + /* get the firmware version */ + hw->eeprom.ops.read(hw, (fw_ptp_cfg_offset + + IXGBE_FW_PATCH_VERSION_4), + &fw_version); + + if (fw_version > 0x5) + status = 0; + +fw_version_out: + return status; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index db339d6..96a1859 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -106,13 +106,17 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) **/ s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) { + s32 status; + /* Reset the hardware */ - hw->mac.ops.reset_hw(hw); + status = hw->mac.ops.reset_hw(hw); - /* Start the HW */ - hw->mac.ops.start_hw(hw); + if (status == 0) { + /* Start the HW */ + status = hw->mac.ops.start_hw(hw); + } - return 0; + return status; } /** diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ca7c5d5..543a606 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2728,6 +2728,15 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) case IXGBE_ERR_MASTER_REQUESTS_PENDING: dev_err(&adapter->pdev->dev, "master disable timed out\n"); break; + case IXGBE_ERR_EEPROM_VERSION: + /* We are running on a pre-production device, log a warning */ + dev_warn(&adapter->pdev->dev, "This device is a pre-production " + "adapter/LOM. Please be aware there may be issues " + "associated with your hardware. If you are " + "experiencing problems please contact your Intel or " + "hardware representative who provided you with this " + "hardware.\n"); + break; default: dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err); } @@ -5608,8 +5617,17 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->eeprom.ops.read(hw, 0x29, &adapter->eeprom_version); /* reset the hardware with the new settings */ - hw->mac.ops.start_hw(hw); + err = hw->mac.ops.start_hw(hw); + if (err == IXGBE_ERR_EEPROM_VERSION) { + /* We are running on a pre-production device, log a warning */ + dev_warn(&pdev->dev, "This device is a pre-production " + "adapter/LOM. Please be aware there may be issues " + "associated with your hardware. If you are " + "experiencing problems please contact your Intel or " + "hardware representative who provided you with this " + "hardware.\n"); + } strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 68cac36..fa87309 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1516,6 +1516,8 @@ #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 +#define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 +#define IXGBE_FW_PATCH_VERSION_4 0x7 /* PCI Bus Info */ #define IXGBE_PCI_LINK_STATUS 0xB2 @@ -2495,6 +2497,7 @@ struct ixgbe_info { #define IXGBE_ERR_SFP_NOT_PRESENT -20 #define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT -21 #define IXGBE_ERR_FDIR_REINIT_FAILED -23 +#define IXGBE_ERR_EEPROM_VERSION -24 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ -- cgit v0.10.2 From a1c1db392090bd280d1c3e2ed52ef682746ee332 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 4 Jun 2009 16:02:44 +0000 Subject: ixgbe: Increase the driver version number With all the last patchsets going in for 82599 feature enablement, the driver version needs to be increased for better identification. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 543a606..d36003c 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -48,7 +48,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.24-k2" +#define DRV_VERSION "2.0.34-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; -- cgit v0.10.2 From 1993f46739a9600ecdbbaa1ce56d25f6fdc44472 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 5 Jun 2009 14:37:19 +0000 Subject: netdev: smsc911x: allow building on Blackfin systems The smsc911x driver works fine on Blackfin systems, so add it to the arch list in the Kconfig. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3df8fc4..f19018d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1001,7 +1001,7 @@ config SMC911X config SMSC911X tristate "SMSC LAN911x/LAN921x families embedded ethernet support" - depends on ARM || SUPERH + depends on ARM || SUPERH || BLACKFIN select CRC32 select MII select PHYLIB -- cgit v0.10.2 From df911e2dc4c59e259b65c502fe0679ade309b575 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 5 Jun 2009 14:37:20 +0000 Subject: netdev: smsc911x: add missing __devexit_p() usage The smsc911x_drv_remove() function is declared with __devexit, so the assignment to the driver structure needs __devexit_p() wrappings to prevent build failure when hotplug is disabled. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 3cff840..b60639b 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -2155,7 +2155,7 @@ static int smsc911x_resume(struct platform_device *pdev) static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, - .remove = smsc911x_drv_remove, + .remove = __devexit_p(smsc911x_drv_remove), .driver = { .name = SMSC_CHIPNAME, }, -- cgit v0.10.2 From d6f58c2e63b4197cba99edd3a4c5c7f4935708fb Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sun, 7 Jun 2009 13:58:25 +0000 Subject: qlge: Fix firmware event handler loop. Check status on every iteration of event handler loop and exit if an error occurred. If an error occurred then recover process will be queued so this loop should no continue. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 9f81b79..7cb30fd 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -831,13 +831,19 @@ void ql_mpi_work(struct work_struct *work) container_of(work, struct ql_adapter, mpi_work.work); struct mbox_params mbc; struct mbox_params *mbcp = &mbc; + int err = 0; mutex_lock(&qdev->mpi_mutex); while (ql_read32(qdev, STS) & STS_PI) { memset(mbcp, 0, sizeof(struct mbox_params)); mbcp->out_count = 1; - ql_mpi_handler(qdev, mbcp); + /* Don't continue if an async event + * did not complete properly. + */ + err = ql_mpi_handler(qdev, mbcp); + if (err) + break; } mutex_unlock(&qdev->mpi_mutex); -- cgit v0.10.2 From 709ac4f43d76135daa9c2e33ab90eadd16bfce15 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sun, 7 Jun 2009 13:58:26 +0000 Subject: qlge: Fix bug in firmware event handler. Each firmware mailbox command can have a different number of valid data elements. When waiting for a mailbox command to complete it the process passes it's element count and waits for the completion. It is possible that while waiting an unrelated firmware async event (AE) can arrive. When this happens, the handler will over write the element count with the value for the newly arrived AE. This can cause the mailbox command to not get all of it's data. This patch restores original mailbox count at the end of the handler. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 7cb30fd..ff84243 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -453,6 +453,13 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) } end: ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); + /* Restore the original mailbox count to + * what the caller asked for. This can get + * changed when a mailbox command is waiting + * for a response and an AEN arrives and + * is handled. + * */ + mbcp->out_count = orig_count; return status; } -- cgit v0.10.2 From c8269b21ddfd0181881aca959cff64ff15a0b7d3 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sun, 7 Jun 2009 13:58:27 +0000 Subject: qlge: Fix bug in MTU setting process. Since an FCoE function shares a port with this NIC function, the jumbo settings must always be in place. This patch causes the hardware to be set up for jumbo if it is not already done. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index ff84243..de96b8a 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -761,7 +761,6 @@ void ql_mpi_port_cfg_work(struct work_struct *work) { struct ql_adapter *qdev = container_of(work, struct ql_adapter, mpi_port_cfg_work.work); - struct net_device *ndev = qdev->ndev; int status; status = ql_mb_get_port_cfg(qdev); @@ -771,9 +770,7 @@ void ql_mpi_port_cfg_work(struct work_struct *work) goto err; } - if (ndev->mtu <= 2500) - goto end; - else if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && + if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && qdev->max_frame_size == CFG_DEFAULT_MAX_FRAME_SIZE) goto end; -- cgit v0.10.2 From d2ba498668cb9f18677dd150b23f754953dc1fda Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sun, 7 Jun 2009 13:58:28 +0000 Subject: qlge: Fix timeout on indexed register wait. There are 8 banks of 'sub-registers' each of which are accessed through address/data register pair. An example would be reading flash or the xgmac. Accessing these require the driver to wait for a ready bit before writing the address and then accessing the data. This patch increases the timeout to 100us to prevent timeouts that have been seen on some platforms. These register are accessed in process context only. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index fcb159e..e186071 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -50,7 +50,7 @@ #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 UDELAY_DELAY 100 #define TX_DESC_PER_IOCB 8 -- cgit v0.10.2 From 365da8722d9df54efb8212bf82a87d816c522845 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Sun, 7 Jun 2009 13:58:29 +0000 Subject: qlge: Fix timeout on firmware mailbox commands. Some firmware mailbox commands require the firmware to communicate with the FCoE driver running on another PCI function. This can potentially take several seconds. This wait is done in process context only. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index de96b8a..3bd60a4 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -90,14 +90,14 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) */ static int ql_wait_mbx_cmd_cmplt(struct ql_adapter *qdev) { - int count = 50; /* TODO: arbitrary for now. */ + int count = 100; u32 value; do { value = ql_read32(qdev, STS); if (value & STS_PI) return 0; - udelay(UDELAY_DELAY); /* 10us */ + mdelay(UDELAY_DELAY); /* 100ms */ } while (--count); return -ETIMEDOUT; } -- cgit v0.10.2 From 744c6b2976778ac6944e580fc413842df85be84e Mon Sep 17 00:00:00 2001 From: Riccardo Ghetta Date: Sun, 7 Jun 2009 19:47:58 +0000 Subject: sis190: fix for x86_64 (bug 11509) Corrected dma sync handling on small packets. Should fix http://bugzilla.kernel.org/show_bug.cgi?id=11509 Note: While this bug was reported only on x86_64, it could have affected any architecture. Signed-off-by: Riccardo Ghetta Signed-off-by: David S. Miller diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 13b8ca4..9ea13c0 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -539,8 +539,8 @@ static bool sis190_try_rx_copy(struct sis190_private *tp, if (!skb) goto out; - pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pci_dev, addr, tp->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_reserve(skb, 2); skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size); *sk_buff = skb; -- cgit v0.10.2 From c3223d2446a7ce7438be49d68c4e65267fc6e0b2 Mon Sep 17 00:00:00 2001 From: Riccardo Ghetta Date: Thu, 4 Jun 2009 09:04:55 +0000 Subject: sis190: better message on unknown PHY Signed-off-by: Riccardo Ghetta Signed-off-by: David S. Miller diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 9ea13c0..ee32ad2 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -347,7 +347,7 @@ static struct { u32 msg_enable; } debug = { -1 }; -MODULE_DESCRIPTION("SiS sis190 Gigabit Ethernet driver"); +MODULE_DESCRIPTION("SiS sis190/191 Gigabit Ethernet driver"); module_param(rx_copybreak, int, 0); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param_named(debug, debug.msg_enable, int, 0); @@ -1313,12 +1313,15 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? LAN : HOME) : p->type; tp->features |= p->feature; - } else + net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", + pci_name(tp->pci_dev), p->name, phy_id); + } else { phy->type = UNKNOWN; - - net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", - pci_name(tp->pci_dev), - (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id); + net_probe(tp, KERN_INFO + "%s: unknown PHY 0x%x:0x%x transceiver at address %d\n", + pci_name(tp->pci_dev), + phy->id[0], (phy->id[1] & 0xfff0), phy_id); + } } static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp) -- cgit v0.10.2 From 856f8f41d44c9a310665213745bba655e52641fd Mon Sep 17 00:00:00 2001 From: Riccardo Ghetta Date: Thu, 4 Jun 2009 09:05:07 +0000 Subject: sis190: add new phy found on asus F5Sr laptop Signed-off-by: Riccardo Ghetta Signed-off-by: David S. Miller diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index ee32ad2..75bd947 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -317,6 +317,7 @@ static struct mii_chip_info { unsigned int type; u32 feature; } mii_chip_table[] = { + { "Atheros PHY", { 0x004d, 0xd010 }, LAN, 0 }, { "Atheros PHY AR8012", { 0x004d, 0xd020 }, LAN, 0 }, { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 }, { "Broadcom PHY AC131", { 0x0143, 0xbc70 }, LAN, 0 }, -- cgit v0.10.2 From 1feede014bf3c58f60b35f91dcd8a2f89b3908ad Mon Sep 17 00:00:00 2001 From: Riccardo Ghetta Date: Thu, 4 Jun 2009 09:05:20 +0000 Subject: sis190: fix gigabit negotiation Fixes an initialization error; the chip negotiates gigabit, but the driver mistakenly handled it as 100Mb. Changes based on both SiS own GPL driver and forcedeth. Hopefully should fix http://bugzilla.kernel.org/show_bug.cgi?id=9735 http://bugzilla.kernel.org/show_bug.cgi?id=11149 Signed-off-by: Riccardo Ghetta Signed-off-by: David S. Miller diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 75bd947..e224766 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -47,7 +47,7 @@ #define PHY_ID_ANY 0x1f #define MII_REG_ANY 0x1f -#define DRV_VERSION "1.2" +#define DRV_VERSION "1.3" #define DRV_NAME "sis190" #define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " @@ -943,9 +943,9 @@ static void sis190_phy_task(struct work_struct *work) u32 ctl; const char *msg; } reg31[] = { - { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000, + { LPA_1000FULL, 0x07000c00 | 0x00001000, "1000 Mbps Full Duplex" }, - { LPA_1000XHALF | LPA_SLCT, 0x07000c00, + { LPA_1000HALF, 0x07000c00, "1000 Mbps Half Duplex" }, { LPA_100FULL, 0x04000800 | 0x00001000, "100 Mbps Full Duplex" }, @@ -956,22 +956,35 @@ static void sis190_phy_task(struct work_struct *work) { LPA_10HALF, 0x04000400, "10 Mbps Half Duplex" }, { 0, 0x04000400, "unknown" } - }, *p; - u16 adv; + }, *p = NULL; + u16 adv, autoexp, gigadv, gigrec; val = mdio_read(ioaddr, phy_id, 0x1f); net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val); val = mdio_read(ioaddr, phy_id, MII_LPA); adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE); - net_link(tp, KERN_INFO "%s: mii lpa = %04x adv = %04x.\n", - dev->name, val, adv); - - val &= adv; + autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION); + net_link(tp, KERN_INFO "%s: mii lpa=%04x adv=%04x exp=%04x.\n", + dev->name, val, adv, autoexp); + + if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) { + /* check for gigabit speed */ + gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000); + gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000); + val = (gigadv & (gigrec >> 2)); + if (val & ADVERTISE_1000FULL) + p = reg31; + else if (val & ADVERTISE_1000HALF) + p = reg31 + 1; + } + if (!p) { + val &= adv; - for (p = reg31; p->val; p++) { - if ((val & p->val) == p->val) - break; + for (p = reg31; p->val; p++) { + if ((val & p->val) == p->val) + break; + } } p->ctl |= SIS_R32(StationControl) & ~0x0f001c00; -- cgit v0.10.2 From b82f08ea162edeee6c2c70c6c4321bea4763fa35 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 4 Jun 2009 00:59:18 +0000 Subject: virtio_net: Set correct gso->hdr_len Through a bug in the tun driver, I noticed that virtio_net is producing bogus hdr_len values. In particular, it only includes the IP header in the linear area, and excludes the entire TCP header. This causes the TCP header to be copied twice for each packet. (The bug omitted the second copy :) This patch corrects this. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0c9ca67..09bd441 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -470,7 +470,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) } if (skb_is_gso(skb)) { - hdr->hdr_len = skb_transport_header(skb) - skb->data; + hdr->hdr_len = skb_headlen(skb); hdr->gso_size = skb_shinfo(skb)->gso_size; if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; -- cgit v0.10.2 From 4909122fb8350e70c347f1201256908a92058044 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Jun 2009 00:20:01 -0700 Subject: tun: Optimise handling of bogus gso->hdr_len As all current versions of virtio_net generate a value for the header length that's too small, we should optimise this so that we don't copy it twice. This can be done by ensuring that it is at least as large as the place where we'll write the checksum. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3f0cdc1..8d82511 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -565,6 +565,10 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) return -EFAULT; + if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && + gso.csum_start + gso.csum_offset + 2 > gso.hdr_len) + gso.hdr_len = gso.csum_start + gso.csum_offset + 2; + if (gso.hdr_len > len) return -EINVAL; offset += sizeof(pi); -- cgit v0.10.2 From 5ff8dda3035d95df5bf6979136eb82b0e301726b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 4 Jun 2009 01:22:01 +0000 Subject: net: Ensure partial checksum offset is inside the skb head On Thu, Jun 04, 2009 at 09:06:00PM +1000, Herbert Xu wrote: > > tun: Optimise handling of bogus gso->hdr_len > > As all current versions of virtio_net generate a value for the > header length that's too small, we should optimise this so that > we don't copy it twice. This can be done by ensuring that it is > at least as large as the place where we'll write the checksum. > > Signed-off-by: Herbert Xu With this applied we can strengthen the partial checksum check: In skb_partial_csum_set we check to see if the checksum offset is within the packet. However, we really should check that it is within the skb head as that's the only bit we can modify without copying. Signed-off-by: Herbert Xu Acked-by: Rusty Russell Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6adf19e..a2473b1 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3026,12 +3026,12 @@ EXPORT_SYMBOL_GPL(skb_tstamp_tx); */ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) { - if (unlikely(start > skb->len - 2) || - unlikely((int)start + off > skb->len - 2)) { + if (unlikely(start > skb_headlen(skb)) || + unlikely((int)start + off > skb_headlen(skb) - 2)) { if (net_ratelimit()) printk(KERN_WARNING "bad partial csum: csum=%u/%u len=%u\n", - start, off, skb->len); + start, off, skb_headlen(skb)); return false; } skb->ip_summed = CHECKSUM_PARTIAL; -- cgit v0.10.2 From b07878e5471a8c880cb3cffee3a73048f38d2001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20R=C2=9A=C3=B6jfors?= Date: Thu, 4 Jun 2009 03:35:55 +0000 Subject: netdev: Added KS8842 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a driver for the Micrel KS8842 ethernet switch. The supplied code is for driving the KS8842 through the Timberdale FPGA on the Russellville board, a development board for Intel Atom CPU in the automotive area. Signed-off-by: Richard Röjfors Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f19018d..18c29a8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1723,6 +1723,11 @@ config TLAN Please email feedback to . +config KS8842 + tristate "Micrel KSZ8842" + help + This platform driver is for Micrel KSZ8842 chip. + config VIA_RHINE tristate "VIA Rhine support" depends on NET_PCI && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 774c2b4..1c378dd 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o obj-$(CONFIG_SKFP) += skfp/ +obj-$(CONFIG_KS8842) += ks8842.o obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c new file mode 100644 index 0000000..39b0aea --- /dev/null +++ b/drivers/net/ks8842.c @@ -0,0 +1,732 @@ +/* + * ks8842_main.c timberdale KS8842 ethernet driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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. + */ + +/* Supports: + * The Micrel KS8842 behind the timberdale FPGA + */ + +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "ks8842" + +/* Timberdale specific Registers */ +#define REG_TIMB_RST 0x1c + +/* KS8842 registers */ + +#define REG_SELECT_BANK 0x0e + +/* bank 0 registers */ +#define REG_QRFCR 0x04 + +/* bank 2 registers */ +#define REG_MARL 0x00 +#define REG_MARM 0x02 +#define REG_MARH 0x04 + +/* bank 3 registers */ +#define REG_GRR 0x06 + +/* bank 16 registers */ +#define REG_TXCR 0x00 +#define REG_TXSR 0x02 +#define REG_RXCR 0x04 +#define REG_TXMIR 0x08 +#define REG_RXMIR 0x0A + +/* bank 17 registers */ +#define REG_TXQCR 0x00 +#define REG_RXQCR 0x02 +#define REG_TXFDPR 0x04 +#define REG_RXFDPR 0x06 +#define REG_QMU_DATA_LO 0x08 +#define REG_QMU_DATA_HI 0x0A + +/* bank 18 registers */ +#define REG_IER 0x00 +#define IRQ_LINK_CHANGE 0x8000 +#define IRQ_TX 0x4000 +#define IRQ_RX 0x2000 +#define IRQ_RX_OVERRUN 0x0800 +#define IRQ_TX_STOPPED 0x0200 +#define IRQ_RX_STOPPED 0x0100 +#define IRQ_RX_ERROR 0x0080 +#define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \ + IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR) +#define REG_ISR 0x02 +#define REG_RXSR 0x04 +#define RXSR_VALID 0x8000 +#define RXSR_BROADCAST 0x80 +#define RXSR_MULTICAST 0x40 +#define RXSR_UNICAST 0x20 +#define RXSR_FRAMETYPE 0x08 +#define RXSR_TOO_LONG 0x04 +#define RXSR_RUNT 0x02 +#define RXSR_CRC_ERROR 0x01 +#define RXSR_ERROR (RXSR_TOO_LONG | RXSR_RUNT | RXSR_CRC_ERROR) + +/* bank 32 registers */ +#define REG_SW_ID_AND_ENABLE 0x00 +#define REG_SGCR1 0x02 +#define REG_SGCR2 0x04 +#define REG_SGCR3 0x06 + +/* bank 39 registers */ +#define REG_MACAR1 0x00 +#define REG_MACAR2 0x02 +#define REG_MACAR3 0x04 + +/* bank 45 registers */ +#define REG_P1MBCR 0x00 +#define REG_P1MBSR 0x02 + +/* bank 46 registers */ +#define REG_P2MBCR 0x00 +#define REG_P2MBSR 0x02 + +/* bank 48 registers */ +#define REG_P1CR2 0x02 + +/* bank 49 registers */ +#define REG_P1CR4 0x02 +#define REG_P1SR 0x04 + +struct ks8842_adapter { + void __iomem *hw_addr; + int irq; + struct tasklet_struct tasklet; + spinlock_t lock; /* spinlock to be interrupt safe */ + struct platform_device *pdev; +}; + +static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank) +{ + iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK); +} + +static inline void ks8842_write8(struct ks8842_adapter *adapter, u16 bank, + u8 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite8(value, adapter->hw_addr + offset); +} + +static inline void ks8842_write16(struct ks8842_adapter *adapter, u16 bank, + u16 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite16(value, adapter->hw_addr + offset); +} + +static inline void ks8842_enable_bits(struct ks8842_adapter *adapter, u16 bank, + u16 bits, int offset) +{ + u16 reg; + ks8842_select_bank(adapter, bank); + reg = ioread16(adapter->hw_addr + offset); + reg |= bits; + iowrite16(reg, adapter->hw_addr + offset); +} + +static inline void ks8842_clear_bits(struct ks8842_adapter *adapter, u16 bank, + u16 bits, int offset) +{ + u16 reg; + ks8842_select_bank(adapter, bank); + reg = ioread16(adapter->hw_addr + offset); + reg &= ~bits; + iowrite16(reg, adapter->hw_addr + offset); +} + +static inline void ks8842_write32(struct ks8842_adapter *adapter, u16 bank, + u32 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite32(value, adapter->hw_addr + offset); +} + +static inline u8 ks8842_read8(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread8(adapter->hw_addr + offset); +} + +static inline u16 ks8842_read16(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread16(adapter->hw_addr + offset); +} + +static inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread32(adapter->hw_addr + offset); +} + +static void ks8842_reset(struct ks8842_adapter *adapter) +{ + /* The KS8842 goes haywire when doing softare reset + * a work around in the timberdale IP is implemented to + * do a hardware reset instead + ks8842_write16(adapter, 3, 1, REG_GRR); + msleep(10); + iowrite16(0, adapter->hw_addr + REG_GRR); + */ + iowrite16(32, adapter->hw_addr + REG_SELECT_BANK); + iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST); + msleep(20); +} + +static void ks8842_update_link_status(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + /* check the status of the link */ + if (ks8842_read16(adapter, 45, REG_P1MBSR) & 0x4) { + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } else { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + } +} + +static void ks8842_enable_tx(struct ks8842_adapter *adapter) +{ + ks8842_enable_bits(adapter, 16, 0x01, REG_TXCR); +} + +static void ks8842_disable_tx(struct ks8842_adapter *adapter) +{ + ks8842_clear_bits(adapter, 16, 0x01, REG_TXCR); +} + +static void ks8842_enable_rx(struct ks8842_adapter *adapter) +{ + ks8842_enable_bits(adapter, 16, 0x01, REG_RXCR); +} + +static void ks8842_disable_rx(struct ks8842_adapter *adapter) +{ + ks8842_clear_bits(adapter, 16, 0x01, REG_RXCR); +} + +static void ks8842_reset_hw(struct ks8842_adapter *adapter) +{ + /* reset the HW */ + ks8842_reset(adapter); + + /* Enable QMU Transmit flow control / transmit padding / Transmit CRC */ + ks8842_write16(adapter, 16, 0x000E, REG_TXCR); + + /* enable the receiver, uni + multi + broadcast + flow ctrl + + crc strip */ + ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400, + REG_RXCR); + + /* TX frame pointer autoincrement */ + ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR); + + /* RX frame pointer autoincrement */ + ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR); + + /* RX 2 kb high watermark */ + ks8842_write16(adapter, 0, 0x1000, REG_QRFCR); + + /* aggresive back off in half duplex */ + ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1); + + /* enable no excessive collison drop */ + ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2); + + /* Enable port 1 force flow control / back pressure / transmit / recv */ + ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2); + + /* restart port auto-negotiation */ + ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); + /* only advertise 10Mbps */ + ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4); + + /* Enable the transmitter */ + ks8842_enable_tx(adapter); + + /* Enable the receiver */ + ks8842_enable_rx(adapter); + + /* clear all interrupts */ + ks8842_write16(adapter, 18, 0xffff, REG_ISR); + + /* enable interrupts */ + ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); + + /* enable the switch */ + ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); +} + +static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest) +{ + int i; + u16 mac; + + for (i = 0; i < ETH_ALEN; i++) + dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); + + /* make sure the switch port uses the same MAC as the QMU */ + mac = ks8842_read16(adapter, 2, REG_MARL); + ks8842_write16(adapter, 39, mac, REG_MACAR1); + mac = ks8842_read16(adapter, 2, REG_MARM); + ks8842_write16(adapter, 39, mac, REG_MACAR2); + mac = ks8842_read16(adapter, 2, REG_MARH); + ks8842_write16(adapter, 39, mac, REG_MACAR3); +} + +static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter) +{ + return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff; +} + +static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + int len = skb->len; + u32 *ptr = (u32 *)skb->data; + u32 ctrl; + + dev_dbg(&adapter->pdev->dev, + "%s: len %u head %p data %p tail %p end %p\n", + __func__, skb->len, skb->head, skb->data, + skb_tail_pointer(skb), skb_end_pointer(skb)); + + /* check FIFO buffer space, we need space for CRC and command bits */ + if (ks8842_tx_fifo_space(adapter) < len + 8) + return NETDEV_TX_BUSY; + + /* the control word, enable IRQ, port 1 and the length */ + ctrl = 0x8000 | 0x100 | (len << 16); + ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO); + + netdev->stats.tx_bytes += len; + + /* copy buffer */ + while (len > 0) { + iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO); + len -= sizeof(u32); + ptr++; + } + + /* enqueue packet */ + ks8842_write16(adapter, 17, 1, REG_TXQCR); + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static void ks8842_rx_frame(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO); + int len = (status >> 16) & 0x7ff; + + status &= 0xffff; + + dev_dbg(&adapter->pdev->dev, "%s - rx_data: status: %x\n", + __func__, status); + + /* check the status */ + if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { + struct sk_buff *skb = netdev_alloc_skb(netdev, len + 2); + + dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n", + __func__, len); + if (skb) { + u32 *data; + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += len; + if (status & RXSR_MULTICAST) + netdev->stats.multicast++; + + /* Align socket buffer in 4-byte boundary for + better performance. */ + skb_reserve(skb, 2); + data = (u32 *)skb_put(skb, len); + + ks8842_select_bank(adapter, 17); + while (len > 0) { + *data++ = ioread32(adapter->hw_addr + + REG_QMU_DATA_LO); + len -= sizeof(u32); + } + + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); + } else + netdev->stats.rx_dropped++; + } else { + dev_dbg(&adapter->pdev->dev, "RX error, status: %x\n", status); + netdev->stats.rx_errors++; + if (status & RXSR_TOO_LONG) + netdev->stats.rx_length_errors++; + if (status & RXSR_CRC_ERROR) + netdev->stats.rx_crc_errors++; + if (status & RXSR_RUNT) + netdev->stats.rx_frame_errors++; + } + + /* set high watermark to 3K */ + ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR); + + /* release the frame */ + ks8842_write16(adapter, 17, 0x01, REG_RXQCR); + + /* set high watermark to 2K */ + ks8842_enable_bits(adapter, 0, 1 << 12, REG_QRFCR); +} + +void ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter) +{ + u16 rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff; + dev_dbg(&adapter->pdev->dev, "%s Entry - rx_data: %d\n", + __func__, rx_data); + while (rx_data) { + ks8842_rx_frame(netdev, adapter); + rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff; + } +} + +void ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter) +{ + u16 sr = ks8842_read16(adapter, 16, REG_TXSR); + dev_dbg(&adapter->pdev->dev, "%s - entry, sr: %x\n", __func__, sr); + netdev->stats.tx_packets++; + if (netif_queue_stopped(netdev)) + netif_wake_queue(netdev); +} + +void ks8842_handle_rx_overrun(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + netdev->stats.rx_errors++; + netdev->stats.rx_fifo_errors++; +} + +void ks8842_tasklet(unsigned long arg) +{ + struct net_device *netdev = (struct net_device *)arg; + struct ks8842_adapter *adapter = netdev_priv(netdev); + u16 isr; + unsigned long flags; + u16 entry_bank; + + /* read current bank to be able to set it back */ + spin_lock_irqsave(&adapter->lock, flags); + entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); + spin_unlock_irqrestore(&adapter->lock, flags); + + isr = ks8842_read16(adapter, 18, REG_ISR); + dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); + + /* Ack */ + ks8842_write16(adapter, 18, isr, REG_ISR); + + if (!netif_running(netdev)) + return; + + if (isr & IRQ_LINK_CHANGE) + ks8842_update_link_status(netdev, adapter); + + if (isr & (IRQ_RX | IRQ_RX_ERROR)) + ks8842_handle_rx(netdev, adapter); + + if (isr & IRQ_TX) + ks8842_handle_tx(netdev, adapter); + + if (isr & IRQ_RX_OVERRUN) + ks8842_handle_rx_overrun(netdev, adapter); + + if (isr & IRQ_TX_STOPPED) { + ks8842_disable_tx(adapter); + ks8842_enable_tx(adapter); + } + + if (isr & IRQ_RX_STOPPED) { + ks8842_disable_rx(adapter); + ks8842_enable_rx(adapter); + } + + /* re-enable interrupts, put back the bank selection register */ + spin_lock_irqsave(&adapter->lock, flags); + ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); + iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +static irqreturn_t ks8842_irq(int irq, void *devid) +{ + struct ks8842_adapter *adapter = devid; + u16 isr; + u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); + irqreturn_t ret = IRQ_NONE; + + isr = ks8842_read16(adapter, 18, REG_ISR); + dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); + + if (isr) { + /* disable IRQ */ + ks8842_write16(adapter, 18, 0x00, REG_IER); + + /* schedule tasklet */ + tasklet_schedule(&adapter->tasklet); + + ret = IRQ_HANDLED; + } + + iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); + + return ret; +} + + +/* Netdevice operations */ + +static int ks8842_open(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + int err; + + dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__); + + /* reset the HW */ + ks8842_reset_hw(adapter); + + ks8842_update_link_status(netdev, adapter); + + err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME, + adapter); + if (err) { + printk(KERN_ERR "Failed to request IRQ: %d: %d\n", + adapter->irq, err); + return err; + } + + return 0; +} + +static int ks8842_close(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + + dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__); + + /* free the irq */ + free_irq(adapter->irq, adapter); + + /* disable the switch */ + ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE); + + return 0; +} + +static int ks8842_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + int ret; + struct ks8842_adapter *adapter = netdev_priv(netdev); + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + ret = ks8842_tx_frame(skb, netdev); + + if (ks8842_tx_fifo_space(adapter) < netdev->mtu + 8) + netif_stop_queue(netdev); + + return ret; +} + +static int ks8842_set_mac(struct net_device *netdev, void *p) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + struct sockaddr *addr = p; + char *mac = (u8 *)addr->sa_data; + int i; + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, mac, netdev->addr_len); + + spin_lock_irqsave(&adapter->lock, flags); + for (i = 0; i < ETH_ALEN; i++) { + ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i); + ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1], + REG_MACAR1 + i); + } + spin_unlock_irqrestore(&adapter->lock, flags); + return 0; +} + +static void ks8842_tx_timeout(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + spin_lock_irqsave(&adapter->lock, flags); + /* disable interrupts */ + ks8842_write16(adapter, 18, 0, REG_IER); + ks8842_write16(adapter, 18, 0xFFFF, REG_ISR); + spin_unlock_irqrestore(&adapter->lock, flags); + + ks8842_reset_hw(adapter); + + ks8842_update_link_status(netdev, adapter); +} + +static const struct net_device_ops ks8842_netdev_ops = { + .ndo_open = ks8842_open, + .ndo_stop = ks8842_close, + .ndo_start_xmit = ks8842_xmit_frame, + .ndo_set_mac_address = ks8842_set_mac, + .ndo_tx_timeout = ks8842_tx_timeout, + .ndo_validate_addr = eth_validate_addr +}; + +static struct ethtool_ops ks8842_ethtool_ops = { + .get_link = ethtool_op_get_link, +}; + +static int __devinit ks8842_probe(struct platform_device *pdev) +{ + int err = -ENOMEM; + struct resource *iomem; + struct net_device *netdev; + struct ks8842_adapter *adapter; + u16 id; + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME)) + goto err_mem_region; + + netdev = alloc_etherdev(sizeof(struct ks8842_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter = netdev_priv(netdev); + adapter->hw_addr = ioremap(iomem->start, resource_size(iomem)); + if (!adapter->hw_addr) + goto err_ioremap; + + adapter->irq = platform_get_irq(pdev, 0); + if (adapter->irq < 0) { + err = adapter->irq; + goto err_get_irq; + } + + adapter->pdev = pdev; + + tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev); + spin_lock_init(&adapter->lock); + + netdev->netdev_ops = &ks8842_netdev_ops; + netdev->ethtool_ops = &ks8842_ethtool_ops; + + ks8842_read_mac_addr(adapter, netdev->dev_addr); + + id = ks8842_read16(adapter, 32, REG_SW_ID_AND_ENABLE); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + platform_set_drvdata(pdev, netdev); + + printk(KERN_INFO DRV_NAME + " Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n", + (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7); + + return 0; + +err_register: +err_get_irq: + iounmap(adapter->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + release_mem_region(iomem->start, resource_size(iomem)); +err_mem_region: + return err; +} + +static int __devexit ks8842_remove(struct platform_device *pdev) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct ks8842_adapter *adapter = netdev_priv(netdev); + struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + unregister_netdev(netdev); + tasklet_kill(&adapter->tasklet); + iounmap(adapter->hw_addr); + free_netdev(netdev); + release_mem_region(iomem->start, resource_size(iomem)); + platform_set_drvdata(pdev, NULL); + return 0; +} + + +static struct platform_driver ks8842_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ks8842_probe, + .remove = ks8842_remove, +}; + +static int __init ks8842_init(void) +{ + return platform_driver_register(&ks8842_platform_driver); +} + +static void __exit ks8842_exit(void) +{ + platform_driver_unregister(&ks8842_platform_driver); +} + +module_init(ks8842_init); +module_exit(ks8842_exit); + +MODULE_DESCRIPTION("Timberdale KS8842 ethernet driver"); +MODULE_AUTHOR("Mocean Laboratories "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ks8842"); + -- cgit v0.10.2 From d65a68a8da5c9d1041ebc5e018e677d641910668 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Thu, 4 Jun 2009 05:50:29 +0000 Subject: hso: convert dev_alloc_skb() to netdev_alloc_skb() Signed-off-by: Paulius Zaleckas Signed-off-by: David S. Miller diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 5ddd8c4..e3580f4 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -899,15 +899,14 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, continue; } /* Allocate an sk_buff */ - odev->skb_rx_buf = dev_alloc_skb(frame_len); + odev->skb_rx_buf = netdev_alloc_skb(odev->net, + frame_len); if (!odev->skb_rx_buf) { /* We got no receive buffer. */ D1("could not allocate memory"); odev->rx_parse_state = WAIT_SYNC; return; } - /* Here's where it came from */ - odev->skb_rx_buf->dev = odev->net; /* Copy what we got so far. make room for iphdr * after tail. */ -- cgit v0.10.2 From f957bcf0164e45bd77867e02412035e1c2fd7058 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 4 Jun 2009 23:07:59 +0000 Subject: s2io: Remove private boolean definitions Remove the private definition of TRUE/FALSE and use the ones from linux/stddef.h. Also remove the definition of BOOL which is not referenced inside the driver anyway. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2bc73ed..458daa0 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1764,7 +1764,7 @@ static int init_nic(struct s2io_nic *nic) * by then we return error. */ time = 0; - while (TRUE) { + while (true) { val64 = readq(&bar0->rti_command_mem); if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) break; @@ -2137,7 +2137,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag) herc = (sp->device_type == XFRAME_II_DEVICE); - if (flag == FALSE) { + if (flag == false) { if ((!herc && (sp->pdev->revision >= 4)) || herc) { if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE)) ret = 1; @@ -3587,7 +3587,7 @@ static void s2io_reset(struct s2io_nic * sp) writeq(val64, &bar0->pcc_err_reg); } - sp->device_enabled_once = FALSE; + sp->device_enabled_once = false; } /** @@ -5572,10 +5572,10 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, val64 = readq(&bar0->rmac_pause_cfg); if (val64 & RMAC_PAUSE_GEN_ENABLE) - ep->tx_pause = TRUE; + ep->tx_pause = true; if (val64 & RMAC_PAUSE_RX_ENABLE) - ep->rx_pause = TRUE; - ep->autoneg = FALSE; + ep->rx_pause = true; + ep->autoneg = false; } /** @@ -6806,7 +6806,7 @@ static void s2io_set_link(struct work_struct *work) val64 |= ADAPTER_LED_ON; writeq(val64, &bar0->adapter_control); } - nic->device_enabled_once = TRUE; + nic->device_enabled_once = true; } else { DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); @@ -7754,7 +7754,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) struct s2io_nic *sp; struct net_device *dev; int i, j, ret; - int dma_flag = FALSE; + int dma_flag = false; u32 mac_up, mac_down; u64 val64 = 0, tmp64 = 0; struct XENA_dev_config __iomem *bar0 = NULL; @@ -7777,7 +7777,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); - dma_flag = TRUE; + dma_flag = true; if (pci_set_consistent_dma_mask (pdev, DMA_BIT_MASK(64))) { DBG_PRINT(ERR_DBG, @@ -7818,7 +7818,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->dev = dev; sp->pdev = pdev; sp->high_dma_flag = dma_flag; - sp->device_enabled_once = FALSE; + sp->device_enabled_once = false; if (rx_ring_mode == 1) sp->rxd_mode = RXD_MODE_1; if (rx_ring_mode == 2) @@ -7964,7 +7964,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - if (sp->high_dma_flag == TRUE) + if (sp->high_dma_flag == true) dev->features |= NETIF_F_HIGHDMA; dev->features |= NETIF_F_TSO; dev->features |= NETIF_F_TSO6; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 55cb943..d5c5be6 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -18,15 +18,6 @@ #define vBIT(val, loc, sz) (((u64)val) << (64-loc-sz)) #define INV(d) ((d&0xff)<<24) | (((d>>8)&0xff)<<16) | (((d>>16)&0xff)<<8)| ((d>>24)&0xff) -#ifndef BOOL -#define BOOL int -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - #undef SUCCESS #define SUCCESS 0 #define FAILURE -1 -- cgit v0.10.2 From eae3f29cc73f83cc3f1891d3ad40021b5172c630 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 5 Jun 2009 04:03:35 +0000 Subject: net: num_dma_maps is not used Get rid of num_dma_maps in struct skb_shared_info, as it seems unused. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7305da9..74850581 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -194,9 +194,6 @@ struct skb_shared_info { unsigned short gso_type; __be32 ip6_frag_id; union skb_shared_tx tx_flags; -#ifdef CONFIG_HAS_DMA - unsigned int num_dma_maps; -#endif struct sk_buff *frag_list; struct skb_shared_hwtstamps hwtstamps; skb_frag_t frags[MAX_SKB_FRAGS]; diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c index 8623492..7adb623 100644 --- a/net/core/skb_dma_map.c +++ b/net/core/skb_dma_map.c @@ -30,7 +30,6 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb, goto unwind; sp->dma_maps[i + 1] = map; } - sp->num_dma_maps = i + 1; return 0; -- cgit v0.10.2 From 042a53a9e437feaf2230dd2cadcecfae9c7bfe05 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 5 Jun 2009 04:04:16 +0000 Subject: net: skb_shared_info optimization skb_dma_unmap() is quite expensive for small packets, because we use two different cache lines from skb_shared_info. One to access nr_frags, one to access dma_maps[0] Instead of dma_maps being an array of MAX_SKB_FRAGS + 1 elements, let dma_head alone in a new dma_head field, close to nr_frags, to reduce cache lines misses. Tested on my dev machine (bnx2 & tg3 adapters), nice speedup ! Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index f530172..391d2d4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -5487,7 +5487,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) dev_kfree_skb(skb); return -EIO; } - map = skb_shinfo(skb)->dma_maps[0]; + map = skb_shinfo(skb)->dma_head; REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); @@ -6167,7 +6167,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tx_buf = &txr->tx_buf_ring[ring_prod]; tx_buf->skb = skb; @@ -6191,7 +6191,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd = &txr->tx_desc_ring[ring_prod]; len = frag->size; - mapping = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; txbd->tx_bd_haddr_hi = (u64) mapping >> 32; txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 05e87a5..8d36743 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2998,7 +2998,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, size -= 4; buffer_info->length = size; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; @@ -3039,7 +3039,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, size -= 4; buffer_info->length = size; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 38694c7..9043f1b 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3916,7 +3916,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; count++; len -= size; @@ -3947,7 +3947,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; len -= size; offset += size; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 958b287..ea17319 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3139,8 +3139,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; - count++; + buffer_info->dma = skb_shinfo(skb)->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -3164,7 +3163,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - return count; + return count + 1; } static inline void igb_tx_queue_adv(struct igb_adapter *adapter, diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 5f7ba1a4..22aadb7 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2119,8 +2119,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; - count++; + buffer_info->dma = skb_shinfo(skb)->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -2144,7 +2143,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - return count; + return count + 1; } static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter, diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 6eb7f37..9c897cf 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1300,7 +1300,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; WARN_ON(buffer_info->dma != 0); buffer_info->time_stamp = jiffies; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; pci_map_single(adapter->pdev, skb->data + offset, size, @@ -1340,7 +1340,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; buffer_info->time_stamp = jiffies; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; buffer_info->next_to_watch = 0; len -= size; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d36003c..09994e9 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4837,7 +4837,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = map[0] + offset; + tx_buffer_info->dma = skb_shinfo(skb)->dma_head + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; @@ -4869,7 +4869,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = map[f + 1] + offset; + tx_buffer_info->dma = map[f] + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a39b534..46a3f86 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5021,7 +5021,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, /* New SKB is guaranteed to be linear. */ entry = *start; ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE); - new_addr = skb_shinfo(new_skb)->dma_maps[0]; + new_addr = skb_shinfo(new_skb)->dma_head; /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. @@ -5155,7 +5155,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tp->tx_buffers[entry].skb = skb; @@ -5173,7 +5173,7 @@ 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 = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; tp->tx_buffers[entry].skb = NULL; tg3_set_txd(tp, entry, mapping, len, @@ -5331,7 +5331,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tp->tx_buffers[entry].skb = skb; @@ -5356,7 +5356,7 @@ 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 = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; tp->tx_buffers[entry].skb = NULL; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 74850581..aad484c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -189,6 +189,9 @@ struct skb_shared_info { atomic_t dataref; unsigned short nr_frags; unsigned short gso_size; +#ifdef CONFIG_HAS_DMA + dma_addr_t dma_head; +#endif /* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; unsigned short gso_type; @@ -198,7 +201,7 @@ struct skb_shared_info { struct skb_shared_hwtstamps hwtstamps; skb_frag_t frags[MAX_SKB_FRAGS]; #ifdef CONFIG_HAS_DMA - dma_addr_t dma_maps[MAX_SKB_FRAGS + 1]; + dma_addr_t dma_maps[MAX_SKB_FRAGS]; #endif /* Intermediate layers must ensure that destructor_arg * remains valid until skb destructor */ diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c index 7adb623..79687df 100644 --- a/net/core/skb_dma_map.c +++ b/net/core/skb_dma_map.c @@ -20,7 +20,7 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb, if (dma_mapping_error(dev, map)) goto out_err; - sp->dma_maps[0] = map; + sp->dma_head = map; for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; @@ -28,7 +28,7 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb, fp->size, dir); if (dma_mapping_error(dev, map)) goto unwind; - sp->dma_maps[i + 1] = map; + sp->dma_maps[i] = map; } return 0; @@ -37,10 +37,10 @@ unwind: while (--i >= 0) { skb_frag_t *fp = &sp->frags[i]; - dma_unmap_page(dev, sp->dma_maps[i + 1], + dma_unmap_page(dev, sp->dma_maps[i], fp->size, dir); } - dma_unmap_single(dev, sp->dma_maps[0], + dma_unmap_single(dev, sp->dma_head, skb_headlen(skb), dir); out_err: return -ENOMEM; @@ -53,12 +53,12 @@ void skb_dma_unmap(struct device *dev, struct sk_buff *skb, struct skb_shared_info *sp = skb_shinfo(skb); int i; - dma_unmap_single(dev, sp->dma_maps[0], + dma_unmap_single(dev, sp->dma_head, skb_headlen(skb), dir); for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; - dma_unmap_page(dev, sp->dma_maps[i + 1], + dma_unmap_page(dev, sp->dma_maps[i], fp->size, dir); } } -- cgit v0.10.2 From d2d27bfd11659675fdd1c20b1c7f8f59873cad60 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Fri, 5 Jun 2009 09:35:40 +0000 Subject: net: Fix skb_copy_datagram_from_iovec() to pass the right offset I am working on enabling UFO between KVM guests using virtio-net and i have some patches that i got working with 2.6.30-rc8. When i wanted to try them with net-next-2.6, i noticed that virtio-net is not working with that tree. After some debugging, it turned out to be several bugs in the recent patches to fix aio with tun driver, specifically the following 2 commits. http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=0a1ec07a67bd8b0033dace237249654d015efa21 http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=6f26c9a7555e5bcca3560919db9b852015077dae Fix the call to memcpy_from_iovecend() in skb_copy_datagram_from_iovec to pass the right iovec offset. Signed-off-by: Sridhar Samudrala Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/net/core/datagram.c b/net/core/datagram.c index e2a36f0..774bcd9 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -466,7 +466,8 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, if (copy > 0) { if (copy > len) copy = len; - if (memcpy_fromiovecend(skb->data + offset, from, 0, copy)) + if (memcpy_fromiovecend(skb->data + offset, from, from_offset, + copy)) goto fault; if ((len -= copy) == 0) return 0; -- cgit v0.10.2 From 2faef52b72958b8b1c08e927b9b0691c314cf6f4 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Fri, 5 Jun 2009 09:35:44 +0000 Subject: net: Fix memcpy_toiovecend() to use the right offset Increment the iovec base by the offset passed in for the initial copy_to_user() in memcpy_to_iovecend(). Signed-off-by: Sridhar Samudrala Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/net/core/iovec.c b/net/core/iovec.c index 40a76ce..16ad45d 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -112,9 +112,9 @@ int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, continue; } copy = min_t(unsigned int, iov->iov_len - offset, len); - offset = 0; - if (copy_to_user(iov->iov_base, kdata, copy)) + if (copy_to_user(iov->iov_base + offset, kdata, copy)) return -EFAULT; + offset = 0; kdata += copy; len -= copy; } -- cgit v0.10.2 From 6f536f403979d37021508c5804509a379d853788 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Mon, 8 Jun 2009 00:27:28 -0700 Subject: tun: Fix copy/paste error in tun_get_user Use the right structure while incrementing the offset in tun_get_user. Signed-off-by: Sridhar Samudrala Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8d82511..d83ccb8 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -571,7 +571,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, if (gso.hdr_len > len) return -EINVAL; - offset += sizeof(pi); + offset += sizeof(gso); } if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { -- cgit v0.10.2 From a5b19b635c39fdb819500b0a746b44fe40c9a303 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Mon, 8 Jun 2009 00:39:58 -0700 Subject: mlx4: FIX error flow when initializing EQ table If mlx4_create_eq() would fail for one of EQ's assigned for completion handling, the code would try to free the same EQ we failed to create. The crash was found by Christoph Lameter Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 8830dcb..dee1887 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -623,8 +623,10 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, &priv->eq_table.eq[i]); - if (err) + if (err) { + --i; goto err_out_unmap; + } } err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, -- cgit v0.10.2 From 1d0ebfe7c9621d43804e9ce9f2b898541a7d9652 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Mon, 8 Jun 2009 00:40:35 -0700 Subject: net pkgen.c:fix no need for check vfree() does its own 'NULL' check, so no need for check before calling it. Signed-off-by: Figo.zhang Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b8ccd3c..19b8c20 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3691,8 +3691,7 @@ out1: #ifdef CONFIG_XFRM free_SAs(pkt_dev); #endif - if (pkt_dev->flows) - vfree(pkt_dev->flows); + vfree(pkt_dev->flows); kfree(pkt_dev); return err; } @@ -3791,8 +3790,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, #ifdef CONFIG_XFRM free_SAs(pkt_dev); #endif - if (pkt_dev->flows) - vfree(pkt_dev->flows); + vfree(pkt_dev->flows); kfree(pkt_dev); return 0; } -- cgit v0.10.2 From ef681ce1e8b3e63317cd724c200b2fd39286c005 Mon Sep 17 00:00:00 2001 From: Andre Detsch Date: Mon, 8 Jun 2009 00:42:30 -0700 Subject: e100: Fix napi_enable BUG_ON when recovering from EEH error BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)) was being hit during e100 EEH recovery. The problem source was a napi_enable call being made during e100_io_error_detected. Napi should remain disabled after e100_down, and only be reenabled when the interface is recovered. This patch also updates e100_io_error_detected in order to make it similar to the current versions of the error_detected callback in drivers such as e1000e and ixgbe. Signed-off-by: Andre Detsch Signed-off-by: David S. Miller diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 0f9ee13..0c37dd9 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2822,12 +2822,13 @@ static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); - /* Similar to calling e100_down(), but avoids adapter I/O. */ - e100_close(netdev); - - /* Detach; put netif into a state similar to hotplug unplug. */ - napi_enable(&nic->napi); netif_device_detach(netdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (netif_running(netdev)) + e100_down(nic); pci_disable_device(pdev); /* Request a slot reset. */ -- cgit v0.10.2 From f0a4d0e5b5bfd271e6737f7c095994835b70d450 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 8 Jun 2009 00:44:31 -0700 Subject: tun: Fix unregister race It is possible for tun_chr_close to race with dellink on the a tun device. In which case if __tun_get runs before dellink but dellink runs before tun_chr_close calls unregister_netdevice we will attempt to unregister the netdevice after it is already gone. The two cases are already serialized on the rtnl_lock, so I have gone for the cheap simple fix of moving rtnl_lock to cover __tun_get in tun_chr_close. Eliminating the possibility of the tun device being unregistered between __tun_get and unregister_netdevice in tun_chr_close. Signed-off-by: Eric W. Biederman Tested-by: David Woodhouse Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d83ccb8..811d351 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1322,21 +1322,22 @@ static int tun_chr_open(struct inode *inode, struct file * file) static int tun_chr_close(struct inode *inode, struct file *file) { struct tun_file *tfile = file->private_data; - struct tun_struct *tun = __tun_get(tfile); + struct tun_struct *tun; + rtnl_lock(); + tun = __tun_get(tfile); if (tun) { DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); - rtnl_lock(); __tun_detach(tun); /* If desireable, unregister the netdevice. */ if (!(tun->flags & TUN_PERSIST)) unregister_netdevice(tun->dev); - rtnl_unlock(); } + rtnl_unlock(); tun = tfile->tun; if (tun) -- cgit v0.10.2 From 4e329972052c3649367b91de783f6293b8653cb2 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sun, 7 Jun 2009 09:09:23 +0000 Subject: isdn: rename capi_ctr_reseted() to capi_ctr_down() Change the name of the Kernel CAPI exported function capi_ctr_reseted() to something representing its purpose better. Impact: renaming, no functional change Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI index 786d619..4631538 100644 --- a/Documentation/isdn/INTERFACE.CAPI +++ b/Documentation/isdn/INTERFACE.CAPI @@ -45,7 +45,7 @@ From then on, Kernel CAPI may call the registered callback functions for the device. If the device becomes unusable for any reason (shutdown, disconnect ...), the -driver has to call capi_ctr_reseted(). This will prevent further calls to the +driver has to call capi_ctr_down(). This will prevent further calls to the callback functions by Kernel CAPI. @@ -166,7 +166,7 @@ int detach_capi_ctr(struct capi_ctr *ctrlr) register/unregister a device (controller) with Kernel CAPI void capi_ctr_ready(struct capi_ctr *ctrlr) -void capi_ctr_reseted(struct capi_ctr *ctrlr) +void capi_ctr_down(struct capi_ctr *ctrlr) signal controller ready/not ready void capi_ctr_suspend_output(struct capi_ctr *ctrlr) diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index f331703..57d2636 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -377,14 +377,14 @@ void capi_ctr_ready(struct capi_ctr * card) EXPORT_SYMBOL(capi_ctr_ready); /** - * capi_ctr_reseted() - signal CAPI controller reset + * capi_ctr_down() - signal CAPI controller not ready * @card: controller descriptor structure. * * Called by hardware driver to signal that the controller is down and * unavailable for use. */ -void capi_ctr_reseted(struct capi_ctr * card) +void capi_ctr_down(struct capi_ctr * card) { u16 appl; @@ -413,7 +413,7 @@ void capi_ctr_reseted(struct capi_ctr * card) notify_push(KCI_CONTRDOWN, card->cnr, 0, 0); } -EXPORT_SYMBOL(capi_ctr_reseted); +EXPORT_SYMBOL(capi_ctr_down); /** * capi_ctr_suspend_output() - suspend controller @@ -517,7 +517,7 @@ EXPORT_SYMBOL(attach_capi_ctr); int detach_capi_ctr(struct capi_ctr *card) { if (card->cardstate != CARD_DETECTED) - capi_ctr_reseted(card); + capi_ctr_down(card); ncards--; diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index abf05ec..a7c0083 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -330,7 +330,7 @@ void b1_reset_ctr(struct capi_ctr *ctrl) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } void b1_register_appl(struct capi_ctr *ctrl, diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index da34b98..0e84aaa 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -759,7 +759,7 @@ void b1dma_reset_ctr(struct capi_ctr *ctrl) memset(cinfo->version, 0, sizeof(cinfo->version)); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 9df1d3f..6833301 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -681,7 +681,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(&cinfo->capi_ctrl); + capi_ctr_down(&cinfo->capi_ctrl); } card->nlogcontr = 0; return IRQ_HANDLED; @@ -909,7 +909,7 @@ static void c4_reset_ctr(struct capi_ctr *ctrl) for (i=0; i < card->nr_controllers; i++) { cinfo = &card->ctrlinfo[i]; memset(cinfo->version, 0, sizeof(cinfo->version)); - capi_ctr_reseted(&cinfo->capi_ctrl); + capi_ctr_down(&cinfo->capi_ctrl); } card->nlogcontr = 0; } diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index e772449..1c53fd4 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -339,7 +339,7 @@ static void t1isa_reset_ctr(struct capi_ctr *ctrl) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } static void t1isa_remove(struct pci_dev *pdev) diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 53f6ad1..4ffaa14 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -67,7 +67,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl) printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); #endif capilib_release(&cinfo->ncci_head); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } /****************************** @@ -347,7 +347,7 @@ int hycapi_capi_stop(hysdn_card *card) if(cinfo) { ctrl = &cinfo->capi_ctrl; /* ctrl->suspend_output(ctrl); */ - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } return 0; } diff --git a/include/linux/isdn/capilli.h b/include/linux/isdn/capilli.h index 35e9b0f..7acb87a 100644 --- a/include/linux/isdn/capilli.h +++ b/include/linux/isdn/capilli.h @@ -79,7 +79,7 @@ int attach_capi_ctr(struct capi_ctr *); int detach_capi_ctr(struct capi_ctr *); void capi_ctr_ready(struct capi_ctr * card); -void capi_ctr_reseted(struct capi_ctr * card); +void capi_ctr_down(struct capi_ctr * card); void capi_ctr_suspend_output(struct capi_ctr * card); void capi_ctr_resume_output(struct capi_ctr * card); void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb); diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 78958c0..97f8d68 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -382,7 +382,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) BT_DBG("ctrl %p", ctrl); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); atomic_inc(&session->terminate); cmtp_schedule(session); -- cgit v0.10.2 From 4793d15b25821003486bb11b54eaf2f3130ecacd Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sun, 7 Jun 2009 09:09:23 +0000 Subject: isdn: kerneldoc for capiutil.c Add kerneldoc comments for the exported funtions in capiutil.c. Impact: documentation Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index 29419a8..c7c2902 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -490,7 +490,14 @@ static void pars_2_message(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ +/** + * capi_cmsg2message() - assemble CAPI 2.0 message from _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg) { cmsg->m = msg; @@ -553,7 +560,14 @@ static void message_2_pars(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ +/** + * capi_message2cmsg() - disassemble CAPI 2.0 message into _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) { memset(cmsg, 0, sizeof(_cmsg)); @@ -573,7 +587,18 @@ unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) return 0; } -/*-------------------------------------------------------*/ +/** + * capi_cmsg_header() - initialize header part of _cmsg structure + * @cmsg: _cmsg structure + * @_ApplId: ApplID field value + * @_Command: Command field value + * @_Subcommand: Subcommand field value + * @_Messagenumber: Message Number field value + * @_Controller: Controller/PLCI/NCCI field value + * + * Return value: 0 for success + */ + unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId, u8 _Command, u8 _Subcommand, u16 _Messagenumber, u32 _Controller) @@ -641,6 +666,14 @@ static char *mnames[] = [0x4e] = "MANUFACTURER_RESP" }; +/** + * capi_cmd2str() - convert CAPI 2.0 command/subcommand number to name + * @cmd: command number + * @subcmd: subcommand number + * + * Return value: static string, NULL if command/subcommand unknown + */ + char *capi_cmd2str(u8 cmd, u8 subcmd) { return mnames[command_2_index(cmd, subcmd)]; @@ -879,6 +912,11 @@ init: return cdb; } +/** + * cdebbuf_free() - free CAPI debug buffer + * @cdb: buffer to free + */ + void cdebbuf_free(_cdebbuf *cdb) { if (likely(cdb == g_debbuf)) { @@ -891,6 +929,16 @@ void cdebbuf_free(_cdebbuf *cdb) } +/** + * capi_message2str() - format CAPI 2.0 message for printing + * @msg: CAPI 2.0 message + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message in @msg. + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + _cdebbuf *capi_message2str(u8 * msg) { _cdebbuf *cdb; @@ -926,6 +974,17 @@ _cdebbuf *capi_message2str(u8 * msg) return cdb; } +/** + * capi_cmsg2str() - format _cmsg structure for printing + * @cmsg: _cmsg structure + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message stored in @cmsg by a previous call to + * capi_cmsg2message() or capi_message2cmsg(). + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + _cdebbuf *capi_cmsg2str(_cmsg * cmsg) { _cdebbuf *cdb; -- cgit v0.10.2 From 7d31acda9f8eaa27e2fd232712f7e1f3e9a79bdb Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sun, 7 Jun 2009 09:09:24 +0000 Subject: isdn: prevent NULL ptr Oops in capi_cmsg2str() The dereferencing of the private pointer cmsg->m in capi_cmsg2str() may cause an Oops in case of an error, which is particularly inconvenient as that function is typically used to format an error message. Add a NULL pointer check to avoid this. Impact: error handling improvement Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index c7c2902..16f2e46 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -989,6 +989,8 @@ _cdebbuf *capi_cmsg2str(_cmsg * cmsg) { _cdebbuf *cdb; + if (!cmsg->m) + return NULL; /* no message */ cdb = cdebbuf_alloc(); if (!cdb) return NULL; -- cgit v0.10.2 From fe93299a008a7056fe1790744b3a425ddf79a16b Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sun, 7 Jun 2009 09:09:24 +0000 Subject: isdn: extend INTERFACE.CAPI document Clarify calling context and return codes of callback methods, and add a description of the _cmsg structure and helper functions. Impact: documentation Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI index 4631538..686e107 100644 --- a/Documentation/isdn/INTERFACE.CAPI +++ b/Documentation/isdn/INTERFACE.CAPI @@ -114,20 +114,36 @@ char *driver_name int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata) (optional) pointer to a callback function for sending firmware and configuration data to the device + Return value: 0 on success, error code on error + Called in process context. void (*reset_ctr)(struct capi_ctr *ctrlr) - pointer to a callback function for performing a reset on the device, - releasing all registered applications + (optional) pointer to a callback function for performing a reset on + the device, releasing all registered applications + Called in process context. void (*register_appl)(struct capi_ctr *ctrlr, u16 applid, capi_register_params *rparam) void (*release_appl)(struct capi_ctr *ctrlr, u16 applid) pointers to callback functions for registration and deregistration of applications with the device + Calls to these functions are serialized by Kernel CAPI so that only + one call to any of them is active at any time. u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb) pointer to a callback function for sending a CAPI message to the device + Return value: CAPI error code + If the method returns 0 (CAPI_NOERROR) the driver has taken ownership + of the skb and the caller may no longer access it. If it returns a + non-zero (error) value then ownership of the skb returns to the caller + who may reuse or free it. + The return value should only be used to signal problems with respect + to accepting or queueing the message. Errors occurring during the + actual processing of the message should be signaled with an + appropriate reply message. + Calls to this function are not serialized by Kernel CAPI, ie. it must + be prepared to be re-entered. char *(*procinfo)(struct capi_ctr *ctrlr) pointer to a callback function returning the entry for the device in @@ -138,6 +154,8 @@ read_proc_t *ctr_read_proc system entry, /proc/capi/controllers/; will be called with a pointer to the device's capi_ctr structure as the last (data) argument +Note: Callback functions are never called in interrupt context. + - to be filled in before calling capi_ctr_ready(): u8 manu[CAPI_MANUFACTURER_LEN] @@ -153,6 +171,45 @@ u8 serial[CAPI_SERIAL_LEN] value to return for CAPI_GET_SERIAL +4.3 The _cmsg Structure + +(declared in ) + +The _cmsg structure stores the contents of a CAPI 2.0 message in an easily +accessible form. It contains members for all possible CAPI 2.0 parameters, of +which only those appearing in the message type currently being processed are +actually used. Unused members should be set to zero. + +Members are named after the CAPI 2.0 standard names of the parameters they +represent. See for the exact spelling. Member data +types are: + +u8 for CAPI parameters of type 'byte' + +u16 for CAPI parameters of type 'word' + +u32 for CAPI parameters of type 'dword' + +_cstruct for CAPI parameters of type 'struct' not containing any + variably-sized (struct) subparameters (eg. 'Called Party Number') + The member is a pointer to a buffer containing the parameter in + CAPI encoding (length + content). It may also be NULL, which will + be taken to represent an empty (zero length) parameter. + +_cmstruct for CAPI parameters of type 'struct' containing 'struct' + subparameters ('Additional Info' and 'B Protocol') + The representation is a single byte containing one of the values: + CAPI_DEFAULT: the parameter is empty + CAPI_COMPOSE: the values of the subparameters are stored + individually in the corresponding _cmsg structure members + +Functions capi_cmsg2message() and capi_message2cmsg() are provided to convert +messages between their transport encoding described in the CAPI 2.0 standard +and their _cmsg structure representation. Note that capi_cmsg2message() does +not know or check the size of its destination buffer. The caller must make +sure it is big enough to accomodate the resulting CAPI message. + + 5. Lower Layer Interface Functions (declared in ) @@ -211,3 +268,32 @@ CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr) Controller/PLCI/NCCI (u32) CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16) + +Library functions for working with _cmsg structures +(from ): + +unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg) + Assembles a CAPI 2.0 message from the parameters in *cmsg, storing the + result in *msg. + +unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg) + Disassembles the CAPI 2.0 message in *msg, storing the parameters in + *cmsg. + +unsigned capi_cmsg_header(_cmsg *cmsg, u16 ApplId, u8 Command, u8 Subcommand, + u16 Messagenumber, u32 Controller) + Fills the header part and address field of the _cmsg structure *cmsg + with the given values, zeroing the remainder of the structure so only + parameters with non-default values need to be changed before sending + the message. + +void capi_cmsg_answer(_cmsg *cmsg) + Sets the low bit of the Subcommand field in *cmsg, thereby converting + _REQ to _CONF and _IND to _RESP. + +char *capi_cmd2str(u8 Command, u8 Subcommand) + Returns the CAPI 2.0 message name corresponding to the given command + and subcommand values, as a static ASCII string. The return value may + be NULL if the command/subcommand is not one of those defined in the + CAPI 2.0 standard. + -- cgit v0.10.2 From 963267bc5d4de4a0da104a64300375d186575332 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Jun 2009 02:42:35 -0700 Subject: declance: Restore tx descriptor ring locking A driver overhaul on 29 Feb 2000 (!) broke locking around fiddling with the tx descriptor ring in start_xmit(); a follow-on "fix" removed the broken remnants altogether. Here's a patch to restore proper locking in the function -- the complement in the interrupt handler has been correct all the time. This *may* have been the reason for the occasional confusion of the chip -- triggering a tx timeout followed by a chip reset sequence -- seen on R4k-based DECstations with the onboard Ethernet interface. Another theory is the confusion is due to an unindentified problem -- perhaps a silicon erratum -- associated with the variation of the MT ASIC used to interface the R4k CPU to the rest of the system on these computers; with its aggressive write-back buffering the design is particularly weakly ordered when it comes to MMIO (in the absence of ordering barriers uncached reads are allowed to bypass earlier uncached writes, even if to the same location), which may trigger all kinds of corner cases in peripheral hardware as well as software. Either way this piece of code is buggy. Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller diff --git a/drivers/net/declance.c b/drivers/net/declance.c index b62405a..2b22e58 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -895,6 +895,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; volatile u16 *ib = (volatile u16 *)dev->mem_start; + unsigned long flags; int entry, len; len = skb->len; @@ -907,6 +908,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += len; + spin_lock_irqsave(&lp->lock, flags); + entry = lp->tx_new; *lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len); *lib_ptr(ib, btx_ring[entry].misc, lp->type) = 0; @@ -925,6 +928,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Kick the lance: transmit now */ writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD); + spin_unlock_irqrestore(&lp->lock, flags); + dev->trans_start = jiffies; dev_kfree_skb(skb); -- cgit v0.10.2 From 21bea495943f9532f16e819066b340762124f5dd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 8 Jun 2009 21:38:31 +0900 Subject: fat: split fat_generic_ioctl Split up fat_generic_ioctl and add separate functions for the two implemented ioctls. Signed-off-by: Christoph Hellwig Signed-off-by: OGAWA Hirofumi diff --git a/fs/fat/file.c b/fs/fat/file.c index 6214287..9b94094 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -18,106 +18,112 @@ #include #include "fat.h" -int fat_generic_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) { + u32 attr; + + mutex_lock(&inode->i_mutex); + attr = fat_make_attrs(inode); + mutex_unlock(&inode->i_mutex); + + return put_user(attr, user_attr); +} + +static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) +{ + struct inode *inode = file->f_path.dentry->d_inode; struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - u32 __user *user_attr = (u32 __user *)arg; + int is_dir = S_ISDIR(inode->i_mode); + u32 attr, oldattr; + struct iattr ia; + int err; - switch (cmd) { - case FAT_IOCTL_GET_ATTRIBUTES: - { - u32 attr; + err = get_user(attr, user_attr); + if (err) + goto out; - mutex_lock(&inode->i_mutex); - attr = fat_make_attrs(inode); - mutex_unlock(&inode->i_mutex); + mutex_lock(&inode->i_mutex); + err = mnt_want_write(file->f_path.mnt); + if (err) + goto out_unlock_inode; - return put_user(attr, user_attr); + /* + * ATTR_VOLUME and ATTR_DIR cannot be changed; this also + * prevents the user from turning us into a VFAT + * longname entry. Also, we obviously can't set + * any of the NTFS attributes in the high 24 bits. + */ + attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); + /* Merge in ATTR_VOLUME and ATTR_DIR */ + attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | + (is_dir ? ATTR_DIR : 0); + oldattr = fat_make_attrs(inode); + + /* Equivalent to a chmod() */ + ia.ia_valid = ATTR_MODE | ATTR_CTIME; + ia.ia_ctime = current_fs_time(inode->i_sb); + if (is_dir) + ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); + else { + ia.ia_mode = fat_make_mode(sbi, attr, + S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); } - case FAT_IOCTL_SET_ATTRIBUTES: - { - u32 attr, oldattr; - int err, is_dir = S_ISDIR(inode->i_mode); - struct iattr ia; - err = get_user(attr, user_attr); - if (err) - return err; + /* The root directory has no attributes */ + if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { + err = -EINVAL; + goto out_drop_write; + } - mutex_lock(&inode->i_mutex); - - err = mnt_want_write(filp->f_path.mnt); - if (err) - goto up_no_drop_write; - - /* - * ATTR_VOLUME and ATTR_DIR cannot be changed; this also - * prevents the user from turning us into a VFAT - * longname entry. Also, we obviously can't set - * any of the NTFS attributes in the high 24 bits. - */ - attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); - /* Merge in ATTR_VOLUME and ATTR_DIR */ - attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | - (is_dir ? ATTR_DIR : 0); - oldattr = fat_make_attrs(inode); - - /* Equivalent to a chmod() */ - ia.ia_valid = ATTR_MODE | ATTR_CTIME; - ia.ia_ctime = current_fs_time(inode->i_sb); - if (is_dir) - ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); - else { - ia.ia_mode = fat_make_mode(sbi, attr, - S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); - } + if (sbi->options.sys_immutable && + ((attr | oldattr) & ATTR_SYS) && + !capable(CAP_LINUX_IMMUTABLE)) { + err = -EPERM; + goto out_drop_write; + } - /* The root directory has no attributes */ - if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { - err = -EINVAL; - goto up; - } + /* + * The security check is questionable... We single + * out the RO attribute for checking by the security + * module, just because it maps to a file mode. + */ + err = security_inode_setattr(file->f_path.dentry, &ia); + if (err) + goto out_drop_write; - if (sbi->options.sys_immutable) { - if ((attr | oldattr) & ATTR_SYS) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - err = -EPERM; - goto up; - } - } - } + /* This MUST be done before doing anything irreversible... */ + err = fat_setattr(file->f_path.dentry, &ia); + if (err) + goto out_drop_write; + + fsnotify_change(file->f_path.dentry, ia.ia_valid); + if (sbi->options.sys_immutable) { + if (attr & ATTR_SYS) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= S_IMMUTABLE; + } - /* - * The security check is questionable... We single - * out the RO attribute for checking by the security - * module, just because it maps to a file mode. - */ - err = security_inode_setattr(filp->f_path.dentry, &ia); - if (err) - goto up; - - /* This MUST be done before doing anything irreversible... */ - err = fat_setattr(filp->f_path.dentry, &ia); - if (err) - goto up; - - fsnotify_change(filp->f_path.dentry, ia.ia_valid); - if (sbi->options.sys_immutable) { - if (attr & ATTR_SYS) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= S_IMMUTABLE; - } + fat_save_attrs(inode, attr); + mark_inode_dirty(inode); +out_drop_write: + mnt_drop_write(file->f_path.mnt); +out_unlock_inode: + mutex_unlock(&inode->i_mutex); +out: + return err; +} - fat_save_attrs(inode, attr); - mark_inode_dirty(inode); -up: - mnt_drop_write(filp->f_path.mnt); -up_no_drop_write: - mutex_unlock(&inode->i_mutex); - return err; - } +int fat_generic_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + u32 __user *user_attr = (u32 __user *)arg; + + switch (cmd) { + case FAT_IOCTL_GET_ATTRIBUTES: + return fat_ioctl_get_attributes(inode, user_attr); + case FAT_IOCTL_SET_ATTRIBUTES: + return fat_ioctl_set_attributes(filp, user_attr); default: return -ENOTTY; /* Inappropriate ioctl for device */ } -- cgit v0.10.2 From 8db4dc46dcff7568896aa1eae4bd07620ce3dd93 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 20 Apr 2009 01:31:05 -0300 Subject: Bluetooth: Use macros for L2CAP channel identifiers Use macros instead of hardcoded numbers to make the L2CAP source code more readable. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f566aa1..ed4ba91 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -106,6 +106,12 @@ struct l2cap_conn_rsp { __le16 status; } __attribute__ ((packed)); +/* channel indentifier */ +#define L2CAP_CID_SIGNALING 0x0001 +#define L2CAP_CID_CONN_LESS 0x0002 +#define L2CAP_CID_DYN_START 0x0040 +#define L2CAP_CID_DYN_END 0xffff + /* connect result */ #define L2CAP_CR_SUCCESS 0x0000 #define L2CAP_CR_PEND 0x0001 diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ca4d3b4..ff1744e 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -161,9 +161,9 @@ static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) { - u16 cid = 0x0040; + u16 cid = L2CAP_CID_DYN_START; - for (; cid < 0xffff; cid++) { + for (; cid < L2CAP_CID_DYN_END; cid++) { if(!__l2cap_get_chan_by_scid(l, cid)) return cid; } @@ -215,13 +215,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so l2cap_pi(sk)->scid = l2cap_alloc_cid(l); } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ - l2cap_pi(sk)->scid = 0x0002; - l2cap_pi(sk)->dcid = 0x0002; + l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; + l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ - l2cap_pi(sk)->scid = 0x0001; - l2cap_pi(sk)->dcid = 0x0001; + l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; + l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } @@ -1598,7 +1598,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); - lh->cid = cpu_to_le16(0x0001); + lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); cmd->code = code; @@ -2420,11 +2420,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("len %d, cid 0x%4.4x", len, cid); switch (cid) { - case 0x0001: + case L2CAP_CID_SIGNALING: l2cap_sig_channel(conn, skb); break; - case 0x0002: + case L2CAP_CID_CONN_LESS: psm = get_unaligned((__le16 *) skb->data); skb_pull(skb, 2); l2cap_conless_channel(conn, psm, skb); -- cgit v0.10.2 From 589d27464846c7cb758f93d9ee380c8ff05a161c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 20 Apr 2009 01:31:07 -0300 Subject: Bluetooth: Use macro for L2CAP hint mask on receiving config request Using the L2CAP_CONF_HINT macro is easier to understand than using a hardcoded 0x80 value. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ed4ba91..300b63f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -149,6 +149,8 @@ struct l2cap_conf_opt { } __attribute__ ((packed)); #define L2CAP_CONF_OPT_SIZE 2 +#define L2CAP_CONF_HINT 0x80 + #define L2CAP_CONF_MTU 0x01 #define L2CAP_CONF_FLUSH_TO 0x02 #define L2CAP_CONF_QOS 0x03 diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ff1744e..c0c0915 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1739,7 +1739,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); - hint = type & 0x80; + hint = type & L2CAP_CONF_HINT; type &= 0x7f; switch (type) { -- cgit v0.10.2 From 44d0e48e8a1fa174edf11e03dc70bd6a146b2a40 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Apr 2009 07:09:16 +0200 Subject: Bluetooth: Remove unnecessary variable initialization The initial value of err is not used until it is set to -ENOMEM. So just remove the initialization completely. Based on a patch from Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c0c0915..77e6715 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -844,7 +844,7 @@ static int l2cap_do_connect(struct sock *sk) struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; - int err = 0; + int err; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); -- cgit v0.10.2 From af05b30bcb65da3ed488af54ee92e96bebe0be5e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 20 Apr 2009 01:31:08 -0300 Subject: Bluetooth: Fix errors and warnings in L2CAP reported by checkpatch.pl This patch fixes the errors without changing the l2cap.o binary: text data bss dec hex filename 18059 568 0 18627 48c3 l2cap.o.after 18059 568 0 18627 48c3 l2cap.o.before Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 77e6715..f6a82f2 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -40,10 +40,10 @@ #include #include #include +#include #include #include -#include #include #include @@ -134,7 +134,8 @@ static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 struct sock *s; read_lock(&l->lock); s = __l2cap_get_chan_by_scid(l, cid); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l->lock); return s; } @@ -154,7 +155,8 @@ static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 struct sock *s; read_lock(&l->lock); s = __l2cap_get_chan_by_ident(l, ident); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l->lock); return s; } @@ -164,7 +166,7 @@ static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) u16 cid = L2CAP_CID_DYN_START; for (; cid < L2CAP_CID_DYN_END; cid++) { - if(!__l2cap_get_chan_by_scid(l, cid)) + if (!__l2cap_get_chan_by_scid(l, cid)) return cid; } @@ -204,7 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so { struct l2cap_chan_list *l = &conn->chan_list; - BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, + l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); conn->disc_reason = 0x13; @@ -272,7 +275,7 @@ static inline int l2cap_check_security(struct sock *sk) if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) auth_type = HCI_AT_NO_BONDING_MITM; else - auth_type = HCI_AT_NO_BONDING; + auth_type = HCI_AT_NO_BONDING; if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; @@ -588,7 +591,8 @@ static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t struct sock *s; read_lock(&l2cap_sk_list.lock); s = __l2cap_get_sock_by_psm(state, psm, src); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l2cap_sk_list.lock); return s; } @@ -849,7 +853,8 @@ static int l2cap_do_connect(struct sock *sk) BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); - if (!(hdev = hci_get_route(dst, src))) + hdev = hci_get_route(dst, src); + if (!hdev) return -EHOSTUNREACH; hci_dev_lock_bh(hdev); @@ -950,7 +955,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al goto done; } - switch(sk->sk_state) { + switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: @@ -975,7 +980,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); l2cap_pi(sk)->psm = la.l2_psm; - if ((err = l2cap_do_connect(sk))) + err = l2cap_do_connect(sk); + if (err) goto done; wait: @@ -1114,7 +1120,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb, **frag; - int err, hlen, count, sent=0; + int err, hlen, count, sent = 0; struct l2cap_hdr *lh; BT_DBG("sk %p len %d", sk, len); @@ -1167,8 +1173,8 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) frag = &(*frag)->next; } - - if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0) + err = hci_send_acl(conn->hcon, skb, 0); + if (err < 0) goto fail; return sent; @@ -1556,7 +1562,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_chan_list *l = &conn->chan_list; struct sk_buff *nskb; - struct sock * sk; + struct sock *sk; BT_DBG("conn %p", conn); @@ -1568,8 +1574,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) /* Don't send frame to the socket it came from */ if (skb->sk == sk) continue; - - if (!(nskb = skb_clone(skb, GFP_ATOMIC))) + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) continue; if (sock_queue_rcv_skb(sk, nskb)) @@ -1587,7 +1593,8 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, struct l2cap_hdr *lh; int len, count; - BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen); + BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", + conn, code, ident, dlen); len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; count = min_t(unsigned int, conn->mtu, len); @@ -1966,10 +1973,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); if (scid) { - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; } else { - if (!(sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident))) + sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + if (!sk) return 0; } @@ -2012,7 +2021,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) return -ENOENT; if (sk->sk_state == BT_DISCONN) @@ -2079,9 +2089,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr flags = __le16_to_cpu(rsp->flags); result = __le16_to_cpu(rsp->result); - BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", + scid, flags, result); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; switch (result) { @@ -2142,7 +2154,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) return 0; rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); @@ -2169,7 +2182,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; l2cap_chan_del(sk, 0); @@ -2403,7 +2417,8 @@ drop: kfree_skb(skb); done: - if (sk) bh_unlock_sock(sk); + if (sk) + bh_unlock_sock(sk); return 0; } @@ -2650,7 +2665,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl } /* Allocate skb for the complete frame (with header) */ - if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC))) + conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!conn->rx_skb) goto drop; skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), @@ -2710,7 +2726,7 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf) read_unlock_bh(&l2cap_sk_list.lock); - return (str - buf); + return str - buf; } static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL); -- cgit v0.10.2 From 47ec1dcd696d56a7c396e5838516a566ecd4b03d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 2 May 2009 18:57:55 -0700 Subject: Bluetooth: Add basic constants for L2CAP ERTM support and use them This adds the basic constants required to add support for L2CAP Enhanced Retransmission feature. Based on a patch from Nathan Holstein Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 300b63f..e919fca 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -26,8 +26,13 @@ #define __L2CAP_H /* L2CAP defaults */ -#define L2CAP_DEFAULT_MTU 672 -#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF +#define L2CAP_DEFAULT_MTU 672 +#define L2CAP_DEFAULT_FLUSH_TO 0xffff +#define L2CAP_DEFAULT_RX_WINDOW 1 +#define L2CAP_DEFAULT_MAX_RECEIVE 1 +#define L2CAP_DEFAULT_RETRANS_TO 300 /* 300 milliseconds */ +#define L2CAP_DEFAULT_MONITOR_TO 1000 /* 1 second */ +#define L2CAP_DEFAULT_MAX_RX_APDU 0xfff7 #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ @@ -64,17 +69,29 @@ struct l2cap_conninfo { #define L2CAP_LM_SECURE 0x0020 /* L2CAP command codes */ -#define L2CAP_COMMAND_REJ 0x01 -#define L2CAP_CONN_REQ 0x02 -#define L2CAP_CONN_RSP 0x03 -#define L2CAP_CONF_REQ 0x04 -#define L2CAP_CONF_RSP 0x05 -#define L2CAP_DISCONN_REQ 0x06 -#define L2CAP_DISCONN_RSP 0x07 -#define L2CAP_ECHO_REQ 0x08 -#define L2CAP_ECHO_RSP 0x09 -#define L2CAP_INFO_REQ 0x0a -#define L2CAP_INFO_RSP 0x0b +#define L2CAP_COMMAND_REJ 0x01 +#define L2CAP_CONN_REQ 0x02 +#define L2CAP_CONN_RSP 0x03 +#define L2CAP_CONF_REQ 0x04 +#define L2CAP_CONF_RSP 0x05 +#define L2CAP_DISCONN_REQ 0x06 +#define L2CAP_DISCONN_RSP 0x07 +#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_INFO_REQ 0x0a +#define L2CAP_INFO_RSP 0x0b + +/* L2CAP feature mask */ +#define L2CAP_FEAT_FLOWCTL 0x00000001 +#define L2CAP_FEAT_RETRANS 0x00000002 +#define L2CAP_FEAT_ERTM 0x00000008 +#define L2CAP_FEAT_STREAMING 0x00000010 +#define L2CAP_FEAT_FCS 0x00000020 +#define L2CAP_FEAT_FIXED_CHAN 0x00000080 + +/* L2CAP checksum option */ +#define L2CAP_FCS_NONE 0x00 +#define L2CAP_FCS_CRC16 0x01 /* L2CAP structures */ struct l2cap_hdr { @@ -113,16 +130,16 @@ struct l2cap_conn_rsp { #define L2CAP_CID_DYN_END 0xffff /* connect result */ -#define L2CAP_CR_SUCCESS 0x0000 -#define L2CAP_CR_PEND 0x0001 -#define L2CAP_CR_BAD_PSM 0x0002 -#define L2CAP_CR_SEC_BLOCK 0x0003 -#define L2CAP_CR_NO_MEM 0x0004 +#define L2CAP_CR_SUCCESS 0x0000 +#define L2CAP_CR_PEND 0x0001 +#define L2CAP_CR_BAD_PSM 0x0002 +#define L2CAP_CR_SEC_BLOCK 0x0003 +#define L2CAP_CR_NO_MEM 0x0004 /* connect status */ -#define L2CAP_CS_NO_INFO 0x0000 -#define L2CAP_CS_AUTHEN_PEND 0x0001 -#define L2CAP_CS_AUTHOR_PEND 0x0002 +#define L2CAP_CS_NO_INFO 0x0000 +#define L2CAP_CS_AUTHEN_PEND 0x0001 +#define L2CAP_CS_AUTHOR_PEND 0x0002 struct l2cap_conf_req { __le16 dcid; @@ -150,11 +167,13 @@ struct l2cap_conf_opt { #define L2CAP_CONF_OPT_SIZE 2 #define L2CAP_CONF_HINT 0x80 +#define L2CAP_CONF_MASK 0x7f #define L2CAP_CONF_MTU 0x01 #define L2CAP_CONF_FLUSH_TO 0x02 #define L2CAP_CONF_QOS 0x03 #define L2CAP_CONF_RFC 0x04 +#define L2CAP_CONF_FCS 0x05 #define L2CAP_CONF_MAX_SIZE 22 @@ -170,6 +189,8 @@ struct l2cap_conf_rfc { #define L2CAP_MODE_BASIC 0x00 #define L2CAP_MODE_RETRANS 0x01 #define L2CAP_MODE_FLOWCTL 0x02 +#define L2CAP_MODE_ERTM 0x03 +#define L2CAP_MODE_STREAM 0x04 struct l2cap_disconn_req { __le16 dcid; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f6a82f2..3382950 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -52,7 +52,7 @@ #define VERSION "2.13" -static u32 l2cap_feat_mask = 0x0080; +static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; static const struct proto_ops l2cap_sock_ops; @@ -1747,7 +1747,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) len -= l2cap_get_conf_opt(&req, &type, &olen, &val); hint = type & L2CAP_CONF_HINT; - type &= 0x7f; + type &= L2CAP_CONF_MASK; switch (type) { case L2CAP_CONF_MTU: @@ -2244,7 +2244,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm if (type == L2CAP_IT_FEAT_MASK) { conn->feat_mask = get_unaligned_le32(rsp->data); - if (conn->feat_mask & 0x0080) { + if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { struct l2cap_info_req req; req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); -- cgit v0.10.2 From b4324b5dc5b62ba76372e1bf8927230cf744df66 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 7 Jun 2009 18:06:51 +0200 Subject: Bluetooth: Remove pointless endian conversion helpers The Bluetooth source uses some endian conversion helpers, that in the end translate to kernel standard routines. So remove this obfuscation since it is fully pointless. Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 3ad5390..cf8bcb2 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -81,12 +81,6 @@ enum { BT_CLOSED }; -/* Endianness conversions */ -#define htobs(a) __cpu_to_le16(a) -#define htobl(a) __cpu_to_le32(a) -#define btohs(a) __le16_to_cpu(a) -#define btohl(a) __le32_to_cpu(a) - /* BD Address */ typedef struct { __u8 b[6]; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 3382950..bd0a4c1 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -812,7 +812,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) goto done; } - if (la.l2_psm && btohs(la.l2_psm) < 0x1001 && + if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) { err = -EACCES; goto done; @@ -829,7 +829,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) l2cap_pi(sk)->sport = la.l2_psm; sk->sk_state = BT_BOUND; - if (btohs(la.l2_psm) == 0x0001 || btohs(la.l2_psm) == 0x0003) + if (__le16_to_cpu(la.l2_psm) == 0x0001 || + __le16_to_cpu(la.l2_psm) == 0x0003) l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; } @@ -1015,9 +1016,9 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) write_lock_bh(&l2cap_sk_list.lock); for (psm = 0x1001; psm < 0x1100; psm += 2) - if (!__l2cap_get_sock_by_addr(htobs(psm), src)) { - l2cap_pi(sk)->psm = htobs(psm); - l2cap_pi(sk)->sport = htobs(psm); + if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { + l2cap_pi(sk)->psm = cpu_to_le16(psm); + l2cap_pi(sk)->sport = cpu_to_le16(psm); err = 0; break; } @@ -1106,11 +1107,11 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l if (peer) { la->l2_psm = l2cap_pi(sk)->psm; bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); - la->l2_cid = htobs(l2cap_pi(sk)->dcid); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); } else { la->l2_psm = l2cap_pi(sk)->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); - la->l2_cid = htobs(l2cap_pi(sk)->scid); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); } return 0; @@ -2720,8 +2721,8 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf) str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->sec_level); + sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, + pi->dcid, pi->imtu, pi->omtu, pi->sec_level); } read_unlock_bh(&l2cap_sk_list.lock); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 374536e05..e50566e 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -679,7 +679,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst bacpy(&addr.l2_bdaddr, dst); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = htobs(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); if (*err == 0 || *err == -EINPROGRESS) @@ -852,9 +852,9 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d } if (cr && channel_mtu >= 0) - pn->mtu = htobs(channel_mtu); + pn->mtu = cpu_to_le16(channel_mtu); else - pn->mtu = htobs(d->mtu); + pn->mtu = cpu_to_le16(d->mtu); *ptr = __fcs(buf); ptr++; @@ -1056,7 +1056,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) if (len > 127) { hdr = (void *) skb_push(skb, 4); - put_unaligned(htobs(__len16(len)), (__le16 *) &hdr->len); + put_unaligned(cpu_to_le16(__len16(len)), (__le16 *) &hdr->len); } else { hdr = (void *) skb_push(skb, 3); hdr->len = __len8(len); @@ -1289,7 +1289,7 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) d->priority = pn->priority; - d->mtu = btohs(pn->mtu); + d->mtu = __le16_to_cpu(pn->mtu); if (cr && d->mtu > s->mtu) d->mtu = s->mtu; @@ -1922,7 +1922,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) /* Bind socket */ bacpy(&addr.l2_bdaddr, ba); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = htobs(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0) { -- cgit v0.10.2 From ac28494c51ad20c7ff9cb991eaeee359a500d88e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 7 Jun 2009 18:09:57 +0200 Subject: Bluetooth: Use only MISC_DYNAMIC_MINOR for virtual driver Allowing to specify a specific misc minor number for the virtual driver is pretty much useless and nobody is using this feature. So just remove it and use MISC_DYNAMIC_MINOR all the time. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 0bbefba..379d302 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -40,7 +40,7 @@ #include #include -#define VERSION "1.2" +#define VERSION "1.3" static int minor = MISC_DYNAMIC_MINOR; @@ -342,16 +342,15 @@ static const struct file_operations vhci_fops = { }; static struct miscdevice vhci_miscdev= { - .name = "vhci", - .fops = &vhci_fops, + .name = "vhci", + .fops = &vhci_fops, + .minor = MISC_DYNAMIC_MINOR, }; static int __init vhci_init(void) { BT_INFO("Virtual HCI driver ver %s", VERSION); - vhci_miscdev.minor = minor; - if (misc_register(&vhci_miscdev) < 0) { BT_ERR("Can't register misc device with minor %d", minor); return -EIO; @@ -369,9 +368,6 @@ static void __exit vhci_exit(void) module_init(vhci_init); module_exit(vhci_exit); -module_param(minor, int, 0444); -MODULE_PARM_DESC(minor, "Miscellaneous minor device number"); - MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_VERSION(VERSION); -- cgit v0.10.2 From 4db7589f3d88c09d740560f1dcf2d4d843d918f2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 8 Jun 2009 14:13:57 +0200 Subject: Bluetooth: Use wait_event_interruptible for virtual driver The virtual driver still uses a home grown way of waiting for events and so just replace it with wait_event_interruptible. And while at it remove the useless access_ok() checks. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 379d302..0f5e049 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -179,41 +179,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, static ssize_t vhci_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { - DECLARE_WAITQUEUE(wait, current); struct vhci_data *data = file->private_data; struct sk_buff *skb; ssize_t ret = 0; - add_wait_queue(&data->read_wait, &wait); while (count) { - set_current_state(TASK_INTERRUPTIBLE); - skb = skb_dequeue(&data->readq); - if (!skb) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - schedule(); - continue; + if (skb) { + ret = vhci_put_user(data, skb, buf, count); + if (ret < 0) + skb_queue_head(&data->readq, skb); + else + kfree_skb(skb); + break; } - if (access_ok(VERIFY_WRITE, buf, count)) - ret = vhci_put_user(data, skb, buf, count); - else - ret = -EFAULT; + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } - kfree_skb(skb); - break; + ret = wait_event_interruptible(data->read_wait, + !skb_queue_empty(&data->readq)); + if (ret < 0) + break; } - set_current_state(TASK_RUNNING); - remove_wait_queue(&data->read_wait, &wait); return ret; } @@ -223,9 +213,6 @@ static ssize_t vhci_write(struct file *file, { struct vhci_data *data = file->private_data; - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - return vhci_get_user(data, buf, count); } -- cgit v0.10.2 From 3857abc622102b808de11ff3393d541b826ab952 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 8 Jun 2009 14:24:03 +0200 Subject: Bluetooth: Remove BKL from open callback of virtual driver The BKL push down added some BKL into the open callback of the virtual driver. The driver is really simple and need no such locking and so just remove it. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 0f5e049..7ebdb1d 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -246,11 +246,9 @@ static int vhci_open(struct inode *inode, struct file *file) skb_queue_head_init(&data->readq); init_waitqueue_head(&data->read_wait); - lock_kernel(); hdev = hci_alloc_dev(); if (!hdev) { kfree(data); - unlock_kernel(); return -ENOMEM; } @@ -271,12 +269,10 @@ static int vhci_open(struct inode *inode, struct file *file) BT_ERR("Can't register HCI device"); kfree(data); hci_free_dev(hdev); - unlock_kernel(); return -EBUSY; } file->private_data = data; - unlock_kernel(); return nonseekable_open(inode, file); } -- cgit v0.10.2 From 092b85853b161a5ca285c429faf1cf2ff4318a01 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 8 Jun 2009 14:31:00 +0200 Subject: Bluetooth: Remove unused and unneeded support in virtual driver The virtual driver implements fasync and ioctl support, but it is not used and unneeded due to its constraints via the Bluetooth core layer. So too just make the driver simpler, remove support for both of them. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 7ebdb1d..1df9dda 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -51,14 +51,8 @@ struct vhci_data { wait_queue_head_t read_wait; struct sk_buff_head readq; - - struct fasync_struct *fasync; }; -#define VHCI_FASYNC 0x0010 - -static struct miscdevice vhci_miscdev; - static int vhci_open_dev(struct hci_dev *hdev) { set_bit(HCI_RUNNING, &hdev->flags); @@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb) memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); skb_queue_tail(&data->readq, skb); - if (data->flags & VHCI_FASYNC) - kill_fasync(&data->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&data->read_wait); return 0; @@ -293,35 +284,13 @@ static int vhci_release(struct inode *inode, struct file *file) return 0; } -static int vhci_fasync(int fd, struct file *file, int on) -{ - struct vhci_data *data = file->private_data; - int err = 0; - - lock_kernel(); - err = fasync_helper(fd, file, on, &data->fasync); - if (err < 0) - goto out; - - if (on) - data->flags |= VHCI_FASYNC; - else - data->flags &= ~VHCI_FASYNC; - -out: - unlock_kernel(); - return err; -} - static const struct file_operations vhci_fops = { - .owner = THIS_MODULE, .read = vhci_read, .write = vhci_write, .poll = vhci_poll, .ioctl = vhci_ioctl, .open = vhci_open, .release = vhci_release, - .fasync = vhci_fasync, }; static struct miscdevice vhci_miscdev= { -- cgit v0.10.2 From 611b30f74b5d8ca036a9923b3bf6e0ee10a21a53 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 8 Jun 2009 14:41:38 +0200 Subject: Bluetooth: Add native RFKILL soft-switch support for all devices With the re-write of the RFKILL subsystem it is now possible to easily integrate RFKILL soft-switch support into the Bluetooth subsystem. All Bluetooth devices will now get automatically RFKILL support. Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 73aead2..c4ca422 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -137,6 +137,8 @@ struct hci_dev { struct device *parent; struct device dev; + struct rfkill *rfkill; + struct module *owner; int (*open)(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cd06151..406ad07 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -476,6 +477,11 @@ int hci_dev_open(__u16 dev) hci_req_lock(hdev); + if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) { + ret = -ERFKILL; + goto done; + } + if (test_bit(HCI_UP, &hdev->flags)) { ret = -EALREADY; goto done; @@ -813,6 +819,24 @@ int hci_get_dev_info(void __user *arg) /* ---- Interface to HCI drivers ---- */ +static int hci_rfkill_set_block(void *data, bool blocked) +{ + struct hci_dev *hdev = data; + + BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked); + + if (!blocked) + return 0; + + hci_dev_do_close(hdev); + + return 0; +} + +static const struct rfkill_ops hci_rfkill_ops = { + .set_block = hci_rfkill_set_block, +}; + /* Alloc HCI device */ struct hci_dev *hci_alloc_dev(void) { @@ -844,7 +868,8 @@ int hci_register_dev(struct hci_dev *hdev) struct list_head *head = &hci_dev_list, *p; int i, id = 0; - BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner); + BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, + hdev->type, hdev->owner); if (!hdev->open || !hdev->close || !hdev->destruct) return -EINVAL; @@ -900,6 +925,15 @@ int hci_register_dev(struct hci_dev *hdev) hci_register_sysfs(hdev); + hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, + RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev); + if (hdev->rfkill) { + if (rfkill_register(hdev->rfkill) < 0) { + rfkill_destroy(hdev->rfkill); + hdev->rfkill = NULL; + } + } + hci_notify(hdev, HCI_DEV_REG); return id; @@ -924,6 +958,11 @@ int hci_unregister_dev(struct hci_dev *hdev) hci_notify(hdev, HCI_DEV_UNREG); + if (hdev->rfkill) { + rfkill_unregister(hdev->rfkill); + rfkill_destroy(hdev->rfkill); + } + hci_unregister_sysfs(hdev); __hci_dev_put(hdev); -- cgit v0.10.2 From f87fb666bb00a7afcbd7992d236e42ac544996f9 Mon Sep 17 00:00:00 2001 From: Jan Kasprzak Date: Mon, 8 Jun 2009 15:53:43 +0200 Subject: netfilter: nf_ct_icmp: keep the ICMP ct entries longer Current conntrack code kills the ICMP conntrack entry as soon as the first reply is received. This is incorrect, as we then see only the first ICMP echo reply out of several possible duplicates as ESTABLISHED, while the rest will be INVALID. Also this unnecessarily increases the conntrackd traffic on H-A firewalls. Make all the ICMP conntrack entries (including the replied ones) last for the default of nf_conntrack_icmp{,v6}_timeout seconds. Signed-off-by: Jan "Yenya" Kasprzak Signed-off-by: Patrick McHardy diff --git a/include/net/netfilter/ipv4/nf_conntrack_icmp.h b/include/net/netfilter/ipv4/nf_conntrack_icmp.h deleted file mode 100644 index 3dd22cf..0000000 --- a/include/net/netfilter/ipv4/nf_conntrack_icmp.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _NF_CONNTRACK_ICMP_H -#define _NF_CONNTRACK_ICMP_H -/* ICMP tracking. */ -#include - -struct ip_ct_icmp -{ - /* Optimization: when number in == number out, forget immediately. */ - atomic_t count; -}; -#endif /* _NF_CONNTRACK_ICMP_H */ diff --git a/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h index 86591af..67edd50 100644 --- a/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h +++ b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h @@ -9,7 +9,6 @@ #ifndef _NF_CONNTRACK_ICMPV6_H #define _NF_CONNTRACK_ICMPV6_H -#include #ifndef ICMPV6_NI_QUERY #define ICMPV6_NI_QUERY 139 @@ -18,10 +17,4 @@ #define ICMPV6_NI_REPLY 140 #endif -struct nf_ct_icmpv6 -{ - /* Optimization: when number in == number out, forget immediately. */ - atomic_t count; -}; - #endif /* _NF_CONNTRACK_ICMPV6_H */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 2ba36dd..2b87737 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -34,8 +33,6 @@ union nf_conntrack_proto { struct nf_ct_dccp dccp; struct ip_ct_sctp sctp; struct ip_ct_tcp tcp; - struct ip_ct_icmp icmp; - struct nf_ct_icmpv6 icmpv6; struct nf_ct_gre gre; }; diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index c6ab3d9..d71ba76 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -82,17 +82,10 @@ static int icmp_packet(struct nf_conn *ct, u_int8_t pf, unsigned int hooknum) { - /* Try to delete connection immediately after all replies: - won't actually vanish as we still have skb, and del_timer - means this will only run once even if count hits zero twice - (theoretically possible with SMP) */ - if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { - if (atomic_dec_and_test(&ct->proto.icmp.count)) - nf_ct_kill_acct(ct, ctinfo, skb); - } else { - atomic_inc(&ct->proto.icmp.count); - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); - } + /* Do not immediately delete the connection after the first + successful reply to avoid excessive conntrackd traffic + and also to handle correctly ICMP echo reply duplicates. */ + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); return NF_ACCEPT; } @@ -116,7 +109,6 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple); return false; } - atomic_set(&ct->proto.icmp.count, 0); return true; } diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index a0acd96..642dcb1 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -95,17 +95,10 @@ static int icmpv6_packet(struct nf_conn *ct, u_int8_t pf, unsigned int hooknum) { - /* Try to delete connection immediately after all replies: - won't actually vanish as we still have skb, and del_timer - means this will only run once even if count hits zero twice - (theoretically possible with SMP) */ - if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { - if (atomic_dec_and_test(&ct->proto.icmp.count)) - nf_ct_kill_acct(ct, ctinfo, skb); - } else { - atomic_inc(&ct->proto.icmp.count); - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); - } + /* Do not immediately delete the connection after the first + successful reply to avoid excessive conntrackd traffic + and also to handle correctly ICMP echo reply duplicates. */ + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); return NF_ACCEPT; } @@ -131,7 +124,6 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, type + 128); return false; } - atomic_set(&ct->proto.icmp.count, 0); return true; } -- cgit v0.10.2 From 11eeef41d5f63c7d2f7fdfcc733eb7fb137cc384 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Mon, 8 Jun 2009 17:01:51 +0200 Subject: netfilter: passive OS fingerprint xtables match Passive OS fingerprinting netfilter module allows to passively detect remote OS and perform various netfilter actions based on that knowledge. This module compares some data (WS, MSS, options and it's order, ttl, df and others) from packets with SYN bit set with dynamically loaded OS fingerprints. Fingerprint matching rules can be downloaded from OpenBSD source tree or found in archive and loaded via netfilter netlink subsystem into the kernel via special util found in archive. Archive contains library file (also attached), which was shipped with iptables extensions some time ago (at least when ipt_osf existed in patch-o-matic). Following changes were made in this release: * added NLM_F_CREATE/NLM_F_EXCL checks * dropped _rcu list traversing helpers in the protected add/remove calls * dropped unneded structures, debug prints, obscure comment and check Fingerprints can be downloaded from http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os or can be found in archive Example usage: -d switch removes fingerprints Please consider for inclusion. Thank you. Passive OS fingerprint homepage (archives, examples): http://www.ioremap.net/projects/osf Signed-off-by: Evgeniy Polyakov Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index af9d2fb..2aea503 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -33,6 +33,7 @@ header-y += xt_limit.h header-y += xt_mac.h header-y += xt_mark.h header-y += xt_multiport.h +header-y += xt_osf.h header-y += xt_owner.h header-y += xt_pkttype.h header-y += xt_quota.h diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 2214e51..bff4d57 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -46,7 +46,8 @@ struct nfgenmsg { #define NFNL_SUBSYS_CTNETLINK_EXP 2 #define NFNL_SUBSYS_QUEUE 3 #define NFNL_SUBSYS_ULOG 4 -#define NFNL_SUBSYS_COUNT 5 +#define NFNL_SUBSYS_OSF 5 +#define NFNL_SUBSYS_COUNT 6 #ifdef __KERNEL__ diff --git a/include/linux/netfilter/xt_osf.h b/include/linux/netfilter/xt_osf.h new file mode 100644 index 0000000..fd2272e --- /dev/null +++ b/include/linux/netfilter/xt_osf.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2003+ Evgeniy Polyakov + * + * + * 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 _XT_OSF_H +#define _XT_OSF_H + +#define MAXGENRELEN 32 + +#define XT_OSF_GENRE (1<<0) +#define XT_OSF_TTL (1<<1) +#define XT_OSF_LOG (1<<2) +#define XT_OSF_INVERT (1<<3) + +#define XT_OSF_LOGLEVEL_ALL 0 /* log all matched fingerprints */ +#define XT_OSF_LOGLEVEL_FIRST 1 /* log only the first matced fingerprint */ +#define XT_OSF_LOGLEVEL_ALL_KNOWN 2 /* do not log unknown packets */ + +#define XT_OSF_TTL_TRUE 0 /* True ip and fingerprint TTL comparison */ +#define XT_OSF_TTL_LESS 1 /* Check if ip TTL is less than fingerprint one */ +#define XT_OSF_TTL_NOCHECK 2 /* Do not compare ip and fingerprint TTL at all */ + +struct xt_osf_info { + char genre[MAXGENRELEN]; + __u32 len; + __u32 flags; + __u32 loglevel; + __u32 ttl; +}; + +/* + * Wildcard MSS (kind of). + * It is used to implement a state machine for the different wildcard values + * of the MSS and window sizes. + */ +struct xt_osf_wc { + __u32 wc; + __u32 val; +}; + +/* + * This struct represents IANA options + * http://www.iana.org/assignments/tcp-parameters + */ +struct xt_osf_opt { + __u16 kind, length; + struct xt_osf_wc wc; +}; + +struct xt_osf_user_finger { + struct xt_osf_wc wss; + + __u8 ttl, df; + __u16 ss, mss; + __u16 opt_num; + + char genre[MAXGENRELEN]; + char version[MAXGENRELEN]; + char subtype[MAXGENRELEN]; + + /* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */ + struct xt_osf_opt opt[MAX_IPOPTLEN]; +}; + +struct xt_osf_nlmsg { + struct xt_osf_user_finger f; + struct iphdr ip; + struct tcphdr tcp; +}; + +/* Defines for IANA option kinds */ + +enum iana_options { + OSFOPT_EOL = 0, /* End of options */ + OSFOPT_NOP, /* NOP */ + OSFOPT_MSS, /* Maximum segment size */ + OSFOPT_WSO, /* Window scale option */ + OSFOPT_SACKP, /* SACK permitted */ + OSFOPT_SACK, /* SACK */ + OSFOPT_ECHO, + OSFOPT_ECHOREPLY, + OSFOPT_TS, /* Timestamp option */ + OSFOPT_POCP, /* Partial Order Connection Permitted */ + OSFOPT_POSP, /* Partial Order Service Profile */ + + /* Others are not used in the current OSF */ + OSFOPT_EMPTY = 255, +}; + +/* + * Initial window size option state machine: multiple of mss, mtu or + * plain numeric value. Can also be made as plain numeric value which + * is not a multiple of specified value. + */ +enum xt_osf_window_size_options { + OSF_WSS_PLAIN = 0, + OSF_WSS_MSS, + OSF_WSS_MTU, + OSF_WSS_MODULO, + OSF_WSS_MAX, +}; + +/* + * Add/remove fingerprint from the kernel. + */ +enum xt_osf_msg_types { + OSF_MSG_ADD, + OSF_MSG_REMOVE, + OSF_MSG_MAX, +}; + +enum xt_osf_attr_type { + OSF_ATTR_UNSPEC, + OSF_ATTR_FINGER, + OSF_ATTR_MAX, +}; + +#endif /* _XT_OSF_H */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index cb3ad74..79ba47f 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -917,6 +917,19 @@ config NETFILTER_XT_MATCH_U32 Details and examples are in the kernel module source. +config NETFILTER_XT_MATCH_OSF + tristate '"osf" Passive OS fingerprint match' + depends on NETFILTER_ADVANCED && NETFILTER_NETLINK + help + This option selects the Passive OS Fingerprinting match module + that allows to passively match the remote operating system by + analyzing incoming TCP SYN packets. + + Rules and loading software can be downloaded from + http://www.ioremap.net/projects/osf + + To compile it as a module, choose M here. If unsure, say N. + endif # NETFILTER_XTABLES endmenu diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 6282060..49f62ee 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o +obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c new file mode 100644 index 0000000..863e409 --- /dev/null +++ b/net/netfilter/xt_osf.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2003+ Evgeniy Polyakov + * + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +struct xt_osf_finger { + struct rcu_head rcu_head; + struct list_head finger_entry; + struct xt_osf_user_finger finger; +}; + +enum osf_fmatch_states { + /* Packet does not match the fingerprint */ + FMATCH_WRONG = 0, + /* Packet matches the fingerprint */ + FMATCH_OK, + /* Options do not match the fingerprint, but header does */ + FMATCH_OPT_WRONG, +}; + +/* + * Indexed by dont-fragment bit. + * It is the only constant value in the fingerprint. + */ +static struct list_head xt_osf_fingers[2]; + +static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = { + [OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) }, +}; + +static void xt_osf_finger_free_rcu(struct rcu_head *rcu_head) +{ + struct xt_osf_finger *f = container_of(rcu_head, struct xt_osf_finger, rcu_head); + + kfree(f); +} + +static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb, + struct nlmsghdr *nlh, struct nlattr *osf_attrs[]) +{ + struct xt_osf_user_finger *f; + struct xt_osf_finger *kf = NULL, *sf; + int err = 0; + + if (!osf_attrs[OSF_ATTR_FINGER]) + return -EINVAL; + + if (!(nlh->nlmsg_flags & NLM_F_CREATE)) + return -EINVAL; + + f = nla_data(osf_attrs[OSF_ATTR_FINGER]); + + kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL); + if (!kf) + return -ENOMEM; + + memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger)); + + list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) { + if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger))) + continue; + + kfree(kf); + kf = NULL; + + if (nlh->nlmsg_flags & NLM_F_EXCL) + err = -EEXIST; + break; + } + + /* + * We are protected by nfnl mutex. + */ + if (kf) + list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]); + + return err; +} + +static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb, + struct nlmsghdr *nlh, struct nlattr *osf_attrs[]) +{ + struct xt_osf_user_finger *f; + struct xt_osf_finger *sf; + int err = ENOENT; + + if (!osf_attrs[OSF_ATTR_FINGER]) + return -EINVAL; + + f = nla_data(osf_attrs[OSF_ATTR_FINGER]); + + list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) { + if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger))) + continue; + + /* + * We are protected by nfnl mutex. + */ + list_del_rcu(&sf->finger_entry); + call_rcu(&sf->rcu_head, xt_osf_finger_free_rcu); + + err = 0; + break; + } + + return err; +} + +static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = { + [OSF_MSG_ADD] = { + .call = xt_osf_add_callback, + .attr_count = OSF_ATTR_MAX, + .policy = xt_osf_policy, + }, + [OSF_MSG_REMOVE] = { + .call = xt_osf_remove_callback, + .attr_count = OSF_ATTR_MAX, + .policy = xt_osf_policy, + }, +}; + +static const struct nfnetlink_subsystem xt_osf_nfnetlink = { + .name = "osf", + .subsys_id = NFNL_SUBSYS_OSF, + .cb_count = OSF_MSG_MAX, + .cb = xt_osf_nfnetlink_callbacks, +}; + +static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info, + unsigned char f_ttl) +{ + const struct iphdr *ip = ip_hdr(skb); + + if (info->flags & XT_OSF_TTL) { + if (info->ttl == XT_OSF_TTL_TRUE) + return ip->ttl == f_ttl; + if (info->ttl == XT_OSF_TTL_NOCHECK) + return 1; + else if (ip->ttl <= f_ttl) + return 1; + else { + struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + int ret = 0; + + for_ifa(in_dev) { + if (inet_ifa_match(ip->saddr, ifa)) { + ret = (ip->ttl == f_ttl); + break; + } + } + endfor_ifa(in_dev); + + return ret; + } + } + + return ip->ttl == f_ttl; +} + +static bool xt_osf_match_packet(const struct sk_buff *skb, + const struct xt_match_param *p) +{ + const struct xt_osf_info *info = p->matchinfo; + const struct iphdr *ip = ip_hdr(skb); + const struct tcphdr *tcp; + struct tcphdr _tcph; + int fmatch = FMATCH_WRONG, fcount = 0; + unsigned int optsize = 0, check_WSS = 0; + u16 window, totlen, mss = 0; + bool df; + const unsigned char *optp = NULL, *_optp = NULL; + unsigned char opts[MAX_IPOPTLEN]; + const struct xt_osf_finger *kf; + const struct xt_osf_user_finger *f; + + if (!info) + return false; + + tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph); + if (!tcp) + return false; + + if (!tcp->syn) + return false; + + totlen = ntohs(ip->tot_len); + df = ntohs(ip->frag_off) & IP_DF; + window = ntohs(tcp->window); + + if (tcp->doff * 4 > sizeof(struct tcphdr)) { + optsize = tcp->doff * 4 - sizeof(struct tcphdr); + + _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) + + sizeof(struct tcphdr), optsize, opts); + } + + rcu_read_lock(); + list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) { + f = &kf->finger; + + if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre)) + continue; + + optp = _optp; + fmatch = FMATCH_WRONG; + + if (totlen == f->ss && xt_osf_ttl(skb, info, f->ttl)) { + int foptsize, optnum; + + /* + * Should not happen if userspace parser was written correctly. + */ + if (f->wss.wc >= OSF_WSS_MAX) + continue; + + /* Check options */ + + foptsize = 0; + for (optnum = 0; optnum < f->opt_num; ++optnum) + foptsize += f->opt[optnum].length; + + if (foptsize > MAX_IPOPTLEN || + optsize > MAX_IPOPTLEN || + optsize != foptsize) + continue; + + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { + if (f->opt[optnum].kind == (*optp)) { + __u32 len = f->opt[optnum].length; + const __u8 *optend = optp + len; + int loop_cont = 0; + + fmatch = FMATCH_OK; + + switch (*optp) { + case OSFOPT_MSS: + mss = optp[3]; + mss <<= 8; + mss |= optp[2]; + + mss = ntohs(mss); + break; + case OSFOPT_TS: + loop_cont = 1; + break; + } + + optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + + if (fmatch != FMATCH_OK) + break; + } + + if (fmatch != FMATCH_OPT_WRONG) { + fmatch = FMATCH_WRONG; + + switch (check_WSS) { + case OSF_WSS_PLAIN: + if (f->wss.val == 0 || window == f->wss.val) + fmatch = FMATCH_OK; + break; + case OSF_WSS_MSS: + /* + * Some smart modems decrease mangle MSS to + * SMART_MSS_2, so we check standard, decreased + * and the one provided in the fingerprint MSS + * values. + */ +#define SMART_MSS_1 1460 +#define SMART_MSS_2 1448 + if (window == f->wss.val * mss || + window == f->wss.val * SMART_MSS_1 || + window == f->wss.val * SMART_MSS_2) + fmatch = FMATCH_OK; + break; + case OSF_WSS_MTU: + if (window == f->wss.val * (mss + 40) || + window == f->wss.val * (SMART_MSS_1 + 40) || + window == f->wss.val * (SMART_MSS_2 + 40)) + fmatch = FMATCH_OK; + break; + case OSF_WSS_MODULO: + if ((window % f->wss.val) == 0) + fmatch = FMATCH_OK; + break; + } + } + + if (fmatch != FMATCH_OK) + continue; + + fcount++; + + if (info->flags & XT_OSF_LOG) + nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL, + "%s [%s:%s] : %pi4:%d -> %pi4:%d hops=%d\n", + f->genre, f->version, f->subtype, + &ip->saddr, ntohs(tcp->source), + &ip->daddr, ntohs(tcp->dest), + f->ttl - ip->ttl); + + if ((info->flags & XT_OSF_LOG) && + info->loglevel == XT_OSF_LOGLEVEL_FIRST) + break; + } + } + rcu_read_unlock(); + + if (!fcount && (info->flags & XT_OSF_LOG)) + nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL, + "Remote OS is not known: %pi4:%u -> %pi4:%u\n", + &ip->saddr, ntohs(tcp->source), + &ip->daddr, ntohs(tcp->dest)); + + if (fcount) + fmatch = FMATCH_OK; + + return fmatch == FMATCH_OK; +} + +static struct xt_match xt_osf_match = { + .name = "osf", + .revision = 0, + .family = NFPROTO_IPV4, + .proto = IPPROTO_TCP, + .hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_FORWARD), + .match = xt_osf_match_packet, + .matchsize = sizeof(struct xt_osf_info), + .me = THIS_MODULE, +}; + +static int __init xt_osf_init(void) +{ + int err = -EINVAL; + int i; + + for (i=0; ifinger_entry); + call_rcu(&f->rcu_head, xt_osf_finger_free_rcu); + } + } + rcu_read_unlock(); + + rcu_barrier(); +} + +module_init(xt_osf_init); +module_exit(xt_osf_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +MODULE_DESCRIPTION("Passive OS fingerprint matching."); +MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF); -- cgit v0.10.2 From 05f77f85f47e30a53f7971b687f3b0250e42f665 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 8 Jun 2009 16:16:56 -0700 Subject: bluetooth: Kill skb_frags_no(), unused. Furthermore, it twiddles with the details of SKB list handling directly, which we're trying to eliminate. Signed-off-by: David S. Miller diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 3ad5390..144d1d5 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -171,15 +171,6 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, unsigned long l return skb; } -static inline int skb_frags_no(struct sk_buff *skb) -{ - register struct sk_buff *frag = skb_shinfo(skb)->frag_list; - register int n = 1; - - for (; frag; frag=frag->next, n++); - return n; -} - int bt_err(__u16 code); extern int hci_sock_init(void); -- cgit v0.10.2 From ee0398717078260ee4ffa97d407071bc774e2dac Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:17:13 -0700 Subject: skbuff: Add frag list abstraction interfaces. With the hope that these can be used to eliminate direct references to the frag list implementation. Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index aad484c..f1c93b8 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1077,7 +1077,7 @@ extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, int size); #define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) -#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_shinfo(skb)->frag_list) +#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frags(skb)) #define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb)) #ifdef NET_SKBUFF_DATA_USES_OFFSET @@ -1716,6 +1716,25 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) skb = skb->prev) +static inline bool skb_has_frags(const struct sk_buff *skb) +{ + return skb_shinfo(skb)->frag_list != NULL; +} + +static inline void skb_frag_list_init(struct sk_buff *skb) +{ + skb_shinfo(skb)->frag_list = NULL; +} + +static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag) +{ + frag->next = skb_shinfo(skb)->frag_list; + skb_shinfo(skb)->frag_list = frag; +} + +#define skb_walk_frags(skb, iter) \ + for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) + extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, int *peeked, int *err); extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, -- cgit v0.10.2 From a5bd8a13e9e0322c7f76b34790ba34e2e0ce2ac5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:17:27 -0700 Subject: netdevice.h: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2a80138..9ea8d6d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1904,7 +1904,7 @@ static inline int net_gso_ok(int features, int gso_type) static inline int skb_gso_ok(struct sk_buff *skb, int features) { return net_gso_ok(features, skb_shinfo(skb)->gso_type) && - (!skb_shinfo(skb)->frag_list || (features & NETIF_F_FRAGLIST)); + (!skb_has_frags(skb) || (features & NETIF_F_FRAGLIST)); } static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) -- cgit v0.10.2 From c32ba3f9b8aa2441c7cfcd065f79981cf8cfe9f4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:17:44 -0700 Subject: appletalk: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index d6a9243..b603cba 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -939,6 +939,7 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, int len, unsigned long sum) { int start = skb_headlen(skb); + struct sk_buff *frag_iter; int i, copy; /* checksum stuff in header space */ @@ -977,26 +978,22 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list = list->next) { - int end; + skb_walk_frags(skb, frag_iter) { + int end; - WARN_ON(start > offset + len); + WARN_ON(start > offset + len); - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - sum = atalk_sum_skb(list, offset - start, - copy, sum); - if ((len -= copy) == 0) - return sum; - offset += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + sum = atalk_sum_skb(frag_iter, offset - start, + copy, sum); + if ((len -= copy) == 0) + return sum; + offset += copy; } + start = end; } BUG_ON(len > 0); -- cgit v0.10.2 From 5b1a002ade68173f21b2126a778278df72202ba6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:18:15 -0700 Subject: datagram: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/core/datagram.c b/net/core/datagram.c index 774bcd9..58abee1 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -282,6 +282,7 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; /* Copy header. */ if (copy > 0) { @@ -322,28 +323,24 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_datagram_iovec(list, - offset - start, - to, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; + skb_walk_frags(skb, frag_iter) { + int end; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_iovec(frag_iter, + offset - start, + to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; } + start = end; } if (!len) return 0; @@ -369,6 +366,7 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; /* Copy header. */ if (copy > 0) { @@ -411,30 +409,26 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_datagram_const_iovec(list, - offset - start, - to, to_offset, - copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - to_offset += copy; - } - start = end; + skb_walk_frags(skb, frag_iter) { + int end; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_const_iovec(frag_iter, + offset - start, + to, to_offset, + copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to_offset += copy; } + start = end; } if (!len) return 0; @@ -461,6 +455,7 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; /* Copy header. */ if (copy > 0) { @@ -506,31 +501,27 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_datagram_from_iovec(list, - offset - start, - from, - from_offset, - copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - from_offset += copy; - } - start = end; + skb_walk_frags(skb, frag_iter) { + int end; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_from_iovec(frag_iter, + offset - start, + from, + from_offset, + copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + from_offset += copy; } + start = end; } if (!len) return 0; @@ -545,8 +536,9 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, __wsum *csump) { int start = skb_headlen(skb); - int pos = 0; int i, copy = start - offset; + struct sk_buff *frag_iter; + int pos = 0; /* Copy header. */ if (copy > 0) { @@ -597,33 +589,29 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list=list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - __wsum csum2 = 0; - if (copy > len) - copy = len; - if (skb_copy_and_csum_datagram(list, - offset - start, - to, copy, - &csum2)) - goto fault; - *csump = csum_block_add(*csump, csum2, pos); - if ((len -= copy) == 0) - return 0; - offset += copy; - to += copy; - pos += copy; - } - start = end; + skb_walk_frags(skb, frag_iter) { + int end; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + __wsum csum2 = 0; + if (copy > len) + copy = len; + if (skb_copy_and_csum_datagram(frag_iter, + offset - start, + to, copy, + &csum2)) + goto fault; + *csump = csum_block_add(*csump, csum2, pos); + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + pos += copy; } + start = end; } if (!len) return 0; -- cgit v0.10.2 From 4cf704fbea96075942bd033fd75aa4e76ae1c8a1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:18:51 -0700 Subject: net/core/dev.c: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 1f38401..4913089 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1820,7 +1820,7 @@ int dev_queue_xmit(struct sk_buff *skb) if (netif_needs_gso(dev, skb)) goto gso; - if (skb_shinfo(skb)->frag_list && + if (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST) && __skb_linearize(skb)) goto out_kfree_skb; @@ -2407,7 +2407,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) if (!(skb->dev->features & NETIF_F_GRO)) goto normal; - if (skb_is_gso(skb) || skb_shinfo(skb)->frag_list) + if (skb_is_gso(skb) || skb_has_frags(skb)) goto normal; rcu_read_lock(); -- cgit v0.10.2 From fbb398a832086c370bce47789e155bf5a08774e9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:18:59 -0700 Subject: net/core/skbuff.c: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a2473b1..49961ba 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -210,7 +210,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, shinfo->gso_type = 0; shinfo->ip6_frag_id = 0; shinfo->tx_flags.flags = 0; - shinfo->frag_list = NULL; + skb_frag_list_init(skb); memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps)); if (fclone) { @@ -323,7 +323,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) { struct sk_buff *list; - for (list = skb_shinfo(skb)->frag_list; list; list = list->next) + skb_walk_frags(skb, list) skb_get(list); } @@ -338,7 +338,7 @@ static void skb_release_data(struct sk_buff *skb) put_page(skb_shinfo(skb)->frags[i].page); } - if (skb_shinfo(skb)->frag_list) + if (skb_has_frags(skb)) skb_drop_fraglist(skb); kfree(skb->head); @@ -503,7 +503,7 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size) shinfo->gso_type = 0; shinfo->ip6_frag_id = 0; shinfo->tx_flags.flags = 0; - shinfo->frag_list = NULL; + skb_frag_list_init(skb); memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps)); memset(skb, 0, offsetof(struct sk_buff, tail)); @@ -758,7 +758,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) skb_shinfo(n)->nr_frags = i; } - if (skb_shinfo(skb)->frag_list) { + if (skb_has_frags(skb)) { skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; skb_clone_fraglist(n); } @@ -821,7 +821,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) get_page(skb_shinfo(skb)->frags[i].page); - if (skb_shinfo(skb)->frag_list) + if (skb_has_frags(skb)) skb_clone_fraglist(skb); skb_release_data(skb); @@ -1093,7 +1093,7 @@ drop_pages: for (; i < nfrags; i++) put_page(skb_shinfo(skb)->frags[i].page); - if (skb_shinfo(skb)->frag_list) + if (skb_has_frags(skb)) skb_drop_fraglist(skb); goto done; } @@ -1188,7 +1188,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta) /* Optimization: no fragments, no reasons to preestimate * size of pulled pages. Superb. */ - if (!skb_shinfo(skb)->frag_list) + if (!skb_has_frags(skb)) goto pull_pages; /* Estimate size of pulled pages. */ @@ -1285,8 +1285,9 @@ EXPORT_SYMBOL(__pskb_pull_tail); int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) { - int i, copy; int start = skb_headlen(skb); + struct sk_buff *frag_iter; + int i, copy; if (offset > (int)skb->len - len) goto fault; @@ -1328,28 +1329,23 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_bits(list, offset - start, - to, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - to += copy; - } - start = end; + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_bits(frag_iter, offset - start, to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; } + start = end; } if (!len) return 0; @@ -1534,6 +1530,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, .ops = &sock_pipe_buf_ops, .spd_release = sock_spd_release, }; + struct sk_buff *frag_iter; struct sock *sk = skb->sk; /* @@ -1548,13 +1545,11 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, /* * now see if we have a frag_list to map */ - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list && tlen; list = list->next) { - if (__skb_splice_bits(list, &offset, &tlen, &spd, sk)) - break; - } + skb_walk_frags(skb, frag_iter) { + if (!tlen) + break; + if (__skb_splice_bits(frag_iter, &offset, &tlen, &spd, sk)) + break; } done: @@ -1593,8 +1588,9 @@ done: int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len) { - int i, copy; int start = skb_headlen(skb); + struct sk_buff *frag_iter; + int i, copy; if (offset > (int)skb->len - len) goto fault; @@ -1635,28 +1631,24 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len) start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_store_bits(list, offset - start, - from, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - from += copy; - } - start = end; + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_store_bits(frag_iter, offset - start, + from, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + from += copy; } + start = end; } if (!len) return 0; @@ -1673,6 +1665,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; int pos = 0; /* Checksum header. */ @@ -1712,29 +1705,25 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - __wsum csum2; - if (copy > len) - copy = len; - csum2 = skb_checksum(list, offset - start, - copy, 0); - csum = csum_block_add(csum, csum2, pos); - if ((len -= copy) == 0) - return csum; - offset += copy; - pos += copy; - } - start = end; + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + __wsum csum2; + if (copy > len) + copy = len; + csum2 = skb_checksum(frag_iter, offset - start, + copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + pos += copy; } + start = end; } BUG_ON(len); @@ -1749,6 +1738,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; int pos = 0; /* Copy header. */ @@ -1793,31 +1783,27 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + __wsum csum2; + int end; - for (; list; list = list->next) { - __wsum csum2; - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - csum2 = skb_copy_and_csum_bits(list, - offset - start, - to, copy, 0); - csum = csum_block_add(csum, csum2, pos); - if ((len -= copy) == 0) - return csum; - offset += copy; - to += copy; - pos += copy; - } - start = end; + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + csum2 = skb_copy_and_csum_bits(frag_iter, + offset - start, + to, copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + to += copy; + pos += copy; } + start = end; } BUG_ON(len); return csum; @@ -2327,8 +2313,7 @@ next_skb: st->frag_data = NULL; } - if (st->root_skb == st->cur_skb && - skb_shinfo(st->root_skb)->frag_list) { + if (st->root_skb == st->cur_skb && skb_has_frags(st->root_skb)) { st->cur_skb = skb_shinfo(st->root_skb)->frag_list; st->frag_idx = 0; goto next_skb; @@ -2639,7 +2624,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) } else skb_get(fskb2); - BUG_ON(skb_shinfo(nskb)->frag_list); + SKB_FRAG_ASSERT(nskb); skb_shinfo(nskb)->frag_list = fskb2; } @@ -2796,6 +2781,7 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; int elt = 0; if (copy > 0) { @@ -2829,26 +2815,22 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list = list->next) { - int end; + skb_walk_frags(skb, frag_iter) { + int end; - WARN_ON(start > offset + len); + WARN_ON(start > offset + len); - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - elt += __skb_to_sgvec(list, sg+elt, offset - start, - copy); - if ((len -= copy) == 0) - return elt; - offset += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start, + copy); + if ((len -= copy) == 0) + return elt; + offset += copy; } + start = end; } BUG_ON(len); return elt; @@ -2896,7 +2878,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) return -ENOMEM; /* Easy case. Most of packets will go this way. */ - if (!skb_shinfo(skb)->frag_list) { + if (!skb_has_frags(skb)) { /* A little of trouble, not enough of space for trailer. * This should not happen, when stack is tuned to generate * good frames. OK, on miss we reallocate and reserve even more @@ -2931,7 +2913,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) if (skb1->next == NULL && tailbits) { if (skb_shinfo(skb1)->nr_frags || - skb_shinfo(skb1)->frag_list || + skb_has_frags(skb1) || skb_tailroom(skb1) < tailbits) ntail = tailbits + 128; } @@ -2940,7 +2922,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) skb_cloned(skb1) || ntail || skb_shinfo(skb1)->nr_frags || - skb_shinfo(skb1)->frag_list) { + skb_has_frags(skb1)) { struct sk_buff *skb2; /* Fuck, we are miserable poor guys... */ -- cgit v0.10.2 From 285e42802bb3da91102967f63fb9e28e61f7831e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:19:10 -0700 Subject: net/core/user_dma.c: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/core/user_dma.c b/net/core/user_dma.c index 164b090..25d717e 100644 --- a/net/core/user_dma.c +++ b/net/core/user_dma.c @@ -51,6 +51,7 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; dma_cookie_t cookie = 0; /* Copy header. */ @@ -94,31 +95,28 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - copy = end - offset; - if (copy > 0) { - if (copy > len) - copy = len; - cookie = dma_skb_copy_datagram_iovec(chan, list, - offset - start, to, copy, - pinned_list); - if (cookie < 0) - goto fault; - len -= copy; - if (len == 0) - goto end; - offset += copy; - } - start = end; + skb_walk_frags(skb, frag_iter) { + int end; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + copy = end - offset; + if (copy > 0) { + if (copy > len) + copy = len; + cookie = dma_skb_copy_datagram_iovec(chan, frag_iter, + offset - start, + to, copy, + pinned_list); + if (cookie < 0) + goto fault; + len -= copy; + if (len == 0) + goto end; + offset += copy; } + start = end; } end: -- cgit v0.10.2 From d7fcf1a5cae2c970e9afe7192fe0c13d931247e0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:19:37 -0700 Subject: ipv4: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 1f1b824..575f9bd 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -507,7 +507,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, /* If the first fragment is fragmented itself, we split * it to two chunks: the first with data and paged part * and the second, holding only fragments. */ - if (skb_shinfo(head)->frag_list) { + if (skb_has_frags(head)) { struct sk_buff *clone; int i, plen = 0; @@ -516,7 +516,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, clone->next = head->next; head->next = clone; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_shinfo(head)->frag_list = NULL; + skb_frag_list_init(head); for (i=0; inr_frags; i++) plen += skb_shinfo(head)->frags[i].size; clone->len = clone->data_len = head->data_len - plen; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 3d6167f..9248d28 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -474,7 +474,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) * LATER: this step can be merged to real generation of fragments, * we can switch to copy when see the first bad fragment. */ - if (skb_shinfo(skb)->frag_list) { + if (skb_has_frags(skb)) { struct sk_buff *frag; int first_len = skb_pagelen(skb); int truesizes = 0; @@ -485,7 +485,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) skb_cloned(skb)) goto slow_path; - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* Correct geometry. */ if (frag->len > mtu || ((frag->len & 7) && frag->next) || @@ -510,7 +510,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) err = 0; offset = 0; frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); skb->data_len = first_len - skb_headlen(skb); skb->truesize -= truesizes; skb->len = first_len; -- cgit v0.10.2 From 4d9092bb41c8fdca45513461587d8b4ad3918f74 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:20:05 -0700 Subject: ipv6: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c8dc8e5..db6c722 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -658,7 +658,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) } mtu -= hlen + sizeof(struct frag_hdr); - if (skb_shinfo(skb)->frag_list) { + if (skb_has_frags(skb)) { int first_len = skb_pagelen(skb); int truesizes = 0; @@ -667,7 +667,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) skb_cloned(skb)) goto slow_path; - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* Correct geometry. */ if (frag->len > mtu || ((frag->len & 7) && frag->next) || @@ -690,7 +690,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) err = 0; offset = 0; frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); /* BUILD HEADER */ *prevhdr = NEXTHDR_FRAGMENT; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 54a387d..2642a41 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -494,7 +494,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, /* If the first fragment is fragmented itself, we split * it to two chunks: the first with data and paged part * and the second, holding only fragments. */ - if (skb_shinfo(head)->frag_list) { + if (skb_has_frags(head)) { struct sk_buff *clone; int i, plen = 0; @@ -503,7 +503,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, clone->next = head->next; head->next = clone; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_shinfo(head)->frag_list = NULL; + skb_frag_list_init(head); for (i=0; inr_frags; i++) plen += skb_shinfo(head)->frags[i].size; clone->len = clone->data_len = head->data_len - plen; -- cgit v0.10.2 From 343a99724e4431d8618bea2eb7552e12c965425a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:23:58 -0700 Subject: netfilter: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c index 65e470b..6983e41 100644 --- a/net/ipv4/netfilter/nf_nat_proto_sctp.c +++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c @@ -33,6 +33,7 @@ sctp_manip_pkt(struct sk_buff *skb, enum nf_nat_manip_type maniptype) { const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); + struct sk_buff *frag; sctp_sctphdr_t *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; __be32 oldip, newip; @@ -57,8 +58,8 @@ sctp_manip_pkt(struct sk_buff *skb, } crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff); - for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) - crc32 = sctp_update_cksum((u8 *)skb->data, skb_headlen(skb), + skb_walk_frags(skb, frag); + crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag), crc32); crc32 = sctp_end_cksum(crc32); hdr->checksum = crc32; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 058a5e4..f3aba25 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -409,7 +409,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) /* If the first fragment is fragmented itself, we split * it to two chunks: the first with data and paged part * and the second, holding only fragments. */ - if (skb_shinfo(head)->frag_list) { + if (skb_has_frags(head)) { struct sk_buff *clone; int i, plen = 0; @@ -420,7 +420,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) clone->next = head->next; head->next = clone; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_shinfo(head)->frag_list = NULL; + skb_frag_list_init(head); for (i=0; inr_frags; i++) plen += skb_shinfo(head)->frags[i].size; clone->len = clone->data_len = head->data_len - plen; -- cgit v0.10.2 From 5c313e9a7773ec4d7ac554e841fba583f7c63aba Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:21:58 -0700 Subject: phonet: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 851f6a3..480839d 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -115,10 +115,10 @@ static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb) rskb->truesize += rskb->len; /* Avoid nested fragments */ - for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next) + skb_walk_frags(skb, fs) flen += fs->len; skb->next = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); skb->len -= flen; skb->data_len -= flen; skb->truesize -= flen; diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 8ad2b53..eef833e 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -940,10 +940,10 @@ int pep_write(struct sock *sk, struct sk_buff *skb) rskb->truesize += rskb->len; /* Avoid nested fragments */ - for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next) + skb_walk_frags(skb, fs) flen += fs->len; skb->next = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); skb->len -= flen; skb->data_len -= flen; skb->truesize -= flen; -- cgit v0.10.2 From 1b003be39e91a6cd013c9ea580ccc24d1fac9959 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:22:35 -0700 Subject: sctp: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/sctp/input.c b/net/sctp/input.c index d2e9880..c0c973e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -81,13 +81,13 @@ static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb); /* Calculate the SCTP checksum of an SCTP packet. */ static inline int sctp_rcv_checksum(struct sk_buff *skb) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; struct sctphdr *sh = sctp_hdr(skb); __le32 cmp = sh->checksum; + struct sk_buff *list; __le32 val; __u32 tmp = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); - for (; list; list = list->next) + skb_walk_frags(skb, list) tmp = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), tmp); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 7c3dfd2..0f01e5d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1881,7 +1881,7 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) len -= skb_len; __skb_pull(skb, skb_len); - for (list = skb_shinfo(skb)->frag_list; list; list = list->next) { + skb_walk_frags(skb, list) { rlen = sctp_skb_pull(list, len); skb->len -= (len-rlen); skb->data_len -= (len-rlen); @@ -6660,7 +6660,7 @@ static void sctp_sock_rfree_frag(struct sk_buff *skb) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) + skb_walk_frags(skb, frag) sctp_sock_rfree_frag(frag); done: @@ -6675,7 +6675,7 @@ static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) + skb_walk_frags(skb, frag) sctp_skb_set_owner_r_frag(frag, sk); done: diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 5f186ca..8b3560f 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -976,9 +976,8 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, * In general, the skb passed from IP can have only 1 level of * fragments. But we allow multiple levels of fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc); - } } /* Do accounting for bytes just read by user and release the references to @@ -1003,7 +1002,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* NOTE: skb_shinfos are recursive. Although IP returns * skb's with only 1 level of fragments, SCTP reassembly can * increase the levels. @@ -1026,7 +1025,7 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* NOTE: skb_shinfos are recursive. Although IP returns * skb's with only 1 level of fragments, SCTP reassembly can * increase the levels. -- cgit v0.10.2 From d4fd3bc101909802f9ed083093cce688cc3416aa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 00:22:47 -0700 Subject: xfrm: Use frag list abstraction interfaces. Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 96036cf..d31ccb4 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -696,8 +696,9 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, { int start = skb_headlen(skb); int i, copy = start - offset; - int err; + struct sk_buff *frag_iter; struct scatterlist sg; + int err; /* Checksum header. */ if (copy > 0) { @@ -742,28 +743,24 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list; list = list->next) { - int end; - - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - err = skb_icv_walk(list, desc, offset-start, - copy, icv_update); - if (unlikely(err)) - return err; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; + skb_walk_frags(skb, frag_iter) { + int end; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + err = skb_icv_walk(frag_iter, desc, offset-start, + copy, icv_update); + if (unlikely(err)) + return err; + if ((len -= copy) == 0) + return 0; + offset += copy; } + start = end; } BUG_ON(len); return 0; -- cgit v0.10.2 From ebc8d2ab61dde6cf775ae7bb1ed9e38dfe12ca65 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 01:01:31 -0700 Subject: be2net: Remove unnecessary frag list traversing. This driver does not indicate support for frag lists. Furthermore, even if it did, the code is walking the frag lists incorrectly. The idiom is: for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) but it's doing: for (iter = skb_shinfo(skb)->frag_list; iter; iter = skb_shinfo(iter)->frag_list) which would never work. And this proves that this driver never saw an SKB with active frag lists. So just remove the code altogether and the driver TX path becomes much simpler. Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 5f17d80..347d002 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -337,13 +337,10 @@ static void be_tx_stats_update(struct be_adapter *adapter, /* Determine number of WRB entries needed to xmit data in an skb */ static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy) { - int cnt = 0; - while (skb) { - if (skb->len > skb->data_len) - cnt++; - cnt += skb_shinfo(skb)->nr_frags; - skb = skb_shinfo(skb)->frag_list; - } + int cnt = (skb->len > skb->data_len); + + cnt += skb_shinfo(skb)->nr_frags; + /* to account for hdr wrb */ cnt++; if (cnt & 1) { @@ -409,31 +406,28 @@ static int make_tx_wrbs(struct be_adapter *adapter, hdr = queue_head_node(txq); queue_head_inc(txq); - while (skb) { - if (skb->len > skb->data_len) { - int len = skb->len - skb->data_len; - busaddr = pci_map_single(pdev, skb->data, len, - PCI_DMA_TODEVICE); - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, len); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += len; - } + if (skb->len > skb->data_len) { + int len = skb->len - skb->data_len; + busaddr = pci_map_single(pdev, skb->data, len, + PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); + wrb_fill(wrb, busaddr, len); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + queue_head_inc(txq); + copied += len; + } - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - struct skb_frag_struct *frag = - &skb_shinfo(skb)->frags[i]; - busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, frag->size); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += frag->size; - } - skb = skb_shinfo(skb)->frag_list; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *frag = + &skb_shinfo(skb)->frags[i]; + busaddr = pci_map_page(pdev, frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); + wrb_fill(wrb, busaddr, frag->size); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + queue_head_inc(txq); + copied += frag->size; } if (dummy_wrb) { -- cgit v0.10.2 From 0c27922e4933ceb86644f4a9b1af212ffe5aad75 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 8 Jun 2009 03:49:24 +0000 Subject: net: dev_addr_init() fix commit f001fde5eadd915f4858d22ed70d7040f48767cf (net: introduce a list of device addresses dev_addr_list (v6)) added one regression Vegard Nossum found in its testings. With kmemcheck help, Vegard found some uninitialized memory was read and reported to user, potentialy leaking kernel data. ( thread can be found on http://lkml.org/lkml/2009/5/30/177 ) dev_addr_init() incorrectly uses sizeof() operator. We were initializing one byte instead of MAX_ADDR_LEN bytes. Reported-by: Vegard Nossum Signed-off-by: Eric Dumazet Acked-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 4913089..81b392e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3655,8 +3655,8 @@ static int dev_addr_init(struct net_device *dev) /* rtnl_mutex must be held here */ INIT_LIST_HEAD(&dev->dev_addr_list); - memset(addr, 0, sizeof(*addr)); - err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(*addr), + memset(addr, 0, sizeof(addr)); + err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(addr), NETDEV_HW_ADDR_T_LAN); if (!err) { /* -- cgit v0.10.2 From 728bf09827d350cdaa1f093170e745e8dac49b7a Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Mon, 8 Jun 2009 22:05:00 +0000 Subject: pkt_sched: Use PSCHED_SHIFT in PSCHED time conversion Use PSCHED_SHIFT constant instead of '10' in PSCHED_US2NS() and PSCHED_NS2US() macros to enable changing this value later. Additionally use PSCHED_SHIFT in sch_hfsc SM_SHIFT and ISM_SHIFT definitions. This part of the patch is based on feedback from Patrick McHardy . Reported-by: Antonio Almeida Tested-by: Antonio Almeida Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index e37fe31..cd0e026 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -42,8 +42,9 @@ typedef u64 psched_time_t; typedef long psched_tdiff_t; /* Avoid doing 64 bit divide by 1000 */ -#define PSCHED_US2NS(x) ((s64)(x) << 10) -#define PSCHED_NS2US(x) ((x) >> 10) +#define PSCHED_SHIFT 10 +#define PSCHED_US2NS(x) ((s64)(x) << PSCHED_SHIFT) +#define PSCHED_NS2US(x) ((x) >> PSCHED_SHIFT) #define PSCHED_TICKS_PER_SEC PSCHED_NS2US(NSEC_PER_SEC) #define PSCHED_PASTPERFECT 0 diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 5022f9c..362c281 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -372,7 +372,7 @@ cftree_update(struct hfsc_class *cl) * ism: (psched_us/byte) << ISM_SHIFT * dx: psched_us * - * The clock source resolution with ktime is 1.024us. + * The clock source resolution with ktime and PSCHED_SHIFT 10 is 1.024us. * * sm and ism are scaled in order to keep effective digits. * SM_SHIFT and ISM_SHIFT are selected to keep at least 4 effective @@ -383,9 +383,11 @@ cftree_update(struct hfsc_class *cl) * bytes/1.024us 12.8e-3 128e-3 1280e-3 12800e-3 128000e-3 * * 1.024us/byte 78.125 7.8125 0.78125 0.078125 0.0078125 + * + * So, for PSCHED_SHIFT 10 we need: SM_SHIFT 20, ISM_SHIFT 18. */ -#define SM_SHIFT 20 -#define ISM_SHIFT 18 +#define SM_SHIFT (30 - PSCHED_SHIFT) +#define ISM_SHIFT (8 + PSCHED_SHIFT) #define SM_MASK ((1ULL << SM_SHIFT) - 1) #define ISM_MASK ((1ULL << ISM_SHIFT) - 1) -- cgit v0.10.2 From a4a710c4a7490587406462bf1d54504b7783d7d7 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Mon, 8 Jun 2009 22:05:13 +0000 Subject: pkt_sched: Change PSCHED_SHIFT from 10 to 6 Change PSCHED_SHIFT from 10 to 6 to increase schedulers time resolution. This will increase 16x a number of (internal) ticks per nanosecond, and is needed to improve accuracy of schedulers based on rate tables, like HTB, TBF or CBQ, with rates above 100Mbit. It is assumed this change is safe for 32bit accounting of time diffs up to 2 minutes, which should be enough for common use (extremely low rate values may overflow, so get inaccurate instead). To make full use of this change an updated iproute2 will be needed. (But using older iproute2 should be safe too.) This change breaks ticks - microseconds similarity, so some minor code fixes might be needed. It is also planned to change naming adequately eg. to PSCHED_TICKS2NS() etc. in the near future. Reported-by: Antonio Almeida Tested-by: Antonio Almeida Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index cd0e026..120935b 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -41,8 +41,8 @@ static inline void *qdisc_priv(struct Qdisc *q) typedef u64 psched_time_t; typedef long psched_tdiff_t; -/* Avoid doing 64 bit divide by 1000 */ -#define PSCHED_SHIFT 10 +/* Avoid doing 64 bit divide */ +#define PSCHED_SHIFT 6 #define PSCHED_US2NS(x) ((s64)(x) << PSCHED_SHIFT) #define PSCHED_NS2US(x) ((x) >> PSCHED_SHIFT) -- cgit v0.10.2 From fcb94e422479da52ed90bab230c59617a0462416 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 8 Jun 2009 12:18:47 +0000 Subject: Add constants for the ieee 802.15.4 stack IEEE 802.15.4 stack requires several constants to be defined/adjusted. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Sergey Lapin Signed-off-by: David S. Miller diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 5ff8980..b554300 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -86,6 +86,8 @@ #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ +#define ARPHRD_IEEE802154 804 +#define ARPHRD_IEEE802154_PHY 805 #define ARPHRD_PHONET 820 /* PhoNet media type */ #define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index cfe4fe1..11a60e4 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -106,6 +106,7 @@ #define ETH_P_DSA 0x001B /* Distributed Switch Arch. */ #define ETH_P_TRAILER 0x001C /* Trailer switch tagging */ #define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ +#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */ /* * This is an Ethernet frame header. diff --git a/include/linux/socket.h b/include/linux/socket.h index d2310cb..3b461df 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -194,7 +194,8 @@ struct ucred { #define AF_RXRPC 33 /* RxRPC sockets */ #define AF_ISDN 34 /* mISDN sockets */ #define AF_PHONET 35 /* Phonet sockets */ -#define AF_MAX 36 /* For now.. */ +#define AF_IEEE802154 36 /* IEEE802154 sockets */ +#define AF_MAX 37 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC @@ -233,6 +234,7 @@ struct ucred { #define PF_RXRPC AF_RXRPC #define PF_ISDN AF_ISDN #define PF_PHONET AF_PHONET +#define PF_IEEE802154 AF_IEEE802154 #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ diff --git a/net/core/dev.c b/net/core/dev.c index 81b392e..11560e3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -269,7 +269,8 @@ static const unsigned short netdev_lock_type[] = ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, - ARPHRD_PHONET_PIPE, ARPHRD_VOID, ARPHRD_NONE}; + ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY, + ARPHRD_VOID, ARPHRD_NONE}; static const char *netdev_lock_name[] = {"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", @@ -286,7 +287,8 @@ static const char *netdev_lock_name[] = "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", - "_xmit_PHONET_PIPE", "_xmit_VOID", "_xmit_NONE"}; + "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_IEEE802154_PHY", + "_xmit_VOID", "_xmit_NONE"}; static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; diff --git a/net/core/sock.c b/net/core/sock.c index 58dec9d..04e35eb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -155,6 +155,7 @@ static const char *af_family_key_strings[AF_MAX+1] = { "sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" , "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" , "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" , + "sk_lock-AF_IEEE802154", "sk_lock-AF_MAX" }; static const char *af_family_slock_key_strings[AF_MAX+1] = { @@ -170,6 +171,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = { "slock-27" , "slock-28" , "slock-AF_CAN" , "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , + "slock-AF_IEEE802154", "slock-AF_MAX" }; static const char *af_family_clock_key_strings[AF_MAX+1] = { @@ -185,6 +187,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = { "clock-27" , "clock-28" , "clock-AF_CAN" , "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , + "clock-AF_IEEE802154", "clock-AF_MAX" }; -- cgit v0.10.2 From 9ec7671603573ede31207eb5b0b3e1aa211b2854 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 8 Jun 2009 12:18:48 +0000 Subject: net: add IEEE 802.15.4 socket family implementation Add support for communication over IEEE 802.15.4 networks. This implementation is neither certified nor complete, but aims to that goal. This commit contains only the socket interface for communication over IEEE 802.15.4 networks. One can either send RAW datagrams or use SOCK_DGRAM to encapsulate data inside normal IEEE 802.15.4 packets. Configuration interface, drivers and software MAC 802.15.4 implementation will follow. Initial implementation was done by Maxim Gorbachyov, Maxim Osipov and Pavel Smolensky as a research project at Siemens AG. Later the stack was heavily reworked to better suit the linux networking model, and is now maitained as an open project partially sponsored by Siemens. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Sergey Lapin Signed-off-by: David S. Miller diff --git a/include/net/ieee802154/af_ieee802154.h b/include/net/ieee802154/af_ieee802154.h new file mode 100644 index 0000000..0d78605 --- /dev/null +++ b/include/net/ieee802154/af_ieee802154.h @@ -0,0 +1,60 @@ +/* + * IEEE 802.15.4 inteface for userspace + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#ifndef _AF_IEEE802154_H +#define _AF_IEEE802154_H + +#include /* for sa_family_t */ + +enum { + IEEE802154_ADDR_NONE = 0x0, + /* RESERVED = 0x01, */ + IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */ + IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */ +}; + +/* address length, octets */ +#define IEEE802154_ADDR_LEN 8 + +struct ieee802154_addr { + int addr_type; + u16 pan_id; + union { + u8 hwaddr[IEEE802154_ADDR_LEN]; + u16 short_addr; + }; +}; + +#define IEEE802154_PANID_BROADCAST 0xffff +#define IEEE802154_ADDR_BROADCAST 0xffff +#define IEEE802154_ADDR_UNDEF 0xfffe + +struct sockaddr_ieee802154 { + sa_family_t family; /* AF_IEEE802154 */ + struct ieee802154_addr addr; +}; + +/* master device */ +#define IEEE802154_SIOC_ADD_SLAVE (SIOCDEVPRIVATE + 0) + +#endif diff --git a/include/net/ieee802154/mac_def.h b/include/net/ieee802154/mac_def.h new file mode 100644 index 0000000..8cb6846 --- /dev/null +++ b/include/net/ieee802154/mac_def.h @@ -0,0 +1,160 @@ +/* + * IEEE802.15.4-2003 specification + * + * Copyright (C) 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Pavel Smolenskiy + * Maxim Gorbachyov + * Maxim Osipov + * Dmitry Eremin-Solenikov + */ + +#ifndef IEEE802154_MAC_DEF_H +#define IEEE802154_MAC_DEF_H + +#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */ +#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */ +#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */ +#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */ + +#define IEEE802154_FC_TYPE_SHIFT 0 +#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1) +#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT) +#define IEEE802154_FC_SET_TYPE(v, x) do { \ + v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \ + (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \ + } while (0) + +#define IEEE802154_FC_SECEN (1 << 3) +#define IEEE802154_FC_FRPEND (1 << 4) +#define IEEE802154_FC_ACK_REQ (1 << 5) +#define IEEE802154_FC_INTRA_PAN (1 << 6) + +#define IEEE802154_FC_SAMODE_SHIFT 14 +#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT) +#define IEEE802154_FC_DAMODE_SHIFT 10 +#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT) + +#define IEEE802154_FC_SAMODE(x) \ + (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT) + +#define IEEE802154_FC_DAMODE(x) \ + (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT) + + +/* MAC's Command Frames Identifiers */ +#define IEEE802154_CMD_ASSOCIATION_REQ 0x01 +#define IEEE802154_CMD_ASSOCIATION_RESP 0x02 +#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03 +#define IEEE802154_CMD_DATA_REQ 0x04 +#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05 +#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06 +#define IEEE802154_CMD_BEACON_REQ 0x07 +#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08 +#define IEEE802154_CMD_GTS_REQ 0x09 + +/* + * The return values of MAC operations + */ +enum { + /* + * The requested operation was completed successfully. + * For a transmission request, this value indicates + * a successful transmission. + */ + IEEE802154_SUCCESS = 0x0, + + /* The beacon was lost following a synchronization request. */ + IEEE802154_BEACON_LOSS = 0xe0, + /* + * A transmission could not take place due to activity on the + * channel, i.e., the CSMA-CA mechanism has failed. + */ + IEEE802154_CHNL_ACCESS_FAIL = 0xe1, + /* The GTS request has been denied by the PAN coordinator. */ + IEEE802154_DENINED = 0xe2, + /* The attempt to disable the transceiver has failed. */ + IEEE802154_DISABLE_TRX_FAIL = 0xe3, + /* + * The received frame induces a failed security check according to + * the security suite. + */ + IEEE802154_FAILED_SECURITY_CHECK = 0xe4, + /* + * The frame resulting from secure processing has a length that is + * greater than aMACMaxFrameSize. + */ + IEEE802154_FRAME_TOO_LONG = 0xe5, + /* + * The requested GTS transmission failed because the specified GTS + * either did not have a transmit GTS direction or was not defined. + */ + IEEE802154_INVALID_GTS = 0xe6, + /* + * A request to purge an MSDU from the transaction queue was made using + * an MSDU handle that was not found in the transaction table. + */ + IEEE802154_INVALID_HANDLE = 0xe7, + /* A parameter in the primitive is out of the valid range.*/ + IEEE802154_INVALID_PARAMETER = 0xe8, + /* No acknowledgment was received after aMaxFrameRetries. */ + IEEE802154_NO_ACK = 0xe9, + /* A scan operation failed to find any network beacons.*/ + IEEE802154_NO_BEACON = 0xea, + /* No response data were available following a request. */ + IEEE802154_NO_DATA = 0xeb, + /* The operation failed because a short address was not allocated. */ + IEEE802154_NO_SHORT_ADDRESS = 0xec, + /* + * A receiver enable request was unsuccessful because it could not be + * completed within the CAP. + */ + IEEE802154_OUT_OF_CAP = 0xed, + /* + * A PAN identifier conflict has been detected and communicated to the + * PAN coordinator. + */ + IEEE802154_PANID_CONFLICT = 0xee, + /* A coordinator realignment command has been received. */ + IEEE802154_REALIGMENT = 0xef, + /* The transaction has expired and its information discarded. */ + IEEE802154_TRANSACTION_EXPIRED = 0xf0, + /* There is no capacity to store the transaction. */ + IEEE802154_TRANSACTION_OVERFLOW = 0xf1, + /* + * The transceiver was in the transmitter enabled state when the + * receiver was requested to be enabled. + */ + IEEE802154_TX_ACTIVE = 0xf2, + /* The appropriate key is not available in the ACL. */ + IEEE802154_UNAVAILABLE_KEY = 0xf3, + /* + * A SET/GET request was issued with the identifier of a PIB attribute + * that is not supported. + */ + IEEE802154_UNSUPPORTED_ATTR = 0xf4, + /* + * A request to perform a scan operation failed because the MLME was + * in the process of performing a previously initiated scan operation. + */ + IEEE802154_SCAN_IN_PROGRESS = 0xfc, +}; + + +#endif + + diff --git a/include/net/ieee802154/netdevice.h b/include/net/ieee802154/netdevice.h new file mode 100644 index 0000000..e2506af --- /dev/null +++ b/include/net/ieee802154/netdevice.h @@ -0,0 +1,115 @@ +/* + * An interface between IEEE802.15.4 device and rest of the kernel. + * + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Pavel Smolenskiy + * Maxim Gorbachyov + * Maxim Osipov + * Dmitry Eremin-Solenikov + */ + +#ifndef IEEE802154_NETDEVICE_H +#define IEEE802154_NETDEVICE_H + +/* + * A control block of skb passed between the ARPHRD_IEEE802154 device + * and other stack parts. + */ +struct ieee802154_mac_cb { + u8 lqi; + struct ieee802154_addr sa; + struct ieee802154_addr da; + u8 flags; + u8 seq; +}; + +static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb) +{ + return (struct ieee802154_mac_cb *)skb->cb; +} + +#define MAC_CB_FLAG_TYPEMASK ((1 << 3) - 1) + +#define MAC_CB_FLAG_ACKREQ (1 << 3) +#define MAC_CB_FLAG_SECEN (1 << 4) +#define MAC_CB_FLAG_INTRAPAN (1 << 5) + +static inline int mac_cb_is_ackreq(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ; +} + +static inline int mac_cb_is_secen(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN; +} + +static inline int mac_cb_is_intrapan(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN; +} + +static inline int mac_cb_type(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK; +} + +#define IEEE802154_MAC_SCAN_ED 0 +#define IEEE802154_MAC_SCAN_ACTIVE 1 +#define IEEE802154_MAC_SCAN_PASSIVE 2 +#define IEEE802154_MAC_SCAN_ORPHAN 3 + +/* + * This should be located at net_device->ml_priv + */ +struct ieee802154_mlme_ops { + int (*assoc_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 channel, u8 cap); + int (*assoc_resp)(struct net_device *dev, + struct ieee802154_addr *addr, + u16 short_addr, u8 status); + int (*disassoc_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 reason); + int (*start_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 channel, u8 bcn_ord, u8 sf_ord, + u8 pan_coord, u8 blx, u8 coord_realign); + int (*scan_req)(struct net_device *dev, + u8 type, u32 channels, u8 duration); + + /* + * FIXME: these should become the part of PIB/MIB interface. + * However we still don't have IB interface of any kind + */ + u16 (*get_pan_id)(struct net_device *dev); + u16 (*get_short_addr)(struct net_device *dev); + u8 (*get_dsn)(struct net_device *dev); + u8 (*get_bsn)(struct net_device *dev); +}; + +static inline struct ieee802154_mlme_ops *ieee802154_mlme_ops( + struct net_device *dev) +{ + return dev->ml_priv; +} + +#endif + + diff --git a/net/Kconfig b/net/Kconfig index c19f549c..7051b97 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -179,6 +179,7 @@ source "net/lapb/Kconfig" source "net/econet/Kconfig" source "net/wanrouter/Kconfig" source "net/phonet/Kconfig" +source "net/ieee802154/Kconfig" source "net/sched/Kconfig" source "net/dcb/Kconfig" diff --git a/net/Makefile b/net/Makefile index 9e00a55..ba324ae 100644 --- a/net/Makefile +++ b/net/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_NET_9P) += 9p/ ifneq ($(CONFIG_DCB),) obj-y += dcb/ endif +obj-y += ieee802154/ ifeq ($(CONFIG_NET),y) obj-$(CONFIG_SYSCTL) += sysctl_net.o diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig new file mode 100644 index 0000000..1c1de97 --- /dev/null +++ b/net/ieee802154/Kconfig @@ -0,0 +1,12 @@ +config IEEE802154 + tristate "IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support (EXPERIMENTAL)" + depends on EXPERIMENTAL + ---help--- + IEEE Std 802.15.4 defines a low data rate, low power and low + complexity short range wireless personal area networks. It was + designed to organise networks of sensors, switches, etc automation + devices. Maximum allowed data rate is 250 kb/s and typical personal + operating space around 10m. + + Say Y here to compile LR-WPAN support into the kernel or say M to + compile it as modules. diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile new file mode 100644 index 0000000..7451c7c --- /dev/null +++ b/net/ieee802154/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_IEEE802154) += af_802154.o +af_802154-y := af_ieee802154.o raw.o dgram.o + +ccflags-y += -Wall -DDEBUG diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h new file mode 100644 index 0000000..b1ec525 --- /dev/null +++ b/net/ieee802154/af802154.h @@ -0,0 +1,36 @@ +/* + * Internal interfaces for ieee 802.15.4 address family. + * + * Copyright 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#ifndef AF802154_H +#define AF802154_H + +struct sk_buff; +struct net_devce; +extern struct proto ieee802154_raw_prot; +extern struct proto ieee802154_dgram_prot; +void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb); +int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb); +struct net_device *ieee802154_get_dev(struct net *net, + struct ieee802154_addr *addr); + +#endif diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c new file mode 100644 index 0000000..882a927 --- /dev/null +++ b/net/ieee802154/af_ieee802154.c @@ -0,0 +1,372 @@ +/* + * IEEE802154.4 socket interface + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Maxim Gorbachyov + */ + +#include +#include +#include +#include +#include +#include /* For TIOCOUTQ/INQ */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "af802154.h" + +#define DBG_DUMP(data, len) { \ + int i; \ + pr_debug("function: %s: data: len %d:\n", __func__, len); \ + for (i = 0; i < len; i++) {\ + pr_debug("%02x: %02x\n", i, (data)[i]); \ + } \ +} + +/* + * Utility function for families + */ +struct net_device *ieee802154_get_dev(struct net *net, + struct ieee802154_addr *addr) +{ + struct net_device *dev = NULL; + struct net_device *tmp; + u16 pan_id, short_addr; + + switch (addr->addr_type) { + case IEEE802154_ADDR_LONG: + rtnl_lock(); + dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr); + if (dev) + dev_hold(dev); + rtnl_unlock(); + break; + case IEEE802154_ADDR_SHORT: + if (addr->pan_id == 0xffff || + addr->short_addr == IEEE802154_ADDR_UNDEF || + addr->short_addr == 0xffff) + break; + + rtnl_lock(); + + for_each_netdev(net, tmp) { + if (tmp->type != ARPHRD_IEEE802154) + continue; + + pan_id = ieee802154_mlme_ops(tmp)->get_pan_id(tmp); + short_addr = + ieee802154_mlme_ops(tmp)->get_short_addr(tmp); + + if (pan_id == addr->pan_id && + short_addr == addr->short_addr) { + dev = tmp; + dev_hold(dev); + break; + } + } + + rtnl_unlock(); + break; + default: + pr_warning("Unsupported ieee802154 address type: %d\n", + addr->addr_type); + break; + } + + return dev; +} + +static int ieee802154_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (sk) { + sock->sk = NULL; + sk->sk_prot->close(sk, 0); + } + return 0; +} +static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + + return sk->sk_prot->sendmsg(iocb, sk, msg, len); +} + +static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, + int addr_len) +{ + struct sock *sk = sock->sk; + + if (sk->sk_prot->bind) + return sk->sk_prot->bind(sk, uaddr, addr_len); + + return sock_no_bind(sock, uaddr, addr_len); +} + +static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) +{ + struct sock *sk = sock->sk; + + if (uaddr->sa_family == AF_UNSPEC) + return sk->sk_prot->disconnect(sk, flags); + + return sk->sk_prot->connect(sk, uaddr, addr_len); +} + +static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, + unsigned int cmd) +{ + struct ifreq ifr; + int ret = -EINVAL; + struct net_device *dev; + + if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) + return -EFAULT; + + ifr.ifr_name[IFNAMSIZ-1] = 0; + + dev_load(sock_net(sk), ifr.ifr_name); + dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); + if (dev->type == ARPHRD_IEEE802154 || + dev->type == ARPHRD_IEEE802154_PHY) + ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); + + if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) + ret = -EFAULT; + dev_put(dev); + + return ret; +} + +static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + struct sock *sk = sock->sk; + + switch (cmd) { + case SIOCGSTAMP: + return sock_get_timestamp(sk, (struct timeval __user *)arg); + case SIOCGSTAMPNS: + return sock_get_timestampns(sk, (struct timespec __user *)arg); + case SIOCGIFADDR: + case SIOCSIFADDR: + return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg, + cmd); + default: + if (!sk->sk_prot->ioctl) + return -ENOIOCTLCMD; + return sk->sk_prot->ioctl(sk, cmd, arg); + } +} + +static const struct proto_ops ieee802154_raw_ops = { + .family = PF_IEEE802154, + .owner = THIS_MODULE, + .release = ieee802154_sock_release, + .bind = ieee802154_sock_bind, + .connect = ieee802154_sock_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = sock_no_getname, + .poll = datagram_poll, + .ioctl = ieee802154_sock_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_common_setsockopt, + .getsockopt = sock_common_getsockopt, + .sendmsg = ieee802154_sock_sendmsg, + .recvmsg = sock_common_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_sock_common_setsockopt, + .compat_getsockopt = compat_sock_common_getsockopt, +#endif +}; + +static const struct proto_ops ieee802154_dgram_ops = { + .family = PF_IEEE802154, + .owner = THIS_MODULE, + .release = ieee802154_sock_release, + .bind = ieee802154_sock_bind, + .connect = ieee802154_sock_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = sock_no_getname, + .poll = datagram_poll, + .ioctl = ieee802154_sock_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_common_setsockopt, + .getsockopt = sock_common_getsockopt, + .sendmsg = ieee802154_sock_sendmsg, + .recvmsg = sock_common_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_sock_common_setsockopt, + .compat_getsockopt = compat_sock_common_getsockopt, +#endif +}; + + +/* + * Create a socket. Initialise the socket, blank the addresses + * set the state. + */ +static int ieee802154_create(struct net *net, struct socket *sock, + int protocol) +{ + struct sock *sk; + int rc; + struct proto *proto; + const struct proto_ops *ops; + + if (net != &init_net) + return -EAFNOSUPPORT; + + switch (sock->type) { + case SOCK_RAW: + proto = &ieee802154_raw_prot; + ops = &ieee802154_raw_ops; + break; + case SOCK_DGRAM: + proto = &ieee802154_dgram_prot; + ops = &ieee802154_dgram_ops; + break; + default: + rc = -ESOCKTNOSUPPORT; + goto out; + } + + rc = -ENOMEM; + sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto); + if (!sk) + goto out; + rc = 0; + + sock->ops = ops; + + sock_init_data(sock, sk); + /* FIXME: sk->sk_destruct */ + sk->sk_family = PF_IEEE802154; + + /* Checksums on by default */ + sock_set_flag(sk, SOCK_ZAPPED); + + if (sk->sk_prot->hash) + sk->sk_prot->hash(sk); + + if (sk->sk_prot->init) { + rc = sk->sk_prot->init(sk); + if (rc) + sk_common_release(sk); + } +out: + return rc; +} + +static struct net_proto_family ieee802154_family_ops = { + .family = PF_IEEE802154, + .create = ieee802154_create, + .owner = THIS_MODULE, +}; + +static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + DBG_DUMP(skb->data, skb->len); + if (!netif_running(dev)) + return -ENODEV; + pr_debug("got frame, type %d, dev %p\n", dev->type, dev); + + if (!net_eq(dev_net(dev), &init_net)) + goto drop; + + ieee802154_raw_deliver(dev, skb); + + if (dev->type != ARPHRD_IEEE802154) + goto drop; + + if (skb->pkt_type != PACKET_OTHERHOST) + return ieee802154_dgram_deliver(dev, skb); + +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + + +static struct packet_type ieee802154_packet_type = { + .type = __constant_htons(ETH_P_IEEE802154), + .func = ieee802154_rcv, +}; + +static int __init af_ieee802154_init(void) +{ + int rc = -EINVAL; + + rc = proto_register(&ieee802154_raw_prot, 1); + if (rc) + goto out; + + rc = proto_register(&ieee802154_dgram_prot, 1); + if (rc) + goto err_dgram; + + /* Tell SOCKET that we are alive */ + rc = sock_register(&ieee802154_family_ops); + if (rc) + goto err_sock; + dev_add_pack(&ieee802154_packet_type); + + rc = 0; + goto out; + +err_sock: + proto_unregister(&ieee802154_dgram_prot); +err_dgram: + proto_unregister(&ieee802154_raw_prot); +out: + return rc; +} +static void __exit af_ieee802154_remove(void) +{ + dev_remove_pack(&ieee802154_packet_type); + sock_unregister(PF_IEEE802154); + proto_unregister(&ieee802154_dgram_prot); + proto_unregister(&ieee802154_raw_prot); +} + +module_init(af_ieee802154_init); +module_exit(af_ieee802154_remove); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_IEEE802154); diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c new file mode 100644 index 0000000..1f5ea11 --- /dev/null +++ b/net/ieee802154/dgram.c @@ -0,0 +1,394 @@ +/* + * ZigBee socket interface + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "af802154.h" + +static HLIST_HEAD(dgram_head); +static DEFINE_RWLOCK(dgram_lock); + +struct dgram_sock { + struct sock sk; + + int bound; + struct ieee802154_addr src_addr; + struct ieee802154_addr dst_addr; +}; + +static inline struct dgram_sock *dgram_sk(const struct sock *sk) +{ + return container_of(sk, struct dgram_sock, sk); +} + + +static void dgram_hash(struct sock *sk) +{ + write_lock_bh(&dgram_lock); + sk_add_node(sk, &dgram_head); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + write_unlock_bh(&dgram_lock); +} + +static void dgram_unhash(struct sock *sk) +{ + write_lock_bh(&dgram_lock); + if (sk_del_node_init(sk)) + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + write_unlock_bh(&dgram_lock); +} + +static int dgram_init(struct sock *sk) +{ + struct dgram_sock *ro = dgram_sk(sk); + + ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; + ro->dst_addr.pan_id = 0xffff; + memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); + return 0; +} + +static void dgram_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + +static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) +{ + struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + struct dgram_sock *ro = dgram_sk(sk); + int err = 0; + struct net_device *dev; + + ro->bound = 0; + + if (len < sizeof(*addr)) + return -EINVAL; + + if (addr->family != AF_IEEE802154) + return -EINVAL; + + lock_sock(sk); + + dev = ieee802154_get_dev(sock_net(sk), &addr->addr); + if (!dev) { + err = -ENODEV; + goto out; + } + + if (dev->type != ARPHRD_IEEE802154) { + err = -ENODEV; + goto out_put; + } + + memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr)); + + ro->bound = 1; +out_put: + dev_put(dev); +out: + release_sock(sk); + + return err; +} + +static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + switch (cmd) { + case SIOCOUTQ: + { + int amount = atomic_read(&sk->sk_wmem_alloc); + return put_user(amount, (int __user *)arg); + } + + case SIOCINQ: + { + struct sk_buff *skb; + unsigned long amount; + + amount = 0; + spin_lock_bh(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); + if (skb != NULL) { + /* + * We will only return the amount + * of this packet since that is all + * that will be read. + */ + /* FIXME: parse the header for more correct value */ + amount = skb->len - (3+8+8); + } + spin_unlock_bh(&sk->sk_receive_queue.lock); + return put_user(amount, (int __user *)arg); + } + + } + return -ENOIOCTLCMD; +} + +/* FIXME: autobind */ +static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, + int len) +{ + struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + struct dgram_sock *ro = dgram_sk(sk); + int err = 0; + + if (len < sizeof(*addr)) + return -EINVAL; + + if (addr->family != AF_IEEE802154) + return -EINVAL; + + lock_sock(sk); + + if (!ro->bound) { + err = -ENETUNREACH; + goto out; + } + + memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr)); + +out: + release_sock(sk); + return err; +} + +static int dgram_disconnect(struct sock *sk, int flags) +{ + struct dgram_sock *ro = dgram_sk(sk); + + lock_sock(sk); + + ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; + memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); + + release_sock(sk); + + return 0; +} + +static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t size) +{ + struct net_device *dev; + unsigned mtu; + struct sk_buff *skb; + struct dgram_sock *ro = dgram_sk(sk); + int err; + + if (msg->msg_flags & MSG_OOB) { + pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); + return -EOPNOTSUPP; + } + + if (!ro->bound) + dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); + else + dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr); + + if (!dev) { + pr_debug("no dev\n"); + err = -ENXIO; + goto out; + } + mtu = dev->mtu; + pr_debug("name = %s, mtu = %u\n", dev->name, mtu); + + skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, + msg->msg_flags & MSG_DONTWAIT, + &err); + if (!skb) + goto out_dev; + + skb_reserve(skb, LL_RESERVED_SPACE(dev)); + + skb_reset_network_header(skb); + + mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ; + mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); + err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, + ro->bound ? &ro->src_addr : NULL, size); + if (err < 0) + goto out_skb; + + skb_reset_mac_header(skb); + + err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); + if (err < 0) + goto out_skb; + + if (size > mtu) { + pr_debug("size = %u, mtu = %u\n", size, mtu); + err = -EINVAL; + goto out_skb; + } + + skb->dev = dev; + skb->sk = sk; + skb->protocol = htons(ETH_P_IEEE802154); + + dev_put(dev); + + err = dev_queue_xmit(skb); + if (err > 0) + err = net_xmit_errno(err); + + return err ?: size; + +out_skb: + kfree_skb(skb); +out_dev: + dev_put(dev); +out: + return err; +} + +static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len, int noblock, int flags, + int *addr_len) +{ + size_t copied = 0; + int err = -EOPNOTSUPP; + struct sk_buff *skb; + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto out; + + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + /* FIXME: skip headers if necessary ?! */ + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto done; + + sock_recv_timestamp(msg, sk, skb); + + if (flags & MSG_TRUNC) + copied = skb->len; +done: + skb_free_datagram(sk, skb); +out: + if (err) + return err; + return copied; +} + +static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) +{ + if (sock_queue_rcv_skb(sk, skb) < 0) { + atomic_inc(&sk->sk_drops); + kfree_skb(skb); + return NET_RX_DROP; + } + + return NET_RX_SUCCESS; +} + +static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id, + u16 short_addr, struct dgram_sock *ro) +{ + if (!ro->bound) + return 1; + + if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG && + !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN)) + return 1; + + if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT && + pan_id == ro->src_addr.pan_id && + short_addr == ro->src_addr.short_addr) + return 1; + + return 0; +} + +int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) +{ + struct sock *sk, *prev = NULL; + struct hlist_node *node; + int ret = NET_RX_SUCCESS; + u16 pan_id, short_addr; + + /* Data frame processing */ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev); + + read_lock(&dgram_lock); + sk_for_each(sk, node, &dgram_head) { + if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr, + dgram_sk(sk))) { + if (prev) { + struct sk_buff *clone; + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) + dgram_rcv_skb(prev, clone); + } + + prev = sk; + } + } + + if (prev) + dgram_rcv_skb(prev, skb); + else { + kfree_skb(skb); + ret = NET_RX_DROP; + } + read_unlock(&dgram_lock); + + return ret; +} + +struct proto ieee802154_dgram_prot = { + .name = "IEEE-802.15.4-MAC", + .owner = THIS_MODULE, + .obj_size = sizeof(struct dgram_sock), + .init = dgram_init, + .close = dgram_close, + .bind = dgram_bind, + .sendmsg = dgram_sendmsg, + .recvmsg = dgram_recvmsg, + .hash = dgram_hash, + .unhash = dgram_unhash, + .connect = dgram_connect, + .disconnect = dgram_disconnect, + .ioctl = dgram_ioctl, +}; + diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c new file mode 100644 index 0000000..8b892e0 --- /dev/null +++ b/net/ieee802154/raw.c @@ -0,0 +1,254 @@ +/* + * Raw IEEE 802.15.4 sockets + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#include +#include +#include +#include +#include +#include + +#include "af802154.h" + +static HLIST_HEAD(raw_head); +static DEFINE_RWLOCK(raw_lock); + +static void raw_hash(struct sock *sk) +{ + write_lock_bh(&raw_lock); + sk_add_node(sk, &raw_head); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + write_unlock_bh(&raw_lock); +} + +static void raw_unhash(struct sock *sk) +{ + write_lock_bh(&raw_lock); + if (sk_del_node_init(sk)) + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + write_unlock_bh(&raw_lock); +} + +static void raw_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + +static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len) +{ + struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + int err = 0; + struct net_device *dev = NULL; + + if (len < sizeof(*addr)) + return -EINVAL; + + if (addr->family != AF_IEEE802154) + return -EINVAL; + + lock_sock(sk); + + dev = ieee802154_get_dev(sock_net(sk), &addr->addr); + if (!dev) { + err = -ENODEV; + goto out; + } + + if (dev->type != ARPHRD_IEEE802154_PHY && + dev->type != ARPHRD_IEEE802154) { + err = -ENODEV; + goto out_put; + } + + sk->sk_bound_dev_if = dev->ifindex; + sk_dst_reset(sk); + +out_put: + dev_put(dev); +out: + release_sock(sk); + + return err; +} + +static int raw_connect(struct sock *sk, struct sockaddr *uaddr, + int addr_len) +{ + return -ENOTSUPP; +} + +static int raw_disconnect(struct sock *sk, int flags) +{ + return 0; +} + +static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t size) +{ + struct net_device *dev; + unsigned mtu; + struct sk_buff *skb; + int err; + + if (msg->msg_flags & MSG_OOB) { + pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); + return -EOPNOTSUPP; + } + + lock_sock(sk); + if (!sk->sk_bound_dev_if) + dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); + else + dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); + release_sock(sk); + + if (!dev) { + pr_debug("no dev\n"); + err = -ENXIO; + goto out; + } + + mtu = dev->mtu; + pr_debug("name = %s, mtu = %u\n", dev->name, mtu); + + if (size > mtu) { + pr_debug("size = %u, mtu = %u\n", size, mtu); + err = -EINVAL; + goto out_dev; + } + + skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + goto out_dev; + + skb_reserve(skb, LL_RESERVED_SPACE(dev)); + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + + err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); + if (err < 0) + goto out_skb; + + skb->dev = dev; + skb->sk = sk; + skb->protocol = htons(ETH_P_IEEE802154); + + dev_put(dev); + + err = dev_queue_xmit(skb); + if (err > 0) + err = net_xmit_errno(err); + + return err ?: size; + +out_skb: + kfree_skb(skb); +out_dev: + dev_put(dev); +out: + return err; +} + +static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) +{ + size_t copied = 0; + int err = -EOPNOTSUPP; + struct sk_buff *skb; + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto out; + + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto done; + + sock_recv_timestamp(msg, sk, skb); + + if (flags & MSG_TRUNC) + copied = skb->len; +done: + skb_free_datagram(sk, skb); +out: + if (err) + return err; + return copied; +} + +static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) +{ + if (sock_queue_rcv_skb(sk, skb) < 0) { + atomic_inc(&sk->sk_drops); + kfree_skb(skb); + return NET_RX_DROP; + } + + return NET_RX_SUCCESS; +} + + +void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + + read_lock(&raw_lock); + sk_for_each(sk, node, &raw_head) { + bh_lock_sock(sk); + if (!sk->sk_bound_dev_if || + sk->sk_bound_dev_if == dev->ifindex) { + + struct sk_buff *clone; + + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) + raw_rcv_skb(sk, clone); + } + bh_unlock_sock(sk); + } + read_unlock(&raw_lock); +} + +struct proto ieee802154_raw_prot = { + .name = "IEEE-802.15.4-RAW", + .owner = THIS_MODULE, + .obj_size = sizeof(struct sock), + .close = raw_close, + .bind = raw_bind, + .sendmsg = raw_sendmsg, + .recvmsg = raw_recvmsg, + .hash = raw_hash, + .unhash = raw_unhash, + .connect = raw_connect, + .disconnect = raw_disconnect, +}; + -- cgit v0.10.2 From 2c21d11518b688cd4c8e7ddfcd4ba41482ad075b Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 8 Jun 2009 12:18:49 +0000 Subject: net: add NL802154 interface for configuration of 802.15.4 devices Add a netlink interface for configuration of IEEE 802.15.4 device. Also this interface specifies events notification sent by devices towards higher layers. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Sergey Lapin Signed-off-by: David S. Miller diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h new file mode 100644 index 0000000..2cda00c --- /dev/null +++ b/include/linux/nl802154.h @@ -0,0 +1,119 @@ +/* + * nl802154.h + * + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef NL802154_H +#define NL802154_H + +#define IEEE802154_NL_NAME "802.15.4 MAC" +#define IEEE802154_MCAST_COORD_NAME "coordinator" +#define IEEE802154_MCAST_BEACON_NAME "beacon" + +enum { + __IEEE802154_ATTR_INVALID, + + IEEE802154_ATTR_DEV_NAME, + IEEE802154_ATTR_DEV_INDEX, + + IEEE802154_ATTR_STATUS, + + IEEE802154_ATTR_SHORT_ADDR, + IEEE802154_ATTR_HW_ADDR, + IEEE802154_ATTR_PAN_ID, + + IEEE802154_ATTR_CHANNEL, + + IEEE802154_ATTR_COORD_SHORT_ADDR, + IEEE802154_ATTR_COORD_HW_ADDR, + IEEE802154_ATTR_COORD_PAN_ID, + + IEEE802154_ATTR_SRC_SHORT_ADDR, + IEEE802154_ATTR_SRC_HW_ADDR, + IEEE802154_ATTR_SRC_PAN_ID, + + IEEE802154_ATTR_DEST_SHORT_ADDR, + IEEE802154_ATTR_DEST_HW_ADDR, + IEEE802154_ATTR_DEST_PAN_ID, + + IEEE802154_ATTR_CAPABILITY, + IEEE802154_ATTR_REASON, + IEEE802154_ATTR_SCAN_TYPE, + IEEE802154_ATTR_CHANNELS, + IEEE802154_ATTR_DURATION, + IEEE802154_ATTR_ED_LIST, + IEEE802154_ATTR_BCN_ORD, + IEEE802154_ATTR_SF_ORD, + IEEE802154_ATTR_PAN_COORD, + IEEE802154_ATTR_BAT_EXT, + IEEE802154_ATTR_COORD_REALIGN, + IEEE802154_ATTR_SEC, + + __IEEE802154_ATTR_MAX, +}; + +#define IEEE802154_ATTR_MAX (__IEEE802154_ATTR_MAX - 1) + +extern struct nla_policy ieee802154_policy[]; + +/* commands */ +/* REQ should be responded with CONF + * and INDIC with RESP + */ +enum { + __IEEE802154_COMMAND_INVALID, + + IEEE802154_ASSOCIATE_REQ, + IEEE802154_ASSOCIATE_CONF, + IEEE802154_DISASSOCIATE_REQ, + IEEE802154_DISASSOCIATE_CONF, + IEEE802154_GET_REQ, + IEEE802154_GET_CONF, + IEEE802154_RESET_REQ, + IEEE802154_RESET_CONF, + IEEE802154_SCAN_REQ, + IEEE802154_SCAN_CONF, + IEEE802154_SET_REQ, + IEEE802154_SET_CONF, + IEEE802154_START_REQ, + IEEE802154_START_CONF, + IEEE802154_SYNC_REQ, + IEEE802154_POLL_REQ, + IEEE802154_POLL_CONF, + + IEEE802154_ASSOCIATE_INDIC, + IEEE802154_ASSOCIATE_RESP, + IEEE802154_DISASSOCIATE_INDIC, + IEEE802154_BEACON_NOTIFY_INDIC, + IEEE802154_ORPHAN_INDIC, + IEEE802154_ORPHAN_RESP, + IEEE802154_COMM_STATUS_INDIC, + IEEE802154_SYNC_LOSS_INDIC, + + IEEE802154_GTS_REQ, /* Not supported yet */ + IEEE802154_GTS_INDIC, /* Not supported yet */ + IEEE802154_GTS_CONF, /* Not supported yet */ + IEEE802154_RX_ENABLE_REQ, /* Not supported yet */ + IEEE802154_RX_ENABLE_CONF, /* Not supported yet */ + + __IEEE802154_CMD_MAX, +}; + +#define IEEE802154_CMD_MAX (__IEEE802154_CMD_MAX - 1) + +#endif diff --git a/include/net/ieee802154/nl802154.h b/include/net/ieee802154/nl802154.h new file mode 100644 index 0000000..78efcdf --- /dev/null +++ b/include/net/ieee802154/nl802154.h @@ -0,0 +1,41 @@ +/* + * nl802154.h + * + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef IEEE802154_NL_H +#define IEEE802154_NL_H + +struct net_device; +struct ieee802154_addr; + +int ieee802154_nl_assoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 cap); +int ieee802154_nl_assoc_confirm(struct net_device *dev, + u16 short_addr, u8 status); +int ieee802154_nl_disassoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason); +int ieee802154_nl_disassoc_confirm(struct net_device *dev, + u8 status); +int ieee802154_nl_scan_confirm(struct net_device *dev, + u8 status, u8 scan_type, u32 unscanned, + u8 *edl/*, struct list_head *pan_desc_list */); +int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, + u16 coord_addr); + +#endif diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 7451c7c..f99338a 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,4 +1,5 @@ -obj-$(CONFIG_IEEE802154) += af_802154.o +obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o +nl802154-y := netlink.o nl_policy.o af_802154-y := af_ieee802154.o raw.o dgram.o ccflags-y += -Wall -DDEBUG diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c new file mode 100644 index 0000000..105ad10 --- /dev/null +++ b/net/ieee802154/netlink.c @@ -0,0 +1,523 @@ +/* + * Netlink inteface for IEEE 802.15.4 stack + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int ieee802154_seq_num; + +static struct genl_family ieee802154_coordinator_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = IEEE802154_NL_NAME, + .version = 1, + .maxattr = IEEE802154_ATTR_MAX, +}; + +static struct genl_multicast_group ieee802154_coord_mcgrp = { + .name = IEEE802154_MCAST_COORD_NAME, +}; + +static struct genl_multicast_group ieee802154_beacon_mcgrp = { + .name = IEEE802154_MCAST_BEACON_NAME, +}; + +/* Requests to userspace */ +static struct sk_buff *ieee802154_nl_create(int flags, u8 req) +{ + void *hdr; + struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + + if (!msg) + return NULL; + + hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, + &ieee802154_coordinator_family, flags, req); + if (!hdr) { + nlmsg_free(msg); + return NULL; + } + + return msg; +} + +static int ieee802154_nl_finish(struct sk_buff *msg) +{ + /* XXX: nlh is right at the start of msg */ + void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); + + if (!genlmsg_end(msg, hdr)) + goto out; + + return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, + GFP_ATOMIC); +out: + nlmsg_free(msg); + return -ENOBUFS; +} + +int ieee802154_nl_assoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 cap) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + if (addr->addr_type != IEEE802154_ADDR_LONG) { + pr_err("%s: received non-long source address!\n", __func__); + return -EINVAL; + } + + msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, + addr->hwaddr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_assoc_indic); + +int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, + u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr); + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); + +int ieee802154_nl_disassoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + if (addr->addr_type == IEEE802154_ADDR_LONG) + NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, + addr->hwaddr); + else + NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, + addr->short_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); + +int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); + +int ieee802154_nl_beacon_indic(struct net_device *dev, + u16 panid, u16 coord_addr) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_beacon_indic); + +int ieee802154_nl_scan_confirm(struct net_device *dev, + u8 status, u8 scan_type, u32 unscanned, + u8 *edl/* , struct list_head *pan_desc_list */) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); + NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); + + if (edl) + NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_scan_confirm); + +/* Requests from userspace */ +static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) +{ + struct net_device *dev; + + if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { + char name[IFNAMSIZ + 1]; + nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], + sizeof(name)); + dev = dev_get_by_name(&init_net, name); + } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) + dev = dev_get_by_index(&init_net, + nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); + else + return NULL; + + if (dev->type != ARPHRD_IEEE802154) { + dev_put(dev); + return NULL; + } + + return dev; +} + +static int ieee802154_associate_req(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if (!info->attrs[IEEE802154_ATTR_CHANNEL] || + !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || + (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && + !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || + !info->attrs[IEEE802154_ATTR_CAPABILITY]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, + info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], + IEEE802154_ADDR_LEN); + } else { + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); + } + addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + + ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, + nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), + nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); + + dev_put(dev); + return ret; +} + +static int ieee802154_associate_resp(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if (!info->attrs[IEEE802154_ATTR_STATUS] || + !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || + !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], + IEEE802154_ADDR_LEN); + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + + + ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, + nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), + nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); + + dev_put(dev); + return ret; +} + +static int ieee802154_disassociate_req(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && + !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || + !info->attrs[IEEE802154_ATTR_REASON]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, + info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], + IEEE802154_ADDR_LEN); + } else { + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); + } + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + + ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, + nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); + + dev_put(dev); + return ret; +} + +/* + * PANid, channel, beacon_order = 15, superframe_order = 15, + * PAN_coordinator, battery_life_extension = 0, + * coord_realignment = 0, security_enable = 0 +*/ +static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + + u8 channel, bcn_ord, sf_ord; + int pan_coord, blx, coord_realign; + int ret; + + if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || + !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || + !info->attrs[IEEE802154_ATTR_CHANNEL] || + !info->attrs[IEEE802154_ATTR_BCN_ORD] || + !info->attrs[IEEE802154_ATTR_SF_ORD] || + !info->attrs[IEEE802154_ATTR_PAN_COORD] || + !info->attrs[IEEE802154_ATTR_BAT_EXT] || + !info->attrs[IEEE802154_ATTR_COORD_REALIGN] + ) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); + addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + + channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); + bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); + sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); + pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); + blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); + coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); + + ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, + bcn_ord, sf_ord, pan_coord, blx, coord_realign); + + dev_put(dev); + return ret; +} + +static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev; + int ret; + u8 type; + u32 channels; + u8 duration; + + if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || + !info->attrs[IEEE802154_ATTR_CHANNELS] || + !info->attrs[IEEE802154_ATTR_DURATION]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); + channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); + duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); + + ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, + duration); + + dev_put(dev); + return ret; +} + +#define IEEE802154_OP(_cmd, _func) \ + { \ + .cmd = _cmd, \ + .policy = ieee802154_policy, \ + .doit = _func, \ + .dumpit = NULL, \ + .flags = GENL_ADMIN_PERM, \ + } + +static struct genl_ops ieee802154_coordinator_ops[] = { + IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), + IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), + IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), + IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), + IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), +}; + +static int __init ieee802154_nl_init(void) +{ + int rc; + int i; + + rc = genl_register_family(&ieee802154_coordinator_family); + if (rc) + goto fail; + + rc = genl_register_mc_group(&ieee802154_coordinator_family, + &ieee802154_coord_mcgrp); + if (rc) + goto fail; + + rc = genl_register_mc_group(&ieee802154_coordinator_family, + &ieee802154_beacon_mcgrp); + if (rc) + goto fail; + + + for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { + rc = genl_register_ops(&ieee802154_coordinator_family, + &ieee802154_coordinator_ops[i]); + if (rc) + goto fail; + } + + return 0; + +fail: + genl_unregister_family(&ieee802154_coordinator_family); + return rc; +} +module_init(ieee802154_nl_init); + +static void __exit ieee802154_nl_exit(void) +{ + genl_unregister_family(&ieee802154_coordinator_family); +} +module_exit(ieee802154_nl_exit); + diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c new file mode 100644 index 0000000..c7d71d1 --- /dev/null +++ b/net/ieee802154/nl_policy.c @@ -0,0 +1,52 @@ +/* + * nl802154.h + * + * Copyright (C) 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#define NLA_HW_ADDR NLA_U64 + +struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { + [IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, }, + [IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, }, + + [IEEE802154_ATTR_STATUS] = { .type = NLA_U8, }, + [IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, }, + [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, }, + [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, }, + [IEEE802154_ATTR_SRC_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_SRC_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_SRC_PAN_ID] = { .type = NLA_U16, }, + [IEEE802154_ATTR_DEST_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_DEST_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_DEST_PAN_ID] = { .type = NLA_U16, }, + + [IEEE802154_ATTR_CAPABILITY] = { .type = NLA_U8, }, + [IEEE802154_ATTR_REASON] = { .type = NLA_U8, }, + [IEEE802154_ATTR_SCAN_TYPE] = { .type = NLA_U8, }, + [IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, }, + [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, + [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, +}; -- cgit v0.10.2 From 02cf228639233aa227a152955a98564c7a18f9ee Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 8 Jun 2009 12:18:50 +0000 Subject: ieee802154: add documentation about our stack Add MAINTAINERS entry and a small text describing our stack interfaces, how to hook the drivers, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Sergey Lapin Signed-off-by: David S. Miller diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt new file mode 100644 index 0000000..a0280ad --- /dev/null +++ b/Documentation/networking/ieee802154.txt @@ -0,0 +1,76 @@ + + Linux IEEE 802.15.4 implementation + + +Introduction +============ + +The Linux-ZigBee project goal is to provide complete implementation +of IEEE 802.15.4 / ZigBee / 6LoWPAN protocols. IEEE 802.15.4 is a stack +of protocols for organizing Low-Rate Wireless Personal Area Networks. + +Currently only IEEE 802.15.4 layer is implemented. We have choosen +to use plain Berkeley socket API, the generic Linux networking stack +to transfer IEEE 802.15.4 messages and a special protocol over genetlink +for configuration/management + + +Socket API +========== + +int sd = socket(PF_IEEE802154, SOCK_DGRAM, 0); +..... + +The address family, socket addresses etc. are defined in the +include/net/ieee802154/af_ieee802154.h header or in the special header +in our userspace package (see either linux-zigbee sourceforge download page +or git tree at git://linux-zigbee.git.sourceforge.net/gitroot/linux-zigbee). + +One can use SOCK_RAW for passing raw data towards device xmit function. YMMV. + + +MLME - MAC Level Management +============================ + +Most of IEEE 802.15.4 MLME interfaces are directly mapped on netlink commands. +See the include/net/ieee802154/nl802154.h header. Our userspace tools package +(see above) provides CLI configuration utility for radio interfaces and simple +coordinator for IEEE 802.15.4 networks as an example users of MLME protocol. + + +Kernel side +============= + +Like with WiFi, there are several types of devices implementing IEEE 802.15.4. +1) 'HardMAC'. The MAC layer is implemented in the device itself, the device + exports MLME and data API. +2) 'SoftMAC' or just radio. These types of devices are just radio transceivers + possibly with some kinds of acceleration like automatic CRC computation and + comparation, automagic ACK handling, address matching, etc. + +Those types of devices require different approach to be hooked into Linux kernel. + + +HardMAC +======= + +See the header include/net/ieee802154/netdevice.h. You have to implement Linux +net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family +code via plain sk_buffs. The control block of sk_buffs will contain additional +info as described in the struct ieee802154_mac_cb. + +To hook the MLME interface you have to populate the ml_priv field of your +net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are +required. + +We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c + + +SoftMAC +======= + +We are going to provide intermediate layer impelementing IEEE 802.15.4 MAC +in software. This is currently WIP. + +See header include/net/ieee802154/mac802154.h and several drivers in +drivers/ieee802154/ diff --git a/MAINTAINERS b/MAINTAINERS index 2f6a8fc..a6df68f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2819,6 +2819,18 @@ L: linux1394-devel@lists.sourceforge.net S: Maintained F: drivers/ieee1394/raw1394* +IEEE 802.15.4 SUBSYSTEM +P: Dmitry Eremin-Solenikov +M: dbaryshkov@gmail.com +P: Sergey Lapin +M: slapin@ossfans.org +L: linux-zigbee-devel@lists.sourceforge.net +W: http://apps.sourceforge.net/trac/linux-zigbee +T: git git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git +S: Maintained +F: net/ieee802154/ +F: drivers/ieee801254/ + INTEGRITY MEASUREMENT ARCHITECTURE (IMA) P: Mimi Zohar M: zohar@us.ibm.com -- cgit v0.10.2 From 8459464f07cf67cab07b17d5736d75fb86adab22 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 8 Jun 2009 12:18:51 +0000 Subject: ieee802154: add simple HardMAC driver sample fakehard is a really simple driver implementing only necessary callbacks and serves the role of an example of driver for HardMAC IEEE 802.15.4 device. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Sergey Lapin Signed-off-by: David S. Miller diff --git a/drivers/Makefile b/drivers/Makefile index 1266ead..9e7d4e5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -107,3 +107,4 @@ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ +obj-y += ieee802154/ diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig new file mode 100644 index 0000000..25740bd --- /dev/null +++ b/drivers/ieee802154/Kconfig @@ -0,0 +1,22 @@ +menuconfig IEEE802154_DRIVERS + bool "IEEE 802.15.4 drivers" + depends on NETDEVICES && IEEE802154 + default y + ---help--- + Say Y here to get to see options for IEEE 802.15.4 Low-Rate + Wireless Personal Area Network device drivers. This option alone + does not add any kernel code. + + If you say N, all options in this submenu will be skipped and + disabled. + +config IEEE802154_FAKEHARD + tristate "Fake LR-WPAN driver with several interconnected devices" + depends on IEEE802154_DRIVERS + ---help--- + Say Y here to enable the fake driver that serves as an example + of HardMAC device driver. + + This driver can also be built as a module. To do so say M here. + The module will be called 'fakehard'. + diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile new file mode 100644 index 0000000..e0e8e1a --- /dev/null +++ b/drivers/ieee802154/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o + +EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c new file mode 100644 index 0000000..0384144 --- /dev/null +++ b/drivers/ieee802154/fakehard.c @@ -0,0 +1,270 @@ +/* + * Sample driver for HardMAC IEEE 802.15.4 devices + * + * Copyright (C) 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Dmitry Eremin-Solenikov + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static u16 fake_get_pan_id(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0xeba1; +} + +static u16 fake_get_short_addr(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x1; +} + +static u8 fake_get_dsn(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x00; /* DSN are implemented in HW, so return just 0 */ +} + +static u8 fake_get_bsn(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x00; /* BSN are implemented in HW, so return just 0 */ +} + +static int fake_assoc_req(struct net_device *dev, + struct ieee802154_addr *addr, u8 channel, u8 cap) +{ + /* We simply emulate it here */ + return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), + IEEE802154_SUCCESS); +} + +static int fake_assoc_resp(struct net_device *dev, + struct ieee802154_addr *addr, u16 short_addr, u8 status) +{ + return 0; +} + +static int fake_disassoc_req(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason) +{ + return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); +} + +static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, + u8 channel, + u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, + u8 coord_realign) +{ + return 0; +} + +static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, + u8 duration) +{ + u8 edl[27] = {}; + return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, + channels, + type == IEEE802154_MAC_SCAN_ED ? edl : NULL); +} + +static struct ieee802154_mlme_ops fake_mlme = { + .assoc_req = fake_assoc_req, + .assoc_resp = fake_assoc_resp, + .disassoc_req = fake_disassoc_req, + .start_req = fake_start_req, + .scan_req = fake_scan_req, + + .get_pan_id = fake_get_pan_id, + .get_short_addr = fake_get_short_addr, + .get_dsn = fake_get_dsn, + .get_bsn = fake_get_bsn, +}; + +static int ieee802154_fake_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; +} + +static int ieee802154_fake_close(struct net_device *dev) +{ + netif_stop_queue(dev); + return 0; +} + +static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) +{ + skb->iif = dev->ifindex; + skb->dev = dev; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + dev->trans_start = jiffies; + + /* FIXME: do hardware work here ... */ + + return 0; +} + + +static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr, + int cmd) +{ + struct sockaddr_ieee802154 *sa = + (struct sockaddr_ieee802154 *)&ifr->ifr_addr; + u16 pan_id, short_addr; + + switch (cmd) { + case SIOCGIFADDR: + /* FIXME: fixed here, get from device IRL */ + pan_id = fake_get_pan_id(dev); + short_addr = fake_get_short_addr(dev); + if (pan_id == IEEE802154_PANID_BROADCAST || + short_addr == IEEE802154_ADDR_BROADCAST) + return -EADDRNOTAVAIL; + + sa->family = AF_IEEE802154; + sa->addr.addr_type = IEEE802154_ADDR_SHORT; + sa->addr.pan_id = pan_id; + sa->addr.short_addr = short_addr; + return 0; + } + return -ENOIOCTLCMD; +} + +static int ieee802154_fake_mac_addr(struct net_device *dev, void *p) +{ + return -EBUSY; /* HW address is built into the device */ +} + +static const struct net_device_ops fake_ops = { + .ndo_open = ieee802154_fake_open, + .ndo_stop = ieee802154_fake_close, + .ndo_start_xmit = ieee802154_fake_xmit, + .ndo_do_ioctl = ieee802154_fake_ioctl, + .ndo_set_mac_address = ieee802154_fake_mac_addr, +}; + + +static void ieee802154_fake_setup(struct net_device *dev) +{ + dev->addr_len = IEEE802154_ADDR_LEN; + memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN); + dev->features = NETIF_F_NO_CSUM; + dev->needed_tailroom = 2; /* FCS */ + dev->mtu = 127; + dev->tx_queue_len = 10; + dev->type = ARPHRD_IEEE802154; + dev->flags = IFF_NOARP | IFF_BROADCAST; + dev->watchdog_timeo = 0; +} + + +static int __devinit ieee802154fake_probe(struct platform_device *pdev) +{ + struct net_device *dev = + alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); + int err; + + if (!dev) + return -ENOMEM; + + memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", + dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + dev->netdev_ops = &fake_ops; + dev->ml_priv = &fake_mlme; + + /* + * If the name is a format string the caller wants us to do a + * name allocation. + */ + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto out; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + platform_set_drvdata(pdev, dev); + + err = register_netdev(dev); + if (err < 0) + goto out; + + + dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); + return 0; + +out: + unregister_netdev(dev); + return err; +} + +static int __devexit ieee802154fake_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + unregister_netdev(dev); + free_netdev(dev); + return 0; +} + +static struct platform_device *ieee802154fake_dev; + +static struct platform_driver ieee802154fake_driver = { + .probe = ieee802154fake_probe, + .remove = __devexit_p(ieee802154fake_remove), + .driver = { + .name = "ieee802154hardmac", + .owner = THIS_MODULE, + }, +}; + +static __init int fake_init(void) +{ + ieee802154fake_dev = platform_device_register_simple( + "ieee802154hardmac", -1, NULL, 0); + return platform_driver_register(&ieee802154fake_driver); +} + +static __exit void fake_exit(void) +{ + platform_driver_unregister(&ieee802154fake_driver); + platform_device_unregister(ieee802154fake_dev); +} + +module_init(fake_init); +module_exit(fake_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 18c29a8..3f739cf 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2725,6 +2725,8 @@ source "drivers/net/wan/Kconfig" source "drivers/atm/Kconfig" +source "drivers/ieee802154/Kconfig" + source "drivers/s390/net/Kconfig" config XEN_NETDEV_FRONTEND -- cgit v0.10.2 From 23a2d1b233f535fc74f8dca66e488980b4db041b Mon Sep 17 00:00:00 2001 From: Dave Graham Date: Mon, 8 Jun 2009 14:28:17 +0000 Subject: e1000e: Fixes possible phy corrupton on 82571 designs. Phy corruption has been observed on 2-port 82571 adapters, and is root-caused to lack of synchronization between the 2 driver instances, which conflict when attempting to access the phy via the single MDIC register. A semaphore exists for this purpose, and is now used on these designs. Because PXE &/or EFI boot code (which we cannot expect to be built with this fix) may leave the inter-instance semaphore in an invalid initial state when the driver first loads, this fix also includes a one-time (per driver load) fix-up of the semaphore initial state. Signed-off-by: dave graham Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index c4b3f4f..b53b40b 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -71,6 +71,7 @@ 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); +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); /** * e1000_init_phy_params_82571 - Init PHY func ptrs. @@ -212,6 +213,9 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct e1000_mac_info *mac = &hw->mac; struct e1000_mac_operations *func = &mac->ops; + u32 swsm = 0; + u32 swsm2 = 0; + bool force_clear_smbi = false; /* Set media type */ switch (adapter->pdev->device) { @@ -276,6 +280,50 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) break; } + /* + * Ensure that the inter-port SWSM.SMBI lock bit is clear before + * first NVM or PHY acess. This should be done for single-port + * devices, and for one port only on dual-port devices so that + * for those devices we can still use the SMBI lock to synchronize + * inter-port accesses to the PHY & NVM. + */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + swsm2 = er32(SWSM2); + + if (!(swsm2 & E1000_SWSM2_LOCK)) { + /* Only do this for the first interface on this card */ + ew32(SWSM2, + swsm2 | E1000_SWSM2_LOCK); + force_clear_smbi = true; + } else + force_clear_smbi = false; + break; + default: + force_clear_smbi = true; + break; + } + + if (force_clear_smbi) { + /* Make sure SWSM.SMBI is clear */ + swsm = er32(SWSM); + if (swsm & E1000_SWSM_SMBI) { + /* This bit should not be set on a first interface, and + * indicates that the bootagent or EFI code has + * improperly left this bit enabled + */ + hw_dbg(hw, "Please update your 82571 Bootagent\n"); + } + ew32(SWSM, swsm & ~E1000_SWSM_SMBI); + } + + /* + * Initialze device specific counter of SMBI acquisition + * timeouts. + */ + hw->dev_spec.e82571.smb_counter = 0; + return 0; } @@ -413,11 +461,37 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) { u32 swsm; - s32 timeout = hw->nvm.word_size + 1; + s32 sw_timeout = hw->nvm.word_size + 1; + s32 fw_timeout = hw->nvm.word_size + 1; s32 i = 0; + /* + * If we have timedout 3 times on trying to acquire + * the inter-port SMBI semaphore, there is old code + * operating on the other port, and it is not + * releasing SMBI. Modify the number of times that + * we try for the semaphore to interwork with this + * older code. + */ + if (hw->dev_spec.e82571.smb_counter > 2) + sw_timeout = 1; + + /* Get the SW semaphore */ + while (i < sw_timeout) { + swsm = er32(SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + i++; + } + + if (i == sw_timeout) { + hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); + hw->dev_spec.e82571.smb_counter++; + } /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < fw_timeout; i++) { swsm = er32(SWSM); ew32(SWSM, swsm | E1000_SWSM_SWESMBI); @@ -428,9 +502,9 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) udelay(50); } - if (i == timeout) { + if (i == fw_timeout) { /* Release semaphores */ - e1000e_put_hw_semaphore(hw); + e1000_put_hw_semaphore_82571(hw); hw_dbg(hw, "Driver can't access the NVM\n"); return -E1000_ERR_NVM; } @@ -449,9 +523,7 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) u32 swsm; swsm = er32(SWSM); - - swsm &= ~E1000_SWSM_SWESMBI; - + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); ew32(SWSM, swsm); } diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 674a47e..8890c97 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -376,6 +376,8 @@ #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ +#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ + /* Interrupt Cause Read */ #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index fce3f05..163c1c0 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -214,6 +214,7 @@ enum e1e_registers { E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ E1000_SWSM = 0x05B50, /* SW Semaphore */ E1000_FWSM = 0x05B54, /* FW Semaphore */ + E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ E1000_HICR = 0x08F00, /* Host Interface Control */ }; @@ -883,6 +884,7 @@ struct e1000_fc_info { struct e1000_dev_spec_82571 { bool laa_is_present; bool alt_mac_addr_is_present; + u32 smb_counter; }; struct e1000_shadow_ram { -- cgit v0.10.2 From edfea6e641edee07bc69c70dd978088fc1cecd74 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 8 Jun 2009 14:28:36 +0000 Subject: e1000e: Call e1000e_config_collision_dist() after TCTL has been set e1000e_config_collision_dist() sets tctl, but subsequently tctl is overwritten. It seems to me that as things stand the call to e1000e_config_collision_dist() has no effect and should either be removed or moved down a little bit. This kernel patch takes the latter option. Signed-off-by: Simon Horman Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 9043f1b..677f604 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2256,8 +2256,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TARC(1), tarc); } - e1000e_config_collision_dist(hw); - /* Setup Transmit Descriptor Settings for eop descriptor */ adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; @@ -2270,6 +2268,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TCTL, tctl); + e1000e_config_collision_dist(hw); + adapter->tx_queue_len = adapter->netdev->tx_queue_len; } -- cgit v0.10.2 From 18760f1e74e8dfe8f30d4891e66163d1e6feb893 Mon Sep 17 00:00:00 2001 From: Chaitanya Lala Date: Mon, 8 Jun 2009 14:28:54 +0000 Subject: e1000e: Expose MDI-X status via ethtool change Ethtool is a standard way of getting information about ethernet interfaces. We enhance ethtool kernel interface & e1000e to make the MDI-X status readable via ethtool in userspace. Signed-off-by: Chaitanya Lala Signed-off-by: Arthur Jones Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 3d64356..1bf4d2a 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -167,6 +167,15 @@ static int e1000_get_settings(struct net_device *netdev, ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + + /* MDI-X => 2; MDI =>1; Invalid =>0 */ + if ((hw->phy.media_type == e1000_media_type_copper) && + !hw->mac.get_link_status) + ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : + ETH_TP_MDI; + else + ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + return 0; } diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 380b042..9b660bd 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -30,7 +30,8 @@ struct ethtool_cmd { __u32 maxtxpkt; /* Tx pkts before generating tx int */ __u32 maxrxpkt; /* Rx pkts before generating rx int */ __u16 speed_hi; - __u16 reserved2; + __u8 eth_tp_mdix; + __u8 reserved2; __u32 lp_advertising; /* Features the link partner advertises */ __u32 reserved[2]; }; @@ -632,6 +633,11 @@ struct ethtool_ops { #define AUTONEG_DISABLE 0x00 #define AUTONEG_ENABLE 0x01 +/* Mode MDI or MDI-X */ +#define ETH_TP_MDI_INVALID 0x00 +#define ETH_TP_MDI 0x01 +#define ETH_TP_MDI_X 0x02 + /* Wake-On-Lan options. */ #define WAKE_PHY (1 << 0) #define WAKE_UCAST (1 << 1) -- cgit v0.10.2 From 3d8fd38567729202afd0ff3904c818ed0cb1de52 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 8 Jun 2009 14:38:44 +0000 Subject: ixgbe: Include offloaded FCoE data into total rx/tx statistics for 82599 Include offloaded FCoE data into total rx/tx statistics for 82599 so they are properly reflected by ethtool or ifconfig. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index d5939de..3c3bf1f 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -280,7 +280,9 @@ out_noddp_unmap: * * This checks ddp status. * - * Returns : 0 for success and skb will not be delivered to ULD + * Returns : < 0 indicates an error or not a FCiE ddp, 0 indicates + * not passing the skb to ULD, > 0 indicates is the length of data + * being ddped. */ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, union ixgbe_adv_rx_desc *rx_desc, @@ -334,6 +336,8 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, /* return 0 to bypass going to ULD for DDPed data */ if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP) rc = 0; + else + rc = ddp->len; } ddp_out: diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index b7f9b63..c5b5002 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -28,6 +28,7 @@ #ifndef _IXGBE_FCOE_H #define _IXGBE_FCOE_H +#include #include /* shift bits within STAT fo FCSTAT */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 09994e9..a551a96 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -293,12 +293,24 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, if (cleaned && skb) { unsigned int segs, bytecount; + unsigned int hlen = skb_headlen(skb); /* gso_segs is currently only valid for tcp */ segs = skb_shinfo(skb)->gso_segs ?: 1; +#ifdef IXGBE_FCOE + /* adjust for FCoE Sequence Offload */ + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + && (skb->protocol == htons(ETH_P_FCOE)) && + skb_is_gso(skb)) { + hlen = skb_transport_offset(skb) + + sizeof(struct fc_frame_header) + + sizeof(struct fcoe_crc_eof); + segs = DIV_ROUND_UP(skb->len - hlen, + skb_shinfo(skb)->gso_size); + } +#endif /* IXGBE_FCOE */ /* multiply data chunks by size of headers */ - bytecount = ((segs - 1) * skb_headlen(skb)) + - skb->len; + bytecount = ((segs - 1) * hlen) + skb->len; total_packets += segs; total_bytes += bytecount; } @@ -683,6 +695,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, bool cleaned = false; int cleaned_count = 0; unsigned int total_rx_bytes = 0, total_rx_packets = 0; +#ifdef IXGBE_FCOE + int ddp_bytes = 0; +#endif /* IXGBE_FCOE */ i = rx_ring->next_to_clean; rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); @@ -793,9 +808,11 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, skb->protocol = eth_type_trans(skb, adapter->netdev); #ifdef IXGBE_FCOE /* if ddp, not passing to ULD unless for FCP_RSP or error */ - if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) - if (!ixgbe_fcoe_ddp(adapter, rx_desc, skb)) + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb); + if (!ddp_bytes) goto next_desc; + } #endif /* IXGBE_FCOE */ ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc); @@ -821,6 +838,21 @@ next_desc: if (cleaned_count) ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); +#ifdef IXGBE_FCOE + /* include DDPed FCoE data */ + if (ddp_bytes > 0) { + unsigned int mss; + + mss = adapter->netdev->mtu - sizeof(struct fcoe_hdr) - + sizeof(struct fc_frame_header) - + sizeof(struct fcoe_crc_eof); + if (mss > 512) + mss &= ~511; + total_rx_bytes += ddp_bytes; + total_rx_packets += DIV_ROUND_UP(ddp_bytes, mss); + } +#endif /* IXGBE_FCOE */ + rx_ring->total_packets += total_rx_packets; rx_ring->total_bytes += total_rx_bytes; adapter->net_stats.rx_bytes += total_rx_bytes; -- cgit v0.10.2 From 25b0b999fbf5cc1893b110d530102951795d2f73 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 8 Jun 2009 10:30:19 +0000 Subject: bnx2: no need to check before vfreeing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to check if a pointer is NULL before calling vfree(), since vfree() function already check for it. Signed-off-by: Breno Leitão Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 391d2d4..f99e17e 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -546,8 +546,7 @@ bnx2_free_rx_mem(struct bnx2 *bp) rxr->rx_desc_mapping[j]); rxr->rx_desc_ring[j] = NULL; } - if (rxr->rx_buf_ring) - vfree(rxr->rx_buf_ring); + vfree(rxr->rx_buf_ring); rxr->rx_buf_ring = NULL; for (j = 0; j < bp->rx_max_pg_ring; j++) { @@ -557,8 +556,7 @@ bnx2_free_rx_mem(struct bnx2 *bp) rxr->rx_pg_desc_mapping[j]); rxr->rx_pg_desc_ring[j] = NULL; } - if (rxr->rx_pg_ring) - vfree(rxr->rx_pg_ring); + vfree(rxr->rx_pg_ring); rxr->rx_pg_ring = NULL; } } -- cgit v0.10.2 From a31e1ffd2231b8fdf7eda9ed750a4a0df9bcad4e Mon Sep 17 00:00:00 2001 From: Laszlo Attila Toth Date: Tue, 9 Jun 2009 15:16:34 +0200 Subject: netfilter: xt_socket: added new revision of the 'socket' match supporting flags If the XT_SOCKET_TRANSPARENT flag is set, enabled 'transparent' socket option is required for the socket to be matched. Signed-off-by: Laszlo Attila Toth Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/xt_socket.h b/include/linux/netfilter/xt_socket.h new file mode 100644 index 0000000..6f475b8 --- /dev/null +++ b/include/linux/netfilter/xt_socket.h @@ -0,0 +1,12 @@ +#ifndef _XT_SOCKET_H +#define _XT_SOCKET_H + +enum { + XT_SOCKET_TRANSPARENT = 1 << 0, +}; + +struct xt_socket_mtinfo1 { + __u8 flags; +}; + +#endif /* _XT_SOCKET_H */ diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 1acc089..ebf00ad 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -22,6 +22,8 @@ #include #include +#include + #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #define XT_SOCKET_HAVE_CONNTRACK 1 #include @@ -86,7 +88,8 @@ extract_icmp_fields(const struct sk_buff *skb, static bool -socket_mt(const struct sk_buff *skb, const struct xt_match_param *par) +socket_match(const struct sk_buff *skb, const struct xt_match_param *par, + const struct xt_socket_mtinfo1 *info) { const struct iphdr *iph = ip_hdr(skb); struct udphdr _hdr, *hp = NULL; @@ -141,10 +144,24 @@ socket_mt(const struct sk_buff *skb, const struct xt_match_param *par) sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol, saddr, daddr, sport, dport, par->in, false); if (sk != NULL) { - bool wildcard = (sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->rcv_saddr == 0); + bool wildcard; + bool transparent = true; + + /* Ignore sockets listening on INADDR_ANY */ + wildcard = (sk->sk_state != TCP_TIME_WAIT && + inet_sk(sk)->rcv_saddr == 0); + + /* Ignore non-transparent sockets, + if XT_SOCKET_TRANSPARENT is used */ + if (info && info->flags & XT_SOCKET_TRANSPARENT) + transparent = ((sk->sk_state != TCP_TIME_WAIT && + inet_sk(sk)->transparent) || + (sk->sk_state == TCP_TIME_WAIT && + inet_twsk(sk)->tw_transparent)); nf_tproxy_put_sock(sk); - if (wildcard) + + if (wildcard || !transparent) sk = NULL; } @@ -157,23 +174,47 @@ socket_mt(const struct sk_buff *skb, const struct xt_match_param *par) return (sk != NULL); } -static struct xt_match socket_mt_reg __read_mostly = { - .name = "socket", - .family = AF_INET, - .match = socket_mt, - .hooks = 1 << NF_INET_PRE_ROUTING, - .me = THIS_MODULE, +static bool +socket_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) +{ + return socket_match(skb, par, NULL); +} + +static bool +socket_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) +{ + return socket_match(skb, par, par->matchinfo); +} + +static struct xt_match socket_mt_reg[] __read_mostly = { + { + .name = "socket", + .revision = 0, + .family = NFPROTO_IPV4, + .match = socket_mt_v0, + .hooks = 1 << NF_INET_PRE_ROUTING, + .me = THIS_MODULE, + }, + { + .name = "socket", + .revision = 1, + .family = NFPROTO_IPV4, + .match = socket_mt_v1, + .matchsize = sizeof(struct xt_socket_mtinfo1), + .hooks = 1 << NF_INET_PRE_ROUTING, + .me = THIS_MODULE, + }, }; static int __init socket_mt_init(void) { nf_defrag_ipv4_enable(); - return xt_register_match(&socket_mt_reg); + return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); } static void __exit socket_mt_exit(void) { - xt_unregister_match(&socket_mt_reg); + xt_unregister_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); } module_init(socket_mt_init); -- cgit v0.10.2 From e04cc15f52eb072937cec2bbd8499f37afe5e1ef Mon Sep 17 00:00:00 2001 From: Hisashi Hifumi Date: Tue, 9 Jun 2009 16:47:45 +0900 Subject: ocfs2: fdatasync should skip unimportant metadata writeout In ocfs2, fdatasync and fsync are identical. I think fdatasync should skip committing transaction when inode->i_state is set just I_DIRTY_SYNC and this indicates only atime or/and mtime updates. Following patch improves fdatasync throughput. #sysbench --num-threads=16 --max-requests=300000 --test=fileio --file-block-size=4K --file-total-size=16G --file-test-mode=rndwr --file-fsync-mode=fdatasync run Results: -2.6.30-rc8 Test execution summary: total time: 107.1445s total number of events: 119559 total time taken by event execution: 116.1050 per-request statistics: min: 0.0000s avg: 0.0010s max: 0.1220s approx. 95 percentile: 0.0016s Threads fairness: events (avg/stddev): 7472.4375/303.60 execution time (avg/stddev): 7.2566/0.64 -2.6.30-rc8-patched Test execution summary: total time: 86.8529s total number of events: 300016 total time taken by event execution: 24.3077 per-request statistics: min: 0.0000s avg: 0.0001s max: 0.0336s approx. 95 percentile: 0.0001s Threads fairness: events (avg/stddev): 18751.0000/718.75 execution time (avg/stddev): 1.5192/0.05 Signed-off-by: Hisashi Hifumi Acked-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 1a96cac..07267e0 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -187,6 +187,9 @@ static int ocfs2_sync_file(struct file *file, if (err) goto bail; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + goto bail; + journal = osb->journal->j_journal; err = jbd2_journal_force_commit(journal); -- cgit v0.10.2 From 1506e30b5f25f6c3357167a18f0e4ae6f5662a28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 17:49:06 -0700 Subject: rfkill: include err.h Since we use ERR_PTR and similar macros, we need to include linux/err.h. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index ee3edde..d7e818a 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -105,6 +105,7 @@ enum rfkill_user_states { #include #include #include +#include /* this is opaque */ struct rfkill; -- cgit v0.10.2 From 0808dc80939b08ec215f472e17a5d8f6b148037e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Jun 2009 18:05:28 -0700 Subject: netfilter: Fix extra semi-colon in skb_walk_frags() changes. Noticed by Jesper Dangaard Brouer Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c index 6983e41..3fc598ee 100644 --- a/net/ipv4/netfilter/nf_nat_proto_sctp.c +++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c @@ -58,7 +58,7 @@ sctp_manip_pkt(struct sk_buff *skb, } crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff); - skb_walk_frags(skb, frag); + skb_walk_frags(skb, frag) crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag), crc32); crc32 = sctp_end_cksum(crc32); -- cgit v0.10.2 From cfec0cbc92cdcec5a540bf340c5a9fb8c89e5af1 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 05:39:29 +0000 Subject: qlge: Add support for retrieving firmware version. This is used by driver banner and ethtool info. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index e186071..258ef44 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1430,6 +1430,7 @@ struct ql_adapter { /* Hardware information */ u32 chip_rev_id; + u32 fw_rev_id; u32 func; /* PCI function for this adapter */ spinlock_t adapter_lock; @@ -1580,6 +1581,7 @@ void ql_mpi_idc_work(struct work_struct *work); void ql_mpi_port_cfg_work(struct work_struct *work); int ql_mb_get_fw_state(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev); +int ql_mb_about_fw(struct ql_adapter *qdev); #if 1 #define QL_ALL_DUMP diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 913b2a5..ea02163 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -293,7 +293,10 @@ static void ql_get_drvinfo(struct net_device *ndev, 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); + snprintf(drvinfo->fw_version, 32, "v%d.%d.%d", + (qdev->fw_rev_id & 0x00ff0000) >> 16, + (qdev->fw_rev_id & 0x0000ff00) >> 8, + (qdev->fw_rev_id & 0x000000ff)); strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); drvinfo->n_stats = 0; drvinfo->testinfo_len = 0; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 0b0778d..5fb875d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -837,6 +837,13 @@ exit: static int ql_8000_port_initialize(struct ql_adapter *qdev) { int status; + /* + * Get MPI firmware version for driver banner + * and ethool info. + */ + status = ql_mb_about_fw(qdev); + if (status) + goto exit; status = ql_mb_get_fw_state(qdev); if (status) goto exit; diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 3bd60a4..a67c14a 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -547,6 +547,40 @@ end: return status; } + +/* Get MPI firmware version. This will be used for + * driver banner and for ethtool info. + * Returns zero on success. + */ +int ql_mb_about_fw(struct ql_adapter *qdev) +{ + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + int status = 0; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 1; + mbcp->out_count = 3; + + mbcp->mbox_in[0] = MB_CMD_ABOUT_FW; + + status = ql_mailbox_command(qdev, mbcp); + if (status) + return status; + + if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { + QPRINTK(qdev, DRV, ERR, + "Failed about firmware command\n"); + status = -EIO; + } + + /* Store the firmware version */ + qdev->fw_rev_id = mbcp->mbox_out[1]; + + return status; +} + /* Get functional state for MPI firmware. * Returns zero on success. */ -- cgit v0.10.2 From e4059d942a211cc752c145bd46b03386e425be0b Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 05:39:30 +0000 Subject: qlge: Remove netif_set_gso_max_size() call. Not necessary if hardware supports 65536 as it's the default setting. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5fb875d..a45e282 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3367,7 +3367,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) * completion handler rx_rings. */ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; - netif_set_gso_max_size(qdev->ndev, 65536); for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; -- cgit v0.10.2 From a32959cd9df77423c8b375119ee7f135ff302bc1 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 05:39:27 +0000 Subject: qlge: Drop inbound error frames. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index a45e282..0775b4d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1525,6 +1525,13 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, return; } + /* Frame error, so drop the packet. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { + QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", + ib_mac_rsp->flags2); + dev_kfree_skb_any(skb); + return; + } prefetch(skb->data); skb->dev = ndev; if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { @@ -1547,7 +1554,6 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, * csum or frame errors. */ if (qdev->rx_csum && - !(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { -- cgit v0.10.2 From ec33a49135d96df56ef106a49c2434ca81f821f9 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 05:39:28 +0000 Subject: qlge: Drop inbound frames > MTU. The max frame size register is set higher than the MTU to accomodate FCoE frames. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 0775b4d..738691d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1532,6 +1532,15 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, dev_kfree_skb_any(skb); return; } + + /* The max framesize filter on this chip is set higher than + * MTU since FCoE uses 2k frames. + */ + if (skb->len > ndev->mtu + ETH_HLEN) { + dev_kfree_skb_any(skb); + return; + } + prefetch(skb->data); skb->dev = ndev; if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { -- cgit v0.10.2 From 542512e4824c1cecc05478f279dccbde1d8bf97a Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 05:39:33 +0000 Subject: qlge: Add support for using alternate MAC address. Extract either manufacturer or Bladecenter Open Fabric Manager (BOFM) MAC address. BOFM may indicate an alternate MAC address. This patch honors that request by extracting the MAC address from a different flash location if a flag is set. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 738691d..d6517eb 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -675,6 +675,7 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) int status; __le32 *p = (__le32 *)&qdev->flash; u32 offset; + u8 mac_addr[6]; /* Get flash offset for function and adjust * for dword access. @@ -705,14 +706,26 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) goto exit; } - if (!is_valid_ether_addr(qdev->flash.flash_params_8000.mac_addr)) { + /* Extract either manufacturer or BOFM modified + * MAC address. + */ + if (qdev->flash.flash_params_8000.data_type1 == 2) + memcpy(mac_addr, + qdev->flash.flash_params_8000.mac_addr1, + qdev->ndev->addr_len); + else + memcpy(mac_addr, + qdev->flash.flash_params_8000.mac_addr, + qdev->ndev->addr_len); + + if (!is_valid_ether_addr(mac_addr)) { QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n"); status = -EINVAL; goto exit; } memcpy(qdev->ndev->dev_addr, - qdev->flash.flash_params_8000.mac_addr, + mac_addr, qdev->ndev->addr_len); exit: -- cgit v0.10.2 From e4552f51ceefcf51b79c5bf8dafc7abb4bb7657d Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 05:39:32 +0000 Subject: qlge: Add support for varied pcie function numbers. Currently we support only PCIe NIC functions zero and one, and FCoE functions as 3 and 4. Future configurations can mix these up in any fashion. This patch removes the 0-1 dependancy and allows usage of any of the 4 functions. We also find the alternate NIC function (if exist) and determine our port number based on the comparison of the two functions: Lower function number gets first port, higher function gets second port. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 258ef44..5eb52ca 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -65,6 +65,17 @@ #define DB_PAGE_SIZE 4096 +/* MPI test register definitions. This register + * is used for determining alternate NIC function's + * PCI->func number. + */ +enum { + MPI_TEST_FUNC_PORT_CFG = 0x1002, + MPI_TEST_NIC1_FUNC_SHIFT = 1, + MPI_TEST_NIC2_FUNC_SHIFT = 5, + MPI_TEST_NIC_FUNC_MASK = 0x00000007, +}; + /* * Processor Address Register (PROC_ADDR) bit definitions. */ @@ -1432,6 +1443,8 @@ struct ql_adapter { u32 chip_rev_id; u32 fw_rev_id; u32 func; /* PCI function for this adapter */ + u32 alt_func; /* PCI function for alternate adapter */ + u32 port; /* Port number this adapter */ spinlock_t adapter_lock; spinlock_t hw_lock; @@ -1581,6 +1594,7 @@ void ql_mpi_idc_work(struct work_struct *work); void ql_mpi_port_cfg_work(struct work_struct *work); int ql_mb_get_fw_state(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev); +int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); int ql_mb_about_fw(struct ql_adapter *qdev); #if 1 diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index d6517eb..5055f5b 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -680,7 +680,7 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) /* Get flash offset for function and adjust * for dword access. */ - if (!qdev->func) + if (!qdev->port) offset = FUNC0_FLASH_OFFSET / sizeof(u32); else offset = FUNC1_FLASH_OFFSET / sizeof(u32); @@ -744,7 +744,7 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev) /* Second function's parameters follow the first * function's. */ - if (qdev->func) + if (qdev->port) offset = size; if (ql_sem_spinlock(qdev, SEM_FLASH_MASK)) @@ -3220,9 +3220,10 @@ 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, " + "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, " "XG Roll = %d, XG Rev = %d.\n", qdev->func, + qdev->port, qdev->chip_rev_id & 0x0000000f, qdev->chip_rev_id >> 4 & 0x0000000f, qdev->chip_rev_id >> 8 & 0x0000000f, @@ -3677,12 +3678,53 @@ static struct nic_operations qla8000_nic_ops = { .port_initialize = ql_8000_port_initialize, }; +/* Find the pcie function number for the other NIC + * on this chip. Since both NIC functions share a + * common firmware we have the lowest enabled function + * do any common work. Examples would be resetting + * after a fatal firmware error, or doing a firmware + * coredump. + */ +static int ql_get_alt_pcie_func(struct ql_adapter *qdev) +{ + int status = 0; + u32 temp; + u32 nic_func1, nic_func2; + + status = ql_read_mpi_reg(qdev, MPI_TEST_FUNC_PORT_CFG, + &temp); + if (status) + return status; + + nic_func1 = ((temp >> MPI_TEST_NIC1_FUNC_SHIFT) & + MPI_TEST_NIC_FUNC_MASK); + nic_func2 = ((temp >> MPI_TEST_NIC2_FUNC_SHIFT) & + MPI_TEST_NIC_FUNC_MASK); + + if (qdev->func == nic_func1) + qdev->alt_func = nic_func2; + else if (qdev->func == nic_func2) + qdev->alt_func = nic_func1; + else + status = -EIO; + + return status; +} -static void ql_get_board_info(struct ql_adapter *qdev) +static int ql_get_board_info(struct ql_adapter *qdev) { + int status; qdev->func = (ql_read32(qdev, STS) & STS_FUNC_ID_MASK) >> STS_FUNC_ID_SHIFT; - if (qdev->func) { + if (qdev->func > 3) + return -EIO; + + status = ql_get_alt_pcie_func(qdev); + if (status) + return status; + + qdev->port = (qdev->func < qdev->alt_func) ? 0 : 1; + if (qdev->port) { qdev->xg_sem_mask = SEM_XGMAC1_MASK; qdev->port_link_up = STS_PL1; qdev->port_init = STS_PI1; @@ -3701,6 +3743,7 @@ static void ql_get_board_info(struct ql_adapter *qdev) qdev->nic_ops = &qla8012_nic_ops; else if (qdev->device_id == QLGE_DEVICE_ID_8000) qdev->nic_ops = &qla8000_nic_ops; + return status; } static void ql_release_all(struct pci_dev *pdev) @@ -3795,7 +3838,12 @@ static int __devinit ql_init_device(struct pci_dev *pdev, qdev->ndev = ndev; qdev->pdev = pdev; - ql_get_board_info(qdev); + err = ql_get_board_info(qdev); + if (err) { + dev_err(&pdev->dev, "Register access failed.\n"); + err = -EIO; + goto err_out; + } qdev->msg_enable = netif_msg_init(debug, default_msg); spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->stats_lock); -- cgit v0.10.2 From 00acd0d2ecac925fdcbe47cbda5ea517f87ad354 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 05:39:31 +0000 Subject: qlge: Add set TX csum ethtool op. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index ea02163..37c99fe 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -404,6 +404,7 @@ const struct ethtool_ops qlge_ethtool_ops = { .get_rx_csum = ql_get_rx_csum, .set_rx_csum = ql_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, -- cgit v0.10.2 From 1abb0de2f89c1f9c454c973356b9e4867722f10a Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 9 Jun 2009 06:35:12 +0000 Subject: qlge: bugfix: Get rid of errant spin_unlock(). Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5055f5b..024c734 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3299,7 +3299,6 @@ static int ql_adapter_up(struct ql_adapter *qdev) err = ql_adapter_initialize(qdev); if (err) { QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n"); - spin_unlock(&qdev->hw_lock); goto err_init; } set_bit(QL_ADAPTER_UP, &qdev->flags); -- cgit v0.10.2 From 6e327c11a91d190650df9aabe7d3694d4838bfa1 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 8 Jun 2009 03:11:28 +0000 Subject: 8021q: Vlan driver should use rcu_barrier() on unload instead of syncronize_net() The VLAN 8021q driver needs to call rcu_barrier() when unloading the module, instead of syncronize_net(). This is needed to make sure that outstanding call_rcu() callbacks have completed, before the callback function code is removed on module unload. Signed-off-by: Jesper Dangaard Brouer Reviewed-by: Paul E. McKenney Acked-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 714e1c3..fe64908 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -758,7 +758,7 @@ static void __exit vlan_cleanup_module(void) BUG_ON(!hlist_empty(&vlan_group_hash[i])); unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); - synchronize_net(); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ vlan_gvrp_uninit(); } -- cgit v0.10.2 From 67137f3cc727e4da0297ffd7bfade837aa15ecfa Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 8 Jun 2009 03:11:33 +0000 Subject: nfnetlink_queue: Use rcu_barrier() on module unload. This module uses rcu_call() thus it should use rcu_barrier() on module unload. Also fixed a trivial typo 'nfetlink' -> 'nfnetlink' in comment. Signed-off-by: Jesper Dangaard Brouer Acked-by: Paul E. McKenney Acked-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 8c86011..71daa09 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -1,6 +1,6 @@ /* * This is a module which is used for queueing packets and communicating with - * userspace via nfetlink. + * userspace via nfnetlink. * * (C) 2005 by Harald Welte * (C) 2007 by Patrick McHardy @@ -932,6 +932,8 @@ static void __exit nfnetlink_queue_fini(void) #endif nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); + + rcu_barrier(); /* Wait for completion of call_rcu()'s */ } MODULE_DESCRIPTION("netfilter packet queue handler"); -- cgit v0.10.2 From 382bfeec48e43c416af9b271b9b70d2f61ef32d2 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 8 Jun 2009 03:11:38 +0000 Subject: can: af_can.c use rcu_barrier() on module unload. This module uses rcu_call() thus it should use rcu_barrier() on module unload. Signed-off-by: Jesper Dangaard Brouer Acked-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/net/can/af_can.c b/net/can/af_can.c index 10f0528..e733725 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -903,6 +903,8 @@ static __exit void can_exit(void) } spin_unlock(&can_rcvlists_lock); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + kmem_cache_destroy(rcv_cache); } -- cgit v0.10.2 From eaa184a1a1cda3991420c47bc960ddea6cbacff2 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 8 Jun 2009 03:11:43 +0000 Subject: sctp: protocol.c call rcu_barrier() on unload. On module unload call rcu_barrier(), this is needed as synchronize_rcu() is not strong enough. The kmem_cache_destroy() does invoke synchronize_rcu() but it does not provide same protection. Signed-off-by: Jesper Dangaard Brouer Acked-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index cb2c50d..79cbd47 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1370,6 +1370,8 @@ SCTP_STATIC __exit void sctp_exit(void) sctp_proc_exit(); cleanup_sctp_mibs(); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + kmem_cache_destroy(sctp_chunk_cachep); kmem_cache_destroy(sctp_bucket_cachep); } -- cgit v0.10.2 From bf12691d846b48fa6e3289810a822687457036cf Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 8 Jun 2009 03:11:48 +0000 Subject: sunrpc/auth_gss: Call rcu_barrier() on module unload. As the module uses rcu_call() we should make sure that all rcu callback has been completed before removing the code. Signed-off-by: Jesper Dangaard Brouer Acked-by: Paul E. McKenney Signed-off-by: David S. Miller diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index e630b38..66d458f 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1548,6 +1548,7 @@ static void __exit exit_rpcsec_gss(void) { gss_svc_shutdown(); rpcauth_unregister(&authgss_ops); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ } MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 51611a120e8120290152edd7d0020d22a7f4b4a3 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Wed, 10 Jun 2009 01:12:39 -0700 Subject: can: sja1000_of_platform: fix build problems with printk format According to "Documentation/printk-formats.txt", if the type is dependent on a config option for its size, like resource_size_t, we should use a format specifier of its largest possible type and explicitly cast to it. Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c index aa953fb..3373560 100644 --- a/drivers/net/can/sja1000/sja1000_of_platform.c +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -108,15 +108,17 @@ static int __devinit sja1000_ofp_probe(struct of_device *ofdev, res_size = resource_size(&res); if (!request_mem_region(res.start, res_size, DRV_NAME)) { - dev_err(&ofdev->dev, "couldn't request %#x..%#x\n", - res.start, res.end); + dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); return -EBUSY; } base = ioremap_nocache(res.start, res_size); if (!base) { - dev_err(&ofdev->dev, "couldn't ioremap %#x..%#x\n", - res.start, res.end); + dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); err = -ENOMEM; goto exit_release_mem; } -- cgit v0.10.2 From 440f0d588555892601cfe511728a0fc0c8204063 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 10 Jun 2009 14:32:47 +0200 Subject: netfilter: nf_conntrack: use per-conntrack locks for protocol data Introduce per-conntrack locks and use them instead of the global protocol locks to avoid contention. Especially tcp_lock shows up very high in profiles on larger machines. This will also allow to simplify the upcoming reliable event delivery patches. Signed-off-by: Patrick McHardy diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 2b87737..ecc79f9 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -93,6 +93,8 @@ struct nf_conn { plus 1 for any connection(s) we are `master' for */ struct nf_conntrack ct_general; + spinlock_t lock; + /* XXX should I move this to the tail ? - Y.K */ /* These are my tuples; original and reply */ struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index ba32ed7..3767fb4 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -59,11 +59,11 @@ struct nf_conntrack_l4proto const struct nf_conntrack_tuple *); /* Print out the private part of the conntrack. */ - int (*print_conntrack)(struct seq_file *s, const struct nf_conn *); + int (*print_conntrack)(struct seq_file *s, struct nf_conn *); /* convert protoinfo to nfnetink attributes */ int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, - const struct nf_conn *ct); + struct nf_conn *ct); /* Calculate protoinfo nlattr size */ int (*nlattr_size)(void); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index b54c234..edf9569 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -519,6 +519,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, return ERR_PTR(-ENOMEM); } + spin_lock_init(&ct->lock); atomic_set(&ct->ct_general.use, 1); ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 4448b06..4e503ad 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -143,7 +143,7 @@ nla_put_failure: } static inline int -ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) +ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct) { struct nf_conntrack_l4proto *l4proto; struct nlattr *nest_proto; @@ -347,7 +347,7 @@ nla_put_failure: static int ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, - int event, const struct nf_conn *ct) + int event, struct nf_conn *ct) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 11801c4..6b08d32 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -24,8 +24,6 @@ #include #include -static DEFINE_RWLOCK(dccp_lock); - /* Timeouts are based on values from RFC4340: * * - REQUEST: @@ -491,7 +489,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, return NF_ACCEPT; } - write_lock_bh(&dccp_lock); + spin_lock_bh(&ct->lock); role = ct->proto.dccp.role[dir]; old_state = ct->proto.dccp.state; @@ -535,13 +533,13 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.dccp.last_dir = dir; ct->proto.dccp.last_pkt = type; - write_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_DCCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_dccp: invalid packet ignored "); return NF_ACCEPT; case CT_DCCP_INVALID: - write_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_DCCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_dccp: invalid state transition "); @@ -551,7 +549,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.dccp.last_dir = dir; ct->proto.dccp.last_pkt = type; ct->proto.dccp.state = new_state; - write_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); dn = dccp_pernet(net); nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]); @@ -617,18 +615,18 @@ static int dccp_print_tuple(struct seq_file *s, ntohs(tuple->dst.u.dccp.port)); } -static int dccp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +static int dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct) { return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); } #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, - const struct nf_conn *ct) + struct nf_conn *ct) { struct nlattr *nest_parms; - read_lock_bh(&dccp_lock); + spin_lock_bh(&ct->lock); nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; @@ -638,11 +636,11 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, NLA_PUT_BE64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, cpu_to_be64(ct->proto.dccp.handshake_seq)); nla_nest_end(skb, nest_parms); - read_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); return 0; nla_put_failure: - read_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); return -1; } @@ -673,7 +671,7 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) return -EINVAL; } - write_lock_bh(&dccp_lock); + spin_lock_bh(&ct->lock); ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) { ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; @@ -686,7 +684,7 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) ct->proto.dccp.handshake_seq = be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ])); } - write_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); return 0; } diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 117b801..175a28c 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -219,8 +219,7 @@ static int gre_print_tuple(struct seq_file *s, } /* print private data for conntrack */ -static int gre_print_conntrack(struct seq_file *s, - const struct nf_conn *ct) +static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) { return seq_printf(s, "timeout=%u, stream_timeout=%u ", (ct->proto.gre.timeout / HZ), diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 101b4ad..c10e6f3 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -25,9 +25,6 @@ #include #include -/* Protects ct->proto.sctp */ -static DEFINE_RWLOCK(sctp_lock); - /* FIXME: Examine ipfilter's timeouts and conntrack transitions more closely. They're more complex. --RR @@ -164,13 +161,13 @@ static int sctp_print_tuple(struct seq_file *s, } /* Print out the private part of the conntrack. */ -static int sctp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +static int sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct) { enum sctp_conntrack state; - read_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); state = ct->proto.sctp.state; - read_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); return seq_printf(s, "%s ", sctp_conntrack_names[state]); } @@ -318,7 +315,7 @@ static int sctp_packet(struct nf_conn *ct, } old_state = new_state = SCTP_CONNTRACK_NONE; - write_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { /* Special cases of Verification tag check (Sec 8.5.1) */ if (sch->type == SCTP_CID_INIT) { @@ -371,7 +368,7 @@ static int sctp_packet(struct nf_conn *ct, if (old_state != new_state) nf_conntrack_event_cache(IPCT_PROTOINFO, ct); } - write_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); nf_ct_refresh_acct(ct, ctinfo, skb, sctp_timeouts[new_state]); @@ -386,7 +383,7 @@ static int sctp_packet(struct nf_conn *ct, return NF_ACCEPT; out_unlock: - write_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); out: return -NF_ACCEPT; } @@ -469,11 +466,11 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, #include static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, - const struct nf_conn *ct) + struct nf_conn *ct) { struct nlattr *nest_parms; - read_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; @@ -488,14 +485,14 @@ static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, CTA_PROTOINFO_SCTP_VTAG_REPLY, ct->proto.sctp.vtag[IP_CT_DIR_REPLY]); - read_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); nla_nest_end(skb, nest_parms); return 0; nla_put_failure: - read_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); return -1; } @@ -527,13 +524,13 @@ static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]) return -EINVAL; - write_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]); ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]); ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]); - write_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); return 0; } diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index b7e8a82..5c5739c 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -29,9 +29,6 @@ #include #include -/* Protects ct->proto.tcp */ -static DEFINE_RWLOCK(tcp_lock); - /* "Be conservative in what you do, be liberal in what you accept from others." If it's non-zero, we mark only out of window RST segments as INVALID. */ @@ -309,13 +306,13 @@ static int tcp_print_tuple(struct seq_file *s, } /* Print out the private part of the conntrack. */ -static int tcp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +static int tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct) { enum tcp_conntrack state; - read_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); state = ct->proto.tcp.state; - read_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return seq_printf(s, "%s ", tcp_conntrack_names[state]); } @@ -725,14 +722,14 @@ void nf_conntrack_tcp_update(const struct sk_buff *skb, end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph); - write_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); /* * We have to worry for the ack in the reply packet only... */ if (after(end, ct->proto.tcp.seen[dir].td_end)) ct->proto.tcp.seen[dir].td_end = end; ct->proto.tcp.last_end = end; - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, @@ -841,7 +838,7 @@ static int tcp_packet(struct nf_conn *ct, th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); BUG_ON(th == NULL); - write_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); old_state = ct->proto.tcp.state; dir = CTINFO2DIR(ctinfo); index = get_conntrack_index(th); @@ -871,7 +868,7 @@ static int tcp_packet(struct nf_conn *ct, && ct->proto.tcp.last_index == TCP_RST_SET)) { /* Attempt to reopen a closed/aborted connection. * Delete this connection and look up again. */ - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); /* Only repeat if we can actually remove the timer. * Destruction may already be in progress in process @@ -907,7 +904,7 @@ static int tcp_packet(struct nf_conn *ct, * that the client cannot but retransmit its SYN and * thus initiate a clean new session. */ - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: killing out of sync session "); @@ -920,7 +917,7 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.last_end = segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th); - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid packet ignored "); @@ -929,7 +926,7 @@ static int tcp_packet(struct nf_conn *ct, /* Invalid packet */ pr_debug("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n", dir, get_conntrack_index(th), old_state); - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid state "); @@ -960,7 +957,7 @@ static int tcp_packet(struct nf_conn *ct, if (!tcp_in_window(ct, &ct->proto.tcp, dir, index, skb, dataoff, th, pf)) { - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return -NF_ACCEPT; } in_window: @@ -989,7 +986,7 @@ static int tcp_packet(struct nf_conn *ct, timeout = nf_ct_tcp_timeout_unacknowledged; else timeout = tcp_timeouts[new_state]; - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (new_state != old_state) nf_conntrack_event_cache(IPCT_PROTOINFO, ct); @@ -1106,12 +1103,12 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, #include static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, - const struct nf_conn *ct) + struct nf_conn *ct) { struct nlattr *nest_parms; struct nf_ct_tcp_flags tmp = {}; - read_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); nest_parms = nla_nest_start(skb, CTA_PROTOINFO_TCP | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; @@ -1131,14 +1128,14 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, tmp.flags = ct->proto.tcp.seen[1].flags; NLA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY, sizeof(struct nf_ct_tcp_flags), &tmp); - read_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); nla_nest_end(skb, nest_parms); return 0; nla_put_failure: - read_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return -1; } @@ -1169,7 +1166,7 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]) >= TCP_CONNTRACK_MAX) return -EINVAL; - write_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); if (tb[CTA_PROTOINFO_TCP_STATE]) ct->proto.tcp.state = nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]); @@ -1196,7 +1193,7 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) ct->proto.tcp.seen[1].td_scale = nla_get_u8(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY]); } - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return 0; } -- cgit v0.10.2 From 65822070646ed7f2cf520439006dd863529be16e Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 29 Apr 2009 00:53:14 +0900 Subject: nilfs2: remove nilfs_dat_prepare_free function This function is unused. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index bb8a581..1827f62 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -92,21 +92,6 @@ void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req) nilfs_palloc_abort_alloc_entry(dat, req); } -int nilfs_dat_prepare_free(struct inode *dat, struct nilfs_palloc_req *req) -{ - int ret; - - ret = nilfs_palloc_prepare_free_entry(dat, req); - if (ret < 0) - return ret; - ret = nilfs_dat_prepare_entry(dat, req, 0); - if (ret < 0) { - nilfs_palloc_abort_free_entry(dat, req); - return ret; - } - return 0; -} - void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) { struct nilfs_dat_entry *entry; -- cgit v0.10.2 From d97a51a7e3c298d9899ea91165dfa0783fa5cc5c Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 3 May 2009 21:43:01 +0900 Subject: nilfs2: unify bmap operations starting use of indirect block address This simplifies some low level functions of bmap. Three bmap pointer operations, nilfs_bmap_start_v(), nilfs_bmap_commit_v(), and nilfs_bmap_abort_v(), are unified into one nilfs_bmap_start_v() function. And the related indirect function calls are replaced with it. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 064279e..4f2523f 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -511,24 +511,16 @@ static void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, nilfs_dat_abort_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -static int nilfs_bmap_prepare_start_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +int nilfs_bmap_start_v(struct nilfs_bmap *bmap, union nilfs_bmap_ptr_req *req, + sector_t blocknr) { - return nilfs_dat_prepare_start(nilfs_bmap_get_dat(bmap), &req->bpr_req); -} - -static void nilfs_bmap_commit_start_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req, - sector_t blocknr) -{ - nilfs_dat_commit_start(nilfs_bmap_get_dat(bmap), &req->bpr_req, - blocknr); -} + struct inode *dat = nilfs_bmap_get_dat(bmap); + int ret; -static void nilfs_bmap_abort_start_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - nilfs_dat_abort_start(nilfs_bmap_get_dat(bmap), &req->bpr_req); + ret = nilfs_dat_prepare_start(dat, &req->bpr_req); + if (likely(!ret)) + nilfs_dat_commit_start(dat, &req->bpr_req, blocknr); + return ret; } static int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, @@ -636,9 +628,6 @@ static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_v = { .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, - .bpop_prepare_start_ptr = nilfs_bmap_prepare_start_v, - .bpop_commit_start_ptr = nilfs_bmap_commit_start_v, - .bpop_abort_start_ptr = nilfs_bmap_abort_start_v, .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, .bpop_commit_end_ptr = nilfs_bmap_commit_end_v, .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, @@ -650,9 +639,6 @@ static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_vmdt = { .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, - .bpop_prepare_start_ptr = nilfs_bmap_prepare_start_v, - .bpop_commit_start_ptr = nilfs_bmap_commit_start_v, - .bpop_abort_start_ptr = nilfs_bmap_abort_start_v, .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, .bpop_commit_end_ptr = nilfs_bmap_commit_end_vmdt, .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, @@ -664,9 +650,6 @@ static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_p = { .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_p, .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_p, .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_p, - .bpop_prepare_start_ptr = NULL, - .bpop_commit_start_ptr = NULL, - .bpop_abort_start_ptr = NULL, .bpop_prepare_end_ptr = NULL, .bpop_commit_end_ptr = NULL, .bpop_abort_end_ptr = NULL, @@ -678,9 +661,6 @@ static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_gc = { .bpop_prepare_alloc_ptr = NULL, .bpop_commit_alloc_ptr = NULL, .bpop_abort_alloc_ptr = NULL, - .bpop_prepare_start_ptr = NULL, - .bpop_commit_start_ptr = NULL, - .bpop_abort_start_ptr = NULL, .bpop_prepare_end_ptr = NULL, .bpop_commit_end_ptr = NULL, .bpop_abort_end_ptr = NULL, diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 4f2708a..ad251d3 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -96,13 +96,6 @@ struct nilfs_bmap_ptr_operations { union nilfs_bmap_ptr_req *); void (*bpop_abort_alloc_ptr)(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); - int (*bpop_prepare_start_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); - void (*bpop_commit_start_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *, - sector_t); - void (*bpop_abort_start_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); int (*bpop_prepare_end_ptr)(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); void (*bpop_commit_end_ptr)(struct nilfs_bmap *, @@ -183,6 +176,8 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); * Internal use only */ +int nilfs_bmap_start_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *, + sector_t); int nilfs_bmap_move_v(const struct nilfs_bmap *, __u64, sector_t); int nilfs_bmap_mark_dirty(const struct nilfs_bmap *, __u64); diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 6b37a27..959e5a7 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -2066,12 +2066,9 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree, ptr = nilfs_btree_node_get_ptr(btree, parent, path[level + 1].bp_index); req.bpr_ptr = ptr; - ret = btree->bt_bmap.b_pops->bpop_prepare_start_ptr(&btree->bt_bmap, - &req); - if (ret < 0) + ret = nilfs_bmap_start_v(&btree->bt_bmap, &req, blocknr); + if (unlikely(ret < 0)) return ret; - btree->bt_bmap.b_pops->bpop_commit_start_ptr(&btree->bt_bmap, - &req, blocknr); key = nilfs_btree_node_get_key(btree, parent, path[level + 1].bp_index); diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index c6379e4..5cbba82 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -327,12 +327,9 @@ static int nilfs_direct_assign_v(struct nilfs_direct *direct, int ret; req.bpr_ptr = ptr; - ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr( - &direct->d_bmap, &req); - if (ret < 0) + ret = nilfs_bmap_start_v(&direct->d_bmap, &req, blocknr); + if (unlikely(ret < 0)) return ret; - direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap, - &req, blocknr); binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); -- cgit v0.10.2 From dda54f4b872512eba484c38631bd6ae5b5716f41 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 16 May 2009 21:49:10 +0900 Subject: nilfs2: add sufile function that can modify multiple segment usages This is a preparation for the later cleanup patch ("nilfs2: remove list of freeing segments"). This adds nilfs_sufile_updatev() to sufile, which can modify multiple segment usages at a time. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 98e6867..da12732 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Written by Koji Sato . + * Rivised by Ryusuke Konishi . */ #include @@ -108,6 +109,102 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, nilfs_mdt_mark_buffer_dirty(header_bh); } +/** + * nilfs_sufile_updatev - modify multiple segment usages at a time + * @sufile: inode of segment usage file + * @segnumv: array of segment numbers + * @nsegs: size of @segnumv array + * @create: creation flag + * @ndone: place to store number of modified segments on @segnumv + * @dofunc: primitive operation for the update + * + * Description: nilfs_sufile_updatev() repeatedly calls @dofunc + * against the given array of segments. The @dofunc is called with + * buffers of a header block and the sufile block in which the target + * segment usage entry is contained. If @ndone is given, the number + * of successfully modified segments from the head is stored in the + * place @ndone points to. + * + * Return Value: On success, zero is returned. On error, one of the + * following negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + * + * %-ENOENT - Given segment usage is in hole block (may be returned if + * @create is zero) + * + * %-EINVAL - Invalid segment usage number + */ +int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs, + int create, size_t *ndone, + void (*dofunc)(struct inode *, __u64, + struct buffer_head *, + struct buffer_head *)) +{ + struct buffer_head *header_bh, *bh; + unsigned long blkoff, prev_blkoff; + __u64 *seg; + size_t nerr = 0, n = 0; + int ret = 0; + + if (unlikely(nsegs == 0)) + goto out; + + down_write(&NILFS_MDT(sufile)->mi_sem); + for (seg = segnumv; seg < segnumv + nsegs; seg++) { + if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) { + printk(KERN_WARNING + "%s: invalid segment number: %llu\n", __func__, + (unsigned long long)*seg); + nerr++; + } + } + if (nerr > 0) { + ret = -EINVAL; + goto out_sem; + } + + ret = nilfs_sufile_get_header_block(sufile, &header_bh); + if (ret < 0) + goto out_sem; + + seg = segnumv; + blkoff = nilfs_sufile_get_blkoff(sufile, *seg); + ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh); + if (ret < 0) + goto out_header; + + for (;;) { + dofunc(sufile, *seg, header_bh, bh); + + if (++seg >= segnumv + nsegs) + break; + prev_blkoff = blkoff; + blkoff = nilfs_sufile_get_blkoff(sufile, *seg); + if (blkoff == prev_blkoff) + continue; + + /* get different block */ + brelse(bh); + ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh); + if (unlikely(ret < 0)) + goto out_header; + } + brelse(bh); + + out_header: + n = seg - segnumv; + brelse(header_bh); + out_sem: + up_write(&NILFS_MDT(sufile)->mi_sem); + out: + if (ndone) + *ndone = n; + return ret; +} + int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create, void (*dofunc)(struct inode *, __u64, struct buffer_head *, diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index a2e2efd..e8e2627 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h @@ -46,6 +46,10 @@ int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *); ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, struct nilfs_suinfo *, size_t); +int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *, + void (*dofunc)(struct inode *, __u64, + struct buffer_head *, + struct buffer_head *)); int nilfs_sufile_update(struct inode *, __u64, int, void (*dofunc)(struct inode *, __u64, struct buffer_head *, -- cgit v0.10.2 From 071cb4b81987a28c7ac2702003cff3e61684a630 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 16 May 2009 23:44:55 +0900 Subject: nilfs2: eliminate removal list of segments This will clean up the removal list of segments and the related functions from segment.c and ioctl.c, which have hurt code readability. This elimination is applied by using nilfs_sufile_updatev() previously introduced in the patch ("nilfs2: add sufile function that can modify multiple segment usages"). Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index d6759b9..bdad7e4 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -435,24 +435,6 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, return nmembs; } -static int nilfs_ioctl_free_segments(struct the_nilfs *nilfs, - struct nilfs_argv *argv, void *buf) -{ - size_t nmembs = argv->v_nmembs; - struct nilfs_sb_info *sbi = nilfs->ns_writer; - int ret; - - if (unlikely(!sbi)) { - /* never happens because called for a writable mount */ - WARN_ON(1); - return -EROFS; - } - ret = nilfs_segctor_add_segments_to_be_freed( - NILFS_SC(sbi), buf, nmembs); - - return (ret < 0) ? ret : nmembs; -} - int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, struct nilfs_argv *argv, void **kbufs) { @@ -491,14 +473,6 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, msg = "cannot mark copying blocks dirty"; goto failed; } - ret = nilfs_ioctl_free_segments(nilfs, &argv[4], kbufs[4]); - if (ret < 0) { - /* - * can safely abort because this operation is atomic. - */ - msg = "cannot set segments to be freed"; - goto failed; - } return 0; failed: diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 1e68821..dc0277a 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -26,7 +26,6 @@ #include #include "page.h" #include "segbuf.h" -#include "seglist.h" static struct kmem_cache *nilfs_segbuf_cachep; diff --git a/fs/nilfs2/seglist.h b/fs/nilfs2/seglist.h index d39df91..e448e40 100644 --- a/fs/nilfs2/seglist.h +++ b/fs/nilfs2/seglist.h @@ -32,11 +32,6 @@ struct nilfs_segment_entry { __u64 segnum; -#define NILFS_SLH_FREED 0x0001 /* The segment was freed provisonally. - It must be cancelled if - construction aborted */ - - unsigned flags; struct list_head list; struct buffer_head *bh_su; struct nilfs_segment_usage *raw_su; @@ -52,7 +47,6 @@ nilfs_alloc_segment_entry(__u64 segnum) if (likely(ent)) { ent->segnum = segnum; - ent->flags = 0; ent->bh_su = NULL; ent->raw_su = NULL; INIT_LIST_HEAD(&ent->list); diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 22c7f65..aa97754 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -39,7 +39,6 @@ #include "sufile.h" #include "cpfile.h" #include "ifile.h" -#include "seglist.h" #include "segbuf.h" @@ -79,7 +78,8 @@ enum { /* State flags of collection */ #define NILFS_CF_NODE 0x0001 /* Collecting node blocks */ #define NILFS_CF_IFILE_STARTED 0x0002 /* IFILE stage has started */ -#define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED) +#define NILFS_CF_SUFREED 0x0004 /* segment usages has been freed */ +#define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED | NILFS_CF_SUFREED) /* Operations depending on the construction mode and file type */ struct nilfs_sc_operations { @@ -810,7 +810,7 @@ static int nilfs_segctor_clean(struct nilfs_sc_info *sci) { return list_empty(&sci->sc_dirty_files) && !test_bit(NILFS_SC_DIRTY, &sci->sc_flags) && - list_empty(&sci->sc_cleaning_segments) && + sci->sc_nfreesegs == 0 && (!nilfs_doing_gc() || list_empty(&sci->sc_gc_inodes)); } @@ -1005,44 +1005,6 @@ static void nilfs_drop_collected_inodes(struct list_head *head) } } -static void nilfs_segctor_cancel_free_segments(struct nilfs_sc_info *sci, - struct inode *sufile) - -{ - struct list_head *head = &sci->sc_cleaning_segments; - struct nilfs_segment_entry *ent; - int err; - - list_for_each_entry(ent, head, list) { - if (!(ent->flags & NILFS_SLH_FREED)) - break; - err = nilfs_sufile_cancel_free(sufile, ent->segnum); - WARN_ON(err); /* do not happen */ - ent->flags &= ~NILFS_SLH_FREED; - } -} - -static int nilfs_segctor_prepare_free_segments(struct nilfs_sc_info *sci, - struct inode *sufile) -{ - struct list_head *head = &sci->sc_cleaning_segments; - struct nilfs_segment_entry *ent; - int err; - - list_for_each_entry(ent, head, list) { - err = nilfs_sufile_free(sufile, ent->segnum); - if (unlikely(err)) - return err; - ent->flags |= NILFS_SLH_FREED; - } - return 0; -} - -static void nilfs_segctor_commit_free_segments(struct nilfs_sc_info *sci) -{ - nilfs_dispose_segment_list(&sci->sc_cleaning_segments); -} - static int nilfs_segctor_apply_buffers(struct nilfs_sc_info *sci, struct inode *inode, struct list_head *listp, @@ -1161,6 +1123,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) struct the_nilfs *nilfs = sbi->s_nilfs; struct list_head *head; struct nilfs_inode_info *ii; + size_t ndone; int err = 0; switch (sci->sc_stage.scnt) { @@ -1250,10 +1213,16 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) break; sci->sc_stage.scnt++; /* Fall through */ case NILFS_ST_SUFILE: - err = nilfs_segctor_prepare_free_segments(sci, - nilfs->ns_sufile); - if (unlikely(err)) + err = nilfs_sufile_freev(nilfs->ns_sufile, sci->sc_freesegs, + sci->sc_nfreesegs, &ndone); + if (unlikely(err)) { + nilfs_sufile_cancel_freev(nilfs->ns_sufile, + sci->sc_freesegs, ndone, + NULL); break; + } + sci->sc_stage.flags |= NILFS_CF_SUFREED; + err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile, &nilfs_sc_file_ops); if (unlikely(err)) @@ -1486,7 +1455,15 @@ static void nilfs_segctor_end_construction(struct nilfs_sc_info *sci, { if (unlikely(err)) { nilfs_segctor_free_incomplete_segments(sci, nilfs); - nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); + if (sci->sc_stage.flags & NILFS_CF_SUFREED) { + int ret; + + ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile, + sci->sc_freesegs, + sci->sc_nfreesegs, + NULL); + WARN_ON(ret); /* do not happen */ + } } nilfs_segctor_clear_segment_buffers(sci); } @@ -1585,7 +1562,13 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE) break; - nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); + if (sci->sc_stage.flags & NILFS_CF_SUFREED) { + err = nilfs_sufile_cancel_freev(nilfs->ns_sufile, + sci->sc_freesegs, + sci->sc_nfreesegs, + NULL); + WARN_ON(err); /* do not happen */ + } nilfs_segctor_clear_segment_buffers(sci); err = nilfs_segctor_extend_segments(sci, nilfs, nadd); @@ -2224,10 +2207,8 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) nilfs_segctor_complete_write(sci); /* Commit segments */ - if (has_sr) { - nilfs_segctor_commit_free_segments(sci); + if (has_sr) nilfs_segctor_clear_metadata_dirty(sci); - } nilfs_segctor_end_construction(sci, nilfs, 0); @@ -2301,48 +2282,6 @@ void nilfs_flush_segment(struct super_block *sb, ino_t ino) /* assign bit 0 to data files */ } -int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *sci, - __u64 *segnum, size_t nsegs) -{ - struct nilfs_segment_entry *ent; - struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs; - struct inode *sufile = nilfs->ns_sufile; - LIST_HEAD(list); - __u64 *pnum; - size_t i; - int err; - - for (pnum = segnum, i = 0; i < nsegs; pnum++, i++) { - ent = nilfs_alloc_segment_entry(*pnum); - if (unlikely(!ent)) { - err = -ENOMEM; - goto failed; - } - list_add_tail(&ent->list, &list); - - err = nilfs_open_segment_entry(ent, sufile); - if (unlikely(err)) - goto failed; - - if (unlikely(!nilfs_segment_usage_dirty(ent->raw_su))) - printk(KERN_WARNING "NILFS: unused segment is " - "requested to be cleaned (segnum=%llu)\n", - (unsigned long long)ent->segnum); - nilfs_close_segment_entry(ent, sufile); - } - list_splice(&list, sci->sc_cleaning_segments.prev); - return 0; - - failed: - nilfs_dispose_segment_list(&list); - return err; -} - -void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *sci) -{ - nilfs_dispose_segment_list(&sci->sc_cleaning_segments); -} - struct nilfs_segctor_wait_request { wait_queue_t wq; __u32 seq; @@ -2607,10 +2546,13 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, err = nilfs_init_gcdat_inode(nilfs); if (unlikely(err)) goto out_unlock; + err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs); if (unlikely(err)) goto out_unlock; + sci->sc_freesegs = kbufs[4]; + sci->sc_nfreesegs = argv[4].v_nmembs; list_splice_init(&nilfs->ns_gc_inodes, sci->sc_gc_inodes.prev); for (;;) { @@ -2629,6 +2571,8 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, } out_unlock: + sci->sc_freesegs = NULL; + sci->sc_nfreesegs = 0; nilfs_clear_gcdat_inode(nilfs); nilfs_transaction_unlock(sbi); return err; @@ -2835,7 +2779,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi) INIT_LIST_HEAD(&sci->sc_dirty_files); INIT_LIST_HEAD(&sci->sc_segbufs); INIT_LIST_HEAD(&sci->sc_gc_inodes); - INIT_LIST_HEAD(&sci->sc_cleaning_segments); INIT_LIST_HEAD(&sci->sc_copied_buffers); sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; @@ -2901,9 +2844,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) nilfs_dispose_list(sbi, &sci->sc_dirty_files, 1); } - if (!list_empty(&sci->sc_cleaning_segments)) - nilfs_dispose_segment_list(&sci->sc_cleaning_segments); - WARN_ON(!list_empty(&sci->sc_segbufs)); down_write(&sbi->s_nilfs->ns_segctor_sem); diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index 476bdd5..f36a851 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h @@ -90,8 +90,9 @@ struct nilfs_segsum_pointer { * @sc_nblk_inc: Block count of current generation * @sc_dirty_files: List of files to be written * @sc_gc_inodes: List of GC inodes having blocks to be written - * @sc_cleaning_segments: List of segments to be freed through construction * @sc_copied_buffers: List of copied buffers (buffer heads) to freeze data + * @sc_freesegs: array of segment numbers to be freed + * @sc_nfreesegs: number of segments on @sc_freesegs * @sc_dsync_inode: inode whose data pages are written for a sync operation * @sc_dsync_start: start byte offset of data pages * @sc_dsync_end: end byte offset of data pages (inclusive) @@ -131,9 +132,11 @@ struct nilfs_sc_info { struct list_head sc_dirty_files; struct list_head sc_gc_inodes; - struct list_head sc_cleaning_segments; struct list_head sc_copied_buffers; + __u64 *sc_freesegs; + size_t sc_nfreesegs; + struct nilfs_inode_info *sc_dsync_inode; loff_t sc_dsync_start; loff_t sc_dsync_end; @@ -225,10 +228,6 @@ extern void nilfs_flush_segment(struct super_block *, ino_t); extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *, void **); -extern int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *, - __u64 *, size_t); -extern void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *); - extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *); extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *); diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index e8e2627..fd6232e 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h @@ -54,36 +54,16 @@ int nilfs_sufile_update(struct inode *, __u64, int, void (*dofunc)(struct inode *, __u64, struct buffer_head *, struct buffer_head *)); -void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, - struct buffer_head *); void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *, struct buffer_head *); void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *, struct buffer_head *); +void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, + struct buffer_head *); void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *, struct buffer_head *); /** - * nilfs_sufile_cancel_free - - * @sufile: inode of segment usage file - * @segnum: segment number - * - * Description: - * - * Return Value: On success, 0 is returned. On error, one of the following - * negative error codes is returned. - * - * %-EIO - I/O error. - * - * %-ENOMEM - Insufficient amount of memory available. - */ -static inline int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum) -{ - return nilfs_sufile_update(sufile, segnum, 0, - nilfs_sufile_do_cancel_free); -} - -/** * nilfs_sufile_scrap - make a segment garbage * @sufile: inode of segment usage file * @segnum: segment number to be freed @@ -104,6 +84,38 @@ static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum) } /** + * nilfs_sufile_freev - free segments + * @sufile: inode of segment usage file + * @segnumv: array of segment numbers + * @nsegs: size of @segnumv array + * @ndone: place to store the number of freed segments + */ +static inline int nilfs_sufile_freev(struct inode *sufile, __u64 *segnumv, + size_t nsegs, size_t *ndone) +{ + return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone, + nilfs_sufile_do_free); +} + +/** + * nilfs_sufile_cancel_freev - reallocate freeing segments + * @sufile: inode of segment usage file + * @segnumv: array of segment numbers + * @nsegs: size of @segnumv array + * @ndone: place to store the number of cancelled segments + * + * Return Value: On success, 0 is returned. On error, a negative error codes + * is returned. + */ +static inline int nilfs_sufile_cancel_freev(struct inode *sufile, + __u64 *segnumv, size_t nsegs, + size_t *ndone) +{ + return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone, + nilfs_sufile_do_cancel_free); +} + +/** * nilfs_sufile_set_error - mark a segment as erroneous * @sufile: inode of segment usage file * @segnum: segment number -- cgit v0.10.2 From 654137dd46bc7e9f088a4a551a2b77a8541dfdb8 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 17 May 2009 19:07:21 +0900 Subject: nilfs2: remove header file for segment list operations This will eliminate obsolete list operations of nilfs_segment_entry structure which has been used to handle mutiple segment numbers. The patch ("nilfs2: remove list of freeing segments") removed use of the structure from the segment constructor code, and this patch simplifies the remaining code by integrating it into recovery.c. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index 57afa9d..d80cc71 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -28,7 +28,6 @@ #include "segment.h" #include "sufile.h" #include "page.h" -#include "seglist.h" #include "segbuf.h" /* @@ -395,6 +394,24 @@ static void dispose_recovery_list(struct list_head *head) } } +struct nilfs_segment_entry { + struct list_head list; + __u64 segnum; +}; + +static int nilfs_segment_list_add(struct list_head *head, __u64 segnum) +{ + struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS); + + if (unlikely(!ent)) + return -ENOMEM; + + ent->segnum = segnum; + INIT_LIST_HEAD(&ent->list); + list_add_tail(&ent->list, head); + return 0; +} + void nilfs_dispose_segment_list(struct list_head *head) { while (!list_empty(head)) { @@ -402,7 +419,7 @@ void nilfs_dispose_segment_list(struct list_head *head) = list_entry(head->next, struct nilfs_segment_entry, list); list_del(&ent->list); - nilfs_free_segment_entry(ent); + kfree(ent); } } @@ -431,12 +448,10 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, if (unlikely(err)) goto failed; - err = -ENOMEM; for (i = 1; i < 4; i++) { - ent = nilfs_alloc_segment_entry(segnum[i]); - if (unlikely(!ent)) + err = nilfs_segment_list_add(head, segnum[i]); + if (unlikely(err)) goto failed; - list_add_tail(&ent->list, head); } /* @@ -450,7 +465,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, goto failed; } list_del(&ent->list); - nilfs_free_segment_entry(ent); + kfree(ent); } /* Allocate new segments for recovery */ @@ -791,7 +806,6 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, u64 seg_seq; __u64 segnum, nextnum = 0; __u64 cno; - struct nilfs_segment_entry *ent; LIST_HEAD(segments); int empty_seg = 0, scan_newer = 0; int ret; @@ -892,12 +906,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, if (empty_seg++) goto super_root_found; /* found a valid super root */ - ent = nilfs_alloc_segment_entry(segnum); - if (unlikely(!ent)) { - ret = -ENOMEM; + ret = nilfs_segment_list_add(&segments, segnum); + if (unlikely(ret)) goto failed; - } - list_add_tail(&ent->list, &segments); seg_seq++; segnum = nextnum; diff --git a/fs/nilfs2/seglist.h b/fs/nilfs2/seglist.h deleted file mode 100644 index e448e40..0000000 --- a/fs/nilfs2/seglist.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * seglist.h - expediential structure and routines to handle list of segments - * (would be removed in a future release) - * - * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Written by Ryusuke Konishi - * - */ -#ifndef _NILFS_SEGLIST_H -#define _NILFS_SEGLIST_H - -#include -#include -#include -#include "sufile.h" - -struct nilfs_segment_entry { - __u64 segnum; - - struct list_head list; - struct buffer_head *bh_su; - struct nilfs_segment_usage *raw_su; -}; - - -void nilfs_dispose_segment_list(struct list_head *); - -static inline struct nilfs_segment_entry * -nilfs_alloc_segment_entry(__u64 segnum) -{ - struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS); - - if (likely(ent)) { - ent->segnum = segnum; - ent->bh_su = NULL; - ent->raw_su = NULL; - INIT_LIST_HEAD(&ent->list); - } - return ent; -} - -static inline int nilfs_open_segment_entry(struct nilfs_segment_entry *ent, - struct inode *sufile) -{ - return nilfs_sufile_get_segment_usage(sufile, ent->segnum, - &ent->raw_su, &ent->bh_su); -} - -static inline void nilfs_close_segment_entry(struct nilfs_segment_entry *ent, - struct inode *sufile) -{ - if (!ent->bh_su) - return; - nilfs_sufile_put_segment_usage(sufile, ent->segnum, ent->bh_su); - ent->bh_su = NULL; - ent->raw_su = NULL; -} - -static inline void nilfs_free_segment_entry(struct nilfs_segment_entry *ent) -{ - kfree(ent); -} - -#endif /* _NILFS_SEGLIST_H */ diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index f36a851..0d2a475 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h @@ -239,5 +239,6 @@ extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *, extern int nilfs_recover_logical_segments(struct the_nilfs *, struct nilfs_sb_info *, struct nilfs_recovery_info *); +extern void nilfs_dispose_segment_list(struct list_head *); #endif /* _NILFS_SEGMENT_H */ diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 7f65b3b..dfe2e32 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -32,7 +32,6 @@ #include "cpfile.h" #include "sufile.h" #include "dat.h" -#include "seglist.h" #include "segbuf.h" void nilfs_set_last_segment(struct the_nilfs *nilfs, -- cgit v0.10.2 From 087d01b4253b611773ca81ad894486e7e17e74f6 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 22 May 2009 00:33:13 +0900 Subject: nilfs2: remove nilfs_bmap_put_block nilfs_bmap_put_block() is a wrapper function calling brelse(). This eliminates the wrapper for simplicity. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 4f2523f..ee9914a 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -424,12 +424,6 @@ int nilfs_bmap_get_block(const struct nilfs_bmap *bmap, __u64 ptr, ptr, 0, bhp, 0); } -void nilfs_bmap_put_block(const struct nilfs_bmap *bmap, - struct buffer_head *bh) -{ - brelse(bh); -} - int nilfs_bmap_get_new_block(const struct nilfs_bmap *bmap, __u64 ptr, struct buffer_head **bhp) { diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index ad251d3..5b580b8 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -204,7 +204,6 @@ void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); int nilfs_bmap_get_block(const struct nilfs_bmap *, __u64, struct buffer_head **); -void nilfs_bmap_put_block(const struct nilfs_bmap *, struct buffer_head *); int nilfs_bmap_get_new_block(const struct nilfs_bmap *, __u64, struct buffer_head **); void nilfs_bmap_delete_block(const struct nilfs_bmap *, struct buffer_head *); diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 959e5a7..102e218 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -109,8 +109,7 @@ static void nilfs_btree_clear_path(const struct nilfs_btree *btree, level < NILFS_BTREE_LEVEL_MAX; level++) { if (path[level].bp_bh != NULL) { - nilfs_bmap_put_block(&btree->bt_bmap, - path[level].bp_bh); + brelse(path[level].bp_bh); path[level].bp_bh = NULL; } /* sib_bh is released or deleted by prepare or commit @@ -669,13 +668,13 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree, nilfs_btree_node_get_key(btree, node, 0)); if (move) { - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); + brelse(path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; path[level].bp_index += lnchildren; path[level + 1].bp_index--; } else { - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); + brelse(path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; path[level].bp_index -= n; } @@ -722,14 +721,14 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree, path[level + 1].bp_index--; if (move) { - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); + brelse(path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; path[level].bp_index -= nilfs_btree_node_get_nchildren(btree, node); path[level + 1].bp_index++; } else { - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); + brelse(path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; } @@ -781,7 +780,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree, *keyp = nilfs_btree_node_get_key(btree, right, 0); *ptrp = path[level].bp_newreq.bpr_ptr; - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); + brelse(path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; } else { @@ -790,7 +789,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree, *keyp = nilfs_btree_node_get_key(btree, right, 0); *ptrp = path[level].bp_newreq.bpr_ptr; - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); + brelse(path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; } @@ -936,7 +935,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, stats->bs_nblocks++; goto out; } else - nilfs_bmap_put_block(&btree->bt_bmap, bh); + brelse(bh); } /* right sibling */ @@ -956,7 +955,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, stats->bs_nblocks++; goto out; } else - nilfs_bmap_put_block(&btree->bt_bmap, bh); + brelse(bh); } /* split */ @@ -1153,7 +1152,7 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree, nilfs_btree_promote_key(btree, path, level + 1, nilfs_btree_node_get_key(btree, node, 0)); - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); + brelse(path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; path[level].bp_index += n; } @@ -1192,7 +1191,7 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree, nilfs_btree_node_get_key(btree, right, 0)); path[level + 1].bp_index--; - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); + brelse(path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; } @@ -1403,7 +1402,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, &btree->bt_bmap, &path[level].bp_oldreq); err_out_child_node: for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { - nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); + brelse(path[level].bp_sib_bh); if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) btree->bt_bmap.b_pops->bpop_abort_end_ptr( &btree->bt_bmap, &path[level].bp_oldreq); @@ -1515,7 +1514,7 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) nextmaxkey = (nchildren > 1) ? nilfs_btree_node_get_key(btree, node, nchildren - 2) : 0; if (bh != NULL) - nilfs_bmap_put_block(bmap, bh); + brelse(bh); return (maxkey == key) && (nextmaxkey < bmap->b_low); } @@ -1563,7 +1562,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, } if (bh != NULL) - nilfs_bmap_put_block(bmap, bh); + brelse(bh); return nitems; } @@ -1661,7 +1660,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_bmap_set_dirty(bmap); unlock_buffer(bh); - nilfs_bmap_put_block(bmap, bh); + brelse(bh); /* create root node at level 2 */ node = nilfs_btree_get_root(btree); @@ -2176,7 +2175,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) if (!buffer_dirty(bh)) nilfs_btnode_mark_dirty(bh); - nilfs_bmap_put_block(&btree->bt_bmap, bh); + brelse(bh); if (!nilfs_bmap_dirty(&btree->bt_bmap)) nilfs_bmap_set_dirty(&btree->bt_bmap); -- cgit v0.10.2 From 9f098900ad34edfe3bcc2498cfa372f588b96c62 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 22 May 2009 00:38:56 +0900 Subject: nilfs2: remove nilfs_bmap_delete_block nilfs_bmap_delete_block() is a wrapper function calling nilfs_btnode_delete(). This removes it for simplicity. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index ee9914a..d7dbedf 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -437,12 +437,6 @@ int nilfs_bmap_get_new_block(const struct nilfs_bmap *bmap, __u64 ptr, return 0; } -void nilfs_bmap_delete_block(const struct nilfs_bmap *bmap, - struct buffer_head *bh) -{ - nilfs_btnode_delete(bh); -} - __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *bmap, const struct buffer_head *bh) { diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 5b580b8..0af3190 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -206,7 +206,6 @@ int nilfs_bmap_get_block(const struct nilfs_bmap *, __u64, struct buffer_head **); int nilfs_bmap_get_new_block(const struct nilfs_bmap *, __u64, struct buffer_head **); -void nilfs_bmap_delete_block(const struct nilfs_bmap *, struct buffer_head *); /* Assume that bmap semaphore is locked. */ diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 102e218..61e70d7 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -1026,7 +1026,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, &path[level].bp_newreq); err_out_child_node: for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { - nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_sib_bh); + nilfs_btnode_delete(path[level].bp_sib_bh); btree->bt_bmap.b_pops->bpop_abort_alloc_ptr( &btree->bt_bmap, &path[level].bp_newreq); @@ -1220,7 +1220,7 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree, unlock_buffer(path[level].bp_bh); unlock_buffer(path[level].bp_sib_bh); - nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_bh); + nilfs_btnode_delete(path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; path[level].bp_index += nilfs_btree_node_get_nchildren(btree, left); @@ -1251,7 +1251,7 @@ static void nilfs_btree_concat_right(struct nilfs_btree *btree, unlock_buffer(path[level].bp_bh); unlock_buffer(path[level].bp_sib_bh); - nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_sib_bh); + nilfs_btnode_delete(path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; path[level + 1].bp_index++; } @@ -1275,7 +1275,7 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree, nilfs_btree_node_move_left(btree, root, child, n); unlock_buffer(path[level].bp_bh); - nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_bh); + nilfs_btnode_delete(path[level].bp_bh); path[level].bp_bh = NULL; } -- cgit v0.10.2 From f198dbb9cf580c09644ebdf46846115c6daff14e Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 22 May 2009 01:07:13 +0900 Subject: nilfs2: move get block functions in bmap.c into btree codes Two get block function for btree nodes, nilfs_bmap_get_block() and nilfs_bmap_get_new_block(), are called only from the btree codes. This relocation will increase opportunities of compiler optimization. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index d7dbedf..cf5c5d2 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -417,26 +417,6 @@ void nilfs_bmap_sub_blocks(const struct nilfs_bmap *bmap, int n) mark_inode_dirty(bmap->b_inode); } -int nilfs_bmap_get_block(const struct nilfs_bmap *bmap, __u64 ptr, - struct buffer_head **bhp) -{ - return nilfs_btnode_get(&NILFS_BMAP_I(bmap)->i_btnode_cache, - ptr, 0, bhp, 0); -} - -int nilfs_bmap_get_new_block(const struct nilfs_bmap *bmap, __u64 ptr, - struct buffer_head **bhp) -{ - int ret; - - ret = nilfs_btnode_get(&NILFS_BMAP_I(bmap)->i_btnode_cache, - ptr, 0, bhp, 1); - if (ret < 0) - return ret; - set_buffer_nilfs_volatile(*bhp); - return 0; -} - __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *bmap, const struct buffer_head *bh) { diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 0af3190..978073b 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -202,12 +202,6 @@ void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); -int nilfs_bmap_get_block(const struct nilfs_bmap *, __u64, - struct buffer_head **); -int nilfs_bmap_get_new_block(const struct nilfs_bmap *, __u64, - struct buffer_head **); - - /* Assume that bmap semaphore is locked. */ static inline int nilfs_bmap_dirty(const struct nilfs_bmap *bmap) { diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 61e70d7..63ee350 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -122,10 +122,29 @@ static void nilfs_btree_clear_path(const struct nilfs_btree *btree, } } - /* * B-tree node operations */ +static int nilfs_btree_get_block(const struct nilfs_btree *btree, __u64 ptr, + struct buffer_head **bhp) +{ + struct address_space *btnc = + &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; + return nilfs_btnode_get(btnc, ptr, 0, bhp, 0); +} + +static int nilfs_btree_get_new_block(const struct nilfs_btree *btree, + __u64 ptr, struct buffer_head **bhp) +{ + struct address_space *btnc = + &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; + int ret; + + ret = nilfs_btnode_get(btnc, ptr, 0, bhp, 1); + if (!ret) + set_buffer_nilfs_volatile(*bhp); + return ret; +} static inline int nilfs_btree_node_get_flags(const struct nilfs_btree *btree, @@ -487,8 +506,7 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, path[level].bp_index = index; for (level--; level >= minlevel; level--) { - ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, - &path[level].bp_bh); + ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); if (ret < 0) return ret; node = nilfs_btree_get_nonroot_node(btree, path, level); @@ -534,8 +552,7 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree, path[level].bp_index = index; for (level--; level > 0; level--) { - ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, - &path[level].bp_bh); + ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); if (ret < 0) return ret; node = nilfs_btree_get_nonroot_node(btree, path, level); @@ -923,8 +940,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, if (pindex > 0) { sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex - 1); - ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, - &bh); + ret = nilfs_btree_get_block(btree, sibptr, &bh); if (ret < 0) goto err_out_child_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -943,8 +959,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, nilfs_btree_node_get_nchildren(btree, parent) - 1) { sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex + 1); - ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, - &bh); + ret = nilfs_btree_get_block(btree, sibptr, &bh); if (ret < 0) goto err_out_child_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -965,9 +980,9 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; - ret = nilfs_bmap_get_new_block(&btree->bt_bmap, - path[level].bp_newreq.bpr_ptr, - &bh); + ret = nilfs_btree_get_new_block(btree, + path[level].bp_newreq.bpr_ptr, + &bh); if (ret < 0) goto err_out_curr_node; @@ -997,8 +1012,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; - ret = nilfs_bmap_get_new_block(&btree->bt_bmap, - path[level].bp_newreq.bpr_ptr, &bh); + ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr, + &bh); if (ret < 0) goto err_out_curr_node; @@ -1320,8 +1335,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, /* left sibling */ sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex - 1); - ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, - &bh); + ret = nilfs_btree_get_block(btree, sibptr, &bh); if (ret < 0) goto err_out_curr_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -1342,8 +1356,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, /* right sibling */ sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex + 1); - ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, - &bh); + ret = nilfs_btree_get_block(btree, sibptr, &bh); if (ret < 0) goto err_out_curr_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -1500,7 +1513,7 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) if (nchildren > 1) return 0; ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); - ret = nilfs_bmap_get_block(bmap, ptr, &bh); + ret = nilfs_btree_get_block(btree, ptr, &bh); if (ret < 0) return ret; node = (struct nilfs_btree_node *)bh->b_data; @@ -1541,7 +1554,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, nchildren = nilfs_btree_node_get_nchildren(btree, root); WARN_ON(nchildren > 1); ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); - ret = nilfs_bmap_get_block(bmap, ptr, &bh); + ret = nilfs_btree_get_block(btree, ptr, &bh); if (ret < 0) return ret; node = (struct nilfs_btree_node *)bh->b_data; @@ -1598,7 +1611,7 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, if (ret < 0) goto err_out_dreq; - ret = nilfs_bmap_get_new_block(bmap, nreq->bpr_ptr, &bh); + ret = nilfs_btree_get_new_block(btree, nreq->bpr_ptr, &bh); if (ret < 0) goto err_out_nreq; @@ -2167,7 +2180,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) WARN_ON(ret == -ENOENT); goto out; } - ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, &bh); + ret = nilfs_btree_get_block(btree, ptr, &bh); if (ret < 0) { WARN_ON(ret == -ENOENT); goto out; -- cgit v0.10.2 From e473c1f265f429427e09531435ceaf0fdbb86d15 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 22 May 2009 02:18:36 +0900 Subject: nilfs2: remove pointless NULL check of bpop_commit_alloc_ptr function This indirect function is set to NULL only for gc cache inodes, but the gc cache inodes never call this function. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 63ee350..5b2606a 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -1067,10 +1067,8 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree, btree->bt_ops->btop_set_target(btree, key, ptr); for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { - if (btree->bt_bmap.b_pops->bpop_commit_alloc_ptr != NULL) { - btree->bt_bmap.b_pops->bpop_commit_alloc_ptr( - &btree->bt_bmap, &path[level - 1].bp_newreq); - } + btree->bt_bmap.b_pops->bpop_commit_alloc_ptr( + &btree->bt_bmap, &path[level - 1].bp_newreq); path[level].bp_op(btree, path, level, &key, &ptr); } @@ -1656,10 +1654,8 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, btree = (struct nilfs_btree *)bmap; nilfs_btree_init(bmap, low, high); if (nreq != NULL) { - if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) { - bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); - bmap->b_pops->bpop_commit_alloc_ptr(bmap, nreq); - } + bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, nreq); /* create child node at level 1 */ lock_buffer(bh); @@ -1681,8 +1677,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT, 2, 1, &keys[0], &tmpptr); } else { - if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) - bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); /* create root node at level 1 */ node = nilfs_btree_get_root(btree); diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 5cbba82..eaeccb0 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -111,9 +111,7 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, bh = (struct buffer_head *)((unsigned long)ptr); set_buffer_nilfs_volatile(bh); - if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL) - direct->d_bmap.b_pops->bpop_commit_alloc_ptr( - &direct->d_bmap, req); + direct->d_bmap.b_pops->bpop_commit_alloc_ptr(&direct->d_bmap, req); nilfs_direct_set_ptr(direct, key, req->bpr_ptr); if (!nilfs_bmap_dirty(&direct->d_bmap)) -- cgit v0.10.2 From 3033342a0b76048e32ce1faebfa85cf8f1aa93b5 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 24 May 2009 00:09:44 +0900 Subject: nilfs2: remove useless b_low and b_high fields from nilfs_bmap struct This will cut off 16 bytes from the nilfs_bmap struct which is embedded in the on-memory inode of nilfs. The b_high field was never used, and the b_low field stores a constant value which can be determined by whether the inode uses btree for block mapping or not. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index cf5c5d2..de67d2a 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -101,8 +101,7 @@ static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) if (n < 0) return n; ret = nilfs_btree_convert_and_insert( - bmap, key, ptr, keys, ptrs, n, - NILFS_BMAP_LARGE_LOW, NILFS_BMAP_LARGE_HIGH); + bmap, key, ptr, keys, ptrs, n); if (ret == 0) bmap->b_u.u_flags |= NILFS_BMAP_LARGE; @@ -158,8 +157,7 @@ static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) if (n < 0) return n; ret = nilfs_direct_delete_and_convert( - bmap, key, keys, ptrs, n, - NILFS_BMAP_SMALL_LOW, NILFS_BMAP_SMALL_HIGH); + bmap, key, keys, ptrs, n); if (ret == 0) bmap->b_u.u_flags &= ~NILFS_BMAP_LARGE; @@ -681,12 +679,7 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode) } return (bmap->b_u.u_flags & NILFS_BMAP_LARGE) ? - nilfs_btree_init(bmap, - NILFS_BMAP_LARGE_LOW, - NILFS_BMAP_LARGE_HIGH) : - nilfs_direct_init(bmap, - NILFS_BMAP_SMALL_LOW, - NILFS_BMAP_SMALL_HIGH); + nilfs_btree_init(bmap) : nilfs_direct_init(bmap); } /** diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 978073b..28c77bb 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -125,8 +125,6 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr) * @b_inode: owner of bmap * @b_ops: bmap operation table * @b_pops: bmap ptr operation table - * @b_low: low watermark of conversion - * @b_high: high watermark of conversion * @b_last_allocated_key: last allocated key for data block * @b_last_allocated_ptr: last allocated ptr for data block * @b_state: state @@ -140,8 +138,6 @@ struct nilfs_bmap { struct inode *b_inode; const struct nilfs_bmap_operations *b_ops; const struct nilfs_bmap_ptr_operations *b_pops; - __u64 b_low; - __u64 b_high; __u64 b_last_allocated_key; __u64 b_last_allocated_ptr; int b_state; diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 5b2606a..f5a0ec6 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -1527,7 +1527,7 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) if (bh != NULL) brelse(bh); - return (maxkey == key) && (nextmaxkey < bmap->b_low); + return (maxkey == key) && (nextmaxkey < NILFS_BMAP_LARGE_LOW); } static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, @@ -1634,7 +1634,7 @@ static void nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr, const __u64 *keys, const __u64 *ptrs, - int n, __u64 low, __u64 high, + int n, union nilfs_bmap_ptr_req *dreq, union nilfs_bmap_ptr_req *nreq, struct buffer_head *bh) @@ -1652,7 +1652,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, /* convert and insert */ btree = (struct nilfs_btree *)bmap; - nilfs_btree_init(bmap, low, high); + nilfs_btree_init(bmap); if (nreq != NULL) { bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); bmap->b_pops->bpop_commit_alloc_ptr(bmap, nreq); @@ -1701,13 +1701,10 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, * @keys: * @ptrs: * @n: - * @low: - * @high: */ int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr, - const __u64 *keys, const __u64 *ptrs, - int n, __u64 low, __u64 high) + const __u64 *keys, const __u64 *ptrs, int n) { struct buffer_head *bh; union nilfs_bmap_ptr_req dreq, nreq, *di, *ni; @@ -1732,7 +1729,7 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap, if (ret < 0) return ret; nilfs_btree_commit_convert_and_insert(bmap, key, ptr, keys, ptrs, n, - low, high, di, ni, bh); + di, ni, bh); nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); return 0; } @@ -2245,14 +2242,11 @@ static const struct nilfs_btree_operations nilfs_btree_ops_p = { .btop_assign = nilfs_btree_assign_p, }; -int nilfs_btree_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) +int nilfs_btree_init(struct nilfs_bmap *bmap) { - struct nilfs_btree *btree; + struct nilfs_btree *btree = (struct nilfs_btree *)bmap; - btree = (struct nilfs_btree *)bmap; bmap->b_ops = &nilfs_btree_ops; - bmap->b_low = low; - bmap->b_high = high; switch (bmap->b_inode->i_ino) { case NILFS_DAT_INO: btree->bt_ops = &nilfs_btree_ops_p; @@ -2267,7 +2261,5 @@ int nilfs_btree_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) void nilfs_btree_init_gc(struct nilfs_bmap *bmap) { - bmap->b_low = NILFS_BMAP_LARGE_LOW; - bmap->b_high = NILFS_BMAP_LARGE_HIGH; bmap->b_ops = &nilfs_btree_ops_gc; } diff --git a/fs/nilfs2/btree.h b/fs/nilfs2/btree.h index 4766deb..48aad2a 100644 --- a/fs/nilfs2/btree.h +++ b/fs/nilfs2/btree.h @@ -108,10 +108,9 @@ struct nilfs_btree { int nilfs_btree_path_cache_init(void); void nilfs_btree_path_cache_destroy(void); -int nilfs_btree_init(struct nilfs_bmap *, __u64, __u64); +int nilfs_btree_init(struct nilfs_bmap *); int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64, - const __u64 *, const __u64 *, - int, __u64, __u64); + const __u64 *, const __u64 *, int); void nilfs_btree_init_gc(struct nilfs_bmap *); #endif /* _NILFS_BTREE_H */ diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index eaeccb0..8e8095c 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -242,8 +242,7 @@ static int nilfs_direct_gather_data(struct nilfs_bmap *bmap, } int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, - __u64 key, __u64 *keys, __u64 *ptrs, - int n, __u64 low, __u64 high) + __u64 key, __u64 *keys, __u64 *ptrs, int n) { struct nilfs_direct *direct; __le64 *dptrs; @@ -273,8 +272,7 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, dptrs[i] = NILFS_BMAP_INVALID_PTR; } - nilfs_direct_init(bmap, low, high); - + nilfs_direct_init(bmap); return 0; } @@ -410,14 +408,11 @@ static const struct nilfs_direct_operations nilfs_direct_ops_p = { .dop_assign = nilfs_direct_assign_p, }; -int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) +int nilfs_direct_init(struct nilfs_bmap *bmap) { - struct nilfs_direct *direct; + struct nilfs_direct *direct = (struct nilfs_direct *)bmap; - direct = (struct nilfs_direct *)bmap; bmap->b_ops = &nilfs_direct_ops; - bmap->b_low = low; - bmap->b_high = high; switch (bmap->b_inode->i_ino) { case NILFS_DAT_INO: direct->d_ops = &nilfs_direct_ops_p; diff --git a/fs/nilfs2/direct.h b/fs/nilfs2/direct.h index 45d2c5c..d645f13 100644 --- a/fs/nilfs2/direct.h +++ b/fs/nilfs2/direct.h @@ -70,9 +70,9 @@ struct nilfs_direct { #define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1) -int nilfs_direct_init(struct nilfs_bmap *, __u64, __u64); +int nilfs_direct_init(struct nilfs_bmap *); int nilfs_direct_delete_and_convert(struct nilfs_bmap *, __u64, __u64 *, - __u64 *, int, __u64, __u64); + __u64 *, int); #endif /* _NILFS_DIRECT_H */ -- cgit v0.10.2 From d4b961576df2769b936bd967b01e8c607c3c9ad8 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 24 May 2009 03:25:44 +0900 Subject: nilfs2: remove bmap pointer operations Previously, the bmap codes of nilfs used three types of function tables. The abuse of indirect function calls decreased source readability and suffered many indirect jumps which would confuse branch prediction of processors. This eliminates one type of the function tables, nilfs_bmap_ptr_operations, which was used to dispatch low level pointer operations of the nilfs bmap. This adds a new integer variable "b_ptr_type" to nilfs_bmap struct, and uses the value to select the pointer operations. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index de67d2a..51824c7 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -31,21 +31,26 @@ #include "dat.h" #include "alloc.h" +static struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) +{ + return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); +} + int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, __u64 *ptrp) { - __u64 ptr; + sector_t blocknr; int ret; down_read(&bmap->b_sem); ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp); if (ret < 0) goto out; - if (bmap->b_pops->bpop_translate != NULL) { - ret = bmap->b_pops->bpop_translate(bmap, *ptrp, &ptr); - if (ret < 0) - goto out; - *ptrp = ptr; + if (NILFS_BMAP_USE_VBN(bmap)) { + ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), *ptrp, + &blocknr); + if (!ret) + *ptrp = blocknr; } out: @@ -442,11 +447,6 @@ __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *bmap, __u64 key) return NILFS_BMAP_INVALID_PTR; } -static struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) -{ - return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); -} - #define NILFS_BMAP_GROUP_DIV 8 __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) { @@ -459,20 +459,20 @@ __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) (entries_per_group / NILFS_BMAP_GROUP_DIV); } -static int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { return nilfs_dat_prepare_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -static void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { nilfs_dat_commit_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -static void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { nilfs_dat_abort_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); } @@ -489,26 +489,21 @@ int nilfs_bmap_start_v(struct nilfs_bmap *bmap, union nilfs_bmap_ptr_req *req, return ret; } -static int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { return nilfs_dat_prepare_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -static void nilfs_bmap_commit_end_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, 0); -} - -static void nilfs_bmap_commit_end_vmdt(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +void nilfs_bmap_commit_end_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { - nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, 1); + nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, + bmap->b_ptr_type == NILFS_BMAP_PTR_VS); } -static void nilfs_bmap_abort_end_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +void nilfs_bmap_abort_end_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { nilfs_dat_abort_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); } @@ -524,116 +519,44 @@ int nilfs_bmap_mark_dirty(const struct nilfs_bmap *bmap, __u64 vblocknr) return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), vblocknr); } -int nilfs_bmap_prepare_update(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *oldreq, - union nilfs_bmap_ptr_req *newreq) +int nilfs_bmap_prepare_update_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *oldreq, + union nilfs_bmap_ptr_req *newreq) { + struct inode *dat = nilfs_bmap_get_dat(bmap); int ret; - ret = bmap->b_pops->bpop_prepare_end_ptr(bmap, oldreq); + ret = nilfs_dat_prepare_end(dat, &oldreq->bpr_req); if (ret < 0) return ret; - ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, newreq); + ret = nilfs_dat_prepare_alloc(dat, &newreq->bpr_req); if (ret < 0) - bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); + nilfs_dat_abort_end(dat, &oldreq->bpr_req); return ret; } -void nilfs_bmap_commit_update(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *oldreq, - union nilfs_bmap_ptr_req *newreq) -{ - bmap->b_pops->bpop_commit_end_ptr(bmap, oldreq); - bmap->b_pops->bpop_commit_alloc_ptr(bmap, newreq); -} - -void nilfs_bmap_abort_update(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *oldreq, - union nilfs_bmap_ptr_req *newreq) -{ - bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); - bmap->b_pops->bpop_abort_alloc_ptr(bmap, newreq); -} - -static int nilfs_bmap_translate_v(const struct nilfs_bmap *bmap, __u64 ptr, - __u64 *ptrp) +void nilfs_bmap_commit_update_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *oldreq, + union nilfs_bmap_ptr_req *newreq) { - sector_t blocknr; - int ret; - - ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), ptr, &blocknr); - if (ret < 0) - return ret; - if (ptrp != NULL) - *ptrp = blocknr; - return 0; -} + struct inode *dat = nilfs_bmap_get_dat(bmap); -static int nilfs_bmap_prepare_alloc_p(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - /* ignore target ptr */ - req->bpr_ptr = bmap->b_last_allocated_ptr++; - return 0; + nilfs_dat_commit_end(dat, &oldreq->bpr_req, + bmap->b_ptr_type == NILFS_BMAP_PTR_VS); + nilfs_dat_commit_alloc(dat, &newreq->bpr_req); } -static void nilfs_bmap_commit_alloc_p(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +void nilfs_bmap_abort_update_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *oldreq, + union nilfs_bmap_ptr_req *newreq) { - /* do nothing */ -} + struct inode *dat = nilfs_bmap_get_dat(bmap); -static void nilfs_bmap_abort_alloc_p(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - bmap->b_last_allocated_ptr--; + nilfs_dat_abort_end(dat, &oldreq->bpr_req); + nilfs_dat_abort_alloc(dat, &newreq->bpr_req); } -static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_v = { - .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, - .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, - .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, - .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, - .bpop_commit_end_ptr = nilfs_bmap_commit_end_v, - .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, - - .bpop_translate = nilfs_bmap_translate_v, -}; - -static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_vmdt = { - .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, - .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, - .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, - .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, - .bpop_commit_end_ptr = nilfs_bmap_commit_end_vmdt, - .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, - - .bpop_translate = nilfs_bmap_translate_v, -}; - -static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_p = { - .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_p, - .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_p, - .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_p, - .bpop_prepare_end_ptr = NULL, - .bpop_commit_end_ptr = NULL, - .bpop_abort_end_ptr = NULL, - - .bpop_translate = NULL, -}; - -static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_gc = { - .bpop_prepare_alloc_ptr = NULL, - .bpop_commit_alloc_ptr = NULL, - .bpop_abort_alloc_ptr = NULL, - .bpop_prepare_end_ptr = NULL, - .bpop_commit_end_ptr = NULL, - .bpop_abort_end_ptr = NULL, - - .bpop_translate = NULL, -}; - static struct lock_class_key nilfs_bmap_dat_lock_key; /** @@ -660,20 +583,20 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode) bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; switch (bmap->b_inode->i_ino) { case NILFS_DAT_INO: - bmap->b_pops = &nilfs_bmap_ptr_ops_p; - bmap->b_last_allocated_key = 0; /* XXX: use macro */ + bmap->b_ptr_type = NILFS_BMAP_PTR_P; + bmap->b_last_allocated_key = 0; bmap->b_last_allocated_ptr = NILFS_BMAP_NEW_PTR_INIT; lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); break; case NILFS_CPFILE_INO: case NILFS_SUFILE_INO: - bmap->b_pops = &nilfs_bmap_ptr_ops_vmdt; - bmap->b_last_allocated_key = 0; /* XXX: use macro */ + bmap->b_ptr_type = NILFS_BMAP_PTR_VS; + bmap->b_last_allocated_key = 0; bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; break; default: - bmap->b_pops = &nilfs_bmap_ptr_ops_v; - bmap->b_last_allocated_key = 0; /* XXX: use macro */ + bmap->b_ptr_type = NILFS_BMAP_PTR_VM; + bmap->b_last_allocated_key = 0; bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; break; } @@ -705,7 +628,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap) memset(&bmap->b_u, 0, NILFS_BMAP_SIZE); init_rwsem(&bmap->b_sem); bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; - bmap->b_pops = &nilfs_bmap_ptr_ops_gc; + bmap->b_ptr_type = NILFS_BMAP_PTR_U; bmap->b_last_allocated_key = 0; bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; bmap->b_state = 0; diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 28c77bb..47f5b74 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -86,27 +86,6 @@ struct nilfs_bmap_operations { }; -/** - * struct nilfs_bmap_ptr_operations - bmap ptr operation table - */ -struct nilfs_bmap_ptr_operations { - int (*bpop_prepare_alloc_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); - void (*bpop_commit_alloc_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); - void (*bpop_abort_alloc_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); - int (*bpop_prepare_end_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); - void (*bpop_commit_end_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); - void (*bpop_abort_end_ptr)(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); - - int (*bpop_translate)(const struct nilfs_bmap *, __u64, __u64 *); -}; - - #define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(__le64)) #define NILFS_BMAP_KEY_BIT (sizeof(unsigned long) * 8 /* CHAR_BIT */) #define NILFS_BMAP_NEW_PTR_INIT \ @@ -124,9 +103,9 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr) * @b_sem: semaphore * @b_inode: owner of bmap * @b_ops: bmap operation table - * @b_pops: bmap ptr operation table * @b_last_allocated_key: last allocated key for data block * @b_last_allocated_ptr: last allocated ptr for data block + * @b_ptr_type: pointer type * @b_state: state */ struct nilfs_bmap { @@ -137,12 +116,22 @@ struct nilfs_bmap { struct rw_semaphore b_sem; struct inode *b_inode; const struct nilfs_bmap_operations *b_ops; - const struct nilfs_bmap_ptr_operations *b_pops; __u64 b_last_allocated_key; __u64 b_last_allocated_ptr; + int b_ptr_type; int b_state; }; +/* pointer type */ +#define NILFS_BMAP_PTR_P 0 /* physical block number (i.e. LBN) */ +#define NILFS_BMAP_PTR_VS 1 /* virtual block number (single + version) */ +#define NILFS_BMAP_PTR_VM 2 /* virtual block number (has multiple + versions) */ +#define NILFS_BMAP_PTR_U (-1) /* never perform pointer operations */ + +#define NILFS_BMAP_USE_VBN(bmap) ((bmap)->b_ptr_type > 0) + /* state */ #define NILFS_BMAP_DIRTY 0x00000001 @@ -171,6 +160,63 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); /* * Internal use only */ +int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); +void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); +void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + +static inline int nilfs_bmap_prepare_alloc_ptr(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + if (NILFS_BMAP_USE_VBN(bmap)) + return nilfs_bmap_prepare_alloc_v(bmap, req); + /* ignore target ptr */ + req->bpr_ptr = bmap->b_last_allocated_ptr++; + return 0; +} + +static inline void nilfs_bmap_commit_alloc_ptr(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + if (NILFS_BMAP_USE_VBN(bmap)) + nilfs_bmap_commit_alloc_v(bmap, req); +} + +static inline void nilfs_bmap_abort_alloc_ptr(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + if (NILFS_BMAP_USE_VBN(bmap)) + nilfs_bmap_abort_alloc_v(bmap, req); + else + bmap->b_last_allocated_ptr--; +} + +int nilfs_bmap_prepare_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); +void nilfs_bmap_commit_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); +void nilfs_bmap_abort_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); + +static inline int nilfs_bmap_prepare_end_ptr(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + return NILFS_BMAP_USE_VBN(bmap) ? + nilfs_bmap_prepare_end_v(bmap, req) : 0; +} + +static inline void nilfs_bmap_commit_end_ptr(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + if (NILFS_BMAP_USE_VBN(bmap)) + nilfs_bmap_commit_end_v(bmap, req); +} + +static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + if (NILFS_BMAP_USE_VBN(bmap)) + nilfs_bmap_abort_end_v(bmap, req); +} int nilfs_bmap_start_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *, sector_t); @@ -184,15 +230,15 @@ __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *, __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64); __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *); -int nilfs_bmap_prepare_update(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *, - union nilfs_bmap_ptr_req *); -void nilfs_bmap_commit_update(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *, - union nilfs_bmap_ptr_req *); -void nilfs_bmap_abort_update(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *, - union nilfs_bmap_ptr_req *); +int nilfs_bmap_prepare_update_v(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *, + union nilfs_bmap_ptr_req *); +void nilfs_bmap_commit_update_v(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *, + union nilfs_bmap_ptr_req *); +void nilfs_bmap_abort_update_v(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *, + union nilfs_bmap_ptr_req *); void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index f5a0ec6..20e3fd0 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -917,8 +917,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, path[level].bp_newreq.bpr_ptr = btree->bt_ops->btop_find_target(btree, path, key); - ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( - &btree->bt_bmap, &path[level].bp_newreq); + ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, + &path[level].bp_newreq); if (ret < 0) goto err_out_data; @@ -976,8 +976,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* split */ path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; - ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( - &btree->bt_bmap, &path[level].bp_newreq); + ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, + &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; ret = nilfs_btree_get_new_block(btree, @@ -1008,8 +1008,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* grow */ path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; - ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( - &btree->bt_bmap, &path[level].bp_newreq); + ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, + &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr, @@ -1037,18 +1037,16 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* error */ err_out_curr_node: - btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, - &path[level].bp_newreq); + nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); err_out_child_node: for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { nilfs_btnode_delete(path[level].bp_sib_bh); - btree->bt_bmap.b_pops->bpop_abort_alloc_ptr( - &btree->bt_bmap, &path[level].bp_newreq); + nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, + &path[level].bp_newreq); } - btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, - &path[level].bp_newreq); + nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); err_out_data: *levelp = level; stats->bs_nblocks = 0; @@ -1067,8 +1065,8 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree, btree->bt_ops->btop_set_target(btree, key, ptr); for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { - btree->bt_bmap.b_pops->bpop_commit_alloc_ptr( - &btree->bt_bmap, &path[level - 1].bp_newreq); + nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap, + &path[level - 1].bp_newreq); path[level].bp_op(btree, path, level, &key, &ptr); } @@ -1312,12 +1310,10 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, path[level].bp_oldreq.bpr_ptr = nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); - if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { - ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( - &btree->bt_bmap, &path[level].bp_oldreq); - if (ret < 0) - goto err_out_child_node; - } + ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, + &path[level].bp_oldreq); + if (ret < 0) + goto err_out_child_node; if (nilfs_btree_node_get_nchildren(btree, node) > nilfs_btree_node_nchildren_min(btree, node)) { @@ -1391,12 +1387,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, node = nilfs_btree_get_root(btree); path[level].bp_oldreq.bpr_ptr = nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); - if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { - ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( - &btree->bt_bmap, &path[level].bp_oldreq); - if (ret < 0) - goto err_out_child_node; - } + + ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, + &path[level].bp_oldreq); + if (ret < 0) + goto err_out_child_node; + /* child of the root node is deleted */ path[level].bp_op = nilfs_btree_do_delete; stats->bs_nblocks++; @@ -1408,15 +1404,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, /* error */ err_out_curr_node: - if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) - btree->bt_bmap.b_pops->bpop_abort_end_ptr( - &btree->bt_bmap, &path[level].bp_oldreq); + nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq); err_out_child_node: for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { brelse(path[level].bp_sib_bh); - if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) - btree->bt_bmap.b_pops->bpop_abort_end_ptr( - &btree->bt_bmap, &path[level].bp_oldreq); + nilfs_bmap_abort_end_ptr(&btree->bt_bmap, + &path[level].bp_oldreq); } *levelp = level; stats->bs_nblocks = 0; @@ -1430,9 +1423,8 @@ static void nilfs_btree_commit_delete(struct nilfs_btree *btree, int level; for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { - if (btree->bt_bmap.b_pops->bpop_commit_end_ptr != NULL) - btree->bt_bmap.b_pops->bpop_commit_end_ptr( - &btree->bt_bmap, &path[level].bp_oldreq); + nilfs_bmap_commit_end_ptr(&btree->bt_bmap, + &path[level].bp_oldreq); path[level].bp_op(btree, path, level, NULL, NULL); } @@ -1597,7 +1589,7 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, if (btree->bt_ops->btop_find_target != NULL) dreq->bpr_ptr = btree->bt_ops->btop_find_target(btree, NULL, key); - ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, dreq); + ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq); if (ret < 0) return ret; @@ -1605,7 +1597,7 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, stats->bs_nblocks++; if (nreq != NULL) { nreq->bpr_ptr = dreq->bpr_ptr + 1; - ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, nreq); + ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq); if (ret < 0) goto err_out_dreq; @@ -1622,9 +1614,9 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, /* error */ err_out_nreq: - bmap->b_pops->bpop_abort_alloc_ptr(bmap, nreq); + nilfs_bmap_abort_alloc_ptr(bmap, nreq); err_out_dreq: - bmap->b_pops->bpop_abort_alloc_ptr(bmap, dreq); + nilfs_bmap_abort_alloc_ptr(bmap, dreq); stats->bs_nblocks = 0; return ret; @@ -1654,8 +1646,8 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, btree = (struct nilfs_btree *)bmap; nilfs_btree_init(bmap); if (nreq != NULL) { - bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); - bmap->b_pops->bpop_commit_alloc_ptr(bmap, nreq); + nilfs_bmap_commit_alloc_ptr(bmap, dreq); + nilfs_bmap_commit_alloc_ptr(bmap, nreq); /* create child node at level 1 */ lock_buffer(bh); @@ -1677,7 +1669,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT, 2, 1, &keys[0], &tmpptr); } else { - bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); + nilfs_bmap_commit_alloc_ptr(bmap, dreq); /* create root node at level 1 */ node = nilfs_btree_get_root(btree); @@ -1758,9 +1750,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, nilfs_btree_node_get_ptr(btree, parent, path[level + 1].bp_index); path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1; - ret = nilfs_bmap_prepare_update(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + ret = nilfs_bmap_prepare_update_v(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); if (ret < 0) return ret; @@ -1772,9 +1764,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, &path[level].bp_ctxt); if (ret < 0) { - nilfs_bmap_abort_update(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + nilfs_bmap_abort_update_v(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); return ret; } } @@ -1788,9 +1780,9 @@ static void nilfs_btree_commit_update_v(struct nilfs_btree *btree, { struct nilfs_btree_node *parent; - nilfs_bmap_commit_update(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + nilfs_bmap_commit_update_v(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); if (buffer_nilfs_node(path[level].bp_bh)) { nilfs_btnode_commit_change_key( @@ -1809,9 +1801,9 @@ static void nilfs_btree_abort_update_v(struct nilfs_btree *btree, struct nilfs_btree_path *path, int level) { - nilfs_bmap_abort_update(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + nilfs_bmap_abort_update_v(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); if (buffer_nilfs_node(path[level].bp_bh)) nilfs_btnode_abort_change_key( &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 8e8095c..2a546c8 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -92,8 +92,7 @@ static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, if (direct->d_ops->dop_find_target != NULL) req->bpr_ptr = direct->d_ops->dop_find_target(direct, key); - ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap, - req); + ret = nilfs_bmap_prepare_alloc_ptr(&direct->d_bmap, req); if (ret < 0) return ret; @@ -111,7 +110,7 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, bh = (struct buffer_head *)((unsigned long)ptr); set_buffer_nilfs_volatile(bh); - direct->d_bmap.b_pops->bpop_commit_alloc_ptr(&direct->d_bmap, req); + nilfs_bmap_commit_alloc_ptr(&direct->d_bmap, req); nilfs_direct_set_ptr(direct, key, req->bpr_ptr); if (!nilfs_bmap_dirty(&direct->d_bmap)) @@ -150,25 +149,18 @@ static int nilfs_direct_prepare_delete(struct nilfs_direct *direct, { int ret; - if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) { - req->bpr_ptr = nilfs_direct_get_ptr(direct, key); - ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr( - &direct->d_bmap, req); - if (ret < 0) - return ret; - } - - stats->bs_nblocks = 1; - return 0; + req->bpr_ptr = nilfs_direct_get_ptr(direct, key); + ret = nilfs_bmap_prepare_end_ptr(&direct->d_bmap, req); + if (!ret) + stats->bs_nblocks = 1; + return ret; } static void nilfs_direct_commit_delete(struct nilfs_direct *direct, union nilfs_bmap_ptr_req *req, __u64 key) { - if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL) - direct->d_bmap.b_pops->bpop_commit_end_ptr( - &direct->d_bmap, req); + nilfs_bmap_commit_end_ptr(&direct->d_bmap, req); nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); } @@ -289,11 +281,11 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, if (!buffer_nilfs_volatile(bh)) { oldreq.bpr_ptr = ptr; newreq.bpr_ptr = ptr; - ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq, - &newreq); + ret = nilfs_bmap_prepare_update_v(&direct->d_bmap, &oldreq, + &newreq); if (ret < 0) return ret; - nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq); + nilfs_bmap_commit_update_v(&direct->d_bmap, &oldreq, &newreq); set_buffer_nilfs_volatile(bh); nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr); } else -- cgit v0.10.2 From 355c6b61034a571565dcd28801588671255d2329 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 24 May 2009 16:46:37 +0900 Subject: nilfs2: remove nilfs_direct_operations from direct mapping will remove indirect function calls using nilfs_direct_operations table. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 2a546c8..33467ad 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -90,8 +90,8 @@ static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, { int ret; - if (direct->d_ops->dop_find_target != NULL) - req->bpr_ptr = direct->d_ops->dop_find_target(direct, key); + if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) + req->bpr_ptr = nilfs_direct_find_target_v(direct, key); ret = nilfs_bmap_prepare_alloc_ptr(&direct->d_bmap, req); if (ret < 0) return ret; @@ -116,8 +116,8 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, if (!nilfs_bmap_dirty(&direct->d_bmap)) nilfs_bmap_set_dirty(&direct->d_bmap); - if (direct->d_ops->dop_set_target != NULL) - direct->d_ops->dop_set_target(direct, key, req->bpr_ptr); + if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) + nilfs_direct_set_target_v(direct, key, req->bpr_ptr); } static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) @@ -297,12 +297,10 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, struct buffer_head *bh) { - struct nilfs_direct *direct; + struct nilfs_direct *direct = (struct nilfs_direct *)bmap; - direct = (struct nilfs_direct *)bmap; - return (direct->d_ops->dop_propagate != NULL) ? - direct->d_ops->dop_propagate(direct, bh) : - 0; + return NILFS_BMAP_USE_VBN(bmap) ? + nilfs_direct_propagate_v(direct, bh) : 0; } static int nilfs_direct_assign_v(struct nilfs_direct *direct, @@ -362,8 +360,9 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap, return -EINVAL; } - return direct->d_ops->dop_assign(direct, key, ptr, bh, - blocknr, binfo); + return NILFS_BMAP_USE_VBN(bmap) ? + nilfs_direct_assign_v(direct, key, ptr, bh, blocknr, binfo) : + nilfs_direct_assign_p(direct, key, ptr, bh, blocknr, binfo); } static const struct nilfs_bmap_operations nilfs_direct_ops = { @@ -386,33 +385,8 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = { }; -static const struct nilfs_direct_operations nilfs_direct_ops_v = { - .dop_find_target = nilfs_direct_find_target_v, - .dop_set_target = nilfs_direct_set_target_v, - .dop_propagate = nilfs_direct_propagate_v, - .dop_assign = nilfs_direct_assign_v, -}; - -static const struct nilfs_direct_operations nilfs_direct_ops_p = { - .dop_find_target = NULL, - .dop_set_target = NULL, - .dop_propagate = NULL, - .dop_assign = nilfs_direct_assign_p, -}; - int nilfs_direct_init(struct nilfs_bmap *bmap) { - struct nilfs_direct *direct = (struct nilfs_direct *)bmap; - bmap->b_ops = &nilfs_direct_ops; - switch (bmap->b_inode->i_ino) { - case NILFS_DAT_INO: - direct->d_ops = &nilfs_direct_ops_p; - break; - default: - direct->d_ops = &nilfs_direct_ops_v; - break; - } - return 0; } diff --git a/fs/nilfs2/direct.h b/fs/nilfs2/direct.h index d645f13..a5ffd66 100644 --- a/fs/nilfs2/direct.h +++ b/fs/nilfs2/direct.h @@ -31,18 +31,6 @@ struct nilfs_direct; /** - * struct nilfs_direct_operations - direct mapping operation table - */ -struct nilfs_direct_operations { - __u64 (*dop_find_target)(const struct nilfs_direct *, __u64); - void (*dop_set_target)(struct nilfs_direct *, __u64, __u64); - int (*dop_propagate)(struct nilfs_direct *, struct buffer_head *); - int (*dop_assign)(struct nilfs_direct *, __u64, __u64, - struct buffer_head **, sector_t, - union nilfs_binfo *); -}; - -/** * struct nilfs_direct_node - direct node * @dn_flags: flags * @dn_pad: padding @@ -55,13 +43,9 @@ struct nilfs_direct_node { /** * struct nilfs_direct - direct mapping * @d_bmap: bmap structure - * @d_ops: direct mapping operation table */ struct nilfs_direct { struct nilfs_bmap d_bmap; - - /* direct-mapping-specific members */ - const struct nilfs_direct_operations *d_ops; }; -- cgit v0.10.2 From 7cde31d7d6959b2c608aa6b200eb68892d3a6063 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 24 May 2009 18:07:59 +0900 Subject: nilfs2: remove nilfs_btree_operations from btree mapping will remove indirect function calls using nilfs_btree_operations table. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 20e3fd0..24395e6 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -913,9 +913,9 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, level = NILFS_BTREE_LEVEL_DATA; /* allocate a new ptr for data block */ - if (btree->bt_ops->btop_find_target != NULL) + if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) path[level].bp_newreq.bpr_ptr = - btree->bt_ops->btop_find_target(btree, path, key); + nilfs_btree_find_target_v(btree, path, key); ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); @@ -1061,8 +1061,8 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree, set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr; - if (btree->bt_ops->btop_set_target != NULL) - btree->bt_ops->btop_set_target(btree, key, ptr); + if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) + nilfs_btree_set_target_v(btree, key, ptr); for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap, @@ -1586,9 +1586,9 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, /* for data */ /* cannot find near ptr */ - if (btree->bt_ops->btop_find_target != NULL) - dreq->bpr_ptr - = btree->bt_ops->btop_find_target(btree, NULL, key); + if (NILFS_BMAP_USE_VBN(bmap)) + dreq->bpr_ptr = nilfs_btree_find_target_v(btree, NULL, key); + ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq); if (ret < 0) return ret; @@ -1681,8 +1681,8 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_bmap_set_dirty(bmap); } - if (btree->bt_ops->btop_set_target != NULL) - btree->bt_ops->btop_set_target(btree, key, dreq->bpr_ptr); + if (NILFS_BMAP_USE_VBN(bmap)) + nilfs_btree_set_target_v(btree, key, dreq->bpr_ptr); } /** @@ -1926,7 +1926,9 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, goto out; } - ret = btree->bt_ops->btop_propagate(btree, path, level, bh); + ret = NILFS_BMAP_USE_VBN(bmap) ? + nilfs_btree_propagate_v(btree, path, level, bh) : + nilfs_btree_propagate_p(btree, path, level, bh); out: nilfs_btree_clear_path(btree, path); @@ -2107,8 +2109,9 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap, goto out; } - ret = btree->bt_ops->btop_assign(btree, path, level, bh, - blocknr, binfo); + ret = NILFS_BMAP_USE_VBN(bmap) ? + nilfs_btree_assign_v(btree, path, level, bh, blocknr, binfo) : + nilfs_btree_assign_p(btree, path, level, bh, blocknr, binfo); out: nilfs_btree_clear_path(btree, path); @@ -2220,34 +2223,9 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { .bop_gather_data = NULL, }; -static const struct nilfs_btree_operations nilfs_btree_ops_v = { - .btop_find_target = nilfs_btree_find_target_v, - .btop_set_target = nilfs_btree_set_target_v, - .btop_propagate = nilfs_btree_propagate_v, - .btop_assign = nilfs_btree_assign_v, -}; - -static const struct nilfs_btree_operations nilfs_btree_ops_p = { - .btop_find_target = NULL, - .btop_set_target = NULL, - .btop_propagate = nilfs_btree_propagate_p, - .btop_assign = nilfs_btree_assign_p, -}; - int nilfs_btree_init(struct nilfs_bmap *bmap) { - struct nilfs_btree *btree = (struct nilfs_btree *)bmap; - bmap->b_ops = &nilfs_btree_ops; - switch (bmap->b_inode->i_ino) { - case NILFS_DAT_INO: - btree->bt_ops = &nilfs_btree_ops_p; - break; - default: - btree->bt_ops = &nilfs_btree_ops_v; - break; - } - return 0; } diff --git a/fs/nilfs2/btree.h b/fs/nilfs2/btree.h index 48aad2a..0e72bbb 100644 --- a/fs/nilfs2/btree.h +++ b/fs/nilfs2/btree.h @@ -34,28 +34,6 @@ struct nilfs_btree; struct nilfs_btree_path; /** - * struct nilfs_btree_operations - B-tree operation table - */ -struct nilfs_btree_operations { - __u64 (*btop_find_target)(const struct nilfs_btree *, - const struct nilfs_btree_path *, __u64); - void (*btop_set_target)(struct nilfs_btree *, __u64, __u64); - - struct the_nilfs *(*btop_get_nilfs)(struct nilfs_btree *); - - int (*btop_propagate)(struct nilfs_btree *, - struct nilfs_btree_path *, - int, - struct buffer_head *); - int (*btop_assign)(struct nilfs_btree *, - struct nilfs_btree_path *, - int, - struct buffer_head **, - sector_t, - union nilfs_binfo *); -}; - -/** * struct nilfs_btree_node - B-tree node * @bn_flags: flags * @bn_level: level @@ -80,13 +58,9 @@ struct nilfs_btree_node { /** * struct nilfs_btree - B-tree structure * @bt_bmap: bmap base structure - * @bt_ops: B-tree operation table */ struct nilfs_btree { struct nilfs_bmap bt_bmap; - - /* B-tree-specific members */ - const struct nilfs_btree_operations *bt_ops; }; -- cgit v0.10.2 From 258ef67e246fd548e7ad91c23004ad157c03cce5 Mon Sep 17 00:00:00 2001 From: Hisashi Hifumi Date: Wed, 13 May 2009 11:19:40 +0900 Subject: NILFS2: Pagecache usage optimization on NILFS2 Hi, I introduced "is_partially_uptodate" aops for NILFS2. A page can have multiple buffers and even if a page is not uptodate, some buffers can be uptodate on pagesize != blocksize environment. This aops checks that all buffers which correspond to a part of a file that we want to read are uptodate. If so, we do not have to issue actual read IO to HDD even if a page is not uptodate because the portion we want to read are uptodate. "block_is_partially_uptodate" function is already used by ext2/3/4. With the following patch random read/write mixed workloads or random read after random write workloads can be optimized and we can get performance improvement. I did a performance test using the sysbench. 1 --file-block-size=8K --file-total-size=2G --file-test-mode=rndrw --file-fsync-freq=0 --fil e-rw-ratio=1 run -2.6.30-rc5 Test execution summary: total time: 151.2907s total number of events: 200000 total time taken by event execution: 2409.8387 per-request statistics: min: 0.0000s avg: 0.0120s max: 0.9306s approx. 95 percentile: 0.0439s Threads fairness: events (avg/stddev): 12500.0000/238.52 execution time (avg/stddev): 150.6149/0.01 -2.6.30-rc5-patched Test execution summary: total time: 140.8828s total number of events: 200000 total time taken by event execution: 2240.8577 per-request statistics: min: 0.0000s avg: 0.0112s max: 0.8750s approx. 95 percentile: 0.0418s Threads fairness: events (avg/stddev): 12500.0000/218.43 execution time (avg/stddev): 140.0536/0.01 arch: ia64 pagesize: 16k Thanks. Signed-off-by: Hisashi Hifumi Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 49ab4a4..3f70eed 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -249,6 +249,7 @@ struct address_space_operations nilfs_aops = { /* .releasepage = nilfs_releasepage, */ .invalidatepage = block_invalidatepage, .direct_IO = nilfs_direct_IO, + .is_partially_uptodate = block_is_partially_uptodate, }; struct inode *nilfs_new_inode(struct inode *dir, int mode) -- cgit v0.10.2 From 003ff182fddde09ddfb8d079bbdb02f9d2122082 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Tue, 12 May 2009 03:58:47 +0900 Subject: nilfs2: allow future expansion of metadata read out via get info ioctl Nilfs has some ioctl commands to read out metadata from meta data files: - NILFS_IOCTL_GET_CPINFO for checkpoint file, - NILFS_IOCTL_GET_SUINFO for segment usage file, and - NILFS_IOCTL_GET_VINFO for Disk Address Transalation (DAT) file, respectively. Every routine on these metadata files is implemented so that it allows future expansion of on-disk format. But, the above ioctl commands do not support expansion even though nilfs_argv structure can handle arbitrary size for data exchanged via ioctl. This allows future expansion of the following structures which give basic format of the "get information" ioctls: - struct nilfs_cpinfo - struct nilfs_suinfo - struct nilfs_vinfo So, this introduces forward compatility of such ioctl commands. In this patch, a sanity check in nilfs_ioctl_get_info() function is changed to accept larger data structure [1], and metadata read routines are rewritten so that they become compatible for larger structures; the routines will just ignore the remaining fields which the current version of nilfs doesn't know. [1] The ioctl function already has another upper limit (PAGE_SIZE against a structure, which appears in nilfs_ioctl_wrap_copy function), and this will not cause security problem. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 300f1cd..b5a8cd6 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -384,9 +384,10 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, } static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, - struct nilfs_cpinfo *ci, size_t nci) + void *buf, unsigned cisz, size_t nci) { struct nilfs_checkpoint *cp; + struct nilfs_cpinfo *ci = buf; struct buffer_head *bh; size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; @@ -410,17 +411,22 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, kaddr = kmap_atomic(bh->b_page, KM_USER0); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { - if (!nilfs_checkpoint_invalid(cp)) - nilfs_cpfile_checkpoint_to_cpinfo( - cpfile, cp, &ci[n++]); + if (!nilfs_checkpoint_invalid(cp)) { + nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, + ci); + ci = (void *)ci + cisz; + n++; + } } kunmap_atomic(kaddr, KM_USER0); brelse(bh); } ret = n; - if (n > 0) - *cnop = ci[n - 1].ci_cno + 1; + if (n > 0) { + ci = (void *)ci - cisz; + *cnop = ci->ci_cno + 1; + } out: up_read(&NILFS_MDT(cpfile)->mi_sem); @@ -428,11 +434,12 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, } static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, - struct nilfs_cpinfo *ci, size_t nci) + void *buf, unsigned cisz, size_t nci) { struct buffer_head *bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; + struct nilfs_cpinfo *ci = buf; __u64 curr = *cnop, next; unsigned long curr_blkoff, next_blkoff; void *kaddr; @@ -472,7 +479,9 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, if (unlikely(nilfs_checkpoint_invalid(cp) || !nilfs_checkpoint_snapshot(cp))) break; - nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n++]); + nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci); + ci = (void *)ci + cisz; + n++; next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); if (next == 0) break; /* reach end of the snapshot list */ @@ -511,13 +520,13 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, */ ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, - struct nilfs_cpinfo *ci, size_t nci) + void *buf, unsigned cisz, size_t nci) { switch (mode) { case NILFS_CHECKPOINT: - return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci); + return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci); case NILFS_SNAPSHOT: - return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); + return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci); default: return -EINVAL; } @@ -535,7 +544,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) ssize_t nci; int ret; - nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1); + nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1); if (nci < 0) return nci; else if (nci == 0 || ci.ci_cno != cno) diff --git a/fs/nilfs2/cpfile.h b/fs/nilfs2/cpfile.h index 1a8a100..788a459 100644 --- a/fs/nilfs2/cpfile.h +++ b/fs/nilfs2/cpfile.h @@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64); int nilfs_cpfile_change_cpmode(struct inode *, __u64, int); int nilfs_cpfile_is_snapshot(struct inode *, __u64); int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); -ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, - struct nilfs_cpinfo *, size_t); +ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, void *, unsigned, + size_t); #endif /* _NILFS_CPFILE_H */ diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 1827f62..0b2710e 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -376,36 +376,37 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) return ret; } -ssize_t nilfs_dat_get_vinfo(struct inode *dat, struct nilfs_vinfo *vinfo, +ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz, size_t nvi) { struct buffer_head *entry_bh; struct nilfs_dat_entry *entry; + struct nilfs_vinfo *vinfo = buf; __u64 first, last; void *kaddr; unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block; int i, j, n, ret; for (i = 0; i < nvi; i += n) { - ret = nilfs_palloc_get_entry_block(dat, vinfo[i].vi_vblocknr, + ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr, 0, &entry_bh); if (ret < 0) return ret; kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); /* last virtual block number in this block */ - first = vinfo[i].vi_vblocknr; + first = vinfo->vi_vblocknr; do_div(first, entries_per_block); first *= entries_per_block; last = first + entries_per_block - 1; for (j = i, n = 0; - j < nvi && vinfo[j].vi_vblocknr >= first && - vinfo[j].vi_vblocknr <= last; - j++, n++) { + j < nvi && vinfo->vi_vblocknr >= first && + vinfo->vi_vblocknr <= last; + j++, n++, vinfo = (void *)vinfo + visz) { entry = nilfs_palloc_block_get_entry( - dat, vinfo[j].vi_vblocknr, entry_bh, kaddr); - vinfo[j].vi_start = le64_to_cpu(entry->de_start); - vinfo[j].vi_end = le64_to_cpu(entry->de_end); - vinfo[j].vi_blocknr = le64_to_cpu(entry->de_blocknr); + dat, vinfo->vi_vblocknr, entry_bh, kaddr); + vinfo->vi_start = le64_to_cpu(entry->de_start); + vinfo->vi_end = le64_to_cpu(entry->de_end); + vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr); } kunmap_atomic(kaddr, KM_USER0); brelse(entry_bh); diff --git a/fs/nilfs2/dat.h b/fs/nilfs2/dat.h index d956065..d328b81 100644 --- a/fs/nilfs2/dat.h +++ b/fs/nilfs2/dat.h @@ -47,6 +47,6 @@ void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *); int nilfs_dat_mark_dirty(struct inode *, __u64); int nilfs_dat_freev(struct inode *, __u64 *, size_t); int nilfs_dat_move(struct inode *, __u64, sector_t); -ssize_t nilfs_dat_get_vinfo(struct inode *, struct nilfs_vinfo *, size_t); +ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t); #endif /* _NILFS_DAT_H */ diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index bdad7e4..6ea5f87 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -152,7 +152,7 @@ nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, down_read(&nilfs->ns_segctor_sem); ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, - nmembs); + size, nmembs); up_read(&nilfs->ns_segctor_sem); return ret; } @@ -182,7 +182,8 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, int ret; down_read(&nilfs->ns_segctor_sem); - ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs); + ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size, + nmembs); up_read(&nilfs->ns_segctor_sem); return ret; } @@ -212,7 +213,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, int ret; down_read(&nilfs->ns_segctor_sem); - ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); + ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs); up_read(&nilfs->ns_segctor_sem); return ret; } @@ -589,7 +590,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, if (copy_from_user(&argv, argp, sizeof(argv))) return -EFAULT; - if (argv.v_size != membsz) + if (argv.v_size < membsz) return -EINVAL; ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index da12732..37994d4 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c @@ -587,7 +587,8 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, * nilfs_sufile_get_suinfo - * @sufile: inode of segment usage file * @segnum: segment number to start looking - * @si: array of suinfo + * @buf: array of suinfo + * @sisz: byte size of suinfo * @nsi: size of suinfo array * * Description: @@ -599,11 +600,12 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, * * %-ENOMEM - Insufficient amount of memory available. */ -ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, - struct nilfs_suinfo *si, size_t nsi) +ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, + unsigned sisz, size_t nsi) { struct buffer_head *su_bh; struct nilfs_segment_usage *su; + struct nilfs_suinfo *si = buf; size_t susz = NILFS_MDT(sufile)->mi_entry_size; struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; void *kaddr; @@ -628,20 +630,22 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, if (ret != -ENOENT) goto out; /* hole */ - memset(&si[i], 0, sizeof(struct nilfs_suinfo) * n); + memset(si, 0, sisz * n); + si = (void *)si + sisz * n; continue; } kaddr = kmap_atomic(su_bh->b_page, KM_USER0); su = nilfs_sufile_block_get_segment_usage( sufile, segnum, su_bh, kaddr); - for (j = 0; j < n; j++, su = (void *)su + susz) { - si[i + j].sui_lastmod = le64_to_cpu(su->su_lastmod); - si[i + j].sui_nblocks = le32_to_cpu(su->su_nblocks); - si[i + j].sui_flags = le32_to_cpu(su->su_flags) & + for (j = 0; j < n; + j++, su = (void *)su + susz, si = (void *)si + sisz) { + si->sui_lastmod = le64_to_cpu(su->su_lastmod); + si->sui_nblocks = le32_to_cpu(su->su_nblocks); + si->sui_flags = le32_to_cpu(su->su_flags) & ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE); if (nilfs_segment_is_active(nilfs, segnum + j)) - si[i + j].sui_flags |= + si->sui_flags |= (1UL << NILFS_SEGMENT_USAGE_ACTIVE); } kunmap_atomic(kaddr, KM_USER0); diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index fd6232e..a2c4d76 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h @@ -43,7 +43,7 @@ void nilfs_sufile_put_segment_usage(struct inode *, __u64, struct buffer_head *); int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *); int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *); -ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, struct nilfs_suinfo *, +ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned, size_t); int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *, -- cgit v0.10.2 From 30bda0b8ae470997dc681d6fd82108bac5caebf8 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 17 May 2009 10:57:43 +0900 Subject: nilfs2: set bio unplug flag for the last bio in segment This sets BIO_RW_UNPLUG flag on the last bio of each segment during write. The last bio should be unplugged immediately because the caller waits for the completion after the submission. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index dc0277a..9e3fe17 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -393,7 +393,7 @@ int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, * Last BIO is always sent through the following * submission. */ - rw |= (1 << BIO_RW_SYNCIO); + rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); res = nilfs_submit_seg_bio(wi, rw); if (unlikely(res)) goto failed_bio; -- cgit v0.10.2 From e85dc1d5295779d2e6d973b7ed524d6bd3825a3f Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 27 May 2009 07:27:12 +0900 Subject: nilfs2: enable sync_page method This adds a missing sync_page method which unplugs bio requests when waiting for page locks. This will improve read performance of nilfs. Here is a measurement result using dd command. Without this patch: # mount -t nilfs2 /dev/sde1 /test # dd if=/test/aaa of=/dev/null bs=512k 1024+0 records in 1024+0 records out 536870912 bytes (537 MB) copied, 6.00688 seconds, 89.4 MB/s With this patch: # mount -t nilfs2 /dev/sde1 /test # dd if=/test/aaa of=/dev/null bs=512k 1024+0 records in 1024+0 records out 536870912 bytes (537 MB) copied, 3.54998 seconds, 151 MB/s Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 3f70eed..f25fd4b 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -240,7 +240,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, struct address_space_operations nilfs_aops = { .writepage = nilfs_writepage, .readpage = nilfs_readpage, - /* .sync_page = nilfs_sync_page, */ + .sync_page = block_sync_page, .writepages = nilfs_writepages, .set_page_dirty = nilfs_set_page_dirty, .readpages = nilfs_readpages, -- cgit v0.10.2 From fb6e7113ae3ba6c7d0de77c6ccbcfa659899ff0f Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 30 May 2009 11:27:17 +0900 Subject: nilfs2: modify list of unsupported features in caveats This clarifies missing features of nilfs as a regular filesystem. Signed-off-by: Ryusuke Konishi diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt index 55c4300..01539f4 100644 --- a/Documentation/filesystems/nilfs2.txt +++ b/Documentation/filesystems/nilfs2.txt @@ -39,9 +39,8 @@ Features which NILFS2 does not support yet: - extended attributes - POSIX ACLs - quotas - - writable snapshots - - remote backup (CDP) - - data integrity + - fsck + - resize - defragmentation Mount options -- cgit v0.10.2 From 30c25be71fcbd87fd33518045cc014e69bff3d6f Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 30 May 2009 19:08:09 +0900 Subject: nilfs2: return EBUSY against delete request on snapshot This helps userland programs like the rmcp command to distinguish error codes returned against a checkpoint removal request. Previously -EPERM was returned, and not discriminable from real permission errors. This also allows removal of the latest checkpoint because the deletion leads to create a new checkpoint, and thus it's harmless for the filesystem. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index b5a8cd6..4184c1c 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -295,10 +295,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, return -EINVAL; } - /* cannot delete the latest checkpoint */ - if (start == nilfs_mdt_cno(cpfile) - 1) - return -EPERM; - down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); @@ -542,20 +538,14 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) struct nilfs_cpinfo ci; __u64 tcno = cno; ssize_t nci; - int ret; nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1); if (nci < 0) return nci; else if (nci == 0 || ci.ci_cno != cno) return -ENOENT; - - /* cannot delete the latest checkpoint nor snapshots */ - ret = nilfs_cpinfo_snapshot(&ci); - if (ret < 0) - return ret; - else if (ret > 0 || cno == nilfs_mdt_cno(cpfile) - 1) - return -EPERM; + else if (nilfs_cpinfo_snapshot(&ci)) + return -EBUSY; return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); } -- cgit v0.10.2 From a53b4751ae92adb372017222887f3ec625cba60b Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 27 May 2009 22:11:46 +0900 Subject: nilfs2: use device's backing_dev_info for btree node caches Previously, default_backing_dev_info was used for the mapping of btree node caches. This uses device dependent backing_dev_info to allow detailed control of the device for the btree node pages. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index 4cc07b2..0e01957 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c @@ -48,13 +48,14 @@ void nilfs_btnode_cache_init_once(struct address_space *btnc) static struct address_space_operations def_btnode_aops; -void nilfs_btnode_cache_init(struct address_space *btnc) +void nilfs_btnode_cache_init(struct address_space *btnc, + struct backing_dev_info *bdi) { btnc->host = NULL; /* can safely set to host inode ? */ btnc->flags = 0; mapping_set_gfp_mask(btnc, GFP_NOFS); btnc->assoc_mapping = NULL; - btnc->backing_dev_info = &default_backing_dev_info; + btnc->backing_dev_info = bdi; btnc->a_ops = &def_btnode_aops; } diff --git a/fs/nilfs2/btnode.h b/fs/nilfs2/btnode.h index 35faa86..3e22751 100644 --- a/fs/nilfs2/btnode.h +++ b/fs/nilfs2/btnode.h @@ -38,7 +38,7 @@ struct nilfs_btnode_chkey_ctxt { }; void nilfs_btnode_cache_init_once(struct address_space *); -void nilfs_btnode_cache_init(struct address_space *); +void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *); void nilfs_btnode_cache_clear(struct address_space *); int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, struct buffer_head **, int); diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index bb78745..7b7032e 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -449,7 +449,7 @@ struct inode * nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, ino_t ino, gfp_t gfp_mask) { - struct inode *inode = nilfs_alloc_inode(sb); + struct inode *inode = nilfs_alloc_inode_common(nilfs); if (!inode) return NULL; diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index da6fc0b..edf6a59 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -263,6 +263,7 @@ extern void nilfs_dirty_inode(struct inode *); extern struct dentry *nilfs_get_parent(struct dentry *); /* super.c */ +extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); extern struct inode *nilfs_alloc_inode(struct super_block *); extern void nilfs_destroy_inode(struct inode *); extern void nilfs_error(struct super_block *, const char *, const char *, ...) diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 6989b03..9acf30b 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -134,7 +134,7 @@ void nilfs_warning(struct super_block *sb, const char *function, static struct kmem_cache *nilfs_inode_cachep; -struct inode *nilfs_alloc_inode(struct super_block *sb) +struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) { struct nilfs_inode_info *ii; @@ -144,10 +144,15 @@ struct inode *nilfs_alloc_inode(struct super_block *sb) ii->i_bh = NULL; ii->i_state = 0; ii->vfs_inode.i_version = 1; - nilfs_btnode_cache_init(&ii->i_btnode_cache); + nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi); return &ii->vfs_inode; } +struct inode *nilfs_alloc_inode(struct super_block *sb) +{ + return nilfs_alloc_inode_common(NILFS_SB(sb)->s_nilfs); +} + void nilfs_destroy_inode(struct inode *inode) { kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); -- cgit v0.10.2 From fa032744ad41de1b0a1807e7c379c6196e72ad80 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 27 May 2009 22:44:34 +0900 Subject: nilfs2: add sync_page method to page caches of meta data This applies block_sync_page() function to the sync_page method of page caches for meta data files, gc page caches, and btree node buffers. This is a companion patch of ("nilfs2: enable sync_page mothod") which applied the function for data pages. This allows lock_page() for those meta data to unplug pending bio requests. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index 0e01957..7e0b61b 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c @@ -46,7 +46,9 @@ void nilfs_btnode_cache_init_once(struct address_space *btnc) INIT_LIST_HEAD(&btnc->i_mmap_nonlinear); } -static struct address_space_operations def_btnode_aops; +static struct address_space_operations def_btnode_aops = { + .sync_page = block_sync_page, +}; void nilfs_btnode_cache_init(struct address_space *btnc, struct backing_dev_info *bdi) diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 19d2102..1b3c2bb 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c @@ -52,8 +52,9 @@ #include "dat.h" #include "ifile.h" -static struct address_space_operations def_gcinode_aops = {}; -/* XXX need def_gcinode_iops/fops? */ +static struct address_space_operations def_gcinode_aops = { + .sync_page = block_sync_page, +}; /* * nilfs_gccache_submit_read_data() - add data buffer and submit read request diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 7b7032e..3d3ddb3 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -430,6 +430,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) static struct address_space_operations def_mdt_aops = { .writepage = nilfs_mdt_write_page, + .sync_page = block_sync_page, }; static struct inode_operations def_mdt_iops; -- cgit v0.10.2 From c3a7abf06ce719a51139e62a034590be99abbc2c Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 25 May 2009 02:47:14 +0900 Subject: nilfs2: support contiguous lookup of blocks Although get_block() callback function can return extent of contiguous blocks with bh->b_size, nilfs_get_block() function did not support this feature. This adds contiguous lookup feature to the block mapping codes of nilfs, and allows the nilfs_get_blocks() function to return the extent information by applying the feature. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 51824c7..36df60b 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -31,7 +31,7 @@ #include "dat.h" #include "alloc.h" -static struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) +struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) { return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); } @@ -58,6 +58,16 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, return ret; } +int nilfs_bmap_lookup_contig(struct nilfs_bmap *bmap, __u64 key, __u64 *ptrp, + unsigned maxblocks) +{ + int ret; + + down_read(&bmap->b_sem); + ret = bmap->b_ops->bop_lookup_contig(bmap, key, ptrp, maxblocks); + up_read(&bmap->b_sem); + return ret; +} /** * nilfs_bmap_lookup - find a record diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 47f5b74..b2890cd 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -64,6 +64,8 @@ struct nilfs_bmap_stats { */ struct nilfs_bmap_operations { int (*bop_lookup)(const struct nilfs_bmap *, __u64, int, __u64 *); + int (*bop_lookup_contig)(const struct nilfs_bmap *, __u64, __u64 *, + unsigned); int (*bop_insert)(struct nilfs_bmap *, __u64, __u64); int (*bop_delete)(struct nilfs_bmap *, __u64); void (*bop_clear)(struct nilfs_bmap *); @@ -140,6 +142,7 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *); +int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned); int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *); @@ -160,6 +163,7 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); /* * Internal use only */ +struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *); int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *, diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 24395e6..aa41272 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -29,6 +29,7 @@ #include "btnode.h" #include "btree.h" #include "alloc.h" +#include "dat.h" /** * struct nilfs_btree_path - A path on which B-tree operations are executed @@ -595,6 +596,87 @@ static int nilfs_btree_lookup(const struct nilfs_bmap *bmap, return ret; } +static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, + __u64 key, __u64 *ptrp, unsigned maxblocks) +{ + struct nilfs_btree *btree = (struct nilfs_btree *)bmap; + struct nilfs_btree_path *path; + struct nilfs_btree_node *node; + struct inode *dat = NULL; + __u64 ptr, ptr2; + sector_t blocknr; + int level = NILFS_BTREE_LEVEL_NODE_MIN; + int ret, cnt, index, maxlevel; + + path = nilfs_btree_alloc_path(btree); + if (path == NULL) + return -ENOMEM; + nilfs_btree_init_path(btree, path); + ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level); + if (ret < 0) + goto out; + + if (NILFS_BMAP_USE_VBN(bmap)) { + dat = nilfs_bmap_get_dat(bmap); + ret = nilfs_dat_translate(dat, ptr, &blocknr); + if (ret < 0) + goto out; + ptr = blocknr; + } + cnt = 1; + if (cnt == maxblocks) + goto end; + + maxlevel = nilfs_btree_height(btree) - 1; + node = nilfs_btree_get_node(btree, path, level); + index = path[level].bp_index + 1; + for (;;) { + while (index < nilfs_btree_node_get_nchildren(btree, node)) { + if (nilfs_btree_node_get_key(btree, node, index) != + key + cnt) + goto end; + ptr2 = nilfs_btree_node_get_ptr(btree, node, index); + if (dat) { + ret = nilfs_dat_translate(dat, ptr2, &blocknr); + if (ret < 0) + goto out; + ptr2 = blocknr; + } + if (ptr2 != ptr + cnt || ++cnt == maxblocks) + goto end; + index++; + continue; + } + if (level == maxlevel) + break; + + /* look-up right sibling node */ + node = nilfs_btree_get_node(btree, path, level + 1); + index = path[level + 1].bp_index + 1; + if (index >= nilfs_btree_node_get_nchildren(btree, node) || + nilfs_btree_node_get_key(btree, node, index) != key + cnt) + break; + ptr2 = nilfs_btree_node_get_ptr(btree, node, index); + path[level + 1].bp_index = index; + + brelse(path[level].bp_bh); + path[level].bp_bh = NULL; + ret = nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh); + if (ret < 0) + goto out; + node = nilfs_btree_get_nonroot_node(btree, path, level); + index = 0; + path[level].bp_index = index; + } + end: + *ptrp = ptr; + ret = cnt; + out: + nilfs_btree_clear_path(btree, path); + nilfs_btree_free_path(btree, path); + return ret; +} + static void nilfs_btree_promote_key(struct nilfs_btree *btree, struct nilfs_btree_path *path, int level, __u64 key) @@ -2187,6 +2269,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) static const struct nilfs_bmap_operations nilfs_btree_ops = { .bop_lookup = nilfs_btree_lookup, + .bop_lookup_contig = nilfs_btree_lookup_contig, .bop_insert = nilfs_btree_insert, .bop_delete = nilfs_btree_delete, .bop_clear = NULL, @@ -2206,6 +2289,7 @@ static const struct nilfs_bmap_operations nilfs_btree_ops = { static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { .bop_lookup = NULL, + .bop_lookup_contig = NULL, .bop_insert = NULL, .bop_delete = NULL, .bop_clear = NULL, diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 33467ad..342d976 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -25,6 +25,7 @@ #include "page.h" #include "direct.h" #include "alloc.h" +#include "dat.h" static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct) { @@ -62,6 +63,47 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap, return 0; } +static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap, + __u64 key, __u64 *ptrp, + unsigned maxblocks) +{ + struct nilfs_direct *direct = (struct nilfs_direct *)bmap; + struct inode *dat = NULL; + __u64 ptr, ptr2; + sector_t blocknr; + int ret, cnt; + + if (key > NILFS_DIRECT_KEY_MAX || + (ptr = nilfs_direct_get_ptr(direct, key)) == + NILFS_BMAP_INVALID_PTR) + return -ENOENT; + + if (NILFS_BMAP_USE_VBN(bmap)) { + dat = nilfs_bmap_get_dat(bmap); + ret = nilfs_dat_translate(dat, ptr, &blocknr); + if (ret < 0) + return ret; + ptr = blocknr; + } + + maxblocks = min_t(unsigned, maxblocks, NILFS_DIRECT_KEY_MAX - key + 1); + for (cnt = 1; cnt < maxblocks && + (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) != + NILFS_BMAP_INVALID_PTR; + cnt++) { + if (dat) { + ret = nilfs_dat_translate(dat, ptr2, &blocknr); + if (ret < 0) + return ret; + ptr2 = blocknr; + } + if (ptr2 != ptr + cnt) + break; + } + *ptrp = ptr; + return cnt; +} + static __u64 nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key) { @@ -367,6 +409,7 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap, static const struct nilfs_bmap_operations nilfs_direct_ops = { .bop_lookup = nilfs_direct_lookup, + .bop_lookup_contig = nilfs_direct_lookup_contig, .bop_insert = nilfs_direct_insert, .bop_delete = nilfs_direct_delete, .bop_clear = NULL, diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index f25fd4b..2696d6b 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -43,22 +43,23 @@ * * This function does not issue actual read request of the specified data * block. It is done by VFS. - * Bulk read for direct-io is not supported yet. (should be supported) */ int nilfs_get_block(struct inode *inode, sector_t blkoff, struct buffer_head *bh_result, int create) { struct nilfs_inode_info *ii = NILFS_I(inode); - unsigned long blknum = 0; + __u64 blknum = 0; int err = 0, ret; struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); + unsigned maxblocks = bh_result->b_size >> inode->i_blkbits; - /* This exclusion control is a workaround; should be revised */ - down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ - ret = nilfs_bmap_lookup(ii->i_bmap, (unsigned long)blkoff, &blknum); - up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ - if (ret == 0) { /* found */ + down_read(&NILFS_MDT(dat)->mi_sem); + ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks); + up_read(&NILFS_MDT(dat)->mi_sem); + if (ret >= 0) { /* found */ map_bh(bh_result, inode->i_sb, blknum); + if (ret > 0) + bh_result->b_size = (ret << inode->i_blkbits); goto out; } /* data block was not found */ -- cgit v0.10.2 From a60e77e5a41330334fd0ca428f18919d1ea6ed62 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 Jun 2009 18:26:06 +0200 Subject: iwlwifi: port to cfg80211 rfkill This ports the iwlwifi rfkill code to the new API offered by cfg80211 and thus removes a lot of useless stuff. The soft- rfkill is completely removed since that is now handled by setting the interfaces down. Signed-off-by: Johannes Berg Tested-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 6fe259f..029ccb6 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -10,10 +10,6 @@ config IWLWIFI_LEDS bool "Enable LED support in iwlagn and iwl3945 drivers" depends on IWLWIFI -config IWLWIFI_RFKILL - def_bool y - depends on IWLWIFI && RFKILL - config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" depends on IWLWIFI diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index d79d97a..1d4e0a2 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -4,7 +4,6 @@ iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o -iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 4d8a325..fbb3a57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -36,10 +36,6 @@ #include #include -/*used for rfkill*/ -#include -#include - /* Hardware specific file defines the PCI IDs table for that hardware module */ extern struct pci_device_id iwl3945_hw_card_ids[]; @@ -155,7 +151,6 @@ struct iwl3945_frame { #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b77208d..a5637c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -737,19 +737,13 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!(flags & RXON_CARD_DISABLED)) iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } @@ -1045,7 +1039,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); else clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1218,7 +1212,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); else clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1726,12 +1720,10 @@ static void __iwl_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill bits and return */ + * clear all bits but the RF Kill bit and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -1740,11 +1732,9 @@ static void __iwl_down(struct iwl_priv *priv) } /* ...otherwise clear out all the status bits but the RF Kill - * bits and continue taking the NIC down. */ + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_FW_ERROR, &priv->status) << @@ -1866,9 +1856,10 @@ static int __iwl_up(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by %s RF Kill switch\n", - test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); + IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); return 0; } @@ -2001,7 +1992,6 @@ static void iwl_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl_bg_restart(struct work_struct *data) @@ -2179,8 +2169,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) return ret; @@ -2775,7 +2763,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl_bg_up); INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); @@ -3046,12 +3033,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else set_bit(STATUS_RF_KILL_HW, &priv->status); - err = iwl_rfkill_init(priv); - if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); iwl_power_initialize(priv); return 0; @@ -3115,7 +3098,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_synchronize_irq(priv); - iwl_rfkill_unregister(priv); iwl_dealloc_ucode_pci(priv); if (priv->rxq.bd) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 51cae4e..f9d16ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -36,7 +36,6 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-rfkill.h" #include "iwl-power.h" #include "iwl-sta.h" #include "iwl-helpers.h" @@ -2211,126 +2210,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) } EXPORT_SYMBOL(iwl_send_card_state); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) - return; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO OFF\n"); - - iwl_scan_cancel(priv); - /* FIXME: This is a workaround for 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); - spin_unlock_irqrestore(&priv->lock, flags); - /* call the host command only if no hw rf-kill set */ - if (!test_bit(STATUS_RF_KILL_HW, &priv->status) && - iwl_is_ready(priv)) - iwl_send_card_state(priv, - CARD_STATE_CMD_DISABLE, 0); - set_bit(STATUS_RF_KILL_SW, &priv->status); - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - } -} -EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio); - -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (!test_bit(STATUS_RF_KILL_SW, &priv->status)) - return 0; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO ON\n"); - - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* If the driver is up it will receive CARD_STATE_NOTIFICATION - * notification where it will clear SW rfkill status. - * Setting it here would break the handler. Only if the - * interface is down we can set here since we don't - * receive any further notification. - */ - if (!priv->is_open) - clear_bit(STATUS_RF_KILL_SW, &priv->status); - spin_unlock_irqrestore(&priv->lock, flags); - - /* wake up ucode */ - msleep(10); - - iwl_read32(priv, CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&priv->reg_lock, flags); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); - - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " - "disabled by HW switch\n"); - return 0; - } - - /* when driver is up while rfkill is on, it wont receive - * any CARD_STATE_NOTIFICATION notifications so we have to - * restart it in here - */ - if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) { - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!iwl_is_rfkill(priv)) - queue_work(priv->workqueue, &priv->up); - } - - /* If the driver is already loaded, it will receive - * CARD_STATE_NOTIFICATION notifications and the handler will - * call restart to reload the driver. - */ - return 1; -} -EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio); - -void iwl_bg_rf_kill(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); - - wake_up_interruptible(&priv->wait_command_queue); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - if (!iwl_is_rfkill(priv)) { - IWL_DEBUG_RF_KILL(priv, - "HW and/or SW RF Kill no longer active, restarting " - "device\n"); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && - priv->is_open) - queue_work(priv->workqueue, &priv->restart); - } else { - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - - if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) - IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " - "disabled by SW switch\n"); - else - IWL_WARN(priv, "Radio Frequency Kill Switch is On:\n" - "Kill switch must be turned off for " - "wireless networking to work.\n"); - } - mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); -} -EXPORT_SYMBOL(iwl_bg_rf_kill); - void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -2849,23 +2728,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - if (conf->radio_enabled && - iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " - "waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) - iwl_radio_kill_sw_disable_radio(priv); - } - - if (!conf->radio_enabled) { - IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); - goto out; - } - if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b52d0fb..dabf663 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -348,14 +348,6 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); ****************************************************/ 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_bg_rf_kill(struct work_struct *work); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); - /******************************************************************************* * Rate ******************************************************************************/ @@ -498,7 +490,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 @@ -533,11 +524,6 @@ static inline int iwl_is_init(struct iwl_priv *priv) return test_bit(STATUS_INIT, &priv->status); } -static inline int iwl_is_rfkill_sw(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_SW, &priv->status); -} - static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) { return test_bit(STATUS_RF_KILL_HW, &priv->status); @@ -545,7 +531,7 @@ static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) static inline int iwl_is_rfkill(struct iwl_priv *priv) { - return iwl_is_rfkill_hw(priv) || iwl_is_rfkill_sw(priv); + return iwl_is_rfkill_hw(priv); } static inline int iwl_is_ready_rf(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index af70229..11e08c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -449,8 +449,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_INT_ENABLED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", test_bit(STATUS_RF_KILL_HW, &priv->status)); - pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_SW:\t %d\n", - test_bit(STATUS_RF_KILL_SW, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", test_bit(STATUS_INIT, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 28c39cf..e2d620f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -41,7 +41,6 @@ #include "iwl-prph.h" #include "iwl-fh.h" #include "iwl-debug.h" -#include "iwl-rfkill.h" #include "iwl-4965-hw.h" #include "iwl-3945-hw.h" #include "iwl-3945-led.h" @@ -936,9 +935,6 @@ struct iwl_priv { * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; -#if defined(CONFIG_IWLWIFI_RFKILL) - struct rfkill *rfkill; -#endif #ifdef CONFIG_IWLWIFI_LEDS unsigned long last_blink_time; @@ -1072,7 +1068,6 @@ struct iwl_priv { struct work_struct calibrated_work; struct work_struct scan_completed; struct work_struct rx_replenish; - struct work_struct rf_kill; struct work_struct abort_scan; struct work_struct update_link_led; struct work_struct auth_work; diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c deleted file mode 100644 index 1314993..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ /dev/null @@ -1,131 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#include -#include -#include - -#include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" - -/* software rf-kill from user */ -static int iwl_rfkill_soft_rf_kill(void *data, bool blocked) -{ - struct iwl_priv *priv = data; - - if (!priv->rfkill) - return -EINVAL; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return 0; - - IWL_DEBUG_RF_KILL(priv, "received soft RFKILL: block=%d\n", blocked); - - mutex_lock(&priv->mutex); - - if (iwl_is_rfkill_hw(priv)) - goto out_unlock; - - if (!blocked) - iwl_radio_kill_sw_enable_radio(priv); - else - iwl_radio_kill_sw_disable_radio(priv); - -out_unlock: - mutex_unlock(&priv->mutex); - return 0; -} - -static const struct rfkill_ops iwl_rfkill_ops = { - .set_block = iwl_rfkill_soft_rf_kill, -}; - -int iwl_rfkill_init(struct iwl_priv *priv) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret = 0; - - BUG_ON(device == NULL); - - IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); - priv->rfkill = rfkill_alloc(priv->cfg->name, - device, - RFKILL_TYPE_WLAN, - &iwl_rfkill_ops, priv); - if (!priv->rfkill) { - IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); - ret = -ENOMEM; - goto error; - } - - ret = rfkill_register(priv->rfkill); - if (ret) { - IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); - goto free_rfkill; - } - - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return 0; - -free_rfkill: - rfkill_destroy(priv->rfkill); - priv->rfkill = NULL; - -error: - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return ret; -} -EXPORT_SYMBOL(iwl_rfkill_init); - -void iwl_rfkill_unregister(struct iwl_priv *priv) -{ - - if (priv->rfkill) { - rfkill_unregister(priv->rfkill); - rfkill_destroy(priv->rfkill); - } - - priv->rfkill = NULL; -} -EXPORT_SYMBOL(iwl_rfkill_unregister); - -/* set RFKILL to the right state. */ -void iwl_rfkill_set_hw_state(struct iwl_priv *priv) -{ - if (!priv->rfkill) - return; - - if (rfkill_set_hw_state(priv->rfkill, - !!iwl_is_rfkill_hw(priv))) - iwl_radio_kill_sw_disable_radio(priv); - else - iwl_radio_kill_sw_enable_radio(priv); -} -EXPORT_SYMBOL(iwl_rfkill_set_hw_state); diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h deleted file mode 100644 index 633dafb..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#ifndef __iwl_rf_kill_h__ -#define __iwl_rf_kill_h__ - -struct iwl_priv; - -#include - -#ifdef CONFIG_IWLWIFI_RFKILL - -void iwl_rfkill_set_hw_state(struct iwl_priv *priv); -void iwl_rfkill_unregister(struct iwl_priv *priv); -int iwl_rfkill_init(struct iwl_priv *priv); -#else -static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {} -static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {} -static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; } -#endif - - - -#endif /* __iwl_rf_kill_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 92fa1a3..83d3160 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1009,18 +1009,12 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } @@ -2586,8 +2580,6 @@ static void __iwl3945_down(struct iwl_priv *priv) if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -2596,11 +2588,9 @@ static void __iwl3945_down(struct iwl_priv *priv) } /* ...otherwise clear out all the status bits but the RF Kill - * bits and continue taking the NIC down. */ + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_FW_ERROR, &priv->status) << @@ -2657,12 +2647,6 @@ static int __iwl3945_up(struct iwl_priv *priv) return -EIO; } - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARN(priv, "Radio disabled by SW RF kill (module " - "parameter)\n"); - return -ENODEV; - } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { IWL_ERR(priv, "ucode not available for device bring up\n"); return -EIO; @@ -2779,15 +2763,14 @@ static void iwl3945_rfkill_poll(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rfkill_poll.work); - unsigned long status = priv->status; if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); else set_bit(STATUS_RF_KILL_HW, &priv->status); - if (test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); queue_delayed_work(priv->workqueue, &priv->rfkill_poll, round_jiffies_relative(2 * HZ)); @@ -3019,7 +3002,6 @@ static void iwl3945_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl3945_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl3945_bg_restart(struct work_struct *data) @@ -3182,8 +3164,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) goto out_release_irq; @@ -3836,7 +3816,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl3945_bg_up); INIT_WORK(&priv->restart, iwl3945_bg_restart); INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); @@ -4203,13 +4182,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - err = iwl_rfkill_init(priv); - if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); - /* Start monitoring the killswitch */ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, 2 * HZ); @@ -4275,7 +4247,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); - iwl_rfkill_unregister(priv); cancel_delayed_work_sync(&priv->rfkill_poll); iwl3945_dealloc_ucode_pci(priv); -- cgit v0.10.2 From aa18294a289548f45ea6a784f008295ccddf6b14 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 4 Jun 2009 20:13:19 +0300 Subject: rndis_wlan: cleanup: capitalize enum labels Capitalize enum labels as told in Documents/CodingStyle. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c254fdf..de94496 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -157,55 +157,55 @@ MODULE_PARM_DESC(workaround_interval, #define NDIS_802_11_LENGTH_RATES_EX 16 enum ndis_80211_net_type { - ndis_80211_type_freq_hop, - ndis_80211_type_direct_seq, - ndis_80211_type_ofdm_a, - ndis_80211_type_ofdm_g + NDIS_80211_TYPE_FREQ_HOP, + NDIS_80211_TYPE_DIRECT_SEQ, + NDIS_80211_TYPE_OFDM_A, + NDIS_80211_TYPE_OFDM_G }; enum ndis_80211_net_infra { - ndis_80211_infra_adhoc, - ndis_80211_infra_infra, - ndis_80211_infra_auto_unknown + NDIS_80211_INFRA_ADHOC, + NDIS_80211_INFRA_INFRA, + NDIS_80211_INFRA_AUTO_UNKNOWN }; enum ndis_80211_auth_mode { - ndis_80211_auth_open, - ndis_80211_auth_shared, - ndis_80211_auth_auto_switch, - ndis_80211_auth_wpa, - ndis_80211_auth_wpa_psk, - ndis_80211_auth_wpa_none, - ndis_80211_auth_wpa2, - ndis_80211_auth_wpa2_psk + NDIS_80211_AUTH_OPEN, + NDIS_80211_AUTH_SHARED, + NDIS_80211_AUTH_AUTO_SWITCH, + NDIS_80211_AUTH_WPA, + NDIS_80211_AUTH_WPA_PSK, + NDIS_80211_AUTH_WPA_NONE, + NDIS_80211_AUTH_WPA2, + NDIS_80211_AUTH_WPA2_PSK }; enum ndis_80211_encr_status { - ndis_80211_encr_wep_enabled, - ndis_80211_encr_disabled, - ndis_80211_encr_wep_key_absent, - ndis_80211_encr_not_supported, - ndis_80211_encr_tkip_enabled, - ndis_80211_encr_tkip_key_absent, - ndis_80211_encr_ccmp_enabled, - ndis_80211_encr_ccmp_key_absent + NDIS_80211_ENCR_WEP_ENABLED, + NDIS_80211_ENCR_DISABLED, + NDIS_80211_ENCR_WEP_KEY_ABSENT, + NDIS_80211_ENCR_NOT_SUPPORTED, + NDIS_80211_ENCR_TKIP_ENABLED, + NDIS_80211_ENCR_TKIP_KEY_ABSENT, + NDIS_80211_ENCR_CCMP_ENABLED, + NDIS_80211_ENCR_CCMP_KEY_ABSENT }; enum ndis_80211_priv_filter { - ndis_80211_priv_accept_all, - ndis_80211_priv_8021x_wep + NDIS_80211_PRIV_ACCEPT_ALL, + NDIS_80211_PRIV_8021X_WEP }; enum ndis_80211_addkey_bits { - ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28), - ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29), - ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30), - ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31), + NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), + NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), + NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; enum ndis_80211_addwep_bits { - ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30), - ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31), + NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; struct ndis_80211_ssid { @@ -835,23 +835,23 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa2; + auth_mode = NDIS_80211_AUTH_WPA2; else - auth_mode = ndis_80211_auth_wpa2_psk; + auth_mode = NDIS_80211_AUTH_WPA2_PSK; } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa; + auth_mode = NDIS_80211_AUTH_WPA; else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) - auth_mode = ndis_80211_auth_wpa_psk; + auth_mode = NDIS_80211_AUTH_WPA_PSK; else - auth_mode = ndis_80211_auth_wpa_none; + auth_mode = NDIS_80211_AUTH_WPA_NONE; } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) - auth_mode = ndis_80211_auth_auto_switch; + auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; else - auth_mode = ndis_80211_auth_shared; + auth_mode = NDIS_80211_AUTH_SHARED; } else - auth_mode = ndis_80211_auth_open; + auth_mode = NDIS_80211_AUTH_OPEN; tmp = cpu_to_le32(auth_mode); ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, @@ -876,9 +876,9 @@ static int set_priv_filter(struct usbnet *usbdev) if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) - tmp = cpu_to_le32(ndis_80211_priv_8021x_wep); + tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); else - tmp = cpu_to_le32(ndis_80211_priv_accept_all); + tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp, sizeof(tmp)); @@ -896,18 +896,18 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) groupwise); if (pairwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (pairwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else if (pairwise & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) - encr_mode = ndis_80211_encr_wep_enabled; + encr_mode = NDIS_80211_ENCR_WEP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else - encr_mode = ndis_80211_encr_disabled; + encr_mode = NDIS_80211_ENCR_DISABLED; tmp = cpu_to_le32(encr_mode); ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp, @@ -975,7 +975,7 @@ static void set_default_iw_params(struct usbnet *usbdev) priv->wpa_keymgmt = 0; priv->wpa_version = 0; - set_infra_mode(usbdev, ndis_80211_infra_infra); + set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, IW_AUTH_ALG_OPEN_SYSTEM); set_priv_filter(usbdev); @@ -1011,7 +1011,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) memcpy(&ndis_key.material, key, key_len); if (index == priv->encr_tx_key_index) { - ndis_key.index |= ndis_80211_addwep_transmit_key; + ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, IW_AUTH_CIPHER_NONE); if (ret) @@ -1047,15 +1047,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, return -EINVAL; if (key_len > sizeof(ndis_key.material) || key_len < 0) return -EINVAL; - if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq) + if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) return -EINVAL; - if ((flags & ndis_80211_addkey_pairwise_key) && !addr) + if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr) return -EINVAL; devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, - !!(flags & ndis_80211_addkey_transmit_key), - !!(flags & ndis_80211_addkey_pairwise_key), - !!(flags & ndis_80211_addkey_set_init_recv_seq)); + !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), + !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), + !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); memset(&ndis_key, 0, sizeof(ndis_key)); @@ -1073,15 +1073,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, } else memcpy(ndis_key.material, key, key_len); - if (flags & ndis_80211_addkey_set_init_recv_seq) + if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) memcpy(ndis_key.rsc, rx_seq, 6); - if (flags & ndis_80211_addkey_pairwise_key) { + if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { /* pairwise key */ memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); } else { /* group key */ - if (priv->infra_mode == ndis_80211_infra_adhoc) + if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) memset(ndis_key.bssid, 0xff, ETH_ALEN); else get_bssid(usbdev, ndis_key.bssid); @@ -1096,7 +1096,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, priv->encr_key_len[index] = key_len; priv->encr_key_wpa[index] = 1; - if (flags & ndis_80211_addkey_transmit_key) + if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) priv->encr_tx_key_index = index; return 0; @@ -1128,7 +1128,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) /* pairwise key */ if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) remove_key.index |= - ndis_80211_addkey_pairwise_key; + NDIS_80211_ADDKEY_PAIRWISE_KEY; memcpy(remove_key.bssid, bssid, sizeof(remove_key.bssid)); } else @@ -1238,10 +1238,10 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, switch (type) { case NL80211_IFTYPE_ADHOC: - mode = ndis_80211_infra_adhoc; + mode = NDIS_80211_INFRA_ADHOC; break; case NL80211_IFTYPE_STATION: - mode = ndis_80211_infra_infra; + mode = NDIS_80211_INFRA_INFRA; break; default: return -EINVAL; @@ -1698,11 +1698,11 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, flags = 0; if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - flags |= ndis_80211_addkey_set_init_recv_seq; + flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) - flags |= ndis_80211_addkey_pairwise_key; + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - flags |= ndis_80211_addkey_transmit_key; + flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, ext->rx_seq, ext->alg, flags); @@ -2160,14 +2160,14 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) n = 8; for (i = 0; i < n; i++) { switch (le32_to_cpu(networks_supported.items[i])) { - case ndis_80211_type_freq_hop: - case ndis_80211_type_direct_seq: + case NDIS_80211_TYPE_FREQ_HOP: + case NDIS_80211_TYPE_DIRECT_SEQ: priv->caps |= CAP_MODE_80211B; break; - case ndis_80211_type_ofdm_a: + case NDIS_80211_TYPE_OFDM_A: priv->caps |= CAP_MODE_80211A; break; - case ndis_80211_type_ofdm_g: + case NDIS_80211_TYPE_OFDM_G: priv->caps |= CAP_MODE_80211G; break; } -- cgit v0.10.2 From 582241a08409c89b086774c60b55c1a1706a7e5d Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 4 Jun 2009 20:13:25 +0300 Subject: rndis_wlan: cleanup: rename all rndis_wext* objects to rndis_wlan* Driver used to be named rndis_wext before inclusion to upstream. Since rndis_wlan is being converted to cfg80211, use of rndis_wext* names can be confusing. So rename all rndis_wext to rndis_wlan (as should have been when driver was renamed). Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index de94496..7441d55 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -361,7 +361,7 @@ static const struct ieee80211_rate rndis_rates[] = { }; /* RNDIS device private data */ -struct rndis_wext_private { +struct rndis_wlan_private { struct usbnet *usbdev; struct wireless_dev wdev; @@ -441,13 +441,13 @@ static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -static struct rndis_wext_private *get_rndis_wext_priv(struct usbnet *dev) +static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) { - return (struct rndis_wext_private *)dev->driver_priv; + return (struct rndis_wlan_private *)dev->driver_priv; } -static u32 get_bcm4320_power(struct rndis_wext_private *priv) +static u32 get_bcm4320_power(struct rndis_wlan_private *priv) { return BCM4320_DEFAULT_TXPOWER * bcm4320_power_output[priv->param_power_output] / 100; @@ -480,7 +480,7 @@ static int rndis_error_status(__le32 rndis_status) static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -526,7 +526,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -747,7 +747,7 @@ static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); @@ -794,7 +794,7 @@ static int is_associated(struct usbnet *usbdev) static int disassociate(struct usbnet *usbdev, int reset_ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_ssid ssid; int i, ret = 0; @@ -826,7 +826,7 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int auth_mode, ret; @@ -869,7 +869,7 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) static int set_priv_filter(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); @@ -887,7 +887,7 @@ static int set_priv_filter(struct usbnet *usbdev) static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int encr_mode, ret; @@ -925,7 +925,7 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) static int set_assoc_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg); set_priv_filter(usbdev); @@ -937,7 +937,7 @@ static int set_assoc_params(struct usbnet *usbdev) static int set_infra_mode(struct usbnet *usbdev, int mode) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int ret, i; @@ -970,7 +970,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) static void set_default_iw_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); priv->wpa_keymgmt = 0; priv->wpa_version = 0; @@ -996,7 +996,7 @@ static int deauthenticate(struct usbnet *usbdev) /* index must be 0 - N, as per NDIS */ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; int ret; @@ -1039,7 +1039,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const struct sockaddr *addr, const u8 *rx_seq, int alg, int flags) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; int ret; @@ -1106,7 +1106,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; __le32 keyindex; int ret; @@ -1161,7 +1161,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) static void set_multicast_list(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct dev_mc_list *mclist; __le32 filter; int ret, i, size; @@ -1256,7 +1256,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; __le32 tmp; @@ -1286,7 +1286,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, struct ndis_80211_bssid_ex *bssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ieee80211_channel *channel; s32 signal; u64 timestamp; @@ -1371,8 +1371,8 @@ out: static void rndis_get_scan_results(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, scan_work.work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, scan_work.work); struct usbnet *usbdev = priv->usbdev; int ret; @@ -1497,7 +1497,7 @@ static int rndis_iw_set_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = -ENOTSUPP; switch (p->flags & IW_AUTH_INDEX) { @@ -1578,7 +1578,7 @@ static int rndis_iw_get_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); switch (p->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -1609,7 +1609,7 @@ static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret, index, key_len; u8 *key; @@ -1672,7 +1672,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, { struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int keyidx, flags; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1713,7 +1713,7 @@ static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = 0; #ifdef DEBUG @@ -1747,7 +1747,7 @@ static int rndis_iw_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); devdbg(usbdev, "SIOCGIWGENIE"); @@ -1886,7 +1886,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power; if (priv->radio_on) { @@ -1912,7 +1912,7 @@ static int rndis_iw_set_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power = 0; if (!wrqu->txpower.disabled) { @@ -1969,7 +1969,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned char bssid[ETH_ALEN]; @@ -1994,7 +1994,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); unsigned long flags; spin_lock_irqsave(&priv->stats_lock, flags); @@ -2037,28 +2037,28 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme, }; -static const iw_handler rndis_wext_private_handler[] = { +static const iw_handler rndis_wlan_private_handler[] = { }; -static const struct iw_priv_args rndis_wext_private_args[] = { +static const struct iw_priv_args rndis_wlan_private_args[] = { }; static const struct iw_handler_def rndis_iw_handlers = { .num_standard = ARRAY_SIZE(rndis_iw_handler), - .num_private = ARRAY_SIZE(rndis_wext_private_handler), - .num_private_args = ARRAY_SIZE(rndis_wext_private_args), + .num_private = ARRAY_SIZE(rndis_wlan_private_handler), + .num_private_args = ARRAY_SIZE(rndis_wlan_private_args), .standard = (iw_handler *)rndis_iw_handler, - .private = (iw_handler *)rndis_wext_private_handler, - .private_args = (struct iw_priv_args *)rndis_wext_private_args, + .private = (iw_handler *)rndis_wlan_private_handler, + .private_args = (struct iw_priv_args *)rndis_wlan_private_args, .get_wireless_stats = rndis_get_wireless_stats, }; -static void rndis_wext_worker(struct work_struct *work) +static void rndis_wlan_worker(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, work); struct usbnet *usbdev = priv->usbdev; union iwreq_data evt; unsigned char bssid[ETH_ALEN]; @@ -2119,10 +2119,10 @@ get_bssid: set_multicast_list(usbdev); } -static void rndis_wext_set_multicast_list(struct net_device *dev) +static void rndis_wlan_set_multicast_list(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) return; @@ -2131,9 +2131,9 @@ static void rndis_wext_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } -static void rndis_wext_link_change(struct usbnet *usbdev, int state) +static void rndis_wlan_link_change(struct usbnet *usbdev, int state) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* queue work to avoid recursive calls into rndis_command */ set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending); @@ -2141,14 +2141,14 @@ static void rndis_wext_link_change(struct usbnet *usbdev, int state) } -static int rndis_wext_get_caps(struct usbnet *usbdev) +static int rndis_wlan_get_caps(struct usbnet *usbdev) { struct { __le32 num_items; __le32 items[8]; } networks_supported; int len, retval, i, n; - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* determine supported modes */ len = sizeof(networks_supported); @@ -2181,8 +2181,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) #define STATS_UPDATE_JIFFIES (HZ) static void rndis_update_wireless_stats(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, stats_work.work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, stats_work.work); struct usbnet *usbdev = priv->usbdev; struct iw_statistics iwstats; __le32 rssi, tmp; @@ -2297,7 +2297,7 @@ static int bcm4320a_early_init(struct usbnet *usbdev) static int bcm4320b_early_init(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); char buf[8]; /* Early initialization settings, setting these won't have effect @@ -2363,21 +2363,21 @@ static int bcm4320b_early_init(struct usbnet *usbdev) } /* same as rndis_netdev_ops but with local multicast handler */ -static const struct net_device_ops rndis_wext_netdev_ops = { +static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = rndis_wext_set_multicast_list, + .ndo_set_multicast_list = rndis_wlan_set_multicast_list, }; -static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) +static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) { struct wiphy *wiphy; - struct rndis_wext_private *priv; + struct rndis_wlan_private *priv; int retval, len; __le32 tmp; @@ -2385,7 +2385,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) * NOTE: We only support a single virtual interface, so wiphy * and wireless_dev are somewhat synonymous for this device. */ - wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wext_private)); + wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private)); if (!wiphy) return -ENOMEM; @@ -2395,7 +2395,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) priv->wdev.iftype = NL80211_IFTYPE_STATION; /* These have to be initialized before calling generic_rndis_bind(). - * Otherwise we'll be in big trouble in rndis_wext_early_init(). + * Otherwise we'll be in big trouble in rndis_wlan_early_init(). */ usbdev->driver_priv = priv; usbdev->net->wireless_handlers = &rndis_iw_handlers; @@ -2406,7 +2406,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - INIT_WORK(&priv->work, rndis_wext_worker); + INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); @@ -2420,9 +2420,9 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) * picks up rssi to closest station instead of to access point). * * rndis_host wants to avoid all OID as much as possible - * so do promisc/multicast handling in rndis_wext. + * so do promisc/multicast handling in rndis_wlan. */ - usbdev->net->netdev_ops = &rndis_wext_netdev_ops; + usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, @@ -2455,7 +2455,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) wiphy->max_scan_ssids = 1; /* TODO: fill-out band information based on priv->caps */ - rndis_wext_get_caps(usbdev); + rndis_wlan_get_caps(usbdev); memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); @@ -2497,9 +2497,9 @@ fail: } -static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) +static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* turn radio off */ disassociate(usbdev, 0); @@ -2520,7 +2520,7 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) } -static int rndis_wext_reset(struct usbnet *usbdev) +static int rndis_wlan_reset(struct usbnet *usbdev) { return deauthenticate(usbdev); } @@ -2529,40 +2529,40 @@ static int rndis_wext_reset(struct usbnet *usbdev) static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320b_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; static const struct driver_info bcm4320a_info = { .description = "Wireless RNDIS device, BCM4320a based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320a_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; -static const struct driver_info rndis_wext_info = { +static const struct driver_info rndis_wlan_info = { .description = "Wireless RNDIS device", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320a_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; /*-------------------------------------------------------------------------*/ @@ -2672,11 +2672,11 @@ static const struct usb_device_id products [] = { { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { }, // END }; -- cgit v0.10.2 From 4d1d49858c0a5a4fb1be4bc7972754cd640245ba Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 4 Jun 2009 21:57:03 +0200 Subject: net/libertas: remove GPIO-CS handling in SPI interface code This removes the dependency on GPIO framework and lets the SPI host driver handle the chip select. The SPI host driver is required to keep the CS active for the entire message unless cs_change says otherwise. This patch collects the two/three single SPI transfers into a message. Also the delay in read path in case use_dummy_writes are not used is moved into the SPI host driver. Tested-by: Mike Rapoport Tested-by: Andrey Yurovsky Signed-off-by: Sebastian Andrzej Siewior Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index daf4c80..fb7541c 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -153,7 +153,7 @@ config LIBERTAS_SDIO config LIBERTAS_SPI tristate "Marvell Libertas 8686 SPI 802.11b/g cards" - depends on LIBERTAS && SPI && GENERIC_GPIO + depends on LIBERTAS && SPI ---help--- A driver for Marvell Libertas 8686 SPI devices. diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index ea23c5d..f8c2898 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -51,13 +50,6 @@ struct if_spi_card { u16 card_id; u8 card_rev; - /* Pin number for our GPIO chip-select. */ - /* TODO: Once the generic SPI layer has some additional features, we - * should take this out and use the normal chip select here. - * We need support for chip select delays, and not dropping chipselect - * after each word. */ - int gpio_cs; - /* The last time that we initiated an SPU operation */ unsigned long prev_xfer_time; @@ -130,12 +122,10 @@ static void spu_transaction_init(struct if_spi_card *card) * If not, we have to busy-wait to be on the safe side. */ ndelay(400); } - gpio_set_value(card->gpio_cs, 0); /* assert CS */ } static void spu_transaction_finish(struct if_spi_card *card) { - gpio_set_value(card->gpio_cs, 1); /* drop CS */ card->prev_xfer_time = jiffies; } @@ -145,6 +135,13 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer data_trans; + + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&data_trans, 0, sizeof(data_trans)); /* You must give an even number of bytes to the SPU, even if it * doesn't care about the last one. */ @@ -153,13 +150,16 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) spu_transaction_init(card); /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); - err = spi_write(card->spi, buf, len); + data_trans.tx_buf = buf; + data_trans.len = len; -out: + spi_message_add_tail(®_trans, &m); + spi_message_add_tail(&data_trans, &m); + + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } @@ -186,10 +186,13 @@ static inline int spu_reg_is_port_reg(u16 reg) static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) { - unsigned int i, delay; + unsigned int delay; int err = 0; - u16 zero = 0; u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer dummy_trans; + struct spi_transfer data_trans; /* You must take an even number of bytes from the SPU, even if you * don't care about the last one. */ @@ -197,29 +200,34 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) spu_transaction_init(card); + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&dummy_trans, 0, sizeof(dummy_trans)); + memset(&data_trans, 0, sizeof(data_trans)); + /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); + spi_message_add_tail(®_trans, &m); delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay : card->spu_reg_delay; if (card->use_dummy_writes) { /* Clock in dummy cycles while the SPU fills the FIFO */ - for (i = 0; i < delay / 16; ++i) { - err = spi_write(card->spi, (u8 *)&zero, sizeof(u16)); - if (err) - return err; - } + dummy_trans.len = delay / 8; + spi_message_add_tail(&dummy_trans, &m); } else { /* Busy-wait while the SPU fills the FIFO */ - ndelay(100 + (delay * 10)); + reg_trans.delay_usecs = + DIV_ROUND_UP((100 + (delay * 10)), 1000); } /* read in data */ - err = spi_read(card->spi, buf, len); + data_trans.rx_buf = buf; + data_trans.len = len; + spi_message_add_tail(&data_trans, &m); -out: + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } @@ -1049,7 +1057,6 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, card); card->pdata = pdata; card->spi = spi; - card->gpio_cs = pdata->gpio_cs; card->prev_xfer_time = jiffies; sema_init(&card->spi_ready, 0); @@ -1058,26 +1065,18 @@ static int __devinit if_spi_probe(struct spi_device *spi) INIT_LIST_HEAD(&card->data_packet_list); spin_lock_init(&card->buffer_lock); - /* set up GPIO CS line. TODO: use regular CS line */ - err = gpio_request(card->gpio_cs, "if_spi_gpio_chip_select"); - if (err) - goto free_card; - err = gpio_direction_output(card->gpio_cs, 1); - if (err) - goto free_gpio; - /* Initialize the SPI Interface Unit */ err = spu_init(card, pdata->use_dummy_writes); if (err) - goto free_gpio; + goto free_card; err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); if (err) - goto free_gpio; + goto free_card; /* Firmware load */ err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); if (err) - goto free_gpio; + goto free_card; if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC) lbs_deb_spi("Firmware is already loaded for " "Marvell WLAN 802.11 adapter\n"); @@ -1085,7 +1084,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) err = if_spi_calculate_fw_names(card->card_id, card->helper_fw_name, card->main_fw_name); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter " "(chip_id = 0x%04x, chip_rev = 0x%02x) " @@ -1096,23 +1095,23 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi->max_speed_hz); err = if_spi_prog_helper_firmware(card); if (err) - goto free_gpio; + goto free_card; err = if_spi_prog_main_firmware(card); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n"); } err = spu_set_interrupt_mode(card, 0, 1); if (err) - goto free_gpio; + goto free_card; /* Register our card with libertas. * This will call alloc_etherdev */ priv = lbs_add_card(card, &spi->dev); if (!priv) { err = -ENOMEM; - goto free_gpio; + goto free_card; } card->priv = priv; priv->card = card; @@ -1157,8 +1156,6 @@ terminate_thread: if_spi_terminate_spi_thread(card); remove_card: lbs_remove_card(priv); /* will call free_netdev */ -free_gpio: - gpio_free(card->gpio_cs); free_card: free_if_spi_card(card); out: @@ -1179,7 +1176,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) free_irq(spi->irq, card); if_spi_terminate_spi_thread(card); lbs_remove_card(priv); /* will call free_netdev */ - gpio_free(card->gpio_cs); if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); diff --git a/include/linux/spi/libertas_spi.h b/include/linux/spi/libertas_spi.h index 79506f5..1b5d538 100644 --- a/include/linux/spi/libertas_spi.h +++ b/include/linux/spi/libertas_spi.h @@ -22,9 +22,6 @@ struct libertas_spi_platform_data { * speed, you may want to use 0 here. */ u16 use_dummy_writes; - /* GPIO number to use as chip select */ - u16 gpio_cs; - /* Board specific setup/teardown */ int (*setup)(struct spi_device *spi); int (*teardown)(struct spi_device *spi); -- cgit v0.10.2 From 5ee58d7e6ad019675b4090582aec4fa1180d8703 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 5 Jun 2009 08:21:50 -0400 Subject: mac80211: fix minstrel single-rate memory corruption The minstrel rate controller periodically looks up rate indexes in a sampling table. When accessing a specific row and column, minstrel correctly does a bounds check which, on the surface, appears to handle the case where mi->n_rates < 2. However, mi->sample_idx is actually defined as an unsigned, so the right hand side is taken to be a huge positive number when negative, and the check will always fail. Consequently, the RC will overrun the array and cause random memory corruption when communicating with a peer that has only a single rate. The max value of mi->sample_idx is around 25 so casting to int should have no ill effects. Without the change, uptime is a few minutes under load with an AP that has a single hard-coded rate, and both the AP and STA could potentially crash. With the change, both lasted 12 hours with a steady load. Thanks to Ognjen Maric for providing the single-rate clue so I could reproduce this. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=12490 on the regression list (also http://bugzilla.kernel.org/show_bug.cgi?id=13000). Cc: stable@kernel.org Reported-by: Sergey S. Kostyliov Reported-by: Ognjen Maric Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 0a11515..b218b98 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -215,7 +215,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi) unsigned int sample_ndx; sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column); mi->sample_idx++; - if (mi->sample_idx > (mi->n_rates - 2)) { + if ((int) mi->sample_idx > (mi->n_rates - 2)) { mi->sample_idx = 0; mi->sample_column++; if (mi->sample_column >= SAMPLE_COLUMNS) -- cgit v0.10.2 From b52a033c2c501a8015df3727a4bd73389ccb1641 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Thu, 4 Jun 2009 23:18:33 +0200 Subject: b43: Fix possible unaligned u32 access Fix possible unaligned u32 access in b43_generate_plcp_hdr(). Unaligned data is read/write with a u32 pointer instead of using the packed structure. Some versions of gcc ignore the "packed" attribute, if the structure element is accessed through a local pointer. Signed-off-by: Matthieu CASTET Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index a63d888..55f36a7 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -118,7 +118,6 @@ u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate) void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, const u16 octets, const u8 bitrate) { - __le32 *data = &(plcp->data); __u8 *raw = plcp->raw; if (b43_is_ofdm_rate(bitrate)) { @@ -127,7 +126,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, d = b43_plcp_get_ratecode_ofdm(bitrate); B43_WARN_ON(octets & 0xF000); d |= (octets << 5); - *data = cpu_to_le32(d); + plcp->data = cpu_to_le32(d); } else { u32 plen; @@ -141,7 +140,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, raw[1] = 0x04; } else raw[1] = 0x04; - *data |= cpu_to_le32(plen << 16); + plcp->data |= cpu_to_le32(plen << 16); raw[0] = b43_plcp_get_ratecode_cck(bitrate); } } -- cgit v0.10.2 From dacb6f1d8fa5200efc4e609fe63a750b960993b6 Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Thu, 4 Jun 2009 22:16:18 +0200 Subject: mac80211 : fix unaligned rx skb mac80211 is checking is the skb is aligned on 32 bit boundary. But it is checking against ethernet header, whereas Linux expect IP header aligned. And ethernet ether size is 6*2+2=14, so aligning ethernet header make IP header unaligned. Signed-off-by: Matthieu CASTET Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6a9b8e6..7541251 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1335,7 +1335,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) * mac80211. That also explains the __skb_push() * below. */ - align = (unsigned long)skb->data & 3; + align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; if (align) { if (WARN_ON(skb_headroom(skb) < 3)) { dev_kfree_skb(skb); -- cgit v0.10.2 From 2543a0c4c0fde46f9f206cec1e1cf951a2a63a66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 5 Jun 2009 11:47:43 +0200 Subject: ar9170: interpret firmware debug commands This adds new commands that the original firmware will not send but we can use them to debug firmware. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index b104d7e..de57aa9 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -442,6 +442,38 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) /* retransmission issue / SIFS/EIFS collision ?! */ break; + /* firmware debug */ + case 0xca: + printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4); + break; + case 0xcb: + len -= 4; + + switch (len) { + case 1: + printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", + *((char *)buf + 4)); + break; + case 2: + printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", + le16_to_cpup((__le16 *)((char *)buf + 4))); + break; + case 4: + printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", + le32_to_cpup((__le32 *)((char *)buf + 4))); + break; + case 8: + printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", + (unsigned long)le64_to_cpup( + (__le64 *)((char *)buf + 4))); + break; + } + break; + case 0xcc: + print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, + (char *)buf + 4, len - 4); + break; + default: printk(KERN_INFO "received unhandled event %x\n", cmd->type); print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); -- cgit v0.10.2 From 9b9c5aaeedfda256ed77094303e2a7242c3290da Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Jun 2009 05:07:23 +0200 Subject: ar9170: xmit code revamp This patch is a back-port from aggregation testing code. In the past, we didn't limit the amount of active tx urbs. However, ar9170 only has a limited buffer reserved for pending data frames. This wasn't much of a problem with the slower 802.11b/g. We simply stopped the full queue and moved on to something different in the mean time. But - as you guessed it - this simple approach stands in way for a decent aggregation implementation. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index c7cba66..bb97981 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,6 +109,11 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; +#define AR9170_QUEUE_TIMEOUT 64 +#define AR9170_TX_TIMEOUT 8 +#define AR9170_JANITOR_DELAY 128 +#define AR9170_TX_INVALID_RATE 0xffffffff + struct ar9170 { struct ieee80211_hw *hw; struct mutex mutex; @@ -117,10 +122,11 @@ struct ar9170 { int (*open)(struct ar9170 *); void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int); + int (*tx)(struct ar9170 *, struct sk_buff *); int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , void *, u32 , void *); void (*callback_cmd)(struct ar9170 *, u32 , void *); + int (*flush)(struct ar9170 *); /* interface mode settings */ struct ieee80211_vif *vif; @@ -177,10 +183,10 @@ struct ar9170 { struct ar9170_eeprom eeprom; struct ath_regulatory regulatory; - /* global tx status for unregistered Stations. */ - struct sk_buff_head global_tx_status; - struct sk_buff_head global_tx_status_waste; - struct delayed_work tx_status_janitor; + /* tx queues - as seen by hw - */ + struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; + struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; + struct delayed_work tx_janitor; /* rxstream mpdu merge */ struct ar9170_rxstream_mpdu_merge rx_mpdu; @@ -189,11 +195,19 @@ struct ar9170 { }; struct ar9170_sta_info { - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; }; -#define IS_STARTED(a) (a->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) +#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) +#define AR9170_TX_FLAG_NO_ACK BIT(1) +#define AR9170_TX_FLAG_BLOCK_ACK BIT(2) + +struct ar9170_tx_info { + unsigned long timeout; + unsigned int flags; +}; + +#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) +#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) #define AR9170_FILTER_CHANGED_MODE BIT(0) #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) @@ -204,9 +218,9 @@ void *ar9170_alloc(size_t priv_size); int ar9170_register(struct ar9170 *ar, struct device *pdev); void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); void ar9170_unregister(struct ar9170 *ar); -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool update_statistics, u16 tx_status); +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); +int ar9170_nag_limiter(struct ar9170 *ar); /* MAC */ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 3c8004f..6cbfb2f 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -420,4 +420,7 @@ enum ar9170_txq { __AR9170_NUM_TXQ, }; +#define AR9170_TXQ_DEPTH 32 +#define AR9170_TX_MAX_PENDING 128 + #endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index de57aa9..9d38cf6 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -173,59 +173,122 @@ static struct ieee80211_supported_band ar9170_band_5GHz = { .ht_cap = AR9170_HT_CAP, }; -#ifdef AR9170_QUEUE_DEBUG -/* - * In case some wants works with AR9170's crazy tx_status queueing techniques. - * He might need this rather useful probing function. - * - * NOTE: caller must hold the queue's spinlock! - */ +static void ar9170_tx(struct ar9170 *ar); +#ifdef AR9170_QUEUE_DEBUG static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; - printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " - "mac_control:%04x, phy_control:%08x]\n", + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x " + "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), - le32_to_cpu(txc->phy_control)); + ieee80211_get_DA(hdr), arinfo->flags, + le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), + jiffies_to_msecs(arinfo->timeout - jiffies)); } -static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, - struct sk_buff_head *queue) +static void __ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) { struct sk_buff *skb; int i = 0; printk(KERN_DEBUG "---[ cut here ]---\n"); - printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", + printk(KERN_DEBUG "%s: %d entries in queue.\n", wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; - - printk(KERN_DEBUG "index:%d => \n", i); + printk(KERN_DEBUG "index:%d => \n", i++); ar9170_print_txheader(ar, skb); } + if (i != skb_queue_len(queue)) + printk(KERN_DEBUG "WARNING: queue frame counter " + "mismatch %d != %d\n", skb_queue_len(queue), i); printk(KERN_DEBUG "---[ end ]---\n"); } -#endif /* AR9170_QUEUE_DEBUG */ -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool valid_status, u16 tx_status) +static void ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) +{ + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + __ar9170_dump_txqueue(ar, queue); + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void __ar9170_dump_txstats(struct ar9170 *ar) +{ + int i; + + printk(KERN_DEBUG "%s: QoS queue stats\n", + wiphy_name(ar->hw->wiphy)); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) + printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n", + wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit, + ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i])); +} + +static void ar9170_dump_txstats(struct ar9170 *ar) { - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0, queue = skb_get_queue_mapping(skb); unsigned long flags; spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - if (ieee80211_queue_stopped(ar->hw, queue)) - ieee80211_wake_queue(ar->hw, queue); + __ar9170_dump_txstats(ar); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); +} +#endif /* AR9170_QUEUE_DEBUG */ + +/* caller must guarantee exclusive access for _bin_ queue. */ +static void ar9170_recycle_expired(struct ar9170 *ar, + struct sk_buff_head *queue, + struct sk_buff_head *bin) +{ + struct sk_buff *skb, *old = NULL; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + while ((skb = skb_peek(queue))) { + struct ieee80211_tx_info *txinfo; + struct ar9170_tx_info *arinfo; + + txinfo = IEEE80211_SKB_CB(skb); + arinfo = (void *) txinfo->rate_driver_data; + + if (time_is_before_jiffies(arinfo->timeout)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => " + "recycle \n", wiphy_name(ar->hw->wiphy), + jiffies, arinfo->timeout); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + __skb_unlink(skb, queue); + __skb_queue_tail(bin, skb); + } else { + break; + } + + if (unlikely(old == skb)) { + /* bail out - queue is shot. */ + + WARN_ON(1); + break; + } + old = skb; + } + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, + u16 tx_status) +{ + struct ieee80211_tx_info *txinfo; + unsigned int retries = 0; txinfo = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(txinfo); @@ -247,45 +310,61 @@ void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, break; } - if (valid_status) - txinfo->status.rates[0].count = retries + 1; - + txinfo->status.rates[0].count = retries + 1; skb_pull(skb, sizeof(struct ar9170_tx_control)); ieee80211_tx_status_irqsafe(ar->hw, skb); } -static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, - const u8 *mac, - const u32 queue, - struct sk_buff_head *q) +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; + unsigned int queue = skb_get_queue_mapping(skb); unsigned long flags; - struct sk_buff *skb; - spin_lock_irqsave(&q->lock, flags); - skb_queue_walk(q, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 txc_queue = (le32_to_cpu(txc->phy_control) & - AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[queue].len--; - if ((queue != txc_queue) || - (compare_ether_addr(ieee80211_get_DA(hdr), mac))) - continue; + if (skb_queue_empty(&ar->tx_pending[queue])) { +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), queue); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ + ieee80211_wake_queue(ar->hw, queue); + } + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - __skb_unlink(skb, q); - spin_unlock_irqrestore(&q->lock, flags); - return skb; + if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { + dev_kfree_skb_any(skb); + } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + + skb_queue_tail(&ar->tx_status[queue], skb); + } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) { + ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); + } else { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: unsupported frame flags!\n", + wiphy_name(ar->hw->wiphy)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + dev_kfree_skb_any(skb); + } + + if (!ar->tx_stats[queue].len && + !skb_queue_empty(&ar->tx_pending[queue])) { + ar9170_tx(ar); } - spin_unlock_irqrestore(&q->lock, flags); - return NULL; } -static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, - const u32 queue) +static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, + const u8 *mac, + struct sk_buff_head *queue, + const u32 rate) { - struct ieee80211_sta *sta; + unsigned long flags; struct sk_buff *skb; /* @@ -296,78 +375,91 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, * the firmware provided (-> destination MAC, and phy_control) - * and hope that we picked the right one... */ - rcu_read_lock(); - sta = ieee80211_find_sta(ar->hw, mac); - - if (likely(sta)) { - struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; - skb = skb_dequeue(&sta_priv->tx_status[queue]); - rcu_read_unlock(); - if (likely(skb)) - return skb; - } else - rcu_read_unlock(); - - /* scan the waste queue for candidates */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status_waste); - if (!skb) { - /* so it still _must_ be in the global list. */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status); - } + spin_lock_irqsave(&queue->lock, flags); + skb_queue_walk(queue, skb) { + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + u32 r; + + if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { #ifdef AR9170_QUEUE_DEBUG - if (unlikely((!skb) && net_ratelimit())) { - printk(KERN_ERR "%s: ESS:[%pM] does not have any " - "outstanding frames in this queue (%d).\n", - wiphy_name(ar->hw->wiphy), mac, queue); + printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n", + wiphy_name(ar->hw->wiphy), mac, + ieee80211_get_DA(hdr)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> + AR9170_TX_PHY_MCS_SHIFT; + + if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n", + wiphy_name(ar->hw->wiphy), rate, r); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + __skb_unlink(skb, queue); + spin_unlock_irqrestore(&queue->lock, flags); + return skb; } + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_ERR "%s: ESS:[%pM] does not have any " + "outstanding frames in queue.\n", + wiphy_name(ar->hw->wiphy), mac); + __ar9170_dump_txqueue(ar, queue); #endif /* AR9170_QUEUE_DEBUG */ - return skb; + spin_unlock_irqrestore(&queue->lock, flags); + + return NULL; } /* - * This worker tries to keep the global tx_status queue empty. - * So we can guarantee that incoming tx_status reports for - * unregistered stations are always synced with the actual - * frame - which we think - belongs to. + * This worker tries to keeps an maintain tx_status queues. + * So we can guarantee that incoming tx_status reports are + * actually for a pending frame. */ -static void ar9170_tx_status_janitor(struct work_struct *work) +static void ar9170_tx_janitor(struct work_struct *work) { struct ar9170 *ar = container_of(work, struct ar9170, - tx_status_janitor.work); - struct sk_buff *skb; + tx_janitor.work); + struct sk_buff_head waste; + unsigned int i; + bool resched = false; if (unlikely(!IS_STARTED(ar))) return ; - /* recycle the garbage back to mac80211... one by one. */ - while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { + skb_queue_head_init(&waste); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { #ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: dispose queued frame =>\n", - wiphy_name(ar->hw->wiphy)); - ar9170_print_txheader(ar, skb); + printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); #endif /* AR9170_QUEUE_DEBUG */ - ar9170_handle_tx_status(ar, skb, false, - AR9170_TX_STATUS_FAILED); - } - while ((skb = skb_dequeue(&ar->global_tx_status))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", - wiphy_name(ar->hw->wiphy)); + ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); + ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); + skb_queue_purge(&waste); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status_waste, skb); + if (!skb_queue_empty(&ar->tx_status[i]) || + !skb_queue_empty(&ar->tx_pending[i])) + resched = true; } - /* recall the janitor in 100ms - if there's garbage in the can. */ - if (skb_queue_len(&ar->global_tx_status_waste) > 0) - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); + if (resched) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) @@ -394,15 +486,21 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) */ struct sk_buff *skb; - u32 queue = (le32_to_cpu(cmd->tx_status.rate) & - AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; + u32 phy = le32_to_cpu(cmd->tx_status.rate); + u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> + AR9170_TX_PHY_QOS_SHIFT; +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n", + wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q); +#endif /* AR9170_QUEUE_DEBUG */ - skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); + skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, + &ar->tx_status[q], + AR9170_TX_INVALID_RATE); if (unlikely(!skb)) return ; - ar9170_handle_tx_status(ar, skb, true, - le16_to_cpu(cmd->tx_status.status)); + ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); break; } @@ -487,7 +585,7 @@ static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) ar->rx_mpdu.has_plcp = false; } -static int ar9170_nag_limiter(struct ar9170 *ar) +int ar9170_nag_limiter(struct ar9170 *ar) { bool print_message; @@ -988,8 +1086,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw) /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) - ar->tx_stats[i].limit = 8; + for (i = 0; i < __AR9170_NUM_TXQ; i++) + ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; /* reset QoS defaults */ AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ @@ -1035,18 +1133,17 @@ out: static void ar9170_op_stop(struct ieee80211_hw *hw) { struct ar9170 *ar = hw->priv; + unsigned int i; if (IS_STARTED(ar)) ar->state = AR9170_IDLE; flush_workqueue(ar->hw->workqueue); - cancel_delayed_work_sync(&ar->tx_status_janitor); + cancel_delayed_work_sync(&ar->tx_janitor); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); - skb_queue_purge(&ar->global_tx_status_waste); - skb_queue_purge(&ar->global_tx_status); if (IS_ACCEPTING_CMD(ar)) { ar9170_set_leds_state(ar, 0); @@ -1056,51 +1153,32 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) ar->stop(ar); } + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_purge(&ar->tx_pending[i]); + skb_queue_purge(&ar->tx_status[i]); + } mutex_unlock(&ar->mutex); } -int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) { - struct ar9170 *ar = hw->priv; struct ieee80211_hdr *hdr; struct ar9170_tx_control *txc; struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; struct ieee80211_tx_rate *txrate; + struct ar9170_tx_info *arinfo; unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags = 0; - struct ar9170_sta_info *sta_info = NULL; - u32 power, chains; u16 keytype = 0; u16 len, icv = 0; - int err; - bool tx_status; - if (unlikely(!IS_STARTED(ar))) - goto err_free; + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); hdr = (void *)skb->data; info = IEEE80211_SKB_CB(skb); len = skb->len; - spin_lock_irqsave(&ar->tx_stats_lock, flags); - if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - return NETDEV_TX_OK; - } - - ar->tx_stats[queue].len++; - ar->tx_stats[queue].count++; - if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) - ieee80211_stop_queue(hw, queue); - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - txc = (void *)skb_push(skb, sizeof(*txc)); - tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || - ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); - if (info->control.hw_key) { icv = info->control.hw_key->icv_len; @@ -1116,7 +1194,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) break; default: WARN_ON(1); - goto err_dequeue; + goto err_out; } } @@ -1133,16 +1211,65 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_NO_ACK) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - txrate = &info->control.rates[0]; - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); + arinfo = (void *)info->rate_driver_data; + arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (unlikely(!info->control.sta)) + goto err_out; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); + arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; + goto out; + } + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); + /* + * WARNING: + * Putting the QoS queue bits into an unexplored territory is + * certainly not elegant. + * + * In my defense: This idea provides a reasonable way to + * smuggle valuable information to the tx_status callback. + * Also, the idea behind this bit-abuse came straight from + * the original driver code. + */ + + txc->phy_control |= + cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK; + } else { + arinfo->flags = AR9170_TX_FLAG_NO_ACK; + } + +out: + return 0; + +err_out: + skb_pull(skb, sizeof(*txc)); + return -EINVAL; +} + +static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc; + struct ieee80211_tx_info *info; + struct ieee80211_rate *rate = NULL; + struct ieee80211_tx_rate *txrate; + u32 power, chains; + + txc = (void *) skb->data; + info = IEEE80211_SKB_CB(skb); + txrate = &info->control.rates[0]; + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); @@ -1162,9 +1289,12 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) u32 r = txrate->idx; u8 *txpower; + /* heavy clip control */ + txc->phy_control |= cpu_to_le32((r & 0x7) << 7); + r <<= AR9170_TX_PHY_MCS_SHIFT; - if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) - goto err_dequeue; + BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); + txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); @@ -1226,53 +1356,154 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) chains = AR9170_TX_PHY_TXCHAIN_1; } txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); +} - if (tx_status) { - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ +static void ar9170_tx(struct ar9170 *ar) +{ + struct sk_buff *skb; + unsigned long flags; + struct ieee80211_tx_info *info; + struct ar9170_tx_info *arinfo; + unsigned int i, frames, frames_failed, remaining_space; + int err; + bool schedule_garbagecollector = false; - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - if (info->control.sta) { - sta_info = (void *) info->control.sta->drv_priv; - skb_queue_tail(&sta_info->tx_status[queue], skb); - } else { - skb_queue_tail(&ar->global_tx_status, skb); + if (unlikely(!IS_STARTED(ar))) + return ; + + remaining_space = AR9170_TX_MAX_PENDING; + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + spin_lock_irqsave(&ar->tx_stats_lock, flags); + if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: queue %d full\n", + wiphy_name(ar->hw->wiphy), i); + + __ar9170_dump_txstats(ar); + printk(KERN_DEBUG "stuck frames: ===> \n"); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); +#endif /* AR9170_QUEUE_DEBUG */ + ieee80211_stop_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + continue; + } - queue_delayed_work(ar->hw->workqueue, - &ar->tx_status_janitor, - msecs_to_jiffies(100)); + frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, + skb_queue_len(&ar->tx_pending[i])); + + if (remaining_space < frames) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: tx quota reached queue:%d, " + "remaining slots:%d, needed:%d\n", + wiphy_name(ar->hw->wiphy), i, remaining_space, + frames); + + ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_DEBUG */ + frames = remaining_space; + } + + ar->tx_stats[i].len += frames; + ar->tx_stats[i].count += frames; + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + + if (!frames) + continue; + + frames_failed = 0; + while (frames) { + skb = skb_dequeue(&ar->tx_pending[i]); + if (unlikely(!skb)) { + frames_failed += frames; + frames = 0; + break; + } + + info = IEEE80211_SKB_CB(skb); + arinfo = (void *) info->rate_driver_data; + + /* TODO: cancel stuck frames */ + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: send frame q:%d =>\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + + err = ar->tx(ar, skb); + if (unlikely(err)) { + frames_failed++; + dev_kfree_skb_any(skb); + } else { + remaining_space--; + schedule_garbagecollector = true; + } + + frames--; + } + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: ar9170_tx report for queue %d\n", + wiphy_name(ar->hw->wiphy), i); + + printk(KERN_DEBUG "%s: unprocessed pending frames left:\n", + wiphy_name(ar->hw->wiphy)); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); +#endif /* AR9170_QUEUE_DEBUG */ + + if (unlikely(frames_failed)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: frames failed =>\n", + wiphy_name(ar->hw->wiphy), frames_failed); +#endif /* AR9170_QUEUE_DEBUG */ + + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[i].len -= frames_failed; + ar->tx_stats[i].count -= frames_failed; + ieee80211_wake_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); } } - err = ar->tx(ar, skb, tx_status, 0); - if (unlikely(tx_status && err)) { - if (info->control.sta) - skb_unlink(skb, &sta_info->tx_status[queue]); - else - skb_unlink(skb, &ar->global_tx_status); + if (schedule_garbagecollector) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); +} + +int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ar9170 *ar = hw->priv; + struct ieee80211_tx_info *info; + + if (unlikely(!IS_STARTED(ar))) + goto err_free; + + if (unlikely(ar9170_tx_prepare(ar, skb))) + goto err_free; + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + /* drop frame, we do not allow TX A-MPDU aggregation yet. */ + goto err_free; + } else { + unsigned int queue = skb_get_queue_mapping(skb); + + ar9170_tx_prepare_phy(ar, skb); + skb_queue_tail(&ar->tx_pending[queue], skb); } + ar9170_tx(ar); return NETDEV_TX_OK; -err_dequeue: - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - ar->tx_stats[queue].count--; - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - err_free: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1698,43 +1929,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ar9170 *ar = hw->priv; - struct ar9170_sta_info *info = (void *) sta->drv_priv; - struct sk_buff *skb; - unsigned int i; - - switch (cmd) { - case STA_NOTIFY_ADD: - for (i = 0; i < ar->hw->queues; i++) - skb_queue_head_init(&info->tx_status[i]); - break; - - case STA_NOTIFY_REMOVE: - - /* - * transfer all outstanding frames that need a tx_status - * reports to the global tx_status queue - */ - - for (i = 0; i < ar->hw->queues; i++) { - while ((skb = skb_dequeue(&info->tx_status[i]))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: queueing frame in " - "global tx_status queue =>\n", - wiphy_name(ar->hw->wiphy)); - - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status, skb); - } - } - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - break; - - default: - break; - } } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -1773,7 +1967,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, int ret; mutex_lock(&ar->mutex); - if ((param) && !(queue > ar->hw->queues)) { + if ((param) && !(queue > __AR9170_NUM_TXQ)) { memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], param, sizeof(*param)); @@ -1849,12 +2043,14 @@ void *ar9170_alloc(size_t priv_size) mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); - skb_queue_head_init(&ar->global_tx_status); - skb_queue_head_init(&ar->global_tx_status_waste); + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_head_init(&ar->tx_status[i]); + skb_queue_head_init(&ar->tx_pending[i]); + } ar9170_rx_reset_rx_mpdu(ar); INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); + INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); /* all hw supports 2.4 GHz, so set channel to 1 by default */ ar->channel = &ar9170_2ghz_chantable[0]; diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index f752698..754b1f8 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -96,7 +96,49 @@ static struct usb_device_id ar9170_usb_ids[] = { }; MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); -static void ar9170_usb_tx_urb_complete_free(struct urb *urb) +static void ar9170_usb_submit_urb(struct ar9170_usb *aru) +{ + struct urb *urb; + unsigned long flags; + int err; + + if (unlikely(!IS_STARTED(&aru->common))) + return ; + + spin_lock_irqsave(&aru->tx_urb_lock, flags); + if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) { + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + return ; + } + aru->tx_submitted_urbs++; + + urb = usb_get_from_anchor(&aru->tx_pending); + if (!urb) { + aru->tx_submitted_urbs--; + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + return ; + } + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + aru->tx_pending_urbs--; + usb_anchor_urb(urb, &aru->tx_submitted); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err)) { + if (ar9170_nag_limiter(&aru->common)) + dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", + err); + + usb_unanchor_urb(urb); + aru->tx_submitted_urbs--; + ar9170_tx_callback(&aru->common, urb->context); + } + + usb_free_urb(urb); +} + +static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) { struct sk_buff *skb = urb->context; struct ar9170_usb *aru = (struct ar9170_usb *) @@ -107,8 +149,11 @@ static void ar9170_usb_tx_urb_complete_free(struct urb *urb) return ; } - ar9170_handle_tx_status(&aru->common, skb, false, - AR9170_TX_STATUS_COMPLETE); + aru->tx_submitted_urbs--; + + ar9170_tx_callback(&aru->common, skb); + + ar9170_usb_submit_urb(aru); } static void ar9170_usb_tx_urb_complete(struct urb *urb) @@ -290,21 +335,47 @@ err_out: return err; } -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +static int ar9170_usb_flush(struct ar9170 *ar) { - int ret; + struct ar9170_usb *aru = (void *) ar; + struct urb *urb; + int ret, err = 0; - aru->common.state = AR9170_UNKNOWN_STATE; + if (IS_STARTED(ar)) + aru->common.state = AR9170_IDLE; - usb_unlink_anchored_urbs(&aru->tx_submitted); + usb_wait_anchor_empty_timeout(&aru->tx_pending, + msecs_to_jiffies(800)); + while ((urb = usb_get_from_anchor(&aru->tx_pending))) { + ar9170_tx_callback(&aru->common, (void *) urb->context); + usb_free_urb(urb); + } - /* give the LED OFF command and the deauth frame a chance to air. */ + /* lets wait a while until the tx - queues are dried out */ ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, msecs_to_jiffies(100)); if (ret == 0) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - usb_poison_anchored_urbs(&aru->tx_submitted); + err = -ETIMEDOUT; + + usb_kill_anchored_urbs(&aru->tx_submitted); + + if (IS_ACCEPTING_CMD(ar)) + aru->common.state = AR9170_STARTED; + + return err; +} + +static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +{ + int err; + aru->common.state = AR9170_UNKNOWN_STATE; + + err = ar9170_usb_flush(&aru->common); + if (err) + dev_err(&aru->udev->dev, "stuck tx urbs!\n"); + + usb_poison_anchored_urbs(&aru->tx_submitted); usb_poison_anchored_urbs(&aru->rx_submitted); } @@ -388,12 +459,10 @@ err_free: return err; } -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, - bool txstatus_needed, unsigned int extra_len) +static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_usb *aru = (struct ar9170_usb *) ar; struct urb *urb; - int err; if (unlikely(!IS_STARTED(ar))) { /* Seriously, what were you drink... err... thinking!? */ @@ -406,18 +475,17 @@ static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, usb_fill_bulk_urb(urb, aru->udev, usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len + extra_len, (txstatus_needed ? - ar9170_usb_tx_urb_complete : - ar9170_usb_tx_urb_complete_free), skb); + skb->data, skb->len, + ar9170_usb_tx_urb_complete_frame, skb); urb->transfer_flags |= URB_ZERO_PACKET; - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) - usb_unanchor_urb(urb); + usb_anchor_urb(urb, &aru->tx_pending); + aru->tx_pending_urbs++; usb_free_urb(urb); - return err; + + ar9170_usb_submit_urb(aru); + return 0; } static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) @@ -617,10 +685,8 @@ static void ar9170_usb_stop(struct ar9170 *ar) if (IS_ACCEPTING_CMD(ar)) aru->common.state = AR9170_STOPPED; - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(1000)); - if (ret == 0) + ret = ar9170_usb_flush(ar); + if (ret) dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); usb_poison_anchored_urbs(&aru->tx_submitted); @@ -716,10 +782,16 @@ static int ar9170_usb_probe(struct usb_interface *intf, SET_IEEE80211_DEV(ar->hw, &udev->dev); init_usb_anchor(&aru->rx_submitted); + init_usb_anchor(&aru->tx_pending); init_usb_anchor(&aru->tx_submitted); init_completion(&aru->cmd_wait); + spin_lock_init(&aru->tx_urb_lock); + + aru->tx_pending_urbs = 0; + aru->tx_submitted_urbs = 0; aru->common.stop = ar9170_usb_stop; + aru->common.flush = ar9170_usb_flush; aru->common.open = ar9170_usb_open; aru->common.tx = ar9170_usb_tx; aru->common.exec_cmd = ar9170_usb_exec_cmd; diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index 69f4bce..d098f4d 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -51,6 +51,7 @@ #include "ar9170.h" #define AR9170_NUM_RX_URBS 16 +#define AR9170_NUM_TX_URBS 8 struct firmware; @@ -60,11 +61,15 @@ struct ar9170_usb { struct usb_interface *intf; struct usb_anchor rx_submitted; + struct usb_anchor tx_pending; struct usb_anchor tx_submitted; bool req_one_stage_fw; - spinlock_t cmdlock; + spinlock_t tx_urb_lock; + unsigned int tx_submitted_urbs; + unsigned int tx_pending_urbs; + struct completion cmd_wait; int readlen; u8 *readbuf; -- cgit v0.10.2 From 207ee1621722876bb79828689582bf77fd1be200 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 12:26:52 +0200 Subject: rfkill: print events when input handler is disabled/enabled It is useful for debugging when we know if something disabled the in-kernel rfkill input handler. Signed-off-by: Johannes Berg Acked-by: Marcel Holtmann Signed-off-by: John W. Linville diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 11b7314..e161ebc 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1134,7 +1134,8 @@ static int rfkill_fop_release(struct inode *inode, struct file *file) #ifdef CONFIG_RFKILL_INPUT if (data->input_handler) - atomic_dec(&rfkill_input_disabled); + if (atomic_dec_return(&rfkill_input_disabled) == 0) + printk(KERN_DEBUG "rfkill: input handler enabled\n"); #endif kfree(data); @@ -1157,7 +1158,8 @@ static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, mutex_lock(&data->mtx); if (!data->input_handler) { - atomic_inc(&rfkill_input_disabled); + if (atomic_inc_return(&rfkill_input_disabled) == 1) + printk(KERN_DEBUG "rfkill: input handler disabled\n"); data->input_handler = true; } -- cgit v0.10.2 From e6a3b61681dcb963e6465ffbc4330b44824f35e3 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Tue, 9 Jun 2009 17:33:27 +0200 Subject: ath5k: added cfg80211 based rfkill support This patch introduces initial rfkill support for the ath5k driver based on rfkill support in the cfg80211 framework. All rfkill related code is separated into newly created rfkill.c. Changes to existing code are minimal: * added a new data structure ath5k_rfkill to the ath5k_softc structure * inserted calls to HW rfkill init/deinit routines * ath5k_intr() has been extended to handle AR5K_INT_GPIO interrupts Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 509b6f9..4863f4b 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -39,3 +39,11 @@ config ATH5K_DEBUG modprobe ath5k debug=0x00000400 +config ATH5K_RFKILL + bool "Atheros 5xxx rfkill support" + depends on ATH5K + default y + ---help--- + Include support for enabling/disabling WiFi via rfkill switch + with Atheros 5xxx cards + diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index 84a74c5..f1e281c 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -12,4 +12,5 @@ ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o +ath5k-$(CONFIG_ATH5K_RFKILL) += rfkill.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 8137182..4c84e30 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1256,6 +1256,15 @@ 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); +/* rfkill Functions */ +#ifdef CONFIG_ATH5K_RFKILL +extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); +extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); +#else +static inline void ath5k_rfkill_hw_start(struct ath5k_hw *ah) {} +static inline void ath5k_rfkill_hw_stop(struct ath5k_hw *ah) {} +#endif + /* 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); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 85a00db..f55675c 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2360,6 +2360,8 @@ ath5k_init(struct ath5k_softc *sc) if (ret) goto done; + ath5k_rfkill_hw_start(ah); + /* * Reset the key cache since some parts do not reset the * contents on initial power up or resume from suspend. @@ -2468,6 +2470,8 @@ ath5k_stop_hw(struct ath5k_softc *sc) tasklet_kill(&sc->restq); tasklet_kill(&sc->beacontq); + ath5k_rfkill_hw_stop(sc->ah); + return ret; } @@ -2526,6 +2530,12 @@ ath5k_intr(int irq, void *dev_id) */ ath5k_hw_update_mib_counters(ah, &sc->ll_stats); } +#ifdef CONFIG_ATH5K_RFKILL + if (status & AR5K_INT_GPIO) + { + tasklet_schedule(&sc->rf_kill.toggleq); + } +#endif } } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 852b2c1..7a0ecdd 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -46,6 +46,7 @@ #include #include #include +#include #include "ath5k.h" #include "debug.h" @@ -91,6 +92,15 @@ struct ath5k_led struct led_classdev led_dev; /* led classdev */ }; +/* Rfkill */ +struct ath5k_rfkill { + /* GPIO PIN for rfkill */ + u16 gpio; + /* polarity of rfkill GPIO PIN */ + bool polarity; + /* RFKILL toggle tasklet */ + struct tasklet_struct toggleq; +}; #if CHAN_DEBUG #define ATH_CHAN_MAX (26+26+26+200+200) @@ -167,6 +177,10 @@ struct ath5k_softc { struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ +#ifdef CONFIG_ATH5K_RFKILL + struct ath5k_rfkill rf_kill; +#endif + spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct ath5k_buf *bbuf; /* beacon buffer */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 6606773..bd0a97a 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1304,23 +1304,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ah->ah_version != AR5K_AR5210) ath5k_hw_set_imr(ah, ah->ah_imr); - /* - * Setup RFKill interrupt if rfkill flag is set on eeprom. - * TODO: Use gpio pin and polarity infos from eeprom - * TODO: Handle this in ath5k_intr because it'll result - * a nasty interrupt storm. - */ -#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 - /* Enable 32KHz clock function for AR5212+ chips * Set clocks to 32KHz operation and use an * external 32KHz crystal when sleeping if one diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c new file mode 100644 index 0000000..492ada9 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/rfkill.c @@ -0,0 +1,121 @@ +/* + * RFKILL support for ath5k + * + * Copyright (c) 2009 Tobias Doerffel + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "base.h" + + +static inline void ath5k_rfkill_disable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill disable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity); +} + + +static inline void ath5k_rfkill_enable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill enable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity); +} + +static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable) +{ + struct ath5k_hw *ah = sc->ah; + ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio); + ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ? + !!ah->ah_gpio[0] : !ah->ah_gpio[0]); +} + +static bool +ath5k_is_rfkill_set(struct ath5k_softc *sc) +{ + /* configuring GPIO for input for some reason disables rfkill */ + /*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/ + return ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) == + sc->rf_kill.polarity; +} + +static void +ath5k_tasklet_rfkill_toggle(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + bool blocked; + + blocked = ath5k_is_rfkill_set(sc); + wiphy_rfkill_set_hw_state(sc->hw->wiphy, blocked); +} + + +void +ath5k_rfkill_hw_start(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* read rfkill GPIO configuration from EEPROM header */ + sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin; + sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol; + + tasklet_init(&sc->rf_kill.toggleq, ath5k_tasklet_rfkill_toggle, + (unsigned long)sc); + + ath5k_rfkill_disable(sc); + + /* enable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + ath5k_rfkill_set_intr(sc, true); + } +} + + +void +ath5k_rfkill_hw_stop(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* disable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + ath5k_rfkill_set_intr(sc, false); + } + + tasklet_kill(&sc->rf_kill.toggleq); + + /* enable RFKILL when stopping HW so Wifi LED is turned off */ + ath5k_rfkill_enable(sc); +} + -- cgit v0.10.2 From f41f3f373dd72344c65d801d6381fe83ef3a2c54 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 12:30:34 -0500 Subject: b43/legacy: port to cfg80211 rfkill This ports the b43/legacy rfkill code to the new API offered by cfg80211 and thus removes a lot of useless stuff. Signed-off-by: Johannes Berg Signed-off-by: Larry Finger Cc: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 07a99e3..67f564e 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -98,13 +98,6 @@ config B43_LEDS depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43) default y -# This config option automatically enables b43 RFKILL support, -# if it's possible. -config B43_RFKILL - bool - depends on B43 && (RFKILL = y || RFKILL = B43) - default y - # This config option automatically enables b43 HW-RNG support, # if the HW-RNG core is enabled. config B43_HWRNG diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 281ef83..da379f4 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -13,7 +13,7 @@ b43-y += lo.o b43-y += wa.o b43-y += dma.o b43-$(CONFIG_B43_PIO) += pio.o -b43-$(CONFIG_B43_RFKILL) += rfkill.o +b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o b43-$(CONFIG_B43_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 4e8ad84..75aede0 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -631,9 +631,6 @@ struct b43_wl { char rng_name[30 + 1]; #endif /* CONFIG_B43_HWRNG */ - /* The RF-kill button */ - struct b43_rfkill rfkill; - /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 9a498d3..c8b3170 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -28,6 +28,7 @@ #include "b43.h" #include "leds.h" +#include "rfkill.h" static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, @@ -164,10 +165,10 @@ static void b43_map_led(struct b43_wldev *dev, snprintf(name, sizeof(name), "b43-%s::radio", wiphy_name(hw->wiphy)); b43_register_led(dev, &dev->led_radio, name, - b43_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) b43_led_turn_on(dev, led_index, activelow); break; case B43_LED_WEIRD: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1d3e400..5d9f198 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4298,7 +4298,6 @@ static int b43_op_start(struct ieee80211_hw *hw) struct b43_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -4312,18 +4311,12 @@ static int b43_op_start(struct ieee80211_hw *hw) wl->beacon1_uploaded = 0; wl->beacon_templates_virgin = 1; - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43_rfkill_init(dev); - mutex_lock(&wl->mutex); if (b43_status(dev) < B43_STAT_INITIALIZED) { err = b43_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -4332,17 +4325,16 @@ static int b43_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + /* XXX: only do if device doesn't support rfkill irq */ + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43_rfkill_exit(dev); - return err; } @@ -4351,7 +4343,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - b43_rfkill_exit(dev); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -4433,6 +4424,7 @@ static const struct ieee80211_ops b43_hw_ops = { .sta_notify = b43_op_sta_notify, .sw_scan_start = b43_op_sw_scan_start_notifier, .sw_scan_complete = b43_op_sw_scan_complete_notifier, + .rfkill_poll = b43_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. @@ -4920,7 +4912,7 @@ static struct ssb_driver b43_ssb_driver = { static void b43_print_driverinfo(void) { const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", - *feat_leds = "", *feat_rfkill = ""; + *feat_leds = ""; #ifdef CONFIG_B43_PCI_AUTOSELECT feat_pci = "P"; @@ -4934,14 +4926,11 @@ static void b43_print_driverinfo(void) #ifdef CONFIG_B43_LEDS feat_leds = "L"; #endif -#ifdef CONFIG_B43_RFKILL - feat_rfkill = "R"; -#endif printk(KERN_INFO "Broadcom 43xx driver loaded " - "[ Features: %s%s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s, Firmware-ID: " B43_SUPPORTED_FIRMWARE_ID " ]\n", feat_pci, feat_pcmcia, feat_nphy, - feat_leds, feat_rfkill); + feat_leds); } static int __init b43_init(void) diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index f4c2d79..44cc918 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -1,7 +1,7 @@ #ifndef LINUX_B43_PHY_COMMON_H_ #define LINUX_B43_PHY_COMMON_H_ -#include +#include struct b43_wldev; diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 9604784..31e5599 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -22,15 +22,11 @@ */ -#include "rfkill.h" #include "b43.h" -#include "phy_common.h" - -#include /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) +bool b43_is_hw_radio_enabled(struct b43_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) @@ -45,110 +41,39 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43_rfkill_poll(struct rfkill *rfkill, void *data) +void b43_rfkill_poll(struct ieee80211_hw *hw) { - struct b43_wldev *dev = data; - struct b43_wl *wl = dev->wl; + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); - enabled = !rfkill_set_hw_state(rfkill, !enabled); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); if (enabled != dev->phy.radio_on) b43_software_rfkill(dev, !enabled); } - mutex_unlock(&wl->mutex); -} - -/* Called when the RFKILL toggled in software. */ -static int b43_rfkill_soft_set(void *data, bool blocked) -{ - struct b43_wldev *dev = data; - struct b43_wl *wl = dev->wl; - int err = -EINVAL; - - if (WARN_ON(!wl->rfkill.registered)) - return -EINVAL; - mutex_lock(&wl->mutex); - - if (b43_status(dev) < B43_STAT_INITIALIZED) - goto out_unlock; - - if (!dev->radio_hw_enable) - goto out_unlock; + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + } - if (!blocked != dev->phy.radio_on) - b43_software_rfkill(dev, blocked); - err = 0; -out_unlock: mutex_unlock(&wl->mutex); - return err; -} - -const char *b43_rfkill_led_name(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_trigger_name(rfk->rfkill); -} - -static const struct rfkill_ops b43_rfkill_ops = { - .set_block = b43_rfkill_soft_set, - .poll = b43_rfkill_poll, -}; - -void b43_rfkill_init(struct b43_wldev *dev) -{ - struct b43_wl *wl = dev->wl; - struct b43_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - snprintf(rfk->name, sizeof(rfk->name), - "b43-%s", wiphy_name(wl->hw->wiphy)); - - rfk->rfkill = rfkill_alloc(rfk->name, - dev->dev->dev, - RFKILL_TYPE_WLAN, - &b43_rfkill_ops, dev); - if (!rfk->rfkill) - goto out_error; - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free; - - rfk->registered = 1; - - return; - err_free: - rfkill_destroy(rfk->rfkill); - out_error: - rfk->registered = 0; - b43warn(wl, "RF-kill button init failed\n"); -} - -void b43_rfkill_exit(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - rfkill_unregister(rfk->rfkill); - rfkill_destroy(rfk->rfkill); - rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index da497e0..f046c3c 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h @@ -1,49 +1,11 @@ #ifndef B43_RFKILL_H_ #define B43_RFKILL_H_ +struct ieee80211_hw; struct b43_wldev; +void b43_rfkill_poll(struct ieee80211_hw *hw); -#ifdef CONFIG_B43_RFKILL - -#include - - -struct b43_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43_rfkill_init(struct b43_wldev *dev); -void b43_rfkill_exit(struct b43_wldev *dev); - -const char *b43_rfkill_led_name(struct b43_wldev *dev); - - -#else /* CONFIG_B43_RFKILL */ -/* No RFKILL support. */ - -struct b43_rfkill { - /* empty */ -}; - -static inline void b43_rfkill_init(struct b43_wldev *dev) -{ -} -static inline void b43_rfkill_exit(struct b43_wldev *dev) -{ -} -static inline char * b43_rfkill_led_name(struct b43_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43_RFKILL */ +bool b43_is_hw_radio_enabled(struct b43_wldev *dev); #endif /* B43_RFKILL_H_ */ diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 6893f43..94a4634 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -42,14 +42,6 @@ config B43LEGACY_LEDS depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) default y -# RFKILL support -# This config option automatically enables b43legacy RFKILL support, -# if it's possible. -config B43LEGACY_RFKILL - bool - depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) - default y - # This config option automatically enables b43 HW-RNG support, # if the HW-RNG core is enabled. config B43LEGACY_HWRNG diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile index 80cdb73..227a77e 100644 --- a/drivers/net/wireless/b43legacy/Makefile +++ b/drivers/net/wireless/b43legacy/Makefile @@ -6,7 +6,7 @@ b43legacy-y += radio.o b43legacy-y += sysfs.o b43legacy-y += xmit.o # b43 RFKILL button support -b43legacy-$(CONFIG_B43LEGACY_RFKILL) += rfkill.o +b43legacy-y += rfkill.o # b43legacy LED support b43legacy-$(CONFIG_B43LEGACY_LEDS) += leds.o # b43legacy debugging diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 19a4b0b..77fda14 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -602,9 +602,6 @@ struct b43legacy_wl { char rng_name[30 + 1]; #endif - /* The RF-kill button */ - struct b43legacy_rfkill rfkill; - /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 538d311..37e9be8 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -28,6 +28,7 @@ #include "b43legacy.h" #include "leds.h" +#include "rfkill.h" static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index, @@ -164,10 +165,10 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev, snprintf(name, sizeof(name), "b43legacy-%s::radio", wiphy_name(hw->wiphy)); b43legacy_register_led(dev, &dev->led_radio, name, - b43legacy_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43legacy_is_hw_radio_enabled(dev)) b43legacy_led_turn_on(dev, led_index, activelow); break; case B43legacy_LED_WEIRD: diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index f6f3fbf..e5136fb 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3431,11 +3431,6 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) struct b43legacy_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; - - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43legacy_rfkill_init(dev); /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -3451,10 +3446,8 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -3463,17 +3456,15 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43legacy_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43legacy_rfkill_exit(dev); - return err; } @@ -3482,7 +3473,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; - b43legacy_rfkill_exit(dev); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -3518,6 +3508,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .start = b43legacy_op_start, .stop = b43legacy_op_stop, .set_tim = b43legacy_op_beacon_set_tim, + .rfkill_poll = b43legacy_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index c6230a6..8783022 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -22,15 +22,12 @@ */ -#include "rfkill.h" #include "radio.h" #include "b43legacy.h" -#include - /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) @@ -45,23 +42,31 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) +void b43legacy_rfkill_poll(struct ieee80211_hw *hw) { - struct b43legacy_wldev *dev = data; - struct b43legacy_wl *wl = dev->wl; + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); - enabled = !rfkill_set_hw_state(rfkill, !enabled); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); if (enabled != dev->phy.radio_on) { if (enabled) b43legacy_radio_turn_on(dev); @@ -69,95 +74,11 @@ static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) b43legacy_radio_turn_off(dev, 0); } } - mutex_unlock(&wl->mutex); -} - -/* Called when the RFKILL toggled in software. - * This is called without locking. */ -static int b43legacy_rfkill_soft_set(void *data, bool blocked) -{ - struct b43legacy_wldev *dev = data; - struct b43legacy_wl *wl = dev->wl; - int ret = -EINVAL; - if (!wl->rfkill.registered) - return -EINVAL; - - mutex_lock(&wl->mutex); - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) - goto out_unlock; - - if (!dev->radio_hw_enable) - goto out_unlock; - - if (!blocked != dev->phy.radio_on) { - if (!blocked) - b43legacy_radio_turn_on(dev); - else - b43legacy_radio_turn_off(dev, 0); + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); } - ret = 0; -out_unlock: mutex_unlock(&wl->mutex); - return ret; -} - -const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_trigger_name(rfk->rfkill); } - -static const struct rfkill_ops b43legacy_rfkill_ops = { - .set_block = b43legacy_rfkill_soft_set, - .poll = b43legacy_rfkill_poll, -}; - -void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ - struct b43legacy_wl *wl = dev->wl; - struct b43legacy_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - snprintf(rfk->name, sizeof(rfk->name), - "b43legacy-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill = rfkill_alloc(rfk->name, - dev->dev->dev, - RFKILL_TYPE_WLAN, - &b43legacy_rfkill_ops, dev); - if (!rfk->rfkill) - goto out_error; - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free; - - rfk->registered = 1; - - return; - err_free: - rfkill_destroy(rfk->rfkill); - out_error: - rfk->registered = 0; - b43legacywarn(wl, "RF-kill button init failed\n"); -} - -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - rfkill_unregister(rfk->rfkill); - rfkill_destroy(rfk->rfkill); - rfk->rfkill = NULL; -} - diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h index adffc50..7558557 100644 --- a/drivers/net/wireless/b43legacy/rfkill.h +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -1,55 +1,11 @@ #ifndef B43legacy_RFKILL_H_ #define B43legacy_RFKILL_H_ +struct ieee80211_hw; struct b43legacy_wldev; -#ifdef CONFIG_B43LEGACY_RFKILL +void b43legacy_rfkill_poll(struct ieee80211_hw *hw); -#include - - - -struct b43legacy_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43legacy-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43legacy_rfkill_init(struct b43legacy_wldev *dev); -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); - -const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); - - -#else /* CONFIG_B43LEGACY_RFKILL */ -/* No RFKILL support. */ - -struct b43legacy_rfkill { - /* empty */ -}; - -static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ -} -static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43LEGACY_RFKILL */ +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev); #endif /* B43legacy_RFKILL_H_ */ -- cgit v0.10.2 From b91d0e364077fad401454699143ad6a78902c20a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 8 Jun 2009 08:14:28 +0200 Subject: rfkill: remove input Kconfig Now that we added the ioctl, there's no need to ask the user to configure this. We will keep it enabled for now, and eventually swap the default to n. Also let embedded users select it only if they need it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index fd7600d..eaf7658 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -18,7 +18,7 @@ config RFKILL_LEDS default y config RFKILL_INPUT - bool "RF switch input support" + bool "RF switch input support" if EMBEDDED depends on RFKILL depends on INPUT = y || RFKILL = INPUT default y if !EMBEDDED -- cgit v0.10.2 From fc240e3fc5791c572402b0857948da7b1e68d77f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 21:57:08 +0200 Subject: sony: fix rfkill code During the rfkill conversion I added code to call sony_nc_rfkill_set with the wrong argument, causing a segfault Reinette reported. The compiler could not catch that because the argument is, and needs to be, void *. Signed-off-by: Johannes Berg Reported-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index aec0b27..f289344 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1135,8 +1135,7 @@ static void sony_nc_rfkill_update() if (hwblock) { if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) - sony_nc_rfkill_set(sony_rfkill_devices[i], - true); + sony_nc_rfkill_set((void *)i, true); continue; } -- cgit v0.10.2 From 8f77f3849cc3ae2d6df9301785a3d316ea7d7ee1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 21:58:37 +0200 Subject: mac80211: do not pass PS frames out of mac80211 again In order to handle powersave frames properly we had needed to pass these out to the device queues again, and introduce the skb->requeue bit. This, however, also has unnecessary overhead by needing to 'clean up' already tried frames, and this clean-up code is also buggy when software encryption is used. Instead of sending the frames via the master netdev queue again, simply put them into the pending queue. This also fixes a problem where frames for that particular station could be reordered when some were still on the software queues and older ones are re-injected into the software queue after them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f1c93b8..fa51293 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -304,9 +304,6 @@ typedef unsigned char *sk_buff_data_t; * @tc_verd: traffic control verdict * @ndisc_nodetype: router type (from link layer) * @do_not_encrypt: set to prevent encryption of this frame - * @requeue: set to indicate that the wireless core should attempt - * a software retry on this frame if we failed to - * receive an ACK for it * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking @@ -380,7 +377,6 @@ struct sk_buff { #endif #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) __u8 do_not_encrypt:1; - __u8 requeue:1; #endif /* 0/13/14 bit hole */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 17d61d1..c061044 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -239,6 +239,8 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, * used to indicate that a pending frame requires TX processing before * it can be sent out. + * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, + * used to indicate that a frame was already retried due to PS */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -256,6 +258,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), IEEE80211_TX_INTFL_RCALGO = BIT(13), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), + IEEE80211_TX_INTFL_RETRIED = BIT(15), }; /** diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 49961ba..b94d777 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -552,7 +552,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->vlan_tci = old->vlan_tci; #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) new->do_not_encrypt = old->do_not_encrypt; - new->requeue = old->requeue; #endif skb_copy_secmark(new, old); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c088c46..4dbc289 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -589,6 +589,7 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_AGGREGATION, IEEE80211_QUEUE_STOP_REASON_SUSPEND, IEEE80211_QUEUE_STOP_REASON_PENDING, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; struct ieee80211_master_priv { @@ -1121,6 +1122,10 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, enum queue_stop_reason reason); void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, enum queue_stop_reason reason); +void ieee80211_add_pending_skb(struct ieee80211_local *local, + struct sk_buff *skb); +int ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs); void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2683df9..092a017 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -369,60 +369,12 @@ static void ieee80211_tasklet_handler(unsigned long data) } } -/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to - * make a prepared TX frame (one that has been given to hw) to look like brand - * new IEEE 802.11 frame that is ready to go through TX processing again. - */ -static void ieee80211_remove_tx_extra(struct ieee80211_local *local, - struct ieee80211_key *key, - struct sk_buff *skb) -{ - unsigned int hdrlen, iv_len, mic_len; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - if (!key) - goto no_key; - - switch (key->conf.alg) { - case ALG_WEP: - iv_len = WEP_IV_LEN; - mic_len = WEP_ICV_LEN; - break; - case ALG_TKIP: - iv_len = TKIP_IV_LEN; - mic_len = TKIP_ICV_LEN; - break; - case ALG_CCMP: - iv_len = CCMP_HDR_LEN; - mic_len = CCMP_MIC_LEN; - break; - default: - goto no_key; - } - - if (skb->len >= hdrlen + mic_len && - !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - skb_trim(skb, skb->len - mic_len); - if (skb->len >= hdrlen + iv_len) { - memmove(skb->data + iv_len, skb->data, hdrlen); - hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len); - } - -no_key: - if (ieee80211_is_data_qos(hdr->frame_control)) { - hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); - memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data, - hdrlen - IEEE80211_QOS_CTL_LEN); - skb_pull(skb, IEEE80211_QOS_CTL_LEN); - } -} - static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + sta->tx_filtered_count++; /* @@ -464,16 +416,15 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, */ if (test_sta_flags(sta, WLAN_STA_PS) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, skb); skb_queue_tail(&sta->tx_filtered, skb); return; } - if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { + if (!test_sta_flags(sta, WLAN_STA_PS) && + !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { /* Software retry the packet once */ - skb->requeue = 1; - ieee80211_remove_tx_extra(local, sta->key, skb); - dev_queue_xmit(skb); + info->flags |= IEEE80211_TX_INTFL_RETRIED; + ieee80211_add_pending_skb(local, skb); return; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7541251..de5bba7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -797,8 +797,7 @@ static int ap_sta_ps_end(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; - struct sk_buff *skb; - int sent = 0; + int sent, buffered; atomic_dec(&sdata->bss->num_sta_ps); @@ -814,22 +813,16 @@ static int ap_sta_ps_end(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Send all buffered frames to the station */ - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - sent++; - skb->requeue = 1; - dev_queue_xmit(skb); - } - while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - local->total_ps_buffered--; - sent++; + sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); + buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); + sent += buffered; + local->total_ps_buffered -= buffered; + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame " - "since STA not sleeping anymore\n", sdata->dev->name, - sta->sta.addr, sta->sta.aid); + printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " + "since STA not sleeping anymore\n", sdata->dev->name, + sta->sta.addr, sta->sta.aid, sent - buffered, buffered); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - skb->requeue = 1; - dev_queue_xmit(skb); - } return sent; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1436f74..bfaa9ce 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; } @@ -420,7 +421,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) * frame filtering and keeps a station blacklist on its own * (e.g: p54), so that frames can be delivered unimpeded. * - * Note: It should be save to disable the filter now. + * Note: It should be safe to disable the filter now. * As, it is really unlikely that we still have any pending * frame for this station in the hw's buffers/fifos left, * that is not rejected with a unsuccessful tx_status yet. diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22f6381..66ce96a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -341,6 +341,52 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) } EXPORT_SYMBOL(ieee80211_stop_queue); +void ieee80211_add_pending_skb(struct ieee80211_local *local, + struct sk_buff *skb) +{ + struct ieee80211_hw *hw = &local->hw; + unsigned long flags; + int queue = skb_get_queue_mapping(skb); + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING); + skb_queue_tail(&local->pending[queue], skb); + __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); +} + +int ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs) +{ + struct ieee80211_hw *hw = &local->hw; + struct sk_buff *skb; + unsigned long flags; + int queue, ret = 0, i; + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < hw->queues; i++) + __ieee80211_stop_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + + while ((skb = skb_dequeue(skbs))) { + ret++; + queue = skb_get_queue_mapping(skb); + skb_queue_tail(&local->pending[queue], skb); + } + + for (i = 0; i < hw->queues; i++) { + if (ret) + __ieee80211_stop_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_PENDING); + __ieee80211_wake_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + + return ret; +} + void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, enum queue_stop_reason reason) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 694343b..116a923 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -101,7 +101,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) * Now we know the 1d priority, fill in the QoS header if * there is one (and we haven't done this before). */ - if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *p = ieee80211_get_qos_ctl(hdr); u8 ack_policy = 0; tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -- cgit v0.10.2 From b3fa1329eaf2a7b97124dacf5b663fd51346ac19 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Mon, 8 Jun 2009 13:27:27 +0100 Subject: rfkill: remove set_global_sw_state rfkill_set_global_sw_state() (previously rfkill_set_default()) will no longer be exported by the rewritten rfkill core. Instead, platform drivers which can provide persistent soft-rfkill state across power-down/reboot should indicate their initial state by calling rfkill_set_sw_state() before registration. Otherwise, they will be initialized to a default value during registration by a set_block call. We remove existing calls to rfkill_set_sw_state() which happen before registration, since these had no effect in the old model. If these drivers do have persistent state, the calls can be put back (subject to testing :-). This affects hp-wmi and acer-wmi. Drivers with persistent state will affect the global state only if rfkill-input is enabled. This is required, otherwise booting with wireless soft-blocked and pressing the wireless-toggle key once would have no apparent effect. This special case will be removed in future along with rfkill-input, in favour of a more flexible userspace daemon (see Documentation/feature-removal-schedule.txt). Now rfkill_global_states[n].def is only used to preserve global states over EPO, it is renamed to ".sav". Signed-off-by: Alan Jenkins Acked-by: Henrique de Moraes Holschuh Signed-off-by: John W. Linville diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index b618fa5..09a503e5 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -988,7 +988,6 @@ static struct rfkill *acer_rfkill_register(struct device *dev, char *name, u32 cap) { int err; - u32 state; struct rfkill *rfkill_dev; rfkill_dev = rfkill_alloc(name, dev, type, @@ -996,8 +995,6 @@ static struct rfkill *acer_rfkill_register(struct device *dev, (void *)(unsigned long)cap); if (!rfkill_dev) return ERR_PTR(-ENOMEM); - get_u32(&state, cap); - rfkill_set_sw_state(rfkill_dev, !state); err = rfkill_register(rfkill_dev); if (err) { diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 1208d0c..03bf522 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -675,8 +675,8 @@ static int eeepc_hotk_add(struct acpi_device *device) if (!ehotk->eeepc_wlan_rfkill) goto wlan_fail; - rfkill_set_global_sw_state(RFKILL_TYPE_WLAN, - get_acpi(CM_ASL_WLAN) != 1); + rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, + get_acpi(CM_ASL_WLAN) != 1); result = rfkill_register(ehotk->eeepc_wlan_rfkill); if (result) goto wlan_fail; @@ -693,8 +693,8 @@ static int eeepc_hotk_add(struct acpi_device *device) if (!ehotk->eeepc_bluetooth_rfkill) goto bluetooth_fail; - rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH, - get_acpi(CM_ASL_BLUETOOTH) != 1); + rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill, + get_acpi(CM_ASL_BLUETOOTH) != 1); result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); if (result) goto bluetooth_fail; diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 8d93114..16fffe44 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -422,7 +422,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) RFKILL_TYPE_WLAN, &hp_wmi_rfkill_ops, (void *) 0); - rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state()); err = rfkill_register(wifi_rfkill); if (err) goto register_wifi_error; @@ -433,8 +432,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) RFKILL_TYPE_BLUETOOTH, &hp_wmi_rfkill_ops, (void *) 1); - rfkill_set_sw_state(bluetooth_rfkill, - hp_wmi_bluetooth_state()); err = rfkill_register(bluetooth_rfkill); if (err) goto register_bluetooth_error; @@ -445,7 +442,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) RFKILL_TYPE_WWAN, &hp_wmi_rfkill_ops, (void *) 2); - rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state()); err = rfkill_register(wwan_rfkill); if (err) goto register_wwan_err; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cfcafa4..86e9585 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1168,21 +1168,6 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); - initial_sw_status = (tp_rfkops->get_status)(); - if (initial_sw_status < 0) { - printk(TPACPI_ERR - "failed to read initial state for %s, error %d; " - "will turn radio off\n", name, initial_sw_status); - } else { - initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); - if (set_default) { - /* try to set the initial state as the default for the - * rfkill type, since we ask the firmware to preserve - * it across S5 in NVRAM */ - rfkill_set_global_sw_state(rfktype, initial_sw_state); - } - } - atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL); if (atp_rfk) atp_rfk->rfkill = rfkill_alloc(name, @@ -1200,8 +1185,20 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, atp_rfk->id = id; atp_rfk->ops = tp_rfkops; - rfkill_set_states(atp_rfk->rfkill, initial_sw_state, - tpacpi_rfk_check_hwblock_state()); + initial_sw_status = (tp_rfkops->get_status)(); + if (initial_sw_status < 0) { + printk(TPACPI_ERR + "failed to read initial state for %s, error %d\n", + name, initial_sw_status); + } else { + initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); + if (set_default) { + /* try to keep the initial state, since we ask the + * firmware to preserve it across S5 in NVRAM */ + rfkill_set_sw_state(atp_rfk->rfkill, initial_sw_state); + } + } + rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); res = rfkill_register(atp_rfk->rfkill); if (res < 0) { diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index d7e818a..c1dca0b 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -157,8 +157,14 @@ struct rfkill * __must_check rfkill_alloc(const char *name, * @rfkill: rfkill structure to be registered * * This function should be called by the transmitter driver to register - * the rfkill structure needs to be registered. Before calling this function - * the driver needs to be ready to service method calls from rfkill. + * the rfkill structure. Before calling this function the driver needs + * to be ready to service method calls from rfkill. + * + * If the software blocked state is not set before registration, + * set_block will be called to initialize it to a default value. + * + * If the hardware blocked state is not set before registration, + * it is assumed to be unblocked. */ int __must_check rfkill_register(struct rfkill *rfkill); @@ -251,19 +257,6 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked); void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw); /** - * rfkill_set_global_sw_state - set global sw block default - * @type: rfkill type to set default for - * @blocked: default to set - * - * This function sets the global default -- use at boot if your platform has - * an rfkill switch. If not early enough this call may be ignored. - * - * XXX: instead of ignoring -- how about just updating all currently - * registered drivers? - */ -void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked); - -/** * rfkill_blocked - query rfkill block * * @rfkill: rfkill struct to query @@ -317,11 +310,6 @@ static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) { } -static inline void rfkill_set_global_sw_state(const enum rfkill_type type, - bool blocked) -{ -} - static inline bool rfkill_blocked(struct rfkill *rfkill) { return false; diff --git a/net/rfkill/core.c b/net/rfkill/core.c index e161ebc..fa430bd 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -57,6 +57,7 @@ struct rfkill { bool registered; bool suspended; + bool persistent; const struct rfkill_ops *ops; void *data; @@ -116,11 +117,9 @@ MODULE_PARM_DESC(default_state, "Default initial state for all radio types, 0 = radio off"); static struct { - bool cur, def; + bool cur, sav; } rfkill_global_states[NUM_RFKILL_TYPES]; -static unsigned long rfkill_states_default_locked; - static bool rfkill_epo_lock_active; @@ -392,7 +391,7 @@ void rfkill_epo(void) rfkill_set_block(rfkill, true); for (i = 0; i < NUM_RFKILL_TYPES; i++) { - rfkill_global_states[i].def = rfkill_global_states[i].cur; + rfkill_global_states[i].sav = rfkill_global_states[i].cur; rfkill_global_states[i].cur = true; } @@ -417,7 +416,7 @@ void rfkill_restore_states(void) rfkill_epo_lock_active = false; for (i = 0; i < NUM_RFKILL_TYPES; i++) - __rfkill_switch_all(i, rfkill_global_states[i].def); + __rfkill_switch_all(i, rfkill_global_states[i].sav); mutex_unlock(&rfkill_global_mutex); } @@ -464,29 +463,6 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type) } #endif -void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked) -{ - BUG_ON(type == RFKILL_TYPE_ALL); - - mutex_lock(&rfkill_global_mutex); - - /* don't allow unblock when epo */ - if (rfkill_epo_lock_active && !blocked) - goto out; - - /* too late */ - if (rfkill_states_default_locked & BIT(type)) - goto out; - - rfkill_states_default_locked |= BIT(type); - - rfkill_global_states[type].cur = blocked; - rfkill_global_states[type].def = blocked; - out: - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL(rfkill_set_global_sw_state); - bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) { @@ -532,13 +508,14 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) blocked = blocked || hwblock; spin_unlock_irqrestore(&rfkill->lock, flags); - if (!rfkill->registered) - return blocked; + if (!rfkill->registered) { + rfkill->persistent = true; + } else { + if (prev != blocked && !hwblock) + schedule_work(&rfkill->uevent_work); - if (prev != blocked && !hwblock) - schedule_work(&rfkill->uevent_work); - - rfkill_led_trigger_event(rfkill); + rfkill_led_trigger_event(rfkill); + } return blocked; } @@ -563,13 +540,14 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) spin_unlock_irqrestore(&rfkill->lock, flags); - if (!rfkill->registered) - return; - - if (swprev != sw || hwprev != hw) - schedule_work(&rfkill->uevent_work); + if (!rfkill->registered) { + rfkill->persistent = true; + } else { + if (swprev != sw || hwprev != hw) + schedule_work(&rfkill->uevent_work); - rfkill_led_trigger_event(rfkill); + rfkill_led_trigger_event(rfkill); + } } EXPORT_SYMBOL(rfkill_set_states); @@ -888,15 +866,6 @@ int __must_check rfkill_register(struct rfkill *rfkill) dev_set_name(dev, "rfkill%lu", rfkill_no); rfkill_no++; - if (!(rfkill_states_default_locked & BIT(rfkill->type))) { - /* first of its kind */ - BUILD_BUG_ON(NUM_RFKILL_TYPES > - sizeof(rfkill_states_default_locked) * 8); - rfkill_states_default_locked |= BIT(rfkill->type); - rfkill_global_states[rfkill->type].cur = - rfkill_global_states[rfkill->type].def; - } - list_add_tail(&rfkill->node, &rfkill_list); error = device_add(dev); @@ -916,7 +885,17 @@ int __must_check rfkill_register(struct rfkill *rfkill) if (rfkill->ops->poll) schedule_delayed_work(&rfkill->poll_work, round_jiffies_relative(POLL_INTERVAL)); - schedule_work(&rfkill->sync_work); + + if (!rfkill->persistent || rfkill_epo_lock_active) { + schedule_work(&rfkill->sync_work); + } else { +#ifdef CONFIG_RFKILL_INPUT + bool soft_blocked = !!(rfkill->state & RFKILL_BLOCK_SW); + + if (!atomic_read(&rfkill_input_disabled)) + __rfkill_switch_all(rfkill->type, soft_blocked); +#endif + } rfkill_send_events(rfkill, RFKILL_OP_ADD); @@ -1193,7 +1172,7 @@ static int __init rfkill_init(void) int i; for (i = 0; i < NUM_RFKILL_TYPES; i++) - rfkill_global_states[i].def = !rfkill_default_state; + rfkill_global_states[i].cur = !rfkill_default_state; error = class_register(&rfkill_class); if (error) -- cgit v0.10.2 From 869fb3a46cd18235e6f176328a2d8085ffe2c704 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Mon, 8 Jun 2009 11:31:11 +0100 Subject: sony-laptop: no need to unblock rfkill on load The re-written rfkill core ensures rfkill devices are initialized to the system default state. The core calls set_block after registration so the driver shouldn't need to. Signed-off-by: Alan Jenkins Signed-off-by: John W. Linville diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f289344..e48d9a4 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1114,7 +1114,6 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, return err; } sony_rfkill_devices[nc_type] = rfk; - sony_nc_rfkill_set((void *)nc_type, false); return err; } -- cgit v0.10.2 From 908209c160da8ecb68052111972b7a21310eac3f Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Mon, 8 Jun 2009 13:12:23 +0100 Subject: rfkill: don't impose global states on resume (just restore the previous states) Once rfkill-input is disabled, the "global" states will only be used as default initial states. Since the states will always be the same after resume, we shouldn't generate events on resume. Signed-off-by: Alan Jenkins Signed-off-by: John W. Linville diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index c1dca0b..16e39c7 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -212,7 +212,7 @@ void rfkill_destroy(struct rfkill *rfkill); * * rfkill drivers that get events when the hard-blocked state changes * use this function to notify the rfkill core (and through that also - * userspace) of the current state -- they should also use this after + * userspace) of the current state. They should also use this after * resume if the state could have changed. * * You need not (but may) call this function if poll_state is assigned. @@ -234,8 +234,9 @@ bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked); * rfkill drivers that get events when the soft-blocked state changes * (yes, some platforms directly act on input but allow changing again) * use this function to notify the rfkill core (and through that also - * userspace) of the current state -- they should also use this after - * resume if the state could have changed. + * userspace) of the current state. It is not necessary to notify on + * resume; since hibernation can always change the soft-blocked state, + * the rfkill core will unconditionally restore the previous state. * * This function can be called in any context, even from within rfkill * callbacks. diff --git a/net/rfkill/core.c b/net/rfkill/core.c index fa430bd..4e68ab4 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -728,15 +728,11 @@ static int rfkill_resume(struct device *dev) struct rfkill *rfkill = to_rfkill(dev); bool cur; - mutex_lock(&rfkill_global_mutex); - cur = rfkill_global_states[rfkill->type].cur; + cur = !!(rfkill->state & RFKILL_BLOCK_SW); rfkill_set_block(rfkill, cur); - mutex_unlock(&rfkill_global_mutex); rfkill->suspended = false; - schedule_work(&rfkill->uevent_work); - rfkill_resume_polling(rfkill); return 0; -- cgit v0.10.2 From 403a3a136122457165321e90b7569a321cc9ac12 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 8 Jun 2009 21:04:57 +0200 Subject: b43: Add fw capabilities Add automagic feature flags, so the firmware can tell the driver about supported features and the driver can switch features on/off as needed. Signed-off-by: Michael Buesch Signed-off-by: Stefan Lippers-Hollmann Tested-by: Stefan Lippers-Hollmann Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 75aede0..f580c28 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -163,6 +163,7 @@ enum { #define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ #define B43_SHM_SH_PCTLWDPOS 0x0008 #define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */ +#define B43_SHM_SH_FWCAPA 0x0042 /* Firmware capabilities (Opensource firmware only) */ #define B43_SHM_SH_PHYVER 0x0050 /* PHY version */ #define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ #define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ @@ -297,6 +298,10 @@ enum { #define B43_HF_MLADVW 0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */ #define B43_HF_PR45960W 0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */ +/* Firmware capabilities field in SHM (Opensource firmware only) */ +#define B43_FWCAPA_HWCRYPTO 0x0001 +#define B43_FWCAPA_QOS 0x0002 + /* MacFilter offsets. */ #define B43_MACFILTER_SELF 0x0000 #define B43_MACFILTER_BSSID 0x0003 @@ -596,6 +601,13 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; + /* The number of queues that were registered with the mac80211 subsystem + * initially. This is a backup copy of hw->queues in case hw->queues has + * to be dynamically lowered at runtime (Firmware does not support QoS). + * hw->queues has to be restored to the original value before unregistering + * from the mac80211 subsystem. */ + u16 mac80211_initially_registered_queues; + struct mutex mutex; spinlock_t irq_lock; /* R/W lock for data transmission. @@ -749,6 +761,8 @@ struct b43_wldev { bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ + bool qos_enabled; /* TRUE, if QoS is used. */ + bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ /* PHY/Radio device. */ struct b43_phy phy; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index eae680b..7964cc3 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1285,7 +1285,7 @@ static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev, { struct b43_dmaring *ring; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 5d9f198..6456afe 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -80,8 +80,8 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -int b43_modparam_qos = 1; -module_param_named(qos, b43_modparam_qos, int, 0444); +static int modparam_qos = 1; +module_param_named(qos, modparam_qos, int, 0444); MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); static int modparam_btcoex = 1; @@ -538,6 +538,13 @@ void b43_hf_write(struct b43_wldev *dev, u64 value) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); } +/* Read the firmware capabilities bitmask (Opensource firmware only) */ +static u16 b43_fwcapa_read(struct b43_wldev *dev) +{ + B43_WARN_ON(!dev->fw.opensource); + return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA); +} + void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) { u32 low, high; @@ -2307,12 +2314,34 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.patch = fwpatch; dev->fw.opensource = (fwdate == 0xFFFF); + /* Default to use-all-queues. */ + dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; + dev->qos_enabled = !!modparam_qos; + /* Default to firmware/hardware crypto acceleration. */ + dev->hwcrypto_enabled = 1; + if (dev->fw.opensource) { + u16 fwcapa; + /* Patchlevel info is encoded in the "time" field. */ dev->fw.patch = fwtime; - b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", - dev->fw.rev, dev->fw.patch, - dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); + b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", + dev->fw.rev, dev->fw.patch); + + fwcapa = b43_fwcapa_read(dev); + if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) { + b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n"); + /* Disable hardware crypto and fall back to software crypto. */ + dev->hwcrypto_enabled = 0; + } + if (!(fwcapa & B43_FWCAPA_QOS)) { + b43info(dev->wl, "QoS not supported by firmware\n"); + /* Disable QoS. Tweak hw->queues to 1. It will be restored before + * ieee80211_unregister to make sure the networking core can + * properly free possible resources. */ + dev->wl->hw->queues = 1; + dev->qos_enabled = 0; + } } else { b43info(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", @@ -3627,7 +3656,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; - if (dev->fw.pcm_request_failed) { + if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) { /* We don't have firmware for the crypto engine. * Must use software-crypto. */ err = -EOPNOTSUPP; @@ -4727,6 +4756,7 @@ static int b43_wireless_init(struct ssb_device *dev) b43err(NULL, "Could not allocate ieee80211 device\n"); goto out; } + wl = hw_to_b43_wl(hw); /* fill hw info */ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | @@ -4740,7 +4770,8 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); - hw->queues = b43_modparam_qos ? 4 : 1; + hw->queues = modparam_qos ? 4 : 1; + wl->mac80211_initially_registered_queues = hw->queues; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) @@ -4748,9 +4779,7 @@ static int b43_wireless_init(struct ssb_device *dev) else SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); - /* Get and initialize struct b43_wl */ - wl = hw_to_b43_wl(hw); - memset(wl, 0, sizeof(*wl)); + /* Initialize struct b43_wl */ wl->hw = hw; spin_lock_init(&wl->irq_lock); rwlock_init(&wl->tx_lock); @@ -4816,8 +4845,13 @@ static void b43_remove(struct ssb_device *dev) cancel_work_sync(&wldev->restart_work); B43_WARN_ON(!wl); - if (wl->current_dev == wldev) + if (wl->current_dev == wldev) { + /* Restore the queues count before unregistering, because firmware detect + * might have modified it. Restoring is important, so the networking + * stack can properly free resources. */ + wl->hw->queues = wl->mac80211_initially_registered_queues; ieee80211_unregister_hw(wl->hw); + } b43_one_core_detach(dev); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 40abcf5..950fb1b 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -39,7 +39,6 @@ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) -extern int b43_modparam_qos; extern int b43_modparam_verbose; /* Logmessage verbosity levels. Update the b43_modparam_verbose helptext, if diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 8cd9776..69138e8 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -313,7 +313,7 @@ static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev, { struct b43_pio_txqueue *q; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: -- cgit v0.10.2 From 558f6d3229ddb9f11ca4ffee0439046c283882ff Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 8 Jun 2009 18:54:37 -0700 Subject: cfg80211: fix for duplicate response for driver reg request As Pavel puts userspace can be stupid and should not cause kernel crashes. In this case Pavel was able to find a crash here but unable to reproduce. Either way lets deal with this. This should fix: ------------[ cut here ]------------ kernel BUG at /home/proski/src/linux-2.6/net/wireless/reg.c:2132! Oops: Exception in kernel mode, sig: 5 [#1] PowerMac Modules linked in: ath5k ath [last unloaded: scsi_wait_scan] NIP: c02f3eac LR: c02f3d08 CTR: 00000000 REGS: ef107aa0 TRAP: 0700 Not tainted (2.6.30-rc8-wl) MSR: 00029032 CR: 88002442 XER: 20000000 TASK = ef84acb0[834] 'crda' THREAD: ef106000 GPR00: ef953840 ef107b50 ef84acb0 ef1380bc 00000006 c035a5c8 ef107b90 c035a5c8 GPR08: 00080005 efb68980 c0445628 ef130004 28002422 10019ce0 10012d3c 00000001 GPR16: 1070b2ac 00000005 48023558 1070b380 4802304c 00000000 ef107ddc c035a5c8 GPR24: ef107b78 c0443350 ef8bcb00 00000005 ef138080 c04a6a70 c04a0000 ef8bcb00 NIP [c02f3eac] set_regdom+0x4c4/0x4ec LR [c02f3d08] set_regdom+0x320/0x4ec Call Trace: [ef107b50] [c02f3d08] set_regdom+0x320/0x4ec (unreliable) [ef107b70] [c02f9d10] nl80211_set_reg+0x140/0x2d0 [ef107bc0] [c02aa2b8] genl_rcv_msg+0x204/0x228 [ef107c10] [c02a97cc] netlink_rcv_skb+0xe8/0x10c [ef107c30] [c02aa094] genl_rcv+0x3c/0x5c [ef107c40] [c02a9050] netlink_unicast+0x308/0x36c [ef107c80] [c02a92bc] netlink_sendmsg+0x208/0x2f0 [ef107cd0] [c0282048] sock_sendmsg+0xac/0xe4 [ef107db0] [c02822b4] sys_sendmsg+0x234/0x2d8 [ef107f00] [c0283a88] sys_socketcall+0x108/0x258 [ef107f40] [c0012790] ret_from_syscall+0x0/0x38 Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ea4c299..5e14371 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2129,7 +2129,12 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * driver wanted to the wiphy to deal with conflicts */ - BUG_ON(request_wiphy->regd); + /* + * Userspace could have sent two replies with only + * one kernel request. + */ + if (request_wiphy->regd) + return -EALREADY; r = reg_copy_regd(&request_wiphy->regd, rd); if (r) -- cgit v0.10.2 From 736708bd04b7a8941fddda32211982cab5d14431 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 9 Jun 2009 14:11:46 +0530 Subject: mac80211: Fix the way ADDBA request count being modified addba_req_num[tid] is supposed to have the count of consecutive addba request attempts on 'tid' which failed. This count is checked against a retry threshold (3 times) before starting the addba negotiation. This patch fixes the way this addba count is incremented/reset and thereby avoids indefinite addba attempts. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 43d00ff..9e5762a 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -132,6 +132,9 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, state = &sta->ampdu_mlme.tid_state_tx[tid]; + if (*state == HT_AGG_STATE_OPERATIONAL) + sta->ampdu_mlme.addba_req_num[tid] = 0; + *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); @@ -337,6 +340,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); + sta->ampdu_mlme.addba_req_num[tid]++; /* activate the timer for the recipient's addBA response */ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; @@ -606,7 +610,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) *state = HT_AGG_STATE_IDLE; /* from now on packets are no longer put onto sta->pending */ - sta->ampdu_mlme.addba_req_num[tid] = 0; kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; @@ -689,7 +692,6 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, sta->ampdu_mlme.addba_req_num[tid] = 0; } else { - sta->ampdu_mlme.addba_req_num[tid]++; ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); } spin_unlock_bh(&sta->lock); -- cgit v0.10.2 From 5eae6592e9bdc989151171828ee97e0ad9e1b1ac Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 9 Jun 2009 15:28:21 +0530 Subject: ath9k: Fix tx stuck when connected to aggr disabled HT AP This patch along with my previous patch in mac80211 "Fix the way ADDBA count..", fixes hang in tx when connected to an HT AP which rejects/times out on addba req. AGGR_ADDBA_PROGRESS should be cleared in aggr state when addba negotiation is terminated due to either addba response is timed out or addba is denied by the AP. With out clearing this bit, all frames are queued onto s/w queue for getting tx'd as aggr and will never be scheduled onto hw queue. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a8def4f..b61a071 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -711,6 +711,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) return 0; if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + txtid->state &= ~AGGR_ADDBA_PROGRESS; txtid->addba_exchangeattempts = 0; return 0; } -- cgit v0.10.2 From 0bffe40f21e2ddc5215b1faec4e8dbbc215e7d4d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 16:18:32 +0200 Subject: mac80211: don't use master netdev name Always use the wiphy name instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a9211cc..3f47276 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1122,8 +1122,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, p.txop = params->txop; if (drv_conf_tx(local, params->queue, &p)) { printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", local->mdev->name, - params->queue); + "parameters for queue %d\n", + wiphy_name(local->hw.wiphy), params->queue); return -EINVAL; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 509469c..e8a3d3c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -793,13 +793,13 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " "cWmin=%d cWmax=%d txop=%d\n", - local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, - params.cw_max, params.txop); + wiphy_name(local->hw.wiphy), queue, aci, acm, + params.aifs, params.cw_min, params.cw_max, params.txop); #endif if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", local->mdev->name, - queue); + "parameters for queue %d\n", + wiphy_name(local->hw.wiphy), queue); } } -- cgit v0.10.2 From 27004b10ce56985d8a010ce966af179f1b34193f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 19:48:25 +0200 Subject: mac80211: clean up return value of __ieee80211_parse_tx_radiotap The return type has more than two values, but it can validly only ever return TX_DROP and TX_CONTINUE, so use a bool instead of ieee80211_tx_result. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bfaa9ce..1aed88d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -908,9 +908,8 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) * deal with packet injection down monitor interface * with Radiotap Header -- only called for monitor mode interface */ -static ieee80211_tx_result -__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, - struct sk_buff *skb) +static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, + struct sk_buff *skb) { /* * this is the moment to interpret and discard the radiotap header that @@ -961,7 +960,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * on transmission */ if (skb->len < (iterator.max_length + FCS_LEN)) - return TX_DROP; + return false; skb_trim(skb, skb->len - FCS_LEN); } @@ -983,7 +982,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, } if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TX_DROP; + return false; /* * remove the radiotap header @@ -992,7 +991,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, */ skb_pull(skb, iterator.max_length); - return TX_CONTINUE; + return true; } /* @@ -1026,7 +1025,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { - if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) + if (!__ieee80211_parse_tx_radiotap(tx, skb)) return TX_DROP; /* -- cgit v0.10.2 From a6ae0716e5c3b5f9dbe5ed8f473a6c7b89692365 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 9 Jun 2009 23:43:11 -0400 Subject: ath5k: minor rfkill cleanup Always enable rfkill since the ifdefs in the code is not really worth the Kconfig option. Also fix a few code style things, and remove the usage of the ah_gpio[] array so we can remove it later. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 4863f4b..509b6f9 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -39,11 +39,3 @@ config ATH5K_DEBUG modprobe ath5k debug=0x00000400 -config ATH5K_RFKILL - bool "Atheros 5xxx rfkill support" - depends on ATH5K - default y - ---help--- - Include support for enabling/disabling WiFi via rfkill switch - with Atheros 5xxx cards - diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index f1e281c..090dc6d 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -11,6 +11,6 @@ ath5k-y += reset.o ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o +ath5k-y += rfkill.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o -ath5k-$(CONFIG_ATH5K_RFKILL) += rfkill.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 4c84e30..6358233 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1257,13 +1257,8 @@ 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); /* rfkill Functions */ -#ifdef CONFIG_ATH5K_RFKILL extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); -#else -static inline void ath5k_rfkill_hw_start(struct ath5k_hw *ah) {} -static inline void ath5k_rfkill_hw_stop(struct ath5k_hw *ah) {} -#endif /* Misc functions */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index f55675c..55f7de0 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2530,12 +2530,9 @@ ath5k_intr(int irq, void *dev_id) */ ath5k_hw_update_mib_counters(ah, &sc->ll_stats); } -#ifdef CONFIG_ATH5K_RFKILL if (status & AR5K_INT_GPIO) - { tasklet_schedule(&sc->rf_kill.toggleq); - } -#endif + } } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 7a0ecdd..f9b7f2f 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -177,9 +177,7 @@ struct ath5k_softc { struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ -#ifdef CONFIG_ATH5K_RFKILL struct ath5k_rfkill rf_kill; -#endif spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c index 492ada9..41a877b 100644 --- a/drivers/net/wireless/ath/ath5k/rfkill.c +++ b/drivers/net/wireless/ath/ath5k/rfkill.c @@ -56,10 +56,12 @@ static inline void ath5k_rfkill_enable(struct ath5k_softc *sc) static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable) { struct ath5k_hw *ah = sc->ah; + u32 curval; + ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio); - ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); + curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ? - !!ah->ah_gpio[0] : !ah->ah_gpio[0]); + !!curval : !curval); } static bool @@ -97,9 +99,8 @@ ath5k_rfkill_hw_start(struct ath5k_hw *ah) ath5k_rfkill_disable(sc); /* enable interrupt for rfkill switch */ - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) ath5k_rfkill_set_intr(sc, true); - } } @@ -109,9 +110,8 @@ ath5k_rfkill_hw_stop(struct ath5k_hw *ah) struct ath5k_softc *sc = ah->ah_sc; /* disable interrupt for rfkill switch */ - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) ath5k_rfkill_set_intr(sc, false); - } tasklet_kill(&sc->rf_kill.toggleq); -- cgit v0.10.2 From 43f7853180ed522944b3b1d4979cdb9f2b103ca3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 10 Jun 2009 15:16:15 +0200 Subject: mac80211: disable moving between PS modes during scan We don't want to trigger moving between PS mode during scan, because then we will sometimes end up sending nullfunc frames during scan. We're supposed to only send one prior to scan and after scan. This fixes an oops which occured due to an assert in ath9k: http://marc.info/?l=linux-wireless&m=124277331319024 The assert was happening because the rate control algorithm figures it should find at least one valid dual stream or single stream rate. Since we allow mac80211 to send nullfunc frames during scan and dynamic PS was enabled at times we ended up trying to send nullfunc frames for the target sta on the wrong band for which we have no valid rate to communicate with it. This breaks the assumptions in rate control. We determine we also need to disable moving between PS modes when not associated so lets just add that now as well, and we should not have a ps_sdata when that interface cannot actually go into PS because it's not associated. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e8a3d3c..898e9b0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -621,9 +621,6 @@ static void ieee80211_change_ps(struct ieee80211_local *local) struct ieee80211_conf *conf = &local->hw.conf; if (local->ps_sdata) { - if (!(local->ps_sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) - return; - ieee80211_enable_ps(local, local->ps_sdata); } else if (conf->flags & IEEE80211_CONF_PS) { conf->flags &= ~IEEE80211_CONF_PS; @@ -653,7 +650,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) count++; } - if (count == 1 && found->u.mgd.powersave) { + if (count == 1 && found->u.mgd.powersave && + (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) { s32 beaconint_us; if (latency < 0) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1aed88d..364222b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1415,7 +1415,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && - local->hw.conf.dynamic_ps_timeout > 0) { + local->hw.conf.dynamic_ps_timeout > 0 && + !local->sw_scanning && !local->hw_scanning && local->ps_sdata) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); -- cgit v0.10.2 From 4e751843d406a4d0471c207872b9e24957de8357 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Jun 2009 15:16:52 +0200 Subject: mac80211: disable PS while probing AP When associated, but probing the AP because we detected beacon loss, we need to disable powersave to be able to receive the probe response. Change the code to do that by checking whether we're trying to probe when determining the possibility of going into PS, and recalculate the PS ability at the necessary spots. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 898e9b0..d779c57 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -651,7 +651,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } if (count == 1 && found->u.mgd.powersave && - (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) { + (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && + !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { s32 beaconint_us; if (latency < 0) @@ -1320,6 +1321,11 @@ void ieee80211_beacon_loss_work(struct work_struct *work) #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_ps(sdata->local, -1); + mutex_unlock(&sdata->local->iflist_mtx); + ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); @@ -1340,6 +1346,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct sta_info *sta; + unsigned long last_rx; bool disassoc = false; /* TODO: start monitoring current AP signal quality and number of @@ -1356,17 +1363,21 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", sdata->dev->name, ifmgd->bssid); disassoc = true; - goto unlock; + rcu_read_unlock(); + goto out; } + last_rx = sta->last_rx; + rcu_read_unlock(); + if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && - time_after(jiffies, sta->last_rx + IEEE80211_PROBE_WAIT)) { + time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) { printk(KERN_DEBUG "%s: no probe response from AP %pM " "- disassociating\n", sdata->dev->name, ifmgd->bssid); disassoc = true; ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; - goto unlock; + goto out; } /* @@ -1385,26 +1396,29 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) } #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); - goto unlock; + goto out; } - if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { + if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) { ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); } + out: if (!disassoc) mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); - - unlock: - rcu_read_unlock(); - - if (disassoc) + else ieee80211_set_disassoc(sdata, true, true, WLAN_REASON_PREV_AUTH_NOT_VALID); } @@ -1887,8 +1901,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_authenticate(sdata); } - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) + if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_ps(sdata->local, -1); + mutex_unlock(&sdata->local->iflist_mtx); + } } /* @@ -1946,6 +1964,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } #endif ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); } ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); -- cgit v0.10.2 From 2f0accc13520b2644b85f80aedce10d10d88b0ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Jun 2009 16:50:29 +0200 Subject: cfg80211: fix rfkill locking problem rfkill currently requires a global lock within the rfkill_register() function, and holds that lock over calls to the set_block() methods. This means that we cannot hold a lock around rfkill_register() that we also require in set_block(), directly or indirectly. Fix cfg80211 to register rfkill outside the block locked by its global lock. Much of what cfg80211 does in the locked block doesn't need to be locked anyway. Reported-by: Vasanthakumar Thiagarajan Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 3b74b88..d585029 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -395,21 +395,23 @@ int wiphy_register(struct wiphy *wiphy) /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); - mutex_lock(&cfg80211_mutex); - - /* set up regulatory info */ - wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); - res = device_add(&drv->wiphy.dev); if (res) - goto out_unlock; + return res; res = rfkill_register(drv->rfkill); if (res) goto out_rm_dev; + mutex_lock(&cfg80211_mutex); + + /* set up regulatory info */ + wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); + list_add(&drv->list, &cfg80211_drv_list); + mutex_unlock(&cfg80211_mutex); + /* add to debugfs */ drv->wiphy.debugfsdir = debugfs_create_dir(wiphy_name(&drv->wiphy), @@ -430,13 +432,10 @@ int wiphy_register(struct wiphy *wiphy) cfg80211_debugfs_drv_add(drv); - res = 0; - goto out_unlock; + return 0; out_rm_dev: device_del(&drv->wiphy.dev); - out_unlock: - mutex_unlock(&cfg80211_mutex); return res; } EXPORT_SYMBOL(wiphy_register); -- cgit v0.10.2 From e5241c448f94feee40b2a285c8bf55d066420073 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 11 Jun 2009 02:10:19 -0700 Subject: ieee802154: Use '%Zu' printf format for size_t. Signed-off-by: David S. Miller diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 1f5ea11..1779677 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -248,7 +248,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_skb; if (size > mtu) { - pr_debug("size = %u, mtu = %u\n", size, mtu); + pr_debug("size = %Zu, mtu = %u\n", size, mtu); err = -EINVAL; goto out_skb; } diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 8b892e0..fca44d5 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -132,7 +132,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, pr_debug("name = %s, mtu = %u\n", dev->name, mtu); if (size > mtu) { - pr_debug("size = %u, mtu = %u\n", size, mtu); + pr_debug("size = %Zu, mtu = %u\n", size, mtu); err = -EINVAL; goto out_dev; } -- cgit v0.10.2 From 3f68535adad8dd89499505a65fb25d0e02d118cc Mon Sep 17 00:00:00 2001 From: john stultz Date: Wed, 21 Jan 2009 22:53:22 -0700 Subject: clocksource: sanity check sysfs clocksource changes Thomas, Andrew and Ingo pointed out that we don't have any safety checks in the clocksource sysfs entries to make sure sysadmins don't try to change the clocksource to a non high-res timer capable clocksource (such as jiffies) when high-res timers (HRT) is enabled. Doing so will likely hang a system. Correct this by filtering non HRT clocksources from available_clocksources and not accepting non HRT clocksources with HRT enabled. Signed-off-by: John Stultz Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 0d2f7c8..58021b0 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -305,7 +305,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) extern ktime_t ktime_get(void); extern ktime_t ktime_get_real(void); - +extern int hrtimer_hres_active(void); DECLARE_PER_CPU(struct tick_device, tick_cpu_device); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index cb8a15c..1a70c18 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -476,7 +476,7 @@ static inline int hrtimer_is_hres_enabled(void) /* * Is the high resolution mode active ? */ -static inline int hrtimer_hres_active(void) +int hrtimer_hres_active(void) { return __get_cpu_var(hrtimer_bases).hres_active; } @@ -704,7 +704,7 @@ static int hrtimer_switch_to_hres(void) #else -static inline int hrtimer_hres_active(void) { return 0; } +int hrtimer_hres_active(void) { return 0; } static inline int hrtimer_is_hres_enabled(void) { return 0; } static inline int hrtimer_switch_to_hres(void) { return 0; } static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 80189f6..18b9f5d 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -30,6 +30,7 @@ #include #include /* for spin_unlock_irq() using preempt_count() m68k */ #include +#include void timecounter_init(struct timecounter *tc, const struct cyclecounter *cc, @@ -509,6 +510,18 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, } } + /* + * Check to make sure we don't switch to a non-HRT usable + * clocksource if HRT is enabled and running + */ + if (hrtimer_hres_active() && + !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) { + printk(KERN_WARNING "%s clocksource is not HRT compatible. " + "Cannot switch while in HRT mode\n", ovr->name); + ovr = NULL; + override_name[0] = 0; + } + /* Reselect, when the override name has changed */ if (ovr != clocksource_override) { clocksource_override = ovr; @@ -537,7 +550,10 @@ sysfs_show_available_clocksources(struct sys_device *dev, spin_lock_irq(&clocksource_lock); list_for_each_entry(src, &clocksource_list, list) { - count += snprintf(buf + count, + /* Don't show non-HRES clocksource if HRES is enabled */ + if (!hrtimer_hres_active() || + (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) + count += snprintf(buf + count, max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "%s ", src->name); } -- cgit v0.10.2 From 720017623ab294b66c8a95d7bc5ccf75a581ebe4 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Wed, 10 Jun 2009 09:55:04 +0000 Subject: e100: add non-MII PHY support Restore support for cards with MII-lacking PHYs as compared to removed pre-2.6.29 eepro100 driver: use full low-level MII I/O access abstraction by providing clean PHY-specific mdio_ctrl() functions for either standard MII-compliant cards, slightly special ones or non-MII PHY ones. We now have another netdev_priv member for mdio_ctrl(), thus we have some array indirection, but we save some additional opcodes for specific phy_82552_v handling in the common case. [akpm@linux-foundation.org: cleanups] Signed-off-by: Andreas Mohr Cc: Jeff Kirsher Cc: Jesse Brandeburg Cc: Bruce Allan Cc: PJ Waskiewicz Cc: John Ronciak Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 0c37dd9..119dc53 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -143,6 +143,8 @@ * FIXES: * 2005/12/02 - Michael O'Donnell * - Stratus87247: protect MDI control register manipulations + * 2009/06/01 - Andreas Mohr + * - add clean lowlevel I/O emulation for cards with MII-lacking PHYs */ #include @@ -372,6 +374,7 @@ enum eeprom_op { enum eeprom_offsets { eeprom_cnfg_mdix = 0x03, + eeprom_phy_iface = 0x06, eeprom_id = 0x0A, eeprom_config_asf = 0x0D, eeprom_smbus_addr = 0x90, @@ -381,6 +384,18 @@ enum eeprom_cnfg_mdix { eeprom_mdix_enabled = 0x0080, }; +enum eeprom_phy_iface { + NoSuchPhy = 0, + I82553AB, + I82553C, + I82503, + DP83840, + S80C240, + S80C24, + I82555, + DP83840A = 10, +}; + enum eeprom_id { eeprom_id_wol = 0x0020, }; @@ -545,6 +560,7 @@ struct nic { u32 msg_enable ____cacheline_aligned; struct net_device *netdev; struct pci_dev *pdev; + u16 (*mdio_ctrl)(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data); struct rx *rxs ____cacheline_aligned; struct rx *rx_to_use; @@ -899,7 +915,21 @@ err_unlock: return err; } -static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) +static int mdio_read(struct net_device *netdev, int addr, int reg) +{ + struct nic *nic = netdev_priv(netdev); + return nic->mdio_ctrl(nic, addr, mdi_read, reg, 0); +} + +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + struct nic *nic = netdev_priv(netdev); + + nic->mdio_ctrl(nic, addr, mdi_write, reg, data); +} + +/* the standard mdio_ctrl() function for usual MII-compliant hardware */ +static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) { u32 data_out = 0; unsigned int i; @@ -938,30 +968,83 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) return (u16)data_out; } -static int mdio_read(struct net_device *netdev, int addr, int reg) -{ - return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0); +/* slightly tweaked mdio_ctrl() function for phy_82552_v specifics */ +static u16 mdio_ctrl_phy_82552_v(struct nic *nic, + u32 addr, + u32 dir, + u32 reg, + u16 data) +{ + if ((reg == MII_BMCR) && (dir == mdi_write)) { + if (data & (BMCR_ANRESTART | BMCR_ANENABLE)) { + u16 advert = mdio_read(nic->netdev, nic->mii.phy_id, + MII_ADVERTISE); + + /* + * Workaround Si issue where sometimes the part will not + * autoneg to 100Mbps even when advertised. + */ + if (advert & ADVERTISE_100FULL) + data |= BMCR_SPEED100 | BMCR_FULLDPLX; + else if (advert & ADVERTISE_100HALF) + data |= BMCR_SPEED100; + } + } + return mdio_ctrl_hw(nic, addr, dir, reg, data); } -static void mdio_write(struct net_device *netdev, int addr, int reg, int data) -{ - struct nic *nic = netdev_priv(netdev); - - if ((nic->phy == phy_82552_v) && (reg == MII_BMCR) && - (data & (BMCR_ANRESTART | BMCR_ANENABLE))) { - u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); - - /* - * Workaround Si issue where sometimes the part will not - * autoneg to 100Mbps even when advertised. - */ - if (advert & ADVERTISE_100FULL) - data |= BMCR_SPEED100 | BMCR_FULLDPLX; - else if (advert & ADVERTISE_100HALF) - data |= BMCR_SPEED100; +/* Fully software-emulated mdio_ctrl() function for cards without + * MII-compliant PHYs. + * For now, this is mainly geared towards 80c24 support; in case of further + * requirements for other types (i82503, ...?) either extend this mechanism + * or split it, whichever is cleaner. + */ +static u16 mdio_ctrl_phy_mii_emulated(struct nic *nic, + u32 addr, + u32 dir, + u32 reg, + u16 data) +{ + /* might need to allocate a netdev_priv'ed register array eventually + * to be able to record state changes, but for now + * some fully hardcoded register handling ought to be ok I guess. */ + + if (dir == mdi_read) { + switch (reg) { + case MII_BMCR: + /* Auto-negotiation, right? */ + return BMCR_ANENABLE | + BMCR_FULLDPLX; + case MII_BMSR: + return BMSR_LSTATUS /* for mii_link_ok() */ | + BMSR_ANEGCAPABLE | + BMSR_10FULL; + case MII_ADVERTISE: + /* 80c24 is a "combo card" PHY, right? */ + return ADVERTISE_10HALF | + ADVERTISE_10FULL; + default: + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data); + return 0xFFFF; + } + } else { + switch (reg) { + default: + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data); + return 0xFFFF; + } } - - mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); +} +static inline int e100_phy_supports_mii(struct nic *nic) +{ + /* for now, just check it by comparing whether we + are using MII software emulation. + */ + return (nic->mdio_ctrl != mdio_ctrl_phy_mii_emulated); } static void e100_get_defaults(struct nic *nic) @@ -1013,7 +1096,8 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ config->tx_underrun_retry = 0x3; /* # of underrun retries */ - config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ + if (e100_phy_supports_mii(nic)) + config->mii_mode = 1; /* 1=MII mode, 0=i82503 mode */ config->pad10 = 0x6; config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ @@ -1270,6 +1354,42 @@ static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) offsetof(struct mem, dump_buf)); } +static int e100_phy_check_without_mii(struct nic *nic) +{ + u8 phy_type; + int without_mii; + + phy_type = (nic->eeprom[eeprom_phy_iface] >> 8) & 0x0f; + + switch (phy_type) { + case NoSuchPhy: /* Non-MII PHY; UNTESTED! */ + case I82503: /* Non-MII PHY; UNTESTED! */ + case S80C24: /* Non-MII PHY; tested and working */ + /* paragraph from the FreeBSD driver, "FXP_PHY_80C24": + * The Seeq 80c24 AutoDUPLEX(tm) Ethernet Interface Adapter + * doesn't have a programming interface of any sort. The + * media is sensed automatically based on how the link partner + * is configured. This is, in essence, manual configuration. + */ + DPRINTK(PROBE, INFO, + "found MII-less i82503 or 80c24 or other PHY\n"); + + nic->mdio_ctrl = mdio_ctrl_phy_mii_emulated; + nic->mii.phy_id = 0; /* is this ok for an MII-less PHY? */ + + /* these might be needed for certain MII-less cards... + * nic->flags |= ich; + * nic->flags |= ich_10h_workaround; */ + + without_mii = 1; + break; + default: + without_mii = 0; + break; + } + return without_mii; +} + #define NCONFIG_AUTO_SWITCH 0x0080 #define MII_NSC_CONG MII_RESV1 #define NSC_CONG_ENABLE 0x0100 @@ -1290,9 +1410,21 @@ static int e100_phy_init(struct nic *nic) if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) break; } - DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); - if (addr == 32) - return -EAGAIN; + if (addr == 32) { + /* uhoh, no PHY detected: check whether we seem to be some + * weird, rare variant which is *known* to not have any MII. + * But do this AFTER MII checking only, since this does + * lookup of EEPROM values which may easily be unreliable. */ + if (e100_phy_check_without_mii(nic)) + return 0; /* simply return and hope for the best */ + else { + /* for unknown cases log a fatal error */ + DPRINTK(HW, ERR, + "Failed to locate any known PHY, aborting.\n"); + return -EAGAIN; + } + } else + DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); /* Isolate all the PHY ids */ for (addr = 0; addr < 32; addr++) @@ -1320,6 +1452,9 @@ static int e100_phy_init(struct nic *nic) if (nic->phy == phy_82552_v) { u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); + /* assign special tweaked mdio_ctrl() function */ + nic->mdio_ctrl = mdio_ctrl_phy_82552_v; + /* Workaround Si not advertising flow-control during autoneg */ advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert); @@ -2585,6 +2720,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->netdev = netdev; nic->pdev = pdev; nic->msg_enable = (1 << debug) - 1; + nic->mdio_ctrl = mdio_ctrl_hw; pci_set_drvdata(pdev, netdev); if ((err = pci_enable_device(pdev))) { -- cgit v0.10.2 From ef5c89967d50042b29937fb724e057c1aa3c5207 Mon Sep 17 00:00:00 2001 From: "sg.tweak@gmail.com" Date: Wed, 10 Jun 2009 09:55:02 +0000 Subject: drivers/net/macvlan.c: fix cloning of tagged VLAN interfaces Addresses http://bugzilla.kernel.org/show_bug.cgi?id=13348 akpm: the reporter disappeared, so I typed it in again. It is not possible to make clone of tagged VLAN interface to be used as mac-based vlan interfave. How reproducible: Use any 802.1q tagged vlan interface, e.g. eth2.700 and clone it: ip link add link eth2.700 address 00:04:75:cb:38:09 macvlan0 type macvlan ip link set dev macvlan0 up ip addr add 10.195.1.1/24 dev macvlan0 So far, so good. Now try to ping anything via macvlan0: ping 10.195.1.2 Actual results: For every attempted packet tx kernel writes to console: ------------[ cut here ]------------ WARNING: at net/8021q/vlan_dev.c:254 vlan_dev_hard_header+0x36/0x126 [8021q]() Hardware name: M22ES Modules linked in: arptable_filter arp_tables bridge veth macvlan arc4 ecb ppp_mppe ppp_async crc_ccitt ppp_generic slhc autofs4 sunrpc 8021q garp stp ipt_REJECT nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack xt_tcpudp x_tables dm_mirror dm_region_hash dm_log dm_multipath dm_mod sbs sbshc lp floppy snd_intel8x0 joydev snd_seq_dummy snd_intel8x0m snd_ac97_codec ide_cd_mod ac97_bus snd_seq_oss cdrom snd_seq_midi_event serio_raw snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss parport_pc snd_pcm parport battery 8139cp snd_timer i2c_sis96x ac button snd rtc_cmos rtc_core 8139too soundcore rtc_lib mii i2c_core pcspkr snd_page_alloc pata_sis libata sd_mod scsi_mod ext3 jbd ehci_hcd ohci_hcd uhci_hcd [last unloaded: ip_tables] Pid: 0, comm: swapper Tainted: G W 2.6.29.3 #1 Call Trace: [] warn_slowpath+0x60/0x9f [] warn_slowpath+0x87/0x9f [] vlan_dev_hard_header+0x0/0x126 [8021q] [] vlan_dev_hard_header+0x36/0x126 [8021q] [] vlan_dev_hard_header+0x0/0x126 [8021q] [] macvlan_hard_header+0x3c/0x47 [macvlan] [] macvlan_hard_header+0x0/0x47 [macvlan] [] arp_create+0xef/0x1ff [] arp_send+0x3d/0x54 [] arp_solicit+0x16c/0x177 [] neigh_timer_handler+0x227/0x269 [] neigh_timer_handler+0x0/0x269 [] run_timer_softirq+0xf0/0x141 [] __do_softirq+0x76/0xf8 [] __do_softirq+0x0/0xf8 [] handle_level_irq+0x0/0xad [] irq_exit+0x35/0x62 [] do_IRQ+0xdf/0xf4 [] common_interrupt+0x27/0x2c [] default_idle+0x2a/0x3d [] cpu_idle+0x57/0x70 Macvlan driver always uses standard ethernet header length for all types of interface to which it is linked. This patch fixes this problem. Reported-by: Cc: Alan Cox Cc: "Rafael J. Wysocki" Cc: "David S. Miller" Cc: Stephen Hemminger Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 021d994..99eed9f 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -359,6 +359,7 @@ static int macvlan_init(struct net_device *dev) (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; dev->iflink = lowerdev->ifindex; + dev->hard_header_len = lowerdev->hard_header_len; macvlan_set_lockdep_class(dev); -- cgit v0.10.2 From b77e5228849fdcd7a5d73beb16b9ad99395236ec Mon Sep 17 00:00:00 2001 From: Risto Suominen Date: Wed, 10 Jun 2009 09:55:00 +0000 Subject: de2104x: support for systems lacking cache coherence Add a configurable Descriptor Skip Length for systems that lack cache coherence. (akpm: I think this should be done as a module parameter, not a compile-tinme option) Signed-off-by: Risto Suominen Cc: Grant Grundler Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig index d913405..1cc8cf4 100644 --- a/drivers/net/tulip/Kconfig +++ b/drivers/net/tulip/Kconfig @@ -27,6 +27,18 @@ config DE2104X To compile this driver as a module, choose M here. The module will be called de2104x. +config DE2104X_DSL + int "Descriptor Skip Length in 32 bit longwords" + depends on DE2104X + range 0 31 + default 0 + help + Setting this value allows to align ring buffer descriptors into their + own cache lines. Value of 4 corresponds to the typical 32 byte line + (the descriptor is 16 bytes). This is necessary on systems that lack + cache coherence, an example is PowerMac 5500. Otherwise 0 is safe. + Default is 0, and range is 0 to 31. + config TULIP tristate "DECchip Tulip (dc2114x) PCI support" depends on PCI diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d4c5ecc..e7609a0 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -82,6 +82,13 @@ MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copi NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) +/* Descriptor skip length in 32 bit longwords. */ +#ifndef CONFIG_DE2104X_DSL +#define DSL 0 +#else +#define DSL CONFIG_DE2104X_DSL +#endif + #define DE_RX_RING_SIZE 64 #define DE_TX_RING_SIZE 64 #define DE_RING_BYTES \ @@ -153,6 +160,7 @@ enum { CmdReset = (1 << 0), CacheAlign16 = 0x00008000, BurstLen4 = 0x00000400, + DescSkipLen = (DSL << 2), /* Rx/TxPoll bits */ NormalTxPoll = (1 << 0), @@ -246,7 +254,7 @@ static const u32 de_intr_mask = * Set the programmable burst length to 4 longwords for all: * DMA errors result without these values. Cache align 16 long. */ -static const u32 de_bus_mode = CacheAlign16 | BurstLen4; +static const u32 de_bus_mode = CacheAlign16 | BurstLen4 | DescSkipLen; struct de_srom_media_block { u8 opts; @@ -266,6 +274,9 @@ struct de_desc { __le32 opts2; __le32 addr1; __le32 addr2; +#if DSL + __le32 skip[DSL]; +#endif }; struct media_info { -- cgit v0.10.2 From 0ed586d075ef65c0268982e5b7f36d0ffaa95547 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 10 Jun 2009 09:55:03 +0000 Subject: atl1c: WAKE_MCAST tested twice, not WAKE_UCAST The WAKE_MCAST bit is tested twice, the first should be WAKE_UCAST. Signed-off-by: Roel Kluin Cc: Jie Yang Cc: Jay Cliburn Cc: Chris Snook Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 45c5b73..e4afbd6 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -271,7 +271,7 @@ static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct atl1c_adapter *adapter = netdev_priv(netdev); if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | - WAKE_MCAST | WAKE_BCAST | WAKE_MCAST)) + WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)) return -EOPNOTSUPP; /* these settings will always override what we currently have */ adapter->wol = 0; -- cgit v0.10.2 From 88c55e3cbd1bd4e8f52dcda67456763710a025a5 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 10 Jun 2009 15:49:33 +0000 Subject: qlge: Relax alignment on TX harware queue. The alignment was on size of queue boundary, but the hardware only requires 4-byte alignment. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 5eb52ca..b1ddfd1 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -27,6 +27,8 @@ "%s: " fmt, __func__, ##args); \ } while (0) +#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */ + #define QLGE_VENDOR_ID 0x1077 #define QLGE_DEVICE_ID_8012 0x8012 #define QLGE_DEVICE_ID_8000 0x8000 diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 024c734..17d512c 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2237,7 +2237,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, &tx_ring->wq_base_dma); if ((tx_ring->wq_base == NULL) - || tx_ring->wq_base_dma & (tx_ring->wq_size - 1)) { + || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) { QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n"); return -ENOMEM; } -- cgit v0.10.2 From b8facca01ba381c3f8ff2391fbe3860ebc6a6bdc Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 10 Jun 2009 15:49:34 +0000 Subject: qlge: Allow RX buf rings to be > than 4096 bytes. RX buffer rings can be comprised of non-contiguous fixed size chunks of memory. The ring is given to the hardware as a pointer to a location that stores the location of the queue. If the queue is greater than 4096 bytes then the hardware gets a list of said pointers. This patch addes the necessary logic to generate the list if the queue size exceeds 4096. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index b1ddfd1..156e02e 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -41,7 +41,18 @@ #define NUM_SMALL_BUFFERS 512 #define NUM_LARGE_BUFFERS 512 +#define DB_PAGE_SIZE 4096 + +/* Calculate the number of (4k) pages required to + * contain a buffer queue of the given length. + */ +#define MAX_DB_PAGES_PER_BQ(x) \ + (((x * sizeof(u64)) / DB_PAGE_SIZE) + \ + (((x * sizeof(u64)) % DB_PAGE_SIZE) ? 1 : 0)) +#define RX_RING_SHADOW_SPACE (sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64)) #define SMALL_BUFFER_SIZE 256 #define LARGE_BUFFER_SIZE PAGE_SIZE #define MAX_SPLIT_SIZE 1023 @@ -65,8 +76,6 @@ #define TX_DESC_PER_OAL 0 #endif -#define DB_PAGE_SIZE 4096 - /* MPI test register definitions. This register * is used for determining alternate NIC function's * PCI->func number. diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 17d512c..b9a5f59 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2552,14 +2552,16 @@ 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); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); u64 shadow_reg_dma = qdev->rx_ring_shadow_reg_dma + - (rx_ring->cq_id * sizeof(u64) * 4); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); void __iomem *doorbell_area = qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); int err = 0; u16 bq_len; u64 tmp; + __le64 *base_indirect_ptr; + int page_entries; /* Set up the shadow registers for this ring. */ rx_ring->prod_idx_sh_reg = shadow_reg; @@ -2568,8 +2570,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) 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); + shadow_reg += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); + shadow_reg_dma += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); rx_ring->sbq_base_indirect = shadow_reg; rx_ring->sbq_base_indirect_dma = shadow_reg_dma; @@ -2606,7 +2608,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->lbq_len) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ tmp = (u64)rx_ring->lbq_base_dma;; - *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->lbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq_base_indirect_dma); bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 : @@ -2623,7 +2632,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->sbq_len) { cqicb->flags |= FLAGS_LS; /* Load sbq values */ tmp = (u64)rx_ring->sbq_base_dma;; - *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->sbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->sbq_len)); cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq_base_indirect_dma); cqicb->sbq_buf_size = -- cgit v0.10.2 From d005ba6cc82440d9ebf96f3ec8f79c54578b898f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 10 Jun 2009 05:28:04 +0000 Subject: mdio: Expose 10GBASE-T MDI-X status via ethtool This is available in a standard MDIO register in 10GBASE-T PHYs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 6648303..dc45e98 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -296,6 +296,23 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || ecmd->speed == SPEED_10000); } + + /* 10GBASE-T MDI/MDI-X */ + if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) { + switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBT_SWAPPOL)) { + case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: + ecmd->eth_tp_mdix = ETH_TP_MDI; + break; + case 0: + ecmd->eth_tp_mdix = ETH_TP_MDI_X; + break; + default: + /* It's complicated... */ + ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + break; + } + } } EXPORT_SYMBOL(mdio45_ethtool_gset_npage); diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 5685164..cfdf1df 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -45,6 +45,7 @@ #define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */ /* Media-dependent registers. */ +#define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */ #define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ #define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A. * Lanes B-D are numbered 134-136. */ @@ -195,6 +196,14 @@ #define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 #define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 +/* PMA 10GBASE-T pair swap & polarity */ +#define MDIO_PMA_10GBT_SWAPPOL_ABNX 0x0001 /* Pair A/B uncrossed */ +#define MDIO_PMA_10GBT_SWAPPOL_CDNX 0x0002 /* Pair C/D uncrossed */ +#define MDIO_PMA_10GBT_SWAPPOL_AREV 0x0100 /* Pair A polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_BREV 0x0200 /* Pair B polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_CREV 0x0400 /* Pair C polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_DREV 0x0800 /* Pair D polarity reversed */ + /* PMA 10GBASE-T TX power register. */ #define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */ -- cgit v0.10.2 From e762cd70efad6b6236b084ff7e5ce54a5f524320 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 10 Jun 2009 05:30:05 +0000 Subject: sfc: Expose 100/1000BASE-T MDI-X status via ethtool Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index db723c5..f4d5090 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -63,6 +63,7 @@ /* extended status register */ #define PMA_PMD_XSTATUS_REG 49153 +#define PMA_PMD_XSTAT_MDIX_LBN 14 #define PMA_PMD_XSTAT_FLP_LBN (12) /* LED control register */ @@ -741,9 +742,17 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); - if (efx->phy_type != PHY_TYPE_SFX7101) + if (efx->phy_type != PHY_TYPE_SFX7101) { ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); + if (ecmd->speed != SPEED_10000) { + ecmd->eth_tp_mdix = + (efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XSTATUS_REG) & + (1 << PMA_PMD_XSTAT_MDIX_LBN)) + ? ETH_TP_MDI_X : ETH_TP_MDI; + } + } /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ -- cgit v0.10.2 From 87433bfc75f34599c38137e172b6bf8fd41971ba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 9 Jun 2009 22:55:53 +0000 Subject: r8169: use dev_kfree_skb() instead of dev_kfree_skb_irq() rtl8169_tx_interrupt() is used from NAPI context, it can directly free skbs. dev_kfree_skb_irq() is a leftover from pre-NAPI times of this driver. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index e94316b..007c881 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3379,7 +3379,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev, rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { - dev_kfree_skb_irq(tx_skb->skb); + dev_kfree_skb(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; -- cgit v0.10.2 From 74b793e1ef79edc49bc031a88d62f1e93fc6b30f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 9 Jun 2009 23:25:21 +0000 Subject: cxgb3: remove __GFP_NOFAIL usage Pre-allocate a skb at init time to be used for control messages to the HW if skb allocation fails. Tolerate failures to send messages initializing some memories at the cost of parity error detection for these memories. Retry sending connection id release messages if both alloc_skb(GFP_ATOMIC) and alloc_skb(GFP_KERNEL) fail. Do not bring the interface up if messages binding queue set to port fail to be sent. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index e48e508..1694fad 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -253,6 +253,8 @@ struct adapter { struct mutex mdio_lock; spinlock_t stats_lock; spinlock_t work_lock; + + struct sk_buff *nofail_skb; }; static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index aef3ab2..538dda4 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -433,40 +433,78 @@ static int init_tp_parity(struct adapter *adap) for (i = 0; i < 16; i++) { struct cpl_smt_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); req->iff = i; t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_l2t_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); req->params = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_rte_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); req->l2t_idx = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } - skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); memset(greq, 0, sizeof(*greq)); greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); @@ -475,8 +513,17 @@ static int init_tp_parity(struct adapter *adap) t3_mgmt_tx(adap, skb); i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + if (skb == adap->nofail_skb) { + i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + } + t3_tp_set_offload_mode(adap, 0); return i; + +alloc_skb_fail: + t3_tp_set_offload_mode(adap, 0); + return -ENOMEM; } /** @@ -871,7 +918,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, struct mngt_pktsched_wr *req; int ret; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + return -ENOMEM; + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; @@ -881,6 +933,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, req->max = hi; req->binding = port; ret = t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field), + GFP_KERNEL); + if (!adap->nofail_skb) + ret = -ENOMEM; + } return ret; } @@ -3020,6 +3078,14 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_disable_device; } + adapter->nofail_skb = + alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL); + if (!adapter->nofail_skb) { + dev_err(&pdev->dev, "cannot allocate nofail buffer\n"); + err = -ENOMEM; + goto out_free_adapter; + } + adapter->regs = ioremap_nocache(mmio_start, mmio_len); if (!adapter->regs) { dev_err(&pdev->dev, "cannot map device registers\n"); @@ -3176,6 +3242,8 @@ static void __devexit remove_one(struct pci_dev *pdev) free_netdev(adapter->port[i]); iounmap(adapter->regs); + if (adapter->nofail_skb) + kfree_skb(adapter->nofail_skb); kfree(adapter); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 620d80b..f9f54b5 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -566,13 +566,31 @@ static void t3_process_tid_release_list(struct work_struct *work) spin_unlock_bh(&td->tid_release_lock); skb = alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL | __GFP_NOFAIL); + GFP_KERNEL); + if (!skb) + skb = td->nofail_skb; + if (!skb) { + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + td->tid_release_list = (struct t3c_tid_entry *)p; + break; + } mk_tid_release(skb, p - td->tid_maps.tid_tab); cxgb3_ofld_send(tdev, skb); p->ctx = NULL; + if (skb == td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); spin_lock_bh(&td->tid_release_lock); } + td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1; spin_unlock_bh(&td->tid_release_lock); + + if (!td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); } /* use ctx as a next pointer in the tid release list */ @@ -585,7 +603,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) p->ctx = (void *)td->tid_release_list; p->client = NULL; td->tid_release_list = p; - if (!p->ctx) + if (!p->ctx || td->release_list_incomplete) schedule_work(&td->tid_release_task); spin_unlock_bh(&td->tid_release_lock); } @@ -1274,6 +1292,9 @@ int cxgb3_offload_activate(struct adapter *adapter) if (list_empty(&adapter_list)) register_netevent_notifier(&nb); + t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL); + t->release_list_incomplete = 0; + add_adapter(adapter); return 0; @@ -1298,6 +1319,8 @@ void cxgb3_offload_deactivate(struct adapter *adapter) T3C_DATA(tdev) = NULL; t3_free_l2t(L2DATA(tdev)); L2DATA(tdev) = NULL; + if (t->nofail_skb) + kfree_skb(t->nofail_skb); kfree(t); } diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index a8e8e5f..55945f4 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -191,6 +191,9 @@ struct t3c_data { struct t3c_tid_entry *tid_release_list; spinlock_t tid_release_lock; struct work_struct tid_release_task; + + struct sk_buff *nofail_skb; + unsigned int release_list_incomplete; }; /* -- cgit v0.10.2 From 50d36a93dc2c773c9625c62275b88ac936d9c4ba Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Wed, 10 Jun 2009 04:21:55 +0000 Subject: vxge: No need for check vfree() pointer. vfree() does its own 'NULL' check, so no need for check before calling it. Signed-off-by: Figo.zhang Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 6b41c88..26cde57 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -1884,17 +1884,13 @@ void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool) mempool->memblock_size, dma_object); } - if (mempool->items_arr) - vfree(mempool->items_arr); + vfree(mempool->items_arr); - if (mempool->memblocks_dma_arr) - vfree(mempool->memblocks_dma_arr); + vfree(mempool->memblocks_dma_arr); - if (mempool->memblocks_priv_arr) - vfree(mempool->memblocks_priv_arr); + vfree(mempool->memblocks_priv_arr); - if (mempool->memblocks_arr) - vfree(mempool->memblocks_arr); + vfree(mempool->memblocks_arr); vfree(mempool); } -- cgit v0.10.2 From c0feed87fe452c20681ae29909adaecedd1ec9f3 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Wed, 10 Jun 2009 04:18:38 +0000 Subject: tehuti: No need check vfree() pointer. vfree() does its own 'NULL' check, so no need for check before calling it. Signed-off-by: Figo.zhang Signed-off-by: David S. Miller diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 093807a..3c2679c 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -948,8 +948,7 @@ static void print_rxfd(struct rxf_desc *rxfd); static void bdx_rxdb_destroy(struct rxdb *db) { - if (db) - vfree(db); + vfree(db); } static struct rxdb *bdx_rxdb_create(int nelem) @@ -1482,10 +1481,8 @@ static void bdx_tx_db_close(struct txdb *d) { BDX_ASSERT(d == NULL); - if (d->start) { - vfree(d->start); - d->start = NULL; - } + vfree(d->start); + d->start = NULL; } /************************************************************************* -- cgit v0.10.2 From b305be78a044c5f6a9d146229a280d08db0c630a Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Wed, 10 Jun 2009 02:18:35 +0000 Subject: be2net: Use cancel_delayed_work_sync instead of cancel_delayed_work() Use cancel_delayed_work_sycn instead of cancel_delayed_work() to reliably kill be_worker() as it rearms itself. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 347d002..69046a1 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1533,7 +1533,7 @@ static int be_close(struct net_device *netdev) struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec; - cancel_delayed_work(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_stop_queue(netdev); netif_carrier_off(netdev); -- cgit v0.10.2 From 6811086899f2740c08d0ade26f8b9d705708e0cc Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Wed, 10 Jun 2009 02:21:16 +0000 Subject: be2net: fix netdev stats rx_errors and rx_dropped Fix netdev stat rx_errors to cover length related errors and checksum errors and rx_dropped to the pkts dropped due to lack of buffers Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 69046a1..6487eb4 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -168,6 +168,7 @@ static void netdev_stats_update(struct be_adapter *adapter) struct be_port_rxf_stats *port_stats = &rxf_stats->port[adapter->port_num]; struct net_device_stats *dev_stats = &adapter->stats.net_stats; + struct be_erx_stats *erx_stats = &hw_stats->erx; dev_stats->rx_packets = port_stats->rx_total_frames; dev_stats->tx_packets = port_stats->tx_unicastframes + @@ -181,29 +182,33 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_errors = port_stats->rx_crc_errors + port_stats->rx_alignment_symbol_errors + port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; - - /* packet transmit problems */ - dev_stats->tx_errors = 0; - - /* no space in linux buffers */ - dev_stats->rx_dropped = 0; - - /* no space available in linux */ - dev_stats->tx_dropped = 0; - - dev_stats->multicast = port_stats->tx_multicastframes; - dev_stats->collisions = 0; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long + + port_stats->rx_dropped_too_small + + port_stats->rx_dropped_too_short + + port_stats->rx_dropped_header_too_small + + port_stats->rx_dropped_tcp_length + + port_stats->rx_dropped_runt + + port_stats->rx_tcp_checksum_errs + + port_stats->rx_ip_checksum_errs + + port_stats->rx_udp_checksum_errs; + + /* no space in linux buffers: best possible approximation */ + dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0]; /* detailed rx errors */ dev_stats->rx_length_errors = port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long; + /* receive ring buffer overflow */ dev_stats->rx_over_errors = 0; + dev_stats->rx_crc_errors = port_stats->rx_crc_errors; /* frame alignment errors */ dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; + /* receiver fifo overrun */ /* drops_no_pbuf is no per i/f, it's per BE card */ dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + @@ -211,6 +216,16 @@ static void netdev_stats_update(struct be_adapter *adapter) rxf_stats->rx_drops_no_pbuf; /* receiver missed packetd */ dev_stats->rx_missed_errors = 0; + + /* packet transmit problems */ + dev_stats->tx_errors = 0; + + /* no space available in linux */ + dev_stats->tx_dropped = 0; + + dev_stats->multicast = port_stats->tx_multicastframes; + dev_stats->collisions = 0; + /* detailed tx_errors */ dev_stats->tx_aborted_errors = 0; dev_stats->tx_carrier_errors = 0; -- cgit v0.10.2 From 76fbb42919396b9bf68c9a03ceb037c971a02e2f Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Wed, 10 Jun 2009 02:21:56 +0000 Subject: be2net: Fix rx stats updation in non-lro path rx stats are not getting updated when an rx_compl with only one frag is rcvd in non-lro path. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 6487eb4..5aadd71 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -743,7 +743,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, if (pktsize <= rx_frag_size) { BUG_ON(num_rcvd != 1); - return; + goto done; } /* More frags present for this completion */ @@ -765,6 +765,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, memset(page_info, 0, sizeof(*page_info)); } +done: be_rx_stats_update(adapter, pktsize, num_rcvd); return; } -- cgit v0.10.2 From a7a0ef31def6b6badd94fc96c8f17c2e18d91513 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Wed, 10 Jun 2009 02:23:28 +0000 Subject: be2net: Fix early reset of rx-completion be_rx_compl_get() must not reset(via the valid word) the rx_compl as the rx_compl is not processed yet; it must be reset after it is processed. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 5aadd71..86f70af 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -876,12 +876,19 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); - rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; - queue_tail_inc(&adapter->rx_obj.cq); return rxcp; } +/* To reset the valid bit, we need to reset the whole word as + * when walking the queue the valid entries are little-endian + * and invalid entries are host endian + */ +static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp) +{ + rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; +} + static inline struct page *be_alloc_pages(u32 size) { gfp_t alloc_flags = GFP_ATOMIC; @@ -1013,6 +1020,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* First cleanup pending rx completions */ while ((rxcp = be_rx_compl_get(adapter)) != NULL) { be_rx_compl_discard(adapter, rxcp); + be_rx_compl_reset(rxcp); be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); } @@ -1294,6 +1302,8 @@ int be_poll_rx(struct napi_struct *napi, int budget) be_rx_compl_process_lro(adapter, rxcp); else be_rx_compl_process(adapter, rxcp); + + be_rx_compl_reset(rxcp); } lro_flush_all(&adapter->rx_obj.lro_mgr); -- cgit v0.10.2 From 934037bc2ed29a94bbde72aa6a2e66bdc5861b98 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Wed, 10 Jun 2009 02:23:50 +0000 Subject: be2net: Fix be_tx_q_clean() being called on freed queues In the tx queue destroy path, be_tx_q_clean() is currently called after the tx queues are freed; it must be called before. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 86f70af..66bb568 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1056,8 +1056,13 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) struct be_queue_info *q; q = &adapter->tx_obj.q; - if (q->created) + if (q->created) { be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); + + /* No more tx completions can be rcvd now; clean up if there + * are any pending completions or pending tx requests */ + be_tx_q_clean(adapter); + } be_queue_free(adapter, q); q = &adapter->tx_obj.cq; @@ -1065,10 +1070,6 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); be_queue_free(adapter, q); - /* No more tx completions can be rcvd now; clean up if there are - * any pending completions or pending tx requests */ - be_tx_q_clean(adapter); - q = &adapter->tx_eq.q; if (q->created) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); -- cgit v0.10.2 From f2333a014c1e13ac8e1b73a6fd77731c524eff78 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Thu, 11 Jun 2009 02:49:10 -0700 Subject: netxen: No need to check vfree() pointer. vfree() does its own 'NULL' check, so no need for check before calling it. Signed-off-by: Figo.zhang Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 4a51c31..6f77ad5 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -178,10 +178,8 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - if (rds_ring->rx_buf_arr) { - vfree(rds_ring->rx_buf_arr); - rds_ring->rx_buf_arr = NULL; - } + vfree(rds_ring->rx_buf_arr); + rds_ring->rx_buf_arr = NULL; } kfree(recv_ctx->rds_rings); @@ -190,8 +188,7 @@ skip_rds: return; tx_ring = adapter->tx_ring; - if (tx_ring->cmd_buf_arr) - vfree(tx_ring->cmd_buf_arr); + vfree(tx_ring->cmd_buf_arr); } int netxen_alloc_sw_resources(struct netxen_adapter *adapter) -- cgit v0.10.2 From 2b85a34e911bf483c27cfdd124aeb1605145dc80 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 11 Jun 2009 02:55:43 -0700 Subject: net: No more expensive sock_hold()/sock_put() on each tx One of the problem with sock memory accounting is it uses a pair of sock_hold()/sock_put() for each transmitted packet. This slows down bidirectional flows because the receive path also needs to take a refcount on socket and might use a different cpu than transmit path or transmit completion path. So these two atomic operations also trigger cache line bounces. We can see this in tx or tx/rx workloads (media gateways for example), where sock_wfree() can be in top five functions in profiles. We use this sock_hold()/sock_put() so that sock freeing is delayed until all tx packets are completed. As we also update sk_wmem_alloc, we could offset sk_wmem_alloc by one unit at init time, until sk_free() is called. Once sk_free() is called, we atomic_dec_and_test(sk_wmem_alloc) to decrement initial offset and atomicaly check if any packets are in flight. skb_set_owner_w() doesnt call sock_hold() anymore sock_wfree() doesnt call sock_put() anymore, but check if sk_wmem_alloc reached 0 to perform the final freeing. Drawback is that a skb->truesize error could lead to unfreeable sockets, or even worse, prematurely calling __sk_free() on a live socket. Nice speedups on SMP. tbench for example, going from 2691 MB/s to 2711 MB/s on my 8 cpu dev machine, even if tbench was not really hitting sk_refcnt contention point. 5 % speedup on a UDP transmit workload (depends on number of flows), lowering TX completion cpu usage. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/sock.h b/include/net/sock.h index 4bb1ff9..010e14a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1217,9 +1217,13 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from, static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) { - sock_hold(sk); skb->sk = sk; skb->destructor = sock_wfree; + /* + * We used to take a refcount on sk, but following operation + * is enough to guarantee sk_free() wont free this sock until + * all in-flight packets are completed + */ atomic_add(skb->truesize, &sk->sk_wmem_alloc); } diff --git a/net/core/sock.c b/net/core/sock.c index 04e35eb..06e26b7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1008,7 +1008,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, } EXPORT_SYMBOL(sk_alloc); -void sk_free(struct sock *sk) +static void __sk_free(struct sock *sk) { struct sk_filter *filter; @@ -1031,6 +1031,17 @@ void sk_free(struct sock *sk) put_net(sock_net(sk)); sk_prot_free(sk->sk_prot_creator, sk); } + +void sk_free(struct sock *sk) +{ + /* + * We substract one from sk_wmem_alloc and can know if + * some packets are still in some tx queue. + * If not null, sock_wfree() will call __sk_free(sk) later + */ + if (atomic_dec_and_test(&sk->sk_wmem_alloc)) + __sk_free(sk); +} EXPORT_SYMBOL(sk_free); /* @@ -1071,7 +1082,10 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; atomic_set(&newsk->sk_rmem_alloc, 0); - atomic_set(&newsk->sk_wmem_alloc, 0); + /* + * sk_wmem_alloc set to one (see sk_free() and sock_wfree()) + */ + atomic_set(&newsk->sk_wmem_alloc, 1); atomic_set(&newsk->sk_omem_alloc, 0); skb_queue_head_init(&newsk->sk_receive_queue); skb_queue_head_init(&newsk->sk_write_queue); @@ -1175,12 +1189,18 @@ void __init sk_init(void) void sock_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; + int res; /* In case it might be waiting for more memory. */ - atomic_sub(skb->truesize, &sk->sk_wmem_alloc); + res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc); if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) sk->sk_write_space(sk); - sock_put(sk); + /* + * if sk_wmem_alloc reached 0, we are last user and should + * free this sock, as sk_free() call could not do it. + */ + if (res == 0) + __sk_free(sk); } EXPORT_SYMBOL(sock_wfree); @@ -1819,6 +1839,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_stamp = ktime_set(-1L, 0); atomic_set(&sk->sk_refcnt, 1); + atomic_set(&sk->sk_wmem_alloc, 1); atomic_set(&sk->sk_drops, 0); } EXPORT_SYMBOL(sock_init_data); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 9248d28..2470262 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -498,7 +498,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) BUG_ON(frag->sk); if (skb->sk) { - sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; truesizes += frag->truesize; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index db6c722..7c76e3d 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -680,7 +680,6 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) BUG_ON(frag->sk); if (skb->sk) { - sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; truesizes += frag->truesize; -- cgit v0.10.2 From fb10167478a3a8e29fe122a7bf4c67b5cfc48a1b Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 7 May 2009 10:27:42 -0700 Subject: wimax/i2400m: introduce module parameter to disable entering power save The i2400m driver waits for the device to report being ready for entering power save before asking it to do so. This module parameter allows control of said operation; if disabled, the driver won't ask the device to enter power save mode. This is useful in setups where power saving is not so important or when the overhead imposed by network reentry after power save is not acceptable; by combining this with parameter 'idle_mode_disabled', the driver will always maintain both the connection and the device in active state. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index bd193ae..89cdfe4 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -505,8 +505,15 @@ void i2400m_report_hook(struct i2400m *i2400m, * it. */ case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { - d_printf(1, dev, "ready for powersave, requesting\n"); - i2400m_cmd_enter_powersave(i2400m); + if (i2400m_power_save_disabled) + d_printf(1, dev, "ready for powersave, " + "not requesting (disabled by module " + "parameter)\n"); + else { + d_printf(1, dev, "ready for powersave, " + "requesting\n"); + i2400m_cmd_enter_powersave(i2400m); + } } break; }; diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index ef16c57..86dd18a 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -82,6 +82,14 @@ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644); MODULE_PARM_DESC(rx_reorder_disabled, "If true, RX reordering will be disabled."); +int i2400m_power_save_disabled; /* 0 (power saving enabled) by default */ +module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); +MODULE_PARM_DESC(power_save_disabled, + "If true, the driver will not tell the device to enter " + "power saving mode when it reports it is ready for it. " + "False by default (so the device is told to do power " + "saving)."); + /** * i2400m_queue_work - schedule work on a i2400m's queue * diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 434ba31..8dba246 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -709,6 +709,7 @@ static const __le32 i2400m_SBOOT_BARKER[4] = { cpu_to_le32(I2400M_SBOOT_BARKER) }; +extern int i2400m_power_save_disabled; /* * Utility functions -- cgit v0.10.2 From fff1068559a2ae00a036b80c5df3c564fc6c6305 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 8 May 2009 08:58:51 -0700 Subject: wimax/i2400m: don't call netif_start_queue() in _tx_msg_sent() Reported and fixed by Cindy H Kao. When the device is stopped __i2400m_dev_stop() stops the network queue. However, when this is done in the middle of heavy network operation, when the bus-specific subdriver is still wrapping up and it reports a sent TX transaction with _tx_msg_sent() right after the device was stopped, the queue was being started again, which was causing a stream of oopsen and finally a panic. In any case, said call has no place there. It's a left over from an early implementation that was discarded later on. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 613a88f..8ef724d 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -773,7 +773,6 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m) n = i2400m->tx_out / I2400M_TX_BUF_SIZE; i2400m->tx_out %= I2400M_TX_BUF_SIZE; i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; - netif_start_queue(i2400m->wimax_dev.net_dev); spin_unlock_irqrestore(&i2400m->tx_lock, flags); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); } -- cgit v0.10.2 From e9a6b45be580d648ed2f21646214733504bd4d6f Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 8 May 2009 13:02:41 -0700 Subject: wimax/i2400m: i2400m's work queue should be initialized before RX support RX support is the only user of the work-queue, to process reports/notifications from the device. Thus, it needs the work queue to be initialized first. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 86dd18a..006eb12 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -385,6 +385,11 @@ error: * Uploads firmware and brings up all the resources needed to be able * to communicate with the device. * + * The workqueue has to be setup early, at least before RX handling + * (it's only real user for now) so it can process reports as they + * arrive. We also want to destroy it if we retry, to make sure it is + * flushed...easier like this. + * * TX needs to be setup before the bus-specific code (otherwise on * shutdown, the bus-tx code could try to access it). */ @@ -410,15 +415,15 @@ retry: result = i2400m_rx_setup(i2400m); if (result < 0) goto error_rx_setup; - result = i2400m->bus_dev_start(i2400m); - if (result < 0) - goto error_bus_dev_start; i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); if (i2400m->work_queue == NULL) { result = -ENOMEM; dev_err(dev, "cannot create workqueue\n"); goto error_create_workqueue; } + result = i2400m->bus_dev_start(i2400m); + if (result < 0) + goto error_bus_dev_start; result = i2400m_firmware_check(i2400m); /* fw versions ok? */ if (result < 0) goto error_fw_check; @@ -440,10 +445,10 @@ retry: error_dev_initialize: error_check_mac_addr: error_fw_check: - destroy_workqueue(i2400m->work_queue); -error_create_workqueue: i2400m->bus_dev_stop(i2400m); error_bus_dev_start: + destroy_workqueue(i2400m->work_queue); +error_create_workqueue: i2400m_rx_release(i2400m); error_rx_setup: i2400m_tx_release(i2400m); @@ -479,7 +484,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) * * Returns: 0 if ok, < 0 errno code on error. * - * Releases all the resources allocated to communicate with the device. + * Releases all the resources allocated to communicate with the + * device. Note we cannot destroy the workqueue earlier as until RX is + * fully destroyed, it could still try to schedule jobs. */ static void __i2400m_dev_stop(struct i2400m *i2400m) @@ -491,8 +498,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m) wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); i2400m_dev_shutdown(i2400m); i2400m->ready = 0; - destroy_workqueue(i2400m->work_queue); i2400m->bus_dev_stop(i2400m); + destroy_workqueue(i2400m->work_queue); i2400m_rx_release(i2400m); i2400m_tx_release(i2400m); wimax_state_change(wimax_dev, WIMAX_ST_DOWN); -- cgit v0.10.2 From 16eafba8defcd507831eec926b61db474af0aabb Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 8 May 2009 12:46:26 -0700 Subject: wimax/i2400m: i2400m_schedule_work() doesn't need i2400m->work_queue By mistake, the BUG_ON() check was left in there and it will fail when called if i2400m->work_queue is still not setup. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 006eb12..897794c 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -180,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m, int result; struct i2400m_work *iw; - BUG_ON(i2400m->work_queue == NULL); result = -ENOMEM; iw = kzalloc(sizeof(*iw), gfp_flags); if (iw == NULL) -- cgit v0.10.2 From ead68239913cb9c19150facf1656517f81d66fcb Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Tue, 12 May 2009 06:22:27 -0700 Subject: wimax/i2400m: Change d_printf() level for secure boot messages Changing debug level of print out to support validation engineers getting the messages they need. Signed-off-by: diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 675c6ce..7ee1b99 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -532,14 +532,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, cmd = (void *) bcf + offset; if (i2400m->sboot == 0) { struct i2400m_bootrom_header jump_ack; - d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n", + d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); cmd->data_size = 0; ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), &jump_ack, sizeof(jump_ack), 0); } else { - d_printf(3, dev, "secure boot, jumping to 0x%08x\n", + d_printf(1, dev, "secure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); cmd_buf = i2400m->bm_cmd_buf; memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); -- cgit v0.10.2 From 10b1de6b774a531c9054ee01e734a85ffbab179e Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Tue, 12 May 2009 07:54:00 -0700 Subject: wimax/i2400m/sdio: Implement I2400M_RT_BUS reset type This reset type causes the WiMAX function to be disabled and re-enabled, which will force the WiMAX device to reset and enter boot mode. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Dirk Brandewie diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h index 08c2fb7..2071721 100644 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ b/drivers/net/wimax/i2400m/i2400m-sdio.h @@ -78,6 +78,8 @@ enum { /* The number of ticks to wait for the device to signal that * it is ready */ I2400MS_INIT_SLEEP_INTERVAL = 10, + /* How long to wait for the device to settle after reset */ + I2400MS_SETTLE_TIME = 40, }; diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 777c981..d6fac5c 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -255,7 +255,7 @@ error_kzalloc: static int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) { - int result; + int result = 0; struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); struct device *dev = i2400m_dev(i2400m); @@ -280,8 +280,22 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) sizeof(i2400m_COLD_BOOT_BARKER)); else if (rt == I2400M_RT_BUS) { do_bus_reset: - dev_err(dev, "FIXME: SDIO bus reset not implemented\n"); - result = rt == I2400M_RT_WARM ? -ENODEV : -ENOSYS; + /* call netif_tx_disable() before sending IOE disable, + * so that all the tx from network layer are stopped + * while IOE is being reset. Make sure it is called + * only after register_netdev() was issued. + */ + if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED) + netif_tx_disable(i2400m->wimax_dev.net_dev); + + sdio_claim_host(i2400ms->func); + sdio_disable_func(i2400ms->func); + sdio_release_host(i2400ms->func); + + /* Wait for the device to settle */ + msleep(40); + + result = i2400ms_enable_function(i2400ms->func); } else BUG(); if (result < 0 && rt != I2400M_RT_BUS) { -- cgit v0.10.2 From 8593a1967fb9746d318dde88a0a39a36dbfc3445 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 20 May 2009 16:53:30 -0700 Subject: wimax/i2400m: rename misleading I2400M_PL_PAD to I2400M_PL_ALIGN The constant is being use as an alignment factor, not as a padding factor; made reading/reviewing the code quite confusing. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 7ee1b99..26924f1 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -397,7 +397,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, unsigned int direct, unsigned int do_csum) { int ret; - size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD); + size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN); struct device *dev = i2400m_dev(i2400m); struct { struct i2400m_bootrom_header cmd; diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 7643850..07c32e6 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -1148,7 +1148,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) num_pls = le16_to_cpu(msg_hdr->num_pls); pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */ num_pls * sizeof(msg_hdr->pld[0]); - pl_itr = ALIGN(pl_itr, I2400M_PL_PAD); + pl_itr = ALIGN(pl_itr, I2400M_PL_ALIGN); if (pl_itr > skb->len) { /* got all the payload descriptors? */ dev_err(dev, "RX: HW BUG? message too short (%u bytes) for " "%u payload descriptors (%zu each, total %zu)\n", @@ -1166,7 +1166,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) single_last = num_pls == 1 || i == num_pls - 1; i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i], skb->data + pl_itr); - pl_itr += ALIGN(pl_size, I2400M_PL_PAD); + pl_itr += ALIGN(pl_size, I2400M_PL_ALIGN); cond_resched(); /* Don't monopolize */ } kfree_skb(skb); diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 8ef724d..a635fd7 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -491,7 +491,7 @@ void i2400m_tx_close(struct i2400m *i2400m) */ hdr_size = sizeof(*tx_msg) + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]); - hdr_size = ALIGN(hdr_size, I2400M_PL_PAD); + hdr_size = ALIGN(hdr_size, I2400M_PL_ALIGN); tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; tx_msg_moved = (void *) tx_msg + tx_msg->offset; memmove(tx_msg_moved, tx_msg, hdr_size); @@ -574,7 +574,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", i2400m, buf, buf_len, pl_type); - padded_len = ALIGN(buf_len, I2400M_PL_PAD); + padded_len = ALIGN(buf_len, I2400M_PL_ALIGN); d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); /* If there is no current TX message, create one; if the * current one is out of payload slots or we have a singleton, diff --git a/include/linux/wimax/i2400m.h b/include/linux/wimax/i2400m.h index d5148a7..433693e 100644 --- a/include/linux/wimax/i2400m.h +++ b/include/linux/wimax/i2400m.h @@ -266,7 +266,7 @@ enum i2400m_ro_type { /* Misc constants */ enum { - I2400M_PL_PAD = 16, /* Payload data size alignment */ + I2400M_PL_ALIGN = 16, /* Payload data size alignment */ I2400M_PL_SIZE_MAX = 0x3EFF, I2400M_MAX_PLS_IN_MSG = 60, /* protocol barkers: sync sequences; for notifications they -- cgit v0.10.2 From c56affafdd29eb9764b0e35e3434cc06f6bc3781 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 20 May 2009 17:16:05 -0700 Subject: wimax/i2400m: fix panic/warnings caused by missed check on empty TX message In some situations, when a new TX message header is started, there might be no space for data payloads. In this case the message is left with zero payloads and the i2400m_tx_close() function has just to mark it as "to skip". If it tries to go ahead it will overwrite things because there is no space to add padding as defined by the bus-specific layer. This can cause buffer overruns and in some stress cases, panics. Found and diagnosed by Cindy H. Kao. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index a635fd7..7c46c05 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -474,10 +474,18 @@ void i2400m_tx_close(struct i2400m *i2400m) struct i2400m_msg_hdr *tx_msg_moved; size_t aligned_size, padding, hdr_size; void *pad_buf; + unsigned num_pls; if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ goto out; - + num_pls = le16_to_cpu(tx_msg->num_pls); + /* We can get this situation when a new message was started + * and there was no space to add payloads before hitting the + tail (and taking padding into consideration). */ + if (num_pls == 0) { + tx_msg->size |= I2400M_TX_SKIP; + goto out; + } /* Relocate the message header * * Find the current header size, align it to 16 and if we need -- cgit v0.10.2 From 2971a5bac8cab3cb56f19e9c494ecb3b120c5199 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 20 May 2009 17:40:35 -0700 Subject: wimax/i2400m: fix panic due to missed corner cases on tail_room calculation i2400m_tx_skip_tail() needs to handle the special case of being called when the tail room that is left over in the FIFO is zero. This happens when a TX message header was opened at the very end of the FIFO (without payloads). The i2400m_tx_close() code already marked said TX message (header) to be skipped and this function should be doing nothing. It is called anyway because it is part of a common "corner case" path handling which takes care of more cases than only this one. The tail room computation was also improved to take care of the case when tx_in is at the end of the buffer boundary; tail_room has to be modded (%) to the buffer size. To do that in a single well-documented place, __i2400m_tx_tail_room() is introduced and used. Treat i2400m->tx_in == 0 as a corner case and handle it accordingly. Found and diagnosed by Cindy H. Kao. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 7c46c05..4295dcf 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -278,6 +278,48 @@ enum { #define TAIL_FULL ((void *)~(unsigned long)NULL) /* + * Calculate how much tail room is available + * + * Note the trick here. This path is ONLY caleed for Case A (see + * i2400m_tx_fifo_push() below), where we have: + * + * Case A + * N ___________ + * | tail room | + * | | + * |<- IN ->| + * | | + * | data | + * | | + * |<- OUT ->| + * | | + * | head room | + * 0 ----------- + * + * When calculating the tail_room, tx_in might get to be zero if + * i2400m->tx_in is right at the end of the buffer (really full + * buffer) if there is no head room. In this case, tail_room would be + * I2400M_TX_BUF_SIZE, although it is actually zero. Hence the final + * mod (%) operation. However, when doing this kind of optimization, + * i2400m->tx_in being zero would fail, so we treat is an a special + * case. + */ +static inline +size_t __i2400m_tx_tail_room(struct i2400m *i2400m) +{ + size_t tail_room; + size_t tx_in; + + if (unlikely(i2400m->tx_in) == 0) + return I2400M_TX_BUF_SIZE; + tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; + tail_room = I2400M_TX_BUF_SIZE - tx_in; + tail_room %= I2400M_TX_BUF_SIZE; + return tail_room; +} + + +/* * Allocate @size bytes in the TX fifo, return a pointer to it * * @i2400m: device descriptor @@ -338,7 +380,7 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) return NULL; } /* Is there space at the tail? */ - tail_room = I2400M_TX_BUF_SIZE - i2400m->tx_in % I2400M_TX_BUF_SIZE; + tail_room = __i2400m_tx_tail_room(i2400m); if (tail_room < needed_size) { if (i2400m->tx_out % I2400M_TX_BUF_SIZE < i2400m->tx_in % I2400M_TX_BUF_SIZE) { @@ -367,17 +409,29 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the * header). * + * Tail room can get to be zero if a message was opened when there was + * space only for a header. _tx_close() will mark it as to-skip (as it + * will have no payloads) and there will be no more space to flush, so + * nothing has to be done here. This is probably cheaper than ensuring + * in _tx_new() that there is some space for payloads...as we could + * always possibly hit the same problem if the payload wouldn't fit. + * * Note: * * Assumes i2400m->tx_lock is taken, and we use that as a barrier + * + * This path is only taken for Case A FIFO situations [see + * i2400m_tx_fifo_push()] */ static void i2400m_tx_skip_tail(struct i2400m *i2400m) { struct device *dev = i2400m_dev(i2400m); size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; - size_t tail_room = I2400M_TX_BUF_SIZE - tx_in; + size_t tail_room = __i2400m_tx_tail_room(i2400m); struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; + if (unlikely(tail_room == 0)) + return; BUG_ON(tail_room < sizeof(*msg)); msg->size = tail_room | I2400M_TX_SKIP; d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", -- cgit v0.10.2 From b4bd07e3b13e3c848c7678c4fc870cca1d22ed4e Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 21 May 2009 19:46:45 -0700 Subject: wimax/i2400m: don't reset device on i2400m_dev_shutdown() i2400m_dev_shutdown() tried to reset the device to put it in a known state before shutting down. But that turned out to be pointless. We reach this case in two paths: 1 - when the device resets, to clean up state 2 - when the driver is unloaded, for the same however, in both cases it is pointless; in (1) the device is already reset, why do it again? in (2) we can't -- the USB stack, for example, doesn't allow communicating with the device when the driver is being unbound and if the device is disconnected, the device is gone already. So just remove it. Leave the function as a placeholder for future cleanups that will be done from data allocated by the driver during device operation. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index 89cdfe4..d8e0cdf 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -1396,16 +1396,16 @@ error: * * @i2400m: device descriptor * - * Gracefully stops the device, moving it to the lowest power - * consumption state possible. + * Release resources acquired during the running of the device; in + * theory, should also tell the device to go to sleep, switch off the + * radio, all that, but at this point, in most cases (driver + * disconnection, reset handling) we can't even talk to the device. */ void i2400m_dev_shutdown(struct i2400m *i2400m) { - int result = -ENODEV; struct device *dev = i2400m_dev(i2400m); d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - result = i2400m->bus_reset(i2400m, I2400M_RT_WARM); - d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result); + d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); return; } -- cgit v0.10.2 From 59063afa0afabc68d2b6ca0d106da9165e1c7d39 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 27 May 2009 01:04:40 -0700 Subject: wimax/i2400m: fix oops when the TX FIFO fills up due to a missing check When the TX FIFO filled up and i2400m_tx_new() failed to allocate a new TX message header, a missing check for said condition was causing a kernel oops when trying to dereference a NULL i2400m->tx_msg pointer. Found and diagnosed by Cindy H. Kao. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 4295dcf..fa16ccf 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -653,6 +653,8 @@ try_new: i2400m_tx_close(i2400m); i2400m_tx_new(i2400m); } + if (i2400m->tx_msg == NULL) + goto error_tx_new; if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { d_printf(2, dev, "TX: message too big, going new\n"); i2400m_tx_close(i2400m); -- cgit v0.10.2 From b4013f91cdda10f3f15530914f3c7f39738b0b50 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 3 Jun 2009 09:45:55 +0800 Subject: wimax/i2400m: if a device reboot happens during probe, handle it When a device reboot happens when we are under probe, with init_mutex taken, make sure we can recover. Have dev_reset_handle set boot mode and i2400m_msg_to_dev() will see it and fail gracefully instead of timing out. Found and diagnosed by Cindy H. Kao. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index d8e0cdf..f9399f2 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -695,6 +695,7 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", i2400m, buf, buf_len); + rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ if (i2400m->boot_mode) return ERR_PTR(-ENODEV); diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 897794c..e8d022d 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -610,6 +610,8 @@ out: */ int i2400m_dev_reset_handle(struct i2400m *i2400m) { + i2400m->boot_mode = 1; + wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, GFP_ATOMIC); } diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 26924f1..01c926e 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -985,6 +985,7 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", i2400m, bcf, bcf_size); i2400m->boot_mode = 1; + wmb(); /* Make sure other readers see it */ hw_reboot: if (count-- == 0) { ret = -ERESTARTSYS; @@ -1033,6 +1034,7 @@ hw_reboot: d_printf(2, dev, "fw %s successfully uploaded\n", i2400m->fw_name); i2400m->boot_mode = 0; + wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ error_dnload_finalize: error_dnload_bcf: error_dnload_init: -- cgit v0.10.2 From ecddfd5ed73c070413f07a5251c16c10e69f35a2 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 3 Jun 2009 16:13:14 +0800 Subject: wimax/i2400m: Allow bus-specific driver to specify retry count The code that sets up the i2400m (firmware load and general driver setup after it) includes a couple of retry loops. The SDIO device sometimes can get in more complicated corners than the USB one (due to its interaction with other SDIO functions), that require trying a few more times. To solve that, without having a failing USB device taking longer to be considered dead, allow the retry counts to be specified by the bus-specific driver, which the general driver takes as a parameter. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index e8d022d..8d8628e 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -399,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) struct wimax_dev *wimax_dev = &i2400m->wimax_dev; struct net_device *net_dev = wimax_dev->net_dev; struct device *dev = i2400m_dev(i2400m); - int times = 3; + int times = i2400m->bus_bm_retries; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); retry: diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 01c926e..c48fa24 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -980,7 +980,7 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, { int ret = 0; struct device *dev = i2400m_dev(i2400m); - int count = I2400M_BOOT_RETRIES; + int count = i2400m->bus_bm_retries; d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", i2400m, bcf, bcf_size); diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 8dba246..59cd783 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -150,6 +150,7 @@ enum { /* Firmware uploading */ I2400M_BOOT_RETRIES = 3, + I3200_BOOT_RETRIES = 3, /* Size of the Boot Mode Command buffer */ I2400M_BM_CMD_BUF_SIZE = 16 * 1024, I2400M_BM_ACK_BUF_SIZE = 256, @@ -224,6 +225,17 @@ struct i2400m_roq; * process, so it cannot rely on common infrastructure being laid * out. * + * @bus_bm_retries: [fill] How many times shall a firmware upload / + * device initialization be retried? Different models of the same + * device might need different values, hence it is set by the + * bus-specific driver. Note this value is used in two places, + * i2400m_fw_dnload() and __i2400m_dev_start(); they won't become + * multiplicative (__i2400m_dev_start() calling N times + * i2400m_fw_dnload() and this trying N times to download the + * firmware), as if __i2400m_dev_start() only retries if the + * firmware crashed while initializing the device (not in a + * general case). + * * @bus_bm_cmd_send: [fill] Function called to send a boot-mode * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This * is synchronous and has to return 0 if ok or < 0 errno code in @@ -399,6 +411,8 @@ struct i2400m { size_t bus_tx_block_size; size_t bus_pl_size_max; + unsigned bus_bm_retries; + int (*bus_dev_start)(struct i2400m *); void (*bus_dev_stop)(struct i2400m *); void (*bus_tx_kick)(struct i2400m *); diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index d6fac5c..afde897 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -418,6 +418,9 @@ int i2400ms_probe(struct sdio_func *func, i2400m->bus_dev_stop = i2400ms_bus_dev_stop; i2400m->bus_tx_kick = i2400ms_bus_tx_kick; i2400m->bus_reset = i2400ms_bus_reset; + /* The iwmc3200-wimax sometimes requires the driver to try + * hard when we paint it into a corner. */ + i2400m->bus_bm_retries = I3200_BOOT_RETRIES; i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; i2400m->bus_fw_names = i2400ms_bus_fw_names; diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 1785132..ebc05da 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -399,6 +399,7 @@ int i2400mu_probe(struct usb_interface *iface, i2400m->bus_dev_stop = i2400mu_bus_dev_stop; i2400m->bus_tx_kick = i2400mu_bus_tx_kick; i2400m->bus_reset = i2400mu_bus_reset; + i2400m->bus_bm_retries = I2400M_BOOT_RETRIES; i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; i2400m->bus_fw_names = i2400mu_bus_fw_names; -- cgit v0.10.2 From 7308a0c23901f2a295265bb71d8521ef7d47bf4c Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 21 May 2009 11:56:34 -0700 Subject: wimax/i2400m: move boot time poke table out of common driver This change moves the table of "pokes" performed on the device at boot time to the bus specific portion of the driver. Different models of the i2400m device supported by this driver require different poke tables, thus having a single table that works for all is impossible. For that, the table is moved to the bus-specific driver, who can decide which table to use based on the specifics of the device and point the generic driver to it. Signed-off-by: Dirk Brandewie diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index c48fa24..349344a 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -770,40 +770,21 @@ error_read_mac: static int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) { -#define POKE(a, d) { \ - .address = cpu_to_le32(a), \ - .data = cpu_to_le32(d) \ -} - static const struct { - __le32 address; - __le32 data; - } i2400m_pokes[] = { - POKE(0x081A58, 0xA7810230), - POKE(0x080040, 0x00000000), - POKE(0x080048, 0x00000082), - POKE(0x08004C, 0x0000081F), - POKE(0x080054, 0x00000085), - POKE(0x080058, 0x00000180), - POKE(0x08005C, 0x00000018), - POKE(0x080060, 0x00000010), - POKE(0x080574, 0x00000001), - POKE(0x080550, 0x00000005), - POKE(0xAE0000, 0x00000000), - }; -#undef POKE - unsigned i; - int ret; + unsigned i = 0; + int ret = 0; struct device *dev = i2400m_dev(i2400m); - - dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n"); - d_fnstart(5, dev, "(i2400m %p)\n", i2400m); - for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) { - ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data, - sizeof(i2400m_pokes[i].data), - i2400m_pokes[i].address, 1, 1); - if (ret < 0) - break; + if (i2400m->bus_bm_pokes_table) { + while (i2400m->bus_bm_pokes_table[i].address) { + ret = i2400m_download_chunk( + i2400m, + &i2400m->bus_bm_pokes_table[i].data, + sizeof(i2400m->bus_bm_pokes_table[i].data), + i2400m->bus_bm_pokes_table[i].address, 1, 1); + if (ret < 0) + break; + i++; + } } d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); return ret; diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 59cd783..1fe5da4 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -156,6 +156,27 @@ enum { I2400M_BM_ACK_BUF_SIZE = 256, }; +/** + * struct i2400m_poke_table - Hardware poke table for the Intel 2400m + * + * This structure will be used to create a device specific poke table + * to put the device in a consistant state at boot time. + * + * @address: The device address to poke + * + * @data: The data value to poke to the device address + * + */ +struct i2400m_poke_table{ + __le32 address; + __le32 data; +}; + +#define I2400M_FW_POKE(a, d) { \ + .address = cpu_to_le32(a), \ + .data = cpu_to_le32(d) \ +} + /** * i2400m_reset_type - methods to reset a device @@ -264,6 +285,12 @@ struct i2400m_roq; * address provided in boot mode is kind of broken and needs to * be re-read later on. * + * @bus_bm_pokes_table: [fill/optional] A table of device addresses + * and values that will be poked at device init time to move the + * device to the correct state for the type of boot/firmware being + * used. This table MUST be terminated with (0x000000, + * 0x00000000) or bad things will happen. + * * * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX * stack. Due to the way a net_device is allocated, we need to @@ -424,6 +451,7 @@ struct i2400m { struct i2400m_bootrom_header *, size_t); const char **bus_fw_names; unsigned bus_bm_mac_addr_impaired:1; + const struct i2400m_poke_table *bus_bm_pokes_table; spinlock_t tx_lock; /* protect TX state */ void *tx_buf; -- cgit v0.10.2 From 1c0b2dd75772cbce0aef8886b7f38313542216de Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 21 May 2009 11:56:35 -0700 Subject: wimax/i2400m/sdio: Add device specific poke table. Add a poke table for the SDIO device (as it is different than USB). Signed-off-by: Dirk Brandewie diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index afde897..74de174 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -78,6 +78,14 @@ static const char *i2400ms_bus_fw_names[] = { }; +static const struct i2400m_poke_table i2400ms_pokes[] = { + I2400M_FW_POKE(0x6BE260, 0x00000088), + I2400M_FW_POKE(0x080550, 0x00000005), + I2400M_FW_POKE(0xAE0000, 0x00000000), + I2400M_FW_POKE(0x000000, 0x00000000), /* MUST be 0 terminated or bad + * things will happen */ +}; + /* * Enable the SDIO function * @@ -425,6 +433,7 @@ int i2400ms_probe(struct sdio_func *func, i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; i2400m->bus_fw_names = i2400ms_bus_fw_names; i2400m->bus_bm_mac_addr_impaired = 1; + i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; sdio_claim_host(func); result = sdio_set_block_size(func, I2400MS_BLK_SIZE); -- cgit v0.10.2 From 6e053d6c79b3c1c9f6efc6563a811023c41be86a Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 5 Jun 2009 09:31:26 +0800 Subject: wimax/i2400m: don't reset device when bootrom init retries are exceeded When i2400m_bootrom_init() fails to put the device into a state of being ready to accept firmware, the driver was currently trying to reset it if it failed to do so. This is not too useful; as part of trying to put the device in the right state a few resets have already been tried. At this point, things are probably fried out and an extra reset might do more harm than good (for example causing reseting of other functions in the same composite device). So it is left up to the callers to determine the error path to take (at the end this is always i2400m_setup(), who depending on how many retries are left, might give up on the device). From a fix by Cindy H. Kao. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 349344a..e81750e 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -696,8 +696,7 @@ error_dev_gone: return result; error_timeout: - dev_err(dev, "Timed out waiting for reboot ack, resetting\n"); - i2400m->bus_reset(i2400m, I2400M_RT_BUS); + dev_err(dev, "Timed out waiting for reboot ack\n"); result = -ETIMEDOUT; goto exit_timeout; } -- cgit v0.10.2 From 16820c166d3ad5973d388b5aa70ee7e535386657 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 7 May 2009 01:02:39 -0700 Subject: wimax/i2400m/sdio: Move all the RX code to a unified, IRQ based receive routine The current SDIO code was working in polling mode for boot-mode (firmware load) mode. This was causing issues on some hardware. Moved all the RX code to use a unified IRQ handler that based on the type of data the device is sending can discriminate and decide which is the right destination. As well, all the reads from the device are made to be at least the block size (256); the driver will ignore the rest when not needed. Signed-off-by: Dirk Brandewie Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h index 2071721..9c4e318 100644 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ b/drivers/net/wimax/i2400m/i2400m-sdio.h @@ -107,6 +107,10 @@ struct i2400ms { char tx_wq_name[32]; struct dentry *debugfs_dentry; + + wait_queue_head_t bm_wfa_wq; + int bm_wait_result; + size_t bm_ack_size; }; @@ -131,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, struct i2400m_bootrom_header *, size_t); +extern void i2400ms_bus_bm_release(struct i2400m *); +extern int i2400ms_bus_bm_setup(struct i2400m *); + #endif /* #ifndef __I2400M_SDIO_H__ */ diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c index 3487205..7d6ec0f 100644 --- a/drivers/net/wimax/i2400m/sdio-fw.c +++ b/drivers/net/wimax/i2400m/sdio-fw.c @@ -46,17 +46,24 @@ * Inaky Perez-Gonzalez * - SDIO rehash for changes in the bus-driver model * + * Dirk Brandewie + * - Make it IRQ based, not polling + * * THE PROCEDURE * * See fw.c for the generic description of this procedure. * * This file implements only the SDIO specifics. It boils down to how * to send a command and waiting for an acknowledgement from the - * device. We do polled reads. + * device. + * + * All this code is sequential -- all i2400ms_bus_bm_*() functions are + * executed in the same thread, except i2400ms_bm_irq() [on its own by + * the SDIO driver]. This makes it possible to avoid locking. * * COMMAND EXECUTION * - * THe generic firmware upload code will call i2400m_bus_bm_cmd_send() + * The generic firmware upload code will call i2400m_bus_bm_cmd_send() * to send commands. * * The SDIO devices expects things in 256 byte blocks, so it will pad @@ -64,12 +71,15 @@ * * ACK RECEPTION * - * This works in polling mode -- the fw loader says when to wait for - * data and for that it calls i2400ms_bus_bm_wait_for_ack(). + * This works in IRQ mode -- the fw loader says when to wait for data + * and for that it calls i2400ms_bus_bm_wait_for_ack(). * - * This will poll the device for data until it is received. We need to - * receive at least as much bytes as where asked for (although it'll - * always be a multiple of 256 bytes). + * This checks if there is any data available (RX size > 0); if not, + * waits for the IRQ handler to notify about it. Once there is data, + * it is read and passed to the caller. Doing it this way we don't + * need much coordination/locking, and it makes it much more difficult + * for an interrupt to be lost and the wait_for_ack() function getting + * stuck even when data is pending. */ #include #include "i2400m-sdio.h" @@ -78,6 +88,7 @@ #define D_SUBMODULE fw #include "sdio-debug-levels.h" + /* * Send a boot-mode command to the SDIO function * @@ -139,7 +150,7 @@ error_too_big: /* - * Read an ack from the device's boot-mode (polling) + * Read an ack from the device's boot-mode * * @i2400m: * @_ack: pointer to where to store the read data @@ -150,75 +161,49 @@ error_too_big: * The ACK for a BM command is always at least sizeof(*ack) bytes, so * check for that. We don't need to check for device reboots * - * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout; - * this way we have control over it...there is no way that I know - * of setting an SDIO transaction timeout. */ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, struct i2400m_bootrom_header *ack, size_t ack_size) { - int result; - ssize_t rx_size; - u64 timeout; + ssize_t result; struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; + int size; BUG_ON(sizeof(*ack) > ack_size); d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", i2400m, ack, ack_size); - timeout = get_jiffies_64() + 2 * HZ; - sdio_claim_host(func); - while (1) { - if (time_after64(get_jiffies_64(), timeout)) { - rx_size = -ETIMEDOUT; - dev_err(dev, "timeout waiting for ack data\n"); - goto error_timedout; - } + spin_lock(&i2400m->rx_lock); + i2400ms->bm_ack_size = -EINPROGRESS; + spin_unlock(&i2400m->rx_lock); - /* Find the RX size, check if it fits or not -- it if - * doesn't fit, fail, as we have no way to dispose of - * the extra data. */ - rx_size = __i2400ms_rx_get_size(i2400ms); - if (rx_size < 0) - goto error_rx_get_size; - result = -ENOSPC; /* Check it fits */ - if (rx_size < sizeof(*ack)) { - rx_size = -EIO; - dev_err(dev, "HW BUG? received is too small (%zu vs " - "%zu needed)\n", sizeof(*ack), rx_size); - goto error_too_small; - } - if (rx_size > I2400M_BM_ACK_BUF_SIZE) { - dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs " - "%zu needed)\n", I2400M_BM_ACK_BUF_SIZE, - rx_size); - goto error_too_small; - } + result = wait_event_timeout(i2400ms->bm_wfa_wq, + i2400ms->bm_ack_size != -EINPROGRESS, + 2 * HZ); + if (result == 0) { + result = -ETIMEDOUT; + dev_err(dev, "BM: error waiting for an ack\n"); + goto error_timeout; + } - /* Read it */ - result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf, - I2400MS_DATA_ADDR, rx_size); - if (result == -ETIMEDOUT || result == -ETIME) - continue; - if (result < 0) { - dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n", - rx_size, result); - goto error_read; - } else - break; + spin_lock(&i2400m->rx_lock); + result = i2400ms->bm_ack_size; + BUG_ON(result == -EINPROGRESS); + if (result < 0) /* so we exit when rx_release() is called */ + dev_err(dev, "BM: %s failed: %zd\n", __func__, result); + else { + size = min(ack_size, i2400ms->bm_ack_size); + memcpy(ack, i2400m->bm_ack_buf, size); } - rx_size = min((ssize_t)ack_size, rx_size); - memcpy(ack, i2400m->bm_ack_buf, rx_size); -error_read: -error_too_small: -error_rx_get_size: -error_timedout: - sdio_release_host(func); - d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n", - i2400m, ack, ack_size, (long) rx_size); - return rx_size; + i2400ms->bm_ack_size = -EINPROGRESS; + spin_unlock(&i2400m->rx_lock); + +error_timeout: + d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n", + i2400m, ack, ack_size, result); + return result; } diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c index a3008b9..321bead 100644 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ b/drivers/net/wimax/i2400m/sdio-rx.c @@ -69,6 +69,13 @@ #define D_SUBMODULE rx #include "sdio-debug-levels.h" +static const __le32 i2400m_ACK_BARKER[4] = { + __constant_cpu_to_le32(I2400M_ACK_BARKER), + __constant_cpu_to_le32(I2400M_ACK_BARKER), + __constant_cpu_to_le32(I2400M_ACK_BARKER), + __constant_cpu_to_le32(I2400M_ACK_BARKER) +}; + /* * Read and return the amount of bytes available for RX @@ -131,25 +138,35 @@ void i2400ms_rx(struct i2400ms *i2400ms) ret = rx_size; goto error_get_size; } + ret = -ENOMEM; skb = alloc_skb(rx_size, GFP_ATOMIC); if (NULL == skb) { dev_err(dev, "RX: unable to alloc skb\n"); goto error_alloc_skb; } - ret = sdio_memcpy_fromio(func, skb->data, I2400MS_DATA_ADDR, rx_size); if (ret < 0) { dev_err(dev, "RX: SDIO data read failed: %d\n", ret); goto error_memcpy_fromio; } - /* Check if device has reset */ - if (!memcmp(skb->data, i2400m_NBOOT_BARKER, - sizeof(i2400m_NBOOT_BARKER)) - || !memcmp(skb->data, i2400m_SBOOT_BARKER, - sizeof(i2400m_SBOOT_BARKER))) { + + rmb(); /* make sure we get boot_mode from dev_reset_handle */ + if (i2400m->boot_mode == 1) { + spin_lock(&i2400m->rx_lock); + i2400ms->bm_ack_size = rx_size; + spin_unlock(&i2400m->rx_lock); + memcpy(i2400m->bm_ack_buf, skb->data, rx_size); + wake_up(&i2400ms->bm_wfa_wq); + dev_err(dev, "RX: SDIO boot mode message\n"); + kfree_skb(skb); + } else if (unlikely(!memcmp(skb->data, i2400m_NBOOT_BARKER, + sizeof(i2400m_NBOOT_BARKER)) + || !memcmp(skb->data, i2400m_SBOOT_BARKER, + sizeof(i2400m_SBOOT_BARKER)))) { ret = i2400m_dev_reset_handle(i2400m); + dev_err(dev, "RX: SDIO reboot barker\n"); kfree_skb(skb); } else { skb_put(skb, rx_size); @@ -179,7 +196,6 @@ void i2400ms_irq(struct sdio_func *func) { int ret; struct i2400ms *i2400ms = sdio_get_drvdata(func); - struct i2400m *i2400m = &i2400ms->i2400m; struct device *dev = &func->dev; int val; @@ -194,10 +210,7 @@ void i2400ms_irq(struct sdio_func *func) goto error_no_irq; } sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); - if (WARN_ON(i2400m->boot_mode != 0)) - dev_err(dev, "RX: SW BUG? boot mode and IRQ is up?\n"); - else - i2400ms_rx(i2400ms); + i2400ms_rx(i2400ms); error_no_irq: d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); return; @@ -214,8 +227,15 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms) int result; struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; + struct i2400m *i2400m = &i2400ms->i2400m; d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); + + init_waitqueue_head(&i2400ms->bm_wfa_wq); + spin_lock(&i2400m->rx_lock); + i2400ms->bm_wait_result = -EINPROGRESS; + spin_unlock(&i2400m->rx_lock); + sdio_claim_host(func); result = sdio_claim_irq(func, i2400ms_irq); if (result < 0) { @@ -245,8 +265,13 @@ void i2400ms_rx_release(struct i2400ms *i2400ms) int result; struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; + struct i2400m *i2400m = &i2400ms->i2400m; d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); + spin_lock(&i2400m->rx_lock); + i2400ms->bm_ack_size = -EINTR; + spin_unlock(&i2400m->rx_lock); + wake_up_all(&i2400ms->bm_wfa_wq); sdio_claim_host(func); sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); sdio_release_irq(func); diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 74de174..2538825 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -156,19 +156,14 @@ int i2400ms_bus_dev_start(struct i2400m *i2400m) d_fnstart(3, dev, "(i2400m %p)\n", i2400m); msleep(200); - result = i2400ms_rx_setup(i2400ms); - if (result < 0) - goto error_rx_setup; result = i2400ms_tx_setup(i2400ms); if (result < 0) goto error_tx_setup; d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); return result; - i2400ms_tx_release(i2400ms); error_tx_setup: - i2400ms_rx_release(i2400ms); -error_rx_setup: + i2400ms_tx_release(i2400ms); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); return result; } @@ -182,7 +177,6 @@ void i2400ms_bus_dev_stop(struct i2400m *i2400m) struct device *dev = &func->dev; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - i2400ms_rx_release(i2400ms); i2400ms_tx_release(i2400ms); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); } @@ -296,6 +290,7 @@ do_bus_reset: if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED) netif_tx_disable(i2400m->wimax_dev.net_dev); + i2400ms_rx_release(i2400ms); sdio_claim_host(i2400ms->func); sdio_disable_func(i2400ms->func); sdio_release_host(i2400ms->func); @@ -304,6 +299,8 @@ do_bus_reset: msleep(40); result = i2400ms_enable_function(i2400ms->func); + if (result >= 0) + i2400ms_rx_setup(i2400ms); } else BUG(); if (result < 0 && rt != I2400M_RT_BUS) { @@ -449,6 +446,10 @@ int i2400ms_probe(struct sdio_func *func, goto error_func_enable; } + result = i2400ms_rx_setup(i2400ms); + if (result < 0) + goto error_rx_setup; + result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); if (result < 0) { dev_err(dev, "cannot setup device: %d\n", result); @@ -466,6 +467,8 @@ int i2400ms_probe(struct sdio_func *func, error_debugfs_add: i2400m_release(i2400m); error_setup: + i2400ms_rx_release(i2400ms); +error_rx_setup: sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); @@ -488,6 +491,7 @@ void i2400ms_remove(struct sdio_func *func) d_fnstart(3, dev, "SDIO func %p\n", func); debugfs_remove_recursive(i2400ms->debugfs_dentry); + i2400ms_rx_release(i2400ms); i2400m_release(i2400m); sdio_set_drvdata(func, NULL); sdio_claim_host(func); -- cgit v0.10.2 From 8b5b30ee7ddc989b59ce05dcf2d024a819dc8040 Mon Sep 17 00:00:00 2001 From: Cindy H Kao Date: Wed, 10 Jun 2009 16:52:10 -0700 Subject: wimax/i2400m: when bootstrap fails, reinitialize the bootrom When a device reset happens during firmware load [in i2400m_dev_bootstrap()], __i2400m_dev_start() will retry a number of times. However, for those retries to be able to accomplish anything, the device's bootrom has to be reinitialized. Thus, on the retry path, pass the I2400M_MAC_REINIT to the firmware load code. Signed-off-by: Cindy H Kao diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 8d8628e..2a093c5 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -454,7 +454,7 @@ error_rx_setup: error_tx_setup: error_bootstrap: if (result == -ERESTARTSYS && times-- > 0) { - flags = I2400M_BRI_SOFT; + flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; goto retry; } d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", -- cgit v0.10.2 From 0bcfc5ef016e8217709c65c5a7335e40ceabc99c Mon Sep 17 00:00:00 2001 From: Cindy H Kao Date: Wed, 10 Jun 2009 17:06:19 -0700 Subject: wimax/i2400m: use -EL3RST to indicate device reset instead of -ERESTARTSYS When the i2400m device resets, the driver code will force some functions to return a -ERESTARTSYS error code, which can is used by the caller to determine which recovery actions to take. However, in certain situations the only thing that can be done is to bubble up said error code to user space, for handling. However, -ERESTARSYS was a poor choice, as it is supposed to be used by the kernel only. As such, replace -ERESTARTSYS with -EL3RST; as well, in i2400m_msg_to_dev(), when the device is in boot mode (following a recent reset), return -EL3RST instead of -ENODEV (meaning the device is in bootrom mode after a reset, not that the device was disconnected, and thus, normal commands cannot be executed). Signed-off-by: Cindy H Kao diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index f9399f2..0730868 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -697,7 +697,7 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ if (i2400m->boot_mode) - return ERR_PTR(-ENODEV); + return ERR_PTR(-EL3RST); msg_l3l4_hdr = buf; /* Check msg & payload consistency */ diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 2a093c5..304f044 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -453,7 +453,7 @@ error_rx_setup: i2400m_tx_release(i2400m); error_tx_setup: error_bootstrap: - if (result == -ERESTARTSYS && times-- > 0) { + if (result == -EL3RST && times-- > 0) { flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; goto retry; } @@ -560,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) * i2400m_dev_stop() [we are shutting down anyway, so * ignore it] or we are resetting somewhere else. */ dev_err(dev, "device rebooted\n"); - i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS); + i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); complete(&i2400m->msg_completion); goto out; } -- cgit v0.10.2 From 5ef12d98a19254ee5dc851bd83e214b43ec1f725 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Thu, 11 Jun 2009 04:16:28 -0700 Subject: neigh: fix state transition INCOMPLETE->FAILED via Netlink request The current code errors out the INCOMPLETE neigh entry skb queue only from the timer if maximum probes have been attempted and there has been no reply. This also causes the transtion to FAILED state. However, the neigh entry can be also updated via Netlink to inform that the address is unavailable. Currently, neigh_update() just stops the timers and leaves the pending skb's unreleased. This results that the clean up code in the timer callback is never called, preventing also proper garbage collection. This fixes neigh_update() to process the pending skb queue immediately if INCOMPLETE -> FAILED state transtion occurs due to a Netlink request. Signed-off-by: Timo Teras Signed-off-by: David S. Miller diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c54229b..163b4f5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -771,6 +771,28 @@ static __inline__ int neigh_max_probes(struct neighbour *n) p->ucast_probes + p->app_probes + p->mcast_probes); } +static void neigh_invalidate(struct neighbour *neigh) +{ + struct sk_buff *skb; + + NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); + NEIGH_PRINTK2("neigh %p is failed.\n", neigh); + neigh->updated = jiffies; + + /* It is very thin place. report_unreachable is very complicated + routine. Particularly, it can hit the same neighbour entry! + + So that, we try to be accurate and avoid dead loop. --ANK + */ + while (neigh->nud_state == NUD_FAILED && + (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { + write_unlock(&neigh->lock); + neigh->ops->error_report(neigh, skb); + write_lock(&neigh->lock); + } + skb_queue_purge(&neigh->arp_queue); +} + /* Called when a timer expires for a neighbour entry. */ static void neigh_timer_handler(unsigned long arg) @@ -835,26 +857,9 @@ static void neigh_timer_handler(unsigned long arg) if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) { - struct sk_buff *skb; - neigh->nud_state = NUD_FAILED; - neigh->updated = jiffies; notify = 1; - NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); - NEIGH_PRINTK2("neigh %p is failed.\n", neigh); - - /* It is very thin place. report_unreachable is very complicated - routine. Particularly, it can hit the same neighbour entry! - - So that, we try to be accurate and avoid dead loop. --ANK - */ - while (neigh->nud_state == NUD_FAILED && - (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - write_unlock(&neigh->lock); - neigh->ops->error_report(neigh, skb); - write_lock(&neigh->lock); - } - skb_queue_purge(&neigh->arp_queue); + neigh_invalidate(neigh); } if (neigh->nud_state & NUD_IN_TIMER) { @@ -1001,6 +1006,11 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, neigh->nud_state = new; err = 0; notify = old & NUD_VALID; + if ((old & (NUD_INCOMPLETE | NUD_PROBE)) && + (new & NUD_FAILED)) { + neigh_invalidate(neigh); + notify = 1; + } goto out; } -- cgit v0.10.2 From 130aa61a77b8518f1ea618e1b7d214d60b405f10 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Jun 2009 05:46:04 -0700 Subject: bonding: fix multiple module load problem Some users still load bond module multiple times to create bonding devices. This accidentally was broken by a later patch about the time sysfs was fixed. According to Jay, it was broken by: commit b8a9787eddb0e4665f31dd1d64584732b2b5d051 Author: Jay Vosburgh Date: Fri Jun 13 18:12:04 2008 -0700 bonding: Allow setting max_bonds to zero Note: sysfs and procfs still produce WARN() messages when this is done so the sysfs method is the recommended API. Signed-off-by: Stephen Hemminger Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 3a1b7b0..5fb861a 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1541,6 +1541,7 @@ int bond_create_sysfs(void) printk(KERN_ERR "network device named %s already exists in sysfs", class_attr_bonding_masters.attr.name); + ret = 0; } return ret; -- cgit v0.10.2 From 334a47f6345560af047f164c356d71c3226965d5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 Jun 2009 16:16:09 +0200 Subject: netfilter: nf_ct_tcp: fix up build after merge Replace the last occurence of tcp_lock by the per-conntrack lock. Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 5142e60..33fc0a4 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -944,7 +944,7 @@ static int tcp_packet(struct nf_conn *ct, && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) && before(ntohl(th->seq), ct->proto.tcp.seen[!dir].td_maxack)) { /* Invalid RST */ - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid RST "); -- cgit v0.10.2 From 8a745b9d91962991ce87a649a4dc3af3206c2c8b Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 2 Jun 2009 14:57:35 +0200 Subject: ISDN:Fix DMA alloc for hfcpci Replace wrong code with correct DMA API functions. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index f126566..3d337d9 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -82,8 +82,9 @@ release_io_hfcpci(struct IsdnCardState *cs) Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ del_timer(&cs->hw.hfcpci.timer); - kfree(cs->hw.hfcpci.share_start); - cs->hw.hfcpci.share_start = NULL; + pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, + cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); + cs->hw.hfcpci.fifos = NULL; iounmap((void *)cs->hw.hfcpci.pci_io); } @@ -1663,8 +1664,19 @@ setup_hfcpci(struct IsdnCard *card) dev_hfcpci); i++; if (tmp_hfcpci) { + dma_addr_t dma_mask = DMA_BIT_MASK(32) & ~0x7fffUL; if (pci_enable_device(tmp_hfcpci)) continue; + if (pci_set_dma_mask(tmp_hfcpci, dma_mask)) { + printk(KERN_WARNING + "HiSax hfc_pci: No suitable DMA available.\n"); + continue; + } + if (pci_set_consistent_dma_mask(tmp_hfcpci, dma_mask)) { + printk(KERN_WARNING + "HiSax hfc_pci: No suitable consistent DMA available.\n"); + continue; + } pci_set_master(tmp_hfcpci); if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) continue; @@ -1693,22 +1705,29 @@ setup_hfcpci(struct IsdnCard *card) printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); return (0); } + /* Allocate memory for FIFOS */ - /* Because the HFC-PCI needs a 32K physical alignment, we */ - /* need to allocate the double mem and align the address */ - if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) { - printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); + cs->hw.hfcpci.fifos = pci_alloc_consistent(cs->hw.hfcpci.dev, + 0x8000, &cs->hw.hfcpci.dma); + if (!cs->hw.hfcpci.fifos) { + printk(KERN_WARNING "HFC-PCI: Error allocating FIFO memory!\n"); + return 0; + } + if (cs->hw.hfcpci.dma & 0x7fff) { + printk(KERN_WARNING + "HFC-PCI: Error DMA memory not on 32K boundary (%lx)\n", + (u_long)cs->hw.hfcpci.dma); + pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, + cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); return 0; } - cs->hw.hfcpci.fifos = (void *) - (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000; - pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos)); + pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma); cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256); printk(KERN_INFO - "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n", + "HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n", cs->hw.hfcpci.pci_io, cs->hw.hfcpci.fifos, - (u_int) virt_to_bus(cs->hw.hfcpci.fifos), + (u_long)cs->hw.hfcpci.dma, cs->irq, HZ); spin_lock_irqsave(&cs->lock, flags); diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index f852704..0685c19 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -703,7 +703,7 @@ struct hfcPCI_hw { int nt_timer; struct pci_dev *dev; unsigned char *pci_io; /* start of PCI IO memory */ - void *share_start; /* shared memory for Fifos start */ + dma_addr_t dma; /* dma handle for Fifos */ void *fifos; /* FIFO memory */ int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ struct timer_list timer; -- cgit v0.10.2 From 1ce1513f48e3bc4d55ee672f0e39f5063a02ab7a Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 2 Jun 2009 15:37:37 +0200 Subject: mISDN: Fix overlapping data access Remove code rewriting a buffer by itself. This fix bug 12970 on bugzilla.kernel.org. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index ac61f19..e994167 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -55,20 +55,19 @@ static ssize_t attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) { struct mISDN_dsp_element *elem = dev_get_drvdata(dev); - ssize_t len = 0; - int i = 0; + int i; + char *p = buf; *buf = 0; - for (; i < elem->num_args; ++i) - len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n" - "\n", buf, + for (i = 0; i < elem->num_args; i++) + p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n", elem->args[i].name, elem->args[i].def ? "Default: " : "", elem->args[i].def ? elem->args[i].def : "", elem->args[i].def ? "\n" : "", elem->args[i].desc); - return len; + return p - buf; } static struct device_attribute element_attributes[] = { -- cgit v0.10.2 From cdae28e1a28f26c765c5882a48b9fd4a5b9ce91c Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Tue, 2 Jun 2009 18:15:12 +0200 Subject: mISDN: Free hfcpci IRQ if init was not successful If we get no interrupts for after 3 resets we need to unregister the interrupt function, which is already done outside the loop. Signed-off-by: Andreas Mohr Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 776afc8..228ffbe 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1806,10 +1806,9 @@ init_card(struct hfc_pci *hc) printk(KERN_WARNING "HFC PCI: IRQ(%d) getting no interrupts " "during init %d\n", hc->irq, 4 - cnt); - if (cnt == 1) { - spin_unlock_irqrestore(&hc->lock, flags); - return -EIO; - } else { + if (cnt == 1) + break; + else { reset_hfcpci(hc); cnt--; } -- cgit v0.10.2 From 395df11f5fa7fe852be28ccec8aaa15634386ad1 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 10 Jun 2009 12:52:44 -0700 Subject: drivers/isdn/i4l/isdn_tty.c: fix check for array overindexing The check for overindexing of dev->mdm.info[] has an off-by-one. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Acked-by: Karsten Keil diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 1a2222c..b4d4522 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1592,7 +1592,7 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp) int retval, line; line = tty->index; - if (line < 0 || line > ISDN_MAX_CHANNELS) + if (line < 0 || line >= ISDN_MAX_CHANNELS) return -ENODEV; info = &dev->mdm.info[line]; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) -- cgit v0.10.2 From 8164491dd628ffcac5d61267f747997689ee256c Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 9 Jun 2009 14:38:39 +0200 Subject: mISDN: Do not disable IRQ in ph_data_ind() This fix triggering the WARN_ON_ONCE(in_irq() || irqs_disabled()); in local_bh_enable(). Here is no need to grab this lock, this was wrong at all and may cause a deadlock and access to freed memory, since on a TEI remove the current listelement can be deleted under us. So this is clearly a case for list_for_each_entry_safe. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index bfcdd97..e04bad6 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -862,8 +862,7 @@ static int ph_data_ind(struct manager *mgr, struct sk_buff *skb) { int ret = -EINVAL; - struct layer2 *l2; - u_long flags; + struct layer2 *l2, *nl2; u_char mt; if (skb->len < 8) { @@ -908,11 +907,9 @@ ph_data_ind(struct manager *mgr, struct sk_buff *skb) new_tei_req(mgr, &skb->data[4]); goto done; } - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { + list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); } - read_unlock_irqrestore(&mgr->lock, flags); done: return ret; } -- cgit v0.10.2 From 670025478c2a687453cd1bac697d7d765843f59d Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Thu, 11 Jun 2009 15:52:10 +0200 Subject: mISDN: cleanup mISDNhw.h Remove unused stuff. Signed-off-by: Karsten Keil diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index ce900f4..7f9831d 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -89,11 +89,6 @@ struct dchannel { void (*phfunc) (struct dchannel *); u_int state; void *l1; - /* HW access */ - u_char (*read_reg) (void *, u_char); - void (*write_reg) (void *, u_char, u_char); - void (*read_fifo) (void *, u_char *, int); - void (*write_fifo) (void *, u_char *, int); void *hw; int slot; /* multiport card channel slot */ struct timer_list timer; @@ -151,11 +146,6 @@ struct bchannel { u_long Flags; struct work_struct workq; u_int state; - /* HW access */ - u_char (*read_reg) (void *, u_char); - void (*write_reg) (void *, u_char, u_char); - void (*read_fifo) (void *, u_char *, int); - void (*write_fifo) (void *, u_char *, int); void *hw; int slot; /* multiport card channel slot */ struct timer_list timer; -- cgit v0.10.2 From d2f4c10544231c3681f937a1e511f4780b4b39af Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 11 Jun 2009 11:12:48 -0700 Subject: wimax: fix warning caused by not checking retval of rfkill_set_hw_state() Caused by an API update. The return value can be safely ignored, as there is notthing we can do with it. Signed-off-by: Inaky Perez-Gonzalez diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index bb102e4..70ef4df 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -113,7 +113,8 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, else wimax_state = WIMAX_ST_RADIO_OFF; - rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); + result = rfkill_set_hw_state(wimax_dev->rfkill, + state == WIMAX_RF_OFF); __wimax_state_change(wimax_dev, wimax_state); } -- cgit v0.10.2 From 98eb0f53e2fc66482e2ea8033c58b20a079e5260 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 11 Jun 2009 11:13:41 -0700 Subject: wimax: fix gcc warnings in sh4 when calling BUG() SH4's BUG() seems to confuse the compiler as it is considered to return; thus, some functions would trigger usage of uninitialized variables or non-void functions returning void. Work around by initializing/returning. Signed-off-by: Inaky Perez-Gonzalez diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index 487ec58..43927b5 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c @@ -54,8 +54,10 @@ int i2400m_radio_is(struct i2400m *i2400m, enum wimax_rf_state state) /* state == WIMAX_RF_ON */ return i2400m->state != I2400M_SS_RF_OFF && i2400m->state != I2400M_SS_RF_SHUTDOWN; - else + else { BUG(); + return -EINVAL; /* shut gcc warnings on certain arches */ + } } diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index ebc05da..cfdaf69 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -254,8 +254,10 @@ do_bus_reset: dev_err(dev, "USB reset failed (%d), giving up!\n", result); } - } else + } else { + result = -EINVAL; /* shut gcc up in certain arches */ BUG(); + } if (result < 0 && result != -EINVAL /* device is gone */ && rt != I2400M_RT_BUS) { -- cgit v0.10.2 From 24992eacd8a9f4af286bdaaab627b6802ceb8bce Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 01:53:09 +0200 Subject: netfilter: ip_tables: fix build error Fix build error introduced by commit bb70dfa5 (netfilter: xtables: consolidate comefrom debug cast access): net/ipv4/netfilter/ip_tables.c: In function 'ipt_do_table': net/ipv4/netfilter/ip_tables.c:421: error: 'comefrom' undeclared (first use in this function) net/ipv4/netfilter/ip_tables.c:421: error: (Each undeclared identifier is reported only once net/ipv4/netfilter/ip_tables.c:421: error: for each function it appears in.) Signed-off-by: Patrick McHardy diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 5bf7c3f..fdefae6 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -418,7 +418,7 @@ ipt_do_table(struct sk_buff *skb, #endif verdict = t->u.kernel.target->target(skb, &tgpar); #ifdef CONFIG_NETFILTER_DEBUG - if (comefrom != 0xeeeeeeec && verdict == IPT_CONTINUE) { + if (tb_comefrom != 0xeeeeeeec && verdict == IPT_CONTINUE) { printk("Target %s reentered!\n", t->u.kernel.target->name); verdict = NF_DROP; -- cgit v0.10.2 From 17d0cdfa8f3c09a110061c67421d662b3e149d0a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 11 Jun 2009 17:23:24 -0700 Subject: net: ntohs() misuse Some drivers incorrectly use ntohs() instead of htons() A cleanup as htons() returns same result than ntohs(), but better to use the proper one. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index e1ae10c..9fc6d6d 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1602,7 +1602,7 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb) } if (skb_is_gso(skb)) { - if (skb->protocol == ntohs(ETH_P_IP) || + if (skb->protocol == htons(ETH_P_IP) || (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6)) { proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); @@ -1878,7 +1878,7 @@ static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev) TPD_VLAN_SHIFT; } - if (skb->protocol == ntohs(ETH_P_8021Q)) + if (skb->protocol == htons(ETH_P_8021Q)) tpd->word3 |= 1 << TPD_VL_TAGGED_SHIFT; if (skb_network_offset(skb) != ETH_HLEN) diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 560f387..94d7325 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2382,7 +2382,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) mss = skb_shinfo(skb)->gso_size; if (mss) { - if (skb->protocol == ntohs(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) { proto_hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); if (unlikely(proto_hdr_len > len)) { diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c5593f4..e3cfefa 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -530,7 +530,7 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) * case where the checksum is right the higher layers will still * drop the packet as appropriate. */ - if (eh->h_proto != ntohs(ETH_P_IP)) + if (eh->h_proto != htons(ETH_P_IP)) return; ih = (struct iphdr *) ((char *)eh + ETH_HLEN); -- cgit v0.10.2 From 8981f01001c616f58f1623ecadfab8b1ed758da7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 11 Jun 2009 20:55:17 -0700 Subject: virtio_net: Fix IP alignment on non-mergeable RX path We need to enforce the IP alignment on the non-mergeable RX path just like the other RX path. Not doing so results in misaligned IP headers. Signed-off-by: Herbert Xu Signed-off-by: Rusty Russell Signed-off-by: David S. Miller diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 09bd441..f0bb1a4 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -283,10 +283,11 @@ static void try_fill_recv_maxbufs(struct virtnet_info *vi) for (;;) { struct virtio_net_hdr *hdr; - skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN); + skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN + NET_IP_ALIGN); if (unlikely(!skb)) break; + skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, MAX_PACKET_LEN); hdr = skb_vnet_hdr(skb); -- cgit v0.10.2 From 746e6ad23cd6fec2edce056e014a0eabeffa838c Mon Sep 17 00:00:00 2001 From: John Dykstra Date: Thu, 11 Jun 2009 20:57:21 -0700 Subject: [PATCH] net core: Some interface flags not returned by SIOCGIFFLAGS Commit b00055aacdb172c05067612278ba27265fcd05ce " [NET] core: add RFC2863 operstate" defined new interface flag values. Its documentation specified that these flags could be accessed from user space via SIOCGIFFLAGS. However, this does not work because the new flags do not fit in that ioctl's argument width. Change the documentation to match the code's behavior. Also change the source to explicitly show the truncation. This _should_ have no effect on executable code, and did not with gcc 4.2.4 generating x86 code. A new ioctl could be defined to return all interface flags to user space. However, since this has been broken for three years with no one complaining, there doesn't seem much need. They are still accessible via netlink. Reported-by: "Fredrik Arnerup" Signed-off-by: John Dykstra Signed-off-by: David S. Miller diff --git a/Documentation/networking/operstates.txt b/Documentation/networking/operstates.txt index c9074f9..1a77a3c 100644 --- a/Documentation/networking/operstates.txt +++ b/Documentation/networking/operstates.txt @@ -38,9 +38,6 @@ ifinfomsg::if_flags & IFF_LOWER_UP: ifinfomsg::if_flags & IFF_DORMANT: Driver has signaled netif_dormant_on() -These interface flags can also be queried without netlink using the -SIOCGIFFLAGS ioctl. - TLV IFLA_OPERSTATE contains RFC2863 state of the interface in numeric representation: diff --git a/net/core/dev.c b/net/core/dev.c index 11560e3..a09bf65 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4209,7 +4209,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm switch (cmd) { case SIOCGIFFLAGS: /* Get interface flags */ - ifr->ifr_flags = dev_get_flags(dev); + ifr->ifr_flags = (short) dev_get_flags(dev); return 0; case SIOCGIFMETRIC: /* Get the metric on the interface -- cgit v0.10.2 From da6782927de809d9d427bd4bd6a4024243e41f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 5 Jun 2009 05:35:28 +0000 Subject: bridge: Simplify interface for ATM LANE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch changes FDB entry check for ATM LANE bridge integration. There's no point in holding a FDB entry around SKB building. br_fdb_get()/br_fdb_put() pair are changed into single br_fdb_test_addr() hook that checks if the addr has FDB entry pointing to other port to the one the request arrived on. FDB entry refcounting is removed as it's not used anywhere else. Signed-off-by: MichaÅ‚ MirosÅ‚aw Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/atm/lec.c b/net/atm/lec.c index 199b6bb..75b9d59 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -34,7 +34,6 @@ /* Proxy LEC knows about bridging */ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -#include #include "../bridge/br_private.h" static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; @@ -518,18 +517,14 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) case l_should_bridge: #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) { - struct net_bridge_fdb_entry *f; - pr_debug("%s: bridge zeppelin asks about %pM\n", dev->name, mesg->content.proxy.mac_addr); - if (br_fdb_get_hook == NULL || dev->br_port == NULL) + if (br_fdb_test_addr_hook == NULL) break; - f = br_fdb_get_hook(dev->br_port->br, - mesg->content.proxy.mac_addr); - if (f != NULL && f->dst->dev != dev - && f->dst->state == BR_STATE_FORWARDING) { + if (br_fdb_test_addr_hook(dev, + mesg->content.proxy.mac_addr)) { /* hit from bridge table, send LE_ARP_RESPONSE */ struct sk_buff *skb2; struct sock *sk; @@ -540,10 +535,8 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); - if (skb2 == NULL) { - br_fdb_put_hook(f); + if (skb2 == NULL) break; - } skb2->len = sizeof(struct atmlec_msg); skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg)); @@ -552,8 +545,6 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) skb_queue_tail(&sk->sk_receive_queue, skb2); sk->sk_data_ready(sk, skb2->len); } - if (f != NULL) - br_fdb_put_hook(f); } #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ break; diff --git a/net/bridge/br.c b/net/bridge/br.c index 4d2c1f1..9aac521 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -65,8 +65,9 @@ static int __init br_init(void) brioctl_set(br_ioctl_deviceless_stub); br_handle_frame_hook = br_handle_frame; - br_fdb_get_hook = br_fdb_get; - br_fdb_put_hook = br_fdb_put; +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + br_fdb_test_addr_hook = br_fdb_test_addr; +#endif return 0; err_out4: @@ -95,8 +96,9 @@ static void __exit br_deinit(void) synchronize_net(); br_netfilter_fini(); - br_fdb_get_hook = NULL; - br_fdb_put_hook = NULL; +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + br_fdb_test_addr_hook = NULL; +#endif br_handle_frame_hook = NULL; br_fdb_fini(); diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index cb3e97b..57bf05c 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -71,10 +71,17 @@ static inline int br_mac_hash(const unsigned char *mac) return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); } +static void fdb_rcu_free(struct rcu_head *head) +{ + struct net_bridge_fdb_entry *ent + = container_of(head, struct net_bridge_fdb_entry, rcu); + kmem_cache_free(br_fdb_cache, ent); +} + static inline void fdb_delete(struct net_bridge_fdb_entry *f) { hlist_del_rcu(&f->hlist); - br_fdb_put(f); + call_rcu(&f->rcu, fdb_rcu_free); } void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) @@ -226,33 +233,26 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, return NULL; } -/* Interface used by ATM hook that keeps a ref count */ -struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, - unsigned char *addr) +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +/* Interface used by ATM LANE hook to test + * if an addr is on some other bridge port */ +int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) { struct net_bridge_fdb_entry *fdb; + int ret; + + if (!dev->br_port) + return 0; rcu_read_lock(); - fdb = __br_fdb_get(br, addr); - if (fdb && !atomic_inc_not_zero(&fdb->use_count)) - fdb = NULL; + fdb = __br_fdb_get(dev->br_port->br, addr); + ret = fdb && fdb->dst->dev != dev && + fdb->dst->state == BR_STATE_FORWARDING; rcu_read_unlock(); - return fdb; -} - -static void fdb_rcu_free(struct rcu_head *head) -{ - struct net_bridge_fdb_entry *ent - = container_of(head, struct net_bridge_fdb_entry, rcu); - kmem_cache_free(br_fdb_cache, ent); -} -/* Set entry up for deletion with RCU */ -void br_fdb_put(struct net_bridge_fdb_entry *ent) -{ - if (atomic_dec_and_test(&ent->use_count)) - call_rcu(&ent->rcu, fdb_rcu_free); + return ret; } +#endif /* CONFIG_ATM_LANE */ /* * Fill buffer with forwarding table records in @@ -326,7 +326,6 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC); if (fdb) { memcpy(fdb->addr.addr, addr, ETH_ALEN); - atomic_set(&fdb->use_count, 1); hlist_add_head_rcu(&fdb->hlist, head); fdb->dst = source; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index b6c3b71..d5b5537 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -51,7 +51,6 @@ struct net_bridge_fdb_entry struct net_bridge_port *dst; struct rcu_head rcu; - atomic_t use_count; unsigned long ageing_timer; mac_addr addr; unsigned char is_local; @@ -154,9 +153,7 @@ extern void br_fdb_delete_by_port(struct net_bridge *br, const struct net_bridge_port *p, int do_all); extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, const unsigned char *addr); -extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, - unsigned char *addr); -extern void br_fdb_put(struct net_bridge_fdb_entry *ent); +extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr); extern int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count, unsigned long off); extern int br_fdb_insert(struct net_bridge *br, @@ -242,10 +239,9 @@ extern void br_stp_port_timer_init(struct net_bridge_port *p); extern unsigned long br_timer_value(const struct timer_list *timer); /* br.c */ -extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, - unsigned char *addr); -extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); - +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr); +#endif /* br_netlink.c */ extern int br_netlink_init(void); diff --git a/net/core/dev.c b/net/core/dev.c index a09bf65..ea00e36 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2071,11 +2071,13 @@ static inline int deliver_skb(struct sk_buff *skb, } #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) -/* These hooks defined here for ATM */ -struct net_bridge; -struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, - unsigned char *addr); -void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly; + +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +/* This hook is defined here for ATM LANE */ +int (*br_fdb_test_addr_hook)(struct net_device *dev, + unsigned char *addr) __read_mostly; +EXPORT_SYMBOL(br_fdb_test_addr_hook); +#endif /* * If bridge module is loaded call bridging hook. @@ -2083,6 +2085,8 @@ void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly; */ struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff *skb) __read_mostly; +EXPORT_SYMBOL(br_handle_frame_hook); + static inline struct sk_buff *handle_bridge(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) @@ -5665,12 +5669,6 @@ EXPORT_SYMBOL(net_enable_timestamp); EXPORT_SYMBOL(net_disable_timestamp); EXPORT_SYMBOL(dev_get_flags); -#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -EXPORT_SYMBOL(br_handle_frame_hook); -EXPORT_SYMBOL(br_fdb_get_hook); -EXPORT_SYMBOL(br_fdb_put_hook); -#endif - EXPORT_SYMBOL(dev_load); EXPORT_PER_CPU_SYMBOL(softnet_data); -- cgit v0.10.2 From ba2533a47865ec0dbc72834287a8a048e9337a95 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 12 Jun 2009 16:55:56 +0100 Subject: ASoC: Remove odd bit clock ratios for WM8903 These are not supported since performance can not be guaranteed when they are in use. Signed-off-by: Mark Brown Cc: stable@kernel.org diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index d8a9222..e8d2e3e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1257,22 +1257,18 @@ static struct { int div; } bclk_divs[] = { { 10, 0 }, - { 15, 1 }, { 20, 2 }, { 30, 3 }, { 40, 4 }, { 50, 5 }, - { 55, 6 }, { 60, 7 }, { 80, 8 }, { 100, 9 }, - { 110, 10 }, { 120, 11 }, { 160, 12 }, { 200, 13 }, { 220, 14 }, { 240, 15 }, - { 250, 16 }, { 300, 17 }, { 320, 18 }, { 440, 19 }, -- cgit v0.10.2 From d510fe70db4c62ac899c486506fdfb7f3b518c86 Mon Sep 17 00:00:00 2001 From: Graff Yang Date: Tue, 12 May 2009 13:47:54 -0700 Subject: irda: new Blackfin on-chip SIR IrDA driver Signed-off-by: Graff Yang Cc: Mike Frysinger Cc: Bryan Wu Signed-off-by: Samuel Ortiz Signed-off-by: Andrew Morton diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index e631755..f763842 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -17,6 +17,51 @@ config IRTTY_SIR If unsure, say Y. +config BFIN_SIR + tristate "Blackfin SIR on UART" + depends on BLACKFIN && IRDA + default n + help + Say Y here if your want to enable SIR function on Blackfin UART + devices. + + To activate this driver you can start irattach like: + "irattach irda0 -s" + + Saying M, it will be built as a module named bfin_sir. + + Note that you need to turn off one of the serial drivers for SIR + to use that UART. + +config BFIN_SIR0 + bool "Blackfin SIR on UART0" + depends on BFIN_SIR && !SERIAL_BFIN_UART0 + +config BFIN_SIR1 + bool "Blackfin SIR on UART1" + depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561) + +config BFIN_SIR2 + bool "Blackfin SIR on UART2" + depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539) + +config BFIN_SIR3 + bool "Blackfin SIR on UART3" + depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x) + +choice + prompt "SIR Mode" + depends on BFIN_SIR + default SIR_BFIN_DMA + +config SIR_BFIN_DMA + bool "DMA mode" + depends on !DMA_UNCACHED_NONE + +config SIR_BFIN_PIO + bool "PIO mode" +endchoice + comment "Dongle support" config DONGLE diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 5d20fde..d82e1e3 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_MCS_FIR) += mcs7780.o obj-$(CONFIG_AU1000_FIR) += au1k_ir.o # SIR drivers obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o +obj-$(CONFIG_BFIN_SIR) += bfin_sir.o # dongle drivers for SIR drivers obj-$(CONFIG_ESI_DONGLE) += esi-sir.o obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c new file mode 100644 index 0000000..f3eed6a --- /dev/null +++ b/drivers/net/irda/bfin_sir.c @@ -0,0 +1,820 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ +#include "bfin_sir.h" + +#ifdef CONFIG_SIR_BFIN_DMA +#define DMA_SIR_RX_XCNT 10 +#define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT) +#define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250) +#endif + +#if ANOMALY_05000447 +static int max_rate = 57600; +#else +static int max_rate = 115200; +#endif + +static void turnaround_delay(unsigned long last_jif, int mtt) +{ + long ticks; + + mtt = mtt < 10000 ? 10000 : mtt; + ticks = 1 + mtt / (USEC_PER_SEC / HZ); + schedule_timeout_uninterruptible(ticks); +} + +static void __devinit bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev) +{ + int i; + struct resource *res; + + for (i = 0; i < pdev->num_resources; i++) { + res = &pdev->resource[i]; + switch (res->flags) { + case IORESOURCE_MEM: + sp->membase = (void __iomem *)res->start; + break; + case IORESOURCE_IRQ: + sp->irq = res->start; + break; + case IORESOURCE_DMA: + sp->rx_dma_channel = res->start; + sp->tx_dma_channel = res->end; + break; + default: + break; + } + } + + sp->clk = get_sclk(); +#ifdef CONFIG_SIR_BFIN_DMA + sp->tx_done = 1; + init_timer(&(sp->rx_dma_timer)); +#endif +} + +static void bfin_sir_stop_tx(struct bfin_sir_port *port) +{ +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); +#endif + + while (!(SIR_UART_GET_LSR(port) & THRE)) { + cpu_relax(); + continue; + } + + SIR_UART_STOP_TX(port); +} + +static void bfin_sir_enable_tx(struct bfin_sir_port *port) +{ + SIR_UART_ENABLE_TX(port); +} + +static void bfin_sir_stop_rx(struct bfin_sir_port *port) +{ + SIR_UART_STOP_RX(port); +} + +static void bfin_sir_enable_rx(struct bfin_sir_port *port) +{ + SIR_UART_ENABLE_RX(port); +} + +static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) +{ + int ret = -EINVAL; + unsigned int quot; + unsigned short val, lsr, lcr; + static int utime; + int count = 10; + + lcr = WLS(8); + + switch (speed) { + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + + quot = (port->clk + (8 * speed)) / (16 * speed)\ + - ANOMALY_05000230; + + do { + udelay(utime); + lsr = SIR_UART_GET_LSR(port); + } while (!(lsr & TEMT) && count--); + + /* The useconds for 1 bits to transmit */ + utime = 1000000 / speed + 1; + + /* Clear UCEN bit to reset the UART state machine + * and control registers + */ + val = SIR_UART_GET_GCTL(port); + val &= ~UCEN; + SIR_UART_PUT_GCTL(port, val); + + /* Set DLAB in LCR to Access THR RBR IER */ + SIR_UART_SET_DLAB(port); + SSYNC(); + + SIR_UART_PUT_DLL(port, quot & 0xFF); + SIR_UART_PUT_DLH(port, (quot >> 8) & 0xFF); + SSYNC(); + + /* Clear DLAB in LCR */ + SIR_UART_CLEAR_DLAB(port); + SSYNC(); + + SIR_UART_PUT_LCR(port, lcr); + + val = SIR_UART_GET_GCTL(port); + val |= UCEN; + SIR_UART_PUT_GCTL(port, val); + + ret = 0; + break; + default: + printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed); + break; + } + + val = SIR_UART_GET_GCTL(port); + /* If not add the 'RPOLC', we can't catch the receive interrupt. + * It's related with the HW layout and the IR transiver. + */ + val |= IREN | RPOLC; + SIR_UART_PUT_GCTL(port, val); + return ret; +} + +static int bfin_sir_is_receiving(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!(SIR_UART_GET_IER(port) & ERBFI)) + return 0; + return self->rx_buff.state != OUTSIDE_FRAME; +} + +#ifdef CONFIG_SIR_BFIN_PIO +static void bfin_sir_tx_chars(struct net_device *dev) +{ + unsigned int chr; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (self->tx_buff.len != 0) { + chr = *(self->tx_buff.data); + SIR_UART_PUT_CHAR(port, chr); + self->tx_buff.data++; + self->tx_buff.len--; + } else { + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_stop_tx(port); + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + } +} + +static void bfin_sir_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned char ch; + + SIR_UART_CLEAR_LSR(port); + ch = SIR_UART_GET_CHAR(port); + async_unwrap_char(dev, &self->stats, &self->rx_buff, ch); + dev->last_rx = jiffies; +} + +static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + while ((SIR_UART_GET_LSR(port) & DR)) + bfin_sir_rx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (SIR_UART_GET_LSR(port) & THRE) + bfin_sir_tx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_PIO */ + +#ifdef CONFIG_SIR_BFIN_DMA +static void bfin_sir_dma_tx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!port->tx_done) + return; + port->tx_done = 0; + + if (self->tx_buff.len == 0) { + self->stats.tx_packets++; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + port->tx_done = 1; + netif_wake_queue(dev); + return; + } + + blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data), + (unsigned long)(self->tx_buff.data+self->tx_buff.len)); + set_dma_config(port->tx_dma_channel, + set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, + INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, + DMA_SYNC_RESTART)); + set_dma_start_addr(port->tx_dma_channel, + (unsigned long)(self->tx_buff.data)); + set_dma_x_count(port->tx_dma_channel, self->tx_buff.len); + set_dma_x_modify(port->tx_dma_channel, 1); + enable_dma(port->tx_dma_channel); +} + +static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) { + clear_dma_irqstat(port->tx_dma_channel); + bfin_sir_stop_tx(port); + + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.len; + self->tx_buff.len = 0; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + port->tx_done = 1; + } + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static void bfin_sir_dma_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int i; + + SIR_UART_CLEAR_LSR(port); + + for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++) + async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]); +} + +void bfin_sir_rx_dma_timeout(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int x_pos, pos; + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel); + if (x_pos == DMA_SIR_RX_XCNT) + x_pos = 0; + + pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos; + + if (pos > port->rx_dma_buf.tail) { + port->rx_dma_buf.tail = pos; + bfin_sir_dma_rx_chars(dev); + port->rx_dma_buf.head = port->rx_dma_buf.tail; + } + spin_unlock_irqrestore(&self->lock, flags); +} + +static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned short irqstat; + + spin_lock(&self->lock); + + port->rx_dma_nrows++; + port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows; + bfin_sir_dma_rx_chars(dev); + if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) { + port->rx_dma_nrows = 0; + port->rx_dma_buf.tail = 0; + } + port->rx_dma_buf.head = port->rx_dma_buf.tail; + + irqstat = get_dma_curr_irqstat(port->rx_dma_channel); + clear_dma_irqstat(port->rx_dma_channel); + spin_unlock(&self->lock); + + mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS); + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_DMA */ + +static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev) +{ +#ifdef CONFIG_SIR_BFIN_DMA + dma_addr_t dma_handle; +#endif /* CONFIG_SIR_BFIN_DMA */ + + if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n"); + return -EBUSY; + } + + if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n"); + free_dma(port->rx_dma_channel); + return -EBUSY; + } + +#ifdef CONFIG_SIR_BFIN_DMA + + set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev); + set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev); + + port->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); + port->rx_dma_buf.head = 0; + port->rx_dma_buf.tail = 0; + port->rx_dma_nrows = 0; + + set_dma_config(port->rx_dma_channel, + set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, + INTR_ON_ROW, DIMENSION_2D, + DATA_SIZE_8, DMA_SYNC_RESTART)); + set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT); + set_dma_x_modify(port->rx_dma_channel, 1); + set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT); + set_dma_y_modify(port->rx_dma_channel, 1); + set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf); + enable_dma(port->rx_dma_channel); + + port->rx_dma_timer.data = (unsigned long)(dev); + port->rx_dma_timer.function = (void *)bfin_sir_rx_dma_timeout; + +#else + + if (request_irq(port->irq, bfin_sir_rx_int, IRQF_DISABLED, "BFIN_SIR_RX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n"); + return -EBUSY; + } + + if (request_irq(port->irq+1, bfin_sir_tx_int, IRQF_DISABLED, "BFIN_SIR_TX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n"); + free_irq(port->irq, dev); + return -EBUSY; + } +#endif + + return 0; +} + +static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev) +{ + unsigned short val; + + bfin_sir_stop_rx(port); + SIR_UART_DISABLE_INTS(port); + + val = SIR_UART_GET_GCTL(port); + val &= ~(UCEN | IREN | RPOLC); + SIR_UART_PUT_GCTL(port, val); + +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); + disable_dma(port->rx_dma_channel); + del_timer(&(port->rx_dma_timer)); + dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0); +#else + free_irq(port->irq+1, dev); + free_irq(port->irq, dev); +#endif + free_dma(port->tx_dma_channel); + free_dma(port->rx_dma_channel); +} + +#ifdef CONFIG_PM +static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + if (self->open) { + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + netif_device_detach(dev); + } + + return 0; +} +static int bfin_sir_resume(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + struct bfin_sir_port *port; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + port = self->sir_port; + if (self->open) { + if (self->newspeed) { + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_startup(port, dev); + bfin_sir_set_speed(port, 9600); + bfin_sir_enable_rx(port); + netif_device_attach(dev); + } + return 0; +} +#else +#define bfin_sir_suspend NULL +#define bfin_sir_resume NULL +#endif + +static void bfin_sir_send_work(struct work_struct *work) +{ + struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work); + struct net_device *dev = self->sir_port->dev; + struct bfin_sir_port *port = self->sir_port; + unsigned short val; + int tx_cnt = 10; + + while (bfin_sir_is_receiving(dev) && --tx_cnt) + turnaround_delay(dev->last_rx, self->mtt); + + bfin_sir_stop_rx(port); + + /* To avoid losting RX interrupt, we reset IR function before + * sending data. We also can set the speed, which will + * reset all the UART. + */ + val = SIR_UART_GET_GCTL(port); + val &= ~(IREN | RPOLC); + SIR_UART_PUT_GCTL(port, val); + SSYNC(); + val |= IREN | RPOLC; + SIR_UART_PUT_GCTL(port, val); + SSYNC(); + /* bfin_sir_set_speed(port, self->speed); */ + +#ifdef CONFIG_SIR_BFIN_DMA + bfin_sir_dma_tx_chars(dev); +#endif + bfin_sir_enable_tx(port); + dev->trans_start = jiffies; +} + +static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + netif_stop_queue(dev); + + self->mtt = irda_get_mtt(skb); + + if (speed != self->speed && speed != -1) + self->newspeed = speed; + + self->tx_buff.data = self->tx_buff.head; + if (skb->len == 0) + self->tx_buff.len = 0; + else + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); + + schedule_work(&self->work); + dev_kfree_skb(skb); + + return 0; +} + +static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + if (self->open) { + ret = bfin_sir_set_speed(port, rq->ifr_baudrate); + bfin_sir_enable_rx(port); + } else { + dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = bfin_sir_is_receiving(dev); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static struct net_device_stats *bfin_sir_stats(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + return &self->stats; +} + +static int bfin_sir_open(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int err = -ENOMEM; + + self->newspeed = 0; + self->speed = 9600; + + spin_lock_init(&self->lock); + + err = bfin_sir_startup(port, dev); + if (err) + goto err_startup; + + bfin_sir_set_speed(port, 9600); + + self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME); + if (!self->irlap) + goto err_irlap; + + INIT_WORK(&self->work, bfin_sir_send_work); + + /* + * Now enable the interrupt then start the queue + */ + self->open = 1; + bfin_sir_enable_rx(port); + + netif_start_queue(dev); + + return 0; + +err_irlap: + self->open = 0; + bfin_sir_shutdown(port, dev); +err_startup: + return err; +} + +static int bfin_sir_stop(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + + if (self->rxskb) { + dev_kfree_skb(self->rxskb); + self->rxskb = NULL; + } + + /* Stop IrLAP */ + if (self->irlap) { + irlap_close(self->irlap); + self->irlap = NULL; + } + + netif_stop_queue(dev); + self->open = 0; + + return 0; +} + +static int bfin_sir_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (!io->head) + return -ENOMEM; + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + return 0; +} + +static int __devinit bfin_sir_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct bfin_sir_self *self; + unsigned int baudrate_mask; + struct bfin_sir_port *sir_port; + int err; + + if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \ + per[pdev->id][3] == pdev->id) { + err = peripheral_request_list(per[pdev->id], DRIVER_NAME); + if (err) + return err; + } else { + dev_err(&pdev->dev, "Invalid pdev id, please check board file\n"); + return -ENODEV; + } + + err = -ENOMEM; + sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL); + if (!sir_port) + goto err_mem_0; + + bfin_sir_init_ports(sir_port, pdev); + + dev = alloc_irdadev(sizeof(*self)); + if (!dev) + goto err_mem_1; + + self = netdev_priv(dev); + self->dev = &pdev->dev; + self->sir_port = sir_port; + sir_port->dev = dev; + + err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU); + if (err) + goto err_mem_2; + err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME); + if (err) + goto err_mem_3; + + dev->hard_start_xmit = bfin_sir_hard_xmit; + dev->open = bfin_sir_open; + dev->stop = bfin_sir_stop; + dev->do_ioctl = bfin_sir_ioctl; + dev->get_stats = bfin_sir_stats; + dev->irq = sir_port->irq; + + irda_init_max_qos_capabilies(&self->qos); + + baudrate_mask = IR_9600; + + switch (max_rate) { + case 115200: + baudrate_mask |= IR_115200; + case 57600: + baudrate_mask |= IR_57600; + case 38400: + baudrate_mask |= IR_38400; + case 19200: + baudrate_mask |= IR_19200; + case 9600: + break; + default: + dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n"); + } + + self->qos.baud_rate.bits &= baudrate_mask; + + self->qos.min_turn_time.bits = 1; /* 10 ms or more */ + + irda_qos_bits_to_value(&self->qos); + + err = register_netdev(dev); + + if (err) { + kfree(self->tx_buff.head); +err_mem_3: + kfree(self->rx_buff.head); +err_mem_2: + free_netdev(dev); +err_mem_1: + kfree(sir_port); +err_mem_0: + peripheral_free_list(per[pdev->id]); + } else + platform_set_drvdata(pdev, sir_port); + + return err; +} + +static int __devexit bfin_sir_remove(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev = NULL; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + dev = sir_port->dev; + self = netdev_priv(dev); + unregister_netdev(dev); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + free_netdev(dev); + kfree(sir_port); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver bfin_ir_driver = { + .probe = bfin_sir_probe, + .remove = __devexit_p(bfin_sir_remove), + .suspend = bfin_sir_suspend, + .resume = bfin_sir_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init bfin_sir_init(void) +{ + return platform_driver_register(&bfin_ir_driver); +} + +static void __exit bfin_sir_exit(void) +{ + platform_driver_unregister(&bfin_ir_driver); +} + +module_init(bfin_sir_init); +module_exit(bfin_sir_exit); + +module_param(max_rate, int, 0); +MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)"); + +MODULE_AUTHOR("Graf Yang "); +MODULE_DESCRIPTION("Blackfin IrDA driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h new file mode 100644 index 0000000..dac71b1 --- /dev/null +++ b/drivers/net/irda/bfin_sir.h @@ -0,0 +1,148 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_SIR_BFIN_DMA +struct dma_rx_buf { + char *buf; + int head; + int tail; +}; +#endif + +struct bfin_sir_port { + unsigned char __iomem *membase; + unsigned int irq; + unsigned int lsr; + unsigned long clk; + struct net_device *dev; +#ifdef CONFIG_SIR_BFIN_DMA + int tx_done; + struct dma_rx_buf rx_dma_buf; + struct timer_list rx_dma_timer; + int rx_dma_nrows; +#endif + unsigned int tx_dma_channel; + unsigned int rx_dma_channel; +}; + +struct bfin_sir_port_res { + unsigned long base_addr; + int irq; + unsigned int rx_dma_channel; + unsigned int tx_dma_channel; +}; + +struct bfin_sir_self { + struct bfin_sir_port *sir_port; + spinlock_t lock; + unsigned int open; + int speed; + int newspeed; + + struct sk_buff *txskb; + struct sk_buff *rxskb; + struct net_device_stats stats; + struct device *dev; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct work_struct work; + int mtt; +}; + +#define DRIVER_NAME "bfin_sir" + +#define SIR_UART_GET_CHAR(port) bfin_read16((port)->membase + OFFSET_RBR) +#define SIR_UART_GET_DLL(port) bfin_read16((port)->membase + OFFSET_DLL) +#define SIR_UART_GET_DLH(port) bfin_read16((port)->membase + OFFSET_DLH) +#define SIR_UART_GET_LCR(port) bfin_read16((port)->membase + OFFSET_LCR) +#define SIR_UART_GET_GCTL(port) bfin_read16((port)->membase + OFFSET_GCTL) + +#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v) +#define SIR_UART_PUT_DLL(port, v) bfin_write16(((port)->membase + OFFSET_DLL), v) +#define SIR_UART_PUT_DLH(port, v) bfin_write16(((port)->membase + OFFSET_DLH), v) +#define SIR_UART_PUT_LCR(port, v) bfin_write16(((port)->membase + OFFSET_LCR), v) +#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v) + +#ifdef CONFIG_BF54x +#define SIR_UART_GET_LSR(port) bfin_read16((port)->membase + OFFSET_LSR) +#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER_SET) +#define SIR_UART_SET_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_SET), v) +#define SIR_UART_CLEAR_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v) +#define SIR_UART_PUT_LSR(port, v) bfin_write16(((port)->membase + OFFSET_LSR), v) +#define SIR_UART_CLEAR_LSR(port) bfin_write16(((port)->membase + OFFSET_LSR), -1) + +#define SIR_UART_SET_DLAB(port) +#define SIR_UART_CLEAR_DLAB(port) + +#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_SET_IER(port, v) +#define SIR_UART_DISABLE_INTS(port) SIR_UART_CLEAR_IER(port, 0xF) +#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_LSR(port, TFI); SIR_UART_CLEAR_IER(port, ETBEI); } while (0) +#define SIR_UART_ENABLE_TX(port) do { SIR_UART_SET_IER(port, ETBEI); } while (0) +#define SIR_UART_STOP_RX(port) do { SIR_UART_CLEAR_IER(port, ERBFI); } while (0) +#define SIR_UART_ENABLE_RX(port) do { SIR_UART_SET_IER(port, ERBFI); } while (0) +#else + +#define SIR_UART_GET_IIR(port) bfin_read16((port)->membase + OFFSET_IIR) +#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER) +#define SIR_UART_PUT_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER), v) + +#define SIR_UART_SET_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) | DLAB); } while (0) +#define SIR_UART_CLEAR_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) & ~DLAB); } while (0) + +#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_PUT_IER(port, v) +#define SIR_UART_DISABLE_INTS(port) SIR_UART_PUT_IER(port, 0) +#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ETBEI); } while (0) +#define SIR_UART_ENABLE_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ETBEI); } while (0) +#define SIR_UART_STOP_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ERBFI); } while (0) +#define SIR_UART_ENABLE_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ERBFI); } while (0) + +static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port) +{ + unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR); + port->lsr |= (lsr & (BI|FE|PE|OE)); + return lsr | port->lsr; +} + +static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port) +{ + port->lsr = 0; + bfin_read16(port->membase + OFFSET_LSR); +} +#endif + +static const unsigned short per[][4] = { + /* rx pin tx pin NULL uart_number */ + {P_UART0_RX, P_UART0_TX, 0, 0}, + {P_UART1_RX, P_UART1_TX, 0, 1}, + {P_UART2_RX, P_UART2_TX, 0, 2}, + {P_UART3_RX, P_UART3_TX, 0, 3}, +}; -- cgit v0.10.2 From adbf7f01e78287701c0270a5262f319935d94082 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 5 Jun 2009 12:54:44 +0200 Subject: irda: smsc wait count reaches -1 The sir retries count reaches -1 rather than 0. Signed-off-by: Roel Kluin Signed-off-by: Samuel Ortiz Signed-off-by: Andrew Morton diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 59d7980..d0797ad 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -2124,7 +2124,7 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT)) udelay(1); - if (count == 0) + if (count < 0) IRDA_DEBUG(0, "%s(): stuck transmitter\n", __func__); } -- cgit v0.10.2 From e0057975e09a85ac92be81e975d0d0a911b1c4c6 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 5 Jun 2009 16:12:00 +0200 Subject: irda: add git tree to MAINTAINERS file We now have an IrDA git tree on kernel.org: git://git.kernel.org/pub/scm/linux/kernel/git/sameo/irda-2.6.git Signed-off-by: Samuel Ortiz diff --git a/MAINTAINERS b/MAINTAINERS index a6df68f..61c190a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3122,6 +3122,7 @@ M: samuel@sortiz.org L: irda-users@lists.sourceforge.net (subscribers-only) W: http://irda.sourceforge.net/ S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/irda-2.6.git F: Documentation/networking/irda.txt F: drivers/net/irda/ F: include/net/irda/ -- cgit v0.10.2 From 635c265f32d8a3f73402813d6a8dd47f2a363df5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 13 Jun 2009 10:12:59 +0200 Subject: ALSA: ctxfi - Replace atc lock to mutex The spinlock in atc can cause a sleep in lock: Kernel failure message 1: BUG: sleeping function called from invalid context at mm/slub.c:1599 in_atomic(): 0, irqs_disabled(): 1, pid: 2537, name: gstreamer-prope Pid: 2537, comm: gstreamer-prope Tainted: P 2.6.29.4-167.fc11.x86_64 #1 Call Trace: [] __might_sleep+0x10b/0x110 [] __kmalloc+0x73/0x130 [] ? daio_rsc_init+0xaa/0x125 [snd_ctxfi] [] dao_rsc_init+0x55/0x1c0 [snd_ctxfi] [] dao_rsc_reinit+0x55/0x5d [snd_ctxfi] [] ? _spin_lock_irqsave+0x32/0x3b [] atc_spdif_out_passthru+0x92/0x136 [snd_ctxfi] ... Since the lock path is no critical path, it can be gracefully replaced with a mutex. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 80fb2ba..b0adc80 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -259,7 +259,6 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) int n_amixer = apcm->substream->runtime->channels, i = 0; int device = apcm->substream->pcm->device; unsigned int pitch; - unsigned long flags; if (NULL != apcm->src) { /* Prepared pcm playback */ @@ -311,10 +310,10 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; for (i = 0; i < n_amixer; i++) { amixer = apcm->amixers[i]; - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); amixer->ops->setup(amixer, &src->rsc, INIT_VOL, atc->pcm[i+device*2]); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); src = src->ops->next_interleave(src); if (NULL == src) src = apcm->src; @@ -865,7 +864,6 @@ static int spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) { struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); - unsigned long flags; unsigned int rate = apcm->substream->runtime->rate; unsigned int status; int err; @@ -885,7 +883,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) return -ENOENT; } - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); dao->ops->get_spos(dao, &status); if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { status &= ((~IEC958_AES3_CON_FS) << 24); @@ -895,7 +893,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) } if ((rate != atc->pll_rate) && (32000 != rate)) err = atc_pll_init(atc, rate); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); return err; } @@ -908,7 +906,6 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) struct dao *dao; int err; int i; - unsigned long flags; if (NULL != apcm->src) return 0; @@ -934,13 +931,13 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; } /* Connect to SPDIFOO */ - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); dao = container_of(atc->daios[SPDIFOO], struct dao, daio); amixer = apcm->amixers[0]; dao->ops->set_left_input(dao, &amixer->rsc); amixer = apcm->amixers[1]; dao->ops->set_right_input(dao, &amixer->rsc); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); ct_timer_prepare(apcm->timer); @@ -1088,7 +1085,6 @@ static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) { - unsigned long flags; struct dao_desc da_dsc = {0}; struct dao *dao; int err; @@ -1096,7 +1092,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) struct rsc *rscs[2] = {NULL}; unsigned int spos = 0; - spin_lock_irqsave(&atc->atc_lock, flags); + mutex_lock(&atc->atc_mutex); dao = container_of(atc->daios[SPDIFOO], struct dao, daio); da_dsc.msr = state ? 1 : atc->msr; da_dsc.passthru = state ? 1 : 0; @@ -1114,7 +1110,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) } dao->ops->set_spos(dao, spos); dao->ops->commit_write(dao); - spin_unlock_irqrestore(&atc->atc_lock, flags); + mutex_unlock(&atc->atc_mutex); return err; } @@ -1572,7 +1568,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, atc->msr = msr; atc->chip_type = chip_type; - spin_lock_init(&atc->atc_lock); + mutex_init(&atc->atc_mutex); /* Find card model */ err = atc_identify_card(atc); diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index a033472..9fe620ea 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -19,7 +19,7 @@ #define CTATC_H #include -#include +#include #include #include #include @@ -90,7 +90,7 @@ struct ct_atc { void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index); - spinlock_t atc_lock; + struct mutex atc_mutex; int (*pcm_playback_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm); -- cgit v0.10.2 From e46b0c8c08cd97eb8f9a523986908add3ece0cc6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 13 Jun 2009 10:16:43 +0200 Subject: ALSA: hda - Add quirk for Acer Aspire 6935G Added model=acer-aspire-8930g for Acer Aspire 6935G (1025:0146). Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 337d2a5..d22b260 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9014,6 +9014,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", ALC888_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", + ALC888_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", -- cgit v0.10.2 From 3790c8cdb99f23824b23cb16df608281b335ee91 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 03:00:35 +0000 Subject: net: fix network driver ndo_start_xmit() return values (part 1) Fix up drivers that return an errno value to qdisc_restart(), causing qdisc_restart() to print a warning and requeue/retransmit the skb. - xpnet: memory allocation error, intention is to drop - ethoc: oversized packet, packet must be dropped - ibmlana: skb freed: use after free - rrunner: skb freed: use after free Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 6faefcf..8d1c60a 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -450,7 +450,8 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) "packet\n", sizeof(struct xpnet_pending_msg)); dev->stats.tx_errors++; - return -ENOMEM; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } /* get the beginning of the first cacheline and end of last */ diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 91a9b1a..ceb6a9c 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -811,7 +811,7 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > ETHOC_BUFSIZ)) { priv->stats.tx_errors++; - return -EMSGSIZE; + goto out; } entry = priv->cur_tx % priv->num_tx; @@ -840,9 +840,9 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; - dev_kfree_skb(skb); - spin_unlock_irq(&priv->lock); +out: + dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index c25bc0b..448098d 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -815,7 +815,7 @@ static int ibmlana_close(struct net_device *dev) static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) { ibmlana_priv *priv = netdev_priv(dev); - int retval = 0, tmplen, addr; + int tmplen, addr; unsigned long flags; tda_t tda; int baddr; @@ -824,7 +824,6 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) the upper layer is in deep desperation and we simply ignore the frame. */ if (priv->txusedcnt >= TXBUFCNT) { - retval = -EIO; dev->stats.tx_dropped++; goto tx_done; } @@ -874,7 +873,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); tx_done: dev_kfree_skb(skb); - return retval; + return NETDEV_TX_OK; } /* switch receiver mode. */ diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index d890829..81dbcbb 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1425,7 +1425,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(new_skb = dev_alloc_skb(len + 8))) { dev_kfree_skb(skb); netif_wake_queue(dev); - return -EBUSY; + return NETDEV_TX_OK; } skb_reserve(new_skb, 8); skb_put(new_skb, len); -- cgit v0.10.2 From 4bd73ae2682d9069746bb049a416d9ab90c6684b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 03:17:19 +0000 Subject: net: fix network drivers ndo_start_xmit() return values (part 2) Fix up IRDA drivers that return an errno value to qdisc_restart(), causing qdisc_restart() to print a warning an requeue/retransmit the skb. - donauboe: intention appears to be to have the skb retransmitted without error message - irda-usb: intention is to drop silently according to comment - kingsub-sir: skb is freed: use after free - ks959-sir: skb is freed: use after free - ksdazzle-sir: skb is freed: use after free - mcs7880: skb is freed: use after free All but donauboe compile tested. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 6b6548b..9a0346e 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -994,11 +994,11 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) /* change speed pending, wait for its execution */ if (self->new_speed) - return -EBUSY; + return NETDEV_TX_BUSY; /* device stopped (apm) wait for restart */ if (self->stopped) - return -EBUSY; + return NETDEV_TX_BUSY; toshoboe_checkstuck (self); @@ -1049,7 +1049,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) if (self->txpending) { spin_unlock_irqrestore(&self->spinlock, flags); - return -EBUSY; + return NETDEV_TX_BUSY; } /* If in SIR mode we need to generate a string of XBOFs */ @@ -1105,7 +1105,7 @@ dumpbufs(skb->data,skb->len,'>'); ,skb->len, self->ring->tx[self->txs].control, self->txpending); toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); spin_unlock_irqrestore(&self->spinlock, flags); - return -EBUSY; + return NETDEV_TX_BUSY; } if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON) diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 394b2b1..0c0831c 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -389,7 +389,6 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) s32 speed; s16 xbofs; int res, mtt; - int err = 1; /* Failed */ IRDA_DEBUG(4, "%s() on %s\n", __func__, netdev->name); @@ -430,7 +429,6 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) irda_usb_change_speed_xbofs(self); netdev->trans_start = jiffies; /* Will netif_wake_queue() in callback */ - err = 0; /* No error */ goto drop; } } @@ -542,7 +540,7 @@ drop: /* Drop silently the skb and exit */ dev_kfree_skb(skb); spin_unlock_irqrestore(&self->lock, flags); - return err; /* Usually 1 */ + return NETDEV_TX_OK; } /*------------------------------------------------------------------*/ diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index 9d813bc..c3e4e2c 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -156,9 +156,6 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) int wraplen; int ret = 0; - if (skb == NULL || netdev == NULL) - return -EINVAL; - netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -197,7 +194,7 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return ret; + return NETDEV_TX_OK; } /* Receive callback function */ diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index b6ffe97..d73b8b6 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -391,9 +391,6 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int wraplen; int ret = 0; - if (skb == NULL || netdev == NULL) - return -EINVAL; - netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -428,7 +425,7 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return ret; + return NETDEV_TX_OK; } /* Receive callback function */ diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 64df27f..1ef45ec 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -304,9 +304,6 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int wraplen; int ret = 0; - if (skb == NULL || netdev == NULL) - return -EINVAL; - netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -341,7 +338,7 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return ret; + return NETDEV_TX_OK; } /* Receive callback function */ diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index fac504d..f4df100 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -824,10 +824,6 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) int wraplen; int ret = 0; - - if (skb == NULL || ndev == NULL) - return -EINVAL; - netif_stop_queue(ndev); mcs = netdev_priv(ndev); @@ -870,7 +866,7 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) dev_kfree_skb(skb); spin_unlock_irqrestore(&mcs->lock, flags); - return ret; + return NETDEV_TX_OK; } static const struct net_device_ops mcs_netdev_ops = { -- cgit v0.10.2 From 4153e77596c4caaf52293b0c6b2207d73ed8f1eb Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 04:08:02 +0000 Subject: net: fix network drivers ndo_start_xmit() return values (part 3) net: fix network drivers ndo_start_xmit() return values (part 3) Fix up wireless drivers that return an errno value to qdisc_restart(), causing qdisc_restart() to print a warning an requeue/retransmit the skb. - airo: transmission not implemented for chip, intention is to free and abort - ipw2200: transmission not implemented for promiscous mode, intention is to drop - prism54: intention is to drop - wl3501_cs: intention appears to be to drop - zd1201: error counter indicates intention is to drop All drivers compile tested. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 9eabf4d..dfb30b9 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2193,7 +2193,8 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if (test_bit(FLAG_MPI, &priv->flags)) { /* Not implemented yet for MPI350 */ netif_stop_queue(dev); - return -ENETDOWN; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } if ( skb == NULL ) { diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index c3b3dfe..44c29b3 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11524,7 +11524,8 @@ static int ipw_prom_stop(struct net_device *dev) static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { IPW_DEBUG_INFO("prom dev->xmit\n"); - return -EOPNOTSUPP; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } static const struct net_device_ops ipw_prom_netdev_ops = { diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index ef3ef45..8f62109 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -87,7 +87,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) unsigned long flags; unsigned char wds_mac[6]; u32 curr_frag; - int err = 0; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); @@ -107,8 +106,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); - - err = -EBUSY; goto drop_free; } /* Check alignment and WDS frame formatting. The start of the packet should @@ -152,7 +149,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) if (unlikely(newskb == NULL)) { printk(KERN_ERR "%s: Cannot allocate skb\n", ndev->name); - err = -ENOMEM; goto drop_free; } newskb_offset = (4 - (long) newskb->data) & 0x03; @@ -197,8 +193,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) if (unlikely(pci_map_address == 0)) { printk(KERN_WARNING "%s: cannot map buffer to PCI\n", ndev->name); - - err = -EIO; goto drop_free; } /* Place the fragment in the control block structure. */ @@ -246,7 +240,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) ndev->stats.tx_dropped++; spin_unlock_irqrestore(&priv->slock, flags); dev_kfree_skb(skb); - return err; + return NETDEV_TX_OK; } static inline int diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 1f64d60..e3e96bb 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1348,6 +1348,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (rc) { ++dev->stats.tx_dropped; netif_stop_queue(dev); + rc = NETDEV_TX_OK; } else { ++dev->stats.tx_packets; dev->stats.tx_bytes += skb->len; diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 5fabd9c..4430b8d9 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -819,11 +819,11 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (err) { dev->stats.tx_errors++; netif_start_queue(dev); - return err; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; } - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; kfree_skb(skb); return 0; -- cgit v0.10.2 From 47f88c99c2ad0c05dd415e1c2a6d59426eb305ed Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 04:37:34 +0000 Subject: net: fix network drivers ndo_start_xmit() return values (part 4) Fix up WAN drivers that return an errno value to qdisc_restart(), causing qdisc_restart() to print a warning an requeue/retransmit the skb. - cycx_x25: intention appears to be to requeue the skb Does not compile cleanly for me even without this patch, so untested. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 35dea3b..f525f9f 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -615,7 +615,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, case WAN_DISCONNECTED: if (cycx_x25_chan_connect(dev)) { netif_stop_queue(dev); - return -EBUSY; + return NETDEV_TX_BUSY; } /* fall thru */ case WAN_CONNECTED: @@ -624,7 +624,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); if (cycx_x25_chan_send(dev, skb)) - return -EBUSY; + return NETDEV_TX_BUSY; break; default: @@ -656,7 +656,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, if (cycx_x25_chan_send(dev, skb)) { /* prepare for future retransmissions */ skb_push(skb, 1); - return -EBUSY; + return NETDEV_TX_BUSY; } } -- cgit v0.10.2 From ae71bafdd4ce29856addfede1ab7046f4e45775b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 05:13:07 +0000 Subject: net: fix network drivers ndo_start_xmit() return values (part 5) Fix up s390 drivers that return an errno value to qdisc_restart(), causing qdisc_restart() to print a warning an requeue/retransmit the skb. - claw: impossible condition, simply remove it Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 30a43cc..7b6f46d 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -338,12 +338,6 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) CLAW_DBF_TEXT(4, trace, "claw_tx"); p_ch=&privptr->channel[WRITE]; - if (skb == NULL) { - privptr->stats.tx_dropped++; - privptr->stats.tx_errors++; - CLAW_DBF_TEXT_(2, trace, "clawtx%d", -EIO); - return -EIO; - } spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); rc=claw_hw_tx( skb, dev, 1 ); spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); -- cgit v0.10.2 From 98ca4a46d27348476c9196ebc0a0c5297431d90f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 05:20:01 +0000 Subject: net: fix network drivers ndo_start_xmit() return values (part 6) Fix up hamradio drivers that return an errno value to dev_queue_xmit(), causing it to print a warning an free the skb. - bpqether: skb is freed: use after free Compile tested only. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index d509b37..5105548 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -274,7 +274,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { printk(KERN_WARNING "bpqether: out of memory\n"); kfree_skb(skb); - return -ENOMEM; + return NETDEV_TX_OK; } if (skb->sk != NULL) @@ -294,7 +294,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) if ((dev = bpq_get_ether_dev(dev)) == NULL) { dev->stats.tx_dropped++; kfree_skb(skb); - return -ENODEV; + return NETDEV_TX_OK; } skb->protocol = ax25_type_trans(skb, dev); -- cgit v0.10.2 From 81fbbf60408ad6b98ff72120de948cb7fd2498d0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 05:34:37 +0000 Subject: net: fix network drivers ndo_start_xmit() return values (part 7) Fix up ATM drivers that return an errno value to qdisc_restart(), causing qdisc_restart() to print a warning an requeue/retransmit the skb. - lec: condition can only be remedied by userspace, until that retransmissions Compile tested only. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/atm/lec.c b/net/atm/lec.c index 75b9d59..ff2e594 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -270,7 +270,8 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("%s:No lecd attached\n", dev->name); dev->stats.tx_errors++; netif_stop_queue(dev); - return -EUNATCH; + kfree_skb(skb); + return NETDEV_TX_OK; } pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n", -- cgit v0.10.2 From 5b2c4b972c0226406361f83b747eb5cdab51e68e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 06:14:36 +0000 Subject: net: fix network drivers ndo_start_xmit() return values (part 8) Fix up USB drivers that return an errno value (result of usb_submit_urb()) to qdisc_restart(), causing qdisc_restart() to print a warning and requeue/ retransmit the skb. - hso: skb is freed: use after free - at76_usb: skb is freed: use after free Compile tested only. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index e3580f4..f8c6d7e 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -816,7 +816,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) } dev_kfree_skb(skb); /* we're done */ - return result; + return NETDEV_TX_OK; } static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index c8af9a8..3f303ae 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -3242,12 +3242,11 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n", priv->netdev->name, priv->tx_urb, priv->tx_urb->hcpriv, priv->tx_urb->complete); - } else { + } else stats->tx_bytes += skb->len; - dev_kfree_skb(skb); - } - return ret; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } static void at76_tx_timeout(struct net_device *netdev) -- cgit v0.10.2 From 5b548140225c6bbbbd560551dd1048b2c0ce58be Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 12 Jun 2009 06:22:29 +0000 Subject: net: use symbolic values for ndo_start_xmit() return codes Convert magic values 1 and -1 to NETDEV_TX_BUSY and NETDEV_TX_LOCKED respectively. 0 (NETDEV_TX_OK) is not changed to keep the noise down, except in very few cases where its in direct proximity to one of the other values. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index cb8943d..34d54e7 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1069,7 +1069,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - return 1; + return NETDEV_TX_BUSY; } /* we have our lp locked from now on */ @@ -1273,14 +1273,14 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&dev->lock, flags); isdn_net_dial(); /* Initiate dialing */ netif_stop_queue(ndev); - return 1; /* let upper layer requeue skb packet */ + return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */ } #endif /* Initiate dialing */ spin_unlock_irqrestore(&dev->lock, flags); isdn_net_dial(); isdn_net_device_stop_queue(lp); - return 1; + return NETDEV_TX_BUSY; } else { isdn_net_unreachable(ndev, skb, "No phone number"); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index c2804f2..a9e48e2 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -703,7 +703,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) printk (KERN_ERR "%s: no tx context available: %u\n", __func__, priv->mpt_txfidx_tail); - return 1; + return NETDEV_TX_BUSY; } mf = mpt_get_msg_frame(LanCtx, mpt_dev); @@ -713,7 +713,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) printk (KERN_ERR "%s: Unable to alloc request frame\n", __func__); - return 1; + return NETDEV_TX_BUSY; } ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index b284994..f71b354 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1088,7 +1088,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) pr_debug("%s: failed to transmit packet\n", dev->name); } spin_unlock_irqrestore(&adapter->lock, flags); - return 1; + return NETDEV_TX_BUSY; } if (elp_debug >= 3) pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len); diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 7fd0ff7..3e00fa8 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -1014,7 +1014,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, int i; if (vp->tx_full) /* No room to transmit with */ - return 1; + return NETDEV_TX_BUSY; if (vp->cur_tx != 0) prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE]; else diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index c10ca30..aaa8a9f 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1030,7 +1030,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); if(atomic_read(&lp->tx_count)==0) { - return 1; + return NETDEV_TX_BUSY; } if (skb_padto(skb, ETH_ZLEN)) { diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index a6e8a2d..c34aee9 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2107,7 +2107,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", dev->name); netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } vp->tx_skbuff[entry] = skb; diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 7a331ac..69f5b7d 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -541,7 +541,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (!TX_BUFFS_AVAIL) - return -1; + return NETDEV_TX_LOCKED; netif_stop_queue (dev); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index c9fc0ff..50efde1 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -756,7 +756,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&cp->lock, intr_flags); pr_err(PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } #if CP_VLAN_TAG_USED diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 02f64d5..85a1817 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -564,7 +564,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) if (!TX_BUFFS_AVAIL){ local_irq_restore(flags); - return -1; + return NETDEV_TX_LOCKED; } #ifdef DEBUG_DRIVER diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 7f4bc8a..2e7419a 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -829,7 +829,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; } else { printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n"); - return 1; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) + return NETDEV_TX_BUSY; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) on this skb, he also reports -ENETDOWN and printk's, so either we free and return(0) or don't free and return 1 */ } diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index ec8a1ae..4550371 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -526,7 +526,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) if (priv(dev)->tx_tail == next_ptr) { local_irq_restore(flags); - return 1; /* unable to queue */ + return NETDEV_TX_BUSY; /* unable to queue */ } dev->trans_start = jiffies; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index d58c105..d3c734f 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -957,7 +957,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) /* We've wrapped around and the transmitter is still busy */ netif_stop_queue(dev); aup->tx_full = 1; - return 1; + return NETDEV_TX_BUSY; } else if (buff_stat & TX_T_DONE) { update_tx_stats(dev, ptxd->status); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f522276..eb06667 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2934,7 +2934,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) * individual queues. */ if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb)) - return 1; + return NETDEV_TX_BUSY; dev->trans_start = jiffies; return 0; } diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 7433b88..3eee666 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1551,7 +1551,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&lp->lock); if (net_debug) printk("cs89x0: Tx buffer not free!\n"); - return 1; + return NETDEV_TX_BUSY; } /* Write the contents of the packet */ writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); diff --git a/drivers/net/de600.c b/drivers/net/de600.c index c866ca9..e1af089 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -168,14 +168,14 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */ tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) - return 1; + return NETDEV_TX_BUSY; /* else */ printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem"); /* Restart the adapter. */ spin_lock_irqsave(&de600_lock, flags); if (adapter_init(dev)) { spin_unlock_irqrestore(&de600_lock, flags); - return 1; + return NETDEV_TX_BUSY; } spin_unlock_irqrestore(&de600_lock, flags); } @@ -199,7 +199,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) { if (adapter_init(dev)) { spin_unlock_irqrestore(&de600_lock, flags); - return 1; + return NETDEV_TX_BUSY; } } } diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 039bc1a..55d2bb6 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -531,7 +531,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) case (TXBF0 | TXBF1): /* NONE!!! */ printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name); spin_unlock_irqrestore(&de620_lock, flags); - return 1; + return NETDEV_TX_BUSY; } de620_write_block(dev, buffer, skb->len, len-skb->len); diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 4ec055d..102b8d4 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3318,7 +3318,7 @@ static int dfx_xmt_queue_pkt( { skb_pull(skb,3); spin_unlock_irqrestore(&bp->lock, flags); - return(1); /* requeue packet for later */ + return NETDEV_TX_BUSY; /* requeue packet for later */ } /* diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 9301eb2..97ea2d6 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -957,7 +957,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) if (TX_BUFFS_AVAIL) netif_start_queue(dev); } else - status = -1; + status = NETDEV_TX_LOCKED; out: return status; @@ -1839,7 +1839,7 @@ static int load_packet(struct net_device *dev, struct sk_buff *skb) lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */ } else { - status = -1; + status = NETDEV_TX_LOCKED; } return status; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index e402e91..dd771de 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -756,7 +756,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) dm9000_dbg(db, 3, "%s:\n", __func__); if (db->tx_pkt_cnt > 1) - return 1; + return NETDEV_TX_BUSY; spin_lock_irqsave(&db->lock, flags); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 119dc53..e52a201 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1716,7 +1716,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* This is a hard error - log it. */ DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n"); netif_stop_queue(netdev); - return 1; + return NETDEV_TX_BUSY; } netdev->trans_start = jiffies; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 1a685a0..1e97232 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -873,7 +873,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) err_out: ENABLE_IRQs; spin_unlock_irq (&lp->hw_lock); - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 28db691..0f19b74 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -290,7 +290,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!fep->link) { /* Link is down or autonegotiation is in progress. */ - return 1; + return NETDEV_TX_BUSY; } spin_lock_irqsave(&fep->hw_lock, flags); @@ -305,7 +305,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) */ printk("%s: tx queue full!.\n", dev->name); spin_unlock_irqrestore(&fep->hw_lock, flags); - return 1; + return NETDEV_TX_BUSY; } /* Clear all of the status flags */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 26151fa..9d5b62c 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1280,7 +1280,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) status=readw(hmp->base + TxStatus); if( !(status & 0x0001) || (status & 0x0002)) writew(0x0001, hmp->base + TxCmd); - return 1; + return NETDEV_TX_BUSY; } /* Caution: the write order is important here, set the field diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index bb78c11..5e4b7af 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -777,7 +777,7 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) return 0; } if (bc->skb) - return -1; + return NETDEV_TX_LOCKED; /* strip KISS byte */ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { dev_kfree_skb(skb); diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 61de56e..d034f8c 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -409,7 +409,7 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) return 0; } if (sm->skb) - return -1; + return NETDEV_TX_LOCKED; netif_stop_queue(dev); sm->skb = skb; return 0; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 032c0db..fda2fc8 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -531,7 +531,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } if (netif_queue_stopped(dev)) { @@ -541,7 +541,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) */ if (time_before(jiffies, dev->trans_start + 20 * HZ)) { /* 20 sec timeout not reached */ - return 1; + return NETDEV_TX_BUSY; } printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 806533c..beb8421 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1484,7 +1484,7 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) stop_queue: netif_stop_queue(ndev); DBG2(dev, "stopped TX queue" NL); - return 1; + return NETDEV_TX_BUSY; } /* Tx lock BHs */ diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index 269153e..c4361d4 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -512,13 +512,13 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return 1; + return NETDEV_TX_BUSY; } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return 1; + return NETDEV_TX_BUSY; } pDB = aup->tx_db_inuse[aup->tx_head]; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index d940809..fd0796c 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -607,7 +607,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) * stopped so the network layer will retry after the * fsm completes and wakes the queue. */ - return 1; + return NETDEV_TX_BUSY; } else if (unlikely(err)) { /* other fatal error - forget the speed change and diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 789b6cb..f28c233 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -370,7 +370,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&ei_local->page_lock); enable_irq_lockdep_irqrestore(dev->irq, &flags); dev->stats.tx_errors++; - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index e24175a..dab4533 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -400,7 +400,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) /* Gasp! It hasn't. But that shouldn't happen since we're waiting for TxOk, so return 1 and requeue this packet. */ local_irq_restore(flags); - return 1; + return NETDEV_TX_BUSY; } /* Write the contents of the packet */ diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 7222659..5b5c253 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -645,7 +645,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) "BUG! Tx Ring full when queue awake!\n"); dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", bp->tx_head, bp->tx_tail); - return 1; + return NETDEV_TX_BUSY; } entry = bp->tx_head; diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 1ad740b..1427755 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -547,7 +547,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); mp->tx_fullup = 1; spin_unlock_irqrestore(&mp->lock, flags); - return 1; /* can't take it at the moment */ + return NETDEV_TX_BUSY; /* can't take it at the moment */ } spin_unlock_irqrestore(&mp->lock, flags); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index c9a30d3..1f6e36e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2687,7 +2687,7 @@ again: /* we are out of transmit resources */ tx->stop_queue++; netif_tx_stop_queue(netdev_queue); - return 1; + return NETDEV_TX_BUSY; } /* Setup checksum offloading, if needed */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 9a802ad..5f0758b 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -640,7 +640,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!TX_BUFFS_AVAIL(head, tail)) { DTX(("no buffs available, returning 1\n")); - return 1; + return NETDEV_TX_BUSY; } spin_lock_irqsave(&mp->irq_lock, flags); diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 6474f02..1f10ed6 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1165,7 +1165,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) if (test_and_set_bit(0, (void*)&p->lock)) { printk(KERN_ERR "%s: Queue was locked.\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } { diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 940962a..1576ac0 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1097,7 +1097,7 @@ again: if (unlikely(dev->CFG_cache & CFG_LNKSTS)) { netif_stop_queue(ndev); if (unlikely(dev->CFG_cache & CFG_LNKSTS)) - return 1; + return NETDEV_TX_BUSY; netif_start_queue(ndev); } @@ -1115,7 +1115,7 @@ again: netif_start_queue(ndev); goto again; } - return 1; + return NETDEV_TX_BUSY; } if (free_idx == dev->tx_intr_idx) { diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 15b8fe6..0e38d80 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1130,7 +1130,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); dev->stats.tx_errors++; - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 81e6660..479d5b4 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -877,7 +877,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length > ETH_FRAME_LEN) { printk(KERN_NOTICE "%s: Attempting to send a large packet" " (%d bytes).\n", dev->name, length); - return 1; + return NETDEV_TX_BUSY; } DEBUG(4, "%s: Transmitting a packet of length %lu.\n", diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 48dbb35..37e05d3 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1388,7 +1388,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_aborted_errors++; printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } smc->saved_skb = skb; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index a3685c0..ef37d22 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1399,7 +1399,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n", dev->name, freespace, okay ? " (okay)":" (not enough)"); if (!okay) { /* not enough space */ - return 1; /* upper layer may decide to requeue this packet */ + return NETDEV_TX_BUSY; /* upper layer may decide to requeue this packet */ } /* send the packet */ PutWord(XIRCREG_EDP, (u_short)pktlen); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 0be0f0b..7a62f78 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -955,12 +955,12 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) struct plip_local *snd = &nl->snd_data; if (netif_queue_stopped(dev)) - return 1; + return NETDEV_TX_BUSY; /* We may need to grab the bus */ if (!nl->port_owner) { if (parport_claim(nl->pardev)) - return 1; + return NETDEV_TX_BUSY; nl->port_owner = 1; } @@ -969,7 +969,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) if (skb->len > dev->mtu + dev->hard_header_len) { printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len); netif_start_queue (dev); - return 1; + return NETDEV_TX_BUSY; } if (net_debug > 2) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 7a4b9fb..d8c9cf1 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2084,7 +2084,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&sc->sbm_lock, flags); - return 1; + return NETDEV_TX_BUSY; } dev->trans_start = jiffies; diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 0709b75..341882f 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1108,7 +1108,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (!sh_eth_txfree(ndev)) { netif_stop_queue(ndev); spin_unlock_irqrestore(&mdp->lock, flags); - return 1; + return NETDEV_TX_BUSY; } } spin_unlock_irqrestore(&mdp->lock, flags); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 2d4617b..a9a897bb 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1584,7 +1584,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) /* Don't transmit data before the complete of auto-negotiation */ if(!sis_priv->autong_complete){ netif_stop_queue(net_dev); - return 1; + return NETDEV_TX_BUSY; } spin_lock_irqsave(&sis_priv->lock, flags); diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 19d343c4..088fe26 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1082,7 +1082,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) if (bp->QueueSkb == 0) { // return with tbusy set: queue full netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } bp->QueueSkb--; skb_queue_tail(&bp->SendSkbQueue, skb); diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 9a7973a..e02471b 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -503,7 +503,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de /* THIS SHOULD NEVER HAPPEN. */ dev->stats.tx_aborted_errors++; printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); - return 1; + return NETDEV_TX_BUSY; } lp->saved_skb = skb; diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 211e805..e4255d8 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -223,7 +223,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) if (!laddr) { printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); - return 1; + return NETDEV_TX_BUSY } sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index fcb943f..838cce8 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1236,7 +1236,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) */ if ((np->cur_tx - np->dirty_tx) + skb_num_frags(skb) * 2 > TX_RING_SIZE) { netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE) diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index a39c0b9..7bb2742 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -1023,7 +1023,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) #if(NUM_XMIT_BUFFS > 1) if(test_and_set_bit(0,(void *) &p->lock)) { printk("%s: Queue was locked\n",dev->name); - return 1; + return NETDEV_TX_BUSY; } else #endif diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 9bd9dad..534dfe3 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -526,7 +526,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (netif_queue_stopped(dev)) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 20) - return( 1 ); + return NETDEV_TX_BUSY; DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", dev->name, DREG )); @@ -577,7 +577,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { printk( "%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ - return 1; + return NETDEV_TX_BUSY; } AREG = CSR0; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 4e9bd38..4ef72919 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2275,7 +2275,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&hp->happy_lock); printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } entry = hp->tx_new; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index aa69649..384cb5e 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1111,7 +1111,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); priv->txBusyCount++; - return 1; + return NETDEV_TX_BUSY; } tail_list->forward = 0; diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 534c0f3..13dbc59 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1243,7 +1243,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } else { spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - return 1; + return NETDEV_TX_BUSY; } } diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 2e70ee8..b358bbb 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1187,7 +1187,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) } else { netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return 1; + return NETDEV_TX_BUSY; } } diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index d068a9d..c369749 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1055,7 +1055,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } else { spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return 1; + return NETDEV_TX_BUSY; } } diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index a91d9c5..54ad4ed 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -4601,7 +4601,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); if(tp->QueueSkb == 0) - return (1); /* Return with tbusy set: queue full */ + return NETDEV_TX_BUSY; /* Return with tbusy set: queue full */ tp->QueueSkb--; skb_queue_tail(&tp->SendSkbQueue, skb); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index b11bb72..a2eab72 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -633,7 +633,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device if (tms380tr_debug > 0) printk(KERN_DEBUG "%s: No free TPL\n", dev->name); spin_unlock_irqrestore(&tp->lock, flags); - return 1; + return NETDEV_TX_BUSY; } dmabuf = 0; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index e7609a0..81f054d 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -612,7 +612,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) if (tx_free == 0) { netif_stop_queue(dev); spin_unlock_irq(&de->lock); - return 1; + return NETDEV_TX_BUSY; } tx_free--; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 3225617..eb72d2e 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1461,12 +1461,12 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int status = 0; + int status = NETDEV_TX_OK; u_long flags = 0; netif_stop_queue(dev); if (!lp->tx_enable) { /* Cannot send for now */ - return -1; + return NETDEV_TX_LOCKED; } /* @@ -1480,7 +1480,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) /* Test if cache is already locked - requeue skb if so */ if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) - return -1; + return NETDEV_TX_LOCKED; /* Transmit descriptor ring full or stale skb */ if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) { diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index f2e6699..8e78f00 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -686,7 +686,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) spin_unlock_irqrestore(&db->lock, flags); printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt); - return 1; + return NETDEV_TX_BUSY; } /* Disable NIC interrupt */ diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 8761a5a..9277ce8 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -591,7 +591,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt); - return 1; + return NETDEV_TX_BUSY; } /* Disable NIC interrupt */ diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index e8d155c..2fa275a 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -205,15 +205,15 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) { case DLCI_RET_OK: dev->stats.tx_packets++; - ret = 0; + ret = NETDEV_TX_OK; break; case DLCI_RET_ERR: dev->stats.tx_errors++; - ret = 0; + ret = NETDEV_TX_OK; break; case DLCI_RET_DROP: dev->stats.tx_dropped++; - ret = 1; + ret = NETDEV_TX_BUSY; break; } /* Alan Cox recommends always returning 0, and always freeing the packet */ diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index f4211fe..3fb9dbc 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -469,7 +469,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) } } - return 1; + return NETDEV_TX_BUSY; } #else /* CONFIG_SBNI_MULTILINE */ diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 8130b79..e4ad7b6 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -283,7 +283,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) #endif netif_stop_queue(dev); spin_unlock_irq(&port->lock); - return 1; /* request packet to be queued */ + return NETDEV_TX_BUSY; /* request packet to be queued */ } #ifdef DEBUG_PKT diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index dfb30b9..c70604f 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1935,7 +1935,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_stop_queue (dev); if (npacks > MAXTXQ) { dev->stats.tx_fifo_errors++; - return 1; + return NETDEV_TX_BUSY; } skb_queue_tail (&ai->txq, skb); return 0; @@ -2139,7 +2139,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (i == MAX_FIDS / 2) { dev->stats.tx_fifo_errors++; - return 1; + return NETDEV_TX_BUSY; } } /* check min length*/ @@ -2211,7 +2211,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if (i == MAX_FIDS) { dev->stats.tx_fifo_errors++; - return 1; + return NETDEV_TX_BUSY; } } /* check min length*/ diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index a54a67c4..d84caf1 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1199,7 +1199,7 @@ bad_end: arlan_process_interrupt(dev); netif_stop_queue (dev); ARLAN_DEBUG_EXIT("arlan_tx"); - return 1; + return NETDEV_TX_BUSY; } diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 27eef8f..291a94b 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -818,7 +818,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } frame_ctl = IEEE80211_FTYPE_DATA; diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 6693423..d313b00 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -377,7 +377,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; - int ret = 1; + int ret = NETDEV_TX_BUSY; u16 fc; struct hostap_tx_data tx; ap_tx_ret tx_ret; diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index 65a8195..da2ad54 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -539,7 +539,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&ieee->lock, flags); netif_stop_queue(dev); dev->stats.tx_errors++; - return 1; + return NETDEV_TX_BUSY; } EXPORT_SYMBOL(ieee80211_xmit); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 22e7185..b10b038 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -923,7 +923,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(pcmcia_dev_present(link))) { DEBUG(2, "ray_dev_start_xmit - device not present\n"); - return -1; + return NETDEV_TX_LOCKED; } DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); if (local->authentication_state == NEED_TO_AUTH) { @@ -931,7 +931,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) { local->authentication_state = AUTHENTICATED; netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } } @@ -944,7 +944,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) case XMIT_NO_CCS: case XMIT_NEED_AUTH: netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; case XMIT_NO_INTR: case XMIT_MSG_BAD: case XMIT_OK: diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index b7b0c46..38366a5 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1540,7 +1540,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); - return (1); + return NETDEV_TX_BUSY; } netif_stop_queue(dev); diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 25d27b6..ab7fc5c 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2867,7 +2867,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) spin_unlock_irqrestore(&lp->spinlock, flags); /* Check that we can continue */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) - return 1; + return NETDEV_TX_BUSY; } /* Do we need some padding? */ @@ -2880,10 +2880,10 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) skb_copy_from_linear_data(skb, data, skb->len); /* Write packet on the card */ if(wv_packet_write(dev, data, ETH_ZLEN)) - return 1; /* We failed */ + return NETDEV_TX_BUSY; /* We failed */ } else if(wv_packet_write(dev, skb->data, skb->len)) - return 1; /* We failed */ + return NETDEV_TX_BUSY; /* We failed */ dev_kfree_skb(skb); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index be716e4..aec9e5d 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1315,9 +1315,9 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } dev->trans_start = jiffies; - rc = netiucv_transmit_skb(privptr->conn, skb) != 0; + rc = netiucv_transmit_skb(privptr->conn, skb); netiucv_clear_busy(dev); - return rc; + return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK; } /** diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c index 951c73d..59e99cc 100644 --- a/drivers/staging/et131x/et131x_netdev.c +++ b/drivers/staging/et131x/et131x_netdev.c @@ -585,11 +585,11 @@ int et131x_tx(struct sk_buff *skb, struct net_device *netdev) * available */ netif_stop_queue(netdev); - status = 1; + status = NETDEV_TX_BUSY; } else { DBG_WARNING(et131x_dbginfo, "Misc error; drop packet\n"); - status = 0; + status = NETDEV_TX_OK; } } diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 33a0687..1294e05 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -814,7 +814,7 @@ int ieee80211_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&ieee->lock, flags); netif_stop_queue(dev); stats->tx_errors++; - return 1; + return NETDEV_TX_BUSY; } diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 393e4df..bc0d764 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -432,21 +432,21 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, /* success and more buf */ /* avail, re: hw_txdata */ netif_wake_queue(wlandev->netdev); - result = 0; + result = NETDEV_TX_OK; } else if (txresult == 1) { /* success, no more avail */ pr_debug("txframe success, no more bufs\n"); /* netdev->tbusy = 1; don't set here, irqhdlr */ /* may have already cleared it */ - result = 0; + result = NETDEV_TX_OK; } else if (txresult == 2) { /* alloc failure, drop frame */ pr_debug("txframe returned alloc_fail\n"); - result = 1; + result = NETDEV_TX_BUSY; } else { /* buffer full or queue busy, drop frame. */ pr_debug("txframe returned full or busy\n"); - result = 1; + result = NETDEV_TX_BUSY; } failed: diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 4007770..016f63b 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -520,7 +520,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) */ if (list_empty(&dev->tx_reqs)) { spin_unlock_irqrestore(&dev->req_lock, flags); - return 1; + return NETDEV_TX_BUSY; } req = container_of(dev->tx_reqs.next, struct usb_request, list); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 364222b..d238a89 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1615,7 +1615,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - int ret = 1, head_need; + int ret = NETDEV_TX_BUSY, head_need; u16 ethertype, hdrlen, meshhdrlen = 0; __le16 fc; struct ieee80211_hdr hdr; diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 7dcf256..389d6e0 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -137,7 +137,7 @@ static int rose_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); - return 1; + return NETDEV_TX_BUSY; } dev_kfree_skb(skb); stats->tx_errors++; diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index cb1cb1e..9c002b6 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -338,7 +338,7 @@ restart: if (busy) { netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } dev->stats.tx_errors++; -- cgit v0.10.2 From cd6d95d8449b7c9f415f26041e9ae173d387b6bd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Jun 2009 11:29:27 +0200 Subject: clocksource: prevent selection of low resolution clocksourse also for nohz=on commit 3f68535adad (clocksource: sanity check sysfs clocksource changes) prevents selection of non high resolution capable clocksources when high resolution mode is active, but did not take into account that the same rules apply for highres=off nohz=on. Check the tick device mode instead of hrtimer_hres_active() to verify whether the system needs to be protected from a switch to jiffies or other non highres capable clock sources. Reported-by: Luming Yu Signed-off-by: Thomas Gleixner diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 58021b0..0d2f7c8 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -305,7 +305,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) extern ktime_t ktime_get(void); extern ktime_t ktime_get_real(void); -extern int hrtimer_hres_active(void); + DECLARE_PER_CPU(struct tick_device, tick_cpu_device); diff --git a/include/linux/tick.h b/include/linux/tick.h index 469b82d..0482229 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -97,10 +97,12 @@ extern void tick_clock_notify(void); extern int tick_check_oneshot_change(int allow_nohz); extern struct tick_sched *tick_get_tick_sched(int cpu); extern void tick_check_idle(int cpu); +extern int tick_oneshot_mode_active(void); # else static inline void tick_clock_notify(void) { } static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } static inline void tick_check_idle(int cpu) { } +static inline int tick_oneshot_mode_active(void) { return 0; } # endif #else /* CONFIG_GENERIC_CLOCKEVENTS */ @@ -109,6 +111,7 @@ static inline void tick_cancel_sched_timer(int cpu) { } static inline void tick_clock_notify(void) { } static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } static inline void tick_check_idle(int cpu) { } +static inline int tick_oneshot_mode_active(void) { return 0; } #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ # ifdef CONFIG_NO_HZ diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 1a70c18..cb8a15c 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -476,7 +476,7 @@ static inline int hrtimer_is_hres_enabled(void) /* * Is the high resolution mode active ? */ -int hrtimer_hres_active(void) +static inline int hrtimer_hres_active(void) { return __get_cpu_var(hrtimer_bases).hres_active; } @@ -704,7 +704,7 @@ static int hrtimer_switch_to_hres(void) #else -int hrtimer_hres_active(void) { return 0; } +static inline int hrtimer_hres_active(void) { return 0; } static inline int hrtimer_is_hres_enabled(void) { return 0; } static inline int hrtimer_switch_to_hres(void) { return 0; } static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 18b9f5d..592bf58 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -30,7 +30,6 @@ #include #include /* for spin_unlock_irq() using preempt_count() m68k */ #include -#include void timecounter_init(struct timecounter *tc, const struct cyclecounter *cc, @@ -511,13 +510,13 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, } /* - * Check to make sure we don't switch to a non-HRT usable - * clocksource if HRT is enabled and running + * Check to make sure we don't switch to a non-highres capable + * clocksource if the tick code is in oneshot mode (highres or nohz) */ - if (hrtimer_hres_active() && + if (tick_oneshot_mode_active() && !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) { printk(KERN_WARNING "%s clocksource is not HRT compatible. " - "Cannot switch while in HRT mode\n", ovr->name); + "Cannot switch while in HRT/NOHZ mode\n", ovr->name); ovr = NULL; override_name[0] = 0; } @@ -550,9 +549,12 @@ sysfs_show_available_clocksources(struct sys_device *dev, spin_lock_irq(&clocksource_lock); list_for_each_entry(src, &clocksource_list, list) { - /* Don't show non-HRES clocksource if HRES is enabled */ - if (!hrtimer_hres_active() || - (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) + /* + * Don't show non-HRES clocksource if the tick code is + * in one shot mode (highres=on or nohz=on) + */ + if (!tick_oneshot_mode_active() || + (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) count += snprintf(buf + count, max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "%s ", src->name); diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 2e8de67..a96c0e2 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -128,6 +128,23 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) return 0; } +/** + * tick_check_oneshot_mode - check whether the system is in oneshot mode + * + * returns 1 when either nohz or highres are enabled. otherwise 0. + */ +int tick_oneshot_mode_active(void) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + ret = __get_cpu_var(tick_cpu_device).mode == TICKDEV_MODE_ONESHOT; + local_irq_restore(flags); + + return ret; +} + #ifdef CONFIG_HIGH_RES_TIMERS /** * tick_init_highres - switch to high resolution mode -- cgit v0.10.2 From 266d07cb1c9a0c345d7d3aea889f92062894059e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 13 Jun 2009 12:21:10 +0200 Subject: netfilter: nf_log: fix sleeping function called from invalid context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix regression introduced by 17625274 "netfilter: sysctl support of logger choice": BUG: sleeping function called from invalid context at /mnt/s390test/linux-2.6-tip/arch/s390/include/asm/uaccess.h:234 in_atomic(): 1, irqs_disabled(): 0, pid: 3245, name: sysctl CPU: 1 Not tainted 2.6.30-rc8-tipjun10-02053-g39ae214 #1 Process sysctl (pid: 3245, task: 000000007f675da0, ksp: 000000007eb17cf0) 0000000000000000 000000007eb17be8 0000000000000002 0000000000000000 000000007eb17c88 000000007eb17c00 000000007eb17c00 0000000000048156 00000000003e2de8 000000007f676118 000000007eb17f10 0000000000000000 0000000000000000 000000007eb17be8 000000000000000d 000000007eb17c58 00000000003e2050 000000000001635c 000000007eb17be8 000000007eb17c30 Call Trace: (Ý<00000000000162e6>¨ show_trace+0x13a/0x148) Ý<00000000000349ea>¨ __might_sleep+0x13a/0x164 Ý<0000000000050300>¨ proc_dostring+0x134/0x22c Ý<0000000000312b70>¨ nf_log_proc_dostring+0xfc/0x188 Ý<0000000000136f5e>¨ proc_sys_call_handler+0xf6/0x118 Ý<0000000000136fda>¨ proc_sys_read+0x26/0x34 Ý<00000000000d6e9c>¨ vfs_read+0xac/0x158 Ý<00000000000d703e>¨ SyS_read+0x56/0x88 Ý<0000000000027f42>¨ sysc_noemu+0x10/0x16 Use the nf_log_mutex instead of RCU to fix this. Reported-and-tested-by: Maran Pakkirisamy Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index beb3731..2fefe14 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -248,14 +248,14 @@ static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, rcu_assign_pointer(nf_loggers[tindex], logger); mutex_unlock(&nf_log_mutex); } else { - rcu_read_lock(); - logger = rcu_dereference(nf_loggers[tindex]); + mutex_lock(&nf_log_mutex); + logger = nf_loggers[tindex]; if (!logger) table->data = "NONE"; else table->data = logger->name; r = proc_dostring(table, write, filp, buffer, lenp, ppos); - rcu_read_unlock(); + mutex_unlock(&nf_log_mutex); } return r; -- cgit v0.10.2 From 65cb9fda32be613216f601a330b311c3bd7a8436 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 13 Jun 2009 12:21:49 +0200 Subject: netfilter: nf_conntrack: use mod_timer_pending() for conntrack refresh Use mod_timer_pending() instead of atomic sequence of del_timer()/ add_timer(). mod_timer_pending() does not rearm an inactive timer, so we don't need the conntrack lock anymore to make sure we don't accidentally rearm a timer of a conntrack which is in the process of being destroyed. With this change, we don't need to take the global lock anymore at all, counter updates can be performed under the per-conntrack lock. Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index edf9569..d8dffe7 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -807,8 +807,6 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); NF_CT_ASSERT(skb); - spin_lock_bh(&nf_conntrack_lock); - /* Only update if this is not a fixed timeout */ if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) goto acct; @@ -822,11 +820,8 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, /* Only update the timeout if the new timeout is at least HZ jiffies from the old timeout. Need del_timer for race avoidance (may already be dying). */ - if (newtime - ct->timeout.expires >= HZ - && del_timer(&ct->timeout)) { - ct->timeout.expires = newtime; - add_timer(&ct->timeout); - } + if (newtime - ct->timeout.expires >= HZ) + mod_timer_pending(&ct->timeout, newtime); } acct: @@ -835,13 +830,13 @@ acct: acct = nf_conn_acct_find(ct); if (acct) { + spin_lock_bh(&ct->lock); acct[CTINFO2DIR(ctinfo)].packets++; acct[CTINFO2DIR(ctinfo)].bytes += skb->len - skb_network_offset(skb); + spin_unlock_bh(&ct->lock); } } - - spin_unlock_bh(&nf_conntrack_lock); } EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); @@ -853,14 +848,14 @@ bool __nf_ct_kill_acct(struct nf_conn *ct, if (do_acct) { struct nf_conn_counter *acct; - spin_lock_bh(&nf_conntrack_lock); acct = nf_conn_acct_find(ct); if (acct) { + spin_lock_bh(&ct->lock); acct[CTINFO2DIR(ctinfo)].packets++; acct[CTINFO2DIR(ctinfo)].bytes += skb->len - skb_network_offset(skb); + spin_unlock_bh(&ct->lock); } - spin_unlock_bh(&nf_conntrack_lock); } if (del_timer(&ct->timeout)) { -- cgit v0.10.2 From a0891aa6a635f658f29bb061a00d6d3486941519 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Jun 2009 12:26:29 +0200 Subject: netfilter: conntrack: move event caching to conntrack extension infrastructure This patch reworks the per-cpu event caching to use the conntrack extension infrastructure. The main drawback is that we consume more memory per conntrack if event delivery is enabled. This patch is required by the reliable event delivery that follows to this patch. BTW, this patch allows you to enable/disable event delivery via /proc/sys/net/netfilter/nf_conntrack_events in runtime, although you can still disable event caching as compilation option. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 1afb907..e7ae297 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -6,61 +6,52 @@ #define _NF_CONNTRACK_ECACHE_H #include -#include #include #include +#include +#include +#include -/* Connection tracking event bits */ +/* Connection tracking event types */ enum ip_conntrack_events { - /* New conntrack */ - IPCT_NEW_BIT = 0, - IPCT_NEW = (1 << IPCT_NEW_BIT), - - /* Expected connection */ - IPCT_RELATED_BIT = 1, - IPCT_RELATED = (1 << IPCT_RELATED_BIT), - - /* Destroyed conntrack */ - IPCT_DESTROY_BIT = 2, - IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), - - /* Status has changed */ - IPCT_STATUS_BIT = 3, - IPCT_STATUS = (1 << IPCT_STATUS_BIT), + IPCT_NEW = 0, /* new conntrack */ + IPCT_RELATED = 1, /* related conntrack */ + IPCT_DESTROY = 2, /* destroyed conntrack */ + IPCT_STATUS = 3, /* status has changed */ + IPCT_PROTOINFO = 4, /* protocol information has changed */ + IPCT_HELPER = 5, /* new helper has been set */ + IPCT_MARK = 6, /* new mark has been set */ + IPCT_NATSEQADJ = 7, /* NAT is doing sequence adjustment */ + IPCT_SECMARK = 8, /* new security mark has been set */ +}; - /* Update of protocol info */ - IPCT_PROTOINFO_BIT = 4, - IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), +enum ip_conntrack_expect_events { + IPEXP_NEW = 0, /* new expectation */ +}; - /* New helper for conntrack */ - IPCT_HELPER_BIT = 5, - IPCT_HELPER = (1 << IPCT_HELPER_BIT), +struct nf_conntrack_ecache { + unsigned long cache; /* bitops want long */ +}; - /* Mark is set */ - IPCT_MARK_BIT = 6, - IPCT_MARK = (1 << IPCT_MARK_BIT), +static inline struct nf_conntrack_ecache * +nf_ct_ecache_find(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE); +} - /* NAT sequence adjustment */ - IPCT_NATSEQADJ_BIT = 7, - IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), +static inline struct nf_conntrack_ecache * +nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp) +{ + struct net *net = nf_ct_net(ct); - /* Secmark is set */ - IPCT_SECMARK_BIT = 8, - IPCT_SECMARK = (1 << IPCT_SECMARK_BIT), -}; + if (!net->ct.sysctl_events) + return NULL; -enum ip_conntrack_expect_events { - IPEXP_NEW_BIT = 0, - IPEXP_NEW = (1 << IPEXP_NEW_BIT), + return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); }; #ifdef CONFIG_NF_CONNTRACK_EVENTS -struct nf_conntrack_ecache { - struct nf_conn *ct; - unsigned int events; -}; - /* This structure is passed to event handler */ struct nf_ct_event { struct nf_conn *ct; @@ -76,30 +67,30 @@ extern struct nf_ct_event_notifier *nf_conntrack_event_cb; extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); -extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); -extern void __nf_ct_event_cache_init(struct nf_conn *ct); -extern void nf_ct_event_cache_flush(struct net *net); +extern void nf_ct_deliver_cached_events(struct nf_conn *ct); static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) { - struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *ecache; - - local_bh_disable(); - ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); - if (ct != ecache->ct) - __nf_ct_event_cache_init(ct); - ecache->events |= event; - local_bh_enable(); + struct nf_conntrack_ecache *e; + + if (nf_conntrack_event_cb == NULL) + return; + + e = nf_ct_ecache_find(ct); + if (e == NULL) + return; + + set_bit(event, &e->cache); } static inline void -nf_conntrack_event_report(enum ip_conntrack_events event, - struct nf_conn *ct, - u32 pid, - int report) +nf_conntrack_eventmask_report(unsigned int eventmask, + struct nf_conn *ct, + u32 pid, + int report) { + struct net *net = nf_ct_net(ct); struct nf_ct_event_notifier *notify; rcu_read_lock(); @@ -107,22 +98,32 @@ nf_conntrack_event_report(enum ip_conntrack_events event, if (notify == NULL) goto out_unlock; + if (!net->ct.sysctl_events) + goto out_unlock; + if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { struct nf_ct_event item = { .ct = ct, .pid = pid, .report = report }; - notify->fcn(event, &item); + notify->fcn(eventmask, &item); } out_unlock: rcu_read_unlock(); } static inline void +nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, + u32 pid, int report) +{ + nf_conntrack_eventmask_report(1 << event, ct, pid, report); +} + +static inline void nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) { - nf_conntrack_event_report(event, ct, 0, 0); + nf_conntrack_eventmask_report(1 << event, ct, 0, 0); } struct nf_exp_event { @@ -145,6 +146,7 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, u32 pid, int report) { + struct net *net = nf_ct_exp_net(exp); struct nf_exp_event_notifier *notify; rcu_read_lock(); @@ -152,13 +154,16 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, if (notify == NULL) goto out_unlock; + if (!net->ct.sysctl_events) + goto out_unlock; + { struct nf_exp_event item = { .exp = exp, .pid = pid, .report = report }; - notify->fcn(event, &item); + notify->fcn(1 << event, &item); } out_unlock: rcu_read_unlock(); @@ -178,6 +183,10 @@ extern void nf_conntrack_ecache_fini(struct net *net); static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) {} +static inline void nf_conntrack_eventmask_report(unsigned int eventmask, + struct nf_conn *ct, + u32 pid, + int report) {} static inline void nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) {} static inline void nf_conntrack_event_report(enum ip_conntrack_events event, @@ -191,7 +200,6 @@ static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, struct nf_conntrack_expect *exp, u32 pid, int report) {} -static inline void nf_ct_event_cache_flush(struct net *net) {} static inline int nf_conntrack_ecache_init(struct net *net) { diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h index da8ee52..7f8fc5d 100644 --- a/include/net/netfilter/nf_conntrack_extend.h +++ b/include/net/netfilter/nf_conntrack_extend.h @@ -8,12 +8,14 @@ enum nf_ct_ext_id NF_CT_EXT_HELPER, NF_CT_EXT_NAT, NF_CT_EXT_ACCT, + NF_CT_EXT_ECACHE, NF_CT_EXT_NUM, }; #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat #define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter +#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache /* Extensions: optional stuff which isn't permanently in struct. */ struct nf_ct_ext { diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index 9dc5840..505a51c 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -15,15 +15,14 @@ struct netns_ct { struct hlist_head *expect_hash; struct hlist_nulls_head unconfirmed; struct ip_conntrack_stat *stat; -#ifdef CONFIG_NF_CONNTRACK_EVENTS - struct nf_conntrack_ecache *ecache; -#endif + int sysctl_events; int sysctl_acct; int sysctl_checksum; unsigned int sysctl_log_invalid; /* Log invalid packets */ #ifdef CONFIG_SYSCTL struct ctl_table_header *sysctl_header; struct ctl_table_header *acct_sysctl_header; + struct ctl_table_header *event_sysctl_header; #endif int hash_vmalloc; int expect_vmalloc; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index d8dffe7..bcacbb5 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -577,6 +578,7 @@ init_conntrack(struct net *net, } nf_ct_acct_ext_add(ct, GFP_ATOMIC); + nf_ct_ecache_ext_add(ct, GFP_ATOMIC); spin_lock_bh(&nf_conntrack_lock); exp = nf_ct_find_expectation(net, tuple); @@ -1031,8 +1033,6 @@ static void nf_conntrack_cleanup_init_net(void) static void nf_conntrack_cleanup_net(struct net *net) { - nf_ct_event_cache_flush(net); - nf_conntrack_ecache_fini(net); i_see_dead_people: nf_ct_iterate_cleanup(net, kill_all, NULL); if (atomic_read(&net->ct.count) != 0) { @@ -1045,6 +1045,7 @@ static void nf_conntrack_cleanup_net(struct net *net) nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, nf_conntrack_htable_size); + nf_conntrack_ecache_fini(net); nf_conntrack_acct_fini(net); nf_conntrack_expect_fini(net); free_percpu(net->ct.stat); @@ -1220,9 +1221,6 @@ static int nf_conntrack_init_net(struct net *net) ret = -ENOMEM; goto err_stat; } - ret = nf_conntrack_ecache_init(net); - if (ret < 0) - goto err_ecache; net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, &net->ct.hash_vmalloc, 1); if (!net->ct.hash) { @@ -1236,6 +1234,9 @@ static int nf_conntrack_init_net(struct net *net) ret = nf_conntrack_acct_init(net); if (ret < 0) goto err_acct; + ret = nf_conntrack_ecache_init(net); + if (ret < 0) + goto err_ecache; /* Set up fake conntrack: - to never be deleted, not in any hashes */ @@ -1248,14 +1249,14 @@ static int nf_conntrack_init_net(struct net *net) return 0; +err_ecache: + nf_conntrack_acct_fini(net); err_acct: nf_conntrack_expect_fini(net); err_expect: nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, nf_conntrack_htable_size); err_hash: - nf_conntrack_ecache_fini(net); -err_ecache: free_percpu(net->ct.stat); err_stat: return ret; diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index 5516b3e..683281b 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -21,6 +21,7 @@ #include #include +#include static DEFINE_MUTEX(nf_ct_ecache_mutex); @@ -32,94 +33,38 @@ EXPORT_SYMBOL_GPL(nf_expect_event_cb); /* deliver cached events and clear cache entry - must be called with locally * disabled softirqs */ -static inline void -__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) +void nf_ct_deliver_cached_events(struct nf_conn *ct) { + unsigned long events; struct nf_ct_event_notifier *notify; + struct nf_conntrack_ecache *e; rcu_read_lock(); notify = rcu_dereference(nf_conntrack_event_cb); if (notify == NULL) goto out_unlock; - if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) - && ecache->events) { + e = nf_ct_ecache_find(ct); + if (e == NULL) + goto out_unlock; + + events = xchg(&e->cache, 0); + + if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) { struct nf_ct_event item = { - .ct = ecache->ct, + .ct = ct, .pid = 0, .report = 0 }; - notify->fcn(ecache->events, &item); + notify->fcn(events, &item); } - ecache->events = 0; - nf_ct_put(ecache->ct); - ecache->ct = NULL; - out_unlock: rcu_read_unlock(); } - -/* Deliver all cached events for a particular conntrack. This is called - * by code prior to async packet handling for freeing the skb */ -void nf_ct_deliver_cached_events(const struct nf_conn *ct) -{ - struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *ecache; - - local_bh_disable(); - ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); - if (ecache->ct == ct) - __nf_ct_deliver_cached_events(ecache); - local_bh_enable(); -} EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); -/* Deliver cached events for old pending events, if current conntrack != old */ -void __nf_ct_event_cache_init(struct nf_conn *ct) -{ - struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *ecache; - - /* take care of delivering potentially old events */ - ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); - BUG_ON(ecache->ct == ct); - if (ecache->ct) - __nf_ct_deliver_cached_events(ecache); - /* initialize for this conntrack/packet */ - ecache->ct = ct; - nf_conntrack_get(&ct->ct_general); -} -EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init); - -/* flush the event cache - touches other CPU's data and must not be called - * while packets are still passing through the code */ -void nf_ct_event_cache_flush(struct net *net) -{ - struct nf_conntrack_ecache *ecache; - int cpu; - - for_each_possible_cpu(cpu) { - ecache = per_cpu_ptr(net->ct.ecache, cpu); - if (ecache->ct) - nf_ct_put(ecache->ct); - } -} - -int nf_conntrack_ecache_init(struct net *net) -{ - net->ct.ecache = alloc_percpu(struct nf_conntrack_ecache); - if (!net->ct.ecache) - return -ENOMEM; - return 0; -} - -void nf_conntrack_ecache_fini(struct net *net) -{ - free_percpu(net->ct.ecache); -} - int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) { int ret = 0; @@ -185,3 +130,107 @@ void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new) mutex_unlock(&nf_ct_ecache_mutex); } EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); + +#define NF_CT_EVENTS_DEFAULT 1 +static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; + +#ifdef CONFIG_SYSCTL +static struct ctl_table event_sysctl_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_events", + .data = &init_net.ct.sysctl_events, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + {} +}; +#endif /* CONFIG_SYSCTL */ + +static struct nf_ct_ext_type event_extend __read_mostly = { + .len = sizeof(struct nf_conntrack_ecache), + .align = __alignof__(struct nf_conntrack_ecache), + .id = NF_CT_EXT_ECACHE, +}; + +#ifdef CONFIG_SYSCTL +static int nf_conntrack_event_init_sysctl(struct net *net) +{ + struct ctl_table *table; + + table = kmemdup(event_sysctl_table, sizeof(event_sysctl_table), + GFP_KERNEL); + if (!table) + goto out; + + table[0].data = &net->ct.sysctl_events; + + net->ct.event_sysctl_header = + register_net_sysctl_table(net, + nf_net_netfilter_sysctl_path, table); + if (!net->ct.event_sysctl_header) { + printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n"); + goto out_register; + } + return 0; + +out_register: + kfree(table); +out: + return -ENOMEM; +} + +static void nf_conntrack_event_fini_sysctl(struct net *net) +{ + struct ctl_table *table; + + table = net->ct.event_sysctl_header->ctl_table_arg; + unregister_net_sysctl_table(net->ct.event_sysctl_header); + kfree(table); +} +#else +static int nf_conntrack_event_init_sysctl(struct net *net) +{ + return 0; +} + +static void nf_conntrack_event_fini_sysctl(struct net *net) +{ +} +#endif /* CONFIG_SYSCTL */ + +int nf_conntrack_ecache_init(struct net *net) +{ + int ret; + + net->ct.sysctl_events = nf_ct_events; + + if (net_eq(net, &init_net)) { + ret = nf_ct_extend_register(&event_extend); + if (ret < 0) { + printk(KERN_ERR "nf_ct_event: Unable to register " + "event extension.\n"); + goto out_extend_register; + } + } + + ret = nf_conntrack_event_init_sysctl(net); + if (ret < 0) + goto out_sysctl; + + return 0; + +out_sysctl: + if (net_eq(net, &init_net)) + nf_ct_extend_unregister(&event_extend); +out_extend_register: + return ret; +} + +void nf_conntrack_ecache_fini(struct net *net) +{ + nf_conntrack_event_fini_sysctl(net); + if (net_eq(net, &init_net)) + nf_ct_extend_unregister(&event_extend); +} diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 4e503ad..19706ef 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -468,10 +468,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) if (ct == &nf_conntrack_untracked) return 0; - if (events & IPCT_DESTROY) { + if (events & (1 << IPCT_DESTROY)) { type = IPCTNL_MSG_CT_DELETE; group = NFNLGRP_CONNTRACK_DESTROY; - } else if (events & (IPCT_NEW | IPCT_RELATED)) { + } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) { type = IPCTNL_MSG_CT_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; group = NFNLGRP_CONNTRACK_NEW; @@ -519,7 +519,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) if (ctnetlink_dump_status(skb, ct) < 0) goto nla_put_failure; - if (events & IPCT_DESTROY) { + if (events & (1 << IPCT_DESTROY)) { if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) goto nla_put_failure; @@ -527,31 +527,31 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) if (ctnetlink_dump_timeout(skb, ct) < 0) goto nla_put_failure; - if (events & IPCT_PROTOINFO + if (events & (1 << IPCT_PROTOINFO) && ctnetlink_dump_protoinfo(skb, ct) < 0) goto nla_put_failure; - if ((events & IPCT_HELPER || nfct_help(ct)) + if ((events & (1 << IPCT_HELPER) || nfct_help(ct)) && ctnetlink_dump_helpinfo(skb, ct) < 0) goto nla_put_failure; #ifdef CONFIG_NF_CONNTRACK_SECMARK - if ((events & IPCT_SECMARK || ct->secmark) + if ((events & (1 << IPCT_SECMARK) || ct->secmark) && ctnetlink_dump_secmark(skb, ct) < 0) goto nla_put_failure; #endif - if (events & IPCT_RELATED && + if (events & (1 << IPCT_RELATED) && ctnetlink_dump_master(skb, ct) < 0) goto nla_put_failure; - if (events & IPCT_NATSEQADJ && + if (events & (1 << IPCT_NATSEQADJ) && ctnetlink_dump_nat_seq_adj(skb, ct) < 0) goto nla_put_failure; } #ifdef CONFIG_NF_CONNTRACK_MARK - if ((events & IPCT_MARK || ct->mark) + if ((events & (1 << IPCT_MARK) || ct->mark) && ctnetlink_dump_mark(skb, ct) < 0) goto nla_put_failure; #endif @@ -1253,6 +1253,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[], } nf_ct_acct_ext_add(ct, GFP_ATOMIC); + nf_ct_ecache_ext_add(ct, GFP_ATOMIC); #if defined(CONFIG_NF_CONNTRACK_MARK) if (cda[CTA_MARK]) @@ -1340,13 +1341,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, else events = IPCT_NEW; - nf_conntrack_event_report(IPCT_STATUS | - IPCT_HELPER | - IPCT_PROTOINFO | - IPCT_NATSEQADJ | - IPCT_MARK | events, - ct, NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_eventmask_report((1 << IPCT_STATUS) | + (1 << IPCT_HELPER) | + (1 << IPCT_PROTOINFO) | + (1 << IPCT_NATSEQADJ) | + (1 << IPCT_MARK) | events, + ct, NETLINK_CB(skb).pid, + nlmsg_report(nlh)); nf_ct_put(ct); } else spin_unlock_bh(&nf_conntrack_lock); @@ -1365,13 +1366,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err == 0) { nf_conntrack_get(&ct->ct_general); spin_unlock_bh(&nf_conntrack_lock); - nf_conntrack_event_report(IPCT_STATUS | - IPCT_HELPER | - IPCT_PROTOINFO | - IPCT_NATSEQADJ | - IPCT_MARK, - ct, NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_eventmask_report((1 << IPCT_STATUS) | + (1 << IPCT_HELPER) | + (1 << IPCT_PROTOINFO) | + (1 << IPCT_NATSEQADJ) | + (1 << IPCT_MARK), + ct, NETLINK_CB(skb).pid, + nlmsg_report(nlh)); nf_ct_put(ct); } else spin_unlock_bh(&nf_conntrack_lock); @@ -1515,7 +1516,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) unsigned int type; int flags = 0; - if (events & IPEXP_NEW) { + if (events & (1 << IPEXP_NEW)) { type = IPCTNL_MSG_EXP_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; } else -- cgit v0.10.2 From 9858a3ae1d4b390fbaa9c30b83cb66d861b76294 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Jun 2009 12:28:22 +0200 Subject: netfilter: conntrack: move helper destruction to nf_ct_helper_destroy() This patch moves the helper destruction to a function that lives in nf_conntrack_helper.c. This new function is used in the patch to add ctnetlink reliable event delivery. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index ee2a4b3..1b70680 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -50,6 +50,8 @@ extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags); +extern void nf_ct_helper_destroy(struct nf_conn *ct); + static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) { return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index bcacbb5..14235b1 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -224,17 +224,8 @@ static void death_by_timeout(unsigned long ul_conntrack) { struct nf_conn *ct = (void *)ul_conntrack; struct net *net = nf_ct_net(ct); - struct nf_conn_help *help = nfct_help(ct); - struct nf_conntrack_helper *helper; - - if (help) { - rcu_read_lock(); - helper = rcu_dereference(help->helper); - if (helper && helper->destroy) - helper->destroy(ct); - rcu_read_unlock(); - } + nf_ct_helper_destroy(ct); spin_lock_bh(&nf_conntrack_lock); /* Inside lock so preempt is disabled on module removal path. * Otherwise we can get spurious warnings. */ diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 0fa5a42..65c2a7b 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -136,6 +136,20 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i, return 0; } +void nf_ct_helper_destroy(struct nf_conn *ct) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_helper *helper; + + if (help) { + rcu_read_lock(); + helper = rcu_dereference(help->helper); + if (helper && helper->destroy) + helper->destroy(ct); + rcu_read_unlock(); + } +} + int nf_conntrack_helper_register(struct nf_conntrack_helper *me) { unsigned int h = helper_hash(&me->tuple); -- cgit v0.10.2 From d219dce76c64f2c883dad0537fa09a56d5ff0a10 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Jun 2009 12:28:57 +0200 Subject: list_nulls: add hlist_nulls_add_head and hlist_nulls_del This patch adds the hlist_nulls_add_head() function which is based on hlist_nulls_add_head_rcu() but without the use of rcu_assign_pointer(). It also adds hlist_nulls_del which is exactly the same like hlist_nulls_del_rcu(). Signed-off-by: Pablo Neira Ayuso Acked-by: Eric Dumazet Signed-off-by: Patrick McHardy diff --git a/include/linux/list_nulls.h b/include/linux/list_nulls.h index 93150ec..5d10ae3 100644 --- a/include/linux/list_nulls.h +++ b/include/linux/list_nulls.h @@ -56,6 +56,18 @@ static inline int hlist_nulls_empty(const struct hlist_nulls_head *h) return is_a_nulls(h->first); } +static inline void hlist_nulls_add_head(struct hlist_nulls_node *n, + struct hlist_nulls_head *h) +{ + struct hlist_nulls_node *first = h->first; + + n->next = first; + n->pprev = &h->first; + h->first = n; + if (!is_a_nulls(first)) + first->pprev = &n->next; +} + static inline void __hlist_nulls_del(struct hlist_nulls_node *n) { struct hlist_nulls_node *next = n->next; @@ -65,6 +77,12 @@ static inline void __hlist_nulls_del(struct hlist_nulls_node *n) next->pprev = pprev; } +static inline void hlist_nulls_del(struct hlist_nulls_node *n) +{ + __hlist_nulls_del(n); + n->pprev = LIST_POISON2; +} + /** * hlist_nulls_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop cursor. -- cgit v0.10.2 From dd7669a92c6066b2b31bae7e04cd787092920883 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Jun 2009 12:30:52 +0200 Subject: netfilter: conntrack: optional reliable conntrack event delivery This patch improves ctnetlink event reliability if one broadcast listener has set the NETLINK_BROADCAST_ERROR socket option. The logic is the following: if an event delivery fails, we keep the undelivered events in the missed event cache. Once the next packet arrives, we add the new events (if any) to the missed events in the cache and we try a new delivery, and so on. Thus, if ctnetlink fails to deliver an event, we try to deliver them once we see a new packet. Therefore, we may lose state transitions but the userspace process gets in sync at some point. At worst case, if no events were delivered to userspace, we make sure that destroy events are successfully delivered. Basically, if ctnetlink fails to deliver the destroy event, we remove the conntrack entry from the hashes and we insert them in the dying list, which contains inactive entries. Then, the conntrack timer is added with an extra grace timeout of random32() % 15 seconds to trigger the event again (this grace timeout is tunable via /proc). The use of a limited random timeout value allows distributing the "destroy" resends, thus, avoiding accumulating lots "destroy" events at the same time. Event delivery may re-order but we can identify them by means of the tuple plus the conntrack ID. The maximum number of conntrack entries (active or inactive) is still handled by nf_conntrack_max. Thus, we may start dropping packets at some point if we accumulate a lot of inactive conntrack entries that did not successfully report the destroy event to userspace. During my stress tests consisting of setting a very small buffer of 2048 bytes for conntrackd and the NETLINK_BROADCAST_ERROR socket flag, and generating lots of very small connections, I noticed very few destroy entries on the fly waiting to be resend. A simple way to test this patch consist of creating a lot of entries, set a very small Netlink buffer in conntrackd (+ a patch which is not in the git tree to set the BROADCAST_ERROR flag) and invoke `conntrack -F'. For expectations, no changes are introduced in this patch. Currently, event delivery is only done for new expectations (no events from expectation expiration, removal and confirmation). In that case, they need a per-expectation event cache to implement the same idea that is exposed in this patch. This patch can be useful to provide reliable flow-accouting. We still have to add a new conntrack extension to store the creation and destroy time. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index ecc79f9..a632689 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -201,6 +201,8 @@ extern struct nf_conntrack_tuple_hash * __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); extern void nf_conntrack_hash_insert(struct nf_conn *ct); +extern void nf_ct_delete_from_lists(struct nf_conn *ct); +extern void nf_ct_insert_dying_list(struct nf_conn *ct); extern void nf_conntrack_flush_report(struct net *net, u32 pid, int report); diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index e7ae297..4f20d58 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -32,6 +32,8 @@ enum ip_conntrack_expect_events { struct nf_conntrack_ecache { unsigned long cache; /* bitops want long */ + unsigned long missed; /* missed events */ + u32 pid; /* netlink pid of destroyer */ }; static inline struct nf_conntrack_ecache * @@ -84,14 +86,16 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) set_bit(event, &e->cache); } -static inline void +static inline int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, u32 pid, int report) { + int ret = 0; struct net *net = nf_ct_net(ct); struct nf_ct_event_notifier *notify; + struct nf_conntrack_ecache *e; rcu_read_lock(); notify = rcu_dereference(nf_conntrack_event_cb); @@ -101,29 +105,52 @@ nf_conntrack_eventmask_report(unsigned int eventmask, if (!net->ct.sysctl_events) goto out_unlock; + e = nf_ct_ecache_find(ct); + if (e == NULL) + goto out_unlock; + if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { struct nf_ct_event item = { .ct = ct, - .pid = pid, + .pid = e->pid ? e->pid : pid, .report = report }; - notify->fcn(eventmask, &item); + /* This is a resent of a destroy event? If so, skip missed */ + unsigned long missed = e->pid ? 0 : e->missed; + + ret = notify->fcn(eventmask | missed, &item); + if (unlikely(ret < 0 || missed)) { + spin_lock_bh(&ct->lock); + if (ret < 0) { + /* This is a destroy event that has been + * triggered by a process, we store the PID + * to include it in the retransmission. */ + if (eventmask & (1 << IPCT_DESTROY) && + e->pid == 0 && pid != 0) + e->pid = pid; + else + e->missed |= eventmask; + } else + e->missed &= ~missed; + spin_unlock_bh(&ct->lock); + } } out_unlock: rcu_read_unlock(); + return ret; } -static inline void +static inline int nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, u32 pid, int report) { - nf_conntrack_eventmask_report(1 << event, ct, pid, report); + return nf_conntrack_eventmask_report(1 << event, ct, pid, report); } -static inline void +static inline int nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) { - nf_conntrack_eventmask_report(1 << event, ct, 0, 0); + return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); } struct nf_exp_event { @@ -183,16 +210,16 @@ extern void nf_conntrack_ecache_fini(struct net *net); static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) {} -static inline void nf_conntrack_eventmask_report(unsigned int eventmask, - struct nf_conn *ct, - u32 pid, - int report) {} -static inline void nf_conntrack_event(enum ip_conntrack_events event, - struct nf_conn *ct) {} -static inline void nf_conntrack_event_report(enum ip_conntrack_events event, - struct nf_conn *ct, - u32 pid, - int report) {} +static inline int nf_conntrack_eventmask_report(unsigned int eventmask, + struct nf_conn *ct, + u32 pid, + int report) { return 0; } +static inline int nf_conntrack_event(enum ip_conntrack_events event, + struct nf_conn *ct) { return 0; } +static inline int nf_conntrack_event_report(enum ip_conntrack_events event, + struct nf_conn *ct, + u32 pid, + int report) { return 0; } static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, struct nf_conntrack_expect *exp) {} diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index 505a51c..ba1ba0c 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -14,8 +14,10 @@ struct netns_ct { struct hlist_nulls_head *hash; struct hlist_head *expect_hash; struct hlist_nulls_head unconfirmed; + struct hlist_nulls_head dying; struct ip_conntrack_stat *stat; int sysctl_events; + unsigned int sysctl_events_retry_timeout; int sysctl_acct; int sysctl_checksum; unsigned int sysctl_log_invalid; /* Log invalid packets */ diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 14235b1..5f72b94 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -183,10 +183,6 @@ destroy_conntrack(struct nf_conntrack *nfct) NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); - if (!test_bit(IPS_DYING_BIT, &ct->status)) - nf_conntrack_event(IPCT_DESTROY, ct); - set_bit(IPS_DYING_BIT, &ct->status); - /* To make sure we don't get any weird locking issues here: * destroy_conntrack() MUST NOT be called with a write lock * to nf_conntrack_lock!!! -HW */ @@ -220,9 +216,8 @@ destroy_conntrack(struct nf_conntrack *nfct) nf_conntrack_free(ct); } -static void death_by_timeout(unsigned long ul_conntrack) +void nf_ct_delete_from_lists(struct nf_conn *ct) { - struct nf_conn *ct = (void *)ul_conntrack; struct net *net = nf_ct_net(ct); nf_ct_helper_destroy(ct); @@ -232,6 +227,59 @@ static void death_by_timeout(unsigned long ul_conntrack) NF_CT_STAT_INC(net, delete_list); clean_from_lists(ct); spin_unlock_bh(&nf_conntrack_lock); +} +EXPORT_SYMBOL_GPL(nf_ct_delete_from_lists); + +static void death_by_event(unsigned long ul_conntrack) +{ + struct nf_conn *ct = (void *)ul_conntrack; + struct net *net = nf_ct_net(ct); + + if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { + /* bad luck, let's retry again */ + ct->timeout.expires = jiffies + + (random32() % net->ct.sysctl_events_retry_timeout); + add_timer(&ct->timeout); + return; + } + /* we've got the event delivered, now it's dying */ + set_bit(IPS_DYING_BIT, &ct->status); + spin_lock(&nf_conntrack_lock); + hlist_nulls_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); + spin_unlock(&nf_conntrack_lock); + nf_ct_put(ct); +} + +void nf_ct_insert_dying_list(struct nf_conn *ct) +{ + struct net *net = nf_ct_net(ct); + + /* add this conntrack to the dying list */ + spin_lock_bh(&nf_conntrack_lock); + hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, + &net->ct.dying); + spin_unlock_bh(&nf_conntrack_lock); + /* set a new timer to retry event delivery */ + setup_timer(&ct->timeout, death_by_event, (unsigned long)ct); + ct->timeout.expires = jiffies + + (random32() % net->ct.sysctl_events_retry_timeout); + add_timer(&ct->timeout); +} +EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); + +static void death_by_timeout(unsigned long ul_conntrack) +{ + struct nf_conn *ct = (void *)ul_conntrack; + + if (!test_bit(IPS_DYING_BIT, &ct->status) && + unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) { + /* destroy event was not delivered */ + nf_ct_delete_from_lists(ct); + nf_ct_insert_dying_list(ct); + return; + } + set_bit(IPS_DYING_BIT, &ct->status); + nf_ct_delete_from_lists(ct); nf_ct_put(ct); } @@ -982,11 +1030,13 @@ static int kill_report(struct nf_conn *i, void *data) { struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data; - /* get_next_corpse sets the dying bit for us */ - nf_conntrack_event_report(IPCT_DESTROY, - i, - fr->pid, - fr->report); + /* If we fail to deliver the event, death_by_timeout() will retry */ + if (nf_conntrack_event_report(IPCT_DESTROY, i, + fr->pid, fr->report) < 0) + return 1; + + /* Avoid the delivery of the destroy event in death_by_timeout(). */ + set_bit(IPS_DYING_BIT, &i->status); return 1; } @@ -1015,6 +1065,21 @@ void nf_conntrack_flush_report(struct net *net, u32 pid, int report) } EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); +static void nf_ct_release_dying_list(void) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conn *ct; + struct hlist_nulls_node *n; + + spin_lock_bh(&nf_conntrack_lock); + hlist_nulls_for_each_entry(h, n, &init_net.ct.dying, hnnode) { + ct = nf_ct_tuplehash_to_ctrack(h); + /* never fails to remove them, no listeners at this point */ + nf_ct_kill(ct); + } + spin_unlock_bh(&nf_conntrack_lock); +} + static void nf_conntrack_cleanup_init_net(void) { nf_conntrack_helper_fini(); @@ -1026,6 +1091,7 @@ static void nf_conntrack_cleanup_net(struct net *net) { i_see_dead_people: nf_ct_iterate_cleanup(net, kill_all, NULL); + nf_ct_release_dying_list(); if (atomic_read(&net->ct.count) != 0) { schedule(); goto i_see_dead_people; @@ -1207,6 +1273,7 @@ static int nf_conntrack_init_net(struct net *net) atomic_set(&net->ct.count, 0); INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); + INIT_HLIST_NULLS_HEAD(&net->ct.dying, 0); net->ct.stat = alloc_percpu(struct ip_conntrack_stat); if (!net->ct.stat) { ret = -ENOMEM; diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index 683281b..aee560b 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -56,8 +56,21 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct) .pid = 0, .report = 0 }; - - notify->fcn(events, &item); + int ret; + /* We make a copy of the missed event cache without taking + * the lock, thus we may send missed events twice. However, + * this does not harm and it happens very rarely. */ + unsigned long missed = e->missed; + + ret = notify->fcn(events | missed, &item); + if (unlikely(ret < 0 || missed)) { + spin_lock_bh(&ct->lock); + if (ret < 0) + e->missed |= events; + else + e->missed &= ~missed; + spin_unlock_bh(&ct->lock); + } } out_unlock: @@ -133,6 +146,7 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); #define NF_CT_EVENTS_DEFAULT 1 static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; +static int nf_ct_events_retry_timeout __read_mostly = 15*HZ; #ifdef CONFIG_SYSCTL static struct ctl_table event_sysctl_table[] = { @@ -144,6 +158,14 @@ static struct ctl_table event_sysctl_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_events_retry_timeout", + .data = &init_net.ct.sysctl_events_retry_timeout, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, {} }; #endif /* CONFIG_SYSCTL */ @@ -165,6 +187,7 @@ static int nf_conntrack_event_init_sysctl(struct net *net) goto out; table[0].data = &net->ct.sysctl_events; + table[1].data = &net->ct.sysctl_events_retry_timeout; net->ct.event_sysctl_header = register_net_sysctl_table(net, @@ -205,6 +228,7 @@ int nf_conntrack_ecache_init(struct net *net) int ret; net->ct.sysctl_events = nf_ct_events; + net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; if (net_eq(net, &init_net)) { ret = nf_ct_extend_register(&event_extend); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 19706ef..49479d1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -463,6 +463,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) struct sk_buff *skb; unsigned int type; unsigned int flags = 0, group; + int err; /* ignore our fake conntrack entry */ if (ct == &nf_conntrack_untracked) @@ -558,7 +559,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) rcu_read_unlock(); nlmsg_end(skb, nlh); - nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); + err = nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); + if (err == -ENOBUFS || err == -EAGAIN) + return -ENOBUFS; + return 0; nla_put_failure: @@ -798,10 +802,15 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, } } - nf_conntrack_event_report(IPCT_DESTROY, - ct, - NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + if (nf_conntrack_event_report(IPCT_DESTROY, ct, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)) < 0) { + nf_ct_delete_from_lists(ct); + /* we failed to report the event, try later */ + nf_ct_insert_dying_list(ct); + nf_ct_put(ct); + return 0; + } /* death_by_timeout would report the event again */ set_bit(IPS_DYING_BIT, &ct->status); -- cgit v0.10.2 From 3dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 13 Jun 2009 12:32:39 +0200 Subject: x_tables: Convert printk to pr_err Signed-off-by: Joe Perches Signed-off-by: Patrick McHardy diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 46dba5f..025d1a0 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -364,14 +364,14 @@ int xt_check_match(struct xt_mtchk_param *par, * ebt_among is exempt from centralized matchsize checking * because it uses a dynamic-size data set. */ - printk("%s_tables: %s match: invalid size %Zu != %u\n", + pr_err("%s_tables: %s match: invalid size %Zu != %u\n", xt_prefix[par->family], par->match->name, XT_ALIGN(par->match->matchsize), size); return -EINVAL; } if (par->match->table != NULL && strcmp(par->match->table, par->table) != 0) { - printk("%s_tables: %s match: only valid in %s table, not %s\n", + pr_err("%s_tables: %s match: only valid in %s table, not %s\n", xt_prefix[par->family], par->match->name, par->match->table, par->table); return -EINVAL; @@ -379,7 +379,7 @@ int xt_check_match(struct xt_mtchk_param *par, if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { char used[64], allow[64]; - printk("%s_tables: %s match: used from hooks %s, but only " + pr_err("%s_tables: %s match: used from hooks %s, but only " "valid from %s\n", xt_prefix[par->family], par->match->name, textify_hooks(used, sizeof(used), par->hook_mask), @@ -387,7 +387,7 @@ int xt_check_match(struct xt_mtchk_param *par, return -EINVAL; } if (par->match->proto && (par->match->proto != proto || inv_proto)) { - printk("%s_tables: %s match: only valid for protocol %u\n", + pr_err("%s_tables: %s match: only valid for protocol %u\n", xt_prefix[par->family], par->match->name, par->match->proto); return -EINVAL; @@ -514,14 +514,14 @@ int xt_check_target(struct xt_tgchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { if (XT_ALIGN(par->target->targetsize) != size) { - printk("%s_tables: %s target: invalid size %Zu != %u\n", + pr_err("%s_tables: %s target: invalid size %Zu != %u\n", xt_prefix[par->family], par->target->name, XT_ALIGN(par->target->targetsize), size); return -EINVAL; } if (par->target->table != NULL && strcmp(par->target->table, par->table) != 0) { - printk("%s_tables: %s target: only valid in %s table, not %s\n", + pr_err("%s_tables: %s target: only valid in %s table, not %s\n", xt_prefix[par->family], par->target->name, par->target->table, par->table); return -EINVAL; @@ -529,7 +529,7 @@ int xt_check_target(struct xt_tgchk_param *par, if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { char used[64], allow[64]; - printk("%s_tables: %s target: used from hooks %s, but only " + pr_err("%s_tables: %s target: used from hooks %s, but only " "usable from %s\n", xt_prefix[par->family], par->target->name, textify_hooks(used, sizeof(used), par->hook_mask), @@ -537,7 +537,7 @@ int xt_check_target(struct xt_tgchk_param *par, return -EINVAL; } if (par->target->proto && (par->target->proto != proto || inv_proto)) { - printk("%s_tables: %s target: only valid for protocol %u\n", + pr_err("%s_tables: %s target: only valid for protocol %u\n", xt_prefix[par->family], par->target->name, par->target->proto); return -EINVAL; -- cgit v0.10.2 From 16aadcb680e188bd0a6d7b0ecd5d0ceabd4fba4d Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Tue, 9 Jun 2009 01:18:41 +0000 Subject: Blackfin: only handle CPLB protection violations when MPU is enabled We don't need to handle CPLB protection violations unless we are running with the MPU on. Fix the entry code to call common trap_c, and remove the code which is never run. This allows the traps test suite to run on older boards with the MPU disabled. URL: http://blackfin.uclinux.org/gf/tracker/5129 Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/kernel/cplb-nompu/cplbmgr.c b/arch/blackfin/kernel/cplb-nompu/cplbmgr.c index 8cbb47c..12b0308 100644 --- a/arch/blackfin/kernel/cplb-nompu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-nompu/cplbmgr.c @@ -28,6 +28,7 @@ #include #include #include +#include /* * WARNING @@ -100,28 +101,6 @@ static inline void write_icplb_data(int cpu, int idx, unsigned long data, #endif } -/* - * Given the contents of the status register, return the index of the - * CPLB that caused the fault. - */ -static inline int faulting_cplb_index(int status) -{ - int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF); - return 30 - signbits; -} - -/* - * Given the contents of the status register and the DCPLB_DATA contents, - * return true if a write access should be permitted. - */ -static inline int write_permitted(int status, unsigned long data) -{ - if (status & FAULT_USERSUPV) - return !!(data & CPLB_SUPV_WR); - else - return !!(data & CPLB_USER_WR); -} - /* Counters to implement round-robin replacement. */ static int icplb_rr_index[NR_CPUS] PDT_ATTR; static int dcplb_rr_index[NR_CPUS] PDT_ATTR; @@ -245,43 +224,16 @@ MGR_ATTR static int dcplb_miss(int cpu) return CPLB_RELOADED; } -MGR_ATTR static noinline int dcplb_protection_fault(int cpu) -{ - int status = bfin_read_DCPLB_STATUS(); - - nr_dcplb_prot[cpu]++; - - if (likely(status & FAULT_RW)) { - int idx = faulting_cplb_index(status); - unsigned long regaddr = DCPLB_DATA0 + idx * 4; - unsigned long data = bfin_read32(regaddr); - - /* Check if fault is to dirty a clean page */ - if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) && - write_permitted(status, data)) { - - dcplb_tbl[cpu][idx].data = data; - bfin_write32(regaddr, data); - return CPLB_RELOADED; - } - } - - return CPLB_PROT_VIOL; -} - MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs) { int cause = seqstat & 0x3f; unsigned int cpu = smp_processor_id(); switch (cause) { - case 0x2C: + case VEC_CPLB_I_M: return icplb_miss(cpu); - case 0x26: + case VEC_CPLB_M: return dcplb_miss(cpu); default: - if (unlikely(cause == 0x23)) - return dcplb_protection_fault(cpu); - return CPLB_UNKNOWN_ERR; } } diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index da0558a..25c6aa4 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -42,6 +42,7 @@ #include /* TIF_NEED_RESCHED */ #include #include +#include #include @@ -84,13 +85,15 @@ ENTRY(_ex_workaround_261) if !cc jump _bfin_return_from_exception; /* fall through */ R7 = P4; - R6 = 0x26; /* Data CPLB Miss */ + R6 = VEC_CPLB_M; /* Data CPLB Miss */ cc = R6 == R7; if cc jump _ex_dcplb_miss (BP); - R6 = 0x23; /* Data CPLB Miss */ +#ifdef CONFIG_MPU + R6 = VEC_CPLB_VL; /* Data CPLB Violation */ cc = R6 == R7; if cc jump _ex_dcplb_viol (BP); - /* Handle 0x23 Data CPLB Protection Violation +#endif + /* Handle Data CPLB Protection Violation * and Data CPLB Multiple Hits - Linux Trap Zero */ jump _ex_trap_c; @@ -270,7 +273,7 @@ ENTRY(_bfin_return_from_exception) r6.l = lo(SEQSTAT_EXCAUSE); r6.h = hi(SEQSTAT_EXCAUSE); r7 = r7 & r6; - r6 = 0x25; + r6 = VEC_UNCOV; CC = R7 == R6; if CC JUMP _double_fault; #endif -- cgit v0.10.2 From aa286ba3aef7d1b78467313111a13888fb4c3a66 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 5 Jun 2009 16:43:39 +0000 Subject: Blackfin: export ip_compute_csum/csum_partial_copy_from_user symbols All other arches do this, and some places like the net/scsi code will fail as modules without them. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/lib/checksum.c b/arch/blackfin/lib/checksum.c index 762a7f0..cd605e7 100644 --- a/arch/blackfin/lib/checksum.c +++ b/arch/blackfin/lib/checksum.c @@ -116,6 +116,7 @@ __sum16 ip_compute_csum(const void *buff, int len) { return (__force __sum16)~do_csum(buff, len); } +EXPORT_SYMBOL(ip_compute_csum); /* * copy from fs while checksumming, otherwise like csum_partial @@ -130,6 +131,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst, memcpy(dst, (__force void *)src, len); return csum_partial(dst, len, sum); } +EXPORT_SYMBOL(csum_partial_copy_from_user); /* * copy from ds while checksumming, otherwise like csum_partial -- cgit v0.10.2 From 67834fa93d7a4fac9069a07e739110d3916d8cd4 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 10 Jun 2009 06:26:26 +0000 Subject: Blackfin: rename bfin_addr_dcachable to bfin_addr_dcacheable The latter naming convention is much more common. Signed-off-by: Jie Zhang Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h index 94697f0..18bc4f7 100644 --- a/arch/blackfin/include/asm/cacheflush.h +++ b/arch/blackfin/include/asm/cacheflush.h @@ -97,7 +97,7 @@ do { memcpy(dst, src, len); \ extern unsigned long reserved_mem_dcache_on; extern unsigned long reserved_mem_icache_on; -static inline int bfin_addr_dcachable(unsigned long addr) +static inline int bfin_addr_dcacheable(unsigned long addr) { #ifdef CONFIG_BFIN_DCACHE if (addr < (_ramend - DMA_UNCACHED_REGION)) diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 763ed84..e0bf8cc 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -453,10 +453,10 @@ void *dma_memcpy(void *pdst, const void *psrc, size_t size) unsigned long src = (unsigned long)psrc; size_t bulk, rest; - if (bfin_addr_dcachable(src)) + if (bfin_addr_dcacheable(src)) blackfin_dcache_flush_range(src, src + size); - if (bfin_addr_dcachable(dst)) + if (bfin_addr_dcacheable(dst)) blackfin_dcache_invalidate_range(dst, dst + size); bulk = size & ~0xffff; diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index 87463ce..784923e 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -151,7 +151,7 @@ static noinline int dcplb_miss(unsigned int cpu) d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_DCACHE - if (bfin_addr_dcachable(addr)) { + if (bfin_addr_dcacheable(addr)) { d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND; #ifdef CONFIG_BFIN_WT d_data |= CPLB_L1_AOW | CPLB_WT; diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index f014cc2..011c5bd 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -803,7 +803,7 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->rx, drv_data->len_in_bytes); /* invalidate caches, if needed */ - if (bfin_addr_dcachable((unsigned long) drv_data->rx)) + if (bfin_addr_dcacheable((unsigned long) drv_data->rx)) invalidate_dcache_range((unsigned long) drv_data->rx, (unsigned long) (drv_data->rx + drv_data->len_in_bytes)); @@ -816,7 +816,7 @@ static void bfin_spi_pump_transfers(unsigned long data) dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); /* flush caches, if needed */ - if (bfin_addr_dcachable((unsigned long) drv_data->tx)) + if (bfin_addr_dcacheable((unsigned long) drv_data->tx)) flush_dcache_range((unsigned long) drv_data->tx, (unsigned long) (drv_data->tx + drv_data->len_in_bytes)); -- cgit v0.10.2 From 70f12567ac9aca9c2f242ae060d7de245904889e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 7 Jun 2009 17:18:25 -0400 Subject: Blackfin: add support for GENERIC_BUG Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index c56fd3e..74cdcf3 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -28,6 +28,10 @@ config BLACKFIN select HAVE_OPROFILE select ARCH_WANT_OPTIONAL_GPIOLIB +config GENERIC_BUG + def_bool y + depends on BUG + config ZONE_DMA bool default y diff --git a/arch/blackfin/include/asm/bug.h b/arch/blackfin/include/asm/bug.h index 6d3e11b..655e495 100644 --- a/arch/blackfin/include/asm/bug.h +++ b/arch/blackfin/include/asm/bug.h @@ -2,13 +2,58 @@ #define _BLACKFIN_BUG_H #ifdef CONFIG_BUG -#define HAVE_ARCH_BUG -#define BUG() do { \ - dump_bfin_trace_buffer(); \ - printk(KERN_EMERG "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ - panic("BUG!"); \ -} while (0) +#define BFIN_BUG_OPCODE 0xefcd + +#ifdef CONFIG_DEBUG_BUGVERBOSE + +#define _BUG_OR_WARN(flags) \ + asm volatile( \ + "1: .hword %0\n" \ + " .section __bug_table,\"a\",@progbits\n" \ + "2: .long 1b\n" \ + " .long %1\n" \ + " .short %2\n" \ + " .short %3\n" \ + " .org 2b + %4\n" \ + " .previous" \ + : \ + : "i"(BFIN_BUG_OPCODE), "i"(__FILE__), \ + "i"(__LINE__), "i"(flags), \ + "i"(sizeof(struct bug_entry))) + +#else + +#define _BUG_OR_WARN(flags) \ + asm volatile( \ + "1: .hword %0\n" \ + " .section __bug_table,\"a\",@progbits\n" \ + "2: .long 1b\n" \ + " .short %1\n" \ + " .org 2b + %2\n" \ + " .previous" \ + : \ + : "i"(BFIN_BUG_OPCODE), "i"(flags), \ + "i"(sizeof(struct bug_entry))) + +#endif /* CONFIG_DEBUG_BUGVERBOSE */ + +#define BUG() \ + do { \ + _BUG_OR_WARN(0); \ + for (;;); \ + } while (0) + +#define WARN_ON(condition) \ + ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + _BUG_OR_WARN(BUGFLAG_WARNING); \ + unlikely(__ret_warn_on); \ + }) + +#define HAVE_ARCH_BUG +#define HAVE_ARCH_WARN_ON #endif diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index aa76dfb..2405f19 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -27,6 +27,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include @@ -381,6 +382,23 @@ asmlinkage void trap_c(struct pt_regs *fp) /* 0x20 - Reserved, Caught by default */ /* 0x21 - Undefined Instruction, handled here */ case VEC_UNDEF_I: +#ifdef CONFIG_BUG + if (kernel_mode_regs(fp)) { + switch (report_bug(fp->pc, fp)) { + case BUG_TRAP_TYPE_NONE: + break; + case BUG_TRAP_TYPE_WARN: + dump_bfin_trace_buffer(); + fp->pc += 2; + goto traps_done; + case BUG_TRAP_TYPE_BUG: + /* call to panic() will dump trace, and it is + * off at this point, so it won't be clobbered + */ + panic("BUG()"); + } + } +#endif info.si_code = ILL_ILLOPC; sig = SIGILL; verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); @@ -792,6 +810,18 @@ void dump_bfin_trace_buffer(void) } EXPORT_SYMBOL(dump_bfin_trace_buffer); +#ifdef CONFIG_BUG +int is_valid_bugaddr(unsigned long addr) +{ + unsigned short opcode; + + if (!get_instruction(&opcode, (unsigned short *)addr)) + return 0; + + return opcode == BFIN_BUG_OPCODE; +} +#endif + /* * Checks to see if the address pointed to is either a * 16-bit CALL instruction, or a 32-bit CALL instruction diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index 8b67167..119fbdb 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -166,6 +166,20 @@ SECTIONS } PERCPU(4) SECURITY_INIT + + /* we have to discard exit text and such at runtime, not link time, to + * handle embedded cross-section references (alt instructions, bug + * table, eh_frame, etc...) + */ + .exit.text : + { + EXIT_TEXT + } + .exit.data : + { + EXIT_DATA + } + .init.ramfs : { . = ALIGN(4); @@ -264,8 +278,6 @@ SECTIONS /DISCARD/ : { - EXIT_TEXT - EXIT_DATA *(.exitcall.exit) } } -- cgit v0.10.2 From 2466ac65560ee8b7506eea3987aba9519355fd02 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Mon, 8 Jun 2009 17:52:27 +0000 Subject: Blackfin: include the cpu compiled version in /proc/cpuinfo Since the compiled-for cpu revision can be significant, include it in the cpuinfo output along side the cpu revision we're currently running on. Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 80447f9..f5f516e 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -1098,7 +1098,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) CPUID, bfin_cpuid()); seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n" - "stepping\t: %d\n", + "stepping\t: %d ", cpu, cclk/1000000, sclk/1000000, #ifdef CONFIG_MPU "mpu on", @@ -1107,7 +1107,16 @@ static int show_cpuinfo(struct seq_file *m, void *v) #endif revid); - seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n", + if (bfin_revid() != bfin_compiled_revid()) { + if (bfin_compiled_revid() == -1) + seq_printf(m, "(Compiled for Rev none)"); + else if (bfin_compiled_revid() == 0xffff) + seq_printf(m, "(Compiled for Rev any)"); + else + seq_printf(m, "(Compiled for Rev %d)", bfin_compiled_revid()); + } + + seq_printf(m, "\ncpu MHz\t\t: %lu.%03lu/%lu.%03lu\n", cclk/1000000, cclk%1000000, sclk/1000000, sclk%1000000); seq_printf(m, "bogomips\t: %lu.%02lu\n" -- cgit v0.10.2 From 47e9dedb720364e0adff0e99960fa294c6161f71 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 10 Jun 2009 08:57:08 +0000 Subject: Blackfin: add blackfin_invalidate_entire_icache for SMP systems The KGDB code uses this when switching processors to make sure the icache is in a valid state. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h index 8663781..2ef669e 100644 --- a/arch/blackfin/include/asm/cache.h +++ b/arch/blackfin/include/asm/cache.h @@ -34,9 +34,13 @@ #define L1_CACHE_SHIFT_MAX 5 #if defined(CONFIG_SMP) && \ - !defined(CONFIG_BFIN_CACHE_COHERENT) && \ - defined(CONFIG_BFIN_DCACHE) -#define __ARCH_SYNC_CORE_DCACHE + !defined(CONFIG_BFIN_CACHE_COHERENT) +# if defined(CONFIG_BFIN_ICACHE) +# define __ARCH_SYNC_CORE_ICACHE +# endif +# if defined(CONFIG_BFIN_DCACHE) +# define __ARCH_SYNC_CORE_DCACHE +# endif #ifndef __ASSEMBLY__ asmlinkage void __raw_smp_mark_barrier_asm(void); asmlinkage void __raw_smp_check_barrier_asm(void); @@ -51,6 +55,7 @@ static inline void smp_check_barrier(void) } void resync_core_dcache(void); +void resync_core_icache(void); #endif #endif diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h index 18bc4f7..5c17dee 100644 --- a/arch/blackfin/include/asm/cacheflush.h +++ b/arch/blackfin/include/asm/cacheflush.h @@ -37,6 +37,7 @@ extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned lo extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address); extern void blackfin_dflush_page(void *page); extern void blackfin_invalidate_entire_dcache(void); +extern void blackfin_invalidate_entire_icache(void); #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) diff --git a/arch/blackfin/include/asm/cpu.h b/arch/blackfin/include/asm/cpu.h index c2594ef..565b813 100644 --- a/arch/blackfin/include/asm/cpu.h +++ b/arch/blackfin/include/asm/cpu.h @@ -34,6 +34,7 @@ struct blackfin_cpudata { unsigned int dmemctl; unsigned long loops_per_jiffy; unsigned long dcache_invld_count; + unsigned long icache_invld_count; }; DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data); diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index f5f516e..6454bab 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -1181,6 +1181,9 @@ static int show_cpuinfo(struct seq_file *m, void *v) #ifdef __ARCH_SYNC_CORE_DCACHE seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", cpudata->dcache_invld_count); #endif +#ifdef __ARCH_SYNC_CORE_ICACHE + seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", cpudata->icache_invld_count); +#endif #ifdef CONFIG_BFIN_ICACHE_LOCK switch ((cpudata->imemctl >> 3) & WAYALL_L) { case WAY0_L: diff --git a/arch/blackfin/mach-common/cache-c.c b/arch/blackfin/mach-common/cache-c.c index e6ab1f8..b59ce3c 100644 --- a/arch/blackfin/mach-common/cache-c.c +++ b/arch/blackfin/mach-common/cache-c.c @@ -16,9 +16,21 @@ void blackfin_invalidate_entire_dcache(void) { u32 dmem = bfin_read_DMEM_CONTROL(); - SSYNC(); bfin_write_DMEM_CONTROL(dmem & ~0xc); SSYNC(); bfin_write_DMEM_CONTROL(dmem); SSYNC(); } + +/* Invalidate the Entire Instruction cache by + * clearing IMC bit + */ +void blackfin_invalidate_entire_icache(void) +{ + u32 imem = bfin_read_IMEM_CONTROL(); + bfin_write_IMEM_CONTROL(imem & ~0x4); + SSYNC(); + bfin_write_IMEM_CONTROL(imem); + SSYNC(); +} + diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 3b8ebae..c187da2 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -468,6 +468,17 @@ void smp_icache_flush_range_others(unsigned long start, unsigned long end) } EXPORT_SYMBOL_GPL(smp_icache_flush_range_others); +#ifdef __ARCH_SYNC_CORE_ICACHE +void resync_core_icache(void) +{ + unsigned int cpu = get_cpu(); + blackfin_invalidate_entire_icache(); + ++per_cpu(cpu_data, cpu).icache_invld_count; + put_cpu(); +} +EXPORT_SYMBOL(resync_core_icache); +#endif + #ifdef __ARCH_SYNC_CORE_DCACHE unsigned long barrier_mask __attribute__ ((__section__(".l2.bss"))); -- cgit v0.10.2 From 6510a20e1b1a3a5703429a09d03adf44882ae373 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 7 Jun 2009 15:07:25 -0400 Subject: Blackfin: fix trap_c() exit paths The trap_c() code pushes the hardware trace status onto the stack, but doesn't always restore it when returning from some trap code paths. So unify the exit code paths to all head to the end of the function. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 2405f19..ed7127b 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -309,7 +309,7 @@ asmlinkage void trap_c(struct pt_regs *fp) CHK_DEBUGGER_TRAP_MAYBE(); /* Check if this is a breakpoint in kernel space */ if (fp->ipend & 0xffc0) - return; + goto traps_done; else break; /* 0x03 - User Defined, userspace stack overflow */ @@ -325,7 +325,7 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = TRAP_ILLTRAP; sig = SIGTRAP; CHK_DEBUGGER_TRAP(); - return; + goto traps_done; #endif /* 0x04 - User Defined */ /* 0x05 - User Defined */ @@ -355,7 +355,7 @@ asmlinkage void trap_c(struct pt_regs *fp) CHK_DEBUGGER_TRAP_MAYBE(); /* Check if this is a single step in kernel space */ if (fp->ipend & 0xffc0) - return; + goto traps_done; else break; /* 0x11 - Trace Buffer Full, handled here */ @@ -459,7 +459,7 @@ asmlinkage void trap_c(struct pt_regs *fp) CHK_DEBUGGER_TRAP_MAYBE(); /* Check if this is a watchpoint in kernel space */ if (fp->ipend & 0xffc0) - return; + goto traps_done; else break; #ifdef CONFIG_BF535 @@ -624,8 +624,8 @@ asmlinkage void trap_c(struct pt_regs *fp) if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8)) fp->pc = SAFE_USER_INSTRUCTION; + traps_done: trace_buffer_restore(j); - return; } /* Typical exception handling routines */ -- cgit v0.10.2 From 82bd1d7d45a69c54fb6beedb78ccb1c7d308dd93 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 7 Jun 2009 17:08:28 -0400 Subject: Blackfin: push down exception oops checking Rather than maintain a duplicate list of valid exceptions we can take in the kernel both in the first if() check and the switch() check, delay the oops check to after the switch(). All valid exceptions will have returned by this point leaving only the invalid ones. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index ed7127b..d279552 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -239,6 +239,11 @@ asmlinkage void double_fault_c(struct pt_regs *fp) } +static int kernel_mode_regs(struct pt_regs *regs) +{ + return regs->ipend & 0xffc0; +} + asmlinkage void trap_c(struct pt_regs *fp) { #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON @@ -247,6 +252,7 @@ asmlinkage void trap_c(struct pt_regs *fp) #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO unsigned int cpu = smp_processor_id(); #endif + const char *strerror = NULL; int sig = 0; siginfo_t info; unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; @@ -260,27 +266,10 @@ asmlinkage void trap_c(struct pt_regs *fp) * double faults if the stack has become corrupt */ - /* If the fault was caused by a kernel thread, or interrupt handler - * we will kernel panic, so the system reboots. - * If KGDB is enabled, don't set this for kernel breakpoints - */ - - /* TODO: check to see if we are in some sort of deferred HWERR - * that we should be able to recover from, not kernel panic - */ - if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP) -#ifdef CONFIG_KGDB - && (trapnr != VEC_EXCPT02) +#ifndef CONFIG_KGDB + /* IPEND is skipped if KGDB isn't enabled (see entry code) */ + fp->ipend = bfin_read_IPEND(); #endif - ){ - console_verbose(); - oops_in_progress = 1; - } else if (current) { - if (current->mm == NULL) { - console_verbose(); - oops_in_progress = 1; - } - } /* trap_c() will be called for exceptions. During exceptions * processing, the pc value should be set with retx value. @@ -308,7 +297,7 @@ asmlinkage void trap_c(struct pt_regs *fp) sig = SIGTRAP; CHK_DEBUGGER_TRAP_MAYBE(); /* Check if this is a breakpoint in kernel space */ - if (fp->ipend & 0xffc0) + if (kernel_mode_regs(fp)) goto traps_done; else break; @@ -316,7 +305,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_EXCPT03: info.si_code = SEGV_STACKFLOW; sig = SIGSEGV; - verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x03(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x02 - KGDB initial connection and break signal trap */ @@ -345,7 +334,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_EXCPT04 ... VEC_EXCPT15: info.si_code = ILL_ILLPARAOP; sig = SIGILL; - verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x04(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x10 HW Single step, handled here */ @@ -354,7 +343,7 @@ asmlinkage void trap_c(struct pt_regs *fp) sig = SIGTRAP; CHK_DEBUGGER_TRAP_MAYBE(); /* Check if this is a single step in kernel space */ - if (fp->ipend & 0xffc0) + if (kernel_mode_regs(fp)) goto traps_done; else break; @@ -362,7 +351,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_OVFLOW: info.si_code = TRAP_TRACEFLOW; sig = SIGTRAP; - verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x11(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x12 - Reserved, Caught by default */ @@ -401,35 +390,35 @@ asmlinkage void trap_c(struct pt_regs *fp) #endif info.si_code = ILL_ILLOPC; sig = SIGILL; - verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x22 - Illegal Instruction Combination, handled here */ case VEC_ILGAL_I: info.si_code = ILL_ILLPARAOP; sig = SIGILL; - verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x22(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x23 - Data CPLB protection violation, handled here */ case VEC_CPLB_VL: info.si_code = ILL_CPLB_VI; sig = SIGBUS; - verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x23(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x24 - Data access misaligned, handled here */ case VEC_MISALI_D: info.si_code = BUS_ADRALN; sig = SIGBUS; - verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x24(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x25 - Unrecoverable Event, handled here */ case VEC_UNCOV: info.si_code = ILL_ILLEXCPT; sig = SIGILL; - verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x25(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, @@ -437,7 +426,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_CPLB_M: info.si_code = BUS_ADRALN; sig = SIGBUS; - verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x26(KERN_NOTICE); break; /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ case VEC_CPLB_MHIT: @@ -445,10 +434,10 @@ asmlinkage void trap_c(struct pt_regs *fp) sig = SIGSEGV; #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START) - verbose_printk(KERN_NOTICE "NULL pointer access\n"); + strerror = KERN_NOTICE "NULL pointer access\n"; else #endif - verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x27(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x28 - Emulation Watchpoint, handled here */ @@ -458,7 +447,7 @@ asmlinkage void trap_c(struct pt_regs *fp) pr_debug(EXC_0x28(KERN_DEBUG)); CHK_DEBUGGER_TRAP_MAYBE(); /* Check if this is a watchpoint in kernel space */ - if (fp->ipend & 0xffc0) + if (kernel_mode_regs(fp)) goto traps_done; else break; @@ -467,7 +456,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */ info.si_code = BUS_OPFETCH; sig = SIGBUS; - verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n"); + strerror = KERN_NOTICE "BF535: VEC_ISTRU_VL\n"; CHK_DEBUGGER_TRAP_MAYBE(); break; #else @@ -477,21 +466,21 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_MISALI_I: info.si_code = BUS_ADRALN; sig = SIGBUS; - verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x2A(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2B - Instruction CPLB protection violation, handled here */ case VEC_CPLB_I_VL: info.si_code = ILL_CPLB_VI; sig = SIGBUS; - verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x2B(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ case VEC_CPLB_I_M: info.si_code = ILL_CPLB_MISS; sig = SIGBUS; - verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x2C(KERN_NOTICE); break; /* 0x2D - Instruction CPLB Multiple Hits, handled here */ case VEC_CPLB_I_MHIT: @@ -499,17 +488,17 @@ asmlinkage void trap_c(struct pt_regs *fp) sig = SIGSEGV; #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START) - verbose_printk(KERN_NOTICE "Jump to NULL address\n"); + strerror = KERN_NOTICE "Jump to NULL address\n"; else #endif - verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x2D(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2E - Illegal use of Supervisor Resource, handled here */ case VEC_ILL_RES: info.si_code = ILL_PRVOPC; sig = SIGILL; - verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE)); + strerror = KERN_NOTICE EXC_0x2E(KERN_NOTICE); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2F - Reserved, Caught by default */ @@ -537,17 +526,17 @@ asmlinkage void trap_c(struct pt_regs *fp) case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): info.si_code = BUS_ADRALN; sig = SIGBUS; - verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE)); + strerror = KERN_NOTICE HWC_x2(KERN_NOTICE); break; /* External Memory Addressing Error */ case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): info.si_code = BUS_ADRERR; sig = SIGBUS; - verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE)); + strerror = KERN_NOTICE HWC_x3(KERN_NOTICE); break; /* Performance Monitor Overflow */ case (SEQSTAT_HWERRCAUSE_PERF_FLOW): - verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE)); + strerror = KERN_NOTICE HWC_x12(KERN_NOTICE); break; /* RAISE 5 instruction */ case (SEQSTAT_HWERRCAUSE_RAISE_5): @@ -564,7 +553,6 @@ asmlinkage void trap_c(struct pt_regs *fp) * if we get here we hit a reserved one, so panic */ default: - oops_in_progress = 1; info.si_code = ILL_ILLPARAOP; sig = SIGILL; verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", @@ -575,6 +563,16 @@ asmlinkage void trap_c(struct pt_regs *fp) BUG_ON(sig == 0); + /* If the fault was caused by a kernel thread, or interrupt handler + * we will kernel panic, so the system reboots. + */ + if (kernel_mode_regs(fp) || (current && !current->mm)) { + console_verbose(); + oops_in_progress = 1; + if (strerror) + verbose_printk(strerror); + } + if (sig != SIGTRAP) { dump_bfin_process(fp); dump_bfin_mem(fp); -- cgit v0.10.2 From f9ee3ab81c222219ad4467b75b406efe2616d8a4 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 8 Jun 2009 09:51:30 -0400 Subject: Blackfin: fix flag storage for irq funcs The IRQ functions take an "unsigned long" flags variable, not any other type, so fix the places where we use "int" or "long". Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index 7bbf44e..b1d92f1 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -90,7 +90,7 @@ static inline int atomic_test_mask(int mask, atomic_t *v) static inline void atomic_add(int i, atomic_t *v) { - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter += i; @@ -99,7 +99,7 @@ static inline void atomic_add(int i, atomic_t *v) static inline void atomic_sub(int i, atomic_t *v) { - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter -= i; @@ -110,7 +110,7 @@ static inline void atomic_sub(int i, atomic_t *v) static inline int atomic_add_return(int i, atomic_t *v) { int __temp = 0; - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter += i; @@ -124,7 +124,7 @@ static inline int atomic_add_return(int i, atomic_t *v) static inline int atomic_sub_return(int i, atomic_t *v) { int __temp = 0; - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter -= i; @@ -136,7 +136,7 @@ static inline int atomic_sub_return(int i, atomic_t *v) static inline void atomic_inc(volatile atomic_t *v) { - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter++; @@ -145,7 +145,7 @@ static inline void atomic_inc(volatile atomic_t *v) static inline void atomic_dec(volatile atomic_t *v) { - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter--; @@ -154,7 +154,7 @@ static inline void atomic_dec(volatile atomic_t *v) static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter &= ~mask; @@ -163,7 +163,7 @@ static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) static inline void atomic_set_mask(unsigned int mask, atomic_t *v) { - long flags; + unsigned long flags; local_irq_save_hw(flags); v->counter |= mask; diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h index 21b036e..75fee2f 100644 --- a/arch/blackfin/include/asm/bitops.h +++ b/arch/blackfin/include/asm/bitops.h @@ -109,7 +109,8 @@ static inline void clear_bit(int nr, volatile unsigned long *addr) static inline void change_bit(int nr, volatile unsigned long *addr) { - int mask, flags; + int mask; + unsigned long flags; unsigned long *ADDR = (unsigned long *)addr; ADDR += nr >> 5; -- cgit v0.10.2 From 86f2008bf546af9a434f480710e8d33891616bf5 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 10 Jun 2009 08:42:41 +0000 Subject: Blackfin: fix deadlock in SMP IPI handler When a low priority interrupt (like ethernet) is triggered between 2 high priority IPI messages, a deadlock in disable_irq() is hit by the second IPI handler. This is because the second IPI message is queued within the first IPI handler, but the handler doesn't process all messages, and new ones are inserted rather than appended. So now we process all the pending messages, and append new ones to the pending list. URL: http://blackfin.uclinux.org/gf/tracker/5226 Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index c187da2..6184005 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -144,7 +144,7 @@ static void ipi_call_function(unsigned int cpu, struct ipi_message *msg) static irqreturn_t ipi_handler(int irq, void *dev_instance) { - struct ipi_message *msg, *mg; + struct ipi_message *msg; struct ipi_message_queue *msg_queue; unsigned int cpu = smp_processor_id(); @@ -154,7 +154,8 @@ static irqreturn_t ipi_handler(int irq, void *dev_instance) msg_queue->count++; spin_lock(&msg_queue->lock); - list_for_each_entry_safe(msg, mg, &msg_queue->head, list) { + while (!list_empty(&msg_queue->head)) { + msg = list_entry(msg_queue->head.next, typeof(*msg), list); list_del(&msg->list); switch (msg->type) { case BFIN_IPI_RESCHEDULE: @@ -221,7 +222,7 @@ int smp_call_function(void (*func)(void *info), void *info, int wait) for_each_cpu_mask(cpu, callmap) { msg_queue = &per_cpu(ipi_msg_queue, cpu); spin_lock_irqsave(&msg_queue->lock, flags); - list_add(&msg->list, &msg_queue->head); + list_add_tail(&msg->list, &msg_queue->head); spin_unlock_irqrestore(&msg_queue->lock, flags); platform_send_ipi_cpu(cpu); } @@ -261,7 +262,7 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info, msg_queue = &per_cpu(ipi_msg_queue, cpu); spin_lock_irqsave(&msg_queue->lock, flags); - list_add(&msg->list, &msg_queue->head); + list_add_tail(&msg->list, &msg_queue->head); spin_unlock_irqrestore(&msg_queue->lock, flags); platform_send_ipi_cpu(cpu); @@ -292,7 +293,7 @@ void smp_send_reschedule(int cpu) msg_queue = &per_cpu(ipi_msg_queue, cpu); spin_lock_irqsave(&msg_queue->lock, flags); - list_add(&msg->list, &msg_queue->head); + list_add_tail(&msg->list, &msg_queue->head); spin_unlock_irqrestore(&msg_queue->lock, flags); platform_send_ipi_cpu(cpu); @@ -320,7 +321,7 @@ void smp_send_stop(void) for_each_cpu_mask(cpu, callmap) { msg_queue = &per_cpu(ipi_msg_queue, cpu); spin_lock_irqsave(&msg_queue->lock, flags); - list_add(&msg->list, &msg_queue->head); + list_add_tail(&msg->list, &msg_queue->head); spin_unlock_irqrestore(&msg_queue->lock, flags); platform_send_ipi_cpu(cpu); } -- cgit v0.10.2 From 54ebae7166275a618f0228138e67ff7d10a3b9d0 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 10 Jun 2009 06:11:21 +0000 Subject: Blackfin: do not configure the UART early if on wrong processor Before we configure the early UART, check to make sure we are running on the expected processor - otherwise, we cause problems by configuring pins that don't exist (and causing an infinite loop of faults). Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c index 3302719..2ab5681 100644 --- a/arch/blackfin/kernel/early_printk.c +++ b/arch/blackfin/kernel/early_printk.c @@ -202,11 +202,15 @@ asmlinkage void __init init_early_exception_vectors(void) asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr) { /* This can happen before the uart is initialized, so initialize - * the UART now + * the UART now (but only if we are running on the processor we think + * we are compiled for - otherwise we write to MMRs that don't exist, + * and cause other problems. Nothing comes out the UART, but it does + * end up in the __buf_log. */ - if (likely(early_console == NULL)) + if (likely(early_console == NULL) && CPUID == bfin_cpuid()) setup_early_printk(DEFAULT_EARLY_PORT); + printk(KERN_EMERG "Early panic\n"); dump_bfin_mem(fp); show_regs(fp); dump_bfin_trace_buffer(); -- cgit v0.10.2 From 53122693c3cef005495279835286c36c58e035e8 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Fri, 5 Jun 2009 12:11:11 +0000 Subject: Blackfin: define SPI IRQ in board resources The Blackfin SPI driver can be driven by an IRQ now, so declare it in the board resources. Signed-off-by: Yi Li Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/mach-bf518/boards/ezbrd.c b/arch/blackfin/mach-bf518/boards/ezbrd.c index 62bba09..8969a24 100644 --- a/arch/blackfin/mach-bf518/boards/ezbrd.c +++ b/arch/blackfin/mach-bf518/boards/ezbrd.c @@ -369,6 +369,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI0, .end = CH_SPI0, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI0, + .end = IRQ_SPI0, .flags = IORESOURCE_IRQ, }, }; @@ -399,6 +404,11 @@ static struct resource bfin_spi1_resource[] = { [1] = { .start = CH_SPI1, .end = CH_SPI1, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI1, + .end = IRQ_SPI1, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c index 6d6f9ef..1eaf27f 100644 --- a/arch/blackfin/mach-bf527/boards/cm_bf527.c +++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c @@ -664,6 +664,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c index 1435c5d..9f9c000 100644 --- a/arch/blackfin/mach-bf527/boards/ezbrd.c +++ b/arch/blackfin/mach-bf527/boards/ezbrd.c @@ -467,6 +467,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c index 147edd1..3e5b7db 100644 --- a/arch/blackfin/mach-bf527/boards/ezkit.c +++ b/arch/blackfin/mach-bf527/boards/ezkit.c @@ -723,6 +723,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c index 895f213..38cf8ff 100644 --- a/arch/blackfin/mach-bf533/boards/H8606.c +++ b/arch/blackfin/mach-bf533/boards/H8606.c @@ -266,6 +266,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf533/boards/blackstamp.c b/arch/blackfin/mach-bf533/boards/blackstamp.c index 0765872..9ecdc36 100644 --- a/arch/blackfin/mach-bf533/boards/blackstamp.c +++ b/arch/blackfin/mach-bf533/boards/blackstamp.c @@ -162,6 +162,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c index a727e53..1443e92 100644 --- a/arch/blackfin/mach-bf533/boards/cm_bf533.c +++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c @@ -160,6 +160,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c index 842f1c9..89a5ec4 100644 --- a/arch/blackfin/mach-bf533/boards/ezkit.c +++ b/arch/blackfin/mach-bf533/boards/ezkit.c @@ -196,6 +196,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c index e19c565..a68ade8 100644 --- a/arch/blackfin/mach-bf533/boards/stamp.c +++ b/arch/blackfin/mach-bf533/boards/stamp.c @@ -299,6 +299,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c index 4fee196..2a87d1c 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c @@ -182,8 +182,13 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, - } + }, }; /* SPI controller data */ diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c index 3c15981..399f81d 100644 --- a/arch/blackfin/mach-bf537/boards/minotaur.c +++ b/arch/blackfin/mach-bf537/boards/minotaur.c @@ -184,6 +184,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c index 26707ce..838240f 100644 --- a/arch/blackfin/mach-bf537/boards/pnav10.c +++ b/arch/blackfin/mach-bf537/boards/pnav10.c @@ -398,8 +398,13 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, - } + }, }; /* SPI controller data */ diff --git a/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/arch/blackfin/mach-bf537/boards/tcm_bf537.c index 2805745..e523e6e 100644 --- a/arch/blackfin/mach-bf537/boards/tcm_bf537.c +++ b/arch/blackfin/mach-bf537/boards/tcm_bf537.c @@ -182,6 +182,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf538/boards/ezkit.c b/arch/blackfin/mach-bf538/boards/ezkit.c index e37cb93..57695b4 100644 --- a/arch/blackfin/mach-bf538/boards/ezkit.c +++ b/arch/blackfin/mach-bf538/boards/ezkit.c @@ -352,6 +352,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI0, .end = CH_SPI0, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI0, + .end = IRQ_SPI0, .flags = IORESOURCE_IRQ, } }; @@ -366,6 +371,11 @@ static struct resource bfin_spi1_resource[] = { [1] = { .start = CH_SPI1, .end = CH_SPI1, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI1, + .end = IRQ_SPI1, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf548/boards/cm_bf548.c b/arch/blackfin/mach-bf548/boards/cm_bf548.c index f53ad68..f5a3c30 100644 --- a/arch/blackfin/mach-bf548/boards/cm_bf548.c +++ b/arch/blackfin/mach-bf548/boards/cm_bf548.c @@ -612,6 +612,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI0, .end = CH_SPI0, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI0, + .end = IRQ_SPI0, .flags = IORESOURCE_IRQ, } }; @@ -626,6 +631,11 @@ static struct resource bfin_spi1_resource[] = { [1] = { .start = CH_SPI1, .end = CH_SPI1, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI1, + .end = IRQ_SPI1, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c index add5a17..a4b1ee8 100644 --- a/arch/blackfin/mach-bf548/boards/ezkit.c +++ b/arch/blackfin/mach-bf548/boards/ezkit.c @@ -741,6 +741,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI0, .end = CH_SPI0, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI0, + .end = IRQ_SPI0, .flags = IORESOURCE_IRQ, } }; @@ -755,6 +760,11 @@ static struct resource bfin_spi1_resource[] = { [1] = { .start = CH_SPI1, .end = CH_SPI1, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI1, + .end = IRQ_SPI1, .flags = IORESOURCE_IRQ, } }; diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c index 0dd9685..0c9d72c 100644 --- a/arch/blackfin/mach-bf561/boards/cm_bf561.c +++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c @@ -177,8 +177,13 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, - } + }, }; /* SPI controller data */ diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c index 0e2178a..b5ef7ff 100644 --- a/arch/blackfin/mach-bf561/boards/ezkit.c +++ b/arch/blackfin/mach-bf561/boards/ezkit.c @@ -304,6 +304,11 @@ static struct resource bfin_spi0_resource[] = { [1] = { .start = CH_SPI, .end = CH_SPI, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = IRQ_SPI, + .end = IRQ_SPI, .flags = IORESOURCE_IRQ, } }; -- cgit v0.10.2 From a427293f84ea2491fbdcfbddadc2a2f68e0d2969 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 10 Jun 2009 08:45:12 +0000 Subject: Blackfin: bf518f-ezbrd: fix SPI CS for SPI flash The SPI flash on the BF518F-EZBRD board is actually hooked up to CS2, not CS1, so make sure the resources are correct. URL: http://blackfin.uclinux.org/gf/tracker/5220 Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/mach-bf518/boards/ezbrd.c b/arch/blackfin/mach-bf518/boards/ezbrd.c index 8969a24..1382f03 100644 --- a/arch/blackfin/mach-bf518/boards/ezbrd.c +++ b/arch/blackfin/mach-bf518/boards/ezbrd.c @@ -246,7 +246,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ .bus_num = 0, /* Framework bus number */ - .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ + .chip_select = 2, /* On BF518F-EZBRD it's SPI0_SSEL2 */ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, .mode = SPI_MODE_3, -- cgit v0.10.2 From 4f84b6e0bb9a7d92c791ba3607674c98f69418cb Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 10 Jun 2009 20:45:48 -0400 Subject: Blackfin: bf537-stamp: update ADP5520 resources The ADP5520 hooks up to PF7 rather than PG0. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index dfb5036..ff7228c 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -1345,7 +1345,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = { #if defined(CONFIG_PMIC_ADP5520) || defined(CONFIG_PMIC_ADP5520_MODULE) { I2C_BOARD_INFO("pmic-adp5520", 0x32), - .irq = IRQ_PF7, + .irq = IRQ_PG0, .platform_data = (void *)&adp5520_pdev_data, }, #endif -- cgit v0.10.2 From 6640cfa82b77fa63f6d3fc284dbd3ab957842936 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Thu, 11 Jun 2009 01:51:57 -0400 Subject: Blackfin: update aedos-ipipe code to upstream 1.10-00 Signed-off-by: Yi Li Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/ipipe.h b/arch/blackfin/include/asm/ipipe.h index 51d0bf5..bbe1c37 100644 --- a/arch/blackfin/include/asm/ipipe.h +++ b/arch/blackfin/include/asm/ipipe.h @@ -35,10 +35,10 @@ #include #include -#define IPIPE_ARCH_STRING "1.9-01" +#define IPIPE_ARCH_STRING "1.10-00" #define IPIPE_MAJOR_NUMBER 1 -#define IPIPE_MINOR_NUMBER 9 -#define IPIPE_PATCH_NUMBER 1 +#define IPIPE_MINOR_NUMBER 10 +#define IPIPE_PATCH_NUMBER 0 #ifdef CONFIG_SMP #error "I-pipe/blackfin: SMP not implemented" @@ -54,10 +54,11 @@ do { \ #define task_hijacked(p) \ ({ \ - int __x__ = ipipe_current_domain != ipipe_root_domain; \ - /* We would need to clear the SYNC flag for the root domain */ \ - /* over the current processor in SMP mode. */ \ - local_irq_enable_hw(); __x__; \ + int __x__ = __ipipe_root_domain_p; \ + __clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \ + if (__x__) \ + local_irq_enable_hw(); \ + !__x__; \ }) struct ipipe_domain; @@ -179,23 +180,24 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul) #define __ipipe_run_isr(ipd, irq) \ do { \ - if (ipd == ipipe_root_domain) { \ + if (!__ipipe_pipeline_head_p(ipd)) \ local_irq_enable_hw(); \ - if (ipipe_virtual_irq_p(irq)) \ + if (ipd == ipipe_root_domain) { \ + if (unlikely(ipipe_virtual_irq_p(irq))) { \ + irq_enter(); \ ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \ - else \ + irq_exit(); \ + } else \ ipd->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); \ - local_irq_disable_hw(); \ } else { \ __clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \ - local_irq_enable_nohead(ipd); \ ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \ /* Attempt to exit the outer interrupt level before \ * starting the deferred IRQ processing. */ \ - local_irq_disable_nohead(ipd); \ __ipipe_run_irqtail(); \ __set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \ } \ + local_irq_disable_hw(); \ } while (0) #define __ipipe_syscall_watched_p(p, sc) \ diff --git a/arch/blackfin/kernel/ipipe.c b/arch/blackfin/kernel/ipipe.c index 5fc4248..d8cde1f 100644 --- a/arch/blackfin/kernel/ipipe.c +++ b/arch/blackfin/kernel/ipipe.c @@ -99,7 +99,7 @@ void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs) * interrupt. */ m_ack = (regs == NULL || irq == IRQ_SYSTMR || irq == IRQ_CORETMR); - this_domain = ipipe_current_domain; + this_domain = __ipipe_current_domain; if (unlikely(test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))) head = &this_domain->p_link; @@ -212,7 +212,9 @@ void __ipipe_unstall_root_raw(void) int __ipipe_syscall_root(struct pt_regs *regs) { + struct ipipe_percpu_domain_data *p; unsigned long flags; + int ret; /* * We need to run the IRQ tail hook whenever we don't @@ -231,29 +233,31 @@ int __ipipe_syscall_root(struct pt_regs *regs) /* * This routine either returns: * 0 -- if the syscall is to be passed to Linux; - * 1 -- if the syscall should not be passed to Linux, and no + * >0 -- if the syscall should not be passed to Linux, and no * tail work should be performed; - * -1 -- if the syscall should not be passed to Linux but the + * <0 -- if the syscall should not be passed to Linux but the * tail work has to be performed (for handling signals etc). */ - if (__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) && - __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs) > 0) { - if (ipipe_root_domain_p && !in_atomic()) { - /* - * Sync pending VIRQs before _TIF_NEED_RESCHED - * is tested. - */ - local_irq_save_hw(flags); - if ((ipipe_root_cpudom_var(irqpend_himask) & IPIPE_IRQMASK_VIRT) != 0) - __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT); - local_irq_restore_hw(flags); - return -1; - } + if (!__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL)) + return 0; + + ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs); + + local_irq_save_hw(flags); + + if (!__ipipe_root_domain_p) { + local_irq_restore_hw(flags); return 1; } - return 0; + p = ipipe_root_cpudom_ptr(); + if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0) + __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT); + + local_irq_restore_hw(flags); + + return -ret; } unsigned long ipipe_critical_enter(void (*syncfn) (void)) @@ -329,9 +333,7 @@ asmlinkage void __ipipe_sync_root(void) void ___ipipe_sync_pipeline(unsigned long syncmask) { - struct ipipe_domain *ipd = ipipe_current_domain; - - if (ipd == ipipe_root_domain) { + if (__ipipe_root_domain_p) { if (test_bit(IPIPE_SYNCDEFER_FLAG, &ipipe_root_cpudom_var(status))) return; } -- cgit v0.10.2 From 7a8b71db9dbb87640ffabcf42285781a808de342 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 5 Jun 2009 20:41:17 -0400 Subject: Blackfin: bf548-ezkit: update smsc911x resources The older smsc911x driver made platform data optional, but the newer one always requires it, so add proper settings to the BF548-EZKIT. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c index a4b1ee8..805a57b 100644 --- a/arch/blackfin/mach-bf548/boards/ezkit.c +++ b/arch/blackfin/mach-bf548/boards/ezkit.c @@ -396,6 +396,8 @@ static struct platform_device bfin_sir3_device = { #endif #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +#include + static struct resource smsc911x_resources[] = { { .name = "smsc911x-memory", @@ -409,11 +411,22 @@ static struct resource smsc911x_resources[] = { .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, }, }; + +static struct smsc911x_platform_config smsc911x_config = { + .flags = SMSC911X_USE_32BIT, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + static struct platform_device smsc911x_device = { .name = "smsc911x", .id = 0, .num_resources = ARRAY_SIZE(smsc911x_resources), .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, }; #endif -- cgit v0.10.2 From bac7d89ebe64eca9ce63ee6a5e4341d252671467 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 7 Jun 2009 03:46:06 -0400 Subject: Blackfin: convert Kconfig style to def_bool Makes the file easier to read when there isn't so much clutter. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 74cdcf3..2cf455a 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -6,24 +6,19 @@ mainmenu "Blackfin Kernel Configuration" config MMU - bool - default n + def_bool n config FPU - bool - default n + def_bool n config RWSEM_GENERIC_SPINLOCK - bool - default y + def_bool y config RWSEM_XCHGADD_ALGORITHM - bool - default n + def_bool n config BLACKFIN - bool - default y + def_bool y select HAVE_IDE select HAVE_OPROFILE select ARCH_WANT_OPTIONAL_GPIOLIB @@ -33,36 +28,29 @@ config GENERIC_BUG depends on BUG config ZONE_DMA - bool - default y + def_bool y config GENERIC_FIND_NEXT_BIT - bool - default y + def_bool y config GENERIC_HWEIGHT - bool - default y + def_bool y config GENERIC_HARDIRQS - bool - default y + def_bool y config GENERIC_IRQ_PROBE - bool - default y + def_bool y config GENERIC_GPIO - bool - default y + def_bool y config FORCE_MAX_ZONEORDER int default "14" config GENERIC_CALIBRATE_DELAY - bool - default y + def_bool y source "init/Kconfig" -- cgit v0.10.2 From 538067c822e2512d9a165c71c0c5722168470304 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 7 Jun 2009 03:47:01 -0400 Subject: Blackfin: add support for bzip2/lzma compressed kernel images Since U-Boot can support these compression types, add appropriate targets to the Blackfin boot files. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 2cf455a..6ae9a03 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -20,6 +20,9 @@ config RWSEM_XCHGADD_ALGORITHM config BLACKFIN def_bool y select HAVE_IDE + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_BZIP2 + select HAVE_KERNEL_LZMA select HAVE_OPROFILE select ARCH_WANT_OPTIONAL_GPIOLIB diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile index d54c828..6f9533c 100644 --- a/arch/blackfin/Makefile +++ b/arch/blackfin/Makefile @@ -137,7 +137,7 @@ archclean: INSTALL_PATH ?= /tftpboot boot := arch/$(ARCH)/boot -BOOT_TARGETS = vmImage +BOOT_TARGETS = vmImage vmImage.bz2 vmImage.gz vmImage.lzma PHONY += $(BOOT_TARGETS) install KBUILD_IMAGE := $(boot)/vmImage @@ -150,7 +150,10 @@ install: $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install define archhelp - echo '* vmImage - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)' + echo '* vmImage - Alias to selected kernel format (vmImage.gz by default)' + echo ' vmImage.bz2 - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.bz2)' + echo '* vmImage.gz - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.gz)' + echo ' vmImage.lzma - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.lzma)' echo ' install - Install kernel using' echo ' (your) ~/bin/$(CROSS_COMPILE)installkernel or' echo ' (distribution) PATH: $(CROSS_COMPILE)installkernel or' diff --git a/arch/blackfin/boot/.gitignore b/arch/blackfin/boot/.gitignore index 3ae0399..229e508 100644 --- a/arch/blackfin/boot/.gitignore +++ b/arch/blackfin/boot/.gitignore @@ -1 +1,2 @@ -+vmImage +vmImage* +vmlinux* diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile index e028d13..3ab6f23 100644 --- a/arch/blackfin/boot/Makefile +++ b/arch/blackfin/boot/Makefile @@ -8,24 +8,41 @@ MKIMAGE := $(srctree)/scripts/mkuboot.sh -targets := vmImage -extra-y += vmlinux.bin vmlinux.gz +targets := vmImage vmImage.bz2 vmImage.gz vmImage.lzma +extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma quiet_cmd_uimage = UIMAGE $@ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \ - -C gzip -n 'Linux-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \ + -C $(2) -n 'Linux-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \ -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \ -d $< $@ $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) -$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE $(call if_changed,gzip) -$(obj)/vmImage: $(obj)/vmlinux.gz - $(call if_changed,uimage) - @$(kecho) 'Kernel: $@ is ready' +$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE + $(call if_changed,bzip2) + +$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE + $(call if_changed,lzma) + +$(obj)/vmImage.bz2: $(obj)/vmlinux.bin.bz2 + $(call if_changed,uimage,bzip2) + +$(obj)/vmImage.gz: $(obj)/vmlinux.bin.gz + $(call if_changed,uimage,gzip) + +$(obj)/vmImage.lzma: $(obj)/vmlinux.bin.lzma + $(call if_changed,uimage,lzma) + +suffix-$(CONFIG_KERNEL_GZIP) := gz +suffix-$(CONFIG_KERNEL_BZIP2) := bz2 +suffix-$(CONFIG_KERNEL_LZMA) := lzma +$(obj)/vmImage: $(obj)/vmImage.$(suffix-y) + @ln -sf $(notdir $<) $@ install: sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" -- cgit v0.10.2 From 8f86001f76609f70bfcce34e7e2a11860e012ace Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 8 Jun 2009 12:49:48 -0400 Subject: Blackfin: add support for irqflags This converts the irq handling in the Blackfin arch from the old irq.h / system.h method to the new irqflags.h. A stepping stone on the way to other tracing functionality. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 6ae9a03..d68cb0d 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -55,6 +55,9 @@ config FORCE_MAX_ZONEORDER config GENERIC_CALIBRATE_DELAY def_bool y +config TRACE_IRQFLAGS_SUPPORT + def_bool y + source "init/Kconfig" source "kernel/Kconfig.preempt" diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h index 7645e85..400bdd5 100644 --- a/arch/blackfin/include/asm/irq.h +++ b/arch/blackfin/include/asm/irq.h @@ -17,270 +17,17 @@ #ifndef _BFIN_IRQ_H_ #define _BFIN_IRQ_H_ -/* SYS_IRQS and NR_IRQS are defined in */ -#include -#include -#include - -#ifdef CONFIG_SMP -/* Forward decl needed due to cdef inter dependencies */ -static inline uint32_t __pure bfin_dspid(void); -# define blackfin_core_id() (bfin_dspid() & 0xff) -# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask -#else -extern unsigned long bfin_irq_flags; -#endif - -#ifdef CONFIG_IPIPE - -#include +#include -void __ipipe_unstall_root(void); - -void __ipipe_restore_root(unsigned long flags); - -#ifdef CONFIG_DEBUG_HWERR -# define __all_masked_irq_flags 0x3f -# define __save_and_cli_hw(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - "sti %1;" \ - : "=&d"(x) \ - : "d" (0x3F) \ - ) -#else -# define __all_masked_irq_flags 0x1f -# define __save_and_cli_hw(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - : "=&d"(x) \ - ) -#endif - -#define irqs_enabled_from_flags_hw(x) ((x) != __all_masked_irq_flags) -#define raw_irqs_disabled_flags(flags) (!irqs_enabled_from_flags_hw(flags)) -#define local_test_iflag_hw(x) irqs_enabled_from_flags_hw(x) - -#define local_save_flags(x) \ - do { \ - (x) = __ipipe_test_root() ? \ - __all_masked_irq_flags : bfin_irq_flags; \ - barrier(); \ - } while (0) - -#define local_irq_save(x) \ - do { \ - (x) = __ipipe_test_and_stall_root() ? \ - __all_masked_irq_flags : bfin_irq_flags; \ - barrier(); \ - } while (0) - -static inline void local_irq_restore(unsigned long x) -{ - barrier(); - __ipipe_restore_root(x == __all_masked_irq_flags); -} - -#define local_irq_disable() \ - do { \ - __ipipe_stall_root(); \ - barrier(); \ - } while (0) - -static inline void local_irq_enable(void) -{ - barrier(); - __ipipe_unstall_root(); -} - -#define irqs_disabled() __ipipe_test_root() - -#define local_save_flags_hw(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - "sti %0;" \ - : "=d"(x) \ - ) - -#define irqs_disabled_hw() \ - ({ \ - unsigned long flags; \ - local_save_flags_hw(flags); \ - !irqs_enabled_from_flags_hw(flags); \ - }) - -static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real) -{ - /* Merge virtual and real interrupt mask bits into a single - 32bit word. */ - return (real & ~(1 << 31)) | ((virt != 0) << 31); -} - -static inline int raw_demangle_irq_bits(unsigned long *x) -{ - int virt = (*x & (1 << 31)) != 0; - *x &= ~(1L << 31); - return virt; -} - -#ifdef CONFIG_IPIPE_TRACE_IRQSOFF - -#define local_irq_disable_hw() \ - do { \ - int _tmp_dummy; \ - if (!irqs_disabled_hw()) \ - ipipe_trace_begin(0x80000000); \ - __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : ); \ - } while (0) - -#define local_irq_enable_hw() \ - do { \ - if (irqs_disabled_hw()) \ - ipipe_trace_end(0x80000000); \ - __asm__ __volatile__ ("sti %0;" : : "d"(bfin_irq_flags)); \ - } while (0) - -#define local_irq_save_hw(x) \ - do { \ - __save_and_cli_hw(x); \ - if (local_test_iflag_hw(x)) \ - ipipe_trace_begin(0x80000001); \ - } while (0) - -#define local_irq_restore_hw(x) \ - do { \ - if (local_test_iflag_hw(x)) { \ - ipipe_trace_end(0x80000001); \ - local_irq_enable_hw_notrace(); \ - } \ - } while (0) - -#define local_irq_disable_hw_notrace() \ - do { \ - int _tmp_dummy; \ - __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : ); \ - } while (0) - -#define local_irq_enable_hw_notrace() \ - __asm__ __volatile__( \ - "sti %0;" \ - : \ - : "d"(bfin_irq_flags) \ - ) - -#define local_irq_save_hw_notrace(x) __save_and_cli_hw(x) - -#define local_irq_restore_hw_notrace(x) \ - do { \ - if (local_test_iflag_hw(x)) \ - local_irq_enable_hw_notrace(); \ - } while (0) - -#else /* CONFIG_IPIPE_TRACE_IRQSOFF */ - -#define local_irq_enable_hw() \ - __asm__ __volatile__( \ - "sti %0;" \ - : \ - : "d"(bfin_irq_flags) \ - ) - -#define local_irq_disable_hw() \ - do { \ - int _tmp_dummy; \ - __asm__ __volatile__ ( \ - "cli %0;" \ - : "=d" (_tmp_dummy)); \ - } while (0) - -#define local_irq_restore_hw(x) \ - do { \ - if (irqs_enabled_from_flags_hw(x)) \ - local_irq_enable_hw(); \ - } while (0) - -#define local_irq_save_hw(x) __save_and_cli_hw(x) - -#define local_irq_disable_hw_notrace() local_irq_disable_hw() -#define local_irq_enable_hw_notrace() local_irq_enable_hw() -#define local_irq_save_hw_notrace(x) local_irq_save_hw(x) -#define local_irq_restore_hw_notrace(x) local_irq_restore_hw(x) - -#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */ - -#else /* !CONFIG_IPIPE */ - -/* - * Interrupt configuring macros. - */ -#define local_irq_disable() \ - do { \ - int __tmp_dummy; \ - __asm__ __volatile__( \ - "cli %0;" \ - : "=d" (__tmp_dummy) \ - ); \ - } while (0) - -#define local_irq_enable() \ - __asm__ __volatile__( \ - "sti %0;" \ - : \ - : "d" (bfin_irq_flags) \ - ) - -#ifdef CONFIG_DEBUG_HWERR -# define __save_and_cli(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - "sti %1;" \ - : "=&d" (x) \ - : "d" (0x3F) \ - ) -#else -# define __save_and_cli(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - : "=&d" (x) \ - ) -#endif - -#define local_save_flags(x) \ - __asm__ __volatile__( \ - "cli %0;" \ - "sti %0;" \ - : "=d" (x) \ - ) - -#ifdef CONFIG_DEBUG_HWERR -#define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0) -#else -#define irqs_enabled_from_flags(x) ((x) != 0x1f) -#endif - -#define local_irq_restore(x) \ - do { \ - if (irqs_enabled_from_flags(x)) \ - local_irq_enable(); \ - } while (0) - -/* For spinlocks etc */ -#define local_irq_save(x) __save_and_cli(x) - -#define irqs_disabled() \ -({ \ - unsigned long flags; \ - local_save_flags(flags); \ - !irqs_enabled_from_flags(flags); \ -}) - -#define local_irq_save_hw(x) local_irq_save(x) -#define local_irq_restore_hw(x) local_irq_restore(x) -#define local_irq_enable_hw() local_irq_enable() -#define local_irq_disable_hw() local_irq_disable() -#define irqs_disabled_hw() irqs_disabled() +/* SYS_IRQS and NR_IRQS are defined in */ +#include -#endif /* !CONFIG_IPIPE */ +/* Xenomai IPIPE helpers */ +#define local_irq_restore_hw(x) local_irq_restore(x) +#define local_irq_save_hw(x) local_irq_save(x) +#define local_irq_enable_hw(x) local_irq_enable(x) +#define local_irq_disable_hw(x) local_irq_disable(x) +#define irqs_disabled_hw(x) irqs_disabled(x) #if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE) # define NOP_PAD_ANOMALY_05000244 "nop; nop;" diff --git a/arch/blackfin/include/asm/irqflags.h b/arch/blackfin/include/asm/irqflags.h new file mode 100644 index 0000000..139cba4 --- /dev/null +++ b/arch/blackfin/include/asm/irqflags.h @@ -0,0 +1,63 @@ +/* + * interface to Blackfin CEC + * + * Copyright 2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#ifndef __ASM_BFIN_IRQFLAGS_H__ +#define __ASM_BFIN_IRQFLAGS_H__ + +#ifdef CONFIG_SMP +# include +# include +/* Forward decl needed due to cdef inter dependencies */ +static inline uint32_t __pure bfin_dspid(void); +# define blackfin_core_id() (bfin_dspid() & 0xff) +# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask +#else +extern unsigned long bfin_irq_flags; +#endif + +static inline void bfin_sti(unsigned long flags) +{ + asm volatile("sti %0;" : : "d" (flags)); +} + +static inline unsigned long bfin_cli(void) +{ + unsigned long flags; + asm volatile("cli %0;" : "=d" (flags)); + return flags; +} + +static inline void raw_local_irq_disable(void) +{ + bfin_cli(); +} +static inline void raw_local_irq_enable(void) +{ + bfin_sti(bfin_irq_flags); +} + +#define raw_local_save_flags(flags) do { (flags) = bfin_read_IMASK(); } while (0) + +#define raw_irqs_disabled_flags(flags) (((flags) & ~0x3f) == 0) + +static inline void raw_local_irq_restore(unsigned long flags) +{ + if (!raw_irqs_disabled_flags(flags)) + raw_local_irq_enable(); +} + +static inline unsigned long __raw_local_irq_save(void) +{ + unsigned long flags = bfin_cli(); +#ifdef CONFIG_DEBUG_HWERR + bfin_sti(0x3f); +#endif + return flags; +} +#define raw_local_irq_save(flags) do { (flags) = __raw_local_irq_save(); } while (0) + +#endif diff --git a/arch/blackfin/include/asm/system.h b/arch/blackfin/include/asm/system.h index a4c8254..294dbda 100644 --- a/arch/blackfin/include/asm/system.h +++ b/arch/blackfin/include/asm/system.h @@ -35,10 +35,10 @@ #define _BLACKFIN_SYSTEM_H #include -#include +#include #include +#include #include -#include #include /* -- cgit v0.10.2 From e38eb89210ce7171291e4164c24b8d1e6c5385ea Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 8 Jun 2009 18:11:21 -0400 Subject: Blackfin: punt unused/wrong mutex-dec.h Looks like the mutex-dec.h header file was incorrectly copied into the Blackfin asm path. Nothing uses it, so punt it. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/mutex-dec.h b/arch/blackfin/include/asm/mutex-dec.h deleted file mode 100644 index 0134151..0000000 --- a/arch/blackfin/include/asm/mutex-dec.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * include/asm-generic/mutex-dec.h - * - * Generic implementation of the mutex fastpath, based on atomic - * decrement/increment. - */ -#ifndef _ASM_GENERIC_MUTEX_DEC_H -#define _ASM_GENERIC_MUTEX_DEC_H - -/** - * __mutex_fastpath_lock - try to take the lock by moving the count - * from 1 to a 0 value - * @count: pointer of type atomic_t - * @fail_fn: function to call if the original value was not 1 - * - * Change the count from 1 to a value lower than 1, and call if - * it wasn't 1 originally. This function MUST leave the value lower than - * 1 even when the "1" assertion wasn't true. - */ -static inline void -__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *)) -{ - if (unlikely(atomic_dec_return(count) < 0)) - fail_fn(count); - else - smp_mb(); -} - -/** - * __mutex_fastpath_lock_retval - try to take the lock by moving the count - * from 1 to a 0 value - * @count: pointer of type atomic_t - * @fail_fn: function to call if the original value was not 1 - * - * Change the count from 1 to a value lower than 1, and call if - * it wasn't 1 originally. This function returns 0 if the fastpath succeeds, - * or anything the slow path function returns. - */ -static inline int -__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *)) -{ - if (unlikely(atomic_dec_return(count) < 0)) - return fail_fn(count); - else { - smp_mb(); - return 0; - } -} - -/** - * __mutex_fastpath_unlock - try to promote the count from 0 to 1 - * @count: pointer of type atomic_t - * @fail_fn: function to call if the original value was not 0 - * - * Try to promote the count from 0 to 1. If it wasn't 0, call . - * In the failure case, this function is allowed to either set the value to - * 1, or to set it to a value lower than 1. - * - * If the implementation sets it to a value of lower than 1, then the - * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs - * to return 0 otherwise. - */ -static inline void -__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *)) -{ - smp_mb(); - if (unlikely(atomic_inc_return(count) <= 0)) - fail_fn(count); -} - -#define __mutex_slowpath_needs_to_unlock() 1 - -/** - * __mutex_fastpath_trylock - try to acquire the mutex, without waiting - * - * @count: pointer of type atomic_t - * @fail_fn: fallback function - * - * Change the count from 1 to a value lower than 1, and return 0 (failure) - * if it wasn't 1 originally, or return 1 (success) otherwise. This function - * MUST leave the value lower than 1 even when the "1" assertion wasn't true. - * Additionally, if the value was < 0 originally, this function must not leave - * it to 0 on failure. - * - * If the architecture has no effective trylock variant, it should call the - * spinlock-based trylock variant unconditionally. - */ -static inline int -__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) -{ - /* - * We have two variants here. The cmpxchg based one is the best one - * because it never induce a false contention state. It is included - * here because architectures using the inc/dec algorithms over the - * xchg ones are much more likely to support cmpxchg natively. - * - * If not we fall back to the spinlock based variant - that is - * just as efficient (and simpler) as a 'destructive' probing of - * the mutex state would be. - */ -#ifdef __HAVE_ARCH_CMPXCHG - if (likely(atomic_cmpxchg(count, 1, 0) == 1)) { - smp_mb(); - return 1; - } - return 0; -#else - return fail_fn(count); -#endif -} - -#endif -- cgit v0.10.2 From 5203fa82f3907a9c3357f84aa1cdfb57e55cc175 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 8 Jun 2009 18:40:28 -0400 Subject: Blackfin: move custom sections into sections.h The Blackfin arch has a bunch of custom section markings for its on-chip regions, but they aren't declared in the right header. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h index daffc06..e39277e 100644 --- a/arch/blackfin/include/asm/bfin-global.h +++ b/arch/blackfin/include/asm/bfin-global.h @@ -31,7 +31,7 @@ #ifndef __ASSEMBLY__ -#include +#include #include #include #include @@ -99,15 +99,6 @@ extern const char bfin_board_name[]; extern unsigned long bfin_sic_iwr[]; extern unsigned vr_wakeup; extern u16 _bfin_swrst; /* shadow for Software Reset Register (SWRST) */ -extern unsigned long _ramstart, _ramend, _rambase; -extern unsigned long memory_start, memory_end, physical_mem_end; -extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[], - _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _sbss_b_l1[], _ebss_b_l1[], - _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[], - _ebss_l2[], _l2_lma_start[]; - -/* only used when MTD_UCLINUX */ -extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size; #ifdef CONFIG_BFIN_ICACHE_LOCK extern void cache_grab_lock(int way); diff --git a/arch/blackfin/include/asm/sections.h b/arch/blackfin/include/asm/sections.h index 1443c33..e7fd0ec 100644 --- a/arch/blackfin/include/asm/sections.h +++ b/arch/blackfin/include/asm/sections.h @@ -4,4 +4,15 @@ /* nothing to see, move along */ #include +/* only used when MTD_UCLINUX */ +extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size; + +extern unsigned long _ramstart, _ramend, _rambase; +extern unsigned long memory_start, memory_end, physical_mem_end; + +extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[], + _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _sbss_b_l1[], _ebss_b_l1[], + _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[], + _ebss_l2[], _l2_lma_start[]; + #endif -- cgit v0.10.2 From c7b412f41d9c95d084e049fe83248ebb41a2d8f5 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 8 Jun 2009 18:44:45 -0400 Subject: Blackfin: add preliminary support for STACKTRACE Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index d68cb0d..77ec14f 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -55,6 +55,9 @@ config FORCE_MAX_ZONEORDER config GENERIC_CALIBRATE_DELAY def_bool y +config STACKTRACE_SUPPORT + def_bool y + config TRACE_IRQFLAGS_SUPPORT def_bool y diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index fd4d432..a66dda4 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KGDB_TESTS) += kgdb_test.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_STACKTRACE) += stacktrace.o # the kgdb test puts code into L2 and without linker # relaxation, we need to force long calls to/from it diff --git a/arch/blackfin/kernel/stacktrace.c b/arch/blackfin/kernel/stacktrace.c new file mode 100644 index 0000000..30301e1 --- /dev/null +++ b/arch/blackfin/kernel/stacktrace.c @@ -0,0 +1,53 @@ +/* + * Blackfin stacktrace code (mostly copied from avr32) + * + * Copyright 2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +register unsigned long current_frame_pointer asm("FP"); + +struct stackframe { + unsigned long fp; + unsigned long rets; +}; + +/* + * Save stack-backtrace addresses into a stack_trace buffer. + */ +void save_stack_trace(struct stack_trace *trace) +{ + unsigned long low, high; + unsigned long fp; + struct stackframe *frame; + int skip = trace->skip; + + low = (unsigned long)task_stack_page(current); + high = low + THREAD_SIZE; + fp = current_frame_pointer; + + while (fp >= low && fp <= (high - sizeof(*frame))) { + frame = (struct stackframe *)fp; + + if (skip) { + skip--; + } else { + trace->entries[trace->nr_entries++] = frame->rets; + if (trace->nr_entries >= trace->max_entries) + break; + } + + /* + * The next frame must be at a higher address than the + * current frame. + */ + low = fp + sizeof(*frame); + fp = frame->fp; + } +} +EXPORT_SYMBOL_GPL(save_stack_trace); -- cgit v0.10.2 From 6fa68e7a7f0641e8b7f263141d600877cdc2b5f2 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 8 Jun 2009 18:45:01 -0400 Subject: Blackfin: enable support for LOCKDEP Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 77ec14f..d03fd63 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -55,6 +55,9 @@ config FORCE_MAX_ZONEORDER config GENERIC_CALIBRATE_DELAY def_bool y +config LOCKDEP_SUPPORT + def_bool y + config STACKTRACE_SUPPORT def_bool y -- cgit v0.10.2 From 1c873be744410e26fb91ee9228c90adff6eabe15 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 9 Jun 2009 07:25:09 -0400 Subject: Blackfin: initial support for ftrace Just the basic ftrace support here -- mcount and the ftrace stub. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index d03fd63..ea8d92c 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -19,6 +19,7 @@ config RWSEM_XCHGADD_ALGORITHM config BLACKFIN def_bool y + select HAVE_FUNCTION_TRACER select HAVE_IDE select HAVE_KERNEL_GZIP select HAVE_KERNEL_BZIP2 diff --git a/arch/blackfin/include/asm/ftrace.h b/arch/blackfin/include/asm/ftrace.h index 40a8c17..8643680 100644 --- a/arch/blackfin/include/asm/ftrace.h +++ b/arch/blackfin/include/asm/ftrace.h @@ -1 +1,13 @@ -/* empty */ +/* + * Blackfin ftrace code + * + * Copyright 2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#ifndef __ASM_BFIN_FTRACE_H__ +#define __ASM_BFIN_FTRACE_H__ + +#define MCOUNT_INSN_SIZE 8 /* sizeof mcount call: LINK + CALL */ + +#endif diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index a66dda4..d2ae285 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -15,6 +15,7 @@ else obj-y += time.o endif +obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o obj-$(CONFIG_IPIPE) += ipipe.o obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index 53e893f..aa05e63 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c @@ -103,3 +103,8 @@ EXPORT_SYMBOL(__raw_smp_mark_barrier_asm); EXPORT_SYMBOL(__raw_smp_check_barrier_asm); #endif #endif + +#ifdef CONFIG_FUNCTION_TRACER +extern void _mcount(void); +EXPORT_SYMBOL(_mcount); +#endif diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S new file mode 100644 index 0000000..ce71487 --- /dev/null +++ b/arch/blackfin/kernel/ftrace-entry.S @@ -0,0 +1,72 @@ +/* + * mcount and friends -- ftrace stuff + * + * Copyright (C) 2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#include +#include + +.text + +/* GCC will have called us before setting up the function prologue, so we + * can clobber the normal scratch registers, but we need to make sure to + * save/restore the registers used for argument passing (R0-R2) in case + * the profiled function is using them. With data registers, R3 is the + * only one we can blow away. With pointer registers, we have P0-P2. + * + * Upon entry, the RETS will point to the top of the current profiled + * function. And since GCC setup the frame for us, the previous function + * will be waiting there. mmmm pie. + */ +ENTRY(__mcount) + /* save third function arg early so we can do testing below */ + [--sp] = r2; + + /* load the function pointer to the tracer */ + p0.l = _ftrace_trace_function; + p0.h = _ftrace_trace_function; + r3 = [p0]; + + /* optional micro optimization: don't call the stub tracer */ + r2.l = _ftrace_stub; + r2.h = _ftrace_stub; + cc = r2 == r3; + if ! cc jump .Ldo_trace; + + r2 = [sp++]; + rts; + +.Ldo_trace: + + /* save first/second function arg and the return register */ + [--sp] = r0; + [--sp] = r1; + [--sp] = rets; + + /* setup the tracer function */ + p0 = r3; + + /* tracer(ulong frompc, ulong selfpc): + * frompc: the pc that did the call to ... + * selfpc: ... this location + * the selfpc itself will need adjusting for the mcount call + */ + r1 = rets; + r0 = [fp + 4]; + r1 += -MCOUNT_INSN_SIZE; + + /* call the tracer */ + call (p0); + + /* restore state and get out of dodge */ + rets = [sp++]; + r1 = [sp++]; + r0 = [sp++]; + r2 = [sp++]; + +.globl _ftrace_stub +_ftrace_stub: + rts; +ENDPROC(__mcount) -- cgit v0.10.2 From 1ee76d7e169ff2b0ff1df4b40b9d5276eec9ffb4 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 10 Jun 2009 04:45:29 -0400 Subject: Blackfin: initial support for ftrace grapher Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index ea8d92c..5bc1360 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -19,6 +19,7 @@ config RWSEM_XCHGADD_ALGORITHM config BLACKFIN def_bool y + select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER select HAVE_IDE select HAVE_KERNEL_GZIP diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index d2ae285..3731088 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -16,6 +16,9 @@ else endif obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o +obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o +CFLAGS_REMOVE_ftrace.o = -pg + obj-$(CONFIG_IPIPE) += ipipe.o obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S index ce71487..6980b7a 100644 --- a/arch/blackfin/kernel/ftrace-entry.S +++ b/arch/blackfin/kernel/ftrace-entry.S @@ -35,6 +35,28 @@ ENTRY(__mcount) cc = r2 == r3; if ! cc jump .Ldo_trace; +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + /* if the ftrace_graph_return function pointer is not set to + * the ftrace_stub entry, call prepare_ftrace_return(). + */ + p0.l = _ftrace_graph_return; + p0.h = _ftrace_graph_return; + r3 = [p0]; + cc = r2 == r3; + if ! cc jump _ftrace_graph_caller; + + /* similarly, if the ftrace_graph_entry function pointer is not + * set to the ftrace_graph_entry_stub entry, ... + */ + p0.l = _ftrace_graph_entry; + p0.h = _ftrace_graph_entry; + r2.l = _ftrace_graph_entry_stub; + r2.h = _ftrace_graph_entry_stub; + r3 = [p0]; + cc = r2 == r3; + if ! cc jump _ftrace_graph_caller; +#endif + r2 = [sp++]; rts; @@ -61,6 +83,7 @@ ENTRY(__mcount) call (p0); /* restore state and get out of dodge */ +.Lfinish_trace: rets = [sp++]; r1 = [sp++]; r0 = [sp++]; @@ -70,3 +93,48 @@ ENTRY(__mcount) _ftrace_stub: rts; ENDPROC(__mcount) + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +/* The prepare_ftrace_return() function is similar to the trace function + * except it takes a pointer to the location of the frompc. This is so + * the prepare_ftrace_return() can hijack it temporarily for probing + * purposes. + */ +ENTRY(_ftrace_graph_caller) + /* save first/second function arg and the return register */ + [--sp] = r0; + [--sp] = r1; + [--sp] = rets; + + r0 = fp; + r1 = rets; + r0 += 4; + r1 += -MCOUNT_INSN_SIZE; + call _prepare_ftrace_return; + + jump .Lfinish_trace; +ENDPROC(_ftrace_graph_caller) + +/* Undo the rewrite caused by ftrace_graph_caller(). The common function + * ftrace_return_to_handler() will return the original rets so we can + * restore it and be on our way. + */ +ENTRY(_return_to_handler) + /* make sure original return values are saved */ + [--sp] = p0; + [--sp] = r0; + [--sp] = r1; + + /* get original return address */ + call _ftrace_return_to_handler; + rets = r0; + + /* anomaly 05000371 - make sure we have at least three instructions + * between rets setting and the return + */ + r1 = [sp++]; + r0 = [sp++]; + p0 = [sp++]; + rts; +ENDPROC(_return_to_handler) +#endif diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c new file mode 100644 index 0000000..905bfc4 --- /dev/null +++ b/arch/blackfin/kernel/ftrace.c @@ -0,0 +1,42 @@ +/* + * ftrace graph code + * + * Copyright (C) 2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +/* + * Hook the return address and push it in the stack of return addrs + * in current thread info. + */ +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) +{ + struct ftrace_graph_ent trace; + unsigned long return_hooker = (unsigned long)&return_to_handler; + + if (unlikely(atomic_read(¤t->tracing_graph_pause))) + return; + + if (ftrace_push_return_trace(*parent, self_addr, &trace.depth) == -EBUSY) + return; + + trace.func = self_addr; + + /* Only trace if the calling function expects to */ + if (!ftrace_graph_entry(&trace)) { + current->curr_ret_stack--; + return; + } + + /* all is well in the world ! hijack RETS ... */ + *parent = return_hooker; +} + +#endif diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index 119fbdb..6ac307c 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -54,6 +54,7 @@ SECTIONS SCHED_TEXT #endif LOCK_TEXT + IRQENTRY_TEXT KPROBES_TEXT *(.text.*) *(.fixup) -- cgit v0.10.2 From d0cb9b4ef680c518087b019e29fe5c2eca9a0740 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 11 Jun 2009 21:52:35 +0000 Subject: Blackfin: improve CLKIN_HZ config default Most boards use 25000000 as the default HZ, so rather than add a whole bunch more boards, make it the default for everyone. This also fixes randconfig builds as there was no default before. Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 5bc1360..26e4858 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -414,12 +414,12 @@ comment "Clock/PLL Setup" config CLKIN_HZ int "Frequency of the crystal on the board in Hz" + default "10000000" if BFIN532_IP0X default "11059200" if BFIN533_STAMP + default "24576000" if PNAV10 + default "25000000" # most people use this default "27000000" if BFIN533_EZKIT - default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD || BFIN538_EZKIT || BFIN518F-EZBRD) default "30000000" if BFIN561_EZKIT - default "24576000" if PNAV10 - default "10000000" if BFIN532_IP0X help The frequency of CLKIN crystal oscillator on the board in Hz. Warning: This value should match the crystal on the board. Otherwise, -- cgit v0.10.2 From 61cdd7a28f8b515140cb5d8aea518678f0fae024 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 12 Jun 2009 07:30:55 -0400 Subject: Blackfin: hook up new rt_tgsigqueueinfo syscall Signed-off-by: Mike Frysinger diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h index cf5066d..da35133 100644 --- a/arch/blackfin/include/asm/unistd.h +++ b/arch/blackfin/include/asm/unistd.h @@ -380,8 +380,9 @@ #define __NR_inotify_init1 365 #define __NR_preadv 366 #define __NR_pwritev 367 +#define __NR_rt_tgsigqueueinfo 368 -#define __NR_syscall 368 +#define __NR_syscall 369 #define NR_syscalls __NR_syscall /* Old optional stuff no one actually uses */ diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 25c6aa4..31fa313 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -1608,6 +1608,7 @@ ENTRY(_sys_call_table) .long _sys_inotify_init1 /* 365 */ .long _sys_preadv .long _sys_pwritev + .long _sys_rt_tgsigqueueinfo .rept NR_syscalls-(.-_sys_call_table)/4 .long _sys_ni_syscall -- cgit v0.10.2 From 5ba73683ba5223b218b26f878663e3907e85eedc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 13 Jun 2009 11:14:55 +0100 Subject: ASoC: Revert duplicated code in SSM2602 driver The Blackfin submission was done as a patch against a different tree and contained a duplicate hunk which will cause us to loose track of the substream pointers when shutting down. Remove one of the duplicated hunks. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 1fc4c8e..c550750 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -375,10 +375,6 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; struct ssm2602_priv *ssm2602 = codec->private_data; - if (ssm2602->master_substream == substream) - ssm2602->master_substream = ssm2602->slave_substream; - - ssm2602->slave_substream = NULL; /* deactivate */ if (!codec->active) ssm2602_write(codec, SSM2602_ACTIVE, 0); -- cgit v0.10.2 From d2991f75354941a4cdf61ce7443d21804b978f89 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:44 +0000 Subject: bonding: bond_create always called with default parameters bond_create() is always called with same parameters so move the argument down. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2f4329e..a1fa8de 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -101,7 +101,7 @@ static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; static char *arp_validate = NULL; static char *fail_over_mac = NULL; -struct bond_params bonding_defaults; +static struct bond_params bonding_defaults; module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); @@ -4592,7 +4592,7 @@ static const struct net_device_ops bond_netdev_ops = { * Does not allocate but creates a /proc entry. * Allowed to fail. */ -static int bond_init(struct net_device *bond_dev, struct bond_params *params) +static int bond_init(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); @@ -4602,7 +4602,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) rwlock_init(&bond->lock); rwlock_init(&bond->curr_slave_lock); - bond->params = *params; /* copy params struct */ + bond->params = bonding_defaults; bond->wq = create_singlethread_workqueue(bond_dev->name); if (!bond->wq) @@ -5116,7 +5116,7 @@ static void bond_set_lockdep_class(struct net_device *dev) * Caller must NOT hold rtnl_lock; we need to release it here before we * set up our sysfs entries. */ -int bond_create(char *name, struct bond_params *params) +int bond_create(const char *name) { struct net_device *bond_dev; struct bonding *bond; @@ -5159,7 +5159,7 @@ int bond_create(char *name, struct bond_params *params) * need to set function pointers. */ - res = bond_init(bond_dev, params); + res = bond_init(bond_dev); if (res < 0) { goto out_netdev; } @@ -5212,7 +5212,7 @@ static int __init bonding_init(void) init_rwsem(&bonding_rwsem); for (i = 0; i < max_bonds; i++) { - res = bond_create(NULL, &bonding_defaults); + res = bond_create(NULL); if (res) goto err; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 5fb861a..1172fe6 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -112,7 +112,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t if (command[0] == '+') { printk(KERN_INFO DRV_NAME ": %s is being created...\n", ifname); - rv = bond_create(ifname, &bonding_defaults); + rv = bond_create(ifname); if (rv) { printk(KERN_INFO DRV_NAME ": Bond creation failed.\n"); res = rv; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 41ceca1..a6efa09 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -321,7 +321,7 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); -int bond_create(char *name, struct bond_params *params); +int bond_create(const char *name); void bond_destroy(struct bonding *bond); int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); int bond_create_sysfs(void); @@ -349,7 +349,6 @@ extern const struct bond_parm_tbl bond_mode_tbl[]; extern const struct bond_parm_tbl xmit_hashtype_tbl[]; extern const struct bond_parm_tbl arp_validate_tbl[]; extern const struct bond_parm_tbl fail_over_mac_tbl[]; -extern struct bond_params bonding_defaults; extern struct bond_parm_tbl ad_select_tbl[]; /* exported from bond_sysfs.c */ -- cgit v0.10.2 From d93216051ae60995736518ca9ebb58a0e6ade212 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:45 +0000 Subject: bonding: initialize before registration Avoid a unnecessary carrier state transistion that happens when device is registered. Lockdep works better if initialization is done before registration as well. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a1fa8de..99ddd28 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5164,15 +5164,15 @@ int bond_create(const char *name) goto out_netdev; } + bond_set_lockdep_class(bond_dev); + + netif_carrier_off(bond_dev); + res = register_netdevice(bond_dev); if (res < 0) { goto out_bond; } - bond_set_lockdep_class(bond_dev); - - netif_carrier_off(bond_dev); - up_write(&bonding_rwsem); rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(netdev_priv(bond_dev)); -- cgit v0.10.2 From 7e0838404541d2758bee089632690aabd82f3d5d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:46 +0000 Subject: bonding: remove bonding read/write semaphore The whole read/write semaphore locking can be removed. It doesn't add any protection that isn't already done by using the RTNL mutex properly. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 99ddd28..23b832f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3489,10 +3489,10 @@ static int bond_event_changename(struct bonding *bond) { bond_remove_proc_entry(bond); bond_create_proc_entry(bond); - down_write(&(bonding_rwsem)); + bond_destroy_sysfs_entry(bond); bond_create_sysfs_entry(bond); - up_write(&(bonding_rwsem)); + return NOTIFY_DONE; } @@ -4015,7 +4015,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd return -EPERM; } - down_write(&(bonding_rwsem)); slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); pr_debug("slave_dev=%p: \n", slave_dev); @@ -4048,7 +4047,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd dev_put(slave_dev); } - up_write(&(bonding_rwsem)); return res; } @@ -5123,8 +5121,6 @@ int bond_create(const char *name) int res; rtnl_lock(); - down_write(&bonding_rwsem); - /* Check to see if the bond already exists. */ if (name) { list_for_each_entry(bond, &bond_dev_list, bond_list) @@ -5173,24 +5169,20 @@ int bond_create(const char *name) goto out_bond; } - up_write(&bonding_rwsem); - rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(netdev_priv(bond_dev)); if (res < 0) goto out_unreg; + rtnl_unlock(); return 0; out_unreg: - rtnl_lock(); - down_write(&bonding_rwsem); unregister_netdevice(bond_dev); out_bond: bond_deinit(bond_dev); out_netdev: free_netdev(bond_dev); out_rtnl: - up_write(&bonding_rwsem); rtnl_unlock(); return res; } @@ -5209,8 +5201,6 @@ static int __init bonding_init(void) bond_create_proc_dir(); - init_rwsem(&bonding_rwsem); - for (i = 0; i < max_bonds; i++) { res = bond_create(NULL); if (res) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 1172fe6..8041b67 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -44,20 +44,6 @@ /*---------------------------- Declarations -------------------------------*/ static int expected_refcount = -1; -/*--------------------------- Data Structures -----------------------------*/ - -/* Bonding sysfs lock. Why can't we just use the subsystem lock? - * Because kobject_register tries to acquire the subsystem lock. If - * we already hold the lock (which we would if the user was creating - * a new bond through the sysfs interface), we deadlock. - * This lock is only needed when deleting a bond - we need to make sure - * that we don't collide with an ongoing ioctl. - */ - -struct rw_semaphore bonding_rwsem; - - - /*------------------------------ Functions --------------------------------*/ @@ -70,7 +56,7 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) int res = 0; struct bonding *bond; - down_read(&(bonding_rwsem)); + rtnl_lock(); list_for_each_entry(bond, &bond_dev_list, bond_list) { if (res > (PAGE_SIZE - IFNAMSIZ)) { @@ -84,7 +70,8 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) } if (res) buf[res-1] = '\n'; /* eat the leftover space */ - up_read(&(bonding_rwsem)); + + rtnl_unlock(); return res; } @@ -122,7 +109,6 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t if (command[0] == '-') { rtnl_lock(); - down_write(&bonding_rwsem); list_for_each_entry(bond, &bond_dev_list, bond_list) if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { @@ -157,7 +143,6 @@ err_no_cmd: return -EPERM; out_unlock: - up_write(&bonding_rwsem); rtnl_unlock(); /* Always return either count or an error. If you return 0, you'll @@ -253,7 +238,6 @@ static ssize_t bonding_store_slaves(struct device *d, if (!rtnl_trylock()) return restart_syscall(); - down_write(&(bonding_rwsem)); sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; @@ -357,7 +341,6 @@ err_no_cmd: ret = -EPERM; out: - up_write(&(bonding_rwsem)); rtnl_unlock(); return ret; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a6efa09..af81e9b 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -351,9 +351,6 @@ extern const struct bond_parm_tbl arp_validate_tbl[]; extern const struct bond_parm_tbl fail_over_mac_tbl[]; extern struct bond_parm_tbl ad_select_tbl[]; -/* exported from bond_sysfs.c */ -extern struct rw_semaphore bonding_rwsem; - #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) void bond_send_unsolicited_na(struct bonding *bond); void bond_register_ipv6_notifier(void); -- cgit v0.10.2 From 9e71626c1c23ec69372c43c6fe66c1171032bf42 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:47 +0000 Subject: bonding: fix destructor It is not safe to use a network device destructor that is a function in the module, since it can be called after module is unloaded if sysfs handle is open. When eventually using netlink, the device cleanup code needs to be done via uninit function. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 23b832f..2fc3561 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1972,25 +1972,19 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) * Destroy a bonding device. * Must be under rtnl_lock when this function is called. */ -void bond_destroy(struct bonding *bond) -{ - bond_deinit(bond->dev); - bond_destroy_sysfs_entry(bond); - unregister_netdevice(bond->dev); -} - -static void bond_destructor(struct net_device *bond_dev) +static void bond_uninit(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); + bond_deinit(bond_dev); + bond_destroy_sysfs_entry(bond); + if (bond->wq) destroy_workqueue(bond->wq); netif_addr_lock_bh(bond_dev); bond_mc_list_destroy(bond); netif_addr_unlock_bh(bond_dev); - - free_netdev(bond_dev); } /* @@ -2006,7 +2000,7 @@ int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *sl if ((ret == 0) && (bond->slave_cnt == 0)) { printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n", bond_dev->name, bond_dev->name); - bond_destroy(bond); + unregister_netdevice(bond_dev); } return ret; } @@ -4572,6 +4566,7 @@ static const struct ethtool_ops bond_ethtool_ops = { }; static const struct net_device_ops bond_netdev_ops = { + .ndo_uninit = bond_uninit, .ndo_open = bond_open, .ndo_stop = bond_close, .ndo_start_xmit = bond_start_xmit, @@ -4622,7 +4617,7 @@ static int bond_init(struct net_device *bond_dev) bond_dev->ethtool_ops = &bond_ethtool_ops; bond_set_mode_ops(bond, bond->params.mode); - bond_dev->destructor = bond_destructor; + bond_dev->destructor = free_netdev; /* Initialize the device options */ bond_dev->tx_queue_len = 0; @@ -4706,7 +4701,7 @@ static void bond_free_all(void) bond_work_cancel_all(bond); /* Release the bonded slaves */ bond_release_all(bond_dev); - bond_destroy(bond); + unregister_netdevice(bond_dev); } bond_destroy_proc_dir(); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 8041b67..7235759 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -127,7 +127,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t printk(KERN_INFO DRV_NAME ": %s is being deleted...\n", bond->dev->name); - bond_destroy(bond); + unregister_netdevice(bond->dev); goto out_unlock; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index af81e9b..6290a50 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -322,7 +322,6 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); int bond_create(const char *name); -void bond_destroy(struct bonding *bond); int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); int bond_create_sysfs(void); void bond_destroy_sysfs(void); -- cgit v0.10.2 From 3d632c3f28e69f0d6d44aa09c4df708d63a91a7c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:48 +0000 Subject: bonding: fix style issues Resolve some of the complaints from checkpatch, and remove "magic emacs format" comments, and useless MODULE_SUPPORTED_DEVICE(). But should not change actual code. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2fc3561..ea6b904 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -51,10 +51,10 @@ #include #include #include +#include #include -#include #include -#include +#include #include #include #include @@ -89,18 +89,18 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int num_grat_arp = 1; static int num_unsol_na = 1; static int miimon = BOND_LINK_MON_INTERV; -static int updelay = 0; -static int downdelay = 0; +static int updelay; +static int downdelay; static int use_carrier = 1; -static char *mode = NULL; -static char *primary = NULL; -static char *lacp_rate = NULL; -static char *ad_select = NULL; -static char *xmit_hash_policy = NULL; +static char *mode; +static char *primary; +static char *lacp_rate; +static char *ad_select; +static char *xmit_hash_policy; static int arp_interval = BOND_LINK_ARP_INTERV; -static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; -static char *arp_validate = NULL; -static char *fail_over_mac = NULL; +static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; +static char *arp_validate; +static char *fail_over_mac; static struct bond_params bonding_defaults; module_param(max_bonds, int, 0); @@ -151,14 +151,14 @@ static const char * const version = LIST_HEAD(bond_dev_list); #ifdef CONFIG_PROC_FS -static struct proc_dir_entry *bond_proc_dir = NULL; +static struct proc_dir_entry *bond_proc_dir; #endif -static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; -static int arp_ip_count = 0; +static __be32 arp_target[BOND_MAX_ARP_TARGETS]; +static int arp_ip_count; static int bond_mode = BOND_MODE_ROUNDROBIN; -static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2; -static int lacp_fast = 0; +static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2; +static int lacp_fast; const struct bond_parm_tbl bond_lacp_tbl[] = { @@ -221,7 +221,7 @@ static const char *bond_mode_name(int mode) [BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)", [BOND_MODE_XOR] = "load balancing (xor)", [BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)", - [BOND_MODE_8023AD]= "IEEE 802.3ad Dynamic link aggregation", + [BOND_MODE_8023AD] = "IEEE 802.3ad Dynamic link aggregation", [BOND_MODE_TLB] = "transmit load balancing", [BOND_MODE_ALB] = "adaptive load balancing", }; @@ -246,12 +246,11 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) struct vlan_entry *vlan; pr_debug("bond: %s, vlan id %d\n", - (bond ? bond->dev->name: "None"), vlan_id); + (bond ? bond->dev->name : "None"), vlan_id); vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL); - if (!vlan) { + if (!vlan) return -ENOMEM; - } INIT_LIST_HEAD(&vlan->vlan_list); vlan->vlan_id = vlan_id; @@ -351,16 +350,15 @@ static int bond_has_challenged_slaves(struct bonding *bond) * * Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL, * or @curr->next otherwise (even if it is @curr itself again). - * + * * Caller must hold bond->lock */ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) { struct vlan_entry *next, *last; - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) return NULL; - } if (!curr) { next = list_entry(bond->vlan_list.next, @@ -382,11 +380,11 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) /** * bond_dev_queue_xmit - Prepare skb for xmit. - * + * * @bond: bond device that got this skb for tx. * @skb: hw accel VLAN tagged skb to transmit * @slave_dev: slave that is supposed to xmit this skbuff - * + * * When the bond gets an skb to transmit that is * already hardware accelerated VLAN tagged, and it * needs to relay this skb to a slave that is not @@ -394,7 +392,8 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) * i.e. strip the hwaccel tag and re-insert it as part * of the payload. */ -int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev) +int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, + struct net_device *slave_dev) { unsigned short uninitialized_var(vlan_id); @@ -428,7 +427,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_de * b. The operation is protected by the RTNL semaphore in the 8021q code, * c. Holding a lock with BH disabled while directly calling a base driver * entry point is generally a BAD idea. - * + * * The design of synchronization/protection for this operation in the 8021q * module is good for one or more VLAN devices over a single physical device * and cannot be extended for a teaming solution like bonding, so there is a @@ -443,7 +442,8 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_de * @bond_dev: bonding net device that got called * @grp: vlan group being registered */ -static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp) +static void bond_vlan_rx_register(struct net_device *bond_dev, + struct vlan_group *grp) { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; @@ -485,7 +485,7 @@ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) res = bond_add_vlan(bond, vid); if (res) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to add vlan id %d\n", bond_dev->name, vid); } @@ -520,7 +520,7 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) res = bond_del_vlan(bond, vid); if (res) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to remove vlan id %d\n", bond_dev->name, vid); } @@ -551,7 +551,8 @@ out: write_unlock_bh(&bond->lock); } -static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev) +static void bond_del_vlans_from_slave(struct bonding *bond, + struct net_device *slave_dev) { const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct vlan_entry *vlan; @@ -673,7 +674,7 @@ static int bond_update_speed_duplex(struct slave *slave) * if supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), - * depening upon the setting of the use_carrier parameter. + * depending upon the setting of the use_carrier parameter. * * Return either BMSR_LSTATUS, meaning that the link is up (or we * can't tell and just pretend it is), or 0, meaning that the link is @@ -685,10 +686,11 @@ static int bond_update_speed_duplex(struct slave *slave) * It'd be nice if there was a good way to tell if a driver supports * netif_carrier, but there really isn't. */ -static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting) +static int bond_check_dev_link(struct bonding *bond, + struct net_device *slave_dev, int reporting) { const struct net_device_ops *slave_ops = slave_dev->netdev_ops; - static int (* ioctl)(struct net_device *, struct ifreq *, int); + static int (*ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; @@ -706,7 +708,7 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de } } - /* Ethtool can't be used, fallback to MII ioclts. */ + /* Ethtool can't be used, fallback to MII ioctls. */ ioctl = slave_ops->ndo_do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ @@ -726,9 +728,8 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de mii = if_mii(&ifr); if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; - if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { - return (mii->val_out & BMSR_LSTATUS); - } + if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) + return mii->val_out & BMSR_LSTATUS; } } @@ -738,7 +739,7 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de * cannot report link status). If not reporting, pretend * we're ok. */ - return (reporting ? -1 : BMSR_LSTATUS); + return reporting ? -1 : BMSR_LSTATUS; } /*----------------------------- Multicast list ------------------------------*/ @@ -746,7 +747,8 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de /* * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise */ -static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) +static inline int bond_is_dmi_same(const struct dev_mc_list *dmi1, + const struct dev_mc_list *dmi2) { return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && dmi1->dmi_addrlen == dmi2->dmi_addrlen; @@ -755,14 +757,14 @@ static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list /* * returns dmi entry if found, NULL otherwise */ -static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) +static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, + struct dev_mc_list *mc_list) { struct dev_mc_list *idmi; for (idmi = mc_list; idmi; idmi = idmi->next) { - if (bond_is_dmi_same(dmi, idmi)) { + if (bond_is_dmi_same(dmi, idmi)) return idmi; - } } return NULL; @@ -824,15 +826,14 @@ static void bond_mc_add(struct bonding *bond, void *addr, int alen) { if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ - if (bond->curr_active_slave) { + if (bond->curr_active_slave) dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0); - } } else { struct slave *slave; int i; - bond_for_each_slave(bond, slave, i) { + + bond_for_each_slave(bond, slave, i) dev_mc_add(slave->dev, addr, alen, 0); - } } } @@ -844,9 +845,9 @@ static void bond_mc_delete(struct bonding *bond, void *addr, int alen) { if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ - if (bond->curr_active_slave) { - dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0); - } + if (bond->curr_active_slave) + dev_mc_delete(bond->curr_active_slave->dev, addr, + alen, 0); } else { struct slave *slave; int i; @@ -870,9 +871,8 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) rcu_read_lock(); in_dev = __in_dev_get_rcu(bond->dev); if (in_dev) { - for (im = in_dev->mc_list; im; im = im->next) { + for (im = in_dev->mc_list; im; im = im->next) ip_mc_rejoin_group(im); - } } rcu_read_unlock(); @@ -891,7 +891,8 @@ static void bond_mc_list_destroy(struct bonding *bond) kfree(dmi); dmi = bond->mc_list; } - bond->mc_list = NULL; + + bond->mc_list = NULL; } /* @@ -924,14 +925,14 @@ static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, /* * flush all members of flush->mc_list from device dev->mc_list */ -static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) +static void bond_mc_list_flush(struct net_device *bond_dev, + struct net_device *slave_dev) { struct bonding *bond = netdev_priv(bond_dev); struct dev_mc_list *dmi; - for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } if (bond->params.mode == BOND_MODE_8023AD) { /* del lacpdu mc addr from mc list */ @@ -948,44 +949,40 @@ static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *s * old active slaves (if any) according to the multicast mode, and * promiscuous flags unconditionally. */ -static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active) +static void bond_mc_swap(struct bonding *bond, struct slave *new_active, + struct slave *old_active) { struct dev_mc_list *dmi; - if (!USES_PRIMARY(bond->params.mode)) { + if (!USES_PRIMARY(bond->params.mode)) /* nothing to do - mc list is already up-to-date on * all slaves */ return; - } if (old_active) { - if (bond->dev->flags & IFF_PROMISC) { + if (bond->dev->flags & IFF_PROMISC) dev_set_promiscuity(old_active->dev, -1); - } - if (bond->dev->flags & IFF_ALLMULTI) { + if (bond->dev->flags & IFF_ALLMULTI) dev_set_allmulti(old_active->dev, -1); - } - for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { - dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) + dev_mc_delete(old_active->dev, dmi->dmi_addr, + dmi->dmi_addrlen, 0); } if (new_active) { /* FIXME: Signal errors upstream. */ - if (bond->dev->flags & IFF_PROMISC) { + if (bond->dev->flags & IFF_PROMISC) dev_set_promiscuity(new_active->dev, 1); - } - if (bond->dev->flags & IFF_ALLMULTI) { + if (bond->dev->flags & IFF_ALLMULTI) dev_set_allmulti(new_active->dev, 1); - } - for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { - dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) + dev_mc_add(new_active->dev, dmi->dmi_addr, + dmi->dmi_addrlen, 0); bond_resend_igmp_join_requests(bond); } } @@ -1039,7 +1036,7 @@ static void bond_do_fail_over_mac(struct bonding *bond, rv = dev_set_mac_address(new_active->dev, &saddr); if (rv) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error %d setting MAC of slave %s\n", bond->dev->name, -rv, new_active->dev->name); goto out; @@ -1053,7 +1050,7 @@ static void bond_do_fail_over_mac(struct bonding *bond, rv = dev_set_mac_address(old_active->dev, &saddr); if (rv) - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error %d setting MAC of slave %s\n", bond->dev->name, -rv, new_active->dev->name); out: @@ -1061,7 +1058,7 @@ out: write_lock_bh(&bond->curr_slave_lock); break; default: - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: bond_do_fail_over_mac impossible: bad policy %d\n", bond->dev->name, bond->params.fail_over_mac); break; @@ -1086,17 +1083,17 @@ static struct slave *bond_find_best_slave(struct bonding *bond) new_active = old_active = bond->curr_active_slave; if (!new_active) { /* there were no active slaves left */ - if (bond->slave_cnt > 0) { /* found one slave */ + if (bond->slave_cnt > 0) /* found one slave */ new_active = bond->first_slave; - } else { + else return NULL; /* still no slave, return NULL */ - } } - /* first try the primary link; if arping, a link must tx/rx traffic - * before it can be considered the curr_active_slave - also, we would skip - * slaves between the curr_active_slave and primary_slave that may be up - * and able to arp + /* + * first try the primary link; if arping, a link must tx/rx + * traffic before it can be considered the curr_active_slave. + * also, we would skip slaves between the curr_active_slave + * and primary_slave that may be up and able to arp */ if ((bond->primary_slave) && (!bond->params.arp_interval) && @@ -1144,16 +1141,15 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { struct slave *old_active = bond->curr_active_slave; - if (old_active == new_active) { + if (old_active == new_active) return; - } if (new_active) { new_active->jiffies = jiffies; if (new_active->link == BOND_LINK_BACK) { if (USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: making interface %s the new " "active one %d ms earlier.\n", bond->dev->name, new_active->dev->name, @@ -1163,15 +1159,14 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) new_active->delay = 0; new_active->link = BOND_LINK_UP; - if (bond->params.mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) bond_3ad_handle_link_change(new_active, BOND_LINK_UP); - } if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); } else { if (USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: making interface %s the new " "active one.\n", bond->dev->name, new_active->dev->name); @@ -1179,9 +1174,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } } - if (USES_PRIMARY(bond->params.mode)) { + if (USES_PRIMARY(bond->params.mode)) bond_mc_swap(bond, new_active, old_active); - } if (bond_is_lb(bond)) { bond_alb_handle_active_change(bond, new_active); @@ -1194,9 +1188,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { - if (old_active) { + if (old_active) bond_set_slave_inactive_flags(old_active); - } if (new_active) { bond_set_slave_active_flags(new_active); @@ -1226,7 +1219,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) * bond_select_active_slave - select a new active slave, if needed * @bond: our bonding struct * - * This functions shoud be called when one of the following occurs: + * This functions should be called when one of the following occurs: * - The old curr_active_slave has been released or lost its link. * - The primary_slave has got its link back. * - A slave has got its link back and there's no old curr_active_slave. @@ -1246,11 +1239,11 @@ void bond_select_active_slave(struct bonding *bond) return; if (netif_carrier_ok(bond->dev)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: first active interface up!\n", bond->dev->name); } else { - printk(KERN_INFO DRV_NAME ": %s: " + pr_info(DRV_NAME ": %s: " "now running without any active interface !\n", bond->dev->name); } @@ -1292,13 +1285,11 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) */ static void bond_detach_slave(struct bonding *bond, struct slave *slave) { - if (slave->next) { + if (slave->next) slave->next->prev = slave->prev; - } - if (slave->prev) { + if (slave->prev) slave->prev->next = slave->next; - } if (bond->first_slave == slave) { /* slave is the first slave */ if (bond->slave_cnt > 1) { /* there are more slave */ @@ -1329,7 +1320,7 @@ static int bond_sethwaddr(struct net_device *bond_dev, (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \ NETIF_F_HW_VLAN_FILTER) -/* +/* * Compute the common dev->feature set available to all slaves. Some * feature bits are managed elsewhere, so preserve those feature bits * on the master device. @@ -1397,14 +1388,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL && slave_ops->ndo_do_ioctl == NULL) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: no link monitoring support for %s\n", bond_dev->name, slave_dev->name); } /* bond must be initialized by bond_open() before enslaving */ if (!(bond_dev->flags & IFF_UP)) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME " %s: master_dev is not up in bond_enslave\n", bond_dev->name); } @@ -1420,14 +1411,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); if (!list_empty(&bond->vlan_list)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: cannot enslave VLAN " "challenged slave %s on VLAN enabled " "bond %s\n", bond_dev->name, slave_dev->name, bond_dev->name); return -EPERM; } else { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: enslaved VLAN challenged " "slave %s. Adding VLANs will be blocked as " "long as %s is part of bond %s\n", @@ -1447,12 +1438,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* * Old ifenslave binaries are no longer supported. These can - * be identified with moderate accurary by the state of the slave: + * be identified with moderate accuracy by the state of the slave: * the current ifenslave will set the interface down prior to * enslaving it; the old ifenslave will not. */ if ((slave_dev->flags & IFF_UP)) { - printk(KERN_ERR DRV_NAME ": %s is up. " + pr_err(DRV_NAME ": %s is up. " "This may be due to an out of date ifenslave.\n", slave_dev->name); res = -EPERM; @@ -1470,7 +1461,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (slave_dev->type != ARPHRD_ETHER) bond_setup_by_slave(bond_dev, slave_dev); } else if (bond_dev->type != slave_dev->type) { - printk(KERN_ERR DRV_NAME ": %s ether type (%d) is different " + pr_err(DRV_NAME ": %s ether type (%d) is different " "from other slaves (%d), can not enslave it.\n", slave_dev->name, slave_dev->type, bond_dev->type); @@ -1480,14 +1471,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (slave_ops->ndo_set_mac_address == NULL) { if (bond->slave_cnt == 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: The first slave device " "specified does not support setting the MAC " "address. Setting fail_over_mac to active.", bond_dev->name); bond->params.fail_over_mac = BOND_FOM_ACTIVE; } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: The slave device specified " "does not support setting the MAC address, " "but fail_over_mac is not set to active.\n" @@ -1537,7 +1528,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { - pr_debug("Openning slave %s failed\n", slave_dev->name); + pr_debug("Opening slave %s failed\n", slave_dev->name); goto err_unset_master; } @@ -1549,9 +1540,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * it might fail and we do not want to have to undo everything */ res = bond_alb_init_slave(bond, new_slave); - if (res) { + if (res) goto err_close; - } } /* If the mode USES_PRIMARY, then the new slave gets the @@ -1576,9 +1566,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) netif_addr_lock_bh(bond_dev); /* upload master's mc_list to new slave */ - for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { - dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) + dev_mc_add(slave_dev, dmi->dmi_addr, + dmi->dmi_addrlen, 0); netif_addr_unlock_bh(bond_dev); } @@ -1619,7 +1609,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * supported); thus, we don't need to change * the messages for netif_carrier. */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: MII and ETHTOOL support not " "available for interface %s, and " "arp_interval/arp_ip_target module parameters " @@ -1628,7 +1618,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_dev->name, slave_dev->name); } else if (link_reporting == -1) { /* unable get link status using mii/ethtool */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: can't get link status from " "interface %s; the network driver associated " "with this interface does not support MII or " @@ -1660,13 +1650,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (bond_update_speed_duplex(new_slave) && (new_slave->link != BOND_LINK_DOWN)) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: failed to get speed and duplex from %s, " "assumed to be 100Mb/sec and Full.\n", bond_dev->name, new_slave->dev->name); if (bond->params.mode == BOND_MODE_8023AD) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: Operation of 802.3ad mode requires ETHTOOL " "support in base driver for proper aggregator " "selection.\n", bond_dev->name); @@ -1675,9 +1665,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { /* if there is a primary slave, remember it */ - if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { + if (strcmp(bond->params.primary, new_slave->dev->name) == 0) bond->primary_slave = new_slave; - } } write_lock_bh(&bond->curr_slave_lock); @@ -1724,9 +1713,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * anyway (it holds no special properties of the bond device), * so we can change it without calling change_active_interface() */ - if (!bond->curr_active_slave) { + if (!bond->curr_active_slave) bond->curr_active_slave = new_slave; - } + break; } /* switch(bond_mode) */ @@ -1740,7 +1729,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (res) goto err_close; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: enslaving %s as a%s interface with a%s link.\n", bond_dev->name, slave_dev->name, new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", @@ -1772,7 +1761,7 @@ err_free: err_undo_flags: bond_dev->features = old_features; - + return res; } @@ -1797,7 +1786,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: cannot release %s.\n", bond_dev->name, slave_dev->name); return -EINVAL; @@ -1808,7 +1797,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) slave = bond_get_slave_by_dev(bond, slave_dev); if (!slave) { /* not a slave of this bond */ - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: %s not enslaved\n", bond_dev->name, slave_dev->name); write_unlock_bh(&bond->lock); @@ -1819,7 +1808,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr, ETH_ALEN); if (!mac_addr_differ && (bond->slave_cnt > 1)) - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: the permanent HWaddr of %s - " "%pM - is still in use by %s. " "Set the HWaddr of %s to a different address " @@ -1837,7 +1826,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_3ad_unbind_slave(slave); } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: releasing %s interface %s\n", bond_dev->name, (slave->state == BOND_STATE_ACTIVE) @@ -1853,13 +1842,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_compute_features(bond); - if (bond->primary_slave == slave) { + if (bond->primary_slave == slave) bond->primary_slave = NULL; - } - if (oldcurrent == slave) { + if (oldcurrent == slave) bond_change_active_slave(bond, NULL); - } if (bond_is_lb(bond)) { /* Must be called only after the slave has been @@ -1901,18 +1888,18 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) if (list_empty(&bond->vlan_list)) { bond_dev->features |= NETIF_F_VLAN_CHALLENGED; } else { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: clearing HW address of %s while it " "still has VLANs.\n", bond_dev->name, bond_dev->name); - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: When re-adding slaves, make sure the bond's " "HW address matches its VLANs'.\n", bond_dev->name); } } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) && !bond_has_challenged_slaves(bond)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: last VLAN challenged slave %s " "left bond %s. VLAN blocking is removed\n", bond_dev->name, slave_dev->name, bond_dev->name); @@ -1932,14 +1919,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) */ if (!USES_PRIMARY(bond->params.mode)) { /* unset promiscuity level from slave */ - if (bond_dev->flags & IFF_PROMISC) { + if (bond_dev->flags & IFF_PROMISC) dev_set_promiscuity(slave_dev, -1); - } /* unset allmulti level from slave */ - if (bond_dev->flags & IFF_ALLMULTI) { + if (bond_dev->flags & IFF_ALLMULTI) dev_set_allmulti(slave_dev, -1); - } /* flush master's mc_list from slave */ netif_addr_lock_bh(bond_dev); @@ -1988,17 +1973,18 @@ static void bond_uninit(struct net_device *bond_dev) } /* -* First release a slave and than destroy the bond if no more slaves iare left. +* First release a slave and than destroy the bond if no more slaves are left. * Must be under rtnl_lock when this function is called. */ -int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev) +int bond_release_and_destroy(struct net_device *bond_dev, + struct net_device *slave_dev) { struct bonding *bond = netdev_priv(bond_dev); int ret; ret = bond_release(bond_dev, slave_dev); if ((ret == 0) && (bond->slave_cnt == 0)) { - printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n", + pr_info(DRV_NAME ": %s: destroying bond %s.\n", bond_dev->name, bond_dev->name); unregister_netdevice(bond_dev); } @@ -2019,9 +2005,8 @@ static int bond_release_all(struct net_device *bond_dev) netif_carrier_off(bond_dev); - if (bond->slave_cnt == 0) { + if (bond->slave_cnt == 0) goto out; - } bond->current_arp_slave = NULL; bond->primary_slave = NULL; @@ -2031,9 +2016,8 @@ static int bond_release_all(struct net_device *bond_dev) /* Inform AD package of unbinding of slave * before slave is detached from the list. */ - if (bond->params.mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) bond_3ad_unbind_slave(slave); - } slave_dev = slave->dev; bond_detach_slave(bond, slave); @@ -2062,14 +2046,12 @@ static int bond_release_all(struct net_device *bond_dev) */ if (!USES_PRIMARY(bond->params.mode)) { /* unset promiscuity level from slave */ - if (bond_dev->flags & IFF_PROMISC) { + if (bond_dev->flags & IFF_PROMISC) dev_set_promiscuity(slave_dev, -1); - } /* unset allmulti level from slave */ - if (bond_dev->flags & IFF_ALLMULTI) { + if (bond_dev->flags & IFF_ALLMULTI) dev_set_allmulti(slave_dev, -1); - } /* flush master's mc_list from slave */ netif_addr_lock_bh(bond_dev); @@ -2104,20 +2086,20 @@ static int bond_release_all(struct net_device *bond_dev) */ memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - } else { - printk(KERN_WARNING DRV_NAME + else { + pr_warning(DRV_NAME ": %s: Warning: clearing HW address of %s while it " "still has VLANs.\n", bond_dev->name, bond_dev->name); - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: When re-adding slaves, make sure the bond's " "HW address matches its VLANs'.\n", bond_dev->name); } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: released all slaves\n", bond_dev->name); @@ -2135,8 +2117,8 @@ out: * - is already active. * - The link state of is not BOND_LINK_UP. * - is not running. - * In these cases, this fuction does nothing. - * In the other cases, currnt_slave pointer is changed and 0 is returned. + * In these cases, this function does nothing. + * In the other cases, current_slave pointer is changed and 0 is returned. */ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -2145,15 +2127,12 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi struct slave *new_active = NULL; int res = 0; - if (!USES_PRIMARY(bond->params.mode)) { + if (!USES_PRIMARY(bond->params.mode)) return -EINVAL; - } /* Verify that master_dev is indeed the master of slave_dev */ - if (!(slave_dev->flags & IFF_SLAVE) || - (slave_dev->master != bond_dev)) { + if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev)) return -EINVAL; - } read_lock(&bond->lock); @@ -2178,9 +2157,8 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, new_active); write_unlock_bh(&bond->curr_slave_lock); - } else { + } else res = -EINVAL; - } read_unlock(&bond->lock); @@ -2249,7 +2227,7 @@ static int bond_miimon_inspect(struct bonding *bond) slave->link = BOND_LINK_FAIL; slave->delay = bond->params.downdelay; if (slave->delay) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status down for %s" "interface %s, disabling it in %d ms.\n", bond->dev->name, @@ -2268,7 +2246,7 @@ static int bond_miimon_inspect(struct bonding *bond) */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status up again after %d " "ms for interface %s.\n", bond->dev->name, @@ -2295,7 +2273,7 @@ static int bond_miimon_inspect(struct bonding *bond) slave->delay = bond->params.updelay; if (slave->delay) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status up for " "interface %s, enabling it in %d ms.\n", bond->dev->name, slave->dev->name, @@ -2307,7 +2285,7 @@ static int bond_miimon_inspect(struct bonding *bond) case BOND_LINK_BACK: if (!link_state) { slave->link = BOND_LINK_DOWN; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status down again after %d " "ms for interface %s.\n", bond->dev->name, @@ -2361,7 +2339,7 @@ static void bond_miimon_commit(struct bonding *bond) slave->state = BOND_STATE_BACKUP; } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status definitely " "up for interface %s.\n", bond->dev->name, slave->dev->name); @@ -2390,7 +2368,7 @@ static void bond_miimon_commit(struct bonding *bond) bond->params.mode == BOND_MODE_8023AD) bond_set_slave_inactive_flags(slave); - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status definitely down for " "interface %s, disabling it\n", bond->dev->name, slave->dev->name); @@ -2409,7 +2387,7 @@ static void bond_miimon_commit(struct bonding *bond) continue; default: - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: invalid new link %d on slave %s\n", bond->dev->name, slave->new_link, slave->dev->name); @@ -2530,18 +2508,18 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, slave_dev->name, dest_ip, src_ip, vlan_id); - + skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, NULL, slave_dev->dev_addr, NULL); if (!skb) { - printk(KERN_ERR DRV_NAME ": ARP packet allocation failed\n"); + pr_err(DRV_NAME ": ARP packet allocation failed\n"); return; } if (vlan_id) { skb = vlan_put_tag(skb, vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); + pr_err(DRV_NAME ": failed to insert VLAN tag\n"); return; } } @@ -2581,7 +2559,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) rv = ip_route_output_key(&init_net, &rt, &fl); if (rv) { if (net_ratelimit()) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: no route to arp_ip_target %pI4\n", bond->dev->name, &fl.fl4_dst); } @@ -2618,7 +2596,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } if (net_ratelimit()) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: no path to arp_ip_target %pI4 via rt.dev %s\n", bond->dev->name, &fl.fl4_dst, rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); @@ -2766,13 +2744,11 @@ void bond_loadbalance_arp_mon(struct work_struct *work) delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); - if (bond->kill_timers) { + if (bond->kill_timers) goto out; - } - if (bond->slave_cnt == 0) { + if (bond->slave_cnt == 0) goto re_arm; - } read_lock(&bond->curr_slave_lock); oldcurrent = bond->curr_active_slave; @@ -2800,14 +2776,14 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * is closed. */ if (!oldcurrent) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status definitely " "up for interface %s, ", bond->dev->name, slave->dev->name); do_failover = 1; } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: interface %s is now up\n", bond->dev->name, slave->dev->name); @@ -2826,18 +2802,16 @@ void bond_loadbalance_arp_mon(struct work_struct *work) slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; - if (slave->link_failure_count < UINT_MAX) { + if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: interface %s is now down.\n", bond->dev->name, slave->dev->name); - if (slave == oldcurrent) { + if (slave == oldcurrent) do_failover = 1; - } } } @@ -2848,9 +2822,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * do - all replies will be rx'ed on same link causing slaves * to be unstable during low/no traffic periods */ - if (IS_UP(slave->dev)) { + if (IS_UP(slave->dev)) bond_arp_send_all(bond, slave); - } } if (do_failover) { @@ -2981,7 +2954,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) bond_change_active_slave(bond, slave); bond->current_arp_slave = NULL; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: %s is up and now the " "active interface\n", bond->dev->name, slave->dev->name); @@ -2997,7 +2970,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) bond_set_slave_inactive_flags(slave); bond->current_arp_slave = NULL; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: backup interface %s is now up\n", bond->dev->name, slave->dev->name); } @@ -3013,7 +2986,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) slave->link = BOND_LINK_DOWN; if (slave == bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status down for active " "interface %s, disabling it\n", bond->dev->name, slave->dev->name); @@ -3032,7 +3005,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) bond->current_arp_slave = NULL; } else if (slave->state == BOND_STATE_BACKUP) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: backup interface %s is now down\n", bond->dev->name, slave->dev->name); @@ -3041,7 +3014,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) break; default: - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: impossible: new_link %d on slave %s\n", bond->dev->name, slave->new_link, slave->dev->name); @@ -3075,7 +3048,7 @@ static void bond_ab_arp_probe(struct bonding *bond) read_lock(&bond->curr_slave_lock); if (bond->current_arp_slave && bond->curr_active_slave) - printk("PROBE: c_arp %s && cas %s BAD\n", + pr_info(DRV_NAME "PROBE: c_arp %s && cas %s BAD\n", bond->current_arp_slave->dev->name, bond->curr_active_slave->dev->name); @@ -3125,7 +3098,7 @@ static void bond_ab_arp_probe(struct bonding *bond) bond_set_slave_inactive_flags(slave); - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: backup interface %s is now down.\n", bond->dev->name, slave->dev->name); } @@ -3175,9 +3148,8 @@ void bond_activebackup_arp_mon(struct work_struct *work) bond_ab_arp_probe(bond); re_arm: - if (bond->params.arp_interval) { + if (bond->params.arp_interval) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); - } out: read_unlock(&bond->lock); } @@ -3199,14 +3171,12 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) read_lock(&dev_base_lock); read_lock(&bond->lock); - if (*pos == 0) { + if (*pos == 0) return SEQ_START_TOKEN; - } bond_for_each_slave(bond, slave, i) { - if (++off == *pos) { + if (++off == *pos) return slave; - } } return NULL; @@ -3218,9 +3188,8 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) struct slave *slave = v; ++*pos; - if (v == SEQ_START_TOKEN) { + if (v == SEQ_START_TOKEN) return bond->first_slave; - } slave = slave->next; @@ -3283,14 +3252,14 @@ static void bond_info_show_master(struct seq_file *seq) /* ARP information */ - if(bond->params.arp_interval > 0) { - int printed=0; + if (bond->params.arp_interval > 0) { + int printed = 0; seq_printf(seq, "ARP Polling Interval (ms): %d\n", bond->params.arp_interval); seq_printf(seq, "ARP IP target/s (n.n.n.n form):"); - for(i = 0; (i < BOND_MAX_ARP_TARGETS) ;i++) { + for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (!bond->params.arp_targets[i]) break; if (printed) @@ -3330,7 +3299,8 @@ static void bond_info_show_master(struct seq_file *seq) } } -static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) +static void bond_info_show_slave(struct seq_file *seq, + const struct slave *slave) { struct bonding *bond = seq->private; @@ -3346,12 +3316,11 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave const struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; - if (agg) { + if (agg) seq_printf(seq, "Aggregator ID: %d\n", agg->aggregator_identifier); - } else { + else seq_puts(seq, "Aggregator ID: N/A\n"); - } } } @@ -3360,9 +3329,8 @@ static int bond_info_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) { seq_printf(seq, "%s\n", version); bond_info_show_master(seq); - } else { + } else bond_info_show_slave(seq, v); - } return 0; } @@ -3407,13 +3375,12 @@ static int bond_create_proc_entry(struct bonding *bond) bond->proc_entry = proc_create_data(bond_dev->name, S_IRUGO, bond_proc_dir, &bond_info_fops, bond); - if (bond->proc_entry == NULL) { - printk(KERN_WARNING DRV_NAME + if (bond->proc_entry == NULL) + pr_warning(DRV_NAME ": Warning: Cannot create /proc/net/%s/%s\n", DRV_NAME, bond_dev->name); - } else { + else memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); - } } return 0; @@ -3436,7 +3403,7 @@ static void bond_create_proc_dir(void) if (!bond_proc_dir) { bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net); if (!bond_proc_dir) - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: cannot create /proc/net/%s\n", DRV_NAME); } @@ -3484,13 +3451,14 @@ static int bond_event_changename(struct bonding *bond) bond_remove_proc_entry(bond); bond_create_proc_entry(bond); - bond_destroy_sysfs_entry(bond); - bond_create_sysfs_entry(bond); + bond_destroy_sysfs_entry(bond); + bond_create_sysfs_entry(bond); return NOTIFY_DONE; } -static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) +static int bond_master_netdev_event(unsigned long event, + struct net_device *bond_dev) { struct bonding *event_bond = netdev_priv(bond_dev); @@ -3507,7 +3475,8 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond return NOTIFY_DONE; } -static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) +static int bond_slave_netdev_event(unsigned long event, + struct net_device *slave_dev) { struct net_device *bond_dev = slave_dev->master; struct bonding *bond = netdev_priv(bond_dev); @@ -3585,7 +3554,8 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * locks for us to safely manipulate the slave devices (RTNL lock, * dev_probe_lock). */ -static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +static int bond_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) { struct net_device *event_dev = (struct net_device *)ptr; @@ -3940,9 +3910,9 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd switch (cmd) { case SIOCGMIIPHY: mii = if_mii(ifr); - if (!mii) { + if (!mii) return -EINVAL; - } + mii->phy_id = 0; /* Fall Through */ case SIOCGMIIREG: @@ -3951,18 +3921,18 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd * instead of SIOCGMIIPHY. */ mii = if_mii(ifr); - if (!mii) { + if (!mii) return -EINVAL; - } + if (mii->reg_num == 1) { struct bonding *bond = netdev_priv(bond_dev); mii->val_out = 0; read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (netif_carrier_ok(bond->dev)) { + if (netif_carrier_ok(bond->dev)) mii->val_out = BMSR_LSTATUS; - } + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); } @@ -3972,32 +3942,26 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd case SIOCBONDINFOQUERY: u_binfo = (struct ifbond __user *)ifr->ifr_data; - if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) return -EFAULT; - } res = bond_info_query(bond_dev, &k_binfo); - if (res == 0) { - if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { - return -EFAULT; - } - } + if (res == 0 && + copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) + return -EFAULT; return res; case BOND_SLAVE_INFO_QUERY_OLD: case SIOCBONDSLAVEINFOQUERY: u_sinfo = (struct ifslave __user *)ifr->ifr_data; - if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) return -EFAULT; - } res = bond_slave_info_query(bond_dev, &k_sinfo); - if (res == 0) { - if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { - return -EFAULT; - } - } + if (res == 0 && + copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) + return -EFAULT; return res; default: @@ -4005,17 +3969,16 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd break; } - if (!capable(CAP_NET_ADMIN)) { + if (!capable(CAP_NET_ADMIN)) return -EPERM; - } slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); pr_debug("slave_dev=%p: \n", slave_dev); - if (!slave_dev) { + if (!slave_dev) res = -ENODEV; - } else { + else { pr_debug("slave_dev->name=%s: \n", slave_dev->name); switch (cmd) { case BOND_ENSLAVE_OLD: @@ -4052,30 +4015,30 @@ static void bond_set_multicast_list(struct net_device *bond_dev) /* * Do promisc before checking multicast_mode */ - if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) { + if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) /* * FIXME: Need to handle the error when one of the multi-slaves * encounters error. */ bond_set_promiscuity(bond, 1); - } - if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) { + + if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) bond_set_promiscuity(bond, -1); - } + /* set allmulti flag to slaves */ - if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) { + if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) /* * FIXME: Need to handle the error when one of the multi-slaves * encounters error. */ bond_set_allmulti(bond, 1); - } - if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) { + + if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) bond_set_allmulti(bond, -1); - } + read_lock(&bond->lock); @@ -4083,16 +4046,14 @@ static void bond_set_multicast_list(struct net_device *bond_dev) /* looking for addresses to add to slaves' mc list */ for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { - if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) { + if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } } /* looking for addresses to delete from slaves' list */ for (dmi = bond->mc_list; dmi; dmi = dmi->next) { - if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) { + if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } } /* save master's multicast list */ @@ -4212,9 +4173,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) if (bond->params.fail_over_mac == BOND_FOM_ACTIVE) return 0; - if (!is_valid_ether_addr(sa->sa_data)) { + if (!is_valid_ether_addr(sa->sa_data)) return -EADDRNOTAVAIL; - } /* Can't hold bond->lock with bh disabled here since * some base drivers panic. On the other hand we can't @@ -4285,9 +4245,8 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev read_lock(&bond->lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } /* * Concurrent TX may collide on rr_tx_counter; we accept that @@ -4297,9 +4256,8 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev bond_for_each_slave(bond, slave, i) { slave_no--; - if (slave_no < 0) { + if (slave_no < 0) break; - } } start_at = slave; @@ -4334,9 +4292,8 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } if (!bond->curr_active_slave) goto out; @@ -4344,10 +4301,10 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); out: - if (res) { + if (res) /* no suitable interface, frame not sent */ dev_kfree_skb(skb); - } + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); return 0; @@ -4368,17 +4325,15 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) read_lock(&bond->lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } slave_no = bond->xmit_hash_policy(skb, bond_dev, bond->slave_cnt); bond_for_each_slave(bond, slave, i) { slave_no--; - if (slave_no < 0) { + if (slave_no < 0) break; - } } start_at = slave; @@ -4414,17 +4369,15 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) read_lock(&bond->lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } read_lock(&bond->curr_slave_lock); start_at = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); - if (!start_at) { + if (!start_at) goto out; - } bond_for_each_slave_from(bond, slave, i, start_at) { if (IS_UP(slave->dev) && @@ -4433,7 +4386,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) if (tx_dev) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: bond_xmit_broadcast(): " "skb_clone() failed\n", bond_dev->name); @@ -4450,15 +4403,14 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) } } - if (tx_dev) { + if (tx_dev) res = bond_dev_queue_xmit(bond, skb, tx_dev); - } out: - if (res) { + if (res) /* no suitable interface, frame not sent */ dev_kfree_skb(skb); - } + /* frame sent to all suitable interfaces */ read_unlock(&bond->lock); return 0; @@ -4502,7 +4454,7 @@ static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev) return bond_alb_xmit(skb, dev); default: /* Should never happen, mode already checked */ - printk(KERN_ERR DRV_NAME ": %s: Error: Unknown bonding mode %d\n", + pr_err(DRV_NAME ": %s: Error: Unknown bonding mode %d\n", dev->name, bond->params.mode); WARN_ON_ONCE(1); dev_kfree_skb(skb); @@ -4539,7 +4491,7 @@ void bond_set_mode_ops(struct bonding *bond, int mode) break; default: /* Should never happen, mode already checked */ - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Unknown bonding mode %d\n", bond_dev->name, mode); @@ -4752,7 +4704,7 @@ static int bond_check_params(struct bond_params *params) if (mode) { bond_mode = bond_parse_parm(mode, bond_mode_tbl); if (bond_mode == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: Invalid bonding mode \"%s\"\n", mode == NULL ? "NULL" : mode); return -EINVAL; @@ -4762,16 +4714,16 @@ static int bond_check_params(struct bond_params *params) if (xmit_hash_policy) { if ((bond_mode != BOND_MODE_XOR) && (bond_mode != BOND_MODE_8023AD)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": xor_mode param is irrelevant in mode %s\n", bond_mode_name(bond_mode)); } else { xmit_hashtype = bond_parse_parm(xmit_hash_policy, xmit_hashtype_tbl); if (xmit_hashtype == -1) { - printk(KERN_ERR DRV_NAME - ": Error: Invalid xmit_hash_policy \"%s\"\n", - xmit_hash_policy == NULL ? "NULL" : + pr_err(DRV_NAME + ": Error: Invalid xmit_hash_policy \"%s\"\n", + xmit_hash_policy == NULL ? "NULL" : xmit_hash_policy); return -EINVAL; } @@ -4780,13 +4732,13 @@ static int bond_check_params(struct bond_params *params) if (lacp_rate) { if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": lacp_rate param is irrelevant in mode %s\n", bond_mode_name(bond_mode)); } else { lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl); if (lacp_fast == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: Invalid lacp rate \"%s\"\n", lacp_rate == NULL ? "NULL" : lacp_rate); return -EINVAL; @@ -4797,14 +4749,14 @@ static int bond_check_params(struct bond_params *params) if (ad_select) { params->ad_select = bond_parse_parm(ad_select, ad_select_tbl); if (params->ad_select == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: Invalid ad_select \"%s\"\n", ad_select == NULL ? "NULL" : ad_select); return -EINVAL; } if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": ad_select param only affects 802.3ad mode\n"); } } else { @@ -4812,7 +4764,7 @@ static int bond_check_params(struct bond_params *params) } if (max_bonds < 0 || max_bonds > INT_MAX) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: max_bonds (%d) not in range %d-%d, so it " "was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS); @@ -4820,7 +4772,7 @@ static int bond_check_params(struct bond_params *params) } if (miimon < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon module parameter (%d), " "not in range 0-%d, so it was reset to %d\n", miimon, INT_MAX, BOND_LINK_MON_INTERV); @@ -4828,7 +4780,7 @@ static int bond_check_params(struct bond_params *params) } if (updelay < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: updelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", updelay, INT_MAX); @@ -4836,7 +4788,7 @@ static int bond_check_params(struct bond_params *params) } if (downdelay < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: downdelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", downdelay, INT_MAX); @@ -4844,7 +4796,7 @@ static int bond_check_params(struct bond_params *params) } if ((use_carrier != 0) && (use_carrier != 1)) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: use_carrier module parameter (%d), " "not of valid value (0/1), so it was set to 1\n", use_carrier); @@ -4852,14 +4804,14 @@ static int bond_check_params(struct bond_params *params) } if (num_grat_arp < 0 || num_grat_arp > 255) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: num_grat_arp (%d) not in range 0-255 so it " "was reset to 1 \n", num_grat_arp); num_grat_arp = 1; } if (num_unsol_na < 0 || num_unsol_na > 255) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: num_unsol_na (%d) not in range 0-255 so it " "was reset to 1 \n", num_unsol_na); num_unsol_na = 1; @@ -4868,12 +4820,12 @@ static int bond_check_params(struct bond_params *params) /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon must be specified, " "otherwise bonding will not detect link " "failure, speed and duplex which are " "essential for 802.3ad operation\n"); - printk(KERN_WARNING "Forcing miimon to 100msec\n"); + pr_warning("Forcing miimon to 100msec\n"); miimon = 100; } } @@ -4882,12 +4834,12 @@ static int bond_check_params(struct bond_params *params) if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { if (!miimon) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon must be specified, " "otherwise bonding will not detect link " "failure and link speed which are essential " "for TLB/ALB load balancing\n"); - printk(KERN_WARNING "Forcing miimon to 100msec\n"); + pr_warning("Forcing miimon to 100msec\n"); miimon = 100; } } @@ -4907,7 +4859,7 @@ static int bond_check_params(struct bond_params *params) /* just warn the user the up/down delay will have * no effect since miimon is zero... */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon module parameter not set " "and updelay (%d) or downdelay (%d) module " "parameter is set; updelay and downdelay have " @@ -4917,7 +4869,7 @@ static int bond_check_params(struct bond_params *params) } else { /* don't allow arp monitoring */ if (arp_interval) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon (%d) and arp_interval (%d) " "can't be used simultaneously, disabling ARP " "monitoring\n", @@ -4926,7 +4878,7 @@ static int bond_check_params(struct bond_params *params) } if ((updelay % miimon) != 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: updelay (%d) is not a multiple " "of miimon (%d), updelay rounded to %d ms\n", updelay, miimon, (updelay / miimon) * miimon); @@ -4935,7 +4887,7 @@ static int bond_check_params(struct bond_params *params) updelay /= miimon; if ((downdelay % miimon) != 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: downdelay (%d) is not a multiple " "of miimon (%d), downdelay rounded to %d ms\n", downdelay, miimon, @@ -4946,7 +4898,7 @@ static int bond_check_params(struct bond_params *params) } if (arp_interval < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: arp_interval module parameter (%d) " ", not in range 0-%d, so it was reset to %d\n", arp_interval, INT_MAX, BOND_LINK_ARP_INTERV); @@ -4959,7 +4911,7 @@ static int bond_check_params(struct bond_params *params) /* not complete check, but should be good enough to catch mistakes */ if (!isdigit(arp_ip_target[arp_ip_count][0])) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: bad arp_ip_target module parameter " "(%s), ARP monitoring will not be performed\n", arp_ip_target[arp_ip_count]); @@ -4972,7 +4924,7 @@ static int bond_check_params(struct bond_params *params) if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: arp_interval module parameter (%d) " "specified without providing an arp_ip_target " "parameter, arp_interval was reset to 0\n", @@ -4982,12 +4934,12 @@ static int bond_check_params(struct bond_params *params) if (arp_validate) { if (bond_mode != BOND_MODE_ACTIVEBACKUP) { - printk(KERN_ERR DRV_NAME - ": arp_validate only supported in active-backup mode\n"); + pr_err(DRV_NAME + ": arp_validate only supported in active-backup mode\n"); return -EINVAL; } if (!arp_interval) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": arp_validate requires arp_interval\n"); return -EINVAL; } @@ -4995,7 +4947,7 @@ static int bond_check_params(struct bond_params *params) arp_validate_value = bond_parse_parm(arp_validate, arp_validate_tbl); if (arp_validate_value == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: invalid arp_validate \"%s\"\n", arp_validate == NULL ? "NULL" : arp_validate); return -EINVAL; @@ -5004,20 +4956,20 @@ static int bond_check_params(struct bond_params *params) arp_validate_value = 0; if (miimon) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": MII link monitoring set to %d ms\n", miimon); } else if (arp_interval) { int i; - printk(KERN_INFO DRV_NAME - ": ARP monitoring set to %d ms, validate %s, with %d target(s):", + pr_info(DRV_NAME ": ARP monitoring set to %d ms," + " validate %s, with %d target(s):", arp_interval, arp_validate_tbl[arp_validate_value].modename, arp_ip_count); for (i = 0; i < arp_ip_count; i++) - printk (" %s", arp_ip_target[i]); + printk(" %s", arp_ip_target[i]); printk("\n"); @@ -5025,7 +4977,7 @@ static int bond_check_params(struct bond_params *params) /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: either miimon or arp_interval and " "arp_ip_target module parameters must be specified, " "otherwise bonding will not detect link failures! see " @@ -5036,7 +4988,7 @@ static int bond_check_params(struct bond_params *params) /* currently, using a primary only makes sense * in active backup, TLB or ALB modes */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: %s primary device specified but has no " "effect in %s mode\n", primary, bond_mode_name(bond_mode)); @@ -5047,14 +4999,14 @@ static int bond_check_params(struct bond_params *params) fail_over_mac_value = bond_parse_parm(fail_over_mac, fail_over_mac_tbl); if (fail_over_mac_value == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: invalid fail_over_mac \"%s\"\n", arp_validate == NULL ? "NULL" : arp_validate); return -EINVAL; } if (bond_mode != BOND_MODE_ACTIVEBACKUP) - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: fail_over_mac only affects " "active-backup mode.\n"); } else { @@ -5120,9 +5072,8 @@ int bond_create(const char *name) if (name) { list_for_each_entry(bond, &bond_dev_list, bond_list) if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { - printk(KERN_ERR DRV_NAME - ": cannot add bond %s; it already exists\n", - name); + pr_err(DRV_NAME ": cannot add bond %s;" + " it already exists\n", name); res = -EPERM; goto out_rtnl; } @@ -5131,8 +5082,7 @@ int bond_create(const char *name) bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", ether_setup); if (!bond_dev) { - printk(KERN_ERR DRV_NAME - ": %s: eek! can't alloc netdev!\n", + pr_err(DRV_NAME ": %s: eek! can't alloc netdev!\n", name); res = -ENOMEM; goto out_rtnl; @@ -5151,18 +5101,16 @@ int bond_create(const char *name) */ res = bond_init(bond_dev); - if (res < 0) { + if (res < 0) goto out_netdev; - } bond_set_lockdep_class(bond_dev); netif_carrier_off(bond_dev); res = register_netdevice(bond_dev); - if (res < 0) { + if (res < 0) goto out_bond; - } res = bond_create_sysfs_entry(netdev_priv(bond_dev)); if (res < 0) @@ -5187,12 +5135,11 @@ static int __init bonding_init(void) int i; int res; - printk(KERN_INFO "%s", version); + pr_info("%s", version); res = bond_check_params(&bonding_defaults); - if (res) { + if (res) goto out; - } bond_create_proc_dir(); @@ -5239,13 +5186,3 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); -MODULE_SUPPORTED_DEVICE("most ethernet devices"); - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ - diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 7235759..ecb2020 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1,4 +1,3 @@ - /* * Copyright(c) 2004-2005 Intel Corporation. All rights reserved. * @@ -38,7 +37,7 @@ #include "bonding.h" -#define to_dev(obj) container_of(obj,struct device,kobj) +#define to_dev(obj) container_of(obj, struct device, kobj) #define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd)))) /*---------------------------- Declarations -------------------------------*/ @@ -83,7 +82,8 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) * */ -static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t count) +static ssize_t bonding_store_bonds(struct class *cls, + const char *buffer, size_t count) { char command[IFNAMSIZ + 1] = {0, }; char *ifname; @@ -97,11 +97,11 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t goto err_no_cmd; if (command[0] == '+') { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s is being created...\n", ifname); rv = bond_create(ifname); if (rv) { - printk(KERN_INFO DRV_NAME ": Bond creation failed.\n"); + pr_info(DRV_NAME ": Bond creation failed.\n"); res = rv; } goto out; @@ -118,28 +118,28 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t */ if (atomic_read(&bond->dev->dev.kobj.kref.refcount) > expected_refcount){ - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": Unable remove bond %s due to open references.\n", ifname); res = -EPERM; goto out_unlock; } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s is being deleted...\n", bond->dev->name); unregister_netdevice(bond->dev); goto out_unlock; } - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": unable to delete non-existent bond %s\n", ifname); res = -ENODEV; goto out_unlock; } err_no_cmd: - printk(KERN_ERR DRV_NAME - ": no command found in bonding_masters. Use +ifname or -ifname.\n"); + pr_err(DRV_NAME ": no command found in bonding_masters." + " Use +ifname or -ifname.\n"); return -EPERM; out_unlock: @@ -155,7 +155,8 @@ out: static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO, bonding_show_bonds, bonding_store_bonds); -int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave) +int bond_create_slave_symlinks(struct net_device *master, + struct net_device *slave) { char linkname[IFNAMSIZ+7]; int ret = 0; @@ -166,19 +167,20 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla if (ret) return ret; /* next, create a link from the master to the slave */ - sprintf(linkname,"slave_%s",slave->name); + sprintf(linkname, "slave_%s", slave->name); ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), linkname); return ret; } -void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave) +void bond_destroy_slave_symlinks(struct net_device *master, + struct net_device *slave) { char linkname[IFNAMSIZ+7]; sysfs_remove_link(&(slave->dev.kobj), "master"); - sprintf(linkname,"slave_%s",slave->name); + sprintf(linkname, "slave_%s", slave->name); sysfs_remove_link(&(master->dev.kobj), linkname); } @@ -252,7 +254,7 @@ static ssize_t bonding_store_slaves(struct device *d, read_lock(&bond->lock); bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Interface %s is already enslaved!\n", bond->dev->name, ifname); ret = -EPERM; @@ -261,21 +263,20 @@ static ssize_t bonding_store_slaves(struct device *d, } read_unlock(&bond->lock); - printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n", + pr_info(DRV_NAME ": %s: Adding slave %s.\n", bond->dev->name, ifname); dev = dev_get_by_name(&init_net, ifname); if (!dev) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Interface %s does not exist!\n", bond->dev->name, ifname); ret = -EPERM; goto out; - } - else + } else dev_put(dev); if (dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Unable to enslave %s " "because it is already up.\n", bond->dev->name, dev->name); @@ -302,9 +303,9 @@ static ssize_t bonding_store_slaves(struct device *d, bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) slave->original_mtu = original_mtu; - if (res) { + if (res) ret = res; - } + goto out; } @@ -318,7 +319,7 @@ static ssize_t bonding_store_slaves(struct device *d, break; } if (dev) { - printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", + pr_info(DRV_NAME ": %s: Removing slave %s\n", bond->dev->name, dev->name); res = bond_release(bond->dev, dev); if (res) { @@ -327,9 +328,9 @@ static ssize_t bonding_store_slaves(struct device *d, } /* set the slave MTU to the default */ dev_set_mtu(dev, original_mtu); - } - else { - printk(KERN_ERR DRV_NAME ": unable to remove non-existent slave %s for bond %s.\n", + } else { + pr_err(DRV_NAME ": unable to remove non-existent" + " slave %s for bond %s.\n", ifname, bond->dev->name); ret = -ENODEV; } @@ -337,7 +338,7 @@ static ssize_t bonding_store_slaves(struct device *d, } err_no_cmd: - printk(KERN_ERR DRV_NAME ": no command found in slaves file for bond %s. Use +ifname or -ifname.\n", bond->dev->name); + pr_err(DRV_NAME ": no command found in slaves file for bond %s. Use +ifname or -ifname.\n", bond->dev->name); ret = -EPERM; out: @@ -345,7 +346,8 @@ out: return ret; } -static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); +static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, + bonding_store_slaves); /* * Show and set the bonding mode. The bond interface must be down to @@ -369,16 +371,15 @@ static ssize_t bonding_store_mode(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME - ": unable to update mode of %s because interface is up.\n", - bond->dev->name); + pr_err(DRV_NAME ": unable to update mode of %s" + " because interface is up.\n", bond->dev->name); ret = -EPERM; goto out; } new_value = bond_parse_parm(buf, bond_mode_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid mode value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); @@ -393,17 +394,19 @@ static ssize_t bonding_store_mode(struct device *d, bond->params.mode = new_value; bond_set_mode_ops(bond, bond->params.mode); - printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n", - bond->dev->name, bond_mode_tbl[new_value].modename, new_value); + pr_info(DRV_NAME ": %s: setting mode to %s (%d).\n", + bond->dev->name, bond_mode_tbl[new_value].modename, + new_value); } out: return ret; } -static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + bonding_show_mode, bonding_store_mode); /* - * Show and set the bonding transmit hash method. The bond interface must be down to - * change the xmit hash policy. + * Show and set the bonding transmit hash method. + * The bond interface must be down to change the xmit hash policy. */ static ssize_t bonding_show_xmit_hash(struct device *d, struct device_attribute *attr, @@ -424,7 +427,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME "%s: Interface is up. Unable to update xmit policy.\n", bond->dev->name); ret = -EPERM; @@ -433,7 +436,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d, new_value = bond_parse_parm(buf, xmit_hashtype_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid xmit hash policy value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); @@ -442,13 +445,15 @@ static ssize_t bonding_store_xmit_hash(struct device *d, } else { bond->params.xmit_policy = new_value; bond_set_mode_ops(bond, bond->params.mode); - printk(KERN_INFO DRV_NAME ": %s: setting xmit hash policy to %s (%d).\n", - bond->dev->name, xmit_hashtype_tbl[new_value].modename, new_value); + pr_info(DRV_NAME ": %s: setting xmit hash policy to %s (%d).\n", + bond->dev->name, + xmit_hashtype_tbl[new_value].modename, new_value); } out: return ret; } -static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); +static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, + bonding_show_xmit_hash, bonding_store_xmit_hash); /* * Show and set arp_validate. @@ -473,39 +478,41 @@ static ssize_t bonding_store_arp_validate(struct device *d, new_value = bond_parse_parm(buf, arp_validate_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid arp_validate value %s\n", bond->dev->name, buf); return -EINVAL; } if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: arp_validate only supported in active-backup mode.\n", bond->dev->name); return -EINVAL; } - printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n", + pr_info(DRV_NAME ": %s: setting arp_validate to %s (%d).\n", bond->dev->name, arp_validate_tbl[new_value].modename, new_value); - if (!bond->params.arp_validate && new_value) { + if (!bond->params.arp_validate && new_value) bond_register_arp(bond); - } else if (bond->params.arp_validate && !new_value) { + else if (bond->params.arp_validate && !new_value) bond_unregister_arp(bond); - } bond->params.arp_validate = new_value; return count; } -static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); +static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, + bonding_store_arp_validate); /* * Show and store fail_over_mac. User only allowed to change the * value when there are no slaves. */ -static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attribute *attr, char *buf) +static ssize_t bonding_show_fail_over_mac(struct device *d, + struct device_attribute *attr, + char *buf) { struct bonding *bond = to_bond(d); @@ -514,13 +521,15 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attrib bond->params.fail_over_mac); } -static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t bonding_store_fail_over_mac(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value; struct bonding *bond = to_bond(d); if (bond->slave_cnt != 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Can't alter fail_over_mac with slaves in bond.\n", bond->dev->name); return -EPERM; @@ -528,21 +537,22 @@ static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attri new_value = bond_parse_parm(buf, fail_over_mac_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid fail_over_mac value %s.\n", bond->dev->name, buf); return -EINVAL; } bond->params.fail_over_mac = new_value; - printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n", + pr_info(DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n", bond->dev->name, fail_over_mac_tbl[new_value].modename, new_value); return count; } -static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac); +static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, + bonding_show_fail_over_mac, bonding_store_fail_over_mac); /* * Show and set the arp timer interval. There are two tricky bits @@ -567,28 +577,28 @@ static ssize_t bonding_store_arp_interval(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no arp_interval value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid arp_interval value %d not in range 1-%d; rejected.\n", bond->dev->name, new_value, INT_MAX); ret = -EINVAL; goto out; } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting ARP monitoring interval to %d.\n", bond->dev->name, new_value); bond->params.arp_interval = new_value; if (bond->params.arp_interval) bond->dev->priv_flags |= IFF_MASTER_ARPMON; if (bond->params.miimon) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: ARP monitoring cannot be used with MII monitoring. " "%s Disabling MII monitoring.\n", bond->dev->name, bond->dev->name); @@ -599,7 +609,7 @@ static ssize_t bonding_store_arp_interval(struct device *d, } } if (!bond->params.arp_targets[0]) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: ARP monitoring has been set up, " "but no ARP targets have been specified.\n", bond->dev->name); @@ -625,7 +635,8 @@ static ssize_t bonding_store_arp_interval(struct device *d, out: return ret; } -static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); +static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR, + bonding_show_arp_interval, bonding_store_arp_interval); /* * Show and set the arp targets. @@ -661,7 +672,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, /* look for adds */ if (buf[0] == '+') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: invalid ARP target %pI4 specified for addition\n", bond->dev->name, &newtarget); ret = -EINVAL; @@ -670,14 +681,14 @@ static ssize_t bonding_store_arp_targets(struct device *d, /* look for an empty slot to put the target in, and check for dupes */ for (i = 0; (i < BOND_MAX_ARP_TARGETS) && !done; i++) { if (targets[i] == newtarget) { /* duplicate */ - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: ARP target %pI4 is already present\n", bond->dev->name, &newtarget); ret = -EINVAL; goto out; } if (targets[i] == 0) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: adding ARP target %pI4.\n", bond->dev->name, &newtarget); done = 1; @@ -685,17 +696,16 @@ static ssize_t bonding_store_arp_targets(struct device *d, } } if (!done) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: ARP target table is full!\n", bond->dev->name); ret = -EINVAL; goto out; } - } - else if (buf[0] == '-') { + } else if (buf[0] == '-') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: invalid ARP target %pI4 specified for removal\n", bond->dev->name, &newtarget); ret = -EINVAL; @@ -705,7 +715,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, for (i = 0; (i < BOND_MAX_ARP_TARGETS) && !done; i++) { if (targets[i] == newtarget) { int j; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: removing ARP target %pI4.\n", bond->dev->name, &newtarget); for (j = i; (j < (BOND_MAX_ARP_TARGETS-1)) && targets[j+1]; j++) @@ -716,15 +726,15 @@ static ssize_t bonding_store_arp_targets(struct device *d, } } if (!done) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: unable to remove nonexistent ARP target %pI4.\n", bond->dev->name, &newtarget); ret = -EINVAL; goto out; } - } - else { - printk(KERN_ERR DRV_NAME ": no command found in arp_ip_targets file for bond %s. Use + or -.\n", + } else { + pr_err(DRV_NAME ": no command found in arp_ip_targets file" + " for bond %s. Use + or -.\n", bond->dev->name); ret = -EPERM; goto out; @@ -757,7 +767,7 @@ static ssize_t bonding_store_downdelay(struct device *d, struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to set down delay as MII monitoring is disabled\n", bond->dev->name); ret = -EPERM; @@ -765,14 +775,14 @@ static ssize_t bonding_store_downdelay(struct device *d, } if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no down delay value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid down delay value %d not in range %d-%d; rejected.\n", bond->dev->name, new_value, 1, INT_MAX); ret = -EINVAL; @@ -787,15 +797,17 @@ static ssize_t bonding_store_downdelay(struct device *d, bond->params.miimon); } bond->params.downdelay = new_value / bond->params.miimon; - printk(KERN_INFO DRV_NAME ": %s: Setting down delay to %d.\n", - bond->dev->name, bond->params.downdelay * bond->params.miimon); + pr_info(DRV_NAME ": %s: Setting down delay to %d.\n", + bond->dev->name, + bond->params.downdelay * bond->params.miimon); } out: return ret; } -static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); +static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR, + bonding_show_downdelay, bonding_store_downdelay); static ssize_t bonding_show_updelay(struct device *d, struct device_attribute *attr, @@ -815,7 +827,7 @@ static ssize_t bonding_store_updelay(struct device *d, struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to set up delay as MII monitoring is disabled\n", bond->dev->name); ret = -EPERM; @@ -823,14 +835,14 @@ static ssize_t bonding_store_updelay(struct device *d, } if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no up delay value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid down delay value %d not in range %d-%d; rejected.\n", bond->dev->name, new_value, 1, INT_MAX); ret = -EINVAL; @@ -845,7 +857,7 @@ static ssize_t bonding_store_updelay(struct device *d, bond->params.miimon); } bond->params.updelay = new_value / bond->params.miimon; - printk(KERN_INFO DRV_NAME ": %s: Setting up delay to %d.\n", + pr_info(DRV_NAME ": %s: Setting up delay to %d.\n", bond->dev->name, bond->params.updelay * bond->params.miimon); } @@ -853,7 +865,8 @@ static ssize_t bonding_store_updelay(struct device *d, out: return ret; } -static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); +static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR, + bonding_show_updelay, bonding_store_updelay); /* * Show and set the LACP interval. Interface must be down, and the mode @@ -878,7 +891,7 @@ static ssize_t bonding_store_lacp(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to update LACP rate because interface is up.\n", bond->dev->name); ret = -EPERM; @@ -886,7 +899,7 @@ static ssize_t bonding_store_lacp(struct device *d, } if (bond->params.mode != BOND_MODE_8023AD) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to update LACP rate because bond is not in 802.3ad mode.\n", bond->dev->name); ret = -EPERM; @@ -897,19 +910,20 @@ static ssize_t bonding_store_lacp(struct device *d, if ((new_value == 1) || (new_value == 0)) { bond->params.lacp_fast = new_value; - printk(KERN_INFO DRV_NAME - ": %s: Setting LACP rate to %s (%d).\n", - bond->dev->name, bond_lacp_tbl[new_value].modename, new_value); + pr_info(DRV_NAME ": %s: Setting LACP rate to %s (%d).\n", + bond->dev->name, bond_lacp_tbl[new_value].modename, + new_value); } else { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid LACP rate value %.*s.\n", - bond->dev->name, (int)strlen(buf) - 1, buf); + bond->dev->name, (int)strlen(buf) - 1, buf); ret = -EINVAL; } out: return ret; } -static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, + bonding_show_lacp, bonding_store_lacp); static ssize_t bonding_show_ad_select(struct device *d, struct device_attribute *attr, @@ -931,7 +945,7 @@ static ssize_t bonding_store_ad_select(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to update ad_select because interface " "is up.\n", bond->dev->name); ret = -EPERM; @@ -942,12 +956,12 @@ static ssize_t bonding_store_ad_select(struct device *d, if (new_value != -1) { bond->params.ad_select = new_value; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting ad_select to %s (%d).\n", bond->dev->name, ad_select_tbl[new_value].modename, new_value); } else { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid ad_select value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); ret = -EINVAL; @@ -955,8 +969,8 @@ static ssize_t bonding_store_ad_select(struct device *d, out: return ret; } - -static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); +static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, + bonding_show_ad_select, bonding_store_ad_select); /* * Show and set the number of grat ARP to send after a failover event. @@ -978,14 +992,14 @@ static ssize_t bonding_store_n_grat_arp(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no num_grat_arp value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0 || new_value > 255) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n", bond->dev->name, new_value); ret = -EINVAL; @@ -996,10 +1010,11 @@ static ssize_t bonding_store_n_grat_arp(struct device *d, out: return ret; } -static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp); +static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, + bonding_show_n_grat_arp, bonding_store_n_grat_arp); /* - * Show and set the number of unsolicted NA's to send after a failover event. + * Show and set the number of unsolicited NA's to send after a failover event. */ static ssize_t bonding_show_n_unsol_na(struct device *d, struct device_attribute *attr, @@ -1018,25 +1033,26 @@ static ssize_t bonding_store_n_unsol_na(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no num_unsol_na value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } + if (new_value < 0 || new_value > 255) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", bond->dev->name, new_value); ret = -EINVAL; goto out; - } else { + } else bond->params.num_unsol_na = new_value; - } out: return ret; } -static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, bonding_show_n_unsol_na, bonding_store_n_unsol_na); +static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, + bonding_show_n_unsol_na, bonding_store_n_unsol_na); /* * Show and set the MII monitor interval. There are two tricky bits @@ -1061,37 +1077,37 @@ static ssize_t bonding_store_miimon(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no miimon value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid miimon value %d not in range %d-%d; rejected.\n", bond->dev->name, new_value, 1, INT_MAX); ret = -EINVAL; goto out; } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting MII monitoring interval to %d.\n", bond->dev->name, new_value); bond->params.miimon = new_value; - if(bond->params.updelay) - printk(KERN_INFO DRV_NAME + if (bond->params.updelay) + pr_info(DRV_NAME ": %s: Note: Updating updelay (to %d) " "since it is a multiple of the miimon value.\n", bond->dev->name, bond->params.updelay * bond->params.miimon); - if(bond->params.downdelay) - printk(KERN_INFO DRV_NAME + if (bond->params.downdelay) + pr_info(DRV_NAME ": %s: Note: Updating downdelay (to %d) " "since it is a multiple of the miimon value.\n", bond->dev->name, bond->params.downdelay * bond->params.miimon); if (bond->params.arp_interval) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: MII monitoring cannot be used with " "ARP monitoring. Disabling ARP monitoring...\n", bond->dev->name); @@ -1125,7 +1141,8 @@ static ssize_t bonding_store_miimon(struct device *d, out: return ret; } -static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); +static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, + bonding_show_miimon, bonding_store_miimon); /* * Show and set the primary slave. The store function is much @@ -1161,7 +1178,7 @@ static ssize_t bonding_store_primary(struct device *d, write_lock_bh(&bond->curr_slave_lock); if (!USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Unable to set primary slave; %s is in mode %d\n", bond->dev->name, bond->dev->name, bond->params.mode); } else { @@ -1169,7 +1186,7 @@ static ssize_t bonding_store_primary(struct device *d, if (strnicmp (slave->dev->name, buf, strlen(slave->dev->name)) == 0) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting %s as primary slave.\n", bond->dev->name, slave->dev->name); bond->primary_slave = slave; @@ -1181,13 +1198,13 @@ static ssize_t bonding_store_primary(struct device *d, /* if we got here, then we didn't match the name of any slave */ if (strlen(buf) == 0 || buf[0] == '\n') { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting primary slave to None.\n", bond->dev->name); bond->primary_slave = NULL; bond_select_active_slave(bond); } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Unable to set %.*s as primary slave as it is not a slave.\n", bond->dev->name, (int)strlen(buf) - 1, buf); } @@ -1199,7 +1216,8 @@ out: return count; } -static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); +static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, + bonding_show_primary, bonding_store_primary); /* * Show and set the use_carrier flag. @@ -1222,7 +1240,7 @@ static ssize_t bonding_store_carrier(struct device *d, if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no use_carrier value specified.\n", bond->dev->name); ret = -EINVAL; @@ -1230,17 +1248,18 @@ static ssize_t bonding_store_carrier(struct device *d, } if ((new_value == 0) || (new_value == 1)) { bond->params.use_carrier = new_value; - printk(KERN_INFO DRV_NAME ": %s: Setting use_carrier to %d.\n", + pr_info(DRV_NAME ": %s: Setting use_carrier to %d.\n", bond->dev->name, new_value); } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Ignoring invalid use_carrier value %d.\n", bond->dev->name, new_value); } out: return count; } -static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); +static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, + bonding_show_carrier, bonding_store_carrier); /* @@ -1269,8 +1288,8 @@ static ssize_t bonding_store_active_slave(struct device *d, { int i; struct slave *slave; - struct slave *old_active = NULL; - struct slave *new_active = NULL; + struct slave *old_active = NULL; + struct slave *new_active = NULL; struct bonding *bond = to_bond(d); if (!rtnl_trylock()) @@ -1278,11 +1297,11 @@ static ssize_t bonding_store_active_slave(struct device *d, read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); - if (!USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME - ": %s: Unable to change active slave; %s is in mode %d\n", - bond->dev->name, bond->dev->name, bond->params.mode); - } else { + if (!USES_PRIMARY(bond->params.mode)) + pr_info(DRV_NAME ": %s: Unable to change active slave;" + " %s is in mode %d\n", + bond->dev->name, bond->dev->name, bond->params.mode); + else { bond_for_each_slave(bond, slave, i) { if (strnicmp (slave->dev->name, buf, @@ -1321,18 +1340,18 @@ static ssize_t bonding_store_active_slave(struct device *d, /* if we got here, then we didn't match the name of any slave */ if (strlen(buf) == 0 || buf[0] == '\n') { - printk(KERN_INFO DRV_NAME - ": %s: Setting active slave to None.\n", - bond->dev->name); + pr_info(DRV_NAME + ": %s: Setting active slave to None.\n", + bond->dev->name); bond->primary_slave = NULL; - bond_select_active_slave(bond); + bond_select_active_slave(bond); } else { - printk(KERN_INFO DRV_NAME - ": %s: Unable to set %.*s as active slave as it is not a slave.\n", - bond->dev->name, (int)strlen(buf) - 1, buf); + pr_info(DRV_NAME ": %s: Unable to set %.*s" + " as active slave as it is not a slave.\n", + bond->dev->name, (int)strlen(buf) - 1, buf); } } -out: + out: write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); rtnl_unlock(); @@ -1340,7 +1359,8 @@ out: return count; } -static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); +static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, + bonding_show_active_slave, bonding_store_active_slave); /* @@ -1357,7 +1377,7 @@ static ssize_t bonding_show_mii_status(struct device *d, curr = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); - return sprintf(buf, "%s\n", (curr) ? "up" : "down"); + return sprintf(buf, "%s\n", curr ? "up" : "down"); } static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); @@ -1374,7 +1394,9 @@ static ssize_t bonding_show_ad_aggregator(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.aggregator_id); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.aggregator_id); } return count; @@ -1394,7 +1416,9 @@ static ssize_t bonding_show_ad_num_ports(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0: ad_info.ports); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.ports); } return count; @@ -1414,7 +1438,9 @@ static ssize_t bonding_show_ad_actor_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.actor_key); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.actor_key); } return count; @@ -1434,7 +1460,9 @@ static ssize_t bonding_show_ad_partner_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.partner_key); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.partner_key); } return count; @@ -1454,9 +1482,8 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - if (!bond_3ad_get_active_agg_info(bond, &ad_info)) { + if (!bond_3ad_get_active_agg_info(bond, &ad_info)) count = sprintf(buf, "%pM\n", ad_info.partner_system); - } } return count; @@ -1549,9 +1576,8 @@ int bond_create_sysfs_entry(struct bonding *bond) int err; err = sysfs_create_group(&(dev->dev.kobj), &bonding_group); - if (err) { + if (err) printk(KERN_EMERG "eek! didn't create group!\n"); - } if (expected_refcount < 1) expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount); -- cgit v0.10.2 From 6d7ab43ccce5fddeca945ba6b06ba32cda4e3355 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:49 +0000 Subject: bonding: elminate bad refcount code The "expected_refcount" stuff in bonding sysfs module is a mistake. Sysfs does proper refcounting, and it is okay to remove a bond device that has some user process holding the file open. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ecb2020..e3fb7f5 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -40,12 +40,6 @@ #define to_dev(obj) container_of(obj, struct device, kobj) #define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd)))) -/*---------------------------- Declarations -------------------------------*/ - -static int expected_refcount = -1; - -/*------------------------------ Functions --------------------------------*/ - /* * "show" function for the bond_masters attribute. * The class parameter is ignored. @@ -112,18 +106,6 @@ static ssize_t bonding_store_bonds(struct class *cls, list_for_each_entry(bond, &bond_dev_list, bond_list) if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { - /* check the ref count on the bond's kobject. - * If it's > expected, then there's a file open, - * and we have to fail. - */ - if (atomic_read(&bond->dev->dev.kobj.kref.refcount) - > expected_refcount){ - pr_info(DRV_NAME - ": Unable remove bond %s due to open references.\n", - ifname); - res = -EPERM; - goto out_unlock; - } pr_info(DRV_NAME ": %s is being deleted...\n", bond->dev->name); @@ -1579,9 +1561,6 @@ int bond_create_sysfs_entry(struct bonding *bond) if (err) printk(KERN_EMERG "eek! didn't create group!\n"); - if (expected_refcount < 1) - expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount); - return err; } /* -- cgit v0.10.2 From 373500db927706d1f60785aff40b9884f789b01a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:50 +0000 Subject: bonding: network device names are case sensative The bonding device acts unlike all other Linux network device functions in that it ignores case of device names. The developer must have come from windows! Cleanup the management of names and use standard routines where possible. Flag places where bonding device still doesn't work right with network namespaces. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ea6b904..a6e7891 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5064,19 +5064,16 @@ static void bond_set_lockdep_class(struct net_device *dev) int bond_create(const char *name) { struct net_device *bond_dev; - struct bonding *bond; int res; rtnl_lock(); /* Check to see if the bond already exists. */ - if (name) { - list_for_each_entry(bond, &bond_dev_list, bond_list) - if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { - pr_err(DRV_NAME ": cannot add bond %s;" - " it already exists\n", name); - res = -EPERM; - goto out_rtnl; - } + /* FIXME: pass netns from caller */ + if (name && __dev_get_by_name(&init_net, name)) { + pr_err(DRV_NAME ": cannot add bond %s; already exists\n", + name); + res = -EEXIST; + goto out_rtnl; } bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index e3fb7f5..395f3b1 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -68,6 +68,17 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) return res; } +static struct net_device *bond_get_by_name(const char *ifname) +{ + struct bonding *bond; + + list_for_each_entry(bond, &bond_dev_list, bond_list) { + if (strncmp(bond->dev->name, ifname, IFNAMSIZ) == 0) + return bond->dev; + } + return NULL; +} + /* * "store" function for the bond_masters attribute. This is what * creates and deletes entire bonds. @@ -82,7 +93,6 @@ static ssize_t bonding_store_bonds(struct class *cls, char command[IFNAMSIZ + 1] = {0, }; char *ifname; int rv, res = count; - struct bonding *bond; sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; @@ -98,41 +108,35 @@ static ssize_t bonding_store_bonds(struct class *cls, pr_info(DRV_NAME ": Bond creation failed.\n"); res = rv; } - goto out; - } + } else if (command[0] == '-') { + struct net_device *bond_dev; - if (command[0] == '-') { rtnl_lock(); + bond_dev = bond_get_by_name(ifname); + if (bond_dev) { + pr_info(DRV_NAME ": %s is being deleted...\n", + ifname); + unregister_netdevice(bond_dev); + } else { + pr_err(DRV_NAME ": unable to delete non-existent %s\n", + ifname); + res = -ENODEV; + } + rtnl_unlock(); + } else + goto err_no_cmd; - list_for_each_entry(bond, &bond_dev_list, bond_list) - if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { - pr_info(DRV_NAME - ": %s is being deleted...\n", - bond->dev->name); - unregister_netdevice(bond->dev); - goto out_unlock; - } - - pr_err(DRV_NAME - ": unable to delete non-existent bond %s\n", ifname); - res = -ENODEV; - goto out_unlock; - } + /* Always return either count or an error. If you return 0, you'll + * get called forever, which is bad. + */ + return res; err_no_cmd: pr_err(DRV_NAME ": no command found in bonding_masters." " Use +ifname or -ifname.\n"); return -EPERM; - -out_unlock: - rtnl_unlock(); - - /* Always return either count or an error. If you return 0, you'll - * get called forever, which is bad. - */ -out: - return res; } + /* class attribute for bond_masters file. This ends up in /sys/class/net */ static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO, bonding_show_bonds, bonding_store_bonds); @@ -233,29 +237,16 @@ static ssize_t bonding_store_slaves(struct device *d, /* Got a slave name in ifname. Is it already in the list? */ found = 0; - read_lock(&bond->lock); - bond_for_each_slave(bond, slave, i) - if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { - pr_err(DRV_NAME - ": %s: Interface %s is already enslaved!\n", - bond->dev->name, ifname); - ret = -EPERM; - read_unlock(&bond->lock); - goto out; - } - read_unlock(&bond->lock); - pr_info(DRV_NAME ": %s: Adding slave %s.\n", - bond->dev->name, ifname); - dev = dev_get_by_name(&init_net, ifname); + /* FIXME: get netns from sysfs object */ + dev = __dev_get_by_name(&init_net, ifname); if (!dev) { pr_info(DRV_NAME ": %s: Interface %s does not exist!\n", bond->dev->name, ifname); - ret = -EPERM; + ret = -ENODEV; goto out; - } else - dev_put(dev); + } if (dev->flags & IFF_UP) { pr_err(DRV_NAME @@ -265,6 +256,22 @@ static ssize_t bonding_store_slaves(struct device *d, ret = -EPERM; goto out; } + + read_lock(&bond->lock); + bond_for_each_slave(bond, slave, i) + if (slave->dev == dev) { + pr_err(DRV_NAME + ": %s: Interface %s is already enslaved!\n", + bond->dev->name, ifname); + ret = -EPERM; + read_unlock(&bond->lock); + goto out; + } + read_unlock(&bond->lock); + + pr_info(DRV_NAME ": %s: Adding slave %s.\n", + bond->dev->name, ifname); + /* If this is the first slave, then we need to set the master's hardware address to be the same as the slave's. */ -- cgit v0.10.2 From 5c5129b54f2f346c86cd23fea67e71b45f7f84ff Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:51 +0000 Subject: bonding: use is_zero_ether_addr Remove bogus non-portable possibly unaligned way of testing for zero addres.. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 395f3b1..55bf34f 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "bonding.h" @@ -275,10 +276,9 @@ static ssize_t bonding_store_slaves(struct device *d, /* If this is the first slave, then we need to set the master's hardware address to be the same as the slave's. */ - if (!(*((u32 *) & (bond->dev->dev_addr[0])))) { + if (is_zero_ether_addr(bond->dev->dev_addr)) memcpy(bond->dev->dev_addr, dev->dev_addr, dev->addr_len); - } /* Set the slave's MTU to match the bond */ original_mtu = dev->mtu; -- cgit v0.10.2 From 181470fcf3f8ecc16625bc45a5f6f678e57bfb22 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Jun 2009 19:02:52 +0000 Subject: bonding: initialization rework Need to rework how bonding devices are initialized to make it more amenable to creating bonding devices via netlink. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a6e7891..d927f71 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -210,6 +210,7 @@ struct bond_parm_tbl ad_select_tbl[] = { /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); +static int bond_init(struct net_device *bond_dev); static void bond_deinit(struct net_device *bond_dev); /*---------------------------- General routines -----------------------------*/ @@ -4518,6 +4519,7 @@ static const struct ethtool_ops bond_ethtool_ops = { }; static const struct net_device_ops bond_netdev_ops = { + .ndo_init = bond_init, .ndo_uninit = bond_uninit, .ndo_open = bond_open, .ndo_stop = bond_close, @@ -4533,38 +4535,22 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, }; -/* - * Does not allocate but creates a /proc entry. - * Allowed to fail. - */ -static int bond_init(struct net_device *bond_dev) +static void bond_setup(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - pr_debug("Begin bond_init for %s\n", bond_dev->name); - /* initialize rwlocks */ rwlock_init(&bond->lock); rwlock_init(&bond->curr_slave_lock); bond->params = bonding_defaults; - bond->wq = create_singlethread_workqueue(bond_dev->name); - if (!bond->wq) - return -ENOMEM; - /* Initialize pointers */ - bond->first_slave = NULL; - bond->curr_active_slave = NULL; - bond->current_arp_slave = NULL; - bond->primary_slave = NULL; bond->dev = bond_dev; - bond->send_grat_arp = 0; - bond->send_unsol_na = 0; - bond->setup_by_slave = 0; INIT_LIST_HEAD(&bond->vlan_list); /* Initialize the device entry points */ + ether_setup(bond_dev); bond_dev->netdev_ops = &bond_netdev_ops; bond_dev->ethtool_ops = &bond_ethtool_ops; bond_set_mode_ops(bond, bond->params.mode); @@ -4575,6 +4561,8 @@ static int bond_init(struct net_device *bond_dev) bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; bond_dev->priv_flags |= IFF_BONDING; + bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; + if (bond->params.arp_interval) bond_dev->priv_flags |= IFF_MASTER_ARPMON; @@ -4599,10 +4587,6 @@ static int bond_init(struct net_device *bond_dev) NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); - bond_create_proc_entry(bond); - list_add_tail(&bond->bond_list, &bond_dev_list); - - return 0; } static void bond_work_cancel_all(struct bonding *bond) @@ -5056,6 +5040,29 @@ static void bond_set_lockdep_class(struct net_device *dev) netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL); } +/* + * Called from registration process + */ +static int bond_init(struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + + pr_debug("Begin bond_init for %s\n", bond_dev->name); + + bond->wq = create_singlethread_workqueue(bond_dev->name); + if (!bond->wq) + return -ENOMEM; + + bond_set_lockdep_class(bond_dev); + + netif_carrier_off(bond_dev); + + bond_create_proc_entry(bond); + list_add_tail(&bond->bond_list, &bond_dev_list); + + return 0; +} + /* Create a new bond based on the specified name and bonding parameters. * If name is NULL, obtain a suitable "bond%d" name for us. * Caller must NOT hold rtnl_lock; we need to release it here before we @@ -5077,7 +5084,7 @@ int bond_create(const char *name) } bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", - ether_setup); + bond_setup); if (!bond_dev) { pr_err(DRV_NAME ": %s: eek! can't alloc netdev!\n", name); @@ -5085,26 +5092,12 @@ int bond_create(const char *name) goto out_rtnl; } - bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; if (!name) { res = dev_alloc_name(bond_dev, "bond%d"); if (res < 0) goto out_netdev; } - /* bond_init() must be called after dev_alloc_name() (for the - * /proc files), but before register_netdevice(), because we - * need to set function pointers. - */ - - res = bond_init(bond_dev); - if (res < 0) - goto out_netdev; - - bond_set_lockdep_class(bond_dev); - - netif_carrier_off(bond_dev); - res = register_netdevice(bond_dev); if (res < 0) goto out_bond; -- cgit v0.10.2 From 13be8a126850692839934116fbdaf008bfdedec1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 12 Jun 2009 12:59:20 +0000 Subject: ieee802154: fix kconfig bool/tristate muckup menuconfig IEEE802154_DRIVERS is a bool that depends on tristate IEEE802154. If the IEEE802154 symbol is 'm', the bool becomes 'y'. This allows tristate symbols under IEEE802154_DRIVERS to be configured as 'y' and cause build problems. Changing the menuconfig bool to a tristate fixes this. drivers/built-in.o: In function `fake_scan_req': fakehard.c:(.text+0x46d625): undefined reference to `ieee802154_nl_scan_confirm' drivers/built-in.o: In function `fake_disassoc_req': fakehard.c:(.text+0x46d66f): undefined reference to `ieee802154_nl_disassoc_confirm' drivers/built-in.o: In function `fake_assoc_req': fakehard.c:(.text+0x46d6be): undefined reference to `ieee802154_nl_assoc_confirm' Signed-off-by: Randy Dunlap Acked-by: Sergey Lapin Signed-off-by: David S. Miller diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 25740bd..9b9f43a 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -1,5 +1,5 @@ menuconfig IEEE802154_DRIVERS - bool "IEEE 802.15.4 drivers" + tristate "IEEE 802.15.4 drivers" depends on NETDEVICES && IEEE802154 default y ---help--- -- cgit v0.10.2 From 125bb8f5637bd653244728f734bcac218986d910 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 11 Jun 2009 20:10:07 +0000 Subject: net: use a deferred timer in rt_check_expire For the sake of power saver lovers, use a deferrable timer to fire rt_check_expire() As some big routers cache equilibrium depends on garbage collection done in time, we take into account elapsed time between two rt_check_expire() invocations to adjust the amount of slots we have to check. Based on an initial idea and patch from Tero Kristo Signed-off-by: Eric Dumazet Signed-off-by: Tero Kristo Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a849bb1..cd76b3c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -131,8 +131,8 @@ static int ip_rt_min_advmss __read_mostly = 256; static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; static int rt_chain_length_max __read_mostly = 20; -static void rt_worker_func(struct work_struct *work); -static DECLARE_DELAYED_WORK(expires_work, rt_worker_func); +static struct delayed_work expires_work; +static unsigned long expires_ljiffies; /* * Interface to generic destination cache. @@ -787,9 +787,12 @@ static void rt_check_expire(void) struct rtable *rth, *aux, **rthp; unsigned long samples = 0; unsigned long sum = 0, sum2 = 0; + unsigned long delta; u64 mult; - mult = ((u64)ip_rt_gc_interval) << rt_hash_log; + delta = jiffies - expires_ljiffies; + expires_ljiffies = jiffies; + mult = ((u64)delta) << rt_hash_log; if (ip_rt_gc_timeout > 1) do_div(mult, ip_rt_gc_timeout); goal = (unsigned int)mult; @@ -3397,6 +3400,8 @@ int __init ip_rt_init(void) /* All the timers, started at system startup tend to synchronize. Perturb it a bit. */ + INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func); + expires_ljiffies = jiffies; schedule_delayed_work(&expires_work, net_random() % ip_rt_gc_interval + ip_rt_gc_interval); -- cgit v0.10.2 From e61a4b634a15c11725eac8e66b457ba411168c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 11 Jun 2009 19:38:02 +0000 Subject: ipv4: update ARPD help text Removed the statements about ARP cache size as this config option does not affect it. The cache size is controlled by neigh_table gc thresholds. Remove also expiremental and obsolete markings as the API originally intended for arp caching is useful for implementing ARP-like protocols (e.g. NHRP) in user space and has been there for a long enough time. Signed-off-by: Timo Teras Signed-off-by: David S. Miller diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 5b919f7..70491d9 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -273,29 +273,20 @@ config IP_PIMSM_V2 you want to play with it. config ARPD - bool "IP: ARP daemon support (EXPERIMENTAL)" - depends on EXPERIMENTAL + bool "IP: ARP daemon support" ---help--- - Normally, the kernel maintains an internal cache which maps IP - addresses to hardware addresses on the local network, so that - Ethernet/Token Ring/ etc. frames are sent to the proper address on - the physical networking layer. For small networks having a few - hundred directly connected hosts or less, keeping this address - resolution (ARP) cache inside the kernel works well. However, - maintaining an internal ARP cache does not work well for very large - switched networks, and will use a lot of kernel memory if TCP/IP - connections are made to many machines on the network. - - If you say Y here, the kernel's internal ARP cache will never grow - to more than 256 entries (the oldest entries are expired in a LIFO - manner) and communication will be attempted with the user space ARP - daemon arpd. Arpd then answers the address resolution request either - from its own cache or by asking the net. - - This code is experimental and also obsolete. If you want to use it, - you need to find a version of the daemon arpd on the net somewhere, - and you should also say Y to "Kernel/User network link driver", - below. If unsure, say N. + The kernel maintains an internal cache which maps IP addresses to + hardware addresses on the local network, so that Ethernet/Token Ring/ + etc. frames are sent to the proper address on the physical networking + layer. Normally, kernel uses the ARP protocol to resolve these + mappings. + + Saying Y here adds support to have an user space daemon to do this + resolution instead. This is useful for implementing an alternate + address resolution protocol (e.g. NHRP on mGRE tunnels) and also for + testing purposes. + + If unsure, say N. config SYN_COOKIES bool "IP: TCP syncookie support (disabled per default)" -- cgit v0.10.2 From 403dbb97f654cd59b87999fe1b64d29bf90b3a2a Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Sun, 14 Jun 2009 03:16:13 -0700 Subject: PIM-SM: namespace changes IPv4: - make PIM register vifs netns local - set the netns when a PIM register vif is created - make PIM available in all network namespaces (if CONFIG_IP_PIMSM_V2) by adding the protocol handler when multicast routing is initialized IPv6: - make PIM register vifs netns local - make PIM available in all network namespaces (if CONFIG_IPV6_PIMSM_V2) by adding the protocol handler when multicast routing is initialized Signed-off-by: Tom Goff Signed-off-by: David S. Miller diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index ffd9861..9a8da5e 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -226,9 +226,10 @@ static void reg_vif_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->netdev_ops = ®_vif_netdev_ops, dev->destructor = free_netdev; + dev->features |= NETIF_F_NETNS_LOCAL; } -static struct net_device *ipmr_reg_vif(void) +static struct net_device *ipmr_reg_vif(struct net *net) { struct net_device *dev; struct in_device *in_dev; @@ -238,6 +239,8 @@ static struct net_device *ipmr_reg_vif(void) if (dev == NULL) return NULL; + dev_net_set(dev, net); + if (register_netdevice(dev)) { free_netdev(dev); return NULL; @@ -448,7 +451,7 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock) */ if (net->ipv4.mroute_reg_vif_num >= 0) return -EADDRINUSE; - dev = ipmr_reg_vif(); + dev = ipmr_reg_vif(net); if (!dev) return -ENOBUFS; err = dev_set_allmulti(dev, 1); @@ -1031,16 +1034,6 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int if (v != net->ipv4.mroute_do_pim) { net->ipv4.mroute_do_pim = v; net->ipv4.mroute_do_assert = v; -#ifdef CONFIG_IP_PIMSM_V2 - if (net->ipv4.mroute_do_pim) - ret = inet_add_protocol(&pim_protocol, - IPPROTO_PIM); - else - ret = inet_del_protocol(&pim_protocol, - IPPROTO_PIM); - if (ret < 0) - ret = -EAGAIN; -#endif } rtnl_unlock(); return ret; @@ -1954,6 +1947,7 @@ static const struct file_operations ipmr_mfc_fops = { #ifdef CONFIG_IP_PIMSM_V2 static struct net_protocol pim_protocol = { .handler = pim_rcv, + .netns_ok = 1, }; #endif @@ -2040,8 +2034,19 @@ int __init ip_mr_init(void) err = register_netdevice_notifier(&ip_mr_notifier); if (err) goto reg_notif_fail; +#ifdef CONFIG_IP_PIMSM_V2 + if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) { + printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n"); + err = -EAGAIN; + goto add_proto_fail; + } +#endif return 0; +#ifdef CONFIG_IP_PIMSM_V2 +add_proto_fail: + unregister_netdevice_notifier(&ip_mr_notifier); +#endif reg_notif_fail: del_timer(&ipmr_expire_timer); unregister_pernet_subsys(&ipmr_net_ops); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index a35d8fc..c769f15 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -441,6 +441,7 @@ static void reg_vif_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->netdev_ops = ®_vif_netdev_ops; dev->destructor = free_netdev; + dev->features |= NETIF_F_NETNS_LOCAL; } static struct net_device *ip6mr_reg_vif(struct net *net) @@ -1077,7 +1078,18 @@ int __init ip6_mr_init(void) err = register_netdevice_notifier(&ip6_mr_notifier); if (err) goto reg_notif_fail; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) { + printk(KERN_ERR "ip6_mr_init: can't add PIM protocol\n"); + err = -EAGAIN; + goto add_proto_fail; + } +#endif return 0; +#ifdef CONFIG_IPV6_PIMSM_V2 +add_proto_fail: + unregister_netdevice_notifier(&ip6_mr_notifier); +#endif reg_notif_fail: del_timer(&ipmr_expire_timer); unregister_pernet_subsys(&ip6mr_net_ops); @@ -1363,14 +1375,6 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int if (v != net->ipv6.mroute_do_pim) { net->ipv6.mroute_do_pim = v; net->ipv6.mroute_do_assert = v; - if (net->ipv6.mroute_do_pim) - ret = inet6_add_protocol(&pim6_protocol, - IPPROTO_PIM); - else - ret = inet6_del_protocol(&pim6_protocol, - IPPROTO_PIM); - if (ret < 0) - ret = -EAGAIN; } rtnl_unlock(); return ret; -- cgit v0.10.2 From 1a097181ee8b0c492c021eb3dbaa5f9cd813ad0e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 14 Jun 2009 15:21:25 +0200 Subject: Bluetooth: Fix Kconfig issue with RFKILL integration Since the re-write of the RFKILL subsystem it is no longer good to just select RFKILL, but it is important to add a proper depends on rule. Based on a report by Alexander Beregalov Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 7725da9..59fdb1d 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -3,8 +3,9 @@ # menuconfig BT - depends on NET && !S390 tristate "Bluetooth subsystem support" + depends on NET && !S390 + depends on RFKILL || !RFKILL help Bluetooth is low-cost, low-power, short-range wireless technology. It was designed as a replacement for cables and other short-range -- cgit v0.10.2 From 3c4bdc4bd4af791a72147b6ebc29553808f53cea Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 14 Jun 2009 15:24:44 +0200 Subject: Bluetooth: Fix issue with uninitialized nsh.type in DTL-1 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current build shows a warning with the DTL-1 driver: CC [M] drivers/bluetooth/dtl1_cs.o drivers/bluetooth/dtl1_cs.c: In function ‘dtl1_hci_send_frame’: drivers/bluetooth/dtl1_cs.c:396: warning: ‘nsh.type’ may be used uninitialized in this function Fix this by adding a proper error for unknown packet types. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 901bdd9..2cc7b32 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -415,6 +415,8 @@ static int dtl1_hci_send_frame(struct sk_buff *skb) hdev->stat.sco_tx++; nsh.type = 0x83; break; + default: + return -EILSEQ; }; nsh.zero = 0; -- cgit v0.10.2 From 6d5701b29e392f77d222254aa8e375315d59f0aa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 14 Jun 2009 11:33:37 +0100 Subject: ASoC: Instantiate any forgotten DAPM widgets With the recent changes to the DAPM power checks it has become important to explicitly instantiate all widgets but some drivers were forgetting to do that. Since everything needs to do it add a call to instantiate them immediately before the card registration - it does no harm when it is called repeatedly and saves work in drivers. Tested-by: pHilipp Zabel Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3f44150..1d70829 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1389,6 +1389,9 @@ int snd_soc_init_card(struct snd_soc_device *socdev) snprintf(codec->card->longname, sizeof(codec->card->longname), "%s (%s)", card->name, codec->name); + /* Make sure all DAPM widgets are instantiated */ + snd_soc_dapm_new_widgets(codec); + ret = snd_card_register(codec->card); if (ret < 0) { printk(KERN_ERR "asoc: failed to register soundcard for %s\n", -- cgit v0.10.2 From 33745fb3448f90d2b9e414ccc6689e9ee70cfae4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Sun, 14 Jun 2009 12:51:30 +0200 Subject: ASoC: magician: fix PXA SSP clock polarity Follow-up fix needed since "ASoC: pxa-ssp.c fix clock/frame invert". Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index c89a3cd..326955d 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -184,7 +184,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; -- cgit v0.10.2 From 0a8eba9b7f7aa3ad0305627c99ad4d6deedd871d Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 14 Jun 2009 22:56:48 +0100 Subject: ramfs: ignore unknown mount options On systems where CONFIG_SHMEM is disabled, mounting tmpfs filesystems can fail when tmpfs options are used. This is because tmpfs creates a small wrapper around ramfs which rejects unknown options, and ramfs itself only supports a tiny subset of what tmpfs supports. This makes it pretty hard to use the same userspace systems across different configuration systems. As such, ramfs should ignore the tmpfs options when tmpfs is merely a wrapper around ramfs. This used to work before commit c3b1b1cbf0 as previously, ramfs would ignore all options. But now, we get: ramfs: bad mount option: size=10M mount: mounting mdev on /dev failed: Invalid argument Another option might be to restore the previous behavior, where ramfs simply ignored all unknown mount options ... which is what Hugh prefers. Signed-off-by: Mike Frysinger Signed-off-by: Hugh Dickins Acked-by: Matt Mackall Acked-by: Wu Fengguang Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 3a6b193..0ff7566 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -202,9 +202,12 @@ static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) return -EINVAL; opts->mode = option & S_IALLUGO; break; - default: - printk(KERN_ERR "ramfs: bad mount option: %s\n", p); - return -EINVAL; + /* + * We might like to report bad mount options here; + * but traditionally ramfs has ignored all mount options, + * and as it is used as a !CONFIG_SHMEM simple substitute + * for tmpfs, better continue to ignore other mount options. + */ } } -- cgit v0.10.2 From d9e89bf0c0a25273921381df8edd41e69b74b74c Mon Sep 17 00:00:00 2001 From: Andrea Borgia Date: Sun, 14 Jun 2009 12:16:17 +0200 Subject: ALSA: usb-audio - rework quirk for TerraTec Aureon USB 5.1 MkII This patch changes yet again the ID for the TTA cards, resulting in a more reasonable name: 1 [Aureon51MkII ]: USB-Audio - Aureon5.1MkII TerraTec Aureon5.1MkII at usb-0000:00:03.0-2, full speed Signed-off-by: Andrea Borgia Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f0f7624..f6f201e 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1989,7 +1989,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), USB_DEVICE(0x0ccd, 0x0028), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { .vendor_name = "TerraTec", - .product_name = "Aureon 5.1 MkII", + .product_name = "Aureon5.1MkII", .ifnum = QUIRK_NO_INTERFACE } }, -- cgit v0.10.2 From e0f7cb8c8cc6cccce28d2ce39ad8c60d23c3799f Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Mon, 15 Jun 2009 02:31:29 -0700 Subject: ipv4: Fix fib_trie rebalancing While doing trie_rebalance(): resize(), inflate(), halve() RCU free tnodes before updating their parents. It depends on RCU delaying the real destruction, but if RCU readers start after call_rcu() and before parent update they could access freed memory. It is currently prevented with preempt_disable() on the update side, but it's not safe, except maybe classic RCU, plus it conflicts with memory allocations with GFP_KERNEL flag used from these functions. This patch explicitly delays freeing of tnodes by adding them to the list, which is flushed after the update is finished. Reported-by: Yan Zheng Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 538d2a9..d1a39b1 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -123,6 +123,7 @@ struct tnode { union { struct rcu_head rcu; struct work_struct work; + struct tnode *tnode_free; }; struct node *child[0]; }; @@ -161,6 +162,8 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, static struct node *resize(struct trie *t, struct tnode *tn); static struct tnode *inflate(struct trie *t, struct tnode *tn); static struct tnode *halve(struct trie *t, struct tnode *tn); +/* tnodes to free after resize(); protected by RTNL */ +static struct tnode *tnode_free_head; static struct kmem_cache *fn_alias_kmem __read_mostly; static struct kmem_cache *trie_leaf_kmem __read_mostly; @@ -385,6 +388,29 @@ static inline void tnode_free(struct tnode *tn) call_rcu(&tn->rcu, __tnode_free_rcu); } +static void tnode_free_safe(struct tnode *tn) +{ + BUG_ON(IS_LEAF(tn)); + + if (node_parent((struct node *) tn)) { + tn->tnode_free = tnode_free_head; + tnode_free_head = tn; + } else { + tnode_free(tn); + } +} + +static void tnode_free_flush(void) +{ + struct tnode *tn; + + while ((tn = tnode_free_head)) { + tnode_free_head = tn->tnode_free; + tn->tnode_free = NULL; + tnode_free(tn); + } +} + static struct leaf *leaf_new(void) { struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); @@ -495,7 +521,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* No children */ if (tn->empty_children == tnode_child_length(tn)) { - tnode_free(tn); + tnode_free_safe(tn); return NULL; } /* One child */ @@ -509,7 +535,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* compress one level */ node_set_parent(n, NULL); - tnode_free(tn); + tnode_free_safe(tn); return n; } /* @@ -670,7 +696,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* compress one level */ node_set_parent(n, NULL); - tnode_free(tn); + tnode_free_safe(tn); return n; } @@ -756,7 +782,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) put_child(t, tn, 2*i, inode->child[0]); put_child(t, tn, 2*i+1, inode->child[1]); - tnode_free(inode); + tnode_free_safe(inode); continue; } @@ -801,9 +827,9 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) put_child(t, tn, 2*i, resize(t, left)); put_child(t, tn, 2*i+1, resize(t, right)); - tnode_free(inode); + tnode_free_safe(inode); } - tnode_free(oldtnode); + tnode_free_safe(oldtnode); return tn; nomem: { @@ -885,7 +911,7 @@ static struct tnode *halve(struct trie *t, struct tnode *tn) put_child(t, newBinNode, 1, right); put_child(t, tn, i/2, resize(t, newBinNode)); } - tnode_free(oldtnode); + tnode_free_safe(oldtnode); return tn; nomem: { @@ -989,7 +1015,6 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) t_key cindex, key; struct tnode *tp; - preempt_disable(); key = tn->key; while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { @@ -1001,16 +1026,18 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) (struct node *)tn, wasfull); tp = node_parent((struct node *) tn); + tnode_free_flush(); if (!tp) break; tn = tp; } /* Handle last (top) tnode */ - if (IS_TNODE(tn)) + if (IS_TNODE(tn)) { tn = (struct tnode *)resize(t, (struct tnode *)tn); + tnode_free_flush(); + } - preempt_enable(); return (struct node *)tn; } -- cgit v0.10.2 From ca44d6e60f9de26281fda203f58b570e1748c015 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Mon, 15 Jun 2009 02:31:47 -0700 Subject: pkt_sched: Rename PSCHED_US2NS and PSCHED_NS2US Let's use TICKS instead of US, so PSCHED_TICKS2NS and PSCHED_NS2TICKS (like in PSCHED_TICKS_PER_SEC already) to avoid misleading. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 120935b..82a3191 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -43,15 +43,15 @@ typedef long psched_tdiff_t; /* Avoid doing 64 bit divide */ #define PSCHED_SHIFT 6 -#define PSCHED_US2NS(x) ((s64)(x) << PSCHED_SHIFT) -#define PSCHED_NS2US(x) ((x) >> PSCHED_SHIFT) +#define PSCHED_TICKS2NS(x) ((s64)(x) << PSCHED_SHIFT) +#define PSCHED_NS2TICKS(x) ((x) >> PSCHED_SHIFT) -#define PSCHED_TICKS_PER_SEC PSCHED_NS2US(NSEC_PER_SEC) +#define PSCHED_TICKS_PER_SEC PSCHED_NS2TICKS(NSEC_PER_SEC) #define PSCHED_PASTPERFECT 0 static inline psched_time_t psched_get_time(void) { - return PSCHED_NS2US(ktime_to_ns(ktime_get())); + return PSCHED_NS2TICKS(ktime_to_ns(ktime_get())); } static inline psched_tdiff_t diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 3200979..24d17ce 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -484,7 +484,7 @@ void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires) wd->qdisc->flags |= TCQ_F_THROTTLED; time = ktime_set(0, 0); - time = ktime_add_ns(time, PSCHED_US2NS(expires)); + time = ktime_add_ns(time, PSCHED_TICKS2NS(expires)); hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS); } EXPORT_SYMBOL(qdisc_watchdog_schedule); @@ -1680,7 +1680,7 @@ static int psched_show(struct seq_file *seq, void *v) hrtimer_get_res(CLOCK_MONOTONIC, &ts); seq_printf(seq, "%08x %08x %08x %08x\n", - (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1), + (u32)NSEC_PER_USEC, (u32)PSCHED_TICKS2NS(1), 1000000, (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts))); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index d728d81..23a1676 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -509,7 +509,7 @@ static void cbq_ovl_delay(struct cbq_class *cl) q->pmask |= (1<delay_timer) && ktime_to_ns(ktime_sub( hrtimer_get_expires(&q->delay_timer), @@ -620,7 +620,7 @@ static enum hrtimer_restart cbq_undelay(struct hrtimer *timer) ktime_t time; time = ktime_set(0, 0); - time = ktime_add_ns(time, PSCHED_US2NS(now + delay)); + time = ktime_add_ns(time, PSCHED_TICKS2NS(now + delay)); hrtimer_start(&q->delay_timer, time, HRTIMER_MODE_ABS); } -- cgit v0.10.2 From 55f4fa4e33e90c6b25b4c8ed038392a73b654fef Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 23 Apr 2009 20:10:43 +0200 Subject: Maxim 1586 regulator driver The Maxim 1586 regulator is a voltage regulator with 2 voltage outputs, specially suitable for Marvell PXA chips. One output is in the range of required VCC_CORE by the PXA27x chips, the other in the VCC_USIM required as well by PXA27x chips. The chip is controlled through the I2C bus. Signed-off-by: Robert Jarzmik Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e58c0ce..707da4d2 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -56,6 +56,15 @@ config REGULATOR_BQ24022 charging select between 100 mA and 500 mA charging current limit. +config REGULATOR_MAX1586 + tristate "Maxim 1586/1587 voltage regulator" + depends on I2C + default n + help + This driver controls a Maxim 1586 or 1587 voltage output + regulator via I2C bus. The provided regulator is suitable + for PXA27x chips to control VCC_CORE and VCC_USIM voltages. + config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TPS695x0 PMIC" depends on TWL4030_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index bac133a..1d7de87 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o +obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c new file mode 100644 index 0000000..bbbb55f --- /dev/null +++ b/drivers/regulator/max1586.c @@ -0,0 +1,249 @@ +/* + * max1586.c -- Voltage and current regulation for the Maxim 1586 + * + * Copyright (C) 2008 Robert Jarzmik + * + * 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 +#include +#include +#include +#include +#include + +#define MAX1586_V3_MAX_VSEL 31 +#define MAX1586_V6_MAX_VSEL 3 + +#define MAX1586_V3_MIN_UV 700000 +#define MAX1586_V3_MAX_UV 1475000 +#define MAX1586_V3_STEP_UV 25000 + +#define MAX1586_V6_MIN_UV 0 +#define MAX1586_V6_MAX_UV 3000000 + +#define I2C_V3_SELECT (0 << 5) +#define I2C_V6_SELECT (1 << 5) + +/* + * V3 voltage + * On I2C bus, sending a "x" byte to the max1586 means : + * set V3 to 0.700V + (x & 0x1f) * 0.025V + */ +static int max1586_v3_calc_voltage(unsigned selector) +{ + return MAX1586_V3_MIN_UV + (MAX1586_V3_STEP_UV * selector); +} + +static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) +{ + struct i2c_client *client = rdev_get_drvdata(rdev); + unsigned selector; + u8 v3_prog; + + if (min_uV < MAX1586_V3_MIN_UV || min_uV > MAX1586_V3_MAX_UV) + return -EINVAL; + if (max_uV < MAX1586_V3_MIN_UV || max_uV > MAX1586_V3_MAX_UV) + return -EINVAL; + + selector = (min_uV - MAX1586_V3_MIN_UV) / MAX1586_V3_STEP_UV; + if (max1586_v3_calc_voltage(selector) > max_uV) + return -EINVAL; + + dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", + max1586_v3_calc_voltage(selector) / 1000); + + v3_prog = I2C_V3_SELECT | (u8) selector; + return i2c_smbus_write_byte(client, v3_prog); +} + +static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector) +{ + if (selector > MAX1586_V3_MAX_VSEL) + return -EINVAL; + return max1586_v3_calc_voltage(selector); +} + +/* + * V6 voltage + * On I2C bus, sending a "x" byte to the max1586 means : + * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) + * As regulator framework doesn't accept voltages to be 0V, we use 1uV. + */ +static int max1586_v6_calc_voltage(unsigned selector) +{ + static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; + + return voltages_uv[selector]; +} + +static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) +{ + struct i2c_client *client = rdev_get_drvdata(rdev); + unsigned selector; + u8 v6_prog; + + if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV) + return -EINVAL; + if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV) + return -EINVAL; + + if (min_uV >= 3000000) + selector = 3; + if (min_uV < 3000000) + selector = 2; + if (min_uV < 2500000) + selector = 1; + if (min_uV < 1800000) + selector = 0; + + if (max1586_v6_calc_voltage(selector) > max_uV) + return -EINVAL; + + dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", + max1586_v6_calc_voltage(selector) / 1000); + + v6_prog = I2C_V6_SELECT | (u8) selector; + return i2c_smbus_write_byte(client, v6_prog); +} + +static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector) +{ + if (selector > MAX1586_V6_MAX_VSEL) + return -EINVAL; + return max1586_v6_calc_voltage(selector); +} + +/* + * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back + * the set up value. + */ +static struct regulator_ops max1586_v3_ops = { + .set_voltage = max1586_v3_set, + .list_voltage = max1586_v3_list, +}; + +static struct regulator_ops max1586_v6_ops = { + .set_voltage = max1586_v6_set, + .list_voltage = max1586_v6_list, +}; + +static struct regulator_desc max1586_reg[] = { + { + .name = "Output_V3", + .id = MAX1586_V3, + .ops = &max1586_v3_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = MAX1586_V3_MAX_VSEL + 1, + .owner = THIS_MODULE, + }, + { + .name = "Output_V6", + .id = MAX1586_V6, + .ops = &max1586_v6_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = MAX1586_V6_MAX_VSEL + 1, + .owner = THIS_MODULE, + }, +}; + +static int max1586_pmic_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct regulator_dev **rdev; + struct max1586_platform_data *pdata = client->dev.platform_data; + int i, id, ret = 0; + + rdev = kzalloc(sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), + GFP_KERNEL); + if (!rdev) + return -ENOMEM; + + ret = -EINVAL; + for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { + id = pdata->subdevs[i].id; + if (!pdata->subdevs[i].platform_data) + continue; + if (id < MAX1586_V3 || id > MAX1586_V6) { + dev_err(&client->dev, "invalid regulator id %d\n", id); + goto err; + } + rdev[i] = regulator_register(&max1586_reg[id], &client->dev, + pdata->subdevs[i].platform_data, + client); + if (IS_ERR(rdev[i])) { + ret = PTR_ERR(rdev[i]); + dev_err(&client->dev, "failed to register %s\n", + max1586_reg[id].name); + goto err; + } + } + + i2c_set_clientdata(client, rdev); + dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); + return 0; + +err: + while (--i >= 0) + regulator_unregister(rdev[i]); + kfree(rdev); + return ret; +} + +static int max1586_pmic_remove(struct i2c_client *client) +{ + struct regulator_dev **rdev = i2c_get_clientdata(client); + int i; + + for (i = 0; i <= MAX1586_V6; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + kfree(rdev); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static const struct i2c_device_id max1586_id[] = { + { "max1586", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max1586_id); + +static struct i2c_driver max1586_pmic_driver = { + .probe = max1586_pmic_probe, + .remove = max1586_pmic_remove, + .driver = { + .name = "max1586", + }, + .id_table = max1586_id, +}; + +static int __init max1586_pmic_init(void) +{ + return i2c_add_driver(&max1586_pmic_driver); +} +subsys_initcall(max1586_pmic_init); + +static void __exit max1586_pmic_exit(void) +{ + i2c_del_driver(&max1586_pmic_driver); +} +module_exit(max1586_pmic_exit); + +/* Module information */ +MODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver"); +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/regulator/max1586.h b/include/linux/regulator/max1586.h new file mode 100644 index 0000000..2056973 --- /dev/null +++ b/include/linux/regulator/max1586.h @@ -0,0 +1,52 @@ +/* + * max1586.h -- Voltage regulation for the Maxim 1586 + * + * Copyright (C) 2008 Robert Jarzmik + * + * 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 REGULATOR_MAX1586 +#define REGULATOR_MAX1586 + +#include + +#define MAX1586_V3 0 +#define MAX1586_V6 1 + +/** + * max1586_subdev_data - regulator data + * @id: regulator Id (either MAX1586_V3 or MAX1586_V6) + * @name: regulator cute name (example for V3: "vcc_core") + * @platform_data: regulator init data (contraints, supplies, ...) + */ +struct max1586_subdev_data { + int id; + char *name; + struct regulator_init_data *platform_data; +}; + +/** + * max1586_platform_data - platform data for max1586 + * @num_subdevs: number of regultors used (may be 1 or 2) + * @subdevs: regulator used + * At most, there will be a regulator for V3 and one for V6 voltages. + */ +struct max1586_platform_data { + int num_subdevs; + struct max1586_subdev_data *subdevs; +}; + +#endif -- cgit v0.10.2 From 1d98cccf7f8b944ba4ea56d14bbb7c2eeee59bfe Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 26 Apr 2009 16:49:39 +0300 Subject: regulator: add userspace-consumer driver The userspace-consumer driver allows control of voltage and current regulator state from userspace. This is required for fine-grained power management of devices that are completely controller by userspace applications, e.g. a GPS transciever connected to a serial port. Signed-off-by: Mike Rapoport Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 707da4d2..5bec17c 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -47,6 +47,16 @@ config REGULATOR_VIRTUAL_CONSUMER If unsure, say no. +config REGULATOR_USERSPACE_CONSUMER + tristate "Userspace regulator consumer support" + default n + help + There are some classes of devices that are controlled entirely + from user space. Usersapce consumer driver provides ability to + control power supplies for such devices. + + If unsure, say no. + config REGULATOR_BQ24022 tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" default n diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 1d7de87..faf7bcc 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_REGULATOR) += core.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o +obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c new file mode 100644 index 0000000..71fcf9d --- /dev/null +++ b/drivers/regulator/userspace-consumer.c @@ -0,0 +1,200 @@ +/* + * userspace-consumer.c + * + * Copyright 2009 CompuLab, Ltd. + * + * Author: Mike Rapoport + * + * Based of virtual consumer driver: + * Copyright 2008 Wolfson Microelectronics PLC. + * Author: Mark Brown + * + * 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 +#include +#include +#include +#include + +struct userspace_consumer_data { + const char *name; + + struct mutex lock; + bool enabled; + + int num_supplies; + struct regulator_bulk_data *supplies; +}; + +static ssize_t show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct userspace_consumer_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} + +static ssize_t show_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct userspace_consumer_data *data = dev_get_drvdata(dev); + + if (data->enabled) + return sprintf(buf, "enabled\n"); + + return sprintf(buf, "disabled\n"); +} + +static ssize_t set_state(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct userspace_consumer_data *data = dev_get_drvdata(dev); + bool enabled; + int ret; + + /* + * sysfs_streq() doesn't need the \n's, but we add them so the strings + * will be shared with show_state(), above. + */ + if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1")) + enabled = true; + else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0")) + enabled = false; + else { + dev_err(dev, "Configuring invalid mode\n"); + return count; + } + + mutex_lock(&data->lock); + if (enabled != data->enabled) { + if (enabled) + ret = regulator_bulk_enable(data->num_supplies, + data->supplies); + else + ret = regulator_bulk_disable(data->num_supplies, + data->supplies); + + if (ret == 0) + data->enabled = enabled; + else + dev_err(dev, "Failed to configure state: %d\n", ret); + } + mutex_unlock(&data->lock); + + return count; +} + +static DEVICE_ATTR(name, 0444, show_name, NULL); +static DEVICE_ATTR(state, 0644, show_state, set_state); + +static struct device_attribute *attributes[] = { + &dev_attr_name, + &dev_attr_state, +}; + +static int regulator_userspace_consumer_probe(struct platform_device *pdev) +{ + struct regulator_userspace_consumer_data *pdata; + struct userspace_consumer_data *drvdata; + int ret, i; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -EINVAL; + + drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL); + if (drvdata == NULL) + return -ENOMEM; + + drvdata->name = pdata->name; + drvdata->num_supplies = pdata->num_supplies; + drvdata->supplies = pdata->supplies; + + mutex_init(&drvdata->lock); + + ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies, + drvdata->supplies); + if (ret) { + dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret); + goto err_alloc_supplies; + } + + for (i = 0; i < ARRAY_SIZE(attributes); i++) { + ret = device_create_file(&pdev->dev, attributes[i]); + if (ret != 0) + goto err_create_attrs; + } + + if (pdata->init_on) + ret = regulator_bulk_enable(drvdata->num_supplies, + drvdata->supplies); + + drvdata->enabled = pdata->init_on; + + if (ret) { + dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret); + goto err_create_attrs; + } + + platform_set_drvdata(pdev, drvdata); + + return 0; + +err_create_attrs: + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(&pdev->dev, attributes[i]); + + regulator_bulk_free(drvdata->num_supplies, drvdata->supplies); + +err_alloc_supplies: + kfree(drvdata); + return ret; +} + +static int regulator_userspace_consumer_remove(struct platform_device *pdev) +{ + struct userspace_consumer_data *data = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(&pdev->dev, attributes[i]); + + if (data->enabled) + regulator_bulk_disable(data->num_supplies, data->supplies); + + regulator_bulk_free(data->num_supplies, data->supplies); + kfree(data); + + return 0; +} + +static struct platform_driver regulator_userspace_consumer_driver = { + .probe = regulator_userspace_consumer_probe, + .remove = regulator_userspace_consumer_remove, + .driver = { + .name = "reg-userspace-consumer", + }, +}; + + +static int __init regulator_userspace_consumer_init(void) +{ + return platform_driver_register(®ulator_userspace_consumer_driver); +} +module_init(regulator_userspace_consumer_init); + +static void __exit regulator_userspace_consumer_exit(void) +{ + platform_driver_unregister(®ulator_userspace_consumer_driver); +} +module_exit(regulator_userspace_consumer_exit); + +MODULE_AUTHOR("Mike Rapoport "); +MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/regulator/userspace-consumer.h b/include/linux/regulator/userspace-consumer.h new file mode 100644 index 0000000..b4554ce --- /dev/null +++ b/include/linux/regulator/userspace-consumer.h @@ -0,0 +1,25 @@ +#ifndef __REGULATOR_PLATFORM_CONSUMER_H_ +#define __REGULATOR_PLATFORM_CONSUMER_H_ + +struct regulator_consumer_supply; + +/** + * struct regulator_userspace_consumer_data - line consumer + * initialisation data. + * + * @name: Name for the consumer line + * @num_supplies: Number of supplies feeding the line + * @supplies: Supplies configuration. + * @init_on: Set if the regulators supplying the line should be + * enabled during initialisation + */ +struct regulator_userspace_consumer_data { + const char *name; + + int num_supplies; + struct regulator_bulk_data *supplies; + + bool init_on; +}; + +#endif /* __REGULATOR_PLATFORM_CONSUMER_H_ */ -- cgit v0.10.2 From 7c314991d7d7ad4edf96e8322bcb30e8452957b7 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 28 Apr 2009 12:01:16 +0100 Subject: regulator: build fix for powerpc - renamed show_state This patch fixes the follwing build failure on powerpc:- > Today's linux-next build (powerpc allyesconfig) failed like this: > > drivers/regulator/userspace-consumer.c:43: error: conflicting types > for 'show_state' > include/linux/sched.h:273: note: previous definition of 'show_state' > was here > > Caused by commit 5defa2bce704ca4151cfe24e4297aa7797cafd22 ("regulator: > add userspace-consumer driver") which I have reverted for today. Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 71fcf9d..06d2fa9 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -32,7 +32,7 @@ struct userspace_consumer_data { struct regulator_bulk_data *supplies; }; -static ssize_t show_name(struct device *dev, +static ssize_t reg_show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct userspace_consumer_data *data = dev_get_drvdata(dev); @@ -40,7 +40,7 @@ static ssize_t show_name(struct device *dev, return sprintf(buf, "%s\n", data->name); } -static ssize_t show_state(struct device *dev, +static ssize_t reg_show_state(struct device *dev, struct device_attribute *attr, char *buf) { struct userspace_consumer_data *data = dev_get_drvdata(dev); @@ -51,7 +51,7 @@ static ssize_t show_state(struct device *dev, return sprintf(buf, "disabled\n"); } -static ssize_t set_state(struct device *dev, struct device_attribute *attr, +static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct userspace_consumer_data *data = dev_get_drvdata(dev); @@ -90,8 +90,8 @@ static ssize_t set_state(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(name, 0444, show_name, NULL); -static DEVICE_ATTR(state, 0644, show_state, set_state); +static DEVICE_ATTR(name, 0444, reg_show_name, NULL); +static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state); static struct device_attribute *attributes[] = { &dev_attr_name, -- cgit v0.10.2 From 5a1b22beeff30d870bf2169a37e343e06cb5db3a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 27 Apr 2009 18:21:18 +0100 Subject: regulator: Move regulator drivers to subsys_initcall() Regulators need to be available early in init in order to allow them to be available for consumers when requested. This is generally done by registering them at subsys_initcall() time but not all regulator drivers have done that. Convert these drivers to do so in order to mimimise future support. Signed-off-by: Mark Brown Acked-by: Mike Rapoport Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index c6628f5..b8b89ef 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -504,7 +504,7 @@ static int __init da903x_regulator_init(void) { return platform_driver_register(&da903x_regulator_driver); } -module_init(da903x_regulator_init); +subsys_initcall(da903x_regulator_init); static void __exit da903x_regulator_exit(void) { diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 23d5546..6e0bede 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -117,7 +117,7 @@ static int __init regulator_fixed_voltage_init(void) { return platform_driver_register(®ulator_fixed_voltage_driver); } -module_init(regulator_fixed_voltage_init); +subsys_initcall(regulator_fixed_voltage_init); static void __exit regulator_fixed_voltage_exit(void) { diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index cd761d8..8e14900 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -316,7 +316,7 @@ static int __init pcf50633_regulator_init(void) { return platform_driver_register(&pcf50633_regulator_driver); } -module_init(pcf50633_regulator_init); +subsys_initcall(pcf50633_regulator_init); static void __exit pcf50633_regulator_exit(void) { diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 1574260..01a6c95 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -380,7 +380,7 @@ static int __init wm8400_regulator_init(void) { return platform_driver_register(&wm8400_regulator_driver); } -module_init(wm8400_regulator_init); +subsys_initcall(wm8400_regulator_init); static void __exit wm8400_regulator_exit(void) { -- cgit v0.10.2 From 9035cefc2d4b67591cbc2e4e8fbc8d73901ca9eb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Apr 2009 11:13:54 +0100 Subject: regulator: Support list_voltage for fixed voltage regulator Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 6e0bede..4c525af 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -44,10 +44,22 @@ static int fixed_voltage_get_voltage(struct regulator_dev *dev) return data->microvolts; } +static int fixed_voltage_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + if (selector != 0) + return -EINVAL; + + return data->microvolts; +} + static struct regulator_ops fixed_voltage_ops = { .is_enabled = fixed_voltage_is_enabled, .enable = fixed_voltage_enable, .get_voltage = fixed_voltage_get_voltage, + .list_voltage = fixed_voltage_list_voltage, }; static int regulator_fixed_voltage_probe(struct platform_device *pdev) @@ -69,7 +81,8 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; - drvdata->desc.ops = &fixed_voltage_ops, + drvdata->desc.ops = &fixed_voltage_ops; + drvdata->desc.n_voltages = 1; drvdata->microvolts = config->microvolts; -- cgit v0.10.2 From 38c53c89139e6140b895b419b18c586e8593a6e8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Apr 2009 11:13:55 +0100 Subject: regulator: Set MODULE_ALIAS for regulator drivers Several of the regulator drivers didn't have MODULE_ALIAS so couldn't be auto loaded. Add the MODULE_ALIAS in case they do get built as modules. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 4c525af..cdc674f 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -141,3 +141,4 @@ module_exit(regulator_fixed_voltage_exit); MODULE_AUTHOR("Mark Brown "); MODULE_DESCRIPTION("Fixed voltage regulator"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:reg-fixed-voltage"); diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 71403fa..e7db566 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -347,3 +347,4 @@ module_exit(regulator_virtual_consumer_exit); MODULE_AUTHOR("Mark Brown "); MODULE_DESCRIPTION("Virtual regulator consumer"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:reg-virt-consumer"); diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 771eca1..17a00b0 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1570,3 +1570,4 @@ module_exit(wm8350_regulator_exit); MODULE_AUTHOR("Liam Girdwood"); MODULE_DESCRIPTION("WM8350 voltage and current regulator driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-regulator"); -- cgit v0.10.2 From 1909e2f658ee6ec5bcca62a5599f5653857cfe18 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Apr 2009 15:21:37 -0700 Subject: regulator: remove driver_data direct access of struct device In the near future, the driver core is going to not allow direct access to the driver_data pointer in struct device. Instead, the functions dev_get_drvdata() and dev_set_drvdata() should be used. These functions have been around since the beginning, so are backwards compatible with all older kernel versions. Cc: Mark Brown Cc: Liam Girdwood Signed-off-by: Greg Kroah-Hartman Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 01a6c95..d9a2c98 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -320,7 +320,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; rdev = regulator_register(®ulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, pdev->dev.driver_data); + pdev->dev.platform_data, dev_get_drvdata(&pdev->dev)); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -359,7 +359,7 @@ static struct platform_driver wm8400_regulator_driver = { int wm8400_register_regulator(struct device *dev, int reg, struct regulator_init_data *initdata) { - struct wm8400 *wm8400 = dev->driver_data; + struct wm8400 *wm8400 = dev_get_drvdata(dev); if (wm8400->regulators[reg].name) return -EBUSY; @@ -369,8 +369,8 @@ int wm8400_register_regulator(struct device *dev, int reg, wm8400->regulators[reg].name = "wm8400-regulator"; wm8400->regulators[reg].id = reg; wm8400->regulators[reg].dev.parent = dev; - wm8400->regulators[reg].dev.driver_data = wm8400; wm8400->regulators[reg].dev.platform_data = initdata; + dev_set_drvdata(&wm8400->regulators[reg].dev, wm8400); return platform_device_register(&wm8400->regulators[reg]); } -- cgit v0.10.2 From 0cbdf7bce5b98807b946d1a96956f30dcae24a50 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 19 May 2009 07:33:55 +0200 Subject: LP3971 PMIC regulator driver (updated and combined version) This patch adds regulator drivers for National Semiconductors LP3971 PMIC. This LP3971 PMIC controller has 3 DC/DC voltage converters and 5 low drop-out (LDO) regulators. LP3971 PMIC controller uses I2C interface. Reviewed-by: Kyungmin Park Signed-off-by: Marek Szyprowski Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 5bec17c..f431779 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -110,4 +110,11 @@ config REGULATOR_PCF50633 Say Y here to support the voltage regulators and convertors on PCF50633 +config REGULATOR_LP3971 + tristate "National Semiconductors LP3971 PMIC regulator driver" + depends on I2C + help + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3971 PMIC + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index faf7bcc..4d762c4 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o +obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c new file mode 100644 index 0000000..35abebe --- /dev/null +++ b/drivers/regulator/lp3971.c @@ -0,0 +1,562 @@ +/* + * Regulator driver for National Semiconductors LP3971 PMIC chip + * + * Copyright (C) 2009 Samsung Electronics + * Author: Marek Szyprowski + * + * Based on wm8350.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +struct lp3971 { + struct device *dev; + struct mutex io_lock; + struct i2c_client *i2c; + int num_regulators; + struct regulator_dev **rdev; +}; + +static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg); +static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val); + +#define LP3971_SYS_CONTROL1_REG 0x07 + +/* System control register 1 initial value, + bits 4 and 5 are EPROM programmable */ +#define SYS_CONTROL1_INIT_VAL 0x40 +#define SYS_CONTROL1_INIT_MASK 0xCF + +#define LP3971_BUCK_VOL_ENABLE_REG 0x10 +#define LP3971_BUCK_VOL_CHANGE_REG 0x20 + +/* Voltage control registers shift: + LP3971_BUCK1 -> 0 + LP3971_BUCK2 -> 4 + LP3971_BUCK3 -> 6 +*/ +#define BUCK_VOL_CHANGE_SHIFT(x) (((1 << x) & ~0x01) << 1) +#define BUCK_VOL_CHANGE_FLAG_GO 0x01 +#define BUCK_VOL_CHANGE_FLAG_TARGET 0x02 +#define BUCK_VOL_CHANGE_FLAG_MASK 0x03 + +#define LP3971_BUCK1_BASE 0x23 +#define LP3971_BUCK2_BASE 0x29 +#define LP3971_BUCK3_BASE 0x32 + +const static int buck_base_addr[] = { + LP3971_BUCK1_BASE, + LP3971_BUCK2_BASE, + LP3971_BUCK3_BASE, +}; + +#define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x]) +#define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1) + +const static int buck_voltage_map[] = { + 0, 800, 850, 900, 950, 1000, 1050, 1100, + 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, + 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, + 3000, 3300, +}; + +#define BUCK_TARGET_VOL_MASK 0x3f +#define BUCK_TARGET_VOL_MIN_IDX 0x01 +#define BUCK_TARGET_VOL_MAX_IDX 0x19 + +#define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2) + +#define LP3971_LDO_ENABLE_REG 0x12 +#define LP3971_LDO_VOL_CONTR_BASE 0x39 + +/* Voltage control registers: + LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0 + LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0 + LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1 + LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1 + LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2 +*/ +#define LP3971_LDO_VOL_CONTR_REG(x) (LP3971_LDO_VOL_CONTR_BASE + (x >> 1)) + +/* Voltage control registers shift: + LP3971_LDO1 -> 0, LP3971_LDO2 -> 4 + LP3971_LDO3 -> 0, LP3971_LDO4 -> 4 + LP3971_LDO5 -> 0 +*/ +#define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2) +#define LDO_VOL_CONTR_MASK 0x0f + +const static int ldo45_voltage_map[] = { + 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, + 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, +}; + +const static int ldo123_voltage_map[] = { + 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, + 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, +}; + +const static int *ldo_voltage_map[] = { + ldo123_voltage_map, /* LDO1 */ + ldo123_voltage_map, /* LDO2 */ + ldo123_voltage_map, /* LDO3 */ + ldo45_voltage_map, /* LDO4 */ + ldo45_voltage_map, /* LDO5 */ +}; + +#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)]) + +#define LDO_VOL_MIN_IDX 0x00 +#define LDO_VOL_MAX_IDX 0x0f + +static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index) +{ + int ldo = rdev_get_id(dev) - LP3971_LDO1; + return 1000 * LDO_VOL_VALUE_MAP(ldo)[index]; +} + +static int lp3971_ldo_is_enabled(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 mask = 1 << (1 + ldo); + u16 val; + + val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG); + return (val & mask) != 0; +} + +static int lp3971_ldo_enable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 mask = 1 << (1 + ldo); + + return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask); +} + +static int lp3971_ldo_disable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 mask = 1 << (1 + ldo); + + return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0); +} + +static int lp3971_ldo_get_voltage(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 val, reg; + + reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo)); + val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK; + + return 1000 * LDO_VOL_VALUE_MAP(ldo)[val]; +} + +static int lp3971_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = LDO_VOL_VALUE_MAP(ldo); + u16 val; + + if (min_vol < vol_map[LDO_VOL_MIN_IDX] || + min_vol > vol_map[LDO_VOL_MAX_IDX]) + return -EINVAL; + + for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++) + if (vol_map[val] >= min_vol) + break; + + if (vol_map[val] > max_vol) + return -EINVAL; + + return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), + LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val); +} + +static struct regulator_ops lp3971_ldo_ops = { + .list_voltage = lp3971_ldo_list_voltage, + .is_enabled = lp3971_ldo_is_enabled, + .enable = lp3971_ldo_enable, + .disable = lp3971_ldo_disable, + .get_voltage = lp3971_ldo_get_voltage, + .set_voltage = lp3971_ldo_set_voltage, +}; + +static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) +{ + return 1000 * buck_voltage_map[index]; +} + +static int lp3971_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG); + return (val & mask) != 0; +} + +static int lp3971_dcdc_enable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 mask = 1 << (buck * 2); + + return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask); +} + +static int lp3971_dcdc_disable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 mask = 1 << (buck * 2); + + return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0); +} + +static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 reg; + int val; + + reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck)); + reg &= BUCK_TARGET_VOL_MASK; + + if (reg <= BUCK_TARGET_VOL_MAX_IDX) + val = 1000 * buck_voltage_map[reg]; + else { + val = 0; + dev_warn(&dev->dev, "chip reported incorrect voltage value.\n"); + } + + return val; +} + +static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = buck_voltage_map; + u16 val; + int ret; + + if (min_vol < vol_map[BUCK_TARGET_VOL_MIN_IDX] || + min_vol > vol_map[BUCK_TARGET_VOL_MAX_IDX]) + return -EINVAL; + + for (val = BUCK_TARGET_VOL_MIN_IDX; val <= BUCK_TARGET_VOL_MAX_IDX; + val++) + if (vol_map[val] >= min_vol) + break; + + if (vol_map[val] > max_vol) + return -EINVAL; + + ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck), + BUCK_TARGET_VOL_MASK, val); + if (ret) + return ret; + + ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG, + BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck), + BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck)); + if (ret) + return ret; + + return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG, + BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck), + 0 << BUCK_VOL_CHANGE_SHIFT(buck)); +} + +static struct regulator_ops lp3971_dcdc_ops = { + .list_voltage = lp3971_dcdc_list_voltage, + .is_enabled = lp3971_dcdc_is_enabled, + .enable = lp3971_dcdc_enable, + .disable = lp3971_dcdc_disable, + .get_voltage = lp3971_dcdc_get_voltage, + .set_voltage = lp3971_dcdc_set_voltage, +}; + +static struct regulator_desc regulators[] = { + { + .name = "LDO1", + .id = LP3971_LDO1, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO2", + .id = LP3971_LDO2, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO3", + .id = LP3971_LDO3, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO4", + .id = LP3971_LDO4, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo45_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO5", + .id = LP3971_LDO5, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo45_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC1", + .id = LP3971_DCDC1, + .ops = &lp3971_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC2", + .id = LP3971_DCDC2, + .ops = &lp3971_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC3", + .id = LP3971_DCDC3, + .ops = &lp3971_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, +}; + +static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count, + u16 *dest) +{ + int ret; + + if (count != 1) + return -EIO; + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0 || count != 1) + return -EIO; + + *dest = ret; + return 0; +} + +static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count, + const u16 *src) +{ + int ret; + + if (count != 1) + return -EIO; + ret = i2c_smbus_write_byte_data(i2c, reg, *src); + if (ret >= 0) + return 0; + + return ret; +} + +static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg) +{ + u16 val = 0; + + mutex_lock(&lp3971->io_lock); + + lp3971_i2c_read(lp3971->i2c, reg, 1, &val); + + dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val&0xff); + + mutex_unlock(&lp3971->io_lock); + + return val & 0xff; +} + +static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val) +{ + u16 tmp; + int ret; + + mutex_lock(&lp3971->io_lock); + + ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp); + tmp = (tmp & ~mask) | val; + if (ret == 0) { + ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp); + dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val&0xff); + } + mutex_unlock(&lp3971->io_lock); + + return ret; +} + +static int setup_regulators(struct lp3971 *lp3971, + struct lp3971_platform_data *pdata) +{ + int i, err; + int num_regulators = pdata->num_regulators; + lp3971->num_regulators = num_regulators; + lp3971->rdev = kzalloc(sizeof(struct regulator_dev *) * num_regulators, + GFP_KERNEL); + + /* Instantiate the regulators */ + for (i = 0; i < num_regulators; i++) { + int id = pdata->regulators[i].id; + lp3971->rdev[i] = regulator_register(®ulators[id], + lp3971->dev, pdata->regulators[i].initdata, lp3971); + + err = IS_ERR(lp3971->rdev[i]); + if (err) { + dev_err(lp3971->dev, "regulator init failed: %d\n", + err); + goto error; + } + } + + return 0; +error: + for (i = 0; i < num_regulators; i++) + if (lp3971->rdev[i]) + regulator_unregister(lp3971->rdev[i]); + kfree(lp3971->rdev); + lp3971->rdev = NULL; + return err; +} + +static int __devinit lp3971_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct lp3971 *lp3971; + struct lp3971_platform_data *pdata = i2c->dev.platform_data; + int ret; + u16 val; + + lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL); + if (lp3971 == NULL) { + ret = -ENOMEM; + goto err; + } + + lp3971->i2c = i2c; + lp3971->dev = &i2c->dev; + i2c_set_clientdata(i2c, lp3971); + + mutex_init(&lp3971->io_lock); + + /* Detect LP3971 */ + ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val); + if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) + ret = -ENODEV; + if (ret < 0) { + dev_err(&i2c->dev, "failed to detect device\n"); + goto err_detect; + } + + if (pdata) { + ret = setup_regulators(lp3971, pdata); + if (ret < 0) + goto err_detect; + } else + dev_warn(lp3971->dev, "No platform init data supplied\n"); + + return 0; + +err_detect: + i2c_set_clientdata(i2c, NULL); + kfree(lp3971); +err: + return ret; +} + +static int __devexit lp3971_i2c_remove(struct i2c_client *i2c) +{ + struct lp3971 *lp3971 = i2c_get_clientdata(i2c); + int i; + for (i = 0; i < lp3971->num_regulators; i++) + if (lp3971->rdev[i]) + regulator_unregister(lp3971->rdev[i]); + kfree(lp3971->rdev); + i2c_set_clientdata(i2c, NULL); + kfree(lp3971); + + return 0; +} + +static const struct i2c_device_id lp3971_i2c_id[] = { + { "lp3971", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); + +static struct i2c_driver lp3971_i2c_driver = { + .driver = { + .name = "LP3971", + .owner = THIS_MODULE, + }, + .probe = lp3971_i2c_probe, + .remove = lp3971_i2c_remove, + .id_table = lp3971_i2c_id, +}; + +static int __init lp3971_module_init(void) +{ + int ret = -ENODEV; + + ret = i2c_add_driver(&lp3971_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + + return ret; +} +module_init(lp3971_module_init); + +static void __exit lp3971_module_exit(void) +{ + i2c_del_driver(&lp3971_i2c_driver); +} +module_exit(lp3971_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marek Szyprowski "); +MODULE_DESCRIPTION("LP3971 PMIC driver"); diff --git a/include/linux/regulator/lp3971.h b/include/linux/regulator/lp3971.h new file mode 100644 index 0000000..6140164 --- /dev/null +++ b/include/linux/regulator/lp3971.h @@ -0,0 +1,51 @@ +/* + * National Semiconductors LP3971 PMIC chip client interface + * + * Copyright (C) 2009 Samsung Electronics + * Author: Marek Szyprowski + * + * Based on wm8400.h + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __LINUX_REGULATOR_LP3971_H +#define __LINUX_REGULATOR_LP3971_H + +#include + +#define LP3971_LDO1 0 +#define LP3971_LDO2 1 +#define LP3971_LDO3 2 +#define LP3971_LDO4 3 +#define LP3971_LDO5 4 + +#define LP3971_DCDC1 5 +#define LP3971_DCDC2 6 +#define LP3971_DCDC3 7 + +#define LP3971_NUM_REGULATORS 8 + +struct lp3971_regulator_subdev { + int id; + struct regulator_init_data *initdata; +}; + +struct lp3971_platform_data { + int num_regulators; + struct lp3971_regulator_subdev *regulators; +}; + +#endif -- cgit v0.10.2 From 6113c3a5a63b8f0d5613b2a71cd1f5335a37b89a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 19 May 2009 11:44:37 +0100 Subject: regulator: lp3971 - fix driver link error when built-in. lp3971_i2c_remove' referenced in section `.data' of drivers/built-in.o: defined in discarded section `.devexit.text' of drivers/built-in.o Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 35abebe..a61018a 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -535,7 +535,7 @@ static struct i2c_driver lp3971_i2c_driver = { .owner = THIS_MODULE, }, .probe = lp3971_i2c_probe, - .remove = lp3971_i2c_remove, + .remove = __devexit_p(lp3971_i2c_remove), .id_table = lp3971_i2c_id, }; -- cgit v0.10.2 From b110a8fb242bc34e4b7686252899ce0fca956e2c Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 28 May 2009 07:15:16 +0200 Subject: regulator/max1586: support increased V3 voltage range The V3 regulator can be configured with an external resistor connected to the feedback pin (R24 in the data sheet) to increase the voltage range. For example, hx4700 has R24 = 3.32 kOhm to achieve a maximum V3 voltage of 1.55 V which is needed for 624 MHz CPU frequency. Signed-off-by: Philipp Zabel Acked-by: Mark Brown Acked-by: Robert Jarzmik Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index bbbb55f..92799f4 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -29,7 +29,6 @@ #define MAX1586_V3_MIN_UV 700000 #define MAX1586_V3_MAX_UV 1475000 -#define MAX1586_V3_STEP_UV 25000 #define MAX1586_V6_MIN_UV 0 #define MAX1586_V6_MAX_UV 3000000 @@ -37,33 +36,52 @@ #define I2C_V3_SELECT (0 << 5) #define I2C_V6_SELECT (1 << 5) +struct max1586_data { + struct i2c_client *client; + + /* min/max V3 voltage */ + int min_uV; + int max_uV; + + struct regulator_dev *rdev[0]; +}; + /* * V3 voltage * On I2C bus, sending a "x" byte to the max1586 means : * set V3 to 0.700V + (x & 0x1f) * 0.025V + * This voltage can be increased by external resistors + * R24 and R25=100kOhm as described in the data sheet. + * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm */ -static int max1586_v3_calc_voltage(unsigned selector) +static int max1586_v3_calc_voltage(struct max1586_data *max1586, + unsigned selector) { - return MAX1586_V3_MIN_UV + (MAX1586_V3_STEP_UV * selector); + unsigned range_uV = max1586->max_uV - max1586->min_uV; + + return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL); } static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) { - struct i2c_client *client = rdev_get_drvdata(rdev); + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + struct i2c_client *client = max1586->client; + unsigned range_uV = max1586->max_uV - max1586->min_uV; unsigned selector; u8 v3_prog; - if (min_uV < MAX1586_V3_MIN_UV || min_uV > MAX1586_V3_MAX_UV) - return -EINVAL; - if (max_uV < MAX1586_V3_MIN_UV || max_uV > MAX1586_V3_MAX_UV) + if (min_uV > max1586->max_uV || max_uV < max1586->min_uV) return -EINVAL; + if (min_uV < max1586->min_uV) + min_uV = max1586->min_uV; - selector = (min_uV - MAX1586_V3_MIN_UV) / MAX1586_V3_STEP_UV; - if (max1586_v3_calc_voltage(selector) > max_uV) + selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + + range_uV - 1) / range_uV; + if (max1586_v3_calc_voltage(max1586, selector) > max_uV) return -EINVAL; dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", - max1586_v3_calc_voltage(selector) / 1000); + max1586_v3_calc_voltage(max1586, selector) / 1000); v3_prog = I2C_V3_SELECT | (u8) selector; return i2c_smbus_write_byte(client, v3_prog); @@ -71,9 +89,11 @@ static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector) { + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + if (selector > MAX1586_V3_MAX_VSEL) return -EINVAL; - return max1586_v3_calc_voltage(selector); + return max1586_v3_calc_voltage(max1586, selector); } /* @@ -164,14 +184,25 @@ static int max1586_pmic_probe(struct i2c_client *client, { struct regulator_dev **rdev; struct max1586_platform_data *pdata = client->dev.platform_data; - int i, id, ret = 0; + struct max1586_data *max1586; + int i, id, ret = -ENOMEM; + + max1586 = kzalloc(sizeof(struct max1586_data) + + sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), + GFP_KERNEL); + if (!max1586) + goto out; - rdev = kzalloc(sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), - GFP_KERNEL); - if (!rdev) - return -ENOMEM; + max1586->client = client; - ret = -EINVAL; + if (!pdata->v3_gain) { + ret = -EINVAL; + goto out_unmap; + } + max1586->min_uV = MAX1586_V3_MIN_UV * pdata->v3_gain / 1000000; + max1586->max_uV = MAX1586_V3_MAX_UV * pdata->v3_gain / 1000000; + + rdev = max1586->rdev; for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { id = pdata->subdevs[i].id; if (!pdata->subdevs[i].platform_data) @@ -182,7 +213,7 @@ static int max1586_pmic_probe(struct i2c_client *client, } rdev[i] = regulator_register(&max1586_reg[id], &client->dev, pdata->subdevs[i].platform_data, - client); + max1586); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(&client->dev, "failed to register %s\n", @@ -198,7 +229,9 @@ static int max1586_pmic_probe(struct i2c_client *client, err: while (--i >= 0) regulator_unregister(rdev[i]); - kfree(rdev); +out_unmap: + kfree(max1586); +out: return ret; } diff --git a/include/linux/regulator/max1586.h b/include/linux/regulator/max1586.h index 2056973..4456319 100644 --- a/include/linux/regulator/max1586.h +++ b/include/linux/regulator/max1586.h @@ -26,6 +26,12 @@ #define MAX1586_V3 0 #define MAX1586_V6 1 +/* precalculated values for v3_gain */ +#define MAX1586_GAIN_NO_R24 1000000 /* 700000 .. 1475000 mV */ +#define MAX1586_GAIN_R24_3k32 1051098 /* 735768 .. 1550369 mV */ +#define MAX1586_GAIN_R24_5k11 1078648 /* 755053 .. 1591005 mV */ +#define MAX1586_GAIN_R24_7k5 1115432 /* 780802 .. 1645262 mV */ + /** * max1586_subdev_data - regulator data * @id: regulator Id (either MAX1586_V3 or MAX1586_V6) @@ -43,10 +49,15 @@ struct max1586_subdev_data { * @num_subdevs: number of regultors used (may be 1 or 2) * @subdevs: regulator used * At most, there will be a regulator for V3 and one for V6 voltages. + * @v3_gain: gain on the V3 voltage output multiplied by 1e6. + * This can be calculated as ((1 + R24/R25 + R24/185.5kOhm) * 1e6) + * for an external resistor configuration as described in the + * data sheet (R25=100kOhm). */ struct max1586_platform_data { int num_subdevs; struct max1586_subdev_data *subdevs; + int v3_gain; }; #endif -- cgit v0.10.2 From c8f1e5025ca2fa8e6e037451f3d271e66745a19b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 28 May 2009 21:00:03 +0200 Subject: regulator/max1586: fix V3 gain calculation integer overflow On Thu, May 28, 2009 at 10:59 AM, Mark Brown wrote: > On Thu, May 28, 2009 at 07:15:16AM +0200, Philipp Zabel wrote: >> The V3 regulator can be configured with an external resistor >> connected to the feedback pin (R24 in the data sheet) to >> increase the voltage range. >> >> For example, hx4700 has R24 = 3.32 kOhm to achieve a maximum >> V3 voltage of 1.55 V which is needed for 624 MHz CPU frequency. >> >> Signed-off-by: Philipp Zabel > > Looks good. > > Acked-by: Mark Brown Thanks, but it turns out I hit a 32 bit integer overflow in the gain calculation. I'd like to mend that with the following patch. Now max_uV could be increased up to 4.294 V, enough to charge LiPo cells. Signed-off-by: Philipp Zabel Acked-by: Robert Jarzmik Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 92799f4..2c082d3 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -40,8 +40,8 @@ struct max1586_data { struct i2c_client *client; /* min/max V3 voltage */ - int min_uV; - int max_uV; + unsigned int min_uV; + unsigned int max_uV; struct regulator_dev *rdev[0]; }; @@ -199,8 +199,8 @@ static int max1586_pmic_probe(struct i2c_client *client, ret = -EINVAL; goto out_unmap; } - max1586->min_uV = MAX1586_V3_MIN_UV * pdata->v3_gain / 1000000; - max1586->max_uV = MAX1586_V3_MAX_UV * pdata->v3_gain / 1000000; + max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; + max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; rdev = max1586->rdev; for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { -- cgit v0.10.2 From f708eb1d71dc8ffb184da9f0bc53461c6dc10653 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jun 2009 12:31:38 +0200 Subject: ALSA: intel8x0 - Fix PCM position craziness The PCM pointer callback sometimes returns invalid positions and this screws up the hw_ptr updater in PCM core. Especially since now the jiffies check is optional with xrun_debug, the invalid position is handled as is, and causes serious sound skips, etc. This patch simplifies the position-fix strategy in intel8x0 to be more robust: - just falls back to the last position if bogus position is detected - another sanity check for the backward move of the position due to a race of register update and the base-index update This patch is applicable also for 2.6.30. Tested-by: David Miller Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 173bebf..8aa5687 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -356,8 +356,6 @@ struct ichdev { unsigned int position; unsigned int pos_shift; unsigned int last_pos; - unsigned long last_pos_jiffies; - unsigned int jiffy_to_bytes; int frags; int lvi; int lvi_frag; @@ -844,7 +842,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; ichdev->last_pos = ichdev->position; - ichdev->last_pos_jiffies = jiffies; break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; @@ -1048,7 +1045,6 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; } snd_intel8x0_setup_periods(chip, ichdev); - ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ; return 0; } @@ -1073,19 +1069,23 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; } while (timeout--); + ptr = ichdev->last_pos; if (ptr1 != 0) { ptr1 <<= ichdev->pos_shift; ptr = ichdev->fragsize1 - ptr1; ptr += position; - ichdev->last_pos = ptr; - ichdev->last_pos_jiffies = jiffies; - } else { - ptr1 = jiffies - ichdev->last_pos_jiffies; - if (ptr1) - ptr1 -= 1; - ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes; - ptr %= ichdev->size; + if (ptr < ichdev->last_pos) { + unsigned int pos_base, last_base; + pos_base = position / ichdev->fragsize1; + last_base = ichdev->last_pos / ichdev->fragsize1; + /* another sanity check; ptr1 can go back to full + * before the base position is updated + */ + if (pos_base == last_base) + ptr = ichdev->last_pos; + } } + ichdev->last_pos = ptr; spin_unlock(&chip->reg_lock); if (ptr >= ichdev->size) return 0; -- cgit v0.10.2 From 8dca419721d188bfee5f19fad45275856c619a5c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jun 2009 14:50:52 +0200 Subject: ALSA: ctxfi - Fix deadlock with xfi-timer The PCM x-fi native update routine can cause deadlocks when the trigger(START) is called while the stream is running. This patch fixes the deadlock by just postponing the pcm period update to the next possible wake-up. Also it adds the flip of ti->running flag (just to be sure as now). Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index 779c6c3..93b0aed 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -180,7 +180,7 @@ static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer) * * call this inside the lock and irq disabled */ -static int ct_xfitimer_reprogram(struct ct_timer *atimer) +static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update) { struct ct_timer_instance *ti; unsigned int min_intr = (unsigned int)-1; @@ -216,6 +216,8 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer) ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + rate - 1, rate); } + if (ti->need_update && !can_update) + min_intr = 0; /* pending to the next irq */ if (ti->frag_count < min_intr) min_intr = ti->frag_count; } @@ -235,7 +237,7 @@ static void ct_xfitimer_check_period(struct ct_timer *atimer) spin_lock_irqsave(&atimer->list_lock, flags); list_for_each_entry(ti, &atimer->instance_head, instance_list) { - if (ti->need_update) { + if (ti->running && ti->need_update) { ti->need_update = 0; ti->apcm->interrupt(ti->apcm); } @@ -252,7 +254,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer) spin_lock_irqsave(&atimer->lock, flags); atimer->irq_handling = 1; do { - update = ct_xfitimer_reprogram(atimer); + update = ct_xfitimer_reprogram(atimer, 1); spin_unlock(&atimer->lock); if (update) ct_xfitimer_check_period(atimer); @@ -265,6 +267,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer) static void ct_xfitimer_prepare(struct ct_timer_instance *ti) { ti->frag_count = ti->substream->runtime->period_size; + ti->running = 0; ti->need_update = 0; } @@ -273,7 +276,6 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti) static void ct_xfitimer_update(struct ct_timer *atimer) { unsigned long flags; - int update; spin_lock_irqsave(&atimer->lock, flags); if (atimer->irq_handling) { @@ -284,10 +286,8 @@ static void ct_xfitimer_update(struct ct_timer *atimer) } ct_xfitimer_irq_stop(atimer); - update = ct_xfitimer_reprogram(atimer); + ct_xfitimer_reprogram(atimer, 0); spin_unlock_irqrestore(&atimer->lock, flags); - if (update) - ct_xfitimer_check_period(atimer); } static void ct_xfitimer_start(struct ct_timer_instance *ti) @@ -298,6 +298,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti) spin_lock_irqsave(&atimer->lock, flags); if (list_empty(&ti->running_list)) atimer->wc = ct_xfitimer_get_wc(atimer); + ti->running = 1; + ti->need_update = 0; list_add(&ti->running_list, &atimer->running_head); spin_unlock_irqrestore(&atimer->lock, flags); ct_xfitimer_update(atimer); @@ -310,7 +312,7 @@ static void ct_xfitimer_stop(struct ct_timer_instance *ti) spin_lock_irqsave(&atimer->lock, flags); list_del_init(&ti->running_list); - ti->need_update = 0; + ti->running = 0; spin_unlock_irqrestore(&atimer->lock, flags); ct_xfitimer_update(atimer); } -- cgit v0.10.2 From 1cf92b453a405f6e452737962933a19ec1582029 Mon Sep 17 00:00:00 2001 From: Jack Stone Date: Mon, 15 Jun 2009 18:01:46 +0200 Subject: i2c: Remove void casts Remove uneeded void casts. Signed-off-by: Jack Stone Signed-off-by: Jean Delvare diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 85e2e919..dfd7bc8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1509,7 +1509,7 @@ struct i2c_adapter* i2c_get_adapter(int id) struct i2c_adapter *adapter; mutex_lock(&core_lock); - adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + adapter = idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; -- cgit v0.10.2 From 66b650f04576a6737579ec404446450026ff2e0b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 15 Jun 2009 18:01:46 +0200 Subject: i2c: Retry automatically on arbitration loss Some small changes in i2c core to retry i2c xfers until either the maximum number of retries or the timeout is hit. Signed-off-by: Clifford Wolf Signed-off-by: Jean Delvare diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dfd7bc8..635c488 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1022,7 +1022,8 @@ module_exit(i2c_exit); */ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - int ret; + unsigned long orig_jiffies; + int ret, try; /* REVISIT the fault reporting model here is weak: * @@ -1060,7 +1061,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) mutex_lock_nested(&adap->bus_lock, adap->level); } - ret = adap->algo->master_xfer(adap,msgs,num); + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (ret = 0, try = 0; try <= adap->retries; try++) { + ret = adap->algo->master_xfer(adap, msgs, num); + if (ret != -EAGAIN) + break; + if (time_after(jiffies, orig_jiffies + adap->timeout)) + break; + } mutex_unlock(&adap->bus_lock); return ret; @@ -1995,14 +2004,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data) { + unsigned long orig_jiffies; + int try; s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { mutex_lock(&adapter->bus_lock); - res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, - command, protocol, data); + + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adapter->retries; try++) { + res = adapter->algo->smbus_xfer(adapter, addr, flags, + read_write, command, + protocol, data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adapter->timeout)) + break; + } mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, -- cgit v0.10.2 From fa1b2ca4fa271f9300a764b9d505a027156f749b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:48 +0200 Subject: i2c: Do not probe for TV chips on Voodoo3 adapters There's no point in giving the I2C bus of Voodoo3 adapters a class value, there's no video chip driver checking for it anymore. If support is ever needed, the video device should be instantiated explicitly rather than probed. To the best of my knowledge the only video chip that can be found on these boards is a BT869 video encoder, for which no support exists currently. Signed-off-by: Jean Delvare Acked-by: Krzysztof Helt diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 1a474ac..7663d57 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { static struct i2c_adapter voodoo3_i2c_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, .name = "I2C Voodoo3/Banshee adapter", .algo_data = &voo_i2c_bit_data, }; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 89f231d..ff43c88 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1315,7 +1315,6 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); chan->adapter.owner = THIS_MODULE; - chan->adapter.class = I2C_CLASS_TV_ANALOG; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = dev; chan->algo.setsda = tdfxfb_i2c_setsda; -- cgit v0.10.2 From c52cf01f5b35d77b2a918c319e22567de5c3c15f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:48 +0200 Subject: i2c: Do not give adapters a default parent We don't need to give adapters a parent if they don't have one. The driver core will put them in the virtual device directory and all will be fine. Signed-off-by: Jean Delvare diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 635c488..5ed622e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -451,16 +450,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) mutex_lock(&core_lock); - /* Add the adapter to the driver core. - * If the parent pointer is not set up, - * we add this adapter to the host bus. - */ - if (adap->dev.parent == NULL) { - adap->dev.parent = &platform_bus; - pr_debug("I2C adapter driver [%s] forgot to specify " - "physical device\n", adap->name); - } - /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; -- cgit v0.10.2 From 4b364f230a5ef984818837ec7c2be0884eac191c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 15 Jun 2009 18:01:49 +0200 Subject: i2c/chips: Move max6875 to drivers/misc/eeprom This driver only reads the user EEPROM of that chip, so we can move it to the eeprom-directory in order to further clean up (and later remove) drivers/i2c/chips. The Kconfig text was updated to match the current functionality, dropping the meanwhile obsoleted parts. Defconfigs have been adapted. Signed-off-by: Wolfram Sang Acked-by: Ben Gardner Signed-off-by: Jean Delvare diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 783da85..d6d35b2 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -963,7 +963,7 @@ CONFIG_EEPROM_LEGACY=y CONFIG_SENSORS_PCF8574=y # CONFIG_PCF8575 is not set CONFIG_SENSORS_PCF8591=y -CONFIG_SENSORS_MAX6875=y +CONFIG_EEPROM_MAX6875=y # CONFIG_SENSORS_TSL2550 is not set CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 8426d3b..fadb351 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -1849,7 +1849,7 @@ CONFIG_EEPROM_LEGACY=m CONFIG_SENSORS_PCF8574=m CONFIG_SENSORS_PCA9539=m CONFIG_SENSORS_PCF8591=m -CONFIG_SENSORS_MAX6875=m +CONFIG_EEPROM_MAX6875=m # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 7d044df..12dc7c4 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -1808,7 +1808,7 @@ CONFIG_PCF8575=m CONFIG_SENSORS_PCA9539=m CONFIG_SENSORS_PCF8591=m # CONFIG_TPS65010 is not set -CONFIG_SENSORS_MAX6875=m +CONFIG_EEPROM_MAX6875=m CONFIG_SENSORS_TSL2550=m CONFIG_MCU_MPC8349EMITX=m # CONFIG_I2C_DEBUG_CORE is not set diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 8f8c81e..02d746c 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -64,21 +64,6 @@ config SENSORS_PCA9539 This driver is deprecated and will be dropped soon. Use drivers/gpio/pca953x.c instead. -config SENSORS_MAX6875 - tristate "Maxim MAX6875 Power supply supervisor" - depends on EXPERIMENTAL - help - If you say yes here you get support for the Maxim MAX6875 - EEPROM-programmable, quad power-supply sequencer/supervisor. - - This provides an interface to program the EEPROM and reset the chip. - - This driver also supports the Maxim MAX6874 hex power-supply - sequencer/supervisor if found at a compatible address. - - This driver can also be built as a module. If so, the module - will be called max6875. - config SENSORS_TSL2550 tristate "Taos TSL2550 ambient light sensor" depends on EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 55a3760..f4680d1 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -11,7 +11,6 @@ # obj-$(CONFIG_DS1682) += ds1682.o -obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_PCF8575) += pcf8575.o diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c deleted file mode 100644 index 033d9d8..0000000 --- a/drivers/i2c/chips/max6875.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - max6875.c - driver for MAX6874/MAX6875 - - Copyright (C) 2005 Ben Gardner - - Based on i2c/chips/eeprom.c - - The MAX6875 has a bank of registers and two banks of EEPROM. - Address ranges are defined as follows: - * 0x0000 - 0x0046 = configuration registers - * 0x8000 - 0x8046 = configuration EEPROM - * 0x8100 - 0x82FF = user EEPROM - - This driver makes the user EEPROM available for read. - - The registers & config EEPROM should be accessed via i2c-dev. - - The MAX6875 ignores the lowest address bit, so each chip responds to - two addresses - 0x50/0x51 and 0x52/0x53. - - Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read - address, so this driver is destructive if loaded for the wrong EEPROM chip. - - 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; version 2 of the License. -*/ - -#include -#include -#include -#include -#include -#include - -/* Do not scan - the MAX6875 access method will write to some EEPROM chips */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Insmod parameters */ -I2C_CLIENT_INSMOD_1(max6875); - -/* The MAX6875 can only read/write 16 bytes at a time */ -#define SLICE_SIZE 16 -#define SLICE_BITS 4 - -/* USER EEPROM is at addresses 0x8100 - 0x82FF */ -#define USER_EEPROM_BASE 0x8100 -#define USER_EEPROM_SIZE 0x0200 -#define USER_EEPROM_SLICES 32 - -/* MAX6875 commands */ -#define MAX6875_CMD_BLK_READ 0x84 - -/* Each client has this additional data */ -struct max6875_data { - struct i2c_client *fake_client; - struct mutex update_lock; - - u32 valid; - u8 data[USER_EEPROM_SIZE]; - unsigned long last_updated[USER_EEPROM_SLICES]; -}; - -static void max6875_update_slice(struct i2c_client *client, int slice) -{ - struct max6875_data *data = i2c_get_clientdata(client); - int i, j, addr; - u8 *buf; - - if (slice >= USER_EEPROM_SLICES) - return; - - mutex_lock(&data->update_lock); - - buf = &data->data[slice << SLICE_BITS]; - - if (!(data->valid & (1 << slice)) || - time_after(jiffies, data->last_updated[slice])) { - - dev_dbg(&client->dev, "Starting update of slice %u\n", slice); - - data->valid &= ~(1 << slice); - - addr = USER_EEPROM_BASE + (slice << SLICE_BITS); - - /* select the eeprom address */ - if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { - dev_err(&client->dev, "address set failed\n"); - goto exit_up; - } - - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - if (i2c_smbus_read_i2c_block_data(client, - MAX6875_CMD_BLK_READ, - SLICE_SIZE, - buf) != SLICE_SIZE) { - goto exit_up; - } - } else { - for (i = 0; i < SLICE_SIZE; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) { - goto exit_up; - } - buf[i] = j; - } - } - data->last_updated[slice] = jiffies; - data->valid |= (1 << slice); - } -exit_up: - mutex_unlock(&data->update_lock); -} - -static ssize_t max6875_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = kobj_to_i2c_client(kobj); - struct max6875_data *data = i2c_get_clientdata(client); - int slice, max_slice; - - if (off > USER_EEPROM_SIZE) - return 0; - - if (off + count > USER_EEPROM_SIZE) - count = USER_EEPROM_SIZE - off; - - /* refresh slices which contain requested bytes */ - max_slice = (off + count - 1) >> SLICE_BITS; - for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) - max6875_update_slice(client, slice); - - memcpy(buf, &data->data[off], count); - - return count; -} - -static struct bin_attribute user_eeprom_attr = { - .attr = { - .name = "eeprom", - .mode = S_IRUGO, - }, - .size = USER_EEPROM_SIZE, - .read = max6875_read, -}; - -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int max6875_detect(struct i2c_client *client, int kind, - struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA - | I2C_FUNC_SMBUS_READ_BYTE)) - return -ENODEV; - - /* Only check even addresses */ - if (client->addr & 1) - return -ENODEV; - - strlcpy(info->type, "max6875", I2C_NAME_SIZE); - - return 0; -} - -static int max6875_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct max6875_data *data; - int err; - - if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) - return -ENOMEM; - - /* A fake client is created on the odd address */ - data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); - if (!data->fake_client) { - err = -ENOMEM; - goto exit_kfree; - } - - /* Init real i2c_client */ - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - - err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr); - if (err) - goto exit_remove_fake; - - return 0; - -exit_remove_fake: - i2c_unregister_device(data->fake_client); -exit_kfree: - kfree(data); - return err; -} - -static int max6875_remove(struct i2c_client *client) -{ - struct max6875_data *data = i2c_get_clientdata(client); - - i2c_unregister_device(data->fake_client); - - sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); - kfree(data); - - return 0; -} - -static const struct i2c_device_id max6875_id[] = { - { "max6875", 0 }, - { } -}; - -static struct i2c_driver max6875_driver = { - .driver = { - .name = "max6875", - }, - .probe = max6875_probe, - .remove = max6875_remove, - .id_table = max6875_id, - - .detect = max6875_detect, - .address_data = &addr_data, -}; - -static int __init max6875_init(void) -{ - return i2c_add_driver(&max6875_driver); -} - -static void __exit max6875_exit(void) -{ - i2c_del_driver(&max6875_driver); -} - - -MODULE_AUTHOR("Ben Gardner "); -MODULE_DESCRIPTION("MAX6875 driver"); -MODULE_LICENSE("GPL"); - -module_init(max6875_init); -module_exit(max6875_exit); diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 89fec05..9118613 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -48,6 +48,20 @@ config EEPROM_LEGACY This driver can also be built as a module. If so, the module will be called eeprom. +config EEPROM_MAX6875 + tristate "Maxim MAX6874/5 power supply supervisor" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get read-only support for the user EEPROM of + the Maxim MAX6874/5 EEPROM-programmable, quad power-supply + sequencer/supervisor. + + All other features of this chip should be accessed via i2c-dev. + + This driver can also be built as a module. If so, the module + will be called max6875. + + config EEPROM_93CX6 tristate "EEPROM 93CX6 support" help diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 539dd8f..df3d68f 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_EEPROM_AT24) += at24.o obj-$(CONFIG_EEPROM_AT25) += at25.o obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o +obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c new file mode 100644 index 0000000..3c0c58e --- /dev/null +++ b/drivers/misc/eeprom/max6875.c @@ -0,0 +1,246 @@ +/* + max6875.c - driver for MAX6874/MAX6875 + + Copyright (C) 2005 Ben Gardner + + Based on eeprom.c + + The MAX6875 has a bank of registers and two banks of EEPROM. + Address ranges are defined as follows: + * 0x0000 - 0x0046 = configuration registers + * 0x8000 - 0x8046 = configuration EEPROM + * 0x8100 - 0x82FF = user EEPROM + + This driver makes the user EEPROM available for read. + + The registers & config EEPROM should be accessed via i2c-dev. + + The MAX6875 ignores the lowest address bit, so each chip responds to + two addresses - 0x50/0x51 and 0x52/0x53. + + Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read + address, so this driver is destructive if loaded for the wrong EEPROM chip. + + 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; version 2 of the License. +*/ + +#include +#include +#include +#include +#include +#include + +/* Do not scan - the MAX6875 access method will write to some EEPROM chips */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(max6875); + +/* The MAX6875 can only read/write 16 bytes at a time */ +#define SLICE_SIZE 16 +#define SLICE_BITS 4 + +/* USER EEPROM is at addresses 0x8100 - 0x82FF */ +#define USER_EEPROM_BASE 0x8100 +#define USER_EEPROM_SIZE 0x0200 +#define USER_EEPROM_SLICES 32 + +/* MAX6875 commands */ +#define MAX6875_CMD_BLK_READ 0x84 + +/* Each client has this additional data */ +struct max6875_data { + struct i2c_client *fake_client; + struct mutex update_lock; + + u32 valid; + u8 data[USER_EEPROM_SIZE]; + unsigned long last_updated[USER_EEPROM_SLICES]; +}; + +static void max6875_update_slice(struct i2c_client *client, int slice) +{ + struct max6875_data *data = i2c_get_clientdata(client); + int i, j, addr; + u8 *buf; + + if (slice >= USER_EEPROM_SLICES) + return; + + mutex_lock(&data->update_lock); + + buf = &data->data[slice << SLICE_BITS]; + + if (!(data->valid & (1 << slice)) || + time_after(jiffies, data->last_updated[slice])) { + + dev_dbg(&client->dev, "Starting update of slice %u\n", slice); + + data->valid &= ~(1 << slice); + + addr = USER_EEPROM_BASE + (slice << SLICE_BITS); + + /* select the eeprom address */ + if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { + dev_err(&client->dev, "address set failed\n"); + goto exit_up; + } + + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (i2c_smbus_read_i2c_block_data(client, + MAX6875_CMD_BLK_READ, + SLICE_SIZE, + buf) != SLICE_SIZE) { + goto exit_up; + } + } else { + for (i = 0; i < SLICE_SIZE; i++) { + j = i2c_smbus_read_byte(client); + if (j < 0) { + goto exit_up; + } + buf[i] = j; + } + } + data->last_updated[slice] = jiffies; + data->valid |= (1 << slice); + } +exit_up: + mutex_unlock(&data->update_lock); +} + +static ssize_t max6875_read(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = kobj_to_i2c_client(kobj); + struct max6875_data *data = i2c_get_clientdata(client); + int slice, max_slice; + + if (off > USER_EEPROM_SIZE) + return 0; + + if (off + count > USER_EEPROM_SIZE) + count = USER_EEPROM_SIZE - off; + + /* refresh slices which contain requested bytes */ + max_slice = (off + count - 1) >> SLICE_BITS; + for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) + max6875_update_slice(client, slice); + + memcpy(buf, &data->data[off], count); + + return count; +} + +static struct bin_attribute user_eeprom_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO, + }, + .size = USER_EEPROM_SIZE, + .read = max6875_read, +}; + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int max6875_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA + | I2C_FUNC_SMBUS_READ_BYTE)) + return -ENODEV; + + /* Only check even addresses */ + if (client->addr & 1) + return -ENODEV; + + strlcpy(info->type, "max6875", I2C_NAME_SIZE); + + return 0; +} + +static int max6875_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max6875_data *data; + int err; + + if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) + return -ENOMEM; + + /* A fake client is created on the odd address */ + data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); + if (!data->fake_client) { + err = -ENOMEM; + goto exit_kfree; + } + + /* Init real i2c_client */ + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr); + if (err) + goto exit_remove_fake; + + return 0; + +exit_remove_fake: + i2c_unregister_device(data->fake_client); +exit_kfree: + kfree(data); + return err; +} + +static int max6875_remove(struct i2c_client *client) +{ + struct max6875_data *data = i2c_get_clientdata(client); + + i2c_unregister_device(data->fake_client); + + sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); + kfree(data); + + return 0; +} + +static const struct i2c_device_id max6875_id[] = { + { "max6875", 0 }, + { } +}; + +static struct i2c_driver max6875_driver = { + .driver = { + .name = "max6875", + }, + .probe = max6875_probe, + .remove = max6875_remove, + .id_table = max6875_id, + + .detect = max6875_detect, + .address_data = &addr_data, +}; + +static int __init max6875_init(void) +{ + return i2c_add_driver(&max6875_driver); +} + +static void __exit max6875_exit(void) +{ + i2c_del_driver(&max6875_driver); +} + + +MODULE_AUTHOR("Ben Gardner "); +MODULE_DESCRIPTION("MAX6875 driver"); +MODULE_LICENSE("GPL"); + +module_init(max6875_init); +module_exit(max6875_exit); -- cgit v0.10.2 From a231591f0427cfb91ae247be974a7fa0e6b37389 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 15 Jun 2009 18:01:49 +0200 Subject: i2c-viapro: Add new PCI device ID for VX855 The south bridge of the VIA VX855 chipset has a different PCI Device ID so i2c-viapro.c needs to be updated with this. Signed-off-by: Harald Welte Signed-off-by: Jean Delvare diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 22efedf..2e758b0 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -19,6 +19,9 @@ Supported adapters: * VIA Technologies, Inc. VX800/VX820 Datasheet: available on http://linux.via.com.tw + * VIA Technologies, Inc. VX855/VX875 + Datasheet: Availability unknown + Authors: Kyösti Mälkki , Mark D. Studebaker , @@ -53,6 +56,7 @@ Your lspci -n listing must show one of these : device 1106:3287 (VT8251) device 1106:8324 (CX700) device 1106:8353 (VX800/VX820) + device 1106:8409 (VX855/VX875) If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c8460fa..0d04d3e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -211,7 +211,7 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820" + tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx" depends on PCI help If you say yes to this option, support will be included for the VIA @@ -225,8 +225,8 @@ config I2C_VIAPRO VT8237R/A/S VT8251 CX700 - VX800 - VX820 + VX800/VX820 + VX855/VX875 This driver can also be built as a module. If so, the module will be called i2c-viapro. diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 02e6f72..54d810a 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -37,6 +37,7 @@ VT8251 0x3287 yes CX700 0x8324 yes VX800/VX820 0x8353 yes + VX855/VX875 0x8409 yes Note: we assume there can only be one device, with one SMBus interface. */ @@ -404,6 +405,7 @@ found: switch (pdev->device) { case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_VX800: + case PCI_DEVICE_ID_VIA_VX855: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855), + .driver_data = SMBBA3 }, { 0, } }; -- cgit v0.10.2 From 1b9f37d488f09342610b29ac1c8e734e540932ab Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:50 +0200 Subject: therm_pm72: Convert to a new-style i2c driver The legacy i2c binding model is going away soon, so convert the macintosh therm_pm72 driver to the new model or it will break. This is really a quick and dirty conversion, that should do the trick for now, but no doubt that something cleaner can be done if anyone is interested. Signed-off-by: Jean Delvare Cc: Benjamin Herrenschmidt Tested-by: Paul Mackerras diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 817607e..a028598 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -287,22 +287,6 @@ struct fcu_fan_table fcu_fans[] = { }; /* - * i2c_driver structure to attach to the host i2c controller - */ - -static int therm_pm72_attach(struct i2c_adapter *adapter); -static int therm_pm72_detach(struct i2c_adapter *adapter); - -static struct i2c_driver therm_pm72_driver = -{ - .driver = { - .name = "therm_pm72", - }, - .attach_adapter = therm_pm72_attach, - .detach_adapter = therm_pm72_detach, -}; - -/* * Utility function to create an i2c_client structure and * attach it to one of u3 adapters */ @@ -310,6 +294,7 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) { struct i2c_client *clt; struct i2c_adapter *adap; + struct i2c_board_info info; if (id & 0x200) adap = k2; @@ -320,31 +305,21 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) if (adap == NULL) return NULL; - clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (clt == NULL) - return NULL; - - clt->addr = (id >> 1) & 0x7f; - clt->adapter = adap; - clt->driver = &therm_pm72_driver; - strncpy(clt->name, name, I2C_NAME_SIZE-1); - - if (i2c_attach_client(clt)) { + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (id >> 1) & 0x7f; + strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE); + clt = i2c_new_device(adap, &info); + if (!clt) { printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id); - kfree(clt); return NULL; } - return clt; -} -/* - * Utility function to get rid of the i2c_client structure - * (will also detach from the adapter hopepfully) - */ -static void detach_i2c_chip(struct i2c_client *clt) -{ - i2c_detach_client(clt); - kfree(clt); + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&clt->detected, &clt->driver->clients); + return clt; } /* @@ -1203,8 +1178,6 @@ static int init_cpu_state(struct cpu_pid_state *state, int index) return 0; fail: - if (state->monitor) - detach_i2c_chip(state->monitor); state->monitor = NULL; return -ENODEV; @@ -1232,7 +1205,6 @@ static void dispose_cpu_state(struct cpu_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm); } - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1407,7 +1379,6 @@ static void dispose_backside_state(struct backside_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_backside_temperature); device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1532,7 +1503,6 @@ static void dispose_drives_state(struct drives_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_drives_temperature); device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1654,7 +1624,6 @@ static void dispose_dimms_state(struct dimm_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1779,7 +1748,6 @@ static void dispose_slots_state(struct slots_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_slots_temperature); device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -2008,8 +1976,6 @@ static int attach_fcu(void) */ static void detach_fcu(void) { - if (fcu) - detach_i2c_chip(fcu); fcu = NULL; } @@ -2060,12 +2026,21 @@ static int therm_pm72_attach(struct i2c_adapter *adapter) return 0; } +static int therm_pm72_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + /* Always succeed, the real work was done in therm_pm72_attach() */ + return 0; +} + /* - * Called on every adapter when the driver or the i2c controller + * Called when any of the devices which participates into thermal management * is going away. */ -static int therm_pm72_detach(struct i2c_adapter *adapter) +static int therm_pm72_remove(struct i2c_client *client) { + struct i2c_adapter *adapter = client->adapter; + mutex_lock(&driver_lock); if (state != state_detached) @@ -2096,6 +2071,30 @@ static int therm_pm72_detach(struct i2c_adapter *adapter) return 0; } +/* + * i2c_driver structure to attach to the host i2c controller + */ + +static const struct i2c_device_id therm_pm72_id[] = { + /* + * Fake device name, thermal management is done by several + * chips but we don't need to differentiate between them at + * this point. + */ + { "therm_pm72", 0 }, + { } +}; + +static struct i2c_driver therm_pm72_driver = { + .driver = { + .name = "therm_pm72", + }, + .attach_adapter = therm_pm72_attach, + .probe = therm_pm72_probe, + .remove = therm_pm72_remove, + .id_table = therm_pm72_id, +}; + static int fan_check_loc_match(const char *loc, int fan) { char tmp[64]; -- cgit v0.10.2 From 351ca3e31197929535418f5affc761cd9fb07428 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:51 +0200 Subject: windfarm: Convert to new-style i2c drivers The legacy i2c binding model is going away soon, so convert the macintosh windfarm drivers to the new model or they will break. Signed-off-by: Jean Delvare Tested-by: Johannes Berg Tested-by: Paul Mackerras Cc: Benjamin Herrenschmidt diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index b92b959..529886c 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -37,34 +37,22 @@ struct wf_lm75_sensor { int ds1775 : 1; int inited : 1; - struct i2c_client i2c; + struct i2c_client *i2c; struct wf_sensor sens; }; #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) -#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c) - -static int wf_lm75_attach(struct i2c_adapter *adapter); -static int wf_lm75_detach(struct i2c_client *client); - -static struct i2c_driver wf_lm75_driver = { - .driver = { - .name = "wf_lm75", - }, - .attach_adapter = wf_lm75_attach, - .detach_client = wf_lm75_detach, -}; static int wf_lm75_get(struct wf_sensor *sr, s32 *value) { struct wf_lm75_sensor *lm = wf_to_lm75(sr); s32 data; - if (lm->i2c.adapter == NULL) + if (lm->i2c == NULL) return -ENODEV; /* Init chip if necessary */ if (!lm->inited) { - u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1); + u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1); DBG("wf_lm75: Initializing %s, cfg was: %02x\n", sr->name, cfg); @@ -73,7 +61,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) * the firmware for now */ cfg_new = cfg & ~0x01; - i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new); + i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new); lm->inited = 1; /* If we just powered it up, let's wait 200 ms */ @@ -81,7 +69,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) } /* Read temperature register */ - data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0)); + data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0)); data <<= 8; *value = data; @@ -92,12 +80,6 @@ static void wf_lm75_release(struct wf_sensor *sr) { struct wf_lm75_sensor *lm = wf_to_lm75(sr); - /* check if client is registered and detach from i2c */ - if (lm->i2c.adapter) { - i2c_detach_client(&lm->i2c); - lm->i2c.adapter = NULL; - } - kfree(lm); } @@ -107,59 +89,77 @@ static struct wf_sensor_ops wf_lm75_ops = { .owner = THIS_MODULE, }; -static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, - u8 addr, int ds1775, - const char *loc) +static int wf_lm75_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wf_lm75_sensor *lm; int rc; - DBG("wf_lm75: creating %s device at address 0x%02x\n", - ds1775 ? "ds1775" : "lm75", addr); - lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); if (lm == NULL) - return NULL; + return -ENODEV; + + lm->inited = 0; + lm->ds1775 = id->driver_data; + lm->i2c = client; + lm->sens.name = client->dev.platform_data; + lm->sens.ops = &wf_lm75_ops; + i2c_set_clientdata(client, lm); + + rc = wf_register_sensor(&lm->sens); + if (rc) { + i2c_set_clientdata(client, NULL); + kfree(lm); + } + + return rc; +} + +static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter, + u8 addr, int ds1775, + const char *loc) +{ + struct i2c_board_info info; + struct i2c_client *client; + char *name; + + DBG("wf_lm75: creating %s device at address 0x%02x\n", + ds1775 ? "ds1775" : "lm75", addr); /* Usual rant about sensor names not beeing very consistent in * the device-tree, oh well ... * Add more entries below as you deal with more setups */ if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) - lm->sens.name = "hd-temp"; + name = "hd-temp"; else if (!strcmp(loc, "Incoming Air Temp")) - lm->sens.name = "incoming-air-temp"; + name = "incoming-air-temp"; else if (!strcmp(loc, "ODD Temp")) - lm->sens.name = "optical-drive-temp"; + name = "optical-drive-temp"; else if (!strcmp(loc, "HD Temp")) - lm->sens.name = "hard-drive-temp"; + name = "hard-drive-temp"; else goto fail; - lm->inited = 0; - lm->sens.ops = &wf_lm75_ops; - lm->ds1775 = ds1775; - lm->i2c.addr = (addr >> 1) & 0x7f; - lm->i2c.adapter = adapter; - lm->i2c.driver = &wf_lm75_driver; - strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1); - - rc = i2c_attach_client(&lm->i2c); - if (rc) { - printk(KERN_ERR "windfarm: failed to attach %s %s to i2c," - " err %d\n", ds1775 ? "ds1775" : "lm75", - lm->i2c.name, rc); - goto fail; - } + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (addr >> 1) & 0x7f; + info.platform_data = name; + strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE); - if (wf_register_sensor(&lm->sens)) { - i2c_detach_client(&lm->i2c); + client = i2c_new_device(adapter, &info); + if (client == NULL) { + printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n", + ds1775 ? "ds1775" : "lm75", name); goto fail; } - return lm; + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return client; fail: - kfree(lm); return NULL; } @@ -202,21 +202,38 @@ static int wf_lm75_attach(struct i2c_adapter *adapter) return 0; } -static int wf_lm75_detach(struct i2c_client *client) +static int wf_lm75_remove(struct i2c_client *client) { - struct wf_lm75_sensor *lm = i2c_to_lm75(client); + struct wf_lm75_sensor *lm = i2c_get_clientdata(client); DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name); /* Mark client detached */ - lm->i2c.adapter = NULL; + lm->i2c = NULL; /* release sensor */ wf_unregister_sensor(&lm->sens); + i2c_set_clientdata(client, NULL); return 0; } +static const struct i2c_device_id wf_lm75_id[] = { + { "wf_lm75", 0 }, + { "wf_ds1775", 1 }, + { } +}; + +static struct i2c_driver wf_lm75_driver = { + .driver = { + .name = "wf_lm75", + }, + .attach_adapter = wf_lm75_attach, + .probe = wf_lm75_probe, + .remove = wf_lm75_remove, + .id_table = wf_lm75_id, +}; + static int __init wf_lm75_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index e207a90..e2a55ec 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -26,34 +26,22 @@ #define MAX6690_EXTERNAL_TEMP 1 struct wf_6690_sensor { - struct i2c_client i2c; + struct i2c_client *i2c; struct wf_sensor sens; }; #define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) -#define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c) - -static int wf_max6690_attach(struct i2c_adapter *adapter); -static int wf_max6690_detach(struct i2c_client *client); - -static struct i2c_driver wf_max6690_driver = { - .driver = { - .name = "wf_max6690", - }, - .attach_adapter = wf_max6690_attach, - .detach_client = wf_max6690_detach, -}; static int wf_max6690_get(struct wf_sensor *sr, s32 *value) { struct wf_6690_sensor *max = wf_to_6690(sr); s32 data; - if (max->i2c.adapter == NULL) + if (max->i2c == NULL) return -ENODEV; /* chip gets initialized by firmware */ - data = i2c_smbus_read_byte_data(&max->i2c, MAX6690_EXTERNAL_TEMP); + data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP); if (data < 0) return data; *value = data << 16; @@ -64,10 +52,6 @@ static void wf_max6690_release(struct wf_sensor *sr) { struct wf_6690_sensor *max = wf_to_6690(sr); - if (max->i2c.adapter) { - i2c_detach_client(&max->i2c); - max->i2c.adapter = NULL; - } kfree(max); } @@ -77,19 +61,40 @@ static struct wf_sensor_ops wf_max6690_ops = { .owner = THIS_MODULE, }; -static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, - const char *loc) +static int wf_max6690_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wf_6690_sensor *max; - char *name; + int rc; max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); if (max == NULL) { - printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " - "no memory\n", loc); - return; + printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " + "no memory\n"); + return -ENOMEM; + } + + max->i2c = client; + max->sens.name = client->dev.platform_data; + max->sens.ops = &wf_max6690_ops; + i2c_set_clientdata(client, max); + + rc = wf_register_sensor(&max->sens); + if (rc) { + i2c_set_clientdata(client, NULL); + kfree(max); } + return rc; +} + +static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter, + u8 addr, const char *loc) +{ + struct i2c_board_info info; + struct i2c_client *client; + char *name; + if (!strcmp(loc, "BACKSIDE")) name = "backside-temp"; else if (!strcmp(loc, "NB Ambient")) @@ -99,27 +104,26 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, else goto fail; - max->sens.ops = &wf_max6690_ops; - max->sens.name = name; - max->i2c.addr = addr >> 1; - max->i2c.adapter = adapter; - max->i2c.driver = &wf_max6690_driver; - strncpy(max->i2c.name, name, I2C_NAME_SIZE-1); + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = addr >> 1; + info.platform_data = name; + strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE); - if (i2c_attach_client(&max->i2c)) { + client = i2c_new_device(adapter, &info); + if (client == NULL) { printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n"); goto fail; } - if (wf_register_sensor(&max->sens)) { - i2c_detach_client(&max->i2c); - goto fail; - } - - return; + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return client; fail: - kfree(max); + return NULL; } static int wf_max6690_attach(struct i2c_adapter *adapter) @@ -154,16 +158,31 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) return 0; } -static int wf_max6690_detach(struct i2c_client *client) +static int wf_max6690_remove(struct i2c_client *client) { - struct wf_6690_sensor *max = i2c_to_6690(client); + struct wf_6690_sensor *max = i2c_get_clientdata(client); - max->i2c.adapter = NULL; + max->i2c = NULL; wf_unregister_sensor(&max->sens); return 0; } +static const struct i2c_device_id wf_max6690_id[] = { + { "wf_max6690", 0 }, + { } +}; + +static struct i2c_driver wf_max6690_driver = { + .driver = { + .name = "wf_max6690", + }, + .attach_adapter = wf_max6690_attach, + .probe = wf_max6690_probe, + .remove = wf_max6690_remove, + .id_table = wf_max6690_id, +}; + static int __init wf_max6690_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 7847e98..5da729e 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -39,7 +39,7 @@ struct wf_sat { struct mutex mutex; unsigned long last_read; /* jiffies when cache last updated */ u8 cache[16]; - struct i2c_client i2c; + struct i2c_client *i2c; struct device_node *node; }; @@ -54,18 +54,6 @@ struct wf_sat_sensor { }; #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) -#define i2c_to_sat(c) container_of(c, struct wf_sat, i2c) - -static int wf_sat_attach(struct i2c_adapter *adapter); -static int wf_sat_detach(struct i2c_client *client); - -static struct i2c_driver wf_sat_driver = { - .driver = { - .name = "wf_smu_sat", - }, - .attach_adapter = wf_sat_attach, - .detach_client = wf_sat_detach, -}; struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, unsigned int *size) @@ -81,13 +69,13 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, if (sat_id > 1 || (sat = sats[sat_id]) == NULL) return NULL; - err = i2c_smbus_write_word_data(&sat->i2c, 8, id << 8); + err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8); if (err) { printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err); return NULL; } - err = i2c_smbus_read_word_data(&sat->i2c, 9); + err = i2c_smbus_read_word_data(sat->i2c, 9); if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n"); return NULL; @@ -105,7 +93,7 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, return NULL; for (i = 0; i < len; i += 4) { - err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data); + err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data); if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", err); @@ -138,7 +126,7 @@ static int wf_sat_read_cache(struct wf_sat *sat) { int err; - err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache); + err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache); if (err < 0) return err; sat->last_read = jiffies; @@ -161,7 +149,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value) int i, err; s32 val; - if (sat->i2c.adapter == NULL) + if (sat->i2c == NULL) return -ENODEV; mutex_lock(&sat->mutex); @@ -193,10 +181,6 @@ static void wf_sat_release(struct wf_sensor *sr) struct wf_sat *sat = sens->sat; if (atomic_dec_and_test(&sat->refcnt)) { - if (sat->i2c.adapter) { - i2c_detach_client(&sat->i2c); - sat->i2c.adapter = NULL; - } if (sat->nr >= 0) sats[sat->nr] = NULL; kfree(sat); @@ -212,38 +196,58 @@ static struct wf_sensor_ops wf_sat_ops = { static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) { + struct i2c_board_info info; + struct i2c_client *client; + const u32 *reg; + u8 addr; + + reg = of_get_property(dev, "reg", NULL); + if (reg == NULL) + return; + addr = *reg; + DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (addr >> 1) & 0x7f; + info.platform_data = dev; + strlcpy(info.type, "wf_sat", I2C_NAME_SIZE); + + client = i2c_new_device(adapter, &info); + if (client == NULL) { + printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); + return; + } + + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); +} + +static int wf_sat_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *dev = client->dev.platform_data; struct wf_sat *sat; struct wf_sat_sensor *sens; const u32 *reg; const char *loc, *type; - u8 addr, chip, core; + u8 chip, core; struct device_node *child; int shift, cpu, index; char *name; int vsens[2], isens[2]; - reg = of_get_property(dev, "reg", NULL); - if (reg == NULL) - return; - addr = *reg; - DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); - sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL); if (sat == NULL) - return; + return -ENOMEM; sat->nr = -1; sat->node = of_node_get(dev); atomic_set(&sat->refcnt, 0); mutex_init(&sat->mutex); - sat->i2c.addr = (addr >> 1) & 0x7f; - sat->i2c.adapter = adapter; - sat->i2c.driver = &wf_sat_driver; - strncpy(sat->i2c.name, "smu-sat", I2C_NAME_SIZE-1); - - if (i2c_attach_client(&sat->i2c)) { - printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); - goto fail; - } + sat->i2c = client; + i2c_set_clientdata(client, sat); vsens[0] = vsens[1] = -1; isens[0] = isens[1] = -1; @@ -344,10 +348,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) if (sat->nr >= 0) sats[sat->nr] = sat; - return; - - fail: - kfree(sat); + return 0; } static int wf_sat_attach(struct i2c_adapter *adapter) @@ -366,16 +367,32 @@ static int wf_sat_attach(struct i2c_adapter *adapter) return 0; } -static int wf_sat_detach(struct i2c_client *client) +static int wf_sat_remove(struct i2c_client *client) { - struct wf_sat *sat = i2c_to_sat(client); + struct wf_sat *sat = i2c_get_clientdata(client); /* XXX TODO */ - sat->i2c.adapter = NULL; + sat->i2c = NULL; + i2c_set_clientdata(client, NULL); return 0; } +static const struct i2c_device_id wf_sat_id[] = { + { "wf_sat", 0 }, + { } +}; + +static struct i2c_driver wf_sat_driver = { + .driver = { + .name = "wf_smu_sat", + }, + .attach_adapter = wf_sat_attach, + .probe = wf_sat_probe, + .remove = wf_sat_remove, + .id_table = wf_sat_id, +}; + static int __init sat_sensors_init(void) { return i2c_add_driver(&wf_sat_driver); -- cgit v0.10.2 From 2e613e7f69226bd020987bbf0c2ee251c019ab33 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:51 +0200 Subject: therm_adt746x: Convert to a new-style i2c driver The legacy i2c binding model is going away soon, so convert the ppc therm_adt746x driver to the new model or it will break. Signed-off-by: Jean Delvare Tested-by: Andreas Schwab Tested-by: Paul Mackerras Cc: Benjamin Herrenschmidt diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index c0621d5..4a8bf46 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -71,7 +71,7 @@ MODULE_PARM_DESC(verbose,"Verbose log operations " "(default 0)"); struct thermostat { - struct i2c_client clt; + struct i2c_client *clt; u8 temps[3]; u8 cached_temp[3]; u8 initial_limits[3]; @@ -86,9 +86,6 @@ static struct of_device * of_dev; static struct thermostat* thermostat; static struct task_struct *thread_therm = NULL; -static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, - int busno); - static void write_both_fan_speed(struct thermostat *th, int speed); static void write_fan_speed(struct thermostat *th, int speed, int fan); @@ -100,7 +97,7 @@ write_reg(struct thermostat* th, int reg, u8 data) tmp[0] = reg; tmp[1] = data; - rc = i2c_master_send(&th->clt, (const char *)tmp, 2); + rc = i2c_master_send(th->clt, (const char *)tmp, 2); if (rc < 0) return rc; if (rc != 2) @@ -115,12 +112,12 @@ read_reg(struct thermostat* th, int reg) int rc; reg_addr = (u8)reg; - rc = i2c_master_send(&th->clt, ®_addr, 1); + rc = i2c_master_send(th->clt, ®_addr, 1); if (rc < 0) return rc; if (rc != 1) return -ENODEV; - rc = i2c_master_recv(&th->clt, (char *)&data, 1); + rc = i2c_master_recv(th->clt, (char *)&data, 1); if (rc < 0) return rc; return data; @@ -130,26 +127,36 @@ static int attach_thermostat(struct i2c_adapter *adapter) { unsigned long bus_no; + struct i2c_board_info info; + struct i2c_client *client; if (strncmp(adapter->name, "uni-n", 5)) return -ENODEV; bus_no = simple_strtoul(adapter->name + 6, NULL, 10); if (bus_no != therm_bus) return -ENODEV; - return attach_one_thermostat(adapter, therm_address, bus_no); + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE); + info.addr = therm_address; + client = i2c_new_device(adapter, &info); + if (!client) + return -ENODEV; + + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return 0; } static int -detach_thermostat(struct i2c_adapter *adapter) +remove_thermostat(struct i2c_client *client) { - struct thermostat* th; + struct thermostat *th = i2c_get_clientdata(client); int i; - if (thermostat == NULL) - return 0; - - th = thermostat; - if (thread_therm != NULL) { kthread_stop(thread_therm); } @@ -165,8 +172,6 @@ detach_thermostat(struct i2c_adapter *adapter) write_both_fan_speed(th, -1); - i2c_detach_client(&th->clt); - thermostat = NULL; kfree(th); @@ -174,14 +179,6 @@ detach_thermostat(struct i2c_adapter *adapter) return 0; } -static struct i2c_driver thermostat_driver = { - .driver = { - .name = "therm_adt746x", - }, - .attach_adapter = attach_thermostat, - .detach_adapter = detach_thermostat, -}; - static int read_fan_speed(struct thermostat *th, u8 addr) { u8 tmp[2]; @@ -369,8 +366,8 @@ static void set_limit(struct thermostat *th, int i) th->limits[i] = default_limits_local[i] + limit_adjust; } -static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, - int busno) +static int probe_thermostat(struct i2c_client *client, + const struct i2c_device_id *id) { struct thermostat* th; int rc; @@ -383,16 +380,12 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, if (!th) return -ENOMEM; - th->clt.addr = addr; - th->clt.adapter = adapter; - th->clt.driver = &thermostat_driver; - strcpy(th->clt.name, "thermostat"); + i2c_set_clientdata(client, th); + th->clt = client; rc = read_reg(th, 0); if (rc < 0) { - printk(KERN_ERR "adt746x: Thermostat failed to read config " - "from bus %d !\n", - busno); + dev_err(&client->dev, "Thermostat failed to read config!\n"); kfree(th); return -ENODEV; } @@ -421,14 +414,6 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, thermostat = th; - if (i2c_attach_client(&th->clt)) { - printk(KERN_INFO "adt746x: Thermostat failed to attach " - "client !\n"); - thermostat = NULL; - kfree(th); - return -ENODEV; - } - /* be sure to really write fan speed the first time */ th->last_speed[0] = -2; th->last_speed[1] = -2; @@ -454,6 +439,21 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, return 0; } +static const struct i2c_device_id therm_adt746x_id[] = { + { "therm_adt746x", 0 }, + { } +}; + +static struct i2c_driver thermostat_driver = { + .driver = { + .name = "therm_adt746x", + }, + .attach_adapter = attach_thermostat, + .probe = probe_thermostat, + .remove = remove_thermostat, + .id_table = therm_adt746x_id, +}; + /* * Now, unfortunately, sysfs doesn't give us a nice void * we could * pass around to the attribute functions, so we don't really have -- cgit v0.10.2 From 036533e232922ec6667817de9b037d0b1ebd062e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:01:52 +0200 Subject: therm_windtunnel: Convert to a new-style i2c driver The legacy i2c binding model is going away soon, so convert the ppc therm_windtunnel driver to the new model or it will break. Signed-off-by: Jean Delvare Cc: Benjamin Herrenschmidt Cc: Paul Mackerras diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 3da0a02..4002331 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -48,16 +48,6 @@ #define LOG_TEMP 0 /* continously log temperature */ -static int do_probe( struct i2c_adapter *adapter, int addr, int kind); - -/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - 0x4c, 0x4d, 0x4e, 0x4f, - 0x2c, 0x2d, 0x2e, 0x2f, - I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD; - static struct { volatile int running; struct task_struct *poll_task; @@ -315,53 +305,54 @@ static int control_loop(void *dummy) static int do_attach( struct i2c_adapter *adapter ) { - int ret = 0; + /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ + static const unsigned short scan_ds1775[] = { + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + I2C_CLIENT_END + }; + static const unsigned short scan_adm1030[] = { + 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END + }; if( strncmp(adapter->name, "uni-n", 5) ) return 0; if( !x.running ) { - ret = i2c_probe( adapter, &addr_data, &do_probe ); + struct i2c_board_info info; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE); + i2c_new_probed_device(adapter, &info, scan_ds1775); + + strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE); + i2c_new_probed_device(adapter, &info, scan_adm1030); + if( x.thermostat && x.fan ) { x.running = 1; x.poll_task = kthread_run(control_loop, NULL, "g4fand"); } } - return ret; + return 0; } static int -do_detach( struct i2c_client *client ) +do_remove(struct i2c_client *client) { - int err; - - if( (err=i2c_detach_client(client)) ) - printk(KERN_ERR "failed to detach thermostat client\n"); - else { - if( x.running ) { - x.running = 0; - kthread_stop(x.poll_task); - x.poll_task = NULL; - } - if( client == x.thermostat ) - x.thermostat = NULL; - else if( client == x.fan ) - x.fan = NULL; - else { - printk(KERN_ERR "g4fan: bad client\n"); - } - kfree( client ); + if (x.running) { + x.running = 0; + kthread_stop(x.poll_task); + x.poll_task = NULL; } - return err; -} + if (client == x.thermostat) + x.thermostat = NULL; + else if (client == x.fan) + x.fan = NULL; + else + printk(KERN_ERR "g4fan: bad client\n"); -static struct i2c_driver g4fan_driver = { - .driver = { - .name = "therm_windtunnel", - }, - .attach_adapter = do_attach, - .detach_client = do_detach, -}; + return 0; +} static int attach_fan( struct i2c_client *cl ) @@ -374,13 +365,8 @@ attach_fan( struct i2c_client *cl ) goto out; printk("ADM1030 fan controller [@%02x]\n", cl->addr ); - strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) ); - - if( !i2c_attach_client(cl) ) - x.fan = cl; + x.fan = cl; out: - if( cl != x.fan ) - kfree( cl ); return 0; } @@ -412,39 +398,47 @@ attach_thermostat( struct i2c_client *cl ) x.temp = temp; x.overheat_temp = os_temp; x.overheat_hyst = hyst_temp; - - strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) ); - - if( !i2c_attach_client(cl) ) - x.thermostat = cl; + x.thermostat = cl; out: - if( cl != x.thermostat ) - kfree( cl ); return 0; } +enum chip { ds1775, adm1030 }; + +static const struct i2c_device_id therm_windtunnel_id[] = { + { "therm_ds1775", ds1775 }, + { "therm_adm1030", adm1030 }, + { } +}; + static int -do_probe( struct i2c_adapter *adapter, int addr, int kind ) +do_probe(struct i2c_client *cl, const struct i2c_device_id *id) { - struct i2c_client *cl; + struct i2c_adapter *adapter = cl->adapter; if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE) ) return 0; - if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) ) - return -ENOMEM; - - cl->addr = addr; - cl->adapter = adapter; - cl->driver = &g4fan_driver; - cl->flags = 0; - - if( addr < 0x48 ) + switch (id->driver_data) { + case adm1030: return attach_fan( cl ); - return attach_thermostat( cl ); + case ds1775: + return attach_thermostat(cl); + } + return 0; } +static struct i2c_driver g4fan_driver = { + .driver = { + .name = "therm_windtunnel", + }, + .attach_adapter = do_attach, + .probe = do_probe, + .remove = do_remove, + .id_table = therm_windtunnel_id, +}; + /************************************************************************/ /* initialization / cleanup */ -- cgit v0.10.2 From 1dcd775eb302f897865bbab8779ae4165c13cd7e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 13 Jun 2009 14:50:15 +0930 Subject: [IA64] fix compile error in arch/ia64/mm/extable.c ad6561dffa17f17bb68d7207d422c26c381c4313 ("module: trim exception table on init free.") put a bogus trim_init_extable() function into ia64 which didn't compile. Signed-off-by: Rusty Russell Signed-off-by: Tony Luck diff --git a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c index e95d5ad..c99a41e 100644 --- a/arch/ia64/mm/extable.c +++ b/arch/ia64/mm/extable.c @@ -8,7 +8,7 @@ #include #include -#include +#include static int cmp_ex(const void *a, const void *b) { @@ -55,7 +55,7 @@ void sort_extable (struct exception_table_entry *start, static inline unsigned long ex_to_addr(const struct exception_table_entry *x) { - return (unsigned long)&x->insn + x->insn; + return (unsigned long)&x->addr + x->addr; } #ifdef CONFIG_MODULES -- cgit v0.10.2 From cd659fd0d7c91b7830d1fea0c76a640e171d2d43 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:39:45 +0200 Subject: hwmon: Fix more __devexit_p glitches Make sure __devexit and devexit_p() match in all hwmon drivers. Suggested by a similar fix from Mike Frysinger. Signed-off-by: Jean Delvare Acked-by: Hans de Goede Acked-by: Jonathan Cameron diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 5f81ddf..4639b2a 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -247,7 +247,7 @@ static struct platform_driver f71882fg_driver = { .name = DRVNAME, }, .probe = f71882fg_probe, - .remove = __devexit_p(f71882fg_remove), + .remove = f71882fg_remove, }; static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 6cbdc2f..56cd600 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -627,35 +627,35 @@ static struct platform_driver sht_drivers[] = { .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht11", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht15", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht71", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht75", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, }; -- cgit v0.10.2 From 8070408b5446232ba6eb6e0809a329da58a6ae52 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 15 Jun 2009 18:39:46 +0200 Subject: hwmon: (ibmaem) Automatically load on HC10 blade Enable auto-probing for the HC10 blade and amend the supported system list. Signed-off-by: Darrick J. Wong Signed-off-by: Jean Delvare diff --git a/Documentation/hwmon/ibmaem b/Documentation/hwmon/ibmaem index e98bdfe..1e0d59e 100644 --- a/Documentation/hwmon/ibmaem +++ b/Documentation/hwmon/ibmaem @@ -7,7 +7,7 @@ henceforth as AEM. Supported systems: * Any recent IBM System X server with AEM support. This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2, - x3950 M2, and certain HS2x/LS2x/QS2x blades. The IPMI host interface + x3950 M2, and certain HC10/HS2x/LS2x/QS2x blades. The IPMI host interface driver ("ipmi-si") needs to be loaded for this driver to do anything. Prefix: 'ibmaem' Datasheet: Not available diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d73f5f4..86a5cff 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -418,7 +418,7 @@ config SENSORS_IBMAEM power sensors and capping hardware in various IBM System X servers that support Active Energy Manager. This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2, - and certain HS2x/LS2x/QS2x blades. + and certain HC10/HS2x/LS2x/QS2x blades. This driver can also be built as a module. If so, the module will be called ibmaem. diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index fe74609..405d3fb 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -1127,3 +1127,4 @@ MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*"); +MODULE_ALIAS("dmi:bvnIBM:*:pnIBMBladeHC10-*"); -- cgit v0.10.2 From ab2b79d5e22d3cdd2b191e479c60e69df528369a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Jun 2009 18:39:46 +0200 Subject: hwmon: (tmp401) Add support for TI's TMP401 sensor chip This is a new hwmon driver for TI's TMP401 temperature sensor IC. This driver was written on behalf of an embedded systems vendor under the Linux driver project. It has been tested using a TI TMP401 sample attached to a i2c-tiny-usb adapter. Which was provided by Till Harbaum, many thanks to him for this! Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 86a5cff..79117c3 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -787,6 +787,16 @@ config SENSORS_THMC50 This driver can also be built as a module. If so, the module will be called thmc50. +config SENSORS_TMP401 + tristate "Texas Instruments TMP401 and compatibles" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for Texas Instruments TMP401 and + TMP411 temperature sensor chips. + + This driver can also be built as a module. If so, the module + will be called tmp401. + config SENSORS_VIA686A tristate "VIA686A" depends on PCI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 0ae2698..b793dce 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o obj-$(CONFIG_SENSORS_THMC50) += thmc50.o +obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o obj-$(CONFIG_SENSORS_VT8231) += vt8231.o diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c new file mode 100644 index 0000000..49932de --- /dev/null +++ b/drivers/hwmon/tmp401.c @@ -0,0 +1,565 @@ +/* tmp401.c + * + * Copyright (C) 2007,2008 Hans de Goede + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. + * + * Note this IC is in some aspect similar to the LM90, but it has quite a + * few differences too, for example the local temp has a higher resolution + * and thus has 16 bits registers for its value and limit instead of 8 bits. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(tmp401); + + +/* + * The TMP401 registers, note some registers have different addresses for + * reading and writing + */ +#define TMP401_STATUS 0x02 +#define TMP401_CONFIG_READ 0x03 +#define TMP401_CONFIG_WRITE 0x09 +#define TMP401_CONVERSION_RATE_READ 0x04 +#define TMP401_CONVERSION_RATE_WRITE 0x0A +#define TMP401_TEMP_CRIT_HYST 0x21 +#define TMP401_CONSECUTIVE_ALERT 0x22 +#define TMP401_MANUFACTURER_ID_REG 0xFE +#define TMP401_DEVICE_ID_REG 0xFF + +static const u8 TMP401_TEMP_MSB[2] = { 0x00, 0x01 }; +static const u8 TMP401_TEMP_LSB[2] = { 0x15, 0x10 }; +static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2] = { 0x06, 0x08 }; +static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2] = { 0x0C, 0x0E }; +static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2] = { 0x17, 0x14 }; +static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2] = { 0x05, 0x07 }; +static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2] = { 0x0B, 0x0D }; +static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2] = { 0x16, 0x13 }; +/* These are called the THERM limit / hysteresis / mask in the datasheet */ +static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 }; + +/* Flags */ +#define TMP401_CONFIG_RANGE 0x04 +#define TMP401_CONFIG_SHUTDOWN 0x40 +#define TMP401_STATUS_LOCAL_CRIT 0x01 +#define TMP401_STATUS_REMOTE_CRIT 0x02 +#define TMP401_STATUS_REMOTE_OPEN 0x04 +#define TMP401_STATUS_REMOTE_LOW 0x08 +#define TMP401_STATUS_REMOTE_HIGH 0x10 +#define TMP401_STATUS_LOCAL_LOW 0x20 +#define TMP401_STATUS_LOCAL_HIGH 0x40 + +/* Manufacturer / Device ID's */ +#define TMP401_MANUFACTURER_ID 0x55 +#define TMP401_DEVICE_ID 0x11 + +/* + * Functions declarations + */ + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int tmp401_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info); +static int tmp401_remove(struct i2c_client *client); +static struct tmp401_data *tmp401_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static const struct i2c_device_id tmp401_id[] = { + { "tmp401", tmp401 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp401_id); + +static struct i2c_driver tmp401_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "tmp401", + }, + .probe = tmp401_probe, + .remove = tmp401_remove, + .id_table = tmp401_id, + .detect = tmp401_detect, + .address_data = &addr_data, +}; + +/* + * Client data (each client gets its own) + */ + +struct tmp401_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* register values */ + u8 status; + u8 config; + u16 temp[2]; + u16 temp_low[2]; + u16 temp_high[2]; + u8 temp_crit[2]; + u8 temp_crit_hyst; +}; + +/* + * Sysfs attr show / store functions + */ + +static int tmp401_register_to_temp(u16 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64 * 256; + + return (temp * 625 + 80) / 160; +} + +static u16 tmp401_temp_to_register(long temp, u8 config) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = SENSORS_LIMIT(temp, -64000, 191000); + temp += 64000; + } else + temp = SENSORS_LIMIT(temp, 0, 127000); + + return (temp * 160 + 312) / 625; +} + +static int tmp401_crit_register_to_temp(u8 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64; + + return temp * 1000; +} + +static u8 tmp401_crit_temp_to_register(long temp, u8 config) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = SENSORS_LIMIT(temp, -64000, 191000); + temp += 64000; + } else + temp = SENSORS_LIMIT(temp, 0, 127000); + + return (temp + 500) / 1000; +} + +static ssize_t show_temp_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp[index], data->config)); +} + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_low[index], data->config)); +} + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_high[index], data->config)); +} + +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_crit_register_to_temp(data->temp_crit[index], + data->config)); +} + +static ssize_t show_temp_crit_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + mutex_lock(&data->update_lock); + temp = tmp401_crit_register_to_temp(data->temp_crit[index], + data->config); + temp -= data->temp_crit_hyst * 1000; + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t show_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int mask = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (data->status & mask) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_temp_min(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u16 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8); + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF); + + data->temp_low[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u16 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8); + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF); + + data->temp_high[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_crit_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_CRIT_LIMIT[index], reg); + + data->temp_crit[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + if (data->config & TMP401_CONFIG_RANGE) + val = SENSORS_LIMIT(val, -64000, 191000); + else + val = SENSORS_LIMIT(val, 0, 127000); + + mutex_lock(&data->update_lock); + temp = tmp401_crit_register_to_temp(data->temp_crit[index], + data->config); + val = SENSORS_LIMIT(val, temp - 255000, temp); + reg = ((temp - val) + 500) / 1000; + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_CRIT_HYST, reg); + + data->temp_crit_hyst = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static struct sensor_device_attribute tmp401_attr[] = { + SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), + SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0), + SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), + SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0), + SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst, + store_temp_crit_hyst, 0), + SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_LOW), + SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_HIGH), + SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_CRIT), + SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), + SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1), + SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), + SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1), + SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1), + SENSOR_ATTR(temp2_fault, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_OPEN), + SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_LOW), + SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_HIGH), + SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_CRIT), +}; + +/* + * Begin non sysfs callback code (aka Real code) + */ + +static void tmp401_init_client(struct i2c_client *client) +{ + int config, config_orig; + + /* Set the conversion rate to 2 Hz */ + i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); + + /* Start conversions (disable shutdown if necessary) */ + config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (config < 0) { + dev_warn(&client->dev, "Initialization failed!\n"); + return; + } + + config_orig = config; + config &= ~TMP401_CONFIG_SHUTDOWN; + + if (config != config_orig) + i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config); +} + +static int tmp401_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + /* Detect and identify the chip */ + if (kind <= 0) { + u8 reg; + + reg = i2c_smbus_read_byte_data(client, + TMP401_MANUFACTURER_ID_REG); + if (reg != TMP401_MANUFACTURER_ID) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); + if (reg != TMP401_DEVICE_ID) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (reg & 0x1b) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, + TMP401_CONVERSION_RATE_READ); + if (reg > 15) + return -ENODEV; + } + strlcpy(info->type, "tmp401", I2C_NAME_SIZE); + + return 0; +} + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i, err = 0; + struct tmp401_data *data; + + data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* Initialize the TMP401 chip */ + tmp401_init_client(client); + + /* Register sysfs hooks */ + for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) { + err = device_create_file(&client->dev, + &tmp401_attr[i].dev_attr); + if (err) + goto exit_remove; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + data->hwmon_dev = NULL; + goto exit_remove; + } + + dev_info(&client->dev, "Detected TI TMP401 chip\n"); + + return 0; + +exit_remove: + tmp401_remove(client); /* will also free data for us */ + return err; +} + +static int tmp401_remove(struct i2c_client *client) +{ + struct tmp401_data *data = i2c_get_clientdata(client); + int i; + + if (data->hwmon_dev) + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) + device_remove_file(&client->dev, &tmp401_attr[i].dev_attr); + + kfree(data); + return 0; +} + +static struct tmp401_data *tmp401_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tmp401_data *data = i2c_get_clientdata(client); + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS); + data->config = i2c_smbus_read_byte_data(client, + TMP401_CONFIG_READ); + for (i = 0; i < 2; i++) { + /* High byte must be read first immediately followed + by the low byte */ + data->temp[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_MSB[i]) << 8; + data->temp[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LSB[i]); + data->temp_low[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8; + data->temp_low[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_LSB[i]); + data->temp_high[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8; + data->temp_high[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_LSB[i]); + data->temp_crit[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_CRIT_LIMIT[i]); + } + + data->temp_crit_hyst = i2c_smbus_read_byte_data(client, + TMP401_TEMP_CRIT_HYST); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init tmp401_init(void) +{ + return i2c_add_driver(&tmp401_driver); +} + +static void __exit tmp401_exit(void) +{ + i2c_del_driver(&tmp401_driver); +} + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(tmp401_init); +module_exit(tmp401_exit); -- cgit v0.10.2 From fce0758f5990b34af4ffba589b23f25c700beb2f Mon Sep 17 00:00:00 2001 From: Andre Prendel Date: Mon, 15 Jun 2009 18:39:47 +0200 Subject: hwmon: (tmp401) Add support for TI's TMP411 sensors chip This adds support for TI's TMP411 sensor chip. Preliminary support were done by Gabriel Konat, Sander Leget and Wouter Willems. The chip is compatible with TI's TMP401 sensor chip. It has additional support for historical minimun/maximum measurements. Signed-off-by: Andre Prendel Acked-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index 49932de..7b34f2c 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -1,6 +1,9 @@ /* tmp401.c * * Copyright (C) 2007,2008 Hans de Goede + * Preliminary tmp411 support by: + * Gabriel Konat, Sander Leget, Wouter Willems + * Copyright (C) 2009 Andre Prendel * * 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 @@ -40,8 +43,7 @@ static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; /* Insmod parameters */ -I2C_CLIENT_INSMOD_1(tmp401); - +I2C_CLIENT_INSMOD_2(tmp401, tmp411); /* * The TMP401 registers, note some registers have different addresses for @@ -56,6 +58,7 @@ I2C_CLIENT_INSMOD_1(tmp401); #define TMP401_CONSECUTIVE_ALERT 0x22 #define TMP401_MANUFACTURER_ID_REG 0xFE #define TMP401_DEVICE_ID_REG 0xFF +#define TMP411_N_FACTOR_REG 0x18 static const u8 TMP401_TEMP_MSB[2] = { 0x00, 0x01 }; static const u8 TMP401_TEMP_LSB[2] = { 0x15, 0x10 }; @@ -68,6 +71,11 @@ static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2] = { 0x16, 0x13 }; /* These are called the THERM limit / hysteresis / mask in the datasheet */ static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 }; +static const u8 TMP411_TEMP_LOWEST_MSB[2] = { 0x30, 0x34 }; +static const u8 TMP411_TEMP_LOWEST_LSB[2] = { 0x31, 0x35 }; +static const u8 TMP411_TEMP_HIGHEST_MSB[2] = { 0x32, 0x36 }; +static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 }; + /* Flags */ #define TMP401_CONFIG_RANGE 0x04 #define TMP401_CONFIG_SHUTDOWN 0x40 @@ -82,6 +90,7 @@ static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 }; /* Manufacturer / Device ID's */ #define TMP401_MANUFACTURER_ID 0x55 #define TMP401_DEVICE_ID 0x11 +#define TMP411_DEVICE_ID 0x12 /* * Functions declarations @@ -100,6 +109,7 @@ static struct tmp401_data *tmp401_update_device(struct device *dev); static const struct i2c_device_id tmp401_id[] = { { "tmp401", tmp401 }, + { "tmp411", tmp411 }, { } }; MODULE_DEVICE_TABLE(i2c, tmp401_id); @@ -125,6 +135,7 @@ struct tmp401_data { struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ + int kind; /* register values */ u8 status; @@ -134,6 +145,8 @@ struct tmp401_data { u16 temp_high[2]; u8 temp_crit[2]; u8 temp_crit_hyst; + u16 temp_lowest[2]; + u16 temp_highest[2]; }; /* @@ -238,6 +251,28 @@ static ssize_t show_temp_crit_hyst(struct device *dev, return sprintf(buf, "%d\n", temp); } +static ssize_t show_temp_lowest(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_lowest[index], + data->config)); +} + +static ssize_t show_temp_highest(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_highest[index], + data->config)); +} + static ssize_t show_status(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -361,6 +396,30 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute return count; } +/* + * Resets the historical measurements of minimum and maximum temperatures. + * This is done by writing any value to any of the minimum/maximum registers + * (0x30-0x37). + */ +static ssize_t reset_temp_history(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + long val; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + if (val != 1) { + dev_err(dev, "temp_reset_history value %ld not" + " supported. Use 1 to reset the history!\n", val); + return -EINVAL; + } + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP411_TEMP_LOWEST_MSB[0], val); + + return count; +} + static struct sensor_device_attribute tmp401_attr[] = { SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0), @@ -390,6 +449,21 @@ static struct sensor_device_attribute tmp401_attr[] = { }; /* + * Additional features of the TMP411 chip. + * The TMP411 stores the minimum and maximum + * temperature measured since power-on, chip-reset, or + * minimum and maximum register reset for both the local + * and remote channels. + */ +static struct sensor_device_attribute tmp411_attr[] = { + SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0), + SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0), + SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1), + SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1), + SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0), +}; + +/* * Begin non sysfs callback code (aka Real code) */ @@ -432,8 +506,17 @@ static int tmp401_detect(struct i2c_client *client, int kind, return -ENODEV; reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); - if (reg != TMP401_DEVICE_ID) + + switch (reg) { + case TMP401_DEVICE_ID: + kind = tmp401; + break; + case TMP411_DEVICE_ID: + kind = tmp411; + break; + default: return -ENODEV; + } reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); if (reg & 0x1b) @@ -441,10 +524,11 @@ static int tmp401_detect(struct i2c_client *client, int kind, reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ); + /* Datasheet says: 0x1-0x6 */ if (reg > 15) return -ENODEV; } - strlcpy(info->type, "tmp401", I2C_NAME_SIZE); + strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE); return 0; } @@ -454,6 +538,7 @@ static int tmp401_probe(struct i2c_client *client, { int i, err = 0; struct tmp401_data *data; + const char *names[] = { "TMP401", "TMP411" }; data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL); if (!data) @@ -461,6 +546,7 @@ static int tmp401_probe(struct i2c_client *client, i2c_set_clientdata(client, data); mutex_init(&data->update_lock); + data->kind = id->driver_data; /* Initialize the TMP401 chip */ tmp401_init_client(client); @@ -473,6 +559,16 @@ static int tmp401_probe(struct i2c_client *client, goto exit_remove; } + /* Register aditional tmp411 sysfs hooks */ + if (data->kind == tmp411) { + for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) { + err = device_create_file(&client->dev, + &tmp411_attr[i].dev_attr); + if (err) + goto exit_remove; + } + } + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); @@ -480,7 +576,8 @@ static int tmp401_probe(struct i2c_client *client, goto exit_remove; } - dev_info(&client->dev, "Detected TI TMP401 chip\n"); + dev_info(&client->dev, "Detected TI %s chip\n", + names[data->kind - 1]); return 0; @@ -500,15 +597,60 @@ static int tmp401_remove(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) device_remove_file(&client->dev, &tmp401_attr[i].dev_attr); + if (data->kind == tmp411) { + for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) + device_remove_file(&client->dev, + &tmp411_attr[i].dev_attr); + } + kfree(data); return 0; } +static struct tmp401_data *tmp401_update_device_reg16( + struct i2c_client *client, struct tmp401_data *data) +{ + int i; + + for (i = 0; i < 2; i++) { + /* + * High byte must be read first immediately followed + * by the low byte + */ + data->temp[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_MSB[i]) << 8; + data->temp[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LSB[i]); + data->temp_low[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8; + data->temp_low[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_LSB[i]); + data->temp_high[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8; + data->temp_high[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_LSB[i]); + data->temp_crit[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_CRIT_LIMIT[i]); + + if (data->kind == tmp411) { + data->temp_lowest[i] = i2c_smbus_read_byte_data(client, + TMP411_TEMP_LOWEST_MSB[i]) << 8; + data->temp_lowest[i] |= i2c_smbus_read_byte_data( + client, TMP411_TEMP_LOWEST_LSB[i]); + + data->temp_highest[i] = i2c_smbus_read_byte_data( + client, TMP411_TEMP_HIGHEST_MSB[i]) << 8; + data->temp_highest[i] |= i2c_smbus_read_byte_data( + client, TMP411_TEMP_HIGHEST_LSB[i]); + } + } + return data; +} + static struct tmp401_data *tmp401_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct tmp401_data *data = i2c_get_clientdata(client); - int i; mutex_lock(&data->update_lock); @@ -516,24 +658,7 @@ static struct tmp401_data *tmp401_update_device(struct device *dev) data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS); data->config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); - for (i = 0; i < 2; i++) { - /* High byte must be read first immediately followed - by the low byte */ - data->temp[i] = i2c_smbus_read_byte_data(client, - TMP401_TEMP_MSB[i]) << 8; - data->temp[i] |= i2c_smbus_read_byte_data(client, - TMP401_TEMP_LSB[i]); - data->temp_low[i] = i2c_smbus_read_byte_data(client, - TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8; - data->temp_low[i] |= i2c_smbus_read_byte_data(client, - TMP401_TEMP_LOW_LIMIT_LSB[i]); - data->temp_high[i] = i2c_smbus_read_byte_data(client, - TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8; - data->temp_high[i] |= i2c_smbus_read_byte_data(client, - TMP401_TEMP_HIGH_LIMIT_LSB[i]); - data->temp_crit[i] = i2c_smbus_read_byte_data(client, - TMP401_TEMP_CRIT_LIMIT[i]); - } + tmp401_update_device_reg16(client, data); data->temp_crit_hyst = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST); -- cgit v0.10.2 From cd4e96c5dd4a72bdc54ea9981e02465708c204d3 Mon Sep 17 00:00:00 2001 From: Andre Prendel Date: Mon, 15 Jun 2009 18:39:49 +0200 Subject: hwmon: (tmp401) Add documentation Documentation for the tmp401 driver. The documentation describes the tmp401 driver and the supported Texas Instruments TMP401 and TMP411 temperature sensor chips. Further documentation for new sysfs attributes supported by this driver is added to Documentation/hwmon/sysfs-interface. Signed-off-by: Andre Prendel Acked-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 004ee16..dcbd502 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -70,6 +70,7 @@ are interpreted as 0! For more on how written strings are interpreted see the [0-*] denotes any positive number starting from 0 [1-*] denotes any positive number starting from 1 RO read only value +WO write only value RW read/write value Read/write values may be read-only for some chips, depending on the @@ -295,6 +296,24 @@ temp[1-*]_label Suggested temperature channel label. user-space. RO +temp[1-*]_lowest + Historical minimum temperature + Unit: millidegree Celsius + RO + +temp[1-*]_highest + Historical maximum temperature + Unit: millidegree Celsius + RO + +temp[1-*]_reset_history + Reset temp_lowest and temp_highest + WO + +temp_reset_history + Reset temp_lowest and temp_highest for all sensors + WO + Some chips measure temperature using external thermistors and an ADC, and report the temperature measurement as a voltage. Converting this voltage back to a temperature (or the other way around for limits) requires diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401 new file mode 100644 index 0000000..9fc4472 --- /dev/null +++ b/Documentation/hwmon/tmp401 @@ -0,0 +1,42 @@ +Kernel driver tmp401 +==================== + +Supported chips: + * Texas Instruments TMP401 + Prefix: 'tmp401' + Addresses scanned: I2C 0x4c + Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html + * Texas Instruments TMP411 + Prefix: 'tmp411' + Addresses scanned: I2C 0x4c + Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html + +Authors: + Hans de Goede + Andre Prendel + +Description +----------- + +This driver implements support for Texas Instruments TMP401 and +TMP411 chips. These chips implements one remote and one local +temperature sensor. Temperature is measured in degrees +Celsius. Resolution of the remote sensor is 0.0625 degree. Local +sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not +supported by the driver so far, so using the default resolution of 0.5 +degree). + +The driver provides the common sysfs-interface for temperatures (see +/Documentation/hwmon/sysfs-interface under Temperatures). + +The TMP411 chip is compatible with TMP401. It provides some additional +features. + +* Minimum and Maximum temperature measured since power-on, chip-reset + + Exported via sysfs attributes tempX_lowest and tempX_highest. + +* Reset of historical minimum/maximum temperature measurements + + Exported via sysfs attribute temp_reset_history. Writing 1 to this + file triggers a reset. -- cgit v0.10.2 From c1e48dce05ff06266cdfd0cba55fc5367cd499a5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:39:50 +0200 Subject: hwmon: (w83627ehf) Add W83627DHG-P support Add support for the new incarnation of the Winbond/Nuvoton W83627DHG chip known as W83627DHG-P. It is basically the same as the original W83627DHG with an additional automatic can speed control mode (not supported by the driver yet.) Signed-off-by: Jean Delvare Tested-by: Madhu diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index b6eb593..02b7489 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -12,6 +12,10 @@ Supported chips: Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf + * Winbond W83627DHG-P + Prefix: 'w83627dhg' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: not available * Winbond W83667HG Prefix: 'w83667hg' Addresses scanned: ISA address retrieved from Super I/O registers @@ -28,8 +32,8 @@ Description ----------- This driver implements support for the Winbond W83627EHF, W83627EHG, -W83627DHG and W83667HG super I/O chips. We will refer to them collectively -as Winbond chips. +W83627DHG, W83627DHG-P and W83667HG super I/O chips. We will refer to them +collectively as Winbond chips. The chips implement three temperature sensors, five fan rotation speed sensors, ten analog voltage sensors (only nine for the 627DHG), one @@ -135,3 +139,6 @@ done in the driver for all register addresses. The DHG also supports PECI, where the DHG queries Intel CPU temperatures, and the ICH8 southbridge gets that data via PECI from the DHG, so that the southbridge drives the fans. And the DHG supports SST, a one-wire serial bus. + +The DHG-P has an additional automatic fan speed control mode named Smart Fan +(TM) III+. This mode is not yet supported by the driver. diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index e64b420..0e97469 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -36,6 +36,7 @@ w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 0x8860 0xa1 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 + w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 */ @@ -53,12 +54,13 @@ #include #include "lm75.h" -enum kinds { w83627ehf, w83627dhg, w83667hg }; +enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg }; /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ static const char * w83627ehf_device_names[] = { "w83627ehf", "w83627dhg", + "w83627dhg", "w83667hg", }; @@ -86,6 +88,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); #define SIO_W83627EHF_ID 0x8850 #define SIO_W83627EHG_ID 0x8860 #define SIO_W83627DHG_ID 0xa020 +#define SIO_W83627DHG_P_ID 0xb070 #define SIO_W83667HG_ID 0xa510 #define SIO_ID_MASK 0xFFF0 @@ -1517,6 +1520,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; + static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; static const char __initdata sio_name_W83667HG[] = "W83667HG"; u16 val; @@ -1542,6 +1546,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, sio_data->kind = w83627dhg; sio_name = sio_name_W83627DHG; break; + case SIO_W83627DHG_P_ID: + sio_data->kind = w83627dhg_p; + sio_name = sio_name_W83627DHG_P; + break; case SIO_W83667HG_ID: sio_data->kind = w83667hg; sio_name = sio_name_W83667HG; -- cgit v0.10.2 From 2958b1ec6be1d71105d67d70de9d7d70f5e97151 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 15 Jun 2009 18:39:50 +0200 Subject: hwmon: PCI quirk for hwmon access on MSI MS-7031 board The MSI MS-7031 is based on an ATI IXP300 south bridge. On this south bridge, accessible I/O ports must be enabled explicitly. Unfortunately the BIOS forgets to enable access to the hardware monitoring chip I/O ports, so hardware monitoring fails. Add a quirk enabling access to the required ports (0x295-0x296). This is exactly what MSI's own hardware monitoring application is doing, so it has to be the right way. Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index e15c3e7..29ea675 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -18,6 +18,7 @@ #include #include #include +#include #define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" @@ -86,8 +87,36 @@ void hwmon_device_unregister(struct device *dev) "hwmon_device_unregister() failed: bad class ID!\n"); } +static void __init hwmon_pci_quirks(void) +{ +#if defined CONFIG_X86 && defined CONFIG_PCI + struct pci_dev *sb; + u16 base; + u8 enable; + + /* Open access to 0x295-0x296 on MSI MS-7031 */ + sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); + if (sb && + (sb->subsystem_vendor == 0x1462 && /* MSI */ + sb->subsystem_device == 0x0031)) { /* MS-7031 */ + + pci_read_config_byte(sb, 0x48, &enable); + pci_read_config_word(sb, 0x64, &base); + + if (base == 0 && !(enable & BIT(2))) { + dev_info(&sb->dev, + "Opening wide generic port at 0x295\n"); + pci_write_config_word(sb, 0x64, 0x295); + pci_write_config_byte(sb, 0x48, enable | BIT(2)); + } + } +#endif +} + static int __init hwmon_init(void) { + hwmon_pci_quirks(); + hwmon_class = class_create(THIS_MODULE, "hwmon"); if (IS_ERR(hwmon_class)) { printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); -- cgit v0.10.2 From 3fc7838a20cdd9aab0077f355b8c44135cd4b6bd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Jun 2009 18:39:50 +0200 Subject: hwmon: (f71882fg) Cleanup f8000 pwm handling Currently we are using separate per model sysfs attr for the 3th pwm, because the 3th pwm of the f8000 only has automatic mode and not manual mode. Doing things this way was getting in the way for adding f71858fg support, so this patch makes the pwm attr identical for all models, and instead adds a check to store_pwm_enable() disallowing setting the 3th pwm to manual mode on a f8000 IC. Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 4639b2a..eb324e6 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -1,6 +1,6 @@ /*************************************************************************** * Copyright (C) 2006 by Hans Edgington * - * Copyright (C) 2007,2008 by Hans de Goede * + * Copyright (C) 2007-2009 Hans de Goede * * * * 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 * @@ -395,6 +395,9 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[] = { show_pwm_auto_point_channel, store_pwm_auto_point_channel, 0, 1), + SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), + SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, + store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR, show_pwm_interpolate, store_pwm_interpolate, 0, 2), SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, @@ -450,9 +453,6 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 1), - SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), - SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, - store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 1, 2), @@ -565,9 +565,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 1), - SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), - SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, - store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 2), @@ -659,8 +656,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { static struct sensor_device_attribute_2 f8000_fan_attr[] = { SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), - SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2), - SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 2), @@ -1440,6 +1435,10 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute int nr = to_sensor_dev_attr_2(devattr)->index; long val = simple_strtol(buf, NULL, 10); + /* Special case for F8000 pwm channel 3 which only does auto mode */ + if (data->type == f8000 && nr == 2 && val != 2) + return -EINVAL; + mutex_lock(&data->update_lock); data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); /* Special case for F8000 auto PWM mode / Thermostat mode */ -- cgit v0.10.2 From 996cadb2bf3787adcf4e164e1b351966c9e787f6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Jun 2009 18:39:51 +0200 Subject: hwmon: (f71882fg) Sanity check f8000 pwm settings We depend up on the pwm_enable register (0x96) not containing any reserved settings in various places. We were already checking to make sure there were no reserved settings in the register for the f71862fg, this patch adds the same checking for the f8000, while at it it also moves the code to a more apropriate place so we don't need to check if the fan/pwm part of the IC is enabled twice. Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index eb324e6..a65eac8 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -1735,19 +1735,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) goto exit_free; } - data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - /* If it is a 71862 and the fan / pwm part is enabled sanity check - the pwm settings */ - if (data->type == f71862fg && (start_reg & 0x02)) { - if ((data->pwm_enable & 0x15) != 0x15) { - dev_err(&pdev->dev, - "Invalid (reserved) pwm settings: 0x%02x\n", - (unsigned int)data->pwm_enable); - err = -ENODEV; - goto exit_free; - } - } - /* Register sysfs interface files */ err = device_create_file(&pdev->dev, &dev_attr_name); if (err) @@ -1778,6 +1765,29 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) } if (start_reg & 0x02) { + data->pwm_enable = + f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + + /* Sanity check the pwm settings */ + switch (data->type) { + case f71862fg: + err = (data->pwm_enable & 0x15) != 0x15; + break; + case f71882fg: + err = 0; + break; + case f8000: + err = data->pwm_enable & 0x20; + break; + } + if (err) { + dev_err(&pdev->dev, + "Invalid (reserved) pwm settings: 0x%02x\n", + (unsigned int)data->pwm_enable); + err = -ENODEV; + goto exit_unregister_sysfs; + } + err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr, ARRAY_SIZE(fxxxx_fan_attr)); if (err) -- cgit v0.10.2 From b6858bca8d7bf52e2564cba5a5ed87e1019d3fd9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Jun 2009 18:39:51 +0200 Subject: hwmon: (f71882fg) Add temp#_fault sysfs attr for f8000 While working on f71852fg support I noticed that the f8000 sysfs attr table was missing entries for temp#_fault, which the f8000 does have and which we were already reading. Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index a65eac8..7e5b94c 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -344,6 +344,7 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 0), SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 1), @@ -351,12 +352,14 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { store_temp_max, 0, 1), SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 2), SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 2), SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), }; /* Fan / PWM attr common to all models */ -- cgit v0.10.2 From 09475d32e652fe60901fe8c9cd50f3f6db0c4933 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Jun 2009 18:39:52 +0200 Subject: hwmon: (f71882fg) Add support for the F71858F Add support for the hwmon part of the Fintek F71858FG superio IC to the f71882fg driver. Many thanks to Jelle de Jong for lending me a motherboard with this superio on it. Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg index a832126..bee4c30 100644 --- a/Documentation/hwmon/f71882fg +++ b/Documentation/hwmon/f71882fg @@ -2,14 +2,18 @@ Kernel driver f71882fg ====================== Supported chips: - * Fintek F71882FG and F71883FG - Prefix: 'f71882fg' + * Fintek F71858FG + Prefix: 'f71858fg' Addresses scanned: none, address read from Super I/O config space Datasheet: Available from the Fintek website * Fintek F71862FG and F71863FG Prefix: 'f71862fg' Addresses scanned: none, address read from Super I/O config space Datasheet: Available from the Fintek website + * Fintek F71882FG and F71883FG + Prefix: 'f71882fg' + Addresses scanned: none, address read from Super I/O config space + Datasheet: Available from the Fintek website * Fintek F8000 Prefix: 'f8000' Addresses scanned: none, address read from Super I/O config space @@ -66,13 +70,13 @@ printed when loading the driver. Three different fan control modes are supported; the mode number is written to the pwm#_enable file. Note that not all modes are supported on all -chips, and some modes may only be available in RPM / PWM mode on the F8000. +chips, and some modes may only be available in RPM / PWM mode. Writing an unsupported mode will result in an invalid parameter error. * 1: Manual mode You ask for a specific PWM duty cycle / DC voltage or a specific % of fan#_full_speed by writing to the pwm# file. This mode is only - available on the F8000 if the fan channel is in RPM mode. + available on the F71858FG / F8000 if the fan channel is in RPM mode. * 2: Normal auto mode You can define a number of temperature/fan speed trip points, which % the diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 79117c3..f8090e1 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -306,11 +306,11 @@ config SENSORS_F71805F will be called f71805f. config SENSORS_F71882FG - tristate "Fintek F71862FG, F71882FG and F8000" + tristate "Fintek F71858FG, F71862FG, F71882FG and F8000" depends on EXPERIMENTAL help If you say yes here you get support for hardware monitoring - features of the Fintek F71882FG/F71883FG, F71862FG/71863FG + features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG and F8000 Super-I/O chips. This driver can also be built as a module. If so, the module diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 7e5b94c..4146105 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -32,6 +32,7 @@ #define DRVNAME "f71882fg" +#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */ #define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */ #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ #define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ @@ -44,6 +45,7 @@ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ +#define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ @@ -70,6 +72,7 @@ #define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr)) #define F71882FG_REG_TEMP_STATUS 0x62 #define F71882FG_REG_TEMP_BEEP 0x63 +#define F71882FG_REG_TEMP_CONFIG 0x69 #define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr)) #define F71882FG_REG_TEMP_TYPE 0x6B #define F71882FG_REG_TEMP_DIODE_OPEN 0x6F @@ -92,9 +95,10 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -enum chips { f71862fg, f71882fg, f8000 }; +enum chips { f71858fg, f71862fg, f71882fg, f8000 }; static const char *f71882fg_names[] = { + "f71858fg", "f71862fg", "f71882fg", "f8000", @@ -119,6 +123,7 @@ struct f71882fg_data { struct device *hwmon_dev; struct mutex update_lock; + int temp_start; /* temp numbering start (0 or 1) */ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_limits; /* In jiffies */ @@ -136,7 +141,7 @@ struct f71882fg_data { /* Note: all models have only 3 temperature channels, but on some they are addressed as 0-2 and on others as 1-3, so for coding convenience we reserve space for 4 channels */ - u8 temp[4]; + u16 temp[4]; u8 temp_ovt[4]; u8 temp_high[4]; u8 temp_hyst[2]; /* 2 hysts stored per reg */ @@ -144,6 +149,7 @@ struct f71882fg_data { u8 temp_status; u8 temp_beep; u8 temp_diode_open; + u8 temp_config; u8 pwm[4]; u8 pwm_enable; u8 pwm_auto_point_hyst[2]; @@ -252,6 +258,50 @@ static struct platform_driver f71882fg_driver = { static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +/* Temp and in attr for the f71858fg */ +static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = { + SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), + SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), + SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), + SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), + SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 0), + SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 0), + SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0), + SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 0), + SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 0), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), + SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), + SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 1), + SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 1), + SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), + SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 1), + SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 1), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), + SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), + SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), + SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 2), + SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 2), + SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2), + SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 2), + SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 2), + SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), +}; + /* Temp and in attr common to both the f71862fg and f71882fg */ static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = { SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), @@ -476,22 +526,8 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 3, 2), }; -/* Fan / PWM attr for the f71882fg */ -static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { - SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 0), - SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 1), - SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 2), - SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), - SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, - show_fan_full_speed, - store_fan_full_speed, 0, 3), - SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 3), - SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), - +/* Fan / PWM attr common to both the f71882fg and f71858fg */ +static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = { SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 0), @@ -605,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 2, 2), SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 2), +}; + +/* Fan / PWM attr found on the f71882fg but not on the f71858fg */ +static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { + SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 0), + SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 1), + SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 2), + + SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), + SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, + show_fan_full_speed, + store_fan_full_speed, 0, 3), + SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 3), + SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3), SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable, @@ -855,13 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) outb(val & 255, data->addr + DATA_REG_OFFSET); } +static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) +{ + if (data->type == f71858fg) + return f71882fg_read16(data, F71882FG_REG_TEMP(nr)); + else + return f71882fg_read8(data, F71882FG_REG_TEMP(nr)); +} + static struct f71882fg_data *f71882fg_update_device(struct device *dev) { struct f71882fg_data *data = dev_get_drvdata(dev); int nr, reg = 0, reg2; int nr_fans = (data->type == f71882fg) ? 4 : 3; - int nr_ins = (data->type == f8000) ? 3 : 9; - int temp_start = (data->type == f8000) ? 0 : 1; + int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9; mutex_lock(&data->update_lock); @@ -876,7 +937,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) } /* Get High & boundary temps*/ - for (nr = temp_start; nr < 3 + temp_start; nr++) { + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) { data->temp_ovt[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_OVT(nr)); data->temp_high[nr] = f71882fg_read8(data, @@ -884,14 +945,17 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) } if (data->type != f8000) { - data->fan_beep = f71882fg_read8(data, - F71882FG_REG_FAN_BEEP); - data->temp_beep = f71882fg_read8(data, - F71882FG_REG_TEMP_BEEP); data->temp_hyst[0] = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(0)); data->temp_hyst[1] = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(1)); + } + + if (data->type == f71862fg || data->type == f71882fg) { + data->fan_beep = f71882fg_read8(data, + F71882FG_REG_FAN_BEEP); + data->temp_beep = f71882fg_read8(data, + F71882FG_REG_TEMP_BEEP); /* Have to hardcode type, because temp1 is special */ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); data->temp_type[2] = (reg & 0x04) ? 2 : 4; @@ -902,10 +966,10 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) data->temp_type[1] = 6 /* PECI */; else if ((reg2 & 0x03) == 0x02) data->temp_type[1] = 5 /* AMDSI */; - else if (data->type != f8000) + else if (data->type == f71862fg || data->type == f71882fg) data->temp_type[1] = (reg & 0x02) ? 2 : 4; else - data->temp_type[1] = 2; /* F8000 only supports BJT */ + data->temp_type[1] = 2; /* Only supports BJT */ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); @@ -961,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) F71882FG_REG_TEMP_STATUS); data->temp_diode_open = f71882fg_read8(data, F71882FG_REG_TEMP_DIODE_OPEN); - for (nr = temp_start; nr < 3 + temp_start; nr++) - data->temp[nr] = f71882fg_read8(data, - F71882FG_REG_TEMP(nr)); + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) + data->temp[nr] = f71882fg_read_temp(data, nr); data->fan_status = f71882fg_read8(data, F71882FG_REG_FAN_STATUS); @@ -1166,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, { struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; + int sign, temp; + + if (data->type == f71858fg) { + /* TEMP_TABLE_SEL 1 or 3 ? */ + if (data->temp_config & 1) { + sign = data->temp[nr] & 0x0001; + temp = (data->temp[nr] >> 5) & 0x7ff; + } else { + sign = data->temp[nr] & 0x8000; + temp = (data->temp[nr] >> 5) & 0x3ff; + } + temp *= 125; + if (sign) + temp -= 128000; + } else + temp = data->temp[nr] * 1000; - return sprintf(buf, "%d\n", data->temp[nr] * 1000); + return sprintf(buf, "%d\n", temp); } static ssize_t show_temp_max(struct device *dev, struct device_attribute @@ -1460,6 +1539,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute } else { switch (val) { case 1: + /* The f71858fg does not support manual RPM mode */ + if (data->type == f71858fg && + ((data->pwm_enable >> (2 * nr)) & 1)) { + count = -EINVAL; + goto leave; + } data->pwm_enable |= 2 << (2 * nr); break; /* Manual */ case 2: @@ -1618,9 +1703,9 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev, int result; struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_start = (data->type == f8000) ? 0 : 1; - result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start); + result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - + data->temp_start); return sprintf(buf, "%d\n", result); } @@ -1631,7 +1716,6 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, { struct f71882fg_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_start = (data->type == f8000) ? 0 : 1; long val = simple_strtol(buf, NULL, 10); switch (val) { @@ -1647,7 +1731,7 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, default: return -EINVAL; } - val += temp_start; + val += data->temp_start; mutex_lock(&data->update_lock); data->pwm_auto_point_mapping[nr] = f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); @@ -1723,6 +1807,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; data->type = sio_data->type; + data->temp_start = + (data->type == f71858fg || data->type == f8000) ? 0 : 1; mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); @@ -1745,6 +1831,20 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) if (start_reg & 0x01) { switch (data->type) { + case f71858fg: + data->temp_config = + f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG); + if (data->temp_config & 0x10) + /* The f71858fg temperature alarms behave as + the f8000 alarms in this mode */ + err = f71882fg_create_sysfs_files(pdev, + f8000_in_temp_attr, + ARRAY_SIZE(f8000_in_temp_attr)); + else + err = f71882fg_create_sysfs_files(pdev, + f71858fg_in_temp_attr, + ARRAY_SIZE(f71858fg_in_temp_attr)); + break; case f71882fg: err = f71882fg_create_sysfs_files(pdev, f71882fg_in_temp_attr, @@ -1773,6 +1873,12 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) /* Sanity check the pwm settings */ switch (data->type) { + case f71858fg: + err = 0; + for (i = 0; i < nr_fans; i++) + if (((data->pwm_enable >> (i * 2)) & 3) == 3) + err = 1; + break; case f71862fg: err = (data->pwm_enable & 0x15) != 0x15; break; @@ -1806,6 +1912,13 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) err = f71882fg_create_sysfs_files(pdev, f71882fg_fan_attr, ARRAY_SIZE(f71882fg_fan_attr)); + if (err) + goto exit_unregister_sysfs; + /* fall through! */ + case f71858fg: + err = f71882fg_create_sysfs_files(pdev, + f71882fg_f71858fg_fan_attr, + ARRAY_SIZE(f71882fg_f71858fg_fan_attr)); break; case f8000: err = f71882fg_create_sysfs_files(pdev, @@ -1890,6 +2003,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { + case SIO_F71858_ID: + sio_data->type = f71858fg; + break; case SIO_F71862_ID: sio_data->type = f71862fg; break; @@ -1904,7 +2020,11 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, goto exit; } - superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (sio_data->type == f71858fg) + superio_select(sioaddr, SIO_F71858FG_LD_HWM); + else + superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { printk(KERN_WARNING DRVNAME ": Device not activated\n"); goto exit; -- cgit v0.10.2 From 52b5226f481c09cc499cc28b1e9347d314b340f1 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Mon, 15 Jun 2009 18:39:52 +0200 Subject: hwmon: (max6650) Add support for alarms Export the alarm flags provided by the MAX6650/MAX6651 fan-speed regulator and monitor chips via sysfs. Signed-off-by: Christian Engelmayer Acked-by: Hans de Goede Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index f27af6a..86142a8 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -12,7 +12,7 @@ * also work with the MAX6651. It does not distinguish max6650 and max6651 * chips. * - * Tha datasheet was last seen at: + * The datasheet was last seen at: * * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf * @@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650); #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 #define MAX6650_COUNT_MASK 0x03 +/* + * Alarm status register bits + */ + +#define MAX6650_ALRM_MAX 0x01 +#define MAX6650_ALRM_MIN 0x02 +#define MAX6650_ALRM_TACH 0x04 +#define MAX6650_ALRM_GPIO1 0x08 +#define MAX6650_ALRM_GPIO2 0x10 + /* Minimum and maximum values of the FAN-RPM */ #define FAN_RPM_MIN 240 #define FAN_RPM_MAX 30000 @@ -151,6 +161,7 @@ struct max6650_data u8 tach[4]; u8 count; u8 dac; + u8 alarm; }; static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, @@ -418,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, return count; } +/* + * Get alarm stati: + * Possible values: + * 0 = no alarm + * 1 = alarm + */ + +static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct max6650_data *data = max6650_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + int alarm = 0; + + if (data->alarm & attr->index) { + mutex_lock(&data->update_lock); + alarm = 1; + data->alarm &= ~attr->index; + data->alarm |= i2c_smbus_read_byte_data(client, + MAX6650_REG_ALARM); + mutex_unlock(&data->update_lock); + } + + return sprintf(buf, "%d\n", alarm); +} + static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); @@ -426,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target); static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); +static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_MAX); +static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_MIN); +static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_TACH); +static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_GPIO1); +static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_GPIO2); + +static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, + int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct i2c_client *client = to_i2c_client(dev); + u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN); + struct device_attribute *devattr; + /* + * Hide the alarms that have not been enabled by the firmware + */ + + devattr = container_of(a, struct device_attribute, attr); + if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr + || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr + || devattr == &sensor_dev_attr_fan1_fault.dev_attr + || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr + || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) { + if (!(alarm_en & to_sensor_dev_attr(devattr)->index)) + return 0; + } + + return a->mode; +} static struct attribute *max6650_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, @@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = { &dev_attr_fan1_div.attr, &dev_attr_pwm1_enable.attr, &dev_attr_pwm1.attr, + &sensor_dev_attr_fan1_max_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_fault.dev_attr.attr, + &sensor_dev_attr_gpio1_alarm.dev_attr.attr, + &sensor_dev_attr_gpio2_alarm.dev_attr.attr, NULL }; static struct attribute_group max6650_attr_grp = { .attrs = max6650_attrs, + .is_visible = max6650_attrs_visible, }; /* @@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev) MAX6650_REG_COUNT); data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); + /* Alarms are cleared on read in case the condition that + * caused the alarm is removed. Keep the value latched here + * for providing the register through different alarm files. */ + data->alarm |= i2c_smbus_read_byte_data(client, + MAX6650_REG_ALARM); + data->last_updated = jiffies; data->valid = 1; } -- cgit v0.10.2 From 6b791bcc8b2ae21daf95d18cff2f1eca7a64c9a5 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Fri, 12 Jun 2009 14:18:36 +0800 Subject: ocfs2: Adjust rightmost path in ocfs2_add_branch. In ocfs2_add_branch, we use the rightmost rec of the leaf extent block to generate the e_cpos for the newly added branch. In the most case, it is OK but if the parent extent block's rightmost rec covers more clusters than the leaf does, it will cause kernel panic if we insert some clusters in it. The message is something like: (7445,1):ocfs2_insert_at_leaf:3775 ERROR: bug expression: le16_to_cpu(el->l_next_free_rec) >= le16_to_cpu(el->l_count) (7445,1):ocfs2_insert_at_leaf:3775 ERROR: inode 66053, depth 0, count 28, next free 28, rec.cpos 270, rec.clusters 1, insert.cpos 275, insert.clusters 1 [] ? ocfs2_do_insert_extent+0xb58/0xda0 [ocfs2] [] ? ocfs2_insert_extent+0x5bd/0x6ba [ocfs2] [] ? ocfs2_add_clusters_in_btree+0x37f/0x564 [ocfs2] ... The panic can be easily reproduced by the following small test case (with bs=512, cs=4K, and I remove all the error handling so that it looks clear enough for reading). int main(int argc, char **argv) { int fd, i; char buf[5] = "test"; fd = open(argv[1], O_RDWR|O_CREAT); for (i = 0; i < 30; i++) { lseek(fd, 40960 * i, SEEK_SET); write(fd, buf, 5); } ftruncate(fd, 1146880); lseek(fd, 1126400, SEEK_SET); write(fd, buf, 5); close(fd); return 0; } The reason of the panic is that: the 30 writes and the ftruncate makes the file's extent list looks like: Tree Depth: 1 Count: 19 Next Free Rec: 1 ## Offset Clusters Block# 0 0 280 86183 SubAlloc Bit: 7 SubAlloc Slot: 0 Blknum: 86183 Next Leaf: 0 CRC32: 00000000 ECC: 0000 Tree Depth: 0 Count: 28 Next Free Rec: 28 ## Offset Clusters Block# Flags 0 0 1 143368 0x0 1 10 1 143376 0x0 ... 26 260 1 143576 0x0 27 270 1 143584 0x0 Now another write at 1126400(275 cluster) whiich will write at the gap between 271 and 280 will trigger ocfs2_add_branch, but the result after the function looks like: Tree Depth: 1 Count: 19 Next Free Rec: 2 ## Offset Clusters Block# 0 0 280 86183 1 271 0 143592 So the extent record is intersected and make the following operation bug out. This patch just try to remove the gap before we add the new branch, so that the root(branch) rightmost rec will cover the same right position. So in the above case, before adding branch the tree will be changed to Tree Depth: 1 Count: 19 Next Free Rec: 1 ## Offset Clusters Block# 0 0 271 86183 SubAlloc Bit: 7 SubAlloc Slot: 0 Blknum: 86183 Next Leaf: 0 CRC32: 00000000 ECC: 0000 Tree Depth: 0 Count: 28 Next Free Rec: 28 ## Offset Clusters Block# Flags 0 0 1 143368 0x0 1 10 1 143376 0x0 ... 26 260 1 143576 0x0 27 270 1 143584 0x0 And after branch add, the tree looks like Tree Depth: 1 Count: 19 Next Free Rec: 2 ## Offset Clusters Block# 0 0 271 86183 1 271 0 143592 Signed-off-by: Tao Ma Acked-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 678a067..9edcde4 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -475,6 +475,12 @@ struct ocfs2_path { #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el) #define path_num_items(_path) ((_path)->p_tree_depth + 1) +static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path, + u32 cpos); +static void ocfs2_adjust_rightmost_records(struct inode *inode, + handle_t *handle, + struct ocfs2_path *path, + struct ocfs2_extent_rec *insert_rec); /* * Reset the actual path elements so that we can re-use the structure * to build another path. Generally, this involves freeing the buffer @@ -1013,6 +1019,54 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el) } /* + * Change range of the branches in the right most path according to the leaf + * extent block's rightmost record. + */ +static int ocfs2_adjust_rightmost_branch(handle_t *handle, + struct inode *inode, + struct ocfs2_extent_tree *et) +{ + int status; + struct ocfs2_path *path = NULL; + struct ocfs2_extent_list *el; + struct ocfs2_extent_rec *rec; + + path = ocfs2_new_path_from_et(et); + if (!path) { + status = -ENOMEM; + return status; + } + + status = ocfs2_find_path(inode, path, UINT_MAX); + if (status < 0) { + mlog_errno(status); + goto out; + } + + status = ocfs2_extend_trans(handle, path_num_items(path) + + handle->h_buffer_credits); + if (status < 0) { + mlog_errno(status); + goto out; + } + + status = ocfs2_journal_access_path(inode, handle, path); + if (status < 0) { + mlog_errno(status); + goto out; + } + + el = path_leaf_el(path); + rec = &el->l_recs[le32_to_cpu(el->l_next_free_rec) - 1]; + + ocfs2_adjust_rightmost_records(inode, handle, path, rec); + +out: + ocfs2_free_path(path); + return status; +} + +/* * Add an entire tree branch to our inode. eb_bh is the extent block * to start at, if we don't want to start the branch at the dinode * structure. @@ -1038,7 +1092,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, struct ocfs2_extent_block *eb; struct ocfs2_extent_list *eb_el; struct ocfs2_extent_list *el; - u32 new_cpos; + u32 new_cpos, root_end; mlog_entry_void(); @@ -1055,6 +1109,27 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, new_blocks = le16_to_cpu(el->l_tree_depth); + eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; + new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); + root_end = ocfs2_sum_rightmost_rec(et->et_root_el); + + /* + * If there is a gap before the root end and the real end + * of the righmost leaf block, we need to remove the gap + * between new_cpos and root_end first so that the tree + * is consistent after we add a new branch(it will start + * from new_cpos). + */ + if (root_end > new_cpos) { + mlog(0, "adjust the cluster end from %u to %u\n", + root_end, new_cpos); + status = ocfs2_adjust_rightmost_branch(handle, inode, et); + if (status) { + mlog_errno(status); + goto bail; + } + } + /* allocate the number of new eb blocks we need */ new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *), GFP_KERNEL); @@ -1071,9 +1146,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, goto bail; } - eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; - new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); - /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be * linked with the rest of the tree. * conversly, new_eb_bhs[0] is the new bottommost leaf. -- cgit v0.10.2 From 9af0b38ff3f4f79c62dd909405b113bf7c1a23aa Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Thu, 11 Jun 2009 11:02:03 -0700 Subject: ocfs2/net: Use wait_event() in o2net_send_message_vec() Replace wait_event_interruptible() with wait_event() in o2net_send_message_vec(). This is because this function is called by the dlm that expects signals to be blocked. Fixes oss bugzilla#1126 http://oss.oracle.com/bugzilla/show_bug.cgi?id=1126 Signed-off-by: Sunil Mushran Signed-off-by: Joel Becker diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 9fbe849..334f231 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -974,7 +974,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn, int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, size_t caller_veclen, u8 target_node, int *status) { - int ret, error = 0; + int ret; struct o2net_msg *msg = NULL; size_t veclen, caller_bytes = 0; struct kvec *vec = NULL; @@ -1015,10 +1015,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, o2net_set_nst_sock_time(&nst); - ret = wait_event_interruptible(nn->nn_sc_wq, - o2net_tx_can_proceed(nn, &sc, &error)); - if (!ret && error) - ret = error; + wait_event(nn->nn_sc_wq, o2net_tx_can_proceed(nn, &sc, &ret)); if (ret) goto out; -- cgit v0.10.2 From 978d910d31c5202e251298bf3f603300a54605dd Mon Sep 17 00:00:00 2001 From: Yan Zheng Date: Mon, 15 Jun 2009 20:01:02 -0400 Subject: Btrfs: always update root items for fs trees at commit time commit_fs_roots skips updating root items for fs trees that aren't modified. This is unsafe now that relocation code modifies root item's last_snapshot field without modifying corresponding fs tree. Signed-off-by: Yan Zheng Signed-off-by: Chris Mason diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 2e177d7..4e83457 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -543,13 +543,13 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, btrfs_free_log(trans, root); btrfs_update_reloc_root(trans, root); - if (root->commit_root == root->node) - continue; - - free_extent_buffer(root->commit_root); - root->commit_root = btrfs_root_node(root); + if (root->commit_root != root->node) { + free_extent_buffer(root->commit_root); + root->commit_root = btrfs_root_node(root); + btrfs_set_root_node(&root->root_item, + root->node); + } - btrfs_set_root_node(&root->root_item, root->node); err = btrfs_update_root(trans, fs_info->tree_root, &root->root_key, &root->root_item); -- cgit v0.10.2 From 81be834713a7d6b9463663145d493fe9daee2d61 Mon Sep 17 00:00:00 2001 From: Gui Jianfeng Date: Fri, 12 Jun 2009 15:27:50 +0200 Subject: cfq: cleanup for last_end_request in cfq_data Actually, last_end_request in cfq_data isn't used now. So lets just remove it. Signed-off-by: Gui Jianfeng Signed-off-by: Jens Axboe diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index ef2f72d..8447fde 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -122,7 +122,6 @@ struct cfq_data { struct cfq_queue *async_idle_cfqq; sector_t last_position; - unsigned long last_end_request; /* * tunables, see top of file @@ -2164,9 +2163,6 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) if (cfq_cfqq_sync(cfqq)) cfqd->sync_flight--; - if (!cfq_class_idle(cfqq)) - cfqd->last_end_request = now; - if (sync) RQ_CIC(rq)->last_end_request = now; @@ -2479,7 +2475,6 @@ static void *cfq_init_queue(struct request_queue *q) INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); - cfqd->last_end_request = jiffies; cfqd->cfq_quantum = cfq_quantum; cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1]; -- cgit v0.10.2 From 0989a025d2f4f9f51ea641bd26c563c53dc63f55 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Jun 2009 14:42:56 +0200 Subject: block: don't overwrite bdi->state after bdi_init() has been run Move the defaults to where we do the init of the backing_dev_info. Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index f6452f6..94d88fa 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -498,6 +498,11 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug; q->backing_dev_info.unplug_io_data = q; + q->backing_dev_info.ra_pages = + (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; + q->backing_dev_info.state = 0; + q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; + err = bdi_init(&q->backing_dev_info); if (err) { kmem_cache_free(blk_requestq_cachep, q); diff --git a/block/blk-settings.c b/block/blk-settings.c index d71cedc..138610b 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -129,10 +129,6 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE); q->make_request_fn = mfn; - q->backing_dev_info.ra_pages = - (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; - q->backing_dev_info.state = 0; - q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; blk_queue_max_sectors(q, SAFE_MAX_SECTORS); blk_queue_logical_block_size(q, 512); blk_queue_dma_alignment(q, 511); -- cgit v0.10.2 From ad081f1430515d0b727eba99ec435a526c61a599 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Jun 2009 14:43:40 +0200 Subject: btrfs: properly register fs backing device btrfs assigns this bdi to all inodes on that file system, so make sure it's registered. This isn't really important now, but will be when we put dirty inodes there. Even now, we miss the stats when the bdi isn't visible. Also fixes failure to check bdi_init() return value, and bad inherit of ->capabilities flags from the default bdi. Acked-by: Chris Mason Signed-off-by: Jens Axboe diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0d50d49..d28d29c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -42,6 +42,8 @@ static struct extent_io_ops btree_extent_io_ops; static void end_workqueue_fn(struct btrfs_work *work); +static atomic_t btrfs_bdi_num = ATOMIC_INIT(0); + /* * end_io_wq structs are used to do processing in task context when an IO is * complete. This is used during reads to verify checksums, and it is used @@ -1342,12 +1344,25 @@ static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) free_extent_map(em); } +/* + * If this fails, caller must call bdi_destroy() to get rid of the + * bdi again. + */ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) { - bdi_init(bdi); + int err; + + bdi->capabilities = BDI_CAP_MAP_COPY; + err = bdi_init(bdi); + if (err) + return err; + + err = bdi_register(bdi, NULL, "btrfs-%d", + atomic_inc_return(&btrfs_bdi_num)); + if (err) + return err; + bdi->ra_pages = default_backing_dev_info.ra_pages; - bdi->state = 0; - bdi->capabilities = default_backing_dev_info.capabilities; bdi->unplug_io_fn = btrfs_unplug_io_fn; bdi->unplug_io_data = info; bdi->congested_fn = btrfs_congested_fn; @@ -1569,7 +1584,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, fs_info->sb = sb; fs_info->max_extent = (u64)-1; fs_info->max_inline = 8192 * 1024; - setup_bdi(fs_info, &fs_info->bdi); + if (setup_bdi(fs_info, &fs_info->bdi)) + goto fail_bdi; fs_info->btree_inode = new_inode(sb); fs_info->btree_inode->i_ino = 1; fs_info->btree_inode->i_nlink = 1; @@ -1946,8 +1962,8 @@ fail_iput: btrfs_close_devices(fs_info->fs_devices); btrfs_mapping_tree_free(&fs_info->mapping_tree); +fail_bdi: bdi_destroy(&fs_info->bdi); - fail: kfree(extent_root); kfree(tree_root); -- cgit v0.10.2 From a979eff1811a07f5fd331c5f6f727370747b42ad Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 29 May 2009 09:19:23 +0200 Subject: ubifs: register backing_dev_info Signed-off-by: Jens Axboe diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 3589eab..3260b73 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1937,6 +1937,9 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) err = bdi_init(&c->bdi); if (err) goto out_close; + err = bdi_register(&c->bdi, NULL, "ubifs"); + if (err) + goto out_bdi; err = ubifs_parse_options(c, data, 0); if (err) -- cgit v0.10.2 From 6923715ae39ed39ac2fc1993e5061668f4f71ad0 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Fri, 12 Jun 2009 15:29:30 +0200 Subject: cfq: remove extraneous '\n' in blktrace output I noticed a blank line in blktrace output. This patch fixes that. Signed-off-by: Jeff Moyer Signed-off-by: Jens Axboe diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 8447fde..833ec18 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1252,7 +1252,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) BUG_ON(cfqd->busy_queues); - cfq_log(cfqd, "forced_dispatch=%d\n", dispatched); + cfq_log(cfqd, "forced_dispatch=%d", dispatched); return dispatched; } -- cgit v0.10.2 From e475bba2fdee9c3dbfe25f026f8fb8de69508ad2 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 16 Jun 2009 08:23:52 +0200 Subject: block: Introduce helper to reset queue limits to default values DM reuses the request queue when swapping in a new device table Introduce blk_set_default_limits() which can be used to reset the the queue_limits prior to stacking devices. Signed-off-by: Martin K. Petersen Acked-by: Alasdair G Kergon Acked-by: Mike Snitzer Signed-off-by: Jens Axboe diff --git a/block/blk-settings.c b/block/blk-settings.c index 138610b..7541ea4 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -96,6 +96,31 @@ void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn) EXPORT_SYMBOL_GPL(blk_queue_lld_busy); /** + * blk_set_default_limits - reset limits to default values + * @limits: the queue_limits structure to reset + * + * Description: + * Returns a queue_limit struct to its default state. Can be used by + * stacking drivers like DM that stage table swaps and reuse an + * existing device queue. + */ +void blk_set_default_limits(struct queue_limits *lim) +{ + lim->max_phys_segments = MAX_PHYS_SEGMENTS; + lim->max_hw_segments = MAX_HW_SEGMENTS; + lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; + lim->max_segment_size = MAX_SEGMENT_SIZE; + lim->max_sectors = lim->max_hw_sectors = SAFE_MAX_SECTORS; + lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; + lim->bounce_pfn = BLK_BOUNCE_ANY; + lim->alignment_offset = 0; + lim->io_opt = 0; + lim->misaligned = 0; + lim->no_cluster = 0; +} +EXPORT_SYMBOL(blk_set_default_limits); + +/** * blk_queue_make_request - define an alternate make_request function for a device * @q: the request queue for the device to be affected * @mfn: the alternate make_request function @@ -123,14 +148,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) * set defaults */ q->nr_requests = BLKDEV_MAX_RQ; - blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); - blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS); - blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK); - blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE); q->make_request_fn = mfn; - blk_queue_max_sectors(q, SAFE_MAX_SECTORS); - blk_queue_logical_block_size(q, 512); blk_queue_dma_alignment(q, 511); blk_queue_congestion_threshold(q); q->nr_batching = BLK_BATCH_REQ; @@ -143,6 +162,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) q->unplug_timer.function = blk_unplug_timeout; q->unplug_timer.data = (unsigned long)q; + blk_set_default_limits(&q->limits); + /* * by default assume old behaviour and bounce for any highmem page */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0b1a6ca..8963d91 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -926,6 +926,7 @@ extern void blk_queue_alignment_offset(struct request_queue *q, unsigned int alignment); extern void blk_queue_io_min(struct request_queue *q, unsigned int min); extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt); +extern void blk_set_default_limits(struct queue_limits *lim); extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, sector_t offset); extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, -- cgit v0.10.2 From 5ced504b1bd1979378de35c56aa5d3d79fb5033f Mon Sep 17 00:00:00 2001 From: unsik Kim Date: Tue, 16 Jun 2009 08:40:20 +0200 Subject: mg_disk: seperate mg_disk.h again eec9462088a26c046d4db3100796a340a50890b8 fold mg_disk.h into mg_disk.c, but mg_disk platform driver needs private data for operation. This also make mg_disk.c as machine independent. Seperate only needed structure and defines to mg_disk.h Signed-off-by: unsik Kim Signed-off-by: Jens Axboe diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 60de5a0..f703f54 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -22,13 +22,12 @@ #include #include #include +#include #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1) /* name for block device */ #define MG_DISK_NAME "mgd" -/* name for platform device */ -#define MG_DEV_NAME "mg_disk" #define MG_DISK_MAJ 0 #define MG_DISK_MAX_PART 16 @@ -103,33 +102,8 @@ #define MG_TMAX_SWRST_TO_RDY 500 #define MG_TMAX_RSTOUT 3000 -/* device attribution */ -/* use mflash as boot device */ -#define MG_BOOT_DEV (1 << 0) -/* use mflash as storage device */ -#define MG_STORAGE_DEV (1 << 1) -/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */ -#define MG_STORAGE_DEV_SKIP_RST (1 << 2) - #define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST) -/* names of GPIO resource */ -#define MG_RST_PIN "mg_rst" -/* except MG_BOOT_DEV, reset-out pin should be assigned */ -#define MG_RSTOUT_PIN "mg_rstout" - -/* private driver data */ -struct mg_drv_data { - /* disk resource */ - u32 use_polling; - - /* device attribution */ - u32 dev_attr; - - /* internally used */ - struct mg_host *host; -}; - /* main structure for mflash driver */ struct mg_host { struct device *dev; diff --git a/include/linux/mg_disk.h b/include/linux/mg_disk.h new file mode 100644 index 0000000..e11f4d9 --- /dev/null +++ b/include/linux/mg_disk.h @@ -0,0 +1,45 @@ +/* + * include/linux/mg_disk.c + * + * Private data for mflash platform driver + * + * (c) 2008 mGine Co.,LTD + * (c) 2008 unsik Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __MG_DISK_H__ +#define __MG_DISK_H__ + +/* name for platform device */ +#define MG_DEV_NAME "mg_disk" + +/* names of GPIO resource */ +#define MG_RST_PIN "mg_rst" +/* except MG_BOOT_DEV, reset-out pin should be assigned */ +#define MG_RSTOUT_PIN "mg_rstout" + +/* device attribution */ +/* use mflash as boot device */ +#define MG_BOOT_DEV (1 << 0) +/* use mflash as storage device */ +#define MG_STORAGE_DEV (1 << 1) +/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */ +#define MG_STORAGE_DEV_SKIP_RST (1 << 2) + +/* private driver data */ +struct mg_drv_data { + /* disk resource */ + u32 use_polling; + + /* device attribution */ + u32 dev_attr; + + /* internally used */ + void *host; +}; + +#endif -- cgit v0.10.2 From 823d494ac11111064cf39abd4178ce299414c771 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 16 Jun 2009 10:30:20 +0200 Subject: [S390] pm: ccw bus power management callbacks Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index ba007d8..18f0a75 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -1,11 +1,9 @@ /* - * include/asm-s390/ccwdev.h - * include/asm-s390x/ccwdev.h + * Copyright IBM Corp. 2002, 2009 * - * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Arnd Bergmann + * Author(s): Arnd Bergmann * - * Interface for CCW device drivers + * Interface for CCW device drivers */ #ifndef _S390_CCWDEV_H_ #define _S390_CCWDEV_H_ @@ -104,6 +102,11 @@ struct ccw_device { * @set_offline: called when setting device offline * @notify: notify driver of device state changes * @shutdown: called at device shutdown + * @prepare: prepare for pm state transition + * @complete: undo work done in @prepare + * @freeze: callback for freezing during hibernation snapshotting + * @thaw: undo work done in @freeze + * @restore: callback for restoring after hibernation * @driver: embedded device driver structure * @name: device driver name */ @@ -116,6 +119,11 @@ struct ccw_driver { int (*set_offline) (struct ccw_device *); int (*notify) (struct ccw_device *, int); void (*shutdown) (struct ccw_device *); + int (*prepare) (struct ccw_device *); + void (*complete) (struct ccw_device *); + int (*freeze)(struct ccw_device *); + int (*thaw) (struct ccw_device *); + int (*restore)(struct ccw_device *); struct device_driver driver; char *name; }; diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index dc98b2c..30f5161 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev, DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); +int ccw_set_cmf(struct ccw_device *cdev, int enable) +{ + return cmbops->set(cdev, enable ? 2 : 0); +} + /** * enable_cmf() - switch on the channel measurement for a specific device * @cdev: The ccw device to be enabled diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 35441fa..228a6c3 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1895,6 +1895,242 @@ static void ccw_device_shutdown(struct device *dev) disable_cmf(cdev); } +static int ccw_device_pm_prepare(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + + if (work_pending(&cdev->private->kick_work)) + return -EAGAIN; + /* Fail while device is being set online/offline. */ + if (atomic_read(&cdev->private->onoff)) + return -EAGAIN; + + if (cdev->online && cdev->drv && cdev->drv->prepare) + return cdev->drv->prepare(cdev); + + return 0; +} + +static void ccw_device_pm_complete(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + + if (cdev->online && cdev->drv && cdev->drv->complete) + cdev->drv->complete(cdev); +} + +static int ccw_device_pm_freeze(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret, cm_enabled; + + /* Fail suspend while device is in transistional state. */ + if (!dev_fsm_final_state(cdev)) + return -EAGAIN; + if (!cdev->online) + return 0; + if (cdev->drv && cdev->drv->freeze) { + ret = cdev->drv->freeze(cdev); + if (ret) + return ret; + } + + spin_lock_irq(sch->lock); + cm_enabled = cdev->private->cmb != NULL; + spin_unlock_irq(sch->lock); + if (cm_enabled) { + /* Don't have the css write on memory. */ + ret = ccw_set_cmf(cdev, 0); + if (ret) + return ret; + } + /* From here on, disallow device driver I/O. */ + spin_lock_irq(sch->lock); + ret = cio_disable_subchannel(sch); + spin_unlock_irq(sch->lock); + + return ret; +} + +static int ccw_device_pm_thaw(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret, cm_enabled; + + if (!cdev->online) + return 0; + + spin_lock_irq(sch->lock); + /* Allow device driver I/O again. */ + ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); + cm_enabled = cdev->private->cmb != NULL; + spin_unlock_irq(sch->lock); + if (ret) + return ret; + + if (cm_enabled) { + ret = ccw_set_cmf(cdev, 1); + if (ret) + return ret; + } + + if (cdev->drv && cdev->drv->thaw) + ret = cdev->drv->thaw(cdev); + + return ret; +} + +static void __ccw_device_pm_restore(struct ccw_device *cdev) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret; + + if (cio_is_console(sch->schid)) + goto out; + /* + * While we were sleeping, devices may have gone or become + * available again. Kick re-detection. + */ + spin_lock_irq(sch->lock); + cdev->private->flags.resuming = 1; + ret = ccw_device_recognition(cdev); + spin_unlock_irq(sch->lock); + if (ret) { + CIO_MSG_EVENT(0, "Couldn't start recognition for device " + "%s (ret=%d)\n", dev_name(&cdev->dev), ret); + spin_lock_irq(sch->lock); + cdev->private->state = DEV_STATE_DISCONNECTED; + spin_unlock_irq(sch->lock); + /* notify driver after the resume cb */ + goto out; + } + wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED); + +out: + cdev->private->flags.resuming = 0; +} + +static int resume_handle_boxed(struct ccw_device *cdev) +{ + cdev->private->state = DEV_STATE_BOXED; + if (ccw_device_notify(cdev, CIO_BOXED)) + return 0; + ccw_device_schedule_sch_unregister(cdev); + return -ENODEV; +} + +static int resume_handle_disc(struct ccw_device *cdev) +{ + cdev->private->state = DEV_STATE_DISCONNECTED; + if (ccw_device_notify(cdev, CIO_GONE)) + return 0; + ccw_device_schedule_sch_unregister(cdev); + return -ENODEV; +} + +static int ccw_device_pm_restore(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret = 0, cm_enabled; + + __ccw_device_pm_restore(cdev); + spin_lock_irq(sch->lock); + if (cio_is_console(sch->schid)) { + cio_enable_subchannel(sch, (u32)(addr_t)sch); + spin_unlock_irq(sch->lock); + goto out_restore; + } + cdev->private->flags.donotify = 0; + /* check recognition results */ + switch (cdev->private->state) { + case DEV_STATE_OFFLINE: + break; + case DEV_STATE_BOXED: + ret = resume_handle_boxed(cdev); + spin_unlock_irq(sch->lock); + if (ret) + goto out; + goto out_restore; + case DEV_STATE_DISCONNECTED: + goto out_disc_unlock; + default: + goto out_unreg_unlock; + } + /* check if the device id has changed */ + if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { + CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " + "%04x to %04x)\n", dev_name(&sch->dev), + cdev->private->dev_id.devno, + sch->schib.pmcw.dev); + goto out_unreg_unlock; + } + /* check if the device type has changed */ + if (!ccw_device_test_sense_data(cdev)) { + ccw_device_update_sense_data(cdev); + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_do_unbind_bind); + queue_work(ccw_device_work, &cdev->private->kick_work); + ret = -ENODEV; + goto out_unlock; + } + if (!cdev->online) { + ret = 0; + goto out_unlock; + } + ret = ccw_device_online(cdev); + if (ret) + goto out_disc_unlock; + + cm_enabled = cdev->private->cmb != NULL; + spin_unlock_irq(sch->lock); + + wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + if (cdev->private->state != DEV_STATE_ONLINE) { + spin_lock_irq(sch->lock); + goto out_disc_unlock; + } + if (cm_enabled) { + ret = ccw_set_cmf(cdev, 1); + if (ret) { + CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " + "(rc=%d)\n", dev_name(&cdev->dev), ret); + ret = 0; + } + } + +out_restore: + if (cdev->online && cdev->drv && cdev->drv->restore) + ret = cdev->drv->restore(cdev); +out: + return ret; + +out_disc_unlock: + ret = resume_handle_disc(cdev); + spin_unlock_irq(sch->lock); + if (ret) + return ret; + goto out_restore; + +out_unreg_unlock: + ccw_device_schedule_sch_unregister(cdev); + ret = -ENODEV; +out_unlock: + spin_unlock_irq(sch->lock); + return ret; +} + +static struct dev_pm_ops ccw_pm_ops = { + .prepare = ccw_device_pm_prepare, + .complete = ccw_device_pm_complete, + .freeze = ccw_device_pm_freeze, + .thaw = ccw_device_pm_thaw, + .restore = ccw_device_pm_restore, +}; + struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, @@ -1902,6 +2138,7 @@ struct bus_type ccw_bus_type = { .probe = ccw_device_probe, .remove = ccw_device_remove, .shutdown = ccw_device_shutdown, + .pm = &ccw_pm_ops, }; /** diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index f1cbbd9..e397510 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *); int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); +void ccw_device_update_sense_data(struct ccw_device *); +int ccw_device_test_sense_data(struct ccw_device *); void ccw_device_schedule_sch_unregister(struct ccw_device *); int ccw_purge_blacklisted(void); @@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type; void retry_set_schib(struct ccw_device *cdev); void cmf_retry_copy_block(struct ccw_device *); int cmf_reenable(struct ccw_device *); +int ccw_set_cmf(struct ccw_device *cdev, int enable); extern struct device_attribute dev_attr_cmb_enable; #endif diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index e460492..3db88c5 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) panic("Can't stop i/o on subchannel.\n"); } -static int -ccw_device_handle_oper(struct ccw_device *cdev) +void ccw_device_update_sense_data(struct ccw_device *cdev) { - struct subchannel *sch; + memset(&cdev->id, 0, sizeof(cdev->id)); + cdev->id.cu_type = cdev->private->senseid.cu_type; + cdev->id.cu_model = cdev->private->senseid.cu_model; + cdev->id.dev_type = cdev->private->senseid.dev_type; + cdev->id.dev_model = cdev->private->senseid.dev_model; +} - sch = to_subchannel(cdev->dev.parent); - cdev->private->flags.recog_done = 1; - /* - * Check if cu type and device type still match. If - * not, it is certainly another device and we have to - * de- and re-register. - */ - if (cdev->id.cu_type != cdev->private->senseid.cu_type || - cdev->id.cu_model != cdev->private->senseid.cu_model || - cdev->id.dev_type != cdev->private->senseid.dev_type || - cdev->id.dev_model != cdev->private->senseid.dev_model) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_do_unbind_bind); - queue_work(ccw_device_work, &cdev->private->kick_work); - return 0; - } - cdev->private->flags.donotify = 1; - return 1; +int ccw_device_test_sense_data(struct ccw_device *cdev) +{ + return cdev->id.cu_type == cdev->private->senseid.cu_type && + cdev->id.cu_model == cdev->private->senseid.cu_model && + cdev->id.dev_type == cdev->private->senseid.dev_type && + cdev->id.dev_model == cdev->private->senseid.dev_model; } /* @@ -233,7 +225,7 @@ static void ccw_device_recog_done(struct ccw_device *cdev, int state) { struct subchannel *sch; - int notify, old_lpm, same_dev; + int old_lpm; sch = to_subchannel(cdev->dev.parent); @@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) wake_up(&cdev->private->wait_q); return; } - notify = 0; - same_dev = 0; /* Keep the compiler quiet... */ + if (cdev->private->flags.resuming) { + cdev->private->state = state; + cdev->private->flags.recog_done = 1; + wake_up(&cdev->private->wait_q); + return; + } switch (state) { case DEV_STATE_NOT_OPER: CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " @@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) sch->schid.ssid, sch->schid.sch_no); break; case DEV_STATE_OFFLINE: - if (cdev->online) { - same_dev = ccw_device_handle_oper(cdev); - notify = 1; + if (!cdev->online) { + ccw_device_update_sense_data(cdev); + /* Issue device info message. */ + CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " + "CU Type/Mod = %04X/%02X, Dev Type/Mod " + "= %04X/%02X\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, + cdev->id.cu_type, cdev->id.cu_model, + cdev->id.dev_type, cdev->id.dev_model); + break; } - /* fill out sense information */ - memset(&cdev->id, 0, sizeof(cdev->id)); - cdev->id.cu_type = cdev->private->senseid.cu_type; - cdev->id.cu_model = cdev->private->senseid.cu_model; - cdev->id.dev_type = cdev->private->senseid.dev_type; - cdev->id.dev_model = cdev->private->senseid.dev_model; - if (notify) { - cdev->private->state = DEV_STATE_OFFLINE; - if (same_dev) { - /* Get device online again. */ - ccw_device_online(cdev); - wake_up(&cdev->private->wait_q); - } - return; + cdev->private->state = DEV_STATE_OFFLINE; + cdev->private->flags.recog_done = 1; + if (ccw_device_test_sense_data(cdev)) { + cdev->private->flags.donotify = 1; + ccw_device_online(cdev); + wake_up(&cdev->private->wait_q); + } else { + ccw_device_update_sense_data(cdev); + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_do_unbind_bind); + queue_work(ccw_device_work, &cdev->private->kick_work); } - /* Issue device info message. */ - CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " - "CU Type/Mod = %04X/%02X, Dev Type/Mod = " - "%04X/%02X\n", - cdev->private->dev_id.ssid, - cdev->private->dev_id.devno, - cdev->id.cu_type, cdev->id.cu_model, - cdev->id.dev_type, cdev->id.dev_model); - break; + return; case DEV_STATE_BOXED: CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " " subchannel 0.%x.%04x\n", @@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev) struct subchannel *sch; int ret; - if ((cdev->private->state != DEV_STATE_NOT_OPER) && - (cdev->private->state != DEV_STATE_BOXED)) - return -EINVAL; sch = to_subchannel(cdev->dev.parent); ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); if (ret != 0) diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index bf0a24a..2d0efee 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -1,10 +1,8 @@ /* - * drivers/s390/cio/device_ops.c + * Copyright IBM Corp. 2002, 2009 * - * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * Cornelia Huck (cornelia.huck@de.ibm.com) */ #include #include @@ -116,12 +114,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) if (!cdev || !cdev->dev.parent) return -ENODEV; + sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; - sch = to_subchannel(cdev->dev.parent); + ret = cio_clear(sch); if (ret == 0) cdev->private->intparm = intparm; @@ -162,6 +163,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, if (!cdev || !cdev->dev.parent) return -ENODEV; sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state == DEV_STATE_VERIFY || @@ -337,12 +340,15 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) if (!cdev || !cdev->dev.parent) return -ENODEV; + sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; - sch = to_subchannel(cdev->dev.parent); + ret = cio_halt(sch); if (ret == 0) cdev->private->intparm = intparm; @@ -369,6 +375,8 @@ int ccw_device_resume(struct ccw_device *cdev) if (!cdev || !cdev->dev.parent) return -ENODEV; sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE || @@ -580,6 +588,8 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, int rc; sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state != DEV_STATE_ONLINE) return -EIO; /* Adjust requested path mask to excluded varied off paths. */ @@ -669,6 +679,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state != DEV_STATE_ONLINE) return -EIO; if (!scsw_is_tm(&sch->schib.scsw) || diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index c4f3e7c..0b8f381 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -107,6 +107,7 @@ struct ccw_device_private { unsigned int recog_done:1; /* dev. recog. complete */ unsigned int fake_irb:1; /* deliver faked irb */ unsigned int intretry:1; /* retry internal operation */ + unsigned int resuming:1; /* recognition while resume */ } __attribute__((packed)) flags; unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; -- cgit v0.10.2 From 7e597a21a1470b12428cb0edd03c40986026451f Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 16 Jun 2009 10:30:21 +0200 Subject: [S390] pm: ccwgroup bus power management callbacks Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h index a27f689..c79c1e7 100644 --- a/arch/s390/include/asm/ccwgroup.h +++ b/arch/s390/include/asm/ccwgroup.h @@ -38,6 +38,11 @@ struct ccwgroup_device { * @set_online: function called when device is set online * @set_offline: function called when device is set offline * @shutdown: function called when device is shut down + * @prepare: prepare for pm state transition + * @complete: undo work done in @prepare + * @freeze: callback for freezing during hibernation snapshotting + * @thaw: undo work done in @freeze + * @restore: callback for restoring after hibernation * @driver: embedded driver structure */ struct ccwgroup_driver { @@ -51,6 +56,11 @@ struct ccwgroup_driver { int (*set_online) (struct ccwgroup_device *); int (*set_offline) (struct ccwgroup_device *); void (*shutdown)(struct ccwgroup_device *); + int (*prepare) (struct ccwgroup_device *); + void (*complete) (struct ccwgroup_device *); + int (*freeze)(struct ccwgroup_device *); + int (*thaw) (struct ccwgroup_device *); + int (*restore)(struct ccwgroup_device *); struct device_driver driver; }; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 22ce765..a5a62f1 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -1,11 +1,10 @@ /* - * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup * - * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Arnd Bergmann (arndb@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) + * Copyright IBM Corp. 2002, 2009 + * + * Author(s): Arnd Bergmann (arndb@de.ibm.com) + * Cornelia Huck (cornelia.huck@de.ibm.com) */ #include #include @@ -501,6 +500,74 @@ static void ccwgroup_shutdown(struct device *dev) gdrv->shutdown(gdev); } +static int ccwgroup_pm_prepare(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + /* Fail while device is being set online/offline. */ + if (atomic_read(&gdev->onoff)) + return -EAGAIN; + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->prepare ? gdrv->prepare(gdev) : 0; +} + +static void ccwgroup_pm_complete(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return; + + if (gdrv->complete) + gdrv->complete(gdev); +} + +static int ccwgroup_pm_freeze(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->freeze ? gdrv->freeze(gdev) : 0; +} + +static int ccwgroup_pm_thaw(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->thaw ? gdrv->thaw(gdev) : 0; +} + +static int ccwgroup_pm_restore(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->restore ? gdrv->restore(gdev) : 0; +} + +static struct dev_pm_ops ccwgroup_pm_ops = { + .prepare = ccwgroup_pm_prepare, + .complete = ccwgroup_pm_complete, + .freeze = ccwgroup_pm_freeze, + .thaw = ccwgroup_pm_thaw, + .restore = ccwgroup_pm_restore, +}; + static struct bus_type ccwgroup_bus_type = { .name = "ccwgroup", .match = ccwgroup_bus_match, @@ -508,6 +575,7 @@ static struct bus_type ccwgroup_bus_type = { .probe = ccwgroup_probe, .remove = ccwgroup_remove, .shutdown = ccwgroup_shutdown, + .pm = &ccwgroup_pm_ops, }; -- cgit v0.10.2 From dcbd16d5111258df7c821ec1e4124fe6ffbf3c16 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 16 Jun 2009 10:30:22 +0200 Subject: [S390] pm: css bus power management callbacks Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 883f16f..1ecd3e5 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -549,8 +549,7 @@ cleanup: return ret; } -static int -__chsc_do_secm(struct channel_subsystem *css, int enable, void *page) +int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) { struct { struct chsc_header request; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index ba59bce..425e8f8 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void); extern int chsc_enable_facility(int); struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); +int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page); int chsc_chp_vary(struct chp_id chpid, int on); int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0085d89..85d43c6 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1,10 +1,10 @@ /* - * drivers/s390/cio/css.c - * driver for channel subsystem + * driver for channel subsystem * - * Copyright IBM Corp. 2002,2008 - * Author(s): Arnd Bergmann (arndb@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) + * Copyright IBM Corp. 2002, 2009 + * + * Author(s): Arnd Bergmann (arndb@de.ibm.com) + * Cornelia Huck (cornelia.huck@de.ibm.com) */ #define KMSG_COMPONENT "cio" @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -780,6 +781,79 @@ static struct notifier_block css_reboot_notifier = { }; /* + * Since the css devices are neither on a bus nor have a class + * nor have a special device type, we cannot stop/restart channel + * path measurements via the normal suspend/resume callbacks, but have + * to use notifiers. + */ +static int css_power_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + void *secm_area; + int ret, i; + + switch (event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + mutex_lock(&css->mutex); + if (!css->cm_enabled) { + mutex_unlock(&css->mutex); + continue; + } + secm_area = (void *)get_zeroed_page(GFP_KERNEL | + GFP_DMA); + if (secm_area) { + if (__chsc_do_secm(css, 0, secm_area)) + ret = NOTIFY_BAD; + free_page((unsigned long)secm_area); + } else + ret = NOTIFY_BAD; + + mutex_unlock(&css->mutex); + } + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + mutex_lock(&css->mutex); + if (!css->cm_enabled) { + mutex_unlock(&css->mutex); + continue; + } + secm_area = (void *)get_zeroed_page(GFP_KERNEL | + GFP_DMA); + if (secm_area) { + if (__chsc_do_secm(css, 1, secm_area)) + ret = NOTIFY_BAD; + free_page((unsigned long)secm_area); + } else + ret = NOTIFY_BAD; + + mutex_unlock(&css->mutex); + } + /* search for subchannels, which appeared during hibernation */ + css_schedule_reprobe(); + break; + default: + ret = NOTIFY_DONE; + } + return ret; + +} +static struct notifier_block css_power_notifier = { + .notifier_call = css_power_event, +}; + +/* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the * static console subchannel). @@ -852,6 +926,11 @@ init_channel_subsystem (void) ret = register_reboot_notifier(&css_reboot_notifier); if (ret) goto out_unregister; + ret = register_pm_notifier(&css_power_notifier); + if (ret) { + unregister_reboot_notifier(&css_reboot_notifier); + goto out_unregister; + } css_init_done = 1; /* Enable default isc for I/O subchannels. */ @@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } +static int css_pm_prepare(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (mutex_is_locked(&sch->reg_mutex)) + return -EAGAIN; + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + /* Notify drivers that they may not register children. */ + return drv->prepare ? drv->prepare(sch) : 0; +} + +static void css_pm_complete(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return; + drv = to_cssdriver(sch->dev.driver); + if (drv->complete) + drv->complete(sch); +} + +static int css_pm_freeze(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + return drv->freeze ? drv->freeze(sch) : 0; +} + +static int css_pm_thaw(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + return drv->thaw ? drv->thaw(sch) : 0; +} + +static int css_pm_restore(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + return drv->restore ? drv->restore(sch) : 0; +} + +static struct dev_pm_ops css_pm_ops = { + .prepare = css_pm_prepare, + .complete = css_pm_complete, + .freeze = css_pm_freeze, + .thaw = css_pm_thaw, + .restore = css_pm_restore, +}; + struct bus_type css_bus_type = { .name = "css", .match = css_bus_match, @@ -960,6 +1106,7 @@ struct bus_type css_bus_type = { .remove = css_remove, .shutdown = css_shutdown, .uevent = css_uevent, + .pm = &css_pm_ops, }; /** diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 57ebf12..9763eee 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -70,6 +70,11 @@ struct chp_link; * @probe: function called on probe * @remove: function called on remove * @shutdown: called at device shutdown + * @prepare: prepare for pm state transition + * @complete: undo work done in @prepare + * @freeze: callback for freezing during hibernation snapshotting + * @thaw: undo work done in @freeze + * @restore: callback for restoring after hibernation * @name: name of the device driver */ struct css_driver { @@ -82,6 +87,11 @@ struct css_driver { int (*probe)(struct subchannel *); int (*remove)(struct subchannel *); void (*shutdown)(struct subchannel *); + int (*prepare) (struct subchannel *); + void (*complete) (struct subchannel *); + int (*freeze)(struct subchannel *); + int (*thaw) (struct subchannel *); + int (*restore)(struct subchannel *); const char *name; }; -- cgit v0.10.2 From 93a275921daf83e6e4efbafdd82712bcaa93f491 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 16 Jun 2009 10:30:23 +0200 Subject: [S390] pm: io subchannel driver power management callbacks Signed-off-by: Cornelia Huck Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 228a6c3..64bd79a 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -138,6 +138,19 @@ static struct css_device_id io_subchannel_ids[] = { }; MODULE_DEVICE_TABLE(css, io_subchannel_ids); +static int io_subchannel_prepare(struct subchannel *sch) +{ + struct ccw_device *cdev; + /* + * Don't allow suspend while a ccw device registration + * is still outstanding. + */ + cdev = sch_get_cdev(sch); + if (cdev && !device_is_registered(&cdev->dev)) + return -EAGAIN; + return 0; +} + static struct css_driver io_subchannel_driver = { .owner = THIS_MODULE, .subchannel_type = io_subchannel_ids, @@ -148,6 +161,7 @@ static struct css_driver io_subchannel_driver = { .probe = io_subchannel_probe, .remove = io_subchannel_remove, .shutdown = io_subchannel_shutdown, + .prepare = io_subchannel_prepare, }; struct workqueue_struct *ccw_device_work; -- cgit v0.10.2 From ad285ae9fc6b9c0058f2a558b43fe8817685ebfa Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 16 Jun 2009 10:30:24 +0200 Subject: [S390] pm: chsc subchannel driver power management callbacks Signed-off-by: Cornelia Huck Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 93eca17..cc5144b 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -1,7 +1,8 @@ /* * Driver for s390 chsc subchannels * - * Copyright IBM Corp. 2008 + * Copyright IBM Corp. 2008, 2009 + * * Author(s): Cornelia Huck * */ @@ -112,6 +113,31 @@ static void chsc_subchannel_shutdown(struct subchannel *sch) cio_disable_subchannel(sch); } +static int chsc_subchannel_prepare(struct subchannel *sch) +{ + int cc; + struct schib schib; + /* + * Don't allow suspend while the subchannel is not idle + * since we don't have a way to clear the subchannel and + * cannot disable it with a request running. + */ + cc = stsch(sch->schid, &schib); + if (!cc && scsw_stctl(&schib.scsw)) + return -EAGAIN; + return 0; +} + +static int chsc_subchannel_freeze(struct subchannel *sch) +{ + return cio_disable_subchannel(sch); +} + +static int chsc_subchannel_restore(struct subchannel *sch) +{ + return cio_enable_subchannel(sch, (u32)(unsigned long)sch); +} + static struct css_device_id chsc_subchannel_ids[] = { { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, { /* end of list */ }, @@ -125,6 +151,10 @@ static struct css_driver chsc_subchannel_driver = { .probe = chsc_subchannel_probe, .remove = chsc_subchannel_remove, .shutdown = chsc_subchannel_shutdown, + .prepare = chsc_subchannel_prepare, + .freeze = chsc_subchannel_freeze, + .thaw = chsc_subchannel_restore, + .restore = chsc_subchannel_restore, .name = "chsc_subchannel", }; -- cgit v0.10.2 From d41dd122acf960db78c9ddc87684b43751dd36d9 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Tue, 16 Jun 2009 10:30:25 +0200 Subject: [S390] pm: dasd power management callbacks. Introduce the power management callbacks to the dasd driver. On suspend the dasd devices are stopped and removed from the focus of alias management. On resume they are reinitialized by rereading the device characteristics and adding the device to the alias management. In case the device has gone away during suspend it will caught in the suspend state with stopped flag set to UNRESUMED. After it appears again the restore function is called again. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 442bb98..e5b84db 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -5,8 +5,7 @@ * Carsten Otte * Martin Schwidefsky * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 - * + * Copyright IBM Corp. 1999, 2009 */ #define KMSG_COMPONENT "dasd" @@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *); static void dasd_device_tasklet(struct dasd_device *); static void dasd_block_tasklet(struct dasd_block *); static void do_kick_device(struct work_struct *); +static void do_restore_device(struct work_struct *); static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); static void dasd_device_timeout(unsigned long); static void dasd_block_timeout(unsigned long); @@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void) device->timer.function = dasd_device_timeout; device->timer.data = (unsigned long) device; INIT_WORK(&device->kick_work, do_kick_device); + INIT_WORK(&device->restore_device, do_restore_device); device->state = DASD_STATE_NEW; device->target = DASD_STATE_NEW; @@ -512,6 +513,25 @@ void dasd_kick_device(struct dasd_device *device) } /* + * dasd_restore_device will schedule a call do do_restore_device to the kernel + * event daemon. + */ +static void do_restore_device(struct work_struct *work) +{ + struct dasd_device *device = container_of(work, struct dasd_device, + restore_device); + device->cdev->drv->restore(device->cdev); + dasd_put_device(device); +} + +void dasd_restore_device(struct dasd_device *device) +{ + dasd_get_device(device); + /* queue call to dasd_restore_device to the kernel event daemon. */ + schedule_work(&device->restore_device); +} + +/* * Set the target state for a device and starts the state change. */ void dasd_set_target_state(struct dasd_device *device, int target) @@ -908,6 +928,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) DBF_DEV_EVENT(DBF_DEBUG, device, "%s", "start_IO: -EIO device gone, retry"); break; + case -EINVAL: + /* most likely caused in power management context */ + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + "start_IO: -EINVAL device currently " + "not accessible"); + break; default: /* internal error 11 - unknown rc */ snprintf(errorstring, ERRORLENGTH, "11 %d", rc); @@ -2400,6 +2426,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) case CIO_OPER: /* FIXME: add a sanity check. */ device->stopped &= ~DASD_STOPPED_DC_WAIT; + if (device->stopped & DASD_UNRESUMED_PM) { + device->stopped &= ~DASD_UNRESUMED_PM; + dasd_restore_device(device); + ret = 1; + break; + } dasd_schedule_device_bh(device); if (device->block) dasd_schedule_block_bh(device->block); @@ -2410,6 +2442,79 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) return ret; } +int dasd_generic_pm_freeze(struct ccw_device *cdev) +{ + struct dasd_ccw_req *cqr, *n; + int rc; + struct list_head freeze_queue; + struct dasd_device *device = dasd_device_from_cdev(cdev); + + if (IS_ERR(device)) + return PTR_ERR(device); + /* disallow new I/O */ + device->stopped |= DASD_STOPPED_PM; + /* clear active requests */ + INIT_LIST_HEAD(&freeze_queue); + spin_lock_irq(get_ccwdev_lock(cdev)); + rc = 0; + list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) { + /* Check status and move request to flush_queue */ + if (cqr->status == DASD_CQR_IN_IO) { + rc = device->discipline->term_IO(cqr); + if (rc) { + /* unable to terminate requeust */ + dev_err(&device->cdev->dev, + "Unable to terminate request %p " + "on suspend\n", cqr); + spin_unlock_irq(get_ccwdev_lock(cdev)); + dasd_put_device(device); + return rc; + } + } + list_move_tail(&cqr->devlist, &freeze_queue); + } + + spin_unlock_irq(get_ccwdev_lock(cdev)); + + list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) { + wait_event(dasd_flush_wq, + (cqr->status != DASD_CQR_CLEAR_PENDING)); + if (cqr->status == DASD_CQR_CLEARED) + cqr->status = DASD_CQR_QUEUED; + } + /* move freeze_queue to start of the ccw_queue */ + spin_lock_irq(get_ccwdev_lock(cdev)); + list_splice_tail(&freeze_queue, &device->ccw_queue); + spin_unlock_irq(get_ccwdev_lock(cdev)); + + if (device->discipline->freeze) + rc = device->discipline->freeze(device); + + dasd_put_device(device); + return rc; +} +EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze); + +int dasd_generic_restore_device(struct ccw_device *cdev) +{ + struct dasd_device *device = dasd_device_from_cdev(cdev); + int rc = 0; + + if (IS_ERR(device)) + return PTR_ERR(device); + + dasd_schedule_device_bh(device); + if (device->block) + dasd_schedule_block_bh(device->block); + + if (device->discipline->restore) + rc = device->discipline->restore(device); + + dasd_put_device(device); + return rc; +} +EXPORT_SYMBOL_GPL(dasd_generic_restore_device); + static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, void *rdc_buffer, int rdc_buffer_size, diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index e77666c..4cac5b5 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) spin_unlock(&dasd_devmap_lock); return 0; } +EXPORT_SYMBOL_GPL(dasd_get_uid); /* * Register the given device unique identifier into devmap struct. diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cf0cfdb..1c28ec3 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -5,10 +5,9 @@ * Carsten Otte * Martin Schwidefsky * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * Copyright IBM Corp. 1999, 2009 * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 * Author.........: Nigel Hislop - * */ #define KMSG_COMPONENT "dasd" @@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev) return dasd_generic_set_online(cdev, &dasd_eckd_discipline); } -static struct ccw_driver dasd_eckd_driver = { - .name = "dasd-eckd", - .owner = THIS_MODULE, - .ids = dasd_eckd_ids, - .probe = dasd_eckd_probe, - .remove = dasd_generic_remove, - .set_offline = dasd_generic_set_offline, - .set_online = dasd_eckd_set_online, - .notify = dasd_generic_notify, -}; - static const int sizes_trk0[] = { 28, 148, 84 }; #define LABEL_SIZE 140 @@ -3236,6 +3224,98 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, dasd_eckd_dump_sense_ccw(device, req, irb); } +int dasd_eckd_pm_freeze(struct dasd_device *device) +{ + /* + * the device should be disconnected from our LCU structure + * on restore we will reconnect it and reread LCU specific + * information like PAV support that might have changed + */ + dasd_alias_remove_device(device); + dasd_alias_disconnect_device_from_lcu(device); + + return 0; +} + +int dasd_eckd_restore_device(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + int is_known, rc; + struct dasd_uid temp_uid; + + /* allow new IO again */ + device->stopped &= ~DASD_STOPPED_PM; + + private = (struct dasd_eckd_private *) device->private; + + /* Read Configuration Data */ + rc = dasd_eckd_read_conf(device); + if (rc) + goto out_err; + + /* Generate device unique id and register in devmap */ + rc = dasd_eckd_generate_uid(device, &private->uid); + dasd_get_uid(device->cdev, &temp_uid); + if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) + dev_err(&device->cdev->dev, "The UID of the DASD has changed\n"); + if (rc) + goto out_err; + dasd_set_uid(device->cdev, &private->uid); + + /* register lcu with alias handling, enable PAV if this is a new lcu */ + is_known = dasd_alias_make_device_known_to_lcu(device); + if (is_known < 0) + return is_known; + if (!is_known) { + /* new lcu found */ + rc = dasd_eckd_validate_server(device); /* will switch pav on */ + if (rc) + goto out_err; + } + + /* Read Feature Codes */ + rc = dasd_eckd_read_features(device); + if (rc) + goto out_err; + + /* Read Device Characteristics */ + memset(&private->rdc_data, 0, sizeof(private->rdc_data)); + rc = dasd_generic_read_dev_chars(device, "ECKD", + &private->rdc_data, 64); + if (rc) { + DBF_EVENT(DBF_WARNING, + "Read device characteristics failed, rc=%d for " + "device: %s", rc, dev_name(&device->cdev->dev)); + goto out_err; + } + + /* add device to alias management */ + dasd_alias_add_device(device); + + return 0; + +out_err: + /* + * if the resume failed for the DASD we put it in + * an UNRESUMED stop state + */ + device->stopped |= DASD_UNRESUMED_PM; + return 0; +} + +static struct ccw_driver dasd_eckd_driver = { + .name = "dasd-eckd", + .owner = THIS_MODULE, + .ids = dasd_eckd_ids, + .probe = dasd_eckd_probe, + .remove = dasd_generic_remove, + .set_offline = dasd_generic_set_offline, + .set_online = dasd_eckd_set_online, + .notify = dasd_generic_notify, + .freeze = dasd_generic_pm_freeze, + .thaw = dasd_generic_restore_device, + .restore = dasd_generic_restore_device, +}; /* * max_blocks is dependent on the amount of storage that is available @@ -3274,6 +3354,8 @@ static struct dasd_discipline dasd_eckd_discipline = { .dump_sense_dbf = dasd_eckd_dump_sense_dbf, .fill_info = dasd_eckd_fill_info, .ioctl = dasd_eckd_ioctl, + .freeze = dasd_eckd_pm_freeze, + .restore = dasd_eckd_restore_device, }; static int __init diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 597c6ff..e21ee73 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -2,8 +2,7 @@ * File...........: linux/drivers/s390/block/dasd_fba.c * Author(s)......: Holger Smolinski * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 - * + * Copyright IBM Corp. 1999, 2009 */ #define KMSG_COMPONENT "dasd" @@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = { .set_offline = dasd_generic_set_offline, .set_online = dasd_fba_set_online, .notify = dasd_generic_notify, + .freeze = dasd_generic_pm_freeze, + .thaw = dasd_generic_restore_device, + .restore = dasd_generic_restore_device, }; static void diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index f97ceb7..fd63b2f 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -4,8 +4,7 @@ * Horst Hummel * Martin Schwidefsky * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 - * + * Copyright IBM Corp. 1999, 2009 */ #ifndef DASD_INT_H @@ -295,6 +294,10 @@ struct dasd_discipline { int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); int (*ioctl) (struct dasd_block *, unsigned int, void __user *); + + /* suspend/resume functions */ + int (*freeze) (struct dasd_device *); + int (*restore) (struct dasd_device *); }; extern struct dasd_discipline *dasd_diag_discipline_pointer; @@ -367,6 +370,7 @@ struct dasd_device { atomic_t tasklet_scheduled; struct tasklet_struct tasklet; struct work_struct kick_work; + struct work_struct restore_device; struct timer_list timer; debug_info_t *debug_area; @@ -410,6 +414,8 @@ struct dasd_block { #define DASD_STOPPED_PENDING 4 /* long busy */ #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ #define DASD_STOPPED_SU 16 /* summary unit check handling */ +#define DASD_STOPPED_PM 32 /* pm state transition */ +#define DASD_UNRESUMED_PM 64 /* pm resume failed state */ /* per device flags */ #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ @@ -556,6 +562,7 @@ void dasd_free_block(struct dasd_block *); void dasd_enable_device(struct dasd_device *); void dasd_set_target_state(struct dasd_device *, int); void dasd_kick_device(struct dasd_device *); +void dasd_restore_device(struct dasd_device *); void dasd_add_request_head(struct dasd_ccw_req *); void dasd_add_request_tail(struct dasd_ccw_req *); @@ -578,6 +585,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_notify(struct ccw_device *, int); void dasd_generic_handle_state_change(struct dasd_device *); +int dasd_generic_pm_freeze(struct ccw_device *); +int dasd_generic_restore_device(struct ccw_device *); int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); char *dasd_get_sense(struct irb *); -- cgit v0.10.2 From 7db11a363fc41cec170a94a3542031e5e64bb333 Mon Sep 17 00:00:00 2001 From: Hans-Joachim Picht Date: Tue, 16 Jun 2009 10:30:26 +0200 Subject: [S390] pm: add kernel_page_present Fix the following build failure caused by make allyesconfig using CONFIG_HIBERNATION and CONFIG_DEBUG_PAGEALLOC kernel/built-in.o: In function `saveable_page': kernel/power/snapshot.c:897: undefined reference to `kernel_page_present' kernel/built-in.o: In function `safe_copy_page': kernel/power/snapshot.c:948: undefined reference to `kernel_page_present' make: *** [.tmp_vmlinux1] Error 1 Signed-off-by: Hans-Joachim Picht Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 4ca8e82..5656672 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -313,3 +313,22 @@ int s390_enable_sie(void) return 0; } EXPORT_SYMBOL_GPL(s390_enable_sie); + +#ifdef CONFIG_DEBUG_PAGEALLOC +#ifdef CONFIG_HIBERNATION +bool kernel_page_present(struct page *page) +{ + unsigned long addr; + int cc; + + addr = page_to_phys(page); + asm("lra %1,0(%1)\n" + "ipm %0\n" + "srl %0,28" + :"=d"(cc),"+a"(addr)::"cc"); + return cc == 0; +} + +#endif /* CONFIG_HIBERNATION */ +#endif /* CONFIG_DEBUG_PAGEALLOC */ + -- cgit v0.10.2 From 14532095dfe9e8faf2d314d9c2170f64737c7dff Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 16 Jun 2009 10:30:27 +0200 Subject: [S390] pm: xpram driver power management callbacks Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 0ae0c83..2e9e1ec 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -39,7 +39,10 @@ #include /* HDIO_GETGEO */ #include #include +#include +#include #include +#include #define XPRAM_NAME "xpram" #define XPRAM_DEVS 1 /* one partition */ @@ -48,6 +51,7 @@ typedef struct { unsigned int size; /* size of xpram segment in pages */ unsigned int offset; /* start page of xpram segment */ + unsigned int csum; /* partition checksum for suspend */ } xpram_device_t; static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; @@ -138,7 +142,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) /* * Check if xpram is available. */ -static int __init xpram_present(void) +static int xpram_present(void) { unsigned long mem_page; int rc; @@ -154,7 +158,7 @@ static int __init xpram_present(void) /* * Return index of the last available xpram page. */ -static unsigned long __init xpram_highest_page_index(void) +static unsigned long xpram_highest_page_index(void) { unsigned int page_index, add_bit; unsigned long mem_page; @@ -383,6 +387,106 @@ out: } /* + * Save checksums for all partitions. + */ +static int xpram_save_checksums(void) +{ + unsigned long mem_page; + int rc, i; + + rc = 0; + mem_page = (unsigned long) __get_free_page(GFP_KERNEL); + if (!mem_page) + return -ENOMEM; + for (i = 0; i < xpram_devs; i++) { + rc = xpram_page_in(mem_page, xpram_devices[i].offset); + if (rc) + goto fail; + xpram_devices[i].csum = csum_partial((const void *) mem_page, + PAGE_SIZE, 0); + } +fail: + free_page(mem_page); + return rc ? -ENXIO : 0; +} + +/* + * Verify checksums for all partitions. + */ +static int xpram_validate_checksums(void) +{ + unsigned long mem_page; + unsigned int csum; + int rc, i; + + rc = 0; + mem_page = (unsigned long) __get_free_page(GFP_KERNEL); + if (!mem_page) + return -ENOMEM; + for (i = 0; i < xpram_devs; i++) { + rc = xpram_page_in(mem_page, xpram_devices[i].offset); + if (rc) + goto fail; + csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0); + if (xpram_devices[i].csum != csum) { + rc = -EINVAL; + goto fail; + } + } +fail: + free_page(mem_page); + return rc ? -ENXIO : 0; +} + +/* + * Resume failed: Print error message and call panic. + */ +static void xpram_resume_error(const char *message) +{ + pr_err("Resume error: %s\n", message); + panic("xpram resume error\n"); +} + +/* + * Check if xpram setup changed between suspend and resume. + */ +static int xpram_restore(struct device *dev) +{ + if (!xpram_pages) + return 0; + if (xpram_present() != 0) + xpram_resume_error("xpram disappeared"); + if (xpram_pages != xpram_highest_page_index() + 1) + xpram_resume_error("Size of xpram changed"); + if (xpram_validate_checksums()) + xpram_resume_error("Data of xpram changed"); + return 0; +} + +/* + * Save necessary state in suspend. + */ +static int xpram_freeze(struct device *dev) +{ + return xpram_save_checksums(); +} + +static struct dev_pm_ops xpram_pm_ops = { + .freeze = xpram_freeze, + .restore = xpram_restore, +}; + +static struct platform_driver xpram_pdrv = { + .driver = { + .name = XPRAM_NAME, + .owner = THIS_MODULE, + .pm = &xpram_pm_ops, + }, +}; + +static struct platform_device *xpram_pdev; + +/* * Finally, the init/exit functions. */ static void __exit xpram_exit(void) @@ -394,6 +498,8 @@ static void __exit xpram_exit(void) put_disk(xpram_disks[i]); } unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); + platform_device_unregister(xpram_pdev); + platform_driver_unregister(&xpram_pdrv); } static int __init xpram_init(void) @@ -411,7 +517,24 @@ static int __init xpram_init(void) rc = xpram_setup_sizes(xpram_pages); if (rc) return rc; - return xpram_setup_blkdev(); + rc = platform_driver_register(&xpram_pdrv); + if (rc) + return rc; + xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0); + if (IS_ERR(xpram_pdev)) { + rc = PTR_ERR(xpram_pdev); + goto fail_platform_driver_unregister; + } + rc = xpram_setup_blkdev(); + if (rc) + goto fail_platform_device_unregister; + return 0; + +fail_platform_device_unregister: + platform_device_unregister(xpram_pdev); +fail_platform_driver_unregister: + platform_driver_unregister(&xpram_pdrv); + return rc; } module_init(xpram_init); -- cgit v0.10.2 From 6664845cef13b0a224f43f6c46eddd0b3e018c04 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 16 Jun 2009 10:30:28 +0200 Subject: [S390] cio: force console function If something goes wrong in a suspend / resume cycle a ccw based console if very likely in the suspended state and cannot print anything. Introduce ccw_device_force_console to force the wake up of the console device to be able to print the oops message. The console device drivers should use this function only if the system paniced. Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index 18f0a75..2a54195 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -192,6 +192,7 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *); #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver) extern struct ccw_device *ccw_device_probe_console(void); +extern int ccw_device_force_console(void); // FIXME: these have to go extern int _ccw_device_get_subchannel_number(struct ccw_device *); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 64bd79a..3c57c1a 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1789,6 +1789,15 @@ ccw_device_probe_console(void) return &console_cdev; } +static int ccw_device_pm_restore(struct device *dev); + +int ccw_device_force_console(void) +{ + if (!console_cdev_in_use) + return -ENODEV; + return ccw_device_pm_restore(&console_cdev.dev); +} +EXPORT_SYMBOL_GPL(ccw_device_force_console); const char *cio_get_console_cdev_name(struct subchannel *sch) { -- cgit v0.10.2 From 77812a27577dba6adb71b1de8ee690ced5002067 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 16 Jun 2009 10:30:29 +0200 Subject: [S390] pm: con3215 power management callbacks Introduce the power management callbacks to the 3215 console. On suspend the console buffer is flushed to the 3215 device to have an empty console buffer. Printks done while the 3215 device is suspended are buffered in the 64K buffer of the 3215 device. If the buffer is full new messages will push out the oldest messages to make room for the most recent message. On resume the buffered messages are printed. If the system panics before the 3215 device is resumed ccw_device_force_console is used to get the console working again. Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 9ab06e0..b79f31a 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1,14 +1,12 @@ /* - * drivers/s390/char/con3215.c - * 3215 line mode terminal driver. + * 3215 line mode terminal driver. * - * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Copyright IBM Corp. 1999, 2009 + * Author(s): Martin Schwidefsky * - * Updated: - * Aug-2000: Added tab support - * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu) + * Updated: + * Aug-2000: Added tab support + * Dan Morrison, IBM Corporation */ #include @@ -56,6 +54,7 @@ #define RAW3215_CLOSING 32 /* set while in close process */ #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ +#define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */ #define TAB_STOP_SIZE 8 /* tab stop size */ @@ -111,8 +110,8 @@ static struct tty_driver *tty3215_driver; /* * Get a request structure from the free list */ -static inline struct raw3215_req * -raw3215_alloc_req(void) { +static inline struct raw3215_req *raw3215_alloc_req(void) +{ struct raw3215_req *req; unsigned long flags; @@ -126,8 +125,8 @@ raw3215_alloc_req(void) { /* * Put a request structure back to the free list */ -static inline void -raw3215_free_req(struct raw3215_req *req) { +static inline void raw3215_free_req(struct raw3215_req *req) +{ unsigned long flags; if (req->type == RAW3215_FREE) @@ -145,8 +144,7 @@ raw3215_free_req(struct raw3215_req *req) { * because a 3215 terminal won't accept a new read before the old one is * completed. */ -static void -raw3215_mk_read_req(struct raw3215_info *raw) +static void raw3215_mk_read_req(struct raw3215_info *raw) { struct raw3215_req *req; struct ccw1 *ccw; @@ -174,8 +172,7 @@ raw3215_mk_read_req(struct raw3215_info *raw) * buffer to the 3215 device. If a queued write exists it is replaced by * the new, probably lengthened request. */ -static void -raw3215_mk_write_req(struct raw3215_info *raw) +static void raw3215_mk_write_req(struct raw3215_info *raw) { struct raw3215_req *req; struct ccw1 *ccw; @@ -251,8 +248,7 @@ raw3215_mk_write_req(struct raw3215_info *raw) /* * Start a read or a write request */ -static void -raw3215_start_io(struct raw3215_info *raw) +static void raw3215_start_io(struct raw3215_info *raw) { struct raw3215_req *req; int res; @@ -290,8 +286,7 @@ raw3215_start_io(struct raw3215_info *raw) /* * Function to start a delayed output after RAW3215_TIMEOUT seconds */ -static void -raw3215_timeout(unsigned long __data) +static void raw3215_timeout(unsigned long __data) { struct raw3215_info *raw = (struct raw3215_info *) __data; unsigned long flags; @@ -300,8 +295,10 @@ raw3215_timeout(unsigned long __data) if (raw->flags & RAW3215_TIMER_RUNS) { del_timer(&raw->timer); raw->flags &= ~RAW3215_TIMER_RUNS; - raw3215_mk_write_req(raw); - raw3215_start_io(raw); + if (!(raw->flags & RAW3215_FROZEN)) { + raw3215_mk_write_req(raw); + raw3215_start_io(raw); + } } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } @@ -312,10 +309,9 @@ raw3215_timeout(unsigned long __data) * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not * done immediately a timer is started with a delay of RAW3215_TIMEOUT. */ -static inline void -raw3215_try_io(struct raw3215_info *raw) +static inline void raw3215_try_io(struct raw3215_info *raw) { - if (!(raw->flags & RAW3215_ACTIVE)) + if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN)) return; if (raw->queued_read != NULL) raw3215_start_io(raw); @@ -359,8 +355,8 @@ static void raw3215_next_io(struct raw3215_info *raw) /* * Interrupt routine, called from common io layer */ -static void -raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) +static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, + struct irb *irb) { struct raw3215_info *raw; struct raw3215_req *req; @@ -459,14 +455,40 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } /* + * Drop the oldest line from the output buffer. + */ +static void raw3215_drop_line(struct raw3215_info *raw) +{ + int ix; + char ch; + + BUG_ON(raw->written != 0); + ix = (raw->head - raw->count) & (RAW3215_BUFFER_SIZE - 1); + while (raw->count > 0) { + ch = raw->buffer[ix]; + ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1); + raw->count--; + if (ch == 0x15) + break; + } + raw->head = ix; +} + +/* * Wait until length bytes are available int the output buffer. * Has to be called with the s390irq lock held. Can be called * disabled. */ -static void -raw3215_make_room(struct raw3215_info *raw, unsigned int length) +static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) { while (RAW3215_BUFFER_SIZE - raw->count < length) { + /* While console is frozen for suspend we have no other + * choice but to drop message from the buffer to make + * room for even more messages. */ + if (raw->flags & RAW3215_FROZEN) { + raw3215_drop_line(raw); + continue; + } /* there might be a request pending */ raw->flags |= RAW3215_FLUSHING; raw3215_mk_write_req(raw); @@ -488,8 +510,8 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length) /* * String write routine for 3215 devices */ -static void -raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) +static void raw3215_write(struct raw3215_info *raw, const char *str, + unsigned int length) { unsigned long flags; int c, count; @@ -529,8 +551,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) /* * Put character routine for 3215 devices */ -static void -raw3215_putchar(struct raw3215_info *raw, unsigned char ch) +static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) { unsigned long flags; unsigned int length, i; @@ -566,8 +587,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) * Flush routine, it simply sets the flush flag and tries to start * pending IO. */ -static void -raw3215_flush_buffer(struct raw3215_info *raw) +static void raw3215_flush_buffer(struct raw3215_info *raw) { unsigned long flags; @@ -583,8 +603,7 @@ raw3215_flush_buffer(struct raw3215_info *raw) /* * Fire up a 3215 device. */ -static int -raw3215_startup(struct raw3215_info *raw) +static int raw3215_startup(struct raw3215_info *raw) { unsigned long flags; @@ -602,8 +621,7 @@ raw3215_startup(struct raw3215_info *raw) /* * Shutdown a 3215 device. */ -static void -raw3215_shutdown(struct raw3215_info *raw) +static void raw3215_shutdown(struct raw3215_info *raw) { DECLARE_WAITQUEUE(wait, current); unsigned long flags; @@ -628,8 +646,7 @@ raw3215_shutdown(struct raw3215_info *raw) spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } -static int -raw3215_probe (struct ccw_device *cdev) +static int raw3215_probe (struct ccw_device *cdev) { struct raw3215_info *raw; int line; @@ -675,8 +692,7 @@ raw3215_probe (struct ccw_device *cdev) return 0; } -static void -raw3215_remove (struct ccw_device *cdev) +static void raw3215_remove (struct ccw_device *cdev) { struct raw3215_info *raw; @@ -689,8 +705,7 @@ raw3215_remove (struct ccw_device *cdev) } } -static int -raw3215_set_online (struct ccw_device *cdev) +static int raw3215_set_online (struct ccw_device *cdev) { struct raw3215_info *raw; @@ -701,8 +716,7 @@ raw3215_set_online (struct ccw_device *cdev) return raw3215_startup(raw); } -static int -raw3215_set_offline (struct ccw_device *cdev) +static int raw3215_set_offline (struct ccw_device *cdev) { struct raw3215_info *raw; @@ -715,6 +729,36 @@ raw3215_set_offline (struct ccw_device *cdev) return 0; } +static int raw3215_pm_stop(struct ccw_device *cdev) +{ + struct raw3215_info *raw; + unsigned long flags; + + /* Empty the output buffer, then prevent new I/O. */ + raw = cdev->dev.driver_data; + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); + raw3215_make_room(raw, RAW3215_BUFFER_SIZE); + raw->flags |= RAW3215_FROZEN; + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); + return 0; +} + +static int raw3215_pm_start(struct ccw_device *cdev) +{ + struct raw3215_info *raw; + unsigned long flags; + + /* Allow I/O again and flush output buffer. */ + raw = cdev->dev.driver_data; + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); + raw->flags &= ~RAW3215_FROZEN; + raw->flags |= RAW3215_FLUSHING; + raw3215_try_io(raw); + raw->flags &= ~RAW3215_FLUSHING; + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); + return 0; +} + static struct ccw_device_id raw3215_id[] = { { CCW_DEVICE(0x3215, 0) }, { /* end of list */ }, @@ -728,14 +772,17 @@ static struct ccw_driver raw3215_ccw_driver = { .remove = &raw3215_remove, .set_online = &raw3215_set_online, .set_offline = &raw3215_set_offline, + .freeze = &raw3215_pm_stop, + .thaw = &raw3215_pm_start, + .restore = &raw3215_pm_start, }; #ifdef CONFIG_TN3215_CONSOLE /* * Write a string to the 3215 console */ -static void -con3215_write(struct console *co, const char *str, unsigned int count) +static void con3215_write(struct console *co, const char *str, + unsigned int count) { struct raw3215_info *raw; int i; @@ -768,13 +815,17 @@ static struct tty_driver *con3215_device(struct console *c, int *index) * panic() calls con3215_flush through a panic_notifier * before the system enters a disabled, endless loop. */ -static void -con3215_flush(void) +static void con3215_flush(void) { struct raw3215_info *raw; unsigned long flags; raw = raw3215[0]; /* console 3215 is the first one */ + if (raw->flags & RAW3215_FROZEN) + /* The console is still frozen for suspend. */ + if (ccw_device_force_console()) + /* Forcing didn't work, no panic message .. */ + return; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_make_room(raw, RAW3215_BUFFER_SIZE); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -811,8 +862,7 @@ static struct console con3215 = { * 3215 console initialization code called from console_init(). * NOTE: This is called before kmalloc is available. */ -static int __init -con3215_init(void) +static int __init con3215_init(void) { struct ccw_device *cdev; struct raw3215_info *raw; @@ -875,8 +925,7 @@ console_initcall(con3215_init); * * This routine is called whenever a 3215 tty is opened. */ -static int -tty3215_open(struct tty_struct *tty, struct file * filp) +static int tty3215_open(struct tty_struct *tty, struct file * filp) { struct raw3215_info *raw; int retval, line; @@ -909,8 +958,7 @@ tty3215_open(struct tty_struct *tty, struct file * filp) * This routine is called when the 3215 tty is closed. We wait * for the remaining request to be completed. Then we clean up. */ -static void -tty3215_close(struct tty_struct *tty, struct file * filp) +static void tty3215_close(struct tty_struct *tty, struct file * filp) { struct raw3215_info *raw; @@ -927,8 +975,7 @@ tty3215_close(struct tty_struct *tty, struct file * filp) /* * Returns the amount of free space in the output buffer. */ -static int -tty3215_write_room(struct tty_struct *tty) +static int tty3215_write_room(struct tty_struct *tty) { struct raw3215_info *raw; @@ -944,9 +991,8 @@ tty3215_write_room(struct tty_struct *tty) /* * String write routine for 3215 ttys */ -static int -tty3215_write(struct tty_struct * tty, - const unsigned char *buf, int count) +static int tty3215_write(struct tty_struct * tty, + const unsigned char *buf, int count) { struct raw3215_info *raw; @@ -960,8 +1006,7 @@ tty3215_write(struct tty_struct * tty, /* * Put character routine for 3215 ttys */ -static int -tty3215_put_char(struct tty_struct *tty, unsigned char ch) +static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) { struct raw3215_info *raw; @@ -972,16 +1017,14 @@ tty3215_put_char(struct tty_struct *tty, unsigned char ch) return 1; } -static void -tty3215_flush_chars(struct tty_struct *tty) +static void tty3215_flush_chars(struct tty_struct *tty) { } /* * Returns the number of characters in the output buffer */ -static int -tty3215_chars_in_buffer(struct tty_struct *tty) +static int tty3215_chars_in_buffer(struct tty_struct *tty) { struct raw3215_info *raw; @@ -989,8 +1032,7 @@ tty3215_chars_in_buffer(struct tty_struct *tty) return raw->count; } -static void -tty3215_flush_buffer(struct tty_struct *tty) +static void tty3215_flush_buffer(struct tty_struct *tty) { struct raw3215_info *raw; @@ -1002,9 +1044,8 @@ tty3215_flush_buffer(struct tty_struct *tty) /* * Currently we don't have any io controls for 3215 ttys */ -static int -tty3215_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int tty3215_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -1019,8 +1060,7 @@ tty3215_ioctl(struct tty_struct *tty, struct file * file, /* * Disable reading from a 3215 tty */ -static void -tty3215_throttle(struct tty_struct * tty) +static void tty3215_throttle(struct tty_struct * tty) { struct raw3215_info *raw; @@ -1031,8 +1071,7 @@ tty3215_throttle(struct tty_struct * tty) /* * Enable reading from a 3215 tty */ -static void -tty3215_unthrottle(struct tty_struct * tty) +static void tty3215_unthrottle(struct tty_struct * tty) { struct raw3215_info *raw; unsigned long flags; @@ -1049,8 +1088,7 @@ tty3215_unthrottle(struct tty_struct * tty) /* * Disable writing to a 3215 tty */ -static void -tty3215_stop(struct tty_struct *tty) +static void tty3215_stop(struct tty_struct *tty) { struct raw3215_info *raw; @@ -1061,8 +1099,7 @@ tty3215_stop(struct tty_struct *tty) /* * Enable writing to a 3215 tty */ -static void -tty3215_start(struct tty_struct *tty) +static void tty3215_start(struct tty_struct *tty) { struct raw3215_info *raw; unsigned long flags; @@ -1096,8 +1133,7 @@ static const struct tty_operations tty3215_ops = { * 3215 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -static int __init -tty3215_init(void) +static int __init tty3215_init(void) { struct tty_driver *driver; int ret; @@ -1142,8 +1178,7 @@ tty3215_init(void) return 0; } -static void __exit -tty3215_exit(void) +static void __exit tty3215_exit(void) { tty_unregister_driver(tty3215_driver); put_tty_driver(tty3215_driver); -- cgit v0.10.2 From cbb2aec3e7271f4cefcba2942aecc658d5841307 Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacket Date: Tue, 16 Jun 2009 10:30:30 +0200 Subject: [S390] pm: lcs driver power management callbacks Signed-off-by: Klaus-Dieter Wacker Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index a45bc24..07a25c3 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1,15 +1,12 @@ /* - * linux/drivers/s390/net/lcs.c - * * Linux for S/390 Lan Channel Station Network Driver * - * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Original Code written by - * DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * Rewritten by - * Frank Pavlic (fpavlic@de.ibm.com) and - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * Author(s): Original Code written by + * DJ Barrow + * Rewritten by + * Frank Pavlic and + * Martin Schwidefsky * * 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 @@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) put_device(&ccwgdev->dev); } +static int lcs_pm_suspend(struct lcs_card *card) +{ + if (card->dev) + netif_device_detach(card->dev); + lcs_set_allowed_threads(card, 0); + lcs_wait_for_threads(card, 0xffffffff); + if (card->state != DEV_STATE_DOWN) + __lcs_shutdown_device(card->gdev, 1); + return 0; +} + +static int lcs_pm_resume(struct lcs_card *card) +{ + int rc = 0; + + if (card->state == DEV_STATE_RECOVER) + rc = lcs_new_device(card->gdev); + if (card->dev) + netif_device_attach(card->dev); + if (rc) { + dev_warn(&card->gdev->dev, "The lcs device driver " + "failed to recover the device\n"); + } + return rc; +} + +static int lcs_prepare(struct ccwgroup_device *gdev) +{ + return 0; +} + +static void lcs_complete(struct ccwgroup_device *gdev) +{ + return; +} + +static int lcs_freeze(struct ccwgroup_device *gdev) +{ + struct lcs_card *card = dev_get_drvdata(&gdev->dev); + return lcs_pm_suspend(card); +} + +static int lcs_thaw(struct ccwgroup_device *gdev) +{ + struct lcs_card *card = dev_get_drvdata(&gdev->dev); + return lcs_pm_resume(card); +} + +static int lcs_restore(struct ccwgroup_device *gdev) +{ + struct lcs_card *card = dev_get_drvdata(&gdev->dev); + return lcs_pm_resume(card); +} + /** * LCS ccwgroup driver registration */ @@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = { .remove = lcs_remove_device, .set_online = lcs_new_device, .set_offline = lcs_shutdown_device, + .prepare = lcs_prepare, + .complete = lcs_complete, + .freeze = lcs_freeze, + .thaw = lcs_thaw, + .restore = lcs_restore, }; /** -- cgit v0.10.2 From bbcfcdc8324e75532c4d2592a545a91fcb45f229 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Tue, 16 Jun 2009 10:30:31 +0200 Subject: [S390] pm: qeth driver power management callbacks Signed-off-by: Frank Blaschka Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 74c49d9..d53621c 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/qeth_core_main.c * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2009 * Author(s): Utz Bacher , * Frank Pavlic , * Thomas Spatzier , @@ -4195,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev) card->discipline.ccwgdriver->shutdown(gdev); } +static int qeth_core_prepare(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->prepare) + return card->discipline.ccwgdriver->prepare(gdev); + return 0; +} + +static void qeth_core_complete(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->complete) + card->discipline.ccwgdriver->complete(gdev); +} + +static int qeth_core_freeze(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->freeze) + return card->discipline.ccwgdriver->freeze(gdev); + return 0; +} + +static int qeth_core_thaw(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->thaw) + return card->discipline.ccwgdriver->thaw(gdev); + return 0; +} + +static int qeth_core_restore(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->restore) + return card->discipline.ccwgdriver->restore(gdev); + return 0; +} + static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .owner = THIS_MODULE, .name = "qeth", @@ -4204,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .set_online = qeth_core_set_online, .set_offline = qeth_core_set_offline, .shutdown = qeth_core_shutdown, + .prepare = qeth_core_prepare, + .complete = qeth_core_complete, + .freeze = qeth_core_freeze, + .thaw = qeth_core_thaw, + .restore = qeth_core_restore, }; static ssize_t diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index ecd3d06..81d7f26 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/qeth_l2_main.c * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2009 * Author(s): Utz Bacher , * Frank Pavlic , * Thomas Spatzier , @@ -1141,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev) qeth_clear_qdio_buffers(card); } +static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + + if (card->dev) + netif_device_detach(card->dev); + qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + if (card->state == CARD_STATE_UP) { + card->use_hard_stop = 1; + __qeth_l2_set_offline(card->gdev, 1); + } else + __qeth_l2_set_offline(card->gdev, 0); + return 0; +} + +static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + int rc = 0; + + if (gdev->state == CCWGROUP_OFFLINE) + goto out; + + if (card->state == CARD_STATE_RECOVER) { + rc = __qeth_l2_set_online(card->gdev, 1); + if (rc) { + if (card->dev) { + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); + } + } + } else + rc = __qeth_l2_set_online(card->gdev, 0); +out: + qeth_set_allowed_threads(card, 0xffffffff, 0); + if (card->dev) + netif_device_attach(card->dev); + if (rc) + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + return rc; +} + struct ccwgroup_driver qeth_l2_ccwgroup_driver = { .probe = qeth_l2_probe_device, .remove = qeth_l2_remove_device, .set_online = qeth_l2_set_online, .set_offline = qeth_l2_set_offline, .shutdown = qeth_l2_shutdown, + .freeze = qeth_l2_pm_suspend, + .thaw = qeth_l2_pm_resume, + .restore = qeth_l2_pm_resume, }; EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 6f2386e..5487240 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/qeth_l3_main.c * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2009 * Author(s): Utz Bacher , * Frank Pavlic , * Thomas Spatzier , @@ -3283,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev) qeth_clear_qdio_buffers(card); } +static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + + if (card->dev) + netif_device_detach(card->dev); + qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + if (card->state == CARD_STATE_UP) { + card->use_hard_stop = 1; + __qeth_l3_set_offline(card->gdev, 1); + } else + __qeth_l3_set_offline(card->gdev, 0); + return 0; +} + +static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + int rc = 0; + + if (gdev->state == CCWGROUP_OFFLINE) + goto out; + + if (card->state == CARD_STATE_RECOVER) { + rc = __qeth_l3_set_online(card->gdev, 1); + if (rc) { + if (card->dev) { + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); + } + } + } else + rc = __qeth_l3_set_online(card->gdev, 0); +out: + qeth_set_allowed_threads(card, 0xffffffff, 0); + if (card->dev) + netif_device_attach(card->dev); + if (rc) + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + return rc; +} + struct ccwgroup_driver qeth_l3_ccwgroup_driver = { .probe = qeth_l3_probe_device, .remove = qeth_l3_remove_device, .set_online = qeth_l3_set_online, .set_offline = qeth_l3_set_offline, .shutdown = qeth_l3_shutdown, + .freeze = qeth_l3_pm_suspend, + .thaw = qeth_l3_pm_resume, + .restore = qeth_l3_pm_resume, }; EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); -- cgit v0.10.2 From b8a2d42a8276d4dbc5a5c99f4422132c43ce3e1d Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Tue, 16 Jun 2009 10:30:32 +0200 Subject: [S390] pm: ctcm driver power management callbacks Signed-off-by: Frank Blaschka Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 54c4649..222e473 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/ctcm_main.c * - * Copyright IBM Corp. 2001, 2007 + * Copyright IBM Corp. 2001, 2009 * Author(s): * Original CTC driver(s): * Fritz Elfert (felfert@millenux.com) @@ -1688,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) put_device(&cgdev->dev); } +static int ctcm_pm_suspend(struct ccwgroup_device *gdev) +{ + struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); + + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + netif_device_detach(priv->channel[READ]->netdev); + ctcm_close(priv->channel[READ]->netdev); + ccw_device_set_offline(gdev->cdev[1]); + ccw_device_set_offline(gdev->cdev[0]); + return 0; +} + +static int ctcm_pm_resume(struct ccwgroup_device *gdev) +{ + struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); + int rc; + + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + rc = ccw_device_set_online(gdev->cdev[1]); + if (rc) + goto err_out; + rc = ccw_device_set_online(gdev->cdev[0]); + if (rc) + goto err_out; + ctcm_open(priv->channel[READ]->netdev); +err_out: + netif_device_attach(priv->channel[READ]->netdev); + return rc; +} + static struct ccwgroup_driver ctcm_group_driver = { .owner = THIS_MODULE, .name = CTC_DRIVER_NAME, @@ -1697,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = { .remove = ctcm_remove_device, .set_online = ctcm_new_device, .set_offline = ctcm_shutdown_device, + .freeze = ctcm_pm_suspend, + .thaw = ctcm_pm_resume, + .restore = ctcm_pm_resume, }; -- cgit v0.10.2 From 88efc2c503e82072a19b531d54e02f22de14a132 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Tue, 16 Jun 2009 10:30:33 +0200 Subject: [S390] pm: claw driver power management callbacks Signed-off-by: Frank Blaschka Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 7b6f46d..d40f7a9 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -3,12 +3,12 @@ * ESCON CLAW network driver * * Linux for zSeries version - * Copyright (C) 2002,2005 IBM Corporation + * Copyright IBM Corp. 2002, 2009 * Author(s) Original code written by: - * Kazuo Iimura (iimura@jp.ibm.com) + * Kazuo Iimura * Rewritten by - * Andy Richter (richtera@us.ibm.com) - * Marc Price (mwprice@us.ibm.com) + * Andy Richter + * Marc Price * * sysfs parms: * group x.x.rrrr,x.x.wwww @@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev); /* Functions for unpack reads */ static void unpack_read(struct net_device *dev); +static int claw_pm_prepare(struct ccwgroup_device *gdev) +{ + return -EPERM; +} + /* ccwgroup table */ static struct ccwgroup_driver claw_group_driver = { @@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = { .remove = claw_remove_device, .set_online = claw_new_device, .set_offline = claw_shutdown_device, + .prepare = claw_pm_prepare, }; /* -- cgit v0.10.2 From daa70fa960fb5625d762988cca7e4733573d90a3 Mon Sep 17 00:00:00 2001 From: Martin Petermann Date: Tue, 16 Jun 2009 10:30:34 +0200 Subject: [S390] pm: zfcp driver power management callbacks Signed-off-by: Martin Petermann Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index b2fe5cd..d9da5c4 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -13,6 +13,36 @@ #define ZFCP_MODEL_PRIV 0x4 +static int zfcp_ccw_suspend(struct ccw_device *cdev) + +{ + struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + + down(&zfcp_data.config_sema); + + zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); + zfcp_erp_wait(adapter); + + up(&zfcp_data.config_sema); + + return 0; +} + +static int zfcp_ccw_activate(struct ccw_device *cdev) + +{ + struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + + zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, + ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, + "ccresu2", NULL); + zfcp_erp_wait(adapter); + flush_work(&adapter->scan_work); + + return 0; +} + static struct ccw_device_id zfcp_ccw_device_id[] = { { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) }, @@ -227,6 +257,9 @@ static struct ccw_driver zfcp_ccw_driver = { .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, .shutdown = zfcp_ccw_shutdown, + .freeze = zfcp_ccw_suspend, + .thaw = zfcp_ccw_activate, + .restore = zfcp_ccw_activate, }; /** -- cgit v0.10.2 From 58872d5f367876a81dcda82465381d80d321a81d Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 16 Jun 2009 10:30:35 +0200 Subject: [S390] pm: vmwatchdog power management callbacks. This patch implements suspend/hibernation for the vmwatchdog driver. The pm_notifier_callchain is used to get control on PM events. Since watchdog operation and suspend cannot work together in a reliable fashion, the open flag is also used to prevent suspend and open from happening at the same time. The watchdog can also be active with no open file descriptor. This patch adds another flag which is only changed in vmwdt_keep_alive and vmwdt_disable. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 21a2a82..cb7854c 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -1,17 +1,23 @@ /* * Watchdog implementation based on z/VM Watchdog Timer API * + * Copyright IBM Corp. 2004,2009 + * * The user space watchdog daemon can use this driver as * /dev/vmwatchdog to have z/VM execute the specified CP * command when the timeout expires. The default command is * "IPL", which which cause an immediate reboot. */ +#define KMSG_COMPONENT "vmwatchdog" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include #include #include #include +#include #include #include @@ -43,6 +49,9 @@ static unsigned int vmwdt_interval = 60; static unsigned long vmwdt_is_open; static int vmwdt_expect_close; +#define VMWDT_OPEN 0 /* devnode is open or suspend in progress */ +#define VMWDT_RUNNING 1 /* The watchdog is armed */ + enum vmwdt_func { /* function codes */ wdt_init = 0, @@ -92,6 +101,7 @@ static int vmwdt_keepalive(void) EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; + set_bit(VMWDT_RUNNING, &vmwdt_is_open); ret = __diag288(func, vmwdt_interval, ebc_cmd, len); WARN_ON(ret != 0); kfree(ebc_cmd); @@ -102,6 +112,7 @@ static int vmwdt_disable(void) { int ret = __diag288(wdt_cancel, 0, "", 0); WARN_ON(ret != 0); + clear_bit(VMWDT_RUNNING, &vmwdt_is_open); return ret; } @@ -123,13 +134,13 @@ static int vmwdt_open(struct inode *i, struct file *f) { int ret; lock_kernel(); - if (test_and_set_bit(0, &vmwdt_is_open)) { + if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { unlock_kernel(); return -EBUSY; } ret = vmwdt_keepalive(); if (ret) - clear_bit(0, &vmwdt_is_open); + clear_bit(VMWDT_OPEN, &vmwdt_is_open); unlock_kernel(); return ret ? ret : nonseekable_open(i, f); } @@ -139,7 +150,7 @@ static int vmwdt_close(struct inode *i, struct file *f) if (vmwdt_expect_close == 42) vmwdt_disable(); vmwdt_expect_close = 0; - clear_bit(0, &vmwdt_is_open); + clear_bit(VMWDT_OPEN, &vmwdt_is_open); return 0; } @@ -223,6 +234,57 @@ static ssize_t vmwdt_write(struct file *f, const char __user *buf, return count; } +static int vmwdt_resume(void) +{ + clear_bit(VMWDT_OPEN, &vmwdt_is_open); + return NOTIFY_DONE; +} + +/* + * It makes no sense to go into suspend while the watchdog is running. + * Depending on the memory size, the watchdog might trigger, while we + * are still saving the memory. + * We reuse the open flag to ensure that suspend and watchdog open are + * exclusive operations + */ +static int vmwdt_suspend(void) +{ + if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { + pr_err("The watchdog is in use. " + "This prevents hibernation or suspend.\n"); + return NOTIFY_BAD; + } + if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { + clear_bit(VMWDT_OPEN, &vmwdt_is_open); + pr_err("The watchdog is running. " + "This prevents hibernation or suspend.\n"); + return NOTIFY_BAD; + } + return NOTIFY_DONE; +} + +/* + * This function is called for suspend and resume. + */ +static int vmwdt_power_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + switch (event) { + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + return vmwdt_resume(); + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + return vmwdt_suspend(); + default: + return NOTIFY_DONE; + } +} + +static struct notifier_block vmwdt_power_notifier = { + .notifier_call = vmwdt_power_event, +}; + static const struct file_operations vmwdt_fops = { .open = &vmwdt_open, .release = &vmwdt_close, @@ -244,12 +306,21 @@ static int __init vmwdt_init(void) ret = vmwdt_probe(); if (ret) return ret; - return misc_register(&vmwdt_dev); + ret = register_pm_notifier(&vmwdt_power_notifier); + if (ret) + return ret; + ret = misc_register(&vmwdt_dev); + if (ret) { + unregister_pm_notifier(&vmwdt_power_notifier); + return ret; + } + return 0; } module_init(vmwdt_init); static void __exit vmwdt_exit(void) { - WARN_ON(misc_deregister(&vmwdt_dev) != 0); + unregister_pm_notifier(&vmwdt_power_notifier); + misc_deregister(&vmwdt_dev); } module_exit(vmwdt_exit); -- cgit v0.10.2 From 524dbcdad7a84a054b4458aa94e152ffb2bfabbd Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 16 Jun 2009 10:30:36 +0200 Subject: [S390] pm: appldata power management callbacks Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 1dfc710..264528e 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -5,7 +5,7 @@ * Exports appldata_register_ops() and appldata_unregister_ops() for the * data gathering modules. * - * Copyright IBM Corp. 2003, 2008 + * Copyright IBM Corp. 2003, 2009 * * Author: Gerald Schaefer */ @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,6 +43,9 @@ #define TOD_MICRO 0x01000 /* nr. of TOD clock units for 1 microsecond */ + +static struct platform_device *appldata_pdev; + /* * /proc entries (sysctl) */ @@ -86,6 +91,7 @@ static atomic_t appldata_expire_count = ATOMIC_INIT(0); static DEFINE_SPINLOCK(appldata_timer_lock); static int appldata_interval = APPLDATA_CPU_INTERVAL; static int appldata_timer_active; +static int appldata_timer_suspended = 0; /* * Work queue @@ -475,6 +481,93 @@ void appldata_unregister_ops(struct appldata_ops *ops) /********************** module-ops management **************************/ +/**************************** suspend / resume *******************************/ +static int appldata_freeze(struct device *dev) +{ + struct appldata_ops *ops; + int rc; + struct list_head *lh; + + get_online_cpus(); + spin_lock(&appldata_timer_lock); + if (appldata_timer_active) { + __appldata_vtimer_setup(APPLDATA_DEL_TIMER); + appldata_timer_suspended = 1; + } + spin_unlock(&appldata_timer_lock); + put_online_cpus(); + + mutex_lock(&appldata_ops_mutex); + list_for_each(lh, &appldata_ops_list) { + ops = list_entry(lh, struct appldata_ops, list); + if (ops->active == 1) { + rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, + (unsigned long) ops->data, ops->size, + ops->mod_lvl); + if (rc != 0) + pr_err("Stopping the data collection for %s " + "failed with rc=%d\n", ops->name, rc); + } + } + mutex_unlock(&appldata_ops_mutex); + return 0; +} + +static int appldata_restore(struct device *dev) +{ + struct appldata_ops *ops; + int rc; + struct list_head *lh; + + get_online_cpus(); + spin_lock(&appldata_timer_lock); + if (appldata_timer_suspended) { + __appldata_vtimer_setup(APPLDATA_ADD_TIMER); + appldata_timer_suspended = 0; + } + spin_unlock(&appldata_timer_lock); + put_online_cpus(); + + mutex_lock(&appldata_ops_mutex); + list_for_each(lh, &appldata_ops_list) { + ops = list_entry(lh, struct appldata_ops, list); + if (ops->active == 1) { + ops->callback(ops->data); // init record + rc = appldata_diag(ops->record_nr, + APPLDATA_START_INTERVAL_REC, + (unsigned long) ops->data, ops->size, + ops->mod_lvl); + if (rc != 0) { + pr_err("Starting the data collection for %s " + "failed with rc=%d\n", ops->name, rc); + } + } + } + mutex_unlock(&appldata_ops_mutex); + return 0; +} + +static int appldata_thaw(struct device *dev) +{ + return appldata_restore(dev); +} + +static struct dev_pm_ops appldata_pm_ops = { + .freeze = appldata_freeze, + .thaw = appldata_thaw, + .restore = appldata_restore, +}; + +static struct platform_driver appldata_pdrv = { + .driver = { + .name = "appldata", + .owner = THIS_MODULE, + .pm = &appldata_pm_ops, + }, +}; +/************************* suspend / resume ****************************/ + + /******************************* init / exit *********************************/ static void __cpuinit appldata_online_cpu(int cpu) @@ -531,11 +624,23 @@ static struct notifier_block __cpuinitdata appldata_nb = { */ static int __init appldata_init(void) { - int i; + int i, rc; + + rc = platform_driver_register(&appldata_pdrv); + if (rc) + return rc; + appldata_pdev = platform_device_register_simple("appldata", -1, NULL, + 0); + if (IS_ERR(appldata_pdev)) { + rc = PTR_ERR(appldata_pdev); + goto out_driver; + } appldata_wq = create_singlethread_workqueue("appldata"); - if (!appldata_wq) - return -ENOMEM; + if (!appldata_wq) { + rc = -ENOMEM; + goto out_device; + } get_online_cpus(); for_each_online_cpu(i) @@ -547,6 +652,12 @@ static int __init appldata_init(void) appldata_sysctl_header = register_sysctl_table(appldata_dir_table); return 0; + +out_device: + platform_device_unregister(appldata_pdev); +out_driver: + platform_driver_unregister(&appldata_pdrv); + return rc; } __initcall(appldata_init); -- cgit v0.10.2 From b241f7bcc603babd3de903fa855d418ee7c4751d Mon Sep 17 00:00:00 2001 From: Frank Munzert Date: Tue, 16 Jun 2009 10:30:37 +0200 Subject: [S390] pm: vmur driver power management callbacks Signed-off-by: Frank Munzert Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 5dcef81..9245821 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -2,7 +2,7 @@ * Linux driver for System z and s390 unit record devices * (z/VM virtual punch, reader, printer) * - * Copyright IBM Corp. 2001, 2007 + * Copyright IBM Corp. 2001, 2009 * Authors: Malcolm Beattie * Michael Holzheu * Frank Munzert @@ -60,6 +60,7 @@ static int ur_probe(struct ccw_device *cdev); static void ur_remove(struct ccw_device *cdev); static int ur_set_online(struct ccw_device *cdev); static int ur_set_offline(struct ccw_device *cdev); +static int ur_pm_suspend(struct ccw_device *cdev); static struct ccw_driver ur_driver = { .name = "vmur", @@ -69,6 +70,7 @@ static struct ccw_driver ur_driver = { .remove = ur_remove, .set_online = ur_set_online, .set_offline = ur_set_offline, + .freeze = ur_pm_suspend, }; static DEFINE_MUTEX(vmur_mutex); @@ -158,6 +160,28 @@ static void urdev_put(struct urdev *urd) } /* + * State and contents of ur devices can be changed by class D users issuing + * CP commands such as PURGE or TRANSFER, while the Linux guest is suspended. + * Also the Linux guest might be logged off, which causes all active spool + * files to be closed. + * So we cannot guarantee that spool files are still the same when the Linux + * guest is resumed. In order to avoid unpredictable results at resume time + * we simply refuse to suspend if a ur device node is open. + */ +static int ur_pm_suspend(struct ccw_device *cdev) +{ + struct urdev *urd = cdev->dev.driver_data; + + TRACE("ur_pm_suspend: cdev=%p\n", cdev); + if (urd->open_flag) { + pr_err("Unit record device %s is busy, %s refusing to " + "suspend.\n", dev_name(&cdev->dev), ur_banner); + return -EBUSY; + } + return 0; +} + +/* * Low-level functions to do I/O to a ur device. * alloc_chan_prog * free_chan_prog -- cgit v0.10.2 From 9f62fa1618987e9fadb2eef86d35ef168ddf5a1f Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Tue, 16 Jun 2009 10:30:38 +0200 Subject: [S390] pm: vmlogrdr power management callbacks Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index d8a2289..e925808 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -3,7 +3,7 @@ * character device driver for reading z/VM system service records * * - * Copyright 2004 IBM Corporation + * Copyright IBM Corp. 2004, 2009 * character device driver for reading z/VM system service records, * Version 1.0 * Author(s): Xenia Tkatschow @@ -660,6 +660,29 @@ static struct attribute *vmlogrdr_attrs[] = { NULL, }; +static int vmlogrdr_pm_prepare(struct device *dev) +{ + int rc; + struct vmlogrdr_priv_t *priv = dev->driver_data; + + rc = 0; + if (priv) { + spin_lock_bh(&priv->priv_lock); + if (priv->dev_in_use) + rc = -EBUSY; + spin_unlock_bh(&priv->priv_lock); + } + if (rc) + pr_err("vmlogrdr: device %s is busy. Refuse to suspend.\n", + dev_name(dev)); + return rc; +} + + +static struct dev_pm_ops vmlogrdr_pm_ops = { + .prepare = vmlogrdr_pm_prepare, +}; + static struct attribute_group vmlogrdr_attr_group = { .attrs = vmlogrdr_attrs, }; @@ -668,6 +691,7 @@ static struct class *vmlogrdr_class; static struct device_driver vmlogrdr_driver = { .name = "vmlogrdr", .bus = &iucv_bus, + .pm = &vmlogrdr_pm_ops, }; @@ -729,6 +753,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) dev->bus = &iucv_bus; dev->parent = iucv_root; dev->driver = &vmlogrdr_driver; + dev->driver_data = priv; /* * The release function could be called after the * module has been unloaded. It's _only_ task is to -- cgit v0.10.2 From 3ef32e62cb55785f6f1b5ad7290744f74bdadaf0 Mon Sep 17 00:00:00 2001 From: Frank Munzert Date: Tue, 16 Jun 2009 10:30:39 +0200 Subject: [S390] pm: tape power management callbacks Signed-off-by: Frank Munzert Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index 5469e09..a263337 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -3,7 +3,7 @@ * tape device driver for 3480/3490E/3590 tapes. * * S390 and zSeries version - * Copyright IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Carsten Otte * Tuan Ngo-Anh * Martin Schwidefsky @@ -286,6 +286,7 @@ extern void tape_state_set(struct tape_device *, enum tape_state); extern int tape_generic_online(struct tape_device *, struct tape_discipline *); extern int tape_generic_offline(struct ccw_device *); +extern int tape_generic_pm_suspend(struct ccw_device *); /* Externals from tape_devmap.c */ extern int tape_generic_probe(struct ccw_device *); diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 2d00a38..144d2a5 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -2,7 +2,7 @@ * drivers/s390/char/tape_34xx.c * tape device discipline for 3480/3490 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Carsten Otte * Tuan Ngo-Anh * Martin Schwidefsky @@ -1302,6 +1302,7 @@ static struct ccw_driver tape_34xx_driver = { .remove = tape_generic_remove, .set_online = tape_34xx_online, .set_offline = tape_generic_offline, + .freeze = tape_generic_pm_suspend, }; static int diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index c453b2f..23e6598 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.c * tape device discipline for 3590 tapes. * - * Copyright IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -1715,6 +1715,7 @@ static struct ccw_driver tape_3590_driver = { .remove = tape_generic_remove, .set_offline = tape_generic_offline, .set_online = tape_3590_online, + .freeze = tape_generic_pm_suspend, }; /* diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 8a109f3..3ebaa8e 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -3,7 +3,7 @@ * basic function of the tape device driver * * S390 and zSeries version - * Copyright IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh @@ -380,6 +380,55 @@ tape_cleanup_device(struct tape_device *device) } /* + * Suspend device. + * + * Called by the common I/O layer if the drive should be suspended on user + * request. We refuse to suspend if the device is loaded or in use for the + * following reason: + * While the Linux guest is suspended, it might be logged off which causes + * devices to be detached. Tape devices are automatically rewound and unloaded + * during DETACH processing (unless the tape device was attached with the + * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to + * resume the original state of the tape device, since we would need to + * manually re-load the cartridge which was active at suspend time. + */ +int tape_generic_pm_suspend(struct ccw_device *cdev) +{ + struct tape_device *device; + + device = cdev->dev.driver_data; + if (!device) { + return -ENODEV; + } + + DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n", + device->cdev_id, device); + + if (device->medium_state != MS_UNLOADED) { + pr_err("A cartridge is loaded in tape device %s, " + "refusing to suspend\n", dev_name(&cdev->dev)); + return -EBUSY; + } + + spin_lock_irq(get_ccwdev_lock(device->cdev)); + switch (device->tape_state) { + case TS_INIT: + case TS_NOT_OPER: + case TS_UNUSED: + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + break; + default: + pr_err("Tape device %s is busy, refusing to " + "suspend\n", dev_name(&cdev->dev)); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + return -EBUSY; + } + + DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id); + return 0; +} + +/* * Set device offline. * * Called by the common I/O layer if the drive should set offline on user @@ -1273,6 +1322,7 @@ EXPORT_SYMBOL(tape_generic_remove); EXPORT_SYMBOL(tape_generic_probe); EXPORT_SYMBOL(tape_generic_online); EXPORT_SYMBOL(tape_generic_offline); +EXPORT_SYMBOL(tape_generic_pm_suspend); EXPORT_SYMBOL(tape_put_device); EXPORT_SYMBOL(tape_get_device_reference); EXPORT_SYMBOL(tape_state_verbose); -- cgit v0.10.2 From 62b7494209495847269a6ce0504cbefd23d42eb1 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 16 Jun 2009 10:30:40 +0200 Subject: [S390] pm: power management support for SCLP drivers. The SCLP base driver defines a new notifier call back for all upper level SCLP drivers, like the SCLP console, etc. This guarantees that in suspend first the upper level drivers are suspended and afterwards the SCLP base driver. For resume it is the other way round. The SCLP base driver itself registers a new platform device at the platform bus and gets PM notifications via the dev_pm_ops. In suspend, the SCLP base driver switches off the receiver and sender mask This is done in sclp_deactivate(). After suspend all new requests will be rejected with -EIO and no more interrupts will be received, because the masks are switched off. For resume the sender and receiver masks are reset in the sclp_reactivate() function. When the SCLP console is suspended, all new messages are cached in the sclp console buffers. In resume, all the cached messages are written to the console. In addition to that we have an early resume function that removes the cached messages from the suspend image. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 4377e93..a983f50 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/sclp.c - * core function to access sclp interface + * core function to access sclp interface * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * + * Author(s): Martin Peschke + * Martin Schwidefsky */ #include @@ -16,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include @@ -47,6 +49,16 @@ static struct sclp_req sclp_init_req; static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +/* Suspend request */ +static DECLARE_COMPLETION(sclp_request_queue_flushed); + +static void sclp_suspend_req_cb(struct sclp_req *req, void *data) +{ + complete(&sclp_request_queue_flushed); +} + +static struct sclp_req sclp_suspend_req; + /* Timer for request retries. */ static struct timer_list sclp_request_timer; @@ -84,6 +96,12 @@ static volatile enum sclp_mask_state_t { sclp_mask_state_initializing } sclp_mask_state = sclp_mask_state_idle; +/* Internal state: is the driver suspended? */ +static enum sclp_suspend_state_t { + sclp_suspend_state_running, + sclp_suspend_state_suspended, +} sclp_suspend_state = sclp_suspend_state_running; + /* Maximum retry counts */ #define SCLP_INIT_RETRY 3 #define SCLP_MASK_RETRY 3 @@ -211,6 +229,8 @@ sclp_process_queue(void) del_timer(&sclp_request_timer); while (!list_empty(&sclp_req_queue)) { req = list_entry(sclp_req_queue.next, struct sclp_req, list); + if (!req->sccb) + goto do_post; rc = __sclp_start_request(req); if (rc == 0) break; @@ -222,6 +242,7 @@ sclp_process_queue(void) sclp_request_timeout, 0); break; } +do_post: /* Post-processing for aborted request */ list_del(&req->list); if (req->callback) { @@ -233,6 +254,19 @@ sclp_process_queue(void) spin_unlock_irqrestore(&sclp_lock, flags); } +static int __sclp_can_add_request(struct sclp_req *req) +{ + if (req == &sclp_suspend_req || req == &sclp_init_req) + return 1; + if (sclp_suspend_state != sclp_suspend_state_running) + return 0; + if (sclp_init_state != sclp_init_state_initialized) + return 0; + if (sclp_activation_state != sclp_activation_state_active) + return 0; + return 1; +} + /* Queue a new request. Return zero on success, non-zero otherwise. */ int sclp_add_request(struct sclp_req *req) @@ -241,9 +275,7 @@ sclp_add_request(struct sclp_req *req) int rc; spin_lock_irqsave(&sclp_lock, flags); - if ((sclp_init_state != sclp_init_state_initialized || - sclp_activation_state != sclp_activation_state_active) && - req != &sclp_init_req) { + if (!__sclp_can_add_request(req)) { spin_unlock_irqrestore(&sclp_lock, flags); return -EIO; } @@ -254,10 +286,16 @@ sclp_add_request(struct sclp_req *req) /* Start if request is first in list */ if (sclp_running_state == sclp_running_state_idle && req->list.prev == &sclp_req_queue) { + if (!req->sccb) { + list_del(&req->list); + rc = -ENODATA; + goto out; + } rc = __sclp_start_request(req); if (rc) list_del(&req->list); } +out: spin_unlock_irqrestore(&sclp_lock, flags); return rc; } @@ -560,6 +598,7 @@ sclp_register(struct sclp_register *reg) /* Trigger initial state change callback */ reg->sclp_receive_mask = 0; reg->sclp_send_mask = 0; + reg->pm_event_posted = 0; list_add(®->list, &sclp_reg_list); spin_unlock_irqrestore(&sclp_lock, flags); rc = sclp_init_mask(1); @@ -880,20 +919,134 @@ static struct notifier_block sclp_reboot_notifier = { .notifier_call = sclp_reboot_event }; +/* + * Suspend/resume SCLP notifier implementation + */ + +static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback) +{ + struct sclp_register *reg; + unsigned long flags; + + if (!rollback) { + spin_lock_irqsave(&sclp_lock, flags); + list_for_each_entry(reg, &sclp_reg_list, list) + reg->pm_event_posted = 0; + spin_unlock_irqrestore(&sclp_lock, flags); + } + do { + spin_lock_irqsave(&sclp_lock, flags); + list_for_each_entry(reg, &sclp_reg_list, list) { + if (rollback && reg->pm_event_posted) + goto found; + if (!rollback && !reg->pm_event_posted) + goto found; + } + spin_unlock_irqrestore(&sclp_lock, flags); + return; +found: + spin_unlock_irqrestore(&sclp_lock, flags); + if (reg->pm_event_fn) + reg->pm_event_fn(reg, sclp_pm_event); + reg->pm_event_posted = rollback ? 0 : 1; + } while (1); +} + +/* + * Susend/resume callbacks for platform device + */ + +static int sclp_freeze(struct device *dev) +{ + unsigned long flags; + int rc; + + sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0); + + spin_lock_irqsave(&sclp_lock, flags); + sclp_suspend_state = sclp_suspend_state_suspended; + spin_unlock_irqrestore(&sclp_lock, flags); + + /* Init supend data */ + memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req)); + sclp_suspend_req.callback = sclp_suspend_req_cb; + sclp_suspend_req.status = SCLP_REQ_FILLED; + init_completion(&sclp_request_queue_flushed); + + rc = sclp_add_request(&sclp_suspend_req); + if (rc == 0) + wait_for_completion(&sclp_request_queue_flushed); + else if (rc != -ENODATA) + goto fail_thaw; + + rc = sclp_deactivate(); + if (rc) + goto fail_thaw; + return 0; + +fail_thaw: + spin_lock_irqsave(&sclp_lock, flags); + sclp_suspend_state = sclp_suspend_state_running; + spin_unlock_irqrestore(&sclp_lock, flags); + sclp_pm_event(SCLP_PM_EVENT_THAW, 1); + return rc; +} + +static int sclp_undo_suspend(enum sclp_pm_event event) +{ + unsigned long flags; + int rc; + + rc = sclp_reactivate(); + if (rc) + return rc; + + spin_lock_irqsave(&sclp_lock, flags); + sclp_suspend_state = sclp_suspend_state_running; + spin_unlock_irqrestore(&sclp_lock, flags); + + sclp_pm_event(event, 0); + return 0; +} + +static int sclp_thaw(struct device *dev) +{ + return sclp_undo_suspend(SCLP_PM_EVENT_THAW); +} + +static int sclp_restore(struct device *dev) +{ + return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE); +} + +static struct dev_pm_ops sclp_pm_ops = { + .freeze = sclp_freeze, + .thaw = sclp_thaw, + .restore = sclp_restore, +}; + +static struct platform_driver sclp_pdrv = { + .driver = { + .name = "sclp", + .owner = THIS_MODULE, + .pm = &sclp_pm_ops, + }, +}; + +static struct platform_device *sclp_pdev; + /* Initialize SCLP driver. Return zero if driver is operational, non-zero * otherwise. */ static int sclp_init(void) { unsigned long flags; - int rc; + int rc = 0; spin_lock_irqsave(&sclp_lock, flags); /* Check for previous or running initialization */ - if (sclp_init_state != sclp_init_state_uninitialized) { - spin_unlock_irqrestore(&sclp_lock, flags); - return 0; - } + if (sclp_init_state != sclp_init_state_uninitialized) + goto fail_unlock; sclp_init_state = sclp_init_state_initializing; /* Set up variables */ INIT_LIST_HEAD(&sclp_req_queue); @@ -904,27 +1057,17 @@ sclp_init(void) spin_unlock_irqrestore(&sclp_lock, flags); rc = sclp_check_interface(); spin_lock_irqsave(&sclp_lock, flags); - if (rc) { - sclp_init_state = sclp_init_state_uninitialized; - spin_unlock_irqrestore(&sclp_lock, flags); - return rc; - } + if (rc) + goto fail_init_state_uninitialized; /* Register reboot handler */ rc = register_reboot_notifier(&sclp_reboot_notifier); - if (rc) { - sclp_init_state = sclp_init_state_uninitialized; - spin_unlock_irqrestore(&sclp_lock, flags); - return rc; - } + if (rc) + goto fail_init_state_uninitialized; /* Register interrupt handler */ rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, &ext_int_info_hwc); - if (rc) { - unregister_reboot_notifier(&sclp_reboot_notifier); - sclp_init_state = sclp_init_state_uninitialized; - spin_unlock_irqrestore(&sclp_lock, flags); - return rc; - } + if (rc) + goto fail_unregister_reboot_notifier; sclp_init_state = sclp_init_state_initialized; spin_unlock_irqrestore(&sclp_lock, flags); /* Enable service-signal external interruption - needs to happen with @@ -932,11 +1075,56 @@ sclp_init(void) ctl_set_bit(0, 9); sclp_init_mask(1); return 0; + +fail_unregister_reboot_notifier: + unregister_reboot_notifier(&sclp_reboot_notifier); +fail_init_state_uninitialized: + sclp_init_state = sclp_init_state_uninitialized; +fail_unlock: + spin_unlock_irqrestore(&sclp_lock, flags); + return rc; } +/* + * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able + * to print the panic message. + */ +static int sclp_panic_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + if (sclp_suspend_state == sclp_suspend_state_suspended) + sclp_undo_suspend(SCLP_PM_EVENT_THAW); + return NOTIFY_OK; +} + +static struct notifier_block sclp_on_panic_nb = { + .notifier_call = sclp_panic_notify, + .priority = SCLP_PANIC_PRIO, +}; + static __init int sclp_initcall(void) { + int rc; + + rc = platform_driver_register(&sclp_pdrv); + if (rc) + return rc; + sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); + rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; + if (rc) + goto fail_platform_driver_unregister; + rc = atomic_notifier_chain_register(&panic_notifier_list, + &sclp_on_panic_nb); + if (rc) + goto fail_platform_device_unregister; + return sclp_init(); + +fail_platform_device_unregister: + platform_device_unregister(sclp_pdev); +fail_platform_driver_unregister: + platform_driver_unregister(&sclp_pdrv); + return rc; } arch_initcall(sclp_initcall); diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index bac80e8..60e7cb0 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -1,10 +1,8 @@ /* - * drivers/s390/char/sclp.h + * Copyright IBM Corp. 1999, 2009 * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Author(s): Martin Peschke + * Martin Schwidefsky */ #ifndef __SCLP_H__ @@ -17,7 +15,7 @@ /* maximum number of pages concerning our own memory management */ #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) -#define MAX_CONSOLE_PAGES 4 +#define MAX_CONSOLE_PAGES 6 #define EVTYP_OPCMD 0x01 #define EVTYP_MSG 0x02 @@ -68,6 +66,15 @@ typedef unsigned int sclp_cmdw_t; #define GDS_KEY_SELFDEFTEXTMSG 0x31 +enum sclp_pm_event { + SCLP_PM_EVENT_FREEZE, + SCLP_PM_EVENT_THAW, + SCLP_PM_EVENT_RESTORE, +}; + +#define SCLP_PANIC_PRIO 1 +#define SCLP_PANIC_PRIO_CLIENT 0 + typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ struct sccb_header { @@ -134,6 +141,10 @@ struct sclp_register { void (*state_change_fn)(struct sclp_register *); /* called for events in cp_receive_mask/sclp_receive_mask */ void (*receiver_fn)(struct evbuf_header *); + /* called for power management events */ + void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event); + /* pm event posted flag */ + int pm_event_posted; }; /* externals from sclp.c */ diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 9a25c4b..336811a 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -1,11 +1,9 @@ /* - * drivers/s390/char/sclp_con.c - * SCLP line mode console driver + * SCLP line mode console driver * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * Author(s): Martin Peschke + * Martin Schwidefsky */ #include @@ -32,13 +30,14 @@ static spinlock_t sclp_con_lock; static struct list_head sclp_con_pages; /* List of full struct sclp_buffer structures ready for output */ static struct list_head sclp_con_outqueue; -/* Counter how many buffers are emitted (max 1) and how many */ -/* are on the output queue. */ -static int sclp_con_buffer_count; /* Pointer to current console buffer */ static struct sclp_buffer *sclp_conbuf; /* Timer for delayed output of console messages */ static struct timer_list sclp_con_timer; +/* Suspend mode flag */ +static int sclp_con_suspended; +/* Flag that output queue is currently running */ +static int sclp_con_queue_running; /* Output format for console messages */ static unsigned short sclp_con_columns; @@ -53,42 +52,71 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc) do { page = sclp_unmake_buffer(buffer); spin_lock_irqsave(&sclp_con_lock, flags); + /* Remove buffer from outqueue */ list_del(&buffer->list); - sclp_con_buffer_count--; list_add_tail((struct list_head *) page, &sclp_con_pages); + /* Check if there is a pending buffer on the out queue. */ buffer = NULL; if (!list_empty(&sclp_con_outqueue)) - buffer = list_entry(sclp_con_outqueue.next, - struct sclp_buffer, list); + buffer = list_first_entry(&sclp_con_outqueue, + struct sclp_buffer, list); + if (!buffer || sclp_con_suspended) { + sclp_con_queue_running = 0; + spin_unlock_irqrestore(&sclp_con_lock, flags); + break; + } spin_unlock_irqrestore(&sclp_con_lock, flags); - } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); + } while (sclp_emit_buffer(buffer, sclp_conbuf_callback)); } -static void -sclp_conbuf_emit(void) +/* + * Finalize and emit first pending buffer. + */ +static void sclp_conbuf_emit(void) { struct sclp_buffer* buffer; unsigned long flags; - int count; int rc; spin_lock_irqsave(&sclp_con_lock, flags); - buffer = sclp_conbuf; + if (sclp_conbuf) + list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue); sclp_conbuf = NULL; - if (buffer == NULL) { - spin_unlock_irqrestore(&sclp_con_lock, flags); - return; - } - list_add_tail(&buffer->list, &sclp_con_outqueue); - count = sclp_con_buffer_count++; + if (sclp_con_queue_running || sclp_con_suspended) + goto out_unlock; + if (list_empty(&sclp_con_outqueue)) + goto out_unlock; + buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer, + list); + sclp_con_queue_running = 1; spin_unlock_irqrestore(&sclp_con_lock, flags); - if (count) - return; + rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); if (rc) sclp_conbuf_callback(buffer, rc); + return; +out_unlock: + spin_unlock_irqrestore(&sclp_con_lock, flags); +} + +/* + * Wait until out queue is empty + */ +static void sclp_console_sync_queue(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_con_lock, flags); + if (timer_pending(&sclp_con_timer)) + del_timer_sync(&sclp_con_timer); + while (sclp_con_queue_running) { + spin_unlock_irqrestore(&sclp_con_lock, flags); + sclp_sync_wait(); + spin_lock_irqsave(&sclp_con_lock, flags); + } + spin_unlock_irqrestore(&sclp_con_lock, flags); } /* @@ -123,6 +151,8 @@ sclp_console_write(struct console *console, const char *message, /* make sure we have a console output buffer */ if (sclp_conbuf == NULL) { while (list_empty(&sclp_con_pages)) { + if (sclp_con_suspended) + goto out; spin_unlock_irqrestore(&sclp_con_lock, flags); sclp_sync_wait(); spin_lock_irqsave(&sclp_con_lock, flags); @@ -157,6 +187,7 @@ sclp_console_write(struct console *console, const char *message, sclp_con_timer.expires = jiffies + HZ/10; add_timer(&sclp_con_timer); } +out: spin_unlock_irqrestore(&sclp_con_lock, flags); } @@ -168,30 +199,43 @@ sclp_console_device(struct console *c, int *index) } /* - * This routine is called from panic when the kernel - * is going to give up. We have to make sure that all buffers - * will be flushed to the SCLP. + * Make sure that all buffers will be flushed to the SCLP. */ static void sclp_console_flush(void) { + sclp_conbuf_emit(); + sclp_console_sync_queue(); +} + +/* + * Resume console: If there are cached messages, emit them. + */ +static void sclp_console_resume(void) +{ unsigned long flags; + spin_lock_irqsave(&sclp_con_lock, flags); + sclp_con_suspended = 0; + spin_unlock_irqrestore(&sclp_con_lock, flags); sclp_conbuf_emit(); +} + +/* + * Suspend console: Set suspend flag and flush console + */ +static void sclp_console_suspend(void) +{ + unsigned long flags; + spin_lock_irqsave(&sclp_con_lock, flags); - if (timer_pending(&sclp_con_timer)) - del_timer(&sclp_con_timer); - while (sclp_con_buffer_count > 0) { - spin_unlock_irqrestore(&sclp_con_lock, flags); - sclp_sync_wait(); - spin_lock_irqsave(&sclp_con_lock, flags); - } + sclp_con_suspended = 1; spin_unlock_irqrestore(&sclp_con_lock, flags); + sclp_console_flush(); } -static int -sclp_console_notify(struct notifier_block *self, - unsigned long event, void *data) +static int sclp_console_notify(struct notifier_block *self, + unsigned long event, void *data) { sclp_console_flush(); return NOTIFY_OK; @@ -199,7 +243,7 @@ sclp_console_notify(struct notifier_block *self, static struct notifier_block on_panic_nb = { .notifier_call = sclp_console_notify, - .priority = 1, + .priority = SCLP_PANIC_PRIO_CLIENT, }; static struct notifier_block on_reboot_nb = { @@ -221,6 +265,22 @@ static struct console sclp_console = }; /* + * This function is called for SCLP suspend and resume events. + */ +void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) +{ + switch (sclp_pm_event) { + case SCLP_PM_EVENT_FREEZE: + sclp_console_suspend(); + break; + case SCLP_PM_EVENT_RESTORE: + case SCLP_PM_EVENT_THAW: + sclp_console_resume(); + break; + } +} + +/* * called by console_init() in drivers/char/tty_io.c at boot-time. */ static int __init @@ -243,7 +303,6 @@ sclp_console_init(void) } INIT_LIST_HEAD(&sclp_con_outqueue); spin_lock_init(&sclp_con_lock); - sclp_con_buffer_count = 0; sclp_conbuf = NULL; init_timer(&sclp_con_timer); diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 710af42..4be63be 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/sclp_rw.c - * driver: reading from and writing to system console on S/390 via SCLP + * driver: reading from and writing to system console on S/390 via SCLP * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * + * Author(s): Martin Peschke + * Martin Schwidefsky */ #include @@ -26,9 +25,16 @@ */ #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) +static void sclp_rw_pm_event(struct sclp_register *reg, + enum sclp_pm_event sclp_pm_event) +{ + sclp_console_pm_event(sclp_pm_event); +} + /* Event type structure for write message and write priority message */ static struct sclp_register sclp_rw_event = { - .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK + .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK, + .pm_event_fn = sclp_rw_pm_event, }; /* diff --git a/drivers/s390/char/sclp_rw.h b/drivers/s390/char/sclp_rw.h index 6aa7a69..85f491e 100644 --- a/drivers/s390/char/sclp_rw.h +++ b/drivers/s390/char/sclp_rw.h @@ -1,11 +1,10 @@ /* - * drivers/s390/char/sclp_rw.h - * interface to the SCLP-read/write driver + * interface to the SCLP-read/write driver * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corporation 1999, 2009 + * + * Author(s): Martin Peschke + * Martin Schwidefsky */ #ifndef __SCLP_RW_H__ @@ -93,4 +92,5 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short); void sclp_set_htab(struct sclp_buffer *, unsigned short); int sclp_chars_in_buffer(struct sclp_buffer *); +void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event); #endif /* __SCLP_RW_H__ */ diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index a839aa5..5518e24 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -1,10 +1,9 @@ /* - * drivers/s390/char/sclp_vt220.c - * SCLP VT220 terminal driver. + * SCLP VT220 terminal driver. * - * S390 version - * Copyright IBM Corp. 2003,2008 - * Author(s): Peter Oberparleiter + * Copyright IBM Corp. 2003, 2009 + * + * Author(s): Peter Oberparleiter */ #include @@ -69,8 +68,11 @@ static struct list_head sclp_vt220_empty; /* List of pending requests */ static struct list_head sclp_vt220_outqueue; -/* Number of requests in outqueue */ -static int sclp_vt220_outqueue_count; +/* Suspend mode flag */ +static int sclp_vt220_suspended; + +/* Flag that output queue is currently running */ +static int sclp_vt220_queue_running; /* Timer used for delaying write requests to merge subsequent messages into * a single buffer */ @@ -92,6 +94,8 @@ static int __initdata sclp_vt220_init_count; static int sclp_vt220_flush_later; static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); +static void sclp_vt220_pm_event_fn(struct sclp_register *reg, + enum sclp_pm_event sclp_pm_event); static int __sclp_vt220_emit(struct sclp_vt220_request *request); static void sclp_vt220_emit_current(void); @@ -100,7 +104,8 @@ static struct sclp_register sclp_vt220_register = { .send_mask = EVTYP_VT220MSG_MASK, .receive_mask = EVTYP_VT220MSG_MASK, .state_change_fn = NULL, - .receiver_fn = sclp_vt220_receiver_fn + .receiver_fn = sclp_vt220_receiver_fn, + .pm_event_fn = sclp_vt220_pm_event_fn, }; @@ -120,15 +125,19 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) spin_lock_irqsave(&sclp_vt220_lock, flags); /* Move request from outqueue to empty queue */ list_del(&request->list); - sclp_vt220_outqueue_count--; list_add_tail((struct list_head *) page, &sclp_vt220_empty); /* Check if there is a pending buffer on the out queue. */ request = NULL; if (!list_empty(&sclp_vt220_outqueue)) request = list_entry(sclp_vt220_outqueue.next, struct sclp_vt220_request, list); + if (!request || sclp_vt220_suspended) { + sclp_vt220_queue_running = 0; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + break; + } spin_unlock_irqrestore(&sclp_vt220_lock, flags); - } while (request && __sclp_vt220_emit(request)); + } while (__sclp_vt220_emit(request)); if (request == NULL && sclp_vt220_flush_later) sclp_vt220_emit_current(); /* Check if the tty needs a wake up call */ @@ -212,26 +221,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request) } /* - * Queue and emit given request. - */ -static void -sclp_vt220_emit(struct sclp_vt220_request *request) -{ - unsigned long flags; - int count; - - spin_lock_irqsave(&sclp_vt220_lock, flags); - list_add_tail(&request->list, &sclp_vt220_outqueue); - count = sclp_vt220_outqueue_count++; - spin_unlock_irqrestore(&sclp_vt220_lock, flags); - /* Emit only the first buffer immediately - callback takes care of - * the rest */ - if (count == 0 && __sclp_vt220_emit(request)) - sclp_vt220_process_queue(request); -} - -/* - * Queue and emit current request. Return zero on success, non-zero otherwise. + * Queue and emit current request. */ static void sclp_vt220_emit_current(void) @@ -241,22 +231,33 @@ sclp_vt220_emit_current(void) struct sclp_vt220_sccb *sccb; spin_lock_irqsave(&sclp_vt220_lock, flags); - request = NULL; - if (sclp_vt220_current_request != NULL) { + if (sclp_vt220_current_request) { sccb = (struct sclp_vt220_sccb *) sclp_vt220_current_request->sclp_req.sccb; /* Only emit buffers with content */ if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) { - request = sclp_vt220_current_request; + list_add_tail(&sclp_vt220_current_request->list, + &sclp_vt220_outqueue); sclp_vt220_current_request = NULL; if (timer_pending(&sclp_vt220_timer)) del_timer(&sclp_vt220_timer); } sclp_vt220_flush_later = 0; } + if (sclp_vt220_queue_running || sclp_vt220_suspended) + goto out_unlock; + if (list_empty(&sclp_vt220_outqueue)) + goto out_unlock; + request = list_first_entry(&sclp_vt220_outqueue, + struct sclp_vt220_request, list); + sclp_vt220_queue_running = 1; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + + if (__sclp_vt220_emit(request)) + sclp_vt220_process_queue(request); + return; +out_unlock: spin_unlock_irqrestore(&sclp_vt220_lock, flags); - if (request != NULL) - sclp_vt220_emit(request); } #define SCLP_NORMAL_WRITE 0x00 @@ -396,7 +397,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, if (sclp_vt220_current_request == NULL) { while (list_empty(&sclp_vt220_empty)) { spin_unlock_irqrestore(&sclp_vt220_lock, flags); - if (may_fail) + if (may_fail || sclp_vt220_suspended) goto out; else sclp_sync_wait(); @@ -531,7 +532,7 @@ sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) static void sclp_vt220_flush_chars(struct tty_struct *tty) { - if (sclp_vt220_outqueue_count == 0) + if (!sclp_vt220_queue_running) sclp_vt220_emit_current(); else sclp_vt220_flush_later = 1; @@ -635,7 +636,6 @@ static int __init __sclp_vt220_init(int num_pages) init_timer(&sclp_vt220_timer); sclp_vt220_current_request = NULL; sclp_vt220_buffered_chars = 0; - sclp_vt220_outqueue_count = 0; sclp_vt220_tty = NULL; sclp_vt220_flush_later = 0; @@ -736,7 +736,7 @@ static void __sclp_vt220_flush_buffer(void) spin_lock_irqsave(&sclp_vt220_lock, flags); if (timer_pending(&sclp_vt220_timer)) del_timer(&sclp_vt220_timer); - while (sclp_vt220_outqueue_count > 0) { + while (sclp_vt220_queue_running) { spin_unlock_irqrestore(&sclp_vt220_lock, flags); sclp_sync_wait(); spin_lock_irqsave(&sclp_vt220_lock, flags); @@ -744,6 +744,46 @@ static void __sclp_vt220_flush_buffer(void) spin_unlock_irqrestore(&sclp_vt220_lock, flags); } +/* + * Resume console: If there are cached messages, emit them. + */ +static void sclp_vt220_resume(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_vt220_lock, flags); + sclp_vt220_suspended = 0; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + sclp_vt220_emit_current(); +} + +/* + * Suspend console: Set suspend flag and flush console + */ +static void sclp_vt220_suspend(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_vt220_lock, flags); + sclp_vt220_suspended = 1; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + __sclp_vt220_flush_buffer(); +} + +static void sclp_vt220_pm_event_fn(struct sclp_register *reg, + enum sclp_pm_event sclp_pm_event) +{ + switch (sclp_pm_event) { + case SCLP_PM_EVENT_FREEZE: + sclp_vt220_suspend(); + break; + case SCLP_PM_EVENT_RESTORE: + case SCLP_PM_EVENT_THAW: + sclp_vt220_resume(); + break; + } +} + static int sclp_vt220_notify(struct notifier_block *self, unsigned long event, void *data) -- cgit v0.10.2 From 6c005961c15ff85fe1047c197d50b843567c89f8 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 16 Jun 2009 10:30:41 +0200 Subject: [S390] iucv: establish reboot notifier To guarantee a proper cleanup, patch adds a reboot notifier to the iucv base code, which disables iucv interrupts, shuts down established iucv pathes, and removes iucv declarations for z/VM. Checks have to be added to the iucv-API functions, whether iucv-buffers removed at reboot time are still declared. Signed-off-by: Ursula Braun Signed-off-by: Martin Schwidefsky diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 61e8038..0e9f212 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -1,7 +1,8 @@ /* * IUCV base infrastructure. * - * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001, 2009 + * * Author(s): * Original source: * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 @@ -45,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -758,6 +760,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp) } EXPORT_SYMBOL(iucv_unregister); +static int iucv_reboot_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + int i, rc; + + get_online_cpus(); + on_each_cpu(iucv_block_cpu, NULL, 1); + preempt_disable(); + for (i = 0; i < iucv_max_pathid; i++) { + if (iucv_path_table[i]) + rc = iucv_sever_pathid(i, NULL); + } + preempt_enable(); + put_online_cpus(); + iucv_disable(); + return NOTIFY_DONE; +} + +static struct notifier_block iucv_reboot_notifier = { + .notifier_call = iucv_reboot_event, +}; + /** * iucv_path_accept * @path: address of iucv path structure @@ -777,6 +801,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } /* Prepare parameter block. */ parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); @@ -792,6 +820,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, path->msglim = parm->ctrl.ipmsglim; path->flags = parm->ctrl.ipflags1; } +out: local_bh_enable(); return rc; } @@ -821,6 +850,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->ctrl.ipmsglim = path->msglim; @@ -855,6 +888,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, rc = -EIO; } } +out: spin_unlock_bh(&iucv_table_lock); return rc; } @@ -876,12 +910,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ippathid = path->pathid; rc = iucv_call_b2f0(IUCV_QUIESCE, parm); +out: local_bh_enable(); return rc; } @@ -903,12 +942,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ippathid = path->pathid; rc = iucv_call_b2f0(IUCV_RESUME, parm); +out: local_bh_enable(); return rc; } @@ -927,6 +971,10 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) int rc; preempt_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } if (iucv_active_cpu != smp_processor_id()) spin_lock_bh(&iucv_table_lock); rc = iucv_sever_pathid(path->pathid, userdata); @@ -934,6 +982,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) list_del_init(&path->list); if (iucv_active_cpu != smp_processor_id()) spin_unlock_bh(&iucv_table_lock); +out: preempt_enable(); return rc; } @@ -956,6 +1005,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->purge.ippathid = path->pathid; @@ -967,6 +1020,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; msg->tag = parm->purge.ipmsgtag; } +out: local_bh_enable(); return rc; } @@ -1043,6 +1097,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, if (msg->flags & IUCV_IPRMDATA) return iucv_message_receive_iprmdata(path, msg, flags, buffer, size, residual); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = (u32)(addr_t) buffer; @@ -1058,6 +1116,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, if (residual) *residual = parm->db.ipbfln1f; } +out: return rc; } EXPORT_SYMBOL(__iucv_message_receive); @@ -1111,6 +1170,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ippathid = path->pathid; @@ -1118,6 +1181,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) parm->db.iptrgcls = msg->class; parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); rc = iucv_call_b2f0(IUCV_REJECT, parm); +out: local_bh_enable(); return rc; } @@ -1145,6 +1209,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { @@ -1162,6 +1230,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, parm->db.iptrgcls = msg->class; } rc = iucv_call_b2f0(IUCV_REPLY, parm); +out: local_bh_enable(); return rc; } @@ -1190,6 +1259,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, union iucv_param *parm; int rc; + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { @@ -1212,6 +1285,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, rc = iucv_call_b2f0(IUCV_SEND, parm); if (!rc) msg->id = parm->db.ipmsgid; +out: return rc; } EXPORT_SYMBOL(__iucv_message_send); @@ -1272,6 +1346,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { @@ -1297,6 +1375,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, rc = iucv_call_b2f0(IUCV_SEND, parm); if (!rc) msg->id = parm->db.ipmsgid; +out: local_bh_enable(); return rc; } @@ -1740,15 +1819,20 @@ static int __init iucv_init(void) rc = register_hotcpu_notifier(&iucv_cpu_notifier); if (rc) goto out_free; + rc = register_reboot_notifier(&iucv_reboot_notifier); + if (rc) + goto out_cpu; ASCEBC(iucv_error_no_listener, 16); ASCEBC(iucv_error_no_memory, 16); ASCEBC(iucv_error_pathid, 16); iucv_available = 1; rc = bus_register(&iucv_bus); if (rc) - goto out_cpu; + goto out_reboot; return 0; +out_reboot: + unregister_reboot_notifier(&iucv_reboot_notifier); out_cpu: unregister_hotcpu_notifier(&iucv_cpu_notifier); out_free: @@ -1783,6 +1867,7 @@ static void __exit iucv_exit(void) list_for_each_entry_safe(p, n, &iucv_work_queue, list) kfree(p); spin_unlock_irq(&iucv_queue_lock); + unregister_reboot_notifier(&iucv_reboot_notifier); unregister_hotcpu_notifier(&iucv_cpu_notifier); for_each_possible_cpu(cpu) { kfree(iucv_param_irq[cpu]); -- cgit v0.10.2 From 672e405b603af0bed99a4c173cdfce9bbf81c963 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 16 Jun 2009 10:30:42 +0200 Subject: [S390] pm: iucv power management callbacks. Patch calls the PM callback functions of iucv-bus devices, which are responsible for removal of their established iucv pathes. The PM freeze callback for the first iucv-bus device disables all iucv interrupts except the connection severed interrupt. The PM freeze callback for the last iucv-bus device shuts down iucv. The PM thaw callback for the first iucv-bus device re-enables iucv if it has been shut down during freeze. If freezing has been interrupted, it re-enables iucv interrupts according to the needs of iucv-exploiters. The PM restore callback for the first iucv-bus device re-enables iucv. Signed-off-by: Ursula Braun Signed-off-by: Martin Schwidefsky diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 0e9f212..c833481d 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -11,6 +11,8 @@ * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * Rewritten for af_iucv: * Martin Schwidefsky + * PM functions: + * Ursula Braun (ursula.braun@de.ibm.com) * * Documentation used: * The original source @@ -77,9 +79,24 @@ static int iucv_bus_match(struct device *dev, struct device_driver *drv) return 0; } +static int iucv_pm_prepare(struct device *); +static void iucv_pm_complete(struct device *); +static int iucv_pm_freeze(struct device *); +static int iucv_pm_thaw(struct device *); +static int iucv_pm_restore(struct device *); + +static struct dev_pm_ops iucv_pm_ops = { + .prepare = iucv_pm_prepare, + .complete = iucv_pm_complete, + .freeze = iucv_pm_freeze, + .thaw = iucv_pm_thaw, + .restore = iucv_pm_restore, +}; + struct bus_type iucv_bus = { .name = "iucv", .match = iucv_bus_match, + .pm = &iucv_pm_ops, }; EXPORT_SYMBOL(iucv_bus); @@ -149,6 +166,7 @@ enum iucv_command_codes { IUCV_RESUME = 14, IUCV_SEVER = 15, IUCV_SETMASK = 16, + IUCV_SETCONTROLMASK = 17, }; /* @@ -366,6 +384,18 @@ static void iucv_allow_cpu(void *data) parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETMASK, parm); + /* + * Enable all iucv control interrupts. + * ipmask contains bits for the different interrupts + * 0x80 - Flag to allow pending connections interrupts + * 0x40 - Flag to allow connection complete interrupts + * 0x20 - Flag to allow connection severed interrupts + * 0x10 - Flag to allow connection quiesced interrupts + * 0x08 - Flag to allow connection resumed interrupts + */ + memset(parm, 0, sizeof(union iucv_param)); + parm->set_mask.ipmask = 0xf8; + iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); /* Set indication that iucv interrupts are allowed for this cpu. */ cpu_set(cpu, iucv_irq_cpumask); } @@ -391,6 +421,31 @@ static void iucv_block_cpu(void *data) } /** + * iucv_block_cpu_almost + * @data: unused + * + * Allow connection-severed interrupts only on this cpu. + */ +static void iucv_block_cpu_almost(void *data) +{ + int cpu = smp_processor_id(); + union iucv_param *parm; + + /* Allow iucv control interrupts only */ + parm = iucv_param_irq[cpu]; + memset(parm, 0, sizeof(union iucv_param)); + parm->set_mask.ipmask = 0x08; + iucv_call_b2f0(IUCV_SETMASK, parm); + /* Allow iucv-severed interrupt only */ + memset(parm, 0, sizeof(union iucv_param)); + parm->set_mask.ipmask = 0x20; + iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); + + /* Clear indication that iucv interrupts are allowed for this cpu. */ + cpu_clear(cpu, iucv_irq_cpumask); +} + +/** * iucv_declare_cpu * @data: unused * @@ -1766,6 +1821,130 @@ static void iucv_external_interrupt(u16 code) spin_unlock(&iucv_queue_lock); } +static int iucv_pm_prepare(struct device *dev) +{ + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_INFO "iucv_pm_prepare\n"); +#endif + if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) + rc = dev->driver->pm->prepare(dev); + return rc; +} + +static void iucv_pm_complete(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_INFO "iucv_pm_complete\n"); +#endif + if (dev->driver && dev->driver->pm && dev->driver->pm->complete) + dev->driver->pm->complete(dev); +} + +/** + * iucv_path_table_empty() - determine if iucv path table is empty + * + * Returns 0 if there are still iucv pathes defined + * 1 if there are no iucv pathes defined + */ +int iucv_path_table_empty(void) +{ + int i; + + for (i = 0; i < iucv_max_pathid; i++) { + if (iucv_path_table[i]) + return 0; + } + return 1; +} + +/** + * iucv_pm_freeze() - Freeze PM callback + * @dev: iucv-based device + * + * disable iucv interrupts + * invoke callback function of the iucv-based driver + * shut down iucv, if no iucv-pathes are established anymore + */ +static int iucv_pm_freeze(struct device *dev) +{ + int cpu; + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "iucv_pm_freeze\n"); +#endif + for_each_cpu_mask_nr(cpu, iucv_irq_cpumask) + smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1); + if (dev->driver && dev->driver->pm && dev->driver->pm->freeze) + rc = dev->driver->pm->freeze(dev); + if (iucv_path_table_empty()) + iucv_disable(); + return rc; +} + +/** + * iucv_pm_thaw() - Thaw PM callback + * @dev: iucv-based device + * + * make iucv ready for use again: allocate path table, declare interrupt buffers + * and enable iucv interrupts + * invoke callback function of the iucv-based driver + */ +static int iucv_pm_thaw(struct device *dev) +{ + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "iucv_pm_thaw\n"); +#endif + if (!iucv_path_table) { + rc = iucv_enable(); + if (rc) + goto out; + } + if (cpus_empty(iucv_irq_cpumask)) { + if (iucv_nonsmp_handler) + /* enable interrupts on one cpu */ + iucv_allow_cpu(NULL); + else + /* enable interrupts on all cpus */ + iucv_setmask_mp(); + } + if (dev->driver && dev->driver->pm && dev->driver->pm->thaw) + rc = dev->driver->pm->thaw(dev); +out: + return rc; +} + +/** + * iucv_pm_restore() - Restore PM callback + * @dev: iucv-based device + * + * make iucv ready for use again: allocate path table, declare interrupt buffers + * and enable iucv interrupts + * invoke callback function of the iucv-based driver + */ +static int iucv_pm_restore(struct device *dev) +{ + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table); +#endif + if (cpus_empty(iucv_irq_cpumask)) { + rc = iucv_query_maxconn(); + rc = iucv_enable(); + if (rc) + goto out; + } + if (dev->driver && dev->driver->pm && dev->driver->pm->restore) + rc = dev->driver->pm->restore(dev); +out: + return rc; +} + /** * iucv_init * -- cgit v0.10.2 From 1175b257c8a2cb384823621cad0c1e0945f74300 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 16 Jun 2009 10:30:43 +0200 Subject: [S390] pm: netiucv power management callbacks. Patch establishes a dummy netiucv device to make sure iucv is notified about suspend/resume even if netiucv is the only loaded iucv-exploting module without any real net_device defined. The PM freeze callback closes all open netiucv connections. Thus the corresponding iucv path is removed. The PM thaw/restore callback re-opens previously closed netiucv connections. Signed-off-by: Ursula Braun Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index aec9e5d..fdb02d0 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,11 +1,15 @@ /* * IUCV network driver * - * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) + * Copyright IBM Corp. 2001, 2009 * - * Sysfs integration and all bugs therein by Cornelia Huck - * (cornelia.huck@de.ibm.com) + * Author(s): + * Original netiucv driver: + * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) + * Sysfs integration and all bugs therein: + * Cornelia Huck (cornelia.huck@de.ibm.com) + * PM functions: + * Ursula Braun (ursula.braun@de.ibm.com) * * Documentation used: * the source of the original IUCV driver by: @@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ #define PRINTK_HEADER " iucv: " /* for debugging */ +/* dummy device to make sure netiucv_pm functions are called */ +static struct device *netiucv_dev; + +static int netiucv_pm_prepare(struct device *); +static void netiucv_pm_complete(struct device *); +static int netiucv_pm_freeze(struct device *); +static int netiucv_pm_restore_thaw(struct device *); + +static struct dev_pm_ops netiucv_pm_ops = { + .prepare = netiucv_pm_prepare, + .complete = netiucv_pm_complete, + .freeze = netiucv_pm_freeze, + .thaw = netiucv_pm_restore_thaw, + .restore = netiucv_pm_restore_thaw, +}; + static struct device_driver netiucv_driver = { .owner = THIS_MODULE, .name = "netiucv", .bus = &iucv_bus, + .pm = &netiucv_pm_ops, }; static int netiucv_callback_connreq(struct iucv_path *, @@ -233,6 +254,7 @@ struct netiucv_priv { fsm_instance *fsm; struct iucv_connection *conn; struct device *dev; + int pm_state; }; /** @@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev) return 0; } +static int netiucv_pm_prepare(struct device *dev) +{ + IUCV_DBF_TEXT(trace, 3, __func__); + return 0; +} + +static void netiucv_pm_complete(struct device *dev) +{ + IUCV_DBF_TEXT(trace, 3, __func__); + return; +} + +/** + * netiucv_pm_freeze() - Freeze PM callback + * @dev: netiucv device + * + * close open netiucv interfaces + */ +static int netiucv_pm_freeze(struct device *dev) +{ + struct netiucv_priv *priv = dev->driver_data; + struct net_device *ndev = NULL; + int rc = 0; + + IUCV_DBF_TEXT(trace, 3, __func__); + if (priv && priv->conn) + ndev = priv->conn->netdev; + if (!ndev) + goto out; + netif_device_detach(ndev); + priv->pm_state = fsm_getstate(priv->fsm); + rc = netiucv_close(ndev); +out: + return rc; +} + +/** + * netiucv_pm_restore_thaw() - Thaw and restore PM callback + * @dev: netiucv device + * + * re-open netiucv interfaces closed during freeze + */ +static int netiucv_pm_restore_thaw(struct device *dev) +{ + struct netiucv_priv *priv = dev->driver_data; + struct net_device *ndev = NULL; + int rc = 0; + + IUCV_DBF_TEXT(trace, 3, __func__); + if (priv && priv->conn) + ndev = priv->conn->netdev; + if (!ndev) + goto out; + switch (priv->pm_state) { + case DEV_STATE_RUNNING: + case DEV_STATE_STARTWAIT: + rc = netiucv_open(ndev); + break; + default: + break; + } + netif_device_attach(ndev); +out: + return rc; +} + /** * Start transmission of a packet. * Called from generic network device layer. @@ -1731,7 +1819,6 @@ static int netiucv_register_device(struct net_device *ndev) struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); int ret; - IUCV_DBF_TEXT(trace, 3, __func__); if (dev) { @@ -2100,6 +2187,7 @@ static void __exit netiucv_exit(void) netiucv_unregister_device(dev); } + device_unregister(netiucv_dev); driver_unregister(&netiucv_driver); iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); @@ -2125,10 +2213,25 @@ static int __init netiucv_init(void) IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); goto out_iucv; } - + /* establish dummy device */ + netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!netiucv_dev) { + rc = -ENOMEM; + goto out_driver; + } + dev_set_name(netiucv_dev, "netiucv"); + netiucv_dev->bus = &iucv_bus; + netiucv_dev->parent = iucv_root; + netiucv_dev->release = (void (*)(struct device *))kfree; + netiucv_dev->driver = &netiucv_driver; + rc = device_register(netiucv_dev); + if (rc) + goto out_driver; netiucv_banner(); return rc; +out_driver: + driver_unregister(&netiucv_driver); out_iucv: iucv_unregister(&netiucv_handler, 1); out_dbf: -- cgit v0.10.2 From c23cad923bfebd295ec49dc9265569993903488d Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 16 Jun 2009 10:30:44 +0200 Subject: [S390] PM: af_iucv power management callbacks. Patch establishes a dummy afiucv-device to make sure af_iucv is notified as iucv-bus device about suspend/resume. The PM freeze callback severs all iucv pathes of connected af_iucv sockets. The PM thaw/restore callback switches the state of all previously connected sockets to IUCV_DISCONN. Signed-off-by: Ursula Braun Signed-off-by: Martin Schwidefsky diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index a9b3a6f..656cbd1 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1,11 +1,12 @@ /* - * linux/net/iucv/af_iucv.c - * * IUCV protocol stack for Linux on zSeries * - * Copyright 2006 IBM Corporation + * Copyright IBM Corp. 2006, 2009 * * Author(s): Jennifer Hunt + * Hendrik Brueckner + * PM functions: + * Ursula Braun */ #define KMSG_COMPONENT "af_iucv" @@ -90,6 +91,122 @@ static inline void low_nmcpy(unsigned char *dst, char *src) memcpy(&dst[8], src, 8); } +static int afiucv_pm_prepare(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_prepare\n"); +#endif + return 0; +} + +static void afiucv_pm_complete(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_complete\n"); +#endif + return; +} + +/** + * afiucv_pm_freeze() - Freeze PM callback + * @dev: AFIUCV dummy device + * + * Sever all established IUCV communication pathes + */ +static int afiucv_pm_freeze(struct device *dev) +{ + struct iucv_sock *iucv; + struct sock *sk; + struct hlist_node *node; + int err = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_freeze\n"); +#endif + read_lock(&iucv_sk_list.lock); + sk_for_each(sk, node, &iucv_sk_list.head) { + iucv = iucv_sk(sk); + skb_queue_purge(&iucv->send_skb_q); + skb_queue_purge(&iucv->backlog_skb_q); + switch (sk->sk_state) { + case IUCV_SEVERED: + case IUCV_DISCONN: + case IUCV_CLOSING: + case IUCV_CONNECTED: + if (iucv->path) { + err = iucv_path_sever(iucv->path, NULL); + iucv_path_free(iucv->path); + iucv->path = NULL; + } + break; + case IUCV_OPEN: + case IUCV_BOUND: + case IUCV_LISTEN: + case IUCV_CLOSED: + default: + break; + } + } + read_unlock(&iucv_sk_list.lock); + return err; +} + +/** + * afiucv_pm_restore_thaw() - Thaw and restore PM callback + * @dev: AFIUCV dummy device + * + * socket clean up after freeze + */ +static int afiucv_pm_restore_thaw(struct device *dev) +{ + struct iucv_sock *iucv; + struct sock *sk; + struct hlist_node *node; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_restore_thaw\n"); +#endif + read_lock(&iucv_sk_list.lock); + sk_for_each(sk, node, &iucv_sk_list.head) { + iucv = iucv_sk(sk); + switch (sk->sk_state) { + case IUCV_CONNECTED: + sk->sk_err = EPIPE; + sk->sk_state = IUCV_DISCONN; + sk->sk_state_change(sk); + break; + case IUCV_DISCONN: + case IUCV_SEVERED: + case IUCV_CLOSING: + case IUCV_LISTEN: + case IUCV_BOUND: + case IUCV_OPEN: + default: + break; + } + } + read_unlock(&iucv_sk_list.lock); + return 0; +} + +static struct dev_pm_ops afiucv_pm_ops = { + .prepare = afiucv_pm_prepare, + .complete = afiucv_pm_complete, + .freeze = afiucv_pm_freeze, + .thaw = afiucv_pm_restore_thaw, + .restore = afiucv_pm_restore_thaw, +}; + +static struct device_driver af_iucv_driver = { + .owner = THIS_MODULE, + .name = "afiucv", + .bus = &iucv_bus, + .pm = &afiucv_pm_ops, +}; + +/* dummy device used as trigger for PM functions */ +static struct device *af_iucv_dev; + /** * iucv_msg_length() - Returns the length of an iucv message. * @msg: Pointer to struct iucv_message, MUST NOT be NULL @@ -1556,8 +1673,30 @@ static int __init afiucv_init(void) err = sock_register(&iucv_sock_family_ops); if (err) goto out_proto; + /* establish dummy device */ + err = driver_register(&af_iucv_driver); + if (err) + goto out_sock; + af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!af_iucv_dev) { + err = -ENOMEM; + goto out_driver; + } + dev_set_name(af_iucv_dev, "af_iucv"); + af_iucv_dev->bus = &iucv_bus; + af_iucv_dev->parent = iucv_root; + af_iucv_dev->release = (void (*)(struct device *))kfree; + af_iucv_dev->driver = &af_iucv_driver; + err = device_register(af_iucv_dev); + if (err) + goto out_driver; + return 0; +out_driver: + driver_unregister(&af_iucv_driver); +out_sock: + sock_unregister(PF_IUCV); out_proto: proto_unregister(&iucv_proto); out_iucv: @@ -1568,6 +1707,8 @@ out: static void __exit afiucv_exit(void) { + device_unregister(af_iucv_dev); + driver_unregister(&af_iucv_driver); sock_unregister(PF_IUCV); proto_unregister(&iucv_proto); iucv_unregister(&af_iucv_handler, 0); -- cgit v0.10.2 From 0259162ecd083f1ce0f6022e669f393330b06f4d Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 16 Jun 2009 10:30:45 +0200 Subject: [S390] pm: hvc_iucv power management callbacks The patch adds supporting for suspending and resuming IUCV HVC terminal devices from disk. The obligatory Linux device driver interfaces has been added by registering a device driver on the IUCV bus. For each IUCV HVC terminal device the driver creates a respective device on the IUCV bus. To support suspend and resume, the PM freeze callback severs any established IUCV communication path and triggers a HVC tty hang-up when the system image is restored. IUCV communication path are no longer valid when the z/VM guest is halted. The device driver initialization has been updated to register devices and the a new routine has been extracted to facilitate the hang-up of IUCV HVC terminal devices. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 54481a8..86105ef 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -4,7 +4,7 @@ * This HVC device driver provides terminal access using * z/VM IUCV communication paths. * - * Copyright IBM Corp. 2008 + * Copyright IBM Corp. 2008, 2009 * * Author(s): Hendrik Brueckner */ @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ struct hvc_iucv_private { wait_queue_head_t sndbuf_waitq; /* wait for send completion */ struct list_head tty_outqueue; /* outgoing IUCV messages */ struct list_head tty_inqueue; /* incoming IUCV messages */ + struct device *dev; /* device structure */ }; struct iucv_tty_buffer { @@ -542,7 +544,68 @@ static void flush_sndbuf_sync(struct hvc_iucv_private *priv) if (sync_wait) wait_event_timeout(priv->sndbuf_waitq, - tty_outqueue_empty(priv), HZ); + tty_outqueue_empty(priv), HZ/10); +} + +/** + * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up + * @priv: Pointer to hvc_iucv_private structure + * + * This routine severs an existing IUCV communication path and hangs + * up the underlying HVC terminal device. + * The hang-up occurs only if an IUCV communication path is established; + * otherwise there is no need to hang up the terminal device. + * + * The IUCV HVC hang-up is separated into two steps: + * 1. After the IUCV path has been severed, the iucv_state is set to + * IUCV_SEVERED. + * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the + * IUCV_SEVERED state causes the tty hang-up in the HVC layer. + * + * If the tty has not yet been opened, clean up the hvc_iucv_private + * structure to allow re-connects. + * If the tty has been opened, let get_chars() return -EPIPE to signal + * the HVC layer to hang up the tty and, if so, wake up the HVC thread + * to call get_chars()... + * + * Special notes on hanging up a HVC terminal instantiated as console: + * Hang-up: 1. do_tty_hangup() replaces file ops (= hung_up_tty_fops) + * 2. do_tty_hangup() calls tty->ops->close() for console_filp + * => no hangup notifier is called by HVC (default) + * 2. hvc_close() returns because of tty_hung_up_p(filp) + * => no delete notifier is called! + * Finally, the back-end is not being notified, thus, the tty session is + * kept active (TTY_OPEN) to be ready for re-connects. + * + * Locking: spin_lock(&priv->lock) w/o disabling bh + */ +static void hvc_iucv_hangup(struct hvc_iucv_private *priv) +{ + struct iucv_path *path; + + path = NULL; + spin_lock(&priv->lock); + if (priv->iucv_state == IUCV_CONNECTED) { + path = priv->path; + priv->path = NULL; + priv->iucv_state = IUCV_SEVERED; + if (priv->tty_state == TTY_CLOSED) + hvc_iucv_cleanup(priv); + else + /* console is special (see above) */ + if (priv->is_console) { + hvc_iucv_cleanup(priv); + priv->tty_state = TTY_OPENED; + } else + hvc_kick(); + } + spin_unlock(&priv->lock); + + /* finally sever path (outside of priv->lock due to lock ordering) */ + if (path) { + iucv_path_sever(path, NULL); + iucv_path_free(path); + } } /** @@ -735,11 +798,8 @@ out_path_handled: * @ipuser: User specified data for this path * (AF_IUCV: port/service name and originator port) * - * The function also severs the path (as required by the IUCV protocol) and - * sets the iucv state to IUCV_SEVERED for the associated struct - * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty - * hangup (hvc_iucv_get_chars() / hvc_iucv_write()). - * If tty portion of the HVC is closed, clean up the outqueue. + * This function calls the hvc_iucv_hangup() function for the + * respective IUCV HVC terminal. * * Locking: struct hvc_iucv_private->lock */ @@ -747,33 +807,7 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { struct hvc_iucv_private *priv = path->private; - spin_lock(&priv->lock); - priv->iucv_state = IUCV_SEVERED; - - /* If the tty has not yet been opened, clean up the hvc_iucv_private - * structure to allow re-connects. - * This is also done for our console device because console hangups - * are handled specially and no notifier is called by HVC. - * The tty session is active (TTY_OPEN) and ready for re-connects... - * - * If it has been opened, let get_chars() return -EPIPE to signal the - * HVC layer to hang up the tty. - * If so, we need to wake up the HVC thread to call get_chars()... - */ - priv->path = NULL; - if (priv->tty_state == TTY_CLOSED) - hvc_iucv_cleanup(priv); - else - if (priv->is_console) { - hvc_iucv_cleanup(priv); - priv->tty_state = TTY_OPENED; - } else - hvc_kick(); - spin_unlock(&priv->lock); - - /* finally sever path (outside of priv->lock due to lock ordering) */ - iucv_path_sever(path, ipuser); - iucv_path_free(path); + hvc_iucv_hangup(priv); } /** @@ -853,6 +887,37 @@ static void hvc_iucv_msg_complete(struct iucv_path *path, destroy_tty_buffer_list(&list_remove); } +/** + * hvc_iucv_pm_freeze() - Freeze PM callback + * @dev: IUVC HVC terminal device + * + * Sever an established IUCV communication path and + * trigger a hang-up of the underlying HVC terminal. + */ +static int hvc_iucv_pm_freeze(struct device *dev) +{ + struct hvc_iucv_private *priv = dev_get_drvdata(dev); + + local_bh_disable(); + hvc_iucv_hangup(priv); + local_bh_enable(); + + return 0; +} + +/** + * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback + * @dev: IUVC HVC terminal device + * + * Wake up the HVC thread to trigger hang-up and respective + * HVC back-end notifier invocations. + */ +static int hvc_iucv_pm_restore_thaw(struct device *dev) +{ + hvc_kick(); + return 0; +} + /* HVC operations */ static struct hv_ops hvc_iucv_ops = { @@ -863,6 +928,20 @@ static struct hv_ops hvc_iucv_ops = { .notifier_hangup = hvc_iucv_notifier_hangup, }; +/* Suspend / resume device operations */ +static struct dev_pm_ops hvc_iucv_pm_ops = { + .freeze = hvc_iucv_pm_freeze, + .thaw = hvc_iucv_pm_restore_thaw, + .restore = hvc_iucv_pm_restore_thaw, +}; + +/* IUCV HVC device driver */ +static struct device_driver hvc_iucv_driver = { + .name = KMSG_COMPONENT, + .bus = &iucv_bus, + .pm = &hvc_iucv_pm_ops, +}; + /** * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance * @id: hvc_iucv_table index @@ -897,14 +976,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) /* set console flag */ priv->is_console = is_console; - /* finally allocate hvc */ + /* allocate hvc device */ priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); if (IS_ERR(priv->hvc)) { rc = PTR_ERR(priv->hvc); - free_page((unsigned long) priv->sndbuf); - kfree(priv); - return rc; + goto out_error_hvc; } /* notify HVC thread instead of using polling */ @@ -915,8 +992,45 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) memcpy(priv->srv_name, name, 8); ASCEBC(priv->srv_name, 8); + /* create and setup device */ + priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL); + if (!priv->dev) { + rc = -ENOMEM; + goto out_error_dev; + } + dev_set_name(priv->dev, "hvc_iucv%d", id); + dev_set_drvdata(priv->dev, priv); + priv->dev->bus = &iucv_bus; + priv->dev->parent = iucv_root; + priv->dev->driver = &hvc_iucv_driver; + priv->dev->release = (void (*)(struct device *)) kfree; + rc = device_register(priv->dev); + if (rc) { + kfree(priv->dev); + goto out_error_dev; + } + hvc_iucv_table[id] = priv; return 0; + +out_error_dev: + hvc_remove(priv->hvc); +out_error_hvc: + free_page((unsigned long) priv->sndbuf); + kfree(priv); + + return rc; +} + +/** + * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances + */ +static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv) +{ + hvc_remove(priv->hvc); + device_unregister(priv->dev); + free_page((unsigned long) priv->sndbuf); + kfree(priv); } /** @@ -1109,6 +1223,11 @@ static int __init hvc_iucv_init(void) goto out_error; } + /* register IUCV HVC device driver */ + rc = driver_register(&hvc_iucv_driver); + if (rc) + goto out_error; + /* parse hvc_iucv_allow string and create z/VM user ID filter list */ if (hvc_iucv_filter_string) { rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); @@ -1183,15 +1302,14 @@ out_error_iucv: iucv_unregister(&hvc_iucv_handler, 0); out_error_hvc: for (i = 0; i < hvc_iucv_devices; i++) - if (hvc_iucv_table[i]) { - if (hvc_iucv_table[i]->hvc) - hvc_remove(hvc_iucv_table[i]->hvc); - kfree(hvc_iucv_table[i]); - } + if (hvc_iucv_table[i]) + hvc_iucv_destroy(hvc_iucv_table[i]); out_error_memory: mempool_destroy(hvc_iucv_mempool); kmem_cache_destroy(hvc_iucv_buffer_cache); out_error: + if (hvc_iucv_filter) + kfree(hvc_iucv_filter); hvc_iucv_devices = 0; /* ensure that we do not provide any device */ return rc; } -- cgit v0.10.2 From 6a1d96dced593bc17d7a17fdb93c99b275e71eba Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 16 Jun 2009 10:30:46 +0200 Subject: [S390] pm: smsgiucv power management callbacks. Create dummy iucv-device to get control when the system is suspended and resumed. Server the smsg iucv path on suspend, reestablish the path on resume. Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 164e090..e76a320 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -1,7 +1,8 @@ /* * IUCV special message driver * - * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2003, 2009 + * * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -40,6 +41,8 @@ MODULE_AUTHOR MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); static struct iucv_path *smsg_path; +/* dummy device used as trigger for PM functions */ +static struct device *smsg_dev; static DEFINE_SPINLOCK(smsg_list_lock); static LIST_HEAD(smsg_list); @@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix, kfree(cb); } +static int smsg_pm_freeze(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "smsg_pm_freeze\n"); +#endif + if (smsg_path) + iucv_path_sever(smsg_path, NULL); + return 0; +} + +static int smsg_pm_restore_thaw(struct device *dev) +{ + int rc; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "smsg_pm_restore_thaw\n"); +#endif + if (smsg_path) { + memset(smsg_path, 0, sizeof(*smsg_path)); + smsg_path->msglim = 255; + smsg_path->flags = 0; + rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", + NULL, NULL, NULL); + printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc); + } + return 0; +} + +static struct dev_pm_ops smsg_pm_ops = { + .freeze = smsg_pm_freeze, + .thaw = smsg_pm_restore_thaw, + .restore = smsg_pm_restore_thaw, +}; + static struct device_driver smsg_driver = { + .owner = THIS_MODULE, .name = "SMSGIUCV", .bus = &iucv_bus, + .pm = &smsg_pm_ops, }; static void __exit smsg_exit(void) { cpcmd("SET SMSG IUCV", NULL, 0, NULL); + device_unregister(smsg_dev); iucv_unregister(&smsg_handler, 1); driver_unregister(&smsg_driver); } @@ -166,12 +206,29 @@ static int __init smsg_init(void) rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", NULL, NULL, NULL); if (rc) - goto out_free; + goto out_free_path; + smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!smsg_dev) { + rc = -ENOMEM; + goto out_free_path; + } + dev_set_name(smsg_dev, "smsg_iucv"); + smsg_dev->bus = &iucv_bus; + smsg_dev->parent = iucv_root; + smsg_dev->release = (void (*)(struct device *))kfree; + smsg_dev->driver = &smsg_driver; + rc = device_register(smsg_dev); + if (rc) + goto out_free_dev; + cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; -out_free: +out_free_dev: + kfree(smsg_dev); +out_free_path: iucv_path_free(smsg_path); + smsg_path = NULL; out_register: iucv_unregister(&smsg_handler, 1); out_driver: -- cgit v0.10.2 From 4b214a0c7720bfcfaca936047a359f8859fc8424 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 16 Jun 2009 10:30:47 +0200 Subject: [S390] pm: con3270 power management callbacks. Introduce the power management callbacks to the 3270 driver. On suspend the current 3270 view is deactivated and for non-console 3270 device the release callback is done. This disconnects the current tty / fullscreen application from the 3270 device. On resume the current view is reactivated, on the tty you get a fresh login. If the system panics before the 3270 device has been resumed, the ccw device for the 3270 console is reactivated with ccw_device_force_console. Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index ed5396d..44d02e3 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/con3270.c - * IBM/3270 Driver - console view. + * IBM/3270 Driver - console view. * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ #include @@ -530,6 +529,7 @@ con3270_flush(void) cp = condev; if (!cp->view.dev) return; + raw3270_pm_unfreeze(&cp->view); spin_lock_irqsave(&cp->view.lock, flags); con3270_wait_write(cp); cp->nr_up = 0; diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 40759c3..097d384 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/fs3270.c - * IBM/3270 Driver - fullscreen driver. + * IBM/3270 Driver - fullscreen driver. * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5/2.6 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5/2.6 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ #include @@ -399,6 +398,11 @@ fs3270_free_view(struct raw3270_view *view) static void fs3270_release(struct raw3270_view *view) { + struct fs3270 *fp; + + fp = (struct fs3270 *) view; + if (fp->fs_pid) + kill_pid(fp->fs_pid, SIGHUP, 1); } /* View to a 3270 device. Can be console, tty or fullscreen. */ diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 0b15cf1..81c151b 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/raw3270.c - * IBM/3270 Driver - core functions. + * IBM/3270 Driver - core functions. * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ #include @@ -61,6 +60,7 @@ struct raw3270 { #define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ #define RAW3270_FLAGS_READY 4 /* Device is useable by views */ #define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */ +#define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */ /* Semaphore to protect global data of raw3270 (devices, views, etc). */ static DEFINE_MUTEX(raw3270_mutex); @@ -306,7 +306,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq) spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags); rp = view->dev; - if (!rp || rp->view != view) + if (!rp || rp->view != view || + test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) rc = -EACCES; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; @@ -323,7 +324,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq) int rc; rp = view->dev; - if (!rp || rp->view != view) + if (!rp || rp->view != view || + test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) rc = -EACCES; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; @@ -764,7 +766,8 @@ raw3270_reset(struct raw3270_view *view) int rc; rp = view->dev; - if (!rp || rp->view != view) + if (!rp || rp->view != view || + test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) rc = -EACCES; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; @@ -922,6 +925,8 @@ raw3270_activate_view(struct raw3270_view *view) rc = 0; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; + else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) + rc = -EACCES; else { oldview = NULL; if (rp->view) { @@ -969,7 +974,8 @@ raw3270_deactivate_view(struct raw3270_view *view) list_del_init(&view->list); list_add_tail(&view->list, &rp->view_list); /* Try to activate another view. */ - if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { + if (test_bit(RAW3270_FLAGS_READY, &rp->flags) && + !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { list_for_each_entry(view, &rp->view_list, list) { rp->view = view; if (view->fn->activate(view) == 0) @@ -1068,7 +1074,8 @@ raw3270_del_view(struct raw3270_view *view) rp->view = NULL; } list_del_init(&view->list); - if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { + if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) && + !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { /* Try to activate another view. */ list_for_each_entry(nv, &rp->view_list, list) { if (nv->fn->activate(nv) == 0) { @@ -1337,6 +1344,58 @@ raw3270_set_offline (struct ccw_device *cdev) return 0; } +static int raw3270_pm_stop(struct ccw_device *cdev) +{ + struct raw3270 *rp; + struct raw3270_view *view; + unsigned long flags; + + rp = cdev->dev.driver_data; + if (!rp) + return 0; + spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); + if (rp->view) + rp->view->fn->deactivate(rp->view); + if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) { + /* + * Release tty and fullscreen for all non-console + * devices. + */ + list_for_each_entry(view, &rp->view_list, list) { + if (view->fn->release) + view->fn->release(view); + } + } + set_bit(RAW3270_FLAGS_FROZEN, &rp->flags); + spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); + return 0; +} + +static int raw3270_pm_start(struct ccw_device *cdev) +{ + struct raw3270 *rp; + unsigned long flags; + + rp = cdev->dev.driver_data; + if (!rp) + return 0; + spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); + clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags); + if (rp->view) + rp->view->fn->activate(rp->view); + spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); + return 0; +} + +void raw3270_pm_unfreeze(struct raw3270_view *view) +{ + struct raw3270 *rp; + + rp = view->dev; + if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) + ccw_device_force_console(); +} + static struct ccw_device_id raw3270_id[] = { { CCW_DEVICE(0x3270, 0) }, { CCW_DEVICE(0x3271, 0) }, @@ -1360,6 +1419,9 @@ static struct ccw_driver raw3270_ccw_driver = { .remove = &raw3270_remove, .set_online = &raw3270_set_online, .set_offline = &raw3270_set_offline, + .freeze = &raw3270_pm_stop, + .thaw = &raw3270_pm_start, + .restore = &raw3270_pm_start, }; static int diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h index 90beaa8..ed34eb2 100644 --- a/drivers/s390/char/raw3270.h +++ b/drivers/s390/char/raw3270.h @@ -1,11 +1,10 @@ /* - * drivers/s390/char/raw3270.h - * IBM/3270 Driver + * IBM/3270 Driver * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ #include @@ -195,6 +194,7 @@ void raw3270_wait_cons_dev(struct raw3270 *); /* Notifier for device addition/removal */ int raw3270_register_notifier(void (*notifier)(int, int)); void raw3270_unregister_notifier(void (*notifier)(int, int)); +void raw3270_pm_unfreeze(struct raw3270_view *); /* * Little memory allocator for string objects. -- cgit v0.10.2 From 039979049834bde56f67f8078c802b416bd4763c Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 16 Jun 2009 10:30:48 +0200 Subject: [S390] pm: memory hotplug power management callbacks Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 77ab6e3..5cc11c6 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -1,9 +1,8 @@ /* - * drivers/s390/char/sclp_cmd.c + * Copyright IBM Corp. 2007, 2009 * - * Copyright IBM Corp. 2007 - * Author(s): Heiko Carstens , - * Peter Oberparleiter + * Author(s): Heiko Carstens , + * Peter Oberparleiter */ #define KMSG_COMPONENT "sclp_cmd" @@ -12,11 +11,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -292,6 +293,7 @@ static DEFINE_MUTEX(sclp_mem_mutex); static LIST_HEAD(sclp_mem_list); static u8 sclp_max_storage_id; static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; +static int sclp_mem_state_changed; struct memory_increment { struct list_head list; @@ -450,6 +452,8 @@ static int sclp_mem_notifier(struct notifier_block *nb, rc = -EINVAL; break; } + if (!rc) + sclp_mem_state_changed = 1; mutex_unlock(&sclp_mem_mutex); return rc ? NOTIFY_BAD : NOTIFY_OK; } @@ -525,6 +529,14 @@ static void __init insert_increment(u16 rn, int standby, int assigned) list_add(&new_incr->list, prev); } +static int sclp_mem_freeze(struct device *dev) +{ + if (!sclp_mem_state_changed) + return 0; + pr_err("Memory hotplug state changed, suspend refused.\n"); + return -EPERM; +} + struct read_storage_sccb { struct sccb_header header; u16 max_id; @@ -534,8 +546,20 @@ struct read_storage_sccb { u32 entries[0]; } __packed; +static struct dev_pm_ops sclp_mem_pm_ops = { + .freeze = sclp_mem_freeze, +}; + +static struct platform_driver sclp_mem_pdrv = { + .driver = { + .name = "sclp_mem", + .pm = &sclp_mem_pm_ops, + }, +}; + static int __init sclp_detect_standby_memory(void) { + struct platform_device *sclp_pdev; struct read_storage_sccb *sccb; int i, id, assigned, rc; @@ -588,7 +612,17 @@ static int __init sclp_detect_standby_memory(void) rc = register_memory_notifier(&sclp_mem_nb); if (rc) goto out; + rc = platform_driver_register(&sclp_mem_pdrv); + if (rc) + goto out; + sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); + rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; + if (rc) + goto out_driver; sclp_add_standby_memory(); + goto out; +out_driver: + platform_driver_unregister(&sclp_mem_pdrv); out: free_page((unsigned long) sccb); return rc; diff --git a/mm/Kconfig b/mm/Kconfig index 71830ba..6f4610a 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -128,11 +128,11 @@ config SPARSEMEM_VMEMMAP config MEMORY_HOTPLUG bool "Allow for memory hot-add" depends on SPARSEMEM || X86_64_ACPI_NUMA - depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG + depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG depends on (IA64 || X86 || PPC64 || SUPERH || S390) comment "Memory hotplug is currently incompatible with Software Suspend" - depends on SPARSEMEM && HOTPLUG && HIBERNATION + depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390 config MEMORY_HOTPLUG_SPARSE def_bool y -- cgit v0.10.2 From fb78140cedcd2805e5cfec12af59c0a6dfa112db Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 16 Jun 2009 10:30:49 +0200 Subject: [S390] pm: monwriter power management callbacks. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index c7d7483..66fb8eb 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -1,9 +1,7 @@ /* - * drivers/s390/char/monwriter.c - * * Character device driver for writing z/VM *MONITOR service records. * - * Copyright (C) IBM Corp. 2006 + * Copyright IBM Corp. 2006, 2009 * * Author(s): Melissa Howland */ @@ -22,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +39,10 @@ struct mon_buf { char *data; }; +static LIST_HEAD(mon_priv_list); + struct mon_private { + struct list_head priv_list; struct list_head list; struct monwrite_hdr hdr; size_t hdr_to_read; @@ -188,6 +190,7 @@ static int monwrite_open(struct inode *inode, struct file *filp) monpriv->hdr_to_read = sizeof(monpriv->hdr); mutex_init(&monpriv->thread_mutex); filp->private_data = monpriv; + list_add_tail(&monpriv->priv_list, &mon_priv_list); unlock_kernel(); return nonseekable_open(inode, filp); } @@ -206,6 +209,7 @@ static int monwrite_close(struct inode *inode, struct file *filp) kfree(entry->data); kfree(entry); } + list_del(&monpriv->priv_list); kfree(monpriv); return 0; } @@ -281,20 +285,102 @@ static struct miscdevice mon_dev = { }; /* + * suspend/resume + */ + +static int monwriter_freeze(struct device *dev) +{ + struct mon_private *monpriv; + struct mon_buf *monbuf; + + list_for_each_entry(monpriv, &mon_priv_list, priv_list) { + list_for_each_entry(monbuf, &monpriv->list, list) { + if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT) + monwrite_diag(&monbuf->hdr, monbuf->data, + APPLDATA_STOP_REC); + } + } + return 0; +} + +static int monwriter_restore(struct device *dev) +{ + struct mon_private *monpriv; + struct mon_buf *monbuf; + + list_for_each_entry(monpriv, &mon_priv_list, priv_list) { + list_for_each_entry(monbuf, &monpriv->list, list) { + if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL) + monwrite_diag(&monbuf->hdr, monbuf->data, + APPLDATA_START_INTERVAL_REC); + if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG) + monwrite_diag(&monbuf->hdr, monbuf->data, + APPLDATA_START_CONFIG_REC); + } + } + return 0; +} + +static int monwriter_thaw(struct device *dev) +{ + return monwriter_restore(dev); +} + +static struct dev_pm_ops monwriter_pm_ops = { + .freeze = monwriter_freeze, + .thaw = monwriter_thaw, + .restore = monwriter_restore, +}; + +static struct platform_driver monwriter_pdrv = { + .driver = { + .name = "monwriter", + .owner = THIS_MODULE, + .pm = &monwriter_pm_ops, + }, +}; + +static struct platform_device *monwriter_pdev; + +/* * module init/exit */ static int __init mon_init(void) { - if (MACHINE_IS_VM) - return misc_register(&mon_dev); - else + int rc; + + if (!MACHINE_IS_VM) return -ENODEV; + + rc = platform_driver_register(&monwriter_pdrv); + if (rc) + return rc; + + monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL, + 0); + if (IS_ERR(monwriter_pdev)) { + rc = PTR_ERR(monwriter_pdev); + goto out_driver; + } + + rc = misc_register(&mon_dev); + if (rc) + goto out_device; + return 0; + +out_device: + platform_device_unregister(monwriter_pdev); +out_driver: + platform_driver_unregister(&monwriter_pdrv); + return rc; } static void __exit mon_exit(void) { WARN_ON(misc_deregister(&mon_dev) != 0); + platform_device_unregister(monwriter_pdev); + platform_driver_unregister(&monwriter_pdrv); } module_init(mon_init); -- cgit v0.10.2 From 2b1e3e5558b9de0f85ed9183a7adb2d61aab363b Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 16 Jun 2009 10:30:50 +0200 Subject: [S390] pm: monreader power management callbacks. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 97e63cf..75a8831 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -1,10 +1,9 @@ /* - * drivers/s390/char/monreader.c - * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright IBM Corp. 2004, 2008 - * Author: Gerald Schaefer + * Copyright IBM Corp. 2004, 2009 + * + * Author: Gerald Schaefer */ #define KMSG_COMPONENT "monreader" @@ -22,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +78,7 @@ static u8 user_data_sever[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; +static struct device *monreader_device; /****************************************************************************** * helper functions * @@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp) goto out_path; } filp->private_data = monpriv; + monreader_device->driver_data = monpriv; unlock_kernel(); return nonseekable_open(inode, filp); out_path: - kfree(monpriv->path); + iucv_path_free(monpriv->path); out_priv: mon_free_mem(monpriv); out_use: @@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp) /* * Close IUCV connection and unregister */ - rc = iucv_path_sever(monpriv->path, user_data_sever); - if (rc) - pr_warning("Disconnecting the z/VM *MONITOR system service " - "failed with rc=%i\n", rc); + if (monpriv->path) { + rc = iucv_path_sever(monpriv->path, user_data_sever); + if (rc) + pr_warning("Disconnecting the z/VM *MONITOR system " + "service failed with rc=%i\n", rc); + iucv_path_free(monpriv->path); + } atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); @@ -452,6 +457,94 @@ static struct miscdevice mon_dev = { .minor = MISC_DYNAMIC_MINOR, }; + +/****************************************************************************** + * suspend / resume * + *****************************************************************************/ +static int monreader_freeze(struct device *dev) +{ + struct mon_private *monpriv = dev->driver_data; + int rc; + + if (!monpriv) + return 0; + if (monpriv->path) { + rc = iucv_path_sever(monpriv->path, user_data_sever); + if (rc) + pr_warning("Disconnecting the z/VM *MONITOR system " + "service failed with rc=%i\n", rc); + iucv_path_free(monpriv->path); + } + atomic_set(&monpriv->iucv_severed, 0); + atomic_set(&monpriv->iucv_connected, 0); + atomic_set(&monpriv->read_ready, 0); + atomic_set(&monpriv->msglim_count, 0); + monpriv->write_index = 0; + monpriv->read_index = 0; + monpriv->path = NULL; + return 0; +} + +static int monreader_thaw(struct device *dev) +{ + struct mon_private *monpriv = dev->driver_data; + int rc; + + if (!monpriv) + return 0; + rc = -ENOMEM; + monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); + if (!monpriv->path) + goto out; + rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, + MON_SERVICE, NULL, user_data_connect, monpriv); + if (rc) { + pr_err("Connecting to the z/VM *MONITOR system service " + "failed with rc=%i\n", rc); + goto out_path; + } + wait_event(mon_conn_wait_queue, + atomic_read(&monpriv->iucv_connected) || + atomic_read(&monpriv->iucv_severed)); + if (atomic_read(&monpriv->iucv_severed)) + goto out_path; + return 0; +out_path: + rc = -EIO; + iucv_path_free(monpriv->path); + monpriv->path = NULL; +out: + atomic_set(&monpriv->iucv_severed, 1); + return rc; +} + +static int monreader_restore(struct device *dev) +{ + int rc; + + segment_unload(mon_dcss_name); + rc = segment_load(mon_dcss_name, SEGMENT_SHARED, + &mon_dcss_start, &mon_dcss_end); + if (rc < 0) { + segment_warning(rc, mon_dcss_name); + panic("fatal monreader resume error: no monitor dcss\n"); + } + return monreader_thaw(dev); +} + +static struct dev_pm_ops monreader_pm_ops = { + .freeze = monreader_freeze, + .thaw = monreader_thaw, + .restore = monreader_restore, +}; + +static struct device_driver monreader_driver = { + .name = "monreader", + .bus = &iucv_bus, + .pm = &monreader_pm_ops, +}; + + /****************************************************************************** * module init/exit * *****************************************************************************/ @@ -475,16 +568,33 @@ static int __init mon_init(void) return rc; } + rc = driver_register(&monreader_driver); + if (rc) + goto out_iucv; + monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!monreader_device) + goto out_driver; + dev_set_name(monreader_device, "monreader-dev"); + monreader_device->bus = &iucv_bus; + monreader_device->parent = iucv_root; + monreader_device->driver = &monreader_driver; + monreader_device->release = (void (*)(struct device *))kfree; + rc = device_register(monreader_device); + if (rc) { + kfree(monreader_device); + goto out_driver; + } + rc = segment_type(mon_dcss_name); if (rc < 0) { segment_warning(rc, mon_dcss_name); - goto out_iucv; + goto out_device; } if (rc != SEG_TYPE_SC) { pr_err("The specified *MONITOR DCSS %s does not have the " "required type SC\n", mon_dcss_name); rc = -EINVAL; - goto out_iucv; + goto out_device; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, @@ -492,7 +602,7 @@ static int __init mon_init(void) if (rc < 0) { segment_warning(rc, mon_dcss_name); rc = -EINVAL; - goto out_iucv; + goto out_device; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); @@ -503,6 +613,10 @@ static int __init mon_init(void) out: segment_unload(mon_dcss_name); +out_device: + device_unregister(monreader_device); +out_driver: + driver_unregister(&monreader_driver); out_iucv: iucv_unregister(&monreader_iucv_handler, 1); return rc; @@ -512,6 +626,8 @@ static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); + device_unregister(monreader_device); + driver_unregister(&monreader_driver); iucv_unregister(&monreader_iucv_handler, 1); return; } -- cgit v0.10.2 From c369527f18f8560bd3580be2676cb55b54b02ee6 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 16 Jun 2009 10:30:51 +0200 Subject: [S390] pm: dcssblk power management callbacks. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index b21caf1..016f9e9 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -14,10 +14,11 @@ #include #include #include -#include -#include #include #include +#include +#include +#include #define DCSSBLK_NAME "dcssblk" #define DCSSBLK_MINORS_PER_DISK 1 @@ -940,11 +941,94 @@ dcssblk_check_params(void) } /* + * Suspend / Resume + */ +static int dcssblk_freeze(struct device *dev) +{ + struct dcssblk_dev_info *dev_info; + int rc = 0; + + list_for_each_entry(dev_info, &dcssblk_devices, lh) { + switch (dev_info->segment_type) { + case SEG_TYPE_SR: + case SEG_TYPE_ER: + case SEG_TYPE_SC: + if (!dev_info->is_shared) + rc = -EINVAL; + break; + default: + rc = -EINVAL; + break; + } + if (rc) + break; + } + if (rc) + pr_err("Suspend failed because device %s is writeable.\n", + dev_info->segment_name); + return rc; +} + +static int dcssblk_restore(struct device *dev) +{ + struct dcssblk_dev_info *dev_info; + struct segment_info *entry; + unsigned long start, end; + int rc = 0; + + list_for_each_entry(dev_info, &dcssblk_devices, lh) { + list_for_each_entry(entry, &dev_info->seg_list, lh) { + segment_unload(entry->segment_name); + rc = segment_load(entry->segment_name, SEGMENT_SHARED, + &start, &end); + if (rc < 0) { +// TODO in_use check ? + segment_warning(rc, entry->segment_name); + goto out_panic; + } + if (start != entry->start || end != entry->end) { + pr_err("Mismatch of start / end address after " + "resuming device %s\n", + entry->segment_name); + goto out_panic; + } + } + } + return 0; +out_panic: + panic("fatal dcssblk resume error\n"); +} + +static int dcssblk_thaw(struct device *dev) +{ + return 0; +} + +static struct dev_pm_ops dcssblk_pm_ops = { + .freeze = dcssblk_freeze, + .thaw = dcssblk_thaw, + .restore = dcssblk_restore, +}; + +static struct platform_driver dcssblk_pdrv = { + .driver = { + .name = "dcssblk", + .owner = THIS_MODULE, + .pm = &dcssblk_pm_ops, + }, +}; + +static struct platform_device *dcssblk_pdev; + + +/* * The init/exit functions. */ static void __exit dcssblk_exit(void) { + platform_device_unregister(dcssblk_pdev); + platform_driver_unregister(&dcssblk_pdrv); root_device_unregister(dcssblk_root_dev); unregister_blkdev(dcssblk_major, DCSSBLK_NAME); } @@ -954,30 +1038,44 @@ dcssblk_init(void) { int rc; - dcssblk_root_dev = root_device_register("dcssblk"); - if (IS_ERR(dcssblk_root_dev)) - return PTR_ERR(dcssblk_root_dev); - rc = device_create_file(dcssblk_root_dev, &dev_attr_add); - if (rc) { - root_device_unregister(dcssblk_root_dev); + rc = platform_driver_register(&dcssblk_pdrv); + if (rc) return rc; + + dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL, + 0); + if (IS_ERR(dcssblk_pdev)) { + rc = PTR_ERR(dcssblk_pdev); + goto out_pdrv; } - rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); - if (rc) { - root_device_unregister(dcssblk_root_dev); - return rc; + + dcssblk_root_dev = root_device_register("dcssblk"); + if (IS_ERR(dcssblk_root_dev)) { + rc = PTR_ERR(dcssblk_root_dev); + goto out_pdev; } + rc = device_create_file(dcssblk_root_dev, &dev_attr_add); + if (rc) + goto out_root; + rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); + if (rc) + goto out_root; rc = register_blkdev(0, DCSSBLK_NAME); - if (rc < 0) { - root_device_unregister(dcssblk_root_dev); - return rc; - } + if (rc < 0) + goto out_root; dcssblk_major = rc; init_rwsem(&dcssblk_devices_sem); dcssblk_check_params(); - return 0; + +out_root: + root_device_unregister(dcssblk_root_dev); +out_pdev: + platform_device_unregister(dcssblk_pdev); +out_pdrv: + platform_driver_unregister(&dcssblk_pdrv); + return rc; } module_init(dcssblk_init); -- cgit v0.10.2 From 155af2f95f905c830688dd0ca7c7cac4107334fd Mon Sep 17 00:00:00 2001 From: Hans-Joachim Picht Date: Tue, 16 Jun 2009 10:30:52 +0200 Subject: [S390] s390: hibernation support for s390 This patch introduces the hibernation backend support to the s390 architecture. Now it is possible to suspend a mainframe Linux guest using the following command: echo disk > /sys/power/state Signed-off-by: Hans-Joachim Picht Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 99dc3de..a14dba0 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -348,6 +348,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG config ARCH_ENABLE_MEMORY_HOTREMOVE def_bool y +config ARCH_HIBERNATION_POSSIBLE + def_bool y if 64BIT + source "mm/Kconfig" comment "I/O subsystem configuration" @@ -592,6 +595,12 @@ config SECCOMP endmenu +menu "Power Management" + +source "kernel/power/Kconfig" + +endmenu + source "net/Kconfig" config PCMCIA diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 578c61f..0ff387c 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -88,7 +88,9 @@ LDFLAGS_vmlinux := -e start head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \ - arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ + arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ \ + arch/s390/power/ + libs-y += arch/s390/lib/ drivers-y += drivers/s390/ drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/ diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h new file mode 100644 index 0000000..dc75c61 --- /dev/null +++ b/arch/s390/include/asm/suspend.h @@ -0,0 +1,10 @@ +#ifndef __ASM_S390_SUSPEND_H +#define __ASM_S390_SUSPEND_H + +static inline int arch_prepare_suspend(void) +{ + return 0; +} + +#endif + diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 3a8b26e..4fb83c1 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -1,11 +1,7 @@ /* - * include/asm-s390/system.h + * Copyright IBM Corp. 1999, 2009 * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * - * Derived from "include/asm-i386/system.h" + * Author(s): Martin Schwidefsky */ #ifndef __ASM_SYSTEM_H @@ -469,6 +465,20 @@ extern psw_t sysc_restore_trace_psw; extern psw_t io_restore_trace_psw; #endif +static inline int tprot(unsigned long addr) +{ + int rc = -EFAULT; + + asm volatile( + " tprot 0(%1),0\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) : "a" (addr) : "cc"); + return rc; +} + #endif /* __KERNEL__ */ #endif diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index fb26373..f9b1440 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -1,7 +1,7 @@ /* * arch/s390/kernel/early.c * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2009 * Author(s): Hongjie Yang , * Heiko Carstens */ @@ -210,7 +210,7 @@ static noinline __init void detect_machine_type(void) machine_flags |= MACHINE_FLAG_VM; } -static __init void early_pgm_check_handler(void) +static void early_pgm_check_handler(void) { unsigned long addr; const struct exception_table_entry *fixup; @@ -222,7 +222,7 @@ static __init void early_pgm_check_handler(void) S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; } -static noinline __init void setup_lowcore_early(void) +void setup_lowcore_early(void) { psw_t psw; diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c index 9872999..559af0d 100644 --- a/arch/s390/kernel/mem_detect.c +++ b/arch/s390/kernel/mem_detect.c @@ -1,6 +1,7 @@ /* - * Copyright IBM Corp. 2008 - * Author(s): Heiko Carstens + * Copyright IBM Corp. 2008, 2009 + * + * Author(s): Heiko Carstens */ #include @@ -9,20 +10,6 @@ #include #include -static inline int tprot(unsigned long addr) -{ - int rc = -EFAULT; - - asm volatile( - " tprot 0(%1),0\n" - "0: ipm %0\n" - " srl %0,28\n" - "1:\n" - EX_TABLE(0b,1b) - : "+d" (rc) : "a" (addr) : "cc"); - return rc; -} - #define ADDR2G (1ULL << 31) static void find_memory_chunks(struct mem_chunk chunk[]) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index cc8c484..fd8e311 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -1,7 +1,7 @@ /* * arch/s390/kernel/smp.c * - * Copyright IBM Corp. 1999,2007 + * Copyright IBM Corp. 1999, 2009 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), * Martin Schwidefsky (schwidefsky@de.ibm.com) * Heiko Carstens (heiko.carstens@de.ibm.com) @@ -1031,6 +1031,42 @@ out: static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show, dispatching_store); +/* + * If the resume kernel runs on another cpu than the suspended kernel, + * we have to switch the cpu IDs in the logical map. + */ +void smp_switch_boot_cpu_in_resume(u32 resume_phys_cpu_id, + struct _lowcore *suspend_lowcore) +{ + int cpu, suspend_cpu_id, resume_cpu_id; + u32 suspend_phys_cpu_id; + + suspend_phys_cpu_id = __cpu_logical_map[suspend_lowcore->cpu_nr]; + suspend_cpu_id = suspend_lowcore->cpu_nr; + + for_each_present_cpu(cpu) { + if (__cpu_logical_map[cpu] == resume_phys_cpu_id) { + resume_cpu_id = cpu; + goto found; + } + } + panic("Could not find resume cpu in logical map.\n"); + +found: + printk("Resume cpu ID: %i/%i\n", resume_phys_cpu_id, resume_cpu_id); + printk("Suspend cpu ID: %i/%i\n", suspend_phys_cpu_id, suspend_cpu_id); + + __cpu_logical_map[resume_cpu_id] = suspend_phys_cpu_id; + __cpu_logical_map[suspend_cpu_id] = resume_phys_cpu_id; + + lowcore_ptr[suspend_cpu_id]->cpu_addr = resume_phys_cpu_id; +} + +u32 smp_get_phys_cpu_id(void) +{ + return __cpu_logical_map[smp_processor_id()]; +} + static int __init topology_init(void) { int cpu; diff --git a/arch/s390/power/Makefile b/arch/s390/power/Makefile new file mode 100644 index 0000000..973bb45 --- /dev/null +++ b/arch/s390/power/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for s390 PM support +# + +obj-$(CONFIG_HIBERNATION) += suspend.o +obj-$(CONFIG_HIBERNATION) += swsusp.o +obj-$(CONFIG_HIBERNATION) += swsusp_64.o +obj-$(CONFIG_HIBERNATION) += swsusp_asm64.o diff --git a/arch/s390/power/suspend.c b/arch/s390/power/suspend.c new file mode 100644 index 0000000..b3351ec --- /dev/null +++ b/arch/s390/power/suspend.c @@ -0,0 +1,40 @@ +/* + * Suspend support specific for s390. + * + * Copyright IBM Corp. 2009 + * + * Author(s): Hans-Joachim Picht + */ + +#include +#include +#include +#include +#include +#include + +/* + * References to section boundaries + */ +extern const void __nosave_begin, __nosave_end; + +/* + * check if given pfn is in the 'nosave' or in the read only NSS section + */ +int pfn_is_nosave(unsigned long pfn) +{ + unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; + unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) + >> PAGE_SHIFT; + unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1; + unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); + + if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) + return 1; + if (pfn >= stext_pfn && pfn <= eshared_pfn) { + if (ipl_info.type == IPL_TYPE_NSS) + return 1; + } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0)) + return 1; + return 0; +} diff --git a/arch/s390/power/swsusp.c b/arch/s390/power/swsusp.c new file mode 100644 index 0000000..e6a4fe9 --- /dev/null +++ b/arch/s390/power/swsusp.c @@ -0,0 +1,30 @@ +/* + * Support for suspend and resume on s390 + * + * Copyright IBM Corp. 2009 + * + * Author(s): Hans-Joachim Picht + * + */ + + +/* + * save CPU registers before creating a hibernation image and before + * restoring the memory state from it + */ +void save_processor_state(void) +{ + /* implentation contained in the + * swsusp_arch_suspend function + */ +} + +/* + * restore the contents of CPU registers + */ +void restore_processor_state(void) +{ + /* implentation contained in the + * swsusp_arch_resume function + */ +} diff --git a/arch/s390/power/swsusp_64.c b/arch/s390/power/swsusp_64.c new file mode 100644 index 0000000..9516a51 --- /dev/null +++ b/arch/s390/power/swsusp_64.c @@ -0,0 +1,17 @@ +/* + * Support for suspend and resume on s390 + * + * Copyright IBM Corp. 2009 + * + * Author(s): Hans-Joachim Picht + * + */ + +#include +#include + +void do_after_copyback(void) +{ + mb(); +} + diff --git a/arch/s390/power/swsusp_asm64.S b/arch/s390/power/swsusp_asm64.S new file mode 100644 index 0000000..3c74e7d --- /dev/null +++ b/arch/s390/power/swsusp_asm64.S @@ -0,0 +1,199 @@ +/* + * S390 64-bit swsusp implementation + * + * Copyright IBM Corp. 2009 + * + * Author(s): Hans-Joachim Picht + * Michael Holzheu + */ + +#include +#include +#include + +/* + * Save register context in absolute 0 lowcore and call swsusp_save() to + * create in-memory kernel image. The context is saved in the designated + * "store status" memory locations (see POP). + * We return from this function twice. The first time during the suspend to + * disk process. The second time via the swsusp_arch_resume() function + * (see below) in the resume process. + * This function runs with disabled interrupts. + */ + .section .text + .align 2 + .globl swsusp_arch_suspend +swsusp_arch_suspend: + stmg %r6,%r15,__SF_GPRS(%r15) + lgr %r1,%r15 + aghi %r15,-STACK_FRAME_OVERHEAD + stg %r1,__SF_BACKCHAIN(%r15) + + /* Deactivate DAT */ + stnsm __SF_EMPTY(%r15),0xfb + + /* Switch off lowcore protection */ + stctg %c0,%c0,__SF_EMPTY(%r15) + ni __SF_EMPTY+4(%r15),0xef + lctlg %c0,%c0,__SF_EMPTY(%r15) + + /* Store prefix register on stack */ + stpx __SF_EMPTY(%r15) + + /* Setup base register for lowcore (absolute 0) */ + llgf %r1,__SF_EMPTY(%r15) + + /* Get pointer to save area */ + aghi %r1,0x1000 + + /* Store registers */ + mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ + stfpc 0x31c(%r1) /* store fpu control */ + std 0,0x200(%r1) /* store f0 */ + std 1,0x208(%r1) /* store f1 */ + std 2,0x210(%r1) /* store f2 */ + std 3,0x218(%r1) /* store f3 */ + std 4,0x220(%r1) /* store f4 */ + std 5,0x228(%r1) /* store f5 */ + std 6,0x230(%r1) /* store f6 */ + std 7,0x238(%r1) /* store f7 */ + std 8,0x240(%r1) /* store f8 */ + std 9,0x248(%r1) /* store f9 */ + std 10,0x250(%r1) /* store f10 */ + std 11,0x258(%r1) /* store f11 */ + std 12,0x260(%r1) /* store f12 */ + std 13,0x268(%r1) /* store f13 */ + std 14,0x270(%r1) /* store f14 */ + std 15,0x278(%r1) /* store f15 */ + stam %a0,%a15,0x340(%r1) /* store access registers */ + stctg %c0,%c15,0x380(%r1) /* store control registers */ + stmg %r0,%r15,0x280(%r1) /* store general registers */ + + stpt 0x328(%r1) /* store timer */ + stckc 0x330(%r1) /* store clock comparator */ + + /* Activate DAT */ + stosm __SF_EMPTY(%r15),0x04 + + /* Set prefix page to zero */ + xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) + spx __SF_EMPTY(%r15) + + /* Setup lowcore */ + brasl %r14,setup_lowcore_early + + /* Save image */ + brasl %r14,swsusp_save + + /* Switch on lowcore protection */ + stctg %c0,%c0,__SF_EMPTY(%r15) + oi __SF_EMPTY+4(%r15),0x10 + lctlg %c0,%c0,__SF_EMPTY(%r15) + + /* Restore prefix register and return */ + lghi %r1,0x1000 + spx 0x318(%r1) + lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) + lghi %r2,0 + br %r14 + +/* + * Restore saved memory image to correct place and restore register context. + * Then we return to the function that called swsusp_arch_suspend(). + * swsusp_arch_resume() runs with disabled interrupts. + */ + .globl swsusp_arch_resume +swsusp_arch_resume: + stmg %r6,%r15,__SF_GPRS(%r15) + lgr %r1,%r15 + aghi %r15,-STACK_FRAME_OVERHEAD + stg %r1,__SF_BACKCHAIN(%r15) + + /* Save boot cpu number */ + brasl %r14,smp_get_phys_cpu_id + lgr %r10,%r2 + + /* Deactivate DAT */ + stnsm __SF_EMPTY(%r15),0xfb + + /* Switch off lowcore protection */ + stctg %c0,%c0,__SF_EMPTY(%r15) + ni __SF_EMPTY+4(%r15),0xef + lctlg %c0,%c0,__SF_EMPTY(%r15) + + /* Set prefix page to zero */ + xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) + spx __SF_EMPTY(%r15) + + /* Restore saved image */ + larl %r1,restore_pblist + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 2f +0: + lg %r2,8(%r1) + lg %r4,0(%r1) + lghi %r3,PAGE_SIZE + lghi %r5,PAGE_SIZE +1: + mvcle %r2,%r4,0 + jo 1b + lg %r1,16(%r1) + ltgr %r1,%r1 + jnz 0b +2: + ptlb /* flush tlb */ + + /* Restore registers */ + lghi %r13,0x1000 /* %r1 = pointer to save arae */ + + spt 0x328(%r13) /* reprogram timer */ + //sckc 0x330(%r13) /* set clock comparator */ + + lctlg %c0,%c15,0x380(%r13) /* load control registers */ + lam %a0,%a15,0x340(%r13) /* load access registers */ + + lfpc 0x31c(%r13) /* load fpu control */ + ld 0,0x200(%r13) /* load f0 */ + ld 1,0x208(%r13) /* load f1 */ + ld 2,0x210(%r13) /* load f2 */ + ld 3,0x218(%r13) /* load f3 */ + ld 4,0x220(%r13) /* load f4 */ + ld 5,0x228(%r13) /* load f5 */ + ld 6,0x230(%r13) /* load f6 */ + ld 7,0x238(%r13) /* load f7 */ + ld 8,0x240(%r13) /* load f8 */ + ld 9,0x248(%r13) /* load f9 */ + ld 10,0x250(%r13) /* load f10 */ + ld 11,0x258(%r13) /* load f11 */ + ld 12,0x260(%r13) /* load f12 */ + ld 13,0x268(%r13) /* load f13 */ + ld 14,0x270(%r13) /* load f14 */ + ld 15,0x278(%r13) /* load f15 */ + + /* Load old stack */ + lg %r15,0x2f8(%r13) + + /* Pointer to save arae */ + lghi %r13,0x1000 + + /* Switch CPUs */ + lgr %r2,%r10 /* get cpu id */ + llgf %r3,0x318(%r13) + brasl %r14,smp_switch_boot_cpu_in_resume + + /* Restore prefix register */ + spx 0x318(%r13) + + /* Switch on lowcore protection */ + stctg %c0,%c0,__SF_EMPTY(%r15) + oi __SF_EMPTY+4(%r15),0x10 + lctlg %c0,%c0,__SF_EMPTY(%r15) + + /* Activate DAT */ + stosm __SF_EMPTY(%r15),0x04 + + /* Return 0 */ + lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) + lghi %r2,0 + br %r14 -- cgit v0.10.2 From e212d6f25084e8e9b02a04ba514d7bb1e4a4924a Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Tue, 16 Jun 2009 11:19:36 +0200 Subject: block: remove some includings of blktrace_api.h When porting blktrace to tracepoints, we changed to trace/block.h for trace prober declarations. Signed-off-by: Li Zefan Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 94d88fa..b06cf5c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #define CREATE_TRACE_POINTS diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index b22cec9..c7a527c 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 3fd8b1e..48db308 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -19,7 +19,6 @@ #include #include #include -#include #include diff --git a/fs/bio.c b/fs/bio.c index 5f80848..24c9140 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -25,7 +25,6 @@ #include #include #include -#include #include /* for struct sg_iovec */ #include diff --git a/mm/bounce.c b/mm/bounce.c index 4ebe3ea..a2b76a5 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/mm/highmem.c b/mm/highmem.c index 68eb1d9..25878cc 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -26,7 +26,6 @@ #include #include #include -#include #include /* -- cgit v0.10.2 From 557fe0e8842e919aeacedeb5f35444c78232b3c8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 31 Mar 2009 17:15:40 -0700 Subject: sparc64: Reclaim trap_block[]->hdesc This really isn't necessary at all, a local variable suits the job just fine. This frees up 8 bytes in the trap_block[] that we can use later to store the per-cpu base addresses. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index a11b89e..c58d87b 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -80,7 +80,7 @@ struct trap_per_cpu { unsigned int dev_mondo_qmask; unsigned int resum_qmask; unsigned int nonresum_qmask; - void *hdesc; + unsigned long __unused; } __attribute__((aligned(64))); extern struct trap_per_cpu trap_block[NR_CPUS]; extern void init_cur_cpu_trap(struct thread_info *); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index f7642e5a..4226d0e 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -278,7 +278,7 @@ static unsigned long kimage_addr_to_ra(void *p) return kern_base + (val - KERNBASE); } -static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg) +static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg, void **descrp) { extern unsigned long sparc64_ttable_tl0; extern unsigned long kern_locked_tte_data; @@ -298,12 +298,12 @@ static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread "hvtramp_descr.\n"); return; } + *descrp = hdesc; hdesc->cpu = cpu; hdesc->num_mappings = num_kernel_image_mappings; tb = &trap_block[cpu]; - tb->hdesc = hdesc; hdesc->fault_info_va = (unsigned long) &tb->fault_info; hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info); @@ -341,12 +341,12 @@ static struct thread_info *cpu_new_thread = NULL; static int __cpuinit smp_boot_one_cpu(unsigned int cpu) { - struct trap_per_cpu *tb = &trap_block[cpu]; unsigned long entry = (unsigned long)(&sparc64_cpu_startup); unsigned long cookie = (unsigned long)(&cpu_new_thread); struct task_struct *p; + void *descr = NULL; int timeout, ret; p = fork_idle(cpu); @@ -359,7 +359,8 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu) #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) if (ldom_domaining_enabled) ldom_startcpu_cpuid(cpu, - (unsigned long) cpu_new_thread); + (unsigned long) cpu_new_thread, + &descr); else #endif prom_startcpu_cpuid(cpu, entry, cookie); @@ -383,10 +384,7 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu) } cpu_new_thread = NULL; - if (tb->hdesc) { - kfree(tb->hdesc); - tb->hdesc = NULL; - } + kfree(descr); return ret; } -- cgit v0.10.2 From 19f0fa3fb3499d8c5fb861933959f546d05fc202 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Apr 2009 01:26:43 -0700 Subject: sparc64: Move trap_block[] definitions into a new header file. Later we're going to want to get at these definitions from asm/percpu.h and that's not possible via cpudata.h because of the set of dependencies the non-trap_block[] stuff has. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index c58d87b..926397d 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -6,9 +6,6 @@ #ifndef _SPARC64_CPUDATA_H #define _SPARC64_CPUDATA_H -#include -#include - #ifndef __ASSEMBLY__ #include @@ -38,202 +35,10 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) #define local_cpu_data() __get_cpu_var(__cpu_data) -/* Trap handling code needs to get at a few critical values upon - * trap entry and to process TSB misses. These cannot be in the - * per_cpu() area as we really need to lock them into the TLB and - * thus make them part of the main kernel image. As a result we - * try to make this as small as possible. - * - * This is padded out and aligned to 64-bytes to avoid false sharing - * on SMP. - */ - -/* If you modify the size of this structure, please update - * TRAP_BLOCK_SZ_SHIFT below. - */ -struct thread_info; -struct trap_per_cpu { -/* D-cache line 1: Basic thread information, cpu and device mondo queues */ - struct thread_info *thread; - unsigned long pgd_paddr; - unsigned long cpu_mondo_pa; - unsigned long dev_mondo_pa; - -/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */ - unsigned long resum_mondo_pa; - unsigned long resum_kernel_buf_pa; - unsigned long nonresum_mondo_pa; - unsigned long nonresum_kernel_buf_pa; - -/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */ - struct hv_fault_status fault_info; - -/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list. */ - unsigned long cpu_mondo_block_pa; - unsigned long cpu_list_pa; - unsigned long tsb_huge; - unsigned long tsb_huge_temp; - -/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */ - unsigned long irq_worklist_pa; - unsigned int cpu_mondo_qmask; - unsigned int dev_mondo_qmask; - unsigned int resum_qmask; - unsigned int nonresum_qmask; - unsigned long __unused; -} __attribute__((aligned(64))); -extern struct trap_per_cpu trap_block[NR_CPUS]; -extern void init_cur_cpu_trap(struct thread_info *); -extern void setup_tba(void); -extern int ncpus_probed; extern const struct seq_operations cpuinfo_op; -extern unsigned long real_hard_smp_processor_id(void); - -struct cpuid_patch_entry { - unsigned int addr; - unsigned int cheetah_safari[4]; - unsigned int cheetah_jbus[4]; - unsigned int starfire[4]; - unsigned int sun4v[4]; -}; -extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end; - -struct sun4v_1insn_patch_entry { - unsigned int addr; - unsigned int insn; -}; -extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch, - __sun4v_1insn_patch_end; - -struct sun4v_2insn_patch_entry { - unsigned int addr; - unsigned int insns[2]; -}; -extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, - __sun4v_2insn_patch_end; - #endif /* !(__ASSEMBLY__) */ -#define TRAP_PER_CPU_THREAD 0x00 -#define TRAP_PER_CPU_PGD_PADDR 0x08 -#define TRAP_PER_CPU_CPU_MONDO_PA 0x10 -#define TRAP_PER_CPU_DEV_MONDO_PA 0x18 -#define TRAP_PER_CPU_RESUM_MONDO_PA 0x20 -#define TRAP_PER_CPU_RESUM_KBUF_PA 0x28 -#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30 -#define TRAP_PER_CPU_NONRESUM_KBUF_PA 0x38 -#define TRAP_PER_CPU_FAULT_INFO 0x40 -#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA 0xc0 -#define TRAP_PER_CPU_CPU_LIST_PA 0xc8 -#define TRAP_PER_CPU_TSB_HUGE 0xd0 -#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 -#define TRAP_PER_CPU_IRQ_WORKLIST_PA 0xe0 -#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8 -#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec -#define TRAP_PER_CPU_RESUM_QMASK 0xf0 -#define TRAP_PER_CPU_NONRESUM_QMASK 0xf4 - -#define TRAP_BLOCK_SZ_SHIFT 8 - -#include - -#define __GET_CPUID(REG) \ - /* Spitfire implementation (default). */ \ -661: ldxa [%g0] ASI_UPA_CONFIG, REG; \ - srlx REG, 17, REG; \ - and REG, 0x1f, REG; \ - nop; \ - .section .cpuid_patch, "ax"; \ - /* Instruction location. */ \ - .word 661b; \ - /* Cheetah Safari implementation. */ \ - ldxa [%g0] ASI_SAFARI_CONFIG, REG; \ - srlx REG, 17, REG; \ - and REG, 0x3ff, REG; \ - nop; \ - /* Cheetah JBUS implementation. */ \ - ldxa [%g0] ASI_JBUS_CONFIG, REG; \ - srlx REG, 17, REG; \ - and REG, 0x1f, REG; \ - nop; \ - /* Starfire implementation. */ \ - sethi %hi(0x1fff40000d0 >> 9), REG; \ - sllx REG, 9, REG; \ - or REG, 0xd0, REG; \ - lduwa [REG] ASI_PHYS_BYPASS_EC_E, REG;\ - /* sun4v implementation. */ \ - mov SCRATCHPAD_CPUID, REG; \ - ldxa [REG] ASI_SCRATCHPAD, REG; \ - nop; \ - nop; \ - .previous; - -#ifdef CONFIG_SMP - -#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - __GET_CPUID(TMP) \ - sethi %hi(trap_block), DEST; \ - sllx TMP, TRAP_BLOCK_SZ_SHIFT, TMP; \ - or DEST, %lo(trap_block), DEST; \ - add DEST, TMP, DEST; \ - -/* Clobbers TMP, current address space PGD phys address into DEST. */ -#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; - -/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ -#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; - -/* Clobbers TMP, loads DEST with current thread info pointer. */ -#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_THREAD], DEST; - -/* Given the current thread info pointer in THR, load the per-cpu - * area base of the current processor into DEST. REG1, REG2, and REG3 are - * clobbered. - * - * You absolutely cannot use DEST as a temporary in this code. The - * reason is that traps can happen during execution, and return from - * trap will load the fully resolved DEST per-cpu base. This can corrupt - * the calculations done by the macro mid-stream. - */ -#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \ - lduh [THR + TI_CPU], REG1; \ - sethi %hi(__per_cpu_shift), REG3; \ - sethi %hi(__per_cpu_base), REG2; \ - ldx [REG3 + %lo(__per_cpu_shift)], REG3; \ - ldx [REG2 + %lo(__per_cpu_base)], REG2; \ - sllx REG1, REG3, REG3; \ - add REG3, REG2, DEST; - -#else - -#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - sethi %hi(trap_block), DEST; \ - or DEST, %lo(trap_block), DEST; \ - -/* Uniprocessor versions, we know the cpuid is zero. */ -#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; - -/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ -#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; - -#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_THREAD], DEST; - -/* No per-cpu areas on uniprocessor, so no need to load DEST. */ -#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) - -#endif /* !(CONFIG_SMP) */ +#include #endif /* _SPARC64_CPUDATA_H */ diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h new file mode 100644 index 0000000..68fd9ee --- /dev/null +++ b/arch/sparc/include/asm/trap_block.h @@ -0,0 +1,207 @@ +#ifndef _SPARC_TRAP_BLOCK_H +#define _SPARC_TRAP_BLOCK_H + +#include +#include + +#ifndef __ASSEMBLY__ + +/* Trap handling code needs to get at a few critical values upon + * trap entry and to process TSB misses. These cannot be in the + * per_cpu() area as we really need to lock them into the TLB and + * thus make them part of the main kernel image. As a result we + * try to make this as small as possible. + * + * This is padded out and aligned to 64-bytes to avoid false sharing + * on SMP. + */ + +/* If you modify the size of this structure, please update + * TRAP_BLOCK_SZ_SHIFT below. + */ +struct thread_info; +struct trap_per_cpu { +/* D-cache line 1: Basic thread information, cpu and device mondo queues */ + struct thread_info *thread; + unsigned long pgd_paddr; + unsigned long cpu_mondo_pa; + unsigned long dev_mondo_pa; + +/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */ + unsigned long resum_mondo_pa; + unsigned long resum_kernel_buf_pa; + unsigned long nonresum_mondo_pa; + unsigned long nonresum_kernel_buf_pa; + +/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */ + struct hv_fault_status fault_info; + +/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list. */ + unsigned long cpu_mondo_block_pa; + unsigned long cpu_list_pa; + unsigned long tsb_huge; + unsigned long tsb_huge_temp; + +/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */ + unsigned long irq_worklist_pa; + unsigned int cpu_mondo_qmask; + unsigned int dev_mondo_qmask; + unsigned int resum_qmask; + unsigned int nonresum_qmask; + unsigned long __unused; +} __attribute__((aligned(64))); +extern struct trap_per_cpu trap_block[NR_CPUS]; +extern void init_cur_cpu_trap(struct thread_info *); +extern void setup_tba(void); +extern int ncpus_probed; + +extern unsigned long real_hard_smp_processor_id(void); + +struct cpuid_patch_entry { + unsigned int addr; + unsigned int cheetah_safari[4]; + unsigned int cheetah_jbus[4]; + unsigned int starfire[4]; + unsigned int sun4v[4]; +}; +extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end; + +struct sun4v_1insn_patch_entry { + unsigned int addr; + unsigned int insn; +}; +extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch, + __sun4v_1insn_patch_end; + +struct sun4v_2insn_patch_entry { + unsigned int addr; + unsigned int insns[2]; +}; +extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, + __sun4v_2insn_patch_end; + + +#endif /* !(__ASSEMBLY__) */ + +#define TRAP_PER_CPU_THREAD 0x00 +#define TRAP_PER_CPU_PGD_PADDR 0x08 +#define TRAP_PER_CPU_CPU_MONDO_PA 0x10 +#define TRAP_PER_CPU_DEV_MONDO_PA 0x18 +#define TRAP_PER_CPU_RESUM_MONDO_PA 0x20 +#define TRAP_PER_CPU_RESUM_KBUF_PA 0x28 +#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30 +#define TRAP_PER_CPU_NONRESUM_KBUF_PA 0x38 +#define TRAP_PER_CPU_FAULT_INFO 0x40 +#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA 0xc0 +#define TRAP_PER_CPU_CPU_LIST_PA 0xc8 +#define TRAP_PER_CPU_TSB_HUGE 0xd0 +#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 +#define TRAP_PER_CPU_IRQ_WORKLIST_PA 0xe0 +#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8 +#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec +#define TRAP_PER_CPU_RESUM_QMASK 0xf0 +#define TRAP_PER_CPU_NONRESUM_QMASK 0xf4 + +#define TRAP_BLOCK_SZ_SHIFT 8 + +#include + +#define __GET_CPUID(REG) \ + /* Spitfire implementation (default). */ \ +661: ldxa [%g0] ASI_UPA_CONFIG, REG; \ + srlx REG, 17, REG; \ + and REG, 0x1f, REG; \ + nop; \ + .section .cpuid_patch, "ax"; \ + /* Instruction location. */ \ + .word 661b; \ + /* Cheetah Safari implementation. */ \ + ldxa [%g0] ASI_SAFARI_CONFIG, REG; \ + srlx REG, 17, REG; \ + and REG, 0x3ff, REG; \ + nop; \ + /* Cheetah JBUS implementation. */ \ + ldxa [%g0] ASI_JBUS_CONFIG, REG; \ + srlx REG, 17, REG; \ + and REG, 0x1f, REG; \ + nop; \ + /* Starfire implementation. */ \ + sethi %hi(0x1fff40000d0 >> 9), REG; \ + sllx REG, 9, REG; \ + or REG, 0xd0, REG; \ + lduwa [REG] ASI_PHYS_BYPASS_EC_E, REG;\ + /* sun4v implementation. */ \ + mov SCRATCHPAD_CPUID, REG; \ + ldxa [REG] ASI_SCRATCHPAD, REG; \ + nop; \ + nop; \ + .previous; + +#ifdef CONFIG_SMP + +#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + __GET_CPUID(TMP) \ + sethi %hi(trap_block), DEST; \ + sllx TMP, TRAP_BLOCK_SZ_SHIFT, TMP; \ + or DEST, %lo(trap_block), DEST; \ + add DEST, TMP, DEST; \ + +/* Clobbers TMP, current address space PGD phys address into DEST. */ +#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; + +/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ +#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; + +/* Clobbers TMP, loads DEST with current thread info pointer. */ +#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_THREAD], DEST; + +/* Given the current thread info pointer in THR, load the per-cpu + * area base of the current processor into DEST. REG1, REG2, and REG3 are + * clobbered. + * + * You absolutely cannot use DEST as a temporary in this code. The + * reason is that traps can happen during execution, and return from + * trap will load the fully resolved DEST per-cpu base. This can corrupt + * the calculations done by the macro mid-stream. + */ +#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \ + lduh [THR + TI_CPU], REG1; \ + sethi %hi(__per_cpu_shift), REG3; \ + sethi %hi(__per_cpu_base), REG2; \ + ldx [REG3 + %lo(__per_cpu_shift)], REG3; \ + ldx [REG2 + %lo(__per_cpu_base)], REG2; \ + sllx REG1, REG3, REG3; \ + add REG3, REG2, DEST; + +#else + +#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + sethi %hi(trap_block), DEST; \ + or DEST, %lo(trap_block), DEST; \ + +/* Uniprocessor versions, we know the cpuid is zero. */ +#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; + +/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ +#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; + +#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_THREAD], DEST; + +/* No per-cpu areas on uniprocessor, so no need to load DEST. */ +#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) + +#endif /* !(CONFIG_SMP) */ + +#endif /* _SPARC_TRAP_BLOCK_H */ -- cgit v0.10.2 From 5a5488d3bb9a23d9884572e5d85dfeefe8749d3d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Apr 2009 01:47:10 -0700 Subject: sparc64: Store per-cpu offset in trap_block[] Surprisingly this actually makes LOAD_PER_CPU_BASE() a little more efficient. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/percpu_64.h b/arch/sparc/include/asm/percpu_64.h index bee6459..c0ab102 100644 --- a/arch/sparc/include/asm/percpu_64.h +++ b/arch/sparc/include/asm/percpu_64.h @@ -7,12 +7,12 @@ register unsigned long __local_per_cpu_offset asm("g5"); #ifdef CONFIG_SMP +#include + extern void real_setup_per_cpu_areas(void); -extern unsigned long __per_cpu_base; -extern unsigned long __per_cpu_shift; #define __per_cpu_offset(__cpu) \ - (__per_cpu_base + ((unsigned long)(__cpu) << __per_cpu_shift)) + (trap_block[(__cpu)].__per_cpu_base) #define per_cpu_offset(x) (__per_cpu_offset(x)) #define __my_cpu_offset __local_per_cpu_offset diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h index 68fd9ee..7e26b2d 100644 --- a/arch/sparc/include/asm/trap_block.h +++ b/arch/sparc/include/asm/trap_block.h @@ -48,7 +48,7 @@ struct trap_per_cpu { unsigned int dev_mondo_qmask; unsigned int resum_qmask; unsigned int nonresum_qmask; - unsigned long __unused; + unsigned long __per_cpu_base; } __attribute__((aligned(64))); extern struct trap_per_cpu trap_block[NR_CPUS]; extern void init_cur_cpu_trap(struct thread_info *); @@ -101,6 +101,7 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, #define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec #define TRAP_PER_CPU_RESUM_QMASK 0xf0 #define TRAP_PER_CPU_NONRESUM_QMASK 0xf4 +#define TRAP_PER_CPU_PER_CPU_BASE 0xf8 #define TRAP_BLOCK_SZ_SHIFT 8 @@ -172,12 +173,11 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, */ #define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \ lduh [THR + TI_CPU], REG1; \ - sethi %hi(__per_cpu_shift), REG3; \ - sethi %hi(__per_cpu_base), REG2; \ - ldx [REG3 + %lo(__per_cpu_shift)], REG3; \ - ldx [REG2 + %lo(__per_cpu_base)], REG2; \ - sllx REG1, REG3, REG3; \ - add REG3, REG2, DEST; + sethi %hi(trap_block), REG2; \ + sllx REG1, TRAP_BLOCK_SZ_SHIFT, REG1; \ + or REG2, %lo(trap_block), REG2; \ + add REG2, REG1, REG2; \ + ldx [REG2 + TRAP_PER_CPU_PER_CPU_BASE], DEST; #else diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 91bf4c7..f8f2105 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -641,28 +641,6 @@ tlb_fixup_done: /* Not reached... */ 1: - /* If we boot on a non-zero cpu, all of the per-cpu - * variable references we make before setting up the - * per-cpu areas will use a bogus offset. Put a - * compensating factor into __per_cpu_base to handle - * this cleanly. - * - * What the per-cpu code calculates is: - * - * __per_cpu_base + (cpu << __per_cpu_shift) - * - * These two variables are zero initially, so to - * make it all cancel out to zero we need to put - * "0 - (cpu << 0)" into __per_cpu_base so that the - * above formula evaluates to zero. - * - * We cannot even perform a printk() until this stuff - * is setup as that calls cpu_clock() which uses - * per-cpu variables. - */ - sub %g0, %o0, %o1 - sethi %hi(__per_cpu_base), %o2 - stx %o1, [%o2 + %lo(__per_cpu_base)] #else mov 0, %o0 #endif diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 4226d0e..b20f253 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1371,23 +1371,17 @@ void smp_send_stop(void) { } -unsigned long __per_cpu_base __read_mostly; -unsigned long __per_cpu_shift __read_mostly; - -EXPORT_SYMBOL(__per_cpu_base); -EXPORT_SYMBOL(__per_cpu_shift); - void __init real_setup_per_cpu_areas(void) { - unsigned long paddr, goal, size, i; + unsigned long base, shift, paddr, goal, size, i; char *ptr; /* Copy section for each CPU (we discard the original) */ goal = PERCPU_ENOUGH_ROOM; - __per_cpu_shift = PAGE_SHIFT; + shift = PAGE_SHIFT; for (size = PAGE_SIZE; size < goal; size <<= 1UL) - __per_cpu_shift++; + shift++; paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE); if (!paddr) { @@ -1396,10 +1390,12 @@ void __init real_setup_per_cpu_areas(void) } ptr = __va(paddr); - __per_cpu_base = ptr - __per_cpu_start; + base = ptr - __per_cpu_start; - for (i = 0; i < NR_CPUS; i++, ptr += size) + for (i = 0; i < NR_CPUS; i++, ptr += size) { + __per_cpu_offset(i) = base + (i * size); memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); + } /* Setup %g5 for the boot cpu. */ __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index d809c4e..d073aab 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -2509,6 +2509,7 @@ void do_getpsr(struct pt_regs *regs) } struct trap_per_cpu trap_block[NR_CPUS]; +EXPORT_SYMBOL(trap_block); /* This can get invoked before sched_init() so play it super safe * and use hard_smp_processor_id(). @@ -2592,7 +2593,9 @@ void __init trap_init(void) (TRAP_PER_CPU_RESUM_QMASK != offsetof(struct trap_per_cpu, resum_qmask)) || (TRAP_PER_CPU_NONRESUM_QMASK != - offsetof(struct trap_per_cpu, nonresum_qmask))) + offsetof(struct trap_per_cpu, nonresum_qmask)) || + (TRAP_PER_CPU_PER_CPU_BASE != + offsetof(struct trap_per_cpu, __per_cpu_base))) trap_per_cpu_offsets_are_bolixed_dave(); if ((TSB_CONFIG_TSB != -- cgit v0.10.2 From 8249778908783f329a8852285b083ce86437e089 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Apr 2009 01:57:36 -0700 Subject: sparc64: Use BUILD_BUG_ON() in trap_init(). Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index d073aab..10f7bb9 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -2531,86 +2531,97 @@ extern void tsb_config_offsets_are_bolixed_dave(void); void __init trap_init(void) { /* Compile time sanity check. */ - if (TI_TASK != offsetof(struct thread_info, task) || - TI_FLAGS != offsetof(struct thread_info, flags) || - TI_CPU != offsetof(struct thread_info, cpu) || - TI_FPSAVED != offsetof(struct thread_info, fpsaved) || - TI_KSP != offsetof(struct thread_info, ksp) || - TI_FAULT_ADDR != offsetof(struct thread_info, fault_address) || - TI_KREGS != offsetof(struct thread_info, kregs) || - TI_UTRAPS != offsetof(struct thread_info, utraps) || - TI_EXEC_DOMAIN != offsetof(struct thread_info, exec_domain) || - TI_REG_WINDOW != offsetof(struct thread_info, reg_window) || - TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) || - TI_GSR != offsetof(struct thread_info, gsr) || - TI_XFSR != offsetof(struct thread_info, xfsr) || - TI_USER_CNTD0 != offsetof(struct thread_info, user_cntd0) || - TI_USER_CNTD1 != offsetof(struct thread_info, user_cntd1) || - TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) || - TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) || - TI_PCR != offsetof(struct thread_info, pcr_reg) || - TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || - TI_NEW_CHILD != offsetof(struct thread_info, new_child) || - TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || - TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) || - TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) || - TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) || - TI_FPREGS != offsetof(struct thread_info, fpregs) || - (TI_FPREGS & (64 - 1))) - thread_info_offsets_are_bolixed_dave(); - - if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) || - (TRAP_PER_CPU_PGD_PADDR != - offsetof(struct trap_per_cpu, pgd_paddr)) || - (TRAP_PER_CPU_CPU_MONDO_PA != - offsetof(struct trap_per_cpu, cpu_mondo_pa)) || - (TRAP_PER_CPU_DEV_MONDO_PA != - offsetof(struct trap_per_cpu, dev_mondo_pa)) || - (TRAP_PER_CPU_RESUM_MONDO_PA != - offsetof(struct trap_per_cpu, resum_mondo_pa)) || - (TRAP_PER_CPU_RESUM_KBUF_PA != - offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) || - (TRAP_PER_CPU_NONRESUM_MONDO_PA != - offsetof(struct trap_per_cpu, nonresum_mondo_pa)) || - (TRAP_PER_CPU_NONRESUM_KBUF_PA != - offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) || - (TRAP_PER_CPU_FAULT_INFO != - offsetof(struct trap_per_cpu, fault_info)) || - (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA != - offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) || - (TRAP_PER_CPU_CPU_LIST_PA != - offsetof(struct trap_per_cpu, cpu_list_pa)) || - (TRAP_PER_CPU_TSB_HUGE != - offsetof(struct trap_per_cpu, tsb_huge)) || - (TRAP_PER_CPU_TSB_HUGE_TEMP != - offsetof(struct trap_per_cpu, tsb_huge_temp)) || - (TRAP_PER_CPU_IRQ_WORKLIST_PA != - offsetof(struct trap_per_cpu, irq_worklist_pa)) || - (TRAP_PER_CPU_CPU_MONDO_QMASK != - offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || - (TRAP_PER_CPU_DEV_MONDO_QMASK != - offsetof(struct trap_per_cpu, dev_mondo_qmask)) || - (TRAP_PER_CPU_RESUM_QMASK != - offsetof(struct trap_per_cpu, resum_qmask)) || - (TRAP_PER_CPU_NONRESUM_QMASK != - offsetof(struct trap_per_cpu, nonresum_qmask)) || - (TRAP_PER_CPU_PER_CPU_BASE != - offsetof(struct trap_per_cpu, __per_cpu_base))) - trap_per_cpu_offsets_are_bolixed_dave(); - - if ((TSB_CONFIG_TSB != - offsetof(struct tsb_config, tsb)) || - (TSB_CONFIG_RSS_LIMIT != - offsetof(struct tsb_config, tsb_rss_limit)) || - (TSB_CONFIG_NENTRIES != - offsetof(struct tsb_config, tsb_nentries)) || - (TSB_CONFIG_REG_VAL != - offsetof(struct tsb_config, tsb_reg_val)) || - (TSB_CONFIG_MAP_VADDR != - offsetof(struct tsb_config, tsb_map_vaddr)) || - (TSB_CONFIG_MAP_PTE != - offsetof(struct tsb_config, tsb_map_pte))) - tsb_config_offsets_are_bolixed_dave(); + BUILD_BUG_ON(TI_TASK != offsetof(struct thread_info, task) || + TI_FLAGS != offsetof(struct thread_info, flags) || + TI_CPU != offsetof(struct thread_info, cpu) || + TI_FPSAVED != offsetof(struct thread_info, fpsaved) || + TI_KSP != offsetof(struct thread_info, ksp) || + TI_FAULT_ADDR != offsetof(struct thread_info, + fault_address) || + TI_KREGS != offsetof(struct thread_info, kregs) || + TI_UTRAPS != offsetof(struct thread_info, utraps) || + TI_EXEC_DOMAIN != offsetof(struct thread_info, + exec_domain) || + TI_REG_WINDOW != offsetof(struct thread_info, + reg_window) || + TI_RWIN_SPTRS != offsetof(struct thread_info, + rwbuf_stkptrs) || + TI_GSR != offsetof(struct thread_info, gsr) || + TI_XFSR != offsetof(struct thread_info, xfsr) || + TI_USER_CNTD0 != offsetof(struct thread_info, + user_cntd0) || + TI_USER_CNTD1 != offsetof(struct thread_info, + user_cntd1) || + TI_KERN_CNTD0 != offsetof(struct thread_info, + kernel_cntd0) || + TI_KERN_CNTD1 != offsetof(struct thread_info, + kernel_cntd1) || + TI_PCR != offsetof(struct thread_info, pcr_reg) || + TI_PRE_COUNT != offsetof(struct thread_info, + preempt_count) || + TI_NEW_CHILD != offsetof(struct thread_info, new_child) || + TI_SYS_NOERROR != offsetof(struct thread_info, + syscall_noerror) || + TI_RESTART_BLOCK != offsetof(struct thread_info, + restart_block) || + TI_KUNA_REGS != offsetof(struct thread_info, + kern_una_regs) || + TI_KUNA_INSN != offsetof(struct thread_info, + kern_una_insn) || + TI_FPREGS != offsetof(struct thread_info, fpregs) || + (TI_FPREGS & (64 - 1))); + + BUILD_BUG_ON(TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, + thread) || + (TRAP_PER_CPU_PGD_PADDR != + offsetof(struct trap_per_cpu, pgd_paddr)) || + (TRAP_PER_CPU_CPU_MONDO_PA != + offsetof(struct trap_per_cpu, cpu_mondo_pa)) || + (TRAP_PER_CPU_DEV_MONDO_PA != + offsetof(struct trap_per_cpu, dev_mondo_pa)) || + (TRAP_PER_CPU_RESUM_MONDO_PA != + offsetof(struct trap_per_cpu, resum_mondo_pa)) || + (TRAP_PER_CPU_RESUM_KBUF_PA != + offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) || + (TRAP_PER_CPU_NONRESUM_MONDO_PA != + offsetof(struct trap_per_cpu, nonresum_mondo_pa)) || + (TRAP_PER_CPU_NONRESUM_KBUF_PA != + offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) || + (TRAP_PER_CPU_FAULT_INFO != + offsetof(struct trap_per_cpu, fault_info)) || + (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA != + offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) || + (TRAP_PER_CPU_CPU_LIST_PA != + offsetof(struct trap_per_cpu, cpu_list_pa)) || + (TRAP_PER_CPU_TSB_HUGE != + offsetof(struct trap_per_cpu, tsb_huge)) || + (TRAP_PER_CPU_TSB_HUGE_TEMP != + offsetof(struct trap_per_cpu, tsb_huge_temp)) || + (TRAP_PER_CPU_IRQ_WORKLIST_PA != + offsetof(struct trap_per_cpu, irq_worklist_pa)) || + (TRAP_PER_CPU_CPU_MONDO_QMASK != + offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || + (TRAP_PER_CPU_DEV_MONDO_QMASK != + offsetof(struct trap_per_cpu, dev_mondo_qmask)) || + (TRAP_PER_CPU_RESUM_QMASK != + offsetof(struct trap_per_cpu, resum_qmask)) || + (TRAP_PER_CPU_NONRESUM_QMASK != + offsetof(struct trap_per_cpu, nonresum_qmask)) || + (TRAP_PER_CPU_PER_CPU_BASE != + offsetof(struct trap_per_cpu, __per_cpu_base))); + + BUILD_BUG_ON((TSB_CONFIG_TSB != + offsetof(struct tsb_config, tsb)) || + (TSB_CONFIG_RSS_LIMIT != + offsetof(struct tsb_config, tsb_rss_limit)) || + (TSB_CONFIG_NENTRIES != + offsetof(struct tsb_config, tsb_nentries)) || + (TSB_CONFIG_REG_VAL != + offsetof(struct tsb_config, tsb_reg_val)) || + (TSB_CONFIG_MAP_VADDR != + offsetof(struct tsb_config, tsb_map_vaddr)) || + (TSB_CONFIG_MAP_PTE != + offsetof(struct tsb_config, tsb_map_pte))); /* Attach to the address space of init_task. On SMP we * do this in smp.c:smp_callin for other cpus. -- cgit v0.10.2 From 9bab54143ca16592536c9d35f43cfac0a2a28ea8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 21:46:14 -0700 Subject: sparc64: Refactor OBP cpu scanning code using an iterator. With feedback from Sam Ravnborg. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index 900d447..1b15212 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -86,6 +86,7 @@ extern int of_node_to_nid(struct device_node *dp); #endif extern void prom_build_devicetree(void); +extern void of_populate_present_mask(void); /* Dummy ref counting routines - to be implemented later */ static inline struct device_node *of_node_get(struct device_node *node) diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c index ca55c70..4d92f48 100644 --- a/arch/sparc/kernel/prom_64.c +++ b/arch/sparc/kernel/prom_64.c @@ -374,75 +374,26 @@ static const char *get_mid_prop(void) return (tlb_type == spitfire ? "upa-portid" : "portid"); } -struct device_node *of_find_node_by_cpuid(int cpuid) -{ - struct device_node *dp; - const char *mid_prop = get_mid_prop(); - - for_each_node_by_type(dp, "cpu") { - int id = of_getintprop_default(dp, mid_prop, -1); - const char *this_mid_prop = mid_prop; - - if (id < 0) { - this_mid_prop = "cpuid"; - id = of_getintprop_default(dp, this_mid_prop, -1); - } - - if (id < 0) { - prom_printf("OF: Serious problem, cpu lacks " - "%s property", this_mid_prop); - prom_halt(); - } - if (cpuid == id) - return dp; - } - return NULL; -} - -void __init of_fill_in_cpu_data(void) +static void *of_iterate_over_cpus(void *(*func)(struct device_node *, int, int), int arg) { struct device_node *dp; const char *mid_prop; - if (tlb_type == hypervisor) - return; - mid_prop = get_mid_prop(); - ncpus_probed = 0; for_each_node_by_type(dp, "cpu") { int cpuid = of_getintprop_default(dp, mid_prop, -1); const char *this_mid_prop = mid_prop; - struct device_node *portid_parent; - int portid = -1; + void *ret; - portid_parent = NULL; if (cpuid < 0) { this_mid_prop = "cpuid"; cpuid = of_getintprop_default(dp, this_mid_prop, -1); - if (cpuid >= 0) { - int limit = 2; - - portid_parent = dp; - while (limit--) { - portid_parent = portid_parent->parent; - if (!portid_parent) - break; - portid = of_getintprop_default(portid_parent, - "portid", -1); - if (portid >= 0) - break; - } - } } - if (cpuid < 0) { prom_printf("OF: Serious problem, cpu lacks " "%s property", this_mid_prop); prom_halt(); } - - ncpus_probed++; - #ifdef CONFIG_SMP if (cpuid >= NR_CPUS) { printk(KERN_WARNING "Ignoring CPU %d which is " @@ -450,79 +401,143 @@ void __init of_fill_in_cpu_data(void) cpuid, NR_CPUS); continue; } -#else - /* On uniprocessor we only want the values for the - * real physical cpu the kernel booted onto, however - * cpu_data() only has one entry at index 0. - */ - if (cpuid != real_hard_smp_processor_id()) - continue; - cpuid = 0; #endif + ret = func(dp, cpuid, arg); + if (ret) + return ret; + } + return NULL; +} - cpu_data(cpuid).clock_tick = - of_getintprop_default(dp, "clock-frequency", 0); - - if (portid_parent) { - cpu_data(cpuid).dcache_size = - of_getintprop_default(dp, "l1-dcache-size", - 16 * 1024); - cpu_data(cpuid).dcache_line_size = - of_getintprop_default(dp, "l1-dcache-line-size", - 32); - cpu_data(cpuid).icache_size = - of_getintprop_default(dp, "l1-icache-size", - 8 * 1024); - cpu_data(cpuid).icache_line_size = - of_getintprop_default(dp, "l1-icache-line-size", - 32); - cpu_data(cpuid).ecache_size = - of_getintprop_default(dp, "l2-cache-size", 0); - cpu_data(cpuid).ecache_line_size = - of_getintprop_default(dp, "l2-cache-line-size", 0); - if (!cpu_data(cpuid).ecache_size || - !cpu_data(cpuid).ecache_line_size) { - cpu_data(cpuid).ecache_size = - of_getintprop_default(portid_parent, - "l2-cache-size", - (4 * 1024 * 1024)); - cpu_data(cpuid).ecache_line_size = - of_getintprop_default(portid_parent, - "l2-cache-line-size", 64); - } - - cpu_data(cpuid).core_id = portid + 1; - cpu_data(cpuid).proc_id = portid; +static void *check_cpu_node(struct device_node *dp, int cpuid, int id) +{ + if (id == cpuid) + return dp; + return NULL; +} + +struct device_node *of_find_node_by_cpuid(int cpuid) +{ + return of_iterate_over_cpus(check_cpu_node, cpuid); +} + +static void *record_one_cpu(struct device_node *dp, int cpuid, int arg) +{ + ncpus_probed++; #ifdef CONFIG_SMP - sparc64_multi_core = 1; + set_cpu_present(cpuid, true); + set_cpu_possible(cpuid, true); #endif - } else { - cpu_data(cpuid).dcache_size = - of_getintprop_default(dp, "dcache-size", 16 * 1024); - cpu_data(cpuid).dcache_line_size = - of_getintprop_default(dp, "dcache-line-size", 32); + return NULL; +} - cpu_data(cpuid).icache_size = - of_getintprop_default(dp, "icache-size", 16 * 1024); - cpu_data(cpuid).icache_line_size = - of_getintprop_default(dp, "icache-line-size", 32); +void __init of_populate_present_mask(void) +{ + if (tlb_type == hypervisor) + return; + + ncpus_probed = 0; + of_iterate_over_cpus(record_one_cpu, 0); +} +static void *fill_in_one_cpu(struct device_node *dp, int cpuid, int arg) +{ + struct device_node *portid_parent = NULL; + int portid = -1; + + if (of_find_property(dp, "cpuid", NULL)) { + int limit = 2; + + portid_parent = dp; + while (limit--) { + portid_parent = portid_parent->parent; + if (!portid_parent) + break; + portid = of_getintprop_default(portid_parent, + "portid", -1); + if (portid >= 0) + break; + } + } + +#ifndef CONFIG_SMP + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + return NULL; + cpuid = 0; +#endif + + cpu_data(cpuid).clock_tick = + of_getintprop_default(dp, "clock-frequency", 0); + + if (portid_parent) { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "l1-dcache-size", + 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "l1-dcache-line-size", + 32); + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "l1-icache-size", + 8 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "l1-icache-line-size", + 32); + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "l2-cache-size", 0); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "l2-cache-line-size", 0); + if (!cpu_data(cpuid).ecache_size || + !cpu_data(cpuid).ecache_line_size) { cpu_data(cpuid).ecache_size = - of_getintprop_default(dp, "ecache-size", + of_getintprop_default(portid_parent, + "l2-cache-size", (4 * 1024 * 1024)); cpu_data(cpuid).ecache_line_size = - of_getintprop_default(dp, "ecache-line-size", 64); - - cpu_data(cpuid).core_id = 0; - cpu_data(cpuid).proc_id = -1; + of_getintprop_default(portid_parent, + "l2-cache-line-size", 64); } + cpu_data(cpuid).core_id = portid + 1; + cpu_data(cpuid).proc_id = portid; #ifdef CONFIG_SMP - set_cpu_present(cpuid, true); - set_cpu_possible(cpuid, true); + sparc64_multi_core = 1; #endif + } else { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "dcache-size", 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "dcache-line-size", 32); + + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "icache-size", 16 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "icache-line-size", 32); + + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "ecache-size", + (4 * 1024 * 1024)); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "ecache-line-size", 64); + + cpu_data(cpuid).core_id = 0; + cpu_data(cpuid).proc_id = -1; } + return NULL; +} + +void __init of_fill_in_cpu_data(void) +{ + if (tlb_type == hypervisor) + return; + + of_populate_present_mask(); + of_iterate_over_cpus(fill_in_one_cpu, 0); + smp_fill_in_sib_core_maps(); } -- cgit v0.10.2 From 5052f525fde2dcb550cc3b4f15d2bfdd2a5c8782 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 8 Apr 2009 19:55:47 -0700 Subject: sparc64: Refactor MDESC cpu scanning code using an iterator. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/mdesc.h b/arch/sparc/include/asm/mdesc.h index 1acc727..8f8a520 100644 --- a/arch/sparc/include/asm/mdesc.h +++ b/arch/sparc/include/asm/mdesc.h @@ -72,6 +72,7 @@ struct mdesc_notifier_client { extern void mdesc_register_notifier(struct mdesc_notifier_client *client); extern void mdesc_fill_in_cpu_data(cpumask_t mask); +extern void mdesc_populate_present_mask(cpumask_t *mask); extern void sun4v_mdesc_init(void); diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index f0e6ed2..f50af3f 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -574,7 +574,7 @@ static void __init report_platform_properties(void) mdesc_release(hp); } -static void __devinit fill_in_one_cache(cpuinfo_sparc *c, +static void __cpuinit fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_handle *hp, u64 mp) { @@ -619,8 +619,7 @@ static void __devinit fill_in_one_cache(cpuinfo_sparc *c, } } -static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp, - int core_id) +static void __cpuinit mark_core_ids(struct mdesc_handle *hp, u64 mp, int core_id) { u64 a; @@ -653,7 +652,7 @@ static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp, } } -static void __devinit set_core_ids(struct mdesc_handle *hp) +static void __cpuinit set_core_ids(struct mdesc_handle *hp) { int idx; u64 mp; @@ -678,8 +677,7 @@ static void __devinit set_core_ids(struct mdesc_handle *hp) } } -static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, - int proc_id) +static void __cpuinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id) { u64 a; @@ -698,8 +696,7 @@ static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, } } -static void __devinit __set_proc_ids(struct mdesc_handle *hp, - const char *exec_unit_name) +static void __cpuinit __set_proc_ids(struct mdesc_handle *hp, const char *exec_unit_name) { int idx; u64 mp; @@ -720,13 +717,13 @@ static void __devinit __set_proc_ids(struct mdesc_handle *hp, } } -static void __devinit set_proc_ids(struct mdesc_handle *hp) +static void __cpuinit set_proc_ids(struct mdesc_handle *hp) { __set_proc_ids(hp, "exec_unit"); __set_proc_ids(hp, "exec-unit"); } -static void __devinit get_one_mondo_bits(const u64 *p, unsigned int *mask, +static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) { u64 val; @@ -745,7 +742,7 @@ use_default: *mask = ((1U << def) * 64U) - 1U; } -static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp, +static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp, struct trap_per_cpu *tb) { const u64 *val; @@ -763,23 +760,15 @@ static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp, get_one_mondo_bits(val, &tb->nonresum_qmask, 2); } -void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask) +static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask) { struct mdesc_handle *hp = mdesc_grab(); + void *ret = NULL; u64 mp; - ncpus_probed = 0; mdesc_for_each_node_by_name(hp, mp, "cpu") { const u64 *id = mdesc_get_property(hp, mp, "id", NULL); - const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL); - struct trap_per_cpu *tb; - cpuinfo_sparc *c; - int cpuid; - u64 a; - - ncpus_probed++; - - cpuid = *id; + int cpuid = *id; #ifdef CONFIG_SMP if (cpuid >= NR_CPUS) { @@ -788,62 +777,105 @@ void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask) cpuid, NR_CPUS); continue; } - if (!cpu_isset(cpuid, mask)) - continue; -#else - /* On uniprocessor we only want the values for the - * real physical cpu the kernel booted onto, however - * cpu_data() only has one entry at index 0. - */ - if (cpuid != real_hard_smp_processor_id()) + if (!cpu_isset(cpuid, *mask)) continue; - cpuid = 0; #endif - c = &cpu_data(cpuid); - c->clock_tick = *cfreq; + ret = func(hp, mp, cpuid, arg); + if (ret) + goto out; + } +out: + mdesc_release(hp); + return ret; +} - tb = &trap_block[cpuid]; - get_mondo_data(hp, mp, tb); +static void * __cpuinit record_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg) +{ + ncpus_probed++; +#ifdef CONFIG_SMP + set_cpu_present(cpuid, true); +#endif + return NULL; +} - mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { - u64 j, t = mdesc_arc_target(hp, a); - const char *t_name; +void __cpuinit mdesc_populate_present_mask(cpumask_t *mask) +{ + if (tlb_type != hypervisor) + return; - t_name = mdesc_node_name(hp, t); - if (!strcmp(t_name, "cache")) { - fill_in_one_cache(c, hp, t); - continue; - } + ncpus_probed = 0; + mdesc_iterate_over_cpus(record_one_cpu, NULL, mask); +} - mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) { - u64 n = mdesc_arc_target(hp, j); - const char *n_name; +static void * __cpuinit fill_in_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg) +{ + const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL); + struct trap_per_cpu *tb; + cpuinfo_sparc *c; + u64 a; - n_name = mdesc_node_name(hp, n); - if (!strcmp(n_name, "cache")) - fill_in_one_cache(c, hp, n); - } +#ifndef CONFIG_SMP + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + return NULL; + cpuid = 0; +#endif + + c = &cpu_data(cpuid); + c->clock_tick = *cfreq; + + tb = &trap_block[cpuid]; + get_mondo_data(hp, mp, tb); + + mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { + u64 j, t = mdesc_arc_target(hp, a); + const char *t_name; + + t_name = mdesc_node_name(hp, t); + if (!strcmp(t_name, "cache")) { + fill_in_one_cache(c, hp, t); + continue; } -#ifdef CONFIG_SMP - cpu_set(cpuid, cpu_present_map); -#endif + mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) { + u64 n = mdesc_arc_target(hp, j); + const char *n_name; - c->core_id = 0; - c->proc_id = -1; + n_name = mdesc_node_name(hp, n); + if (!strcmp(n_name, "cache")) + fill_in_one_cache(c, hp, n); + } } + c->core_id = 0; + c->proc_id = -1; + + return NULL; +} + +void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask) +{ + struct mdesc_handle *hp; + + mdesc_populate_present_mask(&mask); + mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, &mask); + #ifdef CONFIG_SMP sparc64_multi_core = 1; #endif + hp = mdesc_grab(); + set_core_ids(hp); set_proc_ids(hp); - smp_fill_in_sib_core_maps(); - mdesc_release(hp); + + smp_fill_in_sib_core_maps(); } static ssize_t mdesc_read(struct file *file, char __user *buf, -- cgit v0.10.2 From 890db403d59fbeaf273ed019d0b1862223d80a9a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Apr 2009 03:13:15 -0700 Subject: sparc: Call OF and MD cpu scanning explicitly from paging_init() We need to split up the cpu present mask setup from the cpu_data initialization, and this is a first step towards that. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index 1b15212..be8d7aa 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -87,6 +87,7 @@ extern int of_node_to_nid(struct device_node *dp); extern void prom_build_devicetree(void); extern void of_populate_present_mask(void); +extern void of_fill_in_cpu_data(void); /* Dummy ref counting routines - to be implemented later */ static inline struct device_node *of_node_get(struct device_node *node) diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index f50af3f..602cbb7 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -919,7 +919,6 @@ void __init sun4v_mdesc_init(void) { struct mdesc_handle *hp; unsigned long len, real_len, status; - cpumask_t mask; (void) sun4v_mach_desc(0UL, 0UL, &len); @@ -943,7 +942,4 @@ void __init sun4v_mdesc_init(void) cur_mdesc = hp; report_platform_properties(); - - cpus_setall(mask); - mdesc_fill_in_cpu_data(mask); } diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h index bb0f0fd..453397f 100644 --- a/arch/sparc/kernel/prom.h +++ b/arch/sparc/kernel/prom.h @@ -22,7 +22,6 @@ static inline int is_root_node(const struct device_node *dp) extern char *build_path_component(struct device_node *dp); extern void of_console_init(void); -extern void of_fill_in_cpu_data(void); extern unsigned int prom_early_allocated; diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index ff7b591..0fb5789 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -313,6 +313,4 @@ void __init prom_build_devicetree(void) printk("PROM: Built device tree with %u bytes of memory.\n", prom_early_allocated); - - of_fill_in_cpu_data(); } diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index cbb282d..26bb391 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c @@ -358,6 +358,7 @@ void __init paging_init(void) protection_map[15] = PAGE_SHARED; btfixup(); prom_build_devicetree(); + of_fill_in_cpu_data(); device_scan(); } diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index f26a352..c589d6e 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1806,9 +1806,12 @@ void __init paging_init(void) real_setup_per_cpu_areas(); prom_build_devicetree(); + of_fill_in_cpu_data(); - if (tlb_type == hypervisor) + if (tlb_type == hypervisor) { sun4v_mdesc_init(); + mdesc_fill_in_cpu_data(CPU_MASK_ALL); + } /* Once the OF device tree and MDESC have been setup, we know * the list of possible cpus. Therefore we can allocate the -- cgit v0.10.2 From a2094502dce23e9ace04d49702aa7a4d5996df55 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Apr 2009 03:15:11 -0700 Subject: sparc64: Make mdesc_fill_in_cpu_data take a cpumask_t pointer. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/mdesc.h b/arch/sparc/include/asm/mdesc.h index 8f8a520..9faa046 100644 --- a/arch/sparc/include/asm/mdesc.h +++ b/arch/sparc/include/asm/mdesc.h @@ -71,7 +71,7 @@ struct mdesc_notifier_client { extern void mdesc_register_notifier(struct mdesc_notifier_client *client); -extern void mdesc_fill_in_cpu_data(cpumask_t mask); +extern void mdesc_fill_in_cpu_data(cpumask_t *mask); extern void mdesc_populate_present_mask(cpumask_t *mask); extern void sun4v_mdesc_init(void); diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index 90350f83..51b05c4 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -544,7 +544,7 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp, resp_len, ncpus, mask, DR_CPU_STAT_CONFIGURED); - mdesc_fill_in_cpu_data(*mask); + mdesc_fill_in_cpu_data(mask); for_each_cpu_mask(cpu, *mask) { int err; diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 602cbb7..6d2015e 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -857,12 +857,12 @@ static void * __cpuinit fill_in_one_cpu(struct mdesc_handle *hp, u64 mp, int cpu return NULL; } -void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask) +void __cpuinit mdesc_fill_in_cpu_data(cpumask_t *mask) { struct mdesc_handle *hp; - mdesc_populate_present_mask(&mask); - mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, &mask); + mdesc_populate_present_mask(mask); + mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask); #ifdef CONFIG_SMP sparc64_multi_core = 1; diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index c589d6e..87fea94 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1810,7 +1810,7 @@ void __init paging_init(void) if (tlb_type == hypervisor) { sun4v_mdesc_init(); - mdesc_fill_in_cpu_data(CPU_MASK_ALL); + mdesc_fill_in_cpu_data(CPU_MASK_ALL_PTR); } /* Once the OF device tree and MDESC have been setup, we know -- cgit v0.10.2 From b696fdc259f0d94348a9327bed352fac44d4883d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 May 2009 22:37:25 -0700 Subject: sparc64: Defer cpu_data() setup until end of per-cpu data initialization. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index 51b05c4..4a700f4 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -544,6 +544,7 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp, resp_len, ncpus, mask, DR_CPU_STAT_CONFIGURED); + mdesc_populate_present_mask(mask); mdesc_fill_in_cpu_data(mask); for_each_cpu_mask(cpu, *mask) { diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 6d2015e..938da19 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -861,7 +861,6 @@ void __cpuinit mdesc_fill_in_cpu_data(cpumask_t *mask) { struct mdesc_handle *hp; - mdesc_populate_present_mask(mask); mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask); #ifdef CONFIG_SMP diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c index 4d92f48..fb06ac2 100644 --- a/arch/sparc/kernel/prom_64.c +++ b/arch/sparc/kernel/prom_64.c @@ -535,7 +535,6 @@ void __init of_fill_in_cpu_data(void) if (tlb_type == hypervisor) return; - of_populate_present_mask(); of_iterate_over_cpus(fill_in_one_cpu, 0); smp_fill_in_sib_core_maps(); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index b20f253..045fbb5 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1399,4 +1399,8 @@ void __init real_setup_per_cpu_areas(void) /* Setup %g5 for the boot cpu. */ __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); + + of_fill_in_cpu_data(); + if (tlb_type == hypervisor) + mdesc_fill_in_cpu_data(CPU_MASK_ALL_PTR); } diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 87fea94..785f0a2 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1799,20 +1799,16 @@ void __init paging_init(void) if (tlb_type == hypervisor) sun4v_ktsb_register(); - /* We must setup the per-cpu areas before we pull in the - * PROM and the MDESC. The code there fills in cpu and - * other information into per-cpu data structures. - */ - real_setup_per_cpu_areas(); - prom_build_devicetree(); - of_fill_in_cpu_data(); + of_populate_present_mask(); if (tlb_type == hypervisor) { sun4v_mdesc_init(); - mdesc_fill_in_cpu_data(CPU_MASK_ALL_PTR); + mdesc_populate_present_mask(CPU_MASK_ALL_PTR); } + real_setup_per_cpu_areas(); + /* Once the OF device tree and MDESC have been setup, we know * the list of possible cpus. Therefore we can allocate the * IRQ stacks. -- cgit v0.10.2 From 73fffc037e2383a0ed126d57bdcda9b369769ae8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Apr 2009 16:15:20 -0700 Subject: sparc64: Get rid of real_setup_per_cpu_areas(). Now that we defer the cpu_data() initializations to the end of per-cpu setup, we can get rid of this local hack we had to setup the per-cpu areas eary. This is a necessary step in order to support HAVE_DYNAMIC_PER_CPU_AREA since the per-cpu setup must run when page structs are available. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/percpu_64.h b/arch/sparc/include/asm/percpu_64.h index c0ab102..007aafb 100644 --- a/arch/sparc/include/asm/percpu_64.h +++ b/arch/sparc/include/asm/percpu_64.h @@ -9,8 +9,6 @@ register unsigned long __local_per_cpu_offset asm("g5"); #include -extern void real_setup_per_cpu_areas(void); - #define __per_cpu_offset(__cpu) \ (trap_block[(__cpu)].__per_cpu_base) #define per_cpu_offset(x) (__per_cpu_offset(x)) @@ -19,8 +17,6 @@ extern void real_setup_per_cpu_areas(void); #else /* ! SMP */ -#define real_setup_per_cpu_areas() do { } while (0) - #endif /* SMP */ #include diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 045fbb5..5302344 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -1371,9 +1371,9 @@ void smp_send_stop(void) { } -void __init real_setup_per_cpu_areas(void) +void __init setup_per_cpu_areas(void) { - unsigned long base, shift, paddr, goal, size, i; + unsigned long base, shift, goal, size, i; char *ptr; /* Copy section for each CPU (we discard the original) */ @@ -1383,13 +1383,12 @@ void __init real_setup_per_cpu_areas(void) for (size = PAGE_SIZE; size < goal; size <<= 1UL) shift++; - paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE); - if (!paddr) { + ptr = __alloc_bootmem(size * NR_CPUS, PAGE_SIZE, 0); + if (!ptr) { prom_printf("Cannot allocate per-cpu memory.\n"); prom_halt(); } - ptr = __va(paddr); base = ptr - __per_cpu_start; for (i = 0; i < NR_CPUS; i++, ptr += size) { diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 785f0a2..b5a5932 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1679,11 +1679,6 @@ pgd_t swapper_pg_dir[2048]; static void sun4u_pgprot_init(void); static void sun4v_pgprot_init(void); -/* Dummy function */ -void __init setup_per_cpu_areas(void) -{ -} - void __init paging_init(void) { unsigned long end_pfn, shift, phys_base; @@ -1807,8 +1802,6 @@ void __init paging_init(void) mdesc_populate_present_mask(CPU_MASK_ALL_PTR); } - real_setup_per_cpu_areas(); - /* Once the OF device tree and MDESC have been setup, we know * the list of possible cpus. Therefore we can allocate the * IRQ stacks. -- cgit v0.10.2 From 0c243ad81f234672bebb72cf3dd014b9c841781d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Apr 2009 16:22:27 -0700 Subject: sparc64: Only allocate per-cpu areas for possible cpus. This gets us real close to the generic implementation of setup_per_cpu_areas() except: 1) We store the per-cpu offset into the trap_block[], whereas the generic code has it's own static array. 2) We have to initialize the %g5 register to hold the boot cpu's per-cpu area offset. 3) The OBP/MDESC cpu info scan is performed at the end. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 5302344..567a6a47b 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1373,27 +1373,17 @@ void smp_send_stop(void) void __init setup_per_cpu_areas(void) { - unsigned long base, shift, goal, size, i; + unsigned long size, i, nr_possible_cpus = num_possible_cpus(); char *ptr; /* Copy section for each CPU (we discard the original) */ - goal = PERCPU_ENOUGH_ROOM; + size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE); + ptr = alloc_bootmem_pages(size * nr_possible_cpus); - shift = PAGE_SHIFT; - for (size = PAGE_SIZE; size < goal; size <<= 1UL) - shift++; - - ptr = __alloc_bootmem(size * NR_CPUS, PAGE_SIZE, 0); - if (!ptr) { - prom_printf("Cannot allocate per-cpu memory.\n"); - prom_halt(); - } - - base = ptr - __per_cpu_start; - - for (i = 0; i < NR_CPUS; i++, ptr += size) { - __per_cpu_offset(i) = base + (i * size); + for_each_possible_cpu(i) { + __per_cpu_offset(i) = ptr - __per_cpu_start; memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); + ptr += size; } /* Setup %g5 for the boot cpu. */ -- cgit v0.10.2 From 4fd78a5f1edf62ab1ca3d23efee4a8a336edb2b6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 8 Apr 2009 20:32:02 -0700 Subject: sparc64: Use new dynamic per-cpu allocator. Signed-off-by: David S. Miller diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index cc12cd4..2185cf9 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -93,6 +93,9 @@ config AUDIT_ARCH config HAVE_SETUP_PER_CPU_AREA def_bool y if SPARC64 +config HAVE_DYNAMIC_PER_CPU_AREA + def_bool y if SPARC64 + config GENERIC_HARDIRQS_NO__DO_IRQ bool def_bool y if SPARC64 diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 567a6a47b..1de47d2 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1371,19 +1372,165 @@ void smp_send_stop(void) { } +/** + * pcpu_alloc_bootmem - NUMA friendly alloc_bootmem wrapper for percpu + * @cpu: cpu to allocate for + * @size: size allocation in bytes + * @align: alignment + * + * Allocate @size bytes aligned at @align for cpu @cpu. This wrapper + * does the right thing for NUMA regardless of the current + * configuration. + * + * RETURNS: + * Pointer to the allocated area on success, NULL on failure. + */ +static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size, + unsigned long align) +{ + const unsigned long goal = __pa(MAX_DMA_ADDRESS); +#ifdef CONFIG_NEED_MULTIPLE_NODES + int node = cpu_to_node(cpu); + void *ptr; + + if (!node_online(node) || !NODE_DATA(node)) { + ptr = __alloc_bootmem(size, align, goal); + pr_info("cpu %d has no node %d or node-local memory\n", + cpu, node); + pr_debug("per cpu data for cpu%d %lu bytes at %016lx\n", + cpu, size, __pa(ptr)); + } else { + ptr = __alloc_bootmem_node(NODE_DATA(node), + size, align, goal); + pr_debug("per cpu data for cpu%d %lu bytes on node%d at " + "%016lx\n", cpu, size, node, __pa(ptr)); + } + return ptr; +#else + return __alloc_bootmem(size, align, goal); +#endif +} + +static size_t pcpur_size __initdata; +static void **pcpur_ptrs __initdata; + +static struct page * __init pcpur_get_page(unsigned int cpu, int pageno) +{ + size_t off = (size_t)pageno << PAGE_SHIFT; + + if (off >= pcpur_size) + return NULL; + + return virt_to_page(pcpur_ptrs[cpu] + off); +} + +#define PCPU_CHUNK_SIZE (4UL * 1024UL * 1024UL) + +static void __init pcpu_map_range(unsigned long start, unsigned long end, + struct page *page) +{ + unsigned long pfn = page_to_pfn(page); + unsigned long pte_base; + + BUG_ON((pfn< end) + this_end = end; + + while (start < this_end) { + unsigned long paddr = pfn << PAGE_SHIFT; + + pte_val(*pte) = (paddr | pte_base); + + start += PAGE_SIZE; + pte++; + pfn++; + } + } +} + void __init setup_per_cpu_areas(void) { - unsigned long size, i, nr_possible_cpus = num_possible_cpus(); - char *ptr; + size_t dyn_size, static_size = __per_cpu_end - __per_cpu_start; + static struct vm_struct vm; + unsigned long delta, cpu; + size_t pcpu_unit_size; + size_t ptrs_size; + + pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE + + PERCPU_DYNAMIC_RESERVE); + dyn_size = pcpur_size - static_size - PERCPU_MODULE_RESERVE; + + + ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0])); + pcpur_ptrs = alloc_bootmem(ptrs_size); + + for_each_possible_cpu(cpu) { + pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE, + PCPU_CHUNK_SIZE); + + free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size), + PCPU_CHUNK_SIZE - pcpur_size); + + memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size); + } + + /* allocate address and map */ + vm.flags = VM_ALLOC; + vm.size = num_possible_cpus() * PCPU_CHUNK_SIZE; + vm_area_register_early(&vm, PCPU_CHUNK_SIZE); + + for_each_possible_cpu(cpu) { + unsigned long start = (unsigned long) vm.addr; + unsigned long end; + + start += cpu * PCPU_CHUNK_SIZE; + end = start + PCPU_CHUNK_SIZE; + pcpu_map_range(start, end, virt_to_page(pcpur_ptrs[cpu])); + } + + pcpu_unit_size = pcpu_setup_first_chunk(pcpur_get_page, static_size, + PERCPU_MODULE_RESERVE, dyn_size, + PCPU_CHUNK_SIZE, vm.addr, NULL); - /* Copy section for each CPU (we discard the original) */ - size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE); - ptr = alloc_bootmem_pages(size * nr_possible_cpus); + free_bootmem(__pa(pcpur_ptrs), ptrs_size); - for_each_possible_cpu(i) { - __per_cpu_offset(i) = ptr - __per_cpu_start; - memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); - ptr += size; + delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; + for_each_possible_cpu(cpu) { + __per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size; } /* Setup %g5 for the boot cpu. */ -- cgit v0.10.2 From 280ff97494e0fef4124bee5c52e39b23a18dd283 Mon Sep 17 00:00:00 2001 From: "Hong H. Pham" Date: Thu, 4 Jun 2009 02:10:11 -0700 Subject: sparc64: fix and optimize irq distribution irq_choose_cpu() should compare the affinity mask against cpu_online_map rather than CPU_MASK_ALL, since irq_select_affinity() sets the interrupt's affinity mask to cpu_online_map "and" CPU_MASK_ALL (which ends up being just cpu_online_map). The mask comparison in irq_choose_cpu() will always fail since the two masks are not the same. So the CPU chosen is the first CPU in the intersection of cpu_online_map and CPU_MASK_ALL, which is always CPU0. That means all interrupts are reassigned to CPU0... Distributing interrupts to CPUs in a linearly increasing round robin fashion is not optimal for the UltraSPARC T1/T2. Also, the irq_rover in irq_choose_cpu() causes an interrupt to be assigned to a different processor each time the interrupt is allocated and released. This may lead to an unbalanced distribution over time. A static mapping of interrupts to processors is done to optimize and balance interrupt distribution. For the T1/T2, interrupts are spread to different cores first, and then to strands within a core. The following is some benchmarks showing the effects of interrupt distribution on a T2. The test was done with iperf using a pair of T5220 boxes, each with a 10GBe NIU (XAUI) connected back to back. TCP | Stock Linear RR IRQ Optimized IRQ Streams | 2.6.30-rc5 Distribution Distribution | GBits/sec GBits/sec GBits/sec --------+----------------------------------------- 1 0.839 0.862 0.868 8 1.16 4.96 5.88 16 1.15 6.40 8.04 100 1.09 7.28 8.68 Signed-off-by: Hong H. Pham Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 54742e5..47029c6 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_SPARC64) += sstate.o obj-$(CONFIG_SPARC64) += mdesc.o obj-$(CONFIG_SPARC64) += pcr.o obj-$(CONFIG_SPARC64) += nmi.o +obj-$(CONFIG_SPARC64_SMP) += cpumap.o # sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation obj-$(CONFIG_SPARC32) += devres.o diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c new file mode 100644 index 0000000..7430ed0 --- /dev/null +++ b/arch/sparc/kernel/cpumap.c @@ -0,0 +1,431 @@ +/* cpumap.c: used for optimizing CPU assignment + * + * Copyright (C) 2009 Hong H. Pham + */ + +#include +#include +#include +#include +#include +#include +#include "cpumap.h" + + +enum { + CPUINFO_LVL_ROOT = 0, + CPUINFO_LVL_NODE, + CPUINFO_LVL_CORE, + CPUINFO_LVL_PROC, + CPUINFO_LVL_MAX, +}; + +enum { + ROVER_NO_OP = 0, + /* Increment rover every time level is visited */ + ROVER_INC_ON_VISIT = 1 << 0, + /* Increment parent's rover every time rover wraps around */ + ROVER_INC_PARENT_ON_LOOP = 1 << 1, +}; + +struct cpuinfo_node { + int id; + int level; + int num_cpus; /* Number of CPUs in this hierarchy */ + int parent_index; + int child_start; /* Array index of the first child node */ + int child_end; /* Array index of the last child node */ + int rover; /* Child node iterator */ +}; + +struct cpuinfo_level { + int start_index; /* Index of first node of a level in a cpuinfo tree */ + int end_index; /* Index of last node of a level in a cpuinfo tree */ + int num_nodes; /* Number of nodes in a level in a cpuinfo tree */ +}; + +struct cpuinfo_tree { + int total_nodes; + + /* Offsets into nodes[] for each level of the tree */ + struct cpuinfo_level level[CPUINFO_LVL_MAX]; + struct cpuinfo_node nodes[0]; +}; + + +static struct cpuinfo_tree *cpuinfo_tree; + +static u16 cpu_distribution_map[NR_CPUS]; +static DEFINE_SPINLOCK(cpu_map_lock); + + +/* Niagara optimized cpuinfo tree traversal. */ +static const int niagara_iterate_method[] = { + [CPUINFO_LVL_ROOT] = ROVER_NO_OP, + + /* Strands (or virtual CPUs) within a core may not run concurrently + * on the Niagara, as instruction pipeline(s) are shared. Distribute + * work to strands in different cores first for better concurrency. + * Go to next NUMA node when all cores are used. + */ + [CPUINFO_LVL_NODE] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP, + + /* Strands are grouped together by proc_id in cpuinfo_sparc, i.e. + * a proc_id represents an instruction pipeline. Distribute work to + * strands in different proc_id groups if the core has multiple + * instruction pipelines (e.g. the Niagara 2/2+ has two). + */ + [CPUINFO_LVL_CORE] = ROVER_INC_ON_VISIT, + + /* Pick the next strand in the proc_id group. */ + [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT, +}; + +/* Generic cpuinfo tree traversal. Distribute work round robin across NUMA + * nodes. + */ +static const int generic_iterate_method[] = { + [CPUINFO_LVL_ROOT] = ROVER_INC_ON_VISIT, + [CPUINFO_LVL_NODE] = ROVER_NO_OP, + [CPUINFO_LVL_CORE] = ROVER_INC_PARENT_ON_LOOP, + [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP, +}; + + +static int cpuinfo_id(int cpu, int level) +{ + int id; + + switch (level) { + case CPUINFO_LVL_ROOT: + id = 0; + break; + case CPUINFO_LVL_NODE: + id = cpu_to_node(cpu); + break; + case CPUINFO_LVL_CORE: + id = cpu_data(cpu).core_id; + break; + case CPUINFO_LVL_PROC: + id = cpu_data(cpu).proc_id; + break; + default: + id = -EINVAL; + } + return id; +} + +/* + * Enumerate the CPU information in __cpu_data to determine the start index, + * end index, and number of nodes for each level in the cpuinfo tree. The + * total number of cpuinfo nodes required to build the tree is returned. + */ +static int enumerate_cpuinfo_nodes(struct cpuinfo_level *tree_level) +{ + int prev_id[CPUINFO_LVL_MAX]; + int i, n, num_nodes; + + for (i = CPUINFO_LVL_ROOT; i < CPUINFO_LVL_MAX; i++) { + struct cpuinfo_level *lv = &tree_level[i]; + + prev_id[i] = -1; + lv->start_index = lv->end_index = lv->num_nodes = 0; + } + + num_nodes = 1; /* Include the root node */ + + for (i = 0; i < num_possible_cpus(); i++) { + if (!cpu_online(i)) + continue; + + n = cpuinfo_id(i, CPUINFO_LVL_NODE); + if (n > prev_id[CPUINFO_LVL_NODE]) { + tree_level[CPUINFO_LVL_NODE].num_nodes++; + prev_id[CPUINFO_LVL_NODE] = n; + num_nodes++; + } + n = cpuinfo_id(i, CPUINFO_LVL_CORE); + if (n > prev_id[CPUINFO_LVL_CORE]) { + tree_level[CPUINFO_LVL_CORE].num_nodes++; + prev_id[CPUINFO_LVL_CORE] = n; + num_nodes++; + } + n = cpuinfo_id(i, CPUINFO_LVL_PROC); + if (n > prev_id[CPUINFO_LVL_PROC]) { + tree_level[CPUINFO_LVL_PROC].num_nodes++; + prev_id[CPUINFO_LVL_PROC] = n; + num_nodes++; + } + } + + tree_level[CPUINFO_LVL_ROOT].num_nodes = 1; + + n = tree_level[CPUINFO_LVL_NODE].num_nodes; + tree_level[CPUINFO_LVL_NODE].start_index = 1; + tree_level[CPUINFO_LVL_NODE].end_index = n; + + n++; + tree_level[CPUINFO_LVL_CORE].start_index = n; + n += tree_level[CPUINFO_LVL_CORE].num_nodes; + tree_level[CPUINFO_LVL_CORE].end_index = n - 1; + + tree_level[CPUINFO_LVL_PROC].start_index = n; + n += tree_level[CPUINFO_LVL_PROC].num_nodes; + tree_level[CPUINFO_LVL_PROC].end_index = n - 1; + + return num_nodes; +} + +/* Build a tree representation of the CPU hierarchy using the per CPU + * information in __cpu_data. Entries in __cpu_data[0..NR_CPUS] are + * assumed to be sorted in ascending order based on node, core_id, and + * proc_id (in order of significance). + */ +static struct cpuinfo_tree *build_cpuinfo_tree(void) +{ + struct cpuinfo_tree *new_tree; + struct cpuinfo_node *node; + struct cpuinfo_level tmp_level[CPUINFO_LVL_MAX]; + int num_cpus[CPUINFO_LVL_MAX]; + int level_rover[CPUINFO_LVL_MAX]; + int prev_id[CPUINFO_LVL_MAX]; + int n, id, cpu, prev_cpu, last_cpu, level; + + n = enumerate_cpuinfo_nodes(tmp_level); + + new_tree = kzalloc(sizeof(struct cpuinfo_tree) + + (sizeof(struct cpuinfo_node) * n), GFP_ATOMIC); + if (!new_tree) + return NULL; + + new_tree->total_nodes = n; + memcpy(&new_tree->level, tmp_level, sizeof(tmp_level)); + + prev_cpu = cpu = first_cpu(cpu_online_map); + + /* Initialize all levels in the tree with the first CPU */ + for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; level--) { + n = new_tree->level[level].start_index; + + level_rover[level] = n; + node = &new_tree->nodes[n]; + + id = cpuinfo_id(cpu, level); + if (unlikely(id < 0)) { + kfree(new_tree); + return NULL; + } + node->id = id; + node->level = level; + node->num_cpus = 1; + + node->parent_index = (level > CPUINFO_LVL_ROOT) + ? new_tree->level[level - 1].start_index : -1; + + node->child_start = node->child_end = node->rover = + (level == CPUINFO_LVL_PROC) + ? cpu : new_tree->level[level + 1].start_index; + + prev_id[level] = node->id; + num_cpus[level] = 1; + } + + for (last_cpu = (num_possible_cpus() - 1); last_cpu >= 0; last_cpu--) { + if (cpu_online(last_cpu)) + break; + } + + while (++cpu <= last_cpu) { + if (!cpu_online(cpu)) + continue; + + for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; + level--) { + id = cpuinfo_id(cpu, level); + if (unlikely(id < 0)) { + kfree(new_tree); + return NULL; + } + + if ((id != prev_id[level]) || (cpu == last_cpu)) { + prev_id[level] = id; + node = &new_tree->nodes[level_rover[level]]; + node->num_cpus = num_cpus[level]; + num_cpus[level] = 1; + + if (cpu == last_cpu) + node->num_cpus++; + + /* Connect tree node to parent */ + if (level == CPUINFO_LVL_ROOT) + node->parent_index = -1; + else + node->parent_index = + level_rover[level - 1]; + + if (level == CPUINFO_LVL_PROC) { + node->child_end = + (cpu == last_cpu) ? cpu : prev_cpu; + } else { + node->child_end = + level_rover[level + 1] - 1; + } + + /* Initialize the next node in the same level */ + n = ++level_rover[level]; + if (n <= new_tree->level[level].end_index) { + node = &new_tree->nodes[n]; + node->id = id; + node->level = level; + + /* Connect node to child */ + node->child_start = node->child_end = + node->rover = + (level == CPUINFO_LVL_PROC) + ? cpu : level_rover[level + 1]; + } + } else + num_cpus[level]++; + } + prev_cpu = cpu; + } + + return new_tree; +} + +static void increment_rover(struct cpuinfo_tree *t, int node_index, + int root_index, const int *rover_inc_table) +{ + struct cpuinfo_node *node = &t->nodes[node_index]; + int top_level, level; + + top_level = t->nodes[root_index].level; + for (level = node->level; level >= top_level; level--) { + node->rover++; + if (node->rover <= node->child_end) + return; + + node->rover = node->child_start; + /* If parent's rover does not need to be adjusted, stop here. */ + if ((level == top_level) || + !(rover_inc_table[level] & ROVER_INC_PARENT_ON_LOOP)) + return; + + node = &t->nodes[node->parent_index]; + } +} + +static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index) +{ + const int *rover_inc_table; + int level, new_index, index = root_index; + + switch (sun4v_chip_type) { + case SUN4V_CHIP_NIAGARA1: + case SUN4V_CHIP_NIAGARA2: + rover_inc_table = niagara_iterate_method; + break; + default: + rover_inc_table = generic_iterate_method; + } + + for (level = t->nodes[root_index].level; level < CPUINFO_LVL_MAX; + level++) { + new_index = t->nodes[index].rover; + if (rover_inc_table[level] & ROVER_INC_ON_VISIT) + increment_rover(t, index, root_index, rover_inc_table); + + index = new_index; + } + return index; +} + +static void _cpu_map_rebuild(void) +{ + int i; + + if (cpuinfo_tree) { + kfree(cpuinfo_tree); + cpuinfo_tree = NULL; + } + + cpuinfo_tree = build_cpuinfo_tree(); + if (!cpuinfo_tree) + return; + + /* Build CPU distribution map that spans all online CPUs. No need + * to check if the CPU is online, as that is done when the cpuinfo + * tree is being built. + */ + for (i = 0; i < cpuinfo_tree->nodes[0].num_cpus; i++) + cpu_distribution_map[i] = iterate_cpu(cpuinfo_tree, 0); +} + +/* Fallback if the cpuinfo tree could not be built. CPU mapping is linear + * round robin. + */ +static int simple_map_to_cpu(unsigned int index) +{ + int i, end, cpu_rover; + + cpu_rover = 0; + end = index % num_online_cpus(); + for (i = 0; i < num_possible_cpus(); i++) { + if (cpu_online(cpu_rover)) { + if (cpu_rover >= end) + return cpu_rover; + + cpu_rover++; + } + } + + /* Impossible, since num_online_cpus() <= num_possible_cpus() */ + return first_cpu(cpu_online_map); +} + +static int _map_to_cpu(unsigned int index) +{ + struct cpuinfo_node *root_node; + + if (unlikely(!cpuinfo_tree)) { + _cpu_map_rebuild(); + if (!cpuinfo_tree) + return simple_map_to_cpu(index); + } + + root_node = &cpuinfo_tree->nodes[0]; +#ifdef CONFIG_HOTPLUG_CPU + if (unlikely(root_node->num_cpus != num_online_cpus())) { + _cpu_map_rebuild(); + if (!cpuinfo_tree) + return simple_map_to_cpu(index); + } +#endif + return cpu_distribution_map[index % root_node->num_cpus]; +} + +int map_to_cpu(unsigned int index) +{ + int mapped_cpu; + unsigned long flag; + + spin_lock_irqsave(&cpu_map_lock, flag); + mapped_cpu = _map_to_cpu(index); + +#ifdef CONFIG_HOTPLUG_CPU + while (unlikely(!cpu_online(mapped_cpu))) + mapped_cpu = _map_to_cpu(index); +#endif + spin_unlock_irqrestore(&cpu_map_lock, flag); + return mapped_cpu; +} +EXPORT_SYMBOL(map_to_cpu); + +void cpu_map_rebuild(void) +{ + unsigned long flag; + + spin_lock_irqsave(&cpu_map_lock, flag); + _cpu_map_rebuild(); + spin_unlock_irqrestore(&cpu_map_lock, flag); +} diff --git a/arch/sparc/kernel/cpumap.h b/arch/sparc/kernel/cpumap.h new file mode 100644 index 0000000..e639880 --- /dev/null +++ b/arch/sparc/kernel/cpumap.h @@ -0,0 +1,16 @@ +#ifndef _CPUMAP_H +#define _CPUMAP_H + +#ifdef CONFIG_SMP +extern void cpu_map_rebuild(void); +extern int map_to_cpu(unsigned int index); +#define cpu_map_init() cpu_map_rebuild() +#else +#define cpu_map_init() do {} while (0) +static inline int map_to_cpu(unsigned int index) +{ + return raw_smp_processor_id(); +} +#endif + +#endif diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index e5e78f9..bd07505 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -45,6 +45,7 @@ #include #include "entry.h" +#include "cpumap.h" #define NUM_IVECS (IMAP_INR + 1) @@ -256,35 +257,13 @@ static int irq_choose_cpu(unsigned int virt_irq) int cpuid; cpumask_copy(&mask, irq_desc[virt_irq].affinity); - if (cpus_equal(mask, CPU_MASK_ALL)) { - static int irq_rover; - static DEFINE_SPINLOCK(irq_rover_lock); - unsigned long flags; - - /* Round-robin distribution... */ - do_round_robin: - spin_lock_irqsave(&irq_rover_lock, flags); - - while (!cpu_online(irq_rover)) { - if (++irq_rover >= nr_cpu_ids) - irq_rover = 0; - } - cpuid = irq_rover; - do { - if (++irq_rover >= nr_cpu_ids) - irq_rover = 0; - } while (!cpu_online(irq_rover)); - - spin_unlock_irqrestore(&irq_rover_lock, flags); + if (cpus_equal(mask, cpu_online_map)) { + cpuid = map_to_cpu(virt_irq); } else { cpumask_t tmp; cpus_and(tmp, cpu_online_map, mask); - - if (cpus_empty(tmp)) - goto do_round_robin; - - cpuid = first_cpu(tmp); + cpuid = cpus_empty(tmp) ? map_to_cpu(virt_irq) : first_cpu(tmp); } return cpuid; diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 1de47d2..cfb3d06 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -48,6 +48,8 @@ #include #include +#include "cpumap.h" + int sparc64_multi_core __read_mostly; DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; @@ -1314,6 +1316,8 @@ int __cpu_disable(void) cpu_clear(cpu, cpu_online_map); ipi_call_unlock(); + cpu_map_rebuild(); + return 0; } -- cgit v0.10.2 From 3f06cd29358dd390d62afcde14fde54cec9deef9 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 4 May 2009 10:35:36 +0000 Subject: bw2: use standard fields for framebuffer physical address and length Use standard fields fbinfo.fix.smem_start and fbinfo.fix.smem_len for physical address and length of framebuffer. This also fixes output of the 'fbset -i' command - address and length of the framebuffer is displayed correctly. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 1e35ba6..b0b147c 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -111,9 +111,7 @@ struct bw2_par { u32 flags; #define BW2_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -167,17 +165,15 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) struct bw2_par *par = (struct bw2_par *)info->par; return sbusfb_mmap_helper(bw2_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct bw2_par *par = (struct bw2_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN2BW, 1, par->fbsize); + FBTYPE_SUN2BW, 1, info->fix.smem_len); } /* @@ -294,7 +290,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 1); @@ -317,13 +313,13 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * goto out_unmap_regs; } - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); info->flags = FBINFO_DEFAULT; info->fbops = &bw2_ops; info->screen_base = of_ioremap(&op->resource[0], 0, - par->fbsize, "bw2 ram"); + info->fix.smem_len, "bw2 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -338,12 +334,12 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", - dp->full_name, par->which_io, par->physbase); + dp->full_name, par->which_io, info->fix.smem_start); return 0; out_unmap_screen: - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); @@ -363,7 +359,7 @@ static int __devexit bw2_remove(struct of_device *op) unregister_framebuffer(info); of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); framebuffer_release(info); -- cgit v0.10.2 From de4dc48ee26ccc9dbc6a86b0710f7fd408149056 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 4 May 2009 10:36:50 +0000 Subject: cg14: use standard fields for framebuffer physical address and length Use standard fields fbinfo.fix.smem_start and fbinfo.fix.smem_len for physical address and length of framebuffer. This also fixes output of the 'fbset -i' command - address and length of the framebuffer is displayed correctly. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index a2d1882..fe45a3b 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -196,9 +196,7 @@ struct cg14_par { u32 flags; #define CG14_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long iospace; - unsigned long fbsize; struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES]; @@ -271,7 +269,7 @@ static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg14_par *par = (struct cg14_par *) info->par; return sbusfb_mmap_helper(par->mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->iospace, vma); } @@ -343,7 +341,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) default: ret = sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_MDICOLOR, 8, par->fbsize); + FBTYPE_MDICOLOR, 8, + info->fix.smem_len); break; }; @@ -462,7 +461,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, par->cursor, sizeof(struct cg14_cursor)); if (info->screen_base) of_iounmap(&op->resource[1], - info->screen_base, par->fbsize); + info->screen_base, info->fix.smem_len); } static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) @@ -488,14 +487,14 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); if (!strcmp(dp->parent->name, "sbus") || !strcmp(dp->parent->name, "sbi")) { - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->iospace = op->resource[0].flags & IORESOURCE_BITS; } else { - par->physbase = op->resource[1].start; + info->fix.smem_start = op->resource[1].start; par->iospace = op->resource[0].flags & IORESOURCE_BITS; } @@ -507,7 +506,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id sizeof(struct cg14_cursor), "cg14 cursor"); info->screen_base = of_ioremap(&op->resource[1], 0, - par->fbsize, "cg14 ram"); + info->fix.smem_len, "cg14 ram"); if (!par->regs || !par->clut || !par->cursor || !info->screen_base) goto out_unmap_regs; @@ -557,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, - par->iospace, par->physbase, + par->iospace, info->fix.smem_start, par->ramsize >> 20); return 0; -- cgit v0.10.2 From 9fbfd4b8a4d8c097bcb0efd14a84a6869c0ac4d5 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 4 May 2009 10:37:46 +0000 Subject: cg3: use standard fields for framebuffer physical address and length Use standard fields fbinfo.fix.smem_start and fbinfo.fix.smem_len for physical address and length of framebuffer. This also fixes output of the 'fbset -i' command - address and length of the framebuffer is displayed correctly. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 99f87fb..b2319fa 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -118,9 +118,7 @@ struct cg3_par { #define CG3_FLAG_BLANKED 0x00000001 #define CG3_FLAG_RDI 0x00000002 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -231,17 +229,15 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg3_par *par = (struct cg3_par *)info->par; return sbusfb_mmap_helper(cg3_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg3_par *par = (struct cg3_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN3COLOR, 8, par->fbsize); + FBTYPE_SUN3COLOR, 8, info->fix.smem_len); } /* @@ -368,7 +364,7 @@ static int __devinit cg3_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -382,7 +378,7 @@ static int __devinit cg3_probe(struct of_device *op, linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, sizeof(struct cg3_regs), "cg3 regs"); @@ -392,7 +388,7 @@ static int __devinit cg3_probe(struct of_device *op, info->flags = FBINFO_DEFAULT; info->fbops = &cg3_ops; info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET, - par->fbsize, "cg3 ram"); + info->fix.smem_len, "cg3 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -418,7 +414,7 @@ static int __devinit cg3_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: cg3 at %lx:%lx\n", - dp->full_name, par->which_io, par->physbase); + dp->full_name, par->which_io, info->fix.smem_start); return 0; @@ -426,7 +422,7 @@ out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_screen: - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); @@ -447,7 +443,7 @@ static int __devexit cg3_remove(struct of_device *op) fb_dealloc_cmap(&info->cmap); of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); framebuffer_release(info); -- cgit v0.10.2 From 963b916c1cb42450c7a061b13fcce6c9a2cdea28 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 4 May 2009 10:39:45 +0000 Subject: cg6: use standard fields for framebuffer physical address and length Use standard fields fbinfo.fix.smem_start and fbinfo.fix.smem_len for physical address and length of framebuffer. This also fixes output of the 'fbset -i' command - address and length of the framebuffer are displayed correctly. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 940ec04..0d47c60 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -263,9 +263,7 @@ struct cg6_par { u32 flags; #define CG6_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; static int cg6_sync(struct fb_info *info) @@ -596,16 +594,14 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg6_par *par = (struct cg6_par *)info->par; return sbusfb_mmap_helper(cg6_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg6_par *par = (struct cg6_par *)info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUNFAST_COLOR, 8, par->fbsize); + FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len); } /* @@ -631,12 +627,12 @@ static void __devinit cg6_init_fix(struct fb_info *info, int linebytes) break; }; if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { - if (par->fbsize <= 0x100000) + if (info->fix.smem_len <= 0x100000) cg6_card_name = "TGX"; else cg6_card_name = "TGX+"; } else { - if (par->fbsize <= 0x100000) + if (info->fix.smem_len <= 0x100000) cg6_card_name = "GX"; else cg6_card_name = "GX+"; @@ -738,7 +734,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); if (info->screen_base) - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, + info->fix.smem_len); } static int __devinit cg6_probe(struct of_device *op, @@ -759,7 +756,7 @@ static int __devinit cg6_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -769,11 +766,11 @@ static int __devinit cg6_probe(struct of_device *op, linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); dblbuf = of_getintprop_default(dp, "dblbuf", 0); if (dblbuf) - par->fbsize *= 4; + info->fix.smem_len *= 4; par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, 4096, "cgsix fbc"); @@ -792,7 +789,7 @@ static int __devinit cg6_probe(struct of_device *op, info->fbops = &cg6_ops; info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, - par->fbsize, "cgsix ram"); + info->fix.smem_len, "cgsix ram"); if (!par->fbc || !par->tec || !par->thc || !par->bt || !par->fhc || !info->screen_base) goto out_unmap_regs; @@ -817,7 +814,7 @@ static int __devinit cg6_probe(struct of_device *op, printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", dp->full_name, info->fix.id, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; -- cgit v0.10.2 From 8803f7afe6370af8cd97991bde0c3b53eca4e8da Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 4 May 2009 10:41:56 +0000 Subject: leo: use standard fields for framebuffer physical address and length Use standard fields fbinfo.fix.smem_start and fbinfo.fix.smem_len for physical address and length of framebuffer. This also fixes output of the 'fbset -i' command - address and length of the framebuffer are displayed correctly. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 7c7e8c2..e145e2d 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -191,9 +191,7 @@ struct leo_par { u32 flags; #define LEO_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; static void leo_wait(struct leo_lx_krn __iomem *lx_krn) @@ -420,16 +418,14 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) struct leo_par *par = (struct leo_par *)info->par; return sbusfb_mmap_helper(leo_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct leo_par *par = (struct leo_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUNLEO, 32, par->fbsize); + FBTYPE_SUNLEO, 32, info->fix.smem_len); } /* @@ -569,7 +565,7 @@ static int __devinit leo_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 32); @@ -577,7 +573,7 @@ static int __devinit leo_probe(struct of_device *op, linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->lc_ss0_usr = of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, @@ -627,7 +623,7 @@ static int __devinit leo_probe(struct of_device *op, printk(KERN_INFO "%s: leo at %lx:%lx\n", dp->full_name, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; -- cgit v0.10.2 From 0d76cb2606cbb2e21f3832773458bb0241f99c6d Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 4 May 2009 10:42:57 +0000 Subject: p9100: use standard fields for framebuffer physical address and length Use standard fields fbinfo.fix.smem_start and fbinfo.fix.smem_len for physical address and length of framebuffer. This also fixes output of the 'fbset -i' command - address and length of the framebuffer are displayed correctly. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 7000f2c..7fa4ab0 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -134,9 +134,7 @@ struct p9100_par { u32 flags; #define P9100_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -224,18 +222,16 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) struct p9100_par *par = (struct p9100_par *)info->par; return sbusfb_mmap_helper(p9100_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int p9100_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct p9100_par *par = (struct p9100_par *) info->par; - /* Make it look like a cg3. */ return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN3COLOR, 8, par->fbsize); + FBTYPE_SUN3COLOR, 8, info->fix.smem_len); } /* @@ -271,7 +267,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id spin_lock_init(&par->lock); /* This is the framebuffer and the only resource apps can mmap. */ - par->physbase = op->resource[2].start; + info->fix.smem_start = op->resource[2].start; par->which_io = op->resource[2].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -280,7 +276,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id info->var.blue.length = 8; linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->regs = of_ioremap(&op->resource[0], 0, sizeof(struct p9100_regs), "p9100 regs"); @@ -290,7 +286,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id info->flags = FBINFO_DEFAULT; info->fbops = &p9100_ops; info->screen_base = of_ioremap(&op->resource[2], 0, - par->fbsize, "p9100 ram"); + info->fix.smem_len, "p9100 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -311,7 +307,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "%s: p9100 at %lx:%lx\n", dp->full_name, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; @@ -319,7 +315,7 @@ out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_screen: - of_iounmap(&op->resource[2], info->screen_base, par->fbsize); + of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); @@ -340,7 +336,7 @@ static int __devexit p9100_remove(struct of_device *op) fb_dealloc_cmap(&info->cmap); of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); - of_iounmap(&op->resource[2], info->screen_base, par->fbsize); + of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); framebuffer_release(info); -- cgit v0.10.2 From b9f69f4f4a953b2b5299fff7fc98e69221e29514 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 14 May 2009 16:23:08 +0000 Subject: sparc: move the duplication in dma-mapping_{32|64}.h to dma-mapping.h Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 0f4150e..8c911ea 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -5,4 +5,46 @@ #else #include #endif + +#define DMA_ERROR_CODE (~(dma_addr_t)0x0) + +extern int dma_supported(struct device *dev, u64 mask); +extern int dma_set_mask(struct device *dev, u64 dma_mask); + +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return (dma_addr == DMA_ERROR_CODE); +} + +static inline int dma_get_cache_alignment(void) +{ + /* + * no easy way to get cache size on all processors, so return + * the maximum possible, to be safe + */ + return (1 << INTERNODE_CACHE_SHIFT); +} + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d, h) (1) + +static inline void dma_sync_single_range_for_cpu(struct device *dev, + dma_addr_t dma_handle, + unsigned long offset, + size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_cpu(dev, dma_handle+offset, size, dir); +} + +static inline void dma_sync_single_range_for_device(struct device *dev, + dma_addr_t dma_handle, + unsigned long offset, + size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_device(dev, dma_handle+offset, size, dir); +} + #endif diff --git a/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h index 8a57ea0..7f09c85 100644 --- a/arch/sparc/include/asm/dma-mapping_32.h +++ b/arch/sparc/include/asm/dma-mapping_32.h @@ -7,10 +7,6 @@ struct device; struct scatterlist; struct page; -#define DMA_ERROR_CODE (~(dma_addr_t)0x0) - -extern int dma_supported(struct device *dev, u64 mask); -extern int dma_set_mask(struct device *dev, u64 dma_mask); extern void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag); extern void dma_free_coherent(struct device *dev, size_t size, @@ -37,24 +33,10 @@ extern void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); -extern void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction); -extern void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction); extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction); extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction); -extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr); -extern int dma_get_cache_alignment(void); - -#define dma_alloc_noncoherent dma_alloc_coherent -#define dma_free_noncoherent dma_free_coherent #endif /* _ASM_SPARC_DMA_MAPPING_H */ diff --git a/arch/sparc/include/asm/dma-mapping_64.h b/arch/sparc/include/asm/dma-mapping_64.h index bfa64f9..017ae70 100644 --- a/arch/sparc/include/asm/dma-mapping_64.h +++ b/arch/sparc/include/asm/dma-mapping_64.h @@ -4,8 +4,6 @@ #include #include -#define DMA_ERROR_CODE (~(dma_addr_t)0x0) - struct dma_ops { void *(*alloc_coherent)(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag); @@ -31,9 +29,6 @@ struct dma_ops { }; extern const struct dma_ops *dma_ops; -extern int dma_supported(struct device *dev, u64 mask); -extern int dma_set_mask(struct device *dev, u64 dma_mask); - static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { @@ -102,25 +97,6 @@ static inline void dma_sync_single_for_device(struct device *dev, /* No flushing needed to sync cpu writes to the device. */ } -static inline void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction) -{ - dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction); -} - -static inline void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - - static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction) @@ -135,20 +111,4 @@ static inline void dma_sync_sg_for_device(struct device *dev, /* No flushing needed to sync cpu writes to the device. */ } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return (dma_addr == DMA_ERROR_CODE); -} - -static inline int dma_get_cache_alignment(void) -{ - /* no easy way to get cache size on all processors, so return - * the maximum possible, to be safe */ - return (1 << INTERNODE_CACHE_SHIFT); -} - -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) - #endif /* _ASM_SPARC64_DMA_MAPPING_H */ diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index ebc8403..3c9ff4f 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -167,24 +167,6 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, } EXPORT_SYMBOL(dma_sync_single_for_device); -void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction) -{ - dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction); -} -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - dma_sync_single_for_device(dev, dma_handle+offset, size, direction); -} -EXPORT_SYMBOL(dma_sync_single_range_for_device); - void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction) { @@ -213,15 +195,3 @@ void dma_sync_sg_for_device(struct device *dev, BUG(); } EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return (dma_addr == DMA_ERROR_CODE); -} -EXPORT_SYMBOL(dma_mapping_error); - -int dma_get_cache_alignment(void) -{ - return 32; -} -EXPORT_SYMBOL(dma_get_cache_alignment); -- cgit v0.10.2 From 2e8fcfe2e51b2ee0fef3313e3c9ec25b9d6ed255 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 14 May 2009 16:23:09 +0000 Subject: sparc: add sync_single_for_device and sync_sg_for_device to struct dma_ops This adds sync_single_for_device() and sync_sg_for_device() to struct dma_ops in order to unify dma-mpping_{32|64}.h. dma-mpping_32.h needs them though dma-mpping_64.h doesn't. Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/dma-mapping_64.h b/arch/sparc/include/asm/dma-mapping_64.h index 017ae70..0c4fb1f 100644 --- a/arch/sparc/include/asm/dma-mapping_64.h +++ b/arch/sparc/include/asm/dma-mapping_64.h @@ -23,9 +23,15 @@ struct dma_ops { void (*sync_single_for_cpu)(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); + void (*sync_single_for_device)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction); + void (*sync_sg_for_device)(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir); }; extern const struct dma_ops *dma_ops; -- cgit v0.10.2 From 797a75686528e9f6f9bfee2a719a00b47868c999 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 14 May 2009 16:23:10 +0000 Subject: sparc: use dma_map_page instead of dma_map_single This patch converts dma_map_single and dma_unmap_single to use map_page and unmap_page respectively and removes unnecessary map_single and unmap_single. map_page can be used to implement map_single but the opposite is impossible. Having only dma_map_page in struct dma_ops is enough. Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/dma-mapping_64.h b/arch/sparc/include/asm/dma-mapping_64.h index 0c4fb1f..579757e 100644 --- a/arch/sparc/include/asm/dma-mapping_64.h +++ b/arch/sparc/include/asm/dma-mapping_64.h @@ -9,12 +9,12 @@ struct dma_ops { dma_addr_t *dma_handle, gfp_t flag); void (*free_coherent)(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle); - dma_addr_t (*map_single)(struct device *dev, void *cpu_addr, - size_t size, - enum dma_data_direction direction); - void (*unmap_single)(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction); + dma_addr_t (*map_page)(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction); + void (*unmap_page)(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction); int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction); void (*unmap_sg)(struct device *dev, struct scatterlist *sg, @@ -51,29 +51,30 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction direction) { - return dma_ops->map_single(dev, cpu_addr, size, direction); + return dma_ops->map_page(dev, virt_to_page(cpu_addr), + (unsigned long)cpu_addr & ~PAGE_MASK, size, + direction); } static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction) { - dma_ops->unmap_single(dev, dma_addr, size, direction); + dma_ops->unmap_page(dev, dma_addr, size, direction); } static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction) { - return dma_ops->map_single(dev, page_address(page) + offset, - size, direction); + return dma_ops->map_page(dev, page, offset, size, direction); } static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, enum dma_data_direction direction) { - dma_ops->unmap_single(dev, dma_address, size, direction); + dma_ops->unmap_page(dev, dma_address, size, direction); } static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index d8900e1..0aeaefe 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -351,8 +351,9 @@ static void dma_4u_free_coherent(struct device *dev, size_t size, free_pages((unsigned long)cpu, order); } -static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz, - enum dma_data_direction direction) +static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t sz, + enum dma_data_direction direction) { struct iommu *iommu; struct strbuf *strbuf; @@ -368,7 +369,7 @@ static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz, if (unlikely(direction == DMA_NONE)) goto bad_no_ctx; - oaddr = (unsigned long)ptr; + oaddr = (unsigned long)(page_address(page) + offset); npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -472,8 +473,8 @@ do_flush_sync: vaddr, ctx, npages); } -static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr, - size_t sz, enum dma_data_direction direction) +static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr, + size_t sz, enum dma_data_direction direction) { struct iommu *iommu; struct strbuf *strbuf; @@ -824,8 +825,8 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev, static const struct dma_ops sun4u_dma_ops = { .alloc_coherent = dma_4u_alloc_coherent, .free_coherent = dma_4u_free_coherent, - .map_single = dma_4u_map_single, - .unmap_single = dma_4u_unmap_single, + .map_page = dma_4u_map_page, + .unmap_page = dma_4u_unmap_page, .map_sg = dma_4u_map_sg, .unmap_sg = dma_4u_unmap_sg, .sync_single_for_cpu = dma_4u_sync_single_for_cpu, diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 5db5ebe..2485eaa 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -230,8 +230,9 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu, free_pages((unsigned long)cpu, order); } -static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz, - enum dma_data_direction direction) +static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t sz, + enum dma_data_direction direction) { struct iommu *iommu; unsigned long flags, npages, oaddr; @@ -245,7 +246,7 @@ static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz, if (unlikely(direction == DMA_NONE)) goto bad; - oaddr = (unsigned long)ptr; + oaddr = (unsigned long)(page_address(page) + offset); npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -294,8 +295,8 @@ iommu_map_fail: return DMA_ERROR_CODE; } -static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr, - size_t sz, enum dma_data_direction direction) +static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr, + size_t sz, enum dma_data_direction direction) { struct pci_pbm_info *pbm; struct iommu *iommu; @@ -537,8 +538,8 @@ static void dma_4v_sync_sg_for_cpu(struct device *dev, static const struct dma_ops sun4v_dma_ops = { .alloc_coherent = dma_4v_alloc_coherent, .free_coherent = dma_4v_free_coherent, - .map_single = dma_4v_map_single, - .unmap_single = dma_4v_unmap_single, + .map_page = dma_4v_map_page, + .unmap_page = dma_4v_unmap_page, .map_sg = dma_4v_map_sg, .unmap_sg = dma_4v_unmap_sg, .sync_single_for_cpu = dma_4v_sync_single_for_cpu, -- cgit v0.10.2 From d69864158e24f323e818403c6b89ad4871aea6f6 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 14 May 2009 16:23:11 +0000 Subject: sparc: remove dma-mapping_{32|64}.h This modifies SPARC32 to use struct dma_map ops. It means that we can remove dma-mapping_{32|64}.h. Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 8c911ea..204e4bf 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -1,33 +1,134 @@ #ifndef ___ASM_SPARC_DMA_MAPPING_H #define ___ASM_SPARC_DMA_MAPPING_H -#if defined(__sparc__) && defined(__arch64__) -#include -#else -#include -#endif + +#include +#include #define DMA_ERROR_CODE (~(dma_addr_t)0x0) extern int dma_supported(struct device *dev, u64 mask); extern int dma_set_mask(struct device *dev, u64 dma_mask); -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d, h) (1) + +struct dma_ops { + void *(*alloc_coherent)(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); + void (*free_coherent)(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle); + dma_addr_t (*map_page)(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction); + void (*unmap_page)(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction); + int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction); + void (*unmap_sg)(struct device *dev, struct scatterlist *sg, + int nhwentries, + enum dma_data_direction direction); + void (*sync_single_for_cpu)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + void (*sync_single_for_device)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, + int nelems, + enum dma_data_direction direction); + void (*sync_sg_for_device)(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir); +}; +extern const struct dma_ops *dma_ops; + +static inline void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) { - return (dma_addr == DMA_ERROR_CODE); + return dma_ops->alloc_coherent(dev, size, dma_handle, flag); } -static inline int dma_get_cache_alignment(void) +static inline void dma_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) { - /* - * no easy way to get cache size on all processors, so return - * the maximum possible, to be safe - */ - return (1 << INTERNODE_CACHE_SHIFT); + dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) +static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction) +{ + return dma_ops->map_page(dev, virt_to_page(cpu_addr), + (unsigned long)cpu_addr & ~PAGE_MASK, size, + direction); +} + +static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction) +{ + dma_ops->unmap_page(dev, dma_addr, size, direction); +} + +static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + return dma_ops->map_page(dev, page, offset, size, direction); +} + +static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, + enum dma_data_direction direction) +{ + dma_ops->unmap_page(dev, dma_address, size, direction); +} + +static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + return dma_ops->map_sg(dev, sg, nents, direction); +} + +static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + dma_ops->unmap_sg(dev, sg, nents, direction); +} + +static inline void dma_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction); +} + +static inline void dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, + size_t size, + enum dma_data_direction direction) +{ + if (dma_ops->sync_single_for_device) + dma_ops->sync_single_for_device(dev, dma_handle, size, + direction); +} + +static inline void dma_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction); +} + +static inline void dma_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + if (dma_ops->sync_sg_for_device) + dma_ops->sync_sg_for_device(dev, sg, nelems, direction); +} static inline void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, @@ -47,4 +148,19 @@ static inline void dma_sync_single_range_for_device(struct device *dev, dma_sync_single_for_device(dev, dma_handle+offset, size, dir); } + +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return (dma_addr == DMA_ERROR_CODE); +} + +static inline int dma_get_cache_alignment(void) +{ + /* + * no easy way to get cache size on all processors, so return + * the maximum possible, to be safe + */ + return (1 << INTERNODE_CACHE_SHIFT); +} + #endif diff --git a/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h deleted file mode 100644 index 7f09c85..0000000 --- a/arch/sparc/include/asm/dma-mapping_32.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _ASM_SPARC_DMA_MAPPING_H -#define _ASM_SPARC_DMA_MAPPING_H - -#include - -struct device; -struct scatterlist; -struct page; - -extern void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag); -extern void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle); -extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, - enum dma_data_direction direction); -extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction); -extern dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction); -extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction); -extern int dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction); -extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction); -extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction); -extern void dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction); -extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction direction); -extern void dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction); - -#endif /* _ASM_SPARC_DMA_MAPPING_H */ diff --git a/arch/sparc/include/asm/dma-mapping_64.h b/arch/sparc/include/asm/dma-mapping_64.h deleted file mode 100644 index 579757e..0000000 --- a/arch/sparc/include/asm/dma-mapping_64.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _ASM_SPARC64_DMA_MAPPING_H -#define _ASM_SPARC64_DMA_MAPPING_H - -#include -#include - -struct dma_ops { - void *(*alloc_coherent)(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag); - void (*free_coherent)(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle); - dma_addr_t (*map_page)(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction); - void (*unmap_page)(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction); - int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction); - void (*unmap_sg)(struct device *dev, struct scatterlist *sg, - int nhwentries, - enum dma_data_direction direction); - void (*sync_single_for_cpu)(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction); - void (*sync_single_for_device)(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction); - void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, - int nelems, - enum dma_data_direction direction); - void (*sync_sg_for_device)(struct device *dev, - struct scatterlist *sg, int nents, - enum dma_data_direction dir); -}; -extern const struct dma_ops *dma_ops; - -static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - return dma_ops->alloc_coherent(dev, size, dma_handle, flag); -} - -static inline void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); -} - -static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, - enum dma_data_direction direction) -{ - return dma_ops->map_page(dev, virt_to_page(cpu_addr), - (unsigned long)cpu_addr & ~PAGE_MASK, size, - direction); -} - -static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction) -{ - dma_ops->unmap_page(dev, dma_addr, size, direction); -} - -static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - return dma_ops->map_page(dev, page, offset, size, direction); -} - -static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, - enum dma_data_direction direction) -{ - dma_ops->unmap_page(dev, dma_address, size, direction); -} - -static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - return dma_ops->map_sg(dev, sg, nents, direction); -} - -static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - dma_ops->unmap_sg(dev, sg, nents, direction); -} - -static inline void dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction); -} - -static inline void dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - -static inline void dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction); -} - -static inline void dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - -#endif /* _ASM_SPARC64_DMA_MAPPING_H */ diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index 3c9ff4f..524c32f 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -35,8 +35,8 @@ int dma_set_mask(struct device *dev, u64 dma_mask) } EXPORT_SYMBOL(dma_set_mask); -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) +static void *dma32_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -44,10 +44,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size, #endif return sbus_alloc_consistent(dev, size, dma_handle); } -EXPORT_SYMBOL(dma_alloc_coherent); -void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) +static void dma32_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -58,38 +57,10 @@ void dma_free_coherent(struct device *dev, size_t size, #endif sbus_free_consistent(dev, size, cpu_addr, dma_handle); } -EXPORT_SYMBOL(dma_free_coherent); -dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return pci_map_single(to_pci_dev(dev), cpu_addr, - size, (int)direction); -#endif - return sbus_map_single(dev, cpu_addr, size, (int)direction); -} -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_unmap_single(to_pci_dev(dev), dma_addr, - size, (int)direction); - return; - } -#endif - sbus_unmap_single(dev, dma_addr, size, (int)direction); -} -EXPORT_SYMBOL(dma_unmap_single); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) +static dma_addr_t dma32_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -99,10 +70,9 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page, return sbus_map_single(dev, page_address(page) + offset, size, (int)direction); } -EXPORT_SYMBOL(dma_map_page); -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction) +static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -113,10 +83,9 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, #endif sbus_unmap_single(dev, dma_address, size, (int)direction); } -EXPORT_SYMBOL(dma_unmap_page); -int dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) +static int dma32_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -124,10 +93,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, #endif return sbus_map_sg(dev, sg, nents, direction); } -EXPORT_SYMBOL(dma_map_sg); -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) +void dma32_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -137,10 +105,10 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, #endif sbus_unmap_sg(dev, sg, nents, (int)direction); } -EXPORT_SYMBOL(dma_unmap_sg); -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) +static void dma32_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -151,10 +119,10 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, #endif sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction); } -EXPORT_SYMBOL(dma_sync_single_for_cpu); -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) +static void dma32_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -165,10 +133,9 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, #endif sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction); } -EXPORT_SYMBOL(dma_sync_single_for_device); -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction direction) +static void dma32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -179,11 +146,10 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, #endif BUG(); } -EXPORT_SYMBOL(dma_sync_sg_for_cpu); -void dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) +static void dma32_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -194,4 +160,19 @@ void dma_sync_sg_for_device(struct device *dev, #endif BUG(); } -EXPORT_SYMBOL(dma_sync_sg_for_device); + +static const struct dma_ops dma32_dma_ops = { + .alloc_coherent = dma32_alloc_coherent, + .free_coherent = dma32_free_coherent, + .map_page = dma32_map_page, + .unmap_page = dma32_unmap_page, + .map_sg = dma32_map_sg, + .unmap_sg = dma32_unmap_sg, + .sync_single_for_cpu = dma32_sync_single_for_cpu, + .sync_single_for_device = dma32_sync_single_for_device, + .sync_sg_for_cpu = dma32_sync_sg_for_cpu, + .sync_sg_for_device = dma32_sync_sg_for_device, +}; + +const struct dma_ops *dma_ops = &dma32_dma_ops; +EXPORT_SYMBOL(dma_ops); -- cgit v0.10.2 From c9f5b7e77c30da25104a3f7f26ac46c07d7b5cb6 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 4 Jun 2009 02:00:02 -0700 Subject: sparc: move of_device common code to of_device_common This patch moves code common to of_device_32.c and of_device_64.c into of_device_common.h and of_device_common.c. The only functional difference is in sparc32 where of_bus_default_map is used in place of of_bus_sbus_map because they are equivelent. There is still room for further code consolidation with some minor refactoring. Boot tested on sparc32 and compile tested on sparc64. Signed-off-by: Robert Reif Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 47029c6..475ce46 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -37,6 +37,7 @@ obj-y += una_asm_$(BITS).o obj-$(CONFIG_SPARC32) += muldiv.o obj-y += prom_common.o obj-y += prom_$(BITS).o +obj-y += of_device_common.o obj-y += of_device_$(BITS).o obj-$(CONFIG_SPARC64) += prom_irqtrans.o diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index c8f14c1..9039670 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c @@ -6,159 +6,11 @@ #include #include #include +#include #include #include -static int node_match(struct device *dev, void *data) -{ - struct of_device *op = to_of_device(dev); - struct device_node *dp = data; - - return (op->node == dp); -} - -struct of_device *of_find_device_by_node(struct device_node *dp) -{ - struct device *dev = bus_find_device(&of_platform_bus_type, NULL, - dp, node_match); - - if (dev) - return to_of_device(dev); - - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - -unsigned int irq_of_parse_and_map(struct device_node *node, int index) -{ - struct of_device *op = of_find_device_by_node(node); - - if (!op || index >= op->num_irqs) - return 0; - - return op->irqs[index]; -} -EXPORT_SYMBOL(irq_of_parse_and_map); - -/* Take the archdata values for IOMMU, STC, and HOSTDATA found in - * BUS and propagate to all child of_device objects. - */ -void of_propagate_archdata(struct of_device *bus) -{ - struct dev_archdata *bus_sd = &bus->dev.archdata; - struct device_node *bus_dp = bus->node; - struct device_node *dp; - - for (dp = bus_dp->child; dp; dp = dp->sibling) { - struct of_device *op = of_find_device_by_node(dp); - - op->dev.archdata.iommu = bus_sd->iommu; - op->dev.archdata.stc = bus_sd->stc; - op->dev.archdata.host_controller = bus_sd->host_controller; - op->dev.archdata.numa_node = bus_sd->numa_node; - - if (dp->child) - of_propagate_archdata(op); - } -} - -struct bus_type of_platform_bus_type; -EXPORT_SYMBOL(of_platform_bus_type); - -static inline u64 of_read_addr(const u32 *cell, int size) -{ - u64 r = 0; - while (size--) - r = (r << 32) | *(cell++); - return r; -} - -static void __init get_cells(struct device_node *dp, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dp); - if (sizec) - *sizec = of_n_size_cells(dp); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 - -struct of_bus { - const char *name; - const char *addr_prop_name; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - int (*map)(u32 *addr, const u32 *range, - int na, int ns, int pna); - unsigned long (*get_flags)(const u32 *addr, unsigned long); -}; - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - get_cells(dev, addrc, sizec); -} - -/* Make sure the least significant 64-bits are in-range. Even - * for 3 or 4 cell values it is a good enough approximation. - */ -static int of_out_of_range(const u32 *addr, const u32 *base, - const u32 *size, int na, int ns) -{ - u64 a = of_read_addr(addr, na); - u64 b = of_read_addr(base, na); - - if (a < b) - return 1; - - b += of_read_addr(size, ns); - if (a >= b) - return 1; - - return 0; -} - -static int of_bus_default_map(u32 *addr, const u32 *range, - int na, int ns, int pna) -{ - u32 result[OF_MAX_ADDR_CELLS]; - int i; - - if (ns > 2) { - printk("of_device: Cannot handle size cells (%d) > 2.", ns); - return -EINVAL; - } - - if (of_out_of_range(addr, range, range + na + pna, na, ns)) - return -EINVAL; - - /* Start with the parent range base. */ - memcpy(result, range + na, pna * 4); - - /* Add in the child address offset. */ - for (i = 0; i < na; i++) - result[pna - 1 - i] += - (addr[na - 1 - i] - - range[na - 1 - i]); - - memcpy(addr, result, pna * 4); - - return 0; -} - -static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) -{ - if (flags) - return flags; - return IORESOURCE_MEM; -} +#include "of_device_common.h" /* * PCI bus specific translator @@ -240,47 +92,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) return flags; } -/* - * SBUS bus specific translator - */ - -static int of_bus_sbus_match(struct device_node *np) -{ - struct device_node *dp = np; - - while (dp) { - if (!strcmp(dp->name, "sbus") || - !strcmp(dp->name, "sbi")) - return 1; - - /* Have a look at use_1to1_mapping(). We're trying - * to match SBUS if that's the top-level bus and we - * don't have some intervening real bus that provides - * ranges based translations. - */ - if (of_find_property(dp, "ranges", NULL) != NULL) - break; - - dp = dp->parent; - } - - return 0; -} - -static void of_bus_sbus_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna) -{ - return of_bus_default_map(addr, range, na, ns, pna); -} - static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags) { return IORESOURCE_MEM; @@ -307,7 +118,7 @@ static struct of_bus of_busses[] = { .addr_prop_name = "reg", .match = of_bus_sbus_match, .count_cells = of_bus_sbus_count_cells, - .map = of_bus_sbus_map, + .map = of_bus_default_map, .get_flags = of_bus_sbus_get_flags, }, /* Default */ diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c index 5ac287a..881947e 100644 --- a/arch/sparc/kernel/of_device_64.c +++ b/arch/sparc/kernel/of_device_64.c @@ -10,6 +10,8 @@ #include #include +#include "of_device_common.h" + void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) { unsigned long ret = res->start + offset; @@ -35,156 +37,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size) } EXPORT_SYMBOL(of_iounmap); -static int node_match(struct device *dev, void *data) -{ - struct of_device *op = to_of_device(dev); - struct device_node *dp = data; - - return (op->node == dp); -} - -struct of_device *of_find_device_by_node(struct device_node *dp) -{ - struct device *dev = bus_find_device(&of_platform_bus_type, NULL, - dp, node_match); - - if (dev) - return to_of_device(dev); - - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - -unsigned int irq_of_parse_and_map(struct device_node *node, int index) -{ - struct of_device *op = of_find_device_by_node(node); - - if (!op || index >= op->num_irqs) - return 0; - - return op->irqs[index]; -} -EXPORT_SYMBOL(irq_of_parse_and_map); - -/* Take the archdata values for IOMMU, STC, and HOSTDATA found in - * BUS and propagate to all child of_device objects. - */ -void of_propagate_archdata(struct of_device *bus) -{ - struct dev_archdata *bus_sd = &bus->dev.archdata; - struct device_node *bus_dp = bus->node; - struct device_node *dp; - - for (dp = bus_dp->child; dp; dp = dp->sibling) { - struct of_device *op = of_find_device_by_node(dp); - - op->dev.archdata.iommu = bus_sd->iommu; - op->dev.archdata.stc = bus_sd->stc; - op->dev.archdata.host_controller = bus_sd->host_controller; - op->dev.archdata.numa_node = bus_sd->numa_node; - - if (dp->child) - of_propagate_archdata(op); - } -} - -struct bus_type of_platform_bus_type; -EXPORT_SYMBOL(of_platform_bus_type); - -static inline u64 of_read_addr(const u32 *cell, int size) -{ - u64 r = 0; - while (size--) - r = (r << 32) | *(cell++); - return r; -} - -static void get_cells(struct device_node *dp, int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dp); - if (sizec) - *sizec = of_n_size_cells(dp); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 - -struct of_bus { - const char *name; - const char *addr_prop_name; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - int (*map)(u32 *addr, const u32 *range, - int na, int ns, int pna); - unsigned long (*get_flags)(const u32 *addr, unsigned long); -}; - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - get_cells(dev, addrc, sizec); -} - -/* Make sure the least significant 64-bits are in-range. Even - * for 3 or 4 cell values it is a good enough approximation. - */ -static int of_out_of_range(const u32 *addr, const u32 *base, - const u32 *size, int na, int ns) -{ - u64 a = of_read_addr(addr, na); - u64 b = of_read_addr(base, na); - - if (a < b) - return 1; - - b += of_read_addr(size, ns); - if (a >= b) - return 1; - - return 0; -} - -static int of_bus_default_map(u32 *addr, const u32 *range, - int na, int ns, int pna) -{ - u32 result[OF_MAX_ADDR_CELLS]; - int i; - - if (ns > 2) { - printk("of_device: Cannot handle size cells (%d) > 2.", ns); - return -EINVAL; - } - - if (of_out_of_range(addr, range, range + na + pna, na, ns)) - return -EINVAL; - - /* Start with the parent range base. */ - memcpy(result, range + na, pna * 4); - - /* Add in the child address offset. */ - for (i = 0; i < na; i++) - result[pna - 1 - i] += - (addr[na - 1 - i] - - range[na - 1 - i]); - - memcpy(addr, result, pna * 4); - - return 0; -} - -static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) -{ - if (flags) - return flags; - return IORESOURCE_MEM; -} - /* * PCI bus specific translator */ @@ -295,42 +147,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) } /* - * SBUS bus specific translator - */ - -static int of_bus_sbus_match(struct device_node *np) -{ - struct device_node *dp = np; - - while (dp) { - if (!strcmp(dp->name, "sbus") || - !strcmp(dp->name, "sbi")) - return 1; - - /* Have a look at use_1to1_mapping(). We're trying - * to match SBUS if that's the top-level bus and we - * don't have some intervening real bus that provides - * ranges based translations. - */ - if (of_find_property(dp, "ranges", NULL) != NULL) - break; - - dp = dp->parent; - } - - return 0; -} - -static void of_bus_sbus_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -/* * FHC/Central bus specific translator. * * This is just needed to hard-code the address and size cell diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c new file mode 100644 index 0000000..cb8eb79 --- /dev/null +++ b/arch/sparc/kernel/of_device_common.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "of_device_common.h" + +static int node_match(struct device *dev, void *data) +{ + struct of_device *op = to_of_device(dev); + struct device_node *dp = data; + + return (op->node == dp); +} + +struct of_device *of_find_device_by_node(struct device_node *dp) +{ + struct device *dev = bus_find_device(&of_platform_bus_type, NULL, + dp, node_match); + + if (dev) + return to_of_device(dev); + + return NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + +unsigned int irq_of_parse_and_map(struct device_node *node, int index) +{ + struct of_device *op = of_find_device_by_node(node); + + if (!op || index >= op->num_irqs) + return 0; + + return op->irqs[index]; +} +EXPORT_SYMBOL(irq_of_parse_and_map); + +/* Take the archdata values for IOMMU, STC, and HOSTDATA found in + * BUS and propagate to all child of_device objects. + */ +void of_propagate_archdata(struct of_device *bus) +{ + struct dev_archdata *bus_sd = &bus->dev.archdata; + struct device_node *bus_dp = bus->node; + struct device_node *dp; + + for (dp = bus_dp->child; dp; dp = dp->sibling) { + struct of_device *op = of_find_device_by_node(dp); + + op->dev.archdata.iommu = bus_sd->iommu; + op->dev.archdata.stc = bus_sd->stc; + op->dev.archdata.host_controller = bus_sd->host_controller; + op->dev.archdata.numa_node = bus_sd->numa_node; + + if (dp->child) + of_propagate_archdata(op); + } +} + +struct bus_type of_platform_bus_type; +EXPORT_SYMBOL(of_platform_bus_type); + +static void get_cells(struct device_node *dp, int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dp); + if (sizec) + *sizec = of_n_size_cells(dp); +} + +/* + * Default translator (generic bus) + */ + +void of_bus_default_count_cells(struct device_node *dev, int *addrc, int *sizec) +{ + get_cells(dev, addrc, sizec); +} + +/* Make sure the least significant 64-bits are in-range. Even + * for 3 or 4 cell values it is a good enough approximation. + */ +int of_out_of_range(const u32 *addr, const u32 *base, + const u32 *size, int na, int ns) +{ + u64 a = of_read_addr(addr, na); + u64 b = of_read_addr(base, na); + + if (a < b) + return 1; + + b += of_read_addr(size, ns); + if (a >= b) + return 1; + + return 0; +} + +int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna) +{ + u32 result[OF_MAX_ADDR_CELLS]; + int i; + + if (ns > 2) { + printk("of_device: Cannot handle size cells (%d) > 2.", ns); + return -EINVAL; + } + + if (of_out_of_range(addr, range, range + na + pna, na, ns)) + return -EINVAL; + + /* Start with the parent range base. */ + memcpy(result, range + na, pna * 4); + + /* Add in the child address offset. */ + for (i = 0; i < na; i++) + result[pna - 1 - i] += + (addr[na - 1 - i] - + range[na - 1 - i]); + + memcpy(addr, result, pna * 4); + + return 0; +} + +unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) +{ + if (flags) + return flags; + return IORESOURCE_MEM; +} + +/* + * SBUS bus specific translator + */ + +int of_bus_sbus_match(struct device_node *np) +{ + struct device_node *dp = np; + + while (dp) { + if (!strcmp(dp->name, "sbus") || + !strcmp(dp->name, "sbi")) + return 1; + + /* Have a look at use_1to1_mapping(). We're trying + * to match SBUS if that's the top-level bus and we + * don't have some intervening real bus that provides + * ranges based translations. + */ + if (of_find_property(dp, "ranges", NULL) != NULL) + break; + + dp = dp->parent; + } + + return 0; +} + +void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} diff --git a/arch/sparc/kernel/of_device_common.h b/arch/sparc/kernel/of_device_common.h new file mode 100644 index 0000000..cdfd239 --- /dev/null +++ b/arch/sparc/kernel/of_device_common.h @@ -0,0 +1,36 @@ +#ifndef _OF_DEVICE_COMMON_H +#define _OF_DEVICE_COMMON_H + +static inline u64 of_read_addr(const u32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | *(cell++); + return r; +} + +void of_bus_default_count_cells(struct device_node *dev, int *addrc, + int *sizec); +int of_out_of_range(const u32 *addr, const u32 *base, + const u32 *size, int na, int ns); +int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna); +unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags); + +int of_bus_sbus_match(struct device_node *np); +void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec); + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +struct of_bus { + const char *name; + const char *addr_prop_name; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + int (*map)(u32 *addr, const u32 *range, + int na, int ns, int pna); + unsigned long (*get_flags)(const u32 *addr, unsigned long); +}; + +#endif /* _OF_DEVICE_COMMON_H */ -- cgit v0.10.2 From 949e82744b31b555dd6dba40758e05338f305233 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Fri, 24 Apr 2009 03:58:24 +0000 Subject: sparc: Simplify code using is_power_of_2() routine. Signed-off-by: Robert P. J. Day Signed-off-by: David S. Miller diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 06c9a7d..ade4eb3 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -349,7 +350,7 @@ static void srmmu_free_nocache(unsigned long vaddr, int size) vaddr, srmmu_nocache_end); BUG(); } - if (size & (size-1)) { + if (!is_power_of_2(size)) { printk("Size 0x%x is not a power of 2\n", size); BUG(); } -- cgit v0.10.2 From 9be12f9b1c4fd5f18cc82c170a32bfe1713ba76d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 13 Jun 2009 01:03:24 -0700 Subject: sparc64: Add proper dynamic ftrace support. Signed-off-by: David S. Miller Acked-by: Steven Rostedt Acked-by: Ingo Molnar diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 2185cf9..3f8b6a9 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -37,6 +37,8 @@ config SPARC64 select HAVE_KPROBES select HAVE_LMB select HAVE_SYSCALL_WRAPPERS + select HAVE_DYNAMIC_FTRACE + select HAVE_FTRACE_MCOUNT_RECORD select USE_GENERIC_SMP_HELPERS if SMP select RTC_DRV_CMOS select RTC_DRV_BQ4802 diff --git a/arch/sparc/include/asm/ftrace.h b/arch/sparc/include/asm/ftrace.h index d27716c..b0f18e9 100644 --- a/arch/sparc/include/asm/ftrace.h +++ b/arch/sparc/include/asm/ftrace.h @@ -11,4 +11,15 @@ extern void _mcount(void); #endif +#ifdef CONFIG_DYNAMIC_FTRACE +/* reloction of mcount call site is the same as the address */ +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} + +struct dyn_arch_ftrace { +}; +#endif /* CONFIG_DYNAMIC_FTRACE */ + #endif /* _ASM_SPARC64_FTRACE */ diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index d0218e7..d3b1a30 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c @@ -7,14 +7,10 @@ #include +#ifdef CONFIG_DYNAMIC_FTRACE static const u32 ftrace_nop = 0x01000000; -unsigned char *ftrace_nop_replace(void) -{ - return (char *)&ftrace_nop; -} - -unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) +static u32 ftrace_call_replace(unsigned long ip, unsigned long addr) { static u32 call; s32 off; @@ -22,15 +18,11 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) off = ((s32)addr - (s32)ip); call = 0x40000000 | ((u32)off >> 2); - return (unsigned char *) &call; + return call; } -int -ftrace_modify_code(unsigned long ip, unsigned char *old_code, - unsigned char *new_code) +static int ftrace_modify_code(unsigned long ip, u32 old, u32 new) { - u32 old = *(u32 *)old_code; - u32 new = *(u32 *)new_code; u32 replaced; int faulted; @@ -59,18 +51,43 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, return faulted; } +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned long ip = rec->ip; + u32 old, new; + + old = ftrace_call_replace(ip, addr); + new = ftrace_nop; + return ftrace_modify_code(ip, old, new); +} + +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned long ip = rec->ip; + u32 old, new; + + old = ftrace_nop; + new = ftrace_call_replace(ip, addr); + return ftrace_modify_code(ip, old, new); +} + int ftrace_update_ftrace_func(ftrace_func_t func) { unsigned long ip = (unsigned long)(&ftrace_call); - unsigned char old[MCOUNT_INSN_SIZE], *new; + u32 old, new; - memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); + old = *(u32 *) &ftrace_call; new = ftrace_call_replace(ip, (unsigned long)func); return ftrace_modify_code(ip, old, new); } int __init ftrace_dyn_arch_init(void *data) { - ftrace_mcount_set(data); + unsigned long *p = data; + + *p = 0; + return 0; } +#endif + diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 91033e6..7109e2b 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -226,6 +226,26 @@ if ($arch eq "x86_64") { if ($is_module eq "0") { $cc .= " -mconstant-gp"; } +} elsif ($arch eq "sparc64") { + # In the objdump output there are giblets like: + # 0000000000000000 : + # As there's some data blobs that get emitted into the + # text section before the first instructions and the first + # real symbols. We don't want to match that, so to combat + # this we use '\w' so we'll match just plain symbol names, + # and not those that also include hex offsets inside of the + # '<>' brackets. Actually the generic function_regex setting + # could safely use this too. + $function_regex = "^([0-9a-fA-F]+)\\s+<(\\w*?)>:"; + + # Sparc64 calls '_mcount' instead of plain 'mcount'. + $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; + + $alignment = 8; + $type = ".xword"; + $ld .= " -m elf64_sparc"; + $cc .= " -m64"; + $objcopy .= " -O elf64-sparc"; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } -- cgit v0.10.2 From 6ac5c610828c051666f667d2bdbd51fc15a59e98 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 15 Jun 2009 03:06:18 -0700 Subject: sparc: replace uses of CPU_MASK_ALL_PTR CPU_MASK_ALL is the (deprecated) "all bits set" cpumask, defined as so: #define CPU_MASK_ALL (cpumask_t) { { ... } } Taking the address of such a temporary is questionable at best, unfortunately 321a8e9d (cpumask: add CPU_MASK_ALL_PTR macro) added CPU_MASK_ALL_PTR: #define CPU_MASK_ALL_PTR (&CPU_MASK_ALL) Which formalizes this practice. One day gcc could bite us over this usage (though we seem to have gotten away with it so far). [Description by Rusty Russell] Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index cfb3d06..fa44eaf 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1542,5 +1542,5 @@ void __init setup_per_cpu_areas(void) of_fill_in_cpu_data(); if (tlb_type == hypervisor) - mdesc_fill_in_cpu_data(CPU_MASK_ALL_PTR); + mdesc_fill_in_cpu_data(cpu_all_mask); } diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index b5a5932..ca92e2f 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1799,7 +1799,7 @@ void __init paging_init(void) if (tlb_type == hypervisor) { sun4v_mdesc_init(); - mdesc_populate_present_mask(CPU_MASK_ALL_PTR); + mdesc_populate_present_mask(cpu_all_mask); } /* Once the OF device tree and MDESC have been setup, we know -- cgit v0.10.2 From 32e5897da1fc5180aa817c81e6aca74a8f6b6957 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 16 Jun 2009 03:46:54 -0700 Subject: openprom: Squelch useless GCC warning. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/sbus/char/openprom.c: In function ‘openprom_sunos_ioctl’: drivers/sbus/char/openprom.c:306: warning: ‘opp’ may be used uninitialized in this function Signed-off-by: David S. Miller diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 124f660..75ac19b 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -303,7 +303,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, struct device_node *dp) { DATA *data = file->private_data; - struct openpromio *opp; + struct openpromio *opp = NULL; int bufsize, error = 0; static int cnt; void __user *argp = (void __user *)arg; -- cgit v0.10.2 From d1ae4ce3d0db5153435558f0f3f4ef8f4c790dee Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 16 Jun 2009 04:17:58 -0700 Subject: sparc: Wire up sys_rt_tgsigqueueinfo(). Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index b8eb71e..b2c406d 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -394,8 +394,9 @@ #define __NR_accept4 323 #define __NR_preadv 324 #define __NR_pwritev 325 +#define __NR_rt_tgsigqueueinfo 326 -#define NR_SYSCALLS 326 +#define NR_SYSCALLS 327 #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 00ec3b1..6909016 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -81,4 +81,6 @@ sys_call_table: /*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 -/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev +/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv +/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo + diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 82b5bf8..6b3ee88 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -82,7 +82,8 @@ sys_call_table32: .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 -/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv, compat_sys_pwritev +/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv + .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo #endif /* CONFIG_COMPAT */ @@ -156,4 +157,5 @@ sys_call_table: .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 -/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev +/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv + .word sys_pwritev, sys_rt_tgsigqueueinfo -- cgit v0.10.2 From aaa7e2f74f11b5f7e30483807b896d7b3369586f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 16 Jun 2009 04:59:53 -0700 Subject: sparc64: Update defconfig. Signed-off-by: David S. Miller diff --git a/arch/sparc/configs/sparc64_defconfig b/arch/sparc/configs/sparc64_defconfig index b5d63bd..0123a4c 100644 --- a/arch/sparc/configs/sparc64_defconfig +++ b/arch/sparc/configs/sparc64_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.30-rc2 -# Fri Apr 17 02:03:07 2009 +# Linux kernel version: 2.6.30 +# Tue Jun 16 04:59:36 2009 # CONFIG_64BIT=y CONFIG_SPARC=y @@ -19,6 +19,7 @@ CONFIG_LOCKDEP_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y CONFIG_AUDIT_ARCH=y CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_MMU=y CONFIG_ARCH_NO_VIRT_TO_BUS=y @@ -82,7 +83,6 @@ CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_STRIP_ASM_SYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y @@ -95,16 +95,21 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y + +# +# Performance Counters +# CONFIG_VM_EVENT_COUNTERS=y CONFIG_PCI_QUIRKS=y CONFIG_SLUB_DEBUG=y +# CONFIG_STRIP_ASM_SYMS is not set # CONFIG_COMPAT_BRK is not set # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set CONFIG_PROFILING=y CONFIG_TRACEPOINTS=y -# CONFIG_MARKERS is not set +CONFIG_MARKERS=y CONFIG_OPROFILE=m CONFIG_HAVE_OPROFILE=y CONFIG_KPROBES=y @@ -202,6 +207,7 @@ CONFIG_NR_QUICK=1 CONFIG_UNEVICTABLE_LRU=y CONFIG_HAVE_MLOCK=y CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=8192 CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_PREEMPT_NONE is not set @@ -321,6 +327,7 @@ CONFIG_VLAN_8021Q=m # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set # CONFIG_NET_SCHED is not set # CONFIG_DCB is not set @@ -340,7 +347,11 @@ CONFIG_WIRELESS=y CONFIG_WIRELESS_OLD_REGULATORY=y # CONFIG_WIRELESS_EXT is not set # CONFIG_LIB80211 is not set -# CONFIG_MAC80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +CONFIG_MAC80211_DEFAULT_PS_VALUE=0 # CONFIG_WIMAX is not set # CONFIG_RFKILL is not set # CONFIG_NET_9P is not set @@ -364,6 +375,7 @@ CONFIG_EXTRA_FIRMWARE="" CONFIG_CONNECTOR=m # CONFIG_MTD is not set CONFIG_OF_DEVICE=y +CONFIG_OF_MDIO=m # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_FD is not set @@ -399,6 +411,7 @@ CONFIG_MISC_DEVICES=y # CONFIG_EEPROM_AT24 is not set # CONFIG_EEPROM_LEGACY is not set # CONFIG_EEPROM_93CX6 is not set +# CONFIG_CB710_CORE is not set CONFIG_HAVE_IDE=y CONFIG_IDE=y @@ -477,10 +490,6 @@ CONFIG_BLK_DEV_SR=m CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m # CONFIG_CHR_DEV_SCH is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -499,6 +508,7 @@ CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set @@ -507,6 +517,7 @@ CONFIG_SCSI_LOWLEVEL=y # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set # CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set @@ -521,7 +532,6 @@ CONFIG_SCSI_LOWLEVEL=y # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_MVSAS is not set # CONFIG_SCSI_STEX is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_QLOGIC_1280 is not set @@ -569,7 +579,6 @@ CONFIG_DM_ZERO=m # CONFIG_IEEE1394 is not set # CONFIG_I2O is not set CONFIG_NETDEVICES=y -CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_MACVLAN is not set @@ -635,6 +644,7 @@ CONFIG_NET_PCI=y # CONFIG_SMSC9420 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set +# CONFIG_KS8842 is not set # CONFIG_VIA_RHINE is not set # CONFIG_SC92031 is not set # CONFIG_ATL2 is not set @@ -1127,6 +1137,11 @@ CONFIG_SND_VERBOSE_PROCFS=y # CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set CONFIG_SND_VMASTER=y +CONFIG_SND_RAWMIDI_SEQ=m +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set CONFIG_SND_MPU401_UART=m CONFIG_SND_AC97_CODEC=m CONFIG_SND_DRIVERS=y @@ -1153,6 +1168,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_OXYGEN is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set +# CONFIG_SND_CTXFI is not set # CONFIG_SND_DARLA20 is not set # CONFIG_SND_GINA20 is not set # CONFIG_SND_LAYLA20 is not set @@ -1183,6 +1199,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_INTEL8X0 is not set # CONFIG_SND_INTEL8X0M is not set # CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LX6464ES is not set # CONFIG_SND_MAESTRO3 is not set # CONFIG_SND_MIXART is not set # CONFIG_SND_NM256 is not set @@ -1229,6 +1246,7 @@ CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y # CONFIG_DRAGONRISE_FF is not set CONFIG_HID_EZKEY=y CONFIG_HID_KYE=y @@ -1246,9 +1264,14 @@ CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y # CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y # CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_ZEROPLUS=y # CONFIG_ZEROPLUS_FF is not set CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y @@ -1462,6 +1485,7 @@ CONFIG_FILE_LOCKING=y # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_BTRFS_FS is not set +CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y @@ -1636,25 +1660,28 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_DEBUG_PAGEALLOC is not set CONFIG_NOP_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y CONFIG_TRACING_SUPPORT=y - -# -# Tracers -# +CONFIG_FTRACE=y # CONFIG_FUNCTION_TRACER is not set # CONFIG_IRQSOFF_TRACER is not set # CONFIG_SCHED_TRACER is not set -# CONFIG_CONTEXT_SWITCH_TRACER is not set -# CONFIG_EVENT_TRACER is not set # CONFIG_BOOT_TRACER is not set -# CONFIG_TRACE_BRANCH_PROFILING is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set # CONFIG_STACK_TRACER is not set # CONFIG_KMEMTRACE is not set # CONFIG_WORKQUEUE_TRACER is not set CONFIG_BLK_DEV_IO_TRACE=y # CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set # CONFIG_DYNAMIC_DEBUG is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y -- cgit v0.10.2 From 5fd29d6ccbc98884569d6f3105aeca70858b3e0f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 16 Jun 2009 10:57:02 -0700 Subject: printk: clean up handling of log-levels and newlines It used to be that we would only look at the log-level in a printk() after explicit newlines, which can cause annoying problems when the previous printk() did not end with a '\n'. In that case, the log-level marker would be just printed out in the middle of the line, and be seen as just noise rather than change the logging level. This changes things to always look at the log-level in the first bytes of the printout. If a log level marker is found, it is always used as the log-level. Additionally, if no newline existed, one is added (unless the log-level is the explicit KERN_CONT marker, to explicitly show that it's a continuation of a previous line). Acked-by: Arjan van de Ven Signed-off-by: Linus Torvalds diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 883cd44..066bb1e 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -102,7 +102,7 @@ extern const char linux_proc_banner[]; * line that had no enclosing \n). Only to be used by core/arch code * during early bootup (a continued line is not SMP-safe otherwise). */ -#define KERN_CONT "" +#define KERN_CONT "" extern int console_printk[]; diff --git a/kernel/printk.c b/kernel/printk.c index 5052b54..a87770c 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -687,20 +687,33 @@ asmlinkage int vprintk(const char *fmt, va_list args) sizeof(printk_buf) - printed_len, fmt, args); + p = printk_buf; + + /* Do we have a loglevel in the string? */ + if (p[0] == '<') { + unsigned char c = p[1]; + if (c && p[2] == '>') { + switch (c) { + case '0' ... '7': /* loglevel */ + current_log_level = c - '0'; + if (!new_text_line) { + emit_log_char('\n'); + new_text_line = 1; + } + /* Fallthrough - skip the loglevel */ + case 'c': /* KERN_CONT */ + p += 3; + break; + } + } + } + /* * Copy the output into log_buf. If the caller didn't provide * appropriate log level tags, we insert them here */ - for (p = printk_buf; *p; p++) { + for ( ; *p; p++) { if (new_text_line) { - /* If a token, set current_log_level and skip over */ - if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' && - p[2] == '>') { - current_log_level = p[1] - '0'; - p += 3; - printed_len -= 3; - } - /* Always output the token */ emit_log_char('<'); emit_log_char(current_log_level + '0'); -- cgit v0.10.2 From e28d713704117bca0820c732210df6075b09f13b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 16 Jun 2009 11:02:28 -0700 Subject: printk: Add KERN_DEFAULT printk log-level This adds a KERN_DEFAULT loglevel marker, for when you cannot decide which loglevel you want, and just want to keep an existing printk with the default loglevel. The difference between having KERN_DEFAULT and having no log-level marker at all is two-fold: - having the log-level marker will now force a new-line if the previous printout had not added one (perhaps because it forgot, but perhaps because it expected a continuation) - having a log-level marker is required if you are printing out a message that otherwise itself could perhaps otherwise be mistaken for a log-level. Signed-of-by: Linus Torvalds diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 066bb1e..1b2e174 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -97,6 +97,8 @@ extern const char linux_proc_banner[]; #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */ +/* Use the default kernel loglevel */ +#define KERN_DEFAULT "" /* * Annotation for a "continued" line of log printout (only done after a * line that had no enclosing \n). Only to be used by core/arch code diff --git a/kernel/printk.c b/kernel/printk.c index a87770c..b4d97b5 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -696,6 +696,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) switch (c) { case '0' ... '7': /* loglevel */ current_log_level = c - '0'; + /* Fallthrough - make sure we're on a new line */ + case 'd': /* KERN_DEFAULT */ if (!new_text_line) { emit_log_char('\n'); new_text_line = 1; -- cgit v0.10.2 From b231125af7811a2f68c455d3bda95ac170ee4fa6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 16 Jun 2009 11:07:14 -0700 Subject: printk: add KERN_DEFAULT loglevel to print_modules() Several WARN_ON() messages omit the '\n' at the end of the string, which is a simple (and understandable) error. The next line printed after that warning line is usually the current module list, and that printk does not have a log-level marker - resulting in one long mixed-up line. Adding this loglevel marker will now avoid this unreadable mess. Signed-off-by: Linus Torvalds diff --git a/kernel/module.c b/kernel/module.c index e4ab36c..215aaab 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2899,7 +2899,7 @@ void print_modules(void) struct module *mod; char buf[8]; - printk("Modules linked in:"); + printk(KERN_DEFAULT "Modules linked in:"); /* Most callers should already have preempt disabled, but make sure */ preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) -- cgit v0.10.2 From cbcb6d66af4c6169ce1c2d01a3ab345f04b8359d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 15 Jun 2009 16:27:29 +0100 Subject: pty: Narrow the race on ldisc locking The pty code has always been buggy on its ldisc handling. The recent changes made the window for the race much bigger. Pending fixing it properly which is not at all trivial, at least make the race small again so we don't disrupt other dev work. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 5acd29e..3910ce1 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -104,7 +104,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, struct tty_struct *to = tty->link; int c; - if (!to || tty->stopped) + if (!to || !to->ldisc || tty->stopped) return 0; c = to->receive_room; @@ -148,7 +148,7 @@ static int pty_chars_in_buffer(struct tty_struct *tty) int count; /* We should get the line discipline lock for "tty->link" */ - if (!to || !to->ldisc->ops->chars_in_buffer) + if (!to || !to->ldisc || !to->ldisc->ops->chars_in_buffer) return 0; /* The ldisc must report 0 if no characters available to be read */ @@ -183,7 +183,7 @@ static void pty_flush_buffer(struct tty_struct *tty) struct tty_struct *to = tty->link; unsigned long flags; - if (!to) + if (!to || !to->ldisc) return; if (to->ldisc->ops->flush_buffer) -- cgit v0.10.2 From 46a50661fc95d4acf5e4c203f7889234238ce642 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 15 Jun 2009 16:28:29 +0100 Subject: tty: Fix leaks introduced by the shift to separate ldisc objects Gold star for the kmemleak detector. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 39c8f86..94b3e06 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc) } } spin_unlock_irqrestore(&tty_ldisc_lock, flags); - if (err) + if (err) { + kfree(ld); return ERR_PTR(err); + } return ld; } @@ -262,7 +264,7 @@ const struct file_operations tty_ldiscs_proc_fops = { * @ld: line discipline * * Install an instance of a line discipline into a tty structure. The - * ldisc must have a reference count above zero to ensure it remains/ + * ldisc must have a reference count above zero to ensure it remains. * The tty instance refcount starts at zero. * * Locking: -- cgit v0.10.2 From 8d2ead743dd54dff1fe3d0f4933e5da8bfe07472 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 16 Jun 2009 17:00:26 +0100 Subject: tty: Fix leaks introduced by the shift to separate ldisc objects Gold star for the kmemleak detector. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 39c8f86..94b3e06 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc) } } spin_unlock_irqrestore(&tty_ldisc_lock, flags); - if (err) + if (err) { + kfree(ld); return ERR_PTR(err); + } return ld; } @@ -262,7 +264,7 @@ const struct file_operations tty_ldiscs_proc_fops = { * @ld: line discipline * * Install an instance of a line discipline into a tty structure. The - * ldisc must have a reference count above zero to ensure it remains/ + * ldisc must have a reference count above zero to ensure it remains. * The tty instance refcount starts at zero. * * Locking: -- cgit v0.10.2 From 52856ed732aeab5e8e0b7c9e2a7a3d31736218ab Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 16 Jun 2009 17:00:40 +0100 Subject: ldisc: Make sure the ldisc isn't active when we close it Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 94b3e06..874c248 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -793,6 +793,8 @@ void tty_ldisc_hangup(struct tty_struct *tty) /* Avoid racing set_ldisc */ mutex_lock(&tty->ldisc_mutex); /* Switch back to N_TTY */ + tty_ldisc_halt(tty); + tty_ldisc_wait_idle(tty); tty_ldisc_reinit(tty); /* At this point we have a closed ldisc and we want to reopen it. We could defer this to the next open but -- cgit v0.10.2 From 677ca3060c474d7d89941948e32493d9c18c52d2 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 16 Jun 2009 17:00:53 +0100 Subject: ldisc: debug aids Signed-off-by: Linus Torvalds diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 874c248..a19e935 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -207,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld) ldo->refcount--; module_put(ldo->owner); spin_unlock_irqrestore(&tty_ldisc_lock, flags); + WARN_ON(ld->refcount); kfree(ld); } -- cgit v0.10.2 From 5dca607bcf10d3f08d07ffeac664c6769c336145 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 16 Jun 2009 17:01:02 +0100 Subject: tty: fix unused warning when TCGETX is not defined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If TCGETX is not defined, we end up with this warning: drivers/char/tty_ioctl.c: In function ‘tty_mode_ioctl’: drivers/char/tty_ioctl.c:950: warning: unused variable ‘ktermx’ Since the variable is only used in one case statement, push it down to the local case scope. Signed-off-by: Mike Frysinger Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 8116bb1c..b24f6c6 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, void __user *p = (void __user *)arg; int ret = 0; struct ktermios kterm; - struct termiox ktermx; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return ret; #endif #ifdef TCGETX - case TCGETX: + case TCGETX: { + struct termiox ktermx; if (real_tty->termiox == NULL) return -EINVAL; mutex_lock(&real_tty->termios_mutex); @@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, if (copy_to_user(p, &ktermx, sizeof(struct termiox))) ret = -EFAULT; return ret; + } case TCSETX: return set_termiox(real_tty, p, 0); case TCSETXW: -- cgit v0.10.2 From 762faaed91e4ea4a3c34bc58f3221d9487acb470 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 16 Jun 2009 17:01:13 +0100 Subject: pty: Narrow the race on ldisc locking The pty code has always been buggy on its ldisc handling. The recent changes made the window for the race much bigger. Pending fixing it properly which is not at all trivial, at least make the race small again so we don't disrupt other dev work. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 5acd29e..daebe1b 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty) * a count. * * FIXME: Our pty_write method is called with our ldisc lock held but - * not our partners. We can't just take the other one blindly without - * risking deadlocks. + * not our partners. We can't just wait on the other one blindly without + * risking deadlocks. At some point when everything has settled down we need + * to look into making pty_write at least able to sleep over an ldisc change. + * + * The return on no ldisc is a bit counter intuitive but the logic works + * like this. During an ldisc change the other end will flush its buffers. We + * thus return the full length which is identical to the case where we had + * proper locking and happened to queue the bytes just before the flush during + * the ldisc change. */ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct tty_struct *to = tty->link; - int c; + struct tty_ldisc *ld; + int c = count; if (!to || tty->stopped) return 0; - - c = to->receive_room; - if (c > count) - c = count; - to->ldisc->ops->receive_buf(to, buf, NULL, c); - + ld = tty_ldisc_ref(to); + + if (ld) { + c = to->receive_room; + if (c > count) + c = count; + ld->ops->receive_buf(to, buf, NULL, c); + tty_ldisc_deref(ld); + } return c; } @@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty) static int pty_chars_in_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; - int count; + struct tty_ldisc *ld; + int count = 0; /* We should get the line discipline lock for "tty->link" */ - if (!to || !to->ldisc->ops->chars_in_buffer) + if (!to) + return 0; + /* We cannot take a sleeping reference here without deadlocking with + an ldisc change - but it doesn't really matter */ + ld = tty_ldisc_ref(to); + if (ld == NULL) return 0; /* The ldisc must report 0 if no characters available to be read */ - count = to->ldisc->ops->chars_in_buffer(to); + if (ld->ops->chars_in_buffer) + count = ld->ops->chars_in_buffer(to); + + tty_ldisc_deref(ld); if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; @@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; unsigned long flags; + struct tty_ldisc *ld; if (!to) return; + ld = tty_ldisc_ref(to); + + /* The other end is changing discipline */ + if (!ld) + return; - if (to->ldisc->ops->flush_buffer) + if (ld->ops->flush_buffer) to->ldisc->ops->flush_buffer(to); + tty_ldisc_deref(ld); if (to->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); -- cgit v0.10.2 From 1aa4bed82a684308f54bf782cffaecd4b1dc3cf4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 16 Jun 2009 17:01:33 +0100 Subject: tty: fix sanity check The WARN_ON() that was added to tty_reopen can be triggered in the specific case of a hangup occurring during a re-open of a tty which is not in the middle of being otherwise closed. In that case however the WARN() is bogus as we don't hold the neccessary locks to make a correct decision. The case we should be checking is "if the ldisc is not changing and reopen is occuring". We could drop the WARN_ON but for the moment the debug is more valuable even if it means taking a mutex as it will find any other cases. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 939e198..a3afa0c 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty) tty->count++; tty->driver = driver; /* N.B. why do this every time?? */ + mutex_lock(&tty->ldisc_mutex); WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); + mutex_unlock(&tty->ldisc_mutex); return 0; } -- cgit v0.10.2 From dc9879291be479e096c5cfac33effc2ade74309b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 16 Jun 2009 17:01:52 +0100 Subject: MAINTAINERS: update 8250 section, give Alan Cox a name Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 2cb7566..09f6b3e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -157,9 +157,10 @@ S: Maintained F: drivers/net/r8169.c 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER +P: Alan Cox +M: alan@lxorguk.ukuu.org.uk L: linux-serial@vger.kernel.org W: http://serial.sourceforge.net -M: alan@lxorguk.ukuu.org.uk S: Odd Fixes F: drivers/serial/8250* F: include/linux/serial_8250.h -- cgit v0.10.2 From 0ccad87012c6c2e7446e4dc0f0894cf182a5270a Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Tue, 16 Jun 2009 17:02:03 +0100 Subject: atmel_serial: fix hang in set_termios when crtscts is enabled After enabling hardware flow control, any subsequent termios call may hang waiting for the transmitter to drain. This appears to be caused by a busy-loop in set_termios() waiting for the transmitter to become empty, which may take a very long time (or hang indefinitely) if the device at the other end is blocking us. A quick look through the tty and serial_core code indicates that any necessary flushing (which is optional) has already been done at this point, so there's no need for the driver to flush the transmitter on its own. Fix it by removing the busy-loop altogether. Tested-by: Eirik Aanonsen Signed-off-by: Haavard Skinnemoen Signed-off-by: Andrew Morton Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index b3497d7..338b15c 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -1104,11 +1104,13 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); - /* save/disable interrupts and drain transmitter */ + /* + * save/disable interrupts. The tty layer will ensure that the + * transmitter is empty if requested by the caller, so there's + * no need to wait for it here. + */ imr = UART_GET_IMR(port); UART_PUT_IDR(port, -1); - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) - cpu_relax(); /* disable receiver and transmitter */ UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); -- cgit v0.10.2 From 1a2c4b3147ac0645605d6def2855478861d9361b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 16 Jun 2009 17:02:15 +0100 Subject: imx: Check for NULL pointer deref before calling tty_encode_baud_rate Signed-off-by: Sascha Hauer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 285b414..5d7b58f 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -924,11 +924,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); - tdiv64 = sport->port.uartclk; - tdiv64 *= num; - do_div(tdiv64, denom * 16 * div); - tty_encode_baud_rate(sport->port.info->port.tty, - (speed_t)tdiv64, (speed_t)tdiv64); + if (port->info && port->info->port.tty) { + tdiv64 = sport->port.uartclk; + tdiv64 *= num; + do_div(tdiv64, denom * 16 * div); + tty_encode_baud_rate(sport->port.info->port.tty, + (speed_t)tdiv64, (speed_t)tdiv64); + } num -= 1; denom -= 1; -- cgit v0.10.2